diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 00000000000000..e4c4eef10b28c1 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 + +check-private-items = true + +disallowed-macros = [ + # The `clippy::dbg_macro` lint only works with `std::dbg!`, thus we simulate + # it here, see: https://github.com/rust-lang/rust-clippy/issues/11303. + { path = "kernel::dbg", reason = "the `dbg!` macro is intended as a debugging tool" }, +] diff --git a/.get_maintainer.ignore b/.get_maintainer.ignore index 7d1b30aae87426..b458815f1d1bf4 100644 --- a/.get_maintainer.ignore +++ b/.get_maintainer.ignore @@ -3,3 +3,4 @@ Alan Cox Christoph Hellwig Jeff Kirsher Marc Gonzalez +Ralf Baechle diff --git a/.gitignore b/.gitignore index 56972adb5031af..6839cf84acda0d 100644 --- a/.gitignore +++ b/.gitignore @@ -103,6 +103,7 @@ modules.order # We don't want to ignore the following even if they are dot-files # !.clang-format +!.clippy.toml !.cocciconfig !.editorconfig !.get_maintainer.ignore @@ -128,6 +129,7 @@ series # ctags files tags +!tags/ TAGS # cscope files diff --git a/.mailmap b/.mailmap index 5e829da09e7f3a..7efe43237ca8eb 100644 --- a/.mailmap +++ b/.mailmap @@ -37,6 +37,7 @@ Alexei Avshalom Lazar Alexei Starovoitov Alexei Starovoitov Alexei Starovoitov +Alexey Klimov Alexey Makhalov Alex Elder Alex Elder @@ -251,6 +252,8 @@ Guru Das Srinagesh Gustavo Padovan Gustavo Padovan Hanjun Guo +Hans Verkuil +Hans Verkuil Heiko Carstens Heiko Carstens Heiko Stuebner @@ -269,6 +272,7 @@ Jack Pham Jaegeuk Kim Jaegeuk Kim Jaegeuk Kim +Jai Luthra Jakub Kicinski James Bottomley James Bottomley @@ -730,6 +734,8 @@ Will Deacon Wolfram Sang Wolfram Sang Yakir Yang +Yanteng Si +Ying Huang Yusuke Goda Zack Rusin Zhu Yanjun diff --git a/CREDITS b/CREDITS index 96660c63f5b9ac..b1777b53c63a93 100644 --- a/CREDITS +++ b/CREDITS @@ -185,6 +185,11 @@ P: 1024/AF7B30C1 CF 97 C2 CC 6D AE A7 FE C8 BA 9C FC 88 DE 32 C3 D: Linux/MIPS port D: Linux/68k hacker D: AX25 maintainer +D: EDAC-CAVIUM OCTEON maintainer +D: IOC3 ETHERNET DRIVER maintainer +D: NETROM NETWORK LAYER maintainer +D: ROSE NETWORK LAYER maintainer +D: TURBOCHANNEL SUBSYSTEM maintainer S: Hauptstrasse 19 S: 79837 St. Blasien S: Germany @@ -574,6 +579,9 @@ N: Zach Brown E: zab@zabbo.net D: maestro pci sound +N: Zefan Li +D: Contribution to control group stuff + N: David Brownell D: Kernel engineer, mentor, and friend. Maintained USB EHCI and D: gadget layers, SPI subsystem, GPIO subsystem, and more than a few @@ -3795,6 +3803,10 @@ S: Department of Zoology, University of Washington S: Seattle, WA 98195-1800 S: USA +N: York Sun +E: york.sun@nxp.com +D: Freescale DDR EDAC + N: Eugene Surovegin E: ebs@ebshome.net W: https://kernel.ebshome.net/ diff --git a/Documentation/ABI/obsolete/sysfs-selinux-user b/Documentation/ABI/obsolete/sysfs-selinux-user new file mode 100644 index 00000000000000..8ab7557f283fe3 --- /dev/null +++ b/Documentation/ABI/obsolete/sysfs-selinux-user @@ -0,0 +1,12 @@ +What: /sys/fs/selinux/user +Date: April 2005 (predates git) +KernelVersion: 2.6.12-rc2 (predates git) +Contact: selinux@vger.kernel.org +Description: + + The selinuxfs "user" node allows userspace to request a list + of security contexts that can be reached for a given SELinux + user from a given starting context. This was used by libselinux + when various login-style programs requested contexts for + users, but libselinux stopped using it in 2020. + Kernel support will be removed no sooner than Dec 2025. diff --git a/Documentation/ABI/stable/sysfs-block b/Documentation/ABI/stable/sysfs-block index 7a820a7d53aabf..0cceb2badc836b 100644 --- a/Documentation/ABI/stable/sysfs-block +++ b/Documentation/ABI/stable/sysfs-block @@ -424,6 +424,13 @@ Description: [RW] This file is used to control (on/off) the iostats accounting of the disk. +What: /sys/block//queue/iostats_passthrough +Date: October 2024 +Contact: linux-block@vger.kernel.org +Description: + [RW] This file is used to control (on/off) the iostats + accounting of the disk for passthrough commands. + What: /sys/block//queue/logical_block_size Date: May 2009 diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 4feb692c4c1d37..b6720768d63d23 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -342,6 +342,70 @@ Description: Specific uncompressed frame descriptors support ========================= ===================================== +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased +Date: Sept 2024 +KernelVersion: 5.15 +Description: Framebased format descriptors + +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name +Date: Sept 2024 +KernelVersion: 5.15 +Description: Specific framebased format descriptors + + ================== ======================================= + bFormatIndex unique id for this format descriptor; + only defined after parent header is + linked into the streaming class; + read-only + bmaControls this format's data for bmaControls in + the streaming header + bmInterlaceFlags specifies interlace information, + read-only + bAspectRatioY the X dimension of the picture aspect + ratio, read-only + bAspectRatioX the Y dimension of the picture aspect + ratio, read-only + bDefaultFrameIndex optimum frame index for this stream + bBitsPerPixel number of bits per pixel used to + specify color in the decoded video + frame + guidFormat globally unique id used to identify + stream-encoding format + ================== ======================================= + +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name/name +Date: Sept 2024 +KernelVersion: 5.15 +Description: Specific framebased frame descriptors + + ========================= ===================================== + bFrameIndex unique id for this framedescriptor; + only defined after parent format is + linked into the streaming header; + read-only + dwFrameInterval indicates how frame interval can be + programmed; a number of values + separated by newline can be specified + dwDefaultFrameInterval the frame interval the device would + like to use as default + dwBytesPerLine Specifies the number of bytes per line + of video for packed fixed frame size + formats, allowing the receiver to + perform stride alignment of the video. + If the bVariableSize value (above) is + TRUE (1), or if the format does not + permit such alignment, this value shall + be set to zero (0). + dwMaxBitRate the maximum bit rate at the shortest + frame interval in bps + dwMinBitRate the minimum bit rate at the longest + frame interval in bps + wHeight height of decoded bitmap frame in px + wWidth width of decoded bitmam frame in px + bmCapabilities still image support, fixed frame-rate + support + ========================= ===================================== + What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header Date: Dec 2014 KernelVersion: 4.0 diff --git a/Documentation/ABI/testing/debugfs-hisi-hpre b/Documentation/ABI/testing/debugfs-hisi-hpre index d4e16ef9ac9a99..29fb7d5ffc691f 100644 --- a/Documentation/ABI/testing/debugfs-hisi-hpre +++ b/Documentation/ABI/testing/debugfs-hisi-hpre @@ -184,3 +184,10 @@ Date: Apr 2020 Contact: linux-crypto@vger.kernel.org Description: Dump the total number of time out requests. Available for both PF and VF, and take no other effect on HPRE. + +What: /sys/kernel/debug/hisi_hpre//cap_regs +Date: Oct 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the values of the qm and hpre capability bit registers and + support the query of device specifications to facilitate fault locating. + Available for both PF and VF, and take no other effect on HPRE. diff --git a/Documentation/ABI/testing/debugfs-hisi-migration b/Documentation/ABI/testing/debugfs-hisi-migration new file mode 100644 index 00000000000000..2c01b2d387ddde --- /dev/null +++ b/Documentation/ABI/testing/debugfs-hisi-migration @@ -0,0 +1,25 @@ +What: /sys/kernel/debug/vfio//migration/hisi_acc/dev_data +Date: Jan 2025 +KernelVersion: 6.13 +Contact: Longfang Liu +Description: Read the configuration data and some status data + required for device live migration. These data include device + status data, queue configuration data, some task configuration + data and device attribute data. The output format of the data + is defined by the live migration driver. + +What: /sys/kernel/debug/vfio//migration/hisi_acc/migf_data +Date: Jan 2025 +KernelVersion: 6.13 +Contact: Longfang Liu +Description: Read the data from the last completed live migration. + This data includes the same device status data as in "dev_data". + The migf_data is the dev_data that is migrated. + +What: /sys/kernel/debug/vfio//migration/hisi_acc/cmd_state +Date: Jan 2025 +KernelVersion: 6.13 +Contact: Longfang Liu +Description: Used to obtain the device command sending and receiving + channel status. Returns failure or success logs based on the + results. diff --git a/Documentation/ABI/testing/debugfs-hisi-sec b/Documentation/ABI/testing/debugfs-hisi-sec index 6c6c9a6e150acb..82bf4a0dc7f78a 100644 --- a/Documentation/ABI/testing/debugfs-hisi-sec +++ b/Documentation/ABI/testing/debugfs-hisi-sec @@ -157,3 +157,10 @@ Contact: linux-crypto@vger.kernel.org Description: Dump the total number of completed but marked error requests to be received. Available for both PF and VF, and take no other effect on SEC. + +What: /sys/kernel/debug/hisi_sec2//cap_regs +Date: Oct 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the values of the qm and sec capability bit registers and + support the query of device specifications to facilitate fault locating. + Available for both PF and VF, and take no other effect on SEC. diff --git a/Documentation/ABI/testing/debugfs-hisi-zip b/Documentation/ABI/testing/debugfs-hisi-zip index a22dd694221935..0abd65d27e9bb3 100644 --- a/Documentation/ABI/testing/debugfs-hisi-zip +++ b/Documentation/ABI/testing/debugfs-hisi-zip @@ -158,3 +158,10 @@ Contact: linux-crypto@vger.kernel.org Description: Dump the total number of BD type error requests to be received. Available for both PF and VF, and take no other effect on ZIP. + +What: /sys/kernel/debug/hisi_zip//cap_regs +Date: Oct 2024 +Contact: linux-crypto@vger.kernel.org +Description: Dump the values of the qm and zip capability bit registers and + support the query of device specifications to facilitate fault locating. + Available for both PF and VF, and take no other effect on ZIP. diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-vpa-pmu b/Documentation/ABI/testing/sysfs-bus-event_source-devices-vpa-pmu new file mode 100644 index 00000000000000..a116aee9709aa8 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-vpa-pmu @@ -0,0 +1,25 @@ +What: /sys/bus/event_source/devices/vpa_pmu/format +Date: November 2024 +Contact: Linux on PowerPC Developer List +Description: Read-only. Attribute group to describe the magic bits + that go into perf_event_attr.config for a particular pmu. + (See ABI/testing/sysfs-bus-event_source-devices-format). + + Each attribute under this group defines a bit range of the + perf_event_attr.config. Supported attribute are listed + below:: + + event = "config:0-31" - event ID + + For example:: + + l1_to_l2_lat = "event=0x1" + +What: /sys/bus/event_source/devices/vpa_pmu/events +Date: November 2024 +Contact: Linux on PowerPC Developer List +Description: Read-only. Attribute group to describe performance monitoring + events for the Virtual Processor Area events. Each attribute + in this group describes a single performance monitoring event + supported by vpa_pmu. The name of the file is the name of + the event (See ABI/testing/sysfs-bus-event_source-devices-events). diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 89943c2d54e8a8..f83bd6829285cd 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -2268,6 +2268,30 @@ Description: An example format is 16-bytes, 2-digits-per-byte, HEX-string representing the sensor unique ID number. +What: /sys/bus/iio/devices/iio:deviceX/filter_type_available +What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_filter_mode_available +KernelVersion: 6.1 +Contact: linux-iio@vger.kernel.org +Description: + Reading returns a list with the possible filter modes. Options + for the attribute: + + * "sinc3" - The digital sinc3 filter. Moderate 1st + conversion time. Good noise performance. + * "sinc4" - Sinc 4. Excellent noise performance. Long + 1st conversion time. + * "sinc5" - The digital sinc5 filter. Excellent noise + performance + * "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion + time. + * "sinc3+rej60" - Sinc3 + 60Hz rejection. + * "sinc3+sinc1" - Sinc3 + averaging by 8. Low 1st conversion + time. + * "sinc3+pf1" - Sinc3 + device specific Post Filter 1. + * "sinc3+pf2" - Sinc3 + device specific Post Filter 2. + * "sinc3+pf3" - Sinc3 + device specific Post Filter 3. + * "sinc3+pf4" - Sinc3 + device specific Post Filter 4. + What: /sys/.../events/in_proximity_thresh_either_runningperiod KernelVersion: 6.6 Contact: linux-iio@vger.kernel.org @@ -2339,3 +2363,11 @@ KernelVersion: 6.10 Contact: linux-iio@vger.kernel.org Description: The value of current sense resistor in Ohms. + +What: /sys/.../iio:deviceX/in_attention_input +KernelVersion: 6.13 +Contact: linux-iio@vger.kernel.org +Description: + Value representing the user's attention to the system expressed + in units as percentage. This usually means if the user is + looking at the screen or not. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130 b/Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130 deleted file mode 100644 index f24ed6687e900e..00000000000000 --- a/Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130 +++ /dev/null @@ -1,46 +0,0 @@ -What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_filter_mode_available -KernelVersion: 6.2 -Contact: linux-iio@vger.kernel.org -Description: - Reading returns a list with the possible filter modes. - - * "sinc4" - Sinc 4. Excellent noise performance. Long - 1st conversion time. No natural 50/60Hz rejection. - - * "sinc4+sinc1" - Sinc4 + averaging by 8. Low 1st conversion - time. - - * "sinc3" - Sinc3. Moderate 1st conversion time. - Good noise performance. - - * "sinc3+rej60" - Sinc3 + 60Hz rejection. At a sampling - frequency of 50Hz, achieves simultaneous 50Hz and 60Hz - rejection. - - * "sinc3+sinc1" - Sinc3 + averaging by 8. Low 1st conversion - time. Best used with a sampling frequency of at least - 216.19Hz. - - * "sinc3+pf1" - Sinc3 + Post Filter 1. 53dB rejection @ - 50Hz, 58dB rejection @ 60Hz. - - * "sinc3+pf2" - Sinc3 + Post Filter 2. 70dB rejection @ - 50Hz, 70dB rejection @ 60Hz. - - * "sinc3+pf3" - Sinc3 + Post Filter 3. 99dB rejection @ - 50Hz, 103dB rejection @ 60Hz. - - * "sinc3+pf4" - Sinc3 + Post Filter 4. 103dB rejection @ - 50Hz, 109dB rejection @ 60Hz. - -What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_filter_mode -KernelVersion: 6.2 -Contact: linux-iio@vger.kernel.org -Description: - Set the filter mode of the differential channel. When the filter - mode changes, the in_voltageY-voltageZ_sampling_frequency and - in_voltageY-voltageZ_sampling_frequency_available attributes - might also change to accommodate the new filter mode. - If the current sampling frequency is out of range for the new - filter mode, the sampling frequency will be changed to the - closest valid one. diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 7f63c7e9777358..5da6a14dc326bd 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -163,6 +163,17 @@ Description: will be present in sysfs. Writing 1 to this file will perform reset. +What: /sys/bus/pci/devices/.../reset_subordinate +Date: October 2024 +Contact: linux-pci@vger.kernel.org +Description: + This is visible only for bridge devices. If you want to reset + all devices attached through the subordinate bus of a specific + bridge device, writing 1 to this will try to do it. This will + affect all devices attached to the system through this bridge + similiar to writing 1 to their individual "reset" file, so use + with caution. + What: /sys/bus/pci/devices/.../vpd Date: February 2008 Contact: Ben Hutchings diff --git a/Documentation/ABI/testing/sysfs-bus-platform-drivers-amd_x3d_vcache b/Documentation/ABI/testing/sysfs-bus-platform-drivers-amd_x3d_vcache new file mode 100644 index 00000000000000..ac3431736f5cac --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-platform-drivers-amd_x3d_vcache @@ -0,0 +1,12 @@ +What: /sys/bus/platform/drivers/amd_x3d_vcache/AMDI0101:00/amd_x3d_mode +Date: November 2024 +KernelVersion: 6.13 +Contact: Basavaraj Natikar +Description: (RW) AMD 3D V-Cache optimizer allows users to switch CPU core + rankings dynamically. + + This file switches between these two modes: + - "frequency" cores within the faster CCD are prioritized before + those in the slower CCD. + - "cache" cores within the larger L3 CCD are prioritized before + those in the smaller L3 CCD. diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes index 9c82c7b42ff823..2713efa509b465 100644 --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes @@ -193,7 +193,7 @@ Description: mechanism: The means of authentication. This attribute is mandatory. - Only supported type currently is "password". + Supported types are "password" or "certificate". max_password_length: A file that can be read to obtain the @@ -303,6 +303,7 @@ Description: being configured allowing anyone to make changes. After any of these operations the system must reboot for the changes to take effect. + Admin and System certificates are supported from 2025 systems onward. certificate_thumbprint: Read only attribute used to display the MD5, SHA1 and SHA256 thumbprints diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec index 281b995beb05ae..38e101c17a0048 100644 --- a/Documentation/ABI/testing/sysfs-class-typec +++ b/Documentation/ABI/testing/sysfs-class-typec @@ -149,6 +149,19 @@ Description: advertise to the partner. The currently used capabilities are in brackets. Selection happens by writing to the file. +What: /sys/class/typec//usb_capability +Date: November 2024 +Contact: Heikki Krogerus +Description: Lists the supported USB Modes. The default USB mode that is used + next time with the Enter_USB Message is in brackets. The default + mode can be changed by writing to the file when supported by the + driver. + + Valid values: + - usb2 (USB 2.0) + - usb3 (USB 3.2) + - usb4 (USB4) + USB Type-C partner devices (eg. /sys/class/typec/port0-partner/) What: /sys/class/typec/-partner/accessory_mode @@ -220,6 +233,20 @@ Description: directory exists, it will have an attribute file for every VDO in Discover Identity command result. +What: /sys/class/typec/-partner/usb_mode +Date: November 2024 +Contact: Heikki Krogerus +Description: The USB Modes that the partner device supports. The active mode + is displayed in brackets. The active USB mode can be changed by + writing to this file when the port driver is able to send Data + Reset Message to the partner. That requires USB Power Delivery + contract between the partner and the port. + + Valid values: + - usb2 (USB 2.0) + - usb3 (USB 3.2) + - usb4 (USB4) + USB Type-C cable devices (eg. /sys/class/typec/port0-cable/) Note: Electronically Marked Cables will have a device also for one cable plug diff --git a/Documentation/ABI/testing/sysfs-class-watchdog b/Documentation/ABI/testing/sysfs-class-watchdog index 94fb7461595123..70eabccf055786 100644 --- a/Documentation/ABI/testing/sysfs-class-watchdog +++ b/Documentation/ABI/testing/sysfs-class-watchdog @@ -76,7 +76,7 @@ Description: timeout when the pretimeout interrupt is delivered. Pretimeout is an optional feature. -What: /sys/class/watchdog/watchdogn/pretimeout_avaialable_governors +What: /sys/class/watchdog/watchdogn/pretimeout_available_governors Date: February 2017 Contact: Wim Van Sebroeck Description: diff --git a/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs b/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs index 1666340820f75a..d1b3a95a5518ac 100644 --- a/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs +++ b/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs @@ -79,3 +79,48 @@ Description: indicates a lane. crc_err_cnt: (RO) CRC err count on this port. ============= ==== ============================================= + +What: /sys/devices/platform/HISI04Bx:00/used_types +Date: August 2024 +KernelVersion: 6.12 +Contact: Huisong Li +Description: + This interface is used to show all HCCS types used on the + platform, like, HCCS-v1, HCCS-v2 and so on. + +What: /sys/devices/platform/HISI04Bx:00/available_inc_dec_lane_types +What: /sys/devices/platform/HISI04Bx:00/dec_lane_of_type +What: /sys/devices/platform/HISI04Bx:00/inc_lane_of_type +Date: August 2024 +KernelVersion: 6.12 +Contact: Huisong Li +Description: + These interfaces under /sys/devices/platform/HISI04Bx/ are + used to support the low power consumption feature of some + HCCS types by changing the number of lanes used. The interfaces + changing the number of lanes used are 'dec_lane_of_type' and + 'inc_lane_of_type' which require root privileges. These + interfaces aren't exposed if no HCCS type on platform support + this feature. Please note that decreasing lane number is only + allowed if all the specified HCCS ports are not busy. + + The low power consumption interfaces are as follows: + + ============================= ==== ================================ + available_inc_dec_lane_types: (RO) available HCCS types (string) to + increase and decrease the number + of lane used, e.g. HCCS-v2. + dec_lane_of_type: (WO) input HCCS type supported + decreasing lane to decrease the + used lane number of all specified + HCCS type ports on platform to + the minimum. + You can query the 'cur_lane_num' + to get the minimum lane number + after executing successfully. + inc_lane_of_type: (WO) input HCCS type supported + increasing lane to increase the + used lane number of all specified + HCCS type ports on platform to + the full lane state. + ============================= ==== ================================ diff --git a/Documentation/ABI/testing/sysfs-driver-hid-corsair-void b/Documentation/ABI/testing/sysfs-driver-hid-corsair-void new file mode 100644 index 00000000000000..83fa625c002521 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-hid-corsair-void @@ -0,0 +1,38 @@ +What: /sys/bus/hid/drivers/hid-corsair-void//fw_version_headset +Date: January 2024 +KernelVersion: 6.13 +Contact: Stuart Hayhurst +Description: (R) The firmware version of the headset + * Returns -ENODATA if no version was reported + +What: /sys/bus/hid/drivers/hid-corsair-void//fw_version_receiver +Date: January 2024 +KernelVersion: 6.13 +Contact: Stuart Hayhurst +Description: (R) The firmware version of the receiver + +What: /sys/bus/hid/drivers/hid-corsair-void//microphone_up +Date: July 2023 +KernelVersion: 6.13 +Contact: Stuart Hayhurst +Description: (R) Get the physical position of the microphone + * 1 -> Microphone up + * 0 -> Microphone down + +What: /sys/bus/hid/drivers/hid-corsair-void//send_alert +Date: July 2023 +KernelVersion: 6.13 +Contact: Stuart Hayhurst +Description: (W) Play a built-in notification from the headset (0 / 1) + +What: /sys/bus/hid/drivers/hid-corsair-void//set_sidetone +Date: December 2023 +KernelVersion: 6.13 +Contact: Stuart Hayhurst +Description: (W) Set the sidetone volume (0 - sidetone_max) + +What: /sys/bus/hid/drivers/hid-corsair-void//sidetone_max +Date: July 2024 +KernelVersion: 6.13 +Contact: Stuart Hayhurst +Description: (R) Report the maximum sidetone volume diff --git a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon index be4141a7522f6b..a885e5316d021f 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -83,3 +83,11 @@ Contact: intel-gfx@lists.freedesktop.org Description: RO. Fan speed of device in RPM. Only supported for particular Intel i915 graphics platforms. + +What: /sys/bus/pci/drivers/i915/.../hwmon/hwmon/temp1_input +Date: November 2024 +KernelVersion: 6.12 +Contact: intel-gfx@lists.freedesktop.org +Description: RO. GPU package temperature in millidegree Celsius. + + Only supported for particular Intel i915 graphics platforms. diff --git a/Documentation/ABI/testing/sysfs-driver-panthor-profiling b/Documentation/ABI/testing/sysfs-driver-panthor-profiling new file mode 100644 index 00000000000000..af05fccedc15f9 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-panthor-profiling @@ -0,0 +1,10 @@ +What: /sys/bus/platform/drivers/panthor/.../profiling +Date: September 2024 +KernelVersion: 6.11.0 +Contact: Adrian Larumbe +Description: + Bitmask to enable drm fdinfo's job profiling measurements. + Valid values are: + 0: Don't enable fdinfo job profiling sources. + 1: Enable GPU cycle measurements for running jobs. + 2: Enable GPU timestamp sampling for running jobs. diff --git a/Documentation/ABI/testing/sysfs-driver-spi-intel b/Documentation/ABI/testing/sysfs-driver-spi-intel new file mode 100644 index 00000000000000..d7c9139ddbf327 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-spi-intel @@ -0,0 +1,20 @@ +What: /sys/devices/.../intel_spi_protected +Date: Feb 2025 +KernelVersion: 6.13 +Contact: Alexander Usyskin +Description: This attribute allows the userspace to check if the + Intel SPI flash controller is write protected from the host. + +What: /sys/devices/.../intel_spi_locked +Date: Feb 2025 +KernelVersion: 6.13 +Contact: Alexander Usyskin +Description: This attribute allows the user space to check if the + Intel SPI flash controller locks supported opcodes. + +What: /sys/devices/.../intel_spi_bios_locked +Date: Feb 2025 +KernelVersion: 6.13 +Contact: Alexander Usyskin +Description: This attribute allows the user space to check if the + Intel SPI flash controller BIOS region is locked for writes. diff --git a/Documentation/ABI/testing/sysfs-fs-erofs b/Documentation/ABI/testing/sysfs-fs-erofs index 284224d1b56fe1..b134146d735bc5 100644 --- a/Documentation/ABI/testing/sysfs-fs-erofs +++ b/Documentation/ABI/testing/sysfs-fs-erofs @@ -16,3 +16,14 @@ Description: Control strategy of sync decompression: readahead on atomic contexts only. - 1 (force on): enable for readpage and readahead. - 2 (force off): disable for all situations. + +What: /sys/fs/erofs//drop_caches +Date: November 2024 +Contact: "Guo Chunhai" +Description: Writing to this will drop compression-related caches, + currently used to drop in-memory pclusters and cached + compressed folios: + + - 1 : invalidate cached compressed folios + - 2 : drop in-memory pclusters + - 3 : drop in-memory pclusters and cached compressed folios diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index fdedf1ea944ba8..3e1630c70d8ae7 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -311,10 +311,13 @@ Description: Do background GC aggressively when set. Set to 0 by default. GC approach and turns SSR mode on. gc urgent low(2): lowers the bar of checking I/O idling in order to process outstanding discard commands and GC a - little bit aggressively. uses cost benefit GC approach. + little bit aggressively. always uses cost benefit GC approach, + and will override age-threshold GC approach if ATGC is enabled + at the same time. gc urgent mid(3): does GC forcibly in a period of given gc_urgent_sleep_time and executes a mid level of I/O idling check. - uses cost benefit GC approach. + always uses cost benefit GC approach, and will override + age-threshold GC approach if ATGC is enabled at the same time. What: /sys/fs/f2fs//gc_urgent_sleep_time Date: August 2017 @@ -819,3 +822,9 @@ Description: It controls the valid block ratio threshold not to trigger excessiv for zoned deivces. The initial value of it is 95(%). F2FS will stop the background GC thread from intiating GC for sections having valid blocks exceeding the ratio. + +What: /sys/fs/f2fs//max_read_extent_count +Date: November 2024 +Contact: "Chao Yu" +Description: It controls max read extent count for per-inode, the value of threshold + is 10240 by default. diff --git a/Documentation/PCI/endpoint/pci-endpoint.rst b/Documentation/PCI/endpoint/pci-endpoint.rst index 21507e3cc2385c..35f82f2d45f5ef 100644 --- a/Documentation/PCI/endpoint/pci-endpoint.rst +++ b/Documentation/PCI/endpoint/pci-endpoint.rst @@ -117,6 +117,35 @@ by the PCI endpoint function driver. The PCI endpoint function driver should use pci_epc_mem_free_addr() to free the memory space allocated using pci_epc_mem_alloc_addr(). +* pci_epc_map_addr() + + A PCI endpoint function driver should use pci_epc_map_addr() to map to a RC + PCI address the CPU address of local memory obtained with + pci_epc_mem_alloc_addr(). + +* pci_epc_unmap_addr() + + A PCI endpoint function driver should use pci_epc_unmap_addr() to unmap the + CPU address of local memory mapped to a RC address with pci_epc_map_addr(). + +* pci_epc_mem_map() + + A PCI endpoint controller may impose constraints on the RC PCI addresses that + can be mapped. The function pci_epc_mem_map() allows endpoint function + drivers to allocate and map controller memory while handling such + constraints. This function will determine the size of the memory that must be + allocated with pci_epc_mem_alloc_addr() for successfully mapping a RC PCI + address range. This function will also indicate the size of the PCI address + range that was actually mapped, which can be less than the requested size, as + well as the offset into the allocated memory to use for accessing the mapped + RC PCI address range. + +* pci_epc_mem_unmap() + + A PCI endpoint function driver can use pci_epc_mem_unmap() to unmap and free + controller memory that was allocated and mapped using pci_epc_mem_map(). + + Other EPC APIs ~~~~~~~~~~~~~~ diff --git a/Documentation/PCI/index.rst b/Documentation/PCI/index.rst index e73f84aebde3b2..5e7c4e6e726bbf 100644 --- a/Documentation/PCI/index.rst +++ b/Documentation/PCI/index.rst @@ -18,3 +18,4 @@ PCI Bus Subsystem pcieaer-howto endpoint/index boot-interrupts + tph diff --git a/Documentation/PCI/pciebus-howto.rst b/Documentation/PCI/pciebus-howto.rst index f344452651e1f1..375d9ce171f623 100644 --- a/Documentation/PCI/pciebus-howto.rst +++ b/Documentation/PCI/pciebus-howto.rst @@ -217,8 +217,12 @@ capability structure except the PCI Express capability structure, that is shared between many drivers including the service drivers. RMW Capability accessors (pcie_capability_clear_and_set_word(), pcie_capability_set_word(), and pcie_capability_clear_word()) protect -a selected set of PCI Express Capability Registers (Link Control -Register and Root Control Register). Any change to those registers -should be performed using RMW accessors to avoid problems due to -concurrent updates. For the up-to-date list of protected registers, -see pcie_capability_clear_and_set_word(). +a selected set of PCI Express Capability Registers: + +* Link Control Register +* Root Control Register +* Link Control 2 Register + +Any change to those registers should be performed using RMW accessors to +avoid problems due to concurrent updates. For the up-to-date list of +protected registers, see pcie_capability_clear_and_set_word(). diff --git a/Documentation/PCI/tph.rst b/Documentation/PCI/tph.rst new file mode 100644 index 00000000000000..e8993be64fd64d --- /dev/null +++ b/Documentation/PCI/tph.rst @@ -0,0 +1,132 @@ +.. SPDX-License-Identifier: GPL-2.0 + + +=========== +TPH Support +=========== + +:Copyright: 2024 Advanced Micro Devices, Inc. +:Authors: - Eric van Tassell + - Wei Huang + + +Overview +======== + +TPH (TLP Processing Hints) is a PCIe feature that allows endpoint devices +to provide optimization hints for requests that target memory space. +These hints, in a format called Steering Tags (STs), are embedded in the +requester's TLP headers, enabling the system hardware, such as the Root +Complex, to better manage platform resources for these requests. + +For example, on platforms with TPH-based direct data cache injection +support, an endpoint device can include appropriate STs in its DMA +traffic to specify which cache the data should be written to. This allows +the CPU core to have a higher probability of getting data from cache, +potentially improving performance and reducing latency in data +processing. + + +How to Use TPH +============== + +TPH is presented as an optional extended capability in PCIe. The Linux +kernel handles TPH discovery during boot, but it is up to the device +driver to request TPH enablement if it is to be utilized. Once enabled, +the driver uses the provided API to obtain the Steering Tag for the +target memory and to program the ST into the device's ST table. + +Enable TPH support in Linux +--------------------------- + +To support TPH, the kernel must be built with the CONFIG_PCIE_TPH option +enabled. + +Manage TPH +---------- + +To enable TPH for a device, use the following function:: + + int pcie_enable_tph(struct pci_dev *pdev, int mode); + +This function enables TPH support for device with a specific ST mode. +Current supported modes include: + + * PCI_TPH_ST_NS_MODE - NO ST Mode + * PCI_TPH_ST_IV_MODE - Interrupt Vector Mode + * PCI_TPH_ST_DS_MODE - Device Specific Mode + +`pcie_enable_tph()` checks whether the requested mode is actually +supported by the device before enabling. The device driver can figure out +which TPH mode is supported and can be properly enabled based on the +return value of `pcie_enable_tph()`. + +To disable TPH, use the following function:: + + void pcie_disable_tph(struct pci_dev *pdev); + +Manage ST +--------- + +Steering Tags are platform specific. PCIe spec does not specify where STs +are from. Instead PCI Firmware Specification defines an ACPI _DSM method +(see the `Revised _DSM for Cache Locality TPH Features ECN +`_) for retrieving +STs for a target memory of various properties. This method is what is +supported in this implementation. + +To retrieve a Steering Tag for a target memory associated with a specific +CPU, use the following function:: + + int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type type, + unsigned int cpu_uid, u16 *tag); + +The `type` argument is used to specify the memory type, either volatile +or persistent, of the target memory. The `cpu_uid` argument specifies the +CPU where the memory is associated to. + +After the ST value is retrieved, the device driver can use the following +function to write the ST into the device:: + + int pcie_tph_set_st_entry(struct pci_dev *pdev, unsigned int index, + u16 tag); + +The `index` argument is the ST table entry index the ST tag will be +written into. `pcie_tph_set_st_entry()` will figure out the proper +location of ST table, either in the MSI-X table or in the TPH Extended +Capability space, and write the Steering Tag into the ST entry pointed by +the `index` argument. + +It is completely up to the driver to decide how to use these TPH +functions. For example a network device driver can use the TPH APIs above +to update the Steering Tag when interrupt affinity of a RX/TX queue has +been changed. Here is a sample code for IRQ affinity notifier: + +.. code-block:: c + + static void irq_affinity_notified(struct irq_affinity_notify *notify, + const cpumask_t *mask) + { + struct drv_irq *irq; + unsigned int cpu_id; + u16 tag; + + irq = container_of(notify, struct drv_irq, affinity_notify); + cpumask_copy(irq->cpu_mask, mask); + + /* Pick a right CPU as the target - here is just an example */ + cpu_id = cpumask_first(irq->cpu_mask); + + if (pcie_tph_get_cpu_st(irq->pdev, TPH_MEM_TYPE_VM, cpu_id, + &tag)) + return; + + if (pcie_tph_set_st_entry(irq->pdev, irq->msix_nr, tag)) + return; + } + +Disable TPH system-wide +----------------------- + +There is a kernel command line option available to control TPH feature: + * "notph": TPH will be disabled for all endpoint devices. diff --git a/Documentation/RCU/stallwarn.rst b/Documentation/RCU/stallwarn.rst index ca7b7cd806a16c..30080ff6f4062d 100644 --- a/Documentation/RCU/stallwarn.rst +++ b/Documentation/RCU/stallwarn.rst @@ -249,7 +249,7 @@ ticks this GP)" indicates that this CPU has not taken any scheduling-clock interrupts during the current stalled grace period. The "idle=" portion of the message prints the dyntick-idle state. -The hex number before the first "/" is the low-order 12 bits of the +The hex number before the first "/" is the low-order 16 bits of the dynticks counter, which will have an even-numbered value if the CPU is in dyntick-idle mode and an odd-numbered value otherwise. The hex number between the two "/"s is the value of the nesting, which will be diff --git a/Documentation/accel/qaic/aic080.rst b/Documentation/accel/qaic/aic080.rst new file mode 100644 index 00000000000000..d563771ea6ce48 --- /dev/null +++ b/Documentation/accel/qaic/aic080.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +=============================== + Qualcomm Cloud AI 80 (AIC080) +=============================== + +Overview +======== + +The Qualcomm Cloud AI 80/AIC080 family of products are a derivative of AIC100. +The number of NSPs and clock rates are reduced to fit within resource +constrained solutions. The PCIe Product ID is 0xa080. + +As a derivative product, all AIC100 documentation applies. diff --git a/Documentation/accel/qaic/aic100.rst b/Documentation/accel/qaic/aic100.rst index 590dae77ea124f..273da6192fb346 100644 --- a/Documentation/accel/qaic/aic100.rst +++ b/Documentation/accel/qaic/aic100.rst @@ -229,6 +229,8 @@ of the defined channels, and their uses. | _PERIODIC | | | timestamps in the device side logs with| | | | | the host time source. | +----------------+---------+----------+----------------------------------------+ +| IPCR | 24 & 25 | AMSS | AF_QIPCRTR clients and servers. | ++----------------+---------+----------+----------------------------------------+ DMA Bridge ========== diff --git a/Documentation/accel/qaic/index.rst b/Documentation/accel/qaic/index.rst index ad19b88d1a669e..967b9dd8baceac 100644 --- a/Documentation/accel/qaic/index.rst +++ b/Documentation/accel/qaic/index.rst @@ -10,4 +10,5 @@ accelerator cards. .. toctree:: qaic + aic080 aic100 diff --git a/Documentation/admin-guide/LSM/apparmor.rst b/Documentation/admin-guide/LSM/apparmor.rst index 6cf81bbd7ce8b8..47939ee89d7462 100644 --- a/Documentation/admin-guide/LSM/apparmor.rst +++ b/Documentation/admin-guide/LSM/apparmor.rst @@ -18,8 +18,11 @@ set ``CONFIG_SECURITY_APPARMOR=y`` If AppArmor should be selected as the default security module then set:: - CONFIG_DEFAULT_SECURITY="apparmor" - CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 + CONFIG_DEFAULT_SECURITY_APPARMOR=y + +The CONFIG_LSM parameter manages the order and selection of LSMs. +Specify apparmor as the first "major" module (e.g. AppArmor, SELinux, Smack) +in the list. Build the kernel diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst index 678d70d6e1c3ac..714a5171bfc0b8 100644 --- a/Documentation/admin-guide/blockdev/zram.rst +++ b/Documentation/admin-guide/blockdev/zram.rst @@ -47,6 +47,8 @@ The list of possible return codes: -ENOMEM zram was not able to allocate enough memory to fulfil your needs. -EINVAL invalid input has been provided. +-EAGAIN re-try operation later (e.g. when attempting to run recompress + and writeback simultaneously). ======== ============================================================= If you use 'echo', the returned value is set by the 'echo' utility, diff --git a/Documentation/admin-guide/bug-bisect.rst b/Documentation/admin-guide/bug-bisect.rst index 585630d14581c7..f4f867cabb1778 100644 --- a/Documentation/admin-guide/bug-bisect.rst +++ b/Documentation/admin-guide/bug-bisect.rst @@ -108,6 +108,27 @@ a fully reliable and straight-forward way to reproduce the regression, too.* With that the process is complete. Now report the regression as described by Documentation/admin-guide/reporting-issues.rst. +Bisecting linux-next +-------------------- + +If you face a problem only happening in linux-next, bisect between the +linux-next branches 'stable' and 'master'. The following commands will start +the process for a linux-next tree you added as a remote called 'next':: + + git bisect start + git bisect good next/stable + git bisect bad next/master + +The 'stable' branch refers to the state of linux-mainline that the current +linux-next release (found in the 'master' branch) is based on -- the former +thus should be free of any problems that show up in -next, but not in Linus' +tree. + +This will bisect across a wide range of changes, some of which you might have +used in earlier linux-next releases without problems. Sadly there is no simple +way to avoid checking them: bisecting from one linux-next release to a later +one (say between 'next-20241020' and 'next-20241021') is impossible, as they +share no common history. Additional reading material --------------------------- diff --git a/Documentation/admin-guide/cgroup-v1/memory.rst b/Documentation/admin-guide/cgroup-v1/memory.rst index 270501db9f4e85..286d16fc22ebb7 100644 --- a/Documentation/admin-guide/cgroup-v1/memory.rst +++ b/Documentation/admin-guide/cgroup-v1/memory.rst @@ -90,9 +90,7 @@ Brief summary of control files. used. memory.swappiness set/show swappiness parameter of vmscan (See sysctl's vm.swappiness) - memory.move_charge_at_immigrate set/show controls of moving charges - This knob is deprecated and shouldn't be - used. + memory.move_charge_at_immigrate This knob is deprecated. memory.oom_control set/show oom controls. This knob is deprecated and shouldn't be used. @@ -243,10 +241,6 @@ behind this approach is that a cgroup that aggressively uses a shared page will eventually get charged for it (once it is uncharged from the cgroup that brought it in -- this will happen on memory pressure). -But see :ref:`section 8.2 ` when moving a -task to another cgroup, its pages may be recharged to the new cgroup, if -move_charge_at_immigrate has been chosen. - 2.4 Swap Extension -------------------------------------- @@ -756,78 +750,8 @@ If we want to change this to 1G, we can at any time use:: THIS IS DEPRECATED! -It's expensive and unreliable! It's better practice to launch workload -tasks directly from inside their target cgroup. Use dedicated workload -cgroups to allow fine-grained policy adjustments without having to -move physical pages between control domains. - -Users can move charges associated with a task along with task migration, that -is, uncharge task's pages from the old cgroup and charge them to the new cgroup. -This feature is not supported in !CONFIG_MMU environments because of lack of -page tables. - -8.1 Interface -------------- - -This feature is disabled by default. It can be enabled (and disabled again) by -writing to memory.move_charge_at_immigrate of the destination cgroup. - -If you want to enable it:: - - # echo (some positive value) > memory.move_charge_at_immigrate - -.. note:: - Each bits of move_charge_at_immigrate has its own meaning about what type - of charges should be moved. See :ref:`section 8.2 - ` for details. - -.. note:: - Charges are moved only when you move mm->owner, in other words, - a leader of a thread group. - -.. note:: - If we cannot find enough space for the task in the destination cgroup, we - try to make space by reclaiming memory. Task migration may fail if we - cannot make enough space. - -.. note:: - It can take several seconds if you move charges much. - -And if you want disable it again:: - - # echo 0 > memory.move_charge_at_immigrate - -.. _cgroup-v1-memory-movable-charges: - -8.2 Type of charges which can be moved --------------------------------------- - -Each bit in move_charge_at_immigrate has its own meaning about what type of -charges should be moved. But in any case, it must be noted that an account of -a page or a swap can be moved only when it is charged to the task's current -(old) memory cgroup. - -+---+--------------------------------------------------------------------------+ -|bit| what type of charges would be moved ? | -+===+==========================================================================+ -| 0 | A charge of an anonymous page (or swap of it) used by the target task. | -| | You must enable Swap Extension (see 2.4) to enable move of swap charges. | -+---+--------------------------------------------------------------------------+ -| 1 | A charge of file pages (normal file, tmpfs file (e.g. ipc shared memory) | -| | and swaps of tmpfs file) mmapped by the target task. Unlike the case of | -| | anonymous pages, file pages (and swaps) in the range mmapped by the task | -| | will be moved even if the task hasn't done page fault, i.e. they might | -| | not be the task's "RSS", but other task's "RSS" that maps the same file. | -| | The mapcount of the page is ignored (the page can be moved independent | -| | of the mapcount). You must enable Swap Extension (see 2.4) to | -| | enable move of swap charges. | -+---+--------------------------------------------------------------------------+ - -8.3 TODO --------- - -- All of moving charge operations are done under cgroup_mutex. It's not good - behavior to hold the mutex too long, so we may need some trick. +Reading memory.move_charge_at_immigrate will always return 0 and writing +to it will always return -EINVAL. 9. Memory thresholds ==================== diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index 6d02168d78bed6..315ede811c9d0d 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -1655,6 +1655,11 @@ The following nested keys are defined. pgdemote_khugepaged Number of pages demoted by khugepaged. + hugetlb + Amount of memory used by hugetlb pages. This metric only shows + up if hugetlb usage is accounted for in memory.current (i.e. + cgroup is mounted with the memory_hugetlb_accounting option). + memory.numa_stat A read-only nested-keyed file which exists on non-root cgroups. @@ -2954,7 +2959,7 @@ following two functions. a queue (device) has been associated with the bio and before submission. - wbc_account_cgroup_owner(@wbc, @page, @bytes) + wbc_account_cgroup_owner(@wbc, @folio, @bytes) Should be called for each data segment being written out. While this function doesn't care exactly when it's called during the writeback session, it's the easiest and most diff --git a/Documentation/admin-guide/kernel-parameters.rst b/Documentation/admin-guide/kernel-parameters.rst index fdea7c26ef8040..59931f21c97497 100644 --- a/Documentation/admin-guide/kernel-parameters.rst +++ b/Documentation/admin-guide/kernel-parameters.rst @@ -27,6 +27,16 @@ kernel command line (/proc/cmdline) and collects module parameters when it loads a module, so the kernel command line can be used for loadable modules too. +This document may not be entirely up to date and comprehensive. The command +"modinfo -p ${modulename}" shows a current list of all parameters of a loadable +module. Loadable modules, after being loaded into the running kernel, also +reveal their parameters in /sys/module/${modulename}/parameters/. Some of these +parameters may be changed at runtime by the command +``echo -n ${value} > /sys/module/${modulename}/parameters/${parm}``. + +Special handling +---------------- + Hyphens (dashes) and underscores are equivalent in parameter names, so:: log_buf_len=1M print-fatal-signals=1 @@ -39,8 +49,8 @@ Double-quotes can be used to protect spaces in values, e.g.:: param="spaces in here" -cpu lists: ----------- +cpu lists +~~~~~~~~~ Some kernel parameters take a list of CPUs as a value, e.g. isolcpus, nohz_full, irqaffinity, rcu_nocbs. The format of this list is: @@ -82,12 +92,17 @@ so that "nohz_full=all" is the equivalent of "nohz_full=0-N". The semantics of "N" and "all" is supported on a level of bitmaps and holds for all users of bitmap_parselist(). -This document may not be entirely up to date and comprehensive. The command -"modinfo -p ${modulename}" shows a current list of all parameters of a loadable -module. Loadable modules, after being loaded into the running kernel, also -reveal their parameters in /sys/module/${modulename}/parameters/. Some of these -parameters may be changed at runtime by the command -``echo -n ${value} > /sys/module/${modulename}/parameters/${parm}``. +Metric suffixes +~~~~~~~~~~~~~~~ + +The [KMG] suffix is commonly described after a number of kernel +parameter values. 'K', 'M', 'G', 'T', 'P', and 'E' suffixes are allowed. +These letters represent the _binary_ multipliers 'Kilo', 'Mega', 'Giga', +'Tera', 'Peta', and 'Exa', equaling 2^10, 2^20, 2^30, 2^40, 2^50, and +2^60 bytes respectively. Such letter suffixes can also be entirely omitted. + +Kernel Build Options +-------------------- The parameters listed below are only valid if certain kernel build options were enabled and if respective hardware is present. This list should be kept @@ -159,6 +174,7 @@ is applicable:: SCSI Appropriate SCSI support is enabled. A lot of drivers have their options described inside the Documentation/scsi/ sub-directory. + SDW SoundWire support is enabled. SECURITY Different security models are enabled. SELINUX SELinux support is enabled. SERIAL Serial support is enabled. @@ -211,10 +227,5 @@ a fixed number of characters. This limit depends on the architecture and is between 256 and 4096 characters. It is defined in the file ./include/uapi/asm-generic/setup.h as COMMAND_LINE_SIZE. -Finally, the [KMG] suffix is commonly described after a number of kernel -parameter values. These 'K', 'M', and 'G' letters represent the _binary_ -multipliers 'Kilo', 'Mega', and 'Giga', equaling 2^10, 2^20, and 2^30 -bytes respectively. Such letter suffixes can also be entirely omitted: - .. include:: kernel-parameters.txt :literal: diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index d401577b5a6ace..3872bc6ec49d63 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -446,6 +446,9 @@ arm64.nobti [ARM64] Unconditionally disable Branch Target Identification support + arm64.nogcs [ARM64] Unconditionally disable Guarded Control Stack + support + arm64.nomops [ARM64] Unconditionally disable Memory Copy and Memory Set instructions support @@ -918,12 +921,16 @@ the parameter has no effect. crash_kexec_post_notifiers - Run kdump after running panic-notifiers and dumping - kmsg. This only for the users who doubt kdump always - succeeds in any situation. - Note that this also increases risks of kdump failure, - because some panic notifiers can make the crashed - kernel more unstable. + Only jump to kdump kernel after running the panic + notifiers and dumping kmsg. This option increases + the risks of a kdump failure, since some panic + notifiers can make the crashed kernel more unstable. + In configurations where kdump may not be reliable, + running the panic notifiers could allow collecting + more data on dmesg, like stack traces from other CPUS + or extra data dumped by panic_print. Note that some + configurations enable this option unconditionally, + like Hyper-V, PowerPC (fadump) and AMD SEV-SNP. crashkernel=size[KMG][@offset[KMG]] [KNL,EARLY] Using kexec, Linux can switch to a 'crash kernel' @@ -1546,6 +1553,7 @@ failslab= fail_usercopy= fail_page_alloc= + fail_skb_realloc= fail_make_request=[KNL] General fault injection mechanism. Format: ,,, @@ -4678,6 +4686,10 @@ nomio [S390] Do not use MIO instructions. norid [S390] ignore the RID field and force use of one PCI domain per PCI function + notph [PCIE] If the PCIE_TPH kernel config parameter + is enabled, this kernel boot option can be used + to disable PCIe TLP Processing Hints support + system-wide. pcie_aspm= [PCIE] Forcibly enable or ignore PCIe Active State Power Management. @@ -4810,6 +4822,11 @@ can be preempted anytime. Tasks will also yield contended spinlocks (if the critical section isn't explicitly preempt disabled beyond the lock itself). + lazy - Scheduler controlled. Similar to full but instead + of preempting the task immediately, the task gets + one HZ tick time to yield itself before the + preemption will be forced. One preemption is when the + task returns to user space. print-fatal-signals= [KNL] debug: print fatal signals @@ -5412,11 +5429,6 @@ Set time (jiffies) between CPU-hotplug operations, or zero to disable CPU-hotplug testing. - rcutorture.read_exit= [KNL] - Set the number of read-then-exit kthreads used - to test the interaction of RCU updaters and - task-exit processing. - rcutorture.read_exit_burst= [KNL] The number of times in a given read-then-exit episode that a set of read-then-exit kthreads @@ -5426,6 +5438,14 @@ The delay, in seconds, between successive read-then-exit testing episodes. + rcutorture.reader_flavor= [KNL] + A bit mask indicating which readers to use. + If there is more than one bit set, the readers + are entered from low-order bit up, and are + exited in the opposite order. For SRCU, the + 0x1 bit is normal readers, 0x2 NMI-safe readers, + and 0x4 light-weight readers. + rcutorture.shuffle_interval= [KNL] Set task-shuffle interval (s). Shuffling tasks allows some CPUs to go into dyntick-idle mode @@ -6060,6 +6080,10 @@ non-zero "wait" parameter. See weight_single and weight_many. + sdw_mclk_divider=[SDW] + Specify the MCLK divider for Intel SoundWire buses in + case the BIOS does not provide the clock rate properly. + skew_tick= [KNL,EARLY] Offset the periodic timer tick per cpu to mitigate xtime_lock contention on larger systems, and/or RCU lock contention on all systems with CONFIG_MAXSMP set. @@ -6147,6 +6171,16 @@ For more information see Documentation/mm/slub.rst. (slub_nomerge legacy name also accepted for now) + slab_strict_numa [MM] + Support memory policies on a per object level + in the slab allocator. The default is for memory + policies to be applied at the folio level when + a new folio is needed or a partial folio is + retrieved from the lists. Increases overhead + in the slab fastpaths but gains more accurate + NUMA kernel object placement which helps with slow + interconnects in NUMA systems. + slram= [HW,MTD] smart2= [HW] @@ -6700,6 +6734,16 @@ Force threading of all interrupt handlers except those marked explicitly IRQF_NO_THREAD. + thp_shmem= [KNL] + Format: [KMG],[KMG]:;[KMG]-[KMG]: + Control the default policy of each hugepage size for the + internal shmem mount. is one of policies available + for the shmem mount ("always", "inherit", "never", "within_size", + and "advise"). + It can be used multiple times for multiple shmem THP sizes. + See Documentation/admin-guide/mm/transhuge.rst for more + details. + topology= [S390,EARLY] Format: {off | on} Specify if the kernel should make use of the cpu @@ -6876,6 +6920,12 @@ reserve_mem=12M:4096:trace trace_instance=boot_map^traceoff^traceprintk@trace,sched,irq + Note, saving the trace buffer across reboots does require that the system + is set up to not wipe memory. For instance, CONFIG_RESET_ATTACK_MITIGATION + can force a memory reset on boot which will clear any trace that was stored. + This is just one of many ways that can clear memory. Make sure your system + keeps the content of memory across reboots before relying on this option. + See also Documentation/trace/debugging.rst @@ -6935,6 +6985,13 @@ See Documentation/admin-guide/mm/transhuge.rst for more details. + transparent_hugepage_shmem= [KNL] + Format: [always|within_size|advise|never|deny|force] + Can be used to control the hugepage allocation policy for + the internal shmem mount. + See Documentation/admin-guide/mm/transhuge.rst + for more details. + trusted.source= [KEYS] Format: This parameter identifies the trust source as a backend diff --git a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst index b6aeae3327ceb5..ea7fa2a8bbf0b9 100644 --- a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst +++ b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst @@ -315,7 +315,7 @@ To reduce its OS jitter, do at least one of the following: to do. Name: - rcuop/%d and rcuos/%d + rcuop/%d, rcuos/%d, and rcuog/%d Purpose: Offload RCU callbacks from the corresponding CPU. diff --git a/Documentation/admin-guide/media/building.rst b/Documentation/admin-guide/media/building.rst index a0647342991637..7a413ba07f93bb 100644 --- a/Documentation/admin-guide/media/building.rst +++ b/Documentation/admin-guide/media/building.rst @@ -15,7 +15,7 @@ Please notice, however, that, if: you should use the main media development tree ``master`` branch: - https://git.linuxtv.org/media_tree.git/ + https://git.linuxtv.org/media.git/ In this case, you may find some useful information at the `LinuxTv wiki pages `_: diff --git a/Documentation/admin-guide/media/index.rst b/Documentation/admin-guide/media/index.rst index be7e0e4482ca51..b11737ae6c0468 100644 --- a/Documentation/admin-guide/media/index.rst +++ b/Documentation/admin-guide/media/index.rst @@ -20,6 +20,11 @@ Documentation/driver-api/media/index.rst - for driver development information and Kernel APIs used by media devices; +Documentation/process/debugging/media_specific_debugging_guide.rst + + - for advice about essential tools and techniques to debug drivers on this + subsystem + .. toctree:: :caption: Table of Contents :maxdepth: 2 diff --git a/Documentation/admin-guide/media/omap4_camera.rst b/Documentation/admin-guide/media/omap4_camera.rst deleted file mode 100644 index 2ada9b1e6897f4..00000000000000 --- a/Documentation/admin-guide/media/omap4_camera.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -OMAP4 ISS Driver -================ - -Author: Sergio Aguirre - -Copyright (C) 2012, Texas Instruments - -Introduction ------------- - -The OMAP44XX family of chips contains the Imaging SubSystem (a.k.a. ISS), -Which contains several components that can be categorized in 3 big groups: - -- Interfaces (2 Interfaces: CSI2-A & CSI2-B/CCP2) -- ISP (Image Signal Processor) -- SIMCOP (Still Image Coprocessor) - -For more information, please look in [#f1]_ for latest version of: -"OMAP4430 Multimedia Device Silicon Revision 2.x" - -As of Revision AB, the ISS is described in detail in section 8. - -This driver is supporting **only** the CSI2-A/B interfaces for now. - -It makes use of the Media Controller framework [#f2]_, and inherited most of the -code from OMAP3 ISP driver (found under drivers/media/platform/ti/omap3isp/\*), -except that it doesn't need an IOMMU now for ISS buffers memory mapping. - -Supports usage of MMAP buffers only (for now). - -Tested platforms ----------------- - -- OMAP4430SDP, w/ ES2.1 GP & SEVM4430-CAM-V1-0 (Contains IMX060 & OV5640, in - which only the last one is supported, outputting YUV422 frames). - -- TI Blaze MDP, w/ OMAP4430 ES2.2 EMU (Contains 1 IMX060 & 2 OV5650 sensors, in - which only the OV5650 are supported, outputting RAW10 frames). - -- PandaBoard, Rev. A2, w/ OMAP4430 ES2.1 GP & OV adapter board, tested with - following sensors: - * OV5640 - * OV5650 - -- Tested on mainline kernel: - - http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=summary - - Tag: v3.3 (commit c16fa4f2ad19908a47c63d8fa436a1178438c7e7) - -File list ---------- -drivers/staging/media/omap4iss/ -include/linux/platform_data/media/omap4iss.h - -References ----------- - -.. [#f1] http://focus.ti.com/general/docs/wtbu/wtbudocumentcenter.tsp?navigationId=12037&templateId=6123#62 -.. [#f2] http://lwn.net/Articles/420485/ diff --git a/Documentation/admin-guide/media/raspberrypi-rp1-cfe.dot b/Documentation/admin-guide/media/raspberrypi-rp1-cfe.dot new file mode 100644 index 00000000000000..7717f229104963 --- /dev/null +++ b/Documentation/admin-guide/media/raspberrypi-rp1-cfe.dot @@ -0,0 +1,27 @@ +digraph board { + rankdir=TB + n00000001 [label="{{ 0} | csi2\n/dev/v4l-subdev0 | { 1 | 2 | 3 | 4}}", shape=Mrecord, style=filled, fillcolor=green] + n00000001:port1 -> n00000011 [style=dashed] + n00000001:port1 -> n00000007:port0 + n00000001:port2 -> n00000015 + n00000001:port2 -> n00000007:port0 [style=dashed] + n00000001:port3 -> n00000019 [style=dashed] + n00000001:port3 -> n00000007:port0 [style=dashed] + n00000001:port4 -> n0000001d [style=dashed] + n00000001:port4 -> n00000007:port0 [style=dashed] + n00000007 [label="{{ 0 | 1} | pisp-fe\n/dev/v4l-subdev1 | { 2 | 3 | 4}}", shape=Mrecord, style=filled, fillcolor=green] + n00000007:port2 -> n00000021 + n00000007:port3 -> n00000025 [style=dashed] + n00000007:port4 -> n00000029 + n0000000d [label="{imx219 6-0010\n/dev/v4l-subdev2 | { 0}}", shape=Mrecord, style=filled, fillcolor=green] + n0000000d:port0 -> n00000001:port0 [style=bold] + n00000011 [label="rp1-cfe-csi2-ch0\n/dev/video0", shape=box, style=filled, fillcolor=yellow] + n00000015 [label="rp1-cfe-csi2-ch1\n/dev/video1", shape=box, style=filled, fillcolor=yellow] + n00000019 [label="rp1-cfe-csi2-ch2\n/dev/video2", shape=box, style=filled, fillcolor=yellow] + n0000001d [label="rp1-cfe-csi2-ch3\n/dev/video3", shape=box, style=filled, fillcolor=yellow] + n00000021 [label="rp1-cfe-fe-image0\n/dev/video4", shape=box, style=filled, fillcolor=yellow] + n00000025 [label="rp1-cfe-fe-image1\n/dev/video5", shape=box, style=filled, fillcolor=yellow] + n00000029 [label="rp1-cfe-fe-stats\n/dev/video6", shape=box, style=filled, fillcolor=yellow] + n0000002d [label="rp1-cfe-fe-config\n/dev/video7", shape=box, style=filled, fillcolor=yellow] + n0000002d -> n00000007:port1 +} diff --git a/Documentation/admin-guide/media/raspberrypi-rp1-cfe.rst b/Documentation/admin-guide/media/raspberrypi-rp1-cfe.rst new file mode 100644 index 00000000000000..668d978a9875b7 --- /dev/null +++ b/Documentation/admin-guide/media/raspberrypi-rp1-cfe.rst @@ -0,0 +1,78 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================ +Raspberry Pi PiSP Camera Front End (rp1-cfe) +============================================ + +The PiSP Camera Front End +========================= + +The PiSP Camera Front End (CFE) is a module which combines a CSI-2 receiver with +a simple ISP, called the Front End (FE). + +The CFE has four DMA engines and can write frames from four separate streams +received from the CSI-2 to the memory. One of those streams can also be routed +directly to the FE, which can do minimal image processing, write two versions +(e.g. non-scaled and downscaled versions) of the received frames to memory and +provide statistics of the received frames. + +The FE registers are documented in the `Raspberry Pi Image Signal Processor +(ISP) Specification document +`_, +and example code for FE can be found in `libpisp +`_. + +The rp1-cfe driver +================== + +The Raspberry Pi PiSP Camera Front End (rp1-cfe) driver is located under +drivers/media/platform/raspberrypi/rp1-cfe. It uses the `V4L2 API` to register +a number of video capture and output devices, the `V4L2 subdev API` to register +subdevices for the CSI-2 received and the FE that connects the video devices in +a single media graph realized using the `Media Controller (MC) API`. + +The media topology registered by the `rp1-cfe` driver, in this particular +example connected to an imx219 sensor, is the following one: + +.. _rp1-cfe-topology: + +.. kernel-figure:: raspberrypi-rp1-cfe.dot + :alt: Diagram of an example media pipeline topology + :align: center + +The media graph contains the following video device nodes: + +- rp1-cfe-csi2-ch0: capture device for the first CSI-2 stream +- rp1-cfe-csi2-ch1: capture device for the second CSI-2 stream +- rp1-cfe-csi2-ch2: capture device for the third CSI-2 stream +- rp1-cfe-csi2-ch3: capture device for the fourth CSI-2 stream +- rp1-cfe-fe-image0: capture device for the first FE output +- rp1-cfe-fe-image1: capture device for the second FE output +- rp1-cfe-fe-stats: capture device for the FE statistics +- rp1-cfe-fe-config: output device for FE configuration + +rp1-cfe-csi2-chX +---------------- + +The rp1-cfe-csi2-chX capture devices are normal V4L2 capture devices which +can be used to capture video frames or metadata received from the CSI-2. + +rp1-cfe-fe-image0, rp1-cfe-fe-image1 +------------------------------------ + +The rp1-cfe-fe-image0 and rp1-cfe-fe-image1 capture devices are used to write +the processed frames to memory. + +rp1-cfe-fe-stats +---------------- + +The format of the FE statistics buffer is defined by +:c:type:`pisp_statistics` C structure and the meaning of each parameter is +described in the `PiSP specification` document. + +rp1-cfe-fe-config +----------------- + +The format of the FE configuration buffer is defined by +:c:type:`pisp_fe_config` C structure and the meaning of each parameter is +described in the `PiSP specification` document. diff --git a/Documentation/admin-guide/media/saa7134.rst b/Documentation/admin-guide/media/saa7134.rst index 51eae7eb5ab7f4..18d7cbc897db4b 100644 --- a/Documentation/admin-guide/media/saa7134.rst +++ b/Documentation/admin-guide/media/saa7134.rst @@ -67,7 +67,7 @@ Changes / Fixes Please mail to linux-media AT vger.kernel.org unified diffs against the linux media git tree: - https://git.linuxtv.org/media_tree.git/ + https://git.linuxtv.org/media.git/ This is done by committing a patch at a clone of the git tree and submitting the patch using ``git send-email``. Don't forget to diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst index b6af448b9fe978..e8761561b2fe7f 100644 --- a/Documentation/admin-guide/media/v4l-drivers.rst +++ b/Documentation/admin-guide/media/v4l-drivers.rst @@ -20,12 +20,12 @@ Video4Linux (V4L) driver-specific documentation ivtv mgb4 omap3isp - omap4_camera philips qcom_camss raspberrypi-pisp-be rcar-fdp1 rkisp1 + raspberrypi-rp1-cfe saa7134 si470x si4713 diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst index a1bb495eab59aa..5034915f4e8e89 100644 --- a/Documentation/admin-guide/mm/transhuge.rst +++ b/Documentation/admin-guide/mm/transhuge.rst @@ -326,6 +326,29 @@ PMD_ORDER THP policy will be overridden. If the policy for PMD_ORDER is not defined within a valid ``thp_anon``, its policy will default to ``never``. +Similarly to ``transparent_hugepage``, you can control the hugepage +allocation policy for the internal shmem mount by using the kernel parameter +``transparent_hugepage_shmem=``, where ```` is one of the +seven valid policies for shmem (``always``, ``within_size``, ``advise``, +``never``, ``deny``, and ``force``). + +In the same manner as ``thp_anon`` controls each supported anonymous THP +size, ``thp_shmem`` controls each supported shmem THP size. ``thp_shmem`` +has the same format as ``thp_anon``, but also supports the policy +``within_size``. + +``thp_shmem=`` may be specified multiple times to configure all THP sizes +as required. If ``thp_shmem=`` is specified at least once, any shmem THP +sizes not explicitly configured on the command line are implicitly set to +``never``. + +``transparent_hugepage_shmem`` setting only affects the global toggle. If +``thp_shmem`` is not specified, PMD_ORDER hugepage will default to +``inherit``. However, if a valid ``thp_shmem`` setting is provided by the +user, the PMD_ORDER hugepage policy will be overridden. If the policy for +PMD_ORDER is not defined within a valid ``thp_shmem``, its policy will +default to ``never``. + Hugepages in tmpfs/shmem ======================== @@ -530,10 +553,18 @@ anon_fault_fallback_charge instead falls back to using huge pages with lower orders or small pages even though the allocation was successful. -swpout - is incremented every time a huge page is swapped out in one +zswpout + is incremented every time a huge page is swapped out to zswap in one piece without splitting. +swpin + is incremented every time a huge page is swapped in from a non-zswap + swap device in one piece. + +swpout + is incremented every time a huge page is swapped out to a non-zswap + swap device in one piece without splitting. + swpout_fallback is incremented if a huge page has to be split before swapout. Usually because failed to allocate some continuous swap space diff --git a/Documentation/admin-guide/perf/index.rst b/Documentation/admin-guide/perf/index.rst index 8502bc174640a4..a58bd3f7e19079 100644 --- a/Documentation/admin-guide/perf/index.rst +++ b/Documentation/admin-guide/perf/index.rst @@ -26,3 +26,4 @@ Performance monitor support meson-ddr-pmu cxl ampere_cspmu + mrvl-pem-pmu diff --git a/Documentation/admin-guide/perf/mrvl-pem-pmu.rst b/Documentation/admin-guide/perf/mrvl-pem-pmu.rst new file mode 100644 index 00000000000000..c39007149b9734 --- /dev/null +++ b/Documentation/admin-guide/perf/mrvl-pem-pmu.rst @@ -0,0 +1,56 @@ +================================================================= +Marvell Odyssey PEM Performance Monitoring Unit (PMU UNCORE) +================================================================= + +The PCI Express Interface Units(PEM) are associated with a corresponding +monitoring unit. This includes performance counters to track various +characteristics of the data that is transmitted over the PCIe link. + +The counters track inbound and outbound transactions which +includes separate counters for posted/non-posted/completion TLPs. +Also, inbound and outbound memory read requests along with their +latencies can also be monitored. Address Translation Services(ATS)events +such as ATS Translation, ATS Page Request, ATS Invalidation along with +their corresponding latencies are also tracked. + +There are separate 64 bit counters to measure posted/non-posted/completion +tlps in inbound and outbound transactions. ATS events are measured by +different counters. + +The PMU driver exposes the available events and format options under sysfs, +/sys/bus/event_source/devices/mrvl_pcie_rc_pmu_<>/events/ +/sys/bus/event_source/devices/mrvl_pcie_rc_pmu_<>/format/ + +Examples:: + + # perf list | grep mrvl_pcie_rc_pmu + mrvl_pcie_rc_pmu_<>/ats_inv/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ats_inv_latency/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ats_pri/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ats_pri_latency/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ats_trans/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ats_trans_latency/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_inflight/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_reads/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_req_no_ro_ebus/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_req_no_ro_ncb/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_tlp_cpl_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_tlp_dwords_cpl_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_tlp_dwords_npr/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_tlp_dwords_pr/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_tlp_npr/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ib_tlp_pr/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_inflight_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_merges_cpl_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_merges_npr_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_merges_pr_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_reads_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_tlp_cpl_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_tlp_dwords_cpl_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_tlp_dwords_npr_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_tlp_dwords_pr_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_tlp_npr_partid/ [Kernel PMU event] + mrvl_pcie_rc_pmu_<>/ob_tlp_pr_partid/ [Kernel PMU event] + + + # perf stat -e ib_inflight,ib_reads,ib_req_no_ro_ebus,ib_req_no_ro_ncb diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst index 210a808b74ec2c..412423c54f2580 100644 --- a/Documentation/admin-guide/pm/amd-pstate.rst +++ b/Documentation/admin-guide/pm/amd-pstate.rst @@ -251,9 +251,7 @@ performance supported in `AMD CPPC Performance Capability `_). In some ASICs, the highest CPPC performance is not the one in the ``_CPC`` table, so we need to expose it to sysfs. If boost is not active, but still supported, this maximum frequency will be larger than the one in -``cpuinfo``. On systems that support preferred core, the driver will have -different values for some cores than others and this will reflect the values -advertised by the platform at bootup. +``cpuinfo``. This attribute is read-only. ``amd_pstate_lowest_nonlinear_freq`` diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst index 47499a1742bd49..f5ec6c9312e1da 100644 --- a/Documentation/admin-guide/sysctl/fs.rst +++ b/Documentation/admin-guide/sysctl/fs.rst @@ -38,6 +38,11 @@ requests. ``aio-max-nr`` allows you to change the maximum value ``aio-max-nr`` does not result in the pre-allocation or re-sizing of any kernel data structures. +dentry-negative +---------------------------- + +Policy for negative dentries. Set to 1 to to always delete the dentry when a +file is removed, and 0 to disable it. By default, this behavior is disabled. dentry-state ------------ @@ -332,3 +337,13 @@ Each "watch" costs roughly 90 bytes on a 32-bit kernel, and roughly 160 bytes on a 64-bit one. The current default value for ``max_user_watches`` is 4% of the available low memory, divided by the "watch" cost in bytes. + +5. /proc/sys/fs/fuse - Configuration options for FUSE filesystems +===================================================================== + +This directory contains the following configuration options for FUSE +filesystems: + +``/proc/sys/fs/fuse/max_pages_limit`` is a read/write file for +setting/getting the maximum number of pages that can be used for servicing +requests in FUSE. diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index f8bc1630eba056..b2b36d0c3094d7 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -401,6 +401,15 @@ The upper bound on the number of tasks that are checked. This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled. +hung_task_detect_count +====================== + +Indicates the total number of tasks that have been detected as hung since +the system boot. + +This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled. + + hung_task_timeout_secs ====================== diff --git a/Documentation/arch/arm64/arm-cca.rst b/Documentation/arch/arm64/arm-cca.rst new file mode 100644 index 00000000000000..c48b7d4ab6bde4 --- /dev/null +++ b/Documentation/arch/arm64/arm-cca.rst @@ -0,0 +1,69 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================================== +Arm Confidential Compute Architecture +===================================== + +Arm systems that support the Realm Management Extension (RME) contain +hardware to allow a VM guest to be run in a way which protects the code +and data of the guest from the hypervisor. It extends the older "two +world" model (Normal and Secure World) into four worlds: Normal, Secure, +Root and Realm. Linux can then also be run as a guest to a monitor +running in the Realm world. + +The monitor running in the Realm world is known as the Realm Management +Monitor (RMM) and implements the Realm Management Monitor +specification[1]. The monitor acts a bit like a hypervisor (e.g. it runs +in EL2 and manages the stage 2 page tables etc of the guests running in +Realm world), however much of the control is handled by a hypervisor +running in the Normal World. The Normal World hypervisor uses the Realm +Management Interface (RMI) defined by the RMM specification to request +the RMM to perform operations (e.g. mapping memory or executing a vCPU). + +The RMM defines an environment for guests where the address space (IPA) +is split into two. The lower half is protected - any memory that is +mapped in this half cannot be seen by the Normal World and the RMM +restricts what operations the Normal World can perform on this memory +(e.g. the Normal World cannot replace pages in this region without the +guest's cooperation). The upper half is shared, the Normal World is free +to make changes to the pages in this region, and is able to emulate MMIO +devices in this region too. + +A guest running in a Realm may also communicate with the RMM using the +Realm Services Interface (RSI) to request changes in its environment or +to perform attestation about its environment. In particular it may +request that areas of the protected address space are transitioned +between 'RAM' and 'EMPTY' (in either direction). This allows a Realm +guest to give up memory to be returned to the Normal World, or to +request new memory from the Normal World. Without an explicit request +from the Realm guest the RMM will otherwise prevent the Normal World +from making these changes. + +Linux as a Realm Guest +---------------------- + +To run Linux as a guest within a Realm, the following must be provided +either by the VMM or by a `boot loader` run in the Realm before Linux: + + * All protected RAM described to Linux (by DT or ACPI) must be marked + RIPAS RAM before handing control over to Linux. + + * MMIO devices must be either unprotected (e.g. emulated by the Normal + World) or marked RIPAS DEV. + + * MMIO devices emulated by the Normal World and used very early in boot + (specifically earlycon) must be specified in the upper half of IPA. + For earlycon this can be done by specifying the address on the + command line, e.g. with an IPA size of 33 bits and the base address + of the emulated UART at 0x1000000: ``earlycon=uart,mmio,0x101000000`` + + * Linux will use bounce buffers for communicating with unprotected + devices. It will transition some protected memory to RIPAS EMPTY and + expect to be able to access unprotected pages at the same IPA address + but with the highest valid IPA bit set. The expectation is that the + VMM will remove the physical pages from the protected mapping and + provide those pages as unprotected pages. + +References +---------- +[1] https://developer.arm.com/documentation/den0137/ diff --git a/Documentation/arch/arm64/booting.rst b/Documentation/arch/arm64/booting.rst index b57776a68f156d..3278fb4bf219da 100644 --- a/Documentation/arch/arm64/booting.rst +++ b/Documentation/arch/arm64/booting.rst @@ -41,6 +41,9 @@ to automatically locate and size all RAM, or it may use knowledge of the RAM in the machine, or any other method the boot loader designer sees fit.) +For Arm Confidential Compute Realms this includes ensuring that all +protected RAM has a Realm IPA state (RIPAS) of "RAM". + 2. Setup the device tree ------------------------- @@ -385,6 +388,9 @@ Before jumping into the kernel, the following conditions must be met: - HCRX_EL2.MSCEn (bit 11) must be initialised to 0b1. + - HCRX_EL2.MCE2 (bit 10) must be initialised to 0b1 and the hypervisor + must handle MOPS exceptions as described in :ref:`arm64_mops_hyp`. + For CPUs with the Extended Translation Control Register feature (FEAT_TCR2): - If EL3 is present: @@ -411,6 +417,38 @@ Before jumping into the kernel, the following conditions must be met: - HFGRWR_EL2.nPIRE0_EL1 (bit 57) must be initialised to 0b1. + - For CPUs with Guarded Control Stacks (FEAT_GCS): + + - GCSCR_EL1 must be initialised to 0. + + - GCSCRE0_EL1 must be initialised to 0. + + - If EL3 is present: + + - SCR_EL3.GCSEn (bit 39) must be initialised to 0b1. + + - If EL2 is present: + + - GCSCR_EL2 must be initialised to 0. + + - If the kernel is entered at EL1 and EL2 is present: + + - HCRX_EL2.GCSEn must be initialised to 0b1. + + - HFGITR_EL2.nGCSEPP (bit 59) must be initialised to 0b1. + + - HFGITR_EL2.nGCSSTR_EL1 (bit 58) must be initialised to 0b1. + + - HFGITR_EL2.nGCSPUSHM_EL1 (bit 57) must be initialised to 0b1. + + - HFGRTR_EL2.nGCS_EL1 (bit 53) must be initialised to 0b1. + + - HFGRTR_EL2.nGCS_EL0 (bit 52) must be initialised to 0b1. + + - HFGWTR_EL2.nGCS_EL1 (bit 53) must be initialised to 0b1. + + - HFGWTR_EL2.nGCS_EL0 (bit 52) must be initialised to 0b1. + The requirements described above for CPU mode, caches, MMUs, architected timers, coherency and system registers apply to all CPUs. All CPUs must enter the kernel in the same exception level. Where the values documented diff --git a/Documentation/arch/arm64/cpu-feature-registers.rst b/Documentation/arch/arm64/cpu-feature-registers.rst index 44f9bd78539d36..253e9743de2f96 100644 --- a/Documentation/arch/arm64/cpu-feature-registers.rst +++ b/Documentation/arch/arm64/cpu-feature-registers.rst @@ -152,6 +152,8 @@ infrastructure: +------------------------------+---------+---------+ | DIT | [51-48] | y | +------------------------------+---------+---------+ + | MPAM | [43-40] | n | + +------------------------------+---------+---------+ | SVE | [35-32] | y | +------------------------------+---------+---------+ | GIC | [27-24] | n | diff --git a/Documentation/arch/arm64/elf_hwcaps.rst b/Documentation/arch/arm64/elf_hwcaps.rst index 694f67fa07d196..2ff922a406ad83 100644 --- a/Documentation/arch/arm64/elf_hwcaps.rst +++ b/Documentation/arch/arm64/elf_hwcaps.rst @@ -16,9 +16,9 @@ architected discovery mechanism available to userspace code at EL0. The kernel exposes the presence of these features to userspace through a set of flags called hwcaps, exposed in the auxiliary vector. -Userspace software can test for features by acquiring the AT_HWCAP or -AT_HWCAP2 entry of the auxiliary vector, and testing whether the relevant -flags are set, e.g.:: +Userspace software can test for features by acquiring the AT_HWCAP, +AT_HWCAP2 or AT_HWCAP3 entry of the auxiliary vector, and testing +whether the relevant flags are set, e.g.:: bool floating_point_is_present(void) { @@ -170,6 +170,10 @@ HWCAP_PACG ID_AA64ISAR1_EL1.GPI == 0b0001, as described by Documentation/arch/arm64/pointer-authentication.rst. +HWCAP_GCS + Functionality implied by ID_AA64PFR1_EL1.GCS == 0b1, as + described by Documentation/arch/arm64/gcs.rst. + HWCAP2_DCPODP Functionality implied by ID_AA64ISAR1_EL1.DPB == 0b0010. diff --git a/Documentation/arch/arm64/gcs.rst b/Documentation/arch/arm64/gcs.rst new file mode 100644 index 00000000000000..1f65a3193e7765 --- /dev/null +++ b/Documentation/arch/arm64/gcs.rst @@ -0,0 +1,227 @@ +=============================================== +Guarded Control Stack support for AArch64 Linux +=============================================== + +This document outlines briefly the interface provided to userspace by Linux in +order to support use of the ARM Guarded Control Stack (GCS) feature. + +This is an outline of the most important features and issues only and not +intended to be exhaustive. + + + +1. General +----------- + +* GCS is an architecture feature intended to provide greater protection + against return oriented programming (ROP) attacks and to simplify the + implementation of features that need to collect stack traces such as + profiling. + +* When GCS is enabled a separate guarded control stack is maintained by the + PE which is writeable only through specific GCS operations. This + stores the call stack only, when a procedure call instruction is + performed the current PC is pushed onto the GCS and on RET the + address in the LR is verified against that on the top of the GCS. + +* When active the current GCS pointer is stored in the system register + GCSPR_EL0. This is readable by userspace but can only be updated + via specific GCS instructions. + +* The architecture provides instructions for switching between guarded + control stacks with checks to ensure that the new stack is a valid + target for switching. + +* The functionality of GCS is similar to that provided by the x86 Shadow + Stack feature, due to sharing of userspace interfaces the ABI refers to + shadow stacks rather than GCS. + +* Support for GCS is reported to userspace via HWCAP_GCS in the aux vector + AT_HWCAP2 entry. + +* GCS is enabled per thread. While there is support for disabling GCS + at runtime this should be done with great care. + +* GCS memory access faults are reported as normal memory access faults. + +* GCS specific errors (those reported with EC 0x2d) will be reported as + SIGSEGV with a si_code of SEGV_CPERR (control protection error). + +* GCS is supported only for AArch64. + +* On systems where GCS is supported GCSPR_EL0 is always readable by EL0 + regardless of the GCS configuration for the thread. + +* The architecture supports enabling GCS without verifying that return values + in LR match those in the GCS, the LR will be ignored. This is not supported + by Linux. + + + +2. Enabling and disabling Guarded Control Stacks +------------------------------------------------- + +* GCS is enabled and disabled for a thread via the PR_SET_SHADOW_STACK_STATUS + prctl(), this takes a single flags argument specifying which GCS features + should be used. + +* When set PR_SHADOW_STACK_ENABLE flag allocates a Guarded Control Stack + and enables GCS for the thread, enabling the functionality controlled by + GCSCRE0_EL1.{nTR, RVCHKEN, PCRSEL}. + +* When set the PR_SHADOW_STACK_PUSH flag enables the functionality controlled + by GCSCRE0_EL1.PUSHMEn, allowing explicit GCS pushes. + +* When set the PR_SHADOW_STACK_WRITE flag enables the functionality controlled + by GCSCRE0_EL1.STREn, allowing explicit stores to the Guarded Control Stack. + +* Any unknown flags will cause PR_SET_SHADOW_STACK_STATUS to return -EINVAL. + +* PR_LOCK_SHADOW_STACK_STATUS is passed a bitmask of features with the same + values as used for PR_SET_SHADOW_STACK_STATUS. Any future changes to the + status of the specified GCS mode bits will be rejected. + +* PR_LOCK_SHADOW_STACK_STATUS allows any bit to be locked, this allows + userspace to prevent changes to any future features. + +* There is no support for a process to remove a lock that has been set for + it. + +* PR_SET_SHADOW_STACK_STATUS and PR_LOCK_SHADOW_STACK_STATUS affect only the + thread that called them, any other running threads will be unaffected. + +* New threads inherit the GCS configuration of the thread that created them. + +* GCS is disabled on exec(). + +* The current GCS configuration for a thread may be read with the + PR_GET_SHADOW_STACK_STATUS prctl(), this returns the same flags that + are passed to PR_SET_SHADOW_STACK_STATUS. + +* If GCS is disabled for a thread after having previously been enabled then + the stack will remain allocated for the lifetime of the thread. At present + any attempt to reenable GCS for the thread will be rejected, this may be + revisited in future. + +* It should be noted that since enabling GCS will result in GCS becoming + active immediately it is not normally possible to return from the function + that invoked the prctl() that enabled GCS. It is expected that the normal + usage will be that GCS is enabled very early in execution of a program. + + + +3. Allocation of Guarded Control Stacks +---------------------------------------- + +* When GCS is enabled for a thread a new Guarded Control Stack will be + allocated for it of half the standard stack size or 2 gigabytes, + whichever is smaller. + +* When a new thread is created by a thread which has GCS enabled then a + new Guarded Control Stack will be allocated for the new thread with + half the size of the standard stack. + +* When a stack is allocated by enabling GCS or during thread creation then + the top 8 bytes of the stack will be initialised to 0 and GCSPR_EL0 will + be set to point to the address of this 0 value, this can be used to + detect the top of the stack. + +* Additional Guarded Control Stacks can be allocated using the + map_shadow_stack() system call. + +* Stacks allocated using map_shadow_stack() can optionally have an end of + stack marker and cap placed at the top of the stack. If the flag + SHADOW_STACK_SET_TOKEN is specified a cap will be placed on the stack, + if SHADOW_STACK_SET_MARKER is not specified the cap will be the top 8 + bytes of the stack and if it is specified then the cap will be the next + 8 bytes. While specifying just SHADOW_STACK_SET_MARKER by itself is + valid since the marker is all bits 0 it has no observable effect. + +* Stacks allocated using map_shadow_stack() must have a size which is a + multiple of 8 bytes larger than 8 bytes and must be 8 bytes aligned. + +* An address can be specified to map_shadow_stack(), if one is provided then + it must be aligned to a page boundary. + +* When a thread is freed the Guarded Control Stack initially allocated for + that thread will be freed. Note carefully that if the stack has been + switched this may not be the stack currently in use by the thread. + + +4. Signal handling +-------------------- + +* A new signal frame record gcs_context encodes the current GCS mode and + pointer for the interrupted context on signal delivery. This will always + be present on systems that support GCS. + +* The record contains a flag field which reports the current GCS configuration + for the interrupted context as PR_GET_SHADOW_STACK_STATUS would. + +* The signal handler is run with the same GCS configuration as the interrupted + context. + +* When GCS is enabled for the interrupted thread a signal handling specific + GCS cap token will be written to the GCS, this is an architectural GCS cap + with the token type (bits 0..11) all clear. The GCSPR_EL0 reported in the + signal frame will point to this cap token. + +* The signal handler will use the same GCS as the interrupted context. + +* When GCS is enabled on signal entry a frame with the address of the signal + return handler will be pushed onto the GCS, allowing return from the signal + handler via RET as normal. This will not be reported in the gcs_context in + the signal frame. + + +5. Signal return +----------------- + +When returning from a signal handler: + +* If there is a gcs_context record in the signal frame then the GCS flags + and GCSPR_EL0 will be restored from that context prior to further + validation. + +* If there is no gcs_context record in the signal frame then the GCS + configuration will be unchanged. + +* If GCS is enabled on return from a signal handler then GCSPR_EL0 must + point to a valid GCS signal cap record, this will be popped from the + GCS prior to signal return. + +* If the GCS configuration is locked when returning from a signal then any + attempt to change the GCS configuration will be treated as an error. This + is true even if GCS was not enabled prior to signal entry. + +* GCS may be disabled via signal return but any attempt to enable GCS via + signal return will be rejected. + + +6. ptrace extensions +--------------------- + +* A new regset NT_ARM_GCS is defined for use with PTRACE_GETREGSET and + PTRACE_SETREGSET. + +* The GCS mode, including enable and disable, may be configured via ptrace. + If GCS is enabled via ptrace no new GCS will be allocated for the thread. + +* Configuration via ptrace ignores locking of GCS mode bits. + + +7. ELF coredump extensions +--------------------------- + +* NT_ARM_GCS notes will be added to each coredump for each thread of the + dumped process. The contents will be equivalent to the data that would + have been read if a PTRACE_GETREGSET of the corresponding type were + executed for each thread when the coredump was generated. + + + +8. /proc extensions +-------------------- + +* Guarded Control Stack pages will include "ss" in their VmFlags in + /proc//smaps. diff --git a/Documentation/arch/arm64/index.rst b/Documentation/arch/arm64/index.rst index 78544de0a8a9e8..6a012c98bdcd3b 100644 --- a/Documentation/arch/arm64/index.rst +++ b/Documentation/arch/arm64/index.rst @@ -10,16 +10,19 @@ ARM64 Architecture acpi_object_usage amu arm-acpi + arm-cca asymmetric-32bit booting cpu-feature-registers cpu-hotplug elf_hwcaps + gcs hugetlbpage kdump legacy_instructions memory memory-tagging-extension + mops perf pointer-authentication ptdump diff --git a/Documentation/arch/arm64/mops.rst b/Documentation/arch/arm64/mops.rst new file mode 100644 index 00000000000000..2ef5b147f8dc6b --- /dev/null +++ b/Documentation/arch/arm64/mops.rst @@ -0,0 +1,44 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================== +Memory copy/set instructions (MOPS) +=================================== + +A MOPS memory copy/set operation consists of three consecutive CPY* or SET* +instructions: a prologue, main and epilogue (for example: CPYP, CPYM, CPYE). + +A main or epilogue instruction can take a MOPS exception for various reasons, +for example when a task is migrated to a CPU with a different MOPS +implementation, or when the instruction's alignment and size requirements are +not met. The software exception handler is then expected to reset the registers +and restart execution from the prologue instruction. Normally this is handled +by the kernel. + +For more details refer to "D1.3.5.7 Memory Copy and Memory Set exceptions" in +the Arm Architecture Reference Manual DDI 0487K.a (Arm ARM). + +.. _arm64_mops_hyp: + +Hypervisor requirements +----------------------- + +A hypervisor running a Linux guest must handle all MOPS exceptions from the +guest kernel, as Linux may not be able to handle the exception at all times. +For example, a MOPS exception can be taken when the hypervisor migrates a vCPU +to another physical CPU with a different MOPS implementation. + +To do this, the hypervisor must: + + - Set HCRX_EL2.MCE2 to 1 so that the exception is taken to the hypervisor. + + - Have an exception handler that implements the algorithm from the Arm ARM + rules CNTMJ and MWFQH. + + - Set the guest's PSTATE.SS to 0 in the exception handler, to handle a + potential step of the current instruction. + + Note: Clearing PSTATE.SS is needed so that a single step exception is taken + on the next instruction (the prologue instruction). Otherwise prologue + would get silently stepped over and the single step exception taken on the + main instruction. Note that if the guest instruction is not being stepped + then clearing PSTATE.SS has no effect. diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst index 65bfab1b186146..b42fea07c5cec8 100644 --- a/Documentation/arch/arm64/silicon-errata.rst +++ b/Documentation/arch/arm64/silicon-errata.rst @@ -255,8 +255,11 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | Hisilicon | Hip08 SMMU PMCG | #162001800 | N/A | +----------------+-----------------+-----------------+-----------------------------+ -| Hisilicon | Hip{08,09,10,10C| #162001900 | N/A | -| | ,11} SMMU PMCG | | | +| Hisilicon | Hip{08,09,09A,10| #162001900 | N/A | +| | ,10C,11} | | | +| | SMMU PMCG | | | ++----------------+-----------------+-----------------+-----------------------------+ +| Hisilicon | Hip09 | #162100801 | HISILICON_ERRATUM_162100801 | +----------------+-----------------+-----------------+-----------------------------+ +----------------+-----------------+-----------------+-----------------------------+ | Qualcomm Tech. | Kryo/Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 | diff --git a/Documentation/arch/arm64/sme.rst b/Documentation/arch/arm64/sme.rst index be317d45741743..b2fa01f85cb5e3 100644 --- a/Documentation/arch/arm64/sme.rst +++ b/Documentation/arch/arm64/sme.rst @@ -346,6 +346,10 @@ The regset data starts with struct user_za_header, containing: * Writes to NT_ARM_ZT will set PSTATE.ZA to 1. +* If any register data is provided along with SME_PT_VL_ONEXEC then the + registers data will be interpreted with the current vector length, not + the vector length configured for use on exec. + 8. ELF coredump extensions --------------------------- diff --git a/Documentation/arch/arm64/sve.rst b/Documentation/arch/arm64/sve.rst index 8d8837fc39ec71..28152492c29cbc 100644 --- a/Documentation/arch/arm64/sve.rst +++ b/Documentation/arch/arm64/sve.rst @@ -402,6 +402,10 @@ The regset data starts with struct user_sve_header, containing: streaming mode and any SETREGSET of NT_ARM_SSVE will enter streaming mode if the target was not in streaming mode. +* If any register data is provided along with SVE_PT_VL_ONEXEC then the + registers data will be interpreted with the current vector length, not + the vector length configured for use on exec. + * The effect of writing a partial, incomplete payload is unspecified. diff --git a/Documentation/arch/loongarch/irq-chip-model.rst b/Documentation/arch/loongarch/irq-chip-model.rst index 6dd48256e39f74..a7ecce11e445c4 100644 --- a/Documentation/arch/loongarch/irq-chip-model.rst +++ b/Documentation/arch/loongarch/irq-chip-model.rst @@ -85,6 +85,70 @@ to CPUINTC directly:: | Devices | +---------+ +Virtual Extended IRQ model +========================== + +In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interrupt +go to CPUINTC directly, CPU UARTS interrupts go to PCH-PIC, while all other +devices interrupts go to PCH-PIC/PCH-MSI and gathered by V-EIOINTC (Virtual +Extended I/O Interrupt Controller), and then go to CPUINTC directly:: + + +-----+ +-------------------+ +-------+ + | IPI |--> | CPUINTC(0-255vcpu)| <-- | Timer | + +-----+ +-------------------+ +-------+ + ^ + | + +-----------+ + | V-EIOINTC | + +-----------+ + ^ ^ + | | + +---------+ +---------+ + | PCH-PIC | | PCH-MSI | + +---------+ +---------+ + ^ ^ ^ + | | | + +--------+ +---------+ +---------+ + | UARTs | | Devices | | Devices | + +--------+ +---------+ +---------+ + + +Description +----------- +V-EIOINTC (Virtual Extended I/O Interrupt Controller) is an extension of +EIOINTC, it only works in VM mode which runs in KVM hypervisor. Interrupts can +be routed to up to four vCPUs via standard EIOINTC, however with V-EIOINTC +interrupts can be routed to up to 256 virtual cpus. + +With standard EIOINTC, interrupt routing setting includes two parts: eight +bits for CPU selection and four bits for CPU IP (Interrupt Pin) selection. +For CPU selection there is four bits for EIOINTC node selection, four bits +for EIOINTC CPU selection. Bitmap method is used for CPU selection and +CPU IP selection, so interrupt can only route to CPU0 - CPU3 and IP0-IP3 in +one EIOINTC node. + +With V-EIOINTC it supports to route more CPUs and CPU IP (Interrupt Pin), +there are two newly added registers with V-EIOINTC. + +EXTIOI_VIRT_FEATURES +-------------------- +This register is read-only register, which indicates supported features with +V-EIOINTC. Feature EXTIOI_HAS_INT_ENCODE and EXTIOI_HAS_CPU_ENCODE is added. + +Feature EXTIOI_HAS_INT_ENCODE is part of standard EIOINTC. If it is 1, it +indicates that CPU Interrupt Pin selection can be normal method rather than +bitmap method, so interrupt can be routed to IP0 - IP15. + +Feature EXTIOI_HAS_CPU_ENCODE is entension of V-EIOINTC. If it is 1, it +indicates that CPU selection can be normal method rather than bitmap method, +so interrupt can be routed to CPU0 - CPU255. + +EXTIOI_VIRT_CONFIG +------------------ +This register is read-write register, for compatibility intterupt routed uses +the default method which is the same with standard EIOINTC. If the bit is set +with 1, it indicated HW to use normal method rather than bitmap method. + Advanced Extended IRQ model =========================== diff --git a/Documentation/arch/powerpc/booting.rst b/Documentation/arch/powerpc/booting.rst index 11aa440f98cc9c..472e97891aef21 100644 --- a/Documentation/arch/powerpc/booting.rst +++ b/Documentation/arch/powerpc/booting.rst @@ -93,8 +93,8 @@ given platform based on the content of the device-tree. Thus, you should: a) add your platform support as a _boolean_ option in - arch/powerpc/Kconfig, following the example of PPC_PSERIES, - PPC_PMAC and PPC_MAPLE. The latter is probably a good + arch/powerpc/Kconfig, following the example of PPC_PSERIES + and PPC_PMAC. The latter is probably a good example of a board support to start from. b) create your main platform file as diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst index 85b709257918ad..955fbcd19ce90f 100644 --- a/Documentation/arch/riscv/hwprobe.rst +++ b/Documentation/arch/riscv/hwprobe.rst @@ -239,6 +239,9 @@ The following keys are defined: ratified in commit 98918c844281 ("Merge pull request #1217 from riscv/zawrs") of riscv-isa-manual. + * :c:macro:`RISCV_HWPROBE_EXT_SUPM`: The Supm extension is supported as + defined in version 1.0 of the RISC-V Pointer Masking extensions. + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated. Returns similar values to :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was mistakenly classified as a bitmask rather than a value. @@ -274,3 +277,19 @@ The following keys are defined: represent the highest userspace virtual address usable. * :c:macro:`RISCV_HWPROBE_KEY_TIME_CSR_FREQ`: Frequency (in Hz) of `time CSR`. + +* :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF`: An enum value describing the + performance of misaligned vector accesses on the selected set of processors. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN`: The performance of misaligned + vector accesses is unknown. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW`: 32-bit misaligned accesses using vector + registers are slower than the equivalent quantity of byte accesses via vector registers. + Misaligned accesses may be supported directly in hardware, or trapped and emulated by software. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_FAST`: 32-bit misaligned accesses using vector + registers are faster than the equivalent quantity of byte accesses via vector registers. + + * :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED`: Misaligned vector accesses are + not supported at all and will generate a misaligned address fault. diff --git a/Documentation/arch/riscv/uabi.rst b/Documentation/arch/riscv/uabi.rst index 2b420bab0527a7..243e40062e34ed 100644 --- a/Documentation/arch/riscv/uabi.rst +++ b/Documentation/arch/riscv/uabi.rst @@ -68,3 +68,19 @@ Misaligned accesses Misaligned scalar accesses are supported in userspace, but they may perform poorly. Misaligned vector accesses are only supported if the Zicclsm extension is supported. + +Pointer masking +--------------- + +Support for pointer masking in userspace (the Supm extension) is provided via +the ``PR_SET_TAGGED_ADDR_CTRL`` and ``PR_GET_TAGGED_ADDR_CTRL`` ``prctl()`` +operations. Pointer masking is disabled by default. To enable it, userspace +must call ``PR_SET_TAGGED_ADDR_CTRL`` with the ``PR_PMLEN`` field set to the +number of mask/tag bits needed by the application. ``PR_PMLEN`` is interpreted +as a lower bound; if the kernel is unable to satisfy the request, the +``PR_SET_TAGGED_ADDR_CTRL`` operation will fail. The actual number of tag bits +is returned in ``PR_PMLEN`` by the ``PR_GET_TAGGED_ADDR_CTRL`` operation. + +Additionally, when pointer masking is enabled (``PR_PMLEN`` is greater than 0), +a tagged address ABI is supported, with the same interface and behavior as +documented for AArch64 (Documentation/arch/arm64/tagged-address-abi.rst). diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst index 1e499ecf5f4ef4..2fd917638e426d 100644 --- a/Documentation/arch/x86/amd_hsmp.rst +++ b/Documentation/arch/x86/amd_hsmp.rst @@ -4,8 +4,9 @@ AMD HSMP interface ============================================ -Newer Fam19h EPYC server line of processors from AMD support system -management functionality via HSMP (Host System Management Port). +Newer Fam19h(model 0x00-0x1f, 0x30-0x3f, 0x90-0x9f, 0xa0-0xaf), +Fam1Ah(model 0x00-0x1f) EPYC server line of processors from AMD support +system management functionality via HSMP (Host System Management Port). The Host System Management Port (HSMP) is an interface to provide OS-level software with access to system management functions via a @@ -16,14 +17,25 @@ More details on the interface can be found in chapter Eg: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/programmer-references/55898_B1_pub_0_50.zip -HSMP interface is supported on EPYC server CPU models only. +HSMP interface is supported on EPYC line of server CPUs and MI300A (APU). HSMP device ============================================ -amd_hsmp driver under the drivers/platforms/x86/ creates miscdevice -/dev/hsmp to let user space programs run hsmp mailbox commands. +amd_hsmp driver under drivers/platforms/x86/amd/hsmp/ has separate driver files +for ACPI object based probing, platform device based probing and for the common +code for these two drivers. + +Kconfig option CONFIG_AMD_HSMP_PLAT compiles plat.c and creates amd_hsmp.ko. +Kconfig option CONFIG_AMD_HSMP_ACPI compiles acpi.c and creates hsmp_acpi.ko. +Selecting any of these two configs automatically selects CONFIG_AMD_HSMP. This +compiles common code hsmp.c and creates hsmp_common.ko module. + +Both the ACPI and plat drivers create the miscdevice /dev/hsmp to let +user space programs run hsmp mailbox commands. + +The ACPI object format supported by the driver is defined below. $ ls -al /dev/hsmp crw-r--r-- 1 root root 10, 123 Jan 21 21:41 /dev/hsmp @@ -59,6 +71,51 @@ Note: lseek() is not supported as entire metrics table is read. Metrics table definitions will be documented as part of Public PPR. The same is defined in the amd_hsmp.h header. +ACPI device object format +========================= +The ACPI object format expected from the amd_hsmp driver +for socket with ID00 is given below:: + + Device(HSMP) + { + Name(_HID, "AMDI0097") + Name(_UID, "ID00") + Name(HSE0, 0x00000001) + Name(RBF0, ResourceTemplate() + { + Memory32Fixed(ReadWrite, 0xxxxxxx, 0x00100000) + }) + Method(_CRS, 0, NotSerialized) + { + Return(RBF0) + } + Method(_STA, 0, NotSerialized) + { + If(LEqual(HSE0, One)) + { + Return(0x0F) + } + Else + { + Return(Zero) + } + } + Name(_DSD, Package(2) + { + Buffer(0x10) + { + 0x9D, 0x61, 0x4D, 0xB7, 0x07, 0x57, 0xBD, 0x48, + 0xA6, 0x9F, 0x4E, 0xA2, 0x87, 0x1F, 0xC2, 0xF6 + }, + Package(3) + { + Package(2) {"MsgIdOffset", 0x00010934}, + Package(2) {"MsgRspOffset", 0x00010980}, + Package(2) {"MsgArgOffset", 0x000109E0} + } + }) + } + An example ========== diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst index 4fd492cb49704f..ad2d8ddad27fe4 100644 --- a/Documentation/arch/x86/boot.rst +++ b/Documentation/arch/x86/boot.rst @@ -896,10 +896,19 @@ Offset/size: 0x260/4 The kernel runtime start address is determined by the following algorithm:: - if (relocatable_kernel) - runtime_start = align_up(load_address, kernel_alignment) - else - runtime_start = pref_address + if (relocatable_kernel) { + if (load_address < pref_address) + load_address = pref_address; + runtime_start = align_up(load_address, kernel_alignment); + } else { + runtime_start = pref_address; + } + +Hence the necessary memory window location and size can be estimated by +a boot loader as:: + + memory_window_start = runtime_start; + memory_window_size = init_size; ============ =============== Field name: handover_offset diff --git a/Documentation/arch/x86/buslock.rst b/Documentation/arch/x86/buslock.rst index 4c5a4822eeb70b..31f1bfdff16f88 100644 --- a/Documentation/arch/x86/buslock.rst +++ b/Documentation/arch/x86/buslock.rst @@ -26,7 +26,8 @@ Detection ========= Intel processors may support either or both of the following hardware -mechanisms to detect split locks and bus locks. +mechanisms to detect split locks and bus locks. Some AMD processors also +support bus lock detect. #AC exception for split lock detection -------------------------------------- diff --git a/Documentation/arch/x86/x86_64/boot-options.rst b/Documentation/arch/x86/x86_64/boot-options.rst index 98d4805f0823a1..d69e3cfbdba5a5 100644 --- a/Documentation/arch/x86/x86_64/boot-options.rst +++ b/Documentation/arch/x86/x86_64/boot-options.rst @@ -305,3 +305,8 @@ The available options are: debug Enable debug messages. + + nosnp + Do not enable SEV-SNP (applies to host/hypervisor only). Setting + 'nosnp' avoids the RMP check overhead in memory accesses when + users do not want to run SEV-SNP guests. diff --git a/Documentation/arch/x86/x86_64/mm.rst b/Documentation/arch/x86/x86_64/mm.rst index 35e5e18c83d04b..f2db178b353f8e 100644 --- a/Documentation/arch/x86/x86_64/mm.rst +++ b/Documentation/arch/x86/x86_64/mm.rst @@ -29,15 +29,27 @@ Complete virtual memory map with 4-level page tables Start addr | Offset | End addr | Size | VM area description ======================================================================================================================== | | | | - 0000000000000000 | 0 | 00007fffffffffff | 128 TB | user-space virtual memory, different per mm + 0000000000000000 | 0 | 00007fffffffefff | ~128 TB | user-space virtual memory, different per mm + 00007ffffffff000 | ~128 TB | 00007fffffffffff | 4 kB | ... guard hole __________________|____________|__________________|_________|___________________________________________________________ | | | | - 0000800000000000 | +128 TB | ffff7fffffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical - | | | | virtual memory addresses up to the -128 TB + 0000800000000000 | +128 TB | 7fffffffffffffff | ~8 EB | ... huge, almost 63 bits wide hole of non-canonical + | | | | virtual memory addresses up to the -8 EB | | | | starting offset of kernel mappings. + | | | | + | | | | LAM relaxes canonicallity check allowing to create aliases + | | | | for userspace memory here. __________________|____________|__________________|_________|___________________________________________________________ | | Kernel-space virtual memory, shared between all processes: + __________________|____________|__________________|_________|___________________________________________________________ + | | | | + 8000000000000000 | -8 EB | ffff7fffffffffff | ~8 EB | ... huge, almost 63 bits wide hole of non-canonical + | | | | virtual memory addresses up to the -128 TB + | | | | starting offset of kernel mappings. + | | | | + | | | | LAM_SUP relaxes canonicallity check allowing to create + | | | | aliases for kernel memory here. ____________________________________________________________|___________________________________________________________ | | | | ffff800000000000 | -128 TB | ffff87ffffffffff | 8 TB | ... guard hole, also reserved for hypervisor @@ -88,15 +100,26 @@ Complete virtual memory map with 5-level page tables Start addr | Offset | End addr | Size | VM area description ======================================================================================================================== | | | | - 0000000000000000 | 0 | 00ffffffffffffff | 64 PB | user-space virtual memory, different per mm + 0000000000000000 | 0 | 00fffffffffff000 | ~64 PB | user-space virtual memory, different per mm + 00fffffffffff000 | ~64 PB | 00ffffffffffffff | 4 kB | ... guard hole __________________|____________|__________________|_________|___________________________________________________________ | | | | - 0100000000000000 | +64 PB | feffffffffffffff | ~16K PB | ... huge, still almost 64 bits wide hole of non-canonical - | | | | virtual memory addresses up to the -64 PB + 0100000000000000 | +64 PB | 7fffffffffffffff | ~8 EB | ... huge, almost 63 bits wide hole of non-canonical + | | | | virtual memory addresses up to the -8EB TB | | | | starting offset of kernel mappings. + | | | | + | | | | LAM relaxes canonicallity check allowing to create aliases + | | | | for userspace memory here. __________________|____________|__________________|_________|___________________________________________________________ | | Kernel-space virtual memory, shared between all processes: + ____________________________________________________________|___________________________________________________________ + 8000000000000000 | -8 EB | feffffffffffffff | ~8 EB | ... huge, almost 63 bits wide hole of non-canonical + | | | | virtual memory addresses up to the -64 PB + | | | | starting offset of kernel mappings. + | | | | + | | | | LAM_SUP relaxes canonicallity check allowing to create + | | | | aliases for kernel memory here. ____________________________________________________________|___________________________________________________________ | | | | ff00000000000000 | -64 PB | ff0fffffffffffff | 4 PB | ... guard hole, also reserved for hypervisor diff --git a/Documentation/block/cmdline-partition.rst b/Documentation/block/cmdline-partition.rst index 530bedff548aac..526ba201dddcff 100644 --- a/Documentation/block/cmdline-partition.rst +++ b/Documentation/block/cmdline-partition.rst @@ -39,13 +39,16 @@ blkdevparts=[;] create a link to block device partition with the name "PARTNAME". User space application can access partition by partition name. +ro + read-only. Flag the partition as read-only. + Example: eMMC disk names are "mmcblk0" and "mmcblk0boot0". bootargs:: - 'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)' + 'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot)ro,-(kernel)' dmesg:: diff --git a/Documentation/block/ublk.rst b/Documentation/block/ublk.rst index ff74b3ec4a98c6..51665a3e6a50cd 100644 --- a/Documentation/block/ublk.rst +++ b/Documentation/block/ublk.rst @@ -199,24 +199,36 @@ managing and controlling ublk devices with help of several control commands: - user recovery feature description - Two new features are added for user recovery: ``UBLK_F_USER_RECOVERY`` and - ``UBLK_F_USER_RECOVERY_REISSUE``. - - With ``UBLK_F_USER_RECOVERY`` set, after one ubq_daemon(ublk server's io + Three new features are added for user recovery: ``UBLK_F_USER_RECOVERY``, + ``UBLK_F_USER_RECOVERY_REISSUE``, and ``UBLK_F_USER_RECOVERY_FAIL_IO``. To + enable recovery of ublk devices after the ublk server exits, the ublk server + should specify the ``UBLK_F_USER_RECOVERY`` flag when creating the device. The + ublk server may additionally specify at most one of + ``UBLK_F_USER_RECOVERY_REISSUE`` and ``UBLK_F_USER_RECOVERY_FAIL_IO`` to + modify how I/O is handled while the ublk server is dying/dead (this is called + the ``nosrv`` case in the driver code). + + With just ``UBLK_F_USER_RECOVERY`` set, after one ubq_daemon(ublk server's io handler) is dying, ublk does not delete ``/dev/ublkb*`` during the whole recovery stage and ublk device ID is kept. It is ublk server's responsibility to recover the device context by its own knowledge. Requests which have not been issued to userspace are requeued. Requests which have been issued to userspace are aborted. - With ``UBLK_F_USER_RECOVERY_REISSUE`` set, after one ubq_daemon(ublk - server's io handler) is dying, contrary to ``UBLK_F_USER_RECOVERY``, + With ``UBLK_F_USER_RECOVERY_REISSUE`` additionally set, after one ubq_daemon + (ublk server's io handler) is dying, contrary to ``UBLK_F_USER_RECOVERY``, requests which have been issued to userspace are requeued and will be re-issued to the new process after handling ``UBLK_CMD_END_USER_RECOVERY``. ``UBLK_F_USER_RECOVERY_REISSUE`` is designed for backends who tolerate double-write since the driver may issue the same I/O request twice. It might be useful to a read-only FS or a VM backend. + With ``UBLK_F_USER_RECOVERY_FAIL_IO`` additionally set, after the ublk server + exits, requests which have issued to userspace are failed, as are any + subsequently issued requests. Applications continuously issuing I/O against + devices with this flag set will see a stream of I/O errors until a new ublk + server recovers the device. + Unprivileged ublk device is supported by passing ``UBLK_F_UNPRIVILEGED_DEV``. Once the flag is set, all control commands can be sent by unprivileged user. Except for command of ``UBLK_CMD_ADD_DEV``, permission check on diff --git a/Documentation/bpf/btf.rst b/Documentation/bpf/btf.rst index 93060283b6fda2..2478cef758f816 100644 --- a/Documentation/bpf/btf.rst +++ b/Documentation/bpf/btf.rst @@ -835,7 +835,7 @@ section named by ``btf_ext_info_sec->sec_name_off``. See :ref:`Documentation/bpf/llvm_reloc.rst ` for more information on CO-RE relocations. -4.2 .BTF_ids section +4.3 .BTF_ids section -------------------- The .BTF_ids section encodes BTF ID values that are used within the kernel. @@ -896,6 +896,81 @@ and is used as a filter when resolving the BTF ID value. All the BTF ID lists and sets are compiled in the .BTF_ids section and resolved during the linking phase of kernel build by ``resolve_btfids`` tool. +4.4 .BTF.base section +--------------------- +Split BTF - where the .BTF section only contains types not in the associated +base .BTF section - is an extremely efficient way to encode type information +for kernel modules, since they generally consist of a few module-specific +types along with a large set of shared kernel types. The former are encoded +in split BTF, while the latter are encoded in base BTF, resulting in more +compact representations. A type in split BTF that refers to a type in +base BTF refers to it using its base BTF ID, and split BTF IDs start +at last_base_BTF_ID + 1. + +The downside of this approach however is that this makes the split BTF +somewhat brittle - when the base BTF changes, base BTF ID references are +no longer valid and the split BTF itself becomes useless. The role of the +.BTF.base section is to make split BTF more resilient for cases where +the base BTF may change, as is the case for kernel modules not built every +time the kernel is for example. .BTF.base contains named base types; INTs, +FLOATs, STRUCTs, UNIONs, ENUM[64]s and FWDs. INTs and FLOATs are fully +described in .BTF.base sections, while composite types like structs +and unions are not fully defined - the .BTF.base type simply serves as +a description of the type the split BTF referred to, so structs/unions +have 0 members in the .BTF.base section. ENUM[64]s are similarly recorded +with 0 members. Any other types are added to the split BTF. This +distillation process then leaves us with a .BTF.base section with +such minimal descriptions of base types and .BTF split section which refers +to those base types. Later, we can relocate the split BTF using both the +information stored in the .BTF.base section and the new .BTF base; the type +information in the .BTF.base section allows us to update the split BTF +references to point at the corresponding new base BTF IDs. + +BTF relocation happens on kernel module load when a kernel module has a +.BTF.base section, and libbpf also provides a btf__relocate() API to +accomplish this. + +As an example consider the following base BTF:: + + [1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED + [2] STRUCT 'foo' size=8 vlen=2 + 'f1' type_id=1 bits_offset=0 + 'f2' type_id=1 bits_offset=32 + +...and associated split BTF:: + + [3] PTR '(anon)' type_id=2 + +i.e. split BTF describes a pointer to struct foo { int f1; int f2 }; + +.BTF.base will consist of:: + + [1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED + [2] STRUCT 'foo' size=8 vlen=0 + +If we relocate the split BTF later using the following new base BTF:: + + [1] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64 encoding=(none) + [2] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED + [3] STRUCT 'foo' size=8 vlen=2 + 'f1' type_id=2 bits_offset=0 + 'f2' type_id=2 bits_offset=32 + +...we can use our .BTF.base description to know that the split BTF reference +is to struct foo, and relocation results in new split BTF:: + + [4] PTR '(anon)' type_id=3 + +Note that we had to update BTF ID and start BTF ID for the split BTF. + +So we see how .BTF.base plays the role of facilitating later relocation, +leading to more resilient split BTF. + +.BTF.base sections will be generated automatically for out-of-tree kernel module +builds - i.e. where KBUILD_EXTMOD is set (as it would be for "make M=path/2/mod" +cases). .BTF.base generation requires pahole support for the "distilled_base" +BTF feature; this is available in pahole v1.28 and later. + 5. Using BTF ============ diff --git a/Documentation/bpf/verifier.rst b/Documentation/bpf/verifier.rst index d2376154000227..95e6f80a407e52 100644 --- a/Documentation/bpf/verifier.rst +++ b/Documentation/bpf/verifier.rst @@ -507,7 +507,7 @@ Notes: from the parent state to the current state. * Details about REG_LIVE_READ32 are omitted. - + * Function ``propagate_liveness()`` (see section :ref:`read_marks_for_cache_hits`) might override the first parent link. Please refer to the comments in the ``propagate_liveness()`` and ``mark_reg_read()`` source code for further @@ -571,7 +571,7 @@ works:: are considered equivalent. .. _read_marks_for_cache_hits: - + Read marks propagation for cache hits ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/core-api/cpu_hotplug.rst b/Documentation/core-api/cpu_hotplug.rst index a21dbf261be7f5..e1b0eeabbb5e58 100644 --- a/Documentation/core-api/cpu_hotplug.rst +++ b/Documentation/core-api/cpu_hotplug.rst @@ -616,7 +616,7 @@ ONLINE section for notifications on online and offline operation:: .... cpuhp_remove_instance(state, &inst2->node); .... - remove_multi_state(state); + cpuhp_remove_multi_state(state); Testing of hotplug states diff --git a/Documentation/core-api/gfp_mask-from-fs-io.rst b/Documentation/core-api/gfp_mask-from-fs-io.rst index e7c32a8de126a5..858b2fbcb36c73 100644 --- a/Documentation/core-api/gfp_mask-from-fs-io.rst +++ b/Documentation/core-api/gfp_mask-from-fs-io.rst @@ -55,14 +55,16 @@ scope. What about __vmalloc(GFP_NOFS) ============================== -vmalloc doesn't support GFP_NOFS semantic because there are hardcoded -GFP_KERNEL allocations deep inside the allocator which are quite non-trivial -to fix up. That means that calling ``vmalloc`` with GFP_NOFS/GFP_NOIO is -almost always a bug. The good news is that the NOFS/NOIO semantic can be -achieved by the scope API. +Since v5.17, and specifically after the commit 451769ebb7e79 ("mm/vmalloc: +alloc GFP_NO{FS,IO} for vmalloc"), GFP_NOFS/GFP_NOIO are now supported in +``[k]vmalloc`` by implicitly using scope API. + +In earlier kernels ``vmalloc`` didn't support GFP_NOFS semantic because there +were hardcoded GFP_KERNEL allocations deep inside the allocator. That means +that calling ``vmalloc`` with GFP_NOFS/GFP_NOIO was almost always a bug. In the ideal world, upper layers should already mark dangerous contexts -and so no special care is required and vmalloc should be called without -any problems. Sometimes if the context is not really clear or there are -layering violations then the recommended way around that is to wrap ``vmalloc`` -by the scope API with a comment explaining the problem. +and so no special care is required and ``vmalloc`` should be called without any +problems. Sometimes if the context is not really clear or there are layering +violations then the recommended way around that (on pre-v5.17 kernels) is to +wrap ``vmalloc`` by the scope API with a comment explaining the problem. diff --git a/Documentation/core-api/index.rst b/Documentation/core-api/index.rst index 6a875743dd4b7f..563b8fc0002f73 100644 --- a/Documentation/core-api/index.rst +++ b/Documentation/core-api/index.rst @@ -52,6 +52,7 @@ Library functionality that is used throughout the kernel. wrappers/atomic_bitops floating-point union_find + min_heap Low level entry and exit ======================== diff --git a/Documentation/core-api/min_heap.rst b/Documentation/core-api/min_heap.rst new file mode 100644 index 00000000000000..0c636c8b7aa581 --- /dev/null +++ b/Documentation/core-api/min_heap.rst @@ -0,0 +1,300 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============ +Min Heap API +============ + +Introduction +============ + +The Min Heap API provides a set of functions and macros for managing min-heaps +in the Linux kernel. A min-heap is a binary tree structure where the value of +each node is less than or equal to the values of its children, ensuring that +the smallest element is always at the root. + +This document provides a guide to the Min Heap API, detailing how to define and +use min-heaps. Users should not directly call functions with **__min_heap_*()** +prefixes, but should instead use the provided macro wrappers. + +In addition to the standard version of the functions, the API also includes a +set of inline versions for performance-critical scenarios. These inline +functions have the same names as their non-inline counterparts but include an +**_inline** suffix. For example, **__min_heap_init_inline** and its +corresponding macro wrapper **min_heap_init_inline**. The inline versions allow +custom comparison and swap functions to be called directly, rather than through +indirect function calls. This can significantly reduce overhead, especially +when CONFIG_MITIGATION_RETPOLINE is enabled, as indirect function calls become +more expensive. As with the non-inline versions, it is important to use the +macro wrappers for inline functions instead of directly calling the functions +themselves. + +Data Structures +=============== + +Min-Heap Definition +------------------- + +The core data structure for representing a min-heap is defined using the +**MIN_HEAP_PREALLOCATED** and **DEFINE_MIN_HEAP** macros. These macros allow +you to define a min-heap with a preallocated buffer or dynamically allocated +memory. + +Example: + +.. code-block:: c + + #define MIN_HEAP_PREALLOCATED(_type, _name, _nr) + struct _name { + int nr; /* Number of elements in the heap */ + int size; /* Maximum number of elements that can be held */ + _type *data; /* Pointer to the heap data */ + _type preallocated[_nr]; /* Static preallocated array */ + } + + #define DEFINE_MIN_HEAP(_type, _name) MIN_HEAP_PREALLOCATED(_type, _name, 0) + +A typical heap structure will include a counter for the number of elements +(`nr`), the maximum capacity of the heap (`size`), and a pointer to an array of +elements (`data`). Optionally, you can specify a static array for preallocated +heap storage using **MIN_HEAP_PREALLOCATED**. + +Min Heap Callbacks +------------------ + +The **struct min_heap_callbacks** provides customization options for ordering +elements in the heap and swapping them. It contains two function pointers: + +.. code-block:: c + + struct min_heap_callbacks { + bool (*less)(const void *lhs, const void *rhs, void *args); + void (*swp)(void *lhs, void *rhs, void *args); + }; + +- **less** is the comparison function used to establish the order of elements. +- **swp** is a function for swapping elements in the heap. If swp is set to + NULL, the default swap function will be used, which swaps the elements based on their size + +Macro Wrappers +============== + +The following macro wrappers are provided for interacting with the heap in a +user-friendly manner. Each macro corresponds to a function that operates on the +heap, and they abstract away direct calls to internal functions. + +Each macro accepts various parameters that are detailed below. + +Heap Initialization +-------------------- + +.. code-block:: c + + min_heap_init(heap, data, size); + +- **heap**: A pointer to the min-heap structure to be initialized. +- **data**: A pointer to the buffer where the heap elements will be stored. If + `NULL`, the preallocated buffer within the heap structure will be used. +- **size**: The maximum number of elements the heap can hold. + +This macro initializes the heap, setting its initial state. If `data` is +`NULL`, the preallocated memory inside the heap structure will be used for +storage. Otherwise, the user-provided buffer is used. The operation is **O(1)**. + +**Inline Version:** min_heap_init_inline(heap, data, size) + +Accessing the Top Element +------------------------- + +.. code-block:: c + + element = min_heap_peek(heap); + +- **heap**: A pointer to the min-heap from which to retrieve the smallest + element. + +This macro returns a pointer to the smallest element (the root) of the heap, or +`NULL` if the heap is empty. The operation is **O(1)**. + +**Inline Version:** min_heap_peek_inline(heap) + +Heap Insertion +-------------- + +.. code-block:: c + + success = min_heap_push(heap, element, callbacks, args); + +- **heap**: A pointer to the min-heap into which the element should be inserted. +- **element**: A pointer to the element to be inserted into the heap. +- **callbacks**: A pointer to a `struct min_heap_callbacks` providing the + `less` and `swp` functions. +- **args**: Optional arguments passed to the `less` and `swp` functions. + +This macro inserts an element into the heap. It returns `true` if the insertion +was successful and `false` if the heap is full. The operation is **O(log n)**. + +**Inline Version:** min_heap_push_inline(heap, element, callbacks, args) + +Heap Removal +------------ + +.. code-block:: c + + success = min_heap_pop(heap, callbacks, args); + +- **heap**: A pointer to the min-heap from which to remove the smallest element. +- **callbacks**: A pointer to a `struct min_heap_callbacks` providing the + `less` and `swp` functions. +- **args**: Optional arguments passed to the `less` and `swp` functions. + +This macro removes the smallest element (the root) from the heap. It returns +`true` if the element was successfully removed, or `false` if the heap is +empty. The operation is **O(log n)**. + +**Inline Version:** min_heap_pop_inline(heap, callbacks, args) + +Heap Maintenance +---------------- + +You can use the following macros to maintain the heap's structure: + +.. code-block:: c + + min_heap_sift_down(heap, pos, callbacks, args); + +- **heap**: A pointer to the min-heap. +- **pos**: The index from which to start sifting down. +- **callbacks**: A pointer to a `struct min_heap_callbacks` providing the + `less` and `swp` functions. +- **args**: Optional arguments passed to the `less` and `swp` functions. + +This macro restores the heap property by moving the element at the specified +index (`pos`) down the heap until it is in the correct position. The operation +is **O(log n)**. + +**Inline Version:** min_heap_sift_down_inline(heap, pos, callbacks, args) + +.. code-block:: c + + min_heap_sift_up(heap, idx, callbacks, args); + +- **heap**: A pointer to the min-heap. +- **idx**: The index of the element to sift up. +- **callbacks**: A pointer to a `struct min_heap_callbacks` providing the + `less` and `swp` functions. +- **args**: Optional arguments passed to the `less` and `swp` functions. + +This macro restores the heap property by moving the element at the specified +index (`idx`) up the heap. The operation is **O(log n)**. + +**Inline Version:** min_heap_sift_up_inline(heap, idx, callbacks, args) + +.. code-block:: c + + min_heapify_all(heap, callbacks, args); + +- **heap**: A pointer to the min-heap. +- **callbacks**: A pointer to a `struct min_heap_callbacks` providing the + `less` and `swp` functions. +- **args**: Optional arguments passed to the `less` and `swp` functions. + +This macro ensures that the entire heap satisfies the heap property. It is +called when the heap is built from scratch or after many modifications. The +operation is **O(n)**. + +**Inline Version:** min_heapify_all_inline(heap, callbacks, args) + +Removing Specific Elements +-------------------------- + +.. code-block:: c + + success = min_heap_del(heap, idx, callbacks, args); + +- **heap**: A pointer to the min-heap. +- **idx**: The index of the element to delete. +- **callbacks**: A pointer to a `struct min_heap_callbacks` providing the + `less` and `swp` functions. +- **args**: Optional arguments passed to the `less` and `swp` functions. + +This macro removes an element at the specified index (`idx`) from the heap and +restores the heap property. The operation is **O(log n)**. + +**Inline Version:** min_heap_del_inline(heap, idx, callbacks, args) + +Other Utilities +=============== + +- **min_heap_full(heap)**: Checks whether the heap is full. + Complexity: **O(1)**. + +.. code-block:: c + + bool full = min_heap_full(heap); + +- `heap`: A pointer to the min-heap to check. + +This macro returns `true` if the heap is full, otherwise `false`. + +**Inline Version:** min_heap_full_inline(heap) + +- **min_heap_empty(heap)**: Checks whether the heap is empty. + Complexity: **O(1)**. + +.. code-block:: c + + bool empty = min_heap_empty(heap); + +- `heap`: A pointer to the min-heap to check. + +This macro returns `true` if the heap is empty, otherwise `false`. + +**Inline Version:** min_heap_empty_inline(heap) + +Example Usage +============= + +An example usage of the min-heap API would involve defining a heap structure, +initializing it, and inserting and removing elements as needed. + +.. code-block:: c + + #include + + int my_less_function(const void *lhs, const void *rhs, void *args) { + return (*(int *)lhs < *(int *)rhs); + } + + struct min_heap_callbacks heap_cb = { + .less = my_less_function, /* Comparison function for heap order */ + .swp = NULL, /* Use default swap function */ + }; + + void example_usage(void) { + /* Pre-populate the buffer with elements */ + int buffer[5] = {5, 2, 8, 1, 3}; + /* Declare a min-heap */ + DEFINE_MIN_HEAP(int, my_heap); + + /* Initialize the heap with preallocated buffer and size */ + min_heap_init(&my_heap, buffer, 5); + + /* Build the heap using min_heapify_all */ + my_heap.nr = 5; /* Set the number of elements in the heap */ + min_heapify_all(&my_heap, &heap_cb, NULL); + + /* Peek at the top element (should be 1 in this case) */ + int *top = min_heap_peek(&my_heap); + pr_info("Top element: %d\n", *top); + + /* Pop the top element (1) and get the new top (2) */ + min_heap_pop(&my_heap, &heap_cb, NULL); + top = min_heap_peek(&my_heap); + pr_info("New top element: %d\n", *top); + + /* Insert a new element (0) and recheck the top */ + int new_element = 0; + min_heap_push(&my_heap, &new_element, &heap_cb, NULL); + top = min_heap_peek(&my_heap); + pr_info("Top element after insertion: %d\n", *top); + } diff --git a/Documentation/core-api/packing.rst b/Documentation/core-api/packing.rst index 3ed13bc9a19546..821691f23c541c 100644 --- a/Documentation/core-api/packing.rst +++ b/Documentation/core-api/packing.rst @@ -151,6 +151,77 @@ the more significant 4-byte word. We always think of our offsets as if there were no quirk, and we translate them afterwards, before accessing the memory region. +Note on buffer lengths not multiple of 4 +---------------------------------------- + +To deal with memory layout quirks where groups of 4 bytes are laid out "little +endian" relative to each other, but "big endian" within the group itself, the +concept of groups of 4 bytes is intrinsic to the packing API (not to be +confused with the memory access, which is performed byte by byte, though). + +With buffer lengths not multiple of 4, this means one group will be incomplete. +Depending on the quirks, this may lead to discontinuities in the bit fields +accessible through the buffer. The packing API assumes discontinuities were not +the intention of the memory layout, so it avoids them by effectively logically +shortening the most significant group of 4 octets to the number of octets +actually available. + +Example with a 31 byte sized buffer given below. Physical buffer offsets are +implicit, and increase from left to right within a group, and from top to +bottom within a column. + +No quirks: + +:: + + 31 29 28 | Group 7 (most significant) + 27 26 25 24 | Group 6 + 23 22 21 20 | Group 5 + 19 18 17 16 | Group 4 + 15 14 13 12 | Group 3 + 11 10 9 8 | Group 2 + 7 6 5 4 | Group 1 + 3 2 1 0 | Group 0 (least significant) + +QUIRK_LSW32_IS_FIRST: + +:: + + 3 2 1 0 | Group 0 (least significant) + 7 6 5 4 | Group 1 + 11 10 9 8 | Group 2 + 15 14 13 12 | Group 3 + 19 18 17 16 | Group 4 + 23 22 21 20 | Group 5 + 27 26 25 24 | Group 6 + 30 29 28 | Group 7 (most significant) + +QUIRK_LITTLE_ENDIAN: + +:: + + 30 28 29 | Group 7 (most significant) + 24 25 26 27 | Group 6 + 20 21 22 23 | Group 5 + 16 17 18 19 | Group 4 + 12 13 14 15 | Group 3 + 8 9 10 11 | Group 2 + 4 5 6 7 | Group 1 + 0 1 2 3 | Group 0 (least significant) + +QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST: + +:: + + 0 1 2 3 | Group 0 (least significant) + 4 5 6 7 | Group 1 + 8 9 10 11 | Group 2 + 12 13 14 15 | Group 3 + 16 17 18 19 | Group 4 + 20 21 22 23 | Group 5 + 24 25 26 27 | Group 6 + 28 29 30 | Group 7 (most significant) + Intended use ------------ diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index 14e093da3ccd93..ecccc0473da9c1 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -209,12 +209,17 @@ Struct Resources :: %pr [mem 0x60000000-0x6fffffff flags 0x2200] or + [mem 0x60000000 flags 0x2200] or [mem 0x0000000060000000-0x000000006fffffff flags 0x2200] + [mem 0x0000000060000000 flags 0x2200] %pR [mem 0x60000000-0x6fffffff pref] or + [mem 0x60000000 pref] or [mem 0x0000000060000000-0x000000006fffffff pref] + [mem 0x0000000060000000 pref] For printing struct resources. The ``R`` and ``r`` specifiers result in a -printed resource with (R) or without (r) a decoded flags member. +printed resource with (R) or without (r) a decoded flags member. If start is +equal to end only print the start value. Passed by reference. @@ -231,6 +236,19 @@ width of the CPU data path. Passed by reference. +Struct Range +------------ + +:: + + %pra [range 0x0000000060000000-0x000000006fffffff] or + [range 0x0000000060000000] + +For printing struct range. struct range holds an arbitrary range of u64 +values. If start is equal to end only print the start value. + +Passed by reference. + DMA address types dma_addr_t ---------------------------- diff --git a/Documentation/core-api/swiotlb.rst b/Documentation/core-api/swiotlb.rst index cf06bae44ff85b..9e0fe027dd3bd0 100644 --- a/Documentation/core-api/swiotlb.rst +++ b/Documentation/core-api/swiotlb.rst @@ -295,9 +295,9 @@ slot set. Fourth, the io_tlb_slot array keeps track of any "padding slots" allocated to meet alloc_align_mask requirements described above. When -swiotlb_tlb_map_single() allocates bounce buffer space to meet alloc_align_mask +swiotlb_tbl_map_single() allocates bounce buffer space to meet alloc_align_mask requirements, it may allocate pre-padding space across zero or more slots. But -when swiotbl_tlb_unmap_single() is called with the bounce buffer address, the +when swiotlb_tbl_unmap_single() is called with the bounce buffer address, the alloc_align_mask value that governed the allocation, and therefore the allocation of any padding slots, is not known. The "pad_slots" field records the number of padding slots so that swiotlb_tbl_unmap_single() can free them. diff --git a/Documentation/core-api/symbol-namespaces.rst b/Documentation/core-api/symbol-namespaces.rst index 12e4aecdae9452..27a9cccc792c1e 100644 --- a/Documentation/core-api/symbol-namespaces.rst +++ b/Documentation/core-api/symbol-namespaces.rst @@ -46,7 +46,7 @@ Please note that due to macro expansion that argument needs to be a preprocessor symbol. E.g. to export the symbol ``usb_stor_suspend`` into the namespace ``USB_STORAGE``, use:: - EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE); + EXPORT_SYMBOL_NS(usb_stor_suspend, "USB_STORAGE"); The corresponding ksymtab entry struct ``kernel_symbol`` will have the member ``namespace`` set accordingly. A symbol that is exported without a namespace will @@ -68,7 +68,7 @@ is to define the default namespace in the ``Makefile`` of the subsystem. E.g. to export all symbols defined in usb-common into the namespace USB_COMMON, add a line like this to drivers/usb/common/Makefile:: - ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON + ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"USB_COMMON"' That will affect all EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL() statements. A symbol exported with EXPORT_SYMBOL_NS() while this definition is present, will @@ -79,7 +79,7 @@ A second option to define the default namespace is directly in the compilation unit as preprocessor statement. The above example would then read:: #undef DEFAULT_SYMBOL_NAMESPACE - #define DEFAULT_SYMBOL_NAMESPACE USB_COMMON + #define DEFAULT_SYMBOL_NAMESPACE "USB_COMMON" within the corresponding compilation unit before any EXPORT_SYMBOL macro is used. @@ -94,7 +94,7 @@ for the namespaces it uses symbols from. E.g. a module using the usb_stor_suspend symbol from above, needs to import the namespace USB_STORAGE using a statement like:: - MODULE_IMPORT_NS(USB_STORAGE); + MODULE_IMPORT_NS("USB_STORAGE"); This will create a ``modinfo`` tag in the module for each imported namespace. This has the side effect, that the imported namespaces of a module can be diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst index 16f861c9791e4a..e295835fc1164e 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -245,8 +245,8 @@ CPU which can be assigned to the work items of a wq. For example, with at the same time per CPU. This is always a per-CPU attribute, even for unbound workqueues. -The maximum limit for ``@max_active`` is 512 and the default value used -when 0 is specified is 256. These values are chosen sufficiently high +The maximum limit for ``@max_active`` is 2048 and the default value used +when 0 is specified is 1024. These values are chosen sufficiently high such that they are not the limiting factor while providing protection in runaway cases. @@ -357,6 +357,11 @@ Guidelines difference in execution characteristics between using a dedicated wq and a system wq. + Note: If something may generate more than @max_active outstanding + work items (do stress test your producers), it may saturate a system + wq and potentially lead to deadlock. It should utilize its own + dedicated workqueue rather than the system wq. + * Unless work items are expected to consume a huge amount of CPU cycles, using a bound wq is usually beneficial due to the increased level of locality in wq operations and work item execution. diff --git a/Documentation/crypto/api-akcipher.rst b/Documentation/crypto/api-akcipher.rst index 40aa8746e2a1f2..ca1ecdd4a7d378 100644 --- a/Documentation/crypto/api-akcipher.rst +++ b/Documentation/crypto/api-akcipher.rst @@ -8,10 +8,10 @@ Asymmetric Cipher API --------------------- .. kernel-doc:: include/crypto/akcipher.h - :doc: Generic Public Key API + :doc: Generic Public Key Cipher API .. kernel-doc:: include/crypto/akcipher.h - :functions: crypto_alloc_akcipher crypto_free_akcipher crypto_akcipher_set_pub_key crypto_akcipher_set_priv_key crypto_akcipher_maxsize crypto_akcipher_encrypt crypto_akcipher_decrypt crypto_akcipher_sign crypto_akcipher_verify + :functions: crypto_alloc_akcipher crypto_free_akcipher crypto_akcipher_set_pub_key crypto_akcipher_set_priv_key crypto_akcipher_maxsize crypto_akcipher_encrypt crypto_akcipher_decrypt Asymmetric Cipher Request Handle -------------------------------- diff --git a/Documentation/crypto/api-sig.rst b/Documentation/crypto/api-sig.rst new file mode 100644 index 00000000000000..aaec18e26d545f --- /dev/null +++ b/Documentation/crypto/api-sig.rst @@ -0,0 +1,15 @@ +Asymmetric Signature Algorithm Definitions +------------------------------------------ + +.. kernel-doc:: include/crypto/sig.h + :functions: sig_alg + +Asymmetric Signature API +------------------------ + +.. kernel-doc:: include/crypto/sig.h + :doc: Generic Public Key Signature API + +.. kernel-doc:: include/crypto/sig.h + :functions: crypto_alloc_sig crypto_free_sig crypto_sig_set_pubkey crypto_sig_set_privkey crypto_sig_keysize crypto_sig_maxsize crypto_sig_digestsize crypto_sig_sign crypto_sig_verify + diff --git a/Documentation/crypto/api.rst b/Documentation/crypto/api.rst index ff31c30561d4f6..8b2a905218862d 100644 --- a/Documentation/crypto/api.rst +++ b/Documentation/crypto/api.rst @@ -10,4 +10,5 @@ Programming Interface api-digest api-rng api-akcipher + api-sig api-kpp diff --git a/Documentation/crypto/architecture.rst b/Documentation/crypto/architecture.rst index 646c3380a7edc4..15dcd62fd22f26 100644 --- a/Documentation/crypto/architecture.rst +++ b/Documentation/crypto/architecture.rst @@ -214,6 +214,8 @@ the aforementioned cipher types: - CRYPTO_ALG_TYPE_AKCIPHER Asymmetric cipher +- CRYPTO_ALG_TYPE_SIG Asymmetric signature + - CRYPTO_ALG_TYPE_PCOMPRESS Enhanced version of CRYPTO_ALG_TYPE_COMPRESS allowing for segmented compression / decompression instead of performing the operation on one segment diff --git a/Documentation/dev-tools/autofdo.rst b/Documentation/dev-tools/autofdo.rst new file mode 100644 index 00000000000000..1f0a451e9ccd32 --- /dev/null +++ b/Documentation/dev-tools/autofdo.rst @@ -0,0 +1,168 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================== +Using AutoFDO with the Linux kernel +=================================== + +This enables AutoFDO build support for the kernel when using +the Clang compiler. AutoFDO (Auto-Feedback-Directed Optimization) +is a type of profile-guided optimization (PGO) used to enhance the +performance of binary executables. It gathers information about the +frequency of execution of various code paths within a binary using +hardware sampling. This data is then used to guide the compiler's +optimization decisions, resulting in a more efficient binary. AutoFDO +is a powerful optimization technique, and data indicates that it can +significantly improve kernel performance. It's especially beneficial +for workloads affected by front-end stalls. + +For AutoFDO builds, unlike non-FDO builds, the user must supply a +profile. Acquiring an AutoFDO profile can be done in several ways. +AutoFDO profiles are created by converting hardware sampling using +the "perf" tool. It is crucial that the workload used to create these +perf files is representative; they must exhibit runtime +characteristics similar to the workloads that are intended to be +optimized. Failure to do so will result in the compiler optimizing +for the wrong objective. + +The AutoFDO profile often encapsulates the program's behavior. If the +performance-critical codes are architecture-independent, the profile +can be applied across platforms to achieve performance gains. For +instance, using the profile generated on Intel architecture to build +a kernel for AMD architecture can also yield performance improvements. + +There are two methods for acquiring a representative profile: +(1) Sample real workloads using a production environment. +(2) Generate the profile using a representative load test. +When enabling the AutoFDO build configuration without providing an +AutoFDO profile, the compiler only modifies the dwarf information in +the kernel without impacting runtime performance. It's advisable to +use a kernel binary built with the same AutoFDO configuration to +collect the perf profile. While it's possible to use a kernel built +with different options, it may result in inferior performance. + +One can collect profiles using AutoFDO build for the previous kernel. +AutoFDO employs relative line numbers to match the profiles, offering +some tolerance for source changes. This mode is commonly used in a +production environment for profile collection. + +In a profile collection based on a load test, the AutoFDO collection +process consists of the following steps: + +#. Initial build: The kernel is built with AutoFDO options + without a profile. + +#. Profiling: The above kernel is then run with a representative + workload to gather execution frequency data. This data is + collected using hardware sampling, via perf. AutoFDO is most + effective on platforms supporting advanced PMU features like + LBR on Intel machines. + +#. AutoFDO profile generation: Perf output file is converted to + the AutoFDO profile via offline tools. + +The support requires a Clang compiler LLVM 17 or later. + +Preparation +=========== + +Configure the kernel with:: + + CONFIG_AUTOFDO_CLANG=y + +Customization +============= + +The default CONFIG_AUTOFDO_CLANG setting covers kernel space objects for +AutoFDO builds. One can, however, enable or disable AutoFDO build for +individual files and directories by adding a line similar to the following +to the respective kernel Makefile: + +- For enabling a single file (e.g. foo.o) :: + + AUTOFDO_PROFILE_foo.o := y + +- For enabling all files in one directory :: + + AUTOFDO_PROFILE := y + +- For disabling one file :: + + AUTOFDO_PROFILE_foo.o := n + +- For disabling all files in one directory :: + + AUTOFDO_PROFILE := n + +Workflow +======== + +Here is an example workflow for AutoFDO kernel: + +1) Build the kernel on the host machine with LLVM enabled, + for example, :: + + $ make menuconfig LLVM=1 + + Turn on AutoFDO build config:: + + CONFIG_AUTOFDO_CLANG=y + + With a configuration that with LLVM enabled, use the following command:: + + $ scripts/config -e AUTOFDO_CLANG + + After getting the config, build with :: + + $ make LLVM=1 + +2) Install the kernel on the test machine. + +3) Run the load tests. The '-c' option in perf specifies the sample + event period. We suggest using a suitable prime number, like 500009, + for this purpose. + + - For Intel platforms:: + + $ perf record -e BR_INST_RETIRED.NEAR_TAKEN:k -a -N -b -c -o -- + + - For AMD platforms: + + The supported systems are: Zen3 with BRS, or Zen4 with amd_lbr_v2. To check, + + For Zen3:: + + $ cat proc/cpuinfo | grep " brs" + + For Zen4:: + + $ cat proc/cpuinfo | grep amd_lbr_v2 + + The following command generated the perf data file:: + + $ perf record --pfm-events RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a -N -b -c -o -- + +4) (Optional) Download the raw perf file to the host machine. + +5) To generate an AutoFDO profile, two offline tools are available: + create_llvm_prof and llvm_profgen. The create_llvm_prof tool is part + of the AutoFDO project and can be found on GitHub + (https://github.com/google/autofdo), version v0.30.1 or later. + The llvm_profgen tool is included in the LLVM compiler itself. It's + important to note that the version of llvm_profgen doesn't need to match + the version of Clang. It needs to be the LLVM 19 release of Clang + or later, or just from the LLVM trunk. :: + + $ llvm-profgen --kernel --binary= --perfdata= -o + + or :: + + $ create_llvm_prof --binary= --profile= --format=extbinary --out= + + Note that multiple AutoFDO profile files can be merged into one via:: + + $ llvm-profdata merge -o ... + +6) Rebuild the kernel using the AutoFDO profile file with the same config as step 1, + (Note CONFIG_AUTOFDO_CLANG needs to be enabled):: + + $ make LLVM=1 CLANG_AUTOFDO_PROFILE= diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst index a9fac978a52514..abb3ff6820766e 100644 --- a/Documentation/dev-tools/checkpatch.rst +++ b/Documentation/dev-tools/checkpatch.rst @@ -470,8 +470,6 @@ API usage usleep_range() should be preferred over udelay(). The proper way of using usleep_range() is mentioned in the kernel docs. - See: https://www.kernel.org/doc/html/latest/timers/timers-howto.html#delays-information-on-the-various-kernel-delay-sleep-mechanisms - Comments -------- diff --git a/Documentation/dev-tools/coccinelle.rst b/Documentation/dev-tools/coccinelle.rst index 535ce126fb4fa2..6e70a1e9a3c0e9 100644 --- a/Documentation/dev-tools/coccinelle.rst +++ b/Documentation/dev-tools/coccinelle.rst @@ -250,25 +250,17 @@ variables for .cocciconfig is as follows: - Your directory from which spatch is called is processed next - The directory provided with the ``--dir`` option is processed last, if used -Since coccicheck runs through make, it naturally runs from the kernel -proper dir; as such the second rule above would be implied for picking up a -.cocciconfig when using ``make coccicheck``. - ``make coccicheck`` also supports using M= targets. If you do not supply any M= target, it is assumed you want to target the entire kernel. The kernel coccicheck script has:: - if [ "$KBUILD_EXTMOD" = "" ] ; then - OPTIONS="--dir $srctree $COCCIINCLUDE" - else - OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE" - fi - -KBUILD_EXTMOD is set when an explicit target with M= is used. For both cases -the spatch ``--dir`` argument is used, as such third rule applies when whether -M= is used or not, and when M= is used the target directory can have its own -.cocciconfig file. When M= is not passed as an argument to coccicheck the -target directory is the same as the directory from where spatch was called. + OPTIONS="--dir $srcroot $COCCIINCLUDE" + +Here, $srcroot refers to the source directory of the target: it points to the +external module's source directory when M= used, and otherwise, to the kernel +source directory. The third rule ensures the spatch reads the .cocciconfig from +the target directory, allowing external modules to have their own .cocciconfig +file. If not using the kernel's coccicheck target, keep the above precedence order logic of .cocciconfig reading. If using the kernel's coccicheck target, diff --git a/Documentation/dev-tools/gcov.rst b/Documentation/dev-tools/gcov.rst index dbd26b02ff3c94..075df6a4598d8e 100644 --- a/Documentation/dev-tools/gcov.rst +++ b/Documentation/dev-tools/gcov.rst @@ -23,7 +23,7 @@ Possible uses: associated code is never run?) .. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html -.. _lcov: http://ltp.sourceforge.net/coverage/lcov.php +.. _lcov: https://github.com/linux-test-project/lcov Preparation diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst index 53d4d124f9c52f..3c0ac08b270911 100644 --- a/Documentation/dev-tools/index.rst +++ b/Documentation/dev-tools/index.rst @@ -34,6 +34,8 @@ Documentation/dev-tools/testing-overview.rst ktap checkuapi gpio-sloppy-logic-analyzer + autofdo + propeller .. only:: subproject and html diff --git a/Documentation/dev-tools/kasan.rst b/Documentation/dev-tools/kasan.rst index d7de44f5339d43..0a1418ab72fdfc 100644 --- a/Documentation/dev-tools/kasan.rst +++ b/Documentation/dev-tools/kasan.rst @@ -511,19 +511,14 @@ Tests ~~~~~ There are KASAN tests that allow verifying that KASAN works and can detect -certain types of memory corruptions. The tests consist of two parts: +certain types of memory corruptions. -1. Tests that are integrated with the KUnit Test Framework. Enabled with -``CONFIG_KASAN_KUNIT_TEST``. These tests can be run and partially verified +All KASAN tests are integrated with the KUnit Test Framework and can be enabled +via ``CONFIG_KASAN_KUNIT_TEST``. The tests can be run and partially verified automatically in a few different ways; see the instructions below. -2. Tests that are currently incompatible with KUnit. Enabled with -``CONFIG_KASAN_MODULE_TEST`` and can only be run as a module. These tests can -only be verified manually by loading the kernel module and inspecting the -kernel log for KASAN reports. - -Each KUnit-compatible KASAN test prints one of multiple KASAN reports if an -error is detected. Then the test prints its number and status. +Each KASAN test prints one of multiple KASAN reports if an error is detected. +Then the test prints its number and status. When a test passes:: @@ -550,16 +545,16 @@ Or, if one of the tests failed:: not ok 1 - kasan -There are a few ways to run KUnit-compatible KASAN tests. +There are a few ways to run the KASAN tests. 1. Loadable module - With ``CONFIG_KUNIT`` enabled, KASAN-KUnit tests can be built as a loadable - module and run by loading ``kasan_test.ko`` with ``insmod`` or ``modprobe``. + With ``CONFIG_KUNIT`` enabled, the tests can be built as a loadable module + and run by loading ``kasan_test.ko`` with ``insmod`` or ``modprobe``. 2. Built-In - With ``CONFIG_KUNIT`` built-in, KASAN-KUnit tests can be built-in as well. + With ``CONFIG_KUNIT`` built-in, the tests can be built-in as well. In this case, the tests will run at boot as a late-init call. 3. Using kunit_tool diff --git a/Documentation/dev-tools/kgdb.rst b/Documentation/dev-tools/kgdb.rst index f83ba2601e55d5..cb626a7a000c41 100644 --- a/Documentation/dev-tools/kgdb.rst +++ b/Documentation/dev-tools/kgdb.rst @@ -75,11 +75,11 @@ supports it for the architecture you are using, you can use hardware breakpoints if you desire to run with the ``CONFIG_STRICT_KERNEL_RWX`` option turned on, else you need to turn off this option. -Next you should choose one of more I/O drivers to interconnect debugging +Next you should choose one or more I/O drivers to interconnect the debugging host and debugged target. Early boot debugging requires a KGDB I/O driver that supports early debugging and the driver must be built into the kernel directly. Kgdb I/O driver configuration takes place via -kernel or module parameters which you can learn more about in the in the +kernel or module parameters which you can learn more about in the section that describes the parameter kgdboc. Here is an example set of ``.config`` symbols to enable or disable for kgdb:: @@ -201,8 +201,8 @@ Using loadable module or built-in Configure kgdboc at runtime with sysfs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -At run time you can enable or disable kgdboc by echoing a parameters -into the sysfs. Here are two examples: +At run time you can enable or disable kgdboc by writing parameters +into sysfs. Here are two examples: 1. Enable kgdboc on ttyS0:: @@ -329,7 +329,7 @@ ways to activate this feature. 2. Use sysfs before configuring an I/O driver:: - echo 1 > /sys/module/kgdb/parameters/kgdb_use_con + echo 1 > /sys/module/debug_core/parameters/kgdb_use_con .. note:: @@ -374,10 +374,10 @@ default behavior is always set to 0. Kernel parameter: ``nokaslr`` ----------------------------- -If the architecture that you are using enable KASLR by default, +If the architecture that you are using enables KASLR by default, you should consider turning it off. KASLR randomizes the -virtual address where the kernel image is mapped and confuse -gdb which resolve kernel symbol address from symbol table +virtual address where the kernel image is mapped and confuses +gdb which resolves addresses of kernel symbols from the symbol table of vmlinux. Using kdb @@ -631,8 +631,6 @@ automatically changes into kgdb mode. kgdb - Now disconnect your terminal program and connect gdb in its place - 2. At the kdb prompt, disconnect the terminal program and connect gdb in its place. @@ -749,7 +747,7 @@ The kernel debugger is organized into a number of components: helper functions in some of the other kernel components to make it possible for kdb to examine and report information about the kernel without taking locks that could cause a kernel deadlock. The kdb core - contains implements the following functionality. + implements the following functionality. - A simple shell diff --git a/Documentation/dev-tools/kmemleak.rst b/Documentation/dev-tools/kmemleak.rst index 2cb00b53339fe9..7d784e03f3f9d5 100644 --- a/Documentation/dev-tools/kmemleak.rst +++ b/Documentation/dev-tools/kmemleak.rst @@ -161,6 +161,7 @@ See the include/linux/kmemleak.h header for the functions prototype. - ``kmemleak_free_percpu`` - notify of a percpu memory block freeing - ``kmemleak_update_trace`` - update object allocation stack trace - ``kmemleak_not_leak`` - mark an object as not a leak +- ``kmemleak_transient_leak`` - mark an object as a transient leak - ``kmemleak_ignore`` - do not scan or report an object as leak - ``kmemleak_scan_area`` - add scan areas inside a memory block - ``kmemleak_no_scan`` - do not scan a memory block diff --git a/Documentation/dev-tools/kmsan.rst b/Documentation/dev-tools/kmsan.rst index 6a48d96c5c85b3..0dc668b183f6c1 100644 --- a/Documentation/dev-tools/kmsan.rst +++ b/Documentation/dev-tools/kmsan.rst @@ -133,7 +133,7 @@ KMSAN shadow memory ------------------- KMSAN associates a metadata byte (also called shadow byte) with every byte of -kernel memory. A bit in the shadow byte is set iff the corresponding bit of the +kernel memory. A bit in the shadow byte is set if the corresponding bit of the kernel memory byte is uninitialized. Marking the memory uninitialized (i.e. setting its shadow bytes to ``0xff``) is called poisoning, marking it initialized (setting the shadow bytes to ``0x00``) is called unpoisoning. diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst index f3766e326d1e33..fdb1df86783a5a 100644 --- a/Documentation/dev-tools/kselftest.rst +++ b/Documentation/dev-tools/kselftest.rst @@ -31,6 +31,15 @@ kselftest runs as a userspace process. Tests that can be written/run in userspace may wish to use the `Test Harness`_. Tests that need to be run in kernel space may wish to use a `Test Module`_. +Documentation on the tests +========================== + +For documentation on the kselftests themselves, see: + +.. toctree:: + + testing-devices + Running the selftests (hotplug tests are run in limited mode) ============================================================= diff --git a/Documentation/dev-tools/propeller.rst b/Documentation/dev-tools/propeller.rst new file mode 100644 index 00000000000000..92195958e3dbca --- /dev/null +++ b/Documentation/dev-tools/propeller.rst @@ -0,0 +1,162 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================================== +Using Propeller with the Linux kernel +===================================== + +This enables Propeller build support for the kernel when using Clang +compiler. Propeller is a profile-guided optimization (PGO) method used +to optimize binary executables. Like AutoFDO, it utilizes hardware +sampling to gather information about the frequency of execution of +different code paths within a binary. Unlike AutoFDO, this information +is then used right before linking phase to optimize (among others) +block layout within and across functions. + +A few important notes about adopting Propeller optimization: + +#. Although it can be used as a standalone optimization step, it is + strongly recommended to apply Propeller on top of AutoFDO, + AutoFDO+ThinLTO or Instrument FDO. The rest of this document + assumes this paradigm. + +#. Propeller uses another round of profiling on top of + AutoFDO/AutoFDO+ThinLTO/iFDO. The whole build process involves + "build-afdo - train-afdo - build-propeller - train-propeller - + build-optimized". + +#. Propeller requires LLVM 19 release or later for Clang/Clang++ + and the linker(ld.lld). + +#. In addition to LLVM toolchain, Propeller requires a profiling + conversion tool: https://github.com/google/autofdo with a release + after v0.30.1: https://github.com/google/autofdo/releases/tag/v0.30.1. + +The Propeller optimization process involves the following steps: + +#. Initial building: Build the AutoFDO or AutoFDO+ThinLTO binary as + you would normally do, but with a set of compile-time / link-time + flags, so that a special metadata section is created within the + kernel binary. The special section is only intend to be used by the + profiling tool, it is not part of the runtime image, nor does it + change kernel run time text sections. + +#. Profiling: The above kernel is then run with a representative + workload to gather execution frequency data. This data is collected + using hardware sampling, via perf. Propeller is most effective on + platforms supporting advanced PMU features like LBR on Intel + machines. This step is the same as profiling the kernel for AutoFDO + (the exact perf parameters can be different). + +#. Propeller profile generation: Perf output file is converted to a + pair of Propeller profiles via an offline tool. + +#. Optimized build: Build the AutoFDO or AutoFDO+ThinLTO optimized + binary as you would normally do, but with a compile-time / + link-time flag to pick up the Propeller compile time and link time + profiles. This build step uses 3 profiles - the AutoFDO profile, + the Propeller compile-time profile and the Propeller link-time + profile. + +#. Deployment: The optimized kernel binary is deployed and used + in production environments, providing improved performance + and reduced latency. + +Preparation +=========== + +Configure the kernel with:: + + CONFIG_AUTOFDO_CLANG=y + CONFIG_PROPELLER_CLANG=y + +Customization +============= + +The default CONFIG_PROPELLER_CLANG setting covers kernel space objects +for Propeller builds. One can, however, enable or disable Propeller build +for individual files and directories by adding a line similar to the +following to the respective kernel Makefile: + +- For enabling a single file (e.g. foo.o):: + + PROPELLER_PROFILE_foo.o := y + +- For enabling all files in one directory:: + + PROPELLER_PROFILE := y + +- For disabling one file:: + + PROPELLER_PROFILE_foo.o := n + +- For disabling all files in one directory:: + + PROPELLER__PROFILE := n + + +Workflow +======== + +Here is an example workflow for building an AutoFDO+Propeller kernel: + +1) Assuming an AutoFDO profile is already collected following + instructions in the AutoFDO document, build the kernel on the host + machine, with AutoFDO and Propeller build configs :: + + CONFIG_AUTOFDO_CLANG=y + CONFIG_PROPELLER_CLANG=y + + and :: + + $ make LLVM=1 CLANG_AUTOFDO_PROFILE= + +2) Install the kernel on the test machine. + +3) Run the load tests. The '-c' option in perf specifies the sample + event period. We suggest using a suitable prime number, like 500009, + for this purpose. + + - For Intel platforms:: + + $ perf record -e BR_INST_RETIRED.NEAR_TAKEN:k -a -N -b -c -o -- + + - For AMD platforms:: + + $ perf record --pfm-event RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a -N -b -c -o -- + + Note you can repeat the above steps to collect multiple s. + +4) (Optional) Download the raw perf file(s) to the host machine. + +5) Use the create_llvm_prof tool (https://github.com/google/autofdo) to + generate Propeller profile. :: + + $ create_llvm_prof --binary= --profile= + --format=propeller --propeller_output_module_name + --out=_cc_profile.txt + --propeller_symorder=_ld_profile.txt + + "" can be something like "/home/user/dir/any_string". + + This command generates a pair of Propeller profiles: + "_cc_profile.txt" and + "_ld_profile.txt". + + If there are more than 1 perf_file collected in the previous step, + you can create a temp list file "" with each line + containing one perf file name and run:: + + $ create_llvm_prof --binary= --profile=@ + --format=propeller --propeller_output_module_name + --out=_cc_profile.txt + --propeller_symorder=_ld_profile.txt + +6) Rebuild the kernel using the AutoFDO and Propeller + profiles. :: + + CONFIG_AUTOFDO_CLANG=y + CONFIG_PROPELLER_CLANG=y + + and :: + + $ make LLVM=1 CLANG_AUTOFDO_PROFILE= CLANG_PROPELLER_PROFILE_PREFIX= diff --git a/Documentation/dev-tools/testing-devices.rst b/Documentation/dev-tools/testing-devices.rst new file mode 100644 index 00000000000000..ab26adb9905110 --- /dev/null +++ b/Documentation/dev-tools/testing-devices.rst @@ -0,0 +1,47 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (c) 2024 Collabora Ltd + +============================= +Device testing with kselftest +============================= + + +There are a few different kselftests available for testing devices generically, +with some overlap in coverage and different requirements. This document aims to +give an overview of each one. + +Note: Paths in this document are relative to the kselftest folder +(``tools/testing/selftests``). + +Device oriented kselftests: + +* Devicetree (``dt``) + + * **Coverage**: Probe status for devices described in Devicetree + * **Requirements**: None + +* Error logs (``devices/error_logs``) + + * **Coverage**: Error (or more critical) log messages presence coming from any + device + * **Requirements**: None + +* Discoverable bus (``devices/probe``) + + * **Coverage**: Presence and probe status of USB or PCI devices that have been + described in the reference file + * **Requirements**: Manually describe the devices that should be tested in a + YAML reference file (see ``devices/probe/boards/google,spherion.yaml`` for + an example) + +* Exist (``devices/exist``) + + * **Coverage**: Presence of all devices + * **Requirements**: Generate the reference (see ``devices/exist/README.rst`` + for details) on a known-good kernel + +Therefore, the suggestion is to enable the error log and devicetree tests on all +(DT-based) platforms, since they don't have any requirements. Then to greatly +improve coverage, generate the reference for each platform and enable the exist +test. The discoverable bus test can be used to verify the probe status of +specific USB or PCI devices, but is probably not worth it for most cases. diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile index bf7d64632e20af..8390d6c00030ac 100644 --- a/Documentation/devicetree/bindings/Makefile +++ b/Documentation/devicetree/bindings/Makefile @@ -56,7 +56,6 @@ DT_DOCS = $(patsubst $(srctree)/%,%,$(shell $(find_all_cmd))) override DTC_FLAGS := \ -Wno-avoid_unnecessary_addr_size \ -Wno-graph_child_address \ - -Wno-interrupt_provider \ -Wno-unique_unit_address \ -Wunique_unit_address_if_enabled diff --git a/Documentation/devicetree/bindings/arm/airoha,en7581-chip-scu.yaml b/Documentation/devicetree/bindings/arm/airoha,en7581-chip-scu.yaml new file mode 100644 index 00000000000000..67c449d804c22b --- /dev/null +++ b/Documentation/devicetree/bindings/arm/airoha,en7581-chip-scu.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/airoha,en7581-chip-scu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha Chip SCU Controller for EN7581 SoC + +maintainers: + - Lorenzo Bianconi + +description: + The airoha chip-scu block provides a configuration interface for clock, + io-muxing and other functionalities used by multiple controllers (e.g. clock, + pinctrl, ecc) on EN7581 SoC. + +properties: + compatible: + items: + - enum: + - airoha,en7581-chip-scu + - const: syscon + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + syscon@1fa20000 { + compatible = "airoha,en7581-chip-scu", "syscon"; + reg = <0x0 0x1fa20000 0x0 0x388>; + }; + }; diff --git a/Documentation/devicetree/bindings/arm/apple.yaml b/Documentation/devicetree/bindings/arm/apple.yaml index 883fd67e375272..dc9aab19ff11d5 100644 --- a/Documentation/devicetree/bindings/arm/apple.yaml +++ b/Documentation/devicetree/bindings/arm/apple.yaml @@ -12,7 +12,58 @@ maintainers: description: | ARM platforms using SoCs designed by Apple Inc., branded "Apple Silicon". - This currently includes devices based on the "M1" SoC: + This currently includes devices based on the "A7" SoC: + + - iPhone 5s + - iPad Air (1) + - iPad mini 2 + - iPad mini 3 + + Devices based on the "A8" SoC: + + - iPhone 6 + - iPhone 6 Plus + - iPad mini 4 + - iPod touch 6 + - Apple TV HD + + Device based on the "A8X" SoC: + + - iPad Air 2 + + Devices based on the "A9" SoC: + + - iPhone 6s + - iPhone 6s Plus + - iPhone SE (2016) + - iPad 5 + + Devices based on the "A9X" SoC: + + - iPad Pro (9.7-inch) + - iPad Pro (12.9-inch) + + Devices based on the "A10" SoC: + + - iPhone 7 + - iPhone 7 Plus + - iPod touch 7 + - iPad 6 + - iPad 7 + + Devices based on the "A10X" SoC: + + - Apple TV 4K (1st generation) + - iPad Pro (2nd Generation) (10.5 Inch) + - iPad Pro (2nd Generation) (12.9 Inch) + + Devices based on the "A11" SoC: + + - iPhone 8 + - iPhone 8 Plus + - iPhone X + + Devices based on the "M1" SoC: - Mac mini (M1, 2020) - MacBook Pro (13-inch, M1, 2020) @@ -65,6 +116,113 @@ properties: const: "/" compatible: oneOf: + - description: Apple A7 SoC based platforms + items: + - enum: + - apple,j71 # iPad Air (Wi-Fi) + - apple,j72 # iPad Air (Cellular) + - apple,j73 # iPad Air (Cellular, China) + - apple,j85 # iPad mini 2 (Wi-Fi) + - apple,j85m # iPad mini 3 (Wi-Fi) + - apple,j86 # iPad mini 2 (Cellular) + - apple,j86m # iPad mini 3 (Cellular) + - apple,j87 # iPad mini 2 (Cellular, China) + - apple,j87m # iPad mini 3 (Cellular, China) + - apple,n51 # iPhone 5s (GSM) + - apple,n53 # iPhone 5s (LTE) + - const: apple,s5l8960x + - const: apple,arm-platform + + - description: Apple A8 SoC based platforms + items: + - enum: + - apple,j42d # Apple TV HD + - apple,j96 # iPad mini 4 (Wi-Fi) + - apple,j97 # iPad mini 4 (Cellular) + - apple,n56 # iPhone 6 Plus + - apple,n61 # iPhone 6 + - apple,n102 # iPod touch 6 + - const: apple,t7000 + - const: apple,arm-platform + + - description: Apple A8X SoC based platforms + items: + - enum: + - apple,j81 # iPad Air 2 (Wi-Fi) + - apple,j82 # iPad Air 2 (Cellular) + - const: apple,t7001 + - const: apple,arm-platform + + - description: Apple Samsung A9 SoC based platforms + items: + - enum: + - apple,j71s # iPad 5 (Wi-Fi) (S8000) + - apple,j72s # iPad 5 (Cellular) (S8000) + - apple,n66 # iPhone 6s Plus (S8000) + - apple,n69u # iPhone SE (S8000) + - apple,n71 # iPhone 6S (S8000) + - const: apple,s8000 + - const: apple,arm-platform + + - description: Apple TSMC A9 SoC based platforms + items: + - enum: + - apple,j71t # iPad 5 (Wi-Fi) (S8003) + - apple,j72t # iPad 5 (Cellular) (S8003) + - apple,n66m # iPhone 6s Plus (S8003) + - apple,n69 # iPhone SE (S8003) + - apple,n71m # iPhone 6S (S8003) + - const: apple,s8003 + - const: apple,arm-platform + + - description: Apple A9X SoC based platforms + items: + - enum: + - apple,j127 # iPad Pro (9.7-inch) (Wi-Fi) + - apple,j128 # iPad Pro (9.7-inch) (Cellular) + - apple,j98a # iPad Pro (12.9-inch) (Wi-Fi) + - apple,j99a # iPad Pro (12.9-inch) (Cellular) + - const: apple,s8001 + - const: apple,arm-platform + + - description: Apple A10 SoC based platforms + items: + - enum: + - apple,d10 # iPhone 7 (Qualcomm) + - apple,d11 # iPhone 7 (Intel) + - apple,d101 # iPhone 7 Plus (Qualcomm) + - apple,d111 # iPhone 7 Plus (Intel) + - apple,j71b # iPad 6 (Wi-Fi) + - apple,j72b # iPad 6 (Cellular) + - apple,j171 # iPad 7 (Wi-Fi) + - apple,j172 # iPad 7 (Cellular) + - apple,n112 # iPod touch 7 + - const: apple,t8010 + - const: apple,arm-platform + + - description: Apple A10X SoC based platforms + items: + - enum: + - apple,j105a # Apple TV 4K (1st Generation) + - apple,j120 # iPad Pro 2 (12.9-inch) (Wi-Fi) + - apple,j121 # iPad Pro 2 (12.9-inch) (Cellular) + - apple,j207 # iPad Pro 2 (10.5-inch) (Wi-Fi) + - apple,j208 # iPad Pro 2 (10.5-inch) (Cellular) + - const: apple,t8011 + - const: apple,arm-platform + + - description: Apple A11 SoC based platforms + items: + - enum: + - apple,d20 # iPhone 8 (Global) + - apple,d21 # iPhone 8 Plus (Global) + - apple,d22 # iPhone X (Global) + - apple,d201 # iPhone 8 (GSM) + - apple,d211 # iPhone 8 Plus (GSM) + - apple,d221 # iPhone X (GSM) + - const: apple,t8015 + - const: apple,arm-platform + - description: Apple M1 SoC based platforms items: - enum: diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.yaml b/Documentation/devicetree/bindings/arm/atmel-at91.yaml index 82f37328cc694c..7160ec80ac1b05 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.yaml +++ b/Documentation/devicetree/bindings/arm/atmel-at91.yaml @@ -106,6 +106,12 @@ properties: - const: microchip,sam9x60 - const: atmel,at91sam9 + - description: Microchip SAM9X7 Evaluation Boards + items: + - const: microchip,sam9x75-curiosity + - const: microchip,sam9x7 + - const: atmel,at91sam9 + - description: Nattis v2 board with Natte v2 power board items: - const: axentia,nattis-2 diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index f308ff6c3532e2..73dd73d2d4fa22 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -87,8 +87,14 @@ properties: enum: - apple,avalanche - apple,blizzard - - apple,icestorm + - apple,cyclone - apple,firestorm + - apple,hurricane-zephyr + - apple,icestorm + - apple,mistral + - apple,monsoon + - apple,twister + - apple,typhoon - arm,arm710t - arm,arm720t - arm,arm740t @@ -202,10 +208,14 @@ properties: - qcom,kryo560 - qcom,kryo570 - qcom,kryo660 + - qcom,kryo670 - qcom,kryo685 - qcom,kryo780 - qcom,oryon - qcom,scorpion + - samsung,mongoose-m2 + - samsung,mongoose-m3 + - samsung,mongoose-m5 enable-method: $ref: /schemas/types.yaml#/definitions/string diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index b39a7e031177e6..6e0dcf4307f100 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -379,7 +379,9 @@ properties: - description: i.MX6Q PHYTEC phyFLEX-i.MX6 items: - - const: phytec,imx6q-pbab01 # PHYTEC phyFLEX carrier board + - enum: + - comvetia,imx6q-lxr # Comvetia LXR board + - phytec,imx6q-pbab01 # PHYTEC phyFLEX carrier board - const: phytec,imx6q-pfla02 # PHYTEC phyFLEX-i.MX6 Quad - const: fsl,imx6q @@ -523,9 +525,11 @@ properties: - const: dfi,fs700e-m60 - const: fsl,imx6dl - - description: i.MX6DL DHCOM PicoITX Board + - description: i.MX6DL DHCOM based Boards items: - - const: dh,imx6dl-dhcom-picoitx + - enum: + - dh,imx6dl-dhcom-pdk2 # i.MX6DL DHCOM SoM on PDK2 board + - dh,imx6dl-dhcom-picoitx # i.MX6DL DHCOM SoM on PicoITX board - const: dh,imx6dl-dhcom-som - const: fsl,imx6dl @@ -620,6 +624,14 @@ properties: - kobo,librah2o - const: fsl,imx6sll + - description: i.MX6SLL Kobo Clara 2e Rev. A/B + items: + - enum: + - kobo,clara2e-a + - kobo,clara2e-b + - const: kobo,clara2e + - const: fsl,imx6sll + - description: i.MX6SX based Boards items: - enum: @@ -995,6 +1007,7 @@ properties: - menlo,mx8menlo # Verdin iMX8M Mini Module on i.MX8MM Menlo board - toradex,verdin-imx8mm-nonwifi-dahlia # Verdin iMX8M Mini Module on Dahlia - toradex,verdin-imx8mm-nonwifi-dev # Verdin iMX8M Mini Module on Verdin Development Board + - toradex,verdin-imx8mm-nonwifi-ivy # Verdin iMX8M Mini Module on Ivy - toradex,verdin-imx8mm-nonwifi-mallow # Verdin iMX8M Mini Module on Mallow - toradex,verdin-imx8mm-nonwifi-yavia # Verdin iMX8M Mini Module on Yavia - const: toradex,verdin-imx8mm-nonwifi # Verdin iMX8M Mini Module without Wi-Fi / BT @@ -1006,6 +1019,7 @@ properties: - enum: - toradex,verdin-imx8mm-wifi-dahlia # Verdin iMX8M Mini Wi-Fi / BT Module on Dahlia - toradex,verdin-imx8mm-wifi-dev # Verdin iMX8M Mini Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-imx8mm-wifi-ivy # Verdin iMX8M Mini Wi-Fi / BT Module on Ivy - toradex,verdin-imx8mm-wifi-mallow # Verdin iMX8M Mini Wi-Fi / BT Module on Mallow - toradex,verdin-imx8mm-wifi-yavia # Verdin iMX8M Mini Wi-Fi / BT Module on Yavia - const: toradex,verdin-imx8mm-wifi # Verdin iMX8M Mini Wi-Fi / BT Module @@ -1082,12 +1096,14 @@ properties: - gateworks,imx8mp-gw73xx-2x # i.MX8MP Gateworks Board - gateworks,imx8mp-gw74xx # i.MX8MP Gateworks Board - gateworks,imx8mp-gw75xx-2x # i.MX8MP Gateworks Board + - gateworks,imx8mp-gw82xx-2x # i.MX8MP Gateworks Board - skov,imx8mp-skov-revb-hdmi # SKOV i.MX8MP climate control without panel - skov,imx8mp-skov-revb-lt6 # SKOV i.MX8MP climate control with 7” panel - skov,imx8mp-skov-revb-mi1010ait-1cp1 # SKOV i.MX8MP climate control with 10.1" panel - toradex,verdin-imx8mp # Verdin iMX8M Plus Modules - toradex,verdin-imx8mp-nonwifi # Verdin iMX8M Plus Modules without Wi-Fi / BT - toradex,verdin-imx8mp-wifi # Verdin iMX8M Plus Wi-Fi / BT Modules + - ysoft,imx8mp-iota2-lumpy # Y Soft i.MX8MP IOTA2 Lumpy Board - const: fsl,imx8mp - description: Avnet (MSC Branded) Boards with SM2S i.MX8M Plus Modules @@ -1097,11 +1113,19 @@ properties: - const: avnet,sm2s-imx8mp # SM2S-IMX8PLUS SoM - const: fsl,imx8mp + - description: Boundary Device Nitrogen8MP Universal SMARC Carrier Board + items: + - const: boundary,imx8mp-nitrogen-smarc-universal-board + - const: boundary,imx8mp-nitrogen-smarc-som + - const: fsl,imx8mp + - description: i.MX8MP DHCOM based Boards items: - enum: + - dh,imx8mp-dhcom-drc02 # i.MX8MP DHCOM SoM on DRC02 board - dh,imx8mp-dhcom-pdk2 # i.MX8MP DHCOM SoM on PDK2 board - dh,imx8mp-dhcom-pdk3 # i.MX8MP DHCOM SoM on PDK3 board + - dh,imx8mp-dhcom-picoitx # i.MX8MP DHCOM SoM on PicoITX board - const: dh,imx8mp-dhcom-som # i.MX8MP DHCOM SoM - const: fsl,imx8mp @@ -1112,6 +1136,19 @@ properties: - const: engicam,icore-mx8mp # i.MX8MP Engicam i.Core MX8M Plus SoM - const: fsl,imx8mp + - description: Kontron i.MX8MP OSM-S SoM based Boards + items: + - const: kontron,imx8mp-bl-osm-s # Kontron BL i.MX8MP OSM-S Board + - const: kontron,imx8mp-osm-s # Kontron i.MX8MP OSM-S SoM + - const: fsl,imx8mp + + - description: Kontron i.MX8MP SMARC based Boards + items: + - const: kontron,imx8mp-smarc-eval-carrier # Kontron i.MX8MP SMARC Eval Carrier + - const: kontron,imx8mp-smarc # Kontron i.MX8MP SMARC Module + - const: kontron,imx8mp-osm-s # Kontron i.MX8MP OSM-S SoM + - const: fsl,imx8mp + - description: PHYTEC phyCORE-i.MX8MP SoM based boards items: - const: phytec,imx8mp-phyboard-pollux-rdk # phyBOARD-Pollux RDK @@ -1137,6 +1174,7 @@ properties: - enum: - toradex,verdin-imx8mp-nonwifi-dahlia # Verdin iMX8M Plus Module on Dahlia - toradex,verdin-imx8mp-nonwifi-dev # Verdin iMX8M Plus Module on Verdin Development Board + - toradex,verdin-imx8mp-nonwifi-ivy # Verdin iMX8M Plus Module on Ivy - toradex,verdin-imx8mp-nonwifi-mallow # Verdin iMX8M Plus Module on Mallow - toradex,verdin-imx8mp-nonwifi-yavia # Verdin iMX8M Plus Module on Yavia - const: toradex,verdin-imx8mp-nonwifi # Verdin iMX8M Plus Module without Wi-Fi / BT @@ -1148,6 +1186,7 @@ properties: - enum: - toradex,verdin-imx8mp-wifi-dahlia # Verdin iMX8M Plus Wi-Fi / BT Module on Dahlia - toradex,verdin-imx8mp-wifi-dev # Verdin iMX8M Plus Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-imx8mp-wifi-ivy # Verdin iMX8M Plus Wi-Fi / BT Module on Ivy - toradex,verdin-imx8mp-wifi-mallow # Verdin iMX8M Plus Wi-Fi / BT Module on Mallow - toradex,verdin-imx8mp-wifi-yavia # Verdin iMX8M Plus Wi-Fi / BT Module on Yavia - const: toradex,verdin-imx8mp-wifi # Verdin iMX8M Plus Wi-Fi / BT Module diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml index b3c6888c14573d..3f4262e93c789c 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml @@ -93,6 +93,34 @@ properties: '#reset-cells': const: 1 + port: + $ref: /schemas/graph.yaml#/properties/port + description: + Output port node. This port connects the MMSYS/VDOSYS output to + the first component of one display pipeline, for example one of + the available OVL or RDMA blocks. + Some MediaTek SoCs support multiple display outputs per MMSYS. + properties: + endpoint@0: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Output to the primary display pipeline + + endpoint@1: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Output to the secondary display pipeline + + endpoint@2: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Output to the tertiary display pipeline + + anyOf: + - required: + - endpoint@0 + - required: + - endpoint@1 + - required: + - endpoint@2 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/arm/pmu.yaml b/Documentation/devicetree/bindings/arm/pmu.yaml index 528544d0a1614c..a148ff54f2b8a9 100644 --- a/Documentation/devicetree/bindings/arm/pmu.yaml +++ b/Documentation/devicetree/bindings/arm/pmu.yaml @@ -74,6 +74,7 @@ properties: - qcom,krait-pmu - qcom,scorpion-pmu - qcom,scorpion-mp-pmu + - samsung,mongoose-pmu interrupts: # Don't know how many CPUs, so no constraints to specify diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 5cb54d69af0b72..9679fed7259b95 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -45,6 +45,7 @@ description: | qcs8550 qcm2290 qcm6490 + qcs9100 qdu1000 qrb2210 qrb4210 @@ -76,6 +77,7 @@ description: | sm6375 sm7125 sm7225 + sm7325 sm8150 sm8250 sm8350 @@ -821,6 +823,7 @@ properties: - items: - enum: - lenovo,thinkpad-x13s + - microsoft,arcata - qcom,sc8280xp-crd - qcom,sc8280xp-qrd - const: qcom,sc8280xp @@ -912,6 +915,13 @@ properties: - qcom,sa8775p-ride-r3 - const: qcom,sa8775p + - items: + - enum: + - qcom,qcs9100-ride + - qcom,qcs9100-ride-r3 + - const: qcom,qcs9100 + - const: qcom,sa8775p + - items: - enum: - google,cheza @@ -989,6 +999,11 @@ properties: - fairphone,fp4 - const: qcom,sm7225 + - items: + - enum: + - nothing,spacewar + - const: qcom,sm7325 + - items: - enum: - microsoft,surface-duo @@ -1058,6 +1073,7 @@ properties: - items: - enum: - asus,vivobook-s15 + - dell,xps13-9345 - lenovo,yoga-slim7x - microsoft,romulus13 - microsoft,romulus15 diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index 687823e58c2257..753199a12923fa 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -49,11 +49,23 @@ properties: - anbernic,rg-arc-s - const: rockchip,rk3566 + - description: ArmSoM Sige5 board + items: + - const: armsom,sige5 + - const: rockchip,rk3576 + - description: ArmSoM Sige7 board items: - const: armsom,sige7 - const: rockchip,rk3588 + - description: ArmSoM LM7 SoM + items: + - enum: + - armsom,w3 + - const: armsom,lm7 + - const: rockchip,rk3588 + - description: Asus Tinker board items: - const: asus,rk3288-tinker @@ -232,6 +244,11 @@ properties: - friendlyarm,nanopi-r2s-plus - const: rockchip,rk3328 + - description: FriendlyElec NanoPi R3S + items: + - const: friendlyarm,nanopi-r3s + - const: rockchip,rk3566 + - description: FriendlyElec NanoPi4 series boards items: - enum: @@ -760,6 +777,7 @@ properties: items: - enum: - powkiddy,rgb10max3 + - powkiddy,rgb20sx - powkiddy,rgb30 - powkiddy,rk2023 - powkiddy,x55 @@ -789,6 +807,11 @@ properties: - const: radxa,cm3i - const: rockchip,rk3568 + - description: Radxa E20C + items: + - const: radxa,e20c + - const: rockchip,rk3528 + - description: Radxa Rock items: - const: radxa,rock @@ -872,6 +895,11 @@ properties: - const: radxa,rock-5b - const: rockchip,rk3588 + - description: Radxa ROCK 5C + items: + - const: radxa,rock-5c + - const: rockchip,rk3588s + - description: Radxa ROCK S0 items: - const: radxa,rock-s0 @@ -884,6 +912,11 @@ properties: - radxa,zero-3w - const: rockchip,rk3566 + - description: Relfor SAIB board + items: + - const: relfor,saib + - const: rockchip,rv1109 + - description: Rikomagic MK808 v1 items: - const: rikomagic,mk808 @@ -978,6 +1011,11 @@ properties: - const: rockchip,rk3588-evb1-v10 - const: rockchip,rk3588 + - description: Rockchip RK3588S Evaluation board + items: + - const: rockchip,rk3588s-evb1-v10 + - const: rockchip,rk3588s + - description: Rockchip RV1108 Evaluation board items: - const: rockchip,rv1108-evb @@ -1051,7 +1089,9 @@ properties: - description: Xunlong Orange Pi 5 items: - - const: xunlong,orangepi-5 + - enum: + - xunlong,orangepi-5 + - xunlong,orangepi-5b - const: rockchip,rk3588s - description: Zkmagic A95X Z2 @@ -1069,6 +1109,11 @@ properties: - const: rockchip,rk3568-evb1-v10 - const: rockchip,rk3568 + - description: Sinovoip RK3308 Banana Pi P2 Pro + items: + - const: sinovoip,rk3308-bpi-p2pro + - const: rockchip,rk3308 + - description: Sinovoip RK3568 Banana Pi R2 Pro items: - const: sinovoip,rk3568-bpi-r2pro diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml index 01dcbd8aa70303..b5ba5ffc36d687 100644 --- a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml +++ b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml @@ -224,6 +224,24 @@ properties: - winlink,e850-96 # WinLink E850-96 - const: samsung,exynos850 + - description: Exynos8895 based boards + items: + - enum: + - samsung,dreamlte # Samsung Galaxy S8 (SM-G950F) + - const: samsung,exynos8895 + + - description: Exynos9810 based boards + items: + - enum: + - samsung,starlte # Samsung Galaxy S9 (SM-G960F) + - const: samsung,exynos9810 + + - description: Exynos990 based boards + items: + - enum: + - samsung,c1s # Samsung Galaxy Note20 5G (SM-N981B) + - const: samsung,exynos990 + - description: Exynos Auto v9 based boards items: - enum: diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml index 4aa15f3668e037..046536d02706f8 100644 --- a/Documentation/devicetree/bindings/arm/sunxi.yaml +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml @@ -846,6 +846,12 @@ properties: - const: allwinner,sun50i-h64 - const: allwinner,sun50i-a64 + - description: RerVision A33-Vstar (with A33-Core1 SoM) + items: + - const: rervision,a33-vstar + - const: rervision,a33-core1 + - const: allwinner,sun8i-a33 + - description: RerVision H3-DVK items: - const: rervision,h3-dvk diff --git a/Documentation/devicetree/bindings/arm/tegra.yaml b/Documentation/devicetree/bindings/arm/tegra.yaml index 2889fd0e65921d..65e0ff1fdf1ecd 100644 --- a/Documentation/devicetree/bindings/arm/tegra.yaml +++ b/Documentation/devicetree/bindings/arm/tegra.yaml @@ -217,6 +217,11 @@ properties: - const: nvidia,p3737-0000+p3701-0000 - const: nvidia,p3701-0000 - const: nvidia,tegra234 + - description: Jetson AGX Orin Developer Kit with Industrial Module + items: + - const: nvidia,p3737-0000+p3701-0008 + - const: nvidia,p3701-0008 + - const: nvidia,tegra234 - description: NVIDIA IGX Orin Development Kit items: - const: nvidia,p3740-0002+p3701-0008 diff --git a/Documentation/devicetree/bindings/arm/ti/k3.yaml b/Documentation/devicetree/bindings/arm/ti/k3.yaml index 5df99e361c2158..18f155cd06c840 100644 --- a/Documentation/devicetree/bindings/arm/ti/k3.yaml +++ b/Documentation/devicetree/bindings/arm/ti/k3.yaml @@ -56,6 +56,7 @@ properties: - enum: - toradex,verdin-am62-nonwifi-dahlia # Verdin AM62 Module on Dahlia - toradex,verdin-am62-nonwifi-dev # Verdin AM62 Module on Verdin Development Board + - toradex,verdin-am62-nonwifi-ivy # Verdin AM62 Module on Ivy - toradex,verdin-am62-nonwifi-mallow # Verdin AM62 Module on Mallow - toradex,verdin-am62-nonwifi-yavia # Verdin AM62 Module on Yavia - const: toradex,verdin-am62-nonwifi # Verdin AM62 Module without Wi-Fi / BT @@ -67,6 +68,7 @@ properties: - enum: - toradex,verdin-am62-wifi-dahlia # Verdin AM62 Wi-Fi / BT Module on Dahlia - toradex,verdin-am62-wifi-dev # Verdin AM62 Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-am62-wifi-ivy # Verdin AM62 Wi-Fi / BT Module on Ivy - toradex,verdin-am62-wifi-mallow # Verdin AM62 Wi-Fi / BT Module on Mallow - toradex,verdin-am62-wifi-yavia # Verdin AM62 Wi-Fi / BT Module on Yavia - const: toradex,verdin-am62-wifi # Verdin AM62 Wi-Fi / BT Module @@ -144,6 +146,12 @@ properties: - ti,j722s-evm - const: ti,j722s + - description: K3 J742S2 SoC + items: + - enum: + - ti,j742s2-evm + - const: ti,j742s2 + - description: K3 J784s4 SoC items: - enum: diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.yaml b/Documentation/devicetree/bindings/ata/ahci-platform.yaml index ef19468e302251..cc35cdc02840f5 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.yaml +++ b/Documentation/devicetree/bindings/ata/ahci-platform.yaml @@ -84,6 +84,9 @@ properties: minItems: 1 maxItems: 3 + iommus: + maxItems: 1 + patternProperties: "^sata-port@[0-9a-f]+$": $ref: /schemas/ata/ahci-common.yaml#/$defs/ahci-port diff --git a/Documentation/devicetree/bindings/cache/l2c2x0.yaml b/Documentation/devicetree/bindings/cache/l2c2x0.yaml index d7840a5c40375d..10c1a900202fc2 100644 --- a/Documentation/devicetree/bindings/cache/l2c2x0.yaml +++ b/Documentation/devicetree/bindings/cache/l2c2x0.yaml @@ -100,9 +100,8 @@ properties: filter. Addresses in the filter window are directed to the M1 port. Other addresses will go to the M0 port. $ref: /schemas/types.yaml#/definitions/uint32-array - items: - minItems: 2 - maxItems: 2 + minItems: 2 + maxItems: 2 arm,io-coherent: description: indicates that the system is operating in an hardware diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml index 68ea5f70b75f03..03b1941eaa33dd 100644 --- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml +++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml @@ -20,8 +20,12 @@ description: | properties: compatible: enum: + - qcom,qcs615-llcc + - qcom,qcs8300-llcc - qcom,qdu1000-llcc - qcom,sa8775p-llcc + - qcom,sar1130p-llcc + - qcom,sar2130p-llcc - qcom,sc7180-llcc - qcom,sc7280-llcc - qcom,sc8180x-llcc @@ -39,11 +43,11 @@ properties: reg: minItems: 2 - maxItems: 9 + maxItems: 10 reg-names: minItems: 2 - maxItems: 9 + maxItems: 10 interrupts: maxItems: 1 @@ -67,6 +71,33 @@ allOf: compatible: contains: enum: + - qcom,sar1130p-llcc + - qcom,sar2130p-llcc + then: + properties: + reg: + items: + - description: LLCC0 base register region + - description: LLCC1 base register region + - description: LLCC broadcast OR register region + - description: LLCC broadcast AND register region + - description: LLCC scratchpad broadcast OR register region + - description: LLCC scratchpad broadcast AND register region + reg-names: + items: + - const: llcc0_base + - const: llcc1_base + - const: llcc_broadcast_base + - const: llcc_broadcast_and_base + - const: llcc_scratchpad_broadcast_base + - const: llcc_scratchpad_broadcast_and_base + + - if: + properties: + compatible: + contains: + enum: + - qcom,qcs615-llcc - qcom,sc7180-llcc - qcom,sm6350-llcc then: @@ -134,6 +165,36 @@ allOf: - qcom,qdu1000-llcc - qcom,sc8180x-llcc - qcom,sc8280xp-llcc + then: + properties: + reg: + items: + - description: LLCC0 base register region + - description: LLCC1 base register region + - description: LLCC2 base register region + - description: LLCC3 base register region + - description: LLCC4 base register region + - description: LLCC5 base register region + - description: LLCC6 base register region + - description: LLCC7 base register region + - description: LLCC broadcast base register region + reg-names: + items: + - const: llcc0_base + - const: llcc1_base + - const: llcc2_base + - const: llcc3_base + - const: llcc4_base + - const: llcc5_base + - const: llcc6_base + - const: llcc7_base + - const: llcc_broadcast_base + + - if: + properties: + compatible: + contains: + enum: - qcom,x1e80100-llcc then: properties: @@ -148,6 +209,7 @@ allOf: - description: LLCC6 base register region - description: LLCC7 base register region - description: LLCC broadcast base register region + - description: LLCC broadcast AND register region reg-names: items: - const: llcc0_base @@ -159,12 +221,14 @@ allOf: - const: llcc6_base - const: llcc7_base - const: llcc_broadcast_base + - const: llcc_broadcast_and_base - if: properties: compatible: contains: enum: + - qcom,qcs8300-llcc - qcom,sdm845-llcc - qcom,sm8150-llcc - qcom,sm8250-llcc diff --git a/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt b/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt deleted file mode 100644 index d19885b7c73fc6..00000000000000 --- a/Documentation/devicetree/bindings/clock/actions,owl-cmu.txt +++ /dev/null @@ -1,52 +0,0 @@ -* Actions Semi Owl Clock Management Unit (CMU) - -The Actions Semi Owl Clock Management Unit generates and supplies clock -to various controllers within the SoC. The clock binding described here is -applicable to S900, S700 and S500 SoC's. - -Required Properties: - -- compatible: should be one of the following, - "actions,s900-cmu" - "actions,s700-cmu" - "actions,s500-cmu" -- reg: physical base address of the controller and length of memory mapped - region. -- clocks: Reference to the parent clocks ("hosc", "losc") -- #clock-cells: should be 1. -- #reset-cells: should be 1. - -Each clock is assigned an identifier, and client nodes can use this identifier -to specify the clock which they consume. - -All available clocks are defined as preprocessor macros in corresponding -dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h or -actions,s500-cmu.h header and can be used in device tree sources. - -External clocks: - -The hosc clock used as input for the plls is generated outside the SoC. It is -expected that it is defined using standard clock bindings as "hosc". - -Actions Semi S900 CMU also requires one more clock: - - "losc" - internal low frequency oscillator - -Example: Clock Management Unit node: - - cmu: clock-controller@e0160000 { - compatible = "actions,s900-cmu"; - reg = <0x0 0xe0160000 0x0 0x1000>; - clocks = <&hosc>, <&losc>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - -Example: UART controller node that consumes clock generated by the clock -management unit: - - uart: serial@e012a000 { - compatible = "actions,s900-uart", "actions,owl-uart"; - reg = <0x0 0xe012a000 0x0 0x2000>; - interrupts = ; - clocks = <&cmu CLK_UART5>; - }; diff --git a/Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml b/Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml new file mode 100644 index 00000000000000..28396441bc9898 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/actions,owl-cmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Actions Semi Owl Clock Management Unit (CMU) + +maintainers: + - Manivannan Sadhasivam + +description: | + The Actions Semi Owl Clock Management Unit generates and supplies clock + to various controllers within the SoC. + + See also: + include/dt-bindings/clock/actions,s500-cmu.h + include/dt-bindings/clock/actions,s700-cmu.h + include/dt-bindings/clock/actions,s900-cmu.h + +properties: + compatible: + enum: + - actions,s500-cmu + - actions,s700-cmu + - actions,s900-cmu + + reg: + maxItems: 1 + + clocks: + items: + - description: Host oscillator source + - description: Internal low frequency oscillator source + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - "#clock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + clock-controller@e0160000 { + compatible = "actions,s900-cmu"; + reg = <0xe0160000 0x1000>; + clocks = <&hosc>, <&losc>; + #clock-cells = <1>; + #reset-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml b/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml index 5e942bccf27787..2b2041818a0a44 100644 --- a/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml +++ b/Documentation/devicetree/bindings/clock/adi,axi-clkgen.yaml @@ -26,9 +26,21 @@ properties: description: Specifies the reference clock(s) from which the output frequency is derived. This must either reference one clock if only the first clock - input is connected or two if both clock inputs are connected. - minItems: 1 - maxItems: 2 + input is connected or two if both clock inputs are connected. The last + clock is the AXI bus clock that needs to be enabled so we can access the + core registers. + minItems: 2 + maxItems: 3 + + clock-names: + oneOf: + - items: + - const: clkin1 + - const: s_axi_aclk + - items: + - const: clkin1 + - const: clkin2 + - const: s_axi_aclk '#clock-cells': const: 0 @@ -40,6 +52,7 @@ required: - compatible - reg - clocks + - clock-names - '#clock-cells' additionalProperties: false @@ -50,5 +63,6 @@ examples: compatible = "adi,axi-clkgen-2.00.a"; #clock-cells = <0>; reg = <0xff000000 0x1000>; - clocks = <&osc 1>; + clocks = <&osc 1>, <&clkc 15>; + clock-names = "clkin1", "s_axi_aclk"; }; diff --git a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml index 84353fd09428f4..fe2c5c1baf4332 100644 --- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml @@ -34,8 +34,10 @@ properties: - airoha,en7581-scu reg: - minItems: 2 - maxItems: 4 + items: + - description: scu base address + - description: misc scu base address + minItems: 1 "#clock-cells": description: @@ -60,9 +62,7 @@ allOf: then: properties: reg: - items: - - description: scu base address - - description: misc scu base address + minItems: 2 '#reset-cells': false @@ -73,11 +73,7 @@ allOf: then: properties: reg: - items: - - description: scu base address - - description: misc scu base address - - description: reset base address - - description: pb scu base address + maxItems: 1 additionalProperties: false @@ -96,12 +92,9 @@ examples: #address-cells = <2>; #size-cells = <2>; - scuclk: clock-controller@1fa20000 { + scuclk: clock-controller@1fb00000 { compatible = "airoha,en7581-scu"; - reg = <0x0 0x1fa20000 0x0 0x400>, - <0x0 0x1fb00000 0x0 0x90>, - <0x0 0x1fb00830 0x0 0x8>, - <0x0 0x1fbe3400 0x0 0xfc>; + reg = <0x0 0x1fb00000 0x0 0x970>; #clock-cells = <1>; #reset-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml new file mode 100644 index 00000000000000..ab73d465417124 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.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/amlogic,meson8-clkc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Controller + +maintainers: + - Neil Armstrong + +properties: + compatible: + oneOf: + - enum: + - amlogic,meson8-clkc + - amlogic,meson8b-clkc + - items: + - const: amlogic,meson8m2-clkc + - const: amlogic,meson8-clkc + + clocks: + minItems: 2 + maxItems: 3 + + clock-names: + minItems: 2 + items: + - const: xtal + - const: ddr_pll + - const: clk_32k + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - clocks + - clock-names + - '#reset-cells' + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt deleted file mode 100644 index cc51e4746b3b77..00000000000000 --- a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt +++ /dev/null @@ -1,51 +0,0 @@ -* Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Unit - -The Amlogic Meson8 / Meson8b / Meson8m2 clock controller generates and -supplies clock to various controllers within the SoC. - -Required Properties: - -- compatible: must be one of: - - "amlogic,meson8-clkc" for Meson8 (S802) SoCs - - "amlogic,meson8b-clkc" for Meson8 (S805) SoCs - - "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs -- #clock-cells: should be 1. -- #reset-cells: should be 1. -- clocks: list of clock phandles, one for each entry in clock-names -- clock-names: should contain the following: - * "xtal": the 24MHz system oscillator - * "ddr_pll": the DDR PLL clock - * "clk_32k": (if present) the 32kHz clock signal from GPIOAO_6 (CLK_32K_IN) - -Parent node should have the following properties : -- compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon" -- reg: base address and size of the HHI system control register space. - -Each clock is assigned an identifier and client nodes can use this identifier -to specify the clock which they consume. All available clocks are defined as -preprocessor macros in the dt-bindings/clock/meson8b-clkc.h header and can be -used in device tree sources. - -Similarly a preprocessor macro for each reset line is defined in -dt-bindings/reset/amlogic,meson8b-clkc-reset.h (which can be used from the -device tree sources). - - -Example: Clock controller node: - - clkc: clock-controller { - compatible = "amlogic,meson8b-clkc"; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - -Example: UART controller node that consumes the clock generated by the clock - controller: - - uart_AO: serial@c81004c0 { - compatible = "amlogic,meson-uart"; - reg = <0xc81004c0 0x14>; - interrupts = <0 90 1>; - clocks = <&clkc CLKID_CLK81>; - }; diff --git a/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml b/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml new file mode 100644 index 00000000000000..d3e0faf3c64dab --- /dev/null +++ b/Documentation/devicetree/bindings/clock/gated-fixed-clock.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/gated-fixed-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Gated Fixed clock + +maintainers: + - Heiko Stuebner + +properties: + compatible: + const: gated-fixed-clock + + "#clock-cells": + const: 0 + + clock-frequency: true + + clock-output-names: + maxItems: 1 + + enable-gpios: + description: + Contains a single GPIO specifier for the GPIO that enables and disables + the oscillator. + maxItems: 1 + + vdd-supply: + description: handle of the regulator that provides the supply voltage + +required: + - compatible + - "#clock-cells" + - clock-frequency + - vdd-supply + +additionalProperties: false + +examples: + - | + clock-1000000000 { + compatible = "gated-fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000000>; + vdd-supply = <®_vdd>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/imx93-clock.yaml b/Documentation/devicetree/bindings/clock/imx93-clock.yaml index ccb53c6b96c119..98c0800732ef5d 100644 --- a/Documentation/devicetree/bindings/clock/imx93-clock.yaml +++ b/Documentation/devicetree/bindings/clock/imx93-clock.yaml @@ -16,6 +16,7 @@ description: | properties: compatible: enum: + - fsl,imx91-ccm - fsl,imx93-ccm reg: diff --git a/Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml b/Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml new file mode 100644 index 00000000000000..4e78933232b6b9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/marvell,pxa1908.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell PXA1908 Clock Controllers + +maintainers: + - Duje Mihanović + +description: | + The PXA1908 clock subsystem generates and supplies clock to various + controllers within the PXA1908 SoC. The PXA1908 contains numerous clock + controller blocks, with the ones currently supported being APBC, APBCP, MPMU + and APMU roughly corresponding to internal buses. + + All these clock identifiers could be found in . + +properties: + compatible: + enum: + - marvell,pxa1908-apbc + - marvell,pxa1908-apbcp + - marvell,pxa1908-mpmu + - marvell,pxa1908-apmu + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false + +examples: + # APMU block: + - | + clock-controller@d4282800 { + compatible = "marvell,pxa1908-apmu"; + reg = <0xd4282800 0x400>; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml index db5f48e4dd157f..591a9e862c7d46 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml @@ -12,7 +12,8 @@ maintainers: description: The Mediatek apmixedsys controller provides PLLs to the system. - The clock values can be found in . + The clock values can be found in + and . properties: compatible: @@ -34,6 +35,7 @@ properties: - enum: - mediatek,mt2701-apmixedsys - mediatek,mt2712-apmixedsys + - mediatek,mt6735-apmixedsys - mediatek,mt6765-apmixedsys - mediatek,mt6779-apmixed - mediatek,mt6795-apmixedsys diff --git a/Documentation/devicetree/bindings/clock/mediatek,infracfg.yaml b/Documentation/devicetree/bindings/clock/mediatek,infracfg.yaml index 252c46d316ee55..d1d30700d9b0e4 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,infracfg.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,infracfg.yaml @@ -11,9 +11,10 @@ maintainers: description: The Mediatek infracfg controller provides various clocks and reset outputs - to the system. The clock values can be found in , - and reset values in and - . + to the system. The clock values can be found in + and , and reset values in + , and + . properties: compatible: @@ -22,6 +23,7 @@ properties: - enum: - mediatek,mt2701-infracfg - mediatek,mt2712-infracfg + - mediatek,mt6735-infracfg - mediatek,mt6765-infracfg - mediatek,mt6795-infracfg - mediatek,mt6779-infracfg_ao diff --git a/Documentation/devicetree/bindings/clock/mediatek,pericfg.yaml b/Documentation/devicetree/bindings/clock/mediatek,pericfg.yaml index 2f06baecfd2334..b98cf45efe2f63 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,pericfg.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,pericfg.yaml @@ -20,6 +20,7 @@ properties: - enum: - mediatek,mt2701-pericfg - mediatek,mt2712-pericfg + - mediatek,mt6735-pericfg - mediatek,mt6765-pericfg - mediatek,mt6795-pericfg - mediatek,mt7622-pericfg diff --git a/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml b/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml index 10483e26878fb4..a86a64893c675a 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml @@ -28,6 +28,10 @@ properties: - mediatek,mt2712-mfgcfg - mediatek,mt2712-vdecsys - mediatek,mt2712-vencsys + - mediatek,mt6735-imgsys + - mediatek,mt6735-mfgcfg + - mediatek,mt6735-vdecsys + - mediatek,mt6735-vencsys - mediatek,mt6765-camsys - mediatek,mt6765-imgsys - mediatek,mt6765-mipi0a diff --git a/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml b/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml index bdf3b55bd56fd4..c080fb0a161819 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml @@ -12,7 +12,8 @@ maintainers: description: The Mediatek topckgen controller provides various clocks to the system. - The clock values can be found in . + The clock values can be found in and + . properties: compatible: @@ -31,6 +32,7 @@ properties: - enum: - mediatek,mt2701-topckgen - mediatek,mt2712-topckgen + - mediatek,mt6735-topckgen - mediatek,mt6765-topckgen - mediatek,mt6779-topckgen - mediatek,mt6795-topckgen diff --git a/Documentation/devicetree/bindings/clock/microchip,lan966x-gck.yaml b/Documentation/devicetree/bindings/clock/microchip,lan966x-gck.yaml index df2bec18870651..16106e8b637f9a 100644 --- a/Documentation/devicetree/bindings/clock/microchip,lan966x-gck.yaml +++ b/Documentation/devicetree/bindings/clock/microchip,lan966x-gck.yaml @@ -16,7 +16,18 @@ description: | properties: compatible: - const: microchip,lan966x-gck + oneOf: + - enum: + - microchip,lan966x-gck + - microchip,lan9691-gck + - items: + - enum: + - microchip,lan9698-gck + - microchip,lan9696-gck + - microchip,lan9694-gck + - microchip,lan9693-gck + - microchip,lan9692-gck + - const: microchip,lan9691-gck reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml b/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml deleted file mode 100644 index 2d4f2cde1e5891..00000000000000 --- a/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/clock/mobileye,eyeq5-clk.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Mobileye EyeQ5 clock controller - -description: - The EyeQ5 clock controller handles 10 read-only PLLs derived from the main - crystal clock. It also exposes one divider clock, a child of one of the PLLs. - Its registers live in a shared region called OLB. - -maintainers: - - Grégory Clement - - Théo Lebrun - - Vladimir Kondratiev - -properties: - compatible: - const: mobileye,eyeq5-clk - - reg: - maxItems: 2 - - reg-names: - items: - - const: plls - - const: ospi - - "#clock-cells": - const: 1 - - clocks: - maxItems: 1 - description: - Input parent clock to all PLLs. Expected to be the main crystal. - - clock-names: - items: - - const: ref - -required: - - compatible - - reg - - reg-names - - "#clock-cells" - - clocks - - clock-names - -additionalProperties: false diff --git a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml index 5dc360b2ea4b76..d0291bfff23a27 100644 --- a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml +++ b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml @@ -13,9 +13,10 @@ properties: compatible: items: - enum: - - nxp,imx95-lvds-csr - - nxp,imx95-display-csr - nxp,imx95-camera-csr + - nxp,imx95-display-csr + - nxp,imx95-hsio-blk-ctl + - nxp,imx95-lvds-csr - nxp,imx95-netcmix-blk-ctrl - nxp,imx95-vpu-csr - const: syscon diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-sm8450.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-sm8450.yaml index d848361beeb32b..77273aee5d52d6 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc-sm8450.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-sm8450.yaml @@ -17,7 +17,9 @@ description: | properties: compatible: - const: qcom,gcc-sm8450 + enum: + - qcom,gcc-sm8450 + - qcom,sm8475-gcc clocks: items: diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq5332-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq5332-gcc.yaml index 9193de681de2e7..1230183fc0a996 100644 --- a/Documentation/devicetree/bindings/clock/qcom,ipq5332-gcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,ipq5332-gcc.yaml @@ -4,31 +4,35 @@ $id: http://devicetree.org/schemas/clock/qcom,ipq5332-gcc.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Qualcomm Global Clock & Reset Controller on IPQ5332 +title: Qualcomm Global Clock & Reset Controller on IPQ5332 and IPQ5424 maintainers: - Bjorn Andersson description: | Qualcomm global clock control module provides the clocks, resets and power - domains on IPQ5332. + domains on IPQ5332 and IPQ5424. - See also:: include/dt-bindings/clock/qcom,gcc-ipq5332.h - -allOf: - - $ref: qcom,gcc.yaml# + See also: + include/dt-bindings/clock/qcom,gcc-ipq5332.h + include/dt-bindings/clock/qcom,gcc-ipq5424.h properties: compatible: - const: qcom,ipq5332-gcc + enum: + - qcom,ipq5332-gcc + - qcom,ipq5424-gcc clocks: + minItems: 5 items: - description: Board XO clock source - description: Sleep clock source - description: PCIE 2lane PHY pipe clock source - description: PCIE 2lane x1 PHY pipe clock source (For second lane) - description: USB PCIE wrapper pipe clock source + - description: PCIE 2-lane PHY2 pipe clock source + - description: PCIE 2-lane PHY3 pipe clock source '#power-domain-cells': false '#interconnect-cells': @@ -38,6 +42,29 @@ required: - compatible - clocks +allOf: + - $ref: qcom,gcc.yaml# + - if: + properties: + compatible: + contains: + const: qcom,ipq5332-gcc + then: + properties: + clocks: + maxItems: 5 + + - if: + properties: + compatible: + contains: + const: qcom,ipq5424-gcc + then: + properties: + clocks: + minItems: 7 + maxItems: 7 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/clock/qcom,qcs8300-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,qcs8300-gcc.yaml new file mode 100644 index 00000000000000..081bc452081f96 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,qcs8300-gcc.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,qcs8300-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. Global Clock & Reset Controller on QCS8300 + +maintainers: + - Taniya Das + - Imran Shaik + +description: | + Qualcomm Technologies, Inc. Global clock control module provides the clocks, resets and + power domains on QCS8300 + + See also: include/dt-bindings/clock/qcom,qcs8300-gcc.h + +properties: + compatible: + const: qcom,qcs8300-gcc + + clocks: + items: + - description: Board XO source + - description: Sleep clock source + - description: PCIE 0 Pipe clock source + - description: PCIE 1 Pipe clock source + - description: PCIE Phy Auxiliary clock source + - description: First EMAC controller reference clock + - description: UFS Phy Rx symbol 0 clock source + - description: UFS Phy Rx symbol 1 clock source + - description: UFS Phy Tx symbol 0 clock source + - description: USB3 Phy wrapper pipe clock source + +required: + - compatible + - clocks + - '#power-domain-cells' + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,qcs8300-gcc"; + reg = <0x00100000 0xc7018>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&sleep_clk>, + <&pcie_0_pipe_clk>, + <&pcie_1_pipe_clk>, + <&pcie_phy_aux_clk>, + <&rxc0_ref_clk>, + <&ufs_phy_rx_symbol_0_clk>, + <&ufs_phy_rx_symbol_1_clk>, + <&ufs_phy_tx_symbol_0_clk>, + <&usb3_phy_wrapper_gcc_usb30_prim_pipe_clk>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index ca857942ed6c08..a561a306b947a6 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -19,6 +19,7 @@ properties: enum: - qcom,qdu1000-rpmh-clk - qcom,sa8775p-rpmh-clk + - qcom,sar2130p-rpmh-clk - qcom,sc7180-rpmh-clk - qcom,sc7280-rpmh-clk - qcom,sc8180x-rpmh-clk diff --git a/Documentation/devicetree/bindings/clock/qcom,sa8775p-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sa8775p-camcc.yaml new file mode 100644 index 00000000000000..36a60d8f5ae3a5 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sa8775p-camcc.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sa8775p-camcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Camera Clock & Reset Controller on SA8775P + +maintainers: + - Taniya Das + +description: | + Qualcomm camera clock control module provides the clocks, resets and power + domains on SA8775p. + + See also: include/dt-bindings/clock/qcom,sa8775p-camcc.h + +properties: + compatible: + enum: + - qcom,sa8775p-camcc + + clocks: + items: + - description: Camera AHB clock from GCC + - description: Board XO source + - description: Board active XO source + - description: Sleep clock source + + power-domains: + maxItems: 1 + description: MMCX power domain + +required: + - compatible + - clocks + - power-domains + - '#power-domain-cells' + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + clock-controller@ade0000 { + compatible = "qcom,sa8775p-camcc"; + reg = <0x0ade0000 0x20000>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>; + power-domains = <&rpmhpd SA8775P_MMCX>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,sa8775p-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sa8775p-dispcc.yaml new file mode 100644 index 00000000000000..ce61755e62d40b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sa8775p-dispcc.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/qcom,sa8775p-dispcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display Clock & Reset Controller on SA8775P + +maintainers: + - Taniya Das + +description: | + Qualcomm display clock control module provides the clocks, resets and power + domains on SA8775P. + + See also: include/dt-bindings/clock/qcom,sa8775p-dispcc.h + +properties: + compatible: + enum: + - qcom,sa8775p-dispcc0 + - qcom,sa8775p-dispcc1 + + clocks: + items: + - description: GCC AHB clock source + - description: Board XO source + - description: Board XO_AO source + - description: Sleep clock source + - description: Link clock from DP0 PHY + - description: VCO DIV clock from DP0 PHY + - description: Link clock from DP1 PHY + - description: VCO DIV clock from DP1 PHY + - description: Byte clock from DSI0 PHY + - description: Pixel clock from DSI0 PHY + - description: Byte clock from DSI1 PHY + - description: Pixel clock from DSI1 PHY + + power-domains: + maxItems: 1 + description: MMCX power domain + +required: + - compatible + - clocks + - power-domains + - '#power-domain-cells' + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + clock-controller@af00000 { + compatible = "qcom,sa8775p-dispcc0"; + reg = <0x0af00000 0x20000>; + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>, + <&dp_phy0 0>, + <&dp_phy0 1>, + <&dp_phy1 2>, + <&dp_phy1 3>, + <&dsi_phy0 0>, + <&dsi_phy0 1>, + <&dsi_phy1 2>, + <&dsi_phy1 3>; + power-domains = <&rpmhpd SA8775P_MMCX>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,sa8775p-videocc.yaml b/Documentation/devicetree/bindings/clock/qcom,sa8775p-videocc.yaml new file mode 100644 index 00000000000000..928131bff4c195 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sa8775p-videocc.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sa8775p-videocc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Video Clock & Reset Controller on SA8775P + +maintainers: + - Taniya Das + +description: | + Qualcomm video clock control module provides the clocks, resets and power + domains on SA8775P. + + See also: include/dt-bindings/clock/qcom,sa8775p-videocc.h + +properties: + compatible: + enum: + - qcom,sa8775p-videocc + + clocks: + items: + - description: Video AHB clock from GCC + - description: Board XO source + - description: Board active XO source + - description: Sleep Clock source + + power-domains: + maxItems: 1 + description: MMCX power domain + +required: + - compatible + - clocks + - power-domains + - '#power-domain-cells' + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + videocc: clock-controller@abf0000 { + compatible = "qcom,sa8775p-videocc"; + reg = <0x0abf0000 0x10000>; + clocks = <&gcc GCC_VIDEO_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>; + power-domains = <&rpmhpd SA8775P_MMCX>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,sar2130p-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sar2130p-gcc.yaml new file mode 100644 index 00000000000000..9a430bbd872aeb --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sar2130p-gcc.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sar2130p-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on sar2130p + +maintainers: + - Dmitry Baryshkov + +description: | + Qualcomm global clock control module provides the clocks, resets and + power domains on sar2130p. + + See also: include/dt-bindings/clock/qcom,sar2130p-gcc.h + +properties: + compatible: + const: qcom,sar2130p-gcc + + clocks: + items: + - description: XO reference clock + - description: Sleep clock + - description: PCIe 0 pipe clock + - description: PCIe 1 pipe clock + - description: Primary USB3 PHY wrapper pipe clock + + protected-clocks: + maxItems: 240 + + power-domains: + maxItems: 1 + +required: + - compatible + - clocks + - '#power-domain-cells' + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + gcc: clock-controller@100000 { + compatible = "qcom,sar2130p-gcc"; + reg = <0x100000 0x1f4200>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&sleep_clk>, + <&pcie_0_pipe_clk>, + <&pcie_1_pipe_clk>, + <&usb_0_ssphy>; + power-domains = <&rpmhpd RPMHPD_CX>; + + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml index 26afbbe655112f..0766f66c7dc4f6 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml @@ -26,6 +26,7 @@ properties: enum: - qcom,sc8280xp-camcc - qcom,sm8450-camcc + - qcom,sm8475-camcc - qcom,sm8550-camcc - qcom,sm8650-camcc - qcom,x1e80100-camcc diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml index 4794c53793a89f..e9123bbfd49109 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml @@ -19,6 +19,7 @@ properties: compatible: enum: - qcom,sm8450-dispcc + - qcom,sm8475-dispcc clocks: minItems: 3 diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml index 2d2c59aa8c6b09..5c65f5ecf0f387 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml @@ -14,6 +14,7 @@ description: | domains on Qualcomm SoCs. See also:: + include/dt-bindings/clock/qcom,sar2130p-gpucc.h include/dt-bindings/clock/qcom,sm4450-gpucc.h include/dt-bindings/clock/qcom,sm8450-gpucc.h include/dt-bindings/clock/qcom,sm8550-gpucc.h @@ -24,8 +25,10 @@ description: | properties: compatible: enum: + - qcom,sar2130p-gpucc - qcom,sm4450-gpucc - qcom,sm8450-gpucc + - qcom,sm8475-gpucc - qcom,sm8550-gpucc - qcom,sm8650-gpucc - qcom,x1e80100-gpucc diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml index 9829ba28fe0ed3..62714fa54db824 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml @@ -22,6 +22,7 @@ properties: compatible: enum: - qcom,sm8450-videocc + - qcom,sm8475-videocc - qcom,sm8550-videocc - qcom,sm8650-videocc diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml index c17035a180dbf3..c57d55a9293c21 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml @@ -22,6 +22,7 @@ description: | properties: compatible: enum: + - qcom,sar2130p-dispcc - qcom,sm8550-dispcc - qcom,sm8650-dispcc - qcom,x1e80100-dispcc diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml index 48fdd562d74394..3b546deb514af2 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml @@ -21,6 +21,7 @@ properties: compatible: items: - enum: + - qcom,sar2130p-tcsr - qcom,sm8550-tcsr - qcom,sm8650-tcsr - qcom,x1e80100-tcsr diff --git a/Documentation/devicetree/bindings/clock/renesas,r9a08g045-vbattb.yaml b/Documentation/devicetree/bindings/clock/renesas,r9a08g045-vbattb.yaml new file mode 100644 index 00000000000000..3707e4118949d9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,r9a08g045-vbattb.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/renesas,r9a08g045-vbattb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas Battery Backup Function (VBATTB) + +description: + Renesas VBATTB is an always on powered module (backed by battery) which + controls the RTC clock (VBATTCLK), tamper detection logic and a small + general usage memory (128B). + +maintainers: + - Claudiu Beznea + +properties: + compatible: + const: renesas,r9a08g045-vbattb + + reg: + maxItems: 1 + + interrupts: + items: + - description: tamper detector interrupt + + clocks: + items: + - description: VBATTB module clock + - description: RTC input clock (crystal or external clock device) + + clock-names: + items: + - const: bclk + - const: rtx + + '#clock-cells': + const: 1 + + power-domains: + maxItems: 1 + + resets: + items: + - description: VBATTB module reset + + quartz-load-femtofarads: + description: load capacitance of the on board crystal + enum: [ 4000, 7000, 9000, 12500 ] + default: 4000 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - '#clock-cells' + - power-domains + - resets + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + clock-controller@1005c000 { + compatible = "renesas,r9a08g045-vbattb"; + reg = <0x1005c000 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD R9A08G045_VBAT_BCLK>, <&vbattb_xtal>; + clock-names = "bclk", "rtx"; + assigned-clocks = <&vbattb VBATTB_MUX>; + assigned-clock-parents = <&vbattb VBATTB_XC>; + #clock-cells = <1>; + power-domains = <&cpg>; + resets = <&cpg R9A08G045_VBAT_BRESETN>; + quartz-load-femtofarads = <12500>; + }; diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt deleted file mode 100644 index 904ae682ea9021..00000000000000 --- a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.txt +++ /dev/null @@ -1,58 +0,0 @@ -* Rockchip RK3328 Clock and Reset Unit - -The RK3328 clock controller generates and supplies clock to various -controllers within the SoC and also implements a reset controller for SoC -peripherals. - -Required Properties: - -- compatible: should be "rockchip,rk3328-cru" -- reg: physical base address of the controller and length of memory mapped - region. -- #clock-cells: should be 1. -- #reset-cells: should be 1. - -Optional Properties: - -- rockchip,grf: phandle to the syscon managing the "general register files" - If missing pll rates are not changeable, due to the missing pll lock status. - -Each clock is assigned an identifier and client nodes can use this identifier -to specify the clock which they consume. All available clocks are defined as -preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be -used in device tree sources. Similar macros exist for the reset sources in -these files. - -External clocks: - -There are several clocks that are generated outside the SoC. It is expected -that they are defined using standard clock bindings with following -clock-output-names: - - "xin24m" - crystal input - required, - - "clkin_i2s" - external I2S clock - optional, - - "gmac_clkin" - external GMAC clock - optional - - "phy_50m_out" - output clock of the pll in the mac phy - - "hdmi_phy" - output clock of the hdmi phy pll - optional - -Example: Clock controller node: - - cru: clock-controller@ff440000 { - compatible = "rockchip,rk3328-cru"; - reg = <0x0 0xff440000 0x0 0x1000>; - rockchip,grf = <&grf>; - - #clock-cells = <1>; - #reset-cells = <1>; - }; - -Example: UART controller node that consumes the clock generated by the clock - controller: - - uart0: serial@ff120000 { - compatible = "snps,dw-apb-uart"; - reg = <0xff120000 0x100>; - interrupts = ; - reg-shift = <2>; - reg-io-width = <4>; - clocks = <&cru SCLK_UART0>; - }; diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.yaml b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.yaml new file mode 100644 index 00000000000000..f079c7a2559bbe --- /dev/null +++ b/Documentation/devicetree/bindings/clock/rockchip,rk3328-cru.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/rockchip,rk3328-cru.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip RK3328 Clock and Reset Unit (CRU) + +maintainers: + - Elaine Zhang + - Heiko Stuebner + +description: | + The RK3328 clock controller generates and supplies clocks to various + controllers within the SoC and also implements a reset controller for SoC + peripherals. + Each clock is assigned an identifier and client nodes can use this identifier + to specify the clock which they consume. All available clocks are defined as + preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be + used in device tree sources. Similar macros exist for the reset sources in + these files. + There are several clocks that are generated outside the SoC. It is expected + that they are defined using standard clock bindings with following + clock-output-names: + - "xin24m" - crystal input - required, + - "clkin_i2s" - external I2S clock - optional, + - "gmac_clkin" - external GMAC clock - optional + - "phy_50m_out" - output clock of the pll in the mac phy + - "hdmi_phy" - output clock of the hdmi phy pll - optional + +properties: + compatible: + enum: + - rockchip,rk3328-cru + + reg: + maxItems: 1 + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + + clocks: + maxItems: 1 + + clock-names: + const: xin24m + + rockchip,grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon managing the "general register files" (GRF), + if missing pll rates are not changeable, due to the missing pll + lock status. + +required: + - compatible + - reg + - "#clock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + cru: clock-controller@ff440000 { + compatible = "rockchip,rk3328-cru"; + reg = <0xff440000 0x1000>; + rockchip,grf = <&grf>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos8895-clock.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos8895-clock.yaml new file mode 100644 index 00000000000000..111de33ce00bdc --- /dev/null +++ b/Documentation/devicetree/bindings/clock/samsung,exynos8895-clock.yaml @@ -0,0 +1,239 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/samsung,exynos8895-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung Exynos8895 SoC clock controller + +maintainers: + - Ivaylo Ivanov + - Chanwoo Choi + - Krzysztof Kozlowski + +description: | + Exynos8895 clock controller is comprised of several CMU units, generating + clocks for different domains. Those CMU units are modeled as separate device + tree nodes, and might depend on each other. The root clock in that root tree + is an external clock: OSCCLK (26 MHz). This external clock must be defined + as a fixed-rate clock in dts. + + CMU_TOP is a top-level CMU, where all base clocks are prepared using PLLs and + dividers; all other clocks of function blocks (other CMUs) are usually + derived from CMU_TOP. + + Each clock is assigned an identifier and client nodes can use this identifier + to specify the clock which they consume. All clocks available for usage + in clock consumer nodes are defined as preprocessor macros in + 'include/dt-bindings/clock/samsung,exynos8895.h' header. + +properties: + compatible: + enum: + - samsung,exynos8895-cmu-fsys0 + - samsung,exynos8895-cmu-fsys1 + - samsung,exynos8895-cmu-peric0 + - samsung,exynos8895-cmu-peric1 + - samsung,exynos8895-cmu-peris + - samsung,exynos8895-cmu-top + + clocks: + minItems: 1 + maxItems: 16 + + clock-names: + minItems: 1 + maxItems: 16 + + "#clock-cells": + const: 1 + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + - reg + - "#clock-cells" + +allOf: + - if: + properties: + compatible: + contains: + const: samsung,exynos8895-cmu-fsys0 + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: CMU_FSYS0 BUS clock (from CMU_TOP) + - description: CMU_FSYS0 DPGTC clock (from CMU_TOP) + - description: CMU_FSYS0 MMC_EMBD clock (from CMU_TOP) + - description: CMU_FSYS0 UFS_EMBD clock (from CMU_TOP) + - description: CMU_FSYS0 USBDRD30 clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + - const: dpgtc + - const: mmc + - const: ufs + - const: usbdrd30 + + - if: + properties: + compatible: + contains: + const: samsung,exynos8895-cmu-fsys1 + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: CMU_FSYS1 BUS clock (from CMU_TOP) + - description: CMU_FSYS1 PCIE clock (from CMU_TOP) + - description: CMU_FSYS1 UFS_CARD clock (from CMU_TOP) + - description: CMU_FSYS1 MMC_CARD clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + - const: pcie + - const: ufs + - const: mmc + + - if: + properties: + compatible: + contains: + const: samsung,exynos8895-cmu-peric0 + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: CMU_PERIC0 BUS clock (from CMU_TOP) + - description: CMU_PERIC0 UART_DBG clock (from CMU_TOP) + - description: CMU_PERIC0 USI00 clock (from CMU_TOP) + - description: CMU_PERIC0 USI01 clock (from CMU_TOP) + - description: CMU_PERIC0 USI02 clock (from CMU_TOP) + - description: CMU_PERIC0 USI03 clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + - const: uart + - const: usi0 + - const: usi1 + - const: usi2 + - const: usi3 + + - if: + properties: + compatible: + contains: + const: samsung,exynos8895-cmu-peric1 + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: CMU_PERIC1 BUS clock (from CMU_TOP) + - description: CMU_PERIC1 SPEEDY2 clock (from CMU_TOP) + - description: CMU_PERIC1 SPI_CAM0 clock (from CMU_TOP) + - description: CMU_PERIC1 SPI_CAM1 clock (from CMU_TOP) + - description: CMU_PERIC1 UART_BT clock (from CMU_TOP) + - description: CMU_PERIC1 USI04 clock (from CMU_TOP) + - description: CMU_PERIC1 USI05 clock (from CMU_TOP) + - description: CMU_PERIC1 USI06 clock (from CMU_TOP) + - description: CMU_PERIC1 USI07 clock (from CMU_TOP) + - description: CMU_PERIC1 USI08 clock (from CMU_TOP) + - description: CMU_PERIC1 USI09 clock (from CMU_TOP) + - description: CMU_PERIC1 USI10 clock (from CMU_TOP) + - description: CMU_PERIC1 USI11 clock (from CMU_TOP) + - description: CMU_PERIC1 USI12 clock (from CMU_TOP) + - description: CMU_PERIC1 USI13 clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + - const: speedy + - const: cam0 + - const: cam1 + - const: uart + - const: usi4 + - const: usi5 + - const: usi6 + - const: usi7 + - const: usi8 + - const: usi9 + - const: usi10 + - const: usi11 + - const: usi12 + - const: usi13 + + - if: + properties: + compatible: + contains: + const: samsung,exynos8895-cmu-peris + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + - description: CMU_PERIS BUS clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + + - if: + properties: + compatible: + contains: + const: samsung,exynos8895-cmu-top + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + + clock-names: + items: + - const: oscclk + +additionalProperties: false + +examples: + - | + #include + + cmu_fsys1: clock-controller@11400000 { + compatible = "samsung,exynos8895-cmu-fsys1"; + reg = <0x11400000 0x8000>; + #clock-cells = <1>; + + clocks = <&oscclk>, + <&cmu_top CLK_DOUT_CMU_FSYS1_BUS>, + <&cmu_top CLK_DOUT_CMU_FSYS1_PCIE>, + <&cmu_top CLK_DOUT_CMU_FSYS1_UFS_CARD>, + <&cmu_top CLK_DOUT_CMU_FSYS1_MMC_CARD>; + clock-names = "oscclk", "bus", "pcie", "ufs", "mmc"; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/ti/composite.txt b/Documentation/devicetree/bindings/clock/ti/composite.txt index 6f7e1331b5466c..238e6f7d74f899 100644 --- a/Documentation/devicetree/bindings/clock/ti/composite.txt +++ b/Documentation/devicetree/bindings/clock/ti/composite.txt @@ -16,8 +16,8 @@ merged to this clock. The component clocks shall be of one of the "ti,*composite*-clock" types. [1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Documentation/devicetree/bindings/clock/ti/mux.txt -[3] Documentation/devicetree/bindings/clock/ti/divider.txt +[2] Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml +[3] Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml [4] Documentation/devicetree/bindings/clock/ti/gate.txt Required properties: diff --git a/Documentation/devicetree/bindings/clock/ti/divider.txt b/Documentation/devicetree/bindings/clock/ti/divider.txt deleted file mode 100644 index 4d7c76f0b35695..00000000000000 --- a/Documentation/devicetree/bindings/clock/ti/divider.txt +++ /dev/null @@ -1,115 +0,0 @@ -Binding for TI divider clock - -This binding uses the common clock binding[1]. It assumes a -register-mapped adjustable clock rate divider that does not gate and has -only one input clock or parent. By default the value programmed into -the register is one less than the actual divisor value. E.g: - -register value actual divisor value -0 1 -1 2 -2 3 - -This assumption may be modified by the following optional properties: - -ti,index-starts-at-one - valid divisor values start at 1, not the default -of 0. E.g: -register value actual divisor value -1 1 -2 2 -3 3 - -ti,index-power-of-two - valid divisor values are powers of two. E.g: -register value actual divisor value -0 1 -1 2 -2 4 - -Additionally an array of valid dividers may be supplied like so: - - ti,dividers = <4>, <8>, <0>, <16>; - -Which will map the resulting values to a divisor table by their index: -register value actual divisor value -0 4 -1 8 -2 -3 16 - -Any zero value in this array means the corresponding bit-value is invalid -and must not be used. - -The binding must also provide the register to control the divider and -unless the divider array is provided, min and max dividers. Optionally -the number of bits to shift that mask, if necessary. If the shift value -is missing it is the same as supplying a zero shift. - -This binding can also optionally provide support to the hardware autoidle -feature, see [2]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt - -Required properties: -- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock". -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : link to phandle of parent clock -- reg : offset for register controlling adjustable divider - -Optional properties: -- clock-output-names : from common clock binding. -- ti,dividers : array of integers defining divisors -- ti,bit-shift : number of bits to shift the divider value, defaults to 0 -- ti,min-div : min divisor for dividing the input clock rate, only - needed if the first divisor is offset from the default value (1) -- ti,max-div : max divisor for dividing the input clock rate, only needed - if ti,dividers is not defined. -- ti,index-starts-at-one : valid divisor programming starts at 1, not zero, - only valid if ti,dividers is not defined. -- ti,index-power-of-two : valid divisor programming must be a power of two, - only valid if ti,dividers is not defined. -- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock, - see [2] -- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0, - see [2] -- ti,set-rate-parent : clk_set_rate is propagated to parent -- ti,latch-bit : latch the divider value to HW, only needed if the register - access requires this. As an example dra76x DPLL_GMAC H14 divider implements - such behavior. - -Examples: -dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&dpll_usb_ck>; - ti,max-div = <127>; - reg = <0x190>; - ti,index-starts-at-one; -}; - -aess_fclk: aess_fclk@4a004528 { - #clock-cells = <0>; - compatible = "ti,divider-clock"; - clocks = <&abe_clk>; - ti,bit-shift = <24>; - reg = <0x528>; - ti,max-div = <2>; -}; - -dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck { - #clock-cells = <0>; - compatible = "ti,composite-divider-clock"; - clocks = <&dpll_core_x2_ck>; - ti,max-div = <31>; - reg = <0x0134>; - ti,index-starts-at-one; -}; - -ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 { - #clock-cells = <0>; - compatible = "ti,composite-divider-clock"; - clocks = <&corex2_fck>; - ti,bit-shift = <8>; - reg = <0x0a40>; - ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; -}; diff --git a/Documentation/devicetree/bindings/clock/ti/interface.txt b/Documentation/devicetree/bindings/clock/ti/interface.txt deleted file mode 100644 index 85fb1f2d2d286b..00000000000000 --- a/Documentation/devicetree/bindings/clock/ti/interface.txt +++ /dev/null @@ -1,55 +0,0 @@ -Binding for Texas Instruments interface clock. - -This binding uses the common clock binding[1]. This clock is -quite much similar to the basic gate-clock [2], however, -it supports a number of additional features, including -companion clock finding (match corresponding functional gate -clock) and hardware autoidle enable / disable. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml - -Required properties: -- compatible : shall be one of: - "ti,omap3-interface-clock" - basic OMAP3 interface clock - "ti,omap3-no-wait-interface-clock" - interface clock which has no hardware - capability for waiting clock to be ready - "ti,omap3-hsotgusb-interface-clock" - interface clock with USB specific HW - handling - "ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling - "ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling - "ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling - "ti,omap2430-interface-clock" - interface clock with OMAP2430 specific HW - handling -- #clock-cells : from common clock binding; shall be set to 0 -- clocks : link to phandle of parent clock -- reg : base address for the control register - -Optional properties: -- clock-output-names : from common clock binding. -- ti,bit-shift : bit shift for the bit enabling/disabling the clock (default 0) - -Examples: - aes1_ick: aes1_ick@48004a14 { - #clock-cells = <0>; - compatible = "ti,omap3-interface-clock"; - clocks = <&security_l4_ick2>; - reg = <0x48004a14 0x4>; - ti,bit-shift = <3>; - }; - - cam_ick: cam_ick@48004f10 { - #clock-cells = <0>; - compatible = "ti,omap3-no-wait-interface-clock"; - clocks = <&l4_ick>; - reg = <0x48004f10 0x4>; - ti,bit-shift = <0>; - }; - - ssi_ick_3430es2: ssi_ick_3430es2@48004a10 { - #clock-cells = <0>; - compatible = "ti,omap3-ssi-interface-clock"; - clocks = <&ssi_l4_ick>; - reg = <0x48004a10 0x4>; - ti,bit-shift = <0>; - }; diff --git a/Documentation/devicetree/bindings/clock/ti/mux.txt b/Documentation/devicetree/bindings/clock/ti/mux.txt deleted file mode 100644 index cd56d3c1c09f3b..00000000000000 --- a/Documentation/devicetree/bindings/clock/ti/mux.txt +++ /dev/null @@ -1,78 +0,0 @@ -Binding for TI mux clock. - -This binding uses the common clock binding[1]. It assumes a -register-mapped multiplexer with multiple input clock signals or -parents, one of which can be selected as output. This clock does not -gate or adjust the parent rate via a divider or multiplier. - -By default the "clocks" property lists the parents in the same order -as they are programmed into the register. E.g: - - clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>; - -results in programming the register as follows: - -register value selected parent clock -0 foo_clock -1 bar_clock -2 baz_clock - -Some clock controller IPs do not allow a value of zero to be programmed -into the register, instead indexing begins at 1. The optional property -"index-starts-at-one" modified the scheme as follows: - -register value selected clock parent -1 foo_clock -2 bar_clock -3 baz_clock - -The binding must provide the register to control the mux. Optionally -the number of bits to shift the control field in the register can be -supplied. If the shift value is missing it is the same as supplying -a zero shift. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: -- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock". -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : link phandles of parent clocks -- reg : register offset for register controlling adjustable mux - -Optional properties: -- clock-output-names : from common clock binding. -- ti,bit-shift : number of bits to shift the bit-mask, defaults to - 0 if not present -- ti,index-starts-at-one : valid input select programming starts at 1, not - zero -- ti,set-rate-parent : clk_set_rate is propagated to parent clock, - not supported by the composite-mux-clock subtype -- ti,latch-bit : latch the mux value to HW, only needed if the register - access requires this. As an example, dra7x DPLL_GMAC H14 muxing - implements such behavior. - -Examples: - -sys_clkin_ck: sys_clkin_ck@4a306110 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; - reg = <0x0110>; - ti,index-starts-at-one; -}; - -abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 { - #clock-cells = <0>; - compatible = "ti,mux-clock"; - clocks = <&sys_clkin_ck>, <&sys_32k_ck>; - ti,bit-shift = <24>; - reg = <0x0108>; -}; - -mcbsp5_mux_fck: mcbsp5_mux_fck { - #clock-cells = <0>; - compatible = "ti,composite-mux-clock"; - clocks = <&core_96m_fck>, <&mcbsp_clks>; - ti,bit-shift = <4>; - reg = <0x02d8>; -}; diff --git a/Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml b/Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml new file mode 100644 index 00000000000000..3fbe236eb565a8 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml @@ -0,0 +1,193 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti/ti,divider-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments divider clock + +maintainers: + - Tero Kristo + +description: | + This clock It assumes a register-mapped adjustable clock rate divider + that does not gate and has only one input clock or parent. By default the + value programmed into the register is one less than the actual divisor value. + E.g: + + register value actual divisor value + 0 1 + 1 2 + 2 3 + + This assumption may be modified by the following optional properties: + + ti,index-starts-at-one - valid divisor values start at 1, not the default + of 0. E.g: + register value actual divisor value + 1 1 + 2 2 + 3 3 + + ti,index-power-of-two - valid divisor values are powers of two. E.g: + register value actual divisor value + 0 1 + 1 2 + 2 4 + + Additionally an array of valid dividers may be supplied like so: + + ti,dividers = <4>, <8>, <0>, <16>; + + Which will map the resulting values to a divisor table by their index: + register value actual divisor value + 0 4 + 1 8 + 2 + 3 16 + + Any zero value in this array means the corresponding bit-value is invalid + and must not be used. + + The binding must also provide the register to control the divider and + unless the divider array is provided, min and max dividers. Optionally + the number of bits to shift that mask, if necessary. If the shift value + is missing it is the same as supplying a zero shift. + + This binding can also optionally provide support to the hardware autoidle + feature, see [1]. + + [1] Documentation/devicetree/bindings/clock/ti/autoidle.txt + +properties: + compatible: + enum: + - ti,divider-clock + - ti,composite-divider-clock + + "#clock-cells": + const: 0 + + clocks: + maxItems: 1 + + clock-output-names: + maxItems: 1 + + reg: + maxItems: 1 + + ti,dividers: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + array of integers defining divisors + + ti,bit-shift: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + number of bits to shift the divider value + maximum: 31 + default: 0 + + ti,min-div: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + min divisor for dividing the input clock rate, only + needed if the first divisor is offset from the default value (1) + minimum: 1 + default: 1 + + + ti,max-div: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + max divisor for dividing the input clock rate, only needed + if ti,dividers is not defined. + + ti,index-starts-at-one: + type: boolean + description: + valid divisor programming starts at 1, not zero, + only valid if ti,dividers is not defined + + ti,index-power-of-two: + type: boolean + description: + valid divisor programming must be a power of two, + only valid if ti,dividers is not defined. + + ti,autoidle-shift: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + bit shift of the autoidle enable bit for the clock, + see [1]. + maximum: 31 + default: 0 + + ti,invert-autoidle-bit: + type: boolean + description: + autoidle is enabled by setting the bit to 0, + see [1] + + ti,set-rate-parent: + type: boolean + description: + clk_set_rate is propagated to parent | + + ti,latch-bit: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + latch the divider value to HW, only needed if the register + compatible access requires this. As an example dra76x DPLL_GMAC + H14 divider implements such behavior. + +dependentSchemas: + ti,dividers: + properties: + ti,min-div: false + ti,max-div: false + ti,index-power-of-two: false + ti,index-starts-at-one: false + +required: + - compatible + - "#clock-cells" + - clocks + - reg + +additionalProperties: false + +examples: + - | + bus { + #address-cells = <1>; + #size-cells = <0>; + + clock-controller@190 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + reg = <0x190>; + ti,index-starts-at-one; + }; + + clock-controller@528 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + ti,bit-shift = <24>; + reg = <0x528>; + ti,max-div = <2>; + }; + + clock-controller@a40 { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <8>; + reg = <0x0a40>; + ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; + }; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/ti,interface-clock.yaml b/Documentation/devicetree/bindings/clock/ti/ti,interface-clock.yaml new file mode 100644 index 00000000000000..1eaf95d88e0b9d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/ti,interface-clock.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti/ti,interface-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments interface clock. + +maintainers: + - Tero Kristo + +description: | + This clock is quite much similar to the basic gate-clock[1], however, + it supports a number of additional features, including + companion clock finding (match corresponding functional gate + clock) and hardware autoidle enable / disable. + + [1] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml + +properties: + compatible: + enum: + - ti,omap3-interface-clock # basic OMAP3 interface clock + - ti,omap3-no-wait-interface-clock # interface clock which has no hardware + # capability for waiting clock to be ready + - ti,omap3-hsotgusb-interface-clock # interface clock with USB specific HW handling + - ti,omap3-dss-interface-clock # interface clock with DSS specific HW handling + - ti,omap3-ssi-interface-clock # interface clock with SSI specific HW handling + - ti,am35xx-interface-clock # interface clock with AM35xx specific HW handling + - ti,omap2430-interface-clock # interface clock with OMAP2430 specific HW handling + + "#clock-cells": + const: 0 + + clocks: + maxItems: 1 + + clock-output-names: + maxItems: 1 + + reg: + maxItems: 1 + + ti,bit-shift: + description: + bit shift for the bit enabling/disabling the clock + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + maximum: 31 + +required: + - compatible + - clocks + - '#clock-cells' + - reg + +additionalProperties: false + +examples: + - | + bus { + #address-cells = <1>; + #size-cells = <0>; + + aes1_ick: clock-controller@3 { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <3>; + }; + }; diff --git a/Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml b/Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml new file mode 100644 index 00000000000000..485b6aae85d449 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti/ti,mux-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments mux clock + +maintainers: + - Tero Kristo + +description: | + This clock assumes a register-mapped multiplexer with multiple inpt clock + signals or parents, one of which can be selected as output. This clock does + not gate or adjust the parent rate via a divider or multiplier. + + By default the "clocks" property lists the parents in the same order + as they are programmed into the register. E.g: + + clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>; + + Results in programming the register as follows: + + register value selected parent clock + 0 foo_clock + 1 bar_clock + 2 baz_clock + + Some clock controller IPs do not allow a value of zero to be programmed + into the register, instead indexing begins at 1. The optional property + "index-starts-at-one" modified the scheme as follows: + + register value selected clock parent + 1 foo_clock + 2 bar_clock + 3 baz_clock + + The binding must provide the register to control the mux. Optionally + the number of bits to shift the control field in the register can be + supplied. If the shift value is missing it is the same as supplying + a zero shift. + +properties: + compatible: + enum: + - ti,mux-clock + - ti,composite-mux-clock + + "#clock-cells": + const: 0 + + clocks: true + + clock-output-names: + maxItems: 1 + + reg: + maxItems: 1 + + ti,bit-shift: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Number of bits to shift the bit-mask + maximum: 31 + default: 0 + + ti,index-starts-at-one: + type: boolean + description: + Valid input select programming starts at 1, not zero + + ti,set-rate-parent: + type: boolean + description: + clk_set_rate is propagated to parent clock, + not supported by the composite-mux-clock subtype. + + ti,latch-bit: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Latch the mux value to HW, only needed if the register + access requires this. As an example, dra7x DPLL_GMAC H14 muxing + implements such behavior. + maximum: 31 + +if: + properties: + compatible: + contains: + const: ti,composite-mux-clock +then: + properties: + ti,set-rate-parent: false + +required: + - compatible + - "#clock-cells" + - clocks + - reg + +additionalProperties: false + +examples: + - | + bus { + #address-cells = <1>; + #size-cells = <0>; + + clock-controller@110 { + compatible = "ti,mux-clock"; + reg = <0x0110>; + #clock-cells = <0>; + clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>; + ti,index-starts-at-one; + ti,set-rate-parent; + }; + + clock-controller@120 { + compatible = "ti,composite-mux-clock"; + reg = <0x0120>; + #clock-cells = <0>; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <4>; + }; + }; diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml index 9d5324dc1027a3..b44a76a958f4ee 100644 --- a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml +++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml @@ -39,6 +39,11 @@ properties: - const: clk_in1 - const: s_axi_aclk + xlnx,static-config: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicate whether the core has been configured without support for dynamic + runtime reconfguration of the clocking primitive MMCM/PLL. xlnx,speed-grade: $ref: /schemas/types.yaml#/definitions/uint32 @@ -70,6 +75,7 @@ examples: compatible = "xlnx,clocking-wizard"; reg = <0xb0000000 0x10000>; #clock-cells = <1>; + xlnx,static-config; xlnx,speed-grade = <1>; xlnx,nr-outputs = <6>; clock-names = "clk_in1", "s_axi_aclk"; diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml index fb216ce68bb357..67700440e23b5b 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -253,6 +253,46 @@ properties: additionalProperties: false + sink-wait-cap-time-ms: + description: Represents the max time in ms that USB Type-C port (in sink + role) should wait for the port partner (source role) to send source caps. + SinkWaitCap timer starts when port in sink role attaches to the source. + This timer will stop when sink receives PD source cap advertisement before + timeout in which case it'll move to capability negotiation stage. A + timeout leads to a hard reset message by the port. + minimum: 310 + maximum: 620 + default: 310 + + ps-source-off-time-ms: + description: Represents the max time in ms that a DRP in source role should + take to turn off power after the PsSourceOff timer starts. PsSourceOff + timer starts when a sink's PHY layer receives EOP of the GoodCRC message + (corresponding to an Accept message sent in response to a PR_Swap or a + FR_Swap request). This timer stops when last bit of GoodCRC EOP + corresponding to the received PS_RDY message is transmitted by the PHY + layer. A timeout shall lead to error recovery in the type-c port. + minimum: 750 + maximum: 920 + default: 920 + + cc-debounce-time-ms: + description: Represents the max time in ms that a port shall wait to + determine if it's attached to a partner. + minimum: 100 + maximum: 200 + default: 200 + + sink-bc12-completion-time-ms: + description: Represents the max time in ms that a port in sink role takes + to complete Battery Charger (BC1.2) Detection. BC1.2 detection is a + hardware mechanism, which in some TCPC implementations, can run in + parallel once the Type-C connection state machine reaches the "potential + connect as sink" state. In TCPCs where this causes delays to respond to + the incoming PD messages, sink-bc12-completion-time-ms is used to delay + PD negotiation till BC1.2 detection completes. + default: 0 + dependencies: sink-vdos-v1: [ sink-vdos ] sink-vdos: [ sink-vdos-v1 ] @@ -380,7 +420,7 @@ examples: }; # USB-C connector attached to a typec port controller(ptn5110), which has - # power delivery support and enables drp. + # power delivery support, explicitly defines time properties and enables drp. - | #include typec: ptn5110 { @@ -393,6 +433,10 @@ examples: sink-pdos = ; op-sink-microwatt = <10000000>; + sink-wait-cap-time-ms = <465>; + ps-source-off-time-ms = <835>; + cc-debounce-time-ms = <101>; + sink-bc12-completion-time-ms = <500>; }; }; diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml index 1e9797f964108f..e937eb7355e7fb 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-qcom-hw.yaml @@ -23,6 +23,7 @@ properties: - enum: - qcom,qcm2290-cpufreq-hw - qcom,sc7180-cpufreq-hw + - qcom,sc8180x-cpufreq-hw - qcom,sdm670-cpufreq-hw - qcom,sdm845-cpufreq-hw - qcom,sm6115-cpufreq-hw @@ -34,7 +35,9 @@ properties: items: - enum: - qcom,qdu1000-cpufreq-epss + - qcom,sa8255p-cpufreq-epss - qcom,sa8775p-cpufreq-epss + - qcom,sar2130p-cpufreq-epss - qcom,sc7280-cpufreq-epss - qcom,sc8280xp-cpufreq-epss - qcom,sdx75-cpufreq-epss @@ -107,6 +110,7 @@ allOf: contains: enum: - qcom,qcm2290-cpufreq-hw + - qcom,sar2130p-cpufreq-epss then: properties: reg: @@ -130,7 +134,9 @@ allOf: contains: enum: - qcom,qdu1000-cpufreq-epss + - qcom,sa8255p-cpufreq-epss - qcom,sc7180-cpufreq-hw + - qcom,sc8180x-cpufreq-hw - qcom,sc8280xp-cpufreq-epss - qcom,sdm670-cpufreq-hw - qcom,sdm845-cpufreq-hw diff --git a/Documentation/devicetree/bindings/cpufreq/qemu,virtual-cpufreq.yaml b/Documentation/devicetree/bindings/cpufreq/qemu,virtual-cpufreq.yaml new file mode 100644 index 00000000000000..018d98bcdc8267 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/qemu,virtual-cpufreq.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/cpufreq/qemu,virtual-cpufreq.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Virtual CPUFreq + +maintainers: + - David Dai + - Saravana Kannan + +description: + Virtual CPUFreq is a virtualized driver in guest kernels that sends performance + selection of its vCPUs as a hint to the host through MMIO regions. Each vCPU + is associated with a performance domain which can be shared with other vCPUs. + Each performance domain has its own set of registers for performance controls. + +properties: + compatible: + const: qemu,virtual-cpufreq + + reg: + maxItems: 1 + description: + Address and size of region containing performance controls for each of the + performance domains. Regions for each performance domain is placed + contiguously and contain registers for controlling DVFS(Dynamic Frequency + and Voltage) characteristics. The size of the region is proportional to + total number of performance domains. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <1>; + #size-cells = <1>; + + cpufreq@1040000 { + compatible = "qemu,virtual-cpufreq"; + reg = <0x1040000 0x2000>; + }; + }; diff --git a/Documentation/devicetree/bindings/crypto/fsl,sec-v4.0.yaml b/Documentation/devicetree/bindings/crypto/fsl,sec-v4.0.yaml index 9c8c9991f29ad6..f0c4a7c83568a4 100644 --- a/Documentation/devicetree/bindings/crypto/fsl,sec-v4.0.yaml +++ b/Documentation/devicetree/bindings/crypto/fsl,sec-v4.0.yaml @@ -114,8 +114,9 @@ patternProperties: table that specifies the PPID to LIODN mapping. Needed if the PAMU is used. Value is a 12 bit value where value is a LIODN ID for this JR. This property is normally set by boot firmware. - $ref: /schemas/types.yaml#/definitions/uint32 - maximum: 0xfff + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + - maximum: 0xfff '^rtic@[0-9a-f]+$': type: object @@ -186,8 +187,9 @@ patternProperties: Needed if the PAMU is used. Value is a 12 bit value where value is a LIODN ID for this JR. This property is normally set by boot firmware. - $ref: /schemas/types.yaml#/definitions/uint32 - maximum: 0xfff + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + - maximum: 0xfff fsl,rtic-region: description: diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml index e285e382d4ecce..c09be97434ac01 100644 --- a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml @@ -44,6 +44,7 @@ properties: - items: - enum: + - qcom,sa8775p-qce - qcom,sc7280-qce - qcom,sm6350-qce - qcom,sm8250-qce diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml new file mode 100644 index 00000000000000..0a10e10d80ffda --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml @@ -0,0 +1,250 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/ite,it6263.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ITE IT6263 LVDS to HDMI converter + +maintainers: + - Liu Ying + +description: | + The IT6263 is a high-performance single-chip De-SSC(De-Spread Spectrum) LVDS + to HDMI converter. Combined with LVDS receiver and HDMI 1.4a transmitter, + the IT6263 supports LVDS input and HDMI 1.4 output by conversion function. + The built-in LVDS receiver can support single-link and dual-link LVDS inputs, + and the built-in HDMI transmitter is fully compliant with HDMI 1.4a/3D, HDCP + 1.2 and backward compatible with DVI 1.0 specification. + + The IT6263 also encodes and transmits up to 8 channels of I2S digital audio, + with sampling rate up to 192KHz and sample size up to 24 bits. In addition, + an S/PDIF input port takes in compressed audio of up to 192KHz frame rate. + + The newly supported High-Bit Rate(HBR) audio by HDMI specifications v1.3 is + provided by the IT6263 in two interfaces: the four I2S input ports or the + S/PDIF input port. With both interfaces the highest possible HBR frame rate + is supported at up to 768KHz. + +allOf: + - $ref: /schemas/display/lvds-dual-ports.yaml# + +properties: + compatible: + const: ite,it6263 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: audio master clock + + clock-names: + const: mclk + + data-mapping: + enum: + - jeida-18 + - jeida-24 + - jeida-30 + - vesa-24 + - vesa-30 + + reset-gpios: + maxItems: 1 + + ivdd-supply: + description: 1.8V digital logic power + + ovdd-supply: + description: 3.3V I/O pin power + + txavcc18-supply: + description: 1.8V HDMI analog frontend power + + txavcc33-supply: + description: 3.3V HDMI analog frontend power + + pvcc1-supply: + description: 1.8V HDMI frontend core PLL power + + pvcc2-supply: + description: 1.8V HDMI frontend filter PLL power + + avcc-supply: + description: 3.3V LVDS frontend power + + anvdd-supply: + description: 1.8V LVDS frontend analog power + + apvdd-supply: + description: 1.8V LVDS frontend PLL power + + "#sound-dai-cells": + const: 0 + + ite,i2s-audio-fifo-sources: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 4 + items: + enum: [0, 1, 2, 3] + description: + Each array element indicates the pin number of an I2S serial data input + line which is connected to an audio FIFO, from audio FIFO0 to FIFO3. + + ite,rl-channel-swap-audio-sources: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 4 + uniqueItems: true + items: + enum: [0, 1, 2, 3] + description: + Each array element indicates an audio source whose right channel and left + channel are swapped by this converter. For I2S, the element is the pin + number of an I2S serial data input line. For S/PDIF, the element is always + 0. + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: true + + port@1: + oneOf: + - required: [dual-lvds-odd-pixels] + - required: [dual-lvds-even-pixels] + + port@2: + $ref: /schemas/graph.yaml#/properties/port + description: video port for the HDMI output + + port@3: + $ref: /schemas/graph.yaml#/properties/port + description: sound input port + + required: + - port@0 + - port@2 + +required: + - compatible + - reg + - data-mapping + - ivdd-supply + - ovdd-supply + - txavcc18-supply + - txavcc33-supply + - pvcc1-supply + - pvcc2-supply + - avcc-supply + - anvdd-supply + - apvdd-supply + +unevaluatedProperties: false + +examples: + - | + /* single-link LVDS input */ + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hdmi@4c { + compatible = "ite,it6263"; + reg = <0x4c>; + data-mapping = "jeida-24"; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + ivdd-supply = <®_buck5>; + ovdd-supply = <®_vext_3v3>; + txavcc18-supply = <®_buck5>; + txavcc33-supply = <®_vext_3v3>; + pvcc1-supply = <®_buck5>; + pvcc2-supply = <®_buck5>; + avcc-supply = <®_vext_3v3>; + anvdd-supply = <®_buck5>; + apvdd-supply = <®_buck5>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + it6263_lvds_link1: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + + port@2 { + reg = <2>; + + it6263_out: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; + }; + }; + }; + + - | + /* dual-link LVDS input */ + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hdmi@4c { + compatible = "ite,it6263"; + reg = <0x4c>; + data-mapping = "jeida-24"; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + ivdd-supply = <®_buck5>; + ovdd-supply = <®_vext_3v3>; + txavcc18-supply = <®_buck5>; + txavcc33-supply = <®_vext_3v3>; + pvcc1-supply = <®_buck5>; + pvcc2-supply = <®_buck5>; + avcc-supply = <®_vext_3v3>; + anvdd-supply = <®_buck5>; + apvdd-supply = <®_buck5>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + + it6263_lvds_link1_dual: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + + port@1 { + reg = <1>; + dual-lvds-even-pixels; + + it6263_lvds_link2_dual: endpoint { + remote-endpoint = <&ldb_lvds_ch1>; + }; + }; + + port@2 { + reg = <2>; + + it6263_out_dual: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml b/Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml index 5a69547ad3d796..1509c4535e53c6 100644 --- a/Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml +++ b/Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml @@ -81,9 +81,22 @@ properties: properties: port@0: - $ref: /schemas/graph.yaml#/properties/port + unevaluatedProperties: false + $ref: /schemas/graph.yaml#/$defs/port-base description: Parallel RGB input port + properties: + endpoint: + $ref: /schemas/graph.yaml#/$defs/endpoint-base + unevaluatedProperties: false + + properties: + bus-width: + description: + Endpoint bus width. + enum: [ 16, 18, 24 ] + default: 24 + port@1: $ref: /schemas/graph.yaml#/properties/port description: HDMI output port diff --git a/Documentation/devicetree/bindings/display/bridge/ti,tdp158.yaml b/Documentation/devicetree/bindings/display/bridge/ti,tdp158.yaml new file mode 100644 index 00000000000000..1c522f72c4bae3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/ti,tdp158.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/ti,tdp158.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI TDP158 HDMI to TMDS Redriver + +maintainers: + - Arnaud Vrac + - Pierre-Hugues Husson + +properties: + compatible: + const: ti,tdp158 + +# The reg property is required if and only if the device is connected +# to an I2C bus. In pin strap mode, reg must not be specified. + reg: + description: I2C address of the device + +# Pin 36 = Operation Enable / Reset Pin +# OE = L: Power Down Mode +# OE = H: Normal Operation +# Internal weak pullup - device resets on H to L transitions + enable-gpios: + description: GPIO controlling bridge enable + + vcc-supply: + description: Power supply 3.3V + + vdd-supply: + description: Power supply 1.1V + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Bridge input + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Bridge output + + required: + - port@0 + - port@1 + +required: + - compatible + - vcc-supply + - vdd-supply + - ports + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358768.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358768.yaml index 779d8c57f854db..bb5d3b5438003c 100644 --- a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358768.yaml +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358768.yaml @@ -60,6 +60,10 @@ properties: data-lines: $ref: /schemas/types.yaml#/definitions/uint32 enum: [ 16, 18, 24 ] + deprecated: true + + bus-width: + enum: [ 16, 18, 24 ] port@1: $ref: /schemas/graph.yaml#/properties/port diff --git a/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt b/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt index 3c35338a2867cf..269b1ae2fca998 100644 --- a/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt +++ b/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt @@ -119,7 +119,6 @@ Optional properties: - interface-pix-fmt: How this display is connected to the display interface. Currently supported types: "rgb24", "rgb565", "bgr666" and "lvds666". -- edid: verbatim EDID data block describing attached display. - ddc: phandle describing the i2c bus handling the display data channel - port@[0-1]: Port nodes with endpoint definitions as defined in @@ -131,7 +130,6 @@ example: disp0 { compatible = "fsl,imx-parallel-display"; - edid = [edid-data]; interface-pix-fmt = "rgb24"; port@0 { diff --git a/Documentation/devicetree/bindings/display/imx/ldb.txt b/Documentation/devicetree/bindings/display/imx/ldb.txt index 8e6e7d797943ff..03653a291b549b 100644 --- a/Documentation/devicetree/bindings/display/imx/ldb.txt +++ b/Documentation/devicetree/bindings/display/imx/ldb.txt @@ -62,7 +62,6 @@ Required properties: display-timings are used instead. Optional properties (required if display-timings are used): - - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing - display-timings : A node that describes the display timings as defined in Documentation/devicetree/bindings/display/panel/display-timing.txt. - fsl,data-mapping : should be "spwg" or "jeida" diff --git a/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml b/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml index d68982fe2e9be1..ab842594feb9cd 100644 --- a/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml +++ b/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml @@ -26,12 +26,17 @@ description: | Device compatible with those specifications have been marketed under the FPD-Link and FlatLink brands. + This bindings also supports 30-bit data mapping compatible with JEIDA and + VESA. + properties: data-mapping: enum: - jeida-18 - jeida-24 + - jeida-30 - vesa-24 + - vesa-30 description: | The color signals mapping order. @@ -60,6 +65,19 @@ properties: DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B7__><__B6__><__B5__><__B4__>< DATA3 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__>< + - "jeida-30" - 30-bit data mapping compatible with JEIDA and VESA. Data + are transferred as follows on 5 LVDS lanes. + + Slot 0 1 2 3 4 5 6 + ________________ _________________ + Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ + DATA0 ><__G4__><__R9__><__R8__><__R7__><__R6__><__R5__><__R4__>< + DATA1 ><__B5__><__B4__><__G9__><__G8__><__G7__><__G6__><__G5__>< + DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B9__><__B8__><__B7__><__B6__>< + DATA3 ><_CTL3_><__B3__><__B2__><__G3__><__G2__><__R3__><__R2__>< + DATA4 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__>< + - "vesa-24" - 24-bit data mapping compatible with the [VESA] specification. Data are transferred as follows on 4 LVDS lanes. @@ -72,6 +90,19 @@ properties: DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__>< + - "vesa-30" - 30-bit data mapping compatible with VESA. Data are + transferred as follows on 5 LVDS lanes. + + Slot 0 1 2 3 4 5 6 + ________________ _________________ + Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ + DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__>< + DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__>< + DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< + DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__>< + DATA4 ><_CTL3_><__B9__><__B8__><__G9__><__G8__><__R9__><__R8__>< + Control signals are mapped as follows. CTL0: HSync diff --git a/Documentation/devicetree/bindings/display/lvds-dual-ports.yaml b/Documentation/devicetree/bindings/display/lvds-dual-ports.yaml new file mode 100644 index 00000000000000..785701fe159069 --- /dev/null +++ b/Documentation/devicetree/bindings/display/lvds-dual-ports.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/lvds-dual-ports.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dual-link LVDS Display Common Properties + +maintainers: + - Liu Ying + +description: | + Common properties for LVDS displays with dual LVDS links. Extend LVDS display + common properties defined in lvds.yaml. + + Dual-link LVDS displays receive odd pixels and even pixels separately from + the dual LVDS links. One link receives odd pixels and the other receives + even pixels. Some of those displays may also use only one LVDS link to + receive all pixels, being odd and even agnostic. + +allOf: + - $ref: lvds.yaml# + +properties: + ports: + $ref: /schemas/graph.yaml#/properties/ports + + patternProperties: + '^port@[01]$': + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: | + port@0 represents the first LVDS input link. + port@1 represents the second LVDS input link. + + properties: + dual-lvds-odd-pixels: + type: boolean + description: LVDS input link for odd pixels + + dual-lvds-even-pixels: + type: boolean + description: LVDS input link for even pixels + + oneOf: + - required: [dual-lvds-odd-pixels] + - required: [dual-lvds-even-pixels] + - properties: + dual-lvds-odd-pixels: false + dual-lvds-even-pixels: false + + anyOf: + - required: + - port@0 + - required: + - port@1 + +required: + - ports + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,aal.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,aal.yaml index cf24434854ff08..47ddba5c41af93 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,aal.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,aal.yaml @@ -62,6 +62,27 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: AAL input port + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + AAL output to the next component's input, for example could be one + of many gamma, overdrive or other blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg @@ -89,5 +110,24 @@ examples: power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; clocks = <&mmsys CLK_MM_DISP_AAL>; mediatek,gce-client-reg = <&gce SUBSYS_1401XXXX 0x5000 0x1000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + aal0_in: endpoint { + remote-endpoint = <&ccorr0_out>; + }; + }; + + port@1 { + reg = <1>; + aal0_out: endpoint { + remote-endpoint = <&gamma0_in>; + }; + }; + }; }; }; diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ccorr.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ccorr.yaml index 9f8366763831c0..fca8e7bb0cbc05 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ccorr.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ccorr.yaml @@ -57,6 +57,27 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: CCORR input port + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + CCORR output to the input of the next desired component in the + display pipeline, usually only one of the available AAL blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,color.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,color.yaml index 7df786bbad2043..6160439ce4d7e4 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,color.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,color.yaml @@ -65,6 +65,28 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: COLOR input port + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + COLOR output to the input of the next desired component in the + display pipeline, for example one of the available CCORR or AAL + blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dither.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dither.yaml index 6fceb1f95d2ab2..abaf27916d13dd 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dither.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dither.yaml @@ -56,6 +56,28 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: DITHER input, usually from a POSTMASK or GAMMA block. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + DITHER output to the input of the next desired component in the + display pipeline, for example one of the available DSC compressors, + DP_INTF, DSI, LVDS or others. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml index 497c0eb4ed0b5e..0f1e556dc8ef3d 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.yaml @@ -81,13 +81,34 @@ properties: Output port node. This port should be connected to the input port of an attached HDMI, LVDS or DisplayPort encoder chip. + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: DPI input port + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: DPI output to an HDMI, LVDS or DisplayPort encoder input + + required: + - port@0 + - port@1 + required: - compatible - reg - interrupts - clocks - clock-names - - port + +oneOf: + - required: + - port + - required: + - ports additionalProperties: false @@ -96,7 +117,7 @@ examples: #include #include - dpi0: dpi@1401d000 { + dpi: dpi@1401d000 { compatible = "mediatek,mt8173-dpi"; reg = <0x1401d000 0x1000>; interrupts = ; diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsc.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsc.yaml index 2cbdd9ee449d2d..846de6c17d9313 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsc.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsc.yaml @@ -49,6 +49,30 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + Display Stream Compression input, usually from one of the DITHER + or MERGE blocks. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + Display Stream Compression output to the input of the next desired + component in the display pipeline, for example to MERGE, DP_INTF, + DPI or DSI. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml index a7aa8fcb0dd12b..27ffbccc2a082e 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml @@ -77,6 +77,26 @@ properties: Output port node. This port should be connected to the input port of an attached DSI panel or DSI-to-eDP encoder chip. + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input ports can have multiple endpoints, each of those connects + to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: DSI input port, usually from DITHER, DSC or MERGE + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + DSI output to an attached DSI panel, or a DSI-to-X encoder chip + + required: + - port@0 + - port@1 + required: - compatible - reg @@ -86,7 +106,12 @@ required: - clock-names - phys - phy-names - - port + +oneOf: + - required: + - port + - required: + - ports unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml index 677882348eded7..98db47894eebf0 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml @@ -110,6 +110,28 @@ properties: include/dt-bindings/gce/-gce.h, mapping to the register of display function block. + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: ETHDR input, usually from one of the MERGE blocks. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + ETHDR output to the input of the next desired component in the + display pipeline, for example one of the available MERGE blocks, + or others. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,gamma.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,gamma.yaml index 6823d3ce5049a7..48542dc7e784d7 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,gamma.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,gamma.yaml @@ -65,6 +65,25 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: GAMMA input, usually from one of the AAL blocks. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + GAMMA output to the input of the next desired component in the + display pipeline, for example one of the available DITHER or + POSTMASK blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml index dae839279950bf..0de9f64f3f8456 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml @@ -77,6 +77,29 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + MERGE input port, usually from DITHER, DPI, DSC, DSI, MDP_RDMA, + ETHDR or even from a different MERGE block + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + MERGE output to a DSC, DPI, DP_INTF, DSI, ETHDR, Write DMA, or + a different MERGE block, or others. + + required: + - port@0 + - port@1 + resets: description: reset controller See Documentation/devicetree/bindings/reset/reset.txt for details. diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,od.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,od.yaml index 831c653caffd7d..71534febd49c67 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,od.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,od.yaml @@ -38,6 +38,28 @@ properties: items: - description: OD Clock + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: OD input port, usually from an AAL block + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + OD output to the input of the next desired component in the + display pipeline, for example one of the available RDMA or + other blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl-2l.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl-2l.yaml index c7dd0ef02dcf51..bacdfe7d08a619 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl-2l.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl-2l.yaml @@ -57,6 +57,28 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: OVL input port from MMSYS, VDOSYS or other OVLs + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + OVL output to the input of the next desired component in the + display pipeline, for example one of the available COLOR, RDMA + or WDMA blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl.yaml index d55611c7ce5ebc..9ea796a033b2ca 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl.yaml @@ -75,6 +75,28 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: OVL input port from MMSYS or one of multiple VDOSYS + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + OVL output to the input of the next desired component in the + display pipeline, for example one of the available COLOR, RDMA + or WDMA blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,postmask.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,postmask.yaml index 11fe32e50a5943..fb6fe4742624bb 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,postmask.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,postmask.yaml @@ -52,6 +52,27 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: POSTMASK input port, usually from GAMMA + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + POSTMASK output to the input of the next desired component in the + display pipeline, for example one of the available DITHER blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,rdma.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,rdma.yaml index 4cadb245d02800..878f676b581f95 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,rdma.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,rdma.yaml @@ -87,6 +87,28 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: RDMA input port, usually from MMSYS, OD or OVL + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + RDMA output to the input of the next desired component in the + display pipeline, for example one of the available COLOR, DPI, + DSI, MERGE or UFOE blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ufoe.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ufoe.yaml index 39e3e2d4a0db8b..61a5e22effbf2d 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ufoe.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ufoe.yaml @@ -43,6 +43,27 @@ properties: items: - description: UFOe Clock + ports: + $ref: /schemas/graph.yaml#/properties/ports + description: + Input and output ports can have multiple endpoints, each of those + connects to either the primary, secondary, etc, display pipeline. + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: UFOE input, usually from one of the RDMA blocks. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + UFOE output to the input of the next desired component in the + display pipeline, usually one of the available DSI blocks. + + required: + - port@0 + - port@1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index 97993feda19368..a212f335d5ffae 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -17,6 +17,7 @@ properties: compatible: oneOf: - enum: + - qcom,sa8775p-dp - qcom,sc7180-dp - qcom,sc7280-dp - qcom,sc7280-edp diff --git a/Documentation/devicetree/bindings/display/msm/gmu.yaml b/Documentation/devicetree/bindings/display/msm/gmu.yaml index b1bd372996d571..ab884e2364293e 100644 --- a/Documentation/devicetree/bindings/display/msm/gmu.yaml +++ b/Documentation/devicetree/bindings/display/msm/gmu.yaml @@ -125,6 +125,7 @@ allOf: enum: - qcom,adreno-gmu-635.0 - qcom,adreno-gmu-660.1 + - qcom,adreno-gmu-663.0 then: properties: reg: diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml new file mode 100644 index 00000000000000..58f8a01f29c7aa --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sa8775p-mdss.yaml @@ -0,0 +1,241 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sa8775p-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. SA87755P Display MDSS + +maintainers: + - Mahadevan + +description: + SA8775P MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like + DPU display controller, DP interfaces and EDP etc. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + const: qcom,sa8775p-mdss + + clocks: + items: + - description: Display AHB + - description: Display hf AXI + - description: Display core + + iommus: + maxItems: 1 + + interconnects: + maxItems: 3 + + interconnect-names: + maxItems: 3 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + const: qcom,sa8775p-dpu + + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + items: + - const: qcom,sa8775p-dp + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + + display-subsystem@ae00000 { + compatible = "qcom,sa8775p-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + + interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>, + <&mmss_noc MASTER_MDP1 &mc_virt SLAVE_EBI1>, + <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "mdp1-mem", + "cpu-cfg"; + + + resets = <&dispcc_core_bcr>; + power-domains = <&dispcc_gdsc>; + + clocks = <&dispcc_ahb_clk>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc_mdp_clk>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu 0x1000 0x402>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sa8775p-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc_ahb_clk>, + <&dispcc_mdp_lut_clk>, + <&dispcc_mdp_clk>, + <&dispcc_mdp_vsync_clk>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc_mdp_vsync_clk>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdss0_mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + interrupt-parent = <&mdss0>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss0_dp0_in>; + }; + }; + }; + + mdss0_mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + + opp-575000000 { + opp-hz = /bits/ 64 <575000000>; + required-opps = <&rpmhpd_opp_turbo>; + }; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + required-opps = <&rpmhpd_opp_turbo_l1>; + }; + }; + }; + + displayport-controller@af54000 { + compatible = "qcom,sa8775p-dp"; + + pinctrl-0 = <&dp_hot_plug_det>; + pinctrl-names = "default"; + + reg = <0xaf54000 0x104>, + <0xaf54200 0x0c0>, + <0xaf55000 0x770>, + <0xaf56000 0x09c>; + + interrupt-parent = <&mdss0>; + interrupts = <12>; + + clocks = <&dispcc_mdss_ahb_clk>, + <&dispcc_dptx0_aux_clk>, + <&dispcc_dptx0_link_clk>, + <&dispcc_dptx0_link_intf_clk>, + <&dispcc_dptx0_pixel0_clk>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel"; + + assigned-clocks = <&dispcc_mdss_dptx0_link_clk_src>, + <&dispcc_mdss_dptx0_pixel0_clk_src>; + assigned-clock-parents = <&mdss0_edp_phy 0>, <&mdss0_edp_phy 1>; + + phys = <&mdss0_edp_phy>; + phy-names = "dp"; + + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd SA8775P_MMCX>; + + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss0_dp0_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + mdss0_dp_out: endpoint { }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml index b0fbe86219d105..6902795b4e2c24 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-dpu.yaml @@ -7,13 +7,21 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Qualcomm Display DPU on SC7280 maintainers: + - Bjorn Andersson + - Neil Armstrong + - Dmitry Baryshkov - Krishna Manikandan $ref: /schemas/display/msm/dpu-common.yaml# properties: compatible: - const: qcom,sc7280-dpu + enum: + - qcom,sc7280-dpu + - qcom,sc8280xp-dpu + - qcom,sm8350-dpu + - qcom,sm8450-dpu + - qcom,sm8550-dpu reg: items: diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc8280xp-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc8280xp-dpu.yaml deleted file mode 100644 index d19e3bec4600e5..00000000000000 --- a/Documentation/devicetree/bindings/display/msm/qcom,sc8280xp-dpu.yaml +++ /dev/null @@ -1,122 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/qcom,sc8280xp-dpu.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm SC8280XP Display Processing Unit - -maintainers: - - Bjorn Andersson - -description: - Device tree bindings for SC8280XP Display Processing Unit. - -$ref: /schemas/display/msm/dpu-common.yaml# - -properties: - compatible: - const: qcom,sc8280xp-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display hf axi clock - - description: Display sf axi clock - - description: Display ahb clock - - description: Display lut clock - - description: Display core clock - - description: Display vsync clock - - clock-names: - items: - - const: bus - - const: nrt_bus - - const: iface - - const: lut - - const: core - - const: vsync - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - #include - - display-controller@ae01000 { - compatible = "qcom,sc8280xp-dpu"; - reg = <0x0ae01000 0x8f000>, - <0x0aeb0000 0x2008>; - reg-names = "mdp", "vbif"; - - clocks = <&gcc GCC_DISP_HF_AXI_CLK>, - <&gcc GCC_DISP_SF_AXI_CLK>, - <&dispcc0 DISP_CC_MDSS_AHB_CLK>, - <&dispcc0 DISP_CC_MDSS_MDP_LUT_CLK>, - <&dispcc0 DISP_CC_MDSS_MDP_CLK>, - <&dispcc0 DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "bus", - "nrt_bus", - "iface", - "lut", - "core", - "vsync"; - - assigned-clocks = <&dispcc0 DISP_CC_MDSS_MDP_CLK>, - <&dispcc0 DISP_CC_MDSS_VSYNC_CLK>; - assigned-clock-rates = <460000000>, - <19200000>; - - operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SC8280XP_MMCX>; - - interrupt-parent = <&mdss0>; - interrupts = <0>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - endpoint { - remote-endpoint = <&mdss0_dp0_in>; - }; - }; - - port@4 { - reg = <4>; - endpoint { - remote-endpoint = <&mdss0_dp1_in>; - }; - }; - - port@5 { - reg = <5>; - endpoint { - remote-endpoint = <&mdss0_dp3_in>; - }; - }; - - port@6 { - reg = <6>; - endpoint { - remote-endpoint = <&mdss0_dp2_in>; - }; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-dpu.yaml index 13146b3f053cff..a88d22f30a6028 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-dpu.yaml @@ -13,7 +13,9 @@ $ref: /schemas/display/msm/dpu-common.yaml# properties: compatible: - const: qcom,sm8150-dpu + enum: + - qcom,sm8150-dpu + - qcom,sm8250-dpu reg: items: diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml deleted file mode 100644 index ffa5047e901fc9..00000000000000 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/qcom,sm8250-dpu.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm SM8250 Display DPU - -maintainers: - - Dmitry Baryshkov - -$ref: /schemas/display/msm/dpu-common.yaml# - -properties: - compatible: - const: qcom,sm8250-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display ahb clock - - description: Display hf axi clock - - description: Display core clock - - description: Display vsync clock - - clock-names: - items: - - const: iface - - const: bus - - const: core - - const: vsync - -required: - - compatible - - reg - - reg-names - - clocks - - clock-names - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - #include - - display-controller@ae01000 { - compatible = "qcom,sm8250-dpu"; - reg = <0x0ae01000 0x8f000>, - <0x0aeb0000 0x2008>; - reg-names = "mdp", "vbif"; - - clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&gcc GCC_DISP_HF_AXI_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "iface", "bus", "core", "vsync"; - - assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - assigned-clock-rates = <19200000>; - - operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd RPMHPD_MMCX>; - - interrupt-parent = <&mdss>; - interrupts = <0>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - - port@1 { - reg = <1>; - endpoint { - remote-endpoint = <&dsi1_in>; - }; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml deleted file mode 100644 index 96ef2d9c351216..00000000000000 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/qcom,sm8350-dpu.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm SM8350 Display DPU - -maintainers: - - Robert Foss - -$ref: /schemas/display/msm/dpu-common.yaml# - -properties: - compatible: - const: qcom,sm8350-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display hf axi clock - - description: Display sf axi clock - - description: Display ahb clock - - description: Display lut clock - - description: Display core clock - - description: Display vsync clock - - clock-names: - items: - - const: bus - - const: nrt_bus - - const: iface - - const: lut - - const: core - - const: vsync - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - #include - - display-controller@ae01000 { - compatible = "qcom,sm8350-dpu"; - reg = <0x0ae01000 0x8f000>, - <0x0aeb0000 0x2008>; - reg-names = "mdp", "vbif"; - - clocks = <&gcc GCC_DISP_HF_AXI_CLK>, - <&gcc GCC_DISP_SF_AXI_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "bus", - "nrt_bus", - "iface", - "lut", - "core", - "vsync"; - - assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - assigned-clock-rates = <19200000>; - - operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd RPMHPD_MMCX>; - - interrupt-parent = <&mdss>; - interrupts = <0>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dpu_intf1_out: endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - }; - - mdp_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp-200000000 { - opp-hz = /bits/ 64 <200000000>; - required-opps = <&rpmhpd_opp_low_svs>; - }; - - opp-300000000 { - opp-hz = /bits/ 64 <300000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-345000000 { - opp-hz = /bits/ 64 <345000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - }; - - opp-460000000 { - opp-hz = /bits/ 64 <460000000>; - required-opps = <&rpmhpd_opp_nom>; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml deleted file mode 100644 index 2a5d3daed0e1c0..00000000000000 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml +++ /dev/null @@ -1,139 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/qcom,sm8450-dpu.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm SM8450 Display DPU - -maintainers: - - Dmitry Baryshkov - -$ref: /schemas/display/msm/dpu-common.yaml# - -properties: - compatible: - const: qcom,sm8450-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display hf axi - - description: Display sf axi - - description: Display ahb - - description: Display lut - - description: Display core - - description: Display vsync - - clock-names: - items: - - const: bus - - const: nrt_bus - - const: iface - - const: lut - - const: core - - const: vsync - -required: - - compatible - - reg - - reg-names - - clocks - - clock-names - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - #include - - display-controller@ae01000 { - compatible = "qcom,sm8450-dpu"; - reg = <0x0ae01000 0x8f000>, - <0x0aeb0000 0x2008>; - reg-names = "mdp", "vbif"; - - clocks = <&gcc GCC_DISP_HF_AXI_CLK>, - <&gcc GCC_DISP_SF_AXI_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "bus", - "nrt_bus", - "iface", - "lut", - "core", - "vsync"; - - assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - assigned-clock-rates = <19200000>; - - operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd RPMHPD_MMCX>; - - interrupt-parent = <&mdss>; - interrupts = <0>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dpu_intf1_out: endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - - port@1 { - reg = <1>; - dpu_intf2_out: endpoint { - remote-endpoint = <&dsi1_in>; - }; - }; - }; - - mdp_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp-172000000{ - opp-hz = /bits/ 64 <172000000>; - required-opps = <&rpmhpd_opp_low_svs_d1>; - }; - - opp-200000000 { - opp-hz = /bits/ 64 <200000000>; - required-opps = <&rpmhpd_opp_low_svs>; - }; - - opp-325000000 { - opp-hz = /bits/ 64 <325000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-375000000 { - opp-hz = /bits/ 64 <375000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - }; - - opp-500000000 { - opp-hz = /bits/ 64 <500000000>; - required-opps = <&rpmhpd_opp_nom>; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml deleted file mode 100644 index 16a541fca66f3e..00000000000000 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml +++ /dev/null @@ -1,133 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/msm/qcom,sm8550-dpu.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Qualcomm SM8550 Display DPU - -maintainers: - - Neil Armstrong - -$ref: /schemas/display/msm/dpu-common.yaml# - -properties: - compatible: - const: qcom,sm8550-dpu - - reg: - items: - - description: Address offset and size for mdp register set - - description: Address offset and size for vbif register set - - reg-names: - items: - - const: mdp - - const: vbif - - clocks: - items: - - description: Display AHB - - description: Display hf axi - - description: Display MDSS ahb - - description: Display lut - - description: Display core - - description: Display vsync - - clock-names: - items: - - const: bus - - const: nrt_bus - - const: iface - - const: lut - - const: core - - const: vsync - -required: - - compatible - - reg - - reg-names - - clocks - - clock-names - -unevaluatedProperties: false - -examples: - - | - #include - #include - #include - #include - - display-controller@ae01000 { - compatible = "qcom,sm8550-dpu"; - reg = <0x0ae01000 0x8f000>, - <0x0aeb0000 0x2008>; - reg-names = "mdp", "vbif"; - - clocks = <&gcc GCC_DISP_AHB_CLK>, - <&gcc GCC_DISP_HF_AXI_CLK>, - <&dispcc DISP_CC_MDSS_AHB_CLK>, - <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, - <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - clock-names = "bus", - "nrt_bus", - "iface", - "lut", - "core", - "vsync"; - - assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; - assigned-clock-rates = <19200000>; - - operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd RPMHPD_MMCX>; - - interrupt-parent = <&mdss>; - interrupts = <0>; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - dpu_intf1_out: endpoint { - remote-endpoint = <&dsi0_in>; - }; - }; - - port@1 { - reg = <1>; - dpu_intf2_out: endpoint { - remote-endpoint = <&dsi1_in>; - }; - }; - }; - - mdp_opp_table: opp-table { - compatible = "operating-points-v2"; - - opp-200000000 { - opp-hz = /bits/ 64 <200000000>; - required-opps = <&rpmhpd_opp_low_svs>; - }; - - opp-325000000 { - opp-hz = /bits/ 64 <325000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-375000000 { - opp-hz = /bits/ 64 <375000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - }; - - opp-514000000 { - opp-hz = /bits/ 64 <514000000>; - required-opps = <&rpmhpd_opp_nom>; - }; - }; - }; -... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml index c4087cc5abbdd4..01cf79bd754b49 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml @@ -14,6 +14,7 @@ $ref: /schemas/display/msm/dpu-common.yaml# properties: compatible: enum: + - qcom,sa8775p-dpu - qcom,sm8650-dpu - qcom,x1e80100-dpu diff --git a/Documentation/devicetree/bindings/display/panel/advantech,idk-2121wr.yaml b/Documentation/devicetree/bindings/display/panel/advantech,idk-2121wr.yaml index 2e8dbdb5a3d5ad..05ca3b2385f835 100644 --- a/Documentation/devicetree/bindings/display/panel/advantech,idk-2121wr.yaml +++ b/Documentation/devicetree/bindings/display/panel/advantech,idk-2121wr.yaml @@ -20,6 +20,7 @@ description: | dual-lvds-odd-pixels or dual-lvds-even-pixels). allOf: + - $ref: /schemas/display/lvds-dual-ports.yaml# - $ref: panel-common.yaml# properties: @@ -44,22 +45,10 @@ properties: properties: port@0: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false - description: The sink for odd pixels. - properties: - dual-lvds-odd-pixels: true - required: - dual-lvds-odd-pixels port@1: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false - description: The sink for even pixels. - properties: - dual-lvds-even-pixels: true - required: - dual-lvds-even-pixels @@ -75,7 +64,6 @@ required: - height-mm - data-mapping - panel-timing - - ports examples: - |+ diff --git a/Documentation/devicetree/bindings/display/panel/panel-common.yaml b/Documentation/devicetree/bindings/display/panel/panel-common.yaml index 0a57a31f4f3dde..087415753d606c 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-common.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-common.yaml @@ -51,6 +51,14 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 90, 180, 270] + flip-horizontal: + description: boolean to flip image horizontally + type: boolean + + flip-vertical: + description: boolean to flip image vertically + type: boolean + # Display Timings panel-timing: description: diff --git a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml index 155d8ffa8f6ef1..5af2d69300751a 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-lvds.yaml @@ -50,6 +50,8 @@ properties: - hannstar,hsd101pww2 # Hydis Technologies 7" WXGA (800x1280) TFT LCD LVDS panel - hydis,hv070wx2-1e0 + # Jenson Display BL-JT60050-01A 7" WSVGA (1024x600) color TFT LCD LVDS panel + - jenson,bl-jt60050-01a - tbs,a711-panel - const: panel-lvds diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml index 10ed4b57232b9b..e80fc7006984e0 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml @@ -22,6 +22,7 @@ description: | If the panel is more advanced a dedicated binding file is required. allOf: + - $ref: /schemas/display/lvds-dual-ports.yaml# - $ref: panel-common.yaml# properties: @@ -55,28 +56,10 @@ properties: properties: port@0: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false - description: The first sink port. - - properties: - dual-lvds-odd-pixels: - type: boolean - description: The first sink port for odd pixels. - required: - dual-lvds-odd-pixels port@1: - $ref: /schemas/graph.yaml#/$defs/port-base - unevaluatedProperties: false - description: The second sink port. - - properties: - dual-lvds-even-pixels: - type: boolean - description: The second sink port for even pixels. - required: - dual-lvds-even-pixels @@ -88,7 +71,6 @@ unevaluatedProperties: false required: - compatible - - ports - power-supply examples: diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index b89e3979057911..18b63f356bb4bb 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -200,6 +200,8 @@ properties: - logictechno,lttd800480070-l2rt # Logic Technologies LTTD800480070-L6WH-RT 7” 800x480 TFT Resistive Touch Module - logictechno,lttd800480070-l6wh-rt + # Microchip AC69T88A 5" 800X480 LVDS interface TFT LCD Panel + - microchip,ac69t88a # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel - mitsubishi,aa070mc01-ca1 # Mitsubishi AA084XE01 8.4" XGA TFT LCD panel diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ams581vf01.yaml b/Documentation/devicetree/bindings/display/panel/samsung,ams581vf01.yaml new file mode 100644 index 00000000000000..70dff9c0ef2bec --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/samsung,ams581vf01.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/samsung,ams581vf01.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung AMS581VF01 SOFEF01-based 5.81" 1080x2340 MIPI-DSI Panel + +maintainers: + - Danila Tikhonov + +description: + The Samsung AMS581VF01 is a 5.81 inch 1080x2340 MIPI-DSI CMD mode OLED panel. + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: samsung,ams581vf01 + + reg: + maxItems: 1 + + vdd3p3-supply: + description: 3.3V source voltage rail + + vddio-supply: + description: I/O source voltage rail + + vsn-supply: + description: Negative source voltage rail + + vsp-supply: + description: Positive source voltage rail + + reset-gpios: true + port: true + +required: + - compatible + - reg + - vdd3p3-supply + - vddio-supply + - vsn-supply + - vsp-supply + - reset-gpios + - port + +additionalProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "samsung,ams581vf01"; + reg = <0>; + + vdd3p3-supply = <&vreg_l7c_3p0>; + vddio-supply = <&vreg_l13a_1p8>; + vsn-supply = <&vreg_ibb>; + vsp-supply = <&vreg_lab>; + + reset-gpios = <&pm6150l_gpios 9 GPIO_ACTIVE_LOW>; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/samsung,ams639rq08.yaml b/Documentation/devicetree/bindings/display/panel/samsung,ams639rq08.yaml new file mode 100644 index 00000000000000..f5b6ecb96f994f --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/samsung,ams639rq08.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/samsung,ams639rq08.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung AMS639RQ08 EA8076-based 6.39" 1080x2340 MIPI-DSI Panel + +maintainers: + - Danila Tikhonov + - Jens Reidel + +description: + The Samsung AMS639RQ08 is a 6.39 inch 1080x2340 MIPI-DSI CMD mode AMOLED panel. + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: samsung,ams639rq08 + + reg: + maxItems: 1 + + vdd3p3-supply: + description: 3.3V source voltage rail + + vddio-supply: + description: I/O source voltage rail + + vsn-supply: + description: Negative source voltage rail + + vsp-supply: + description: Positive source voltage rail + + reset-gpios: true + port: true + +required: + - compatible + - reg + - vdd3p3-supply + - vddio-supply + - vsn-supply + - vsp-supply + - reset-gpios + - port + +additionalProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "samsung,ams639rq08"; + reg = <0>; + + vdd3p3-supply = <&vreg_l18a_2p8>; + vddio-supply = <&vreg_l13a_1p8>; + vsn-supply = <&vreg_ibb>; + vsp-supply = <&vreg_lab>; + + reset-gpios = <&pm6150l_gpios 9 GPIO_ACTIVE_LOW>; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha8.yaml b/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha8.yaml new file mode 100644 index 00000000000000..05a78429aaead8 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e3ha8.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/samsung,s6e3ha8.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung s6e3ha8 AMOLED DSI panel + +description: The s6e3ha8 is a 1440x2960 DPI display panel from Samsung Mobile + Displays (SMD). + +maintainers: + - Dzmitry Sankouski + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: samsung,s6e3ha8 + + reg: + maxItems: 1 + + reset-gpios: true + + port: true + + vdd3-supply: + description: VDD regulator + + vci-supply: + description: VCI regulator + + vddr-supply: + description: VDDR regulator + +required: + - compatible + - reset-gpios + - vdd3-supply + - vci-supply + - vddr-supply + +unevaluatedProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "samsung,s6e3ha8"; + reg = <0>; + vci-supply = <&s2dos05_ldo4>; + vddr-supply = <&s2dos05_buck1>; + vdd3-supply = <&s2dos05_ldo1>; + te-gpios = <&tlmm 10 GPIO_ACTIVE_HIGH>; + reset-gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&sde_dsi_active &sde_te_active_sleep>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_active_sleep>; + pinctrl-names = "default", "sleep"; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e88a0-ams427ap24.yaml b/Documentation/devicetree/bindings/display/panel/samsung,s6e88a0-ams427ap24.yaml new file mode 100644 index 00000000000000..db284ba5be2099 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e88a0-ams427ap24.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/samsung,s6e88a0-ams427ap24.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung AMS427AP24 panel with S6E88A0 controller + +maintainers: + - Jakob Hauser + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: samsung,s6e88a0-ams427ap24 + + reg: + maxItems: 1 + + port: true + reset-gpios: true + flip-horizontal: true + + vdd3-supply: + description: core voltage supply + + vci-supply: + description: voltage supply for analog circuits + +required: + - compatible + - reg + - port + - reset-gpios + - vdd3-supply + - vci-supply + +additionalProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "samsung,s6e88a0-ams427ap24"; + reg = <0>; + + vdd3-supply = <&pm8916_l17>; + vci-supply = <&pm8916_l6>; + reset-gpios = <&tlmm 25 GPIO_ACTIVE_LOW>; + flip-horizontal; + + port { + panel_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa0.yaml b/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa0.yaml index 4601fa46068077..19c8cc83db9781 100644 --- a/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa0.yaml +++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e8aa0.yaml @@ -21,6 +21,8 @@ properties: reset-gpios: true display-timings: true + flip-horizontal: true + flip-vertical: true vdd3-supply: description: core voltage supply @@ -46,14 +48,6 @@ properties: panel-height-mm: description: physical panel height [mm] - flip-horizontal: - description: boolean to flip image horizontally - type: boolean - - flip-vertical: - description: boolean to flip image vertically - type: boolean - required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml new file mode 100644 index 00000000000000..d8e761865f27e2 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml @@ -0,0 +1,188 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/rockchip/rockchip,rk3588-dw-hdmi-qp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip DW HDMI QP TX Encoder + +maintainers: + - Cristian Ciocaltea + +description: | + Rockchip RK3588 SoC integrates the Synopsys DesignWare HDMI QP TX controller + IP and a HDMI/eDP TX Combo PHY based on a Samsung IP block, providing the + following features, among others: + + * Fixed Rate Link (FRL) + * Display Stream Compression (DSC) + * 4K@120Hz and 8K@60Hz video modes + * Variable Refresh Rate (VRR) including Quick Media Switching (QMS) + * Fast Vactive (FVA) + * SCDC I2C DDC access + * Multi-stream audio + * Enhanced Audio Return Channel (EARC) + +allOf: + - $ref: /schemas/sound/dai-common.yaml# + +properties: + compatible: + enum: + - rockchip,rk3588-dw-hdmi-qp + + reg: + maxItems: 1 + + clocks: + items: + - description: Peripheral/APB bus clock + - description: EARC RX biphase clock + - description: Reference clock + - description: Audio interface clock + - description: TMDS/FRL link clock + - description: Video datapath clock + + clock-names: + items: + - const: pclk + - const: earc + - const: ref + - const: aud + - const: hdp + - const: hclk_vo1 + + interrupts: + items: + - description: AVP Unit interrupt + - description: CEC interrupt + - description: eARC RX interrupt + - description: Main Unit interrupt + - description: HPD interrupt + + interrupt-names: + items: + - const: avp + - const: cec + - const: earc + - const: main + - const: hpd + + phys: + maxItems: 1 + description: The HDMI/eDP PHY + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Video port for RGB/YUV input. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Video port for HDMI/eDP output. + + required: + - port@0 + - port@1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 2 + + reset-names: + items: + - const: ref + - const: hdp + + "#sound-dai-cells": + const: 0 + + rockchip,grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Some HDMI QP related data is accessed through SYS GRF regs. + + rockchip,vo-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Additional HDMI QP related data is accessed through VO GRF regs. + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - interrupt-names + - phys + - ports + - resets + - reset-names + - rockchip,grf + - rockchip,vo-grf + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + hdmi@fde80000 { + compatible = "rockchip,rk3588-dw-hdmi-qp"; + reg = <0x0 0xfde80000 0x0 0x20000>; + clocks = <&cru PCLK_HDMITX0>, + <&cru CLK_HDMITX0_EARC>, + <&cru CLK_HDMITX0_REF>, + <&cru MCLK_I2S5_8CH_TX>, + <&cru CLK_HDMIHDP0>, + <&cru HCLK_VO1>; + clock-names = "pclk", "earc", "ref", "aud", "hdp", "hclk_vo1"; + interrupts = , + , + , + , + ; + interrupt-names = "avp", "cec", "earc", "main", "hpd"; + phys = <&hdptxphy_hdmi0>; + power-domains = <&power RK3588_PD_VO1>; + resets = <&cru SRST_HDMITX0_REF>, <&cru SRST_HDMIHDP0>; + reset-names = "ref", "hdp"; + rockchip,grf = <&sys_grf>; + rockchip,vo-grf = <&vo1_grf>; + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; + }; + + port@1 { + reg = <1>; + + hdmi0_out_con0: endpoint { + remote-endpoint = <&hdmi_con0_in>; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/samsung/samsung,exynos7-decon.yaml b/Documentation/devicetree/bindings/display/samsung/samsung,exynos7-decon.yaml index 992c23ca7a4ee8..53916e4c95d8c0 100644 --- a/Documentation/devicetree/bindings/display/samsung/samsung,exynos7-decon.yaml +++ b/Documentation/devicetree/bindings/display/samsung/samsung,exynos7-decon.yaml @@ -19,7 +19,9 @@ description: | properties: compatible: - const: samsung,exynos7-decon + enum: + - samsung,exynos7-decon + - samsung,exynos7870-decon clocks: maxItems: 4 diff --git a/Documentation/devicetree/bindings/display/sharp,ls010b7dh04.yaml b/Documentation/devicetree/bindings/display/sharp,ls010b7dh04.yaml new file mode 100644 index 00000000000000..8097f091c2a55f --- /dev/null +++ b/Documentation/devicetree/bindings/display/sharp,ls010b7dh04.yaml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/sharp,ls010b7dh04.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sharp Memory LCD panels + +maintainers: + - Alex Lanzano + +description: + Sharp Memory LCDs are a series of monochrome displays that operate over + a SPI bus. The displays require a signal (VCOM) to be generated to prevent + DC bias build up resulting in pixels being unable to change. Three modes + can be used to provide the VCOM signal ("software", "external", "pwm"). + +properties: + compatible: + enum: + - sharp,ls010b7dh04 + - sharp,ls011b7dh03 + - sharp,ls012b7dd01 + - sharp,ls013b7dh03 + - sharp,ls013b7dh05 + - sharp,ls018b7dh02 + - sharp,ls027b7dh01 + - sharp,ls027b7dh01a + - sharp,ls032b7dd02 + - sharp,ls044q7dh01 + + reg: + maxItems: 1 + + spi-max-frequency: + maximum: 2000000 + + sharp,vcom-mode: + $ref: /schemas/types.yaml#/definitions/string + description: | + software - This mode relies on a software operation to send a + "maintain display" message to the display, toggling the vcom + bit on and off with each message + + external - This mode relies on an external clock to generate + the signal on the EXTCOMM pin + + pwm - This mode relies on a pwm device to generate the signal + on the EXTCOMM pin + + enum: [software, external, pwm] + + enable-gpios: true + + pwms: + maxItems: 1 + description: External VCOM signal + +required: + - compatible + - reg + - sharp,vcom-mode + +allOf: + - $ref: panel/panel-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + + - if: + properties: + sharp,vcom-mode: + const: pwm + then: + required: + - pwms + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + display@0 { + compatible = "sharp,ls013b7dh03"; + reg = <0>; + spi-cs-high; + spi-max-frequency = <1000000>; + sharp,vcom-mode = "software"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/dma/dma-common.yaml b/Documentation/devicetree/bindings/dma/dma-common.yaml index ea700f8ee6c6aa..fde5160b5d29e4 100644 --- a/Documentation/devicetree/bindings/dma/dma-common.yaml +++ b/Documentation/devicetree/bindings/dma/dma-common.yaml @@ -32,10 +32,9 @@ properties: The first item in the array is for channels 0-31, the second is for channels 32-63, etc. $ref: /schemas/types.yaml#/definitions/uint32-array - items: - minItems: 1 - # Should be enough - maxItems: 255 + minItems: 1 + # Should be enough + maxItems: 255 dma-channels: $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml index 4df4e61895d212..4ad56a409b9cac 100644 --- a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml @@ -26,6 +26,7 @@ properties: - enum: - qcom,qcm2290-gpi-dma - qcom,qdu1000-gpi-dma + - qcom,sar2130p-gpi-dma - qcom,sc7280-gpi-dma - qcom,sdx75-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 ca24cf48769f6d..b356251de5a829 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml @@ -4,18 +4,16 @@ $id: http://devicetree.org/schemas/dma/renesas,rz-dmac.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Renesas RZ/{G2L,G2UL,V2L} DMA Controller +title: Renesas RZ DMA Controller maintainers: - Biju Das -allOf: - - $ref: dma-controller.yaml# - properties: compatible: items: - enum: + - renesas,r7s72100-dmac # RZ/A1H - renesas,r9a07g043-dmac # RZ/G2UL and RZ/Five - renesas,r9a07g044-dmac # RZ/G2{L,LC} - renesas,r9a07g054-dmac # RZ/V2L @@ -93,13 +91,26 @@ required: - reg - interrupts - interrupt-names - - clocks - - clock-names - '#dma-cells' - dma-channels - - power-domains - - resets - - reset-names + +allOf: + - $ref: dma-controller.yaml# + + - if: + not: + properties: + compatible: + contains: + enum: + - renesas,r7s72100-dmac + then: + required: + - clocks + - clock-names + - power-domains + - resets + - reset-names additionalProperties: false diff --git a/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml b/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml index 3b22183a1a3792..609e38901434a4 100644 --- a/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml +++ b/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml @@ -27,11 +27,16 @@ allOf: properties: compatible: - items: - - enum: - - microchip,mpfs-pdma - - sifive,fu540-c000-pdma - - const: sifive,pdma0 + oneOf: + - items: + - const: microchip,pic64gx-pdma + - const: microchip,mpfs-pdma + - const: sifive,pdma0 + - items: + - enum: + - microchip,mpfs-pdma + - sifive,fu540-c000-pdma + - const: sifive,pdma0 description: Should be "sifive,-pdma" and "sifive,pdma". Supported compatible strings are - diff --git a/Documentation/devicetree/bindings/dma/stm32/st,stm32-dma3.yaml b/Documentation/devicetree/bindings/dma/stm32/st,stm32-dma3.yaml index 7fdc44b2e64679..36f9fe860eb990 100644 --- a/Documentation/devicetree/bindings/dma/stm32/st,stm32-dma3.yaml +++ b/Documentation/devicetree/bindings/dma/stm32/st,stm32-dma3.yaml @@ -96,6 +96,12 @@ properties: including the update of the LLI if any 0x3: at channel level, the transfer complete event is generated at the end of the last LLI + -bit 16: Prevent packing/unpacking mode + 0x0: pack/unpack enabled when source data width/burst != destination data width/burst + 0x1: memory data width/burst forced to peripheral data width/burst to prevent pack/unpack + -bit 17: Prevent additional transfers due to linked-list refactoring + 0x0: don't prevent additional transfers for optimal performance + 0x1: prevent additional transfer to accommodate user constraints such as single transfer required: - compatible diff --git a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml index 9af40da5688efe..ab93ffd3d2e5b6 100644 --- a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml +++ b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml @@ -99,14 +99,35 @@ allOf: contains: enum: - fsl,imx8qxp-dsp - - fsl,imx8qm-dsp - fsl,imx8qxp-hifi4 + then: + properties: + power-domains: + minItems: 2 + maxItems: 2 + + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8qm-dsp - fsl,imx8qm-hifi4 then: properties: power-domains: minItems: 4 - else: + + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8mp-dsp + - fsl,imx8mp-hifi4 + - fsl,imx8ulp-dsp + - fsl,imx8ulp-hifi4 + then: properties: power-domains: maxItems: 1 @@ -157,10 +178,8 @@ examples: <&adma_lpcg IMX_ADMA_LPCG_OCRAM_IPG_CLK>, <&adma_lpcg IMX_ADMA_LPCG_DSP_CORE_CLK>; clock-names = "ipg", "ocram", "core"; - power-domains = <&pd IMX_SC_R_MU_13A>, - <&pd IMX_SC_R_MU_13B>, - <&pd IMX_SC_R_DSP>, - <&pd IMX_SC_R_DSP_RAM>; + power-domains = <&pd IMX_SC_R_MU_13B>, + <&pd IMX_SC_R_MU_2A>; mbox-names = "txdb0", "txdb1", "rxdb0", "rxdb1"; mboxes = <&lsio_mu13 2 0>, <&lsio_mu13 2 1>, <&lsio_mu13 3 0>, <&lsio_mu13 3 1>; memory-region = <&dsp_reserved>; diff --git a/Documentation/devicetree/bindings/eeprom/at24.yaml b/Documentation/devicetree/bindings/eeprom/at24.yaml index b6239ec3512b34..590ba0ef5fa261 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.yaml +++ b/Documentation/devicetree/bindings/eeprom/at24.yaml @@ -141,6 +141,8 @@ properties: - const: microchip,24aa025e48 - items: - const: microchip,24aa025e64 + - items: + - const: st,24256e-wl - pattern: '^atmel,24c(32|64)d-wl$' # Actual vendor is st label: diff --git a/Documentation/devicetree/bindings/example-schema.yaml b/Documentation/devicetree/bindings/example-schema.yaml index a41f9b9a196bbc..484f8babcda4b9 100644 --- a/Documentation/devicetree/bindings/example-schema.yaml +++ b/Documentation/devicetree/bindings/example-schema.yaml @@ -262,4 +262,5 @@ examples: reg-names = "core", "aux"; interrupts = <10>; interrupt-controller; + #interrupt-cells = <2>; }; diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml index ff7a6f12cd00f5..abbd62f1fed099 100644 --- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml +++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml @@ -131,6 +131,21 @@ properties: be a non-zero value if set. minimum: 1 + arm,max-msg-size: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + An optional value, expressed in bytes, representing the maximum size + allowed for the payload of messages transmitted on this transport. + + arm,max-msg: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + An optional value representing the maximum number of concurrent in-flight + messages allowed by this transport; this number represents the maximum + number of concurrently outstanding messages that the server can handle on + this platform. If set, the value should be non-zero. + minimum: 1 + arm,smc-id: $ref: /schemas/types.yaml#/definitions/uint32 description: diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index 2cc83771d8e708..2ee03000000781 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -42,8 +42,11 @@ properties: - qcom,scm-msm8996 - qcom,scm-msm8998 - qcom,scm-qcm2290 + - qcom,scm-qcs8300 - qcom,scm-qdu1000 + - qcom,scm-sa8255p - qcom,scm-sa8775p + - qcom,scm-sar2130p - qcom,scm-sc7180 - qcom,scm-sc7280 - qcom,scm-sc8180x @@ -64,6 +67,7 @@ properties: - qcom,scm-sm8450 - qcom,scm-sm8550 - qcom,scm-sm8650 + - qcom,scm-sm8750 - qcom,scm-qcs404 - qcom,scm-x1e80100 - const: qcom,scm @@ -195,6 +199,7 @@ allOf: - qcom,scm-sm8450 - qcom,scm-sm8550 - qcom,scm-sm8650 + - qcom,scm-sm8750 then: properties: interrupts: false @@ -204,6 +209,7 @@ allOf: compatible: contains: enum: + - qcom,scm-sa8255p - qcom,scm-sa8775p then: properties: diff --git a/Documentation/devicetree/bindings/fpga/altera-passive-serial.txt b/Documentation/devicetree/bindings/fpga/altera-passive-serial.txt deleted file mode 100644 index 48478bc07e29c5..00000000000000 --- a/Documentation/devicetree/bindings/fpga/altera-passive-serial.txt +++ /dev/null @@ -1,29 +0,0 @@ -Altera Passive Serial SPI FPGA Manager - -Altera FPGAs support a method of loading the bitstream over what is -referred to as "passive serial". -The passive serial link is not technically SPI, and might require extra -circuits in order to play nicely with other SPI slaves on the same bus. - -See https://www.altera.com/literature/hb/cyc/cyc_c51013.pdf - -Required properties: -- compatible: Must be one of the following: - "altr,fpga-passive-serial", - "altr,fpga-arria10-passive-serial" -- reg: SPI chip select of the FPGA -- nconfig-gpios: config pin (referred to as nCONFIG in the manual) -- nstat-gpios: status pin (referred to as nSTATUS in the manual) - -Optional properties: -- confd-gpios: confd pin (referred to as CONF_DONE in the manual) - -Example: - fpga: fpga@0 { - compatible = "altr,fpga-passive-serial"; - spi-max-frequency = <20000000>; - reg = <0>; - nconfig-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; - nstat-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; - confd-gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; - }; diff --git a/Documentation/devicetree/bindings/fpga/altr,fpga-passive-serial.yaml b/Documentation/devicetree/bindings/fpga/altr,fpga-passive-serial.yaml new file mode 100644 index 00000000000000..ffb7cc54556fe9 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altr,fpga-passive-serial.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fpga/altr,fpga-passive-serial.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Altera Passive Serial SPI FPGA Manager + +maintainers: + - Fabio Estevam + +description: | + Altera FPGAs support a method of loading the bitstream over what is + referred to as "passive serial". + The passive serial link is not technically SPI, and might require extra + circuits in order to play nicely with other SPI slaves on the same bus. + + See https://www.altera.com/literature/hb/cyc/cyc_c51013.pdf + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - altr,fpga-passive-serial + - altr,fpga-arria10-passive-serial + + spi-max-frequency: + maximum: 20000000 + + reg: + maxItems: 1 + + nconfig-gpios: + description: + Config pin (referred to as nCONFIG in the manual). + maxItems: 1 + + nstat-gpios: + description: + Status pin (referred to as nSTATUS in the manual). + maxItems: 1 + + confd-gpios: + description: + confd pin (referred to as CONF_DONE in the manual) + maxItems: 1 + +required: + - compatible + - reg + - nconfig-gpios + - nstat-gpios + +additionalProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + fpga@0 { + compatible = "altr,fpga-passive-serial"; + reg = <0>; + nconfig-gpios = <&gpio4 18 GPIO_ACTIVE_LOW>; + nstat-gpios = <&gpio4 19 GPIO_ACTIVE_LOW>; + confd-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/fuse/renesas,rcar-efuse.yaml b/Documentation/devicetree/bindings/fuse/renesas,rcar-efuse.yaml deleted file mode 100644 index d7e289244e72cc..00000000000000 --- a/Documentation/devicetree/bindings/fuse/renesas,rcar-efuse.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/fuse/renesas,rcar-efuse.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: R-Car E-FUSE connected to PFC - -maintainers: - - Geert Uytterhoeven - -description: - The E-FUSE is a type of non-volatile memory, which is accessible through the - Pin Function Controller (PFC) on some R-Car Gen4 SoCs. - -properties: - compatible: - enum: - - renesas,r8a779a0-efuse # R-Car V3U - - renesas,r8a779f0-efuse # R-Car S4-8 - - reg: - maxItems: 1 - description: PFC System Group Fuse Control and Monitor register block - - clocks: - maxItems: 1 - - power-domains: - maxItems: 1 - - resets: - maxItems: 1 - -required: - - compatible - - reg - - clocks - - power-domains - - resets - -additionalProperties: false - -examples: - - | - #include - #include - - fuse: fuse@e6078800 { - compatible = "renesas,r8a779a0-efuse"; - reg = <0xe6078800 0x100>; - clocks = <&cpg CPG_MOD 916>; - power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; - resets = <&cpg 916>; - }; diff --git a/Documentation/devicetree/bindings/fuse/renesas,rcar-otp.yaml b/Documentation/devicetree/bindings/fuse/renesas,rcar-otp.yaml deleted file mode 100644 index d74872ae9ff378..00000000000000 --- a/Documentation/devicetree/bindings/fuse/renesas,rcar-otp.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/fuse/renesas,rcar-otp.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: R-Car E-FUSE connected to OTP_MEM - -maintainers: - - Geert Uytterhoeven - -description: - The E-FUSE is a type of non-volatile memory, which is accessible through the - One-Time Programmable Memory (OTP_MEM) module on some R-Car Gen4 SoCs. - -properties: - compatible: - enum: - - renesas,r8a779g0-otp # R-CarV4H - - renesas,r8a779h0-otp # R-CarV4M - - reg: - items: - - description: OTP_MEM_0 - - description: OTP_MEM_1 - -required: - - compatible - - reg - -additionalProperties: false - -examples: - - | - otp: otp@e61be000 { - compatible = "renesas,r8a779g0-otp"; - reg = <0xe61be000 0x1000>, <0xe61bf000 0x1000>; - }; diff --git a/Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml b/Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml index cf11aa7ec8c7be..b9afd07a9d2460 100644 --- a/Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml @@ -15,6 +15,7 @@ properties: - aspeed,ast2400-gpio - aspeed,ast2500-gpio - aspeed,ast2600-gpio + - aspeed,ast2700-gpio reg: maxItems: 1 @@ -25,7 +26,7 @@ properties: gpio-controller: true gpio-line-names: - minItems: 36 + minItems: 12 maxItems: 232 gpio-ranges: true @@ -42,7 +43,7 @@ properties: const: 2 ngpios: - minimum: 36 + minimum: 12 maximum: 232 required: @@ -93,6 +94,20 @@ allOf: enum: [ 36, 208 ] required: - ngpios + - if: + properties: + compatible: + contains: + const: aspeed,ast2700-gpio + then: + properties: + gpio-line-names: + minItems: 12 + maxItems: 216 + ngpios: + enum: [ 12, 216 ] + required: + - ngpios additionalProperties: false diff --git a/Documentation/devicetree/bindings/gpio/gpio-mmio.yaml b/Documentation/devicetree/bindings/gpio/gpio-mmio.yaml index b394e058256e0d..87e986386f32a4 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mmio.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-mmio.yaml @@ -37,7 +37,8 @@ properties: description: A list of registers in the controller. The width of each register is determined by its size. All registers must have the same width. The number - of GPIOs is set by the width, with bit 0 corresponding to GPIO 0. + of GPIOs is set by the width, with bit 0 corresponding to GPIO 0, unless + the ngpios property further restricts the number of used lines. items: - description: Register to READ the value of the GPIO lines. If GPIO line is high, @@ -74,6 +75,15 @@ properties: native-endian: true + ngpios: + minimum: 1 + maximum: 63 + description: + If this property is present the number of usable GPIO lines are restricted + to the first 0 .. ngpios lines. This is useful when the GPIO MMIO register + has 32 bits for GPIO but only the first 12 are actually connected to + real electronics, and then we set ngpios to 12. + no-output: $ref: /schemas/types.yaml#/definitions/flag description: @@ -111,6 +121,7 @@ examples: compatible = "brcm,bcm6345-gpio"; reg-names = "dirout", "dat"; reg = <0xfffe0406 2>, <0xfffe040a 2>; + ngpios = <15>; native-endian; gpio-controller; #gpio-cells = <2>; diff --git a/Documentation/devicetree/bindings/gpio/st,nomadik-gpio.yaml b/Documentation/devicetree/bindings/gpio/st,nomadik-gpio.yaml index 38d37d8f7201b1..b3e8951959b52e 100644 --- a/Documentation/devicetree/bindings/gpio/st,nomadik-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/st,nomadik-gpio.yaml @@ -89,6 +89,7 @@ examples: interrupts = <0 120 0x4>; #gpio-cells = <2>; gpio-controller; + #interrupt-cells = <2>; interrupt-controller; st,supports-sleepmode; gpio-bank = <1>; diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml index 278399adc55069..735c7f06c24e63 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml @@ -26,6 +26,7 @@ properties: - renesas,r9a07g054-mali - rockchip,px30-mali - rockchip,rk3568-mali + - rockchip,rk3576-mali - const: arm,mali-bifrost # Mali Bifrost GPU model/revision is fully discoverable - items: - enum: diff --git a/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml index 780ccb5ee9b466..385aac7161a0db 100644 --- a/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml +++ b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml @@ -23,6 +23,9 @@ properties: - items: - enum: - samsung,exynos7885-chipid + - samsung,exynos8895-chipid + - samsung,exynos9810-chipid + - samsung,exynos990-chipid - samsung,exynosautov9-chipid - samsung,exynosautov920-chipid - const: samsung,exynos850-chipid diff --git a/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml b/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml index 1f98da32f3feb9..37e1dc9c7dd379 100644 --- a/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml +++ b/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml @@ -26,6 +26,7 @@ properties: - lltc,ltc3886 - lltc,ltc3887 - lltc,ltc3889 + - lltc,ltc7841 - lltc,ltc7880 - lltc,ltm2987 - lltc,ltm4664 @@ -50,6 +51,7 @@ properties: * ltc2977, ltc2979, ltc2980, ltm2987 : vout0 - vout7 * ltc2978 : vout0 - vout7 * ltc3880, ltc3882, ltc3884, ltc3886, ltc3887, ltc3889 : vout0 - vout1 + * ltc7841 : vout0 * ltc7880 : vout0 - vout1 * ltc3883 : vout0 * ltm4664 : vout0 - vout1 diff --git a/Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml b/Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml new file mode 100644 index 00000000000000..c1e5dedc2f6aad --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/nuvoton,nct7363.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton NCT7363Y Hardware Monitoring IC + +maintainers: + - Ban Feng + +description: | + The NCT7363Y is a fan controller which provides up to 16 independent + FAN input monitors, and up to 16 independent PWM outputs with SMBus interface. + + Datasheets: Available from Nuvoton upon request + +properties: + compatible: + enum: + - nuvoton,nct7363 + - nuvoton,nct7362 + + reg: + maxItems: 1 + + "#pwm-cells": + const: 2 + +patternProperties: + "^fan-[0-9]+$": + $ref: fan-common.yaml# + unevaluatedProperties: false + required: + - pwms + - tach-ch + +required: + - compatible + - reg + - "#pwm-cells" + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hwmon: hwmon@22 { + compatible = "nuvoton,nct7363"; + reg = <0x22>; + #pwm-cells = <2>; + + fan-0 { + pwms = <&hwmon 0 50000>; + tach-ch = /bits/ 8 <0x00>; + }; + fan-1 { + pwms = <&hwmon 1 50000>; + tach-ch = /bits/ 8 <0x01>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml new file mode 100644 index 00000000000000..bac5f8e352aa46 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml @@ -0,0 +1,148 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/pmbus/isil,isl68137.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas Digital Multiphase Voltage Regulators with PMBus + +maintainers: + - Grant Peltier + +description: | + Renesas digital multiphase voltage regulators with PMBus. + https://www.renesas.com/en/products/power-management/multiphase-power/multiphase-dcdc-switching-controllers + +properties: + compatible: + enum: + - isil,isl68137 + - renesas,isl68220 + - renesas,isl68221 + - renesas,isl68222 + - renesas,isl68223 + - renesas,isl68224 + - renesas,isl68225 + - renesas,isl68226 + - renesas,isl68227 + - renesas,isl68229 + - renesas,isl68233 + - renesas,isl68239 + - renesas,isl69222 + - renesas,isl69223 + - renesas,isl69224 + - renesas,isl69225 + - renesas,isl69227 + - renesas,isl69228 + - renesas,isl69234 + - renesas,isl69236 + - renesas,isl69239 + - renesas,isl69242 + - renesas,isl69243 + - renesas,isl69247 + - renesas,isl69248 + - renesas,isl69254 + - renesas,isl69255 + - renesas,isl69256 + - renesas,isl69259 + - isil,isl69260 + - renesas,isl69268 + - isil,isl69269 + - renesas,isl69298 + - renesas,raa228000 + - renesas,raa228004 + - renesas,raa228006 + - renesas,raa228228 + - renesas,raa229001 + - renesas,raa229004 + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^channel@([0-3])$": + type: object + description: + Container for properties specific to a particular channel (rail). + + properties: + reg: + description: The channel (rail) index. + items: + minimum: 0 + maximum: 3 + + vout-voltage-divider: + description: | + Resistances of a voltage divider placed between Vout and the voltage + sense (Vsense) pin for the given channel (rail). It has two numbers + representing the resistances of the voltage divider provided as + which yields an adjusted Vout as + Vout_adj = Vout * Rtotal / Rout given the original Vout as reported + by the Vsense pin. Given a circuit configuration similar to the one + below, Rtotal = R1 + Rout. + + Vout ----. + | + .-----. + | R1 | + '-----' + | + +---- Vsense + | + .-----. + | Rout| + '-----' + | + GND + + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 2 + + required: + - reg + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + isl68239@60 { + compatible = "isil,isl68137"; + reg = <0x60>; + }; + }; + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + isl68239@60 { + compatible = "renesas,isl68239"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + vout-voltage-divider = <1000 2000>; // Reported Vout/Pout would be scaled by 2 + }; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/mps,mp2975.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/mps,mp2975.yaml new file mode 100644 index 00000000000000..f7bc4f077929d0 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/mps,mp2975.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/pmbus/mps,mp2975.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MPS MP2975 Synchronous Buck Regulator + +maintainers: + - Naresh Solanki + +description: + The MPS MP2971, MP2973 & MP2975 is a multi-phase voltage regulator + designed for use in high-performance computing and server + applications. It supports I2C/PMBus for control and monitoring. + +properties: + compatible: + enum: + - mps,mp2971 + - mps,mp2973 + - mps,mp2975 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + regulators: + type: object + description: + List of regulators provided by this controller. + + patternProperties: + "^vout[0-1]$": + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@58 { + compatible = "mps,mp2973"; + reg = <0x58>; + + interrupt-parent = <&smb_pex_cpu1_event>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + + regulators { + vout0 { + regulator-name = "pvccin_cpu1"; + regulator-enable-ramp-delay = <200>; + }; + vout1 { + regulator-name = "pvccfa_ehv_fivra_cpu1"; + regulator-enable-ramp-delay = <200>; + }; + }; + }; + }; + diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml new file mode 100644 index 00000000000000..f4115870e45094 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/pmbus/ti,tps25990.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TPS25990 Stackable eFuse + +maintainers: + - Jerome Brunet + +description: + The TI TPS25990 is an integrated, high-current circuit + protection and power management device with PMBUS interface + +properties: + compatible: + const: ti,tps25990 + + reg: + maxItems: 1 + + ti,rimon-micro-ohms: + description: + micro Ohms value of the resistance installed between the Imon pin + and the ground reference. + + interrupts: + description: PMBUS SMB Alert Interrupt. + maxItems: 1 + + regulators: + type: object + description: + list of regulators provided by this controller. + + properties: + vout: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + gpdac1: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + gpdac2: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + additionalProperties: false + +required: + - compatible + - reg + - ti,rimon-micro-ohms + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hw-monitor@46 { + compatible = "ti,tps25990"; + reg = <0x46>; + + interrupt-parent = <&gpio>; + interrupts = <42 IRQ_TYPE_LEVEL_LOW>; + ti,rimon-micro-ohms = <1370000000>; + + regulators { + cpu0_vout: vout { + regulator-name = "main_cpu0"; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/vicor,pli1209bc.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/vicor,pli1209bc.yaml new file mode 100644 index 00000000000000..4aa62d67e1a959 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/vicor,pli1209bc.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/pmbus/vicor,pli1209bc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Vicor PLI1209BC Power Regulator + +maintainers: + - Marcello Sylvester Bauer + - Naresh Solanki + +description: + The Vicor PLI1209BC is a Digital Supervisor with Isolation for use + with BCM Bus Converter Modules. + +properties: + compatible: + enum: + - vicor,pli1209bc + + reg: + maxItems: 1 + + regulators: + type: object + description: + List of regulators provided by this controller. + + properties: + vout2: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + regulator@5f { + compatible = "vicor,pli1209bc"; + reg = <0x5f>; + + regulators { + p12v_d: vout2 { + regulator-name = "bcm3"; + regulator-boot-on; + }; + }; + }; + }; + diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml index 4e5abf7580cc66..8b4ed5ee962fb5 100644 --- a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml +++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml @@ -31,6 +31,16 @@ properties: it must be self resetting edge interrupts. maxItems: 1 + fan-stop-to-start-percent: + description: + Minimum fan RPM in percent to start when stopped. + minimum: 0 + maximum: 100 + + fan-stop-to-start-us: + description: + Time to wait in microseconds after start when stopped. + pulses-per-revolution: description: Define the number of pulses per fan revolution for each tachometer diff --git a/Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml b/Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml new file mode 100644 index 00000000000000..dd82a80e411544 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/renesas,isl28022.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas ISL28022 power monitor + +maintainers: + - Carsten Spieß + +description: | + The ISL28022 is a power monitor with I2C interface. The device monitors + voltage, current via shunt resistor and calculated power. + + Datasheets: + https://www.renesas.com/us/en/www/doc/datasheet/isl28022.pdf + +properties: + compatible: + const: renesas,isl28022 + + reg: + maxItems: 1 + + shunt-resistor-micro-ohms: + description: + Shunt resistor value in micro-Ohm + minimum: 800 + default: 10000 + + renesas,shunt-range-microvolt: + description: + Maximal shunt voltage range of +/- 40 mV, 80 mV, 160 mV or 320 mV + default: 320000 + enum: [40000, 80000, 160000, 320000] + + renesas,average-samples: + description: + Number of samples to be used to report voltage, current and power values. + default: 1 + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 4, 8, 16, 32, 64, 128] + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + power-monitor@40 { + compatible = "renesas,isl28022"; + reg = <0x40>; + shunt-resistor-micro-ohms = <8000>; + renesas,shunt-range-microvolt = <40000>; + renesas,average-samples = <128>; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml b/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml new file mode 100644 index 00000000000000..5d33f1a23d0325 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/ti,amc6821.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AMC6821 Intelligent Temperature Monitor and PWM Fan Controller + +maintainers: + - Farouk Bouabid + - Quentin Schulz + +description: + Intelligent temperature monitor and pulse-width modulation (PWM) fan + controller. + +properties: + compatible: + oneOf: + - items: + - const: tsd,mule + - const: ti,amc6821 + - const: ti,amc6821 + + reg: + maxItems: 1 + + i2c-mux: + type: object + +required: + - compatible + - reg + +if: + properties: + compatible: + contains: + const: tsd,mule + +then: + required: + - i2c-mux + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + fan@18 { + compatible = "ti,amc6821"; + reg = <0x18>; + }; + }; + + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + fan@18 { + compatible = "tsd,mule", "ti,amc6821"; + reg = <0x18>; + + i2c-mux { + compatible = "tsd,mule-i2c-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@6f { + compatible = "isil,isl1208"; + reg = <0x6f>; + }; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml index 6ae961732e6b5b..05a9cb36cd8287 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml @@ -20,6 +20,7 @@ description: | properties: compatible: enum: + - silergy,sy24655 - ti,ina209 - ti,ina219 - ti,ina220 diff --git a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml index 0ad10d43fac0c9..a6f9319e068d4e 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml @@ -4,22 +4,26 @@ $id: http://devicetree.org/schemas/hwmon/ti,tmp108.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: TMP108 temperature sensor +title: TMP108/P3T1085(NXP) temperature sensor maintainers: - Krzysztof Kozlowski description: | - The TMP108 is a digital-output temperature sensor with a + The TMP108/P3T1085(NXP) is a digital-output temperature sensor with a dynamically-programmable limit window, and under- and overtemperature alert functions. + P3T1085(NXP) support I3C. + Datasheets: https://www.ti.com/product/TMP108 + https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf properties: compatible: enum: + - nxp,p3t1085 - ti,tmp108 interrupts: diff --git a/Documentation/devicetree/bindings/i2c/i2c-imx.yaml b/Documentation/devicetree/bindings/i2c/i2c-imx.yaml index 85ee1282d6d2d2..0682a5a10d41c4 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-imx.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-imx.yaml @@ -18,6 +18,7 @@ properties: - const: fsl,imx1-i2c - const: fsl,imx21-i2c - const: fsl,vf610-i2c + - const: nxp,s32g2-i2c - items: - enum: - fsl,ls1012a-i2c @@ -54,6 +55,9 @@ properties: - fsl,imx8mn-i2c - fsl,imx8mp-i2c - const: fsl,imx21-i2c + - items: + - const: nxp,s32g3-i2c + - const: nxp,s32g2-i2c reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml index 984fc1ed3ec6ae..c4efcef591337b 100644 --- a/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml @@ -33,6 +33,7 @@ properties: - allwinner,sun50i-a100-i2c - allwinner,sun50i-h616-i2c - allwinner,sun50i-r329-i2c + - allwinner,sun55i-a523-i2c - const: allwinner,sun8i-v536-i2c - const: allwinner,sun6i-a31-i2c - const: marvell,mv64xxx-i2c diff --git a/Documentation/devicetree/bindings/i2c/microchip,corei2c.yaml b/Documentation/devicetree/bindings/i2c/microchip,corei2c.yaml index afa3db7262298e..6ff58b64d49627 100644 --- a/Documentation/devicetree/bindings/i2c/microchip,corei2c.yaml +++ b/Documentation/devicetree/bindings/i2c/microchip,corei2c.yaml @@ -16,7 +16,9 @@ properties: compatible: oneOf: - items: - - const: microchip,mpfs-i2c # Microchip PolarFire SoC compatible SoCs + - enum: + - microchip,pic64gx-i2c + - microchip,mpfs-i2c # Microchip PolarFire SoC compatible SoCs - const: microchip,corei2c-rtl-v7 # Microchip Fabric based i2c IP core - const: microchip,corei2c-rtl-v7 # Microchip Fabric based i2c IP core diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml index 7dab3852c7f87f..ef26ba6eda28e9 100644 --- a/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml +++ b/Documentation/devicetree/bindings/i2c/qcom,i2c-cci.yaml @@ -27,6 +27,7 @@ properties: - enum: - qcom,sc7280-cci - qcom,sc8280xp-cci + - qcom,sdm670-cci - qcom,sdm845-cci - qcom,sm6350-cci - qcom,sm8250-cci @@ -139,6 +140,24 @@ allOf: - const: cci - const: camss_ahb + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm670-cci + then: + properties: + clocks: + minItems: 4 + maxItems: 4 + clock-names: + items: + - const: camnoc_axi + - const: soc_ahb + - const: cpas_ahb + - const: cci + - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml new file mode 100644 index 00000000000000..eddfd329c67b74 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/i2c/realtek,rtl9301-i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek RTL I2C Controller + +maintainers: + - Chris Packham + +description: + The RTL9300 SoC has two I2C controllers. Each of these has an SCL line (which + if not-used for SCL can be a GPIO). There are 8 common SDA lines that can be + assigned to either I2C controller. + +properties: + compatible: + oneOf: + - items: + - enum: + - realtek,rtl9302b-i2c + - realtek,rtl9302c-i2c + - realtek,rtl9303-i2c + - const: realtek,rtl9301-i2c + - const: realtek,rtl9301-i2c + + reg: + description: Register offset and size this I2C controller. + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + '^i2c@[0-7]$': + $ref: /schemas/i2c/i2c-controller.yaml + unevaluatedProperties: false + + properties: + reg: + description: The SDA pin associated with the I2C bus. + maxItems: 1 + + required: + - reg + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c@36c { + compatible = "realtek,rtl9301-i2c"; + reg = <0x36c 0x14>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml b/Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml index 60035a787e5c06..e5d05263c45a57 100644 --- a/Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/snps,designware-i2c.yaml @@ -97,6 +97,22 @@ properties: - const: tx - const: rx + snps,bus-capacitance-pf: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + This property indicates the bus capacitance in picofarads (pF). + This value is used to compute the tHIGH and tLOW periods for high speed + mode. + enum: [100, 400] + default: 100 + + snps,clk-freq-optimized: + description: + This property indicates whether the hardware reduce its clock frequency + by reducing the internal latency required to generate the high period and + low period of SCL line. + type: boolean + unevaluatedProperties: false required: @@ -121,6 +137,8 @@ examples: i2c-sda-hold-time-ns = <300>; i2c-sda-falling-time-ns = <300>; i2c-scl-falling-time-ns = <300>; + snps,bus-capacitance-pf = <400>; + snps,clk-freq-optimized; }; - | i2c@2000 { diff --git a/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml b/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml index 44c54b162bb107..012402debfeb24 100644 --- a/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/st,nomadik-i2c.yaml @@ -22,6 +22,7 @@ select: enum: - st,nomadik-i2c - mobileye,eyeq5-i2c + - mobileye,eyeq6h-i2c required: - compatible @@ -29,15 +30,15 @@ properties: compatible: oneOf: - items: - - const: st,nomadik-i2c + - enum: + - st,nomadik-i2c + - mobileye,eyeq5-i2c + - mobileye,eyeq6h-i2c - const: arm,primecell - items: - const: stericsson,db8500-i2c - const: st,nomadik-i2c - const: arm,primecell - - items: - - const: mobileye,eyeq5-i2c - - const: arm,primecell reg: maxItems: 1 @@ -54,7 +55,7 @@ properties: - items: - const: mclk - const: apb_pclk - # Clock name in DB8500 or EyeQ5 + # Clock name in DB8500 or EyeQ - items: - const: i2cclk - const: apb_pclk @@ -67,7 +68,7 @@ properties: clock-frequency: minimum: 1 - maximum: 400000 + maximum: 3400000 mobileye,olb: $ref: /schemas/types.yaml#/definitions/phandle-array diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml index 8e7835cf36fd23..b9bc02b5b07a4c 100644 --- a/Documentation/devicetree/bindings/iio/adc/adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml @@ -37,6 +37,10 @@ properties: to both the positive and negative inputs of a differential ADC. The first value specifies the positive input pin, the second specifies the negative input pin. + There are also some ADCs, where the differential channel has dedicated + positive and negative inputs which can be used to measure differential + voltage levels. For those setups, this property can be configured with + the 'reg' property for both inputs (i.e. diff-channels = ). single-channel: $ref: /schemas/types.yaml#/definitions/uint32 diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml index 17c5d39cc2c17d..ad15cf9bc2ffd1 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7173.yaml @@ -28,6 +28,7 @@ description: | Datasheets for supported chips: https://www.analog.com/media/en/technical-documentation/data-sheets/AD4111.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD4112.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/AD4114.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD4115.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD4116.pdf @@ -44,6 +45,7 @@ properties: enum: - adi,ad4111 - adi,ad4112 + - adi,ad4113 - adi,ad4114 - adi,ad4115 - adi,ad4116 @@ -331,6 +333,7 @@ allOf: enum: - adi,ad4111 - adi,ad4112 + - adi,ad4113 - adi,ad4114 - adi,ad4115 - adi,ad4116 diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml index 0065d650882489..ada08005b3cd1c 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7380.yaml @@ -25,6 +25,8 @@ description: | * https://www.analog.com/en/products/ad7386-4.html * https://www.analog.com/en/products/ad7387-4.html * https://www.analog.com/en/products/ad7388-4.html + * https://www.analog.com/en/products/adaq4370-4.html + * https://www.analog.com/en/products/adaq4380-4.html $ref: /schemas/spi/spi-peripheral-props.yaml# @@ -46,6 +48,8 @@ properties: - adi,ad7386-4 - adi,ad7387-4 - adi,ad7388-4 + - adi,adaq4370-4 + - adi,adaq4380-4 reg: maxItems: 1 @@ -70,6 +74,20 @@ properties: refin-supply: description: A 2.5V to 3.3V supply for external reference voltage, for ad7380-4 only. + For adaq devices, a 5V supply voltage. A 3.3V internal reference is + derived from it. Connect to vs-p-supply for normal operation. + + vs-p-supply: + description: + Amplifiers positive supply. + + vs-n-supply: + description: + Amplifiers negative supply. + + ldo-supply: + description: + LDO supply. Connect to vs-p-supply or a 3.6 to 5.5 V supply. aina-supply: description: @@ -97,12 +115,45 @@ properties: specify the ALERT interrupt. maxItems: 1 + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + required: - compatible - reg - vcc-supply - vlogic-supply +patternProperties: + "^channel@[0-3]$": + $ref: adc.yaml + type: object + + properties: + reg: + description: + The channel number. From 0 to 3 corresponding to channels A,B,C,D + minimum: 0 + maximum: 3 + + adi,gain-milli: + description: + The hardware gain applied to the ADC input (in milli units). + If not present, default to 1000 (no actual gain applied). + Refer to the typical connection diagrams section of the datasheet for + pin wiring. + $ref: /schemas/types.yaml#/definitions/uint16 + enum: [300, 600, 1000, 1600] + default: 1000 + + required: + - reg + + additionalProperties: false + unevaluatedProperties: false allOf: @@ -140,6 +191,7 @@ allOf: aind-supply: false # ad7380-4 uses refin-supply as external reference. + # adaq devices use internal reference only, derived from refin-supply # All other chips from ad738x family use refio as optional external reference. # When refio-supply is omitted, internal reference is used. - if: @@ -147,6 +199,8 @@ allOf: compatible: enum: - adi,ad7380-4 + - adi,adaq4370-4 + - adi,adaq4380-4 then: properties: refio-supply: false @@ -156,6 +210,27 @@ allOf: properties: refin-supply: false + # adaq devices need more supplies and using channel to declare gain property + # only applies to adaq devices + - if: + properties: + compatible: + enum: + - adi,adaq4370-4 + - adi,adaq4380-4 + then: + required: + - vs-p-supply + - vs-n-supply + - ldo-supply + else: + properties: + vs-p-supply: false + vs-n-supply: false + ldo-supply: false + patternProperties: + "^channel@[0-3]$": false + examples: - | #include @@ -180,3 +255,48 @@ examples: refio-supply = <&supply_2_5V>; }; }; + + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,adaq4380-4"; + reg = <0>; + + spi-cpol; + spi-cpha; + spi-max-frequency = <80000000>; + + interrupts = <27 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + vcc-supply = <&supply_3_3V>; + vlogic-supply = <&supply_3_3V>; + refin-supply = <&supply_5V>; + vs-p-supply = <&supply_5V>; + vs-n-supply = <&supply_0V>; + ldo-supply = <&supply_5V>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + adi,gain-milli = /bits/ 16 <300>; + }; + + channel@2 { + reg = <2>; + adi,gain-milli = /bits/ 16 <600>; + }; + + channel@3 { + reg = <3>; + adi,gain-milli = /bits/ 16 <1000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml index 69408cae3db960..ab5881d0d017f5 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml @@ -14,6 +14,11 @@ description: | https://www.analog.com/media/en/technical-documentation/data-sheets/AD7605-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606_7606-6_7606-4.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7606B.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606c-16.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7606c-18.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7607.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7608.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7609.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/AD7616.pdf properties: @@ -24,11 +29,27 @@ properties: - adi,ad7606-6 - adi,ad7606-8 # Referred to as AD7606 (without -8) in the datasheet - adi,ad7606b + - adi,ad7606c-16 + - adi,ad7606c-18 + - adi,ad7607 + - adi,ad7608 + - adi,ad7609 - adi,ad7616 reg: maxItems: 1 + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + # According to the datasheet, "Data is clocked in from SDI on the falling + # edge of SCLK, while data is clocked out on DOUTA on the rising edge of + # SCLK". Also, even if not stated textually in the datasheet, it is made + # clear on the diagrams that sclk idles at high. Subsequently, in case SPI + # interface is used, the correct way is to only set spi-cpol. spi-cpha: true spi-cpol: true @@ -114,18 +135,91 @@ properties: assumed that the pins are hardwired to VDD. type: boolean + pwms: + description: + In case the conversion is triggered by a PWM instead of a GPIO plugged to + the CONVST pin, the PWM must be referenced. + The first is the PWM connected to CONVST or CONVST1 for the chips with the + 2nd PWM connected to CONVST2, if CONVST2 is available and not shorted to + CONVST1. + minItems: 1 + maxItems: 2 + + pwm-names: + items: + - const: convst1 + - const: convst2 + + io-backends: + description: + A reference to the iio-backend, which is responsible handling the BUSY + pin's falling edge and communication. + An example of backend can be found at + http://analogdevicesinc.github.io/hdl/library/axi_ad7606x/index.html + + +patternProperties: + "^channel@[1-8]$": + type: object + $ref: adc.yaml + unevaluatedProperties: false + + properties: + reg: + description: + The channel number, as specified in the datasheet (from 1 to 8). + minimum: 1 + maximum: 8 + + diff-channels: + description: + Each channel can be configured as a bipolar differential channel. + The ADC uses the same positive and negative inputs for this. + This property must be specified as 'reg' (or the channel number) for + both positive and negative inputs (i.e. diff-channels = ). + Since the configuration is bipolar differential, the 'bipolar' + property is required. + items: + minimum: 1 + maximum: 8 + + bipolar: + description: + The ADC channels can be configured as + * Bipolar single-ended + * Unipolar single-ended + * Bipolar differential + Therefore in the DT, if no channel node is specified, it is considered + 'unipolar single-ended'. So for the other configurations the 'bipolar' + property must be specified. If 'diff-channels' is specified, it is + considered a bipolar differential channel. Otherwise it is bipolar + single-ended. + + required: + - reg + - bipolar + required: - compatible - reg - - spi-cpha - avcc-supply - vdrive-supply - - interrupts - - adi,conversion-start-gpios allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# + - oneOf: + - required: + - adi,conversion-start-gpios + - required: + - pwms + + - oneOf: + - required: + - interrupts + - required: + - io-backends + - if: properties: compatible: @@ -162,17 +256,66 @@ allOf: - adi,ad7606-4 - adi,ad7606-6 - adi,ad7606-8 + - adi,ad7607 + - adi,ad7608 + - adi,ad7609 then: properties: adi,sw-mode: false else: properties: + pwms: + maxItems: 1 + pwm-names: + maxItems: 1 adi,conversion-start-gpios: maxItems: 1 + - if: + not: + required: + - adi,sw-mode + then: + patternProperties: + "^channel@[1-8]$": false + + - if: + not: + properties: + compatible: + enum: + - adi,ad7606c-16 + - adi,ad7606c-18 + then: + patternProperties: + "^channel@[1-8]$": false + unevaluatedProperties: false examples: + - | + #include + iio-backend { + #address-cells = <1>; + #size-cells = <0>; + adi_adc@0 { + compatible = "adi,ad7606b"; + reg = <0>; + pwms = <&axi_pwm_gen 0 0>; + + avcc-supply = <&adc_vref>; + vdrive-supply = <&vdd_supply>; + + reset-gpios = <&gpio0 91 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpio0 90 GPIO_ACTIVE_LOW>; + adi,range-gpios = <&gpio0 89 GPIO_ACTIVE_HIGH>; + adi,oversampling-ratio-gpios = <&gpio0 88 GPIO_ACTIVE_HIGH + &gpio0 87 GPIO_ACTIVE_HIGH + &gpio0 86 GPIO_ACTIVE_HIGH>; + io-backends = <&iio_backend>; + }; + }; + - | #include #include @@ -185,7 +328,6 @@ examples: reg = <0>; spi-max-frequency = <1000000>; spi-cpol; - spi-cpha; avcc-supply = <&adc_vref>; vdrive-supply = <&vdd_supply>; @@ -202,4 +344,53 @@ examples: standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; }; }; + - | + #include + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7606c-18"; + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + spi-max-frequency = <1000000>; + spi-cpol; + + avcc-supply = <&adc_vref>; + vdrive-supply = <&vdd_supply>; + + interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio>; + + adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>; + adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; + standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>; + + adi,sw-mode; + + channel@1 { + reg = <1>; + diff-channels = <1 1>; + bipolar; + }; + + channel@3 { + reg = <3>; + bipolar; + }; + + channel@8 { + reg = <8>; + diff-channels = <8 8>; + bipolar; + }; + + }; + }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7625.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7625.yaml new file mode 100644 index 00000000000000..8848562af28f20 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7625.yaml @@ -0,0 +1,176 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7625.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices Fast PulSAR Analog to Digital Converters + +maintainers: + - Michael Hennerich + - Nuno Sá + +description: | + A family of single channel differential analog to digital converters. + + * https://www.analog.com/en/products/ad7625.html + * https://www.analog.com/en/products/ad7626.html + * https://www.analog.com/en/products/ad7960.html + * https://www.analog.com/en/products/ad7961.html + +properties: + compatible: + enum: + - adi,ad7625 + - adi,ad7626 + - adi,ad7960 + - adi,ad7961 + + vdd1-supply: true + vdd2-supply: true + vio-supply: true + + ref-supply: + description: + Voltage regulator for the external reference voltage (REF). + + refin-supply: + description: + Voltage regulator for the reference buffer input (REFIN). + + clocks: + description: + The clock connected to the CLK pins, gated by the clk_gate PWM. + maxItems: 1 + + pwms: + items: + - description: PWM connected to the CNV input on the ADC. + - description: PWM that gates the clock connected to the ADC's CLK input. + + pwm-names: + items: + - const: cnv + - const: clk_gate + + io-backends: + description: + The AXI ADC IP block connected to the D+/- and DCO+/- lines of the + ADC. An example backend can be found at + http://analogdevicesinc.github.io/hdl/projects/pulsar_lvds/index.html. + maxItems: 1 + + adi,no-dco: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicates the wiring of the DCO+/- lines. If true, then they are + grounded and the device is in self-clocked mode. If this is not + present, then the device is in echoed clock mode. + + adi,en0-always-on: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicates if EN0 is hard-wired to the high state. If neither this + nor en0-gpios are present, then EN0 is hard-wired low. + + adi,en1-always-on: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicates if EN1 is hard-wired to the high state. If neither this + nor en1-gpios are present, then EN1 is hard-wired low. + + adi,en2-always-on: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicates if EN2 is hard-wired to the high state. If neither this + nor en2-gpios are present, then EN2 is hard-wired low. + + adi,en3-always-on: + $ref: /schemas/types.yaml#/definitions/flag + description: + Indicates if EN3 is hard-wired to the high state. If neither this + nor en3-gpios are present, then EN3 is hard-wired low. + + en0-gpios: + description: + Configurable EN0 pin. + + en1-gpios: + description: + Configurable EN1 pin. + + en2-gpios: + description: + Configurable EN2 pin. + + en3-gpios: + description: + Configurable EN3 pin. + +required: + - compatible + - vdd1-supply + - vdd2-supply + - vio-supply + - clocks + - pwms + - pwm-names + - io-backends + +allOf: + - if: + required: + - ref-supply + then: + properties: + refin-supply: false + - if: + required: + - refin-supply + then: + properties: + ref-supply: false + - if: + properties: + compatible: + contains: + enum: + - adi,ad7625 + - adi,ad7626 + then: + properties: + en2-gpios: false + en3-gpios: false + adi,en2-always-on: false + adi,en3-always-on: false + + - if: + properties: + compatible: + contains: + enum: + - adi,ad7960 + - adi,ad7961 + then: + # ad796x parts must have one of the two supplies + oneOf: + - required: [ref-supply] + - required: [refin-supply] + +additionalProperties: false + +examples: + - | + #include + adc { + compatible = "adi,ad7625"; + vdd1-supply = <&supply_5V>; + vdd2-supply = <&supply_2_5V>; + vio-supply = <&supply_2_5V>; + io-backends = <&axi_adc>; + clocks = <&ref_clk>; + pwms = <&axi_pwm_gen 0 0>, <&axi_pwm_gen 1 0>; + pwm-names = "cnv", "clk_gate"; + en0-gpios = <&gpio0 86 GPIO_ACTIVE_HIGH>; + en1-gpios = <&gpio0 87 GPIO_ACTIVE_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml new file mode 100644 index 00000000000000..044f92f39cfa76 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7779.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/adi,ad7779.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD777X family 8-Channel, 24-Bit, Simultaneous Sampling ADCs + +maintainers: + - Ramona Nechita + +description: | + The AD777X family consist of 8-channel, simultaneous sampling analog-to- + digital converter (ADC). Eight full Σ-Δ ADCs are on-chip. The + AD7771 provides an ultralow input current to allow direct sensor + connection. Each input channel has a programmable gain stage + allowing gains of 1, 2, 4, and 8 to map lower amplitude sensor + outputs into the full-scale ADC input range, maximizing the + dynamic range of the signal chain. + + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7770.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7771.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/ad7779.pdf + +$ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - adi,ad7770 + - adi,ad7771 + - adi,ad7779 + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + clocks: + maxItems: 1 + + avdd1-supply: + description: Front-End analog supply AVDD1. Can be used as conversion ref. + + avdd2-supply: + description: AVDD2 Analog Supply from 2.2 V to 3.6 V. + + avdd4-supply: + description: AVDD4 SAR Analog Supply and Reference Source. + + interrupts: + minItems: 1 + items: + - description: | + adc_rdy: Interrupt line for DRDY signal which indicates the end of + conversion independently of the interface selected to read back the + Σ-∆ conversion. + - description: | + Alert: The chip includes self diagnostic features to guarantee the + correct operation. If an error is detected, the ALERT pin is pulled + high to generate an external interruption to the controller. + + interrupt-names: + minItems: 1 + maxItems: 2 + items: + enum: + - adc_rdy + - alert + + start-gpios: + description: + Pin that controls start synchronization pulse. + maxItems: 1 + + reset-gpios: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7779"; + reg = <0>; + start-gpios = <&gpio0 87 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio0 93 GPIO_ACTIVE_LOW>; + interrupt-parent = <&intc>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "adc_rdy"; + clocks = <&adc_clk>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml index f748f3a60b3528..b0962a4583ac71 100644 --- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.yaml @@ -98,6 +98,7 @@ allOf: compatible: contains: enum: + - amlogic,meson8-saradc - amlogic,meson8b-saradc - amlogic,meson8m2-saradc then: diff --git a/Documentation/devicetree/bindings/iio/adc/gehc,pmc-adc.yaml b/Documentation/devicetree/bindings/iio/adc/gehc,pmc-adc.yaml new file mode 100644 index 00000000000000..2cea7c104a269c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/gehc,pmc-adc.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/gehc,pmc-adc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GE HealthCare PMC Analog to Digital Converter (ADC) + +maintainers: + - Herve Codina + +description: + The GE HealthCare PMC ADC is a 16-Channel (voltage and current), 16-Bit ADC + with an I2C Interface. + +properties: + compatible: + const: gehc,pmc-adc + + reg: + maxItems: 1 + + vdd-supply: + description: + Regulator for the VDD power supply. + + vdda-supply: + description: + Regulator for the VDD analog (VDDA) power supply. + + vddio-supply: + description: + Regulator for the VDD IO (VDDIO) power supply. + + vref-supply: + description: + Regulator for the voltage reference power supply. + + clocks: + maxItems: 1 + description: + The component uses an external oscillator (osc) if an external oscillator + is connected to its clock pins. Otherwise, it uses an internal reference + clock. + + clock-names: + items: + - const: osc + + "#io-channel-cells": + const: 2 + description: | + The first cell is the channel type (dt-bindings/iio/adc/gehc,pmc-adc.h + defines these values): + - 0: voltage + - 1: current + The second cell is the channel number from 0 to 15. + +required: + - compatible + - reg + - vdd-supply + - vdda-supply + - vddio-supply + - vref-supply + - '#io-channel-cells' + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@14 { + compatible = "gehc,pmc-adc"; + reg = <0x14>; + vdd-supply = <®_vdd>; + vdda-supply = <®_vdda>; + vddio-supply = <®_vddio>; + vref-supply = <®_vref>; + #io-channel-cells = <2>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/adc/sprd,sc2720-adc.yaml b/Documentation/devicetree/bindings/iio/adc/sprd,sc2720-adc.yaml index 8181cf9a8e07d4..a678323d78e3b5 100644 --- a/Documentation/devicetree/bindings/iio/adc/sprd,sc2720-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/sprd,sc2720-adc.yaml @@ -80,23 +80,6 @@ required: additionalProperties: false examples: - - | - #include - pmic { - #address-cells = <1>; - #size-cells = <0>; - adc@480 { - compatible = "sprd,sc2731-adc"; - reg = <0x480>; - interrupt-parent = <&sc2731_pmic>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; - #io-channel-cells = <1>; - hwlocks = <&hwlock 4>; - nvmem-cells = <&adc_big_scale>, <&adc_small_scale>; - nvmem-cell-names = "big_scale_calib", "small_scale_calib"; - }; - }; - - | #include pmic { diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml index fc8b97f820775b..2d2561a526838d 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad3552r.yaml @@ -30,7 +30,7 @@ properties: maxItems: 1 spi-max-frequency: - maximum: 30000000 + maximum: 66000000 reset-gpios: maxItems: 1 @@ -60,6 +60,12 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2, 3] + io-backends: + description: The iio backend reference. + Device can be optionally connected to the "axi-ad3552r IP" fpga-based + QSPI + DDR (Double Data Rate) controller to reach high speed transfers. + maxItems: 1 + '#address-cells': const: 1 @@ -128,6 +134,7 @@ patternProperties: - custom-output-range-config allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml index c81285d84db7a2..79cb4b78a88a97 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml @@ -26,16 +26,47 @@ properties: vdd-supply: true vss-supply: true + vcc-supply: + description: + Supply that powers the chip. + + iovcc-supply: + description: + Supply for the digital interface. + + vrefp-supply: + description: + Positive referance input voltage range. From 5v to (vdd - 2.5) + + vrefn-supply: + description: + Negative referance input voltage range. From (vss + 2.5) to 0. + adi,rbuf-gain2-en: description: Specify to allow an external amplifier to be connected in a gain of two configuration. type: boolean + reset-gpios: + maxItems: 1 + + clear-gpios: + maxItems: 1 + + ldac-gpios: + description: + LDAC pin to be used as a hardware trigger to update the DAC channels. + maxItems: 1 + required: - compatible - reg - vdd-supply - vss-supply + - vcc-supply + - iovcc-supply + - vrefp-supply + - vrefn-supply allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# @@ -44,6 +75,7 @@ unevaluatedProperties: false examples: - | + #include spi { #address-cells = <1>; #size-cells = <0>; @@ -53,6 +85,13 @@ examples: reg = <0>; vss-supply = <&dac_vss>; vdd-supply = <&dac_vdd>; + vcc-supply = <&dac_vcc>; + iovcc-supply = <&dac_iovcc>; + vrefp-supply = <&dac_vrefp>; + vrefn-supply = <&dac_vrefn>; + reset-gpios = <&gpio_bd 16 GPIO_ACTIVE_LOW>; + clear-gpios = <&gpio_bd 17 GPIO_ACTIVE_LOW>; + ldac-gpios = <&gpio_bd 18 GPIO_ACTIVE_HIGH>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad8460.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad8460.yaml new file mode 100644 index 00000000000000..b65928024e12fe --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad8460.yaml @@ -0,0 +1,164 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2024 Analog Devices Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/adi,ad8460.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AD8460 DAC + +maintainers: + - Mariel Tinaco + +description: | + Analog Devices AD8460 110 V High Voltage, 1 A High Current, + Arbitrary Waveform Generator with Integrated 14-Bit High Speed DAC + https://www.analog.com/media/en/technical-documentation/data-sheets/ad8460.pdf + +properties: + compatible: + enum: + - adi,ad8460 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + dmas: + maxItems: 1 + + dma-names: + items: + - const: tx + + spi-max-frequency: + maximum: 20000000 + + hvcc-supply: + description: Positive high voltage power supply line + + hvee-supply: + description: Negative high voltage power supply line + + vcc-5v-supply: + description: Low voltage power supply + + vref-5v-supply: + description: Reference voltage for analog low voltage + + dvdd-3p3v-supply: + description: Digital supply bypass + + avdd-3p3v-supply: + description: Analog supply bypass + + refio-1p2v-supply: + description: Drive voltage in the range of 1.2V maximum to as low as + low as 0.12V through the REF_IO pin to adjust full scale output span + + adi,external-resistor-ohms: + description: Specify value of external resistor connected to FS_ADJ pin + to establish internal HVDAC's reference current I_REF + minimum: 2000 + maximum: 20000 + default: 2000 + + adi,range-microvolt: + description: Voltage output range specified as + items: + - minimum: -55000000 + maximum: 0 + default: 0 + - minimum: 0 + maximum: 55000000 + default: 0 + + adi,range-microamp: + description: Current output range specified as + items: + - minimum: -1000000 + maximum: 0 + default: 0 + - minimum: 0 + maximum: 1000000 + default: 0 + + adi,max-millicelsius: + description: Overtemperature threshold + minimum: 0 + maximum: 150000 + default: 0 + + shutdown-reset-gpios: + description: Corresponds to SDN_RESET pin. To exit shutdown + or sleep mode, pulse SDN_RESET HIGH, then leave LOW. + maxItems: 1 + + reset-gpios: + description: Manual Power On Reset (POR). Pull this GPIO pin + LOW and then HIGH to reset all digital registers to default + maxItems: 1 + + shutdown-gpios: + description: Corresponds to SDN_IO pin. Shutdown may be + initiated by the user, by pulsing SDN_IO high. To exit shutdown, + pulse SDN_IO low, then float. + maxItems: 1 + +required: + - compatible + - reg + - clocks + - hvcc-supply + - hvee-supply + - vcc-5v-supply + - vref-5v-supply + - dvdd-3p3v-supply + - avdd-3p3v-supply + - refio-1p2v-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "adi,ad8460"; + reg = <0>; + spi-max-frequency = <8000000>; + + dmas = <&tx_dma 0>; + dma-names = "tx"; + + shutdown-reset-gpios = <&gpio 86 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 91 GPIO_ACTIVE_LOW>; + shutdown-gpios = <&gpio 88 GPIO_ACTIVE_HIGH>; + + clocks = <&sync_ext_clk>; + + hvcc-supply = <&hvcc>; + hvee-supply = <&hvee>; + vcc-5v-supply = <&vcc_5>; + vref-5v-supply = <&vref_5>; + dvdd-3p3v-supply = <&dvdd_3_3>; + avdd-3p3v-supply = <&avdd_3_3>; + refio-1p2v-supply = <&refio_1_2>; + + adi,external-resistor-ohms = <2000>; + adi,range-microvolt = <(-40000000) 40000000>; + adi,range-microamp = <0 50000>; + adi,max-millicelsius = <50000>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml index a55e9bfc66d746..1adba9aceeb113 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,axi-dac.yaml @@ -19,11 +19,13 @@ description: | memory via DMA into the DAC. https://wiki.analog.com/resources/fpga/docs/axi_dac_ip + https://analogdevicesinc.github.io/hdl/library/axi_ad3552r/index.html properties: compatible: enum: - adi,axi-dac-9.1.b + - adi,axi-ad3552r reg: maxItems: 1 @@ -36,7 +38,14 @@ properties: - const: tx clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 + + clock-names: + items: + - const: s_axi_aclk + - const: dac_clk + minItems: 1 '#io-backend-cells': const: 0 @@ -47,7 +56,29 @@ required: - reg - clocks -additionalProperties: false +allOf: + - if: + properties: + compatible: + contains: + const: adi,axi-ad3552r + then: + $ref: /schemas/spi/spi-controller.yaml# + properties: + clocks: + minItems: 2 + clock-names: + minItems: 2 + required: + - clock-names + else: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + +unevaluatedProperties: false examples: - | @@ -57,6 +88,38 @@ examples: dmas = <&tx_dma 0>; dma-names = "tx"; #io-backend-cells = <0>; - clocks = <&axi_clk>; + clocks = <&clkc 15>; + clock-names = "s_axi_aclk"; + }; + + - | + #include + axi_dac: spi@44a70000 { + compatible = "adi,axi-ad3552r"; + reg = <0x44a70000 0x1000>; + dmas = <&dac_tx_dma 0>; + dma-names = "tx"; + #io-backend-cells = <0>; + clocks = <&clkc 15>, <&ref_clk>; + clock-names = "s_axi_aclk", "dac_clk"; + + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "adi,ad3552r"; + reg = <0>; + reset-gpios = <&gpio0 92 GPIO_ACTIVE_HIGH>; + io-backends = <&axi_dac>; + spi-max-frequency = <20000000>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + adi,output-range-microvolt = <(-10000000) (10000000)>; + }; + }; }; ... diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml new file mode 100644 index 00000000000000..7b0cde1c9b0a41 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/bosch,bmi270.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bosch BMI270 6-Axis IMU + +maintainers: + - Alex Lanzano + +description: | + BMI270 is a 6-axis inertial measurement unit that can measure acceleration and + angular velocity. The sensor also supports configurable interrupt events such + as motion, step counter, and wrist motion gestures. The sensor can communicate + I2C or SPI. + https://www.bosch-sensortec.com/products/motion-sensors/imus/bmi270/ + +properties: + compatible: + enum: + - bosch,bmi260 + - bosch,bmi270 + + reg: + maxItems: 1 + + vdd-supply: true + vddio-supply: true + + interrupts: + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + maxItems: 2 + items: + enum: + - INT1 + - INT2 + + drive-open-drain: + description: + set if the specified interrupt pins should be configured as + open drain. If not set, defaults to push-pull. + + mount-matrix: + description: + an optional 3x3 mounting rotation matrix. + +required: + - compatible + - reg + - vdd-supply + - vddio-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + imu@68 { + compatible = "bosch,bmi270"; + reg = <0x68>; + vdd-supply = <&vdd>; + vddio-supply = <&vddio>; + interrupt-parent = <&gpio1>; + interrupts = <16 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT1"; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,smi240.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,smi240.yaml new file mode 100644 index 00000000000000..58f1411728f63c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/bosch,smi240.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/bosch,smi240.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bosch smi240 imu + +maintainers: + - Jianping Shen + +description: + Inertial Measurement Unit with Accelerometer and Gyroscope + with a measurement range of +/-300°/s and up to 16g. + https://www.bosch-semiconductors.com/mems-sensors/highly-automated-driving/smi240/ + +properties: + compatible: + const: bosch,smi240 + + reg: + maxItems: 1 + + vdd-supply: true + vddio-supply: true + +required: + - compatible + - reg + - vdd-supply + - vddio-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + imu@0 { + compatible = "bosch,smi240"; + reg = <0>; + vdd-supply = <&vdd>; + vddio-supply = <&vddio>; + spi-max-frequency = <10000000>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml index 3769f8e8e98cee..7e4492bbd0278a 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: InvenSense ICM-426xx Inertial Measurement Unit maintainers: - - Jean-Baptiste Maneyrol + - Jean-Baptiste Maneyrol description: | 6-axis MotionTracking device that combines a 3-axis gyroscope and a 3-axis diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml index 587ff2bced2ddd..f91954870a44c6 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device maintainers: - - Jean-Baptiste Maneyrol + - Jean-Baptiste Maneyrol description: | These devices support both I2C and SPI bus interfaces. @@ -36,6 +36,11 @@ properties: - items: - const: invensense,icm20608d - const: invensense,icm20608 + - items: + - enum: + - invensense,iam20680hp + - invensense,iam20680ht + - const: invensense,iam20680 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/light/ti,opt3001.yaml b/Documentation/devicetree/bindings/iio/light/ti,opt3001.yaml index 441e9343fc975f..67ca8d08256a52 100644 --- a/Documentation/devicetree/bindings/iio/light/ti,opt3001.yaml +++ b/Documentation/devicetree/bindings/iio/light/ti,opt3001.yaml @@ -15,7 +15,9 @@ description: | properties: compatible: - const: ti,opt3001 + enum: + - ti,opt3001 + - ti,opt3002 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/light/veml6030.yaml b/Documentation/devicetree/bindings/iio/light/veml6030.yaml deleted file mode 100644 index fb19a2d7a84970..00000000000000 --- a/Documentation/devicetree/bindings/iio/light/veml6030.yaml +++ /dev/null @@ -1,64 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/iio/light/veml6030.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: VEML6030 Ambient Light Sensor (ALS) - -maintainers: - - Rishi Gupta - -description: | - Bindings for the ambient light sensor veml6030 from Vishay - Semiconductors over an i2c interface. - - Irrespective of whether interrupt is used or not, application - can get the ALS and White channel reading from IIO raw interface. - - If the interrupts are used, application will receive an IIO event - whenever configured threshold is crossed. - - Specifications about the sensor can be found at: - https://www.vishay.com/docs/84366/veml6030.pdf - -properties: - compatible: - enum: - - vishay,veml6030 - - reg: - description: - I2C address of the device. - enum: - - 0x10 # ADDR pin pulled down - - 0x48 # ADDR pin pulled up - - interrupts: - description: - interrupt mapping for IRQ. Configure with IRQ_TYPE_LEVEL_LOW. - Refer to interrupt-controller/interrupts.txt for generic - interrupt client node bindings. - maxItems: 1 - -required: - - compatible - - reg - -additionalProperties: false - -examples: - - | - #include - - i2c { - #address-cells = <1>; - #size-cells = <0>; - - light-sensor@10 { - compatible = "vishay,veml6030"; - reg = <0x10>; - interrupts = <12 IRQ_TYPE_LEVEL_LOW>; - }; - }; -... diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml new file mode 100644 index 00000000000000..4ea69f1fdd63ae --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: GPL-2.0+ +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/vishay,veml6030.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: VEML3235, VEML6030, VEML6035 and VEML7700 Ambient Light Sensors (ALS) + +maintainers: + - Rishi Gupta + +description: | + Bindings for the ambient light sensors veml6030 and veml6035 from + Vishay Semiconductors over an i2c interface. + + Irrespective of whether interrupt is used or not, application + can get the ALS and White channel reading from IIO raw interface. + + If the interrupts are used, application will receive an IIO event + whenever configured threshold is crossed. + + Specifications about the sensors can be found at: + https://www.vishay.com/docs/80131/veml3235.pdf + https://www.vishay.com/docs/84366/veml6030.pdf + https://www.vishay.com/docs/84889/veml6035.pdf + https://www.vishay.com/docs/84286/veml7700.pdf + +properties: + compatible: + enum: + - vishay,veml3235 + - vishay,veml6030 + - vishay,veml6035 + - vishay,veml7700 + + reg: + maxItems: 1 + + interrupts: + description: + interrupt mapping for IRQ. Configure with IRQ_TYPE_LEVEL_LOW. + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + maxItems: 1 + + vdd-supply: true + +required: + - compatible + - reg + - vdd-supply + +allOf: + - if: + properties: + compatible: + enum: + - vishay,veml6030 + then: + properties: + reg: + enum: + - 0x10 # ADDR pin pulled down + - 0x48 # ADDR pin pulled up + + - if: + properties: + compatible: + enum: + - vishay,veml6035 + then: + properties: + reg: + enum: + - 0x29 + + - if: + properties: + compatible: + enum: + - vishay,veml3235 + - vishay,veml7700 + then: + properties: + reg: + enum: + - 0x10 + interrupts: false + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + light-sensor@10 { + compatible = "vishay,veml6030"; + reg = <0x10>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + vdd-supply = <&vdd>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml index ecf2339e02f65c..d2effccbfb563f 100644 --- a/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml +++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/iio/light/vishay,veml6075.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Vishay VEML6075 UVA/B and VEML6040 RGBW sensors +title: Vishay VEML6070 UVA, VEML6075 UVA/B and VEML6040 RGBW sensors maintainers: - Javier Carrasco @@ -16,11 +16,19 @@ properties: compatible: enum: - vishay,veml6040 + - vishay,veml6070 - vishay,veml6075 reg: maxItems: 1 + vishay,rset-ohms: + description: + Resistor used to select the integration time. + default: 270000 + minimum: 75000 + maximum: 1200000 + vdd-supply: true required: @@ -28,6 +36,17 @@ required: - reg - vdd-supply +allOf: + - if: + properties: + compatible: + enum: + - vishay,veml6040 + - vishay,veml6075 + then: + properties: + vishay,rset-ohms: false + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/iio/magnetometer/allegromicro,als31300.yaml b/Documentation/devicetree/bindings/iio/magnetometer/allegromicro,als31300.yaml new file mode 100644 index 00000000000000..52e3781834ee9d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/allegromicro,als31300.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/magnetometer/allegromicro,als31300.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allegro MicroSystems ALS31300 3-D Linear Hall Effect sensor + +maintainers: + - Neil Armstrong + +properties: + $nodename: + pattern: '^magnetometer@[0-9a-f]+$' + + compatible: + enum: + - allegromicro,als31300-500 # Factory configured at 500 Gauss input range + - allegromicro,als31300-1000 # Factory configured at 1000 Gauss input range + - allegromicro,als31300-2000 # Factory configured at 2000 Gauss input range + + reg: + maxItems: 1 + + vcc-supply: + description: 5.5V supply + + interrupts: + maxItems: 1 + +required: + - compatible + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + magnetometer@61 { + compatible = "allegromicro,als31300-500"; + reg = <0x61>; + vcc-supply = <&hall_vcc>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml index 6fda887ee9d42e..cb201cecfa1a3e 100644 --- a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml @@ -47,15 +47,33 @@ properties: maxItems: 1 interrupts: - description: - interrupt mapping for IRQ (BMP085 only) maxItems: 1 + drive-open-drain: + description: + set if the interrupt pin should be configured as open drain. + If not set, defaults to push-pull configuration. + type: boolean + required: - compatible - vddd-supply - vdda-supply +allOf: + - if: + properties: + compatible: + not: + contains: + enum: + - bosch,bmp085 + - bosch,bmp380 + - bosch,bmp580 + then: + properties: + interrupts: false + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/iio/temperature/ti,tmp006.yaml b/Documentation/devicetree/bindings/iio/temperature/ti,tmp006.yaml index d43002b9bfdc02..590f50ba3a3150 100644 --- a/Documentation/devicetree/bindings/iio/temperature/ti,tmp006.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/ti,tmp006.yaml @@ -23,6 +23,9 @@ properties: vdd-supply: description: provide VDD power to the sensor. + interrupts: + maxItems: 1 + required: - compatible - reg @@ -31,6 +34,7 @@ additionalProperties: false examples: - | + #include i2c { #address-cells = <1>; #size-cells = <0>; @@ -38,5 +42,7 @@ examples: compatible = "ti,tmp006"; reg = <0x40>; vdd-supply = <&ldo4_reg>; + interrupt-parent = <&gpio1>; + interrupts = <4 IRQ_TYPE_EDGE_FALLING>; }; }; diff --git a/Documentation/devicetree/bindings/input/goodix,gt7986u-spifw.yaml b/Documentation/devicetree/bindings/input/goodix,gt7986u-spifw.yaml new file mode 100644 index 00000000000000..92bd0041febaf5 --- /dev/null +++ b/Documentation/devicetree/bindings/input/goodix,gt7986u-spifw.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/goodix,gt7986u-spifw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Goodix GT7986U SPI HID Touchscreen + +maintainers: + - Charles Wang + +description: | + Supports the Goodix GT7986U touchscreen. + This touch controller reports data packaged according to the HID protocol + over the SPI bus, but it is incompatible with Microsoft's HID-over-SPI protocol. + + NOTE: these bindings are distinct from the bindings used with the + GT7986U when the chip is running I2C firmware. This is because there's + not a single device that talks over both I2C and SPI but rather + distinct touchscreens that happen to be built with the same ASIC but + that are distinct products running distinct firmware. + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - goodix,gt7986u-spifw + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + spi-max-frequency: true + +required: + - compatible + - reg + - interrupts + - reset-gpios + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@0 { + compatible = "goodix,gt7986u-spifw"; + reg = <0>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + spi-max-frequency = <10000000>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml index 70567d92c746ef..60f09caa0e4c75 100644 --- a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml +++ b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml @@ -19,7 +19,7 @@ description: | by the PMIC that is defined as a Multi-Function Device (MFD). For MediaTek MT6323/MT6397 PMIC bindings see - Documentation/devicetree/bindings/mfd/mt6397.txt + Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml properties: compatible: @@ -28,6 +28,7 @@ properties: - mediatek,mt6331-keys - mediatek,mt6357-keys - mediatek,mt6358-keys + - mediatek,mt6359-keys - mediatek,mt6397-keys power-off-time-sec: true diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.yaml b/Documentation/devicetree/bindings/input/rotary-encoder.yaml index e315aab7f584f0..f9332bb2343f22 100644 --- a/Documentation/devicetree/bindings/input/rotary-encoder.yaml +++ b/Documentation/devicetree/bindings/input/rotary-encoder.yaml @@ -41,7 +41,7 @@ properties: device, hence no steps need to be passed. rotary-encoder,rollover: - $ref: /schemas/types.yaml#/definitions/int32 + $ref: /schemas/types.yaml#/definitions/flag description: Automatic rollover when the rotary value becomes greater than the specified steps or smaller than 0. For absolute axis only. diff --git a/Documentation/devicetree/bindings/input/touchscreen/novatek,nvt-ts.yaml b/Documentation/devicetree/bindings/input/touchscreen/novatek,nvt-ts.yaml new file mode 100644 index 00000000000000..bd6a60486d1f19 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/novatek,nvt-ts.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/novatek,nvt-ts.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Novatek NVT Touchscreen Controller + +maintainers: + - Hans de Goede + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + enum: + - novatek,nt11205-ts + - novatek,nt36672a-ts + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + vcc-supply: true + iovcc-supply: true + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + touchscreen@1 { + compatible = "novatek,nt36672a-ts"; + reg = <0x01>; + interrupts-extended = <&tlmm 31 IRQ_TYPE_EDGE_RISING>; + reset-gpios = <&tlmm 32 GPIO_ACTIVE_LOW>; + vcc-supply = <&vreg_l22a_2p85>; + iovcc-supply = <&vreg_l14a_1p8>; + pinctrl-0 = <&ts_int_default &ts_reset_default>; + pinctrl-1 = <&ts_int_sleep &ts_reset_sleep>; + pinctrl-names = "default", "sleep"; + touchscreen-size-x = <1080>; + touchscreen-size-y = <2246>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.txt b/Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.txt deleted file mode 100644 index 43ef770dfeb919..00000000000000 --- a/Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.txt +++ /dev/null @@ -1,22 +0,0 @@ -Zodiac Inflight Innovations RAVE Supervisory Processor Power Button Bindings - -RAVE SP input device is a "MFD cell" device corresponding to power -button functionality of RAVE Supervisory Processor. It is expected -that its Device Tree node is specified as a child of the node -corresponding to the parent RAVE SP device (as documented in -Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) - -Required properties: - -- compatible: Should be "zii,rave-sp-pwrbutton" - -Example: - - rave-sp { - compatible = "zii,rave-sp-rdu1"; - current-speed = <38400>; - - pwrbutton { - compatible = "zii,rave-sp-pwrbutton"; - }; - } diff --git a/Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.yaml b/Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.yaml new file mode 100644 index 00000000000000..b26e6fe174f221 --- /dev/null +++ b/Documentation/devicetree/bindings/input/zii,rave-sp-pwrbutton.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/zii,rave-sp-pwrbutton.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zodiac Inflight Innovations RAVE Supervisory Processor Power Button + +maintainers: + - Frank Li + +description: + RAVE SP input device is a "MFD cell" device corresponding to power + button functionality of RAVE Supervisory Processor. It is expected + that its Device Tree node is specified as a child of the node + corresponding to the parent RAVE SP device (as documented in + Documentation/devicetree/bindings/mfd/zii,rave-sp.yaml) + +properties: + compatible: + const: zii,rave-sp-pwrbutton + +required: + - compatible + +allOf: + - $ref: input.yaml + +unevaluatedProperties: false + +examples: + - | + pwrbutton { + compatible = "zii,rave-sp-pwrbutton"; + }; + diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml index 189f5900ee50d6..251410aabf38be 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml @@ -26,6 +26,7 @@ properties: - items: - enum: - qcom,qcm2290-cpu-bwmon + - qcom,qcs8300-cpu-bwmon - qcom,sa8775p-cpu-bwmon - qcom,sc7180-cpu-bwmon - qcom,sc7280-cpu-bwmon @@ -40,6 +41,7 @@ properties: - const: qcom,sdm845-bwmon # BWMON v4, unified register space - items: - enum: + - qcom,qcs8300-llcc-bwmon - qcom,sa8775p-llcc-bwmon - qcom,sc7180-llcc-bwmon - qcom,sc8280xp-llcc-bwmon diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qcs615-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,qcs615-rpmh.yaml new file mode 100644 index 00000000000000..9d762b2a1fcf87 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,qcs615-rpmh.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,qcs615-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on QCS615 + +maintainers: + - Raviteja Laggyshetty + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also: include/dt-bindings/interconnect/qcom,qcs615-rpmh.h + +properties: + compatible: + enum: + - qcom,qcs615-aggre1-noc + - qcom,qcs615-camnoc-virt + - qcom,qcs615-config-noc + - qcom,qcs615-dc-noc + - qcom,qcs615-gem-noc + - qcom,qcs615-ipa-virt + - qcom,qcs615-mc-virt + - qcom,qcs615-mmss-noc + - qcom,qcs615-system-noc + + reg: + maxItems: 1 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,qcs615-camnoc-virt + - qcom,qcs615-ipa-virt + - qcom,qcs615-mc-virt + then: + properties: + reg: false + else: + required: + - reg + +unevaluatedProperties: false + +examples: + - | + gem_noc: interconnect@9680000 { + compatible = "qcom,qcs615-gem-noc"; + reg = <0x9680000 0x3e200>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect-2 { + compatible = "qcom,qcs615-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,qcs8300-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,qcs8300-rpmh.yaml new file mode 100644 index 00000000000000..e9f528d6d9a8cb --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,qcs8300-rpmh.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,qcs8300-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on QCS8300 + +maintainers: + - Raviteja Laggyshetty + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). + + See also: include/dt-bindings/interconnect/qcom,qcs8300-rpmh.h + +properties: + compatible: + enum: + - qcom,qcs8300-aggre1-noc + - qcom,qcs8300-aggre2-noc + - qcom,qcs8300-clk-virt + - qcom,qcs8300-config-noc + - qcom,qcs8300-dc-noc + - qcom,qcs8300-gem-noc + - qcom,qcs8300-gpdsp-anoc + - qcom,qcs8300-lpass-ag-noc + - qcom,qcs8300-mc-virt + - qcom,qcs8300-mmss-noc + - qcom,qcs8300-nspa-noc + - qcom,qcs8300-pcie-anoc + - qcom,qcs8300-system-noc + + reg: + maxItems: 1 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,qcs8300-clk-virt + - qcom,qcs8300-mc-virt + then: + properties: + reg: false + else: + required: + - reg + +unevaluatedProperties: false + +examples: + - | + gem_noc: interconnect@9100000 { + compatible = "qcom,qcs8300-gem-noc"; + reg = <0x9100000 0xf7080>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + clk_virt: interconnect-0 { + compatible = "qcom,qcs8300-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sar2130p-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sar2130p-rpmh.yaml new file mode 100644 index 00000000000000..4647dac740e9b8 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sar2130p-rpmh.yaml @@ -0,0 +1,117 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sar2130p-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on SAR2130P + +maintainers: + - Dmitry Baryshkov + - Georgi Djakov + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also:: include/dt-bindings/interconnect/qcom,sar2130p-rpmh.h + +properties: + compatible: + enum: + - qcom,sar2130p-clk-virt + - qcom,sar2130p-config-noc + - qcom,sar2130p-gem-noc + - qcom,sar2130p-lpass-ag-noc + - qcom,sar2130p-mc-virt + - qcom,sar2130p-mmss-noc + - qcom,sar2130p-nsp-noc + - qcom,sar2130p-pcie-anoc + - qcom,sar2130p-system-noc + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,sar2130p-clk-virt + - qcom,sar2130p-mc-virt + then: + properties: + reg: false + else: + required: + - reg + + - if: + properties: + compatible: + contains: + enum: + - qcom,sar2130p-pcie-anoc + then: + properties: + clocks: + items: + - description: aggre-NOC PCIe AXI clock + - description: cfg-NOC PCIe a-NOC AHB clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sar2130p-system-noc + then: + properties: + clocks: + items: + - description: aggre USB3 PRIM AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sar2130p-system-noc + - qcom,sar2130p-pcie-anoc + then: + required: + - clocks + else: + properties: + clocks: false + +unevaluatedProperties: false + +examples: + - | + clk_virt: interconnect-0 { + compatible = "qcom,sar2130p-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@1680000 { + compatible = "qcom,sar2130p-system-noc"; + reg = <0x01680000 0x29080>; + #interconnect-cells = <2>; + clocks = <&gcc_prim_axi_clk>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml index 5f051c666cbe5f..f3247a47f9eedc 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml @@ -132,10 +132,9 @@ properties: Address property. Base address of an alias of the GICD region containing only the {SET,CLR}SPI registers to be used if isolation is required, and if supported by the HW. - $ref: /schemas/types.yaml#/definitions/uint32-array - items: - minItems: 1 - maxItems: 2 + oneOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - $ref: /schemas/types.yaml#/definitions/uint64 ppi-partitions: type: object @@ -223,9 +222,8 @@ patternProperties: (u32, u32) tuple describing the untranslated address and size of the pre-ITS window. $ref: /schemas/types.yaml#/definitions/uint32-array - items: - minItems: 2 - maxItems: 2 + minItems: 2 + maxItems: 2 required: - compatible diff --git a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml new file mode 100644 index 00000000000000..55636d06a67483 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/aspeed,ast2700-intc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Aspeed AST2700 Interrupt Controller + +description: + This interrupt controller hardware is second level interrupt controller that + is hooked to a parent interrupt controller. It's useful to combine multiple + interrupt sources into 1 interrupt to parent interrupt controller. + +maintainers: + - Kevin Chen + +properties: + compatible: + enum: + - aspeed,ast2700-intc-ic + + reg: + maxItems: 1 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + description: + The first cell is the IRQ number, the second cell is the trigger + type as defined in interrupt.txt in this directory. + + interrupts: + maxItems: 6 + description: | + Depend to which INTC0 or INTC1 used. + INTC0 and INTC1 are two kinds of interrupt controller with enable and raw + status registers for use. + INTC0 is used to assert GIC if interrupt in INTC1 asserted. + INTC1 is used to assert INTC0 if interrupt of modules asserted. + +-----+ +-------+ +---------+---module0 + | GIC |---| INTC0 |--+--| INTC1_0 |---module2 + | | | | | | |---... + +-----+ +-------+ | +---------+---module31 + | + | +---------+---module0 + +---| INTC1_1 |---module2 + | | |---... + | +---------+---module31 + ... + | +---------+---module0 + +---| INTC1_5 |---module2 + | |---... + +---------+---module31 + + +required: + - compatible + - reg + - interrupt-controller + - '#interrupt-cells' + - interrupts + +additionalProperties: false + +examples: + - | + #include + + bus { + #address-cells = <2>; + #size-cells = <2>; + + interrupt-controller@12101b00 { + compatible = "aspeed,ast2700-intc-ic"; + reg = <0 0x12101b00 0 0x10>; + #interrupt-cells = <2>; + interrupt-controller; + interrupts = , + , + , + , + , + ; + }; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.yaml b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.yaml index d4658fe3867cab..d671ed884c9e47 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.yaml @@ -23,6 +23,7 @@ properties: - atmel,sama5d3-aic - atmel,sama5d4-aic - microchip,sam9x60-aic + - microchip,sam9x7-aic reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,mu-msi.yaml b/Documentation/devicetree/bindings/interrupt-controller/fsl,mu-msi.yaml index 799ae5c3e32ae7..b5282c857f444c 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,mu-msi.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,mu-msi.yaml @@ -62,8 +62,6 @@ properties: - const: processor-a-side - const: processor-b-side - interrupt-controller: true - msi-controller: true "#msi-cells": @@ -73,7 +71,6 @@ required: - compatible - reg - interrupts - - interrupt-controller - msi-controller - "#msi-cells" @@ -88,7 +85,6 @@ examples: compatible = "fsl,imx6sx-mu-msi"; msi-controller; #msi-cells = <0>; - interrupt-controller; reg = <0x5d270000 0x10000>, /* A side */ <0x5d300000 0x10000>; /* B side */ reg-names = "processor-a-side", "processor-b-side"; diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml index b1ea08a41bb0c3..a54da66a89e732 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml @@ -29,6 +29,7 @@ properties: - qcom,qdu1000-pdc - qcom,sa8255p-pdc - qcom,sa8775p-pdc + - qcom,sar2130p-pdc - qcom,sc7180-pdc - qcom,sc7280-pdc - qcom,sc8180x-pdc diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzv2h-icu.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzv2h-icu.yaml new file mode 100644 index 00000000000000..d7ef4f1323a7a3 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzv2h-icu.yaml @@ -0,0 +1,278 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/renesas,rzv2h-icu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas RZ/V2H(P) Interrupt Control Unit + +maintainers: + - Fabrizio Castro + - Geert Uytterhoeven + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +description: + The Interrupt Control Unit (ICU) handles external interrupts (NMI, IRQ, and + TINT), error interrupts, DMAC requests, GPT interrupts, and internal + interrupts. + +properties: + compatible: + const: renesas,r9a09g057-icu # RZ/V2H(P) + + '#interrupt-cells': + description: The first cell is the SPI number of the NMI or the + PORT_IRQ[0-15] interrupt, as per user manual. The second cell is used to + specify the flag. + const: 2 + + '#address-cells': + const: 0 + + interrupt-controller: true + + reg: + maxItems: 1 + + interrupts: + minItems: 58 + items: + - description: NMI interrupt + - description: PORT_IRQ0 interrupt + - description: PORT_IRQ1 interrupt + - description: PORT_IRQ2 interrupt + - description: PORT_IRQ3 interrupt + - description: PORT_IRQ4 interrupt + - description: PORT_IRQ5 interrupt + - description: PORT_IRQ6 interrupt + - description: PORT_IRQ7 interrupt + - description: PORT_IRQ8 interrupt + - description: PORT_IRQ9 interrupt + - description: PORT_IRQ10 interrupt + - description: PORT_IRQ11 interrupt + - description: PORT_IRQ12 interrupt + - description: PORT_IRQ13 interrupt + - description: PORT_IRQ14 interrupt + - description: PORT_IRQ15 interrupt + - description: GPIO interrupt, TINT0 + - description: GPIO interrupt, TINT1 + - description: GPIO interrupt, TINT2 + - description: GPIO interrupt, TINT3 + - description: GPIO interrupt, TINT4 + - description: GPIO interrupt, TINT5 + - description: GPIO interrupt, TINT6 + - description: GPIO interrupt, TINT7 + - description: GPIO interrupt, TINT8 + - description: GPIO interrupt, TINT9 + - description: GPIO interrupt, TINT10 + - description: GPIO interrupt, TINT11 + - description: GPIO interrupt, TINT12 + - description: GPIO interrupt, TINT13 + - description: GPIO interrupt, TINT14 + - description: GPIO interrupt, TINT15 + - description: GPIO interrupt, TINT16 + - description: GPIO interrupt, TINT17 + - description: GPIO interrupt, TINT18 + - description: GPIO interrupt, TINT19 + - description: GPIO interrupt, TINT20 + - description: GPIO interrupt, TINT21 + - description: GPIO interrupt, TINT22 + - description: GPIO interrupt, TINT23 + - description: GPIO interrupt, TINT24 + - description: GPIO interrupt, TINT25 + - description: GPIO interrupt, TINT26 + - description: GPIO interrupt, TINT27 + - description: GPIO interrupt, TINT28 + - description: GPIO interrupt, TINT29 + - description: GPIO interrupt, TINT30 + - description: GPIO interrupt, TINT31 + - description: Software interrupt, INTA55_0 + - description: Software interrupt, INTA55_1 + - description: Software interrupt, INTA55_2 + - description: Software interrupt, INTA55_3 + - description: Error interrupt to CA55 + - description: GTCCRA compare match/input capture (U0) + - description: GTCCRB compare match/input capture (U0) + - description: GTCCRA compare match/input capture (U1) + - description: GTCCRB compare match/input capture (U1) + + interrupt-names: + minItems: 58 + items: + - const: nmi + - const: port_irq0 + - const: port_irq1 + - const: port_irq2 + - const: port_irq3 + - const: port_irq4 + - const: port_irq5 + - const: port_irq6 + - const: port_irq7 + - const: port_irq8 + - const: port_irq9 + - const: port_irq10 + - const: port_irq11 + - const: port_irq12 + - const: port_irq13 + - const: port_irq14 + - const: port_irq15 + - const: tint0 + - const: tint1 + - const: tint2 + - const: tint3 + - const: tint4 + - const: tint5 + - const: tint6 + - const: tint7 + - const: tint8 + - const: tint9 + - const: tint10 + - const: tint11 + - const: tint12 + - const: tint13 + - const: tint14 + - const: tint15 + - const: tint16 + - const: tint17 + - const: tint18 + - const: tint19 + - const: tint20 + - const: tint21 + - const: tint22 + - const: tint23 + - const: tint24 + - const: tint25 + - const: tint26 + - const: tint27 + - const: tint28 + - const: tint29 + - const: tint30 + - const: tint31 + - const: int-ca55-0 + - const: int-ca55-1 + - const: int-ca55-2 + - const: int-ca55-3 + - const: icu-error-ca55 + - const: gpt-u0-gtciada + - const: gpt-u0-gtciadb + - const: gpt-u1-gtciada + - const: gpt-u1-gtciadb + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - '#interrupt-cells' + - '#address-cells' + - interrupt-controller + - interrupts + - interrupt-names + - clocks + - power-domains + - resets + +unevaluatedProperties: false + +examples: + - | + #include + #include + + icu: interrupt-controller@10400000 { + compatible = "renesas,r9a09g057-icu"; + reg = <0x10400000 0x10000>; + #interrupt-cells = <2>; + #address-cells = <0>; + interrupt-controller; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "nmi", + "port_irq0", "port_irq1", "port_irq2", + "port_irq3", "port_irq4", "port_irq5", + "port_irq6", "port_irq7", "port_irq8", + "port_irq9", "port_irq10", "port_irq11", + "port_irq12", "port_irq13", "port_irq14", + "port_irq15", + "tint0", "tint1", "tint2", "tint3", + "tint4", "tint5", "tint6", "tint7", + "tint8", "tint9", "tint10", "tint11", + "tint12", "tint13", "tint14", "tint15", + "tint16", "tint17", "tint18", "tint19", + "tint20", "tint21", "tint22", "tint23", + "tint24", "tint25", "tint26", "tint27", + "tint28", "tint29", "tint30", "tint31", + "int-ca55-0", "int-ca55-1", + "int-ca55-2", "int-ca55-3", + "icu-error-ca55", + "gpt-u0-gtciada", "gpt-u0-gtciadb", + "gpt-u1-gtciada", "gpt-u1-gtciadb"; + clocks = <&cpg CPG_MOD 0x5>; + power-domains = <&cpg>; + resets = <&cpg 0x36>; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml new file mode 100644 index 00000000000000..8d330906bbbd19 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-sswi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD C900 ACLINT Supervisor-level Software Interrupt Device + +maintainers: + - Inochi Amaoto + +description: + The SSWI device is a part of the THEAD ACLINT device. It provides + supervisor-level IPI functionality for a set of HARTs on a THEAD + platform. It provides a register to set an IPI (SETSSIP) for each + HART connected to the SSWI device. + +properties: + compatible: + items: + - enum: + - sophgo,sg2044-aclint-sswi + - const: thead,c900-aclint-sswi + + reg: + maxItems: 1 + + "#interrupt-cells": + const: 0 + + interrupt-controller: true + + interrupts-extended: + minItems: 1 + maxItems: 4095 + +additionalProperties: false + +required: + - compatible + - reg + - "#interrupt-cells" + - interrupt-controller + - interrupts-extended + +examples: + - | + interrupt-controller@94000000 { + compatible = "sophgo,sg2044-aclint-sswi", "thead,c900-aclint-sswi"; + reg = <0x94000000 0x00004000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupts-extended = <&cpu1intc 1>, + <&cpu2intc 1>, + <&cpu3intc 1>, + <&cpu4intc 1>; + }; +... diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml index 6a49d74b992a34..5449266f258a93 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.yaml @@ -109,6 +109,7 @@ examples: compatible = "ti,sci-inta"; reg = <0x0 0x33d00000 0x0 0x100000>; interrupt-controller; + #interrupt-cells = <0>; msi-controller; interrupt-parent = <&main_navss_intr>; ti,sci = <&dmsc>; diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index 92d350b8e01a83..c1e11bc6b7a054 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -36,10 +36,12 @@ properties: items: - enum: - qcom,qcm2290-smmu-500 + - qcom,qcs615-smmu-500 - qcom,qcs8300-smmu-500 - qcom,qdu1000-smmu-500 - qcom,sa8255p-smmu-500 - qcom,sa8775p-smmu-500 + - qcom,sar2130p-smmu-500 - qcom,sc7180-smmu-500 - qcom,sc7280-smmu-500 - qcom,sc8180x-smmu-500 @@ -88,6 +90,7 @@ properties: - qcom,qcm2290-smmu-500 - qcom,sa8255p-smmu-500 - qcom,sa8775p-smmu-500 + - qcom,sar2130p-smmu-500 - qcom,sc7280-smmu-500 - qcom,sc8180x-smmu-500 - qcom,sc8280xp-smmu-500 @@ -524,6 +527,7 @@ allOf: compatible: items: - enum: + - qcom,sar2130p-smmu-500 - qcom,sm8550-smmu-500 - qcom,sm8650-smmu-500 - qcom,x1e80100-smmu-500 @@ -555,6 +559,7 @@ allOf: - cavium,smmu-v2 - marvell,ap806-smmu-500 - nvidia,smmu-500 + - qcom,qcs615-smmu-500 - qcom,qcs8300-smmu-500 - qcom,qdu1000-smmu-500 - qcom,sa8255p-smmu-500 diff --git a/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml new file mode 100644 index 00000000000000..5d015eeb06d030 --- /dev/null +++ b/Documentation/devicetree/bindings/iommu/riscv,iommu.yaml @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iommu/riscv,iommu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RISC-V IOMMU Architecture Implementation + +maintainers: + - Tomasz Jeznach + +description: | + The RISC-V IOMMU provides memory address translation and isolation for + input and output devices, supporting per-device translation context, + shared process address spaces including the ATS and PRI components of + the PCIe specification, two stage address translation and MSI remapping. + It supports identical translation table format to the RISC-V address + translation tables with page level access and protection attributes. + Hardware uses in-memory command and fault reporting queues with wired + interrupt or MSI notifications. + + Visit https://github.com/riscv-non-isa/riscv-iommu for more details. + + For information on assigning RISC-V IOMMU to its peripheral devices, + see generic IOMMU bindings. + +properties: + # For PCIe IOMMU hardware compatible property should contain the vendor + # and device ID according to the PCI Bus Binding specification. + # Since PCI provides built-in identification methods, compatible is not + # actually required. For non-PCIe hardware implementations 'riscv,iommu' + # should be specified along with 'reg' property providing MMIO location. + compatible: + oneOf: + - items: + - enum: + - qemu,riscv-iommu + - const: riscv,iommu + - items: + - enum: + - pci1efd,edf1 + - const: riscv,pci-iommu + + reg: + maxItems: 1 + description: + For non-PCI devices this represents base address and size of for the + IOMMU memory mapped registers interface. + For PCI IOMMU hardware implementation this should represent an address + of the IOMMU, as defined in the PCI Bus Binding reference. + + '#iommu-cells': + const: 1 + description: + The single cell describes the requester id emitted by a master to the + IOMMU. + + interrupts: + minItems: 1 + maxItems: 4 + description: + Wired interrupt vectors available for RISC-V IOMMU to notify the + RISC-V HARTS. The cause to interrupt vector is software defined + using IVEC IOMMU register. + + msi-parent: true + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - '#iommu-cells' + +additionalProperties: false + +examples: + - |+ + /* Example 1 (IOMMU device with wired interrupts) */ + #include + + iommu1: iommu@1bccd000 { + compatible = "qemu,riscv-iommu", "riscv,iommu"; + reg = <0x1bccd000 0x1000>; + interrupt-parent = <&aplic_smode>; + interrupts = <32 IRQ_TYPE_LEVEL_HIGH>, + <33 IRQ_TYPE_LEVEL_HIGH>, + <34 IRQ_TYPE_LEVEL_HIGH>, + <35 IRQ_TYPE_LEVEL_HIGH>; + #iommu-cells = <1>; + }; + + /* Device with two IOMMU device IDs, 0 and 7 */ + master1 { + iommus = <&iommu1 0>, <&iommu1 7>; + }; + + - |+ + /* Example 2 (IOMMU device with shared wired interrupt) */ + #include + + iommu2: iommu@1bccd000 { + compatible = "qemu,riscv-iommu", "riscv,iommu"; + reg = <0x1bccd000 0x1000>; + interrupt-parent = <&aplic_smode>; + interrupts = <32 IRQ_TYPE_LEVEL_HIGH>; + #iommu-cells = <1>; + }; + + - |+ + /* Example 3 (IOMMU device with MSIs) */ + iommu3: iommu@1bcdd000 { + compatible = "qemu,riscv-iommu", "riscv,iommu"; + reg = <0x1bccd000 0x1000>; + msi-parent = <&imsics_smode>; + #iommu-cells = <1>; + }; + + - |+ + /* Example 4 (IOMMU PCIe device with MSIs) */ + bus { + #address-cells = <2>; + #size-cells = <2>; + + pcie@30000000 { + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0x0 0x30000000 0x0 0x1000000>; + ranges = <0x02000000 0x0 0x41000000 0x0 0x41000000 0x0 0x0f000000>; + + /* + * The IOMMU manages all functions in this PCI domain except + * itself. Omit BDF 00:01.0. + */ + iommu-map = <0x0 &iommu0 0x0 0x8>, + <0x9 &iommu0 0x9 0xfff7>; + + /* The IOMMU programming interface uses slot 00:01.0 */ + iommu0: iommu@1,0 { + compatible = "pci1efd,edf1", "riscv,pci-iommu"; + reg = <0x800 0 0 0 0>; + #iommu-cells = <1>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.txt b/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.txt deleted file mode 100644 index ff5c921386502f..00000000000000 --- a/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.txt +++ /dev/null @@ -1,23 +0,0 @@ -Zodiac Inflight Innovations RAVE Supervisory Processor Backlight Bindings - -RAVE SP backlight device is a "MFD cell" device corresponding to -backlight functionality of RAVE Supervisory Processor. It is expected -that its Device Tree node is specified as a child of the node -corresponding to the parent RAVE SP device (as documented in -Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) - -Required properties: - -- compatible: Should be "zii,rave-sp-backlight" - -Example: - - rave-sp { - compatible = "zii,rave-sp-rdu1"; - current-speed = <38400>; - - backlight { - compatible = "zii,rave-sp-backlight"; - }; - } - diff --git a/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.yaml new file mode 100644 index 00000000000000..ee93a3e64852a4 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/zii,rave-sp-backlight.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/backlight/zii,rave-sp-backlight.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zodiac Inflight Innovations RAVE Supervisory Processor Backlight + +maintainers: + - Frank Li + +description: + RAVE SP backlight device is a "MFD cell" device corresponding to + backlight functionality of RAVE Supervisory Processor. It is expected + that its Device Tree node is specified as a child of the node + corresponding to the parent RAVE SP device (as documented in + Documentation/devicetree/bindings/mfd/zii,rave-sp.yaml) + +properties: + compatible: + const: zii,rave-sp-backlight + +required: + - compatible + +allOf: + - $ref: common.yaml + +unevaluatedProperties: false + +examples: + - | + backlight { + compatible = "zii,rave-sp-backlight"; + }; + diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index bf9a101e4d4206..3e8319e4433923 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -118,6 +118,8 @@ properties: # No trigger assigned to the LED. This is the default mode # if trigger is absent - none + # LED indicates remote control feedback + - rc-feedback # LED indicates camera torch state - torch # LED indicates USB gadget activity @@ -202,6 +204,12 @@ properties: #trigger-source-cells property in the source node. $ref: /schemas/types.yaml#/definitions/phandle-array + active-high: + type: boolean + description: + Makes LED active high. To turn the LED ON, line needs to be + set to high voltage instead of low. + active-low: type: boolean description: @@ -225,6 +233,14 @@ properties: Maximum timeout in microseconds after which the flash LED is turned off. Required for flash LED nodes with configurable timeout. +allOf: + - if: + required: + - active-low + then: + properties: + active-high: false + additionalProperties: true examples: diff --git a/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml b/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml index bb20394fca5c38..62326507c1aac2 100644 --- a/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml +++ b/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml @@ -41,6 +41,16 @@ properties: "#size-cells": const: 0 + brcm,serial-shift-bits: + minimum: 1 + maximum: 32 + description: + This describes the number of 8-bit serial shifters connected to the LED + controller block. The hardware is typically using 8-bit shift registers + with 8 LEDs per shift register, so 4 shifters results in 32 LEDs or 2 + shifters give 16 LEDs etc, but the hardware supports any odd number of + registers. If left unspecified, the hardware boot-time default is used. + patternProperties: "^led@[a-f0-9]+$": type: object @@ -71,6 +81,7 @@ examples: leds@ff800800 { compatible = "brcm,bcm4908-leds", "brcm,bcm63138-leds"; reg = <0xff800800 0xdc>; + brcm,serial-shift-bits = <16>; #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/leds/leds-mt6323.txt b/Documentation/devicetree/bindings/leds/leds-mt6323.txt deleted file mode 100644 index 052dccb8f2ce0f..00000000000000 --- a/Documentation/devicetree/bindings/leds/leds-mt6323.txt +++ /dev/null @@ -1,63 +0,0 @@ -Device Tree Bindings for LED support on MT6323 PMIC - -MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED -controllers are defined as the subnode of the function node provided by MT6323 -PMIC controller that is being defined as one kind of Muti-Function Device (MFD) -using shared bus called PMIC wrapper for each subfunction to access remote -MT6323 PMIC hardware. - -For MT6323 MFD bindings see: -Documentation/devicetree/bindings/mfd/mt6397.txt -For MediaTek PMIC wrapper bindings see: -Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml - -Required properties: -- compatible : Must be one of - - "mediatek,mt6323-led" - - "mediatek,mt6331-led" - - "mediatek,mt6332-led" -- address-cells : Must be 1 -- size-cells : Must be 0 - -Each led is represented as a child node of the mediatek,mt6323-led that -describes the initial behavior for each LED physically and currently only four -LED child nodes can be supported. - -Required properties for the LED child node: -- reg : LED channel number (0..3) - -Optional properties for the LED child node: -- label : See Documentation/devicetree/bindings/leds/common.txt -- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt -- default-state: See Documentation/devicetree/bindings/leds/common.txt - -Example: - - mt6323: pmic { - compatible = "mediatek,mt6323"; - - ... - - mt6323led: leds { - compatible = "mediatek,mt6323-led"; - #address-cells = <1>; - #size-cells = <0>; - - led@0 { - reg = <0>; - label = "LED0"; - linux,default-trigger = "timer"; - default-state = "on"; - }; - led@1 { - reg = <1>; - label = "LED1"; - default-state = "off"; - }; - led@2 { - reg = <2>; - label = "LED2"; - default-state = "on"; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/leds/leds-pca955x.txt b/Documentation/devicetree/bindings/leds/leds-pca955x.txt deleted file mode 100644 index 817f460f3a72ac..00000000000000 --- a/Documentation/devicetree/bindings/leds/leds-pca955x.txt +++ /dev/null @@ -1,89 +0,0 @@ -* NXP - pca955x LED driver - -The PCA955x family of chips are I2C LED blinkers whose pins not used -to control LEDs can be used as general purpose I/Os. The GPIO pins can -be input or output, and output pins can also be pulse-width controlled. - -Required properties: -- compatible : should be one of : - "nxp,pca9550" - "nxp,pca9551" - "nxp,pca9552" - "ibm,pca9552" - "nxp,pca9553" -- #address-cells: must be 1 -- #size-cells: must be 0 -- reg: I2C slave address. depends on the model. - -Optional properties: -- gpio-controller: allows pins to be used as GPIOs. -- #gpio-cells: must be 2. -- gpio-line-names: define the names of the GPIO lines - -LED sub-node properties: -- reg : number of LED line. - from 0 to 1 for the pca9550 - from 0 to 7 for the pca9551 - from 0 to 15 for the pca9552 - from 0 to 3 for the pca9553 -- type: (optional) either - PCA955X_TYPE_NONE - PCA955X_TYPE_LED - PCA955X_TYPE_GPIO - see dt-bindings/leds/leds-pca955x.h (default to LED) -- label : (optional) - see Documentation/devicetree/bindings/leds/common.txt -- linux,default-trigger : (optional) - see Documentation/devicetree/bindings/leds/common.txt - -Examples: - -pca9552: pca9552@60 { - compatible = "nxp,pca9552"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x60>; - - gpio-controller; - #gpio-cells = <2>; - gpio-line-names = "GPIO12", "GPIO13", "GPIO14", "GPIO15"; - - gpio@12 { - reg = <12>; - type = ; - }; - gpio@13 { - reg = <13>; - type = ; - }; - gpio@14 { - reg = <14>; - type = ; - }; - gpio@15 { - reg = <15>; - type = ; - }; - - led@0 { - label = "red:power"; - linux,default-trigger = "default-on"; - reg = <0>; - type = ; - }; - led@1 { - label = "green:power"; - reg = <1>; - type = ; - }; - led@2 { - label = "pca9552:yellow"; - reg = <2>; - type = ; - }; - led@3 { - label = "pca9552:white"; - reg = <3>; - type = ; - }; -}; diff --git a/Documentation/devicetree/bindings/leds/leds-pwm.yaml b/Documentation/devicetree/bindings/leds/leds-pwm.yaml index 113b7c218303ad..61b97e8bc36d08 100644 --- a/Documentation/devicetree/bindings/leds/leds-pwm.yaml +++ b/Documentation/devicetree/bindings/leds/leds-pwm.yaml @@ -34,6 +34,12 @@ patternProperties: Maximum brightness possible for the LED $ref: /schemas/types.yaml#/definitions/uint32 + default-brightness: + description: + Brightness to be set if LED's default state is on. Used only during + initialization. If the option is not set then max brightness is used. + $ref: /schemas/types.yaml#/definitions/uint32 + required: - pwms - max-brightness diff --git a/Documentation/devicetree/bindings/leds/nxp,pca955x.yaml b/Documentation/devicetree/bindings/leds/nxp,pca955x.yaml new file mode 100644 index 00000000000000..ae7384cc760c1c --- /dev/null +++ b/Documentation/devicetree/bindings/leds/nxp,pca955x.yaml @@ -0,0 +1,158 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/nxp,pca955x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PCA955X LED controllers + +maintainers: + - Nate Case + +description: | + The PCA955x family of chips are I2C LED blinkers whose pins not used + to control LEDs can be used as general purpose I/Os. The GPIO pins can + be input or output, and output pins can also be pulse-width controlled. + + For more product information please see the link below: + - https://www.nxp.com/docs/en/data-sheet/PCA9552.pdf + +properties: + compatible: + enum: + - nxp,pca9550 + - nxp,pca9551 + - nxp,pca9552 + - ibm,pca9552 + - nxp,pca9553 + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + gpio-controller: true + + gpio-line-names: + minItems: 1 + maxItems: 16 + + "#gpio-cells": + const: 2 + +patternProperties: + "^led@[0-9a-f]$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + maxItems: 1 + type: + description: | + Output configuration, see include/dt-bindings/leds/leds-pca955x.h + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + minimum: 0 + maximum: 2 + + required: + - reg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - nxp,pca9550 + then: + patternProperties: + "^led@[0-9a-f]$": + properties: + reg: + maximum: 1 + - if: + properties: + compatible: + contains: + enum: + - nxp,pca9551 + then: + patternProperties: + "^led@[0-9a-f]$": + properties: + reg: + maximum: 7 + - if: + properties: + compatible: + contains: + enum: + - nxp,pca9552 + - ibm,pca9552 + then: + patternProperties: + "^led@[0-9a-f]$": + properties: + reg: + maximum: 15 + - if: + properties: + compatible: + contains: + enum: + - nxp,pca9553 + then: + patternProperties: + "^led@[0-9a-f]$": + properties: + reg: + maximum: 3 + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@60 { + compatible = "nxp,pca9552"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + label = "red:power"; + linux,default-trigger = "default-on"; + type = ; + }; + led@1 { + reg = <1>; + label = "green:power"; + type = ; + }; + led@2 { + reg = <2>; + label = "pca9552:yellow"; + type = ; + }; + led@3 { + reg = <3>; + label = "pca9552:white"; + type = ; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/leds/sprd,sc2731-bltc.yaml b/Documentation/devicetree/bindings/leds/sprd,sc2731-bltc.yaml index 5853410c7a4597..97535d6dc47a7c 100644 --- a/Documentation/devicetree/bindings/leds/sprd,sc2731-bltc.yaml +++ b/Documentation/devicetree/bindings/leds/sprd,sc2731-bltc.yaml @@ -50,35 +50,4 @@ required: - '#size-cells' additionalProperties: false - -examples: - - | - #include - - pmic { - #address-cells = <1>; - #size-cells = <0>; - - led-controller@200 { - compatible = "sprd,sc2731-bltc"; - reg = <0x200>; - #address-cells = <1>; - #size-cells = <0>; - - led@0 { - reg = <0x0>; - color = ; - }; - - led@1 { - reg = <0x1>; - color = ; - }; - - led@2 { - reg = <0x2>; - color = ; - }; - }; - }; ... diff --git a/Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml b/Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml index a4f1fe63659aab..02f06314d85fe0 100644 --- a/Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml +++ b/Documentation/devicetree/bindings/mailbox/arm,mhuv2.yaml @@ -197,7 +197,7 @@ examples: reg = <0 0x596e8000 0 0x88000>; clocks = <&adma_lpcg 0>, <&adma_lpcg 1>, <&adma_lpcg 2>; clock-names = "ipg", "ocram", "core"; - power-domains = <&pd 0>, <&pd 1>, <&pd 2>, <&pd 3>; + power-domains = <&pd 0>, <&pd 1>; mbox-names = "txdb0", "txdb1", "rxdb0", "rxdb1"; mboxes = <&mhu_tx 2 0>, //data-transfer protocol with 5 windows, mhu-tx <&mhu_tx 3 0>, //data-transfer protocol with 7 windows, mhu-tx diff --git a/Documentation/devicetree/bindings/mailbox/microchip,mpfs-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/microchip,mpfs-mailbox.yaml index 404477910f029e..1332aab9a888f1 100644 --- a/Documentation/devicetree/bindings/mailbox/microchip,mpfs-mailbox.yaml +++ b/Documentation/devicetree/bindings/mailbox/microchip,mpfs-mailbox.yaml @@ -15,6 +15,8 @@ properties: reg: oneOf: + - items: + - description: mailbox data registers - items: - description: mailbox control & data registers - description: mailbox interrupt registers @@ -23,6 +25,7 @@ properties: - description: mailbox control registers - description: mailbox interrupt registers - description: mailbox data registers + deprecated: true interrupts: maxItems: 1 @@ -41,12 +44,12 @@ additionalProperties: false examples: - | soc { - #address-cells = <2>; - #size-cells = <2>; - mbox: mailbox@37020000 { + #address-cells = <1>; + #size-cells = <1>; + + mailbox@37020800 { compatible = "microchip,mpfs-mailbox"; - reg = <0x0 0x37020000 0x0 0x58>, <0x0 0x2000318C 0x0 0x40>, - <0x0 0x37020800 0x0 0x100>; + reg = <0x37020800 0x100>; interrupt-parent = <&L1>; interrupts = <96>; #mbox-cells = <1>; diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml index 982c741e622513..9d2dfd85b20731 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml @@ -165,12 +165,13 @@ allOf: - if: properties: compatible: - enum: - - qcom,msm8953-apcs-kpss-global - - qcom,msm8994-apcs-kpss-global - - qcom,msm8996-apcs-hmss-global - - qcom,qcm2290-apcs-hmss-global - - qcom,sdm845-apss-shared + contains: + enum: + - qcom,msm8953-apcs-kpss-global + - qcom,msm8994-apcs-kpss-global + - qcom,msm8996-apcs-hmss-global + - qcom,qcm2290-apcs-hmss-global + - qcom,sdm845-apss-shared then: properties: clocks: false diff --git a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml index 2d66770ed3612f..f69c0ec5d19d3d 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml @@ -28,6 +28,7 @@ properties: - qcom,qdu1000-ipcc - qcom,sa8255p-ipcc - qcom,sa8775p-ipcc + - qcom,sar2130p-ipcc - qcom,sc7280-ipcc - qcom,sc8280xp-ipcc - qcom,sdx75-ipcc @@ -38,6 +39,7 @@ properties: - qcom,sm8450-ipcc - qcom,sm8550-ipcc - qcom,sm8650-ipcc + - qcom,sm8750-ipcc - qcom,x1e80100-ipcc - const: qcom,ipcc diff --git a/Documentation/devicetree/bindings/mailbox/thead,th1520-mbox.yaml b/Documentation/devicetree/bindings/mailbox/thead,th1520-mbox.yaml new file mode 100644 index 00000000000000..0971fb97896efe --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/thead,th1520-mbox.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mailbox/thead,th1520-mbox.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-head TH1520 Mailbox Controller + +description: + The T-head mailbox controller enables communication and coordination between + cores within the SoC by passing messages (e.g., data, status, and control) + through mailbox channels. It also allows one core to signal another processor + using interrupts via the Interrupt Controller Unit (ICU). + +maintainers: + - Michal Wilczynski + +properties: + compatible: + const: thead,th1520-mbox + + clocks: + items: + - description: Clock for the local mailbox + - description: Clock for remote ICU 0 + - description: Clock for remote ICU 1 + - description: Clock for remote ICU 2 + + clock-names: + items: + - const: clk-local + - const: clk-remote-icu0 + - const: clk-remote-icu1 + - const: clk-remote-icu2 + + reg: + items: + - description: Mailbox local base address + - description: Remote ICU 0 base address + - description: Remote ICU 1 base address + - description: Remote ICU 2 base address + + reg-names: + items: + - const: local + - const: remote-icu0 + - const: remote-icu1 + - const: remote-icu2 + + interrupts: + maxItems: 1 + + '#mbox-cells': + const: 1 + description: + The one and only cell describes destination CPU ID. + +required: + - compatible + - clocks + - clock-names + - reg + - reg-names + - interrupts + - '#mbox-cells' + +additionalProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + mailbox@ffffc38000 { + compatible = "thead,th1520-mbox"; + reg = <0xff 0xffc38000 0x0 0x4000>, + <0xff 0xffc44000 0x0 0x1000>, + <0xff 0xffc4c000 0x0 0x1000>, + <0xff 0xffc54000 0x0 0x1000>; + reg-names = "local", "remote-icu0", "remote-icu1", "remote-icu2"; + clocks = <&clk CLK_MBOX0>, <&clk CLK_MBOX1>, <&clk CLK_MBOX2>, + <&clk CLK_MBOX3>; + clock-names = "clk-local", "clk-remote-icu0", "clk-remote-icu1", + "clk-remote-icu2"; + interrupts = <28>; + #mbox-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml index c8d887eee3bbed..4371a0ef276174 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml @@ -39,6 +39,12 @@ properties: maxItems: 1 adv,force-bt656-4: + deprecated: true + description: + Indicates that the output is a BT.656-4 compatible stream. + type: boolean + + adi,force-bt656-4: description: Indicates that the output is a BT.656-4 compatible stream. type: boolean diff --git a/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml b/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml index 60f19e1152b331..1a57f2aa198228 100644 --- a/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml +++ b/Documentation/devicetree/bindings/media/i2c/hynix,hi846.yaml @@ -28,12 +28,6 @@ properties: items: - description: Reference to the mclk clock. - assigned-clocks: - maxItems: 1 - - assigned-clock-rates: - maxItems: 1 - reset-gpios: description: Reference to the GPIO connected to the RESETB pin. Active low. maxItems: 1 @@ -82,8 +76,6 @@ required: - compatible - reg - clocks - - assigned-clocks - - assigned-clock-rates - vddio-supply - vdda-supply - vddd-supply @@ -105,8 +97,6 @@ examples: pinctrl-names = "default"; pinctrl-0 = <&pinctrl_csi1>; clocks = <&clk 0>; - assigned-clocks = <&clk 0>; - assigned-clock-rates = <25000000>; vdda-supply = <®_camera_vdda>; vddd-supply = <®_camera_vddd>; vddio-supply = <®_camera_vddio>; diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml index 6c72e77b927c0d..26f85151afbd3e 100644 --- a/Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml +++ b/Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml @@ -25,7 +25,10 @@ description: | properties: compatible: - const: maxim,max96712 + items: + - enum: + - maxim,max96712 + - maxim,max96724 reg: description: I2C device address diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov08x40.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov08x40.yaml new file mode 100644 index 00000000000000..552efdf8934f73 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov08x40.yaml @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright (c) 2024 Linaro Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov08x40.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Omnivision OV08X40 CMOS Sensor + +maintainers: + - Bryan O'Donoghue + +description: | + The Omnivision OV08X40 is a 9.2 megapixel, CMOS image sensor which supports: + - Automatic black level calibration (ABLC) + - Programmable controls for frame rate, mirror and flip, binning, cropping + and windowing + - Output formats 10-bit 4C RGB RAW, 10-bit Bayer RAW + - 4-lane MIPI D-PHY TX @ 1 Gbps per lane + - 2-lane MPIP D-PHY TX @ 2 Gbps per lane + - Dynamic defect pixel cancellation + - Standard SCCB command interface + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +properties: + compatible: + const: ovti,ov08x40 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + avdd-supply: + description: Analogue circuit voltage supply. + + dovdd-supply: + description: I/O circuit voltage supply. + + dvdd-supply: + description: Digital circuit voltage supply. + + reset-gpios: + description: Active low GPIO connected to XSHUTDOWN pad of the sensor. + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + additionalProperties: false + + properties: + data-lanes: + oneOf: + - items: + - const: 1 + - const: 2 + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + link-frequencies: true + remote-endpoint: true + + required: + - data-lanes + - link-frequencies + - remote-endpoint + +required: + - compatible + - reg + - clocks + - port + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ov08x40: camera@36 { + compatible = "ovti,ov08x40"; + reg = <0x36>; + + reset-gpios = <&tlmm 111 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_rgb_defaultt>; + + clocks = <&ov08x40_clk>; + + assigned-clocks = <&ov08x40_clk>; + assigned-clock-parents = <&ov08x40_clk_parent>; + assigned-clock-rates = <19200000>; + + avdd-supply = <&vreg_l7b_2p8>; + dvdd-supply = <&vreg_l7b_1p8>; + dovdd-supply = <&vreg_l3m_1p8>; + + port { + ov08x40_ep: endpoint { + remote-endpoint = <&csiphy4_ep>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <400000000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5648.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5648.yaml index 1f497679168c83..8028c8b107c46c 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov5648.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov5648.yaml @@ -20,12 +20,6 @@ properties: items: - description: XVCLK Clock - assigned-clocks: - maxItems: 1 - - assigned-clock-rates: - maxItems: 1 - dvdd-supply: description: Digital Domain Power Supply @@ -68,8 +62,6 @@ required: - compatible - reg - clocks - - assigned-clocks - - assigned-clock-rates - dvdd-supply - dovdd-supply - port @@ -93,9 +85,6 @@ examples: avdd-supply = <&ov5648_avdd>; dovdd-supply = <&ov5648_dovdd>; clocks = <&ov5648_xvclk 0>; - assigned-clocks = <&ov5648_xvclk 0>; - assigned-clock-rates = <24000000>; - ov5648_out: port { ov5648_out_mipi_csi2: endpoint { diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov8865.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov8865.yaml index 8a70e23ba6abed..320b9aacbb8bf0 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov8865.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov8865.yaml @@ -20,12 +20,6 @@ properties: items: - description: EXTCLK Clock - assigned-clocks: - maxItems: 1 - - assigned-clock-rates: - maxItems: 1 - dvdd-supply: description: Digital Domain Power Supply @@ -68,8 +62,6 @@ required: - compatible - reg - clocks - - assigned-clocks - - assigned-clock-rates - dvdd-supply - avdd-supply - dovdd-supply @@ -94,8 +86,6 @@ examples: pinctrl-0 = <&csi_mclk_pin>; clocks = <&ccu CLK_CSI_MCLK>; - assigned-clocks = <&ccu CLK_CSI_MCLK>; - assigned-clock-rates = <24000000>; avdd-supply = <®_ov8865_avdd>; dovdd-supply = <®_ov8865_dovdd>; diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml index 79a7658f6d0547..401c8613f84038 100644 --- a/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml @@ -27,10 +27,6 @@ properties: description: I2C address maxItems: 1 - assigned-clocks: true - assigned-clock-parents: true - assigned-clock-rates: true - clocks: description: Clock frequency from 6 to 27MHz maxItems: 1 @@ -87,10 +83,6 @@ examples: reg = <0x60>; clocks = <&ov9282_clk>; - assigned-clocks = <&ov9282_clk>; - assigned-clock-parents = <&ov9282_clk_parent>; - assigned-clock-rates = <24000000>; - port { ov9282: endpoint { remote-endpoint = <&cam>; diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml index c978abc0cdb35c..975c1d77c8e5d2 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml @@ -24,10 +24,6 @@ properties: - sony,imx258 - sony,imx258-pdaf - assigned-clocks: true - assigned-clock-parents: true - assigned-clock-rates: true - clocks: description: Clock frequency from 6 to 27 MHz. @@ -125,9 +121,6 @@ examples: reg = <0x6c>; clocks = <&imx258_clk>; - assigned-clocks = <&imx258_clk>; - assigned-clock-rates = <19200000>; - port { endpoint { remote-endpoint = <&csi1_ep>; diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml index bce57b22f7b63b..3842e513046349 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml @@ -24,10 +24,6 @@ properties: description: I2C address maxItems: 1 - assigned-clocks: true - assigned-clock-parents: true - assigned-clock-rates: true - clocks: description: Clock frequency from 6 to 27 MHz, 37.125MHz, 74.25MHz maxItems: 1 @@ -74,10 +70,6 @@ examples: reg = <0x1a>; clocks = <&imx334_clk>; - assigned-clocks = <&imx334_clk>; - assigned-clock-parents = <&imx334_clk_parent>; - assigned-clock-rates = <24000000>; - port { imx334: endpoint { remote-endpoint = <&cam>; diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml index 77bf3a4ee89db3..80f879b6bd01bf 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml @@ -24,10 +24,6 @@ properties: description: I2C address maxItems: 1 - assigned-clocks: true - assigned-clock-parents: true - assigned-clock-rates: true - clocks: description: Clock frequency from 6 to 27 MHz, 37.125MHz, 74.25MHz maxItems: 1 @@ -86,10 +82,6 @@ examples: reg = <0x1a>; clocks = <&imx335_clk>; - assigned-clocks = <&imx335_clk>; - assigned-clock-parents = <&imx335_clk_parent>; - assigned-clock-rates = <24000000>; - avdd-supply = <&camera_vdda_2v9>; ovdd-supply = <&camera_vddo_1v8>; dvdd-supply = <&camera_vddd_1v2>; diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml index d9b7815650fdb8..5447ab0768a66a 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml @@ -26,10 +26,6 @@ properties: description: I2C address maxItems: 1 - assigned-clocks: true - assigned-clock-parents: true - assigned-clock-rates: true - clocks: description: Clock frequency 6MHz, 12MHz, 18MHz, 24MHz or 27MHz maxItems: 1 @@ -86,10 +82,6 @@ examples: reg = <0x1a>; clocks = <&imx412_clk>; - assigned-clocks = <&imx412_clk>; - assigned-clock-parents = <&imx412_clk_parent>; - assigned-clock-rates = <24000000>; - port { imx412: endpoint { remote-endpoint = <&cam>; diff --git a/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml b/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml index 535acf2b88a908..bc339a7374b224 100644 --- a/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml +++ b/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml @@ -135,8 +135,7 @@ properties: data-lanes: $ref: /schemas/media/video-interfaces.yaml#/properties/data-lanes - items: - maxItems: 4 + maxItems: 4 description: This property is for lane reordering between the THP7312 and the imaging sensor that it is connected to. diff --git a/Documentation/devicetree/bindings/media/qcom,msm8953-camss.yaml b/Documentation/devicetree/bindings/media/qcom,msm8953-camss.yaml new file mode 100644 index 00000000000000..8856fba385b112 --- /dev/null +++ b/Documentation/devicetree/bindings/media/qcom,msm8953-camss.yaml @@ -0,0 +1,322 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/qcom,msm8953-camss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm MSM8953 Camera Subsystem (CAMSS) + +maintainers: + - Barnabas Czeman + +description: + The CAMSS IP is a CSI decoder and ISP present on Qualcomm platforms + +properties: + compatible: + const: qcom,msm8953-camss + + clocks: + minItems: 30 + maxItems: 30 + + clock-names: + items: + - const: ahb + - const: csi0 + - const: csi0_ahb + - const: csi0_phy + - const: csi0_pix + - const: csi0_rdi + - const: csi1 + - const: csi1_ahb + - const: csi1_phy + - const: csi1_pix + - const: csi1_rdi + - const: csi2 + - const: csi2_ahb + - const: csi2_phy + - const: csi2_pix + - const: csi2_rdi + - const: csi_vfe0 + - const: csi_vfe1 + - const: csiphy0_timer + - const: csiphy1_timer + - const: csiphy2_timer + - const: ispif_ahb + - const: micro_ahb + - const: top_ahb + - const: vfe0 + - const: vfe0_ahb + - const: vfe0_axi + - const: vfe1 + - const: vfe1_ahb + - const: vfe1_axi + + interrupts: + minItems: 9 + maxItems: 9 + + interrupt-names: + items: + - const: csid0 + - const: csid1 + - const: csid2 + - const: csiphy0 + - const: csiphy1 + - const: csiphy2 + - const: ispif + - const: vfe0 + - const: vfe1 + + iommus: + maxItems: 1 + + power-domains: + items: + - description: VFE0 GDSC - Video Front End, Global Distributed Switch Controller. + - description: VFE1 GDSC - Video Front End, Global Distributed Switch Controller. + + power-domain-names: + items: + - const: vfe0 + - const: vfe1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + description: + CSI input ports. + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + Input port for receiving CSI data. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + description: + An array of physical data lanes indexes. + Position of an entry determines the logical + lane number, while the value of an entry + indicates physical lane index. Lane swapping + is supported. Physical lane indexes; + 0, 2, 3, 4. + minItems: 1 + maxItems: 4 + + required: + - data-lanes + + port@1: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + Input port for receiving CSI data. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 4 + + required: + - data-lanes + + port@2: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + Input port for receiving CSI data. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 4 + + required: + - data-lanes + + reg: + minItems: 13 + maxItems: 13 + + reg-names: + items: + - const: csi_clk_mux + - const: csid0 + - const: csid1 + - const: csid2 + - const: csiphy0 + - const: csiphy0_clk_mux + - const: csiphy1 + - const: csiphy1_clk_mux + - const: csiphy2 + - const: csiphy2_clk_mux + - const: ispif + - const: vfe0 + - const: vfe1 + + vdda-supply: + description: + Definition of the regulator used as analog power supply. + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - interrupts + - interrupt-names + - iommus + - power-domains + - power-domain-names + - vdda-supply + +additionalProperties: false + +examples: + - | + #include + #include + + camss: camss@1b00020 { + compatible = "qcom,msm8953-camss"; + + reg = <0x1b00020 0x10>, + <0x1b30000 0x100>, + <0x1b30400 0x100>, + <0x1b30800 0x100>, + <0x1b34000 0x1000>, + <0x1b00030 0x4>, + <0x1b35000 0x1000>, + <0x1b00038 0x4>, + <0x1b36000 0x1000>, + <0x1b00040 0x4>, + <0x1b31000 0x500>, + <0x1b10000 0x1000>, + <0x1b14000 0x1000>; + reg-names = "csi_clk_mux", + "csid0", + "csid1", + "csid2", + "csiphy0", + "csiphy0_clk_mux", + "csiphy1", + "csiphy1_clk_mux", + "csiphy2", + "csiphy2_clk_mux", + "ispif", + "vfe0", + "vfe1"; + + clocks = <&gcc GCC_CAMSS_AHB_CLK>, + <&gcc GCC_CAMSS_CSI0_CLK>, + <&gcc GCC_CAMSS_CSI0_AHB_CLK>, + <&gcc GCC_CAMSS_CSI0PHY_CLK>, + <&gcc GCC_CAMSS_CSI0PIX_CLK>, + <&gcc GCC_CAMSS_CSI0RDI_CLK>, + <&gcc GCC_CAMSS_CSI1_CLK>, + <&gcc GCC_CAMSS_CSI1_AHB_CLK>, + <&gcc GCC_CAMSS_CSI1PHY_CLK>, + <&gcc GCC_CAMSS_CSI1PIX_CLK>, + <&gcc GCC_CAMSS_CSI1RDI_CLK>, + <&gcc GCC_CAMSS_CSI2_CLK>, + <&gcc GCC_CAMSS_CSI2_AHB_CLK>, + <&gcc GCC_CAMSS_CSI2PHY_CLK>, + <&gcc GCC_CAMSS_CSI2PIX_CLK>, + <&gcc GCC_CAMSS_CSI2RDI_CLK>, + <&gcc GCC_CAMSS_CSI_VFE0_CLK>, + <&gcc GCC_CAMSS_CSI_VFE1_CLK>, + <&gcc GCC_CAMSS_CSI0PHYTIMER_CLK>, + <&gcc GCC_CAMSS_CSI1PHYTIMER_CLK>, + <&gcc GCC_CAMSS_CSI2PHYTIMER_CLK>, + <&gcc GCC_CAMSS_ISPIF_AHB_CLK>, + <&gcc GCC_CAMSS_MICRO_AHB_CLK>, + <&gcc GCC_CAMSS_TOP_AHB_CLK>, + <&gcc GCC_CAMSS_VFE0_CLK>, + <&gcc GCC_CAMSS_VFE0_AHB_CLK>, + <&gcc GCC_CAMSS_VFE0_AXI_CLK>, + <&gcc GCC_CAMSS_VFE1_CLK>, + <&gcc GCC_CAMSS_VFE1_AHB_CLK>, + <&gcc GCC_CAMSS_VFE1_AXI_CLK>; + clock-names = "ahb", + "csi0", + "csi0_ahb", + "csi0_phy", + "csi0_pix", + "csi0_rdi", + "csi1", + "csi1_ahb", + "csi1_phy", + "csi1_pix", + "csi1_rdi", + "csi2", + "csi2_ahb", + "csi2_phy", + "csi2_pix", + "csi2_rdi", + "csi_vfe0", + "csi_vfe1", + "csiphy0_timer", + "csiphy1_timer", + "csiphy2_timer", + "ispif_ahb", + "micro_ahb", + "top_ahb", + "vfe0", + "vfe0_ahb", + "vfe0_axi", + "vfe1", + "vfe1_ahb", + "vfe1_axi"; + + interrupts = , + , + , + , + , + , + , + , + ; + interrupt-names = "csid0", + "csid1", + "csid2", + "csiphy0", + "csiphy1", + "csiphy2", + "ispif", + "vfe0", + "vfe1"; + + iommus = <&apps_iommu 0x14>; + + power-domains = <&gcc VFE0_GDSC>, + <&gcc VFE1_GDSC>; + power-domain-names = "vfe0", "vfe1"; + + vdda-supply = <®_2v8>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/media/raspberrypi,rp1-cfe.yaml b/Documentation/devicetree/bindings/media/raspberrypi,rp1-cfe.yaml new file mode 100644 index 00000000000000..eba5394719b906 --- /dev/null +++ b/Documentation/devicetree/bindings/media/raspberrypi,rp1-cfe.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/raspberrypi,rp1-cfe.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Raspberry Pi PiSP Camera Front End + +maintainers: + - Tomi Valkeinen + - Raspberry Pi Kernel Maintenance + +description: | + The Raspberry Pi PiSP Camera Front End is a module in Raspberrypi 5's RP1 I/O + controller, that contains: + - MIPI D-PHY + - MIPI CSI-2 receiver + - Simple image processor (called PiSP Front End, or FE) + + The FE documentation is available at: + https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf + + The PHY and CSI-2 receiver part have no public documentation. + +properties: + compatible: + items: + - const: raspberrypi,rp1-cfe + + reg: + items: + - description: CSI-2 registers + - description: D-PHY registers + - description: MIPI CFG (a simple top-level mux) registers + - description: FE registers + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + description: CSI-2 RX Port + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + minItems: 1 + maxItems: 4 + + required: + - data-lanes + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + rp1 { + #address-cells = <2>; + #size-cells = <2>; + + csi@110000 { + compatible = "raspberrypi,rp1-cfe"; + reg = <0xc0 0x40110000 0x0 0x100>, + <0xc0 0x40114000 0x0 0x100>, + <0xc0 0x40120000 0x0 0x100>, + <0xc0 0x40124000 0x0 0x1000>; + + interrupts = <42>; + + clocks = <&rp1_clocks>; + + port { + csi_ep: endpoint { + remote-endpoint = <&cam_endpoint>; + data-lanes = <1 2>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/renesas,csi2.yaml b/Documentation/devicetree/bindings/media/renesas,csi2.yaml index 977ab188d6547f..80b77875874d19 100644 --- a/Documentation/devicetree/bindings/media/renesas,csi2.yaml +++ b/Documentation/devicetree/bindings/media/renesas,csi2.yaml @@ -32,6 +32,7 @@ properties: - renesas,r8a77990-csi2 # R-Car E3 - renesas,r8a779a0-csi2 # R-Car V3U - renesas,r8a779g0-csi2 # R-Car V4H + - renesas,r8a779h0-csi2 # R-Car V4M reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/media/renesas,isp.yaml b/Documentation/devicetree/bindings/media/renesas,isp.yaml index 33650a1ea03458..c4de4555b7535a 100644 --- a/Documentation/devicetree/bindings/media/renesas,isp.yaml +++ b/Documentation/devicetree/bindings/media/renesas,isp.yaml @@ -22,6 +22,8 @@ properties: - enum: - renesas,r8a779a0-isp # V3U - renesas,r8a779g0-isp # V4H + - renesas,r8a779h0-isp # V4M + - const: renesas,rcar-gen4-isp # Generic R-Car Gen4 reg: maxItems: 1 @@ -116,7 +118,7 @@ examples: #include isp1: isp@fed20000 { - compatible = "renesas,r8a779a0-isp"; + compatible = "renesas,r8a779a0-isp", "renesas,rcar-gen4-isp"; reg = <0xfed20000 0x10000>; interrupts = ; clocks = <&cpg CPG_MOD 613>; diff --git a/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml b/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml index f762fdc05e4d18..b9f033f2f3ce46 100644 --- a/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml +++ b/Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml @@ -13,7 +13,7 @@ description: | CSI_RX_IF section. maintainers: - - Jai Luthra + - Jai Luthra properties: compatible: diff --git a/Documentation/devicetree/bindings/memory-controllers/exynos-srom.yaml b/Documentation/devicetree/bindings/memory-controllers/exynos-srom.yaml index 10a2d97e5f8b51..a5598ade399f23 100644 --- a/Documentation/devicetree/bindings/memory-controllers/exynos-srom.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/exynos-srom.yaml @@ -66,9 +66,8 @@ patternProperties: samsung,srom-timing: $ref: /schemas/types.yaml#/definitions/uint32-array - items: - minItems: 6 - maxItems: 6 + minItems: 6 + maxItems: 6 description: | Array of 6 integers, specifying bank timings in the following order: Tacp, Tcah, Tcoh, Tacc, Tcos, Tacs. diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,ddr.yaml b/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,ddr.yaml index 84f778a99546bb..e0786153eec736 100644 --- a/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,ddr.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,ddr.yaml @@ -40,6 +40,7 @@ properties: - fsl,p1021-memory-controller - fsl,p2020-memory-controller - fsl,qoriq-memory-controller + - nxp,imx9-memory-controller interrupts: maxItems: 1 @@ -51,13 +52,41 @@ properties: type: boolean reg: - maxItems: 1 + items: + - description: Controller register space + - description: Inject register space + minItems: 1 + + reg-names: + items: + - const: ctrl + - const: inject + minItems: 1 required: - compatible - interrupts - reg +allOf: + - if: + properties: + compatible: + contains: + enum: + - nxp,imx9-memory-controller + then: + properties: + reg: + minItems: 2 + reg-names: + minItems: 2 + else: + properties: + reg: + maxItems: 1 + reg-names: false + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,ifc.yaml b/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,ifc.yaml index d1c3421bee107b..f7cf0f91c1c020 100644 --- a/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,ifc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/fsl/fsl,ifc.yaml @@ -58,17 +58,39 @@ properties: access window as configured. patternProperties: - "^.*@[a-f0-9]+(,[a-f0-9]+)+$": + "^nand@[a-f0-9]+(,[a-f0-9]+)+$": type: object - description: | - Child device nodes describe the devices connected to IFC such as NOR (e.g. - cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices - like FPGAs, CPLDs, etc. + properties: + compatible: + const: fsl,ifc-nand + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 1 + + patternProperties: + "^partition@[0-9a-f]+": + $ref: /schemas/mtd/partitions/partition.yaml# + deprecated: true required: - compatible - reg + additionalProperties: false + + "(flash|fpga|board-control|cpld)@[a-f0-9]+(,[a-f0-9]+)+$": + type: object + oneOf: + - $ref: /schemas/board/fsl,fpga-qixis.yaml# + - $ref: /schemas/mtd/mtd-physmap.yaml# + unevaluatedProperties: false + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/mfd/airoha,en7581-gpio-sysctl.yaml b/Documentation/devicetree/bindings/mfd/airoha,en7581-gpio-sysctl.yaml new file mode 100644 index 00000000000000..4a81ed82ef34dc --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/airoha,en7581-gpio-sysctl.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/airoha,en7581-gpio-sysctl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha EN7581 GPIO System Controller + +maintainers: + - Christian Marangi + - Lorenzo Bianconi + +description: + Airoha EN7581 SoC GPIO system controller which provided a register map + for controlling the GPIO, pins and PWM of the SoC. + +properties: + compatible: + items: + - const: airoha,en7581-gpio-sysctl + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + + pinctrl: + type: object + $ref: /schemas/pinctrl/airoha,en7581-pinctrl.yaml + description: + Child node definition for EN7581 Pin controller + + pwm: + type: object + $ref: /schemas/pwm/airoha,en7581-pwm.yaml + description: + Child node definition for EN7581 PWM controller + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + system-controller@1fbf0200 { + compatible = "airoha,en7581-gpio-sysctl", "syscon", "simple-mfd"; + reg = <0x1fbf0200 0xc0>; + + pinctrl { + compatible = "airoha,en7581-pinctrl"; + + interrupt-parent = <&gic>; + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + mmc-pins { + mux { + function = "emmc"; + groups = "emmc"; + }; + }; + + mdio-pins { + mux { + function = "mdio"; + groups = "mdio"; + }; + + conf { + pins = "gpio2"; + output-enable; + }; + }; + }; + + pwm { + compatible = "airoha,en7581-pwm"; + + #pwm-cells = <3>; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml b/Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml index 86ee69c0f45b5a..c800d5e53b6512 100644 --- a/Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml +++ b/Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml @@ -9,6 +9,8 @@ title: Aspeed System Control Unit description: The Aspeed System Control Unit manages the global behaviour of the SoC, configuring elements such as clocks, pinmux, and reset. + In AST2700 SOC which has two soc connection, each soc have its own scu + register control, ast2700-scu0 for soc0, ast2700-scu1 for soc1. maintainers: - Joel Stanley @@ -21,6 +23,8 @@ properties: - aspeed,ast2400-scu - aspeed,ast2500-scu - aspeed,ast2600-scu + - aspeed,ast2700-scu0 + - aspeed,ast2700-scu1 - const: syscon - const: simple-mfd @@ -30,7 +34,8 @@ properties: ranges: true '#address-cells': - const: 1 + minimum: 1 + maximum: 2 '#size-cells': const: 1 @@ -76,6 +81,7 @@ patternProperties: - aspeed,ast2400-silicon-id - aspeed,ast2500-silicon-id - aspeed,ast2600-silicon-id + - aspeed,ast2700-silicon-id - const: aspeed,silicon-id reg: diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml new file mode 100644 index 00000000000000..86451f151a6aea --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml @@ -0,0 +1,598 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/mediatek,mt6397.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT6397/MT6323 PMIC + +maintainers: + - Sen Chu + - Macpaul Lin + +description: | + MT6397/MT6323 is a power management system chip. + Please see the sub-modules below for supported features. + + MT6397/MT6323 is a multifunction device with the following sub modules: + - Regulators + - RTC + - ADC + - Audio codec + - GPIO + - Clock + - LED + - Keys + - Power controller + + It is interfaced to host controller using SPI interface by a proprietary hardware + called PMIC wrapper or pwrap. MT6397/MT6323 PMIC is a child device of pwrap. + See the following for pwrap node definitions: + Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml + +properties: + compatible: + oneOf: + - enum: + - mediatek,mt6323 + - mediatek,mt6331 # "mediatek,mt6331" for PMIC MT6331 and MT6332. + - mediatek,mt6358 + - mediatek,mt6359 + - mediatek,mt6397 + - items: + - enum: + - mediatek,mt6366 + - const: mediatek,mt6358 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + rtc: + type: object + $ref: /schemas/rtc/rtc.yaml# + unevaluatedProperties: false + description: + MT6397 Real Time Clock. + + properties: + compatible: + oneOf: + - enum: + - mediatek,mt6323-rtc + - mediatek,mt6331-rtc + - mediatek,mt6358-rtc + - mediatek,mt6397-rtc + - items: + - enum: + - mediatek,mt6366-rtc + - const: mediatek,mt6358-rtc + + start-year: true + + required: + - compatible + + regulators: + type: object + description: + List of child nodes that specify the regulators. + additionalProperties: true + + properties: + compatible: + oneOf: + - enum: + - mediatek,mt6323-regulator + - mediatek,mt6358-regulator + - mediatek,mt6359-regulator + - mediatek,mt6397-regulator + - items: + - enum: + - mediatek,mt6366-regulator + - const: mediatek,mt6358-regulator + + required: + - compatible + + adc: + type: object + $ref: /schemas/iio/adc/mediatek,mt6359-auxadc.yaml# + unevaluatedProperties: false + + audio-codec: + type: object + description: + Audio codec support with MT6358 and MT6397. + additionalProperties: true + + properties: + compatible: + oneOf: + - enum: + - mediatek,mt6358-sound + - mediatek,mt6359-codec + - mediatek,mt6397-codec + - items: + - enum: + - mediatek,mt6366-sound + - const: mediatek,mt6358-sound + + required: + - compatible + + clocks: + type: object + additionalProperties: false + description: + This is a clock buffer node for mt6397. However, there are no sub nodes + or any public document exposed in public. + + properties: + compatible: + const: mediatek,mt6397-clk + + '#clock-cells': + const: 1 + + required: + - compatible + + leds: + type: object + additionalProperties: false + description: | + MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED + controllers are defined as the subnode of the function node provided by MT6323 + PMIC controller that is being defined as one kind of Muti-Function Device (MFD) + using shared bus called PMIC wrapper for each subfunction to access remote + MT6323 PMIC hardware. + + Each led is represented as a child node of the mediatek,mt6323-led that + describes the initial behavior for each LED physically and currently only four + LED child nodes can be supported. + + properties: + compatible: + enum: + - mediatek,mt6323-led + - mediatek,mt6331-led + - mediatek,mt6332-led + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^led@[0-3]$": + type: object + $ref: /schemas/leds/common.yaml# + unevaluatedProperties: false + + properties: + reg: + description: + LED channel number (0..3) + minimum: 0 + maximum: 3 + + required: + - reg + + required: + - compatible + - "#address-cells" + - "#size-cells" + + keys: + type: object + $ref: /schemas/input/mediatek,pmic-keys.yaml + unevaluatedProperties: false + description: + Power and Home keys. + + power-controller: + type: object + additionalProperties: false + description: + The power controller which could be found on PMIC is responsible for + externally powering off or on the remote MediaTek SoC through the + circuit BBPU (baseband power up). + + properties: + compatible: + const: mediatek,mt6323-pwrc + + '#power-domain-cells': + const: 0 + + pinctrl: + type: object + $ref: /schemas/pinctrl/mediatek,mt65xx-pinctrl.yaml + unevaluatedProperties: false + description: + Pin controller + +required: + - compatible + - regulators + +additionalProperties: false + +examples: + - | + #include + #include + + pmic { + compatible = "mediatek,mt6323"; + interrupt-parent = <&pio>; + interrupts = <150 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <2>; + + leds { + compatible = "mediatek,mt6323-led"; + #address-cells = <1>; + #size-cells = <0>; + }; + + regulators { + compatible = "mediatek,mt6323-regulator"; + + buck_vproc { + regulator-name = "vproc"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-always-on; + regulator-boot-on; + }; + + buck_vsys { + regulator-name = "vsys"; + regulator-min-microvolt = <1400000>; + regulator-max-microvolt = <2987500>; + regulator-ramp-delay = <25000>; + regulator-always-on; + regulator-boot-on; + }; + + buck_vpa { + regulator-name = "vpa"; + regulator-min-microvolt = < 500000>; + regulator-max-microvolt = <3650000>; + }; + + ldo_vtcxo { + regulator-name = "vtcxo"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <90>; + regulator-always-on; + regulator-boot-on; + }; + + ldo_vcn28 { + regulator-name = "vcn28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <185>; + }; + + ldo_vcn33_bt { + regulator-name = "vcn33_bt"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <185>; + }; + + ldo_vcn33_wifi { + regulator-name = "vcn33_wifi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <185>; + }; + + ldo_va { + regulator-name = "va"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + ldo_vcama { + regulator-name = "vcama"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vio28 { + regulator-name = "vio28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + ldo_vusb { + regulator-name = "vusb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + regulator-boot-on; + }; + + ldo_vmc { + regulator-name = "vmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + ldo_vmch { + regulator-name = "vmch"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + ldo_vemc3v3 { + regulator-name = "vemc3v3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + ldo_vgp1 { + regulator-name = "vgp1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vgp2 { + regulator-name = "vgp2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vgp3 { + regulator-name = "vgp3"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vcn18 { + regulator-name = "vcn18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vsim1 { + regulator-name = "vsim1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vsim2 { + regulator-name = "vsim2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vrtc { + regulator-name = "vrtc"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo_vcamaf { + regulator-name = "vcamaf"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vibr { + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + }; + + ldo_vrf18 { + regulator-name = "vrf18"; + regulator-min-microvolt = <1825000>; + regulator-max-microvolt = <1825000>; + regulator-enable-ramp-delay = <187>; + }; + + ldo_vm { + regulator-name = "vm"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + ldo_vio18 { + regulator-name = "vio18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + ldo_vcamd { + regulator-name = "vcamd"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + ldo_vcamio { + regulator-name = "vcamio"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + }; + + keys { + compatible = "mediatek,mt6323-keys"; + mediatek,long-press-mode = <1>; + power-off-time-sec = <0>; + + power { + linux,keycodes = <116>; + wakeup-source; + }; + + home { + linux,keycodes = <114>; + }; + }; + + power-controller { + compatible = "mediatek,mt6323-pwrc"; + #power-domain-cells = <0>; + }; + + rtc { + compatible = "mediatek,mt6323-rtc"; + }; + }; + + - | + #include + #include + + pmic { + compatible = "mediatek,mt6358"; + interrupt-controller; + #interrupt-cells = <2>; + + audio-codec { + compatible = "mediatek,mt6358-sound"; + Avdd-supply = <&mt6358_vaud28_reg>; + mediatek,dmic-mode = <0>; + }; + + regulators { + compatible = "mediatek,mt6358-regulator"; + + buck_vdram1 { + regulator-name = "vdram1"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2087500>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <0>; + regulator-always-on; + regulator-allowed-modes = <0 1>; + }; + + // ... + + ldo_vsim2 { + regulator-name = "vsim2"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3100000>; + regulator-enable-ramp-delay = <540>; + }; + }; + + rtc { + compatible = "mediatek,mt6358-rtc"; + }; + + keys { + compatible = "mediatek,mt6358-keys"; + + power { + linux,keycodes = ; + wakeup-source; + }; + + home { + linux,keycodes = ; + }; + }; + }; + + - | + #include + + pmic { + compatible = "mediatek,mt6397"; + + interrupt-parent = <&pio>; + interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <2>; + + audio-codec { + compatible = "mediatek,mt6397-codec"; + }; + + clocks { + compatible = "mediatek,mt6397-clk"; + #clock-cells = <1>; + }; + + pinctrl { + compatible = "mediatek,mt6397-pinctrl"; + gpio-controller; + #gpio-cells = <2>; + }; + + regulators { + compatible = "mediatek,mt6397-regulator"; + + buck_vpca15 { + regulator-name = "vpca15"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <200>; + }; + + // ... + + ldo_vibr { + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + }; + + rtc { + compatible = "mediatek,mt6397-rtc"; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt deleted file mode 100644 index 10540aa7afa1af..00000000000000 --- a/Documentation/devicetree/bindings/mfd/mt6397.txt +++ /dev/null @@ -1,110 +0,0 @@ -MediaTek MT6397/MT6323 Multifunction Device Driver - -MT6397/MT6323 is a multifunction device with the following sub modules: -- Regulator -- RTC -- Audio codec -- GPIO -- Clock -- LED -- Keys -- Power controller - -It is interfaced to host controller using SPI interface by a proprietary hardware -called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap. -See the following for pwarp node definitions: -../soc/mediatek/mediatek,pwrap.yaml - -This document describes the binding for MFD device and its sub module. - -Required properties: -compatible: - "mediatek,mt6323" for PMIC MT6323 - "mediatek,mt6331" for PMIC MT6331 and MT6332 - "mediatek,mt6357" for PMIC MT6357 - "mediatek,mt6358" for PMIC MT6358 - "mediatek,mt6359" for PMIC MT6359 - "mediatek,mt6366", "mediatek,mt6358" for PMIC MT6366 - "mediatek,mt6397" for PMIC MT6397 - -Optional subnodes: - -- rtc - Required properties: Should be one of follows - - compatible: "mediatek,mt6323-rtc" - - compatible: "mediatek,mt6331-rtc" - - compatible: "mediatek,mt6358-rtc" - - compatible: "mediatek,mt6397-rtc" - For details, see ../rtc/rtc-mt6397.txt -- regulators - Required properties: - - compatible: "mediatek,mt6323-regulator" - see ../regulator/mt6323-regulator.txt - - compatible: "mediatek,mt6358-regulator" - - compatible: "mediatek,mt6366-regulator", "mediatek-mt6358-regulator" - see ../regulator/mt6358-regulator.txt - - compatible: "mediatek,mt6397-regulator" - see ../regulator/mt6397-regulator.txt -- codec - Required properties: - - compatible: "mediatek,mt6397-codec" or "mediatek,mt6358-sound" -- clk - Required properties: - - compatible: "mediatek,mt6397-clk" -- led - Required properties: - - compatible: "mediatek,mt6323-led" - see ../leds/leds-mt6323.txt - -- keys - Required properties: Should be one of the following - - compatible: "mediatek,mt6323-keys" - - compatible: "mediatek,mt6331-keys" - - compatible: "mediatek,mt6397-keys" - see ../input/mtk-pmic-keys.txt - -- power-controller - Required properties: - - compatible: "mediatek,mt6323-pwrc" - For details, see ../power/reset/mt6323-poweroff.txt - -- pin-controller - Required properties: - - compatible: "mediatek,mt6397-pinctrl" - For details, see ../pinctrl/pinctrl-mt65xx.txt - -Example: - pwrap: pwrap@1000f000 { - compatible = "mediatek,mt8135-pwrap"; - - ... - - pmic { - compatible = "mediatek,mt6397"; - - codec: mt6397codec { - compatible = "mediatek,mt6397-codec"; - }; - - regulators { - compatible = "mediatek,mt6397-regulator"; - - mt6397_vpca15_reg: buck_vpca15 { - regulator-compatible = "buck_vpca15"; - regulator-name = "vpca15"; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <1400000>; - regulator-ramp-delay = <12500>; - regulator-always-on; - }; - - mt6397_vgp4_reg: ldo_vgp4 { - regulator-compatible = "ldo_vgp4"; - regulator-name = "vgp4"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3300000>; - regulator-enable-ramp-delay = <218>; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index a2b2fbf77d5cb8..078a6886f8b1e9 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -76,12 +76,14 @@ properties: - qcom,pmc8180 - qcom,pmc8180c - qcom,pmc8380 + - qcom,pmd8028 - qcom,pmd9635 - qcom,pmi632 - qcom,pmi8950 - qcom,pmi8962 - qcom,pmi8994 - qcom,pmi8998 + - qcom,pmih0108 - qcom,pmk8002 - qcom,pmk8350 - qcom,pmk8550 diff --git a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml index 7d0b0b40315051..79add913e35c84 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml @@ -21,6 +21,9 @@ properties: - qcom,msm8998-tcsr - qcom,qcm2290-tcsr - qcom,qcs404-tcsr + - qcom,qcs615-tcsr + - qcom,qcs8300-tcsr + - qcom,sa8255p-tcsr - qcom,sa8775p-tcsr - qcom,sc7180-tcsr - qcom,sc7280-tcsr @@ -47,6 +50,7 @@ properties: - qcom,tcsr-msm8226 - qcom,tcsr-msm8660 - qcom,tcsr-msm8916 + - qcom,tcsr-msm8917 - qcom,tcsr-msm8953 - qcom,tcsr-msm8960 - qcom,tcsr-msm8974 diff --git a/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml new file mode 100644 index 00000000000000..f053303ab1e6b4 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/realtek,rtl9301-switch.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/realtek,rtl9301-switch.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek Switch with Internal CPU + +maintainers: + - Chris Packham + +description: + The RTL9300 is a series of is an Ethernet switches with an integrated CPU. A + number of different peripherals are accessed through a common register block, + represented here as a syscon node. + +properties: + compatible: + items: + - enum: + - realtek,rtl9301-switch + - realtek,rtl9302b-switch + - realtek,rtl9302c-switch + - realtek,rtl9303-switch + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 1 + +patternProperties: + 'reboot@[0-9a-f]+$': + $ref: /schemas/power/reset/syscon-reboot.yaml# + + 'i2c@[0-9a-f]+$': + $ref: /schemas/i2c/realtek,rtl9301-i2c.yaml# + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + ethernet-switch@1b000000 { + compatible = "realtek,rtl9301-switch", "syscon", "simple-mfd"; + reg = <0x1b000000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + + reboot@c { + compatible = "syscon-reboot"; + reg = <0x0c 0x4>; + value = <0x01>; + }; + + i2c@36c { + compatible = "realtek,rtl9301-i2c"; + reg = <0x36c 0x14>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + gpio@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + + i2c@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + gpio@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; + + i2c@388 { + compatible = "realtek,rtl9301-i2c"; + reg = <0x388 0x14>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@7 { + reg = <7>; + #address-cells = <1>; + #size-cells = <0>; + gpio@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; + }; + diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml index fa17686a64f79f..09e7d68e92bf3d 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml @@ -55,14 +55,15 @@ properties: minimum: 0 maximum: 1 - rohm,charger-sense-resistor-ohms: - minimum: 10000000 - maximum: 50000000 + rohm,charger-sense-resistor-micro-ohms: + minimum: 10000 + maximum: 50000 + default: 30000 description: | BD71827 and BD71828 have SAR ADC for measuring charging currents. External sense resistor (RSENSE in data sheet) should be used. If some - other but 30MOhm resistor is used the resistance value should be given - here in Ohms. + other but 30mOhm resistor is used the resistance value should be given + here in microohms. regulators: $ref: /schemas/regulator/rohm,bd71828-regulator.yaml @@ -114,7 +115,7 @@ examples: #gpio-cells = <2>; gpio-reserved-ranges = <0 1>, <2 1>; - rohm,charger-sense-resistor-ohms = <10000000>; + rohm,charger-sense-resistor-micro-ohms = <10000>; regulators { buck1: BUCK1 { diff --git a/Documentation/devicetree/bindings/mfd/samsung,s2dos05.yaml b/Documentation/devicetree/bindings/mfd/samsung,s2dos05.yaml new file mode 100644 index 00000000000000..b85285720c16da --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/samsung,s2dos05.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/samsung,s2dos05.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung S2DOS05 Power Management IC + +maintainers: + - Dzmitry Sankouski + +description: + This is a device tree bindings for S2DOS family of Power Management IC (PMIC). + + The S2DOS05 is a companion power management IC for the panel and touchscreen + in smart phones. Provides voltage regulators and + ADC for power/current measurements. + + Regulator section has 4 LDO and 1 BUCK regulators and also + provides ELVDD, ELVSS, AVDD lines. + +properties: + compatible: + const: samsung,s2dos05 + + reg: + maxItems: 1 + + regulators: + patternProperties: + "^buck|ldo[1-4]$": + type: object + $ref: /schemas/regulator/regulator.yaml# + unevaluatedProperties: false + + required: + - regulator-name + + additionalProperties: false + +required: + - compatible + - reg + - regulators + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@60 { + compatible = "samsung,s2dos05"; + reg = <0x60>; + + regulators { + ldo1 { + regulator-active-discharge = <1>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2000000>; + regulator-name = "ldo1"; + }; + + ldo2 { + regulator-active-discharge = <1>; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "ldo2"; + }; + + ldo3 { + regulator-active-discharge = <1>; + regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-name = "ldo3"; + }; + + ldo4 { + regulator-active-discharge = <1>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3775000>; + regulator-name = "ldo4"; + }; + + buck { + regulator-active-discharge = <1>; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <2100000>; + regulator-name = "buck"; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/mfd/sprd,sc2731.yaml b/Documentation/devicetree/bindings/mfd/sprd,sc2731.yaml new file mode 100644 index 00000000000000..8beec7e8e4c69a --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/sprd,sc2731.yaml @@ -0,0 +1,252 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/sprd,sc2731.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum SC27xx PMIC + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +description: | + Spreadtrum PMICs belonging to the SC27xx series integrate all mobile handset + power management, audio codec, battery management and user interface support + functions in a single chip. They have 6 major functional blocks: + - DCDCs to support CPU, memory + - LDOs to support both internal and external requirements + - Battery management system, such as charger, fuel gauge + - Audio codec + - User interface functions, such as indicator, flash LED and so on + - IC level interface, such as power on/off control, RTC, typec and so on + +properties: + $nodename: + pattern: '^pmic@[0-9a-f]+$' + + compatible: + enum: + - sprd,sc2720 + - sprd,sc2721 + - sprd,sc2723 + - sprd,sc2730 + - sprd,sc2731 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-controller: true + spi-max-frequency: true + + '#address-cells': + const: 1 + + '#interrupt-cells': + const: 1 + + '#size-cells': + const: 0 + + regulators: + type: object + $ref: /schemas/regulator/sprd,sc2731-regulator.yaml# + +patternProperties: + "^adc@[0-9a-f]+$": + type: object + $ref: /schemas/iio/adc/sprd,sc2720-adc.yaml# + + "^charger@[0-9a-f]+$": + type: object + $ref: /schemas/power/supply/sc2731-charger.yaml# + + "^efuse@[0-9a-f]+$": + type: object + additionalProperties: true + properties: + compatible: + enum: + - sprd,sc2720-efuse + - sprd,sc2721-efuse + - sprd,sc2723-efuse + - sprd,sc2730-efuse + - sprd,sc2731-efuse + + "^fuel-gauge@[0-9a-f]+$": + type: object + $ref: /schemas/power/supply/sc27xx-fg.yaml# + + "^gpio@[0-9a-f]+$": + type: object + $ref: /schemas/gpio/sprd,gpio-eic.yaml# + + "^led-controller@[0-9a-f]+$": + type: object + $ref: /schemas/leds/sprd,sc2731-bltc.yaml# + + "^rtc@[0-9a-f]+$": + type: object + $ref: /schemas/rtc/sprd,sc2731-rtc.yaml# + + "^vibrator@[0-9a-f]+$": + type: object + $ref: /schemas/input/sprd,sc27xx-vibrator.yaml# + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - spi-max-frequency + - '#address-cells' + - '#interrupt-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + sc2731_pmic: pmic@0 { + compatible = "sprd,sc2731"; + reg = <0>; + interrupts = ; + interrupt-controller; + spi-max-frequency = <26000000>; + #address-cells = <1>; + #interrupt-cells = <1>; + #size-cells = <0>; + + charger@0 { + compatible = "sprd,sc2731-charger"; + reg = <0x0>; + phys = <&ssphy>; + monitored-battery = <&bat>; + }; + + led-controller@200 { + compatible = "sprd,sc2731-bltc"; + reg = <0x200>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0x0>; + color = ; + }; + + led@1 { + reg = <0x1>; + color = ; + }; + + led@2 { + reg = <0x2>; + color = ; + }; + }; + + rtc@280 { + compatible = "sprd,sc2731-rtc"; + reg = <0x280>; + interrupt-parent = <&sc2731_pmic>; + interrupts = <2>; + }; + + pmic_eic: gpio@300 { + compatible = "sprd,sc2731-eic"; + reg = <0x300>; + interrupt-parent = <&sc2731_pmic>; + interrupts = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + efuse@380 { + compatible = "sprd,sc2731-efuse"; + reg = <0x380>; + hwlocks = <&hwlock 12>; + #address-cells = <1>; + #size-cells = <1>; + + /* Data cells */ + fgu_calib: calib@6 { + reg = <0x6 0x2>; + bits = <0 9>; + }; + + adc_big_scale: calib@24 { + reg = <0x24 0x2>; + }; + + adc_small_scale: calib@26 { + reg = <0x26 0x2>; + }; + }; + + adc@480 { + compatible = "sprd,sc2731-adc"; + reg = <0x480>; + interrupt-parent = <&sc2731_pmic>; + interrupts = <0>; + #io-channel-cells = <1>; + hwlocks = <&hwlock 4>; + nvmem-cells = <&adc_big_scale>, <&adc_small_scale>; + nvmem-cell-names = "big_scale_calib", "small_scale_calib"; + }; + + fuel-gauge@a00 { + compatible = "sprd,sc2731-fgu"; + reg = <0xa00>; + battery-detect-gpios = <&pmic_eic 9 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&sc2731_pmic>; + interrupts = <4>; + io-channels = <&pmic_adc 5>, <&pmic_adc 14>; + io-channel-names = "bat-temp", "charge-vol"; + nvmem-cells = <&fgu_calib>; + nvmem-cell-names = "fgu_calib"; + monitored-battery = <&bat>; + sprd,calib-resistance-micro-ohms = <21500>; + }; + + vibrator@ec8 { + compatible = "sprd,sc2731-vibrator"; + reg = <0xec8>; + }; + + regulators { + compatible = "sprd,sc2731-regulator"; + + BUCK_CPU0 { + regulator-name = "vddarm0"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1996875>; + regulator-ramp-delay = <25000>; + regulator-always-on; + }; + + LDO_CAMA0 { + regulator-name = "vddcama0"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3750000>; + regulator-enable-ramp-delay = <100>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/mfd/sprd,sc27xx-pmic.txt b/Documentation/devicetree/bindings/mfd/sprd,sc27xx-pmic.txt deleted file mode 100644 index 21b9a897fca5db..00000000000000 --- a/Documentation/devicetree/bindings/mfd/sprd,sc27xx-pmic.txt +++ /dev/null @@ -1,40 +0,0 @@ -Spreadtrum SC27xx Power Management Integrated Circuit (PMIC) - -The Spreadtrum SC27xx series PMICs contain SC2720, SC2721, SC2723, SC2730 -and SC2731. The Spreadtrum PMIC belonging to SC27xx series integrates all -mobile handset power management, audio codec, battery management and user -interface support function in a single chip. It has 6 major functional -blocks: -- DCDCs to support CPU, memory. -- LDOs to support both internal and external requirement. -- Battery management system, such as charger, fuel gauge. -- Audio codec. -- User interface function, such as indicator, flash LED and so on. -- IC level interface, such as power on/off control, RTC and typec and so on. - -Required properties: -- compatible: Should be one of the following: - "sprd,sc2720" - "sprd,sc2721" - "sprd,sc2723" - "sprd,sc2730" - "sprd,sc2731" -- reg: The address of the device chip select, should be 0. -- spi-max-frequency: Typically set to 26000000. -- interrupts: The interrupt line the device is connected to. -- interrupt-controller: Marks the device node as an interrupt controller. -- #interrupt-cells: The number of cells to describe an PMIC IRQ, must be 2. -- #address-cells: Child device offset number of cells, must be 1. -- #size-cells: Child device size number of cells, must be 0. - -Example: -pmic@0 { - compatible = "sprd,sc2731"; - reg = <0>; - spi-max-frequency = <26000000>; - interrupts = ; - interrupt-controller; - #interrupt-cells = <2>; - #address-cells = <1>; - #size-cells = <0>; -}; diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index cc9b17ad69f23d..b414de4fa779ba 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -88,6 +88,7 @@ select: - mediatek,mt8173-pctl-a-syscfg - mediatek,mt8365-syscfg - microchip,lan966x-cpu-syscon + - microchip,mpfs-sysreg-scb - microchip,sam9x60-sfr - microchip,sama7g5-ddr3phy - mscc,ocelot-cpu-syscon @@ -185,6 +186,7 @@ properties: - mediatek,mt8173-pctl-a-syscfg - mediatek,mt8365-syscfg - microchip,lan966x-cpu-syscon + - microchip,mpfs-sysreg-scb - microchip,sam9x60-sfr - microchip,sama7g5-ddr3phy - mscc,ocelot-cpu-syscon diff --git a/Documentation/devicetree/bindings/mfd/ti,twl.yaml b/Documentation/devicetree/bindings/mfd/ti,twl.yaml index e94b0fd7af0f85..f162ab60c09b56 100644 --- a/Documentation/devicetree/bindings/mfd/ti,twl.yaml +++ b/Documentation/devicetree/bindings/mfd/ti,twl.yaml @@ -54,7 +54,7 @@ allOf: $ref: /schemas/iio/adc/ti,twl4030-madc.yaml unevaluatedProperties: false - bci: + charger: type: object $ref: /schemas/power/supply/twl4030-charger.yaml unevaluatedProperties: false @@ -105,6 +105,11 @@ allOf: regulator-initial-mode: false properties: + charger: + type: object + properties: + compatible: + const: ti,twl6030-charger gpadc: type: object properties: @@ -136,6 +141,13 @@ allOf: regulator-initial-mode: false properties: + charger: + type: object + properties: + compatible: + items: + - const: ti,twl6032-charger + - const: ti,twl6030-charger gpadc: type: object properties: @@ -169,6 +181,14 @@ properties: "#clock-cells": const: 1 + charger: + type: object + additionalProperties: true + properties: + compatible: true + required: + - compatible + rtc: type: object additionalProperties: false @@ -222,6 +242,14 @@ examples: interrupt-controller; #interrupt-cells = <1>; + charger { + compatible = "ti,twl6030-charger"; + interrupts = <2>, <5>; + io-channels = <&gpadc 10>; + io-channel-names = "vusb"; + monitored-battery = <&bat>; + }; + gpadc { compatible = "ti,twl6030-gpadc"; interrupts = <6>; @@ -259,7 +287,7 @@ examples: interrupt-controller; #interrupt-cells = <1>; - bci { + charger { compatible = "ti,twl4030-bci"; interrupts = <9>, <2>; bci3v1-supply = <&vusb3v1>; diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml index 14ab367fc88715..3f7661bdd20204 100644 --- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml +++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml @@ -71,6 +71,7 @@ allOf: - x-powers,axp15060 - x-powers,axp305 - x-powers,axp313a + - x-powers,axp323 then: required: @@ -82,6 +83,7 @@ allOf: contains: enum: - x-powers,axp313a + - x-powers,axp323 - x-powers,axp15060 - x-powers,axp717 @@ -100,6 +102,7 @@ properties: - x-powers,axp221 - x-powers,axp223 - x-powers,axp313a + - x-powers,axp323 - x-powers,axp717 - x-powers,axp803 - x-powers,axp806 diff --git a/Documentation/devicetree/bindings/mfd/zii,rave-sp.txt b/Documentation/devicetree/bindings/mfd/zii,rave-sp.txt deleted file mode 100644 index e0f901edc06356..00000000000000 --- a/Documentation/devicetree/bindings/mfd/zii,rave-sp.txt +++ /dev/null @@ -1,39 +0,0 @@ -Zodiac Inflight Innovations RAVE Supervisory Processor - -RAVE Supervisory Processor communicates with SoC over UART. It is -expected that its Device Tree node is specified as a child of a node -corresponding to UART controller used for communication. - -Required parent device properties: - - - compatible: Should be one of: - - "zii,rave-sp-niu" - - "zii,rave-sp-mezz" - - "zii,rave-sp-esb" - - "zii,rave-sp-rdu1" - - "zii,rave-sp-rdu2" - - - current-speed: Should be set to baud rate SP device is using - -RAVE SP consists of the following sub-devices: - -Device Description ------- ----------- -rave-sp-wdt : Watchdog -rave-sp-nvmem : Interface to onboard EEPROM -rave-sp-backlight : Display backlight -rave-sp-hwmon : Interface to onboard hardware sensors -rave-sp-leds : Interface to onboard LEDs -rave-sp-input : Interface to onboard power button - -Example of usage: - - rdu { - compatible = "zii,rave-sp-rdu2"; - current-speed = <1000000>; - - watchdog { - compatible = "zii,rave-sp-watchdog"; - }; - }; - diff --git a/Documentation/devicetree/bindings/mfd/zii,rave-sp.yaml b/Documentation/devicetree/bindings/mfd/zii,rave-sp.yaml new file mode 100644 index 00000000000000..1d078c5ef16898 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/zii,rave-sp.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/zii,rave-sp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zodiac Inflight Innovations RAVE Supervisory Processor + +maintainers: + - Frank Li + +description: + RAVE Supervisory Processor communicates with SoC over UART. It is + expected that its Device Tree node is specified as a child of a node + corresponding to UART controller used for communication. + +properties: + compatible: + enum: + - zii,rave-sp-niu + - zii,rave-sp-mezz + - zii,rave-sp-esb + - zii,rave-sp-rdu1 + - zii,rave-sp-rdu2 + + "#address-cells": + const: 1 + + "#size-cells": + const: 1 + + watchdog: + $ref: /schemas/watchdog/zii,rave-sp-wdt.yaml + + backlight: + $ref: /schemas/leds/backlight/zii,rave-sp-backlight.yaml + + pwrbutton: + $ref: /schemas/input/zii,rave-sp-pwrbutton.yaml + +patternProperties: + '^eeprom@[0-9a-f]+$': + $ref: /schemas/nvmem/zii,rave-sp-eeprom.yaml + +required: + - compatible + +allOf: + - $ref: /schemas/serial/serial-peripheral-props.yaml + +unevaluatedProperties: false + +examples: + - | + mfd { + compatible = "zii,rave-sp-rdu2"; + current-speed = <1000000>; + + watchdog { + compatible = "zii,rave-sp-watchdog"; + }; + }; + diff --git a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml index 6c40611405a087..0432cc96f7cac9 100644 --- a/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/cdns,sdhci.yaml @@ -15,6 +15,7 @@ properties: - enum: - amd,pensando-elba-sd4hc - microchip,mpfs-sd4hc + - microchip,pic64gx-sd4hc - socionext,uniphier-sd4hc - const: cdns,sd4hc @@ -120,7 +121,7 @@ required: - clocks allOf: - - $ref: mmc-controller.yaml + - $ref: sdhci-common.yaml - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/mmc/mmc-card.yaml b/Documentation/devicetree/bindings/mmc/mmc-card.yaml index fd347126449ac0..1d91d4272de05e 100644 --- a/Documentation/devicetree/bindings/mmc/mmc-card.yaml +++ b/Documentation/devicetree/bindings/mmc/mmc-card.yaml @@ -13,6 +13,10 @@ description: | This documents describes the devicetree bindings for a mmc-host controller child node describing a mmc-card / an eMMC. + It's possible to define a fixed partition table for an eMMC for the user + partition, the 2 BOOT partition (boot1/2) and the 4 GP (gp1/2/3/4) if supported + by the eMMC. + properties: compatible: const: mmc-card @@ -26,6 +30,24 @@ properties: Use this to indicate that the mmc-card has a broken hpi implementation, and that hpi should not be used. +patternProperties: + "^partitions(-boot[12]|-gp[14])?$": + $ref: /schemas/mtd/partitions/partitions.yaml + + patternProperties: + "^partition@[0-9a-f]+$": + $ref: /schemas/mtd/partitions/partition.yaml + + properties: + reg: + description: Must be multiple of 512 as it's converted + internally from bytes to SECTOR_SIZE (512 bytes) + + required: + - reg + + unevaluatedProperties: false + required: - compatible - reg @@ -42,6 +64,36 @@ examples: compatible = "mmc-card"; reg = <0>; broken-hpi; + + partitions { + compatible = "fixed-partitions"; + + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "kernel"; /* Kernel */ + reg = <0x0 0x2000000>; /* 32 MB */ + }; + + partition@2000000 { + label = "rootfs"; + reg = <0x2000000 0x40000000>; /* 1GB */ + }; + }; + + partitions-boot1 { + compatible = "fixed-partitions"; + + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl"; + reg = <0x0 0x2000000>; /* 32MB */ + read-only; + }; + }; }; }; diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml index c532ec92d2d9c6..f86ebd81f5a560 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml @@ -21,9 +21,11 @@ properties: - mediatek,mt7620-mmc - mediatek,mt7622-mmc - mediatek,mt7986-mmc + - mediatek,mt7988-mmc - mediatek,mt8135-mmc - mediatek,mt8173-mmc - mediatek,mt8183-mmc + - mediatek,mt8196-mmc - mediatek,mt8516-mmc - items: - const: mediatek,mt7623-mmc @@ -190,6 +192,7 @@ allOf: - mediatek,mt8186-mmc - mediatek,mt8188-mmc - mediatek,mt8195-mmc + - mediatek,mt8196-mmc - mediatek,mt8516-mmc then: properties: @@ -263,6 +266,27 @@ allOf: - const: bus_clk - const: sys_cg + - if: + properties: + compatible: + contains: + enum: + - mediatek,mt7988-mmc + then: + properties: + clocks: + items: + - description: source clock + - description: HCLK which used for host + - description: Advanced eXtensible Interface + - description: Advanced High-performance Bus clock + clock-names: + items: + - const: source + - const: hclk + - const: axi_cg + - const: ahb_cg + - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index 11979b026d2110..8b393e26e025f3 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -38,11 +38,14 @@ properties: - enum: - qcom,ipq5018-sdhci - qcom,ipq5332-sdhci + - qcom,ipq5424-sdhci - qcom,ipq6018-sdhci - qcom,ipq9574-sdhci - qcom,qcm2290-sdhci - qcom,qcs404-sdhci + - qcom,qcs615-sdhci - qcom,qdu1000-sdhci + - qcom,sar2130p-sdhci - qcom,sc7180-sdhci - qcom,sc7280-sdhci - qcom,sc8280xp-sdhci @@ -62,6 +65,7 @@ properties: - qcom,sm8450-sdhci - qcom,sm8550-sdhci - qcom,sm8650-sdhci + - qcom,x1e80100-sdhci - const: qcom,sdhci-msm-v5 # for sdcc version 5.0 reg: diff --git a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml index 058253d6d889c2..62086366837cf5 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/fixed-partitions.yaml @@ -82,7 +82,7 @@ examples: uimage@100000 { reg = <0x0100000 0x200000>; - compress = "lzma"; + compression = "lzma"; }; }; diff --git a/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml index 37a65badb448a1..0a2d7baf5db32c 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml @@ -34,6 +34,12 @@ properties: firmware-name: maxItems: 1 + device-wakeup-gpios: + maxItems: 1 + description: + Host-To-Chip power save mechanism is driven by this GPIO + connected to BT_WAKE_IN pin of the NXP chipset. + required: - compatible @@ -41,10 +47,12 @@ additionalProperties: false examples: - | + #include serial { bluetooth { compatible = "nxp,88w8987-bt"; fw-init-baudrate = <3000000>; firmware-name = "uartuart8987_bt_v0.bin"; + device-wakeup-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; }; }; diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml index 30c0c3e6f37a4a..62ca63e8a26fda 100644 --- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml +++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml @@ -34,6 +34,7 @@ properties: - microchip,ksz9563 - microchip,ksz8563 - microchip,ksz8567 + - microchip,lan9646 reset-gpios: description: @@ -81,6 +82,26 @@ properties: interrupts: maxItems: 1 + mdio: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + properties: + mdio-parent-bus: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle pointing to the MDIO bus controller connected to the + secondary MDIO interface. This property should be used when + the internal MDIO bus is accessed via a secondary MDIO + interface rather than the primary management interface. + + patternProperties: + "^ethernet-phy@[0-9a-f]$": + type: object + $ref: /schemas/net/ethernet-phy.yaml# + unevaluatedProperties: false + description: + Integrated PHY node + required: - compatible - reg @@ -138,7 +159,6 @@ examples: pinctrl-0 = <&pinctrl_spi_ksz>; cs-gpios = <&pioC 25 0>; - id = <1>; ksz9477: switch@0 { compatible = "microchip,ksz9477"; diff --git a/Documentation/devicetree/bindings/net/dsa/realtek.yaml b/Documentation/devicetree/bindings/net/dsa/realtek.yaml index 70b6bda3cf98e5..f348e66fb51583 100644 --- a/Documentation/devicetree/bindings/net/dsa/realtek.yaml +++ b/Documentation/devicetree/bindings/net/dsa/realtek.yaml @@ -147,7 +147,7 @@ examples: #include platform { - switch { + ethernet-switch { compatible = "realtek,rtl8366rb"; /* 22 = MDIO (has input reads), 21 = MDC (clock, output only) */ mdc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; @@ -163,35 +163,35 @@ examples: #interrupt-cells = <1>; }; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "lan0"; phy-handle = <&phy0>; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan1"; phy-handle = <&phy1>; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan2"; phy-handle = <&phy2>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan3"; phy-handle = <&phy3>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "wan"; phy-handle = <&phy4>; }; - port@5 { + ethernet-port@5 { reg = <5>; ethernet = <&gmac0>; phy-mode = "rgmii"; @@ -241,7 +241,7 @@ examples: #include platform { - switch { + ethernet-switch { compatible = "realtek,rtl8365mb"; mdc-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>; mdio-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>; @@ -255,30 +255,30 @@ examples: #interrupt-cells = <1>; }; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "swp0"; phy-handle = <ðphy0>; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "swp1"; phy-handle = <ðphy1>; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "swp2"; phy-handle = <ðphy2>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "swp3"; phy-handle = <ðphy3>; }; - port@6 { + ethernet-port@6 { reg = <6>; ethernet = <&fec1>; phy-mode = "rgmii"; @@ -330,7 +330,7 @@ examples: #address-cells = <1>; #size-cells = <0>; - switch@29 { + ethernet-switch@29 { compatible = "realtek,rtl8365mb"; reg = <29>; @@ -344,36 +344,36 @@ examples: #interrupt-cells = <1>; }; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "lan4"; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan3"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan1"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "wan"; }; - port@7 { + ethernet-port@7 { reg = <7>; ethernet = <ðernet>; phy-mode = "rgmii"; diff --git a/Documentation/devicetree/bindings/net/ethernet-phy.yaml b/Documentation/devicetree/bindings/net/ethernet-phy.yaml index d9b62741a2259b..2c71454ae8e362 100644 --- a/Documentation/devicetree/bindings/net/ethernet-phy.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-phy.yaml @@ -158,6 +158,27 @@ properties: Mark the corresponding energy efficient ethernet mode as broken and request the ethernet to stop advertising it. + timing-role: + $ref: /schemas/types.yaml#/definitions/string + enum: + - forced-master + - forced-slave + - preferred-master + - preferred-slave + description: | + Specifies the timing role of the PHY in the network link. This property is + required for setups where the role must be explicitly assigned via the + device tree due to limitations in hardware strapping or incorrect strap + configurations. + It is applicable to Single Pair Ethernet (1000/100/10Base-T1) and other + PHY types, including 1000Base-T, where it controls whether the PHY should + be a master (clock source) or a slave (clock receiver). + + - 'forced-master': The PHY is forced to operate as a master. + - 'forced-slave': The PHY is forced to operate as a slave. + - 'preferred-master': Prefer the PHY to be master but allow negotiation. + - 'preferred-slave': Prefer the PHY to be slave but allow negotiation. + pses: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 diff --git a/Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml b/Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml index c1dd6aa04321e2..71c43ece829549 100644 --- a/Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml +++ b/Documentation/devicetree/bindings/net/fsl,enetc-mdio.yaml @@ -20,10 +20,13 @@ maintainers: properties: compatible: - items: - - enum: - - pci1957,ee01 - - const: fsl,enetc-mdio + oneOf: + - items: + - enum: + - pci1957,ee01 + - const: fsl,enetc-mdio + - items: + - const: pci1131,ee00 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/net/fsl,enetc.yaml b/Documentation/devicetree/bindings/net/fsl,enetc.yaml index e152c93998fe1f..ca70f005017113 100644 --- a/Documentation/devicetree/bindings/net/fsl,enetc.yaml +++ b/Documentation/devicetree/bindings/net/fsl,enetc.yaml @@ -20,14 +20,25 @@ maintainers: properties: compatible: - items: + oneOf: + - items: + - enum: + - pci1957,e100 + - const: fsl,enetc - enum: - - pci1957,e100 - - const: fsl,enetc + - pci1131,e101 reg: maxItems: 1 + clocks: + items: + - description: MAC transmit/receive reference clock + + clock-names: + items: + - const: ref + mdio: $ref: mdio.yaml unevaluatedProperties: false @@ -40,6 +51,17 @@ required: allOf: - $ref: /schemas/pci/pci-device.yaml - $ref: ethernet-controller.yaml + - if: + not: + properties: + compatible: + contains: + enum: + - pci1131,e101 + then: + properties: + clocks: false + clock-names: false unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/net/fsl,fec.yaml b/Documentation/devicetree/bindings/net/fsl,fec.yaml index 5536c06139cae5..24e863fdbdab08 100644 --- a/Documentation/devicetree/bindings/net/fsl,fec.yaml +++ b/Documentation/devicetree/bindings/net/fsl,fec.yaml @@ -183,6 +183,13 @@ properties: description: Register bits of stop mode control, the format is <&gpr req_gpr req_bit>. + fsl,pps-channel: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + description: + Specifies to which timer instance the PPS signal is routed. + enum: [0, 1, 2, 3] + mdio: $ref: mdio.yaml# unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/net/marvell,aquantia.yaml b/Documentation/devicetree/bindings/net/marvell,aquantia.yaml index 9854fab4c4db08..f269615126d86c 100644 --- a/Documentation/devicetree/bindings/net/marvell,aquantia.yaml +++ b/Documentation/devicetree/bindings/net/marvell,aquantia.yaml @@ -48,6 +48,12 @@ properties: firmware-name: description: specify the name of PHY firmware to load + marvell,mdi-cfg-order: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + description: + force normal (0) or reverse (1) order of MDI pairs, overriding MDI_CFG bootstrap pin. + nvmem-cells: description: phandle to the firmware nvmem cell maxItems: 1 diff --git a/Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml b/Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml index 71c25c4580eae3..cc674b21588c47 100644 --- a/Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml +++ b/Documentation/devicetree/bindings/net/mdio-mux-gpio.yaml @@ -53,37 +53,21 @@ examples: ethernet-phy@1 { reg = <1>; - marvell,reg-init = <3 0x10 0 0x5777>, - <3 0x11 0 0x00aa>, - <3 0x12 0 0x4105>, - <3 0x13 0 0x0a60>; interrupt-parent = <&gpio>; interrupts = <10 8>; /* Pin 10, active low */ }; ethernet-phy@2 { reg = <2>; - marvell,reg-init = <3 0x10 0 0x5777>, - <3 0x11 0 0x00aa>, - <3 0x12 0 0x4105>, - <3 0x13 0 0x0a60>; interrupt-parent = <&gpio>; interrupts = <10 8>; /* Pin 10, active low */ }; ethernet-phy@3 { reg = <3>; - marvell,reg-init = <3 0x10 0 0x5777>, - <3 0x11 0 0x00aa>, - <3 0x12 0 0x4105>, - <3 0x13 0 0x0a60>; interrupt-parent = <&gpio>; interrupts = <10 8>; /* Pin 10, active low */ }; ethernet-phy@4 { reg = <4>; - marvell,reg-init = <3 0x10 0 0x5777>, - <3 0x11 0 0x00aa>, - <3 0x12 0 0x4105>, - <3 0x13 0 0x0a60>; interrupt-parent = <&gpio>; interrupts = <10 8>; /* Pin 10, active low */ }; @@ -96,37 +80,21 @@ examples: ethernet-phy@1 { reg = <1>; - marvell,reg-init = <3 0x10 0 0x5777>, - <3 0x11 0 0x00aa>, - <3 0x12 0 0x4105>, - <3 0x13 0 0x0a60>; interrupt-parent = <&gpio>; interrupts = <12 8>; /* Pin 12, active low */ }; ethernet-phy@2 { reg = <2>; - marvell,reg-init = <3 0x10 0 0x5777>, - <3 0x11 0 0x00aa>, - <3 0x12 0 0x4105>, - <3 0x13 0 0x0a60>; interrupt-parent = <&gpio>; interrupts = <12 8>; /* Pin 12, active low */ }; ethernet-phy@3 { reg = <3>; - marvell,reg-init = <3 0x10 0 0x5777>, - <3 0x11 0 0x00aa>, - <3 0x12 0 0x4105>, - <3 0x13 0 0x0a60>; interrupt-parent = <&gpio>; interrupts = <12 8>; /* Pin 12, active low */ }; ethernet-phy@4 { reg = <4>; - marvell,reg-init = <3 0x10 0 0x5777>, - <3 0x11 0 0x00aa>, - <3 0x12 0 0x4105>, - <3 0x13 0 0x0a60>; interrupt-parent = <&gpio>; interrupts = <12 8>; /* Pin 12, active low */ }; diff --git a/Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml b/Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml index fcafef8d5a338c..dedfad526666c0 100644 --- a/Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml +++ b/Documentation/devicetree/bindings/net/microchip,sparx5-switch.yaml @@ -9,6 +9,7 @@ title: Microchip Sparx5 Ethernet switch controller maintainers: - Steen Hegelund - Lars Povlsen + - Daniel Machon description: | The SparX-5 Enterprise Ethernet switch family provides a rich set of @@ -34,7 +35,24 @@ properties: pattern: "^switch@[0-9a-f]+$" compatible: - const: microchip,sparx5-switch + oneOf: + - enum: + - microchip,lan9691-switch + - microchip,sparx5-switch + - items: + - enum: + - microchip,lan969c-switch + - microchip,lan969b-switch + - microchip,lan969a-switch + - microchip,lan9699-switch + - microchip,lan9698-switch + - microchip,lan9697-switch + - microchip,lan9696-switch + - microchip,lan9695-switch + - microchip,lan9694-switch + - microchip,lan9693-switch + - microchip,lan9692-switch + - const: microchip,lan9691-switch reg: items: diff --git a/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml b/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml index 6924aff0b2c50e..364b361511808b 100644 --- a/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml +++ b/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml @@ -17,6 +17,7 @@ properties: - enum: - nxp,nq310 - nxp,pn547 + - nxp,pn553 - const: nxp,nxp-nci-i2c enable-gpios: diff --git a/Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml b/Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml new file mode 100644 index 00000000000000..97389fd5dbbfa2 --- /dev/null +++ b/Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/nxp,netc-blk-ctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NETC Blocks Control + +description: + Usually, NETC has 2 blocks of 64KB registers, integrated endpoint register + block (IERB) and privileged register block (PRB). IERB is used for pre-boot + initialization for all NETC devices, such as ENETC, Timer, EMIDO and so on. + And PRB controls global reset and global error handling for NETC. Moreover, + for the i.MX platform, there is also a NETCMIX block for link configuration, + such as MII protocol, PCS protocol, etc. + +maintainers: + - Wei Fang + - Clark Wang + +properties: + compatible: + enum: + - nxp,imx95-netc-blk-ctrl + + reg: + maxItems: 3 + + reg-names: + items: + - const: ierb + - const: prb + - const: netcmix + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + ranges: true + + clocks: + maxItems: 1 + + clock-names: + items: + - const: ipg + + power-domains: + maxItems: 1 + +patternProperties: + "^pcie@[0-9a-f]+$": + $ref: /schemas/pci/host-generic-pci.yaml# + +required: + - compatible + - reg + - reg-names + - "#address-cells" + - "#size-cells" + - ranges + +additionalProperties: false + +examples: + - | + bus { + #address-cells = <2>; + #size-cells = <2>; + + system-controller@4cde0000 { + compatible = "nxp,imx95-netc-blk-ctrl"; + reg = <0x0 0x4cde0000 0x0 0x10000>, + <0x0 0x4cdf0000 0x0 0x10000>, + <0x0 0x4c81000c 0x0 0x18>; + reg-names = "ierb", "prb", "netcmix"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + clocks = <&scmi_clk 98>; + clock-names = "ipg"; + power-domains = <&scmi_devpd 18>; + + pcie@4cb00000 { + compatible = "pci-host-ecam-generic"; + reg = <0x0 0x4cb00000 0x0 0x100000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x1 0x1>; + ranges = <0x82000000 0x0 0x4cce0000 0x0 0x4cce0000 0x0 0x20000 + 0xc2000000 0x0 0x4cd10000 0x0 0x4cd10000 0x0 0x10000>; + + mdio@0,0 { + compatible = "pci1131,ee00"; + reg = <0x010000 0 0 0 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/nxp,tja11xx.yaml b/Documentation/devicetree/bindings/net/nxp,tja11xx.yaml index a754a61adc2df3..5f9f7efff53838 100644 --- a/Documentation/devicetree/bindings/net/nxp,tja11xx.yaml +++ b/Documentation/devicetree/bindings/net/nxp,tja11xx.yaml @@ -62,6 +62,22 @@ allOf: reference clock output when RMII mode enabled. Only supported on TJA1100 and TJA1101. + - if: + properties: + compatible: + contains: + enum: + - ethernet-phy-id001b.b010 + - ethernet-phy-id001b.b013 + - ethernet-phy-id001b.b030 + - ethernet-phy-id001b.b031 + + then: + properties: + nxp,rmii-refclk-out: + type: boolean + description: Enable 50MHz RMII reference clock output on REF_CLK pin. + patternProperties: "^ethernet-phy@[0-9a-f]+$": type: object diff --git a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml index 6672327358bc13..0bcd593a7bd093 100644 --- a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml @@ -18,11 +18,20 @@ allOf: properties: compatible: - enum: - - qcom,qcs404-ethqos - - qcom,sa8775p-ethqos - - qcom,sc8280xp-ethqos - - qcom,sm8150-ethqos + oneOf: + - items: + - enum: + - qcom,qcs8300-ethqos + - const: qcom,sa8775p-ethqos + - items: + - enum: + - qcom,qcs615-ethqos + - const: qcom,sm8150-ethqos + - enum: + - qcom,qcs404-ethqos + - qcom,sa8775p-ethqos + - qcom,sc8280xp-ethqos + - qcom,sm8150-ethqos reg: maxItems: 2 diff --git a/Documentation/devicetree/bindings/net/renesas,ether.yaml b/Documentation/devicetree/bindings/net/renesas,ether.yaml index 29355ab98569da..f0a52f47f95a0d 100644 --- a/Documentation/devicetree/bindings/net/renesas,ether.yaml +++ b/Documentation/devicetree/bindings/net/renesas,ether.yaml @@ -59,6 +59,9 @@ properties: clocks: maxItems: 1 + iommus: + maxItems: 1 + power-domains: maxItems: 1 @@ -123,7 +126,6 @@ examples: reg = <1>; interrupt-parent = <&irqc0>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; - micrel,led-mode = <1>; reset-gpios = <&gpio5 31 GPIO_ACTIVE_LOW>; }; }; diff --git a/Documentation/devicetree/bindings/net/sff,sfp.yaml b/Documentation/devicetree/bindings/net/sff,sfp.yaml index 90611b598d2bdd..15616ad737f571 100644 --- a/Documentation/devicetree/bindings/net/sff,sfp.yaml +++ b/Documentation/devicetree/bindings/net/sff,sfp.yaml @@ -132,7 +132,7 @@ examples: pinctrl-names = "default"; pinctrl-0 = <&cpm_phy0_pins &cps_phy0_pins>; reg = <0>; - interrupt = <&cpm_gpio2 18 IRQ_TYPE_EDGE_FALLING>; + interrupts = <18 IRQ_TYPE_EDGE_FALLING>; sfp = <&sfp2>; }; }; diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index 4e2ba1bf788c98..eb1f3ae41ab9ab 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -26,6 +26,7 @@ select: - snps,dwmac-3.610 - snps,dwmac-3.70a - snps,dwmac-3.710 + - snps,dwmac-3.72a - snps,dwmac-4.00 - snps,dwmac-4.10a - snps,dwmac-4.20a @@ -90,6 +91,7 @@ properties: - snps,dwmac-3.610 - snps,dwmac-3.70a - snps,dwmac-3.710 + - snps,dwmac-3.72a - snps,dwmac-4.00 - snps,dwmac-4.10a - snps,dwmac-4.20a @@ -99,6 +101,7 @@ properties: - snps,dwxgmac-2.10 - starfive,jh7100-dwmac - starfive,jh7110-dwmac + - thead,th1520-gmac reg: minItems: 1 @@ -560,7 +563,7 @@ properties: max read outstanding req. limit snps,kbbe: - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: /schemas/types.yaml#/definitions/flag description: do not cross 1KiB boundary. diff --git a/Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml b/Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml new file mode 100644 index 00000000000000..6d9de330376226 --- /dev/null +++ b/Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/thead,th1520-gmac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-HEAD TH1520 GMAC Ethernet controller + +maintainers: + - Drew Fustini + +description: | + The TH1520 GMAC is described in the TH1520 Peripheral Interface User Manual + https://git.beagleboard.org/beaglev-ahead/beaglev-ahead/-/tree/main/docs + + Features include + - Compliant with IEEE802.3 Specification + - IEEE 1588-2008 standard for precision networked clock synchronization + - Supports 10/100/1000Mbps data transfer rate + - Supports RGMII/MII interface + - Preamble and start of frame data (SFD) insertion in Transmit path + - Preamble and SFD deletion in the Receive path + - Automatic CRC and pad generation options for receive frames + - MDIO master interface for PHY device configuration and management + + The GMAC Registers consists of two parts + - APB registers are used to configure clock frequency/clock enable/clock + direction/PHY interface type. + - AHB registers are use to configure GMAC core (DesignWare Core part). + GMAC core register consists of DMA registers and GMAC registers. + +select: + properties: + compatible: + contains: + enum: + - thead,th1520-gmac + required: + - compatible + +allOf: + - $ref: snps,dwmac.yaml# + +properties: + compatible: + items: + - enum: + - thead,th1520-gmac + - const: snps,dwmac-3.70a + + reg: + items: + - description: DesignWare GMAC IP core registers + - description: GMAC APB registers + + reg-names: + items: + - const: dwmac + - const: apb + + clocks: + items: + - description: GMAC main clock + - description: Peripheral registers interface clock + + clock-names: + items: + - const: stmmaceth + - const: pclk + + interrupts: + items: + - description: Combined signal for various interrupt events + + interrupt-names: + items: + - const: macirq + +required: + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + gmac0: ethernet@e7070000 { + compatible = "thead,th1520-gmac", "snps,dwmac-3.70a"; + reg = <0xe7070000 0x2000>, <0xec003000 0x1000>; + reg-names = "dwmac", "apb"; + clocks = <&clk 1>, <&clk 2>; + clock-names = "stmmaceth", "pclk"; + interrupts = <66>; + interrupt-names = "macirq"; + phy-mode = "rgmii-id"; + snps,fixed-burst; + snps,axi-config = <&stmmac_axi_setup>; + snps,pbl = <32>; + phy-handle = <&phy0>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml index e564f20d8f4157..a3607d55ef3671 100644 --- a/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml +++ b/Documentation/devicetree/bindings/net/wireless/brcm,bcm4329-fmac.yaml @@ -53,6 +53,7 @@ properties: - pci14e4,4488 # BCM4377 - pci14e4,4425 # BCM4378 - pci14e4,4433 # BCM4387 + - pci14e4,449d # BCM43752 reg: description: SDIO function number for the device (for most cases @@ -121,6 +122,14 @@ properties: NVRAM. This would normally be filled in by the bootloader from platform configuration data. + clocks: + items: + - description: External Low Power Clock input (32.768KHz) + + clock-names: + items: + - const: lpo + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml index 2460ccc082371b..5d40f22765bb67 100644 --- a/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml +++ b/Documentation/devicetree/bindings/net/wireless/microchip,wilc1000.yaml @@ -16,7 +16,11 @@ description: properties: compatible: - const: microchip,wilc1000 + oneOf: + - items: + - const: microchip,wilc3000 + - const: microchip,wilc1000 + - const: microchip,wilc1000 reg: true diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml index 8675d7d0215cdb..a71fdf05bc1ea4 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml @@ -50,6 +50,9 @@ properties: vddrfa1p7-supply: description: VDD_RFA_1P7 supply regulator handle + vddrfa1p8-supply: + description: VDD_RFA_1P8 supply regulator handle + vddpcie0p9-supply: description: VDD_PCIE_0P9 supply regulator handle @@ -77,6 +80,22 @@ allOf: - vddrfa1p7-supply - vddpcie0p9-supply - vddpcie1p8-supply + - if: + properties: + compatible: + contains: + const: pci17cb,1103 + then: + required: + - vddrfacmn-supply + - vddaon-supply + - vddwlcx-supply + - vddwlmx-supply + - vddrfa0p8-supply + - vddrfa1p2-supply + - vddrfa1p8-supply + - vddpcie0p9-supply + - vddpcie1p8-supply additionalProperties: false @@ -99,6 +118,16 @@ examples: compatible = "pci17cb,1103"; reg = <0x10000 0x0 0x0 0x0 0x0>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>; + vddaon-supply = <&vreg_pmu_aon_0p8>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p8>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + qcom,ath11k-calibration-variant = "LE_X13S"; }; }; diff --git a/Documentation/devicetree/bindings/net/xlnx,emaclite.yaml b/Documentation/devicetree/bindings/net/xlnx,emaclite.yaml index 92d8ade988f69d..e16384aff55775 100644 --- a/Documentation/devicetree/bindings/net/xlnx,emaclite.yaml +++ b/Documentation/devicetree/bindings/net/xlnx,emaclite.yaml @@ -29,6 +29,9 @@ properties: interrupts: maxItems: 1 + clocks: + maxItems: 1 + phy-handle: true local-mac-address: true @@ -45,6 +48,7 @@ required: - compatible - reg - interrupts + - clocks - phy-handle additionalProperties: false @@ -56,6 +60,7 @@ examples: reg = <0x40e00000 0x10000>; interrupt-parent = <&axi_intc_1>; interrupts = <1>; + clocks = <&dummy>; local-mac-address = [00 00 00 00 00 00]; phy-handle = <&phy0>; xlnx,rx-ping-pong; diff --git a/Documentation/devicetree/bindings/nvmem/renesas,rcar-efuse.yaml b/Documentation/devicetree/bindings/nvmem/renesas,rcar-efuse.yaml new file mode 100644 index 00000000000000..ce7d65afa46025 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/renesas,rcar-efuse.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/renesas,rcar-efuse.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: R-Car E-FUSE connected to PFC + +maintainers: + - Geert Uytterhoeven + +description: + The E-FUSE is a type of non-volatile memory, which is accessible through the + Pin Function Controller (PFC) on some R-Car Gen4 SoCs. + +allOf: + - $ref: nvmem.yaml# + +properties: + compatible: + enum: + - renesas,r8a779a0-efuse # R-Car V3U + - renesas,r8a779f0-efuse # R-Car S4-8 + + reg: + maxItems: 1 + description: PFC System Group Fuse Control and Monitor register block + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - power-domains + - resets + +unevaluatedProperties: false + +examples: + - | + #include + #include + + fuse@e6078800 { + compatible = "renesas,r8a779f0-efuse"; + reg = <0xe6078800 0x200>; + clocks = <&cpg CPG_MOD 915>; + power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>; + resets = <&cpg 915>; + + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + calib@144 { + reg = <0x144 0x08>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/nvmem/renesas,rcar-otp.yaml b/Documentation/devicetree/bindings/nvmem/renesas,rcar-otp.yaml new file mode 100644 index 00000000000000..3313c03ea68dfd --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/renesas,rcar-otp.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/renesas,rcar-otp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: R-Car E-FUSE connected to OTP_MEM + +maintainers: + - Geert Uytterhoeven + +description: + The E-FUSE is a type of non-volatile memory, which is accessible through the + One-Time Programmable Memory (OTP_MEM) module on some R-Car Gen4 SoCs. + +allOf: + - $ref: nvmem.yaml# + +properties: + compatible: + enum: + - renesas,r8a779g0-otp # R-CarV4H + - renesas,r8a779h0-otp # R-CarV4M + + reg: + items: + - description: OTP_MEM_0 + - description: OTP_MEM_1. + The addresses of cells defined under the optional nvmem-layout + subnode are relative to this register bank. + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + otp@e61be000 { + compatible = "renesas,r8a779g0-otp"; + reg = <0xe61be000 0x1000>, <0xe61bf000 0x1000>; + }; diff --git a/Documentation/devicetree/bindings/nvmem/sc27xx-efuse.txt b/Documentation/devicetree/bindings/nvmem/sc27xx-efuse.txt deleted file mode 100644 index 586c08286aa9af..00000000000000 --- a/Documentation/devicetree/bindings/nvmem/sc27xx-efuse.txt +++ /dev/null @@ -1,52 +0,0 @@ -= Spreadtrum SC27XX PMIC eFuse device tree bindings = - -Required properties: -- compatible: Should be one of the following. - "sprd,sc2720-efuse" - "sprd,sc2721-efuse" - "sprd,sc2723-efuse" - "sprd,sc2730-efuse" - "sprd,sc2731-efuse" -- reg: Specify the address offset of efuse controller. -- hwlocks: Reference to a phandle of a hwlock provider node. - -= Data cells = -Are child nodes of eFuse, bindings of which as described in -bindings/nvmem/nvmem.txt - -Example: - - sc2731_pmic: pmic@0 { - compatible = "sprd,sc2731"; - reg = <0>; - spi-max-frequency = <26000000>; - interrupts = ; - interrupt-controller; - #interrupt-cells = <2>; - #address-cells = <1>; - #size-cells = <0>; - - efuse@380 { - compatible = "sprd,sc2731-efuse"; - reg = <0x380>; - #address-cells = <1>; - #size-cells = <1>; - hwlocks = <&hwlock 12>; - - /* Data cells */ - thermal_calib: calib@10 { - reg = <0x10 0x2>; - }; - }; - }; - -= Data consumers = -Are device nodes which consume nvmem data cells. - -Example: - - thermal { - ... - nvmem-cells = <&thermal_calib>; - nvmem-cell-names = "calibration"; - }; diff --git a/Documentation/devicetree/bindings/nvmem/sprd,sc2731-efuse.yaml b/Documentation/devicetree/bindings/nvmem/sprd,sc2731-efuse.yaml new file mode 100644 index 00000000000000..dc25fe3d1841f5 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/sprd,sc2731-efuse.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/sprd,sc2731-efuse.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum SC27XX PMIC eFuse + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + compatible: + enum: + - sprd,sc2720-efuse + - sprd,sc2721-efuse + - sprd,sc2723-efuse + - sprd,sc2730-efuse + - sprd,sc2731-efuse + + reg: + maxItems: 1 + + hwlocks: + maxItems: 1 + +required: + - compatible + - reg + - hwlocks + +allOf: + - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# + +unevaluatedProperties: false + +examples: + - | + pmic { + #address-cells = <1>; + #size-cells = <0>; + + efuse@380 { + compatible = "sprd,sc2731-efuse"; + reg = <0x380>; + hwlocks = <&hwlock 12>; + #address-cells = <1>; + #size-cells = <1>; + + /* Data cells */ + fgu_calib: calib@6 { + reg = <0x6 0x2>; + bits = <0 9>; + }; + + adc_big_scale: calib@24 { + reg = <0x24 0x2>; + }; + + adc_small_scale: calib@26 { + reg = <0x26 0x2>; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/nvmem/sprd,ums312-efuse.yaml b/Documentation/devicetree/bindings/nvmem/sprd,ums312-efuse.yaml new file mode 100644 index 00000000000000..00e0fd1353a3f7 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/sprd,ums312-efuse.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/sprd,ums312-efuse.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum UMS312 eFuse + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + compatible: + const: sprd,ums312-efuse + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: enable + + hwlocks: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - hwlocks + +allOf: + - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + efuse@32240000 { + compatible = "sprd,ums312-efuse"; + reg = <0x32240000 0x10000>; + clocks = <&aonapb_gate CLK_EFUSE_EB>; + clock-names = "enable"; + hwlocks = <&hwlock 8>; + #address-cells = <1>; + #size-cells = <1>; + + /* Data cells */ + thermal_calib: calib@10 { + reg = <0x10 0x2>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/nvmem/sprd-efuse.txt b/Documentation/devicetree/bindings/nvmem/sprd-efuse.txt deleted file mode 100644 index 96b6feec27f0b2..00000000000000 --- a/Documentation/devicetree/bindings/nvmem/sprd-efuse.txt +++ /dev/null @@ -1,39 +0,0 @@ -= Spreadtrum eFuse device tree bindings = - -Required properties: -- compatible: Should be "sprd,ums312-efuse". -- reg: Specify the address offset of efuse controller. -- clock-names: Should be "enable". -- clocks: The phandle and specifier referencing the controller's clock. -- hwlocks: Reference to a phandle of a hwlock provider node. - -= Data cells = -Are child nodes of eFuse, bindings of which as described in -bindings/nvmem/nvmem.txt - -Example: - - ap_efuse: efuse@32240000 { - compatible = "sprd,ums312-efuse"; - reg = <0 0x32240000 0 0x10000>; - clock-names = "enable"; - hwlocks = <&hwlock 8>; - clocks = <&aonapb_gate CLK_EFUSE_EB>; - - /* Data cells */ - thermal_calib: calib@10 { - reg = <0x10 0x2>; - }; - }; - -= Data consumers = -Are device nodes which consume nvmem data cells. - -Example: - - thermal { - ... - - nvmem-cells = <&thermal_calib>; - nvmem-cell-names = "calibration"; - }; diff --git a/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.txt b/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.txt deleted file mode 100644 index 0df79d9e07ec22..00000000000000 --- a/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.txt +++ /dev/null @@ -1,40 +0,0 @@ -Zodiac Inflight Innovations RAVE EEPROM Bindings - -RAVE SP EEPROM device is a "MFD cell" device exposing physical EEPROM -attached to RAVE Supervisory Processor. It is expected that its Device -Tree node is specified as a child of the node corresponding to the -parent RAVE SP device (as documented in -Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) - -Required properties: - -- compatible: Should be "zii,rave-sp-eeprom" - -Optional properties: - -- zii,eeprom-name: Unique EEPROM identifier describing its function in the - system. Will be used as created NVMEM deivce's name. - -Data cells: - -Data cells are child nodes of eerpom node, bindings for which are -documented in Documentation/devicetree/bindings/nvmem/nvmem.txt - -Example: - - rave-sp { - compatible = "zii,rave-sp-rdu1"; - current-speed = <38400>; - - eeprom@a4 { - compatible = "zii,rave-sp-eeprom"; - reg = <0xa4 0x4000>; - #address-cells = <1>; - #size-cells = <1>; - zii,eeprom-name = "main-eeprom"; - - wdt_timeout: wdt-timeout@81 { - reg = <0x81 2>; - }; - }; - } diff --git a/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.yaml b/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.yaml new file mode 100644 index 00000000000000..d073c51c2b9a99 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/zii,rave-sp-eeprom.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/zii,rave-sp-eeprom.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zodiac Inflight Innovations RAVE EEPROM + +maintainers: + - Frank Li + +description: + RAVE SP EEPROM device is a "MFD cell" device exposing physical EEPROM + attached to RAVE Supervisory Processor. It is expected that its Device + Tree node is specified as a child of the node corresponding to the + parent RAVE SP device (as documented in + Documentation/devicetree/bindings/mfd/zii,rave-sp.yaml) + +properties: + compatible: + const: zii,rave-sp-eeprom + + reg: + maxItems: 1 + + zii,eeprom-name: + $ref: /schemas/types.yaml#/definitions/string + description: + Unique EEPROM identifier describing its function in the + system. Will be used as created NVMEM deivce's name. + +required: + - compatible + +allOf: + - $ref: nvmem.yaml# + - $ref: nvmem-deprecated-cells.yaml# + +unevaluatedProperties: false + +examples: + - | + eeprom@a4 { + compatible = "zii,rave-sp-eeprom"; + reg = <0xa4 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + zii,eeprom-name = "main-eeprom"; + + wdt-timeout@81 { + reg = <0x81 2>; + }; + }; + diff --git a/Documentation/devicetree/bindings/opp/operating-points-v2-ti-cpu.yaml b/Documentation/devicetree/bindings/opp/operating-points-v2-ti-cpu.yaml index fd0c8d5c5f3e7e..624d1f3f1382fb 100644 --- a/Documentation/devicetree/bindings/opp/operating-points-v2-ti-cpu.yaml +++ b/Documentation/devicetree/bindings/opp/operating-points-v2-ti-cpu.yaml @@ -45,7 +45,25 @@ patternProperties: clock-latency-ns: true opp-hz: true opp-microvolt: true - opp-supported-hw: true + opp-supported-hw: + items: + items: + - description: + The revision of the SoC the OPP is supported by. + This can be easily obtained from the datasheet of the + part being ordered/used. For example, it will be 0x01 for SR1.0 + + - description: + The eFuse bits that indicate the particular OPP is available. + The device datasheet has a table talking about Device Speed Grades. + This table is to be sorted with only the unique elements of the + MAXIMUM OPERATING FREQUENCY starting from the first row which + tells the lowest OPP, to the highest. The corresponding bits + need to be set based on N elements of speed grade the device supports. + So, if there are 3 possible unique MAXIMUM OPERATING FREQUENCY + in the table, then BIT(0) | (1) | (2) will be set, which means + the value shall be 0x7. + opp-suspend: true turbo-mode: true diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml index 0925c520195ae3..2ad1652c25848b 100644 --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml @@ -92,9 +92,8 @@ properties: may have two component regions -- base and extended -- so this information cannot be deduced from the dma-ranges. $ref: /schemas/types.yaml#/definitions/uint64-array - items: - minItems: 1 - maxItems: 3 + minItems: 1 + maxItems: 3 resets: minItems: 1 diff --git a/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml b/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml index 898c1be2d6a435..f05aab2b1addca 100644 --- a/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml +++ b/Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml @@ -149,7 +149,7 @@ allOf: then: properties: clocks: - minItems: 4 + minItems: 6 clock-names: items: @@ -178,7 +178,7 @@ allOf: then: properties: clocks: - minItems: 4 + minItems: 6 clock-names: items: @@ -207,6 +207,7 @@ allOf: properties: clocks: minItems: 4 + maxItems: 4 clock-names: items: diff --git a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml index 612633ba59e2c5..2e154756970297 100644 --- a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml +++ b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml @@ -17,6 +17,12 @@ properties: compatible: const: microchip,pcie-host-1.0 # PolarFire + reg: + minItems: 3 + + reg-names: + minItems: 3 + clocks: description: Fabric Interface Controllers, FICs, are the interface between the FPGA @@ -62,8 +68,9 @@ examples: pcie0: pcie@2030000000 { compatible = "microchip,pcie-host-1.0"; reg = <0x0 0x70000000 0x0 0x08000000>, - <0x0 0x43000000 0x0 0x00010000>; - reg-names = "cfg", "apb"; + <0x0 0x43008000 0x0 0x00002000>, + <0x0 0x4300a000 0x0 0x00002000>; + reg-names = "cfg", "bridge", "ctrl"; device_type = "pci"; #address-cells = <3>; #size-cells = <2>; diff --git a/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml b/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml index 7a57a80052a016..039eecdbd6aad2 100644 --- a/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml +++ b/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml @@ -18,12 +18,18 @@ allOf: properties: reg: - maxItems: 2 + maxItems: 3 + minItems: 2 reg-names: - items: - - const: cfg - - const: apb + oneOf: + - items: + - const: cfg + - const: apb + - items: + - const: cfg + - const: bridge + - const: ctrl interrupts: minItems: 1 diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-common.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-common.yaml index e18900c4157616..0480c58f7d998a 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-common.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-common.yaml @@ -81,6 +81,10 @@ properties: vddpe-3v3-supply: description: PCIe endpoint power supply + operating-points-v2: true + opp-table: + type: object + required: - reg - reg-names diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml index 46bd59eefadba1..6e0a6d8f0ed070 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml @@ -70,10 +70,6 @@ properties: - const: msi7 - const: global - operating-points-v2: true - opp-table: - type: object - resets: maxItems: 1 diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml index 24cb38673581d7..2b5498a35dcc17 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8550.yaml @@ -20,6 +20,7 @@ properties: - const: qcom,pcie-sm8550 - items: - enum: + - qcom,sar2130p-pcie - qcom,pcie-sm8650 - const: qcom,pcie-sm8550 @@ -39,7 +40,7 @@ properties: clocks: minItems: 7 - maxItems: 8 + maxItems: 9 clock-names: minItems: 7 @@ -52,6 +53,7 @@ properties: - const: ddrss_sf_tbu # PCIe SF TBU clock - const: noc_aggr # Aggre NoC PCIe AXI clock - const: cnoc_sf_axi # Config NoC PCIe1 AXI clock + - const: qmip_pcie_ahb # QMIP PCIe AHB clock interrupts: minItems: 8 diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml index a9db0a2315639e..257068a1826492 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-x1e80100.yaml @@ -47,9 +47,10 @@ properties: interrupts: minItems: 8 - maxItems: 8 + maxItems: 9 interrupt-names: + minItems: 8 items: - const: msi0 - const: msi1 @@ -59,6 +60,7 @@ properties: - const: msi5 - const: msi6 - const: msi7 + - const: global resets: minItems: 1 @@ -130,9 +132,10 @@ examples: , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", "msi3", - "msi4", "msi5", "msi6", "msi7"; + "msi4", "msi5", "msi6", "msi7", "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml index ffabbac57fc167..bd87f6b49d6805 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml @@ -26,6 +26,7 @@ properties: - qcom,pcie-ipq8064-v2 - qcom,pcie-ipq8074 - qcom,pcie-ipq8074-gen3 + - qcom,pcie-ipq9574 - qcom,pcie-msm8996 - qcom,pcie-qcs404 - qcom,pcie-sdm845 @@ -164,6 +165,7 @@ allOf: enum: - qcom,pcie-ipq6018 - qcom,pcie-ipq8074-gen3 + - qcom,pcie-ipq9574 then: properties: reg: @@ -400,6 +402,53 @@ allOf: - const: axi_m_sticky # AXI Master Sticky reset - const: axi_s_sticky # AXI Slave Sticky reset + - if: + properties: + compatible: + contains: + enum: + - qcom,pcie-ipq9574 + then: + properties: + clocks: + minItems: 6 + maxItems: 6 + clock-names: + items: + - const: axi_m # AXI Master clock + - const: axi_s # AXI Slave clock + - const: axi_bridge + - const: rchng + - const: ahb + - const: aux + + resets: + minItems: 8 + maxItems: 8 + reset-names: + items: + - const: pipe # PIPE reset + - const: sticky # Core Sticky reset + - const: axi_s_sticky # AXI Slave Sticky reset + - const: axi_s # AXI Slave reset + - const: axi_m_sticky # AXI Master Sticky reset + - const: axi_m # AXI Master reset + - const: aux # AUX Reset + - const: ahb # AHB Reset + + interrupts: + minItems: 8 + interrupt-names: + items: + - const: msi0 + - const: msi1 + - const: msi2 + - const: msi3 + - const: msi4 + - const: msi5 + - const: msi6 + - const: msi7 + - if: properties: compatible: @@ -510,6 +559,7 @@ allOf: - qcom,pcie-ipq8064v2 - qcom,pcie-ipq8074 - qcom,pcie-ipq8074-gen3 + - qcom,pcie-ipq9574 - qcom,pcie-qcs404 then: required: diff --git a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml index 548f59d76ef209..205326fb2d75c6 100644 --- a/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml @@ -230,7 +230,6 @@ examples: interrupts = <25>, <24>; interrupt-names = "msi", "hp"; - #interrupt-cells = <1>; reset-gpios = <&port0 0 1>; diff --git a/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml b/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml index 67151aaa39480c..5f432452c815bc 100644 --- a/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml @@ -16,6 +16,13 @@ properties: compatible: const: starfive,jh7110-pcie + + reg: + maxItems: 2 + + reg-names: + maxItems: 2 + clocks: items: - description: NOC bus clock diff --git a/Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml b/Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml index 37e8b98f2cdc10..8597ea625edba5 100644 --- a/Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml +++ b/Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml @@ -31,7 +31,9 @@ properties: - const: fsl,imx8dxl-ddr-pmu - const: fsl,imx8-ddr-pmu - items: - - const: fsl,imx95-ddr-pmu + - enum: + - fsl,imx91-ddr-pmu + - fsl,imx95-ddr-pmu - const: fsl,imx93-ddr-pmu reg: diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun50i-a64-usb-phy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun50i-a64-usb-phy.yaml index f557feca97630c..21209126ed008e 100644 --- a/Documentation/devicetree/bindings/phy/allwinner,sun50i-a64-usb-phy.yaml +++ b/Documentation/devicetree/bindings/phy/allwinner,sun50i-a64-usb-phy.yaml @@ -15,9 +15,13 @@ properties: const: 1 compatible: - enum: - - allwinner,sun20i-d1-usb-phy - - allwinner,sun50i-a64-usb-phy + oneOf: + - enum: + - allwinner,sun20i-d1-usb-phy + - allwinner,sun50i-a64-usb-phy + - items: + - const: allwinner,sun50i-a100-usb-phy + - const: allwinner,sun20i-d1-usb-phy reg: items: diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml index 426101530a21ee..d72c02ab55ae80 100644 --- a/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/bcm-ns-usb2-phy.yaml @@ -18,16 +18,8 @@ properties: const: brcm,ns-usb2-phy reg: - anyOf: - - maxItems: 1 - description: PHY control register - - maxItems: 1 - description: iomem address range of DMU (Device Management Unit) - deprecated: true - - reg-names: - items: - - const: dmu + maxItems: 1 + description: PHY control register brcm,syscon-clkset: description: phandle to syscon for clkset register @@ -50,12 +42,7 @@ required: - clocks - clock-names - "#phy-cells" - -oneOf: - - required: - - brcm,syscon-clkset - - required: - - reg-names + - brcm,syscon-clkset additionalProperties: false diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml index dc3a3f709feaa6..daee0c0fc91539 100644 --- a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml +++ b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml @@ -11,12 +11,17 @@ maintainers: properties: compatible: - enum: - - fsl,imx8mq-usb-phy - - fsl,imx8mp-usb-phy + oneOf: + - enum: + - fsl,imx8mq-usb-phy + - fsl,imx8mp-usb-phy + - items: + - const: fsl,imx95-usb-phy + - const: fsl,imx8mp-usb-phy reg: - maxItems: 1 + minItems: 1 + maxItems: 2 "#phy-cells": const: 0 @@ -89,7 +94,31 @@ required: - clocks - clock-names -additionalProperties: false +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx95-usb-phy + then: + properties: + reg: + items: + - description: USB PHY Control range + - description: USB PHY TCA Block range + else: + properties: + reg: + maxItems: 1 + + - if: + required: + - orientation-switch + then: + $ref: /schemas/usb/usb-switch.yaml# + +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/phy/fsl,mxs-usbphy.yaml b/Documentation/devicetree/bindings/phy/fsl,mxs-usbphy.yaml index ce665a2779b796..d01b7d18704056 100644 --- a/Documentation/devicetree/bindings/phy/fsl,mxs-usbphy.yaml +++ b/Documentation/devicetree/bindings/phy/fsl,mxs-usbphy.yaml @@ -32,6 +32,7 @@ properties: - enum: - fsl,imx8dxl-usbphy - fsl,imx8qm-usbphy + - fsl,imx8qxp-usbphy - fsl,imx8ulp-usbphy - const: fsl,imx7ulp-usbphy diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml index 423b7c4e62f2a9..6be3aa4557e55d 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml @@ -125,6 +125,16 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 default: 28 + power-domains: + description: + The TPHY of MediaTek should exist within a power domain. The + developer should be aware that the hardware design of MediaTek TPHY + does not require the addition of MTCMOS. If the power to the TPHY + is turned off, it will impact other functions. From the current + perspective of USB hardware design, even if MTCMOS is added to the + TPHY, it should remain always on. + maxItems: 1 + # Required child node: patternProperties: "^(usb|pcie|sata)-phy@[0-9a-f]+$": diff --git a/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml b/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml index bdbdb3bbddbea5..fa0b02916dacfa 100644 --- a/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml +++ b/Documentation/devicetree/bindings/phy/microchip,sparx5-serdes.yaml @@ -8,6 +8,7 @@ title: Microchip Sparx5 Serdes controller maintainers: - Steen Hegelund + - Daniel Machon description: | The Sparx5 SERDES interfaces share the same basic functionality, but @@ -62,12 +63,26 @@ description: | * 10.3125 Gbps (10GBASE-R/10GBASE-KR/USXGMII) * 25.78125 Gbps (25GBASE-KR/25GBASE-CR/25GBASE-SR/25GBASE-LR/25GBASE-ER) + lan969x has ten SERDES10G interfaces that share the same features, operating + modes and data rates as the equivalent Sparx5 SERDES10G interfaces. + properties: $nodename: pattern: "^serdes@[0-9a-f]+$" compatible: - const: microchip,sparx5-serdes + oneOf: + - enum: + - microchip,sparx5-serdes + - microchip,lan9691-serdes + - items: + - enum: + - microchip,lan9698-serdes + - microchip,lan9696-serdes + - microchip,lan9694-serdes + - microchip,lan9693-serdes + - microchip,lan9692-serdes + - const: microchip,lan9691-serdes reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/phy/nxp,ptn3222.yaml b/Documentation/devicetree/bindings/phy/nxp,ptn3222.yaml new file mode 100644 index 00000000000000..acec5bb2391d72 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/nxp,ptn3222.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/nxp,ptn3222.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PTN3222 1-port eUSB2 to USB2 redriver + +maintainers: + - Dmitry Baryshkov + +properties: + compatible: + enum: + - nxp,ptn3222 + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + vdd1v8-supply: + description: power supply (1.8V) + + vdd3v3-supply: + description: power supply (3.3V) + + reset-gpios: true + +required: + - compatible + - reg + - '#phy-cells' + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + redriver@4f { + compatible = "nxp,ptn3222"; + reg = <0x4f>; + #phy-cells = <0>; + vdd3v3-supply = <&vreg_3p3>; + vdd1v8-supply = <&vreg_1p8>; + reset-gpios = <&gpio_reset GPIO_ACTIVE_LOW>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml index 37f028f7a09554..137ac5703853d8 100644 --- a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml +++ b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml @@ -96,7 +96,7 @@ patternProperties: Specifies the type of PHY for which the group of PHY lanes is used. Refer include/dt-bindings/phy/phy.h. Constants from the header should be used. $ref: /schemas/types.yaml#/definitions/uint32 - enum: [2, 4] + enum: [2, 4, 8, 9] cdns,num-lanes: description: diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt deleted file mode 100644 index 710cccd5ee56ee..00000000000000 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-hdmi.txt +++ /dev/null @@ -1,43 +0,0 @@ -ROCKCHIP HDMI PHY WITH INNO IP BLOCK - -Required properties: - - compatible : should be one of the listed compatibles: - * "rockchip,rk3228-hdmi-phy", - * "rockchip,rk3328-hdmi-phy"; - - reg : Address and length of the hdmi phy control register set - - clocks : phandle + clock specifier for the phy clocks - - clock-names : string, clock name, must contain "sysclk" for system - control and register configuration, "refoclk" for crystal- - oscillator reference PLL clock input and "refpclk" for pclk- - based refeference PLL clock input. - - #clock-cells: should be 0. - - clock-output-names : shall be the name for the output clock. - - interrupts : phandle + interrupt specified for the hdmiphy interrupt - - #phy-cells : must be 0. See ./phy-bindings.txt for details. - -Optional properties for rk3328-hdmi-phy: - - nvmem-cells = phandle + nvmem specifier for the cpu-version efuse - - nvmem-cell-names : "cpu-version" to read the chip version, required - for adjustment to some frequency settings - -Example: - hdmi_phy: hdmi-phy@12030000 { - compatible = "rockchip,rk3228-hdmi-phy"; - reg = <0x12030000 0x10000>; - #phy-cells = <0>; - clocks = <&cru PCLK_HDMI_PHY>, <&xin24m>, <&cru DCLK_HDMIPHY>; - clock-names = "sysclk", "refoclk", "refpclk"; - #clock-cells = <0>; - clock-output-names = "hdmi_phy"; - status = "disabled"; - }; - -Then the PHY can be used in other nodes such as: - - hdmi: hdmi@200a0000 { - compatible = "rockchip,rk3228-dw-hdmi"; - ... - phys = <&hdmi_phy>; - phy-names = "hdmi"; - ... - }; diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml index 1f1f8863b80d05..b42f1272903d80 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml @@ -13,6 +13,7 @@ maintainers: properties: compatible: enum: + - rockchip,rk3576-usbdp-phy - rockchip,rk3588-usbdp-phy reg: diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml index 4e15d90d08b0ec..293fb6a9b1c330 100644 --- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml @@ -17,6 +17,7 @@ description: properties: compatible: enum: + - qcom,sa8775p-edp-phy - qcom,sc7280-edp-phy - qcom,sc8180x-edp-phy - qcom,sc8280xp-dp-phy diff --git a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml index f1f4e4f83352d7..1636285fbe535c 100644 --- a/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,msm8998-qmp-usb3-phy.yaml @@ -18,6 +18,7 @@ properties: enum: - qcom,msm8998-qmp-usb3-phy - qcom,qcm2290-qmp-usb3-phy + - qcom,qcs615-qmp-usb3-phy - qcom,sdm660-qmp-usb3-phy - qcom,sm6115-qmp-usb3-phy @@ -96,6 +97,7 @@ allOf: contains: enum: - qcom,msm8998-qmp-usb3-phy + - qcom,qcs615-qmp-usb3-phy - qcom,sdm660-qmp-usb3-phy then: properties: diff --git a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml index 95eecbaef05c0e..4aed4b5d65ec5a 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml @@ -25,6 +25,7 @@ properties: - qcom,msm8996-qusb2-phy - qcom,msm8998-qusb2-phy - qcom,qcm2290-qusb2-phy + - qcom,qcs615-qusb2-phy - qcom,sdm660-qusb2-phy - qcom,sm4250-qusb2-phy - qcom,sm6115-qusb2-phy diff --git a/Documentation/devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml index b9107759b2a517..90fc8c039219c7 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sa8775p-dwmac-sgmii-phy.yaml @@ -15,7 +15,12 @@ description: properties: compatible: - const: qcom,sa8775p-dwmac-sgmii-phy + oneOf: + - items: + - enum: + - qcom,qcs8300-dwmac-sgmii-phy + - const: qcom,sa8775p-dwmac-sgmii-phy + - const: qcom,sa8775p-dwmac-sgmii-phy reg: items: 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 380a9222a51d86..13fdf5f1bebae9 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -41,6 +41,7 @@ properties: - qcom,x1e80100-qmp-gen3x2-pcie-phy - qcom,x1e80100-qmp-gen4x2-pcie-phy - qcom,x1e80100-qmp-gen4x4-pcie-phy + - qcom,x1e80100-qmp-gen4x8-pcie-phy reg: minItems: 1 @@ -172,6 +173,7 @@ allOf: - qcom,x1e80100-qmp-gen3x2-pcie-phy - qcom,x1e80100-qmp-gen4x2-pcie-phy - qcom,x1e80100-qmp-gen4x4-pcie-phy + - qcom,x1e80100-qmp-gen4x8-pcie-phy then: properties: clocks: @@ -202,6 +204,7 @@ allOf: - qcom,sm8650-qmp-gen4x2-pcie-phy - qcom,x1e80100-qmp-gen4x2-pcie-phy - qcom,x1e80100-qmp-gen4x4-pcie-phy + - qcom,x1e80100-qmp-gen4x8-pcie-phy then: properties: resets: 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 f9cfbd0b2de6c4..72bed2933b034f 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -15,26 +15,35 @@ description: properties: compatible: - enum: - - qcom,msm8996-qmp-ufs-phy - - qcom,msm8998-qmp-ufs-phy - - qcom,sa8775p-qmp-ufs-phy - - qcom,sc7180-qmp-ufs-phy - - qcom,sc7280-qmp-ufs-phy - - qcom,sc8180x-qmp-ufs-phy - - qcom,sc8280xp-qmp-ufs-phy - - qcom,sdm845-qmp-ufs-phy - - qcom,sm6115-qmp-ufs-phy - - qcom,sm6125-qmp-ufs-phy - - qcom,sm6350-qmp-ufs-phy - - qcom,sm7150-qmp-ufs-phy - - qcom,sm8150-qmp-ufs-phy - - qcom,sm8250-qmp-ufs-phy - - qcom,sm8350-qmp-ufs-phy - - qcom,sm8450-qmp-ufs-phy - - qcom,sm8475-qmp-ufs-phy - - qcom,sm8550-qmp-ufs-phy - - qcom,sm8650-qmp-ufs-phy + oneOf: + - items: + - enum: + - qcom,qcs615-qmp-ufs-phy + - const: qcom,sm6115-qmp-ufs-phy + - items: + - enum: + - qcom,qcs8300-qmp-ufs-phy + - const: qcom,sa8775p-qmp-ufs-phy + - enum: + - qcom,msm8996-qmp-ufs-phy + - qcom,msm8998-qmp-ufs-phy + - qcom,sa8775p-qmp-ufs-phy + - qcom,sc7180-qmp-ufs-phy + - qcom,sc7280-qmp-ufs-phy + - qcom,sc8180x-qmp-ufs-phy + - qcom,sc8280xp-qmp-ufs-phy + - qcom,sdm845-qmp-ufs-phy + - qcom,sm6115-qmp-ufs-phy + - qcom,sm6125-qmp-ufs-phy + - qcom,sm6350-qmp-ufs-phy + - qcom,sm7150-qmp-ufs-phy + - qcom,sm8150-qmp-ufs-phy + - qcom,sm8250-qmp-ufs-phy + - qcom,sm8350-qmp-ufs-phy + - qcom,sm8450-qmp-ufs-phy + - qcom,sm8475-qmp-ufs-phy + - qcom,sm8550-qmp-ufs-phy + - qcom,sm8650-qmp-ufs-phy reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml index 0e0b6cae07bc7c..baf5134ea3d8a2 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml @@ -20,6 +20,7 @@ properties: - qcom,ipq8074-qmp-usb3-phy - qcom,ipq9574-qmp-usb3-phy - qcom,msm8996-qmp-usb3-phy + - qcom,qcs8300-qmp-usb3-uni-phy - qcom,qdu1000-qmp-usb3-uni-phy - qcom,sa8775p-qmp-usb3-uni-phy - qcom,sc8180x-qmp-usb3-uni-phy @@ -111,6 +112,7 @@ allOf: compatible: contains: enum: + - qcom,qcs8300-qmp-usb3-uni-phy - qcom,qdu1000-qmp-usb3-uni-phy - qcom,sa8775p-qmp-usb3-uni-phy - qcom,sc8180x-qmp-usb3-uni-phy diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml index b82f7f5731ed4a..142b3c8839d62d 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml @@ -17,6 +17,7 @@ properties: oneOf: - items: - enum: + - qcom,sar2130p-snps-eusb2-phy - qcom,sdx75-snps-eusb2-phy - qcom,sm8650-snps-eusb2-phy - qcom,x1e80100-snps-eusb2-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 519c2b403f66d5..661759b2506443 100644 --- a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml @@ -22,6 +22,7 @@ properties: - const: qcom,usb-snps-hs-5nm-phy - items: - enum: + - qcom,qcs8300-usb-hs-phy - qcom,qdu1000-usb-hs-phy - qcom,sc7280-usb-hs-phy - qcom,sc8180x-usb-hs-phy diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml index 5254413137c644..6a7ef556414ceb 100644 --- a/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml +++ b/Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml @@ -20,6 +20,7 @@ properties: - rockchip,rk3366-usb2phy - rockchip,rk3399-usb2phy - rockchip,rk3568-usb2phy + - rockchip,rk3576-usb2phy - rockchip,rk3588-usb2phy - rockchip,rv1108-usb2phy @@ -34,10 +35,15 @@ properties: const: 0 clocks: - maxItems: 1 + minItems: 1 + maxItems: 3 clock-names: - const: phyclk + minItems: 1 + items: + - const: phyclk + - const: aclk + - const: aclk_slv assigned-clocks: description: @@ -172,6 +178,41 @@ allOf: - interrupts - interrupt-names + - if: + properties: + compatible: + contains: + enum: + - rockchip,px30-usb2phy + - rockchip,rk3128-usb2phy + - rockchip,rk3228-usb2phy + - rockchip,rk3308-usb2phy + - rockchip,rk3328-usb2phy + - rockchip,rk3366-usb2phy + - rockchip,rk3399-usb2phy + - rockchip,rk3568-usb2phy + - rockchip,rk3588-usb2phy + - rockchip,rv1108-usb2phy + then: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + + - if: + properties: + compatible: + contains: + enum: + - rockchip,rk3576-usb2phy + then: + properties: + clocks: + minItems: 3 + clock-names: + minItems: 3 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/phy/rockchip,rk3228-hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/rockchip,rk3228-hdmi-phy.yaml new file mode 100644 index 00000000000000..ac15bf857ef997 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/rockchip,rk3228-hdmi-phy.yaml @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/rockchip,rk3228-hdmi-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip HDMI PHY with Innosilicon IP block + +maintainers: + - Heiko Stuebner + +properties: + compatible: + enum: + - rockchip,rk3228-hdmi-phy + - rockchip,rk3328-hdmi-phy + + reg: + maxItems: 1 + + clocks: + maxItems: 3 + + clock-names: + items: + - const: sysclk + - const: refoclk + - const: refpclk + + clock-output-names: + description: + The hdmiphy output clock name, that gets fed back to the CRU. + + "#clock-cells": + const: 0 + + interrupts: + maxItems: 1 + + nvmem-cells: + maxItems: 1 + description: A phandle + nvmem specifier for the cpu-version efuse + for adjustment to some frequency settings, depending on cpu-version + + nvmem-cell-names: + items: + - const: cpu-version + + '#phy-cells': + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - clock-output-names + - '#clock-cells' + - '#phy-cells' + +allOf: + - if: + properties: + compatible: + contains: + const: rockchip,rk3228-hdmi-phy + + then: + properties: + interrupts: false + + - if: + properties: + compatible: + contains: + const: rockchip,rk3328-hdmi-phy + + then: + required: + - interrupts + +additionalProperties: false + +examples: + - | + + #include + hdmi_phy: phy@12030000 { + compatible = "rockchip,rk3228-hdmi-phy"; + reg = <0x12030000 0x10000>; + #phy-cells = <0>; + clocks = <&cru PCLK_HDMI_PHY>, <&xin24m>, <&cru DCLK_HDMI_PHY>; + clock-names = "sysclk", "refoclk", "refpclk"; + #clock-cells = <0>; + + clock-output-names = "hdmi_phy"; + }; diff --git a/Documentation/devicetree/bindings/phy/st,stm32mp25-combophy.yaml b/Documentation/devicetree/bindings/phy/st,stm32mp25-combophy.yaml new file mode 100644 index 00000000000000..a2e82c0bb56b40 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/st,stm32mp25-combophy.yaml @@ -0,0 +1,119 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/st,stm32mp25-combophy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32MP25 USB3/PCIe COMBOPHY + +maintainers: + - Christian Bruel + +description: + Single lane PHY shared (exclusive) between the USB3 and PCIe controllers. + Supports 5Gbit/s for USB3 and PCIe gen2 or 2.5Gbit/s for PCIe gen1. + +properties: + compatible: + const: st,stm32mp25-combophy + + reg: + maxItems: 1 + + "#phy-cells": + const: 1 + + clocks: + minItems: 2 + items: + - description: apb Bus clock mandatory to access registers. + - description: ker Internal RCC reference clock for USB3 or PCIe + - description: pad Optional on board clock input for PCIe only. Typically an + external 100Mhz oscillator wired on dedicated CLKIN pad. Used as reference + clock input instead of the ker + + clock-names: + minItems: 2 + items: + - const: apb + - const: ker + - const: pad + + resets: + maxItems: 1 + + reset-names: + const: phy + + power-domains: + maxItems: 1 + + wakeup-source: true + + interrupts: + maxItems: 1 + description: interrupt used for wakeup + + access-controllers: + maxItems: 1 + description: Phandle to the rifsc device to check access right. + + st,ssc-on: + $ref: /schemas/types.yaml#/definitions/flag + description: + A property whose presence indicates that the Spread Spectrum Clocking is active. + + st,rx-equalizer: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + default: 2 + description: + A 3 bit value to tune the RX fixed equalizer setting for optimal eye compliance + + st,output-micro-ohms: + minimum: 3999000 + maximum: 6090000 + default: 4968000 + description: + A value property to tune the Single Ended Output Impedance, simulations results + at 25C for a VDDP=0.8V. The hardware accepts discrete values in this range. + + st,output-vswing-microvolt: + minimum: 442000 + maximum: 803000 + default: 803000 + description: + A value property in microvolt to tune the Single Ended Output Voltage Swing to change the + Vlo, Vhi for a VDDP = 0.8V. The hardware accepts discrete values in this range. + +required: + - compatible + - reg + - "#phy-cells" + - clocks + - clock-names + - resets + - reset-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + + phy@480c0000 { + compatible = "st,stm32mp25-combophy"; + reg = <0x480c0000 0x1000>; + #phy-cells = <1>; + clocks = <&rcc CK_BUS_USB3PCIEPHY>, <&rcc CK_KER_USB3PCIEPHY>; + clock-names = "apb", "ker"; + resets = <&rcc USB3PCIEPHY_R>; + reset-names = "phy"; + access-controllers = <&rifsc 67>; + power-domains = <&CLUSTER_PD>; + wakeup-source; + interrupts-extended = <&exti1 45 IRQ_TYPE_EDGE_FALLING>; + }; diff --git a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml index 79dad3e89aa698..4a8c3829d85d3c 100644 --- a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml +++ b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml @@ -14,10 +14,15 @@ properties: pattern: "^can-phy" compatible: - enum: - - nxp,tjr1443 - - ti,tcan1042 - - ti,tcan1043 + oneOf: + - items: + - enum: + - microchip,ata6561 + - const: ti,tcan1042 + - enum: + - ti,tcan1042 + - ti,tcan1043 + - nxp,tjr1443 '#phy-cells': const: 0 diff --git a/Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml new file mode 100644 index 00000000000000..b2601d698dcd41 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml @@ -0,0 +1,400 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/airoha,en7581-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha EN7581 Pin Controller + +maintainers: + - Lorenzo Bianconi + +description: + The Airoha's EN7581 Pin controller is used to control SoC pins. + +properties: + compatible: + const: airoha,en7581-pinctrl + + interrupts: + maxItems: 1 + + gpio-controller: true + + '#gpio-cells': + const: 2 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + +allOf: + - $ref: pinctrl.yaml# + +required: + - compatible + - interrupts + - gpio-controller + - "#gpio-cells" + - interrupt-controller + - "#interrupt-cells" + +patternProperties: + '-pins$': + type: object + + patternProperties: + '^mux(-|$)': + type: object + + description: + pinmux configuration nodes. + + $ref: /schemas/pinctrl/pinmux-node.yaml + + properties: + function: + description: + A string containing the name of the function to mux to the group. + enum: [pon, tod_1pps, sipo, mdio, uart, i2c, jtag, pcm, spi, + pcm_spi, i2s, emmc, pnand, pcie_reset, pwm, phy1_led0, + phy2_led0, phy3_led0, phy4_led0, phy1_led1, phy2_led1, + phy3_led1, phy4_led1] + + groups: + description: + An array of strings. Each string contains the name of a group. + + required: + - function + - groups + + allOf: + - if: + properties: + function: + const: pon + then: + properties: + groups: + enum: [pon] + - if: + properties: + function: + const: tod_1pps + then: + properties: + groups: + enum: [pon_tod_1pps, gsw_tod_1pps] + - if: + properties: + function: + const: sipo + then: + properties: + groups: + enum: [sipo, sipo_rclk] + - if: + properties: + function: + const: mdio + then: + properties: + groups: + enum: [mdio] + - if: + properties: + function: + const: uart + then: + properties: + groups: + items: + enum: [uart2, uart2_cts_rts, hsuart, hsuart_cts_rts, + uart4, uart5] + maxItems: 2 + - if: + properties: + function: + const: i2c + then: + properties: + groups: + enum: [i2c1] + - if: + properties: + function: + const: jtag + then: + properties: + groups: + enum: [jtag_udi, jtag_dfd] + - if: + properties: + function: + const: pcm + then: + properties: + groups: + enum: [pcm1, pcm2] + - if: + properties: + function: + const: spi + then: + properties: + groups: + items: + enum: [spi_quad, spi_cs1] + maxItems: 2 + - if: + properties: + function: + const: pcm_spi + then: + properties: + groups: + items: + enum: [pcm_spi, pcm_spi_int, pcm_spi_rst, pcm_spi_cs1, + pcm_spi_cs2_p156, pcm_spi_cs2_p128, pcm_spi_cs3, + pcm_spi_cs4] + maxItems: 7 + - if: + properties: + function: + const: i2c + then: + properties: + groups: + enum: [i2s] + - if: + properties: + function: + const: emmc + then: + properties: + groups: + enum: [emmc] + - if: + properties: + function: + const: pnand + then: + properties: + groups: + enum: [pnand] + - if: + properties: + function: + const: pcie_reset + then: + properties: + groups: + enum: [pcie_reset0, pcie_reset1, pcie_reset2] + - if: + properties: + function: + const: pwm + then: + properties: + groups: + enum: [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, + gpio36, gpio37, gpio38, gpio39, gpio40, gpio41, + gpio42, gpio43, gpio44, gpio45, gpio46, gpio47] + - if: + properties: + function: + const: phy1_led0 + then: + properties: + groups: + enum: [gpio33, gpio34, gpio35, gpio42] + - if: + properties: + function: + const: phy2_led0 + then: + properties: + groups: + enum: [gpio33, gpio34, gpio35, gpio42] + - if: + properties: + function: + const: phy3_led0 + then: + properties: + groups: + enum: [gpio33, gpio34, gpio35, gpio42] + - if: + properties: + function: + const: phy4_led0 + then: + properties: + groups: + enum: [gpio33, gpio34, gpio35, gpio42] + - if: + properties: + function: + const: phy1_led1 + then: + properties: + groups: + enum: [gpio43, gpio44, gpio45, gpio46] + - if: + properties: + function: + const: phy2_led1 + then: + properties: + groups: + enum: [gpio43, gpio44, gpio45, gpio46] + - if: + properties: + function: + const: phy3_led1 + then: + properties: + groups: + enum: [gpio43, gpio44, gpio45, gpio46] + - if: + properties: + function: + const: phy4_led1 + then: + properties: + groups: + enum: [gpio43, gpio44, gpio45, gpio46] + + additionalProperties: false + + '^conf(-|$)': + type: object + + description: + pinconf configuration nodes. + + $ref: /schemas/pinctrl/pincfg-node.yaml + + properties: + pins: + description: + An array of strings. Each string contains the name of a pin. + items: + enum: [uart1_txd, uart1_rxd, i2c_scl, i2c_sda, spi_cs0, spi_clk, + spi_mosi, spi_miso, 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, + pcie_reset0, pcie_reset1, pcie_reset2] + minItems: 1 + maxItems: 58 + + bias-disable: true + + bias-pull-up: true + + bias-pull-down: true + + input-enable: true + + output-enable: true + + output-low: true + + output-high: true + + drive-open-drain: true + + drive-strength: + description: + Selects the drive strength for MIO pins, in mA. + enum: [2, 4, 6, 8] + + required: + - pins + + additionalProperties: false + + additionalProperties: false + +additionalProperties: false + +examples: + - | + #include + + pinctrl { + compatible = "airoha,en7581-pinctrl"; + + interrupt-parent = <&gic>; + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + pcie1-rst-pins { + conf { + pins = "pcie_reset1"; + drive-open-drain = <1>; + }; + }; + + pwm-pins { + mux { + function = "pwm"; + groups = "gpio18"; + }; + }; + + spi-pins { + mux { + function = "spi"; + groups = "spi_quad", "spi_cs1"; + }; + }; + + uart2-pins { + mux { + function = "uart"; + groups = "uart2", "uart2_cts_rts"; + }; + }; + + uar5-pins { + mux { + function = "uart"; + groups = "uart5"; + }; + }; + + mmc-pins { + mux { + function = "emmc"; + groups = "emmc"; + }; + }; + + mdio-pins { + mux { + function = "mdio"; + groups = "mdio"; + }; + + conf { + pins = "gpio2"; + output-enable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-cbus.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-cbus.yaml index 412bbcc276f3b3..c954761e01505c 100644 --- a/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-cbus.yaml +++ b/Documentation/devicetree/bindings/pinctrl/amlogic,meson8-pinctrl-cbus.yaml @@ -46,7 +46,7 @@ patternProperties: - const: gpio gpio-line-names: - minItems: 86 # AXG + minItems: 83 # Meson8b maxItems: 120 # Meson8 unevaluatedProperties: diff --git a/Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml index 9c07935919ea56..63737d85894429 100644 --- a/Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml @@ -18,6 +18,11 @@ properties: compatible: items: - enum: + - apple,s5l8960x-pinctrl + - apple,t7000-pinctrl + - apple,s8000-pinctrl + - apple,t8010-pinctrl + - apple,t8015-pinctrl - apple,t8103-pinctrl - apple,t8112-pinctrl - apple,t6000-pinctrl diff --git a/Documentation/devicetree/bindings/pinctrl/canaan,k230-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/canaan,k230-pinctrl.yaml new file mode 100644 index 00000000000000..0b462eb6dfe169 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/canaan,k230-pinctrl.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/canaan,k230-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Canaan Kendryte K230 Pin Controller + +maintainers: + - Ze Huang <18771902331@163.com> + +description: + The Canaan Kendryte K230 platform includes 64 IO pins, each capable of + multiplexing up to 5 different functions. Pin function configuration is + performed on a per-pin basis. + +properties: + compatible: + const: canaan,k230-pinctrl + + reg: + maxItems: 1 + +patternProperties: + '-pins$': + type: object + additionalProperties: false + description: + A pinctrl node should contain at least one subnode representing the + pinctrl groups available on the machine. + + patternProperties: + '-cfg$': + type: object + allOf: + - $ref: /schemas/pinctrl/pincfg-node.yaml + - $ref: /schemas/pinctrl/pinmux-node.yaml + additionalProperties: false + description: + Each subnode will list the pins it needs, and how they should + be configured, with regard to muxer configuration, bias, input + enable/disable, input schmitt trigger, slew-rate enable/disable, + slew-rate, drive strength. + + properties: + pinmux: + description: + The list of GPIOs and their mux settings that properties in + the node apply to. This should be set with the macro + 'K230_PINMUX(pin, mode)' + + bias-disable: true + + bias-pull-up: true + + bias-pull-down: true + + drive-strength: + minimum: 0 + maximum: 15 + + input-enable: true + + output-enable: true + + input-schmitt-enable: true + + slew-rate: + description: | + slew rate control enable + 0: disable + 1: enable + + enum: [0, 1] + + power-source: + description: | + Specifies the power source voltage for the IO bank that the + pin belongs to. Each bank of IO pins operate at a specific, + fixed voltage levels. Incorrect voltage configuration can + damage the chip. The defined constants represent the + possible voltage configurations: + + - K230_MSC_3V3 (value 0): 3.3V power supply + - K230_MSC_1V8 (value 1): 1.8V power supply + + The following banks have the corresponding voltage + configurations: + + - bank IO0 to IO1: Fixed at 1.8V + - bank IO2 to IO13: Fixed at 1.8V + - bank IO14 to IO25: Fixed at 1.8V + - bank IO26 to IO37: Fixed at 1.8V + - bank IO38 to IO49: Fixed at 1.8V + - bank IO50 to IO61: Fixed at 3.3V + - bank IO62 to IO63: Fixed at 1.8V + + enum: [0, 1] + + required: + - pinmux + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + pinctrl@91105000 { + compatible = "canaan,k230-pinctrl"; + reg = <0x91105000 0x100>; + + uart2-pins { + uart2-pins-cfg { + pinmux = <0x503>, /* uart2 txd */ + <0x603>; /* uart2 rxd */ + slew-rate = <0>; + drive-strength = <4>; + power-source = <1>; + input-enable; + output-enable; + bias-disable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt deleted file mode 100644 index c083dfd25db931..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt +++ /dev/null @@ -1,33 +0,0 @@ -* Freescale IMX35 IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx35-iomuxc" -- fsl,pins: two integers array, represents a group of pins mux and config - setting. The format is fsl,pins = , PIN_FUNC_ID is a - pin working on a specific function, CONFIG is the pad setting value like - pull-up for this pin. Please refer to imx35 datasheet for the valid pad - config settings. - -CONFIG bits definition: -PAD_CTL_DRIVE_VOLAGAGE_18 (1 << 13) -PAD_CTL_DRIVE_VOLAGAGE_33 (0 << 13) -PAD_CTL_HYS (1 << 8) -PAD_CTL_PKE (1 << 7) -PAD_CTL_PUE (1 << 6) -PAD_CTL_PUS_100K_DOWN (0 << 4) -PAD_CTL_PUS_47K_UP (1 << 4) -PAD_CTL_PUS_100K_UP (2 << 4) -PAD_CTL_PUS_22K_UP (3 << 4) -PAD_CTL_ODE_CMOS (0 << 3) -PAD_CTL_ODE_OPENDRAIN (1 << 3) -PAD_CTL_DSE_NOMINAL (0 << 1) -PAD_CTL_DSE_HIGH (1 << 1) -PAD_CTL_DSE_MAX (2 << 1) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) - -Refer to imx35-pinfunc.h in device tree source folder for all available -imx35 PIN_FUNC_ID. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.yaml new file mode 100644 index 00000000000000..265c43ab76f4c3 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.yaml @@ -0,0 +1,184 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/fsl,imx35-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale IMX35/IMX5x/IMX6 IOMUX Controller + +maintainers: + - Dong Aisheng + +description: + Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory + for common binding part and usage. + +allOf: + - $ref: pinctrl.yaml# + +properties: + compatible: + oneOf: + - enum: + - fsl,imx35-iomuxc + - fsl,imx51-iomuxc + - fsl,imx53-iomuxc + - fsl,imx6dl-iomuxc + - fsl,imx6q-iomuxc + - fsl,imx6sl-iomuxc + - fsl,imx6sll-iomuxc + - fsl,imx6sx-iomuxc + - fsl,imx6ul-iomuxc + - fsl,imx6ull-iomuxc-snvs + - items: + - const: fsl,imx50-iomuxc + - const: fsl,imx53-iomuxc + + reg: + maxItems: 1 + +# Client device subnode's properties +patternProperties: + 'grp$': + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + + properties: + fsl,pins: + description: + each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can + be found in . The last integer + CONFIG is the pad setting value like pull-up on this pin. Please + refer to matching i.MX Reference Manual for detailed CONFIG settings. + $ref: /schemas/types.yaml#/definitions/uint32-matrix + items: + items: + - description: | + "mux_reg" indicates the offset of mux register. + - description: | + "conf_reg" indicates the offset of pad configuration register. + - description: | + "input_reg" indicates the offset of select input register. + - description: | + "mux_val" indicates the mux value to be applied. + - description: | + "input_val" indicates the select input value to be applied. + - description: | + "pad_setting" indicates the pad configuration value to be applied. + Common i.MX35 + PAD_CTL_DRIVE_VOLAGAGE_18 (1 << 13) + PAD_CTL_DRIVE_VOLAGAGE_33 (0 << 13) + PAD_CTL_HYS (1 << 8) + PAD_CTL_PKE (1 << 7) + PAD_CTL_PUE (1 << 6) + PAD_CTL_PUS_100K_DOWN (0 << 4) + PAD_CTL_PUS_47K_UP (1 << 4) + PAD_CTL_PUS_100K_UP (2 << 4) + PAD_CTL_PUS_22K_UP (3 << 4) + PAD_CTL_ODE_CMOS (0 << 3) + PAD_CTL_ODE_OPENDRAIN (1 << 3) + PAD_CTL_DSE_NOMINAL (0 << 1) + PAD_CTL_DSE_HIGH (1 << 1) + PAD_CTL_DSE_MAX (2 << 1) + PAD_CTL_SRE_FAST (1 << 0) + PAD_CTL_SRE_SLOW (0 << 0) + Common i.MX50/i.MX51/i.MX53 bits + PAD_CTL_HVE (1 << 13) + PAD_CTL_HYS (1 << 8) + PAD_CTL_PKE (1 << 7) + PAD_CTL_PUE (1 << 6) + PAD_CTL_PUS_100K_DOWN (0 << 4) + PAD_CTL_PUS_47K_UP (1 << 4) + PAD_CTL_PUS_100K_UP (2 << 4) + PAD_CTL_PUS_22K_UP (3 << 4) + PAD_CTL_ODE (1 << 3) + PAD_CTL_DSE_LOW (0 << 1) + PAD_CTL_DSE_MED (1 << 1) + PAD_CTL_DSE_HIGH (2 << 1) + PAD_CTL_DSE_MAX (3 << 1) + PAD_CTL_SRE_FAST (1 << 0) + PAD_CTL_SRE_SLOW (0 << 0) + Common i.MX6 bits + PAD_CTL_HYS (1 << 16) + PAD_CTL_PUS_100K_DOWN (0 << 14) + PAD_CTL_PUS_47K_UP (1 << 14) + PAD_CTL_PUS_100K_UP (2 << 14) + PAD_CTL_PUS_22K_UP (3 << 14) + PAD_CTL_PUE (1 << 13) + PAD_CTL_PKE (1 << 12) + PAD_CTL_ODE (1 << 11) + PAD_CTL_SPEED_LOW (0 << 6) + PAD_CTL_SPEED_MED (1 << 6) + PAD_CTL_SPEED_HIGH (3 << 6) + PAD_CTL_DSE_DISABLE (0 << 3) + PAD_CTL_SRE_FAST (1 << 0) + PAD_CTL_SRE_SLOW (0 << 0) + i.MX6SL/MX6SLL specific bits + PAD_CTL_LVE (1 << 22) (MX6SL/SLL only) + i.MX6SLL/i.MX6SX/i.MX6UL/i.MX6ULL specific bits + PAD_CTL_DSE_260ohm (1 << 3) + PAD_CTL_DSE_130ohm (2 << 3) + PAD_CTL_DSE_87ohm (3 << 3) + PAD_CTL_DSE_65ohm (4 << 3) + PAD_CTL_DSE_52ohm (5 << 3) + PAD_CTL_DSE_43ohm (6 << 3) + PAD_CTL_DSE_37ohm (7 << 3) + i.MX6DL/i.MX6Q/i.MX6SL specific bits + PAD_CTL_DSE_240ohm (1 << 3) + PAD_CTL_DSE_120ohm (2 << 3) + PAD_CTL_DSE_80ohm (3 << 3) + PAD_CTL_DSE_60ohm (4 << 3) + PAD_CTL_DSE_48ohm (5 << 3) + PAD_CTL_DSE_40ohm (6 << 3) + PAD_CTL_DSE_34ohm (7 << 3) + + required: + - fsl,pins + + additionalProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + iomuxc: pinctrl@20e0000 { + compatible = "fsl,imx6ul-iomuxc"; + reg = <0x020e0000 0x4000>; + + mux_uart: uartgrp { + fsl,pins = < + 0x0084 0x0310 0x0000 0 0 0x1b0b1 + 0x0088 0x0314 0x0624 0 3 0x1b0b1 + >; + }; + }; + - | + iomuxc_snvs: pinctrl@2290000 { + compatible = "fsl,imx6ull-iomuxc-snvs"; + reg = <0x02290000 0x4000>; + + pinctrl_snvs_usbc_det: snvsusbcdetgrp { + fsl,pins = < + 0x0010 0x0054 0x0000 0x5 0x0 0x130b0 + >; + }; + }; + - | + iomuxc_mx6q: pinctrl@20e0000 { + compatible = "fsl,imx6q-iomuxc"; + reg = <0x20e0000 0x4000>; + + pinctrl_uart4: uart4grp { + fsl,pins = + <0x288 0x658 0x000 0x3 0x0 0x140>, + <0x28c 0x65c 0x938 0x3 0x3 0x140>; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx50-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx50-pinctrl.txt deleted file mode 100644 index 6da01d619d33e2..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx50-pinctrl.txt +++ /dev/null @@ -1,32 +0,0 @@ -* Freescale IMX50 IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx50-iomuxc" -- fsl,pins: two integers array, represents a group of pins mux and config - setting. The format is fsl,pins = , PIN_FUNC_ID is a - pin working on a specific function, CONFIG is the pad setting value like - pull-up for this pin. Please refer to imx50 datasheet for the valid pad - config settings. - -CONFIG bits definition: -PAD_CTL_HVE (1 << 13) -PAD_CTL_HYS (1 << 8) -PAD_CTL_PKE (1 << 7) -PAD_CTL_PUE (1 << 6) -PAD_CTL_PUS_100K_DOWN (0 << 4) -PAD_CTL_PUS_47K_UP (1 << 4) -PAD_CTL_PUS_100K_UP (2 << 4) -PAD_CTL_PUS_22K_UP (3 << 4) -PAD_CTL_ODE (1 << 3) -PAD_CTL_DSE_LOW (0 << 1) -PAD_CTL_DSE_MED (1 << 1) -PAD_CTL_DSE_HIGH (2 << 1) -PAD_CTL_DSE_MAX (3 << 1) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) - -Refer to imx50-pinfunc.h in device tree source folder for all available -imx50 PIN_FUNC_ID. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx51-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx51-pinctrl.txt deleted file mode 100644 index 4d1408fcc99cfb..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx51-pinctrl.txt +++ /dev/null @@ -1,32 +0,0 @@ -* Freescale IMX51 IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx51-iomuxc" -- fsl,pins: two integers array, represents a group of pins mux and config - setting. The format is fsl,pins = , PIN_FUNC_ID is a - pin working on a specific function, CONFIG is the pad setting value like - pull-up for this pin. Please refer to imx51 datasheet for the valid pad - config settings. - -CONFIG bits definition: -PAD_CTL_HVE (1 << 13) -PAD_CTL_HYS (1 << 8) -PAD_CTL_PKE (1 << 7) -PAD_CTL_PUE (1 << 6) -PAD_CTL_PUS_100K_DOWN (0 << 4) -PAD_CTL_PUS_47K_UP (1 << 4) -PAD_CTL_PUS_100K_UP (2 << 4) -PAD_CTL_PUS_22K_UP (3 << 4) -PAD_CTL_ODE (1 << 3) -PAD_CTL_DSE_LOW (0 << 1) -PAD_CTL_DSE_MED (1 << 1) -PAD_CTL_DSE_HIGH (2 << 1) -PAD_CTL_DSE_MAX (3 << 1) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) - -Refer to imx51-pinfunc.h in device tree source folder for all available -imx51 PIN_FUNC_ID. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx53-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx53-pinctrl.txt deleted file mode 100644 index 25dcb77cfaf741..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx53-pinctrl.txt +++ /dev/null @@ -1,32 +0,0 @@ -* Freescale IMX53 IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx53-iomuxc" -- fsl,pins: two integers array, represents a group of pins mux and config - setting. The format is fsl,pins = , PIN_FUNC_ID is a - pin working on a specific function, CONFIG is the pad setting value like - pull-up for this pin. Please refer to imx53 datasheet for the valid pad - config settings. - -CONFIG bits definition: -PAD_CTL_HVE (1 << 13) -PAD_CTL_HYS (1 << 8) -PAD_CTL_PKE (1 << 7) -PAD_CTL_PUE (1 << 6) -PAD_CTL_PUS_100K_DOWN (0 << 4) -PAD_CTL_PUS_47K_UP (1 << 4) -PAD_CTL_PUS_100K_UP (2 << 4) -PAD_CTL_PUS_22K_UP (3 << 4) -PAD_CTL_ODE (1 << 3) -PAD_CTL_DSE_LOW (0 << 1) -PAD_CTL_DSE_MED (1 << 1) -PAD_CTL_DSE_HIGH (2 << 1) -PAD_CTL_DSE_MAX (3 << 1) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) - -Refer to imx53-pinfunc.h in device tree source folder for all available -imx53 PIN_FUNC_ID. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6dl-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6dl-pinctrl.txt deleted file mode 100644 index 0ac5bee875056d..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6dl-pinctrl.txt +++ /dev/null @@ -1,38 +0,0 @@ -* Freescale IMX6 DualLite/Solo IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx6dl-iomuxc" -- fsl,pins: two integers array, represents a group of pins mux and config - setting. The format is fsl,pins = , PIN_FUNC_ID is a - pin working on a specific function, CONFIG is the pad setting value like - pull-up for this pin. Please refer to imx6dl datasheet for the valid pad - config settings. - -CONFIG bits definition: -PAD_CTL_HYS (1 << 16) -PAD_CTL_PUS_100K_DOWN (0 << 14) -PAD_CTL_PUS_47K_UP (1 << 14) -PAD_CTL_PUS_100K_UP (2 << 14) -PAD_CTL_PUS_22K_UP (3 << 14) -PAD_CTL_PUE (1 << 13) -PAD_CTL_PKE (1 << 12) -PAD_CTL_ODE (1 << 11) -PAD_CTL_SPEED_LOW (1 << 6) -PAD_CTL_SPEED_MED (2 << 6) -PAD_CTL_SPEED_HIGH (3 << 6) -PAD_CTL_DSE_DISABLE (0 << 3) -PAD_CTL_DSE_240ohm (1 << 3) -PAD_CTL_DSE_120ohm (2 << 3) -PAD_CTL_DSE_80ohm (3 << 3) -PAD_CTL_DSE_60ohm (4 << 3) -PAD_CTL_DSE_48ohm (5 << 3) -PAD_CTL_DSE_40ohm (6 << 3) -PAD_CTL_DSE_34ohm (7 << 3) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) - -Refer to imx6dl-pinfunc.h in device tree source folder for all available -imx6dl PIN_FUNC_ID. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6q-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6q-pinctrl.txt deleted file mode 100644 index 546610cf2ae71c..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6q-pinctrl.txt +++ /dev/null @@ -1,38 +0,0 @@ -* Freescale IMX6Q IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx6q-iomuxc" -- fsl,pins: two integers array, represents a group of pins mux and config - setting. The format is fsl,pins = , PIN_FUNC_ID is a - pin working on a specific function, CONFIG is the pad setting value like - pull-up for this pin. Please refer to imx6q datasheet for the valid pad - config settings. - -CONFIG bits definition: -PAD_CTL_HYS (1 << 16) -PAD_CTL_PUS_100K_DOWN (0 << 14) -PAD_CTL_PUS_47K_UP (1 << 14) -PAD_CTL_PUS_100K_UP (2 << 14) -PAD_CTL_PUS_22K_UP (3 << 14) -PAD_CTL_PUE (1 << 13) -PAD_CTL_PKE (1 << 12) -PAD_CTL_ODE (1 << 11) -PAD_CTL_SPEED_LOW (1 << 6) -PAD_CTL_SPEED_MED (2 << 6) -PAD_CTL_SPEED_HIGH (3 << 6) -PAD_CTL_DSE_DISABLE (0 << 3) -PAD_CTL_DSE_240ohm (1 << 3) -PAD_CTL_DSE_120ohm (2 << 3) -PAD_CTL_DSE_80ohm (3 << 3) -PAD_CTL_DSE_60ohm (4 << 3) -PAD_CTL_DSE_48ohm (5 << 3) -PAD_CTL_DSE_40ohm (6 << 3) -PAD_CTL_DSE_34ohm (7 << 3) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) - -Refer to imx6q-pinfunc.h in device tree source folder for all available -imx6q PIN_FUNC_ID. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6sl-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6sl-pinctrl.txt deleted file mode 100644 index e5f6d1f065a421..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6sl-pinctrl.txt +++ /dev/null @@ -1,39 +0,0 @@ -* Freescale IMX6 SoloLite IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx6sl-iomuxc" -- fsl,pins: two integers array, represents a group of pins mux and config - setting. The format is fsl,pins = , PIN_FUNC_ID is a - pin working on a specific function, CONFIG is the pad setting value like - pull-up for this pin. Please refer to imx6sl datasheet for the valid pad - config settings. - -CONFIG bits definition: -PAD_CTL_LVE (1 << 22) -PAD_CTL_HYS (1 << 16) -PAD_CTL_PUS_100K_DOWN (0 << 14) -PAD_CTL_PUS_47K_UP (1 << 14) -PAD_CTL_PUS_100K_UP (2 << 14) -PAD_CTL_PUS_22K_UP (3 << 14) -PAD_CTL_PUE (1 << 13) -PAD_CTL_PKE (1 << 12) -PAD_CTL_ODE (1 << 11) -PAD_CTL_SPEED_LOW (1 << 6) -PAD_CTL_SPEED_MED (2 << 6) -PAD_CTL_SPEED_HIGH (3 << 6) -PAD_CTL_DSE_DISABLE (0 << 3) -PAD_CTL_DSE_240ohm (1 << 3) -PAD_CTL_DSE_120ohm (2 << 3) -PAD_CTL_DSE_80ohm (3 << 3) -PAD_CTL_DSE_60ohm (4 << 3) -PAD_CTL_DSE_48ohm (5 << 3) -PAD_CTL_DSE_40ohm (6 << 3) -PAD_CTL_DSE_34ohm (7 << 3) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) - -Refer to imx6sl-pinfunc.h in device tree source folder for all available -imx6sl PIN_FUNC_ID. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6sll-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6sll-pinctrl.txt deleted file mode 100644 index 175e8939a3018d..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6sll-pinctrl.txt +++ /dev/null @@ -1,40 +0,0 @@ -* Freescale i.MX6 SLL IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx6sll-iomuxc" -- fsl,pins: each entry consists of 6 integers and represents the mux and config - setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in - imx6sll-pinfunc.h under device tree source folder. The last integer CONFIG is - the pad setting value like pull-up on this pin. Please refer to i.MX6SLL - Reference Manual for detailed CONFIG settings. - -CONFIG bits definition: -PAD_CTL_LVE (1 << 22) -PAD_CTL_HYS (1 << 16) -PAD_CTL_PUS_100K_DOWN (0 << 14) -PAD_CTL_PUS_47K_UP (1 << 14) -PAD_CTL_PUS_100K_UP (2 << 14) -PAD_CTL_PUS_22K_UP (3 << 14) -PAD_CTL_PUE (1 << 13) -PAD_CTL_PKE (1 << 12) -PAD_CTL_ODE (1 << 11) -PAD_CTL_SPEED_LOW (0 << 6) -PAD_CTL_SPEED_MED (1 << 6) -PAD_CTL_SPEED_HIGH (3 << 6) -PAD_CTL_DSE_DISABLE (0 << 3) -PAD_CTL_DSE_260ohm (1 << 3) -PAD_CTL_DSE_130ohm (2 << 3) -PAD_CTL_DSE_87ohm (3 << 3) -PAD_CTL_DSE_65ohm (4 << 3) -PAD_CTL_DSE_52ohm (5 << 3) -PAD_CTL_DSE_43ohm (6 << 3) -PAD_CTL_DSE_37ohm (7 << 3) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) - -Refer to imx6sll-pinfunc.h in device tree source folder for all available -imx6sll PIN_FUNC_ID. diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6sx-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6sx-pinctrl.txt deleted file mode 100644 index b1b595220f1bd9..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6sx-pinctrl.txt +++ /dev/null @@ -1,36 +0,0 @@ -* Freescale i.MX6 SoloX IOMUX Controller - -Please refer to fsl,imx-pinctrl.txt in this directory for common binding part -and usage. - -Required properties: -- compatible: "fsl,imx6sx-iomuxc" -- fsl,pins: each entry consists of 6 integers and represents the mux and config - setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in - imx6sx-pinfunc.h under device tree source folder. The last integer CONFIG is - the pad setting value like pull-up on this pin. Please refer to i.MX6 SoloX - Reference Manual for detailed CONFIG settings. - -CONFIG bits definition: -PAD_CTL_HYS (1 << 16) -PAD_CTL_PUS_100K_DOWN (0 << 14) -PAD_CTL_PUS_47K_UP (1 << 14) -PAD_CTL_PUS_100K_UP (2 << 14) -PAD_CTL_PUS_22K_UP (3 << 14) -PAD_CTL_PUE (1 << 13) -PAD_CTL_PKE (1 << 12) -PAD_CTL_ODE (1 << 11) -PAD_CTL_SPEED_LOW (0 << 6) -PAD_CTL_SPEED_MED (1 << 6) -PAD_CTL_SPEED_HIGH (3 << 6) -PAD_CTL_DSE_DISABLE (0 << 3) -PAD_CTL_DSE_260ohm (1 << 3) -PAD_CTL_DSE_130ohm (2 << 3) -PAD_CTL_DSE_87ohm (3 << 3) -PAD_CTL_DSE_65ohm (4 << 3) -PAD_CTL_DSE_52ohm (5 << 3) -PAD_CTL_DSE_43ohm (6 << 3) -PAD_CTL_DSE_37ohm (7 << 3) -PAD_CTL_SRE_FAST (1 << 0) -PAD_CTL_SRE_SLOW (0 << 0) diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.yaml deleted file mode 100644 index 906b264a9e3cda..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.yaml +++ /dev/null @@ -1,116 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/pinctrl/fsl,imx6ul-pinctrl.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Freescale IMX6UL IOMUX Controller - -maintainers: - - Dong Aisheng - -description: - Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory - for common binding part and usage. - -allOf: - - $ref: pinctrl.yaml# - -properties: - compatible: - enum: - - fsl,imx6ul-iomuxc - - fsl,imx6ull-iomuxc-snvs - - reg: - maxItems: 1 - -# Client device subnode's properties -patternProperties: - 'grp$': - type: object - description: - Pinctrl node's client devices use subnodes for desired pin configuration. - Client device subnodes use below standard properties. - - properties: - fsl,pins: - description: - each entry consists of 6 integers and represents the mux and config - setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can - be found in . The last integer - CONFIG is the pad setting value like pull-up on this pin. Please - refer to i.MX6UL Reference Manual for detailed CONFIG settings. - $ref: /schemas/types.yaml#/definitions/uint32-matrix - items: - items: - - description: | - "mux_reg" indicates the offset of mux register. - - description: | - "conf_reg" indicates the offset of pad configuration register. - - description: | - "input_reg" indicates the offset of select input register. - - description: | - "mux_val" indicates the mux value to be applied. - - description: | - "input_val" indicates the select input value to be applied. - - description: | - "pad_setting" indicates the pad configuration value to be applied: - PAD_CTL_HYS (1 << 16) - PAD_CTL_PUS_100K_DOWN (0 << 14) - PAD_CTL_PUS_47K_UP (1 << 14) - PAD_CTL_PUS_100K_UP (2 << 14) - PAD_CTL_PUS_22K_UP (3 << 14) - PAD_CTL_PUE (1 << 13) - PAD_CTL_PKE (1 << 12) - PAD_CTL_ODE (1 << 11) - PAD_CTL_SPEED_LOW (0 << 6) - PAD_CTL_SPEED_MED (1 << 6) - PAD_CTL_SPEED_HIGH (3 << 6) - PAD_CTL_DSE_DISABLE (0 << 3) - PAD_CTL_DSE_260ohm (1 << 3) - PAD_CTL_DSE_130ohm (2 << 3) - PAD_CTL_DSE_87ohm (3 << 3) - PAD_CTL_DSE_65ohm (4 << 3) - PAD_CTL_DSE_52ohm (5 << 3) - PAD_CTL_DSE_43ohm (6 << 3) - PAD_CTL_DSE_37ohm (7 << 3) - PAD_CTL_SRE_FAST (1 << 0) - PAD_CTL_SRE_SLOW (0 << 0) - - required: - - fsl,pins - - additionalProperties: false - -required: - - compatible - - reg - -additionalProperties: false - -examples: - - | - iomuxc: pinctrl@20e0000 { - compatible = "fsl,imx6ul-iomuxc"; - reg = <0x020e0000 0x4000>; - - mux_uart: uartgrp { - fsl,pins = < - 0x0084 0x0310 0x0000 0 0 0x1b0b1 - 0x0088 0x0314 0x0624 0 3 0x1b0b1 - >; - }; - }; - - | - iomuxc_snvs: pinctrl@2290000 { - compatible = "fsl,imx6ull-iomuxc-snvs"; - reg = <0x02290000 0x4000>; - - pinctrl_snvs_usbc_det: snvsusbcdetgrp { - fsl,pins = < - 0x0010 0x0054 0x0000 0x5 0x0 0x130b0 - >; - }; - }; diff --git a/Documentation/devicetree/bindings/pinctrl/microchip,mcp23s08.yaml b/Documentation/devicetree/bindings/pinctrl/microchip,mcp23s08.yaml new file mode 100644 index 00000000000000..e07f4723de177d --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/microchip,mcp23s08.yaml @@ -0,0 +1,161 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/microchip,mcp23s08.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip I/O expander with serial interface (I2C/SPI) + +maintainers: + - Himanshu Bhavani + +description: + Microchip MCP23008, MCP23017, MCP23S08, MCP23S17, MCP23S18 GPIO expander + chips.These chips provide 8 or 16 GPIO pins with either I2C or SPI interface. + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - microchip,mcp23s08 + - microchip,mcp23s17 + - microchip,mcp23s18 + - microchip,mcp23008 + - microchip,mcp23017 + - microchip,mcp23018 + + reg: + maxItems: 1 + + gpio-controller: true + + '#gpio-cells': + const: 2 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + + interrupts: + maxItems: 1 + + reset-gpios: + description: GPIO specifier for active-low reset pin. + maxItems: 1 + + microchip,spi-present-mask: + description: + Multiple SPI chips can share the same SPI chipselect. Set a bit in + bit0-7 in this mask to 1 if there is a chip connected with the + corresponding spi address set. For example if you have a chip with + address 3 connected, you have to set bit3 to 1, which is 0x08. mcp23s08 + chip variant only supports bits 0-3. It is not possible to mix mcp23s08 + and mcp23s17 on the same chipselect. Set at least one bit to 1 for SPI + chips. + $ref: /schemas/types.yaml#/definitions/uint8 + + microchip,irq-mirror: + type: boolean + description: + Sets the mirror flag in the IOCON register. Devices with two interrupt + outputs (these are the devices ending with 17 and those that have 16 IOs) + have two IO banks IO 0-7 form bank 1 and IO 8-15 are bank 2. These chips + have two different interrupt outputs One for bank 1 and another for + bank 2. If irq-mirror is set, both interrupts are generated regardless of + the bank that an input change occurred on. If it is not set,the interrupt + are only generated for the bank they belong to. + + microchip,irq-active-high: + type: boolean + description: + Sets the INTPOL flag in the IOCON register.This configures the IRQ output + polarity as active high. + + drive-open-drain: + type: boolean + description: + Sets the ODR flag in the IOCON register. This configures the IRQ output as + open drain active low. + + pinmux: + type: object + properties: + pins: + description: + The list of GPIO pins controlled by this node. Each pin name + corresponds to a physical pin on the GPIO expander. + items: + pattern: '^gpio([0-9]|[1][0-5])$' + maxItems: 16 + + bias-pull-up: + type: boolean + description: + Configures pull-up resistors for the GPIO pins. Absence of this + property will leave the configuration in its default state. + + required: + - pins + + additionalProperties: false + +required: + - compatible + - reg + - gpio-controller + - '#gpio-cells' + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + gpio@21 { + compatible = "microchip,mcp23017"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + + interrupt-parent = <&gpio1>; + interrupts = <17 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + + microchip,irq-mirror; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c_gpio0>, <&gpiopullups>; + reset-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>; + + gpiopullups: pinmux { + pins = "gpio0", "gpio1", "gpio2", "gpio3", + "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio14", "gpio15"; + bias-pull-up; + }; + }; + }; + + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + gpio@0 { + compatible = "microchip,mcp23s17"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + spi-max-frequency = <1000000>; + microchip,spi-present-mask = /bits/ 8 <0x01>; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml index dbb3e1bd58c104..31bc30a8175299 100644 --- a/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml @@ -12,14 +12,24 @@ maintainers: properties: compatible: - enum: - - microchip,lan966x-pinctrl - - microchip,sparx5-pinctrl - - mscc,jaguar2-pinctrl - - mscc,luton-pinctrl - - mscc,ocelot-pinctrl - - mscc,serval-pinctrl - - mscc,servalt-pinctrl + oneOf: + - enum: + - microchip,lan966x-pinctrl + - microchip,lan9691-pinctrl + - microchip,sparx5-pinctrl + - mscc,jaguar2-pinctrl + - mscc,luton-pinctrl + - mscc,ocelot-pinctrl + - mscc,serval-pinctrl + - mscc,servalt-pinctrl + - items: + - enum: + - microchip,lan9698-pinctrl + - microchip,lan9696-pinctrl + - microchip,lan9694-pinctrl + - microchip,lan9693-pinctrl + - microchip,lan9692-pinctrl + - const: microchip,lan9691-pinctrl reg: items: @@ -85,6 +95,7 @@ allOf: contains: enum: - microchip,lan966x-pinctrl + - microchip,lan9691-pinctrl - microchip,sparx5-pinctrl then: properties: diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt deleted file mode 100644 index 2fa5edac7a35a6..00000000000000 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt +++ /dev/null @@ -1,148 +0,0 @@ -Microchip MCP2308/MCP23S08/MCP23017/MCP23S17 driver for -8-/16-bit I/O expander with serial interface (I2C/SPI) - -Required properties: -- compatible : Should be - - "mcp,mcp23s08" (DEPRECATED) for 8 GPIO SPI version - - "mcp,mcp23s17" (DEPRECATED) for 16 GPIO SPI version - - "mcp,mcp23008" (DEPRECATED) for 8 GPIO I2C version or - - "mcp,mcp23017" (DEPRECATED) for 16 GPIO I2C version of the chip - - - "microchip,mcp23s08" for 8 GPIO SPI version - - "microchip,mcp23s17" for 16 GPIO SPI version - - "microchip,mcp23s18" for 16 GPIO SPI version - - "microchip,mcp23008" for 8 GPIO I2C version or - - "microchip,mcp23017" for 16 GPIO I2C version of the chip - - "microchip,mcp23018" for 16 GPIO I2C version - NOTE: Do not use the old mcp prefix any more. It is deprecated and will be - removed. -- #gpio-cells : Should be two. - - first cell is the pin number - - second cell is used to specify flags as described in - 'Documentation/devicetree/bindings/gpio/gpio.txt'. Allowed values defined by - 'include/dt-bindings/gpio/gpio.h' (e.g. GPIO_ACTIVE_LOW). -- gpio-controller : Marks the device node as a GPIO controller. -- reg : For an address on its bus. I2C uses this a the I2C address of the chip. - SPI uses this to specify the chipselect line which the chip is - connected to. The driver and the SPI variant of the chip support - multiple chips on the same chipselect. Have a look at - microchip,spi-present-mask below. - -Required device specific properties (only for SPI chips): -- mcp,spi-present-mask (DEPRECATED) -- microchip,spi-present-mask : This is a present flag, that makes only sense for SPI - chips - as the name suggests. Multiple SPI chips can share the same - SPI chipselect. Set a bit in bit0-7 in this mask to 1 if there is a - chip connected with the corresponding spi address set. For example if - you have a chip with address 3 connected, you have to set bit3 to 1, - which is 0x08. mcp23s08 chip variant only supports bits 0-3. It is not - possible to mix mcp23s08 and mcp23s17 on the same chipselect. Set at - least one bit to 1 for SPI chips. - NOTE: Do not use the old mcp prefix any more. It is deprecated and will be - removed. -- spi-max-frequency = The maximum frequency this chip is able to handle - -Optional properties: -- #interrupt-cells : Should be two. - - first cell is the pin number - - second cell is used to specify flags. -- interrupt-controller: Marks the device node as a interrupt controller. -- drive-open-drain: Sets the ODR flag in the IOCON register. This configures - the IRQ output as open drain active low. -- reset-gpios: Corresponds to the active-low RESET# pin for the chip - -Optional device specific properties: -- microchip,irq-mirror: Sets the mirror flag in the IOCON register. Devices - with two interrupt outputs (these are the devices ending with 17 and - those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and - IO 8-15 are bank 2. These chips have two different interrupt outputs: - One for bank 1 and another for bank 2. If irq-mirror is set, both - interrupts are generated regardless of the bank that an input change - occurred on. If it is not set, the interrupt are only generated for the - bank they belong to. - On devices with only one interrupt output this property is useless. -- microchip,irq-active-high: Sets the INTPOL flag in the IOCON register. This - configures the IRQ output polarity as active high. - -Example I2C (with interrupt): -gpiom1: gpio@20 { - compatible = "microchip,mcp23017"; - gpio-controller; - #gpio-cells = <2>; - reg = <0x20>; - - interrupt-parent = <&gpio1>; - interrupts = <17 IRQ_TYPE_LEVEL_LOW>; - interrupt-controller; - #interrupt-cells=<2>; - microchip,irq-mirror; -}; - -Example SPI: -gpiom1: gpio@0 { - compatible = "microchip,mcp23s17"; - gpio-controller; - #gpio-cells = <2>; - microchip,spi-present-mask = <0x01>; - reg = <0>; - spi-max-frequency = <1000000>; -}; - -Pull-up configuration -===================== - -If pins are used as output, they can also be configured with pull-ups. This is -done with pinctrl. - -Please refer file -for details of the common pinctrl bindings used by client devices, -including the meaning of the phrase "pin configuration node". - -Optional Pinmux properties: --------------------------- -Following properties are required if default setting of pins are required -at boot. -- pinctrl-names: A pinctrl state named per . -- pinctrl[0...n]: Properties to contain the phandle for pinctrl states per - . - -The pin configurations are defined as child of the pinctrl states node. Each -sub-node have following properties: - -Required properties: ------------------- -- pins: List of pins. Valid values of pins properties are: - gpio0 ... gpio7 for the devices with 8 GPIO pins and - gpio0 ... gpio15 for the devices with 16 GPIO pins. - -Optional properties: -------------------- -The following optional property is defined in the pinmux DT binding document -. Absence of this property will leave the configuration -in its default state. - bias-pull-up - -Example with pinctrl to pull-up output pins: -gpio21: gpio@21 { - compatible = "microchip,mcp23017"; - gpio-controller; - #gpio-cells = <0x2>; - reg = <0x21>; - interrupt-parent = <&socgpio>; - interrupts = <0x17 0x8>; - interrupt-names = "mcp23017@21 irq"; - interrupt-controller; - #interrupt-cells = <0x2>; - microchip,irq-mirror; - pinctrl-names = "default"; - pinctrl-0 = <&i2cgpio0irq>, <&gpio21pullups>; - reset-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>; - - gpio21pullups: pinmux { - pins = "gpio0", "gpio1", "gpio2", "gpio3", - "gpio4", "gpio5", "gpio6", "gpio7", - "gpio8", "gpio9", "gpio10", "gpio11", - "gpio12", "gpio13", "gpio14", "gpio15"; - bias-pull-up; - }; -}; diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml index e02595316c9f49..f83dbf32ad1838 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml @@ -33,6 +33,10 @@ properties: - ti,omap5-padconf - ti,j7200-padconf - const: pinctrl-single + - items: + - enum: + - marvell,pxa1908-padconf + - const: pinconf-single reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5424-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5424-tlmm.yaml new file mode 100644 index 00000000000000..5e64a232fc7a4e --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5424-tlmm.yaml @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,ipq5424-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm IPQ5424 TLMM pin controller + +maintainers: + - Bjorn Andersson + +description: + Top Level Mode Multiplexer pin controller in Qualcomm IPQ5424 SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,ipq5424-tlmm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-reserved-ranges: + minItems: 1 + maxItems: 25 + + gpio-line-names: + maxItems: 50 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-ipq5424-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-ipq5424-tlmm-state" + additionalProperties: false + +$defs: + qcom-ipq5424-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 + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + pattern: "^gpio([0-9]|[1-4][0-9])$" + minItems: 1 + maxItems: 50 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + + enum: [ atest_char, atest_char0, atest_char1, atest_char2, atest_char3, + atest_tic, audio_pri, audio_pri0, audio_pri1, audio_sec, + audio_sec0, audio_sec1, core_voltage, cri_trng0, cri_trng1, + cri_trng2, cri_trng3, cxc_clk, cxc_data, dbg_out, gcc_plltest, + gcc_tlmm, gpio, i2c0_scl, i2c0_sda, i2c1_scl, i2c1_sda, i2c11, + mac0, mac1, mdc_mst, mdc_slv, mdio_mst, mdio_slv, pcie0_clk, + pcie0_wake, pcie1_clk, pcie1_wake, pcie2_clk, pcie2_wake, + pcie3_clk, pcie3_wake, pll_test, prng_rosc0, prng_rosc1, + prng_rosc2, prng_rosc3, PTA0_0, PTA0_1, PTA0_2, PTA10, PTA11, + pwm0, pwm1, pwm2, qdss_cti_trig_in_a0, qdss_cti_trig_out_a0, + qdss_cti_trig_in_a1, qdss_cti_trig_out_a1, qdss_cti_trig_in_b0, + qdss_cti_trig_out_b0, qdss_cti_trig_in_b1, qdss_cti_trig_out_b1, + qdss_traceclk_a, qdss_tracectl_a, qdss_tracedata_a, qspi_clk, + qspi_cs, qspi_data, resout, rx0, rx1, rx2, sdc_clk, sdc_cmd, + sdc_data, spi0, spi1, spi10, spi11, tsens_max, uart0, uart1, + wci_txd, wci_rxd, wsi_clk, wsi_data ] + + required: + - pins + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + tlmm: pinctrl@1000000 { + compatible = "qcom,ipq5424-tlmm"; + reg = <0x01000000 0x300000>; + gpio-controller; + #gpio-cells = <0x2>; + gpio-ranges = <&tlmm 0 0 50>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <0x2>; + + uart1_pins: uart1-state { + pins = "gpio43", "gpio44"; + function = "uart1"; + drive-strength = <8>; + bias-pull-up; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml index c1b799167d81b0..055cea5452eb62 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml @@ -48,6 +48,7 @@ properties: - qcom,pm8916-gpio - qcom,pm8917-gpio - qcom,pm8921-gpio + - qcom,pm8937-gpio - qcom,pm8941-gpio - qcom,pm8950-gpio - qcom,pm8953-gpio @@ -184,6 +185,7 @@ allOf: - qcom,pm8226-gpio - qcom,pm8350b-gpio - qcom,pm8550ve-gpio + - qcom,pm8937-gpio - qcom,pm8950-gpio - qcom,pm8953-gpio - qcom,pmi632-gpio @@ -468,6 +470,7 @@ $defs: - gpio1-gpio6 for pm8550vs - gpio1-gpio38 for pm8917 - gpio1-gpio44 for pm8921 + - gpio1-gpio8 for pm8937 (hole on gpio3, gpio4 and gpio6) - gpio1-gpio36 for pm8941 - gpio1-gpio8 for pm8950 (hole on gpio3) - gpio1-gpio8 for pm8953 (hole on gpio3 and gpio6) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml index 43146709e2044d..9364ae05f3e68f 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml @@ -22,6 +22,7 @@ properties: - qcom,pm8226-mpp - qcom,pm8841-mpp - qcom,pm8916-mpp + - qcom,pm8937-mpp - qcom,pm8941-mpp - qcom,pm8950-mpp - qcom,pmi8950-mpp @@ -92,6 +93,7 @@ $defs: this subnode. Valid pins are - mpp1-mpp4 for pm8841 - mpp1-mpp4 for pm8916 + - mpp1-mpp4 for pm8937 - mpp1-mpp8 for pm8941 - mpp1-mpp4 for pm8950 - mpp1-mpp4 for pmi8950 diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcs615-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qcs615-tlmm.yaml new file mode 100644 index 00000000000000..1ce4b5df584abe --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcs615-tlmm.yaml @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,qcs615-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. QCS615 TLMM block + +maintainers: + - Lijuan Gao + +description: + Top Level Mode Multiplexer pin controller in Qualcomm QCS615 SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,qcs615-tlmm + + reg: + maxItems: 3 + + reg-names: + items: + - const: east + - const: west + - const: south + + interrupts: + maxItems: 1 + + gpio-reserved-ranges: + minItems: 1 + maxItems: 62 + + gpio-line-names: + maxItems: 123 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-qcs615-tlmm-state" + - type: object + patternProperties: + "-pins$": + $ref: "#/$defs/qcom-qcs615-tlmm-state" + additionalProperties: false + +$defs: + qcom-qcs615-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 + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + oneOf: + - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-2])$" + - enum: [ sdc1_clk, sdc1_cmd, sdc1_data, sdc1_rclk, + 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_usb, cam_mclk, cci_async, cci_i2c, cci_timer, copy_gp, + copy_phase, cri_trng, dbg_out_clk, ddr_bist, ddr_pxi, dp_hot, + edp_hot, edp_lcd, emac_gcc, emac_phy_intr, forced_usb, gcc_gp, + gp_pdm, gps_tx, hs0_mi2s, hs1_mi2s, jitter_bist, ldo_en, + ldo_update, m_voc, mclk1, mclk2, mdp_vsync, mdp_vsync0_out, + mdp_vsync1_out, mdp_vsync2_out, mdp_vsync3_out, mdp_vsync4_out, + mdp_vsync5_out, mi2s_1, mss_lte, nav_pps_in, nav_pps_out, + pa_indicator_or, pcie_clk_req, pcie_ep_rst, phase_flag, pll_bist, + pll_bypassnl, pll_reset_n, prng_rosc, qdss_cti, qdss_gpio, + qlink_enable, qlink_request, qspi, qup0, qup1, rgmii, + sd_write_protect, sp_cmu, ter_mi2s, tgu_ch, uim1, uim2, usb0_hs, + usb1_hs, usb_phy_ps, vfr_1, vsense_trigger_mirnat, wlan, wsa_clk, + wsa_data ] + + required: + - pins + +required: + - compatible + - reg + - reg-names + +unevaluatedProperties: false + +examples: + - | + #include + + tlmm: pinctrl@3000000 { + compatible = "qcom,qcs615-tlmm"; + reg = <0x03100000 0x300000>, + <0x03500000 0x300000>, + <0x03c00000 0x300000>; + reg-names = "east", "west", "south"; + interrupts = ; + gpio-ranges = <&tlmm 0 0 123>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + qup3-uart2-state { + pins ="gpio16", "gpio17"; + function = "qup0"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcs8300-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qcs8300-tlmm.yaml new file mode 100644 index 00000000000000..bb0d7132886a1a --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcs8300-tlmm.yaml @@ -0,0 +1,118 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,qcs8300-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. QCS8300 TLMM block + +maintainers: + - Jingyi Wang + +description: | + Top Level Mode Multiplexer pin controller in Qualcomm QCS8300 SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,qcs8300-tlmm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-reserved-ranges: + minItems: 1 + maxItems: 67 + + gpio-line-names: + maxItems: 133 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-qcs8300-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-qcs8300-tlmm-state" + additionalProperties: false + +$defs: + qcom-qcs8300-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 + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + oneOf: + - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-2][0-9]|13[0-2])$" + - enum: [ ufs_reset, sdc1_rclk, sdc1_clk, sdc1_cmd, sdc1_data ] + minItems: 1 + maxItems: 36 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + + enum: [ aoss_cti, atest_char, atest_usb2, audio_ref, cam_mclk, + cci_async, cci_i2c_scl, cci_i2c_sda, cci_timer, cri_trng, + dbg_out, ddr_bist, ddr_pxi0, ddr_pxi1, ddr_pxi2, ddr_pxi3, + edp0_hot, edp0_lcd, edp1_lcd, egpio, emac0_mcg0, emac0_mcg1, + emac0_mcg2, emac0_mcg3, emac0_mdc, emac0_mdio, emac0_ptp_aux, + emac0_ptp_pps, gcc_gp1, gcc_gp2, gcc_gp3, gcc_gp4, gcc_gp5, + gpio, hs0_mi2s, hs1_mi2s, hs2_mi2s, ibi_i3c, jitter_bist, + mdp0_vsync0, mdp0_vsync1, mdp0_vsync3, mdp0_vsync6, mdp0_vsync7, + mdp_vsync, mi2s1_data0, mi2s1_data1, mi2s1_sck, mi2s1_ws, + mi2s2_data0, mi2s2_data1, mi2s2_sck, mi2s2_ws, mi2s_mclk0, + mi2s_mclk1, pcie0_clkreq, pcie1_clkreq, phase_flag, pll_bist, + pll_clk, prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, + qdss_cti, qdss_gpio, qup0_se0, qup0_se1, qup0_se2, qup0_se3, + qup0_se4, qup0_se5, qup0_se6, qup0_se7, qup1_se0, qup1_se1, + qup1_se2, qup1_se3, qup1_se4, qup1_se5, qup1_se6, qup1_se7, + qup2_se0, sailss_emac0, sailss_ospi, sail_top, sgmii_phy, + tb_trig, tgu_ch0, tgu_ch1, tgu_ch2, tgu_ch3, tsense_pwm1, + tsense_pwm2, tsense_pwm3, tsense_pwm4, usb2phy_ac, + vsense_trigger ] + + required: + - pins + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + tlmm: pinctrl@f100000 { + compatible = "qcom,qcs8300-tlmm"; + reg = <0x0f100000 0x300000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 133>; + interrupt-controller; + #interrupt-cells = <2>; + + qup-uart7-state { + pins = "gpio43", "gpio44"; + function = "qup0_se7"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml index e9abbf2c0689bc..749dbc563ac50a 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml @@ -17,7 +17,13 @@ allOf: properties: compatible: - const: qcom,sa8775p-tlmm + oneOf: + - items: + - enum: + - qcom,sa8255p-tlmm + - const: qcom,sa8775p-tlmm + - items: + - const: qcom,sa8775p-tlmm reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sar2130p-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sar2130p-tlmm.yaml new file mode 100644 index 00000000000000..b388380b1ce02e --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sar2130p-tlmm.yaml @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,sar2130p-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. SAR2130P TLMM block + +maintainers: + - Dmitry Baryshkov + +description: + Top Level Mode Multiplexer pin controller in Qualcomm SAR2130P SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,sar2130p-tlmm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-reserved-ranges: + minItems: 1 + maxItems: 78 + + gpio-line-names: + maxItems: 156 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-sar2130p-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-sar2130p-tlmm-state" + additionalProperties: false + +$defs: + qcom-sar2130p-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 + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + oneOf: + - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-4][0-9]|15[0-5])$" + - enum: [ sdc1_clk, sdc1_cmd, sdc1_data, sdc1_rclk ] + minItems: 1 + maxItems: 36 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + enum: [ aoss_cti, atest_char, atest_char0, atest_char1, atest_char2, + atest_char3, atest_usb0, atest_usb00, atest_usb01, atest_usb02, + atest_usb03, audio_ref, 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, + ddr_pxi1, ddr_pxi2, ddr_pxi3, dp0_hot, ext_mclk0, ext_mclk1, + gcc_gp1, gcc_gp2, gcc_gp3, gpio, host2wlan_sol, i2s0_data0, + i2s0_data1, i2s0_sck, i2s0_ws, ibi_i3c, jitter_bist, mdp_vsync, + mdp_vsync0, mdp_vsync1, mdp_vsync2, mdp_vsync3, pcie0_clkreqn, + pcie1_clkreqn, phase_flag0, phase_flag1, phase_flag10, + phase_flag11, phase_flag12, phase_flag13, phase_flag14, + phase_flag15, phase_flag16, phase_flag17, phase_flag18, + phase_flag19, phase_flag2, phase_flag20, phase_flag21, + phase_flag22, phase_flag23, phase_flag24, phase_flag25, + phase_flag26, phase_flag27, phase_flag28, phase_flag29, + phase_flag3, phase_flag30, phase_flag31, phase_flag4, + phase_flag5, phase_flag6, phase_flag7, phase_flag8, + phase_flag9, pll_bist, pll_clk, prng_rosc0, prng_rosc1, + prng_rosc2, prng_rosc3, qdss_cti, qdss_gpio, qdss_gpio0, + qdss_gpio1, qdss_gpio10, qdss_gpio11, qdss_gpio12, qdss_gpio13, + qdss_gpio14, qdss_gpio15, qdss_gpio2, qdss_gpio3, qdss_gpio4, + qdss_gpio5, qdss_gpio6, qdss_gpio7, qdss_gpio8, qdss_gpio9, + qspi0, qspi1, qspi2, qspi3, qspi_clk, qspi_cs0, qspi_cs1, qup0, + qup1, qup2, qup3, qup4, qup5, qup6, qup7, qup8, qup9, qup10, + qup11, tb_trig, tgu_ch0, tgu_ch1, tgu_ch2, tgu_ch3, + tmess_prng0, tmess_prng1, tmess_prng2, tmess_prng3, + tsense_pwm1, tsense_pwm2, usb0_phy, vsense_trigger ] + + required: + - pins + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + pinctrl@f100000 { + compatible = "qcom,sar2130p-tlmm"; + reg = <0x0f100000 0x300000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 156>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + + gpio-wo-state { + pins = "gpio1"; + function = "gpio"; + }; + + uart-w-state { + rx-pins { + pins = "gpio26"; + function = "qup7"; + bias-pull-up; + }; + + tx-pins { + pins = "gpio27"; + function = "qup7"; + bias-disable; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml index db721436230181..e90a5274647dfd 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml @@ -16,7 +16,11 @@ description: properties: compatible: - const: qcom,sm8650-lpass-lpi-pinctrl + oneOf: + - const: qcom,sm8650-lpass-lpi-pinctrl + - items: + - const: qcom,sm8750-lpass-lpi-pinctrl + - const: qcom,sm8650-lpass-lpi-pinctrl reg: items: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8750-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8750-tlmm.yaml new file mode 100644 index 00000000000000..7aecc97745a8cd --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8750-tlmm.yaml @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,sm8750-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. SM8750 TLMM block + +maintainers: + - Melody Olvera + +description: + Top Level Mode Multiplexer pin controller in Qualcomm SM8750 SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,sm8750-tlmm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-reserved-ranges: + minItems: 1 + maxItems: 108 + + gpio-line-names: + maxItems: 215 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-sm8750-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-sm8750-tlmm-state" + additionalProperties: false + +$defs: + qcom-sm8750-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 + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + oneOf: + - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-9][0-9]|20[0-9]|21[0-4])$" + - enum: [ ufs_reset, sdc2_clk, sdc2_cmd, sdc2_data ] + minItems: 1 + maxItems: 36 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + enum: [ gpio, aoss_cti, atest_char, atest_usb, audio_ext_mclk0, + audio_ext_mclk1, audio_ref_clk, cam_aon_mclk2, cam_aon_mclk4, + cam_mclk, cci_async_in, cci_i2c_scl, cci_i2c_sda, cci_timer, + cmu_rng, coex_uart1_rx, coex_uart1_tx, coex_uart2_rx, + coex_uart2_tx, dbg_out_clk, ddr_bist_complete, ddr_bist_fail, + ddr_bist_start, ddr_bist_stop, ddr_pxi0, ddr_pxi1, ddr_pxi2, + ddr_pxi3, dp_hot, egpio, gcc_gp1, gcc_gp2, gcc_gp3, gnss_adc0, + gnss_adc1, i2chub0_se0, i2chub0_se1, i2chub0_se2, i2chub0_se3, + i2chub0_se4, i2chub0_se5, i2chub0_se6, i2chub0_se7, i2chub0_se8, + i2chub0_se9, i2s0_data0, i2s0_data1, i2s0_sck, i2s0_ws, + i2s1_data0, i2s1_data1, i2s1_sck, i2s1_ws, ibi_i3c, jitter_bist, + mdp_esync0_out, mdp_esync1_out, mdp_vsync, mdp_vsync0_out, + mdp_vsync1_out, mdp_vsync2_out, mdp_vsync3_out, mdp_vsync5_out, + mdp_vsync_e, nav_gpio0, nav_gpio1, nav_gpio2, nav_gpio3, + pcie0_clk_req_n, phase_flag, pll_bist_sync, pll_clk_aux, + prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti, + qlink_big_enable, qlink_big_request, qlink_little_enable, + qlink_little_request, qlink_wmss, qspi0, qspi1, qspi2, qspi3, + qspi_clk, qspi_cs, qup1_se0, qup1_se1, qup1_se2, qup1_se3, + qup1_se4, qup1_se5, qup1_se6, qup1_se7, qup2_se0, qup2_se1, + qup2_se2, qup2_se3, qup2_se4, qup2_se5, qup2_se6, qup2_se7, + sd_write_protect, sdc40, sdc41, sdc42, sdc43, sdc4_clk, + sdc4_cmd, tb_trig_sdc2, tb_trig_sdc4, tmess_prng0, tmess_prng1, + tmess_prng2, tmess_prng3, tsense_pwm1, tsense_pwm2, tsense_pwm3, + tsense_pwm4, uim0_clk, uim0_data, uim0_present, uim0_reset, + uim1_clk, uim1_data, uim1_present, uim1_reset, usb1_hs, usb_phy, + vfr_0, vfr_1, vsense_trigger_mirnat, wcn_sw, wcn_sw_ctrl ] + + required: + - pins + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + tlmm: pinctrl@f100000 { + compatible = "qcom,sm8750-tlmm"; + reg = <0x0f100000 0x300000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 216>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + + gpio-wo-state { + pins = "gpio1"; + function = "gpio"; + }; + + uart-w-state { + rx-pins { + pins = "gpio60"; + function = "qup1_se7"; + bias-pull-up; + }; + + tx-pins { + pins = "gpio61"; + function = "qup1_se7"; + bias-disable; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml index 56d90c8e1fa3f9..a1805b6e3f6352 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml @@ -119,6 +119,10 @@ additionalProperties: bias-disable: true bias-pull-down: true bias-pull-up: true + input-schmitt-enable: true + input-schmitt-disable: true + drive-open-drain: true + drive-push-pull: true renesas,output-impedance: description: Output impedance for pins on the RZ/V2H(P) SoC. The value provided by this diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml index 4dfb49b0e07f73..68ed714eb0a178 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml @@ -42,10 +42,13 @@ properties: - samsung,exynos5433-wakeup-eint - samsung,exynos7885-wakeup-eint - samsung,exynos850-wakeup-eint + - samsung,exynos8895-wakeup-eint - const: samsung,exynos7-wakeup-eint - items: - enum: - google,gs101-wakeup-eint + - samsung,exynos9810-wakeup-eint + - samsung,exynos990-wakeup-eint - samsung,exynosautov9-wakeup-eint - const: samsung,exynos850-wakeup-eint - const: samsung,exynos7-wakeup-eint @@ -91,14 +94,18 @@ allOf: - if: properties: compatible: - # Match without "contains", to skip newer variants which are still - # compatible with samsung,exynos7-wakeup-eint - enum: - - samsung,s5pv210-wakeup-eint - - samsung,exynos4210-wakeup-eint - - samsung,exynos5433-wakeup-eint - - samsung,exynos7-wakeup-eint - - samsung,exynos7885-wakeup-eint + oneOf: + # Match without "contains", to skip newer variants which are still + # compatible with samsung,exynos7-wakeup-eint + - enum: + - samsung,exynos4210-wakeup-eint + - samsung,exynos7-wakeup-eint + - samsung,s5pv210-wakeup-eint + - contains: + enum: + - samsung,exynos5433-wakeup-eint + - samsung,exynos7885-wakeup-eint + - samsung,exynos8895-wakeup-eint then: properties: interrupts: diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml index 242dd13c276b5a..5296a9e4faaec6 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml @@ -53,6 +53,9 @@ properties: - samsung,exynos7-pinctrl - samsung,exynos7885-pinctrl - samsung,exynos850-pinctrl + - samsung,exynos8895-pinctrl + - samsung,exynos9810-pinctrl + - samsung,exynos990-pinctrl - samsung,exynosautov9-pinctrl - samsung,exynosautov920-pinctrl - tesla,fsd-pinctrl diff --git a/Documentation/devicetree/bindings/pinctrl/semtech,sx1501q.yaml b/Documentation/devicetree/bindings/pinctrl/semtech,sx1501q.yaml index 4214d7311f6bd8..39d7dad3313b6f 100644 --- a/Documentation/devicetree/bindings/pinctrl/semtech,sx1501q.yaml +++ b/Documentation/devicetree/bindings/pinctrl/semtech,sx1501q.yaml @@ -26,6 +26,10 @@ properties: reg: maxItems: 1 + gpio-line-names: + minItems: 5 + maxItems: 17 + interrupts: maxItems: 1 @@ -87,6 +91,45 @@ required: allOf: - $ref: pinctrl.yaml# + - if: + properties: + compatible: + contains: + enum: + - semtech,sx1501q + - semtech,sx1504q + - semtech,sx1507q + then: + properties: + gpio-line-names: + minItems: 5 + maxItems: 5 + - if: + properties: + compatible: + contains: + enum: + - semtech,sx1502q + - semtech,sx1505q + - semtech,sx1508q + then: + properties: + gpio-line-names: + minItems: 9 + maxItems: 9 + - if: + properties: + compatible: + contains: + enum: + - semtech,sx1503q + - semtech,sx1506q + - semtech,sx1509q + then: + properties: + gpio-line-names: + minItems: 17 + maxItems: 17 - if: not: properties: diff --git a/Documentation/devicetree/bindings/pinctrl/sophgo,cv1800-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/sophgo,cv1800-pinctrl.yaml index 1e6a55afe26a7a..feb4785a3fac59 100644 --- a/Documentation/devicetree/bindings/pinctrl/sophgo,cv1800-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/sophgo,cv1800-pinctrl.yaml @@ -58,7 +58,7 @@ patternProperties: pinmux: description: | The list of GPIOs and their mux settings that properties in the - node apply to. This should be set using the GPIOMUX or GPIOMUX2 + node apply to. This should be set using the PINMUX or PINMUX2 macro. bias-pull-up: diff --git a/Documentation/devicetree/bindings/pinctrl/spacemit,k1-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/spacemit,k1-pinctrl.yaml new file mode 100644 index 00000000000000..b01ecd83b71b5e --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/spacemit,k1-pinctrl.yaml @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/spacemit,k1-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SpacemiT K1 SoC Pin Controller + +maintainers: + - Yixun Lan + +properties: + compatible: + const: spacemit,k1-pinctrl + + reg: + items: + - description: pinctrl io memory base + +patternProperties: + '-cfg$': + type: object + additionalProperties: false + + description: + A pinctrl node should contain at least one subnode representing the + pinctrl groups available on the machine. + + patternProperties: + '-pins$': + type: object + additionalProperties: false + + description: + Each subnode will list the pins it needs, and how they should + be configured, with regard to muxer configuration, bias pull, + drive strength, input schmitt trigger, slew rate, power source. + + allOf: + - $ref: pincfg-node.yaml# + - $ref: pinmux-node.yaml# + + properties: + pinmux: + description: + The list of GPIOs and their mux settings that properties in the + node apply to. This should be set using the K1_PADCONF macro to + construct the value. + + bias-disable: true + + bias-pull-down: true + + bias-pull-up: + description: | + typical value for selecting bias pull up or strong pull up. + 0: normal bias pull up + 1: strong bias pull up + enum: [ 0, 1 ] + + drive-strength: + description: | + typical current when output high level. + 1.8V output: 11, 21, 32, 42 (mA) + 3.3V output: 7, 10, 13, 16, 19, 23, 26, 29 (mA) + + input-schmitt: + description: | + typical threshold for schmitt trigger. + 0: buffer mode + 1: trigger mode + 2, 3: trigger mode + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1, 2, 3 ] + + power-source: + description: external power supplies at 1.8v or 3.3v. + enum: [ 1800, 3300 ] + + slew-rate: + description: | + slew rate for output buffer. + 0: disable it + 1: enable it (via bundled value from drive strength) + 2: slow speed 0 + 3: slow speed 1 + 4: medium speed + 5: fast speed + enum: [ 0, 1, 2, 3, 4, 5 ] + + required: + - pinmux + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #define K1_PADCONF(pin, func) (((pin) << 16) | (func)) + + soc { + #address-cells = <2>; + #size-cells = <2>; + + pinctrl@d401e000 { + compatible = "spacemit,k1-pinctrl"; + reg = <0x0 0xd401e000 0x0 0x400>; + + uart0_2_cfg: uart0-2-cfg { + uart0-2-pins { + pinmux = , + ; + + bias-pull-up = <0>; + drive-strength = <32>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml new file mode 100644 index 00000000000000..21f86740a63d41 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml @@ -0,0 +1,176 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/thead,th1520-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: T-Head TH1520 SoC pin controller + +maintainers: + - Emil Renner Berthing + +description: | + Pinmux and pinconf controller in the T-Head TH1520 RISC-V SoC. + + The TH1520 has 3 groups of pads each controlled from different memory ranges. + Confusingly the memory ranges are named + PADCTRL_AOSYS -> PAD Group 1 + PADCTRL1_APSYS -> PAD Group 2 + PADCTRL0_APSYS -> PAD Group 3 + + Each pad can be muxed individually to up to 6 different functions. For most + pads only a few of those 6 configurations are valid though, and a few pads in + group 1 does not support muxing at all. + + Pinconf is fairly regular except for a few pads in group 1 that either can't + be configured or has some special functions. The rest have configurable drive + strength, input enable, schmitt trigger, slew rate, pull-up and pull-down in + addition to a special strong pull up. + + Certain pads in group 1 can be muxed to AUDIO_PA0 - AUDIO_PA30 functions and + are then meant to be used by the audio co-processor. Each such pad can then + be further muxed to either audio GPIO or one of 4 functions such as UART, I2C + and I2S. If the audio pad is muxed to one of the 4 functions then pinconf is + also configured in different registers. All of this is done from a different + AUDIO_IOCTRL memory range and is left to the audio co-processor for now. + +properties: + compatible: + enum: + - thead,th1520-pinctrl + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + thead,pad-group: + description: | + Select the pad group that is associated with the pin controller instance. + + Base Address Name Group + 0xFF_FFF4_A000 PADCTRL_AOSYS 1 + 0xFF_E7F3_C000 PADCTRL1_APSYS 2 + 0xFF_EC00_7000 PADCTRL0_APSYS 3 + + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 3] + +required: + - compatible + - reg + - clocks + +patternProperties: + '-[0-9]+$': + type: object + additionalProperties: false + + patternProperties: + '-pins$': + type: object + allOf: + - $ref: /schemas/pinctrl/pincfg-node.yaml# + - $ref: /schemas/pinctrl/pinmux-node.yaml# + + additionalProperties: false + + description: + A pinctrl node should contain at least one subnode describing one + or more pads and their associated pinmux and pinconf settings. + + properties: + pins: + description: List of pads that properties in the node apply to. + + function: + enum: [ gpio, pwm, uart, ir, i2c, spi, qspi, sdio, audio, i2s, + gmac0, gmac1, dpu0, dpu1, isp, hdmi, bootsel, debug, + clock, jtag, iso7816, efuse, reset ] + description: The mux function to select for the given pins. + + bias-disable: true + + bias-pull-up: + oneOf: + - type: boolean + description: Enable the regular 48kOhm pull-up + - enum: [ 2100, 48000 ] + description: Enable the strong 2.1kOhm pull-up or regular 48kOhm pull-up + + bias-pull-down: + oneOf: + - type: boolean + - const: 44000 + description: Enable the regular 44kOhm pull-down + + drive-strength: + enum: [ 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25 ] + description: Drive strength in mA + + input-enable: true + + input-disable: true + + input-schmitt-enable: true + + input-schmitt-disable: true + + slew-rate: + maximum: 1 + + required: + - pins + +additionalProperties: false + +examples: + - | + padctrl0_apsys: pinctrl@ec007000 { + compatible = "thead,th1520-pinctrl"; + reg = <0xec007000 0x1000>; + clocks = <&apb_clk>; + thead,pad-group = <3>; + + uart0_pins: uart0-0 { + tx-pins { + pins = "UART0_TXD"; + function = "uart"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "UART0_RXD"; + function = "uart"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + }; + + padctrl1_apsys: pinctrl@e7f3c000 { + compatible = "thead,th1520-pinctrl"; + reg = <0xe7f3c000 0x1000>; + clocks = <&apb_clk>; + thead,pad-group = <2>; + + i2c5_pins: i2c5-0 { + i2c-pins { + pins = "QSPI1_CSN0", /* I2C5_SCL */ + "QSPI1_D0_MOSI"; /* I2C5_SDA */ + function = "i2c"; + bias-pull-up = <2100>; + drive-strength = <7>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,versal-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/xlnx,versal-pinctrl.yaml new file mode 100644 index 00000000000000..55ece6a8be5efd --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/xlnx,versal-pinctrl.yaml @@ -0,0 +1,278 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/xlnx,versal-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx Versal Pinctrl + +maintainers: + - Sai Krishna Potthuri + +description: | + Please refer to pinctrl-bindings.txt in this directory for details of the + common pinctrl bindings used by client devices, including the meaning of the + phrase "pin configuration node". + + Versal's pin configuration nodes act as a container for an arbitrary number of + subnodes. Each of these subnodes represents some desired configuration for a + pin, a group, or a list of pins or groups. This configuration can include the + mux function to select on those pin(s)/group(s), and various pin configuration + parameters, such as pull-up, slew rate, etc. + + Each configuration node can consist of multiple nodes describing the pinmux and + pinconf options. Those nodes can be pinmux nodes or pinconf nodes. + +properties: + compatible: + const: xlnx,versal-pinctrl + +patternProperties: + '^(.*-)?(default|gpio-grp)$': + type: object + patternProperties: + '^mux': + type: object + description: + Pinctrl node's client devices use subnodes for pin muxes, + which in turn use below standard properties. + $ref: pinmux-node.yaml# + + properties: + pins: + description: + List of pins to select (either this or "groups" must be specified) + $ref: "#/$defs/pins/properties/pins" + + groups: + description: + List of groups to select (either this or "pins" must be + specified), available groups for this subnode. + anyOf: + - pattern: '^((LPD|PMC)_)MIO([0-9]|[1-6][0-9]|7[0-7])$' + - $ref: "#/$defs/pins/properties/groups" + + function: + description: + Specify the alternative function to be configured for the + given pin groups. + enum: [spi0, spi0_ss, spi1, spi1_ss, can0, can1, i2c0, i2c1, i2c_pmc, ttc0_clk, + ttc0_wav, ttc1_clk, ttc1_wav, ttc2_clk, ttc2_wav, ttc3_clk, ttc3_wav, wwdt0, + wwdt1, sysmon_i2c0, sysmon_i2c0_alrt, uart0, uart0_ctrl, uart1, uart1_ctrl, + gpio0, gpio1, gpio2, emio0, gem0, gem1, trace0, trace0_clk, mdio0, mdio1, gem_tsu0, + pcie0, smap0, usb0, sd0, sd0_pc, sd0_cd, sd0_wp, sd1, sd1_pc, sd1_wp, sd1_cd, + ospi0, ospi0_ss, qspi0, qspi0_fbclk, qspi0_ss, test_clk, test_scan, tamper_trigger] + + required: + - function + + oneOf: + - required: [ groups ] + - required: [ pins ] + + additionalProperties: false + + '^conf': + type: object + description: + Pinctrl node's client devices use subnodes for pin configurations, + which in turn use the standard properties below. + allOf: + - $ref: pincfg-node.yaml# + - $ref: "#/$defs/pins" + + additionalProperties: false + +allOf: + - $ref: pinctrl.yaml# + +required: + - compatible + +additionalProperties: false + +$defs: + pins: + properties: + groups: + description: + List of pin groups to select in this subnode. + items: + enum: [spi0_0_grp, spi0_1_grp, spi0_2_grp, spi0_3_grp, spi0_4_grp, spi0_5_grp, + spi0_ss_0_grp, spi0_ss_1_grp, spi0_ss_2_grp, spi0_ss_3_grp, spi0_ss_4_grp, + spi0_ss_5_grp, spi0_ss_6_grp, spi0_ss_7_grp, spi0_ss_8_grp, spi0_ss_9_grp, + spi0_ss_10_grp, spi0_ss_11_grp, spi0_ss_12_grp, spi0_ss_13_grp, spi0_ss_14_grp, + spi0_ss_15_grp, spi0_ss_16_grp, spi0_ss_17_grp, spi1_0_grp, spi1_1_grp, + spi1_2_grp, spi1_3_grp, spi1_4_grp, spi1_5_grp, spi1_ss_0_grp, spi1_ss_1_grp, + spi1_ss_2_grp, spi1_ss_3_grp, spi1_ss_4_grp, spi1_ss_5_grp, spi1_ss_6_grp, + spi1_ss_7_grp, spi1_ss_8_grp, spi1_ss_9_grp, spi1_ss_10_grp, spi1_ss_11_grp, + spi1_ss_12_grp, spi1_ss_13_grp, spi1_ss_14_grp, spi1_ss_15_grp, spi1_ss_16_grp + spi1_ss_17_grp, can0_0_grp, can0_1_grp, can0_2_grp, can0_3_grp, can0_4_grp, + can0_5_grp, can0_6_grp, can0_7_grp, can0_8_grp, can0_9_grp, can0_10_grp, + can0_11_grp, can0_12_grp, can0_13_grp, can0_14_grp, can0_15_grp, can0_16_grp, + can0_17_grp, can1_0_grp, can1_1_grp, can1_2_grp, can1_3_grp, can1_4_grp, + can1_5_grp, can1_6_grp, can1_7_grp, can1_8_grp, can1_9_grp, can1_10_grp, + can1_11_grp, can1_12_grp, can1_13_grp, can1_14_grp, can1_15_grp, can1_16_grp, + can1_17_grp, can1_18_grp, i2c0_0_grp, i2c0_1_grp, i2c0_2_grp, i2c0_3_grp, + i2c0_4_grp, i2c0_5_grp, i2c0_6_grp, i2c0_7_grp, i2c0_8_grp, i2c0_9_grp, + i2c0_10_grp, i2c0_11_grp, i2c0_12_grp, i2c0_13_grp, i2c0_14_grp, i2c0_15_grp, + i2c0_16_grp, i2c0_17_grp, i2c1_0_grp, i2c1_1_grp, i2c1_2_grp, i2c1_3_grp, + i2c1_4_grp, i2c1_5_grp, i2c1_6_grp, i2c1_7_grp, i2c1_8_grp, i2c1_9_grp, + i2c1_10_grp, i2c1_11_grp, i2c1_12_grp, i2c1_13_grp, i2c1_14_grp, i2c1_15_grp, + i2c1_16_grp, i2c1_17_grp, i2c1_18_grp, i2c_pmc_0_grp, i2c_pmc_1_grp, + i2c_pmc_2_grp, i2c_pmc_3_grp, i2c_pmc_4_grp, i2c_pmc_5_grp, i2c_pmc_6_grp, + i2c_pmc_7_grp, i2c_pmc_8_grp, i2c_pmc_9_grp, i2c_pmc_10_grp, i2c_pmc_11_grp, + i2c_pmc_12_grp, ttc0_clk_0_grp, ttc0_clk_1_grp, ttc0_clk_2_grp, ttc0_clk_3_grp, + ttc0_clk_4_grp, ttc0_clk_5_grp, ttc0_clk_6_grp, ttc0_clk_7_grp, ttc0_clk_8_grp, + ttc0_wav_0_grp, ttc0_wav_1_grp, ttc0_wav_2_grp, ttc0_wav_3_grp, ttc0_wav_4_grp, + ttc0_wav_5_grp, ttc0_wav_6_grp, ttc0_wav_7_grp, ttc0_wav_8_grp, ttc1_clk_0_grp, + ttc1_clk_1_grp, ttc1_clk_2_grp, ttc1_clk_3_grp, ttc1_clk_4_grp, ttc1_clk_5_grp, + ttc1_clk_6_grp, ttc1_clk_7_grp, ttc1_clk_8_grp, ttc1_wav_0_grp, ttc1_wav_1_grp, + ttc1_wav_2_grp, ttc1_wav_3_grp, ttc1_wav_4_grp, ttc1_wav_5_grp, ttc1_wav_6_grp, + ttc1_wav_7_grp, ttc1_wav_8_grp, ttc2_clk_0_grp, ttc2_clk_1_grp, ttc2_clk_2_grp, + ttc2_clk_3_grp, ttc2_clk_4_grp, ttc2_clk_5_grp, ttc2_clk_6_grp, ttc2_clk_7_grp, + ttc2_clk_8_grp, ttc2_wav_0_grp, ttc2_wav_1_grp, ttc2_wav_2_grp, ttc2_wav_3_grp, + ttc2_wav_4_grp, ttc2_wav_5_grp, ttc2_wav_6_grp, ttc2_wav_7_grp, ttc2_wav_8_grp, + ttc3_clk_0_grp, ttc3_clk_1_grp, ttc3_clk_2_grp, ttc3_clk_3_grp, ttc3_clk_4_grp, + ttc3_clk_5_grp, ttc3_clk_6_grp, ttc3_clk_7_grp, ttc3_clk_8_grp, ttc3_wav_0_grp, + ttc3_wav_1_grp, ttc3_wav_2_grp, ttc3_wav_3_grp, ttc3_wav_4_grp, ttc3_wav_5_grp, + ttc3_wav_6_grp, ttc3_wav_7_grp, ttc3_wav_8_grp, wwdt0_0_grp, wwdt0_1_grp, + wwdt0_2_grp, wwdt0_3_grp, wwdt0_4_grp, wwdt0_5_grp, wwdt1_0_grp, wwdt1_1_grp, + wwdt1_2_grp, wwdt1_3_grp, wwdt1_4_grp, wwdt1_5_grp, sysmon_i2c0_0_grp, + sysmon_i2c0_1_grp, sysmon_i2c0_2_grp, sysmon_i2c0_3_grp, sysmon_i2c0_4_grp, + sysmon_i2c0_5_grp, sysmon_i2c0_6_grp, sysmon_i2c0_7_grp, sysmon_i2c0_8_grp, + sysmon_i2c0_9_grp, sysmon_i2c0_10_grp, sysmon_i2c0_11_grp, sysmon_i2c0_12_grp, + sysmon_i2c0_13_grp, sysmon_i2c0_14_grp, sysmon_i2c0_15_grp, + sysmon_i2c0_16_grp, sysmon_i2c0_17_grp, sysmon_i2c0_alrt_0_grp, + sysmon_i2c0_alrt_1_grp, sysmon_i2c0_alrt_2_grp, sysmon_i2c0_alrt_3_grp, + sysmon_i2c0_alrt_4_grp, sysmon_i2c0_alrt_5_grp, sysmon_i2c0_alrt_6_grp, + sysmon_i2c0_alrt_7_grp, sysmon_i2c0_alrt_8_grp, sysmon_i2c0_alrt_9_grp, + sysmon_i2c0_alrt_10_grp, sysmon_i2c0_alrt_11_grp, sysmon_i2c0_alrt_12_grp, + sysmon_i2c0_alrt_13_grp, sysmon_i2c0_alrt_14_grp, sysmon_i2c0_alrt_15_grp, + sysmon_i2c0_alrt_16_grp, sysmon_i2c0_alrt_17_grp, uart0_0_grp, uart0_1_grp, + uart0_2_grp, uart0_3_grp, uart0_4_grp, uart0_5_grp, uart0_6_grp, uart0_7_grp, + uart0_8_grp, uart0_ctrl_0_grp, uart0_ctrl_1_grp, uart0_ctrl_2_grp, + uart0_ctrl_3_grp, uart0_ctrl_4_grp, uart0_ctrl_5_grp, uart0_ctrl_6_grp, + uart0_ctrl_7_grp, uart0_ctrl_8_grp, uart1_0_grp, uart1_1_grp, uart1_2_grp, + uart1_3_grp, uart1_4_grp, uart1_5_grp, uart1_6_grp, uart1_7_grp, uart1_8_grp, + uart1_ctrl_0_grp, uart1_ctrl_1_grp, uart1_ctrl_2_grp, uart1_ctrl_3_grp, + uart1_ctrl_4_grp, uart1_ctrl_5_grp, uart1_ctrl_6_grp, uart1_ctrl_7_grp, + uart1_ctrl_8_grp, gpio0_0_grp, gpio0_1_grp, gpio0_2_grp, gpio0_3_grp, + gpio0_4_grp, gpio0_5_grp, gpio0_6_grp, gpio0_7_grp, gpio0_8_grp, gpio0_9_grp, + gpio0_10_grp, gpio0_11_grp, gpio0_12_grp, gpio0_13_grp, gpio0_14_grp, + gpio0_15_grp, gpio0_16_grp, gpio0_17_grp, gpio0_18_grp, gpio0_19_grp, + gpio0_20_grp, gpio0_21_grp, gpio0_22_grp, gpio0_23_grp, gpio0_24_grp, + gpio0_25_grp, gpio1_0_grp, gpio1_1_grp, gpio1_2_grp, gpio1_3_grp, gpio1_4_grp, + gpio1_5_grp, gpio1_6_grp, gpio1_7_grp, gpio1_8_grp, gpio1_9_grp, + gpio1_10_grp, gpio1_11_grp, gpio1_12_grp, gpio1_13_grp, gpio1_14_grp, + gpio1_15_grp, gpio1_16_grp, gpio1_17_grp, gpio1_18_grp, gpio1_19_grp, + gpio1_20_grp, gpio1_21_grp, gpio1_22_grp, gpio1_23_grp, gpio1_24_grp, + gpio1_25_grp, gpio2_0_grp, gpio2_1_grp, gpio2_2_grp, gpio2_3_grp, gpio2_4_grp, + gpio2_5_grp, gpio2_6_grp, gpio2_7_grp, gpio2_8_grp, gpio2_9_grp, gpio2_10_grp, + gpio2_11_grp, gpio2_12_grp, gpio2_13_grp, gpio2_14_grp, gpio2_15_grp, + gpio2_16_grp, gpio2_17_grp, gpio2_18_grp, gpio2_19_grp, gpio2_20_grp, + gpio2_21_grp, gpio2_22_grp, gpio2_23_grp, gpio2_24_grp, gpio2_25_grp, + emio0_0_grp, emio0_1_grp, emio0_2_grp, emio0_3_grp, emio0_4_grp, emio0_5_grp, + emio0_6_grp, emio0_7_grp, emio0_8_grp, emio0_9_grp, emio0_10_grp, + emio0_11_grp, emio0_12_grp, emio0_13_grp, emio0_14_grp, emio0_15_grp, + emio0_16_grp, emio0_17_grp, emio0_18_grp, emio0_19_grp, emio0_20_grp, + emio0_21_grp, emio0_22_grp, emio0_23_grp, emio0_24_grp, emio0_25_grp, + emio0_26_grp, emio0_27_grp, emio0_28_grp, emio0_29_grp, emio0_30_grp, + emio0_31_grp, emio0_32_grp, emio0_33_grp, emio0_34_grp, emio0_35_grp, + emio0_36_grp, emio0_37_grp, emio0_38_grp, emio0_39_grp, emio0_40_grp, + emio0_41_grp, emio0_42_grp, emio0_43_grp, emio0_44_grp, emio0_45_grp, + emio0_46_grp, emio0_47_grp, emio0_48_grp, emio0_49_grp, emio0_50_grp, + emio0_51_grp, emio0_52_grp, emio0_53_grp, emio0_54_grp, emio0_55_grp, + emio0_56_grp, emio0_57_grp, emio0_58_grp, emio0_59_grp, emio0_60_grp, + emio0_61_grp, emio0_62_grp, emio0_63_grp, emio0_64_grp, emio0_65_grp, + emio0_66_grp, emio0_67_grp, emio0_68_grp, emio0_69_grp, emio0_70_grp, + emio0_71_grp, emio0_72_grp, emio0_73_grp, emio0_74_grp, emio0_75_grp, + emio0_76_grp, emio0_77_grp, gem0_0_grp, gem0_1_grp, gem1_0_grp, gem1_1_grp, + trace0_0_grp, trace0_1_grp, trace0_2_grp, trace0_clk_0_grp, trace0_clk_1_grp, + trace0_clk_2_grp, mdio0_0_grp, mdio0_1_grp, mdio1_0_grp, mdio1_1_grp, + gem_tsu0_0_grp, gem_tsu0_1_grp, gem_tsu0_2_grp, gem_tsu0_3_grp, pcie0_0_grp, + pcie0_1_grp, pcie0_2_grp, smap0_0_grp, usb0_0_grp, sd0_0_grp, sd0_1_grp, + sd0_2_grp, sd0_3_grp, sd0_4_grp, sd0_5_grp, sd0_6_grp, sd0_7_grp, sd0_8_grp, + sd0_9_grp, sd0_10_grp, sd0_11_grp, sd0_12_grp, sd0_13_grp, sd0_14_grp, + sd0_15_grp, sd0_16_grp, sd0_17_grp, sd0_18_grp, sd0_19_grp, sd0_20_grp, + sd0_21_grp, sd0_pc_0_grp, sd0_pc_1_grp, sd0_cd_0_grp, sd0_cd_1_grp, + sd0_wp_0_grp, sd0_wp_1_grp, sd1_0_grp, sd1_1_grp, sd1_2_grp, sd1_3_grp, + sd1_4_grp, sd1_5_grp, sd1_6_grp, sd1_7_grp, sd1_8_grp, sd1_9_grp, sd1_10_grp, + sd1_11_grp, sd1_12_grp, sd1_13_grp, sd1_14_grp, sd1_15_grp, sd1_16_grp, + sd1_17_grp, sd1_18_grp, sd1_19_grp, sd1_20_grp, sd1_21_grp, sd1_pc_0_grp, + sd1_pc_1_grp, sd1_cd_0_grp, sd1_cd_1_grp, sd1_wp_0_grp, sd1_wp_1_grp, + ospi0_0_grp, ospi0_ss_0_grp, qspi0_0_grp, qspi0_fbclk_0_grp, qspi0_ss_0_grp, + test_clk_0_grp, test_scan_0_grp, tamper_trigger_0_grp] + minItems: 1 + maxItems: 78 + + pins: + description: + List of pin names to select in this subnode. + items: + pattern: '^((LPD|PMC)_)MIO([0-9]|[1-6][0-9]|7[0-7])$' + minItems: 1 + maxItems: 78 + + bias-pull-up: true + bias-pull-down: true + bias-disable: true + input-schmitt-enable: true + input-schmitt-disable: true + bias-high-impedance: true + low-power-enable: true + low-power-disable: true + + slew-rate: + enum: [0, 1] + + output-enable: + description: + This will internally disable the tri-state for MIO pins. + + drive-strength: + description: + Selects the drive strength for MIO pins, in mA. + enum: [2, 4, 8, 12] + + power-source: + enum: [0, 1] + + oneOf: + - required: [ groups ] + - required: [ pins ] + + additionalProperties: false + +examples: + - | + #include + pinctrl { + compatible = "xlnx,versal-pinctrl"; + + uart0-default { + mux { + groups = "uart0_4_grp", "uart0_5_grp"; + function = "uart0"; + }; + + conf { + groups = "uart0_4_grp"; + slew-rate = ; + power-source = ; + }; + + conf-rx { + pins = "PMC_MIO42"; + bias-pull-up; + }; + + conf-tx { + pins = "PMC_MIO43"; + bias-disable; + input-schmitt-disable; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml index c21a66422d4fee..9de3fe73c1eb65 100644 --- a/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpc.yaml @@ -30,6 +30,7 @@ properties: - enum: - fsl,imx6qp-gpc - fsl,imx6sl-gpc + - fsl,imx6sll-gpc - fsl,imx6sx-gpc - fsl,imx6ul-gpc - const: fsl,imx6q-gpc diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml index 8985e2df8a5662..591a080ca3ff0f 100644 --- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml @@ -23,6 +23,7 @@ properties: compatible: enum: + - mediatek,mt6735-power-controller - mediatek,mt6795-power-controller - mediatek,mt8167-power-controller - mediatek,mt8173-power-controller @@ -54,6 +55,10 @@ patternProperties: patternProperties: "^power-domain@[0-9a-f]+$": $ref: "#/$defs/power-domain-node" + patternProperties: + "^power-domain@[0-9a-f]+$": + $ref: "#/$defs/power-domain-node" + unevaluatedProperties: false unevaluatedProperties: false unevaluatedProperties: false unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 929b7ef9c1bcda..655687369a238a 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -32,11 +32,14 @@ properties: - qcom,msm8998-rpmpd - qcom,qcm2290-rpmpd - qcom,qcs404-rpmpd + - qcom,qcs615-rpmhpd + - qcom,qcs8300-rpmhpd - qcom,qdu1000-rpmhpd - qcom,qm215-rpmpd - qcom,sa8155p-rpmhpd - qcom,sa8540p-rpmhpd - qcom,sa8775p-rpmhpd + - qcom,sar2130p-rpmhpd - qcom,sc7180-rpmhpd - qcom,sc7280-rpmhpd - qcom,sc8180x-rpmhpd @@ -58,6 +61,7 @@ properties: - qcom,sm8450-rpmhpd - qcom,sm8550-rpmhpd - qcom,sm8650-rpmhpd + - qcom,sm8750-rpmhpd - qcom,x1e80100-rpmhpd - items: - enum: diff --git a/Documentation/devicetree/bindings/power/reset/mt6323-poweroff.txt b/Documentation/devicetree/bindings/power/reset/mt6323-poweroff.txt deleted file mode 100644 index 933f0c48e88744..00000000000000 --- a/Documentation/devicetree/bindings/power/reset/mt6323-poweroff.txt +++ /dev/null @@ -1,20 +0,0 @@ -Device Tree Bindings for Power Controller on MediaTek PMIC - -The power controller which could be found on PMIC is responsible for externally -powering off or on the remote MediaTek SoC through the circuit BBPU. - -Required properties: -- compatible: Should be one of follows - "mediatek,mt6323-pwrc": for MT6323 PMIC - -Example: - - pmic { - compatible = "mediatek,mt6323"; - - ... - - power-controller { - compatible = "mediatek,mt6323-pwrc"; - }; - } diff --git a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.yaml b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.yaml index 627f8a6078c299..7f5f94673e9c24 100644 --- a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.yaml +++ b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.yaml @@ -31,6 +31,10 @@ properties: allOf: - $ref: reboot-mode.yaml# +patternProperties: + "^mode-.*$": + maxItems: 1 + required: - compatible - nvmem-cells diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml index fc8105a7b9b268..3da3d02a669089 100644 --- a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml +++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml @@ -54,6 +54,10 @@ required: - compatible - reg +patternProperties: + "^mode-.*$": + maxItems: 1 + unevaluatedProperties: false allOf: @@ -75,6 +79,9 @@ allOf: reg-names: items: - const: pon + else: + patternProperties: + "^mode-.*$": false # Special case for pm8941, which doesn't store reset mode - if: diff --git a/Documentation/devicetree/bindings/power/reset/reboot-mode.yaml b/Documentation/devicetree/bindings/power/reset/reboot-mode.yaml index ad0a0b95cec126..3ddac06cec7277 100644 --- a/Documentation/devicetree/bindings/power/reset/reboot-mode.yaml +++ b/Documentation/devicetree/bindings/power/reset/reboot-mode.yaml @@ -28,13 +28,13 @@ description: | properties: mode-normal: - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: /schemas/types.yaml#/definitions/uint32-array description: Default value to set on a reboot if no command was provided. patternProperties: "^mode-.*$": - $ref: /schemas/types.yaml#/definitions/uint32 + $ref: /schemas/types.yaml#/definitions/uint32-array additionalProperties: true diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.yaml b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.yaml index b6acff199cdece..79ffc78b23eaf9 100644 --- a/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.yaml +++ b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.yaml @@ -32,6 +32,10 @@ properties: allOf: - $ref: reboot-mode.yaml# +patternProperties: + "^mode-.*$": + maxItems: 1 + unevaluatedProperties: false required: diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml b/Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml index 75061124d9a8b7..19d3093e6cd2f7 100644 --- a/Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml +++ b/Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml @@ -31,6 +31,10 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 description: Offset in the register map for the reboot register (in bytes). + reg: + maxItems: 1 + description: Base address and size for the reboot register. + regmap: $ref: /schemas/types.yaml#/definitions/phandle deprecated: true @@ -45,9 +49,14 @@ properties: priority: default: 192 +oneOf: + - required: + - offset + - required: + - reg + required: - compatible - - offset additionalProperties: false diff --git a/Documentation/devicetree/bindings/power/supply/qcom,pmi8998-charger.yaml b/Documentation/devicetree/bindings/power/supply/qcom,pmi8998-charger.yaml index 277c47e048b654..a0f9d49ff8fb60 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom,pmi8998-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/qcom,pmi8998-charger.yaml @@ -60,7 +60,6 @@ examples: pmic { #address-cells = <1>; #size-cells = <0>; - #interrupt-cells = <4>; charger@1000 { compatible = "qcom,pmi8998-charger"; diff --git a/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml b/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml index a846a4d14ca946..f5aa72502b4e0c 100644 --- a/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml @@ -30,23 +30,4 @@ properties: - constant-charge-voltage-max-microvolt: maximum constant input voltage. additionalProperties: false - -examples: - - | - bat: battery { - compatible = "simple-battery"; - charge-term-current-microamp = <120000>; - constant-charge-voltage-max-microvolt = <4350000>; - }; - - pmic { - #address-cells = <1>; - #size-cells = <0>; - - battery@a00 { - compatible = "sprd,sc2731-charger"; - reg = <0x0>; - phys = <&ssphy>; - monitored-battery = <&bat>; - }; - }; +... diff --git a/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml b/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml index 9108a2841caf66..c1de2c80291dfe 100644 --- a/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml +++ b/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml @@ -27,6 +27,11 @@ properties: battery-detect-gpios: maxItems: 1 + bat-detect-gpio: + maxItems: 1 + deprecated: true + description: use battery-detect-gpios instead + interrupts: maxItems: 1 @@ -65,40 +70,4 @@ required: - monitored-battery additionalProperties: false - -examples: - - | - #include - bat: battery { - compatible = "simple-battery"; - charge-full-design-microamp-hours = <1900000>; - constant-charge-voltage-max-microvolt = <4350000>; - ocv-capacity-celsius = <20>; - ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, - <4022000 85>, <3983000 80>, <3949000 75>, - <3917000 70>, <3889000 65>, <3864000 60>, - <3835000 55>, <3805000 50>, <3787000 45>, - <3777000 40>, <3773000 35>, <3770000 30>, - <3765000 25>, <3752000 20>, <3724000 15>, - <3680000 10>, <3605000 5>, <3400000 0>; - // ... - }; - - pmic { - #address-cells = <1>; - #size-cells = <0>; - - battery@a00 { - compatible = "sprd,sc2731-fgu"; - reg = <0xa00>; - battery-detect-gpios = <&pmic_eic 9 GPIO_ACTIVE_HIGH>; - interrupt-parent = <&sc2731_pmic>; - interrupts = <4>; - io-channels = <&pmic_adc 5>, <&pmic_adc 14>; - io-channel-names = "bat-temp", "charge-vol"; - nvmem-cells = <&fgu_calib>; - nvmem-cell-names = "fgu_calib"; - monitored-battery = <&bat>; - sprd,calib-resistance-micro-ohms = <21500>; - }; - }; +... diff --git a/Documentation/devicetree/bindings/power/supply/ti,twl6030-charger.yaml b/Documentation/devicetree/bindings/power/supply/ti,twl6030-charger.yaml new file mode 100644 index 00000000000000..fc604d8a469dff --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/ti,twl6030-charger.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/ti,twl6030-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TWL6030/32 BCI (Battery Charger Interface) + +description: + The battery charger needs to be configured to do any charging besides of + precharging. The GPADC in the PMIC has to be used to get the related + voltages. + +maintainers: + - Andreas Kemnade + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + oneOf: + - const: ti,twl6030-charger + - items: + - const: ti,twl6032-charger + - const: ti,twl6030-charger + + interrupts: + items: + - description: Charger Control Interrupt + - description: Charger Fault Interrupt + + io-channels: + items: + - description: VBUS Voltage Channel + + io-channel-names: + items: + - const: vusb + + monitored-battery: true + +required: + - compatible + - interrupts + - monitored-battery + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml b/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml index ec6115d3796bab..aa35209f74cfa8 100644 --- a/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml +++ b/Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml @@ -27,7 +27,7 @@ properties: maxItems: 1 "#pwm-cells": - const: 2 + const: 3 clocks: maxItems: 1 @@ -44,5 +44,5 @@ examples: compatible = "adi,axi-pwmgen-2.00.a"; reg = <0x44b00000 0x1000>; clocks = <&spi_clk>; - #pwm-cells = <2>; + #pwm-cells = <3>; }; diff --git a/Documentation/devicetree/bindings/pwm/airoha,en7581-pwm.yaml b/Documentation/devicetree/bindings/pwm/airoha,en7581-pwm.yaml new file mode 100644 index 00000000000000..f36387572a9781 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/airoha,en7581-pwm.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/airoha,en7581-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha EN7581 PWM Controller + +maintainers: + - Lorenzo Bianconi + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + const: airoha,en7581-pwm + + "#pwm-cells": + const: 3 + +required: + - compatible + - "#pwm-cells" + +additionalProperties: false + +examples: + - | + pwm { + compatible = "airoha,en7581-pwm"; + + #pwm-cells = <3>; + }; diff --git a/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml b/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml index e021cf59421a6e..cc3ebd4deeb695 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml @@ -39,6 +39,7 @@ properties: - amlogic,meson-s4-pwm - items: - enum: + - amlogic,c3-pwm - amlogic,meson-a1-pwm - const: amlogic,meson-s4-pwm - items: diff --git a/Documentation/devicetree/bindings/regulator/lltc,ltc3676.yaml b/Documentation/devicetree/bindings/regulator/lltc,ltc3676.yaml new file mode 100644 index 00000000000000..f47eacf96cd67c --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/lltc,ltc3676.yaml @@ -0,0 +1,167 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/lltc,ltc3676.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Linear Technology LTC3676 8-output regulators + +maintainers: + - Tim Harvey + +description: | + LTC3676 contains eight regulators, 4 switching SW1..SW4 and four LDO1..4 . + +properties: + compatible: + const: lltc,ltc3676 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + regulators: + type: object + additionalProperties: false + description: | + List of regulators provided by this controller, must be named + after their hardware counterparts (SW|LDO)[1-4]. + + patternProperties: + "^(sw[1-4]|ldo[24])$": + type: object + unevaluatedProperties: false + $ref: regulator.yaml# + description: + Properties for single SW or LDO regulator. Regulators SW1..SW4 can + regulate the feedback reference from 412.5mV to 800mV in 12.5 mV + steps. The output voltage thus ranges between 0.4125 * (1 + R1/R2) V + and 0.8 * (1 + R1/R2) V. + Regulators LDO1, LDO2, LDO4 have a fixed 0.725 V reference and thus + output 0.725 * (1 + R1/R2) V. + The LDO1 standby regulator can not be disabled and thus should have + the regulator-always-on property set. + + properties: + lltc,fb-voltage-divider: + description: + An array of two integers containing the resistor values + R1 and R2 of the feedback voltage divider in ohms. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 2 + + required: + - lltc,fb-voltage-divider + + properties: + ldo1: + type: object + unevaluatedProperties: false + $ref: regulator.yaml# + description: + The LDO1 standby regulator can not be disabled and thus should + have the regulator-always-on property set. See patternProperties + description above for the rest of the details. + + properties: + lltc,fb-voltage-divider: + description: + An array of two integers containing the resistor values + R1 and R2 of the feedback voltage divider in ohms. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 2 + maxItems: 2 + + required: + - lltc,fb-voltage-divider + - regulator-always-on + + ldo3: + type: object + unevaluatedProperties: false + $ref: regulator.yaml# + description: + The LDO3 regulator is fixed to 1.8 V. See patternProperties + description above for the rest of the details. + +required: + - compatible + - reg + - regulators + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@3c { + compatible = "lltc,ltc3676"; + reg = <0x3c>; + + regulators { + sw1_reg: sw1 { + regulator-min-microvolt = <674400>; + regulator-max-microvolt = <1308000>; + lltc,fb-voltage-divider = <127000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <1033310>; + regulator-max-microvolt = <200400>; + lltc,fb-voltage-divider = <301000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: sw3 { + regulator-min-microvolt = <674400>; + regulator-max-microvolt = <130800>; + lltc,fb-voltage-divider = <127000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <868310>; + regulator-max-microvolt = <168400>; + lltc,fb-voltage-divider = <221000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: ldo2 { + regulator-min-microvolt = <2490375>; + regulator-max-microvolt = <2490375>; + lltc,fb-voltage-divider = <487000 200000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3_reg: ldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + ldo4_reg: ldo4 { + regulator-min-microvolt = <3023250>; + regulator-max-microvolt = <3023250>; + lltc,fb-voltage-divider = <634000 200000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/regulator/ltc3676.txt b/Documentation/devicetree/bindings/regulator/ltc3676.txt deleted file mode 100644 index d4eb366ce18ce2..00000000000000 --- a/Documentation/devicetree/bindings/regulator/ltc3676.txt +++ /dev/null @@ -1,94 +0,0 @@ -Linear Technology LTC3676 8-output regulators - -Required properties: -- compatible: "lltc,ltc3676" -- reg: I2C slave address - -Required child node: -- regulators: Contains eight regulator child nodes sw1, sw2, sw3, sw4, - ldo1, ldo2, ldo3, and ldo4, specifying the initialization data as - documented in Documentation/devicetree/bindings/regulator/regulator.txt. - -Each regulator is defined using the standard binding for regulators. The -nodes for sw1, sw2, sw3, sw4, ldo1, ldo2 and ldo4 additionally need to specify -the resistor values of their external feedback voltage dividers: - -Required properties (not on ldo3): -- lltc,fb-voltage-divider: An array of two integers containing the resistor - values R1 and R2 of the feedback voltage divider in ohms. - -Regulators sw1, sw2, sw3, sw4 can regulate the feedback reference from: -412.5mV to 800mV in 12.5 mV steps. The output voltage thus ranges between -0.4125 * (1 + R1/R2) V and 0.8 * (1 + R1/R2) V. - -Regulators ldo1, ldo2, and ldo4 have a fixed 0.725 V reference and thus output -0.725 * (1 + R1/R2) V. The ldo3 regulator is fixed to 1.8 V. The ldo1 standby -regulator can not be disabled and thus should have the regulator-always-on -property set. - -Example: - - ltc3676: pmic@3c { - compatible = "lltc,ltc3676"; - reg = <0x3c>; - - regulators { - sw1_reg: sw1 { - regulator-min-microvolt = <674400>; - regulator-max-microvolt = <1308000>; - lltc,fb-voltage-divider = <127000 200000>; - regulator-ramp-delay = <7000>; - regulator-boot-on; - regulator-always-on; - }; - - sw2_reg: sw2 { - regulator-min-microvolt = <1033310>; - regulator-max-microvolt = <200400>; - lltc,fb-voltage-divider = <301000 200000>; - regulator-ramp-delay = <7000>; - regulator-boot-on; - regulator-always-on; - }; - - sw3_reg: sw3 { - regulator-min-microvolt = <674400>; - regulator-max-microvolt = <130800>; - lltc,fb-voltage-divider = <127000 200000>; - regulator-ramp-delay = <7000>; - regulator-boot-on; - regulator-always-on; - }; - - sw4_reg: sw4 { - regulator-min-microvolt = <868310>; - regulator-max-microvolt = <168400>; - lltc,fb-voltage-divider = <221000 200000>; - regulator-ramp-delay = <7000>; - regulator-boot-on; - regulator-always-on; - }; - - ldo2_reg: ldo2 { - regulator-min-microvolt = <2490375>; - regulator-max-microvolt = <2490375>; - lltc,fb-voltage-divider = <487000 200000>; - regulator-boot-on; - regulator-always-on; - }; - - ldo3_reg: ldo3 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - }; - - ldo4_reg: ldo4 { - regulator-min-microvolt = <3023250>; - regulator-max-microvolt = <3023250>; - lltc,fb-voltage-divider = <634000 200000>; - regulator-boot-on; - regulator-always-on; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/regulator/qcom,qca6390-pmu.yaml b/Documentation/devicetree/bindings/regulator/qcom,qca6390-pmu.yaml index 11ed04c9554299..47c425c9fff16f 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,qca6390-pmu.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,qca6390-pmu.yaml @@ -18,6 +18,7 @@ properties: compatible: enum: - qcom,qca6390-pmu + - qcom,wcn6750-pmu - qcom,wcn6855-pmu - qcom,wcn7850-pmu @@ -27,15 +28,27 @@ properties: vddaon-supply: description: VDD_AON supply regulator handle + vddasd-supply: + description: VDD_ASD supply regulator handle + vdddig-supply: description: VDD_DIG supply regulator handle vddpmu-supply: description: VDD_PMU supply regulator handle + vddpmumx-supply: + description: VDD_PMU_MX supply regulator handle + + vddpmucx-supply: + description: VDD_PMU_CX supply regulator handle + vddio1p2-supply: description: VDD_IO_1P2 supply regulator handle + vddrfa0p8-supply: + description: VDD_RFA_0P8 supply regulator handle + vddrfa0p95-supply: description: VDD_RFA_0P95 supply regulator handle @@ -45,12 +58,18 @@ properties: vddrfa1p3-supply: description: VDD_RFA_1P3 supply regulator handle + vddrfa1p7-supply: + description: VDD_RFA_1P7 supply regulator handle + vddrfa1p8-supply: description: VDD_RFA_1P8 supply regulator handle vddrfa1p9-supply: description: VDD_RFA_1P9 supply regulator handle + vddrfa2p2-supply: + description: VDD_RFA_2P2 supply regulator handle + vddpcie1p3-supply: description: VDD_PCIE_1P3 supply regulator handle @@ -72,6 +91,10 @@ properties: maxItems: 1 description: GPIO line indicating the state of the clock supply to the BT module + xo-clk-gpios: + maxItems: 1 + description: GPIO line allowing to select the XO clock configuration for the module + clocks: maxItems: 1 description: Reference clock handle @@ -109,6 +132,20 @@ allOf: - vddpcie1p3-supply - vddpcie1p9-supply - vddio-supply + - if: + properties: + compatible: + contains: + const: qcom,wcn6750-pmu + then: + required: + - vddaon-supply + - vddasd-supply + - vddpmu-supply + - vddrfa0p8-supply + - vddrfa1p2-supply + - vddrfa1p7-supply + - vddrfa2p2-supply - if: properties: compatible: @@ -119,6 +156,8 @@ allOf: - vddio-supply - vddaon-supply - vddpmu-supply + - vddpmumx-supply + - vddpmucx-supply - vddrfa0p95-supply - vddrfa1p3-supply - vddrfa1p9-supply diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index 27c6d5152413fc..3a5a0a6cf5cc70 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -349,7 +349,6 @@ allOf: properties: compatible: enum: - - qcom,pm8550ve-rpmh-regulators - qcom,pm8550vs-rpmh-regulators then: patternProperties: @@ -385,6 +384,7 @@ allOf: compatible: enum: - qcom,pmc8380-rpmh-regulators + - qcom,pm8550ve-rpmh-regulators then: patternProperties: "^vdd-l[1-3]-supply$": true diff --git a/Documentation/devicetree/bindings/regulator/qcom-labibb-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom-labibb-regulator.yaml index e987c39b223e75..83965076d6ab1f 100644 --- a/Documentation/devicetree/bindings/regulator/qcom-labibb-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom-labibb-regulator.yaml @@ -16,7 +16,12 @@ description: properties: compatible: - const: qcom,pmi8998-lab-ibb + oneOf: + - const: qcom,pmi8998-lab-ibb + - items: + - enum: + - qcom,pmi8950-lab-ibb + - const: qcom,pmi8998-lab-ibb lab: type: object diff --git a/Documentation/devicetree/bindings/regulator/sprd,sc2731-regulator.yaml b/Documentation/devicetree/bindings/regulator/sprd,sc2731-regulator.yaml index ffb2924dde36f9..9bd752bab68e78 100644 --- a/Documentation/devicetree/bindings/regulator/sprd,sc2731-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/sprd,sc2731-regulator.yaml @@ -43,25 +43,4 @@ required: - compatible additionalProperties: false - -examples: - - | - regulators { - compatible = "sprd,sc2731-regulator"; - - BUCK_CPU0 { - regulator-name = "vddarm0"; - regulator-min-microvolt = <400000>; - regulator-max-microvolt = <1996875>; - regulator-ramp-delay = <25000>; - regulator-always-on; - }; - - LDO_CAMA0 { - regulator-name = "vddcama0"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <3750000>; - regulator-enable-ramp-delay = <100>; - }; - }; ... diff --git a/Documentation/devicetree/bindings/regulator/vctrl-regulator.yaml b/Documentation/devicetree/bindings/regulator/vctrl-regulator.yaml new file mode 100644 index 00000000000000..6132b8e5b49806 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/vctrl-regulator.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/vctrl-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Voltage controlled regulators + +maintainers: + - Heiko Stuebner + +allOf: + - $ref: regulator.yaml# + +properties: + compatible: + const: vctrl-regulator + + ctrl-supply: + description: Regulator supplying the control voltage + + ctrl-voltage-range: + description: + Array of two integer values describing the range (min/max) of the + control voltage. The values specify the control voltage needed to + generate the corresponding regulator-min/max-microvolt output + voltage. + minItems: 2 + maxItems: 2 + $ref: /schemas/types.yaml#/definitions/uint32-array + + min-slew-down-rate: + description: + Describes how slowly the regulator voltage will decay down in the + worst case (lightest expected load). Specified in uV / us (like + main regulator ramp rate). This value is required when + ovp-threshold-percent is specified. + $ref: /schemas/types.yaml#/definitions/uint32 + + ovp-threshold-percent: + description: + Overvoltage protection (OVP) threshold of the regulator in percent. + Some regulators have an OVP circuitry which shuts down the regulator + when the actual output voltage deviates beyond a certain margin from + the expected value for a given control voltage. On larger voltage + decreases this can occur undesiredly since the output voltage does + not adjust immediately to changes in the control voltage. To avoid + this situation the vctrl driver breaks down larger voltage decreases + into multiple steps, where each step is within the OVP threshold. + minimum: 0 + maximum: 100 + +unevaluatedProperties: false + +dependencies: + ovp-threshold-percent: [ min-slew-down-rate ] + +required: + - compatible + - ctrl-supply + - ctrl-voltage-range + - regulator-min-microvolt + - regulator-max-microvolt + +examples: + - | + vctrl-reg { + compatible = "vctrl-regulator"; + regulator-name = "vctrl_reg"; + + ctrl-supply = <&ctrl_reg>; + ctrl-voltage-range = <200000 500000>; + + min-slew-down-rate = <225>; + ovp-threshold-percent = <16>; + + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1500000>; + }; +... diff --git a/Documentation/devicetree/bindings/regulator/vctrl.txt b/Documentation/devicetree/bindings/regulator/vctrl.txt deleted file mode 100644 index e940377cfd690e..00000000000000 --- a/Documentation/devicetree/bindings/regulator/vctrl.txt +++ /dev/null @@ -1,49 +0,0 @@ -Bindings for Voltage controlled regulators -========================================== - -Required properties: --------------------- -- compatible : must be "vctrl-regulator". -- regulator-min-microvolt : smallest voltage consumers may set -- regulator-max-microvolt : largest voltage consumers may set -- ctrl-supply : The regulator supplying the control voltage. -- ctrl-voltage-range : an array of two integer values describing the range - (min/max) of the control voltage. The values specify - the control voltage needed to generate the corresponding - regulator-min/max-microvolt output voltage. - -Optional properties: --------------------- -- ovp-threshold-percent : overvoltage protection (OVP) threshold of the - regulator in percent. Some regulators have an OVP - circuitry which shuts down the regulator when the - actual output voltage deviates beyond a certain - margin from the expected value for a given control - voltage. On larger voltage decreases this can occur - undesiredly since the output voltage does not adjust - immediately to changes in the control voltage. To - avoid this situation the vctrl driver breaks down - larger voltage decreases into multiple steps, where - each step is within the OVP threshold. -- min-slew-down-rate : Describes how slowly the regulator voltage will decay - down in the worst case (lightest expected load). - Specified in uV / us (like main regulator ramp rate). - This value is required when ovp-threshold-percent is - specified. - -Example: - - vctrl-reg { - compatible = "vctrl-regulator"; - regulator-name = "vctrl_reg"; - - ctrl-supply = <&ctrl_reg>; - - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <1500000>; - - ctrl-voltage-range = <200000 500000>; - - min-slew-down-rate = <225>; - ovp-threshold-percent = <16>; - }; diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml index 4b9fb74fb9e966..fd3423e6051bc8 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,sar2130p-adsp-pas - qcom,sm8350-adsp-pas - qcom,sm8350-cdsp-pas - qcom,sm8350-slpi-pas @@ -61,6 +62,7 @@ allOf: properties: compatible: enum: + - qcom,sar2130p-adsp-pas - qcom,sm8350-adsp-pas - qcom,sm8350-cdsp-pas - qcom,sm8350-slpi-pas @@ -101,6 +103,7 @@ allOf: properties: compatible: enum: + - qcom,sar2130p-adsp-pas - qcom,sm8350-adsp-pas - qcom,sm8350-slpi-pas - qcom,sm8450-adsp-pas diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml index d7fad7b3c2c687..a24cbb61bda7d7 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm8550-pas.yaml @@ -15,16 +15,20 @@ description: properties: compatible: - enum: - - qcom,sdx75-mpss-pas - - qcom,sm8550-adsp-pas - - qcom,sm8550-cdsp-pas - - qcom,sm8550-mpss-pas - - qcom,sm8650-adsp-pas - - qcom,sm8650-cdsp-pas - - qcom,sm8650-mpss-pas - - qcom,x1e80100-adsp-pas - - qcom,x1e80100-cdsp-pas + oneOf: + - enum: + - qcom,sdx75-mpss-pas + - qcom,sm8550-adsp-pas + - qcom,sm8550-cdsp-pas + - qcom,sm8550-mpss-pas + - qcom,sm8650-adsp-pas + - qcom,sm8650-cdsp-pas + - qcom,sm8650-mpss-pas + - qcom,x1e80100-adsp-pas + - qcom,x1e80100-cdsp-pas + - items: + - const: qcom,sm8750-adsp-pas + - const: qcom,sm8550-adsp-pas reg: maxItems: 1 @@ -82,6 +86,20 @@ allOf: maxItems: 5 memory-region: maxItems: 2 + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8750-adsp-pas + then: + properties: + interrupts: + maxItems: 6 + interrupt-names: + maxItems: 6 + memory-region: + maxItems: 2 - if: properties: compatible: @@ -129,10 +147,12 @@ allOf: - if: properties: compatible: - enum: - - qcom,sm8550-adsp-pas - - qcom,sm8650-adsp-pas - - qcom,x1e80100-adsp-pas + contains: + enum: + - qcom,sm8550-adsp-pas + - qcom,sm8650-adsp-pas + - qcom,sm8750-adsp-pas + - qcom,x1e80100-adsp-pas then: properties: power-domains: diff --git a/Documentation/devicetree/bindings/reset/nuvoton,npcm750-reset.yaml b/Documentation/devicetree/bindings/reset/nuvoton,npcm750-reset.yaml index d82e65e37cc0c9..72523f1bbc18a6 100644 --- a/Documentation/devicetree/bindings/reset/nuvoton,npcm750-reset.yaml +++ b/Documentation/devicetree/bindings/reset/nuvoton,npcm750-reset.yaml @@ -21,6 +21,13 @@ properties: '#reset-cells': const: 2 + '#clock-cells': + const: 1 + + clocks: + items: + - description: specify external 25MHz reference clock. + nuvoton,sysgcr: $ref: /schemas/types.yaml#/definitions/phandle description: a phandle to access GCR registers. @@ -39,6 +46,17 @@ required: - '#reset-cells' - nuvoton,sysgcr +if: + properties: + compatible: + contains: + enum: + - nuvoton,npcm845-reset +then: + required: + - '#clock-cells' + - clocks + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml index 2cf2026cff574d..9c7dd7e75e0ca3 100644 --- a/Documentation/devicetree/bindings/riscv/extensions.yaml +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml @@ -128,6 +128,18 @@ properties: changes to interrupts as frozen at commit ccbddab ("Merge pull request #42 from riscv/jhauser-2023-RC4") of riscv-aia. + - const: smmpm + description: | + The standard Smmpm extension for M-mode pointer masking as + ratified at commit d70011dde6c2 ("Update to ratified state") + of riscv-j-extension. + + - const: smnpm + description: | + The standard Smnpm extension for next-mode pointer masking as + ratified at commit d70011dde6c2 ("Update to ratified state") + of riscv-j-extension. + - const: smstateen description: | The standard Smstateen extension for controlling access to CSRs @@ -147,12 +159,46 @@ properties: and mode-based filtering as ratified at commit 01d1df0 ("Add ability to manually trigger workflow. (#2)") of riscv-count-overflow. + - const: ssnpm + description: | + The standard Ssnpm extension for next-mode pointer masking as + ratified at commit d70011dde6c2 ("Update to ratified state") + of riscv-j-extension. + - const: sstc description: | The standard Sstc supervisor-level extension for time compare as ratified at commit 3f9ed34 ("Add ability to manually trigger workflow. (#2)") of riscv-time-compare. + - const: svade + description: | + The standard Svade supervisor-level extension for SW-managed PTE A/D + bit updates as ratified in the 20240213 version of the privileged + ISA specification. + + Both Svade and Svadu extensions control the hardware behavior when + the PTE A/D bits need to be set. The default behavior for the four + possible combinations of these extensions in the device tree are: + 1) Neither Svade nor Svadu present in DT => It is technically + unknown whether the platform uses Svade or Svadu. Supervisor + software should be prepared to handle either hardware updating + of the PTE A/D bits or page faults when they need updated. + 2) Only Svade present in DT => Supervisor must assume Svade to be + always enabled. + 3) Only Svadu present in DT => Supervisor must assume Svadu to be + always enabled. + 4) Both Svade and Svadu present in DT => Supervisor must assume + Svadu turned-off at boot time. To use Svadu, supervisor must + explicitly enable it using the SBI FWFT extension. + + - const: svadu + description: | + The standard Svadu supervisor-level extension for hardware updating + of PTE A/D bits as ratified in the 20240528 version of the + privileged ISA specification. Please refer to Svade dt-binding + description for more details. + - const: svinval description: The standard Svinval supervisor-level extension for fine-grained @@ -178,6 +224,12 @@ properties: as ratified at commit 4a69197e5617 ("Update to ratified state") of riscv-svvptc. + - const: zabha + description: | + The Zabha extension for Byte and Halfword Atomic Memory Operations + as ratified at commit 49f49c842ff9 ("Update to Rafified state") of + riscv-zabha. + - const: zacas description: | The Zacas extension for Atomic Compare-and-Swap (CAS) instructions @@ -290,6 +342,12 @@ properties: in commit 64074bc ("Update version numbers for Zfh/Zfinx") of riscv-isa-manual. + - const: ziccrse + description: + The standard Ziccrse extension which provides forward progress + guarantee on LR/SC sequences, as ratified in commit b1d806605f87 + ("Updated to ratified state.") of the riscv profiles specification. + - const: zk description: The standard Zk Standard Scalar cryptography extension as ratified diff --git a/Documentation/devicetree/bindings/riscv/starfive.yaml b/Documentation/devicetree/bindings/riscv/starfive.yaml index 4d5c857b3cac93..7ef85174353de3 100644 --- a/Documentation/devicetree/bindings/riscv/starfive.yaml +++ b/Documentation/devicetree/bindings/riscv/starfive.yaml @@ -26,6 +26,7 @@ properties: - items: - enum: + - deepcomputing,fml13v01 - milkv,mars - pine64,star64 - starfive,visionfive-2-v1.2a diff --git a/Documentation/devicetree/bindings/rng/airoha,en7581-trng.yaml b/Documentation/devicetree/bindings/rng/airoha,en7581-trng.yaml new file mode 100644 index 00000000000000..dfc6d24ee7d98f --- /dev/null +++ b/Documentation/devicetree/bindings/rng/airoha,en7581-trng.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rng/airoha,en7581-trng.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha EN7851 True Random Number Generator + +maintainers: + - Christian Marangi + +properties: + compatible: + const: airoha,en7581-trng + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + rng@1faa1000 { + compatible = "airoha,en7581-trng"; + reg = <0x1faa1000 0x1000>; + interrupts = ; + }; diff --git a/Documentation/devicetree/bindings/rng/brcm,bcm74110-rng.yaml b/Documentation/devicetree/bindings/rng/brcm,bcm74110-rng.yaml new file mode 100644 index 00000000000000..8e89d4a70b5312 --- /dev/null +++ b/Documentation/devicetree/bindings/rng/brcm,bcm74110-rng.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rng/brcm,bcm74110-rng.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: BCM74110 Random number generator + +description: + Random number generator used on the BCM74110. + +maintainers: + - Markus Mayer + - Florian Fainelli + +properties: + compatible: + enum: + - brcm,bcm74110-rng + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + rng@83ba000 { + compatible = "brcm,bcm74110-rng"; + reg = <0x83ba000 0x14>; + }; diff --git a/Documentation/devicetree/bindings/rng/imx-rng.yaml b/Documentation/devicetree/bindings/rng/imx-rng.yaml index 07f6ff89bcc15e..252fa9a41abec4 100644 --- a/Documentation/devicetree/bindings/rng/imx-rng.yaml +++ b/Documentation/devicetree/bindings/rng/imx-rng.yaml @@ -14,8 +14,8 @@ properties: oneOf: - const: fsl,imx21-rnga - const: fsl,imx25-rngb + - const: fsl,imx31-rnga - items: - - const: fsl,imx31-rnga - const: fsl,imx21-rnga - items: - enum: diff --git a/Documentation/devicetree/bindings/rng/inside-secure,safexcel-eip76.yaml b/Documentation/devicetree/bindings/rng/inside-secure,safexcel-eip76.yaml new file mode 100644 index 00000000000000..0877eb44f9edc6 --- /dev/null +++ b/Documentation/devicetree/bindings/rng/inside-secure,safexcel-eip76.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rng/inside-secure,safexcel-eip76.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Inside-Secure HWRNG Module + +maintainers: + - Jayesh Choudhary + +properties: + compatible: + oneOf: + - enum: + - ti,omap2-rng + - ti,omap4-rng + - inside-secure,safexcel-eip76 + - items: + - enum: + - marvell,armada-8k-rng + - const: inside-secure,safexcel-eip76 + + ti,hwmods: + const: rng + deprecated: true + description: Name of the hwmod associated with the RNG module + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + items: + - description: EIP150 gateable clock + - description: Main gateable clock + + clock-names: + minItems: 1 + items: + - const: core + - const: reg + + +allOf: + - if: + properties: + compatible: + contains: + enum: + - ti,omap4-rng + - inside-secure,safexcel-eip76 + + then: + required: + - interrupts + + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + /* AM335x */ + rng: rng@48310000 { + compatible = "ti,omap4-rng"; + ti,hwmods = "rng"; + reg = <0x48310000 0x2000>; + interrupts = <111>; + }; + - | + /* SafeXcel IP-76 */ + trng: rng@f2760000 { + compatible = "inside-secure,safexcel-eip76"; + reg = <0xf2760000 0x7d>; + interrupts = <0 59 4>; + clocks = <&cpm_syscon0 1 25>; + }; + +... diff --git a/Documentation/devicetree/bindings/rng/omap_rng.yaml b/Documentation/devicetree/bindings/rng/omap_rng.yaml deleted file mode 100644 index c0ac4f68ea5489..00000000000000 --- a/Documentation/devicetree/bindings/rng/omap_rng.yaml +++ /dev/null @@ -1,81 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/rng/omap_rng.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: OMAP SoC and Inside-Secure HWRNG Module - -maintainers: - - Jayesh Choudhary - -properties: - compatible: - enum: - - ti,omap2-rng - - ti,omap4-rng - - inside-secure,safexcel-eip76 - - ti,hwmods: - const: rng - deprecated: true - description: Name of the hwmod associated with the RNG module - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - - clocks: - minItems: 1 - items: - - description: EIP150 gateable clock - - description: Main gateable clock - - clock-names: - minItems: 1 - items: - - const: core - - const: reg - - -allOf: - - if: - properties: - compatible: - contains: - enum: - - ti,omap4-rng - - inside-secure,safexcel-eip76 - - then: - required: - - interrupts - - -required: - - compatible - - reg - -additionalProperties: false - -examples: - - | - /* AM335x */ - rng: rng@48310000 { - compatible = "ti,omap4-rng"; - ti,hwmods = "rng"; - reg = <0x48310000 0x2000>; - interrupts = <111>; - }; - - | - /* SafeXcel IP-76 */ - trng: rng@f2760000 { - compatible = "inside-secure,safexcel-eip76"; - reg = <0xf2760000 0x7d>; - interrupts = <0 59 4>; - clocks = <&cpm_syscon0 1 25>; - }; - -... diff --git a/Documentation/devicetree/bindings/rng/st,stm32-rng.yaml b/Documentation/devicetree/bindings/rng/st,stm32-rng.yaml index 340d01d481d12c..7db65f49773b5b 100644 --- a/Documentation/devicetree/bindings/rng/st,stm32-rng.yaml +++ b/Documentation/devicetree/bindings/rng/st,stm32-rng.yaml @@ -18,12 +18,19 @@ properties: enum: - st,stm32-rng - st,stm32mp13-rng + - st,stm32mp25-rng reg: maxItems: 1 clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 + + clock-names: + items: + - const: core + - const: bus resets: maxItems: 1 @@ -57,6 +64,25 @@ allOf: properties: st,rng-lock-conf: false + - if: + properties: + compatible: + contains: + enum: + - st,stm32-rng + - st,stm32mp13-rng + then: + properties: + clocks: + maxItems: 1 + clock-names: false + else: + properties: + clocks: + minItems: 2 + required: + - clock-names + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml index 4531eec568a657..9df5cdb6f63f2b 100644 --- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml @@ -30,7 +30,9 @@ properties: - const: allwinner,sun50i-a64-rtc - const: allwinner,sun8i-h3-rtc - items: - - const: allwinner,sun20i-d1-rtc + - enum: + - allwinner,sun20i-d1-rtc + - allwinner,sun55i-a523-rtc - const: allwinner,sun50i-r329-rtc reg: diff --git a/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml b/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml new file mode 100644 index 00000000000000..5d3ac737abcbaf --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2024 Amlogic, Inc. All rights reserved +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/amlogic,a4-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic A4 and A5 RTC + +maintainers: + - Yiting Deng + - Xianwei Zhao + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + enum: + - amlogic,a4-rtc + - amlogic,a5-rtc + + reg: + maxItems: 1 + + clocks: + items: + - description: RTC clock source, available 24M or 32K crystal + oscillator source. when using 24M, need to divide 24M into 32K. + - description: RTC module accesses the clock of the apb bus. + + clock-names: + items: + - const: osc + - const: sys + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +additionalProperties: false + +examples: + - | + #include + apb { + #address-cells = <2>; + #size-cells = <2>; + + rtc@8e600 { + compatible = "amlogic,a4-rtc"; + reg = <0x0 0x8e600 0x0 0x38>; + clocks = <&xtal_32k>, <&clkc_periphs 1>; + clock-names = "osc", "sys"; + interrupts = ; + }; + }; diff --git a/Documentation/devicetree/bindings/rtc/microchip,mfps-rtc.yaml b/Documentation/devicetree/bindings/rtc/microchip,mfps-rtc.yaml deleted file mode 100644 index 7742465b938398..00000000000000 --- a/Documentation/devicetree/bindings/rtc/microchip,mfps-rtc.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/rtc/microchip,mfps-rtc.yaml# - -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Microchip PolarFire Soc (MPFS) RTC - -allOf: - - $ref: rtc.yaml# - -maintainers: - - Daire McNamara - - Lewis Hanly - -properties: - compatible: - enum: - - microchip,mpfs-rtc - - reg: - maxItems: 1 - - interrupts: - items: - - description: | - RTC_WAKEUP interrupt - - description: | - RTC_MATCH, asserted when the content of the Alarm register is equal - to that of the RTC's count register. - - clocks: - items: - - description: | - AHB clock - - description: | - Reference clock: divided by the prescaler to create a time-based - strobe (typically 1 Hz) for the calendar counter. By default, the rtc - on the PolarFire SoC shares it's reference with MTIMER so this will - be a 1 MHz clock. - - clock-names: - items: - - const: rtc - - const: rtcref - -required: - - compatible - - reg - - interrupts - - clocks - - clock-names - -additionalProperties: false - -examples: - - | - #include "dt-bindings/clock/microchip,mpfs-clock.h" - rtc@20124000 { - compatible = "microchip,mpfs-rtc"; - reg = <0x20124000 0x1000>; - clocks = <&clkcfg CLK_RTC>, <&clkcfg CLK_RTCREF>; - clock-names = "rtc", "rtcref"; - interrupts = <80>, <81>; - }; -... diff --git a/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml b/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml new file mode 100644 index 00000000000000..a3e60d9f83993c --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/microchip,mpfs-rtc.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/microchip,mpfs-rtc.yaml# + +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip PolarFire Soc (MPFS) RTC + +allOf: + - $ref: rtc.yaml# + +maintainers: + - Daire McNamara + +properties: + compatible: + oneOf: + - items: + - const: microchip,pic64gx-rtc + - const: microchip,mpfs-rtc + - const: microchip,mpfs-rtc + + reg: + maxItems: 1 + + interrupts: + items: + - description: | + RTC_WAKEUP interrupt + - description: | + RTC_MATCH, asserted when the content of the Alarm register is equal + to that of the RTC's count register. + + clocks: + items: + - description: | + AHB clock + - description: | + Reference clock: divided by the prescaler to create a time-based + strobe (typically 1 Hz) for the calendar counter. By default, the rtc + on the PolarFire SoC shares it's reference with MTIMER so this will + be a 1 MHz clock. + + clock-names: + items: + - const: rtc + - const: rtcref + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include "dt-bindings/clock/microchip,mpfs-clock.h" + rtc@20124000 { + compatible = "microchip,mpfs-rtc"; + reg = <0x20124000 0x1000>; + clocks = <&clkcfg CLK_RTC>, <&clkcfg CLK_RTCREF>; + clock-names = "rtc", "rtcref"; + interrupts = <80>, <81>; + }; +... diff --git a/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml b/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml new file mode 100644 index 00000000000000..e70eeb66aa648b --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/renesas,rz-rtca3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas RTCA-3 Real Time Clock + +maintainers: + - Claudiu Beznea + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + items: + - enum: + - renesas,r9a08g045-rtca3 # RZ/G3S + - const: renesas,rz-rtca3 + + reg: + maxItems: 1 + + interrupts: + items: + - description: Alarm interrupt + - description: Periodic interrupt + - description: Carry interrupt + + interrupt-names: + items: + - const: alarm + - const: period + - const: carry + + clocks: + items: + - description: RTC bus clock + - description: RTC counter clock + + clock-names: + items: + - const: bus + - const: counter + + power-domains: + maxItems: 1 + + resets: + items: + - description: VBATTB module reset + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - clock-names + - power-domains + - resets + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + rtc@1004ec00 { + compatible = "renesas,r9a08g045-rtca3", "renesas,rz-rtca3"; + reg = <0x1004ec00 0x400>; + interrupts = , + , + ; + interrupt-names = "alarm", "period", "carry"; + clocks = <&cpg CPG_MOD R9A08G045_VBAT_BCLK>, <&vbattclk VBATTB_VBATTCLK>; + clock-names = "bus", "counter"; + power-domains = <&cpg>; + resets = <&cpg R9A08G045_VBAT_BRESETN>; + }; diff --git a/Documentation/devicetree/bindings/rtc/rtc-mt6397.txt b/Documentation/devicetree/bindings/rtc/rtc-mt6397.txt deleted file mode 100644 index 7212076a8f1b0c..00000000000000 --- a/Documentation/devicetree/bindings/rtc/rtc-mt6397.txt +++ /dev/null @@ -1,31 +0,0 @@ -Device-Tree bindings for MediaTek PMIC based RTC - -MediaTek PMIC based RTC is an independent function of MediaTek PMIC that works -as a type of multi-function device (MFD). The RTC can be configured and set up -with PMIC wrapper bus which is a common resource shared with the other -functions found on the same PMIC. - -For MediaTek PMIC MFD bindings, see: -../mfd/mt6397.txt - -For MediaTek PMIC wrapper bus bindings, see: -../soc/mediatek/pwrap.txt - -Required properties: -- compatible: Should be one of follows - "mediatek,mt6323-rtc": for MT6323 PMIC - "mediatek,mt6358-rtc": for MT6358 PMIC - "mediatek,mt6366-rtc", "mediatek,mt6358-rtc": for MT6366 PMIC - "mediatek,mt6397-rtc": for MT6397 PMIC - -Example: - - pmic { - compatible = "mediatek,mt6323"; - - ... - - rtc { - compatible = "mediatek,mt6323-rtc"; - }; - }; diff --git a/Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml b/Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml index f3d20e976965a2..5756f617df367f 100644 --- a/Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/sprd,sc2731-rtc.yaml @@ -30,20 +30,4 @@ allOf: - $ref: rtc.yaml# unevaluatedProperties: false - -examples: - - | - #include - - pmic { - #address-cells = <1>; - #size-cells = <0>; - - rtc@280 { - compatible = "sprd,sc2731-rtc"; - reg = <0x280>; - interrupt-parent = <&sc2731_pmic>; - interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; - }; - }; ... diff --git a/Documentation/devicetree/bindings/serial/rs485.yaml b/Documentation/devicetree/bindings/serial/rs485.yaml index 9418fd66a8e95a..b93254ad2a287a 100644 --- a/Documentation/devicetree/bindings/serial/rs485.yaml +++ b/Documentation/devicetree/bindings/serial/rs485.yaml @@ -18,16 +18,15 @@ properties: description: prop-encoded-array $ref: /schemas/types.yaml#/definitions/uint32-array items: - items: - - description: Delay between rts signal and beginning of data sent in - milliseconds. It corresponds to the delay before sending data. - default: 0 - maximum: 100 - - description: Delay between end of data sent and rts signal in milliseconds. - It corresponds to the delay after sending data and actual release - of the line. - default: 0 - maximum: 100 + - description: Delay between rts signal and beginning of data sent in + milliseconds. It corresponds to the delay before sending data. + default: 0 + maximum: 100 + - description: Delay between end of data sent and rts signal in milliseconds. + It corresponds to the delay after sending data and actual release + of the line. + default: 0 + maximum: 100 rs485-rts-active-high: description: drive RTS high when sending (this is the default). diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index 788c80e47831cb..070eba9f19d3e0 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -27,6 +27,7 @@ properties: - samsung,exynos4210-uart - samsung,exynos5433-uart - samsung,exynos850-uart + - samsung,exynos8895-uart - items: - enum: - samsung,exynos7-uart @@ -160,18 +161,27 @@ allOf: contains: enum: - google,gs101-uart + - samsung,exynos8895-uart then: required: - samsung,uart-fifosize properties: - reg-io-width: false - clocks: maxItems: 2 clock-names: maxItems: 2 + - if: + properties: + compatible: + contains: + enum: + - google,gs101-uart + then: + properties: + reg-io-width: false + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index 4cdb0dcaccf388..1c163cb5dff105 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -37,6 +37,8 @@ properties: - const: renesas,rzn1-uart - items: - enum: + - brcm,bcm11351-dw-apb-uart + - brcm,bcm21664-dw-apb-uart - rockchip,px30-uart - rockchip,rk1808-uart - rockchip,rk3036-uart @@ -48,18 +50,13 @@ properties: - rockchip,rk3328-uart - rockchip,rk3368-uart - rockchip,rk3399-uart + - rockchip,rk3528-uart - rockchip,rk3568-uart + - rockchip,rk3576-uart - rockchip,rk3588-uart - rockchip,rv1108-uart - rockchip,rv1126-uart - - const: snps,dw-apb-uart - - items: - - enum: - - brcm,bcm11351-dw-apb-uart - - brcm,bcm21664-dw-apb-uart - - const: snps,dw-apb-uart - - items: - - enum: + - sophgo,sg2044-uart - starfive,jh7100-hsuart - starfive,jh7100-uart - starfive,jh7110-uart diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.yaml b/Documentation/devicetree/bindings/serial/sprd-uart.yaml index f4dbb6dc2b6ef2..a2a5056eba048e 100644 --- a/Documentation/devicetree/bindings/serial/sprd-uart.yaml +++ b/Documentation/devicetree/bindings/serial/sprd-uart.yaml @@ -17,6 +17,7 @@ properties: oneOf: - items: - enum: + - sprd,sc9632-uart - sprd,sc9860-uart - sprd,sc9863a-uart - sprd,ums512-uart diff --git a/Documentation/devicetree/bindings/soc/fsl/fsl,qman-portal.yaml b/Documentation/devicetree/bindings/soc/fsl/fsl,qman-portal.yaml index 17016184143f24..e459fec02ba832 100644 --- a/Documentation/devicetree/bindings/soc/fsl/fsl,qman-portal.yaml +++ b/Documentation/devicetree/bindings/soc/fsl/fsl,qman-portal.yaml @@ -35,6 +35,7 @@ properties: fsl,liodn: $ref: /schemas/types.yaml#/definitions/uint32-array + maxItems: 2 description: See pamu.txt. Two LIODN(s). DQRR LIODN (DLIODN) and Frame LIODN (FLIODN) @@ -69,6 +70,7 @@ patternProperties: type: object properties: fsl,liodn: + $ref: /schemas/types.yaml#/definitions/uint32-array description: See pamu.txt, PAMU property used for static LIODN assignment fsl,iommu-parent: diff --git a/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml b/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml index c4ae4f28422b20..f40c157908aa73 100644 --- a/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml +++ b/Documentation/devicetree/bindings/soc/imx/fsl,imx-anatop.yaml @@ -36,6 +36,7 @@ properties: - description: Temperature sensor event - description: Brown-out event on either of the support regulators - description: Brown-out event on either the core, gpu or soc regulators + minItems: 2 tempmon: type: object @@ -43,7 +44,7 @@ properties: $ref: /schemas/thermal/imx-thermal.yaml patternProperties: - "regulator-((1p1)|(2p5)|(3p0)|(vddcore)|(vddpu)|(vddsoc))$": + "regulator-((1p1)|(2p5)|(3p0)|(vdd1p0d)|(vdd1p2)|(vddcore)|(vddpcie)|(vddpu)|(vddsoc))$": type: object unevaluatedProperties: false $ref: /schemas/regulator/anatop-regulator.yaml @@ -52,6 +53,23 @@ required: - compatible - reg +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx7d-anatop + then: + properties: + interrupts: + maxItems: 2 + else: + properties: + interrupts: + minItems: 3 + maxItems: 3 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,mt8183-dvfsrc.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,mt8183-dvfsrc.yaml new file mode 100644 index 00000000000000..1ad5b61b249f2e --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,mt8183-dvfsrc.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/mediatek/mediatek,mt8183-dvfsrc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Dynamic Voltage and Frequency Scaling Resource Collector (DVFSRC) + +description: + The Dynamic Voltage and Frequency Scaling Resource Collector (DVFSRC) is a + Hardware module used to collect all the requests from both software and the + various remote processors embedded into the SoC and decide about a minimum + operating voltage and a minimum DRAM frequency to fulfill those requests in + an effort to provide the best achievable performance per watt. + This hardware IP is capable of transparently performing direct register R/W + on all of the DVFSRC-controlled regulators and SoC bandwidth knobs. + +maintainers: + - AngeloGioacchino Del Regno + - Henry Chen + +properties: + compatible: + oneOf: + - enum: + - mediatek,mt8183-dvfsrc + - mediatek,mt8195-dvfsrc + - items: + - const: mediatek,mt8192-dvfsrc + - const: mediatek,mt8195-dvfsrc + + reg: + maxItems: 1 + description: DVFSRC common register address and length. + + regulators: + type: object + $ref: /schemas/regulator/mediatek,mt6873-dvfsrc-regulator.yaml# + + interconnect: + type: object + $ref: /schemas/interconnect/mediatek,mt8183-emi.yaml# + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + system-controller@10012000 { + compatible = "mediatek,mt8195-dvfsrc"; + reg = <0 0x10012000 0 0x1000>; + + regulators { + compatible = "mediatek,mt8195-dvfsrc-regulator"; + + dvfsrc_vcore: dvfsrc-vcore { + regulator-name = "dvfsrc-vcore"; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <750000>; + regulator-always-on; + }; + + dvfsrc_vscp: dvfsrc-vscp { + regulator-name = "dvfsrc-vscp"; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <750000>; + regulator-always-on; + }; + }; + + emi_icc: interconnect { + compatible = "mediatek,mt8195-emi"; + #interconnect-cells = <1>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt index 2bc367793aec18..3530a6668b4868 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt +++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt @@ -20,6 +20,7 @@ Required properties: - compatible: Should be one of: - "mediatek,mt2701-scpsys" - "mediatek,mt2712-scpsys" + - "mediatek,mt6735-scpsys" - "mediatek,mt6765-scpsys" - "mediatek,mt6797-scpsys" - "mediatek,mt7622-scpsys" diff --git a/Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml b/Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml index a46411149571f1..2c7275c4503b54 100644 --- a/Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml +++ b/Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml @@ -15,13 +15,19 @@ description: | properties: compatible: - items: - - enum: - - atmel,at91rm9200-tcb - - atmel,at91sam9x5-tcb - - atmel,sama5d2-tcb - - const: simple-mfd - - const: syscon + oneOf: + - items: + - enum: + - atmel,at91rm9200-tcb + - atmel,at91sam9x5-tcb + - atmel,sama5d2-tcb + - const: simple-mfd + - const: syscon + - items: + - const: microchip,sam9x7-tcb + - const: atmel,sama5d2-tcb + - const: simple-mfd + - const: syscon reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml index f7e606d45ebcfc..6d11472ba5a704 100644 --- a/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml +++ b/Documentation/devicetree/bindings/soc/mobileye/mobileye,eyeq5-olb.yaml @@ -41,9 +41,7 @@ properties: enum: [ 1, 2 ] '#clock-cells': - description: - Cell is clock index. Optional if compatible has a single clock. - enum: [ 0, 1 ] + const: 1 clocks: maxItems: 1 @@ -312,26 +310,6 @@ allOf: properties: '#reset-cells': false - # Compatibles exposing a single clock. - - if: - properties: - compatible: - contains: - enum: - - mobileye,eyeq6h-central-olb - - mobileye,eyeq6h-east-olb - - mobileye,eyeq6h-west-olb - - mobileye,eyeq6h-ddr0-olb - - mobileye,eyeq6h-ddr1-olb - then: - properties: - '#clock-cells': - const: 0 - else: - properties: - '#clock-cells': - const: 1 - # Only EyeQ5 has pinctrl in OLB. - if: not: diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index 7afdb60edb22bb..e63f800c6caae7 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -25,8 +25,11 @@ properties: compatible: items: - enum: + - qcom,qcs8300-aoss-qmp - qcom,qdu1000-aoss-qmp + - qcom,sa8255p-aoss-qmp - qcom,sa8775p-aoss-qmp + - qcom,sar2130p-aoss-qmp - qcom,sc7180-aoss-qmp - qcom,sc7280-aoss-qmp - qcom,sc8180x-aoss-qmp @@ -40,6 +43,7 @@ properties: - qcom,sm8450-aoss-qmp - qcom,sm8550-aoss-qmp - qcom,sm8650-aoss-qmp + - qcom,sm8750-aoss-qmp - qcom,x1e80100-aoss-qmp - const: qcom,aoss-qmp diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml index 141d666dc3f7b5..1ba1d419e83bbb 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.yaml @@ -55,8 +55,7 @@ properties: qcom,smem: $ref: /schemas/types.yaml#/definitions/uint32-array - items: - maxItems: 2 + maxItems: 2 description: Two identifiers of the inbound and outbound smem items used for this edge. diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml index 50d727f4b76c62..7eca9e1ad6a36f 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml @@ -33,9 +33,11 @@ properties: - rockchip,rk3576-usb-grf - rockchip,rk3576-usbdpphy-grf - rockchip,rk3576-vo0-grf + - rockchip,rk3576-vo1-grf - rockchip,rk3576-vop-grf - rockchip,rk3588-bigcore0-grf - rockchip,rk3588-bigcore1-grf + - rockchip,rk3588-dcphy-grf - rockchip,rk3588-hdptxphy-grf - rockchip,rk3588-ioc - rockchip,rk3588-php-grf @@ -80,6 +82,7 @@ properties: - rockchip,rk3568-pmugrf - rockchip,rk3576-ioc-grf - rockchip,rk3576-pmu0-grf + - rockchip,rk3576-usb2phy-grf - rockchip,rk3588-usb2phy-grf - rockchip,rv1108-grf - rockchip,rv1108-pmugrf @@ -233,6 +236,7 @@ allOf: - rockchip,rk3308-usb2phy-grf - rockchip,rk3328-usb2phy-grf - rockchip,rk3399-grf + - rockchip,rk3576-usb2phy-grf - rockchip,rk3588-usb2phy-grf - rockchip,rv1108-grf @@ -283,6 +287,7 @@ allOf: compatible: contains: enum: + - rockchip,rk3576-vo1-grf - rockchip,rk3588-vo-grf - rockchip,rk3588-vo0-grf - rockchip,rk3588-vo1-grf diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml index 15fcd8f1d8bc7b..6cdfe7e059a355 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml @@ -53,6 +53,8 @@ properties: - items: - enum: - samsung,exynos7885-pmu + - samsung,exynos8895-pmu + - samsung,exynos9810-pmu - samsung,exynosautov9-pmu - samsung,exynosautov920-pmu - tesla,fsd-pmu diff --git a/Documentation/devicetree/bindings/sound/adi,adau1373.yaml b/Documentation/devicetree/bindings/sound/adi,adau1373.yaml new file mode 100644 index 00000000000000..97552bf5d95172 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,adau1373.yaml @@ -0,0 +1,111 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/adi,adau1373.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices ADAU1373 CODEC + +maintainers: + - Nuno Sá + +description: | + Analog Devices ADAU1373 Low power codec with speaker and headphone amplifiers. + https://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1373.pdf + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - adi,adau1373 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + powerdown-gpios: + description: GPIO used for hardware power-down. + maxItems: 1 + + adi,micbias1-microvolt: + description: + This property sets the microphone bias voltage for the first microphone. + enum: [1800000, 2200000, 2600000, 2900000] + default: 2900000 + + adi,micbias2-microvolt: + description: + This property sets the microphone bias voltage for the second microphone. + enum: [1800000, 2200000, 2600000, 2900000] + default: 2900000 + + adi,input1-differential: + description: This property sets the first analog input as differential. + type: boolean + + adi,input2-differential: + description: This property sets the second analog input as differential. + type: boolean + + adi,input3-differential: + description: This property sets the third analog input as differential. + type: boolean + + adi,input4-differential: + description: This property sets the fourth analog input as differential. + type: boolean + + adi,lineout-differential: + description: This property sets the line output as differential. + type: boolean + + adi,lineout-gnd-sense: + description: This property enables the line output ground sense control. + type: boolean + + adi,drc-settings: + description: + This setting is used to control the dynamic range of the signal. The + device provides a maximum of three full band DRCs with 13 entries each. + $ref: /schemas/types.yaml#/definitions/uint8-array + oneOf: + - minItems: 13 + maxItems: 13 + - minItems: 26 + maxItems: 26 + - minItems: 39 + maxItems: 39 + +required: + - "#sound-dai-cells" + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + audio-codec@1a { + compatible = "adi,adau1373"; + reg = <0x1a>; + #sound-dai-cells = <0>; + powerdown-gpios = <&gpio 100 GPIO_ACTIVE_LOW>; + adi,input2-differential; + adi,input1-differential; + adi,lineout-differential; + adi,micbias2-microvolt = <1800000>; + adi,drc-settings = /bits/ 8 < + 0xff 0xff 0x1 0x2 0xa 0xa 0xd 0x1 0xff 0xff 0x5 0xd 0xff + >; + }; + }; +... diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml index 78273647f76650..ebc9097f936ada 100644 --- a/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml +++ b/Documentation/devicetree/bindings/sound/allwinner,sun4i-a10-codec.yaml @@ -22,6 +22,7 @@ properties: - allwinner,sun8i-a23-codec - allwinner,sun8i-h3-codec - allwinner,sun8i-v3s-codec + - allwinner,sun50i-h616-codec reg: maxItems: 1 @@ -40,14 +41,20 @@ properties: - const: codec dmas: - items: - - description: RX DMA Channel - - description: TX DMA Channel + oneOf: + - items: + - description: RX DMA Channel + - description: TX DMA Channel + - items: + - description: TX DMA Channel dma-names: - items: - - const: rx - - const: tx + oneOf: + - items: + - const: rx + - const: tx + - items: + - const: tx resets: maxItems: 1 @@ -229,6 +236,40 @@ allOf: - Mic - Speaker + - if: + properties: + compatible: + enum: + - allwinner,sun50i-h616-codec + + then: + properties: + allwinner,audio-routing: + items: + enum: + - LINEOUT + - Line Out + + dmas: + items: + - description: TX DMA Channel + + dma-names: + items: + - const: tx + + else: + properties: + dmas: + items: + - description: RX DMA Channel + - description: TX DMA Channel + + dma-names: + items: + - const: rx + - const: tx + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/audio-graph.yaml b/Documentation/devicetree/bindings/sound/audio-graph.yaml index 71f52f7e55f6ce..9899d9d1958d9d 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph.yaml @@ -37,8 +37,14 @@ properties: pa-gpios: maxItems: 1 hp-det-gpio: + deprecated: true + maxItems: 1 + hp-det-gpios: maxItems: 1 mic-det-gpio: + deprecated: true + maxItems: 1 + mic-det-gpios: maxItems: 1 required: diff --git a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml index ac5f2e0f42cbd5..3b0b743e49c4c8 100644 --- a/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml +++ b/Documentation/devicetree/bindings/sound/awinic,aw88395.yaml @@ -17,8 +17,9 @@ description: properties: compatible: enum: - - awinic,aw88395 + - awinic,aw88081 - awinic,aw88261 + - awinic,aw88395 - awinic,aw88399 reg: @@ -56,6 +57,7 @@ allOf: compatible: contains: enum: + - awinic,aw88081 - awinic,aw88261 then: properties: diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml new file mode 100644 index 00000000000000..7f8338e8ae369b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/cirrus,cs42l84.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cirrus Logic CS42L84 audio CODEC + +maintainers: + - Martin Povišer + +description: | + The CS42L84 is a headphone jack codec made by Cirrus Logic and embedded + in personal computers sold by Apple. It was first seen in 2021 Macbook + Pro models. It has stereo DAC for playback, mono ADC for capture, and + is somewhat similar to CS42L42 but with a different regmap. + +properties: + compatible: + enum: + - cirrus,cs42l84 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + interrupts: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + jack_codec: codec@4b { + compatible = "cirrus,cs42l84"; + reg = <0x4b>; + reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_LOW>; + interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>; + #sound-dai-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml index 214f135b7777f3..e4b2eb5fae2fc2 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8316.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml @@ -4,12 +4,13 @@ $id: http://devicetree.org/schemas/sound/everest,es8316.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Everest ES8311 and ES8316 audio CODECs +title: Everest ES8311, ES8316 and ES8323 audio CODECs maintainers: - Daniel Drake - Katsuhiro Suzuki - Matteo Martelli + - Binbin Zhou allOf: - $ref: dai-common.yaml# @@ -19,6 +20,7 @@ properties: enum: - everest,es8311 - everest,es8316 + - everest,es8323 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/everest,es8326.yaml b/Documentation/devicetree/bindings/sound/everest,es8326.yaml index d51431df7acf9c..b5594a9d508e87 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8326.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8326.yaml @@ -24,6 +24,10 @@ properties: items: - const: mclk + interrupts: + maxItems: 1 + description: interrupt output for headset detection + "#sound-dai-cells": const: 0 diff --git a/Documentation/devicetree/bindings/sound/everest,es8328.yaml b/Documentation/devicetree/bindings/sound/everest,es8328.yaml index a0f4670fa38c84..ed18e40dcaacf7 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8328.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8328.yaml @@ -50,6 +50,10 @@ properties: HPVDD-supply: description: Regulator providing analog output voltage 3.3V + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - clocks diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.yaml b/Documentation/devicetree/bindings/sound/fsl,esai.yaml index f99ed20fa684a2..27c34ce4c2e22a 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,esai.yaml @@ -18,11 +18,15 @@ description: properties: compatible: - enum: - - fsl,imx35-esai - - fsl,imx6ull-esai - - fsl,imx8qm-esai - - fsl,vf610-esai + oneOf: + - enum: + - fsl,imx35-esai + - fsl,imx6ull-esai + - fsl,vf610-esai + - items: + - enum: + - fsl,imx8qm-esai + - const: fsl,imx6ull-esai reg: maxItems: 1 @@ -65,6 +69,9 @@ properties: - const: rx - const: tx + power-domains: + maxItems: 1 + fsl,fifo-depth: $ref: /schemas/types.yaml#/definitions/uint32 default: 64 @@ -101,6 +108,17 @@ unevaluatedProperties: false allOf: - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + const: fsl,imx8qm-esai + then: + required: + - power-domains + else: + properties: + power-domains: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.yaml b/Documentation/devicetree/bindings/sound/fsl,spdif.yaml index 204f361cea27ab..5654e9f61abaec 100644 --- a/Documentation/devicetree/bindings/sound/fsl,spdif.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.yaml @@ -16,16 +16,23 @@ description: | properties: compatible: - enum: - - fsl,imx35-spdif - - fsl,vf610-spdif - - fsl,imx6sx-spdif - - fsl,imx8qm-spdif - - fsl,imx8qxp-spdif - - fsl,imx8mq-spdif - - fsl,imx8mm-spdif - - fsl,imx8mn-spdif - - fsl,imx8ulp-spdif + oneOf: + - items: + - enum: + - fsl,imx35-spdif + - fsl,imx6sx-spdif + - fsl,imx8mm-spdif + - fsl,imx8mn-spdif + - fsl,imx8mq-spdif + - fsl,imx8qm-spdif + - fsl,imx8qxp-spdif + - fsl,imx8ulp-spdif + - fsl,vf610-spdif + - items: + - enum: + - fsl,imx6sl-spdif + - fsl,imx6sx-spdif + - const: fsl,imx35-spdif reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/inno-rk3036.txt b/Documentation/devicetree/bindings/sound/inno-rk3036.txt deleted file mode 100644 index 758de8e27561f2..00000000000000 --- a/Documentation/devicetree/bindings/sound/inno-rk3036.txt +++ /dev/null @@ -1,20 +0,0 @@ -Inno audio codec for RK3036 - -Inno audio codec is integrated inside RK3036 SoC. - -Required properties: -- compatible : Should be "rockchip,rk3036-codec". -- reg : The registers of codec. -- clock-names : Should be "acodec_pclk". -- clocks : The clock of codec. -- rockchip,grf : The phandle of grf device node. - -Example: - - acodec: acodec-ana@20030000 { - compatible = "rk3036-codec"; - reg = <0x20030000 0x4000>; - rockchip,grf = <&grf>; - clock-names = "acodec_pclk"; - clocks = <&cru ACLK_VCODEC>; - }; diff --git a/Documentation/devicetree/bindings/sound/irondevice,sma1307.yaml b/Documentation/devicetree/bindings/sound/irondevice,sma1307.yaml new file mode 100644 index 00000000000000..1e2a038d004890 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/irondevice,sma1307.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/irondevice,sma1307.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Iron Device SMA1307 Audio Amplifier + +maintainers: + - Kiseok Jo + +description: + SMA1307 boosted digital speaker amplifier with feedback-loop. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - irondevice,sma1307a + - irondevice,sma1307aq + description: + If a 'q' is added, it indicated the product is AEC-Q100 + qualified for automotive applications. SMA1307A supports + both WLCSP and QFN packages. However, SMA1307AQ only + supports the QFN package. + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 1 + +required: + - compatible + - reg + - '#sound-dai-cells' + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + amplifier@1e { + compatible = "irondevice,sma1307a"; + reg = <0x1e>; + #sound-dai-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml new file mode 100644 index 00000000000000..da79510bb2d91b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/loongson,ls2k1000-i2s.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson-2K1000 I2S controller + +maintainers: + - Binbin Zhou + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: loongson,ls2k1000-i2s + + reg: + items: + - description: Loongson I2S controller Registers. + - description: APB DMA config register for Loongson I2S controller. + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + dmas: + maxItems: 2 + + dma-names: + items: + - const: tx + - const: rx + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + - interrupts + - clocks + - dmas + - dma-names + - '#sound-dai-cells' + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2s@1fe2d000 { + compatible = "loongson,ls2k1000-i2s"; + reg = <0x1fe2d000 0x14>, + <0x1fe00438 0x8>; + interrupt-parent = <&liointc0>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + dmas = <&apbdma2 0>, <&apbdma3 0>; + dma-names = "tx", "rx"; + #sound-dai-cells = <0>; + }; +... diff --git a/Documentation/devicetree/bindings/sound/maxim,max98390.yaml b/Documentation/devicetree/bindings/sound/maxim,max98390.yaml index deaa6886c42fcf..d35dd8408c61cd 100644 --- a/Documentation/devicetree/bindings/sound/maxim,max98390.yaml +++ b/Documentation/devicetree/bindings/sound/maxim,max98390.yaml @@ -9,6 +9,9 @@ title: Maxim Integrated MAX98390 Speaker Amplifier with Integrated Dynamic Speak maintainers: - Steve Lee +allOf: + - $ref: dai-common.yaml# + properties: compatible: const: maxim,max98390 @@ -32,11 +35,14 @@ properties: reset-gpios: maxItems: 1 + '#sound-dai-cells': + const: 0 + required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml index f94ad0715e3239..ba482747f0e664 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml @@ -29,6 +29,13 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: The phandle of MT8188 ASoC platform. + mediatek,adsp: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The phandle of the MT8188 ADSP platform, which is the optional Audio DSP + hardware that provides additional audio functionalities if present. + The AFE will link to ADSP when the phandle is provided. + patternProperties: "^dai-link-[0-9]+$": type: object diff --git a/Documentation/devicetree/bindings/sound/mt6359.yaml b/Documentation/devicetree/bindings/sound/mt6359.yaml index 23d411fc4200e6..128698630c865f 100644 --- a/Documentation/devicetree/bindings/sound/mt6359.yaml +++ b/Documentation/devicetree/bindings/sound/mt6359.yaml @@ -23,8 +23,8 @@ properties: Indicates how many data pins are used to transmit two channels of PDM signal. 0 means two wires, 1 means one wire. Default value is 0. enum: - - 0 # one wire - - 1 # two wires + - 0 # two wires + - 1 # one wire mediatek,mic-type-0: $ref: /schemas/types.yaml#/definitions/uint32 @@ -53,9 +53,9 @@ additionalProperties: false examples: - | - mt6359codec: mt6359codec { - mediatek,dmic-mode = <0>; - mediatek,mic-type-0 = <2>; + mt6359codec: audio-codec { + mediatek,dmic-mode = <0>; + mediatek,mic-type-0 = <2>; }; ... diff --git a/Documentation/devicetree/bindings/sound/neofidelity,ntp8835.yaml b/Documentation/devicetree/bindings/sound/neofidelity,ntp8835.yaml new file mode 100644 index 00000000000000..44d72a2ddfc9ab --- /dev/null +++ b/Documentation/devicetree/bindings/sound/neofidelity,ntp8835.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/neofidelity,ntp8835.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NeoFidelity NTP8835/NTP8835C Amplifiers + +maintainers: + - Igor Prusov + +description: | + The NTP8835 is a single chip full digital audio amplifier + including power stages for stereo amplifier systems. + NTP8835 is integrated with versatile digital audio signal + processing functions, high-performance, high-fidelity fully + digital PWM modulator and two high-power full-bridge MOSFET + power stages. NTP8835C has identical programming interface, + but has different output signal characteristics. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - neofidelity,ntp8835 + - neofidelity,ntp8835c + + reg: + enum: + - 0x2a + - 0x2b + - 0x2c + - 0x2d + + reset-gpios: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + clocks: + maxItems: 4 + + clock-names: + items: + - const: wck + - const: bck + - const: scl + - const: mclk + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + audio-codec@2b { + compatible = "neofidelity,ntp8835"; + #sound-dai-cells = <0>; + reg = <0x2b>; + reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + clocks = <&clkc 551>, <&clkc 552>, <&clkc 553>, <&clkc 554>; + clock-names = "wck", "bck", "scl", "mclk"; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml b/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml new file mode 100644 index 00000000000000..952768b3590286 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/neofidelity,ntp8918.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NeoFidelity NTP8918 Amplifier + +maintainers: + - Igor Prusov + +description: + The NTP8918 is a single chip full digital audio amplifier + including power stage for stereo amplifier system. + The NTP8918 is integrated with versatile digital audio signal + processing functions, high-performance, high-fidelity fully + digital PWM modulator and two high-power full-bridge MOSFET + power stages. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - neofidelity,ntp8918 + + reg: + enum: + - 0x2a + - 0x2b + - 0x2c + - 0x2d + + reset-gpios: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + + clocks: + maxItems: 3 + + clock-names: + items: + - const: wck + - const: scl + - const: bck + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + audio-codec@2a { + compatible = "neofidelity,ntp8918"; + #sound-dai-cells = <0>; + reg = <0x2a>; + clocks = <&clkc 150>, <&clkc 151>, <&clkc 152>; + clock-names = "wck", "scl", "bck"; + reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/nxp,uda1342.yaml b/Documentation/devicetree/bindings/sound/nxp,uda1342.yaml new file mode 100644 index 00000000000000..71c6a5a2f5bc06 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nxp,uda1342.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/nxp,uda1342.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP uda1342 audio CODECs + +maintainers: + - Binbin Zhou + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: nxp,uda1342 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 0 + +required: + - compatible + - reg + - '#sound-dai-cells' + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + codec@1a { + compatible = "nxp,uda1342"; + reg = <0x1a>; + #sound-dai-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml index b8540b30741e32..92f95eb74b1928 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml @@ -21,6 +21,7 @@ properties: - items: - enum: - qcom,sm8650-lpass-rx-macro + - qcom,sm8750-lpass-rx-macro - qcom,x1e80100-lpass-rx-macro - const: qcom,sm8550-lpass-rx-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml index 3e2ae16c6aba63..914798a898781d 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml @@ -22,6 +22,7 @@ properties: - items: - enum: - qcom,sm8650-lpass-tx-macro + - qcom,sm8750-lpass-tx-macro - qcom,x1e80100-lpass-tx-macro - const: qcom,sm8550-lpass-tx-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml index 6b483fa3c428e6..f41deaa6f4df57 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml @@ -21,6 +21,7 @@ properties: - items: - enum: - qcom,sm8650-lpass-va-macro + - qcom,sm8750-lpass-va-macro - qcom,x1e80100-lpass-va-macro - const: qcom,sm8550-lpass-va-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml index 6f5644a89febbd..9082e363c70943 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml @@ -21,6 +21,7 @@ properties: - items: - enum: - qcom,sm8650-lpass-wsa-macro + - qcom,sm8750-lpass-wsa-macro - qcom,x1e80100-lpass-wsa-macro - const: qcom,sm8550-lpass-wsa-macro diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 2e2e01493a5f4f..b9e33a7429b0c0 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -25,6 +25,7 @@ properties: - enum: - qcom,sm8550-sndcard - qcom,sm8650-sndcard + - qcom,sm8750-sndcard - const: qcom,sm8450-sndcard - enum: - qcom,apq8096-sndcard diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml new file mode 100644 index 00000000000000..3f4f59287c1cca --- /dev/null +++ b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/realtek,rt5640.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RT5640/RT5639 audio CODEC + +maintainers: + - Neil Armstrong + +description: | + This device supports I2C only. + + Pins on the device (for linking into audio routes) for RT5639/RT5640: + * DMIC1 + * DMIC2 + * MICBIAS1 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * HPOL + * HPOR + * LOUTL + * LOUTR + * SPOLP + * SPOLN + * SPORP + * SPORN + + Additional pins on the device for RT5640: + * MONOP + * MONON + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - realtek,rt5640 + - realtek,rt5639 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: The CODEC's interrupt output. + + realtek,in1-differential: + description: + Indicate MIC1 input is differential, rather than single-ended. + type: boolean + + realtek,in2-differential: + description: + Indicate MIC2 input is differential, rather than single-ended. + type: boolean + + realtek,in3-differential: + description: + Indicate MIC3 input is differential, rather than single-ended. + type: boolean + + realtek,lout-differential: + description: + Indicate LOUT output is differential, rather than single-ended. + type: boolean + + realtek,dmic1-data-pin: + description: Specify which pin to be used as DMIC1 data pin. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic1 is not used + - 1 # using IN2P pin as dmic1 data pin + - 2 # using GPIO3 pin as dmic1 data pin + + realtek,dmic2-data-pin: + description: Specify which pin to be used as DMIC2 data pin. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # dmic2 is not used + - 1 # using IN2N pin as dmic2 data pin + - 2 # using GPIO4 pin as dmic2 data pin + + realtek,jack-detect-source: + description: The Jack Detect source. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # Jack Detect function is not used + - 1 # Use GPIO1 for jack-detect + - 2 # Use JD1_IN4P for jack-detect + - 3 # Use JD2_IN4N for jack-detect + - 4 # Use GPIO2 for jack-detect + - 5 # Use GPIO3 for jack-detect + - 6 # Use GPIO4 for jack-detect + + realtek,jack-detect-not-inverted: + description: + Normal jack-detect switches give an inverted signal, set this bool + in the rare case you've a jack-detect switch which is not inverted. + type: boolean + + realtek,over-current-threshold-microamp: + description: micbias over-current detection threshold in µA + enum: + - 600 + - 1500 + - 2000 + + realtek,over-current-scale-factor: + description: micbias over-current detection scale-factor + $ref: /schemas/types.yaml#/definitions/uint32 + enum: + - 0 # Scale current by 0.5 + - 1 # Scale current by 0.75 + - 2 # Scale current by 1.0 + - 3 # Scale current by 1.5 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + codec@1a { + compatible = "realtek,rt5640"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index dfd768b1ad7d2d..3f07b072d9955f 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -109,7 +109,7 @@ For more detail information, see below - Register Description - CTUn Scale Value exx Register (CTUn_SVxxR) - ${LINUX}/sound/soc/sh/rcar/ctu.c + ${LINUX}/sound/soc/renesas/rcar/ctu.c - comment of header You need to use "simple-scu-audio-card" or "audio-graph-scu-card" for it. diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3036-codec.yaml b/Documentation/devicetree/bindings/sound/rockchip,rk3036-codec.yaml new file mode 100644 index 00000000000000..7570cc1375caa8 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip,rk3036-codec.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/rockchip,rk3036-codec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip RK3036 internal codec + +maintainers: + - Heiko Stuebner + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + const: rockchip,rk3036-codec + + reg: + maxItems: 1 + + clocks: + items: + - description: clock for audio codec + + clock-names: + items: + - const: acodec_pclk + + rockchip,grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The phandle of the syscon node for the GRF register. + + "#sound-dai-cells": + const: 0 + +required: + - compatible + - reg + - clocks + - clock-names + - rockchip,grf + - "#sound-dai-cells" + +unevaluatedProperties: false + +examples: + - | + #include + acodec: audio-codec@20030000 { + compatible = "rockchip,rk3036-codec"; + reg = <0x20030000 0x4000>; + rockchip,grf = <&grf>; + clock-names = "acodec_pclk"; + clocks = <&cru ACLK_VCODEC>; + #sound-dai-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt deleted file mode 100644 index 0c398581d52b0b..00000000000000 --- a/Documentation/devicetree/bindings/sound/rt5640.txt +++ /dev/null @@ -1,97 +0,0 @@ -RT5640/RT5639 audio CODEC - -This device supports I2C only. - -Required properties: - -- compatible : One of "realtek,rt5640" or "realtek,rt5639". - -- reg : The I2C address of the device. - -- interrupts : The CODEC's interrupt output. - -Optional properties: - -- clocks: The phandle of the master clock to the CODEC -- clock-names: Should be "mclk" - -- realtek,in1-differential -- realtek,in2-differential -- realtek,in3-differential - Boolean. Indicate MIC1/2/3 input are differential, rather than single-ended. - -- realtek,lout-differential - Boolean. Indicate LOUT output is differential, rather than stereo. - -- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. - -- realtek,dmic1-data-pin - 0: dmic1 is not used - 1: using IN1P pin as dmic1 data pin - 2: using GPIO3 pin as dmic1 data pin - -- realtek,dmic2-data-pin - 0: dmic2 is not used - 1: using IN1N pin as dmic2 data pin - 2: using GPIO4 pin as dmic2 data pin - -- realtek,jack-detect-source - u32. Valid values: - 0: jack-detect is not used - 1: Use GPIO1 for jack-detect - 2: Use JD1_IN4P for jack-detect - 3: Use JD2_IN4N for jack-detect - 4: Use GPIO2 for jack-detect - 5: Use GPIO3 for jack-detect - 6: Use GPIO4 for jack-detect - -- realtek,jack-detect-not-inverted - bool. Normal jack-detect switches give an inverted signal, set this bool - in the rare case you've a jack-detect switch which is not inverted. - -- realtek,over-current-threshold-microamp - u32, micbias over-current detection threshold in µA, valid values are - 600, 1500 and 2000µA. - -- realtek,over-current-scale-factor - u32, micbias over-current detection scale-factor, valid values are: - 0: Scale current by 0.5 - 1: Scale current by 0.75 - 2: Scale current by 1.0 - 3: Scale current by 1.5 - -Pins on the device (for linking into audio routes) for RT5639/RT5640: - - * DMIC1 - * DMIC2 - * MICBIAS1 - * IN1P - * IN1N - * IN2P - * IN2N - * IN3P - * IN3N - * HPOL - * HPOR - * LOUTL - * LOUTR - * SPOLP - * SPOLN - * SPORP - * SPORN - -Additional pins on the device for RT5640: - - * MONOP - * MONON - -Example: - -rt5640 { - compatible = "realtek,rt5640"; - reg = <0x1c>; - interrupt-parent = <&gpio>; - interrupts = ; - realtek,ldo1-en-gpios = - <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; -}; diff --git a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml index 194ac1d4f4f5f4..9b1bda4852e160 100644 --- a/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml +++ b/Documentation/devicetree/bindings/sound/simple-audio-mux.yaml @@ -29,6 +29,10 @@ properties: $ref: /schemas/types.yaml#/definitions/string-array maxItems: 2 + idle-state: + description: If present specifies the state when the mux is powered down + $ref: /schemas/mux/mux-controller.yaml#/properties/idle-state + sound-name-prefix: true required: @@ -43,4 +47,5 @@ examples: compatible = "simple-audio-mux"; mux-gpios = <&gpio 3 0>; state-labels = "Label_A", "Label_B"; + idle-state = <0>; }; diff --git a/Documentation/devicetree/bindings/sound/simple-card.yaml b/Documentation/devicetree/bindings/sound/simple-card.yaml index 59ac2d1d1ccfa4..533d0a1da56e34 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.yaml +++ b/Documentation/devicetree/bindings/sound/simple-card.yaml @@ -207,8 +207,14 @@ properties: simple-audio-card,pin-switches: $ref: "#/definitions/pin-switches" simple-audio-card,hp-det-gpio: + deprecated: true + maxItems: 1 + simple-audio-card,hp-det-gpios: maxItems: 1 simple-audio-card,mic-det-gpio: + deprecated: true + maxItems: 1 + simple-audio-card,mic-det-gpios: maxItems: 1 patternProperties: @@ -256,8 +262,14 @@ patternProperties: pin-switches: $ref: "#/definitions/pin-switches" hp-det-gpio: + deprecated: true + maxItems: 1 + hp-det-gpios: maxItems: 1 mic-det-gpio: + deprecated: true + maxItems: 1 + mic-det-gpios: maxItems: 1 patternProperties: diff --git a/Documentation/devicetree/bindings/sound/sprd,pcm-platform.yaml b/Documentation/devicetree/bindings/sound/sprd,pcm-platform.yaml new file mode 100644 index 00000000000000..c15c01bbb884af --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sprd,pcm-platform.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/sprd,pcm-platform.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum DMA platform + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + compatible: + const: sprd,pcm-platform + + dmas: + maxItems: 10 + + dma-names: + items: + - const: normal_p_l + - const: normal_p_r + - const: normal_c_l + - const: normal_c_r + - const: voice_c + - const: fast_p + - const: loop_c + - const: loop_p + - const: voip_c + - const: voip_p + +required: + - compatible + - dmas + - dma-names + +additionalProperties: false + +examples: + - | + platform { + compatible = "sprd,pcm-platform"; + dmas = <&agcp_dma 1 1>, <&agcp_dma 2 2>, + <&agcp_dma 3 3>, <&agcp_dma 4 4>, + <&agcp_dma 5 5>, <&agcp_dma 6 6>, + <&agcp_dma 7 7>, <&agcp_dma 8 8>, + <&agcp_dma 9 9>, <&agcp_dma 10 10>; + dma-names = "normal_p_l", "normal_p_r", + "normal_c_l", "normal_c_r", + "voice_c", "fast_p", + "loop_c", "loop_p", + "voip_c", "voip_p"; + }; +... diff --git a/Documentation/devicetree/bindings/sound/sprd,sc9860-mcdt.yaml b/Documentation/devicetree/bindings/sound/sprd,sc9860-mcdt.yaml new file mode 100644 index 00000000000000..3b66bedeff9731 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sprd,sc9860-mcdt.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/sprd,sc9860-mcdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum Multi-Channel Data Transfer controller + +description: + The Multi-channel data transfer controller is used for sound stream + transmission between the audio subsystem and other AP/CP subsystem. It + supports 10 DAC channels and 10 ADC channels, and each channel can be + configured with DMA mode or interrupt mode. + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + compatible: + const: sprd,sc9860-mcdt + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + mcdt@41490000 { + compatible = "sprd,sc9860-mcdt"; + reg = <0x41490000 0x170>; + interrupts = ; + }; +... diff --git a/Documentation/devicetree/bindings/sound/sprd-mcdt.txt b/Documentation/devicetree/bindings/sound/sprd-mcdt.txt deleted file mode 100644 index 274ba0acbfd642..00000000000000 --- a/Documentation/devicetree/bindings/sound/sprd-mcdt.txt +++ /dev/null @@ -1,19 +0,0 @@ -Spreadtrum Multi-Channel Data Transfer Binding - -The Multi-channel data transfer controller is used for sound stream -transmission between audio subsystem and other AP/CP subsystem. It -supports 10 DAC channel and 10 ADC channel, and each channel can be -configured with DMA mode or interrupt mode. - -Required properties: -- compatible: Should be "sprd,sc9860-mcdt". -- reg: Should contain registers address and length. -- interrupts: Should contain one interrupt shared by all channel. - -Example: - -mcdt@41490000 { - compatible = "sprd,sc9860-mcdt"; - reg = <0 0x41490000 0 0x170>; - interrupts = ; -}; diff --git a/Documentation/devicetree/bindings/sound/sprd-pcm.txt b/Documentation/devicetree/bindings/sound/sprd-pcm.txt deleted file mode 100644 index fbbcade2181d80..00000000000000 --- a/Documentation/devicetree/bindings/sound/sprd-pcm.txt +++ /dev/null @@ -1,23 +0,0 @@ -* Spreadtrum DMA platform bindings - -Required properties: -- compatible: Should be "sprd,pcm-platform". -- dmas: Specify the list of DMA controller phandle and DMA request line ordered pairs. -- dma-names: Identifier string for each DMA request line in the dmas property. - These strings correspond 1:1 with the ordered pairs in dmas. - -Example: - - audio_platform:platform@0 { - compatible = "sprd,pcm-platform"; - dmas = <&agcp_dma 1 1>, <&agcp_dma 2 2>, - <&agcp_dma 3 3>, <&agcp_dma 4 4>, - <&agcp_dma 5 5>, <&agcp_dma 6 6>, - <&agcp_dma 7 7>, <&agcp_dma 8 8>, - <&agcp_dma 9 9>, <&agcp_dma 10 10>; - dma-names = "normal_p_l", "normal_p_r", - "normal_c_l", "normal_c_r", - "voice_c", "fast_p", - "loop_c", "loop_p", - "voip_c", "voip_p"; - }; diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml index 8978f6bd63e59e..b4f44f9c7c7d0f 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml @@ -13,13 +13,11 @@ description: The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. Only some SPI instances support I2S. -allOf: - - $ref: dai-common.yaml# - properties: compatible: enum: - st,stm32h7-i2s + - st,stm32mp25-i2s "#sound-dai-cells": const: 0 @@ -33,6 +31,7 @@ properties: - description: clock feeding the internal clock generator. - description: I2S parent clock for sampling rates multiple of 8kHz. - description: I2S parent clock for sampling rates multiple of 11.025kHz. + minItems: 2 clock-names: items: @@ -40,6 +39,7 @@ properties: - const: i2sclk - const: x8k - const: x11k + minItems: 2 interrupts: maxItems: 1 @@ -79,6 +79,36 @@ required: - dmas - dma-names +allOf: + - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + const: st,stm32h7-i2s + + then: + properties: + clocks: + minItems: 4 + + clock-names: + minItems: 4 + + - if: + properties: + compatible: + contains: + const: st,stm32mp25-i2s + + then: + properties: + clocks: + maxItems: 2 + + clock-names: + maxItems: 2 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml index 68f97b462598bc..4a7129d0b15747 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml @@ -20,6 +20,7 @@ properties: enum: - st,stm32f4-sai - st,stm32h7-sai + - st,stm32mp25-sai reg: items: @@ -43,9 +44,11 @@ properties: const: 1 clocks: + minItems: 1 maxItems: 3 clock-names: + minItems: 1 maxItems: 3 access-controllers: @@ -156,7 +159,13 @@ allOf: items: - const: x8k - const: x11k - else: + + - if: + properties: + compatible: + contains: + const: st,stm32mph7-sai + then: properties: clocks: items: @@ -170,6 +179,21 @@ allOf: - const: x8k - const: x11k + - if: + properties: + compatible: + contains: + const: st,stm32mp25-sai + then: + properties: + clocks: + items: + - description: pclk feeds the peripheral bus interface. + + clock-names: + items: + - const: pclk + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml index 3dedc81ec12f67..56c5738ea4c532 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-spdifrx.yaml @@ -50,6 +50,10 @@ properties: resets: maxItems: 1 + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + access-controllers: minItems: 1 maxItems: 2 diff --git a/Documentation/devicetree/bindings/spi/apple,spi.yaml b/Documentation/devicetree/bindings/spi/apple,spi.yaml new file mode 100644 index 00000000000000..7bef605a296353 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/apple,spi.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/apple,spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple ARM SoC SPI controller + +allOf: + - $ref: spi-controller.yaml# + +maintainers: + - Hector Martin + +properties: + compatible: + items: + - enum: + - apple,t8103-spi + - apple,t8112-spi + - apple,t6000-spi + - const: apple,spi + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + spi@39b104000 { + compatible = "apple,t6000-spi", "apple,spi"; + reg = <0x3 0x9b104000 0x0 0x4000>; + interrupt-parent = <&aic>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk>; + }; + }; diff --git a/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.txt b/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.txt deleted file mode 100644 index d7668f41b03bc7..00000000000000 --- a/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.txt +++ /dev/null @@ -1,38 +0,0 @@ -Broadcom BCM2835 auxiliary SPI1/2 controller - -The BCM2835 contains two forms of SPI master controller, one known simply as -SPI0, and the other known as the "Universal SPI Master"; part of the -auxiliary block. This binding applies to the SPI1/2 controller. - -Required properties: -- compatible: Should be "brcm,bcm2835-aux-spi". -- reg: Should contain register location and length for the spi block -- interrupts: Should contain shared interrupt of the aux block -- clocks: The clock feeding the SPI controller - needs to - point to the auxiliary clock driver of the bcm2835, - as this clock will enable the output gate for the specific - clock. -- cs-gpios: the cs-gpios (native cs is NOT supported) - see also spi-bus.txt - -Example: - -spi1@7e215080 { - compatible = "brcm,bcm2835-aux-spi"; - reg = <0x7e215080 0x40>; - interrupts = <1 29>; - clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI1>; - #address-cells = <1>; - #size-cells = <0>; - cs-gpios = <&gpio 18>, <&gpio 17>, <&gpio 16>; -}; - -spi2@7e2150c0 { - compatible = "brcm,bcm2835-aux-spi"; - reg = <0x7e2150c0 0x40>; - interrupts = <1 29>; - clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI2>; - #address-cells = <1>; - #size-cells = <0>; - cs-gpios = <&gpio 43>, <&gpio 44>, <&gpio 45>; -}; diff --git a/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.yaml b/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.yaml new file mode 100644 index 00000000000000..561319544ee327 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/brcm,bcm2835-aux-spi.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/brcm,bcm2835-aux-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom BCM2835 Auxiliary SPI1/2 Controller + +maintainers: + - Karan Sanghavi + +description: + The BCM2835 contains two forms of SPI master controller. One is known simply + as SPI0, and the other as the "Universal SPI Master," which is part of the + auxiliary block. This binding applies to the SPI1 and SPI2 auxiliary + controllers. + +allOf: + - $ref: spi-controller.yaml# + +properties: + compatible: + enum: + - brcm,bcm2835-aux-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + spi@7e215080 { + compatible = "brcm,bcm2835-aux-spi"; + reg = <0x7e215080 0x40>; + interrupts = <1 29>; + clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI1>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml b/Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml new file mode 100644 index 00000000000000..36d79a90552bf4 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/realtek,rtl9301-snand.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SPI-NAND Flash Controller for Realtek RTL9300 SoCs + +maintainers: + - Chris Packham + +description: + The Realtek RTL9300 SoCs have a built in SPI-NAND controller. It supports + typical SPI-NAND page cache operations in single, dual or quad IO mode. + +properties: + compatible: + oneOf: + - items: + - enum: + - realtek,rtl9302b-snand + - realtek,rtl9302c-snand + - realtek,rtl9303-snand + - const: realtek,rtl9301-snand + - const: realtek,rtl9301-snand + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +allOf: + - $ref: /schemas/spi/spi-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + spi@1a400 { + compatible = "realtek,rtl9302c-snand", "realtek,rtl9301-snand"; + reg = <0x1a400 0x44>; + interrupt-parent = <&intc>; + interrupts = <19>; + clocks = <&lx_clk>; + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + compatible = "spi-nand"; + reg = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/spi/samsung,spi.yaml b/Documentation/devicetree/bindings/spi/samsung,spi.yaml index f681372da81fbd..3c206a64d60adf 100644 --- a/Documentation/devicetree/bindings/spi/samsung,spi.yaml +++ b/Documentation/devicetree/bindings/spi/samsung,spi.yaml @@ -26,6 +26,10 @@ properties: - samsung,exynos850-spi - samsung,exynosautov9-spi - tesla,fsd-spi + - items: + - enum: + - samsung,exynos8895-spi + - const: samsung,exynos850-spi - const: samsung,exynos7-spi deprecated: true diff --git a/Documentation/devicetree/bindings/spi/spi-sprd.txt b/Documentation/devicetree/bindings/spi/spi-sprd.txt deleted file mode 100644 index 3c7eacce0ee3b7..00000000000000 --- a/Documentation/devicetree/bindings/spi/spi-sprd.txt +++ /dev/null @@ -1,33 +0,0 @@ -Spreadtrum SPI Controller - -Required properties: -- compatible: Should be "sprd,sc9860-spi". -- reg: Offset and length of SPI controller register space. -- interrupts: Should contain SPI interrupt. -- clock-names: Should contain following entries: - "spi" for SPI clock, - "source" for SPI source (parent) clock, - "enable" for SPI module enable clock. -- clocks: List of clock input name strings sorted in the same order - as the clock-names property. -- #address-cells: The number of cells required to define a chip select - address on the SPI bus. Should be set to 1. -- #size-cells: Should be set to 0. - -Optional properties: -dma-names: Should contain names of the SPI used DMA channel. -dmas: Should contain DMA channels and DMA slave ids which the SPI used - sorted in the same order as the dma-names property. - -Example: -spi0: spi@70a00000{ - compatible = "sprd,sc9860-spi"; - reg = <0 0x70a00000 0 0x1000>; - interrupts = ; - clock-names = "spi", "source","enable"; - clocks = <&clk_spi0>, <&ext_26m>, <&clk_ap_apb_gates 5>; - dma-names = "rx_chn", "tx_chn"; - dmas = <&apdma 11 11>, <&apdma 12 12>; - #address-cells = <1>; - #size-cells = <0>; -}; diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml index e5199b109dad9f..04d4d3b4916dbb 100644 --- a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml +++ b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml @@ -9,9 +9,6 @@ title: Xilinx Zynq UltraScale+ MPSoC GQSPI controller maintainers: - Michal Simek -allOf: - - $ref: spi-controller.yaml# - properties: compatible: enum: @@ -19,6 +16,7 @@ properties: - xlnx,zynqmp-qspi-1.0 reg: + minItems: 1 maxItems: 2 interrupts: @@ -47,6 +45,24 @@ required: unevaluatedProperties: false +allOf: + - $ref: spi-controller.yaml# + + - if: + properties: + compatible: + contains: + const: xlnx,zynqmp-qspi-1.0 + then: + properties: + reg: + minItems: 2 + + else: + properties: + reg: + maxItems: 1 + examples: - | #include diff --git a/Documentation/devicetree/bindings/spi/sprd,sc9860-spi.yaml b/Documentation/devicetree/bindings/spi/sprd,sc9860-spi.yaml new file mode 100644 index 00000000000000..d55c01e9a03818 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/sprd,sc9860-spi.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/sprd,sc9860-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Spreadtrum SC9860 SPI Controller + +maintainers: + - Orson Zhai + - Baolin Wang + - Chunyan Zhang + +properties: + compatible: + const: sprd,sc9860-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: SPI clock + - description: SPI source (parent) clock + - description: SPI module enable clock + + clock-names: + items: + - const: spi + - const: source + - const: enable + + dmas: + maxItems: 2 + + dma-names: + items: + - const: rx_chn + - const: tx_chn + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +allOf: + - $ref: spi-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + spi@70a00000 { + compatible = "sprd,sc9860-spi"; + reg = <0x70a00000 0x1000>; + interrupts = ; + clocks = <&clk_spi0>, <&ext_26m>, <&clk_ap_apb_gates 5>; + clock-names = "spi", "source", "enable"; + dmas = <&apdma 11 11>, <&apdma 12 12>; + dma-names = "rx_chn", "tx_chn"; + #address-cells = <1>; + #size-cells = <0>; + }; +... diff --git a/Documentation/devicetree/bindings/spmi/mtk,spmi-mtk-pmif.yaml b/Documentation/devicetree/bindings/spmi/mtk,spmi-mtk-pmif.yaml index ac99883a3f295b..7f0be0ac644aa3 100644 --- a/Documentation/devicetree/bindings/spmi/mtk,spmi-mtk-pmif.yaml +++ b/Documentation/devicetree/bindings/spmi/mtk,spmi-mtk-pmif.yaml @@ -25,6 +25,7 @@ properties: - items: - enum: - mediatek,mt8186-spmi + - mediatek,mt8188-spmi - const: mediatek,mt8195-spmi reg: diff --git a/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml index a28b70fb330a3a..7c3cc20a80d6cf 100644 --- a/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml +++ b/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml @@ -19,7 +19,11 @@ description: | properties: compatible: - const: qcom,x1e80100-spmi-pmic-arb + oneOf: + - items: + - const: qcom,sar2130p-spmi-pmic-arb + - const: qcom,x1e80100-spmi-pmic-arb + - const: qcom,x1e80100-spmi-pmic-arb reg: items: diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml index faef3d6e0a941a..9b06bcd0195772 100644 --- a/Documentation/devicetree/bindings/sram/qcom,imem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml @@ -21,6 +21,7 @@ properties: - qcom,msm8226-imem - qcom,msm8974-imem - qcom,qcs404-imem + - qcom,qcs8300-imem - qcom,qdu1000-imem - qcom,sa8775p-imem - qcom,sc7180-imem diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml index 0922d1f71ba8a8..7c1337e159f237 100644 --- a/Documentation/devicetree/bindings/sram/sram.yaml +++ b/Documentation/devicetree/bindings/sram/sram.yaml @@ -101,6 +101,12 @@ patternProperties: IO mem address range, relative to the SRAM range. maxItems: 1 + reg-io-width: + description: + The size (in bytes) of the IO accesses that should be performed on the + SRAM. + enum: [1, 2, 4, 8] + pool: description: Indicates that the particular reserved SRAM area is addressable diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index a12fddc8195500..ed5de0f92a9e1e 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -39,6 +39,7 @@ properties: - description: v1 of TSENS items: - enum: + - qcom,msm8937-tsens - qcom,msm8956-tsens - qcom,msm8976-tsens - qcom,qcs404-tsens @@ -53,6 +54,7 @@ properties: - qcom,qcm2290-tsens - qcom,sa8255p-tsens - qcom,sa8775p-tsens + - qcom,sar2130p-tsens - qcom,sc7180-tsens - qcom,sc7280-tsens - qcom,sc8180x-tsens diff --git a/Documentation/devicetree/bindings/timer/actions,owl-timer.txt b/Documentation/devicetree/bindings/timer/actions,owl-timer.txt deleted file mode 100644 index 977054f87563ce..00000000000000 --- a/Documentation/devicetree/bindings/timer/actions,owl-timer.txt +++ /dev/null @@ -1,21 +0,0 @@ -Actions Semi Owl Timer - -Required properties: -- compatible : "actions,s500-timer" for S500 - "actions,s700-timer" for S700 - "actions,s900-timer" for S900 -- reg : Offset and length of the register set for the device. -- interrupts : Should contain the interrupts. -- interrupt-names : Valid names are: "2hz0", "2hz1", - "timer0", "timer1", "timer2", "timer3" - See ../resource-names.txt - -Example: - - timer@b0168000 { - compatible = "actions,s500-timer"; - reg = <0xb0168000 0x100>; - interrupts = , - ; - interrupt-names = "timer0", "timer1"; - }; diff --git a/Documentation/devicetree/bindings/timer/actions,owl-timer.yaml b/Documentation/devicetree/bindings/timer/actions,owl-timer.yaml new file mode 100644 index 00000000000000..646c554a390a3a --- /dev/null +++ b/Documentation/devicetree/bindings/timer/actions,owl-timer.yaml @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/timer/actions,owl-timer.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Actions Semi Owl timer + +maintainers: + - Andreas Färber + +description: + Actions Semi Owl SoCs provide 32bit and 2Hz timers. + The 32bit timers support dynamic irq, as well as one-shot mode. + +properties: + compatible: + enum: + - actions,s500-timer + - actions,s700-timer + - actions,s900-timer + + clocks: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 6 + + interrupt-names: + minItems: 1 + maxItems: 6 + items: + enum: + - 2hz0 + - 2hz1 + - timer0 + - timer1 + - timer2 + - timer3 + + reg: + maxItems: 1 + +required: + - compatible + - clocks + - interrupts + - interrupt-names + - reg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - actions,s500-timer + then: + properties: + interrupts: + minItems: 4 + maxItems: 4 + interrupt-names: + items: + - const: 2hz0 + - const: 2hz1 + - const: timer0 + - const: timer1 + + - if: + properties: + compatible: + contains: + enum: + - actions,s700-timer + - actions,s900-timer + then: + properties: + interrupts: + minItems: 1 + maxItems: 1 + interrupt-names: + items: + - const: timer1 + +additionalProperties: false + +examples: + - | + #include + #include + soc { + #address-cells = <1>; + #size-cells = <1>; + timer@b0168000 { + compatible = "actions,s500-timer"; + reg = <0xb0168000 0x100>; + clocks = <&hosc>; + interrupts = , + , + , + ; + interrupt-names = "2hz0", "2hz1", "timer0", "timer1"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.yaml b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.yaml index 774b7992a0cafc..02d1c355808e4e 100644 --- a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.yaml +++ b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.yaml @@ -33,6 +33,7 @@ properties: - samsung,exynos5420-mct - samsung,exynos5433-mct - samsung,exynos850-mct + - samsung,exynos8895-mct - tesla,fsd-mct - const: samsung,exynos4210-mct @@ -133,6 +134,7 @@ allOf: - samsung,exynos5420-mct - samsung,exynos5433-mct - samsung,exynos850-mct + - samsung,exynos8895-mct then: properties: interrupts: diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 9bf0fb17a05e56..88abb5c174f3bd 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -153,12 +153,6 @@ properties: - isil,isl29028 # Intersil ISL29030 Ambient Light and Proximity Sensor - isil,isl29030 - # Intersil ISL68137 Digital Output Configurable PWM Controller - - isil,isl68137 - # Intersil ISL69260 PMBus Voltage Regulator - - isil,isl69260 - # Intersil ISL69269 PMBus Voltage Regulator - - isil,isl69269 # Intersil ISL76682 Ambient Light Sensor - isil,isl76682 # JEDEC JESD300 (SPD5118) Hub and Serial Presence Detect @@ -279,12 +273,6 @@ properties: - mps,mp2888 # Monolithic Power Systems Inc. multi-phase controller mp2891 - mps,mp2891 - # Monolithic Power Systems Inc. multi-phase controller mp2971 - - mps,mp2971 - # Monolithic Power Systems Inc. multi-phase controller mp2973 - - mps,mp2973 - # Monolithic Power Systems Inc. multi-phase controller mp2975 - - mps,mp2975 # Monolithic Power Systems Inc. multi-phase controller mp2993 - mps,mp2993 # Monolithic Power Systems Inc. multi-phase hot-swap controller mp5920 @@ -309,6 +297,8 @@ properties: - nuvoton,w83773g # OKI ML86V7667 video decoder - oki,ml86v7667 + # ON Semiconductor ADT7462 Temperature, Voltage Monitor and Fan Controller + - onnn,adt7462 # 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch - plx,pex8648 # Pulsedlight LIDAR range-finding sensor @@ -357,8 +347,6 @@ properties: - swir,mangoh-iotport-spi # Ambient Light Sensor with SMBUS/Two Wire Serial Interface - taos,tsl2550 - # Temperature Monitoring and Fan Control - - ti,amc6821 # Temperature and humidity sensor with i2c interface - ti,hdc1000 # Temperature and humidity sensor with i2c interface @@ -400,8 +388,6 @@ properties: - ti,tps546d24 # I2C Touch-Screen Controller - ti,tsc2003 - # Vicor Corporation Digital Supervisor - - vicor,pli1209bc # Winbond/Nuvoton H/W Monitor - winbond,w83793 diff --git a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml index 25a5edeea16459..cde334e3206b0a 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml @@ -26,6 +26,7 @@ properties: - qcom,msm8994-ufshc - qcom,msm8996-ufshc - qcom,msm8998-ufshc + - qcom,qcs8300-ufshc - qcom,sa8775p-ufshc - qcom,sc7180-ufshc - qcom,sc7280-ufshc @@ -146,6 +147,7 @@ allOf: contains: enum: - qcom,msm8998-ufshc + - qcom,qcs8300-ufshc - qcom,sa8775p-ufshc - qcom,sc7280-ufshc - qcom,sc8180x-ufshc diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml index f972ce976e860b..7ffcd236d7bb45 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.yaml @@ -23,7 +23,9 @@ properties: - enum: - allwinner,sun8i-a83t-musb - allwinner,sun20i-d1-musb + - allwinner,sun50i-a100-musb - allwinner,sun50i-h6-musb + - allwinner,sun55i-a523-musb - const: allwinner,sun8i-a33-musb - items: - const: allwinner,sun50i-h616-musb diff --git a/Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml b/Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml index 89fc9a434d05f4..0620d82508c175 100644 --- a/Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml +++ b/Documentation/devicetree/bindings/usb/cypress,cypd4226.yaml @@ -61,18 +61,15 @@ additionalProperties: false examples: - | - #include #include i2c { #address-cells = <1>; #size-cells = <0>; - #interrupt-cells = <2>; typec@8 { compatible = "cypress,cypd4226"; reg = <0x08>; - interrupt-parent = <&gpio_aon>; - interrupts = ; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; firmware-name = "nvidia,jetson-agx-xavier"; #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml b/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml index 9ea1e4cd0709c9..baf130669c3877 100644 --- a/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/fsl,imx8mp-dwc3.yaml @@ -12,7 +12,11 @@ maintainers: properties: compatible: - const: fsl,imx8mp-dwc3 + oneOf: + - items: + - const: fsl,imx95-dwc3 + - const: fsl,imx8mp-dwc3 + - const: fsl,imx8mp-dwc3 reg: items: diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml index 2ed178f16a7822..223f2abd5e592f 100644 --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml @@ -28,9 +28,11 @@ properties: - items: - enum: - allwinner,sun4i-a10-ehci + - allwinner,sun50i-a100-ehci - allwinner,sun50i-a64-ehci - allwinner,sun50i-h6-ehci - allwinner,sun50i-h616-ehci + - allwinner,sun55i-a523-ehci - allwinner,sun5i-a13-ehci - allwinner,sun6i-a31-ehci - allwinner,sun7i-a20-ehci diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml index b9576015736bf8..3ee1586fc8b968 100644 --- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml @@ -15,9 +15,11 @@ properties: - items: - enum: - allwinner,sun4i-a10-ohci + - allwinner,sun50i-a100-ohci - allwinner,sun50i-a64-ohci - allwinner,sun50i-h6-ohci - allwinner,sun50i-h616-ohci + - allwinner,sun55i-a523-ohci - allwinner,sun5i-a13-ohci - allwinner,sun6i-a31-ohci - allwinner,sun7i-a20-ohci diff --git a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml index fc833363cfb492..6fe2d356dcbdec 100644 --- a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml +++ b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml @@ -62,7 +62,14 @@ allOf: peer-hub: true vdd-supply: true -additionalProperties: false +patternProperties: + "^.*@[0-9a-f]{1,2}$": + description: The hard wired USB devices + type: object + $ref: /schemas/usb/usb-device.yaml + additionalProperties: true + +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml index 276bf7554215e6..20b62228371bde 100644 --- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml +++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml @@ -69,6 +69,7 @@ examples: PDO_FIXED_DATA_SWAP | PDO_FIXED_DUAL_ROLE) PDO_FIXED(9000, 2000, 0)>; + sink-bc12-completion-time-ms = <500>; }; }; }; diff --git a/Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml b/Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml index 27b909de49922f..a812317d808931 100644 --- a/Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml +++ b/Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml @@ -14,8 +14,11 @@ maintainers: properties: compatible: - enum: - - microchip,mpfs-musb + oneOf: + - items: + - const: microchip,pic64gx-musb + - const: microchip,mpfs-musb + - const: microchip,mpfs-musb dr_mode: true diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 18758efb8d2966..935e204b607bbd 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -26,8 +26,10 @@ properties: - qcom,msm8998-dwc3 - qcom,qcm2290-dwc3 - qcom,qcs404-dwc3 + - qcom,qcs8300-dwc3 - qcom,qdu1000-dwc3 - qcom,sa8775p-dwc3 + - qcom,sar2130p-dwc3 - qcom,sc7180-dwc3 - qcom,sc7280-dwc3 - qcom,sc8180x-dwc3 @@ -201,6 +203,7 @@ allOf: - qcom,msm8953-dwc3 - qcom,msm8996-dwc3 - qcom,msm8998-dwc3 + - qcom,qcs8300-dwc3 - qcom,sa8775p-dwc3 - qcom,sc7180-dwc3 - qcom,sc7280-dwc3 @@ -338,6 +341,7 @@ allOf: contains: enum: - qcom,qcm2290-dwc3 + - qcom,sar2130p-dwc3 - qcom,sc8180x-dwc3 - qcom,sc8180x-dwc3-mp - qcom,sm6115-dwc3 @@ -465,6 +469,7 @@ allOf: - qcom,ipq4019-dwc3 - qcom,ipq8064-dwc3 - qcom,msm8994-dwc3 + - qcom,qcs8300-dwc3 - qcom,qdu1000-dwc3 - qcom,sa8775p-dwc3 - qcom,sc7180-dwc3 @@ -490,6 +495,7 @@ allOf: minItems: 4 maxItems: 5 interrupt-names: + minItems: 4 items: - const: pwr_event - const: hs_phy_irq diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml index c63db3ebd07bd4..b23ef29bf7949f 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml @@ -76,6 +76,10 @@ properties: Integer to use BUSWAIT register. renesas,enable-gpio: + deprecated: true + maxItems: 1 + + renesas,enable-gpios: maxItems: 1 description: | gpio specifier to check GPIO determining if USB function should be diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml b/Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml index c4924113f9bdec..a21cc098542d79 100644 --- a/Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.yaml @@ -27,6 +27,7 @@ select: enum: - rockchip,rk3328-dwc3 - rockchip,rk3568-dwc3 + - rockchip,rk3576-dwc3 - rockchip,rk3588-dwc3 required: - compatible @@ -37,6 +38,7 @@ properties: - enum: - rockchip,rk3328-dwc3 - rockchip,rk3568-dwc3 + - rockchip,rk3576-dwc3 - rockchip,rk3588-dwc3 - const: snps,dwc3 @@ -113,7 +115,9 @@ allOf: properties: compatible: contains: - const: rockchip,rk3568-dwc3 + enum: + - rockchip,rk3568-dwc3 + - rockchip,rk3576-dwc3 then: properties: clocks: diff --git a/Documentation/devicetree/bindings/usb/ti,tusb1046.yaml b/Documentation/devicetree/bindings/usb/ti,tusb1046.yaml new file mode 100644 index 00000000000000..f713cac4a8ac8e --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ti,tusb1046.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/ti,tusb1046.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TUSB1046-DCI Type-C crosspoint switch + +maintainers: + - Romain Gantois + +allOf: + - $ref: usb-switch.yaml# + +properties: + compatible: + const: ti,tusb1046 + + reg: + maxItems: 1 + +required: + - compatible + - reg + - port + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + typec-mux@44 { + compatible = "ti,tusb1046"; + reg = <0x44>; + + mode-switch; + orientation-switch; + + port { + endpoint { + remote-endpoint = <&typec_controller>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/usb/ti,tusb73x0-pci.yaml b/Documentation/devicetree/bindings/usb/ti,tusb73x0-pci.yaml new file mode 100644 index 00000000000000..ddda734f36fb2a --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ti,tusb73x0-pci.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/ti,tusb73x0-pci.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TUSB73x0 USB 3.0 xHCI Host Controller (PCIe) + +maintainers: + - Francesco Dolcini + +description: + TUSB73x0 USB 3.0 xHCI Host Controller via PCIe x1 Gen2 interface. + The TUSB7320 supports up to two downstream ports, the TUSB7340 supports up + to four downstream ports, both variants share the same PCI device ID. + +properties: + compatible: + const: pci104c,8241 + + reg: + maxItems: 1 + + ti,pwron-active-high: + $ref: /schemas/types.yaml#/definitions/flag + description: + Configure the polarity of the PWRONx# signals. When this is present, the + PWRONx# pins are active high and their internal pull-down resistors are + disabled. When this is absent, the PWRONx# pins are active low (default) + and their internal pull-down resistors are enabled. + +required: + - compatible + - reg + +allOf: + - $ref: usb-xhci.yaml + +additionalProperties: false + +examples: + - | + pcie@0 { + reg = <0x0 0x1000>; + ranges = <0x02000000 0x0 0x100000 0x10000000 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + + usb@0 { + compatible = "pci104c,8241"; + reg = <0x0 0x0 0x0 0x0 0x0>; + ti,pwron-active-high; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index b320a39de7fe40..da01616802c768 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -83,6 +83,8 @@ patternProperties: description: ALFA Network Inc. "^allegro,.*": description: Allegro DVT + "^allegromicro,.*": + description: Allegro MicroSystems, Inc. "^alliedvision,.*": description: Allied Vision Technologies GmbH "^allo,.*": @@ -312,6 +314,8 @@ patternProperties: description: Colorful GRP, Shenzhen Xueyushi Technology Ltd. "^compulab,.*": description: CompuLab Ltd. + "^comvetia,.*": + description: ComVetia AG "^congatec,.*": description: congatec GmbH "^coolpi,.*": @@ -356,6 +360,8 @@ patternProperties: description: DataImage, Inc. "^davicom,.*": description: DAVICOM Semiconductor, Inc. + "^deepcomputing,.*": + description: DeepComputing (HK) Limited "^dell,.*": description: Dell Inc. "^delta,.*": @@ -561,6 +567,8 @@ patternProperties: description: GE Fanuc Intelligent Platforms Embedded Systems, Inc. "^GEFanuc,.*": description: GE Fanuc Intelligent Platforms Embedded Systems, Inc. + "^gehc,.*": + description: GE HealthCare "^gemei,.*": description: Gemei Digital Technology Co., Ltd. "^gemtek,.*": @@ -752,6 +760,8 @@ patternProperties: description: Japan Display Inc. "^jedec,.*": description: JEDEC Solid State Technology Association + "^jenson,.*": + description: Jenson Display Co. Ltd. "^jesurun,.*": description: Shenzhen Jesurun Electronics Business Dept. "^jethome,.*": @@ -1013,6 +1023,8 @@ patternProperties: description: Shanghai Neardi Technology Co., Ltd. "^nec,.*": description: NEC LCD Technologies, Ltd. + "^neofidelity,.*": + description: Neofidelity Inc. "^neonode,.*": description: Neonode Inc. "^netgear,.*": @@ -1045,6 +1057,8 @@ patternProperties: description: Nokia "^nordic,.*": description: Nordic Semiconductor + "^nothing,.*": + description: Nothing Technology Limited "^novatek,.*": description: Novatek "^novtech,.*": @@ -1224,6 +1238,8 @@ patternProperties: description: Unisoc Communications, Inc. "^realtek,.*": description: Realtek Semiconductor Corp. + "^relfor,.*": + description: Relfor Labs Pvt. Ltd. "^remarkable,.*": description: reMarkable AS "^renesas,.*": @@ -1386,6 +1402,8 @@ patternProperties: description: Sophgo Technology Inc. "^sourceparts,.*": description: Source Parts Inc. + "^spacemit,.*": + description: SpacemiT (Hangzhou) Technology Co. Ltd "^spansion,.*": description: Spansion Inc. "^sparkfun,.*": diff --git a/Documentation/devicetree/bindings/watchdog/airoha,en7581-wdt.yaml b/Documentation/devicetree/bindings/watchdog/airoha,en7581-wdt.yaml new file mode 100644 index 00000000000000..6bbab3cb28e545 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/airoha,en7581-wdt.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/airoha,en7581-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Airoha EN7581 Watchdog Timer + +maintainers: + - Christian Marangi + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + const: airoha,en7581-wdt + + reg: + maxItems: 1 + + clocks: + description: BUS clock (timer ticks at half the BUS clock) + maxItems: 1 + + clock-names: + const: bus + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include + + watchdog@1fbf0100 { + compatible = "airoha,en7581-wdt"; + reg = <0x1fbf0100 0x3c>; + + clocks = <&scuclk EN7523_CLK_BUS>; + clock-names = "bus"; + }; diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml index 21872e15916cad..310832fa8c2803 100644 --- a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml @@ -16,6 +16,11 @@ properties: compatible: items: - enum: + - apple,s5l8960x-wdt + - apple,t7000-wdt + - apple,s8000-wdt + - apple,t8010-wdt + - apple,t8015-wdt - apple,t8103-wdt - apple,t8112-wdt - apple,t6000-wdt diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml index 36b836d0620c9b..0da953cb712726 100644 --- a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.yaml @@ -48,6 +48,8 @@ properties: clocks: maxItems: 1 + big-endian: true + fsl,ext-reset-output: $ref: /schemas/types.yaml#/definitions/flag description: | @@ -93,6 +95,18 @@ allOf: properties: fsl,suspend-in-wait: false + - if: + not: + properties: + compatible: + contains: + enum: + - fsl,ls1012a-wdt + - fsl,ls1043a-wdt + then: + properties: + big-endian: false + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index 932393f8c649af..34896a39fa91f6 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -26,6 +26,8 @@ properties: - qcom,apss-wdt-msm8994 - qcom,apss-wdt-qcm2290 - qcom,apss-wdt-qcs404 + - qcom,apss-wdt-qcs615 + - qcom,apss-wdt-qcs8300 - qcom,apss-wdt-sa8255p - qcom,apss-wdt-sa8775p - qcom,apss-wdt-sc7180 diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml index 77a5ddd0426ebc..d175ae9683366d 100644 --- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml @@ -26,6 +26,7 @@ properties: - samsung,exynos7-wdt # for Exynos7 - samsung,exynos850-wdt # for Exynos850 - samsung,exynosautov9-wdt # for Exynosautov9 + - samsung,exynosautov920-wdt # for Exynosautov920 - items: - enum: - tesla,fsd-wdt @@ -77,6 +78,7 @@ allOf: - samsung,exynos7-wdt - samsung,exynos850-wdt - samsung,exynosautov9-wdt + - samsung,exynosautov920-wdt then: required: - samsung,syscon-phandle @@ -88,6 +90,7 @@ allOf: - google,gs101-wdt - samsung,exynos850-wdt - samsung,exynosautov9-wdt + - samsung,exynosautov920-wdt then: properties: clocks: diff --git a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml index b5a3dc37707069..1efefd741c06d1 100644 --- a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml @@ -32,6 +32,7 @@ properties: - rockchip,rk3576-wdt - rockchip,rk3588-wdt - rockchip,rv1108-wdt + - rockchip,rv1126-wdt - const: snps,dw-wdt reg: diff --git a/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.txt b/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.txt deleted file mode 100644 index 3de96186e92e6f..00000000000000 --- a/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.txt +++ /dev/null @@ -1,39 +0,0 @@ -Zodiac Inflight Innovations RAVE Supervisory Processor Watchdog Bindings - -RAVE SP watchdog device is a "MFD cell" device corresponding to -watchdog functionality of RAVE Supervisory Processor. It is expected -that its Device Tree node is specified as a child of the node -corresponding to the parent RAVE SP device (as documented in -Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) - -Required properties: - -- compatible: Depending on wire protocol implemented by RAVE SP - firmware, should be one of: - - "zii,rave-sp-watchdog" - - "zii,rave-sp-watchdog-legacy" - -Optional properties: - -- wdt-timeout: Two byte nvmem cell specified as per - Documentation/devicetree/bindings/nvmem/nvmem.txt - -Example: - - rave-sp { - compatible = "zii,rave-sp-rdu1"; - current-speed = <38400>; - - eeprom { - wdt_timeout: wdt-timeout@8E { - reg = <0x8E 2>; - }; - }; - - watchdog { - compatible = "zii,rave-sp-watchdog"; - nvmem-cells = <&wdt_timeout>; - nvmem-cell-names = "wdt-timeout"; - }; - } - diff --git a/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.yaml b/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.yaml new file mode 100644 index 00000000000000..de0d56725dd40b --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/zii,rave-sp-wdt.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/zii,rave-sp-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Zodiac Inflight Innovations RAVE Supervisory Processor Watchdog + +maintainers: + - Frank Li + +description: + RAVE SP watchdog device is a "MFD cell" device corresponding to + watchdog functionality of RAVE Supervisory Processor. It is expected + that its Device Tree node is specified as a child of the node + corresponding to the parent RAVE SP device (as documented in + Documentation/devicetree/bindings/mfd/zii,rave-sp.yaml) + +properties: + compatible: + enum: + - zii,rave-sp-watchdog + - zii,rave-sp-watchdog-legacy + + nvmem-cell-names: + items: + - const: wdt_timeout + + nvmem-cells: + maxItems: 1 + +required: + - compatible + +allOf: + - $ref: watchdog.yaml# + +unevaluatedProperties: false + +examples: + - | + watchdog { + compatible = "zii,rave-sp-watchdog"; + nvmem-cells = <&wdt_timeout>; + nvmem-cell-names = "wdt_timeout"; + }; + diff --git a/Documentation/devicetree/bindings/writing-schema.rst b/Documentation/devicetree/bindings/writing-schema.rst index 7e71cdd1d6ded6..eb8ced400c7ebf 100644 --- a/Documentation/devicetree/bindings/writing-schema.rst +++ b/Documentation/devicetree/bindings/writing-schema.rst @@ -43,6 +43,36 @@ description or device does, standards the device conforms to, and links to datasheets for more information. + The YAML format has several options for defining the formatting of the text + block. The options are controlled with indicator characters following the key + (e.g. "description: \|"). The minimum formatting needed for a block should be + used. The formatting controls can not only affect whether the YAML can be + parsed correctly, but are important when the text blocks are rendered to + another form. The options are as follows. + + The default without any indicators is flowed, plain scalar style where single + line breaks and leading whitespace are stripped. Paragraphs are delimited by + blank lines (i.e. double line break). This style cannot contain ": " in it as + it will be interpretted as a key. Any " #" sequence will be interpretted as + a comment. There's other restrictions on characters as well. Most + restrictions are on what the first character can be. + + The second style is folded which is indicated by ">" character. In addition + to maintaining line breaks on double line breaks, the folded style also + maintains leading whitespace beyond indentation of the first line. The line + breaks on indented lines are also maintained. + + The third style is literal which is indicated by "\|" character. The literal + style maintains all line breaks and whitespace (beyond indentation of the + first line). + + The above is not a complete description of YAML text blocks. More details on + multi-line YAML text blocks can be found online: + + https://yaml-multiline.info/ + + https://www.yaml.info/learn/quote.html + select Optional. A json-schema used to match nodes for applying the schema. By default, without 'select', nodes are matched against their possible diff --git a/Documentation/doc-guide/kernel-doc.rst b/Documentation/doc-guide/kernel-doc.rst index e6ffd59bb8f0fc..af9697e60165d2 100644 --- a/Documentation/doc-guide/kernel-doc.rst +++ b/Documentation/doc-guide/kernel-doc.rst @@ -533,6 +533,7 @@ identifiers: *[ function/type ...]* Include documentation for each *function* and *type* in *source*. If no *function* is specified, the documentation for all functions and types in the *source* will be included. + *type* can be a struct, union, enum, or typedef identifier. Examples:: diff --git a/Documentation/dontdiff b/Documentation/dontdiff deleted file mode 100644 index de2cb8de6112e3..00000000000000 --- a/Documentation/dontdiff +++ /dev/null @@ -1,271 +0,0 @@ -*.a -*.aux -*.bc -*.bin -*.bz2 -*.c.[012]*.* -*.cis -*.cpio -*.csp -*.dsp -*.dvi -*.elf -*.eps -*.fw -*.gcno -*.gcov -*.gen.S -*.gif -*.grep -*.grp -*.gz -*.html -*.i -*.jpeg -*.ko -*.ll -*.log -*.lst -*.lzma -*.lzo -*.mo -*.moc -*.mod -*.mod.c -*.o -*.o.* -*.order -*.orig -*.out -*.patch -*.pdf -*.plist -*.png -*.pot -*.ps -*.rej -*.s -*.sgml -*.so -*.so.dbg -*.symtypes -*.tab.c -*.tab.h -*.tex -*.ver -*.xml -*.xz -*.zst -*_MODULES -*_vga16.c -*~ -\#*# -*.9 -.* -.*.d -.mm -53c700_d.h -CVS -ChangeSet -GPATH -GRTAGS -GSYMS -GTAGS -Image -Module.markers -Module.symvers -PENDING -SCCS -System.map* -TAGS -aconf -af_names.h -aic7*reg.h* -aic7*reg_print.c* -aic7*seq.h* -aicasm -aicdb.h* -altivec*.c -asm-offsets.h -asm_offsets.h -autoconf.h* -av_permissions.h -bbootsect -binkernel.spec -bootsect -bounds.h -bsetup -btfixupprep -build -bvmlinux -bzImage* -capability_names.h -capflags.c -classlist.h* -comp*.log -compile.h* -conf -config -config-* -config.mak -config.mak.autogen -conmakehash -consolemap_deftbl.c* -cpustr.h -crc32table.h* -cscope.* -defkeymap.c -devlist.h* -devicetable-offsets.h -dnotify_test -dslm -dtc -elf2ecoff -elfconfig.h* -evergreen_reg_safe.h -fixdep -flask.h -fore200e_mkfirm -fore200e_pca_fw.c* -gconf -gconf-cfg -gen-devlist -gen_crc32table -gen_init_cpio -generated -genheaders -genksyms -*_gray256.c -hpet_example -hugepage-mmap -hugepage-shm -ihex2fw -inat-tables.c -initramfs_list -int16.c -int1.c -int2.c -int32.c -int4.c -int8.c -kallsyms -keywords.c -ksym.c* -ksym.h* -*lex.c -*lex.*.c -linux -logo_*.c -logo_*_clut224.c -logo_*_mono.c -mach-types -mach-types.h -machtypes.h -map -map_hugetlb -mconf -mconf-cfg -miboot* -mk_elfconfig -mkboot -mkbugboot -mkcpustr -mkdep -mkprep -mkregtable -mktables -mktree -mkutf8data -modpost -modules-only.symvers -modules.builtin -modules.builtin.modinfo -modules.builtin.ranges -modules.nsdeps -modules.order -modversions.h* -nconf -nconf-cfg -ncscope.* -offset.h -oui.c* -page-types -parse.c -parse.h -patches* -pca200e.bin -pca200e_ecd.bin2 -perf.data -perf.data.old -perf-archive -piggyback -piggy.gzip -piggy.S -pnmtologo -ppc_defs.h* -pss_boot.h -qconf -qconf-cfg -r100_reg_safe.h -r200_reg_safe.h -r300_reg_safe.h -r420_reg_safe.h -r600_reg_safe.h -randstruct.seed -randomize_layout_hash.h -randomize_layout_seed.h -recordmcount -relocs -rlim_names.h -rn50_reg_safe.h -rs600_reg_safe.h -rv515_reg_safe.h -series -setup -setup.bin -setup.elf -sortextable -sImage -sm_tbl* -split-include -syscalltab.h -tables.c -tags -test_get_len -tftpboot.img -timeconst.h -times.h* -trix_boot.h -utsrelease.h* -vdso-syms.lds -vdso.lds -vdso32-int80-syms.lds -vdso32-syms.lds -vdso32-syscall-syms.lds -vdso32-sysenter-syms.lds -vdso32.lds -vdso32.so.dbg -vdso64.lds -vdso64.so.dbg -version.h* -vmImage -vmlinux -vmlinux-* -vmlinux.aout -vmlinux.bin.all -vmlinux.lds -vmlinux.map -vmlinux.symvers -vmlinuz -voffset.h -vsyscall.lds -vsyscall_32.lds -wanxlfw.inc -uImage -unifdef -utf8data.c -wakeup.bin -wakeup.elf -wakeup.lds -zImage* -zoffset.h diff --git a/Documentation/driver-api/auxiliary_bus.rst b/Documentation/driver-api/auxiliary_bus.rst index cec84908fbc0d6..b236de773e1d6c 100644 --- a/Documentation/driver-api/auxiliary_bus.rst +++ b/Documentation/driver-api/auxiliary_bus.rst @@ -24,7 +24,6 @@ Auxiliary Device Creation .. kernel-doc:: drivers/base/auxiliary.c :identifiers: auxiliary_device_init __auxiliary_device_add - auxiliary_find_device Auxiliary Device Memory Model and Lifespan ------------------------------------------ diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 5f2ee8d717b1de..d594d0ea0e9dfa 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -394,7 +394,6 @@ PCI pcim_enable_device() : after success, some PCI ops become managed pcim_iomap() : do iomap() on a single BAR pcim_iomap_regions() : do request_region() and iomap() on multiple BARs - pcim_iomap_regions_request_all() : do request_region() on all and iomap() on multiple BARs pcim_iomap_table() : array of mapped addresses indexed by BAR pcim_iounmap() : do iounmap() on a single BAR pcim_iounmap_regions() : do iounmap() and release_region() on multiple BARs @@ -459,11 +458,10 @@ SERDEV SLAVE DMA ENGINE devm_acpi_dma_controller_register() - devm_acpi_dma_controller_free() SPI - devm_spi_alloc_master() - devm_spi_alloc_slave() + devm_spi_alloc_host() + devm_spi_alloc_target() devm_spi_optimize_message() devm_spi_register_controller() devm_spi_register_host() diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index b4920b34cebcc7..c290833165e67a 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -81,10 +81,10 @@ restart when the system is resumed. This requires coordination between the camera sensor and the rest of the camera pipeline. Bridge drivers are responsible for this coordination, and instruct camera sensors to stop and restart streaming by calling the appropriate subdev operations -(``.s_stream()``, ``.enable_streams()`` or ``.disable_streams()``). Camera -sensor drivers shall therefore **not** keep track of the streaming state to -stop streaming in the PM suspend handler and restart it in the resume handler. -Drivers should in general not implement the system PM handlers. +(``.enable_streams()`` or ``.disable_streams()``). Camera sensor drivers shall +therefore **not** keep track of the streaming state to stop streaming in the PM +suspend handler and restart it in the resume handler. Drivers should in general +not implement the system PM handlers. Camera sensor drivers shall **not** implement the subdev ``.s_power()`` operation, as it is deprecated. While this operation is implemented in some diff --git a/Documentation/driver-api/media/drivers/ipu6.rst b/Documentation/driver-api/media/drivers/ipu6.rst index 6e1dd19b36fbc1..88f6498e74db83 100644 --- a/Documentation/driver-api/media/drivers/ipu6.rst +++ b/Documentation/driver-api/media/drivers/ipu6.rst @@ -98,21 +98,6 @@ The IPU6 driver exports its own DMA operations. The IPU6 driver will update the page table entries for each DMA operation and invalidate the MMU TLB after each unmap and free. -.. code-block:: none - - const struct dma_map_ops ipu6_dma_ops = { - .alloc = ipu6_dma_alloc, - .free = ipu6_dma_free, - .mmap = ipu6_dma_mmap, - .map_sg = ipu6_dma_map_sg, - .unmap_sg = ipu6_dma_unmap_sg, - ... - }; - -.. Note:: IPU6 MMU works behind IOMMU so for each IPU6 DMA ops, driver will call - generic PCI DMA ops to ask IOMMU to do the additional mapping if VT-d - enabled. - Firmware file format ==================== diff --git a/Documentation/driver-api/media/tx-rx.rst b/Documentation/driver-api/media/tx-rx.rst index 29d66a47b56e95..dd09484df1d33d 100644 --- a/Documentation/driver-api/media/tx-rx.rst +++ b/Documentation/driver-api/media/tx-rx.rst @@ -49,11 +49,14 @@ Link frequency The :ref:`V4L2_CID_LINK_FREQ ` control is used to tell the receiver the frequency of the bus (i.e. it is not the same as the symbol rate). -``.s_stream()`` callback -^^^^^^^^^^^^^^^^^^^^^^^^ +``.enable_streams()`` and ``.disable_streams()`` callbacks +^^^^^^^^^^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The struct struct v4l2_subdev_video_ops->s_stream() callback is used by the -receiver driver to control the transmitter driver's streaming state. +The struct v4l2_subdev_pad_ops->enable_streams() and struct +v4l2_subdev_pad_ops->disable_streams() callbacks are used by the receiver driver +to control the transmitter driver's streaming state. These callbacks may not be +called directly, but by using ``v4l2_subdev_enable_streams()`` and +``v4l2_subdev_disable_streams()``. CSI-2 transmitter drivers @@ -127,7 +130,7 @@ Stopping the transmitter ^^^^^^^^^^^^^^^^^^^^^^^^ A transmitter stops sending the stream of images as a result of -calling the ``.s_stream()`` callback. Some transmitters may stop the +calling the ``.disable_streams()`` callback. Some transmitters may stop the stream at a frame boundary whereas others stop immediately, effectively leaving the current frame unfinished. The receiver driver should not make assumptions either way, but function properly in both diff --git a/Documentation/driver-api/pci/pci.rst b/Documentation/driver-api/pci/pci.rst index aa40b1cc243b84..59d86e8271986a 100644 --- a/Documentation/driver-api/pci/pci.rst +++ b/Documentation/driver-api/pci/pci.rst @@ -46,6 +46,9 @@ PCI Support Library .. kernel-doc:: drivers/pci/pci-sysfs.c :internal: +.. kernel-doc:: drivers/pci/tph.c + :export: + PCI Hotplug Support Library --------------------------- diff --git a/Documentation/driver-api/pwrseq.rst b/Documentation/driver-api/pwrseq.rst index a644084ded17a9..ad18b2326b689a 100644 --- a/Documentation/driver-api/pwrseq.rst +++ b/Documentation/driver-api/pwrseq.rst @@ -11,7 +11,7 @@ Introduction ============ This framework is designed to abstract complex power-up sequences that are -shared between multiple logical devices in the linux kernel. +shared between multiple logical devices in the Linux kernel. The intention is to allow consumers to obtain a power sequencing handle exposed by the power sequence provider and delegate the actual requesting and @@ -25,7 +25,7 @@ The power sequencing API uses a number of terms specific to the subsystem: Unit - A unit is a discreet chunk of a power sequence. For instance one unit may + A unit is a discrete chunk of a power sequence. For instance one unit may enable a set of regulators, another may enable a specific GPIO. Units can define dependencies in the form of other units that must be enabled before it itself can be. @@ -62,7 +62,7 @@ Provider interface The provider API is admittedly not nearly as straightforward as the one for consumers but it makes up for it in flexibility. -Each provider can logically split the power-up sequence into descrete chunks +Each provider can logically split the power-up sequence into discrete chunks (units) and define their dependencies. They can then expose named targets that consumers may use as the final point in the sequence that they wish to reach. @@ -72,7 +72,7 @@ register with the pwrseq subsystem by calling pwrseq_device_register(). Dynamic consumer matching ------------------------- -The main difference between pwrseq and other linux kernel providers is the +The main difference between pwrseq and other Linux kernel providers is the mechanism for dynamic matching of consumers and providers. Every power sequence provider driver must implement the `match()` callback and pass it to the pwrseq core when registering with the subsystems. diff --git a/Documentation/fault-injection/fault-injection.rst b/Documentation/fault-injection/fault-injection.rst index 8b8aeea71c685b..1c14ba08fbfc21 100644 --- a/Documentation/fault-injection/fault-injection.rst +++ b/Documentation/fault-injection/fault-injection.rst @@ -45,6 +45,32 @@ Available fault injection capabilities ALLOW_ERROR_INJECTION() macro, by setting debugfs entries under /sys/kernel/debug/fail_function. No boot option supported. +- fail_skb_realloc + + inject skb (socket buffer) reallocation events into the network path. The + primary goal is to identify and prevent issues related to pointer + mismanagement in the network subsystem. By forcing skb reallocation at + strategic points, this feature creates scenarios where existing pointers to + skb headers become invalid. + + When the fault is injected and the reallocation is triggered, cached pointers + to skb headers and data no longer reference valid memory locations. This + deliberate invalidation helps expose code paths where proper pointer updating + is neglected after a reallocation event. + + By creating these controlled fault scenarios, the system can catch instances + where stale pointers are used, potentially leading to memory corruption or + system instability. + + To select the interface to act on, write the network name to + /sys/kernel/debug/fail_skb_realloc/devname. + If this field is left empty (which is the default value), skb reallocation + will be forced on all network interfaces. + + The effectiveness of this fault detection is enhanced when KASAN is + enabled, as it helps identify invalid memory references and use-after-free + (UAF) issues. + - NVMe fault injection inject NVMe status code and retry flag on devices permitted by setting @@ -216,6 +242,19 @@ configuration of fault-injection capabilities. use a negative errno, you better use 'printf' instead of 'echo', e.g.: $ printf %#x -12 > retval +- /sys/kernel/debug/fail_skb_realloc/devname: + + Specifies the network interface on which to force SKB reallocation. If + left empty, SKB reallocation will be applied to all network interfaces. + + Example usage:: + + # Force skb reallocation on eth0 + echo "eth0" > /sys/kernel/debug/fail_skb_realloc/devname + + # Clear the selection and force skb reallocation on all interfaces + echo "" > /sys/kernel/debug/fail_skb_realloc/devname + Boot option ^^^^^^^^^^^ @@ -227,6 +266,7 @@ use the boot option:: fail_usercopy= fail_make_request= fail_futex= + fail_skb_realloc= mmc_core.fail_request=,,, proc entries diff --git a/Documentation/features/locking/queued-spinlocks/arch-support.txt b/Documentation/features/locking/queued-spinlocks/arch-support.txt index 22f2990392ff8f..cf26042480e21d 100644 --- a/Documentation/features/locking/queued-spinlocks/arch-support.txt +++ b/Documentation/features/locking/queued-spinlocks/arch-support.txt @@ -20,7 +20,7 @@ | openrisc: | ok | | parisc: | TODO | | powerpc: | ok | - | riscv: | TODO | + | riscv: | ok | | s390: | TODO | | sh: | TODO | | sparc: | ok | diff --git a/Documentation/filesystems/autofs.rst b/Documentation/filesystems/autofs.rst index 1ac576458c69a8..5eb02394fcc3a1 100644 --- a/Documentation/filesystems/autofs.rst +++ b/Documentation/filesystems/autofs.rst @@ -442,7 +442,7 @@ which can be used to communicate directly with the autofs filesystem. It requires CAP_SYS_ADMIN for access. The 'ioctl's that can be used on this device are described in a separate -document `autofs-mount-control.txt`, and are summarised briefly here. +document `autofs-mount-control.rst`, and are summarised briefly here. Each ioctl is passed a pointer to an `autofs_dev_ioctl` structure:: struct autofs_dev_ioctl { diff --git a/Documentation/filesystems/dlmfs.rst b/Documentation/filesystems/dlmfs.rst index 7e2b1fd471d794..70d4e48242c3ac 100644 --- a/Documentation/filesystems/dlmfs.rst +++ b/Documentation/filesystems/dlmfs.rst @@ -36,7 +36,7 @@ None Usage ===== -If you're just interested in OCFS2, then please see ocfs2.txt. The +If you're just interested in OCFS2, then please see ocfs2.rst. The rest of this document will be geared towards those who want to use dlmfs for easy to setup and easy to use clustered locking in userspace. diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index 68a0885fb5e69e..fb7d2ee022bc06 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -943,3 +943,47 @@ NVMe Zoned Namespace devices can start before the zone-capacity and span across zone-capacity boundary. Such spanning segments are also considered as usable segments. All blocks past the zone-capacity are considered unusable in these segments. + +Device aliasing feature +----------------------- + +f2fs can utilize a special file called a "device aliasing file." This file allows +the entire storage device to be mapped with a single, large extent, not using +the usual f2fs node structures. This mapped area is pinned and primarily intended +for holding the space. + +Essentially, this mechanism allows a portion of the f2fs area to be temporarily +reserved and used by another filesystem or for different purposes. Once that +external usage is complete, the device aliasing file can be deleted, releasing +the reserved space back to F2FS for its own use. + + + +# ls /dev/vd* +/dev/vdb (32GB) /dev/vdc (32GB) +# mkfs.ext4 /dev/vdc +# mkfs.f2fs -c /dev/vdc@vdc.file /dev/vdb +# mount /dev/vdb /mnt/f2fs +# ls -l /mnt/f2fs +vdc.file +# df -h +/dev/vdb 64G 33G 32G 52% /mnt/f2fs + +# mount -o loop /dev/vdc /mnt/ext4 +# df -h +/dev/vdb 64G 33G 32G 52% /mnt/f2fs +/dev/loop7 32G 24K 30G 1% /mnt/ext4 +# umount /mnt/ext4 + +# f2fs_io getflags /mnt/f2fs/vdc.file +get a flag on /mnt/f2fs/vdc.file ret=0, flags=nocow(pinned),immutable +# f2fs_io setflags noimmutable /mnt/f2fs/vdc.file +get a flag on noimmutable ret=0, flags=800010 +set a flag on /mnt/f2fs/vdc.file ret=0, flags=noimmutable +# rm /mnt/f2fs/vdc.file +# df -h +/dev/vdb 64G 753M 64G 2% /mnt/f2fs + +So, the key idea is, user can do any file operations on /dev/vdc, and +reclaim the space after the use, while the space is counted as /data. +That doesn't require modifying partition size and filesystem format. diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst index 0e2fac7a16da1a..76e53821786895 100644 --- a/Documentation/filesystems/fsverity.rst +++ b/Documentation/filesystems/fsverity.rst @@ -16,7 +16,7 @@ btrfs filesystems. Like fscrypt, not too much filesystem-specific code is needed to support fs-verity. fs-verity is similar to `dm-verity -`_ +`_ but works on files rather than block devices. On regular files on filesystems supporting fs-verity, userspace can execute an ioctl that causes the filesystem to build a Merkle tree for the file and persist diff --git a/Documentation/filesystems/index.rst b/Documentation/filesystems/index.rst index e8e496d23e1dd5..44e9e77ffe0d4b 100644 --- a/Documentation/filesystems/index.rst +++ b/Documentation/filesystems/index.rst @@ -29,6 +29,7 @@ algorithms work. fiemap files locks + multigrain-ts mount_api quota seq_file diff --git a/Documentation/filesystems/iomap/operations.rst b/Documentation/filesystems/iomap/operations.rst index b93115ab8748ae..ef082e5a4e0cf9 100644 --- a/Documentation/filesystems/iomap/operations.rst +++ b/Documentation/filesystems/iomap/operations.rst @@ -513,6 +513,21 @@ IOMAP_WRITE`` with any combination of the following enhancements: if the mapping is unwritten and the filesystem cannot handle zeroing the unaligned regions without exposing stale contents. + * ``IOMAP_ATOMIC``: This write is being issued with torn-write + protection. + Only a single bio can be created for the write, and the write must + not be split into multiple I/O requests, i.e. flag REQ_ATOMIC must be + set. + The file range to write must be aligned to satisfy the requirements + of both the filesystem and the underlying block device's atomic + commit capabilities. + If filesystem metadata updates are required (e.g. unwritten extent + conversion or copy on write), all updates for the entire file range + must be committed atomically as well. + Only one space mapping is allowed per untorn write. + Untorn writes must be aligned to, and must not be longer than, a + single file block. + Callers commonly hold ``i_rwsem`` in shared or exclusive mode before calling this function. diff --git a/Documentation/filesystems/mount_api.rst b/Documentation/filesystems/mount_api.rst index 317934c9e8fcac..d92c276f1575af 100644 --- a/Documentation/filesystems/mount_api.rst +++ b/Documentation/filesystems/mount_api.rst @@ -770,7 +770,8 @@ process the parameters it is given. * :: - bool fs_validate_description(const struct fs_parameter_description *desc); + bool fs_validate_description(const char *name, + const struct fs_parameter_description *desc); This performs some validation checks on a parameter description. It returns true if the description is good and false if it is not. It will diff --git a/Documentation/filesystems/multigrain-ts.rst b/Documentation/filesystems/multigrain-ts.rst new file mode 100644 index 00000000000000..c779e47284e80f --- /dev/null +++ b/Documentation/filesystems/multigrain-ts.rst @@ -0,0 +1,125 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================== +Multigrain Timestamps +===================== + +Introduction +============ +Historically, the kernel has always used coarse time values to stamp inodes. +This value is updated every jiffy, so any change that happens within that jiffy +will end up with the same timestamp. + +When the kernel goes to stamp an inode (due to a read or write), it first gets +the current time and then compares it to the existing timestamp(s) to see +whether anything will change. If nothing changed, then it can avoid updating +the inode's metadata. + +Coarse timestamps are therefore good from a performance standpoint, since they +reduce the need for metadata updates, but bad from the standpoint of +determining whether anything has changed, since a lot of things can happen in a +jiffy. + +They are particularly troublesome with NFSv3, where unchanging timestamps can +make it difficult to tell whether to invalidate caches. NFSv4 provides a +dedicated change attribute that should always show a visible change, but not +all filesystems implement this properly, causing the NFS server to substitute +the ctime in many cases. + +Multigrain timestamps aim to remedy this by selectively using fine-grained +timestamps when a file has had its timestamps queried recently, and the current +coarse-grained time does not cause a change. + +Inode Timestamps +================ +There are currently 3 timestamps in the inode that are updated to the current +wallclock time on different activity: + +ctime: + The inode change time. This is stamped with the current time whenever + the inode's metadata is changed. Note that this value is not settable + from userland. + +mtime: + The inode modification time. This is stamped with the current time + any time a file's contents change. + +atime: + The inode access time. This is stamped whenever an inode's contents are + read. Widely considered to be a terrible mistake. Usually avoided with + options like noatime or relatime. + +Updating the mtime always implies a change to the ctime, but updating the +atime due to a read request does not. + +Multigrain timestamps are only tracked for the ctime and the mtime. atimes are +not affected and always use the coarse-grained value (subject to the floor). + +Inode Timestamp Ordering +======================== + +In addition to just providing info about changes to individual files, file +timestamps also serve an important purpose in applications like "make". These +programs measure timestamps in order to determine whether source files might be +newer than cached objects. + +Userland applications like make can only determine ordering based on +operational boundaries. For a syscall those are the syscall entry and exit +points. For io_uring or nfsd operations, that's the request submission and +response. In the case of concurrent operations, userland can make no +determination about the order in which things will occur. + +For instance, if a single thread modifies one file, and then another file in +sequence, the second file must show an equal or later mtime than the first. The +same is true if two threads are issuing similar operations that do not overlap +in time. + +If however, two threads have racing syscalls that overlap in time, then there +is no such guarantee, and the second file may appear to have been modified +before, after or at the same time as the first, regardless of which one was +submitted first. + +Note that the above assumes that the system doesn't experience a backward jump +of the realtime clock. If that occurs at an inopportune time, then timestamps +can appear to go backward, even on a properly functioning system. + +Multigrain Timestamp Implementation +=================================== +Multigrain timestamps are aimed at ensuring that changes to a single file are +always recognizable, without violating the ordering guarantees when multiple +different files are modified. This affects the mtime and the ctime, but the +atime will always use coarse-grained timestamps. + +It uses an unused bit in the i_ctime_nsec field to indicate whether the mtime +or ctime has been queried. If either or both have, then the kernel takes +special care to ensure the next timestamp update will display a visible change. +This ensures tight cache coherency for use-cases like NFS, without sacrificing +the benefits of reduced metadata updates when files aren't being watched. + +The Ctime Floor Value +===================== +It's not sufficient to simply use fine or coarse-grained timestamps based on +whether the mtime or ctime has been queried. A file could get a fine grained +timestamp, and then a second file modified later could get a coarse-grained one +that appears earlier than the first, which would break the kernel's timestamp +ordering guarantees. + +To mitigate this problem, maintain a global floor value that ensures that +this can't happen. The two files in the above example may appear to have been +modified at the same time in such a case, but they will never show the reverse +order. To avoid problems with realtime clock jumps, the floor is managed as a +monotonic ktime_t, and the values are converted to realtime clock values as +needed. + +Implementation Notes +==================== +Multigrain timestamps are intended for use by local filesystems that get +ctime values from the local clock. This is in contrast to network filesystems +and the like that just mirror timestamp values from a server. + +For most filesystems, it's sufficient to just set the FS_MGTIME flag in the +fstype->fs_flags in order to opt-in, providing the ctime is only ever set via +inode_set_ctime_current(). If the filesystem has a ->getattr routine that +doesn't call generic_fillattr, then it should call fill_mg_cmtime() to +fill those values. For setattr, it should use setattr_copy() to update the +timestamps, or otherwise mimic its behavior. diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst index f04ce1215a03e7..de64d2d002a204 100644 --- a/Documentation/filesystems/nfs/exporting.rst +++ b/Documentation/filesystems/nfs/exporting.rst @@ -238,10 +238,3 @@ following flags are defined: all of an inode's dirty data on last close. Exports that behave this way should set EXPORT_OP_FLUSH_ON_CLOSE so that NFSD knows to skip waiting for writeback when closing such files. - - EXPORT_OP_ASYNC_LOCK - Indicates a capable filesystem to do async lock - requests from lockd. Only set EXPORT_OP_ASYNC_LOCK if the filesystem has - it's own ->lock() functionality as core posix_lock_file() implementation - has no async lock request handling yet. For more information about how to - indicate an async lock request from a ->lock() file_operations struct, see - fs/locks.c and comment for the function vfs_lock_file(). diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index 34364471234097..4c8387e1c88068 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -440,6 +440,23 @@ For example:: fsconfig(fs_fd, FSCONFIG_SET_STRING, "datadir+", "/do2", 0); +Specifying layers via file descriptors +-------------------------------------- + +Since kernel v6.13, overlayfs supports specifying layers via file descriptors in +addition to specifying them as paths. This feature is available for the +"datadir+", "lowerdir+", "upperdir", and "workdir+" mount options with the +fsconfig syscall from the new mount api:: + + fsconfig(fs_fd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower1); + fsconfig(fs_fd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower2); + fsconfig(fs_fd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower3); + fsconfig(fs_fd, FSCONFIG_SET_FD, "datadir+", NULL, fd_data1); + fsconfig(fs_fd, FSCONFIG_SET_FD, "datadir+", NULL, fd_data2); + fsconfig(fs_fd, FSCONFIG_SET_FD, "workdir", NULL, fd_work); + fsconfig(fs_fd, FSCONFIG_SET_FD, "upperdir", NULL, fd_upper); + + fs-verity support ----------------- diff --git a/Documentation/filesystems/path-lookup.rst b/Documentation/filesystems/path-lookup.rst index 2b2df6aa54324b..9ced1135608ea4 100644 --- a/Documentation/filesystems/path-lookup.rst +++ b/Documentation/filesystems/path-lookup.rst @@ -531,7 +531,7 @@ this retry process in the next article. Automount points are locations in the filesystem where an attempt to lookup a name can trigger changes to how that lookup should be handled, in particular by mounting a filesystem there. These are -covered in greater detail in autofs.txt in the Linux documentation +covered in greater detail in autofs.rst in the Linux documentation tree, but a few notes specifically related to path lookup are in order here. diff --git a/Documentation/filesystems/path-lookup.txt b/Documentation/filesystems/path-lookup.txt index 1aa7ce099f6f54..d2cf2852e1f8cf 100644 --- a/Documentation/filesystems/path-lookup.txt +++ b/Documentation/filesystems/path-lookup.txt @@ -379,4 +379,4 @@ Papers and other documentation on dcache locking 2. http://lse.sourceforge.net/locking/dcache/dcache.html -3. path-lookup.md in this directory. +3. path-lookup.rst in this directory. diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 92bffcc6747ae9..9ab2a3d6f2b47b 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -177,7 +177,7 @@ settles down a bit. **mandatory** s_export_op is now required for exporting a filesystem. -isofs, ext2, ext3, reiserfs, fat +isofs, ext2, ext3, fat can be used as examples of very different filesystems. --- diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index e834779d961153..6a882c57a7e736 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -579,7 +579,7 @@ encoded manner. The codes are the following: mt arm64 MTE allocation tags are enabled um userfaultfd missing tracking uw userfaultfd wr-protect tracking - ss shadow stack page + ss shadow/guarded control stack page sl sealed == ======================================= diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.rst b/Documentation/filesystems/ramfs-rootfs-initramfs.rst index 447f767c646276..fa4f81099cb448 100644 --- a/Documentation/filesystems/ramfs-rootfs-initramfs.rst +++ b/Documentation/filesystems/ramfs-rootfs-initramfs.rst @@ -315,7 +315,7 @@ the above threads) is: 2) The cpio archive format chosen by the kernel is simpler and cleaner (and thus easier to create and parse) than any of the (literally dozens of) various tar archive formats. The complete initramfs archive format is - explained in buffer-format.txt, created in usr/gen_init_cpio.c, and + explained in buffer-format.rst, created in usr/gen_init_cpio.c, and extracted in init/initramfs.c. All three together come to less than 26k total of human-readable text. diff --git a/Documentation/filesystems/tmpfs.rst b/Documentation/filesystems/tmpfs.rst index 56a26c843dbe96..d677e0428c3f68 100644 --- a/Documentation/filesystems/tmpfs.rst +++ b/Documentation/filesystems/tmpfs.rst @@ -241,6 +241,28 @@ So 'mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs' will give you tmpfs instance on /mytmpfs which can allocate 10GB RAM/SWAP in 10240 inodes and it is only accessible by root. +tmpfs has the following mounting options for case-insensitive lookup support: + +================= ============================================================== +casefold Enable casefold support at this mount point using the given + argument as the encoding standard. Currently only UTF-8 + encodings are supported. If no argument is used, it will load + the latest UTF-8 encoding available. +strict_encoding Enable strict encoding at this mount point (disabled by + default). In this mode, the filesystem refuses to create file + and directory with names containing invalid UTF-8 characters. +================= ============================================================== + +This option doesn't render the entire filesystem case-insensitive. One needs to +still set the casefold flag per directory, by flipping the +F attribute in an +empty directory. Nevertheless, new directories will inherit the attribute. The +mountpoint itself cannot be made case-insensitive. + +Example:: + + $ mount -t tmpfs -o casefold=utf8-12.1.0,strict_encoding fs_name /mytmpfs + $ mount -t tmpfs -o casefold fs_name /mytmpfs + :Author: Christoph Rohland , 1.12.01 @@ -250,3 +272,5 @@ RAM/SWAP in 10240 inodes and it is only accessible by root. KOSAKI Motohiro, 16 Mar 2010 :Updated: Chris Down, 13 July 2020 +:Updated: + André Almeida, 23 Aug 2024 diff --git a/Documentation/gpu/amdgpu/display/dc-arch-overview.svg b/Documentation/gpu/amdgpu/display/dc-arch-overview.svg new file mode 100644 index 00000000000000..23394931cf26e1 --- /dev/null +++ b/Documentation/gpu/amdgpu/display/dc-arch-overview.svg @@ -0,0 +1,731 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + Board/Platform + SoC + Component + DRAM + + dc_plane + + + + dc_plane + + + + + DC + + + + + dc_link + + + + + dc_link + + + + + + + dc_link + + + + + + + + + + + DCN + SoC + Board/Platform + Display + Connector + Connector + + diff --git a/Documentation/gpu/amdgpu/display/dc-components.svg b/Documentation/gpu/amdgpu/display/dc-components.svg new file mode 100644 index 00000000000000..f84bb2a57c05bb --- /dev/null +++ b/Documentation/gpu/amdgpu/display/dc-components.svg @@ -0,0 +1,732 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + Core + + + + + + + + + + Display Core API (dc/dc.h) + Link + Hardware Sequencer API(dc/inc/hw_sequence.h) + Hardware Sequencer + Block Level API (dc/inc/hw) + + + DCHUB + + + + HUBP + + + + DPP + + + + MPC + + + + ... + + Hardware Registers + DMUBBlock + DMUB Hardware API(dmub/dmub_srv.h) + DMUB Service + DMUB Service API(dc/dc_dmub_srv.h) + + diff --git a/Documentation/gpu/amdgpu/display/dc-debug.rst b/Documentation/gpu/amdgpu/display/dc-debug.rst index 817631b1dbf33b..013f63b271f357 100644 --- a/Documentation/gpu/amdgpu/display/dc-debug.rst +++ b/Documentation/gpu/amdgpu/display/dc-debug.rst @@ -2,6 +2,181 @@ Display Core Debug tools ======================== +In this section, you will find helpful information on debugging the amdgpu +driver from the display perspective. This page introduces debug mechanisms and +procedures to help you identify if some issues are related to display code. + +Narrow down display issues +========================== + +Since the display is the driver's visual component, it is common to see users +reporting issues as a display when another component causes the problem. This +section equips users to determine if a specific issue was caused by the display +component or another part of the driver. + +DC dmesg important messages +--------------------------- + +The dmesg log is the first source of information to be checked, and amdgpu +takes advantage of this feature by logging some valuable information. When +looking for the issues associated with amdgpu, remember that each component of +the driver (e.g., smu, PSP, dm, etc.) is loaded one by one, and this +information can be found in the dmesg log. In this sense, look for the part of +the log that looks like the below log snippet:: + + [ 4.254295] [drm] initializing kernel modesetting (IP DISCOVERY 0x1002:0x744C 0x1002:0x0E3B 0xC8). + [ 4.254718] [drm] register mmio base: 0xFCB00000 + [ 4.254918] [drm] register mmio size: 1048576 + [ 4.260095] [drm] add ip block number 0 + [ 4.260318] [drm] add ip block number 1 + [ 4.260510] [drm] add ip block number 2 + [ 4.260696] [drm] add ip block number 3 + [ 4.260878] [drm] add ip block number 4 + [ 4.261057] [drm] add ip block number 5 + [ 4.261231] [drm] add ip block number 6 + [ 4.261402] [drm] add ip block number 7 + [ 4.261568] [drm] add ip block number 8 + [ 4.261729] [drm] add ip block number 9 + [ 4.261887] [drm] add ip block number 10 + +From the above example, you can see the line that reports that ``, +(**Display Manager**), was loaded, which means that display can be part of the +issue. If you do not see that line, something else might have failed before +amdgpu loads the display component, indicating that we don't have a +display issue. + +After you identified that the DM was loaded correctly, you can check for the +display version of the hardware in use, which can be retrieved from the dmesg +log with the command:: + + dmesg | grep -i 'display core' + +This command shows a message that looks like this:: + + [ 4.655828] [drm] Display Core v3.2.285 initialized on DCN 3.2 + +This message has two key pieces of information: + +* **The DC version (e.g., v3.2.285)**: Display developers release a new DC version + every week, and this information can be advantageous in a situation where a + user/developer must find a good point versus a bad point based on a tested + version of the display code. Remember from page :ref:`Display Core `, + that every week the new patches for display are heavily tested with IGT and + manual tests. +* **The DCN version (e.g., DCN 3.2)**: The DCN block is associated with the + hardware generation, and the DCN version conveys the hardware generation that + the driver is currently running. This information helps to narrow down the + code debug area since each DCN version has its files in the DC folder per DCN + component (from the example, the developer might want to focus on + files/folders/functions/structs with the dcn32 label might be executed). + However, keep in mind that DC reuses code across different DCN versions; for + example, it is expected to have some callbacks set in one DCN that are the same + as those from another DCN. In summary, use the DCN version just as a guide. + +From the dmesg file, it is also possible to get the ATOM bios code by using:: + + dmesg | grep -i 'ATOM BIOS' + +Which generates an output that looks like this:: + + [ 4.274534] amdgpu: ATOM BIOS: 113-D7020100-102 + +This type of information is useful to be reported. + +Avoid loading display core +-------------------------- + +Sometimes, it might be hard to figure out which part of the driver is causing +the issue; if you suspect that the display is not part of the problem and your +bug scenario is simple (e.g., some desktop configuration) you can try to remove +the display component from the equation. First, you need to identify `dm` ID +from the dmesg log; for example, search for the following log:: + + [ 4.254295] [drm] initializing kernel modesetting (IP DISCOVERY 0x1002:0x744C 0x1002:0x0E3B 0xC8). + [..] + [ 4.260095] [drm] add ip block number 0 + [ 4.260318] [drm] add ip block number 1 + [..] + [ 4.261057] [drm] add ip block number 5 + +Notice from the above example that the `dm` id is 5 for this specific hardware. +Next, you need to run the following binary operation to identify the IP block +mask:: + + 0xffffffff & ~(1 << [DM ID]) + +From our example the IP mask is:: + + 0xffffffff & ~(1 << 5) = 0xffffffdf + +Finally, to disable DC, you just need to set the below parameter in your +bootloader:: + + amdgpu.ip_block_mask = 0xffffffdf + +If you can boot your system with the DC disabled and still see the issue, it +means you can rule DC out of the equation. However, if the bug disappears, you +still need to consider the DC part of the problem and keep narrowing down the +issue. In some scenarios, disabling DC is impossible since it might be +necessary to use the display component to reproduce the issue (e.g., play a +game). + +**Note: This will probably lead to the absence of a display output.** + +Display flickering +------------------ + +Display flickering might have multiple causes; one is the lack of proper power +to the GPU or problems in the DPM switches. A good first generic verification +is to set the GPU to use high voltage:: + + bash -c "echo high > /sys/class/drm/card0/device/power_dpm_force_performance_level" + +The above command sets the GPU/APU to use the maximum power allowed which +disables DPM switches. If forcing DPM levels high does not fix the issue, it +is less likely that the issue is related to power management. If the issue +disappears, there is a good chance that other components might be involved, and +the display should not be ignored since this could be a DPM issues. From the +display side, if the power increase fixes the issue, it is worth debugging the +clock configuration and the pipe split police used in the specific +configuration. + +Display artifacts +----------------- + +Users may see some screen artifacts that can be categorized into two different +types: localized artifacts and general artifacts. The localized artifacts +happen in some specific areas, such as around the UI window corners; if you see +this type of issue, there is a considerable chance that you have a userspace +problem, likely Mesa or similar. The general artifacts usually happen on the +entire screen. They might be caused by a misconfiguration at the driver level +of the display parameters, but the userspace might also cause this issue. One +way to identify the source of the problem is to take a screenshot or make a +desktop video capture when the problem happens; after checking the +screenshot/video recording, if you don't see any of the artifacts, it means +that the issue is likely on the the driver side. If you can still see the +problem in the data collected, it is an issue that probably happened during +rendering, and the display code just got the framebuffer already corrupted. + +Disabling/Enabling specific features +==================================== + +DC has a struct named `dc_debug_options`, which is statically initialized by +all DCE/DCN components based on the specific hardware characteristic. This +structure usually facilitates the bring-up phase since developers can start +with many disabled features and enable them individually. This is also an +important debug feature since users can change it when debugging specific +issues. + +For example, dGPU users sometimes see a problem where a horizontal fillet of +flickering happens in some specific part of the screen. This could be an +indication of Sub-Viewport issues; after the users identified the target DCN, +they can set the `force_disable_subvp` field to true in the statically +initialized version of `dc_debug_options` to see if the issue gets fixed. Along +the same lines, users/developers can also try to turn off `fams2_config` and +`enable_single_display_2to1_odm_policy`. In summary, the `dc_debug_options` is +an interesting form for identifying the problem. + DC Visual Confirmation ====================== @@ -76,6 +251,18 @@ change in real-time by using something like:: When reporting a bug related to DC, consider attaching this log before and after you reproduce the bug. +Collect Firmware information +============================ + +When reporting issues, it is important to have the firmware information since +it can be helpful for debugging purposes. To get all the firmware information, +use the command:: + + cat /sys/kernel/debug/dri/0/amdgpu_firmware_info + +From the display perspective, pay attention to the firmware of the DMCU and +DMCUB. + DMUB Firmware Debug =================== diff --git a/Documentation/gpu/amdgpu/display/dcn-blocks.rst b/Documentation/gpu/amdgpu/display/dcn-blocks.rst index 5e34366f6dbe4d..756957128dad4d 100644 --- a/Documentation/gpu/amdgpu/display/dcn-blocks.rst +++ b/Documentation/gpu/amdgpu/display/dcn-blocks.rst @@ -1,3 +1,5 @@ +.. _dcn_blocks: + ========== DCN Blocks ========== diff --git a/Documentation/gpu/amdgpu/display/dcn-overview.rst b/Documentation/gpu/amdgpu/display/dcn-overview.rst index 9fea6500448b6f..eb54a6802e0442 100644 --- a/Documentation/gpu/amdgpu/display/dcn-overview.rst +++ b/Documentation/gpu/amdgpu/display/dcn-overview.rst @@ -1,3 +1,5 @@ +.. _dcn_overview: + ======================= Display Core Next (DCN) ======================= diff --git a/Documentation/gpu/amdgpu/display/index.rst b/Documentation/gpu/amdgpu/display/index.rst index f0c342e00a392b..bd2d797c123e66 100644 --- a/Documentation/gpu/amdgpu/display/index.rst +++ b/Documentation/gpu/amdgpu/display/index.rst @@ -90,6 +90,7 @@ table of content: display-manager.rst dcn-overview.rst dcn-blocks.rst + programming-model-dcn.rst mpo-overview.rst dc-debug.rst display-contributing.rst diff --git a/Documentation/gpu/amdgpu/display/programming-model-dcn.rst b/Documentation/gpu/amdgpu/display/programming-model-dcn.rst new file mode 100644 index 00000000000000..c1b48d49fb0bab --- /dev/null +++ b/Documentation/gpu/amdgpu/display/programming-model-dcn.rst @@ -0,0 +1,162 @@ +==================== +DC Programming Model +==================== + +In the :ref:`Display Core Next (DCN) ` and :ref:`DCN Block +` pages, you learned about the hardware components and how they +interact with each other. On this page, the focus is shifted to the display +code architecture. Hence, it is reasonable to remind the reader that the code +in DC is shared with other OSes; for this reason, DC provides a set of +abstractions and operations to connect different APIs with the hardware +configuration. See DC as a service available for a Display Manager (amdgpu_dm) +to access and configure DCN/DCE hardware (DCE is also part of DC, but for +simplicity's sake, this documentation only examines DCN). + +.. note:: + For this page, we will use the term GPU to refers to dGPU and APU. + +Overview +======== + +From the display hardware perspective, it is plausible to expect that if a +problem is well-defined, it will probably be implemented at the hardware level. +On the other hand, when there are multiple ways of achieving something without +a very well-defined scope, the solution is usually implemented as a policy at +the DC level. In other words, some policies are defined in the DC core +(resource management, power optimization, image quality, etc.), and the others +implemented in hardware are enabled via DC configuration. + +In terms of hardware management, DCN has multiple instances of the same block +(e.g., HUBP, DPP, MPC, etc), and during the driver execution, it might be +necessary to use some of these instances. The core has policies in place for +handling those instances. Regarding resource management, the DC objective is +quite simple: minimize the hardware shuffle when the driver performs some +actions. When the state changes from A to B, the transition is considered +easier to maneuver if the hardware resource is still used for the same set of +driver objects. Usually, adding and removing a resource to a `pipe_ctx` (more +details below) is not a problem; however, moving a resource from one `pipe_ctx` +to another should be avoided. + +Another area of influence for DC is power optimization, which has a myriad of +arrangement possibilities. In some way, just displaying an image via DCN should +be relatively straightforward; however, showing it with the best power +footprint is more desirable, but it has many associated challenges. +Unfortunately, there is no straight-forward analytic way to determine if a +configuration is the best one for the context due to the enormous variety of +variables related to this problem (e.g., many different DCN/DCE hardware +versions, different displays configurations, etc.) for this reason DC +implements a dedicated library for trying some configuration and verify if it +is possible to support it or not. This type of policy is extremely complex to +create and maintain, and amdgpu driver relies on Display Mode Library (DML) to +generate the best decisions. + +In summary, DC must deal with the complexity of handling multiple scenarios and +determine policies to manage them. All of the above information is conveyed to +give the reader some idea about the complexity of driving a display from the +driver's perspective. This page hopes to allow the reader to better navigate +over the amdgpu display code. + +Display Driver Architecture Overview +==================================== + +The diagram below provides an overview of the display driver architecture; +notice it illustrates the software layers adopted by DC: + +.. kernel-figure:: dc-components.svg + +The first layer of the diagram is the high-level DC API represented by the +`dc.h` file; below it are two big blocks represented by Core and Link. Next is +the hardware configuration block; the main file describing it is +the`hw_sequencer.h`, where the implementation of the callbacks can be found in +the hardware sequencer folder. Almost at the end, you can see the block level +API (`dc/inc/hw`), which represents each DCN low-level block, such as HUBP, +DPP, MPC, OPTC, etc. Notice on the left side of the diagram that we have a +different set of layers representing the interaction with the DMUB +microcontroller. + +Basic Objects +------------- + +The below diagram outlines the basic display objects. In particular, pay +attention to the names in the boxes since they represent a data structure in +the driver: + +.. kernel-figure:: dc-arch-overview.svg + +Let's start with the central block in the image, `dc`. The `dc` struct is +initialized per GPU; for example, one GPU has one `dc` instance, two GPUs have +two `dc` instances, and so forth. In other words we have one 'dc' per 'amdgpu' +instance. In some ways, this object behaves like the `Singleton` pattern. + +After the `dc` block in the diagram, you can see the `dc_link` component, which +is a low-level abstraction for the connector. One interesting aspect of the +image is that connectors are not part of the DCN block; they are defined by the +platform/board and not by the SoC. The `dc_link` struct is the high-level data +container with information such as connected sinks, connection status, signal +types, etc. After `dc_link`, there is the `dc_sink`, which is the object that +represents the connected display. + +.. note:: + For historical reasons, we used the name `dc_link`, which gives the + wrong impression that this abstraction only deals with physical connections + that the developer can easily manipulate. However, this also covers + conections like eDP or cases where the output is connected to other devices. + +There are two structs that are not represented in the diagram since they were +elaborated in the DCN overview page (check the DCN block diagram :ref:`Display +Core Next (DCN) `); still, it is worth bringing back for this +overview which is `dc_stream` and `dc_state`. The `dc_stream` stores many +properties associated with the data transmission, but most importantly, it +represents the data flow from the connector to the display. Next we have +`dc_state`, which represents the logic state within the hardware at the moment; +`dc_state` is composed of `dc_stream` and `dc_plane`. The `dc_stream` is the DC +version of `drm_crtc` and represents the post-blending pipeline. + +Speaking of the `dc_plane` data structure (first part of the diagram), you can +think about it as an abstraction similar to `drm_plane` that represents the +pre-blending portion of the pipeline. This image was probably processed by GFX +and is ready to be composited under a `dc_stream`. Normally, the driver may +have one or more `dc_plane` connected to the same `dc_stream`, which defines a +composition at the DC level. + +Basic Operations +---------------- + +Now that we have covered the basic objects, it is time to examine some of the +basic hardware/software operations. Let's start with the `dc_create()` +function, which directly works with the `dc` data struct; this function behaves +like a constructor responsible for the basic software initialization and +preparing for enabling other parts of the API. It is important to highlight +that this operation does not touch any hardware configuration; it is only a +software initialization. + +Next, we have the `dc_hardware_init()`, which also relies on the `dc` data +struct. Its main function is to put the hardware in a valid state. It is worth +highlighting that the hardware might initialize in an unknown state, and it is +a requirement to put it in a valid state; this function has multiple callbacks +for the hardware-specific initialization, whereas `dc_hardware_init` does the +hardware initialization and is the first point where we touch hardware. + +The `dc_get_link_at_index` is an operation that depends on the `dc_link` data +structure. This function retrieves and enumerates all the `dc_links` available +on the device; this is required since this information is not part of the SoC +definition but depends on the board configuration. As soon as the `dc_link` is +initialized, it is useful to figure out if any of them are already connected to +the display by using the `dc_link_detect()` function. After the driver figures +out if any display is connected to the device, the challenging phase starts: +configuring the monitor to show something. Nonetheless, dealing with the ideal +configuration is not a DC task since this is the Display Manager (`amdgpu_dm`) +responsibility which in turn is responsible for dealing with the atomic +commits. The only interface DC provides to the configuration phase is the +function `dc_validate_with_context` that receives the configuration information +and, based on that, validates whether the hardware can support it or not. It is +important to add that even if the display supports some specific configuration, +it does not mean the DCN hardware can support it. + +After the DM and DC agree upon the configuration, the stream configuration +phase starts. This task activates one or more `dc_stream` at this phase, and in +the best-case scenario, you might be able to turn the display on with a black +screen (it does not show anything yet since it does not have any plane +associated with it). The final step would be to call the +`dc_update_planes_and_stream,` which will add or remove planes. + diff --git a/Documentation/gpu/amdgpu/index.rst b/Documentation/gpu/amdgpu/index.rst index 847e04924030cf..302d039928ee83 100644 --- a/Documentation/gpu/amdgpu/index.rst +++ b/Documentation/gpu/amdgpu/index.rst @@ -16,4 +16,5 @@ Next (GCN), Radeon DNA (RDNA), and Compute DNA (CDNA) architectures. thermal driver-misc debugging + process-isolation amdgpu-glossary diff --git a/Documentation/gpu/amdgpu/process-isolation.rst b/Documentation/gpu/amdgpu/process-isolation.rst new file mode 100644 index 00000000000000..6b6d70e357a759 --- /dev/null +++ b/Documentation/gpu/amdgpu/process-isolation.rst @@ -0,0 +1,59 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========================= + AMDGPU Process Isolation +========================= + +The AMDGPU driver includes a feature that enables automatic process isolation on the graphics engine. This feature serializes access to the graphics engine and adds a cleaner shader which clears the Local Data Store (LDS) and General Purpose Registers (GPRs) between jobs. All processes using the GPU, including both graphics and compute workloads, are serialized when this feature is enabled. On GPUs that support partitionable graphics engines, this feature can be enabled on a per-partition basis. + +In addition, there is an interface to manually run the cleaner shader when the use of the GPU is complete. This may be preferable in some use cases, such as a single-user system where the login manager triggers the cleaner shader when the user logs out. + +Process Isolation +================= + +The `run_cleaner_shader` and `enforce_isolation` sysfs interfaces allow users to manually execute the cleaner shader and control the process isolation feature, respectively. + +Partition Handling +------------------ + +The `enforce_isolation` file in sysfs can be used to enable process isolation and automatic shader cleanup between processes. On GPUs that support graphics engine partitioning, this can be enabled per partition. The partition and its current setting (0 disabled, 1 enabled) can be read from sysfs. On GPUs that do not support graphics engine partitioning, only a single partition will be present. Writing 1 to the partition position enables enforce isolation, writing 0 disables it. + +Example of enabling enforce isolation on a GPU with multiple partitions: + +.. code-block:: console + + $ echo 1 0 1 0 > /sys/class/drm/card0/device/enforce_isolation + $ cat /sys/class/drm/card0/device/enforce_isolation + 1 0 1 0 + +The output indicates that enforce isolation is enabled on zeroth and second parition and disabled on first and fourth parition. + +For devices with a single partition or those that do not support partitions, there will be only one element: + +.. code-block:: console + + $ echo 1 > /sys/class/drm/card0/device/enforce_isolation + $ cat /sys/class/drm/card0/device/enforce_isolation + 1 + +Cleaner Shader Execution +======================== + +The driver can trigger a cleaner shader to clean up the LDS and GPR state on the graphics engine. When process isolation is enabled, this happens automatically between processes. In addition, there is a sysfs file to manually trigger cleaner shader execution. + +To manually trigger the execution of the cleaner shader, write `0` to the `run_cleaner_shader` sysfs file: + +.. code-block:: console + + $ echo 0 > /sys/class/drm/card0/device/run_cleaner_shader + +For multi-partition devices, you can specify the partition index when triggering the cleaner shader: + +.. code-block:: console + + $ echo 0 > /sys/class/drm/card0/device/run_cleaner_shader # For partition 0 + $ echo 1 > /sys/class/drm/card0/device/run_cleaner_shader # For partition 1 + $ echo 2 > /sys/class/drm/card0/device/run_cleaner_shader # For partition 2 + # ... and so on for each partition + +This command initiates the cleaner shader, which will run and complete before any new tasks are scheduled on the GPU. diff --git a/Documentation/gpu/amdgpu/thermal.rst b/Documentation/gpu/amdgpu/thermal.rst index 6d942b5c58f054..1768a106aab169 100644 --- a/Documentation/gpu/amdgpu/thermal.rst +++ b/Documentation/gpu/amdgpu/thermal.rst @@ -100,6 +100,18 @@ fan_minimum_pwm .. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c :doc: fan_minimum_pwm +fan_zero_rpm_enable +---------------------- + +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c + :doc: fan_zero_rpm_enable + +fan_zero_rpm_stop_temperature +----------------------------- + +.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c + :doc: fan_zero_rpm_stop_temperature + GFXOFF ====== diff --git a/Documentation/gpu/automated_testing.rst b/Documentation/gpu/automated_testing.rst index 2d5a28866afe7e..6d7c6086034d33 100644 --- a/Documentation/gpu/automated_testing.rst +++ b/Documentation/gpu/automated_testing.rst @@ -68,19 +68,25 @@ known to behave unreliably. These tests won't cause a job to fail regardless of the result. They will still be run. Each new flake entry must be associated with a link to the email reporting the -bug to the author of the affected driver, the board name or Device Tree name of -the board, the first kernel version affected, the IGT version used for tests, -and an approximation of the failure rate. +bug to the author of the affected driver or the relevant GitLab issue. The entry +must also include the board name or Device Tree name, the first kernel version +affected, the IGT version used for tests, and an approximation of the failure rate. They should be provided under the following format:: - # Bug Report: $LORE_OR_PATCHWORK_URL + # Bug Report: $LORE_URL_OR_GITLAB_ISSUE # Board Name: broken-board.dtb # Linux Version: 6.6-rc1 # IGT Version: 1.28-gd2af13d9f # Failure Rate: 100 flaky-test +Use the appropriate link below to create a GitLab issue: +amdgpu driver: https://gitlab.freedesktop.org/drm/amd/-/issues +i915 driver: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues +msm driver: https://gitlab.freedesktop.org/drm/msm/-/issues +xe driver: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues + drivers/gpu/drm/ci/${DRIVER_NAME}-${HW_REVISION}-skips.txt ----------------------------------------------------------- diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst index b899cbc5c2b488..1f17ad0790d755 100644 --- a/Documentation/gpu/drivers.rst +++ b/Documentation/gpu/drivers.rst @@ -22,6 +22,8 @@ GPU Driver Documentation afbc komeda-kms panfrost + panthor + zynqmp .. only:: subproject and html diff --git a/Documentation/gpu/drm-client.rst b/Documentation/gpu/drm-client.rst index 58b5a1d1219d11..cbcfe30de777fb 100644 --- a/Documentation/gpu/drm-client.rst +++ b/Documentation/gpu/drm-client.rst @@ -13,3 +13,6 @@ Kernel clients .. kernel-doc:: drivers/gpu/drm/drm_client_modeset.c :export: + +.. kernel-doc:: drivers/gpu/drm/drm_client_event.c + :export: diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 11d9a5730fb22f..cb9ae282771c8a 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -75,18 +75,6 @@ Module Initialization .. kernel-doc:: include/drm/drm_module.h :doc: overview -Managing Ownership of the Framebuffer Aperture ----------------------------------------------- - -.. kernel-doc:: drivers/gpu/drm/drm_aperture.c - :doc: overview - -.. kernel-doc:: include/drm/drm_aperture.h - :internal: - -.. kernel-doc:: drivers/gpu/drm/drm_aperture.c - :export: - Device Instance and Driver Handling ----------------------------------- diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index c3e58856f75b36..8cf2f041af4704 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -110,15 +110,6 @@ fbdev Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_fb_helper.c :doc: fbdev helpers -.. kernel-doc:: drivers/gpu/drm/drm_fbdev_dma.c - :export: - -.. kernel-doc:: drivers/gpu/drm/drm_fbdev_shmem.c - :export: - -.. kernel-doc:: drivers/gpu/drm/drm_fbdev_ttm.c - :export: - .. kernel-doc:: include/drm/drm_fb_helper.h :internal: diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index 370d820be24819..b75cc9a70d1f98 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -305,13 +305,26 @@ Kernel Mode Driver ------------------ The KMD is responsible for checking if the device needs a reset, and to perform -it as needed. Usually a hang is detected when a job gets stuck executing. KMD -should keep track of resets, because userspace can query any time about the -reset status for a specific context. This is needed to propagate to the rest of -the stack that a reset has happened. Currently, this is implemented by each -driver separately, with no common DRM interface. Ideally this should be properly -integrated at DRM scheduler to provide a common ground for all drivers. After a -reset, KMD should reject new command submissions for affected contexts. +it as needed. Usually a hang is detected when a job gets stuck executing. + +Propagation of errors to userspace has proven to be tricky since it goes in +the opposite direction of the usual flow of commands. Because of this vendor +independent error handling was added to the &dma_fence object, this way drivers +can add an error code to their fences before signaling them. See function +dma_fence_set_error() on how to do this and for examples of error codes to use. + +The DRM scheduler also allows setting error codes on all pending fences when +hardware submissions are restarted after an reset. Error codes are also +forwarded from the hardware fence to the scheduler fence to bubble up errors +to the higher levels of the stack and eventually userspace. + +Fence errors can be queried by userspace through the generic SYNC_IOC_FILE_INFO +IOCTL as well as through driver specific interfaces. + +Additional to setting fence errors drivers should also keep track of resets per +context, the DRM scheduler provides the drm_sched_entity_error() function as +helper for this use case. After a reset, KMD should reject new command +submissions for affected contexts. User Mode Driver ---------------- diff --git a/Documentation/gpu/drm-usage-stats.rst b/Documentation/gpu/drm-usage-stats.rst index a80f95ca1b2f49..2717cb2a597e1c 100644 --- a/Documentation/gpu/drm-usage-stats.rst +++ b/Documentation/gpu/drm-usage-stats.rst @@ -73,6 +73,11 @@ scope of each device, in which case `drm-pdev` shall be present as well. Userspace should make sure to not double account any usage statistics by using the above described criteria in order to associate data to individual clients. +- drm-client-name: + +String optionally set by userspace using DRM_IOCTL_SET_CLIENT_NAME. + + Utilization ^^^^^^^^^^^ @@ -144,7 +149,9 @@ Memory Each possible memory type which can be used to store buffer objects by the GPU in question shall be given a stable and unique name to be returned as the -string here. The name "memory" is reserved to refer to normal system memory. +string here. + +The region name "memory" is reserved to refer to normal system memory. Value shall reflect the amount of storage currently consumed by the buffer objects belong to this client, in the respective memory region. @@ -152,6 +159,9 @@ objects belong to this client, in the respective memory region. Default unit shall be bytes with optional unit specifiers of 'KiB' or 'MiB' indicating kibi- or mebi-bytes. +This key is deprecated and is an alias for drm-resident-. Only one of +the two should be present in the output. + - drm-shared-: [KiB|MiB] The total size of buffers that are shared with another file (e.g., have more @@ -159,20 +169,34 @@ than a single handle). - drm-total-: [KiB|MiB] -The total size of buffers that including shared and private memory. +The total size of all created buffers including shared and private memory. The +backing store for the buffers does not have to be currently instantiated to be +counted under this category. - drm-resident-: [KiB|MiB] -The total size of buffers that are resident in the specified region. +The total size of buffers that are resident (have their backing store present or +instantiated) in the specified region. + +This is an alias for drm-memory- and only one of the two should be +present in the output. - drm-purgeable-: [KiB|MiB] The total size of buffers that are purgeable. +For example drivers which implement a form of 'madvise' like functionality can +here count buffers which have instantiated backing store, but have been marked +with an equivalent of MADV_DONTNEED. + - drm-active-: [KiB|MiB] The total size of buffers that are active on one or more engines. +One practical example of this can be presence of unsignaled fences in an GEM +buffer reservation object. Therefore the active category is a subset of +resident. + Implementation Details ====================== @@ -186,4 +210,5 @@ Driver specific implementations * :ref:`i915-usage-stats` * :ref:`panfrost-usage-stats` +* :ref:`panthor-usage-stats` * :ref:`xe-usage-stats` diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst index ad59ae579237a3..7a469df675d82b 100644 --- a/Documentation/gpu/i915.rst +++ b/Documentation/gpu/i915.rst @@ -35,10 +35,10 @@ Interrupt Handling :functions: intel_irq_init intel_irq_init_hw intel_hpd_init .. kernel-doc:: drivers/gpu/drm/i915/i915_irq.c - :functions: intel_runtime_pm_disable_interrupts + :functions: intel_irq_suspend .. kernel-doc:: drivers/gpu/drm/i915/i915_irq.c - :functions: intel_runtime_pm_enable_interrupts + :functions: intel_irq_resume Intel GVT-g Guest Support(vGPU) ------------------------------- diff --git a/Documentation/gpu/msm-preemption.rst b/Documentation/gpu/msm-preemption.rst new file mode 100644 index 00000000000000..d768ca09fdecc1 --- /dev/null +++ b/Documentation/gpu/msm-preemption.rst @@ -0,0 +1,99 @@ +.. SPDX-License-Identifier: GPL-2.0 + +:orphan: + +============== +MSM Preemption +============== + +Preemption allows Adreno GPUs to switch to a higher priority ring when work is +pushed to it, reducing latency for high priority submissions. + +When preemption is enabled 4 rings are initialized, corresponding to different +priority levels. Having multiple rings is purely a software concept as the GPU +only has registers to keep track of one graphics ring. +The kernel is able to switch which ring is currently being processed by +requesting preemption. When certain conditions are met, depending on the +priority level, the GPU will save its current state in a series of buffers, +then restores state from a similar set of buffers specified by the kernel. It +then resumes execution and fires an IRQ to let the kernel know the context +switch has completed. + +This mechanism can be used by the kernel to switch between rings. Whenever a +submission occurs the kernel finds the highest priority ring which isn't empty +and preempts to it if said ring is not the one being currently executed. This is +also done whenever a submission completes to make sure execution resumes on a +lower priority ring when a higher priority ring is done. + +Preemption levels +----------------- + +Preemption can only occur at certain boundaries. The exact conditions can be +configured by changing the preemption level, this allows to compromise between +latency (ie. the time that passes between when the kernel requests preemption +and when the SQE begins saving state) and overhead (the amount of state that +needs to be saved). + +The GPU offers 3 levels: + +Level 0 + Preemption only occurs at the submission level. This requires the least amount + of state to be saved as the execution of userspace submitted IBs is never + interrupted, however it offers very little benefit compared to not enabling + preemption of any kind. + +Level 1 + Preemption occurs at either bin level, if using GMEM rendering, or draw level + in the sysmem rendering case. + +Level 2 + Preemption occurs at draw level. + +Level 1 is the mode that is used by the msm driver. + +Additionally the GPU allows to specify a `skip_save_restore` option. This +disables the saving and restoring of all registers except those relating to the +operation of the SQE itself, reducing overhead. Saving and restoring is only +skipped when using GMEM with Level 1 preemption. When enabling this userspace is +expected to set the state that isn't preserved whenever preemption occurs which +is done by specifying preamble and postambles. Those are IBs that are executed +before and after preemption. + +Preemption buffers +------------------ + +A series of buffers are necessary to store the state of rings while they are not +being executed. There are different kinds of preemption records and most of +those require one buffer per ring. This is because preemption never occurs +between submissions on the same ring, which always run in sequence when the ring +is active. This means that only one context per ring is effectively active. + +SMMU_INFO + This buffer contains info about the current SMMU configuration such as the + ttbr0 register. The SQE firmware isn't actually able to save this record. + As a result SMMU info must be saved manually from the CP to a buffer and the + SMMU record updated with info from said buffer before triggering + preemption. + +NON_SECURE + This is the main preemption record where most state is saved. It is mostly + opaque to the kernel except for the first few words that must be initialized + by the kernel. + +SECURE + This saves state related to the GPU's secure mode. + +NON_PRIV + The intended purpose of this record is unknown. The SQE firmware actually + ignores it and therefore msm doesn't handle it. + +COUNTER + This record is used to save and restore performance counters. + +Handling the permissions of those buffers is critical for security. All but the +NON_PRIV records need to be inaccessible from userspace, so they must be mapped +in the kernel address space with the MSM_BO_MAP_PRIV flag. +For example, making the NON_SECURE record accessible from userspace would allow +any process to manipulate a saved ring's RPTR which can be used to skip the +execution of some packets in a ring and execute user commands with higher +privileges. diff --git a/Documentation/gpu/panthor.rst b/Documentation/gpu/panthor.rst new file mode 100644 index 00000000000000..3f8979fa2b86ed --- /dev/null +++ b/Documentation/gpu/panthor.rst @@ -0,0 +1,46 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +========================= + drm/Panthor CSF driver +========================= + +.. _panthor-usage-stats: + +Panthor DRM client usage stats implementation +============================================== + +The drm/Panthor driver implements the DRM client usage stats specification as +documented in :ref:`drm-client-usage-stats`. + +Example of the output showing the implemented key value pairs and entirety of +the currently possible format options: + +:: + pos: 0 + flags: 02400002 + mnt_id: 29 + ino: 491 + drm-driver: panthor + drm-client-id: 10 + drm-engine-panthor: 111110952750 ns + drm-cycles-panthor: 94439687187 + drm-maxfreq-panthor: 1000000000 Hz + drm-curfreq-panthor: 1000000000 Hz + drm-total-memory: 16480 KiB + drm-shared-memory: 0 + drm-active-memory: 16200 KiB + drm-resident-memory: 16480 KiB + drm-purgeable-memory: 0 + +Possible `drm-engine-` key names are: `panthor`. +`drm-curfreq-` values convey the current operating frequency for that engine. + +Users must bear in mind that engine and cycle sampling are disabled by default, +because of power saving concerns. `fdinfo` users and benchmark applications which +query the fdinfo file must make sure to toggle the job profiling status of the +driver by writing into the appropriate sysfs node:: + + echo > /sys/bus/platform/drivers/panthor/[a-f0-9]*.gpu/profiling + +Where `N` is a bit mask where cycle and timestamp sampling are respectively +enabled by the first and second bits. diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 2b281e3c75a4b2..256d0d1cb2164b 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -834,6 +834,22 @@ Contact: Javier Martinez Canillas Level: Advanced +Querying errors from drm_syncobj +================================ + +The drm_syncobj container can be used by driver independent code to signal +complection of submission. + +One minor feature still missing is a generic DRM IOCTL to query the error +status of binary and timeline drm_syncobj. + +This should probably be improved by implementing the necessary kernel interface +and adding support for that in the userspace stack. + +Contact: Christian König + +Level: Starter + Outside DRM =========== diff --git a/Documentation/gpu/zynqmp.rst b/Documentation/gpu/zynqmp.rst new file mode 100644 index 00000000000000..f57bfa0ad6ece8 --- /dev/null +++ b/Documentation/gpu/zynqmp.rst @@ -0,0 +1,149 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +=============================================== +Xilinx ZynqMP Ultrascale+ DisplayPort Subsystem +=============================================== + +This subsystem handles DisplayPort video and audio output on the ZynqMP. It +supports in-memory framebuffers with the DisplayPort DMA controller +(xilinx-dpdma), as well as "live" video and audio from the programmable logic +(PL). This subsystem can perform several transformations, including color space +conversion, alpha blending, and audio mixing, although not all features are +currently supported. + +debugfs +------- + +To support debugging and compliance testing, several test modes can be enabled +though debugfs. The following files in /sys/kernel/debug/dri/X/DP-1/test/ +control the DisplayPort test modes: + +active: + Writing a 1 to this file will activate test mode, and writing a 0 will + deactivate test mode. Writing a 1 or 0 when the test mode is already + active/inactive will re-activate/re-deactivate test mode. When test + mode is inactive, changes made to other files will have no (immediate) + effect, although the settings will be saved for when test mode is + activated. When test mode is active, changes made to other files will + apply immediately. + +custom: + Custom test pattern value + +downspread: + Enable/disable clock downspreading (spread-spectrum clocking) by + writing 1/0 + +enhanced: + Enable/disable enhanced framing + +ignore_aux_errors: + Ignore AUX errors when set to 1. Writes to this file take effect + immediately (regardless of whether test mode is active) and affect all + AUX transfers. + +ignore_hpd: + Ignore hotplug events (such as cable removals or monitor link + retraining requests) when set to 1. Writes to this file take effect + immediately (regardless of whether test mode is active). + +laneX_preemphasis: + Preemphasis from 0 (lowest) to 2 (highest) for lane X + +laneX_swing: + Voltage swing from 0 (lowest) to 3 (highest) for lane X + +lanes: + Number of lanes to use (1, 2, or 4) + +pattern: + Test pattern. May be one of: + + video + Use regular video input + + symbol-error + Symbol error measurement pattern + + prbs7 + Output of the PRBS7 (x^7 + x^6 + 1) polynomial + + 80bit-custom + A custom 80-bit pattern + + cp2520 + HBR2 compliance eye pattern + + tps1 + Link training symbol pattern TPS1 (/D10.2/) + + tps2 + Link training symbol pattern TPS2 + + tps3 + Link training symbol pattern TPS3 (for HBR2) + +rate: + Rate in hertz. One of + + * 5400000000 (HBR2) + * 2700000000 (HBR) + * 1620000000 (RBR) + +You can dump the displayport test settings with the following command:: + + for prop in /sys/kernel/debug/dri/1/DP-1/test/*; do + printf '%-17s ' ${prop##*/} + if [ ${prop##*/} = custom ]; then + hexdump -C $prop | head -1 + else + cat $prop + fi + done + +The output could look something like:: + + active 1 + custom 00000000 00 00 00 00 00 00 00 00 00 00 |..........| + downspread 0 + enhanced 1 + ignore_aux_errors 1 + ignore_hpd 1 + lane0_preemphasis 0 + lane0_swing 3 + lane1_preemphasis 0 + lane1_swing 3 + lanes 2 + pattern prbs7 + rate 1620000000 + +The recommended test procedure is to connect the board to a monitor, +configure test mode, activate test mode, and then disconnect the cable +and connect it to your test equipment of choice. For example, one +sequence of commands could be:: + + echo 1 > /sys/kernel/debug/dri/1/DP-1/test/enhanced + echo tps1 > /sys/kernel/debug/dri/1/DP-1/test/pattern + echo 1620000000 > /sys/kernel/debug/dri/1/DP-1/test/rate + echo 1 > /sys/kernel/debug/dri/1/DP-1/test/ignore_aux_errors + echo 1 > /sys/kernel/debug/dri/1/DP-1/test/ignore_hpd + echo 1 > /sys/kernel/debug/dri/1/DP-1/test/active + +at which point the cable could be disconnected from the monitor. + +Internals +--------- + +.. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_disp.h + +.. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_dpsub.h + +.. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_kms.h + +.. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_disp.c + +.. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_dp.c + +.. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_dpsub.c + +.. kernel-doc:: drivers/gpu/drm/xlnx/zynqmp_kms.c diff --git a/Documentation/hwmon/f71882fg.rst b/Documentation/hwmon/f71882fg.rst index 38e30fbd4806c4..53d32bf06b709e 100644 --- a/Documentation/hwmon/f71882fg.rst +++ b/Documentation/hwmon/f71882fg.rst @@ -178,10 +178,11 @@ Writing an unsupported mode will result in an invalid parameter error. available on the F71858FG / F8000 if the fan channel is in RPM mode. * 2: Normal auto mode - You can define a number of temperature/fan speed trip points, which % the - fan should run at at this temp and which temp a fan should follow using the - standard sysfs interface. The number and type of trip points is chip - depended, see which files are available in sysfs. + You can define a number of temperature/fan speed trip points that specify + the percentage at which the fan should run at each temperature, and which + temperature sensor a fan should follow, using the standard sysfs interface. + The number and type of trip points are chip dependent - see the available + files in sysfs. Fan/PWM channel 3 of the F8000 is always in this mode! * 3: Thermostat mode (Only available on the F8000 when in duty cycle mode) diff --git a/Documentation/hwmon/ina2xx.rst b/Documentation/hwmon/ina2xx.rst index 7f1939b40f74fe..a3860aae444c08 100644 --- a/Documentation/hwmon/ina2xx.rst +++ b/Documentation/hwmon/ina2xx.rst @@ -53,6 +53,27 @@ Supported chips: https://www.ti.com/ + * Texas Instruments INA260 + + Prefix: 'ina260' + + Addresses: I2C 0x40 - 0x4f + + Datasheet: Publicly available at the Texas Instruments website + + https://www.ti.com/ + + * Silergy SY24655 + + Prefix: 'sy24655' + + Addresses: I2C 0x40 - 0x4f + + Datasheet: Publicly available at the Silergy website + + https://us1.silergy.com/ + + Author: Lothar Felten Description @@ -72,6 +93,14 @@ INA230 and INA231 are high or low side current shunt and power monitors with an I2C interface. The chips monitor both a shunt voltage drop and bus supply voltage. +INA260 is a high or low side current and power monitor with integrated shunt +resistor. + +The SY24655 is a high- and low-side current shunt and power monitor with an I2C +interface. The SY24655 supports both shunt drop and supply voltage, with +programmable calibration value and conversion times. The SY24655 can also +calculate average power for use in energy conversion. + The shunt value in micro-ohms can be set via platform data or device tree at compile-time or via the shunt_resistor attribute in sysfs at run-time. Please refer to the Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings @@ -87,16 +116,16 @@ The actual programmed interval may vary from the desired value. General sysfs entries --------------------- -======================= =============================== +======================= =============================================== in0_input Shunt voltage(mV) channel in1_input Bus voltage(mV) channel curr1_input Current(mA) measurement channel power1_input Power(uW) measurement channel -shunt_resistor Shunt resistance(uOhm) channel -======================= =============================== +shunt_resistor Shunt resistance(uOhm) channel (not for ina260) +======================= =============================================== -Sysfs entries for ina226, ina230 and ina231 only ------------------------------------------------- +Additional sysfs entries for ina226, ina230, ina231, ina260, and sy24655 +------------------------------------------------------------------------ ======================= ==================================================== curr1_lcrit Critical low current @@ -117,6 +146,13 @@ update_interval data conversion time; affects number of samples used to average results for shunt and bus voltages. ======================= ==================================================== +Sysfs entries for sy24655 only +------------------------------ + +======================= ==================================================== +power1_average average power from last reading to the present. +======================= ==================================================== + .. note:: - Configure `shunt_resistor` before configure `power1_crit`, because power diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index ea3b5be8fe4f7a..55f1111594b2e9 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -96,6 +96,7 @@ Hardware Monitoring Kernel Drivers ir35221 ir38064 ir36021 + isl28022 isl68137 it87 jc42 @@ -174,6 +175,7 @@ Hardware Monitoring Kernel Drivers mpq8785 nct6683 nct6775 + nct7363 nct7802 nct7904 npcm750-pwm-fan diff --git a/Documentation/hwmon/isl28022.rst b/Documentation/hwmon/isl28022.rst new file mode 100644 index 00000000000000..8d4422a2dacd9d --- /dev/null +++ b/Documentation/hwmon/isl28022.rst @@ -0,0 +1,63 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver isl28022 +====================== + +Supported chips: + + * Renesas ISL28022 + + Prefix: 'isl28022' + + Addresses scanned: none + + Datasheet: Publicly available at the Renesas website + + https://www.renesas.com/us/en/www/doc/datasheet/isl28022.pdf + +Author: + Carsten Spieß + +Description +----------- + +The ISL28022 is a power monitor with I2C interface. The device monitors +voltage, current via shunt resistor and calculated power. + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +device explicitly. Please see Documentation/i2c/instantiating-devices.rst for +details. + +The shunt value in micro-ohms, shunt voltage range and averaging can be set +with device properties. +Please refer to the Documentation/devicetree/bindings/hwmon/isl,isl28022.yaml +for bindings if the device tree is used. + +The driver supports only shunt and bus continuous ADC mode at 15bit resolution. +Averaging can be set from 1 to 128 samples (power of 2) on both channels. +Shunt voltage range of 40, 80, 160 or 320mV is allowed +The bus voltage range is 60V fixed. + +Sysfs entries +------------- + +The following attributes are supported. All attributes are read-only. + +======================= ======================================================= +in0_input bus voltage (milli Volt) + +curr1_input current (milli Ampere) +power1_input power (micro Watt) +======================= ======================================================= + +Debugfs entries +--------------- + +The following attributes are supported. All attributes are read-only. + +======================= ======================================================= +shunt_voltage shunt voltage (micro Volt) +======================= ======================================================= diff --git a/Documentation/hwmon/ltc2978.rst b/Documentation/hwmon/ltc2978.rst index edf24e5e1e118c..651ca4904c6649 100644 --- a/Documentation/hwmon/ltc2978.rst +++ b/Documentation/hwmon/ltc2978.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + Kernel driver ltc2978 ===================== @@ -117,6 +119,14 @@ Supported chips: Datasheet: https://www.analog.com/en/products/ltc3889 + * Linear Technology LTC7841 + + Prefix: 'ltc7841' + + Addresses scanned: - + + Datasheet: https://www.analog.com/en/products/ltc7841 + * Linear Technology LTC7880 Prefix: 'ltc7880' @@ -290,6 +300,7 @@ in[N]_label "vout[1-8]". LTC7880, LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4700: N=2-3 - LTC3883: N=2 + - LTC7841: N=2 in[N]_input Measured output voltage. @@ -420,6 +431,7 @@ curr[N]_label "iout[1-4]". LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4700: N=2-3 - LTC3883: N=2 + - LTC7841: N=2 curr[N]_input Measured output current. diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst index 9c11a9518c6758..6cc5088b26b738 100644 --- a/Documentation/hwmon/max31827.rst +++ b/Documentation/hwmon/max31827.rst @@ -136,7 +136,7 @@ PEC Support When reading a register value, the PEC byte is computed and sent by the chip. -PEC on word data transaction respresents a signifcant increase in bandwitdh +PEC on word data transaction represents a significant increase in bandwidth usage (+33% for both write and reads) in normal conditions. Since this operation implies there will be an extra delay to each diff --git a/Documentation/hwmon/nct7363.rst b/Documentation/hwmon/nct7363.rst new file mode 100644 index 00000000000000..623cb4f0c8ceae --- /dev/null +++ b/Documentation/hwmon/nct7363.rst @@ -0,0 +1,35 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver nct7363 +===================== + +Supported chip: + + * Nuvoton NCT7363Y + + Prefix: nct7363 + + Addresses: I2C 0x20, 0x21, 0x22, 0x23 + +Author: Ban Feng + + +Description +----------- + +The NCT7363Y is a fan controller which provides up to 16 independent +FAN input monitors, and up to 16 independent PWM outputs with SMBus interface. + + +Sysfs entries +------------- + +Currently, the driver supports the following features: + +========== ========================================== +fanX_input provide current fan rotation value in RPM +fanX_alarm report fan low speed real status +fanX_min get or set fan count threshold + +pwmX get or set PWM fan control value. +========== ========================================== diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 1eaf2b01583768..686a00265bf712 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -308,6 +308,10 @@ currently provides a flags field with four bits used:: #define PMBUS_READ_STATUS_AFTER_FAILED_CHECK BIT(3) + #define PMBUS_NO_WRITE_PROTECT BIT(4) + + #define PMBUS_USE_COEFFICIENTS_CMD BIT(5) + struct pmbus_platform_data { u32 flags; /* Device specific flags */ @@ -358,3 +362,14 @@ This can be done by reading a known register. By setting this flag the driver will try to read the STATUS register after each failed register check. This read may fail, but it will put the chip into a known state. + +PMBUS_NO_WRITE_PROTECT + +Some PMBus chips respond with invalid data when reading the WRITE_PROTECT +register. For such chips, this flag should be set so that the PMBus core +driver doesn't use the WRITE_PROTECT command to determine its behavior. + +PMBUS_USE_COEFFICIENTS_CMD + +When this flag is set the PMBus core driver will use the COEFFICIENTS +register to initialize the coefficients for the direct mode format. diff --git a/Documentation/hwmon/sch5627.rst b/Documentation/hwmon/sch5627.rst index 8639dff234fcec..5f521c6e90ab69 100644 --- a/Documentation/hwmon/sch5627.rst +++ b/Documentation/hwmon/sch5627.rst @@ -39,7 +39,7 @@ Controlling fan speed --------------------- The SCH5627 allows for partially controlling the fan speed. If a temperature -channel excedes tempX_max, all fans are forced to maximum speed. The same is not +channel exceeds tempX_max, all fans are forced to maximum speed. The same is not true for tempX_crit, presumably some other measures to cool down the system are take in this case. In which way the value of fanX_min affects the fan speed is currently unknown. diff --git a/Documentation/hwmon/sht4x.rst b/Documentation/hwmon/sht4x.rst index daf21e76342556..ba094ad0e2816f 100644 --- a/Documentation/hwmon/sht4x.rst +++ b/Documentation/hwmon/sht4x.rst @@ -42,4 +42,18 @@ humidity1_input Measured humidity in %H update_interval The minimum interval for polling the sensor, in milliseconds. Writable. Must be at least 2000. +heater_power The requested heater power, in milliwatts. + Available values: 20, 110, 200 (default: 200). +heater_time The requested operating time of the heater, + in milliseconds. + Available values: 100, 1000 (default 1000). +heater_enable Enable the heater with the selected power + and for the selected time in order to remove + condensed water from the sensor surface. The + heater cannot be manually turned off once + enabled (it will automatically turn off + after completing its operation). + + - 0: turned off (read-only value) + - 1: turn on =============== ============================================ diff --git a/Documentation/hwmon/tmp108.rst b/Documentation/hwmon/tmp108.rst index 6df7cf1b42f491..bc4941d9826819 100644 --- a/Documentation/hwmon/tmp108.rst +++ b/Documentation/hwmon/tmp108.rst @@ -3,6 +3,14 @@ Kernel driver tmp108 Supported chips: + * NXP P3T1085 + + Prefix: 'p3t1085' + + Addresses scanned: none + + Datasheet: https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf + * Texas Instruments TMP108 Prefix: 'tmp108' diff --git a/Documentation/i2c/busses/i2c-i801.rst b/Documentation/i2c/busses/i2c-i801.rst index c840b597912c87..47e8ac5b7099f7 100644 --- a/Documentation/i2c/busses/i2c-i801.rst +++ b/Documentation/i2c/busses/i2c-i801.rst @@ -49,6 +49,7 @@ Supported adapters: * Intel Meteor Lake (SOC and PCH) * Intel Birch Stream (SOC) * Intel Arrow Lake (SOC) + * Intel Panther Lake (SOC) Datasheets: Publicly available at the Intel website diff --git a/Documentation/i2c/busses/i2c-piix4.rst b/Documentation/i2c/busses/i2c-piix4.rst index 07fe6f6f4b186a..94e20b18c59a80 100644 --- a/Documentation/i2c/busses/i2c-piix4.rst +++ b/Documentation/i2c/busses/i2c-piix4.rst @@ -109,3 +109,66 @@ which can easily get corrupted due to a state machine bug. These are mostly Thinkpad laptops, but desktop systems may also be affected. We have no list of all affected systems, so the only safe solution was to prevent access to the SMBus on all IBM systems (detected using DMI data.) + + +Description in the ACPI code +---------------------------- + +Device driver for the PIIX4 chip creates a separate I2C bus for each of its +ports:: + + $ i2cdetect -l + ... + i2c-7 unknown SMBus PIIX4 adapter port 0 at 0b00 N/A + i2c-8 unknown SMBus PIIX4 adapter port 2 at 0b00 N/A + i2c-9 unknown SMBus PIIX4 adapter port 1 at 0b20 N/A + ... + +Therefore if you want to access one of these busses in the ACPI code, port +subdevices are needed to be declared inside the PIIX device:: + + Scope (\_SB_.PCI0.SMBS) + { + Name (_ADR, 0x00140000) + + Device (SMB0) { + Name (_ADR, 0) + } + Device (SMB1) { + Name (_ADR, 1) + } + Device (SMB2) { + Name (_ADR, 2) + } + } + +If this is not the case for your UEFI firmware and you don't have access to the +source code, you can use ACPI SSDT Overlays to provide the missing parts. Just +keep in mind that in this case you would need to load your extra SSDT table +before the piix4 driver starts, i.e. you should provide SSDT via initrd or EFI +variable methods and not via configfs. + +As an example of usage here is the ACPI snippet code that would assign jc42 +driver to the 0x1C device on the I2C bus created by the PIIX port 0:: + + Device (JC42) { + Name (_HID, "PRP0001") + Name (_DDN, "JC42 Temperature sensor") + Name (_CRS, ResourceTemplate () { + I2cSerialBusV2 ( + 0x001c, + ControllerInitiated, + 100000, + AddressingMode7Bit, + "\\_SB.PCI0.SMBS.SMB0", + 0 + ) + }) + + Name (_DSD, Package () { + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { + Package () { "compatible", Package() { "jedec,jc-42.4-temp" } }, + } + }) + } diff --git a/Documentation/i2c/writing-clients.rst b/Documentation/i2c/writing-clients.rst index 0b8439ea954ccd..121e618e72ec52 100644 --- a/Documentation/i2c/writing-clients.rst +++ b/Documentation/i2c/writing-clients.rst @@ -31,12 +31,11 @@ driver model device node, and its I2C address. :: - static struct i2c_device_id foo_idtable[] = { + static const struct i2c_device_id foo_idtable[] = { { "foo", my_id_for_foo }, { "bar", my_id_for_bar }, { } }; - MODULE_DEVICE_TABLE(i2c, foo_idtable); static struct i2c_driver foo_driver = { diff --git a/Documentation/iio/ad7380.rst b/Documentation/iio/ad7380.rst index 6f70b49b9ef27c..c46127700e14ca 100644 --- a/Documentation/iio/ad7380.rst +++ b/Documentation/iio/ad7380.rst @@ -27,6 +27,8 @@ The following chips are supported by this driver: * `AD7386-4 `_ * `AD7387-4 `_ * `AD7388-4 `_ +* `ADAQ4370-4 `_ +* `ADAQ4380-4 `_ Supported features @@ -47,6 +49,12 @@ ad7380-4 ad7380-4 supports only an external reference voltage (2.5V to 3.3V). It must be declared in the device tree as ``refin-supply``. +ADAQ devices +~~~~~~~~~~~~ + +adaq4370-4 and adaq4380-4 don't have an external reference, but use a 3.3V +internal reference derived from one of its supplies (``refin-supply``) + All other devices from ad738x family ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -121,6 +129,14 @@ Example for AD7386/7/8 (2 channels parts): When enabling sequencer mode, the effective sampling rate is divided by two. +Gain (ADAQ devices only) +~~~~~~~~~~~~~~~~~~~~~~~~ + +ADAQ devices have a pin selectable gain in front of each ADC. The appropriate +gain is selectable from device tree using the ``adi,gain-milli`` property. +Refer to the typical connection diagrams section of the datasheet for pin +wiring. + Unimplemented features ---------------------- diff --git a/Documentation/iio/ad7606.rst b/Documentation/iio/ad7606.rst new file mode 100644 index 00000000000000..930199e03c67f6 --- /dev/null +++ b/Documentation/iio/ad7606.rst @@ -0,0 +1,144 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +============= +AD7606 driver +============= + +ADC driver for Analog Devices Inc. AD7606 and similar devices. The module name +is ``ad7606``. + +Supported devices +================= + +The following chips are supported by this driver: + +* `AD7605 `_ +* `AD7606 `_ +* `AD7606B `_ +* `AD7616 `_ + +Supported features +================== + +SPI wiring modes +---------------- + +These ADCs can output data on several SDO lines (1/2/4/8). The driver +currently supports only 1 SDO line. + +Parallel wiring mode +-------------------- + +There is also a parallel interface, with 16 lines (that can be reduced to 8 in +byte mode). The parallel interface is selected by declaring the device as +platform in the device tree (with no io-backends node defined, see below). + +IIO-backend mode +---------------- + +This mode allows to reach the best sample rates, but it requires an external +hardware (eg HDL or APU) to handle the low level communication. +The backend mode is enabled when through the definition of the "io-backends" +property in the device tree. + +The reference configuration for the current implementation of IIO-backend mode +is the HDL reference provided by ADI: +https://wiki.analog.com/resources/eval/user-guides/ad7606x-fmc/hdl + +This implementation embeds an IIO-backend compatible IP (adi-axi-adc) and a PWM +connected to the conversion trigger pin. + +.. code-block:: + + +---+ +---------------------------- + | | +-------+ |AD76xx + | A | controls | | | + | D |-------------->| PWM |-------------->| cnvst + | 7 | | | | + | 6 | +-------+ | + | 0 | controls +-----------+-----------+ | + | 6 |---------->| | |<--| frstdata + | | | Backend | Backend |<--| busy + | D | | Driver | | | + | R | | | |-->| clk + | I | requests |+---------+| DMA | | + | V |----------->| Buffer ||<---- |<=>| DATA + | E | |+---------+| | | + | R | +-----------+-----------+ | + | |-------------------------------------->| reset/configuration gpios + +---+ +----------------------------- + + +Software and hardware modes +--------------------------- + +While all the AD7606/AD7616 series parts can be configured using GPIOs, some of +them can be configured using register. + +The chips that support software mode have more values available for configuring +the device, as well as more settings, and allow to control the range and +calibration per channel. + +The following settings are available per channel in software mode: + - Scale + +Also, there is a broader choice of oversampling ratios in software mode. + +Conversion triggering +--------------------- + +The conversion can be triggered by two distinct ways: + + - A GPIO is connected to the conversion trigger pin, and this GPIO is controlled + by the driver directly. In this configuration, the driver sets back the + conversion trigger pin to high as soon as it has read all the conversions. + + - An external source is connected to the conversion trigger pin. In the + current implementation, it must be a PWM. In this configuration, the driver + does not control directly the conversion trigger pin. Instead, it can + control the PWM's frequency. This trigger is enabled only for iio-backend. + +Reference voltage +----------------- + +2 possible reference voltage sources are supported: + + - Internal reference (2.5V) + - External reference (2.5V) + +The source is determined by the device tree. If ``refin-supply`` is present, +then the external reference is used, otherwise the internal reference is used. + +Oversampling +------------ + +This family supports oversampling to improve SNR. +In software mode, the following ratios are available: +1 (oversampling disabled)/2/4/8/16/32/64/128/256. + +Unimplemented features +---------------------- + +- 2/4/8 SDO lines +- CRC indication +- Calibration + +Device buffers +============== + +IIO triggered buffer +-------------------- + +This driver supports IIO triggered buffers, with a "built in" trigger, i.e the +trigger is allocated and linked by the driver, and a new conversion is triggered +as soon as the samples are transferred, and a timestamp channel is added to make +up for the potential jitter induced by the delays in the interrupt handling. + +IIO backend buffer +------------------ + +When IIO backend is used, the trigger is not needed, and the sample rate is +considered as stable. There is no timestamp channel. The communication is +delegated to an external logic, called a backend, and the backend's driver +handles the buffer. When this mode is enabled, the driver cannot control the +conversion pin, because the busy pin is bound to the backend. diff --git a/Documentation/iio/ad7625.rst b/Documentation/iio/ad7625.rst new file mode 100644 index 00000000000000..61761e3b75c39d --- /dev/null +++ b/Documentation/iio/ad7625.rst @@ -0,0 +1,91 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +==================== +AD7625 driver +==================== + +ADC driver for Analog Devices Inc. AD7625, AD7626, AD7960, and AD7961 +devices. The module name is ``ad7625``. + +Supported devices +================= + +The following chips are supported by this driver: + +* `AD7625 `_ +* `AD7626 `_ +* `AD7960 `_ +* `AD7961 `_ + +The driver requires use of the Pulsar LVDS HDL project: + +* `Pulsar LVDS HDL `_ + +To trigger conversions and enable subsequent data transfer, the devices +require coupled PWM signals with a phase offset. + +Supported features +================== + +Conversion control modes +------------------------ + +The driver currently supports one of two possible LVDS conversion control methods. + +Echoed-Clock interface mode +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: + + +----------------+ + +xxxxxxxxxxxxxxxxxxxxxxxxxx| CNV | + X | | + v | HOST | + +----------------------------+ | | + | CNV+/CNV- DCO+/DCO- |xxxxxxx>| CLK_IN | + | | | | + | | | | + | AD7625 D+/D- |xxxxxxx>| DATA_IN | + | | | | + | | | | + | CLK+/CLK- | "endchoice" -This defines a choice group and accepts any of the above attributes as -options. +This defines a choice group and accepts "prompt", "default", "depends on", and +"help" attributes as options. A choice only allows a single config entry to be selected. diff --git a/Documentation/kbuild/llvm.rst b/Documentation/kbuild/llvm.rst index 6dc66b4f31a7bb..bc8a283bc44bbf 100644 --- a/Documentation/kbuild/llvm.rst +++ b/Documentation/kbuild/llvm.rst @@ -179,6 +179,9 @@ yet. Bug reports are always welcome at the issue tracker below! * - s390 - Maintained - ``LLVM=1`` (LLVM >= 18.1.0), ``CC=clang`` (LLVM < 18.1.0) + * - sparc (sparc64 only) + - Maintained + - ``CC=clang LLVM_IAS=0`` (LLVM >= 20) * - um (User Mode) - Maintained - ``LLVM=1`` diff --git a/Documentation/kbuild/makefiles.rst b/Documentation/kbuild/makefiles.rst index 7964e0c245aebe..d36519f194dc0d 100644 --- a/Documentation/kbuild/makefiles.rst +++ b/Documentation/kbuild/makefiles.rst @@ -449,6 +449,20 @@ $(obj) to prerequisites are referenced with $(src) (because they are not generated files). +$(srcroot) + $(srcroot) refers to the root of the source you are building, which can be + either the kernel source or the external modules source, depending on whether + KBUILD_EXTMOD is set. This can be either a relative or an absolute path, but + if KBUILD_ABS_SRCTREE=1 is set, it is always an absolute path. + +$(srctree) + $(srctree) refers to the root of the kernel source tree. When building the + kernel, this is the same as $(srcroot). + +$(objtree) + $(objtree) refers to the root of the kernel object tree. It is ``.`` when + building the kernel, but it is different when building external modules. + $(kecho) echoing information to user in a rule is often a good practice but when execution ``make -s`` one does not expect to see any output diff --git a/Documentation/kbuild/modules.rst b/Documentation/kbuild/modules.rst index cd5a54d91e6d29..101de236cd0c9a 100644 --- a/Documentation/kbuild/modules.rst +++ b/Documentation/kbuild/modules.rst @@ -59,6 +59,12 @@ Command Syntax $ make -C /lib/modules/`uname -r`/build M=$PWD modules_install + Starting from Linux 6.13, you can use the -f option instead of -C. This + will avoid unnecessary change of the working directory. The external + module will be output to the directory where you invoke make. + + $ make -f /lib/modules/`uname -r`/build/Makefile M=$PWD + Options ------- @@ -66,7 +72,10 @@ Options of the kernel output directory if the kernel was built in a separate build directory.) - make -C $KDIR M=$PWD + You can optionally pass MO= option if you want to build the modules in + a separate directory. + + make -C $KDIR M=$PWD [MO=$BUILD_DIR] -C $KDIR The directory that contains the kernel and relevant build @@ -80,6 +89,9 @@ Options directory where the external module (kbuild file) is located. + MO=$BUILD_DIR + Specifies a separate output directory for the external module. + Targets ------- @@ -215,6 +227,21 @@ Separate Kbuild File and Makefile consisting of several hundred lines, and here it really pays off to separate the kbuild part from the rest. + Linux 6.13 and later support another way. The external module Makefile + can include the kernel Makefile directly, rather than invoking sub Make. + + Example 3:: + + --> filename: Kbuild + obj-m := 8123.o + 8123-y := 8123_if.o 8123_pci.o + + --> filename: Makefile + KDIR ?= /lib/modules/$(shell uname -r)/build + export KBUILD_EXTMOD := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) + include $(KDIR)/Makefile + + Building Multiple Modules ------------------------- diff --git a/Documentation/kernel-hacking/false-sharing.rst b/Documentation/kernel-hacking/false-sharing.rst index 122b0e12465615..eb0596734e55d6 100644 --- a/Documentation/kernel-hacking/false-sharing.rst +++ b/Documentation/kernel-hacking/false-sharing.rst @@ -196,9 +196,9 @@ the hotspot switches to a new place. Miscellaneous ============= -One open issue is that kernel has an optional data structure +One open issue is that the kernel has an optional data structure randomization mechanism, which also randomizes the situation of cache -line sharing of data members. +line sharing among data members. .. [1] https://en.wikipedia.org/wiki/False_sharing diff --git a/Documentation/kernel-hacking/hacking.rst b/Documentation/kernel-hacking/hacking.rst index 1717348a4404e0..0042776a9e17cf 100644 --- a/Documentation/kernel-hacking/hacking.rst +++ b/Documentation/kernel-hacking/hacking.rst @@ -587,7 +587,7 @@ Defined in ``include/linux/export.h`` Similar to :c:func:`EXPORT_SYMBOL()` except that the symbols exported by :c:func:`EXPORT_SYMBOL_GPL()` can only be seen by -modules with a :c:func:`MODULE_LICENSE()` that specifies a GPL +modules with a :c:func:`MODULE_LICENSE()` that specifies a GPLv2 compatible license. It implies that the function is considered an internal implementation issue, and not really an interface. Some maintainers and developers may however require EXPORT_SYMBOL_GPL() diff --git a/Documentation/locking/percpu-rw-semaphore.rst b/Documentation/locking/percpu-rw-semaphore.rst index 247de64108557a..a105bf2dd81236 100644 --- a/Documentation/locking/percpu-rw-semaphore.rst +++ b/Documentation/locking/percpu-rw-semaphore.rst @@ -16,8 +16,8 @@ writing is very expensive, it calls synchronize_rcu() that can take hundreds of milliseconds. The lock is declared with "struct percpu_rw_semaphore" type. -The lock is initialized percpu_init_rwsem, it returns 0 on success and --ENOMEM on allocation failure. +The lock is initialized with percpu_init_rwsem, it returns 0 on success +and -ENOMEM on allocation failure. The lock must be freed with percpu_free_rwsem to avoid memory leak. The lock is locked for read with percpu_down_read, percpu_up_read and diff --git a/Documentation/locking/seqlock.rst b/Documentation/locking/seqlock.rst index bfda1a5fecadc6..ec6411d02ac8f5 100644 --- a/Documentation/locking/seqlock.rst +++ b/Documentation/locking/seqlock.rst @@ -153,7 +153,7 @@ Use seqcount_latch_t when the write side sections cannot be protected from interruption by readers. This is typically the case when the read side can be invoked from NMI handlers. -Check `raw_write_seqcount_latch()` for more information. +Check `write_seqcount_latch()` for more information. .. _seqlock_t: diff --git a/Documentation/maintainer/pull-requests.rst b/Documentation/maintainer/pull-requests.rst index 00b200facf676c..0d63d9d7e347cc 100644 --- a/Documentation/maintainer/pull-requests.rst +++ b/Documentation/maintainer/pull-requests.rst @@ -50,7 +50,7 @@ so outline what is contained here, why it should be merged, and what, if any, testing has been done. All of this information will end up in the tag itself, and then in the merge commit that the maintainer makes if/when they merge the pull request. So write it up well, as it will be in the kernel -tree for forever. +tree forever. As said by Linus:: diff --git a/Documentation/mm/allocation-profiling.rst b/Documentation/mm/allocation-profiling.rst index ffd6655b7be221..316311240e6aa3 100644 --- a/Documentation/mm/allocation-profiling.rst +++ b/Documentation/mm/allocation-profiling.rst @@ -18,12 +18,17 @@ kconfig options: missing annotation Boot parameter: - sysctl.vm.mem_profiling=0|1|never + sysctl.vm.mem_profiling={0|1|never}[,compressed] When set to "never", memory allocation profiling overhead is minimized and it cannot be enabled at runtime (sysctl becomes read-only). When CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=y, default value is "1". When CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT=n, default value is "never". + "compressed" optional parameter will try to store page tag references in a + compact format, avoiding page extensions. This results in improved performance + and memory consumption, however it might fail depending on system configuration. + If compression fails, a warning is issued and memory allocation profiling gets + disabled. sysctl: /proc/sys/vm/mem_profiling diff --git a/Documentation/mm/damon/index.rst b/Documentation/mm/damon/index.rst index dafd6d02892434..5a3359704ccea1 100644 --- a/Documentation/mm/damon/index.rst +++ b/Documentation/mm/damon/index.rst @@ -37,3 +37,9 @@ with no code but simple configurations. To utilize and control DAMON from the user-space, please refer to the administration :doc:`guide `. + +If you prefer academic papers for reading and citations, please use the papers +from `HPDC'22 `_ and +`Middleware19 Industry `_ . +Note that those cover DAMON implementations in Linux v5.16 and v5.15, +respectively. diff --git a/Documentation/mm/page_tables.rst b/Documentation/mm/page_tables.rst index be47b192a596e5..e7c69cc32493fa 100644 --- a/Documentation/mm/page_tables.rst +++ b/Documentation/mm/page_tables.rst @@ -29,7 +29,7 @@ address. With a page granularity of 4KB and a address range of 32 bits, pfn 0 is at address 0x00000000, pfn 1 is at address 0x00001000, pfn 2 is at 0x00002000 and so on until we reach pfn 0xfffff at 0xfffff000. With 16KB pages pfs are -at 0x00004000, 0x00008000 ... 0xffffc000 and pfn goes from 0 to 0x3fffff. +at 0x00004000, 0x00008000 ... 0xffffc000 and pfn goes from 0 to 0x3ffff. As you can see, with 4KB pages the page base address uses bits 12-31 of the address, and this is why `PAGE_SHIFT` in this case is defined as 12 and diff --git a/Documentation/mm/process_addrs.rst b/Documentation/mm/process_addrs.rst index e8618fbc62c9ef..1d416658d7f59e 100644 --- a/Documentation/mm/process_addrs.rst +++ b/Documentation/mm/process_addrs.rst @@ -3,3 +3,853 @@ ================= Process Addresses ================= + +.. toctree:: + :maxdepth: 3 + + +Userland memory ranges are tracked by the kernel via Virtual Memory Areas or +'VMA's of type :c:struct:`!struct vm_area_struct`. + +Each VMA describes a virtually contiguous memory range with identical +attributes, each described by a :c:struct:`!struct vm_area_struct` +object. Userland access outside of VMAs is invalid except in the case where an +adjacent stack VMA could be extended to contain the accessed address. + +All VMAs are contained within one and only one virtual address space, described +by a :c:struct:`!struct mm_struct` object which is referenced by all tasks (that is, +threads) which share the virtual address space. We refer to this as the +:c:struct:`!mm`. + +Each mm object contains a maple tree data structure which describes all VMAs +within the virtual address space. + +.. note:: An exception to this is the 'gate' VMA which is provided by + architectures which use :c:struct:`!vsyscall` and is a global static + object which does not belong to any specific mm. + +------- +Locking +------- + +The kernel is designed to be highly scalable against concurrent read operations +on VMA **metadata** so a complicated set of locks are required to ensure memory +corruption does not occur. + +.. note:: Locking VMAs for their metadata does not have any impact on the memory + they describe nor the page tables that map them. + +Terminology +----------- + +* **mmap locks** - Each MM has a read/write semaphore :c:member:`!mmap_lock` + which locks at a process address space granularity which can be acquired via + :c:func:`!mmap_read_lock`, :c:func:`!mmap_write_lock` and variants. +* **VMA locks** - The VMA lock is at VMA granularity (of course) which behaves + as a read/write semaphore in practice. A VMA read lock is obtained via + :c:func:`!lock_vma_under_rcu` (and unlocked via :c:func:`!vma_end_read`) and a + write lock via :c:func:`!vma_start_write` (all VMA write locks are unlocked + automatically when the mmap write lock is released). To take a VMA write lock + you **must** have already acquired an :c:func:`!mmap_write_lock`. +* **rmap locks** - When trying to access VMAs through the reverse mapping via a + :c:struct:`!struct address_space` or :c:struct:`!struct anon_vma` object + (reachable from a folio via :c:member:`!folio->mapping`). VMAs must be stabilised via + :c:func:`!anon_vma_[try]lock_read` or :c:func:`!anon_vma_[try]lock_write` for + anonymous memory and :c:func:`!i_mmap_[try]lock_read` or + :c:func:`!i_mmap_[try]lock_write` for file-backed memory. We refer to these + locks as the reverse mapping locks, or 'rmap locks' for brevity. + +We discuss page table locks separately in the dedicated section below. + +The first thing **any** of these locks achieve is to **stabilise** the VMA +within the MM tree. That is, guaranteeing that the VMA object will not be +deleted from under you nor modified (except for some specific fields +described below). + +Stabilising a VMA also keeps the address space described by it around. + +Lock usage +---------- + +If you want to **read** VMA metadata fields or just keep the VMA stable, you +must do one of the following: + +* Obtain an mmap read lock at the MM granularity via :c:func:`!mmap_read_lock` (or a + suitable variant), unlocking it with a matching :c:func:`!mmap_read_unlock` when + you're done with the VMA, *or* +* Try to obtain a VMA read lock via :c:func:`!lock_vma_under_rcu`. This tries to + acquire the lock atomically so might fail, in which case fall-back logic is + required to instead obtain an mmap read lock if this returns :c:macro:`!NULL`, + *or* +* Acquire an rmap lock before traversing the locked interval tree (whether + anonymous or file-backed) to obtain the required VMA. + +If you want to **write** VMA metadata fields, then things vary depending on the +field (we explore each VMA field in detail below). For the majority you must: + +* Obtain an mmap write lock at the MM granularity via :c:func:`!mmap_write_lock` (or a + suitable variant), unlocking it with a matching :c:func:`!mmap_write_unlock` when + you're done with the VMA, *and* +* Obtain a VMA write lock via :c:func:`!vma_start_write` for each VMA you wish to + modify, which will be released automatically when :c:func:`!mmap_write_unlock` is + called. +* If you want to be able to write to **any** field, you must also hide the VMA + from the reverse mapping by obtaining an **rmap write lock**. + +VMA locks are special in that you must obtain an mmap **write** lock **first** +in order to obtain a VMA **write** lock. A VMA **read** lock however can be +obtained without any other lock (:c:func:`!lock_vma_under_rcu` will acquire then +release an RCU lock to lookup the VMA for you). + +This constrains the impact of writers on readers, as a writer can interact with +one VMA while a reader interacts with another simultaneously. + +.. note:: The primary users of VMA read locks are page fault handlers, which + means that without a VMA write lock, page faults will run concurrent with + whatever you are doing. + +Examining all valid lock states: + +.. table:: + + ========= ======== ========= ======= ===== =========== ========== + mmap lock VMA lock rmap lock Stable? Read? Write most? Write all? + ========= ======== ========= ======= ===== =========== ========== + \- \- \- N N N N + \- R \- Y Y N N + \- \- R/W Y Y N N + R/W \-/R \-/R/W Y Y N N + W W \-/R Y Y Y N + W W W Y Y Y Y + ========= ======== ========= ======= ===== =========== ========== + +.. warning:: While it's possible to obtain a VMA lock while holding an mmap read lock, + attempting to do the reverse is invalid as it can result in deadlock - if + another task already holds an mmap write lock and attempts to acquire a VMA + write lock that will deadlock on the VMA read lock. + +All of these locks behave as read/write semaphores in practice, so you can +obtain either a read or a write lock for each of these. + +.. note:: Generally speaking, a read/write semaphore is a class of lock which + permits concurrent readers. However a write lock can only be obtained + once all readers have left the critical region (and pending readers + made to wait). + + This renders read locks on a read/write semaphore concurrent with other + readers and write locks exclusive against all others holding the semaphore. + +VMA fields +^^^^^^^^^^ + +We can subdivide :c:struct:`!struct vm_area_struct` fields by their purpose, which makes it +easier to explore their locking characteristics: + +.. note:: We exclude VMA lock-specific fields here to avoid confusion, as these + are in effect an internal implementation detail. + +.. table:: Virtual layout fields + + ===================== ======================================== =========== + Field Description Write lock + ===================== ======================================== =========== + :c:member:`!vm_start` Inclusive start virtual address of range mmap write, + VMA describes. VMA write, + rmap write. + :c:member:`!vm_end` Exclusive end virtual address of range mmap write, + VMA describes. VMA write, + rmap write. + :c:member:`!vm_pgoff` Describes the page offset into the file, mmap write, + the original page offset within the VMA write, + virtual address space (prior to any rmap write. + :c:func:`!mremap`), or PFN if a PFN map + and the architecture does not support + :c:macro:`!CONFIG_ARCH_HAS_PTE_SPECIAL`. + ===================== ======================================== =========== + +These fields describes the size, start and end of the VMA, and as such cannot be +modified without first being hidden from the reverse mapping since these fields +are used to locate VMAs within the reverse mapping interval trees. + +.. table:: Core fields + + ============================ ======================================== ========================= + Field Description Write lock + ============================ ======================================== ========================= + :c:member:`!vm_mm` Containing mm_struct. None - written once on + initial map. + :c:member:`!vm_page_prot` Architecture-specific page table mmap write, VMA write. + protection bits determined from VMA + flags. + :c:member:`!vm_flags` Read-only access to VMA flags describing N/A + attributes of the VMA, in union with + private writable + :c:member:`!__vm_flags`. + :c:member:`!__vm_flags` Private, writable access to VMA flags mmap write, VMA write. + field, updated by + :c:func:`!vm_flags_*` functions. + :c:member:`!vm_file` If the VMA is file-backed, points to a None - written once on + struct file object describing the initial map. + underlying file, if anonymous then + :c:macro:`!NULL`. + :c:member:`!vm_ops` If the VMA is file-backed, then either None - Written once on + the driver or file-system provides a initial map by + :c:struct:`!struct vm_operations_struct` :c:func:`!f_ops->mmap()`. + object describing callbacks to be + invoked on VMA lifetime events. + :c:member:`!vm_private_data` A :c:member:`!void *` field for Handled by driver. + driver-specific metadata. + ============================ ======================================== ========================= + +These are the core fields which describe the MM the VMA belongs to and its attributes. + +.. table:: Config-specific fields + + ================================= ===================== ======================================== =============== + Field Configuration option Description Write lock + ================================= ===================== ======================================== =============== + :c:member:`!anon_name` CONFIG_ANON_VMA_NAME A field for storing a mmap write, + :c:struct:`!struct anon_vma_name` VMA write. + object providing a name for anonymous + mappings, or :c:macro:`!NULL` if none + is set or the VMA is file-backed. The + underlying object is reference counted + and can be shared across multiple VMAs + for scalability. + :c:member:`!swap_readahead_info` CONFIG_SWAP Metadata used by the swap mechanism mmap read, + to perform readahead. This field is swap-specific + accessed atomically. lock. + :c:member:`!vm_policy` CONFIG_NUMA :c:type:`!mempolicy` object which mmap write, + describes the NUMA behaviour of the VMA write. + VMA. The underlying object is reference + counted. + :c:member:`!numab_state` CONFIG_NUMA_BALANCING :c:type:`!vma_numab_state` object which mmap read, + describes the current state of numab-specific + NUMA balancing in relation to this VMA. lock. + Updated under mmap read lock by + :c:func:`!task_numa_work`. + :c:member:`!vm_userfaultfd_ctx` CONFIG_USERFAULTFD Userfaultfd context wrapper object of mmap write, + type :c:type:`!vm_userfaultfd_ctx`, VMA write. + either of zero size if userfaultfd is + disabled, or containing a pointer + to an underlying + :c:type:`!userfaultfd_ctx` object which + describes userfaultfd metadata. + ================================= ===================== ======================================== =============== + +These fields are present or not depending on whether the relevant kernel +configuration option is set. + +.. table:: Reverse mapping fields + + =================================== ========================================= ============================ + Field Description Write lock + =================================== ========================================= ============================ + :c:member:`!shared.rb` A red/black tree node used, if the mmap write, VMA write, + mapping is file-backed, to place the VMA i_mmap write. + in the + :c:member:`!struct address_space->i_mmap` + red/black interval tree. + :c:member:`!shared.rb_subtree_last` Metadata used for management of the mmap write, VMA write, + interval tree if the VMA is file-backed. i_mmap write. + :c:member:`!anon_vma_chain` List of pointers to both forked/CoW’d mmap read, anon_vma write. + :c:type:`!anon_vma` objects and + :c:member:`!vma->anon_vma` if it is + non-:c:macro:`!NULL`. + :c:member:`!anon_vma` :c:type:`!anon_vma` object used by When :c:macro:`NULL` and + anonymous folios mapped exclusively to setting non-:c:macro:`NULL`: + this VMA. Initially set by mmap read, page_table_lock. + :c:func:`!anon_vma_prepare` serialised + by the :c:macro:`!page_table_lock`. This When non-:c:macro:`NULL` and + is set as soon as any page is faulted in. setting :c:macro:`NULL`: + mmap write, VMA write, + anon_vma write. + =================================== ========================================= ============================ + +These fields are used to both place the VMA within the reverse mapping, and for +anonymous mappings, to be able to access both related :c:struct:`!struct anon_vma` objects +and the :c:struct:`!struct anon_vma` in which folios mapped exclusively to this VMA should +reside. + +.. note:: If a file-backed mapping is mapped with :c:macro:`!MAP_PRIVATE` set + then it can be in both the :c:type:`!anon_vma` and :c:type:`!i_mmap` + trees at the same time, so all of these fields might be utilised at + once. + +Page tables +----------- + +We won't speak exhaustively on the subject but broadly speaking, page tables map +virtual addresses to physical ones through a series of page tables, each of +which contain entries with physical addresses for the next page table level +(along with flags), and at the leaf level the physical addresses of the +underlying physical data pages or a special entry such as a swap entry, +migration entry or other special marker. Offsets into these pages are provided +by the virtual address itself. + +In Linux these are divided into five levels - PGD, P4D, PUD, PMD and PTE. Huge +pages might eliminate one or two of these levels, but when this is the case we +typically refer to the leaf level as the PTE level regardless. + +.. note:: In instances where the architecture supports fewer page tables than + five the kernel cleverly 'folds' page table levels, that is stubbing + out functions related to the skipped levels. This allows us to + conceptually act as if there were always five levels, even if the + compiler might, in practice, eliminate any code relating to missing + ones. + +There are four key operations typically performed on page tables: + +1. **Traversing** page tables - Simply reading page tables in order to traverse + them. This only requires that the VMA is kept stable, so a lock which + establishes this suffices for traversal (there are also lockless variants + which eliminate even this requirement, such as :c:func:`!gup_fast`). +2. **Installing** page table mappings - Whether creating a new mapping or + modifying an existing one in such a way as to change its identity. This + requires that the VMA is kept stable via an mmap or VMA lock (explicitly not + rmap locks). +3. **Zapping/unmapping** page table entries - This is what the kernel calls + clearing page table mappings at the leaf level only, whilst leaving all page + tables in place. This is a very common operation in the kernel performed on + file truncation, the :c:macro:`!MADV_DONTNEED` operation via + :c:func:`!madvise`, and others. This is performed by a number of functions + including :c:func:`!unmap_mapping_range` and :c:func:`!unmap_mapping_pages`. + The VMA need only be kept stable for this operation. +4. **Freeing** page tables - When finally the kernel removes page tables from a + userland process (typically via :c:func:`!free_pgtables`) extreme care must + be taken to ensure this is done safely, as this logic finally frees all page + tables in the specified range, ignoring existing leaf entries (it assumes the + caller has both zapped the range and prevented any further faults or + modifications within it). + +.. note:: Modifying mappings for reclaim or migration is performed under rmap + lock as it, like zapping, does not fundamentally modify the identity + of what is being mapped. + +**Traversing** and **zapping** ranges can be performed holding any one of the +locks described in the terminology section above - that is the mmap lock, the +VMA lock or either of the reverse mapping locks. + +That is - as long as you keep the relevant VMA **stable** - you are good to go +ahead and perform these operations on page tables (though internally, kernel +operations that perform writes also acquire internal page table locks to +serialise - see the page table implementation detail section for more details). + +When **installing** page table entries, the mmap or VMA lock must be held to +keep the VMA stable. We explore why this is in the page table locking details +section below. + +.. warning:: Page tables are normally only traversed in regions covered by VMAs. + If you want to traverse page tables in areas that might not be + covered by VMAs, heavier locking is required. + See :c:func:`!walk_page_range_novma` for details. + +**Freeing** page tables is an entirely internal memory management operation and +has special requirements (see the page freeing section below for more details). + +.. warning:: When **freeing** page tables, it must not be possible for VMAs + containing the ranges those page tables map to be accessible via + the reverse mapping. + + The :c:func:`!free_pgtables` function removes the relevant VMAs + from the reverse mappings, but no other VMAs can be permitted to be + accessible and span the specified range. + +Lock ordering +------------- + +As we have multiple locks across the kernel which may or may not be taken at the +same time as explicit mm or VMA locks, we have to be wary of lock inversion, and +the **order** in which locks are acquired and released becomes very important. + +.. note:: Lock inversion occurs when two threads need to acquire multiple locks, + but in doing so inadvertently cause a mutual deadlock. + + For example, consider thread 1 which holds lock A and tries to acquire lock B, + while thread 2 holds lock B and tries to acquire lock A. + + Both threads are now deadlocked on each other. However, had they attempted to + acquire locks in the same order, one would have waited for the other to + complete its work and no deadlock would have occurred. + +The opening comment in :c:macro:`!mm/rmap.c` describes in detail the required +ordering of locks within memory management code: + +.. code-block:: + + inode->i_rwsem (while writing or truncating, not reading or faulting) + mm->mmap_lock + mapping->invalidate_lock (in filemap_fault) + folio_lock + hugetlbfs_i_mmap_rwsem_key (in huge_pmd_share, see hugetlbfs below) + vma_start_write + mapping->i_mmap_rwsem + anon_vma->rwsem + mm->page_table_lock or pte_lock + swap_lock (in swap_duplicate, swap_info_get) + mmlist_lock (in mmput, drain_mmlist and others) + mapping->private_lock (in block_dirty_folio) + i_pages lock (widely used) + lruvec->lru_lock (in folio_lruvec_lock_irq) + inode->i_lock (in set_page_dirty's __mark_inode_dirty) + bdi.wb->list_lock (in set_page_dirty's __mark_inode_dirty) + sb_lock (within inode_lock in fs/fs-writeback.c) + i_pages lock (widely used, in set_page_dirty, + in arch-dependent flush_dcache_mmap_lock, + within bdi.wb->list_lock in __sync_single_inode) + +There is also a file-system specific lock ordering comment located at the top of +:c:macro:`!mm/filemap.c`: + +.. code-block:: + + ->i_mmap_rwsem (truncate_pagecache) + ->private_lock (__free_pte->block_dirty_folio) + ->swap_lock (exclusive_swap_page, others) + ->i_pages lock + + ->i_rwsem + ->invalidate_lock (acquired by fs in truncate path) + ->i_mmap_rwsem (truncate->unmap_mapping_range) + + ->mmap_lock + ->i_mmap_rwsem + ->page_table_lock or pte_lock (various, mainly in memory.c) + ->i_pages lock (arch-dependent flush_dcache_mmap_lock) + + ->mmap_lock + ->invalidate_lock (filemap_fault) + ->lock_page (filemap_fault, access_process_vm) + + ->i_rwsem (generic_perform_write) + ->mmap_lock (fault_in_readable->do_page_fault) + + bdi->wb.list_lock + sb_lock (fs/fs-writeback.c) + ->i_pages lock (__sync_single_inode) + + ->i_mmap_rwsem + ->anon_vma.lock (vma_merge) + + ->anon_vma.lock + ->page_table_lock or pte_lock (anon_vma_prepare and various) + + ->page_table_lock or pte_lock + ->swap_lock (try_to_unmap_one) + ->private_lock (try_to_unmap_one) + ->i_pages lock (try_to_unmap_one) + ->lruvec->lru_lock (follow_page_mask->mark_page_accessed) + ->lruvec->lru_lock (check_pte_range->folio_isolate_lru) + ->private_lock (folio_remove_rmap_pte->set_page_dirty) + ->i_pages lock (folio_remove_rmap_pte->set_page_dirty) + bdi.wb->list_lock (folio_remove_rmap_pte->set_page_dirty) + ->inode->i_lock (folio_remove_rmap_pte->set_page_dirty) + bdi.wb->list_lock (zap_pte_range->set_page_dirty) + ->inode->i_lock (zap_pte_range->set_page_dirty) + ->private_lock (zap_pte_range->block_dirty_folio) + +Please check the current state of these comments which may have changed since +the time of writing of this document. + +------------------------------ +Locking Implementation Details +------------------------------ + +.. warning:: Locking rules for PTE-level page tables are very different from + locking rules for page tables at other levels. + +Page table locking details +-------------------------- + +In addition to the locks described in the terminology section above, we have +additional locks dedicated to page tables: + +* **Higher level page table locks** - Higher level page tables, that is PGD, P4D + and PUD each make use of the process address space granularity + :c:member:`!mm->page_table_lock` lock when modified. + +* **Fine-grained page table locks** - PMDs and PTEs each have fine-grained locks + either kept within the folios describing the page tables or allocated + separated and pointed at by the folios if :c:macro:`!ALLOC_SPLIT_PTLOCKS` is + set. The PMD spin lock is obtained via :c:func:`!pmd_lock`, however PTEs are + mapped into higher memory (if a 32-bit system) and carefully locked via + :c:func:`!pte_offset_map_lock`. + +These locks represent the minimum required to interact with each page table +level, but there are further requirements. + +Importantly, note that on a **traversal** of page tables, sometimes no such +locks are taken. However, at the PTE level, at least concurrent page table +deletion must be prevented (using RCU) and the page table must be mapped into +high memory, see below. + +Whether care is taken on reading the page table entries depends on the +architecture, see the section on atomicity below. + +Locking rules +^^^^^^^^^^^^^ + +We establish basic locking rules when interacting with page tables: + +* When changing a page table entry the page table lock for that page table + **must** be held, except if you can safely assume nobody can access the page + tables concurrently (such as on invocation of :c:func:`!free_pgtables`). +* Reads from and writes to page table entries must be *appropriately* + atomic. See the section on atomicity below for details. +* Populating previously empty entries requires that the mmap or VMA locks are + held (read or write), doing so with only rmap locks would be dangerous (see + the warning below). +* As mentioned previously, zapping can be performed while simply keeping the VMA + stable, that is holding any one of the mmap, VMA or rmap locks. + +.. warning:: Populating previously empty entries is dangerous as, when unmapping + VMAs, :c:func:`!vms_clear_ptes` has a window of time between + zapping (via :c:func:`!unmap_vmas`) and freeing page tables (via + :c:func:`!free_pgtables`), where the VMA is still visible in the + rmap tree. :c:func:`!free_pgtables` assumes that the zap has + already been performed and removes PTEs unconditionally (along with + all other page tables in the freed range), so installing new PTE + entries could leak memory and also cause other unexpected and + dangerous behaviour. + +There are additional rules applicable when moving page tables, which we discuss +in the section on this topic below. + +PTE-level page tables are different from page tables at other levels, and there +are extra requirements for accessing them: + +* On 32-bit architectures, they may be in high memory (meaning they need to be + mapped into kernel memory to be accessible). +* When empty, they can be unlinked and RCU-freed while holding an mmap lock or + rmap lock for reading in combination with the PTE and PMD page table locks. + In particular, this happens in :c:func:`!retract_page_tables` when handling + :c:macro:`!MADV_COLLAPSE`. + So accessing PTE-level page tables requires at least holding an RCU read lock; + but that only suffices for readers that can tolerate racing with concurrent + page table updates such that an empty PTE is observed (in a page table that + has actually already been detached and marked for RCU freeing) while another + new page table has been installed in the same location and filled with + entries. Writers normally need to take the PTE lock and revalidate that the + PMD entry still refers to the same PTE-level page table. + +To access PTE-level page tables, a helper like :c:func:`!pte_offset_map_lock` or +:c:func:`!pte_offset_map` can be used depending on stability requirements. +These map the page table into kernel memory if required, take the RCU lock, and +depending on variant, may also look up or acquire the PTE lock. +See the comment on :c:func:`!__pte_offset_map_lock`. + +Atomicity +^^^^^^^^^ + +Regardless of page table locks, the MMU hardware concurrently updates accessed +and dirty bits (perhaps more, depending on architecture). Additionally, page +table traversal operations in parallel (though holding the VMA stable) and +functionality like GUP-fast locklessly traverses (that is reads) page tables, +without even keeping the VMA stable at all. + +When performing a page table traversal and keeping the VMA stable, whether a +read must be performed once and only once or not depends on the architecture +(for instance x86-64 does not require any special precautions). + +If a write is being performed, or if a read informs whether a write takes place +(on an installation of a page table entry say, for instance in +:c:func:`!__pud_install`), special care must always be taken. In these cases we +can never assume that page table locks give us entirely exclusive access, and +must retrieve page table entries once and only once. + +If we are reading page table entries, then we need only ensure that the compiler +does not rearrange our loads. This is achieved via :c:func:`!pXXp_get` +functions - :c:func:`!pgdp_get`, :c:func:`!p4dp_get`, :c:func:`!pudp_get`, +:c:func:`!pmdp_get`, and :c:func:`!ptep_get`. + +Each of these uses :c:func:`!READ_ONCE` to guarantee that the compiler reads +the page table entry only once. + +However, if we wish to manipulate an existing page table entry and care about +the previously stored data, we must go further and use an hardware atomic +operation as, for example, in :c:func:`!ptep_get_and_clear`. + +Equally, operations that do not rely on the VMA being held stable, such as +GUP-fast (see :c:func:`!gup_fast` and its various page table level handlers like +:c:func:`!gup_fast_pte_range`), must very carefully interact with page table +entries, using functions such as :c:func:`!ptep_get_lockless` and equivalent for +higher level page table levels. + +Writes to page table entries must also be appropriately atomic, as established +by :c:func:`!set_pXX` functions - :c:func:`!set_pgd`, :c:func:`!set_p4d`, +:c:func:`!set_pud`, :c:func:`!set_pmd`, and :c:func:`!set_pte`. + +Equally functions which clear page table entries must be appropriately atomic, +as in :c:func:`!pXX_clear` functions - :c:func:`!pgd_clear`, +:c:func:`!p4d_clear`, :c:func:`!pud_clear`, :c:func:`!pmd_clear`, and +:c:func:`!pte_clear`. + +Page table installation +^^^^^^^^^^^^^^^^^^^^^^^ + +Page table installation is performed with the VMA held stable explicitly by an +mmap or VMA lock in read or write mode (see the warning in the locking rules +section for details as to why). + +When allocating a P4D, PUD or PMD and setting the relevant entry in the above +PGD, P4D or PUD, the :c:member:`!mm->page_table_lock` must be held. This is +acquired in :c:func:`!__p4d_alloc`, :c:func:`!__pud_alloc` and +:c:func:`!__pmd_alloc` respectively. + +.. note:: :c:func:`!__pmd_alloc` actually invokes :c:func:`!pud_lock` and + :c:func:`!pud_lockptr` in turn, however at the time of writing it ultimately + references the :c:member:`!mm->page_table_lock`. + +Allocating a PTE will either use the :c:member:`!mm->page_table_lock` or, if +:c:macro:`!USE_SPLIT_PMD_PTLOCKS` is defined, a lock embedded in the PMD +physical page metadata in the form of a :c:struct:`!struct ptdesc`, acquired by +:c:func:`!pmd_ptdesc` called from :c:func:`!pmd_lock` and ultimately +:c:func:`!__pte_alloc`. + +Finally, modifying the contents of the PTE requires special treatment, as the +PTE page table lock must be acquired whenever we want stable and exclusive +access to entries contained within a PTE, especially when we wish to modify +them. + +This is performed via :c:func:`!pte_offset_map_lock` which carefully checks to +ensure that the PTE hasn't changed from under us, ultimately invoking +:c:func:`!pte_lockptr` to obtain a spin lock at PTE granularity contained within +the :c:struct:`!struct ptdesc` associated with the physical PTE page. The lock +must be released via :c:func:`!pte_unmap_unlock`. + +.. note:: There are some variants on this, such as + :c:func:`!pte_offset_map_rw_nolock` when we know we hold the PTE stable but + for brevity we do not explore this. See the comment for + :c:func:`!__pte_offset_map_lock` for more details. + +When modifying data in ranges we typically only wish to allocate higher page +tables as necessary, using these locks to avoid races or overwriting anything, +and set/clear data at the PTE level as required (for instance when page faulting +or zapping). + +A typical pattern taken when traversing page table entries to install a new +mapping is to optimistically determine whether the page table entry in the table +above is empty, if so, only then acquiring the page table lock and checking +again to see if it was allocated underneath us. + +This allows for a traversal with page table locks only being taken when +required. An example of this is :c:func:`!__pud_alloc`. + +At the leaf page table, that is the PTE, we can't entirely rely on this pattern +as we have separate PMD and PTE locks and a THP collapse for instance might have +eliminated the PMD entry as well as the PTE from under us. + +This is why :c:func:`!__pte_offset_map_lock` locklessly retrieves the PMD entry +for the PTE, carefully checking it is as expected, before acquiring the +PTE-specific lock, and then *again* checking that the PMD entry is as expected. + +If a THP collapse (or similar) were to occur then the lock on both pages would +be acquired, so we can ensure this is prevented while the PTE lock is held. + +Installing entries this way ensures mutual exclusion on write. + +Page table freeing +^^^^^^^^^^^^^^^^^^ + +Tearing down page tables themselves is something that requires significant +care. There must be no way that page tables designated for removal can be +traversed or referenced by concurrent tasks. + +It is insufficient to simply hold an mmap write lock and VMA lock (which will +prevent racing faults, and rmap operations), as a file-backed mapping can be +truncated under the :c:struct:`!struct address_space->i_mmap_rwsem` alone. + +As a result, no VMA which can be accessed via the reverse mapping (either +through the :c:struct:`!struct anon_vma->rb_root` or the :c:member:`!struct +address_space->i_mmap` interval trees) can have its page tables torn down. + +The operation is typically performed via :c:func:`!free_pgtables`, which assumes +either the mmap write lock has been taken (as specified by its +:c:member:`!mm_wr_locked` parameter), or that the VMA is already unreachable. + +It carefully removes the VMA from all reverse mappings, however it's important +that no new ones overlap these or any route remain to permit access to addresses +within the range whose page tables are being torn down. + +Additionally, it assumes that a zap has already been performed and steps have +been taken to ensure that no further page table entries can be installed between +the zap and the invocation of :c:func:`!free_pgtables`. + +Since it is assumed that all such steps have been taken, page table entries are +cleared without page table locks (in the :c:func:`!pgd_clear`, :c:func:`!p4d_clear`, +:c:func:`!pud_clear`, and :c:func:`!pmd_clear` functions. + +.. note:: It is possible for leaf page tables to be torn down independent of + the page tables above it as is done by + :c:func:`!retract_page_tables`, which is performed under the i_mmap + read lock, PMD, and PTE page table locks, without this level of care. + +Page table moving +^^^^^^^^^^^^^^^^^ + +Some functions manipulate page table levels above PMD (that is PUD, P4D and PGD +page tables). Most notable of these is :c:func:`!mremap`, which is capable of +moving higher level page tables. + +In these instances, it is required that **all** locks are taken, that is +the mmap lock, the VMA lock and the relevant rmap locks. + +You can observe this in the :c:func:`!mremap` implementation in the functions +:c:func:`!take_rmap_locks` and :c:func:`!drop_rmap_locks` which perform the rmap +side of lock acquisition, invoked ultimately by :c:func:`!move_page_tables`. + +VMA lock internals +------------------ + +Overview +^^^^^^^^ + +VMA read locking is entirely optimistic - if the lock is contended or a competing +write has started, then we do not obtain a read lock. + +A VMA **read** lock is obtained by :c:func:`!lock_vma_under_rcu`, which first +calls :c:func:`!rcu_read_lock` to ensure that the VMA is looked up in an RCU +critical section, then attempts to VMA lock it via :c:func:`!vma_start_read`, +before releasing the RCU lock via :c:func:`!rcu_read_unlock`. + +VMA read locks hold the read lock on the :c:member:`!vma->vm_lock` semaphore for +their duration and the caller of :c:func:`!lock_vma_under_rcu` must release it +via :c:func:`!vma_end_read`. + +VMA **write** locks are acquired via :c:func:`!vma_start_write` in instances where a +VMA is about to be modified, unlike :c:func:`!vma_start_read` the lock is always +acquired. An mmap write lock **must** be held for the duration of the VMA write +lock, releasing or downgrading the mmap write lock also releases the VMA write +lock so there is no :c:func:`!vma_end_write` function. + +Note that a semaphore write lock is not held across a VMA lock. Rather, a +sequence number is used for serialisation, and the write semaphore is only +acquired at the point of write lock to update this. + +This ensures the semantics we require - VMA write locks provide exclusive write +access to the VMA. + +Implementation details +^^^^^^^^^^^^^^^^^^^^^^ + +The VMA lock mechanism is designed to be a lightweight means of avoiding the use +of the heavily contended mmap lock. It is implemented using a combination of a +read/write semaphore and sequence numbers belonging to the containing +:c:struct:`!struct mm_struct` and the VMA. + +Read locks are acquired via :c:func:`!vma_start_read`, which is an optimistic +operation, i.e. it tries to acquire a read lock but returns false if it is +unable to do so. At the end of the read operation, :c:func:`!vma_end_read` is +called to release the VMA read lock. + +Invoking :c:func:`!vma_start_read` requires that :c:func:`!rcu_read_lock` has +been called first, establishing that we are in an RCU critical section upon VMA +read lock acquisition. Once acquired, the RCU lock can be released as it is only +required for lookup. This is abstracted by :c:func:`!lock_vma_under_rcu` which +is the interface a user should use. + +Writing requires the mmap to be write-locked and the VMA lock to be acquired via +:c:func:`!vma_start_write`, however the write lock is released by the termination or +downgrade of the mmap write lock so no :c:func:`!vma_end_write` is required. + +All this is achieved by the use of per-mm and per-VMA sequence counts, which are +used in order to reduce complexity, especially for operations which write-lock +multiple VMAs at once. + +If the mm sequence count, :c:member:`!mm->mm_lock_seq` is equal to the VMA +sequence count :c:member:`!vma->vm_lock_seq` then the VMA is write-locked. If +they differ, then it is not. + +Each time the mmap write lock is released in :c:func:`!mmap_write_unlock` or +:c:func:`!mmap_write_downgrade`, :c:func:`!vma_end_write_all` is invoked which +also increments :c:member:`!mm->mm_lock_seq` via +:c:func:`!mm_lock_seqcount_end`. + +This way, we ensure that, regardless of the VMA's sequence number, a write lock +is never incorrectly indicated and that when we release an mmap write lock we +efficiently release **all** VMA write locks contained within the mmap at the +same time. + +Since the mmap write lock is exclusive against others who hold it, the automatic +release of any VMA locks on its release makes sense, as you would never want to +keep VMAs locked across entirely separate write operations. It also maintains +correct lock ordering. + +Each time a VMA read lock is acquired, we acquire a read lock on the +:c:member:`!vma->vm_lock` read/write semaphore and hold it, while checking that +the sequence count of the VMA does not match that of the mm. + +If it does, the read lock fails. If it does not, we hold the lock, excluding +writers, but permitting other readers, who will also obtain this lock under RCU. + +Importantly, maple tree operations performed in :c:func:`!lock_vma_under_rcu` +are also RCU safe, so the whole read lock operation is guaranteed to function +correctly. + +On the write side, we acquire a write lock on the :c:member:`!vma->vm_lock` +read/write semaphore, before setting the VMA's sequence number under this lock, +also simultaneously holding the mmap write lock. + +This way, if any read locks are in effect, :c:func:`!vma_start_write` will sleep +until these are finished and mutual exclusion is achieved. + +After setting the VMA's sequence number, the lock is released, avoiding +complexity with a long-term held write lock. + +This clever combination of a read/write semaphore and sequence count allows for +fast RCU-based per-VMA lock acquisition (especially on page fault, though +utilised elsewhere) with minimal complexity around lock ordering. + +mmap write lock downgrading +--------------------------- + +When an mmap write lock is held one has exclusive access to resources within the +mmap (with the usual caveats about requiring VMA write locks to avoid races with +tasks holding VMA read locks). + +It is then possible to **downgrade** from a write lock to a read lock via +:c:func:`!mmap_write_downgrade` which, similar to :c:func:`!mmap_write_unlock`, +implicitly terminates all VMA write locks via :c:func:`!vma_end_write_all`, but +importantly does not relinquish the mmap lock while downgrading, therefore +keeping the locked virtual address space stable. + +An interesting consequence of this is that downgraded locks are exclusive +against any other task possessing a downgraded lock (since a racing task would +have to acquire a write lock first to downgrade it, and the downgraded lock +prevents a new write lock from being obtained until the original lock is +released). + +For clarity, we map read (R)/downgraded write (D)/write (W) locks against one +another showing which locks exclude the others: + +.. list-table:: Lock exclusivity + :widths: 5 5 5 5 + :header-rows: 1 + :stub-columns: 1 + + * - + - R + - D + - W + * - R + - N + - N + - Y + * - D + - N + - Y + - Y + * - W + - Y + - Y + - Y + +Here a Y indicates the locks in the matching row/column are mutually exclusive, +and N indicates that they are not. + +Stack expansion +--------------- + +Stack expansion throws up additional complexities in that we cannot permit there +to be racing page faults, as a result we invoke :c:func:`!vma_start_write` to +prevent this in :c:func:`!expand_downwards` or :c:func:`!expand_upwards`. diff --git a/Documentation/mm/slub.rst b/Documentation/mm/slub.rst index 60d350d08362b0..84ca1dc94e5ee0 100644 --- a/Documentation/mm/slub.rst +++ b/Documentation/mm/slub.rst @@ -175,6 +175,15 @@ can be influenced by kernel parameters: ``slab_max_order`` to 0, what cause minimum possible order of slabs allocation. +``slab_strict_numa`` + Enables the application of memory policies on each + allocation. This results in more accurate placement of + objects which may result in the reduction of accesses + to remote nodes. The default is to only apply memory + policies at the folio level when a new folio is acquired + or a folio is retrieved from the lists. Enabling this + option reduces the fastpath performance of the slab allocator. + SLUB Debug output ================= diff --git a/Documentation/mm/split_page_table_lock.rst b/Documentation/mm/split_page_table_lock.rst index e4f6972eb6c04b..581446d4a4ebaf 100644 --- a/Documentation/mm/split_page_table_lock.rst +++ b/Documentation/mm/split_page_table_lock.rst @@ -16,9 +16,13 @@ There are helpers to lock/unlock a table and other accessor functions: - pte_offset_map_lock() maps PTE and takes PTE table lock, returns pointer to PTE with pointer to its PTE table lock, or returns NULL if no PTE table; - - pte_offset_map_nolock() + - pte_offset_map_ro_nolock() maps PTE, returns pointer to PTE with pointer to its PTE table lock (not taken), or returns NULL if no PTE table; + - pte_offset_map_rw_nolock() + maps PTE, returns pointer to PTE with pointer to its PTE table + lock (not taken) and the value of its pmd entry, or returns NULL + if no PTE table; - pte_offset_map() maps PTE, returns pointer to PTE, or returns NULL if no PTE table; - pte_unmap() diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index f2894ca35de840..8feefeae5376c8 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -85,6 +85,36 @@ definitions: This may happen for example if dpll device was previously locked on an input pin of type PIN_TYPE_SYNCE_ETH_PORT. render-max: true + - + type: enum + name: clock-quality-level + doc: | + level of quality of a clock device. This mainly applies when + the dpll lock-status is DPLL_LOCK_STATUS_HOLDOVER. + The current list is defined according to the table 11-7 contained + in ITU-T G.8264/Y.1364 document. One may extend this list freely + by other ITU-T defined clock qualities, or different ones defined + by another standardization body (for those, please use + different prefix). + entries: + - + name: itu-opt1-prc + value: 1 + - + name: itu-opt1-ssu-a + - + name: itu-opt1-ssu-b + - + name: itu-opt1-eec1 + - + name: itu-opt1-prtc + - + name: itu-opt1-eprtc + - + name: itu-opt1-eeec + - + name: itu-opt1-eprc + render-max: true - type: const name: temp-divider @@ -252,6 +282,17 @@ attribute-sets: name: lock-status-error type: u32 enum: lock-status-error + - + name: clock-quality-level + type: u32 + enum: clock-quality-level + multi-attr: true + doc: | + Level of quality of a clock device. This mainly applies when + the dpll lock-status is DPLL_LOCK_STATUS_HOLDOVER. This could + be put to message multiple times to indicate possible parallel + quality levels (e.g. one specified by ITU option 1 and another + one specified by option 2). - name: pin enum-name: dpll_a_pin diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 6a050d755b9cb4..93369f0eb81628 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -96,7 +96,12 @@ attribute-sets: name: bits type: nest nested-attributes: bitset-bits - + - + name: value + type: binary + - + name: mask + type: binary - name: string attributes: @@ -1951,3 +1956,7 @@ operations: - upstream-sfp-name - downstream-sfp-name dump: *phy-get-op + - + name: phy-ntf + doc: Notification for change in PHY devices. + notify: phy-get diff --git a/Documentation/netlink/specs/net_shaper.yaml b/Documentation/netlink/specs/net_shaper.yaml new file mode 100644 index 00000000000000..8ebad0d02904f9 --- /dev/null +++ b/Documentation/netlink/specs/net_shaper.yaml @@ -0,0 +1,362 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +name: net-shaper + +doc: | + Networking HW rate limiting configuration. + + This API allows configuring HW shapers available on the network + devices at different levels (queues, network device) and allows + arbitrary manipulation of the scheduling tree of the involved + shapers. + + Each @shaper is identified within the given device, by a @handle, + comprising both a @scope and an @id. + + Depending on the @scope value, the shapers are attached to specific + HW objects (queues, devices) or, for @node scope, represent a + scheduling group, that can be placed in an arbitrary location of + the scheduling tree. + + Shapers can be created with two different operations: the @set + operation, to create and update a single "attached" shaper, and + the @group operation, to create and update a scheduling + group. Only the @group operation can create @node scope shapers. + + Existing shapers can be deleted/reset via the @delete operation. + + The user can query the running configuration via the @get operation. + + Different devices can provide different feature sets, e.g. with no + support for complex scheduling hierarchy, or for some shaping + parameters. The user can introspect the HW capabilities via the + @cap-get operation. + +definitions: + - + type: enum + name: scope + doc: Defines the shaper @id interpretation. + render-max: true + entries: + - name: unspec + doc: The scope is not specified. + - + name: netdev + doc: The main shaper for the given network device. + - + name: queue + doc: | + The shaper is attached to the given device queue, + the @id represents the queue number. + - + name: node + doc: | + The shaper allows grouping of queues or other + node shapers; can be nested in either @netdev + shapers or other @node shapers, allowing placement + in any location of the scheduling tree, except + leaves and root. + - + type: enum + name: metric + doc: Different metric supported by the shaper. + entries: + - + name: bps + doc: Shaper operates on a bits per second basis. + - + name: pps + doc: Shaper operates on a packets per second basis. + +attribute-sets: + - + name: net-shaper + attributes: + - + name: handle + type: nest + nested-attributes: handle + doc: Unique identifier for the given shaper inside the owning device. + - + name: metric + type: u32 + enum: metric + doc: Metric used by the given shaper for bw-min, bw-max and burst. + - + name: bw-min + type: uint + doc: Guaranteed bandwidth for the given shaper. + - + name: bw-max + type: uint + doc: Maximum bandwidth for the given shaper or 0 when unlimited. + - + name: burst + type: uint + doc: | + Maximum burst-size for shaping. Should not be interpreted + as a quantum. + - + name: priority + type: u32 + doc: | + Scheduling priority for the given shaper. The priority + scheduling is applied to sibling shapers. + - + name: weight + type: u32 + doc: | + Relative weight for round robin scheduling of the + given shaper. + The scheduling is applied to all sibling shapers + with the same priority. + - + name: ifindex + type: u32 + doc: Interface index owning the specified shaper. + - + name: parent + type: nest + nested-attributes: handle + doc: | + Identifier for the parent of the affected shaper. + Only needed for @group operation. + - + name: leaves + type: nest + multi-attr: true + nested-attributes: leaf-info + doc: | + Describes a set of leaves shapers for a @group operation. + - + name: handle + attributes: + - + name: scope + type: u32 + enum: scope + doc: Defines the shaper @id interpretation. + - + name: id + type: u32 + doc: | + Numeric identifier of a shaper. The id semantic depends on + the scope. For @queue scope it's the queue id and for @node + scope it's the node identifier. + - + name: leaf-info + subset-of: net-shaper + attributes: + - + name: handle + - + name: priority + - + name: weight + - + name: caps + attributes: + - + name: ifindex + type: u32 + doc: Interface index queried for shapers capabilities. + - + name: scope + type: u32 + enum: scope + doc: The scope to which the queried capabilities apply. + - + name: support-metric-bps + type: flag + doc: The device accepts 'bps' metric for bw-min, bw-max and burst. + - + name: support-metric-pps + type: flag + doc: The device accepts 'pps' metric for bw-min, bw-max and burst. + - + name: support-nesting + type: flag + doc: | + The device supports nesting shaper belonging to this scope + below 'node' scoped shapers. Only 'queue' and 'node' + scope can have flag 'support-nesting'. + - + name: support-bw-min + type: flag + doc: The device supports a minimum guaranteed B/W. + - + name: support-bw-max + type: flag + doc: The device supports maximum B/W shaping. + - + name: support-burst + type: flag + doc: The device supports a maximum burst size. + - + name: support-priority + type: flag + doc: The device supports priority scheduling. + - + name: support-weight + type: flag + doc: The device supports weighted round robin scheduling. + +operations: + list: + - + name: get + doc: | + Get information about a shaper for a given device. + attribute-set: net-shaper + + do: + pre: net-shaper-nl-pre-doit + post: net-shaper-nl-post-doit + request: + attributes: &ns-binding + - ifindex + - handle + reply: + attributes: &ns-attrs + - ifindex + - parent + - handle + - metric + - bw-min + - bw-max + - burst + - priority + - weight + + dump: + pre: net-shaper-nl-pre-dumpit + post: net-shaper-nl-post-dumpit + request: + attributes: + - ifindex + reply: + attributes: *ns-attrs + - + name: set + doc: | + Create or update the specified shaper. + The set operation can't be used to create a @node scope shaper, + use the @group operation instead. + attribute-set: net-shaper + flags: [ admin-perm ] + + do: + pre: net-shaper-nl-pre-doit + post: net-shaper-nl-post-doit + request: + attributes: + - ifindex + - handle + - metric + - bw-min + - bw-max + - burst + - priority + - weight + + - + name: delete + doc: | + Clear (remove) the specified shaper. When deleting + a @node shaper, reattach all the node's leaves to the + deleted node's parent. + If, after the removal, the parent shaper has no more + leaves and the parent shaper scope is @node, the parent + node is deleted, recursively. + When deleting a @queue shaper or a @netdev shaper, + the shaper disappears from the hierarchy, but the + queue/device can still send traffic: it has an implicit + node with infinite bandwidth. The queue's implicit node + feeds an implicit RR node at the root of the hierarchy. + attribute-set: net-shaper + flags: [ admin-perm ] + + do: + pre: net-shaper-nl-pre-doit + post: net-shaper-nl-post-doit + request: + attributes: *ns-binding + + - + name: group + doc: | + Create or update a scheduling group, attaching the specified + @leaves shapers under the specified node identified by @handle. + The @leaves shapers scope must be @queue and the node shaper + scope must be either @node or @netdev. + When the node shaper has @node scope, if the @handle @id is not + specified, a new shaper of such scope is created, otherwise the + specified node must already exist. + When updating an existing node shaper, the specified @leaves are + added to the existing node; such node will also retain any preexisting + leave. + The @parent handle for a new node shaper defaults to the parent + of all the leaves, provided all the leaves share the same parent. + Otherwise @parent handle must be specified. + The user can optionally provide shaping attributes for the node + shaper. + The operation is atomic, on failure no change is applied to + the device shaping configuration, otherwise the @node shaper + full identifier, comprising @binding and @handle, is provided + as the reply. + attribute-set: net-shaper + flags: [ admin-perm ] + + do: + pre: net-shaper-nl-pre-doit + post: net-shaper-nl-post-doit + request: + attributes: + - ifindex + - parent + - handle + - metric + - bw-min + - bw-max + - burst + - priority + - weight + - leaves + reply: + attributes: *ns-binding + + - + name: cap-get + doc: | + Get the shaper capabilities supported by the given device + for the specified scope. + attribute-set: caps + + do: + pre: net-shaper-nl-cap-pre-doit + post: net-shaper-nl-cap-post-doit + request: + attributes: + - ifindex + - scope + reply: + attributes: &cap-attrs + - ifindex + - scope + - support-metric-bps + - support-metric-pps + - support-nesting + - support-bw-min + - support-bw-max + - support-burst + - support-priority + - support-weight + + dump: + pre: net-shaper-nl-cap-pre-dumpit + post: net-shaper-nl-cap-post-dumpit + request: + attributes: + - ifindex + reply: + attributes: *cap-attrs diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 08412c279297bf..cbb544bd6c848c 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -248,6 +248,26 @@ attribute-sets: threaded mode. If NAPI is not in threaded mode (i.e. uses normal softirq context), the attribute will be absent. type: u32 + - + name: defer-hard-irqs + doc: The number of consecutive empty polls before IRQ deferral ends + and hardware IRQs are re-enabled. + type: u32 + checks: + max: s32-max + - + name: gro-flush-timeout + doc: The timeout, in nanoseconds, of when to trigger the NAPI watchdog + timer which schedules NAPI processing. Additionally, a non-zero + value will also prevent GRO from flushing recent super-frames at + the end of a NAPI cycle. This may add receive latency in exchange + for reducing the number of frames processed by the network stack. + type: uint + - + name: irq-suspend-timeout + doc: The timeout, in nanoseconds, of how long to suspend irq + processing, if event polling finds events + type: uint - name: queue attributes: @@ -636,6 +656,9 @@ operations: - ifindex - irq - pid + - defer-hard-irqs + - gro-flush-timeout + - irq-suspend-timeout dump: request: attributes: @@ -676,6 +699,18 @@ operations: reply: attributes: - id + - + name: napi-set + doc: Set configurable NAPI instance settings. + attribute-set: napi + flags: [ admin-perm ] + do: + request: + attributes: + - id + - defer-hard-irqs + - gro-flush-timeout + - irq-suspend-timeout kernel-family: headers: [ "linux/list.h"] diff --git a/Documentation/netlink/specs/rt_link.yaml b/Documentation/netlink/specs/rt_link.yaml index 0c4d5d40cae905..9ffa13b77dcf11 100644 --- a/Documentation/netlink/specs/rt_link.yaml +++ b/Documentation/netlink/specs/rt_link.yaml @@ -920,6 +920,13 @@ definitions: - name: l2 - name: l3 + - + name: netkit-scrub + type: enum + entries: + - name: none + - name: default + attribute-sets: - name: link-attrs @@ -1137,6 +1144,10 @@ attribute-sets: name: dpll-pin type: nest nested-attributes: link-dpll-pin-attrs + - + name: max-pacing-offload-horizon + type: uint + doc: EDT offload horizon supported by the device (in nsec). - name: af-spec-attrs attributes: @@ -2147,6 +2158,14 @@ attribute-sets: name: mode type: u32 enum: netkit-mode + - + name: scrub + type: u32 + enum: netkit-scrub + - + name: peer-scrub + type: u32 + enum: netkit-scrub sub-messages: - diff --git a/Documentation/netlink/specs/rt_neigh.yaml b/Documentation/netlink/specs/rt_neigh.yaml new file mode 100644 index 00000000000000..e670b6dc07be4f --- /dev/null +++ b/Documentation/netlink/specs/rt_neigh.yaml @@ -0,0 +1,442 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: rt-neigh +protocol: netlink-raw +protonum: 0 + +doc: + IP neighbour management over rtnetlink. + +definitions: + - + name: ndmsg + type: struct + members: + - + name: family + type: u8 + - + name: pad + type: pad + len: 3 + - + name: ifindex + type: s32 + - + name: state + type: u16 + enum: nud-state + - + name: flags + type: u8 + enum: ntf-flags + - + name: type + type: u8 + enum: rtm-type + - + name: ndtmsg + type: struct + members: + - + name: family + type: u8 + - + name: pad + type: pad + len: 3 + - + name: nud-state + type: flags + entries: + - incomplete + - reachable + - stale + - delay + - probe + - failed + - noarp + - permanent + - + name: ntf-flags + type: flags + entries: + - use + - self + - master + - proxy + - ext-learned + - offloaded + - sticky + - router + - + name: ntf-ext-flags + type: flags + entries: + - managed + - locked + - + name: rtm-type + type: enum + entries: + - unspec + - unicast + - local + - broadcast + - anycast + - multicast + - blackhole + - unreachable + - prohibit + - throw + - nat + - xresolve + - + name: nda-cacheinfo + type: struct + members: + - + name: confirmed + type: u32 + - + name: used + type: u32 + - + name: updated + type: u32 + - + name: refcnt + type: u32 + - + name: ndt-config + type: struct + members: + - + name: key-len + type: u16 + - + name: entry-size + type: u16 + - + name: entries + type: u32 + - + name: last-flush + type: u32 + - + name: last-rand + type: u32 + - + name: hash-rnd + type: u32 + - + name: hash-mask + type: u32 + - + name: hash-chain-gc + type: u32 + - + name: proxy-qlen + type: u32 + - + name: ndt-stats + type: struct + members: + - + name: allocs + type: u64 + - + name: destroys + type: u64 + - + name: hash-grows + type: u64 + - + name: res-failed + type: u64 + - + name: lookups + type: u64 + - + name: hits + type: u64 + - + name: rcv-probes-mcast + type: u64 + - + name: rcv-probes-ucast + type: u64 + - + name: periodic-gc-runs + type: u64 + - + name: forced-gc-runs + type: u64 + - + name: table-fulls + type: u64 + +attribute-sets: + - + name: neighbour-attrs + attributes: + - + name: unspec + type: binary + value: 0 + - + name: dst + type: binary + display-hint: ipv4 + - + name: lladr + type: binary + display-hint: mac + - + name: cacheinfo + type: binary + struct: nda-cacheinfo + - + name: probes + type: u32 + - + name: vlan + type: u16 + - + name: port + type: u16 + - + name: vni + type: u32 + - + name: ifindex + type: u32 + - + name: master + type: u32 + - + name: link-netnsid + type: s32 + - + name: src-vni + type: u32 + - + name: protocol + type: u8 + - + name: nh-id + type: u32 + - + name: fdb-ext-attrs + type: binary + - + name: flags-ext + type: u32 + enum: ntf-ext-flags + - + name: ndm-state-mask + type: u16 + - + name: ndm-flags-mask + type: u8 + - + name: ndt-attrs + attributes: + - + name: name + type: string + - + name: thresh1 + type: u32 + - + name: thresh2 + type: u32 + - + name: thresh3 + type: u32 + - + name: config + type: binary + struct: ndt-config + - + name: parms + type: nest + nested-attributes: ndtpa-attrs + - + name: stats + type: binary + struct: ndt-stats + - + name: gc-interval + type: u64 + - + name: pad + type: pad + - + name: ndtpa-attrs + attributes: + - + name: ifindex + type: u32 + - + name: refcnt + type: u32 + - + name: reachable-time + type: u64 + - + name: base-reachable-time + type: u64 + - + name: retrans-time + type: u64 + - + name: gc-staletime + type: u64 + - + name: delay-probe-time + type: u64 + - + name: queue-len + type: u32 + - + name: app-probes + type: u32 + - + name: ucast-probes + type: u32 + - + name: mcast-probes + type: u32 + - + name: anycast-delay + type: u64 + - + name: proxy-delay + type: u64 + - + name: proxy-qlen + type: u32 + - + name: locktime + type: u64 + - + name: queue-lenbytes + type: u32 + - + name: mcast-reprobes + type: u32 + - + name: pad + type: pad + - + name: interval-probe-time-ms + type: u64 + +operations: + enum-model: directional + list: + - + name: newneigh + doc: Add new neighbour entry + fixed-header: ndmsg + attribute-set: neighbour-attrs + do: + request: + value: 28 + attributes: &neighbour-all + - dst + - lladdr + - probes + - vlan + - port + - vni + - ifindex + - master + - protocol + - nh-id + - flags-ext + - fdb-ext-attrs + - + name: delneigh + doc: Remove an existing neighbour entry + fixed-header: ndmsg + attribute-set: neighbour-attrs + do: + request: + value: 29 + attributes: + - dst + - ifindex + - + name: delneigh-ntf + doc: Notify a neighbour deletion + value: 29 + notify: delneigh + fixed-header: ndmsg + - + name: getneigh + doc: Get or dump neighbour entries + fixed-header: ndmsg + attribute-set: neighbour-attrs + do: + request: + value: 30 + attributes: + - dst + reply: + value: 28 + attributes: *neighbour-all + dump: + request: + attributes: + - ifindex + - master + reply: + attributes: *neighbour-all + - + name: newneigh-ntf + doc: Notify a neighbour creation + value: 28 + notify: getneigh + fixed-header: ndmsg + - + name: getneightbl + doc: Get or dump neighbour tables + fixed-header: ndtmsg + attribute-set: ndt-attrs + dump: + request: + value: 66 + reply: + value: 64 + attributes: + - name + - thresh1 + - thresh2 + - thresh3 + - config + - parms + - stats + - gc-interval + - + name: setneightbl + doc: Set neighbour tables + fixed-header: ndtmsg + attribute-set: ndt-attrs + do: + request: + value: 67 + attributes: + - name + - thresh1 + - thresh2 + - thresh3 + - parms + - gc-interval + +mcast-groups: + list: + - + name: rtnlgrp-neigh + value: 3 diff --git a/Documentation/netlink/specs/rt_rule.yaml b/Documentation/netlink/specs/rt_rule.yaml new file mode 100644 index 00000000000000..03a8eef7952e85 --- /dev/null +++ b/Documentation/netlink/specs/rt_rule.yaml @@ -0,0 +1,242 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: rt-rule +protocol: netlink-raw +protonum: 0 + +doc: + FIB rule management over rtnetlink. + +definitions: + - + name: rtgenmsg + type: struct + members: + - + name: family + type: u8 + - + name: pad + type: pad + len: 3 + - + name: fib-rule-hdr + type: struct + members: + - + name: family + type: u8 + - + name: dst-len + type: u8 + - + name: src-len + type: u8 + - + name: tos + type: u8 + - + name: table + type: u8 + - + name: res1 + type: pad + len: 1 + - + name: res2 + type: pad + len: 1 + - + name: action + type: u8 + enum: fr-act + - + name: flags + type: u32 + - + name: fr-act + type: enum + entries: + - unspec + - to-tbl + - goto + - nop + - res3 + - res4 + - blackhole + - unreachable + - prohibit + - + name: fib-rule-port-range + type: struct + members: + - + name: start + type: u16 + - + name: end + type: u16 + - + name: fib-rule-uid-range + type: struct + members: + - + name: start + type: u32 + - + name: end + type: u32 + +attribute-sets: + - + name: fib-rule-attrs + attributes: + - + name: dst + type: u32 + - + name: src + type: u32 + - + name: iifname + type: string + - + name: goto + type: u32 + - + name: unused2 + type: pad + - + name: priority + type: u32 + - + name: unused3 + type: pad + - + name: unused4 + type: pad + - + name: unused5 + type: pad + - + name: fwmark + type: u32 + display-hint: hex + - + name: flow + type: u32 + - + name: tun-id + type: u64 + - + name: suppress-ifgroup + type: u32 + - + name: suppress-prefixlen + type: u32 + display-hint: hex + - + name: table + type: u32 + - + name: fwmask + type: u32 + display-hint: hex + - + name: oifname + type: string + - + name: pad + type: pad + - + name: l3mdev + type: u8 + - + name: uid-range + type: binary + struct: fib-rule-uid-range + - + name: protocol + type: u8 + - + name: ip-proto + type: u8 + - + name: sport-range + type: binary + struct: fib-rule-port-range + - + name: dport-range + type: binary + struct: fib-rule-port-range + - + name: dscp + type: u8 + +operations: + enum-model: directional + fixed-header: fib-rule-hdr + list: + - + name: newrule + doc: Add new FIB rule + attribute-set: fib-rule-attrs + do: + request: + value: 32 + attributes: &fib-rule-all + - iifname + - oifname + - priority + - fwmark + - flow + - tun-id + - fwmask + - table + - suppress-prefixlen + - suppress-ifgroup + - goto + - l3mdev + - uid-range + - protocol + - ip-proto + - sport-range + - dport-range + - dscp + - + name: newrule-ntf + doc: Notify a rule creation + value: 32 + notify: newrule + - + name: delrule + doc: Remove an existing FIB rule + attribute-set: fib-rule-attrs + do: + request: + value: 33 + attributes: *fib-rule-all + - + name: delrule-ntf + doc: Notify a rule deletion + value: 33 + notify: delrule + - + name: getrule + doc: Dump all FIB rules + attribute-set: fib-rule-attrs + dump: + request: + value: 34 + reply: + value: 32 + attributes: *fib-rule-all + +mcast-groups: + list: + - + name: rtnlgrp-ipv4-rule + value: 8 + - + name: rtnlgrp-ipv6-rule + value: 19 diff --git a/Documentation/netlink/specs/tc.yaml b/Documentation/netlink/specs/tc.yaml index b02d59a0349c44..aacccea5dfe42a 100644 --- a/Documentation/netlink/specs/tc.yaml +++ b/Documentation/netlink/specs/tc.yaml @@ -622,7 +622,7 @@ definitions: - name: max-P type: u32 - doc: probabilty, high resolution + doc: probability, high resolution - name: stats type: binary diff --git a/Documentation/networking/bareudp.rst b/Documentation/networking/bareudp.rst index b9d04ee6dac142..621cb9575c8f7d 100644 --- a/Documentation/networking/bareudp.rst +++ b/Documentation/networking/bareudp.rst @@ -6,16 +6,17 @@ Bare UDP Tunnelling Module Documentation There are various L3 encapsulation standards using UDP being discussed to leverage the UDP based load balancing capability of different networks. -MPLSoUDP (__ https://tools.ietf.org/html/rfc7510) is one among them. +MPLSoUDP (https://tools.ietf.org/html/rfc7510) is one among them. The Bareudp tunnel module provides a generic L3 encapsulation support for tunnelling different L3 protocols like MPLS, IP, NSH etc. inside a UDP tunnel. Special Handling ---------------- + The bareudp device supports special handling for MPLS & IP as they can have multiple ethertypes. -MPLS procotcol can have ethertypes ETH_P_MPLS_UC (unicast) & ETH_P_MPLS_MC (multicast). +The MPLS protocol can have ethertypes ETH_P_MPLS_UC (unicast) & ETH_P_MPLS_MC (multicast). IP protocol can have ethertypes ETH_P_IP (v4) & ETH_P_IPV6 (v6). This special handling can be enabled only for ethertypes ETH_P_IP & ETH_P_MPLS_UC with a flag called multiproto mode. @@ -52,7 +53,7 @@ be enabled explicitly with the "multiproto" flag. 3) Device Usage The bareudp device could be used along with OVS or flower filter in TC. -The OVS or TC flower layer must set the tunnel information in SKB dst field before -sending packet buffer to the bareudp device for transmission. On reception the -bareudp device extracts and stores the tunnel information in SKB dst field before +The OVS or TC flower layer must set the tunnel information in the SKB dst field before +sending the packet buffer to the bareudp device for transmission. On reception, the +bareUDP device extracts and stores the tunnel information in the SKB dst field before passing the packet buffer to the network stack. diff --git a/Documentation/networking/bonding.rst b/Documentation/networking/bonding.rst index e774b48de9f511..7c8d22d6868242 100644 --- a/Documentation/networking/bonding.rst +++ b/Documentation/networking/bonding.rst @@ -2916,6 +2916,17 @@ from the bond (``ifenslave -d bond0 eth0``). The bonding driver will then restore the MAC addresses that the slaves had before they were enslaved. +9. What bonding modes support native XDP? +------------------------------------------ + + * balance-rr (0) + * active-backup (1) + * balance-xor (2) + * 802.3ad (4) + +Note that the vlan+srcmac hash policy does not support native XDP. +For other bonding modes, the XDP program must be loaded with generic mode. + 16. Resources and Links ======================= diff --git a/Documentation/networking/cdc_mbim.rst b/Documentation/networking/cdc_mbim.rst index 37f968acc473a4..8404a3f794f37d 100644 --- a/Documentation/networking/cdc_mbim.rst +++ b/Documentation/networking/cdc_mbim.rst @@ -51,7 +51,7 @@ Such userspace applications includes, but are not limited to: - mbimcli (included with the libmbim [3] library), and - ModemManager [4] -Establishing a MBIM IP session reequires at least these actions by the +Establishing a MBIM IP session requires at least these actions by the management application: - open the control channel diff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst index 934752f675ba40..3c46a48d99ba1d 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst @@ -101,6 +101,37 @@ example, if Rx packets are 10 and Netdev (software statistics) displays rx_bytes as "X", then ethtool (hardware statistics) will display rx_bytes as "X+40" (4 bytes CRC x 10 packets). +ethtool reset +------------- +The driver supports 3 types of resets: + +- PF reset - resets only components associated with the given PF, does not + impact other PFs + +- CORE reset - whole adapter is affected, reset all PFs + +- GLOBAL reset - same as CORE but mac and phy components are also reinitialized + +These are mapped to ethtool reset flags as follow: + +- PF reset: + + # ethtool --reset irq dma filter offload + +- CORE reset: + + # ethtool --reset irq-shared dma-shared filter-shared offload-shared \ + ram-shared + +- GLOBAL reset: + + # ethtool --reset irq-shared dma-shared filter-shared offload-shared \ + mac-shared phy-shared ram-shared + +In switchdev mode you can reset a VF using port representor: + + # ethtool --reset irq dma filter offload + Viewing Link Messages --------------------- diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst index 1e196cb9ce2549..af7db0e91f6b4d 100644 --- a/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst +++ b/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst @@ -14,6 +14,7 @@ Contents - `Basic packet flow`_ - `Devlink health reporters`_ - `Quality of service`_ +- `RVU representors`_ Overview ======== @@ -340,3 +341,93 @@ Setup HTB offload # tc class add dev parent 1: classid 1:2 htb rate 10Gbit prio 2 quantum 188416 # tc class add dev parent 1: classid 1:3 htb rate 10Gbit prio 2 quantum 32768 + + +RVU Representors +================ + +RVU representor driver adds support for creation of representor devices for +RVU PFs' VFs in the system. Representor devices are created when user enables +the switchdev mode. +Switchdev mode can be enabled either before or after setting up SRIOV numVFs. +All representor devices share a single NIXLF but each has a dedicated Rx/Tx +queues. RVU PF representor driver registers a separate netdev for each +Rx/Tx queue pair. + +Current HW does not support built-in switch which can do L2 learning and +forwarding packets between representee and representor. Hence, packet path +between representee and it's representor is achieved by setting up appropriate +NPC MCAM filters. +Transmit packets matching these filters will be loopbacked through hardware +loopback channel/interface (i.e, instead of sending them out of MAC interface). +Which will again match the installed filters and will be forwarded. +This way representee => representor and representor => representee packet +path is achieved. These rules get installed when representors are created +and gets active/deactivate based on the representor/representee interface state. + +Usage example: + + - Change device to switchdev mode:: + + # devlink dev eswitch set pci/0002:1c:00.0 mode switchdev + + - List of representor devices on the system:: + + # ip link show + Rpf1vf0: mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether f6:43:83:ee:26:21 brd ff:ff:ff:ff:ff:ff + Rpf1vf1: mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 12:b2:54:0e:24:54 brd ff:ff:ff:ff:ff:ff + Rpf1vf2: mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 4a:12:c4:4c:32:62 brd ff:ff:ff:ff:ff:ff + Rpf1vf3: mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether ca:cb:68:0e:e2:6e brd ff:ff:ff:ff:ff:ff + Rpf2vf0: mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 06:cc:ad:b4:f0:93 brd ff:ff:ff:ff:ff:ff + + +To delete the representors devices from the system. Change the device to legacy mode. + + - Change device to legacy mode:: + + # devlink dev eswitch set pci/0002:1c:00.0 mode legacy + +RVU representors can be managed using devlink ports +(see :ref:`Documentation/networking/devlink/devlink-port.rst `) interface. + + - Show devlink ports of representors:: + + # devlink port + pci/0002:1c:00.0/0: type eth netdev Rpf1vf0 flavour physical port 0 splittable false + pci/0002:1c:00.0/1: type eth netdev Rpf1vf1 flavour pcivf controller 0 pfnum 1 vfnum 1 external false splittable false + pci/0002:1c:00.0/2: type eth netdev Rpf1vf2 flavour pcivf controller 0 pfnum 1 vfnum 2 external false splittable false + pci/0002:1c:00.0/3: type eth netdev Rpf1vf3 flavour pcivf controller 0 pfnum 1 vfnum 3 external false splittable false + +Function attributes +=================== + +The RVU representor support function attributes for representors. +Port function configuration of the representors are supported through devlink eswitch port. + +MAC address setup +----------------- + +RVU representor driver support devlink port function attr mechanism to setup MAC +address. (refer to Documentation/networking/devlink/devlink-port.rst) + + - To setup MAC address for port 2:: + + # devlink port function set pci/0002:1c:00.0/2 hw_addr 5c:a1:1b:5e:43:11 + # devlink port show pci/0002:1c:00.0/2 + pci/0002:1c:00.0/2: type eth netdev Rpf1vf2 flavour pcivf controller 0 pfnum 1 vfnum 2 external false splittable false + function: + hw_addr 5c:a1:1b:5e:43:11 + + +TC offload +========== + +The rvu representor driver implements support for offloading tc rules using port representors. + + - Drop packets with vlan id 3:: + + # tc filter add dev Rpf1vf0 protocol 802.1Q parent ffff: flower vlan_id 3 vlan_ethtype ipv4 skip_sw action drop + + - Redirect packets with vlan id 5 and IPv4 packets to eth1, after stripping vlan header.:: + + # tc filter add dev Rpf1vf0 ingress protocol 802.1Q flower vlan_id 5 vlan_ethtype ipv4 skip_sw action vlan pop action mirred ingress redirect dev eth1 diff --git a/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst b/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst index 32ff114f5c26a8..04e0595bb0a77e 100644 --- a/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst +++ b/Documentation/networking/device_drivers/ethernet/meta/fbnic.rst @@ -27,3 +27,46 @@ driver takes over. devlink dev info provides version information for all three components. In addition to the version the hg commit hash of the build is included as a separate entry. + +Statistics +---------- + +RPC (Rx parser) +~~~~~~~~~~~~~~~ + + - ``rpc_unkn_etype``: frames containing unknown EtherType + - ``rpc_unkn_ext_hdr``: frames containing unknown IPv6 extension header + - ``rpc_ipv4_frag``: frames containing IPv4 fragment + - ``rpc_ipv6_frag``: frames containing IPv6 fragment + - ``rpc_ipv4_esp``: frames with IPv4 ESP encapsulation + - ``rpc_ipv6_esp``: frames with IPv6 ESP encapsulation + - ``rpc_tcp_opt_err``: frames which encountered TCP option parsing error + - ``rpc_out_of_hdr_err``: frames where header was larger than parsable region + - ``ovr_size_err``: oversized frames + +PCIe +~~~~ + +The fbnic driver exposes PCIe hardware performance statistics through debugfs +(``pcie_stats``). These statistics provide insights into PCIe transaction +behavior and potential performance bottlenecks. + +1. PCIe Transaction Counters: + + These counters track PCIe transaction activity: + - ``pcie_ob_rd_tlp``: Outbound read Transaction Layer Packets count + - ``pcie_ob_rd_dword``: DWORDs transferred in outbound read transactions + - ``pcie_ob_wr_tlp``: Outbound write Transaction Layer Packets count + - ``pcie_ob_wr_dword``: DWORDs transferred in outbound write + transactions + - ``pcie_ob_cpl_tlp``: Outbound completion TLP count + - ``pcie_ob_cpl_dword``: DWORDs transferred in outbound completion TLPs + +2. PCIe Resource Monitoring: + + These counters indicate PCIe resource exhaustion events: + - ``pcie_ob_rd_no_tag``: Read requests dropped due to tag unavailability + - ``pcie_ob_rd_no_cpl_cred``: Read requests dropped due to completion + credit exhaustion + - ``pcie_ob_rd_no_np_cred``: Read requests dropped due to non-posted + credit exhaustion diff --git a/Documentation/networking/device_drivers/wwan/t7xx.rst b/Documentation/networking/device_drivers/wwan/t7xx.rst index f346f5f85f154e..e07de7700dfc95 100644 --- a/Documentation/networking/device_drivers/wwan/t7xx.rst +++ b/Documentation/networking/device_drivers/wwan/t7xx.rst @@ -7,12 +7,13 @@ ============================================ t7xx driver for MTK PCIe based T700 5G modem ============================================ -The t7xx driver is a WWAN PCIe host driver developed for linux or Chrome OS platforms -for data exchange over PCIe interface between Host platform & MediaTek's T700 5G modem. -The driver exposes an interface conforming to the MBIM protocol [1]. Any front end -application (e.g. Modem Manager) could easily manage the MBIM interface to enable -data communication towards WWAN. The driver also provides an interface to interact -with the MediaTek's modem via AT commands. +The t7xx driver is a WWAN PCIe host driver developed for linux or Chrome OS +platforms for data exchange over PCIe interface between Host platform & +MediaTek's T700 5G modem. +The driver exposes an interface conforming to the MBIM protocol [1]. Any front +end application (e.g. Modem Manager) could easily manage the MBIM interface to +enable data communication towards WWAN. The driver also provides an interface +to interact with the MediaTek's modem via AT commands. Basic usage =========== @@ -45,8 +46,8 @@ The driver provides sysfs interfaces to userspace. t7xx_mode --------- -The sysfs interface provides userspace with access to the device mode, this interface -supports read and write operations. +The sysfs interface provides userspace with access to the device mode, this +interface supports read and write operations. Device mode: @@ -67,6 +68,28 @@ Write from userspace to set the device mode. :: $ echo fastboot_switching > /sys/bus/pci/devices/${bdf}/t7xx_mode +t7xx_debug_ports +---------------- +The sysfs interface provides userspace with access to enable/disable the debug +ports, this interface supports read and write operations. + +Debug port status: + +- ``1`` represents enable debug ports +- ``0`` represents disable debug ports + +Currently supported debug ports (ADB/MIPC). + +Read from userspace to get the current debug ports status. + +:: + $ cat /sys/bus/pci/devices/${bdf}/t7xx_debug_ports + +Write from userspace to set the debug ports status. + +:: + $ echo 1 > /sys/bus/pci/devices/${bdf}/t7xx_debug_ports + Management application development ================================== The driver and userspace interfaces are described below. The MBIM protocol is @@ -139,6 +162,25 @@ Please note that driver needs to be reloaded to export /dev/wwan0fastboot0 port, because device needs a cold reset after enter ``fastboot_switching`` mode. +ADB port userspace ABI +---------------------- + +/dev/wwan0adb0 character device +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The driver exposes a ADB protocol interface by implementing ADB WWAN Port. +The userspace end of the ADB channel pipe is a /dev/wwan0adb0 character device. +Application shall use this interface for ADB protocol communication. + +MIPC port userspace ABI +----------------------- + +/dev/wwan0mipc0 character device +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The driver exposes a diagnostic interface by implementing MIPC (Modem +Information Process Center) WWAN Port. The userspace end of the MIPC channel +pipe is a /dev/wwan0mipc0 character device. +Application shall use this interface for MTK modem diagnostic communication. + The MediaTek's T700 modem supports the 3GPP TS 27.007 [4] specification. References @@ -164,3 +206,9 @@ speak the Mobile Interface Broadband Model (MBIM) protocol"* [5] *fastboot "a mechanism for communicating with bootloaders"* - https://android.googlesource.com/platform/system/core/+/refs/heads/main/fastboot/README.md + +[6] *ADB (Android Debug Bridge) "a mechanism to keep track of Android devices +and emulators instances connected to or running on a given host developer +machine with ADB protocol"* + +- https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/README.md diff --git a/Documentation/networking/devlink/octeontx2.rst b/Documentation/networking/devlink/octeontx2.rst index d33a90dd44bf23..84206537aedbc9 100644 --- a/Documentation/networking/devlink/octeontx2.rst +++ b/Documentation/networking/devlink/octeontx2.rst @@ -40,6 +40,27 @@ The ``octeontx2 AF`` driver implements the following driver-specific parameters. - runtime - Use to set the quantum which hardware uses for scheduling among transmit queues. Hardware uses weighted DWRR algorithm to schedule among all transmit queues. + * - ``npc_mcam_high_zone_percent`` + - u8 + - runtime + - Use to set the number of high priority zone entries in NPC MCAM that can be allocated + by a user, out of the three priority zone categories high, mid and low. + * - ``npc_def_rule_cntr`` + - bool + - runtime + - Use to enable or disable hit counters for the default rules in NPC MCAM. + Its not guaranteed that counters gets enabled and mapped to all the default rules, + since the counters are scarce and driver follows a best effort approach. + The default rule serves as the primary packet steering rule for a specific PF or VF, + based on its DMAC address which is installed by AF driver as part of its initialization. + Sample command to read hit counters for default rule from debugfs is as follows, + cat /sys/kernel/debug/cn10k/npc/mcam_rules + * - ``nix_maxlf`` + - u16 + - runtime + - Use to set the maximum number of LFs in NIX hardware block. This would be useful + to increase the availability of default resources allocated to enabled LFs like + MCAM entries for example. The ``octeontx2 PF`` driver implements the following driver-specific parameters. diff --git a/Documentation/networking/diagnostic/index.rst b/Documentation/networking/diagnostic/index.rst new file mode 100644 index 00000000000000..86488aa46b4846 --- /dev/null +++ b/Documentation/networking/diagnostic/index.rst @@ -0,0 +1,17 @@ +.. SPDX-License-Identifier: GPL-2.0 + +====================== +Networking Diagnostics +====================== + +.. toctree:: + :maxdepth: 2 + + twisted_pair_layer1_diagnostics.rst + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/networking/diagnostic/twisted_pair_layer1_diagnostics.rst b/Documentation/networking/diagnostic/twisted_pair_layer1_diagnostics.rst new file mode 100644 index 00000000000000..c9be5cc7e1133d --- /dev/null +++ b/Documentation/networking/diagnostic/twisted_pair_layer1_diagnostics.rst @@ -0,0 +1,767 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Diagnostic Concept for Investigating Twisted Pair Ethernet Variants at OSI Layer 1 +================================================================================== + +Introduction +------------ + +This documentation is designed for two primary audiences: + +1. **Users and System Administrators**: For those dealing with real-world + Ethernet issues, this guide provides a practical, step-by-step + troubleshooting flow to help identify and resolve common problems in Twisted + Pair Ethernet at OSI Layer 1. If you're facing unstable links, speed drops, + or mysterious network issues, jump right into the step-by-step guide and + follow it through to find your solution. + +2. **Kernel Developers**: For developers working with network drivers and PHY + support, this documentation outlines the diagnostic process and highlights + areas where the Linux kernel’s diagnostic interfaces could be extended or + improved. By understanding the diagnostic flow, developers can better + prioritize future enhancements. + +Step-by-Step Diagnostic Guide from Linux (General Ethernet) +----------------------------------------------------------- + +This diagnostic guide covers common Ethernet troubleshooting scenarios, +focusing on **link stability and detection** across different Ethernet +environments, including **Single-Pair Ethernet (SPE)** and **Multi-Pair +Ethernet (MPE)**, as well as power delivery technologies like **PoDL** (Power +over Data Line) and **PoE** (Clause 33 PSE). + +The guide is designed to help users diagnose physical layer (Layer 1) issues on +systems running **Linux kernel version 6.11 or newer**, utilizing **ethtool +version 6.10 or later** and **iproute2 version 6.4.0 or later**. + +In this guide, we assume that users may have **limited or no access to the link +partner** and will focus on diagnosing issues locally. + +Diagnostic Scenarios +~~~~~~~~~~~~~~~~~~~~ + +- **Link is up and stable, but no data transfer**: If the link is stable but + there are issues with data transmission, refer to the **OSI Layer 2 + Troubleshooting Guide**. + +- **Link is unstable**: Link resets, speed drops, or other fluctuations + indicate potential issues at the hardware or physical layer. + +- **No link detected**: The interface is up, but no link is established. + +Verify Interface Status +~~~~~~~~~~~~~~~~~~~~~~~ + +Begin by verifying the status of the Ethernet interface to check if it is +administratively up. Unlike `ethtool`, which provides information on the link +and PHY status, it does not show the **administrative state** of the interface. +To check this, you should use the `ip` command, which describes the interface +state within the angle brackets `"<>"` in its output. + +For example, in the output ``, the important +keywords are: + +- **UP**: The interface is in the administrative "UP" state. +- **NO-CARRIER**: The interface is administratively up, but no physical link is + detected. + +If the output shows ``, this indicates the interface is in +the administrative "DOWN" state. + +- **Command:** `ip link show dev ` + +- **Expected Output:** + + .. code-block:: bash + + 4: eth0: mtu 1500 ... + link/ether 88:14:2b:00:96:f2 brd ff:ff:ff:ff:ff:ff + +- **Interpreting the Output:** + + - **Administrative UP State**: + + - If the output contains **"UP"**, the interface is administratively up, + and the system is trying to establish a physical link. + + - If you also see **"NO-CARRIER"**, it means the physical link has not been + detected, indicating potential Layer 1 issues like a cable fault, + misconfiguration, or no connection at the link partner. In this case, + proceed to the **Inspect Link Status and PHY Configuration** section. + + - **Administrative DOWN State**: + + - If the output lacks **"UP"** and shows only states like + **""**, it means the interface is administratively + down. In this case, bring the interface up using the following command: + + .. code-block:: bash + + ip link set dev up + +- **Next Steps**: + + - If the interface is **administratively up** but shows **NO-CARRIER**, + proceed to the **Inspect Link Status and PHY Configuration** section to + troubleshoot potential physical layer issues. + + - If the interface was **administratively down** and you have brought it up, + ensure to **repeat this verification step** to confirm the new state of the + interface before proceeding + + - **If the interface is up and the link is detected**: + + - If the output shows **"UP"** and there is **no `NO-CARRIER`**, the + interface is administratively up, and the physical link has been + successfully established. If everything is working as expected, the Layer + 1 diagnostics are complete, and no further action is needed. + + - If the interface is up and the link is detected but **no data is being + transferred**, the issue is likely beyond Layer 1, and you should proceed + with diagnosing the higher layers of the OSI model. This may involve + checking Layer 2 configurations (such as VLANs or MAC address issues), + Layer 3 settings (like IP addresses, routing, or ARP), or Layer 4 and + above (firewalls, services, etc.). + + - If the **link is unstable** or **frequently resetting or dropping**, this + may indicate a physical layer issue such as a faulty cable, interference, + or power delivery problems. In this case, proceed with the next step in + this guide. + +Inspect Link Status and PHY Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use `ethtool -I` to check the link status, PHY configuration, supported link +modes, and additional statistics such as the **Link Down Events** counter. This +step is essential for diagnosing Layer 1 problems such as speed mismatches, +duplex issues, and link instability. + +For both **Single-Pair Ethernet (SPE)** and **Multi-Pair Ethernet (MPE)** +devices, you will use this step to gather key details about the link. **SPE** +links generally support a single speed and mode without autonegotiation (with +the exception of **10BaseT1L**), while **MPE** devices typically support +multiple link modes and autonegotiation. + +- **Command:** `ethtool -I ` + +- **Example Output for SPE Interface (Non-autonegotiation)**: + + .. code-block:: bash + + Settings for spe4: + Supported ports: [ TP ] + Supported link modes: 100baseT1/Full + Supported pause frame use: No + Supports auto-negotiation: No + Supported FEC modes: Not reported + Advertised link modes: Not applicable + Advertised pause frame use: No + Advertised auto-negotiation: No + Advertised FEC modes: Not reported + Speed: 100Mb/s + Duplex: Full + Auto-negotiation: off + master-slave cfg: forced slave + master-slave status: slave + Port: Twisted Pair + PHYAD: 6 + Transceiver: external + MDI-X: Unknown + Supports Wake-on: d + Wake-on: d + Link detected: yes + SQI: 7/7 + Link Down Events: 2 + +- **Example Output for MPE Interface (Autonegotiation)**: + + .. code-block:: bash + + Settings for eth1: + Supported ports: [ TP MII ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + Supported pause frame use: Symmetric Receive-only + Supports auto-negotiation: Yes + Supported FEC modes: Not reported + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + Advertised pause frame use: Symmetric Receive-only + Advertised auto-negotiation: Yes + Advertised FEC modes: Not reported + Link partner advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + Link partner advertised pause frame use: Symmetric Receive-only + Link partner advertised auto-negotiation: Yes + Link partner advertised FEC modes: Not reported + Speed: 100Mb/s + Duplex: Full + Auto-negotiation: on + Port: Twisted Pair + PHYAD: 10 + Transceiver: internal + MDI-X: Unknown + Supports Wake-on: pg + Wake-on: p + Link detected: yes + Link Down Events: 1 + +- **Next Steps**: + + - Record the output provided by `ethtool`, particularly noting the + **master-slave status**, **speed**, **duplex**, and other relevant fields. + This information will be useful for further analysis or troubleshooting. + Once the **ethtool** output has been collected and stored, move on to the + next diagnostic step. + +Check Power Delivery (PoDL or PoE) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If it is known that **PoDL** or **PoE** is **not implemented** on the system, +or the **PSE** (Power Sourcing Equipment) is managed by proprietary user-space +software or external tools, you can skip this step. In such cases, verify power +delivery through alternative methods, such as checking hardware indicators +(LEDs), using multimeters, or consulting vendor-specific software for +monitoring power status. + +If **PoDL** or **PoE** is implemented and managed directly by Linux, follow +these steps to ensure power is being delivered correctly: + +- **Command:** `ethtool --show-pse ` + +- **Expected Output Examples**: + + 1. **PSE Not Supported**: + + If no PSE is attached or the interface does not support PSE, the following + output is expected: + + .. code-block:: bash + + netlink error: No PSE is attached + netlink error: Operation not supported + + 2. **PoDL (Single-Pair Ethernet)**: + + When PoDL is implemented, you might see the following attributes: + + .. code-block:: bash + + PSE attributes for eth1: + PoDL PSE Admin State: enabled + PoDL PSE Power Detection Status: delivering power + + 3. **PoE (Clause 33 PSE)**: + + For standard PoE, the output may look like this: + + .. code-block:: bash + + PSE attributes for eth1: + Clause 33 PSE Admin State: enabled + Clause 33 PSE Power Detection Status: delivering power + Clause 33 PSE Available Power Limit: 18000 + +- **Adjust Power Limit (if needed)**: + + - Sometimes, the available power limit may not be sufficient for the link + partner. You can increase the power limit as needed. + + - **Command:** `ethtool --set-pse c33-pse-avail-pw-limit ` + + Example: + + .. code-block:: bash + + ethtool --set-pse eth1 c33-pse-avail-pw-limit 18000 + ethtool --show-pse eth1 + + **Expected Output** after adjusting the power limit: + + .. code-block:: bash + + Clause 33 PSE Available Power Limit: 18000 + + +- **Next Steps**: + + - **PoE or PoDL Not Used**: If **PoE** or **PoDL** is not implemented or used + on the system, proceed to the next diagnostic step, as power delivery is + not relevant for this setup. + + - **PoE or PoDL Controlled Externally**: If **PoE** or **PoDL** is used but + is not managed by the Linux kernel's **PSE-PD** framework (i.e., it is + controlled by proprietary user-space software or external tools), this part + is out of scope for this documentation. Please consult vendor-specific + documentation or external tools for monitoring and managing power delivery. + + - **PSE Admin State Disabled**: + + - If the `PSE Admin State:` is **disabled**, enable it by running one of + the following commands: + + .. code-block:: bash + + ethtool --set-pse podl-pse-admin-control enable + + or, for Clause 33 PSE (PoE): + + ethtool --set-pse c33-pse-admin-control enable + + - After enabling the PSE Admin State, return to the start of the **Check + Power Delivery (PoDL or PoE)** step to recheck the power delivery status. + + - **Power Not Delivered**: If the `Power Detection Status` shows something + other than "delivering power" (e.g., `over current`), troubleshoot the + **PSE**. Check for potential issues such as a short circuit in the cable, + insufficient power delivery, or a fault in the PSE itself. + + - **Power Delivered but No Link**: If power is being delivered but no link is + established, proceed with further diagnostics by performing **Cable + Diagnostics** or reviewing the **Inspect Link Status and PHY + Configuration** steps to identify any underlying issues with the physical + link or settings. + +Cable Diagnostics +~~~~~~~~~~~~~~~~~ + +Use `ethtool` to test for physical layer issues such as cable faults. The test +results can vary depending on the cable's condition, the technology in use, and +the state of the link partner. The results from the cable test will help in +diagnosing issues like open circuits, shorts, impedance mismatches, and +noise-related problems. + +- **Command:** `ethtool --cable-test ` + +The following are the typical outputs for **Single-Pair Ethernet (SPE)** and +**Multi-Pair Ethernet (MPE)**: + +- **For Single-Pair Ethernet (SPE)**: + - **Expected Output (SPE)**: + + .. code-block:: bash + + Cable test completed for device eth1. + Pair A, fault length: 25.00m + Pair A code Open Circuit + + This indicates an open circuit or cable fault at the reported distance, but + results can be influenced by the link partner's state. Refer to the + **"Troubleshooting Based on Cable Test Results"** section for further + interpretation of these results. + +- **For Multi-Pair Ethernet (MPE)**: + - **Expected Output (MPE)**: + + .. code-block:: bash + + Cable test completed for device eth0. + Pair A code OK + Pair B code OK + Pair C code Open Circuit + + Here, Pair C is reported as having an open circuit, while Pairs A and B are + functioning correctly. However, if autonegotiation is in use on Pairs A and + B, the cable test may be disrupted. Refer to the **"Troubleshooting Based on + Cable Test Results"** section for a detailed explanation of these issues and + how to resolve them. + +For detailed descriptions of the different possible cable test results, please +refer to the **"Troubleshooting Based on Cable Test Results"** section. + +Troubleshooting Based on Cable Test Results +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +After running the cable test, the results can help identify specific issues in +the physical connection. However, it is important to note that **cable testing +results heavily depend on the capabilities and characteristics of both the +local hardware and the link partner**. The accuracy and reliability of the +results can vary significantly between different hardware implementations. + +In some cases, this can introduce **blind spots** in the current cable testing +implementation, where certain results may not accurately reflect the actual +physical state of the cable. For example: + +- An **Open Circuit** result might not only indicate a damaged or disconnected + cable but also occur if the cable is properly attached to a powered-down link + partner. + +- Some PHYs may report a **Short within Pair** if the link partner is in + **forced slave mode**, even though there is no actual short in the cable. + +To help users interpret the results more effectively, it could be beneficial to +extend the **kernel UAPI** (User API) to provide additional context or +**possible variants** of issues based on the hardware’s characteristics. Since +these quirks are often hardware-specific, the **kernel driver** would be an +ideal source of such information. By providing flags or hints related to +potential false positives for each test result, users would have a better +understanding of what to verify and where to investigate further. + +Until such improvements are made, users should be aware of these limitations +and manually verify cable issues as needed. Physical inspections may help +resolve uncertainties related to false positive results. + +The results can be one of the following: + +- **OK**: + + - The cable is functioning correctly, and no issues were detected. + + - **Next Steps**: If you are still experiencing issues, it might be related + to higher-layer problems, such as duplex mismatches or speed negotiation, + which are not physical-layer issues. + + - **Special Case for `BaseT1` (1000/100/10BaseT1)**: In `BaseT1` systems, an + "OK" result typically also means that the link is up and likely in **slave + mode**, since cable tests usually only pass in this mode. For some + **10BaseT1L** PHYs, an "OK" result may occur even if the cable is too long + for the PHY's configured range (for example, when the range is configured + for short-distance mode). + +- **Open Circuit**: + + - An **Open Circuit** result typically indicates that the cable is damaged or + disconnected at the reported fault length. Consider these possibilities: + + - If the link partner is in **admin down** state or powered off, you might + still get an "Open Circuit" result even if the cable is functional. + + - **Next Steps**: Inspect the cable at the fault length for visible damage + or loose connections. Verify the link partner is powered on and in the + correct mode. + +- **Short within Pair**: + + - A **Short within Pair** indicates an unintended connection within the same + pair of wires, typically caused by physical damage to the cable. + + - **Next Steps**: Replace or repair the cable and check for any physical + damage or improperly crimped connectors. + +- **Short to Another Pair**: + + - A **Short to Another Pair** means the wires from different pairs are + shorted, which could occur due to physical damage or incorrect wiring. + + - **Next Steps**: Replace or repair the damaged cable. Inspect the cable for + incorrect terminations or pinched wiring. + +- **Impedance Mismatch**: + + - **Impedance Mismatch** indicates a reflection caused by an impedance + discontinuity in the cable. This can happen when a part of the cable has + abnormal impedance (e.g., when different cable types are spliced together + or when there is a defect in the cable). + + - **Next Steps**: Check the cable quality and ensure consistent impedance + throughout its length. Replace any sections of the cable that do not meet + specifications. + +- **Noise**: + + - **Noise** means that the Time Domain Reflectometry (TDR) test could not + complete due to excessive noise on the cable, which can be caused by + interference from electromagnetic sources. + + - **Next Steps**: Identify and eliminate sources of electromagnetic + interference (EMI) near the cable. Consider using shielded cables or + rerouting the cable away from noise sources. + +- **Resolution Not Possible**: + + - **Resolution Not Possible** means that the TDR test could not detect the + issue due to the resolution limitations of the test or because the fault is + beyond the distance that the test can measure. + + - **Next Steps**: Inspect the cable manually if possible, or use alternative + diagnostic tools that can handle greater distances or higher resolution. + +- **Unknown**: + + - An **Unknown** result may occur when the test cannot classify the fault or + when a specific issue is outside the scope of the tool's detection + capabilities. + + - **Next Steps**: Re-run the test, verify the link partner's state, and inspect + the cable manually if necessary. + +Verify Link Partner PHY Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the cable test passes but the link is still not functioning correctly, it’s +essential to verify the configuration of the link partner’s PHY. Mismatches in +speed, duplex settings, or master-slave roles can cause connection issues. + +Autonegotiation Mismatch +^^^^^^^^^^^^^^^^^^^^^^^^ + +- If both link partners support autonegotiation, ensure that autonegotiation is + enabled on both sides and that all supported link modes are advertised. A + mismatch can lead to connectivity problems or sub optimal performance. + +- **Quick Fix:** Reset autonegotiation to the default settings, which will + advertise all default link modes: + + .. code-block:: bash + + ethtool -s autoneg on + +- **Command to check configuration:** `ethtool ` + +- **Expected Output:** Ensure that both sides advertise compatible link modes. + If autonegotiation is off, verify that both link partners are configured for + the same speed and duplex. + + The following example shows a case where the local PHY advertises fewer link + modes than it supports. This will reduce the number of overlapping link modes + with the link partner. In the worst case, there will be no common link modes, + and the link will not be created: + + .. code-block:: bash + + Settings for eth0: + Supported link modes: 1000baseT/Full, 100baseT/Full + Advertised link modes: 1000baseT/Full + Speed: 1000Mb/s + Duplex: Full + Auto-negotiation: on + +Combined Mode Mismatch (Autonegotiation on One Side, Forced on the Other) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- One possible issue occurs when one side is using **autonegotiation** (as in + most modern systems), and the other side is set to a **forced link mode** + (e.g., older hardware with single-speed hubs). In such cases, modern PHYs + will attempt to detect the forced mode on the other side. If the link is + established, you may notice: + + - **No or empty "Link partner advertised link modes"**. + + - **"Link partner advertised auto-negotiation:"** will be **"no"** or not + present. + +- This type of detection does not always work reliably: + + - Typically, the modern PHY will default to **Half Duplex**, even if the link + partner is actually configured for **Full Duplex**. + + - Some PHYs may not work reliably if the link partner switches from one + forced mode to another. In this case, only a down/up cycle may help. + +- **Next Steps**: Set both sides to the same fixed speed and duplex mode to + avoid potential detection issues. + + .. code-block:: bash + + ethtool -s speed 1000 duplex full autoneg off + +Master/Slave Role Mismatch (BaseT1 and 1000BaseT PHYs) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- In **BaseT1** systems (e.g., 1000BaseT1, 100BaseT1), link establishment + requires that one device is configured as **master** and the other as + **slave**. A mismatch in this master-slave configuration can prevent the link + from being established. However, **1000BaseT** also supports configurable + master/slave roles and can face similar issues. + +- **Role Preference in 1000BaseT**: The **1000BaseT** specification allows link + partners to negotiate master-slave roles or role preferences during + autonegotiation. Some PHYs have hardware limitations or bugs that prevent + them from functioning properly in certain roles. In such cases, drivers may + force these PHYs into a specific role (e.g., **forced master** or **forced + slave**) or try a weaker option by setting preferences. If both link partners + have the same issue and are forced into the same mode (e.g., both forced into + master mode), they will not be able to establish a link. + +- **Next Steps**: Ensure that one side is configured as **master** and the + other as **slave** to avoid this issue, particularly when hardware + limitations are involved, or try the weaker **preferred** option instead of + **forced**. Check for any driver-related restrictions or forced modes. + +- **Command to force master/slave mode**: + + .. code-block:: bash + + ethtool -s master-slave forced-master + + or: + + .. code-block:: bash + + ethtool -s master-slave forced-master speed 1000 duplex full autoneg off + + +- **Check the current master/slave status**: + + .. code-block:: bash + + ethtool + + Example Output: + + .. code-block:: bash + + master-slave cfg: forced-master + master-slave status: master + +- **Hardware Bugs and Driver Forcing**: If a known hardware issue forces the + PHY into a specific mode, it’s essential to check the driver source code or + hardware documentation for details. Ensure that the roles are compatible + across both link partners, and if both PHYs are forced into the same mode, + adjust one side accordingly to resolve the mismatch. + +Monitor Link Resets and Speed Drops +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the link is unstable, showing frequent resets or speed drops, this may +indicate issues with the cable, PHY configuration, or environmental factors. +While there is still no completely unified way in Linux to directly monitor +downshift events or link speed changes via user space tools, both the Linux +kernel logs and `ethtool` can provide valuable insights, especially if the +driver supports reporting such events. + +- **Monitor Kernel Logs for Link Resets and Speed Drops**: + + - The Linux kernel will print link status changes, including downshift + events, in the system logs. These messages typically include speed changes, + duplex mode, and downshifted link speed (if the driver supports it). + + - **Command to monitor kernel logs in real-time:** + + .. code-block:: bash + + dmesg -w | grep "Link is Up\|Link is Down" + + - Example Output (if a downshift occurs): + + .. code-block:: bash + + eth0: Link is Up - 100Mbps/Full (downshifted) - flow control rx/tx + eth0: Link is Down + + This indicates that the link has been established but has downshifted from + a higher speed. + + - **Note**: Not all drivers or PHYs support downshift reporting, so you may + not see this information for all devices. + +- **Monitor Link Down Events Using `ethtool`**: + + - Starting with the latest kernel and `ethtool` versions, you can track + **Link Down Events** using the `ethtool -I` command. This will provide + counters for link drops, helping to diagnose link instability issues if + supported by the driver. + + - **Command to monitor link down events:** + + .. code-block:: bash + + ethtool -I + + - Example Output (if supported): + + .. code-block:: bash + + PSE attributes for eth1: + Link Down Events: 5 + + This indicates that the link has dropped 5 times. Frequent link down events + may indicate cable or environmental issues that require further + investigation. + +- **Check Link Status and Speed**: + + - Even though downshift counts or events are not easily tracked, you can + still use `ethtool` to manually check the current link speed and status. + + - **Command:** `ethtool ` + + - **Expected Output:** + + .. code-block:: bash + + Speed: 1000Mb/s + Duplex: Full + Auto-negotiation: on + Link detected: yes + + Any inconsistencies in the expected speed or duplex setting could indicate + an issue. + +- **Disable Energy-Efficient Ethernet (EEE) for Diagnostics**: + + - **EEE** (Energy-Efficient Ethernet) can be a source of link instability due + to transitions in and out of low-power states. For diagnostic purposes, it + may be useful to **temporarily** disable EEE to determine if it is + contributing to link instability. This is **not a generic recommendation** + for disabling power management. + + - **Next Steps**: Disable EEE and monitor if the link becomes stable. If + disabling EEE resolves the issue, report the bug so that the driver can be + fixed. + + - **Command:** + + .. code-block:: bash + + ethtool --set-eee eee off + + - **Important**: If disabling EEE resolves the instability, the issue should + be reported to the maintainers as a bug, and the driver should be corrected + to handle EEE properly without causing instability. Disabling EEE + permanently should not be seen as a solution. + +- **Monitor Error Counters**: + + - While some NIC drivers and PHYs provide error counters, there is no unified + set of PHY-specific counters across all hardware. Additionally, not all + PHYs provide useful information related to errors like CRC errors, frame + drops, or link flaps. Therefore, this step is dependent on the specific + hardware and driver support. + + - **Next Steps**: Use `ethtool -S ` to check if your driver + provides useful error counters. In some cases, counters may provide + information about errors like link flaps or physical layer problems (e.g., + excessive CRC errors), but results can vary significantly depending on the + PHY. + + - **Command:** `ethtool -S ` + + - **Example Output (if supported)**: + + .. code-block:: bash + + rx_crc_errors: 123 + tx_errors: 45 + rx_frame_errors: 78 + + - **Note**: If no meaningful error counters are available or if counters are + not supported, you may need to rely on physical inspections (e.g., cable + condition) or kernel log messages (e.g., link up/down events) to further + diagnose the issue. + +When All Else Fails... +~~~~~~~~~~~~~~~~~~~~~~ + +So you've checked the cables, monitored the logs, disabled EEE, and still... +nothing? Don’t worry, you’re not alone. Sometimes, Ethernet gremlins just don’t +want to cooperate. + +But before you throw in the towel (or the Ethernet cable), take a deep breath. +It’s always possible that: + +1. Your PHY has a unique, undocumented personality. + +2. The problem is lying dormant, waiting for just the right moment to magically + resolve itself (hey, it happens!). + +3. Or, it could be that the ultimate solution simply hasn’t been invented yet. + +If none of the above bring you comfort, there’s one final step: contribute! If +you've uncovered new or unusual issues, or have creative diagnostic methods, +feel free to share your findings and extend this documentation. Together, we +can hunt down every elusive network issue - one twisted pair at a time. + +Remember: sometimes the solution is just a reboot away, but if not, it’s time to +dig deeper - or report that bug! + diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index 295563e9108247..b25926071ece05 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -236,6 +236,7 @@ Userspace to kernel: ``ETHTOOL_MSG_MM_GET`` get MAC merge layer state ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware + ``ETHTOOL_MSG_PHY_GET`` get Ethernet PHY information ===================================== ================================= Kernel to userspace: @@ -283,6 +284,8 @@ Kernel to userspace: ``ETHTOOL_MSG_PLCA_NTF`` PLCA RS parameters ``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status ``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates + ``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information + ``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change ======================================== ================================= ``GET`` requests are sent by userspace applications to retrieve device diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 803dfc1efb7518..46c178e564b340 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -14,6 +14,7 @@ Contents: can can_ucan_protocol device_drivers/index + diagnostic/index dsa/index devlink/index caif/index diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index eacf8983e23074..dcbb6f6caf6de3 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -2170,6 +2170,12 @@ nexthop_compat_mode - BOOLEAN understands the new API, this sysctl can be disabled to achieve full performance benefits of the new API by disabling the nexthop expansion and extraneous notifications. + + Note that as a backward-compatible mode, dumping of modern features + might be incomplete or wrong. For example, resilient groups will not be + shown as such, but rather as just a list of next hops. Also weights that + do not fit into 8 bits will show incorrectly. + Default: true (backward compat mode) fib_notify_on_flag_change - INTEGER diff --git a/Documentation/networking/kapi.rst b/Documentation/networking/kapi.rst index ea55f462cefa15..98682b9a13ee5f 100644 --- a/Documentation/networking/kapi.rst +++ b/Documentation/networking/kapi.rst @@ -104,6 +104,9 @@ Driver Support .. kernel-doc:: include/linux/netdevice.h :internal: +.. kernel-doc:: include/net/net_shaper.h + :internal: + PHY Support ----------- diff --git a/Documentation/networking/napi.rst b/Documentation/networking/napi.rst index dfa5d549be9c03..02720dd71a769b 100644 --- a/Documentation/networking/napi.rst +++ b/Documentation/networking/napi.rst @@ -192,6 +192,33 @@ is reused to control the delay of the timer, while ``napi_defer_hard_irqs`` controls the number of consecutive empty polls before NAPI gives up and goes back to using hardware IRQs. +The above parameters can also be set on a per-NAPI basis using netlink via +netdev-genl. When used with netlink and configured on a per-NAPI basis, the +parameters mentioned above use hyphens instead of underscores: +``gro-flush-timeout`` and ``napi-defer-hard-irqs``. + +Per-NAPI configuration can be done programmatically in a user application +or by using a script included in the kernel source tree: +``tools/net/ynl/cli.py``. + +For example, using the script: + +.. code-block:: bash + + $ kernel-source/tools/net/ynl/cli.py \ + --spec Documentation/netlink/specs/netdev.yaml \ + --do napi-set \ + --json='{"id": 345, + "defer-hard-irqs": 111, + "gro-flush-timeout": 11111}' + +Similarly, the parameter ``irq-suspend-timeout`` can be set using netlink +via netdev-genl. There is no global sysfs parameter for this value. + +``irq-suspend-timeout`` is used to determine how long an application can +completely suspend IRQs. It is used in combination with SO_PREFER_BUSY_POLL, +which can be set on a per-epoll context basis with ``EPIOCSPARAMS`` ioctl. + .. _poll: Busy polling @@ -207,6 +234,46 @@ selected sockets or using the global ``net.core.busy_poll`` and ``net.core.busy_read`` sysctls. An io_uring API for NAPI busy polling also exists. +epoll-based busy polling +------------------------ + +It is possible to trigger packet processing directly from calls to +``epoll_wait``. In order to use this feature, a user application must ensure +all file descriptors which are added to an epoll context have the same NAPI ID. + +If the application uses a dedicated acceptor thread, the application can obtain +the NAPI ID of the incoming connection using SO_INCOMING_NAPI_ID and then +distribute that file descriptor to a worker thread. The worker thread would add +the file descriptor to its epoll context. This would ensure each worker thread +has an epoll context with FDs that have the same NAPI ID. + +Alternatively, if the application uses SO_REUSEPORT, a bpf or ebpf program can +be inserted to distribute incoming connections to threads such that each thread +is only given incoming connections with the same NAPI ID. Care must be taken to +carefully handle cases where a system may have multiple NICs. + +In order to enable busy polling, there are two choices: + +1. ``/proc/sys/net/core/busy_poll`` can be set with a time in useconds to busy + loop waiting for events. This is a system-wide setting and will cause all + epoll-based applications to busy poll when they call epoll_wait. This may + not be desirable as many applications may not have the need to busy poll. + +2. Applications using recent kernels can issue an ioctl on the epoll context + file descriptor to set (``EPIOCSPARAMS``) or get (``EPIOCGPARAMS``) ``struct + epoll_params``:, which user programs can define as follows: + +.. code-block:: c + + struct epoll_params { + uint32_t busy_poll_usecs; + uint16_t busy_poll_budget; + uint8_t prefer_busy_poll; + + /* pad the struct to a multiple of 64bits */ + uint8_t __pad; + }; + IRQ mitigation --------------- @@ -222,12 +289,111 @@ Such applications can pledge to the kernel that they will perform a busy polling operation periodically, and the driver should keep the device IRQs permanently masked. This mode is enabled by using the ``SO_PREFER_BUSY_POLL`` socket option. To avoid system misbehavior the pledge is revoked -if ``gro_flush_timeout`` passes without any busy poll call. +if ``gro_flush_timeout`` passes without any busy poll call. For epoll-based +busy polling applications, the ``prefer_busy_poll`` field of ``struct +epoll_params`` can be set to 1 and the ``EPIOCSPARAMS`` ioctl can be issued to +enable this mode. See the above section for more details. The NAPI budget for busy polling is lower than the default (which makes sense given the low latency intention of normal busy polling). This is not the case with IRQ mitigation, however, so the budget can be adjusted -with the ``SO_BUSY_POLL_BUDGET`` socket option. +with the ``SO_BUSY_POLL_BUDGET`` socket option. For epoll-based busy polling +applications, the ``busy_poll_budget`` field can be adjusted to the desired value +in ``struct epoll_params`` and set on a specific epoll context using the ``EPIOCSPARAMS`` +ioctl. See the above section for more details. + +It is important to note that choosing a large value for ``gro_flush_timeout`` +will defer IRQs to allow for better batch processing, but will induce latency +when the system is not fully loaded. Choosing a small value for +``gro_flush_timeout`` can cause interference of the user application which is +attempting to busy poll by device IRQs and softirq processing. This value +should be chosen carefully with these tradeoffs in mind. epoll-based busy +polling applications may be able to mitigate how much user processing happens +by choosing an appropriate value for ``maxevents``. + +Users may want to consider an alternate approach, IRQ suspension, to help deal +with these tradeoffs. + +IRQ suspension +-------------- + +IRQ suspension is a mechanism wherein device IRQs are masked while epoll +triggers NAPI packet processing. + +While application calls to epoll_wait successfully retrieve events, the kernel will +defer the IRQ suspension timer. If the kernel does not retrieve any events +while busy polling (for example, because network traffic levels subsided), IRQ +suspension is disabled and the IRQ mitigation strategies described above are +engaged. + +This allows users to balance CPU consumption with network processing +efficiency. + +To use this mechanism: + + 1. The per-NAPI config parameter ``irq-suspend-timeout`` should be set to the + maximum time (in nanoseconds) the application can have its IRQs + suspended. This is done using netlink, as described above. This timeout + serves as a safety mechanism to restart IRQ driver interrupt processing if + the application has stalled. This value should be chosen so that it covers + the amount of time the user application needs to process data from its + call to epoll_wait, noting that applications can control how much data + they retrieve by setting ``max_events`` when calling epoll_wait. + + 2. The sysfs parameter or per-NAPI config parameters ``gro_flush_timeout`` + and ``napi_defer_hard_irqs`` can be set to low values. They will be used + to defer IRQs after busy poll has found no data. + + 3. The ``prefer_busy_poll`` flag must be set to true. This can be done using + the ``EPIOCSPARAMS`` ioctl as described above. + + 4. The application uses epoll as described above to trigger NAPI packet + processing. + +As mentioned above, as long as subsequent calls to epoll_wait return events to +userland, the ``irq-suspend-timeout`` is deferred and IRQs are disabled. This +allows the application to process data without interference. + +Once a call to epoll_wait results in no events being found, IRQ suspension is +automatically disabled and the ``gro_flush_timeout`` and +``napi_defer_hard_irqs`` mitigation mechanisms take over. + +It is expected that ``irq-suspend-timeout`` will be set to a value much larger +than ``gro_flush_timeout`` as ``irq-suspend-timeout`` should suspend IRQs for +the duration of one userland processing cycle. + +While it is not stricly necessary to use ``napi_defer_hard_irqs`` and +``gro_flush_timeout`` to use IRQ suspension, their use is strongly +recommended. + +IRQ suspension causes the system to alternate between polling mode and +irq-driven packet delivery. During busy periods, ``irq-suspend-timeout`` +overrides ``gro_flush_timeout`` and keeps the system busy polling, but when +epoll finds no events, the setting of ``gro_flush_timeout`` and +``napi_defer_hard_irqs`` determine the next step. + +There are essentially three possible loops for network processing and +packet delivery: + +1) hardirq -> softirq -> napi poll; basic interrupt delivery +2) timer -> softirq -> napi poll; deferred irq processing +3) epoll -> busy-poll -> napi poll; busy looping + +Loop 2 can take control from Loop 1, if ``gro_flush_timeout`` and +``napi_defer_hard_irqs`` are set. + +If ``gro_flush_timeout`` and ``napi_defer_hard_irqs`` are set, Loops 2 +and 3 "wrestle" with each other for control. + +During busy periods, ``irq-suspend-timeout`` is used as timer in Loop 2, +which essentially tilts network processing in favour of Loop 3. + +If ``gro_flush_timeout`` and ``napi_defer_hard_irqs`` are not set, Loop 3 +cannot take control from Loop 1. + +Therefore, setting ``gro_flush_timeout`` and ``napi_defer_hard_irqs`` is +the recommended usage, because otherwise setting ``irq-suspend-timeout`` +might not have any discernible effect. .. _threaded: diff --git a/Documentation/networking/net_cachelines/inet_connection_sock.rst b/Documentation/networking/net_cachelines/inet_connection_sock.rst index 7a911dc95652ea..4a15627fc93b84 100644 --- a/Documentation/networking/net_cachelines/inet_connection_sock.rst +++ b/Documentation/networking/net_cachelines/inet_connection_sock.rst @@ -5,46 +5,48 @@ inet_connection_sock struct fast path usage breakdown ===================================================== +=================================== ====================== =================== =================== ======================================================================================================================================================== Type Name fastpath_tx_access fastpath_rx_access comment -..struct ..inet_connection_sock -struct_inet_sock icsk_inet read_mostly read_mostly tcp_init_buffer_space,tcp_init_transfer,tcp_finish_connect,tcp_connect,tcp_send_rcvq,tcp_send_syn_data -struct_request_sock_queue icsk_accept_queue - - -struct_inet_bind_bucket icsk_bind_hash read_mostly - tcp_set_state -struct_inet_bind2_bucket icsk_bind2_hash read_mostly - tcp_set_state,inet_put_port -unsigned_long icsk_timeout read_mostly - inet_csk_reset_xmit_timer,tcp_connect -struct_timer_list icsk_retransmit_timer read_mostly - inet_csk_reset_xmit_timer,tcp_connect -struct_timer_list icsk_delack_timer read_mostly - inet_csk_reset_xmit_timer,tcp_connect -u32 icsk_rto read_write - tcp_cwnd_validate,tcp_schedule_loss_probe,tcp_connect_init,tcp_connect,tcp_write_xmit,tcp_push_one -u32 icsk_rto_min - - -u32 icsk_delack_max - - -u32 icsk_pmtu_cookie read_write - tcp_sync_mss,tcp_current_mss,tcp_send_syn_data,tcp_connect_init,tcp_connect -struct_tcp_congestion_ops icsk_ca_ops read_write - tcp_cwnd_validate,tcp_tso_segs,tcp_ca_dst_init,tcp_connect_init,tcp_connect,tcp_write_xmit -struct_inet_connection_sock_af_ops icsk_af_ops read_mostly - tcp_finish_connect,tcp_send_syn_data,tcp_mtup_init,tcp_mtu_check_reprobe,tcp_mtu_probe,tcp_connect_init,tcp_connect,__tcp_transmit_skb -struct_tcp_ulp_ops* icsk_ulp_ops - - -void* icsk_ulp_data - - -u8:5 icsk_ca_state read_write - tcp_cwnd_application_limited,tcp_set_ca_state,tcp_enter_cwr,tcp_tso_should_defer,tcp_mtu_probe,tcp_schedule_loss_probe,tcp_write_xmit,__tcp_transmit_skb -u8:1 icsk_ca_initialized read_write - tcp_init_transfer,tcp_init_congestion_control,tcp_init_transfer,tcp_finish_connect,tcp_connect -u8:1 icsk_ca_setsockopt - - -u8:1 icsk_ca_dst_locked write_mostly - tcp_ca_dst_init,tcp_connect_init,tcp_connect -u8 icsk_retransmits write_mostly - tcp_connect_init,tcp_connect -u8 icsk_pending read_write - inet_csk_reset_xmit_timer,tcp_connect,tcp_check_probe_timer,__tcp_push_pending_frames,tcp_rearm_rto,tcp_event_new_data_sent,tcp_event_new_data_sent -u8 icsk_backoff write_mostly - tcp_write_queue_purge,tcp_connect_init -u8 icsk_syn_retries - - -u8 icsk_probes_out - - -u16 icsk_ext_hdr_len read_mostly - __tcp_mtu_to_mss,tcp_mtu_to_rss,tcp_mtu_probe,tcp_write_xmit,tcp_mtu_to_mss, -struct_icsk_ack_u8 pending read_write read_write inet_csk_ack_scheduled,__tcp_cleanup_rbuf,tcp_cleanup_rbuf,inet_csk_clear_xmit_timer,tcp_event_ack-sent,inet_csk_reset_xmit_timer -struct_icsk_ack_u8 quick read_write write_mostly tcp_dec_quickack_mode,tcp_event_ack_sent,__tcp_transmit_skb,__tcp_select_window,__tcp_cleanup_rbuf -struct_icsk_ack_u8 pingpong - - -struct_icsk_ack_u8 retry write_mostly read_write inet_csk_clear_xmit_timer,tcp_rearm_rto,tcp_event_new_data_sent,tcp_write_xmit,__tcp_send_ack,tcp_send_ack, -struct_icsk_ack_u8 ato read_mostly write_mostly tcp_dec_quickack_mode,tcp_event_ack_sent,__tcp_transmit_skb,__tcp_send_ack,tcp_send_ack -struct_icsk_ack_unsigned_long timeout read_write read_write inet_csk_reset_xmit_timer,tcp_connect -struct_icsk_ack_u32 lrcvtime read_write - tcp_finish_connect,tcp_connect,tcp_event_data_sent,__tcp_transmit_skb -struct_icsk_ack_u16 rcv_mss write_mostly read_mostly __tcp_select_window,__tcp_cleanup_rbuf,tcp_initialize_rcv_mss,tcp_connect_init -struct_icsk_mtup_int search_high read_write - tcp_mtup_init,tcp_sync_mss,tcp_connect_init,tcp_mtu_check_reprobe,tcp_write_xmit -struct_icsk_mtup_int search_low read_write - tcp_mtu_probe,tcp_mtu_check_reprobe,tcp_write_xmit,tcp_sync_mss,tcp_connect_init,tcp_mtup_init -struct_icsk_mtup_u32:31 probe_size read_write - tcp_mtup_init,tcp_connect_init,__tcp_transmit_skb -struct_icsk_mtup_u32:1 enabled read_write - tcp_mtup_init,tcp_sync_mss,tcp_connect_init,tcp_mtu_probe,tcp_write_xmit -struct_icsk_mtup_u32 probe_timestamp read_write - tcp_mtup_init,tcp_connect_init,tcp_mtu_check_reprobe,tcp_mtu_probe -u32 icsk_probes_tstamp - - -u32 icsk_user_timeout - - -u64[104/sizeof(u64)] icsk_ca_priv - - +=================================== ====================== =================== =================== ======================================================================================================================================================== +struct inet_sock icsk_inet read_mostly read_mostly tcp_init_buffer_space,tcp_init_transfer,tcp_finish_connect,tcp_connect,tcp_send_rcvq,tcp_send_syn_data +struct request_sock_queue icsk_accept_queue +struct inet_bind_bucket icsk_bind_hash read_mostly tcp_set_state +struct inet_bind2_bucket icsk_bind2_hash read_mostly tcp_set_state,inet_put_port +unsigned_long icsk_timeout read_mostly inet_csk_reset_xmit_timer,tcp_connect +struct timer_list icsk_retransmit_timer read_mostly inet_csk_reset_xmit_timer,tcp_connect +struct timer_list icsk_delack_timer read_mostly inet_csk_reset_xmit_timer,tcp_connect +u32 icsk_rto read_write tcp_cwnd_validate,tcp_schedule_loss_probe,tcp_connect_init,tcp_connect,tcp_write_xmit,tcp_push_one +u32 icsk_rto_min +u32 icsk_delack_max +u32 icsk_pmtu_cookie read_write tcp_sync_mss,tcp_current_mss,tcp_send_syn_data,tcp_connect_init,tcp_connect +struct tcp_congestion_ops icsk_ca_ops read_write tcp_cwnd_validate,tcp_tso_segs,tcp_ca_dst_init,tcp_connect_init,tcp_connect,tcp_write_xmit +struct inet_connection_sock_af_ops icsk_af_ops read_mostly tcp_finish_connect,tcp_send_syn_data,tcp_mtup_init,tcp_mtu_check_reprobe,tcp_mtu_probe,tcp_connect_init,tcp_connect,__tcp_transmit_skb +struct tcp_ulp_ops* icsk_ulp_ops +void* icsk_ulp_data +u8:5 icsk_ca_state read_write tcp_cwnd_application_limited,tcp_set_ca_state,tcp_enter_cwr,tcp_tso_should_defer,tcp_mtu_probe,tcp_schedule_loss_probe,tcp_write_xmit,__tcp_transmit_skb +u8:1 icsk_ca_initialized read_write tcp_init_transfer,tcp_init_congestion_control,tcp_init_transfer,tcp_finish_connect,tcp_connect +u8:1 icsk_ca_setsockopt +u8:1 icsk_ca_dst_locked write_mostly tcp_ca_dst_init,tcp_connect_init,tcp_connect +u8 icsk_retransmits write_mostly tcp_connect_init,tcp_connect +u8 icsk_pending read_write inet_csk_reset_xmit_timer,tcp_connect,tcp_check_probe_timer,__tcp_push_pending_frames,tcp_rearm_rto,tcp_event_new_data_sent,tcp_event_new_data_sent +u8 icsk_backoff write_mostly tcp_write_queue_purge,tcp_connect_init +u8 icsk_syn_retries +u8 icsk_probes_out +u16 icsk_ext_hdr_len read_mostly __tcp_mtu_to_mss,tcp_mtu_to_rss,tcp_mtu_probe,tcp_write_xmit,tcp_mtu_to_mss, +struct icsk_ack_u8 pending read_write read_write inet_csk_ack_scheduled,__tcp_cleanup_rbuf,tcp_cleanup_rbuf,inet_csk_clear_xmit_timer,tcp_event_ack-sent,inet_csk_reset_xmit_timer +struct icsk_ack_u8 quick read_write write_mostly tcp_dec_quickack_mode,tcp_event_ack_sent,__tcp_transmit_skb,__tcp_select_window,__tcp_cleanup_rbuf +struct icsk_ack_u8 pingpong +struct icsk_ack_u8 retry write_mostly read_write inet_csk_clear_xmit_timer,tcp_rearm_rto,tcp_event_new_data_sent,tcp_write_xmit,__tcp_send_ack,tcp_send_ack, +struct icsk_ack_u8 ato read_mostly write_mostly tcp_dec_quickack_mode,tcp_event_ack_sent,__tcp_transmit_skb,__tcp_send_ack,tcp_send_ack +struct icsk_ack_unsigned_long timeout read_write read_write inet_csk_reset_xmit_timer,tcp_connect +struct icsk_ack_u32 lrcvtime read_write tcp_finish_connect,tcp_connect,tcp_event_data_sent,__tcp_transmit_skb +struct icsk_ack_u16 rcv_mss write_mostly read_mostly __tcp_select_window,__tcp_cleanup_rbuf,tcp_initialize_rcv_mss,tcp_connect_init +struct icsk_mtup_int search_high read_write tcp_mtup_init,tcp_sync_mss,tcp_connect_init,tcp_mtu_check_reprobe,tcp_write_xmit +struct icsk_mtup_int search_low read_write tcp_mtu_probe,tcp_mtu_check_reprobe,tcp_write_xmit,tcp_sync_mss,tcp_connect_init,tcp_mtup_init +struct icsk_mtup_u32:31 probe_size read_write tcp_mtup_init,tcp_connect_init,__tcp_transmit_skb +struct icsk_mtup_u32:1 enabled read_write tcp_mtup_init,tcp_sync_mss,tcp_connect_init,tcp_mtu_probe,tcp_write_xmit +struct icsk_mtup_u32 probe_timestamp read_write tcp_mtup_init,tcp_connect_init,tcp_mtu_check_reprobe,tcp_mtu_probe +u32 icsk_probes_tstamp +u32 icsk_user_timeout +u64[104/sizeof(u64)] icsk_ca_priv +=================================== ====================== =================== =================== ======================================================================================================================================================== diff --git a/Documentation/networking/net_cachelines/inet_sock.rst b/Documentation/networking/net_cachelines/inet_sock.rst index 595d7ef5fc8b09..b11bf48fa2b36a 100644 --- a/Documentation/networking/net_cachelines/inet_sock.rst +++ b/Documentation/networking/net_cachelines/inet_sock.rst @@ -5,40 +5,42 @@ inet_sock struct fast path usage breakdown ========================================== +======================= ===================== =================== =================== ====================================================================================================== Type Name fastpath_tx_access fastpath_rx_access comment -..struct ..inet_sock -struct_sock sk read_mostly read_mostly tcp_init_buffer_space,tcp_init_transfer,tcp_finish_connect,tcp_connect,tcp_send_rcvq,tcp_send_syn_data -struct_ipv6_pinfo* pinet6 - - -be16 inet_sport read_mostly - __tcp_transmit_skb -be32 inet_daddr read_mostly - ip_select_ident_segs -be32 inet_rcv_saddr - - -be16 inet_dport read_mostly - __tcp_transmit_skb -u16 inet_num - - -be32 inet_saddr - - -s16 uc_ttl read_mostly - __ip_queue_xmit/ip_select_ttl -u16 cmsg_flags - - -struct_ip_options_rcu* inet_opt read_mostly - __ip_queue_xmit -u16 inet_id read_mostly - ip_select_ident_segs -u8 tos read_mostly - ip_queue_xmit -u8 min_ttl - - -u8 mc_ttl - - -u8 pmtudisc - - -u8:1 recverr - - -u8:1 is_icsk - - -u8:1 freebind - - -u8:1 hdrincl - - -u8:1 mc_loop - - -u8:1 transparent - - -u8:1 mc_all - - -u8:1 nodefrag - - -u8:1 bind_address_no_port - - -u8:1 recverr_rfc4884 - - -u8:1 defer_connect read_mostly - tcp_sendmsg_fastopen -u8 rcv_tos - - -u8 convert_csum - - -int uc_index - - -int mc_index - - -be32 mc_addr - - -struct_ip_mc_socklist* mc_list - - -struct_inet_cork_full cork read_mostly - __tcp_transmit_skb -struct local_port_range - - +======================= ===================== =================== =================== ====================================================================================================== +struct sock sk read_mostly read_mostly tcp_init_buffer_space,tcp_init_transfer,tcp_finish_connect,tcp_connect,tcp_send_rcvq,tcp_send_syn_data +struct ipv6_pinfo* pinet6 +be16 inet_sport read_mostly __tcp_transmit_skb +be32 inet_daddr read_mostly ip_select_ident_segs +be32 inet_rcv_saddr +be16 inet_dport read_mostly __tcp_transmit_skb +u16 inet_num +be32 inet_saddr +s16 uc_ttl read_mostly __ip_queue_xmit/ip_select_ttl +u16 cmsg_flags +struct ip_options_rcu* inet_opt read_mostly __ip_queue_xmit +u16 inet_id read_mostly ip_select_ident_segs +u8 tos read_mostly ip_queue_xmit +u8 min_ttl +u8 mc_ttl +u8 pmtudisc +u8:1 recverr +u8:1 is_icsk +u8:1 freebind +u8:1 hdrincl +u8:1 mc_loop +u8:1 transparent +u8:1 mc_all +u8:1 nodefrag +u8:1 bind_address_no_port +u8:1 recverr_rfc4884 +u8:1 defer_connect read_mostly tcp_sendmsg_fastopen +u8 rcv_tos +u8 convert_csum +int uc_index +int mc_index +be32 mc_addr +struct ip_mc_socklist* mc_list +struct inet_cork_full cork read_mostly __tcp_transmit_skb +struct local_port_range +======================= ===================== =================== =================== ====================================================================================================== diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst index 22b07c814f4a45..15e31ece675fc4 100644 --- a/Documentation/networking/net_cachelines/net_device.rst +++ b/Documentation/networking/net_cachelines/net_device.rst @@ -5,181 +5,188 @@ net_device struct fast path usage breakdown =========================================== -Type Name fastpath_tx_access fastpath_rx_access Comments -..struct ..net_device -unsigned_long:32 priv_flags read_mostly - __dev_queue_xmit(tx) -unsigned_long:1 lltx read_mostly - HARD_TX_LOCK,HARD_TX_TRYLOCK,HARD_TX_UNLOCK(tx) -char name[16] - - -struct_netdev_name_node* name_node -struct_dev_ifalias* ifalias -unsigned_long mem_end -unsigned_long mem_start -unsigned_long base_addr -unsigned_long state read_mostly read_mostly netif_running(dev) -struct_list_head dev_list -struct_list_head napi_list -struct_list_head unreg_list -struct_list_head close_list -struct_list_head ptype_all read_mostly - dev_nit_active(tx) -struct_list_head ptype_specific read_mostly deliver_ptype_list_skb/__netif_receive_skb_core(rx) -struct adj_list -unsigned_int flags read_mostly read_mostly __dev_queue_xmit,__dev_xmit_skb,ip6_output,__ip6_finish_output(tx);ip6_rcv_core(rx) -xdp_features_t xdp_features -struct_net_device_ops* netdev_ops read_mostly - netdev_core_pick_tx,netdev_start_xmit(tx) -struct_xdp_metadata_ops* xdp_metadata_ops -int ifindex - read_mostly ip6_rcv_core -unsigned_short gflags -unsigned_short hard_header_len read_mostly read_mostly ip6_xmit(tx);gro_list_prepare(rx) -unsigned_int mtu read_mostly - ip_finish_output2 -unsigned_short needed_headroom read_mostly - LL_RESERVED_SPACE/ip_finish_output2 -unsigned_short needed_tailroom -netdev_features_t features read_mostly read_mostly HARD_TX_LOCK,netif_skb_features,sk_setup_caps(tx);netif_elide_gro(rx) -netdev_features_t hw_features -netdev_features_t wanted_features -netdev_features_t vlan_features -netdev_features_t hw_enc_features - - netif_skb_features -netdev_features_t mpls_features -netdev_features_t gso_partial_features read_mostly gso_features_check -unsigned_int min_mtu -unsigned_int max_mtu -unsigned_short type -unsigned_char min_header_len -unsigned_char name_assign_type -int group -struct_net_device_stats stats -struct_net_device_core_stats* core_stats -atomic_t carrier_up_count -atomic_t carrier_down_count -struct_iw_handler_def* wireless_handlers -struct_iw_public_data* wireless_data -struct_ethtool_ops* ethtool_ops -struct_l3mdev_ops* l3mdev_ops -struct_ndisc_ops* ndisc_ops -struct_xfrmdev_ops* xfrmdev_ops -struct_tlsdev_ops* tlsdev_ops -struct_header_ops* header_ops read_mostly - ip_finish_output2,ip6_finish_output2(tx) -unsigned_char operstate -unsigned_char link_mode -unsigned_char if_port -unsigned_char dma -unsigned_char perm_addr[32] -unsigned_char addr_assign_type -unsigned_char addr_len -unsigned_char upper_level -unsigned_char lower_level -unsigned_short neigh_priv_len -unsigned_short padded -unsigned_short dev_id -unsigned_short dev_port -spinlock_t addr_list_lock -int irq -struct_netdev_hw_addr_list uc -struct_netdev_hw_addr_list mc -struct_netdev_hw_addr_list dev_addrs -struct_kset* queues_kset -struct_list_head unlink_list -unsigned_int promiscuity -unsigned_int allmulti -bool uc_promisc -unsigned_char nested_level -struct_in_device* ip_ptr read_mostly read_mostly __in_dev_get -struct_inet6_dev* ip6_ptr read_mostly read_mostly __in6_dev_get -struct_vlan_info* vlan_info -struct_dsa_port* dsa_ptr -struct_tipc_bearer* tipc_ptr -void* atalk_ptr -void* ax25_ptr -struct_wireless_dev* ieee80211_ptr -struct_wpan_dev* ieee802154_ptr -struct_mpls_dev* mpls_ptr -struct_mctp_dev* mctp_ptr -unsigned_char* dev_addr -struct_netdev_queue* _rx read_mostly - netdev_get_rx_queue(rx) -unsigned_int num_rx_queues -unsigned_int real_num_rx_queues - read_mostly get_rps_cpu -struct_bpf_prog* xdp_prog - read_mostly netif_elide_gro() -unsigned_long gro_flush_timeout - read_mostly napi_complete_done -u32 napi_defer_hard_irqs - read_mostly napi_complete_done -unsigned_int gro_max_size - read_mostly skb_gro_receive -unsigned_int gro_ipv4_max_size - read_mostly skb_gro_receive -rx_handler_func_t* rx_handler read_mostly - __netif_receive_skb_core -void* rx_handler_data read_mostly - -struct_netdev_queue* ingress_queue read_mostly - -struct_bpf_mprog_entry tcx_ingress - read_mostly sch_handle_ingress -struct_nf_hook_entries* nf_hooks_ingress -unsigned_char broadcast[32] -struct_cpu_rmap* rx_cpu_rmap -struct_hlist_node index_hlist -struct_netdev_queue* _tx read_mostly - netdev_get_tx_queue(tx) -unsigned_int num_tx_queues - - -unsigned_int real_num_tx_queues read_mostly - skb_tx_hash,netdev_core_pick_tx(tx) -unsigned_int tx_queue_len -spinlock_t tx_global_lock -struct_xdp_dev_bulk_queue__percpu* xdp_bulkq -struct_xps_dev_maps* xps_maps[2] read_mostly - __netif_set_xps_queue -struct_bpf_mprog_entry tcx_egress read_mostly - sch_handle_egress -struct_nf_hook_entries* nf_hooks_egress read_mostly - -struct_hlist_head qdisc_hash[16] -struct_timer_list watchdog_timer -int watchdog_timeo -u32 proto_down_reason -struct_list_head todo_list -int__percpu* pcpu_refcnt -refcount_t dev_refcnt -struct_ref_tracker_dir refcnt_tracker -struct_list_head link_watch_list -enum:8 reg_state -bool dismantle -enum:16 rtnl_link_state -bool needs_free_netdev -void*priv_destructor struct_net_device -struct_netpoll_info* npinfo - read_mostly napi_poll/napi_poll_lock -possible_net_t nd_net - read_mostly (dev_net)napi_busy_loop,tcp_v(4/6)_rcv,ip(v6)_rcv,ip(6)_input,ip(6)_input_finish -void* ml_priv -enum_netdev_ml_priv_type ml_priv_type -struct_pcpu_lstats__percpu* lstats read_mostly dev_lstats_add() -struct_pcpu_sw_netstats__percpu* tstats read_mostly dev_sw_netstats_tx_add() -struct_pcpu_dstats__percpu* dstats -struct_garp_port* garp_port -struct_mrp_port* mrp_port -struct_dm_hw_stat_delta* dm_private -struct_device dev - - -struct_attribute_group* sysfs_groups[4] -struct_attribute_group* sysfs_rx_queue_group -struct_rtnl_link_ops* rtnl_link_ops -unsigned_int gso_max_size read_mostly - sk_dst_gso_max_size -unsigned_int tso_max_size -u16 gso_max_segs read_mostly - gso_max_segs -u16 tso_max_segs -unsigned_int gso_ipv4_max_size read_mostly - sk_dst_gso_max_size -struct_dcbnl_rtnl_ops* dcbnl_ops -s16 num_tc read_mostly - skb_tx_hash -struct_netdev_tc_txq tc_to_txq[16] read_mostly - skb_tx_hash -u8 prio_tc_map[16] -unsigned_int fcoe_ddp_xid -struct_netprio_map* priomap -struct_phy_device* phydev -struct_sfp_bus* sfp_bus -struct_lock_class_key* qdisc_tx_busylock -bool proto_down -unsigned:1 wol_enabled -unsigned:1 threaded - - napi_poll(napi_enable,dev_set_threaded) -unsigned_long:1 see_all_hwtstamp_requests -unsigned_long:1 change_proto_down -unsigned_long:1 netns_local -unsigned_long:1 fcoe_mtu -struct_list_head net_notifier_list -struct_macsec_ops* macsec_ops -struct_udp_tunnel_nic_info* udp_tunnel_nic_info -struct_udp_tunnel_nic* udp_tunnel_nic -unsigned_int xdp_zc_max_segs -struct_bpf_xdp_entity xdp_state[3] -u8 dev_addr_shadow[32] -netdevice_tracker linkwatch_dev_tracker -netdevice_tracker watchdog_dev_tracker -netdevice_tracker dev_registered_tracker -struct_rtnl_hw_stats64* offload_xstats_l3 -struct_devlink_port* devlink_port -struct_dpll_pin* dpll_pin +=================================== =========================== =================== =================== =================================================================================== +Type Name fastpath_tx_access fastpath_rx_access Comments +=================================== =========================== =================== =================== =================================================================================== +unsigned_long:32 priv_flags read_mostly __dev_queue_xmit(tx) +unsigned_long:1 lltx read_mostly HARD_TX_LOCK,HARD_TX_TRYLOCK,HARD_TX_UNLOCK(tx) +char name[16] +struct netdev_name_node* name_node +struct dev_ifalias* ifalias +unsigned_long mem_end +unsigned_long mem_start +unsigned_long base_addr +unsigned_long state read_mostly read_mostly netif_running(dev) +struct list_head dev_list +struct list_head napi_list +struct list_head unreg_list +struct list_head close_list +struct list_head ptype_all read_mostly dev_nit_active(tx) +struct list_head ptype_specific read_mostly deliver_ptype_list_skb/__netif_receive_skb_core(rx) +struct adj_list +unsigned_int flags read_mostly read_mostly __dev_queue_xmit,__dev_xmit_skb,ip6_output,__ip6_finish_output(tx);ip6_rcv_core(rx) +xdp_features_t xdp_features +struct net_device_ops* netdev_ops read_mostly netdev_core_pick_tx,netdev_start_xmit(tx) +struct xdp_metadata_ops* xdp_metadata_ops +int ifindex read_mostly ip6_rcv_core +unsigned_short gflags +unsigned_short hard_header_len read_mostly read_mostly ip6_xmit(tx);gro_list_prepare(rx) +unsigned_int mtu read_mostly ip_finish_output2 +unsigned_short needed_headroom read_mostly LL_RESERVED_SPACE/ip_finish_output2 +unsigned_short needed_tailroom +netdev_features_t features read_mostly read_mostly HARD_TX_LOCK,netif_skb_features,sk_setup_caps(tx);netif_elide_gro(rx) +netdev_features_t hw_features +netdev_features_t wanted_features +netdev_features_t vlan_features +netdev_features_t hw_enc_features netif_skb_features +netdev_features_t mpls_features +netdev_features_t gso_partial_features read_mostly gso_features_check +unsigned_int min_mtu +unsigned_int max_mtu +unsigned_short type +unsigned_char min_header_len +unsigned_char name_assign_type +int group +struct net_device_stats stats +struct net_device_core_stats* core_stats +atomic_t carrier_up_count +atomic_t carrier_down_count +struct iw_handler_def* wireless_handlers +struct ethtool_ops* ethtool_ops +struct l3mdev_ops* l3mdev_ops +struct ndisc_ops* ndisc_ops +struct xfrmdev_ops* xfrmdev_ops +struct tlsdev_ops* tlsdev_ops +struct header_ops* header_ops read_mostly ip_finish_output2,ip6_finish_output2(tx) +unsigned_char operstate +unsigned_char link_mode +unsigned_char if_port +unsigned_char dma +unsigned_char perm_addr[32] +unsigned_char addr_assign_type +unsigned_char addr_len +unsigned_char upper_level +unsigned_char lower_level +unsigned_short neigh_priv_len +unsigned_short padded +unsigned_short dev_id +unsigned_short dev_port +spinlock_t addr_list_lock +int irq +struct netdev_hw_addr_list uc +struct netdev_hw_addr_list mc +struct netdev_hw_addr_list dev_addrs +struct kset* queues_kset +struct list_head unlink_list +unsigned_int promiscuity +unsigned_int allmulti +bool uc_promisc +unsigned_char nested_level +struct in_device* ip_ptr read_mostly read_mostly __in_dev_get +struct hlist_head fib_nh_head +struct inet6_dev* ip6_ptr read_mostly read_mostly __in6_dev_get +struct vlan_info* vlan_info +struct dsa_port* dsa_ptr +struct tipc_bearer* tipc_ptr +void* atalk_ptr +void* ax25_ptr +struct wireless_dev* ieee80211_ptr +struct wpan_dev* ieee802154_ptr +struct mpls_dev* mpls_ptr +struct mctp_dev* mctp_ptr +unsigned_char* dev_addr +struct netdev_queue* _rx read_mostly netdev_get_rx_queue(rx) +unsigned_int num_rx_queues +unsigned_int real_num_rx_queues read_mostly get_rps_cpu +struct bpf_prog* xdp_prog read_mostly netif_elide_gro() +unsigned_long gro_flush_timeout read_mostly napi_complete_done +u32 napi_defer_hard_irqs read_mostly napi_complete_done +unsigned_int gro_max_size read_mostly skb_gro_receive +unsigned_int gro_ipv4_max_size read_mostly skb_gro_receive +rx_handler_func_t* rx_handler read_mostly __netif_receive_skb_core +void* rx_handler_data read_mostly +struct netdev_queue* ingress_queue read_mostly +struct bpf_mprog_entry tcx_ingress read_mostly sch_handle_ingress +struct nf_hook_entries* nf_hooks_ingress +unsigned_char broadcast[32] +struct cpu_rmap* rx_cpu_rmap +struct hlist_node index_hlist +struct netdev_queue* _tx read_mostly netdev_get_tx_queue(tx) +unsigned_int num_tx_queues +unsigned_int real_num_tx_queues read_mostly skb_tx_hash,netdev_core_pick_tx(tx) +unsigned_int tx_queue_len +spinlock_t tx_global_lock +struct xdp_dev_bulk_queue__percpu* xdp_bulkq +struct xps_dev_maps* xps_maps[2] read_mostly __netif_set_xps_queue +struct bpf_mprog_entry tcx_egress read_mostly sch_handle_egress +struct nf_hook_entries* nf_hooks_egress read_mostly +struct hlist_head qdisc_hash[16] +struct timer_list watchdog_timer +int watchdog_timeo +u32 proto_down_reason +struct list_head todo_list +int__percpu* pcpu_refcnt +refcount_t dev_refcnt +struct ref_tracker_dir refcnt_tracker +struct list_head link_watch_list +enum:8 reg_state +bool dismantle +enum:16 rtnl_link_state +bool needs_free_netdev +void*priv_destructor struct net_device +struct netpoll_info* npinfo read_mostly napi_poll/napi_poll_lock +possible_net_t nd_net read_mostly (dev_net)napi_busy_loop,tcp_v(4/6)_rcv,ip(v6)_rcv,ip(6)_input,ip(6)_input_finish +void* ml_priv +enum_netdev_ml_priv_type ml_priv_type +struct pcpu_lstats__percpu* lstats read_mostly dev_lstats_add() +struct pcpu_sw_netstats__percpu* tstats read_mostly dev_sw_netstats_tx_add() +struct pcpu_dstats__percpu* dstats +struct garp_port* garp_port +struct mrp_port* mrp_port +struct dm_hw_stat_delta* dm_private +struct device dev +struct attribute_group* sysfs_groups[4] +struct attribute_group* sysfs_rx_queue_group +struct rtnl_link_ops* rtnl_link_ops +unsigned_int gso_max_size read_mostly sk_dst_gso_max_size +unsigned_int tso_max_size +u16 gso_max_segs read_mostly gso_max_segs +u16 tso_max_segs +unsigned_int gso_ipv4_max_size read_mostly sk_dst_gso_max_size +struct dcbnl_rtnl_ops* dcbnl_ops +s16 num_tc read_mostly skb_tx_hash +struct netdev_tc_txq tc_to_txq[16] read_mostly skb_tx_hash +u8 prio_tc_map[16] +unsigned_int fcoe_ddp_xid +struct netprio_map* priomap +struct phy_device* phydev +struct sfp_bus* sfp_bus +struct lock_class_key* qdisc_tx_busylock +bool proto_down +unsigned:1 wol_enabled +unsigned:1 threaded napi_poll(napi_enable,dev_set_threaded) +unsigned_long:1 see_all_hwtstamp_requests +unsigned_long:1 change_proto_down +unsigned_long:1 netns_local +unsigned_long:1 fcoe_mtu +struct list_head net_notifier_list +struct macsec_ops* macsec_ops +struct udp_tunnel_nic_info* udp_tunnel_nic_info +struct udp_tunnel_nic* udp_tunnel_nic +unsigned_int xdp_zc_max_segs +struct bpf_xdp_entity xdp_state[3] +u8 dev_addr_shadow[32] +netdevice_tracker linkwatch_dev_tracker +netdevice_tracker watchdog_dev_tracker +netdevice_tracker dev_registered_tracker +struct rtnl_hw_stats64* offload_xstats_l3 +struct devlink_port* devlink_port +struct dpll_pin* dpll_pin struct hlist_head page_pools struct dim_irq_moder* irq_moder +u64 max_pacing_offload_horizon +struct_napi_config* napi_config +unsigned_long gro_flush_timeout +u32 napi_defer_hard_irqs +struct hlist_head neighbours[2] +=================================== =========================== =================== =================== =================================================================================== diff --git a/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst index 9b87089a84c61e..629da6dc6d746c 100644 --- a/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst +++ b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst @@ -5,154 +5,156 @@ netns_ipv4 struct fast path usage breakdown =========================================== +=============================== ============================================ =================== =================== ================================================= Type Name fastpath_tx_access fastpath_rx_access comment -..struct ..netns_ipv4 -struct_inet_timewait_death_row tcp_death_row -struct_udp_table* udp_table -struct_ctl_table_header* forw_hdr -struct_ctl_table_header* frags_hdr -struct_ctl_table_header* ipv4_hdr -struct_ctl_table_header* route_hdr -struct_ctl_table_header* xfrm4_hdr -struct_ipv4_devconf* devconf_all -struct_ipv4_devconf* devconf_dflt -struct_ip_ra_chain ra_chain -struct_mutex ra_mutex -struct_fib_rules_ops* rules_ops -struct_fib_table fib_main -struct_fib_table fib_default -unsigned_int fib_rules_require_fldissect -bool fib_has_custom_rules -bool fib_has_custom_local_routes -bool fib_offload_disabled -atomic_t fib_num_tclassid_users -struct_hlist_head* fib_table_hash -struct_sock* fibnl -struct_sock* mc_autojoin_sk -struct_inet_peer_base* peers -struct_fqdir* fqdir -u8 sysctl_icmp_echo_ignore_all -u8 sysctl_icmp_echo_enable_probe -u8 sysctl_icmp_echo_ignore_broadcasts -u8 sysctl_icmp_ignore_bogus_error_responses -u8 sysctl_icmp_errors_use_inbound_ifaddr -int sysctl_icmp_ratelimit -int sysctl_icmp_ratemask -u32 ip_rt_min_pmtu - - -int ip_rt_mtu_expires - - -int ip_rt_min_advmss - - -struct_local_ports ip_local_ports - - -u8 sysctl_tcp_ecn - - -u8 sysctl_tcp_ecn_fallback - - -u8 sysctl_ip_default_ttl - - ip4_dst_hoplimit/ip_select_ttl -u8 sysctl_ip_no_pmtu_disc - - -u8 sysctl_ip_fwd_use_pmtu read_mostly - ip_dst_mtu_maybe_forward/ip_skb_dst_mtu -u8 sysctl_ip_fwd_update_priority - - ip_forward -u8 sysctl_ip_nonlocal_bind - - -u8 sysctl_ip_autobind_reuse - - -u8 sysctl_ip_dynaddr - - -u8 sysctl_ip_early_demux - read_mostly ip(6)_rcv_finish_core -u8 sysctl_raw_l3mdev_accept - - -u8 sysctl_tcp_early_demux - read_mostly ip(6)_rcv_finish_core -u8 sysctl_udp_early_demux -u8 sysctl_nexthop_compat_mode - - -u8 sysctl_fwmark_reflect - - -u8 sysctl_tcp_fwmark_accept - - -u8 sysctl_tcp_l3mdev_accept - - -u8 sysctl_tcp_mtu_probing - - -int sysctl_tcp_mtu_probe_floor - - -int sysctl_tcp_base_mss - - -int sysctl_tcp_min_snd_mss read_mostly - __tcp_mtu_to_mss(tcp_write_xmit) -int sysctl_tcp_probe_threshold - - tcp_mtu_probe(tcp_write_xmit) -u32 sysctl_tcp_probe_interval - - tcp_mtu_check_reprobe(tcp_write_xmit) -int sysctl_tcp_keepalive_time - - -int sysctl_tcp_keepalive_intvl - - -u8 sysctl_tcp_keepalive_probes - - -u8 sysctl_tcp_syn_retries - - -u8 sysctl_tcp_synack_retries - - -u8 sysctl_tcp_syncookies - - generated_on_syn -u8 sysctl_tcp_migrate_req - - reuseport -u8 sysctl_tcp_comp_sack_nr - - __tcp_ack_snd_check -int sysctl_tcp_reordering - read_mostly tcp_may_raise_cwnd/tcp_cong_control -u8 sysctl_tcp_retries1 - - -u8 sysctl_tcp_retries2 - - -u8 sysctl_tcp_orphan_retries - - -u8 sysctl_tcp_tw_reuse - - timewait_sock_ops -int sysctl_tcp_fin_timeout - - TCP_LAST_ACK/tcp_rcv_state_process -unsigned_int sysctl_tcp_notsent_lowat read_mostly - tcp_notsent_lowat/tcp_stream_memory_free -u8 sysctl_tcp_sack - - tcp_syn_options -u8 sysctl_tcp_window_scaling - - tcp_syn_options,tcp_parse_options -u8 sysctl_tcp_timestamps -u8 sysctl_tcp_early_retrans read_mostly - tcp_schedule_loss_probe(tcp_write_xmit) -u8 sysctl_tcp_recovery - - tcp_fastretrans_alert -u8 sysctl_tcp_thin_linear_timeouts - - tcp_retrans_timer(on_thin_streams) -u8 sysctl_tcp_slow_start_after_idle - - unlikely(tcp_cwnd_validate-network-not-starved) -u8 sysctl_tcp_retrans_collapse - - -u8 sysctl_tcp_stdurg - - unlikely(tcp_check_urg) -u8 sysctl_tcp_rfc1337 - - -u8 sysctl_tcp_abort_on_overflow - - -u8 sysctl_tcp_fack - - -int sysctl_tcp_max_reordering - - tcp_check_sack_reordering -int sysctl_tcp_adv_win_scale - - tcp_init_buffer_space -u8 sysctl_tcp_dsack - - partial_packet_or_retrans_in_tcp_data_queue -u8 sysctl_tcp_app_win - - tcp_win_from_space -u8 sysctl_tcp_frto - - tcp_enter_loss -u8 sysctl_tcp_nometrics_save - - TCP_LAST_ACK/tcp_update_metrics -u8 sysctl_tcp_no_ssthresh_metrics_save - - TCP_LAST_ACK/tcp_(update/init)_metrics +=============================== ============================================ =================== =================== ================================================= +struct_inet_timewait_death_row tcp_death_row +struct_udp_table* udp_table +struct_ctl_table_header* forw_hdr +struct_ctl_table_header* frags_hdr +struct_ctl_table_header* ipv4_hdr +struct_ctl_table_header* route_hdr +struct_ctl_table_header* xfrm4_hdr +struct_ipv4_devconf* devconf_all +struct_ipv4_devconf* devconf_dflt +struct_ip_ra_chain ra_chain +struct_mutex ra_mutex +struct_fib_rules_ops* rules_ops +struct_fib_table fib_main +struct_fib_table fib_default +unsigned_int fib_rules_require_fldissect +bool fib_has_custom_rules +bool fib_has_custom_local_routes +bool fib_offload_disabled +atomic_t fib_num_tclassid_users +struct_hlist_head* fib_table_hash +struct_sock* fibnl +struct_sock* mc_autojoin_sk +struct_inet_peer_base* peers +struct_fqdir* fqdir +u8 sysctl_icmp_echo_ignore_all +u8 sysctl_icmp_echo_enable_probe +u8 sysctl_icmp_echo_ignore_broadcasts +u8 sysctl_icmp_ignore_bogus_error_responses +u8 sysctl_icmp_errors_use_inbound_ifaddr +int sysctl_icmp_ratelimit +int sysctl_icmp_ratemask +u32 ip_rt_min_pmtu +int ip_rt_mtu_expires +int ip_rt_min_advmss +struct_local_ports ip_local_ports +u8 sysctl_tcp_ecn +u8 sysctl_tcp_ecn_fallback +u8 sysctl_ip_default_ttl ip4_dst_hoplimit/ip_select_ttl +u8 sysctl_ip_no_pmtu_disc +u8 sysctl_ip_fwd_use_pmtu read_mostly ip_dst_mtu_maybe_forward/ip_skb_dst_mtu +u8 sysctl_ip_fwd_update_priority ip_forward +u8 sysctl_ip_nonlocal_bind +u8 sysctl_ip_autobind_reuse +u8 sysctl_ip_dynaddr +u8 sysctl_ip_early_demux read_mostly ip(6)_rcv_finish_core +u8 sysctl_raw_l3mdev_accept +u8 sysctl_tcp_early_demux read_mostly ip(6)_rcv_finish_core +u8 sysctl_udp_early_demux +u8 sysctl_nexthop_compat_mode +u8 sysctl_fwmark_reflect +u8 sysctl_tcp_fwmark_accept +u8 sysctl_tcp_l3mdev_accept read_mostly __inet6_lookup_established/inet_request_bound_dev_if +u8 sysctl_tcp_mtu_probing +int sysctl_tcp_mtu_probe_floor +int sysctl_tcp_base_mss +int sysctl_tcp_min_snd_mss read_mostly __tcp_mtu_to_mss(tcp_write_xmit) +int sysctl_tcp_probe_threshold tcp_mtu_probe(tcp_write_xmit) +u32 sysctl_tcp_probe_interval tcp_mtu_check_reprobe(tcp_write_xmit) +int sysctl_tcp_keepalive_time +int sysctl_tcp_keepalive_intvl +u8 sysctl_tcp_keepalive_probes +u8 sysctl_tcp_syn_retries +u8 sysctl_tcp_synack_retries +u8 sysctl_tcp_syncookies generated_on_syn +u8 sysctl_tcp_migrate_req reuseport +u8 sysctl_tcp_comp_sack_nr __tcp_ack_snd_check +int sysctl_tcp_reordering read_mostly tcp_may_raise_cwnd/tcp_cong_control +u8 sysctl_tcp_retries1 +u8 sysctl_tcp_retries2 +u8 sysctl_tcp_orphan_retries +u8 sysctl_tcp_tw_reuse timewait_sock_ops +int sysctl_tcp_fin_timeout TCP_LAST_ACK/tcp_rcv_state_process +unsigned_int sysctl_tcp_notsent_lowat read_mostly tcp_notsent_lowat/tcp_stream_memory_free +u8 sysctl_tcp_sack tcp_syn_options +u8 sysctl_tcp_window_scaling tcp_syn_options,tcp_parse_options +u8 sysctl_tcp_timestamps +u8 sysctl_tcp_early_retrans read_mostly tcp_schedule_loss_probe(tcp_write_xmit) +u8 sysctl_tcp_recovery tcp_fastretrans_alert +u8 sysctl_tcp_thin_linear_timeouts tcp_retrans_timer(on_thin_streams) +u8 sysctl_tcp_slow_start_after_idle unlikely(tcp_cwnd_validate-network-not-starved) +u8 sysctl_tcp_retrans_collapse +u8 sysctl_tcp_stdurg unlikely(tcp_check_urg) +u8 sysctl_tcp_rfc1337 +u8 sysctl_tcp_abort_on_overflow +u8 sysctl_tcp_fack +int sysctl_tcp_max_reordering tcp_check_sack_reordering +int sysctl_tcp_adv_win_scale tcp_init_buffer_space +u8 sysctl_tcp_dsack partial_packet_or_retrans_in_tcp_data_queue +u8 sysctl_tcp_app_win tcp_win_from_space +u8 sysctl_tcp_frto tcp_enter_loss +u8 sysctl_tcp_nometrics_save TCP_LAST_ACK/tcp_update_metrics +u8 sysctl_tcp_no_ssthresh_metrics_save TCP_LAST_ACK/tcp_(update/init)_metrics u8 sysctl_tcp_moderate_rcvbuf read_mostly read_mostly tcp_tso_should_defer(tx);tcp_rcv_space_adjust(rx) -u8 sysctl_tcp_tso_win_divisor read_mostly - tcp_tso_should_defer(tcp_write_xmit) -u8 sysctl_tcp_workaround_signed_windows - - tcp_select_window -int sysctl_tcp_limit_output_bytes read_mostly - tcp_small_queue_check(tcp_write_xmit) -int sysctl_tcp_challenge_ack_limit - - -int sysctl_tcp_min_rtt_wlen read_mostly - tcp_ack_update_rtt -u8 sysctl_tcp_min_tso_segs - - unlikely(icsk_ca_ops-written) -u8 sysctl_tcp_tso_rtt_log read_mostly - tcp_tso_autosize -u8 sysctl_tcp_autocorking read_mostly - tcp_push/tcp_should_autocork -u8 sysctl_tcp_reflect_tos - - tcp_v(4/6)_send_synack -int sysctl_tcp_invalid_ratelimit - - -int sysctl_tcp_pacing_ss_ratio - - default_cong_cont(tcp_update_pacing_rate) -int sysctl_tcp_pacing_ca_ratio - - default_cong_cont(tcp_update_pacing_rate) -int sysctl_tcp_wmem[3] read_mostly - tcp_wmem_schedule(sendmsg/sendpage) -int sysctl_tcp_rmem[3] - read_mostly __tcp_grow_window(tx),tcp_rcv_space_adjust(rx) -unsigned_int sysctl_tcp_child_ehash_entries -unsigned_long sysctl_tcp_comp_sack_delay_ns - - __tcp_ack_snd_check -unsigned_long sysctl_tcp_comp_sack_slack_ns - - __tcp_ack_snd_check -int sysctl_max_syn_backlog - - -int sysctl_tcp_fastopen - - -struct_tcp_congestion_ops tcp_congestion_control - - init_cc -struct_tcp_fastopen_context tcp_fastopen_ctx - - -unsigned_int sysctl_tcp_fastopen_blackhole_timeout - - -atomic_t tfo_active_disable_times - - -unsigned_long tfo_active_disable_stamp - - -u32 tcp_challenge_timestamp - - -u32 tcp_challenge_count - - -u8 sysctl_tcp_plb_enabled - - -u8 sysctl_tcp_plb_idle_rehash_rounds - - -u8 sysctl_tcp_plb_rehash_rounds - - -u8 sysctl_tcp_plb_suspend_rto_sec - - -int sysctl_tcp_plb_cong_thresh - - -int sysctl_udp_wmem_min -int sysctl_udp_rmem_min -u8 sysctl_fib_notify_on_flag_change -u8 sysctl_udp_l3mdev_accept -u8 sysctl_igmp_llm_reports -int sysctl_igmp_max_memberships -int sysctl_igmp_max_msf -int sysctl_igmp_qrv -struct_ping_group_range ping_group_range -atomic_t dev_addr_genid -unsigned_int sysctl_udp_child_hash_entries -unsigned_long* sysctl_local_reserved_ports -int sysctl_ip_prot_sock -struct_mr_table* mrt -struct_list_head mr_tables -struct_fib_rules_ops* mr_rules_ops -u32 sysctl_fib_multipath_hash_fields -u8 sysctl_fib_multipath_use_neigh -u8 sysctl_fib_multipath_hash_policy -struct_fib_notifier_ops* notifier_ops -unsigned_int fib_seq -struct_fib_notifier_ops* ipmr_notifier_ops -unsigned_int ipmr_seq -atomic_t rt_genid -siphash_key_t ip_id_key +u8 sysctl_tcp_tso_win_divisor read_mostly tcp_tso_should_defer(tcp_write_xmit) +u8 sysctl_tcp_workaround_signed_windows tcp_select_window +int sysctl_tcp_limit_output_bytes read_mostly tcp_small_queue_check(tcp_write_xmit) +int sysctl_tcp_challenge_ack_limit +int sysctl_tcp_min_rtt_wlen read_mostly tcp_ack_update_rtt +u8 sysctl_tcp_min_tso_segs unlikely(icsk_ca_ops-written) +u8 sysctl_tcp_tso_rtt_log read_mostly tcp_tso_autosize +u8 sysctl_tcp_autocorking read_mostly tcp_push/tcp_should_autocork +u8 sysctl_tcp_reflect_tos tcp_v(4/6)_send_synack +int sysctl_tcp_invalid_ratelimit +int sysctl_tcp_pacing_ss_ratio default_cong_cont(tcp_update_pacing_rate) +int sysctl_tcp_pacing_ca_ratio default_cong_cont(tcp_update_pacing_rate) +int sysctl_tcp_wmem[3] read_mostly tcp_wmem_schedule(sendmsg/sendpage) +int sysctl_tcp_rmem[3] read_mostly __tcp_grow_window(tx),tcp_rcv_space_adjust(rx) +unsigned_int sysctl_tcp_child_ehash_entries +unsigned_long sysctl_tcp_comp_sack_delay_ns __tcp_ack_snd_check +unsigned_long sysctl_tcp_comp_sack_slack_ns __tcp_ack_snd_check +int sysctl_max_syn_backlog +int sysctl_tcp_fastopen +struct_tcp_congestion_ops tcp_congestion_control init_cc +struct_tcp_fastopen_context tcp_fastopen_ctx +unsigned_int sysctl_tcp_fastopen_blackhole_timeout +atomic_t tfo_active_disable_times +unsigned_long tfo_active_disable_stamp +u32 tcp_challenge_timestamp +u32 tcp_challenge_count +u8 sysctl_tcp_plb_enabled +u8 sysctl_tcp_plb_idle_rehash_rounds +u8 sysctl_tcp_plb_rehash_rounds +u8 sysctl_tcp_plb_suspend_rto_sec +int sysctl_tcp_plb_cong_thresh +int sysctl_udp_wmem_min +int sysctl_udp_rmem_min +u8 sysctl_fib_notify_on_flag_change +u8 sysctl_udp_l3mdev_accept +u8 sysctl_igmp_llm_reports +int sysctl_igmp_max_memberships +int sysctl_igmp_max_msf +int sysctl_igmp_qrv +struct_ping_group_range ping_group_range +atomic_t dev_addr_genid +unsigned_int sysctl_udp_child_hash_entries +unsigned_long* sysctl_local_reserved_ports +int sysctl_ip_prot_sock +struct_mr_table* mrt +struct_list_head mr_tables +struct_fib_rules_ops* mr_rules_ops +u32 sysctl_fib_multipath_hash_fields +u8 sysctl_fib_multipath_use_neigh +u8 sysctl_fib_multipath_hash_policy +struct_fib_notifier_ops* notifier_ops +unsigned_int fib_seq +struct_fib_notifier_ops* ipmr_notifier_ops +unsigned_int ipmr_seq +atomic_t rt_genid +siphash_key_t ip_id_key +=============================== ============================================ =================== =================== ================================================= diff --git a/Documentation/networking/net_cachelines/snmp.rst b/Documentation/networking/net_cachelines/snmp.rst index 6a071538566c2a..90ca2d92547d44 100644 --- a/Documentation/networking/net_cachelines/snmp.rst +++ b/Documentation/networking/net_cachelines/snmp.rst @@ -5,131 +5,133 @@ netns_ipv4 enum fast path usage breakdown =========================================== +============== ===================================== =================== =================== ================================================== Type Name fastpath_tx_access fastpath_rx_access comment -..enum -unsigned_long LINUX_MIB_TCPKEEPALIVE write_mostly - tcp_keepalive_timer -unsigned_long LINUX_MIB_DELAYEDACKS write_mostly - tcp_delack_timer_handler,tcp_delack_timer -unsigned_long LINUX_MIB_DELAYEDACKLOCKED write_mostly - tcp_delack_timer_handler,tcp_delack_timer -unsigned_long LINUX_MIB_TCPAUTOCORKING write_mostly - tcp_push,tcp_sendmsg_locked -unsigned_long LINUX_MIB_TCPFROMZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb -unsigned_long LINUX_MIB_TCPTOZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb -unsigned_long LINUX_MIB_TCPWANTZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb -unsigned_long LINUX_MIB_TCPORIGDATASENT write_mostly - tcp_write_xmit -unsigned_long LINUX_MIB_TCPHPHITS - write_mostly tcp_rcv_established,tcp_v4_do_rcv,tcp_v6_do_rcv -unsigned_long LINUX_MIB_TCPRCVCOALESCE - write_mostly tcp_try_coalesce,tcp_queue_rcv,tcp_rcv_established -unsigned_long LINUX_MIB_TCPPUREACKS - write_mostly tcp_ack,tcp_rcv_established -unsigned_long LINUX_MIB_TCPHPACKS - write_mostly tcp_ack,tcp_rcv_established -unsigned_long LINUX_MIB_TCPDELIVERED - write_mostly tcp_newly_delivered,tcp_ack,tcp_rcv_established -unsigned_long LINUX_MIB_SYNCOOKIESSENT -unsigned_long LINUX_MIB_SYNCOOKIESRECV -unsigned_long LINUX_MIB_SYNCOOKIESFAILED -unsigned_long LINUX_MIB_EMBRYONICRSTS -unsigned_long LINUX_MIB_PRUNECALLED -unsigned_long LINUX_MIB_RCVPRUNED -unsigned_long LINUX_MIB_OFOPRUNED -unsigned_long LINUX_MIB_OUTOFWINDOWICMPS -unsigned_long LINUX_MIB_LOCKDROPPEDICMPS -unsigned_long LINUX_MIB_ARPFILTER -unsigned_long LINUX_MIB_TIMEWAITED -unsigned_long LINUX_MIB_TIMEWAITRECYCLED -unsigned_long LINUX_MIB_TIMEWAITKILLED -unsigned_long LINUX_MIB_PAWSACTIVEREJECTED -unsigned_long LINUX_MIB_PAWSESTABREJECTED -unsigned_long LINUX_MIB_DELAYEDACKLOST -unsigned_long LINUX_MIB_LISTENOVERFLOWS -unsigned_long LINUX_MIB_LISTENDROPS -unsigned_long LINUX_MIB_TCPRENORECOVERY -unsigned_long LINUX_MIB_TCPSACKRECOVERY -unsigned_long LINUX_MIB_TCPSACKRENEGING -unsigned_long LINUX_MIB_TCPSACKREORDER -unsigned_long LINUX_MIB_TCPRENOREORDER -unsigned_long LINUX_MIB_TCPTSREORDER -unsigned_long LINUX_MIB_TCPFULLUNDO -unsigned_long LINUX_MIB_TCPPARTIALUNDO -unsigned_long LINUX_MIB_TCPDSACKUNDO -unsigned_long LINUX_MIB_TCPLOSSUNDO -unsigned_long LINUX_MIB_TCPLOSTRETRANSMIT -unsigned_long LINUX_MIB_TCPRENOFAILURES -unsigned_long LINUX_MIB_TCPSACKFAILURES -unsigned_long LINUX_MIB_TCPLOSSFAILURES -unsigned_long LINUX_MIB_TCPFASTRETRANS -unsigned_long LINUX_MIB_TCPSLOWSTARTRETRANS -unsigned_long LINUX_MIB_TCPTIMEOUTS -unsigned_long LINUX_MIB_TCPLOSSPROBES -unsigned_long LINUX_MIB_TCPLOSSPROBERECOVERY -unsigned_long LINUX_MIB_TCPRENORECOVERYFAIL -unsigned_long LINUX_MIB_TCPSACKRECOVERYFAIL -unsigned_long LINUX_MIB_TCPRCVCOLLAPSED -unsigned_long LINUX_MIB_TCPDSACKOLDSENT -unsigned_long LINUX_MIB_TCPDSACKOFOSENT -unsigned_long LINUX_MIB_TCPDSACKRECV -unsigned_long LINUX_MIB_TCPDSACKOFORECV -unsigned_long LINUX_MIB_TCPABORTONDATA -unsigned_long LINUX_MIB_TCPABORTONCLOSE -unsigned_long LINUX_MIB_TCPABORTONMEMORY -unsigned_long LINUX_MIB_TCPABORTONTIMEOUT -unsigned_long LINUX_MIB_TCPABORTONLINGER -unsigned_long LINUX_MIB_TCPABORTFAILED -unsigned_long LINUX_MIB_TCPMEMORYPRESSURES -unsigned_long LINUX_MIB_TCPMEMORYPRESSURESCHRONO -unsigned_long LINUX_MIB_TCPSACKDISCARD -unsigned_long LINUX_MIB_TCPDSACKIGNOREDOLD -unsigned_long LINUX_MIB_TCPDSACKIGNOREDNOUNDO -unsigned_long LINUX_MIB_TCPSPURIOUSRTOS -unsigned_long LINUX_MIB_TCPMD5NOTFOUND -unsigned_long LINUX_MIB_TCPMD5UNEXPECTED -unsigned_long LINUX_MIB_TCPMD5FAILURE -unsigned_long LINUX_MIB_SACKSHIFTED -unsigned_long LINUX_MIB_SACKMERGED -unsigned_long LINUX_MIB_SACKSHIFTFALLBACK -unsigned_long LINUX_MIB_TCPBACKLOGDROP -unsigned_long LINUX_MIB_PFMEMALLOCDROP -unsigned_long LINUX_MIB_TCPMINTTLDROP -unsigned_long LINUX_MIB_TCPDEFERACCEPTDROP -unsigned_long LINUX_MIB_IPRPFILTER -unsigned_long LINUX_MIB_TCPTIMEWAITOVERFLOW -unsigned_long LINUX_MIB_TCPREQQFULLDOCOOKIES -unsigned_long LINUX_MIB_TCPREQQFULLDROP -unsigned_long LINUX_MIB_TCPRETRANSFAIL -unsigned_long LINUX_MIB_TCPBACKLOGCOALESCE -unsigned_long LINUX_MIB_TCPOFOQUEUE -unsigned_long LINUX_MIB_TCPOFODROP -unsigned_long LINUX_MIB_TCPOFOMERGE -unsigned_long LINUX_MIB_TCPCHALLENGEACK -unsigned_long LINUX_MIB_TCPSYNCHALLENGE -unsigned_long LINUX_MIB_TCPFASTOPENACTIVE -unsigned_long LINUX_MIB_TCPFASTOPENACTIVEFAIL -unsigned_long LINUX_MIB_TCPFASTOPENPASSIVE -unsigned_long LINUX_MIB_TCPFASTOPENPASSIVEFAIL -unsigned_long LINUX_MIB_TCPFASTOPENLISTENOVERFLOW -unsigned_long LINUX_MIB_TCPFASTOPENCOOKIEREQD -unsigned_long LINUX_MIB_TCPFASTOPENBLACKHOLE -unsigned_long LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES -unsigned_long LINUX_MIB_BUSYPOLLRXPACKETS -unsigned_long LINUX_MIB_TCPSYNRETRANS -unsigned_long LINUX_MIB_TCPHYSTARTTRAINDETECT -unsigned_long LINUX_MIB_TCPHYSTARTTRAINCWND -unsigned_long LINUX_MIB_TCPHYSTARTDELAYDETECT -unsigned_long LINUX_MIB_TCPHYSTARTDELAYCWND -unsigned_long LINUX_MIB_TCPACKSKIPPEDSYNRECV -unsigned_long LINUX_MIB_TCPACKSKIPPEDPAWS -unsigned_long LINUX_MIB_TCPACKSKIPPEDSEQ -unsigned_long LINUX_MIB_TCPACKSKIPPEDFINWAIT2 -unsigned_long LINUX_MIB_TCPACKSKIPPEDTIMEWAIT -unsigned_long LINUX_MIB_TCPACKSKIPPEDCHALLENGE -unsigned_long LINUX_MIB_TCPWINPROBE -unsigned_long LINUX_MIB_TCPMTUPFAIL -unsigned_long LINUX_MIB_TCPMTUPSUCCESS -unsigned_long LINUX_MIB_TCPDELIVEREDCE -unsigned_long LINUX_MIB_TCPACKCOMPRESSED -unsigned_long LINUX_MIB_TCPZEROWINDOWDROP -unsigned_long LINUX_MIB_TCPRCVQDROP -unsigned_long LINUX_MIB_TCPWQUEUETOOBIG -unsigned_long LINUX_MIB_TCPFASTOPENPASSIVEALTKEY -unsigned_long LINUX_MIB_TCPTIMEOUTREHASH -unsigned_long LINUX_MIB_TCPDUPLICATEDATAREHASH -unsigned_long LINUX_MIB_TCPDSACKRECVSEGS -unsigned_long LINUX_MIB_TCPDSACKIGNOREDDUBIOUS -unsigned_long LINUX_MIB_TCPMIGRATEREQSUCCESS -unsigned_long LINUX_MIB_TCPMIGRATEREQFAILURE -unsigned_long __LINUX_MIB_MAX +============== ===================================== =================== =================== ================================================== +unsigned_long LINUX_MIB_TCPKEEPALIVE write_mostly tcp_keepalive_timer +unsigned_long LINUX_MIB_DELAYEDACKS write_mostly tcp_delack_timer_handler,tcp_delack_timer +unsigned_long LINUX_MIB_DELAYEDACKLOCKED write_mostly tcp_delack_timer_handler,tcp_delack_timer +unsigned_long LINUX_MIB_TCPAUTOCORKING write_mostly tcp_push,tcp_sendmsg_locked +unsigned_long LINUX_MIB_TCPFROMZEROWINDOWADV write_mostly tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPTOZEROWINDOWADV write_mostly tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPWANTZEROWINDOWADV write_mostly tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPORIGDATASENT write_mostly tcp_write_xmit +unsigned_long LINUX_MIB_TCPHPHITS write_mostly tcp_rcv_established,tcp_v4_do_rcv,tcp_v6_do_rcv +unsigned_long LINUX_MIB_TCPRCVCOALESCE write_mostly tcp_try_coalesce,tcp_queue_rcv,tcp_rcv_established +unsigned_long LINUX_MIB_TCPPUREACKS write_mostly tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_TCPHPACKS write_mostly tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_TCPDELIVERED write_mostly tcp_newly_delivered,tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_SYNCOOKIESSENT +unsigned_long LINUX_MIB_SYNCOOKIESRECV +unsigned_long LINUX_MIB_SYNCOOKIESFAILED +unsigned_long LINUX_MIB_EMBRYONICRSTS +unsigned_long LINUX_MIB_PRUNECALLED +unsigned_long LINUX_MIB_RCVPRUNED +unsigned_long LINUX_MIB_OFOPRUNED +unsigned_long LINUX_MIB_OUTOFWINDOWICMPS +unsigned_long LINUX_MIB_LOCKDROPPEDICMPS +unsigned_long LINUX_MIB_ARPFILTER +unsigned_long LINUX_MIB_TIMEWAITED +unsigned_long LINUX_MIB_TIMEWAITRECYCLED +unsigned_long LINUX_MIB_TIMEWAITKILLED +unsigned_long LINUX_MIB_PAWSACTIVEREJECTED +unsigned_long LINUX_MIB_PAWSESTABREJECTED +unsigned_long LINUX_MIB_DELAYEDACKLOST +unsigned_long LINUX_MIB_LISTENOVERFLOWS +unsigned_long LINUX_MIB_LISTENDROPS +unsigned_long LINUX_MIB_TCPRENORECOVERY +unsigned_long LINUX_MIB_TCPSACKRECOVERY +unsigned_long LINUX_MIB_TCPSACKRENEGING +unsigned_long LINUX_MIB_TCPSACKREORDER +unsigned_long LINUX_MIB_TCPRENOREORDER +unsigned_long LINUX_MIB_TCPTSREORDER +unsigned_long LINUX_MIB_TCPFULLUNDO +unsigned_long LINUX_MIB_TCPPARTIALUNDO +unsigned_long LINUX_MIB_TCPDSACKUNDO +unsigned_long LINUX_MIB_TCPLOSSUNDO +unsigned_long LINUX_MIB_TCPLOSTRETRANSMIT +unsigned_long LINUX_MIB_TCPRENOFAILURES +unsigned_long LINUX_MIB_TCPSACKFAILURES +unsigned_long LINUX_MIB_TCPLOSSFAILURES +unsigned_long LINUX_MIB_TCPFASTRETRANS +unsigned_long LINUX_MIB_TCPSLOWSTARTRETRANS +unsigned_long LINUX_MIB_TCPTIMEOUTS +unsigned_long LINUX_MIB_TCPLOSSPROBES +unsigned_long LINUX_MIB_TCPLOSSPROBERECOVERY +unsigned_long LINUX_MIB_TCPRENORECOVERYFAIL +unsigned_long LINUX_MIB_TCPSACKRECOVERYFAIL +unsigned_long LINUX_MIB_TCPRCVCOLLAPSED +unsigned_long LINUX_MIB_TCPDSACKOLDSENT +unsigned_long LINUX_MIB_TCPDSACKOFOSENT +unsigned_long LINUX_MIB_TCPDSACKRECV +unsigned_long LINUX_MIB_TCPDSACKOFORECV +unsigned_long LINUX_MIB_TCPABORTONDATA +unsigned_long LINUX_MIB_TCPABORTONCLOSE +unsigned_long LINUX_MIB_TCPABORTONMEMORY +unsigned_long LINUX_MIB_TCPABORTONTIMEOUT +unsigned_long LINUX_MIB_TCPABORTONLINGER +unsigned_long LINUX_MIB_TCPABORTFAILED +unsigned_long LINUX_MIB_TCPMEMORYPRESSURES +unsigned_long LINUX_MIB_TCPMEMORYPRESSURESCHRONO +unsigned_long LINUX_MIB_TCPSACKDISCARD +unsigned_long LINUX_MIB_TCPDSACKIGNOREDOLD +unsigned_long LINUX_MIB_TCPDSACKIGNOREDNOUNDO +unsigned_long LINUX_MIB_TCPSPURIOUSRTOS +unsigned_long LINUX_MIB_TCPMD5NOTFOUND +unsigned_long LINUX_MIB_TCPMD5UNEXPECTED +unsigned_long LINUX_MIB_TCPMD5FAILURE +unsigned_long LINUX_MIB_SACKSHIFTED +unsigned_long LINUX_MIB_SACKMERGED +unsigned_long LINUX_MIB_SACKSHIFTFALLBACK +unsigned_long LINUX_MIB_TCPBACKLOGDROP +unsigned_long LINUX_MIB_PFMEMALLOCDROP +unsigned_long LINUX_MIB_TCPMINTTLDROP +unsigned_long LINUX_MIB_TCPDEFERACCEPTDROP +unsigned_long LINUX_MIB_IPRPFILTER +unsigned_long LINUX_MIB_TCPTIMEWAITOVERFLOW +unsigned_long LINUX_MIB_TCPREQQFULLDOCOOKIES +unsigned_long LINUX_MIB_TCPREQQFULLDROP +unsigned_long LINUX_MIB_TCPRETRANSFAIL +unsigned_long LINUX_MIB_TCPBACKLOGCOALESCE +unsigned_long LINUX_MIB_TCPOFOQUEUE +unsigned_long LINUX_MIB_TCPOFODROP +unsigned_long LINUX_MIB_TCPOFOMERGE +unsigned_long LINUX_MIB_TCPCHALLENGEACK +unsigned_long LINUX_MIB_TCPSYNCHALLENGE +unsigned_long LINUX_MIB_TCPFASTOPENACTIVE +unsigned_long LINUX_MIB_TCPFASTOPENACTIVEFAIL +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVE +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVEFAIL +unsigned_long LINUX_MIB_TCPFASTOPENLISTENOVERFLOW +unsigned_long LINUX_MIB_TCPFASTOPENCOOKIEREQD +unsigned_long LINUX_MIB_TCPFASTOPENBLACKHOLE +unsigned_long LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES +unsigned_long LINUX_MIB_BUSYPOLLRXPACKETS +unsigned_long LINUX_MIB_TCPSYNRETRANS +unsigned_long LINUX_MIB_TCPHYSTARTTRAINDETECT +unsigned_long LINUX_MIB_TCPHYSTARTTRAINCWND +unsigned_long LINUX_MIB_TCPHYSTARTDELAYDETECT +unsigned_long LINUX_MIB_TCPHYSTARTDELAYCWND +unsigned_long LINUX_MIB_TCPACKSKIPPEDSYNRECV +unsigned_long LINUX_MIB_TCPACKSKIPPEDPAWS +unsigned_long LINUX_MIB_TCPACKSKIPPEDSEQ +unsigned_long LINUX_MIB_TCPACKSKIPPEDFINWAIT2 +unsigned_long LINUX_MIB_TCPACKSKIPPEDTIMEWAIT +unsigned_long LINUX_MIB_TCPACKSKIPPEDCHALLENGE +unsigned_long LINUX_MIB_TCPWINPROBE +unsigned_long LINUX_MIB_TCPMTUPFAIL +unsigned_long LINUX_MIB_TCPMTUPSUCCESS +unsigned_long LINUX_MIB_TCPDELIVEREDCE +unsigned_long LINUX_MIB_TCPACKCOMPRESSED +unsigned_long LINUX_MIB_TCPZEROWINDOWDROP +unsigned_long LINUX_MIB_TCPRCVQDROP +unsigned_long LINUX_MIB_TCPWQUEUETOOBIG +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVEALTKEY +unsigned_long LINUX_MIB_TCPTIMEOUTREHASH +unsigned_long LINUX_MIB_TCPDUPLICATEDATAREHASH +unsigned_long LINUX_MIB_TCPDSACKRECVSEGS +unsigned_long LINUX_MIB_TCPDSACKIGNOREDDUBIOUS +unsigned_long LINUX_MIB_TCPMIGRATEREQSUCCESS +unsigned_long LINUX_MIB_TCPMIGRATEREQFAILURE +unsigned_long __LINUX_MIB_MAX +============== ===================================== =================== =================== ================================================== diff --git a/Documentation/networking/net_cachelines/tcp_sock.rst b/Documentation/networking/net_cachelines/tcp_sock.rst index 1c154cbd18487e..1f79765072b10d 100644 --- a/Documentation/networking/net_cachelines/tcp_sock.rst +++ b/Documentation/networking/net_cachelines/tcp_sock.rst @@ -5,153 +5,155 @@ tcp_sock struct fast path usage breakdown ========================================= +============================= ======================= =================== =================== ================================================================================================================================================================================================================== Type Name fastpath_tx_access fastpath_rx_access Comments -..struct ..tcp_sock -struct_inet_connection_sock inet_conn +============================= ======================= =================== =================== ================================================================================================================================================================================================================== +struct inet_connection_sock inet_conn u16 tcp_header_len read_mostly read_mostly tcp_bound_to_half_wnd,tcp_current_mss(tx);tcp_rcv_established(rx) -u16 gso_segs read_mostly - tcp_xmit_size_goal +u16 gso_segs read_mostly tcp_xmit_size_goal __be32 pred_flags read_write read_mostly tcp_select_window(tx);tcp_rcv_established(rx) -u64 bytes_received - read_write tcp_rcv_nxt_update(rx) -u32 segs_in - read_write tcp_v6_rcv(rx) -u32 data_segs_in - read_write tcp_v6_rcv(rx) +u64 bytes_received read_write tcp_rcv_nxt_update(rx) +u32 segs_in read_write tcp_v6_rcv(rx) +u32 data_segs_in read_write tcp_v6_rcv(rx) u32 rcv_nxt read_mostly read_write tcp_cleanup_rbuf,tcp_send_ack,tcp_inq_hint,tcp_transmit_skb,tcp_receive_window(tx);tcp_v6_do_rcv,tcp_rcv_established,tcp_data_queue,tcp_receive_window,tcp_rcv_nxt_update(write)(rx) -u32 copied_seq - read_mostly tcp_cleanup_rbuf,tcp_rcv_space_adjust,tcp_inq_hint -u32 rcv_wup - read_write __tcp_cleanup_rbuf,tcp_receive_window,tcp_receive_established +u32 copied_seq read_mostly tcp_cleanup_rbuf,tcp_rcv_space_adjust,tcp_inq_hint +u32 rcv_wup read_write __tcp_cleanup_rbuf,tcp_receive_window,tcp_receive_established u32 snd_nxt read_write read_mostly tcp_rate_check_app_limited,__tcp_transmit_skb,tcp_event_new_data_sent(write)(tx);tcp_rcv_established,tcp_ack,tcp_clean_rtx_queue(rx) -u32 segs_out read_write - __tcp_transmit_skb -u32 data_segs_out read_write - __tcp_transmit_skb,tcp_update_skb_after_send -u64 bytes_sent read_write - __tcp_transmit_skb -u64 bytes_acked - read_write tcp_snd_una_update/tcp_ack -u32 dsack_dups +u32 segs_out read_write __tcp_transmit_skb +u32 data_segs_out read_write __tcp_transmit_skb,tcp_update_skb_after_send +u64 bytes_sent read_write __tcp_transmit_skb +u64 bytes_acked read_write tcp_snd_una_update/tcp_ack +u32 dsack_dups u32 snd_una read_mostly read_write tcp_wnd_end,tcp_urg_mode,tcp_minshall_check,tcp_cwnd_validate(tx);tcp_ack,tcp_may_update_window,tcp_clean_rtx_queue(write),tcp_ack_tstamp(rx) -u32 snd_sml read_write - tcp_minshall_check,tcp_minshall_update -u32 rcv_tstamp - read_mostly tcp_ack -u32 lsndtime read_write - tcp_slow_start_after_idle_check,tcp_event_data_sent -u32 last_oow_ack_time -u32 compressed_ack_rcv_nxt +u32 snd_sml read_write tcp_minshall_check,tcp_minshall_update +u32 rcv_tstamp read_mostly tcp_ack +u32 lsndtime read_write tcp_slow_start_after_idle_check,tcp_event_data_sent +u32 last_oow_ack_time +u32 compressed_ack_rcv_nxt u32 tsoffset read_mostly read_mostly tcp_established_options(tx);tcp_fast_parse_options(rx) -struct_list_head tsq_node - - -struct_list_head tsorted_sent_queue read_write - tcp_update_skb_after_send -u32 snd_wl1 - read_mostly tcp_may_update_window +struct list_head tsq_node +struct list_head tsorted_sent_queue read_write tcp_update_skb_after_send +u32 snd_wl1 read_mostly tcp_may_update_window u32 snd_wnd read_mostly read_mostly tcp_wnd_end,tcp_tso_should_defer(tx);tcp_fast_path_on(rx) -u32 max_window read_mostly - tcp_bound_to_half_wnd,forced_push +u32 max_window read_mostly tcp_bound_to_half_wnd,forced_push u32 mss_cache read_mostly read_mostly tcp_rate_check_app_limited,tcp_current_mss,tcp_sync_mss,tcp_sndbuf_expand,tcp_tso_should_defer(tx);tcp_update_pacing_rate,tcp_clean_rtx_queue(rx) u32 window_clamp read_mostly read_write tcp_rcv_space_adjust,__tcp_select_window -u32 rcv_ssthresh read_mostly - __tcp_select_window +u32 rcv_ssthresh read_mostly __tcp_select_window u8 scaling_ratio read_mostly read_mostly tcp_win_from_space -struct tcp_rack -u16 advmss - read_mostly tcp_rcv_space_adjust -u8 compressed_ack -u8:2 dup_ack_counter -u8:1 tlp_retrans +struct tcp_rack +u16 advmss read_mostly tcp_rcv_space_adjust +u8 compressed_ack +u8:2 dup_ack_counter +u8:1 tlp_retrans u8:1 tcp_usec_ts read_mostly read_mostly -u32 chrono_start read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) -u32[3] chrono_stat read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) -u8:2 chrono_type read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) -u8:1 rate_app_limited - read_write tcp_rate_gen -u8:1 fastopen_connect -u8:1 fastopen_no_cookie -u8:1 is_sack_reneg - read_mostly tcp_skb_entail,tcp_ack -u8:2 fastopen_client_fail -u8:4 nonagle read_write - tcp_skb_entail,tcp_push_pending_frames -u8:1 thin_lto -u8:1 recvmsg_inq -u8:1 repair read_mostly - tcp_write_xmit -u8:1 frto -u8 repair_queue - - -u8:2 save_syn -u8:1 syn_data -u8:1 syn_fastopen -u8:1 syn_fastopen_exp -u8:1 syn_fastopen_ch -u8:1 syn_data_acked -u8:1 is_cwnd_limited read_mostly - tcp_cwnd_validate,tcp_is_cwnd_limited -u32 tlp_high_seq - read_mostly tcp_ack -u32 tcp_tx_delay -u64 tcp_wstamp_ns read_write - tcp_pacing_check,tcp_tso_should_defer,tcp_update_skb_after_send +u32 chrono_start read_write tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u32[3] chrono_stat read_write tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u8:2 chrono_type read_write tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u8:1 rate_app_limited read_write tcp_rate_gen +u8:1 fastopen_connect +u8:1 fastopen_no_cookie +u8:1 is_sack_reneg read_mostly tcp_skb_entail,tcp_ack +u8:2 fastopen_client_fail +u8:4 nonagle read_write tcp_skb_entail,tcp_push_pending_frames +u8:1 thin_lto +u8:1 recvmsg_inq +u8:1 repair read_mostly tcp_write_xmit +u8:1 frto +u8 repair_queue +u8:2 save_syn +u8:1 syn_data +u8:1 syn_fastopen +u8:1 syn_fastopen_exp +u8:1 syn_fastopen_ch +u8:1 syn_data_acked +u8:1 is_cwnd_limited read_mostly tcp_cwnd_validate,tcp_is_cwnd_limited +u32 tlp_high_seq read_mostly tcp_ack +u32 tcp_tx_delay +u64 tcp_wstamp_ns read_write tcp_pacing_check,tcp_tso_should_defer,tcp_update_skb_after_send u64 tcp_clock_cache read_write read_write tcp_mstamp_refresh(tcp_write_xmit/tcp_rcv_space_adjust),__tcp_transmit_skb,tcp_tso_should_defer;timer u64 tcp_mstamp read_write read_write tcp_mstamp_refresh(tcp_write_xmit/tcp_rcv_space_adjust)(tx);tcp_rcv_space_adjust,tcp_rate_gen,tcp_clean_rtx_queue,tcp_ack_update_rtt/tcp_time_stamp(rx);timer u32 srtt_us read_mostly read_write tcp_tso_should_defer(tx);tcp_update_pacing_rate,__tcp_set_rto,tcp_rtt_estimator(rx) -u32 mdev_us read_write - tcp_rtt_estimator -u32 mdev_max_us -u32 rttvar_us - read_mostly __tcp_set_rto +u32 mdev_us read_write tcp_rtt_estimator +u32 mdev_max_us +u32 rttvar_us read_mostly __tcp_set_rto u32 rtt_seq read_write tcp_rtt_estimator -struct_minmax rtt_min - read_mostly tcp_min_rtt/tcp_rate_gen,tcp_min_rtttcp_update_rtt_min +struct minmax rtt_min read_mostly tcp_min_rtt/tcp_rate_gen,tcp_min_rtttcp_update_rtt_min u32 packets_out read_write read_write tcp_packets_in_flight(tx/rx);tcp_slow_start_after_idle_check,tcp_nagle_check,tcp_rate_skb_sent,tcp_event_new_data_sent,tcp_cwnd_validate,tcp_write_xmit(tx);tcp_ack,tcp_clean_rtx_queue,tcp_update_pacing_rate(rx) -u32 retrans_out - read_mostly tcp_packets_in_flight,tcp_rate_check_app_limited -u32 max_packets_out - read_write tcp_cwnd_validate -u32 cwnd_usage_seq - read_write tcp_cwnd_validate -u16 urg_data - read_mostly tcp_fast_path_check -u8 ecn_flags read_write - tcp_ecn_send -u8 keepalive_probes -u32 reordering read_mostly - tcp_sndbuf_expand -u32 reord_seen +u32 retrans_out read_mostly tcp_packets_in_flight,tcp_rate_check_app_limited +u32 max_packets_out read_write tcp_cwnd_validate +u32 cwnd_usage_seq read_write tcp_cwnd_validate +u16 urg_data read_mostly tcp_fast_path_check +u8 ecn_flags read_write tcp_ecn_send +u8 keepalive_probes +u32 reordering read_mostly tcp_sndbuf_expand +u32 reord_seen u32 snd_up read_write read_mostly tcp_mark_urg,tcp_urg_mode,__tcp_transmit_skb(tx);tcp_clean_rtx_queue(rx) -struct_tcp_options_received rx_opt read_mostly read_write tcp_established_options(tx);tcp_fast_path_on,tcp_ack_update_window,tcp_is_sack,tcp_data_queue,tcp_rcv_established,tcp_ack_update_rtt(rx) -u32 snd_ssthresh - read_mostly tcp_update_pacing_rate +struct tcp_options_received rx_opt read_mostly read_write tcp_established_options(tx);tcp_fast_path_on,tcp_ack_update_window,tcp_is_sack,tcp_data_queue,tcp_rcv_established,tcp_ack_update_rtt(rx) +u32 snd_ssthresh read_mostly tcp_update_pacing_rate u32 snd_cwnd read_mostly read_mostly tcp_snd_cwnd,tcp_rate_check_app_limited,tcp_tso_should_defer(tx);tcp_update_pacing_rate -u32 snd_cwnd_cnt -u32 snd_cwnd_clamp -u32 snd_cwnd_used -u32 snd_cwnd_stamp -u32 prior_cwnd -u32 prr_delivered +u32 snd_cwnd_cnt +u32 snd_cwnd_clamp +u32 snd_cwnd_used +u32 snd_cwnd_stamp +u32 prior_cwnd +u32 prr_delivered u32 prr_out read_mostly read_mostly tcp_rate_skb_sent,tcp_newly_delivered(tx);tcp_ack,tcp_rate_gen,tcp_clean_rtx_queue(rx) u32 delivered read_mostly read_write tcp_rate_skb_sent, tcp_newly_delivered(tx);tcp_ack, tcp_rate_gen, tcp_clean_rtx_queue (rx) u32 delivered_ce read_mostly read_write tcp_rate_skb_sent(tx);tcp_rate_gen(rx) -u32 lost - read_mostly tcp_ack +u32 lost read_mostly tcp_ack u32 app_limited read_write read_mostly tcp_rate_check_app_limited,tcp_rate_skb_sent(tx);tcp_rate_gen(rx) -u64 first_tx_mstamp read_write - tcp_rate_skb_sent -u64 delivered_mstamp read_write - tcp_rate_skb_sent -u32 rate_delivered - read_mostly tcp_rate_gen -u32 rate_interval_us - read_mostly rate_delivered,rate_app_limited +u64 first_tx_mstamp read_write tcp_rate_skb_sent +u64 delivered_mstamp read_write tcp_rate_skb_sent +u32 rate_delivered read_mostly tcp_rate_gen +u32 rate_interval_us read_mostly rate_delivered,rate_app_limited u32 rcv_wnd read_write read_mostly tcp_select_window,tcp_receive_window,tcp_fast_path_check -u32 write_seq read_write - tcp_rate_check_app_limited,tcp_write_queue_empty,tcp_skb_entail,forced_push,tcp_mark_push -u32 notsent_lowat read_mostly - tcp_stream_memory_free -u32 pushed_seq read_write - tcp_mark_push,forced_push +u32 write_seq read_write tcp_rate_check_app_limited,tcp_write_queue_empty,tcp_skb_entail,forced_push,tcp_mark_push +u32 notsent_lowat read_mostly tcp_stream_memory_free +u32 pushed_seq read_write tcp_mark_push,forced_push u32 lost_out read_mostly read_mostly tcp_left_out(tx);tcp_packets_in_flight(tx/rx);tcp_rate_check_app_limited(rx) u32 sacked_out read_mostly read_mostly tcp_left_out(tx);tcp_packets_in_flight(tx/rx);tcp_clean_rtx_queue(rx) -struct_hrtimer pacing_timer -struct_hrtimer compressed_ack_timer -struct_sk_buff* lost_skb_hint read_mostly tcp_clean_rtx_queue -struct_sk_buff* retransmit_skb_hint read_mostly - tcp_clean_rtx_queue -struct_rb_root out_of_order_queue - read_mostly tcp_data_queue,tcp_fast_path_check -struct_sk_buff* ooo_last_skb -struct_tcp_sack_block[1] duplicate_sack -struct_tcp_sack_block[4] selective_acks -struct_tcp_sack_block[4] recv_sack_cache -struct_sk_buff* highest_sack read_write - tcp_event_new_data_sent -int lost_cnt_hint -u32 prior_ssthresh -u32 high_seq -u32 retrans_stamp -u32 undo_marker -int undo_retrans -u64 bytes_retrans -u32 total_retrans -u32 rto_stamp -u16 total_rto -u16 total_rto_recoveries -u32 total_rto_time -u32 urg_seq - - -unsigned_int keepalive_time -unsigned_int keepalive_intvl -int linger2 -u8 bpf_sock_ops_cb_flags -u8:1 bpf_chg_cc_inprogress -u16 timeout_rehash -u32 rcv_ooopack -u32 rcv_rtt_last_tsecr -struct rcv_rtt_est - read_write tcp_rcv_space_adjust,tcp_rcv_established -struct rcvq_space - read_write tcp_rcv_space_adjust -struct mtu_probe -u32 plb_rehash -u32 mtu_info -bool is_mptcp -bool smc_hs_congested -bool syn_smc -struct_tcp_sock_af_ops* af_specific -struct_tcp_md5sig_info* md5sig_info -struct_tcp_fastopen_request* fastopen_req -struct_request_sock* fastopen_rsk -struct_saved_syn* saved_syn \ No newline at end of file +struct hrtimer pacing_timer +struct hrtimer compressed_ack_timer +struct sk_buff* lost_skb_hint read_mostly tcp_clean_rtx_queue +struct sk_buff* retransmit_skb_hint read_mostly tcp_clean_rtx_queue +struct rb_root out_of_order_queue read_mostly tcp_data_queue,tcp_fast_path_check +struct sk_buff* ooo_last_skb +struct tcp_sack_block[1] duplicate_sack +struct tcp_sack_block[4] selective_acks +struct tcp_sack_block[4] recv_sack_cache +struct sk_buff* highest_sack read_write tcp_event_new_data_sent +int lost_cnt_hint +u32 prior_ssthresh +u32 high_seq +u32 retrans_stamp +u32 undo_marker +int undo_retrans +u64 bytes_retrans +u32 total_retrans +u32 rto_stamp +u16 total_rto +u16 total_rto_recoveries +u32 total_rto_time +u32 urg_seq +unsigned_int keepalive_time +unsigned_int keepalive_intvl +int linger2 +u8 bpf_sock_ops_cb_flags +u8:1 bpf_chg_cc_inprogress +u16 timeout_rehash +u32 rcv_ooopack +u32 rcv_rtt_last_tsecr +struct rcv_rtt_est read_write tcp_rcv_space_adjust,tcp_rcv_established +struct rcvq_space read_write tcp_rcv_space_adjust +struct mtu_probe +u32 plb_rehash +u32 mtu_info +bool is_mptcp +bool smc_hs_congested +bool syn_smc +struct tcp_sock_af_ops* af_specific +struct tcp_md5sig_info* md5sig_info +struct tcp_fastopen_request* fastopen_req +struct request_sock* fastopen_rsk +struct saved_syn* saved_syn +============================= ======================= =================== =================== ================================================================================================================================================================================================================== diff --git a/Documentation/networking/net_dim.rst b/Documentation/networking/net_dim.rst index 8908fd7b0a8d23..4377998e6826d1 100644 --- a/Documentation/networking/net_dim.rst +++ b/Documentation/networking/net_dim.rst @@ -156,7 +156,7 @@ usage is not complete but it should make the outline of the usage clear. my_entity->bytes, &dim_sample); /* Call net DIM */ - net_dim(&my_entity->dim, dim_sample); + net_dim(&my_entity->dim, &dim_sample); ... } diff --git a/Documentation/networking/timestamping.rst b/Documentation/networking/timestamping.rst index 8199e691767189..b37bfbfc7d7970 100644 --- a/Documentation/networking/timestamping.rst +++ b/Documentation/networking/timestamping.rst @@ -194,6 +194,20 @@ SOF_TIMESTAMPING_OPT_ID: among all possibly concurrently outstanding timestamp requests for that socket. + The process can optionally override the default generated ID, by + passing a specific ID with control message SCM_TS_OPT_ID (not + supported for TCP sockets):: + + struct msghdr *msg; + ... + cmsg = CMSG_FIRSTHDR(msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_TS_OPT_ID; + cmsg->cmsg_len = CMSG_LEN(sizeof(__u32)); + *((__u32 *) CMSG_DATA(cmsg)) = opt_id; + err = sendmsg(fd, msg, 0); + + SOF_TIMESTAMPING_OPT_ID_TCP: Pass this modifier along with SOF_TIMESTAMPING_OPT_ID for new TCP timestamping applications. SOF_TIMESTAMPING_OPT_ID defines how the diff --git a/Documentation/networking/tipc.rst b/Documentation/networking/tipc.rst index ab63d298cca21d..9b375b9b9981f6 100644 --- a/Documentation/networking/tipc.rst +++ b/Documentation/networking/tipc.rst @@ -112,7 +112,7 @@ More Information - How to contribute to TIPC: -- http://tipc.io/contacts.html + http://tipc.io/contacts.html - More details about TIPC specification: diff --git a/Documentation/networking/tls-offload.rst b/Documentation/networking/tls-offload.rst index 5f0dea3d571e35..7354d48cdf9266 100644 --- a/Documentation/networking/tls-offload.rst +++ b/Documentation/networking/tls-offload.rst @@ -51,7 +51,7 @@ and send them to the device for encryption and transmission. RX -- -On the receive side if the device handled decryption and authentication +On the receive side, if the device handled decryption and authentication successfully, the driver will set the decrypted bit in the associated :c:type:`struct sk_buff `. The packets reach the TCP stack and are handled normally. ``ktls`` is informed when data is queued to the socket @@ -120,8 +120,9 @@ before installing the connection state in the kernel. RX -- -In RX direction local networking stack has little control over the segmentation, -so the initial records' TCP sequence number may be anywhere inside the segment. +In the RX direction, the local networking stack has little control over +segmentation, so the initial records' TCP sequence number may be anywhere +inside the segment. Normal operation ================ @@ -138,8 +139,8 @@ There are no guarantees on record length or record segmentation. In particular segments may start at any point of a record and contain any number of records. Assuming segments are received in order, the device should be able to perform crypto operations and authentication regardless of segmentation. For this -to be possible device has to keep small amount of segment-to-segment state. -This includes at least: +to be possible, the device has to keep a small amount of segment-to-segment +state. This includes at least: * partial headers (if a segment carried only a part of the TLS header) * partial data block @@ -175,12 +176,12 @@ and packet transformation functions) the device validates the Layer 4 checksum and performs a 5-tuple lookup to find any TLS connection the packet may belong to (technically a 4-tuple lookup is sufficient - IP addresses and TCP port numbers, as the protocol -is always TCP). If connection is matched device confirms if the TCP sequence -number is the expected one and proceeds to TLS handling (record delineation, -decryption, authentication for each record in the packet). The device leaves -the record framing unmodified, the stack takes care of record decapsulation. -Device indicates successful handling of TLS offload in the per-packet context -(descriptor) passed to the host. +is always TCP). If the packet is matched to a connection, the device confirms +if the TCP sequence number is the expected one and proceeds to TLS handling +(record delineation, decryption, authentication for each record in the packet). +The device leaves the record framing unmodified, the stack takes care of record +decapsulation. Device indicates successful handling of TLS offload in the +per-packet context (descriptor) passed to the host. Upon reception of a TLS offloaded packet, the driver sets the :c:member:`decrypted` mark in :c:type:`struct sk_buff ` @@ -439,7 +440,7 @@ by the driver: * ``rx_tls_resync_req_end`` - number of times the TLS async resync request properly ended with providing the HW tracked tcp-seq. * ``rx_tls_resync_req_skip`` - number of times the TLS async resync request - procedure was started by not properly ended. + procedure was started but not properly ended. * ``rx_tls_resync_res_ok`` - number of times the TLS resync response call to the driver was successfully handled. * ``rx_tls_resync_res_skip`` - number of times the TLS resync response call to @@ -507,8 +508,8 @@ in packets as seen on the wire. Transport layer transparency ---------------------------- -The device should not modify any packet headers for the purpose -of the simplifying TLS offload. +For the purpose of simplifying TLS offload, the device should not modify any +packet headers. The device should not depend on any packet headers beyond what is strictly necessary for TLS offload. diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst index 53d1996460abfc..12f429359a823e 100644 --- a/Documentation/power/runtime_pm.rst +++ b/Documentation/power/runtime_pm.rst @@ -347,7 +347,9 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: `int pm_runtime_resume_and_get(struct device *dev);` - run pm_runtime_resume(dev) and if successful, increment the device's - usage counter; return the result of pm_runtime_resume + usage counter; returns 0 on success (whether or not the device's + runtime PM status was already 'active') or the error code from + pm_runtime_resume() on failure. `int pm_request_idle(struct device *dev);` - submit a request to execute the subsystem-level idle callback for the diff --git a/Documentation/process/5.Posting.rst b/Documentation/process/5.Posting.rst index de4edd42d5c0b8..b3eff03ea2491c 100644 --- a/Documentation/process/5.Posting.rst +++ b/Documentation/process/5.Posting.rst @@ -191,11 +191,6 @@ change to a revision control system. It will be followed by: option to diff will associate function names with changes, making the resulting patch easier for others to read. -You should avoid including changes to irrelevant files (those generated by -the build process, for example, or editor backup files) in the patch. The -file "dontdiff" in the Documentation directory can help in this regard; -pass it to diff with the "-X" option. - The tags already briefly mentioned above are used to provide insights how the patch came into being. They are described in detail in the :ref:`Documentation/process/submitting-patches.rst ` diff --git a/Documentation/process/backporting.rst b/Documentation/process/backporting.rst index a71480fcf3b42c..c42779fbcd331e 100644 --- a/Documentation/process/backporting.rst +++ b/Documentation/process/backporting.rst @@ -74,7 +74,7 @@ your source tree. Don't forget to cherry-pick with ``-x`` if you want a written record of where the patch came from! Note that if you are submitting a patch for stable, the format is -slightly different; the first line after the subject line needs tobe +slightly different; the first line after the subject line needs to be either:: commit upstream @@ -553,7 +553,7 @@ Submitting backports to stable ============================== As the stable maintainers try to cherry-pick mainline fixes onto their -stable kernels, they may send out emails asking for backports when when +stable kernels, they may send out emails asking for backports when encountering conflicts, see e.g. . These emails typically include the exact steps you need to cherry-pick @@ -563,9 +563,9 @@ One thing to make sure is that your changelog conforms to the expected format:: - + [ Upstream commit ] - + [ ] Signed-off-by: diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 00f1ed7c59c321..82b5e378eebff3 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -46,7 +46,7 @@ jfsutils 1.1.3 fsck.jfs -V reiserfsprogs 3.6.3 reiserfsck -V xfsprogs 2.6.0 xfs_db -V squashfs-tools 4.0 mksquashfs -version -btrfs-progs 0.18 btrfsck +btrfs-progs 0.18 btrfs --version pcmciautils 004 pccardctl -V quota-tools 3.09 quota -V PPP 2.4.0 pppd --version diff --git a/Documentation/process/code-of-conduct-interpretation.rst b/Documentation/process/code-of-conduct-interpretation.rst index 66b07f14714c28..1d1150954be388 100644 --- a/Documentation/process/code-of-conduct-interpretation.rst +++ b/Documentation/process/code-of-conduct-interpretation.rst @@ -156,3 +156,90 @@ overridden decisions including complete and identifiable voting details. Because how we interpret and enforce the Code of Conduct will evolve over time, this document will be updated when necessary to reflect any changes. + +Enforcement for Unacceptable Behavior Code of Conduct Violations +---------------------------------------------------------------- + +The Code of Conduct committee works to ensure that our community continues +to be inclusive and fosters diverse discussions and viewpoints, and works +to improve those characteristics over time. A majority of the reports the +Code of Conduct Committee receives stem from incorrect understanding regarding +the development process and maintainers' roles, responsibilities, and their +right to make decisions on code acceptance. These are resolved through +clarification of the development process and the scope of the Code of Conduct. + +Unacceptable behaviors could interrupt respectful collaboration for a short +period of time and negatively impact the health of the community longer term. +Unacceptable behaviors often get resolved when individuals acknowledge their +behavior and make amends for it in the setting the violation has taken place. + +The Code of Conduct Committee receives reports about unacceptable behaviors +when they don't get resolved through community discussions. The Code of +Conduct committee takes measures to restore productive and respectful +collaboration when an unacceptable behavior has negatively impacted that +relationship. + +The Code of Conduct Committee has the obligation to keep the reports and +reporters' information private. Reports could come from injured parties +and community members who are observers of unacceptable behaviors. The +Code of Conduct Committee has the responsibility to investigate and resolve +these reports, working with all involved parties. + +The Code of Conduct Committee works with the individual to bring about +change in their understanding of the importance to repair the damage caused +by their behavior to the injured party and the long term negative impact +on the community. + +The goal is to reach a resolution which is agreeable to all parties. If +working with the individual fails to bring about the desired outcome, the +Code of Conduct Committee will evaluate other measures such as seeking +public apology to repair the damage. + +Seek public apology for the violation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Code of Conduct Committee publicly calls out the behavior in the +setting in which the violation has taken place, seeking public apology +for the violation. + +A public apology for the violation is the first step towards rebuilding +the trust. Trust is essential for the continued success and health of the +community which operates on trust and respect. + +Remedial measures if there is no public apology for the violation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Code of Conduct Committee determines the next course of action to restore +the healthy collaboration by recommending remedial measure(s) to the TAB for +approval. + +- Ban violator from participating in the kernel development process for + a period of up to a full kernel development cycle. The Code of Conduct + Committee could require public apology as a condition for lifting the + ban. + +The scope of the ban for a period of time could include: + + a. denying patch contributions and pull requests + b. pausing collaboration with the violator by ignoring their + contributions and/or blocking their email account(s) + c. restricting their ability to communicate via kernel.org platforms, + such as mailing lists and social media sites + +Once the TAB approves one or more of the measures outlined in the scope of +the ban by a two-thirds vote, the Code of Conduct Committee will enforce +the TAB approved measure(s) in collaboration with the community, maintainers, +sub-maintainers, and kernel.org administrators. + +The Code of Conduct Committee is mindful of the negative impact of seeking +public apology and instituting ban could have on individuals. It is also +mindful of the longer term harm to the community that could result from +not taking action when such serious public violations occur. + +The effectiveness of the remedial measure(s) approved by the TAB depends +on the trust and cooperation from the community, maintainers, sub-maintainers, +and kernel.org administrators in enforcing them. + +The Code of Conduct Committee sincerely hopes that unacceptable behaviors +that require seeking public apologies continue to be exceedingly rare +occurrences in the future. diff --git a/Documentation/process/debugging/driver_development_debugging_guide.rst b/Documentation/process/debugging/driver_development_debugging_guide.rst new file mode 100644 index 00000000000000..aef2040942050b --- /dev/null +++ b/Documentation/process/debugging/driver_development_debugging_guide.rst @@ -0,0 +1,223 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======================================== +Debugging advice for driver development +======================================== + +This document serves as a general starting point and lookup for debugging +device drivers. +While this guide focuses on debugging that requires re-compiling the +module/kernel, the :doc:`userspace debugging guide +` will guide +you through tools like dynamic debug, ftrace and other tools useful for +debugging issues and behavior. +For general debugging advice, see the :doc:`general advice document +`. + +.. contents:: + :depth: 3 + +The following sections show you the available tools. + +printk() & friends +------------------ + +These are derivatives of printf() with varying destinations and support for +being dynamically turned on or off, or lack thereof. + +Simple printk() +~~~~~~~~~~~~~~~ + +The classic, can be used to great effect for quick and dirty development +of new modules or to extract arbitrary necessary data for troubleshooting. + +Prerequisite: ``CONFIG_PRINTK`` (usually enabled by default) + +**Pros**: + +- No need to learn anything, simple to use +- Easy to modify exactly to your needs (formatting of the data (See: + :doc:`/core-api/printk-formats`), visibility in the log) +- Can cause delays in the execution of the code (beneficial to confirm whether + timing is a factor) + +**Cons**: + +- Requires rebuilding the kernel/module +- Can cause delays in the execution of the code (which can cause issues to be + not reproducible) + +For the full documentation see :doc:`/core-api/printk-basics` + +Trace_printk +~~~~~~~~~~~~ + +Prerequisite: ``CONFIG_DYNAMIC_FTRACE`` & ``#include `` + +It is a tiny bit less comfortable to use than printk(), because you will have +to read the messages from the trace file (See: :ref:`read_ftrace_log` +instead of from the kernel log, but very useful when printk() adds unwanted +delays into the code execution, causing issues to be flaky or hidden.) + +If the processing of this still causes timing issues then you can try +trace_puts(). + +For the full Documentation see trace_printk() + +dev_dbg +~~~~~~~ + +Print statement, which can be targeted by +:ref:`process/debugging/userspace_debugging_guide:dynamic debug` that contains +additional information about the device used within the context. + +**When is it appropriate to leave a debug print in the code?** + +Permanent debug statements have to be useful for a developer to troubleshoot +driver misbehavior. Judging that is a bit more of an art than a science, but +some guidelines are in the :ref:`Coding style guidelines +`. In almost all cases the +debug statements shouldn't be upstreamed, as a working driver is supposed to be +silent. + +Custom printk +~~~~~~~~~~~~~ + +Example:: + + #define core_dbg(fmt, arg...) do { \ + if (core_debug) \ + printk(KERN_DEBUG pr_fmt("core: " fmt), ## arg); \ + } while (0) + +**When should you do this?** + +It is better to just use a pr_debug(), which can later be turned on/off with +dynamic debug. Additionally, a lot of drivers activate these prints via a +variable like ``core_debug`` set by a module parameter. However, Module +parameters `are not recommended anymore +`_. + +Ftrace +------ + +Creating a custom Ftrace tracepoint +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A tracepoint adds a hook into your code that will be called and logged when the +tracepoint is enabled. This can be used, for example, to trace hitting a +conditional branch or to dump the internal state at specific points of the code +flow during a debugging session. + +Here is a basic description of :ref:`how to implement new tracepoints +`. + +For the full event tracing documentation see :doc:`/trace/events` + +For the full Ftrace documentation see :doc:`/trace/ftrace` + +DebugFS +------- + +Prerequisite: ``CONFIG_DEBUG_FS` & `#include `` + +DebugFS differs from the other approaches of debugging, as it doesn't write +messages to the kernel log nor add traces to the code. Instead it allows the +developer to handle a set of files. +With these files you can either store values of variables or make +register/memory dumps or you can make these files writable and modify +values/settings in the driver. + +Possible use-cases among others: + +- Store register values +- Keep track of variables +- Store errors +- Store settings +- Toggle a setting like debug on/off +- Error injection + +This is especially useful, when the size of a data dump would be hard to digest +as part of the general kernel log (for example when dumping raw bitstream data) +or when you are not interested in all the values all the time, but with the +possibility to inspect them. + +The general idea is: + +- Create a directory during probe (``struct dentry *parent = + debugfs_create_dir("my_driver", NULL);``) +- Create a file (``debugfs_create_u32("my_value", 444, parent, &my_variable);``) + + - In this example the file is found in + ``/sys/kernel/debug/my_driver/my_value`` (with read permissions for + user/group/all) + - any read of the file will return the current contents of the variable + ``my_variable`` + +- Clean up the directory when removing the device + (``debugfs_remove_recursive(parent);``) + +For the full documentation see :doc:`/filesystems/debugfs`. + +KASAN, UBSAN, lockdep and other error checkers +---------------------------------------------- + +KASAN (Kernel Address Sanitizer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prerequisite: ``CONFIG_KASAN`` + +KASAN is a dynamic memory error detector that helps to find use-after-free and +out-of-bounds bugs. It uses compile-time instrumentation to check every memory +access. + +For the full documentation see :doc:`/dev-tools/kasan`. + +UBSAN (Undefined Behavior Sanitizer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prerequisite: ``CONFIG_UBSAN`` + +UBSAN relies on compiler instrumentation and runtime checks to detect undefined +behavior. It is designed to find a variety of issues, including signed integer +overflow, array index out of bounds, and more. + +For the full documentation see :doc:`/dev-tools/ubsan` + +lockdep (Lock Dependency Validator) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prerequisite: ``CONFIG_DEBUG_LOCKDEP`` + +lockdep is a runtime lock dependency validator that detects potential deadlocks +and other locking-related issues in the kernel. +It tracks lock acquisitions and releases, building a dependency graph that is +analyzed for potential deadlocks. +lockdep is especially useful for validating the correctness of lock ordering in +the kernel. + +PSI (Pressure stall information tracking) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prerequisite: ``CONFIG_PSI`` + +PSI is a measurement tool to identify excessive overcommits on hardware +resources, that can cause performance disruptions or even OOM kills. + +device coredump +--------------- + +Prerequisite: ``#include `` + +Provides the infrastructure for a driver to provide arbitrary data to userland. +It is most often used in conjunction with udev or similar userland application +to listen for kernel uevents, which indicate that the dump is ready. Udev has +rules to copy that file somewhere for long-term storage and analysis, as by +default, the data for the dump is automatically cleaned up after 5 minutes. +That data is analyzed with driver-specific tools or GDB. + +You can find an example implementation at: +`drivers/media/platform/qcom/venus/core.c +`__ + +**Copyright** ©2024 : Collabora diff --git a/Documentation/process/debugging/index.rst b/Documentation/process/debugging/index.rst new file mode 100644 index 00000000000000..f6e4a00dfee32b --- /dev/null +++ b/Documentation/process/debugging/index.rst @@ -0,0 +1,78 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================ +Debugging advice for Linux Kernel developers +============================================ + +general guides +-------------- + +.. toctree:: + :maxdepth: 1 + + driver_development_debugging_guide + userspace_debugging_guide + +.. only:: subproject and html + +subsystem specific guides +------------------------- + +.. toctree:: + :maxdepth: 1 + + media_specific_debugging_guide + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` + +General debugging advice +======================== + +Depending on the issue, a different set of tools is available to track down the +problem or even to realize whether there is one in the first place. + +As a first step you have to figure out what kind of issue you want to debug. +Depending on the answer, your methodology and choice of tools may vary. + +Do I need to debug with limited access? +--------------------------------------- + +Do you have limited access to the machine or are you unable to stop the running +execution? + +In this case your debugging capability depends on built-in debugging support of +provided distribution kernel. +The :doc:`/process/debugging/userspace_debugging_guide` provides a brief +overview over a range of possible debugging tools in that situation. You can +check the capability of your kernel, in most cases, by looking into config file +within the /boot directory. + +Do I have root access to the system? +------------------------------------ + +Are you easily able to replace the module in question or to install a new +kernel? + +In that case your range of available tools is a lot bigger, you can find the +tools in the :doc:`/process/debugging/driver_development_debugging_guide`. + +Is timing a factor? +------------------- + +It is important to understand if the problem you want to debug manifests itself +consistently (i.e. given a set of inputs you always get the same, incorrect +output), or inconsistently. If it manifests itself inconsistently, some timing +factor might be at play. If inserting delays into the code does change the +behavior, then quite likely timing is a factor. + +When timing does alter the outcome of the code execution using a simple +printk() for debugging purposes may not work, a similar alternative is to use +trace_printk() , which logs the debug messages to the trace file instead of the +kernel log. + +**Copyright** ©2024 : Collabora diff --git a/Documentation/process/debugging/media_specific_debugging_guide.rst b/Documentation/process/debugging/media_specific_debugging_guide.rst new file mode 100644 index 00000000000000..c5a93bafaf6753 --- /dev/null +++ b/Documentation/process/debugging/media_specific_debugging_guide.rst @@ -0,0 +1,180 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================ +Debugging and tracing in the media subsystem +============================================ + +This document serves as a starting point and lookup for debugging device +drivers in the media subsystem and to debug these drivers from userspace. + +.. contents:: + :depth: 3 + +General debugging advice +------------------------ + +For general advice see the :doc:`general advice document +`. + +The following sections show you some of the available tools. + +dev_debug module parameter +-------------------------- + +Every video device provides a ``dev_debug`` parameter, which allows to get +further insights into the IOCTLs in the background.:: + + # cat /sys/class/video4linux/video3/name + rkvdec + # echo 0xff > /sys/class/video4linux/video3/dev_debug + # dmesg -wH + [...] videodev: v4l2_open: video3: open (0) + [ +0.000036] video3: VIDIOC_QUERYCAP: driver=rkvdec, card=rkvdec, + bus=platform:rkvdec, version=0x00060900, capabilities=0x84204000, + device_caps=0x04204000 + +For the full documentation see :ref:`driver-api/media/v4l2-dev:video device +debugging` + +dev_dbg() / v4l2_dbg() +---------------------- + +Two debug print statements, which are specific for devices and for the v4l2 +subsystem, avoid adding these to your final submission unless they have +long-term value for investigations. + +For a general overview please see the +:ref:`process/debugging/driver_development_debugging_guide:printk() & friends` +guide. + +- Difference between both? + + - v4l2_dbg() utilizes v4l2_printk() under the hood, which further uses + printk() directly, thus it cannot be targeted by dynamic debug + - dev_dbg() can be targeted by dynamic debug + - v4l2_dbg() has a more specific prefix format for the media subsystem, while + dev_dbg only highlights the driver name and the location of the log + +Dynamic debug +------------- + +A method to trim down the debug output to your needs. + +For general advice see the +:ref:`process/debugging/userspace_debugging_guide:dynamic debug` guide. + +Here is one example, that enables all available pr_debug()'s within the file:: + + $ alias ddcmd='echo $* > /proc/dynamic_debug/control' + $ ddcmd '-p; file v4l2-h264.c +p' + $ grep =p /proc/dynamic_debug/control + drivers/media/v4l2-core/v4l2-h264.c:372 [v4l2_h264]print_ref_list_b =p + "ref_pic_list_b%u (cur_poc %u%c) %s" + drivers/media/v4l2-core/v4l2-h264.c:333 [v4l2_h264]print_ref_list_p =p + "ref_pic_list_p (cur_poc %u%c) %s\n" + +Ftrace +------ + +An internal kernel tracer that can trace static predefined events, function +calls, etc. Very useful for debugging problems without changing the kernel and +understanding the behavior of subsystems. + +For general advice see the +:ref:`process/debugging/userspace_debugging_guide:ftrace` guide. + +DebugFS +------- + +This tool allows you to dump or modify internal values of your driver to files +in a custom filesystem. + +For general advice see the +:ref:`process/debugging/driver_development_debugging_guide:debugfs` guide. + +Perf & alternatives +------------------- + +Tools to measure the various stats on a running system to diagnose issues. + +For general advice see the +:ref:`process/debugging/userspace_debugging_guide:perf & alternatives` guide. + +Example for media devices: + +Gather statistics data for a decoding job: (This example is on a RK3399 SoC +with the rkvdec codec driver using the `fluster test suite +`__):: + + perf stat -d python3 fluster.py run -d GStreamer-H.264-V4L2SL-Gst1.0 -ts + JVT-AVC_V1 -tv AUD_MW_E -j1 + ... + Performance counter stats for 'python3 fluster.py run -d + GStreamer-H.264-V4L2SL-Gst1.0 -ts JVT-AVC_V1 -tv AUD_MW_E -j1 -v': + + 7794.23 msec task-clock:u # 0.697 CPUs utilized + 0 context-switches:u # 0.000 /sec + 0 cpu-migrations:u # 0.000 /sec + 11901 page-faults:u # 1.527 K/sec + 882671556 cycles:u # 0.113 GHz (95.79%) + 711708695 instructions:u # 0.81 insn per cycle (95.79%) + 10581935 branches:u # 1.358 M/sec (15.13%) + 6871144 branch-misses:u # 64.93% of all branches (95.79%) + 281716547 L1-dcache-loads:u # 36.144 M/sec (95.79%) + 9019581 L1-dcache-load-misses:u # 3.20% of all L1-dcache accesses (95.79%) + LLC-loads:u + LLC-load-misses:u + + 11.180830431 seconds time elapsed + + 1.502318000 seconds user + 6.377221000 seconds sys + +The availability of events and metrics depends on the system you are running. + +Error checking & panic analysis +------------------------------- + +Various Kernel configuration options to enhance error detection of the Linux +Kernel with the cost of lowering performance. + +For general advice see the +:ref:`process/debugging/driver_development_debugging_guide:kasan, ubsan, +lockdep and other error checkers` guide. + +Driver verification with v4l2-compliance +---------------------------------------- + +To verify, that a driver adheres to the v4l2 API, the tool v4l2-compliance is +used, which is part of the `v4l_utils +`__, a suite of userspace tools to work +with the media subsystem. + +To see the detailed media topology (and check it) use:: + + v4l2-compliance -M /dev/mediaX --verbose + +You can also run a full compliance check for all devices referenced in the +media topology with:: + + v4l2-compliance -m /dev/mediaX + +Debugging problems with receiving video +--------------------------------------- + +Implementing vidioc_log_status in the driver: this can log the current status +to the kernel log. It's called by v4l2-ctl --log-status. Very useful for +debugging problems with receiving video (TV/S-Video/HDMI/etc) since the video +signal is external (so unpredictable). Less useful with camera sensor inputs +since you have control over what the camera sensor does. + +Usually you can just assign the default:: + + .vidioc_log_status = v4l2_ctrl_log_status, + +But you can also create your own callback, to create a custom status log. + +You can find an example in the cobalt driver +(`drivers/media/pci/cobalt/cobalt-v4l2.c `__). + +**Copyright** ©2024 : Collabora diff --git a/Documentation/process/debugging/userspace_debugging_guide.rst b/Documentation/process/debugging/userspace_debugging_guide.rst new file mode 100644 index 00000000000000..db7396261e07ad --- /dev/null +++ b/Documentation/process/debugging/userspace_debugging_guide.rst @@ -0,0 +1,280 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========================== +Userspace debugging advice +========================== + +This document provides a brief overview of common tools to debug the Linux +Kernel from userspace. +For debugging advice aimed at driver developers go :doc:`here +`. +For general debugging advice, see :doc:`general advice document +`. + +.. contents:: + :depth: 3 + +The following sections show you the available tools. + +Dynamic debug +------------- + +Mechanism to filter what ends up in the kernel log by dis-/en-abling log +messages. + +Prerequisite: ``CONFIG_DYNAMIC_DEBUG`` + +Dynamic debug is only able to target: + +- pr_debug() +- dev_dbg() +- print_hex_dump_debug() +- print_hex_dump_bytes() + +Therefore the usability of this tool is, as of now, quite limited as there is +no uniform rule for adding debug prints to the codebase, resulting in a variety +of ways these prints are implemented. + +Also, note that most debug statements are implemented as a variation of +dprintk(), which have to be activated via a parameter in respective module, +dynamic debug is unable to do that step for you. + +Here is one example, that enables all available pr_debug()'s within the file:: + + $ alias ddcmd='echo $* > /proc/dynamic_debug/control' + $ ddcmd '-p; file v4l2-h264.c +p' + $ grep =p /proc/dynamic_debug/control + drivers/media/v4l2-core/v4l2-h264.c:372 [v4l2_h264]print_ref_list_b =p + "ref_pic_list_b%u (cur_poc %u%c) %s" + drivers/media/v4l2-core/v4l2-h264.c:333 [v4l2_h264]print_ref_list_p =p + "ref_pic_list_p (cur_poc %u%c) %s\n" + +**When should you use this over Ftrace ?** + +- When the code contains one of the valid print statements (see above) or when + you have added multiple pr_debug() statements during development +- When timing is not an issue, meaning if multiple pr_debug() statements in + the code won't cause delays +- When you care more about receiving specific log messages than tracing the + pattern of how a function is called + +For the full documentation see :doc:`/admin-guide/dynamic-debug-howto` + +Ftrace +------ + +Prerequisite: ``CONFIG_DYNAMIC_FTRACE`` + +This tool uses the tracefs file system for the control files and output files. +That file system will be mounted as a ``tracing`` directory, which can be found +in either ``/sys/kernel/`` or ``/sys/debug/kernel/``. + +Some of the most important operations for debugging are: + +- You can perform a function trace by adding a function name to the + ``set_ftrace_filter`` file (which accepts any function name found within the + ``available_filter_functions`` file) or you can specifically disable certain + functions by adding their names to the ``set_ftrace_notrace`` file (more info + at: :ref:`trace/ftrace:dynamic ftrace`). +- In order to find out where calls originate from you can activate the + ``func_stack_trace`` option under ``options/func_stack_trace``. +- Tracing the children of a function call and showing the return values are + possible by adding the desired function in the ``set_graph_function`` file + (requires config ``FUNCTION_GRAPH_RETVAL``); more info at + :ref:`trace/ftrace:dynamic ftrace with the function graph tracer`. + +For the full Ftrace documentation see :doc:`/trace/ftrace` + +Or you could also trace for specific events by :ref:`using event tracing +`, which can be defined as described here: +:ref:`Creating a custom Ftrace tracepoint +`. + +For the full Ftrace event tracing documentation see :doc:`/trace/events` + +.. _read_ftrace_log: + +Reading the ftrace log +~~~~~~~~~~~~~~~~~~~~~~ + +The ``trace`` file can be read just like any other file (``cat``, ``tail``, +``head``, ``vim``, etc.), the size of the file is limited by the +``buffer_size_kb`` (``echo 1000 > buffer_size_kb``). The +:ref:`trace/ftrace:trace_pipe` will behave similarly to the ``trace`` file, but +whenever you read from the file the content is consumed. + +Kernelshark +~~~~~~~~~~~ + +A GUI interface to visualize the traces as a graph and list view from the +output of the `trace-cmd +`__ application. + +For the full documentation see ``__ + +Perf & alternatives +------------------- + +The tools mentioned above provide ways to inspect kernel code, results, +variable values, etc. Sometimes you have to find out first where to look and +for those cases, a box of performance tracking tools can help you to frame the +issue. + +Why should you do a performance analysis? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A performance analysis is a good first step when among other reasons: + +- you cannot define the issue +- you do not know where it occurs +- the running system should not be interrupted or it is a remote system, where + you cannot install a new module/kernel + +How to do a simple analysis with linux tools? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For the start of a performance analysis, you can start with the usual tools +like: + +- ``top`` / ``htop`` / ``atop`` (*get an overview of the system load, see + spikes on specific processes*) +- ``mpstat -P ALL`` (*look at the load distribution among CPUs*) +- ``iostat -x`` (*observe input and output devices utilization and performance*) +- ``vmstat`` (*overview of memory usage on the system*) +- ``pidstat`` (*similar to* ``vmstat`` *but per process, to dial it down to the + target*) +- ``strace -tp $PID`` (*once you know the process, you can figure out how it + communicates with the Kernel*) + +These should help to narrow down the areas to look at sufficiently. + +Diving deeper with perf +~~~~~~~~~~~~~~~~~~~~~~~ + +The **perf** tool provides a series of metrics and events to further dial down +on issues. + +Prerequisite: build or install perf on your system + +Gather statistics data for finding all files starting with ``gcc`` in ``/usr``:: + + # perf stat -d find /usr -name 'gcc*' | wc -l + + Performance counter stats for 'find /usr -name gcc*': + + 1277.81 msec task-clock # 0.997 CPUs utilized + 9 context-switches # 7.043 /sec + 1 cpu-migrations # 0.783 /sec + 704 page-faults # 550.943 /sec + 766548897 cycles # 0.600 GHz (97.15%) + 798285467 instructions # 1.04 insn per cycle (97.15%) + 57582731 branches # 45.064 M/sec (2.85%) + 3842573 branch-misses # 6.67% of all branches (97.15%) + 281616097 L1-dcache-loads # 220.390 M/sec (97.15%) + 4220975 L1-dcache-load-misses # 1.50% of all L1-dcache accesses (97.15%) + LLC-loads + LLC-load-misses + + 1.281746009 seconds time elapsed + + 0.508796000 seconds user + 0.773209000 seconds sys + + + 52 + +The availability of events and metrics depends on the system you are running. + +For the full documentation see +``__ + +Perfetto +~~~~~~~~ + +A set of tools to measure and analyze how well applications and systems perform. +You can use it to: + +* identify bottlenecks +* optimize code +* make software run faster and more efficiently. + +**What is the difference between perfetto and perf?** + +* perf is tool as part of and specialized for the Linux Kernel and has CLI user + interface. +* perfetto cross-platform performance analysis stack, has extended + functionality into userspace and provides a WEB user interface. + +For the full documentation see ``__ + +Kernel panic analysis tools +--------------------------- + + To capture the crash dump please use ``Kdump`` & ``Kexec``. Below you can find + some advice for analysing the data. + + For the full documentation see the :doc:`/admin-guide/kdump/kdump` + + In order to find the corresponding line in the code you can use `faddr2line + `__; note + that you need to enable ``CONFIG_DEBUG_INFO`` for that to work. + + An alternative to using ``faddr2line`` is the use of ``objdump`` (and its + derivatives for the different platforms like ``aarch64-linux-gnu-objdump``). + Take this line as an example: + + ``[ +0.000240] rkvdec_device_run+0x50/0x138 [rockchip_vdec]``. + + We can find the corresponding line of code by executing:: + + aarch64-linux-gnu-objdump -dS drivers/staging/media/rkvdec/rockchip-vdec.ko | grep rkvdec_device_run\>: -A 40 + 0000000000000ac8 : + ac8: d503201f nop + acc: d503201f nop + { + ad0: d503233f paciasp + ad4: a9bd7bfd stp x29, x30, [sp, #-48]! + ad8: 910003fd mov x29, sp + adc: a90153f3 stp x19, x20, [sp, #16] + ae0: a9025bf5 stp x21, x22, [sp, #32] + const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; + ae4: f9411814 ldr x20, [x0, #560] + struct rkvdec_dev *rkvdec = ctx->dev; + ae8: f9418015 ldr x21, [x0, #768] + if (WARN_ON(!desc)) + aec: b4000654 cbz x20, bb4 + ret = pm_runtime_resume_and_get(rkvdec->dev); + af0: f943d2b6 ldr x22, [x21, #1952] + ret = __pm_runtime_resume(dev, RPM_GET_PUT); + af4: aa0003f3 mov x19, x0 + af8: 52800081 mov w1, #0x4 // #4 + afc: aa1603e0 mov x0, x22 + b00: 94000000 bl 0 <__pm_runtime_resume> + if (ret < 0) { + b04: 37f80340 tbnz w0, #31, b6c + dev_warn(rkvdec->dev, "Not good\n"); + b08: f943d2a0 ldr x0, [x21, #1952] + b0c: 90000001 adrp x1, 0 + b10: 91000021 add x1, x1, #0x0 + b14: 94000000 bl 0 <_dev_warn> + *bad = 1; + b18: d2800001 mov x1, #0x0 // #0 + ... + + Meaning, in this line from the crash dump:: + + [ +0.000240] rkvdec_device_run+0x50/0x138 [rockchip_vdec] + + I can take the ``0x50`` as offset, which I have to add to the base address + of the corresponding function, which I find in this line:: + + 0000000000000ac8 : + + The result of ``0xac8 + 0x50 = 0xb18`` + And when I search for that address within the function I get the + following line:: + + *bad = 1; + b18: d2800001 mov x1, #0x0 + +**Copyright** ©2024 : Collabora diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst index 6455eba3ef0c52..aa12f266019497 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -72,13 +72,15 @@ beyond). Dealing with bugs ----------------- -Bugs are a fact of life; it is important that we handle them properly. -The documents below describe our policies around the handling of a couple -of special classes of bugs: regressions and security problems. +Bugs are a fact of life; it is important that we handle them properly. The +documents below provide general advice about debugging and describe our +policies around the handling of a couple of special classes of bugs: +regressions and security problems. .. toctree:: :maxdepth: 1 + debugging/index handling-regressions security-bugs cve diff --git a/Documentation/process/kernel-docs.rst b/Documentation/process/kernel-docs.rst index 55552ec4b043c7..3b5b5983fea83b 100644 --- a/Documentation/process/kernel-docs.rst +++ b/Documentation/process/kernel-docs.rst @@ -72,17 +72,6 @@ On-line docs programming. Lots of examples. Currently the new version is being actively maintained at https://github.com/sysprog21/lkmpg. - * Title: **Rust for Linux** - - :Author: various - :URL: https://rust-for-linux.com/ - :Date: rolling version - :Keywords: glossary, terms, linux-kernel. - :Description: From the website: "Rust for Linux is the project adding - support for the Rust language to the Linux kernel. This website is - intended as a hub of links, documentation and resources related to - the project". - Published books --------------- @@ -220,6 +209,158 @@ Miscellaneous other original research and content related to Linux and software development. +Rust +---- + + * Title: **Rust for Linux** + + :Author: various + :URL: https://rust-for-linux.com/ + :Date: rolling version + :Keywords: glossary, terms, linux-kernel, rust. + :Description: From the website: "Rust for Linux is the project adding + support for the Rust language to the Linux kernel. This website is + intended as a hub of links, documentation and resources related to + the project". + + * Title: **Learn Rust the Dangerous Way** + + :Author: Cliff L. Biffle + :URL: https://cliffle.com/p/dangerust/ + :Date: Accessed Sep 11 2024 + :Keywords: rust, blog. + :Description: From the website: "LRtDW is a series of articles + putting Rust features in context for low-level C programmers who + maybe don’t have a formal CS background — the sort of people who + work on firmware, game engines, OS kernels, and the like. + Basically, people like me.". It illustrates line-by-line + conversions from C to Rust. + + * Title: **The Rust Book** + + :Author: Steve Klabnik and Carol Nichols, with contributions from the + Rust community + :URL: https://doc.rust-lang.org/book/ + :Date: Accessed Sep 11 2024 + :Keywords: rust, book. + :Description: From the website: "This book fully embraces the + potential of Rust to empower its users. It’s a friendly and + approachable text intended to help you level up not just your + knowledge of Rust, but also your reach and confidence as a + programmer in general. So dive in, get ready to learn—and welcome + to the Rust community!". + + * Title: **Rust for the Polyglot Programmer** + + :Author: Ian Jackson + :URL: https://www.chiark.greenend.org.uk/~ianmdlvl/rust-polyglot/index.html + :Date: December 2022 + :Keywords: rust, blog, tooling. + :Description: From the website: "There are many guides and + introductions to Rust. This one is something different: it is + intended for the experienced programmer who already knows many + other programming languages. I try to be comprehensive enough to be + a starting point for any area of Rust, but to avoid going into too + much detail except where things are not as you might expect. Also + this guide is not entirely free of opinion, including + recommendations of libraries (crates), tooling, etc.". + + * Title: **Fasterthanli.me** + + :Author: Amos Wenger + :URL: https://fasterthanli.me/ + :Date: Accessed Sep 11 2024 + :Keywords: rust, blog, news. + :Description: From the website: "I make articles and videos about how + computers work. My content is long-form, didactic and exploratory + — and often an excuse to teach Rust!". + + * Title: **Comprehensive Rust** + + :Author: Android team at Google + :URL: https://google.github.io/comprehensive-rust/ + :Date: Accessed Sep 13 2024 + :Keywords: rust, blog. + :Description: From the website: "The course covers the full spectrum + of Rust, from basic syntax to advanced topics like generics and + error handling". + + * Title: **The Embedded Rust Book** + + :Author: Multiple contributors, mostly Jorge Aparicio + :URL: https://docs.rust-embedded.org/book/ + :Date: Accessed Sep 13 2024 + :Keywords: rust, blog. + :Description: From the website: "An introductory book about using + the Rust Programming Language on "Bare Metal" embedded systems, + such as Microcontrollers". + + * Title: **Experiment: Improving the Rust Book** + + :Author: Cognitive Engineering Lab at Brown University + :URL: https://rust-book.cs.brown.edu/ + :Date: Accessed Sep 22 2024 + :Keywords: rust, blog. + :Description: From the website: "The goal of this experiment is to + evaluate and improve the content of the Rust Book to help people + learn Rust more effectively.". + + * Title: **New Rustacean** (podcast) + + :Author: Chris Krycho + :URL: https://newrustacean.com/ + :Date: Accessed Sep 22 2024 + :Keywords: rust, podcast. + :Description: From the website: "This is a podcast about learning + the programming language Rust—from scratch! Apart from this spiffy + landing page, all the site content is built with Rust's own + documentation tools.". + + * Title: **Opsem-team** (repository) + + :Author: Operational semantics team + :URL: https://github.com/rust-lang/opsem-team/tree/main + :Date: Accessed Sep 22 2024 + :Keywords: rust, repository. + :Description: From the README: "The opsem team is the successor of + the unsafe-code-guidelines working group and responsible for + answering many of the difficult questions about the semantics of + unsafe Rust". + + * Title: **You Can't Spell Trust Without Rust** + + :Author: Alexis Beingessner + :URL: https://repository.library.carleton.ca/downloads/1j92g820w?locale=en + :Date: 2015 + :Keywords: rust, master, thesis. + :Description: This thesis focuses on Rust's ownership system, which + ensures memory safety by controlling data manipulation and + lifetime, while also highlighting its limitations and comparing it + to similar systems in Cyclone and C++. + + * Name: **Linux Plumbers (LPC) 2024 Rust presentations** + + :Title: Rust microconference + :URL: https://lpc.events/event/18/sessions/186/#20240918 + :Title: Rust for Linux + :URL: https://lpc.events/event/18/contributions/1912/ + :Title: Journey of a C kernel engineer starting a Rust driver project + :URL: https://lpc.events/event/18/contributions/1911/ + :Title: Crafting a Linux kernel scheduler that runs in user-space + using Rust + :URL: https://lpc.events/event/18/contributions/1723/ + :Title: openHCL: A Linux and Rust based paravisor + :URL: https://lpc.events/event/18/contributions/1956/ + :Keywords: rust, lpc, presentations. + :Description: A number of LPC talks related to Rust. + + * Name: **The Rustacean Station Podcast** + + :URL: https://rustacean-station.org/ + :Keywords: rust, podcasts. + :Description: A community project for creating podcast content for + the Rust programming language. + ------- This document was originally based on: diff --git a/Documentation/process/license-rules.rst b/Documentation/process/license-rules.rst index 2ef44ada3f1195..59a7832df7d08d 100644 --- a/Documentation/process/license-rules.rst +++ b/Documentation/process/license-rules.rst @@ -471,14 +471,16 @@ _`MODULE_LICENSE` source files. "Proprietary" The module is under a proprietary license. - This string is solely for proprietary third - party modules and cannot be used for modules - which have their source code in the kernel - tree. Modules tagged that way are tainting - the kernel with the 'P' flag when loaded and - the kernel module loader refuses to link such - modules against symbols which are exported - with EXPORT_SYMBOL_GPL(). + "Proprietary" is to be understood only as + "The license is not compatible to GPLv2". + This string is solely for non-GPL2 compatible + third party modules and cannot be used for + modules which have their source code in the + kernel tree. Modules tagged that way are + tainting the kernel with the 'P' flag when + loaded and the kernel module loader refuses + to link such modules against symbols which + are exported with EXPORT_SYMBOL_GPL(). ============================= ============================================= diff --git a/Documentation/process/maintainer-tip.rst b/Documentation/process/maintainer-tip.rst index 349a27a5334359..e374b67b3277ac 100644 --- a/Documentation/process/maintainer-tip.rst +++ b/Documentation/process/maintainer-tip.rst @@ -7,7 +7,7 @@ What is the tip tree? --------------------- The tip tree is a collection of several subsystems and areas of -development. The tip tree is both a direct development tree and a +development. The tip tree is both a direct development tree and an aggregation tree for several sub-maintainer trees. The tip tree gitweb URL is: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git @@ -121,7 +121,7 @@ The tip tree preferred format for patch subject prefixes is prefix. 'git log path/to/file' should give you a reasonable hint in most cases. -The condensed patch description in the subject line should start with a +The condensed patch description in the subject line should start with an uppercase letter and should be written in imperative tone. diff --git a/Documentation/rust/coding-guidelines.rst b/Documentation/rust/coding-guidelines.rst index 329b070a1d4736..a2e326b42410f8 100644 --- a/Documentation/rust/coding-guidelines.rst +++ b/Documentation/rust/coding-guidelines.rst @@ -227,3 +227,149 @@ The equivalent in Rust may look like (ignoring documentation): That is, the equivalent of ``GPIO_LINE_DIRECTION_IN`` would be referred to as ``gpio::LineDirection::In``. In particular, it should not be named ``gpio::gpio_line_direction::GPIO_LINE_DIRECTION_IN``. + + +Lints +----- + +In Rust, it is possible to ``allow`` particular warnings (diagnostics, lints) +locally, making the compiler ignore instances of a given warning within a given +function, module, block, etc. + +It is similar to ``#pragma GCC diagnostic push`` + ``ignored`` + ``pop`` in C +[#]_: + +.. code-block:: c + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-function" + static void f(void) {} + #pragma GCC diagnostic pop + +.. [#] In this particular case, the kernel's ``__{always,maybe}_unused`` + attributes (C23's ``[[maybe_unused]]``) may be used; however, the example + is meant to reflect the equivalent lint in Rust discussed afterwards. + +But way less verbose: + +.. code-block:: rust + + #[allow(dead_code)] + fn f() {} + +By that virtue, it makes it possible to comfortably enable more diagnostics by +default (i.e. outside ``W=`` levels). In particular, those that may have some +false positives but that are otherwise quite useful to keep enabled to catch +potential mistakes. + +On top of that, Rust provides the ``expect`` attribute which takes this further. +It makes the compiler warn if the warning was not produced. For instance, the +following will ensure that, when ``f()`` is called somewhere, we will have to +remove the attribute: + +.. code-block:: rust + + #[expect(dead_code)] + fn f() {} + +If we do not, we get a warning from the compiler:: + + warning: this lint expectation is unfulfilled + --> x.rs:3:10 + | + 3 | #[expect(dead_code)] + | ^^^^^^^^^ + | + = note: `#[warn(unfulfilled_lint_expectations)]` on by default + +This means that ``expect``\ s do not get forgotten when they are not needed, which +may happen in several situations, e.g.: + +- Temporary attributes added while developing. + +- Improvements in lints in the compiler, Clippy or custom tools which may + remove a false positive. + +- When the lint is not needed anymore because it was expected that it would be + removed at some point, such as the ``dead_code`` example above. + +It also increases the visibility of the remaining ``allow``\ s and reduces the +chance of misapplying one. + +Thus prefer ``expect`` over ``allow`` unless: + +- Conditional compilation triggers the warning in some cases but not others. + + If there are only a few cases where the warning triggers (or does not + trigger) compared to the total number of cases, then one may consider using + a conditional ``expect`` (i.e. ``cfg_attr(..., expect(...))``). Otherwise, + it is likely simpler to just use ``allow``. + +- Inside macros, when the different invocations may create expanded code that + triggers the warning in some cases but not in others. + +- When code may trigger a warning for some architectures but not others, such + as an ``as`` cast to a C FFI type. + +As a more developed example, consider for instance this program: + +.. code-block:: rust + + fn g() {} + + fn main() { + #[cfg(CONFIG_X)] + g(); + } + +Here, function ``g()`` is dead code if ``CONFIG_X`` is not set. Can we use +``expect`` here? + +.. code-block:: rust + + #[expect(dead_code)] + fn g() {} + + fn main() { + #[cfg(CONFIG_X)] + g(); + } + +This would emit a lint if ``CONFIG_X`` is set, since it is not dead code in that +configuration. Therefore, in cases like this, we cannot use ``expect`` as-is. + +A simple possibility is using ``allow``: + +.. code-block:: rust + + #[allow(dead_code)] + fn g() {} + + fn main() { + #[cfg(CONFIG_X)] + g(); + } + +An alternative would be using a conditional ``expect``: + +.. code-block:: rust + + #[cfg_attr(not(CONFIG_X), expect(dead_code))] + fn g() {} + + fn main() { + #[cfg(CONFIG_X)] + g(); + } + +This would ensure that, if someone introduces another call to ``g()`` somewhere +(e.g. unconditionally), then it would be spotted that it is not dead code +anymore. However, the ``cfg_attr`` is more complex than a simple ``allow``. + +Therefore, it is likely that it is not worth using conditional ``expect``\ s when +more than one or two configurations are involved or when the lint may be +triggered due to non-local changes (such as ``dead_code``). + +For more information about diagnostics in Rust, please see: + + https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html diff --git a/Documentation/rust/index.rst b/Documentation/rust/index.rst index 55dcde9e9e7e9e..ec62001c7d8c78 100644 --- a/Documentation/rust/index.rst +++ b/Documentation/rust/index.rst @@ -56,6 +56,9 @@ more details. arch-support testing +You can also find learning materials for Rust in its section in +:doc:`../process/kernel-docs`. + .. only:: subproject and html Indices diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst index 2d107982c87bbe..4aa50e5fcb8c05 100644 --- a/Documentation/rust/quick-start.rst +++ b/Documentation/rust/quick-start.rst @@ -87,6 +87,23 @@ they should generally work out of the box, e.g.:: zypper install rust rust1.79-src rust-bindgen clang +Ubuntu +****** + +Ubuntu LTS and non-LTS (interim) releases provide recent Rust releases and thus +they should generally work out of the box, e.g.:: + + apt install rustc-1.80 rust-1.80-src bindgen-0.65 rustfmt-1.80 rust-1.80-clippy + +``RUST_LIB_SRC`` needs to be set when using the versioned packages, e.g.:: + + RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.80 --version | cut -d' ' -f2)/library + +In addition, ``bindgen-0.65`` is available in newer releases (24.04 LTS and +24.10), but it may not be available in older ones (20.04 LTS and 22.04 LTS), +thus ``bindgen`` may need to be built manually (please see below). + + Requirements: Building ---------------------- diff --git a/Documentation/scheduler/sched-ext.rst b/Documentation/scheduler/sched-ext.rst index 7b59bbd2e56428..6cb8b676ce0382 100644 --- a/Documentation/scheduler/sched-ext.rst +++ b/Documentation/scheduler/sched-ext.rst @@ -130,7 +130,7 @@ optional. The following modified excerpt is from * Decide which CPU a task should be migrated to before being * enqueued (either at wakeup, fork time, or exec time). If an * idle core is found by the default ops.select_cpu() implementation, - * then dispatch the task directly to SCX_DSQ_LOCAL and skip the + * then insert the task directly into SCX_DSQ_LOCAL and skip the * ops.enqueue() callback. * * Note that this implementation has exactly the same behavior as the @@ -148,15 +148,15 @@ optional. The following modified excerpt is from cpu = scx_bpf_select_cpu_dfl(p, prev_cpu, wake_flags, &direct); if (direct) - scx_bpf_dispatch(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, 0); + scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, 0); return cpu; } /* - * Do a direct dispatch of a task to the global DSQ. This ops.enqueue() - * callback will only be invoked if we failed to find a core to dispatch - * to in ops.select_cpu() above. + * Do a direct insertion of a task to the global DSQ. This ops.enqueue() + * callback will only be invoked if we failed to find a core to insert + * into in ops.select_cpu() above. * * Note that this implementation has exactly the same behavior as the * default ops.enqueue implementation, which just dispatches the task @@ -166,7 +166,7 @@ optional. The following modified excerpt is from */ void BPF_STRUCT_OPS(simple_enqueue, struct task_struct *p, u64 enq_flags) { - scx_bpf_dispatch(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); + scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); } s32 BPF_STRUCT_OPS_SLEEPABLE(simple_init) @@ -202,14 +202,13 @@ and one local dsq per CPU (``SCX_DSQ_LOCAL``). The BPF scheduler can manage an arbitrary number of dsq's using ``scx_bpf_create_dsq()`` and ``scx_bpf_destroy_dsq()``. -A CPU always executes a task from its local DSQ. A task is "dispatched" to a -DSQ. A non-local DSQ is "consumed" to transfer a task to the consuming CPU's -local DSQ. +A CPU always executes a task from its local DSQ. A task is "inserted" into a +DSQ. A task in a non-local DSQ is "move"d into the target CPU's local DSQ. When a CPU is looking for the next task to run, if the local DSQ is not -empty, the first task is picked. Otherwise, the CPU tries to consume the -global DSQ. If that doesn't yield a runnable task either, ``ops.dispatch()`` -is invoked. +empty, the first task is picked. Otherwise, the CPU tries to move a task +from the global DSQ. If that doesn't yield a runnable task either, +``ops.dispatch()`` is invoked. Scheduling Cycle ---------------- @@ -229,26 +228,26 @@ The following briefly shows how a waking task is scheduled and executed. scheduler can wake up any cpu using the ``scx_bpf_kick_cpu()`` helper, using ``ops.select_cpu()`` judiciously can be simpler and more efficient. - A task can be immediately dispatched to a DSQ from ``ops.select_cpu()`` by - calling ``scx_bpf_dispatch()``. If the task is dispatched to - ``SCX_DSQ_LOCAL`` from ``ops.select_cpu()``, it will be dispatched to the + A task can be immediately inserted into a DSQ from ``ops.select_cpu()`` + by calling ``scx_bpf_dsq_insert()``. If the task is inserted into + ``SCX_DSQ_LOCAL`` from ``ops.select_cpu()``, it will be inserted into the local DSQ of whichever CPU is returned from ``ops.select_cpu()``. - Additionally, dispatching directly from ``ops.select_cpu()`` will cause the + Additionally, inserting directly from ``ops.select_cpu()`` will cause the ``ops.enqueue()`` callback to be skipped. Note that the scheduler core will ignore an invalid CPU selection, for example, if it's outside the allowed cpumask of the task. 2. Once the target CPU is selected, ``ops.enqueue()`` is invoked (unless the - task was dispatched directly from ``ops.select_cpu()``). ``ops.enqueue()`` + task was inserted directly from ``ops.select_cpu()``). ``ops.enqueue()`` can make one of the following decisions: - * Immediately dispatch the task to either the global or local DSQ by - calling ``scx_bpf_dispatch()`` with ``SCX_DSQ_GLOBAL`` or + * Immediately insert the task into either the global or local DSQ by + calling ``scx_bpf_dsq_insert()`` with ``SCX_DSQ_GLOBAL`` or ``SCX_DSQ_LOCAL``, respectively. - * Immediately dispatch the task to a custom DSQ by calling - ``scx_bpf_dispatch()`` with a DSQ ID which is smaller than 2^63. + * Immediately insert the task into a custom DSQ by calling + ``scx_bpf_dsq_insert()`` with a DSQ ID which is smaller than 2^63. * Queue the task on the BPF side. @@ -257,23 +256,23 @@ The following briefly shows how a waking task is scheduled and executed. run, ``ops.dispatch()`` is invoked which can use the following two functions to populate the local DSQ. - * ``scx_bpf_dispatch()`` dispatches a task to a DSQ. Any target DSQ can - be used - ``SCX_DSQ_LOCAL``, ``SCX_DSQ_LOCAL_ON | cpu``, - ``SCX_DSQ_GLOBAL`` or a custom DSQ. While ``scx_bpf_dispatch()`` + * ``scx_bpf_dsq_insert()`` inserts a task to a DSQ. Any target DSQ can be + used - ``SCX_DSQ_LOCAL``, ``SCX_DSQ_LOCAL_ON | cpu``, + ``SCX_DSQ_GLOBAL`` or a custom DSQ. While ``scx_bpf_dsq_insert()`` currently can't be called with BPF locks held, this is being worked on - and will be supported. ``scx_bpf_dispatch()`` schedules dispatching + and will be supported. ``scx_bpf_dsq_insert()`` schedules insertion rather than performing them immediately. There can be up to ``ops.dispatch_max_batch`` pending tasks. - * ``scx_bpf_consume()`` tranfers a task from the specified non-local DSQ - to the dispatching DSQ. This function cannot be called with any BPF - locks held. ``scx_bpf_consume()`` flushes the pending dispatched tasks - before trying to consume the specified DSQ. + * ``scx_bpf_move_to_local()`` moves a task from the specified non-local + DSQ to the dispatching DSQ. This function cannot be called with any BPF + locks held. ``scx_bpf_move_to_local()`` flushes the pending insertions + tasks before trying to move from the specified DSQ. 4. After ``ops.dispatch()`` returns, if there are tasks in the local DSQ, the CPU runs the first one. If empty, the following steps are taken: - * Try to consume the global DSQ. If successful, run the task. + * Try to move from the global DSQ. If successful, run the task. * If ``ops.dispatch()`` has dispatched any tasks, retry #3. @@ -286,14 +285,14 @@ Note that the BPF scheduler can always choose to dispatch tasks immediately in ``ops.enqueue()`` as illustrated in the above simple example. If only the built-in DSQs are used, there is no need to implement ``ops.dispatch()`` as a task is never queued on the BPF scheduler and both the local and global -DSQs are consumed automatically. +DSQs are executed automatically. -``scx_bpf_dispatch()`` queues the task on the FIFO of the target DSQ. Use -``scx_bpf_dispatch_vtime()`` for the priority queue. Internal DSQs such as +``scx_bpf_dsq_insert()`` inserts the task on the FIFO of the target DSQ. Use +``scx_bpf_dsq_insert_vtime()`` for the priority queue. Internal DSQs such as ``SCX_DSQ_LOCAL`` and ``SCX_DSQ_GLOBAL`` do not support priority-queue -dispatching, and must be dispatched to with ``scx_bpf_dispatch()``. See the -function documentation and usage in ``tools/sched_ext/scx_simple.bpf.c`` for -more information. +dispatching, and must be dispatched to with ``scx_bpf_dsq_insert()``. See +the function documentation and usage in ``tools/sched_ext/scx_simple.bpf.c`` +for more information. Where to Look ============= diff --git a/Documentation/sound/designs/compress-accel.rst b/Documentation/sound/designs/compress-accel.rst new file mode 100644 index 00000000000000..c9c1744b94c2c0 --- /dev/null +++ b/Documentation/sound/designs/compress-accel.rst @@ -0,0 +1,134 @@ +================================== +ALSA Co-processor Acceleration API +================================== + +Jaroslav Kysela + + +Overview +======== + +There is a requirement to expose the audio hardware that accelerates various +tasks for user space such as sample rate converters, compressed +stream decoders, etc. + +This is description for the API extension for the compress ALSA API which +is able to handle "tasks" that are not bound to real-time operations +and allows for the serialization of operations. + +Requirements +============ + +The main requirements are: + +- serialization of multiple tasks for user space to allow multiple + operations without user space intervention + +- separate buffers (input + output) for each operation + +- expose buffers using mmap to user space + +- signal user space when the task is finished (standard poll mechanism) + +Design +====== + +A new direction SND_COMPRESS_ACCEL is introduced to identify +the passthrough API. + +The API extension shares device enumeration and parameters handling from +the main compressed API. All other realtime streaming ioctls are deactivated +and a new set of task related ioctls are introduced. The standard +read/write/mmap I/O operations are not supported in the passthrough device. + +Device ("stream") state handling is reduced to OPEN/SETUP. All other +states are not available for the passthrough mode. + +Data I/O mechanism is using standard dma-buf interface with all advantages +like mmap, standard I/O, buffer sharing etc. One buffer is used for the +input data and second (separate) buffer is used for the output data. Each task +have separate I/O buffers. + +For the buffering parameters, the fragments means a limit of allocated tasks +for given device. The fragment_size limits the input buffer size for the given +device. The output buffer size is determined by the driver (may be different +from the input buffer size). + +State Machine +============= + +The passthrough audio stream state machine is described below:: + + +----------+ + | | + | OPEN | + | | + +----------+ + | + | + | compr_set_params() + | + v + all passthrough task ops +----------+ + +------------------------------------| | + | | SETUP | + | | + | +----------+ + | | + +------------------------------------------+ + + +Passthrough operations (ioctls) +=============================== + +All operations are protected using stream->device->lock (mutex). + +CREATE +------ +Creates a set of input/output buffers. The input buffer size is +fragment_size. Allocates unique seqno. + +The hardware drivers allocate internal 'struct dma_buf' for both input and +output buffers (using 'dma_buf_export()' function). The anonymous +file descriptors for those buffers are passed to user space. + +FREE +---- +Free a set of input/output buffers. If a task is active, the stop +operation is executed before. If seqno is zero, operation is executed for all +tasks. + +START +----- +Starts (queues) a task. There are two cases of the task start - right after +the task is created. In this case, origin_seqno must be zero. +The second case is for reusing of already finished task. The origin_seqno +must identify the task to be reused. In both cases, a new seqno value +is allocated and returned to user space. + +The prerequisite is that application filled input dma buffer with +new source data and set input_size to pass the real data size to the driver. + +The order of data processing is preserved (first started job must be +finished at first). + +If the multiple tasks require a state handling (e.g. resampling operation), +the user space may set SND_COMPRESS_TFLG_NEW_STREAM flag to mark the +start of the new stream data. It is useful to keep the allocated buffers +for the new operation rather using open/close mechanism. + +STOP +---- +Stop (dequeues) a task. If seqno is zero, operation is executed for all +tasks. + +STATUS +------ +Obtain the task status (active, finished). Also, the driver will set +the real output data size (valid area in the output buffer). + +Credits +======= +- Shengjiu Wang +- Takashi Iwai +- Vinod Koul diff --git a/Documentation/sound/designs/index.rst b/Documentation/sound/designs/index.rst index b79db9ad87325a..6b825c5617fc16 100644 --- a/Documentation/sound/designs/index.rst +++ b/Documentation/sound/designs/index.rst @@ -6,6 +6,7 @@ Designs and Implementations control-names channel-mapping-api + compress-accel compress-offload timestamping jack-controls diff --git a/Documentation/sound/hd-audio/notes.rst b/Documentation/sound/hd-audio/notes.rst index e199131bf5abbb..f81e94d8f145b7 100644 --- a/Documentation/sound/hd-audio/notes.rst +++ b/Documentation/sound/hd-audio/notes.rst @@ -42,7 +42,7 @@ If you are interested in the deep debugging of HD-audio, read the HD-audio specification at first. The specification is found on Intel's web page, for example: -* https://www.intel.com/standards/hdaudio/ +* https://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html HD-Audio Controller diff --git a/Documentation/sound/soc/clocking.rst b/Documentation/sound/soc/clocking.rst index 32122d6877a3d3..25d016ea8b65f6 100644 --- a/Documentation/sound/soc/clocking.rst +++ b/Documentation/sound/soc/clocking.rst @@ -42,5 +42,17 @@ rate, number of channels and word size) to save on power. It is also desirable to use the codec (if possible) to drive (or master) the audio clocks as it usually gives more accurate sample rates than the CPU. +ASoC provided clock APIs +------------------------ +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_sysclk +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_clkdiv + +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_pll + +.. kernel-doc:: sound/soc/soc-dai.c + :identifiers: snd_soc_dai_set_bclk_ratio diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst index 14c4dc026e6bda..73a42d5a9f3029 100644 --- a/Documentation/sound/soc/dapm.rst +++ b/Documentation/sound/soc/dapm.rst @@ -35,6 +35,9 @@ The graph for the STM32MP1-DK1 sound card is shown in picture: :alt: Example DAPM graph :align: center +You can also generate compatible graph for your sound card using +`tools/sound/dapm-graph` utility. + DAPM power domains ================== diff --git a/Documentation/sound/soc/dpcm.rst b/Documentation/sound/soc/dpcm.rst index 2d7ad1d9150431..02419a6f821327 100644 --- a/Documentation/sound/soc/dpcm.rst +++ b/Documentation/sound/soc/dpcm.rst @@ -157,15 +157,13 @@ FE DAI links are defined as follows :- .codec_dai_name = "snd-soc-dummy-dai", .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, }, .....< other FE and BE DAI links here > }; This FE DAI link is pretty similar to a regular DAI link except that we also -set the DAI link to a DPCM FE with the ``dynamic = 1``. The supported FE stream -directions should also be set with the ``dpcm_playback`` and ``dpcm_capture`` -flags. There is also an option to specify the ordering of the trigger call for +set the DAI link to a DPCM FE with the ``dynamic = 1``. +There is also an option to specify the ordering of the trigger call for each FE. This allows the ASoC core to trigger the DSP before or after the other components (as some DSPs have strong requirements for the ordering DAI/DSP start and stop sequences). @@ -189,15 +187,12 @@ The BE DAIs are configured as follows :- .ignore_pmdown_time = 1, .be_hw_params_fixup = hswult_ssp0_fixup, .ops = &haswell_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, }, .....< other BE DAI links here > }; This BE DAI link connects DAI0 to the codec (in this case RT5460 AIF1). It sets -the ``no_pcm`` flag to mark it has a BE and sets flags for supported stream -directions using ``dpcm_playback`` and ``dpcm_capture`` above. +the ``no_pcm`` flag to mark it has a BE. The BE has also flags set for ignoring suspend and PM down time. This allows the BE to work in a hostless mode where the host CPU is not transferring data diff --git a/Documentation/sound/soc/machine.rst b/Documentation/sound/soc/machine.rst index 515c9444deafc6..9db132bc00709e 100644 --- a/Documentation/sound/soc/machine.rst +++ b/Documentation/sound/soc/machine.rst @@ -71,6 +71,18 @@ struct snd_soc_dai_link is used to set up each DAI in your machine. e.g. .ops = &corgi_ops, }; +In the above struct, dai’s are registered using names but you can pass +either dai name or device tree node but not both. Also, names used here +for cpu/codec/platform dais should be globally unique. + +Additionaly below example macro can be used to register cpu, codec and +platform dai:: + + SND_SOC_DAILINK_DEFS(wm2200_cpu_dsp, + DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), + DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "wm0010-sdi1")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); + struct snd_soc_card then sets up the machine with its DAIs. e.g. :: @@ -81,6 +93,10 @@ struct snd_soc_card then sets up the machine with its DAIs. e.g. .num_links = 1, }; +Following this, ``devm_snd_soc_register_card`` can be used to register +the sound card. During the registration, the individual components +such as the codec, CPU, and platform are probed. If all these components +are successfully probed, the sound card gets registered. Machine Power Map ----------------- @@ -95,3 +111,13 @@ Machine Controls ---------------- Machine specific audio mixer controls can be added in the DAI init function. + + +Clocking Controls +----------------- + +As previously noted, clock configuration is handled within the machine driver. +For details on the clock APIs that the machine driver can utilize for +setup, please refer to Documentation/sound/soc/clocking.rst. However, the +callback needs to be registered by the CPU/Codec/Platform drivers to configure +the clocks that is needed for the corresponding device operation. diff --git a/Documentation/staging/magic-number.rst b/Documentation/staging/magic-number.rst index 7029c3c084ee4d..79afddf0e69284 100644 --- a/Documentation/staging/magic-number.rst +++ b/Documentation/staging/magic-number.rst @@ -68,11 +68,11 @@ Changelog:: ===================== ================ ======================== ========================================== Magic Name Number Structure File ===================== ================ ======================== ========================================== -PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h`` +PG_MAGIC 'P' pg_{read,write}_hdr ``include/uapi/linux/pg.h`` 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`` -BAYCOM_MAGIC 0x19730510 baycom_state ``drivers/net/baycom_epp.c`` +SLIP_MAGIC 0x5302 slip ``drivers/net/slip/slip.h`` +BAYCOM_MAGIC 19730510 baycom_state ``drivers/net/hamradio/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`` CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` diff --git a/Documentation/timers/delay_sleep_functions.rst b/Documentation/timers/delay_sleep_functions.rst new file mode 100644 index 00000000000000..49d603a3f1138d --- /dev/null +++ b/Documentation/timers/delay_sleep_functions.rst @@ -0,0 +1,121 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Delay and sleep mechanisms +========================== + +This document seeks to answer the common question: "What is the +RightWay (TM) to insert a delay?" + +This question is most often faced by driver writers who have to +deal with hardware delays and who may not be the most intimately +familiar with the inner workings of the Linux Kernel. + +The following table gives a rough overview about the existing function +'families' and their limitations. This overview table does not replace the +reading of the function description before usage! + +.. list-table:: + :widths: 20 20 20 20 20 + :header-rows: 2 + + * - + - `*delay()` + - `usleep_range*()` + - `*sleep()` + - `fsleep()` + * - + - busy-wait loop + - hrtimers based + - timer list timers based + - combines the others + * - Usage in atomic Context + - yes + - no + - no + - no + * - precise on "short intervals" + - yes + - yes + - depends + - yes + * - precise on "long intervals" + - Do not use! + - yes + - max 12.5% slack + - yes + * - interruptible variant + - no + - yes + - yes + - no + +A generic advice for non atomic contexts could be: + +#. Use `fsleep()` whenever unsure (as it combines all the advantages of the + others) +#. Use `*sleep()` whenever possible +#. Use `usleep_range*()` whenever accuracy of `*sleep()` is not sufficient +#. Use `*delay()` for very, very short delays + +Find some more detailed information about the function 'families' in the next +sections. + +`*delay()` family of functions +------------------------------ + +These functions use the jiffy estimation of clock speed and will busy wait for +enough loop cycles to achieve the desired delay. udelay() is the basic +implementation and ndelay() as well as mdelay() are variants. + +These functions are mainly used to add a delay in atomic context. Please make +sure to ask yourself before adding a delay in atomic context: Is this really +required? + +.. kernel-doc:: include/asm-generic/delay.h + :identifiers: udelay ndelay + +.. kernel-doc:: include/linux/delay.h + :identifiers: mdelay + + +`usleep_range*()` and `*sleep()` family of functions +---------------------------------------------------- + +These functions use hrtimers or timer list timers to provide the requested +sleeping duration. In order to decide which function is the right one to use, +take some basic information into account: + +#. hrtimers are more expensive as they are using an rb-tree (instead of hashing) +#. hrtimers are more expensive when the requested sleeping duration is the first + timer which means real hardware has to be programmed +#. timer list timers always provide some sort of slack as they are jiffy based + +The generic advice is repeated here: + +#. Use `fsleep()` whenever unsure (as it combines all the advantages of the + others) +#. Use `*sleep()` whenever possible +#. Use `usleep_range*()` whenever accuracy of `*sleep()` is not sufficient + +First check fsleep() function description and to learn more about accuracy, +please check msleep() function description. + + +`usleep_range*()` +~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: include/linux/delay.h + :identifiers: usleep_range usleep_range_idle + +.. kernel-doc:: kernel/time/sleep_timeout.c + :identifiers: usleep_range_state + + +`*sleep()` +~~~~~~~~~~ + +.. kernel-doc:: kernel/time/sleep_timeout.c + :identifiers: msleep msleep_interruptible + +.. kernel-doc:: include/linux/delay.h + :identifiers: ssleep fsleep diff --git a/Documentation/timers/index.rst b/Documentation/timers/index.rst index 983f91f8f023e0..4e88116e4dcf73 100644 --- a/Documentation/timers/index.rst +++ b/Documentation/timers/index.rst @@ -12,7 +12,7 @@ Timers hrtimers no_hz timekeeping - timers-howto + delay_sleep_functions .. only:: subproject and html diff --git a/Documentation/timers/timers-howto.rst b/Documentation/timers/timers-howto.rst deleted file mode 100644 index ef7a4652ccc9dc..00000000000000 --- a/Documentation/timers/timers-howto.rst +++ /dev/null @@ -1,115 +0,0 @@ -=================================================================== -delays - Information on the various kernel delay / sleep mechanisms -=================================================================== - -This document seeks to answer the common question: "What is the -RightWay (TM) to insert a delay?" - -This question is most often faced by driver writers who have to -deal with hardware delays and who may not be the most intimately -familiar with the inner workings of the Linux Kernel. - - -Inserting Delays ----------------- - -The first, and most important, question you need to ask is "Is my -code in an atomic context?" This should be followed closely by "Does -it really need to delay in atomic context?" If so... - -ATOMIC CONTEXT: - You must use the `*delay` family of functions. These - functions use the jiffy estimation of clock speed - and will busy wait for enough loop cycles to achieve - the desired delay: - - ndelay(unsigned long nsecs) - udelay(unsigned long usecs) - mdelay(unsigned long msecs) - - udelay is the generally preferred API; ndelay-level - precision may not actually exist on many non-PC devices. - - mdelay is macro wrapper around udelay, to account for - possible overflow when passing large arguments to udelay. - In general, use of mdelay is discouraged and code should - be refactored to allow for the use of msleep. - -NON-ATOMIC CONTEXT: - You should use the `*sleep[_range]` family of functions. - There are a few more options here, while any of them may - work correctly, using the "right" sleep function will - help the scheduler, power management, and just make your - driver better :) - - -- Backed by busy-wait loop: - - udelay(unsigned long usecs) - - -- Backed by hrtimers: - - usleep_range(unsigned long min, unsigned long max) - - -- Backed by jiffies / legacy_timers - - msleep(unsigned long msecs) - msleep_interruptible(unsigned long msecs) - - Unlike the `*delay` family, the underlying mechanism - driving each of these calls varies, thus there are - quirks you should be aware of. - - - SLEEPING FOR "A FEW" USECS ( < ~10us? ): - * Use udelay - - - Why not usleep? - On slower systems, (embedded, OR perhaps a speed- - stepped PC!) the overhead of setting up the hrtimers - for usleep *may* not be worth it. Such an evaluation - will obviously depend on your specific situation, but - it is something to be aware of. - - SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms): - * Use usleep_range - - - Why not msleep for (1ms - 20ms)? - Explained originally here: - https://lore.kernel.org/r/15327.1186166232@lwn.net - - msleep(1~20) may not do what the caller intends, and - will often sleep longer (~20 ms actual sleep for any - value given in the 1~20ms range). In many cases this - is not the desired behavior. - - - Why is there no "usleep" / What is a good range? - Since usleep_range is built on top of hrtimers, the - wakeup will be very precise (ish), thus a simple - usleep function would likely introduce a large number - of undesired interrupts. - - With the introduction of a range, the scheduler is - free to coalesce your wakeup with any other wakeup - that may have happened for other reasons, or at the - worst case, fire an interrupt for your upper bound. - - The larger a range you supply, the greater a chance - that you will not trigger an interrupt; this should - be balanced with what is an acceptable upper bound on - delay / performance for your specific code path. Exact - tolerances here are very situation specific, thus it - is left to the caller to determine a reasonable range. - - SLEEPING FOR LARGER MSECS ( 10ms+ ) - * Use msleep or possibly msleep_interruptible - - - What's the difference? - msleep sets the current task to TASK_UNINTERRUPTIBLE - whereas msleep_interruptible sets the current task to - TASK_INTERRUPTIBLE before scheduling the sleep. In - short, the difference is whether the sleep can be ended - early by a signal. In general, just use msleep unless - you know you have a need for the interruptible variant. - - FLEXIBLE SLEEPING (any delay, uninterruptible) - * Use fsleep diff --git a/Documentation/tools/rtla/common_timerlat_options.rst b/Documentation/tools/rtla/common_timerlat_options.rst index cef6651f143581..10dc802f8d6551 100644 --- a/Documentation/tools/rtla/common_timerlat_options.rst +++ b/Documentation/tools/rtla/common_timerlat_options.rst @@ -31,6 +31,14 @@ *cyclictest* sets this value to *0* by default, use **--dma-latency** *0* to have similar results. +**--deepest-idle-state** *n* + Disable idle states higher than *n* for cpus that are running timerlat threads to + reduce exit from idle latencies. If *n* is -1, all idle states are disabled. + On exit from timerlat, the idle state setting is restored to its original state + before running timerlat. + + Requires rtla to be built with libcpupower. + **-k**, **--kernel-threads** Use timerlat kernel-space threads, in contrast of **-u**. diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index 4073ca48af4ad2..272464bb7c6024 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -1031,14 +1031,15 @@ explains which is which. CPU#: The CPU which the process was running on. irqs-off: 'd' interrupts are disabled. '.' otherwise. - .. caution:: If the architecture does not support a way to - read the irq flags variable, an 'X' will always - be printed here. need-resched: + - 'B' all, TIF_NEED_RESCHED, PREEMPT_NEED_RESCHED and TIF_RESCHED_LAZY is set, - 'N' both TIF_NEED_RESCHED and PREEMPT_NEED_RESCHED is set, - 'n' only TIF_NEED_RESCHED is set, - 'p' only PREEMPT_NEED_RESCHED is set, + - 'L' both PREEMPT_NEED_RESCHED and TIF_RESCHED_LAZY is set, + - 'b' both TIF_NEED_RESCHED and TIF_RESCHED_LAZY is set, + - 'l' only TIF_RESCHED_LAZY is set - '.' otherwise. hardirq/softirq: diff --git a/Documentation/trace/histogram.rst b/Documentation/trace/histogram.rst index 3c9b263de9c24f..0aada18c38c693 100644 --- a/Documentation/trace/histogram.rst +++ b/Documentation/trace/histogram.rst @@ -81,7 +81,7 @@ Documentation written by Tom Zanussi .usecs display a common_timestamp in microseconds .percent display a number of percentage value .graph display a bar-graph of a value - .stacktrace display as a stacktrace (must by a long[] type) + .stacktrace display as a stacktrace (must be a long[] type) ============= ================================================= Note that in general the semantics of a given field aren't diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst index 0b300901fd750c..2c991dc96ace60 100644 --- a/Documentation/trace/index.rst +++ b/Documentation/trace/index.rst @@ -24,6 +24,7 @@ Linux Tracing Technologies histogram histogram-design boottime-trace + debugging hwlat_detector osnoise-tracer timerlat-tracer diff --git a/Documentation/translations/it_IT/core-api/symbol-namespaces.rst b/Documentation/translations/it_IT/core-api/symbol-namespaces.rst index 17abc25ee4c1e4..6ee71398853167 100644 --- a/Documentation/translations/it_IT/core-api/symbol-namespaces.rst +++ b/Documentation/translations/it_IT/core-api/symbol-namespaces.rst @@ -43,7 +43,7 @@ Tenete presente che per via dell'espansione delle macro questo argomento deve essere un simbolo di preprocessore. Per esempio per esportare il simbolo ``usb_stor_suspend`` nello spazio dei nomi ``USB_STORAGE`` usate:: - EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE); + EXPORT_SYMBOL_NS(usb_stor_suspend, "USB_STORAGE"); Di conseguenza, nella tabella dei simboli del kernel ci sarà una voce rappresentata dalla struttura ``kernel_symbol`` che avrà il campo @@ -69,7 +69,7 @@ Per esempio per esportare tutti i simboli definiti in usb-common nello spazio dei nomi USB_COMMON, si può aggiungere la seguente linea in drivers/usb/common/Makefile:: - ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON + ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"USB_COMMON"' Questo cambierà tutte le macro EXPORT_SYMBOL() ed EXPORT_SYMBOL_GPL(). Invece, un simbolo esportato con EXPORT_SYMBOL_NS() non verrà cambiato e il simbolo @@ -79,7 +79,7 @@ Una seconda possibilità è quella di definire il simbolo di preprocessore direttamente nei file da compilare. L'esempio precedente diventerebbe:: #undef DEFAULT_SYMBOL_NAMESPACE - #define DEFAULT_SYMBOL_NAMESPACE USB_COMMON + #define DEFAULT_SYMBOL_NAMESPACE "USB_COMMON" Questo va messo prima di un qualsiasi uso di EXPORT_SYMBOL. @@ -94,7 +94,7 @@ dei nomi che contiene i simboli desiderati. Per esempio un modulo che usa il simbolo usb_stor_suspend deve importare lo spazio dei nomi USB_STORAGE usando la seguente dichiarazione:: - MODULE_IMPORT_NS(USB_STORAGE); + MODULE_IMPORT_NS("USB_STORAGE"); Questo creerà un'etichetta ``modinfo`` per ogni spazio dei nomi importato. Un risvolto di questo fatto è che gli spazi dei diff --git a/Documentation/translations/it_IT/dev-tools/clang-format.rst b/Documentation/translations/it_IT/dev-tools/clang-format.rst new file mode 100644 index 00000000000000..6fab07772da0c8 --- /dev/null +++ b/Documentation/translations/it_IT/dev-tools/clang-format.rst @@ -0,0 +1,197 @@ +.. include:: ../disclaimer-ita.rst + +:Original: :ref:`Documentation/dev-tools/clang-format.rst ` +:Translator: Federico Vaga + +.. _it_clangformat: + +clang-format +============ +``clang-format`` è uno strumento per formattare codice C/C++/... secondo +un gruppo di regole ed euristiche. Come tutti gli strumenti, non è perfetto +e non copre tutti i singoli casi, ma è abbastanza buono per essere utile. + +``clang-format`` può essere usato per diversi fini: + + - Per riformattare rapidamente un blocco di codice secondo lo stile del + kernel. Particolarmente utile quando si sposta del codice e lo si + allinea/ordina. Vedere it_clangformatreformat_. + + - Identificare errori di stile, refusi e possibili miglioramenti nei + file che mantieni, le modifiche che revisioni, le differenze, + eccetera. Vedere it_clangformatreview_. + + - Ti aiuta a seguire lo stile del codice, particolarmente utile per i + nuovi arrivati o per coloro che lavorano allo stesso tempo su diversi + progetti con stili di codifica differenti. + +Il suo file di configurazione è ``.clang-format`` e si trova nella cartella +principale dei sorgenti del kernel. Le regole scritte in quel file tentano +di approssimare le lo stile di codifica del kernel. Si tenta anche di seguire +il più possibile +:ref:`Documentation/translations/it_IT/process/coding-style.rst `. +Dato che non tutto il kernel segue lo stesso stile, potreste voler aggiustare +le regole di base per un particolare sottosistema o cartella. Per farlo, +potete sovrascriverle scrivendole in un altro file ``.clang-format`` in +una sottocartella. + +Questo strumento è già stato incluso da molto tempo nelle distribuzioni +Linux più popolari. Cercate ``clang-format`` nel vostro repositorio. +Altrimenti, potete scaricare una versione pre-generata dei binari di LLVM/clang +oppure generarlo dai codici sorgenti: + + https://releases.llvm.org/download.html + +Troverete più informazioni ai seguenti indirizzi: + + https://clang.llvm.org/docs/ClangFormat.html + + https://clang.llvm.org/docs/ClangFormatStyleOptions.html + + +.. _it_clangformatreview: + +Revisionare lo stile di codifica per file e modifiche +----------------------------------------------------- + +Eseguendo questo programma, potrete revisionare un intero sottosistema, +cartella o singoli file alla ricerca di errori di stile, refusi o +miglioramenti. + +Per farlo, potete eseguire qualcosa del genere:: + + # Make sure your working directory is clean! + clang-format -i kernel/*.[ch] + +E poi date un'occhiata a *git diff*. + +Osservare le righe di questo diff è utile a migliorare/aggiustare +le opzioni di stile nel file di configurazione; così come per verificare +le nuove funzionalità/versioni di ``clang-format``. + +``clang-format`` è in grado di leggere diversi diff unificati, quindi +potrete revisionare facilmente delle modifiche e *git diff*. +La documentazione si trova al seguente indirizzo: + + https://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting + +Per evitare che ``clang-format`` formatti alcune parti di un file, potete +scrivere nel codice:: + + int formatted_code; + // clang-format off + void unformatted_code ; + // clang-format on + void formatted_code_again; + +Nonostante si attraente l'idea di utilizzarlo per mantenere un file +sempre in sintonia con ``clang-format``, specialmente per file nuovi o +se siete un manutentore, ricordatevi che altre persone potrebbero usare +una versione diversa di ``clang-format`` oppure non utilizzarlo del tutto. +Quindi, dovreste trattenervi dall'usare questi marcatori nel codice del +kernel; almeno finché non vediamo che ``clang-format`` è diventato largamente +utilizzato. + + +.. _it_clangformatreformat: + +Riformattare blocchi di codice +------------------------------ + +Utilizzando dei plugin per il vostro editor, potete riformattare una +blocco (selezione) di codice con una singola combinazione di tasti. +Questo è particolarmente utile: quando si riorganizza il codice, per codice +complesso, macro multi-riga (e allineare le loro "barre"), eccetera. + +Ricordatevi che potete sempre aggiustare le modifiche in quei casi dove +questo strumento non ha fatto un buon lavoro. Ma come prima approssimazione, +può essere davvero molto utile. + +Questo programma si integra con molti dei più popolari editor. Alcuni di +essi come vim, emacs, BBEdit, Visaul Studio, lo supportano direttamente. +Al seguente indirizzo troverete le istruzioni: + + https://clang.llvm.org/docs/ClangFormat.html + +Per Atom, Eclipse, Sublime Text, Visual Studio Code, XCode e altri editor +e IDEs dovreste essere in grado di trovare dei plugin pronti all'uso. + +Per questo caso d'uso, considerate l'uso di un secondo ``.clang-format`` +che potete personalizzare con le vostre opzioni. +Consultare it_clangformatextra_. + + +.. _it_clangformatmissing: + +Cose non supportate +------------------- + +``clang-format`` non ha il supporto per alcune cose che sono comuni nel +codice del kernel. Sono facili da ricordare; quindi, se lo usate +regolarmente, imparerete rapidamente a evitare/ignorare certi problemi. + +In particolare, quelli più comuni che noterete sono: + + - Allineamento di ``#define`` su una singola riga, per esempio:: + + #define TRACING_MAP_BITS_DEFAULT 11 + #define TRACING_MAP_BITS_MAX 17 + #define TRACING_MAP_BITS_MIN 7 + + contro:: + + #define TRACING_MAP_BITS_DEFAULT 11 + #define TRACING_MAP_BITS_MAX 17 + #define TRACING_MAP_BITS_MIN 7 + + - Allineamento dei valori iniziali, per esempio:: + + static const struct file_operations uprobe_events_ops = { + .owner = THIS_MODULE, + .open = probes_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, + .write = probes_write, + }; + + contro:: + + static const struct file_operations uprobe_events_ops = { + .owner = THIS_MODULE, + .open = probes_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, + .write = probes_write, + }; + + +.. _it_clangformatextra: + +Funzionalità e opzioni aggiuntive +--------------------------------- + +Al fine di minimizzare le differenze fra il codice attuale e l'output +del programma, alcune opzioni di stile e funzionalità non sono abilitate +nella configurazione base. In altre parole, lo scopo è di rendere le +differenze le più piccole possibili, permettendo la semplificazione +della revisione di file, differenze e modifiche. + +In altri casi (per esempio un particolare sottosistema/cartella/file), lo +stile del kernel potrebbe essere diverso e abilitare alcune di queste +opzioni potrebbe dare risultati migliori. + +Per esempio: + + - Allineare assegnamenti (``AlignConsecutiveAssignments``). + + - Allineare dichiarazioni (``AlignConsecutiveDeclarations``). + + - Riorganizzare il testo nei commenti (``ReflowComments``). + + - Ordinare gli ``#include`` (``SortIncludes``). + +Piuttosto che per interi file, solitamente sono utili per la riformattazione +di singoli blocchi. In alternativa, potete creare un altro file +``.clang-format`` da utilizzare con il vostro editor/IDE. diff --git a/Documentation/translations/it_IT/dev-tools/index.rst b/Documentation/translations/it_IT/dev-tools/index.rst new file mode 100644 index 00000000000000..3d3ed9d15ea147 --- /dev/null +++ b/Documentation/translations/it_IT/dev-tools/index.rst @@ -0,0 +1,17 @@ +.. include:: ../disclaimer-ita.rst + +:Original: Documentation/dev-tools/index.rst + +=================================== +Strumenti di sviluppo per il kernel +=================================== + +Qui raccogliamo i vari documenti riguardanti gli strumenti di sviluppo che +possono essere usati per lavorare col kernel . Per ora, questa è una raccolta +senza un particolare struttura; si accettano patch! + +.. toctree:: + :caption: Tabella dei contenuti + :maxdepth: 2 + + clang-format diff --git a/Documentation/translations/it_IT/i2c/summary.rst b/Documentation/translations/it_IT/i2c/summary.rst index 1535e13a32e28b..99a5b36cfb4494 100644 --- a/Documentation/translations/it_IT/i2c/summary.rst +++ b/Documentation/translations/it_IT/i2c/summary.rst @@ -3,21 +3,17 @@ Introduzione a I2C e SMBus ========================== I²C (letteralmente "I al quadrato C" e scritto I2C nella documentazione del -kernel) è un protocollo sviluppato da Philips. É un protocollo lento a 2 fili -(a velocità variabile, al massimo 400KHz), con un'estensione per le velocità -elevate (3.4 MHz). Questo protocollo offre un bus a basso costo per collegare -dispositivi di vario genere a cui si accede sporadicamente e utilizzando -poca banda. Alcuni sistemi usano varianti che non rispettano i requisiti -originali, per cui non sono indicati come I2C, ma hanno nomi diversi, per -esempio TWI (Interfaccia a due fili), IIC. +kernel) è un protocollo sviluppato da Philips. É un protocollo a 2 fili (a +velocità variabile, solitamente fino a 400KHz, e in modalità alta velocità fino +a 5 MHz). Questo protocollo offre un bus a basso costo per collegare dispositivi +di vario genere a cui si accede sporadicamente e utilizzando poca banda. I2C è +ampiamente usato nei sistemi integrati. Alcuni sistemi usano varianti che non +rispettano i requisiti originali, per cui non sono indicati come I2C, ma hanno +nomi diversi, per esempio TWI (Interfaccia a due fili), IIC. L'ultima specifica ufficiale I2C è la `"Specifica I2C-bus e manuale utente" -(UM10204) `_ -pubblicata da NXP Semiconductors. Tuttavia, è necessario effettuare il login -al sito per accedere al PDF. Una versione precedente della specifica -(revisione 6) è archiviata -`qui `_. +(UM10204) `_ pubblicata da +NXP Semiconductors, al momento della scrittura si tratta della versione 7 SMBus (Bus per la gestione del sistema) si basa sul protocollo I2C ed è principalmente un sottoinsieme di protocolli e segnali I2C. Molti dispositivi @@ -27,38 +23,62 @@ SMBus. I più comuni dispositivi collegati tramite SMBus sono moduli RAM configurati utilizzando EEPROM I2C, e circuiti integrati di monitoraggio hardware. -Poiché SMBus è principalmente un sottoinsieme del bus I2C, -possiamo farne uso su molti sistemi I2C. Ci sono però sistemi che non -soddisfano i vincoli elettrici sia di SMBus che di I2C; e altri che non possono -implementare tutta la semantica o messaggi comuni del protocollo SMBus. +Poiché SMBus è principalmente un sottoinsieme del bus I2C, possiamo farne uso su +molti sistemi I2C. Ci sono però sistemi che non soddisfano i vincoli elettrici +sia di SMBus che di I2C; e altri che non possono implementare tutta la semantica +o messaggi comuni del protocollo SMBus. Terminologia ============ -Utilizzando la terminologia della documentazione ufficiale, il bus I2C connette -uno o più circuiti integrati *master* e uno o più circuiti integrati *slave*. +Il bus I2C connette uno o più circuiti integrati controllori a dei dispositivi. .. kernel-figure:: ../../../i2c/i2c_bus.svg - :alt: Un semplice bus I2C con un master e 3 slave + :alt: Un semplice bus I2C con un controllore e 3 dispositivi Un semplice Bus I2C -Un circuito integrato **master** è un nodo che inizia le comunicazioni con gli -slave. Nell'implementazione del kernel Linux è chiamato **adattatore** o bus. I -driver degli adattatori si trovano nella sottocartella ``drivers/i2c/busses/``. +Un circuito integrato **controllore** (*controller*) è un nodo che inizia le +comunicazioni con i dispositivi (*targets*). Nell'implementazione del kernel +Linux è chiamato **adattatore** o bus. I driver degli adattatori si trovano +nella sottocartella ``drivers/i2c/busses/``. Un **algoritmo** contiene codice generico che può essere utilizzato per implementare una intera classe di adattatori I2C. Ciascun driver dell' adattatore specifico dipende da un driver dell'algoritmo nella sottocartella ``drivers/i2c/algos/`` o include la propria implementazione. -Un circuito integrato **slave** è un nodo che risponde alle comunicazioni -quando indirizzato dal master. In Linux è chiamato **client** (dispositivo). I -driver dei dispositivi sono contenuti in una cartella specifica per la +Un circuito integrato **dispositivo** è un nodo che risponde alle comunicazioni +quando indirizzato dal controllore. In Linux è chiamato **client**. Nonostante i +dispositivi siano circuiti integrati esterni al sistema, Linux può agire come +dispositivo (se l'hardware lo permette) e rispondere alla richieste di altri +controllori sul bus. Questo verrà chiamato **dispositivo locale** (*local +target*). Negli altri casi si parla di **dispositivo remoto** (*remote target*). + +I driver dei dispositivi sono contenuti in una cartella specifica per la funzionalità che forniscono, ad esempio ``drivers/media/gpio/`` per espansori GPIO e ``drivers/media/i2c/`` per circuiti integrati relativi ai video. Per la configurazione di esempio in figura, avrai bisogno di un driver per il tuo adattatore I2C e driver per i tuoi dispositivi I2C (solitamente un driver per ciascuno dispositivo). + +Sinonimi +-------- + +Come menzionato precedentemente, per ragioni storiche l'implementazione I2C del +kernel Linux usa "adatattore" (*adapter*) per i controllori e "client" per i +dispositivi. Un certo numero di strutture dati usano questi sinonimi nei loro +nomi. Dunque, durante le discussioni riguardanti l'implementazione dovrete +essere a coscienza anche di questi termini. Tuttavia si preferiscono i termini +ufficiali. + +Terminologia obsoleta +--------------------- + +Nelle prime specifiche di I2C, il controllore veniva chiamato "master" ed i +dispositivi "slave". Questi termini sono stati resi obsoleti con la versione 7 +della specifica. Inoltre, il loro uso viene scoraggiato dal codice di condotta +del kernel Linux. Tuttavia, potreste ancora trovare questi termini in pagine non +aggiornate. In generale si cerca di usare i termini controllore e dispositivo. diff --git a/Documentation/translations/it_IT/index.rst b/Documentation/translations/it_IT/index.rst index 9220f65e30d1f0..afa680607750bc 100644 --- a/Documentation/translations/it_IT/index.rst +++ b/Documentation/translations/it_IT/index.rst @@ -103,9 +103,11 @@ sviluppatori del kernel. .. toctree:: :maxdepth: 1 - process/license-rules - doc-guide/index - kernel-hacking/index + Regole sulle licenze + Scrivere la documentazione + Strumenti di sviluppo + La guida all'*hacking* + Documentazione per gli utenti ============================= diff --git a/Documentation/translations/it_IT/process/2.Process.rst b/Documentation/translations/it_IT/process/2.Process.rst index 0a62c0f33faf9d..6262c3908665fa 100644 --- a/Documentation/translations/it_IT/process/2.Process.rst +++ b/Documentation/translations/it_IT/process/2.Process.rst @@ -424,10 +424,10 @@ o entrambi. Molte delle liste di discussione del Kernel girano su vger.kernel.org; l'elenco principale lo si trova sul sito: - http://vger.kernel.org/vger-lists.html + https://subspace.kernel.org -Esistono liste gestite altrove; un certo numero di queste sono in -redhat.com/mailman/listinfo. +Tuttavia, esistono liste gestite altrove; controllare il file MAINTAINERS per +trovare la lista relativa ad un sottosistema specifico. La lista di discussione principale per lo sviluppo del kernel è, ovviamente, linux-kernel. Questa lista è un luogo ostile dove trovarsi; i volumi possono diff --git a/Documentation/translations/it_IT/process/4.Coding.rst b/Documentation/translations/it_IT/process/4.Coding.rst index ec874a8dfb9d90..3126342c4b4a70 100644 --- a/Documentation/translations/it_IT/process/4.Coding.rst +++ b/Documentation/translations/it_IT/process/4.Coding.rst @@ -69,7 +69,7 @@ e per revisionare interi file per individuare errori nello stile di codifica, refusi e possibili miglioramenti. Inoltre è utile anche per classificare gli ``#includes``, per allineare variabili/macro, per testi derivati ed altri compiti del genere. Consultate il file -:ref:`Documentation/translations/it_IT/process/clang-format.rst ` +:ref:`Documentation/translations/it_IT/dev-tools/clang-format.rst ` per maggiori dettagli Se utilizzate un programma compatibile con EditorConfig, allora alcune diff --git a/Documentation/translations/it_IT/process/5.Posting.rst b/Documentation/translations/it_IT/process/5.Posting.rst index a61d9e6f743325..3b9b4db6fb9a4b 100644 --- a/Documentation/translations/it_IT/process/5.Posting.rst +++ b/Documentation/translations/it_IT/process/5.Posting.rst @@ -208,11 +208,6 @@ di commit in un sistema di controllo di versione. Sarà seguito da: l'opzione "-p" assocerà alla modifica il nome della funzione alla quale si riferisce, rendendo il risultato più facile da leggere per gli altri. -Dovreste evitare di includere nelle patch delle modifiche per file -irrilevanti (quelli generati dal processo di generazione, per esempio, o i file -di backup del vostro editor). Il file "dontdiff" nella cartella Documentation -potrà esservi d'aiuto su questo punto; passatelo a diff con l'opzione "-X". - Le etichette sopracitate danno un'idea di come una patch prende vita e sono descritte nel dettaglio nel documento :ref:`Documentation/translations/it_IT/process/submitting-patches.rst `. diff --git a/Documentation/translations/it_IT/process/changes.rst b/Documentation/translations/it_IT/process/changes.rst index 0bcf8423cc806e..c7d05e2fff1553 100644 --- a/Documentation/translations/it_IT/process/changes.rst +++ b/Documentation/translations/it_IT/process/changes.rst @@ -34,9 +34,9 @@ PC Card, per esempio, probabilmente non dovreste preoccuparvi di pcmciautils. ====================== ================= ======================================== GNU C 5.1 gcc --version Clang/LLVM (optional) 13.0.0 clang --version -Rust (opzionale) 1.76.0 rustc --version +Rust (opzionale) 1.78.0 rustc --version bindgen (opzionale) 0.65.1 bindgen --version -GNU make 3.81 make --version +GNU make 4.0 make --version bash 4.2 bash --version binutils 2.25 ld -v flex 2.5.35 flex --version @@ -65,6 +65,8 @@ Sphinx\ [#f1]_ 2.4.4 sphinx-build --version cpio any cpio --version GNU tar 1.28 tar --version gtags (opzionale) 6.6.5 gtags --version +mkimage (opzionale) 2017.01 mkimage --version +Python (opzionale) 3.5.x python3 --version ====================== ================= ======================================== .. [#f1] Sphinx è necessario solo per produrre la documentazione del Kernel @@ -88,10 +90,25 @@ potremmo rimuovere gli espedienti che abbiamo implementato per farli funzionare. Per maggiori informazioni :ref:`Building Linux with Clang/LLVM `. +Rust (opzionale) +---------------- + +È necessaria una versione recente del compilatore Rust. + +Verificate le istruzioni Documentation/rust/quick-start.rst su come soddisfare i +requisiti per compilare code Rust. In particolare, la regola ``rustavailable`` +nel ``Makefile`` è utile per verificare perché gli strumenti di compilazione non +vengono trovati. + +bindgen (opzionale) +------------------- + +``bindgen`` viene usato per generare il collegamento (binding) da Rust al lato C del kernel. Dipende da ``libclang``. + Make ---- -Per compilare il kernel vi servirà GNU make 3.81 o successivo. +Per compilare il kernel vi servirà GNU make 4.0 o successivo. Bash ---- @@ -168,6 +185,16 @@ Il programma GNU GLOBAL versione 6.6.5, o successiva, è necessario quando si vuole eseguire ``make gtags`` e generare i relativi indici. Internamente si fa uso del parametro gtags ``-C (--directory)`` che compare in questa versione. +mkimage +------- + +Questo strumento viene usato per produrre un *Flat Image Tree* (FIT), +tipicamente usato su sistemi ARM. Questo strumento è disponibile tramite il +pacchetto ``u-boot-tools`` oppure può essere compilato dal codice sorgente di +U-Boot. Consultate le istruzioni +https://docs.u-boot.org/en/latest/build/tools.html#building-tools-for-linux + + Strumenti di sistema ******************** diff --git a/Documentation/translations/it_IT/process/clang-format.rst b/Documentation/translations/it_IT/process/clang-format.rst deleted file mode 100644 index 6fab07772da0c8..00000000000000 --- a/Documentation/translations/it_IT/process/clang-format.rst +++ /dev/null @@ -1,197 +0,0 @@ -.. include:: ../disclaimer-ita.rst - -:Original: :ref:`Documentation/dev-tools/clang-format.rst ` -:Translator: Federico Vaga - -.. _it_clangformat: - -clang-format -============ -``clang-format`` è uno strumento per formattare codice C/C++/... secondo -un gruppo di regole ed euristiche. Come tutti gli strumenti, non è perfetto -e non copre tutti i singoli casi, ma è abbastanza buono per essere utile. - -``clang-format`` può essere usato per diversi fini: - - - Per riformattare rapidamente un blocco di codice secondo lo stile del - kernel. Particolarmente utile quando si sposta del codice e lo si - allinea/ordina. Vedere it_clangformatreformat_. - - - Identificare errori di stile, refusi e possibili miglioramenti nei - file che mantieni, le modifiche che revisioni, le differenze, - eccetera. Vedere it_clangformatreview_. - - - Ti aiuta a seguire lo stile del codice, particolarmente utile per i - nuovi arrivati o per coloro che lavorano allo stesso tempo su diversi - progetti con stili di codifica differenti. - -Il suo file di configurazione è ``.clang-format`` e si trova nella cartella -principale dei sorgenti del kernel. Le regole scritte in quel file tentano -di approssimare le lo stile di codifica del kernel. Si tenta anche di seguire -il più possibile -:ref:`Documentation/translations/it_IT/process/coding-style.rst `. -Dato che non tutto il kernel segue lo stesso stile, potreste voler aggiustare -le regole di base per un particolare sottosistema o cartella. Per farlo, -potete sovrascriverle scrivendole in un altro file ``.clang-format`` in -una sottocartella. - -Questo strumento è già stato incluso da molto tempo nelle distribuzioni -Linux più popolari. Cercate ``clang-format`` nel vostro repositorio. -Altrimenti, potete scaricare una versione pre-generata dei binari di LLVM/clang -oppure generarlo dai codici sorgenti: - - https://releases.llvm.org/download.html - -Troverete più informazioni ai seguenti indirizzi: - - https://clang.llvm.org/docs/ClangFormat.html - - https://clang.llvm.org/docs/ClangFormatStyleOptions.html - - -.. _it_clangformatreview: - -Revisionare lo stile di codifica per file e modifiche ------------------------------------------------------ - -Eseguendo questo programma, potrete revisionare un intero sottosistema, -cartella o singoli file alla ricerca di errori di stile, refusi o -miglioramenti. - -Per farlo, potete eseguire qualcosa del genere:: - - # Make sure your working directory is clean! - clang-format -i kernel/*.[ch] - -E poi date un'occhiata a *git diff*. - -Osservare le righe di questo diff è utile a migliorare/aggiustare -le opzioni di stile nel file di configurazione; così come per verificare -le nuove funzionalità/versioni di ``clang-format``. - -``clang-format`` è in grado di leggere diversi diff unificati, quindi -potrete revisionare facilmente delle modifiche e *git diff*. -La documentazione si trova al seguente indirizzo: - - https://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting - -Per evitare che ``clang-format`` formatti alcune parti di un file, potete -scrivere nel codice:: - - int formatted_code; - // clang-format off - void unformatted_code ; - // clang-format on - void formatted_code_again; - -Nonostante si attraente l'idea di utilizzarlo per mantenere un file -sempre in sintonia con ``clang-format``, specialmente per file nuovi o -se siete un manutentore, ricordatevi che altre persone potrebbero usare -una versione diversa di ``clang-format`` oppure non utilizzarlo del tutto. -Quindi, dovreste trattenervi dall'usare questi marcatori nel codice del -kernel; almeno finché non vediamo che ``clang-format`` è diventato largamente -utilizzato. - - -.. _it_clangformatreformat: - -Riformattare blocchi di codice ------------------------------- - -Utilizzando dei plugin per il vostro editor, potete riformattare una -blocco (selezione) di codice con una singola combinazione di tasti. -Questo è particolarmente utile: quando si riorganizza il codice, per codice -complesso, macro multi-riga (e allineare le loro "barre"), eccetera. - -Ricordatevi che potete sempre aggiustare le modifiche in quei casi dove -questo strumento non ha fatto un buon lavoro. Ma come prima approssimazione, -può essere davvero molto utile. - -Questo programma si integra con molti dei più popolari editor. Alcuni di -essi come vim, emacs, BBEdit, Visaul Studio, lo supportano direttamente. -Al seguente indirizzo troverete le istruzioni: - - https://clang.llvm.org/docs/ClangFormat.html - -Per Atom, Eclipse, Sublime Text, Visual Studio Code, XCode e altri editor -e IDEs dovreste essere in grado di trovare dei plugin pronti all'uso. - -Per questo caso d'uso, considerate l'uso di un secondo ``.clang-format`` -che potete personalizzare con le vostre opzioni. -Consultare it_clangformatextra_. - - -.. _it_clangformatmissing: - -Cose non supportate -------------------- - -``clang-format`` non ha il supporto per alcune cose che sono comuni nel -codice del kernel. Sono facili da ricordare; quindi, se lo usate -regolarmente, imparerete rapidamente a evitare/ignorare certi problemi. - -In particolare, quelli più comuni che noterete sono: - - - Allineamento di ``#define`` su una singola riga, per esempio:: - - #define TRACING_MAP_BITS_DEFAULT 11 - #define TRACING_MAP_BITS_MAX 17 - #define TRACING_MAP_BITS_MIN 7 - - contro:: - - #define TRACING_MAP_BITS_DEFAULT 11 - #define TRACING_MAP_BITS_MAX 17 - #define TRACING_MAP_BITS_MIN 7 - - - Allineamento dei valori iniziali, per esempio:: - - static const struct file_operations uprobe_events_ops = { - .owner = THIS_MODULE, - .open = probes_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, - .write = probes_write, - }; - - contro:: - - static const struct file_operations uprobe_events_ops = { - .owner = THIS_MODULE, - .open = probes_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, - .write = probes_write, - }; - - -.. _it_clangformatextra: - -Funzionalità e opzioni aggiuntive ---------------------------------- - -Al fine di minimizzare le differenze fra il codice attuale e l'output -del programma, alcune opzioni di stile e funzionalità non sono abilitate -nella configurazione base. In altre parole, lo scopo è di rendere le -differenze le più piccole possibili, permettendo la semplificazione -della revisione di file, differenze e modifiche. - -In altri casi (per esempio un particolare sottosistema/cartella/file), lo -stile del kernel potrebbe essere diverso e abilitare alcune di queste -opzioni potrebbe dare risultati migliori. - -Per esempio: - - - Allineare assegnamenti (``AlignConsecutiveAssignments``). - - - Allineare dichiarazioni (``AlignConsecutiveDeclarations``). - - - Riorganizzare il testo nei commenti (``ReflowComments``). - - - Ordinare gli ``#include`` (``SortIncludes``). - -Piuttosto che per interi file, solitamente sono utili per la riformattazione -di singoli blocchi. In alternativa, potete creare un altro file -``.clang-format`` da utilizzare con il vostro editor/IDE. diff --git a/Documentation/translations/it_IT/process/coding-style.rst b/Documentation/translations/it_IT/process/coding-style.rst index a4b9f44081dae8..c0dc786b84749a 100644 --- a/Documentation/translations/it_IT/process/coding-style.rst +++ b/Documentation/translations/it_IT/process/coding-style.rst @@ -620,18 +620,6 @@ Lo stile preferito per i commenti più lunghi (multi-riga) è: * with beginning and ending almost-blank lines. */ -Per i file in net/ e in drivers/net/ lo stile preferito per i commenti -più lunghi (multi-riga) è leggermente diverso. - -.. code-block:: c - - /* The preferred comment style for files in net/ and drivers/net - * looks like this. - * - * It is nearly the same as the generally preferred comment style, - * but there is no initial almost-blank line. - */ - È anche importante commentare i dati, sia per i tipi base che per tipi derivati. A questo scopo, dichiarate un dato per riga (niente virgole per una dichiarazione multipla). Questo vi lascerà spazio per un piccolo @@ -726,7 +714,7 @@ di stile, refusi e possibilmente anche delle migliorie. È anche utile per ordinare gli ``#include``, per allineare variabili/macro, per ridistribuire il testo e altre cose simili. Per maggiori dettagli, consultate il file -:ref:`Documentation/translations/it_IT/process/clang-format.rst `. +:ref:`Documentation/translations/it_IT/dev-tools/clang-format.rst `. Se utilizzate un programma compatibile con EditorConfig, allora alcune configurazioni basilari come l'indentazione e la fine delle righe verranno @@ -827,6 +815,29 @@ blocco do - while: do_this(b, c); \ } while (0) +Le macro che sembrano funzioni con parametri non usati dovrebbero essere +sostituite da funzioni inline per evitare il problema. + +.. code-block:: c + + static inline void fun(struct foo *foo) + { + } + +Per motivi storici, molti file usano ancora l'approccio "cast a (void)" per +valutare i parametri. Tuttavia, non è raccomandato. Le funzioni inline risolvono +i problemi di "espressioni con effetti avversi valutate più di una volta", +variabili non utilizzate, e in genere per qualche motivo sono documentate +meglio. + +.. code-block:: c + + /* + * Avoid doing this whenever possible and instead opt for static + * inline functions + */ + #define macrofun(foo) do { (void) (foo); } while (0) + Cose da evitare quando si usano le macro: 1) le macro che hanno effetti sul flusso del codice: diff --git a/Documentation/translations/it_IT/process/email-clients.rst b/Documentation/translations/it_IT/process/email-clients.rst index 76ca3226c8cd7a..97173746d8c90b 100644 --- a/Documentation/translations/it_IT/process/email-clients.rst +++ b/Documentation/translations/it_IT/process/email-clients.rst @@ -228,7 +228,7 @@ Mutt è molto personalizzabile. Qui di seguito trovate la configurazione minima per iniziare ad usare Mutt per inviare patch usando Gmail:: # .muttrc - # ================ IMAP ==================== + # ================ IMAP ==================== set imap_user = 'yourusername@gmail.com' set imap_pass = 'yourpassword' set spoolfile = imaps://imap.gmail.com/INBOX @@ -365,27 +365,12 @@ un editor esterno. Un altro problema è che Gmail usa la codifica base64 per tutti quei messaggi che contengono caratteri non ASCII. Questo include cose tipo i nomi europei. -Proton Mail -*********** +HacKerMaiL (TUI) +**************** -Il servizio Proton Mail ha una funzionalità che cripta tutti i messaggi verso -ogni destinatario per cui è possibile trovare una chiave usando il *Web Key -Directory* (WKD). Il servizio kernel.org pubblica il WKD per ogni sviluppatore -in possesso di un conto kernel.org. Di conseguenza, tutti i messaggi inviati -usando Proton Mail verso indirizzi kernel.org verranno criptati. - -Proton Mail non fornisce alcun meccanismo per disabilitare questa funzionalità -perché verrebbe considerato un problema per la riservatezza. Questa funzionalità -è attiva anche quando si inviano messaggi usando il Proton Mail Bridge. Dunque -tutta la posta in uscita verrà criptata, incluse le patch inviate con ``git -send-email``. - -I messaggi criptati sono una fonte di problemi; altri sviluppatori potrebbero -non aver configurato i loro programmi, o strumenti, per gestire messaggi -criptati; inoltre, alcuni programmi di posta elettronica potrebbero criptare le -risposte a messaggi criptati per tutti i partecipanti alla discussione, inclusa -la lista di discussione stessa. - -A meno che non venga introdotta una maniera per disabilitare questa -funzionalità, non è consigliato usare Proton Mail per contribuire allo sviluppo -del kernel. +HacKerMaiL (hkml) è una semplice casella pubblica per la gestione dei messaggi +di posta che non richiede alcuna sottoscrizione ad una lista di discussione. +Viene sviluppato e mantenuto dal manutentore di DAMON e si pone come obiettivo +quello di gestire il processo di sviluppo semplice come quello di DAMON e più in +generale i sottosistemi del kernel. Per maggiori dettagli, fate riferimento al +documento README (https://github.com/sjp38/hackermail/blob/master/README.md). diff --git a/Documentation/translations/it_IT/process/howto.rst b/Documentation/translations/it_IT/process/howto.rst index 090941a0a898e7..f51288602ee3dd 100644 --- a/Documentation/translations/it_IT/process/howto.rst +++ b/Documentation/translations/it_IT/process/howto.rst @@ -344,7 +344,7 @@ principale 4.x, sarà necessario un test d'integrazione. A tale scopo, esiste un repositorio speciale di test nel quale virtualmente tutti i rami dei sottosistemi vengono inclusi su base quotidiana: - https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git + https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git In questo modo, i kernel -next offrono uno sguardo riassuntivo su quello che ci si aspetterà essere nel kernel principale nel successivo periodo @@ -389,12 +389,12 @@ sviluppatori del kernel partecipano alla lista di discussione Linux Kernel. I dettagli su come iscriversi e disiscriversi dalla lista possono essere trovati al sito: - http://vger.kernel.org/vger-lists.html#linux-kernel + https://subspace.kernel.org/subscribing.html Ci sono diversi archivi della lista di discussione. Usate un qualsiasi motore di ricerca per trovarli. Per esempio: - https://lore.kernel.org/lkml/ + https://lore.kernel.org/linux-kernel/ É caldamente consigliata una ricerca in questi archivi sul tema che volete sollevare, prima di pubblicarlo sulla lista. Molte cose sono già state @@ -407,13 +407,13 @@ discussione e il loro uso. Molte di queste liste sono gestite su kernel.org. Per informazioni consultate la seguente pagina: - http://vger.kernel.org/vger-lists.html + https://subspace.kernel.org Per favore ricordatevi della buona educazione quando utilizzate queste liste. Sebbene sia un pò dozzinale, il seguente URL contiene alcune semplici linee guida per interagire con la lista (o con qualsiasi altra lista): - http://www.albion.com/netiquette/ + https://subspace.kernel.org/etiquette.html Se diverse persone rispondo alla vostra mail, la lista dei riceventi (copia conoscenza) potrebbe diventare abbastanza lunga. Non cancellate nessuno dalla diff --git a/Documentation/translations/it_IT/process/index.rst b/Documentation/translations/it_IT/process/index.rst index c24500f746607b..5a5214f5fd7232 100644 --- a/Documentation/translations/it_IT/process/index.rst +++ b/Documentation/translations/it_IT/process/index.rst @@ -99,16 +99,6 @@ degli sviluppatori: kernel-docs -Ed infine, qui ci sono alcune guide più tecniche che son state messe qua solo -perché non si è trovato un posto migliore. - -.. toctree:: - :maxdepth: 1 - - magic-number - clang-format - ../arch/riscv/patch-acceptance - .. only:: subproject and html Indices diff --git a/Documentation/translations/it_IT/process/magic-number.rst b/Documentation/translations/it_IT/process/magic-number.rst deleted file mode 100644 index cd8f23571835f8..00000000000000 --- a/Documentation/translations/it_IT/process/magic-number.rst +++ /dev/null @@ -1,90 +0,0 @@ -.. include:: ../disclaimer-ita.rst - -:Original: :ref:`Documentation/staging/magic-number.rst ` -:Translator: Federico Vaga - -.. _it_magicnumbers: - -I numeri magici di Linux -======================== - -Questo documento è un registro dei numeri magici in uso. Quando -aggiungete un numero magico ad una struttura, dovreste aggiungerlo anche -a questo documento; la cosa migliore è che tutti i numeri magici usati -dalle varie strutture siano unici. - -È **davvero** un'ottima idea proteggere le strutture dati del kernel con -dei numeri magici. Questo vi permette in fase d'esecuzione di (a) verificare -se una struttura è stata malmenata, o (b) avete passato a una procedura la -struttura errata. Quest'ultimo è molto utile - particolarmente quando si passa -una struttura dati tramite un puntatore void \*. Il codice tty, per esempio, -effettua questa operazione con regolarità passando avanti e indietro le -strutture specifiche per driver e discipline. - -Per utilizzare un numero magico, dovete dichiararlo all'inizio della struttura -dati, come di seguito:: - - struct tty_ldisc { - int magic; - ... - }; - -Per favore, seguite questa direttiva quando aggiungerete migliorie al kernel! -Mi ha risparmiato un numero illimitato di ore di debug, specialmente nei casi -più ostici dove si è andati oltre la dimensione di un vettore e la struttura -dati che lo seguiva in memoria è stata sovrascritta. Seguendo questa -direttiva, questi casi vengono identificati velocemente e in sicurezza. - -Registro dei cambiamenti:: - - Theodore Ts'o - 31 Mar 94 - - La tabella magica è aggiornata a Linux 2.1.55. - - Michael Chastain - - 22 Sep 1997 - - Ora dovrebbe essere aggiornata a Linux 2.1.112. Dato che - siamo in un momento di congelamento delle funzionalità - (*feature freeze*) è improbabile che qualcosa cambi prima - della versione 2.2.x. Le righe sono ordinate secondo il - campo numero. - - Krzysztof G. Baranowski - - 29 Jul 1998 - - Aggiornamento della tabella a Linux 2.5.45. Giusti nel congelamento - delle funzionalità ma è comunque possibile che qualche nuovo - numero magico s'intrufoli prima del kernel 2.6.x. - - Petr Baudis - - 03 Nov 2002 - - Aggiornamento della tabella magica a Linux 2.5.74. - - Fabian Frederick - - 09 Jul 2003 - - -===================== ================ ======================== ========================================== -Nome magico Numero Struttura File -===================== ================ ======================== ========================================== -PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h`` -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`` -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`` -CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` -YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` -CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` -QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` -QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` -NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h`` -===================== ================ ======================== ========================================== diff --git a/Documentation/translations/it_IT/process/submit-checklist.rst b/Documentation/translations/it_IT/process/submit-checklist.rst index 2fc09cc1f0be51..692be4af9c9be4 100644 --- a/Documentation/translations/it_IT/process/submit-checklist.rst +++ b/Documentation/translations/it_IT/process/submit-checklist.rst @@ -5,8 +5,9 @@ .. _it_submitchecklist: +============================================================================ Lista delle verifiche da fare prima di inviare una patch per il kernel Linux -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +============================================================================ Qui troverete una lista di cose che uno sviluppatore dovrebbe fare per vedere le proprie patch accettate più rapidamente. @@ -15,118 +16,126 @@ Tutti questi punti integrano la documentazione fornita riguardo alla sottomissione delle patch, in particolare :ref:`Documentation/translations/it_IT/process/submitting-patches.rst `. +Revisiona il tuo codice +======================= + 1) Se state usando delle funzionalità del kernel allora includete (#include) i file che le dichiarano/definiscono. Non dipendente dal fatto che un file d'intestazione include anche quelli usati da voi. -2) Compilazione pulita: - - a) con le opzioni ``CONFIG`` negli stati ``=y``, ``=m`` e ``=n``. Nessun - avviso/errore di ``gcc`` e nessun avviso/errore dal linker. - - b) con ``allnoconfig``, ``allmodconfig`` - - c) quando si usa ``O=builddir`` - - d) Qualsiasi modifica in Documentation/ deve compilare con successo senza - avvisi o errori. Usare ``make htmldocs`` o ``make pdfdocs`` per verificare - e correggere i problemi - -3) Compilare per diverse architetture di processore usando strumenti per - la cross-compilazione o altri. +2) Controllate lo stile del codice della vostra patch secondo le direttive + scritte in :ref:`Documentation/translations/it_IT/process/coding-style.rst `. -4) Una buona architettura per la verifica della cross-compilazione è la ppc64 - perché tende ad usare ``unsigned long`` per le quantità a 64-bit. +3) Tutte le barriere di sincronizzazione {per esempio, ``barrier()``, + ``rmb()``, ``wmb()``} devono essere accompagnate da un commento nei + sorgenti che ne spieghi la logica: cosa fanno e perché. -5) Controllate lo stile del codice della vostra patch secondo le direttive - scritte in :ref:`Documentation/translations/it_IT/process/coding-style.rst `. - Prima dell'invio della patch, usate il verificatore di stile - (``script/checkpatch.pl``) per scovare le violazioni più semplici. - Dovreste essere in grado di giustificare tutte le violazioni rimanenti nella - vostra patch. +Revisionate i cambiamenti a Kconfig +=================================== -6) Le opzioni ``CONFIG``, nuove o modificate, non scombussolano il menu +1) Le opzioni ``CONFIG``, nuove o modificate, non scombussolano il menu di configurazione e sono preimpostate come disabilitate a meno che non soddisfino i criteri descritti in ``Documentation/kbuild/kconfig-language.rst`` alla punto "Voci di menu: valori predefiniti". -7) Tutte le nuove opzioni ``Kconfig`` hanno un messaggio di aiuto. +2) Tutte le nuove opzioni ``Kconfig`` hanno un messaggio di aiuto. -8) La patch è stata accuratamente revisionata rispetto alle più importanti +3) La patch è stata accuratamente revisionata rispetto alle più importanti configurazioni ``Kconfig``. Questo è molto difficile da fare correttamente - un buono lavoro di testa sarà utile. -9) Verificare con sparse. +Fornite documentazione +====================== -10) Usare ``make checkstack`` e correggere tutti i problemi rilevati. +1) Includete :ref:`kernel-doc ` per documentare API globali del + kernel. - .. note:: +2) Tutti i nuovi elementi in ``/proc`` sono documentati in ``Documentation/``. - ``checkstack`` non evidenzia esplicitamente i problemi, ma una funzione - che usa più di 512 byte sullo stack è una buona candidata per una - correzione. +3) Tutti i nuovi parametri d'avvio del kernel sono documentati in + ``Documentation/admin-guide/kernel-parameters.rst``. -11) Includete commenti :ref:`kernel-doc ` per documentare API - globali del kernel. Usate ``make htmldocs`` o ``make pdfdocs`` per - verificare i commenti :ref:`kernel-doc ` ed eventualmente - correggerli. +4) Tutti i nuovi parametri dei moduli sono documentati con ``MODULE_PARM_DESC()``. -12) La patch è stata verificata con le seguenti opzioni abilitate - contemporaneamente: ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``, - ``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``, - ``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``, - ``CONFIG_PROVE_RCU`` e ``CONFIG_DEBUG_OBJECTS_RCU_HEAD``. +5) Tutte le nuove interfacce verso lo spazio utente sono documentate in + ``Documentation/ABI/``. Leggete ``Documentation/ABI/README`` per maggiori + informazioni. Le patch che modificano le interfacce utente dovrebbero + essere inviate in copia anche a linux-api@vger.kernel.org. -13) La patch è stata compilata e verificata in esecuzione con, e senza, - le opzioni ``CONFIG_SMP`` e ``CONFIG_PREEMPT``. +6) Se la patch aggiunge nuove chiamate ioctl, allora aggiornate + ``Documentation/userspace-api/ioctl/ioctl-number.rst``. -14) Se la patch ha effetti sull'IO dei dischi, eccetera: allora dev'essere - verificata con, e senza, l'opzione ``CONFIG_LBDAF``. +Verificate il vostro codice con gli strumenti +============================================= -15) Tutti i percorsi del codice sono stati verificati con tutte le funzionalità - di lockdep abilitate. +1) Prima dell'invio della patch, usate il verificatore di stile + (``script/checkpatch.pl``) per scovare le violazioni più semplici. + Dovreste essere in grado di giustificare tutte le violazioni rimanenti nella + vostra patch. -16) Tutti i nuovi elementi in ``/proc`` sono documentati in ``Documentation/``. +2) Verificare il codice con sparse. -17) Tutti i nuovi parametri d'avvio del kernel sono documentati in - ``Documentation/admin-guide/kernel-parameters.rst``. -18) Tutti i nuovi parametri dei moduli sono documentati con ``MODULE_PARM_DESC()``. +3) Usare ``make checkstack`` e correggere tutti i problemi rilevati. Da notare + che ``checkstack`` non evidenzia esplicitamente i problemi, ma una funzione + che usa più di 512 byte sullo stack è una buona candidata per una correzione. -19) Tutte le nuove interfacce verso lo spazio utente sono documentate in - ``Documentation/ABI/``. Leggete ``Documentation/ABI/README`` per maggiori - informazioni. Le patch che modificano le interfacce utente dovrebbero - essere inviate in copia anche a linux-api@vger.kernel.org. +Compilare il codice +=================== + +1) Compilazione pulita: + + a) con le opzioni ``CONFIG`` negli stati ``=y``, ``=m`` e ``=n``. Nessun + avviso/errore di ``gcc`` e nessun avviso/errore dal linker. -20) La patch è stata verificata con l'iniezione di fallimenti in slab e - nell'allocazione di pagine. Vedere ``Documentation/fault-injection/``. + b) con ``allnoconfig``, ``allmodconfig`` + + c) quando si usa ``O=builddir`` - Se il nuovo codice è corposo, potrebbe essere opportuno aggiungere - l'iniezione di fallimenti specifici per il sottosistema. + d) Qualsiasi modifica in Documentation/ deve compilare con successo senza + avvisi o errori. Usare ``make htmldocs`` o ``make pdfdocs`` per verificare + e correggere i problemi -21) Il nuovo codice è stato compilato con ``gcc -W`` (usate +2) Compilare per diverse architetture di processore usando strumenti per la + cross-compilazione o altri. Una buona architettura per la verifica della + cross-compilazione è la ppc64 perché tende ad usare ``unsigned long`` per le + quantità a 64-bit. + +3) Il nuovo codice è stato compilato con ``gcc -W`` (usate ``make KCFLAGS=-W``). Questo genererà molti avvisi, ma è ottimo per scovare bachi come "warning: comparison between signed and unsigned". -22) La patch è stata verificata dopo essere stata inclusa nella serie di patch - -mm; questo al fine di assicurarsi che continui a funzionare assieme a - tutte le altre patch in coda e i vari cambiamenti nei sottosistemi VM, VFS - e altri. +4) Se il codice che avete modificato dipende o usa una qualsiasi interfaccia o + funzionalità del kernel che è associata a uno dei seguenti simboli + ``Kconfig``, allora verificate che il kernel compili con diverse + configurazioni dove i simboli sono disabilitati e/o ``=m`` (se c'è la + possibilità) [non tutti contemporaneamente, solo diverse combinazioni + casuali]: -23) Tutte le barriere di sincronizzazione {per esempio, ``barrier()``, - ``rmb()``, ``wmb()``} devono essere accompagnate da un commento nei - sorgenti che ne spieghi la logica: cosa fanno e perché. + ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``, + ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``, + ``CONFIG_NET``, ``CONFIG_INET=n`` (ma l'ultimo con ``CONFIG_NET=y``). -24) Se la patch aggiunge nuove chiamate ioctl, allora aggiornate - ``Documentation/userspace-api/ioctl/ioctl-number.rst``. +Verificate il vostro codice +=========================== + +1) La patch è stata verificata con le seguenti opzioni abilitate + contemporaneamente: ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``, + ``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``, + ``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``, + ``CONFIG_PROVE_RCU`` e ``CONFIG_DEBUG_OBJECTS_RCU_HEAD``. + +2) La patch è stata compilata e verificata in esecuzione con, e senza, + le opzioni ``CONFIG_SMP`` e ``CONFIG_PREEMPT``. + +3) Tutti i percorsi del codice sono stati verificati con tutte le funzionalità + di lockdep abilitate. -25) Se il codice che avete modificato dipende o usa una qualsiasi interfaccia o - funzionalità del kernel che è associata a uno dei seguenti simboli - ``Kconfig``, allora verificate che il kernel compili con diverse - configurazioni dove i simboli sono disabilitati e/o ``=m`` (se c'è la - possibilità) [non tutti contemporaneamente, solo diverse combinazioni - casuali]: +4) La patch è stata verificata con l'iniezione di fallimenti in slab e + nell'allocazione di pagine. Vedere ``Documentation/fault-injection/``. + Se il nuovo codice è corposo, potrebbe essere opportuno aggiungere + l'iniezione di fallimenti specifici per il sottosistema. - ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``, - ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``, - ``CONFIG_NET``, ``CONFIG_INET=n`` (ma l'ultimo con ``CONFIG_NET=y``). +5) La patch è stata verificata sul tag più recente di linux-next per assicurarsi + che funzioni assieme a tutte le altre patch in coda, assieme ai vari + cambiamenti nei sottosistemi VM, VFS e altri. diff --git a/Documentation/translations/it_IT/process/submitting-patches.rst b/Documentation/translations/it_IT/process/submitting-patches.rst index a7252e73937a30..1cc4808139ceed 100644 --- a/Documentation/translations/it_IT/process/submitting-patches.rst +++ b/Documentation/translations/it_IT/process/submitting-patches.rst @@ -137,10 +137,10 @@ questione. Quando volete fare riferimento ad una lista di discussione, preferite il servizio d'archiviazione lore.kernel.org. Per create un collegamento URL è -sufficiente usare il campo ``Message-Id``, presente nell'intestazione del +sufficiente usare il campo ``Message-ID``, presente nell'intestazione del messaggio, senza parentesi angolari. Per esempio:: - Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/ + Link: https://lore.kernel.org/30th.anniversary.repost@klaava.Helsinki.FI Prima d'inviare il messaggio ricordatevi di verificare che il collegamento così creato funzioni e che indirizzi verso il messaggio desiderato. @@ -275,11 +275,9 @@ patch riceverà molta più attenzione. Tuttavia, per favore, non spammate le lis di discussione che non sono interessate al vostro lavoro. Molte delle liste di discussione relative al kernel vengono ospitate su -vger.kernel.org; potete trovare un loro elenco alla pagina -http://vger.kernel.org/vger-lists.html. Tuttavia, ci sono altre liste di -discussione ospitate altrove. - -Non inviate più di 15 patch alla volta sulle liste di discussione vger!!! +kernel.org; potete trovare un loro elenco alla pagina +https://subspace.kernel.org. Tuttavia, ci sono altre liste di discussione +ospitate altrove. L'ultimo giudizio sull'integrazione delle modifiche accettate spetta a Linux Torvalds. Il suo indirizzo e-mail è . @@ -891,6 +889,14 @@ Assicuratevi che il commit si basi su sorgenti ufficiali del manutentore/mainline e non su sorgenti interni, accessibile solo a voi, altrimenti sarebbe inutile. +Strumenti +--------- + +Molti degli aspetti più tecnici di questo processo possono essere automatizzati +usando b4, la cui documentazione è disponibile all'indirizzo +. Può aiutare a tracciare la dipendenze, +eseguire checkpatch e con la formattazione e l'invio di messaggi di posta. + Riferimenti ----------- @@ -913,9 +919,6 @@ Greg Kroah-Hartman, "Come scocciare un manutentore di un sottosistema" -No!!!! Basta gigantesche bombe patch alle persone sulla lista linux-kernel@vger.kernel.org! - - Kernel Documentation/translations/it_IT/process/coding-style.rst. E-mail di Linus Torvalds sul formato canonico di una patch: diff --git a/Documentation/translations/it_IT/staging/index.rst b/Documentation/translations/it_IT/staging/index.rst new file mode 100644 index 00000000000000..6b56707f3a3a81 --- /dev/null +++ b/Documentation/translations/it_IT/staging/index.rst @@ -0,0 +1,13 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-ita.rst + +:Original: :ref:`Documentation/staging/index.rst ` + +Documenti in ordine sparso +========================== + +.. toctree:: + :maxdepth: 2 + + magic-number diff --git a/Documentation/translations/it_IT/staging/magic-number.rst b/Documentation/translations/it_IT/staging/magic-number.rst new file mode 100644 index 00000000000000..cd8f23571835f8 --- /dev/null +++ b/Documentation/translations/it_IT/staging/magic-number.rst @@ -0,0 +1,90 @@ +.. include:: ../disclaimer-ita.rst + +:Original: :ref:`Documentation/staging/magic-number.rst ` +:Translator: Federico Vaga + +.. _it_magicnumbers: + +I numeri magici di Linux +======================== + +Questo documento è un registro dei numeri magici in uso. Quando +aggiungete un numero magico ad una struttura, dovreste aggiungerlo anche +a questo documento; la cosa migliore è che tutti i numeri magici usati +dalle varie strutture siano unici. + +È **davvero** un'ottima idea proteggere le strutture dati del kernel con +dei numeri magici. Questo vi permette in fase d'esecuzione di (a) verificare +se una struttura è stata malmenata, o (b) avete passato a una procedura la +struttura errata. Quest'ultimo è molto utile - particolarmente quando si passa +una struttura dati tramite un puntatore void \*. Il codice tty, per esempio, +effettua questa operazione con regolarità passando avanti e indietro le +strutture specifiche per driver e discipline. + +Per utilizzare un numero magico, dovete dichiararlo all'inizio della struttura +dati, come di seguito:: + + struct tty_ldisc { + int magic; + ... + }; + +Per favore, seguite questa direttiva quando aggiungerete migliorie al kernel! +Mi ha risparmiato un numero illimitato di ore di debug, specialmente nei casi +più ostici dove si è andati oltre la dimensione di un vettore e la struttura +dati che lo seguiva in memoria è stata sovrascritta. Seguendo questa +direttiva, questi casi vengono identificati velocemente e in sicurezza. + +Registro dei cambiamenti:: + + Theodore Ts'o + 31 Mar 94 + + La tabella magica è aggiornata a Linux 2.1.55. + + Michael Chastain + + 22 Sep 1997 + + Ora dovrebbe essere aggiornata a Linux 2.1.112. Dato che + siamo in un momento di congelamento delle funzionalità + (*feature freeze*) è improbabile che qualcosa cambi prima + della versione 2.2.x. Le righe sono ordinate secondo il + campo numero. + + Krzysztof G. Baranowski + + 29 Jul 1998 + + Aggiornamento della tabella a Linux 2.5.45. Giusti nel congelamento + delle funzionalità ma è comunque possibile che qualche nuovo + numero magico s'intrufoli prima del kernel 2.6.x. + + Petr Baudis + + 03 Nov 2002 + + Aggiornamento della tabella magica a Linux 2.5.74. + + Fabian Frederick + + 09 Jul 2003 + + +===================== ================ ======================== ========================================== +Nome magico Numero Struttura File +===================== ================ ======================== ========================================== +PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h`` +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`` +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`` +CODA_MAGIC 0xC0DAC0DA coda_file_info ``fs/coda/coda_fs_i.h`` +YAM_MAGIC 0xF10A7654 yam_port ``drivers/net/hamradio/yam.c`` +CCB_MAGIC 0xf2691ad2 ccb ``drivers/scsi/ncr53c8xx.c`` +QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry ``drivers/scsi/arm/queue.c`` +QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry ``drivers/scsi/arm/queue.c`` +NMI_MAGIC 0x48414d4d455201 nmi_s ``arch/mips/include/asm/sn/nmi.h`` +===================== ================ ======================== ========================================== diff --git a/Documentation/translations/ja_JP/process/howto.rst b/Documentation/translations/ja_JP/process/howto.rst index 872876c6789649..d9ba40588e4693 100644 --- a/Documentation/translations/ja_JP/process/howto.rst +++ b/Documentation/translations/ja_JP/process/howto.rst @@ -361,7 +361,7 @@ https://patchwork.kernel.org/ でリストされています。 全サブシステムツリーからほぼ毎日プルされてできる特別なテスト用のリポジ トリが存在します- - https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git + https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git このやり方によって、linux-next は次のマージ機会でどんなものがメイン ラインにマージされるか、おおまかな展望を提供します。 @@ -401,12 +401,12 @@ https://bugzilla.kernel.org でバグ報告を調べようとする人もいる は Linux kernel メーリングリストに参加しています。このリストの登録/脱 退の方法については以下を参照してください- - http://vger.kernel.org/vger-lists.html#linux-kernel + https://subspace.kernel.org/subscribing.html このメーリングリストのアーカイブは web 上の多数の場所に存在します。こ れらのアーカイブを探すにはサーチエンジンを使いましょう。例えば- - https://lore.kernel.org/lkml/ + https://lore.kernel.org/linux-kernel/ リストに投稿する前にすでにその話題がアーカイブに存在するかどうかを検索 することを是非やってください。多数の事がすでに詳細に渡って議論されてお @@ -419,13 +419,13 @@ MAINTAINERS ファイルにリストがありますので参照してくださ 多くのリストは kernel.org でホストされています。これらの情報は以下にあ ります - - http://vger.kernel.org/vger-lists.html + https://subspace.kernel.org メーリングリストを使う場合、良い行動習慣に従うようにしましょう。少し安っ ぽいが、以下の URL は上のリスト(や他のリスト)で会話する場合のシンプル なガイドラインを示しています - - http://www.albion.com/netiquette/ + https://subspace.kernel.org/etiquette.html もし複数の人があなたのメールに返事をした場合、CC: で受ける人のリストは だいぶ多くなるでしょう。正当な理由がない限り、CC: リストから誰かを削除 diff --git a/Documentation/translations/sp_SP/scheduler/index.rst b/Documentation/translations/sp_SP/scheduler/index.rst index 32f9fd7517b278..4ca74f985d2708 100644 --- a/Documentation/translations/sp_SP/scheduler/index.rst +++ b/Documentation/translations/sp_SP/scheduler/index.rst @@ -7,3 +7,4 @@ sched-design-CFS sched-eevdf + sched-bwc diff --git a/Documentation/translations/sp_SP/scheduler/sched-bwc.rst b/Documentation/translations/sp_SP/scheduler/sched-bwc.rst new file mode 100644 index 00000000000000..eec5a127839de4 --- /dev/null +++ b/Documentation/translations/sp_SP/scheduler/sched-bwc.rst @@ -0,0 +1,287 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/scheduler/sched-design-CFS.rst ` +:Translator: Sergio González Collado + +.. _sp_sched_bwc: + +================================= +CFS con control de ancho de banda +================================= + +.. note:: + Este documento únicamente trata el control de ancho de banda de CPUs + para SCHED_NORMAL. El caso de SCHED_RT se trata en Documentation/scheduler/sched-rt-group.rst + +El control de ancho de banda es una extensión CONFIG_FAIR_GROUP_SCHED que +permite especificar el máximo uso disponible de CPU para un grupo o una jerarquía. + +El ancho de banda permitido para un grupo de tareas se especifica usando una +cuota y un periodo. Dentro de un "periodo" (microsegundos), a un grupo +de tareas se le asigna hasta su "cuota" de tiempo de uso de CPU en +microsegundos. Esa cuota es asignada para cada CPU en colas de ejecución +en porciones de tiempo de ejecución en la CPU según los hilos de ejecución +del grupo de tareas van siendo candidatos a ejecutarse. Una vez toda la cuota +ha sido asignada cualquier petición adicional de cuota resultará en esos hilos +de ejecución siendo limitados/estrangulados. Los hilos de ejecución limitados +no serán capaces de ejecutarse de nuevo hasta el siguiente periodo cuando +la cuota sea restablecida. + +La cuota sin asignar de un grupo es monitorizada globalmente, siendo +restablecidas cfs_quota unidades al final de cada periodo. Según los +hilos de ejecución van consumiendo este ancho de banda, este se +transfiere a los "silos" de las cpu-locales en base a la demanda. La +cantidad transferida en cada una de esas actualizaciones es ajustable y +es descrito como un "slice". + +Característica de ráfaga +-------------------------- + +Esta característica toma prestado tiempo ahora, que en un futuro tendrá que +devolver, con el coste de una mayor interferencia hacia los otros usuarios +del sistema. Todo acotado perfectamente. + +El tradicional control de ancho de banda (UP-EDF) es algo como: + + (U = \Sum u_i) <= 1 + +Esto garantiza dos cosas: que cada tiempo límite de ejecución es cumplido +y que el sistema es estable. De todas formas, si U fuese > 1, entonces +por cada segundo de tiempo de reloj de una tarea, tendríamos que +ejecutar más de un segundo y obviamente no se cumpliría con el tiempo +límite de ejecución de la tarea, pero en el siguiente periodo de ejecución +el tiempo límite de la tarea estaría todavía más lejos, y nunca se tendría +tiempo de alcanzar la ejecución, cayendo así en un fallo no acotado. + +La característica de ráfaga implica que el trabajo de una tarea no siempre +consuma totalmente la cuota; esto permite que se pueda describir u_i +como una distribución estadística. + +Por ejemplo, se tiene u_i = {x,e}_i, donde x es el p(95) y x+e p(100) +(el tradicional WCET (WCET:Worst Case Execution Time: son las siglas +en inglés para "peor tiempo de ejecución")). Esto efectivamente permite +a u ser más pequeño, aumentando la eficiencia (podemos ejecutar más +tareas en el sistema), pero al coste de perder el instante límite de +finalización deseado de la tarea, cuando coincidan las peores +probabilidades. De todas formas, si se mantiene la estabilidad, ya que +cada sobre-ejecución se empareja con una infra-ejecución en tanto x esté +por encima de la media. + +Es decir, supóngase que se tienen 2 tareas, ambas específicamente +con p(95), entonces tenemos p(95)*p(95) = 90.25% de probabilidad de +que ambas tareas se ejecuten dentro de su cuota asignada y todo +salga bien. Al mismo tiempo se tiene que p(5)*p(5) = 0.25% de +probabilidad que ambas tareas excedan su cuota de ejecución (fallo +garantizado de su tiempo final de ejecución). En algún punto por +en medio, hay un umbral donde una tarea excede su tiempo límite de +ejecución y la otra no, de forma que se compensan; esto depende de la +función de probabilidad acumulada específica de la tarea. + +Al mismo tiempo, se puede decir que el peor caso de sobrepasar el +tiempo límite de ejecución será \Sum e_i; esto es una retraso acotado +(asumiendo que x+e es de hecho el WCET). + +La interferencia cuando se usa una ráfaga se evalúa por las posibilidades +de fallar en el cumplimiento del tiempo límite y el promedio de WCET. +Los resultados de los tests han mostrado que cuando hay muchos cgroups o +una CPU está infrautilizada, la interferencia es más limitada. Más detalles +se aportan en: https://lore.kernel.org/lkml/5371BD36-55AE-4F71-B9D7-B86DC32E3D2B@linux.alibaba.com/ + +Gestión: +-------- + +Cuota, periodo y ráfaga se gestionan dentro del subsistema de cpu por medio +de cgroupfs. + +.. note:: + Los archivos cgroupfs descritos en esta sección solo se aplican al cgroup + v1. Para cgroup v2, ver :ref:`Documentation/admin-guide/cgroup-v2.rst `. + +- cpu.cfs_quota_us: tiempo de ejecución que se refresca cada periodo (en microsegundos) +- cpu.cfs_period_us: la duración del periodo (en microsegundos) +- cpu.stat: exporta las estadísticas de limitación [explicado a continuación] +- cpu.cfs_burst_us: el máximo tiempo de ejecución acumulado (en microsegundos) + +Los valores por defecto son:: + + cpu.cfs_period_us=100ms + cpu.cfs_quota_us=-1 + cpu.cfs_burst_us=0 + +Un valor de -1 para cpu.cfs_quota_us indica que el grupo no tiene ninguna +restricción de ancho de banda aplicado, ese grupo se describe como un grupo +con ancho de banda sin restringir. Esto representa el comportamiento +tradicional para CFS. + +Asignar cualquier valor (válido) y positivo no menor que cpu.cfs_burst_us +definirá el límite del ancho de banda. La cuota mínima permitida para +la cuota o periodo es 1ms. Hay también un límite superior en la duración del +periodo de 1s. Existen restricciones adicionales cuando los límites de +ancho de banda se usan de manera jerárquica, estos se explican en mayor +detalle más adelante. + +Asignar cualquier valor negativo a cpu.cfs_quota_us eliminará el límite de +ancho de banda y devolverá de nuevo al grupo a un estado sin restricciones. + +Un valor de 0 para cpu.cfs_burst_us indica que el grupo no puede acumular +ningún ancho de banda sin usar. Esto hace que el control del comportamiento +tradicional del ancho de banda para CFS no cambie. Definir cualquier valor +(válido) positivo no mayor que cpu.cfs_quota_us en cpu.cgs_burst_us definirá +el límite con el ancho de banda acumulado no usado. + +Cualquier actualización a las especificaciones del ancho de banda usado +por un grupo resultará en que se deje de limitar si está en un estado +restringido. + +Ajustes globales del sistema +---------------------------- + +Por eficiencia el tiempo de ejecución es transferido en lotes desde una reserva +global y el "silo" de una CPU local. Esto reduce en gran medida la presión +por la contabilidad en grandes sistemas. La cantidad transferida cada vez +que se requiere una actualización se describe como "slice". + +Esto es ajustable vía procfs:: + + /proc/sys/kernel/sched_cfs_bandwidth_slice_us (valor por defecto=5ms) + +Valores de "slice" más grandes reducirán el costo de transferencia, mientras +que valores más pequeños permitirán un control más fino del consumo. + +Estadísticas +------------ + +Las estadísticas del ancho de banda de un grupo se exponen en 5 campos en cpu.stat. + +cpu.stat: + +- nr_periods: Número de intervalos aplicados que han pasado. +- nr_throttled: Número de veces que el grupo ha sido restringido/limitado. +- throttled_time: La duración de tiempo total (en nanosegundos) en las + que las entidades del grupo han sido limitadas. +- nr_bursts: Número de periodos en que ha ocurrido una ráfaga. +- burst_time: Tiempo acumulado (en nanosegundos) en la que una CPU ha + usado más de su cuota en los respectivos periodos. + +Este interfaz es de solo lectura. + +Consideraciones jerárquicas +--------------------------- + +La interfaz refuerza que el ancho de banda de una entidad individual +sea siempre factible, esto es: max(c_i) <= C. De todas maneras, +la sobre-suscripción en el caso agregado está explícitamente permitida +para hacer posible semánticas de conservación de trabajo dentro de una +jerarquia. + + e.g. \Sum (c_i) puede superar C + +[ Donde C es el ancho de banda de el padre, y c_i el de su hijo ] + +Hay dos formas en las que un grupo puede ser limitado: + + a. este consume totalmente su propia cuota en un periodo. + b. la cuota del padre es consumida totalmente en su periodo. + +En el caso b) anterior, incluso si el hijo pudiera tener tiempo de +ejecución restante, este no le será permitido hasta que el tiempo de +ejecución del padre sea actualizado. + +Advertencias sobre el CFS con control de cuota de ancho de banda +---------------------------------------------------------------- + +Una vez una "slice" se asigna a una cpu esta no expira. A pesar de eso todas, +excepto las "slices" menos las de 1ms, puede ser devueltas a la reserva global +si todos los hilos en esa cpu pasan a ser no ejecutables. Esto se configura +en el tiempo de compilación por la variable min_cfs_rq_runtime. Esto es un +ajuste en la eficacia que ayuda a prevenir añadir bloqueos en el candado global. + +El hecho de que las "slices" de una cpu local no expiren tiene como resultado +algunos casos extremos interesantes que debieran ser comprendidos. + +Para una aplicación que es un cgroup y que está limitada en su uso de cpu +es un punto discutible ya que de forma natural consumirá toda su parte +de cuota así como también la totalidad de su cuota en cpu locales en cada +periodo. Como resultado se espera que nr_periods sea aproximadamente igual +a nr_throttled, y que cpuacct.usage se incremente aproximadamente igual +a cfs_quota_us en cada periodo. + +Para aplicaciones que tienen un gran número de hilos de ejecución y que no +estan ligadas a una cpu, este matiz de la no-expiración permite que las +aplicaciones brevemente sobrepasen su cuota límite en la cantidad que +no ha sido usada en cada cpu en la que el grupo de tareas se está ejecutando +(típicamente como mucho 1ms por cada cpu o lo que se ha definido como +min_cfs_rq_runtime). Este pequeño sobreuso únicamente tiene lugar si +la cuota que ha sido asignada a una cpu y no ha sido completamente usada +o devuelta en periodos anteriores. Esta cantidad de sobreuso no será +transferida entre núcleos. Como resultado, este mecanismo todavía cumplirá +estrictamente los límites de la tarea de grupo en el promedio del uso, +pero sobre una ventana de tiempo mayor que un único periodo. Esto +también limita la habilidad de un sobreuso a no más de 1ms por cada cpu. +Esto provee de una experiencia de uso más predecible para aplicaciones +con muchos hilos y con límites de cuota pequeños en máquinas con muchos +núcleos. Esto también elimina la propensión a limitar estas +aplicaciones mientras que simultáneamente usan menores cuotas +de uso por cpu. Otra forma de decir esto es que permitiendo que +la parte no usada de una "slice" permanezca válida entre periodos +disminuye la posibilidad de malgastare cuota que va a expirar en +las reservas de la cpu locales que no necesitan una "slice" completa +de tiempo de ejecución de cpu. + +La interacción entre las aplicaciones ligadas a una CPU y las que no están +ligadas a ninguna cpu ha de ser también considerada, especialmente cuando +un único núcleo tiene un uso del 100%. Si se da a cada una de esas +aplicaciones la mitad de la capacidad de una CPU-núcleo y ambas +están gestionadas en la misma CPU es teóricamente posible que la aplicación +no ligada a ninguna CPU use su 1ms adicional de cuota en algunos periodos, +y por tanto evite que la aplicación ligada a una CPU pueda usar su +cuota completa por esa misma cantidad. En esos caso el algoritmo CFS (vea +sched-design-CFS.rst) el que decida qué aplicación es la elegida para +ejecutarse, ya que ambas serán candidatas a ser ejecutadas y tienen +cuota restante. Esta discrepancia en el tiempo de ejecución se compensará +en los periodos siguientes cuando el sistema esté inactivo. + +Ejemplos +--------- + +1. Un grupo limitado a 1 CPU de tiempo de ejecución. + + Si el periodo son 250ms y la cuota son 250ms el grupo de tareas tendrá el tiempo + de ejecución de 1 CPU cada 250ms:: + + # echo 250000 > cpu.cfs_quota_us /* cuota = 250ms */ + # echo 250000 > cpu.cfs_period_us /* periodo = 250ms */ + +2. Un grupo limitado al tiempo de ejecución de 2 CPUs en una máquina varias CPUs. + + Con un periodo de 500ms y una cuota de 1000ms el grupo de tareas tiene el tiempo + de ejecución de 2 CPUs cada 500ms:: + + # echo 1000000 > cpu.cfs_quota_us /* cuota = 1000ms */ + # echo 500000 > cpu.cfs_period_us /* periodo = 500ms */ + + El periodo más largo aquí permite una capacidad de ráfaga mayor. + +3. Un grupo limitado a un 20% de 1 CPU. + + Con un periodo de 50ms, 10ms de cuota son equivalentes al 20% de 1 CPUs:: + + # echo 10000 > cpu.cfs_quota_us /* cuota = 10ms */ + # echo 50000 > cpu.cfs_period_us /* periodo = 50ms */ + + Usando un periodo pequeño aquí nos aseguramos una respuesta de + la latencia consistente a expensas de capacidad de ráfaga. + +4. Un grupo limitado al 40% de 1 CPU, y permite acumular adicionalmente + hasta un 20% de 1 CPU. + + Con un periodo de 50ms, 20ms de cuota son equivalentes al 40% de + 1 CPU. Y 10ms de ráfaga, son equivalentes a un 20% de 1 CPU:: + + # echo 20000 > cpu.cfs_quota_us /* cuota = 20ms */ + # echo 50000 > cpu.cfs_period_us /* periodo = 50ms */ + # echo 10000 > cpu.cfs_burst_us /* ráfaga = 10ms */ + + Un ajuste mayor en la capacidad de almacenamiento (no mayor que la cuota) + permite una mayor capacidad de ráfaga. + diff --git a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst index 472761938682c0..d4ff80de47b638 100644 --- a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst +++ b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst @@ -87,6 +87,61 @@ PCH-LPC/PCH-MSI,然后被EIOINTC统一收集,再直接到达CPUINTC:: | Devices | +---------+ +虚拟扩展IRQ模型 +=============== + +在这种模型里面, IPI(Inter-Processor Interrupt) 和CPU本地时钟中断直接发送到CPUINTC, +CPU串口 (UARTs) 中断发送到PCH-PIC, 而其他所有设备的中断则分别发送到所连接的PCH_PIC/ +PCH-MSI, 然后V-EIOINTC统一收集,再直接到达CPUINTC:: + + +-----+ +-------------------+ +-------+ + | IPI |--> | CPUINTC(0-255vcpu)| <-- | Timer | + +-----+ +-------------------+ +-------+ + ^ + | + +-----------+ + | V-EIOINTC | + +-----------+ + ^ ^ + | | + +---------+ +---------+ + | PCH-PIC | | PCH-MSI | + +---------+ +---------+ + ^ ^ ^ + | | | + +--------+ +---------+ +---------+ + | UARTs | | Devices | | Devices | + +--------+ +---------+ +---------+ + +V-EIOINTC 是EIOINTC的扩展, 仅工作在虚拟机模式下, 中断经EIOINTC最多可个路由到 +4个虚拟CPU. 但中断经V-EIOINTC最多可个路由到256个虚拟CPU. + +传统的EIOINTC中断控制器,中断路由分为两个部分:8比特用于控制路由到哪个CPU, +4比特用于控制路由到特定CPU的哪个中断管脚。控制CPU路由的8比特前4比特用于控制 +路由到哪个EIOINTC节点,后4比特用于控制此节点哪个CPU。中断路由在选择CPU路由 +和CPU中断管脚路由时,使用bitmap编码方式而不是正常编码方式,所以对于一个 +EIOINTC中断控制器节点,中断只能路由到CPU0 - CPU3,中断管脚IP0-IP3。 + +V-EIOINTC新增了两个寄存器,支持中断路由到更多CPU个和中断管脚。 + +V-EIOINTC功能寄存器 +------------------- +功能寄存器是只读寄存器,用于显示V-EIOINTC支持的特性,目前两个支持两个特性 +EXTIOI_HAS_INT_ENCODE 和 EXTIOI_HAS_CPU_ENCODE。 + +特性EXTIOI_HAS_INT_ENCODE是传统EIOINTC中断控制器的一个特性,如果此比特为1, +显示CPU中断管脚路由方式支持正常编码,而不是bitmap编码,所以中断可以路由到 +管脚IP0 - IP15。 + +特性EXTIOI_HAS_CPU_ENCODE是V-EIOINTC新增特性,如果此比特为1,表示CPU路由 +方式支持正常编码,而不是bitmap编码,所以中断可以路由到CPU0 - CPU255。 + +V-EIOINTC配置寄存器 +------------------- +配置寄存器是可读写寄存器,为了兼容性考虑,如果不写此寄存器,中断路由采用 +和传统EIOINTC相同的路由设置。如果对应比特设置为1,表示采用正常路由方式而 +不是bitmap编码的路由方式。 + 高级扩展IRQ模型 =============== diff --git a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst index bb16f0611046d3..b1bec219912d5a 100644 --- a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst +++ b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst @@ -48,7 +48,7 @@ 要是一个预处理器符号。例如,要把符号 ``usb_stor_suspend`` 导出到命名空间 ``USB_STORAGE``, 请使用:: - EXPORT_SYMBOL_NS(usb_stor_suspend, USB_STORAGE); + EXPORT_SYMBOL_NS(usb_stor_suspend, "USB_STORAGE"); 相应的 ksymtab 条目结构体 ``kernel_symbol`` 将有相应的成员 ``命名空间`` 集。 导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。 @@ -66,7 +66,7 @@ 子系统的 ``Makefile`` 中定义默认命名空间。例如,如果要将usb-common中定义的所有符号导 出到USB_COMMON命名空间,可以在drivers/usb/common/Makefile中添加这样一行:: - ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_COMMON + ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"USB_COMMON"' 这将影响所有 EXPORT_SYMBOL() 和 EXPORT_SYMBOL_GPL() 语句。当这个定义存在时, 用EXPORT_SYMBOL_NS()导出的符号仍然会被导出到作为命名空间参数传递的命名空间中, @@ -76,7 +76,7 @@ 成:: #undef DEFAULT_SYMBOL_NAMESPACE - #define DEFAULT_SYMBOL_NAMESPACE USB_COMMON + #define DEFAULT_SYMBOL_NAMESPACE "USB_COMMON" 应置于相关编译单元中任何 EXPORT_SYMBOL 宏之前 @@ -88,7 +88,7 @@ 表示它所使用的命名空间的符号。例如,一个使用usb_stor_suspend符号的 模块,需要使用如下语句导入命名空间USB_STORAGE:: - MODULE_IMPORT_NS(USB_STORAGE); + MODULE_IMPORT_NS("USB_STORAGE"); 这将在模块中为每个导入的命名空间创建一个 ``modinfo`` 标签。这也顺带 使得可以用modinfo检查模块已导入的命名空间:: diff --git a/Documentation/translations/zh_CN/dev-tools/gcov.rst b/Documentation/translations/zh_CN/dev-tools/gcov.rst index 3158c9da13185a..ea8f94852f417c 100644 --- a/Documentation/translations/zh_CN/dev-tools/gcov.rst +++ b/Documentation/translations/zh_CN/dev-tools/gcov.rst @@ -120,7 +120,7 @@ gcov的内核分析插桩支持内核的编译和运行是在同一台机器上 如果内核编译和运行是不同的机器,那么需要额外的准备工作,这取决于gcov工具 是在哪里使用的: -.. _gcov-test_zh: +.. _gcov-test_zh_CN: a) 若gcov运行在测试机上 @@ -140,7 +140,7 @@ a) 若gcov运行在测试机上 如果文件是软链接,需要替换成真正的目录文件(这是由make的当前工作 目录变量CURDIR引起的)。 -.. _gcov-build_zh: +.. _gcov-build_zh_CN: b) 若gcov运行在编译机上 @@ -205,7 +205,7 @@ kconfig会根据编译工具链的检查自动选择合适的gcov格式。 -------------------------- 用于在编译机上收集覆盖率元文件的示例脚本 -(见 :ref:`编译机和测试机分离 a. ` ) +(见 :ref:`编译机和测试机分离 a. ` ) .. code-block:: sh @@ -238,7 +238,7 @@ kconfig会根据编译工具链的检查自动选择合适的gcov格式。 ------------------------- 用于在测试机上收集覆盖率数据文件的示例脚本 -(见 :ref:`编译机和测试机分离 b. ` ) +(见 :ref:`编译机和测试机分离 b. ` ) .. code-block:: sh diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst index 6a8c637c0be147..7b37194217b031 100644 --- a/Documentation/translations/zh_CN/dev-tools/index.rst +++ b/Documentation/translations/zh_CN/dev-tools/index.rst @@ -22,6 +22,7 @@ Documentation/translations/zh_CN/dev-tools/testing-overview.rst sparse kcov kcsan + kmsan gcov kasan ubsan @@ -32,7 +33,6 @@ Todolist: - checkpatch - coccinelle - - kmsan - kfence - kgdb - kselftest diff --git a/Documentation/translations/zh_CN/dev-tools/kasan.rst b/Documentation/translations/zh_CN/dev-tools/kasan.rst index 4491ad2830ed9e..fd2e3afbdfad0b 100644 --- a/Documentation/translations/zh_CN/dev-tools/kasan.rst +++ b/Documentation/translations/zh_CN/dev-tools/kasan.rst @@ -422,16 +422,12 @@ KASAN连接到vmap基础架构以懒清理未使用的影子内存。 ~~~~ 有一些KASAN测试可以验证KASAN是否正常工作并可以检测某些类型的内存损坏。 -测试由两部分组成: -1. 与KUnit测试框架集成的测试。使用 ``CONFIG_KASAN_KUNIT_TEST`` 启用。 -这些测试可以通过几种不同的方式自动运行和部分验证;请参阅下面的说明。 +所有 KASAN 测试都与 KUnit 测试框架集成,可通过 ``CONFIG_KASAN_KUNIT_TEST`` 启用。 +测试可以通过几种不同的方式自动运行和部分验证;请参阅以下说明。 -2. 与KUnit不兼容的测试。使用 ``CONFIG_KASAN_MODULE_TEST`` 启用并且只能作为模块 -运行。这些测试只能通过加载内核模块并检查内核日志以获取KASAN报告来手动验证。 - -如果检测到错误,每个KUnit兼容的KASAN测试都会打印多个KASAN报告之一,然后测试打印 -其编号和状态。 +如果检测到错误,每个 KASAN 测试都会打印多份 KASAN 报告中的一份。 +然后测试会打印其编号和状态。 当测试通过:: @@ -458,16 +454,16 @@ KASAN连接到vmap基础架构以懒清理未使用的影子内存。 not ok 1 - kasan -有几种方法可以运行与KUnit兼容的KASAN测试。 +有几种方法可以运行 KASAN 测试。 1. 可加载模块 - 启用 ``CONFIG_KUNIT`` 后,KASAN-KUnit测试可以构建为可加载模块,并通过使用 - ``insmod`` 或 ``modprobe`` 加载 ``kasan_test.ko`` 来运行。 + 启用 ``CONFIG_KUNIT`` 后,可以将测试构建为可加载模块 + 并通过使用 ``insmod`` 或 ``modprobe`` 加载 ``kasan_test.ko`` 来运行。 2. 内置 - 通过内置 ``CONFIG_KUNIT`` ,也可以内置KASAN-KUnit测试。在这种情况下, + 通过内置 ``CONFIG_KUNIT``,测试也可以内置。 测试将在启动时作为后期初始化调用运行。 3. 使用kunit_tool diff --git a/Documentation/translations/zh_CN/dev-tools/kmsan.rst b/Documentation/translations/zh_CN/dev-tools/kmsan.rst new file mode 100644 index 00000000000000..b1ddb47bd6c488 --- /dev/null +++ b/Documentation/translations/zh_CN/dev-tools/kmsan.rst @@ -0,0 +1,392 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/dev-tools/kmsan.rst +:Translator: 刘浩阳 Haoyang Liu + +======================= +内核内存消毒剂(KMSAN) +======================= + +KMSAN 是一个动态错误检测器,旨在查找未初始化值的使用。它基于编译器插桩,类似于用 +户空间的 `MemorySanitizer tool`_。 + +需要注意的是 KMSAN 并不适合生产环境,因为它会大幅增加内核内存占用并降低系统运行速度。 + +使用方法 +======== + +构建内核 +-------- + +要构建带有 KMSAN 的内核,你需要一个较新的 Clang (14.0.6+)。 +请参阅 `LLVM documentation`_ 了解如何构建 Clang。 + +现在配置并构建一个启用 CONFIG_KMSAN 的内核。 + +示例报告 +-------- + +以下是一个 KMSAN 报告的示例:: + + ===================================================== + BUG: KMSAN: uninit-value in test_uninit_kmsan_check_memory+0x1be/0x380 [kmsan_test] + test_uninit_kmsan_check_memory+0x1be/0x380 mm/kmsan/kmsan_test.c:273 + kunit_run_case_internal lib/kunit/test.c:333 + kunit_try_run_case+0x206/0x420 lib/kunit/test.c:374 + kunit_generic_run_threadfn_adapter+0x6d/0xc0 lib/kunit/try-catch.c:28 + kthread+0x721/0x850 kernel/kthread.c:327 + ret_from_fork+0x1f/0x30 ??:? + + Uninit was stored to memory at: + do_uninit_local_array+0xfa/0x110 mm/kmsan/kmsan_test.c:260 + test_uninit_kmsan_check_memory+0x1a2/0x380 mm/kmsan/kmsan_test.c:271 + kunit_run_case_internal lib/kunit/test.c:333 + kunit_try_run_case+0x206/0x420 lib/kunit/test.c:374 + kunit_generic_run_threadfn_adapter+0x6d/0xc0 lib/kunit/try-catch.c:28 + kthread+0x721/0x850 kernel/kthread.c:327 + ret_from_fork+0x1f/0x30 ??:? + + Local variable uninit created at: + do_uninit_local_array+0x4a/0x110 mm/kmsan/kmsan_test.c:256 + test_uninit_kmsan_check_memory+0x1a2/0x380 mm/kmsan/kmsan_test.c:271 + + Bytes 4-7 of 8 are uninitialized + Memory access of size 8 starts at ffff888083fe3da0 + + CPU: 0 PID: 6731 Comm: kunit_try_catch Tainted: G B E 5.16.0-rc3+ #104 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 + ===================================================== + +报告指出本地变量 ``uninit`` 在 ``do_uninit_local_array()`` 中未初始化。 +第三个堆栈跟踪对应于该变量创建的位置。 + +第一个堆栈跟踪显示了未初始化值的使用位置(在 +``test_uninit_kmsan_check_memory()``)。 +工具显示了局部变量中未初始化的字节及其被复制到其他内存位置前的堆栈。 + +KMSAN 会在以下情况下报告未初始化的值 ``v``: + + - 在条件判断中,例如 ``if (v) { ... }``; + - 在索引或指针解引用中,例如 ``array[v]`` 或 ``*v``; + - 当它被复制到用户空间或硬件时,例如 ``copy_to_user(..., &v, ...)``; + - 当它作为函数参数传递,并且启用 ``CONFIG_KMSAN_CHECK_PARAM_RETVAL`` 时(见下文)。 + +这些情况(除了复制数据到用户空间或硬件外,这是一个安全问题)被视为 C11 标准下的未定义行为。 + +禁用插桩 +-------- + +可以用 ``__no_kmsan_checks`` 标记函数。这样,KMSAN 会忽略该函数中的未初始化值, +并将其输出标记为已初始化。如此,用户不会收到与该函数相关的 KMSAN 报告。 + +KMSAN 还支持 ``__no_sanitize_memory`` 函数属性。KMSAN 不会对拥有该属性的函数进行 +插桩,这在我们不希望编译器干扰某些底层代码(例如标记为 ``noinstr`` 的代码,该 +代码隐式添加了 ``__no_sanitize_memory``)时可能很有用。 + +然而,这会有代价:此类函数的栈分配将具有不正确的影子/初始值,可能导致误报。来 +自非插桩代码的函数也可能接收到不正确的元数据。 + + +作为经验之谈,避免显式使用 ``__no_sanitize_memory``。 + +也可以通过 Makefile 禁用 KMSAN 对某个文件(例如 main.o)的作用:: + + KMSAN_SANITIZE_main.o := n + +或者对整个目录:: + + KMSAN_SANITIZE := n + +将其应用到文件或目录中的每个函数。大多数用户不会需要 KMSAN_SANITIZE, +除非他们的代码被 KMSAN 破坏(例如在早期启动时运行的代码)。 + +还可以通过调用 ``kmsan_disable_current()`` 和 ``kmsan_enable_current()`` +暂时对当前任务禁用 KMSAN 检查。每个 ``kmsan_enable_current()`` 必须在 +``kmsan_disable_current()`` 之后调用;这些调用对可以嵌套。在调用时需要注意保持 +嵌套区域简短,并且尽可能使用其他方法禁用插桩。 + +支持 +==== + +为了使用 KMSAN,内核必须使用 Clang 构建,到目前为止,Clang 是唯一支持 KMSAN +的编译器。内核插桩过程基于用户空间的 `MemorySanitizer tool`_。 + +目前运行时库仅支持 x86_64 架构。 + +KMSAN 的工作原理 +================ + +KMSAN 阴影内存 +-------------- + +KMSAN 将一个元数据字节(也称为阴影字节)与每个内核内存字节关联。仅当内核内存字节 +的相应位未初始化时,阴影字节中的一个比特位才会被设置。将内存标记为未初始化(即 +将其阴影字节设置为 ``0xff``)称为中毒,将其标记为已初始化(将阴影字节设置为 +``0x00``)称为解毒。 + +当在栈上分配新变量时,默认情况下它会中毒,这由编译器插入的插桩代码完成(除非它 +是立即初始化的栈变量)。任何未使用 ``__GFP_ZERO`` 的堆分配也会中毒。 + +编译器插桩还跟踪阴影值在代码中的使用。当需要时,插桩代码会调用 ``mm/kmsan/`` 中 +的运行时库以持久化阴影值。 + +基本或复合类型的阴影值是长度相同的字节数组。当常量值写入内存时,该内存会被解毒 +。当从内存读取值时,其阴影内存也会被获取,并传递到所有使用该值的操作中。对于每 +个需要一个或多个值的指令,编译器会生成代码根据这些值及其阴影来计算结果的阴影。 + + +示例:: + + int a = 0xff; // i.e. 0x000000ff + int b; + int c = a | b; + +在这种情况下, ``a`` 的阴影为 ``0``, ``b`` 的阴影为 ``0xffffffff``, +``c`` 的阴影为 ``0xffffff00``。这意味着 ``c`` 的高三个字节未初始化,而低字节已 +初始化。 + +起源跟踪 +-------- + +每四字节的内核内存都有一个所谓的源点与之映射。这个源点描述了在程序执行中,未初 +始化值的创建点。每个源点都与完整的分配栈(对于堆分配的内存)或包含未初始化变 +量的函数(对于局部变量)相关联。 + +当一个未初始化的变量在栈或堆上分配时,会创建一个新的源点值,并将该变量的初始值 +填充为这个值。当从内存中读取一个值时,其初始值也会被读取并与阴影一起保留。对于 +每个接受一个或多个值的指令,结果的源点是与任何未初始化输入相对应的源点之一。如 +果一个污染值被写入内存,其起源也会被写入相应的存储中。 + +示例 1:: + + int a = 42; + int b; + int c = a + b; + +在这种情况下, ``b`` 的源点是在函数入口时生成的,并在加法结果写入内存之前存储到 +``c`` 的源点中。 + +如果几个变量共享相同的源点地址,则它们被存储在同一个四字节块中。在这种情况下, +对任何变量的每次写入都会更新所有变量的源点。在这种情况下我们必须牺牲精度,因 +为为单独的位(甚至字节)存储源点成本过高。 + +示例 2:: + + int combine(short a, short b) { + union ret_t { + int i; + short s[2]; + } ret; + ret.s[0] = a; + ret.s[1] = b; + return ret.i; + } + +如果 ``a`` 已初始化而 ``b`` 未初始化,则结果的阴影为 0xffff0000,结果的源点为 +``b`` 的源点。 ``ret.s[0]`` 会有相同的起源,但它不会被使用,因为该变量已初始化。 + +如果两个函数参数都未初始化,则只保留第二个参数的源点。 + +源点链 +~~~~~~ + +为了便于调试,KMSAN 在每次将未初始化值存储到内存时都会创建一个新的源点。新的源点 +引用了其创建栈以及值的前一个起源。这可能导致内存消耗增加,因此我们在运行时限制 +了源点链的长度。 + +Clang 插桩 API +-------------- + +Clang 插桩通过在内核代码中插入定义在 ``mm/kmsan/instrumentation.c`` 中的函数调用 +来实现。 + + +阴影操作 +~~~~~~~~ + +对于每次内存访问,编译器都会发出一个函数调用,该函数返回一对指针,指向给定内存 +的阴影和原始地址:: + + typedef struct { + void *shadow, *origin; + } shadow_origin_ptr_t + + shadow_origin_ptr_t __msan_metadata_ptr_for_load_{1,2,4,8}(void *addr) + shadow_origin_ptr_t __msan_metadata_ptr_for_store_{1,2,4,8}(void *addr) + shadow_origin_ptr_t __msan_metadata_ptr_for_load_n(void *addr, uintptr_t size) + shadow_origin_ptr_t __msan_metadata_ptr_for_store_n(void *addr, uintptr_t size) + +函数名依赖于内存访问的大小。 + +编译器确保对于每个加载的值,其阴影和原始值都从内存中读取。当一个值存储到内存时 +,其阴影和原始值也会通过元数据指针进行存储。 + +处理局部变量 +~~~~~~~~~~~~ + +一个特殊的函数用于为局部变量创建一个新的原始值,并将该变量的原始值设置为该值:: + + void __msan_poison_alloca(void *addr, uintptr_t size, char *descr) + +访问每个任务数据 +~~~~~~~~~~~~~~~~ + +在每个插桩函数的开始处,KMSAN 插入一个对 ``__msan_get_context_state()`` 的调用 +:: + + kmsan_context_state *__msan_get_context_state(void) + +``kmsan_context_state`` 在 ``include/linux/kmsan.h`` 中声明:: + + struct kmsan_context_state { + char param_tls[KMSAN_PARAM_SIZE]; + char retval_tls[KMSAN_RETVAL_SIZE]; + char va_arg_tls[KMSAN_PARAM_SIZE]; + char va_arg_origin_tls[KMSAN_PARAM_SIZE]; + u64 va_arg_overflow_size_tls; + char param_origin_tls[KMSAN_PARAM_SIZE]; + depot_stack_handle_t retval_origin_tls; + }; + +KMSAN 使用此结构体在插桩函数之间传递参数阴影和原始值(除非立刻通过 + ``CONFIG_KMSAN_CHECK_PARAM_RETVAL`` 检查参数)。 + +将未初始化的值传递给函数 +~~~~~~~~~~~~~~~~~~~~~~~~ + +Clang 的 MemorySanitizer 插桩有一个选项 ``-fsanitize-memory-param-retval``,该 +选项使编译器检查按值传递的函数参数,以及函数返回值。 + +该选项由 ``CONFIG_KMSAN_CHECK_PARAM_RETVAL`` 控制,默认启用以便 KMSAN 更早报告 +未初始化的值。有关更多细节,请参考 `LKML discussion`_。 + +由于 LLVM 中的实现检查的方式(它们仅应用于标记为 ``noundef`` 的参数),并不是所 +有参数都能保证被检查,因此我们不能放弃 ``kmsan_context_state`` 中的元数据存储 +。 + +字符串函数 +~~~~~~~~~~~ + +编译器将对 ``memcpy()``/``memmove()``/``memset()`` 的调用替换为以下函数。这些函 +数在数据结构初始化或复制时也会被调用,确保阴影和原始值与数据一起复制:: + + void *__msan_memcpy(void *dst, void *src, uintptr_t n) + void *__msan_memmove(void *dst, void *src, uintptr_t n) + void *__msan_memset(void *dst, int c, uintptr_t n) + +错误报告 +~~~~~~~~ + +对于每个值的使用,编译器发出一个阴影检查,在值中毒的情况下调用 +``__msan_warning()``:: + + void __msan_warning(u32 origin) + +``__msan_warning()`` 使 KMSAN 运行时打印错误报告。 + +内联汇编插桩 +~~~~~~~~~~~~ + +KMSAN 对每个内联汇编输出进行插桩,调用:: + + void __msan_instrument_asm_store(void *addr, uintptr_t size) + +,该函数解除内存区域的污染。 + +这种方法可能会掩盖某些错误,但也有助于避免许多位操作、原子操作等中的假阳性。 + +有时传递给内联汇编的指针不指向有效内存。在这种情况下,它们在运行时被忽略。 + + +运行时库 +-------- + +代码位于 ``mm/kmsan/``。 + +每个任务 KMSAN 状态 +~~~~~~~~~~~~~~~~~~~ + +每个 task_struct 都有一个关联的 KMSAN 任务状态,它保存 KMSAN +上下文(见上文)和一个每个任务计数器以禁止 KMSAN 报告:: + + struct kmsan_context { + ... + unsigned int depth; + struct kmsan_context_state cstate; + ... + } + + struct task_struct { + ... + struct kmsan_context kmsan; + ... + } + +KMSAN 上下文 +~~~~~~~~~~~~ + +在内核任务上下文中运行时,KMSAN 使用 ``current->kmsan.cstate`` 来 +保存函数参数和返回值的元数据。 + +但在内核运行于中断、softirq 或 NMI 上下文中, ``current`` 不可用时, +KMSAN 切换到每 CPU 中断状态:: + + DEFINE_PER_CPU(struct kmsan_ctx, kmsan_percpu_ctx); + +元数据分配 +~~~~~~~~~~ + +内核中有多个地方存储元数据。 + +1. 每个 ``struct page`` 实例包含两个指向其影子和内存页面的指针 +:: + + struct page { + ... + struct page *shadow, *origin; + ... + }; + +在启动时,内核为每个可用的内核页面分配影子和源页面。这是在内核地址空间已经碎片 +化时后完成的,完成的相当晚,因此普通数据页面可能与元数据页面任意交错。 + +这意味着通常两个相邻的内存页面,它们的影子/源页面可能不是连续的。因此,如果内存 +访问跨越内存块的边界,访问影子/源内存可能会破坏其他页面或从中读取错误的值。 + +实际上,由相同 ``alloc_pages()`` 调用返回的连续内存页面将具有连续的元数据,而 +如果这些页面属于两个不同的分配,它们的元数据页面可能会被碎片化。 + +对于内核数据( ``.data``、 ``.bss`` 等)和每 CPU 内存区域,也没有对元数据连续 +性的保证。 + +在 ``__msan_metadata_ptr_for_XXX_YYY()`` 遇到两个页面之间的 +非连续元数据边界时,它返回指向假影子/源区域的指针:: + + char dummy_load_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); + char dummy_store_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); + +``dummy_load_page`` 被初始化为零,因此读取它始终返回零。对 ``dummy_store_page`` 的 +所有写入都被忽略。 + +2. 对于 vmalloc 内存和模块,内存范围、影子和源之间有一个直接映射。KMSAN 将 +vmalloc 区域缩小了 3/4,仅使前四分之一可用于 ``vmalloc()``。vmalloc +区域的第二个四分之一包含第一个四分之一的影子内存,第三个四分之一保存源。第四个 +四分之一的小部分包含内核模块的影子和源。有关更多详细信息,请参阅 +``arch/x86/include/asm/pgtable_64_types.h``。 + +当一系列页面映射到一个连续的虚拟内存空间时,它们的影子和源页面也以连续区域的方 +式映射。 + +参考文献 +======== + +E. Stepanov, K. Serebryany. `MemorySanitizer: fast detector of uninitialized +memory use in C++ +`_. +In Proceedings of CGO 2015. + +.. _MemorySanitizer tool: https://clang.llvm.org/docs/MemorySanitizer.html +.. _LLVM documentation: https://llvm.org/docs/GettingStarted.html +.. _LKML discussion: https://lore.kernel.org/all/20220614144853.3693273-1-glider@google.com/ diff --git a/Documentation/translations/zh_CN/glossary.rst b/Documentation/translations/zh_CN/glossary.rst index 24f094df97cdc0..5975b0426f3db0 100644 --- a/Documentation/translations/zh_CN/glossary.rst +++ b/Documentation/translations/zh_CN/glossary.rst @@ -34,3 +34,4 @@ * semaphores: 信号量。 * spinlock: 自旋锁。 * watermark: 水位,一般指页表的消耗水平。 +* PTE: 页表项。(Page Table Entry) diff --git a/Documentation/translations/zh_CN/kbuild/index.rst b/Documentation/translations/zh_CN/kbuild/index.rst index b51655d981f692..3f9ab52fa5bb6a 100644 --- a/Documentation/translations/zh_CN/kbuild/index.rst +++ b/Documentation/translations/zh_CN/kbuild/index.rst @@ -12,20 +12,21 @@ .. toctree:: :maxdepth: 1 + kconfig headers_install gcc-plugins + kbuild + reproducible-builds + llvm TODO: - kconfig-language - kconfig-macro-language -- kbuild -- kconfig - makefiles - modules - issues -- reproducible-builds -- llvm + .. only:: subproject and html diff --git a/Documentation/translations/zh_CN/kbuild/kbuild.rst b/Documentation/translations/zh_CN/kbuild/kbuild.rst new file mode 100644 index 00000000000000..e5e2aebe1ebc84 --- /dev/null +++ b/Documentation/translations/zh_CN/kbuild/kbuild.rst @@ -0,0 +1,304 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/kbuild/kbuild.rst +:Translator: 慕冬亮 Dongliang Mu + +====== +Kbuild +====== + + +输出文件 +======== + +modules.order +------------- +该文件记录模块在 Makefile 中出现的顺序。modprobe 使用该文件来确定性 +解析匹配多个模块的别名。 + +modules.builtin +--------------- +该文件列出了所有内置到内核中的模块。modprobe 使用该文件来避免尝试加载 +内置模块时出错。 + +modules.builtin.modinfo +----------------------- +该文件包含所有内置模块的 modinfo。与单独模块的 modinfo 不同,所有字段 +都带有模块名称前缀。 + +modules.builtin.ranges +---------------------- +该文件包含所有内核内置模块的地址偏移范围(每个 ELF 节)。结合 System.map +文件,它可以用来将模块名称与符号关联起来。 + +环境变量 +======== + +KCPPFLAGS +--------- +在预处理时传递的额外选项。kbuild 进行所有预处理(包括构建 C 文件和汇编文件) +时,都会使用这些预处理选项。 + +KAFLAGS +------- +传递给汇编器的额外选项(适用于内置模块和外部模块)。 + +AFLAGS_MODULE +------------- +外部模块的额外汇编选项。 + +AFLAGS_KERNEL +------------- +内置模块的额外汇编选项。 + +KCFLAGS +------- +传递给 C 编译器的额外选项(适用于内置模块和外部模块)。 + +KRUSTFLAGS +---------- +传递给 Rust 编译器的额外选项(适用于内置模块和外部模块)。 + +CFLAGS_KERNEL +------------- +在编译内置代码时,传递给 $(CC) 的额外选项。 + +CFLAGS_MODULE +------------- +编译外部模块时,传递给 $(CC) 的额外模块特定选项。 + +RUSTFLAGS_KERNEL +---------------- +在编译内置代码时,传递给 $(RUSTC) 的额外选项。 + +RUSTFLAGS_MODULE +---------------- +用于 $(RUSTC) 的额外模块特定选项。 + +LDFLAGS_MODULE +-------------- +用于 $(LD) 链接模块时的额外选项。 + +HOSTCFLAGS +---------- +在构建主机程序时传递给 $(HOSTCC) 的额外标志。 + +HOSTCXXFLAGS +------------ +在构建主机程序时传递给 $(HOSTCXX) 的额外标志。 + +HOSTRUSTFLAGS +------------- +在构建主机程序时传递给 $(HOSTRUSTC) 的额外标志。 + +HOSTLDFLAGS +----------- +链接主机程序时传递的额外选项。 + +HOSTLDLIBS +---------- +在构建主机程序时链接的额外库。 + +.. _zh_cn_userkbuildflags: + +USERCFLAGS +---------- +用于 $(CC) 编译用户程序(userprogs)时的额外选项。 + +USERLDFLAGS +----------- +用于 $(LD) 链接用户程序时的额外选项。用户程序(userprogs)是使用 CC 链接的, +因此 $(USERLDFLAGS) 应该根据需要包含 "-Wl," 前缀。 + +KBUILD_KCONFIG +-------------- +将顶级 Kconfig 文件设置为此环境变量的值。默认名称为 "Kconfig"。 + +KBUILD_VERBOSE +-------------- +设置 kbuild 的详细程度。可以分配与 "V=..." 相同的值。 + +有关完整列表,请参见 `make help`。 + +设置 "V=..." 优先于 KBUILD_VERBOSE。 + +KBUILD_EXTMOD +------------- +在构建外部模块时设置内核源代码的搜索目录。 + +设置 "M=..." 优先于 KBUILD_EXTMOD。 + +KBUILD_OUTPUT +------------- +指定内核构建的输出目录。 + +在单独的构建目录中为预构建内核构建外部模块时,这个变量也可以指向内核输出目录。请注意, +这并不指定外部模块本身的输出目录。 + +输出目录也可以使用 "O=..." 指定。 + +设置 "O=..." 优先于 KBUILD_OUTPUT。 + +KBUILD_EXTRA_WARN +----------------- +指定额外的构建检查。也可以通过在命令行传递 "W=..." 来设置相同的值。 + +请参阅 `make help` 了解支持的值列表。 + +设置 "W=..." 优先于 KBUILD_EXTRA_WARN。 + +KBUILD_DEBARCH +-------------- +对于 deb-pkg 目标,允许覆盖 deb-pkg 部署的正常启发式方法。通常 deb-pkg 尝试根据 +UTS_MACHINE 变量(在某些架构中还包括内核配置)来猜测正确的架构。KBUILD_DEBARCH +的值假定(不检查)为有效的 Debian 架构。 + +KDOCFLAGS +--------- +指定在构建过程中用于 kernel-doc 检查的额外(警告/错误)标志,查看 +scripts/kernel-doc 了解支持的标志。请注意,这目前不适用于文档构建。 + +ARCH +---- +设置 ARCH 为要构建的架构。 + +在大多数情况下,架构的名称与 arch/ 目录中的子目录名称相同。 + +但某些架构(如 x86 和 sparc)有别名。 + +- x86: i386 表示 32 位,x86_64 表示 64 位 +- parisc: parisc64 表示 64 位 +- sparc: sparc32 表示 32 位,sparc64 表示 64 位 + +CROSS_COMPILE +------------- +指定 binutils 文件名的可选固定部分。CROSS_COMPILE 可以是文件名的一部分或完整路径。 + +在某些设置中,CROSS_COMPILE 也用于 ccache。 + +CF +-- +用于 sparse 的额外选项。 + +CF 通常在命令行中如下所示使用:: + + make CF=-Wbitwise C=2 + +INSTALL_PATH +------------ +INSTALL_PATH 指定放置更新后的内核和系统映像的路径。默认值是 /boot,但你可以设置 +为其他值。 + +INSTALLKERNEL +------------- +使用 "make install" 时调用的安装脚本。 +默认名称是 "installkernel"。 + +该脚本将会以以下参数调用: + + - $1 - 内核版本 + - $2 - 内核映像文件 + - $3 - 内核映射文件 + - $4 - 默认安装路径(如果为空,则使用根目录) + +"make install" 的实现是架构特定的,可能与上述有所不同。 + +提供 INSTALLKERNEL 以便在交叉编译内核时可以指定自定义安装程序。 + +MODLIB +------ +指定模块的安装位置。 +默认值为:: + + $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) + +该值可以被覆盖,在这种情况下将忽略默认值。 + +INSTALL_MOD_PATH +---------------- +INSTALL_MOD_PATH 指定了模块目录重定位时 MODLIB 的前缀,通常由构建根 +(build roots)所需。它没有在 makefile 中定义,但如果需要,可以作为 +参数传递给 make。 + +INSTALL_MOD_STRIP +----------------- +如果 INSTALL_MOD_STRIP 被定义,内核模块在安装后会被剥离。如果 +INSTALL_MOD_STRIP 的值为 '1',则会使用默认选项 --strip-debug。否则, +INSTALL_MOD_STRIP 的值将作为 strip 命令的选项。 + +INSTALL_HDR_PATH +---------------- +INSTALL_HDR_PATH 指定了执行 "make headers_*" 时,用户空间头文件的安装位置。 + +默认值为:: + + $(objtree)/usr + +$(objtree) 是保存输出文件的目录。 +输出目录通常使用命令行中的 "O=..." 进行设置。 + +该值可以被覆盖,在这种情况下将忽略默认值。 + +INSTALL_DTBS_PATH +----------------- +INSTALL_DTBS_PATH 指定了设备树二进制文件的安装位置,通常由构建根(build roots)所需。 +它没有在 makefile 中定义,但如果需要,可以作为参数传递给 make。 + +KBUILD_ABS_SRCTREE +-------------------------------------------------- +Kbuild 在可能的情况下使用相对路径指向源代码树。例如,在源代码树中构建时,源代码树路径是 +'.'。 + +设置该标志请求 Kbuild 使用源代码树的绝对路径。 +在某些情况下这是有用的,例如在生成带有绝对路径条目的标签文件时等。 + +KBUILD_SIGN_PIN +--------------- +当签署内核模块时,如果私钥需要密码或 PIN,此变量允许将密码或 PIN 传递给 sign-file 工具。 + +KBUILD_MODPOST_WARN +------------------- +KBUILD_MODPOST_WARN 可以设置为在最终模块链接阶段出现未定义符号时避免错误。它将这些错误 +转为警告。 + +KBUILD_MODPOST_NOFINAL +---------------------- +KBUILD_MODPOST_NOFINAL 可以设置为跳过模块的最终链接。这仅在加速编译测试时有用。 + +KBUILD_EXTRA_SYMBOLS +-------------------- +用于依赖其他模块符号的模块。详见 modules.rst。 + +ALLSOURCE_ARCHS +--------------- +对于 tags/TAGS/cscope 目标,可以指定包含在数据库中的多个架构,用空格分隔。例如:: + + $ make ALLSOURCE_ARCHS="x86 mips arm" tags + +要获取所有可用架构,也可以指定 all。例如:: + + $ make ALLSOURCE_ARCHS=all tags + +IGNORE_DIRS +----------- +对于 tags/TAGS/cscope 目标,可以选择不包含在数据库中的目录,用空格分隔。例如:: + + $ make IGNORE_DIRS="drivers/gpu/drm/radeon tools" cscope + +KBUILD_BUILD_TIMESTAMP +---------------------- +将该环境变量设置为日期字符串,可以覆盖在 UTS_VERSION 定义中使用的时间戳 +(运行内核时的 uname -v)。该值必须是一个可以传递给 date -d 的字符串。默认值是 +内核构建某个时刻的 date 命令输出。 + +KBUILD_BUILD_USER, KBUILD_BUILD_HOST +------------------------------------ +这两个变量允许覆盖启动时显示的 user@host 字符串以及 /proc/version 中的信息。 +默认值分别是 whoami 和 host 命令的输出。 + +LLVM +---- +如果该变量设置为 1,Kbuild 将使用 Clang 和 LLVM 工具,而不是 GCC 和 GNU +binutils 来构建内核。 diff --git a/Documentation/translations/zh_CN/kbuild/kconfig.rst b/Documentation/translations/zh_CN/kbuild/kconfig.rst new file mode 100644 index 00000000000000..3b06d8913dbf37 --- /dev/null +++ b/Documentation/translations/zh_CN/kbuild/kconfig.rst @@ -0,0 +1,259 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/kbuild/kconfig.rst +:Translator: 慕冬亮 Dongliang Mu + +================ +配置目标和编辑器 +================ + +本文件包含使用 ``make *config`` 的一些帮助。 + +使用 ``make help`` 列出所有可能的配置目标。 + +xconfig('qconf')、menuconfig('mconf')和 nconfig('nconf')程序也包含 +内嵌的帮助文本。请务必查看这些帮助文本以获取导航、搜索和其他帮助信息。 + +gconfig('gconf')程序的帮助文本较少。 + + +通用信息 +======== + +新的内核版本通常会引入新的配置符号。更重要的是,新的内核版本可能会重命名配置符号。 +当这种情况发生时,使用之前正常工作的 .config 文件并运行 "make oldconfig" +不一定会生成一个可正常工作的新内核,因此,你可能需要查看哪些新的内核符号被引入。 + +要查看新配置符号的列表,请使用:: + + cp user/some/old.config .config + make listnewconfig + +配置程序将列出所有新配置符号,每行一个。 + +或者,你可以使用暴力破解方法:: + + make oldconfig + scripts/diffconfig .config.old .config | less + + +环境变量 +======== + +``*config`` 的环境变量: + +``KCONFIG_CONFIG`` + 该环境变量可用于指定一个默认的内核配置文件名,以覆盖默认的 ".config"。 + +``KCONFIG_DEFCONFIG_LIST`` + 该环境变量指定了一个配置文件列表,当 .config 不存在时,这些文件可用作基础配置。 + 列表中的条目以空格分隔,只有第一个存在的文件会被使用。 + +``KCONFIG_OVERWRITECONFIG`` + 如果该环境变量被设置,当 .config 是指向其他位置的符号链接时,Kconfig 不会 + 破坏符号链接。 + +``KCONFIG_WARN_UNKNOWN_SYMBOLS`` + 该环境变量使 Kconfig 对配置输入中所有无法识别的符号发出警告。 + +``KCONFIG_WERROR`` + 如果该环境变量被设置,Kconfig 将所有警告视为错误。 + +``CONFIG_`` + 如果该环境变量被设置,Kconfig 将在保存配置时,为所有符号添加其值作为前缀, + 而不是使用默认值。 + +``{allyes/allmod/allno/rand}config`` 的环境变量: + +``KCONFIG_ALLCONFIG`` + allyesconfig/allmodconfig/allnoconfig/randconfig 这些变体也可以使用环境 + 变量 KCONFIG_ALLCONFIG 作为标志或包含用户要求设置为特定值的配置符号的文件名。 + 如果 KCONFIG_ALLCONFIG 未指定文件名,即 KCONFIG_ALLCONFIG == "" 或 + KCONFIG_ALLCONFIG == "1",则 ``make *config`` 将查找名为 + "all{yes/mod/no/def/random}.config" 的文件(对应于所使用的 ``*config`` + 命令)以强制符号值。如果找不到此文件,它会查找名为 "all.config" 的文件以包含 + 强制值。 + + 这可以创建“微型”配置(miniconfig)或自定义配置文件,其中仅包含感兴趣的配置符号。 + 然后,内核配置系统将生成完整的 .config 文件,包括 miniconfig 文件中的符号。 + + ``KCONFIG_ALLCONFIG`` 文件包含许多预设配置符号(通常是所有符号的子集)。 + 这些变量设置仍需遵守正常的依赖性检查。 + + 示例:: + + KCONFIG_ALLCONFIG=custom-notebook.config make allnoconfig + + 或:: + + KCONFIG_ALLCONFIG=mini.config make allnoconfig + + 或:: + + make KCONFIG_ALLCONFIG=mini.config allnoconfig + + 这些示例将禁用大多数配置选项(allnoconfig),但启用或禁用 miniconfig 文件 + 中显式列出的选项。 + +``randconfig`` 的环境变量: + +``KCONFIG_SEED`` + 如果你想调试 kconfig 解析器/前端的行为,你可以将此变量设置整数值,用于初始化 + 随机数生成器。如果未设置,将使用当前时间。 + +``KCONFIG_PROBABILITY`` + 该变量可用于倾斜概率分布。此变量可不设置或设置为空,或设置为以下三种不同格式: + + ======================= ================== ===================== + KCONFIG_PROBABILITY y:n 分配 y:m:n 分配 + ======================= ================== ===================== + 未设置或设置为空 50 : 50 33 : 33 : 34 + N N : 100-N N/2 : N/2 : 100-N + [1] N:M N+M : 100-(N+M) N : M : 100-(N+M) + [2] N:M:L N : 100-N M : L : 100-(M+L) + ======================= ================== ===================== + +其中 N、M 和 L 是范围在 [0,100] 内的整数(以十进制表示),并且需满足: + + [1] N+M 的范围在 [0,100] 之间 + + [2] M+L 的范围在 [0,100] 之间 + +示例:: + + KCONFIG_PROBABILITY=10 + 10% 的布尔值将设置为 'y',90% 设置为 'n' + 5% 的三态值将设置为 'y',5% 设置为 'm',90% 设置为 'n' + KCONFIG_PROBABILITY=15:25 + 40% 的布尔值将设置为 'y',60% 设置为 'n' + 15% 的三态值将设置为 'y',25% 设置为 'm',60% 设置为 'n' + KCONFIG_PROBABILITY=10:15:15 + 10% 的布尔值将设置为 'y',90% 设置为 'n' + 15% 的三态值将设置为 'y',15% 设置为 'm',70% 设置为 'n' + +``syncconfig`` 的环境变量: + +``KCONFIG_NOSILENTUPDATE`` + 如果该变量非空,它将阻止静默的内核配置更新(需要明确更新)。 + +``KCONFIG_AUTOCONFIG`` + 该环境变量可以设置为 "auto.conf" 文件的路径和名称。默认值为 + "include/config/auto.conf"。 + +``KCONFIG_AUTOHEADER`` + 该环境变量可以设置为 "autoconf.h" 头文件的路径和名称。默认值为 + "include/generated/autoconf.h"。 + +menuconfig +========== + +在 menuconfig 中搜索: + + 搜索功能会搜索内核配置符号名称,因此你必须知道欲搜索内容的大致名称。 + + 示例:: + + /hotplug + 这会列出所有包含 "hotplug" 的配置符号,例如,HOTPLUG_CPU, + MEMORY_HOTPLUG。 + + 若需要搜索帮助,输入 / 后跟 TAB-TAB(高亮显示 )并按回车键。 + 这说明你还可以在搜索字符串中使用正则表达式(regex),所以如果你对 + MEMORY_HOTPLUG 不感兴趣,你可以尝试:: + + /^hotplug + + 在搜索时,符号将按以下顺序排序: + + - 首先,完全匹配的符号,按字母顺序排列(完全匹配是指搜索与符号名称完全匹配); + - 然后是其他匹配项,按字母顺序排列。 + + 例如,^ATH.K 匹配:: + + ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG + [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...] + + 其中只有 ATH5K 和 ATH9K 完全匹配,因此它们排在前面(按字母顺序), + 接下来是其他符号,同样按字母顺序排列。 + + 在此菜单中,按下以 (#) 为前缀的键将直接跳转到该位置。退出此新菜单后, + 你将返回当前的搜索结果。 + +'menuconfig' 的用户界面选项: + +``MENUCONFIG_COLOR`` + 可以使用变量 MENUCONFIG_COLOR 选择不同的配色主题。使用以下命令选择主题:: + + make MENUCONFIG_COLOR= menuconfig + + 可用的主题有:: + + - mono => 选择适合单色显示器的颜色 + - blackbg => 选择具有黑色背景的配色方案 + - classic => 经典外观,蓝色背景 + - bluetitle => 经典外观的 LCD 友好版本(默认) + +``MENUCONFIG_MODE`` + 此模式会将所有子菜单显示为一个大树状结构。 + + 示例:: + + make MENUCONFIG_MODE=single_menu menuconfig + +nconfig +======= + +nconfig 是一个替代的基于文本的配置工具。它在终端(窗口)底部列出功能键,用于执行 +命令。除非你在数据输入窗口中,否则你也可以直接使用相应的数字键来执行命令。例如,你 +可以直接按 6,而非 F6 进行保存。 + +使用 F1 获取全局帮助或 F3 打开简短帮助菜单。 + +在 nconfig 中搜索: + + 你可以在菜单项“提示”字符串中或配置符号中进行搜索。 + + 使用 / 开始在菜单项中搜索。这不支持正则表达式。使用 + 分别为下一个命中项和上一个命中项。使用 退出搜索模式。 + + F8(SymSearch)在配置符号中搜索给定的字符串或正则表达式(regex)。 + + 在 SymSearch 中,按下 (#) 前缀的键会直接跳转到该位置。退出该新菜单后, + 你将返回到当前的搜索结果。 + +环境变量: + +``NCONFIG_MODE`` + 此模式会将所有子菜单显示为一个大型树结构。 + + 示例:: + + make NCONFIG_MODE=single_menu nconfig + +xconfig +======= + +在 xconfig 中搜索: + + 搜索功能会搜索内核配置符号名称,因此你必须知道欲搜索内容的大致名称。 + + 示例:: + + Ctrl-F hotplug + + 或:: + + 菜单:File, Search, hotplug + + 列出所有符号名称中包含 "hotplug" 的配置符号项。在此搜索对话框中, + 你可以更改任何未灰显条目的配置设置。你还可以输入不同的搜索字符串, + 而无需返回主菜单。 + +gconfig +======= + +在 gconfig 中搜索: + + gconfig 中没有搜索命令。然而,gconfig 具有几种不同的查看选择、模式和选项。 diff --git a/Documentation/translations/zh_CN/kbuild/llvm.rst b/Documentation/translations/zh_CN/kbuild/llvm.rst new file mode 100644 index 00000000000000..f87e0181d8e7a1 --- /dev/null +++ b/Documentation/translations/zh_CN/kbuild/llvm.rst @@ -0,0 +1,203 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/kbuild/llvm.rst +:Translator: 慕冬亮 Dongliang Mu + +========================== +使用 Clang/LLVM 构建 Linux +========================== + +本文档介绍如何使用 Clang 和 LLVM 工具构建 Linux 内核。 + +关于 +---- + +Linux 内核传统上一直使用 GNU 工具链(如 GCC 和 binutils)进行编译。持续的工作使得 +`Clang `_ 和 `LLVM `_ 工具可 +作为可行的替代品。一些发行版,如 `Android `_、 +`ChromeOS `_、`OpenMandriva +`_ 和 `Chimera Linux +`_ 使用 Clang 编译的内核。谷歌和 Meta 的数据中心 +集群也运行由 Clang 编译的内核。 + +`LLVM 是由 C++ 对象实现的工具链组件集合 `_。 +Clang 是 LLVM 的前端,支持 C 语言和内核所需的 GNU C 扩展,其发音为 "klang",而非 +"see-lang"。 + +使用 LLVM 构建 +-------------- + +通过以下命令调用 ``make``:: + + make LLVM=1 + +为主机目标进行编译。对于交叉编译:: + + make LLVM=1 ARCH=arm64 + +LLVM= 参数 +---------- + +LLVM 有 GNU binutils 工具的替代品。这些工具可以单独启用。以下是支持的 make 变量 +完整列表:: + + make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \ + OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump READELF=llvm-readelf \ + HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld + +``LLVM=1`` 扩展为上述命令。 + +如果你的 LLVM 工具不在 PATH 中,你可以使用以斜杠结尾的 LLVM 变量提供它们的位置:: + + make LLVM=/path/to/llvm/ + +这将使用 ``/path/to/llvm/clang``、``/path/to/llvm/ld.lld`` 等工具。也可以 +使用以下命令:: + + PATH=/path/to/llvm:$PATH make LLVM=1 + +如果你的 LLVM 工具带有版本后缀,并且你希望测试该特定版本而非无后缀的可执行文件, +类似于 ``LLVM=1``,你可以使用 ``LLVM`` 变量传递该后缀:: + + make LLVM=-14 + +这将使用 ``clang-14``、``ld.lld-14`` 等工具。为了支持带有版本后缀的树外路径组合, +我们建议:: + + PATH=/path/to/llvm/:$PATH make LLVM=-14 + +``LLVM=0`` 与省略 ``LLVM`` 完全不同,它将表现得像 ``LLVM=1``。如果你只希望使用 +某些 LLVM 工具,请使用它们各自的 make 变量。 + +在通过不同命令配置和构建时,应为每次调用 ``make`` 设置相同的 ``LLVM=`` 值。如果 +运行的脚本最终会调用 ``make``,则还应将 ``LLVM=`` 设置为环境变量。 + +交叉编译 +-------- + +单个 Clang 编译器二进制文件(及其对应的 LLVM 工具)通常会包含所有支持的后端,这可以 +简化交叉编译,尤其是使用 ``LLVM=1`` 时。如果仅使用 LLVM 工具,``CROSS_COMPILE`` +或目标三元组前缀就变得不必要。示例:: + + make LLVM=1 ARCH=arm64 + +作为混合 LLVM 和 GNU 工具的示例,对于像 ``ARCH=s390`` 这样目前尚不支持 +``ld.lld`` 或 ``llvm-objcopy`` 的目标,你可以通过以下方式调用 ``make``:: + + make LLVM=1 ARCH=s390 LD=s390x-linux-gnu-ld.bfd \ + OBJCOPY=s390x-linux-gnu-objcopy + +此示例将调用 ``s390x-linux-gnu-ld.bfd`` 作为链接器和 +``s390x-linux-gnu-objcopy``,因此请确保它们在你的 ``$PATH`` 中。 + +当 ``LLVM=1`` 未设置时,``CROSS_COMPILE`` 不会用于给 Clang 编译器二进制文件 +(或相应的 LLVM 工具)添加前缀,而 GNU 工具则需要这样做。 + +LLVM_IAS= 参数 +-------------- + +Clang 可以编译汇编代码。你可以传递 ``LLVM_IAS=0`` 禁用此行为,使 Clang 调用 +相应的非集成汇编器。示例:: + + make LLVM=1 LLVM_IAS=0 + +在交叉编译时,你需要使用 ``CROSS_COMPILE`` 与 ``LLVM_IAS=0``,从而设置 +``--prefix=`` 使得编译器可以对应的非集成汇编器(通常,在面向另一种架构时, +你不想使用系统汇编器)。例如:: + + make LLVM=1 ARCH=arm LLVM_IAS=0 CROSS_COMPILE=arm-linux-gnueabi- + +Ccache +------ + +``ccache`` 可以与 ``clang`` 一起使用,以改善后续构建(尽管在不同构建之间 +KBUILD_BUILD_TIMESTAMP_ 应设置为同一确定值,以避免 100% 的缓存未命中, +详见 Reproducible_builds_ 获取更多信息):: + + KBUILD_BUILD_TIMESTAMP='' make LLVM=1 CC="ccache clang" + +.. _KBUILD_BUILD_TIMESTAMP: kbuild.html#kbuild-build-timestamp +.. _Reproducible_builds: reproducible-builds.html#timestamps + +支持的架构 +---------- + +LLVM 并不支持 Linux 内核所有可支持的架构,同样,即使 LLVM 支持某一架构,也并不意味着在 +该架构下内核可以正常构建或工作。以下是当前 ``CC=clang`` 或 ``LLVM=1`` 支持的架构总结。 +支持级别对应于 MAINTAINERS 文件中的 "S" 值。如果某个架构未列出,则表示 LLVM 不支持它 +或存在已知问题。使用最新的稳定版 LLVM 或甚至开发版本通常会得到最佳结果。一个架构的 +``defconfig`` 通常预期能够良好工作,但某些配置可能存在尚未发现的问题。欢迎在以下 +问题跟踪器中提交错误报告! + +.. list-table:: + :widths: 10 10 10 + :header-rows: 1 + + * - 架构 + - 支持级别 + - ``make`` 命令 + * - arm + - 支持 + - ``LLVM=1`` + * - arm64 + - 支持 + - ``LLVM=1`` + * - hexagon + - 维护 + - ``LLVM=1`` + * - loongarch + - 维护 + - ``LLVM=1`` + * - mips + - 维护 + - ``LLVM=1`` + * - powerpc + - 维护 + - ``LLVM=1`` + * - riscv + - 支持 + - ``LLVM=1`` + * - s390 + - 维护 + - ``LLVM=1`` (LLVM >= 18.1.0),``CC=clang`` (LLVM < 18.1.0) + * - um (用户模式) + - 维护 + - ``LLVM=1`` + * - x86 + - 支持 + - ``LLVM=1`` + +获取帮助 +-------- + +- `网站 `_ +- `邮件列表 `_: +- `旧邮件列表档案 `_ +- `问题跟踪器 `_ +- IRC: #clangbuiltlinux 在 irc.libera.chat +- `Telegram `_: @ClangBuiltLinux +- `维基 `_ +- `初学者问题 `_ + +.. _zh_cn_getting_llvm: + +获取 LLVM +--------- + +我们在 `kernel.org `_ 提供预编译的稳定版 LLVM。 +这些版本已经针对 Linux 内核构建,使用配置文件数据进行优化。相较于其他发行版中的 LLVM,它们应该 +能提高内核构建效率。 + +以下是一些有助于从源代码构建 LLVM 或通过发行版的包管理器获取 LLVM 的链接。 + +- https://releases.llvm.org/download.html +- https://github.com/llvm/llvm-project +- https://llvm.org/docs/GettingStarted.html +- https://llvm.org/docs/CMake.html +- https://apt.llvm.org/ +- https://www.archlinux.org/packages/extra/x86_64/llvm/ +- https://github.com/ClangBuiltLinux/tc-build +- https://github.com/ClangBuiltLinux/linux/wiki/Building-Clang-from-source +- https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/ diff --git a/Documentation/translations/zh_CN/kbuild/reproducible-builds.rst b/Documentation/translations/zh_CN/kbuild/reproducible-builds.rst new file mode 100644 index 00000000000000..5f27ebf2fbfce2 --- /dev/null +++ b/Documentation/translations/zh_CN/kbuild/reproducible-builds.rst @@ -0,0 +1,114 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/kbuild/reproducible-builds.rst + +:Translator: 慕冬亮 Dongliang Mu + +============ +可重现的构建 +============ + +通常希望使用相同工具集构建相同源代码是可重现的,即,输出始终完全相同。这使得能够验证 +二进制分发或嵌入式系统的构建基础设施未被篡改。这样也更容易验证源代码或工具的更改不会 +影响最终生成的二进制文件。 + +`可重现构建项目`_ 提供了有关该主题的更多信息。本文档涵盖了构建内核可能不可重现的 +各种原因,以及如何避免这些问题。 + +时间戳 +------ + +内核在三个地方嵌入时间戳: + +* 通过 ``uname()`` 显示与包含在 ``/proc/version`` 中的版本字符串 + +* initramfs 中的文件时间戳 + +* 如果启动 ``CONFIG_IKHEADERS``,内核或相应模块中嵌入的内核头文件的时间戳, + 通过 ``/sys/kernel/kheaders.tar.xz`` 显示 + +默认情况下,时间戳为当前时间或内核头文件的修改时间。这个内容必须使用 +`KBUILD_BUILD_TIMESTAMP`_ 变量进行覆盖。如果你从某个 git 提交进行构建, +可以使用其提交日期。 + +内核 *不* 使用 ``__DATE__`` 和 ``__TIME__`` 宏,并在使用这些宏时启用警告。 +如果你合并的外部代码使用这些宏,则必须通过设置 `SOURCE_DATE_EPOCH`_ 环境 +变量来覆盖它们对应的时间戳。 + +用户,主机 +---------- + +内核在 ``/proc/version`` 中嵌入构建用户和主机名。必须使用 +`KBUILD_BUILD_USER 和 KBUILD_BUILD_HOST`_ 变量来覆盖这些设置。如果 +您从某个 git 提交进行构建,可以使用其提交者地址。 + +绝对文件名 +---------- + +当内核在树外构建时,调试信息可能包括源文件的绝对文件名。这些信息必须通过在 +`KCFLAGS`_ 变量中包含 ``-fdebug-prefix-map`` 选项来覆盖。 + +根据使用的编译器,``__FILE__`` 宏在树外构建中也可能扩展为绝对文件名。Kbuild +自动使用 ``-fmacro-prefix-map`` 选项来防止这种情况,前提是它被支持。 + +可重现构建网站提供了有关这些 `prefix-map 选项`_ 的更多信息。 + +在源包中的生成文件 +------------------ + +在 ``tools/`` 子目录下,一些程序的构建过程并不完全支持树外构建。这可能导致后续 +使用如 ``make rpm-pkg`` 构建的源码包包含生成的文件。在构建源码包之前,您应该通过 +运行 ``make mrproper`` 或 ``git clean -d -f -x`` 来确保源码树是干净的。 + +模块签名 +-------- + +如果你启用 ``CONFIG_MODULE_SIG_ALL``,默认行为是为每次构建生成不同的临时密钥, +从而导致模块不可重现。然而,将签名密钥包含在源代码中显然会违背签名模块的目的。 + +一种方法是将构建过程分为几个部分,以便不可重现的部分可以作为源处理: + +1. 生成一个持久的签名密钥。将该密钥的证书添加到内核源代码中。 + +2. 将 ``CONFIG_SYSTEM_TRUSTED_KEYS`` 符号设置为包括签名密钥的证书,将 +``CONFIG_MODULE_SIG_KEY`` 设置为空字符串,并禁用 ``CONFIG_MODULE_SIG_ALL``。 +最后,构建内核和模块。 + +3. 为模块创建分离的签名,并将它们作为源发布。 + +4. 附加模块签名并进行第二次构建。这可以重建模块,或使用步骤 2 的输出。 + +结构随机化 +---------- + +如果你启用 ``CONFIG_RANDSTRUCT``,则需要在 ``scripts/basic/randstruct.seed`` +中预生成随机种子,以便每次构建都使用相同的值。有关详细信息,请参见 +``scripts/gen-randstruct-seed.sh``。 + +调试信息冲突 +------------ + +这并非是个不可重现性的问题,而是生成的文件 *过于* 可重现的问题。 + +一旦你设置了所有必要的变量来开展可重现构建,vDSO 的调试信息可能即使对于不同的内核版 +本也是相同的。这会导致不同内核版本的调试信息软件包之间发生文件冲突。 + +为了避免这种情况,你可以通过在 vDSO 中包含一个任意的 salt 字符串,使其对于不同的 +内核版本是不同的。这种机制由 Kconfig 符号 ``CONFIG_BUILD_SALT`` 指定。 + +Git +--- + +未提交的更改或 Git 中的不同提交 ID 也可能导致不同的编译结果。例如,在执行 +``git reset HEAD^`` 后,即使代码相同,编译期间生成的 +``include/config/kernel.release`` 也会不同,导致最终生成的二进制文件也不尽相同。 +有关详细信息,请参见 ``scripts/setlocalversion``。 + +.. _KBUILD_BUILD_TIMESTAMP: kbuild.html#kbuild-build-timestamp +.. _KBUILD_BUILD_USER 和 KBUILD_BUILD_HOST: kbuild.html#kbuild-build-user-kbuild-build-host +.. _KCFLAGS: kbuild.html#kcflags +.. _prefix-map 选项: https://reproducible-builds.org/docs/build-path/ +.. _可重现构建项目: https://reproducible-builds.org/ +.. _SOURCE_DATE_EPOCH: https://reproducible-builds.org/docs/source-date-epoch/ diff --git a/Documentation/translations/zh_CN/mm/active_mm.rst b/Documentation/translations/zh_CN/mm/active_mm.rst index c2816f523bd781..b3352668c4c850 100644 --- a/Documentation/translations/zh_CN/mm/active_mm.rst +++ b/Documentation/translations/zh_CN/mm/active_mm.rst @@ -13,6 +13,11 @@ Active MM ========= +注意,在配置了 CONFIG_MMU_LAZY_TLB_REFCOUNT=n 的内核中,mm_count 引用计数 +可能不再包括“懒惰”用户(运行任务中 ->active_mm == mm && ->mm == NULL)。 +获取和释放这些懒惰引用必须使用 mmgrab_lazy_tlb() 和 mmdrop_lazy_tlb() 这 +两个辅助函数,它们抽象了这个配置选项。 + 这是一封linux之父回复开发者的一封邮件,所以翻译时我尽量保持邮件格式的完整。 :: diff --git a/Documentation/translations/zh_CN/mm/damon/faq.rst b/Documentation/translations/zh_CN/mm/damon/faq.rst index de4be417494ac5..234d63f4f072d4 100644 --- a/Documentation/translations/zh_CN/mm/damon/faq.rst +++ b/Documentation/translations/zh_CN/mm/damon/faq.rst @@ -13,23 +13,6 @@ 常见问题 ======== -为什么是一个新的子系统,而不是扩展perf或其他用户空间工具? -========================================================== - -首先,因为它需要尽可能的轻量级,以便可以在线使用,所以应该避免任何不必要的开销,如内核-用户 -空间的上下文切换成本。第二,DAMON的目标是被包括内核在内的其他程序所使用。因此,对特定工具 -(如perf)的依赖性是不可取的。这就是DAMON在内核空间实现的两个最大的原因。 - - -“闲置页面跟踪” 或 “perf mem” 可以替代DAMON吗? -============================================== - -闲置页跟踪是物理地址空间访问检查的一个低层次的原始方法。“perf mem”也是类似的,尽管它可以 -使用采样来减少开销。另一方面,DAMON是一个更高层次的框架,用于监控各种地址空间。它专注于内 -存管理优化,并提供复杂的精度/开销处理机制。因此,“空闲页面跟踪” 和 “perf mem” 可以提供 -DAMON输出的一个子集,但不能替代DAMON。 - - DAMON是否只支持虚拟内存? ========================= diff --git a/Documentation/translations/zh_CN/mm/hmm.rst b/Documentation/translations/zh_CN/mm/hmm.rst index babbbe756c0fea..0669f947d0bc9b 100644 --- a/Documentation/translations/zh_CN/mm/hmm.rst +++ b/Documentation/translations/zh_CN/mm/hmm.rst @@ -129,13 +129,7 @@ struct page可以与现有的 mm 机制进行最简单、最干净的集成。 int hmm_range_fault(struct hmm_range *range); 如果请求写访问,它将在丢失或只读条目上触发缺页异常(见下文)。缺页异常使用通用的 mm 缺 -页异常代码路径,就像 CPU 缺页异常一样。 - -这两个函数都将 CPU 页表条目复制到它们的 pfns 数组参数中。该数组中的每个条目对应于虚拟 -范围中的一个地址。HMM 提供了一组标志来帮助驱动程序识别特殊的 CPU 页表项。 - -在 sync_cpu_device_pagetables() 回调中锁定是驱动程序必须尊重的最重要的方面,以保 -持事物正确同步。使用模式是:: +页异常代码路径,就像 CPU 缺页异常一样。使用模式是:: int driver_populate_range(...) { diff --git a/Documentation/translations/zh_CN/mm/index.rst b/Documentation/translations/zh_CN/mm/index.rst index b950dd118be73e..c8726bce8f7459 100644 --- a/Documentation/translations/zh_CN/mm/index.rst +++ b/Documentation/translations/zh_CN/mm/index.rst @@ -53,6 +53,8 @@ Linux内存管理文档 page_migration page_owner page_table_check + page_tables + physical_memory remap_file_pages split_page_table_lock vmalloced-kernel-stacks diff --git a/Documentation/translations/zh_CN/mm/overcommit-accounting.rst b/Documentation/translations/zh_CN/mm/overcommit-accounting.rst index d8452d8b7fbbe1..f136a8b818596b 100644 --- a/Documentation/translations/zh_CN/mm/overcommit-accounting.rst +++ b/Documentation/translations/zh_CN/mm/overcommit-accounting.rst @@ -16,8 +16,7 @@ Linux内核支持下列超量使用处理模式 0 启发式超量使用处理。拒绝明显的地址空间超量使用。用于一个典型的系统。 - 它确保严重的疯狂分配失败,同时允许超量使用以减少swap的使用。在这种模式下, - 允许root分配稍多的内存。这是默认的。 + 它确保严重的疯狂分配失败,同时允许超量使用以减少swap的使用。这是默认的。 1 总是超量使用。适用于一些科学应用。经典的例子是使用稀疏数组的代码,只是依赖 几乎完全由零页组成的虚拟内存 diff --git a/Documentation/translations/zh_CN/mm/page_owner.rst b/Documentation/translations/zh_CN/mm/page_owner.rst index b72a972271d92b..c0d1ca4b969527 100644 --- a/Documentation/translations/zh_CN/mm/page_owner.rst +++ b/Documentation/translations/zh_CN/mm/page_owner.rst @@ -26,6 +26,9 @@ page owner是用来追踪谁分配的每一个页面。它可以用来调试内 页面所有者也可以用于各种目的。例如,可以通过每个页面的gfp标志信息获得精确的碎片 统计。如果启用了page owner,它就已经实现并激活了。我们非常欢迎其他用途。 +它也可以用来显示所有的栈以及它们当前分配的基础页面数,这让我们能够快速了解内存的 +使用情况,而无需浏览所有页面并匹配分配和释放操作。 + page owner在默认情况下是禁用的。所以,如果你想使用它,你需要在你的启动cmdline 中加入"page_owner=on"。如果内核是用page owner构建的,并且由于没有启用启动 选项而在运行时禁用page owner,那么运行时的开销是很小的。如果在运行时禁用,它不 @@ -60,6 +63,49 @@ page owner在默认情况下是禁用的。所以,如果你想使用它,你 4) 分析来自页面所有者的信息:: + cat /sys/kernel/debug/page_owner_stacks/show_stacks > stacks.txt + cat stacks.txt + post_alloc_hook+0x177/0x1a0 + get_page_from_freelist+0xd01/0xd80 + __alloc_pages+0x39e/0x7e0 + allocate_slab+0xbc/0x3f0 + ___slab_alloc+0x528/0x8a0 + kmem_cache_alloc+0x224/0x3b0 + sk_prot_alloc+0x58/0x1a0 + sk_alloc+0x32/0x4f0 + inet_create+0x427/0xb50 + __sock_create+0x2e4/0x650 + inet_ctl_sock_create+0x30/0x180 + igmp_net_init+0xc1/0x130 + ops_init+0x167/0x410 + setup_net+0x304/0xa60 + copy_net_ns+0x29b/0x4a0 + create_new_namespaces+0x4a1/0x820 + nr_base_pages: 16 + ... + ... + echo 7000 > /sys/kernel/debug/page_owner_stacks/count_threshold + cat /sys/kernel/debug/page_owner_stacks/show_stacks> stacks_7000.txt + cat stacks_7000.txt + post_alloc_hook+0x177/0x1a0 + get_page_from_freelist+0xd01/0xd80 + __alloc_pages+0x39e/0x7e0 + alloc_pages_mpol+0x22e/0x490 + folio_alloc+0xd5/0x110 + filemap_alloc_folio+0x78/0x230 + page_cache_ra_order+0x287/0x6f0 + filemap_get_pages+0x517/0x1160 + filemap_read+0x304/0x9f0 + xfs_file_buffered_read+0xe6/0x1d0 [xfs] + xfs_file_read_iter+0x1f0/0x380 [xfs] + __kernel_read+0x3b9/0x730 + kernel_read_file+0x309/0x4d0 + __do_sys_finit_module+0x381/0x730 + do_syscall_64+0x8d/0x150 + entry_SYSCALL_64_after_hwframe+0x62/0x6a + nr_base_pages: 20824 + ... + cat /sys/kernel/debug/page_owner > page_owner_full.txt ./page_owner_sort page_owner_full.txt sorted_page_owner.txt diff --git a/Documentation/translations/zh_CN/mm/page_table_check.rst b/Documentation/translations/zh_CN/mm/page_table_check.rst index e8077310a76c60..dc34570dceff3a 100644 --- a/Documentation/translations/zh_CN/mm/page_table_check.rst +++ b/Documentation/translations/zh_CN/mm/page_table_check.rst @@ -54,3 +54,16 @@ 可以选择用PAGE_TABLE_CHECK_ENFORCED来构建内核,以便在没有额外的内核参数的情况下获得页表 支持。 + +实现注意事项 +============ + +我们特意决定不使用 VMA 信息,以避免依赖于 MM 状态(除了有限的 “struct page” 信息)。页表检查 +独立于 Linux-MM 状态机,它验证用户可访问的页面不会被错误地共享。 + +PAGE_TABLE_CHECK 依赖于 EXCLUSIVE_SYSTEM_RAM。原因在于,若没有 EXCLUSIVE_SYSTEM_RAM, +用户被允许通过 /dev/mem 将任意物理内存区域映射到用户空间。同时,页面可能在映射到用户空间期间 +改变自己的属性(例如,从匿名页面变为命名页面),导致页表检查检测到“损坏”。 + +即使有 EXCLUSIVE_SYSTEM_RAM,I/O 页面可能仍然被允许通过 /dev/mem 映射。然而,这些页面始终 +被视为命名页面,所以它们不会破坏页表检查中使用的逻辑。 diff --git a/Documentation/translations/zh_CN/mm/page_tables.rst b/Documentation/translations/zh_CN/mm/page_tables.rst new file mode 100644 index 00000000000000..c9f750fc5298a4 --- /dev/null +++ b/Documentation/translations/zh_CN/mm/page_tables.rst @@ -0,0 +1,221 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/mm/page_tables.rst + +:翻译: + + 张鹏宇 Pengyu Zhang + +:校译: + +==== +页表 +==== + +分页虚拟内存是随虚拟内存的概念一起于 1962 年在 Ferranti Atlas 计算机上被提出的, +这是第一台有分页虚拟内存的计算机。随着时间推移,这个特性被迁移到更新的计算机上, +并且成为所有类 Unix 系统实际的特性。在 1985 年,这个特性被包含在了英特尔 80386 +中,也就是运行 Linux 1.0 的CPU。 + +页表将 CPU 看到的虚拟地址映射到外部内存总线上看到的物理地址。 + +Linux 将页表定义为一个分级结构,目前有五级。对于支持的每种架构,其代码会根据硬件 +限制对这个层级结构进行映射。 + +虚拟地址对应的物理地址通常由底层物理页帧引用。 **页帧号(page frame number,pfn)** +是页的物理地址(在外部内存总线看到的地址)除以 `PAGE_SIZE` 得到的值。 + +物理内存地址 0 对应 *pfn 0*,而最大的 pfn 对应处理器外部地址总线所能寻址物理地址 +的最后一页。 + +在页粒度为 4KB 且地址范围为32位的情况下,pfn 0 对应地址0x00000000,pfn 1 对应 +地址0x00001000,pfn 2 对应地址 0x00002000,以此类推,直到 pfn 0xfffff 对应 +0xfffff000。如果页粒度为 16KB,则 pfn 分别对应地址 0x00004000、0x00008000 +... 0xffffc000,pfn 的范围从 0 到 0x3ffff。 + +如你所见,对于 4KB 页面粒度,页基址使用地址的 12-31 位,这就是为什么在这种情况下 +`PAGE_SHIFT` 被定义为 12,并且 `PAGE_SIZE` 通常由页偏移定义,为 `(1 << PAGE_SHIFT)`。 + +随着内存容量的增加,久而久之层级结构逐渐加深。Linux 最初使用 4KB 页面和一个名为 +`swapper_pg_dir` 的页表,该页表拥有 1024 个表项(entries),覆盖 4MB 的内存, +事实上Torvald 的第一台计算机正好就有 4MB 物理内存。表项在这张表中被称为 *PTE*:s +- 页表项(page table entries)。 + +软件页表层级结构反映了页表硬件已经变得分层化的事实,而这种分层化的目的是为了节省 +页表内存并加快地址映射速度。 + +当然,人们可以想象一张拥有大量表项的单一线性的页表将整个内存分为一个个页。而且, +这样的页表会非常稀疏,因为虚拟内存中大部分位置通常是未使用的。通过页表分层,虚拟 +内存中的大量空洞不会浪费宝贵的页表内存,因为只需要在上层页表中将大块的区域标记为 +未映射即可。 + +另外,在现代处理器中,上层页表项可以直接指向一个物理地址范围,这使得单个上层 +页表项可以连续映射几兆字节甚至几千兆字节的内存范围,从而快捷地实现虚拟地址到 +物理地址的映射:当你找到一个像这样的大型映射范围时,无需在层级结构中进一步遍历。 + +页表的层级结构目前发展为如下所示:: + + +-----+ + | PGD | + +-----+ + | + | +-----+ + +-->| P4D | + +-----+ + | + | +-----+ + +-->| PUD | + +-----+ + | + | +-----+ + +-->| PMD | + +-----+ + | + | +-----+ + +-->| PTE | + +-----+ + + +不同页表层级的符号含义从最底层开始如下: + +- **pte**, `pte_t`, `pteval_t` = **页表项** - 前面提到过。*pte* 是一个由 + `PTRS_PER_PTE` 个 `pteval_t` 类型元素组成的数组,每个元素将一个虚拟内存页 + 映射到一个物理内存页。体系结构定义了 `pteval_t` 的大小和内容。 + + 一个典型的例子是 `pteval_t` 是一个 32 或者 64 位的值,其中高位是 **pfn**, + 而低位则一些特定体系架构相关的位,如内存保护。 + + 这个 **表项(entry)** 有点令人困惑,因为在 Linux 1.0 中它确实指的是单层顶级 + 页表中的单个页表项,但在首次引入二级页表时,它被重新定义为映射元素的数组。 + 因此,*pte* 现在指的是最底层的页 *表*,而不是一个页表 *项*。 + +- **pmd**, `pmd_t`, `pmdval_t` = **页中间目录(Page Middle Directory)**, + 位于 *pte* 之上的层级结构,包含 `PTRS_PER_PMD` 个指向 *pte* 的引用。 + +- **pud**, `pud_t`, `pudval_t` = **页上级目录(Page Upper Directory)** + 是在其他层级之后引入的,用于处理四级页表。它可能未被使用,或者像我们稍后 + 讨论的那样被“折叠”。 + +- **p4d**, `p4d_t`, `p4dval_t` = **页四级目录(Page Level 4 Directory)** + 是在 *pud* 之后用于处理五级页表引入的。至此,显然需要用数字来替代 *pgd*、 + *pmd*、*pud* 等目录层级的名称,不能再继续使用临时的命名方式。这个目录层级 + 只在实际拥有五级页表的系统上使用,否则它会被折叠。 + +- **pgd**, `pgd_t`, `pgdval_t` = **页全局目录(Page Global Directory)** - + Linux 内核用于处理内核内存的 *PGD* 主页表仍然位于 `swapper_pg_dir`。 + 但系统中的每个用户空间进程也有自己的内存上下文,因此也有自己的 *pgd*, + 它位于 `struct mm_struct` 中,而 `struct mm_struct` 又在每个 `struct task_struct` + 中有引用。所以,任务(进程)存在一个形式为 `struct mm_struct` 的内存上下文, + 而这个结构体中有一个指向指向相应的页全局目录 `struct pgt_t *pgd` 指针。 + +重申一下:页表层级结构中的每一层都是一个 *指针数组*,所以 *pgd* 包含 `PTRS_PER_PGD` +个指向下一层的指针,*p4d* 包含 `PTRS_PER_P4D` 个指向 *pud* 项的指针,依此类推。 +每一层的指针数量由体系结构定义。:: + + PMD + --> +-----+ PTE + | ptr |-------> +-----+ + | ptr |- | ptr |-------> PAGE + | ptr | \ | ptr | + | ptr | \ ... + | ... | \ + | ptr | \ PTE + +-----+ +----> +-----+ + | ptr |-------> PAGE + | ptr | + ... + +页表折叠 +======== + +如果架构不使用所有的页表层级,那么这些层级可以被 *折叠*,也就是说被跳过。在 +访问下一层时,所有在页表上执行的操作都会在编译时增强,以跳过这一层。 + +与架构无关的页表处理代码(例如虚拟内存管理器)需要编写得能够遍历当前的所有五个 +层级。对于特定架构的代码,也应优先采用这种风格,以便对未来的变化具有更好的适应性。 + +MMU,TLB 和缺页异常 +=================== + +`内存管理单元(MMU)` 是处理虚拟地址到物理地址转换的硬件组件。它可能会使用相对较小 +的硬件缓存,如 `转换后备缓冲区(TLB)` 和 `页遍历缓存`,以加快这些地址翻译过程。 + +当 CPU 访存时,它会向 MMU 提供一个虚拟地址。MMU 会首先检查 TLB 或者页遍历缓存 +(在支持的架构上)是否存在对应的转换结果。如果没有,MMU 会通过遍历来确定物理地址 +并且建立映射。 + +当页面被写入时,该页的脏位会被设置(即打开)。每个内存页面都有相关的权限位和脏位。 +后者表明这个页自从被加载到内存以来是否被修改。 + +如果没有任何阻碍,物理内存到头来可以被任意访问并且对物理帧进行请求的操作。 + +MMU 无法找到某些转换有多种原因。有可能是 CPU 试图去访问当前进程没有权限访问的 +内存,或者因为访问的数据还不在物理内存中。 + +当这些情况发生时,MMU 会触发缺页异常,这是一种异常类型,用于通知 CPU 暂停当前 +执行并运行一个特殊的函数去处理这些异常。 + +缺页异常有一些常见且预期的原因。这些因素是由称为“懒加载”和“写时复制”的进程管理 +优化技术来触发的。缺页异常也可能发生在当页帧被交换到持久存储(交换分区或者文件) +并从其物理地址移出时。 + +这些技术提高了内存效率,减少了延迟,并且最小化了空间占用。本文档不会深入讨论 +“懒加载”和“写时复制”的细节,因为这些的主题属于进程地址管理范畴,超出了本文范围。 + +交换技术和前面提到的其他技术不同,因为它是在压力过大下情况下减少内存消耗的一种 +迫不得已的手段,因此是不受欢迎的。 + +交换不适用于由内核逻辑地址映射的内存。这些地址是内核虚拟地址空间的子集,直接映射 +一段连续的物理内存。对于提供的任意逻辑地址,它的物理地址可以通过对偏移量进行简单 +的算数运算来确定。对逻辑地址的访问很快,因为这避免了复杂的页表查找,但代价是这些 +内存不能被驱逐或置换。 + +如果内核无法为必须存在于物理帧中的数据腾出空间,那么它会调用内存不足(out-of-memory, +OOM)杀手,通过杀掉低优先级的进程来腾出空间,直到内存压力下降到安全阈值之下。 + +另外,代码漏洞或指示 CPU 访问的精心制作的恶意地址也可能导致缺页异常。一个进程的 +线程可以利用指令来访问不属于其地址空间的(非共享)内存,或者试图执行写入只读位置 +的指令。 + +如果上述情况发生在用户态,内核会向当前线程发送 `段错误` (SIGSEGV)信号。该信号 +通常导致线程及其所属的进程终止。 + +本文将简化并概述 Linux 内核如何处理这些缺页中断、创建表和表项、检查内存是否存在, +以及当内存不存在时,如何请求从持久存储或其他设备加载数据,并更新 MMU 及其缓存。 + +最初的步骤依赖于架构。大多是架构跳转到 `do_page_fault()`,而 x86 中断处理程序是由 +`DEFINE_IDTENTRY_RAW_ERRORCODE()` 宏定义的,该宏调用 `handle_page_fault()`。 + +无论调用路径如何,所有架构最终都会调用 `handle_mm_fault()`,该函数通常会调用 +`__handle_mm_fault()` 来执行实际分配页表的任务。 + +如果不幸无法调用 `__handle_mm_fault()` 则意味着虚拟地址指向了无权访问的物理 +内存区域(至少对于当前上下文如此)。这种情况会导致内核向该进程发送上述的 SIGSEGV +信号,并引发前面提到的后果。 + +这些用于查找偏移量的函数名称通常以 `*_offset()` 结尾,其中“\*”可以是 pgd,p4d, +pud,pmd 或者 pte;而分配相应层级页表的函数名称是 `*_alloc`,它们按照上述命名 +约定以对应页表层级的类型命名。 + +页表遍历可能在中间或者上层结束(PMD,PUD)。 + +Linux 支持比通常 4KB 更大的页面(即所谓的 `巨页`)。当使用这种较大的页面时,没有 +必要使用更低层的页表项(PTE)。巨页通常包含 2MB 到 1GB 的大块连续物理区域,分别由 +PMD 和 PUD 页表项映射。 + +巨页带来许多好处,如减少 TLB 压力,减少页表开销,提高内存分配效率,以及改善 +特定工作负载的性能。然而,这些好处也伴随着权衡,如内存浪费和分配难度增加。 + +在遍历和分配的最后,如果没有返回错误,`__handle_mm_fault()` 最终调用 `handle_pte_fault()` +通过 `do_fault()` 执行 `do_read_fault()`、 `do_cow_fault()` 和 `do_shared_fault()`。 +“read”,“cow”和“shared”分别暗示了它处理错误的类型和原因。 + +实际的工作流程实现是非常复杂的。其设计允许 Linux 根据每种架构的特定特性处理缺页 +异常,同时仍然共享一个通用的整体结构。 + +为了总结 Linux 如何处理缺页中断的概述,需要补充的是,缺页异常处理程序可以通过 +`pagefault_disable()` 和 `pagefault_enable()` 分别禁用和启用。 + +许多代码路径使用了这两个函数,因为它们需要禁止陷入缺页异常处理程序,主要是为了 +防止死锁。 diff --git a/Documentation/translations/zh_CN/mm/physical_memory.rst b/Documentation/translations/zh_CN/mm/physical_memory.rst new file mode 100644 index 00000000000000..4594d15cefecb3 --- /dev/null +++ b/Documentation/translations/zh_CN/mm/physical_memory.rst @@ -0,0 +1,356 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/mm/physical_memory.rst + +:翻译: + + 王亚鑫 Yaxin Wang + +======== +物理内存 +======== + +Linux可用于多种架构,因此需要一个与架构无关的抽象来表示物理内存。本章描述 +了管理运行系统中物理内存的结构。 + +第一个与内存管理相关的主要概念是 `非一致性内存访问(NUMA) +` + +在多核和多插槽机器中,内存可能被组织成不同的存储区,这些存储区根据与处理器 +的距离“不同”而有不同的访问开销。例如,可能为每个CPU分配内存存储区,或者为 +外围设备在附近分配一个非常适合DMA的内存存储区。 + +每个存储区被称为一个节点,节点在Linux中表示为 ``struct pglist_data``, +即使是在UMA架构中也是这样表示。该结构总是通过 ``pg_data_t`` 来引用。特 +定节点的 ``pg_data_t`` 结构体可以通过NODE_DATA(nid)引用,其中nid被称 +为该节点的ID。 + +对于非一致性内存访问(NUMA)架构,节点数据结构在引导时由特定于架构的代码早 +期分配。通常,这些结构在其所在的内存区上本地分配。对于一致性内存访问(UMA) +架构,只使用一个静态的 ``pg_data_t`` 结构体,称为 ``contig_page_data``。 +节点将会在 :ref:`节点 ` 章节中进一步讨论。 + +整个物理内存被划分为一个或多个被称为区域的块,这些区域表示内存的范围。这 +些范围通常由访问内存的架构限制来决定。在节点内,与特定区域对应的内存范围 +由 ``struct zone`` 结构体描述,该结构被定义为 ``zone_t``,每种区域都 +属于以下描述类型的一种。 + +* ``ZONE_DMA`` 和 ``ZONE_DMA32`` 在历史上代表适用于DMA的内存,这些 + 内存由那些不能访问所有可寻址内存的外设访问。多年来,已经有了更好、更稳 + 固的接口来获取满足特定DMA需求的内存(这些接口由 + Documentation/core-api/dma-api.rst 文档描述),但是 ``ZONE_DMA`` + 和 ``ZONE_DMA32`` 仍然表示访问受限的内存范围。 + +取决于架构的不同,这两种区域可以在构建时通过关闭 ``CONFIG_ZONE_DMA`` 和 +``CONFIG_ZONE_DMA32`` 配置选项来禁用。一些64位的平台可能需要这两种区域, +因为他们支持具有不同DMA寻址限制的外设。 + +* ``ZONE_NORMAL`` 是普通内存的区域,这种内存可以被内核随时访问。如果DMA + 设备支持将数据传输到所有可寻址的内存区域,那么可在该区域的页面上执行DMA + 操作。``ZONE_NORMAL`` 总是开启的。 + +* ``ZONE_HIGHMEM`` 是指那些没有在内核页表中永久映射的物理内存部分。该区 + 域的内存只能通过临时映射被内核访问。该区域只在某些32位架构上可用,并且是 + 通过 ``CONFIG_HIGHMEM`` 选项开启。 + +* ``ZONE_MOVABLE`` 是指可访问的普通内存区域,就像 ``ZONE_NORMAL`` + 一样。不同之处在于 ``ZONE_MOVABLE`` 中的大多数页面内容是可移动的。 + 这意味着这些页面的虚拟地址不会改变,但它们的内容可能会在不同的物理页面 + 之间移动。通常,在内存热插拔期间填充 ``ZONE_MOVABLE``,在启动时也可 + 以使用 ``kernelcore``、``movablecore`` 和 ``movable_node`` + 这些内核命令行参数来填充。更多详细信息,请参阅内核文档 + Documentation/mm/page_migration.rst 和 + Documentation/admin-guide/mm/memory-hotplug.rst。 + +* ``ZONE_DEVICE`` 表示位于持久性内存(PMEM)和图形处理单元(GPU) + 等设备上的内存。它与RAM区域类型有不同的特性,并且它的存在是为了提供 + :ref:`struct page` 结构和内存映射服务,以便设备驱动程序能 + 识别物理地址范围。``ZONE_DEVICE`` 通过 ``CONFIG_ZONE_DEVICE`` + 选项开启。 + +需要注意的是,许多内核操作只能使用 ``ZONE_NORMAL`` 来执行,因此它是 +性能最关键区域。区域在 :ref:`区域 ` 章节中有更详细的讨论。 + +节点和区域范围之间的关系由固件报告的物理内存映射决定,另外也由内存寻址 +的架构约束以及内核命令行中的某些参数决定。 + +例如,在具有2GB RAM的x86统一内存架构(UMA)机器上运行32位内核时,整 +个内存将位于节点0,并且将有三个区域: ``ZONE_DMA``、 ``ZONE_NORMAL`` +和 ``ZONE_HIGHMEM``:: + + 0 2G + +-------------------------------------------------------------+ + | node 0 | + +-------------------------------------------------------------+ + + 0 16M 896M 2G + +----------+-----------------------+--------------------------+ + | ZONE_DMA | ZONE_NORMAL | ZONE_HIGHMEM | + +----------+-----------------------+--------------------------+ + + +在内核构建时关闭 ``ZONE_DMA`` 开启 ``ZONE_DMA32``,并且具有16GB +RAM平均分配在两个节点上的arm64机器上,使用 ``movablecore=80%`` 参数 +启动时,``ZONE_DMA32``、``ZONE_NORMAL`` 和 ``ZONE_MOVABLE`` +位于节点0,而 ``ZONE_NORMAL`` 和 ``ZONE_MOVABLE`` 位于节点1:: + + + 1G 9G 17G + +--------------------------------+ +--------------------------+ + | node 0 | | node 1 | + +--------------------------------+ +--------------------------+ + + 1G 4G 4200M 9G 9320M 17G + +---------+----------+-----------+ +------------+-------------+ + | DMA32 | NORMAL | MOVABLE | | NORMAL | MOVABLE | + +---------+----------+-----------+ +------------+-------------+ + + +内存存储区可能位于交错的节点。在下面的例子中,一台x86机器有16GB的RAM分 +布在4个内存存储区上,偶数编号的内存存储区属于节点0,奇数编号的内存条属于 +节点1:: + + 0 4G 8G 12G 16G + +-------------+ +-------------+ +-------------+ +-------------+ + | node 0 | | node 1 | | node 0 | | node 1 | + +-------------+ +-------------+ +-------------+ +-------------+ + + 0 16M 4G + +-----+-------+ +-------------+ +-------------+ +-------------+ + | DMA | DMA32 | | NORMAL | | NORMAL | | NORMAL | + +-----+-------+ +-------------+ +-------------+ +-------------+ + +在这种情况下,节点0将覆盖从0到12GB的内存范围,而节点1将覆盖从4GB到16GB +的内存范围。 + +.. _nodes_zh_CN: + +节点 +==== + +正如我们所提到的,内存中的每个节点由 ``pg_data_t`` 描述,通过 +``struct pglist_data`` 结构体的类型定义。在分配页面时,默认情况下,Linux +使用节点本地分配策略,从离当前运行CPU的最近节点分配内存。由于进程倾向于在同 +一个CPU上运行,很可能会使用当前节点的内存。分配策略可以由用户控制,如内核文 +档 Documentation/admin-guide/mm/numa_memory_policy.rst 中所述。 + +大多数NUMA(非统一内存访问)架构维护了一个指向节点结构的指针数组。这些实际 +的结构在启动过程中的早期被分配,这时特定于架构的代码解析了固件报告的物理内 +存映射。节点初始化的大部分工作是在由free_area_init()实现的启动过程之后 +完成,该函数在后面的小节 :ref:`初始化 ` 中有详细描述。 + +除了节点结构,内核还维护了一个名为 ``node_states`` 的 ``nodemask_t`` +位掩码数组。这个数组中的每个位掩码代表一组特定属性的节点,这些属性由 +``enum node_states`` 定义,定义如下: + +``N_POSSIBLE`` +节点可能在某个时刻上线。 + +``N_ONLINE`` +节点已经上线。 + +``N_NORMAL_MEMORY`` +节点拥有普通内存。 + +``N_HIGH_MEMORY`` +节点拥有普通或高端内存。当关闭 ``CONFIG_HIGHMEM`` 配置时, +也可以称为 ``N_NORMAL_MEMORY``。 + +``N_MEMORY`` +节点拥有(普通、高端、可移动)内存。 + +``N_CPU`` +节点拥有一个或多个CPU。 + +对于具有上述属性的每个节点,``node_states[]`` +掩码中对应于节点ID的位会被置位。 + +例如,对于具有常规内存和CPU的节点2,第二个bit将被设置:: + + node_states[N_POSSIBLE] + node_states[N_ONLINE] + node_states[N_NORMAL_MEMORY] + node_states[N_HIGH_MEMORY] + node_states[N_MEMORY] + node_states[N_CPU] + +有关使用节点掩码(nodemasks)可能进行的各种操作,请参考 +``include/linux/nodemask.h``。 + +除此之外,节点掩码(nodemasks)提供用于遍历节点的宏,即 +``for_each_node()`` 和 ``for_each_online_node()``。 + +例如,要为每个在线节点调用函数 foo(),可以这样操作:: + + for_each_online_node(nid) { + pg_data_t *pgdat = NODE_DATA(nid); + + foo(pgdat); + } + +节点数据结构 +------------ + +节点结构 ``struct pglist_data`` 在 ``include/linux/mmzone.h`` +中声明。这里我们将简要描述这个结构体的字段: + +通用字段 +~~~~~~~~ + +``node_zones`` +表示该节点的区域列表。并非所有区域都可能被填充,但这是 +完整的列表。它被该节点的node_zonelists以及其它节点的 +node_zonelists引用。 + +``node_zonelists`` +表示所有节点中所有区域的列表。此列表定义了分配内存时首选的区域 +顺序。``node_zonelists`` 在核心内存管理结构初始化期间, +由 ``mm/page_alloc.c`` 中的 ``build_zonelists()`` +函数设置。 + +``nr_zones`` +表示此节点中已填充区域的数量。 + +``node_mem_map`` +对于使用FLATMEM内存模型的UMA系统,0号节点的 ``node_mem_map`` +表示每个物理帧的struct pages数组。 + +``node_page_ext`` +对于使用FLATMEM内存模型的UMA系统,0号节点的 ``node_page_ext`` +是struct pages的扩展数组。只有在构建时开启了 ``CONFIG_PAGE_EXTENSION`` +选项的内核中才可用。 + +``node_start_pfn`` +表示此节点中起始页面帧的页面帧号。 + +``node_present_pages`` +表示此节点中存在的物理页面的总数。 + +``node_spanned_pages`` +表示包括空洞在内的物理页面范围的总大小。 + +``node_size_lock`` +一个保护定义节点范围字段的锁。仅在开启了 ``CONFIG_MEMORY_HOTPLUG`` 或 +``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` 配置选项中的某一个时才定义。提 +供了 ``pgdat_resize_lock()`` 和 ``pgdat_resize_unlock()`` 用来操作 +``node_size_lock``,而无需检查 ``CONFIG_MEMORY_HOTPLUG`` 或 +``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` 选项。 + +``node_id`` +节点的节点ID(NID),从0开始。 + +``totalreserve_pages`` +这是每个节点保留的页面,这些页面不可用于用户空间分配。 + +``first_deferred_pfn`` +如果大型机器上的内存初始化被推迟,那么第一个PFN(页帧号)是需要初始化的。 +在开启了 ``CONFIG_DEFERRED_STRUCT_PAGE_INIT`` 选项时定义。 + +``deferred_split_queue`` +每个节点的大页队列,这些大页的拆分被推迟了。仅在开启了 ``CONFIG_TRANSPARENT_HUGEPAGE`` +配置选项时定义。 + +``__lruvec`` +每个节点的lruvec持有LRU(最近最少使用)列表和相关参数。仅在禁用了内存 +控制组(cgroups)时使用。它不应该直接访问,而应该使用 ``mem_cgroup_lruvec()`` +来查找lruvecs。 + +回收控制 +~~~~~~~~ + +另见内核文档 Documentation/mm/page_reclaim.rst 文件。 + +``kswapd`` +每个节点的kswapd内核线程实例。 + +``kswapd_wait``, ``pfmemalloc_wait``, ``reclaim_wait`` +同步内存回收任务的工作队列。 + +``nr_writeback_throttled`` +等待写回脏页时,被限制的任务数量。 + +``kswapd_order`` +控制kswapd尝试回收的order。 + +``kswapd_highest_zoneidx`` +kswapd线程可以回收的最高区域索引。 + +``kswapd_failures`` +kswapd无法回收任何页面的运行次数。 + +``min_unmapped_pages`` +无法回收的未映射文件支持的最小页面数量。由 ``vm.min_unmapped_ratio`` +系统控制台(sysctl)参数决定。在开启 ``CONFIG_NUMA`` 配置时定义。 + +``min_slab_pages`` +无法回收的SLAB页面的最少数量。由 ``vm.min_slab_ratio`` 系统控制台 +(sysctl)参数决定。在开启 ``CONFIG_NUMA`` 时定义。 + +``flags`` +控制回收行为的标志位。 + +内存压缩控制 +~~~~~~~~~~~~ + +``kcompactd_max_order`` +kcompactd应尝试实现的页面order。 + +``kcompactd_highest_zoneidx`` +kcompactd可以压缩的最高区域索引。 + +``kcompactd_wait`` +同步内存压缩任务的工作队列。 + +``kcompactd`` +每个节点的kcompactd内核线程实例。 + +``proactive_compact_trigger`` +决定是否使用主动压缩。由 ``vm.compaction_proactiveness`` 系统控 +制台(sysctl)参数控制。 + +统计信息 +~~~~~~~~ + +``per_cpu_nodestats`` +表示节点的Per-CPU虚拟内存统计信息。 + +``vm_stat`` +表示节点的虚拟内存统计数据。 + +.. _zones_zh_CN: + +区域 +==== + +.. admonition:: Stub + + 本节内容不完整。请列出并描述相应的字段。 + +.. _pages_zh_CN: + +页 +==== + +.. admonition:: Stub + + 本节内容不完整。请列出并描述相应的字段。 + +.. _folios_zh_CN: + +页码 +==== + +.. admonition:: Stub + + 本节内容不完整。请列出并描述相应的字段。 + +.. _initialization_zh_CN: + +初始化 +====== + +.. admonition:: Stub + + 本节内容不完整。请列出并描述相应的字段。 diff --git a/Documentation/translations/zh_CN/process/5.Posting.rst b/Documentation/translations/zh_CN/process/5.Posting.rst index 6a469e1c7debb7..6c83a8f40310c2 100644 --- a/Documentation/translations/zh_CN/process/5.Posting.rst +++ b/Documentation/translations/zh_CN/process/5.Posting.rst @@ -146,10 +146,6 @@ - 补丁本身,采用统一的(“-u”)补丁格式。使用“-p”选项来diff将使函数名与 更改相关联,从而使结果补丁更容易被其他人读取。 -您应该避免在补丁中包括与更改不相关文件(例如,构建过程生成的文件或编辑器 -备份文件)。文档目录中的“dontdiff”文件在这方面有帮助;使用“-X”选项将 -其传递给diff。 - 上面提到的标签(tag)用于描述各种开发人员如何与这个补丁的开发相关联。 :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst ` 文档中对它们进行了详细描述;下面是一个简短的总结。每一行的格式如下: diff --git a/Documentation/translations/zh_CN/process/coding-style.rst b/Documentation/translations/zh_CN/process/coding-style.rst index 10b9cb4f6a650b..0484d0c65c25be 100644 --- a/Documentation/translations/zh_CN/process/coding-style.rst +++ b/Documentation/translations/zh_CN/process/coding-style.rst @@ -560,17 +560,6 @@ Documentation/translations/zh_CN/doc-guide/index.rst 和 scripts/kernel-doc 。 * with beginning and ending almost-blank lines. */ -对于在 net/ 和 drivers/net/ 的文件,首选的长 (多行) 注释风格有些不同。 - -.. code-block:: c - - /* The preferred comment style for files in net/ and drivers/net - * looks like this. - * - * It is nearly the same as the generally preferred comment style, - * but there is no initial almost-blank line. - */ - 注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行 应只声明一个数据 (不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据 写一段小注释来解释它们的用途了。 diff --git a/Documentation/translations/zh_CN/process/email-clients.rst b/Documentation/translations/zh_CN/process/email-clients.rst index 34d51cdadc7b1e..a70393089df3df 100644 --- a/Documentation/translations/zh_CN/process/email-clients.rst +++ b/Documentation/translations/zh_CN/process/email-clients.rst @@ -197,7 +197,7 @@ Mutt不自带编辑器,所以不管你使用什么编辑器,不自动断行 Mutt 是高度可配置的。 这里是个使用mutt通过 Gmail 发送的补丁的最小配置:: # .muttrc - # ================ IMAP ==================== + # ================ IMAP ==================== set imap_user = 'yourusername@gmail.com' set imap_pass = 'yourpassword' set spoolfile = imaps://imap.gmail.com/INBOX @@ -325,3 +325,10 @@ Gmail网页客户端自动地把制表符转换为空格。 另一个问题是Gmail还会把任何含有非ASCII的字符的消息改用base64编码,如欧洲人的 名字。 +HacKerMaiL (TUI) +**************** + +HacKerMaiL (hkml) 是一个基于公共收件箱的简单邮件管理工具,它不需要订阅邮件列表。 +该工具由 DAMON 维护者开发和维护,旨在支持 DAMON 和通用内核子系统的基本开发工作 +流程。详细信息可参考 HacKerMaiL 的 README 文件 +(https://github.com/sjp38/hackermail/blob/master/README.md)。 diff --git a/Documentation/translations/zh_CN/process/programming-language.rst b/Documentation/translations/zh_CN/process/programming-language.rst index fabdc338dbfbc9..95aa4829d78f55 100644 --- a/Documentation/translations/zh_CN/process/programming-language.rst +++ b/Documentation/translations/zh_CN/process/programming-language.rst @@ -3,25 +3,22 @@ :Original: :ref:`Documentation/process/programming-language.rst ` :Translator: Alex Shi -.. _cn_programming_language: - 程序设计语言 ============ -内核是用C语言 :ref:`c-language ` 编写的。更准确地说,内核通常是用 :ref:`gcc ` -在 ``-std=gnu11`` :ref:`gcc-c-dialect-options ` 下编译的:ISO C11的 GNU 方言 - -这种方言包含对语言 :ref:`gnu-extensions ` 的许多扩展,当然,它们许多都在内核中使用。 +内核是用 C 编程语言编写的 [zh_cn_c-language]_。更准确地说,内核通常使用 ``gcc`` [zh_cn_gcc]_ 编译, +并且使用 ``-std=gnu11`` [zh_cn_gcc-c-dialect-options]_:这是 ISO C11 的 GNU 方言。 +``clang`` [zh_cn_clang]_ 也得到了支持,详见文档: +:ref:`使用 Clang/LLVM 构建 Linux `。 -对于一些体系结构,有一些使用 :ref:`clang ` 和 :ref:`icc ` 编译内核 -的支持,尽管在编写此文档时还没有完成,仍需要第三方补丁。 +这种方言包含对 C 语言的许多扩展 [zh_cn_gnu-extensions]_,当然,它们许多都在内核中使用。 属性 ---- -在整个内核中使用的一个常见扩展是属性(attributes) :ref:`gcc-attribute-syntax ` +在整个内核中使用的一个常见扩展是属性(attributes) [zh_cn_gcc-attribute-syntax]_。 属性允许将实现定义的语义引入语言实体(如变量、函数或类型),而无需对语言进行 -重大的语法更改(例如添加新关键字) :ref:`n2049 ` +重大的语法更改(例如添加新关键字) [zh_cn_n2049]_。 在某些情况下,属性是可选的(即不支持这些属性的编译器仍然应该生成正确的代码, 即使其速度较慢或执行的编译时检查/诊断次数不够) @@ -30,42 +27,27 @@ ``__attribute__((__pure__))`` ),以检测可以使用哪些关键字和/或缩短代码, 具体 请参阅 ``include/linux/compiler_attributes.h`` -.. _cn_c-language: - -c-language - http://www.open-std.org/jtc1/sc22/wg14/www/standards - -.. _cn_gcc: - -gcc - https://gcc.gnu.org - -.. _cn_clang: - -clang - https://clang.llvm.org - -.. _cn_icc: - -icc - https://software.intel.com/en-us/c-compilers - -.. _cn_gcc-c-dialect-options: - -c-dialect-options - https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html - -.. _cn_gnu-extensions: - -gnu-extensions - https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html - -.. _cn_gcc-attribute-syntax: - -gcc-attribute-syntax - https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html - -.. _cn_n2049: +Rust +---- -n2049 - http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf +内核对 Rust 编程语言 [zh_cn_rust-language]_ 的支持是实验性的,并且可以通过配置选项 +``CONFIG_RUST`` 来启用。Rust 代码使用 ``rustc`` [zh_cn_rustc]_ 编译器在 +``--edition=2021`` [zh_cn_rust-editions]_ 选项下进行编译。版本(Editions)是一种 +在语言中引入非后向兼容的小型变更的方式。 + +除此之外,内核中还使用了一些不稳定的特性 [zh_cn_rust-unstable-features]_。这些不稳定 +的特性将来可能会发生变化,因此,一个重要的目标是达到仅使用稳定特性的程度。 + +具体请参阅 Documentation/rust/index.rst + +.. [zh_cn_c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards +.. [zh_cn_gcc] https://gcc.gnu.org +.. [zh_cn_clang] https://clang.llvm.org +.. [zh_cn_gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html +.. [zh_cn_gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html +.. [zh_cn_gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html +.. [zh_cn_n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf +.. [zh_cn_rust-language] https://www.rust-lang.org +.. [zh_cn_rustc] https://doc.rust-lang.org/rustc/ +.. [zh_cn_rust-editions] https://doc.rust-lang.org/edition-guide/editions/ +.. [zh_cn_rust-unstable-features] https://github.com/Rust-for-Linux/linux/issues/2 diff --git a/Documentation/translations/zh_CN/process/submitting-patches.rst b/Documentation/translations/zh_CN/process/submitting-patches.rst index 7ca16bda37092a..f7ae584a439efb 100644 --- a/Documentation/translations/zh_CN/process/submitting-patches.rst +++ b/Documentation/translations/zh_CN/process/submitting-patches.rst @@ -105,7 +105,7 @@ xyzzy do frotz”或“[I]changed xyzzy to do frotz”,就好像你在命令 当链接到邮件列表存档时,请首选lore.kernel.org邮件存档服务。用邮件中的 ``Message-ID`` 头(去掉尖括号)可以创建链接URL。例如:: - Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/ + Link: https://lore.kernel.org/30th.anniversary.repost@klaava.Helsinki.FI 请检查该链接以确保可用且指向正确的邮件。 @@ -195,11 +195,8 @@ scripts/get_maintainer.pl在这个步骤中非常有用。如果您找不到正 在MAINTAINERS文件中查找子系统特定的列表;您的补丁可能会在那里得到更多的关注。 不过,请不要发送垃圾邮件到无关的列表。 -许多与内核相关的列表托管在vger.kernel.org上;您可以在 -http://vger.kernel.org/vger-lists.html 上找到它们的列表。不过,也有与内核相关 -的列表托管在其他地方。 - -不要一次发送超过15个补丁到vger邮件列表!!!! +许多与内核相关的列表托管在 kernel.org 上;您可以在 https://subspace.kernel.org +上找到它们的列表。不过,也有与内核相关的列表托管在其他地方。 Linus Torvalds是决定改动能否进入 Linux 内核的最终裁决者。他的邮件地址是 torvalds@linux-foundation.org 。他收到的邮件很多,所以一般来说最好 **别** @@ -621,6 +618,13 @@ Fixes: 指示补丁修复了之前提交的一个问题。它可以便于确定 的工作所基于的树的提交哈希。你应该在封面邮件或系列的第一个补丁中添加它,它应 该放在 ``---`` 行的下面或所有其他内容之后,即只在你的电子邮件签名之前。 +工具 +---- + +这个过程的许多技术方面可以使用 b4 自动完成,其文档可在 +https://b4.docs.kernel.org/en/latest/ 查看。该工具可帮助处理诸如追踪依赖项、运行 +checkpatch 以及格式化和发送邮件等事务。 + 参考文献 -------- @@ -643,9 +647,6 @@ Greg Kroah-Hartman,“如何惹恼内核子系统维护人员” -不!!!别再发巨型补丁炸弹给linux-kernel@vger.kernel.org的人们了! - - 内核 Documentation/translations/zh_CN/process/coding-style.rst Linus Torvalds关于标准补丁格式的邮件 diff --git a/Documentation/translations/zh_TW/dev-tools/gcov.rst b/Documentation/translations/zh_TW/dev-tools/gcov.rst index ce1c9a97de16c4..39ac3fff44cdb9 100644 --- a/Documentation/translations/zh_TW/dev-tools/gcov.rst +++ b/Documentation/translations/zh_TW/dev-tools/gcov.rst @@ -120,7 +120,7 @@ gcov的內核分析插樁支持內核的編譯和運行是在同一臺機器上 如果內核編譯和運行是不同的機器,那麼需要額外的準備工作,這取決於gcov工具 是在哪裏使用的: -.. _gcov-test_zh: +.. _gcov-test_zh_TW: a) 若gcov運行在測試機上 @@ -140,7 +140,7 @@ a) 若gcov運行在測試機上 如果文件是軟鏈接,需要替換成真正的目錄文件(這是由make的當前工作 目錄變量CURDIR引起的)。 -.. _gcov-build_zh: +.. _gcov-build_zh_TW: b) 若gcov運行在編譯機上 @@ -205,7 +205,7 @@ kconfig會根據編譯工具鏈的檢查自動選擇合適的gcov格式。 -------------------------- 用於在編譯機上收集覆蓋率元文件的示例腳本 -(見 :ref:`編譯機和測試機分離 a. ` ) +(見 :ref:`編譯機和測試機分離 a. ` ) .. code-block:: sh @@ -238,7 +238,7 @@ kconfig會根據編譯工具鏈的檢查自動選擇合適的gcov格式。 ------------------------- 用於在測試機上收集覆蓋率數據文件的示例腳本 -(見 :ref:`編譯機和測試機分離 b. ` ) +(見 :ref:`編譯機和測試機分離 b. ` ) .. code-block:: sh diff --git a/Documentation/translations/zh_TW/dev-tools/kasan.rst b/Documentation/translations/zh_TW/dev-tools/kasan.rst index ed342e67d8ed02..27fb7645174d0e 100644 --- a/Documentation/translations/zh_TW/dev-tools/kasan.rst +++ b/Documentation/translations/zh_TW/dev-tools/kasan.rst @@ -404,16 +404,13 @@ KASAN連接到vmap基礎架構以懶清理未使用的影子內存。 ~~~~ 有一些KASAN測試可以驗證KASAN是否正常工作並可以檢測某些類型的內存損壞。 -測試由兩部分組成: -1. 與KUnit測試框架集成的測試。使用 ``CONFIG_KASAN_KUNIT_TEST`` 啓用。 -這些測試可以通過幾種不同的方式自動運行和部分驗證;請參閱下面的說明。 +所有 KASAN 測試均與 KUnit 測試框架集成,並且可以啟用 +透過 ``CONFIG_KASAN_KUNIT_TEST``。可以運行測試並進行部分驗證 +以幾種不同的方式自動進行;請參閱下面的說明。 -2. 與KUnit不兼容的測試。使用 ``CONFIG_KASAN_MODULE_TEST`` 啓用並且只能作爲模塊 -運行。這些測試只能通過加載內核模塊並檢查內核日誌以獲取KASAN報告來手動驗證。 - -如果檢測到錯誤,每個KUnit兼容的KASAN測試都會打印多個KASAN報告之一,然後測試打印 -其編號和狀態。 +如果偵測到錯誤,每個 KASAN 測試都會列印多個 KASAN 報告之一。 +然後測試列印其編號和狀態。 當測試通過:: @@ -440,16 +437,16 @@ KASAN連接到vmap基礎架構以懶清理未使用的影子內存。 not ok 1 - kasan -有幾種方法可以運行與KUnit兼容的KASAN測試。 +有幾種方法可以執行 KASAN 測試。 1. 可加載模塊 - 啓用 ``CONFIG_KUNIT`` 後,KASAN-KUnit測試可以構建爲可加載模塊,並通過使用 - ``insmod`` 或 ``modprobe`` 加載 ``kasan_test.ko`` 來運行。 + 啟用 ``CONFIG_KUNIT`` 後,測試可以建置為可載入模組 + 並且透過使用 ``insmod`` 或 ``modprobe`` 來載入 ``kasan_test.ko`` 來運作。 2. 內置 - 通過內置 ``CONFIG_KUNIT`` ,也可以內置KASAN-KUnit測試。在這種情況下, + 透過內建 ``CONFIG_KUNIT``,測試也可以內建。 測試將在啓動時作爲後期初始化調用運行。 3. 使用kunit_tool diff --git a/Documentation/translations/zh_TW/process/5.Posting.rst b/Documentation/translations/zh_TW/process/5.Posting.rst index 7d66a1c638be1c..38f3a6d618ebfc 100644 --- a/Documentation/translations/zh_TW/process/5.Posting.rst +++ b/Documentation/translations/zh_TW/process/5.Posting.rst @@ -149,10 +149,6 @@ - 補丁本身,採用統一的(“-u”)補丁格式。使用“-p”選項來diff將使函數名與 更改相關聯,從而使結果補丁更容易被其他人讀取。 -您應該避免在補丁中包括與更改不相關文件(例如,構建過程生成的文件或編輯器 -備份文件)。文檔目錄中的“dontdiff”文件在這方面有幫助;使用“-X”選項將 -其傳遞給diff。 - 上面提到的標籤(tag)用於描述各種開發人員如何與這個補丁的開發相關聯。 :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst ` 文檔中對它們進行了詳細描述;下面是一個簡短的總結。每一行的格式如下: diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index e4be1378ba26dc..243f1f1b554a22 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -375,7 +375,7 @@ Code Seq# Include File Comments 0xCB 00-1F CBM serial IEC bus in development: 0xCC 00-0F drivers/misc/ibmvmc.h pseries VMC driver -0xCD 01 linux/reiserfs_fs.h +0xCD 01 linux/reiserfs_fs.h Dead since 6.13 0xCE 01-02 uapi/linux/cxl_mem.h Compute Express Link Memory Devices 0xCF 02 fs/smb/client/cifs_ioctl.h 0xDB 00-0F drivers/char/mwave/mwavepub.h diff --git a/Documentation/userspace-api/iommufd.rst b/Documentation/userspace-api/iommufd.rst index aa004faed5fdb2..70289d6815d2ae 100644 --- a/Documentation/userspace-api/iommufd.rst +++ b/Documentation/userspace-api/iommufd.rst @@ -41,46 +41,133 @@ Following IOMMUFD objects are exposed to userspace: - IOMMUFD_OBJ_DEVICE, representing a device that is bound to iommufd by an external driver. -- IOMMUFD_OBJ_HW_PAGETABLE, representing an actual hardware I/O page table - (i.e. a single struct iommu_domain) managed by the iommu driver. - - The IOAS has a list of HW_PAGETABLES that share the same IOVA mapping and - it will synchronize its mapping with each member HW_PAGETABLE. +- IOMMUFD_OBJ_HWPT_PAGING, representing an actual hardware I/O page table + (i.e. a single struct iommu_domain) managed by the iommu driver. "PAGING" + primarly indicates this type of HWPT should be linked to an IOAS. It also + indicates that it is backed by an iommu_domain with __IOMMU_DOMAIN_PAGING + feature flag. This can be either an UNMANAGED stage-1 domain for a device + running in the user space, or a nesting parent stage-2 domain for mappings + from guest-level physical addresses to host-level physical addresses. + + The IOAS has a list of HWPT_PAGINGs that share the same IOVA mapping and + it will synchronize its mapping with each member HWPT_PAGING. + +- IOMMUFD_OBJ_HWPT_NESTED, representing an actual hardware I/O page table + (i.e. a single struct iommu_domain) managed by user space (e.g. guest OS). + "NESTED" indicates that this type of HWPT should be linked to an HWPT_PAGING. + It also indicates that it is backed by an iommu_domain that has a type of + IOMMU_DOMAIN_NESTED. This must be a stage-1 domain for a device running in + the user space (e.g. in a guest VM enabling the IOMMU nested translation + feature.) As such, it must be created with a given nesting parent stage-2 + domain to associate to. This nested stage-1 page table managed by the user + space usually has mappings from guest-level I/O virtual addresses to guest- + level physical addresses. + +- IOMMUFD_OBJ_VIOMMU, representing a slice of the physical IOMMU instance, + passed to or shared with a VM. It may be some HW-accelerated virtualization + features and some SW resources used by the VM. For examples: + + * Security namespace for guest owned ID, e.g. guest-controlled cache tags + * Non-device-affiliated event reporting, e.g. invalidation queue errors + * Access to a sharable nesting parent pagetable across physical IOMMUs + * Virtualization of various platforms IDs, e.g. RIDs and others + * Delivery of paravirtualized invalidation + * Direct assigned invalidation queues + * Direct assigned interrupts + + Such a vIOMMU object generally has the access to a nesting parent pagetable + to support some HW-accelerated virtualization features. So, a vIOMMU object + must be created given a nesting parent HWPT_PAGING object, and then it would + encapsulate that HWPT_PAGING object. Therefore, a vIOMMU object can be used + to allocate an HWPT_NESTED object in place of the encapsulated HWPT_PAGING. + + .. note:: + + The name "vIOMMU" isn't necessarily identical to a virtualized IOMMU in a + VM. A VM can have one giant virtualized IOMMU running on a machine having + multiple physical IOMMUs, in which case the VMM will dispatch the requests + or configurations from this single virtualized IOMMU instance to multiple + vIOMMU objects created for individual slices of different physical IOMMUs. + In other words, a vIOMMU object is always a representation of one physical + IOMMU, not necessarily of a virtualized IOMMU. For VMMs that want the full + virtualization features from physical IOMMUs, it is suggested to build the + same number of virtualized IOMMUs as the number of physical IOMMUs, so the + passed-through devices would be connected to their own virtualized IOMMUs + backed by corresponding vIOMMU objects, in which case a guest OS would do + the "dispatch" naturally instead of VMM trappings. + +- IOMMUFD_OBJ_VDEVICE, representing a virtual device for an IOMMUFD_OBJ_DEVICE + against an IOMMUFD_OBJ_VIOMMU. This virtual device holds the device's virtual + information or attributes (related to the vIOMMU) in a VM. An immediate vDATA + example can be the virtual ID of the device on a vIOMMU, which is a unique ID + that VMM assigns to the device for a translation channel/port of the vIOMMU, + e.g. vSID of ARM SMMUv3, vDeviceID of AMD IOMMU, and vRID of Intel VT-d to a + Context Table. Potential use cases of some advanced security information can + be forwarded via this object too, such as security level or realm information + in a Confidential Compute Architecture. A VMM should create a vDEVICE object + to forward all the device information in a VM, when it connects a device to a + vIOMMU, which is a separate ioctl call from attaching the same device to an + HWPT_PAGING that the vIOMMU holds. All user-visible objects are destroyed via the IOMMU_DESTROY uAPI. -The diagram below shows relationship between user-visible objects and kernel +The diagrams below show relationships between user-visible objects and kernel datastructures (external to iommufd), with numbers referred to operations creating the objects and links:: - _________________________________________________________ - | iommufd | - | [1] | - | _________________ | - | | | | - | | | | - | | | | - | | | | - | | | | - | | | | - | | | [3] [2] | - | | | ____________ __________ | - | | IOAS |<--| |<------| | | - | | | |HW_PAGETABLE| | DEVICE | | - | | | |____________| |__________| | - | | | | | | - | | | | | | - | | | | | | - | | | | | | - | | | | | | - | |_________________| | | | - | | | | | - |_________|___________________|___________________|_______| - | | | - | _____v______ _______v_____ - | PFN storage | | | | - |------------>|iommu_domain| |struct device| - |____________| |_____________| + _______________________________________________________________________ + | iommufd (HWPT_PAGING only) | + | | + | [1] [3] [2] | + | ________________ _____________ ________ | + | | | | | | | | + | | IOAS |<---| HWPT_PAGING |<---------------------| DEVICE | | + | |________________| |_____________| |________| | + | | | | | + |_________|____________________|__________________________________|_____| + | | | + | ______v_____ ___v__ + | PFN storage | (paging) | |struct| + |------------>|iommu_domain|<-----------------------|device| + |____________| |______| + + _______________________________________________________________________ + | iommufd (with HWPT_NESTED) | + | | + | [1] [3] [4] [2] | + | ________________ _____________ _____________ ________ | + | | | | | | | | | | + | | IOAS |<---| HWPT_PAGING |<---| HWPT_NESTED |<--| DEVICE | | + | |________________| |_____________| |_____________| |________| | + | | | | | | + |_________|____________________|__________________|_______________|_____| + | | | | + | ______v_____ ______v_____ ___v__ + | PFN storage | (paging) | | (nested) | |struct| + |------------>|iommu_domain|<----|iommu_domain|<----|device| + |____________| |____________| |______| + + _______________________________________________________________________ + | iommufd (with vIOMMU/vDEVICE) | + | | + | [5] [6] | + | _____________ _____________ | + | | | | | | + | |----------------| vIOMMU |<---| vDEVICE |<----| | + | | | | |_____________| | | + | | | | | | + | | [1] | | [4] | [2] | + | | ______ | | _____________ _|______ | + | | | | | [3] | | | | | | + | | | IOAS |<---|(HWPT_PAGING)|<---| HWPT_NESTED |<--| DEVICE | | + | | |______| |_____________| |_____________| |________| | + | | | | | | | + |______|________|______________|__________________|_______________|_____| + | | | | | + ______v_____ | ______v_____ ______v_____ ___v__ + | struct | | PFN | (paging) | | (nested) | |struct| + |iommu_device| |------>|iommu_domain|<----|iommu_domain|<----|device| + |____________| storage|____________| |____________| |______| 1. IOMMUFD_OBJ_IOAS is created via the IOMMU_IOAS_ALLOC uAPI. An iommufd can hold multiple IOAS objects. IOAS is the most generic object and does not @@ -94,21 +181,63 @@ creating the objects and links:: device. The driver must also set the driver_managed_dma flag and must not touch the device until this operation succeeds. -3. IOMMUFD_OBJ_HW_PAGETABLE is created when an external driver calls the IOMMUFD - kAPI to attach a bound device to an IOAS. Similarly the external driver uAPI - allows userspace to initiate the attaching operation. If a compatible - pagetable already exists then it is reused for the attachment. Otherwise a - new pagetable object and iommu_domain is created. Successful completion of - this operation sets up the linkages among IOAS, device and iommu_domain. Once - this completes the device could do DMA. - - Every iommu_domain inside the IOAS is also represented to userspace as a - HW_PAGETABLE object. +3. IOMMUFD_OBJ_HWPT_PAGING can be created in two ways: + + * IOMMUFD_OBJ_HWPT_PAGING is automatically created when an external driver + calls the IOMMUFD kAPI to attach a bound device to an IOAS. Similarly the + external driver uAPI allows userspace to initiate the attaching operation. + If a compatible member HWPT_PAGING object exists in the IOAS's HWPT_PAGING + list, then it will be reused. Otherwise a new HWPT_PAGING that represents + an iommu_domain to userspace will be created, and then added to the list. + Successful completion of this operation sets up the linkages among IOAS, + device and iommu_domain. Once this completes the device could do DMA. + + * IOMMUFD_OBJ_HWPT_PAGING can be manually created via the IOMMU_HWPT_ALLOC + uAPI, provided an ioas_id via @pt_id to associate the new HWPT_PAGING to + the corresponding IOAS object. The benefit of this manual allocation is to + allow allocation flags (defined in enum iommufd_hwpt_alloc_flags), e.g. it + allocates a nesting parent HWPT_PAGING if the IOMMU_HWPT_ALLOC_NEST_PARENT + flag is set. + +4. IOMMUFD_OBJ_HWPT_NESTED can be only manually created via the IOMMU_HWPT_ALLOC + uAPI, provided an hwpt_id or a viommu_id of a vIOMMU object encapsulating a + nesting parent HWPT_PAGING via @pt_id to associate the new HWPT_NESTED object + to the corresponding HWPT_PAGING object. The associating HWPT_PAGING object + must be a nesting parent manually allocated via the same uAPI previously with + an IOMMU_HWPT_ALLOC_NEST_PARENT flag, otherwise the allocation will fail. The + allocation will be further validated by the IOMMU driver to ensure that the + nesting parent domain and the nested domain being allocated are compatible. + Successful completion of this operation sets up linkages among IOAS, device, + and iommu_domains. Once this completes the device could do DMA via a 2-stage + translation, a.k.a nested translation. Note that multiple HWPT_NESTED objects + can be allocated by (and then associated to) the same nesting parent. .. note:: - Future IOMMUFD updates will provide an API to create and manipulate the - HW_PAGETABLE directly. + Either a manual IOMMUFD_OBJ_HWPT_PAGING or an IOMMUFD_OBJ_HWPT_NESTED is + created via the same IOMMU_HWPT_ALLOC uAPI. The difference is at the type + of the object passed in via the @pt_id field of struct iommufd_hwpt_alloc. + +5. IOMMUFD_OBJ_VIOMMU can be only manually created via the IOMMU_VIOMMU_ALLOC + uAPI, provided a dev_id (for the device's physical IOMMU to back the vIOMMU) + and an hwpt_id (to associate the vIOMMU to a nesting parent HWPT_PAGING). The + iommufd core will link the vIOMMU object to the struct iommu_device that the + struct device is behind. And an IOMMU driver can implement a viommu_alloc op + to allocate its own vIOMMU data structure embedding the core-level structure + iommufd_viommu and some driver-specific data. If necessary, the driver can + also configure its HW virtualization feature for that vIOMMU (and thus for + the VM). Successful completion of this operation sets up the linkages between + the vIOMMU object and the HWPT_PAGING, then this vIOMMU object can be used + as a nesting parent object to allocate an HWPT_NESTED object described above. + +6. IOMMUFD_OBJ_VDEVICE can be only manually created via the IOMMU_VDEVICE_ALLOC + uAPI, provided a viommu_id for an iommufd_viommu object and a dev_id for an + iommufd_device object. The vDEVICE object will be the binding between these + two parent objects. Another @virt_id will be also set via the uAPI providing + the iommufd core an index to store the vDEVICE object to a vDEVICE array per + vIOMMU. If necessary, the IOMMU driver may choose to implement a vdevce_alloc + op to init its HW for virtualization feature related to a vDEVICE. Successful + completion of this operation sets up the linkages between vIOMMU and device. A device can only bind to an iommufd due to DMA ownership claim and attach to at most one IOAS object (no support of PASID yet). @@ -120,7 +249,10 @@ User visible objects are backed by following datastructures: - iommufd_ioas for IOMMUFD_OBJ_IOAS. - iommufd_device for IOMMUFD_OBJ_DEVICE. -- iommufd_hw_pagetable for IOMMUFD_OBJ_HW_PAGETABLE. +- iommufd_hwpt_paging for IOMMUFD_OBJ_HWPT_PAGING. +- iommufd_hwpt_nested for IOMMUFD_OBJ_HWPT_NESTED. +- iommufd_viommu for IOMMUFD_OBJ_VIOMMU. +- iommufd_vdevice for IOMMUFD_OBJ_VDEVICE. Several terminologies when looking at these datastructures: diff --git a/Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst b/Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst index 2979752acbcd29..a94750d00898c4 100644 --- a/Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst +++ b/Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst @@ -27,7 +27,7 @@ Arguments File descriptor returned by open(). ``duty_cycle`` - Duty cicle, describing the pulse width in percent (from 1 to 99) of + Duty cycle, describing the pulse width in percent (from 1 to 99) of the total cycle. Values 0 and 100 are reserved. Description diff --git a/Documentation/userspace-api/media/v4l/control.rst b/Documentation/userspace-api/media/v4l/control.rst index 57893814a1e5d9..9253cc946f02af 100644 --- a/Documentation/userspace-api/media/v4l/control.rst +++ b/Documentation/userspace-api/media/v4l/control.rst @@ -290,13 +290,15 @@ Control IDs This is a read-only control that can be read by the application and used as a hint to determine the number of CAPTURE buffers to pass to REQBUFS. The value is the minimum number of CAPTURE buffers that is - necessary for hardware to work. + necessary for hardware to work. This control is required for stateful + decoders. ``V4L2_CID_MIN_BUFFERS_FOR_OUTPUT`` ``(integer)`` This is a read-only control that can be read by the application and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS. The value is the minimum number of OUTPUT buffers that is - necessary for hardware to work. + necessary for hardware to work. This control is required for stateful + encoders. .. _v4l2-alpha-component: diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Documentation/userspace-api/media/v4l/meta-formats.rst index c6e56b5888bc9d..86ffb3bc8ade2e 100644 --- a/Documentation/userspace-api/media/v4l/meta-formats.rst +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst @@ -16,6 +16,7 @@ These formats are used for the :ref:`metadata` interface only. metafmt-generic metafmt-intel-ipu3 metafmt-pisp-be + metafmt-pisp-fe metafmt-rkisp1 metafmt-uvc metafmt-vivid diff --git a/Documentation/userspace-api/media/v4l/metafmt-pisp-fe.rst b/Documentation/userspace-api/media/v4l/metafmt-pisp-fe.rst new file mode 100644 index 00000000000000..fddeada83e4afb --- /dev/null +++ b/Documentation/userspace-api/media/v4l/metafmt-pisp-fe.rst @@ -0,0 +1,39 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _v4l2-meta-fmt-rpi-fe-cfg: + +************************ +V4L2_META_FMT_RPI_FE_CFG +************************ + +Raspberry Pi PiSP Front End configuration format +================================================ + +The Raspberry Pi PiSP Front End image signal processor is configured by +userspace by providing a buffer of configuration parameters to the +`rp1-cfe-fe-config` output video device node using the +:c:type:`v4l2_meta_format` interface. + +The `Raspberry Pi PiSP technical specification +`_ +provide detailed description of the Front End configuration and programming +model. + +.. _v4l2-meta-fmt-rpi-fe-stats: + +************************** +V4L2_META_FMT_RPI_FE_STATS +************************** + +Raspberry Pi PiSP Front End statistics format +============================================= + +The Raspberry Pi PiSP Front End image signal processor provides statistics data +by writing to a buffer provided via the `rp1-cfe-fe-stats` capture video device +node using the +:c:type:`v4l2_meta_format` interface. + +The `Raspberry Pi PiSP technical specification +`_ +provide detailed description of the Front End configuration and programming +model. diff --git a/Documentation/userspace-api/media/v4l/pixfmt-y16i.rst b/Documentation/userspace-api/media/v4l/pixfmt-y16i.rst new file mode 100644 index 00000000000000..74ba9e910a38f7 --- /dev/null +++ b/Documentation/userspace-api/media/v4l/pixfmt-y16i.rst @@ -0,0 +1,73 @@ +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later + +.. _V4L2-PIX-FMT-Y16I: + +************************** +V4L2_PIX_FMT_Y16I ('Y16I') +************************** + +Interleaved grey-scale image, e.g. from a stereo-pair + + +Description +=========== + +This is a grey-scale image with a depth of 16 bits per pixel, but with pixels +from 2 sources interleaved and unpacked. Each pixel is stored in a 16-bit word +in the little-endian order. The first pixel is from the left source. + +**Pixel unpacked representation.** +Left/Right pixels 16-bit unpacked - 16-bit for each interleaved pixel. + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - Y'\ :sub:`0L[7:0]` + - Y'\ :sub:`0L[15:8]` + - Y'\ :sub:`0R[7:0]` + - Y'\ :sub:`0R[15:8]` + +**Byte Order.** +Each cell is one byte. + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - Y'\ :sub:`00Llow` + - Y'\ :sub:`00Lhigh` + - Y'\ :sub:`00Rlow` + - Y'\ :sub:`00Rhigh` + - Y'\ :sub:`01Llow` + - Y'\ :sub:`01Lhigh` + - Y'\ :sub:`01Rlow` + - Y'\ :sub:`01Rhigh` + * - start + 8: + - Y'\ :sub:`10Llow` + - Y'\ :sub:`10Lhigh` + - Y'\ :sub:`10Rlow` + - Y'\ :sub:`10Rhigh` + - Y'\ :sub:`11Llow` + - Y'\ :sub:`11Lhigh` + - Y'\ :sub:`11Rlow` + - Y'\ :sub:`11Rhigh` + * - start + 16: + - Y'\ :sub:`20Llow` + - Y'\ :sub:`20Lhigh` + - Y'\ :sub:`20Rlow` + - Y'\ :sub:`20Rhigh` + - Y'\ :sub:`21Llow` + - Y'\ :sub:`21Lhigh` + - Y'\ :sub:`21Rlow` + - Y'\ :sub:`21Rhigh` + * - start + 24: + - Y'\ :sub:`30Llow` + - Y'\ :sub:`30Lhigh` + - Y'\ :sub:`30Rlow` + - Y'\ :sub:`30Rhigh` + - Y'\ :sub:`31Llow` + - Y'\ :sub:`31Lhigh` + - Y'\ :sub:`31Rlow` + - Y'\ :sub:`31Rhigh` diff --git a/Documentation/userspace-api/media/v4l/subdev-formats.rst b/Documentation/userspace-api/media/v4l/subdev-formats.rst index d2a6cd2e1eb2ce..2a94371448dc07 100644 --- a/Documentation/userspace-api/media/v4l/subdev-formats.rst +++ b/Documentation/userspace-api/media/v4l/subdev-formats.rst @@ -2225,7 +2225,7 @@ The following table list existing packed 48bit wide RGB formats. \endgroup On LVDS buses, usually each sample is transferred serialized in seven -time slots per pixel clock, on three (18-bit) or four (24-bit) +time slots per pixel clock, on three (18-bit) or four (24-bit) or five (30-bit) differential data pairs at the same time. The remaining bits are used for control signals as defined by SPWG/PSWG/VESA or JEIDA standards. The 24-bit RGB format serialized in seven time slots on four lanes using @@ -2246,11 +2246,12 @@ JEIDA defined bit mapping will be named - Code - - - - :cspan:`3` Data organization + - :cspan:`4` Data organization * - - - Timeslot - Lane + - 4 - 3 - 2 - 1 @@ -2262,6 +2263,7 @@ JEIDA defined bit mapping will be named - 0 - - + - - d - b\ :sub:`1` - g\ :sub:`0` @@ -2270,6 +2272,7 @@ JEIDA defined bit mapping will be named - 1 - - + - - d - b\ :sub:`0` - r\ :sub:`5` @@ -2278,6 +2281,7 @@ JEIDA defined bit mapping will be named - 2 - - + - - d - g\ :sub:`5` - r\ :sub:`4` @@ -2286,6 +2290,7 @@ JEIDA defined bit mapping will be named - 3 - - + - - b\ :sub:`5` - g\ :sub:`4` - r\ :sub:`3` @@ -2294,6 +2299,7 @@ JEIDA defined bit mapping will be named - 4 - - + - - b\ :sub:`4` - g\ :sub:`3` - r\ :sub:`2` @@ -2302,6 +2308,7 @@ JEIDA defined bit mapping will be named - 5 - - + - - b\ :sub:`3` - g\ :sub:`2` - r\ :sub:`1` @@ -2310,6 +2317,7 @@ JEIDA defined bit mapping will be named - 6 - - + - - b\ :sub:`2` - g\ :sub:`1` - r\ :sub:`0` @@ -2319,6 +2327,7 @@ JEIDA defined bit mapping will be named - 0x1011 - 0 - + - - d - d - b\ :sub:`1` @@ -2327,6 +2336,7 @@ JEIDA defined bit mapping will be named - - 1 - + - - b\ :sub:`7` - d - b\ :sub:`0` @@ -2335,6 +2345,7 @@ JEIDA defined bit mapping will be named - - 2 - + - - b\ :sub:`6` - d - g\ :sub:`5` @@ -2343,6 +2354,7 @@ JEIDA defined bit mapping will be named - - 3 - + - - g\ :sub:`7` - b\ :sub:`5` - g\ :sub:`4` @@ -2351,6 +2363,7 @@ JEIDA defined bit mapping will be named - - 4 - + - - g\ :sub:`6` - b\ :sub:`4` - g\ :sub:`3` @@ -2359,6 +2372,7 @@ JEIDA defined bit mapping will be named - - 5 - + - - r\ :sub:`7` - b\ :sub:`3` - g\ :sub:`2` @@ -2367,6 +2381,7 @@ JEIDA defined bit mapping will be named - - 6 - + - - r\ :sub:`6` - b\ :sub:`2` - g\ :sub:`1` @@ -2377,6 +2392,7 @@ JEIDA defined bit mapping will be named - 0x1012 - 0 - + - - d - d - b\ :sub:`3` @@ -2385,6 +2401,7 @@ JEIDA defined bit mapping will be named - - 1 - + - - b\ :sub:`1` - d - b\ :sub:`2` @@ -2393,6 +2410,7 @@ JEIDA defined bit mapping will be named - - 2 - + - - b\ :sub:`0` - d - g\ :sub:`7` @@ -2401,6 +2419,7 @@ JEIDA defined bit mapping will be named - - 3 - + - - g\ :sub:`1` - b\ :sub:`7` - g\ :sub:`6` @@ -2409,6 +2428,7 @@ JEIDA defined bit mapping will be named - - 4 - + - - g\ :sub:`0` - b\ :sub:`6` - g\ :sub:`5` @@ -2417,6 +2437,7 @@ JEIDA defined bit mapping will be named - - 5 - + - - r\ :sub:`1` - b\ :sub:`5` - g\ :sub:`4` @@ -2425,10 +2446,141 @@ JEIDA defined bit mapping will be named - - 6 - + - + - r\ :sub:`0` + - b\ :sub:`4` + - g\ :sub:`3` + - r\ :sub:`2` + * .. _MEDIA-BUS-FMT-RGB101010-1X7X5-SPWG: + + - MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG + - 0x1026 + - 0 + - + - d + - d + - d + - b\ :sub:`1` + - g\ :sub:`0` + * - + - + - 1 + - + - b\ :sub:`9` + - b\ :sub:`7` + - d + - b\ :sub:`0` + - r\ :sub:`5` + * - + - + - 2 + - + - b\ :sub:`8` + - b\ :sub:`6` + - d + - g\ :sub:`5` + - r\ :sub:`4` + * - + - + - 3 + - + - g\ :sub:`9` + - g\ :sub:`7` + - b\ :sub:`5` + - g\ :sub:`4` + - r\ :sub:`3` + * - + - + - 4 + - + - g\ :sub:`8` + - g\ :sub:`6` + - b\ :sub:`4` + - g\ :sub:`3` + - r\ :sub:`2` + * - + - + - 5 + - + - r\ :sub:`9` + - r\ :sub:`7` + - b\ :sub:`3` + - g\ :sub:`2` + - r\ :sub:`1` + * - + - + - 6 + - + - r\ :sub:`8` + - r\ :sub:`6` + - b\ :sub:`2` + - g\ :sub:`1` - r\ :sub:`0` + * .. _MEDIA-BUS-FMT-RGB101010-1X7X5-JEIDA: + + - MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA + - 0x1027 + - 0 + - + - d + - d + - d + - b\ :sub:`5` + - g\ :sub:`4` + * - + - + - 1 + - + - b\ :sub:`1` + - b\ :sub:`3` + - d - b\ :sub:`4` + - r\ :sub:`9` + * - + - + - 2 + - + - b\ :sub:`0` + - b\ :sub:`2` + - d + - g\ :sub:`9` + - r\ :sub:`8` + * - + - + - 3 + - + - g\ :sub:`1` - g\ :sub:`3` + - b\ :sub:`9` + - g\ :sub:`8` + - r\ :sub:`7` + * - + - + - 4 + - + - g\ :sub:`0` + - g\ :sub:`2` + - b\ :sub:`8` + - g\ :sub:`7` + - r\ :sub:`6` + * - + - + - 5 + - + - r\ :sub:`1` + - r\ :sub:`3` + - b\ :sub:`7` + - g\ :sub:`6` + - r\ :sub:`5` + * - + - + - 6 + - + - r\ :sub:`0` - r\ :sub:`2` + - b\ :sub:`6` + - g\ :sub:`5` + - r\ :sub:`4` .. raw:: latex diff --git a/Documentation/userspace-api/media/v4l/vidioc-enum-fmt.rst b/Documentation/userspace-api/media/v4l/vidioc-enum-fmt.rst index 3adb3d205531b4..0f69aa04607f87 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-enum-fmt.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-enum-fmt.rst @@ -85,7 +85,17 @@ the ``mbus_code`` field is handled differently: * - __u32 - ``index`` - Number of the format in the enumeration, set by the application. - This is in no way related to the ``pixelformat`` field. + This is in no way related to the ``pixelformat`` field. + When the index is ORed with ``V4L2_FMTDESC_FLAG_ENUM_ALL`` the + driver clears the flag and enumerates all the possible formats, + ignoring any limitations from the current configuration. Drivers + which do not support this flag always return an ``EINVAL`` + error code without clearing this flag. + Formats enumerated when using ``V4L2_FMTDESC_FLAG_ENUM_ALL`` flag + shouldn't be used when calling :c:func:`VIDIOC_ENUM_FRAMESIZES` + or :c:func:`VIDIOC_ENUM_FRAMEINTERVALS`. + ``V4L2_FMTDESC_FLAG_ENUM_ALL`` should only be used by drivers that + can return different format list depending on this flag. * - __u32 - ``type`` - Type of the data stream, set by the application. Only these types @@ -234,6 +244,12 @@ the ``mbus_code`` field is handled differently: valid. The buffer consists of ``height`` lines, each having ``width`` Data Units of data and the offset (in bytes) between the beginning of each two consecutive lines is ``bytesperline``. + * - ``V4L2_FMTDESC_FLAG_ENUM_ALL`` + - 0x80000000 + - When the applications ORs ``index`` with ``V4L2_FMTDESC_FLAG_ENUM_ALL`` flag + the driver enumerates all the possible pixel formats without taking care + of any already set configuration. Drivers which do not support this flag, + always return ``EINVAL`` without clearing this flag. Return Value ============ diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst index 24b34cdfa6fea6..78ee406d764793 100644 --- a/Documentation/userspace-api/media/v4l/yuv-formats.rst +++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst @@ -269,5 +269,6 @@ image. pixfmt-yuv-luma pixfmt-y8i pixfmt-y12i + pixfmt-y16i pixfmt-uv8 pixfmt-m420 diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index d67fd4038d22a4..429b5cdf05c399 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -217,6 +217,7 @@ replace define V4L2_FMT_FLAG_CSC_YCBCR_ENC fmtdesc-flags replace define V4L2_FMT_FLAG_CSC_HSV_ENC fmtdesc-flags replace define V4L2_FMT_FLAG_CSC_QUANTIZATION fmtdesc-flags replace define V4L2_FMT_FLAG_META_LINE_BASED fmtdesc-flags +replace define V4L2_FMTDESC_FLAG_ENUM_ALL fmtdesc-flags # V4L2 timecode types replace define V4L2_TC_TYPE_24FPS timecode-type diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index edc070c6e19b21..454c2aaa155e5b 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -7,8 +7,19 @@ The Definitive KVM (Kernel-based Virtual Machine) API Documentation 1. General description ====================== -The kvm API is a set of ioctls that are issued to control various aspects -of a virtual machine. The ioctls belong to the following classes: +The kvm API is centered around different kinds of file descriptors +and ioctls that can be issued to these file descriptors. An initial +open("/dev/kvm") obtains a handle to the kvm subsystem; this handle +can be used to issue system ioctls. A KVM_CREATE_VM ioctl on this +handle will create a VM file descriptor which can be used to issue VM +ioctls. A KVM_CREATE_VCPU or KVM_CREATE_DEVICE ioctl on a VM fd will +create a virtual cpu or device and return a file descriptor pointing to +the new resource. + +In other words, the kvm API is a set of ioctls that are issued to +different kinds of file descriptor in order to control various aspects of +a virtual machine. Depending on the file descriptor that accepts them, +ioctls belong to the following classes: - System ioctls: These query and set global attributes which affect the whole kvm subsystem. In addition a system ioctl is used to create @@ -35,18 +46,19 @@ of a virtual machine. The ioctls belong to the following classes: device ioctls must be issued from the same process (address space) that was used to create the VM. -2. File descriptors -=================== +While most ioctls are specific to one kind of file descriptor, in some +cases the same ioctl can belong to more than one class. + +The KVM API grew over time. For this reason, KVM defines many constants +of the form ``KVM_CAP_*``, each corresponding to a set of functionality +provided by one or more ioctls. Availability of these "capabilities" can +be checked with :ref:`KVM_CHECK_EXTENSION `. Some +capabilities also need to be enabled for VMs or VCPUs where their +functionality is desired (see :ref:`cap_enable` and :ref:`cap_enable_vm`). -The kvm API is centered around file descriptors. An initial -open("/dev/kvm") obtains a handle to the kvm subsystem; this handle -can be used to issue system ioctls. A KVM_CREATE_VM ioctl on this -handle will create a VM file descriptor which can be used to issue VM -ioctls. A KVM_CREATE_VCPU or KVM_CREATE_DEVICE ioctl on a VM fd will -create a virtual cpu or device and return a file descriptor pointing to -the new resource. Finally, ioctls on a vcpu or device fd can be used -to control the vcpu or device. For vcpus, this includes the important -task of actually running guest code. + +2. Restrictions +=============== In general file descriptors can be migrated among processes by means of fork() and the SCM_RIGHTS facility of unix domain socket. These @@ -96,12 +108,9 @@ description: Capability: which KVM extension provides this ioctl. Can be 'basic', which means that is will be provided by any kernel that supports - API version 12 (see section 4.1), a KVM_CAP_xyz constant, which - means availability needs to be checked with KVM_CHECK_EXTENSION - (see section 4.4), or 'none' which means that while not all kernels - support this ioctl, there's no capability bit to check its - availability: for kernels that don't support the ioctl, - the ioctl returns -ENOTTY. + API version 12 (see :ref:`KVM_GET_API_VERSION `), + or a KVM_CAP_xyz constant that can be checked with + :ref:`KVM_CHECK_EXTENSION `. Architectures: which instruction set architectures provide this ioctl. @@ -118,6 +127,8 @@ description: are not detailed, but errors with specific meanings are. +.. _KVM_GET_API_VERSION: + 4.1 KVM_GET_API_VERSION ----------------------- @@ -246,6 +257,8 @@ This list also varies by kvm version and host processor, but does not change otherwise. +.. _KVM_CHECK_EXTENSION: + 4.4 KVM_CHECK_EXTENSION ----------------------- @@ -288,7 +301,7 @@ the VCPU file descriptor can be mmap-ed, including: - if KVM_CAP_DIRTY_LOG_RING is available, a number of pages at KVM_DIRTY_LOG_PAGE_OFFSET * PAGE_SIZE. For more information on - KVM_CAP_DIRTY_LOG_RING, see section 8.3. + KVM_CAP_DIRTY_LOG_RING, see :ref:`KVM_CAP_DIRTY_LOG_RING`. 4.7 KVM_CREATE_VCPU @@ -338,8 +351,8 @@ KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of the virtual cpu's hardware control block. -4.8 KVM_GET_DIRTY_LOG (vm ioctl) --------------------------------- +4.8 KVM_GET_DIRTY_LOG +--------------------- :Capability: basic :Architectures: all @@ -1298,7 +1311,7 @@ See KVM_GET_VCPU_EVENTS for the data structure. :Capability: KVM_CAP_DEBUGREGS :Architectures: x86 -:Type: vm ioctl +:Type: vcpu ioctl :Parameters: struct kvm_debugregs (out) :Returns: 0 on success, -1 on error @@ -1320,7 +1333,7 @@ Reads debug registers from the vcpu. :Capability: KVM_CAP_DEBUGREGS :Architectures: x86 -:Type: vm ioctl +:Type: vcpu ioctl :Parameters: struct kvm_debugregs (in) :Returns: 0 on success, -1 on error @@ -1429,6 +1442,8 @@ because of a quirk in the virtualization implementation (see the internals documentation when it pops into existence). +.. _KVM_ENABLE_CAP: + 4.37 KVM_ENABLE_CAP ------------------- @@ -2116,8 +2131,8 @@ TLB, prior to calling KVM_RUN on the associated vcpu. The "bitmap" field is the userspace address of an array. This array consists of a number of bits, equal to the total number of TLB entries as -determined by the last successful call to KVM_CONFIG_TLB, rounded up to the -nearest multiple of 64. +determined by the last successful call to ``KVM_ENABLE_CAP(KVM_CAP_SW_TLB)``, +rounded up to the nearest multiple of 64. Each bit corresponds to one TLB entry, ordered the same as in the shared TLB array. @@ -2170,42 +2185,6 @@ userspace update the TCE table directly which is useful in some circumstances. -4.63 KVM_ALLOCATE_RMA ---------------------- - -:Capability: KVM_CAP_PPC_RMA -:Architectures: powerpc -:Type: vm ioctl -:Parameters: struct kvm_allocate_rma (out) -:Returns: file descriptor for mapping the allocated RMA - -This allocates a Real Mode Area (RMA) from the pool allocated at boot -time by the kernel. An RMA is a physically-contiguous, aligned region -of memory used on older POWER processors to provide the memory which -will be accessed by real-mode (MMU off) accesses in a KVM guest. -POWER processors support a set of sizes for the RMA that usually -includes 64MB, 128MB, 256MB and some larger powers of two. - -:: - - /* for KVM_ALLOCATE_RMA */ - struct kvm_allocate_rma { - __u64 rma_size; - }; - -The return value is a file descriptor which can be passed to mmap(2) -to map the allocated RMA into userspace. The mapped area can then be -passed to the KVM_SET_USER_MEMORY_REGION ioctl to establish it as the -RMA for a virtual machine. The size of the RMA in bytes (which is -fixed at host kernel boot time) is returned in the rma_size field of -the argument structure. - -The KVM_CAP_PPC_RMA capability is 1 or 2 if the KVM_ALLOCATE_RMA ioctl -is supported; 2 if the processor requires all virtual machines to have -an RMA, or 1 if the processor can use an RMA but doesn't require it, -because it supports the Virtual RMA (VRMA) facility. - - 4.64 KVM_NMI ------------ @@ -2602,7 +2581,7 @@ Specifically: ======================= ========= ===== ======================================= .. [1] These encodings are not accepted for SVE-enabled vcpus. See - KVM_ARM_VCPU_INIT. + :ref:`KVM_ARM_VCPU_INIT`. The equivalent register content can be accessed via bits [127:0] of the corresponding SVE Zn registers instead for vcpus that have SVE @@ -3593,6 +3572,27 @@ Errors: This ioctl returns the guest registers that are supported for the KVM_GET_ONE_REG/KVM_SET_ONE_REG calls. +Note that s390 does not support KVM_GET_REG_LIST for historical reasons +(read: nobody cared). The set of registers in kernels 4.x and newer is: + +- KVM_REG_S390_TODPR + +- KVM_REG_S390_EPOCHDIFF + +- KVM_REG_S390_CPU_TIMER + +- KVM_REG_S390_CLOCK_COMP + +- KVM_REG_S390_PFTOKEN + +- KVM_REG_S390_PFCOMPARE + +- KVM_REG_S390_PFSELECT + +- KVM_REG_S390_PP + +- KVM_REG_S390_GBEA + 4.85 KVM_ARM_SET_DEVICE_ADDR (deprecated) ----------------------------------------- @@ -4956,8 +4956,8 @@ Coalesced pio is based on coalesced mmio. There is little difference between coalesced mmio and pio except that coalesced pio records accesses to I/O ports. -4.117 KVM_CLEAR_DIRTY_LOG (vm ioctl) ------------------------------------- +4.117 KVM_CLEAR_DIRTY_LOG +------------------------- :Capability: KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 :Architectures: x86, arm64, mips @@ -5093,8 +5093,8 @@ Recognised values for feature: Finalizes the configuration of the specified vcpu feature. The vcpu must already have been initialised, enabling the affected feature, by -means of a successful KVM_ARM_VCPU_INIT call with the appropriate flag set in -features[]. +means of a successful :ref:`KVM_ARM_VCPU_INIT ` call with the +appropriate flag set in features[]. For affected vcpu features, this is a mandatory step that must be performed before the vcpu is fully usable. @@ -5266,7 +5266,7 @@ the cpu reset definition in the POP (Principles Of Operation). 4.123 KVM_S390_INITIAL_RESET ---------------------------- -:Capability: none +:Capability: basic :Architectures: s390 :Type: vcpu ioctl :Parameters: none @@ -6205,7 +6205,7 @@ applied. .. _KVM_ARM_GET_REG_WRITABLE_MASKS: 4.139 KVM_ARM_GET_REG_WRITABLE_MASKS -------------------------------------------- +------------------------------------ :Capability: KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES :Architectures: arm64 @@ -6443,6 +6443,8 @@ the capability to be present. `flags` must currently be zero. +.. _kvm_run: + 5. The kvm_run structure ======================== @@ -6855,6 +6857,10 @@ the first `ndata` items (possibly zero) of the data array are valid. the guest issued a SYSTEM_RESET2 call according to v1.1 of the PSCI specification. + - for arm64, data[0] is set to KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2 + if the guest issued a SYSTEM_OFF2 call according to v1.3 of the PSCI + specification. + - for RISC-V, data[0] is set to the value of the second argument of the ``sbi_system_reset`` call. @@ -6888,6 +6894,12 @@ either: - Deny the guest request to suspend the VM. See ARM DEN0022D.b 5.19.2 "Caller responsibilities" for possible return values. +Hibernation using the PSCI SYSTEM_OFF2 call is enabled when PSCI v1.3 +is enabled. If a guest invokes the PSCI SYSTEM_OFF2 function, KVM will +exit to userspace with the KVM_SYSTEM_EVENT_SHUTDOWN event type and with +data[0] set to KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2. The only +supported hibernate type for the SYSTEM_OFF2 function is HIBERNATE_OFF. + :: /* KVM_EXIT_IOAPIC_EOI */ @@ -7162,11 +7174,15 @@ primary storage for certain register types. Therefore, the kernel may use the values in kvm_run even if the corresponding bit in kvm_dirty_regs is not set. +.. _cap_enable: + 6. Capabilities that can be enabled on vCPUs ============================================ There are certain capabilities that change the behavior of the virtual CPU or -the virtual machine when enabled. To enable them, please see section 4.37. +the virtual machine when enabled. To enable them, please see +:ref:`KVM_ENABLE_CAP`. + Below you can find a list of capabilities and what their effect on the vCPU or the virtual machine is when enabling them. @@ -7375,7 +7391,7 @@ KVM API and also from the guest. sets are supported (bitfields defined in arch/x86/include/uapi/asm/kvm.h). -As described above in the kvm_sync_regs struct info in section 5 (kvm_run): +As described above in the kvm_sync_regs struct info in section :ref:`kvm_run`, KVM_CAP_SYNC_REGS "allow[s] userspace to access certain guest registers without having to call SET/GET_*REGS". This reduces overhead by eliminating repeated ioctl calls for setting and/or getting register values. This is @@ -7421,13 +7437,15 @@ Unused bitfields in the bitarrays must be set to zero. This capability connects the vcpu to an in-kernel XIVE device. +.. _cap_enable_vm: + 7. Capabilities that can be enabled on VMs ========================================== There are certain capabilities that change the behavior of the virtual -machine when enabled. To enable them, please see section 4.37. Below -you can find a list of capabilities and what their effect on the VM -is when enabling them. +machine when enabled. To enable them, please see section +:ref:`KVM_ENABLE_CAP`. Below you can find a list of capabilities and +what their effect on the VM is when enabling them. The following information is provided along with the description: @@ -8107,6 +8125,28 @@ KVM_X86_QUIRK_SLOT_ZAP_ALL By default, for KVM_X86_DEFAULT_VM VMs, KVM or moved memslot isn't reachable, i.e KVM _may_ invalidate only SPTEs related to the memslot. + +KVM_X86_QUIRK_STUFF_FEATURE_MSRS By default, at vCPU creation, KVM sets the + vCPU's MSR_IA32_PERF_CAPABILITIES (0x345), + MSR_IA32_ARCH_CAPABILITIES (0x10a), + MSR_PLATFORM_INFO (0xce), and all VMX MSRs + (0x480..0x492) to the maximal capabilities + supported by KVM. KVM also sets + MSR_IA32_UCODE_REV (0x8b) to an arbitrary + value (which is different for Intel vs. + AMD). Lastly, when guest CPUID is set (by + userspace), KVM modifies select VMX MSR + fields to force consistency between guest + CPUID and L2's effective ISA. When this + quirk is disabled, KVM zeroes the vCPU's MSR + values (with two exceptions, see below), + i.e. treats the feature MSRs like CPUID + leaves and gives userspace full control of + the vCPU model definition. This quirk does + not affect VMX MSRs CR0/CR4_FIXED1 (0x487 + and 0x489), as KVM does now allow them to + be set by userspace (KVM sets them based on + guest CPUID, for safety purposes). =================================== ============================================ 7.32 KVM_CAP_MAX_VCPU_ID @@ -8588,6 +8628,8 @@ guest according to the bits in the KVM_CPUID_FEATURES CPUID leaf (0x40000001). Otherwise, a guest may use the paravirtual features regardless of what has actually been exposed through the CPUID leaf. +.. _KVM_CAP_DIRTY_LOG_RING: + 8.29 KVM_CAP_DIRTY_LOG_RING/KVM_CAP_DIRTY_LOG_RING_ACQ_REL ---------------------------------------------------------- diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst index 1bedd56e2fe3ac..c56d5f26c7505b 100644 --- a/Documentation/virt/kvm/locking.rst +++ b/Documentation/virt/kvm/locking.rst @@ -135,8 +135,8 @@ We dirty-log for gfn1, that means gfn2 is lost in dirty-bitmap. For direct sp, we can easily avoid it since the spte of direct sp is fixed to gfn. For indirect sp, we disabled fast page fault for simplicity. -A solution for indirect sp could be to pin the gfn, for example via -gfn_to_pfn_memslot_atomic, before the cmpxchg. After the pinning: +A solution for indirect sp could be to pin the gfn before the cmpxchg. After +the pinning: - We have held the refcount of pfn; that means the pfn can not be freed and be reused for another gfn. @@ -147,49 +147,51 @@ Then, we can ensure the dirty bitmaps is correctly set for a gfn. 2) Dirty bit tracking -In the origin code, the spte can be fast updated (non-atomically) if the +In the original code, the spte can be fast updated (non-atomically) if the spte is read-only and the Accessed bit has already been set since the Accessed bit and Dirty bit can not be lost. But it is not true after fast page fault since the spte can be marked writable between reading spte and updating spte. Like below case: -+------------------------------------------------------------------------+ -| At the beginning:: | -| | -| spte.W = 0 | -| spte.Accessed = 1 | -+------------------------------------+-----------------------------------+ -| CPU 0: | CPU 1: | -+------------------------------------+-----------------------------------+ -| In mmu_spte_clear_track_bits():: | | -| | | -| old_spte = *spte; | | -| | | -| | | -| /* 'if' condition is satisfied. */| | -| if (old_spte.Accessed == 1 && | | -| old_spte.W == 0) | | -| spte = 0ull; | | -+------------------------------------+-----------------------------------+ -| | on fast page fault path:: | -| | | -| | spte.W = 1 | -| | | -| | memory write on the spte:: | -| | | -| | spte.Dirty = 1 | -+------------------------------------+-----------------------------------+ -| :: | | -| | | -| else | | -| old_spte = xchg(spte, 0ull) | | -| if (old_spte.Accessed == 1) | | -| kvm_set_pfn_accessed(spte.pfn);| | -| if (old_spte.Dirty == 1) | | -| kvm_set_pfn_dirty(spte.pfn); | | -| OOPS!!! | | -+------------------------------------+-----------------------------------+ ++-------------------------------------------------------------------------+ +| At the beginning:: | +| | +| spte.W = 0 | +| spte.Accessed = 1 | ++-------------------------------------+-----------------------------------+ +| CPU 0: | CPU 1: | ++-------------------------------------+-----------------------------------+ +| In mmu_spte_update():: | | +| | | +| old_spte = *spte; | | +| | | +| | | +| /* 'if' condition is satisfied. */ | | +| if (old_spte.Accessed == 1 && | | +| old_spte.W == 0) | | +| spte = new_spte; | | ++-------------------------------------+-----------------------------------+ +| | on fast page fault path:: | +| | | +| | spte.W = 1 | +| | | +| | memory write on the spte:: | +| | | +| | spte.Dirty = 1 | ++-------------------------------------+-----------------------------------+ +| :: | | +| | | +| else | | +| old_spte = xchg(spte, new_spte);| | +| if (old_spte.Accessed && | | +| !new_spte.Accessed) | | +| flush = true; | | +| if (old_spte.Dirty && | | +| !new_spte.Dirty) | | +| flush = true; | | +| OOPS!!! | | ++-------------------------------------+-----------------------------------+ The Dirty bit is lost in this case. diff --git a/Documentation/virt/kvm/s390/s390-diag.rst b/Documentation/virt/kvm/s390/s390-diag.rst index ca85f030eb0ba9..3e4f9e3bef8108 100644 --- a/Documentation/virt/kvm/s390/s390-diag.rst +++ b/Documentation/virt/kvm/s390/s390-diag.rst @@ -35,20 +35,24 @@ DIAGNOSE function codes not specific to KVM, please refer to the documentation for the s390 hypervisors defining them. -DIAGNOSE function code 'X'500' - KVM virtio functions ------------------------------------------------------ +DIAGNOSE function code 'X'500' - KVM functions +---------------------------------------------- -If the function code specifies 0x500, various virtio-related functions -are performed. +If the function code specifies 0x500, various KVM-specific functions +are performed, including virtio functions. -General register 1 contains the virtio subfunction code. Supported -virtio subfunctions depend on KVM's userspace. Generally, userspace -provides either s390-virtio (subcodes 0-2) or virtio-ccw (subcode 3). +General register 1 contains the subfunction code. Supported subfunctions +depend on KVM's userspace. Regarding virtio subfunctions, generally +userspace provides either s390-virtio (subcodes 0-2) or virtio-ccw +(subcode 3). Upon completion of the DIAGNOSE instruction, general register 2 contains the function's return code, which is either a return code or a subcode specific value. +If the specified subfunction is not supported, a SPECIFICATION exception +will be triggered. + Subcode 0 - s390-virtio notification and early console printk Handled by userspace. @@ -76,6 +80,23 @@ Subcode 3 - virtio-ccw notification See also the virtio standard for a discussion of this hypercall. +Subcode 4 - storage-limit + Handled by userspace. + + After completion of the DIAGNOSE call, general register 2 will + contain the storage limit: the maximum physical address that might be + used for storage throughout the lifetime of the VM. + + The storage limit does not indicate currently usable storage, it may + include holes, standby storage and areas reserved for other means, such + as memory hotplug or virtio-mem devices. Other interfaces for detecting + actually usable storage, such as SCLP, must be used in conjunction with + this subfunction. + + Note that the storage limit can be larger, but never smaller than the + maximum storage address indicated by SCLP via the "maximum storage + increment" and the "increment size". + DIAGNOSE function code 'X'501 - KVM breakpoint ---------------------------------------------- diff --git a/Documentation/virt/kvm/x86/errata.rst b/Documentation/virt/kvm/x86/errata.rst index 4116045a8744d0..37c79362a48fa8 100644 --- a/Documentation/virt/kvm/x86/errata.rst +++ b/Documentation/virt/kvm/x86/errata.rst @@ -33,6 +33,18 @@ Note however that any software (e.g ``WIN87EM.DLL``) expecting these features to be present likely predates these CPUID feature bits, and therefore doesn't know to check for them anyway. +``KVM_SET_VCPU_EVENTS`` issue +----------------------------- + +Invalid KVM_SET_VCPU_EVENTS input with respect to error codes *may* result in +failed VM-Entry on Intel CPUs. Pre-CET Intel CPUs require that exception +injection through the VMCS correctly set the "error code valid" flag, e.g. +require the flag be set when injecting a #GP, clear when injecting a #UD, +clear when injecting a soft exception, etc. Intel CPUs that enumerate +IA32_VMX_BASIC[56] as '1' relax VMX's consistency checks, and AMD CPUs have no +restrictions whatsoever. KVM_SET_VCPU_EVENTS doesn't sanity check the vector +versus "has_error_code", i.e. KVM's ABI follows AMD behavior. + Nested virtualization features ------------------------------ diff --git a/Documentation/watchdog/watchdog-parameters.rst b/Documentation/watchdog/watchdog-parameters.rst index 29153eed668900..0a0119edfa82d6 100644 --- a/Documentation/watchdog/watchdog-parameters.rst +++ b/Documentation/watchdog/watchdog-parameters.rst @@ -120,16 +120,6 @@ coh901327_wdt: ------------------------------------------------- -cpu5wdt: - port: - base address of watchdog card, default is 0x91 - verbose: - be verbose, default is 0 (no) - ticks: - count down ticks, default is 10000 - -------------------------------------------------- - cpwd: wd0_timeout: Default watchdog0 timeout in 1/10secs diff --git a/Documentation/wmi/devices/alienware-wmi.rst b/Documentation/wmi/devices/alienware-wmi.rst new file mode 100644 index 00000000000000..ddc5e561960e05 --- /dev/null +++ b/Documentation/wmi/devices/alienware-wmi.rst @@ -0,0 +1,397 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +============================================== +Dell AWCC WMI interface driver (alienware-wmi) +============================================== + +Introduction +============ + +The WMI device WMAX has been implemented for many Alienware and Dell's G-Series +models. Throughout these models, two implementations have been identified. The +first one, used by older systems, deals with HDMI, brightness, RGB, amplifier +and deep sleep control. The second one used by newer systems deals primarily +with thermal, overclocking, and GPIO control. + +It is suspected that the latter is used by Alienware Command Center (AWCC) to +manage manufacturer predefined thermal profiles. The alienware-wmi driver +exposes Thermal_Information and Thermal_Control methods through the Platform +Profile API to mimic AWCC's behavior. + +This newer interface, named AWCCMethodFunction has been reverse engineered, as +Dell has not provided any official documentation. We will try to describe to the +best of our ability its discovered inner workings. + +.. note:: + The following method description may be incomplete and some operations have + different implementations between devices. + +WMI interface description +------------------------- + +The WMI interface description can be decoded from the embedded binary MOF (bmof) +data using the `bmfdec `_ utility: + +:: + + [WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("WMI Function"), guid("{A70591CE-A997-11DA-B012-B622A1EF5492}")] + class AWCCWmiMethodFunction { + [key, read] string InstanceName; + [read] boolean Active; + + [WmiMethodId(13), Implemented, read, write, Description("Return Overclocking Report.")] void Return_OverclockingReport([out] uint32 argr); + [WmiMethodId(14), Implemented, read, write, Description("Set OCUIBIOS Control.")] void Set_OCUIBIOSControl([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(15), Implemented, read, write, Description("Clear OC FailSafe Flag.")] void Clear_OCFailSafeFlag([out] uint32 argr); + [WmiMethodId(19), Implemented, read, write, Description("Get Fan Sensors.")] void GetFanSensors([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(20), Implemented, read, write, Description("Thermal Information.")] void Thermal_Information([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(21), Implemented, read, write, Description("Thermal Control.")] void Thermal_Control([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(23), Implemented, read, write, Description("MemoryOCControl.")] void MemoryOCControl([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(26), Implemented, read, write, Description("System Information.")] void SystemInformation([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(28), Implemented, read, write, Description("Power Information.")] void PowerInformation([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(32), Implemented, read, write, Description("FW Update GPIO toggle.")] void FWUpdateGPIOtoggle([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(33), Implemented, read, write, Description("Read Total of GPIOs.")] void ReadTotalofGPIOs([out] uint32 argr); + [WmiMethodId(34), Implemented, read, write, Description("Read GPIO pin Status.")] void ReadGPIOpPinStatus([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(35), Implemented, read, write, Description("Read Chassis Color.")] void ReadChassisColor([out] uint32 argr); + [WmiMethodId(36), Implemented, read, write, Description("Read Platform Properties.")] void ReadPlatformProperties([out] uint32 argr); + [WmiMethodId(37), Implemented, read, write, Description("Game Shift Status.")] void GameShiftStatus([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(128), Implemented, read, write, Description("Caldera SW installation.")] void CalderaSWInstallation([out] uint32 argr); + [WmiMethodId(129), Implemented, read, write, Description("Caldera SW is released.")] void CalderaSWReleased([out] uint32 argr); + [WmiMethodId(130), Implemented, read, write, Description("Caldera Connection Status.")] void CalderaConnectionStatus([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(131), Implemented, read, write, Description("Surprise Unplugged Flag Status.")] void SurpriseUnpluggedFlagStatus([out] uint32 argr); + [WmiMethodId(132), Implemented, read, write, Description("Clear Surprise Unplugged Flag.")] void ClearSurpriseUnpluggedFlag([out] uint32 argr); + [WmiMethodId(133), Implemented, read, write, Description("Cancel Undock Request.")] void CancelUndockRequest([out] uint32 argr); + [WmiMethodId(135), Implemented, read, write, Description("Devices in Caldera.")] void DevicesInCaldera([in] uint32 arg2, [out] uint32 argr); + [WmiMethodId(136), Implemented, read, write, Description("Notify BIOS for SW ready to disconnect Caldera.")] void NotifyBIOSForSWReadyToDisconnectCaldera([out] uint32 argr); + [WmiMethodId(160), Implemented, read, write, Description("Tobii SW installation.")] void TobiiSWinstallation([out] uint32 argr); + [WmiMethodId(161), Implemented, read, write, Description("Tobii SW Released.")] void TobiiSWReleased([out] uint32 argr); + [WmiMethodId(162), Implemented, read, write, Description("Tobii Camera Power Reset.")] void TobiiCameraPowerReset([out] uint32 argr); + [WmiMethodId(163), Implemented, read, write, Description("Tobii Camera Power On.")] void TobiiCameraPowerOn([out] uint32 argr); + [WmiMethodId(164), Implemented, read, write, Description("Tobii Camera Power Off.")] void TobiiCameraPowerOff([out] uint32 argr); + }; + +Some of these methods get quite intricate so we will describe them using +pseudo-code that vaguely resembles the original ASL code. + +Methods not described in the following document have unknown behavior. + +Argument Structure +------------------ + +All input arguments have type **uint32** and their structure is very similar +between methods. Usually, the first byte corresponds to a specific *operation* +the method performs, and the subsequent bytes correspond to *arguments* passed +to this *operation*. For example, if an operation has code 0x01 and requires an +ID 0xA0, the argument you would pass to the method is 0xA001. + + +Thermal Methods +=============== + +WMI method Thermal_Information([in] uint32 arg2, [out] uint32 argr) +------------------------------------------------------------------- + +:: + + if BYTE_0(arg2) == 0x01: + argr = 1 + + if BYTE_0(arg2) == 0x02: + argr = SYSTEM_DESCRIPTION + + if BYTE_0(arg2) == 0x03: + if BYTE_1(arg2) == 0x00: + argr = FAN_ID_0 + + if BYTE_1(arg2) == 0x01: + argr = FAN_ID_1 + + if BYTE_1(arg2) == 0x02: + argr = FAN_ID_2 + + if BYTE_1(arg2) == 0x03: + argr = FAN_ID_3 + + if BYTE_1(arg2) == 0x04: + argr = SENSOR_ID_CPU | 0x0100 + + if BYTE_1(arg2) == 0x05: + argr = SENSOR_ID_GPU | 0x0100 + + if BYTE_1(arg2) == 0x06: + argr = THERMAL_MODE_QUIET_ID + + if BYTE_1(arg2) == 0x07: + argr = THERMAL_MODE_BALANCED_ID + + if BYTE_1(arg2) == 0x08: + argr = THERMAL_MODE_BALANCED_PERFORMANCE_ID + + if BYTE_1(arg2) == 0x09: + argr = THERMAL_MODE_PERFORMANCE_ID + + if BYTE_1(arg2) == 0x0A: + argr = THERMAL_MODE_LOW_POWER_ID + + if BYTE_1(arg2) == 0x0B: + argr = THERMAL_MODE_GMODE_ID + + else: + argr = 0xFFFFFFFF + + if BYTE_0(arg2) == 0x04: + if is_valid_sensor(BYTE_1(arg2)): + argr = SENSOR_TEMP_C + else: + argr = 0xFFFFFFFF + + if BYTE_0(arg2) == 0x05: + if is_valid_fan(BYTE_1(arg2)): + argr = FAN_RPM() + + if BYTE_0(arg2) == 0x06: + skip + + if BYTE_0(arg2) == 0x07: + argr = 0 + + If BYTE_0(arg2) == 0x08: + if is_valid_fan(BYTE_1(arg2)): + argr = 0 + else: + argr = 0xFFFFFFFF + + if BYTE_0(arg2) == 0x09: + if is_valid_fan(BYTE_1(arg2)): + argr = FAN_UNKNOWN_STAT_0() + + else: + argr = 0xFFFFFFFF + + if BYTE_0(arg2) == 0x0A: + argr = THERMAL_MODE_BALANCED_ID + + if BYTE_0(arg2) == 0x0B: + argr = CURRENT_THERMAL_MODE() + + if BYTE_0(arg2) == 0x0C: + if is_valid_fan(BYTE_1(arg2)): + argr = FAN_UNKNOWN_STAT_1() + else: + argr = 0xFFFFFFFF + +Operation 0x02 returns a *system description* buffer with the following +structure: + +:: + + out[0] -> Number of fans + out[1] -> Number of sensors + out[2] -> 0x00 + out[3] -> Number of thermal modes + +Operation 0x03 list all available fan IDs, sensor IDs and thermal profile +codes in order, but different models may have different number of fans and +thermal profiles. These are the known ranges: + +* Fan IDs: from 2 up to 4 +* Sensor IDs: 2 +* Thermal profile codes: from 1 up to 7 + +In total BYTE_1(ARG2) may range from 0x5 up to 0xD depending on the model. + +WMI method Thermal_Control([in] uint32 arg2, [out] uint32 argr) +--------------------------------------------------------------- + +:: + + if BYTE_0(arg2) == 0x01: + if is_valid_thermal_profile(BYTE_1(arg2)): + SET_THERMAL_PROFILE(BYTE_1(arg2)) + argr = 0 + + if BYTE_0(arg2) == 0x02: + if is_valid_fan(BYTE_1(arg2)): + SET_FAN_SPEED_MULTIPLIER(BYTE_2(arg2)) + argr = 0 + else: + argr = 0xFFFFFFFF + +.. note:: + While you can manually change the fan speed multiplier with this method, + Dell's BIOS tends to overwrite this changes anyway. + +These are the known thermal profile codes: + +:: + + CUSTOM 0x00 + + BALANCED_USTT 0xA0 + BALANCED_PERFORMANCE_USTT 0xA1 + COOL_USTT 0xA2 + QUIET_USTT 0xA3 + PERFORMANCE_USTT 0xA4 + LOW_POWER_USTT 0xA5 + + QUIET 0x96 + BALANCED 0x97 + BALANCED_PERFORMANCE 0x98 + PERFORMANCE 0x99 + + GMODE 0xAB + +Usually if a model doesn't support the first four profiles they will support +the User Selectable Thermal Tables (USTT) profiles and vice-versa. + +GMODE replaces PERFORMANCE in G-Series laptops. + +WMI method GameShiftStatus([in] uint32 arg2, [out] uint32 argr) +--------------------------------------------------------------- + +:: + + if BYTE_0(arg2) == 0x1: + TOGGLE_GAME_SHIFT() + argr = GET_GAME_SHIFT_STATUS() + + if BYTE_0(arg2) == 0x2: + argr = GET_GAME_SHIFT_STATUS() + +Game Shift Status does not change the fan speed profile but it could be some +sort of CPU/GPU power profile. Benchmarks have not been done. + +This method is only present on Dell's G-Series laptops and it's implementation +implies GMODE thermal profile is available, even if operation 0x03 of +Thermal_Information does not list it. + +G-key on Dell's G-Series laptops also changes Game Shift status, so both are +directly related. + +WMI method GetFanSensors([in] uint32 arg2, [out] uint32 argr) +------------------------------------------------------------- + +:: + + if BYTE_0(arg2) == 0x1: + if is_valid_fan(BYTE_1(arg2)): + argr = 1 + else: + argr = 0 + + if BYTE_0(arg2) == 0x2: + if is_valid_fan(BYTE_1(arg2)): + if BYTE_2(arg2) == 0: + argr == SENSOR_ID + else + argr == 0xFFFFFFFF + else: + argr = 0 + +Overclocking Methods +==================== + +.. warning:: + These methods have not been tested and are only partially reverse + engineered. + +WMI method Return_OverclockingReport([out] uint32 argr) +------------------------------------------------------- + +:: + + CSMI (0xE3, 0x99) + argr = 0 + +CSMI is an unknown operation. + +WMI method Set_OCUIBIOSControl([in] uint32 arg2, [out] uint32 argr) +------------------------------------------------------------------- + +:: + + CSMI (0xE3, 0x99) + argr = 0 + +CSMI is an unknown operation. + +WMI method Clear_OCFailSafeFlag([out] uint32 argr) +-------------------------------------------------- + +:: + + CSMI (0xE3, 0x99) + argr = 0 + +CSMI is an unknown operation. + + +WMI method MemoryOCControl([in] uint32 arg2, [out] uint32 argr) +--------------------------------------------------------------- + +AWCC supports memory overclocking, but this method is very intricate and has +not been deciphered yet. + +GPIO methods +============ + +These methods are probably related to some kind of firmware update system, +through a GPIO device. + +.. warning:: + These methods have not been tested and are only partially reverse + engineered. + +WMI method FWUpdateGPIOtoggle([in] uint32 arg2, [out] uint32 argr) +------------------------------------------------------------------ + +:: + + if BYTE_0(arg2) == 0: + if BYTE_1(arg2) == 1: + SET_PIN_A_HIGH() + else: + SET_PIN_A_LOW() + + if BYTE_0(arg2) == 1: + if BYTE_1(arg2) == 1: + SET_PIN_B_HIGH() + + else: + SET_PIN_B_LOW() + + else: + argr = 1 + +WMI method ReadTotalofGPIOs([out] uint32 argr) +---------------------------------------------- + +:: + + argr = 0x02 + +WMI method ReadGPIOpPinStatus([in] uint32 arg2, [out] uint32 argr) +------------------------------------------------------------------ + +:: + + if BYTE_0(arg2) == 0: + argr = PIN_A_STATUS + + if BYTE_0(arg2) == 1: + argr = PIN_B_STATUS + +Other information Methods +========================= + +WMI method ReadChassisColor([out] uint32 argr) +---------------------------------------------- + +:: + + argr = CHASSIS_COLOR_ID + +Acknowledgements +================ + +Kudos to `AlexIII `_ for documenting +and testing available thermal profile codes. diff --git a/Documentation/wmi/driver-development-guide.rst b/Documentation/wmi/driver-development-guide.rst index 429137b2f63236..676873c9868049 100644 --- a/Documentation/wmi/driver-development-guide.rst +++ b/Documentation/wmi/driver-development-guide.rst @@ -64,6 +64,7 @@ to matching WMI devices using a struct wmi_device_id table: .id_table = foo_id_table, .probe = foo_probe, .remove = foo_remove, /* optional, devres is preferred */ + .shutdown = foo_shutdown, /* optional, called during shutdown */ .notify = foo_notify, /* optional, for event handling */ .no_notify_data = true, /* optional, enables events containing no additional data */ .no_singleton = true, /* required for new WMI drivers */ @@ -79,6 +80,10 @@ to unregister interfaces to other kernel subsystems and release resources, devre This simplifies error handling during probe and often allows to omit this callback entirely, see Documentation/driver-api/driver-model/devres.rst for details. +The shutdown() callback is called during shutdown, reboot or kexec. Its sole purpose is to disable +the WMI device and put it in a well-known state for the WMI driver to pick up later after reboot +or kexec. Most WMI drivers need no special shutdown handling and can thus omit this callback. + Please note that new WMI drivers are required to be able to be instantiated multiple times, and are forbidden from using any deprecated GUID-based WMI functions. This means that the WMI driver should be prepared for the scenario that multiple matching WMI devices are present @@ -123,7 +128,7 @@ ACPI object is being done by the WMI subsystem, not the driver. The WMI driver core will take care that the notify() callback will only be called after the probe() callback has been called, and that no events are being received by the driver -right before and after calling its remove() callback. +right before and after calling its remove() or shutdown() callback. However WMI driver developers should be aware that multiple WMI events can be received concurrently, so any locking (if necessary) needs to be provided by the WMI driver itself. diff --git a/MAINTAINERS b/MAINTAINERS index b878ddc99f94e7..910305c11e8a88 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -701,7 +701,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-aimslab* AIO @@ -786,6 +786,7 @@ F: drivers/perf/alibaba_uncore_drw_pmu.c ALIENWARE WMI DRIVER L: Dell.Client.Kernel@dell.com S: Maintained +F: Documentation/wmi/devices/alienware-wmi.rst F: drivers/platform/x86/dell/alienware-wmi.c ALLEGRO DVT VIDEO IP CORE DRIVER @@ -809,7 +810,7 @@ ALLWINNER A10 CSI DRIVER M: Maxime Ripard L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml F: drivers/media/platform/sunxi/sun4i-csi/ @@ -818,7 +819,7 @@ M: Yong Deng M: Paul Kocialkowski L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml F: drivers/media/platform/sunxi/sun6i-csi/ @@ -826,7 +827,7 @@ ALLWINNER A31 ISP DRIVER M: Paul Kocialkowski L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-isp.yaml F: drivers/staging/media/sunxi/sun6i-isp/ F: drivers/staging/media/sunxi/sun6i-isp/uapi/sun6i-isp-config.h @@ -835,7 +836,7 @@ ALLWINNER A31 MIPI CSI-2 BRIDGE DRIVER M: Paul Kocialkowski L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml F: drivers/media/platform/sunxi/sun6i-mipi-csi2/ @@ -965,6 +966,14 @@ Q: https://patchwork.kernel.org/project/linux-rdma/list/ F: drivers/infiniband/hw/efa/ F: include/uapi/rdma/efa-abi.h +AMD 3D V-CACHE PERFORMANCE OPTIMIZER DRIVER +M: Basavaraj Natikar +R: Mario Limonciello +L: platform-driver-x86@vger.kernel.org +S: Supported +F: Documentation/ABI/testing/sysfs-bus-platform-drivers-amd_x3d_vcache +F: drivers/platform/x86/amd/x3d_vcache.c + AMD ADDRESS TRANSLATION LIBRARY (ATL) M: Yazen Ghannam L: linux-edac@vger.kernel.org @@ -1074,7 +1083,7 @@ 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 +F: drivers/platform/x86/amd/hsmp/ AMD IOMMU (AMD-VI) M: Joerg Roedel @@ -1106,6 +1115,12 @@ L: linux-i2c@vger.kernel.org S: Maintained F: drivers/i2c/busses/i2c-amd-mp2* +AMD ASF I2C DRIVER +M: Shyam Sundar S K +L: linux-i2c@vger.kernel.org +S: Supported +F: drivers/i2c/busses/i2c-amd-asf-plat.c + AMD PDS CORE DRIVER M: Shannon Nelson M: Brett Creeley @@ -1124,7 +1139,7 @@ F: drivers/platform/x86/amd/pmc/ AMD PMF DRIVER M: Shyam Sundar S K L: platform-driver-x86@vger.kernel.org -S: Maintained +S: Supported F: Documentation/ABI/testing/sysfs-amd-pmf F: drivers/platform/x86/amd/pmf/ @@ -1203,6 +1218,14 @@ F: Documentation/devicetree/bindings/perf/amlogic,g12-ddr-pmu.yaml F: drivers/perf/amlogic/ F: include/soc/amlogic/ +AMLOGIC RTC DRIVER +M: Yiting Deng +M: Xianwei Zhao +L: linux-amlogic@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml +F: drivers/rtc/rtc-amlogic-a4.c + AMPHENOL CHIPCAP 2 HUMIDITY-TEMPERATURE IIO DRIVER M: Javier Carrasco L: linux-hwmon@vger.kernel.org @@ -1256,7 +1279,6 @@ M: Cosmin Tanislav L: linux-iio@vger.kernel.org S: Supported W: https://ez.analog.com/linux-software-drivers -F: Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130 F: Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml F: drivers/iio/adc/ad4130.c @@ -1321,6 +1343,17 @@ 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 AD7625 DRIVER +M: Michael Hennerich +M: Nuno Sá +R: Trevor Gamblin +S: Supported +W: https://ez.analog.com/linux-software-drivers +W: http://analogdevicesinc.github.io/hdl/projects/pulsar_lvds/index.html +F: Documentation/devicetree/bindings/iio/adc/adi,ad7625.yaml +F: Documentation/iio/ad7625.rst +F: drivers/iio/adc/ad7625.c + ANALOG DEVICES INC AD7768-1 DRIVER M: Michael Hennerich L: linux-iio@vger.kernel.org @@ -1348,6 +1381,14 @@ F: Documentation/ABI/testing/debugfs-iio-ad9467 F: Documentation/devicetree/bindings/iio/adc/adi,ad9467.yaml F: drivers/iio/adc/ad9467.c +ANALOG DEVICES INC AD8460 DRIVER +M: Mariel Tinaco +L: linux-iio@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/iio/dac/adi,ad8460.yaml +F: drivers/iio/dac/ad8460.c + ANALOG DEVICES INC AD9739a DRIVER M: Nuno Sa M: Dragos Bogdan @@ -1515,6 +1556,7 @@ L: linux-sound@vger.kernel.org S: Supported W: http://wiki.analog.com/ W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/sound/adi,* F: sound/soc/codecs/ad1* F: sound/soc/codecs/ad7* F: sound/soc/codecs/adau* @@ -1547,6 +1589,7 @@ F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350 F: Documentation/devicetree/bindings/iio/*/adi,* F: Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml F: Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml +F: Documentation/iio/ad7606.rst F: drivers/iio/*/ad* F: drivers/iio/adc/ltc249* F: drivers/iio/amplifiers/hmc425a.c @@ -1990,7 +2033,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-actions@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/actions.yaml -F: Documentation/devicetree/bindings/clock/actions,owl-cmu.txt +F: Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml F: Documentation/devicetree/bindings/dma/owl-dma.yaml F: Documentation/devicetree/bindings/i2c/i2c-owl.yaml F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml @@ -1998,7 +2041,7 @@ F: Documentation/devicetree/bindings/mmc/owl-mmc.yaml F: Documentation/devicetree/bindings/net/actions,owl-emac.yaml F: Documentation/devicetree/bindings/pinctrl/actions,* F: Documentation/devicetree/bindings/power/actions,owl-sps.txt -F: Documentation/devicetree/bindings/timer/actions,owl-timer.txt +F: Documentation/devicetree/bindings/timer/actions,owl-timer.yaml F: arch/arm/boot/dts/actions/ F: arch/arm/mach-actions/ F: arch/arm64/boot/dts/actions/ @@ -2126,9 +2169,11 @@ L: asahi@lists.linux.dev L: linux-sound@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/sound/adi,ssm3515.yaml +F: Documentation/devicetree/bindings/sound/cirrus,cs42l84.yaml F: Documentation/devicetree/bindings/sound/apple,* F: sound/soc/apple/* F: sound/soc/codecs/cs42l83-i2c.c +F: sound/soc/codecs/cs42l84.* F: sound/soc/codecs/ssm3515.c ARM/APPLE MACHINE SUPPORT @@ -2195,7 +2240,7 @@ F: drivers/mmc/host/usdhi6rol0.c F: drivers/pinctrl/pinctrl-artpec* ARM/ASPEED I2C DRIVER -M: Brendan Higgins +M: Ryan Chen R: Benjamin Herrenschmidt R: Joel Stanley L: linux-i2c@vger.kernel.org @@ -2806,6 +2851,7 @@ F: arch/arm64/boot/dts/qcom/sdm845-cheza* ARM/QUALCOMM MAILING LIST L: linux-arm-msm@vger.kernel.org +C: irc://irc.oftc.net/linux-msm F: Documentation/devicetree/bindings/*/qcom* F: Documentation/devicetree/bindings/soc/qcom/ F: arch/arm/boot/dts/qcom/ @@ -2847,6 +2893,7 @@ M: Bjorn Andersson M: Konrad Dybcio L: linux-arm-msm@vger.kernel.org S: Maintained +C: irc://irc.oftc.net/linux-msm T: git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git F: Documentation/devicetree/bindings/arm/qcom-soc.yaml F: Documentation/devicetree/bindings/arm/qcom.yaml @@ -2904,6 +2951,7 @@ Q: http://patchwork.kernel.org/project/linux-renesas-soc/list/ C: irc://irc.libera.chat/renesas-soc T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-devel.git next F: Documentation/devicetree/bindings/hwinfo/renesas,prr.yaml +F: Documentation/devicetree/bindings/nvmem/renesas,* F: Documentation/devicetree/bindings/soc/renesas/ F: arch/arm/boot/dts/renesas/ F: arch/arm/configs/shmobile_defconfig @@ -2911,6 +2959,7 @@ F: arch/arm/include/debug/renesas-scif.S F: arch/arm/mach-shmobile/ F: arch/arm64/boot/dts/renesas/ F: arch/riscv/boot/dts/renesas/ +F: drivers/nvmem/rcar-efuse.c F: drivers/pmdomain/renesas/ F: drivers/soc/renesas/ F: include/linux/soc/renesas/ @@ -3327,6 +3376,8 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git F: Documentation/arch/arm64/ F: arch/arm64/ +F: drivers/virt/coco/arm-cca-guest/ +F: drivers/virt/coco/pkvm-guest/ F: tools/testing/selftests/arm64/ X: arch/arm64/boot/dts/ @@ -3348,7 +3399,7 @@ ASAHI KASEI AK7375 LENS VOICE COIL DRIVER M: Tianshu Qiu L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml F: drivers/media/i2c/ak7375.c @@ -3666,6 +3717,13 @@ F: kernel/audit* F: lib/*audit.c K: \baudit_[a-z_0-9]\+\b +AUTOFDO BUILD +M: Rong Xu +M: Han Shen +S: Supported +F: Documentation/dev-tools/autofdo.rst +F: scripts/Makefile.autofdo + AUXILIARY BUS DRIVER M: Greg Kroah-Hartman R: Dave Ertman @@ -3765,7 +3823,7 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/dvb-usb-v2/az6007.c AZTECH FM RADIO RECEIVER DRIVER @@ -3773,7 +3831,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-aztech* B43 WIRELESS DRIVER @@ -3792,7 +3850,7 @@ F: drivers/net/wireless/broadcom/b43legacy/ BACKLIGHT CLASS/SUBSYSTEM M: Lee Jones -M: Daniel Thompson +M: Daniel Thompson M: Jingoo Han L: dri-devel@lists.freedesktop.org S: Maintained @@ -3835,7 +3893,7 @@ W: http://www.baycom.org/~tom/ham/ham.html F: drivers/net/hamradio/baycom* BCACHE (BLOCK LAYER CACHE) -M: Coly Li +M: Coly Li M: Kent Overstreet L: linux-bcache@vger.kernel.org S: Maintained @@ -3857,7 +3915,7 @@ M: Fabien Dessenne L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/platform/st/sti/bdisp BECKHOFF CX5020 ETHERCAT MASTER DRIVER @@ -4016,6 +4074,13 @@ S: Maintained F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml F: drivers/iio/accel/bma400* +BOSCH SENSORTEC BMI270 IMU IIO DRIVER +M: Alex Lanzano +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml +F: drivers/iio/imu/bmi270/ + BOSCH SENSORTEC BMI323 IMU IIO DRIVER M: Jagath Jog J L: linux-iio@vger.kernel.org @@ -4865,7 +4930,7 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Odd fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/driver-api/media/drivers/bttv* F: drivers/media/pci/bt8xx/bttv* @@ -4979,13 +5044,13 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-cadet* CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER L: linux-media@vger.kernel.org S: Orphan -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/admin-guide/media/cafe_ccic* F: drivers/media/platform/marvell/ @@ -5169,7 +5234,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Supported W: http://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/ABI/testing/debugfs-cec-error-inj F: Documentation/devicetree/bindings/media/cec/cec-common.yaml F: Documentation/driver-api/media/cec-core.rst @@ -5186,7 +5251,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Supported W: http://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/cec/cec-gpio.yaml F: drivers/media/cec/platform/cec-gpio/ @@ -5393,7 +5458,7 @@ CHRONTEL CH7322 CEC DRIVER M: Joe Tessler L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/chrontel,ch7322.yaml F: drivers/media/cec/i2c/ch7322.c @@ -5582,7 +5647,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/pci/cobalt/ COCCINELLE/Semantic Patches (SmPL) @@ -5741,6 +5806,15 @@ F: fs/configfs/ F: include/linux/configfs.h F: samples/configfs/ +CONGATEC BOARD CONTROLLER MFD DRIVER +M: Thomas Richard +S: Maintained +F: drivers/gpio/gpio-cgbc.c +F: drivers/i2c/busses/i2c-cgbc.c +F: drivers/mfd/cgbc-core.c +F: drivers/watchdog/cgbc_wdt.c +F: include/linux/mfd/cgbc.h + CONSOLE SUBSYSTEM M: Greg Kroah-Hartman S: Supported @@ -5756,7 +5830,6 @@ F: kernel/context_tracking.c CONTROL GROUP (CGROUP) M: Tejun Heo -M: Zefan Li M: Johannes Weiner M: Michal Koutný L: cgroups@vger.kernel.org @@ -5785,7 +5858,6 @@ F: include/linux/blk-cgroup.h CONTROL GROUP - CPUSET M: Waiman Long -M: Zefan Li L: cgroups@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git @@ -6026,7 +6098,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes W: http://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/cs3308.c CS5535 Audio ALSA driver @@ -6057,7 +6129,7 @@ M: Andy Walls L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/pci/cx18/ F: include/uapi/linux/ivtv* @@ -6066,7 +6138,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/common/cx2341x* F: include/media/drv-intf/cx2341x.h @@ -6084,7 +6156,7 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Odd fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/driver-api/media/drivers/cx88* F: drivers/media/pci/cx88/ @@ -6301,7 +6373,6 @@ DECSTATION PLATFORM SUPPORT M: "Maciej W. Rozycki" L: linux-mips@vger.kernel.org S: Maintained -W: http://www.linux-mips.org/wiki/DECstation F: arch/mips/dec/ F: arch/mips/include/asm/dec/ F: arch/mips/include/asm/mach-dec/ @@ -6320,7 +6391,7 @@ DEINTERLACE DRIVERS FOR ALLWINNER H3 M: Jernej Skrabec L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/allwinner,sun8i-h3-deinterlace.yaml F: drivers/media/platform/sunxi/sun8i-di/ @@ -6447,7 +6518,7 @@ M: Hugues Fruchet L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/platform/st/sti/delta DENALI NAND DRIVER @@ -6855,7 +6926,7 @@ DONGWOON DW9714 LENS VOICE COIL DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml F: drivers/media/i2c/dw9714.c @@ -6863,13 +6934,13 @@ DONGWOON DW9719 LENS VOICE COIL DRIVER M: Daniel Scally L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/dw9719.c DONGWOON DW9768 LENS VOICE COIL DRIVER L: linux-media@vger.kernel.org S: Orphan -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9768.yaml F: drivers/media/i2c/dw9768.c @@ -6877,7 +6948,7 @@ DONGWOON DW9807 LENS VOICE COIL DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.yaml F: drivers/media/i2c/dw9807-vcm.c @@ -7077,12 +7148,10 @@ M: Javier Martinez Canillas L: dri-devel@lists.freedesktop.org S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git -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 @@ -7278,7 +7347,7 @@ F: drivers/gpu/drm/panel/panel-novatek-nt36672a.c DRM DRIVER FOR NVIDIA GEFORCE/QUADRO GPUS M: Karol Herbst M: Lyude Paul -M: Danilo Krummrich +M: Danilo Krummrich L: dri-devel@lists.freedesktop.org L: nouveau@lists.freedesktop.org S: Supported @@ -7363,6 +7432,18 @@ S: Maintained F: Documentation/devicetree/bindings/display/panel/samsung,s6d7aa0.yaml F: drivers/gpu/drm/panel/panel-samsung-s6d7aa0.c +DRM DRIVER FOR SAMSUNG S6E3HA8 PANELS +M: Dzmitry Sankouski +S: Maintained +F: Documentation/devicetree/bindings/display/panel/samsung,s6e3ha8.yaml +F: drivers/gpu/drm/panel/panel-samsung-s6e3ha8.c + +DRM DRIVER FOR SHARP MEMORY LCD +M: Alex Lanzano +S: Maintained +F: Documentation/devicetree/bindings/display/sharp,ls010b7dh04.yaml +F: drivers/gpu/drm/tiny/sharp-memory.c + DRM DRIVER FOR SITRONIX ST7586 PANELS M: David Lechner S: Maintained @@ -7440,8 +7521,7 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: drivers/gpu/drm/udl/ DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS) -M: Rodrigo Siqueira -M: Maíra Canal +M: Louis Chauvet R: Haneen Mohammed R: Simona Vetter R: Melissa Wen @@ -7773,6 +7853,7 @@ F: include/uapi/drm/v3d_drm.h DRM DRIVERS FOR VC4 M: Maxime Ripard M: Dave Stevenson +R: Maíra Canal R: Raspberry Pi Kernel Maintenance S: Supported T: git https://gitlab.freedesktop.org/drm/misc/kernel.git @@ -7807,6 +7888,7 @@ L: dri-devel@lists.freedesktop.org S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git F: Documentation/devicetree/bindings/display/xlnx/ +F: Documentation/gpu/zynqmp.rst F: drivers/gpu/drm/xlnx/ DRM GPU SCHEDULER @@ -7857,10 +7939,10 @@ F: Documentation/gpu/automated_testing.rst F: drivers/gpu/drm/ci/ DSBR100 USB FM RADIO DRIVER -M: Alexey Klimov +M: Alexey Klimov L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/dsbr100.c DT3155 MEDIA DRIVER @@ -7868,7 +7950,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/pci/dt3155/ DVB_USB_AF9015 MEDIA DRIVER @@ -7913,7 +7995,7 @@ S: Maintained W: https://linuxtv.org W: http://github.com/mkrufky Q: http://patchwork.linuxtv.org/project/linux-media/list/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/dvb-usb/cxusb* DVB_USB_EC168 MEDIA DRIVER @@ -8061,10 +8143,10 @@ S: Maintained F: drivers/edac/highbank* EDAC-CAVIUM OCTEON -M: Ralf Baechle +M: Thomas Bogendoerfer L: linux-edac@vger.kernel.org L: linux-mips@vger.kernel.org -S: Supported +S: Maintained F: drivers/edac/octeon_edac* EDAC-CAVIUM THUNDERX @@ -8104,7 +8186,8 @@ S: Maintained F: drivers/edac/e7xxx_edac.c EDAC-FSL_DDR -M: York Sun +R: Frank Li +L: imx@lists.linux.dev L: linux-edac@vger.kernel.org S: Maintained F: drivers/edac/fsl_ddr_edac.* @@ -8282,7 +8365,7 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/admin-guide/media/em28xx* F: drivers/media/usb/em28xx/ @@ -8370,7 +8453,7 @@ F: include/video/s1d13xxxfb.h EROFS FILE SYSTEM M: Gao Xiang M: Chao Yu -R: Yue Hu +R: Yue Hu R: Jeffle Xu R: Sandeep Dhavale L: linux-erofs@lists.ozlabs.org @@ -8578,7 +8661,7 @@ EXTRON DA HD 4K PLUS CEC DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/cec/usb/extron-da-hd-4k-plus/ EXYNOS DP DRIVER @@ -8841,7 +8924,7 @@ F: include/linux/arm_ffa.h FIRMWARE LOADER (request_firmware) M: Luis Chamberlain M: Russ Weight -M: Danilo Krummrich +M: Danilo Krummrich L: linux-kernel@vger.kernel.org S: Maintained F: Documentation/firmware_class/ @@ -8998,9 +9081,16 @@ F: drivers/dma/fsl-edma*.* FREESCALE ENETC ETHERNET DRIVERS M: Claudiu Manoil M: Vladimir Oltean +M: Wei Fang +M: Clark Wang +L: imx@lists.linux.dev L: netdev@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/fsl,enetc*.yaml +F: Documentation/devicetree/bindings/net/nxp,netc-blk-ctrl.yaml F: drivers/net/ethernet/freescale/enetc/ +F: include/linux/fsl/enetc_mdio.h +F: include/linux/fsl/netc_global.h FREESCALE eTSEC ETHERNET DRIVER (GIANFAR) M: Claudiu Manoil @@ -9011,6 +9101,7 @@ F: drivers/net/ethernet/freescale/gianfar* FREESCALE GPMI NAND DRIVER M: Han Xu +L: imx@lists.linux.dev L: linux-mtd@lists.infradead.org S: Maintained F: drivers/mtd/nand/raw/gpmi-nand/* @@ -9400,7 +9491,7 @@ GALAXYCORE GC2145 SENSOR DRIVER M: Alain Volmat L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml F: drivers/media/i2c/gc2145.c @@ -9437,6 +9528,14 @@ M: Kieran Bingham S: Supported F: scripts/gdb/ +GE HEALTHCARE PMC ADC DRIVER +M: Herve Codina +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/gehc,pmc-adc.yaml +F: drivers/iio/adc/gehc-pmc-adc.c +F: include/dt-bindings/iio/adc/gehc,pmc-adc.h + GEMINI CRYPTO DRIVER M: Corentin Labbe L: linux-crypto@vger.kernel.org @@ -9448,7 +9547,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-gemtek* GENERIC ARCHITECTURE TOPOLOGY @@ -9672,6 +9771,11 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/gpd-pocket-fan.c +GPIB DRIVERS +M: Dave Penkler +S: Maintained +F: drivers/staging/gpib/ + GPIO ACPI SUPPORT M: Mika Westerberg M: Andy Shevchenko @@ -9830,56 +9934,56 @@ GS1662 VIDEO SERIALIZER M: Charles-Antoine Couret L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/spi/gs1662.c GSPCA FINEPIX SUBDRIVER M: Frank Zago L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/gspca/finepix.c GSPCA GL860 SUBDRIVER M: Olivier Lorin L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/gspca/gl860/ GSPCA M5602 SUBDRIVER M: Erik Andren L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/gspca/m5602/ GSPCA PAC207 SONIXB SUBDRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/gspca/pac207.c GSPCA SN9C20X SUBDRIVER M: Brian Johnson L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/gspca/sn9c20x.c GSPCA T613 SUBDRIVER M: Leandro Costantino L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/gspca/t613.c GSPCA USB WEBCAM DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/gspca/ GTP (GPRS Tunneling Protocol) @@ -9996,7 +10100,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/hdpvr/ HEWLETT PACKARD ENTERPRISE ILO CHIF DRIVER @@ -10138,10 +10242,12 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core F: Documentation/timers/ F: include/linux/clockchips.h +F: include/linux/delay.h F: include/linux/hrtimer.h F: include/linux/timer.h F: kernel/time/clockevents.c F: kernel/time/hrtimer.c +F: kernel/time/sleep_timeout.c F: kernel/time/timer.c F: kernel/time/timer_list.c F: kernel/time/timer_migration.* @@ -10251,6 +10357,12 @@ S: Maintained W: http://www.hisilicon.com F: drivers/net/ethernet/hisilicon/hns3/ +HISILICON NETWORK HIBMCGE DRIVER +M: Jijie Shao +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/hisilicon/hibmcge/ + HISILICON NETWORK SUBSYSTEM DRIVER M: Jian Shen M: Salil Mehta @@ -10493,6 +10605,7 @@ F: Documentation/mm/hugetlbfs_reserv.rst F: Documentation/mm/vmemmap_dedup.rst F: fs/hugetlbfs/ F: include/linux/hugetlb.h +F: include/trace/events/hugetlbfs.h F: mm/hugetlb.c F: mm/hugetlb_vmemmap.c F: mm/hugetlb_vmemmap.h @@ -10503,7 +10616,7 @@ M: Jean-Christophe Trotin L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/platform/st/sti/hva HWPOISON MEMORY FAILURE HANDLING @@ -10531,7 +10644,7 @@ HYNIX HI556 SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/hi556.c HYNIX HI846 SENSOR DRIVER @@ -10647,6 +10760,14 @@ S: Maintained F: Documentation/devicetree/bindings/i2c/marvell,mv64xxx-i2c.yaml F: drivers/i2c/busses/i2c-mv64xxx.c +I2C OF COMPONENT PROBER +M: Chen-Yu Tsai +L: linux-i2c@vger.kernel.org +L: devicetree@vger.kernel.org +S: Maintained +F: drivers/i2c/i2c-core-of-prober.c +F: include/linux/i2c-of-prober.h + I2C OVER PARALLEL PORT M: Jean Delvare L: linux-i2c@vger.kernel.org @@ -10716,14 +10837,12 @@ F: Documentation/i2c/busses/i2c-viapro.rst F: drivers/i2c/busses/i2c-ali1535.c F: drivers/i2c/busses/i2c-ali1563.c F: drivers/i2c/busses/i2c-ali15x3.c -F: drivers/i2c/busses/i2c-amd756-s4882.c F: drivers/i2c/busses/i2c-amd756.c F: drivers/i2c/busses/i2c-amd8111.c F: drivers/i2c/busses/i2c-i801.c F: drivers/i2c/busses/i2c-isch.c -F: drivers/i2c/busses/i2c-nforce2-s4985.c F: drivers/i2c/busses/i2c-nforce2.c -F: drivers/i2c/busses/i2c-piix4.c +F: drivers/i2c/busses/i2c-piix4.* F: drivers/i2c/busses/i2c-sis5595.c F: drivers/i2c/busses/i2c-sis630.c F: drivers/i2c/busses/i2c-sis96x.c @@ -11447,7 +11566,7 @@ Q: https://patchwork.kernel.org/project/linux-dmaengine/list/ F: drivers/dma/ioat* INTEL IAA CRYPTO DRIVER -M: Tom Zanussi +M: Kristen Accardi L: linux-crypto@vger.kernel.org S: Supported F: Documentation/driver-api/crypto/iaa/iaa-crypto.rst @@ -11502,7 +11621,7 @@ M: Dan Scally R: Tianshu Qiu L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/userspace-api/media/v4l/pixfmt-srggb10-ipu3.rst F: drivers/media/pci/intel/ipu3/ @@ -11523,12 +11642,12 @@ M: Bingbu Cao R: Tianshu Qiu L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/admin-guide/media/ipu6-isys.rst F: drivers/media/pci/intel/ipu6/ INTEL ISHTP ECLITE DRIVER -M: Sumesh K Naduvalath +M: Srinivas Pandruvada L: platform-driver-x86@vger.kernel.org S: Supported F: drivers/platform/x86/intel/ishtp_eclite.c @@ -11588,7 +11707,7 @@ F: drivers/usb/misc/usb-ljca.c F: include/linux/usb/ljca.h INTEL MANAGEMENT ENGINE (mei) -M: Tomas Winkler +M: Alexander Usyskin L: linux-kernel@vger.kernel.org S: Supported F: Documentation/driver-api/mei/* @@ -11761,7 +11880,7 @@ M: Srinivas Pandruvada L: platform-driver-x86@vger.kernel.org S: Maintained F: Documentation/ABI/testing/debugfs-tpmi -F: drivers/platform/x86/intel/tpmi.c +F: drivers/platform/x86/intel/vsec_tpmi.c F: include/linux/intel_tpmi.h INTEL UNCORE FREQUENCY CONTROL @@ -11869,7 +11988,7 @@ F: Documentation/devicetree/bindings/media/i2c/isil,isl79987.yaml F: drivers/media/i2c/isl7998x.c INVENSENSE ICM-426xx IMU DRIVER -M: Jean-Baptiste Maneyrol +M: Jean-Baptiste Maneyrol L: linux-iio@vger.kernel.org S: Maintained W: https://invensense.tdk.com/ @@ -11884,8 +12003,16 @@ S: Maintained F: Documentation/devicetree/bindings/iio/gyroscope/invensense,mpu3050.yaml F: drivers/iio/gyro/mpu3050* +INVENSENSE MPU-6050 IMU DRIVER +M: Jean-Baptiste Maneyrol +L: linux-iio@vger.kernel.org +S: Maintained +W: https://invensense.tdk.com/ +F: Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml +F: drivers/iio/imu/inv_mpu6050/ + IOC3 ETHERNET DRIVER -M: Ralf Baechle +M: Thomas Bogendoerfer L: linux-mips@vger.kernel.org S: Maintained F: drivers/net/ethernet/sgi/ioc3-eth.c @@ -12036,7 +12163,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-isa* ISAPNP @@ -12104,6 +12231,14 @@ F: drivers/isdn/Makefile F: drivers/isdn/hardware/ F: drivers/isdn/mISDN/ +ISL28022 HARDWARE MONITORING DRIVER +M: Carsten Spieß +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml +F: Documentation/hwmon/isl28022.rst +F: drivers/hwmon/isl28022.c + ISOFS FILESYSTEM M: Jan Kara L: linux-fsdevel@vger.kernel.org @@ -12125,6 +12260,14 @@ W: https://linuxtv.org Q: http://patchwork.linuxtv.org/project/linux-media/list/ F: drivers/media/tuners/it913x* +ITE IT6263 LVDS TO HDMI BRIDGE DRIVER +M: Liu Ying +L: dri-devel@lists.freedesktop.org +S: Maintained +T: git https://gitlab.freedesktop.org/drm/misc/kernel.git +F: Documentation/devicetree/bindings/display/bridge/ite,it6263.yaml +F: drivers/gpu/drm/bridge/ite-it6263.c + ITE IT66121 HDMI BRIDGE DRIVER M: Phong LE M: Neil Armstrong @@ -12138,7 +12281,7 @@ M: Andy Walls L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/admin-guide/media/ivtv* F: drivers/media/pci/ivtv/ F: include/uapi/linux/ivtv* @@ -12286,7 +12429,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-keene* KERNEL AUTOMOUNTER @@ -12334,7 +12477,7 @@ F: mm/usercopy.c F: security/Kconfig.hardening K: \b(add|choose)_random_kstack_offset\b K: \b__check_(object_size|heap_object)\b -K: \b__counted_by\b +K: \b__counted_by(_le|_be)?\b KERNEL JANITORS L: kernel-janitors@vger.kernel.org @@ -12367,6 +12510,7 @@ F: include/trace/misc/sunrpc.h F: include/uapi/linux/nfsd/ F: include/uapi/linux/sunrpc/ F: net/sunrpc/ +F: tools/net/sunrpc/ KERNEL PACMAN PACKAGING (in addition to generic KERNEL BUILD) M: Thomas Weißschuh @@ -12405,7 +12549,7 @@ F: fs/smb/common/ F: fs/smb/server/ KERNEL UNIT TESTING FRAMEWORK (KUnit) -M: Brendan Higgins +M: Brendan Higgins M: David Gow R: Rae Moar L: linux-kselftest@vger.kernel.org @@ -12661,7 +12805,7 @@ F: samples/kfifo/ KGDB / KDB /debug_core M: Jason Wessel -M: Daniel Thompson +M: Daniel Thompson R: Douglas Anderson L: kgdb-bugreport@lists.sourceforge.net S: Maintained @@ -13071,7 +13215,7 @@ M: Michael Ellerman R: Nicholas Piggin R: Christophe Leroy R: Naveen N Rao -R: Madhavan Srinivasan +M: Madhavan Srinivasan L: linuxppc-dev@lists.ozlabs.org S: Supported W: https://github.com/linuxppc/wiki/wiki @@ -13338,12 +13482,12 @@ S: Maintained F: Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml F: drivers/gpio/gpio-loongson-64bit.c -LOONGSON LS2X APB DMA DRIVER +LOONGSON-2 APB DMA DRIVER M: Binbin Zhou L: dmaengine@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml -F: drivers/dma/ls2x-apb-dma.c +F: drivers/dma/loongson2-apb-dma.c LOONGSON LS2X I2C DRIVER M: Binbin Zhou @@ -13570,10 +13714,10 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ F: drivers/media/dvb-frontends/m88rs2000* MA901 MASTERKIT USB FM RADIO DRIVER -M: Alexey Klimov +M: Alexey Klimov L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-ma901.c MAC80211 @@ -13675,6 +13819,7 @@ F: Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml F: drivers/input/misc/88pm886-onkey.c F: drivers/mfd/88pm886.c F: drivers/regulator/88pm886-regulator.c +F: drivers/rtc/rtc-88pm886.c F: include/linux/mfd/88pm886.h MARVELL ARMADA 3700 PHY DRIVERS @@ -13816,6 +13961,12 @@ S: Supported F: Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst F: drivers/net/ethernet/marvell/octeontx2/af/ +MARVELL PEM PMU DRIVER +M: Linu Cherian +M: Gowthami Thiagarajan +S: Supported +F: drivers/perf/marvell_pem_pmu.c + MARVELL PRESTERA ETHERNET SWITCH DRIVER M: Taras Chornyi S: Supported @@ -13851,6 +14002,12 @@ R: schalla@marvell.com R: vattunuru@marvell.com F: drivers/vdpa/octeon_ep/ +MARVELL OCTEON HOTPLUG DRIVER +R: Shijith Thotton +R: Vamsi Attunuru +S: Supported +F: drivers/pci/hotplug/octep_hp.c + MATROX FRAMEBUFFER DRIVER L: linux-fbdev@vger.kernel.org S: Orphan @@ -13868,7 +14025,7 @@ MAX2175 SDR TUNER DRIVER M: Ramesh Shanmugasundaram L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/max2175.txt F: Documentation/userspace-api/media/drivers/max2175.rst F: drivers/media/i2c/max2175* @@ -14048,7 +14205,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-maxiradio* MAXLINEAR ETHERNET PHY DRIVER @@ -14131,7 +14288,7 @@ M: Laurent Pinchart L: linux-media@vger.kernel.org S: Supported W: https://www.linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/mc/ F: include/media/media-*.h F: include/uapi/linux/media.h @@ -14140,7 +14297,7 @@ MEDIA DRIVER FOR FREESCALE IMX PXP M: Philipp Zabel L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/platform/nxp/imx-pxp.[ch] MEDIA DRIVERS FOR ASCOT2E @@ -14149,7 +14306,7 @@ L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org W: http://netup.tv/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/ascot2e* MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS @@ -14157,7 +14314,7 @@ M: Jasmin Jessich L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/cxd2099* MEDIA DRIVERS FOR CXD2841ER @@ -14166,7 +14323,7 @@ L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org W: http://netup.tv/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/cxd2841er* MEDIA DRIVERS FOR CXD2880 @@ -14174,7 +14331,7 @@ M: Yasunari Takiguchi L: linux-media@vger.kernel.org S: Supported W: http://linuxtv.org/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/cxd2880/* F: drivers/media/spi/cxd2880* @@ -14182,7 +14339,7 @@ MEDIA DRIVERS FOR DIGITAL DEVICES PCIE DEVICES L: linux-media@vger.kernel.org S: Orphan W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/pci/ddbridge/* MEDIA DRIVERS FOR FREESCALE IMX @@ -14190,7 +14347,7 @@ M: Steve Longerbeam M: Philipp Zabel L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/admin-guide/media/imx.rst F: Documentation/devicetree/bindings/media/imx.txt F: drivers/staging/media/imx/ @@ -14204,7 +14361,7 @@ M: Martin Kepplinger R: Purism Kernel Team L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/admin-guide/media/imx7.rst F: Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml @@ -14219,7 +14376,7 @@ L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org W: http://netup.tv/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/helene* MEDIA DRIVERS FOR HORUS3A @@ -14228,7 +14385,7 @@ L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org W: http://netup.tv/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/horus3a* MEDIA DRIVERS FOR LNBH25 @@ -14237,14 +14394,14 @@ L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org W: http://netup.tv/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/lnbh25* MEDIA DRIVERS FOR MXL5XX TUNER DEMODULATORS L: linux-media@vger.kernel.org S: Orphan W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/mxl5xx* MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices @@ -14253,7 +14410,7 @@ L: linux-media@vger.kernel.org S: Supported W: https://linuxtv.org W: http://netup.tv/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/pci/netup_unidvb/* MEDIA DRIVERS FOR NVIDIA TEGRA - VDE @@ -14261,7 +14418,7 @@ M: Dmitry Osipenko L: linux-media@vger.kernel.org L: linux-tegra@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml F: drivers/media/platform/nvidia/tegra-vde/ @@ -14270,7 +14427,7 @@ M: Jacopo Mondi L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/renesas,ceu.yaml F: drivers/media/platform/renesas/renesas-ceu.c F: include/media/drv-intf/renesas-ceu.h @@ -14280,7 +14437,7 @@ M: Fabrizio Castro L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/renesas,drif.yaml F: drivers/media/platform/renesas/rcar_drif.c @@ -14289,7 +14446,7 @@ M: Laurent Pinchart L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/renesas,fcp.yaml F: drivers/media/platform/renesas/rcar-fcp.c F: include/media/rcar-fcp.h @@ -14299,7 +14456,7 @@ M: Kieran Bingham L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/renesas,fdp1.yaml F: drivers/media/platform/renesas/rcar_fdp1.c @@ -14308,7 +14465,7 @@ M: Niklas Söderlund L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/renesas,csi2.yaml F: Documentation/devicetree/bindings/media/renesas,isp.yaml F: Documentation/devicetree/bindings/media/renesas,vin.yaml @@ -14322,7 +14479,7 @@ M: Kieran Bingham L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/renesas,vsp1.yaml F: drivers/media/platform/renesas/vsp1/ @@ -14330,14 +14487,14 @@ MEDIA DRIVERS FOR ST STV0910 DEMODULATOR ICs L: linux-media@vger.kernel.org S: Orphan W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/stv0910* MEDIA DRIVERS FOR ST STV6111 TUNER ICs L: linux-media@vger.kernel.org S: Orphan W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/dvb-frontends/stv6111* MEDIA DRIVERS FOR STM32 - DCMI / DCMIPP @@ -14345,7 +14502,7 @@ M: Hugues Fruchet M: Alain Volmat L: linux-media@vger.kernel.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml F: Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml F: drivers/media/platform/st/stm32/stm32-dcmi.c @@ -14357,7 +14514,7 @@ L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org Q: http://patchwork.kernel.org/project/linux-media/list/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/admin-guide/media/ F: Documentation/devicetree/bindings/media/ F: Documentation/driver-api/media/ @@ -14384,10 +14541,12 @@ F: Documentation/devicetree/bindings/net/bluetooth/mediatek,mt7921s-bluetooth.ya F: drivers/bluetooth/btmtkuart.c MEDIATEK BOARD LEVEL SHUTDOWN DRIVERS +M: Sen Chu M: Sean Wang +M: Macpaul Lin L: linux-pm@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/power/reset/mt6323-poweroff.txt +F: Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml F: drivers/power/reset/mt6323-poweroff.c MEDIATEK CIR DRIVER @@ -14427,8 +14586,10 @@ M: Qingfang Deng M: SkyLake Huang L: netdev@vger.kernel.org S: Maintained -F: drivers/net/phy/mediatek-ge-soc.c -F: drivers/net/phy/mediatek-ge.c +F: drivers/net/phy/mediatek/mtk-ge-soc.c +F: drivers/net/phy/mediatek/mtk-phy-lib.c +F: drivers/net/phy/mediatek/mtk-ge.c +F: drivers/net/phy/mediatek/mtk.h F: drivers/phy/mediatek/phy-mtk-xfi-tphy.c MEDIATEK I2C CONTROLLER DRIVER @@ -14492,6 +14653,32 @@ S: Maintained F: Documentation/devicetree/bindings/mmc/mtk-sd.yaml F: drivers/mmc/host/mtk-sd.c +MEDIATEK MT6735 CLOCK & RESET DRIVERS +M: Yassine Oudjana +L: linux-clk@vger.kernel.org +L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: drivers/clk/mediatek/clk-mt6735-apmixedsys.c +F: drivers/clk/mediatek/clk-mt6735-imgsys.c +F: drivers/clk/mediatek/clk-mt6735-infracfg.c +F: drivers/clk/mediatek/clk-mt6735-mfgcfg.c +F: drivers/clk/mediatek/clk-mt6735-pericfg.c +F: drivers/clk/mediatek/clk-mt6735-topckgen.c +F: drivers/clk/mediatek/clk-mt6735-vdecsys.c +F: drivers/clk/mediatek/clk-mt6735-vencsys.c +F: include/dt-bindings/clock/mediatek,mt6735-apmixedsys.h +F: include/dt-bindings/clock/mediatek,mt6735-imgsys.h +F: include/dt-bindings/clock/mediatek,mt6735-infracfg.h +F: include/dt-bindings/clock/mediatek,mt6735-mfgcfg.h +F: include/dt-bindings/clock/mediatek,mt6735-pericfg.h +F: include/dt-bindings/clock/mediatek,mt6735-topckgen.h +F: include/dt-bindings/clock/mediatek,mt6735-vdecsys.h +F: include/dt-bindings/clock/mediatek,mt6735-vencsys.h +F: include/dt-bindings/reset/mediatek,mt6735-infracfg.h +F: include/dt-bindings/reset/mediatek,mt6735-mfgcfg.h +F: include/dt-bindings/reset/mediatek,mt6735-pericfg.h +F: include/dt-bindings/reset/mediatek,mt6735-vdecsys.h + MEDIATEK MT76 WIRELESS LAN DRIVER M: Felix Fietkau M: Lorenzo Bianconi @@ -14548,9 +14735,11 @@ F: Documentation/devicetree/bindings/mtd/mediatek,mtk-nfc.yaml F: drivers/mtd/nand/raw/mtk_* MEDIATEK PMIC LED DRIVER +M: Sen Chu M: Sean Wang +M: Macpaul Lin S: Maintained -F: Documentation/devicetree/bindings/leds/leds-mt6323.txt +F: Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml F: drivers/leds/leds-mt6323.c MEDIATEK RANDOM NUMBER GENERATOR SUPPORT @@ -14850,6 +15039,8 @@ S: Maintained W: http://www.linux-mm.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm T: quilt git://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new +F: Documentation/admin-guide/mm/ +F: Documentation/mm/ F: include/linux/gfp.h F: include/linux/gfp_types.h F: include/linux/memfd.h @@ -14933,7 +15124,7 @@ L: linux-media@vger.kernel.org L: linux-amlogic@lists.infradead.org S: Supported W: http://linux-meson.com/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/cec/amlogic,meson-gx-ao-cec.yaml F: drivers/media/cec/platform/meson/ao-cec-g12a.c F: drivers/media/cec/platform/meson/ao-cec.c @@ -14943,7 +15134,7 @@ M: Neil Armstrong L: linux-media@vger.kernel.org L: linux-amlogic@lists.infradead.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/amlogic,axg-ge2d.yaml F: drivers/media/platform/amlogic/meson-ge2d/ @@ -14959,7 +15150,7 @@ M: Neil Armstrong L: linux-media@vger.kernel.org L: linux-amlogic@lists.infradead.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/amlogic,gx-vdec.yaml F: drivers/staging/media/meson/vdec/ @@ -15143,6 +15334,19 @@ S: Maintained F: Documentation/devicetree/bindings/interrupt-controller/microchip,lan966x-oic.yaml F: drivers/irqchip/irq-lan966x-oic.c +MICROCHIP LAN966X PCI DRIVER +M: Herve Codina +S: Maintained +F: drivers/misc/lan966x_pci.c +F: drivers/misc/lan966x_pci.dtso + +MICROCHIP LAN969X ETHERNET DRIVER +M: Daniel Machon +M: UNGLinuxDriver@microchip.com +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/microchip/sparx5/lan969x/* + MICROCHIP LCDFB DRIVER M: Nicolas Ferre L: linux-fbdev@vger.kernel.org @@ -15463,6 +15667,15 @@ F: arch/arm/boot/dts/marvell/armada-xp-crs326-24g-2s.dts F: arch/arm/boot/dts/marvell/armada-xp-crs328-4c-20s-4s-bit.dts F: arch/arm/boot/dts/marvell/armada-xp-crs328-4c-20s-4s.dts +MIN HEAP +M: Kuan-Wei Chiu +L: linux-kernel@vger.kernel.org +S: Maintained +F: Documentation/core-api/min_heap.rst +F: include/linux/min_heap.h +F: lib/min_heap.c +F: lib/test_min_heap.c + MIPI CCS, SMIA AND SMIA++ IMAGE SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org @@ -15480,7 +15693,6 @@ MIPS M: Thomas Bogendoerfer L: linux-mips@vger.kernel.org S: Maintained -W: http://www.linux-mips.org/ Q: https://patchwork.kernel.org/project/linux-mips/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git F: Documentation/devicetree/bindings/mips/ @@ -15557,7 +15769,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-miropcm20* MITSUMI MM8013 FG DRIVER @@ -15706,10 +15918,10 @@ F: Documentation/hwmon/mp9941.rst F: drivers/hwmon/pmbus/mp9941.c MR800 AVERMEDIA USB FM RADIO DRIVER -M: Alexey Klimov +M: Alexey Klimov L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-mr800.c MRF24J40 IEEE 802.15.4 RADIO DRIVER @@ -15776,7 +15988,7 @@ MT9M114 ONSEMI SENSOR DRIVER M: Laurent Pinchart L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/onnn,mt9m114.yaml F: drivers/media/i2c/mt9m114.c @@ -15784,16 +15996,15 @@ MT9P031 APTINA CAMERA SENSOR M: Laurent Pinchart L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml F: drivers/media/i2c/mt9p031.c -F: include/media/i2c/mt9p031.h MT9T112 APTINA CAMERA SENSOR M: Jacopo Mondi L: linux-media@vger.kernel.org S: Odd Fixes -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/mt9t112.c F: include/media/i2c/mt9t112.h @@ -15801,7 +16012,7 @@ MT9V032 APTINA CAMERA SENSOR M: Laurent Pinchart L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/mt9v032.txt F: drivers/media/i2c/mt9v032.c F: include/media/i2c/mt9v032.h @@ -15810,7 +16021,7 @@ MT9V111 APTINA CAMERA SENSOR M: Jacopo Mondi L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/aptina,mt9v111.yaml F: drivers/media/i2c/mt9v111.c @@ -15942,6 +16153,14 @@ S: Maintained F: Documentation/devicetree/bindings/hwmon/nuvoton,nct6775.yaml F: drivers/hwmon/nct6775-i2c.c +NCT7363 HARDWARE MONITOR DRIVER +M: Ban Feng +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml +F: Documentation/hwmon/nct7363.rst +F: drivers/hwmon/nct7363.c + NETCONSOLE M: Breno Leitao S: Maintained @@ -15993,9 +16212,8 @@ F: net/netfilter/ F: tools/testing/selftests/net/netfilter/ NETROM NETWORK LAYER -M: Ralf Baechle L: linux-hams@vger.kernel.org -S: Maintained +S: Orphan W: https://linux-ax25.in-berlin.de F: include/net/netrom.h F: include/uapi/linux/netrom.h @@ -16051,6 +16269,7 @@ F: Documentation/devicetree/bindings/net/ F: Documentation/networking/net_cachelines/net_device.rst F: drivers/connector/ F: drivers/net/ +F: drivers/ptp/ F: include/dt-bindings/net/ F: include/linux/cn_proc.h F: include/linux/etherdevice.h @@ -16065,10 +16284,13 @@ F: include/linux/platform_data/wiznet.h F: include/uapi/linux/cn_proc.h F: include/uapi/linux/ethtool_netlink.h F: include/uapi/linux/if_* +F: include/uapi/linux/net_shaper.h F: include/uapi/linux/netdev* F: tools/testing/selftests/drivers/net/ X: Documentation/devicetree/bindings/net/bluetooth/ +X: Documentation/devicetree/bindings/net/can/ X: Documentation/devicetree/bindings/net/wireless/ +X: drivers/net/can/ X: drivers/net/wireless/ NETWORKING DRIVERS (WIRELESS) @@ -16115,6 +16337,7 @@ F: Documentation/networking/ F: Documentation/networking/net_cachelines/ F: Documentation/process/maintainer-netdev.rst F: Documentation/userspace-api/netlink/ +F: include/linux/ethtool.h F: include/linux/framer/framer-provider.h F: include/linux/framer/framer.h F: include/linux/in.h @@ -16129,6 +16352,7 @@ F: include/linux/rtnetlink.h F: include/linux/seq_file_net.h F: include/linux/skbuff* F: include/net/ +F: include/uapi/linux/ethtool.h F: include/uapi/linux/genetlink.h F: include/uapi/linux/hsr_netlink.h F: include/uapi/linux/in.h @@ -16157,6 +16381,8 @@ X: include/net/mac80211.h X: include/net/wext.h X: net/9p/ X: net/bluetooth/ +X: net/can/ +X: net/ceph/ X: net/mac80211/ X: net/rfkill/ X: net/wireless/ @@ -16245,7 +16471,7 @@ F: include/net/mptcp.h F: include/trace/events/mptcp.h F: include/uapi/linux/mptcp*.h F: net/mptcp/ -F: tools/testing/selftests/bpf/*/*mptcp*.c +F: tools/testing/selftests/bpf/*/*mptcp*.[ch] F: tools/testing/selftests/net/mptcp/ NETWORKING [TCP] @@ -16439,6 +16665,7 @@ NOVATEK NVT-TS I2C TOUCHSCREEN DRIVER M: Hans de Goede L: linux-input@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/input/touchscreen/novatek,nvt-ts.yaml F: drivers/input/touchscreen/novatek-nvt-ts.c NSDEPS @@ -16739,13 +16966,6 @@ S: Maintained F: Documentation/hwmon/nzxt-kraken3.rst F: drivers/hwmon/nzxt-kraken3.c -NZXT-SMART2 HARDWARE MONITORING DRIVER -M: Aleksandr Mezin -L: linux-hwmon@vger.kernel.org -S: Maintained -F: Documentation/hwmon/nzxt-smart2.rst -F: drivers/hwmon/nzxt-smart2.c - OBJAGG M: Jiri Pirko L: netdev@vger.kernel.org @@ -16887,14 +17107,6 @@ S: Maintained F: Documentation/devicetree/bindings/i2c/ti,omap4-i2c.yaml F: drivers/i2c/busses/i2c-omap.c -OMAP IMAGING SUBSYSTEM (OMAP3 ISP and OMAP4 ISS) -M: Laurent Pinchart -L: linux-media@vger.kernel.org -S: Maintained -F: Documentation/devicetree/bindings/media/ti,omap3isp.txt -F: drivers/media/platform/ti/omap3isp/ -F: drivers/staging/media/omap4iss/ - OMAP MMC SUPPORT M: Aaro Koskinen L: linux-omap@vger.kernel.org @@ -17005,13 +17217,13 @@ OMNIVISION OV01A10 SENSOR DRIVER M: Bingbu Cao L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov01a10.c OMNIVISION OV02A10 SENSOR DRIVER L: linux-media@vger.kernel.org S: Orphan -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov02a10.yaml F: drivers/media/i2c/ov02a10.c @@ -17019,28 +17231,29 @@ OMNIVISION OV08D10 SENSOR DRIVER M: Jimmy Su L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov08d10.c OMNIVISION OV08X40 SENSOR DRIVER M: Jason Chen L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov08x40.c +F: Documentation/devicetree/bindings/media/i2c/ovti,ov08x40.yaml OMNIVISION OV13858 SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov13858.c OMNIVISION OV13B10 SENSOR DRIVER M: Arec Kao L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov13b10.c OMNIVISION OV2680 SENSOR DRIVER @@ -17048,7 +17261,7 @@ M: Rui Miguel Silva M: Hans de Goede L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov2680.yaml F: drivers/media/i2c/ov2680.c @@ -17056,7 +17269,7 @@ OMNIVISION OV2685 SENSOR DRIVER M: Shunqian Zheng L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov2685.yaml F: drivers/media/i2c/ov2685.c @@ -17066,14 +17279,14 @@ R: Sakari Ailus R: Bingbu Cao L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov2740.c OMNIVISION OV4689 SENSOR DRIVER M: Mikhail Rudenko L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov4689.yaml F: drivers/media/i2c/ov4689.c @@ -17081,7 +17294,7 @@ OMNIVISION OV5640 SENSOR DRIVER M: Steve Longerbeam L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov5640.c OMNIVISION OV5647 SENSOR DRIVER @@ -17089,7 +17302,7 @@ M: Dave Stevenson M: Jacopo Mondi L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov5647.yaml F: drivers/media/i2c/ov5647.c @@ -17097,7 +17310,7 @@ OMNIVISION OV5670 SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov5670.yaml F: drivers/media/i2c/ov5670.c @@ -17105,7 +17318,7 @@ OMNIVISION OV5675 SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov5675.yaml F: drivers/media/i2c/ov5675.c @@ -17113,7 +17326,7 @@ OMNIVISION OV5693 SENSOR DRIVER M: Daniel Scally L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml F: drivers/media/i2c/ov5693.c @@ -17121,21 +17334,21 @@ OMNIVISION OV5695 SENSOR DRIVER M: Shunqian Zheng L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov5695.c OMNIVISION OV64A40 SENSOR DRIVER M: Jacopo Mondi L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml F: drivers/media/i2c/ov64a40.c OMNIVISION OV7670 SENSOR DRIVER L: linux-media@vger.kernel.org S: Orphan -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ov7670.txt F: drivers/media/i2c/ov7670.c @@ -17143,7 +17356,7 @@ OMNIVISION OV772x SENSOR DRIVER M: Jacopo Mondi L: linux-media@vger.kernel.org S: Odd fixes -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov772x.yaml F: drivers/media/i2c/ov772x.c F: include/media/i2c/ov772x.h @@ -17151,7 +17364,7 @@ F: include/media/i2c/ov772x.h OMNIVISION OV7740 SENSOR DRIVER L: linux-media@vger.kernel.org S: Orphan -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ov7740.txt F: drivers/media/i2c/ov7740.c @@ -17159,7 +17372,7 @@ OMNIVISION OV8856 SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov8856.yaml F: drivers/media/i2c/ov8856.c @@ -17168,7 +17381,7 @@ M: Jacopo Mondi M: Nicholas Roth L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov8858.yaml F: drivers/media/i2c/ov8858.c @@ -17176,7 +17389,7 @@ OMNIVISION OV9282 SENSOR DRIVER M: Dave Stevenson L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml F: drivers/media/i2c/ov9282.c @@ -17192,7 +17405,7 @@ R: Akinobu Mita R: Sylwester Nawrocki L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/ov9650.txt F: drivers/media/i2c/ov9650.c @@ -17201,7 +17414,7 @@ M: Tianshu Qiu R: Bingbu Cao L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/ov9734.c ONBOARD USB HUB DRIVER @@ -17426,6 +17639,7 @@ S: Supported F: Documentation/core-api/packing.rst F: include/linux/packing.h F: lib/packing.c +F: lib/packing_test.c PADATA PARALLEL EXECUTION MECHANISM M: Steffen Klassert @@ -17865,8 +18079,8 @@ M: Bartosz Golaszewski L: linux-pci@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git -F: drivers/pci/pwrctl/* -F: include/linux/pci-pwrctl.h +F: drivers/pci/pwrctrl/* +F: include/linux/pci-pwrctrl.h PCI SUBSYSTEM M: Bjorn Helgaas @@ -17888,6 +18102,15 @@ F: include/linux/of_pci.h F: include/linux/pci* F: include/uapi/linux/pci* +PCIE BANDWIDTH CONTROLLER +M: Ilpo Järvinen +L: linux-pci@vger.kernel.org +S: Supported +F: drivers/pci/pcie/bwctrl.c +F: drivers/thermal/pcie_cooling.c +F: include/linux/pci-bwctrl.h +F: tools/testing/selftests/pcie_bwctrl/ + PCIE DRIVER FOR AMAZON ANNAPURNA LABS M: Jonathan Chocron L: linux-pci@vger.kernel.org @@ -18187,6 +18410,13 @@ F: drivers/pinctrl/ F: include/dt-bindings/pinctrl/ F: include/linux/pinctrl/ +PIN CONTROLLER - AIROHA +M: Lorenzo Bianconi +L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/pinctrl/airoha,en7581-pinctrl.yaml +F: drivers/pinctrl/mediatek/pinctrl-airoha.c + PIN CONTROLLER - AMD M: Basavaraj Natikar M: Shyam Sundar S K @@ -18263,6 +18493,7 @@ PIN CONTROLLER - QUALCOMM M: Bjorn Andersson L: linux-arm-msm@vger.kernel.org S: Maintained +C: irc://irc.oftc.net/linux-msm F: Documentation/devicetree/bindings/pinctrl/qcom,* F: drivers/pinctrl/qcom/ @@ -18497,6 +18728,13 @@ S: Maintained F: include/linux/psi* F: kernel/sched/psi.c +PROPELLER BUILD +M: Rong Xu +M: Han Shen +S: Supported +F: Documentation/dev-tools/propeller.rst +F: scripts/Makefile.propeller + PRINTK M: Petr Mladek R: Steven Rostedt @@ -18524,7 +18762,6 @@ F: include/linux/proc_fs.h F: tools/testing/selftests/proc/ PROC SYSCTL -M: Luis Chamberlain M: Kees Cook M: Joel Granados L: linux-kernel@vger.kernel.org @@ -18630,6 +18867,13 @@ S: Maintained F: drivers/ptp/ptp_vclock.c F: net/ethtool/phc_vclocks.c +PTP VMCLOCK SUPPORT +M: David Woodhouse +L: netdev@vger.kernel.org +S: Maintained +F: drivers/ptp/ptp_vmclock.c +F: include/uapi/linux/vmclock-abi.h + PTRACE SUPPORT M: Oleg Nesterov S: Maintained @@ -18646,7 +18890,7 @@ PULSE8-CEC DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/cec/usb/pulse8/ PURELIFI PLFXLC DRIVER @@ -18661,7 +18905,7 @@ L: pvrusb2@isely.net (subscribers-only) L: linux-media@vger.kernel.org S: Maintained W: http://www.isely.net/pvrusb2/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/driver-api/media/drivers/pvrusb2* F: drivers/media/usb/pvrusb2/ @@ -18669,7 +18913,7 @@ PWC WEBCAM DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/pwc/* F: include/trace/events/pwc.h @@ -19173,7 +19417,7 @@ R: Bryan O'Donoghue L: linux-media@vger.kernel.org L: linux-arm-msm@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/*venus* F: drivers/media/platform/qcom/venus/ @@ -19218,14 +19462,14 @@ RADIOSHARK RADIO DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-shark.c RADIOSHARK2 RADIO DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-shark2.c F: drivers/media/radio/radio-tea5777.c @@ -19249,7 +19493,7 @@ RAINSHADOW-CEC DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/cec/usb/rainshadow/ RALINK MIPS ARCHITECTURE @@ -19328,12 +19572,19 @@ F: Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml F: drivers/media/platform/raspberrypi/pisp_be/ F: include/uapi/linux/media/raspberrypi/ +RASPBERRY PI PISP CAMERA FRONT END +M: Tomi Valkeinen +M: Raspberry Pi Kernel Maintenance +S: Maintained +F: Documentation/devicetree/bindings/media/raspberrypi,rp1-cfe.yaml +F: drivers/media/platform/raspberrypi/rp1-cfe/ + RC-CORE / LIRC FRAMEWORK M: Sean Young L: linux-media@vger.kernel.org S: Maintained W: http://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/driver-api/media/rc-core.rst F: Documentation/userspace-api/media/rc/ F: drivers/media/rc/ @@ -19490,6 +19741,12 @@ S: Maintained F: Documentation/devicetree/bindings/net/dsa/realtek.yaml F: drivers/net/dsa/realtek/* +REALTEK SPI-NAND +M: Chris Packham +S: Maintained +F: Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml +F: drivers/spi/spi-realtek-rtl-snand.c + REALTEK WIRELESS DRIVER (rtlwifi family) M: Ping-Ke Shih L: linux-wireless@vger.kernel.org @@ -19525,11 +19782,6 @@ F: Documentation/devicetree/bindings/regmap/ F: drivers/base/regmap/ F: include/linux/regmap.h -REISERFS FILE SYSTEM -L: reiserfs-devel@vger.kernel.org -S: Obsolete -F: fs/reiserfs/ - REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM M: Bjorn Andersson M: Mathieu Poirier @@ -19615,6 +19867,17 @@ S: Maintained F: Documentation/devicetree/bindings/sound/renesas,idt821034.yaml F: sound/soc/codecs/idt821034.c +RENESAS R-CAR & FSI AUDIO (ASoC) DRIVERS +M: Kuninori Morimoto +L: linux-sound@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/sound/renesas,rsnd.* +F: Documentation/devicetree/bindings/sound/renesas,fsi.yaml +F: sound/soc/renesas/rcar/ +F: sound/soc/renesas/fsi.c +F: include/sound/sh_fsi.h + RENESAS R-CAR GEN3 & RZ/N1 NAND CONTROLLER DRIVER M: Miquel Raynal L: linux-mtd@lists.infradead.org @@ -19663,6 +19926,15 @@ S: Supported F: Documentation/devicetree/bindings/i2c/renesas,riic.yaml F: drivers/i2c/busses/i2c-riic.c +RENESAS RZ AUDIO (ASoC) DRIVER +M: Biju Das +M: Lad Prabhakar +L: linux-sound@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml +F: sound/soc/renesas/rz-ssi.c + RENESAS RZ/G2L A/D DRIVER M: Lad Prabhakar L: linux-iio@vger.kernel.org @@ -19679,6 +19951,14 @@ S: Supported F: Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml F: drivers/counter/rz-mtu3-cnt.c +RENESAS RTCA-3 RTC DRIVER +M: Claudiu Beznea +L: linux-rtc@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/rtc/renesas,rz-rtca3.yaml +F: drivers/rtc/rtc-renesas-rtca3.c + RENESAS RZ/N1 A5PSW SWITCH DRIVER M: Clément Léger L: linux-renesas-soc@vger.kernel.org @@ -19840,6 +20120,15 @@ F: arch/riscv/ N: riscv K: riscv +RISC-V IOMMU +M: Tomasz Jeznach +L: iommu@lists.linux.dev +L: linux-riscv@lists.infradead.org +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git +F: Documentation/devicetree/bindings/iommu/riscv,iommu.yaml +F: drivers/iommu/riscv/ + RISC-V MICROCHIP FPGA SUPPORT M: Conor Dooley M: Daire McNamara @@ -19859,6 +20148,7 @@ F: arch/riscv/boot/dts/microchip/ F: drivers/char/hw_random/mpfs-rng.c F: drivers/clk/microchip/clk-mpfs*.c F: drivers/firmware/microchip/mpfs-auto-update.c +F: drivers/gpio/gpio-mpfs.c F: drivers/i2c/busses/i2c-microchip-corei2c.c F: drivers/mailbox/mailbox-mpfs.c F: drivers/pci/controller/plda/pcie-microchip-host.c @@ -19899,8 +20189,14 @@ L: linux-riscv@lists.infradead.org S: Maintained T: git https://github.com/pdp7/linux.git F: Documentation/devicetree/bindings/clock/thead,th1520-clk-ap.yaml +F: Documentation/devicetree/bindings/mailbox/thead,th1520-mbox.yaml +F: Documentation/devicetree/bindings/net/thead,th1520-gmac.yaml +F: Documentation/devicetree/bindings/pinctrl/thead,th1520-pinctrl.yaml F: arch/riscv/boot/dts/thead/ F: drivers/clk/thead/clk-th1520-ap.c +F: drivers/mailbox/mailbox-th1520.c +F: drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c +F: drivers/pinctrl/pinctrl-th1520.c F: include/dt-bindings/clock/thead,th1520-clk-ap.h RNBD BLOCK DRIVERS @@ -20065,9 +20361,8 @@ F: include/linux/mfd/rohm-generic.h F: include/linux/mfd/rohm-shared.h ROSE NETWORK LAYER -M: Ralf Baechle L: linux-hams@vger.kernel.org -S: Maintained +S: Orphan W: https://linux-ax25.in-berlin.de F: include/net/rose.h F: include/uapi/linux/rose.h @@ -20077,7 +20372,7 @@ ROTATION DRIVER FOR ALLWINNER A83T M: Jernej Skrabec L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml F: drivers/media/platform/sunxi/sun8i-rotate/ @@ -20141,6 +20436,13 @@ S: Maintained T: git https://github.com/pkshih/rtw.git F: drivers/net/wireless/realtek/rtl8xxxu/ +RTL9300 I2C DRIVER (rtl9300-i2c) +M: Chris Packham +L: linux-i2c@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml +F: drivers/i2c/busses/i2c-rtl9300.c + RTRS TRANSPORT DRIVERS M: Md. Haris Iqbal M: Jack Wang @@ -20175,13 +20477,22 @@ B: https://github.com/Rust-for-Linux/linux/issues C: zulip://rust-for-linux.zulipchat.com P: https://rust-for-linux.com/contributing T: git https://github.com/Rust-for-Linux/linux.git rust-next +F: .clippy.toml F: Documentation/rust/ +F: include/trace/events/rust_sample.h F: rust/ F: samples/rust/ F: scripts/*rust* F: tools/testing/selftests/rust/ K: \b(?i:rust)\b +RUST [ALLOC] +M: Danilo Krummrich +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/kernel/alloc.rs +F: rust/kernel/alloc/ + RXRPC SOCKETS (AF_RXRPC) M: David Howells M: Marc Dionne @@ -20223,6 +20534,16 @@ L: linux-s390@vger.kernel.org S: Supported F: drivers/s390/cio/ +S390 CRYPTO MODULES, PRNG DRIVER, ARCH RANDOM +M: Harald Freudenberger +M: Holger Dengler +L: linux-crypto@vger.kernel.org +L: linux-s390@vger.kernel.org +S: Supported +F: arch/s390/crypto/ +F: arch/s390/include/asm/archrandom.h +F: arch/s390/include/asm/cpacf.h + S390 DASD DRIVER M: Stefan Haberland M: Jan Hoeppner @@ -20232,6 +20553,14 @@ F: block/partitions/ibm.c F: drivers/s390/block/dasd* F: include/linux/dasd_mod.h +S390 HWRANDOM TRNG DRIVER +M: Harald Freudenberger +M: Holger Dengler +L: linux-crypto@vger.kernel.org +L: linux-s390@vger.kernel.org +S: Supported +F: drivers/char/hw_random/s390-trng.c + S390 IOMMU (PCI) M: Niklas Schnelle M: Matthew Rosato @@ -20276,6 +20605,12 @@ F: Documentation/arch/s390/pci.rst F: arch/s390/pci/ F: drivers/pci/hotplug/s390_pci_hpc.c +S390 PTP DRIVER +M: Sven Schnelle +L: linux-s390@vger.kernel.org +S: Supported +F: drivers/ptp/ptp_s390.c + S390 SCM DRIVER M: Vineeth Vijayan L: linux-s390@vger.kernel.org @@ -20313,10 +20648,16 @@ F: arch/s390/kvm/pci* F: drivers/vfio/pci/vfio_pci_zdev.c F: include/uapi/linux/vfio_zdev.h -S390 ZCRYPT DRIVER +S390 ZCRYPT AND PKEY DRIVER AND AP BUS M: Harald Freudenberger +M: Holger Dengler L: linux-s390@vger.kernel.org S: Supported +F: arch/s390/include/asm/ap.h +F: arch/s390/include/asm/pkey.h +F: arch/s390/include/asm/trace/zcrypt.h +F: arch/s390/include/uapi/asm/pkey.h +F: arch/s390/include/uapi/asm/zcrypt.h F: drivers/s390/crypto/ S390 ZFCP DRIVER @@ -20331,7 +20672,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/saa6588* SAA7134 VIDEO4LINUX DRIVER @@ -20339,7 +20680,7 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Odd fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/driver-api/media/drivers/saa7134* F: drivers/media/pci/saa7134/ @@ -20347,7 +20688,7 @@ SAA7146 VIDEO4LINUX-2 DRIVER M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/common/saa7146/ F: drivers/media/pci/saa7146/ F: include/media/drv-intf/saa7146* @@ -20418,7 +20759,7 @@ L: linux-samsung-soc@vger.kernel.org S: Maintained B: mailto:linux-samsung-soc@vger.kernel.org F: Documentation/devicetree/bindings/clock/samsung,s2mps11.yaml -F: Documentation/devicetree/bindings/mfd/samsung,s2m*.yaml +F: Documentation/devicetree/bindings/mfd/samsung,s2*.yaml F: Documentation/devicetree/bindings/mfd/samsung,s5m*.yaml F: Documentation/devicetree/bindings/regulator/samsung,s2m*.yaml F: Documentation/devicetree/bindings/regulator/samsung,s5m*.yaml @@ -20803,6 +21144,7 @@ Q: https://patchwork.kernel.org/project/linux-security-module/list B: mailto:linux-security-module@vger.kernel.org P: https://github.com/LinuxSecurityModule/kernel/blob/main/README.md T: git https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git +F: include/linux/lsm/ F: include/linux/lsm_audit.h F: include/linux/lsm_hook_defs.h F: include/linux/lsm_hooks.h @@ -20949,6 +21291,7 @@ M: Jan Karcher R: D. Wythe R: Tony Lu R: Wen Gu +L: linux-rdma@vger.kernel.org L: linux-s390@vger.kernel.org S: Supported F: net/smc/ @@ -20965,7 +21308,7 @@ SHARP RJ54N1CB0C SENSOR DRIVER M: Jacopo Mondi L: linux-media@vger.kernel.org S: Odd fixes -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/rj54n1cb0c.c F: include/media/i2c/rj54n1cb0c.h @@ -21015,7 +21358,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/silabs,si470x.yaml F: drivers/media/radio/si470x/radio-si470x-i2c.c @@ -21024,7 +21367,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/si470x/radio-si470x-common.c F: drivers/media/radio/si470x/radio-si470x-usb.c F: drivers/media/radio/si470x/radio-si470x.h @@ -21034,7 +21377,7 @@ M: Eduardo Valentin L: linux-media@vger.kernel.org S: Odd Fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/si4713/si4713.? SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER @@ -21042,7 +21385,7 @@ M: Eduardo Valentin L: linux-media@vger.kernel.org S: Odd Fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/si4713/radio-platform-si4713.c SI4713 FM RADIO TRANSMITTER USB DRIVER @@ -21050,7 +21393,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/si4713/radio-usb-si4713.c SIANO DVB DRIVER @@ -21058,23 +21401,23 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Odd fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/common/siano/ F: drivers/media/mmc/siano/ F: drivers/media/usb/siano/ F: drivers/media/usb/siano/ SIEMENS IPC LED DRIVERS -M: Gerd Haeussler -M: Xing Tong Wu +M: Bao Cheng Su +M: Benedikt Niedermayr M: Tobias Schaffner L: linux-leds@vger.kernel.org S: Maintained F: drivers/leds/simple/ SIEMENS IPC PLATFORM DRIVERS -M: Gerd Haeussler -M: Xing Tong Wu +M: Bao Cheng Su +M: Benedikt Niedermayr M: Tobias Schaffner L: platform-driver-x86@vger.kernel.org S: Maintained @@ -21083,8 +21426,8 @@ F: include/linux/platform_data/x86/simatic-ipc-base.h F: include/linux/platform_data/x86/simatic-ipc.h SIEMENS IPC WATCHDOG DRIVERS -M: Gerd Haeussler -M: Xing Tong Wu +M: Bao Cheng Su +M: Benedikt Niedermayr M: Tobias Schaffner L: linux-watchdog@vger.kernel.org S: Maintained @@ -21392,11 +21735,11 @@ F: include/linux/property.h SOFTWARE RAID (Multiple Disks) SUPPORT M: Song Liu -R: Yu Kuai +M: Yu Kuai L: linux-raid@vger.kernel.org S: Supported Q: https://patchwork.kernel.org/project/linux-raid/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux.git F: drivers/md/Kconfig F: drivers/md/Makefile F: drivers/md/md* @@ -21434,14 +21777,14 @@ SONY IMX208 SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/imx208.c SONY IMX214 SENSOR DRIVER M: Ricardo Ribalda L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx214.yaml F: drivers/media/i2c/imx214.c @@ -21449,7 +21792,7 @@ SONY IMX219 SENSOR DRIVER M: Dave Stevenson L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/imx219.yaml F: drivers/media/i2c/imx219.c @@ -21457,7 +21800,7 @@ SONY IMX258 SENSOR DRIVER M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml F: drivers/media/i2c/imx258.c @@ -21465,7 +21808,7 @@ SONY IMX274 SENSOR DRIVER M: Leon Luo L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml F: drivers/media/i2c/imx274.c @@ -21474,7 +21817,7 @@ M: Kieran Bingham M: Umang Jain L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml F: drivers/media/i2c/imx283.c @@ -21482,7 +21825,7 @@ SONY IMX290 SENSOR DRIVER M: Manivannan Sadhasivam L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml F: drivers/media/i2c/imx290.c @@ -21491,7 +21834,7 @@ M: Laurent Pinchart M: Manivannan Sadhasivam L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml F: drivers/media/i2c/imx296.c @@ -21499,20 +21842,20 @@ SONY IMX319 SENSOR DRIVER M: Bingbu Cao L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/imx319.c SONY IMX334 SENSOR DRIVER L: linux-media@vger.kernel.org S: Orphan -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml F: drivers/media/i2c/imx334.c SONY IMX335 SENSOR DRIVER L: linux-media@vger.kernel.org S: Orphan -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml F: drivers/media/i2c/imx335.c @@ -21520,13 +21863,13 @@ SONY IMX355 SENSOR DRIVER M: Tianshu Qiu L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/imx355.c SONY IMX412 SENSOR DRIVER L: linux-media@vger.kernel.org S: Orphan -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml F: drivers/media/i2c/imx412.c @@ -21534,7 +21877,7 @@ SONY IMX415 SENSOR DRIVER M: Michael Riesch L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml F: drivers/media/i2c/imx415.c @@ -21823,7 +22166,7 @@ M: Benjamin Mugnier M: Sylvain Petinot L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/st,st-mipid02.yaml F: drivers/media/i2c/st-mipid02.c @@ -21859,7 +22202,7 @@ M: Benjamin Mugnier M: Sylvain Petinot L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml F: Documentation/userspace-api/media/drivers/vgxy61.rst F: drivers/media/i2c/vgxy61.c @@ -21886,17 +22229,6 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/staging/media/atomisp/ -STAGING - FIELDBUS SUBSYSTEM -M: Sven Van Asbroeck -S: Maintained -F: drivers/staging/fieldbus/* -F: drivers/staging/fieldbus/Documentation/ - -STAGING - HMS ANYBUS-S BUS -M: Sven Van Asbroeck -S: Maintained -F: drivers/staging/fieldbus/anybuss/ - STAGING - INDUSTRIAL IO M: Jonathan Cameron L: linux-iio@vger.kernel.org @@ -21911,18 +22243,6 @@ L: linux-tegra@vger.kernel.org S: Maintained F: drivers/staging/nvec/ -STAGING - OLPC SECONDARY DISPLAY CONTROLLER (DCON) -M: Jens Frederich -M: Jon Nettleton -S: Maintained -W: http://wiki.laptop.org/go/DCON -F: drivers/staging/olpc_dcon/ - -STAGING - REALTEK RTL8712U DRIVERS -M: Florian Schilhabel . -S: Odd Fixes -F: drivers/staging/rtl8712/ - STAGING - SEPS525 LCD CONTROLLER DRIVERS M: Michael Hennerich L: linux-fbdev@vger.kernel.org @@ -21938,11 +22258,6 @@ L: linux-fbdev@vger.kernel.org S: Maintained F: drivers/staging/sm750fb/ -STAGING - VIA VT665X DRIVERS -M: Philipp Hortmann -S: Odd Fixes -F: drivers/staging/vt665?/ - STAGING SUBSYSTEM M: Greg Kroah-Hartman L: linux-staging@lists.linux.dev @@ -22097,7 +22412,7 @@ F: drivers/char/hw_random/jh7110-trng.c STARFIVE WATCHDOG DRIVER M: Xingyu Wu -M: Samin Guo +M: Ziv Xu S: Supported F: Documentation/devicetree/bindings/watchdog/starfive* F: drivers/watchdog/starfive-wdt.c @@ -22149,7 +22464,7 @@ STK1160 USB VIDEO CAPTURE DRIVER M: Ezequiel Garcia L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/stk1160/ STM32 AUDIO (ASoC) DRIVERS @@ -22179,6 +22494,12 @@ F: drivers/*/stm32-*timer* F: drivers/pwm/pwm-stm32* F: include/linux/*/stm32-*tim* +STM32MP25 USB3/PCIE COMBOPHY DRIVER +M: Christian Bruel +S: Maintained +F: Documentation/devicetree/bindings/phy/st,stm32mp25-combophy.yaml +F: drivers/phy/st/phy-stm32-combophy.c + STMMAC ETHERNET DRIVER M: Alexandre Torgue M: Jose Abreu @@ -22209,12 +22530,6 @@ S: Maintained F: Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml F: drivers/input/keyboard/sun4i-lradc-keys.c -SUNDANCE NETWORK DRIVER -M: Denis Kirjanov -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/ethernet/dlink/sundance.c - SUNPLUS ETHERNET DRIVER M: Wells Lu L: netdev@vger.kernel.org @@ -22586,7 +22901,7 @@ L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org Q: http://patchwork.linuxtv.org/project/linux-media/list/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/tuners/tda18250* TDA18271 MEDIA DRIVER @@ -22632,7 +22947,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/tda9840* TEA5761 TUNER DRIVER @@ -22640,7 +22955,7 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Odd fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/tuners/tea5761.* TEA5767 TUNER DRIVER @@ -22648,7 +22963,7 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/tuners/tea5767.* TEA6415C MEDIA DRIVER @@ -22656,7 +22971,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/tea6415c* TEA6420 MEDIA DRIVER @@ -22664,7 +22979,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/i2c/tea6420* TEAM DRIVER @@ -22900,6 +23215,12 @@ F: include/linux/dma/k3-udma-glue.h F: include/linux/dma/ti-cppi5.h X: drivers/dma/ti/cppi41.c +TEXAS INSTRUMENTS TPS25990 HARDWARE MONITOR DRIVER +M: Jerome Brunet +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml + TEXAS INSTRUMENTS TPS23861 PoE PSE DRIVER M: Robert Marko M: Luka Perkov @@ -22952,7 +23273,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-raremono.c THERMAL @@ -23028,7 +23349,7 @@ M: Laurent Pinchart M: Paul Elder L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml F: Documentation/userspace-api/media/drivers/thp7312.rst F: drivers/media/i2c/thp7312.c @@ -23207,7 +23528,7 @@ F: Documentation/devicetree/bindings/net/ti,icss*.yaml F: drivers/net/ethernet/ti/icssg/* TI J721E CSI2RX DRIVER -M: Jai Luthra +M: Jai Luthra L: linux-media@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/media/ti,j721e-csi2rx-shim.yaml @@ -23585,10 +23906,9 @@ F: drivers/net/tun.c TURBOCHANNEL SUBSYSTEM M: "Maciej W. Rozycki" -M: Ralf Baechle L: linux-mips@vger.kernel.org S: Maintained -Q: http://patchwork.linux-mips.org/project/linux-mips/list/ +Q: https://patchwork.kernel.org/project/linux-mips/list/ F: drivers/tc/ F: include/linux/tc.h @@ -23615,7 +23935,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Odd Fixes W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/pci/tw68/ TW686X VIDEO4LINUX DRIVER @@ -23623,7 +23943,7 @@ M: Ezequiel Garcia L: linux-media@vger.kernel.org S: Maintained W: http://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/pci/tw686x/ U-BOOT ENVIRONMENT VARIABLES @@ -23725,6 +24045,7 @@ UNICODE SUBSYSTEM M: Gabriel Krisman Bertazi L: linux-fsdevel@vger.kernel.org S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/krisman/unicode.git F: fs/unicode/ UNIFDEF @@ -23768,7 +24089,9 @@ F: drivers/ufs/host/*dwc* UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER EXYNOS HOOKS M: Alim Akhtar +R: Peter Griffin L: linux-scsi@vger.kernel.org +L: linux-samsung-soc@vger.kernel.org S: Maintained F: drivers/ufs/host/ufs-exynos* @@ -24095,6 +24418,13 @@ L: linux-usb@vger.kernel.org S: Orphan F: drivers/usb/typec/tcpm/ +USB TYPEC TUSB1046 MUX DRIVER +M: Romain Gantois +L: linux-usb@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/usb/ti,tusb1046.yaml +F: drivers/usb/typec/mux/tusb1046.c + USB UHCI DRIVER M: Alan Stern L: linux-usb@vger.kernel.org @@ -24103,10 +24433,11 @@ F: drivers/usb/host/uhci* USB VIDEO CLASS M: Laurent Pinchart +M: Hans de Goede L: linux-media@vger.kernel.org S: Maintained W: http://www.ideasonboard.org/uvc/ -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/usb/uvc/ F: include/uapi/linux/uvcvideo.h @@ -24158,6 +24489,7 @@ F: lib/iov_iter.c USERSPACE DMA BUFFER DRIVER M: Gerd Hoffmann +M: Vivek Kasireddy L: dri-devel@lists.freedesktop.org S: Maintained T: git https://gitlab.freedesktop.org/drm/misc/kernel.git @@ -24212,7 +24544,7 @@ V4L2 ASYNC AND FWNODE FRAMEWORKS M: Sakari Ailus L: linux-media@vger.kernel.org S: Maintained -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/v4l2-core/v4l2-async.c F: drivers/media/v4l2-core/v4l2-fwnode.c F: include/media/v4l2-async.h @@ -24378,7 +24710,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/test-drivers/vicodec/* VIDEO I2C POLLING DRIVER @@ -24406,7 +24738,7 @@ 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 +T: git git://linuxtv.org/media.git F: drivers/media/test-drivers/vidtv/* VIMC VIRTUAL MEDIA CONTROLLER DRIVER @@ -24415,7 +24747,7 @@ R: Kieran Bingham L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/test-drivers/vimc/* VIRT LIB @@ -24646,6 +24978,18 @@ S: Maintained F: drivers/input/serio/userio.c F: include/uapi/linux/userio.h +VISHAY VEML3235 AMBIENT LIGHT SENSOR DRIVER +M: Javier Carrasco +S: Maintained +F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml +F: drivers/iio/light/veml3235.c + +VISHAY VEML6030 AMBIENT LIGHT SENSOR DRIVER +M: Javier Carrasco +S: Maintained +F: Documentation/devicetree/bindings/iio/light/vishay,veml6030.yaml +F: drivers/iio/light/veml6030.c + VISHAY VEML6075 UVA AND UVB LIGHT SENSOR DRIVER M: Javier Carrasco S: Maintained @@ -24663,7 +25007,7 @@ M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/test-drivers/vivid/* VM SOCKETS (AF_VSOCK) @@ -25217,7 +25561,7 @@ M: Mauro Carvalho Chehab L: linux-media@vger.kernel.org S: Maintained W: https://linuxtv.org -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: drivers/media/tuners/xc2028.* XDP (eXpress Data Path) @@ -25441,7 +25785,7 @@ XILINX VIDEO IP CORES M: Laurent Pinchart L: linux-media@vger.kernel.org S: Supported -T: git git://linuxtv.org/media_tree.git +T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/xilinx/ F: drivers/media/platform/xilinx/ F: include/uapi/linux/xilinx-v4l2-controls.h diff --git a/Makefile b/Makefile index 68a8faff25432a..5c9b1d2d59b4dc 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 -PATCHLEVEL = 12 +PATCHLEVEL = 13 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc4 NAME = Baby Opossum Posse # *DOCUMENTATION* @@ -40,7 +40,7 @@ __all: this-makefile := $(lastword $(MAKEFILE_LIST)) abs_srctree := $(realpath $(dir $(this-makefile))) -abs_objtree := $(CURDIR) +abs_output := $(CURDIR) ifneq ($(sub_make_done),1) @@ -134,6 +134,10 @@ ifeq ("$(origin M)", "command line") KBUILD_EXTMOD := $(M) endif +ifeq ("$(origin MO)", "command line") + KBUILD_EXTMOD_OUTPUT := $(MO) +endif + $(if $(word 2, $(KBUILD_EXTMOD)), \ $(error building multiple external modules is not supported)) @@ -176,18 +180,41 @@ export KBUILD_EXTRA_WARN # The O= assignment takes precedence over the KBUILD_OUTPUT environment # variable. -# Do we want to change the working directory? ifeq ("$(origin O)", "command line") KBUILD_OUTPUT := $(O) endif -ifneq ($(KBUILD_OUTPUT),) +ifdef KBUILD_EXTMOD + ifdef KBUILD_OUTPUT + objtree := $(realpath $(KBUILD_OUTPUT)) + $(if $(objtree),,$(error specified kernel directory "$(KBUILD_OUTPUT)" does not exist)) + else + objtree := $(abs_srctree) + endif + # If Make is invoked from the kernel directory (either kernel + # source directory or kernel build directory), external modules + # are built in $(KBUILD_EXTMOD) for backward compatibility, + # otherwise, built in the current directory. + output := $(or $(KBUILD_EXTMOD_OUTPUT),$(if $(filter $(CURDIR),$(objtree) $(abs_srctree)),$(KBUILD_EXTMOD))) + # KBUILD_EXTMOD might be a relative path. Remember its absolute path before + # Make changes the working directory. + srcroot := $(realpath $(KBUILD_EXTMOD)) + $(if $(srcroot),,$(error specified external module directory "$(KBUILD_EXTMOD)" does not exist)) +else + objtree := . + output := $(KBUILD_OUTPUT) +endif + +export objtree srcroot + +# Do we want to change the working directory? +ifneq ($(output),) # $(realpath ...) gets empty if the path does not exist. Run 'mkdir -p' first. -$(shell mkdir -p "$(KBUILD_OUTPUT)") +$(shell mkdir -p "$(output)") # $(realpath ...) resolves symlinks -abs_objtree := $(realpath $(KBUILD_OUTPUT)) -$(if $(abs_objtree),,$(error failed to create output directory "$(KBUILD_OUTPUT)")) -endif # ifneq ($(KBUILD_OUTPUT),) +abs_output := $(realpath $(output)) +$(if $(abs_output),,$(error failed to create output directory "$(output)")) +endif ifneq ($(words $(subst :, ,$(abs_srctree))), 1) $(error source directory cannot contain spaces or colons) @@ -197,7 +224,7 @@ export sub_make_done := 1 endif # sub_make_done -ifeq ($(abs_objtree),$(CURDIR)) +ifeq ($(abs_output),$(CURDIR)) # Suppress "Entering directory ..." if we are at the final work directory. no-print-directory := --no-print-directory else @@ -221,43 +248,41 @@ $(filter-out $(this-makefile), $(MAKECMDGOALS)) __all: __sub-make # Invoke a second make in the output directory, passing relevant variables __sub-make: - $(Q)$(MAKE) $(no-print-directory) -C $(abs_objtree) \ + $(Q)$(MAKE) $(no-print-directory) -C $(abs_output) \ -f $(abs_srctree)/Makefile $(MAKECMDGOALS) else # need-sub-make # We process the rest of the Makefile if this is the final invocation of make -ifeq ($(abs_srctree),$(abs_objtree)) - # building in the source tree - srctree := . - building_out_of_srctree := -else - ifeq ($(abs_srctree)/,$(dir $(abs_objtree))) - # building in a subdirectory of the source tree - srctree := .. - else - srctree := $(abs_srctree) - endif - building_out_of_srctree := 1 +ifndef KBUILD_EXTMOD +srcroot := $(abs_srctree) endif -ifneq ($(KBUILD_ABS_SRCTREE),) -srctree := $(abs_srctree) +ifeq ($(srcroot),$(CURDIR)) +building_out_of_srctree := +else +export building_out_of_srctree := 1 endif -objtree := . +ifdef KBUILD_ABS_SRCTREE + # Do nothing. Use the absolute path. +else ifeq ($(srcroot),$(CURDIR)) + # Building in the source. + srcroot := . +else ifeq ($(srcroot)/,$(dir $(CURDIR))) + # Building in a subdirectory of the source. + srcroot := .. +endif -VPATH := +export srctree := $(if $(KBUILD_EXTMOD),$(abs_srctree),$(srcroot)) -ifeq ($(KBUILD_EXTMOD),) ifdef building_out_of_srctree -VPATH := $(srctree) -endif +export VPATH := $(srcroot) +else +VPATH := endif -export building_out_of_srctree srctree objtree VPATH - # To make sure we do not include .config for any of the *config targets # catch them early, and hand them over to scripts/kconfig/Makefile # It is allowed to specify more targets when calling make, including @@ -276,7 +301,7 @@ no-dot-config-targets := $(clean-targets) \ outputmakefile rustavailable rustfmt rustfmtcheck no-sync-config-targets := $(no-dot-config-targets) %install modules_sign kernelrelease \ image_name -single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %.symtypes %/ +single-targets := %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.rsi %.s %/ config-build := mixed-build := @@ -354,7 +379,7 @@ else # !mixed-build include $(srctree)/scripts/Kbuild.include # Read KERNELRELEASE from include/config/kernel.release (if it exists) -KERNELRELEASE = $(call read-file, include/config/kernel.release) +KERNELRELEASE = $(call read-file, $(objtree)/include/config/kernel.release) KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION) export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION @@ -446,18 +471,23 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS) export rust_common_flags := --edition=2021 \ -Zbinary_dep_depinfo=y \ -Astable_features \ - -Dunsafe_op_in_unsafe_fn \ -Dnon_ascii_idents \ + -Dunsafe_op_in_unsafe_fn \ + -Wmissing_docs \ -Wrust_2018_idioms \ -Wunreachable_pub \ - -Wmissing_docs \ - -Wrustdoc::missing_crate_level_docs \ -Wclippy::all \ + -Wclippy::ignored_unit_patterns \ -Wclippy::mut_mut \ -Wclippy::needless_bitwise_bool \ -Wclippy::needless_continue \ + -Aclippy::needless_lifetimes \ -Wclippy::no_mangle_with_rust_abi \ - -Wclippy::dbg_macro + -Wclippy::undocumented_unsafe_blocks \ + -Wclippy::unnecessary_safety_comment \ + -Wclippy::unnecessary_safety_doc \ + -Wrustdoc::missing_crate_level_docs \ + -Wrustdoc::unescaped_backticks KBUILD_HOSTCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) \ $(HOSTCFLAGS) -I $(srctree)/scripts/include @@ -508,7 +538,7 @@ KGZIP = gzip KBZIP2 = bzip2 KLZOP = lzop LZMA = lzma -LZ4 = lz4c +LZ4 = lz4 XZ = xz ZSTD = zstd @@ -538,7 +568,7 @@ USERINCLUDE := \ LINUXINCLUDE := \ -I$(srctree)/arch/$(SRCARCH)/include \ -I$(objtree)/arch/$(SRCARCH)/include/generated \ - $(if $(building_out_of_srctree),-I$(srctree)/include) \ + -I$(srctree)/include \ -I$(objtree)/include \ $(USERINCLUDE) @@ -582,6 +612,9 @@ endif # Allows the usage of unstable features in stable compilers. export RUSTC_BOOTSTRAP := 1 +# Allows finding `.clippy.toml` in out-of-srctree builds. +export CLIPPY_CONF_DIR := $(srctree) + export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN export HOSTRUSTC KBUILD_HOSTRUSTFLAGS @@ -621,13 +654,25 @@ ifdef building_out_of_srctree # At the same time when output Makefile generated, generate .gitignore to # ignore whole output directory +ifdef KBUILD_EXTMOD +print_env_for_makefile = \ + echo "export KBUILD_OUTPUT = $(objtree)"; \ + echo "export KBUILD_EXTMOD = $(realpath $(srcroot))" ; \ + echo "export KBUILD_EXTMOD_OUTPUT = $(CURDIR)" +else +print_env_for_makefile = \ + echo "export KBUILD_OUTPUT = $(CURDIR)" +endif + quiet_cmd_makefile = GEN Makefile cmd_makefile = { \ - echo "\# Automatically generated by $(srctree)/Makefile: don't edit"; \ - echo "include $(srctree)/Makefile"; \ + echo "\# Automatically generated by $(abs_srctree)/Makefile: don't edit"; \ + $(print_env_for_makefile); \ + echo "include $(abs_srctree)/Makefile"; \ } > Makefile outputmakefile: +ifeq ($(KBUILD_EXTMOD),) @if [ -f $(srctree)/.config -o \ -d $(srctree)/include/config -o \ -d $(srctree)/arch/$(SRCARCH)/include/generated ]; then \ @@ -637,7 +682,16 @@ outputmakefile: echo >&2 "***"; \ false; \ fi - $(Q)ln -fsn $(srctree) source +else + @if [ -f $(srcroot)/modules.order ]; then \ + echo >&2 "***"; \ + echo >&2 "*** The external module source tree is not clean."; \ + echo >&2 "*** Please run 'make -C $(abs_srctree) M=$(realpath $(srcroot)) clean'"; \ + echo >&2 "***"; \ + false; \ + fi +endif + $(Q)ln -fsn $(srcroot) source $(call cmd,makefile) $(Q)test -e .gitignore || \ { echo "# this is build directory, ignore it"; echo "*"; } > .gitignore @@ -709,7 +763,7 @@ endif # in addition to whatever we do anyway. # Just "make" or "make all" shall build modules as well -ifneq ($(filter all modules nsdeps %compile_commands.json clang-%,$(MAKECMDGOALS)),) +ifneq ($(filter all modules nsdeps compile_commands.json clang-%,$(MAKECMDGOALS)),) KBUILD_MODULES := 1 endif @@ -720,7 +774,7 @@ endif export KBUILD_MODULES KBUILD_BUILTIN ifdef need-config -include include/config/auto.conf +include $(objtree)/include/config/auto.conf endif ifeq ($(KBUILD_EXTMOD),) @@ -781,17 +835,22 @@ $(KCONFIG_CONFIG): else # !may-sync-config # External modules and some install targets need include/generated/autoconf.h # and include/config/auto.conf but do not care if they are up-to-date. -# Use auto.conf to trigger the test -PHONY += include/config/auto.conf - -include/config/auto.conf: - @test -e include/generated/autoconf.h -a -e $@ || ( \ - echo >&2; \ - echo >&2 " ERROR: Kernel configuration is invalid."; \ - echo >&2 " include/generated/autoconf.h or $@ are missing.";\ - echo >&2 " Run 'make oldconfig && make prepare' on kernel src to fix it."; \ - echo >&2 ; \ - /bin/false) +# Use auto.conf to show the error message + +checked-configs := $(addprefix $(objtree)/, include/generated/autoconf.h include/generated/rustc_cfg include/config/auto.conf) +missing-configs := $(filter-out $(wildcard $(checked-configs)), $(checked-configs)) + +ifdef missing-configs +PHONY += $(objtree)/include/config/auto.conf + +$(objtree)/include/config/auto.conf: + @echo >&2 '***' + @echo >&2 '*** ERROR: Kernel configuration is invalid. The following files are missing:' + @printf >&2 '*** - %s\n' $(missing-configs) + @echo >&2 '*** Run "make oldconfig && make prepare" on kernel source to fix it.' + @echo >&2 '***' + @/bin/false +endif endif # may-sync-config endif # need-config @@ -1005,8 +1064,10 @@ ifdef CONFIG_CC_IS_GCC KBUILD_CFLAGS += -fconserve-stack endif -# change __FILE__ to the relative path from the srctree -KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=) +# change __FILE__ to the relative path to the source directory +ifdef building_out_of_srctree +KBUILD_CPPFLAGS += $(call cc-option,-fmacro-prefix-map=$(srcroot)/=) +endif # include additional Makefiles when needed include-y := scripts/Makefile.extrawarn @@ -1018,6 +1079,8 @@ include-$(CONFIG_KMSAN) += scripts/Makefile.kmsan include-$(CONFIG_UBSAN) += scripts/Makefile.ubsan include-$(CONFIG_KCOV) += scripts/Makefile.kcov include-$(CONFIG_RANDSTRUCT) += scripts/Makefile.randstruct +include-$(CONFIG_AUTOFDO_CLANG) += scripts/Makefile.autofdo +include-$(CONFIG_PROPELLER_CLANG) += scripts/Makefile.propeller include-$(CONFIG_GCC_PLUGINS) += scripts/Makefile.gcc-plugins include $(addprefix $(srctree)/, $(include-y)) @@ -1098,10 +1161,6 @@ export MODLIB PHONY += prepare0 -export extmod_prefix = $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/) -export MODORDER := $(extmod_prefix)modules.order -export MODULES_NSDEPS := $(extmod_prefix)modules.nsdeps - ifeq ($(KBUILD_EXTMOD),) build-dir := . @@ -1196,7 +1255,8 @@ PHONY += prepare archprepare archprepare: outputmakefile archheaders archscripts scripts include/config/kernel.release \ asm-generic $(version_h) include/generated/utsrelease.h \ - include/generated/compile.h include/generated/autoconf.h remove-stale-files + include/generated/compile.h include/generated/autoconf.h \ + include/generated/rustc_cfg remove-stale-files prepare0: archprepare $(Q)$(MAKE) $(build)=scripts/mod @@ -1427,6 +1487,10 @@ ifdef CONFIG_OF_EARLY_FLATTREE all: dtbs endif +ifdef CONFIG_GENERIC_BUILTIN_DTB +vmlinux: dtbs +endif + endif PHONY += scripts_dtc @@ -1494,7 +1558,8 @@ CLEAN_FILES += vmlinux.symvers modules-only.symvers \ modules.builtin modules.builtin.modinfo modules.nsdeps \ modules.builtin.ranges vmlinux.o.map \ compile_commands.json rust/test \ - rust-project.json .vmlinux.objs .vmlinux.export.c + rust-project.json .vmlinux.objs .vmlinux.export.c \ + .builtin-dtbs-list .builtin-dtb.S # Directories & files removed with 'make mrproper' MRPROPER_FILES += include/config include/generated \ @@ -1602,7 +1667,6 @@ help: @echo ' with a stack size larger than MINSTACKSIZE (default: 100)' @echo ' versioncheck - Sanity check on version.h usage' @echo ' includecheck - Check for duplicate included header files' - @echo ' export_report - List the usages of all exported symbols' @echo ' headerdep - Detect inclusion cycles in headers' @echo ' coccicheck - Check with Coccinelle' @echo ' clang-analyzer - Check with clang static analyzer' @@ -1743,18 +1807,9 @@ rusttest: prepare # Formatting targets PHONY += rustfmt rustfmtcheck -# We skip `rust/alloc` since we want to minimize the diff w.r.t. upstream. -# -# We match using absolute paths since `find` does not resolve them -# when matching, which is a problem when e.g. `srctree` is `..`. -# We `grep` afterwards in order to remove the directory entry itself. rustfmt: - $(Q)find $(abs_srctree) -type f -name '*.rs' \ - -o -path $(abs_srctree)/rust/alloc -prune \ - -o -path $(abs_objtree)/rust/test -prune \ - | grep -Fv $(abs_srctree)/rust/alloc \ - | grep -Fv $(abs_objtree)/rust/test \ - | grep -Fv generated \ + $(Q)find $(srctree) $(RCS_FIND_IGNORE) \ + -type f -a -name '*.rs' -a ! -name '*generated*' -print \ | xargs $(RUSTFMT) $(rustfmt_flags) rustfmtcheck: rustfmt_flags = --check @@ -1793,14 +1848,10 @@ filechk_kernel.release = echo $(KERNELRELEASE) KBUILD_BUILTIN := KBUILD_MODULES := 1 -build-dir := $(KBUILD_EXTMOD) +build-dir := . -compile_commands.json: $(extmod_prefix)compile_commands.json -PHONY += compile_commands.json - -clean-dirs := $(KBUILD_EXTMOD) -clean: private rm-files := $(KBUILD_EXTMOD)/Module.symvers $(KBUILD_EXTMOD)/modules.nsdeps \ - $(KBUILD_EXTMOD)/compile_commands.json +clean-dirs := . +clean: private rm-files := Module.symvers modules.nsdeps compile_commands.json PHONY += prepare # now expand this into a simple variable to reduce the cost of shell evaluations @@ -1859,7 +1910,7 @@ endif ifdef CONFIG_MODULES -$(MODORDER): $(build-dir) +modules.order: $(build-dir) @: # KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. @@ -1870,7 +1921,7 @@ ifneq ($(KBUILD_MODPOST_NOFINAL),1) endif PHONY += modules_check -modules_check: $(MODORDER) +modules_check: modules.order $(Q)$(CONFIG_SHELL) $(srctree)/scripts/modules-check.sh $< else # CONFIG_MODULES @@ -1911,15 +1962,15 @@ $(single-ko): single_modules $(single-no-ko): $(build-dir) @: -# Remove MODORDER when done because it is not the real one. +# Remove modules.order when done because it is not the real one. PHONY += single_modules single_modules: $(single-no-ko) modules_prepare - $(Q){ $(foreach m, $(single-ko), echo $(extmod_prefix)$(m:%.ko=%.o);) } > $(MODORDER) + $(Q){ $(foreach m, $(single-ko), echo $(m:%.ko=%.o);) } > modules.order $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost ifneq ($(KBUILD_MODPOST_NOFINAL),1) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal endif - $(Q)rm -f $(MODORDER) + $(Q)rm -f modules.order single-goals := $(addprefix $(build-dir)/, $(single-no-ko)) @@ -1927,6 +1978,8 @@ KBUILD_MODULES := 1 endif +prepare: outputmakefile + # Preset locale variables to speed up the build process. Limit locale # tweaks to this spot to avoid wrong language settings when running # make menuconfig etc. @@ -1942,7 +1995,7 @@ $(clean-dirs): clean: $(clean-dirs) $(call cmd,rmfiles) - @find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ + @find . $(RCS_FIND_IGNORE) \ \( -name '*.[aios]' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \ -o -name '*.ko.*' \ -o -name '*.dtb' -o -name '*.dtbo' \ @@ -1975,7 +2028,12 @@ tags TAGS cscope gtags: FORCE PHONY += rust-analyzer rust-analyzer: +$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh +ifdef KBUILD_EXTMOD +# FIXME: external modules must not descend into a sub-directory of the kernel + $(Q)$(MAKE) $(build)=$(objtree)/rust src=$(srctree)/rust $@ +else $(Q)$(MAKE) $(build)=rust $@ +endif # Script to generate missing namespace dependencies # --------------------------------------------------------------------------- @@ -1991,12 +2049,12 @@ nsdeps: modules quiet_cmd_gen_compile_commands = GEN $@ cmd_gen_compile_commands = $(PYTHON3) $< -a $(AR) -o $@ $(filter-out $<, $(real-prereqs)) -$(extmod_prefix)compile_commands.json: $(srctree)/scripts/clang-tools/gen_compile_commands.py \ +compile_commands.json: $(srctree)/scripts/clang-tools/gen_compile_commands.py \ $(if $(KBUILD_EXTMOD),, vmlinux.a $(KBUILD_VMLINUX_LIBS)) \ - $(if $(CONFIG_MODULES), $(MODORDER)) FORCE + $(if $(CONFIG_MODULES), modules.order) FORCE $(call if_changed,gen_compile_commands) -targets += $(extmod_prefix)compile_commands.json +targets += compile_commands.json PHONY += clang-tidy clang-analyzer @@ -2004,7 +2062,7 @@ ifdef CONFIG_CC_IS_CLANG quiet_cmd_clang_tools = CHECK $< cmd_clang_tools = $(PYTHON3) $(srctree)/scripts/clang-tools/run-clang-tools.py $@ $< -clang-tidy clang-analyzer: $(extmod_prefix)compile_commands.json +clang-tidy clang-analyzer: compile_commands.json $(call cmd,clang_tools) else clang-tidy clang-analyzer: @@ -2015,7 +2073,7 @@ endif # Scripts to check various things for consistency # --------------------------------------------------------------------------- -PHONY += includecheck versioncheck coccicheck export_report +PHONY += includecheck versioncheck coccicheck includecheck: find $(srctree)/* $(RCS_FIND_IGNORE) \ @@ -2030,9 +2088,6 @@ versioncheck: coccicheck: $(Q)$(BASH) $(srctree)/scripts/$@ -export_report: - $(PERL) $(srctree)/scripts/export_report.pl - PHONY += checkstack kernelrelease kernelversion image_name # UML needs a little special treatment here. It wants to use the host diff --git a/arch/Kconfig b/arch/Kconfig index bd9f095d69fa03..6682b2a53e342c 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -135,6 +135,7 @@ config KPROBES_ON_FTRACE config UPROBES def_bool n depends on ARCH_SUPPORTS_UPROBES + select TASKS_TRACE_RCU help Uprobes is the user-space counterpart to kprobes: they enable instrumentation applications (such as 'perf probe') @@ -811,6 +812,45 @@ config LTO_CLANG_THIN If unsure, say Y. endchoice +config ARCH_SUPPORTS_AUTOFDO_CLANG + bool + +config AUTOFDO_CLANG + bool "Enable Clang's AutoFDO build (EXPERIMENTAL)" + depends on ARCH_SUPPORTS_AUTOFDO_CLANG + depends on CC_IS_CLANG && CLANG_VERSION >= 170000 + help + This option enables Clang’s AutoFDO build. When + an AutoFDO profile is specified in variable + CLANG_AUTOFDO_PROFILE during the build process, + Clang uses the profile to optimize the kernel. + + If no profile is specified, AutoFDO options are + still passed to Clang to facilitate the collection + of perf data for creating an AutoFDO profile in + subsequent builds. + + If unsure, say N. + +config ARCH_SUPPORTS_PROPELLER_CLANG + bool + +config PROPELLER_CLANG + bool "Enable Clang's Propeller build" + depends on ARCH_SUPPORTS_PROPELLER_CLANG + depends on CC_IS_CLANG && CLANG_VERSION >= 190000 + help + This option enables Clang’s Propeller build. When the Propeller + profiles is specified in variable CLANG_PROPELLER_PROFILE_PREFIX + during the build process, Clang uses the profiles to optimize + the kernel. + + If no profile is specified, Propeller options are still passed + to Clang to facilitate the collection of perf data for creating + the Propeller profiles in subsequent builds. + + If unsure, say N. + config ARCH_SUPPORTS_CFI_CLANG bool help @@ -1024,6 +1064,14 @@ config ARCH_WANTS_EXECMEM_LATE enough entropy for module space randomization, for instance arm64. +config ARCH_HAS_EXECMEM_ROX + bool + depends on MMU && !HIGHMEM + help + For architectures that support allocations of executable memory + with read-only execute permissions. Architecture must implement + execmem_fill_trapping_insns() callback to enable this. + config HAVE_IRQ_EXIT_ON_IRQ_STACK bool help @@ -1528,7 +1576,7 @@ config HAVE_SPARSE_SYSCALL_NR entries at 4000, 5000 and 6000 locations. This option turns on syscall related optimizations for a given architecture. -config ARCH_HAS_VDSO_DATA +config ARCH_HAS_VDSO_TIME_DATA bool config HAVE_STATIC_CALL @@ -1682,4 +1730,10 @@ config CC_HAS_SANE_FUNCTION_ALIGNMENT config ARCH_NEED_CMPXCHG_1_EMU bool +config ARCH_WANTS_PRE_LINK_VMLINUX + bool + help + An architecture can select this if it provides arch//tools/Makefile + with .arch.vmlinux.o target to be linked into vmlinux. + endmenu diff --git a/arch/alpha/configs/defconfig b/arch/alpha/configs/defconfig index 1816c1dc22b152..3280bd9e657840 100644 --- a/arch/alpha/configs/defconfig +++ b/arch/alpha/configs/defconfig @@ -51,7 +51,6 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_CMOS=y CONFIG_EXT2_FS=y -CONFIG_REISERFS_FS=m CONFIG_ISO9660_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild index 396caece6d6d99..483965c5a4de2d 100644 --- a/arch/alpha/include/asm/Kbuild +++ b/arch/alpha/include/asm/Kbuild @@ -5,3 +5,4 @@ generic-y += agp.h generic-y += asm-offsets.h generic-y += kvm_para.h generic-y += mcs_spinlock.h +generic-y += text-patching.h diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h index b191d87f89c401..65fe1e54c6da09 100644 --- a/arch/alpha/include/asm/io.h +++ b/arch/alpha/include/asm/io.h @@ -88,7 +88,6 @@ static inline void * phys_to_virt(unsigned long address) #define virt_to_phys virt_to_phys #define phys_to_virt phys_to_virt -#define page_to_phys(page) page_to_pa(page) /* Maximum PIO space address supported? */ #define IO_SPACE_LIMIT 0xffff diff --git a/arch/alpha/include/asm/page.h b/arch/alpha/include/asm/page.h index 70419e6be1a354..5ec4c77e432e0e 100644 --- a/arch/alpha/include/asm/page.h +++ b/arch/alpha/include/asm/page.h @@ -4,11 +4,7 @@ #include #include - -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #ifndef __ASSEMBLY__ @@ -18,7 +14,7 @@ extern void clear_page(void *page); #define clear_user_page(page, vaddr, pg) clear_page(page) #define vma_alloc_zeroed_movable_folio(vma, vaddr) \ - vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false) + vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr) extern void copy_page(void * _to, void * _from); #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) diff --git a/arch/alpha/include/asm/spinlock_types.h b/arch/alpha/include/asm/spinlock_types.h index 2526fd3be5fd71..05a444d77c5314 100644 --- a/arch/alpha/include/asm/spinlock_types.h +++ b/arch/alpha/include/asm/spinlock_types.h @@ -3,7 +3,7 @@ #define _ALPHA_SPINLOCK_TYPES_H #ifndef __LINUX_SPINLOCK_TYPES_RAW_H -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif typedef struct { diff --git a/arch/alpha/include/uapi/asm/mman.h b/arch/alpha/include/uapi/asm/mman.h index 763929e814e9a3..1e700468a68580 100644 --- a/arch/alpha/include/uapi/asm/mman.h +++ b/arch/alpha/include/uapi/asm/mman.h @@ -78,6 +78,9 @@ #define MADV_COLLAPSE 25 /* Synchronous hugepage collapse */ +#define MADV_GUARD_INSTALL 102 /* fatal signal on access to range */ +#define MADV_GUARD_REMOVE 103 /* unguard range */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index 251b73c5481eaa..302507bf9b5ddb 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -146,6 +146,8 @@ #define SCM_DEVMEM_DMABUF SO_DEVMEM_DMABUF #define SO_DEVMEM_DONTNEED 80 +#define SCM_TS_OPT_ID 81 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index c0424de9e7cda2..86185021f75ae3 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -152,7 +152,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, long __user *, basep) { int error; - struct fd arg = fdget_pos(fd); + CLASS(fd_pos, arg)(fd); struct osf_dirent_callback buf = { .ctx.actor = osf_filldir, .dirent = dirent, @@ -160,7 +160,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, .count = count }; - if (!fd_file(arg)) + if (fd_empty(arg)) return -EBADF; error = iterate_dir(fd_file(arg), &buf.ctx); @@ -169,7 +169,6 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, if (count != buf.count) error = count - buf.count; - fdput_pos(arg); return error; } diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c index 5808a66e2a81f7..3048758304b57a 100644 --- a/arch/alpha/kernel/pci-sysfs.c +++ b/arch/alpha/kernel/pci-sysfs.c @@ -64,7 +64,7 @@ static int __pci_mmap_fits(struct pci_dev *pdev, int num, * Return: %0 on success, negative error code otherwise */ static int pci_mmap_resource(struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma, int sparse) { struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); @@ -93,14 +93,14 @@ static int pci_mmap_resource(struct kobject *kobj, } static int pci_mmap_resource_sparse(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma) { return pci_mmap_resource(kobj, attr, vma, 1); } static int pci_mmap_resource_dense(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma) { return pci_mmap_resource(kobj, attr, vma, 0); diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl index 74720667fe0917..c59d53d6d3f349 100644 --- a/arch/alpha/kernel/syscalls/syscall.tbl +++ b/arch/alpha/kernel/syscalls/syscall.tbl @@ -502,3 +502,7 @@ 570 common lsm_set_self_attr sys_lsm_set_self_attr 571 common lsm_list_modules sys_lsm_list_modules 572 common mseal sys_mseal +573 common setxattrat sys_setxattrat +574 common getxattrat sys_getxattrat +575 common listxattrat sys_listxattrat +576 common removexattrat sys_removexattrat diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 5b248814204147..4f2eeda907ecb1 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -6,6 +6,7 @@ config ARC def_bool y select ARC_TIMERS + select ARCH_HAS_CPU_CACHE_ALIASING select ARCH_HAS_CACHE_LINE_SIZE select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DMA_PREP_COHERENT @@ -297,7 +298,6 @@ config ARC_PAGE_SIZE_16K config ARC_PAGE_SIZE_4K bool "4KB" select HAVE_PAGE_SIZE_4KB - depends on ARC_MMU_V3 || ARC_MMU_V4 endchoice @@ -474,7 +474,8 @@ config HIGHMEM config ARC_HAS_PAE40 bool "Support for the 40-bit Physical Address Extension" - depends on ISA_ARCV2 + depends on ARC_MMU_V4 + depends on !ARC_PAGE_SIZE_4K select HIGHMEM select PHYS_ADDR_T_64BIT help diff --git a/arch/arc/Makefile b/arch/arc/Makefile index 2390dd042e3636..fb98478ed1ab09 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -6,7 +6,7 @@ KBUILD_DEFCONFIG := haps_hs_smp_defconfig ifeq ($(CROSS_COMPILE),) -CROSS_COMPILE := $(call cc-cross-prefix, arc-linux- arceb-linux-) +CROSS_COMPILE := $(call cc-cross-prefix, arc-linux- arceb-linux- arc-linux-gnu-) endif cflags-y += -fno-common -pipe -fno-builtin -mmedium-calls -D__linux__ diff --git a/arch/arc/boot/dts/axc001.dtsi b/arch/arc/boot/dts/axc001.dtsi index 2a151607b08057..88bcc7ab6f5af0 100644 --- a/arch/arc/boot/dts/axc001.dtsi +++ b/arch/arc/boot/dts/axc001.dtsi @@ -54,7 +54,7 @@ ictl_intc: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <30>; + ngpios = <30>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arc/boot/dts/axc003.dtsi b/arch/arc/boot/dts/axc003.dtsi index c0a812674ce9ed..9a2dc39a5cff4d 100644 --- a/arch/arc/boot/dts/axc003.dtsi +++ b/arch/arc/boot/dts/axc003.dtsi @@ -62,7 +62,7 @@ ictl_intc: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <30>; + ngpios = <30>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arc/boot/dts/axc003_idu.dtsi b/arch/arc/boot/dts/axc003_idu.dtsi index 67556f4b70574e..f31382cb8be4bb 100644 --- a/arch/arc/boot/dts/axc003_idu.dtsi +++ b/arch/arc/boot/dts/axc003_idu.dtsi @@ -69,7 +69,7 @@ ictl_intc: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <30>; + ngpios = <30>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arc/boot/dts/axs10x_mb.dtsi b/arch/arc/boot/dts/axs10x_mb.dtsi index b6443538530495..3add2fe257f8b8 100644 --- a/arch/arc/boot/dts/axs10x_mb.dtsi +++ b/arch/arc/boot/dts/axs10x_mb.dtsi @@ -250,7 +250,7 @@ gpio0_banka: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <32>; + ngpios = <32>; reg = <0>; }; @@ -258,7 +258,7 @@ gpio0_bankb: gpio-controller@1 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <8>; + ngpios = <8>; reg = <1>; }; @@ -266,7 +266,7 @@ gpio0_bankc: gpio-controller@2 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <8>; + ngpios = <8>; reg = <2>; }; }; @@ -281,7 +281,7 @@ gpio1_banka: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <30>; + ngpios = <30>; reg = <0>; }; @@ -289,7 +289,7 @@ gpio1_bankb: gpio-controller@1 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <10>; + ngpios = <10>; reg = <1>; }; @@ -297,7 +297,7 @@ gpio1_bankc: gpio-controller@2 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <8>; + ngpios = <8>; reg = <2>; }; }; diff --git a/arch/arc/boot/dts/hsdk.dts b/arch/arc/boot/dts/hsdk.dts index 41b980df862b14..98bb850722a4b1 100644 --- a/arch/arc/boot/dts/hsdk.dts +++ b/arch/arc/boot/dts/hsdk.dts @@ -308,7 +308,7 @@ gpio_port_a: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - snps,nr-gpios = <24>; + ngpios = <24>; reg = <0>; }; }; diff --git a/arch/arc/include/asm/Kbuild b/arch/arc/include/asm/Kbuild index 49285a3ce2398c..4c69522e0328ee 100644 --- a/arch/arc/include/asm/Kbuild +++ b/arch/arc/include/asm/Kbuild @@ -6,3 +6,4 @@ generic-y += kvm_para.h generic-y += mcs_spinlock.h generic-y += parport.h generic-y += user.h +generic-y += text-patching.h diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 4b13f60fe7cae8..005d9e4d187a04 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -146,7 +146,7 @@ #ifndef __ASSEMBLY__ -#include +#include /* Helpers */ #define TO_KB(bytes) ((bytes) >> 10) diff --git a/arch/arc/include/asm/cachetype.h b/arch/arc/include/asm/cachetype.h new file mode 100644 index 00000000000000..acd3b6cb4bf5b0 --- /dev/null +++ b/arch/arc/include/asm/cachetype.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_ARC_CACHETYPE_H +#define __ASM_ARC_CACHETYPE_H + +#define cpu_dcache_is_aliasing() false +#define cpu_icache_is_aliasing() true + +#endif diff --git a/arch/arc/include/asm/cmpxchg.h b/arch/arc/include/asm/cmpxchg.h index 58045c89834045..76f43db0890fcd 100644 --- a/arch/arc/include/asm/cmpxchg.h +++ b/arch/arc/include/asm/cmpxchg.h @@ -48,7 +48,7 @@ \ switch(sizeof((_p_))) { \ case 1: \ - _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \ + _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \ break; \ case 4: \ _prev_ = __cmpxchg(_p_, _o_, _n_); \ diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h index f57cb5a6b62403..00171a212b3cb2 100644 --- a/arch/arc/include/asm/io.h +++ b/arch/arc/include/asm/io.h @@ -42,9 +42,6 @@ static inline void ioport_unmap(void __iomem *addr) #define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force u16)cpu_to_be16(v), p); }) #define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force u32)cpu_to_be32(v), p); }) -/* Change struct page to physical address */ -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - #define __raw_readb __raw_readb static inline u8 __raw_readb(const volatile void __iomem *addr) { diff --git a/arch/arc/include/asm/mmu-arcv2.h b/arch/arc/include/asm/mmu-arcv2.h index d85dc07219071f..41412642f27963 100644 --- a/arch/arc/include/asm/mmu-arcv2.h +++ b/arch/arc/include/asm/mmu-arcv2.h @@ -9,7 +9,7 @@ #ifndef _ASM_ARC_MMU_ARCV2_H #define _ASM_ARC_MMU_ARCV2_H -#include +#include /* * TLB Management regs diff --git a/arch/arc/include/uapi/asm/page.h b/arch/arc/include/uapi/asm/page.h index 7fd9e741b5274d..4606a326af5c47 100644 --- a/arch/arc/include/uapi/asm/page.h +++ b/arch/arc/include/uapi/asm/page.h @@ -14,7 +14,7 @@ /* PAGE_SHIFT determines the page size */ #ifdef __KERNEL__ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT +#include #else /* * Default 8k @@ -24,11 +24,10 @@ * not available */ #define PAGE_SHIFT 13 +#define PAGE_SIZE _BITUL(PAGE_SHIFT) /* Default 8K */ +#define PAGE_MASK (~(PAGE_SIZE-1)) #endif -#define PAGE_SIZE _BITUL(PAGE_SHIFT) /* Default 8K */ #define PAGE_OFFSET _AC(0x80000000, UL) /* Kernel starts at 2G onwrds */ -#define PAGE_MASK (~(PAGE_SIZE-1)) - #endif /* _UAPI__ASM_ARC_PAGE_H */ diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c index 4c9e61457b2f69..cc6ac7d128aa1a 100644 --- a/arch/arc/kernel/devtree.c +++ b/arch/arc/kernel/devtree.c @@ -62,7 +62,7 @@ const struct machine_desc * __init setup_machine_fdt(void *dt) const struct machine_desc *mdesc; unsigned long dt_root; - if (!early_init_dt_scan(dt)) + if (!early_init_dt_scan(dt, __pa(dt))) return NULL; mdesc = of_flat_dt_match_machine(NULL, arch_get_next_mach); diff --git a/arch/arc/net/bpf_jit_arcv2.c b/arch/arc/net/bpf_jit_arcv2.c index 4458e409ca0a84..6d989b6d88c69b 100644 --- a/arch/arc/net/bpf_jit_arcv2.c +++ b/arch/arc/net/bpf_jit_arcv2.c @@ -2916,7 +2916,7 @@ bool check_jmp_32(u32 curr_off, u32 targ_off, u8 cond) addendum = (cond == ARC_CC_AL) ? 0 : INSN_len_normal; disp = get_displacement(curr_off + addendum, targ_off); - if (ARC_CC_AL) + if (cond == ARC_CC_AL) return is_valid_far_disp(disp); else return is_valid_near_disp(disp); diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 7f47b4f335c3d2..366f162e147d11 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -242,6 +242,10 @@ choice depends on ARCH_BCM_5301X || ARCH_BCM_NSP select DEBUG_UART_8250 + config DEBUG_BCMBCA + bool "Kernel low-level debugging on BCMBCA UART0" + depends on ARCH_BCMBCA + config DEBUG_BCM_HR2 bool "Kernel low-level debugging on Hurricane 2 UART2" depends on ARCH_BCM_HR2 @@ -1526,7 +1530,7 @@ config DEBUG_LL_INCLUDE default "debug/vf.S" if DEBUG_VF_UART default "debug/vt8500.S" if DEBUG_VT8500_UART0 default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1 - default "debug/bcm63xx.S" if DEBUG_BCM63XX_UART + default "debug/bcm63xx.S" if DEBUG_BCM63XX_UART || DEBUG_BCMBCA default "debug/digicolor.S" if DEBUG_DIGICOLOR_UA0 default "debug/brcmstb.S" if DEBUG_BRCMSTB_UART default "mach/debug-macro.S" @@ -1640,6 +1644,7 @@ config DEBUG_UART_PHYS default 0xfe531000 if DEBUG_STIH41X_SBC_ASC1 default 0xfed32000 if DEBUG_STIH41X_ASC2 default 0xff690000 if DEBUG_RK32_UART2 + default 0xff800640 if DEBUG_BCMBCA default 0xffc02000 if DEBUG_SOCFPGA_UART0 default 0xffc02100 if DEBUG_SOCFPGA_ARRIA10_UART1 default 0xffc03000 if DEBUG_SOCFPGA_CYCLONE5_UART1 @@ -1664,7 +1669,7 @@ config DEBUG_UART_PHYS DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ DEBUG_RMOBILE_SCIFA4 || \ DEBUG_S3C64XX_UART || \ - DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ + DEBUG_BCM63XX_UART || DEBUG_BCMBCA || DEBUG_ASM9260_UART || \ DEBUG_DIGICOLOR_UA0 || \ DEBUG_AT91_UART || DEBUG_STM32_UART || \ DEBUG_STIH41X_ASC2 || DEBUG_STIH41X_SBC_ASC1 || \ @@ -1734,6 +1739,7 @@ config DEBUG_UART_VIRT default 0xfe018000 if DEBUG_MMP_UART3 default 0xfe100000 if DEBUG_IMX23_UART || DEBUG_IMX28_UART default 0xfe300000 if DEBUG_BCM_KONA_UART + default 0xfe300640 if DEBUG_BCMBCA default 0xfeb00000 if DEBUG_HI3620_UART || DEBUG_HIX5HD2_UART default 0xfeb24000 if DEBUG_RK3X_UART0 default 0xfeb26000 if DEBUG_RK3X_UART1 @@ -1765,7 +1771,7 @@ config DEBUG_UART_VIRT DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_QCOM_UARTDM || \ DEBUG_S3C64XX_UART || \ - DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ + DEBUG_BCM63XX_UART || DEBUG_BCMBCA || DEBUG_ASM9260_UART || \ DEBUG_DIGICOLOR_UA0 || \ DEBUG_AT91_UART || DEBUG_STM32_UART || \ DEBUG_STIH41X_ASC2 || DEBUG_STIH41X_SBC_ASC1 || \ diff --git a/arch/arm/Makefile b/arch/arm/Makefile index aafebf145738ab..00ca7886b18efe 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -264,13 +264,13 @@ stack_protector_prepare: prepare0 -mstack-protector-guard=tls \ -mstack-protector-guard-offset=$(shell \ awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}'\ - include/generated/asm-offsets.h)) + $(objtree)/include/generated/asm-offsets.h)) else stack_protector_prepare: prepare0 $(eval SSP_PLUGIN_CFLAGS := \ -fplugin-arg-arm_ssp_per_task_plugin-offset=$(shell \ awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}'\ - include/generated/asm-offsets.h)) + $(objtree)/include/generated/asm-offsets.h)) $(eval KBUILD_CFLAGS += $(SSP_PLUGIN_CFLAGS)) $(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS)) endif diff --git a/arch/arm/boot/dts/allwinner/Makefile b/arch/arm/boot/dts/allwinner/Makefile index cd0d044882cf83..48666f73e638a0 100644 --- a/arch/arm/boot/dts/allwinner/Makefile +++ b/arch/arm/boot/dts/allwinner/Makefile @@ -215,6 +215,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \ sun8i-a33-olinuxino.dtb \ sun8i-a33-q8-tablet.dtb \ sun8i-a33-sinlinx-sina33.dtb \ + sun8i-a33-vstar.dtb \ sun8i-a83t-allwinner-h8homlet-v2.dtb \ sun8i-a83t-bananapi-m3.dtb \ sun8i-a83t-cubietruck-plus.dtb \ @@ -268,7 +269,3 @@ dtb-$(CONFIG_MACH_SUNIV) += \ suniv-f1c100s-licheepi-nano.dtb \ suniv-f1c200s-lctech-pi.dtb \ suniv-f1c200s-popstick-v1.1.dtb -dtb-$(CONFIG_MACH_SUNIV) += \ - suniv-f1c100s-licheepi-nano.dtb \ - suniv-f1c200s-lctech-pi.dtb \ - suniv-f1c200s-popstick-v1.1.dtb diff --git a/arch/arm/boot/dts/allwinner/sun8i-a33-vstar-core1.dtsi b/arch/arm/boot/dts/allwinner/sun8i-a33-vstar-core1.dtsi new file mode 100644 index 00000000000000..ba794b842ec4eb --- /dev/null +++ b/arch/arm/boot/dts/allwinner/sun8i-a33-vstar-core1.dtsi @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2024 Icenowy Zheng + */ + +#include "sun8i-a33.dtsi" + +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_8bit_pins>; + vmmc-supply = <®_dcdc1>; + bus-width = <8>; + non-removable; + cap-mmc-hw-reset; + status = "okay"; +}; + +&mmc2_8bit_pins { + /* Increase drive strength for DDR modes */ + drive-strength = <40>; +}; + +&r_rsb { + status = "okay"; + + axp22x: pmic@3a3 { + compatible = "x-powers,axp223"; + reg = <0x3a3>; + interrupt-parent = <&r_intc>; + interrupts = ; + eldoin-supply = <®_dcdc1>; + x-powers,drive-vbus-en; + }; +}; + +#include "axp223.dtsi" + +®_aldo1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-io"; +}; + +®_aldo2 { + regulator-always-on; + regulator-min-microvolt = <2350000>; + regulator-max-microvolt = <2650000>; + regulator-name = "vdd-dll"; +}; + +®_aldo3 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-avcc"; +}; + +®_dc5ldo { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-cpus"; +}; + +®_dcdc1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-3v3"; +}; + +®_dcdc2 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-sys"; +}; + +®_dcdc3 { + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-cpu"; +}; + +®_dcdc5 { + regulator-always-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-name = "vcc-dram"; +}; + +®_rtc_ldo { + regulator-name = "vcc-rtc"; +}; diff --git a/arch/arm/boot/dts/allwinner/sun8i-a33-vstar.dts b/arch/arm/boot/dts/allwinner/sun8i-a33-vstar.dts new file mode 100644 index 00000000000000..9f5c29b3df46d6 --- /dev/null +++ b/arch/arm/boot/dts/allwinner/sun8i-a33-vstar.dts @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2024 Icenowy Zheng + */ + +/dts-v1/; +#include "sun8i-a33-vstar-core1.dtsi" + +#include +#include + +/ { + model = "Rervision A33-Vstar"; + compatible = "rervision,a33-vstar", + "rervision,a33-core1", + "allwinner,sun8i-a33"; + + aliases { + serial0 = &uart0; + ethernet0 = &r8152; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reg_usb1_vbus: regulator-usb1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb1-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + enable-active-high; + gpio = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2 */ + }; + + wifi_pwrseq: pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&r_pio 0 6 GPIO_ACTIVE_LOW>; /* PL6 */ + clocks = <&rtc CLK_OSC32K_FANOUT>; + clock-names = "ext_clock"; + }; +}; + +&ac_power_supply { + status = "okay"; +}; + +&codec { + status = "okay"; +}; + +&dai { + status = "okay"; +}; + +&ehci0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + hub@1 { + /* Onboard GL850G hub which needs no extra power sequence */ + compatible = "usb5e3,608"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + r8152: ethernet@4 { + /* + * Onboard Realtek RTL8152 USB Ethernet, + * with no MAC address programmed + */ + compatible = "usbbda,8152"; + reg = <4>; + }; + }; +}; + +&lradc { + vref-supply = <®_aldo3>; + status = "okay"; + + button-191 { + label = "V+"; + linux,code = ; + channel = <0>; + voltage = <191011>; + }; + + button-391 { + label = "V-"; + linux,code = ; + channel = <0>; + voltage = <391304>; + }; + + button-600 { + label = "BACK"; + linux,code = ; + channel = <0>; + voltage = <600000>; + }; +}; + +&mmc0 { + vmmc-supply = <®_dcdc1>; + bus-width = <4>; + cd-gpios = <&pio 1 4 GPIO_ACTIVE_LOW>; /* PB4 */ + status = "okay"; +}; + +&mmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pg_pins>; + vmmc-supply = <®_dldo1>; + mmc-pwrseq = <&wifi_pwrseq>; + bus-width = <4>; + non-removable; + status = "okay"; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + interrupt-parent = <&r_pio>; + interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */ + interrupt-names = "host-wake"; + }; +}; + +/* + * Our WiFi chip needs both DLDO1 and DLDO2 to be powered at the same + * time, with the two being in sync. Since this is not really + * supported right now, just use the two as always on, and we will fix + * it later. + */ +®_dldo1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-wifi0"; +}; + +®_dldo2 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-wifi1"; +}; + +®_drivevbus { + regulator-name = "usb0-vbus"; + status = "okay"; +}; + +&sound { + /* TODO: on-board microphone */ + + simple-audio-card,widgets = "Headphone", "Headphone Jack"; + simple-audio-card,routing = + "Left DAC", "DACL", + "Right DAC", "DACR", + "Headphone Jack", "HP"; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pb_pins>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pg_pins>, <&uart1_cts_rts_pg_pins>; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + clocks = <&rtc CLK_OSC32K_FANOUT>; + clock-names = "lpo"; + vbat-supply = <®_dldo1>; + device-wakeup-gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; /* PL10 */ + host-wakeup-gpios = <&r_pio 0 9 GPIO_ACTIVE_HIGH>; /* PL9 */ + shutdown-gpios = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */ + }; +}; + +&usb_otg { + dr_mode = "otg"; + status = "okay"; +}; + +&usb_power_supply { + status = "okay"; +}; + +&usbphy { + usb0_id_det-gpios = <&pio 7 8 GPIO_ACTIVE_HIGH>; /* PH8 */ + usb0_vbus_power-supply = <&usb_power_supply>; + usb0_vbus-supply = <®_drivevbus>; + usb1_vbus-supply = <®_usb1_vbus>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/allwinner/sun9i-a80-cubieboard4.dts b/arch/arm/boot/dts/allwinner/sun9i-a80-cubieboard4.dts index c8ca8cb7f5c94e..52ad95a2063aaf 100644 --- a/arch/arm/boot/dts/allwinner/sun9i-a80-cubieboard4.dts +++ b/arch/arm/boot/dts/allwinner/sun9i-a80-cubieboard4.dts @@ -280,8 +280,8 @@ reg_dcdc4: dcdc4 { reg_dcdc5: dcdc5 { regulator-always-on; - regulator-min-microvolt = <1425000>; - regulator-max-microvolt = <1575000>; + regulator-min-microvolt = <1450000>; + regulator-max-microvolt = <1550000>; regulator-name = "vcc-dram"; }; diff --git a/arch/arm/boot/dts/amlogic/Makefile b/arch/arm/boot/dts/amlogic/Makefile index a84310780ea345..504c533b117329 100644 --- a/arch/arm/boot/dts/amlogic/Makefile +++ b/arch/arm/boot/dts/amlogic/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -dtb-$(CONFIG_MACH_MESON6) += \ - meson6-atv1200.dtb dtb-$(CONFIG_MACH_MESON8) += \ meson8-minix-neo-x8.dtb \ meson8b-ec100.dtb \ diff --git a/arch/arm/boot/dts/amlogic/meson6-atv1200.dts b/arch/arm/boot/dts/amlogic/meson6-atv1200.dts deleted file mode 100644 index 98e1c94c02611e..00000000000000 --- a/arch/arm/boot/dts/amlogic/meson6-atv1200.dts +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* - * Copyright 2014 Carlo Caione - */ - -/dts-v1/; -#include "meson6.dtsi" - -/ { - model = "Geniatech ATV1200"; - compatible = "geniatech,atv1200", "amlogic,meson6"; - - aliases { - serial0 = &uart_AO; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - - memory { - device_type = "memory"; - reg = <0x40000000 0x80000000>; - }; -}; - -&uart_AO { - status = "okay"; -}; - -ðmac { - status = "okay"; -}; diff --git a/arch/arm/boot/dts/amlogic/meson6.dtsi b/arch/arm/boot/dts/amlogic/meson6.dtsi deleted file mode 100644 index 4716030a48d0dd..00000000000000 --- a/arch/arm/boot/dts/amlogic/meson6.dtsi +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR MIT -/* - * Copyright 2014 Carlo Caione - */ - -#include "meson.dtsi" - -/ { - model = "Amlogic Meson6 SoC"; - compatible = "amlogic,meson6"; - - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@200 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - next-level-cache = <&L2>; - reg = <0x200>; - }; - - cpu@201 { - device_type = "cpu"; - compatible = "arm,cortex-a9"; - next-level-cache = <&L2>; - reg = <0x201>; - }; - }; - - apb2: bus@d0000000 { - compatible = "simple-bus"; - reg = <0xd0000000 0x40000>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0xd0000000 0x40000>; - }; - - clk81: clk@0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <200000000>; - }; -}; /* end of / */ - -&efuse { - status = "disabled"; -}; - -&timer_abcde { - clocks = <&xtal>, <&clk81>; - clock-names = "xtal", "pclk"; -}; - -&uart_AO { - clocks = <&xtal>, <&clk81>, <&clk81>; - clock-names = "xtal", "pclk", "baud"; -}; - -&uart_A { - clocks = <&xtal>, <&clk81>, <&clk81>; - clock-names = "xtal", "pclk", "baud"; -}; - -&uart_B { - clocks = <&xtal>, <&clk81>, <&clk81>; - clock-names = "xtal", "pclk", "baud"; -}; - -&uart_C { - clocks = <&xtal>, <&clk81>, <&clk81>; - clock-names = "xtal", "pclk", "baud"; -}; diff --git a/arch/arm/boot/dts/amlogic/meson8-minix-neo-x8.dts b/arch/arm/boot/dts/amlogic/meson8-minix-neo-x8.dts index c6d1c5a8a3bfeb..62987eadc7473f 100644 --- a/arch/arm/boot/dts/amlogic/meson8-minix-neo-x8.dts +++ b/arch/arm/boot/dts/amlogic/meson8-minix-neo-x8.dts @@ -19,7 +19,7 @@ chosen { stdout-path = "serial0:115200n8"; }; - memory { + memory@40000000 { device_type = "memory"; reg = <0x40000000 0x80000000>; }; @@ -93,5 +93,6 @@ &ir_receiver { ðmac { status = "okay"; pinctrl-0 = <ð_pins>; - pnictrl-names = "default"; + pinctrl-names = "default"; + phy-mode = "rmii"; }; diff --git a/arch/arm/boot/dts/amlogic/meson8.dtsi b/arch/arm/boot/dts/amlogic/meson8.dtsi index f57be9ae150f40..9ff142d9fe3f45 100644 --- a/arch/arm/boot/dts/amlogic/meson8.dtsi +++ b/arch/arm/boot/dts/amlogic/meson8.dtsi @@ -196,7 +196,7 @@ power-firmware@4f00000 { }; thermal-zones { - soc { + soc-thermal { polling-delay-passive = <250>; /* milliseconds */ polling-delay = <1000>; /* milliseconds */ thermal-sensors = <&thermal_sensor>; @@ -346,17 +346,16 @@ pmu: pmu@e0 { reg = <0xe0 0x18>; }; - pinctrl_aobus: pinctrl@84 { + pinctrl_aobus: pinctrl@14 { compatible = "amlogic,meson8-aobus-pinctrl"; - reg = <0x84 0xc>; #address-cells = <1>; #size-cells = <1>; - ranges; + ranges = <0x0 0x14 0x1c>; - gpio_ao: ao-bank@14 { - reg = <0x14 0x4>, - <0x2c 0x4>, - <0x24 0x8>; + gpio_ao: bank@0 { + reg = <0x0 0x4>, + <0x18 0x4>, + <0x10 0x8>; reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; @@ -461,18 +460,17 @@ clock-measure@8758 { reg = <0x8758 0x1c>; }; - pinctrl_cbus: pinctrl@9880 { + pinctrl_cbus: pinctrl@8030 { compatible = "amlogic,meson8-cbus-pinctrl"; - reg = <0x9880 0x10>; #address-cells = <1>; #size-cells = <1>; - ranges; + ranges = <0x0 0x8030 0x108>; - gpio: banks@80b0 { - reg = <0x80b0 0x28>, - <0x80e8 0x18>, - <0x8120 0x18>, - <0x8030 0x30>; + gpio: bank@80 { + reg = <0x80 0x28>, + <0xb8 0x18>, + <0xf0 0x18>, + <0x00 0x30>; reg-names = "mux", "pull", "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; @@ -589,7 +587,7 @@ mux { }; &ahb_sram { - ao_arc_sram: ao-arc-sram@0 { + ao_arc_sram: aoarc-sram@0 { compatible = "amlogic,meson8-ao-arc-sram"; reg = <0x0 0x8000>; pool; diff --git a/arch/arm/boot/dts/amlogic/meson8b-ec100.dts b/arch/arm/boot/dts/amlogic/meson8b-ec100.dts index 49890eb12781f4..18ea6592b7d74d 100644 --- a/arch/arm/boot/dts/amlogic/meson8b-ec100.dts +++ b/arch/arm/boot/dts/amlogic/meson8b-ec100.dts @@ -22,7 +22,7 @@ chosen { stdout-path = "serial0:115200n8"; }; - memory { + memory@40000000 { device_type = "memory"; reg = <0x40000000 0x40000000>; }; @@ -98,6 +98,10 @@ sound { compatible = "amlogic,gx-sound-card"; model = "M8B-EC100"; + clocks = <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>, + <&clkc CLKID_MPLL2>; + assigned-clocks = <&clkc CLKID_MPLL0>, <&clkc CLKID_MPLL1>, <&clkc CLKID_MPLL2>; @@ -427,7 +431,7 @@ &gpio { "NAND_CS1 (EMMC)", "NAND_CS2 iNAND_RS1 (EMMC)", "NAND_nR/B iNAND_CMD (EMMC)", "NAND_ALE (EMMC)", "NAND_CLE (EMMC)", "nRE_S1 NAND_nRE (EMMC)", - "nWE_S1 NAND_nWE (EMMC)", "", "", "SPI_CS", + "nWE_S1 NAND_nWE (EMMC)", "", "", "", "SPI_CS", /* Bank DIF */ "RMII_RXD1", "RMII_RXD0", "RMII_CRS_DV", "RMII_50M_IN", "GPIODIF_4", "GPIODIF_5", diff --git a/arch/arm/boot/dts/amlogic/meson8b-mxq.dts b/arch/arm/boot/dts/amlogic/meson8b-mxq.dts index 7adedd3258c33f..fb28cb330f175a 100644 --- a/arch/arm/boot/dts/amlogic/meson8b-mxq.dts +++ b/arch/arm/boot/dts/amlogic/meson8b-mxq.dts @@ -22,7 +22,7 @@ chosen { stdout-path = "serial0:115200n8"; }; - memory { + memory@40000000 { device_type = "memory"; reg = <0x40000000 0x40000000>; }; diff --git a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts index 941682844faf45..2aa012f38a3bf5 100644 --- a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts +++ b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts @@ -22,7 +22,7 @@ chosen { stdout-path = "serial0:115200n8"; }; - memory { + memory@40000000 { device_type = "memory"; reg = <0x40000000 0x40000000>; }; @@ -378,6 +378,6 @@ hub@1 { compatible = "usb5e3,610"; reg = <1>; vdd-supply = <&p5v0>; - reset-gpio = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi index 2d9d24d3a95d69..9e02a97f86a0ef 100644 --- a/arch/arm/boot/dts/amlogic/meson8b.dtsi +++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi @@ -173,7 +173,7 @@ hwrom@0 { }; thermal-zones { - soc { + soc-thermal { polling-delay-passive = <250>; /* milliseconds */ polling-delay = <1000>; /* milliseconds */ thermal-sensors = <&thermal_sensor>; @@ -308,17 +308,16 @@ pmu: pmu@e0 { reg = <0xe0 0x18>; }; - pinctrl_aobus: pinctrl@84 { + pinctrl_aobus: pinctrl@14 { compatible = "amlogic,meson8b-aobus-pinctrl"; - reg = <0x84 0xc>; #address-cells = <1>; #size-cells = <1>; - ranges; + ranges = <0x0 0x14 0x1c>; - gpio_ao: ao-bank@14 { - reg = <0x14 0x4>, - <0x2c 0x4>, - <0x24 0x8>; + gpio_ao: bank@0 { + reg = <0x0 0x4>, + <0x18 0x4>, + <0x10 0x8>; reg-names = "mux", "pull", "gpio"; gpio-controller; #gpio-cells = <2>; @@ -415,18 +414,17 @@ clock-measure@8758 { reg = <0x8758 0x1c>; }; - pinctrl_cbus: pinctrl@9880 { + pinctrl_cbus: pinctrl@8030 { compatible = "amlogic,meson8b-cbus-pinctrl"; - reg = <0x9880 0x10>; #address-cells = <1>; #size-cells = <1>; - ranges; + ranges = <0x0 0x8030 0x108>; - gpio: banks@80b0 { - reg = <0x80b0 0x28>, - <0x80e8 0x18>, - <0x8120 0x18>, - <0x8030 0x38>; + gpio: bank@80 { + reg = <0x80 0x28>, + <0xb8 0x18>, + <0xf0 0x18>, + <0x00 0x38>; reg-names = "mux", "pull", "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; @@ -535,7 +533,7 @@ mux { }; &ahb_sram { - ao_arc_sram: ao-arc-sram@0 { + ao_arc_sram: aoarc-sram@0 { compatible = "amlogic,meson8b-ao-arc-sram"; reg = <0x0 0x8000>; pool; diff --git a/arch/arm/boot/dts/amlogic/meson8m2-mxiii-plus.dts b/arch/arm/boot/dts/amlogic/meson8m2-mxiii-plus.dts index aa4d4bf7062961..08aa661e17adf5 100644 --- a/arch/arm/boot/dts/amlogic/meson8m2-mxiii-plus.dts +++ b/arch/arm/boot/dts/amlogic/meson8m2-mxiii-plus.dts @@ -26,7 +26,7 @@ chosen { stdout-path = "serial0:115200n8"; }; - memory { + memory@40000000 { device_type = "memory"; reg = <0x40000000 0x80000000>; }; diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_vining_fpga.dts index 84f39dec3c4250..170c1ae441a6ef 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_vining_fpga.dts +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_vining_fpga.dts @@ -135,7 +135,7 @@ temp: temperature-sensor@48 { reg = <0x48>; }; - at24@50 { + eeprom@50 { compatible = "atmel,24c01"; pagesize = <8>; reg = <0x50>; @@ -211,7 +211,7 @@ &i2c1 { status = "okay"; clock-frequency = <100000>; - at24@50 { + eeprom@50 { compatible = "atmel,24c02"; pagesize = <8>; reg = <0x50>; diff --git a/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts b/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts index 43202890c95959..83fe00abd65238 100644 --- a/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +++ b/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts @@ -251,6 +251,7 @@ mcu: system-controller@2a { led-controller@2b { compatible = "cznic,turris-omnia-leds"; reg = <0x2b>; + interrupts-extended = <&mcu 11 IRQ_TYPE_NONE>; #address-cells = <1>; #size-cells = <0>; status = "okay"; diff --git a/arch/arm/boot/dts/marvell/kirkwood-openblocks_a7.dts b/arch/arm/boot/dts/marvell/kirkwood-openblocks_a7.dts index 9c438f10f7371b..2bc4b68bd7230f 100644 --- a/arch/arm/boot/dts/marvell/kirkwood-openblocks_a7.dts +++ b/arch/arm/boot/dts/marvell/kirkwood-openblocks_a7.dts @@ -44,7 +44,7 @@ sata@80000 { i2c@11100 { status = "okay"; - s24c02: s24c02@50 { + s24c02: eeprom@50 { compatible = "atmel,24c02"; reg = <0x50>; }; diff --git a/arch/arm/boot/dts/microchip/Makefile b/arch/arm/boot/dts/microchip/Makefile index 0c45c8d17468b7..470fe46433a9b5 100644 --- a/arch/arm/boot/dts/microchip/Makefile +++ b/arch/arm/boot/dts/microchip/Makefile @@ -2,6 +2,7 @@ # Enables support for device-tree overlays DTC_FLAGS_at91-sam9x60_curiosity := -@ DTC_FLAGS_at91-sam9x60ek := -@ +DTC_FLAGS_at91-sam9x75_curiosity := -@ DTC_FLAGS_at91-sama5d27_som1_ek := -@ DTC_FLAGS_at91-sama5d27_wlsom1_ek := -@ DTC_FLAGS_at91-sama5d29_curiosity := -@ @@ -60,6 +61,8 @@ dtb-$(CONFIG_SOC_AT91SAM9) += \ dtb-$(CONFIG_SOC_SAM9X60) += \ at91-sam9x60_curiosity.dtb \ at91-sam9x60ek.dtb +dtb-$(CONFIG_SOC_SAM9X7) += \ + at91-sam9x75_curiosity.dtb dtb-$(CONFIG_SOC_SAM_V7) += \ at91-kizbox2-2.dtb \ at91-kizbox3-hs.dtb \ diff --git a/arch/arm/boot/dts/microchip/aks-cdu.dts b/arch/arm/boot/dts/microchip/aks-cdu.dts index 742fcf525e1b74..b65f80e1ef0552 100644 --- a/arch/arm/boot/dts/microchip/aks-cdu.dts +++ b/arch/arm/boot/dts/microchip/aks-cdu.dts @@ -98,23 +98,27 @@ rootfs@500000 { leds { compatible = "gpio-leds"; - red { + led-red { + label = "red"; gpios = <&pioC 10 GPIO_ACTIVE_HIGH>; linux,default-trigger = "none"; }; - green { + led-green { + label = "green"; gpios = <&pioA 5 GPIO_ACTIVE_LOW>; linux,default-trigger = "none"; default-state = "on"; }; - yellow { + led-yellow { + label = "yellow"; gpios = <&pioB 20 GPIO_ACTIVE_LOW>; linux,default-trigger = "none"; }; - blue { + led-blue { + label = "blue"; gpios = <&pioB 21 GPIO_ACTIVE_LOW>; linux,default-trigger = "none"; }; diff --git a/arch/arm/boot/dts/microchip/animeo_ip.dts b/arch/arm/boot/dts/microchip/animeo_ip.dts index 29936bfbeeb7ea..7f527622d3f243 100644 --- a/arch/arm/boot/dts/microchip/animeo_ip.dts +++ b/arch/arm/boot/dts/microchip/animeo_ip.dts @@ -146,23 +146,23 @@ usb0: ohci@500000 { leds { compatible = "gpio-leds"; - power_green { + led-power-green { label = "power_green"; gpios = <&pioC 17 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; - power_red { + led-power-red { label = "power_red"; gpios = <&pioA 2 GPIO_ACTIVE_HIGH>; }; - tx_green { + led-tx-green { label = "tx_green"; gpios = <&pioC 19 GPIO_ACTIVE_HIGH>; }; - tx_red { + led-tx-red { label = "tx_red"; gpios = <&pioC 18 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/boot/dts/microchip/at91-kizbox2-common.dtsi b/arch/arm/boot/dts/microchip/at91-kizbox2-common.dtsi index e5e21dff882fba..a44d92305dbb0a 100644 --- a/arch/arm/boot/dts/microchip/at91-kizbox2-common.dtsi +++ b/arch/arm/boot/dts/microchip/at91-kizbox2-common.dtsi @@ -85,7 +85,7 @@ led-3 { &i2c1 { status = "okay"; - pmic: act8865@5b { + act8865: pmic@5b { compatible = "active-semi,act8865"; reg = <0x5b>; status = "okay"; diff --git a/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts b/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts index 3b38707d736eed..cdc56b53299d1b 100644 --- a/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts +++ b/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts @@ -53,17 +53,17 @@ leds { pinctrl-0 = <&pinctrl_gpio_leds>; status = "okay"; /* Conflict with pwm0. */ - red { + led-red { label = "red"; gpios = <&pioB 11 GPIO_ACTIVE_HIGH>; }; - green { + led-green { label = "green"; gpios = <&pioB 12 GPIO_ACTIVE_HIGH>; }; - blue { + led-blue { label = "blue"; gpios = <&pioB 13 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; @@ -260,6 +260,37 @@ i2c6: i2c@600 { i2c-digital-filter-width-ns = <35>; status = "okay"; + power-monitor@17 { + compatible = "microchip,pac1934"; + reg = <0x17>; + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <0x1>; + shunt-resistor-micro-ohms = <10000>; + label = "VDDIOM"; + }; + + channel@2 { + reg = <0x2>; + shunt-resistor-micro-ohms = <10000>; + label = "VDDCORE"; + }; + + channel@3 { + reg = <0x3>; + shunt-resistor-micro-ohms = <10000>; + label = "VDD3V3_MPU"; + }; + + channel@4 { + reg = <0x4>; + shunt-resistor-micro-ohms = <10000>; + label = "VDD3V3"; + }; + }; + gpio_exp: mcp23008@20 { compatible = "microchip,mcp23008"; reg = <0x20>; diff --git a/arch/arm/boot/dts/microchip/at91-sam9x75_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sam9x75_curiosity.dts new file mode 100644 index 00000000000000..87b6ea97590b12 --- /dev/null +++ b/arch/arm/boot/dts/microchip/at91-sam9x75_curiosity.dts @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * at91-sam9x75_curiosity.dts - Device Tree file for Microchip SAM9X75 Curiosity board + * + * Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries + * + * Author: Varshini Rajendran + */ +/dts-v1/; +#include "sam9x7.dtsi" +#include + +/ { + model = "Microchip SAM9X75 Curiosity"; + compatible = "microchip,sam9x75-curiosity", "microchip,sam9x7", "atmel,at91sam9"; + + aliases { + i2c0 = &i2c6; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio_default>; + + button-user { + label = "USER"; + gpios = <&pioC 9 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + }; + + led-controller { + compatible = "gpio-leds"; + + led_red: led-red { + label = "red"; + gpios = <&pioC 14 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pinctrl_red_led_gpio_default>; + }; + + led_green: led-green { + label = "green"; + gpios = <&pioC 21 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pinctrl_green_led_gpio_default>; + }; + + led_blue: led-blue { + label = "blue"; + gpios = <&pioC 20 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pinctrl_blue_led_gpio_default>; + linux,default-trigger = "heartbeat"; + }; + }; + + memory@20000000 { + reg = <0x20000000 0x10000000>; + device_type = "memory"; + }; +}; + +&classd { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_classd_default>; + atmel,pwm-type = "diff"; + atmel,non-overlap-time = <10>; + status = "okay"; +}; + +&dbgu { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dbgu_default>; + status = "okay"; +}; + +&dma0 { + status = "okay"; +}; + +&flx6 { + atmel,flexcom-mode = ; + status = "okay"; +}; + +&i2c6 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx6_default>; + i2c-analog-filter; + i2c-digital-filter; + i2c-digital-filter-width-ns = <35>; + status = "okay"; + + pmic@5b { + compatible = "microchip,mcp16502"; + reg = <0x5b>; + + regulators { + vdd_3v3: VDD_IO { + regulator-name = "VDD_IO"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = <2>; + regulator-allowed-modes = <2>, <4>; + regulator-always-on; + + regulator-state-standby { + regulator-on-in-suspend; + regulator-mode = <4>; + }; + + regulator-state-mem { + regulator-mode = <4>; + }; + }; + + vddioddr: VDD_DDR { + regulator-name = "VDD_DDR"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-initial-mode = <2>; + regulator-allowed-modes = <2>, <4>; + regulator-always-on; + + regulator-state-standby { + regulator-on-in-suspend; + regulator-mode = <4>; + }; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-mode = <4>; + }; + }; + + vddcore: VDD_CORE { + regulator-name = "VDD_CORE"; + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1150000>; + regulator-initial-mode = <2>; + regulator-allowed-modes = <2>, <4>; + regulator-always-on; + + regulator-state-standby { + regulator-on-in-suspend; + regulator-mode = <4>; + }; + + regulator-state-mem { + regulator-mode = <4>; + }; + }; + + dcdc4: VDD_OTHER { + regulator-name = "VDD_OTHER"; + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1150000>; + regulator-initial-mode = <2>; + regulator-allowed-modes = <2>, <4>; + regulator-ramp-delay = <3125>; + regulator-always-on; + + regulator-state-standby { + regulator-on-in-suspend; + regulator-mode = <4>; + }; + + regulator-state-mem { + regulator-mode = <4>; + }; + }; + + vldo1: LDO1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + + regulator-state-standby { + regulator-on-in-suspend; + }; + }; + + vldo2: LDO2 { + regulator-name = "LDO2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-standby { + regulator-on-in-suspend; + }; + }; + }; + }; +}; + +&i2s { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2s_default>; + #sound-dai-cells = <0>; + status = "okay"; +}; + +&main_xtal { + clock-frequency = <24000000>; +}; + +&pinctrl { + classd { + pinctrl_classd_default: classd-default { + atmel,pins = + , + ; + }; + }; + + dbgu { + pinctrl_dbgu_default: dbgu-default { + atmel,pins = , + ; + }; + }; + + flexcom { + pinctrl_flx6_default: flx6-default { + atmel,pins = + , + ; + }; + }; + + gpio-keys { + pinctrl_key_gpio_default: key-gpio-default { + atmel,pins = ; + }; + }; + + i2s { + pinctrl_i2s_default: i2s-default { + atmel,pins = + , /* I2SCK */ + , /* I2SWS */ + , /* I2SDIN */ + , /* I2SDOUT */ + ; /* I2SMCK */ + }; + }; + + led-controller { + pinctrl_red_led_gpio_default: red-led-gpio-default { + atmel,pins = ; + }; + pinctrl_green_led_gpio_default: green-led-gpio-default { + atmel,pins = ; + }; + pinctrl_blue_led_gpio_default: blue-led-gpio-default { + atmel,pins = ; + }; + }; + + sdmmc0 { + pinctrl_sdmmc0_default: sdmmc0-default { + atmel,pins = + , /* PA2 CK periph A with pullup */ + , /* PA1 CMD periph A with pullup */ + , /* PA0 DAT0 periph A */ + , /* PA3 DAT1 periph A with pullup */ + , /* PA4 DAT2 periph A with pullup */ + ; /* PA5 DAT3 periph A with pullup */ + }; + }; +}; /* pinctrl */ + +&poweroff { + debounce-delay-us = <976>; + status = "okay"; + + input@0 { + reg = <0>; + }; +}; + +&rtt { + atmel,rtt-rtc-time-reg = <&gpbr 0x0>; +}; + +&sdmmc0 { + bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc0_default>; + cd-gpios = <&pioA 23 GPIO_ACTIVE_LOW>; + disable-wp; + status = "okay"; +}; + +&slow_xtal { + clock-frequency = <32768>; +}; + +&tcb { + timer0: timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>; + }; + + timer1: timer@1 { + compatible = "atmel,tcb-timer"; + reg = <1>; + }; +}; + +&trng { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_som1.dtsi b/arch/arm/boot/dts/microchip/at91-sama5d27_som1.dtsi index 95ecb7d040a88d..8ac85dac5a969d 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d27_som1.dtsi +++ b/arch/arm/boot/dts/microchip/at91-sama5d27_som1.dtsi @@ -106,7 +106,7 @@ i2c0: i2c@f8028000 { scl-gpios = <&pioA PIN_PD22 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; - at24@50 { + eeprom@50 { compatible = "atmel,24c02"; reg = <0x50>; pagesize = <8>; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi index c173f49cb91074..ef11606a82b31c 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi +++ b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1.dtsi @@ -75,7 +75,7 @@ &i2c1 { scl-gpios = <&pioA PIN_PD20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; - mcp16502@5b { + pmic@5b { compatible = "microchip,mcp16502"; reg = <0x5b>; lvin-supply = <®_5v>; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d29_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sama5d29_curiosity.dts index 951a0c97d3c6bb..b6684bf67d3e6e 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d29_curiosity.dts +++ b/arch/arm/boot/dts/microchip/at91-sama5d29_curiosity.dts @@ -149,7 +149,7 @@ &i2c0 { i2c-sda-hold-time-ns = <350>; status = "okay"; - mcp16502@5b { + pmic@5b { compatible = "microchip,mcp16502"; reg = <0x5b>; lvin-supply = <®_5v>; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d2_icp.dts b/arch/arm/boot/dts/microchip/at91-sama5d2_icp.dts index 5e2bb517a4809e..9fa6f1395aa6e2 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d2_icp.dts +++ b/arch/arm/boot/dts/microchip/at91-sama5d2_icp.dts @@ -195,7 +195,38 @@ i2c6: i2c@600 { i2c-digital-filter-width-ns = <35>; status = "okay"; - mcp16502@5b { + power-monitor@10 { + compatible = "microchip,pac1934"; + reg = <0x10>; + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <0x1>; + shunt-resistor-micro-ohms = <10000>; + label = "VDD3V3_1"; + }; + + channel@2 { + reg = <0x2>; + shunt-resistor-micro-ohms = <10000>; + label = "VDD3V3_2"; + }; + + channel@3 { + reg = <0x3>; + shunt-resistor-micro-ohms = <10000>; + label = "VDDCORE"; + }; + + channel@4 { + reg = <0x4>; + shunt-resistor-micro-ohms = <10000>; + label = "VDDIODDR"; + }; + }; + + pmic@5b { compatible = "microchip,mcp16502"; reg = <0x5b>; lvin-supply = <®_5v>; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d2_ptc_ek.dts b/arch/arm/boot/dts/microchip/at91-sama5d2_ptc_ek.dts index 200b20515ab121..e4ae60ef5f8a04 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d2_ptc_ek.dts +++ b/arch/arm/boot/dts/microchip/at91-sama5d2_ptc_ek.dts @@ -231,7 +231,7 @@ i2c1: i2c@fc028000 { scl-gpios = <&pioA PIN_PC7 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; - at24@50 { + eeprom@50 { compatible = "atmel,24c02"; reg = <0x50>; pagesize = <8>; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/microchip/at91-sama5d2_xplained.dts index 6680031387e8c3..4bab3f25b855a1 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/microchip/at91-sama5d2_xplained.dts @@ -411,7 +411,7 @@ i2c1: i2c@fc028000 { scl-gpios = <&pioA PIN_PD5 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; status = "okay"; - at24@54 { + eeprom@54 { compatible = "atmel,24c02"; reg = <0x54>; pagesize = <16>; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/microchip/at91-sama5d3_xplained.dts index 82003372708822..5662992cf213e3 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d3_xplained.dts +++ b/arch/arm/boot/dts/microchip/at91-sama5d3_xplained.dts @@ -87,7 +87,7 @@ i2c0: i2c@f0014000 { i2c1: i2c@f0018000 { status = "okay"; - pmic: act8865@5b { + act8865: pmic@5b { compatible = "active-semi,act8865"; reg = <0x5b>; status = "disabled"; diff --git a/arch/arm/boot/dts/microchip/at91-sama7g54_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sama7g54_curiosity.dts index 645e49fdb7fe79..2dec2218f32ce7 100644 --- a/arch/arm/boot/dts/microchip/at91-sama7g54_curiosity.dts +++ b/arch/arm/boot/dts/microchip/at91-sama7g54_curiosity.dts @@ -186,6 +186,37 @@ i2c10: i2c@600 { i2c-digital-filter-width-ns = <35>; status = "okay"; + power-monitor@1f { + compatible = "microchip,pac1934"; + reg = <0x1f>; + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <0x1>; + shunt-resistor-micro-ohms = <47000>; + label = "VDD3V3"; + }; + + channel@2 { + reg = <0x2>; + shunt-resistor-micro-ohms = <47000>; + label = "VDDIODDR"; + }; + + channel@3 { + reg = <0x3>; + shunt-resistor-micro-ohms = <47000>; + label = "VDDCORE"; + }; + + channel@4 { + reg = <0x4>; + shunt-resistor-micro-ohms = <47000>; + label = "VDDCPU"; + }; + }; + eeprom@51 { compatible = "atmel,24c02"; reg = <0x51>; diff --git a/arch/arm/boot/dts/microchip/at91-sama7g5ek.dts b/arch/arm/boot/dts/microchip/at91-sama7g5ek.dts index ed75d491a24603..0f5e6ad438dd99 100644 --- a/arch/arm/boot/dts/microchip/at91-sama7g5ek.dts +++ b/arch/arm/boot/dts/microchip/at91-sama7g5ek.dts @@ -244,7 +244,38 @@ i2c1: i2c@600 { i2c-digital-filter-width-ns = <35>; status = "okay"; - mcp16502@5b { + power-monitor@10 { + compatible = "microchip,pac1934"; + reg = <0x10>; + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <0x1>; + shunt-resistor-micro-ohms = <10000>; + label = "VDD3V3"; + }; + + channel@2 { + reg = <0x2>; + shunt-resistor-micro-ohms = <10000>; + label = "VDDIODDR"; + }; + + channel@3 { + reg = <0x3>; + shunt-resistor-micro-ohms = <10000>; + label = "VDDCORE"; + }; + + channel@4 { + reg = <0x4>; + shunt-resistor-micro-ohms = <10000>; + label = "VDDCPU"; + }; + }; + + pmic@5b { compatible = "microchip,mcp16502"; reg = <0x5b>; lvin-supply = <®_5v>; diff --git a/arch/arm/boot/dts/microchip/at91rm9200ek.dts b/arch/arm/boot/dts/microchip/at91rm9200ek.dts index 4624a6f076f815..0bf472b157a5df 100644 --- a/arch/arm/boot/dts/microchip/at91rm9200ek.dts +++ b/arch/arm/boot/dts/microchip/at91rm9200ek.dts @@ -127,19 +127,19 @@ root@350000 { leds { compatible = "gpio-leds"; - ds2 { + led-ds2 { label = "green"; gpios = <&pioB 0 GPIO_ACTIVE_LOW>; linux,default-trigger = "mmc0"; }; - ds4 { + led-ds4 { label = "yellow"; gpios = <&pioB 1 GPIO_ACTIVE_LOW>; linux,default-trigger = "heartbeat"; }; - ds6 { + led-ds6 { label = "red"; gpios = <&pioB 2 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/microchip/at91sam9260ek.dts b/arch/arm/boot/dts/microchip/at91sam9260ek.dts index 720c15472c4a5f..e8e65e60564d9d 100644 --- a/arch/arm/boot/dts/microchip/at91sam9260ek.dts +++ b/arch/arm/boot/dts/microchip/at91sam9260ek.dts @@ -165,7 +165,7 @@ button-4 { i2c-gpio-0 { status = "okay"; - 24c512@50 { + eeprom@50 { compatible = "atmel,24c512"; reg = <0x50>; }; @@ -174,13 +174,13 @@ i2c-gpio-0 { leds { compatible = "gpio-leds"; - ds1 { + led-ds1 { label = "ds1"; gpios = <&pioA 9 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; - ds5 { + led-ds5 { label = "ds5"; gpios = <&pioA 6 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/microchip/at91sam9261ek.dts b/arch/arm/boot/dts/microchip/at91sam9261ek.dts index 045cb253f23a6d..a8f523131cd67a 100644 --- a/arch/arm/boot/dts/microchip/at91sam9261ek.dts +++ b/arch/arm/boot/dts/microchip/at91sam9261ek.dts @@ -192,19 +192,19 @@ watchdog@fffffd40 { leds { compatible = "gpio-leds"; - ds8 { + led-ds8 { label = "ds8"; gpios = <&pioA 13 GPIO_ACTIVE_LOW>; linux,default-trigger = "none"; }; - ds7 { + led-ds7 { label = "ds7"; gpios = <&pioA 14 GPIO_ACTIVE_LOW>; linux,default-trigger = "nand-disk"; }; - ds1 { + led-ds1 { label = "ds1"; gpios = <&pioA 23 GPIO_ACTIVE_LOW>; linux,default-trigger = "heartbeat"; diff --git a/arch/arm/boot/dts/microchip/at91sam9263ek.dts b/arch/arm/boot/dts/microchip/at91sam9263ek.dts index ce8baff6a9f4e0..f25692543d71f1 100644 --- a/arch/arm/boot/dts/microchip/at91sam9263ek.dts +++ b/arch/arm/boot/dts/microchip/at91sam9263ek.dts @@ -219,13 +219,13 @@ &pioA 21 GPIO_ACTIVE_HIGH leds { compatible = "gpio-leds"; - d3 { + led-d3 { label = "d3"; gpios = <&pioB 7 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; - d2 { + led-d2 { label = "d2"; gpios = <&pioC 29 GPIO_ACTIVE_LOW>; linux,default-trigger = "nand-disk"; @@ -253,7 +253,7 @@ button-right-click { i2c-gpio-0 { status = "okay"; - 24c512@50 { + eeprom@50 { compatible = "atmel,24c512"; reg = <0x50>; pagesize = <128>; diff --git a/arch/arm/boot/dts/microchip/at91sam9g20ek.dts b/arch/arm/boot/dts/microchip/at91sam9g20ek.dts index 6de7a7cd3c0783..1e62fd371ddb80 100644 --- a/arch/arm/boot/dts/microchip/at91sam9g20ek.dts +++ b/arch/arm/boot/dts/microchip/at91sam9g20ek.dts @@ -14,13 +14,13 @@ / { leds { compatible = "gpio-leds"; - ds1 { + led-ds1 { label = "ds1"; gpios = <&pioA 9 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; - ds5 { + led-ds5 { label = "ds5"; gpios = <&pioA 6 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/microchip/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/microchip/at91sam9g20ek_common.dtsi index 565b99e79c5209..4e7cfbbd42419e 100644 --- a/arch/arm/boot/dts/microchip/at91sam9g20ek_common.dtsi +++ b/arch/arm/boot/dts/microchip/at91sam9g20ek_common.dtsi @@ -220,7 +220,7 @@ usb0: ohci@500000 { i2c-gpio-0 { status = "okay"; - 24c512@50 { + eeprom@50 { compatible = "atmel,24c512"; reg = <0x50>; vcc-supply = <®_3v3>; diff --git a/arch/arm/boot/dts/microchip/at91sam9g45.dtsi b/arch/arm/boot/dts/microchip/at91sam9g45.dtsi index c54eb21d5cba82..157d306ef5c983 100644 --- a/arch/arm/boot/dts/microchip/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/microchip/at91sam9g45.dtsi @@ -753,7 +753,7 @@ macb0: ethernet@fffbc000 { status = "disabled"; }; - trng@fffcc000 { + trng: rng@fffcc000 { compatible = "atmel,at91sam9g45-trng"; reg = <0xfffcc000 0x100>; interrupts = <6 IRQ_TYPE_LEVEL_HIGH 0>; diff --git a/arch/arm/boot/dts/microchip/sam9x60.dtsi b/arch/arm/boot/dts/microchip/sam9x60.dtsi index 04a6d716ecaf8a..36944e18a329ab 100644 --- a/arch/arm/boot/dts/microchip/sam9x60.dtsi +++ b/arch/arm/boot/dts/microchip/sam9x60.dtsi @@ -186,6 +186,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 13>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -388,6 +389,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 32>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -439,6 +441,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 33>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -486,7 +489,7 @@ sha: crypto@f002c000 { clock-names = "sha_clk"; }; - trng: trng@f0030000 { + trng: rng@f0030000 { compatible = "microchip,sam9x60-trng"; reg = <0xf0030000 0x100>; interrupts = <38 IRQ_TYPE_LEVEL_HIGH 0>; @@ -598,6 +601,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 9>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -649,6 +653,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 10>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -700,6 +705,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -751,6 +757,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 5>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -821,6 +828,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -891,6 +899,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 7>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -961,6 +970,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 8>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -1086,6 +1096,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 15>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; @@ -1137,6 +1148,7 @@ AT91_XDMAC_DT_PER_IF(1) | dma-names = "tx", "rx"; clocks = <&pmc PMC_TYPE_PERIPHERAL 16>; clock-names = "usart"; + atmel,usart-mode = ; atmel,use-dma-rx; atmel,use-dma-tx; atmel,fifo-size = <16>; diff --git a/arch/arm/boot/dts/microchip/sam9x7.dtsi b/arch/arm/boot/dts/microchip/sam9x7.dtsi new file mode 100644 index 00000000000000..beb1f34b38d3ba --- /dev/null +++ b/arch/arm/boot/dts/microchip/sam9x7.dtsi @@ -0,0 +1,1220 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * sam9x7.dtsi - Device Tree Include file for Microchip SAM9X7 SoC family + * + * Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries + * + * Author: Varshini Rajendran + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + model = "Microchip SAM9X7 SoC"; + compatible = "microchip,sam9x7"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&aic>; + + aliases { + serial0 = &dbgu; + gpio0 = &pioA; + gpio1 = &pioB; + gpio2 = &pioC; + gpio3 = &pioD; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,arm926ej-s"; + reg = <0>; + device_type = "cpu"; + }; + }; + + clocks { + slow_xtal: clock-slowxtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + main_xtal: clock-mainxtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + }; + + sram: sram@300000 { + compatible = "mmio-sram"; + reg = <0x300000 0x10000>; + ranges = <0 0x300000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + }; + + ahb { + compatible = "simple-bus"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + + sdmmc0: mmc@80000000 { + compatible = "microchip,sam9x7-sdhci", "microchip,sam9x60-sdhci"; + reg = <0x80000000 0x300>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 12>, <&pmc PMC_TYPE_GCK 12>; + clock-names = "hclock", "multclk"; + assigned-clocks = <&pmc PMC_TYPE_GCK 12>; + assigned-clock-rates = <100000000>; + status = "disabled"; + }; + + sdmmc1: mmc@90000000 { + compatible = "microchip,sam9x7-sdhci", "microchip,sam9x60-sdhci"; + reg = <0x90000000 0x300>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 26>, <&pmc PMC_TYPE_GCK 26>; + clock-names = "hclock", "multclk"; + assigned-clocks = <&pmc PMC_TYPE_GCK 26>; + assigned-clock-rates = <100000000>; + status = "disabled"; + }; + }; + + apb { + compatible = "simple-bus"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + + flx4: flexcom@f0000000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf0000000 0x200>; + ranges = <0x0 0xf0000000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 13>; + status = "disabled"; + + uart4: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 13>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(8))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(9))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + spi4: spi@400 { + compatible = "microchip,sam9x7-spi", "atmel,at91rm9200-spi"; + reg = <0x400 0x200>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 13>; + clock-names = "spi_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(8))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(9))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + + i2c4: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 13>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(8))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(9))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx5: flexcom@f0004000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf0004000 0x200>; + ranges = <0x0 0xf0004000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 14>; + status = "disabled"; + + uart5: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 14>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(10))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(11))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + spi5: spi@400 { + compatible = "microchip,sam9x7-spi", "atmel,at91rm9200-spi"; + reg = <0x400 0x200>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 14>; + clock-names = "spi_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(10))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(11))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + + i2c5: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 14>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(10))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(11))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + dma0: dma-controller@f0008000 { + compatible = "microchip,sam9x7-dma", "atmel,sama5d4-dma"; + reg = <0xf0008000 0x1000>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0>; + #dma-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 20>; + clock-names = "dma_clk"; + status = "disabled"; + }; + + ssc: ssc@f0010000 { + compatible = "microchip,sam9x7-ssc", "atmel,at91sam9g45-ssc"; + reg = <0xf0010000 0x4000>; + interrupts = <28 IRQ_TYPE_LEVEL_HIGH 5>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 28>; + clock-names = "pclk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(38))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(39))>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + i2s: i2s@f001c000 { + compatible = "microchip,sam9x7-i2smcc", "microchip,sam9x60-i2smcc"; + reg = <0xf001c000 0x100>; + interrupts = <34 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 34>, <&pmc PMC_TYPE_GCK 34>; + clock-names = "pclk", "gclk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(36))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(37))>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + flx11: flexcom@f0020000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf0020000 0x200>; + ranges = <0x0 0xf0020000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 32>; + status = "disabled"; + + uart11: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <32 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 32>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(22))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(23))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + i2c11: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <32 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 32>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(22))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(23))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx12: flexcom@f0024000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf0024000 0x200>; + ranges = <0x0 0xf0024000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 33>; + status = "disabled"; + + uart12: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <33 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 33>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(24))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(25))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + i2c12: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <33 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 33>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(24))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(25))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + pit64b0: timer@f0028000 { + compatible = "microchip,sam9x7-pit64b", "microchip,sam9x60-pit64b"; + reg = <0xf0028000 0x100>; + interrupts = <37 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 37>, <&pmc PMC_TYPE_GCK 37>; + clock-names = "pclk", "gclk"; + }; + + sha: crypto@f002c000 { + compatible = "microchip,sam9x7-sha", "atmel,at91sam9g46-sha"; + reg = <0xf002c000 0x100>; + interrupts = <41 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 41>; + clock-names = "sha_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(34))>; + dma-names = "tx"; + }; + + trng: rng@f0030000 { + compatible = "microchip,sam9x7-trng", "microchip,sam9x60-trng"; + reg = <0xf0030000 0x100>; + interrupts = <38 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 38>; + status = "disabled"; + }; + + aes: crypto@f0034000 { + compatible = "microchip,sam9x7-aes", "atmel,at91sam9g46-aes"; + reg = <0xf0034000 0x100>; + interrupts = <39 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 39>; + clock-names = "aes_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(32))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(33))>; + dma-names = "tx", "rx"; + }; + + tdes: crypto@f0038000 { + compatible = "microchip,sam9x7-tdes", "atmel,at91sam9g46-tdes"; + reg = <0xf0038000 0x100>; + interrupts = <40 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 40>; + clock-names = "tdes_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(31))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(30))>; + dma-names = "tx", "rx"; + }; + + classd: sound@f003c000 { + compatible = "microchip,sam9x7-classd", "atmel,sama5d2-classd"; + reg = <0xf003c000 0x100>; + interrupts = <42 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 42>, <&pmc PMC_TYPE_GCK 42>; + clock-names = "pclk", "gclk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(35))>; + dma-names = "tx"; + status = "disabled"; + }; + + pit64b1: timer@f0040000 { + compatible = "microchip,sam9x7-pit64b", "microchip,sam9x60-pit64b"; + reg = <0xf0040000 0x100>; + interrupts = <58 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 58>, <&pmc PMC_TYPE_GCK 58>; + clock-names = "pclk", "gclk"; + }; + + can0: can@f8000000 { + compatible = "bosch,m_can"; + reg = <0xf8000000 0x100>, <0x300000 0x7800>; + reg-names = "m_can", "message_ram"; + interrupts = <29 IRQ_TYPE_LEVEL_HIGH 0>, + <68 IRQ_TYPE_LEVEL_HIGH 0>; + interrupt-names = "int0", "int1"; + clocks = <&pmc PMC_TYPE_PERIPHERAL 29>, <&pmc PMC_TYPE_GCK 29>; + clock-names = "hclk", "cclk"; + assigned-clocks = <&pmc PMC_TYPE_CORE PMC_UTMI>, <&pmc PMC_TYPE_GCK 29>; + assigned-clock-rates = <480000000>, <40000000>; + assigned-clock-parents = <&pmc PMC_TYPE_CORE PMC_UTMI>, <&pmc PMC_TYPE_CORE PMC_UTMI>; + bosch,mram-cfg = <0x3400 0 0 64 0 0 32 32>; + status = "disabled"; + }; + + can1: can@f8004000 { + compatible = "bosch,m_can"; + reg = <0xf8004000 0x100>, <0x300000 0xbc00>; + reg-names = "m_can", "message_ram"; + interrupts = <30 IRQ_TYPE_LEVEL_HIGH 0>, + <69 IRQ_TYPE_LEVEL_HIGH 0>; + interrupt-names = "int0", "int1"; + clocks = <&pmc PMC_TYPE_PERIPHERAL 30>, <&pmc PMC_TYPE_GCK 30>; + clock-names = "hclk", "cclk"; + assigned-clocks = <&pmc PMC_TYPE_CORE PMC_UTMI>, <&pmc PMC_TYPE_GCK 30>; + assigned-clock-rates = <480000000>, <40000000>; + assigned-clock-parents = <&pmc PMC_TYPE_CORE PMC_UTMI>, <&pmc PMC_TYPE_CORE PMC_UTMI>; + bosch,mram-cfg = <0x7800 0 0 64 0 0 32 32>; + status = "disabled"; + }; + + tcb: timer@f8008000 { + compatible = "microchip,sam9x7-tcb","atmel,sama5d2-tcb", "simple-mfd", "syscon"; + reg = <0xf8008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 17>, <&pmc PMC_TYPE_GCK 17>, <&clk32k 0>; + clock-names = "t0_clk", "gclk", "slow_clk"; + }; + + flx6: flexcom@f8010000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf8010000 0x200>; + ranges = <0x0 0xf8010000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 9>; + status = "disabled"; + + uart6: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 9>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(12))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(13))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + i2c6: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 9>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(12))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(13))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx7: flexcom@f8014000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf8014000 0x200>; + ranges = <0x0 0xf8014000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 10>; + status = "disabled"; + + uart7: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 10>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(14))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(15))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + i2c7: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 10>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(14))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(15))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx8: flexcom@f8018000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf8018000 0x200>; + ranges = <0x0 0xf8018000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; + status = "disabled"; + + uart8: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(16))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(17))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + i2c8: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 11>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(16))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(17))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx0: flexcom@f801c000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf801c000 0x200>; + ranges = <0x0 0xf801c000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 5>; + status = "disabled"; + + uart0: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 5>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(0))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(1))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + spi0: spi@400 { + compatible = "microchip,sam9x7-spi", "atmel,at91rm9200-spi"; + reg = <0x400 0x200>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 5>; + clock-names = "spi_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(0))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(1))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + + i2c0: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 5>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(0))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(1))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx1: flexcom@f8020000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf8020000 0x200>; + ranges = <0x0 0xf8020000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; + status = "disabled"; + + uart1: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(2))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(3))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + spi1: spi@400 { + compatible = "microchip,sam9x7-spi", "atmel,at91rm9200-spi"; + reg = <0x400 0x200>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; + clock-names = "spi_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(2))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(3))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + + i2c1: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 6>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(2))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(3))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx2: flexcom@f8024000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf8024000 0x200>; + ranges = <0x0 0xf8024000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 7>; + status = "disabled"; + + uart2: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 7>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(4))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(5))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + spi2: spi@400 { + compatible = "microchip,sam9x7-spi", "atmel,at91rm9200-spi"; + reg = <0x400 0x200>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 7>; + clock-names = "spi_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(4))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(5))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + + i2c2: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(4))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(5))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx3: flexcom@f8028000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf8028000 0x200>; + ranges = <0x0 0xf8028000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 8>; + status = "disabled"; + + uart3: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 8>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(6))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(7))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + spi3: spi@400 { + compatible = "microchip,sam9x7-spi", "atmel,at91rm9200-spi"; + reg = <0x400 0x200>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 8>; + clock-names = "spi_clk"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(6))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(7))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + + i2c3: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 8>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(6))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(7))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + gmac: ethernet@f802c000 { + compatible = "microchip,sam9x7-gem", "microchip,sama7g5-gem"; + reg = <0xf802c000 0x1000>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 0 */ + <60 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 1 */ + <61 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 2 */ + <62 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 3 */ + <63 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 4 */ + <64 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 5 */ + clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>, <&pmc PMC_TYPE_GCK 67>; + clock-names = "hclk", "pclk", "tx_clk", "tsu_clk"; + assigned-clocks = <&pmc PMC_TYPE_GCK 67>; + assigned-clock-rates = <266666666>; + status = "disabled"; + }; + + pwm0: pwm@f8034000 { + compatible = "microchip,sam9x7-pwm", "microchip,sam9x60-pwm"; + reg = <0xf8034000 0x300>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH 4>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 18>; + #pwm-cells = <3>; + status = "disabled"; + }; + + flx9: flexcom@f8040000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf8040000 0x200>; + ranges = <0x0 0xf8040000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 15>; + status = "disabled"; + + uart9: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <15 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 15>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(18))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(19))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + i2c9: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <15 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 15>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(18))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(19))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + flx10: flexcom@f8044000 { + compatible = "microchip,sam9x7-flexcom", "atmel,sama5d2-flexcom"; + reg = <0xf8044000 0x200>; + ranges = <0x0 0xf8044000 0x800>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 16>; + status = "disabled"; + + uart10: serial@200 { + compatible = "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <16 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 16>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(20))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(21))>; + dma-names = "tx", "rx"; + atmel,use-dma-rx; + atmel,use-dma-tx; + atmel,fifo-size = <16>; + atmel,usart-mode = ; + status = "disabled"; + }; + + i2c10: i2c@600 { + compatible = "microchip,sam9x7-i2c", "microchip,sam9x60-i2c"; + reg = <0x600 0x200>; + interrupts = <16 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 16>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(20))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | + AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(21))>; + dma-names = "tx", "rx"; + atmel,fifo-size = <16>; + status = "disabled"; + }; + }; + + matrix: matrix@ffffde00 { + compatible = "microchip,sam9x7-matrix", "atmel,at91sam9x5-matrix", "syscon"; + reg = <0xffffde00 0x200>; + }; + + pmecc: ecc-engine@ffffe000 { + compatible = "microchip,sam9x7-pmecc", "atmel,at91sam9g45-pmecc"; + reg = <0xffffe000 0x300>, <0xffffe600 0x100>; + }; + + mpddrc: mpddrc@ffffe800 { + compatible = "microchip,sam9x7-ddramc", "atmel,sama5d3-ddramc"; + reg = <0xffffe800 0x200>; + clocks = <&pmc PMC_TYPE_SYSTEM 2>, <&pmc PMC_TYPE_CORE PMC_MCK>; + clock-names = "ddrck", "mpddr"; + }; + + smc: smc@ffffea00 { + compatible = "microchip,sam9x7-smc", "atmel,at91sam9260-smc", "syscon"; + reg = <0xffffea00 0x100>; + }; + + aic: interrupt-controller@fffff100 { + compatible = "microchip,sam9x7-aic"; + reg = <0xfffff100 0x100>; + #interrupt-cells = <3>; + interrupt-controller; + atmel,external-irqs = <31>; + }; + + dbgu: serial@fffff200 { + compatible = "microchip,sam9x7-dbgu", "atmel,at91sam9260-dbgu", "microchip,sam9x7-usart", "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <47 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 47>; + clock-names = "usart"; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(28))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(29))>; + dma-names = "tx", "rx"; + atmel,usart-mode = ; + status = "disabled"; + }; + + pinctrl: pinctrl@fffff400 { + compatible = "microchip,sam9x7-pinctrl", "microchip,sam9x60-pinctrl", "simple-mfd"; + ranges = <0xfffff400 0xfffff400 0x800>; + #address-cells = <1>; + #size-cells = <1>; + + /* mux-mask corresponding to sam9x7 SoC in TFBGA228L package */ + atmel,mux-mask = < + /* A B C D */ + 0xffffffff 0xffffefc0 0xc0ffd000 0x00000000 /* pioA */ + 0x07ffffff 0x0805fe7f 0x01ff9f81 0x06078000 /* pioB */ + 0xffffffff 0x07dfffff 0xfa3fffff 0x00000000 /* pioC */ + 0x00003fff 0x00003fe0 0x0000003f 0x00000000 /* pioD */ + >; + + pioA: gpio@fffff400 { + compatible = "microchip,sam9x7-gpio", "microchip,sam9x60-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x200>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH 1>; + #interrupt-cells = <2>; + interrupt-controller; + #gpio-cells = <2>; + gpio-controller; + clocks = <&pmc PMC_TYPE_PERIPHERAL 2>; + }; + + pioB: gpio@fffff600 { + compatible = "microchip,sam9x7-gpio", "microchip,sam9x60-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff600 0x200>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH 1>; + #interrupt-cells = <2>; + interrupt-controller; + #gpio-cells = <2>; + gpio-controller; + #gpio-lines = <26>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 3>; + }; + + pioC: gpio@fffff800 { + compatible = "microchip,sam9x7-gpio", "microchip,sam9x60-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff800 0x200>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 1>; + #interrupt-cells = <2>; + interrupt-controller; + #gpio-cells = <2>; + gpio-controller; + clocks = <&pmc PMC_TYPE_PERIPHERAL 4>; + }; + + pioD: gpio@fffffa00 { + compatible = "microchip,sam9x7-gpio", "microchip,sam9x60-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffffa00 0x200>; + interrupts = <44 IRQ_TYPE_LEVEL_HIGH 1>; + #interrupt-cells = <2>; + interrupt-controller; + #gpio-cells = <2>; + gpio-controller; + #gpio-lines = <22>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 44>; + }; + }; + + pmc: clock-controller@fffffc00 { + compatible = "microchip,sam9x7-pmc", "syscon"; + reg = <0xfffffc00 0x200>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + #clock-cells = <2>; + clocks = <&clk32k 1>, <&clk32k 0>, <&main_xtal>; + clock-names = "td_slck", "md_slck", "main_xtal"; + }; + + reset_controller: reset-controller@fffffe00 { + compatible = "microchip,sam9x7-rstc", "microchip,sam9x60-rstc"; + reg = <0xfffffe00 0x10>; + clocks = <&clk32k 0>; + }; + + poweroff: poweroff@fffffe10 { + compatible = "microchip,sam9x7-shdwc", "microchip,sam9x60-shdwc"; + reg = <0xfffffe10 0x10>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk32k 0>; + atmel,wakeup-rtc-timer; + atmel,wakeup-rtt-timer; + status = "disabled"; + }; + + rtt: rtc@fffffe20 { + compatible = "microchip,sam9x7-rtt", "atmel,at91sam9260-rtt"; + reg = <0xfffffe20 0x20>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k 0>; + }; + + clk32k: clock-controller@fffffe50 { + compatible = "microchip,sam9x7-sckc", "microchip,sam9x60-sckc"; + reg = <0xfffffe50 0x4>; + clocks = <&slow_xtal>; + #clock-cells = <1>; + }; + + gpbr: syscon@fffffe60 { + compatible = "microchip,sam9x7-gpbr", "atmel,at91sam9260-gpbr", "syscon"; + reg = <0xfffffe60 0x10>; + }; + + rtc: rtc@fffffea8 { + compatible = "microchip,sam9x7-rtc", "microchip,sam9x60-rtc"; + reg = <0xfffffea8 0x100>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k 0>; + }; + + watchdog: watchdog@ffffff80 { + compatible = "microchip,sam9x7-wdt", "microchip,sam9x60-wdt"; + reg = <0xffffff80 0x24>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/boot/dts/microchip/sama5d2.dtsi b/arch/arm/boot/dts/microchip/sama5d2.dtsi index 5f8e297e19edb7..3f99451aef8324 100644 --- a/arch/arm/boot/dts/microchip/sama5d2.dtsi +++ b/arch/arm/boot/dts/microchip/sama5d2.dtsi @@ -1019,7 +1019,7 @@ AT91_XDMAC_DT_PER_IF(1) | }; }; - trng@fc01c000 { + trng: rng@fc01c000 { compatible = "atmel,at91sam9g45-trng"; reg = <0xfc01c000 0x100>; interrupts = <47 IRQ_TYPE_LEVEL_HIGH 0>; diff --git a/arch/arm/boot/dts/microchip/sama5d3.dtsi b/arch/arm/boot/dts/microchip/sama5d3.dtsi index 39865133aa5670..70f380c399ce09 100644 --- a/arch/arm/boot/dts/microchip/sama5d3.dtsi +++ b/arch/arm/boot/dts/microchip/sama5d3.dtsi @@ -419,7 +419,7 @@ tdes: crypto@f803c000 { clock-names = "tdes_clk"; }; - trng@f8040000 { + trng: rng@f8040000 { compatible = "atmel,at91sam9g45-trng"; reg = <0xf8040000 0x100>; interrupts = <45 IRQ_TYPE_LEVEL_HIGH 0>; diff --git a/arch/arm/boot/dts/microchip/sama5d34ek.dts b/arch/arm/boot/dts/microchip/sama5d34ek.dts index bffd61397cb532..18943b873fffb9 100644 --- a/arch/arm/boot/dts/microchip/sama5d34ek.dts +++ b/arch/arm/boot/dts/microchip/sama5d34ek.dts @@ -36,7 +36,7 @@ i2c0: i2c@f0014000 { i2c1: i2c@f0018000 { status = "okay"; - 24c256@50 { + eeprom@50 { compatible = "atmel,24c256"; reg = <0x50>; pagesize = <64>; diff --git a/arch/arm/boot/dts/microchip/sama5d3xcm_cmp.dtsi b/arch/arm/boot/dts/microchip/sama5d3xcm_cmp.dtsi index 830a0954ba1b01..362806afef44fa 100644 --- a/arch/arm/boot/dts/microchip/sama5d3xcm_cmp.dtsi +++ b/arch/arm/boot/dts/microchip/sama5d3xcm_cmp.dtsi @@ -79,7 +79,7 @@ ethernet-phy@7 { }; i2c1: i2c@f0018000 { - pmic: act8865@5b { + act8865: pmic@5b { compatible = "active-semi,act8865"; reg = <0x5b>; status = "disabled"; diff --git a/arch/arm/boot/dts/microchip/sama5d4.dtsi b/arch/arm/boot/dts/microchip/sama5d4.dtsi index b253ba33fc3850..355132628604ef 100644 --- a/arch/arm/boot/dts/microchip/sama5d4.dtsi +++ b/arch/arm/boot/dts/microchip/sama5d4.dtsi @@ -658,7 +658,7 @@ macb1: ethernet@fc028000 { status = "disabled"; }; - trng@fc030000 { + trng: rng@fc030000 { compatible = "atmel,at91sam9g45-trng"; reg = <0xfc030000 0x100>; interrupts = <53 IRQ_TYPE_LEVEL_HIGH 0>; diff --git a/arch/arm/boot/dts/nxp/imx/Makefile b/arch/arm/boot/dts/nxp/imx/Makefile index 92e291603ea135..39a153536d2a2b 100644 --- a/arch/arm/boot/dts/nxp/imx/Makefile +++ b/arch/arm/boot/dts/nxp/imx/Makefile @@ -73,6 +73,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6dl-cubox-i-emmc-som-v15.dtb \ imx6dl-cubox-i-som-v15.dtb \ imx6dl-dfi-fs700-m60.dtb \ + imx6dl-dhcom-pdk2.dtb \ imx6dl-dhcom-picoitx.dtb \ imx6dl-eckelmann-ci4x10.dtb \ imx6dl-emcon-avari.dtb \ @@ -211,6 +212,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \ imx6q-kontron-samx6i-ads2.dtb \ imx6q-kp-tpc.dtb \ imx6q-logicpd.dtb \ + imx6q-lxr.dtb \ imx6q-marsboard.dtb \ imx6q-mba6a.dtb \ imx6q-mba6b.dtb \ @@ -290,6 +292,8 @@ dtb-$(CONFIG_SOC_IMX6SL) += \ dtb-$(CONFIG_SOC_IMX6SLL) += \ imx6sll-evk.dtb \ imx6sll-kobo-clarahd.dtb \ + imx6sll-kobo-clara2e-a.dtb \ + imx6sll-kobo-clara2e-b.dtb \ imx6sll-kobo-librah2o.dtb dtb-$(CONFIG_SOC_IMX6SX) += \ imx6sx-nitrogen6sx.dtb \ diff --git a/arch/arm/boot/dts/nxp/imx/imx35-eukrea-cpuimx35.dtsi b/arch/arm/boot/dts/nxp/imx/imx35-eukrea-cpuimx35.dtsi index 17bd2a97609abd..ef546525e2ec8a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx35-eukrea-cpuimx35.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx35-eukrea-cpuimx35.dtsi @@ -44,40 +44,38 @@ tsc2007: tsc2007@48 { }; &iomuxc { - imx35-eukrea { - pinctrl_fec: fecgrp { - fsl,pins = < - MX35_PAD_FEC_TX_CLK__FEC_TX_CLK 0x80000000 - MX35_PAD_FEC_RX_CLK__FEC_RX_CLK 0x80000000 - MX35_PAD_FEC_RX_DV__FEC_RX_DV 0x80000000 - MX35_PAD_FEC_COL__FEC_COL 0x80000000 - MX35_PAD_FEC_RDATA0__FEC_RDATA_0 0x80000000 - MX35_PAD_FEC_TDATA0__FEC_TDATA_0 0x80000000 - MX35_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX35_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX35_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX35_PAD_FEC_TX_ERR__FEC_TX_ERR 0x80000000 - MX35_PAD_FEC_RX_ERR__FEC_RX_ERR 0x80000000 - MX35_PAD_FEC_CRS__FEC_CRS 0x80000000 - MX35_PAD_FEC_RDATA1__FEC_RDATA_1 0x80000000 - MX35_PAD_FEC_TDATA1__FEC_TDATA_1 0x80000000 - MX35_PAD_FEC_RDATA2__FEC_RDATA_2 0x80000000 - MX35_PAD_FEC_TDATA2__FEC_TDATA_2 0x80000000 - MX35_PAD_FEC_RDATA3__FEC_RDATA_3 0x80000000 - MX35_PAD_FEC_TDATA3__FEC_TDATA_3 0x80000000 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK 0x80000000 + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK 0x80000000 + MX35_PAD_FEC_RX_DV__FEC_RX_DV 0x80000000 + MX35_PAD_FEC_COL__FEC_COL 0x80000000 + MX35_PAD_FEC_RDATA0__FEC_RDATA_0 0x80000000 + MX35_PAD_FEC_TDATA0__FEC_TDATA_0 0x80000000 + MX35_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX35_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX35_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR 0x80000000 + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR 0x80000000 + MX35_PAD_FEC_CRS__FEC_CRS 0x80000000 + MX35_PAD_FEC_RDATA1__FEC_RDATA_1 0x80000000 + MX35_PAD_FEC_TDATA1__FEC_TDATA_1 0x80000000 + MX35_PAD_FEC_RDATA2__FEC_RDATA_2 0x80000000 + MX35_PAD_FEC_TDATA2__FEC_TDATA_2 0x80000000 + MX35_PAD_FEC_RDATA3__FEC_RDATA_3 0x80000000 + MX35_PAD_FEC_TDATA3__FEC_TDATA_3 0x80000000 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX35_PAD_I2C1_CLK__I2C1_SCL 0x80000000 - MX35_PAD_I2C1_DAT__I2C1_SDA 0x80000000 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX35_PAD_I2C1_CLK__I2C1_SCL 0x80000000 + MX35_PAD_I2C1_DAT__I2C1_SDA 0x80000000 + >; + }; - pinctrl_tsc2007_1: tsc2007grp-1 { - fsl,pins = ; - }; + pinctrl_tsc2007_1: tsc2007-1-grp { + fsl,pins = ; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx35-eukrea-mbimxsd35-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx35-eukrea-mbimxsd35-baseboard.dts index 7f4f812b08111a..e7835a769bbcca 100644 --- a/arch/arm/boot/dts/nxp/imx/imx35-eukrea-mbimxsd35-baseboard.dts +++ b/arch/arm/boot/dts/nxp/imx/imx35-eukrea-mbimxsd35-baseboard.dts @@ -69,57 +69,55 @@ tlv320aic23: codec@1a { }; &iomuxc { - imx35-eukrea { - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS 0x80000000 - MX35_PAD_STXD4__AUDMUX_AUD4_TXD 0x80000000 - MX35_PAD_SRXD4__AUDMUX_AUD4_RXD 0x80000000 - MX35_PAD_SCK4__AUDMUX_AUD4_TXC 0x80000000 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS 0x80000000 + MX35_PAD_STXD4__AUDMUX_AUD4_TXD 0x80000000 + MX35_PAD_SRXD4__AUDMUX_AUD4_RXD 0x80000000 + MX35_PAD_SCK4__AUDMUX_AUD4_TXC 0x80000000 + >; + }; - pinctrl_bp1: bp1grp { - fsl,pins = ; - }; + pinctrl_bp1: bp1grp { + fsl,pins = ; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX35_PAD_SD1_CMD__ESDHC1_CMD 0x80000000 - MX35_PAD_SD1_CLK__ESDHC1_CLK 0x80000000 - MX35_PAD_SD1_DATA0__ESDHC1_DAT0 0x80000000 - MX35_PAD_SD1_DATA1__ESDHC1_DAT1 0x80000000 - MX35_PAD_SD1_DATA2__ESDHC1_DAT2 0x80000000 - MX35_PAD_SD1_DATA3__ESDHC1_DAT3 0x80000000 - MX35_PAD_LD18__GPIO3_24 0x80000000 /* CD */ - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX35_PAD_SD1_CMD__ESDHC1_CMD 0x80000000 + MX35_PAD_SD1_CLK__ESDHC1_CLK 0x80000000 + MX35_PAD_SD1_DATA0__ESDHC1_DAT0 0x80000000 + MX35_PAD_SD1_DATA1__ESDHC1_DAT1 0x80000000 + MX35_PAD_SD1_DATA2__ESDHC1_DAT2 0x80000000 + MX35_PAD_SD1_DATA3__ESDHC1_DAT3 0x80000000 + MX35_PAD_LD18__GPIO3_24 0x80000000 /* CD */ + >; + }; - pinctrl_led1: led1grp { - fsl,pins = ; - }; + pinctrl_led1: led1grp { + fsl,pins = ; + }; - pinctrl_reg_lcd_3v3: reg-lcd-3v3 { - fsl,pins = ; - }; + pinctrl_reg_lcd_3v3: reg-lcd-3v3grp { + fsl,pins = ; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX35_PAD_TXD1__UART1_TXD_MUX 0x1c5 - MX35_PAD_RXD1__UART1_RXD_MUX 0x1c5 - MX35_PAD_CTS1__UART1_CTS 0x1c5 - MX35_PAD_RTS1__UART1_RTS 0x1c5 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX35_PAD_TXD1__UART1_TXD_MUX 0x1c5 + MX35_PAD_RXD1__UART1_RXD_MUX 0x1c5 + MX35_PAD_CTS1__UART1_CTS 0x1c5 + MX35_PAD_RTS1__UART1_RTS 0x1c5 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX35_PAD_RXD2__UART2_RXD_MUX 0x1c5 - MX35_PAD_TXD2__UART2_TXD_MUX 0x1c5 - MX35_PAD_RTS2__UART2_RTS 0x1c5 - MX35_PAD_CTS2__UART2_CTS 0x1c5 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX35_PAD_RXD2__UART2_RXD_MUX 0x1c5 + MX35_PAD_TXD2__UART2_TXD_MUX 0x1c5 + MX35_PAD_RTS2__UART2_RTS 0x1c5 + MX35_PAD_CTS2__UART2_CTS 0x1c5 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx35-pdk.dts b/arch/arm/boot/dts/nxp/imx/imx35-pdk.dts index ddce0a844758b3..a2baf8202f94e9 100644 --- a/arch/arm/boot/dts/nxp/imx/imx35-pdk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx35-pdk.dts @@ -24,26 +24,24 @@ &esdhc1 { }; &iomuxc { - imx35-pdk { - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX35_PAD_SD1_CMD__ESDHC1_CMD 0x80000000 - MX35_PAD_SD1_CLK__ESDHC1_CLK 0x80000000 - MX35_PAD_SD1_DATA0__ESDHC1_DAT0 0x80000000 - MX35_PAD_SD1_DATA1__ESDHC1_DAT1 0x80000000 - MX35_PAD_SD1_DATA2__ESDHC1_DAT2 0x80000000 - MX35_PAD_SD1_DATA3__ESDHC1_DAT3 0x80000000 - >; - }; - - pinctrl_uart1: uart1grp { - fsl,pins = < - MX35_PAD_TXD1__UART1_TXD_MUX 0x1c5 - MX35_PAD_RXD1__UART1_RXD_MUX 0x1c5 - MX35_PAD_CTS1__UART1_CTS 0x1c5 - MX35_PAD_RTS1__UART1_RTS 0x1c5 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX35_PAD_SD1_CMD__ESDHC1_CMD 0x80000000 + MX35_PAD_SD1_CLK__ESDHC1_CLK 0x80000000 + MX35_PAD_SD1_DATA0__ESDHC1_DAT0 0x80000000 + MX35_PAD_SD1_DATA1__ESDHC1_DAT1 0x80000000 + MX35_PAD_SD1_DATA2__ESDHC1_DAT2 0x80000000 + MX35_PAD_SD1_DATA3__ESDHC1_DAT3 0x80000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX35_PAD_TXD1__UART1_TXD_MUX 0x1c5 + MX35_PAD_RXD1__UART1_RXD_MUX 0x1c5 + MX35_PAD_CTS1__UART1_CTS 0x1c5 + MX35_PAD_RTS1__UART1_RTS 0x1c5 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx35.dtsi b/arch/arm/boot/dts/nxp/imx/imx35.dtsi index 442dc15677b87e..30beb39e0162ca 100644 --- a/arch/arm/boot/dts/nxp/imx/imx35.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx35.dtsi @@ -156,7 +156,7 @@ kpp: kpp@43fa8000 { status = "disabled"; }; - iomuxc: iomuxc@43fac000 { + iomuxc: pinctrl@43fac000 { compatible = "fsl,imx35-iomuxc"; reg = <0x43fac000 0x4000>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx50-evk.dts b/arch/arm/boot/dts/nxp/imx/imx50-evk.dts index 3f45c01d9cce39..f40b0d5fdb85fd 100644 --- a/arch/arm/boot/dts/nxp/imx/imx50-evk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx50-evk.dts @@ -52,40 +52,38 @@ &fec { }; &iomuxc { - imx50-evk { - pinctrl_cspi: cspigrp { - fsl,pins = < - MX50_PAD_CSPI_SCLK__CSPI_SCLK 0x00 - MX50_PAD_CSPI_MISO__CSPI_MISO 0x00 - MX50_PAD_CSPI_MOSI__CSPI_MOSI 0x00 - MX50_PAD_CSPI_SS0__GPIO4_11 0xc4 - MX50_PAD_ECSPI1_MOSI__GPIO4_13 0x84 - >; - }; + pinctrl_cspi: cspigrp { + fsl,pins = < + MX50_PAD_CSPI_SCLK__CSPI_SCLK 0x00 + MX50_PAD_CSPI_MISO__CSPI_MISO 0x00 + MX50_PAD_CSPI_MOSI__CSPI_MOSI 0x00 + MX50_PAD_CSPI_SS0__GPIO4_11 0xc4 + MX50_PAD_ECSPI1_MOSI__GPIO4_13 0x84 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX50_PAD_SSI_RXFS__FEC_MDC 0x80 - MX50_PAD_SSI_RXC__FEC_MDIO 0x80 - MX50_PAD_DISP_D0__FEC_TX_CLK 0x80 - MX50_PAD_DISP_D1__FEC_RX_ERR 0x80 - MX50_PAD_DISP_D2__FEC_RX_DV 0x80 - MX50_PAD_DISP_D3__FEC_RDATA_1 0x80 - MX50_PAD_DISP_D4__FEC_RDATA_0 0x80 - MX50_PAD_DISP_D5__FEC_TX_EN 0x80 - MX50_PAD_DISP_D6__FEC_TDATA_1 0x80 - MX50_PAD_DISP_D7__FEC_TDATA_0 0x80 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX50_PAD_SSI_RXFS__FEC_MDC 0x80 + MX50_PAD_SSI_RXC__FEC_MDIO 0x80 + MX50_PAD_DISP_D0__FEC_TX_CLK 0x80 + MX50_PAD_DISP_D1__FEC_RX_ERR 0x80 + MX50_PAD_DISP_D2__FEC_RX_DV 0x80 + MX50_PAD_DISP_D3__FEC_RDATA_1 0x80 + MX50_PAD_DISP_D4__FEC_RDATA_0 0x80 + MX50_PAD_DISP_D5__FEC_TX_EN 0x80 + MX50_PAD_DISP_D6__FEC_TDATA_1 0x80 + MX50_PAD_DISP_D7__FEC_TDATA_0 0x80 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX50_PAD_UART1_TXD__UART1_TXD_MUX 0x1e4 - MX50_PAD_UART1_RXD__UART1_RXD_MUX 0x1e4 - MX50_PAD_UART1_RTS__UART1_RTS 0x1e4 - MX50_PAD_UART1_CTS__UART1_CTS 0x1e4 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX50_PAD_UART1_TXD__UART1_TXD_MUX 0x1e4 + MX50_PAD_UART1_RXD__UART1_RXD_MUX 0x1e4 + MX50_PAD_UART1_RTS__UART1_RTS 0x1e4 + MX50_PAD_UART1_CTS__UART1_CTS 0x1e4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx50.dtsi b/arch/arm/boot/dts/nxp/imx/imx50.dtsi index c5b25d2f6264ae..1b6f444443dd1b 100644 --- a/arch/arm/boot/dts/nxp/imx/imx50.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx50.dtsi @@ -283,7 +283,7 @@ gpt: timer@53fa0000 { clock-names = "ipg", "per"; }; - iomuxc: iomuxc@53fa8000 { + iomuxc: pinctrl@53fa8000 { compatible = "fsl,imx50-iomuxc", "fsl,imx53-iomuxc"; reg = <0x53fa8000 0x4000>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx51-apf51.dts b/arch/arm/boot/dts/nxp/imx/imx51-apf51.dts index ba28ffe06fe231..670e13136f1f2a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx51-apf51.dts +++ b/arch/arm/boot/dts/nxp/imx/imx51-apf51.dts @@ -37,36 +37,34 @@ &fec { }; &iomuxc { - imx51-apf51 { - pinctrl_fec: fecgrp { - fsl,pins = < - MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 - MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 - MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 - MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 - MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 - MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 - MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 - MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 - MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 - MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 - MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 - MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 - MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 - MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 - MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 - MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 - MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 - MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 + MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 + MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 + MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 + MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 + MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 + MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 + MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 + MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 + MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 + MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 + MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 + MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 + MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 + MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 + MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 + MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 + MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 - MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 + MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx51-apf51dev.dts b/arch/arm/boot/dts/nxp/imx/imx51-apf51dev.dts index de6b7607510af8..6ebd80e30683a1 100644 --- a/arch/arm/boot/dts/nxp/imx/imx51-apf51dev.dts +++ b/arch/arm/boot/dts/nxp/imx/imx51-apf51dev.dts @@ -113,102 +113,100 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx51-apf51dev { - pinctrl_backlight: backlightgrp { - fsl,pins = < - MX51_PAD_DI1_D1_CS__GPIO3_4 0x1F5 - >; - }; + pinctrl_backlight: backlightgrp { + fsl,pins = < + MX51_PAD_DI1_D1_CS__GPIO3_4 0x1F5 + >; + }; - pinctrl_hog: hoggrp { - fsl,pins = < - MX51_PAD_EIM_EB2__GPIO2_22 0x0C5 - MX51_PAD_EIM_EB3__GPIO2_23 0x0C5 - MX51_PAD_EIM_CS4__GPIO2_29 0x100 - MX51_PAD_NANDF_D13__GPIO3_27 0x0C5 - MX51_PAD_NANDF_D12__GPIO3_28 0x0C5 - MX51_PAD_CSPI1_SS0__GPIO4_24 0x0C5 - MX51_PAD_CSPI1_SS1__GPIO4_25 0x0C5 - MX51_PAD_GPIO1_2__GPIO1_2 0x0C5 - MX51_PAD_GPIO1_3__GPIO1_3 0x0C5 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX51_PAD_EIM_EB2__GPIO2_22 0x0C5 + MX51_PAD_EIM_EB3__GPIO2_23 0x0C5 + MX51_PAD_EIM_CS4__GPIO2_29 0x100 + MX51_PAD_NANDF_D13__GPIO3_27 0x0C5 + MX51_PAD_NANDF_D12__GPIO3_28 0x0C5 + MX51_PAD_CSPI1_SS0__GPIO4_24 0x0C5 + MX51_PAD_CSPI1_SS1__GPIO4_25 0x0C5 + MX51_PAD_GPIO1_2__GPIO1_2 0x0C5 + MX51_PAD_GPIO1_3__GPIO1_3 0x0C5 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 - MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 - MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 + >; + }; - pinctrl_ecspi2: ecspi2grp { - fsl,pins = < - MX51_PAD_NANDF_RB3__ECSPI2_MISO 0x185 - MX51_PAD_NANDF_D15__ECSPI2_MOSI 0x185 - MX51_PAD_NANDF_RB2__ECSPI2_SCLK 0x185 - >; - }; + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX51_PAD_NANDF_RB3__ECSPI2_MISO 0x185 + MX51_PAD_NANDF_D15__ECSPI2_MOSI 0x185 + MX51_PAD_NANDF_RB2__ECSPI2_SCLK 0x185 + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 - MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 - MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 - MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 - MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 - MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 + MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 + MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 + MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 + MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 + MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 + >; + }; - pinctrl_esdhc2: esdhc2grp { - fsl,pins = < - MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 - MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 - MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 - MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 - MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 - MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 - >; - }; + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 + MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 + MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 + MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 + MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 + MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX51_PAD_EIM_D27__I2C2_SCL 0x400001ed - MX51_PAD_EIM_D24__I2C2_SDA 0x400001ed - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX51_PAD_EIM_D27__I2C2_SCL 0x400001ed + MX51_PAD_EIM_D24__I2C2_SDA 0x400001ed + >; + }; - pinctrl_ipu_disp1: ipudisp1grp { - fsl,pins = < - MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5 - MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5 - MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5 - MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5 - MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5 - MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5 - MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5 - MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5 - MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5 - MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5 - MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5 - MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5 - MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5 - MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5 - MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5 - MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5 - MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5 - MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5 - MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5 - MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5 - MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5 - MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5 - MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5 - MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5 - MX51_PAD_DI1_PIN2__DI1_PIN2 0x5 - MX51_PAD_DI1_PIN3__DI1_PIN3 0x5 - >; - }; + pinctrl_ipu_disp1: ipudisp1grp { + fsl,pins = < + MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5 + MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5 + MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5 + MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5 + MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5 + MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5 + MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5 + MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5 + MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5 + MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5 + MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5 + MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5 + MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5 + MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5 + MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5 + MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5 + MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5 + MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5 + MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5 + MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5 + MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5 + MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5 + MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5 + MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5 + MX51_PAD_DI1_PIN2__DI1_PIN2 0x5 + MX51_PAD_DI1_PIN3__DI1_PIN3 0x5 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx51-babbage.dts b/arch/arm/boot/dts/nxp/imx/imx51-babbage.dts index f4a47e8348b23a..1b6ec55f906839 100644 --- a/arch/arm/boot/dts/nxp/imx/imx51-babbage.dts +++ b/arch/arm/boot/dts/nxp/imx/imx51-babbage.dts @@ -474,246 +474,244 @@ &usbotg { }; &iomuxc { - imx51-babbage { - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX51_PAD_AUD3_BB_TXD__AUD3_TXD 0x80000000 - MX51_PAD_AUD3_BB_RXD__AUD3_RXD 0x80000000 - MX51_PAD_AUD3_BB_CK__AUD3_TXC 0x80000000 - MX51_PAD_AUD3_BB_FS__AUD3_TXFS 0x80000000 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX51_PAD_AUD3_BB_TXD__AUD3_TXD 0x80000000 + MX51_PAD_AUD3_BB_RXD__AUD3_RXD 0x80000000 + MX51_PAD_AUD3_BB_CK__AUD3_TXC 0x80000000 + MX51_PAD_AUD3_BB_FS__AUD3_TXFS 0x80000000 + >; + }; - pinctrl_clk26mhz_audio: clk26mhzaudiocgrp { - fsl,pins = < - MX51_PAD_CSPI1_RDY__GPIO4_26 0x85 - >; - }; + pinctrl_clk26mhz_audio: clk26mhzaudiocgrp { + fsl,pins = < + MX51_PAD_CSPI1_RDY__GPIO4_26 0x85 + >; + }; - pinctrl_clk26mhz_osc: clk26mhzoscgrp { - fsl,pins = < - MX51_PAD_DI1_PIN12__GPIO3_1 0x85 - >; - }; + pinctrl_clk26mhz_osc: clk26mhzoscgrp { + fsl,pins = < + MX51_PAD_DI1_PIN12__GPIO3_1 0x85 + >; + }; - pinctrl_clk26mhz_usb: clk26mhzusbgrp { - fsl,pins = < - MX51_PAD_EIM_D17__GPIO2_1 0x85 - >; - }; + pinctrl_clk26mhz_usb: clk26mhzusbgrp { + fsl,pins = < + MX51_PAD_EIM_D17__GPIO2_1 0x85 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 - MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 - MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 - MX51_PAD_CSPI1_SS0__GPIO4_24 0x85 /* CS0 */ - MX51_PAD_CSPI1_SS1__GPIO4_25 0x85 /* CS1 */ - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 + MX51_PAD_CSPI1_SS0__GPIO4_24 0x85 /* CS0 */ + MX51_PAD_CSPI1_SS1__GPIO4_25 0x85 /* CS1 */ + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 - MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 - MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 - MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 - MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 - MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 - MX51_PAD_GPIO1_0__GPIO1_0 0x100 - MX51_PAD_GPIO1_1__GPIO1_1 0x100 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 + MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 + MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 + MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 + MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 + MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 + MX51_PAD_GPIO1_0__GPIO1_0 0x100 + MX51_PAD_GPIO1_1__GPIO1_1 0x100 + >; + }; - pinctrl_esdhc2: esdhc2grp { - fsl,pins = < - MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 - MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 - MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 - MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 - MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 - MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 - MX51_PAD_GPIO1_5__GPIO1_5 0x100 /* WP */ - MX51_PAD_GPIO1_6__GPIO1_6 0x100 /* CD */ - >; - }; + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 + MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 + MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 + MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 + MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 + MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 + MX51_PAD_GPIO1_5__GPIO1_5 0x100 /* WP */ + MX51_PAD_GPIO1_6__GPIO1_6 0x100 /* CD */ + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX51_PAD_EIM_EB2__FEC_MDIO 0x000001f5 - MX51_PAD_EIM_EB3__FEC_RDATA1 0x00000085 - MX51_PAD_EIM_CS2__FEC_RDATA2 0x00000085 - MX51_PAD_EIM_CS3__FEC_RDATA3 0x00000085 - MX51_PAD_EIM_CS4__FEC_RX_ER 0x00000180 - MX51_PAD_EIM_CS5__FEC_CRS 0x00000180 - MX51_PAD_NANDF_RB2__FEC_COL 0x00000180 - MX51_PAD_NANDF_RB3__FEC_RX_CLK 0x00000180 - MX51_PAD_NANDF_D9__FEC_RDATA0 0x00002180 - MX51_PAD_NANDF_D8__FEC_TDATA0 0x00002004 - MX51_PAD_NANDF_CS2__FEC_TX_ER 0x00002004 - MX51_PAD_NANDF_CS3__FEC_MDC 0x00002004 - MX51_PAD_NANDF_CS4__FEC_TDATA1 0x00002004 - MX51_PAD_NANDF_CS5__FEC_TDATA2 0x00002004 - MX51_PAD_NANDF_CS6__FEC_TDATA3 0x00002004 - MX51_PAD_NANDF_CS7__FEC_TX_EN 0x00002004 - MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK 0x00002180 - MX51_PAD_NANDF_D11__FEC_RX_DV 0x000020a4 - MX51_PAD_EIM_A20__GPIO2_14 0x00000085 /* Phy Reset */ - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX51_PAD_EIM_EB2__FEC_MDIO 0x000001f5 + MX51_PAD_EIM_EB3__FEC_RDATA1 0x00000085 + MX51_PAD_EIM_CS2__FEC_RDATA2 0x00000085 + MX51_PAD_EIM_CS3__FEC_RDATA3 0x00000085 + MX51_PAD_EIM_CS4__FEC_RX_ER 0x00000180 + MX51_PAD_EIM_CS5__FEC_CRS 0x00000180 + MX51_PAD_NANDF_RB2__FEC_COL 0x00000180 + MX51_PAD_NANDF_RB3__FEC_RX_CLK 0x00000180 + MX51_PAD_NANDF_D9__FEC_RDATA0 0x00002180 + MX51_PAD_NANDF_D8__FEC_TDATA0 0x00002004 + MX51_PAD_NANDF_CS2__FEC_TX_ER 0x00002004 + MX51_PAD_NANDF_CS3__FEC_MDC 0x00002004 + MX51_PAD_NANDF_CS4__FEC_TDATA1 0x00002004 + MX51_PAD_NANDF_CS5__FEC_TDATA2 0x00002004 + MX51_PAD_NANDF_CS6__FEC_TDATA3 0x00002004 + MX51_PAD_NANDF_CS7__FEC_TX_EN 0x00002004 + MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK 0x00002180 + MX51_PAD_NANDF_D11__FEC_RX_DV 0x000020a4 + MX51_PAD_EIM_A20__GPIO2_14 0x00000085 /* Phy Reset */ + >; + }; - pinctrl_gpio_keys: gpiokeysgrp { - fsl,pins = < - MX51_PAD_EIM_A27__GPIO2_21 0x5 - >; - }; + pinctrl_gpio_keys: gpiokeysgrp { + fsl,pins = < + MX51_PAD_EIM_A27__GPIO2_21 0x5 + >; + }; - pinctrl_gpio_leds: gpioledsgrp { - fsl,pins = < - MX51_PAD_EIM_D22__GPIO2_6 0x80000000 - >; - }; + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX51_PAD_EIM_D22__GPIO2_6 0x80000000 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX51_PAD_EIM_D19__I2C1_SCL 0x400001ed - MX51_PAD_EIM_D16__I2C1_SDA 0x400001ed - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX51_PAD_EIM_D19__I2C1_SCL 0x400001ed + MX51_PAD_EIM_D16__I2C1_SDA 0x400001ed + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX51_PAD_KEY_COL4__I2C2_SCL 0x400001ed - MX51_PAD_KEY_COL5__I2C2_SDA 0x400001ed - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX51_PAD_KEY_COL4__I2C2_SCL 0x400001ed + MX51_PAD_KEY_COL5__I2C2_SDA 0x400001ed + >; + }; - pinctrl_ipu_disp1: ipudisp1grp { - fsl,pins = < - MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5 - MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5 - MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5 - MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5 - MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5 - MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5 - MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5 - MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5 - MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5 - MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5 - MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5 - MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5 - MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5 - MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5 - MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5 - MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5 - MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5 - MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5 - MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5 - MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5 - MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5 - MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5 - MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5 - MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5 - MX51_PAD_DI1_PIN2__DI1_PIN2 0x5 - MX51_PAD_DI1_PIN3__DI1_PIN3 0x5 - >; - }; + pinctrl_ipu_disp1: ipudisp1grp { + fsl,pins = < + MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5 + MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5 + MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5 + MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5 + MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5 + MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5 + MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5 + MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5 + MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5 + MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5 + MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5 + MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5 + MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5 + MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5 + MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5 + MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5 + MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5 + MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5 + MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5 + MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5 + MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5 + MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5 + MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5 + MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5 + MX51_PAD_DI1_PIN2__DI1_PIN2 0x5 + MX51_PAD_DI1_PIN3__DI1_PIN3 0x5 + >; + }; - pinctrl_ipu_disp2: ipudisp2grp { - fsl,pins = < - MX51_PAD_DISP2_DAT0__DISP2_DAT0 0x5 - MX51_PAD_DISP2_DAT1__DISP2_DAT1 0x5 - MX51_PAD_DISP2_DAT2__DISP2_DAT2 0x5 - MX51_PAD_DISP2_DAT3__DISP2_DAT3 0x5 - MX51_PAD_DISP2_DAT4__DISP2_DAT4 0x5 - MX51_PAD_DISP2_DAT5__DISP2_DAT5 0x5 - MX51_PAD_DISP2_DAT6__DISP2_DAT6 0x5 - MX51_PAD_DISP2_DAT7__DISP2_DAT7 0x5 - MX51_PAD_DISP2_DAT8__DISP2_DAT8 0x5 - MX51_PAD_DISP2_DAT9__DISP2_DAT9 0x5 - MX51_PAD_DISP2_DAT10__DISP2_DAT10 0x5 - MX51_PAD_DISP2_DAT11__DISP2_DAT11 0x5 - MX51_PAD_DISP2_DAT12__DISP2_DAT12 0x5 - MX51_PAD_DISP2_DAT13__DISP2_DAT13 0x5 - MX51_PAD_DISP2_DAT14__DISP2_DAT14 0x5 - MX51_PAD_DISP2_DAT15__DISP2_DAT15 0x5 - MX51_PAD_DI2_PIN2__DI2_PIN2 0x5 - MX51_PAD_DI2_PIN3__DI2_PIN3 0x5 - MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK 0x5 - MX51_PAD_DI_GP4__DI2_PIN15 0x5 - >; - }; + pinctrl_ipu_disp2: ipudisp2grp { + fsl,pins = < + MX51_PAD_DISP2_DAT0__DISP2_DAT0 0x5 + MX51_PAD_DISP2_DAT1__DISP2_DAT1 0x5 + MX51_PAD_DISP2_DAT2__DISP2_DAT2 0x5 + MX51_PAD_DISP2_DAT3__DISP2_DAT3 0x5 + MX51_PAD_DISP2_DAT4__DISP2_DAT4 0x5 + MX51_PAD_DISP2_DAT5__DISP2_DAT5 0x5 + MX51_PAD_DISP2_DAT6__DISP2_DAT6 0x5 + MX51_PAD_DISP2_DAT7__DISP2_DAT7 0x5 + MX51_PAD_DISP2_DAT8__DISP2_DAT8 0x5 + MX51_PAD_DISP2_DAT9__DISP2_DAT9 0x5 + MX51_PAD_DISP2_DAT10__DISP2_DAT10 0x5 + MX51_PAD_DISP2_DAT11__DISP2_DAT11 0x5 + MX51_PAD_DISP2_DAT12__DISP2_DAT12 0x5 + MX51_PAD_DISP2_DAT13__DISP2_DAT13 0x5 + MX51_PAD_DISP2_DAT14__DISP2_DAT14 0x5 + MX51_PAD_DISP2_DAT15__DISP2_DAT15 0x5 + MX51_PAD_DI2_PIN2__DI2_PIN2 0x5 + MX51_PAD_DI2_PIN3__DI2_PIN3 0x5 + MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK 0x5 + MX51_PAD_DI_GP4__DI2_PIN15 0x5 + >; + }; - pinctrl_kpp: kppgrp { - fsl,pins = < - MX51_PAD_KEY_ROW0__KEY_ROW0 0xe0 - MX51_PAD_KEY_ROW1__KEY_ROW1 0xe0 - MX51_PAD_KEY_ROW2__KEY_ROW2 0xe0 - MX51_PAD_KEY_ROW3__KEY_ROW3 0xe0 - MX51_PAD_KEY_COL0__KEY_COL0 0xe8 - MX51_PAD_KEY_COL1__KEY_COL1 0xe8 - MX51_PAD_KEY_COL2__KEY_COL2 0xe8 - MX51_PAD_KEY_COL3__KEY_COL3 0xe8 - >; - }; + pinctrl_kpp: kppgrp { + fsl,pins = < + MX51_PAD_KEY_ROW0__KEY_ROW0 0xe0 + MX51_PAD_KEY_ROW1__KEY_ROW1 0xe0 + MX51_PAD_KEY_ROW2__KEY_ROW2 0xe0 + MX51_PAD_KEY_ROW3__KEY_ROW3 0xe0 + MX51_PAD_KEY_COL0__KEY_COL0 0xe8 + MX51_PAD_KEY_COL1__KEY_COL1 0xe8 + MX51_PAD_KEY_COL2__KEY_COL2 0xe8 + MX51_PAD_KEY_COL3__KEY_COL3 0xe8 + >; + }; - pinctrl_pmic: pmicgrp { - fsl,pins = < - MX51_PAD_GPIO1_8__GPIO1_8 0xe5 /* IRQ */ - >; - }; + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX51_PAD_GPIO1_8__GPIO1_8 0xe5 /* IRQ */ + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 - MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 - MX51_PAD_UART1_RTS__UART1_RTS 0x1c5 - MX51_PAD_UART1_CTS__UART1_CTS 0x1c5 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 + MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 + MX51_PAD_UART1_RTS__UART1_RTS 0x1c5 + MX51_PAD_UART1_CTS__UART1_CTS 0x1c5 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX51_PAD_UART2_RXD__UART2_RXD 0x1c5 - MX51_PAD_UART2_TXD__UART2_TXD 0x1c5 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX51_PAD_UART2_RXD__UART2_RXD 0x1c5 + MX51_PAD_UART2_TXD__UART2_TXD 0x1c5 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX51_PAD_EIM_D25__UART3_RXD 0x1c5 - MX51_PAD_EIM_D26__UART3_TXD 0x1c5 - MX51_PAD_EIM_D27__UART3_RTS 0x1c5 - MX51_PAD_EIM_D24__UART3_CTS 0x1c5 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX51_PAD_EIM_D25__UART3_RXD 0x1c5 + MX51_PAD_EIM_D26__UART3_TXD 0x1c5 + MX51_PAD_EIM_D27__UART3_RTS 0x1c5 + MX51_PAD_EIM_D24__UART3_CTS 0x1c5 + >; + }; - pinctrl_usbh1: usbh1grp { - fsl,pins = < - MX51_PAD_USBH1_CLK__USBH1_CLK 0x80000000 - MX51_PAD_USBH1_DIR__USBH1_DIR 0x80000000 - MX51_PAD_USBH1_NXT__USBH1_NXT 0x80000000 - MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x80000000 - MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x80000000 - MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x80000000 - MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x80000000 - MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x80000000 - MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x80000000 - MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x80000000 - MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x80000000 - >; - }; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX51_PAD_USBH1_CLK__USBH1_CLK 0x80000000 + MX51_PAD_USBH1_DIR__USBH1_DIR 0x80000000 + MX51_PAD_USBH1_NXT__USBH1_NXT 0x80000000 + MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x80000000 + MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x80000000 + MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x80000000 + MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x80000000 + MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x80000000 + MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x80000000 + MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x80000000 + MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x80000000 + >; + }; - pinctrl_usbh1reg: usbh1reggrp { - fsl,pins = < - MX51_PAD_EIM_D21__GPIO2_5 0x85 - >; - }; + pinctrl_usbh1reg: usbh1reggrp { + fsl,pins = < + MX51_PAD_EIM_D21__GPIO2_5 0x85 + >; + }; - pinctrl_usbotgreg: usbotgreggrp { - fsl,pins = < - MX51_PAD_GPIO1_7__GPIO1_7 0x85 - >; - }; + pinctrl_usbotgreg: usbotgreggrp { + fsl,pins = < + MX51_PAD_GPIO1_7__GPIO1_7 0x85 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx51-digi-connectcore-jsk.dts b/arch/arm/boot/dts/nxp/imx/imx51-digi-connectcore-jsk.dts index 10cae7c3a8791d..9750b5f933301c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx51-digi-connectcore-jsk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx51-digi-connectcore-jsk.dts @@ -78,49 +78,47 @@ &usbh1 { }; &iomuxc { - imx51-digi-connectcore-jsk { - pinctrl_owire: owiregrp { - fsl,pins = < - MX51_PAD_OWIRE_LINE__OWIRE_LINE 0x40000000 - >; - }; + pinctrl_owire: owiregrp { + fsl,pins = < + MX51_PAD_OWIRE_LINE__OWIRE_LINE 0x40000000 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 - MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 + MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX51_PAD_UART2_RXD__UART2_RXD 0x1c5 - MX51_PAD_UART2_TXD__UART2_TXD 0x1c5 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX51_PAD_UART2_RXD__UART2_RXD 0x1c5 + MX51_PAD_UART2_TXD__UART2_TXD 0x1c5 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 - MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 + MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 + >; + }; - pinctrl_usbh1: usbh1grp { - fsl,pins = < - MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x1e5 - MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x1e5 - MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x1e5 - MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x1e5 - MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x1e5 - MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x1e5 - MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x1e5 - MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x1e5 - MX51_PAD_USBH1_CLK__USBH1_CLK 0x1e5 - MX51_PAD_USBH1_DIR__USBH1_DIR 0x1e5 - MX51_PAD_USBH1_NXT__USBH1_NXT 0x1e5 - MX51_PAD_USBH1_STP__USBH1_STP 0x1e5 - >; - }; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x1e5 + MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x1e5 + MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x1e5 + MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x1e5 + MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x1e5 + MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x1e5 + MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x1e5 + MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x1e5 + MX51_PAD_USBH1_CLK__USBH1_CLK 0x1e5 + MX51_PAD_USBH1_DIR__USBH1_DIR 0x1e5 + MX51_PAD_USBH1_NXT__USBH1_NXT 0x1e5 + MX51_PAD_USBH1_STP__USBH1_STP 0x1e5 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx51-digi-connectcore-som.dtsi b/arch/arm/boot/dts/nxp/imx/imx51-digi-connectcore-som.dtsi index f0809a16a2ceae..dc72a2d14960fe 100644 --- a/arch/arm/boot/dts/nxp/imx/imx51-digi-connectcore-som.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx51-digi-connectcore-som.dtsi @@ -215,162 +215,160 @@ lan9221: ethernet@5,0 { }; &iomuxc { - imx51-digi-connectcore-som { - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 - MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 - MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 - MX51_PAD_CSPI1_SS0__GPIO4_24 0x85 /* CS0 */ - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 + MX51_PAD_CSPI1_SS0__GPIO4_24 0x85 /* CS0 */ + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX51_PAD_SD1_CLK__SD1_CLK 0x400021d5 - MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 - MX51_PAD_SD1_DATA0__SD1_DATA0 0x400020d5 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX51_PAD_SD1_CLK__SD1_CLK 0x400021d5 + MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 + MX51_PAD_SD1_DATA0__SD1_DATA0 0x400020d5 + >; + }; - pinctrl_esdhc2: esdhc2grp { - fsl,pins = < - MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 - MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 - MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 - MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 - MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 - MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 - >; - }; + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX51_PAD_SD2_CMD__SD2_CMD 0x400020d5 + MX51_PAD_SD2_CLK__SD2_CLK 0x20d5 + MX51_PAD_SD2_DATA0__SD2_DATA0 0x20d5 + MX51_PAD_SD2_DATA1__SD2_DATA1 0x20d5 + MX51_PAD_SD2_DATA2__SD2_DATA2 0x20d5 + MX51_PAD_SD2_DATA3__SD2_DATA3 0x20d5 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 - MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 - MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 - MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 - MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 - MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 - MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 - MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 - MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 - MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 - MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 - MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 - MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 - MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 - MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 - MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 - MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 - MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 + MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 + MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 + MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 + MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 + MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 + MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 + MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 + MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 + MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 + MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 + MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 + MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 + MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 + MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 + MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 + MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 + MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX51_PAD_GPIO1_2__I2C2_SCL 0x400001ed - MX51_PAD_GPIO1_3__I2C2_SDA 0x400001ed - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX51_PAD_GPIO1_2__I2C2_SCL 0x400001ed + MX51_PAD_GPIO1_3__I2C2_SDA 0x400001ed + >; + }; - pinctrl_i2c2_gpio: i2c2gpiogrp { - fsl,pins = < - MX51_PAD_GPIO1_2__GPIO1_2 0x400001ed - MX51_PAD_GPIO1_3__GPIO1_3 0x400001ed - >; - }; + pinctrl_i2c2_gpio: i2c2gpiogrp { + fsl,pins = < + MX51_PAD_GPIO1_2__GPIO1_2 0x400001ed + MX51_PAD_GPIO1_3__GPIO1_3 0x400001ed + >; + }; - pinctrl_nfc: nfcgrp { - fsl,pins = < - MX51_PAD_NANDF_D0__NANDF_D0 0x80000000 - MX51_PAD_NANDF_D1__NANDF_D1 0x80000000 - MX51_PAD_NANDF_D2__NANDF_D2 0x80000000 - MX51_PAD_NANDF_D3__NANDF_D3 0x80000000 - MX51_PAD_NANDF_D4__NANDF_D4 0x80000000 - MX51_PAD_NANDF_D5__NANDF_D5 0x80000000 - MX51_PAD_NANDF_D6__NANDF_D6 0x80000000 - MX51_PAD_NANDF_D7__NANDF_D7 0x80000000 - MX51_PAD_NANDF_ALE__NANDF_ALE 0x80000000 - MX51_PAD_NANDF_CLE__NANDF_CLE 0x80000000 - MX51_PAD_NANDF_RE_B__NANDF_RE_B 0x80000000 - MX51_PAD_NANDF_WE_B__NANDF_WE_B 0x80000000 - MX51_PAD_NANDF_WP_B__NANDF_WP_B 0x80000000 - MX51_PAD_NANDF_CS0__NANDF_CS0 0x80000000 - MX51_PAD_NANDF_RB0__NANDF_RB0 0x80000000 - >; - }; + pinctrl_nfc: nfcgrp { + fsl,pins = < + MX51_PAD_NANDF_D0__NANDF_D0 0x80000000 + MX51_PAD_NANDF_D1__NANDF_D1 0x80000000 + MX51_PAD_NANDF_D2__NANDF_D2 0x80000000 + MX51_PAD_NANDF_D3__NANDF_D3 0x80000000 + MX51_PAD_NANDF_D4__NANDF_D4 0x80000000 + MX51_PAD_NANDF_D5__NANDF_D5 0x80000000 + MX51_PAD_NANDF_D6__NANDF_D6 0x80000000 + MX51_PAD_NANDF_D7__NANDF_D7 0x80000000 + MX51_PAD_NANDF_ALE__NANDF_ALE 0x80000000 + MX51_PAD_NANDF_CLE__NANDF_CLE 0x80000000 + MX51_PAD_NANDF_RE_B__NANDF_RE_B 0x80000000 + MX51_PAD_NANDF_WE_B__NANDF_WE_B 0x80000000 + MX51_PAD_NANDF_WP_B__NANDF_WP_B 0x80000000 + MX51_PAD_NANDF_CS0__NANDF_CS0 0x80000000 + MX51_PAD_NANDF_RB0__NANDF_RB0 0x80000000 + >; + }; - pinctrl_lan9221: lan9221grp { - fsl,pins = < - MX51_PAD_GPIO1_9__GPIO1_9 0xe5 /* IRQ */ - >; - }; + pinctrl_lan9221: lan9221grp { + fsl,pins = < + MX51_PAD_GPIO1_9__GPIO1_9 0xe5 /* IRQ */ + >; + }; - pinctrl_mc13892: mc13892grp { - fsl,pins = < - MX51_PAD_GPIO1_5__GPIO1_5 0xe5 /* IRQ */ - >; - }; + pinctrl_mc13892: mc13892grp { + fsl,pins = < + MX51_PAD_GPIO1_5__GPIO1_5 0xe5 /* IRQ */ + >; + }; - pinctrl_mma7455l: mma7455lgrp { - fsl,pins = < - MX51_PAD_GPIO1_7__GPIO1_7 0xe5 /* IRQ1 */ - MX51_PAD_GPIO1_6__GPIO1_6 0xe5 /* IRQ2 */ - >; - }; + pinctrl_mma7455l: mma7455lgrp { + fsl,pins = < + MX51_PAD_GPIO1_7__GPIO1_7 0xe5 /* IRQ1 */ + MX51_PAD_GPIO1_6__GPIO1_6 0xe5 /* IRQ2 */ + >; + }; - pinctrl_weim: weimgrp { - fsl,pins = < - MX51_PAD_EIM_DA0__EIM_DA0 0x80000000 - MX51_PAD_EIM_DA1__EIM_DA1 0x80000000 - MX51_PAD_EIM_DA2__EIM_DA2 0x80000000 - MX51_PAD_EIM_DA3__EIM_DA3 0x80000000 - MX51_PAD_EIM_DA4__EIM_DA4 0x80000000 - MX51_PAD_EIM_DA5__EIM_DA5 0x80000000 - MX51_PAD_EIM_DA6__EIM_DA6 0x80000000 - MX51_PAD_EIM_DA7__EIM_DA7 0x80000000 - MX51_PAD_EIM_DA8__EIM_DA8 0x80000000 - MX51_PAD_EIM_DA9__EIM_DA9 0x80000000 - MX51_PAD_EIM_DA10__EIM_DA10 0x80000000 - MX51_PAD_EIM_DA11__EIM_DA11 0x80000000 - MX51_PAD_EIM_DA12__EIM_DA12 0x80000000 - MX51_PAD_EIM_DA13__EIM_DA13 0x80000000 - MX51_PAD_EIM_DA14__EIM_DA14 0x80000000 - MX51_PAD_EIM_DA15__EIM_DA15 0x80000000 - MX51_PAD_EIM_A16__EIM_A16 0x80000000 - MX51_PAD_EIM_A17__EIM_A17 0x80000000 - MX51_PAD_EIM_A18__EIM_A18 0x80000000 - MX51_PAD_EIM_A19__EIM_A19 0x80000000 - MX51_PAD_EIM_A20__EIM_A20 0x80000000 - MX51_PAD_EIM_A21__EIM_A21 0x80000000 - MX51_PAD_EIM_A22__EIM_A22 0x80000000 - MX51_PAD_EIM_A23__EIM_A23 0x80000000 - MX51_PAD_EIM_A24__EIM_A24 0x80000000 - MX51_PAD_EIM_A25__EIM_A25 0x80000000 - MX51_PAD_EIM_A26__EIM_A26 0x80000000 - MX51_PAD_EIM_A27__EIM_A27 0x80000000 - MX51_PAD_EIM_D16__EIM_D16 0x80000000 - MX51_PAD_EIM_D17__EIM_D17 0x80000000 - MX51_PAD_EIM_D18__EIM_D18 0x80000000 - MX51_PAD_EIM_D19__EIM_D19 0x80000000 - MX51_PAD_EIM_D20__EIM_D20 0x80000000 - MX51_PAD_EIM_D21__EIM_D21 0x80000000 - MX51_PAD_EIM_D22__EIM_D22 0x80000000 - MX51_PAD_EIM_D23__EIM_D23 0x80000000 - MX51_PAD_EIM_D24__EIM_D24 0x80000000 - MX51_PAD_EIM_D25__EIM_D25 0x80000000 - MX51_PAD_EIM_D26__EIM_D26 0x80000000 - MX51_PAD_EIM_D27__EIM_D27 0x80000000 - MX51_PAD_EIM_D28__EIM_D28 0x80000000 - MX51_PAD_EIM_D29__EIM_D29 0x80000000 - MX51_PAD_EIM_D30__EIM_D30 0x80000000 - MX51_PAD_EIM_D31__EIM_D31 0x80000000 - MX51_PAD_EIM_OE__EIM_OE 0x80000000 - MX51_PAD_EIM_DTACK__EIM_DTACK 0x80000000 - MX51_PAD_EIM_LBA__EIM_LBA 0x80000000 - MX51_PAD_EIM_CS5__EIM_CS5 0x80000000 /* CS5 */ - >; - }; + pinctrl_weim: weimgrp { + fsl,pins = < + MX51_PAD_EIM_DA0__EIM_DA0 0x80000000 + MX51_PAD_EIM_DA1__EIM_DA1 0x80000000 + MX51_PAD_EIM_DA2__EIM_DA2 0x80000000 + MX51_PAD_EIM_DA3__EIM_DA3 0x80000000 + MX51_PAD_EIM_DA4__EIM_DA4 0x80000000 + MX51_PAD_EIM_DA5__EIM_DA5 0x80000000 + MX51_PAD_EIM_DA6__EIM_DA6 0x80000000 + MX51_PAD_EIM_DA7__EIM_DA7 0x80000000 + MX51_PAD_EIM_DA8__EIM_DA8 0x80000000 + MX51_PAD_EIM_DA9__EIM_DA9 0x80000000 + MX51_PAD_EIM_DA10__EIM_DA10 0x80000000 + MX51_PAD_EIM_DA11__EIM_DA11 0x80000000 + MX51_PAD_EIM_DA12__EIM_DA12 0x80000000 + MX51_PAD_EIM_DA13__EIM_DA13 0x80000000 + MX51_PAD_EIM_DA14__EIM_DA14 0x80000000 + MX51_PAD_EIM_DA15__EIM_DA15 0x80000000 + MX51_PAD_EIM_A16__EIM_A16 0x80000000 + MX51_PAD_EIM_A17__EIM_A17 0x80000000 + MX51_PAD_EIM_A18__EIM_A18 0x80000000 + MX51_PAD_EIM_A19__EIM_A19 0x80000000 + MX51_PAD_EIM_A20__EIM_A20 0x80000000 + MX51_PAD_EIM_A21__EIM_A21 0x80000000 + MX51_PAD_EIM_A22__EIM_A22 0x80000000 + MX51_PAD_EIM_A23__EIM_A23 0x80000000 + MX51_PAD_EIM_A24__EIM_A24 0x80000000 + MX51_PAD_EIM_A25__EIM_A25 0x80000000 + MX51_PAD_EIM_A26__EIM_A26 0x80000000 + MX51_PAD_EIM_A27__EIM_A27 0x80000000 + MX51_PAD_EIM_D16__EIM_D16 0x80000000 + MX51_PAD_EIM_D17__EIM_D17 0x80000000 + MX51_PAD_EIM_D18__EIM_D18 0x80000000 + MX51_PAD_EIM_D19__EIM_D19 0x80000000 + MX51_PAD_EIM_D20__EIM_D20 0x80000000 + MX51_PAD_EIM_D21__EIM_D21 0x80000000 + MX51_PAD_EIM_D22__EIM_D22 0x80000000 + MX51_PAD_EIM_D23__EIM_D23 0x80000000 + MX51_PAD_EIM_D24__EIM_D24 0x80000000 + MX51_PAD_EIM_D25__EIM_D25 0x80000000 + MX51_PAD_EIM_D26__EIM_D26 0x80000000 + MX51_PAD_EIM_D27__EIM_D27 0x80000000 + MX51_PAD_EIM_D28__EIM_D28 0x80000000 + MX51_PAD_EIM_D29__EIM_D29 0x80000000 + MX51_PAD_EIM_D30__EIM_D30 0x80000000 + MX51_PAD_EIM_D31__EIM_D31 0x80000000 + MX51_PAD_EIM_OE__EIM_OE 0x80000000 + MX51_PAD_EIM_DTACK__EIM_DTACK 0x80000000 + MX51_PAD_EIM_LBA__EIM_LBA 0x80000000 + MX51_PAD_EIM_CS5__EIM_CS5 0x80000000 /* CS5 */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx51-eukrea-cpuimx51.dtsi b/arch/arm/boot/dts/nxp/imx/imx51-eukrea-cpuimx51.dtsi index c2a929ba8cebd7..0a150c91d30f7e 100644 --- a/arch/arm/boot/dts/nxp/imx/imx51-eukrea-cpuimx51.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx51-eukrea-cpuimx51.dtsi @@ -44,43 +44,41 @@ tsc2007: tsc2007@49 { }; &iomuxc { - imx51-eukrea { - pinctrl_tsc2007_1: tsc2007grp-1 { - fsl,pins = < - MX51_PAD_GPIO_NAND__GPIO_NAND 0x1f5 - MX51_PAD_NANDF_D8__GPIO4_0 0x1f5 - >; - }; + pinctrl_tsc2007_1: tsc2007-1-grp { + fsl,pins = < + MX51_PAD_GPIO_NAND__GPIO_NAND 0x1f5 + MX51_PAD_NANDF_D8__GPIO4_0 0x1f5 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 - MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 - MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 - MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 - MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 - MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 - MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 - MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 - MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 - MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 - MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 - MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 - MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 - MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 - MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 - MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 - MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 - MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX51_PAD_DI_GP3__FEC_TX_ER 0x80000000 + MX51_PAD_DI2_PIN4__FEC_CRS 0x80000000 + MX51_PAD_DI2_PIN2__FEC_MDC 0x80000000 + MX51_PAD_DI2_PIN3__FEC_MDIO 0x80000000 + MX51_PAD_DI2_DISP_CLK__FEC_RDATA1 0x80000000 + MX51_PAD_DI_GP4__FEC_RDATA2 0x80000000 + MX51_PAD_DISP2_DAT0__FEC_RDATA3 0x80000000 + MX51_PAD_DISP2_DAT1__FEC_RX_ER 0x80000000 + MX51_PAD_DISP2_DAT6__FEC_TDATA1 0x80000000 + MX51_PAD_DISP2_DAT7__FEC_TDATA2 0x80000000 + MX51_PAD_DISP2_DAT8__FEC_TDATA3 0x80000000 + MX51_PAD_DISP2_DAT9__FEC_TX_EN 0x80000000 + MX51_PAD_DISP2_DAT10__FEC_COL 0x80000000 + MX51_PAD_DISP2_DAT11__FEC_RX_CLK 0x80000000 + MX51_PAD_DISP2_DAT12__FEC_RX_DV 0x80000000 + MX51_PAD_DISP2_DAT13__FEC_TX_CLK 0x80000000 + MX51_PAD_DISP2_DAT14__FEC_RDATA0 0x80000000 + MX51_PAD_DISP2_DAT15__FEC_TDATA0 0x80000000 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX51_PAD_SD2_CMD__I2C1_SCL 0x400001ed - MX51_PAD_SD2_CLK__I2C1_SDA 0x400001ed - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX51_PAD_SD2_CMD__I2C1_SCL 0x400001ed + MX51_PAD_SD2_CLK__I2C1_SDA 0x400001ed + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx51-eukrea-mbimxsd51-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx51-eukrea-mbimxsd51-baseboard.dts index aff380e999c7ef..0e0b9a811b966c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx51-eukrea-mbimxsd51-baseboard.dts +++ b/arch/arm/boot/dts/nxp/imx/imx51-eukrea-mbimxsd51-baseboard.dts @@ -112,117 +112,115 @@ tlv320aic23: codec@1a { }; &iomuxc { - imx51-eukrea { - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX51_PAD_AUD3_BB_TXD__AUD3_TXD 0x80000000 - MX51_PAD_AUD3_BB_RXD__AUD3_RXD 0x80000000 - MX51_PAD_AUD3_BB_CK__AUD3_TXC 0x80000000 - MX51_PAD_AUD3_BB_FS__AUD3_TXFS 0x80000000 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX51_PAD_AUD3_BB_TXD__AUD3_TXD 0x80000000 + MX51_PAD_AUD3_BB_RXD__AUD3_RXD 0x80000000 + MX51_PAD_AUD3_BB_CK__AUD3_TXC 0x80000000 + MX51_PAD_AUD3_BB_FS__AUD3_TXFS 0x80000000 + >; + }; - pinctrl_can: cangrp { - fsl,pins = < - MX51_PAD_CSI2_PIXCLK__GPIO4_15 0x80000000 /* nReset */ - MX51_PAD_GPIO1_1__GPIO1_1 0x80000000 /* IRQ */ - >; - }; + pinctrl_can: cangrp { + fsl,pins = < + MX51_PAD_CSI2_PIXCLK__GPIO4_15 0x80000000 /* nReset */ + MX51_PAD_GPIO1_1__GPIO1_1 0x80000000 /* IRQ */ + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 - MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 - MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 - MX51_PAD_CSPI1_SS0__GPIO4_24 0x80000000 /* CS0 */ - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX51_PAD_CSPI1_MISO__ECSPI1_MISO 0x185 + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI 0x185 + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK 0x185 + MX51_PAD_CSPI1_SS0__GPIO4_24 0x80000000 /* CS0 */ + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 - MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 - MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 - MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 - MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 - MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX51_PAD_SD1_CMD__SD1_CMD 0x400020d5 + MX51_PAD_SD1_CLK__SD1_CLK 0x20d5 + MX51_PAD_SD1_DATA0__SD1_DATA0 0x20d5 + MX51_PAD_SD1_DATA1__SD1_DATA1 0x20d5 + MX51_PAD_SD1_DATA2__SD1_DATA2 0x20d5 + MX51_PAD_SD1_DATA3__SD1_DATA3 0x20d5 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 - MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX51_PAD_UART1_RXD__UART1_RXD 0x1c5 + MX51_PAD_UART1_TXD__UART1_TXD 0x1c5 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 - MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX51_PAD_UART3_RXD__UART3_RXD 0x1c5 + MX51_PAD_UART3_TXD__UART3_TXD 0x1c5 + >; + }; - pinctrl_uart3_rtscts: uart3rtsctsgrp { - fsl,pins = < - MX51_PAD_KEY_COL4__UART3_RTS 0x1c5 - MX51_PAD_KEY_COL5__UART3_CTS 0x1c5 - >; - }; + pinctrl_uart3_rtscts: uart3rtsctsgrp { + fsl,pins = < + MX51_PAD_KEY_COL4__UART3_RTS 0x1c5 + MX51_PAD_KEY_COL5__UART3_CTS 0x1c5 + >; + }; - pinctrl_backlight_1: backlightgrp-1 { - fsl,pins = < - MX51_PAD_DI1_D1_CS__GPIO3_4 0x1f5 - >; - }; + pinctrl_backlight_1: backlight1grp { + fsl,pins = < + MX51_PAD_DI1_D1_CS__GPIO3_4 0x1f5 + >; + }; - pinctrl_esdhc1_cd: esdhc1_cd { - fsl,pins = < - MX51_PAD_GPIO1_0__GPIO1_0 0xd5 - >; - }; + pinctrl_esdhc1_cd: esdhc1_cdgrp { + fsl,pins = < + MX51_PAD_GPIO1_0__GPIO1_0 0xd5 + >; + }; - pinctrl_gpiokeys_1: gpiokeysgrp-1 { - fsl,pins = < - MX51_PAD_NANDF_D9__GPIO3_31 0x1f5 - >; - }; + pinctrl_gpiokeys_1: gpiokeys1grp { + fsl,pins = < + MX51_PAD_NANDF_D9__GPIO3_31 0x1f5 + >; + }; - pinctrl_gpioled: gpioledgrp-1 { - fsl,pins = < - MX51_PAD_NANDF_D10__GPIO3_30 0x80000000 - >; - }; + pinctrl_gpioled: gpioled1grp { + fsl,pins = < + MX51_PAD_NANDF_D10__GPIO3_30 0x80000000 + >; + }; - pinctrl_reg_lcd_3v3: reg_lcd_3v3 { - fsl,pins = < - MX51_PAD_CSI1_D9__GPIO3_13 0x1f5 - >; - }; + pinctrl_reg_lcd_3v3: reg_lcd_3v3grp { + fsl,pins = < + MX51_PAD_CSI1_D9__GPIO3_13 0x1f5 + >; + }; - pinctrl_usbh1: usbh1grp { - fsl,pins = < - MX51_PAD_USBH1_CLK__USBH1_CLK 0x1e5 - MX51_PAD_USBH1_DIR__USBH1_DIR 0x1e5 - MX51_PAD_USBH1_NXT__USBH1_NXT 0x1e5 - MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x1e5 - MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x1e5 - MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x1e5 - MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x1e5 - MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x1e5 - MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x1e5 - MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x1e5 - MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x1e5 - MX51_PAD_USBH1_STP__USBH1_STP 0x1e5 - >; - }; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX51_PAD_USBH1_CLK__USBH1_CLK 0x1e5 + MX51_PAD_USBH1_DIR__USBH1_DIR 0x1e5 + MX51_PAD_USBH1_NXT__USBH1_NXT 0x1e5 + MX51_PAD_USBH1_DATA0__USBH1_DATA0 0x1e5 + MX51_PAD_USBH1_DATA1__USBH1_DATA1 0x1e5 + MX51_PAD_USBH1_DATA2__USBH1_DATA2 0x1e5 + MX51_PAD_USBH1_DATA3__USBH1_DATA3 0x1e5 + MX51_PAD_USBH1_DATA4__USBH1_DATA4 0x1e5 + MX51_PAD_USBH1_DATA5__USBH1_DATA5 0x1e5 + MX51_PAD_USBH1_DATA6__USBH1_DATA6 0x1e5 + MX51_PAD_USBH1_DATA7__USBH1_DATA7 0x1e5 + MX51_PAD_USBH1_STP__USBH1_STP 0x1e5 + >; + }; - pinctrl_usbh1_vbus: usbh1-vbusgrp { - fsl,pins = < - MX51_PAD_EIM_CS3__GPIO2_28 0x1f5 - >; - }; + pinctrl_usbh1_vbus: usbh1-vbusgrp { + fsl,pins = < + MX51_PAD_EIM_CS3__GPIO2_28 0x1f5 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx51.dtsi b/arch/arm/boot/dts/nxp/imx/imx51.dtsi index 4efce49022e441..cc88da4d7785c5 100644 --- a/arch/arm/boot/dts/nxp/imx/imx51.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx51.dtsi @@ -399,7 +399,7 @@ gpt: timer@73fa0000 { clock-names = "ipg", "per"; }; - iomuxc: iomuxc@73fa8000 { + iomuxc: pinctrl@73fa8000 { compatible = "fsl,imx51-iomuxc"; reg = <0x73fa8000 0x4000>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-ard.dts b/arch/arm/boot/dts/nxp/imx/imx53-ard.dts index 165e1b00b721ba..e580427660b1de 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-ard.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-ard.dts @@ -101,67 +101,65 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-ard { - pinctrl_hog: hoggrp { - fsl,pins = < - MX53_PAD_GPIO_1__GPIO1_1 0x80000000 - MX53_PAD_GPIO_9__GPIO1_9 0x80000000 - MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 - MX53_PAD_GPIO_10__GPIO4_0 0x80000000 - MX53_PAD_DISP0_DAT16__GPIO5_10 0x80000000 - MX53_PAD_DISP0_DAT17__GPIO5_11 0x80000000 - MX53_PAD_DISP0_DAT18__GPIO5_12 0x80000000 - MX53_PAD_DISP0_DAT19__GPIO5_13 0x80000000 - MX53_PAD_EIM_D16__EMI_WEIM_D_16 0x80000000 - MX53_PAD_EIM_D17__EMI_WEIM_D_17 0x80000000 - MX53_PAD_EIM_D18__EMI_WEIM_D_18 0x80000000 - MX53_PAD_EIM_D19__EMI_WEIM_D_19 0x80000000 - MX53_PAD_EIM_D20__EMI_WEIM_D_20 0x80000000 - MX53_PAD_EIM_D21__EMI_WEIM_D_21 0x80000000 - MX53_PAD_EIM_D22__EMI_WEIM_D_22 0x80000000 - MX53_PAD_EIM_D23__EMI_WEIM_D_23 0x80000000 - MX53_PAD_EIM_D24__EMI_WEIM_D_24 0x80000000 - MX53_PAD_EIM_D25__EMI_WEIM_D_25 0x80000000 - MX53_PAD_EIM_D26__EMI_WEIM_D_26 0x80000000 - MX53_PAD_EIM_D27__EMI_WEIM_D_27 0x80000000 - MX53_PAD_EIM_D28__EMI_WEIM_D_28 0x80000000 - MX53_PAD_EIM_D29__EMI_WEIM_D_29 0x80000000 - MX53_PAD_EIM_D30__EMI_WEIM_D_30 0x80000000 - MX53_PAD_EIM_D31__EMI_WEIM_D_31 0x80000000 - MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 0x80000000 - MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 0x80000000 - MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 0x80000000 - MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 0x80000000 - MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 0x80000000 - MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 0x80000000 - MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 0x80000000 - MX53_PAD_EIM_OE__EMI_WEIM_OE 0x80000000 - MX53_PAD_EIM_RW__EMI_WEIM_RW 0x80000000 - MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 0x80000000 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX53_PAD_GPIO_1__GPIO1_1 0x80000000 + MX53_PAD_GPIO_9__GPIO1_9 0x80000000 + MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 + MX53_PAD_GPIO_10__GPIO4_0 0x80000000 + MX53_PAD_DISP0_DAT16__GPIO5_10 0x80000000 + MX53_PAD_DISP0_DAT17__GPIO5_11 0x80000000 + MX53_PAD_DISP0_DAT18__GPIO5_12 0x80000000 + MX53_PAD_DISP0_DAT19__GPIO5_13 0x80000000 + MX53_PAD_EIM_D16__EMI_WEIM_D_16 0x80000000 + MX53_PAD_EIM_D17__EMI_WEIM_D_17 0x80000000 + MX53_PAD_EIM_D18__EMI_WEIM_D_18 0x80000000 + MX53_PAD_EIM_D19__EMI_WEIM_D_19 0x80000000 + MX53_PAD_EIM_D20__EMI_WEIM_D_20 0x80000000 + MX53_PAD_EIM_D21__EMI_WEIM_D_21 0x80000000 + MX53_PAD_EIM_D22__EMI_WEIM_D_22 0x80000000 + MX53_PAD_EIM_D23__EMI_WEIM_D_23 0x80000000 + MX53_PAD_EIM_D24__EMI_WEIM_D_24 0x80000000 + MX53_PAD_EIM_D25__EMI_WEIM_D_25 0x80000000 + MX53_PAD_EIM_D26__EMI_WEIM_D_26 0x80000000 + MX53_PAD_EIM_D27__EMI_WEIM_D_27 0x80000000 + MX53_PAD_EIM_D28__EMI_WEIM_D_28 0x80000000 + MX53_PAD_EIM_D29__EMI_WEIM_D_29 0x80000000 + MX53_PAD_EIM_D30__EMI_WEIM_D_30 0x80000000 + MX53_PAD_EIM_D31__EMI_WEIM_D_31 0x80000000 + MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 0x80000000 + MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 0x80000000 + MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 0x80000000 + MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 0x80000000 + MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 0x80000000 + MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 0x80000000 + MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 0x80000000 + MX53_PAD_EIM_OE__EMI_WEIM_OE 0x80000000 + MX53_PAD_EIM_RW__EMI_WEIM_RW 0x80000000 + MX53_PAD_EIM_CS1__EMI_WEIM_CS_1 0x80000000 + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_PATA_DATA8__ESDHC1_DAT4 0x1d5 - MX53_PAD_PATA_DATA9__ESDHC1_DAT5 0x1d5 - MX53_PAD_PATA_DATA10__ESDHC1_DAT6 0x1d5 - MX53_PAD_PATA_DATA11__ESDHC1_DAT7 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_PATA_DATA8__ESDHC1_DAT4 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC1_DAT5 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC1_DAT6 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC1_DAT7 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 - MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-kp-ddc.dts b/arch/arm/boot/dts/nxp/imx/imx53-kp-ddc.dts index f6f1163666434c..9c480e4d27cef9 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-kp-ddc.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-kp-ddc.dts @@ -102,38 +102,36 @@ gpio-expander2@21 { }; &iomuxc { - imx53-kp-ddc { - pinctrl_disp: dispgrp { - fsl,pins = < - MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x4 - MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x4 - MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x4 - MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x4 - MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x4 - MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x4 - MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x4 - MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x4 - MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x4 - MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x4 - MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x4 - MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x4 - MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x4 - MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x4 - MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x4 - MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x4 - MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x4 - MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x4 - MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x4 - MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x4 - MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x4 - MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x4 - MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x4 - MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x4 - MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x4 - MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x4 - MX53_PAD_GPIO_1__PWM2_PWMO 0x4 - >; - }; + pinctrl_disp: dispgrp { + fsl,pins = < + MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x4 + MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x4 + MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x4 + MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x4 + MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x4 + MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x4 + MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x4 + MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x4 + MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x4 + MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x4 + MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x4 + MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x4 + MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x4 + MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x4 + MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x4 + MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x4 + MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x4 + MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x4 + MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x4 + MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x4 + MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x4 + MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x4 + MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x4 + MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x4 + MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x4 + MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x4 + MX53_PAD_GPIO_1__PWM2_PWMO 0x4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-kp.dtsi b/arch/arm/boot/dts/nxp/imx/imx53-kp.dtsi index ae5f87b8612d48..ebbd4d93e46065 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-kp.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx53-kp.dtsi @@ -98,56 +98,54 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_kp_common>; - imx53-kp-common { - pinctrl_buzzer: buzzergrp { - fsl,pins = < - MX53_PAD_SD1_DATA3__PWM1_PWMO 0x1e4 - >; - }; + pinctrl_buzzer: buzzergrp { + fsl,pins = < + MX53_PAD_SD1_DATA3__PWM1_PWMO 0x1e4 + >; + }; - pinctrl_gpiobuttons: gpiobuttonsgrp { - fsl,pins = < - MX53_PAD_EIM_RW__GPIO2_26 0x1e4 - MX53_PAD_EIM_D22__GPIO3_22 0x1e4 - >; - }; + pinctrl_gpiobuttons: gpiobuttonsgrp { + fsl,pins = < + MX53_PAD_EIM_RW__GPIO2_26 0x1e4 + MX53_PAD_EIM_D22__GPIO3_22 0x1e4 + >; + }; - pinctrl_kp_common: kpcommongrp { - fsl,pins = < - MX53_PAD_EIM_CS0__GPIO2_23 0x1e4 - MX53_PAD_GPIO_19__GPIO4_5 0x1e4 - MX53_PAD_PATA_DATA6__GPIO2_6 0x1e4 - MX53_PAD_PATA_DATA7__GPIO2_7 0xe0 - MX53_PAD_CSI0_DAT14__GPIO6_0 0x1e4 - MX53_PAD_CSI0_DAT16__GPIO6_2 0x1e4 - MX53_PAD_CSI0_DAT18__GPIO6_4 0x1e4 - MX53_PAD_EIM_D17__GPIO3_17 0x1e4 - MX53_PAD_EIM_D18__GPIO3_18 0x1e4 - MX53_PAD_EIM_D21__GPIO3_21 0x1e4 - MX53_PAD_EIM_D29__GPIO3_29 0x1e4 - MX53_PAD_EIM_DA11__GPIO3_11 0x1e4 - MX53_PAD_EIM_DA13__GPIO3_13 0x1e4 - MX53_PAD_EIM_DA14__GPIO3_14 0x1e4 - MX53_PAD_SD1_DATA0__GPIO1_16 0x1e4 - MX53_PAD_SD1_CMD__GPIO1_18 0x1e4 - MX53_PAD_SD1_CLK__GPIO1_20 0x1e4 - >; - }; + pinctrl_kp_common: kpcommongrp { + fsl,pins = < + MX53_PAD_EIM_CS0__GPIO2_23 0x1e4 + MX53_PAD_GPIO_19__GPIO4_5 0x1e4 + MX53_PAD_PATA_DATA6__GPIO2_6 0x1e4 + MX53_PAD_PATA_DATA7__GPIO2_7 0xe0 + MX53_PAD_CSI0_DAT14__GPIO6_0 0x1e4 + MX53_PAD_CSI0_DAT16__GPIO6_2 0x1e4 + MX53_PAD_CSI0_DAT18__GPIO6_4 0x1e4 + MX53_PAD_EIM_D17__GPIO3_17 0x1e4 + MX53_PAD_EIM_D18__GPIO3_18 0x1e4 + MX53_PAD_EIM_D21__GPIO3_21 0x1e4 + MX53_PAD_EIM_D29__GPIO3_29 0x1e4 + MX53_PAD_EIM_DA11__GPIO3_11 0x1e4 + MX53_PAD_EIM_DA13__GPIO3_13 0x1e4 + MX53_PAD_EIM_DA14__GPIO3_14 0x1e4 + MX53_PAD_SD1_DATA0__GPIO1_16 0x1e4 + MX53_PAD_SD1_CMD__GPIO1_18 0x1e4 + MX53_PAD_SD1_CLK__GPIO1_20 0x1e4 + >; + }; - pinctrl_leds: ledgrp { - fsl,pins = < - MX53_PAD_EIM_EB2__GPIO2_30 0x1d4 - MX53_PAD_EIM_D28__GPIO3_28 0x1d4 - MX53_PAD_EIM_WAIT__GPIO5_0 0x1d4 - >; - }; + pinctrl_leds: ledgrp { + fsl,pins = < + MX53_PAD_EIM_EB2__GPIO2_30 0x1d4 + MX53_PAD_EIM_D28__GPIO3_28 0x1d4 + MX53_PAD_EIM_WAIT__GPIO5_0 0x1d4 + >; + }; - pinctrl_uart4: uart4grp { - fsl,pins = < - MX53_PAD_CSI0_DAT12__UART4_TXD_MUX 0x1e4 - MX53_PAD_CSI0_DAT13__UART4_RXD_MUX 0x1e4 - >; - }; + pinctrl_uart4: uart4grp { + fsl,pins = < + MX53_PAD_CSI0_DAT12__UART4_TXD_MUX 0x1e4 + MX53_PAD_CSI0_DAT13__UART4_RXD_MUX 0x1e4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-m53.dtsi b/arch/arm/boot/dts/nxp/imx/imx53-m53.dtsi index 00b8d7ca41a2c6..df543b4751e0a6 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-m53.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx53-m53.dtsi @@ -77,41 +77,39 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-m53evk { - pinctrl_hog: hoggrp { - fsl,pins = < - MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 - MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 - MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 + MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 + MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX53_PAD_EIM_D16__I2C2_SDA 0xc0000000 - MX53_PAD_EIM_EB2__I2C2_SCL 0xc0000000 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_EIM_D16__I2C2_SDA 0xc0000000 + MX53_PAD_EIM_EB2__I2C2_SCL 0xc0000000 + >; + }; - pinctrl_nand: nandgrp { - fsl,pins = < - MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 - MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 - MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 - MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 - MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 - MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 - MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 - MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 0xa4 - MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 0xa4 - MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 0xa4 - MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 0xa4 - MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 0xa4 - MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 0xa4 - MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 0xa4 - MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 0xa4 - >; - }; + pinctrl_nand: nandgrp { + fsl,pins = < + MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 + MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 + MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 + MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 + MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 + MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 + MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 + MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 0xa4 + MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 0xa4 + MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 0xa4 + MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 0xa4 + MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 0xa4 + MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 0xa4 + MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 0xa4 + MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 0xa4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-m53evk.dts b/arch/arm/boot/dts/nxp/imx/imx53-m53evk.dts index ba0c62994f75d0..eb3d6630539506 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-m53evk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-m53evk.dts @@ -156,155 +156,153 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-m53evk { - pinctrl_usb: usbgrp { - fsl,pins = < - MX53_PAD_GPIO_2__GPIO1_2 0x80000000 - MX53_PAD_GPIO_3__USBOH3_USBH1_OC 0x80000000 - >; - }; + pinctrl_usb: usbgrp { + fsl,pins = < + MX53_PAD_GPIO_2__GPIO1_2 0x80000000 + MX53_PAD_GPIO_3__USBOH3_USBH1_OC 0x80000000 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX53_PAD_GPIO_4__GPIO1_4 0x000b0 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX53_PAD_GPIO_4__GPIO1_4 0x000b0 + >; + }; - led_pin_gpio: led_gpio { - fsl,pins = < - MX53_PAD_PATA_DATA8__GPIO2_8 0x80000000 - MX53_PAD_PATA_DATA9__GPIO2_9 0x80000000 - >; - }; + led_pin_gpio: ledgpiogrp { + fsl,pins = < + MX53_PAD_PATA_DATA8__GPIO2_8 0x80000000 + MX53_PAD_PATA_DATA9__GPIO2_9 0x80000000 + >; + }; - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC 0x80000000 - MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD 0x80000000 - MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS 0x80000000 - MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD 0x80000000 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_SD2_DATA3__AUDMUX_AUD4_TXC 0x80000000 + MX53_PAD_SD2_DATA2__AUDMUX_AUD4_TXD 0x80000000 + MX53_PAD_SD2_DATA1__AUDMUX_AUD4_TXFS 0x80000000 + MX53_PAD_SD2_DATA0__AUDMUX_AUD4_RXD 0x80000000 + >; + }; - pinctrl_can1: can1grp { - fsl,pins = < - MX53_PAD_GPIO_7__CAN1_TXCAN 0x80000000 - MX53_PAD_GPIO_8__CAN1_RXCAN 0x80000000 - >; - }; + pinctrl_can1: can1grp { + fsl,pins = < + MX53_PAD_GPIO_7__CAN1_TXCAN 0x80000000 + MX53_PAD_GPIO_8__CAN1_RXCAN 0x80000000 + >; + }; - pinctrl_can2: can2grp { - fsl,pins = < - MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 - MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 - >; - }; + pinctrl_can2: can2grp { + fsl,pins = < + MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 + MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX53_PAD_EIM_D21__I2C1_SCL 0xc0000000 - MX53_PAD_EIM_D28__I2C1_SDA 0xc0000000 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_EIM_D21__I2C1_SCL 0xc0000000 + MX53_PAD_EIM_D28__I2C1_SDA 0xc0000000 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 - MX53_PAD_GPIO_5__I2C3_SCL 0xc0000000 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 + MX53_PAD_GPIO_5__I2C3_SCL 0xc0000000 + >; + }; - pinctrl_ipu_disp1: ipudisp1grp { - fsl,pins = < - MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x5 - MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x5 - MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x5 - MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x5 - MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x5 - MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x5 - MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x5 - MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x5 - MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x5 - MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x5 - MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x5 - MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x5 - MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x5 - MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x5 - MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x5 - MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x5 - MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x5 - MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x5 - MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x5 - MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x5 - MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x5 - MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x5 - MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x5 - MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x5 - MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x5 - MX53_PAD_EIM_DA13__IPU_DI1_D0_CS 0x5 - MX53_PAD_EIM_DA14__IPU_DI1_D1_CS 0x5 - MX53_PAD_EIM_DA15__IPU_DI1_PIN1 0x5 - MX53_PAD_EIM_DA11__IPU_DI1_PIN2 0x5 - MX53_PAD_EIM_DA12__IPU_DI1_PIN3 0x5 - MX53_PAD_EIM_A25__IPU_DI1_PIN12 0x5 - MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x5 - >; - }; + pinctrl_ipu_disp1: ipudisp1grp { + fsl,pins = < + MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x5 + MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x5 + MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x5 + MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x5 + MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x5 + MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x5 + MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x5 + MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x5 + MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x5 + MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x5 + MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x5 + MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x5 + MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x5 + MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x5 + MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x5 + MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x5 + MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x5 + MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x5 + MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x5 + MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x5 + MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x5 + MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x5 + MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x5 + MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x5 + MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x5 + MX53_PAD_EIM_DA13__IPU_DI1_D0_CS 0x5 + MX53_PAD_EIM_DA14__IPU_DI1_D1_CS 0x5 + MX53_PAD_EIM_DA15__IPU_DI1_PIN1 0x5 + MX53_PAD_EIM_DA11__IPU_DI1_PIN2 0x5 + MX53_PAD_EIM_DA12__IPU_DI1_PIN3 0x5 + MX53_PAD_EIM_A25__IPU_DI1_PIN12 0x5 + MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x5 + >; + }; - pinctrl_pwm1: pwm1grp { - fsl,pins = < - MX53_PAD_DISP0_DAT8__PWM1_PWMO 0x5 - >; - }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX53_PAD_DISP0_DAT8__PWM1_PWMO 0x5 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 - MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 - MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 - MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 - MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 - MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 + MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-m53menlo.dts b/arch/arm/boot/dts/nxp/imx/imx53-m53menlo.dts index 558751e730f3e9..6210673f93bea6 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-m53menlo.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-m53menlo.dts @@ -278,186 +278,184 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-m53evk { - hoggrp { - fsl,pins = < - MX53_PAD_GPIO_19__CCM_CLKO 0x1e4 - MX53_PAD_CSI0_DATA_EN__GPIO5_20 0x1e4 - MX53_PAD_CSI0_DAT4__GPIO5_22 0x1e4 - MX53_PAD_CSI0_DAT5__GPIO5_23 0x1c4 - MX53_PAD_CSI0_DAT6__GPIO5_24 0x1e4 - MX53_PAD_CSI0_DAT7__GPIO5_25 0x1e4 - MX53_PAD_CSI0_DAT8__GPIO5_26 0x1e4 - MX53_PAD_CSI0_DAT9__GPIO5_27 0x1c4 - MX53_PAD_CSI0_DAT10__GPIO5_28 0x1e4 - MX53_PAD_CSI0_DAT11__GPIO5_29 0x1e4 - MX53_PAD_PATA_DATA11__GPIO2_11 0x1e4 - MX53_PAD_EIM_D24__GPIO3_24 0x1e4 - MX53_PAD_EIM_D25__GPIO3_25 0x1e4 - MX53_PAD_EIM_D29__GPIO3_29 0x1e4 - MX53_PAD_CSI0_PIXCLK__GPIO5_18 0x1e4 - MX53_PAD_CSI0_VSYNC__GPIO5_21 0x1e4 - MX53_PAD_CSI0_DAT18__GPIO6_4 0x1c4 - MX53_PAD_PATA_DATA8__GPIO2_8 0x1e4 - >; - }; + hoggrp { + fsl,pins = < + MX53_PAD_GPIO_19__CCM_CLKO 0x1e4 + MX53_PAD_CSI0_DATA_EN__GPIO5_20 0x1e4 + MX53_PAD_CSI0_DAT4__GPIO5_22 0x1e4 + MX53_PAD_CSI0_DAT5__GPIO5_23 0x1c4 + MX53_PAD_CSI0_DAT6__GPIO5_24 0x1e4 + MX53_PAD_CSI0_DAT7__GPIO5_25 0x1e4 + MX53_PAD_CSI0_DAT8__GPIO5_26 0x1e4 + MX53_PAD_CSI0_DAT9__GPIO5_27 0x1c4 + MX53_PAD_CSI0_DAT10__GPIO5_28 0x1e4 + MX53_PAD_CSI0_DAT11__GPIO5_29 0x1e4 + MX53_PAD_PATA_DATA11__GPIO2_11 0x1e4 + MX53_PAD_EIM_D24__GPIO3_24 0x1e4 + MX53_PAD_EIM_D25__GPIO3_25 0x1e4 + MX53_PAD_EIM_D29__GPIO3_29 0x1e4 + MX53_PAD_CSI0_PIXCLK__GPIO5_18 0x1e4 + MX53_PAD_CSI0_VSYNC__GPIO5_21 0x1e4 + MX53_PAD_CSI0_DAT18__GPIO6_4 0x1c4 + MX53_PAD_PATA_DATA8__GPIO2_8 0x1e4 + >; + }; - pinctrl_led: ledgrp { - fsl,pins = < - MX53_PAD_CSI0_DAT15__GPIO6_1 0x1c4 - MX53_PAD_CSI0_DAT16__GPIO6_2 0x1c4 - >; - }; + pinctrl_led: ledgrp { + fsl,pins = < + MX53_PAD_CSI0_DAT15__GPIO6_1 0x1c4 + MX53_PAD_CSI0_DAT16__GPIO6_2 0x1c4 + >; + }; - pinctrl_beeper: beepergrp { - fsl,pins = < - MX53_PAD_CSI0_DAT17__GPIO6_3 0x1c4 - >; - }; + pinctrl_beeper: beepergrp { + fsl,pins = < + MX53_PAD_CSI0_DAT17__GPIO6_3 0x1c4 + >; + }; - pinctrl_can1: can1grp { - fsl,pins = < - MX53_PAD_GPIO_7__CAN1_TXCAN 0x1c4 - MX53_PAD_GPIO_8__CAN1_RXCAN 0x1c4 - >; - }; + pinctrl_can1: can1grp { + fsl,pins = < + MX53_PAD_GPIO_7__CAN1_TXCAN 0x1c4 + MX53_PAD_GPIO_8__CAN1_RXCAN 0x1c4 + >; + }; - pinctrl_can2: can2grp { - fsl,pins = < - MX53_PAD_KEY_COL4__CAN2_TXCAN 0x1e4 - MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x1c4 - >; - }; + pinctrl_can2: can2grp { + fsl,pins = < + MX53_PAD_KEY_COL4__CAN2_TXCAN 0x1e4 + MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x1c4 + >; + }; - pinctrl_display_gpio: display-gpiogrp { - fsl,pins = < - MX53_PAD_CSI0_DAT12__GPIO5_30 0x1c4 /* Reset */ - MX53_PAD_CSI0_MCLK__GPIO5_19 0x1e4 /* Int-K */ - MX53_PAD_CSI0_DAT13__GPIO5_31 0x1c4 /* Int-I */ + pinctrl_display_gpio: display-gpiogrp { + fsl,pins = < + MX53_PAD_CSI0_DAT12__GPIO5_30 0x1c4 /* Reset */ + MX53_PAD_CSI0_MCLK__GPIO5_19 0x1e4 /* Int-K */ + MX53_PAD_CSI0_DAT13__GPIO5_31 0x1c4 /* Int-I */ - MX53_PAD_CSI0_DAT14__GPIO6_0 0x1c4 /* Power down */ - >; - }; + MX53_PAD_CSI0_DAT14__GPIO6_0 0x1c4 /* Power down */ + >; + }; - pinctrl_edt_ft5x06: edt-ft5x06grp { - fsl,pins = < - MX53_PAD_PATA_DATA9__GPIO2_9 0x1e4 /* Reset */ - MX53_PAD_CSI0_DAT19__GPIO6_5 0x1c4 /* Interrupt */ - MX53_PAD_PATA_DATA10__GPIO2_10 0x1e4 /* Wake */ - >; - }; + pinctrl_edt_ft5x06: edt-ft5x06grp { + fsl,pins = < + MX53_PAD_PATA_DATA9__GPIO2_9 0x1e4 /* Reset */ + MX53_PAD_CSI0_DAT19__GPIO6_5 0x1c4 /* Interrupt */ + MX53_PAD_PATA_DATA10__GPIO2_10 0x1e4 /* Wake */ + >; + }; - pinctrl_ecspi2: ecspi2grp { - fsl,pins = < - MX53_PAD_EIM_CS0__ECSPI2_SCLK 0xe4 - MX53_PAD_EIM_OE__ECSPI2_MISO 0xe4 - MX53_PAD_EIM_CS1__ECSPI2_MOSI 0xe4 - MX53_PAD_EIM_RW__GPIO2_26 0xe4 - MX53_PAD_EIM_LBA__GPIO2_27 0xe4 - >; - }; + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX53_PAD_EIM_CS0__ECSPI2_SCLK 0xe4 + MX53_PAD_EIM_OE__ECSPI2_MISO 0xe4 + MX53_PAD_EIM_CS1__ECSPI2_MOSI 0xe4 + MX53_PAD_EIM_RW__GPIO2_26 0xe4 + MX53_PAD_EIM_LBA__GPIO2_27 0xe4 + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1e4 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1e4 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1e4 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1e4 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1e4 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1e4 - MX53_PAD_GPIO_1__GPIO1_1 0x1c4 - MX53_PAD_GPIO_9__GPIO1_9 0x1e4 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1e4 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1e4 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1e4 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1e4 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1e4 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1e4 + MX53_PAD_GPIO_1__GPIO1_1 0x1c4 + MX53_PAD_GPIO_9__GPIO1_9 0x1e4 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x1e4 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x1e4 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x1e4 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x1e4 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x1e4 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x1e4 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x1e4 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x1c4 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x1e4 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x1e4 - MX53_PAD_PATA_DA_1__GPIO7_7 0x1e4 - MX53_PAD_EIM_EB3__GPIO2_31 0x1e4 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x1e4 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x1e4 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x1e4 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x1e4 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x1e4 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x1e4 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x1e4 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x1c4 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x1e4 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x1e4 + MX53_PAD_PATA_DA_1__GPIO7_7 0x1e4 + MX53_PAD_EIM_EB3__GPIO2_31 0x1e4 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX53_PAD_EIM_D21__I2C1_SCL 0x400001e4 - MX53_PAD_EIM_D28__I2C1_SDA 0x400001e4 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_EIM_D21__I2C1_SCL 0x400001e4 + MX53_PAD_EIM_D28__I2C1_SDA 0x400001e4 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX53_PAD_GPIO_6__I2C3_SDA 0x400001e4 - MX53_PAD_GPIO_5__I2C3_SCL 0x400001e4 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_6__I2C3_SDA 0x400001e4 + MX53_PAD_GPIO_5__I2C3_SCL 0x400001e4 + >; + }; - pinctrl_lvds0: lvds0grp { - /* LVDS pins only have pin mux configuration */ - fsl,pins = < - MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 - MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 - MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 - MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 - MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 - >; - }; + pinctrl_lvds0: lvds0grp { + /* LVDS pins only have pin mux configuration */ + fsl,pins = < + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 + >; + }; - pinctrl_power_button: powerbutgrp { - fsl,pins = < - MX53_PAD_SD2_DATA0__GPIO1_15 0x1e4 - >; - }; + pinctrl_power_button: powerbutgrp { + fsl,pins = < + MX53_PAD_SD2_DATA0__GPIO1_15 0x1e4 + >; + }; - pinctrl_power_out: poweroutgrp { - fsl,pins = < - MX53_PAD_SD2_DATA2__GPIO1_13 0x1e4 - >; - }; + pinctrl_power_out: poweroutgrp { + fsl,pins = < + MX53_PAD_SD2_DATA2__GPIO1_13 0x1e4 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 - MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 - MX53_PAD_PATA_IORDY__UART1_RTS 0x1e4 - MX53_PAD_PATA_RESET_B__UART1_CTS 0x1e4 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + MX53_PAD_PATA_IORDY__UART1_RTS 0x1e4 + MX53_PAD_PATA_RESET_B__UART1_CTS 0x1e4 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 - MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 - MX53_PAD_PATA_DIOR__UART2_RTS 0x1e4 - MX53_PAD_PATA_INTRQ__UART2_CTS 0x1e4 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 + MX53_PAD_PATA_DIOR__UART2_RTS 0x1e4 + MX53_PAD_PATA_INTRQ__UART2_CTS 0x1e4 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 - MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 - MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 + >; + }; - pinctrl_usb: usbgrp { - fsl,pins = < - MX53_PAD_GPIO_2__GPIO1_2 0x1c4 - MX53_PAD_GPIO_3__USBOH3_USBH1_OC 0x1c4 - MX53_PAD_GPIO_4__GPIO1_4 0x1c4 - MX53_PAD_GPIO_18__GPIO7_13 0x1c4 - >; - }; + pinctrl_usb: usbgrp { + fsl,pins = < + MX53_PAD_GPIO_2__GPIO1_2 0x1c4 + MX53_PAD_GPIO_3__USBOH3_USBH1_OC 0x1c4 + MX53_PAD_GPIO_4__GPIO1_4 0x1c4 + MX53_PAD_GPIO_18__GPIO7_13 0x1c4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-mba53.dts b/arch/arm/boot/dts/nxp/imx/imx53-mba53.dts index 0d336cbdb4513e..c14eb7280f09e6 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-mba53.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-mba53.dts @@ -75,71 +75,65 @@ &ldb { }; &iomuxc { - lvds1 { - pinctrl_lvds1_1: lvds1-grp1 { - fsl,pins = < - MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 - MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 - MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 - MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 - MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 - >; - }; + pinctrl_lvds1_1: lvds1-1-grp { + fsl,pins = < + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 + >; + }; - pinctrl_lvds1_2: lvds1-grp2 { - fsl,pins = < - MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 0x80000000 - MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 0x80000000 - MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 0x80000000 - MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 0x80000000 - MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 0x80000000 - >; - }; + pinctrl_lvds1_2: lvds1-2-grp { + fsl,pins = < + MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 0x80000000 + MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 0x80000000 + MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 0x80000000 + MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 0x80000000 + MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 0x80000000 + >; }; - disp1 { - pinctrl_disp1_1: disp1-grp1 { - fsl,pins = < - MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x80000000 /* DISP1_CLK */ - MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x80000000 /* DISP1_DRDY */ - MX53_PAD_EIM_D23__IPU_DI1_PIN2 0x80000000 /* DISP1_HSYNC */ - MX53_PAD_EIM_EB3__IPU_DI1_PIN3 0x80000000 /* DISP1_VSYNC */ - MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x80000000 - MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x80000000 - MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x80000000 - MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x80000000 - MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x80000000 - MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x80000000 - MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x80000000 - MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x80000000 - MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x80000000 - MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x80000000 - MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x80000000 - MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x80000000 - MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x80000000 - MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x80000000 - MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x80000000 - MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x80000000 - MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x80000000 - MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x80000000 - MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x80000000 - MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x80000000 - MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x80000000 - MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x80000000 - MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x80000000 - MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x80000000 - >; - }; + pinctrl_disp1_1: disp1-1-grp { + fsl,pins = < + MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x80000000 /* DISP1_CLK */ + MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x80000000 /* DISP1_DRDY */ + MX53_PAD_EIM_D23__IPU_DI1_PIN2 0x80000000 /* DISP1_HSYNC */ + MX53_PAD_EIM_EB3__IPU_DI1_PIN3 0x80000000 /* DISP1_VSYNC */ + MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x80000000 + MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x80000000 + MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x80000000 + MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x80000000 + MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x80000000 + MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x80000000 + MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x80000000 + MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x80000000 + MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x80000000 + MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x80000000 + MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x80000000 + MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x80000000 + MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x80000000 + MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x80000000 + MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x80000000 + MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x80000000 + MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x80000000 + MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x80000000 + MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x80000000 + MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x80000000 + MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x80000000 + MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x80000000 + MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x80000000 + MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x80000000 + >; }; - tve { - pinctrl_vga_sync_1: vgasync-grp1 { - fsl,pins = < - /* VGA_VSYNC, HSYNC with max drive strength */ - MX53_PAD_EIM_CS1__IPU_DI1_PIN6 0xe6 - MX53_PAD_EIM_DA15__IPU_DI1_PIN4 0xe6 - >; - }; + pinctrl_vga_sync_1: vgasync-1-grp { + fsl,pins = < + /* VGA_VSYNC, HSYNC with max drive strength */ + MX53_PAD_EIM_CS1__IPU_DI1_PIN6 0xe6 + MX53_PAD_EIM_DA15__IPU_DI1_PIN4 0xe6 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-qsb-common.dtsi b/arch/arm/boot/dts/nxp/imx/imx53-qsb-common.dtsi index 05d7a462ea25a7..1869ad86baf202 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-qsb-common.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx53-qsb-common.dtsi @@ -170,157 +170,155 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-qsb { - pinctrl_hog: hoggrp { - fsl,pins = < - MX53_PAD_GPIO_8__GPIO1_8 0x80000000 - MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 - MX53_PAD_PATA_DATA15__GPIO2_15 0x80000000 - MX53_PAD_EIM_DA11__GPIO3_11 0x80000000 - MX53_PAD_EIM_DA12__GPIO3_12 0x80000000 - MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 - MX53_PAD_PATA_DA_2__GPIO7_8 0x80000000 - MX53_PAD_GPIO_16__GPIO7_11 0x80000000 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX53_PAD_GPIO_8__GPIO1_8 0x80000000 + MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 + MX53_PAD_PATA_DATA15__GPIO2_15 0x80000000 + MX53_PAD_EIM_DA11__GPIO3_11 0x80000000 + MX53_PAD_EIM_DA12__GPIO3_12 0x80000000 + MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 + MX53_PAD_PATA_DA_2__GPIO7_8 0x80000000 + MX53_PAD_GPIO_16__GPIO7_11 0x80000000 + >; + }; - led_pin_gpio7_7: led_gpio7_7 { - fsl,pins = < - MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 - >; - }; + led_pin_gpio7_7: led_gpio7-7-grp { + fsl,pins = < + MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 + >; + }; - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 - MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 - MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 - MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; - pinctrl_codec: codecgrp { - fsl,pins = < - MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x1c4 - >; - }; + pinctrl_codec: codecgrp { + fsl,pins = < + MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x1c4 + >; + }; - pinctrl_display_power: displaypowergrp { - fsl,pins = < - MX53_PAD_EIM_D24__GPIO3_24 0x1e4 - >; - }; + pinctrl_display_power: displaypowergrp { + fsl,pins = < + MX53_PAD_EIM_D24__GPIO3_24 0x1e4 + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - MX53_PAD_EIM_DA13__GPIO3_13 0xe4 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + MX53_PAD_EIM_DA13__GPIO3_13 0xe4 + >; + }; - pinctrl_esdhc3: esdhc3grp { - fsl,pins = < - MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 - MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 - MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 - MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 - MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 - MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 - MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 - MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 - MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 - MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 - >; - }; + pinctrl_esdhc3: esdhc3grp { + fsl,pins = < + MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 + MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 + MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 + MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 + MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 + MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 + MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x4 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x1fc - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x180 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x180 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x180 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x180 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x180 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x4 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x4 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x4 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x4 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x1fc + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x180 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x180 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x180 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x180 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x180 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x4 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x4 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x4 + >; + }; - /* open drain */ - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX53_PAD_CSI0_DAT8__I2C1_SDA 0x400001ec - MX53_PAD_CSI0_DAT9__I2C1_SCL 0x400001ec - >; - }; + /* open drain */ + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT8__I2C1_SDA 0x400001ec + MX53_PAD_CSI0_DAT9__I2C1_SCL 0x400001ec + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 - MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; - pinctrl_ipu_disp0: ipudisp0grp { - fsl,pins = < - MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 - MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 - MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 - MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 - MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 - MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 - MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 - MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 - MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 - MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 - MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 - MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 - MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 - MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 - MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 - MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 - MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 - MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 - MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 - MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 - MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 - MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 - MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 - MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 - MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 - MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 - MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 - MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 - >; - }; + pinctrl_ipu_disp0: ipudisp0grp { + fsl,pins = < + MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 + MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 + MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 + MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 + MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 + MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 + MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 + MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 + MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 + MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 + MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 + MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 + MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 + MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 + MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 + MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 + MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 + MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 + MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 + MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 + MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 + MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 + MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 + MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 + MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 + MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 + MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 + MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 + >; + }; - pinctrl_pwm2: pwm2grp { - fsl,pins = < - MX53_PAD_GPIO_1__PWM2_PWMO 0x5 - >; - }; + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX53_PAD_GPIO_1__PWM2_PWMO 0x5 + >; + }; - pinctrl_vga_sync: vgasync-grp { - fsl,pins = < - /* VGA_HSYNC, VSYNC with max drive strength */ - MX53_PAD_EIM_OE__IPU_DI1_PIN7 0xe6 - MX53_PAD_EIM_RW__IPU_DI1_PIN8 0xe6 - >; - }; + pinctrl_vga_sync: vgasync-grp { + fsl,pins = < + /* VGA_HSYNC, VSYNC with max drive strength */ + MX53_PAD_EIM_OE__IPU_DI1_PIN7 0xe6 + MX53_PAD_EIM_RW__IPU_DI1_PIN8 0xe6 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 - MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-qsrb.dts b/arch/arm/boot/dts/nxp/imx/imx53-qsrb.dts index 1bbf24ad308a18..2f06ad61a76650 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-qsrb.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-qsrb.dts @@ -13,12 +13,10 @@ / { }; &iomuxc { - imx53-qsrb { - pinctrl_pmic: pmicgrp { - fsl,pins = < - MX53_PAD_CSI0_DAT5__GPIO5_23 0x1c4 /* IRQ */ - >; - }; + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX53_PAD_CSI0_DAT5__GPIO5_23 0x1c4 /* IRQ */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-smd.dts b/arch/arm/boot/dts/nxp/imx/imx53-smd.dts index 55435dfdff8aad..386371c816f4d1 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-smd.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-smd.dts @@ -98,140 +98,138 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-smd { - pinctrl_hog: hoggrp { - fsl,pins = < - MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 - MX53_PAD_PATA_DATA15__GPIO2_15 0x80000000 - MX53_PAD_EIM_EB2__GPIO2_30 0x80000000 - MX53_PAD_EIM_DA13__GPIO3_13 0x80000000 - MX53_PAD_EIM_D19__GPIO3_19 0x80000000 - MX53_PAD_KEY_ROW2__GPIO4_11 0x80000000 - MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 + MX53_PAD_PATA_DATA15__GPIO2_15 0x80000000 + MX53_PAD_EIM_EB2__GPIO2_30 0x80000000 + MX53_PAD_EIM_DA13__GPIO3_13 0x80000000 + MX53_PAD_EIM_D19__GPIO3_19 0x80000000 + MX53_PAD_KEY_ROW2__GPIO4_11 0x80000000 + MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 - MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 - MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + >; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + >; + }; - pinctrl_esdhc2: esdhc2grp { - fsl,pins = < - MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 - MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 - MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 - MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 - MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 - MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 - >; - }; + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 + MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 + MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 + MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 + MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 + MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 + >; + }; - pinctrl_esdhc3: esdhc3grp { - fsl,pins = < - MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 - MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 - MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 - MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 - MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 - MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 - MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 - MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 - MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 - MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 - >; - }; + pinctrl_esdhc3: esdhc3grp { + fsl,pins = < + MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 + MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 + MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 + MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 + MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 + MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 + MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX53_PAD_CSI0_DAT8__I2C1_SDA 0xc0000000 - MX53_PAD_CSI0_DAT9__I2C1_SCL 0xc0000000 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT8__I2C1_SDA 0xc0000000 + MX53_PAD_CSI0_DAT9__I2C1_SCL 0xc0000000 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 - MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; - pinctrl_ipu_csi0: ipucsi0grp { - fsl,pins = < - MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 0x1c4 - MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 0x1c4 - MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 0x1c4 - MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 0x1c4 - MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 0x1c4 - MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 0x1c4 - MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 0x1c4 - MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 0x1c4 - MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK 0x1e4 - MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC 0x1e4 - MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC 0x1e4 - MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN 0x1e4 - >; - }; + pinctrl_ipu_csi0: ipucsi0grp { + fsl,pins = < + MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12 0x1c4 + MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13 0x1c4 + MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14 0x1c4 + MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15 0x1c4 + MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16 0x1c4 + MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17 0x1c4 + MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18 0x1c4 + MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19 0x1c4 + MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK 0x1e4 + MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC 0x1e4 + MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC 0x1e4 + MX53_PAD_CSI0_DATA_EN__IPU_CSI0_DATA_EN 0x1e4 + >; + }; - pinctrl_ov5642: ov5642grp { - fsl,pins = < - MX53_PAD_NANDF_WP_B__GPIO6_9 0x1e4 - MX53_PAD_NANDF_RB0__GPIO6_10 0x1e4 - MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x1c4 - >; - }; + pinctrl_ov5642: ov5642grp { + fsl,pins = < + MX53_PAD_NANDF_WP_B__GPIO6_9 0x1e4 + MX53_PAD_NANDF_RB0__GPIO6_10 0x1e4 + MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x1c4 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 - MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX 0x1e4 + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX 0x1e4 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 - MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 - MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 - MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 - MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 + MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-tqma53.dtsi b/arch/arm/boot/dts/nxp/imx/imx53-tqma53.dtsi index c34ee84bd71675..0f0245df380fc0 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-tqma53.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx53-tqma53.dtsi @@ -61,144 +61,142 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-tqma53 { - pinctrl_hog: hoggrp { - fsl,pins = < - MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 /* SSI_MCLK */ - MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 /* LCD_BLT_EN */ - MX53_PAD_PATA_DA_2__GPIO7_8 0x80000000 /* LCD_RESET */ - MX53_PAD_PATA_DATA5__GPIO2_5 0x80000000 /* LCD_POWER */ - MX53_PAD_PATA_DATA6__GPIO2_6 0x80000000 /* PMIC_INT */ - MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 /* CSI_RST */ - MX53_PAD_PATA_DATA15__GPIO2_15 0x80000000 /* CSI_PWDN */ - MX53_PAD_GPIO_19__GPIO4_5 0x80000000 /* #SYSTEM_DOWN */ - MX53_PAD_GPIO_3__GPIO1_3 0x80000000 - MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 /* #PHY_RESET */ - MX53_PAD_GPIO_1__PWM2_PWMO 0x80000000 /* LCD_CONTRAST */ - >; - }; - - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 - MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 - MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 - MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 - >; - }; - - pinctrl_can1: can1grp { - fsl,pins = < - MX53_PAD_KEY_COL2__CAN1_TXCAN 0x80000000 - MX53_PAD_KEY_ROW2__CAN1_RXCAN 0x80000000 - >; - }; - - pinctrl_can2: can2grp { - fsl,pins = < - MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 - MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 - >; - }; - - pinctrl_cspi: cspigrp { - fsl,pins = < - MX53_PAD_SD1_DATA0__CSPI_MISO 0x1d5 - MX53_PAD_SD1_CMD__CSPI_MOSI 0x1d5 - MX53_PAD_SD1_CLK__CSPI_SCLK 0x1d5 - >; - }; - - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 - MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 - MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 - >; - }; - - pinctrl_esdhc2: esdhc2grp { - fsl,pins = < - MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 - MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 - MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 - MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 - MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 - MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 - >; - }; - - pinctrl_esdhc2_cdwp: esdhc2cdwp { - fsl,pins = < - MX53_PAD_GPIO_4__GPIO1_4 0x80000000 /* SD2_CD */ - MX53_PAD_GPIO_2__GPIO1_2 0x80000000 /* SD2_WP */ - >; - }; - - pinctrl_esdhc3: esdhc3grp { - fsl,pins = < - MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 - MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 - MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 - MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 - MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 - MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 - MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 - MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 - MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 - MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 - >; - }; - - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - >; - }; - - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 - MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 - >; - }; - - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 - MX53_PAD_GPIO_5__I2C3_SCL 0xc0000000 - >; - }; - - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 - MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 - >; - }; - - pinctrl_uart2: uart2grp { - fsl,pins = < - MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 - MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 - >; - }; - - pinctrl_uart3: uart3grp { - fsl,pins = < - MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 - MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK 0x80000000 /* SSI_MCLK */ + MX53_PAD_PATA_DA_1__GPIO7_7 0x80000000 /* LCD_BLT_EN */ + MX53_PAD_PATA_DA_2__GPIO7_8 0x80000000 /* LCD_RESET */ + MX53_PAD_PATA_DATA5__GPIO2_5 0x80000000 /* LCD_POWER */ + MX53_PAD_PATA_DATA6__GPIO2_6 0x80000000 /* PMIC_INT */ + MX53_PAD_PATA_DATA14__GPIO2_14 0x80000000 /* CSI_RST */ + MX53_PAD_PATA_DATA15__GPIO2_15 0x80000000 /* CSI_PWDN */ + MX53_PAD_GPIO_19__GPIO4_5 0x80000000 /* #SYSTEM_DOWN */ + MX53_PAD_GPIO_3__GPIO1_3 0x80000000 + MX53_PAD_PATA_DA_0__GPIO7_6 0x80000000 /* #PHY_RESET */ + MX53_PAD_GPIO_1__PWM2_PWMO 0x80000000 /* LCD_CONTRAST */ + >; + }; + + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; + + pinctrl_can1: can1grp { + fsl,pins = < + MX53_PAD_KEY_COL2__CAN1_TXCAN 0x80000000 + MX53_PAD_KEY_ROW2__CAN1_RXCAN 0x80000000 + >; + }; + + pinctrl_can2: can2grp { + fsl,pins = < + MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 + MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 + >; + }; + + pinctrl_cspi: cspigrp { + fsl,pins = < + MX53_PAD_SD1_DATA0__CSPI_MISO 0x1d5 + MX53_PAD_SD1_CMD__CSPI_MOSI 0x1d5 + MX53_PAD_SD1_CLK__CSPI_SCLK 0x1d5 + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + >; + }; + + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 + MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 + MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 + MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 + MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 + MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 + >; + }; + + pinctrl_esdhc2_cdwp: esdhc2cdwpgrp { + fsl,pins = < + MX53_PAD_GPIO_4__GPIO1_4 0x80000000 /* SD2_CD */ + MX53_PAD_GPIO_2__GPIO1_2 0x80000000 /* SD2_WP */ + >; + }; + + pinctrl_esdhc3: esdhc3grp { + fsl,pins = < + MX53_PAD_PATA_DATA8__ESDHC3_DAT0 0x1d5 + MX53_PAD_PATA_DATA9__ESDHC3_DAT1 0x1d5 + MX53_PAD_PATA_DATA10__ESDHC3_DAT2 0x1d5 + MX53_PAD_PATA_DATA11__ESDHC3_DAT3 0x1d5 + MX53_PAD_PATA_DATA0__ESDHC3_DAT4 0x1d5 + MX53_PAD_PATA_DATA1__ESDHC3_DAT5 0x1d5 + MX53_PAD_PATA_DATA2__ESDHC3_DAT6 0x1d5 + MX53_PAD_PATA_DATA3__ESDHC3_DAT7 0x1d5 + MX53_PAD_PATA_RESET_B__ESDHC3_CMD 0x1d5 + MX53_PAD_PATA_IORDY__ESDHC3_CLK 0x1d5 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX53_PAD_KEY_ROW3__I2C2_SDA 0xc0000000 + MX53_PAD_KEY_COL3__I2C2_SCL 0xc0000000 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 + MX53_PAD_GPIO_5__I2C3_SCL 0xc0000000 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1e4 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1e4 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-tx53-x03x.dts b/arch/arm/boot/dts/nxp/imx/imx53-tx53-x03x.dts index a02d77bb567255..5f62c99909c592 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-tx53-x03x.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-tx53-x03x.dts @@ -262,66 +262,64 @@ touchscreen: tsc2007@48 { }; &iomuxc { - imx53-tx53-x03x { - pinctrl_edt_ft5x06_1: edt-ft5x06grp-1 { - fsl,pins = < - MX53_PAD_NANDF_CS2__GPIO6_15 0x1f0 /* Interrupt */ - MX53_PAD_EIM_A16__GPIO2_22 0x04 /* Reset */ - MX53_PAD_EIM_A17__GPIO2_21 0x04 /* Wake */ - >; - }; + pinctrl_edt_ft5x06_1: edt-ft5x06-1-grp { + fsl,pins = < + MX53_PAD_NANDF_CS2__GPIO6_15 0x1f0 /* Interrupt */ + MX53_PAD_EIM_A16__GPIO2_22 0x04 /* Reset */ + MX53_PAD_EIM_A17__GPIO2_21 0x04 /* Wake */ + >; + }; - pinctrl_kpp: kppgrp { - fsl,pins = < - MX53_PAD_GPIO_9__KPP_COL_6 0x1f4 - MX53_PAD_GPIO_4__KPP_COL_7 0x1f4 - MX53_PAD_KEY_COL2__KPP_COL_2 0x1f4 - MX53_PAD_KEY_COL3__KPP_COL_3 0x1f4 - MX53_PAD_GPIO_2__KPP_ROW_6 0x1f4 - MX53_PAD_GPIO_5__KPP_ROW_7 0x1f4 - MX53_PAD_KEY_ROW2__KPP_ROW_2 0x1f4 - MX53_PAD_KEY_ROW3__KPP_ROW_3 0x1f4 - >; - }; + pinctrl_kpp: kppgrp { + fsl,pins = < + MX53_PAD_GPIO_9__KPP_COL_6 0x1f4 + MX53_PAD_GPIO_4__KPP_COL_7 0x1f4 + MX53_PAD_KEY_COL2__KPP_COL_2 0x1f4 + MX53_PAD_KEY_COL3__KPP_COL_3 0x1f4 + MX53_PAD_GPIO_2__KPP_ROW_6 0x1f4 + MX53_PAD_GPIO_5__KPP_ROW_7 0x1f4 + MX53_PAD_KEY_ROW2__KPP_ROW_2 0x1f4 + MX53_PAD_KEY_ROW3__KPP_ROW_3 0x1f4 + >; + }; - pinctrl_rgb24_vga1: rgb24-vgagrp1 { - fsl,pins = < - MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 - MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 - MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 - MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 - MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 - MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 - MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 - MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 - MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 - MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 - MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 - MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 - MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 - MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 - MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 - MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 - MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 - MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 - MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 - MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 - MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 - MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 - MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 - MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 - MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 - MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 - MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 - MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 - >; - }; + pinctrl_rgb24_vga1: rgb24-vga1grp { + fsl,pins = < + MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK 0x5 + MX53_PAD_DI0_PIN15__IPU_DI0_PIN15 0x5 + MX53_PAD_DI0_PIN2__IPU_DI0_PIN2 0x5 + MX53_PAD_DI0_PIN3__IPU_DI0_PIN3 0x5 + MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0 0x5 + MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1 0x5 + MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2 0x5 + MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3 0x5 + MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4 0x5 + MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5 0x5 + MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6 0x5 + MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7 0x5 + MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8 0x5 + MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9 0x5 + MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10 0x5 + MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11 0x5 + MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12 0x5 + MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13 0x5 + MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14 0x5 + MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15 0x5 + MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16 0x5 + MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17 0x5 + MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18 0x5 + MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19 0x5 + MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20 0x5 + MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21 0x5 + MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22 0x5 + MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23 0x5 + >; + }; - pinctrl_tsc2007: tsc2007grp { - fsl,pins = < - MX53_PAD_EIM_D26__GPIO3_26 0x1f0 /* Interrupt */ - >; - }; + pinctrl_tsc2007: tsc2007grp { + fsl,pins = < + MX53_PAD_EIM_D26__GPIO3_26 0x1f0 /* Interrupt */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-tx53-x13x.dts b/arch/arm/boot/dts/nxp/imx/imx53-tx53-x13x.dts index e10c179dbdb395..9c9122da3737a0 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-tx53-x13x.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-tx53-x13x.dts @@ -139,42 +139,40 @@ sgtl5000: codec@a { }; &iomuxc { - imx53-tx53-x13x { - pinctrl_lvds0: lvds0grp { - fsl,pins = < - MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 - MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 - MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 - MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 - MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 - >; - }; + pinctrl_lvds0: lvds0grp { + fsl,pins = < + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3 0x80000000 + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK 0x80000000 + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2 0x80000000 + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1 0x80000000 + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0 0x80000000 + >; + }; - pinctrl_lvds1: lvds1grp { - fsl,pins = < - MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 0x80000000 - MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 0x80000000 - MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 0x80000000 - MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 0x80000000 - MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 0x80000000 - >; - }; + pinctrl_lvds1: lvds1grp { + fsl,pins = < + MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3 0x80000000 + MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2 0x80000000 + MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK 0x80000000 + MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1 0x80000000 + MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0 0x80000000 + >; + }; - pinctrl_pwm1: pwm1grp { - fsl,pins = ; - }; + pinctrl_pwm1: pwm1grp { + fsl,pins = ; + }; - pinctrl_eeti1: eeti1grp { - fsl,pins = < - MX53_PAD_EIM_D22__GPIO3_22 0x1f0 /* Interrupt */ - >; - }; + pinctrl_eeti1: eeti1grp { + fsl,pins = < + MX53_PAD_EIM_D22__GPIO3_22 0x1f0 /* Interrupt */ + >; + }; - pinctrl_eeti2: eeti2grp { - fsl,pins = < - MX53_PAD_EIM_D23__GPIO3_23 0x1f0 /* Interrupt */ - >; - }; + pinctrl_eeti2: eeti2grp { + fsl,pins = < + MX53_PAD_EIM_D23__GPIO3_23 0x1f0 /* Interrupt */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-tx53.dtsi b/arch/arm/boot/dts/nxp/imx/imx53-tx53.dtsi index a439a47fb65ac6..29e3f5f37c25d4 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-tx53.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx53-tx53.dtsi @@ -257,261 +257,259 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-tx53 { - pinctrl_hog: hoggrp { - /* pins not in use by any device on the Starterkit board series */ - fsl,pins = < - /* CMOS Sensor Interface */ - MX53_PAD_CSI0_DAT12__GPIO5_30 0x1f4 - MX53_PAD_CSI0_DAT13__GPIO5_31 0x1f4 - MX53_PAD_CSI0_DAT14__GPIO6_0 0x1f4 - MX53_PAD_CSI0_DAT15__GPIO6_1 0x1f4 - MX53_PAD_CSI0_DAT16__GPIO6_2 0x1f4 - MX53_PAD_CSI0_DAT17__GPIO6_3 0x1f4 - MX53_PAD_CSI0_DAT18__GPIO6_4 0x1f4 - MX53_PAD_CSI0_DAT19__GPIO6_5 0x1f4 - MX53_PAD_CSI0_MCLK__GPIO5_19 0x1f4 - MX53_PAD_CSI0_VSYNC__GPIO5_21 0x1f4 - MX53_PAD_CSI0_PIXCLK__GPIO5_18 0x1f4 - MX53_PAD_GPIO_0__GPIO1_0 0x1f4 - /* Module Specific Signal */ - /* MX53_PAD_NANDF_CS2__GPIO6_15 0x1f4 maybe used by EDT-FT5x06 */ - /* MX53_PAD_EIM_A16__GPIO2_22 0x1f4 maybe used by EDT-FT5x06 */ - MX53_PAD_EIM_D29__GPIO3_29 0x1f4 - MX53_PAD_EIM_EB3__GPIO2_31 0x1f4 - /* MX53_PAD_EIM_A17__GPIO2_21 0x1f4 maybe used by EDT-FT5x06 */ - /* MX53_PAD_EIM_A18__GPIO2_20 0x1f4 used by LED */ - MX53_PAD_EIM_A19__GPIO2_19 0x1f4 - MX53_PAD_EIM_A20__GPIO2_18 0x1f4 - MX53_PAD_EIM_A21__GPIO2_17 0x1f4 - MX53_PAD_EIM_A22__GPIO2_16 0x1f4 - MX53_PAD_EIM_A23__GPIO6_6 0x1f4 - MX53_PAD_EIM_A24__GPIO5_4 0x1f4 - MX53_PAD_CSI0_DAT8__GPIO5_26 0x1f4 - MX53_PAD_CSI0_DAT9__GPIO5_27 0x1f4 - MX53_PAD_CSI0_DAT10__GPIO5_28 0x1f4 - MX53_PAD_CSI0_DAT11__GPIO5_29 0x1f4 - /* MX53_PAD_EIM_D22__GPIO3_22 0x1f4 maybe used by EETI touchpanel driver */ - /* MX53_PAD_EIM_D23__GPIO3_23 0x1f4 maybe used by EETI touchpanel driver */ - MX53_PAD_GPIO_13__GPIO4_3 0x1f4 - MX53_PAD_EIM_CS0__GPIO2_23 0x1f4 - MX53_PAD_EIM_CS1__GPIO2_24 0x1f4 - MX53_PAD_CSI0_DATA_EN__GPIO5_20 0x1f4 - MX53_PAD_EIM_WAIT__GPIO5_0 0x1f4 - MX53_PAD_EIM_EB0__GPIO2_28 0x1f4 - MX53_PAD_EIM_EB1__GPIO2_29 0x1f4 - MX53_PAD_EIM_OE__GPIO2_25 0x1f4 - MX53_PAD_EIM_LBA__GPIO2_27 0x1f4 - MX53_PAD_EIM_RW__GPIO2_26 0x1f4 - MX53_PAD_EIM_DA8__GPIO3_8 0x1f4 - MX53_PAD_EIM_DA9__GPIO3_9 0x1f4 - MX53_PAD_EIM_DA10__GPIO3_10 0x1f4 - MX53_PAD_EIM_DA11__GPIO3_11 0x1f4 - MX53_PAD_EIM_DA12__GPIO3_12 0x1f4 - MX53_PAD_EIM_DA13__GPIO3_13 0x1f4 - MX53_PAD_EIM_DA14__GPIO3_14 0x1f4 - MX53_PAD_EIM_DA15__GPIO3_15 0x1f4 - >; - }; - - pinctrl_can1: can1grp { - fsl,pins = < - MX53_PAD_GPIO_7__CAN1_TXCAN 0x80000000 - MX53_PAD_GPIO_8__CAN1_RXCAN 0x80000000 + pinctrl_hog: hoggrp { + /* pins not in use by any device on the Starterkit board series */ + fsl,pins = < + /* CMOS Sensor Interface */ + MX53_PAD_CSI0_DAT12__GPIO5_30 0x1f4 + MX53_PAD_CSI0_DAT13__GPIO5_31 0x1f4 + MX53_PAD_CSI0_DAT14__GPIO6_0 0x1f4 + MX53_PAD_CSI0_DAT15__GPIO6_1 0x1f4 + MX53_PAD_CSI0_DAT16__GPIO6_2 0x1f4 + MX53_PAD_CSI0_DAT17__GPIO6_3 0x1f4 + MX53_PAD_CSI0_DAT18__GPIO6_4 0x1f4 + MX53_PAD_CSI0_DAT19__GPIO6_5 0x1f4 + MX53_PAD_CSI0_MCLK__GPIO5_19 0x1f4 + MX53_PAD_CSI0_VSYNC__GPIO5_21 0x1f4 + MX53_PAD_CSI0_PIXCLK__GPIO5_18 0x1f4 + MX53_PAD_GPIO_0__GPIO1_0 0x1f4 + /* Module Specific Signal */ + /* MX53_PAD_NANDF_CS2__GPIO6_15 0x1f4 maybe used by EDT-FT5x06 */ + /* MX53_PAD_EIM_A16__GPIO2_22 0x1f4 maybe used by EDT-FT5x06 */ + MX53_PAD_EIM_D29__GPIO3_29 0x1f4 + MX53_PAD_EIM_EB3__GPIO2_31 0x1f4 + /* MX53_PAD_EIM_A17__GPIO2_21 0x1f4 maybe used by EDT-FT5x06 */ + /* MX53_PAD_EIM_A18__GPIO2_20 0x1f4 used by LED */ + MX53_PAD_EIM_A19__GPIO2_19 0x1f4 + MX53_PAD_EIM_A20__GPIO2_18 0x1f4 + MX53_PAD_EIM_A21__GPIO2_17 0x1f4 + MX53_PAD_EIM_A22__GPIO2_16 0x1f4 + MX53_PAD_EIM_A23__GPIO6_6 0x1f4 + MX53_PAD_EIM_A24__GPIO5_4 0x1f4 + MX53_PAD_CSI0_DAT8__GPIO5_26 0x1f4 + MX53_PAD_CSI0_DAT9__GPIO5_27 0x1f4 + MX53_PAD_CSI0_DAT10__GPIO5_28 0x1f4 + MX53_PAD_CSI0_DAT11__GPIO5_29 0x1f4 + /* MX53_PAD_EIM_D22__GPIO3_22 0x1f4 maybe used by EETI touchpanel driver */ + /* MX53_PAD_EIM_D23__GPIO3_23 0x1f4 maybe used by EETI touchpanel driver */ + MX53_PAD_GPIO_13__GPIO4_3 0x1f4 + MX53_PAD_EIM_CS0__GPIO2_23 0x1f4 + MX53_PAD_EIM_CS1__GPIO2_24 0x1f4 + MX53_PAD_CSI0_DATA_EN__GPIO5_20 0x1f4 + MX53_PAD_EIM_WAIT__GPIO5_0 0x1f4 + MX53_PAD_EIM_EB0__GPIO2_28 0x1f4 + MX53_PAD_EIM_EB1__GPIO2_29 0x1f4 + MX53_PAD_EIM_OE__GPIO2_25 0x1f4 + MX53_PAD_EIM_LBA__GPIO2_27 0x1f4 + MX53_PAD_EIM_RW__GPIO2_26 0x1f4 + MX53_PAD_EIM_DA8__GPIO3_8 0x1f4 + MX53_PAD_EIM_DA9__GPIO3_9 0x1f4 + MX53_PAD_EIM_DA10__GPIO3_10 0x1f4 + MX53_PAD_EIM_DA11__GPIO3_11 0x1f4 + MX53_PAD_EIM_DA12__GPIO3_12 0x1f4 + MX53_PAD_EIM_DA13__GPIO3_13 0x1f4 + MX53_PAD_EIM_DA14__GPIO3_14 0x1f4 + MX53_PAD_EIM_DA15__GPIO3_15 0x1f4 >; - }; + }; - pinctrl_can2: can2grp { - fsl,pins = < - MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 - MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 - >; - }; + pinctrl_can1: can1grp { + fsl,pins = < + MX53_PAD_GPIO_7__CAN1_TXCAN 0x80000000 + MX53_PAD_GPIO_8__CAN1_RXCAN 0x80000000 + >; + }; - pinctrl_can_xcvr: can-xcvrgrp { - fsl,pins = ; /* Flexcan XCVR enable */ - }; + pinctrl_can2: can2grp { + fsl,pins = < + MX53_PAD_KEY_COL4__CAN2_TXCAN 0x80000000 + MX53_PAD_KEY_ROW4__CAN2_RXCAN 0x80000000 + >; + }; - pinctrl_ds1339: ds1339grp { - fsl,pins = ; - }; + pinctrl_can_xcvr: can-xcvrgrp { + fsl,pins = ; /* Flexcan XCVR enable */ + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX53_PAD_GPIO_19__ECSPI1_RDY 0x80000000 - MX53_PAD_EIM_EB2__ECSPI1_SS0 0x80000000 - MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 - MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 - MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 - MX53_PAD_EIM_D19__ECSPI1_SS1 0x80000000 - >; - }; + pinctrl_ds1339: ds1339grp { + fsl,pins = ; + }; - pinctrl_esdhc1: esdhc1grp { - fsl,pins = < - MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 - MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 - MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 - MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 - MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 - MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 - MX53_PAD_EIM_D24__GPIO3_24 0x1f0 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_GPIO_19__ECSPI1_RDY 0x80000000 + MX53_PAD_EIM_EB2__ECSPI1_SS0 0x80000000 + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + MX53_PAD_EIM_D19__ECSPI1_SS1 0x80000000 + >; + }; - pinctrl_esdhc2: esdhc2grp { - fsl,pins = < - MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 - MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 - MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 - MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 - MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 - MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 - MX53_PAD_EIM_D25__GPIO3_25 0x1f0 - >; - }; + pinctrl_esdhc1: esdhc1grp { + fsl,pins = < + MX53_PAD_SD1_DATA0__ESDHC1_DAT0 0x1d5 + MX53_PAD_SD1_DATA1__ESDHC1_DAT1 0x1d5 + MX53_PAD_SD1_DATA2__ESDHC1_DAT2 0x1d5 + MX53_PAD_SD1_DATA3__ESDHC1_DAT3 0x1d5 + MX53_PAD_SD1_CMD__ESDHC1_CMD 0x1d5 + MX53_PAD_SD1_CLK__ESDHC1_CLK 0x1d5 + MX53_PAD_EIM_D24__GPIO3_24 0x1f0 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - >; - }; + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 + MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 + MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 + MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 + MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 + MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 + MX53_PAD_EIM_D25__GPIO3_25 0x1f0 + >; + }; - pinctrl_gpio_key: gpio-keygrp { - fsl,pins = ; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX53_PAD_EIM_D21__I2C1_SCL 0x400001e4 - MX53_PAD_EIM_D28__I2C1_SDA 0x400001e4 - >; - }; + pinctrl_gpio_key: gpio-keygrp { + fsl,pins = ; + }; - pinctrl_i2c1_gpio: i2c1-gpiogrp { - fsl,pins = < - MX53_PAD_EIM_D21__GPIO3_21 0x400001e6 - MX53_PAD_EIM_D28__GPIO3_28 0x400001e6 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_EIM_D21__I2C1_SCL 0x400001e4 + MX53_PAD_EIM_D28__I2C1_SDA 0x400001e4 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX53_PAD_GPIO_3__I2C3_SCL 0x400001e4 - MX53_PAD_GPIO_6__I2C3_SDA 0x400001e4 - >; - }; + pinctrl_i2c1_gpio: i2c1-gpiogrp { + fsl,pins = < + MX53_PAD_EIM_D21__GPIO3_21 0x400001e6 + MX53_PAD_EIM_D28__GPIO3_28 0x400001e6 + >; + }; - pinctrl_i2c3_gpio: i2c3-gpiogrp { - fsl,pins = < - MX53_PAD_GPIO_3__GPIO1_3 0x400001e6 - MX53_PAD_GPIO_6__GPIO1_6 0x400001e6 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_3__I2C3_SCL 0x400001e4 + MX53_PAD_GPIO_6__I2C3_SDA 0x400001e4 + >; + }; - pinctrl_nand: nandgrp { - fsl,pins = < - MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 - MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 - MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 - MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 - MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 - MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 - MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 - MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 0xa4 - MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 0xa4 - MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 0xa4 - MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 0xa4 - MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 0xa4 - MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 0xa4 - MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 0xa4 - MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 0xa4 - >; - }; + pinctrl_i2c3_gpio: i2c3-gpiogrp { + fsl,pins = < + MX53_PAD_GPIO_3__GPIO1_3 0x400001e6 + MX53_PAD_GPIO_6__GPIO1_6 0x400001e6 + >; + }; - pinctrl_pwm2: pwm2grp { - fsl,pins = < - MX53_PAD_GPIO_1__PWM2_PWMO 0x80000000 - >; - }; + pinctrl_nand: nandgrp { + fsl,pins = < + MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 + MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 + MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 + MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 + MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 + MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 + MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 + MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0 0xa4 + MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1 0xa4 + MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2 0xa4 + MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3 0xa4 + MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4 0xa4 + MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5 0xa4 + MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6 0xa4 + MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7 0xa4 + >; + }; - pinctrl_ssi1: ssi1grp { - fsl,pins = < - MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 - MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 - MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 - MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 - >; - }; + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX53_PAD_GPIO_1__PWM2_PWMO 0x80000000 + >; + }; - pinctrl_ssi2: ssi2grp { - fsl,pins = < - MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC 0x80000000 - MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD 0x80000000 - MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS 0x80000000 - MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD 0x80000000 - MX53_PAD_EIM_D27__GPIO3_27 0x1f0 - >; - }; + pinctrl_ssi1: ssi1grp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; - pinctrl_stk5led: stk5ledgrp { - fsl,pins = ; - }; + pinctrl_ssi2: ssi2grp { + fsl,pins = < + MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC 0x80000000 + MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD 0x80000000 + MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS 0x80000000 + MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD 0x80000000 + MX53_PAD_EIM_D27__GPIO3_27 0x1f0 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 - MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 - MX53_PAD_PATA_RESET_B__UART1_CTS 0x1c5 - MX53_PAD_PATA_IORDY__UART1_RTS 0x1c5 - >; - }; + pinctrl_stk5led: stk5ledgrp { + fsl,pins = ; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1c5 - MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1c5 - MX53_PAD_PATA_DIOR__UART2_RTS 0x1c5 - MX53_PAD_PATA_INTRQ__UART2_CTS 0x1c5 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + MX53_PAD_PATA_RESET_B__UART1_CTS 0x1c5 + MX53_PAD_PATA_IORDY__UART1_RTS 0x1c5 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 - MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 - MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 - MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX 0x1c5 + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX 0x1c5 + MX53_PAD_PATA_DIOR__UART2_RTS 0x1c5 + MX53_PAD_PATA_INTRQ__UART2_CTS 0x1c5 + >; + }; - pinctrl_usbh1: usbh1grp { - fsl,pins = < - MX53_PAD_EIM_D30__GPIO3_30 0x100 /* OC */ - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX53_PAD_PATA_CS_0__UART3_TXD_MUX 0x1e4 + MX53_PAD_PATA_CS_1__UART3_RXD_MUX 0x1e4 + MX53_PAD_PATA_DA_1__UART3_CTS 0x1e4 + MX53_PAD_PATA_DA_2__UART3_RTS 0x1e4 + >; + }; - pinctrl_usbh1_vbus: usbh1-vbusgrp { - fsl,pins = < - MX53_PAD_EIM_D31__GPIO3_31 0xe0 /* VBUS ENABLE */ - >; - }; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX53_PAD_EIM_D30__GPIO3_30 0x100 /* OC */ + >; + }; - pinctrl_usbotg_vbus: usbotg-vbusgrp { - fsl,pins = < - MX53_PAD_GPIO_7__GPIO1_7 0xe0 /* VBUS ENABLE */ - MX53_PAD_GPIO_8__GPIO1_8 0x100 /* OC */ - >; - }; + pinctrl_usbh1_vbus: usbh1-vbusgrp { + fsl,pins = < + MX53_PAD_EIM_D31__GPIO3_31 0xe0 /* VBUS ENABLE */ + >; + }; + + pinctrl_usbotg_vbus: usbotg-vbusgrp { + fsl,pins = < + MX53_PAD_GPIO_7__GPIO1_7 0xe0 /* VBUS ENABLE */ + MX53_PAD_GPIO_8__GPIO1_8 0x100 /* OC */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-voipac-bsb.dts b/arch/arm/boot/dts/nxp/imx/imx53-voipac-bsb.dts index ae53d178a68305..ae9cc04f23eb5d 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-voipac-bsb.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-voipac-bsb.dts @@ -40,67 +40,65 @@ led2 { &iomuxc { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_hog>; - - imx53-voipac { - pinctrl_hog: hoggrp { - fsl,pins = < - /* SD2_CD */ - MX53_PAD_EIM_D25__GPIO3_25 0x80000000 - /* SD2_WP */ - MX53_PAD_EIM_A19__GPIO2_19 0x80000000 - >; - }; + pinctrl-0 = <&pinctrl_hogbsb>; + + pinctrl_hogbsb: hogbsbgrp { + fsl,pins = < + /* SD2_CD */ + MX53_PAD_EIM_D25__GPIO3_25 0x80000000 + /* SD2_WP */ + MX53_PAD_EIM_A19__GPIO2_19 0x80000000 + >; + }; - led_pin_gpio: led_gpio { - fsl,pins = < - MX53_PAD_EIM_D29__GPIO3_29 0x80000000 - MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 - >; - }; + led_pin_gpio: ledgpiogrp { + fsl,pins = < + MX53_PAD_EIM_D29__GPIO3_29 0x80000000 + MX53_PAD_EIM_EB3__GPIO2_31 0x80000000 + >; + }; - /* Keyboard controller */ - pinctrl_kpp_1: kppgrp-1 { - fsl,pins = < - MX53_PAD_GPIO_9__KPP_COL_6 0xe8 - MX53_PAD_GPIO_4__KPP_COL_7 0xe8 - MX53_PAD_KEY_COL2__KPP_COL_2 0xe8 - MX53_PAD_KEY_COL3__KPP_COL_3 0xe8 - MX53_PAD_KEY_COL4__KPP_COL_4 0xe8 - MX53_PAD_GPIO_2__KPP_ROW_6 0xe0 - MX53_PAD_GPIO_5__KPP_ROW_7 0xe0 - MX53_PAD_KEY_ROW2__KPP_ROW_2 0xe0 - MX53_PAD_KEY_ROW3__KPP_ROW_3 0xe0 - MX53_PAD_KEY_ROW4__KPP_ROW_4 0xe0 - >; - }; + /* Keyboard controller */ + pinctrl_kpp_1: kpp1grp { + fsl,pins = < + MX53_PAD_GPIO_9__KPP_COL_6 0xe8 + MX53_PAD_GPIO_4__KPP_COL_7 0xe8 + MX53_PAD_KEY_COL2__KPP_COL_2 0xe8 + MX53_PAD_KEY_COL3__KPP_COL_3 0xe8 + MX53_PAD_KEY_COL4__KPP_COL_4 0xe8 + MX53_PAD_GPIO_2__KPP_ROW_6 0xe0 + MX53_PAD_GPIO_5__KPP_ROW_7 0xe0 + MX53_PAD_KEY_ROW2__KPP_ROW_2 0xe0 + MX53_PAD_KEY_ROW3__KPP_ROW_3 0xe0 + MX53_PAD_KEY_ROW4__KPP_ROW_4 0xe0 + >; + }; - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 - MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 - MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 - MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC 0x80000000 + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD 0x80000000 + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS 0x80000000 + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD 0x80000000 + >; + }; - pinctrl_esdhc2: esdhc2grp { - fsl,pins = < - MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 - MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 - MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 - MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 - MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 - MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 - >; - }; + pinctrl_esdhc2: esdhc2grp { + fsl,pins = < + MX53_PAD_SD2_CMD__ESDHC2_CMD 0x1d5 + MX53_PAD_SD2_CLK__ESDHC2_CLK 0x1d5 + MX53_PAD_SD2_DATA0__ESDHC2_DAT0 0x1d5 + MX53_PAD_SD2_DATA1__ESDHC2_DAT1 0x1d5 + MX53_PAD_SD2_DATA2__ESDHC2_DAT2 0x1d5 + MX53_PAD_SD2_DATA3__ESDHC2_DAT3 0x1d5 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX53_PAD_GPIO_3__I2C3_SCL 0xc0000000 - MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX53_PAD_GPIO_3__I2C3_SCL 0xc0000000 + MX53_PAD_GPIO_6__I2C3_SDA 0xc0000000 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-voipac-dmm-668.dtsi b/arch/arm/boot/dts/nxp/imx/imx53-voipac-dmm-668.dtsi index c0622cf7188ce2..6dc70a92d831b4 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-voipac-dmm-668.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx53-voipac-dmm-668.dtsi @@ -37,74 +37,72 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx53-voipac { - pinctrl_hog: hoggrp { - fsl,pins = < - /* Make DA9053 regulator functional */ - MX53_PAD_GPIO_16__GPIO7_11 0x80000000 - /* FEC Power enable */ - MX53_PAD_GPIO_11__GPIO4_1 0x80000000 - /* FEC RST */ - MX53_PAD_GPIO_12__GPIO4_2 0x80000000 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + /* Make DA9053 regulator functional */ + MX53_PAD_GPIO_16__GPIO7_11 0x80000000 + /* FEC Power enable */ + MX53_PAD_GPIO_11__GPIO4_1 0x80000000 + /* FEC RST */ + MX53_PAD_GPIO_12__GPIO4_2 0x80000000 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 - MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 - MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX53_PAD_EIM_D16__ECSPI1_SCLK 0x80000000 + MX53_PAD_EIM_D17__ECSPI1_MISO 0x80000000 + MX53_PAD_EIM_D18__ECSPI1_MOSI 0x80000000 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 - MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 - MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 - MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 - MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 - MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 - MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 - MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 - MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 - MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX53_PAD_FEC_MDC__FEC_MDC 0x80000000 + MX53_PAD_FEC_MDIO__FEC_MDIO 0x80000000 + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK 0x80000000 + MX53_PAD_FEC_RX_ER__FEC_RX_ER 0x80000000 + MX53_PAD_FEC_CRS_DV__FEC_RX_DV 0x80000000 + MX53_PAD_FEC_RXD1__FEC_RDATA_1 0x80000000 + MX53_PAD_FEC_RXD0__FEC_RDATA_0 0x80000000 + MX53_PAD_FEC_TX_EN__FEC_TX_EN 0x80000000 + MX53_PAD_FEC_TXD1__FEC_TDATA_1 0x80000000 + MX53_PAD_FEC_TXD0__FEC_TDATA_0 0x80000000 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX53_PAD_EIM_D21__I2C1_SCL 0xc0000000 - MX53_PAD_EIM_D28__I2C1_SDA 0xc0000000 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX53_PAD_EIM_D21__I2C1_SCL 0xc0000000 + MX53_PAD_EIM_D28__I2C1_SDA 0xc0000000 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 - MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX53_PAD_PATA_DIOW__UART1_TXD_MUX 0x1e4 + MX53_PAD_PATA_DMACK__UART1_RXD_MUX 0x1e4 + >; + }; - pinctrl_nand: nandgrp { - fsl,pins = < - MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 - MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 - MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 - MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 - MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 - MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 - MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 - MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 0xa4 - MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 0xa4 - MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 0xa4 - MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 0xa4 - MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 0xa4 - MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 0xa4 - MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 0xa4 - MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 0xa4 - >; - }; + pinctrl_nand: nandgrp { + fsl,pins = < + MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B 0x4 + MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B 0x4 + MX53_PAD_NANDF_CLE__EMI_NANDF_CLE 0x4 + MX53_PAD_NANDF_ALE__EMI_NANDF_ALE 0x4 + MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B 0xe0 + MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0 0xe0 + MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0 0x4 + MX53_PAD_PATA_DATA0__EMI_NANDF_D_0 0xa4 + MX53_PAD_PATA_DATA1__EMI_NANDF_D_1 0xa4 + MX53_PAD_PATA_DATA2__EMI_NANDF_D_2 0xa4 + MX53_PAD_PATA_DATA3__EMI_NANDF_D_3 0xa4 + MX53_PAD_PATA_DATA4__EMI_NANDF_D_4 0xa4 + MX53_PAD_PATA_DATA5__EMI_NANDF_D_5 0xa4 + MX53_PAD_PATA_DATA6__EMI_NANDF_D_6 0xa4 + MX53_PAD_PATA_DATA7__EMI_NANDF_D_7 0xa4 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53.dtsi b/arch/arm/boot/dts/nxp/imx/imx53.dtsi index 07658e477095fa..845e2bf8460add 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx53.dtsi @@ -458,7 +458,7 @@ srtc: rtc@53fa4000 { clocks = <&clks IMX5_CLK_SRTC_GATE>; }; - iomuxc: iomuxc@53fa8000 { + iomuxc: pinctrl@53fa8000 { compatible = "fsl,imx53-iomuxc"; reg = <0x53fa8000 0x4000>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6-logicpd-baseboard.dtsi b/arch/arm/boot/dts/nxp/imx/imx6-logicpd-baseboard.dtsi index d477a937b47a8b..1e0a588b2a1582 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6-logicpd-baseboard.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6-logicpd-baseboard.dtsi @@ -534,7 +534,7 @@ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17069 >; }; - pinctrl_usdhc2_100mhz: h100-usdhc2-100mhz { + pinctrl_usdhc2_100mhz: h100-usdhc2-100mhzgrp { fsl,pins = < MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 /* CD */ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 @@ -546,7 +546,7 @@ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 >; }; - pinctrl_usdhc2_200mhz: h100-usdhc2-200mhz { + pinctrl_usdhc2_200mhz: h100-usdhc2-200mhzgrp { fsl,pins = < MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 /* CD */ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-colibri-aster.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-colibri-aster.dts index 82a0d1a28d12f4..987058ab0a9b38 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-colibri-aster.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-colibri-aster.dts @@ -52,7 +52,7 @@ &pinctrl_usbc_id_1 &pinctrl_weim_gpio_5 >; - pinctrl_gpio_aster: gpioaster { + pinctrl_gpio_aster: gpioastergrp { fsl,pins = < MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x1b0b0 MX6QDL_PAD_KEY_ROW2__GPIO4_IO11 0x1b0b0 diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-dhcom-pdk2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-dhcom-pdk2.dts new file mode 100644 index 00000000000000..38235925257a72 --- /dev/null +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-dhcom-pdk2.dts @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Marek Vasut + * + * DHCOM iMX6 variant: + * DHCM-iMX6DL-C080-R102-F0819-E-SD-RTC-T-HS-I-01D2 + * DHCOM PCB number: 493-400 or newer + * PDK2 PCB number: 516-400 or newer + */ +/dts-v1/; + +#include "imx6dl.dtsi" +#include "imx6qdl-dhcom-som.dtsi" +#include "imx6qdl-dhcom-pdk2.dtsi" + +/ { + model = "DH electronics i.MX6DL DHCOM on Premium Developer Kit (2)"; + compatible = "dh,imx6dl-dhcom-pdk2", "dh,imx6dl-dhcom-som", + "fsl,imx6dl"; +}; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-dhcom-picoitx.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-dhcom-picoitx.dts index 038bb002555678..775caf8208c5b9 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-dhcom-picoitx.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-dhcom-picoitx.dts @@ -3,7 +3,7 @@ * Copyright (C) 2021 DH electronics GmbH * * DHCOM iMX6 variant: - * DHCM-iMX6DL-C0800-R102-F0819-E-SD-RTC-T-HS-I-01D2 + * DHCM-iMX6DL-C080-R102-F0819-E-SD-RTC-T-HS-I-01D2 * DHCOM PCB number: 493-300 or newer * PicoITX PCB number: 487-600 or newer */ diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-eckelmann-ci4x10.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-eckelmann-ci4x10.dts index 33825b5a8f26c8..5ed55f74b398f2 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-eckelmann-ci4x10.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-eckelmann-ci4x10.dts @@ -139,7 +139,7 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - pinctrl_hog: hog { + pinctrl_hog: hoggrp { fsl,pins = < MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x00000018 /* buzzer */ MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x00000018 /* OUT_1 */ diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-mamoj.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-mamoj.dts index 72ee236d2f5e8b..ec5a9bf40677df 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-mamoj.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-mamoj.dts @@ -395,7 +395,7 @@ MX6QDL_PAD_GPIO_8__I2C4_SDA 0x4001b8b1 >; }; - pinctrl_ipu1_lcdif: pinctrlipu1lcdif { /* parallel port 24-bit */ + pinctrl_ipu1_lcdif: pinctrlipu1lcdifgrp { /* parallel port 24-bit */ fsl,pins = < MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 /* VDOUT_PCLK */ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-prtmvt.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-prtmvt.dts index 773a84a5739df1..0b1275a8891f79 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-prtmvt.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-prtmvt.dts @@ -773,7 +773,7 @@ MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x1b0b0 >; }; - pinctrl_pca9539: pca9539 { + pinctrl_pca9539: pca9539grp { fsl,pins = < MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-prtrvt.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-prtrvt.dts index 36b031236e4756..e543c4f2bc945c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-prtrvt.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-prtrvt.dts @@ -133,7 +133,7 @@ &vpu { }; &iomuxc { - pinctrl_can1phy: can1phy { + pinctrl_can1phy: can1phygrp { fsl,pins = < /* CAN1_SR */ MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x13070 diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-prtvt7.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-prtvt7.dts index 568e98cb62aaf5..29dc6875ab6680 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-prtvt7.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-prtvt7.dts @@ -507,7 +507,7 @@ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 >; }; - pinctrl_can1phy: can1phy { + pinctrl_can1phy: can1phygrp { fsl,pins = < /* CAN1_SR */ MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x13070 diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-qmx6.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-qmx6.dtsi index 8a637fdff073d2..de80ca141bcab8 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-qmx6.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-qmx6.dtsi @@ -352,261 +352,259 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - qmx6mux: imx6qdl-qmx6 { - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x110b0 /* Q7[67] HDA_SDO */ - MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x30b0 /* Q7[59] HDA_SYNC */ - MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x30b0 /* Q7[65] HDA_SDI */ - MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x30b0 /* Q7[63] HDA_BITCLK */ - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x110b0 /* Q7[67] HDA_SDO */ + MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x30b0 /* Q7[59] HDA_SYNC */ + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x30b0 /* Q7[65] HDA_SDI */ + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x30b0 /* Q7[63] HDA_BITCLK */ + >; + }; - /* PHY is on System on Module, Q7[3-15] have Ethernet lines */ - pinctrl_enet: enet { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 - >; - }; + /* PHY is on System on Module, Q7[3-15] have Ethernet lines */ + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 + >; + }; - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* PCIE_WAKE_B */ - MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x80000000 /* I2C multiplexer */ - MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 /* SD4_CD# */ - MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x80000000 /* SD4_WP */ - MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1 0x80000000 /* Camera MCLK */ - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* PCIE_WAKE_B */ + MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x80000000 /* I2C multiplexer */ + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 /* SD4_CD# */ + MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x80000000 /* SD4_WP */ + MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1 0x80000000 /* Camera MCLK */ + >; + }; - pinctrl_i2c1: i2c1 { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 /* Q7[66] I2C_CLK */ - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 /* Q7[68] I2C_DAT */ - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 /* Q7[66] I2C_CLK */ + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 /* Q7[68] I2C_DAT */ + >; + }; - pinctrl_i2c1_gpio: i2c1-gpio { - fsl,pins = < - MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x1b0b0 /* Q7[66] I2C_CLK */ - MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x1b0b0 /* Q7[68] I2C_DAT */ - >; - }; + pinctrl_i2c1_gpio: i2c1-gpiogrp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x1b0b0 /* Q7[66] I2C_CLK */ + MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x1b0b0 /* Q7[68] I2C_DAT */ + >; + }; - pinctrl_i2c2: i2c2 { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 /* Q7[152] SDVO_CTRL_CLK */ - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 /* Q7[150] SDVO_CTRL_DAT */ - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 /* Q7[152] SDVO_CTRL_CLK */ + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 /* Q7[150] SDVO_CTRL_DAT */ + >; + }; - pinctrl_i2c2_gpio: i2c2-gpio { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x1b0b0 /* Q7[152] SDVO_CTRL_CLK */ - MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x1b0b0 /* Q7[150] SDVO_CTRL_DAT */ - >; - }; + pinctrl_i2c2_gpio: i2c2-gpiogrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x1b0b0 /* Q7[152] SDVO_CTRL_CLK */ + MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x1b0b0 /* Q7[150] SDVO_CTRL_DAT */ + >; + }; - pinctrl_i2c3: i2c3 { - fsl,pins = < - MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 /* Q7[60] SMB_CLK */ - MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 /* Q7[62] SMB_DAT */ - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 /* Q7[60] SMB_CLK */ + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 /* Q7[62] SMB_DAT */ + >; + }; - pinctrl_i2c3_gpio: i2c3-gpio { - fsl,pins = < - MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x1b0b0 /* Q7[60] SMB_CLK */ - MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 /* Q7[62] SMB_DAT */ - >; - }; + pinctrl_i2c3_gpio: i2c3-gpiogrp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x1b0b0 /* Q7[60] SMB_CLK */ + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 /* Q7[62] SMB_DAT */ + >; + }; - pinctrl_phy_reset: phy-reset { - fsl,pins = < - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x1b0b0 /* RGMII Phy Reset */ - >; - }; + pinctrl_phy_reset: phy-resetgrp { + fsl,pins = < + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x1b0b0 /* RGMII Phy Reset */ + >; + }; - pinctrl_pwm4: pwm4 { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 /* Q7[123] LVDS_BLT_CTRL */ - >; - }; + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 /* Q7[123] LVDS_BLT_CTRL */ + >; + }; - pinctrl_q7_backlight_enable: q7-backlight-enable { - fsl,pins = < - MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 /* Q7[112] LVDS_BLEN */ - >; - }; + pinctrl_q7_backlight_enable: q7-backlight-enablegrp { + fsl,pins = < + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 /* Q7[112] LVDS_BLEN */ + >; + }; - pinctrl_q7_gpio0: q7-gpio0 { - fsl,pins = < - MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0 /* Q7[185] GPIO0 */ - >; - }; + pinctrl_q7_gpio0: q7-gpio0grp { + fsl,pins = < + MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0 /* Q7[185] GPIO0 */ + >; + }; - pinctrl_q7_gpio1: q7-gpio1 { - fsl,pins = < - MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x1b0b0 /* Q7[186] GPIO1 */ - >; - }; + pinctrl_q7_gpio1: q7-gpio1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x1b0b0 /* Q7[186] GPIO1 */ + >; + }; - pinctrl_q7_gpio2: q7-gpio2 { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x1b0b0 /* Q7[187] GPIO2 */ - >; - }; + pinctrl_q7_gpio2: q7-gpio2grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x1b0b0 /* Q7[187] GPIO2 */ + >; + }; - pinctrl_q7_gpio3: q7-gpio3 { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x1b0b0 /* Q7[188] GPIO3 */ - >; - }; + pinctrl_q7_gpio3: q7-gpio3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x1b0b0 /* Q7[188] GPIO3 */ + >; + }; - pinctrl_q7_gpio4: q7-gpio4 { - fsl,pins = < - MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 /* Q7[189] GPIO4 */ - >; - }; + pinctrl_q7_gpio4: q7-gpio4grp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 /* Q7[189] GPIO4 */ + >; + }; - pinctrl_q7_gpio5: q7-gpio5 { - fsl,pins = < - MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x1b0b0 /* Q7[190] GPIO5 */ - >; - }; + pinctrl_q7_gpio5: q7-gpio5grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x1b0b0 /* Q7[190] GPIO5 */ + >; + }; - pinctrl_q7_gpio6: q7-gpio6 { - fsl,pins = < - MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x1b0b0 /* Q7[191] GPIO6 */ - >; - }; + pinctrl_q7_gpio6: q7-gpio6grp { + fsl,pins = < + MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x1b0b0 /* Q7[191] GPIO6 */ + >; + }; - pinctrl_q7_gpio7: q7-gpio7 { - fsl,pins = < - MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 /* Q7[192] GPIO7 */ - >; - }; + pinctrl_q7_gpio7: q7-gpio7grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 /* Q7[192] GPIO7 */ + >; + }; - pinctrl_q7_hda_reset: q7-hda-reset { - fsl,pins = < - MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x1b0b0 /* Q7[61] HDA_RST_N */ - >; - }; + pinctrl_q7_hda_reset: q7-hda-resetgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x1b0b0 /* Q7[61] HDA_RST_N */ + >; + }; - pinctrl_q7_lcd_power: lcd-power { - fsl,pins = < - MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x1b0b0 /* Q7[111] LVDS_PPEN */ - >; - }; + pinctrl_q7_lcd_power: lcd-powergrp { + fsl,pins = < + MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x1b0b0 /* Q7[111] LVDS_PPEN */ + >; + }; - pinctrl_q7_sdio_power: q7-sdio-power { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 /* Q7[47] SDIO_PWR# */ - >; - }; + pinctrl_q7_sdio_power: q7-sdio-powergrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 /* Q7[47] SDIO_PWR# */ + >; + }; - pinctrl_q7_sleep_button: q7-sleep-button { - fsl,pins = < - MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1b0b0 /* Q7[21] SLP_BTN# */ - >; - }; + pinctrl_q7_sleep_button: q7-sleep-buttongrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1b0b0 /* Q7[21] SLP_BTN# */ + >; + }; - pinctrl_q7_spi_cs1: spi-cs1 { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x1b0b0 /* Q7[202] SPI_CS1# */ - >; - }; + pinctrl_q7_spi_cs1: spi-cs1grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x1b0b0 /* Q7[202] SPI_CS1# */ + >; + }; - /* SPI1 bus does not leave System on Module */ - pinctrl_spi1: spi1 { - fsl,pins = < - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x1b0b0 - >; - }; + /* SPI1 bus does not leave System on Module */ + pinctrl_spi1: spi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x1b0b0 + >; + }; - /* Debug connector on Q7 module */ - pinctrl_uart2: uart2 { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; + /* Debug connector on Q7 module */ + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart3: uart3 { - fsl,pins = < - MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 /* Q7[177] UART0_RX */ - MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 /* Q7[171] UART0_TX */ - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 /* Q7[177] UART0_RX */ + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 /* Q7[171] UART0_TX */ + >; + }; - pinctrl_usbotg: usbotg { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 /* Q7[92] USB_ID */ - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 /* Q7[92] USB_ID */ + >; + }; - /* µSD card slot on Q7 module */ - pinctrl_usdhc2: usdhc2 { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 /* SD2_CD */ - >; - }; + /* µSD card slot on Q7 module */ + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 /* SD2_CD */ + >; + }; - /* eMMC module on Q7 module */ - pinctrl_usdhc3: usdhc3 { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 - >; - }; + /* eMMC module on Q7 module */ + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; - pinctrl_usdhc4: usdhc4 { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 /* Q7[45] SDIO_CMD */ - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x17059 /* Q7[42] SDIO_CLK */ - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 /* Q7[48] SDIO_DAT1 */ - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 /* Q7[49] SDIO_DAT0 */ - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 /* Q7[50] SDIO_DAT3 */ - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 /* Q7[51] SDIO_DAT2 */ - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 /* Q7[45] SDIO_CMD */ + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x17059 /* Q7[42] SDIO_CLK */ + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 /* Q7[48] SDIO_DAT1 */ + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 /* Q7[49] SDIO_DAT0 */ + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 /* Q7[50] SDIO_DAT3 */ + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 /* Q7[51] SDIO_DAT2 */ + >; + }; - pinctrl_wdog: wdog { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0 /* Watchdog output signal */ - >; - }; + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x1b0b0 /* Watchdog output signal */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-riotboard.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-riotboard.dts index 114739d104475c..e9ac4768f36c2b 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-riotboard.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-riotboard.dts @@ -391,208 +391,206 @@ &usdhc4 { &iomuxc { pinctrl-names = "default"; - imx6-riotboard { - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 /* CAM_MCLK */ - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 /* CAM_MCLK */ + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x000b1 /* CS0 */ - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x000b1 /* CS0 */ + >; + }; - pinctrl_ecspi2: ecspi2grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT15__GPIO5_IO09 0x000b1 /* CS1 */ - MX6QDL_PAD_DISP0_DAT16__ECSPI2_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT17__ECSPI2_MISO 0x100b1 - MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x000b1 /* CS0 */ - MX6QDL_PAD_DISP0_DAT19__ECSPI2_SCLK 0x100b1 - >; - }; + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT15__GPIO5_IO09 0x000b1 /* CS1 */ + MX6QDL_PAD_DISP0_DAT16__ECSPI2_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT17__ECSPI2_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x000b1 /* CS0 */ + MX6QDL_PAD_DISP0_DAT19__ECSPI2_SCLK 0x100b1 + >; + }; - pinctrl_ecspi3: ecspi3grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 - MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 - MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x000b1 /* CS0 */ - MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x000b1 /* CS1 */ - >; - }; + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 + MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x000b1 /* CS0 */ + MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x000b1 /* CS1 */ + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x0a0b1 /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */ - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 /* AR8035 pin strapping: IO voltage: pull up */ - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x13030 /* AR8035 pin strapping: PHYADDR#0: pull down */ - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030 /* AR8035 pin strapping: PHYADDR#1: pull down */ - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 /* AR8035 pin strapping: MODE#1: pull up */ - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 /* AR8035 pin strapping: MODE#3: pull up */ - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x130b0 /* AR8035 pin strapping: MODE#0: pull down */ - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 /* GPIO16 -> AR8035 25MHz */ - MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x130b0 /* RGMII_nRST */ - MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x180b0 /* AR8035 interrupt */ - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x0a0b1 /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */ + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 /* AR8035 pin strapping: IO voltage: pull up */ + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x13030 /* AR8035 pin strapping: PHYADDR#0: pull down */ + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030 /* AR8035 pin strapping: PHYADDR#1: pull down */ + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 /* AR8035 pin strapping: MODE#1: pull up */ + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 /* AR8035 pin strapping: MODE#3: pull up */ + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x130b0 /* AR8035 pin strapping: MODE#0: pull down */ + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 /* GPIO16 -> AR8035 25MHz */ + MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x130b0 /* RGMII_nRST */ + MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x180b0 /* AR8035 interrupt */ + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 - MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 + MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c4: i2c4grp { - fsl,pins = < - MX6QDL_PAD_GPIO_7__I2C4_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_8__I2C4_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX6QDL_PAD_GPIO_7__I2C4_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_8__I2C4_SDA 0x4001b8b1 + >; + }; - pinctrl_led: ledgrp { - fsl,pins = < - MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b1 /* user led0 */ - MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x1b0b1 /* user led1 */ - >; - }; + pinctrl_led: ledgrp { + fsl,pins = < + MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b1 /* user led0 */ + MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x1b0b1 /* user led1 */ + >; + }; - pinctrl_pwm1: pwm1grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b1 - >; - }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b1 + >; + }; - pinctrl_pwm2: pwm2grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT9__PWM2_OUT 0x1b0b1 - >; - }; + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT9__PWM2_OUT 0x1b0b1 + >; + }; - pinctrl_pwm3: pwm3grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 - >; - }; + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 + >; + }; - pinctrl_pwm4: pwm4grp { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 - >; - }; + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart5: uart5grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 /* MX6QDL_PAD_EIM_D22__USB_OTG_PWR */ - MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b0b0 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 /* MX6QDL_PAD_EIM_D22__USB_OTG_PWR */ + MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b0b0 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 /* SD2 CD */ - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1f0b0 /* SD2 WP */ - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 /* SD2 CD */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1f0b0 /* SD2 WP */ + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* SD3 CD */ - MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 /* SD3 WP */ - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* SD3 CD */ + MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 /* SD3 WP */ + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x17059 /* SD4 RST (eMMC) */ - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x17059 /* SD4 RST (eMMC) */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-tx6dl-comtft.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-tx6dl-comtft.dts index 51a9bb9d6bc281..7436626673fc45 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-tx6dl-comtft.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-tx6dl-comtft.dts @@ -51,7 +51,6 @@ / { &backlight { pwms = <&pwm2 0 500000 0>; - /delete-property/ turn-on-delay-ms; }; &can1 { diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi index c32ea040fecdda..8bc6376d0dc102 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp4-common.dtsi @@ -506,7 +506,7 @@ MX6QDL_PAD_EIM_D30__USB_H1_OC 0x1b098 >; }; - pinctrl_usbh1_vbus: usbh1-vbus { + pinctrl_usbh1_vbus: usbh1-vbusgrp { fsl,pins = < MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x98 >; @@ -519,7 +519,7 @@ MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b098 >; }; - pinctrl_usbotg_vbus: usbotg-vbus { + pinctrl_usbotg_vbus: usbotg-vbusgrp { fsl,pins = < MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x98 >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp43-common.dtsi b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp43-common.dtsi index bcf4d9c870ec97..2f42c56c21f637 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-yapp43-common.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-yapp43-common.dtsi @@ -500,7 +500,7 @@ MX6QDL_PAD_EIM_D30__USB_H1_OC 0x1b098 >; }; - pinctrl_usbh1_vbus: usbh1-vbus { + pinctrl_usbh1_vbus: usbh1-vbusgrp { fsl,pins = < MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x98 >; @@ -513,7 +513,7 @@ MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b098 >; }; - pinctrl_usbotg_vbus: usbotg-vbus { + pinctrl_usbotg_vbus: usbotg-vbusgrp { fsl,pins = < MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x98 >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-arm2.dts b/arch/arm/boot/dts/nxp/imx/imx6q-arm2.dts index 631d6d690959fc..235148c1edf197 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-arm2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-arm2.dts @@ -55,114 +55,112 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6q-arm2 { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x80000000 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x80000000 + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; + }; - pinctrl_gpmi_nand: gpminandgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 - MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 - MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 - MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 - MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 - MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 - MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 - MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 - MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 - MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 - MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 - MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 - MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 - MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 - MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 - MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 - MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 - >; - }; + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_RX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1 - MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1 + >; + }; - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; - pinctrl_usdhc3_cdwp: usdhc3cdwp { - fsl,pins = < - MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 - MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 - >; - }; + pinctrl_usdhc3_cdwp: usdhc3cdwpgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 + MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 - MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 - MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 - MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi index 09d9ca0cb33243..d77472519086bd 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6q-ba16.dtsi @@ -623,7 +623,7 @@ MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 >; }; - pinctrl_usdhc3_reset: usdhc3grp-reset { + pinctrl_usdhc3_reset: usdhc3-resetgrp { fsl,pins = < MX6QDL_PAD_SD3_RST__SD3_RESET 0x170F9 >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-dhcom-pdk2.dts b/arch/arm/boot/dts/nxp/imx/imx6q-dhcom-pdk2.dts index d4d57370615d83..6efd7e9fc1b187 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-dhcom-pdk2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-dhcom-pdk2.dts @@ -4,7 +4,7 @@ * Copyright (C) 2018 Marek Vasut * * DHCOM iMX6 variant: - * DHCM-iMX6Q-C0800-R102-F0819-E-SD-RTC-T-HS-I-01D2 + * DHCM-iMX6Q-C080-R102-F0819-E-SD-RTC-T-HS-I-01D2 * DHCOM PCB number: 493-300 or newer * PDK2 PCB number: 516-400 or newer */ diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-dmo-edmqmx6.dts b/arch/arm/boot/dts/nxp/imx/imx6q-dmo-edmqmx6.dts index 9f7ac7158c465e..c5525b2c1dbd59 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-dmo-edmqmx6.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-dmo-edmqmx6.dts @@ -283,138 +283,136 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6q-dmo-edmqmx6 { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x80000000 - MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x80000000 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x80000000 + MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x80000000 + >; + }; - pinctrl_can1: can1grp { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 - MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x1b0b0 - >; - }; + pinctrl_can1: can1grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 + MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x1b0b0 + >; + }; - pinctrl_ecspi5: ecspi5rp-1 { - fsl,pins = < - MX6QDL_PAD_SD1_DAT0__ECSPI5_MISO 0x80000000 - MX6QDL_PAD_SD1_CMD__ECSPI5_MOSI 0x80000000 - MX6QDL_PAD_SD1_CLK__ECSPI5_SCLK 0x80000000 - MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x80000000 - >; - }; + pinctrl_ecspi5: ecspi5rp-1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT0__ECSPI5_MISO 0x80000000 + MX6QDL_PAD_SD1_CMD__ECSPI5_MOSI 0x80000000 + MX6QDL_PAD_SD1_CLK__ECSPI5_SCLK 0x80000000 + MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x80000000 + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_pcie: pciegrp { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x100b1 - >; - }; + pinctrl_pcie: pciegrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x100b1 + >; + }; - pinctrl_pfuze: pfuze100grp1 { - fsl,pins = < - MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x80000000 - >; - }; + pinctrl_pfuze: pfuze100grp { + fsl,pins = < + MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x80000000 + >; + }; - pinctrl_stmpe1: stmpe1grp { - fsl,pins = ; - }; + pinctrl_stmpe1: stmpe1grp { + fsl,pins = ; + }; - pinctrl_stmpe2: stmpe2grp { - fsl,pins = ; - }; + pinctrl_stmpe2: stmpe2grp { + fsl,pins = ; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 - MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 - MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 - MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-gk802.dts b/arch/arm/boot/dts/nxp/imx/imx6q-gk802.dts index ce55c9558679b8..e0d29b07fbb1ff 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-gk802.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-gk802.dts @@ -70,58 +70,56 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6q-gk802 { - pinctrl_hog: hoggrp { - fsl,pins = < - /* Recovery button, active-low */ - MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x100b1 - /* RTL8192CU enable GPIO, active-low */ - MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + /* Recovery button, active-low */ + MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x100b1 + /* RTL8192CU enable GPIO, active-low */ + MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-h100.dts b/arch/arm/boot/dts/nxp/imx/imx6q-h100.dts index a603562ea49af6..46e011a363e882 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-h100.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-h100.dts @@ -217,120 +217,118 @@ &i2c2 { }; &iomuxc { - h100 { - pinctrl_h100_hdmi: h100-hdmi { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 - >; - }; + pinctrl_h100_hdmi: h100-hdmigrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; - pinctrl_h100_i2c1: h100-i2c1 { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_h100_i2c1: h100-i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_h100_i2c2: h100-i2c2 { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_h100_i2c2: h100-i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_h100_leds: pinctrl-h100-leds { - fsl,pins = < - MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x1b0b0 - MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x1b0b0 - MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x1b0b0 - >; - }; + pinctrl_h100_leds: pinctrl-h100-ledsgrp { + fsl,pins = < + MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x1b0b0 + MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x1b0b0 + MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x1b0b0 + >; + }; - pinctrl_h100_reg_hdmi: h100-reg-hdmi { - fsl,pins = < - MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x1b0b0 - >; - }; + pinctrl_h100_reg_hdmi: h100-reg-hdmigrp { + fsl,pins = < + MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x1b0b0 + >; + }; - pinctrl_h100_sgtl5000: h100-sgtl5000 { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 - MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 - MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 - MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 - MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 - >; - }; + pinctrl_h100_sgtl5000: h100-sgtl5000grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 + MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 + MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 + MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 + MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 + >; + }; - pinctrl_h100_tc358743: h100-tc358743 { - fsl,pins = < - MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x1b0b0 - >; - }; + pinctrl_h100_tc358743: h100-tc358743grp { + fsl,pins = < + MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x1b0b0 + >; + }; - pinctrl_h100_uart2: h100-uart2 { - fsl,pins = < - MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 - MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 - >; - }; + pinctrl_h100_uart2: h100-uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + >; + }; - pinctrl_h100_usbh1_vbus: hummingboard-usbh1-vbus { - fsl,pins = < - MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 - >; - }; + pinctrl_h100_usbh1_vbus: hummingboard-usbh1-vbusgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 + >; + }; - pinctrl_h100_usbotg_id: hummingboard-usbotg-id { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059 - >; - }; + pinctrl_h100_usbotg_id: hummingboard-usbotg-idgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059 + >; + }; - pinctrl_h100_usbotg_vbus: hummingboard-usbotg-vbus { - fsl,pins = < - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 - >; - }; + pinctrl_h100_usbotg_vbus: hummingboard-usbotg-vbusgrp { + fsl,pins = < + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 + >; + }; - pinctrl_h100_usdhc2: h100-usdhc2 { - fsl,pins = < - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 - MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 - >; - }; + pinctrl_h100_usdhc2: h100-usdhc2grp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 + >; + }; - pinctrl_h100_usdhc2_100mhz: h100-usdhc2-100mhz { - fsl,pins = < - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 - MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 - >; - }; + pinctrl_h100_usdhc2_100mhz: h100-usdhc2-100mhzgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 + >; + }; - pinctrl_h100_usdhc2_200mhz: h100-usdhc2-200mhz { - fsl,pins = < - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 - MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 - >; - }; + pinctrl_h100_usdhc2_200mhz: h100-usdhc2-200mhzgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b0b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-logicpd.dts b/arch/arm/boot/dts/nxp/imx/imx6q-logicpd.dts index 46a4ddedb4236d..86b813a57c1e45 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-logicpd.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-logicpd.dts @@ -110,13 +110,13 @@ ®_hdmi { }; &iomuxc { - pinctrl_lcd_reg: lcdreg { + pinctrl_lcd_reg: lcdreggrp { fsl,pins = < MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x100b0 /* R_LCD_PANEL_PWR */ >; }; - pinctrl_lcd_reset: lcdreset { + pinctrl_lcd_reset: lcdresetgrp { fsl,pins = < MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x100b0 /* LCD_nRESET */ >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-lxr.dts b/arch/arm/boot/dts/nxp/imx/imx6q-lxr.dts new file mode 100644 index 00000000000000..ae4f8eeb105d2b --- /dev/null +++ b/arch/arm/boot/dts/nxp/imx/imx6q-lxr.dts @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// +// Copyright 2024 Comvetia AG + +/dts-v1/; +#include "imx6q-phytec-pfla02.dtsi" + +/ { + model = "COMVETIA QSoIP LXR-2"; + compatible = "comvetia,imx6q-lxr", "phytec,imx6q-pfla02", "fsl,imx6q"; + + chosen { + stdout-path = &uart4; + }; + + spi { + compatible = "spi-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi_gpio>; + sck-gpios = <&gpio5 8 GPIO_ACTIVE_HIGH>; + mosi-gpios = <&gpio5 7 GPIO_ACTIVE_HIGH>; + num-chipselects = <0>; + #address-cells = <1>; + #size-cells = <0>; + + fpga@0 { + compatible = "altr,fpga-passive-serial"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fpga>; + nconfig-gpios = <&gpio4 18 GPIO_ACTIVE_LOW>; + nstat-gpios = <&gpio4 19 GPIO_ACTIVE_LOW>; + confd-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&ecspi3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi3>; + cs-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <20000000>; + }; +}; + +&fec { + status = "okay"; +}; + +&i2c3 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&uart4 { + status = "okay"; +}; + +&usdhc3 { + no-1-8-v; + status = "okay"; +}; + +&iomuxc { + pinctrl_fpga: fpgagrp { + fsl,pins = < + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 + MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x1b0b0 + MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x1b0b0 + >; + }; + + pinctrl_spi_gpio: spigpiogrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT14__GPIO5_IO08 0x1b0b0 + MX6QDL_PAD_DISP0_DAT13__GPIO5_IO07 0x1b0b0 + >; + }; +}; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-mba6.dtsi b/arch/arm/boot/dts/nxp/imx/imx6q-mba6.dtsi index 0d7be456729162..1e5eb837fd80d8 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-mba6.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6q-mba6.dtsi @@ -32,7 +32,7 @@ &sata { }; &iomuxc { - pinctrl_ecspi5_mba6x: ecspi5grp-mba6x { + pinctrl_ecspi5_mba6x: ecspi5-mba6xgrp { fsl,pins = < /* HYS, SPEED = MED, 100k up, DSE = 011, SRE_FAST */ MX6QDL_PAD_SD1_DAT0__ECSPI5_MISO 0x1b099 diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-novena.dts b/arch/arm/boot/dts/nxp/imx/imx6q-novena.dts index d392b5bd2eea83..8c3a9ea8d5b34a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-novena.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-novena.dts @@ -530,7 +530,7 @@ &usdhc3 { }; &iomuxc { - pinctrl_audmux_novena: audmuxgrp-novena { + pinctrl_audmux_novena: audmux-novenagrp { fsl,pins = < MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 @@ -539,7 +539,7 @@ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 >; }; - pinctrl_backlight_novena: backlightgrp-novena { + pinctrl_backlight_novena: backlight-novenagrp { fsl,pins = < MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b0 MX6QDL_PAD_CSI0_DAT10__GPIO5_IO28 0x1b0b1 @@ -547,7 +547,7 @@ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x1b0b1 >; }; - pinctrl_ecspi3_novena: ecspi3grp-novena { + pinctrl_ecspi3_novena: ecspi3-novenagrp { fsl,pins = < MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 @@ -555,7 +555,7 @@ MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 >; }; - pinctrl_enet_novena: enetgrp-novena { + pinctrl_enet_novena: enet-novenagrp { fsl,pins = < MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 @@ -578,7 +578,7 @@ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x1b0b1 >; }; - pinctrl_fpga_gpio: fpgagpiogrp-novena { + pinctrl_fpga_gpio: fpgagpio-novenagrp { fsl,pins = < /* FPGA power */ MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b1 @@ -614,7 +614,7 @@ MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x1b0b1 >; }; - pinctrl_fpga_eim: fpgaeimgrp-novena { + pinctrl_fpga_eim: fpgaeim-novenagrp { fsl,pins = < /* FPGA power */ MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b1 @@ -650,7 +650,7 @@ MX6QDL_PAD_EIM_BCLK__EIM_BCLK 0xb0f1 >; }; - pinctrl_gpio_keys_novena: gpiokeysgrp-novena { + pinctrl_gpio_keys_novena: gpiokeys-novenagrp { fsl,pins = < /* User button */ MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 @@ -661,35 +661,35 @@ MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x1b0b0 >; }; - pinctrl_hdmi_novena: hdmigrp-novena { + pinctrl_hdmi_novena: hdmi-novenagrp { fsl,pins = < MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x1b0b1 >; }; - pinctrl_i2c1_novena: i2c1grp-novena { + pinctrl_i2c1_novena: i2c1-novenagrp { fsl,pins = < MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 >; }; - pinctrl_i2c2_novena: i2c2grp-novena { + pinctrl_i2c2_novena: i2c2-novenagrp { fsl,pins = < MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 >; }; - pinctrl_i2c3_novena: i2c3grp-novena { + pinctrl_i2c3_novena: i2c3-novenagrp { fsl,pins = < MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 >; }; - pinctrl_kpp_novena: kppgrp-novena { + pinctrl_kpp_novena: kpp-novenagrp { fsl,pins = < /* Front panel button */ MX6QDL_PAD_KEY_ROW1__KEY_ROW1 0x1b0b1 @@ -698,13 +698,13 @@ MX6QDL_PAD_KEY_COL1__KEY_COL1 0x1b0b1 >; }; - pinctrl_leds_novena: ledsgrp-novena { + pinctrl_leds_novena: leds-novenagrp { fsl,pins = < MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x1b0b1 >; }; - pinctrl_pcie_novena: pciegrp-novena { + pinctrl_pcie_novena: pcie-novenagrp { fsl,pins = < /* Reset */ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b1 @@ -715,13 +715,13 @@ MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x1b0b1 >; }; - pinctrl_sata_novena: satagrp-novena { + pinctrl_sata_novena: sata-novenagrp { fsl,pins = < MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x1b0b1 >; }; - pinctrl_senoko_novena: senokogrp-novena { + pinctrl_senoko_novena: senoko-novenagrp { fsl,pins = < /* Senoko IRQ line */ MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x13048 @@ -730,7 +730,7 @@ MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x1b0b1 >; }; - pinctrl_sound_novena: soundgrp-novena { + pinctrl_sound_novena: sound-novenagrp { fsl,pins = < /* Audio power regulator */ MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x1b0b1 @@ -740,41 +740,41 @@ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000b0 >; }; - pinctrl_stmpe_novena: stmpegrp-novena { + pinctrl_stmpe_novena: stmpe-novenagrp { fsl,pins = < /* Touchscreen interrupt */ MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13 0x1b0b1 >; }; - pinctrl_uart2_novena: uart2grp-novena { + pinctrl_uart2_novena: uart2-novenagrp { fsl,pins = < MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 >; }; - pinctrl_uart3_novena: uart3grp-novena { + pinctrl_uart3_novena: uart3-novenagrp { fsl,pins = < MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 >; }; - pinctrl_uart4_novena: uart4grp-novena { + pinctrl_uart4_novena: uart4-novenagrp { fsl,pins = < MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 >; }; - pinctrl_usbotg_novena: usbotggrp-novena { + pinctrl_usbotg_novena: usbotg-novenagrp { fsl,pins = < MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 >; }; - pinctrl_usdhc2_novena: usdhc2grp-novena { + pinctrl_usdhc2_novena: usdhc2-novenagrp { fsl,pins = < MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 @@ -789,7 +789,7 @@ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b1 >; }; - pinctrl_usdhc3_novena: usdhc3grp-novena { + pinctrl_usdhc3_novena: usdhc3-novenagrp { fsl,pins = < MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9 MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9 diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-prti6q.dts b/arch/arm/boot/dts/nxp/imx/imx6q-prti6q.dts index 8d2b608e0b90fc..fb81bd8ba03516 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-prti6q.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-prti6q.dts @@ -546,7 +546,7 @@ MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x10880 >; }; - pinctrl_wifi_npd: wifinpd { + pinctrl_wifi_npd: wifinpdgrp { fsl,pins = < MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x1b8b0 >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-prtwd2.dts b/arch/arm/boot/dts/nxp/imx/imx6q-prtwd2.dts index 792b8903d3451c..0e02e448db1085 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-prtwd2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-prtwd2.dts @@ -133,7 +133,7 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usb_eth_chg>; - pinctrl_can1phy: can1phy { + pinctrl_can1phy: can1phygrp { fsl,pins = < /* CAN1_SR */ MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x13070 @@ -187,7 +187,7 @@ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 >; }; - pinctrl_wifi_npd: wifinpd { + pinctrl_wifi_npd: wifinpdgrp { fsl,pins = < /* WL_REG_ON */ MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x13069 diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-sbc6x.dts b/arch/arm/boot/dts/nxp/imx/imx6q-sbc6x.dts index 9054c1d58b9d1a..84fbcd12917964 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-sbc6x.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-sbc6x.dts @@ -25,51 +25,49 @@ &fec { }; &iomuxc { - imx6q-sbc6x { - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-tx6q-1010-comtft.dts b/arch/arm/boot/dts/nxp/imx/imx6q-tx6q-1010-comtft.dts index ac3050a835e550..393bfec58e2f47 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-tx6q-1010-comtft.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-tx6q-1010-comtft.dts @@ -51,7 +51,6 @@ / { &backlight { pwms = <&pwm2 0 500000 0>; - /delete-property/ turn-on-delay-ms; }; &can1 { diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-tx6q-1020-comtft.dts b/arch/arm/boot/dts/nxp/imx/imx6q-tx6q-1020-comtft.dts index a773f252816cb5..1ab175ffa238ad 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-tx6q-1020-comtft.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-tx6q-1020-comtft.dts @@ -51,7 +51,6 @@ / { &backlight { pwms = <&pwm2 0 500000 0>; - /delete-property/ turn-on-delay-ms; }; &can1 { diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-utilite-pro.dts b/arch/arm/boot/dts/nxp/imx/imx6q-utilite-pro.dts index ad59b23ef27a08..aae81feee00dba 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-utilite-pro.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-utilite-pro.dts @@ -296,7 +296,7 @@ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 >; }; - pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { fsl,pins = < MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170B9 MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100B9 @@ -307,7 +307,7 @@ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170B9 >; }; - pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { fsl,pins = < MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170F9 MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100F9 diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi index edf55760a5c1a2..1c72da41701179 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi @@ -191,7 +191,7 @@ sound { "MIC_IN", "Mic Jack", "Mic Jack", "Mic Bias", "Headphone Jack", "HP_OUT"; - model = "imx6q-apalis-sgtl5000"; + model = "apalis-imx6"; mux-ext-port = <4>; mux-int-port = <1>; ssi-controller = <&ssi1>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-aristainetos.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-aristainetos.dtsi index baa197c90060e9..acb404c6828b30 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-aristainetos.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-aristainetos.dtsi @@ -179,230 +179,228 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog &pinctrl_gpio>; - imx6qdl-aristainetos { - pinctrl_aristainetos_usbh1_vbus: aristainetos-usbh1-vbus { - fsl,pins = ; - }; - - pinctrl_aristainetos_usbotg_vbus: aristainetos-usbotg-vbus { - fsl,pins = ; - }; - - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x1b0b0 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x1b0b0 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x1b0b0 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x1b0b0 - >; - }; + pinctrl_aristainetos_usbh1_vbus: aristainetos-usbh1-vbusgrp { + fsl,pins = ; + }; - pinctrl_backlight: backlightgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_9__PWM1_OUT 0x1b0b0 - MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b0 - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 - >; - }; - - pinctrl_ecspi2: ecspi2grp { - fsl,pins = < - MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1 - MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1 - MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1 - MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x100b1 - >; - }; - - pinctrl_ecspi4: ecspi4grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x100b1 - MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1 - MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x100b1 - MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x100b1 - MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x1b0b0 /* WP pin */ - >; - }; - - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0 0x1b0b0 - MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1 0x1b0b0 - MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 - MX6QDL_PAD_ENET_RX_ER__ENET_RX_ER 0x1b0b0 - MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0 0x1b0b0 - MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1 0x1b0b0 - MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN 0x1b0b0 - >; - }; + pinctrl_aristainetos_usbotg_vbus: aristainetos-usbotg-vbusgrp { + fsl,pins = ; + }; - pinctrl_flexcan1: flexcan1grp { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 - MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 - >; - }; - - pinctrl_flexcan2: flexcan2grp { - fsl,pins = < - MX6QDL_PAD_SD3_DAT0__FLEXCAN2_TX 0x1b0b0 - MX6QDL_PAD_SD3_DAT1__FLEXCAN2_RX 0x1b0b0 - >; - }; - - pinctrl_gpio: gpiogrp { - fsl,pins = < - MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x1b0b0 - MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x1b0b0 - MX6QDL_PAD_SD4_DAT4__GPIO2_IO12 0x1b0b0 - MX6QDL_PAD_SD4_DAT5__GPIO2_IO13 0x1b0b0 - MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x1b0b0 - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 - MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x1b0b0 - MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 - MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x1b0b0 - MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x1b0b0 - MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x1b0b0 - >; - }; - - pinctrl_gpmi_nand: gpminandgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 - MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 - MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 - MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 - MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 - MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 - MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 - MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 - MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 - MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 - MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 - MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 - MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 - MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 - MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 - MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 - MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x1b0b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x1b0b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x1b0b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x1b0b0 + >; + }; - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x10 - >; - }; + pinctrl_backlight: backlightgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_9__PWM1_OUT 0x1b0b0 + MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b0 + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 - MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 - >; - }; + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1 + MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1 + MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1 + MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x100b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_ecspi4: ecspi4grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x100b1 + MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x100b1 + MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x100b1 + MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x100b1 + MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x1b0b0 /* WP pin */ + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 - >; - }; - - pinctrl_ipu_disp: ipudisp1grp { - fsl,pins = < - MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 - MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 - MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 - MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 - MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x20000 - MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 - MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 - MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 - MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 - MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 - MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 - MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 - MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 - MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 - MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 - MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 - MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 - MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 - MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 - MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 - MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 - MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 - MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 - MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 - MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 - MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 - MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 - MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 - MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 - >; - }; - - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; - - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 - MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0 0x1b0b0 + MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1 0x1b0b0 + MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 + MX6QDL_PAD_ENET_RX_ER__ENET_RX_ER 0x1b0b0 + MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0 0x1b0b0 + MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1 0x1b0b0 + MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN 0x1b0b0 + >; + }; - pinctrl_uart5: uart5grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT14__UART5_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT15__UART5_RX_DATA 0x1b0b1 - >; - }; + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - >; - }; - - pinctrl_usdhc1: usdhc1grp { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 - MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 - MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 - MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 - MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 - MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 - MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1b0b0 + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT0__FLEXCAN2_TX 0x1b0b0 + MX6QDL_PAD_SD3_DAT1__FLEXCAN2_RX 0x1b0b0 >; - }; - - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x1b0b0 + }; + + pinctrl_gpio: gpiogrp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x1b0b0 + MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x1b0b0 + MX6QDL_PAD_SD4_DAT4__GPIO2_IO12 0x1b0b0 + MX6QDL_PAD_SD4_DAT5__GPIO2_IO13 0x1b0b0 + MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x1b0b0 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 + MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x1b0b0 + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 + MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x1b0b0 + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x1b0b0 + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x1b0b0 + >; + }; + + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; + + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x10 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 + MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; + + pinctrl_ipu_disp: ipudisp1grp { + fsl,pins = < + MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 + MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 + MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 + MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 + MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x20000 + MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 + MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 + MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 + MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 + MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 + MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 + MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 + MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 + MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 + MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 + MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 + MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 + MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 + MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 + MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 + MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 + MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 + MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 + MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 + MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 + MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 + MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 + MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 + MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 >; - }; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 + MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT14__UART5_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT15__UART5_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1b0b0 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x1b0b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-aristainetos2.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-aristainetos2.dtsi index f7fac86f0a6bc1..7cc7ae1959882e 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-aristainetos2.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-aristainetos2.dtsi @@ -413,7 +413,7 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpio>; - pinctrl_audmux: audmux { + pinctrl_audmux: audmuxgrp { fsl,pins = < MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x1b0b0 MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x1b0b0 @@ -599,11 +599,11 @@ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 >; }; - pinctrl_aristainetos2_usbh1_vbus: aristainetos-usbh1-vbus { + pinctrl_aristainetos2_usbh1_vbus: aristainetos-usbh1-vbusgrp { fsl,pins = ; }; - pinctrl_aristainetos2_usbotg_vbus: aristainetos-usbotg-vbus { + pinctrl_aristainetos2_usbotg_vbus: aristainetos-usbotg-vbusgrp { fsl,pins = ; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi index b01670cdd52c38..9f33419c260b69 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi @@ -136,7 +136,7 @@ sound { "LINE_IN", "Line In Jack", "MIC_IN", "Mic Jack", "Mic Jack", "Mic Bias"; - model = "imx6dl-colibri-sgtl5000"; + model = "colibri-imx6"; mux-int-port = <1>; mux-ext-port = <5>; ssi-controller = <&ssi1>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-cubox-i.dtsi index bd66430c1d78d0..41d073f5bfe7a5 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-cubox-i.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-cubox-i.dtsi @@ -153,87 +153,85 @@ rtc@68 { }; &iomuxc { - cubox_i { - pinctrl_cubox_i_hdmi: cubox-i-hdmi { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 - >; - }; + pinctrl_cubox_i_hdmi: cubox-i-hdmigrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; - pinctrl_cubox_i_i2c2: cubox-i-i2c2 { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_cubox_i_i2c2: cubox-i-i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_cubox_i_i2c3: cubox-i-i2c3 { - fsl,pins = < - MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_cubox_i_i2c3: cubox-i-i2c3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_cubox_i_ir: cubox-i-ir { - fsl,pins = < - MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 - >; - }; + pinctrl_cubox_i_ir: cubox-i-irgrp { + fsl,pins = < + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 + >; + }; - pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led { - fsl,pins = ; - }; + pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-ledgrp { + fsl,pins = ; + }; - pinctrl_cubox_i_spdif: cubox-i-spdif { - fsl,pins = ; - }; + pinctrl_cubox_i_spdif: cubox-i-spdifgrp { + fsl,pins = ; + }; - pinctrl_cubox_i_usbh1: cubox-i-usbh1 { - fsl,pins = ; - }; + pinctrl_cubox_i_usbh1: cubox-i-usbh1grp { + fsl,pins = ; + }; - pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus { - fsl,pins = ; - }; + pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbusgrp { + fsl,pins = ; + }; - pinctrl_cubox_i_usbotg: cubox-i-usbotg { - /* - * The Cubox-i pulls ID low, but as it's pointless - * leaving it as a pull-up, even if it is just 10uA. - */ - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059 - MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 - >; - }; + pinctrl_cubox_i_usbotg: cubox-i-usbotggrp { + /* + * The Cubox-i pulls ID low, but as it's pointless + * leaving it as a pull-up, even if it is just 10uA. + */ + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 + >; + }; - pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus { - fsl,pins = ; - }; + pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbusgrp { + fsl,pins = ; + }; - pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-aux { - fsl,pins = < - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 - MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 - >; - }; + pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-auxgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 + >; + }; - pinctrl_cubox_i_usdhc2: cubox-i-usdhc2 { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 - >; - }; + pinctrl_cubox_i_usdhc2: cubox-i-usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + >; + }; - pinctrl_gpio_key: gpio-key { - fsl,pins = < - MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x17059 - >; - }; + pinctrl_gpio_key: gpio-keygrp { + fsl,pins = < + MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-dfi-fs700-m60.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-dfi-fs700-m60.dtsi index 0a6c3a092b3430..f560a6b7779aa9 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-dfi-fs700-m60.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-dfi-fs700-m60.dtsi @@ -47,103 +47,101 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6qdl-dfi-fs700-m60 { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 - MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x80000000 /* PMIC irq */ - MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x80000000 /* MAX11801 irq */ - MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x000030b0 /* Backlight enable */ - >; - }; - - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; - - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 - >; - }; - - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; - - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 - >; - }; - - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x80000000 /* card detect */ - >; - }; - - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; - - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 - MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 - MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 - MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 - >; - }; - - pinctrl_ecspi3: ecspi3grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 - MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 - MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x80000000 /* PMIC irq */ + MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x80000000 /* MAX11801 irq */ + MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x000030b0 /* Backlight enable */ + >; + }; + + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; + + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x80000000 /* card detect */ + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; + + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; + }; + + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 + MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-dhcom-pdk2.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-dhcom-pdk2.dtsi index 6248b126b5578a..d7c2b30aecfd1f 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-dhcom-pdk2.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-dhcom-pdk2.dtsi @@ -56,7 +56,6 @@ lcd_display_out: endpoint { }; gpio-keys { - #size-cells = <0>; compatible = "gpio-keys"; button-0 { @@ -144,6 +143,7 @@ led-8 { panel { backlight = <&display_bl>; compatible = "edt,etm0700g0edh6"; + power-supply = <®_panel_3v3>; port { lcd_panel_in: endpoint { @@ -152,6 +152,25 @@ lcd_panel_in: endpoint { }; }; + /* Filtered supply voltage */ + reg_pdk2_24v: regulator-pdk2-24v { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-max-microvolt = <24000000>; + regulator-min-microvolt = <24000000>; + regulator-name = "24V_PDK2"; + }; + + /* 560-200 U1 */ + reg_panel_3v3: regulator-panel-3v3 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "3V3_PANEL"; + vin-supply = <®_pdk2_24v>; + }; + sound { audio-codec = <&sgtl5000>; audio-routing = diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-dhcom-som.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-dhcom-som.dtsi index eaa87b3331648e..af0d95396cd51d 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-dhcom-som.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-dhcom-som.dtsi @@ -256,7 +256,6 @@ sw1_reg: sw1 { regulator-max-microvolt = <1527272>; regulator-min-microvolt = <787500>; regulator-ramp-delay = <7000>; - regulator-suspend-mem-microvolt = <1040000>; }; sw2_reg: sw2 { @@ -275,7 +274,6 @@ sw3_reg: sw3 { regulator-max-microvolt = <1527272>; regulator-min-microvolt = <787500>; regulator-ramp-delay = <7000>; - regulator-suspend-mem-microvolt = <980000>; }; sw4_reg: sw4 { diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-ds.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-ds.dtsi index f7e51755569770..99ebd4dd63e889 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-ds.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-ds.dtsi @@ -253,7 +253,7 @@ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 >; }; - pinctrl_ecspi1_gpio: ecspi1grpgpiogrp { + pinctrl_ecspi1_gpio: ecspi1gpiogrp { fsl,pins = < MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x1b0b0 MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x1b0b0 @@ -349,7 +349,7 @@ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 >; }; - pinctrl_usdhc1_gpio: usdhc1grpgpiogrp { + pinctrl_usdhc1_gpio: usdhc1gpiogrp { fsl,pins = < MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0 >; @@ -366,7 +366,7 @@ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 >; }; - pinctrl_usdhc2_gpio: usdhc2grpgpiogrp { + pinctrl_usdhc2_gpio: usdhc2gpiogrp { fsl,pins = < MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi index a308a3584b6257..97763db3959fb1 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon.dtsi @@ -330,7 +330,6 @@ &i2c2 { }; &iomuxc { - pinctrl_audmux: audmuxgrp { fsl,pins = < MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 @@ -382,79 +381,79 @@ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x100b1 >; }; - pinctrl_emcon_gpio1: emcongpio1 { + pinctrl_emcon_gpio1: emcongpio1grp { fsl,pins = < MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x0b0b1 >; }; - pinctrl_emcon_gpio2: emcongpio2 { + pinctrl_emcon_gpio2: emcongpio2grp { fsl,pins = < MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x0b0b1 >; }; - pinctrl_emcon_gpio3: emcongpio3 { + pinctrl_emcon_gpio3: emcongpio3grp { fsl,pins = < MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x0b0b1 >; }; - pinctrl_emcon_gpio4: emcongpio4 { + pinctrl_emcon_gpio4: emcongpio4grp { fsl,pins = < MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x0b0b1 >; }; - pinctrl_emcon_gpio5: emcongpio5 { + pinctrl_emcon_gpio5: emcongpio5grp { fsl,pins = < MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x0b0b1 >; }; - pinctrl_emcon_gpio6: emcongpio6 { + pinctrl_emcon_gpio6: emcongpio6grp { fsl,pins = < MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x0b0b1 >; }; - pinctrl_emcon_gpio7: emcongpio7 { + pinctrl_emcon_gpio7: emcongpio7grp { fsl,pins = < MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x0b0b1 >; }; - pinctrl_emcon_gpio8: emcongpio8 { + pinctrl_emcon_gpio8: emcongpio8grp { fsl,pins = < MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x0b0b1 >; }; - pinctrl_emcon_irq_a: emconirqa { + pinctrl_emcon_irq_a: emconirqagrp { fsl,pins = < MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x0b0b1 >; }; - pinctrl_emcon_irq_b: emconirqb { + pinctrl_emcon_irq_b: emconirqbgrp { fsl,pins = < MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x0b0b1 >; }; - pinctrl_emcon_irq_c: emconirqc { + pinctrl_emcon_irq_c: emconirqcgrp { fsl,pins = < MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x0b0b1 >; }; - pinctrl_emcon_irq_pwr: emconirqpwr { + pinctrl_emcon_irq_pwr: emconirqpwrgrp { fsl,pins = < MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x0b0b1 >; }; - pinctrl_emcon_wake: emconwake { + pinctrl_emcon_wake: emconwakegrp { fsl,pins = < MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x1b0b1 >; @@ -503,13 +502,13 @@ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b870 >; }; - pinctrl_irq_touch1: irqtouch1 { + pinctrl_irq_touch1: irqtouch1grp { fsl,pins = < MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x0b0b1 >; }; - pinctrl_irq_touch2: irqtouch2 { + pinctrl_irq_touch2: irqtouch2grp { fsl,pins = < MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x0b0b1 >; @@ -552,7 +551,7 @@ MX6QDL_PAD_SD4_DAT0__GPIO2_IO08 0x0b0b1 >; }; - pinctrl_pwm_fan: pwmfan { + pinctrl_pwm_fan: pwmfangrp { fsl,pins = < MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x0b0b1 >; @@ -565,7 +564,7 @@ MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x0b0b1 >; }; - pinctrl_rgb_bl_en: rgbenable { + pinctrl_rgb_bl_en: rgbenablegrp { fsl,pins = < MX6QDL_PAD_SD4_CMD__GPIO7_IO09 0x0b0b1 >; @@ -617,13 +616,13 @@ MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x0b0b1 >; }; - pinctrl_spdif_in: spdifin { + pinctrl_spdif_in: spdifingrp { fsl,pins = < MX6QDL_PAD_GPIO_16__SPDIF_IN 0x1b0b0 >; }; - pinctrl_spdif_out: spdifout { + pinctrl_spdif_out: spdifoutgrp { fsl,pins = < MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x13091 >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-gw54xx.dtsi index 0ed6d25024a24c..94f1d1ae59aa22 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-gw54xx.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-gw54xx.dtsi @@ -770,14 +770,14 @@ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 >; }; - pinctrl_pwm4_backlight: pwm4grpbacklight { + pinctrl_pwm4_backlight: pwm4backlightgrp { fsl,pins = < /* LVDS_PWM J6.5 */ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 >; }; - pinctrl_pwm4_dio: pwm4grpdio { + pinctrl_pwm4_dio: pwm4diogrp { fsl,pins = < /* DIO3 J16.4 */ MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x1b0b1 diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard.dtsi index d1ad65ab6b72ed..54d4bced239572 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard.dtsi @@ -223,100 +223,98 @@ &i2c2 { }; &iomuxc { - hummingboard { - pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 { - fsl,pins = < - MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x80000000 - MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x80000000 - >; - }; + pinctrl_hummingboard_flexcan1: hummingboard-flexcan1grp { + fsl,pins = < + MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x80000000 + MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x80000000 + >; + }; - pinctrl_hummingboard_gpio3_5: hummingboard-gpio3_5 { - fsl,pins = < - MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1 - >; - }; + pinctrl_hummingboard_gpio3_5: hummingboard-gpio3_5grp { + fsl,pins = < + MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0b1 + >; + }; - pinctrl_hummingboard_hdmi: hummingboard-hdmi { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 - >; - }; + pinctrl_hummingboard_hdmi: hummingboard-hdmigrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; - pinctrl_hummingboard_i2c1: hummingboard-i2c1 { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_hummingboard_i2c1: hummingboard-i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_hummingboard_i2c2: hummingboard-i2c2 { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_hummingboard_i2c2: hummingboard-i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_hummingboard_pcie_reset: hummingboard-pcie-reset { - fsl,pins = < - MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x1b0b1 - >; - }; + pinctrl_hummingboard_pcie_reset: hummingboard-pcie-resetgrp { + fsl,pins = < + MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x1b0b1 + >; + }; - pinctrl_hummingboard_pwm1: pwm1grp { - fsl,pins = ; - }; + pinctrl_hummingboard_pwm1: pwm1grp { + fsl,pins = ; + }; - pinctrl_hummingboard_sgtl5000: hummingboard-sgtl5000 { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 - MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 - MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 - MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 - MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 - >; - }; + pinctrl_hummingboard_sgtl5000: hummingboard-sgtl5000grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 + MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 + MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 + MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 + MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 + >; + }; - pinctrl_hummingboard_spdif: hummingboard-spdif { - fsl,pins = ; - }; + pinctrl_hummingboard_spdif: hummingboard-spdifgrp { + fsl,pins = ; + }; - pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbus { - fsl,pins = ; - }; + pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbusgrp { + fsl,pins = ; + }; - pinctrl_hummingboard_usbotg_id: hummingboard-usbotg-id { - /* - * We want it pulled down for a fixed host connection. - */ - fsl,pins = ; - }; + pinctrl_hummingboard_usbotg_id: hummingboard-usbotg-idgrp { + /* + * We want it pulled down for a fixed host connection. + */ + fsl,pins = ; + }; - pinctrl_hummingboard_usbotg_vbus: hummingboard-usbotg-vbus { - fsl,pins = ; - }; + pinctrl_hummingboard_usbotg_vbus: hummingboard-usbotg-vbusgrp { + fsl,pins = ; + }; - pinctrl_hummingboard_usdhc2_aux: hummingboard-usdhc2-aux { - fsl,pins = < - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 - >; - }; + pinctrl_hummingboard_usdhc2_aux: hummingboard-usdhc2-auxgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + >; + }; - pinctrl_hummingboard_usdhc2: hummingboard-usdhc2 { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 - >; - }; - pinctrl_hummingboard_vmmc: hummingboard-vmmc { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 - >; - }; + pinctrl_hummingboard_usdhc2: hummingboard-usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + >; + }; + pinctrl_hummingboard_vmmc: hummingboard-vmmcgrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2-emmc.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2-emmc.dtsi index f400405381a721..c3efb001c5151c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2-emmc.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2-emmc.dtsi @@ -42,22 +42,20 @@ */ &iomuxc { - hummingboard2 { - pinctrl_hummingboard2_usdhc3: hummingboard2-usdhc3 { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 - MX6QDL_PAD_SD3_RST__SD3_RESET 0x17059 - >; - }; + pinctrl_hummingboard2_usdhc3: hummingboard2-usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2.dtsi index e6017f9bf6409b..3069e1738ba2a0 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-hummingboard2.dtsi @@ -261,258 +261,256 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - hummingboard2 { - pinctrl_hog: hoggrp { + pinctrl_hog: hoggrp { fsl,pins = < - /* - * 36 pin headers GPIO description. The pins - * numbering as following - - * - * 3.2v 5v 74 75 - * 73 72 71 70 - * 69 68 67 66 - * - * 77 78 79 76 - * 65 64 61 60 - * 53 52 51 50 - * 49 48 166 132 - * 95 94 90 91 - * GND 54 24 204 - * - * The GPIO numbers can be extracted using - * signal name from below. - * Example - - * MX6QDL_PAD_EIM_DA10__GPIO3_IO10 is - * GPIO(3,10) which is (3-1)*32+10 = gpio 74 - * - * i.e. The mapping of GPIO(X,Y) to Linux gpio - * number is : gpio number = (X-1) * 32 + Y - */ - /* DI1_PIN15 */ - MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x400130b1 - /* DI1_PIN02 */ - MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x400130b1 - /* DISP1_DATA00 */ - MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x400130b1 - /* DISP1_DATA01 */ - MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x400130b1 - /* DISP1_DATA02 */ - MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x400130b1 - /* DISP1_DATA03 */ - MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x400130b1 - /* DISP1_DATA04 */ - MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x400130b1 - /* DISP1_DATA05 */ - MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x400130b1 - /* DISP1_DATA06 */ - MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x400130b1 - /* DISP1_DATA07 */ - MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x400130b1 - /* DI1_D0_CS */ - MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x400130b1 - /* DI1_D1_CS */ - MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x400130b1 - /* DI1_PIN01 */ - MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x400130b1 - /* DI1_PIN03 */ - MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x400130b1 - /* DISP1_DATA08 */ - MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x400130b1 - /* DISP1_DATA09 */ - MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x400130b1 - /* DISP1_DATA10 */ - MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x400130b1 - /* DISP1_DATA11 */ - MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x400130b1 - /* DISP1_DATA12 */ - MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x400130b1 - /* DISP1_DATA13 */ - MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x400130b1 - /* DISP1_DATA14 */ - MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x400130b1 - /* DISP1_DATA15 */ - MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x400130b1 - /* DISP1_DATA16 */ - MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x400130b1 - /* DISP1_DATA17 */ - MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x400130b1 - /* DISP1_DATA18 */ - MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x400130b1 - /* DISP1_DATA19 */ - MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x400130b1 - /* DISP1_DATA20 */ - MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x400130b1 - /* DISP1_DATA21 */ - MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x400130b1 - /* DISP1_DATA22 */ - MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x400130b1 - /* DISP1_DATA23 */ - MX6QDL_PAD_EIM_D27__GPIO3_IO27 0x400130b1 - /* DI1_DISP_CLK */ - MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x400130b1 - /* SPDIF_IN */ - MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x400130b1 - /* SPDIF_OUT */ - MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x400130b1 - - /* MikroBUS GPIO pin number 10 */ - MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x400130b1 - >; - }; + /* + * 36 pin headers GPIO description. The pins + * numbering as following - + * + * 3.2v 5v 74 75 + * 73 72 71 70 + * 69 68 67 66 + * + * 77 78 79 76 + * 65 64 61 60 + * 53 52 51 50 + * 49 48 166 132 + * 95 94 90 91 + * GND 54 24 204 + * + * The GPIO numbers can be extracted using + * signal name from below. + * Example - + * MX6QDL_PAD_EIM_DA10__GPIO3_IO10 is + * GPIO(3,10) which is (3-1)*32+10 = gpio 74 + * + * i.e. The mapping of GPIO(X,Y) to Linux gpio + * number is : gpio number = (X-1) * 32 + Y + */ + /* DI1_PIN15 */ + MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x400130b1 + /* DI1_PIN02 */ + MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x400130b1 + /* DISP1_DATA00 */ + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x400130b1 + /* DISP1_DATA01 */ + MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x400130b1 + /* DISP1_DATA02 */ + MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x400130b1 + /* DISP1_DATA03 */ + MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x400130b1 + /* DISP1_DATA04 */ + MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x400130b1 + /* DISP1_DATA05 */ + MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x400130b1 + /* DISP1_DATA06 */ + MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x400130b1 + /* DISP1_DATA07 */ + MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x400130b1 + /* DI1_D0_CS */ + MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x400130b1 + /* DI1_D1_CS */ + MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x400130b1 + /* DI1_PIN01 */ + MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x400130b1 + /* DI1_PIN03 */ + MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x400130b1 + /* DISP1_DATA08 */ + MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x400130b1 + /* DISP1_DATA09 */ + MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x400130b1 + /* DISP1_DATA10 */ + MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x400130b1 + /* DISP1_DATA11 */ + MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x400130b1 + /* DISP1_DATA12 */ + MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x400130b1 + /* DISP1_DATA13 */ + MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x400130b1 + /* DISP1_DATA14 */ + MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x400130b1 + /* DISP1_DATA15 */ + MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x400130b1 + /* DISP1_DATA16 */ + MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x400130b1 + /* DISP1_DATA17 */ + MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x400130b1 + /* DISP1_DATA18 */ + MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x400130b1 + /* DISP1_DATA19 */ + MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x400130b1 + /* DISP1_DATA20 */ + MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x400130b1 + /* DISP1_DATA21 */ + MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x400130b1 + /* DISP1_DATA22 */ + MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x400130b1 + /* DISP1_DATA23 */ + MX6QDL_PAD_EIM_D27__GPIO3_IO27 0x400130b1 + /* DI1_DISP_CLK */ + MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x400130b1 + /* SPDIF_IN */ + MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x400130b1 + /* SPDIF_OUT */ + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x400130b1 + + /* MikroBUS GPIO pin number 10 */ + MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x400130b1 + >; + }; - pinctrl_hummingboard2_ecspi2: hummingboard2-ecspi2grp { - fsl,pins = < - MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1 - MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1 - MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1 - MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x000b1 /* CS */ - >; - }; + pinctrl_hummingboard2_ecspi2: hummingboard2-ecspi2grp { + fsl,pins = < + MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1 + MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1 + MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1 + MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x000b1 /* CS */ + >; + }; - pinctrl_hummingboard2_gpio7_9: hummingboard2-gpio7_9 { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__GPIO7_IO09 0x80000000 - >; - }; + pinctrl_hummingboard2_gpio7_9: hummingboard2-gpio7_9grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__GPIO7_IO09 0x80000000 + >; + }; - pinctrl_hummingboard2_hdmi: hummingboard2-hdmi { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 - >; - }; + pinctrl_hummingboard2_hdmi: hummingboard2-hdmigrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; - pinctrl_hummingboard2_i2c1: hummingboard2-i2c1 { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_hummingboard2_i2c1: hummingboard2-i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_hummingboard2_i2c2: hummingboard2-i2c2 { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_hummingboard2_i2c2: hummingboard2-i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_hummingboard2_i2c3: hummingboard2-i2c3 { - fsl,pins = < - MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_hummingboard2_i2c3: hummingboard2-i2c3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_hummingboard2_mipi: hummingboard2_mipi { - fsl,pins = < - MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x4001b8b1 - MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x4001b8b1 - MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0 - >; - }; + pinctrl_hummingboard2_mipi: hummingboard2_mipigrp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x4001b8b1 + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x4001b8b1 + MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0 + >; + }; - pinctrl_hummingboard2_pcie_reset: hummingboard2-pcie-reset { - fsl,pins = < - MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x1b0b1 - >; - }; + pinctrl_hummingboard2_pcie_reset: hummingboard2-pcie-resetgrp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x1b0b1 + >; + }; - pinctrl_hummingboard2_pwm1: pwm1grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b1 - >; - }; + pinctrl_hummingboard2_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b1 + >; + }; - pinctrl_hummingboard2_pwm3: pwm3grp { - fsl,pins = < - MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 - >; - }; + pinctrl_hummingboard2_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 + >; + }; - pinctrl_hummingboard2_sgtl5000: hummingboard2-sgtl5000 { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 - MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 - MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 - MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 - MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 - >; - }; + pinctrl_hummingboard2_sgtl5000: hummingboard2-sgtl5000grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 + MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 + MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 + MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 + MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 + >; + }; - pinctrl_hummingboard2_usbh1_vbus: hummingboard2-usbh1-vbus { - fsl,pins = ; - }; + pinctrl_hummingboard2_usbh1_vbus: hummingboard2-usbh1-vbusgrp { + fsl,pins = ; + }; - pinctrl_hummingboard2_usbh2_vbus: hummingboard2-usbh2-vbus { - fsl,pins = ; - }; + pinctrl_hummingboard2_usbh2_vbus: hummingboard2-usbh2-vbusgrp { + fsl,pins = ; + }; - pinctrl_hummingboard2_usbh3_vbus: hummingboard2-usbh3-vbus { - fsl,pins = ; - }; + pinctrl_hummingboard2_usbh3_vbus: hummingboard2-usbh3-vbusgrp { + fsl,pins = ; + }; - pinctrl_hummingboard2_usbotg_id: hummingboard2-usbotg-id { - /* - * We want it pulled down for a fixed host connection. - */ - fsl,pins = ; - }; + pinctrl_hummingboard2_usbotg_id: hummingboard2-usbotg-idgrp { + /* + * We want it pulled down for a fixed host connection. + */ + fsl,pins = ; + }; - pinctrl_hummingboard2_usbotg_vbus: hummingboard2-usbotg-vbus { - fsl,pins = ; - }; + pinctrl_hummingboard2_usbotg_vbus: hummingboard2-usbotg-vbusgrp { + fsl,pins = ; + }; - pinctrl_hummingboard2_usdhc2_aux: hummingboard2-usdhc2-aux { - fsl,pins = < - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 - MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 - >; - }; + pinctrl_hummingboard2_usdhc2_aux: hummingboard2-usdhc2-auxgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 + MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 + >; + }; - pinctrl_hummingboard2_usdhc2: hummingboard2-usdhc2 { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 - >; - }; + pinctrl_hummingboard2_usdhc2: hummingboard2-usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 + >; + }; - pinctrl_hummingboard2_usdhc2_100mhz: hummingboard2-usdhc2-100mhz { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9 - >; - }; + pinctrl_hummingboard2_usdhc2_100mhz: hummingboard2-usdhc2-100mhzgrp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9 + >; + }; - pinctrl_hummingboard2_usdhc2_200mhz: hummingboard2-usdhc2-200mhz { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9 - >; - }; + pinctrl_hummingboard2_usdhc2_200mhz: hummingboard2-usdhc2-200mhzgrp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9 + >; + }; - pinctrl_hummingboard2_vmmc: hummingboard2-vmmc { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 - >; - }; + pinctrl_hummingboard2_vmmc: hummingboard2-vmmcgrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x1b0b0 + >; + }; - pinctrl_hummingboard2_uart3: hummingboard2-uart3 { - fsl,pins = < - MX6QDL_PAD_EIM_D25__UART3_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D24__UART3_RX_DATA 0x40013000 - >; - }; + pinctrl_hummingboard2_uart3: hummingboard2-uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D25__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D24__UART3_RX_DATA 0x40013000 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-kontron-samx6i.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-kontron-samx6i.dtsi index 99b5e78458aa13..c771f87b10dfeb 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-kontron-samx6i.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-kontron-samx6i.dtsi @@ -728,7 +728,7 @@ MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 >; }; - pinctrl_wdog1: wdog1rp { + pinctrl_wdog1: wdog1grp { fsl,pins = < MX6QDL_PAD_GPIO_9__WDOG1_B 0x1b0b0 >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi index 60aa1e947f62f8..8cefda70db6384 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi @@ -106,6 +106,20 @@ reg_vcc3v3_audio: regulator-vcc3v3-audio { vin-supply = <®_mba6_3p3v>; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x14000000>; + alloc-ranges = <0x10000000 0x20000000>; + linux,cma-default; + }; + }; + sound { compatible = "fsl,imx-audio-tlv320aic32x4"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-nit6xlite.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-nit6xlite.dtsi index a30cf0d06206f3..8ee65f9858c0fc 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-nit6xlite.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-nit6xlite.dtsi @@ -276,205 +276,203 @@ &iomuxc { pinctrl-0 = <&pinctrl_j10>; pinctrl-1 = <&pinctrl_j28>; - imx6dl-nit6xlite { - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - /* Phy reset */ - MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x0f0b0 - MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0 - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + /* Phy reset */ + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x0f0b0 + MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; + }; - pinctrl_gpio_keys: gpio-keysgrp { - fsl,pins = < - /* Home Button: J14 pin 5 */ - MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 - /* Back Button: J14 pin 7 */ - MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 - >; - }; + pinctrl_gpio_keys: gpio-keysgrp { + fsl,pins = < + /* Home Button: J14 pin 5 */ + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 + /* Back Button: J14 pin 7 */ + MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 - /* Touch IRQ: J7 pin 4 */ - MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 - /* tcs2004 IRQ */ - MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x1b0b0 - /* tsc2004 reset */ - MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x0b0b0 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 + /* Touch IRQ: J7 pin 4 */ + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 + /* tcs2004 IRQ */ + MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x1b0b0 + /* tsc2004 reset */ + MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x0b0b0 + >; + }; - pinctrl_j10: j10grp { - fsl,pins = < - /* Broadcom WiFi module pins */ - MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 - MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 - MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 - MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 - MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x0b0b0 - MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x1b0b0 - MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0 - >; - }; + pinctrl_j10: j10grp { + fsl,pins = < + /* Broadcom WiFi module pins */ + MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 + MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x0b0b0 + MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x1b0b0 + MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0 + >; + }; - pinctrl_j28: j28grp { - fsl,pins = < - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 - >; - }; + pinctrl_j28: j28grp { + fsl,pins = < + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 + >; + }; - pinctrl_leds: ledsgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x0b0b0 - MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x0b0b0 - MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x030b0 - MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x0b0b0 - MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x0b0b0 - >; - }; + pinctrl_leds: ledsgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x0b0b0 + MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x0b0b0 + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x030b0 + MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x0b0b0 + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x0b0b0 + >; + }; - pinctrl_pwm1: pwm1grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 - >; - }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 + >; + }; - pinctrl_pwm3: pwm3grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 - >; - }; + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 + >; + }; - pinctrl_pwm4: pwm4grp { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 - >; - }; + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 + >; + }; - pinctrl_wlan_vmmc: wlan-vmmcgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x030b0 - >; - }; + pinctrl_wlan_vmmc: wlan-vmmcgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x030b0 + >; + }; - pinctrl_rtc: rtcgrp { - fsl,pins = < - MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x1b0b0 - >; - }; + pinctrl_rtc: rtcgrp { + fsl,pins = < + MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x1b0b0 + >; + }; - pinctrl_sgtl5000: sgtl5000grp { - fsl,pins = < - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000b0 - MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0 - >; - }; + pinctrl_sgtl5000: sgtl5000grp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000b0 + MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 - MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 - /* power enable, high active */ - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 + /* power enable, high active */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-nitrogen6_max.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-nitrogen6_max.dtsi index 33174febf410b9..43d474bbf55d1c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-nitrogen6_max.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-nitrogen6_max.dtsi @@ -411,287 +411,285 @@ touchscreen@38 { }; &iomuxc { - imx6q-nitrogen6-max { - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + >; + }; - pinctrl_can1: can1grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 - >; - }; + pinctrl_can1: can1grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 + >; + }; - pinctrl_can_xcvr: can-xcvrgrp { - fsl,pins = < - /* Flexcan XCVR enable */ - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 - >; - }; + pinctrl_can_xcvr: can-xcvrgrp { + fsl,pins = < + /* Flexcan XCVR enable */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - /* Phy reset */ - MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x0f0b0 - MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0 - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + /* Phy reset */ + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x0f0b0 + MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; + }; - pinctrl_gpio_keys: gpio-keysgrp { - fsl,pins = < - /* Power Button */ - MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 - /* Menu Button */ - MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 - /* Home Button */ - MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 - /* Back Button */ - MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 - /* Volume Up Button */ - MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 - /* Volume Down Button */ - MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1b0b0 - >; - }; + pinctrl_gpio_keys: gpio-keysgrp { + fsl,pins = < + /* Power Button */ + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 + /* Menu Button */ + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 + /* Home Button */ + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 + /* Back Button */ + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 + /* Volume Up Button */ + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 + /* Volume Down Button */ + MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1b0b0 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2mux: i2c2muxgrp { - fsl,pins = < - /* ov5642 camera i2c enable */ - MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x000b0 - /* ov5640_mipi camera i2c enable */ - MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x000b0 - >; - }; + pinctrl_i2c2mux: i2c2muxgrp { + fsl,pins = < + /* ov5642 camera i2c enable */ + MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x000b0 + /* ov5640_mipi camera i2c enable */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x000b0 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 - MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 + >; + }; - pinctrl_i2c3mux: i2c3muxgrp { - fsl,pins = < - /* PCIe I2C enable */ - MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x000b0 - >; - }; + pinctrl_i2c3mux: i2c3muxgrp { + fsl,pins = < + /* PCIe I2C enable */ + MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x000b0 + >; + }; - pinctrl_j15: j15grp { - fsl,pins = < - MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 - MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 - MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 - MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 - MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 - MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 - MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 - MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 - MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 - MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 - MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 - MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 - MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 - MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 - MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 - MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 - MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 - MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 - MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 - MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 - MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 - MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 - MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 - MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 - MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 - MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 - MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 - MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 - >; - }; + pinctrl_j15: j15grp { + fsl,pins = < + MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 + MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 + MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 + MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 + MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 + MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 + MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 + MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 + MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 + MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 + MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 + MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 + MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 + MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 + MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 + MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 + MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 + MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 + MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 + MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 + MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 + MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 + MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 + MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 + MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 + MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 + MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 + MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 + >; + }; - pinctrl_pcie: pciegrp { - fsl,pins = < - /* PCIe reset */ - MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x000b0 - >; - }; + pinctrl_pcie: pciegrp { + fsl,pins = < + /* PCIe reset */ + MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x000b0 + >; + }; - pinctrl_pwm1: pwm1grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 - >; - }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 + >; + }; - pinctrl_pwm2: pwm2grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1 - >; - }; + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1 + >; + }; - pinctrl_pwm3: pwm3grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 - >; - }; + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 + >; + }; - pinctrl_pwm4: pwm4grp { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 - >; - }; + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 + >; + }; - pinctrl_rv4162: rv4162grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x1b0b0 - >; - }; + pinctrl_rv4162: rv4162grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x1b0b0 + >; + }; - pinctrl_sgtl5000: sgtl5000grp { - fsl,pins = < - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000b0 - MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0 - MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0 - >; - }; + pinctrl_sgtl5000: sgtl5000grp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000b0 + MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0 + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart5: uart5grp { - fsl,pins = < - MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x130b1 - MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x030b1 - /* RS485 RX Enable: pull up */ - MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x1b0b1 - /* RS485 DEN: pull down */ - MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x030b1 - /* RS485/!RS232 Select: pull down (rs232) */ - MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x030b1 - /* ON: pull down */ - MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x030b1 - >; - }; + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x130b1 + MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x030b1 + /* RS485 RX Enable: pull up */ + MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x1b0b1 + /* RS485 DEN: pull down */ + MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x030b1 + /* RS485/!RS232 Select: pull down (rs232) */ + MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x030b1 + /* ON: pull down */ + MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x030b1 + >; + }; - pinctrl_usbh1: usbh1grp { - fsl,pins = < - MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x0b0b0 - >; - }; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x0b0b0 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 - /* power enable, high active */ - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 + /* power enable, high active */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x100b0 - MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x100b0 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 - MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 - MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 - MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; + }; - pinctrl_wlan_vmmc: wlan-vmmcgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x100b0 - MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x000b0 - MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x000b0 - MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0 - >; - }; + pinctrl_wlan_vmmc: wlan-vmmcgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x100b0 + MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x000b0 + MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x000b0 + MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-nitrogen6x.dtsi index 121177273dd007..8a0bfc387a5996 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-nitrogen6x.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-nitrogen6x.dtsi @@ -343,231 +343,229 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6q-nitrogen6x { - pinctrl_hog: hoggrp { - fsl,pins = < - /* SGTL5000 sys_mclk */ - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 - MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + /* SGTL5000 sys_mclk */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 + >; + }; - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + >; + }; - pinctrl_can1: can1grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 - >; - }; + pinctrl_can1: can1grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 + >; + }; - pinctrl_can_xcvr: can-xcvrgrp { - fsl,pins = < - /* Flexcan XCVR enable */ - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 - >; - }; + pinctrl_can_xcvr: can-xcvrgrp { + fsl,pins = < + /* Flexcan XCVR enable */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 /* CS */ - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 /* CS */ + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - /* Phy reset */ - MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x000b0 - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + /* Phy reset */ + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x000b0 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; + }; - pinctrl_gpio_keys: gpio-keysgrp { - fsl,pins = < - /* Power Button */ - MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 - /* Menu Button */ - MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 - /* Home Button */ - MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 - /* Back Button */ - MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 - /* Volume Up Button */ - MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 - /* Volume Down Button */ - MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 - >; - }; + pinctrl_gpio_keys: gpio-keysgrp { + fsl,pins = < + /* Power Button */ + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 + /* Menu Button */ + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 + /* Home Button */ + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 + /* Back Button */ + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 + /* Volume Up Button */ + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 + /* Volume Down Button */ + MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_j15: j15grp { - fsl,pins = < - MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 - MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 - MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 - MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 - MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 - MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 - MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 - MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 - MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 - MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 - MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 - MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 - MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 - MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 - MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 - MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 - MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 - MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 - MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 - MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 - MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 - MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 - MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 - MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 - MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 - MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 - MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 - MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 - >; - }; + pinctrl_j15: j15grp { + fsl,pins = < + MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 + MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 + MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 + MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 + MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 + MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 + MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 + MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 + MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 + MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 + MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 + MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 + MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 + MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 + MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 + MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 + MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 + MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 + MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 + MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 + MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 + MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 + MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 + MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 + MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 + MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 + MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 + MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 + >; + }; - pinctrl_pwm1: pwm1grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 - >; - }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 + >; + }; - pinctrl_pwm3: pwm3grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 - >; - }; + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 + >; + }; - pinctrl_pwm4: pwm4grp { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 - >; - }; + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbh1: usbh1grp { - fsl,pins = < - MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x030b0 - >; - }; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x030b0 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 - /* power enable, high active */ - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 + /* power enable, high active */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17071 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10071 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17071 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17071 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17071 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17071 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17071 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10071 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17071 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17071 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17071 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17071 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* CD */ - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* CD */ + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */ - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */ + >; + }; - pinctrl_wlan_vmmc: wlan-vmmcgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x100b0 - MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x000b0 - MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x000b0 - MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0 - >; - }; + pinctrl_wlan_vmmc: wlan-vmmcgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x100b0 + MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x000b0 + MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x000b0 + MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-mira-peb-wlbt-05.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-mira-peb-wlbt-05.dtsi index 84f884d6e55bc2..08b2dd06580ab6 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-mira-peb-wlbt-05.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-mira-peb-wlbt-05.dtsi @@ -54,7 +54,7 @@ brmcf: wifi@1 { }; &iomuxc { - pinctrl_uart3_bt: uart3grp-bt { + pinctrl_uart3_bt: uart3-btgrp { fsl,pins = < MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 @@ -66,7 +66,7 @@ MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0xb0b1 /* HOST WAKEUP */ >; }; - pinctrl_usdhc3_wl: usdhc3grp-wl { + pinctrl_usdhc3_wl: usdhc3-wlgrp { fsl,pins = < MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi index c0c47adc5866e3..aa9a442852f41b 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-phytec-pfla02.dtsi @@ -227,170 +227,168 @@ &i2c3 { }; &iomuxc { - imx6q-phytec-pfla02 { - pinctrl_ecspi3: ecspi3grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 - MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 - MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* CS0 */ - >; - }; + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 + MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* CS0 */ + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 /* Reset GPIO */ - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 /* Reset GPIO */ + >; + }; - pinctrl_flexcan1: flexcan1grp { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 - MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 - >; - }; + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 + >; + }; - pinctrl_gpmi_nand: gpminandgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 - MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 - MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 - MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 - MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 - MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 - MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 - MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 - MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 - MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 - MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 - MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 - MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 - MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 - MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 - MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 - MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 - >; - }; + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_leds: ledsgrp { - fsl,pins = < - MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* Green LED */ - MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 /* Red LED */ - >; - }; + pinctrl_leds: ledsgrp { + fsl,pins = < + MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* Green LED */ + MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 /* Red LED */ + >; + }; - pinctrl_pcie: pciegrp { - fsl,pins = ; - }; + pinctrl_pcie: pciegrp { + fsl,pins = ; + }; - pinctrl_pmic: pmicgrp { - fsl,pins = ; /* PMIC interrupt */ - }; + pinctrl_pmic: pmicgrp { + fsl,pins = ; /* PMIC interrupt */ + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1 - MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x1b0b1 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1 + MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x1b0b1 + >; + }; - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbh1_vbus: usbh1vbusgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 - >; - }; + pinctrl_usbh1_vbus: usbh1vbusgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 - MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; - pinctrl_usdhc3_cdwp: usdhc3cdwp { - fsl,pins = < - MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 - MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 - >; - }; + pinctrl_usdhc3_cdwp: usdhc3cdwpgrp { + fsl,pins = < + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 + >; + }; - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x130b0 - MX6QDL_PAD_DISP0_DAT17__AUD5_TXD 0x110b0 - MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x130b0 - MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x130b0 + MX6QDL_PAD_DISP0_DAT17__AUD5_TXD 0x110b0 + MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x130b0 + MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-rex.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-rex.dtsi index eba698d04243a6..64ded5e5559c75 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-rex.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-rex.dtsi @@ -154,159 +154,157 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6qdl-rex { - pinctrl_hog: hoggrp { - fsl,pins = < - /* SGTL5000 sys_mclk */ - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + /* SGTL5000 sys_mclk */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 + >; + }; - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + >; + }; - pinctrl_ecspi2: ecspi2grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 - MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 - /* CS */ - MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x000b1 - >; - }; + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 + /* CS */ + MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x000b1 + >; + }; - pinctrl_ecspi3: ecspi3grp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT17__ECSPI2_MISO 0x100b1 - MX6QDL_PAD_DISP0_DAT16__ECSPI2_MOSI 0x100b1 - MX6QDL_PAD_DISP0_DAT19__ECSPI2_SCLK 0x100b1 - /* CS */ - MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x000b1 - >; - }; + pinctrl_ecspi3: ecspi3grp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT17__ECSPI2_MISO 0x100b1 + MX6QDL_PAD_DISP0_DAT16__ECSPI2_MOSI 0x100b1 + MX6QDL_PAD_DISP0_DAT19__ECSPI2_SCLK 0x100b1 + /* CS */ + MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x000b1 + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - /* Phy reset */ - MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x000b0 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + /* Phy reset */ + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x000b0 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 - MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 + MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_led: ledgrp { - fsl,pins = < - /* user led */ - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 - >; - }; + pinctrl_led: ledgrp { + fsl,pins = < + /* user led */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 + >; + }; - pinctrl_pca9535: pca9535grp { - fsl,pins = < - MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x17059 - >; - }; + pinctrl_pca9535: pca9535grp { + fsl,pins = < + MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x17059 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbh1: usbh1grp { - fsl,pins = < - /* power enable, high active */ - MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x10b0 - >; - }; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + /* power enable, high active */ + MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x10b0 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b0b0 - /* power enable, high active */ - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x10b0 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b0b0 + /* power enable, high active */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x10b0 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - /* CD */ - MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 - /* WP */ - MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1f0b0 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + /* CD */ + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 + /* WP */ + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1f0b0 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - /* CD */ - MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 - /* WP */ - MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1f0b0 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + /* CD */ + MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 + /* WP */ + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1f0b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-sabreauto.dtsi index 35b6bec7a3fab6..a381cb224c1e21 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-sabreauto.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-sabreauto.dtsi @@ -472,312 +472,310 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6qdl-sabreauto { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 - MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x80000000 - MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x17059 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 + MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x80000000 + MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x17059 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + >; + }; - pinctrl_ecspi1_cs: ecspi1cs { - fsl,pins = < - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 - >; - }; + pinctrl_ecspi1_cs: ecspi1csgrp { + fsl,pins = < + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 + >; + }; - pinctrl_egalax_int: egalax-intgrp { - fsl,pins = < - MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0xb0b1 - >; - }; + pinctrl_egalax_int: egalax-intgrp { + fsl,pins = < + MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0xb0b1 + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; + }; - pinctrl_esai: esaigrp { - fsl,pins = < - MX6QDL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1b030 - MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1b030 - MX6QDL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x1b030 - MX6QDL_PAD_GPIO_5__ESAI_TX2_RX3 0x1b030 - MX6QDL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x1b030 - MX6QDL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1b030 - MX6QDL_PAD_GPIO_17__ESAI_TX0 0x1b030 - MX6QDL_PAD_NANDF_CS3__ESAI_TX1 0x1b030 - MX6QDL_PAD_ENET_MDIO__ESAI_RX_CLK 0x1b030 - MX6QDL_PAD_GPIO_9__ESAI_RX_FS 0x1b030 - >; - }; + pinctrl_esai: esaigrp { + fsl,pins = < + MX6QDL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1b030 + MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1b030 + MX6QDL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x1b030 + MX6QDL_PAD_GPIO_5__ESAI_TX2_RX3 0x1b030 + MX6QDL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x1b030 + MX6QDL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1b030 + MX6QDL_PAD_GPIO_17__ESAI_TX0 0x1b030 + MX6QDL_PAD_NANDF_CS3__ESAI_TX1 0x1b030 + MX6QDL_PAD_ENET_MDIO__ESAI_RX_CLK 0x1b030 + MX6QDL_PAD_GPIO_9__ESAI_RX_FS 0x1b030 + >; + }; - pinctrl_flexcan1: flexcan1grp { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x17059 - MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x17059 - >; - }; + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x17059 + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x17059 + >; + }; - pinctrl_flexcan2: flexcan2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x17059 - MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x17059 - >; - }; + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x17059 + MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x17059 + >; + }; - pinctrl_gpio_keys: gpiokeysgrp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x1b0b0 - MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x1b0b0 - MX6QDL_PAD_SD4_DAT4__GPIO2_IO12 0x1b0b0 - MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x1b0b0 - MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x1b0b0 - >; - }; + pinctrl_gpio_keys: gpiokeysgrp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x1b0b0 + MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x1b0b0 + MX6QDL_PAD_SD4_DAT4__GPIO2_IO12 0x1b0b0 + MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x1b0b0 + MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x1b0b0 + >; + }; - pinctrl_gpio_leds: gpioledsgrp { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x80000000 - >; - }; + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x80000000 + >; + }; - pinctrl_gpmi_nand: gpminandgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 - MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 - MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 - MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 - MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 - MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 - MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 - MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 - MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 - MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 - MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 - MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 - MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 - MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 - MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 - MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 - MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 - >; - }; + pinctrl_gpmi_nand: gpminandgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 + MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 + MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 + MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 + MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 + MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 + MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 + MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 + MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 + MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 + MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 + MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 + MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 + MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 + MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 + MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 + MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 + >; + }; - pinctrl_hdmi_cec: hdmicecgrp { - fsl,pins = < - MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x1f8b0 - >; - }; + pinctrl_hdmi_cec: hdmicecgrp { + fsl,pins = < + MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3mux: i2c3muxgrp { - fsl,pins = < - MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x0b0b1 - >; - }; + pinctrl_i2c3mux: i2c3muxgrp { + fsl,pins = < + MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x0b0b1 + >; + }; - pinctrl_ipu1_csi0: ipu1csi0grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b0 - MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x1b0b0 - MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x1b0b0 - MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x1b0b0 - MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x1b0b0 - MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x1b0b0 - MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x1b0b0 - MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x1b0b0 - MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x1b0b0 - MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x1b0b0 - MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x1b0b0 - >; - }; + pinctrl_ipu1_csi0: ipu1csi0grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b0 + MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x1b0b0 + MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x1b0b0 + MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x1b0b0 + MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x1b0b0 + MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x1b0b0 + MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x1b0b0 + MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x1b0b0 + MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x1b0b0 + MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x1b0b0 + MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x1b0b0 + >; + }; - pinctrl_max7310: max7310grp { - fsl,pins = < - MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x1b0b0 - >; - }; + pinctrl_max7310: max7310grp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x1b0b0 + >; + }; - pinctrl_mma8451_int: mma8451intgrp { - fsl,pins = < - MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0xb0b1 - >; - }; + pinctrl_mma8451_int: mma8451intgrp { + fsl,pins = < + MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0xb0b1 + >; + }; - pinctrl_pwm3: pwm1grp { - fsl,pins = < - MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 - >; - }; + pinctrl_pwm3: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 + >; + }; - pinctrl_gpt_input_capture0: gptinputcapture0grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT0__GPT_CAPTURE1 0x1b0b0 - >; - }; + pinctrl_gpt_input_capture0: gptinputcapture0grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT0__GPT_CAPTURE1 0x1b0b0 + >; + }; - pinctrl_gpt_input_capture1: gptinputcapture1grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT1__GPT_CAPTURE2 0x1b0b0 - >; - }; + pinctrl_gpt_input_capture1: gptinputcapture1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__GPT_CAPTURE2 0x1b0b0 + >; + }; - pinctrl_spdif: spdifgrp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 - >; - }; + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 + >; + }; - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; - pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170b9 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100b9 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170b9 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170b9 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170b9 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170b9 - >; - }; + pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170b9 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100b9 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170b9 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170b9 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170b9 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170b9 + >; + }; - pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170f9 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170f9 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170f9 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170f9 - >; - }; + pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170f9 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170f9 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170f9 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170f9 + >; + }; - pinctrl_weim_cs0: weimcs0grp { - fsl,pins = < - MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0xb0b1 - >; - }; + pinctrl_weim_cs0: weimcs0grp { + fsl,pins = < + MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0xb0b1 + >; + }; - pinctrl_weim_nor: weimnorgrp { - fsl,pins = < - MX6QDL_PAD_EIM_OE__EIM_OE_B 0xb0b1 - MX6QDL_PAD_EIM_RW__EIM_RW 0xb0b1 - MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0xb060 - MX6QDL_PAD_EIM_D16__EIM_DATA16 0x1b0b0 - MX6QDL_PAD_EIM_D17__EIM_DATA17 0x1b0b0 - MX6QDL_PAD_EIM_D18__EIM_DATA18 0x1b0b0 - MX6QDL_PAD_EIM_D19__EIM_DATA19 0x1b0b0 - MX6QDL_PAD_EIM_D20__EIM_DATA20 0x1b0b0 - MX6QDL_PAD_EIM_D21__EIM_DATA21 0x1b0b0 - MX6QDL_PAD_EIM_D22__EIM_DATA22 0x1b0b0 - MX6QDL_PAD_EIM_D23__EIM_DATA23 0x1b0b0 - MX6QDL_PAD_EIM_D24__EIM_DATA24 0x1b0b0 - MX6QDL_PAD_EIM_D25__EIM_DATA25 0x1b0b0 - MX6QDL_PAD_EIM_D26__EIM_DATA26 0x1b0b0 - MX6QDL_PAD_EIM_D27__EIM_DATA27 0x1b0b0 - MX6QDL_PAD_EIM_D28__EIM_DATA28 0x1b0b0 - MX6QDL_PAD_EIM_D29__EIM_DATA29 0x1b0b0 - MX6QDL_PAD_EIM_D30__EIM_DATA30 0x1b0b0 - MX6QDL_PAD_EIM_D31__EIM_DATA31 0x1b0b0 - MX6QDL_PAD_EIM_A23__EIM_ADDR23 0xb0b1 - MX6QDL_PAD_EIM_A22__EIM_ADDR22 0xb0b1 - MX6QDL_PAD_EIM_A21__EIM_ADDR21 0xb0b1 - MX6QDL_PAD_EIM_A20__EIM_ADDR20 0xb0b1 - MX6QDL_PAD_EIM_A19__EIM_ADDR19 0xb0b1 - MX6QDL_PAD_EIM_A18__EIM_ADDR18 0xb0b1 - MX6QDL_PAD_EIM_A17__EIM_ADDR17 0xb0b1 - MX6QDL_PAD_EIM_A16__EIM_ADDR16 0xb0b1 - MX6QDL_PAD_EIM_DA15__EIM_AD15 0xb0b1 - MX6QDL_PAD_EIM_DA14__EIM_AD14 0xb0b1 - MX6QDL_PAD_EIM_DA13__EIM_AD13 0xb0b1 - MX6QDL_PAD_EIM_DA12__EIM_AD12 0xb0b1 - MX6QDL_PAD_EIM_DA11__EIM_AD11 0xb0b1 - MX6QDL_PAD_EIM_DA10__EIM_AD10 0xb0b1 - MX6QDL_PAD_EIM_DA9__EIM_AD09 0xb0b1 - MX6QDL_PAD_EIM_DA8__EIM_AD08 0xb0b1 - MX6QDL_PAD_EIM_DA7__EIM_AD07 0xb0b1 - MX6QDL_PAD_EIM_DA6__EIM_AD06 0xb0b1 - MX6QDL_PAD_EIM_DA5__EIM_AD05 0xb0b1 - MX6QDL_PAD_EIM_DA4__EIM_AD04 0xb0b1 - MX6QDL_PAD_EIM_DA3__EIM_AD03 0xb0b1 - MX6QDL_PAD_EIM_DA2__EIM_AD02 0xb0b1 - MX6QDL_PAD_EIM_DA1__EIM_AD01 0xb0b1 - MX6QDL_PAD_EIM_DA0__EIM_AD00 0xb0b1 - >; - }; + pinctrl_weim_nor: weimnorgrp { + fsl,pins = < + MX6QDL_PAD_EIM_OE__EIM_OE_B 0xb0b1 + MX6QDL_PAD_EIM_RW__EIM_RW 0xb0b1 + MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0xb060 + MX6QDL_PAD_EIM_D16__EIM_DATA16 0x1b0b0 + MX6QDL_PAD_EIM_D17__EIM_DATA17 0x1b0b0 + MX6QDL_PAD_EIM_D18__EIM_DATA18 0x1b0b0 + MX6QDL_PAD_EIM_D19__EIM_DATA19 0x1b0b0 + MX6QDL_PAD_EIM_D20__EIM_DATA20 0x1b0b0 + MX6QDL_PAD_EIM_D21__EIM_DATA21 0x1b0b0 + MX6QDL_PAD_EIM_D22__EIM_DATA22 0x1b0b0 + MX6QDL_PAD_EIM_D23__EIM_DATA23 0x1b0b0 + MX6QDL_PAD_EIM_D24__EIM_DATA24 0x1b0b0 + MX6QDL_PAD_EIM_D25__EIM_DATA25 0x1b0b0 + MX6QDL_PAD_EIM_D26__EIM_DATA26 0x1b0b0 + MX6QDL_PAD_EIM_D27__EIM_DATA27 0x1b0b0 + MX6QDL_PAD_EIM_D28__EIM_DATA28 0x1b0b0 + MX6QDL_PAD_EIM_D29__EIM_DATA29 0x1b0b0 + MX6QDL_PAD_EIM_D30__EIM_DATA30 0x1b0b0 + MX6QDL_PAD_EIM_D31__EIM_DATA31 0x1b0b0 + MX6QDL_PAD_EIM_A23__EIM_ADDR23 0xb0b1 + MX6QDL_PAD_EIM_A22__EIM_ADDR22 0xb0b1 + MX6QDL_PAD_EIM_A21__EIM_ADDR21 0xb0b1 + MX6QDL_PAD_EIM_A20__EIM_ADDR20 0xb0b1 + MX6QDL_PAD_EIM_A19__EIM_ADDR19 0xb0b1 + MX6QDL_PAD_EIM_A18__EIM_ADDR18 0xb0b1 + MX6QDL_PAD_EIM_A17__EIM_ADDR17 0xb0b1 + MX6QDL_PAD_EIM_A16__EIM_ADDR16 0xb0b1 + MX6QDL_PAD_EIM_DA15__EIM_AD15 0xb0b1 + MX6QDL_PAD_EIM_DA14__EIM_AD14 0xb0b1 + MX6QDL_PAD_EIM_DA13__EIM_AD13 0xb0b1 + MX6QDL_PAD_EIM_DA12__EIM_AD12 0xb0b1 + MX6QDL_PAD_EIM_DA11__EIM_AD11 0xb0b1 + MX6QDL_PAD_EIM_DA10__EIM_AD10 0xb0b1 + MX6QDL_PAD_EIM_DA9__EIM_AD09 0xb0b1 + MX6QDL_PAD_EIM_DA8__EIM_AD08 0xb0b1 + MX6QDL_PAD_EIM_DA7__EIM_AD07 0xb0b1 + MX6QDL_PAD_EIM_DA6__EIM_AD06 0xb0b1 + MX6QDL_PAD_EIM_DA5__EIM_AD05 0xb0b1 + MX6QDL_PAD_EIM_DA4__EIM_AD04 0xb0b1 + MX6QDL_PAD_EIM_DA3__EIM_AD03 0xb0b1 + MX6QDL_PAD_EIM_DA2__EIM_AD02 0xb0b1 + MX6QDL_PAD_EIM_DA1__EIM_AD01 0xb0b1 + MX6QDL_PAD_EIM_DA0__EIM_AD00 0xb0b1 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-sabrelite.dtsi index 9c502bf77d0bf0..bdef7e642d3cf2 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-sabrelite.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-sabrelite.dtsi @@ -389,243 +389,241 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6q-sabrelite { - pinctrl_hog: hoggrp { - fsl,pins = < - /* SGTL5000 sys_mclk */ - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + /* SGTL5000 sys_mclk */ + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 + >; + }; - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 - MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 - MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 - MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 + MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 + MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 + MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 + >; + }; - pinctrl_can1: can1grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 - MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 - >; - }; + pinctrl_can1: can1grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0 + MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0 + >; + }; - pinctrl_can_xcvr: can-xcvrgrp { - fsl,pins = < - /* Flexcan XCVR enable */ - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 - >; - }; + pinctrl_can_xcvr: can-xcvrgrp { + fsl,pins = < + /* Flexcan XCVR enable */ + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 /* CS */ - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 /* CS */ + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - /* Phy reset */ - MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x000b0 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x10030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x10030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x10030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x10030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x10030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x10030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + /* Phy reset */ + MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x000b0 + >; + }; - pinctrl_gpio_keys: gpio-keysgrp { - fsl,pins = < - /* Power Button */ - MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 - /* Menu Button */ - MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 - /* Home Button */ - MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 - /* Back Button */ - MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 - /* Volume Up Button */ - MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 - /* Volume Down Button */ - MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 - >; - }; + pinctrl_gpio_keys: gpio-keysgrp { + fsl,pins = < + /* Power Button */ + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 + /* Menu Button */ + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 + /* Home Button */ + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 + /* Back Button */ + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 + /* Volume Up Button */ + MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 + /* Volume Down Button */ + MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_ipu1_csi0: ipu1csi0grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b0 - MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x1b0b0 - MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x1b0b0 - MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x1b0b0 - MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x1b0b0 - MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x1b0b0 - MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x1b0b0 - MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x1b0b0 - MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x1b0b0 - MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x1b0b0 - MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x1b0b0 - MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x1b0b0 - >; - }; + pinctrl_ipu1_csi0: ipu1csi0grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b0 + MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x1b0b0 + MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x1b0b0 + MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x1b0b0 + MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x1b0b0 + MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x1b0b0 + MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x1b0b0 + MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x1b0b0 + MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x1b0b0 + MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x1b0b0 + MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x1b0b0 + MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x1b0b0 + >; + }; - pinctrl_j15: j15grp { - fsl,pins = < - MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 - MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 - MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 - MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 - MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 - MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 - MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 - MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 - MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 - MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 - MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 - MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 - MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 - MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 - MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 - MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 - MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 - MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 - MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 - MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 - MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 - MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 - MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 - MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 - MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 - MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 - MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 - MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 - >; - }; + pinctrl_j15: j15grp { + fsl,pins = < + MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 + MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 + MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 + MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 + MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 + MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 + MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 + MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 + MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 + MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 + MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 + MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 + MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 + MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 + MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 + MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 + MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 + MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 + MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 + MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 + MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 + MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 + MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 + MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 + MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 + MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 + MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 + MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 + >; + }; - pinctrl_ov5640: ov5640grp { - fsl,pins = < - MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x000b0 - MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x0b0b0 - >; - }; + pinctrl_ov5640: ov5640grp { + fsl,pins = < + MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x000b0 + MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x0b0b0 + >; + }; - pinctrl_ov5642: ov5642grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x1b0b0 - MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 - MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x130b0 - MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x000b0 - >; - }; + pinctrl_ov5642: ov5642grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x1b0b0 + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 + MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x130b0 + MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x000b0 + >; + }; - pinctrl_pwm1: pwm1grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 - >; - }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 + >; + }; - pinctrl_pwm3: pwm3grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 - >; - }; + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 + >; + }; - pinctrl_pwm4: pwm4grp { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 - >; - }; + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbh1: usbh1grp { - fsl,pins = < - MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x030b0 - >; - }; + pinctrl_usbh1: usbh1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x030b0 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 - /* power enable, high active */ - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 + /* power enable, high active */ + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* CD */ - MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 /* WP */ - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 /* CD */ + MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 /* WP */ + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */ - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-sabresd.dtsi index 8f4f5fba68cc5f..dc8298f6db34bd 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-sabresd.dtsi @@ -480,251 +480,247 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6qdl-sabresd { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 - MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 - MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 - MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 - MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x1b0b0 - MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0 - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 - MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 + MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 + MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 + MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 + MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x1b0b0 + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0 + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0 + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b0b0 + >; + }; - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1 - MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1 - MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1 - MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x1b0b0 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1 + MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1 + MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1 + MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x1b0b0 + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; - pinctrl_gpio_keys: gpio_keysgrp { - fsl,pins = < - MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0 - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 - MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x1b0b0 - >; - }; + pinctrl_gpio_keys: gpio_keysgrp { + fsl,pins = < + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 + MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x1b0b0 + >; + }; - pinctrl_hdmi_cec: hdmicecgrp { - fsl,pins = < - MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 - >; - }; + pinctrl_hdmi_cec: hdmicecgrp { + fsl,pins = < + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 + >; + }; - pinctrl_hp: hpgrp { - fsl,pins = < - MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x1b0b0 - MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 - >; - }; + pinctrl_hp: hpgrp { + fsl,pins = < + MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x1b0b0 + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 - MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 + MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 + >; + }; - pinctrl_i2c1_mma8451_int: i2c1mma8451intgrp { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0xb0b1 - >; - }; + pinctrl_i2c1_mma8451_int: i2c1mma8451intgrp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0xb0b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2_egalax_int: i2c2egalaxintgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x1b0b0 - >; - }; + pinctrl_i2c2_egalax_int: i2c2egalaxintgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x1b0b0 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3_isl29023_int: i2c3isl29023intgrp { - fsl,pins = < - MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0xb0b1 - >; - }; + pinctrl_i2c3_isl29023_int: i2c3isl29023intgrp { + fsl,pins = < + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0xb0b1 + >; + }; - pinctrl_i2c3_mag3110_int: i2c3mag3110intgrp { - fsl,pins = < - MX6QDL_PAD_EIM_D16__GPIO3_IO16 0xb0b1 - >; - }; + pinctrl_i2c3_mag3110_int: i2c3mag3110intgrp { + fsl,pins = < + MX6QDL_PAD_EIM_D16__GPIO3_IO16 0xb0b1 + >; + }; - pinctrl_ipu1_csi0: ipu1csi0grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b0 - MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x1b0b0 - MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x1b0b0 - MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x1b0b0 - MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x1b0b0 - MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x1b0b0 - MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x1b0b0 - MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x1b0b0 - MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x1b0b0 - MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x1b0b0 - MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x1b0b0 - >; - }; + pinctrl_ipu1_csi0: ipu1csi0grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x1b0b0 + MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x1b0b0 + MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x1b0b0 + MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x1b0b0 + MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x1b0b0 + MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x1b0b0 + MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x1b0b0 + MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x1b0b0 + MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x1b0b0 + MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x1b0b0 + MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x1b0b0 + >; + }; - pinctrl_ov5640: ov5640grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT2__GPIO1_IO19 0x1b0b0 - MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x1b0b0 - >; - }; + pinctrl_ov5640: ov5640grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT2__GPIO1_IO19 0x1b0b0 + MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x1b0b0 + >; + }; - pinctrl_ov5642: ov5642grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x1b0b0 - MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b0 - >; - }; + pinctrl_ov5642: ov5642grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x1b0b0 + MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x1b0b0 + >; + }; - pinctrl_pcie: pciegrp { - fsl,pins = < - MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0 - >; - }; + pinctrl_pcie: pciegrp { + fsl,pins = < + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x1b0b0 + >; + }; - pinctrl_pcie_reg: pciereggrp { - fsl,pins = < - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x1b0b0 - >; - }; + pinctrl_pcie_reg: pciereggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x1b0b0 + >; + }; - pinctrl_pwm1: pwm1grp { - fsl,pins = < - MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 - >; - }; + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 + >; + }; - pinctrl_sensors_reg: sensorsreggrp { - fsl,pins = < - MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x1b0b0 - >; - }; + pinctrl_sensors_reg: sensorsreggrp { + fsl,pins = < + MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x1b0b0 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x17059 - MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x17059 - MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x17059 - MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x17059 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x17059 + MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x17059 + MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x17059 + MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 - MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 - MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 - MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 - MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 - MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 - MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 - MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 - MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 - MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; + }; - pinctrl_wdog: wdoggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__WDOG2_B 0x1b0b0 - >; - }; + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__WDOG2_B 0x1b0b0 + >; }; - gpio_leds { - pinctrl_gpio_leds: gpioledsgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 - >; - }; + pinctrl_gpio_leds: gpioledsgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-solidsense.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-solidsense.dtsi index 234827e554d0f1..60e446ba8f523e 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-solidsense.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-solidsense.dtsi @@ -93,49 +93,47 @@ &i2c3 { &iomuxc { pinctrl-0 = <&pinctrl_hog>, <&pinctrl_solidsense_hog>; - solidsense { - pinctrl_solidsense_hog: solidsense-hog { - fsl,pins = < - /* Nordic RESET_N */ - MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x400130b1 - /* Nordic Chip 1 SWDIO - GPIO 125 */ - MX6QDL_PAD_DISP0_DAT8__GPIO4_IO29 0x400130b1 - /* Nordic Chip 1 SWDCLK - GPIO 59 */ - /* already claimed in the HB2 hogs */ - /* MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x400130b1 */ - /* Nordic Chip 2 SWDIO - GPIO 81 */ - MX6QDL_PAD_EIM_D17__GPIO3_IO17 0x400130b1 - /* Nordic Chip 2 SWCLK - GPIO 82 */ - MX6QDL_PAD_EIM_D18__GPIO3_IO18 0x400130b1 - >; - }; + pinctrl_solidsense_hog: solidsense-hoggrp { + fsl,pins = < + /* Nordic RESET_N */ + MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x400130b1 + /* Nordic Chip 1 SWDIO - GPIO 125 */ + MX6QDL_PAD_DISP0_DAT8__GPIO4_IO29 0x400130b1 + /* Nordic Chip 1 SWDCLK - GPIO 59 */ + /* already claimed in the HB2 hogs */ + /* MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x400130b1 */ + /* Nordic Chip 2 SWDIO - GPIO 81 */ + MX6QDL_PAD_EIM_D17__GPIO3_IO17 0x400130b1 + /* Nordic Chip 2 SWCLK - GPIO 82 */ + MX6QDL_PAD_EIM_D18__GPIO3_IO18 0x400130b1 + >; + }; - pinctrl_solidsense_leds: solidsense-leds { - fsl,pins = < - /* Red LED 1 - GPIO 58 */ - MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x400130b1 - /* Green LED 1 - GPIO 55 */ - MX6QDL_PAD_EIM_CS0__GPIO2_IO23 0x400130b1 - /* Red LED 2 - GPIO 57 */ - MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x400130b1 - /* Green LED 2 - GPIO 56 */ - MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x400130b1 - >; - }; + pinctrl_solidsense_leds: solidsense-ledsgrp { + fsl,pins = < + /* Red LED 1 - GPIO 58 */ + MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x400130b1 + /* Green LED 1 - GPIO 55 */ + MX6QDL_PAD_EIM_CS0__GPIO2_IO23 0x400130b1 + /* Red LED 2 - GPIO 57 */ + MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x400130b1 + /* Green LED 2 - GPIO 56 */ + MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x400130b1 + >; + }; - pinctrl_solidsense_uart2: solidsense-uart2 { - fsl,pins = < - MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_solidsense_uart2: solidsense-uart2grp { + fsl,pins = < + MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_solidsense_uart3: solidsense-uart3 { - fsl,pins = < - MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 - >; - }; + pinctrl_solidsense_uart3: solidsense-uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-brcm.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-brcm.dtsi index b55af61dfecab1..e491f5c9d45516 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-brcm.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-brcm.dtsi @@ -70,55 +70,53 @@ usdhc1_pwrseq: usdhc1_pwrseq { }; &iomuxc { - microsom { - pinctrl_microsom_brcm_bt: microsom-brcm-bt { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070 - MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x40013070 - MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070 - >; - }; + pinctrl_microsom_brcm_bt: microsom-brcm-btgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070 + MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x40013070 + MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070 + >; + }; - pinctrl_microsom_brcm_osc: microsom-brcm-osc { - fsl,pins = < - MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 - >; - }; + pinctrl_microsom_brcm_osc: microsom-brcm-oscgrp { + fsl,pins = < + MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 + >; + }; - pinctrl_microsom_brcm_reg: microsom-brcm-reg { - fsl,pins = < - MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070 - >; - }; + pinctrl_microsom_brcm_reg: microsom-brcm-reggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070 + >; + }; - pinctrl_microsom_brcm_wifi: microsom-brcm-wifi { - fsl,pins = < - MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0 - MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x40013070 - MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070 - MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x40013070 - >; - }; + pinctrl_microsom_brcm_wifi: microsom-brcm-wifigrp { + fsl,pins = < + MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0 + MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x40013070 + MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070 + MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x40013070 + >; + }; - pinctrl_microsom_uart4: microsom-uart4 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 - MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 - >; - }; + pinctrl_microsom_uart4: microsom-uart4grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 + MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 + >; + }; - pinctrl_microsom_usdhc1: microsom-usdhc1 { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 - MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 - MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 - MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 - MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 - MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 - >; - }; + pinctrl_microsom_usdhc1: microsom-usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-emmc.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-emmc.dtsi index 5f3b8baab20ffa..ddca24414d262f 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-emmc.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-emmc.dtsi @@ -40,22 +40,20 @@ */ &iomuxc { - microsom { - pinctrl_microsom_usdhc3: microsom-usdhc3 { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 - MX6QDL_PAD_SD3_RST__SD3_RESET 0x17059 - >; - }; + pinctrl_microsom_usdhc3: microsom-usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + MX6QDL_PAD_SD3_RST__SD3_RESET 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-ti.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-ti.dtsi index 352ac585ca6b82..cd1e682f11add2 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-ti.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som-ti.dtsi @@ -76,56 +76,54 @@ pwrseq_ti_wifi: ti-wifi-pwrseq { }; &iomuxc { - microsom { - pinctrl_microsom_ti_bt: microsom-ti-bt { - fsl,pins = < - /* BT_EN_SOC */ - MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070 - >; - }; + pinctrl_microsom_ti_bt: microsom-ti-btgrp { + fsl,pins = < + /* BT_EN_SOC */ + MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070 + >; + }; - pinctrl_microsom_ti_clk: microsom-ti-clk { - fsl,pins = < - /* EXT_32K */ - MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0 - /* WL_XTAL_PU (unrouted) */ - MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 - >; - }; + pinctrl_microsom_ti_clk: microsom-ti-clkgrp { + fsl,pins = < + /* EXT_32K */ + MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0 + /* WL_XTAL_PU (unrouted) */ + MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 + >; + }; - pinctrl_microsom_ti_wifi_en: microsom-ti-wifi-en { - fsl,pins = < - /* WLAN_EN_SOC */ - MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070 - >; - }; + pinctrl_microsom_ti_wifi_en: microsom-ti-wifi-engrp { + fsl,pins = < + /* WLAN_EN_SOC */ + MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070 + >; + }; - pinctrl_microsom_ti_wifi_irq: microsom-ti-wifi-irq { - fsl,pins = < - /* WLAN_IRQ */ - MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070 - >; - }; + pinctrl_microsom_ti_wifi_irq: microsom-ti-wifi-irqgrp { + fsl,pins = < + /* WLAN_IRQ */ + MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070 + >; + }; - pinctrl_microsom_uart4: microsom-uart4 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 - MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 - >; - }; + pinctrl_microsom_uart4: microsom-uart4grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 + MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 + >; + }; - pinctrl_microsom_usdhc1: microsom-usdhc1 { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 - MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 - MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 - MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 - MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 - MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 - >; - }; + pinctrl_microsom_usdhc1: microsom-usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som.dtsi index ce543e325cd307..7af74b203e399c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-sr-som.dtsi @@ -97,57 +97,55 @@ ethernet-phy@1 { }; &iomuxc { - microsom { - pinctrl_microsom_enet_ar8035: microsom-enet-ar8035 { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b8b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - /* AR8035 reset */ - MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x130b0 - /* AR8035 interrupt */ - MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x1b0b0 - /* GPIO16 -> AR8035 25MHz */ - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x13030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */ - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x0a0b1 - /* AR8035 pin strapping: IO voltage: pull up */ - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - /* AR8035 pin strapping: PHYADDR#0: pull down */ - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x13030 - /* AR8035 pin strapping: PHYADDR#1: pull down */ - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030 - /* AR8035 pin strapping: MODE#1: pull up */ - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - /* AR8035 pin strapping: MODE#3: pull up */ - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - /* AR8035 pin strapping: MODE#0: pull down */ - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x13030 + pinctrl_microsom_enet_ar8035: microsom-enet-ar8035grp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b8b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + /* AR8035 reset */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x130b0 + /* AR8035 interrupt */ + MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x1b0b0 + /* GPIO16 -> AR8035 25MHz */ + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x13030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */ + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x0a0b1 + /* AR8035 pin strapping: IO voltage: pull up */ + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + /* AR8035 pin strapping: PHYADDR#0: pull down */ + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x13030 + /* AR8035 pin strapping: PHYADDR#1: pull down */ + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030 + /* AR8035 pin strapping: MODE#1: pull up */ + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + /* AR8035 pin strapping: MODE#3: pull up */ + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + /* AR8035 pin strapping: MODE#0: pull down */ + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x13030 - /* - * As the RMII pins are also connected to RGMII - * so that an AR8030 can be placed, set these - * to high-z with the same pulls as above. - * Use the GPIO settings to avoid changing the - * input select registers. - */ - MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x03000 - MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x03000 - MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x03000 - >; - }; + /* + * As the RMII pins are also connected to RGMII + * so that an AR8030 can be placed, set these + * to high-z with the same pulls as above. + * Use the GPIO settings to avoid changing the + * input select registers. + */ + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x03000 + MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x03000 + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x03000 + >; + }; - pinctrl_microsom_uart1: microsom-uart1 { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_microsom_uart1: microsom-uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-ts7970.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-ts7970.dtsi index e2db875b61c4e4..11c70431feec90 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-ts7970.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-ts7970.dtsi @@ -265,7 +265,7 @@ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x100b1 /* Onboard Flash CS */ >; }; - pinctrl_ecspi2: ecspi2 { + pinctrl_ecspi2: ecspi2grp { fsl,pins = < MX6QDL_PAD_CSI0_DAT8__ECSPI2_SCLK 0x100b1 MX6QDL_PAD_CSI0_DAT9__ECSPI2_MOSI 0x100b1 @@ -280,7 +280,7 @@ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b088 /* FPGA_IRQ_1 */ >; }; - pinctrl_enet: enet { + pinctrl_enet: enetgrp { fsl,pins = < MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6-lcd.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6-lcd.dtsi index ded241a39906b2..77594546ef3768 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6-lcd.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6-lcd.dtsi @@ -51,7 +51,6 @@ backlight: backlight { pinctrl-0 = <&pinctrl_lcd1_pwr>; enable-gpios = <&gpio2 31 GPIO_ACTIVE_HIGH>; power-supply = <®_3v3>; - turn-on-delay-ms = <35>; /* * a poor man's way to create a 1:1 relationship between * the PWM value and the actual duty cycle diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6-mb7.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6-mb7.dtsi index 99ec7a838f8d27..bae7313d729d95 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6-mb7.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6-mb7.dtsi @@ -42,13 +42,11 @@ / { backlight0 { pwms = <&pwm1 0 500000 PWM_POLARITY_INVERTED>; - turn-on-delay-ms = <35>; power-supply = <®_lcd1_pwr>; }; backlight1 { pwms = <&pwm2 0 500000 PWM_POLARITY_INVERTED>; - turn-on-delay-ms = <35>; power-supply = <®_lcd1_pwr>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6.dtsi index 5a194f4c0cb9b3..2fa37d1b16cc04 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-tx6.dtsi @@ -70,9 +70,8 @@ clocks { #address-cells = <1>; #size-cells = <0>; - mclk: clock@0 { + mclk: clock { compatible = "fixed-clock"; - reg = <0>; #clock-cells = <0>; clock-frequency = <26000000>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-udoo.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-udoo.dtsi index 14272b42f9a1ae..2be7dc4a978180 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-udoo.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-udoo.dtsi @@ -117,132 +117,130 @@ touchscreenp7: touchscreenp7@55 { }; &iomuxc { - imx6q-udoo { - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001f8b1 - MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001f8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001f8b1 + MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001f8b1 + >; + }; - pinctrl_panel: panelgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x70 - MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x70 - >; - }; + pinctrl_panel: panelgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x70 + MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x70 + >; + }; - pinctrl_power_off: poweroffgrp { - fsl,pins = < - MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x30 - >; - }; + pinctrl_power_off: poweroffgrp { + fsl,pins = < + MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x30 + >; + }; - pinctrl_touchscreenp7: touchscreenp7grp { - fsl,pins = < - MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x70 - MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x1b0b0 - >; - }; + pinctrl_touchscreenp7: touchscreenp7grp { + fsl,pins = < + MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x70 + MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x1b0b0 + >; + }; - pinctrl_uart2: uart2grp { - fsl,pins = < - MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart4: uart4grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 - MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart4: uart4grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 + MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 + >; + }; - pinctrl_usbh: usbhgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 - MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0 - >; - }; + pinctrl_usbh: usbhgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 + MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x130b0 + >; + }; - pinctrl_usbotg: usbotg { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - MX6QDL_PAD_EIM_D22__USB_OTG_PWR 0x17059 - MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x17059 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + MX6QDL_PAD_EIM_D22__USB_OTG_PWR 0x17059 + MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0 + >; + }; - pinctrl_ac97_running: ac97running { - fsl,pins = < - MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x1b0b0 - MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x1b0b0 - MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 - MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 - MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 - >; - }; + pinctrl_ac97_running: ac97runninggrp { + fsl,pins = < + MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x1b0b0 + MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x1b0b0 + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 + MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 + >; + }; - pinctrl_ac97_warm_reset: ac97warmreset { - fsl,pins = < - MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x1b0b0 - MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x1b0b0 - MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 - MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 - MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 - >; - }; + pinctrl_ac97_warm_reset: ac97warmresetgrp { + fsl,pins = < + MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x1b0b0 + MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x1b0b0 + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 + MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 + >; + }; - pinctrl_ac97_reset: ac97reset { - fsl,pins = < - MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x1b0b0 - MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x1b0b0 - MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 - MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 - MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 - >; - }; + pinctrl_ac97_reset: ac97resetgrp { + fsl,pins = < + MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x1b0b0 + MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x1b0b0 + MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x13080 + MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x13080 + MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1b0b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-var-dart.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-var-dart.dtsi index d8283eade43e7c..7749074e438d85 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-var-dart.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-var-dart.dtsi @@ -194,7 +194,7 @@ &i2c3 { }; &iomuxc { - pinctrl_audmux: audmux { + pinctrl_audmux: audmuxgrp { fsl,pins = < MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 @@ -205,7 +205,7 @@ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 >; }; - pinctrl_bt: bt { + pinctrl_bt: btgrp { fsl,pins = < /* Bluetooth enable */ MX6QDL_PAD_SD3_DAT6__GPIO6_IO18 0x1b0b1 diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-var-som.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-var-som.dtsi index 59833e8d11d862..2bff5f92242ac6 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-var-som.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-var-som.dtsi @@ -529,11 +529,11 @@ &usbotg { }; &usbphy1 { - fsl,tx-d-cal = <0x5>; + fsl,tx-d-cal = <106>; }; &usbphy2 { - fsl,tx-d-cal = <0x5>; + fsl,tx-d-cal = <106>; }; &usdhc1 { diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revb1.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revb1.dtsi index e781a45785ed8a..3a21ae94227337 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revb1.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revb1.dtsi @@ -9,22 +9,20 @@ &iomuxc { pinctrl-0 = <&pinctrl_hog>; - imx6qdl-wandboard { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* uSDHC1 CD */ - MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 /* uSDHC3 CD */ - MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x0f0b0 /* WL_REF_ON */ - MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x0f0b0 /* WL_RST_N */ - MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x000b0 /* WL_REG_ON */ - MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* WL_HOST_WAKE */ - MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* WL_WAKE */ - MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 /* RGMII_nRST */ - MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x80000000 /* BT_ON */ - MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x80000000 /* BT_WAKE */ - MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x80000000 /* BT_HOST_WAKE */ - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* uSDHC1 CD */ + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 /* uSDHC3 CD */ + MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x0f0b0 /* WL_REF_ON */ + MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x0f0b0 /* WL_RST_N */ + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x000b0 /* WL_REG_ON */ + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* WL_HOST_WAKE */ + MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* WL_WAKE */ + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 /* RGMII_nRST */ + MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x80000000 /* BT_ON */ + MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x80000000 /* BT_WAKE */ + MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x80000000 /* BT_HOST_WAKE */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revc1.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revc1.dtsi index 3874e74703f09c..cc707972f548cf 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revc1.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revc1.dtsi @@ -7,24 +7,22 @@ #include "imx6qdl-wandboard.dtsi" &iomuxc { - pinctrl-0 = <&pinctrl_hog>; + pinctrl-0 = <&pinctrl_hog_c1>; - imx6qdl-wandboard { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* uSDHC1 CD */ - MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 /* uSDHC3 CD */ - MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x0f0b0 /* WIFI_ON (reset, active low) */ - MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x000b0 /* WL_REG_ON (unused) */ - MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* WL_HOST_WAKE, input */ - MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31 0x0f0b0 /* GPIO5_IO31 (Wifi Power Enable) */ - MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* WL_WAKE (unused) */ - MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x80000000 /* BT_ON */ - MX6QDL_PAD_CSI0_DAT12__GPIO5_IO30 0x80000000 /* BT_WAKE */ - MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x80000000 /* BT_HOST_WAKE */ - MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 /* RGMII_nRST */ - >; - }; + pinctrl_hog_c1: hogc1grp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* uSDHC1 CD */ + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 /* uSDHC3 CD */ + MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x0f0b0 /* WIFI_ON (reset, active low) */ + MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x000b0 /* WL_REG_ON (unused) */ + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* WL_HOST_WAKE, input */ + MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31 0x0f0b0 /* GPIO5_IO31 (Wifi Power Enable) */ + MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* WL_WAKE (unused) */ + MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x80000000 /* BT_ON */ + MX6QDL_PAD_CSI0_DAT12__GPIO5_IO30 0x80000000 /* BT_WAKE */ + MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x80000000 /* BT_HOST_WAKE */ + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 /* RGMII_nRST */ + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revd1.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revd1.dtsi index 9b8c9c23ab5475..8d44e758f1f338 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revd1.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard-revd1.dtsi @@ -137,49 +137,47 @@ &fec { }; &iomuxc { - pinctrl-0 = <&pinctrl_hog>; - - imx6qdl-wandboard { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* USDHC1 CD */ - MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 /* uSDHC3 CD */ - MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1f0b1 /* RGMII PHY reset */ - >; - }; + pinctrl-0 = <&pinctrl_hog_d1>; + + pinctrl_hog_d1: hoggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* USDHC1 CD */ + MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 /* uSDHC3 CD */ + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1f0b1 /* RGMII PHY reset */ + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - >; - }; + enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 - MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 + MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 + >; + }; - pinctrl_spdif: spdifgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x1b0b0 - >; - }; + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x1b0b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard.dtsi index 7130b9c3b3aa05..26489eccd5fbe4 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-wandboard.dtsi @@ -157,146 +157,143 @@ ov5645_to_mipi_csi2: endpoint { &iomuxc { pinctrl-names = "default"; - imx6qdl-wandboard { - - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 - MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 - MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 - MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 + MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 + MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 + MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 + >; + }; - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 - MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b030 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b030 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b030 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b030 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 - MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 + MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c1_gpio: i2c1gpiogrp { - fsl,pins = < - MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x4001b8b0 - MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x4001b8b0 - >; - }; + pinctrl_i2c1_gpio: i2c1gpiogrp { + fsl,pins = < + MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x4001b8b0 + MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x4001b8b0 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 - MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2_gpio: i2c2gpiogrp { - fsl,pins = < - MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x4001b8b0 - MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x4001b8b0 - >; - }; + pinctrl_i2c2_gpio: i2c2gpiogrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x4001b8b0 + MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x4001b8b0 + >; + }; - pinctrl_mclk: mclkgrp { - fsl,pins = < - MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 - >; - }; + pinctrl_mclk: mclkgrp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 + >; + }; - pinctrl_ov5645: ov5645grp { - fsl,pins = < - MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x000b0 - MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 - MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 - >; - }; + pinctrl_ov5645: ov5645grp { + fsl,pins = < + MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x000b0 + MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x1b0b0 + MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x1b0b0 + >; + }; - pinctrl_spdif: spdifgrp { - fsl,pins = < - MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1b0b0 - >; - }; + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1b0b0 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 - MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 + MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 + >; + }; - pinctrl_uart3: uart3grp { - fsl,pins = < - MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 - MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 - MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 - >; - }; + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 + MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 + MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 + >; + }; - pinctrl_usbotg: usbotggrp { - fsl,pins = < - MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 - >; - }; + pinctrl_usbotg: usbotggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 + >; + }; - pinctrl_usbotgvbus: usbotgvbusgrp { - fsl,pins = < - MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x130b0 - >; - }; + pinctrl_usbotgvbus: usbotgvbusgrp { + fsl,pins = < + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x130b0 + >; + }; - pinctrl_usdhc1: usdhc1grp { - fsl,pins = < - MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 - MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 - MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 - MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 - MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 - MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 - >; - }; + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qp-prtwd3.dts b/arch/arm/boot/dts/nxp/imx/imx6qp-prtwd3.dts index ae00d538a4dfc3..fbe260c9872e36 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qp-prtwd3.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6qp-prtwd3.dts @@ -548,7 +548,7 @@ MX6QDL_PAD_SD3_RST__SD3_RESET 0x1b0b1 >; }; - pinctrl_wifi_npd: wifinpd { + pinctrl_wifi_npd: wifinpdgrp { fsl,pins = < /* WL_REG_ON */ MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x13069 diff --git a/arch/arm/boot/dts/nxp/imx/imx6qp-sabreauto.dts b/arch/arm/boot/dts/nxp/imx/imx6qp-sabreauto.dts index 2bb3bfb18ec3e2..c5b220aeaefd6c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qp-sabreauto.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6qp-sabreauto.dts @@ -22,27 +22,25 @@ max7322: gpio@68 { }; &iomuxc { - imx6qdl-sabreauto { - pinctrl_enet: enetgrp { - fsl,pins = < - MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 - MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 - MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b018 - MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b018 - MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b018 - MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b018 - MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b018 - MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b018 - MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b018 - MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b018 - MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b018 - MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b018 - MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b018 - MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b018 - MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 - MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 - >; - }; + pinctrl_enet: enetgrp { + fsl,pins = < + MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 + MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 + MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b018 + MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b018 + MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b018 + MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b018 + MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b018 + MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b018 + MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b018 + MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b018 + MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b018 + MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b018 + MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b018 + MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b018 + MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 + MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qp-sabresd.dts b/arch/arm/boot/dts/nxp/imx/imx6qp-sabresd.dts index f69eec18d8657b..792697bd45512c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qp-sabresd.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6qp-sabresd.dts @@ -17,36 +17,34 @@ ®_arm { }; &iomuxc { - imx6qdl-sabresd { - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10071 - MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x17059 - MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x17059 - MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x17059 - MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x17059 - >; - }; - - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10071 - MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 - MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 - MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 - MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10071 + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x17059 + MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x17059 + MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x17059 + MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x17059 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10071 + MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 + MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 + MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 + MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6s-dhcom-drc02.dts b/arch/arm/boot/dts/nxp/imx/imx6s-dhcom-drc02.dts index 4077b607c29ea9..e42c274a9014e8 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6s-dhcom-drc02.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6s-dhcom-drc02.dts @@ -3,7 +3,7 @@ * Copyright (C) 2021 DH electronics GmbH * * DHCOM iMX6 variant: - * DHCM-iMX6S-C0800-R102-F0409-E-CAN2-RTC-I-01D2 + * DHCM-iMX6S-C080-R102-F0409-E-CAN2-RTC-I-01D2 * DHCOM PCB number: 493-400 or newer * DRC02 PCB number: 568-100 or newer */ diff --git a/arch/arm/boot/dts/nxp/imx/imx6sl-evk.dts b/arch/arm/boot/dts/nxp/imx/imx6sl-evk.dts index 7c899291ab0dad..55cdfa7ea20675 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sl-evk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sl-evk.dts @@ -287,271 +287,269 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; - imx6sl-evk { - pinctrl_hog: hoggrp { - fsl,pins = < - MX6SL_PAD_KEY_ROW7__GPIO4_IO07 0x17059 - MX6SL_PAD_KEY_COL7__GPIO4_IO06 0x17059 - MX6SL_PAD_SD2_DAT7__GPIO5_IO00 0x17059 - MX6SL_PAD_SD2_DAT6__GPIO4_IO29 0x17059 - MX6SL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059 - MX6SL_PAD_KEY_COL4__GPIO4_IO00 0x80000000 - MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000 - MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0 - >; - }; + pinctrl_hog: hoggrp { + fsl,pins = < + MX6SL_PAD_KEY_ROW7__GPIO4_IO07 0x17059 + MX6SL_PAD_KEY_COL7__GPIO4_IO06 0x17059 + MX6SL_PAD_SD2_DAT7__GPIO5_IO00 0x17059 + MX6SL_PAD_SD2_DAT6__GPIO4_IO29 0x17059 + MX6SL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059 + MX6SL_PAD_KEY_COL4__GPIO4_IO00 0x80000000 + MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000 + MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0 + >; + }; - pinctrl_audmux3: audmux3grp { - fsl,pins = < - MX6SL_PAD_AUD_RXD__AUD3_RXD 0x4130b0 - MX6SL_PAD_AUD_TXC__AUD3_TXC 0x4130b0 - MX6SL_PAD_AUD_TXD__AUD3_TXD 0x4110b0 - MX6SL_PAD_AUD_TXFS__AUD3_TXFS 0x4130b0 - >; - }; + pinctrl_audmux3: audmux3grp { + fsl,pins = < + MX6SL_PAD_AUD_RXD__AUD3_RXD 0x4130b0 + MX6SL_PAD_AUD_TXC__AUD3_TXC 0x4130b0 + MX6SL_PAD_AUD_TXD__AUD3_TXD 0x4110b0 + MX6SL_PAD_AUD_TXFS__AUD3_TXFS 0x4130b0 + >; + }; - pinctrl_ecspi1: ecspi1grp { - fsl,pins = < - MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1 - MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1 - MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1 - MX6SL_PAD_ECSPI1_SS0__GPIO4_IO11 0x80000000 - >; - }; + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1 + MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1 + MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1 + MX6SL_PAD_ECSPI1_SS0__GPIO4_IO11 0x80000000 + >; + }; - pinctrl_fec: fecgrp { - fsl,pins = < - MX6SL_PAD_FEC_MDC__FEC_MDC 0x1b0b0 - MX6SL_PAD_FEC_MDIO__FEC_MDIO 0x1b0b0 - MX6SL_PAD_FEC_CRS_DV__FEC_RX_DV 0x1b0b0 - MX6SL_PAD_FEC_RXD0__FEC_RX_DATA0 0x1b0b0 - MX6SL_PAD_FEC_RXD1__FEC_RX_DATA1 0x1b0b0 - MX6SL_PAD_FEC_TX_EN__FEC_TX_EN 0x1b0b0 - MX6SL_PAD_FEC_TXD0__FEC_TX_DATA0 0x1b0b0 - MX6SL_PAD_FEC_TXD1__FEC_TX_DATA1 0x1b0b0 - MX6SL_PAD_FEC_REF_CLK__FEC_REF_OUT 0x4001b0a8 - >; - }; + pinctrl_fec: fecgrp { + fsl,pins = < + MX6SL_PAD_FEC_MDC__FEC_MDC 0x1b0b0 + MX6SL_PAD_FEC_MDIO__FEC_MDIO 0x1b0b0 + MX6SL_PAD_FEC_CRS_DV__FEC_RX_DV 0x1b0b0 + MX6SL_PAD_FEC_RXD0__FEC_RX_DATA0 0x1b0b0 + MX6SL_PAD_FEC_RXD1__FEC_RX_DATA1 0x1b0b0 + MX6SL_PAD_FEC_TX_EN__FEC_TX_EN 0x1b0b0 + MX6SL_PAD_FEC_TXD0__FEC_TX_DATA0 0x1b0b0 + MX6SL_PAD_FEC_TXD1__FEC_TX_DATA1 0x1b0b0 + MX6SL_PAD_FEC_REF_CLK__FEC_REF_OUT 0x4001b0a8 + >; + }; - pinctrl_fec_sleep: fecgrp-sleep { - fsl,pins = < - MX6SL_PAD_FEC_MDC__GPIO4_IO23 0x3080 - MX6SL_PAD_FEC_CRS_DV__GPIO4_IO25 0x3080 - MX6SL_PAD_FEC_RXD0__GPIO4_IO17 0x3080 - MX6SL_PAD_FEC_RXD1__GPIO4_IO18 0x3080 - MX6SL_PAD_FEC_TX_EN__GPIO4_IO22 0x3080 - MX6SL_PAD_FEC_TXD0__GPIO4_IO24 0x3080 - MX6SL_PAD_FEC_TXD1__GPIO4_IO16 0x3080 - MX6SL_PAD_FEC_REF_CLK__GPIO4_IO26 0x3080 - >; - }; + pinctrl_fec_sleep: fec-sleep-grp { + fsl,pins = < + MX6SL_PAD_FEC_MDC__GPIO4_IO23 0x3080 + MX6SL_PAD_FEC_CRS_DV__GPIO4_IO25 0x3080 + MX6SL_PAD_FEC_RXD0__GPIO4_IO17 0x3080 + MX6SL_PAD_FEC_RXD1__GPIO4_IO18 0x3080 + MX6SL_PAD_FEC_TX_EN__GPIO4_IO22 0x3080 + MX6SL_PAD_FEC_TXD0__GPIO4_IO24 0x3080 + MX6SL_PAD_FEC_TXD1__GPIO4_IO16 0x3080 + MX6SL_PAD_FEC_REF_CLK__GPIO4_IO26 0x3080 + >; + }; - pinctrl_hp: hpgrp { - fsl,pins = < - MX6SL_PAD_FEC_RX_ER__GPIO4_IO19 0x1b0b0 - >; - }; + pinctrl_hp: hpgrp { + fsl,pins = < + MX6SL_PAD_FEC_RX_ER__GPIO4_IO19 0x1b0b0 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1 - MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1 + MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1 + >; + }; - pinctrl_i2c2: i2c2grp { - fsl,pins = < - MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x4001b8b1 - MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001b8b1 - >; - }; + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x4001b8b1 + MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001b8b1 + >; + }; - pinctrl_kpp: kppgrp { - fsl,pins = < - MX6SL_PAD_KEY_ROW0__KEY_ROW0 0x1b010 - MX6SL_PAD_KEY_ROW1__KEY_ROW1 0x1b010 - MX6SL_PAD_KEY_ROW2__KEY_ROW2 0x1b0b0 - MX6SL_PAD_KEY_COL0__KEY_COL0 0x110b0 - MX6SL_PAD_KEY_COL1__KEY_COL1 0x110b0 - MX6SL_PAD_KEY_COL2__KEY_COL2 0x110b0 - >; - }; + pinctrl_kpp: kppgrp { + fsl,pins = < + MX6SL_PAD_KEY_ROW0__KEY_ROW0 0x1b010 + MX6SL_PAD_KEY_ROW1__KEY_ROW1 0x1b010 + MX6SL_PAD_KEY_ROW2__KEY_ROW2 0x1b0b0 + MX6SL_PAD_KEY_COL0__KEY_COL0 0x110b0 + MX6SL_PAD_KEY_COL1__KEY_COL1 0x110b0 + MX6SL_PAD_KEY_COL2__KEY_COL2 0x110b0 + >; + }; - pinctrl_lcd: lcdgrp { - fsl,pins = < - MX6SL_PAD_LCD_DAT0__LCD_DATA00 0x1b0b0 - MX6SL_PAD_LCD_DAT1__LCD_DATA01 0x1b0b0 - MX6SL_PAD_LCD_DAT2__LCD_DATA02 0x1b0b0 - MX6SL_PAD_LCD_DAT3__LCD_DATA03 0x1b0b0 - MX6SL_PAD_LCD_DAT4__LCD_DATA04 0x1b0b0 - MX6SL_PAD_LCD_DAT5__LCD_DATA05 0x1b0b0 - MX6SL_PAD_LCD_DAT6__LCD_DATA06 0x1b0b0 - MX6SL_PAD_LCD_DAT7__LCD_DATA07 0x1b0b0 - MX6SL_PAD_LCD_DAT8__LCD_DATA08 0x1b0b0 - MX6SL_PAD_LCD_DAT9__LCD_DATA09 0x1b0b0 - MX6SL_PAD_LCD_DAT10__LCD_DATA10 0x1b0b0 - MX6SL_PAD_LCD_DAT11__LCD_DATA11 0x1b0b0 - MX6SL_PAD_LCD_DAT12__LCD_DATA12 0x1b0b0 - MX6SL_PAD_LCD_DAT13__LCD_DATA13 0x1b0b0 - MX6SL_PAD_LCD_DAT14__LCD_DATA14 0x1b0b0 - MX6SL_PAD_LCD_DAT15__LCD_DATA15 0x1b0b0 - MX6SL_PAD_LCD_DAT16__LCD_DATA16 0x1b0b0 - MX6SL_PAD_LCD_DAT17__LCD_DATA17 0x1b0b0 - MX6SL_PAD_LCD_DAT18__LCD_DATA18 0x1b0b0 - MX6SL_PAD_LCD_DAT19__LCD_DATA19 0x1b0b0 - MX6SL_PAD_LCD_DAT20__LCD_DATA20 0x1b0b0 - MX6SL_PAD_LCD_DAT21__LCD_DATA21 0x1b0b0 - MX6SL_PAD_LCD_DAT22__LCD_DATA22 0x1b0b0 - MX6SL_PAD_LCD_DAT23__LCD_DATA23 0x1b0b0 - MX6SL_PAD_LCD_CLK__LCD_CLK 0x1b0b0 - MX6SL_PAD_LCD_ENABLE__LCD_ENABLE 0x1b0b0 - MX6SL_PAD_LCD_HSYNC__LCD_HSYNC 0x1b0b0 - MX6SL_PAD_LCD_VSYNC__LCD_VSYNC 0x1b0b0 - >; - }; + pinctrl_lcd: lcdgrp { + fsl,pins = < + MX6SL_PAD_LCD_DAT0__LCD_DATA00 0x1b0b0 + MX6SL_PAD_LCD_DAT1__LCD_DATA01 0x1b0b0 + MX6SL_PAD_LCD_DAT2__LCD_DATA02 0x1b0b0 + MX6SL_PAD_LCD_DAT3__LCD_DATA03 0x1b0b0 + MX6SL_PAD_LCD_DAT4__LCD_DATA04 0x1b0b0 + MX6SL_PAD_LCD_DAT5__LCD_DATA05 0x1b0b0 + MX6SL_PAD_LCD_DAT6__LCD_DATA06 0x1b0b0 + MX6SL_PAD_LCD_DAT7__LCD_DATA07 0x1b0b0 + MX6SL_PAD_LCD_DAT8__LCD_DATA08 0x1b0b0 + MX6SL_PAD_LCD_DAT9__LCD_DATA09 0x1b0b0 + MX6SL_PAD_LCD_DAT10__LCD_DATA10 0x1b0b0 + MX6SL_PAD_LCD_DAT11__LCD_DATA11 0x1b0b0 + MX6SL_PAD_LCD_DAT12__LCD_DATA12 0x1b0b0 + MX6SL_PAD_LCD_DAT13__LCD_DATA13 0x1b0b0 + MX6SL_PAD_LCD_DAT14__LCD_DATA14 0x1b0b0 + MX6SL_PAD_LCD_DAT15__LCD_DATA15 0x1b0b0 + MX6SL_PAD_LCD_DAT16__LCD_DATA16 0x1b0b0 + MX6SL_PAD_LCD_DAT17__LCD_DATA17 0x1b0b0 + MX6SL_PAD_LCD_DAT18__LCD_DATA18 0x1b0b0 + MX6SL_PAD_LCD_DAT19__LCD_DATA19 0x1b0b0 + MX6SL_PAD_LCD_DAT20__LCD_DATA20 0x1b0b0 + MX6SL_PAD_LCD_DAT21__LCD_DATA21 0x1b0b0 + MX6SL_PAD_LCD_DAT22__LCD_DATA22 0x1b0b0 + MX6SL_PAD_LCD_DAT23__LCD_DATA23 0x1b0b0 + MX6SL_PAD_LCD_CLK__LCD_CLK 0x1b0b0 + MX6SL_PAD_LCD_ENABLE__LCD_ENABLE 0x1b0b0 + MX6SL_PAD_LCD_HSYNC__LCD_HSYNC 0x1b0b0 + MX6SL_PAD_LCD_VSYNC__LCD_VSYNC 0x1b0b0 + >; + }; - pinctrl_led: ledgrp { - fsl,pins = < - MX6SL_PAD_HSIC_STROBE__GPIO3_IO20 0x17059 - >; - }; + pinctrl_led: ledgrp { + fsl,pins = < + MX6SL_PAD_HSIC_STROBE__GPIO3_IO20 0x17059 + >; + }; - pinctrl_pwm1: pwmgrp { - fsl,pins = < - MX6SL_PAD_PWM1__PWM1_OUT 0x110b0 - >; - }; + pinctrl_pwm1: pwmgrp { + fsl,pins = < + MX6SL_PAD_PWM1__PWM1_OUT 0x110b0 + >; + }; - pinctrl_reg_lcd_3v3: reglcd3v3grp { - fsl,pins = < - MX6SL_PAD_KEY_ROW5__GPIO4_IO03 0x17059 - >; - }; + pinctrl_reg_lcd_3v3: reglcd3v3grp { + fsl,pins = < + MX6SL_PAD_KEY_ROW5__GPIO4_IO03 0x17059 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 - MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 + MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 + >; + }; - pinctrl_usbotg1: usbotg1grp { - fsl,pins = < - MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 - >; - }; + pinctrl_usbotg1: usbotg1grp { + fsl,pins = < + MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 + >; + }; - pinctrl_usdhc1: usdhc1grp { - fsl,pins = < - MX6SL_PAD_SD1_CMD__SD1_CMD 0x17059 - MX6SL_PAD_SD1_CLK__SD1_CLK 0x10059 - MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x17059 - MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x17059 - MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x17059 - MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x17059 - MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x17059 - MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x17059 - MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x17059 - MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x17059 - >; - }; + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX6SL_PAD_SD1_CMD__SD1_CMD 0x17059 + MX6SL_PAD_SD1_CLK__SD1_CLK 0x10059 + MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x17059 + MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x17059 + MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x17059 + MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x17059 + MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x17059 + MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x17059 + MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x17059 + MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x17059 + >; + }; - pinctrl_usdhc1_100mhz: usdhc1-100mhz-grp { - fsl,pins = < - MX6SL_PAD_SD1_CMD__SD1_CMD 0x170b9 - MX6SL_PAD_SD1_CLK__SD1_CLK 0x100b9 - MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170b9 - MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170b9 - MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170b9 - MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170b9 - MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170b9 - MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170b9 - MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170b9 - MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170b9 - >; - }; + pinctrl_usdhc1_100mhz: usdhc1-100mhz-grp { + fsl,pins = < + MX6SL_PAD_SD1_CMD__SD1_CMD 0x170b9 + MX6SL_PAD_SD1_CLK__SD1_CLK 0x100b9 + MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170b9 + MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170b9 + MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170b9 + MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170b9 + MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170b9 + MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170b9 + MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170b9 + MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170b9 + >; + }; - pinctrl_usdhc1_200mhz: usdhc1-200mhz-grp { - fsl,pins = < - MX6SL_PAD_SD1_CMD__SD1_CMD 0x170f9 - MX6SL_PAD_SD1_CLK__SD1_CLK 0x100f9 - MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170f9 - MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170f9 - MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170f9 - MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170f9 - MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170f9 - MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170f9 - MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170f9 - MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170f9 - >; - }; + pinctrl_usdhc1_200mhz: usdhc1-200mhz-grp { + fsl,pins = < + MX6SL_PAD_SD1_CMD__SD1_CMD 0x170f9 + MX6SL_PAD_SD1_CLK__SD1_CLK 0x100f9 + MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170f9 + MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170f9 + MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170f9 + MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170f9 + MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170f9 + MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170f9 + MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170f9 + MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170f9 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x17059 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x10059 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x17059 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x17059 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x17059 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x10059 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x17059 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x17059 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x17059 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059 + >; + }; - pinctrl_usdhc2_100mhz: usdhc2-100mhz-grp { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x170b9 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x100b9 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 - >; - }; + pinctrl_usdhc2_100mhz: usdhc2-100mhz-grp { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x100b9 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 + >; + }; - pinctrl_usdhc2_200mhz: usdhc2-200mhz-grp { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x100f9 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 - >; - }; + pinctrl_usdhc2_200mhz: usdhc2-200mhz-grp { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x100f9 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x17059 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x10059 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x17059 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x17059 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x17059 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x17059 - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x17059 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x10059 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x17059 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x17059 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x17059 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x17059 + >; + }; - pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x100b9 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 - >; - }; + pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x100b9 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 + >; + }; - pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x100f9 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 - >; - }; + pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x100f9 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine2hd.dts b/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine2hd.dts index 03d6965f014957..56040da0bd25d1 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine2hd.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine2hd.dts @@ -382,7 +382,7 @@ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001f8b1 >; }; - pinctrl_i2c1_sleep: i2c1grp-sleep { + pinctrl_i2c1_sleep: i2c1sleep-grp { fsl,pins = < MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x400108b1 MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x400108b1 @@ -396,7 +396,7 @@ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001f8b1 >; }; - pinctrl_i2c2_sleep: i2c2grp-sleep { + pinctrl_i2c2_sleep: i2c2sleep-grp { fsl,pins = < MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x400108b1 MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x400108b1 @@ -456,7 +456,7 @@ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059 >; }; - pinctrl_usdhc2_100mhz: usdhc2grp-100mhz { + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { fsl,pins = < MX6SL_PAD_SD2_CMD__SD2_CMD 0x170b9 MX6SL_PAD_SD2_CLK__SD2_CLK 0x130b9 @@ -467,7 +467,7 @@ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 >; }; - pinctrl_usdhc2_200mhz: usdhc2grp-200mhz { + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { fsl,pins = < MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9 MX6SL_PAD_SD2_CLK__SD2_CLK 0x130f9 @@ -478,7 +478,7 @@ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 >; }; - pinctrl_usdhc2_sleep: usdhc2grp-sleep { + pinctrl_usdhc2_sleep: usdhc2sleep-grp { fsl,pins = < MX6SL_PAD_SD2_CMD__GPIO5_IO04 0x100f9 MX6SL_PAD_SD2_CLK__GPIO5_IO05 0x100f9 @@ -500,7 +500,7 @@ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x11059 >; }; - pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { fsl,pins = < MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9 MX6SL_PAD_SD3_CLK__SD3_CLK 0x170b9 @@ -511,7 +511,7 @@ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 >; }; - pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { fsl,pins = < MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9 MX6SL_PAD_SD3_CLK__SD3_CLK 0x170f9 @@ -522,7 +522,7 @@ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 >; }; - pinctrl_usdhc3_sleep: usdhc3grp-sleep { + pinctrl_usdhc3_sleep: usdhc3sleep-grp { fsl,pins = < MX6SL_PAD_SD3_CMD__GPIO5_IO21 0x100c1 MX6SL_PAD_SD3_CLK__GPIO5_IO18 0x100c1 diff --git a/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine3.dts b/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine3.dts index db5d8509935f16..5ba6f15e9ed5aa 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine3.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-shine3.dts @@ -111,7 +111,7 @@ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001f8b1 >; }; - pinctrl_i2c1_sleep: i2c1grp-sleep { + pinctrl_i2c1_sleep: i2c1sleep-grp { fsl,pins = < MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x400108b1 MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x400108b1 @@ -125,7 +125,7 @@ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001f8b1 >; }; - pinctrl_i2c2_sleep: i2c2grp-sleep { + pinctrl_i2c2_sleep: i2c2sleep-grp { fsl,pins = < MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x400108b1 MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x400108b1 @@ -190,7 +190,7 @@ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059 >; }; - pinctrl_usdhc2_100mhz: usdhc2grp-100mhz { + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { fsl,pins = < MX6SL_PAD_SD2_CMD__SD2_CMD 0x170b9 MX6SL_PAD_SD2_CLK__SD2_CLK 0x130b9 @@ -201,7 +201,7 @@ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 >; }; - pinctrl_usdhc2_200mhz: usdhc2grp-200mhz { + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { fsl,pins = < MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9 MX6SL_PAD_SD2_CLK__SD2_CLK 0x130f9 @@ -212,7 +212,7 @@ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 >; }; - pinctrl_usdhc2_sleep: usdhc2grp-sleep { + pinctrl_usdhc2_sleep: usdhc2sleep-grp { fsl,pins = < MX6SL_PAD_SD2_CMD__GPIO5_IO04 0x100f9 MX6SL_PAD_SD2_CLK__GPIO5_IO05 0x100f9 @@ -234,7 +234,7 @@ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x11059 >; }; - pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { fsl,pins = < MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9 MX6SL_PAD_SD3_CLK__SD3_CLK 0x170b9 @@ -245,7 +245,7 @@ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 >; }; - pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { fsl,pins = < MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9 MX6SL_PAD_SD3_CLK__SD3_CLK 0x170f9 @@ -256,7 +256,7 @@ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 >; }; - pinctrl_usdhc3_sleep: usdhc3grp-sleep { + pinctrl_usdhc3_sleep: usdhc3sleep-grp { fsl,pins = < MX6SL_PAD_SD3_CMD__GPIO5_IO21 0x100c1 MX6SL_PAD_SD3_CLK__GPIO5_IO18 0x100c1 diff --git a/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-vision5.dts b/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-vision5.dts index 6bc342035e2b6f..a2534c422a5229 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-vision5.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sl-tolino-vision5.dts @@ -111,7 +111,7 @@ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001f8b1 >; }; - pinctrl_i2c1_sleep: i2c1grp-sleep { + pinctrl_i2c1_sleep: i2c1sleep-grp { fsl,pins = < MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x400108b1 MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x400108b1 @@ -125,7 +125,7 @@ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001f8b1 >; }; - pinctrl_i2c2_sleep: i2c2grp-sleep { + pinctrl_i2c2_sleep: i2c2sleep-grp { fsl,pins = < MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x400108b1 MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x400108b1 diff --git a/arch/arm/boot/dts/nxp/imx/imx6sl-warp.dts b/arch/arm/boot/dts/nxp/imx/imx6sl-warp.dts index 2545c0fe47c828..a5d48c38231467 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sl-warp.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sl-warp.dts @@ -125,110 +125,108 @@ &usdhc3 { }; &iomuxc { - imx6sl-warp { - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x41b0b1 - MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x41b0b1 - >; - }; - - - pinctrl_uart3: uart3grp { - fsl,pins = < - MX6SL_PAD_AUD_RXC__UART3_RX_DATA 0x41b0b1 - MX6SL_PAD_AUD_RXC__UART3_TX_DATA 0x41b0b1 - >; - }; - - pinctrl_uart5: uart5grp { - fsl,pins = < - MX6SL_PAD_ECSPI1_SCLK__UART5_RX_DATA 0x41b0b1 - MX6SL_PAD_ECSPI1_MOSI__UART5_TX_DATA 0x41b0b1 - MX6SL_PAD_ECSPI1_MISO__UART5_RTS_B 0x4130b1 - MX6SL_PAD_ECSPI1_SS0__UART5_CTS_B 0x4130b1 - >; - }; - - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x417059 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x410059 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x417059 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x417059 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x417059 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x417059 - MX6SL_PAD_SD2_DAT4__SD2_DATA4 0x417059 - MX6SL_PAD_SD2_DAT5__SD2_DATA5 0x417059 - MX6SL_PAD_SD2_DAT6__SD2_DATA6 0x417059 - MX6SL_PAD_SD2_DAT7__SD2_DATA7 0x417059 - MX6SL_PAD_SD2_RST__SD2_RESET 0x417059 - >; - }; - - pinctrl_usdhc2_100mhz: usdhc2-100mhz-grp { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x4170b9 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x4100b9 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x4170b9 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x4170b9 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x4170b9 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x4170b9 - MX6SL_PAD_SD2_DAT4__SD2_DATA4 0x4170b9 - MX6SL_PAD_SD2_DAT5__SD2_DATA5 0x4170b9 - MX6SL_PAD_SD2_DAT6__SD2_DATA6 0x4170b9 - MX6SL_PAD_SD2_DAT7__SD2_DATA7 0x4170b9 - MX6SL_PAD_SD2_RST__SD2_RESET 0x4170b9 - >; - }; - - pinctrl_usdhc2_200mhz: usdhc2-200mhz-grp { - fsl,pins = < - MX6SL_PAD_SD2_CMD__SD2_CMD 0x4170f9 - MX6SL_PAD_SD2_CLK__SD2_CLK 0x4100f9 - MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x4170f9 - MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x4170f9 - MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x4170f9 - MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x4170f9 - MX6SL_PAD_SD2_DAT4__SD2_DATA4 0x4170f9 - MX6SL_PAD_SD2_DAT5__SD2_DATA5 0x4170f9 - MX6SL_PAD_SD2_DAT6__SD2_DATA6 0x4170f9 - MX6SL_PAD_SD2_DAT7__SD2_DATA7 0x4170f9 - MX6SL_PAD_SD2_RST__SD2_RESET 0x4170f9 - >; - }; - - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x417059 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x410059 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x417059 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x417059 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x417059 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x417059 - >; - }; - - pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x4170b9 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x4100b9 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x4170b9 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x4170b9 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x4170b9 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x4170b9 - >; - }; - - pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp { - fsl,pins = < - MX6SL_PAD_SD3_CMD__SD3_CMD 0x4170f9 - MX6SL_PAD_SD3_CLK__SD3_CLK 0x4100f9 - MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x4170f9 - MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x4170f9 - MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x4170f9 - MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x4170f9 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x41b0b1 + MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x41b0b1 + >; + }; + + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX6SL_PAD_AUD_RXC__UART3_RX_DATA 0x41b0b1 + MX6SL_PAD_AUD_RXC__UART3_TX_DATA 0x41b0b1 + >; + }; + + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6SL_PAD_ECSPI1_SCLK__UART5_RX_DATA 0x41b0b1 + MX6SL_PAD_ECSPI1_MOSI__UART5_TX_DATA 0x41b0b1 + MX6SL_PAD_ECSPI1_MISO__UART5_RTS_B 0x4130b1 + MX6SL_PAD_ECSPI1_SS0__UART5_CTS_B 0x4130b1 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x417059 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x410059 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x417059 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x417059 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x417059 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x417059 + MX6SL_PAD_SD2_DAT4__SD2_DATA4 0x417059 + MX6SL_PAD_SD2_DAT5__SD2_DATA5 0x417059 + MX6SL_PAD_SD2_DAT6__SD2_DATA6 0x417059 + MX6SL_PAD_SD2_DAT7__SD2_DATA7 0x417059 + MX6SL_PAD_SD2_RST__SD2_RESET 0x417059 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhz-grp { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x4170b9 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x4100b9 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x4170b9 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x4170b9 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x4170b9 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x4170b9 + MX6SL_PAD_SD2_DAT4__SD2_DATA4 0x4170b9 + MX6SL_PAD_SD2_DAT5__SD2_DATA5 0x4170b9 + MX6SL_PAD_SD2_DAT6__SD2_DATA6 0x4170b9 + MX6SL_PAD_SD2_DAT7__SD2_DATA7 0x4170b9 + MX6SL_PAD_SD2_RST__SD2_RESET 0x4170b9 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhz-grp { + fsl,pins = < + MX6SL_PAD_SD2_CMD__SD2_CMD 0x4170f9 + MX6SL_PAD_SD2_CLK__SD2_CLK 0x4100f9 + MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x4170f9 + MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x4170f9 + MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x4170f9 + MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x4170f9 + MX6SL_PAD_SD2_DAT4__SD2_DATA4 0x4170f9 + MX6SL_PAD_SD2_DAT5__SD2_DATA5 0x4170f9 + MX6SL_PAD_SD2_DAT6__SD2_DATA6 0x4170f9 + MX6SL_PAD_SD2_DAT7__SD2_DATA7 0x4170f9 + MX6SL_PAD_SD2_RST__SD2_RESET 0x4170f9 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x417059 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x410059 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x417059 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x417059 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x417059 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x417059 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhz-grp { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x4170b9 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x4100b9 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x4170b9 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x4170b9 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x4170b9 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x4170b9 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhz-grp { + fsl,pins = < + MX6SL_PAD_SD3_CMD__SD3_CMD 0x4170f9 + MX6SL_PAD_SD3_CLK__SD3_CLK 0x4100f9 + MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x4170f9 + MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x4170f9 + MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x4170f9 + MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x4170f9 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6sl.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sl.dtsi index 6aa61235e39e8e..941a2f185056d9 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sl.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6sl.dtsi @@ -378,7 +378,7 @@ pwm4: pwm@208c000 { }; gpt: timer@2098000 { - compatible = "fsl,imx6sl-gpt"; + compatible = "fsl,imx6sl-gpt", "fsl,imx6dl-gpt"; reg = <0x02098000 0x4000>; interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_GPT>, @@ -631,6 +631,7 @@ tempmon: tempmon { nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; nvmem-cell-names = "calib", "temp_grade"; clocks = <&clks IMX6SL_CLK_PLL3_USB_OTG>; + #thermal-sensor-cells = <0>; }; }; @@ -859,7 +860,7 @@ fec: ethernet@2188000 { }; usdhc1: mmc@2190000 { - compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; + compatible = "fsl,imx6sl-usdhc"; reg = <0x02190000 0x4000>; interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USDHC1>, @@ -871,7 +872,7 @@ usdhc1: mmc@2190000 { }; usdhc2: mmc@2194000 { - compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; + compatible = "fsl,imx6sl-usdhc"; reg = <0x02194000 0x4000>; interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USDHC2>, @@ -883,7 +884,7 @@ usdhc2: mmc@2194000 { }; usdhc3: mmc@2198000 { - compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; + compatible = "fsl,imx6sl-usdhc"; reg = <0x02198000 0x4000>; interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USDHC3>, @@ -895,7 +896,7 @@ usdhc3: mmc@2198000 { }; usdhc4: mmc@219c000 { - compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; + compatible = "fsl,imx6sl-usdhc"; reg = <0x0219c000 0x4000>; interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX6SL_CLK_USDHC4>, diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll-evk.dts b/arch/arm/boot/dts/nxp/imx/imx6sll-evk.dts index febc2dd9967de6..05d6827ea2af3f 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sll-evk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sll-evk.dts @@ -461,7 +461,7 @@ MX6SLL_PAD_SD1_DATA3__SD1_DATA3 0x17059 >; }; - pinctrl_usdhc1_100mhz: usdhc1grp-100mhz { + pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp { fsl,pins = < MX6SLL_PAD_SD1_CMD__SD1_CMD 0x170b9 MX6SLL_PAD_SD1_CLK__SD1_CLK 0x130b9 @@ -472,7 +472,7 @@ MX6SLL_PAD_SD1_DATA3__SD1_DATA3 0x170b9 >; }; - pinctrl_usdhc1_200mhz: usdhc1grp-200mhz { + pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp { fsl,pins = < MX6SLL_PAD_SD1_CMD__SD1_CMD 0x170f9 MX6SLL_PAD_SD1_CLK__SD1_CLK 0x130f9 @@ -499,7 +499,7 @@ MX6SLL_PAD_GPIO4_IO21__SD2_STROBE 0x13059 >; }; - pinctrl_usdhc2_100mhz: usdhc2grp-100mhz { + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { fsl,pins = < MX6SLL_PAD_SD2_CMD__SD2_CMD 0x170b9 MX6SLL_PAD_SD2_CLK__SD2_CLK 0x130b9 @@ -515,7 +515,7 @@ MX6SLL_PAD_GPIO4_IO21__SD2_STROBE 0x130b9 >; }; - pinctrl_usdhc2_200mhz: usdhc2grp-200mhz { + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { fsl,pins = < MX6SLL_PAD_SD2_CMD__SD2_CMD 0x170f9 MX6SLL_PAD_SD2_CLK__SD2_CLK 0x130f9 @@ -549,7 +549,7 @@ MX6SLL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059 >; }; - pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { fsl,pins = < MX6SLL_PAD_SD3_CMD__SD3_CMD 0x170a1 MX6SLL_PAD_SD3_CLK__SD3_CLK 0x130a1 @@ -561,7 +561,7 @@ MX6SLL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059 >; }; - pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { fsl,pins = < MX6SLL_PAD_SD3_CMD__SD3_CMD 0x170e9 MX6SLL_PAD_SD3_CLK__SD3_CLK 0x130f9 diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-a.dts b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-a.dts new file mode 100644 index 00000000000000..33756d6de7aa09 --- /dev/null +++ b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-a.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0) +/* + * Device tree for the Kobo Clara 2E rev A ebook reader + * + * Name on mainboard is: 37NB-E60K2M+4A2 + * Serials start with: E60K2M (a number also seen in + * vendor kernel sources) + * + * Copyright 2024 Andreas Kemnade + */ + +/dts-v1/; + +#include "imx6sll-kobo-clara2e-common.dtsi" + +/ { + model = "Kobo Clara 2E"; + compatible = "kobo,clara2e-b", "kobo,clara2e", "fsl,imx6sll"; +}; + +&i2c2 { + /* EPD PMIC SY7636 at 0x62 */ +}; diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts new file mode 100644 index 00000000000000..f81aeacf514209 --- /dev/null +++ b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-b.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0) +/* + * Device tree for the Kobo Clara 2E rev B ebook reader + * + * Name on mainboard is: 37NB-E60K2M+4B0 + * Serials start with: E60K2M (a number also seen in + * vendor kernel sources) + * + * Copyright 2024 Andreas Kemnade + */ + +/dts-v1/; + +#include "imx6sll-kobo-clara2e-common.dtsi" + +/ { + model = "Kobo Clara 2E"; + compatible = "kobo,clara2e-b", "kobo,clara2e", "fsl,imx6sll"; +}; + +&i2c2 { + /* EPD PMIC JD9930 at 0x18 */ +}; diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-common.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-common.dtsi new file mode 100644 index 00000000000000..6f2deb366e0297 --- /dev/null +++ b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clara2e-common.dtsi @@ -0,0 +1,511 @@ +// SPDX-License-Identifier: (GPL-2.0) +/* + * Common part for Kobo Clara 2e device tree + * Copyright 2024 Andreas Kemnade + */ + +/dts-v1/; + +#include +#include +#include +#include "imx6sll.dtsi" + +/ { + aliases { + mmc0 = &usdhc2; + mmc1 = &usdhc3; + }; + + chosen { + stdout-path = &uart1; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; + + key-cover { + label = "Cover"; + gpios = <&gpio4 23 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_led>; + + led { + color = ; + function = LED_FUNCTION_POWER; + gpios = <&gpio4 17 GPIO_ACTIVE_LOW>; + linux,default-trigger = "timer"; + }; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000>; + }; + + reg_wifi: regulator-wifi { + compatible = "regulator-fixed"; + regulator-name = "SD3_SPWR"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + gpio = <&gpio4 29 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&clks { + assigned-clocks = <&clks IMX6SLL_CLK_PLL4_AUDIO_DIV>; + assigned-clock-rates = <393216000>; +}; + +&cpu0 { + arm-supply = <&buck1>; + soc-supply = <&buck2>; +}; + +&i2c1 { + pinctrl-names = "default","sleep"; + pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_sleep>; + clock-frequency = <100000>; + status = "okay"; + + /* backlight aw99703 at 0x36 */ +}; + +&i2c2 { + pinctrl-names = "default","sleep"; + pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-1 = <&pinctrl_i2c2_sleep>; + clock-frequency = <100000>; + status = "okay"; + + /* backlight aw99703 at 0x36 */ + + touchscreen@38 { + compatible = "focaltech,ft5426"; + reg = <0x38>; + pinctrl-names = "default", "suspend"; + pinctrl-0 = <&pinctrl_touch_gpio>; + pinctrl-1 = <&pinctrl_touch_gpio_sleep>; + interrupt-parent = <&gpio4>; + interrupts = <24 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio4 18 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1072>; + touchscreen-size-y = <1448>; + touchscreen-swapped-x-y; + }; +}; + +&i2c3 { + /* Bus seems to be in bad state after boot, allow full recovery */ + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c3>; + pinctrl-1 = <&pinctrl_i2c3_gpio>; + sda-gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>; + scl-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + clock-frequency = <100000>; + status = "okay"; + + pmic@4b { + compatible = "rohm,bd71879", "rohm,bd71828"; + reg = <0x4b>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_bd71828>; + interrupt-parent = <&gpio4>; + interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + system-power-controller; + clocks = <&clks 0>; + #clock-cells = <0>; + clock-output-names = "bd71828-32k-out"; + gpio-controller; + #gpio-cells = <2>; + gpio-reserved-ranges = <0 1>, <2 1>; + + /* charge sense resistor is 30 milli-ohm */ + + regulators { + LDO1 { + name = "LDO1"; + regulator-name = "ldo1"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + LDO2 { + name = "LDO2"; + regulator-name = "ldo2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + LDO3 { + name = "LDO3"; + regulator-name = "ldo3"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + ldo4: LDO4 { + name = "LDO4"; + regulator-name = "ldo4"; + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + }; + + LDO5 { + name = "LDO5"; + regulator-name = "ldo5"; + regulator-always-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + LDO6 { + name = "LDO6"; + regulator-name = "ldo6"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + LDO7 { + name = "LDO7"; + regulator-name = "ldo7"; + regulator-always-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + buck1: BUCK1 { + name = "BUCK1"; + regulator-name = "buck1"; + regulator-always-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + }; + + buck2: BUCK2 { + name = "BUCK2"; + regulator-name = "buck2"; + regulator-always-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2000000>; + regulator-boot-on; + }; + + BUCK3 { + name = "BUCK3"; + regulator-name = "buck3"; + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + BUCK4 { + name = "BUCK4"; + regulator-name = "buck4"; + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + }; + + BUCK5 { + name = "BUCK5"; + regulator-name = "buck5"; + regulator-always-on; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + BUCK6 { + name = "BUCK6"; + regulator-name = "buck6"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2000000>; + }; + + BUCK7 { + name = "BUCK7"; + regulator-name = "buck7"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2000000>; + }; + }; + }; +}; + +&iomuxc { + pinctrl_bd71828: bd71828-gpiogrp { + fsl,pins = < + MX6SLL_PAD_KEY_COL0__GPIO3_IO24 0x1b8b1 + MX6SLL_PAD_GPIO4_IO19__GPIO4_IO19 0x1b8b1 + >; + }; + + pinctrl_gpio_keys: gpio-keysgrp { + fsl,pins = < + MX6SLL_PAD_GPIO4_IO25__GPIO4_IO25 0x17059 /* PWR_SW */ + MX6SLL_PAD_GPIO4_IO23__GPIO4_IO23 0x17059 /* HALL_EN */ + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6SLL_PAD_I2C1_SCL__I2C1_SCL 0x4001f8b1 + MX6SLL_PAD_I2C1_SDA__I2C1_SDA 0x4001f8b1 + >; + }; + + pinctrl_i2c1_sleep: i2c1-sleepgrp { + fsl,pins = < + MX6SLL_PAD_I2C1_SCL__I2C1_SCL 0x400108b1 + MX6SLL_PAD_I2C1_SDA__I2C1_SDA 0x400108b1 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX6SLL_PAD_I2C2_SCL__I2C2_SCL 0x4001f8b1 + MX6SLL_PAD_I2C2_SDA__I2C2_SDA 0x4001f8b1 + >; + }; + + pinctrl_i2c2_sleep: i2c2-sleepgrp { + fsl,pins = < + MX6SLL_PAD_I2C2_SCL__I2C2_SCL 0x400108b1 + MX6SLL_PAD_I2C2_SDA__I2C2_SDA 0x400108b1 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6SLL_PAD_REF_CLK_24M__I2C3_SCL 0x4001f8b1 + MX6SLL_PAD_REF_CLK_32K__I2C3_SDA 0x4001f8b1 + >; + }; + + pinctrl_i2c3_gpio: i2c3-gpiogrp { + fsl,pins = < + MX6SLL_PAD_REF_CLK_24M__GPIO3_IO21 0x4001f8b1 + MX6SLL_PAD_REF_CLK_32K__GPIO3_IO22 0x4001f8b1 + >; + }; + + pinctrl_led: ledgrp { + fsl,pins = < + MX6SLL_PAD_GPIO4_IO17__GPIO4_IO17 0x10059 + >; + }; + + pinctrl_touch_gpio: touch-gpiogrp { + fsl,pins = < + MX6SLL_PAD_GPIO4_IO24__GPIO4_IO24 0x17059 /* TP_INT */ + MX6SLL_PAD_GPIO4_IO18__GPIO4_IO18 0x10059 /* TP_RST */ + >; + }; + + pinctrl_touch_gpio_sleep: touch-gpio-sleepgrp { + fsl,pins = < + MX6SLL_PAD_GPIO4_IO24__GPIO4_IO24 0x10059 /* TP_INT */ + MX6SLL_PAD_GPIO4_IO18__GPIO4_IO18 0x10059 /* TP_RST */ + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6SLL_PAD_UART1_TXD__UART1_DCE_TX 0x1b0b1 + MX6SLL_PAD_UART1_RXD__UART1_DCE_RX 0x1b0b1 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX6SLL_PAD_LCD_ENABLE__UART2_DCE_RX 0x41b0b1 + MX6SLL_PAD_LCD_HSYNC__UART2_DCE_TX 0x41b0b1 + MX6SLL_PAD_LCD_VSYNC__UART2_DCE_RTS 0x41b0b1 + MX6SLL_PAD_LCD_RESET__UART2_DCE_CTS 0x41b0b1 + >; + }; + + pinctrl_uart2_sleep: uart2-sleepgrp { + fsl,pins = < + MX6SLL_PAD_LCD_ENABLE__GPIO2_IO16 0x10059 + MX6SLL_PAD_LCD_HSYNC__GPIO2_IO17 0x10059 + MX6SLL_PAD_LCD_VSYNC__GPIO2_IO18 0x10059 + MX6SLL_PAD_LCD_RESET__GPIO2_IO19 0x10059 + >; + }; + + pinctrl_usbotg1: usbotg1grp { + fsl,pins = < + MX6SLL_PAD_EPDC_PWR_COM__USB_OTG1_ID 0x17059 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6SLL_PAD_SD2_CMD__SD2_CMD 0x17059 + MX6SLL_PAD_SD2_CLK__SD2_CLK 0x13059 + MX6SLL_PAD_SD2_DATA0__SD2_DATA0 0x17059 + MX6SLL_PAD_SD2_DATA1__SD2_DATA1 0x17059 + MX6SLL_PAD_SD2_DATA2__SD2_DATA2 0x17059 + MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x17059 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX6SLL_PAD_SD2_CMD__SD2_CMD 0x170b9 + MX6SLL_PAD_SD2_CLK__SD2_CLK 0x130b9 + MX6SLL_PAD_SD2_DATA0__SD2_DATA0 0x170b9 + MX6SLL_PAD_SD2_DATA1__SD2_DATA1 0x170b9 + MX6SLL_PAD_SD2_DATA2__SD2_DATA2 0x170b9 + MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX6SLL_PAD_SD2_CMD__SD2_CMD 0x170f9 + MX6SLL_PAD_SD2_CLK__SD2_CLK 0x130f9 + MX6SLL_PAD_SD2_DATA0__SD2_DATA0 0x170f9 + MX6SLL_PAD_SD2_DATA1__SD2_DATA1 0x170f9 + MX6SLL_PAD_SD2_DATA2__SD2_DATA2 0x170f9 + MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x170f9 + >; + }; + + pinctrl_usdhc2_sleep: usdhc2-sleepgrp { + fsl,pins = < + MX6SLL_PAD_SD2_CMD__GPIO5_IO04 0x100f9 + MX6SLL_PAD_SD2_CLK__GPIO5_IO05 0x100f9 + MX6SLL_PAD_SD2_DATA0__GPIO5_IO01 0x100f9 + MX6SLL_PAD_SD2_DATA1__GPIO4_IO30 0x100f9 + MX6SLL_PAD_SD2_DATA2__GPIO5_IO03 0x100f9 + MX6SLL_PAD_SD2_DATA3__GPIO4_IO28 0x100f9 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6SLL_PAD_SD3_CMD__SD3_CMD 0x11059 + MX6SLL_PAD_SD3_CLK__SD3_CLK 0x11059 + MX6SLL_PAD_SD3_DATA0__SD3_DATA0 0x11059 + MX6SLL_PAD_SD3_DATA1__SD3_DATA1 0x11059 + MX6SLL_PAD_SD3_DATA2__SD3_DATA2 0x11059 + MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x11059 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX6SLL_PAD_SD3_CMD__SD3_CMD 0x170b9 + MX6SLL_PAD_SD3_CLK__SD3_CLK 0x170b9 + MX6SLL_PAD_SD3_DATA0__SD3_DATA0 0x170b9 + MX6SLL_PAD_SD3_DATA1__SD3_DATA1 0x170b9 + MX6SLL_PAD_SD3_DATA2__SD3_DATA2 0x170b9 + MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x170b9 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX6SLL_PAD_SD3_CMD__SD3_CMD 0x170f9 + MX6SLL_PAD_SD3_CLK__SD3_CLK 0x170f9 + MX6SLL_PAD_SD3_DATA0__SD3_DATA0 0x170f9 + MX6SLL_PAD_SD3_DATA1__SD3_DATA1 0x170f9 + MX6SLL_PAD_SD3_DATA2__SD3_DATA2 0x170f9 + MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x170f9 + >; + }; + + pinctrl_usdhc3_sleep: usdhc3-sleepgrp { + fsl,pins = < + MX6SLL_PAD_SD3_CMD__GPIO5_IO21 0x100c1 + MX6SLL_PAD_SD3_CLK__GPIO5_IO18 0x100c1 + MX6SLL_PAD_SD3_DATA0__GPIO5_IO19 0x100c1 + MX6SLL_PAD_SD3_DATA1__GPIO5_IO20 0x100c1 + MX6SLL_PAD_SD3_DATA2__GPIO5_IO16 0x100c1 + MX6SLL_PAD_SD3_DATA3__GPIO5_IO17 0x100c1 + >; + }; + + pinctrl_wifi_power: wifi-powergrp { + fsl,pins = < + MX6SLL_PAD_SD2_DATA6__GPIO4_IO29 0x10059 + >; + }; +}; + +&snvs_rtc { + /* we are using the rtc in the pmic, not disabled in imx6sll.dtsi */ + status = "disabled"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_uart2>; + pinctrl-1 = <&pinctrl_uart2_sleep>; + status = "okay"; + + /* requires LDO4 + power enable gpio */ + bluetooth { + compatible = "nxp,88w8987-bt"; + fw-init-baudrate = <1500000>; + }; +}; + +&usbotg1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbotg1>; + disable-over-current; + srp-disable; + hnp-disable; + adp-disable; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz","sleep"; + pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + pinctrl-3 = <&pinctrl_usdhc2_sleep>; + non-removable; + status = "okay"; +}; + +&usdhc3 { + pinctrl-names = "default", "state_100mhz", "state_200mhz","sleep"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + pinctrl-3 = <&pinctrl_usdhc3_sleep>; + /* card requires also ldo4 */ + vmmc-supply = <®_wifi>; + cap-power-off-card; + non-removable; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clarahd.dts b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clarahd.dts index c7cfe0b70f04e5..18c9ac8f7560ee 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clarahd.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-clarahd.dts @@ -121,7 +121,7 @@ MX6SLL_PAD_I2C1_SDA__I2C1_SDA 0x4001f8b1 >; }; - pinctrl_i2c1_sleep: i2c1grp-sleep { + pinctrl_i2c1_sleep: i2c1sleep-grp { fsl,pins = < MX6SLL_PAD_I2C1_SCL__I2C1_SCL 0x400108b1 MX6SLL_PAD_I2C1_SDA__I2C1_SDA 0x400108b1 @@ -135,7 +135,7 @@ MX6SLL_PAD_I2C2_SDA__I2C2_SDA 0x4001f8b1 >; }; - pinctrl_i2c2_sleep: i2c2grp-sleep { + pinctrl_i2c2_sleep: i2c2sleep-grp { fsl,pins = < MX6SLL_PAD_I2C2_SCL__I2C2_SCL 0x400108b1 MX6SLL_PAD_I2C2_SDA__I2C2_SDA 0x400108b1 @@ -200,7 +200,7 @@ MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x17059 >; }; - pinctrl_usdhc2_100mhz: usdhc2grp-100mhz { + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { fsl,pins = < MX6SLL_PAD_SD2_CMD__SD2_CMD 0x170b9 MX6SLL_PAD_SD2_CLK__SD2_CLK 0x130b9 @@ -211,7 +211,7 @@ MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x170b9 >; }; - pinctrl_usdhc2_200mhz: usdhc2grp-200mhz { + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { fsl,pins = < MX6SLL_PAD_SD2_CMD__SD2_CMD 0x170f9 MX6SLL_PAD_SD2_CLK__SD2_CLK 0x130f9 @@ -222,7 +222,7 @@ MX6SLL_PAD_SD2_DATA3__SD2_DATA3 0x170f9 >; }; - pinctrl_usdhc2_sleep: usdhc2grp-sleep { + pinctrl_usdhc2_sleep: usdhc2sleep-grp { fsl,pins = < MX6SLL_PAD_SD2_CMD__GPIO5_IO04 0x100f9 MX6SLL_PAD_SD2_CLK__GPIO5_IO05 0x100f9 @@ -244,7 +244,7 @@ MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x11059 >; }; - pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { fsl,pins = < MX6SLL_PAD_SD3_CMD__SD3_CMD 0x170b9 MX6SLL_PAD_SD3_CLK__SD3_CLK 0x170b9 @@ -255,7 +255,7 @@ MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x170b9 >; }; - pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { fsl,pins = < MX6SLL_PAD_SD3_CMD__SD3_CMD 0x170f9 MX6SLL_PAD_SD3_CLK__SD3_CLK 0x170f9 @@ -266,7 +266,7 @@ MX6SLL_PAD_SD3_DATA3__SD3_DATA3 0x170f9 >; }; - pinctrl_usdhc3_sleep: usdhc3grp-sleep { + pinctrl_usdhc3_sleep: usdhc3sleep-grp { fsl,pins = < MX6SLL_PAD_SD3_CMD__GPIO5_IO21 0x100c1 MX6SLL_PAD_SD3_CLK__GPIO5_IO18 0x100c1 diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-librah2o.dts b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-librah2o.dts index 7e4f38dd11e20b..660620d226f717 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-librah2o.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sll-kobo-librah2o.dts @@ -121,7 +121,7 @@ MX6SLL_PAD_I2C1_SDA__I2C1_SDA 0x4001f8b1 >; }; - pinctrl_i2c1_sleep: i2c1grp-sleep { + pinctrl_i2c1_sleep: i2c1sleep-grp { fsl,pins = < MX6SLL_PAD_I2C1_SCL__I2C1_SCL 0x400108b1 MX6SLL_PAD_I2C1_SDA__I2C1_SDA 0x400108b1 @@ -135,7 +135,7 @@ MX6SLL_PAD_I2C2_SDA__I2C2_SDA 0x4001f8b1 >; }; - pinctrl_i2c2_sleep: i2c2grp-sleep { + pinctrl_i2c2_sleep: i2c2sleep-grp { fsl,pins = < MX6SLL_PAD_I2C2_SCL__I2C2_SCL 0x400108b1 MX6SLL_PAD_I2C2_SDA__I2C2_SDA 0x400108b1 diff --git a/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi index ddeb5b37fb78b9..8c5ca4f9b87fd6 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6sll.dtsi @@ -173,7 +173,7 @@ spdif: spdif@2004000 { "rxtx1", "rxtx2", "rxtx3", "rxtx4", "rxtx5", "rxtx6", - "rxtx7", "dma"; + "rxtx7", "spba"; status = "disabled"; }; @@ -358,7 +358,7 @@ pwm4: pwm@208c000 { }; gpt1: timer@2098000 { - compatible = "fsl,imx6sl-gpt"; + compatible = "fsl,imx6sl-gpt", "fsl,imx6dl-gpt"; reg = <0x02098000 0x4000>; interrupts = ; clocks = <&clks IMX6SLL_CLK_GPT_BUS>, @@ -507,12 +507,9 @@ anatop: anatop@20c8000 { interrupts = , , ; - #address-cells = <1>; - #size-cells = <0>; - reg_3p0: regulator-3p0@20c8120 { + reg_3p0: regulator-3p0 { compatible = "fsl,anatop-regulator"; - reg = <0x20c8120>; regulator-name = "vdd3p0"; regulator-min-microvolt = <2625000>; regulator-max-microvolt = <3400000>; @@ -525,7 +522,7 @@ reg_3p0: regulator-3p0@20c8120 { anatop-enable-bit = <0>; }; - tempmon: temperature-sensor { + tempmon: tempmon { compatible = "fsl,imx6sll-tempmon", "fsl,imx6sx-tempmon"; interrupts = ; interrupt-parent = <&gpc>; @@ -533,6 +530,7 @@ tempmon: temperature-sensor { nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; nvmem-cell-names = "calib", "temp_grade"; clocks = <&clks IMX6SLL_CLK_PLL3_USB_OTG>; + #thermal-sensor-cells = <0>; }; }; @@ -601,6 +599,18 @@ gpc: interrupt-controller@20dc000 { #interrupt-cells = <3>; interrupts = ; interrupt-parent = <&intc>; + clocks = <&clks IMX6SLL_CLK_IPG>; + clock-names = "ipg"; + + pgc { + #address-cells = <1>; + #size-cells = <0>; + + power-domain@0 { + reg = <0>; + #power-domain-cells = <0>; + }; + }; }; iomuxc: pinctrl@20e0000 { diff --git a/arch/arm/boot/dts/nxp/imx/imx6sx-sabreauto.dts b/arch/arm/boot/dts/nxp/imx/imx6sx-sabreauto.dts index dfbfb8119bf3b6..033700e052b364 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sx-sabreauto.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sx-sabreauto.dts @@ -333,7 +333,7 @@ MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x17059 /* WP */ >; }; - pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { fsl,pins = < MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 @@ -348,7 +348,7 @@ MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 >; }; - pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { fsl,pins = < MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 diff --git a/arch/arm/boot/dts/nxp/imx/imx6sx-sdb.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sx-sdb.dtsi index 277a6e039045b5..1beac42c1a2736 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sx-sdb.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6sx-sdb.dtsi @@ -399,323 +399,321 @@ &wdog1 { }; &iomuxc { - imx6x-sdb { - pinctrl_audmux: audmuxgrp { - fsl,pins = < - MX6SX_PAD_CSI_DATA00__AUDMUX_AUD6_TXC 0x130b0 - MX6SX_PAD_CSI_DATA01__AUDMUX_AUD6_TXFS 0x130b0 - MX6SX_PAD_CSI_HSYNC__AUDMUX_AUD6_TXD 0x120b0 - MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD 0x130b0 - MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130b0 - >; - }; + pinctrl_audmux: audmuxgrp { + fsl,pins = < + MX6SX_PAD_CSI_DATA00__AUDMUX_AUD6_TXC 0x130b0 + MX6SX_PAD_CSI_DATA01__AUDMUX_AUD6_TXFS 0x130b0 + MX6SX_PAD_CSI_HSYNC__AUDMUX_AUD6_TXD 0x120b0 + MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD 0x130b0 + MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130b0 + >; + }; - pinctrl_enet1: enet1grp { - fsl,pins = < - MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 - MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 - MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b1 - MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 - MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 - MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 - MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0xa0b1 - MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0xa0b1 - MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x3081 - MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x3081 - MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x3081 - MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081 - MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081 - MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081 - MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M 0x91 - /* phy reset */ - MX6SX_PAD_ENET2_CRS__GPIO2_IO_7 0x10b0 - >; - }; + pinctrl_enet1: enet1grp { + fsl,pins = < + MX6SX_PAD_ENET1_MDIO__ENET1_MDIO 0xa0b1 + MX6SX_PAD_ENET1_MDC__ENET1_MDC 0xa0b1 + MX6SX_PAD_RGMII1_TXC__ENET1_RGMII_TXC 0xa0b1 + MX6SX_PAD_RGMII1_TD0__ENET1_TX_DATA_0 0xa0b1 + MX6SX_PAD_RGMII1_TD1__ENET1_TX_DATA_1 0xa0b1 + MX6SX_PAD_RGMII1_TD2__ENET1_TX_DATA_2 0xa0b1 + MX6SX_PAD_RGMII1_TD3__ENET1_TX_DATA_3 0xa0b1 + MX6SX_PAD_RGMII1_TX_CTL__ENET1_TX_EN 0xa0b1 + MX6SX_PAD_RGMII1_RXC__ENET1_RX_CLK 0x3081 + MX6SX_PAD_RGMII1_RD0__ENET1_RX_DATA_0 0x3081 + MX6SX_PAD_RGMII1_RD1__ENET1_RX_DATA_1 0x3081 + MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081 + MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081 + MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081 + MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M 0x91 + /* phy reset */ + MX6SX_PAD_ENET2_CRS__GPIO2_IO_7 0x10b0 + >; + }; - pinctrl_enet_3v3: enet3v3grp { - fsl,pins = < - MX6SX_PAD_ENET2_COL__GPIO2_IO_6 0x80000000 - >; - }; + pinctrl_enet_3v3: enet3v3grp { + fsl,pins = < + MX6SX_PAD_ENET2_COL__GPIO2_IO_6 0x80000000 + >; + }; - pinctrl_enet2: enet2grp { - fsl,pins = < - MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC 0xa0b9 - MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0 0xa0b1 - MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1 0xa0b1 - MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2 0xa0b1 - MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3 0xa0b1 - MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN 0xa0b1 - MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK 0x3081 - MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0 0x3081 - MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1 0x3081 - MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2 0x3081 - MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3 0x3081 - MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN 0x3081 - >; - }; + pinctrl_enet2: enet2grp { + fsl,pins = < + MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC 0xa0b9 + MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0 0xa0b1 + MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1 0xa0b1 + MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2 0xa0b1 + MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3 0xa0b1 + MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN 0xa0b1 + MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK 0x3081 + MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0 0x3081 + MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1 0x3081 + MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2 0x3081 + MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3 0x3081 + MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN 0x3081 + >; + }; - pinctrl_flexcan1: flexcan1grp { - fsl,pins = < - MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b020 - MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x1b020 - >; - }; + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX6SX_PAD_QSPI1B_DQS__CAN1_TX 0x1b020 + MX6SX_PAD_QSPI1A_SS1_B__CAN1_RX 0x1b020 + >; + }; - pinctrl_flexcan2: flexcan2grp { - fsl,pins = < - MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x1b020 - MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x1b020 - >; - }; + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX6SX_PAD_QSPI1B_SS1_B__CAN2_RX 0x1b020 + MX6SX_PAD_QSPI1A_DQS__CAN2_TX 0x1b020 + >; + }; - pinctrl_gpio_keys: gpio_keysgrp { - fsl,pins = < - MX6SX_PAD_CSI_DATA04__GPIO1_IO_18 0x17059 - MX6SX_PAD_CSI_DATA05__GPIO1_IO_19 0x17059 - >; - }; + pinctrl_gpio_keys: gpio_keysgrp { + fsl,pins = < + MX6SX_PAD_CSI_DATA04__GPIO1_IO_18 0x17059 + MX6SX_PAD_CSI_DATA05__GPIO1_IO_19 0x17059 + >; + }; - pinctrl_hp: hpgrp { - fsl,pins = < - MX6SX_PAD_CSI_DATA03__GPIO1_IO_17 0x17059 - >; - }; + pinctrl_hp: hpgrp { + fsl,pins = < + MX6SX_PAD_CSI_DATA03__GPIO1_IO_17 0x17059 + >; + }; - pinctrl_i2c1: i2c1grp { - fsl,pins = < - MX6SX_PAD_GPIO1_IO01__I2C1_SDA 0x4001b8b1 - MX6SX_PAD_GPIO1_IO00__I2C1_SCL 0x4001b8b1 - >; - }; + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX6SX_PAD_GPIO1_IO01__I2C1_SDA 0x4001b8b1 + MX6SX_PAD_GPIO1_IO00__I2C1_SCL 0x4001b8b1 + >; + }; - pinctrl_i2c3: i2c3grp { - fsl,pins = < - MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 - MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 - >; - }; + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX6SX_PAD_KEY_ROW4__I2C3_SDA 0x4001b8b1 + MX6SX_PAD_KEY_COL4__I2C3_SCL 0x4001b8b1 + >; + }; - pinctrl_i2c4: i2c4grp { - fsl,pins = < - MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x4001b8b1 - MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x4001b8b1 - >; - }; + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX6SX_PAD_CSI_DATA07__I2C4_SDA 0x4001b8b1 + MX6SX_PAD_CSI_DATA06__I2C4_SCL 0x4001b8b1 + >; + }; - pinctrl_lcd: lcdgrp { - fsl,pins = < - MX6SX_PAD_LCD1_DATA00__LCDIF1_DATA_0 0x4001b0b0 - MX6SX_PAD_LCD1_DATA01__LCDIF1_DATA_1 0x4001b0b0 - MX6SX_PAD_LCD1_DATA02__LCDIF1_DATA_2 0x4001b0b0 - MX6SX_PAD_LCD1_DATA03__LCDIF1_DATA_3 0x4001b0b0 - MX6SX_PAD_LCD1_DATA04__LCDIF1_DATA_4 0x4001b0b0 - MX6SX_PAD_LCD1_DATA05__LCDIF1_DATA_5 0x4001b0b0 - MX6SX_PAD_LCD1_DATA06__LCDIF1_DATA_6 0x4001b0b0 - MX6SX_PAD_LCD1_DATA07__LCDIF1_DATA_7 0x4001b0b0 - MX6SX_PAD_LCD1_DATA08__LCDIF1_DATA_8 0x4001b0b0 - MX6SX_PAD_LCD1_DATA09__LCDIF1_DATA_9 0x4001b0b0 - MX6SX_PAD_LCD1_DATA10__LCDIF1_DATA_10 0x4001b0b0 - MX6SX_PAD_LCD1_DATA11__LCDIF1_DATA_11 0x4001b0b0 - MX6SX_PAD_LCD1_DATA12__LCDIF1_DATA_12 0x4001b0b0 - MX6SX_PAD_LCD1_DATA13__LCDIF1_DATA_13 0x4001b0b0 - MX6SX_PAD_LCD1_DATA14__LCDIF1_DATA_14 0x4001b0b0 - MX6SX_PAD_LCD1_DATA15__LCDIF1_DATA_15 0x4001b0b0 - MX6SX_PAD_LCD1_DATA16__LCDIF1_DATA_16 0x4001b0b0 - MX6SX_PAD_LCD1_DATA17__LCDIF1_DATA_17 0x4001b0b0 - MX6SX_PAD_LCD1_DATA18__LCDIF1_DATA_18 0x4001b0b0 - MX6SX_PAD_LCD1_DATA19__LCDIF1_DATA_19 0x4001b0b0 - MX6SX_PAD_LCD1_DATA20__LCDIF1_DATA_20 0x4001b0b0 - MX6SX_PAD_LCD1_DATA21__LCDIF1_DATA_21 0x4001b0b0 - MX6SX_PAD_LCD1_DATA22__LCDIF1_DATA_22 0x4001b0b0 - MX6SX_PAD_LCD1_DATA23__LCDIF1_DATA_23 0x4001b0b0 - MX6SX_PAD_LCD1_CLK__LCDIF1_CLK 0x4001b0b0 - MX6SX_PAD_LCD1_ENABLE__LCDIF1_ENABLE 0x4001b0b0 - MX6SX_PAD_LCD1_VSYNC__LCDIF1_VSYNC 0x4001b0b0 - MX6SX_PAD_LCD1_HSYNC__LCDIF1_HSYNC 0x4001b0b0 - MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x4001b0b0 - >; - }; + pinctrl_lcd: lcdgrp { + fsl,pins = < + MX6SX_PAD_LCD1_DATA00__LCDIF1_DATA_0 0x4001b0b0 + MX6SX_PAD_LCD1_DATA01__LCDIF1_DATA_1 0x4001b0b0 + MX6SX_PAD_LCD1_DATA02__LCDIF1_DATA_2 0x4001b0b0 + MX6SX_PAD_LCD1_DATA03__LCDIF1_DATA_3 0x4001b0b0 + MX6SX_PAD_LCD1_DATA04__LCDIF1_DATA_4 0x4001b0b0 + MX6SX_PAD_LCD1_DATA05__LCDIF1_DATA_5 0x4001b0b0 + MX6SX_PAD_LCD1_DATA06__LCDIF1_DATA_6 0x4001b0b0 + MX6SX_PAD_LCD1_DATA07__LCDIF1_DATA_7 0x4001b0b0 + MX6SX_PAD_LCD1_DATA08__LCDIF1_DATA_8 0x4001b0b0 + MX6SX_PAD_LCD1_DATA09__LCDIF1_DATA_9 0x4001b0b0 + MX6SX_PAD_LCD1_DATA10__LCDIF1_DATA_10 0x4001b0b0 + MX6SX_PAD_LCD1_DATA11__LCDIF1_DATA_11 0x4001b0b0 + MX6SX_PAD_LCD1_DATA12__LCDIF1_DATA_12 0x4001b0b0 + MX6SX_PAD_LCD1_DATA13__LCDIF1_DATA_13 0x4001b0b0 + MX6SX_PAD_LCD1_DATA14__LCDIF1_DATA_14 0x4001b0b0 + MX6SX_PAD_LCD1_DATA15__LCDIF1_DATA_15 0x4001b0b0 + MX6SX_PAD_LCD1_DATA16__LCDIF1_DATA_16 0x4001b0b0 + MX6SX_PAD_LCD1_DATA17__LCDIF1_DATA_17 0x4001b0b0 + MX6SX_PAD_LCD1_DATA18__LCDIF1_DATA_18 0x4001b0b0 + MX6SX_PAD_LCD1_DATA19__LCDIF1_DATA_19 0x4001b0b0 + MX6SX_PAD_LCD1_DATA20__LCDIF1_DATA_20 0x4001b0b0 + MX6SX_PAD_LCD1_DATA21__LCDIF1_DATA_21 0x4001b0b0 + MX6SX_PAD_LCD1_DATA22__LCDIF1_DATA_22 0x4001b0b0 + MX6SX_PAD_LCD1_DATA23__LCDIF1_DATA_23 0x4001b0b0 + MX6SX_PAD_LCD1_CLK__LCDIF1_CLK 0x4001b0b0 + MX6SX_PAD_LCD1_ENABLE__LCDIF1_ENABLE 0x4001b0b0 + MX6SX_PAD_LCD1_VSYNC__LCDIF1_VSYNC 0x4001b0b0 + MX6SX_PAD_LCD1_HSYNC__LCDIF1_HSYNC 0x4001b0b0 + MX6SX_PAD_LCD1_RESET__GPIO3_IO_27 0x4001b0b0 + >; + }; - pinctrl_mqs: mqsgrp { - fsl,pins = < - MX6SX_PAD_SD2_CLK__MQS_RIGHT 0x120b0 - MX6SX_PAD_SD2_CMD__MQS_LEFT 0x120b0 - >; - }; + pinctrl_mqs: mqsgrp { + fsl,pins = < + MX6SX_PAD_SD2_CLK__MQS_RIGHT 0x120b0 + MX6SX_PAD_SD2_CMD__MQS_LEFT 0x120b0 + >; + }; - pinctrl_pcie: pciegrp { - fsl,pins = < - MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x10b0 - >; - }; + pinctrl_pcie: pciegrp { + fsl,pins = < + MX6SX_PAD_ENET1_COL__GPIO2_IO_0 0x10b0 + >; + }; - pinctrl_pcie_reg: pciereggrp { - fsl,pins = < - MX6SX_PAD_ENET1_CRS__GPIO2_IO_1 0x10b0 - >; - }; + pinctrl_pcie_reg: pciereggrp { + fsl,pins = < + MX6SX_PAD_ENET1_CRS__GPIO2_IO_1 0x10b0 + >; + }; - pinctrl_peri_3v3: peri3v3grp { - fsl,pins = < - MX6SX_PAD_QSPI1A_DATA0__GPIO4_IO_16 0x80000000 - >; - }; + pinctrl_peri_3v3: peri3v3grp { + fsl,pins = < + MX6SX_PAD_QSPI1A_DATA0__GPIO4_IO_16 0x80000000 + >; + }; - pinctrl_pwm3: pwm3grp-1 { - fsl,pins = < - MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x110b0 - >; - }; + pinctrl_pwm3: pwm3-1grp { + fsl,pins = < + MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x110b0 + >; + }; - pinctrl_qspi2: qspi2grp { - fsl,pins = < - MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0 0x70f1 - MX6SX_PAD_NAND_READY_B__QSPI2_A_DATA_1 0x70f1 - MX6SX_PAD_NAND_CE0_B__QSPI2_A_DATA_2 0x70f1 - MX6SX_PAD_NAND_CE1_B__QSPI2_A_DATA_3 0x70f1 - MX6SX_PAD_NAND_CLE__QSPI2_A_SCLK 0x70f1 - MX6SX_PAD_NAND_ALE__QSPI2_A_SS0_B 0x70f1 - MX6SX_PAD_NAND_DATA01__QSPI2_B_DATA_0 0x70f1 - MX6SX_PAD_NAND_DATA00__QSPI2_B_DATA_1 0x70f1 - MX6SX_PAD_NAND_WE_B__QSPI2_B_DATA_2 0x70f1 - MX6SX_PAD_NAND_RE_B__QSPI2_B_DATA_3 0x70f1 - MX6SX_PAD_NAND_DATA02__QSPI2_B_SCLK 0x70f1 - MX6SX_PAD_NAND_DATA03__QSPI2_B_SS0_B 0x70f1 - >; - }; + pinctrl_qspi2: qspi2grp { + fsl,pins = < + MX6SX_PAD_NAND_WP_B__QSPI2_A_DATA_0 0x70f1 + MX6SX_PAD_NAND_READY_B__QSPI2_A_DATA_1 0x70f1 + MX6SX_PAD_NAND_CE0_B__QSPI2_A_DATA_2 0x70f1 + MX6SX_PAD_NAND_CE1_B__QSPI2_A_DATA_3 0x70f1 + MX6SX_PAD_NAND_CLE__QSPI2_A_SCLK 0x70f1 + MX6SX_PAD_NAND_ALE__QSPI2_A_SS0_B 0x70f1 + MX6SX_PAD_NAND_DATA01__QSPI2_B_DATA_0 0x70f1 + MX6SX_PAD_NAND_DATA00__QSPI2_B_DATA_1 0x70f1 + MX6SX_PAD_NAND_WE_B__QSPI2_B_DATA_2 0x70f1 + MX6SX_PAD_NAND_RE_B__QSPI2_B_DATA_3 0x70f1 + MX6SX_PAD_NAND_DATA02__QSPI2_B_SCLK 0x70f1 + MX6SX_PAD_NAND_DATA03__QSPI2_B_SS0_B 0x70f1 + >; + }; - pinctrl_vcc_sd3: vccsd3grp { - fsl,pins = < - MX6SX_PAD_KEY_COL1__GPIO2_IO_11 0x17059 - >; - }; + pinctrl_vcc_sd3: vccsd3grp { + fsl,pins = < + MX6SX_PAD_KEY_COL1__GPIO2_IO_11 0x17059 + >; + }; - pinctrl_sai1: sai1grp { - fsl,pins = < - MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x130b0 - MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC 0x130b0 - MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0 0x120b0 - MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0 0x130b0 - MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130b0 - >; - }; + pinctrl_sai1: sai1grp { + fsl,pins = < + MX6SX_PAD_CSI_DATA00__SAI1_TX_BCLK 0x130b0 + MX6SX_PAD_CSI_DATA01__SAI1_TX_SYNC 0x130b0 + MX6SX_PAD_CSI_HSYNC__SAI1_TX_DATA_0 0x120b0 + MX6SX_PAD_CSI_VSYNC__SAI1_RX_DATA_0 0x130b0 + MX6SX_PAD_CSI_PIXCLK__AUDMUX_MCLK 0x130b0 + >; + }; - pinctrl_spdif: spdifgrp { - fsl,pins = < - MX6SX_PAD_SD4_DATA4__SPDIF_OUT 0x1b0b0 - >; - }; + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX6SX_PAD_SD4_DATA4__SPDIF_OUT 0x1b0b0 + >; + }; - pinctrl_uart1: uart1grp { - fsl,pins = < - MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX 0x1b0b1 - MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX 0x1b0b1 - >; - }; + pinctrl_uart1: uart1grp { + fsl,pins = < + MX6SX_PAD_GPIO1_IO04__UART1_DCE_TX 0x1b0b1 + MX6SX_PAD_GPIO1_IO05__UART1_DCE_RX 0x1b0b1 + >; + }; - pinctrl_uart5: uart5grp { - fsl,pins = < - MX6SX_PAD_KEY_ROW3__UART5_DCE_RX 0x1b0b1 - MX6SX_PAD_KEY_COL3__UART5_DCE_TX 0x1b0b1 - MX6SX_PAD_KEY_ROW2__UART5_DCE_CTS 0x1b0b1 - MX6SX_PAD_KEY_COL2__UART5_DCE_RTS 0x1b0b1 - >; - }; + pinctrl_uart5: uart5grp { + fsl,pins = < + MX6SX_PAD_KEY_ROW3__UART5_DCE_RX 0x1b0b1 + MX6SX_PAD_KEY_COL3__UART5_DCE_TX 0x1b0b1 + MX6SX_PAD_KEY_ROW2__UART5_DCE_CTS 0x1b0b1 + MX6SX_PAD_KEY_COL2__UART5_DCE_RTS 0x1b0b1 + >; + }; - pinctrl_usb_otg1: usbotg1grp { - fsl,pins = < - MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9 0x10b0 - >; - }; + pinctrl_usb_otg1: usbotg1grp { + fsl,pins = < + MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9 0x10b0 + >; + }; - pinctrl_usb_otg1_id: usbotg1idgrp { - fsl,pins = < - MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID 0x17059 - >; - }; + pinctrl_usb_otg1_id: usbotg1idgrp { + fsl,pins = < + MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID 0x17059 + >; + }; - pinctrl_usb_otg2: usbot2ggrp { - fsl,pins = < - MX6SX_PAD_GPIO1_IO12__GPIO1_IO_12 0x10b0 - >; - }; + pinctrl_usb_otg2: usbot2ggrp { + fsl,pins = < + MX6SX_PAD_GPIO1_IO12__GPIO1_IO_12 0x10b0 + >; + }; - pinctrl_usdhc2: usdhc2grp { - fsl,pins = < - MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x17059 - MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x10059 - MX6SX_PAD_SD2_DATA0__USDHC2_DATA0 0x17059 - MX6SX_PAD_SD2_DATA1__USDHC2_DATA1 0x17059 - MX6SX_PAD_SD2_DATA2__USDHC2_DATA2 0x17059 - MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x17059 - >; - }; + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x17059 + MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x10059 + MX6SX_PAD_SD2_DATA0__USDHC2_DATA0 0x17059 + MX6SX_PAD_SD2_DATA1__USDHC2_DATA1 0x17059 + MX6SX_PAD_SD2_DATA2__USDHC2_DATA2 0x17059 + MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x17059 + >; + }; - pinctrl_usdhc3: usdhc3grp { - fsl,pins = < - MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17059 - MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x10059 - MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x17059 - MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x17059 - MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x17059 - MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x17059 - MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x17059 - MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x17059 - MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x17059 - MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x17059 - MX6SX_PAD_KEY_COL0__GPIO2_IO_10 0x17059 /* CD */ - MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x17059 /* WP */ - >; - }; + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x17059 + MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x10059 + MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x17059 + MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x17059 + MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x17059 + MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x17059 + MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x17059 + MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x17059 + MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x17059 + MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x17059 + MX6SX_PAD_KEY_COL0__GPIO2_IO_10 0x17059 /* CD */ + MX6SX_PAD_KEY_ROW0__GPIO2_IO_15 0x17059 /* WP */ + >; + }; - pinctrl_usdhc3_100mhz: usdhc3grp-100mhz { - fsl,pins = < - MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 - MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 - MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170b9 - MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170b9 - MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170b9 - MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170b9 - MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170b9 - MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170b9 - MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170b9 - MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 - >; - }; + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170b9 + MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100b9 + MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170b9 + MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170b9 + MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170b9 + MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170b9 + MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170b9 + MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170b9 + MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170b9 + MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170b9 + >; + }; - pinctrl_usdhc3_200mhz: usdhc3grp-200mhz { - fsl,pins = < - MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 - MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 - MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170f9 - MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170f9 - MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170f9 - MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170f9 - MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170f9 - MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170f9 - MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170f9 - MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170f9 - >; - }; + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX6SX_PAD_SD3_CMD__USDHC3_CMD 0x170f9 + MX6SX_PAD_SD3_CLK__USDHC3_CLK 0x100f9 + MX6SX_PAD_SD3_DATA0__USDHC3_DATA0 0x170f9 + MX6SX_PAD_SD3_DATA1__USDHC3_DATA1 0x170f9 + MX6SX_PAD_SD3_DATA2__USDHC3_DATA2 0x170f9 + MX6SX_PAD_SD3_DATA3__USDHC3_DATA3 0x170f9 + MX6SX_PAD_SD3_DATA4__USDHC3_DATA4 0x170f9 + MX6SX_PAD_SD3_DATA5__USDHC3_DATA5 0x170f9 + MX6SX_PAD_SD3_DATA6__USDHC3_DATA6 0x170f9 + MX6SX_PAD_SD3_DATA7__USDHC3_DATA7 0x170f9 + >; + }; - pinctrl_usdhc4: usdhc4grp { - fsl,pins = < - MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 - MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 - MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 - MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 - MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 - MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 - MX6SX_PAD_SD4_DATA7__GPIO6_IO_21 0x17059 /* CD */ - MX6SX_PAD_SD4_DATA6__GPIO6_IO_20 0x17059 /* WP */ - >; - }; + pinctrl_usdhc4: usdhc4grp { + fsl,pins = < + MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 + MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 + MX6SX_PAD_SD4_DATA0__USDHC4_DATA0 0x17059 + MX6SX_PAD_SD4_DATA1__USDHC4_DATA1 0x17059 + MX6SX_PAD_SD4_DATA2__USDHC4_DATA2 0x17059 + MX6SX_PAD_SD4_DATA3__USDHC4_DATA3 0x17059 + MX6SX_PAD_SD4_DATA7__GPIO6_IO_21 0x17059 /* CD */ + MX6SX_PAD_SD4_DATA6__GPIO6_IO_20 0x17059 /* WP */ + >; + }; - pinctrl_wdog: wdoggrp { - fsl,pins = < - MX6SX_PAD_GPIO1_IO13__WDOG1_WDOG_ANY 0x30b0 - >; - }; + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX6SX_PAD_GPIO1_IO13__WDOG1_WDOG_ANY 0x30b0 + >; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6sx-softing-vining-2000.dts b/arch/arm/boot/dts/nxp/imx/imx6sx-softing-vining-2000.dts index f999eb2443739c..2ffbe2df4776c5 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sx-softing-vining-2000.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6sx-softing-vining-2000.dts @@ -358,21 +358,21 @@ MX6SX_PAD_NAND_DATA02__GPIO4_IO_6 0x10b0 >; }; - pinctrl_pwm1: pwm1grp-1 { + pinctrl_pwm1: pwm1-1grp { fsl,pins = < /* blue LED */ MX6SX_PAD_RGMII2_RD3__PWM1_OUT 0x1b0b1 >; }; - pinctrl_pwm2: pwm2grp-1 { + pinctrl_pwm2: pwm2-1grp { fsl,pins = < /* green LED */ MX6SX_PAD_RGMII2_RD2__PWM2_OUT 0x1b0b1 >; }; - pinctrl_pwm6: pwm6grp-1 { + pinctrl_pwm6: pwm6-1grp { fsl,pins = < /* red LED */ MX6SX_PAD_RGMII2_TD2__PWM6_OUT 0x1b0b1 @@ -414,7 +414,7 @@ MX6SX_PAD_GPIO1_IO10__ANATOP_OTG1_ID 0x17059 >; }; - pinctrl_usdhc2_50mhz: usdhc2grp-50mhz { + pinctrl_usdhc2_50mhz: usdhc2-50mhzgrp { fsl,pins = < MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x10059 MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x17059 @@ -427,7 +427,7 @@ MX6SX_PAD_LCD1_HSYNC__GPIO3_IO_26 0x10b0 >; }; - pinctrl_usdhc2_100mhz: usdhc2grp-100mhz { + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { fsl,pins = < MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x100b9 MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x170b9 @@ -438,7 +438,7 @@ MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x170b9 >; }; - pinctrl_usdhc2_200mhz: usdhc2grp-200mhz { + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { fsl,pins = < MX6SX_PAD_SD2_CLK__USDHC2_CLK 0x100f9 MX6SX_PAD_SD2_CMD__USDHC2_CMD 0x170f9 @@ -449,7 +449,7 @@ MX6SX_PAD_SD2_DATA3__USDHC2_DATA3 0x170f9 >; }; - pinctrl_usdhc4_50mhz: usdhc4grp-50mhz { + pinctrl_usdhc4_50mhz: usdhc4-50mhzgrp { fsl,pins = < MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x10059 MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x17059 @@ -465,7 +465,7 @@ MX6SX_PAD_SD4_RESET_B__USDHC4_RESET_B 0x17068 >; }; - pinctrl_usdhc4_100mhz: usdhc4-100mhz { + pinctrl_usdhc4_100mhz: usdhc4-100mhzgrp { fsl,pins = < MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100b9 MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170b9 @@ -480,7 +480,7 @@ MX6SX_PAD_SD4_DATA7__USDHC4_DATA7 0x170b9 >; }; - pinctrl_usdhc4_200mhz: usdhc4-200mhz { + pinctrl_usdhc4_200mhz: usdhc4-200mhzgrp { fsl,pins = < MX6SX_PAD_SD4_CLK__USDHC4_CLK 0x100f9 MX6SX_PAD_SD4_CMD__USDHC4_CMD 0x170f9 diff --git a/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi index b386448486df80..a9550f115f8269 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi @@ -715,13 +715,14 @@ reg_soc: regulator-vddsoc { }; tempmon: tempmon { - compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon"; + compatible = "fsl,imx6sx-tempmon"; interrupt-parent = <&gpc>; interrupts = ; fsl,tempmon = <&anatop>; nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; nvmem-cell-names = "calib", "temp_grade"; clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>; + #thermal-sensor-cells = <0>; }; }; @@ -998,7 +999,7 @@ mlb: mlb@218c000 { }; usdhc1: mmc@2190000 { - compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc"; + compatible = "fsl,imx6sx-usdhc"; reg = <0x02190000 0x4000>; interrupts = ; clocks = <&clks IMX6SX_CLK_USDHC1>, @@ -1012,7 +1013,7 @@ usdhc1: mmc@2190000 { }; usdhc2: mmc@2194000 { - compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc"; + compatible = "fsl,imx6sx-usdhc"; reg = <0x02194000 0x4000>; interrupts = ; clocks = <&clks IMX6SX_CLK_USDHC2>, @@ -1026,7 +1027,7 @@ usdhc2: mmc@2194000 { }; usdhc3: mmc@2198000 { - compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc"; + compatible = "fsl,imx6sx-usdhc"; reg = <0x02198000 0x4000>; interrupts = ; clocks = <&clks IMX6SX_CLK_USDHC3>, @@ -1040,7 +1041,7 @@ usdhc3: mmc@2198000 { }; usdhc4: mmc@219c000 { - compatible = "fsl,imx6sx-usdhc", "fsl,imx6sl-usdhc"; + compatible = "fsl,imx6sx-usdhc"; reg = <0x0219c000 0x4000>; interrupts = ; clocks = <&clks IMX6SX_CLK_USDHC4>, diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-isiot.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul-isiot.dtsi index 118df2a457c952..4c09bb31269662 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6ul-isiot.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6ul-isiot.dtsi @@ -322,7 +322,7 @@ MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA 0x120b0 >; }; - pinctrl_stmpe: stmpegrp { + pinctrl_stmpe: stmpegrp { fsl,pins = < MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0x1b0b0 >; diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi index 235aa676618bb4..6de224dd2bb948 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi @@ -274,6 +274,8 @@ uart7: serial@2018000 { clocks = <&clks IMX6UL_CLK_UART7_IPG>, <&clks IMX6UL_CLK_UART7_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 43 4 0>, <&sdma 44 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -285,6 +287,8 @@ uart1: serial@2020000 { clocks = <&clks IMX6UL_CLK_UART1_IPG>, <&clks IMX6UL_CLK_UART1_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 25 4 0>, <&sdma 26 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -296,6 +300,8 @@ uart8: serial@2024000 { clocks = <&clks IMX6UL_CLK_UART8_IPG>, <&clks IMX6UL_CLK_UART8_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 45 4 0>, <&sdma 46 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1075,6 +1081,8 @@ uart2: serial@21e8000 { clocks = <&clks IMX6UL_CLK_UART2_IPG>, <&clks IMX6UL_CLK_UART2_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 27 4 0>, <&sdma 28 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1086,6 +1094,8 @@ uart3: serial@21ec000 { clocks = <&clks IMX6UL_CLK_UART3_IPG>, <&clks IMX6UL_CLK_UART3_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 29 4 0>, <&sdma 30 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1097,6 +1107,8 @@ uart4: serial@21f0000 { clocks = <&clks IMX6UL_CLK_UART4_IPG>, <&clks IMX6UL_CLK_UART4_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 31 4 0>, <&sdma 32 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1108,6 +1120,8 @@ uart5: serial@21f4000 { clocks = <&clks IMX6UL_CLK_UART5_IPG>, <&clks IMX6UL_CLK_UART5_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 33 4 0>, <&sdma 34 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -1129,6 +1143,8 @@ uart6: serial@21fc000 { clocks = <&clks IMX6UL_CLK_UART6_IPG>, <&clks IMX6UL_CLK_UART6_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 0 4 0>, <&sdma 47 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ull.dtsi index 8a1776067ecc35..db0c339022accd 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6ull.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6ull.dtsi @@ -88,6 +88,8 @@ uart8: serial@2288000 { clocks = <&clks IMX6UL_CLK_UART8_IPG>, <&clks IMX6UL_CLK_UART8_SERIAL>; clock-names = "ipg", "per"; + dmas = <&sdma 45 4 0>, <&sdma 46 4 0>; + dma-names = "rx", "tx"; status = "disabled"; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx7-colibri.dtsi b/arch/arm/boot/dts/nxp/imx/imx7-colibri.dtsi index 62e41edcaf1d74..8666dcd7fe9746 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7-colibri.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7-colibri.dtsi @@ -120,7 +120,7 @@ sound { simple-audio-card,bitclock-master = <&dailink_master>; simple-audio-card,format = "i2s"; simple-audio-card,frame-master = <&dailink_master>; - simple-audio-card,name = "imx7-sgtl5000"; + simple-audio-card,name = "colibri-imx7"; simple-audio-card,cpu { sound-dai = <&sai1>; diff --git a/arch/arm/boot/dts/nxp/imx/imx7ulp.dtsi b/arch/arm/boot/dts/nxp/imx/imx7ulp.dtsi index ac338320ac1d7c..3c6ef7bfba6098 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7ulp.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7ulp.dtsi @@ -214,10 +214,11 @@ usbphy1: usb-phy@40350000 { interrupts = ; clocks = <&pcc2 IMX7ULP_CLK_USB_PHY>; #phy-cells = <0>; + nxp,sim = <&sim>; }; usdhc0: mmc@40370000 { - compatible = "fsl,imx7ulp-usdhc", "fsl,imx6sx-usdhc"; + compatible = "fsl,imx7ulp-usdhc"; reg = <0x40370000 0x10000>; interrupts = ; clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>, @@ -231,7 +232,7 @@ usdhc0: mmc@40370000 { }; usdhc1: mmc@40380000 { - compatible = "fsl,imx7ulp-usdhc", "fsl,imx6sx-usdhc"; + compatible = "fsl,imx7ulp-usdhc"; reg = <0x40380000 0x10000>; interrupts = ; clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>, diff --git a/arch/arm/boot/dts/nxp/mxs/imx28-apx4devkit.dts b/arch/arm/boot/dts/nxp/mxs/imx28-apx4devkit.dts index 4c4ea91c286f95..0d845ca81e8996 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx28-apx4devkit.dts +++ b/arch/arm/boot/dts/nxp/mxs/imx28-apx4devkit.dts @@ -116,7 +116,7 @@ sgtl5000: codec@a { }; pcf8563: rtc@51 { - compatible = "phg,pcf8563"; + compatible = "nxp,pcf8563"; reg = <0x51>; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi index ac7494ed633e1b..5f1a6b4b764492 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi @@ -36,58 +36,58 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; reg = <0>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc0>; qcom,saw = <&saw0>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; reg = <1>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc1>; qcom,saw = <&saw1>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; reg = <2>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc2>; qcom,saw = <&saw2>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; reg = <3>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc3>; qcom,saw = <&saw3>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - L2: l2-cache { + l2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; idle-states { - CPU_SPC: cpu-spc { + cpu_spc: cpu-spc { compatible = "qcom,idle-state-spc", "arm,idle-state"; entry-latency-us = <400>; @@ -675,7 +675,7 @@ qfprom: efuse@700000 { tsens_calib: calib@404 { reg = <0x404 0x10>; }; - tsens_backup: backup_calib@414 { + tsens_backup: backup-calib@414 { reg = <0x414 0x10>; }; }; @@ -1625,7 +1625,7 @@ etm@1a1c000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU0>; + cpu = <&cpu0>; out-ports { port { @@ -1643,7 +1643,7 @@ etm@1a1d000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU1>; + cpu = <&cpu1>; out-ports { port { @@ -1661,7 +1661,7 @@ etm@1a1e000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU2>; + cpu = <&cpu2>; out-ports { port { @@ -1679,7 +1679,7 @@ etm@1a1f000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU3>; + cpu = <&cpu3>; out-ports { port { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8084.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8084.dtsi index 014e6c5ee88984..cee0694ef127b5 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8084.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-apq8084.dtsi @@ -17,7 +17,7 @@ reserved-memory { #size-cells = <1>; ranges; - smem_mem: smem_region@fa00000 { + smem_mem: smem-region@fa00000 { reg = <0xfa00000 0x200000>; no-map; }; @@ -32,10 +32,10 @@ cpu@0 { compatible = "qcom,krait"; reg = <0>; enable-method = "qcom,kpss-acc-v2"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc0>; qcom,saw = <&saw0>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; cpu@1 { @@ -43,10 +43,10 @@ cpu@1 { compatible = "qcom,krait"; reg = <1>; enable-method = "qcom,kpss-acc-v2"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc1>; qcom,saw = <&saw1>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; cpu@2 { @@ -54,10 +54,10 @@ cpu@2 { compatible = "qcom,krait"; reg = <2>; enable-method = "qcom,kpss-acc-v2"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc2>; qcom,saw = <&saw2>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; cpu@3 { @@ -65,13 +65,13 @@ cpu@3 { compatible = "qcom,krait"; reg = <3>; enable-method = "qcom,kpss-acc-v2"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc3>; qcom,saw = <&saw3>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - L2: l2-cache { + l2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; @@ -79,7 +79,7 @@ L2: l2-cache { }; idle-states { - CPU_SPC: cpu-spc { + cpu_spc: cpu-spc { compatible = "qcom,idle-state-spc", "arm,idle-state"; entry-latency-us = <150>; @@ -311,7 +311,7 @@ tsens_s9_p1: s9-p1@d8 { bits = <0 6>; }; - tsens_s10_p1: s10_p1@d8 { + tsens_s10_p1: s10-p1@d8 { reg = <0xd8 0x2>; bits = <6 6>; }; @@ -371,137 +371,137 @@ tsens_s9_p2: s9-p2@e1 { bits = <4 6>; }; - tsens_s10_p2: s10_p2@e2 { + tsens_s10_p2: s10-p2@e2 { reg = <0xe2 0x2>; bits = <2 6>; }; - tsens_s5_p2_backup: s5-p2_backup@e3 { + tsens_s5_p2_backup: s5-p2-backup@e3 { reg = <0xe3 0x2>; bits = <0 6>; }; - tsens_mode_backup: mode_backup@e3 { + tsens_mode_backup: mode-backup@e3 { reg = <0xe3 0x1>; bits = <6 2>; }; - tsens_s6_p2_backup: s6-p2_backup@e4 { + tsens_s6_p2_backup: s6-p2-backup@e4 { reg = <0xe4 0x1>; bits = <0 6>; }; - tsens_s7_p2_backup: s7-p2_backup@e4 { + tsens_s7_p2_backup: s7-p2-backup@e4 { reg = <0xe4 0x2>; bits = <6 6>; }; - tsens_s8_p2_backup: s8-p2_backup@e5 { + tsens_s8_p2_backup: s8-p2-backup@e5 { reg = <0xe5 0x2>; bits = <4 6>; }; - tsens_s9_p2_backup: s9-p2_backup@e6 { + tsens_s9_p2_backup: s9-p2-backup@e6 { reg = <0xe6 0x2>; bits = <2 6>; }; - tsens_s10_p2_backup: s10_p2_backup@e7 { + tsens_s10_p2_backup: s10-p2-backup@e7 { reg = <0xe7 0x1>; bits = <0 6>; }; - tsens_base1_backup: base1_backup@440 { + tsens_base1_backup: base1-backup@440 { reg = <0x440 0x1>; bits = <0 8>; }; - tsens_s0_p1_backup: s0-p1_backup@441 { + tsens_s0_p1_backup: s0-p1-backup@441 { reg = <0x441 0x1>; bits = <0 6>; }; - tsens_s1_p1_backup: s1-p1_backup@442 { + tsens_s1_p1_backup: s1-p1-backup@442 { reg = <0x441 0x2>; bits = <6 6>; }; - tsens_s2_p1_backup: s2-p1_backup@442 { + tsens_s2_p1_backup: s2-p1-backup@442 { reg = <0x442 0x2>; bits = <4 6>; }; - tsens_s3_p1_backup: s3-p1_backup@443 { + tsens_s3_p1_backup: s3-p1-backup@443 { reg = <0x443 0x1>; bits = <2 6>; }; - tsens_s4_p1_backup: s4-p1_backup@444 { + tsens_s4_p1_backup: s4-p1-backup@444 { reg = <0x444 0x1>; bits = <0 6>; }; - tsens_s5_p1_backup: s5-p1_backup@444 { + tsens_s5_p1_backup: s5-p1-backup@444 { reg = <0x444 0x2>; bits = <6 6>; }; - tsens_s6_p1_backup: s6-p1_backup@445 { + tsens_s6_p1_backup: s6-p1-backup@445 { reg = <0x445 0x2>; bits = <4 6>; }; - tsens_s7_p1_backup: s7-p1_backup@446 { + tsens_s7_p1_backup: s7-p1-backup@446 { reg = <0x446 0x1>; bits = <2 6>; }; - tsens_use_backup: use_backup@447 { + tsens_use_backup: use-backup@447 { reg = <0x447 0x1>; bits = <5 3>; }; - tsens_s8_p1_backup: s8-p1_backup@448 { + tsens_s8_p1_backup: s8-p1-backup@448 { reg = <0x448 0x1>; bits = <0 6>; }; - tsens_s9_p1_backup: s9-p1_backup@448 { + tsens_s9_p1_backup: s9-p1-backup@448 { reg = <0x448 0x2>; bits = <6 6>; }; - tsens_s10_p1_backup: s10_p1_backup@449 { + tsens_s10_p1_backup: s10-p1-backup@449 { reg = <0x449 0x2>; bits = <4 6>; }; - tsens_base2_backup: base2_backup@44a { + tsens_base2_backup: base2-backup@44a { reg = <0x44a 0x2>; bits = <2 8>; }; - tsens_s0_p2_backup: s0-p2_backup@44b { + tsens_s0_p2_backup: s0-p2-backup@44b { reg = <0x44b 0x3>; bits = <2 6>; }; - tsens_s1_p2_backup: s1-p2_backup@44c { + tsens_s1_p2_backup: s1-p2-backup@44c { reg = <0x44c 0x1>; bits = <0 6>; }; - tsens_s2_p2_backup: s2-p2_backup@44c { + tsens_s2_p2_backup: s2-p2-backup@44c { reg = <0x44c 0x2>; bits = <6 6>; }; - tsens_s3_p2_backup: s3-p2_backup@44d { + tsens_s3_p2_backup: s3-p2-backup@44d { reg = <0x44d 0x2>; bits = <4 6>; }; - tsens_s4_p2_backup: s4-p2_backup@44e { + tsens_s4_p2_backup: s4-p2-backup@44e { reg = <0x44e 0x1>; bits = <2 6>; }; diff --git a/arch/arm/boot/dts/qcom/qcom-ipq4018-ap120c-ac.dtsi b/arch/arm/boot/dts/qcom/qcom-ipq4018-ap120c-ac.dtsi index 0d23c03fae33f1..a6d4390efa7c39 100644 --- a/arch/arm/boot/dts/qcom/qcom-ipq4018-ap120c-ac.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-ipq4018-ap120c-ac.dtsi @@ -166,16 +166,19 @@ partition@170000 { label = "ART"; reg = <0x00170000 0x00010000>; read-only; - compatible = "nvmem-cells"; - #address-cells = <1>; - #size-cells = <1>; - precal_art_1000: precal@1000 { - reg = <0x1000 0x2f20>; - }; + nvmem-layout { + compatible = "fixed-layout"; + #address-cells = <1>; + #size-cells = <1>; + + precal_art_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; - precal_art_5000: precal@5000 { - reg = <0x5000 0x2f20>; + precal_art_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-ipq4018-jalapeno.dts b/arch/arm/boot/dts/qcom/qcom-ipq4018-jalapeno.dts index ac3b30072a2271..6640ea7b6acb2f 100644 --- a/arch/arm/boot/dts/qcom/qcom-ipq4018-jalapeno.dts +++ b/arch/arm/boot/dts/qcom/qcom-ipq4018-jalapeno.dts @@ -25,7 +25,7 @@ mdc-pins { }; }; - serial_pins: serial-state{ + serial_pins: serial-state { pins = "gpio60", "gpio61"; function = "blsp_uart0"; bias-disable; diff --git a/arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi index 56415ab34083f3..06b20c196faf3f 100644 --- a/arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi @@ -47,7 +47,7 @@ cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a7"; enable-method = "qcom,kpss-acc-v2"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc0>; qcom,saw = <&saw0>; reg = <0x0>; @@ -61,7 +61,7 @@ cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a7"; enable-method = "qcom,kpss-acc-v2"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc1>; qcom,saw = <&saw1>; reg = <0x1>; @@ -75,7 +75,7 @@ cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a7"; enable-method = "qcom,kpss-acc-v2"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc2>; qcom,saw = <&saw2>; reg = <0x2>; @@ -89,7 +89,7 @@ cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a7"; enable-method = "qcom,kpss-acc-v2"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc3>; qcom,saw = <&saw3>; reg = <0x3>; @@ -99,7 +99,7 @@ cpu@3 { operating-points-v2 = <&cpu0_opp_table>; }; - L2: l2-cache { + l2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; diff --git a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi index 759a59c2bdbcfa..96e97350153506 100644 --- a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi @@ -27,7 +27,7 @@ cpu0: cpu@0 { enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; reg = <0>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc0>; qcom,saw = <&saw0>; }; @@ -37,12 +37,12 @@ cpu1: cpu@1 { enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; reg = <1>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc1>; qcom,saw = <&saw1>; }; - L2: l2-cache { + l2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; @@ -383,7 +383,7 @@ speedbin_efuse: speedbin@c0 { tsens_calib: calib@400 { reg = <0x400 0xb>; }; - tsens_calib_backup: calib_backup@410 { + tsens_calib_backup: calib-backup@410 { reg = <0x410 0xb>; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi index 573feb3218c33c..7de8d6c550167a 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi @@ -30,7 +30,7 @@ cpu0: cpu@0 { compatible = "arm,cortex-a5"; reg = <0>; device_type = "cpu"; - next-level-cache = <&L2>; + next-level-cache = <&l2>; }; }; @@ -61,7 +61,7 @@ soc: soc { ranges; compatible = "simple-bus"; - L2: cache-controller@2040000 { + l2: cache-controller@2040000 { compatible = "arm,pl310-cache"; reg = <0x02040000 0x1000>; arm,data-latency = <2 2 0>; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi index 3a685ff7e8ccf5..64c8ac94f352e4 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi @@ -39,12 +39,12 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { compatible = "arm,cortex-a7"; enable-method = "qcom,msm8226-smp"; device_type = "cpu"; reg = <0>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; clocks = <&apcs>; operating-points-v2 = <&cpu_opp_table>; qcom,acc = <&acc0>; @@ -52,12 +52,12 @@ CPU0: cpu@0 { #cooling-cells = <2>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { compatible = "arm,cortex-a7"; enable-method = "qcom,msm8226-smp"; device_type = "cpu"; reg = <1>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; clocks = <&apcs>; operating-points-v2 = <&cpu_opp_table>; qcom,acc = <&acc1>; @@ -65,12 +65,12 @@ CPU1: cpu@1 { #cooling-cells = <2>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { compatible = "arm,cortex-a7"; enable-method = "qcom,msm8226-smp"; device_type = "cpu"; reg = <2>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; clocks = <&apcs>; operating-points-v2 = <&cpu_opp_table>; qcom,acc = <&acc2>; @@ -78,12 +78,12 @@ CPU2: cpu@2 { #cooling-cells = <2>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { compatible = "arm,cortex-a7"; enable-method = "qcom,msm8226-smp"; device_type = "cpu"; reg = <3>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; clocks = <&apcs>; operating-points-v2 = <&cpu_opp_table>; qcom,acc = <&acc3>; @@ -91,7 +91,7 @@ CPU3: cpu@3 { #cooling-cells = <2>; }; - L2: l2-cache { + l2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; @@ -1264,10 +1264,10 @@ cpu0-thermal { cooling-maps { map0 { trip = <&cpu_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; @@ -1295,10 +1295,10 @@ cpu1-thermal { cooling-maps { map0 { trip = <&cpu_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi index a66c474cd1aa0d..3f69b98d0041eb 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi @@ -22,7 +22,7 @@ cpu@0 { enable-method = "qcom,gcc-msm8660"; device_type = "cpu"; reg = <0>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; }; cpu@1 { @@ -30,10 +30,10 @@ cpu@1 { enable-method = "qcom,gcc-msm8660"; device_type = "cpu"; reg = <1>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; }; - L2: l2-cache { + l2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8916-smp.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8916-smp.dtsi index 1ba403b83cb1d4..94b7694eeeffaf 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8916-smp.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8916-smp.dtsi @@ -25,7 +25,7 @@ psci { }; }; -&CPU_SLEEP_0 { +&cpu_sleep_0 { compatible = "qcom,idle-state-spc", "arm,idle-state"; }; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index ebc43c5c6e5f75..865fe7cc39511d 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -25,7 +25,7 @@ cpu@0 { enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; reg = <0>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc0>; qcom,saw = <&saw0>; }; @@ -35,12 +35,12 @@ cpu@1 { enable-method = "qcom,kpss-acc-v1"; device_type = "cpu"; reg = <1>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc1>; qcom,saw = <&saw1>; }; - L2: l2-cache { + l2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts index fdb6e22986cfc7..261044fdfee866 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts @@ -167,7 +167,7 @@ &blsp1_i2c3 { status = "okay"; clock-frequency = <100000>; - avago_apds993@39 { + sensor@39 { compatible = "avago,apds9930"; reg = <0x39>; interrupts-extended = <&tlmm 61 IRQ_TYPE_EDGE_FALLING>; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi index 1bd87170252df7..e3f9c56a778cf8 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi @@ -35,51 +35,51 @@ cpus { #size-cells = <0>; interrupts = ; - CPU0: cpu@0 { + cpu0: cpu@0 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v2"; device_type = "cpu"; reg = <0>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc0>; qcom,saw = <&saw0>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v2"; device_type = "cpu"; reg = <1>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc1>; qcom,saw = <&saw1>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v2"; device_type = "cpu"; reg = <2>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc2>; qcom,saw = <&saw2>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { compatible = "qcom,krait"; enable-method = "qcom,kpss-acc-v2"; device_type = "cpu"; reg = <3>; - next-level-cache = <&L2>; + next-level-cache = <&l2>; qcom,acc = <&acc3>; qcom,saw = <&saw3>; - cpu-idle-states = <&CPU_SPC>; + cpu-idle-states = <&cpu_spc>; }; - L2: l2-cache { + l2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; @@ -87,7 +87,7 @@ L2: l2-cache { }; idle-states { - CPU_SPC: cpu-spc { + cpu_spc: cpu-spc { compatible = "qcom,idle-state-spc", "arm,idle-state"; entry-latency-us = <150>; @@ -960,7 +960,7 @@ etm@fc33c000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU0>; + cpu = <&cpu0>; out-ports { port { @@ -978,7 +978,7 @@ etm@fc33d000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU1>; + cpu = <&cpu1>; out-ports { port { @@ -996,7 +996,7 @@ etm@fc33e000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU2>; + cpu = <&cpu2>; out-ports { port { @@ -1014,7 +1014,7 @@ etm@fc33f000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU3>; + cpu = <&cpu3>; out-ports { port { @@ -1299,7 +1299,7 @@ tsens_s9_p1: s9-p1@d8 { bits = <0 6>; }; - tsens_s10_p1: s10_p1@d8 { + tsens_s10_p1: s10-p1@d8 { reg = <0xd8 0x2>; bits = <6 6>; }; @@ -1359,137 +1359,137 @@ tsens_s9_p2: s9-p2@e1 { bits = <4 6>; }; - tsens_s10_p2: s10_p2@e2 { + tsens_s10_p2: s10-p2@e2 { reg = <0xe2 0x2>; bits = <2 6>; }; - tsens_s5_p2_backup: s5-p2_backup@e3 { + tsens_s5_p2_backup: s5-p2-backup@e3 { reg = <0xe3 0x2>; bits = <0 6>; }; - tsens_mode_backup: mode_backup@e3 { + tsens_mode_backup: mode-backup@e3 { reg = <0xe3 0x1>; bits = <6 2>; }; - tsens_s6_p2_backup: s6-p2_backup@e4 { + tsens_s6_p2_backup: s6-p2-backup@e4 { reg = <0xe4 0x1>; bits = <0 6>; }; - tsens_s7_p2_backup: s7-p2_backup@e4 { + tsens_s7_p2_backup: s7-p2-backup@e4 { reg = <0xe4 0x2>; bits = <6 6>; }; - tsens_s8_p2_backup: s8-p2_backup@e5 { + tsens_s8_p2_backup: s8-p2-backup@e5 { reg = <0xe5 0x2>; bits = <4 6>; }; - tsens_s9_p2_backup: s9-p2_backup@e6 { + tsens_s9_p2_backup: s9-p2-backup@e6 { reg = <0xe6 0x2>; bits = <2 6>; }; - tsens_s10_p2_backup: s10_p2_backup@e7 { + tsens_s10_p2_backup: s10-p2-backup@e7 { reg = <0xe7 0x1>; bits = <0 6>; }; - tsens_base1_backup: base1_backup@440 { + tsens_base1_backup: base1-backup@440 { reg = <0x440 0x1>; bits = <0 8>; }; - tsens_s0_p1_backup: s0-p1_backup@441 { + tsens_s0_p1_backup: s0-p1-backup@441 { reg = <0x441 0x1>; bits = <0 6>; }; - tsens_s1_p1_backup: s1-p1_backup@442 { + tsens_s1_p1_backup: s1-p1-backup@442 { reg = <0x441 0x2>; bits = <6 6>; }; - tsens_s2_p1_backup: s2-p1_backup@442 { + tsens_s2_p1_backup: s2-p1-backup@442 { reg = <0x442 0x2>; bits = <4 6>; }; - tsens_s3_p1_backup: s3-p1_backup@443 { + tsens_s3_p1_backup: s3-p1-backup@443 { reg = <0x443 0x1>; bits = <2 6>; }; - tsens_s4_p1_backup: s4-p1_backup@444 { + tsens_s4_p1_backup: s4-p1-backup@444 { reg = <0x444 0x1>; bits = <0 6>; }; - tsens_s5_p1_backup: s5-p1_backup@444 { + tsens_s5_p1_backup: s5-p1-backup@444 { reg = <0x444 0x2>; bits = <6 6>; }; - tsens_s6_p1_backup: s6-p1_backup@445 { + tsens_s6_p1_backup: s6-p1-backup@445 { reg = <0x445 0x2>; bits = <4 6>; }; - tsens_s7_p1_backup: s7-p1_backup@446 { + tsens_s7_p1_backup: s7-p1-backup@446 { reg = <0x446 0x1>; bits = <2 6>; }; - tsens_use_backup: use_backup@447 { + tsens_use_backup: use-backup@447 { reg = <0x447 0x1>; bits = <5 3>; }; - tsens_s8_p1_backup: s8-p1_backup@448 { + tsens_s8_p1_backup: s8-p1-backup@448 { reg = <0x448 0x1>; bits = <0 6>; }; - tsens_s9_p1_backup: s9-p1_backup@448 { + tsens_s9_p1_backup: s9-p1-backup@448 { reg = <0x448 0x2>; bits = <6 6>; }; - tsens_s10_p1_backup: s10_p1_backup@449 { + tsens_s10_p1_backup: s10-p1-backup@449 { reg = <0x449 0x2>; bits = <4 6>; }; - tsens_base2_backup: base2_backup@44a { + tsens_base2_backup: base2-backup@44a { reg = <0x44a 0x2>; bits = <2 8>; }; - tsens_s0_p2_backup: s0-p2_backup@44b { + tsens_s0_p2_backup: s0-p2-backup@44b { reg = <0x44b 0x3>; bits = <2 6>; }; - tsens_s1_p2_backup: s1-p2_backup@44c { + tsens_s1_p2_backup: s1-p2-backup@44c { reg = <0x44c 0x1>; bits = <0 6>; }; - tsens_s2_p2_backup: s2-p2_backup@44c { + tsens_s2_p2_backup: s2-p2-backup@44c { reg = <0x44c 0x2>; bits = <6 6>; }; - tsens_s3_p2_backup: s3-p2_backup@44d { + tsens_s3_p2_backup: s3-p2-backup@44d { reg = <0x44d 0x2>; bits = <4 6>; }; - tsens_s4_p2_backup: s4-p2_backup@44e { + tsens_s4_p2_backup: s4-p2-backup@44e { reg = <0x44e 0x1>; bits = <2 6>; }; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi index 68fa5859d26343..d0f6120b665df0 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi @@ -437,6 +437,7 @@ pcie_ep: pcie-ep@1c00000 { phy-names = "pciephy"; max-link-speed = <3>; num-lanes = <2>; + linux,pci-domain = <0>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi index a949454212e942..3bc67bb8c1eb60 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi @@ -345,6 +345,7 @@ pcie_ep: pcie-ep@1c00000 { max-link-speed = <3>; num-lanes = <2>; + linux,pci-domain = <0>; status = "disabled"; }; @@ -592,39 +593,39 @@ apps_smmu: iommu@15000000 { reg = <0x15000000 0x40000>; #iommu-cells = <2>; #global-interrupts = <1>; - interrupts = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; }; intc: interrupt-controller@17800000 { diff --git a/arch/arm/boot/dts/renesas/emev2-kzm9d.dts b/arch/arm/boot/dts/renesas/emev2-kzm9d.dts index 89495dd373585e..9b64f98310f301 100644 --- a/arch/arm/boot/dts/renesas/emev2-kzm9d.dts +++ b/arch/arm/boot/dts/renesas/emev2-kzm9d.dts @@ -31,28 +31,28 @@ chosen { gpio_keys { compatible = "gpio-keys"; - one { + key-1 { debounce-interval = <50>; wakeup-source; label = "DSW2-1"; linux,code = ; gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; }; - two { + key-2 { debounce-interval = <50>; wakeup-source; label = "DSW2-2"; linux,code = ; gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; }; - three { + key-3 { debounce-interval = <50>; wakeup-source; label = "DSW2-3"; linux,code = ; gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; }; - four { + key-4 { debounce-interval = <50>; wakeup-source; label = "DSW2-4"; @@ -83,8 +83,7 @@ ethernet@20000000 { compatible = "smsc,lan9221", "smsc,lan9115"; reg = <0x20000000 0x10000>; phy-mode = "mii"; - interrupt-parent = <&gpio0>; - interrupts = <1 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&gpio0 1 IRQ_TYPE_EDGE_RISING>; reg-io-width = <4>; smsc,irq-active-high; smsc,irq-push-pull; diff --git a/arch/arm/boot/dts/renesas/iwg20d-q7-common.dtsi b/arch/arm/boot/dts/renesas/iwg20d-q7-common.dtsi index 4351c5a02fa596..2cc2908b48ca1b 100644 --- a/arch/arm/boot/dts/renesas/iwg20d-q7-common.dtsi +++ b/arch/arm/boot/dts/renesas/iwg20d-q7-common.dtsi @@ -219,8 +219,7 @@ sgtl5000: codec@a { touch: touchpanel@38 { compatible = "edt,edt-ft5406"; reg = <0x38>; - interrupt-parent = <&gpio2>; - interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio2 12 IRQ_TYPE_EDGE_FALLING>; vcc-supply = <&vcc_3v3_tft1>; }; }; diff --git a/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi b/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi index de52218ceaa4c0..ca58ea93f58fbb 100644 --- a/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi +++ b/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi @@ -73,8 +73,7 @@ &i2c5 { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio0>; - interrupts = <13 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio0 13 IRQ_TYPE_LEVEL_LOW>; clocks = <&cec_clock>; clock-names = "cec"; diff --git a/arch/arm/boot/dts/renesas/r7s72100-genmai.dts b/arch/arm/boot/dts/renesas/r7s72100-genmai.dts index 29ba098f5dd5e8..c81840dfb7da0c 100644 --- a/arch/arm/boot/dts/renesas/r7s72100-genmai.dts +++ b/arch/arm/boot/dts/renesas/r7s72100-genmai.dts @@ -9,6 +9,7 @@ /dts-v1/; #include "r7s72100.dtsi" #include +#include #include / { @@ -24,11 +25,6 @@ chosen { stdout-path = "serial0:115200n8"; }; - memory@8000000 { - device_type = "memory"; - reg = <0x08000000 0x08000000>; - }; - flash@18000000 { compatible = "mtd-rom"; reg = <0x18000000 0x08000000>; @@ -53,13 +49,29 @@ partition@0 { partition@4000000 { label = "user1"; - reg = <0x04000000 0x40000000>; + reg = <0x04000000 0x04000000>; }; }; }; + keyboard { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&keyboard_pins>; + + key-1 { + /* JP3 must be set to 1-2 (default) */ + interrupts-extended = <&irqc 6 IRQ_TYPE_EDGE_BOTH>; + linux,code = ; + label = "SW6,SW7"; + wakeup-source; + }; + }; + leds { - status = "okay"; + /* Needs SDHI0 to be disabled */ + status = "disabled"; compatible = "gpio-leds"; led1 { @@ -70,47 +82,22 @@ led2 { gpios = <&port4 11 GPIO_ACTIVE_LOW>; }; }; -}; - -&pinctrl { - - scif2_pins: serial2 { - /* P3_0 as TxD2; P3_2 as RxD2 */ - pinmux = , ; - }; - i2c2_pins: i2c2 { - /* RIIC2: P1_4 as SCL, P1_5 as SDA */ - pinmux = , ; + memory@8000000 { + device_type = "memory"; + reg = <0x08000000 0x08000000>; }; - ether_pins: ether { - /* Ethernet on Ports 1,2,3,5 */ - pinmux = ,/* P1_14 = ET_COL */ - , /* P5_9 = ET_MDC */ - , /* P3_3 = ET_MDIO */ - , /* P3_4 = ET_RXCLK */ - , /* P3_5 = ET_RXER */ - , /* P3_6 = ET_RXDV */ - , /* P2_0 = ET_TXCLK */ - , /* P2_1 = ET_TXER */ - , /* P2_2 = ET_TXEN */ - , /* P2_3 = ET_CRS */ - , /* P2_4 = ET_TXD0 */ - , /* P2_5 = ET_TXD1 */ - , /* P2_6 = ET_TXD2 */ - , /* P2_7 = ET_TXD3 */ - , /* P2_8 = ET_RXD0 */ - , /* P2_9 = ET_RXD1 */ - ,/* P2_10 = ET_RXD2 */ - ;/* P2_11 = ET_RXD3 */ + cvcc2: regulator-mmc { + compatible = "regulator-fixed"; + regulator-name = "Cvcc2"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; }; }; -&extal_clk { - clock-frequency = <13330000>; -}; - &bsc { flash@0 { compatible = "cfi-flash"; @@ -167,18 +154,6 @@ partition@60000 { }; }; -&usb_x1_clk { - clock-frequency = <48000000>; -}; - -&rtc_x1_clk { - clock-frequency = <32768>; -}; - -&mtu2 { - status = "okay"; -}; - ðer { pinctrl-names = "default"; pinctrl-0 = <ðer_pins>; @@ -194,6 +169,10 @@ phy0: ethernet-phy@0 { }; }; +&extal_clk { + clock-frequency = <13330000>; +}; + &i2c2 { status = "okay"; clock-frequency = <400000>; @@ -208,6 +187,98 @@ eeprom@50 { }; }; +&mmcif { + pinctrl-0 = <&mmcif_pins>; + pinctrl-names = "default"; + cd-gpios = <&port3 8 GPIO_ACTIVE_LOW>; + + vmmc-supply = <&cvcc2>; + vqmmc-supply = <&cvcc2>; + bus-width = <8>; + status = "okay"; +}; + +&mtu2 { + status = "okay"; +}; + +&ostm0 { + status = "okay"; +}; + +&ostm1 { + status = "okay"; +}; + +&pinctrl { + ether_pins: ether { + /* Ethernet on Ports 1,2,3,5 */ + pinmux = ,/* P1_14 = ET_COL */ + , /* P5_9 = ET_MDC */ + , /* P3_3 = ET_MDIO */ + , /* P3_4 = ET_RXCLK */ + , /* P3_5 = ET_RXER */ + , /* P3_6 = ET_RXDV */ + , /* P2_0 = ET_TXCLK */ + , /* P2_1 = ET_TXER */ + , /* P2_2 = ET_TXEN */ + , /* P2_3 = ET_CRS */ + , /* P2_4 = ET_TXD0 */ + , /* P2_5 = ET_TXD1 */ + , /* P2_6 = ET_TXD2 */ + , /* P2_7 = ET_TXD3 */ + , /* P2_8 = ET_RXD0 */ + , /* P2_9 = ET_RXD1 */ + ,/* P2_10 = ET_RXD2 */ + ;/* P2_11 = ET_RXD3 */ + }; + + i2c2_pins: i2c2 { + /* RIIC2: P1_4 as SCL, P1_5 as SDA */ + pinmux = , ; + }; + + keyboard_pins: keyboard { + /* P3_1 as IRQ6 */ + pinmux = ; + }; + + mmcif_pins: mmcif { + /* MMCIF: P3_8 is CD_GPIO, P3_10 up to P3_15, P4_0 up to P4_3 */ + pinmux = , /* MMC_D1 */ + , /* MMC_D0 */ + , /* MMC_CLK */ + , /* MMC_CMD */ + , /* MMC_D3 */ + , /* MMC_D2 */ + , /* MMC_D4 */ + , /* MMC_D5 */ + , /* MMC_D6 */ + ; /* MMC_D7 */ + }; + + scif2_pins: serial2 { + /* P3_0 as TxD2; P3_2 as RxD2 */ + pinmux = , ; + }; + + sdhi0_pins: sdhi0 { + /* SDHI0: P4_8 up to P4_15 */ + pinmux = , /* SD_CD_0 */ + , /* SD_WP_0 */ + , /* SD_D1_0 */ + , /* SD_D0_0 */ + , /* SD_CLK_0 */ + , /* SD_CMD_0 */ + , /* SD_D3_0 */ + ; /* SD_D2_0 */ + }; +}; + +&rtc_x1_clk { + clock-frequency = <32768>; +}; + &rtc { status = "okay"; }; @@ -219,12 +290,30 @@ &scif2 { status = "okay"; }; +&sdhi0 { + pinctrl-names = "default"; + pinctrl-0 = <&sdhi0_pins>; + + bus-width = <4>; + status = "okay"; +}; + &spi4 { status = "okay"; codec: codec@0 { compatible = "wlf,wm8978"; reg = <0>; - spi-max-frequency = <5000000>; + spi-max-frequency = <500000>; + #sound-dai-cells = <0>; }; }; + +&usb_x1_clk { + clock-frequency = <48000000>; +}; + +&wdt { + timeout-sec = <60>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts b/arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts index b547216d480144..25c6d0c78828f0 100644 --- a/arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts +++ b/arch/arm/boot/dts/renesas/r7s72100-rskrza1.dts @@ -78,24 +78,21 @@ keyboard { pinctrl-0 = <&keyboard_pins>; key-1 { - interrupt-parent = <&irqc>; - interrupts = <3 IRQ_TYPE_EDGE_BOTH>; + interrupts-extended = <&irqc 3 IRQ_TYPE_EDGE_BOTH>; linux,code = ; label = "SW1"; wakeup-source; }; key-2 { - interrupt-parent = <&irqc>; - interrupts = <2 IRQ_TYPE_EDGE_BOTH>; + interrupts-extended = <&irqc 2 IRQ_TYPE_EDGE_BOTH>; linux,code = ; label = "SW2"; wakeup-source; }; key-3 { - interrupt-parent = <&irqc>; - interrupts = <5 IRQ_TYPE_EDGE_BOTH>; + interrupts-extended = <&irqc 5 IRQ_TYPE_EDGE_BOTH>; linux,code = ; label = "SW3"; wakeup-source; @@ -283,3 +280,8 @@ &scif2 { pinctrl-0 = <&scif2_pins>; status = "okay"; }; + +&wdt { + timeout-sec = <60>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/renesas/r7s72100.dtsi b/arch/arm/boot/dts/renesas/r7s72100.dtsi index 08ea4c551ed005..b831bbc431efb9 100644 --- a/arch/arm/boot/dts/renesas/r7s72100.dtsi +++ b/arch/arm/boot/dts/renesas/r7s72100.dtsi @@ -36,7 +36,7 @@ b_clk: b { clock-div = <3>; }; - bsc: bsc { + bsc: bus { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -332,9 +332,9 @@ mmcif: mmc@e804c800 { , ; clocks = <&mstp8_clks R7S72100_CLK_MMCIF>; + dmas = <&dmac 0x2cc9>, <&dmac 0x2cca>; + dma-names = "tx", "rx"; power-domains = <&cpg_clocks>; - reg-io-width = <4>; - bus-width = <8>; status = "disabled"; }; @@ -370,6 +370,37 @@ sdhi1: mmc@e804e800 { status = "disabled"; }; + dmac: dma-controller@e8200000 { + compatible = "renesas,r7s72100-dmac", + "renesas,rz-dmac"; + reg = <0xe8200000 0x1000>, + <0xfcfe1000 0x20>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15"; + #dma-cells = <1>; + dma-channels = <16>; + }; + gic: interrupt-controller@e8201000 { compatible = "arm,pl390"; #interrupt-cells = <3>; diff --git a/arch/arm/boot/dts/renesas/r7s9210-rza2mevb.dts b/arch/arm/boot/dts/renesas/r7s9210-rza2mevb.dts index cd2324b8e8ffbd..f69a7fe56b6e7b 100644 --- a/arch/arm/boot/dts/renesas/r7s9210-rza2mevb.dts +++ b/arch/arm/boot/dts/renesas/r7s9210-rza2mevb.dts @@ -55,8 +55,7 @@ keyboard { pinctrl-0 = <&keyboard_pins>; key-3 { - interrupt-parent = <&irqc>; - interrupts = <0 IRQ_TYPE_EDGE_BOTH>; + interrupts-extended = <&irqc 0 IRQ_TYPE_EDGE_BOTH>; linux,code = ; label = "SW3"; wakeup-source; diff --git a/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts b/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts index 3d02f065f71c27..58becc9fbffd90 100644 --- a/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts +++ b/arch/arm/boot/dts/renesas/r8a73a4-ape6evm.dts @@ -193,8 +193,7 @@ partition@80000 { ethernet@8000000 { compatible = "smsc,lan9220", "smsc,lan9115"; reg = <0x08000000 0x1000>; - interrupt-parent = <&irqc1>; - interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&irqc1 8 IRQ_TYPE_LEVEL_HIGH>; phy-mode = "mii"; reg-io-width = <4>; smsc,irq-active-high; diff --git a/arch/arm/boot/dts/renesas/r8a73a4.dtsi b/arch/arm/boot/dts/renesas/r8a73a4.dtsi index 85261684b5d5fe..2e19ebf9e2ba8a 100644 --- a/arch/arm/boot/dts/renesas/r8a73a4.dtsi +++ b/arch/arm/boot/dts/renesas/r8a73a4.dtsi @@ -428,7 +428,6 @@ mmcif0: mmc@ee200000 { interrupts = ; clocks = <&mstp3_clks R8A73A4_CLK_MMCIF0>; power-domains = <&pd_a3sp>; - reg-io-width = <4>; status = "disabled"; }; @@ -438,7 +437,6 @@ mmcif1: mmc@ee220000 { interrupts = ; clocks = <&mstp3_clks R8A73A4_CLK_MMCIF1>; power-domains = <&pd_a3sp>; - reg-io-width = <4>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts index e1ac2c161e7303..04d24b6d8056ff 100644 --- a/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts +++ b/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts @@ -224,8 +224,7 @@ eeprom@50 { touchscreen@55 { compatible = "sitronix,st1232"; reg = <0x55>; - interrupt-parent = <&irqpin1>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqpin1 2 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&st1232_pins>; pinctrl-names = "default"; gpios = <&pfc 166 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/renesas/r8a7742-iwg21d-q7.dts b/arch/arm/boot/dts/renesas/r8a7742-iwg21d-q7.dts index 64102b664055b4..6a8a0d2113b020 100644 --- a/arch/arm/boot/dts/renesas/r8a7742-iwg21d-q7.dts +++ b/arch/arm/boot/dts/renesas/r8a7742-iwg21d-q7.dts @@ -202,8 +202,7 @@ sgtl5000: codec@a { touch: touchpanel@38 { compatible = "edt,edt-ft5406"; reg = <0x38>; - interrupt-parent = <&gpio0>; - interrupts = <24 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio0 24 IRQ_TYPE_EDGE_FALLING>; /* GP1_29 is also shared with audio codec reset pin */ reset-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>; vcc-supply = <&vcc_3v3_tft1>; diff --git a/arch/arm/boot/dts/renesas/r8a7742-iwg21m.dtsi b/arch/arm/boot/dts/renesas/r8a7742-iwg21m.dtsi index b281a4d164b0aa..661cc5357b5721 100644 --- a/arch/arm/boot/dts/renesas/r8a7742-iwg21m.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7742-iwg21m.dtsi @@ -55,8 +55,7 @@ &i2c0 { rtc@68 { compatible = "ti,bq32000"; reg = <0x68>; - interrupt-parent = <&gpio1>; - interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio1 1 IRQ_TYPE_EDGE_FALLING>; }; }; diff --git a/arch/arm/boot/dts/renesas/r8a7742.dtsi b/arch/arm/boot/dts/renesas/r8a7742.dtsi index 3a5d6b434d0946..9083d288cc339d 100644 --- a/arch/arm/boot/dts/renesas/r8a7742.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7742.dtsi @@ -1651,7 +1651,6 @@ mmcif0: mmc@ee200000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7742_PD_ALWAYS_ON>; resets = <&cpg 315>; - reg-io-width = <4>; status = "disabled"; max-frequency = <97500000>; }; @@ -1667,7 +1666,6 @@ mmcif1: mmc@ee220000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7742_PD_ALWAYS_ON>; resets = <&cpg 305>; - reg-io-width = <4>; status = "disabled"; max-frequency = <97500000>; }; diff --git a/arch/arm/boot/dts/renesas/r8a7743-sk-rzg1m.dts b/arch/arm/boot/dts/renesas/r8a7743-sk-rzg1m.dts index ff274bfcb6646e..9b16fe7ce713c9 100644 --- a/arch/arm/boot/dts/renesas/r8a7743-sk-rzg1m.dts +++ b/arch/arm/boot/dts/renesas/r8a7743-sk-rzg1m.dts @@ -73,8 +73,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc 0 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/renesas/r8a7743.dtsi b/arch/arm/boot/dts/renesas/r8a7743.dtsi index 8833898d5557f4..58a06cf37784c3 100644 --- a/arch/arm/boot/dts/renesas/r8a7743.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7743.dtsi @@ -1639,7 +1639,6 @@ mmcif0: mmc@ee200000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; resets = <&cpg 315>; - reg-io-width = <4>; max-frequency = <97500000>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/renesas/r8a7744.dtsi b/arch/arm/boot/dts/renesas/r8a7744.dtsi index c66c1102fb7218..034244648d18cb 100644 --- a/arch/arm/boot/dts/renesas/r8a7744.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7744.dtsi @@ -1639,7 +1639,6 @@ mmcif0: mmc@ee200000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7744_PD_ALWAYS_ON>; resets = <&cpg 315>; - reg-io-width = <4>; max-frequency = <97500000>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts index a0b574398055ad..5903c1f1356f26 100644 --- a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts +++ b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts @@ -84,8 +84,7 @@ &i2c1 { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 0 IRQ_TYPE_LEVEL_LOW>; clocks = <&cec_clock>; clock-names = "cec"; pd-gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts index 24411044ef6c4f..3ac2526a24a1e1 100644 --- a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts +++ b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts @@ -185,8 +185,7 @@ sgtl5000: codec@a { port-expander@44 { compatible = "st,stmpe811"; reg = <0x44>; - interrupt-parent = <&gpio4>; - interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio4 4 IRQ_TYPE_LEVEL_LOW>; /* 3.25 MHz ADC clock speed */ st,adc-freq = <1>; diff --git a/arch/arm/boot/dts/renesas/r8a7745-sk-rzg1e.dts b/arch/arm/boot/dts/renesas/r8a7745-sk-rzg1e.dts index 0a75e8c79acc0e..571615a5062071 100644 --- a/arch/arm/boot/dts/renesas/r8a7745-sk-rzg1e.dts +++ b/arch/arm/boot/dts/renesas/r8a7745-sk-rzg1e.dts @@ -68,8 +68,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc>; - interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc 8 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/renesas/r8a7745.dtsi b/arch/arm/boot/dts/renesas/r8a7745.dtsi index 6ddde364782b8a..704fa6f3cbd088 100644 --- a/arch/arm/boot/dts/renesas/r8a7745.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7745.dtsi @@ -1513,7 +1513,6 @@ mmcif0: mmc@ee200000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7745_PD_ALWAYS_ON>; resets = <&cpg 315>; - reg-io-width = <4>; max-frequency = <97500000>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/renesas/r8a77470-iwg23s-sbc.dts b/arch/arm/boot/dts/renesas/r8a77470-iwg23s-sbc.dts index 64480228524916..e511eb425bc550 100644 --- a/arch/arm/boot/dts/renesas/r8a77470-iwg23s-sbc.dts +++ b/arch/arm/boot/dts/renesas/r8a77470-iwg23s-sbc.dts @@ -82,8 +82,7 @@ phy3: ethernet-phy@3 { compatible = "ethernet-phy-id0022.1622", "ethernet-phy-ieee802.3-c22"; reg = <3>; - interrupt-parent = <&gpio5>; - interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio5 16 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; }; }; @@ -151,8 +150,7 @@ &i2c4 { hdmi@39 { compatible = "sil,sii9022"; reg = <0x39>; - interrupt-parent = <&gpio2>; - interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 29 IRQ_TYPE_LEVEL_LOW>; ports { #address-cells = <1>; diff --git a/arch/arm/boot/dts/renesas/r8a7778-bockw.dts b/arch/arm/boot/dts/renesas/r8a7778-bockw.dts index a3f9d74e8877b7..a99d226f41a602 100644 --- a/arch/arm/boot/dts/renesas/r8a7778-bockw.dts +++ b/arch/arm/boot/dts/renesas/r8a7778-bockw.dts @@ -61,7 +61,7 @@ sndcodec: simple-audio-card,codec { }; }; -&bsc { +&lbsc { flash@0 { compatible = "cfi-flash"; reg = <0x0 0x04000000>; @@ -96,8 +96,7 @@ ethernet@18300000 { reg = <0x18300000 0x1000>; phy-mode = "mii"; - interrupt-parent = <&irqpin>; - interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqpin 0 IRQ_TYPE_EDGE_FALLING>; reg-io-width = <4>; vddvario-supply = <&fixedregulator3v3>; vdd33a-supply = <&fixedregulator3v3>; diff --git a/arch/arm/boot/dts/renesas/r8a7778.dtsi b/arch/arm/boot/dts/renesas/r8a7778.dtsi index b80e832c927757..859dd29dfce3bd 100644 --- a/arch/arm/boot/dts/renesas/r8a7778.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7778.dtsi @@ -40,7 +40,7 @@ aliases { spi2 = &hspi2; }; - bsc: bus@1c000000 { + lbsc: bus { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/renesas/r8a7779-marzen.dts b/arch/arm/boot/dts/renesas/r8a7779-marzen.dts index 9b13e8d1538b00..2920d87ea6ffef 100644 --- a/arch/arm/boot/dts/renesas/r8a7779-marzen.dts +++ b/arch/arm/boot/dts/renesas/r8a7779-marzen.dts @@ -58,17 +58,15 @@ keypad-0 { pinctrl-0 = <&keypad0_pins>; pinctrl-names = "default"; - interrupt-parent = <&gpio0>; - key-1 { - interrupts = <17 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio0 17 IRQ_TYPE_EDGE_FALLING>; linux,code = ; label = "SW1-1"; wakeup-source; debounce-interval = <20>; }; key-2 { - interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio0 18 IRQ_TYPE_EDGE_FALLING>; linux,code = ; label = "SW1-2"; wakeup-source; @@ -251,8 +249,7 @@ ethernet@18000000 { pinctrl-names = "default"; phy-mode = "mii"; - interrupt-parent = <&irqpin0>; - interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqpin0 1 IRQ_TYPE_EDGE_FALLING>; smsc,irq-push-pull; reg-io-width = <4>; vddvario-supply = <&fixedregulator3v3>; diff --git a/arch/arm/boot/dts/renesas/r8a7779.dtsi b/arch/arm/boot/dts/renesas/r8a7779.dtsi index 1944703cba4fc5..e437c22f452dbc 100644 --- a/arch/arm/boot/dts/renesas/r8a7779.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7779.dtsi @@ -704,7 +704,7 @@ R8A7779_CLK_MMC1 R8A7779_CLK_MMC0 }; }; - lbsc: lbsc { + lbsc: bus { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/renesas/r8a7790-lager.dts b/arch/arm/boot/dts/renesas/r8a7790-lager.dts index 8590981245a620..3bce5876a9d81a 100644 --- a/arch/arm/boot/dts/renesas/r8a7790-lager.dts +++ b/arch/arm/boot/dts/renesas/r8a7790-lager.dts @@ -79,28 +79,28 @@ keyboard { pinctrl-0 = <&keyboard_pins>; pinctrl-names = "default"; - one { + key-1 { linux,code = ; label = "SW2-1"; wakeup-source; debounce-interval = <20>; gpios = <&gpio1 14 GPIO_ACTIVE_LOW>; }; - two { + key-2 { linux,code = ; label = "SW2-2"; wakeup-source; debounce-interval = <20>; gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; }; - three { + key-3 { linux,code = ; label = "SW2-3"; wakeup-source; debounce-interval = <20>; gpios = <&gpio1 26 GPIO_ACTIVE_LOW>; }; - four { + key-4 { linux,code = ; label = "SW2-4"; wakeup-source; @@ -365,8 +365,7 @@ adv7180: endpoint { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <15 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 15 IRQ_TYPE_LEVEL_LOW>; clocks = <&cec_clock>; clock-names = "cec"; @@ -403,8 +402,7 @@ adv7511_out: endpoint { hdmi-in@4c { compatible = "adi,adv7612"; reg = <0x4c>; - interrupt-parent = <&gpio1>; - interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 20 IRQ_TYPE_LEVEL_LOW>; default-input = <0>; ports { @@ -444,8 +442,7 @@ i2cpwr: i2c-mux4 { pmic@58 { compatible = "dlg,da9063"; reg = <0x58>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; @@ -461,8 +458,7 @@ watchdog { vdd_dvfs: regulator@68 { compatible = "dlg,da9210"; reg = <0x68>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; @@ -692,8 +688,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc0>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 0 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio5 31 GPIO_ACTIVE_LOW>; }; @@ -890,7 +885,7 @@ &hsusb { status = "okay"; pinctrl-0 = <&hsusb_pins>; pinctrl-names = "default"; - renesas,enable-gpio = <&gpio5 18 GPIO_ACTIVE_HIGH>; + renesas,enable-gpios = <&gpio5 18 GPIO_ACTIVE_HIGH>; }; &usbphy { diff --git a/arch/arm/boot/dts/renesas/r8a7790-stout.dts b/arch/arm/boot/dts/renesas/r8a7790-stout.dts index 683f7395fab0b6..d7c0a9574ce831 100644 --- a/arch/arm/boot/dts/renesas/r8a7790-stout.dts +++ b/arch/arm/boot/dts/renesas/r8a7790-stout.dts @@ -211,8 +211,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc0>; - interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 1 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; }; @@ -300,8 +299,7 @@ &iic2 { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <15 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 15 IRQ_TYPE_LEVEL_LOW>; clocks = <&osc4_clk>; clock-names = "cec"; @@ -344,8 +342,7 @@ &iic3 { pmic@58 { compatible = "dlg,da9063"; reg = <0x58>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; @@ -365,8 +362,7 @@ watchdog { vdd_dvfs: regulator@68 { compatible = "dlg,da9210"; reg = <0x68>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; @@ -377,8 +373,7 @@ vdd_dvfs: regulator@68 { vdd: regulator@70 { compatible = "dlg,da9210"; reg = <0x70>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; diff --git a/arch/arm/boot/dts/renesas/r8a7790.dtsi b/arch/arm/boot/dts/renesas/r8a7790.dtsi index 20e4d4c6e7481f..f746f0b9e686bb 100644 --- a/arch/arm/boot/dts/renesas/r8a7790.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7790.dtsi @@ -1686,7 +1686,6 @@ mmcif0: mmc@ee200000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; resets = <&cpg 315>; - reg-io-width = <4>; status = "disabled"; max-frequency = <97500000>; }; @@ -1702,7 +1701,6 @@ mmcif1: mmc@ee220000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; resets = <&cpg 305>; - reg-io-width = <4>; status = "disabled"; max-frequency = <97500000>; }; diff --git a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts index 0efd9f98c75ace..e4e1d9c98c6178 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts @@ -397,8 +397,7 @@ adv7180: endpoint { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio3>; - interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 29 IRQ_TYPE_LEVEL_LOW>; clocks = <&cec_clock>; clock-names = "cec"; @@ -435,8 +434,7 @@ adv7511_out: endpoint { hdmi-in@4c { compatible = "adi,adv7612"; reg = <0x4c>; - interrupt-parent = <&gpio4>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio4 2 IRQ_TYPE_LEVEL_LOW>; default-input = <0>; ports { @@ -659,8 +657,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc0>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 0 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>; }; @@ -816,8 +813,7 @@ &i2c6 { pmic@58 { compatible = "dlg,da9063"; reg = <0x58>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; @@ -833,8 +829,7 @@ watchdog { vdd_dvfs: regulator@68 { compatible = "dlg,da9210"; reg = <0x68>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; @@ -859,7 +854,7 @@ &hsusb { status = "okay"; pinctrl-0 = <&usb0_pins>; pinctrl-names = "default"; - renesas,enable-gpio = <&gpio5 31 GPIO_ACTIVE_HIGH>; + renesas,enable-gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>; }; &usbphy { diff --git a/arch/arm/boot/dts/renesas/r8a7791-porter.dts b/arch/arm/boot/dts/renesas/r8a7791-porter.dts index 93c86e92164555..08381498350aac 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-porter.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-porter.dts @@ -194,8 +194,7 @@ adv7180: endpoint { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio3>; - interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 29 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <®_1p8v>; dvdd-supply = <®_1p8v>; @@ -329,8 +328,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc0>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 0 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>; }; @@ -410,8 +408,7 @@ &i2c6 { pmic@5a { compatible = "dlg,da9063l"; reg = <0x5a>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; @@ -423,8 +420,7 @@ watchdog { vdd_dvfs: regulator@68 { compatible = "dlg,da9210"; reg = <0x68>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; diff --git a/arch/arm/boot/dts/renesas/r8a7791.dtsi b/arch/arm/boot/dts/renesas/r8a7791.dtsi index f9c9e1d8f669c3..e57567adff5588 100644 --- a/arch/arm/boot/dts/renesas/r8a7791.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7791.dtsi @@ -1680,7 +1680,6 @@ mmcif0: mmc@ee200000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; resets = <&cpg 315>; - reg-io-width = <4>; status = "disabled"; max-frequency = <97500000>; }; diff --git a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts index 540a9ad28f28ac..a3986076d8e3e9 100644 --- a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts +++ b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts @@ -224,8 +224,7 @@ ethernet@18000000 { compatible = "smsc,lan89218", "smsc,lan9115"; reg = <0x18000000 0x100>; phy-mode = "mii"; - interrupt-parent = <&irqc>; - interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqc 0 IRQ_TYPE_EDGE_FALLING>; smsc,irq-push-pull; reg-io-width = <4>; vddvario-supply = <&d3_3v>; @@ -336,8 +335,7 @@ &i2c1 { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&irqc>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqc 3 IRQ_TYPE_EDGE_FALLING>; avdd-supply = <&d1_8v>; dvdd-supply = <&d1_8v>; @@ -378,8 +376,7 @@ pmic@58 { reg = <0x58>; pinctrl-names = "default"; pinctrl-0 = <&pmic_irq_pins>; - interrupt-parent = <&irqc>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc 2 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/renesas/r8a7792-wheat.dts b/arch/arm/boot/dts/renesas/r8a7792-wheat.dts index 000f21a2a8630a..bfc780f7e396b4 100644 --- a/arch/arm/boot/dts/renesas/r8a7792-wheat.dts +++ b/arch/arm/boot/dts/renesas/r8a7792-wheat.dts @@ -115,8 +115,7 @@ ethernet@18000000 { compatible = "smsc,lan89218", "smsc,lan9115"; reg = <0x18000000 0x100>; phy-mode = "mii"; - interrupt-parent = <&irqc>; - interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqc 0 IRQ_TYPE_EDGE_FALLING>; smsc,irq-push-pull; smsc,save-mac-address; reg-io-width = <4>; diff --git a/arch/arm/boot/dts/renesas/r8a7792.dtsi b/arch/arm/boot/dts/renesas/r8a7792.dtsi index dd3bc32668b7b3..08cbe6c13cee46 100644 --- a/arch/arm/boot/dts/renesas/r8a7792.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7792.dtsi @@ -84,7 +84,7 @@ extal_clk: extal { clock-frequency = <0>; }; - lbsc: lbsc { + lbsc: bus { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/renesas/r8a7793-gose.dts b/arch/arm/boot/dts/renesas/r8a7793-gose.dts index 1ea6c757893bc0..2c05d7c2b37765 100644 --- a/arch/arm/boot/dts/renesas/r8a7793-gose.dts +++ b/arch/arm/boot/dts/renesas/r8a7793-gose.dts @@ -383,8 +383,7 @@ adv7180_out: endpoint { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio3>; - interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 29 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <®_1p8v>; dvdd-supply = <®_1p8v>; @@ -419,8 +418,7 @@ adv7511_out: endpoint { hdmi-in@4c { compatible = "adi,adv7612"; reg = <0x4c>; - interrupt-parent = <&gpio4>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio4 2 IRQ_TYPE_LEVEL_LOW>; default-input = <0>; ports { @@ -622,8 +620,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc0>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 0 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>; }; @@ -756,8 +753,7 @@ &i2c6 { pmic@58 { compatible = "dlg,da9063"; reg = <0x58>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; @@ -773,8 +769,7 @@ watchdog { vdd_dvfs: regulator@68 { compatible = "dlg,da9210"; reg = <0x68>; - interrupt-parent = <&irqc0>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 2 IRQ_TYPE_LEVEL_LOW>; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1000000>; diff --git a/arch/arm/boot/dts/renesas/r8a7793.dtsi b/arch/arm/boot/dts/renesas/r8a7793.dtsi index 24e66ddf37e048..e48e43cc6b03d8 100644 --- a/arch/arm/boot/dts/renesas/r8a7793.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7793.dtsi @@ -1343,7 +1343,6 @@ mmcif0: mmc@ee200000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7793_PD_ALWAYS_ON>; resets = <&cpg 315>; - reg-io-width = <4>; status = "disabled"; max-frequency = <97500000>; }; diff --git a/arch/arm/boot/dts/renesas/r8a7794-alt.dts b/arch/arm/boot/dts/renesas/r8a7794-alt.dts index b5ecafbb2e4de5..f70e26aa83a0a4 100644 --- a/arch/arm/boot/dts/renesas/r8a7794-alt.dts +++ b/arch/arm/boot/dts/renesas/r8a7794-alt.dts @@ -96,28 +96,28 @@ keyboard { pinctrl-0 = <&keyboard_pins>; pinctrl-names = "default"; - one { + key-1 { linux,code = ; label = "SW2-1"; wakeup-source; debounce-interval = <20>; gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; }; - two { + key-2 { linux,code = ; label = "SW2-2"; wakeup-source; debounce-interval = <20>; gpios = <&gpio3 10 GPIO_ACTIVE_LOW>; }; - three { + key-3 { linux,code = ; label = "SW2-3"; wakeup-source; debounce-interval = <20>; gpios = <&gpio3 11 GPIO_ACTIVE_LOW>; }; - four { + key-4 { linux,code = ; label = "SW2-4"; wakeup-source; @@ -381,8 +381,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc0>; - interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 8 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; }; @@ -450,8 +449,7 @@ &i2c7 { pmic@58 { compatible = "dlg,da9063"; reg = <0x58>; - interrupt-parent = <&gpio3>; - interrupts = <31 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 31 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/renesas/r8a7794-silk.dts b/arch/arm/boot/dts/renesas/r8a7794-silk.dts index 595e074085eb4c..2a0819311a3c4e 100644 --- a/arch/arm/boot/dts/renesas/r8a7794-silk.dts +++ b/arch/arm/boot/dts/renesas/r8a7794-silk.dts @@ -262,8 +262,7 @@ adv7180: endpoint { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio5>; - interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio5 23 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <&d1_8v>; dvdd-supply = <&d1_8v>; @@ -415,8 +414,7 @@ phy1: ethernet-phy@1 { compatible = "ethernet-phy-id0022.1537", "ethernet-phy-ieee802.3-c22"; reg = <1>; - interrupt-parent = <&irqc0>; - interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&irqc0 8 IRQ_TYPE_LEVEL_LOW>; micrel,led-mode = <1>; reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; }; @@ -436,8 +434,7 @@ &i2c7 { pmic@58 { compatible = "dlg,da9063"; reg = <0x58>; - interrupt-parent = <&gpio3>; - interrupts = <31 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 31 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/renesas/r8a7794.dtsi b/arch/arm/boot/dts/renesas/r8a7794.dtsi index 8e6386a79aead3..bc16c896c0f9b9 100644 --- a/arch/arm/boot/dts/renesas/r8a7794.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7794.dtsi @@ -1349,7 +1349,6 @@ mmcif0: mmc@ee200000 { dma-names = "tx", "rx", "tx", "rx"; power-domains = <&sysc R8A7794_PD_ALWAYS_ON>; resets = <&cpg 315>; - reg-io-width = <4>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/renesas/sh73a0-kzm9g.dts b/arch/arm/boot/dts/renesas/sh73a0-kzm9g.dts index 98897f710063a9..1ce07d0878dc63 100644 --- a/arch/arm/boot/dts/renesas/sh73a0-kzm9g.dts +++ b/arch/arm/boot/dts/renesas/sh73a0-kzm9g.dts @@ -172,8 +172,7 @@ ethernet@10000000 { compatible = "smsc,lan9221", "smsc,lan9115"; reg = <0x10000000 0x100>; phy-mode = "mii"; - interrupt-parent = <&irqpin0>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqpin0 3 IRQ_TYPE_EDGE_FALLING>; reg-io-width = <4>; smsc,irq-push-pull; smsc,save-mac-address; @@ -196,8 +195,7 @@ &i2c0 { compass@c { compatible = "asahi-kasei,ak8975"; reg = <0x0c>; - interrupt-parent = <&irqpin3>; - interrupts = <4 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqpin3 4 IRQ_TYPE_EDGE_FALLING>; }; ak4648: codec@12 { @@ -209,9 +207,8 @@ ak4648: codec@12 { accelerometer@1d { compatible = "adi,adxl345"; reg = <0x1d>; - interrupt-parent = <&irqpin3>; - interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, - <3 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&irqpin3 2 IRQ_TYPE_LEVEL_HIGH>, + <&irqpin3 3 IRQ_TYPE_LEVEL_HIGH>; }; rtc@32 { @@ -297,8 +294,7 @@ &i2c1 { touchscreen@55 { compatible = "sitronix,st1232"; reg = <0x55>; - interrupt-parent = <&irqpin1>; - interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqpin1 0 IRQ_TYPE_EDGE_FALLING>; }; }; @@ -310,8 +306,7 @@ &i2c3 { pcf8575: gpio@20 { compatible = "nxp,pcf8575"; reg = <0x20>; - interrupt-parent = <&irqpin2>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&irqpin2 3 IRQ_TYPE_EDGE_FALLING>; gpio-controller; #gpio-cells = <2>; interrupt-controller; diff --git a/arch/arm/boot/dts/renesas/sh73a0.dtsi b/arch/arm/boot/dts/renesas/sh73a0.dtsi index 30c67acc4e3557..c7cc17e3c3c540 100644 --- a/arch/arm/boot/dts/renesas/sh73a0.dtsi +++ b/arch/arm/boot/dts/renesas/sh73a0.dtsi @@ -273,7 +273,6 @@ mmcif: mmc@e6bd0000 { ; clocks = <&mstp3_clks SH73A0_CLK_MMCIF0>; power-domains = <&pd_a3sp>; - reg-io-width = <4>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/rockchip/Makefile b/arch/arm/boot/dts/rockchip/Makefile index ab4cd9aab7227c..716f5540e43840 100644 --- a/arch/arm/boot/dts/rockchip/Makefile +++ b/arch/arm/boot/dts/rockchip/Makefile @@ -2,6 +2,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1108-elgin-r1.dtb \ rv1108-evb.dtb \ + rv1109-relfor-saib.dtb \ rv1109-sonoff-ihost.dtb \ rv1126-edgeble-neu2-io.dtb \ rv1126-sonoff-ihost.dtb \ diff --git a/arch/arm/boot/dts/rockchip/rk3036-kylin.dts b/arch/arm/boot/dts/rockchip/rk3036-kylin.dts index 2f84e28057121b..4f928c7898e90a 100644 --- a/arch/arm/boot/dts/rockchip/rk3036-kylin.dts +++ b/arch/arm/boot/dts/rockchip/rk3036-kylin.dts @@ -80,7 +80,7 @@ simple-audio-card,codec { }; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3066a-bqcurie2.dts b/arch/arm/boot/dts/rockchip/rk3066a-bqcurie2.dts index f924d4d64c3d18..c227691013eaf0 100644 --- a/arch/arm/boot/dts/rockchip/rk3066a-bqcurie2.dts +++ b/arch/arm/boot/dts/rockchip/rk3066a-bqcurie2.dts @@ -22,7 +22,7 @@ memory@60000000 { reg = <0x60000000 0x40000000>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm3 0 1000>; regulator-name = "vdd_log"; @@ -34,7 +34,7 @@ vdd_log: vdd-log { status = "okay"; }; - vcc_sd0: fixed-regulator { + vcc_sd0: regulator-fixed { compatible = "regulator-fixed"; regulator-name = "sdmmc-supply"; regulator-min-microvolt = <3000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3066a-marsboard.dts b/arch/arm/boot/dts/rockchip/rk3066a-marsboard.dts index f6e8d49a02efc0..ada7dbfc06a56b 100644 --- a/arch/arm/boot/dts/rockchip/rk3066a-marsboard.dts +++ b/arch/arm/boot/dts/rockchip/rk3066a-marsboard.dts @@ -19,7 +19,7 @@ memory@60000000 { reg = <0x60000000 0x40000000>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm3 0 1000>; regulator-name = "vdd_log"; @@ -31,7 +31,7 @@ vdd_log: vdd-log { status = "okay"; }; - vcc_sd0: sdmmc-regulator { + vcc_sd0: regulator-sdmmc { compatible = "regulator-fixed"; regulator-name = "sdmmc-supply"; regulator-min-microvolt = <3000000>; @@ -41,7 +41,7 @@ vcc_sd0: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vsys: vsys-regulator { + vsys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vsys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3066a-mk808.dts b/arch/arm/boot/dts/rockchip/rk3066a-mk808.dts index 4de9a45c4883b8..25c0bcf85a5685 100644 --- a/arch/arm/boot/dts/rockchip/rk3066a-mk808.dts +++ b/arch/arm/boot/dts/rockchip/rk3066a-mk808.dts @@ -61,21 +61,21 @@ hdmi_con_in: endpoint { }; }; - vcc_2v5: vcc-2v5 { + vcc_2v5: regulator-vcc-2v5 { compatible = "regulator-fixed"; regulator-name = "vcc_2v5"; regulator-min-microvolt = <2500000>; regulator-max-microvolt = <2500000>; }; - vcc_io: vcc-io { + vcc_io: regulator-vcc-io { compatible = "regulator-fixed"; regulator-name = "vcc_io"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; - vcc_host: usb-host-regulator { + vcc_host: regulator-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -89,7 +89,7 @@ vcc_host: usb-host-regulator { vin-supply = <&vcc_io>; }; - vcc_otg: usb-otg-regulator { + vcc_otg: regulator-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -103,7 +103,7 @@ vcc_otg: usb-otg-regulator { vin-supply = <&vcc_io>; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>; pinctrl-0 = <&sdmmc_pwr>; @@ -115,7 +115,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_wifi: sdio-regulator { + vcc_wifi: regulator-sdio { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PD0 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3066a-rayeager.dts b/arch/arm/boot/dts/rockchip/rk3066a-rayeager.dts index 29d8e5bf88f534..b0b029f146436f 100644 --- a/arch/arm/boot/dts/rockchip/rk3066a-rayeager.dts +++ b/arch/arm/boot/dts/rockchip/rk3066a-rayeager.dts @@ -42,7 +42,7 @@ key-power { }; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm3 0 1000>; regulator-name = "vdd_log"; @@ -54,7 +54,7 @@ vdd_log: vdd-log { status = "okay"; }; - vsys: vsys-regulator { + vsys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vsys"; regulator-min-microvolt = <5000000>; @@ -64,7 +64,7 @@ vsys: vsys-regulator { }; /* input for 5V_STDBY is VSYS or DC5V, selectable by jumper J4 */ - vcc_stdby: stdby-regulator { + vcc_stdby: regulator-stdby { compatible = "regulator-fixed"; regulator-name = "5v_stdby"; regulator-min-microvolt = <5000000>; @@ -73,7 +73,7 @@ vcc_stdby: stdby-regulator { regulator-boot-on; }; - vcc_emmc: emmc-regulator { + vcc_emmc: regulator-emmc { compatible = "regulator-fixed"; regulator-name = "emmc_vccq"; regulator-min-microvolt = <3000000>; @@ -81,7 +81,7 @@ vcc_emmc: emmc-regulator { vin-supply = <&vsys>; }; - vcc_sata: sata-regulator { + vcc_sata: regulator-sata { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; @@ -94,7 +94,7 @@ vcc_sata: sata-regulator { vin-supply = <&vcc_stdby>; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -106,7 +106,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_host: usb-host-regulator { + vcc_host: regulator-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -119,7 +119,7 @@ vcc_host: usb-host-regulator { vin-supply = <&vcc_stdby>; }; - vcc_otg: usb-otg-regulator { + vcc_otg: regulator-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3128-evb.dts b/arch/arm/boot/dts/rockchip/rk3128-evb.dts index c7ab7fcdb43615..3d27d921de76a3 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-evb.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-evb.dts @@ -24,7 +24,7 @@ memory@60000000 { reg = <0x60000000 0x40000000>; }; - vcc5v0_otg: vcc5v0-otg-regulator { + vcc5v0_otg: regulator-vcc5v0-otg { compatible = "regulator-fixed"; gpio = <&gpio0 26 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -34,7 +34,7 @@ vcc5v0_otg: vcc5v0-otg-regulator { regulator-max-microvolt = <5000000>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; gpio = <&gpio2 23 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts index 21c1678f4e916b..21f824b0919163 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts @@ -38,7 +38,7 @@ button-recovery { }; }; - dc_5v: dc-5v-regulator { + dc_5v: regulator-dc-5v { compatible = "regulator-fixed"; regulator-name = "DC_5V"; regulator-min-microvolt = <5000000>; @@ -62,7 +62,7 @@ hdmi_connector_in: endpoint { * This is a vbus-supply, which also supplies the GL852G usb hub, * thus has to be always-on */ - host_pwr_5v: host-pwr-5v-regulator { + host_pwr_5v: regulator-host-pwr-5v { compatible = "regulator-fixed"; gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; startup-delay-us = <1500>; @@ -111,7 +111,7 @@ led-spd { }; }; - mcu3v3: mcu3v3-regulator { + mcu3v3: regulator-mcu3v3 { compatible = "regulator-fixed"; regulator-name = "MCU3V3"; regulator-min-microvolt = <3300000>; @@ -121,7 +121,7 @@ mcu3v3: mcu3v3-regulator { regulator-boot-on; }; - vcc_ddr: vcc-ddr-regulator { + vcc_ddr: regulator-vcc-ddr { compatible = "regulator-fixed"; regulator-name = "VCC_DDR"; regulator-min-microvolt = <1500000>; @@ -131,7 +131,7 @@ vcc_ddr: vcc-ddr-regulator { regulator-boot-on; }; - vcc_io: vcc-io-regulator { + vcc_io: regulator-vcc-io { compatible = "regulator-fixed"; regulator-name = "VCC_IO"; regulator-min-microvolt = <3300000>; @@ -141,7 +141,7 @@ vcc_io: vcc-io-regulator { regulator-boot-on; }; - vcc_lan: vcc-lan-regulator { + vcc_lan: regulator-vcc-lan { compatible = "regulator-fixed"; regulator-name = "VCC_LAN"; regulator-min-microvolt = <3300000>; @@ -151,7 +151,7 @@ vcc_lan: vcc-lan-regulator { regulator-boot-on; }; - vcc_sd: vcc-sd-regulator { + vcc_sd: regulator-vcc-sd { compatible = "regulator-fixed"; gpio = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>; startup-delay-us = <500>; @@ -163,7 +163,7 @@ vcc_sd: vcc-sd-regulator { pinctrl-0 = <&sdmmc_pwren>; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "VCC_SYS"; regulator-min-microvolt = <5000000>; @@ -173,7 +173,7 @@ vcc_sys: vcc-sys-regulator { regulator-boot-on; }; - vcc33_hdmi: vcc33-hdmi-regulator { + vcc33_hdmi: regulator-vcc33-hdmi { compatible = "regulator-fixed"; regulator-name = "VCC33_HDMI"; regulator-min-microvolt = <3300000>; @@ -183,7 +183,7 @@ vcc33_hdmi: vcc33-hdmi-regulator { regulator-boot-on; }; - vcca_33: vcca-33-regulator { + vcca_33: regulator-vcca-33 { compatible = "regulator-fixed"; regulator-name = "VCCA_33"; regulator-min-microvolt = <3300000>; @@ -193,7 +193,7 @@ vcca_33: vcca-33-regulator { regulator-boot-on; }; - vdd_11: vdd-11-regulator { + vdd_11: regulator-vdd-11 { compatible = "regulator-fixed"; regulator-name = "VDD_11"; regulator-min-microvolt = <1100000>; @@ -203,7 +203,7 @@ vdd_11: vdd-11-regulator { regulator-boot-on; }; - vdd11_hdmi: vdd11-hdmi-regulator { + vdd11_hdmi: regulator-vdd11-hdmi { compatible = "regulator-fixed"; regulator-name = "VDD11_HDMI"; regulator-min-microvolt = <1100000>; @@ -213,7 +213,7 @@ vdd11_hdmi: vdd11-hdmi-regulator { regulator-boot-on; }; - vdd_arm: vdd-arm-regulator { + vdd_arm: regulator-vdd-arm { compatible = "pwm-regulator"; regulator-name = "VDD_ARM"; pwms = <&pwm1 0 25000 1>; @@ -231,7 +231,7 @@ vdd_arm: vdd-arm-regulator { * driver does not implement regulator support we have to make * sure here that the voltage never drops below 1050 mV. */ - vdd_log: vdd-log-regulator { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; regulator-name = "VDD_LOG"; pwms = <&pwm2 0 25000 1>; diff --git a/arch/arm/boot/dts/rockchip/rk3188-bqedison2qc.dts b/arch/arm/boot/dts/rockchip/rk3188-bqedison2qc.dts index 9312be362a7ada..edc2b7f9112dd7 100644 --- a/arch/arm/boot/dts/rockchip/rk3188-bqedison2qc.dts +++ b/arch/arm/boot/dts/rockchip/rk3188-bqedison2qc.dts @@ -130,7 +130,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio3 RK_PD0 GPIO_ACTIVE_LOW>; }; - avdd_cif: cif-avdd-regulator { + avdd_cif: regulator-cif-avdd { compatible = "regulator-fixed"; regulator-name = "avdd-cif"; regulator-min-microvolt = <2800000>; @@ -142,7 +142,7 @@ avdd_cif: cif-avdd-regulator { vin-supply = <&vcc28_cif>; }; - vcc_5v: vcc-5v-regulator { + vcc_5v: regulator-vcc-5v { compatible = "regulator-fixed"; regulator-name = "vcc-5v"; regulator-min-microvolt = <5000000>; @@ -154,7 +154,7 @@ vcc_5v: vcc-5v-regulator { vin-supply = <&vsys>; }; - vcc_lcd: lcd-regulator { + vcc_lcd: regulator-lcd { compatible = "regulator-fixed"; regulator-name = "vcc-lcd"; gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>; @@ -164,7 +164,7 @@ vcc_lcd: lcd-regulator { vin-supply = <&vcc_io>; }; - vcc_otg: usb-otg-regulator { + vcc_otg: regulator-usb-otg { compatible = "regulator-fixed"; regulator-name = "vcc-otg"; regulator-min-microvolt = <5000000>; @@ -177,7 +177,7 @@ vcc_otg: usb-otg-regulator { vin-supply = <&vcc_5v>; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; regulator-name = "vcc-sd"; regulator-min-microvolt = <3300000>; @@ -189,7 +189,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vccq_emmc: emmc-vccq-regulator { + vccq_emmc: regulator-emmc-vccq { compatible = "regulator-fixed"; regulator-name = "vccq-emmc"; regulator-min-microvolt = <2800000>; @@ -198,7 +198,7 @@ vccq_emmc: emmc-vccq-regulator { }; /* supplied from the bq24196 */ - vsys: vsys-regulator { + vsys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vsys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3188-px3-evb.dts b/arch/arm/boot/dts/rockchip/rk3188-px3-evb.dts index 0a1ae689b162bb..32f36d7a7d2867 100644 --- a/arch/arm/boot/dts/rockchip/rk3188-px3-evb.dts +++ b/arch/arm/boot/dts/rockchip/rk3188-px3-evb.dts @@ -39,7 +39,7 @@ key-power { }; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vsys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3188-radxarock.dts b/arch/arm/boot/dts/rockchip/rk3188-radxarock.dts index 118deacd38c4a6..1f31c0a6774f78 100644 --- a/arch/arm/boot/dts/rockchip/rk3188-radxarock.dts +++ b/arch/arm/boot/dts/rockchip/rk3188-radxarock.dts @@ -78,7 +78,7 @@ ir_recv: ir-receiver { pinctrl-0 = <&ir_recv_pin>; }; - vcc_otg: usb-otg-regulator { + vcc_otg: regulator-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio2 RK_PD7 GPIO_ACTIVE_HIGH>; @@ -91,7 +91,7 @@ vcc_otg: usb-otg-regulator { regulator-boot-on; }; - vcc_sd0: sdmmc-regulator { + vcc_sd0: regulator-sdmmc { compatible = "regulator-fixed"; regulator-name = "sdmmc-supply"; regulator-min-microvolt = <3300000>; @@ -103,7 +103,7 @@ vcc_sd0: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_host: usb-host-regulator { + vcc_host: regulator-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -116,7 +116,7 @@ vcc_host: usb-host-regulator { regulator-boot-on; }; - vsys: vsys-regulator { + vsys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vsys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3228-evb.dts b/arch/arm/boot/dts/rockchip/rk3228-evb.dts index 69a5e239ed1ab1..a450cf31a0be4a 100644 --- a/arch/arm/boot/dts/rockchip/rk3228-evb.dts +++ b/arch/arm/boot/dts/rockchip/rk3228-evb.dts @@ -17,7 +17,7 @@ memory@60000000 { reg = <0x60000000 0x40000000>; }; - vcc_phy: vcc-phy-regulator { + vcc_phy: regulator-vcc-phy { compatible = "regulator-fixed"; enable-active-high; regulator-name = "vcc_phy"; diff --git a/arch/arm/boot/dts/rockchip/rk3229-evb.dts b/arch/arm/boot/dts/rockchip/rk3229-evb.dts index 5c3d08e3eea3a0..c35757d2b5dc28 100644 --- a/arch/arm/boot/dts/rockchip/rk3229-evb.dts +++ b/arch/arm/boot/dts/rockchip/rk3229-evb.dts @@ -18,7 +18,7 @@ memory@60000000 { reg = <0x60000000 0x40000000>; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -34,7 +34,7 @@ ext_gmac: ext_gmac { #clock-cells = <0>; }; - vcc_host: vcc-host-regulator { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; @@ -46,7 +46,7 @@ vcc_host: vcc-host-regulator { vin-supply = <&vcc_sys>; }; - vcc_phy: vcc-phy-regulator { + vcc_phy: regulator-vcc-phy { compatible = "regulator-fixed"; enable-active-high; regulator-name = "vcc_phy"; @@ -57,7 +57,7 @@ vcc_phy: vcc-phy-regulator { vin-supply = <&vccio_1v8>; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -67,7 +67,7 @@ vcc_sys: vcc-sys-regulator { vin-supply = <&dc_12v>; }; - vccio_1v8: vccio-1v8-regulator { + vccio_1v8: regulator-vccio-1v8 { compatible = "regulator-fixed"; regulator-name = "vccio_1v8"; regulator-min-microvolt = <1800000>; @@ -76,7 +76,7 @@ vccio_1v8: vccio-1v8-regulator { vin-supply = <&vcc_sys>; }; - vccio_3v3: vccio-3v3-regulator { + vccio_3v3: regulator-vccio-3v3 { compatible = "regulator-fixed"; regulator-name = "vccio_3v3"; regulator-min-microvolt = <3300000>; @@ -85,7 +85,7 @@ vccio_3v3: vccio-3v3-regulator { vin-supply = <&vcc_sys>; }; - vdd_arm: vdd-arm-regulator { + vdd_arm: regulator-vdd-arm { compatible = "pwm-regulator"; pwms = <&pwm1 0 25000 1>; pwm-supply = <&vcc_sys>; @@ -96,7 +96,7 @@ vdd_arm: vdd-arm-regulator { regulator-boot-on; }; - vdd_log: vdd-log-regulator { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc_sys>; diff --git a/arch/arm/boot/dts/rockchip/rk3229-xms6.dts b/arch/arm/boot/dts/rockchip/rk3229-xms6.dts index 7bfbfd11fb55fd..28333449c43aa0 100644 --- a/arch/arm/boot/dts/rockchip/rk3229-xms6.dts +++ b/arch/arm/boot/dts/rockchip/rk3229-xms6.dts @@ -20,7 +20,7 @@ memory@60000000 { reg = <0x60000000 0x40000000>; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -51,7 +51,7 @@ sdio_pwrseq: sdio-pwrseq { <&gpio2 29 GPIO_ACTIVE_LOW>; }; - vcc_host: vcc-host-regulator { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; @@ -63,7 +63,7 @@ vcc_host: vcc-host-regulator { vin-supply = <&vcc_sys>; }; - vcc_phy: vcc-phy-regulator { + vcc_phy: regulator-vcc-phy { compatible = "regulator-fixed"; enable-active-high; regulator-name = "vcc_phy"; @@ -74,7 +74,7 @@ vcc_phy: vcc-phy-regulator { vin-supply = <&vccio_1v8>; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -84,7 +84,7 @@ vcc_sys: vcc-sys-regulator { vin-supply = <&dc_12v>; }; - vccio_1v8: vccio-1v8-regulator { + vccio_1v8: regulator-vccio-1v8 { compatible = "regulator-fixed"; regulator-name = "vccio_1v8"; regulator-min-microvolt = <1800000>; @@ -93,7 +93,7 @@ vccio_1v8: vccio-1v8-regulator { vin-supply = <&vcc_sys>; }; - vccio_3v3: vccio-3v3-regulator { + vccio_3v3: regulator-vccio-3v3 { compatible = "regulator-fixed"; regulator-name = "vccio_3v3"; regulator-min-microvolt = <3300000>; @@ -102,7 +102,7 @@ vccio_3v3: vccio-3v3-regulator { vin-supply = <&vcc_sys>; }; - vdd_arm: vdd-arm-regulator { + vdd_arm: regulator-vdd-arm { compatible = "pwm-regulator"; pwms = <&pwm1 0 25000 1>; pwm-supply = <&vcc_sys>; @@ -113,7 +113,7 @@ vdd_arm: vdd-arm-regulator { regulator-boot-on; }; - vdd_log: vdd-log-regulator { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc_sys>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-evb-act8846.dts b/arch/arm/boot/dts/rockchip/rk3288-evb-act8846.dts index 8a635c24312741..e1821fadbe7a24 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-evb-act8846.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-evb-act8846.dts @@ -7,7 +7,7 @@ / { model = "Rockchip RK3288 EVB ACT8846"; compatible = "rockchip,rk3288-evb-act8846", "rockchip,rk3288"; - vcc_lcd: vcc-lcd { + vcc_lcd: regulator-vcc-lcd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio7 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -17,7 +17,7 @@ vcc_lcd: vcc-lcd { vin-supply = <&vcc_io>; }; - vcc_wl: vcc-wl { + vcc_wl: regulator-vcc-wl { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio7 RK_PB1 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-evb.dtsi b/arch/arm/boot/dts/rockchip/rk3288-evb.dtsi index 382d2839cf472c..11bb970c6112c8 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-evb.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-evb.dtsi @@ -129,7 +129,7 @@ key-power { }; /* This turns on USB vbus for both host0 (ehci) and host1 (dwc2) */ - vcc_host: vcc-host-regulator { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -140,7 +140,7 @@ vcc_host: vcc-host-regulator { regulator-boot-on; }; - vcc_phy: vcc-phy-regulator { + vcc_phy: regulator-vcc-phy { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -153,7 +153,7 @@ vcc_phy: vcc-phy-regulator { regulator-boot-on; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -167,7 +167,7 @@ vcc_sys: vsys-regulator { * vcc_io directly. Those boards won't be able to power cycle SD cards * but it shouldn't hurt to toggle this pin there anyway. */ - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/rockchip/rk3288-firefly-reload-core.dtsi b/arch/arm/boot/dts/rockchip/rk3288-firefly-reload-core.dtsi index 36efa36b7190a0..59029483741b21 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-firefly-reload-core.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-firefly-reload-core.dtsi @@ -21,7 +21,7 @@ ext_gmac: external-gmac-clock { }; - vcc_flash: flash-regulator { + vcc_flash: regulator-flash { compatible = "regulator-fixed"; regulator-name = "vcc_flash"; regulator-min-microvolt = <1800000>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-firefly-reload.dts b/arch/arm/boot/dts/rockchip/rk3288-firefly-reload.dts index a5a0826341e6d7..a552706727321b 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-firefly-reload.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-firefly-reload.dts @@ -85,7 +85,7 @@ spdif_out: spdif-out { #sound-dai-cells = <0>; }; - vcc_host_5v: usb-host-regulator { + vcc_host_5v: regulator-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -98,7 +98,7 @@ vcc_host_5v: usb-host-regulator { vin-supply = <&vcc_5v>; }; - vcc_5v: vcc_sys: vsys-regulator { + vcc_5v: vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_5v"; regulator-min-microvolt = <5000000>; @@ -107,7 +107,7 @@ vcc_5v: vcc_sys: vsys-regulator { regulator-boot-on; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -119,7 +119,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_otg_5v: usb-otg-regulator { + vcc_otg_5v: regulator-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; @@ -132,7 +132,7 @@ vcc_otg_5v: usb-otg-regulator { vin-supply = <&vcc_5v>; }; - dovdd_1v8: dovdd-1v8-regulator { + dovdd_1v8: regulator-dovdd-1v8 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; @@ -144,7 +144,7 @@ dovdd_1v8: dovdd-1v8-regulator { vin-supply = <&vcc_io>; }; - vcc28_dvp: vcc28-dvp-regulator { + vcc28_dvp: regulator-vcc28-dvp { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; @@ -156,7 +156,7 @@ vcc28_dvp: vcc28-dvp-regulator { vin-supply = <&vcc_io>; }; - af_28: af_28-regulator { + af_28: regulator-af-28 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; @@ -168,7 +168,7 @@ af_28: af_28-regulator { vin-supply = <&vcc_io>; }; - dvdd_1v2: af_28-regulator { + dvdd_1v2: regulator-dvdd-1v2 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio7 RK_PB4 GPIO_ACTIVE_HIGH>; @@ -180,7 +180,7 @@ dvdd_1v2: af_28-regulator { vin-supply = <&vcc_io>; }; - vbat_wl: wifi-regulator { + vbat_wl: regulator-wifi { compatible = "regulator-fixed"; regulator-name = "vbat_wl"; regulator-min-microvolt = <3300000>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-firefly.dtsi b/arch/arm/boot/dts/rockchip/rk3288-firefly.dtsi index 3836c61cfb7613..187d4f0a52ebe2 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-firefly.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-firefly.dtsi @@ -25,7 +25,7 @@ button-recovery { }; }; - dovdd_1v8: dovdd-1v8-regulator { + dovdd_1v8: regulator-dovdd-1v8 { compatible = "regulator-fixed"; regulator-name = "dovdd_1v8"; regulator-min-microvolt = <1800000>; @@ -79,7 +79,7 @@ power_led: led-1 { }; }; - vbat_wl: vcc_sys: vsys-regulator { + vbat_wl: vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -88,7 +88,7 @@ vbat_wl: vcc_sys: vsys-regulator { regulator-boot-on; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -100,7 +100,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_flash: flash-regulator { + vcc_flash: regulator-flash { compatible = "regulator-fixed"; regulator-name = "vcc_flash"; regulator-min-microvolt = <1800000>; @@ -108,7 +108,7 @@ vcc_flash: flash-regulator { vin-supply = <&vcc_io>; }; - vcc_5v: usb-regulator { + vcc_5v: regulator-usb { compatible = "regulator-fixed"; regulator-name = "vcc_5v"; regulator-min-microvolt = <5000000>; @@ -118,7 +118,7 @@ vcc_5v: usb-regulator { vin-supply = <&vcc_sys>; }; - vcc_host_5v: usb-host-regulator { + vcc_host_5v: regulator-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -131,7 +131,7 @@ vcc_host_5v: usb-host-regulator { vin-supply = <&vcc_5v>; }; - vcc_otg_5v: usb-otg-regulator { + vcc_otg_5v: regulator-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; @@ -148,7 +148,7 @@ vcc_otg_5v: usb-otg-regulator { * A TT8142 creates both dovdd_1v8 and vcc28_dvp, controlled * by the dvp_pwr pin. */ - vcc28_dvp: vcc28-dvp-regulator { + vcc28_dvp: regulator-vcc28-dvp { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-miqi.dts b/arch/arm/boot/dts/rockchip/rk3288-miqi.dts index db1eb648e0e1a2..dd42f8d31f7087 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-miqi.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-miqi.dts @@ -37,7 +37,7 @@ work_led: led-0 { }; }; - vcc_flash: flash-regulator { + vcc_flash: regulator-flash { compatible = "regulator-fixed"; regulator-name = "vcc_flash"; regulator-min-microvolt = <1800000>; @@ -45,7 +45,7 @@ vcc_flash: flash-regulator { vin-supply = <&vcc_io>; }; - vcc_host: usb-host-regulator { + vcc_host: regulator-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -58,7 +58,7 @@ vcc_host: usb-host-regulator { vin-supply = <&vcc_sys>; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -70,7 +70,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-phycore-rdk.dts b/arch/arm/boot/dts/rockchip/rk3288-phycore-rdk.dts index 1a515695149230..10ce0554d4fc9b 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-phycore-rdk.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-phycore-rdk.dts @@ -35,7 +35,7 @@ button-1 { }; }; - vcc_host0_5v: usb-host0-regulator { + vcc_host0_5v: regulator-usb-host0 { compatible = "regulator-fixed"; gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -47,7 +47,7 @@ vcc_host0_5v: usb-host0-regulator { vin-supply = <&vdd_in_otg_out>; }; - vcc_host1_5v: usb-host1-regulator { + vcc_host1_5v: regulator-usb-host1 { compatible = "regulator-fixed"; gpio = <&gpio2 0 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -59,7 +59,7 @@ vcc_host1_5v: usb-host1-regulator { vin-supply = <&vdd_in_otg_out>; }; - vcc_otg_5v: usb-otg-regulator { + vcc_otg_5v: regulator-usb-otg { compatible = "regulator-fixed"; gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/rockchip/rk3288-phycore-som.dtsi b/arch/arm/boot/dts/rockchip/rk3288-phycore-som.dtsi index e43887c9635ff6..12ab10c4addef1 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-phycore-som.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-phycore-som.dtsi @@ -46,7 +46,7 @@ user_led: led-0 { }; }; - vdd_emmc_io: vdd-emmc-io { + vdd_emmc_io: regulator-vdd-emmc-io { compatible = "regulator-fixed"; regulator-name = "vdd_emmc_io"; regulator-min-microvolt = <1800000>; @@ -54,7 +54,7 @@ vdd_emmc_io: vdd-emmc-io { vin-supply = <&vdd_3v3_io>; }; - vdd_in_otg_out: vdd-in-otg-out { + vdd_in_otg_out: regulator-vdd-in-otg-out { compatible = "regulator-fixed"; regulator-name = "vdd_in_otg_out"; regulator-always-on; @@ -63,7 +63,7 @@ vdd_in_otg_out: vdd-in-otg-out { regulator-max-microvolt = <5000000>; }; - vdd_misc_1v8: vdd-misc-1v8 { + vdd_misc_1v8: regulator-vdd-misc-1v8 { compatible = "regulator-fixed"; regulator-name = "vdd_misc_1v8"; regulator-always-on; diff --git a/arch/arm/boot/dts/rockchip/rk3288-popmetal.dts b/arch/arm/boot/dts/rockchip/rk3288-popmetal.dts index fd90f3b8fc328f..560bc23c33b18c 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-popmetal.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-popmetal.dts @@ -47,7 +47,7 @@ ir: ir-receiver { pinctrl-0 = <&ir_int>; }; - vcc_flash: flash-regulator { + vcc_flash: regulator-flash { compatible = "regulator-fixed"; regulator-name = "vcc_flash"; regulator-min-microvolt = <1800000>; @@ -55,7 +55,7 @@ vcc_flash: flash-regulator { vin-supply = <&vcc_io>; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -67,7 +67,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -80,7 +80,7 @@ vcc_sys: vsys-regulator { * A PT5128 creates both dovdd_1v8 and vcc28_dvp, controlled * by the dvp_pwr pin. */ - vcc18_dvp: vcc18-dvp-regulator { + vcc18_dvp: regulator-vcc18-dvp { compatible = "regulator-fixed"; regulator-name = "vcc18-dvp"; regulator-min-microvolt = <1800000>; @@ -88,7 +88,7 @@ vcc18_dvp: vcc18-dvp-regulator { vin-supply = <&vcc28_dvp>; }; - vcc28_dvp: vcc28-dvp-regulator { + vcc28_dvp: regulator-vcc28-dvp { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-r89.dts b/arch/arm/boot/dts/rockchip/rk3288-r89.dts index 633e5a0324635d..40c65dbfb1cd78 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-r89.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-r89.dts @@ -48,7 +48,7 @@ ir: ir-receiver { pinctrl-0 = <&ir_int>; }; - vcc_host: vcc-host-regulator { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -59,7 +59,7 @@ vcc_host: vcc-host-regulator { regulator-boot-on; }; - vcc_otg: vcc-otg-regulator { + vcc_otg: regulator-vcc-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; @@ -70,7 +70,7 @@ vcc_otg: vcc-otg-regulator { regulator-boot-on; }; - vcc_sdmmc: sdmmc-regulator { + vcc_sdmmc: regulator-sdmmc { compatible = "regulator-fixed"; regulator-name = "sdmmc-supply"; regulator-min-microvolt = <3300000>; @@ -80,7 +80,7 @@ vcc_sdmmc: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_sys: sys-regulator { + vcc_sys: regulator-sys { compatible = "regulator-fixed"; regulator-name = "sys-supply"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-rock2-som.dtsi b/arch/arm/boot/dts/rockchip/rk3288-rock2-som.dtsi index 76363b8afcb9b4..30f914f22a505f 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-rock2-som.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-rock2-som.dtsi @@ -23,7 +23,7 @@ ext_gmac: external-gmac-clock { clock-output-names = "ext_gmac"; }; - vcc_flash: flash-regulator { + vcc_flash: regulator-flash { compatible = "regulator-fixed"; regulator-name = "vcc_flash"; regulator-min-microvolt = <1800000>; @@ -32,7 +32,7 @@ vcc_flash: flash-regulator { vin-supply = <&vcc_io>; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-rock2-square.dts b/arch/arm/boot/dts/rockchip/rk3288-rock2-square.dts index 13cfdaa95cc7d7..58a7270b87da52 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-rock2-square.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-rock2-square.dts @@ -70,7 +70,7 @@ simple-audio-card,dai-link@1 { /* S/PDIF - S/PDIF */ }; }; - sata_pwr: sata-prw-regulator { + sata_pwr: regulator-sata-prw { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 13 GPIO_ACTIVE_HIGH>; @@ -108,7 +108,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>; }; - vcc_usb_host: vcc-host-regulator { + vcc_usb_host: regulator-vcc-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -117,7 +117,7 @@ vcc_usb_host: vcc-host-regulator { regulator-name = "vcc_host"; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio7 RK_PB3 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/rockchip/rk3288-tinker.dtsi b/arch/arm/boot/dts/rockchip/rk3288-tinker.dtsi index 09618bb7d872c9..8e27a20f284541 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-tinker.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-tinker.dtsi @@ -85,7 +85,7 @@ simple-audio-card,cpu { }; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -94,7 +94,7 @@ vcc_sys: vsys-regulator { regulator-boot-on; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio7 11 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron-brain.dts b/arch/arm/boot/dts/rockchip/rk3288-veyron-brain.dts index aa33d09184ad53..ade9cc291813ab 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-veyron-brain.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-veyron-brain.dts @@ -14,11 +14,11 @@ / { compatible = "google,veyron-brain-rev0", "google,veyron-brain", "google,veyron", "rockchip,rk3288"; - vcc33_sys: vcc33-sys { + vcc33_sys: regulator-vcc33-sys { vin-supply = <&vcc_5v>; }; - vcc33_io: vcc33_io { + vcc33_io: regulator-vcc33-io { compatible = "regulator-fixed"; regulator-name = "vcc33_io"; regulator-always-on; @@ -28,7 +28,7 @@ vcc33_io: vcc33_io { }; /* This turns on vbus for host2 and otg (dwc2) */ - vcc5_host2: vcc5-host2-regulator { + vcc5_host2: regulator-vcc5-host2 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rockchip/rk3288-veyron-chromebook.dtsi index 092316be67f740..3677571b4d827f 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-veyron-chromebook.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-veyron-chromebook.dtsi @@ -43,23 +43,23 @@ switch-lid { }; /* A non-regulated voltage from power supply or battery */ - vccsys: vccsys { + vccsys: regulator-vccsys { compatible = "regulator-fixed"; regulator-name = "vccsys"; regulator-boot-on; regulator-always-on; }; - vcc33_sys: vcc33-sys { + vcc33_sys: regulator-vcc33-sys { vin-supply = <&vccsys>; }; - vcc_5v: vcc-5v { + vcc_5v: regulator-vcc-5v { vin-supply = <&vccsys>; }; /* This turns on vbus for host1 (dwc2) */ - vcc5_host1: vcc5-host1-regulator { + vcc5_host1: regulator-vcc5-host1 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; @@ -71,7 +71,7 @@ vcc5_host1: vcc5-host1-regulator { }; /* This turns on vbus for otg for host mode (dwc2) */ - vcc5v_otg: vcc5v-otg-regulator { + vcc5v_otg: regulator-vcc5v-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi b/arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi index 32c0f10765dd38..fb031964fa2bb0 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-veyron-edp.dtsi @@ -6,7 +6,7 @@ */ / { - backlight_regulator: backlight-regulator { + backlight_regulator: regulator-backlight { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>; @@ -17,7 +17,7 @@ backlight_regulator: backlight-regulator { startup-delay-us = <15000>; }; - panel_regulator: panel-regulator { + panel_regulator: regulator-panel { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio7 RK_PB6 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron-fievel.dts b/arch/arm/boot/dts/rockchip/rk3288-veyron-fievel.dts index 309b122b4d0df2..6a0844e162793d 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-veyron-fievel.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-veyron-fievel.dts @@ -18,7 +18,7 @@ / { "google,veyron-fievel-rev0", "google,veyron-fievel", "google,veyron", "rockchip,rk3288"; - vccsys: vccsys { + vccsys: regulator-vccsys { compatible = "regulator-fixed"; regulator-name = "vccsys"; regulator-boot-on; @@ -29,14 +29,14 @@ vccsys: vccsys { * vcc33_pmuio and vcc33_io is sourced directly from vcc33_sys, * enabled by vcc_18 */ - vcc33_io: vcc33-io { + vcc33_io: regulator-vcc33-io { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; regulator-name = "vcc33_io"; }; - vcc5_host1: vcc5-host1-regulator { + vcc5_host1: regulator-vcc5-host1 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio5 RK_PC2 GPIO_ACTIVE_HIGH>; @@ -47,7 +47,7 @@ vcc5_host1: vcc5-host1-regulator { regulator-boot-on; }; - vcc5_host2: vcc5-host2-regulator { + vcc5_host2: regulator-vcc5-host2 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio5 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -58,7 +58,7 @@ vcc5_host2: vcc5-host2-regulator { regulator-boot-on; }; - vcc5v_otg: vcc5v-otg-regulator { + vcc5v_otg: regulator-vcc5v-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron-mickey.dts b/arch/arm/boot/dts/rockchip/rk3288-veyron-mickey.dts index ffd1121d19bed7..d665c3e8862cdf 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-veyron-mickey.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-veyron-mickey.dts @@ -18,11 +18,11 @@ / { "google,veyron-mickey-rev0", "google,veyron-mickey", "google,veyron", "rockchip,rk3288"; - vcc_5v: vcc-5v { + vcc_5v: regulator-vcc-5v { vin-supply = <&vcc33_sys>; }; - vcc33_io: vcc33_io { + vcc33_io: regulator-vcc33-io { compatible = "regulator-fixed"; regulator-name = "vcc33_io"; regulator-always-on; diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron-pinky.dts b/arch/arm/boot/dts/rockchip/rk3288-veyron-pinky.dts index 6337238891eb0a..cc27d116d02560 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-veyron-pinky.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-veyron-pinky.dts @@ -14,8 +14,8 @@ / { compatible = "google,veyron-pinky-rev2", "google,veyron-pinky", "google,veyron", "rockchip,rk3288"; - /delete-node/backlight-regulator; - /delete-node/panel-regulator; + /delete-node/regulator-backlight; + /delete-node/regulator-panel; /delete-node/emmc-pwrseq; /delete-node/vcc18-lcd; }; diff --git a/arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi b/arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi index d838bf0d5d9a08..260d6c92cfd11d 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-veyron.dtsi @@ -75,7 +75,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>; }; - vcc_5v: vcc-5v { + vcc_5v: regulator-vcc-5v { compatible = "regulator-fixed"; regulator-name = "vcc_5v"; regulator-always-on; @@ -84,7 +84,7 @@ vcc_5v: vcc-5v { regulator-max-microvolt = <5000000>; }; - vcc33_sys: vcc33-sys { + vcc33_sys: regulator-vcc33-sys { compatible = "regulator-fixed"; regulator-name = "vcc33_sys"; regulator-always-on; @@ -93,7 +93,7 @@ vcc33_sys: vcc33-sys { regulator-max-microvolt = <3300000>; }; - vcc50_hdmi: vcc50-hdmi { + vcc50_hdmi: regulator-vcc50-hdmi { compatible = "regulator-fixed"; regulator-name = "vcc50_hdmi"; regulator-always-on; @@ -101,7 +101,7 @@ vcc50_hdmi: vcc50-hdmi { vin-supply = <&vcc_5v>; }; - vdd_logic: vdd-logic { + vdd_logic: regulator-vdd-logic { compatible = "pwm-regulator"; regulator-name = "vdd_logic"; diff --git a/arch/arm/boot/dts/rockchip/rk3288-vmarc-som.dtsi b/arch/arm/boot/dts/rockchip/rk3288-vmarc-som.dtsi index 793951655b73b8..44a9efc68f4258 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-vmarc-som.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288-vmarc-som.dtsi @@ -11,7 +11,7 @@ / { compatible = "vamrs,rk3288-vmarc-som", "rockchip,rk3288"; - vccio_flash: vccio-flash-regulator { + vccio_flash: regulator-vccio-flash { compatible = "regulator-fixed"; regulator-name = "vccio_flash"; regulator-min-microvolt = <1800000>; diff --git a/arch/arm/boot/dts/rockchip/rk3288-vyasa.dts b/arch/arm/boot/dts/rockchip/rk3288-vyasa.dts index b156a83eb7d785..1954475c69b6b6 100644 --- a/arch/arm/boot/dts/rockchip/rk3288-vyasa.dts +++ b/arch/arm/boot/dts/rockchip/rk3288-vyasa.dts @@ -19,7 +19,7 @@ memory { device_type = "memory"; }; - dc12_vbat: dc12-vbat { + dc12_vbat: regulator-dc12-vbat { compatible = "regulator-fixed"; regulator-name = "dc12_vbat"; regulator-min-microvolt = <12000000>; @@ -28,7 +28,7 @@ dc12_vbat: dc12-vbat { regulator-boot-on; }; - vboot_3v3: vboot-3v3 { + vboot_3v3: regulator-vboot-3v3 { compatible = "regulator-fixed"; regulator-name = "vboot_3v3"; regulator-min-microvolt = <3300000>; @@ -38,7 +38,7 @@ vboot_3v3: vboot-3v3 { vin-supply = <&dc12_vbat>; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <3700000>; @@ -48,7 +48,7 @@ vcc_sys: vsys-regulator { vin-supply = <&dc12_vbat>; }; - vboot_5v: vboot-5v { + vboot_5v: regulator-vboot-5v { compatible = "regulator-fixed"; regulator-name = "vboot_sv"; regulator-min-microvolt = <5000000>; @@ -58,7 +58,7 @@ vboot_5v: vboot-5v { vin-supply = <&dc12_vbat>; }; - v3g_3v3: v3g-3v3 { + v3g_3v3: regulator-v3g-3v3 { compatible = "regulator-fixed"; regulator-name = "v3g_3v3"; regulator-min-microvolt = <3300000>; @@ -68,7 +68,7 @@ v3g_3v3: v3g-3v3 { vin-supply = <&dc12_vbat>; }; - vsus_5v: vsus-5v { + vsus_5v: regulator-vsus-5v { compatible = "regulator-fixed"; regulator-name = "vsus_5v"; regulator-min-microvolt = <5000000>; @@ -78,7 +78,7 @@ vsus_5v: vsus-5v { vin-supply = <&vcc_io>; }; - vcc50_hdmi: vcc50-hdmi { + vcc50_hdmi: regulator-vcc50-hdmi { compatible = "regulator-fixed"; regulator-name = "vcc50_hdmi"; enable-active-high; @@ -90,7 +90,7 @@ vcc50_hdmi: vcc50-hdmi { vin-supply = <&vsus_5v>; }; - vusb1_5v: vusb1-5v { + vusb1_5v: regulator-vusb1-5v { compatible = "regulator-fixed"; regulator-name = "vusb1_5v"; enable-active-high; @@ -102,7 +102,7 @@ vusb1_5v: vusb1-5v { vin-supply = <&vsus_5v>; }; - vusb2_5v: vusb2-5v { + vusb2_5v: regulator-vusb2-5v { compatible = "regulator-fixed"; regulator-name = "vusb2_5v"; enable-active-high; diff --git a/arch/arm/boot/dts/rockchip/rockchip-radxa-dalang-carrier.dtsi b/arch/arm/boot/dts/rockchip/rockchip-radxa-dalang-carrier.dtsi index da1d548b7330cd..cf5e2ed356ef70 100644 --- a/arch/arm/boot/dts/rockchip/rockchip-radxa-dalang-carrier.dtsi +++ b/arch/arm/boot/dts/rockchip/rockchip-radxa-dalang-carrier.dtsi @@ -23,7 +23,7 @@ sdio_pwrseq: sdio-pwrseq { pinctrl-0 = <&wifi_enable_h>; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -32,7 +32,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -42,7 +42,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vbus_host: vbus-host { + vbus_host: regulator-vbus-host { compatible = "regulator-fixed"; pinctrl-names = "default"; pinctrl-0 = <&usb1_en_oc>; @@ -51,7 +51,7 @@ vbus_host: vbus-host { vin-supply = <&vcc5v0_sys>; }; - vbus_typec: vbus-typec { + vbus_typec: regulator-vbus-typec { compatible = "regulator-fixed"; pinctrl-names = "default"; pinctrl-0 = <&usb0_en_oc>; diff --git a/arch/arm/boot/dts/rockchip/rv1108-elgin-r1.dts b/arch/arm/boot/dts/rockchip/rv1108-elgin-r1.dts index 89ca2f8d38098d..3c64f0cca9ebe1 100644 --- a/arch/arm/boot/dts/rockchip/rv1108-elgin-r1.dts +++ b/arch/arm/boot/dts/rockchip/rv1108-elgin-r1.dts @@ -25,7 +25,7 @@ chosen { stdout-path = "serial2:1500000n8"; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vsys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rv1108-evb.dts b/arch/arm/boot/dts/rockchip/rv1108-evb.dts index ef150f4ee99d5c..0b04a8325d5430 100644 --- a/arch/arm/boot/dts/rockchip/rv1108-evb.dts +++ b/arch/arm/boot/dts/rockchip/rv1108-evb.dts @@ -60,7 +60,7 @@ backlight: backlight { pwms = <&pwm0 0 25000 0>; }; - vcc_sys: vsys-regulator { + vcc_sys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vsys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/rockchip/rv1109-relfor-saib.dts b/arch/arm/boot/dts/rockchip/rv1109-relfor-saib.dts new file mode 100644 index 00000000000000..c13829d32c3253 --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1109-relfor-saib.dts @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Relfor Labs Pvt. Ltd. + */ + + +/dts-v1/; +#include "rv1109.dtsi" +#include +#include + +/ { + model = "Rockchip RV1109 Relfor Saib Board"; + compatible = "relfor,saib", "rockchip,rv1109"; + + gpio-keys { + compatible = "gpio-keys"; + + button { + gpios = <&gpio2 RK_PA7 GPIO_ACTIVE_HIGH>; + linux,code = ; + label = "GPIO User Switch"; + linux,input-type = <1>; + }; + }; + + ir_receiver: ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ir_rx>; + }; + + ir_transmitter: ir-transmitter { + compatible = "pwm-ir-tx"; + pwms = <&pwm11 0 10000000 1>; + }; + + led-controller { + compatible = "pwm-leds-multicolor"; + + multi-led { + color = ; + function = LED_FUNCTION_INDICATOR; + max-brightness = <65535>; + + led-0 { + active-low; + color = ; + pwms = <&pwm9 0 50000 0>; + }; + + led-1 { + active-low; + color = ; + pwms = <&pwm6 0 50000 0>; + }; + + led-2 { + active-low; + color = ; + pwms = <&pwm10 0 50000 0>; + }; + }; + }; + + pwm-leds { + compatible = "pwm-leds"; + + led-0 { + pwms = <&pwm2 0 50000 0>; + max-brightness = <255>; + linux,default-trigger = "none"; + }; + + led-1 { + pwms = <&pwm8 0 50000 0>; + max-brightness = <0>; + linux,default-trigger = "none"; + }; + + led-2 { + pwms = <&pwm5 0 50000 0>; + max-brightness = <255>; + linux,default-trigger = "none"; + }; + }; + + sdio_pwrseq: pwrseq-sdio { + compatible = "mmc-pwrseq-simple"; + clocks = <&rtc0>; + clock-names = "ext_clock"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_enable_h>; + reset-gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_LOW>; + }; + + vcc_0v8: regulator-vcc-0v8 { + compatible = "regulator-fixed"; + regulator-name = "vcc_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-always-on; + regulator-boot-on; + startup-delay-us = <150>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc_1v2_ddr: regulator-vcc-1v2-ddr { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v2_ddr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + startup-delay-us = <75000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc_1v8: regulator-vcc-1v8 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + startup-delay-us = <51000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc1v8_ir: regulator-vcc1v8-ir { + compatible = "regulator-fixed"; + regulator-name = "vcc1v8_ir"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc5v0_sys>; + }; + + vcc_2v5_ddr: regulator-vcc-2v5-ddr { + compatible = "regulator-fixed"; + regulator-name = "vcc_2v5_ddr"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc3v3_sys>; + }; + + vcc3v3_sys: regulator-vcc3v3-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_sys"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + startup-delay-us = <75000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_sys: regulator-vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_arm: regulator-vdd-arm { + compatible = "pwm-regulator"; + pwms = <&pwm0 0 5000 1>; + regulator-name = "vdd_arm"; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1000000>; + regulator-settling-time-up-us = <18000>; + regulator-always-on; + regulator-boot-on; + pwm-supply = <&vcc3v3_sys>; + vin-supply = <&vcc5v0_sys>; + }; + + vdd_npu_vepu: regulator-vdd-npu-vepu { + compatible = "pwm-regulator"; + pwms = <&pwm1 0 5000 1>; + regulator-name = "vdd_npu_vepu"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <950000>; + regulator-settling-time-up-us = <18000>; + regulator-always-on; + regulator-boot-on; + pwm-supply = <&vcc3v3_sys>; + vin-supply = <&vcc5v0_sys>; + }; + + thermal_sensor1: thermal-sensor1 { + compatible = "generic-adc-thermal"; + #thermal-sensor-cells = <0>; + io-channels = <&saradc 1>; + io-channel-names = "sensor-channel"; + temperature-lookup-table = <(-40000) 826 + 85000 609>; + }; + + thermal_sensor2: thermal-sensor2 { + compatible = "generic-adc-thermal"; + #thermal-sensor-cells = <0>; + io-channels = <&saradc 2>; + io-channel-names = "sensor-channel"; + temperature-lookup-table = <(-40000) 826 + 85000 609>; + }; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&emmc { + bus-width = <8>; + non-removable; + pinctrl-0 = <&emmc_bus8 &emmc_cmd &emmc_clk>; + pinctrl-names = "default"; + rockchip,default-sample-phase = <90>; + vmmc-supply = <&vcc3v3_sys>; + status = "okay"; +}; + +&i2c3 { + pinctrl-0 = <&i2c3m2_xfer>; + pinctrl-names = "default"; + status = "okay"; + + rtc0: rtc@52 { + compatible = "microcrystal,rv3028"; + reg = <0x52>; + #clock-cells = <0>; + interrupt-parent = <&gpio2>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&rtc_int>; + pinctrl-names = "default"; + }; +}; + +&i2s0 { + /delete-property/ pinctrl-0; + rockchip,trcm-sync-rx-only; + pinctrl-0 = <&i2s0m0_sclk_rx>, + <&i2s0m0_lrck_rx>, + <&i2s0m0_sdi0>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pinctrl { + bluetooth-pins { + bt_reset: bt-reset { + rockchip,pins = + <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + bt_wake_dev: bt-wake-dev { + rockchip,pins = + <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + bt_wake_host: bt-wake-host { + rockchip,pins = + <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + buttons { + switch: switch { + rockchip,pins = <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + ir { + ir_rx: ir-rx { + rockchip,pins = <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pwm { + pwm0m0_pins_pull_up: pwm0m0-pins-pull-up { + rockchip,pins = + /* pwm0_pin_m0 */ + <0 RK_PB6 3 &pcfg_pull_up>; + }; + pwm1m0_pins_pull_up: pwm1m0-pins-pull-up { + rockchip,pins = + /* pwm1_pin_m0 */ + <0 RK_PB7 3 &pcfg_pull_up>; + }; + }; + + rtc { + rtc_int: rtc-int { + rockchip,pins = <2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdio-pwrseq { + wifi_enable_h: wifi-enable-h { + rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pmu_io_domains { + pmuio0-supply = <&vcc3v3_sys>; + pmuio1-supply = <&vcc3v3_sys>; + vccio4-supply = <&vcc3v3_sys>; + vccio5-supply = <&vcc3v3_sys>; + vccio6-supply = <&vcc3v3_sys>; + vccio7-supply = <&vcc3v3_sys>; + status = "okay"; +}; + +&pwm0 { + /delete-property/ pinctrl-0; + pinctrl-0 = <&pwm0m0_pins_pull_up>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm1 { + /delete-property/ pinctrl-0; + pinctrl-0 = <&pwm1m0_pins_pull_up>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm2 { + /delete-property/ pinctrl-0; + pinctrl-0 = <&pwm2m1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm5 { + pinctrl-0 = <&pwm5m0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm6 { + pinctrl-0 = <&pwm6m0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm8 { + pinctrl-0 = <&pwm8m1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm9 { + pinctrl-0 = <&pwm9m1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm10 { + pinctrl-0 = <&pwm10m1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm11 { + /delete-property/ pinctrl-0; + pinctrl-0 = <&pwm11m1_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdio { + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + max-frequency = <100000000>; + mmc-pwrseq = <&sdio_pwrseq>; + no-mmc; + no-sd; + non-removable; + pinctrl-0 = <&sdmmc1_clk &sdmmc1_cmd &sdmmc1_bus4>; + pinctrl-names = "default"; + sd-uhs-sdr104; + vmmc-supply = <&vcc3v3_sys>; + status = "okay"; +}; + +&uart0 { + pinctrl-0 = <&uart0_xfer &uart0_ctsn &uart0_rtsn>; + pinctrl-names = "default"; + status = "okay"; + + bluetooth { + compatible = "realtek,rtl8822cs-bt"; + device-wake-gpios = <&gpio1 RK_PC5 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>; + host-wake-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&bt_reset>, <&bt_wake_dev>, <&bt_wake_host>; + pinctrl-names = "default"; + }; +}; + +&uart2 { + pinctrl-0 = <&uart2m1_xfer>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts b/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts index 7707d1b01440b0..d4e93d7c57a680 100644 --- a/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts +++ b/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts @@ -21,7 +21,7 @@ chosen { stdout-path = "serial2:1500000n8"; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -30,7 +30,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -40,7 +40,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - v3v3_sys: v3v3-sys-regulator { + v3v3_sys: regulator-v3v3-sys { compatible = "regulator-fixed"; regulator-name = "v3v3_sys"; regulator-always-on; diff --git a/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2.dtsi b/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2.dtsi index 7ea8d7d16f5f26..5c1b60deb51bf0 100644 --- a/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2.dtsi @@ -11,7 +11,7 @@ aliases { mmc0 = &emmc; }; - vccio_flash: vccio-flash-regulator { + vccio_flash: regulator-vccio-flash { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/rockchip/rv1126.dtsi b/arch/arm/boot/dts/rockchip/rv1126.dtsi index 434846b85c957f..d6e8b63daa4207 100644 --- a/arch/arm/boot/dts/rockchip/rv1126.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126.dtsi @@ -544,6 +544,14 @@ timer0: timer@ff660000 { clock-names = "pclk", "timer"; }; + wdt: watchdog@ff680000 { + compatible = "rockchip,rv1126-wdt", "snps,dw-wdt"; + reg = <0xff680000 0x100>; + interrupts = ; + clocks = <&cru PCLK_WDT>; + status = "disabled"; + }; + i2s0: i2s@ff800000 { compatible = "rockchip,rv1126-i2s-tdm"; reg = <0xff800000 0x1000>; diff --git a/arch/arm/boot/dts/st/spear1310-evb.dts b/arch/arm/boot/dts/st/spear1310-evb.dts index 18191a87f07cd0..ad216571ba5797 100644 --- a/arch/arm/boot/dts/st/spear1310-evb.dts +++ b/arch/arm/boot/dts/st/spear1310-evb.dts @@ -353,7 +353,6 @@ stmpe610@0 { spi-max-frequency = <1000000>; spi-cpha; pl022,interface = <0>; - pl022,slave-tx-disable; pl022,com-mode = <0>; pl022,rx-level-trig = <0>; pl022,tx-level-trig = <0>; @@ -385,7 +384,6 @@ flash@1 { spi-cpol; spi-cpha; pl022,interface = <0>; - pl022,slave-tx-disable; pl022,com-mode = <0x2>; pl022,rx-level-trig = <0>; pl022,tx-level-trig = <0>; diff --git a/arch/arm/boot/dts/st/spear1340-evb.dts b/arch/arm/boot/dts/st/spear1340-evb.dts index cea624fc745c6c..9b515b21a633bc 100644 --- a/arch/arm/boot/dts/st/spear1340-evb.dts +++ b/arch/arm/boot/dts/st/spear1340-evb.dts @@ -446,7 +446,6 @@ flash@0 { spi-cpol; spi-cpha; pl022,interface = <0>; - pl022,slave-tx-disable; pl022,com-mode = <0x2>; pl022,rx-level-trig = <0>; pl022,tx-level-trig = <0>; @@ -461,7 +460,6 @@ stmpe610@1 { spi-cpha; reg = <1>; pl022,interface = <0>; - pl022,slave-tx-disable; pl022,com-mode = <0>; pl022,rx-level-trig = <0>; pl022,tx-level-trig = <0>; diff --git a/arch/arm/boot/dts/st/ste-dbx5x0-pinctrl.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0-pinctrl.dtsi index 31a86606bedaed..9a6304b7ab2566 100644 --- a/arch/arm/boot/dts/st/ste-dbx5x0-pinctrl.dtsi +++ b/arch/arm/boot/dts/st/ste-dbx5x0-pinctrl.dtsi @@ -454,6 +454,31 @@ default_cfg3 { }; }; + /* MC2 without feedback clock on A8 */ + mc2_a_2_default: mc2_a_2_default { + default_mux { + function = "mc2"; + groups = "mc2_a_2"; + }; + default_cfg1 { + pins = "GPIO128_A5"; /* CLK */ + ste,config = <&out_lo>; + }; + default_cfg2 { + pins = + "GPIO129_B4", /* CMD */ + "GPIO131_A12", /* DAT0 */ + "GPIO132_C10", /* DAT1 */ + "GPIO133_B10", /* DAT2 */ + "GPIO134_B9", /* DAT3 */ + "GPIO135_A9", /* DAT4 */ + "GPIO136_C7", /* DAT5 */ + "GPIO137_A7", /* DAT6 */ + "GPIO138_C5"; /* DAT7 */ + ste,config = <&in_pu>; + }; + }; + mc2_a_1_sleep: mc2_a_1_sleep { sleep_cfg1 { pins = "GPIO128_A5"; /* CLK */ @@ -478,6 +503,30 @@ sleep_cfg3 { ste,config = <&in_wkup_pdis>; }; }; + + mc2_a_2_sleep: mc2_a_2_sleep { + sleep_cfg1 { + pins = "GPIO128_A5"; /* CLK */ + ste,config = <&out_lo_wkup_pdis>; + }; + sleep_cfg2 { + pins = + "GPIO129_B4"; /* CMD */ + ste,config = <&in_wkup_pdis_en>; + }; + sleep_cfg3 { + pins = + "GPIO131_A12", /* DAT0 */ + "GPIO132_C10", /* DAT1 */ + "GPIO133_B10", /* DAT2 */ + "GPIO134_B9", /* DAT3 */ + "GPIO135_A9", /* DAT4 */ + "GPIO136_C7", /* DAT5 */ + "GPIO137_A7", /* DAT6 */ + "GPIO138_C5"; /* DAT7 */ + ste,config = <&in_wkup_pdis>; + }; + }; }; sdi4 { diff --git a/arch/arm/boot/dts/st/ste-ux500-samsung-codina-tmo.dts b/arch/arm/boot/dts/st/ste-ux500-samsung-codina-tmo.dts index c623cc35c5ea23..404d4ea9347b99 100644 --- a/arch/arm/boot/dts/st/ste-ux500-samsung-codina-tmo.dts +++ b/arch/arm/boot/dts/st/ste-ux500-samsung-codina-tmo.dts @@ -544,6 +544,7 @@ touchscreen@20 { touchscreen-size-y = <800>; pinctrl-names = "default"; pinctrl-0 = <&tsp_default>; + linux,keycodes = , ; }; }; diff --git a/arch/arm/boot/dts/st/ste-ux500-samsung-codina.dts b/arch/arm/boot/dts/st/ste-ux500-samsung-codina.dts index 2355ca6e9ad6c6..40b0d92dfb1546 100644 --- a/arch/arm/boot/dts/st/ste-ux500-samsung-codina.dts +++ b/arch/arm/boot/dts/st/ste-ux500-samsung-codina.dts @@ -451,13 +451,17 @@ mmc@80005000 { no-sdio; no-sd; vmmc-supply = <&ldo_3v3_reg>; + vqmmc-supply = <&db8500_vsmps2_reg>; pinctrl-names = "default", "sleep"; /* - * GPIO130 will be set to input no pull-up resulting in a resistor - * pulling the reset high and taking the memory out of reset. + * This muxing excludes the feedback clock on GPIO130 + * which is instead used for reset of the eMMC. + * GPIO130 will be set to input no pull-up resulting in + * a resistor pulling the reset high and taking the + * memory out of reset. */ - pinctrl-0 = <&mc2_a_1_default>; - pinctrl-1 = <&mc2_a_1_sleep>; + pinctrl-0 = <&mc2_a_2_default>; + pinctrl-1 = <&mc2_a_2_sleep>; status = "okay"; }; @@ -644,6 +648,7 @@ touchscreen@20 { touchscreen-size-y = <800>; pinctrl-names = "default"; pinctrl-0 = <&tsp_default>; + linux,keycodes = , ; }; }; @@ -677,14 +682,14 @@ default_cfg4 { sdi2 { /* * This will make the resistor mounted in R0.0 pull up - * the reset line and take the eMMC out of reset. On - * R0.4 variants, GPIO130 should be set in GPIO mode and - * pulled down. (Not connected.) + * the reset line and take the eMMC out of reset so set to + * GPIO input mode, no pull-up. On R0.4 variants, GPIO130 + * could be set in GPIO mode and pulled down. (Not connected.) */ - mc2_a_1_default { - default_cfg2 { - pins = "GPIO130_C8"; /* FBCLK */ - ste,config = <&in_nopull>; + mc2_a_2_default { + default_cfg3 { + pins = "GPIO130_C8"; /* RST_N */ + ste,config = <&gpio_in_nopull>; }; }; }; diff --git a/arch/arm/boot/dts/st/stm32mp13-pinctrl.dtsi b/arch/arm/boot/dts/st/stm32mp13-pinctrl.dtsi index 8db1ec4a3b2686..a422b32d71d135 100644 --- a/arch/arm/boot/dts/st/stm32mp13-pinctrl.dtsi +++ b/arch/arm/boot/dts/st/stm32mp13-pinctrl.dtsi @@ -594,6 +594,13 @@ pins { }; }; + /omit-if-no-ref/ + rtc_rsvd_pins_a: rtc-rsvd-0 { + pins { + pinmux = ; /* RTC_OUT2_RMP */ + }; + }; + /omit-if-no-ref/ sai1a_pins_a: sai1a-0 { pins { diff --git a/arch/arm/boot/dts/st/stm32mp135f-dk.dts b/arch/arm/boot/dts/st/stm32mp135f-dk.dts index 1af335a39993b1..3a276589fef793 100644 --- a/arch/arm/boot/dts/st/stm32mp135f-dk.dts +++ b/arch/arm/boot/dts/st/stm32mp135f-dk.dts @@ -121,6 +121,19 @@ panel_in_rgb: endpoint { }; }; }; + + v3v3_ao: v3v3-ao { + compatible = "regulator-fixed"; + regulator-name = "v3v3_ao"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&mcp23017 11 GPIO_ACTIVE_LOW>; + }; }; &adc_1 { @@ -346,7 +359,14 @@ ltdc_out_rgb: endpoint { }; &rtc { + pinctrl-names = "default"; + pinctrl-0 = <&rtc_rsvd_pins_a>; status = "okay"; + + rtc_lsco_pins_a: rtc-lsco-0 { + pins = "out2_rmp"; + function = "lsco"; + }; }; &scmi_regu { @@ -385,6 +405,30 @@ &sdmmc1 { status = "okay"; }; +/* Wifi */ +&sdmmc2 { + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_clk_pins_a>; + pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_clk_pins_a>; + pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>; + non-removable; + cap-sdio-irq; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3_ao>; + mmc-pwrseq = <&wifi_pwrseq>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_lsco_pins_a>; + }; +}; + &spi5 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&spi5_pins_a>; @@ -491,6 +535,14 @@ &usart2 { pinctrl-2 = <&usart2_idle_pins_a>; uart-has-rtscts; status = "okay"; + + bluetooth { + shutdown-gpios = <&mcp23017 13 GPIO_ACTIVE_HIGH>; + compatible = "brcm,bcm43438-bt"; + max-speed = <3000000>; + vbat-supply = <&v3v3_ao>; + vddio-supply = <&v3v3_ao>; + }; }; &usbh_ehci { diff --git a/arch/arm/boot/dts/st/stm32mp13xx-dhcor-som.dtsi b/arch/arm/boot/dts/st/stm32mp13xx-dhcor-som.dtsi index ddad6497775b8e..5edbc790d1d273 100644 --- a/arch/arm/boot/dts/st/stm32mp13xx-dhcor-som.dtsi +++ b/arch/arm/boot/dts/st/stm32mp13xx-dhcor-som.dtsi @@ -201,6 +201,12 @@ eeprom0: eeprom@50 { pagesize = <64>; }; + eeprom0wl: eeprom@58 { + compatible = "st,24256e-wl"; /* ST M24256E WL page of 0x50 */ + pagesize = <64>; + reg = <0x58>; + }; + rv3032: rtc@51 { compatible = "microcrystal,rv3032"; reg = <0x51>; diff --git a/arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi index 70e132dc6147f5..95fafc51a1c8e8 100644 --- a/arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15-pinctrl.dtsi @@ -1696,6 +1696,13 @@ pins { }; }; + /omit-if-no-ref/ + rtc_rsvd_pins_a: rtc-rsvd-0 { + pins { + pinmux = ; /* RTC_OUT2_RMP */ + }; + }; + /omit-if-no-ref/ sai2a_pins_a: sai2a-0 { pins { diff --git a/arch/arm/boot/dts/st/stm32mp151.dtsi b/arch/arm/boot/dts/st/stm32mp151.dtsi index 4f878ec102c1f6..b28dc90926bdac 100644 --- a/arch/arm/boot/dts/st/stm32mp151.dtsi +++ b/arch/arm/boot/dts/st/stm32mp151.dtsi @@ -355,6 +355,8 @@ iwdg2: watchdog@5a002000 { reg = <0x5a002000 0x400>; clocks = <&rcc IWDG2>, <&rcc CK_LSI>; clock-names = "pclk", "lsi"; + interrupts-extended = <&exti 46 IRQ_TYPE_LEVEL_HIGH>; + wakeup-source; status = "disabled"; }; diff --git a/arch/arm/boot/dts/st/stm32mp157c-dk2.dts b/arch/arm/boot/dts/st/stm32mp157c-dk2.dts index 7a701f7ef0c704..5f9c0160a9c492 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-dk2.dts +++ b/arch/arm/boot/dts/st/stm32mp157c-dk2.dts @@ -24,6 +24,11 @@ aliases { chosen { stdout-path = "serial0:115200n8"; }; + + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpioh 4 GPIO_ACTIVE_LOW>; + }; }; &cryp1 { @@ -84,10 +89,54 @@ ltdc_ep1_out: endpoint@1 { }; }; +&rtc { + pinctrl-names = "default"; + pinctrl-0 = <&rtc_rsvd_pins_a>; + + rtc_lsco_pins_a: rtc-lsco-0 { + pins = "out2_rmp"; + function = "lsco"; + }; +}; + +/* Wifi */ +&sdmmc2 { + pinctrl-names = "default", "opendrain", "sleep"; + pinctrl-0 = <&sdmmc2_b4_pins_a>; + pinctrl-1 = <&sdmmc2_b4_od_pins_a>; + pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>; + non-removable; + cap-sdio-irq; + st,neg-edge; + bus-width = <4>; + vmmc-supply = <&v3v3>; + mmc-pwrseq = <&wifi_pwrseq>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_lsco_pins_a>; + }; +}; + +/* Bluetooth */ &usart2 { pinctrl-names = "default", "sleep", "idle"; pinctrl-0 = <&usart2_pins_c>; pinctrl-1 = <&usart2_sleep_pins_c>; pinctrl-2 = <&usart2_idle_pins_c>; - status = "disabled"; + uart-has-rtscts; + status = "okay"; + + bluetooth { + shutdown-gpios = <&gpioz 6 GPIO_ACTIVE_HIGH>; + compatible = "brcm,bcm43438-bt"; + max-speed = <3000000>; + vbat-supply = <&v3v3>; + vddio-supply = <&v3v3>; + }; }; diff --git a/arch/arm/boot/dts/ti/omap/am335x-baltos.dtsi b/arch/arm/boot/dts/ti/omap/am335x-baltos.dtsi index a4beb718559c42..ae2e8dffbe0492 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-baltos.dtsi +++ b/arch/arm/boot/dts/ti/omap/am335x-baltos.dtsi @@ -199,7 +199,6 @@ nand@0,0 { ti,nand-ecc-opt = "bch8"; ti,nand-xfer-type = "prefetch-dma"; - gpmc,device-nand = "true"; gpmc,device-width = <1>; gpmc,sync-clk-ps = <0>; gpmc,cs-on-ns = <0>; @@ -251,7 +250,7 @@ tps: tps@2d { pinctrl-0 = <&tps65910_pins>; }; - at24@50 { + eeprom@50 { compatible = "atmel,24c02"; pagesize = <8>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi b/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi index a0fb431aec8411..c400b7b70d0d20 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/am335x-bone-common.dtsi @@ -216,7 +216,7 @@ tps: tps@24 { reg = <0x24>; }; - baseboard_eeprom: baseboard_eeprom@50 { + baseboard_eeprom: eeprom@50 { compatible = "atmel,24c256"; reg = <0x50>; vcc-supply = <&ldo4_reg>; @@ -240,7 +240,7 @@ &i2c2 { status = "okay"; clock-frequency = <100000>; - cape_eeprom0: cape_eeprom0@54 { + cape_eeprom0: eeprom@54 { compatible = "atmel,24c256"; reg = <0x54>; @@ -255,7 +255,7 @@ cape0_data: cape_data@0 { }; }; - cape_eeprom1: cape_eeprom1@55 { + cape_eeprom1: eeprom@55 { compatible = "atmel,24c256"; reg = <0x55>; @@ -270,7 +270,7 @@ cape1_data: cape_data@0 { }; }; - cape_eeprom2: cape_eeprom2@56 { + cape_eeprom2: eeprom@56 { compatible = "atmel,24c256"; reg = <0x56>; @@ -285,7 +285,7 @@ cape2_data: cape_data@0 { }; }; - cape_eeprom3: cape_eeprom3@57 { + cape_eeprom3: eeprom@57 { compatible = "atmel,24c256"; reg = <0x57>; @@ -409,7 +409,7 @@ ethphy0: ethernet-phy@0 { /* Support GPIO reset on revision C3 boards */ reset-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; reset-assert-us = <300>; - reset-deassert-us = <13000>; + reset-deassert-us = <50000>; }; }; diff --git a/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts b/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts index 8878da773d6790..f579df4c2c540d 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-boneblue.dts @@ -313,7 +313,7 @@ &usb1 { }; &i2c0 { - baseboard_eeprom: baseboard_eeprom@50 { + baseboard_eeprom: eeprom@50 { compatible = "atmel,24c256"; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts b/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts index 17574d0d05259e..ded19e24e66655 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-pdu001.dts @@ -289,7 +289,7 @@ tps: tps@2d { reg = <0x2d>; }; - m2_eeprom: m2_eeprom@50 { + m2_eeprom: eeprom@50 { compatible = "atmel,24c256"; reg = <0x50>; status = "okay"; @@ -303,12 +303,12 @@ &i2c1 { status = "okay"; clock-frequency = <100000>; - board_24aa025e48: board_24aa025e48@50 { + board_24aa025e48: eeprom@50 { compatible = "atmel,24c02"; reg = <0x50>; }; - backplane_24aa025e48: backplane_24aa025e48@53 { + backplane_24aa025e48: eeprom@53 { compatible = "atmel,24c02"; reg = <0x53>; }; diff --git a/arch/arm/boot/dts/ti/omap/am335x-shc.dts b/arch/arm/boot/dts/ti/omap/am335x-shc.dts index 9297cb1efcd4b6..5974828226082f 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-shc.dts +++ b/arch/arm/boot/dts/ti/omap/am335x-shc.dts @@ -169,7 +169,7 @@ tps: tps@24 { reg = <0x24>; }; - at24@50 { + eeprom@50 { compatible = "atmel,24c32"; pagesize = <32>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/am3517-som.dtsi b/arch/arm/boot/dts/ti/omap/am3517-som.dtsi index bd0a6c95afa16d..e36cd98f57fab4 100644 --- a/arch/arm/boot/dts/ti/omap/am3517-som.dtsi +++ b/arch/arm/boot/dts/ti/omap/am3517-som.dtsi @@ -44,7 +44,6 @@ &gpmc { nand@0,0 { compatible = "ti,omap2-nand"; - linux,mtd-name = "micron,mt29f4g16abchch"; reg = <0 0 4>; /* CS0, offset 0, IO size 4 */ nand-bus-width = <16>; ti,nand-ecc-opt = "bch8"; diff --git a/arch/arm/boot/dts/ti/omap/am3874-iceboard.dts b/arch/arm/boot/dts/ti/omap/am3874-iceboard.dts index ac082e83a9a204..bbb9200a1f268d 100644 --- a/arch/arm/boot/dts/ti/omap/am3874-iceboard.dts +++ b/arch/arm/boot/dts/ti/omap/am3874-iceboard.dts @@ -249,8 +249,8 @@ u59: pca9575@23 { tmp100@4c { compatible = "ti,tmp100"; reg = <0x4c>; }; /* EEPROM bank and serial number are treated as separate devices */ - at24c01@57 { compatible = "atmel,24c01"; reg = <0x57>; }; - at24cs01@5f { compatible = "atmel,24cs01"; reg = <0x5f>; }; + eeprom@57 { compatible = "atmel,24c01"; reg = <0x57>; }; + eeprom@5f { compatible = "atmel,24cs01"; reg = <0x5f>; }; }; }; }; @@ -270,8 +270,8 @@ i2c@6 { multi-master; /* All backplanes should have this -- it's how we know they're there. */ - at24c08@54 { compatible="atmel,24c08"; reg=<0x54>; }; - at24cs08@5c { compatible="atmel,24cs08"; reg=<0x5c>; }; + eeprom@54 { compatible="atmel,24c08"; reg=<0x54>; }; + eeprom@5c { compatible="atmel,24cs08"; reg=<0x5c>; }; /* 16 slot backplane */ tmp421@4d { compatible="ti,tmp421"; reg=<0x4d>; }; diff --git a/arch/arm/boot/dts/ti/omap/am437x-cm-t43.dts b/arch/arm/boot/dts/ti/omap/am437x-cm-t43.dts index 172516a7667e19..e06fc30091c89e 100644 --- a/arch/arm/boot/dts/ti/omap/am437x-cm-t43.dts +++ b/arch/arm/boot/dts/ti/omap/am437x-cm-t43.dts @@ -254,7 +254,7 @@ ldo1: regulator-ldo1 { }; }; - eeprom_module: at24@50 { + eeprom_module: eeprom@50 { compatible = "atmel,24c02"; reg = <0x50>; pagesize = <16>; diff --git a/arch/arm/boot/dts/ti/omap/am437x-idk-evm.dts b/arch/arm/boot/dts/ti/omap/am437x-idk-evm.dts index 00682ce7e14c4d..826f687c368abe 100644 --- a/arch/arm/boot/dts/ti/omap/am437x-idk-evm.dts +++ b/arch/arm/boot/dts/ti/omap/am437x-idk-evm.dts @@ -333,7 +333,7 @@ &i2c0 { pinctrl-1 = <&i2c0_pins_sleep>; clock-frequency = <400000>; - at24@50 { + eeprom@50 { compatible = "atmel,24c256"; pagesize = <64>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/am437x-sbc-t43.dts b/arch/arm/boot/dts/ti/omap/am437x-sbc-t43.dts index 5ec57dcb06592c..73badf80b4ff36 100644 --- a/arch/arm/boot/dts/ti/omap/am437x-sbc-t43.dts +++ b/arch/arm/boot/dts/ti/omap/am437x-sbc-t43.dts @@ -112,7 +112,7 @@ pca9555: pca9555@20 { #gpio-cells = <2>; }; - eeprom_base: at24@50 { + eeprom_base: eeprom@50 { compatible = "atmel,24c02"; reg = <0x50>; pagesize = <16>; diff --git a/arch/arm/boot/dts/ti/omap/am437x-sk-evm.dts b/arch/arm/boot/dts/ti/omap/am437x-sk-evm.dts index 9c97006ffd5b01..4700f9879d2d27 100644 --- a/arch/arm/boot/dts/ti/omap/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/ti/omap/am437x-sk-evm.dts @@ -570,7 +570,7 @@ power-button { }; }; - at24@50 { + eeprom@50 { compatible = "atmel,24c256"; pagesize = <64>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/am43x-epos-evm.dts b/arch/arm/boot/dts/ti/omap/am43x-epos-evm.dts index 9193a4cfba78a9..4ac94be8d00037 100644 --- a/arch/arm/boot/dts/ti/omap/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/ti/omap/am43x-epos-evm.dts @@ -651,7 +651,7 @@ ldo1: regulator-ldo1 { }; }; - at24@50 { + eeprom@50 { compatible = "atmel,24c256"; pagesize = <64>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/am57xx-cl-som-am57x.dts b/arch/arm/boot/dts/ti/omap/am57xx-cl-som-am57x.dts index d6e3152b02f70b..3dd898955e767e 100644 --- a/arch/arm/boot/dts/ti/omap/am57xx-cl-som-am57x.dts +++ b/arch/arm/boot/dts/ti/omap/am57xx-cl-som-am57x.dts @@ -429,7 +429,7 @@ rtc0: rtc@56 { reg = <0x56>; }; - eeprom_module: atmel@50 { + eeprom_module: eeprom@50 { compatible = "atmel,24c08"; reg = <0x50>; pagesize = <16>; diff --git a/arch/arm/boot/dts/ti/omap/am57xx-sbc-am57x.dts b/arch/arm/boot/dts/ti/omap/am57xx-sbc-am57x.dts index 64675f4edb6013..41bef36c55541d 100644 --- a/arch/arm/boot/dts/ti/omap/am57xx-sbc-am57x.dts +++ b/arch/arm/boot/dts/ti/omap/am57xx-sbc-am57x.dts @@ -105,7 +105,7 @@ &i2c5 { pinctrl-0 = <&i2c5_pins_default>; clock-frequency = <400000>; - eeprom_base: atmel@54 { + eeprom_base: eeprom@54 { compatible = "atmel,24c08"; reg = <0x54>; pagesize = <16>; diff --git a/arch/arm/boot/dts/ti/omap/dm8148-evm.dts b/arch/arm/boot/dts/ti/omap/dm8148-evm.dts index ae8d9fa09d16b9..57a9eef09f6f09 100644 --- a/arch/arm/boot/dts/ti/omap/dm8148-evm.dts +++ b/arch/arm/boot/dts/ti/omap/dm8148-evm.dts @@ -51,7 +51,6 @@ nand@0,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "micron,mt29f2g16aadwp"; #address-cells = <1>; #size-cells = <1>; ti,nand-ecc-opt = "bch8"; diff --git a/arch/arm/boot/dts/ti/omap/dm8168-evm.dts b/arch/arm/boot/dts/ti/omap/dm8168-evm.dts index 1d80288f6ba5fa..6130b9a5f66068 100644 --- a/arch/arm/boot/dts/ti/omap/dm8168-evm.dts +++ b/arch/arm/boot/dts/ti/omap/dm8168-evm.dts @@ -119,7 +119,6 @@ &gpmc { nand@0,0 { compatible = "ti,omap2-nand"; - linux,mtd-name = "micron,mt29f2g16aadwp"; reg = <0 0 4>; /* CS0, offset 0, IO size 4 */ interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ diff --git a/arch/arm/boot/dts/ti/omap/dra62x-j5eco-evm.dts b/arch/arm/boot/dts/ti/omap/dra62x-j5eco-evm.dts index 2f6ac267fc1503..df05a06823221b 100644 --- a/arch/arm/boot/dts/ti/omap/dra62x-j5eco-evm.dts +++ b/arch/arm/boot/dts/ti/omap/dra62x-j5eco-evm.dts @@ -51,7 +51,6 @@ nand@0,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "micron,mt29f2g16aadwp"; #address-cells = <1>; #size-cells = <1>; ti,nand-ecc-opt = "bch8"; diff --git a/arch/arm/boot/dts/ti/omap/dra7.dtsi b/arch/arm/boot/dts/ti/omap/dra7.dtsi index 164fa88c459e97..b709703f6c0d42 100644 --- a/arch/arm/boot/dts/ti/omap/dra7.dtsi +++ b/arch/arm/boot/dts/ti/omap/dra7.dtsi @@ -9,7 +9,6 @@ #include #include #include -#include #define MAX_SOURCES 400 diff --git a/arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi b/arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi index 04f08b8c64d278..0de16ee262cf47 100644 --- a/arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi +++ b/arch/arm/boot/dts/ti/omap/dra7xx-clocks.dtsi @@ -1376,7 +1376,6 @@ optfclk_pciephy_div: clock-optfclk-pciephy-div-8@4a00821c { clocks = <&apll_pcie_ck>; #clock-cells = <0>; reg = <0x021c>; - ti,dividers = <2>, <1>; ti,bit-shift = <8>; ti,max-div = <2>; }; diff --git a/arch/arm/boot/dts/ti/omap/logicpd-som-lv.dtsi b/arch/arm/boot/dts/ti/omap/logicpd-som-lv.dtsi index c0e6b73fa472db..d51a436d9774d6 100644 --- a/arch/arm/boot/dts/ti/omap/logicpd-som-lv.dtsi +++ b/arch/arm/boot/dts/ti/omap/logicpd-som-lv.dtsi @@ -51,7 +51,6 @@ nand@0,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "micron,mt29f4g16abbda3w"; nand-bus-width = <16>; ti,nand-ecc-opt = "bch8"; rb-gpios = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 */ diff --git a/arch/arm/boot/dts/ti/omap/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/ti/omap/logicpd-torpedo-som.dtsi index 227699890890a6..0b65ac5b423093 100644 --- a/arch/arm/boot/dts/ti/omap/logicpd-torpedo-som.dtsi +++ b/arch/arm/boot/dts/ti/omap/logicpd-torpedo-som.dtsi @@ -49,7 +49,6 @@ nand@0,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "micron,mt29f4g16abbda3w"; nand-bus-width = <16>; ti,nand-ecc-opt = "bch8"; rb-gpios = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 */ @@ -103,7 +102,7 @@ &i2c3 { pinctrl-names = "default"; pinctrl-0 = <&i2c3_pins>; clock-frequency = <400000>; - at24@50 { + eeprom@50 { compatible = "atmel,24c64"; readonly; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/omap3-cm-t3x.dtsi b/arch/arm/boot/dts/ti/omap/omap3-cm-t3x.dtsi index 950a29f9b4a0b7..cd13826d033d8e 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-cm-t3x.dtsi +++ b/arch/arm/boot/dts/ti/omap/omap3-cm-t3x.dtsi @@ -190,7 +190,7 @@ &i2c1 { clock-frequency = <400000>; - at24@50 { + eeprom@50 { compatible = "atmel,24c02"; pagesize = <16>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/omap3-evm-37xx.dts b/arch/arm/boot/dts/ti/omap/omap3-evm-37xx.dts index e0346bf842fcd1..9c60ac853a4045 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-evm-37xx.dts +++ b/arch/arm/boot/dts/ti/omap/omap3-evm-37xx.dts @@ -60,7 +60,6 @@ nand@0,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "hynix,h8kds0un0mer-4em"; nand-bus-width = <16>; gpmc,device-width = <2>; ti,nand-ecc-opt = "bch8"; diff --git a/arch/arm/boot/dts/ti/omap/omap3-evm.dts b/arch/arm/boot/dts/ti/omap/omap3-evm.dts index a2a1613c45c3ef..28caa5d93b87cd 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-evm.dts +++ b/arch/arm/boot/dts/ti/omap/omap3-evm.dts @@ -60,7 +60,6 @@ nand@0,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "micron,mt29f2g16abdhc"; nand-bus-width = <16>; gpmc,device-width = <2>; ti,nand-ecc-opt = "bch8"; diff --git a/arch/arm/boot/dts/ti/omap/omap3-gta04.dtsi b/arch/arm/boot/dts/ti/omap/omap3-gta04.dtsi index 3661340009e7a4..2ee3ddd640209b 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-gta04.dtsi +++ b/arch/arm/boot/dts/ti/omap/omap3-gta04.dtsi @@ -601,7 +601,7 @@ tsc2007@48 { }; /* RFID EEPROM */ - m24lr64@50 { + eeprom@50 { compatible = "atmel,24c64"; reg = <0x50>; }; diff --git a/arch/arm/boot/dts/ti/omap/omap3-gta04a5.dts b/arch/arm/boot/dts/ti/omap/omap3-gta04a5.dts index 8bd6b4b1f30b89..d3a81f0b880fd7 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-gta04a5.dts +++ b/arch/arm/boot/dts/ti/omap/omap3-gta04a5.dts @@ -114,6 +114,16 @@ wlcore: wlcore@2 { }; }; +&uart1 { + bluetooth { + compatible = "ti,wl1837-st"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_pins>; + enable-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>; /* GPIO_137 */ + }; +}; + + &i2c2 { /delete-node/ bmp085@77; /delete-node/ bma180@41; diff --git a/arch/arm/boot/dts/ti/omap/omap3-igep.dtsi b/arch/arm/boot/dts/ti/omap/omap3-igep.dtsi index e068ecf86b8f8a..7346cad84edab9 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-igep.dtsi +++ b/arch/arm/boot/dts/ti/omap/omap3-igep.dtsi @@ -111,7 +111,6 @@ nand@0,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "micron,mt29c4g96maz"; nand-bus-width = <16>; gpmc,device-width = <2>; ti,nand-ecc-opt = "bch8"; diff --git a/arch/arm/boot/dts/ti/omap/omap3-ldp.dts b/arch/arm/boot/dts/ti/omap/omap3-ldp.dts index bb6fab9fa47dfd..cf325f56b46445 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-ldp.dts +++ b/arch/arm/boot/dts/ti/omap/omap3-ldp.dts @@ -103,7 +103,6 @@ nand@0,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "micron,nand"; nand-bus-width = <16>; gpmc,device-width = <2>; ti,nand-ecc-opt = "bch8"; diff --git a/arch/arm/boot/dts/ti/omap/omap3-overo-base.dtsi b/arch/arm/boot/dts/ti/omap/omap3-overo-base.dtsi index cc57626ea6076d..2793821b2c3383 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-overo-base.dtsi +++ b/arch/arm/boot/dts/ti/omap/omap3-overo-base.dtsi @@ -222,7 +222,6 @@ &gpmc { nand@0,0 { compatible = "ti,omap2-nand"; - linux,mtd-name = "micron,mt29c4g96maz"; reg = <0 0 4>; /* CS0, offset 0, IO size 4 */ interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ diff --git a/arch/arm/boot/dts/ti/omap/omap3-sb-t35.dtsi b/arch/arm/boot/dts/ti/omap/omap3-sb-t35.dtsi index 6730c749d5eaf7..da80d7b7d4b149 100644 --- a/arch/arm/boot/dts/ti/omap/omap3-sb-t35.dtsi +++ b/arch/arm/boot/dts/ti/omap/omap3-sb-t35.dtsi @@ -89,7 +89,7 @@ &i2c3 { clock-frequency = <400000>; - at24@50 { + eeprom@50 { compatible = "atmel,24c02"; pagesize = <16>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/omap3430-sdp.dts b/arch/arm/boot/dts/ti/omap/omap3430-sdp.dts index 258ecd9e45198f..cc5e9035ef73a3 100644 --- a/arch/arm/boot/dts/ti/omap/omap3430-sdp.dts +++ b/arch/arm/boot/dts/ti/omap/omap3430-sdp.dts @@ -105,7 +105,6 @@ nand@1,0 { interrupt-parent = <&gpmc>; interrupts = <0 IRQ_TYPE_NONE>, /* fifoevent */ <1 IRQ_TYPE_NONE>; /* termcount */ - linux,mtd-name = "micron,mt29f1g08abb"; #address-cells = <1>; #size-cells = <1>; ti,nand-ecc-opt = "sw"; @@ -148,7 +147,6 @@ partition@780000 { }; onenand@2,0 { - linux,mtd-name = "samsung,kfm2g16q2m-deb8"; #address-cells = <1>; #size-cells = <1>; compatible = "ti,omap2-onenand"; diff --git a/arch/arm/boot/dts/ti/omap/omap36xx.dtsi b/arch/arm/boot/dts/ti/omap/omap36xx.dtsi index c3d79ecd56e398..c217094b50abc9 100644 --- a/arch/arm/boot/dts/ti/omap/omap36xx.dtsi +++ b/arch/arm/boot/dts/ti/omap/omap36xx.dtsi @@ -72,6 +72,7 @@ opp-1000000000 { <1375000 1375000 1375000>; /* only on am/dm37x with speed-binned bit set */ opp-supported-hw = <0xffffffff 2>; + turbo-mode; }; }; diff --git a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts index 339e52ba3614b6..c90f43cc2fae9c 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts @@ -17,16 +17,34 @@ memory@80000000 { reg = <0x80000000 0x40000000>; /* 1024M */ }; + battery: battery { + compatible = "simple-battery"; + device-chemistry = "lithium-ion"; + charge-full-design-microamp-hours = <2720000>; + voltage-max-design-microvolt = <4200000>; + voltage-min-design-microvolt = <3300000>; + + constant-charge-voltage-max-microvolt = <4200000>; + /* + * vendor kernel says max charge 1400000, input limit 900000 + * and charges only with dcp chargers. So it is unclear what + * is really allowed. Play safe for now and restrict things + * here. Maybe 900000 is just the limit of the vendor charger? + */ + constant-charge-current-max-microamp = <900000>; + charge-term-current-microamp = <200000>; + }; + backlight-left { compatible = "pwm-backlight"; pwms = <&twl_pwm 1 7812500>; - power-supply = <&unknown_supply>; + power-supply = <&lb_v50>; }; backlight-right { compatible = "pwm-backlight"; pwms = <&twl_pwm 0 7812500>; - power-supply = <&unknown_supply>; + power-supply = <&lb_v50>; }; chosen { @@ -46,9 +64,53 @@ key-lock { }; }; - unknown_supply: unknown-supply { + cb_v18: regulator-cb-v18 { + pinctrl-names = "default"; + pinctrl-0 = <&cb_v18_pins>; + compatible = "regulator-fixed"; + regulator-name = "cb_v18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + cb_v33: regulator-cb-v33 { + pinctrl-names = "default"; + pinctrl-0 = <&cb_v33_pins>; + compatible = "regulator-fixed"; + regulator-name = "cb_v33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + gpio = <&gpio6 30 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + regulator-cb-v50 { + pinctrl-names = "default"; + pinctrl-0 = <&cb_v50_pins>; + compatible = "regulator-fixed"; + regulator-name = "cb_v50"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + gpio = <&gpio6 31 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + lb_v50: regulator-lb-v50 { + /* required for many things at the head (probably indirectly) */ + pinctrl-names = "default"; + pinctrl-0 = <&lb_v50_pins>; compatible = "regulator-fixed"; - regulator-name = "unknown"; + regulator-name = "lb_v50"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + gpio = <&gpio1 27 GPIO_ACTIVE_HIGH>; + enable-active-high; }; wl12xx_pwrseq: wl12xx-pwrseq { @@ -71,6 +133,73 @@ wl12xx_vmmc: wl12xx-vmmc { }; }; +&gpio1 { + pinctrl-names = "default"; + pinctrl-0 = <&gpio1_hog_pins &gpio1wk_hog_pins>; + + lb-reset-hog { + gpio-hog; + gpios = <9 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "lb_reset"; + }; + + power-en-hog { + gpio-hog; + gpios = <10 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "power_en"; + }; + + /* + * Name taken from vendor kernel but no evidence of actual usage found + * nor what it really controls. + */ + panel-power-en-hog { + gpio-hog; + gpios = <14 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "panel_power_en"; + }; + + /* + * These two are exported to sysfs in vendor kernel, usage unknown, + * backlight state seems unrelated to these. + */ + blc-r-hog { + gpio-hog; + gpios = <17 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "blc_r"; + }; + + blc-l-hog { + gpio-hog; + gpios = <16 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "blc_l"; + }; + + high-hog { + gpio-hog; + gpios = <15 GPIO_ACTIVE_HIGH /* maybe dsi to dpi chip reset? */ + 21 GPIO_ACTIVE_HIGH + 26 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "unknown-high"; + }; + + low-hog { + gpio-hog; + gpios = <18 GPIO_ACTIVE_HIGH + 19 GPIO_ACTIVE_HIGH + 20 GPIO_ACTIVE_HIGH + 22 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "unknown-low"; + }; +}; + &i2c1 { pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins>; @@ -87,6 +216,14 @@ twl: pmic@48 { #interrupt-cells = <1>; system-power-controller; + charger { + compatible = "ti,twl6032-charger", "ti,twl6030-charger"; + interrupts = <2>, <5>; + io-channels = <&gpadc 10>; + io-channel-names = "vusb"; + monitored-battery = <&battery>; + }; + rtc { compatible = "ti,twl4030-rtc"; interrupts = <11>; @@ -166,7 +303,7 @@ twl_pwmled: pwmled { #pwm-cells = <2>; }; - gpadc { + gpadc: gpadc { compatible = "ti,twl6032-gpadc"; interrupts = <3>; #io-channel-cells = <1>; @@ -188,6 +325,19 @@ &i2c2 { clock-frequency = <200000>; + /* is sometimes not available, research needed */ + gpio_head: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; + + /* + * camera chip at 0x3c, available if <&gpio_head 1> high + * and <&gpio_head 5> low + */ + /* at head/glasses */ mpu9150h: imu@68 { compatible = "invensense,mpu9150"; @@ -259,6 +409,8 @@ mpu9150: imu@68 { pinctrl-0 = <&mpu9150_pins>; interrupt-parent = <&gpio2>; interrupt = <7 IRQ_TYPE_LEVEL_HIGH>; + vddio-supply = <&cb_v18>; + vdd-supply = <&cb_v33>; invensense,level-shifter; }; }; @@ -336,12 +488,46 @@ OMAP4_IOPAD(0x1ca, PIN_OUTPUT | MUX_MODE3) /* gpio25 */ >; }; + cb_v18_pins: pinmux-cb-v18-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1d0, PIN_OUTPUT | MUX_MODE3) /* gpio28 */ + >; + }; + + cb_v33_pins: pinmux-cb-v33-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1d2, PIN_OUTPUT | MUX_MODE3) /* gpio190 */ + >; + }; + + cb_v50_pins: pinmux-cb-v50-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1d4, PIN_OUTPUT | MUX_MODE3) /* gpio191 */ + >; + }; + gpio_keys_pins: pinmux-gpio-key-pins { pinctrl-single,pins = < OMAP4_IOPAD(0x56, PIN_INPUT_PULLUP | MUX_MODE3) /* gpio35 */ >; }; + gpio1_hog_pins: pinmux-gpio1-hog-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1b4, PIN_OUTPUT | MUX_MODE3) /* gpio14 */ + OMAP4_IOPAD(0x1b8, PIN_OUTPUT | MUX_MODE3) /* gpio16 */ + OMAP4_IOPAD(0x1ba, PIN_OUTPUT | MUX_MODE3) /* gpio17 */ + + OMAP4_IOPAD(0x1b6, PIN_OUTPUT | MUX_MODE3) /* gpio15 */ + OMAP4_IOPAD(0x1bc, PIN_OUTPUT | MUX_MODE3) /* gpio18 */ + OMAP4_IOPAD(0x1be, PIN_OUTPUT | MUX_MODE3) /* gpio19 */ + OMAP4_IOPAD(0x1c0, PIN_OUTPUT | MUX_MODE3) /* gpio20 */ + OMAP4_IOPAD(0x1c2, PIN_OUTPUT | MUX_MODE3) /* gpio21 */ + OMAP4_IOPAD(0x1c4, PIN_OUTPUT | MUX_MODE3) /* gpio22 */ + OMAP4_IOPAD(0x1cc, PIN_OUTPUT | MUX_MODE3) /* gpio26 */ + >; + }; + i2c1_pins: pinmux-i2c1-pins { pinctrl-single,pins = < OMAP4_IOPAD(0x122, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */ @@ -387,6 +573,12 @@ OMAP4_IOPAD(0x005c, PIN_OUTPUT | MUX_MODE1) >; }; + lb_v50_pins: pinmux-lb-v50-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE3) /* gpio27 */ + >; + }; + mcbsp2_pins: pinmux-mcbsp2-pins { pinctrl-single,pins = < OMAP4_IOPAD(0x0f6, PIN_INPUT | MUX_MODE0) /* abe_mcbsp2_clkx */ @@ -457,6 +649,15 @@ OMAP4_IOPAD(0x1c8, PIN_OUTPUT | MUX_MODE3) /* gpio_24 / WLAN_EN */ }; }; +&omap4_pmx_wkup { + gpio1wk_hog_pins: pinmux-gpio1wk-hog-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x68, PIN_INPUT_PULLDOWN | MUX_MODE3) /* gpio9 */ + OMAP4_IOPAD(0x6a, PIN_INPUT | MUX_MODE3) /* gpio10 */ + >; + }; +}; + &uart2 { pinctrl-names = "default"; pinctrl-0 = <&uart2_pins &bt_pins>; diff --git a/arch/arm/boot/dts/ti/omap/omap4-kc1.dts b/arch/arm/boot/dts/ti/omap/omap4-kc1.dts index c6b79ba8bbc91a..df874d5f5327fc 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-kc1.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-kc1.dts @@ -112,11 +112,7 @@ twl: twl@48 { reg = <0x48>; /* IRQ# = 7 */ interrupts = ; /* IRQ_SYS_1N cascaded to gic */ - - twl_power: power { - compatible = "ti,twl6030-power"; - ti,system-power-controller; - }; + system-power-controller; }; }; diff --git a/arch/arm/boot/dts/ti/omap/omap5-cm-t54.dts b/arch/arm/boot/dts/ti/omap/omap5-cm-t54.dts index 6767382996ab33..2fd8111de90367 100644 --- a/arch/arm/boot/dts/ti/omap/omap5-cm-t54.dts +++ b/arch/arm/boot/dts/ti/omap/omap5-cm-t54.dts @@ -413,7 +413,7 @@ &i2c1 { clock-frequency = <400000>; - at24@50 { + eeprom@50 { compatible = "atmel,24c02"; pagesize = <16>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/omap5-sbc-t54.dts b/arch/arm/boot/dts/ti/omap/omap5-sbc-t54.dts index 02716fb796bda1..7ae60dc198f303 100644 --- a/arch/arm/boot/dts/ti/omap/omap5-sbc-t54.dts +++ b/arch/arm/boot/dts/ti/omap/omap5-sbc-t54.dts @@ -44,7 +44,7 @@ &i2c4 { clock-frequency = <400000>; - at24@50 { + eeprom@50 { compatible = "atmel,24c02"; pagesize = <16>; reg = <0x50>; diff --git a/arch/arm/boot/dts/ti/omap/twl4030.dtsi b/arch/arm/boot/dts/ti/omap/twl4030.dtsi index a5d9c5738317aa..07b9ca942e78d0 100644 --- a/arch/arm/boot/dts/ti/omap/twl4030.dtsi +++ b/arch/arm/boot/dts/ti/omap/twl4030.dtsi @@ -16,7 +16,7 @@ rtc { interrupts = <11>; }; - charger: bci { + charger: charger { compatible = "ti,twl4030-bci"; interrupts = <9>, <2>; bci3v1-supply = <&vusb3v1>; diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 06b0e5fd54a6d6..cb6ef449b987ac 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -516,7 +516,7 @@ static void locomo_remove(struct platform_device *dev) */ static struct platform_driver locomo_device_driver = { .probe = locomo_probe, - .remove_new = locomo_remove, + .remove = locomo_remove, #ifdef CONFIG_PM .suspend = locomo_suspend, .resume = locomo_resume, diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 550978dc3c50ea..9846f30990f711 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -1154,7 +1154,7 @@ static struct dev_pm_ops sa1111_pm_ops = { */ static struct platform_driver sa1111_device_driver = { .probe = sa1111_probe, - .remove_new = sa1111_remove, + .remove = sa1111_remove, .driver = { .name = "sa1111", .pm = &sa1111_pm_ops, diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index 9018c724016654..0b08b6621878bf 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -250,7 +250,7 @@ static void scoop_remove(struct platform_device *pdev) static struct platform_driver scoop_driver = { .probe = scoop_probe, - .remove_new = scoop_remove, + .remove = scoop_remove, .suspend = scoop_suspend, .resume = scoop_resume, .driver = { diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 2022a7fca0f981..f2596a1b2f7d9a 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -201,6 +201,7 @@ CONFIG_AT_XDMAC=y CONFIG_IIO=y CONFIG_AT91_ADC=y CONFIG_AT91_SAMA5D2_ADC=y +CONFIG_PAC1934=m CONFIG_PWM=y CONFIG_PWM_ATMEL=y CONFIG_PWM_ATMEL_HLCDC_PWM=y diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig index 333ef55476a30f..0beecdde55f583 100644 --- a/arch/arm/configs/imx_v6_v7_defconfig +++ b/arch/arm/configs/imx_v6_v7_defconfig @@ -68,6 +68,7 @@ CONFIG_BT=y CONFIG_BT_BNEP=m CONFIG_BT_HCIUART=y CONFIG_BT_HCIUART_LL=y +CONFIG_BT_NXPUART=m CONFIG_CFG80211=y CONFIG_CFG80211_WEXT=y CONFIG_MAC80211=y @@ -253,6 +254,7 @@ CONFIG_MFD_ROHM_BD71828=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_ANATOP=y CONFIG_REGULATOR_BD71815=y +CONFIG_REGULATOR_BD71828=y CONFIG_REGULATOR_DA9052=y CONFIG_REGULATOR_DA9062=y CONFIG_REGULATOR_DA9063=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 9a5f5c439b8791..758276027dbcd0 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -1323,5 +1323,8 @@ CONFIG_CRYPTO_DEV_STM32_HASH=m CONFIG_CRYPTO_DEV_STM32_CRYP=m CONFIG_CMA_SIZE_MBYTES=64 CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +CONFIG_DEBUG_INFO_REDUCED=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index e1cb170c2bf061..38916ac4bce481 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -583,10 +583,6 @@ CONFIG_EXT2_FS_SECURITY=y CONFIG_EXT3_FS=y CONFIG_EXT3_FS_POSIX_ACL=y CONFIG_EXT3_FS_SECURITY=y -CONFIG_REISERFS_FS=m -CONFIG_REISERFS_FS_XATTR=y -CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_REISERFS_FS_SECURITY=y CONFIG_XFS_FS=m CONFIG_AUTOFS_FS=m CONFIG_FUSE_FS=m diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 9096a99b5abdc8..e447329398d524 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -212,6 +212,7 @@ CONFIG_VIDEO_HANTRO=m CONFIG_IIO=y CONFIG_AT91_ADC=y CONFIG_AT91_SAMA5D2_ADC=y +CONFIG_PAC1934=m CONFIG_ENVELOPE_DETECTOR=m CONFIG_DPOT_DAC=m CONFIG_MCP4531=m diff --git a/arch/arm/configs/sama7_defconfig b/arch/arm/configs/sama7_defconfig index 7fa5d251ced282..1a2e93c8ee71bd 100644 --- a/arch/arm/configs/sama7_defconfig +++ b/arch/arm/configs/sama7_defconfig @@ -193,6 +193,7 @@ CONFIG_STAGING=y CONFIG_IIO=y CONFIG_IIO_SW_TRIGGER=y CONFIG_AT91_SAMA5D2_ADC=y +CONFIG_PAC1934=m CONFIG_PWM=y CONFIG_PWM_ATMEL=y CONFIG_MCHP_EIC=y diff --git a/arch/arm/crypto/crct10dif-ce-core.S b/arch/arm/crypto/crct10dif-ce-core.S index 46c02c518a300a..2bbf2df9c1e2fe 100644 --- a/arch/arm/crypto/crct10dif-ce-core.S +++ b/arch/arm/crypto/crct10dif-ce-core.S @@ -112,55 +112,120 @@ FOLD_CONST_L .req q10l FOLD_CONST_H .req q10h + /* + * Pairwise long polynomial multiplication of two 16-bit values + * + * { w0, w1 }, { y0, y1 } + * + * by two 64-bit values + * + * { x0, x1, x2, x3, x4, x5, x6, x7 }, { z0, z1, z2, z3, z4, z5, z6, z7 } + * + * where each vector element is a byte, ordered from least to most + * significant. The resulting 80-bit vectors are XOR'ed together. + * + * This can be implemented using 8x8 long polynomial multiplication, by + * reorganizing the input so that each pairwise 8x8 multiplication + * produces one of the terms from the decomposition below, and + * combining the results of each rank and shifting them into place. + * + * Rank + * 0 w0*x0 ^ | y0*z0 ^ + * 1 (w0*x1 ^ w1*x0) << 8 ^ | (y0*z1 ^ y1*z0) << 8 ^ + * 2 (w0*x2 ^ w1*x1) << 16 ^ | (y0*z2 ^ y1*z1) << 16 ^ + * 3 (w0*x3 ^ w1*x2) << 24 ^ | (y0*z3 ^ y1*z2) << 24 ^ + * 4 (w0*x4 ^ w1*x3) << 32 ^ | (y0*z4 ^ y1*z3) << 32 ^ + * 5 (w0*x5 ^ w1*x4) << 40 ^ | (y0*z5 ^ y1*z4) << 40 ^ + * 6 (w0*x6 ^ w1*x5) << 48 ^ | (y0*z6 ^ y1*z5) << 48 ^ + * 7 (w0*x7 ^ w1*x6) << 56 ^ | (y0*z7 ^ y1*z6) << 56 ^ + * 8 w1*x7 << 64 | y1*z7 << 64 + * + * The inputs can be reorganized into + * + * { w0, w0, w0, w0, y0, y0, y0, y0 }, { w1, w1, w1, w1, y1, y1, y1, y1 } + * { x0, x2, x4, x6, z0, z2, z4, z6 }, { x1, x3, x5, x7, z1, z3, z5, z7 } + * + * and after performing 8x8->16 bit long polynomial multiplication of + * each of the halves of the first vector with those of the second one, + * we obtain the following four vectors of 16-bit elements: + * + * a := { w0*x0, w0*x2, w0*x4, w0*x6 }, { y0*z0, y0*z2, y0*z4, y0*z6 } + * b := { w0*x1, w0*x3, w0*x5, w0*x7 }, { y0*z1, y0*z3, y0*z5, y0*z7 } + * c := { w1*x0, w1*x2, w1*x4, w1*x6 }, { y1*z0, y1*z2, y1*z4, y1*z6 } + * d := { w1*x1, w1*x3, w1*x5, w1*x7 }, { y1*z1, y1*z3, y1*z5, y1*z7 } + * + * Results b and c can be XORed together, as the vector elements have + * matching ranks. Then, the final XOR can be pulled forward, and + * applied between the halves of each of the remaining three vectors, + * which are then shifted into place, and XORed together to produce the + * final 80-bit result. + */ + .macro pmull16x64_p8, v16, v64 + vext.8 q11, \v64, \v64, #1 + vld1.64 {q12}, [r4, :128] + vuzp.8 q11, \v64 + vtbl.8 d24, {\v16\()_L-\v16\()_H}, d24 + vtbl.8 d25, {\v16\()_L-\v16\()_H}, d25 + bl __pmull16x64_p8 + veor \v64, q12, q14 + .endm + +__pmull16x64_p8: + vmull.p8 q13, d23, d24 + vmull.p8 q14, d23, d25 + vmull.p8 q15, d22, d24 + vmull.p8 q12, d22, d25 + + veor q14, q14, q15 + veor d24, d24, d25 + veor d26, d26, d27 + veor d28, d28, d29 + vmov.i32 d25, #0 + vmov.i32 d29, #0 + vext.8 q12, q12, q12, #14 + vext.8 q14, q14, q14, #15 + veor d24, d24, d26 + bx lr +ENDPROC(__pmull16x64_p8) + + .macro pmull16x64_p64, v16, v64 + vmull.p64 q11, \v64\()l, \v16\()_L + vmull.p64 \v64, \v64\()h, \v16\()_H + veor \v64, \v64, q11 + .endm + // Fold reg1, reg2 into the next 32 data bytes, storing the result back // into reg1, reg2. - .macro fold_32_bytes, reg1, reg2 - vld1.64 {q11-q12}, [buf]! + .macro fold_32_bytes, reg1, reg2, p + vld1.64 {q8-q9}, [buf]! - vmull.p64 q8, \reg1\()h, FOLD_CONST_H - vmull.p64 \reg1, \reg1\()l, FOLD_CONST_L - vmull.p64 q9, \reg2\()h, FOLD_CONST_H - vmull.p64 \reg2, \reg2\()l, FOLD_CONST_L + pmull16x64_\p FOLD_CONST, \reg1 + pmull16x64_\p FOLD_CONST, \reg2 -CPU_LE( vrev64.8 q11, q11 ) -CPU_LE( vrev64.8 q12, q12 ) - vswp q11l, q11h - vswp q12l, q12h +CPU_LE( vrev64.8 q8, q8 ) +CPU_LE( vrev64.8 q9, q9 ) + vswp q8l, q8h + vswp q9l, q9h veor.8 \reg1, \reg1, q8 veor.8 \reg2, \reg2, q9 - veor.8 \reg1, \reg1, q11 - veor.8 \reg2, \reg2, q12 .endm // Fold src_reg into dst_reg, optionally loading the next fold constants - .macro fold_16_bytes, src_reg, dst_reg, load_next_consts - vmull.p64 q8, \src_reg\()l, FOLD_CONST_L - vmull.p64 \src_reg, \src_reg\()h, FOLD_CONST_H + .macro fold_16_bytes, src_reg, dst_reg, p, load_next_consts + pmull16x64_\p FOLD_CONST, \src_reg .ifnb \load_next_consts vld1.64 {FOLD_CONSTS}, [fold_consts_ptr, :128]! .endif - veor.8 \dst_reg, \dst_reg, q8 veor.8 \dst_reg, \dst_reg, \src_reg .endm - .macro __adrl, out, sym - movw \out, #:lower16:\sym - movt \out, #:upper16:\sym - .endm - -// -// u16 crc_t10dif_pmull(u16 init_crc, const u8 *buf, size_t len); -// -// Assumes len >= 16. -// -ENTRY(crc_t10dif_pmull) - + .macro crct10dif, p // For sizes less than 256 bytes, we can't fold 128 bytes at a time. cmp len, #256 - blt .Lless_than_256_bytes + blt .Lless_than_256_bytes\@ - __adrl fold_consts_ptr, .Lfold_across_128_bytes_consts + mov_l fold_consts_ptr, .Lfold_across_128_bytes_consts // Load the first 128 data bytes. Byte swapping is necessary to make // the bit order match the polynomial coefficient order. @@ -199,27 +264,27 @@ CPU_LE( vrev64.8 q7, q7 ) // While >= 128 data bytes remain (not counting q0-q7), fold the 128 // bytes q0-q7 into them, storing the result back into q0-q7. -.Lfold_128_bytes_loop: - fold_32_bytes q0, q1 - fold_32_bytes q2, q3 - fold_32_bytes q4, q5 - fold_32_bytes q6, q7 +.Lfold_128_bytes_loop\@: + fold_32_bytes q0, q1, \p + fold_32_bytes q2, q3, \p + fold_32_bytes q4, q5, \p + fold_32_bytes q6, q7, \p subs len, len, #128 - bge .Lfold_128_bytes_loop + bge .Lfold_128_bytes_loop\@ // Now fold the 112 bytes in q0-q6 into the 16 bytes in q7. // Fold across 64 bytes. vld1.64 {FOLD_CONSTS}, [fold_consts_ptr, :128]! - fold_16_bytes q0, q4 - fold_16_bytes q1, q5 - fold_16_bytes q2, q6 - fold_16_bytes q3, q7, 1 + fold_16_bytes q0, q4, \p + fold_16_bytes q1, q5, \p + fold_16_bytes q2, q6, \p + fold_16_bytes q3, q7, \p, 1 // Fold across 32 bytes. - fold_16_bytes q4, q6 - fold_16_bytes q5, q7, 1 + fold_16_bytes q4, q6, \p + fold_16_bytes q5, q7, \p, 1 // Fold across 16 bytes. - fold_16_bytes q6, q7 + fold_16_bytes q6, q7, \p // Add 128 to get the correct number of data bytes remaining in 0...127 // (not counting q7), following the previous extra subtraction by 128. @@ -229,25 +294,23 @@ CPU_LE( vrev64.8 q7, q7 ) // While >= 16 data bytes remain (not counting q7), fold the 16 bytes q7 // into them, storing the result back into q7. - blt .Lfold_16_bytes_loop_done -.Lfold_16_bytes_loop: - vmull.p64 q8, q7l, FOLD_CONST_L - vmull.p64 q7, q7h, FOLD_CONST_H - veor.8 q7, q7, q8 + blt .Lfold_16_bytes_loop_done\@ +.Lfold_16_bytes_loop\@: + pmull16x64_\p FOLD_CONST, q7 vld1.64 {q0}, [buf]! CPU_LE( vrev64.8 q0, q0 ) vswp q0l, q0h veor.8 q7, q7, q0 subs len, len, #16 - bge .Lfold_16_bytes_loop + bge .Lfold_16_bytes_loop\@ -.Lfold_16_bytes_loop_done: +.Lfold_16_bytes_loop_done\@: // Add 16 to get the correct number of data bytes remaining in 0...15 // (not counting q7), following the previous extra subtraction by 16. adds len, len, #16 - beq .Lreduce_final_16_bytes + beq .Lreduce_final_16_bytes\@ -.Lhandle_partial_segment: +.Lhandle_partial_segment\@: // Reduce the last '16 + len' bytes where 1 <= len <= 15 and the first // 16 bytes are in q7 and the rest are the remaining data in 'buf'. To // do this without needing a fold constant for each possible 'len', @@ -262,9 +325,9 @@ CPU_LE( vrev64.8 q0, q0 ) vswp q0l, q0h // q1 = high order part of second chunk: q7 left-shifted by 'len' bytes. - __adrl r3, .Lbyteshift_table + 16 - sub r3, r3, len - vld1.8 {q2}, [r3] + mov_l r1, .Lbyteshift_table + 16 + sub r1, r1, len + vld1.8 {q2}, [r1] vtbl.8 q1l, {q7l-q7h}, q2l vtbl.8 q1h, {q7l-q7h}, q2h @@ -282,12 +345,46 @@ CPU_LE( vrev64.8 q0, q0 ) vbsl.8 q2, q1, q0 // Fold the first chunk into the second chunk, storing the result in q7. - vmull.p64 q0, q3l, FOLD_CONST_L - vmull.p64 q7, q3h, FOLD_CONST_H - veor.8 q7, q7, q0 - veor.8 q7, q7, q2 + pmull16x64_\p FOLD_CONST, q3 + veor.8 q7, q3, q2 + b .Lreduce_final_16_bytes\@ + +.Lless_than_256_bytes\@: + // Checksumming a buffer of length 16...255 bytes + + mov_l fold_consts_ptr, .Lfold_across_16_bytes_consts + + // Load the first 16 data bytes. + vld1.64 {q7}, [buf]! +CPU_LE( vrev64.8 q7, q7 ) + vswp q7l, q7h + + // XOR the first 16 data *bits* with the initial CRC value. + vmov.i8 q0h, #0 + vmov.u16 q0h[3], init_crc + veor.8 q7h, q7h, q0h + + // Load the fold-across-16-bytes constants. + vld1.64 {FOLD_CONSTS}, [fold_consts_ptr, :128]! + + cmp len, #16 + beq .Lreduce_final_16_bytes\@ // len == 16 + subs len, len, #32 + addlt len, len, #16 + blt .Lhandle_partial_segment\@ // 17 <= len <= 31 + b .Lfold_16_bytes_loop\@ // 32 <= len <= 255 + +.Lreduce_final_16_bytes\@: + .endm + +// +// u16 crc_t10dif_pmull(u16 init_crc, const u8 *buf, size_t len); +// +// Assumes len >= 16. +// +ENTRY(crc_t10dif_pmull64) + crct10dif p64 -.Lreduce_final_16_bytes: // Reduce the 128-bit value M(x), stored in q7, to the final 16-bit CRC. // Load 'x^48 * (x^48 mod G(x))' and 'x^48 * (x^80 mod G(x))'. @@ -320,32 +417,19 @@ CPU_LE( vrev64.8 q0, q0 ) vmov.u16 r0, q0l[0] bx lr +ENDPROC(crc_t10dif_pmull64) -.Lless_than_256_bytes: - // Checksumming a buffer of length 16...255 bytes +ENTRY(crc_t10dif_pmull8) + push {r4, lr} + mov_l r4, .L16x64perm - __adrl fold_consts_ptr, .Lfold_across_16_bytes_consts + crct10dif p8 - // Load the first 16 data bytes. - vld1.64 {q7}, [buf]! CPU_LE( vrev64.8 q7, q7 ) vswp q7l, q7h - - // XOR the first 16 data *bits* with the initial CRC value. - vmov.i8 q0h, #0 - vmov.u16 q0h[3], init_crc - veor.8 q7h, q7h, q0h - - // Load the fold-across-16-bytes constants. - vld1.64 {FOLD_CONSTS}, [fold_consts_ptr, :128]! - - cmp len, #16 - beq .Lreduce_final_16_bytes // len == 16 - subs len, len, #32 - addlt len, len, #16 - blt .Lhandle_partial_segment // 17 <= len <= 31 - b .Lfold_16_bytes_loop // 32 <= len <= 255 -ENDPROC(crc_t10dif_pmull) + vst1.64 {q7}, [r3, :128] + pop {r4, pc} +ENDPROC(crc_t10dif_pmull8) .section ".rodata", "a" .align 4 @@ -379,3 +463,6 @@ ENDPROC(crc_t10dif_pmull) .byte 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f .byte 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 .byte 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe , 0x0 + +.L16x64perm: + .quad 0x808080800000000, 0x909090901010101 diff --git a/arch/arm/crypto/crct10dif-ce-glue.c b/arch/arm/crypto/crct10dif-ce-glue.c index 79f3b204d8c03b..a8b74523729ee7 100644 --- a/arch/arm/crypto/crct10dif-ce-glue.c +++ b/arch/arm/crypto/crct10dif-ce-glue.c @@ -19,7 +19,9 @@ #define CRC_T10DIF_PMULL_CHUNK_SIZE 16U -asmlinkage u16 crc_t10dif_pmull(u16 init_crc, const u8 *buf, size_t len); +asmlinkage u16 crc_t10dif_pmull64(u16 init_crc, const u8 *buf, size_t len); +asmlinkage void crc_t10dif_pmull8(u16 init_crc, const u8 *buf, size_t len, + u8 out[16]); static int crct10dif_init(struct shash_desc *desc) { @@ -29,14 +31,14 @@ static int crct10dif_init(struct shash_desc *desc) return 0; } -static int crct10dif_update(struct shash_desc *desc, const u8 *data, - unsigned int length) +static int crct10dif_update_ce(struct shash_desc *desc, const u8 *data, + unsigned int length) { u16 *crc = shash_desc_ctx(desc); if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) { kernel_neon_begin(); - *crc = crc_t10dif_pmull(*crc, data, length); + *crc = crc_t10dif_pmull64(*crc, data, length); kernel_neon_end(); } else { *crc = crc_t10dif_generic(*crc, data, length); @@ -45,6 +47,27 @@ static int crct10dif_update(struct shash_desc *desc, const u8 *data, return 0; } +static int crct10dif_update_neon(struct shash_desc *desc, const u8 *data, + unsigned int length) +{ + u16 *crcp = shash_desc_ctx(desc); + u8 buf[16] __aligned(16); + u16 crc = *crcp; + + if (length > CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) { + kernel_neon_begin(); + crc_t10dif_pmull8(crc, data, length, buf); + kernel_neon_end(); + + crc = 0; + data = buf; + length = sizeof(buf); + } + + *crcp = crc_t10dif_generic(crc, data, length); + return 0; +} + static int crct10dif_final(struct shash_desc *desc, u8 *out) { u16 *crc = shash_desc_ctx(desc); @@ -53,10 +76,22 @@ static int crct10dif_final(struct shash_desc *desc, u8 *out) return 0; } -static struct shash_alg crc_t10dif_alg = { +static struct shash_alg algs[] = {{ + .digestsize = CRC_T10DIF_DIGEST_SIZE, + .init = crct10dif_init, + .update = crct10dif_update_neon, + .final = crct10dif_final, + .descsize = CRC_T10DIF_DIGEST_SIZE, + + .base.cra_name = "crct10dif", + .base.cra_driver_name = "crct10dif-arm-neon", + .base.cra_priority = 150, + .base.cra_blocksize = CRC_T10DIF_BLOCK_SIZE, + .base.cra_module = THIS_MODULE, +}, { .digestsize = CRC_T10DIF_DIGEST_SIZE, .init = crct10dif_init, - .update = crct10dif_update, + .update = crct10dif_update_ce, .final = crct10dif_final, .descsize = CRC_T10DIF_DIGEST_SIZE, @@ -65,19 +100,19 @@ static struct shash_alg crc_t10dif_alg = { .base.cra_priority = 200, .base.cra_blocksize = CRC_T10DIF_BLOCK_SIZE, .base.cra_module = THIS_MODULE, -}; +}}; static int __init crc_t10dif_mod_init(void) { - if (!(elf_hwcap2 & HWCAP2_PMULL)) + if (!(elf_hwcap & HWCAP_NEON)) return -ENODEV; - return crypto_register_shash(&crc_t10dif_alg); + return crypto_register_shashes(algs, 1 + !!(elf_hwcap2 & HWCAP2_PMULL)); } static void __exit crc_t10dif_mod_exit(void) { - crypto_unregister_shash(&crc_t10dif_alg); + crypto_unregister_shashes(algs, 1 + !!(elf_hwcap2 & HWCAP2_PMULL)); } module_init(crc_t10dif_mod_init); diff --git a/arch/arm/include/asm/arm_pmuv3.h b/arch/arm/include/asm/arm_pmuv3.h index f63ba8986b2488..2ec0e5e83fc98f 100644 --- a/arch/arm/include/asm/arm_pmuv3.h +++ b/arch/arm/include/asm/arm_pmuv3.h @@ -212,6 +212,8 @@ static inline void write_pmuserenr(u32 val) write_sysreg(val, PMUSERENR); } +static inline void write_pmuacr(u64 val) {} + static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {} static inline void kvm_clr_pmu_events(u32 clr) {} static inline bool kvm_pmu_counter_deferred(struct perf_event_attr *attr) @@ -231,6 +233,7 @@ static inline void kvm_vcpu_pmu_resync_el0(void) {} #define ARMV8_PMU_DFR_VER_V3P1 0x4 #define ARMV8_PMU_DFR_VER_V3P4 0x5 #define ARMV8_PMU_DFR_VER_V3P5 0x6 +#define ARMV8_PMU_DFR_VER_V3P9 0x9 #define ARMV8_PMU_DFR_VER_IMP_DEF 0xF static inline bool pmuv3_implemented(int pmuver) @@ -249,6 +252,11 @@ static inline bool is_pmuv3p5(int pmuver) return pmuver >= ARMV8_PMU_DFR_VER_V3P5; } +static inline bool is_pmuv3p9(int pmuver) +{ + return pmuver >= ARMV8_PMU_DFR_VER_V3P9; +} + static inline u64 read_pmceid0(void) { u64 val = read_sysreg(PMCEID0); diff --git a/arch/arm/include/asm/div64.h b/arch/arm/include/asm/div64.h index 4b69cf850451b0..d3ef8e416b27d2 100644 --- a/arch/arm/include/asm/div64.h +++ b/arch/arm/include/asm/div64.h @@ -52,10 +52,17 @@ static inline uint32_t __div64_32(uint64_t *n, uint32_t base) #else -static inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias) +#ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE +static __always_inline +#else +static inline +#endif +uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias) { unsigned long long res; register unsigned int tmp asm("ip") = 0; + bool no_ovf = __builtin_constant_p(m) && + ((m >> 32) + (m & 0xffffffff) < 0x100000000); if (!bias) { asm ( "umull %Q0, %R0, %Q1, %Q2\n\t" @@ -63,7 +70,7 @@ static inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias) : "=&r" (res) : "r" (m), "r" (n) : "cc"); - } else if (!(m & ((1ULL << 63) | (1ULL << 31)))) { + } else if (no_ovf) { res = m; asm ( "umlal %Q0, %R0, %Q1, %Q2\n\t" "mov %Q0, #0" @@ -80,7 +87,7 @@ static inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias) : "cc"); } - if (!(m & ((1ULL << 63) | (1ULL << 31)))) { + if (no_ovf) { asm ( "umlal %R0, %Q0, %R1, %Q2\n\t" "umlal %R0, %Q0, %Q1, %R2\n\t" "mov %R0, #0\n\t" diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h index e4eb54f6cd9fef..a35aba7f548ccb 100644 --- a/arch/arm/include/asm/jump_label.h +++ b/arch/arm/include/asm/jump_label.h @@ -9,13 +9,17 @@ #define JUMP_LABEL_NOP_SIZE 4 +/* This macro is also expanded on the Rust side. */ +#define ARCH_STATIC_BRANCH_ASM(key, label) \ + "1:\n\t" \ + WASM(nop) "\n\t" \ + ".pushsection __jump_table, \"aw\"\n\t" \ + ".word 1b, " label ", " key "\n\t" \ + ".popsection\n\t" \ + static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { - asm goto("1:\n\t" - WASM(nop) "\n\t" - ".pushsection __jump_table, \"aw\"\n\t" - ".word 1b, %l[l_yes], %c0\n\t" - ".popsection\n\t" + asm goto(ARCH_STATIC_BRANCH_ASM("%c0", "%l[l_yes]") : : "i" (&((char *)key)[branch]) : : l_yes); return false; diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index ef2aa79ece5ad5..7c2fa7dcec6d4b 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -147,12 +147,6 @@ extern unsigned long vectors_base; #define DTCM_OFFSET UL(0xfffe8000) #endif -/* - * Convert a page to/from a physical address - */ -#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) -#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) - /* * PLAT_PHYS_OFFSET is the offset (from zero) of the start of physical * memory. This is used for XIP and NoMMU kernels, and on platforms that don't diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h index 62af9f7f9e963e..ef11b721230e20 100644 --- a/arch/arm/include/asm/page.h +++ b/arch/arm/include/asm/page.h @@ -7,10 +7,7 @@ #ifndef _ASMARM_PAGE_H #define _ASMARM_PAGE_H -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) +#include #ifndef __ASSEMBLY__ diff --git a/arch/arm/include/asm/patch.h b/arch/arm/include/asm/patch.h deleted file mode 100644 index 0b48247c4600c2..00000000000000 --- a/arch/arm/include/asm/patch.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ARM_KERNEL_PATCH_H -#define _ARM_KERNEL_PATCH_H - -void patch_text(void *addr, unsigned int insn); -void __patch_text_real(void *addr, unsigned int insn, bool remap); - -static inline void __patch_text(void *addr, unsigned int insn) -{ - __patch_text_real(addr, insn, true); -} - -static inline void __patch_text_early(void *addr, unsigned int insn) -{ - __patch_text_real(addr, insn, false); -} - -#endif diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index bdbc1e590891e5..c08f16f2e24357 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h @@ -8,13 +8,6 @@ #ifndef __ARM_PERF_EVENT_H__ #define __ARM_PERF_EVENT_H__ -#ifdef CONFIG_PERF_EVENTS -struct pt_regs; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) -#endif - #define perf_arch_fetch_caller_regs(regs, __ip) { \ (regs)->ARM_pc = (__ip); \ frame_pointer((regs)) = (unsigned long) __builtin_frame_address(0); \ diff --git a/arch/arm/include/asm/spinlock_types.h b/arch/arm/include/asm/spinlock_types.h index 0c14b36ef10131..5404a2a96bf3cb 100644 --- a/arch/arm/include/asm/spinlock_types.h +++ b/arch/arm/include/asm/spinlock_types.h @@ -3,7 +3,7 @@ #define __ASM_SPINLOCK_TYPES_H #ifndef __LINUX_SPINLOCK_TYPES_RAW_H -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif #define TICKET_SHIFT 16 diff --git a/arch/arm/include/asm/text-patching.h b/arch/arm/include/asm/text-patching.h new file mode 100644 index 00000000000000..0b48247c4600c2 --- /dev/null +++ b/arch/arm/include/asm/text-patching.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ARM_KERNEL_PATCH_H +#define _ARM_KERNEL_PATCH_H + +void patch_text(void *addr, unsigned int insn); +void __patch_text_real(void *addr, unsigned int insn, bool remap); + +static inline void __patch_text(void *addr, unsigned int insn) +{ + __patch_text_real(addr, insn, true); +} + +static inline void __patch_text_early(void *addr, unsigned int insn) +{ + __patch_text_real(addr, insn, false); +} + +#endif diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h index 2134cbd5469fee..592d3d015ca729 100644 --- a/arch/arm/include/asm/vdso/gettimeofday.h +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -15,8 +15,6 @@ #define VDSO_HAS_CLOCK_GETRES 1 -extern struct vdso_data *__get_datapage(void); - static __always_inline int gettimeofday_fallback( struct __kernel_old_timeval *_tv, struct timezone *_tz) @@ -139,7 +137,7 @@ static __always_inline u64 __arch_get_hw_counter(int clock_mode, static __always_inline const struct vdso_data *__arch_get_vdso_data(void) { - return __get_datapage(); + return _vdso_data; } #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm/include/asm/vdso/vsyscall.h b/arch/arm/include/asm/vdso/vsyscall.h index 47e41ae8ccd0b9..705414710dcdbf 100644 --- a/arch/arm/include/asm/vdso/vsyscall.h +++ b/arch/arm/include/asm/vdso/vsyscall.h @@ -4,16 +4,12 @@ #ifndef __ASSEMBLY__ -#include #include #include extern struct vdso_data *vdso_data; extern bool cntvct_ok; -/* - * Update the vDSO data page to keep in sync with kernel timekeeping. - */ static __always_inline struct vdso_data *__arm_get_k_vdso_data(void) { diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index fdb74e64206a8a..3b78966e750a2d 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -200,7 +200,7 @@ const struct machine_desc * __init setup_machine_fdt(void *dt_virt) mdesc_best = &__mach_desc_GENERIC_DT; - if (!dt_virt || !early_init_dt_verify(dt_virt)) + if (!dt_virt || !early_init_dt_verify(dt_virt, __pa(dt_virt))) return NULL; mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach); diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 1dfae1af8e31b0..ef6a657c8d1306 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -25,6 +25,7 @@ #include #include #include +#include #include "entry-header.S" #include @@ -561,6 +562,13 @@ ENTRY(__switch_to) @ entries covering the vmalloc region. @ ldr r2, [ip] +#ifdef CONFIG_KASAN_VMALLOC + @ Also dummy read from the KASAN shadow memory for the new stack if we + @ are using KASAN + mov_l r2, KASAN_SHADOW_OFFSET + add r2, r2, ip, lsr #KASAN_SHADOW_SCALE_SHIFT + ldr r2, [r2] +#endif #endif @ When CONFIG_THREAD_INFO_IN_TASK=n, the update of SP itself is what diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index e61591f33a6cd1..845acf9ce21e35 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include /* * The compiler emitted profiling hook consists of diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index dab42d066d068b..e1993e28a9ecfd 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -111,7 +111,7 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs) * Some hardware gives randomly wrong interrupts. Rather * than crashing, do something sensible. */ - if (unlikely(!irq || irq >= nr_irqs)) + if (unlikely(!irq || irq >= irq_get_nr_irqs())) desc = NULL; else desc = irq_to_desc(irq); @@ -151,7 +151,6 @@ void __init init_IRQ(void) #ifdef CONFIG_SPARSE_IRQ int __init arch_probe_nr_irqs(void) { - nr_irqs = machine_desc->nr_irqs ? machine_desc->nr_irqs : NR_IRQS; - return nr_irqs; + return irq_set_nr_irqs(machine_desc->nr_irqs ? : NR_IRQS); } #endif diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c index eb9c24b6e8e23a..a06a92d0f55085 100644 --- a/arch/arm/kernel/jump_label.c +++ b/arch/arm/kernel/jump_label.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include -#include +#include #include static void __arch_jump_label_transform(struct jump_entry *entry, diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index 22f937e6f3ffb1..ab76c55fd610c2 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c index e9e828b6bb3062..4d45e60cd46d1b 100644 --- a/arch/arm/kernel/patch.c +++ b/arch/arm/kernel/patch.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include struct patch { void *addr; diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c index 1d230ac9d0eb5c..a2601b1ef31823 100644 --- a/arch/arm/kernel/perf_callchain.c +++ b/arch/arm/kernel/perf_callchain.c @@ -96,20 +96,3 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re arm_get_current_stackframe(regs, &fr); walk_stackframe(&fr, callchain_trace, entry); } - -unsigned long perf_instruction_pointer(struct pt_regs *regs) -{ - return instruction_pointer(regs); -} - -unsigned long perf_misc_flags(struct pt_regs *regs) -{ - int misc = 0; - - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - - return misc; -} diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 9a14f721a2b064..42a3706e16a6aa 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -93,7 +93,6 @@ static void twd_timer_stop(void) { struct clock_event_device *clk = raw_cpu_ptr(twd_evt); - twd_shutdown(clk); disable_percpu_irq(clk->irq); } diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c index f5781ff54a5ca3..2944721e82a2b3 100644 --- a/arch/arm/kernel/sys_oabi-compat.c +++ b/arch/arm/kernel/sys_oabi-compat.c @@ -235,12 +235,12 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; - struct fd f = fdget_raw(fd); + CLASS(fd_raw, f)(fd); struct flock64 flock; - long err = -EBADF; + long err; - if (!fd_file(f)) - goto out; + if (fd_empty(f)) + return -EBADF; switch (cmd) { case F_GETLK64: @@ -271,8 +271,6 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd, err = sys_fcntl64(fd, cmd, arg); break; } - fdput(f); -out: return err; } diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index d499ad461b004b..29dd2f3c62fec6 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index 2e523f29ec3b2d..6baedf4c630415 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -58,5 +58,6 @@ endif # BCMBCA ifeq ($(CONFIG_ARCH_BCMBCA),y) +obj-$(CONFIG_DEBUG_BCMBCA) += board_bcmbca.o obj-$(CONFIG_SMP) += bcm63xx_smp.o bcm63xx_pmb.o endif diff --git a/arch/arm/mach-bcm/board_bcmbca.c b/arch/arm/mach-bcm/board_bcmbca.c new file mode 100644 index 00000000000000..b510d959870ae3 --- /dev/null +++ b/arch/arm/mach-bcm/board_bcmbca.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2024 Linus Walleij + +#include +#include + +/* This is needed for LL-debug/earlyprintk/debug-macro.S */ +static struct map_desc bcmbca_io_desc[] __initdata = { + { + .virtual = CONFIG_DEBUG_UART_VIRT, + .pfn = __phys_to_pfn(CONFIG_DEBUG_UART_PHYS), + .length = SZ_4K, + .type = MT_DEVICE, + }, +}; + +static void __init bcmbca_map_io(void) +{ + iotable_init(bcmbca_io_desc, ARRAY_SIZE(bcmbca_io_desc)); +} + +static const char * const bcmbca_dt_compat[] = { + /* TODO: Add other BCMBCA SoCs here to get debug UART support */ + "brcm,bcm6846", + NULL, +}; + +DT_MACHINE_START(BCMBCA_DT, "BCMBCA Broadband Access Processors") + .map_io = bcmbca_map_io, + .dt_compat = bcmbca_dt_compat, +MACHINE_END diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c index 43bc98e388bff7..27948b5159938b 100644 --- a/arch/arm/mach-bcm/brcmstb.c +++ b/arch/arm/mach-bcm/brcmstb.c @@ -23,11 +23,6 @@ u32 brcmstb_uart_config[3] = { 0, }; -static void __init brcmstb_init_irq(void) -{ - irqchip_init(); -} - static const char *const brcmstb_match[] __initconst = { "brcm,bcm7445", "brcm,brcmstb", @@ -36,5 +31,4 @@ static const char *const brcmstb_match[] __initconst = { DT_MACHINE_START(BRCMSTB, "Broadcom STB (Flattened Device Tree)") .dt_compat = brcmstb_match, - .init_irq = brcmstb_init_irq, MACHINE_END diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index ab767f05992958..e4fe059cd86141 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -6,7 +6,6 @@ menuconfig ARCH_MXC select CLKSRC_IMX_GPT select GENERIC_IRQ_CHIP select GPIOLIB - select PINCTRL select PM_OPP if PM select SOC_BUS select SRAM @@ -49,7 +48,6 @@ config SOC_IMX31 config SOC_IMX35 bool "i.MX35 support" select MXC_AVIC - select PINCTRL_IMX35 help This enables support for Freescale i.MX35 processor @@ -61,7 +59,6 @@ config SOC_IMX1 bool "i.MX1 support" select CPU_ARM920T select MXC_AVIC - select PINCTRL_IMX1 help This enables support for Freescale i.MX1 processor @@ -73,7 +70,6 @@ config SOC_IMX25 bool "i.MX25 support" select CPU_ARM926T select MXC_AVIC - select PINCTRL_IMX25 help This enables support for Freescale i.MX25 processor @@ -81,7 +77,6 @@ config SOC_IMX27 bool "i.MX27 support" select CPU_ARM926T select MXC_AVIC - select PINCTRL_IMX27 help This enables support for Freescale i.MX27 processor @@ -98,7 +93,6 @@ config SOC_IMX5 config SOC_IMX50 bool "i.MX50 support" - select PINCTRL_IMX50 select SOC_IMX5 help @@ -106,14 +100,12 @@ config SOC_IMX50 config SOC_IMX51 bool "i.MX51 support" - select PINCTRL_IMX51 select SOC_IMX5 help This enables support for Freescale i.MX51 processor config SOC_IMX53 bool "i.MX53 support" - select PINCTRL_IMX53 select SOC_IMX5 help @@ -137,7 +129,6 @@ config SOC_IMX6Q select ARM_ERRATA_775420 select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD - select PINCTRL_IMX6Q select SOC_IMX6 help @@ -147,7 +138,6 @@ config SOC_IMX6SL bool "i.MX6 SoloLite support" select ARM_ERRATA_754322 select ARM_ERRATA_775420 - select PINCTRL_IMX6SL select SOC_IMX6 help @@ -157,7 +147,6 @@ config SOC_IMX6SLL bool "i.MX6 SoloLiteLite support" select ARM_ERRATA_754322 select ARM_ERRATA_775420 - select PINCTRL_IMX6SLL select SOC_IMX6 help @@ -167,7 +156,6 @@ config SOC_IMX6SX bool "i.MX6 SoloX support" select ARM_ERRATA_754322 select ARM_ERRATA_775420 - select PINCTRL_IMX6SX select SOC_IMX6 help @@ -175,7 +163,6 @@ config SOC_IMX6SX config SOC_IMX6UL bool "i.MX6 UltraLite support" - select PINCTRL_IMX6UL select SOC_IMX6 select ARM_ERRATA_814220 @@ -211,7 +198,6 @@ config SOC_IMX7D_CM4 config SOC_IMX7D bool "i.MX7 Dual support" - select PINCTRL_IMX7D select SOC_IMX7D_CA7 if ARCH_MULTI_V7 select SOC_IMX7D_CM4 if ARM_SINGLE_ARMV7M select ARM_ERRATA_814220 if ARCH_MULTI_V7 @@ -221,7 +207,6 @@ config SOC_IMX7D config SOC_IMX7ULP bool "i.MX7ULP support" select CLKSRC_IMX_TPM - select PINCTRL_IMX7ULP select SOC_IMX7D_CA7 if ARCH_MULTI_V7 select SOC_IMX7D_CM4 if ARM_SINGLE_ARMV7M help @@ -237,7 +222,6 @@ config SOC_IMXRT config SOC_VF610 bool "Vybrid Family VF610 support" select ARM_GIC if ARCH_MULTI_V7 - select PINCTRL_VF610 help This enables support for Freescale Vybrid VF610 processor. diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index b68cb86dbe4cf9..e898f7c2733efc 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -596,7 +596,7 @@ static struct platform_driver imx_mmdc_driver = { .of_match_table = imx_mmdc_dt_ids, }, .probe = imx_mmdc_probe, - .remove_new = imx_mmdc_remove, + .remove = imx_mmdc_remove, }; static int __init imx_mmdc_init(void) diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index b36f05b54cc762..a671ca498f887f 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -634,13 +634,11 @@ static void imx6_pm_stby_poweroff(void) static int imx6_pm_stby_poweroff_probe(void) { - if (pm_power_off) { - pr_warn("%s: pm_power_off already claimed %p %ps!\n", - __func__, pm_power_off, pm_power_off); + if (register_platform_power_off(imx6_pm_stby_poweroff)) { + pr_warn("%s: platform power off already claimed!\n", __func__); return -EBUSY; } - pm_power_off = imx6_pm_stby_poweroff; return 0; } diff --git a/arch/arm/mach-omap1/omap-dma.c b/arch/arm/mach-omap1/omap-dma.c index f091f78631d098..aebe5e55ff6071 100644 --- a/arch/arm/mach-omap1/omap-dma.c +++ b/arch/arm/mach-omap1/omap-dma.c @@ -832,7 +832,7 @@ static void omap_system_dma_remove(struct platform_device *pdev) static struct platform_driver omap_system_dma_driver = { .probe = omap_system_dma_probe, - .remove_new = omap_system_dma_remove, + .remove = omap_system_dma_remove, .driver = { .name = "omap_dma_system" }, diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 72fa2e3fd35318..0c8d9000df5a63 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -919,7 +919,7 @@ static void sharpsl_pm_remove(struct platform_device *pdev) static struct platform_driver sharpsl_pm_driver = { .probe = sharpsl_pm_probe, - .remove_new = sharpsl_pm_remove, + .remove = sharpsl_pm_remove, .suspend = sharpsl_pm_suspend, .resume = sharpsl_pm_resume, .driver = { diff --git a/arch/arm/mach-sa1100/jornada720_ssp.c b/arch/arm/mach-sa1100/jornada720_ssp.c index 1956b095e699d1..d94810217095bd 100644 --- a/arch/arm/mach-sa1100/jornada720_ssp.c +++ b/arch/arm/mach-sa1100/jornada720_ssp.c @@ -188,7 +188,7 @@ static void jornada_ssp_remove(struct platform_device *dev) struct platform_driver jornadassp_driver = { .probe = jornada_ssp_probe, - .remove_new = jornada_ssp_remove, + .remove = jornada_ssp_remove, .driver = { .name = "jornada_ssp", }, diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index 0ef0ebbf31ac1f..88fe79f0a4ed36 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -423,7 +423,7 @@ static const struct dev_pm_ops neponset_pm_ops = { static struct platform_driver neponset_device_driver = { .probe = neponset_probe, - .remove_new = neponset_remove, + .remove = neponset_remove, .driver = { .name = "neponset", .pm = PM_OPS, diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index 60e662324699fd..83a79d0c0bec5e 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h @@ -9,7 +9,6 @@ #ifndef __MACH_ZYNQ_COMMON_H__ #define __MACH_ZYNQ_COMMON_H__ -extern int zynq_slcr_init(void); extern int zynq_early_slcr_init(void); extern void zynq_slcr_cpu_stop(int cpu); extern void zynq_slcr_cpu_start(int cpu); diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 831793cd6ff944..2bec87c3327d23 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -61,32 +61,8 @@ static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address, return ret; } -#if defined(CONFIG_SPLIT_PTE_PTLOCKS) -/* - * If we are using split PTE locks, then we need to take the page - * lock here. Otherwise we are using shared mm->page_table_lock - * which is already locked, thus cannot take it. - */ -static inline void do_pte_lock(spinlock_t *ptl) -{ - /* - * Use nested version here to indicate that we are already - * holding one similar spinlock. - */ - spin_lock_nested(ptl, SINGLE_DEPTH_NESTING); -} - -static inline void do_pte_unlock(spinlock_t *ptl) -{ - spin_unlock(ptl); -} -#else /* !defined(CONFIG_SPLIT_PTE_PTLOCKS) */ -static inline void do_pte_lock(spinlock_t *ptl) {} -static inline void do_pte_unlock(spinlock_t *ptl) {} -#endif /* defined(CONFIG_SPLIT_PTE_PTLOCKS) */ - static int adjust_pte(struct vm_area_struct *vma, unsigned long address, - unsigned long pfn) + unsigned long pfn, struct vm_fault *vmf) { spinlock_t *ptl; pgd_t *pgd; @@ -94,6 +70,7 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address, pud_t *pud; pmd_t *pmd; pte_t *pte; + pmd_t pmdval; int ret; pgd = pgd_offset(vma->vm_mm, address); @@ -112,20 +89,33 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address, if (pmd_none_or_clear_bad(pmd)) return 0; +again: /* * This is called while another page table is mapped, so we * must use the nested version. This also means we need to * open-code the spin-locking. */ - pte = pte_offset_map_nolock(vma->vm_mm, pmd, address, &ptl); + pte = pte_offset_map_rw_nolock(vma->vm_mm, pmd, address, &pmdval, &ptl); if (!pte) return 0; - do_pte_lock(ptl); + /* + * If we are using split PTE locks, then we need to take the page + * lock here. Otherwise we are using shared mm->page_table_lock + * which is already locked, thus cannot take it. + */ + if (ptl != vmf->ptl) { + spin_lock_nested(ptl, SINGLE_DEPTH_NESTING); + if (unlikely(!pmd_same(pmdval, pmdp_get_lockless(pmd)))) { + pte_unmap_unlock(pte, ptl); + goto again; + } + } ret = do_adjust_pte(vma, address, pfn, pte); - do_pte_unlock(ptl); + if (ptl != vmf->ptl) + spin_unlock(ptl); pte_unmap(pte); return ret; @@ -133,7 +123,8 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address, static void make_coherent(struct address_space *mapping, struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep, unsigned long pfn) + unsigned long addr, pte_t *ptep, unsigned long pfn, + struct vm_fault *vmf) { struct mm_struct *mm = vma->vm_mm; struct vm_area_struct *mpnt; @@ -160,7 +151,7 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma, if (!(mpnt->vm_flags & VM_MAYSHARE)) continue; offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; - aliases += adjust_pte(mpnt, mpnt->vm_start + offset, pfn); + aliases += adjust_pte(mpnt, mpnt->vm_start + offset, pfn, vmf); } flush_dcache_mmap_unlock(mapping); if (aliases) @@ -203,7 +194,7 @@ void update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma, __flush_dcache_folio(mapping, folio); if (mapping) { if (cache_is_vivt()) - make_coherent(mapping, vma, addr, ptep, pfn); + make_coherent(mapping, vma, addr, ptep, pfn, vmf); else if (vma->vm_flags & VM_EXEC) __flush_icache_all(); } diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 794cfea9f9d4c8..89f1c97f3079c1 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -23,6 +23,7 @@ */ #include #include +#include #include #include #include @@ -115,16 +116,40 @@ int ioremap_page(unsigned long virt, unsigned long phys, } EXPORT_SYMBOL(ioremap_page); +#ifdef CONFIG_KASAN +static unsigned long arm_kasan_mem_to_shadow(unsigned long addr) +{ + return (unsigned long)kasan_mem_to_shadow((void *)addr); +} +#else +static unsigned long arm_kasan_mem_to_shadow(unsigned long addr) +{ + return 0; +} +#endif + +static void memcpy_pgd(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + end = ALIGN(end, PGDIR_SIZE); + memcpy(pgd_offset(mm, start), pgd_offset_k(start), + sizeof(pgd_t) * (pgd_index(end) - pgd_index(start))); +} + void __check_vmalloc_seq(struct mm_struct *mm) { int seq; do { - seq = atomic_read(&init_mm.context.vmalloc_seq); - memcpy(pgd_offset(mm, VMALLOC_START), - pgd_offset_k(VMALLOC_START), - sizeof(pgd_t) * (pgd_index(VMALLOC_END) - - pgd_index(VMALLOC_START))); + seq = atomic_read_acquire(&init_mm.context.vmalloc_seq); + memcpy_pgd(mm, VMALLOC_START, VMALLOC_END); + if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) { + unsigned long start = + arm_kasan_mem_to_shadow(VMALLOC_START); + unsigned long end = + arm_kasan_mem_to_shadow(VMALLOC_END); + memcpy_pgd(mm, start, end); + } /* * Use a store-release so that other CPUs that observe the * counter's new value are guaranteed to see the results of the diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c index d8238da095df7d..9fd877c87a38fd 100644 --- a/arch/arm/probes/kprobes/core.c +++ b/arch/arm/probes/kprobes/core.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include "../decode-arm.h" diff --git a/arch/arm/probes/kprobes/opt-arm.c b/arch/arm/probes/kprobes/opt-arm.c index 7f65048380ca51..966c6042c5ad73 100644 --- a/arch/arm/probes/kprobes/opt-arm.c +++ b/arch/arm/probes/kprobes/opt-arm.c @@ -14,7 +14,7 @@ /* for arm_gen_branch */ #include /* for patch_text */ -#include +#include #include "core.h" diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl index 23c98203c40fe6..49eeb2ad8dbd8e 100644 --- a/arch/arm/tools/syscall.tbl +++ b/arch/arm/tools/syscall.tbl @@ -477,3 +477,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile index 01067a2bc43b74..8a306bbec4a0c4 100644 --- a/arch/arm/vdso/Makefile +++ b/arch/arm/vdso/Makefile @@ -5,7 +5,7 @@ include $(srctree)/lib/vdso/Makefile hostprogs := vdsomunge -obj-vdso := vgettimeofday.o datapage.o note.o +obj-vdso := vgettimeofday.o note.o # Build rules targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds diff --git a/arch/arm/vdso/datapage.S b/arch/arm/vdso/datapage.S deleted file mode 100644 index 9cd73b725d9fb8..00000000000000 --- a/arch/arm/vdso/datapage.S +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include -#include - - .align 2 -.L_vdso_data_ptr: - .long _start - . - VDSO_DATA_SIZE - -ENTRY(__get_datapage) - .fnstart - adr r0, .L_vdso_data_ptr - ldr r1, [r0] - add r0, r0, r1 - bx lr - .fnend -ENDPROC(__get_datapage) diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S index 165d1d2eb76b3c..9bfa0f52923c85 100644 --- a/arch/arm/vdso/vdso.lds.S +++ b/arch/arm/vdso/vdso.lds.S @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -19,7 +20,7 @@ OUTPUT_ARCH(arm) SECTIONS { - PROVIDE(_start = .); + PROVIDE(_vdso_data = . - VDSO_DATA_SIZE); . = SIZEOF_HEADERS; diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index b68efe643a12ca..d44867fc0c5ee8 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -55,6 +55,34 @@ extern unsigned int VFP_arch_feroceon __alias(VFP_arch); */ union vfp_state *vfp_current_hw_state[NR_CPUS]; +/* + * Claim ownership of the VFP unit. + * + * The caller may change VFP registers until vfp_state_release() is called. + * + * local_bh_disable() is used to disable preemption and to disable VFP + * processing in softirq context. On PREEMPT_RT kernels local_bh_disable() is + * not sufficient because it only serializes soft interrupt related sections + * via a local lock, but stays preemptible. Disabling preemption is the right + * choice here as bottom half processing is always in thread context on RT + * kernels so it implicitly prevents bottom half processing as well. + */ +static void vfp_state_hold(void) +{ + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) + local_bh_disable(); + else + preempt_disable(); +} + +static void vfp_state_release(void) +{ + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) + local_bh_enable(); + else + preempt_enable(); +} + /* * Is 'thread's most up to date state stored in this CPUs hardware? * Must be called from non-preemptible context. @@ -240,7 +268,7 @@ static void vfp_panic(char *reason, u32 inst) /* * Process bitmask of exception conditions. */ -static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_regs *regs) +static int vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr) { int si_code = 0; @@ -248,8 +276,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_ if (exceptions == VFP_EXCEPTION_ERROR) { vfp_panic("unhandled bounce", inst); - vfp_raise_sigfpe(FPE_FLTINV, regs); - return; + return FPE_FLTINV; } /* @@ -277,8 +304,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_ RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF); RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV); - if (si_code) - vfp_raise_sigfpe(si_code, regs); + return si_code; } /* @@ -324,6 +350,8 @@ static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs) static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) { u32 fpscr, orig_fpscr, fpsid, exceptions; + int si_code2 = 0; + int si_code = 0; pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc); @@ -369,8 +397,8 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) * unallocated VFP instruction but with FPSCR.IXE set and not * on VFP subarch 1. */ - vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs); - return; + si_code = vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr); + goto exit; } /* @@ -394,14 +422,14 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) */ exceptions = vfp_emulate_instruction(trigger, fpscr, regs); if (exceptions) - vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); + si_code2 = vfp_raise_exceptions(exceptions, trigger, orig_fpscr); /* * If there isn't a second FP instruction, exit now. Note that * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1. */ if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V)) - return; + goto exit; /* * The barrier() here prevents fpinst2 being read @@ -413,7 +441,13 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs) emulate: exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs); if (exceptions) - vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs); + si_code = vfp_raise_exceptions(exceptions, trigger, orig_fpscr); +exit: + vfp_state_release(); + if (si_code2) + vfp_raise_sigfpe(si_code2, regs); + if (si_code) + vfp_raise_sigfpe(si_code, regs); } static void vfp_enable(void *unused) @@ -512,11 +546,9 @@ static inline void vfp_pm_init(void) { } */ void vfp_sync_hwstate(struct thread_info *thread) { - unsigned int cpu = get_cpu(); + vfp_state_hold(); - local_bh_disable(); - - if (vfp_state_in_hw(cpu, thread)) { + if (vfp_state_in_hw(raw_smp_processor_id(), thread)) { u32 fpexc = fmrx(FPEXC); /* @@ -527,8 +559,7 @@ void vfp_sync_hwstate(struct thread_info *thread) fmxr(FPEXC, fpexc); } - local_bh_enable(); - put_cpu(); + vfp_state_release(); } /* Ensure that the thread reloads the hardware VFP state on the next use. */ @@ -683,7 +714,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger) if (!user_mode(regs)) return vfp_kmode_exception(regs, trigger); - local_bh_disable(); + vfp_state_hold(); fpexc = fmrx(FPEXC); /* @@ -748,6 +779,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger) * replay the instruction that trapped. */ fmxr(FPEXC, fpexc); + vfp_state_release(); } else { /* Check for synchronous or asynchronous exceptions */ if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) { @@ -762,17 +794,17 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger) if (!(fpscr & FPSCR_IXE)) { if (!(fpscr & FPSCR_LENGTH_MASK)) { pr_debug("not VFP\n"); - local_bh_enable(); + vfp_state_release(); return -ENOEXEC; } fpexc |= FPEXC_DEX; } } bounce: regs->ARM_pc += 4; + /* VFP_bounce() will invoke vfp_state_release() */ VFP_bounce(trigger, fpexc, regs); } - local_bh_enable(); return 0; } @@ -837,7 +869,7 @@ void kernel_neon_begin(void) unsigned int cpu; u32 fpexc; - local_bh_disable(); + vfp_state_hold(); /* * Kernel mode NEON is only allowed outside of hardirq context with @@ -868,7 +900,7 @@ void kernel_neon_end(void) { /* Disable the NEON/VFP unit. */ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); - local_bh_enable(); + vfp_state_release(); } EXPORT_SYMBOL(kernel_neon_end); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 22f8a7bca6d21c..100570a048c5e8 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -14,13 +14,13 @@ config ARM64 select ARCH_HAS_DEBUG_WX select ARCH_BINFMT_ELF_EXTRA_PHDRS select ARCH_BINFMT_ELF_STATE - select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE select ARCH_ENABLE_HUGEPAGE_MIGRATION if HUGETLB_PAGE && MIGRATION select ARCH_ENABLE_MEMORY_HOTPLUG select ARCH_ENABLE_MEMORY_HOTREMOVE select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2 select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE select ARCH_HAS_CACHE_LINE_SIZE + select ARCH_HAS_CC_PLATFORM select ARCH_HAS_CURRENT_STACK_POINTER select ARCH_HAS_DEBUG_VIRTUAL select ARCH_HAS_DEBUG_VM_PGTABLE @@ -38,12 +38,15 @@ config ARM64 select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + select ARCH_HAS_NONLEAF_PMD_YOUNG if ARM64_HAFT select ARCH_HAS_PTE_DEVMAP select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_HW_PTE_YOUNG select ARCH_HAS_SETUP_DMA_OPS select ARCH_HAS_SET_DIRECT_MAP select ARCH_HAS_SET_MEMORY + select ARCH_HAS_MEM_ENCRYPT + select ARCH_HAS_FORCE_DMA_UNENCRYPTED select ARCH_STACKWALK select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_STRICT_MODULE_RWX @@ -1232,6 +1235,17 @@ config HISILICON_ERRATUM_161600802 If unsure, say Y. +config HISILICON_ERRATUM_162100801 + bool "Hip09 162100801 erratum support" + default y + help + When enabling GICv4.1 in hip09, VMAPP will fail to clear some caches + during unmapping operation, which will cause some vSGIs lost. + To fix the issue, invalidate related vPE cache through GICR_INVALLR + after VMOVP. + + If unsure, say Y. + config QCOM_FALKOR_ERRATUM_1003 bool "Falkor E1003: Incorrect translation due to ASID change" default y @@ -2159,6 +2173,9 @@ config ARM64_EPAN if the cpu does not implement the feature. endmenu # "ARMv8.7 architectural features" +config AS_HAS_MOPS + def_bool $(as-instr,.arch_extension mops) + menu "ARMv8.9 architectural features" config ARM64_POE @@ -2180,8 +2197,44 @@ config ARCH_PKEY_BITS int default 3 +config ARM64_HAFT + bool "Support for Hardware managed Access Flag for Table Descriptors" + depends on ARM64_HW_AFDBM + default y + help + The ARMv8.9/ARMv9.5 introduces the feature Hardware managed Access + Flag for Table descriptors. When enabled an architectural executed + memory access will update the Access Flag in each Table descriptor + which is accessed during the translation table walk and for which + the Access Flag is 0. The Access Flag of the Table descriptor use + the same bit of PTE_AF. + + The feature will only be enabled if all the CPUs in the system + support this feature. If unsure, say Y. + endmenu # "ARMv8.9 architectural features" +menu "v9.4 architectural features" + +config ARM64_GCS + bool "Enable support for Guarded Control Stack (GCS)" + default y + select ARCH_HAS_USER_SHADOW_STACK + select ARCH_USES_HIGH_VMA_FLAGS + depends on !UPROBES + help + Guarded Control Stack (GCS) provides support for a separate + stack with restricted access which contains only return + addresses. This can be used to harden against some attacks + by comparing return address used by the program with what is + stored in the GCS, and may also be used to efficiently obtain + the call stack for applications such as profiling. + + The feature is detected at runtime, and will remain disabled + if the system does not implement the feature. + +endmenu # "v9.4 architectural features" + config ARM64_SVE bool "ARM Scalable Vector Extension support" default y diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 6c6d11536b42ec..370a9d2b6919d2 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -37,8 +37,8 @@ config ARCH_APPLE bool "Apple Silicon SoC family" select APPLE_AIC help - This enables support for Apple's in-house ARM SoC family, starting - with the Apple M1. + This enables support for Apple's in-house ARM SoC family, such + as the Apple M1. menuconfig ARCH_BCM bool "Broadcom SoC Support" diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 9efd3f37c2fd9d..358c68565bfd06 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -71,7 +71,7 @@ stack_protector_prepare: prepare0 -mstack-protector-guard-reg=sp_el0 \ -mstack-protector-guard-offset=$(shell \ awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \ - include/generated/asm-offsets.h)) + $(objtree)/include/generated/asm-offsets.h)) endif ifeq ($(CONFIG_ARM64_BTI_KERNEL),y) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a100-allwinner-perf1.dts b/arch/arm64/boot/dts/allwinner/sun50i-a100-allwinner-perf1.dts index f5c5c1464482cb..a387bccdcefd85 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a100-allwinner-perf1.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a100-allwinner-perf1.dts @@ -7,6 +7,8 @@ #include "sun50i-a100.dtsi" +#include + /{ model = "Allwinner A100 Perf1"; compatible = "allwinner,a100-perf1", "allwinner,sun50i-a100"; @@ -20,6 +22,22 @@ chosen { }; }; +&mmc0 { + vmmc-supply = <®_dcdc1>; + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + bus-width = <4>; + status = "okay"; +}; + +&mmc2 { + vmmc-supply = <®_dcdc1>; + vqmmc-supply = <®_aldo1>; + cap-mmc-hw-reset; + non-removable; + bus-width = <8>; + status = "okay"; +}; + &pio { vcc-pb-supply = <®_dcdc1>; vcc-pc-supply = <®_eldo1>; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi index a3dccf19376535..29ac7716c7a528 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi @@ -25,21 +25,21 @@ cpu0: cpu@0 { enable-method = "psci"; }; - cpu@1 { + cpu1: cpu@1 { compatible = "arm,cortex-a53"; device_type = "cpu"; reg = <0x1>; enable-method = "psci"; }; - cpu@2 { + cpu2: cpu@2 { compatible = "arm,cortex-a53"; device_type = "cpu"; reg = <0x2>; enable-method = "psci"; }; - cpu@3 { + cpu3: cpu@3 { compatible = "arm,cortex-a53"; device_type = "cpu"; reg = <0x3>; @@ -47,6 +47,15 @@ cpu@3 { }; }; + pmu { + compatible = "arm,cortex-a53-pmu"; + interrupts = , + , + , + ; + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -135,6 +144,14 @@ ths_calibration: calib@14 { }; }; + watchdog@30090a0 { + compatible = "allwinner,sun50i-a100-wdt", + "allwinner,sun6i-a31-wdt"; + reg = <0x030090a0 0x20>; + interrupts = ; + clocks = <&dcxo24M>; + }; + pio: pinctrl@300b000 { compatible = "allwinner,sun50i-a100-pinctrl"; reg = <0x0300b000 0x400>; @@ -152,12 +169,83 @@ pio: pinctrl@300b000 { interrupt-controller; #interrupt-cells = <3>; + mmc0_pins: mmc0-pins { + pins = "PF0", "PF1", "PF2", "PF3", + "PF4", "PF5"; + function = "mmc0"; + drive-strength = <30>; + bias-pull-up; + }; + + /omit-if-no-ref/ + mmc1_pins: mmc1-pins { + pins = "PG0", "PG1", "PG2", "PG3", + "PG4", "PG5"; + function = "mmc1"; + drive-strength = <30>; + bias-pull-up; + }; + + mmc2_pins: mmc2-pins { + pins = "PC0", "PC1", "PC5", "PC6", + "PC8", "PC9", "PC10", "PC11", + "PC13", "PC14", "PC15", "PC16"; + function = "mmc2"; + drive-strength = <30>; + bias-pull-up; + }; + uart0_pb_pins: uart0-pb-pins { pins = "PB9", "PB10"; function = "uart0"; }; }; + mmc0: mmc@4020000 { + compatible = "allwinner,sun50i-a100-mmc"; + reg = <0x04020000 0x1000>; + clocks = <&ccu CLK_BUS_MMC0>, <&ccu CLK_MMC0>; + clock-names = "ahb", "mmc"; + resets = <&ccu RST_BUS_MMC0>; + reset-names = "ahb"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc1: mmc@4021000 { + compatible = "allwinner,sun50i-a100-mmc"; + reg = <0x04021000 0x1000>; + clocks = <&ccu CLK_BUS_MMC1>, <&ccu CLK_MMC1>; + clock-names = "ahb", "mmc"; + resets = <&ccu RST_BUS_MMC1>; + reset-names = "ahb"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + + mmc2: mmc@4022000 { + compatible = "allwinner,sun50i-a100-emmc"; + reg = <0x04022000 0x1000>; + clocks = <&ccu CLK_BUS_MMC2>, <&ccu CLK_MMC2>; + clock-names = "ahb", "mmc"; + resets = <&ccu RST_BUS_MMC2>; + reset-names = "ahb"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + uart0: serial@5000000 { compatible = "snps,dw-apb-uart"; reg = <0x05000000 0x400>; @@ -285,6 +373,97 @@ ths: thermal-sensor@5070400 { #thermal-sensor-cells = <1>; }; + usb_otg: usb@5100000 { + compatible = "allwinner,sun50i-a100-musb", + "allwinner,sun8i-a33-musb"; + reg = <0x05100000 0x0400>; + clocks = <&ccu CLK_BUS_OTG>; + resets = <&ccu RST_BUS_OTG>; + interrupts = ; + interrupt-names = "mc"; + phys = <&usbphy 0>; + phy-names = "usb"; + extcon = <&usbphy 0>; + status = "disabled"; + }; + + usbphy: phy@5100400 { + compatible = "allwinner,sun50i-a100-usb-phy", + "allwinner,sun20i-d1-usb-phy"; + reg = <0x05100400 0x100>, + <0x05101800 0x100>, + <0x05200800 0x100>; + reg-names = "phy_ctrl", + "pmu0", + "pmu1"; + clocks = <&ccu CLK_USB_PHY0>, + <&ccu CLK_USB_PHY1>; + clock-names = "usb0_phy", + "usb1_phy"; + resets = <&ccu RST_USB_PHY0>, + <&ccu RST_USB_PHY1>; + reset-names = "usb0_reset", + "usb1_reset"; + status = "disabled"; + #phy-cells = <1>; + }; + + ehci0: usb@5101000 { + compatible = "allwinner,sun50i-a100-ehci", + "generic-ehci"; + reg = <0x05101000 0x100>; + interrupts = ; + clocks = <&ccu CLK_BUS_OHCI0>, + <&ccu CLK_BUS_EHCI0>, + <&ccu CLK_USB_OHCI0>; + resets = <&ccu RST_BUS_OHCI0>, + <&ccu RST_BUS_EHCI0>; + phys = <&usbphy 0>; + phy-names = "usb"; + status = "disabled"; + }; + + ohci0: usb@5101400 { + compatible = "allwinner,sun50i-a100-ohci", + "generic-ohci"; + reg = <0x05101400 0x100>; + interrupts = ; + clocks = <&ccu CLK_BUS_OHCI0>, + <&ccu CLK_USB_OHCI0>; + resets = <&ccu RST_BUS_OHCI0>; + phys = <&usbphy 0>; + phy-names = "usb"; + status = "disabled"; + }; + + ehci1: usb@5200000 { + compatible = "allwinner,sun50i-a100-ehci", + "generic-ehci"; + reg = <0x05200000 0x100>; + interrupts = ; + clocks = <&ccu CLK_BUS_OHCI1>, + <&ccu CLK_BUS_EHCI1>, + <&ccu CLK_USB_OHCI1>; + resets = <&ccu RST_BUS_OHCI1>, + <&ccu RST_BUS_EHCI1>; + phys = <&usbphy 1>; + phy-names = "usb"; + status = "disabled"; + }; + + ohci1: usb@5200400 { + compatible = "allwinner,sun50i-a100-ohci", + "generic-ohci"; + reg = <0x05200400 0x100>; + interrupts = ; + clocks = <&ccu CLK_BUS_OHCI1>, + <&ccu CLK_USB_OHCI1>; + resets = <&ccu RST_BUS_OHCI1>; + phys = <&usbphy 1>; + phy-names = "usb"; + status = "disabled"; + }; + r_ccu: clock@7010000 { compatible = "allwinner,sun50i-a100-r-ccu"; reg = <0x07010000 0x300>; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi index 6eab61a12cd8f8..4bc6c1ef2cde43 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi @@ -188,12 +188,30 @@ touchscreen@5d { &i2c1 { status = "okay"; + /* Alternative magnetometer */ + af8133j: magnetometer@1c { + compatible = "voltafield,af8133j"; + reg = <0x1c>; + reset-gpios = <&pio 1 1 GPIO_ACTIVE_LOW>; + avdd-supply = <®_dldo1>; + dvdd-supply = <®_dldo1>; + mount-matrix = "0", "-1", "0", + "-1", "0", "0", + "0", "0", "-1"; + + /* status will be fixed up in firmware */ + status = "disabled"; + }; + /* Magnetometer */ lis3mdl: magnetometer@1e { compatible = "st,lis3mdl-magn"; reg = <0x1e>; vdd-supply = <®_dldo1>; vddio-supply = <®_dldo1>; + mount-matrix = "0", "1", "0", + "-1", "0", "0", + "0", "0", "1"; }; /* Light/proximity sensor */ @@ -212,6 +230,9 @@ accelerometer@68 { interrupts = <7 5 IRQ_TYPE_EDGE_RISING>; /* PH5 */ vdd-supply = <®_dldo1>; vddio-supply = <®_dldo1>; + mount-matrix = "0", "1", "0", + "-1", "0", "0", + "0", "0", "1"; }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h313-tanix-tx1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h313-tanix-tx1.dts index bb2cde59bd0338..bafd3e803106b7 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h313-tanix-tx1.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h313-tanix-tx1.dts @@ -65,6 +65,11 @@ reg_vcc5v: vcc5v { }; }; +&codec { + allwinner,audio-routing = "Line Out", "LINEOUT"; + status = "okay"; +}; + &cpu0 { cpu-supply = <®_dcdc2>; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts index 526443bb736c36..18fa541795a64d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts @@ -136,6 +136,7 @@ &mmc0 { vmmc-supply = <®_vcc3v3>; bus-width = <4>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + disable-wp; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts index 05486cccee1c4e..128295f5a5d6b9 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo2.dts @@ -88,6 +88,7 @@ ext_rgmii_phy: ethernet-phy@7 { &mmc0 { vmmc-supply = <®_vcc3v3>; + disable-wp; bus-width = <4>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ status = "okay"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-r1s-h5.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-r1s-h5.dts index 3a7ee44708a205..44fdc8b3f79d27 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-r1s-h5.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-r1s-h5.dts @@ -157,6 +157,7 @@ eth_mac1: mac-address@fa { &mmc0 { vmmc-supply = <®_vcc3v3>; + disable-wp; bus-width = <4>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ status = "okay"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts index ce3ae19e72dbd4..0f29da7d51e66d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts @@ -153,6 +153,7 @@ &ir { &mmc0 { vmmc-supply = <®_vcc3v3>; + disable-wp; bus-width = <4>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ status = "okay"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts index b699bb900e13bb..d4fc4e60e4e72d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts @@ -153,6 +153,7 @@ &ir { &mmc0 { vmmc-supply = <®_vcc3v3>; + disable-wp; bus-width = <4>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ status = "okay"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts index ae85131aac9c73..3322cc4d9aa4a5 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts @@ -82,6 +82,7 @@ ext_rgmii_phy: ethernet-phy@1 { &mmc0 { vmmc-supply = <®_vcc3v3>; + disable-wp; bus-width = <4>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ status = "okay"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts index 734481e998b8dd..3eb986c354a9d7 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts @@ -79,6 +79,7 @@ hdmi_out_con: endpoint { &mmc0 { vmmc-supply = <®_vcc3v3>; + disable-wp; bus-width = <4>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; status = "okay"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts index 3be1e8c2fdb9cf..13a0e63afeaf3d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts @@ -129,6 +129,7 @@ ext_rgmii_phy: ethernet-phy@1 { &mmc0 { vmmc-supply = <®_cldo1>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; + disable-wp; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts index 6c3bfe3d09d9a3..ab87c3447cd782 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts @@ -131,6 +131,7 @@ hdmi_out_con: endpoint { &mmc0 { vmmc-supply = <®_cldo1>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + disable-wp; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi index 13b07141c3344b..d05dc5d6e6b9f7 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi.dtsi @@ -94,6 +94,7 @@ hdmi_out_con: endpoint { &mmc0 { vmmc-supply = <®_cldo1>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; + disable-wp; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts index c8b27555287257..fa7a765ee8284a 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts @@ -133,6 +133,7 @@ ext_rgmii_phy: ethernet-phy@1 { &mmc0 { vmmc-supply = <®_cldo1>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; + disable-wp; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi index 855b7d43bc503a..bb7de37c0d58be 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix.dtsi @@ -124,6 +124,7 @@ &mmc0 { pinctrl-0 = <&mmc0_pins>; vmmc-supply = <®_vcc3v3>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; + disable-wp; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero.dtsi index fc7315b9440659..908fa3b847a666 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-orangepi-zero.dtsi @@ -59,6 +59,11 @@ reg_usb1_vbus: regulator-usb1-vbus { }; }; +&codec { + allwinner,audio-routing = "Line Out", "LINEOUT"; + status = "okay"; +}; + &ehci1 { status = "okay"; }; @@ -81,6 +86,7 @@ ext_rgmii_phy: ethernet-phy@1 { &mmc0 { cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + disable-wp; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts b/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts index 26d25b5b59e0f8..968960ebf1d18c 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h616-x96-mate.dts @@ -33,6 +33,11 @@ reg_vcc5v: vcc5v { }; }; +&codec { + allwinner,audio-routing = "Line Out", "LINEOUT"; + status = "okay"; +}; + &cpu0 { cpu-supply = <®_dcdca>; }; @@ -52,6 +57,7 @@ &ir { &mmc0 { vmmc-supply = <®_dcdce>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + disable-wp; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi index e88c1fbac6acc8..cdce3dcb8ec024 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-h616.dtsi @@ -630,21 +630,6 @@ mdio0: mdio { }; }; - spdif: spdif@5093000 { - compatible = "allwinner,sun50i-h616-spdif"; - reg = <0x05093000 0x400>; - interrupts = ; - clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>; - clock-names = "apb", "spdif"; - resets = <&ccu RST_BUS_SPDIF>; - dmas = <&dma 2>; - dma-names = "tx"; - pinctrl-names = "default"; - pinctrl-0 = <&spdif_tx_pin>; - #sound-dai-cells = <0>; - status = "disabled"; - }; - gpadc: adc@5070000 { compatible = "allwinner,sun50i-h616-gpadc", "allwinner,sun20i-d1-gpadc"; @@ -679,6 +664,35 @@ lradc: lradc@5070800 { status = "disabled"; }; + spdif: spdif@5093000 { + compatible = "allwinner,sun50i-h616-spdif"; + reg = <0x05093000 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_SPDIF>, <&ccu CLK_SPDIF>; + clock-names = "apb", "spdif"; + resets = <&ccu RST_BUS_SPDIF>; + dmas = <&dma 2>; + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spdif_tx_pin>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + codec: codec@5096000 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun50i-h616-codec"; + reg = <0x05096000 0x31c>; + interrupts = ; + clocks = <&ccu CLK_BUS_AUDIO_CODEC>, + <&ccu CLK_AUDIO_CODEC_1X>; + clock-names = "apb", "codec"; + resets = <&ccu RST_BUS_AUDIO_CODEC>; + dmas = <&dma 6>; + dma-names = "tx"; + status = "disabled"; + }; + usbotg: usb@5100000 { compatible = "allwinner,sun50i-h616-musb", "allwinner,sun8i-h3-musb"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-longanpi-3h.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-longanpi-3h.dts index 18b29c6b867f3f..16c68177ff6936 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h618-longanpi-3h.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-longanpi-3h.dts @@ -111,6 +111,7 @@ ext_rgmii_phy: ethernet-phy@1 { }; &mmc0 { + disable-wp; bus-width = <4>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ vmmc-supply = <®_vcc3v3>; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts index 6a4f0da9723303..a0fe7a9afb77c2 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts @@ -54,6 +54,11 @@ reg_vcc3v3: vcc3v3 { }; }; +&codec { + allwinner,audio-routing = "Line Out", "LINEOUT"; + status = "okay"; +}; + &cpu0 { cpu-supply = <®_dcdc2>; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-transpeed-8k618-t.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-transpeed-8k618-t.dts index d6631bfe629fa3..f828ca1ce51ef4 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h618-transpeed-8k618-t.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-transpeed-8k618-t.dts @@ -52,6 +52,11 @@ wifi_pwrseq: pwrseq { }; }; +&codec { + allwinner,audio-routing = "Line Out", "LINEOUT"; + status = "okay"; +}; + &cpu0 { cpu-supply = <®_dcdc2>; }; @@ -71,6 +76,7 @@ &ir { &mmc0 { vmmc-supply = <®_dldo1>; cd-gpios = <&pio 8 16 GPIO_ACTIVE_LOW>; /* PI16 */ + disable-wp; bus-width = <4>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts b/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts index 80ccab7b5ba750..a231abf1684ad6 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h700-anbernic-rg35xx-2024.dts @@ -177,6 +177,12 @@ reg_vcc5v: regulator-vcc5v { /* USB-C power input */ }; }; +&codec { + allwinner,audio-routing = "Line Out", "LINEOUT"; + allwinner,pa-gpios = <&pio 8 5 GPIO_ACTIVE_HIGH>; // PI5 + status = "okay"; +}; + &cpu0 { cpu-supply = <®_dcdc1>; }; @@ -270,7 +276,7 @@ reg_aldo3: aldo3 { reg_aldo4: aldo4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; - regulator-name = "vcc-pg"; + regulator-name = "avcc"; }; reg_bldo1: bldo1 { @@ -293,7 +299,10 @@ reg_bldo4: bldo4 { }; reg_cldo1: cldo1 { - /* 3.3v - audio codec - not yet implemented */ + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-spkr-amp"; }; reg_cldo2: cldo2 { diff --git a/arch/arm64/boot/dts/amd/amd-overdrive-rev-b0.dts b/arch/arm64/boot/dts/amd/amd-overdrive-rev-b0.dts index 1a65f1ec183d13..7c82d90e940d3f 100644 --- a/arch/arm64/boot/dts/amd/amd-overdrive-rev-b0.dts +++ b/arch/arm64/boot/dts/amd/amd-overdrive-rev-b0.dts @@ -27,7 +27,6 @@ psci { &ccp0 { status = "okay"; - amd,zlib-support = <1>; }; /** diff --git a/arch/arm64/boot/dts/amd/amd-overdrive-rev-b1.dts b/arch/arm64/boot/dts/amd/amd-overdrive-rev-b1.dts index 52f8d36295a834..58e2b0a6f84192 100644 --- a/arch/arm64/boot/dts/amd/amd-overdrive-rev-b1.dts +++ b/arch/arm64/boot/dts/amd/amd-overdrive-rev-b1.dts @@ -27,7 +27,6 @@ psci { &ccp0 { status = "okay"; - amd,zlib-support = <1>; }; /** diff --git a/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi b/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi index 690020589d41fe..d3d931eb767779 100644 --- a/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi +++ b/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi @@ -123,8 +123,8 @@ spi0: spi@e1020000 { reg = <0 0xe1020000 0 0x1000>; spi-controller; interrupts = <0 330 4>; - clocks = <&uartspiclk_100mhz>; - clock-names = "apb_pclk"; + clocks = <&uartspiclk_100mhz>, <&uartspiclk_100mhz>; + clock-names = "sspclk", "apb_pclk"; }; spi1: spi@e1030000 { @@ -133,8 +133,8 @@ spi1: spi@e1030000 { reg = <0 0xe1030000 0 0x1000>; spi-controller; interrupts = <0 329 4>; - clocks = <&uartspiclk_100mhz>; - clock-names = "apb_pclk"; + clocks = <&uartspiclk_100mhz>, <&uartspiclk_100mhz>; + clock-names = "sspclk", "apb_pclk"; num-cs = <1>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi index d0cda759c25d07..fd0e557eba06c1 100644 --- a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +++ b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi @@ -410,6 +410,300 @@ mux { drive-strength-microamp = <4000>; }; }; + + pwm_a_pins1: pwm-a-pins1 { + mux { + groups = "pwm_a"; + function = "pwm_a"; + }; + }; + + pwm_b_pins1: pwm-b-pins1 { + mux { + groups = "pwm_b"; + function = "pwm_b"; + }; + }; + + pwm_c_pins1: pwm-c-pins1 { + mux { + groups = "pwm_c"; + function = "pwm_c"; + }; + }; + + pwm_d_pins1: pwm-d-pins1 { + mux { + groups = "pwm_d"; + function = "pwm_d"; + }; + }; + + pwm_e_pins1: pwm-e-pins1 { + mux { + groups = "pwm_e"; + function = "pwm_e"; + }; + }; + + pwm_f_pins1: pwm-f-pins1 { + mux { + groups = "pwm_f"; + function = "pwm_f"; + }; + }; + + pwm_g_pins1: pwm-g-pins1 { + mux { + groups = "pwm_g_b"; + function = "pwm_g"; + }; + }; + + pwm_g_pins2: pwm-g-pins2 { + mux { + groups = "pwm_g_c"; + function = "pwm_g"; + }; + }; + + pwm_g_pins3: pwm-g-pins3 { + mux { + groups = "pwm_g_d"; + function = "pwm_g"; + }; + }; + + pwm_g_pins4: pwm-g-pins4 { + mux { + groups = "pwm_g_x0"; + function = "pwm_g"; + }; + }; + + pwm_g_pins5: pwm-g-pins5 { + mux { + groups = "pwm_g_x8"; + function = "pwm_g"; + }; + }; + + pwm_h_pins1: pwm-h-pins1 { + mux { + groups = "pwm_h_b"; + function = "pwm_h"; + }; + }; + + pwm_h_pins2: pwm-h-pins2 { + mux { + groups = "pwm_h_c"; + function = "pwm_h"; + }; + }; + + pwm_h_pins3: pwm-h-pins3 { + mux { + groups = "pwm_h_d"; + function = "pwm_h"; + }; + }; + + pwm_h_pins4: pwm-h-pins4 { + mux { + groups = "pwm_h_x1"; + function = "pwm_h"; + }; + }; + + pwm_h_pins5: pwm-h-pins5 { + mux { + groups = "pwm_h_x9"; + function = "pwm_h"; + }; + }; + + pwm_i_pins1: pwm-i-pins1 { + mux { + groups = "pwm_i_b"; + function = "pwm_i"; + }; + }; + + pwm_i_pins2: pwm-i-pins2 { + mux { + groups = "pwm_i_c"; + function = "pwm_i"; + }; + }; + + pwm_i_pins3: pwm-i-pins3 { + mux { + groups = "pwm_i_d"; + function = "pwm_i"; + }; + }; + + pwm_i_pins4: pwm-i-pins4 { + mux { + groups = "pwm_i_x2"; + function = "pwm_i"; + }; + }; + + pwm_i_pins5: pwm-i-pins5 { + mux { + groups = "pwm_i_x10"; + function = "pwm_i"; + }; + }; + + pwm_j_pins1: pwm-j-pins1 { + mux { + groups = "pwm_j_c"; + function = "pwm_j"; + }; + }; + + pwm_j_pins2: pwm-j-pins2 { + mux { + groups = "pwm_j_d"; + function = "pwm_j"; + }; + }; + + pwm_j_pins3: pwm-j-pins3 { + mux { + groups = "pwm_j_b"; + function = "pwm_j"; + }; + }; + + pwm_j_pins4: pwm-j-pins4 { + mux { + groups = "pwm_j_x3"; + function = "pwm_j"; + }; + }; + + pwm_j_pins5: pwm-j-pins5 { + mux { + groups = "pwm_j_x12"; + function = "pwm_j"; + }; + }; + + pwm_k_pins1: pwm-k-pins1 { + mux { + groups = "pwm_k_c"; + function = "pwm_k"; + }; + }; + + pwm_k_pins2: pwm-k-pins2 { + mux { + groups = "pwm_k_d"; + function = "pwm_k"; + }; + }; + + pwm_k_pins3: pwm-k-pins3 { + mux { + groups = "pwm_k_b"; + function = "pwm_k"; + }; + }; + + pwm_k_pins4: pwm-k-pins4 { + mux { + groups = "pwm_k_x4"; + function = "pwm_k"; + }; + }; + + pwm_k_pins5: pwm-k-pins5 { + mux { + groups = "pwm_k_x13"; + function = "pwm_k"; + }; + }; + + pwm_l_pins1: pwm-l-pins1 { + mux { + groups = "pwm_l_c"; + function = "pwm_l"; + }; + }; + + pwm_l_pins2: pwm-l-pins2 { + mux { + groups = "pwm_l_x"; + function = "pwm_l"; + }; + }; + + pwm_l_pins3: pwm-l-pins3 { + mux { + groups = "pwm_l_b"; + function = "pwm_l"; + }; + }; + + pwm_l_pins4: pwm-l-pins4 { + mux { + groups = "pwm_l_a"; + function = "pwm_l"; + }; + }; + + pwm_m_pins1: pwm-m-pins1 { + mux { + groups = "pwm_m_c"; + function = "pwm_m"; + }; + }; + + pwm_m_pins2: pwm-m-pins2 { + mux { + groups = "pwm_m_x"; + function = "pwm_m"; + }; + }; + + pwm_m_pins3: pwm-m-pins3 { + mux { + groups = "pwm_m_a"; + function = "pwm_m"; + }; + }; + + pwm_m_pins4: pwm-m-pins4 { + mux { + groups = "pwm_m_b"; + function = "pwm_m"; + }; + }; + + pwm_n_pins1: pwm-n-pins1 { + mux { + groups = "pwm_n_x"; + function = "pwm_n"; + }; + }; + + pwm_n_pins2: pwm-n-pins2 { + mux { + groups = "pwm_n_a"; + function = "pwm_n"; + }; + }; + + pwm_n_pins3: pwm-n-pins3 { + mux { + groups = "pwm_n_b"; + function = "pwm_n"; + }; + }; }; gpio_intc: interrupt-controller@4080 { @@ -490,6 +784,16 @@ spicc1: spi@52000 { status = "disabled"; }; + pwm_mn: pwm@54000 { + compatible = "amlogic,c3-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 54000 0x0 0x24>; + clocks = <&clkc_periphs CLKID_PWM_M>, + <&clkc_periphs CLKID_PWM_N>; + #pwm-cells = <3>; + status = "disabled"; + }; + spifc: spi@56000 { compatible = "amlogic,a1-spifc"; reg = <0x0 0x56000 0x0 0x290>; @@ -499,6 +803,66 @@ spifc: spi@56000 { status = "disabled"; }; + pwm_ab: pwm@58000 { + compatible = "amlogic,c3-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x58000 0x0 0x24>; + clocks = <&clkc_periphs CLKID_PWM_A>, + <&clkc_periphs CLKID_PWM_B>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_cd: pwm@5a000 { + compatible = "amlogic,c3-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x5a000 0x0 0x24>; + clocks = <&clkc_periphs CLKID_PWM_C>, + <&clkc_periphs CLKID_PWM_D>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_ef: pwm@5c000 { + compatible = "amlogic,c3-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x5c000 0x0 0x24>; + clocks = <&clkc_periphs CLKID_PWM_E>, + <&clkc_periphs CLKID_PWM_F>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_gh: pwm@5e000 { + compatible = "amlogic,c3-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x5e000 0x0 0x24>; + clocks = <&clkc_periphs CLKID_PWM_G>, + <&clkc_periphs CLKID_PWM_H>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_ij: pwm@60000 { + compatible = "amlogic,c3-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x60000 0x0 0x24>; + clocks = <&clkc_periphs CLKID_PWM_I>, + <&clkc_periphs CLKID_PWM_J>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_kl: pwm@62000 { + compatible = "amlogic,c3-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x62000 0x0 0x24>; + clocks = <&clkc_periphs CLKID_PWM_K>, + <&clkc_periphs CLKID_PWM_L>; + #pwm-cells = <3>; + status = "disabled"; + }; + i2c0: i2c@66000 { compatible = "amlogic,meson-axg-i2c"; reg = <0x0 0x66000 0x0 0x24>; diff --git a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi index e5366d4239b13a..1eba0afb3fd91c 100644 --- a/arch/arm64/boot/dts/amlogic/meson-a1.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-a1.dtsi @@ -245,6 +245,188 @@ mux { }; }; + pwm_a_pins1: pwm-a-pins1 { + mux { + groups = "pwm_a_x6"; + function = "pwm_a"; + }; + }; + + pwm_a_pins2: pwm-a-pins2 { + mux { + groups = "pwm_a_x7"; + function = "pwm_a"; + }; + }; + + pwm_a_pins3: pwm-a-pins3 { + mux { + groups = "pwm_a_f10"; + function = "pwm_a"; + }; + }; + + pwm_a_pins4: pwm-a-pins4 { + mux { + groups = "pwm_a_f6"; + function = "pwm_a"; + }; + }; + + pwm_a_pins5: pwm-a-pins5 { + mux { + groups = "pwm_a_a"; + function = "pwm_a"; + }; + }; + + pwm_b_pins1: pwm-b-pins1 { + mux { + groups = "pwm_b_x"; + function = "pwm_b"; + }; + }; + + pwm_b_pins2: pwm-b-pins2 { + mux { + groups = "pwm_b_f"; + function = "pwm_b"; + }; + }; + + pwm_b_pins3: pwm-b-pins3 { + mux { + groups = "pwm_b_a"; + function = "pwm_b"; + }; + }; + + pwm_c_pins1: pwm-c-pins1 { + mux { + groups = "pwm_c_x"; + function = "pwm_c"; + }; + }; + + pwm_c_pins2: pwm-c-pins2 { + mux { + groups = "pwm_c_f3"; + function = "pwm_c"; + }; + }; + + pwm_c_pins3: pwm-c-pins3 { + mux { + groups = "pwm_c_f8"; + function = "pwm_c"; + }; + }; + + pwm_c_pins4: pwm-c-pins4 { + mux { + groups = "pwm_c_a"; + function = "pwm_c"; + }; + }; + + pwm_d_pins1: pwm-d-pins1 { + mux { + groups = "pwm_d_x15"; + function = "pwm_d"; + }; + }; + + pwm_d_pins2: pwm-d-pins2 { + mux { + groups = "pwm_d_x13"; + function = "pwm_d"; + }; + }; + + pwm_d_pins3: pwm-d-pins3 { + mux { + groups = "pwm_d_x10"; + function = "pwm_d"; + }; + }; + + pwm_d_pins4: pwm-d-pins4 { + mux { + groups = "pwm_d_f"; + function = "pwm_d"; + }; + }; + + pwm_e_pins1: pwm-e-pins1 { + mux { + groups = "pwm_e_p"; + function = "pwm_e"; + }; + }; + + pwm_e_pins2: pwm-e-pins2 { + mux { + groups = "pwm_e_x16"; + function = "pwm_e"; + }; + }; + + pwm_e_pins3: pwm-e-pins3 { + mux { + groups = "pwm_e_x14"; + function = "pwm_e"; + }; + }; + + pwm_e_pins4: pwm-e-pins4 { + mux { + groups = "pwm_e_x2"; + function = "pwm_e"; + }; + }; + + pwm_e_pins5: pwm-e-pins5 { + mux { + groups = "pwm_e_f"; + function = "pwm_e"; + }; + }; + + pwm_e_pins6: pwm-e-pins6 { + mux { + groups = "pwm_e_a"; + function = "pwm_e"; + }; + }; + + pwm_f_pins1: pwm-f-pins1 { + mux { + groups = "pwm_f_b"; + function = "pwm_f"; + }; + }; + + pwm_f_pins2: pwm-f-pins2 { + mux { + groups = "pwm_f_x"; + function = "pwm_f"; + }; + }; + + pwm_f_pins3: pwm-f-pins3 { + mux { + groups = "pwm_f_f4"; + function = "pwm_f"; + }; + }; + + pwm_f_pins4: pwm-f-pins4 { + mux { + groups = "pwm_f_f12"; + function = "pwm_f"; + }; + }; + sdio_pins: sdio { mux0 { groups = "sdcard_d0_x", @@ -340,6 +522,28 @@ uart_AO_B: serial@2000 { status = "disabled"; }; + pwm_ab: pwm@2400 { + compatible = "amlogic,meson-a1-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x2400 0x0 0x24>; + #pwm-cells = <3>; + clocks = <&clkc_periphs CLKID_PWM_A>, + <&clkc_periphs CLKID_PWM_B>; + power-domains = <&pwrc PWRC_I2C_ID>; + status = "disabled"; + }; + + pwm_cd: pwm@2800 { + compatible = "amlogic,meson-a1-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x2800 0x0 0x24>; + #pwm-cells = <3>; + clocks = <&clkc_periphs CLKID_PWM_C>, + <&clkc_periphs CLKID_PWM_D>; + power-domains = <&pwrc PWRC_I2C_ID>; + status = "disabled"; + }; + saradc: adc@2c00 { compatible = "amlogic,meson-g12a-saradc", "amlogic,meson-saradc"; @@ -409,6 +613,7 @@ cpu_temp: temperature-sensor@4c00 { assigned-clock-rates = <500000>; #thermal-sensor-cells = <0>; amlogic,ao-secure = <&sec_AO>; + power-domains = <&pwrc PWRC_I2C_ID>; }; hwrng: rng@5118 { @@ -423,6 +628,17 @@ sec_AO: ao-secure@5a20 { amlogic,has-chip-id; }; + pwm_ef: pwm@5400 { + compatible = "amlogic,meson-a1-pwm", + "amlogic,meson-s4-pwm"; + reg = <0x0 0x5400 0x0 0x24>; + #pwm-cells = <3>; + clocks = <&clkc_periphs CLKID_PWM_E>, + <&clkc_periphs CLKID_PWM_F>; + power-domains = <&pwrc PWRC_I2C_ID>; + status = "disabled"; + }; + clkc_pll: pll-clock-controller@7c80 { compatible = "amlogic,a1-pll-clkc"; reg = <0 0x7c80 0 0x18c>; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi index d08c97797010d6..49b51c54013f15 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi @@ -1913,7 +1913,7 @@ mux { }; }; - uart_ao_a_pins: uart-a-ao { + uart_ao_a_pins: uart-ao-a { mux { groups = "uart_ao_a_tx", "uart_ao_a_rx"; diff --git a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi index ea5721ea02f0e6..5a64239b4708c3 100644 --- a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi +++ b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi @@ -809,7 +809,6 @@ i2c1: i2c@10511000 { interrupts = <0 0x45 0x4>; #clock-cells = <1>; clocks = <&sbapbclk 0>; - bus_num = <1>; }; i2c4: i2c@10640000 { @@ -819,7 +818,6 @@ i2c4: i2c@10640000 { reg = <0x0 0x10640000 0x0 0x1000>; interrupts = <0 0x3a 0x4>; clocks = <&i2c4clk 0>; - bus_num = <4>; }; }; }; diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi index 6ad4703925dc5f..872093b05ce19f 100644 --- a/arch/arm64/boot/dts/apm/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi @@ -851,7 +851,6 @@ i2c0: i2c@10512000 { interrupts = <0 0x44 0x4>; #clock-cells = <1>; clocks = <&ahbclk 0>; - bus_num = <0>; }; phy1: phy@1f21a000 { diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile index aec5e29cdfb737..ab6ebb53218ad9 100644 --- a/arch/arm64/boot/dts/apple/Makefile +++ b/arch/arm64/boot/dts/apple/Makefile @@ -1,4 +1,57 @@ # SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j71.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j73.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j85m.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j86m.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j87m.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-n53.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j72.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j85.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j86.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-j87.dtb +dtb-$(CONFIG_ARCH_APPLE) += s5l8960x-n51.dtb +dtb-$(CONFIG_ARCH_APPLE) += t7000-j42d.dtb +dtb-$(CONFIG_ARCH_APPLE) += t7000-j96.dtb +dtb-$(CONFIG_ARCH_APPLE) += t7000-j97.dtb +dtb-$(CONFIG_ARCH_APPLE) += t7000-n102.dtb +dtb-$(CONFIG_ARCH_APPLE) += t7000-n56.dtb +dtb-$(CONFIG_ARCH_APPLE) += t7000-n61.dtb +dtb-$(CONFIG_ARCH_APPLE) += t7001-j81.dtb +dtb-$(CONFIG_ARCH_APPLE) += t7001-j82.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8000-j71s.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8000-j72s.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8000-n66.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8000-n69u.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8000-n71.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8003-j71t.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8003-j72t.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8003-n66m.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8003-n69.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8003-n71m.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8001-j127.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8001-j128.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8001-j98a.dtb +dtb-$(CONFIG_ARCH_APPLE) += s8001-j99a.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-d101.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-d10.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-d111.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-d11.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-j171.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-j172.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-j71b.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-j72b.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8010-n112.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8011-j105a.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8011-j120.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8011-j121.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8011-j207.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8011-j208.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8015-d201.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8015-d20.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8015-d211.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8015-d21.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8015-d221.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8015-d22.dtb dtb-$(CONFIG_ARCH_APPLE) += t8103-j274.dtb dtb-$(CONFIG_ARCH_APPLE) += t8103-j293.dtb dtb-$(CONFIG_ARCH_APPLE) += t8103-j313.dtb diff --git a/arch/arm64/boot/dts/apple/s5l8960x-5s.dtsi b/arch/arm64/boot/dts/apple/s5l8960x-5s.dtsi new file mode 100644 index 00000000000000..0b16adf07f79b1 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-5s.dtsi @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 5s common device tree + * Based on A7 (APL0698), up to 1.3GHz + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "s5l8960x.dtsi" +#include "s5l8960x-common.dtsi" +#include + +/ { + chassis-type = "handset"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl 2 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl 3 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl 5 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl 4 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + switch-mute { + label = "Mute Switch"; + gpios = <&pinctrl 16 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-air1.dtsi b/arch/arm64/boot/dts/apple/s5l8960x-air1.dtsi new file mode 100644 index 00000000000000..741c5a9f21dd2f --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-air1.dtsi @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Air common device tree + * Based on A7 (APL5698), up to 1.4GHz + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "s5l8960x.dtsi" +#include "s5l8960x-common.dtsi" +#include + +/ { + chassis-type = "tablet"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl 2 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl 3 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl 4 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl 5 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + switch-mute { + label = "Mute Switch"; + gpios = <&pinctrl 110 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-common.dtsi b/arch/arm64/boot/dts/apple/s5l8960x-common.dtsi new file mode 100644 index 00000000000000..243480ca235669 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-common.dtsi @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 5s, iPad mini 2/3, iPad Air + * + * This file contains parts common to all Apple A7 devices. + * + * target-type: J71, J72, J73, J85, J85m, J86, J86m, J87, J87m, N51, N53 + * + * Copyright (c) 2024, Nick Chan + */ + +/ { + aliases { + serial0 = &serial0; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0 0>; /* To be filled by loader */ + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j71.dts b/arch/arm64/boot/dts/apple/s5l8960x-j71.dts new file mode 100644 index 00000000000000..e13036dacb4587 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j71.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Air (Wi-Fi), J71, iPad4,1 (A1474) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-air1.dtsi" + +/ { + compatible = "apple,j71", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad Air (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j72.dts b/arch/arm64/boot/dts/apple/s5l8960x-j72.dts new file mode 100644 index 00000000000000..afb71b8885c656 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j72.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Air (Cellular), J72, iPad4,2 (A1475) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-air1.dtsi" + +/ { + compatible = "apple,j72", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad Air (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j73.dts b/arch/arm64/boot/dts/apple/s5l8960x-j73.dts new file mode 100644 index 00000000000000..c871962df52983 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j73.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Air (Cellular, China), J73, iPad4,2 (A1476) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-air1.dtsi" + +/ { + compatible = "apple,j73", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad Air (Cellular, China)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j85.dts b/arch/arm64/boot/dts/apple/s5l8960x-j85.dts new file mode 100644 index 00000000000000..aefb7b36d7aa36 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j85.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 2 (Wi-Fi), J85, iPad4,4 (A1489) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-mini2.dtsi" + +/ { + compatible = "apple,j85", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad mini 2 (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j85m.dts b/arch/arm64/boot/dts/apple/s5l8960x-j85m.dts new file mode 100644 index 00000000000000..ec2bcaa6d1d5f7 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j85m.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 3 (Wi-Fi), J85m, iPad4,7 (A1599) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-mini3.dtsi" + +/ { + compatible = "apple,j85m", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad mini 3 (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j86.dts b/arch/arm64/boot/dts/apple/s5l8960x-j86.dts new file mode 100644 index 00000000000000..470f2f825e70a4 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j86.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 2 (Cellular), J86, iPad4,5 (A1490) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-mini2.dtsi" + +/ { + compatible = "apple,j86", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad mini 2 (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j86m.dts b/arch/arm64/boot/dts/apple/s5l8960x-j86m.dts new file mode 100644 index 00000000000000..90311d98aaad6c --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j86m.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 3 (Cellular), J86m, iPad4,8 (A1600) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-mini3.dtsi" + +/ { + compatible = "apple,j86m", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad mini 3 (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j87.dts b/arch/arm64/boot/dts/apple/s5l8960x-j87.dts new file mode 100644 index 00000000000000..3580fd8e3831de --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j87.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 2 (Cellular, China), J87, iPad4,6 (A1491) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-mini2.dtsi" + +/ { + compatible = "apple,j87", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad mini 2 (Cellular, China)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-j87m.dts b/arch/arm64/boot/dts/apple/s5l8960x-j87m.dts new file mode 100644 index 00000000000000..fa0da4fa67278c --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-j87m.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 3 (Cellular, China), J87m, iPad4,9 (A1601) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-mini3.dtsi" + +/ { + compatible = "apple,j87m", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPad mini 3 (Cellular, China)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-mini2.dtsi b/arch/arm64/boot/dts/apple/s5l8960x-mini2.dtsi new file mode 100644 index 00000000000000..b27ef568062643 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-mini2.dtsi @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 2 common device tree + * Based on A7 (APL0698), up to 1.3GHz + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "s5l8960x.dtsi" +#include "s5l8960x-common.dtsi" +#include + +/ { + chassis-type = "tablet"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl 2 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl 3 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl 5 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl 4 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + switch-mute { + label = "Mute Switch"; + gpios = <&pinctrl 6 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-mini3.dtsi b/arch/arm64/boot/dts/apple/s5l8960x-mini3.dtsi new file mode 100644 index 00000000000000..4e397b3d7d7ad3 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-mini3.dtsi @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 3 common device tree + * Based on A7 (APL0698), up to 1.3GHz + * + * Copyright (c) 2022, Konrad Dybcio + */ + +/* + * The Mini 3 seems to be only an iteration over the Mini 2 with some + * small changes, like the introduction of Touch ID, hence there is little + * to no differentiation between these 2 for now. + */ +#include "s5l8960x-mini2.dtsi" diff --git a/arch/arm64/boot/dts/apple/s5l8960x-n51.dts b/arch/arm64/boot/dts/apple/s5l8960x-n51.dts new file mode 100644 index 00000000000000..cd52f814fbf2b2 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-n51.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 5s (GSM), N51, iPhone6,1 (A1453/A1533) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-5s.dtsi" + +/ { + compatible = "apple,n51", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPhone 5s (GSM)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x-n53.dts b/arch/arm64/boot/dts/apple/s5l8960x-n53.dts new file mode 100644 index 00000000000000..4795798a4444dc --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x-n53.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 5s (LTE), N53, iPhone6,2 (A1457/A1518/A1528/A1530) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s5l8960x-5s.dtsi" + +/ { + compatible = "apple,n53", "apple,s5l8960x", "apple,arm-platform"; + model = "Apple iPhone 5s (LTE)"; +}; diff --git a/arch/arm64/boot/dts/apple/s5l8960x.dtsi b/arch/arm64/boot/dts/apple/s5l8960x.dtsi new file mode 100644 index 00000000000000..0218ecac1d8364 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s5l8960x.dtsi @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple S5L8960X "A7" SoC + * + * Other Names: H6, "Alcatraz" + * + * Copyright (c) 2022, Konrad Dybcio + * Based on Asahi Linux's M1 (t8103.dtsi) and Corellium's A10 efforts. + */ + +#include +#include +#include +#include + +/ { + interrupt-parent = <&aic>; + #address-cells = <2>; + #size-cells = <2>; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "apple,cyclone"; + reg = <0x0 0x0>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu1: cpu@1 { + compatible = "apple,cyclone"; + reg = <0x0 0x1>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + nonposted-mmio; + ranges; + + serial0: serial@20a0a0000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x0a0a0000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + wdt: watchdog@20e027000 { + compatible = "apple,s5l8960x-wdt", "apple,wdt"; + reg = <0x2 0x0e027000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + aic: interrupt-controller@20e100000 { + compatible = "apple,s5l8960x-aic", "apple,aic"; + reg = <0x2 0x0e100000 0x0 0x100000>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + pinctrl: pinctrl@20e300000 { + compatible = "apple,s5l8960x-pinctrl", "apple,pinctrl"; + reg = <0x2 0x0e300000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 200>; + apple,npins = <200>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt"; + /* Note that A7 doesn't actually have a hypervisor (EL2 is not implemented). */ + interrupts = , + ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/s800-0-3-common.dtsi b/arch/arm64/boot/dts/apple/s800-0-3-common.dtsi new file mode 100644 index 00000000000000..4276bd890e81b1 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s800-0-3-common.dtsi @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6s, iPhone 6s Plus, iPad 5, iPhone SE + * + * This file contains parts common to all Apple A9 devices. + * + * target-type: J71s, J72s, N66, N69u, N71, J71t, J72t, N66m, N69, N71m + * + * Copyright (c) 2024, Nick Chan + */ + +/ { + aliases { + serial0 = &serial0; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0 0>; /* To be filled by loader */ + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/s8000-j71s.dts b/arch/arm64/boot/dts/apple/s8000-j71s.dts new file mode 100644 index 00000000000000..b5a2dfa1121e19 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8000-j71s.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 5 (Wi-Fi) (Samsung), J71s, iPad6,11 (A1822) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8000.dtsi" +#include "s800x-ipad5.dtsi" + +/ { + compatible = "apple,j71s", "apple,s8000", "apple,arm-platform"; + model = "Apple iPad 5 (Wi-Fi) (Samsung)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8000-j72s.dts b/arch/arm64/boot/dts/apple/s8000-j72s.dts new file mode 100644 index 00000000000000..8f3dea5adb0983 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8000-j72s.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 5 (Cellular) (Samsung), J72s, iPad6,12 (A1823) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8000.dtsi" +#include "s800x-ipad5.dtsi" + +/ { + compatible = "apple,j72s", "apple,s8000", "apple,arm-platform"; + model = "Apple iPad 5 (Cellular) (Samsung)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8000-n66.dts b/arch/arm64/boot/dts/apple/s8000-n66.dts new file mode 100644 index 00000000000000..30b4b6630b603e --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8000-n66.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6s Plus (Samsung), N66, iPhone8,2 (A1634/A1687/A1690/A1699) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8000.dtsi" +#include "s800x-6s.dtsi" + +/ { + compatible = "apple,n66", "apple,s8000", "apple,arm-platform"; + model = "Apple iPhone 6s Plus (Samsung)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8000-n69u.dts b/arch/arm64/boot/dts/apple/s8000-n69u.dts new file mode 100644 index 00000000000000..e63bc2e7f7c1f5 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8000-n69u.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone SE (Samsung), N69u, iPhone8,4 (A1662/A1723/A1724) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8000.dtsi" +#include "s800x-se.dtsi" + +/ { + compatible = "apple,n69u", "apple,s8000", "apple,arm-platform"; + model = "Apple iPhone SE (Samsung)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8000-n71.dts b/arch/arm64/boot/dts/apple/s8000-n71.dts new file mode 100644 index 00000000000000..f2964a1fc4349b --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8000-n71.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6s (Samsung), N71, iPhone8,1 (A1633/A1688/A1691/A1700) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8000.dtsi" +#include "s800x-6s.dtsi" + +/ { + compatible = "apple,n71", "apple,s8000", "apple,arm-platform"; + model = "Apple iPhone 6s (Samsung)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8000.dtsi b/arch/arm64/boot/dts/apple/s8000.dtsi new file mode 100644 index 00000000000000..6e9046ea106c08 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8000.dtsi @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple S8000 "A9" (Samsung) SoC + * + * Other names: H8P, "Maui" + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include +#include +#include +#include + +/ { + interrupt-parent = <&aic>; + #address-cells = <2>; + #size-cells = <2>; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "apple,twister"; + reg = <0x0 0x0>; + cpu-release-addr = <0 0>; /* To be filled in by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu1: cpu@1 { + compatible = "apple,twister"; + reg = <0x0 0x1>; + cpu-release-addr = <0 0>; /* To be filled in by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + nonposted-mmio; + ranges; + + serial0: serial@20a0c0000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x0a0c0000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + aic: interrupt-controller@20e100000 { + compatible = "apple,s8000-aic", "apple,aic"; + reg = <0x2 0x0e100000 0x0 0x100000>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + pinctrl_ap: pinctrl@20f100000 { + compatible = "apple,s8000-pinctrl", "apple,pinctrl"; + reg = <0x2 0x0f100000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_ap 0 0 208>; + apple,npins = <208>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + pinctrl_aop: pinctrl@2100f0000 { + compatible = "apple,s8000-pinctrl", "apple,pinctrl"; + reg = <0x2 0x100f0000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aop 0 0 42>; + apple,npins = <42>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + wdt: watchdog@2102b0000 { + compatible = "apple,s8000-wdt", "apple,wdt"; + reg = <0x2 0x102b0000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt"; + /* Note that A9 doesn't actually have a hypervisor (EL2 is not implemented). */ + interrupts = , + ; + }; +}; + +/* + * The A9 was made by two separate fabs on two different process + * nodes: Samsung made the S8000 (APL0898) on 14nm and TSMC made + * the S8003 (APL1022) on 16nm. While they are seemingly the same, + * they do have distinct part numbers and devices using them have + * distinct model names. There are currently no known differences + * between these as far as Linux is concerned, but let's keep things + * structured properly to make it easier to alter the behaviour of + * one of the chips if need be. + */ diff --git a/arch/arm64/boot/dts/apple/s8001-common.dtsi b/arch/arm64/boot/dts/apple/s8001-common.dtsi new file mode 100644 index 00000000000000..e94d0e77653a8a --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8001-common.dtsi @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro (9.7-inch), iPad Pro (12.9-inch) + * + * This file contains parts common to all Apple A9X devices. + * + * target-type: J127, J128, J98a, J99a + * + * Copyright (c) 2024, Nick Chan + */ + +/ { + aliases { + serial0 = &serial0; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0 0>; /* To be filled by loader */ + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/s8001-j127.dts b/arch/arm64/boot/dts/apple/s8001-j127.dts new file mode 100644 index 00000000000000..8b522085cb3ece --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8001-j127.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro (9.7-inch) (Wi-Fi), J127, iPad6,3 (A1673) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8001-pro.dtsi" + +/ { + compatible = "apple,j127", "apple,s8001", "apple,arm-platform"; + model = "Apple iPad Pro (9.7-inch) (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8001-j128.dts b/arch/arm64/boot/dts/apple/s8001-j128.dts new file mode 100644 index 00000000000000..cdd3d06dcbf1e5 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8001-j128.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro (9.7-inch) (Cellular), J128, iPad6,4 (A1674/A1675) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8001-pro.dtsi" + +/ { + compatible = "apple,j128", "apple,s8001", "apple,arm-platform"; + model = "Apple iPad Pro (9.7-inch) (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8001-j98a.dts b/arch/arm64/boot/dts/apple/s8001-j98a.dts new file mode 100644 index 00000000000000..6d6b841e7ab0bd --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8001-j98a.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro (12.9-inch) (Wi-Fi), J98a, iPad6,7 (A1584) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8001-pro.dtsi" + +/ { + compatible = "apple,j98a", "apple,s8001", "apple,arm-platform"; + model = "Apple iPad Pro (12.9-inch) (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8001-j99a.dts b/arch/arm64/boot/dts/apple/s8001-j99a.dts new file mode 100644 index 00000000000000..d20194b1cae733 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8001-j99a.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro (12.9-inch) (Cellular), J99a, iPad6,8 (A1652) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8001-pro.dtsi" + +/ { + compatible = "apple,j99a", "apple,s8001", "apple,arm-platform"; + model = "Apple iPad Pro (12.9-inch) (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8001-pro.dtsi b/arch/arm64/boot/dts/apple/s8001-pro.dtsi new file mode 100644 index 00000000000000..1fce5a7c4200a9 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8001-pro.dtsi @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro (1st generation) common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "s8001.dtsi" +#include "s8001-common.dtsi" +#include + +/ { + chassis-type = "tablet"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl_ap 122 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl_ap 123 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl_ap 15 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl_ap 12 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/s8001.dtsi b/arch/arm64/boot/dts/apple/s8001.dtsi new file mode 100644 index 00000000000000..23ee3238844d95 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8001.dtsi @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple S8001 "A9X" SoC + * + * Other names: H8G, "Elba" + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include +#include +#include +#include + +/ { + interrupt-parent = <&aic>; + #address-cells = <2>; + #size-cells = <2>; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "apple,twister"; + reg = <0x0 0x0>; + cpu-release-addr = <0 0>; /* To be filled in by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu1: cpu@1 { + compatible = "apple,twister"; + reg = <0x0 0x1>; + cpu-release-addr = <0 0>; /* To be filled in by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + nonposted-mmio; + ranges; + + serial0: serial@20a0c0000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x0a0c0000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + aic: interrupt-controller@20e100000 { + compatible = "apple,s8000-aic", "apple,aic"; + reg = <0x2 0x0e100000 0x0 0x100000>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + pinctrl_ap: pinctrl@20f100000 { + compatible = "apple,s8000-pinctrl", "apple,pinctrl"; + reg = <0x2 0x0f100000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_ap 0 0 219>; + apple,npins = <219>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + pinctrl_aop: pinctrl@2100f0000 { + compatible = "apple,s8000-pinctrl", "apple,pinctrl"; + reg = <0x2 0x100f0000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aop 0 0 28>; + apple,npins = <28>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + wdt: watchdog@2102b0000 { + compatible = "apple,s8000-wdt", "apple,wdt"; + reg = <0x2 0x102b0000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt"; + /* Note that A9X doesn't actually have a hypervisor (EL2 is not implemented). */ + interrupts = , + ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/s8003-j71t.dts b/arch/arm64/boot/dts/apple/s8003-j71t.dts new file mode 100644 index 00000000000000..0d906ae80b0756 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8003-j71t.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 5 (Wi-Fi) (TSMC), J71t, iPad6,11 (A1822) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8003.dtsi" +#include "s800x-ipad5.dtsi" + +/ { + compatible = "apple,j71t", "apple,s8003", "apple,arm-platform"; + model = "Apple iPad 5 (Wi-Fi) (TSMC)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8003-j72t.dts b/arch/arm64/boot/dts/apple/s8003-j72t.dts new file mode 100644 index 00000000000000..0cd7d88e9dfbb2 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8003-j72t.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 5 (Cellular) (TSMC), J72t, iPad6,12 (A1823) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8003.dtsi" +#include "s800x-ipad5.dtsi" + +/ { + compatible = "apple,j72t", "apple,s8003", "apple,arm-platform"; + model = "Apple iPad 5 (Cellular) (TSMC)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8003-n66m.dts b/arch/arm64/boot/dts/apple/s8003-n66m.dts new file mode 100644 index 00000000000000..4146cd28160dc4 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8003-n66m.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6s Plus (TSMC), N66m, iPhone8,2 (A1634/A1687/A1690/A1699) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8003.dtsi" +#include "s800x-6s.dtsi" + +/ { + compatible = "apple,n66m", "apple,s8003", "apple,arm-platform"; + model = "Apple iPhone 6s Plus (TSMC)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8003-n69.dts b/arch/arm64/boot/dts/apple/s8003-n69.dts new file mode 100644 index 00000000000000..8eed879b155ece --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8003-n69.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone SE (TSMC), N69, iPhone8,4 (A1662/A1723/A1724) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8003.dtsi" +#include "s800x-se.dtsi" + +/ { + compatible = "apple,n69", "apple,s8003", "apple,arm-platform"; + model = "Apple iPhone SE (TSMC)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8003-n71m.dts b/arch/arm64/boot/dts/apple/s8003-n71m.dts new file mode 100644 index 00000000000000..7ec6d2cda0bf8f --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8003-n71m.dts @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6s (TSMC), N71m, iPhone8,1 (A1633/A1688/A1691/A1700) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "s8003.dtsi" +#include "s800x-6s.dtsi" + +/ { + compatible = "apple,n71m", "apple,s8003", "apple,arm-platform"; + model = "Apple iPhone 6s (TSMC)"; +}; diff --git a/arch/arm64/boot/dts/apple/s8003.dtsi b/arch/arm64/boot/dts/apple/s8003.dtsi new file mode 100644 index 00000000000000..7e4ad4f7e49953 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s8003.dtsi @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple S8003 "A9" (TSMC) SoC + * + * Other names: H8P, "Malta" + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "s8000.dtsi" + +/* + * The A9 was made by two separate fabs on two different process + * nodes: Samsung made the S8000 (APL0898) on 14nm and TSMC made + * the S8003 (APL1022) on 16nm. While they are seemingly the same, + * they do have distinct part numbers and devices using them have + * distinct model names. There are currently no known differences + * between these as far as Linux is concerned, but let's keep things + * structured properly to make it easier to alter the behaviour of + * one of the chips if need be. + */ diff --git a/arch/arm64/boot/dts/apple/s800x-6s.dtsi b/arch/arm64/boot/dts/apple/s800x-6s.dtsi new file mode 100644 index 00000000000000..49b04db310c6e8 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s800x-6s.dtsi @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6s / 6S Plus common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "s800-0-3-common.dtsi" +#include + +/ { + chassis-type = "handset"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl_ap 96 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl_ap 97 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl_ap 67 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl_ap 66 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + switch-mute { + label = "Mute Switch"; + gpios = <&pinctrl_ap 149 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/s800x-ipad5.dtsi b/arch/arm64/boot/dts/apple/s800x-ipad5.dtsi new file mode 100644 index 00000000000000..32570ed3cdf009 --- /dev/null +++ b/arch/arm64/boot/dts/apple/s800x-ipad5.dtsi @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 5 common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "s800-0-3-common.dtsi" +#include + +/ { + chassis-type = "tablet"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl_ap 96 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl_ap 97 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl_ap 143 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl_ap 144 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/s800x-se.dtsi b/arch/arm64/boot/dts/apple/s800x-se.dtsi new file mode 100644 index 00000000000000..a1a5690e83713c --- /dev/null +++ b/arch/arm64/boot/dts/apple/s800x-se.dtsi @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone SE common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "s800-0-3-common.dtsi" +#include + +/ { + chassis-type = "handset"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl_ap 96 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl_ap 97 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl_ap 67 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl_ap 66 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + switch-mute { + label = "Mute Switch"; + gpios = <&pinctrl_ap 149 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-6.dtsi b/arch/arm64/boot/dts/apple/t7000-6.dtsi new file mode 100644 index 00000000000000..f60ea4a4a38716 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-6.dtsi @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6 / 6 Plus common device tree + * Copyright (c) 2022, Konrad Dybcio + */ + +#include +#include "t7000.dtsi" +#include "t7000-common.dtsi" +#include "t7000-handheld.dtsi" + +/ { + chassis-type = "handset"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl 32 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl 33 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl 45 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl 46 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + switch-mute { + label = "Mute Switch"; + gpios = <&pinctrl 131 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-common.dtsi b/arch/arm64/boot/dts/apple/t7000-common.dtsi new file mode 100644 index 00000000000000..87146e6daae799 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-common.dtsi @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple TV HD, iPhone 6, iPhone 6 Plus, iPad mini 4, iPod touch 6 + * + * This file contains parts common to all Apple A8 devices. + * + * target-type: J42d, J96, J97, N56, N61, N102 + * + * Copyright (c) 2024, Nick Chan + */ + +/ { + aliases { + serial0 = &serial0; + serial6 = &serial6; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0 0>; /* To be filled by loader */ + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* To be filled by loader */ + }; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-handheld.dtsi b/arch/arm64/boot/dts/apple/t7000-handheld.dtsi new file mode 100644 index 00000000000000..8984c9ec6cc8e3 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-handheld.dtsi @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6, iPhone 6 Plus, iPad mini 4, iPod touch 6 + * + * This file contains the parts common to handheld devices with t7000 + * + * target-type: J96, J97, N56, N61, N102 + * + * Copyright (c) 2024, Nick Chan + */ + +/ { + chosen { + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-j42d.dts b/arch/arm64/boot/dts/apple/t7000-j42d.dts new file mode 100644 index 00000000000000..2231db6a739d48 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-j42d.dts @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple TV HD, J42d, AppleTV5,3 (A1625) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t7000.dtsi" +#include "t7000-common.dtsi" + +/ { + compatible = "apple,j42d", "apple,t7000", "apple,arm-platform"; + model = "Apple TV HD"; + chassis-type = "television"; + + chosen { + stdout-path = "serial6"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; +}; + +&serial6 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-j96.dts b/arch/arm64/boot/dts/apple/t7000-j96.dts new file mode 100644 index 00000000000000..8a32a50cc2df71 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-j96.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 4 (Wi-Fi), J96, iPad5,1 (A1538) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t7000-mini4.dtsi" + +/ { + compatible = "apple,j96", "apple,t7000", "apple,arm-platform"; + model = "Apple iPad mini 4 (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-j97.dts b/arch/arm64/boot/dts/apple/t7000-j97.dts new file mode 100644 index 00000000000000..ac7d501f88d292 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-j97.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 4 (Cellular), J97, iPad5,2 (A1550) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t7000-mini4.dtsi" + +/ { + compatible = "apple,j97", "apple,t7000", "apple,arm-platform"; + model = "Apple iPad mini 4 (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-mini4.dtsi b/arch/arm64/boot/dts/apple/t7000-mini4.dtsi new file mode 100644 index 00000000000000..c64ddc402fda25 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-mini4.dtsi @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad mini 4 common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "t7000.dtsi" +#include "t7000-common.dtsi" +#include "t7000-handheld.dtsi" +#include + +/ { + chassis-type = "tablet"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl 32 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl 33 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl 45 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl 46 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + switch-mute { + label = "Mute Switch"; + gpios = <&pinctrl 36 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-n102.dts b/arch/arm64/boot/dts/apple/t7000-n102.dts new file mode 100644 index 00000000000000..9c55d339ba4e14 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-n102.dts @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPod touch 6, N102, iPod7,1 (A1574) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t7000.dtsi" +#include "t7000-common.dtsi" +#include "t7000-handheld.dtsi" +#include + +/ { + compatible = "apple,n102", "apple,t7000", "apple,arm-platform"; + model = "Apple iPod touch 6"; + chassis-type = "handset"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl 32 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl 33 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl 46 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl 45 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-n56.dts b/arch/arm64/boot/dts/apple/t7000-n56.dts new file mode 100644 index 00000000000000..2c358df1445856 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-n56.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6 Plus, N56, iPhone7,2 (A1549/A1586/A1589) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t7000-6.dtsi" + +/ { + compatible = "apple,n56", "apple,t7000", "apple,arm-platform"; + model = "Apple iPhone 6 Plus"; +}; diff --git a/arch/arm64/boot/dts/apple/t7000-n61.dts b/arch/arm64/boot/dts/apple/t7000-n61.dts new file mode 100644 index 00000000000000..10b4ca8babf7cd --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000-n61.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 6, N61, iPhone7,2 (A1549/A1586/A1589) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t7000-6.dtsi" + +/ { + compatible = "apple,n61", "apple,t7000", "apple,arm-platform"; + model = "Apple iPhone 6"; +}; diff --git a/arch/arm64/boot/dts/apple/t7000.dtsi b/arch/arm64/boot/dts/apple/t7000.dtsi new file mode 100644 index 00000000000000..a7cc29e84c8410 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7000.dtsi @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T7000 "A8" SoC + * + * Other names: H7P, "Fiji" + * + * Copyright (c) 2022, Konrad Dybcio + * Based on Asahi Linux's M1 (t8103.dtsi) and Corellium's A10 efforts. + */ + +#include +#include +#include +#include + +/ { + interrupt-parent = <&aic>; + #address-cells = <2>; + #size-cells = <2>; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "apple,typhoon"; + reg = <0x0 0x0>; + cpu-release-addr = <0 0>; /* To be filled in by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu1: cpu@1 { + compatible = "apple,typhoon"; + reg = <0x0 0x1>; + cpu-release-addr = <0 0>; /* To be filled in by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + nonposted-mmio; + ranges; + + serial0: serial@20a0c0000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x0a0c0000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + serial6: serial@20a0d8000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x0a0d8000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + wdt: watchdog@20e027000 { + compatible = "apple,t7000-wdt", "apple,wdt"; + reg = <0x2 0x0e027000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + aic: interrupt-controller@20e100000 { + compatible = "apple,t7000-aic", "apple,aic"; + reg = <0x2 0x0e100000 0x0 0x100000>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + pinctrl: pinctrl@20e300000 { + compatible = "apple,t7000-pinctrl", "apple,pinctrl"; + reg = <0x2 0x0e300000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 208>; + apple,npins = <208>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt"; + /* Note that A8 doesn't actually have a hypervisor (EL2 is not implemented). */ + interrupts = , + ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t7001-air2.dtsi b/arch/arm64/boot/dts/apple/t7001-air2.dtsi new file mode 100644 index 00000000000000..19fabd425c5280 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7001-air2.dtsi @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Air 2 common device tree + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "t7001.dtsi" +#include + +/ { + chassis-type = "tablet"; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl 0 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl 1 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl 92 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl 93 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0 0>; /* To be filled by loader */ + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t7001-j81.dts b/arch/arm64/boot/dts/apple/t7001-j81.dts new file mode 100644 index 00000000000000..ca90dc0c872c78 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7001-j81.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Air 2 (Wi-Fi), J81, iPad5,3 (A1566) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t7001-air2.dtsi" + +/ { + compatible = "apple,j81", "apple,t7001", "apple,arm-platform"; + model = "Apple iPad Air 2 (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/t7001-j82.dts b/arch/arm64/boot/dts/apple/t7001-j82.dts new file mode 100644 index 00000000000000..d9fd16f48db7bc --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7001-j82.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Air 2 (Cellular), J82, iPad5,4 (A1567) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t7001-air2.dtsi" + +/ { + compatible = "apple,j82", "apple,t7001", "apple,arm-platform"; + model = "Apple iPad Air 2 (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/t7001.dtsi b/arch/arm64/boot/dts/apple/t7001.dtsi new file mode 100644 index 00000000000000..a76e034c85e346 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t7001.dtsi @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T7001 "A8X" SoC + * + * Copyright (c) 2022, Konrad Dybcio + * Based on Asahi Linux's M1 (t8103.dtsi) and Corellium's A10 efforts. + */ + +#include +#include +#include +#include + +/ { + interrupt-parent = <&aic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &serial0; + }; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "apple,typhoon"; + reg = <0x0 0x0>; + cpu-release-addr = <0 0>; /* To be filled in by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu1: cpu@1 { + compatible = "apple,typhoon"; + reg = <0x0 0x1>; + cpu-release-addr = <0 0>; /* To be filled in by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu2: cpu@2 { + compatible = "apple,typhoon"; + reg = <0x0 0x2>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + nonposted-mmio; + ranges; + + serial0: serial@20a0c0000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x0a0c0000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + wdt: watchdog@20e027000 { + compatible = "apple,t7000-wdt", "apple,wdt"; + reg = <0x2 0x0e027000 0x0 0x1000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + aic: interrupt-controller@20e100000 { + compatible = "apple,t7000-aic", "apple,aic"; + reg = <0x2 0x0e100000 0x0 0x100000>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + pinctrl: pinctrl@20e300000 { + compatible = "apple,t7000-pinctrl", "apple,pinctrl"; + reg = <0x2 0x0e300000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 184>; + apple,npins = <184>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt"; + /* Note that A8X doesn't actually have a hypervisor (EL2 is not implemented). */ + interrupts = , + ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-7.dtsi b/arch/arm64/boot/dts/apple/t8010-7.dtsi new file mode 100644 index 00000000000000..1332fd73f50f08 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-7.dtsi @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 7 / 7 Plus common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "t8010.dtsi" +#include "t8010-common.dtsi" +#include + +/ { + chassis-type = "handset"; + + gpio-keys { + compatible = "gpio-keys"; + + button-power { + label = "Power Button"; + gpios = <&pinctrl_ap 179 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl_ap 180 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl_ap 23 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + switch-mute { + label = "Mute Switch"; + gpios = <&pinctrl_ap 86 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-common.dtsi b/arch/arm64/boot/dts/apple/t8010-common.dtsi new file mode 100644 index 00000000000000..6613fb57c92fff --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-common.dtsi @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Apple iPhone 7, iPhone 7 Plus, iPad 6, iPad 7, iPod touch 7 + * + * This file contains parts common to all Apple A10 devices. + * + * target-type: D10, D11, D101, D111, J71b, J72b, J171, J172, N112 + * + * Copyright (c) 2024, Nick Chan + */ + +/ { + aliases { + serial0 = &serial0; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0 0>; /* To be filled by loader */ + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-d10.dts b/arch/arm64/boot/dts/apple/t8010-d10.dts new file mode 100644 index 00000000000000..39cdd12db6bfc0 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-d10.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 7 (Qualcomm), D10, iPhone9,1 (A1660/A1778/A1779/A1780) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010-7.dtsi" + +/ { + compatible = "apple,d10", "apple,t8010", "apple,arm-platform"; + model = "Apple iPhone 7 (Qualcomm)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-d101.dts b/arch/arm64/boot/dts/apple/t8010-d101.dts new file mode 100644 index 00000000000000..6a9f0856f930ac --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-d101.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 7 (Intel), D101, iPhone9,3 (A1660/A1778/A1779/A1780) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010-7.dtsi" + +/ { + compatible = "apple,d101", "apple,t8010", "apple,arm-platform"; + model = "Apple iPhone 7 (Intel)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-d11.dts b/arch/arm64/boot/dts/apple/t8010-d11.dts new file mode 100644 index 00000000000000..57e41c2cfbe28a --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-d11.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 7 Plus (Qualcomm), D11, iPhone9,2 (A1661/A1784/A1785/A1786) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010-7.dtsi" + +/ { + compatible = "apple,d11", "apple,t8010", "apple,arm-platform"; + model = "Apple iPhone 7 Plus (Qualcomm)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-d111.dts b/arch/arm64/boot/dts/apple/t8010-d111.dts new file mode 100644 index 00000000000000..37e395a48c1df9 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-d111.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 7 Plus (Intel), D111, iPhone9,4 (A1661/A1784/A1785/A1786) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010-7.dtsi" + +/ { + compatible = "apple,d111", "apple,t8010", "apple,arm-platform"; + model = "Apple iPhone 7 Plus (Intel)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-ipad6.dtsi b/arch/arm64/boot/dts/apple/t8010-ipad6.dtsi new file mode 100644 index 00000000000000..81696c6e302c61 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-ipad6.dtsi @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 6 common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "t8010.dtsi" +#include "t8010-common.dtsi" +#include + +/ { + chassis-type = "tablet"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl_ap 180 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl_ap 179 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl_ap 89 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl_ap 90 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-ipad7.dtsi b/arch/arm64/boot/dts/apple/t8010-ipad7.dtsi new file mode 100644 index 00000000000000..bd0e9c0b5696fa --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-ipad7.dtsi @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 7 common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +/* + * The iPad 7 seems to be only an iteration over the iPad 6 with some + * small changes, like the a bigger screen and 1 GiB of RAM more, hence + * there is little to no differentiation between these 2 generations for + * now. + */ +#include "t8010-ipad6.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8010-j171.dts b/arch/arm64/boot/dts/apple/t8010-j171.dts new file mode 100644 index 00000000000000..6751bf3a4afdad --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-j171.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 7 (Wi-Fi), J171, iPad7,11 (A2197) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010-ipad7.dtsi" + +/ { + compatible = "apple,j171", "apple,t8010", "apple,arm-platform"; + model = "Apple iPad 7 (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-j172.dts b/arch/arm64/boot/dts/apple/t8010-j172.dts new file mode 100644 index 00000000000000..51aaa950acd90b --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-j172.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 7 (Cellular), J172, iPad7,12 (A2198/A2200) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010-ipad7.dtsi" + +/ { + compatible = "apple,j172", "apple,t8010", "apple,arm-platform"; + model = "Apple iPad 7 (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-j71b.dts b/arch/arm64/boot/dts/apple/t8010-j71b.dts new file mode 100644 index 00000000000000..534eb8413e08fe --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-j71b.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 6 (Wi-Fi), J71b, iPad7,5 (A1893) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010-ipad6.dtsi" + +/ { + compatible = "apple,j71b", "apple,t8010", "apple,arm-platform"; + model = "Apple iPad 6 (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-j72b.dts b/arch/arm64/boot/dts/apple/t8010-j72b.dts new file mode 100644 index 00000000000000..264924e41f4266 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-j72b.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad 6 (Cellular), J72b, iPad7,6 (A1954) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010-ipad6.dtsi" + +/ { + compatible = "apple,j72b", "apple,t8010", "apple,arm-platform"; + model = "Apple iPad 6 (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8010-n112.dts b/arch/arm64/boot/dts/apple/t8010-n112.dts new file mode 100644 index 00000000000000..6e71c3cb5d92b7 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010-n112.dts @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPod touch 7, N112, iPod9,1 (A2178) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8010.dtsi" +#include "t8010-common.dtsi" +#include + +/ { + compatible = "apple,n112", "apple,t8010", "apple,arm-platform"; + model = "Apple iPod touch 7"; + chassis-type = "handset"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl_ap 86 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl_ap 179 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl_ap 180 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl_ap 23 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8010.dtsi b/arch/arm64/boot/dts/apple/t8010.dtsi new file mode 100644 index 00000000000000..e3d6a835410384 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8010.dtsi @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Apple T8010 "A10" SoC + * + * Other names: H9P, "Cayman" + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include +#include +#include +#include + +/ { + interrupt-parent = <&aic>; + #address-cells = <2>; + #size-cells = <2>; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "apple,hurricane-zephyr"; + reg = <0x0 0x0>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu1: cpu@1 { + compatible = "apple,hurricane-zephyr"; + reg = <0x0 0x1>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + nonposted-mmio; + ranges; + + serial0: serial@20a0c0000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x0a0c0000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + aic: interrupt-controller@20e100000 { + compatible = "apple,t8010-aic", "apple,aic"; + reg = <0x2 0x0e100000 0x0 0x100000>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + pinctrl_ap: pinctrl@20f100000 { + compatible = "apple,t8010-pinctrl", "apple,pinctrl"; + reg = <0x2 0x0f100000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_ap 0 0 208>; + apple,npins = <208>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + pinctrl_aop: pinctrl@2100f0000 { + compatible = "apple,t8010-pinctrl", "apple,pinctrl"; + reg = <0x2 0x100f0000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aop 0 0 42>; + apple,npins = <42>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + wdt: watchdog@2102b0000 { + compatible = "apple,t8010-wdt", "apple,wdt"; + reg = <0x2 0x102b0000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt"; + /* Note that A10 doesn't actually have a hypervisor (EL2 is not implemented). */ + interrupts = , + ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8011-common.dtsi b/arch/arm64/boot/dts/apple/t8011-common.dtsi new file mode 100644 index 00000000000000..44a0d0ea2ee36e --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8011-common.dtsi @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple TV 4K, Apple iPad Pro 2 + * + * This file contains parts common to all Apple A10X devices. + * + * Copyright (c) 2024, Nick Chan + */ + +/ { + aliases { + serial0 = &serial0; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0 0>; /* To be filled by loader */ + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t8011-j105a.dts b/arch/arm64/boot/dts/apple/t8011-j105a.dts new file mode 100644 index 00000000000000..d3e5b69c67aa49 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8011-j105a.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple TV 4K (1st Generation), J105a, AppleTV6,2 (A1482) + * Copyright (c) 2024, Nick Chan + */ + +/dts-v1/; + +#include "t8011.dtsi" +#include "t8011-common.dtsi" + +/ { + compatible = "apple,j105a", "apple,t8011", "apple,arm-platform"; + model = "Apple TV 4K (1st Generation)"; + chassis-type = "television"; +}; diff --git a/arch/arm64/boot/dts/apple/t8011-j120.dts b/arch/arm64/boot/dts/apple/t8011-j120.dts new file mode 100644 index 00000000000000..1b49bb5c97c310 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8011-j120.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro 2 (12.9-inch) (Wi-Fi), J120, iPad7,1 (A1670) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8011.dtsi" +#include "t8011-common.dtsi" +#include "t8011-pro2.dtsi" + +/ { + compatible = "apple,j120", "apple,t8011", "apple,arm-platform"; + model = "Apple iPad Pro 2 (12.9-inch) (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8011-j121.dts b/arch/arm64/boot/dts/apple/t8011-j121.dts new file mode 100644 index 00000000000000..22f4aa1ecbda18 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8011-j121.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro 2 (12.9-inch) (Cellular), J121, iPad7,2 (A1671) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8011.dtsi" +#include "t8011-common.dtsi" +#include "t8011-pro2.dtsi" + +/ { + compatible = "apple,j121", "apple,t8011", "apple,arm-platform"; + model = "Apple iPad Pro 2 (12.9-inch) (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8011-j207.dts b/arch/arm64/boot/dts/apple/t8011-j207.dts new file mode 100644 index 00000000000000..c3384e2cad4499 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8011-j207.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro 2 (10.5-inch) (Wi-Fi), J207, iPad7,3 (A1701) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8011.dtsi" +#include "t8011-common.dtsi" +#include "t8011-pro2.dtsi" + +/ { + compatible = "apple,j207", "apple,t8011", "apple,arm-platform"; + model = "Apple iPad Pro 2 (10.5-inch) (Wi-Fi)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8011-j208.dts b/arch/arm64/boot/dts/apple/t8011-j208.dts new file mode 100644 index 00000000000000..251fa76efb6b28 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8011-j208.dts @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro 2 (10.5-inch) (Cellular), J208, iPad7,4 (A1709) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8011.dtsi" +#include "t8011-common.dtsi" +#include "t8011-pro2.dtsi" + +/ { + compatible = "apple,j208", "apple,t8011", "apple,arm-platform"; + model = "Apple iPad Pro 2 (10.5-inch) (Cellular)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8011-pro2.dtsi b/arch/arm64/boot/dts/apple/t8011-pro2.dtsi new file mode 100644 index 00000000000000..f4e7074150036c --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8011-pro2.dtsi @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPad Pro 2 common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include + +/ { + chassis-type = "tablet"; + + gpio-keys { + compatible = "gpio-keys"; + + button-home { + label = "Home Button"; + gpios = <&pinctrl_ap 139 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-power { + label = "Power Button"; + gpios = <&pinctrl_ap 138 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + + button-voldown { + label = "Volume Down"; + gpios = <&pinctrl_ap 43 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-volup { + label = "Volume Up"; + gpios = <&pinctrl_ap 40 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8011.dtsi b/arch/arm64/boot/dts/apple/t8011.dtsi new file mode 100644 index 00000000000000..6c4ed9dc4a504d --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8011.dtsi @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T8011 "A10X" SoC + * + * Other names: H9G, "Myst" + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include +#include +#include +#include + +/ { + interrupt-parent = <&aic>; + #address-cells = <2>; + #size-cells = <2>; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "apple,hurricane-zephyr"; + reg = <0x0 0x0>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu1: cpu@1 { + compatible = "apple,hurricane-zephyr"; + reg = <0x0 0x1>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu2: cpu@2 { + compatible = "apple,hurricane-zephyr"; + reg = <0x0 0x2>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + nonposted-mmio; + ranges; + + serial0: serial@20a0c0000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x0a0c0000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + aic: interrupt-controller@20e100000 { + compatible = "apple,t8010-aic", "apple,aic"; + reg = <0x2 0x0e100000 0x0 0x100000>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + pinctrl_ap: pinctrl@20f100000 { + compatible = "apple,t8010-pinctrl", "apple,pinctrl"; + reg = <0x2 0x0f100000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_ap 0 0 219>; + apple,npins = <219>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + pinctrl_aop: pinctrl@2100f0000 { + compatible = "apple,t8010-pinctrl", "apple,pinctrl"; + reg = <0x2 0x100f0000 0x0 0x100000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aop 0 0 42>; + apple,npins = <42>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + wdt: watchdog@2102b0000 { + compatible = "apple,t8010-wdt", "apple,wdt"; + reg = <0x2 0x102b0000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt"; + /* Note that A10X doesn't actually have a hypervisor (EL2 is not implemented). */ + interrupts = , + ; + }; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-8.dtsi b/arch/arm64/boot/dts/apple/t8015-8.dtsi new file mode 100644 index 00000000000000..b6505b5185bdd7 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-8.dtsi @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 8 common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "t8015.dtsi" +#include "t8015-common.dtsi" + +/ { + chassis-type = "handset"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-8plus.dtsi b/arch/arm64/boot/dts/apple/t8015-8plus.dtsi new file mode 100644 index 00000000000000..ea291a95f02867 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-8plus.dtsi @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 8 Plus common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +/* The 8 Plus has minor differences like 1 more camera, 1 GiB of RAM more and a bigger display. */ +#include "t8015-8.dtsi" diff --git a/arch/arm64/boot/dts/apple/t8015-common.dtsi b/arch/arm64/boot/dts/apple/t8015-common.dtsi new file mode 100644 index 00000000000000..69258a33ea5008 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-common.dtsi @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 8, iPhone 8 Plus, iPhone X + * + * This file contains parts common to all Apple A11 devices. + * + * target-type: D20, D21, D22, D201, D211, D221 + * + * Copyright (c) 2024, Nick Chan + */ + +/ { + aliases { + serial0 = &serial0; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0 0>; /* To be filled by loader */ + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-d20.dts b/arch/arm64/boot/dts/apple/t8015-d20.dts new file mode 100644 index 00000000000000..35d79e2ceebcdc --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-d20.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 8 (Global), D20 iPhone10,1 (A1863/A1906/A1907) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8015-8.dtsi" + +/ { + compatible = "apple,d20", "apple,t8015", "apple,arm-platform"; + model = "Apple iPhone 8 (Global)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-d201.dts b/arch/arm64/boot/dts/apple/t8015-d201.dts new file mode 100644 index 00000000000000..31e0947fee707d --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-d201.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 8 (GSM), D20 iPhone10,4 (A1905) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8015-8.dtsi" + +/ { + compatible = "apple,d201", "apple,t8015", "apple,arm-platform"; + model = "Apple iPhone 8 (GSM)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-d21.dts b/arch/arm64/boot/dts/apple/t8015-d21.dts new file mode 100644 index 00000000000000..a902ba7f11337b --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-d21.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 8 Plus (Global), D21 iPhone10,2 (A1864/A1897/A1898) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8015-8plus.dtsi" + +/ { + compatible = "apple,d21", "apple,t8015", "apple,arm-platform"; + model = "Apple iPhone 8 Plus (Global)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-d211.dts b/arch/arm64/boot/dts/apple/t8015-d211.dts new file mode 100644 index 00000000000000..3b3f886c0c0902 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-d211.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone 8 Plus (GSM), D211 iPhone10,5 (A1899) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8015-8plus.dtsi" + +/ { + compatible = "apple,d211", "apple,t8015", "apple,arm-platform"; + model = "Apple iPhone 8 Plus (GSM)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-d22.dts b/arch/arm64/boot/dts/apple/t8015-d22.dts new file mode 100644 index 00000000000000..5a7a6092c2d029 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-d22.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone X (Global), D22, iPhone10,3 (A1865) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8015-x.dtsi" + +/ { + compatible = "apple,d22", "apple,t8015", "apple,arm-platform"; + model = "Apple iPhone X (Global)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-d221.dts b/arch/arm64/boot/dts/apple/t8015-d221.dts new file mode 100644 index 00000000000000..dd920c945bd61e --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-d221.dts @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone X (GSM), D221, iPhone10,6 (A1901) + * Copyright (c) 2022, Konrad Dybcio + */ + +/dts-v1/; + +#include "t8015-x.dtsi" + +/ { + compatible = "apple,d221", "apple,t8015", "apple,arm-platform"; + model = "Apple iPhone X (GSM)"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015-x.dtsi b/arch/arm64/boot/dts/apple/t8015-x.dtsi new file mode 100644 index 00000000000000..41134ed40b89d8 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015-x.dtsi @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple iPhone X common device tree + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include "t8015.dtsi" +#include "t8015-common.dtsi" + +/ { + chassis-type = "handset"; +}; diff --git a/arch/arm64/boot/dts/apple/t8015.dtsi b/arch/arm64/boot/dts/apple/t8015.dtsi new file mode 100644 index 00000000000000..8828d830e5be6f --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8015.dtsi @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple T8015 "A11" SoC + * + * Other names: H10, "Skye" + * + * Copyright (c) 2022, Konrad Dybcio + */ + +#include +#include +#include +#include + +/ { + interrupt-parent = <&aic>; + #address-cells = <2>; + #size-cells = <2>; + + clkref: clock-ref { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "clkref"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu_e0>; + }; + core1 { + cpu = <&cpu_e1>; + }; + core2 { + cpu = <&cpu_e2>; + }; + core3 { + cpu = <&cpu_e3>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu_p0>; + }; + core1 { + cpu = <&cpu_p1>; + }; + }; + }; + + cpu_e0: cpu@0 { + compatible = "apple,mistral"; + reg = <0x0 0x0>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu_e1: cpu@1 { + compatible = "apple,mistral"; + reg = <0x0 0x1>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu_e2: cpu@2 { + compatible = "apple,mistral"; + reg = <0x0 0x2>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu_e3: cpu@3 { + compatible = "apple,mistral"; + reg = <0x0 0x3>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu_p0: cpu@10004 { + compatible = "apple,monsoon"; + reg = <0x0 0x10004>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + + cpu_p1: cpu@10005 { + compatible = "apple,monsoon"; + reg = <0x0 0x10005>; + cpu-release-addr = <0 0>; /* To be filled by loader */ + enable-method = "spin-table"; + device_type = "cpu"; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + nonposted-mmio; + ranges; + + serial0: serial@22e600000 { + compatible = "apple,s5l-uart"; + reg = <0x2 0x2e600000 0x0 0x4000>; + reg-io-width = <4>; + interrupt-parent = <&aic>; + interrupts = ; + /* Use the bootloader-enabled clocks for now. */ + clocks = <&clkref>, <&clkref>; + clock-names = "uart", "clk_uart_baud0"; + status = "disabled"; + }; + + aic: interrupt-controller@232100000 { + compatible = "apple,t8015-aic", "apple,aic"; + reg = <0x2 0x32100000 0x0 0x8000>; + #interrupt-cells = <3>; + interrupt-controller; + }; + + pinctrl_ap: pinctrl@233100000 { + compatible = "apple,t8015-pinctrl", "apple,pinctrl"; + reg = <0x2 0x33100000 0x0 0x1000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_ap 0 0 223>; + apple,npins = <223>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + pinctrl_aop: pinctrl@2340f0000 { + compatible = "apple,t8015-pinctrl", "apple,pinctrl"; + reg = <0x2 0x340f0000 0x0 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_aop 0 0 49>; + apple,npins = <49>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + }; + + pinctrl_nub: pinctrl@2351f0000 { + compatible = "apple,t8015-pinctrl", "apple,pinctrl"; + reg = <0x2 0x351f0000 0x0 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_nub 0 0 8>; + apple,npins = <8>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + ; + }; + + wdt: watchdog@2352b0000 { + compatible = "apple,t8015-wdt", "apple,wdt"; + reg = <0x2 0x352b0000 0x0 0x4000>; + clocks = <&clkref>; + interrupt-parent = <&aic>; + interrupts = ; + }; + + pinctrl_smc: pinctrl@236024000 { + compatible = "apple,t8015-pinctrl", "apple,pinctrl"; + reg = <0x2 0x36024000 0x0 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_smc 0 0 6>; + apple,npins = <6>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&aic>; + interrupts = , + , + , + , + , + , + ; + /* + * SMC is not yet supported and accessing this pinctrl while SMC is + * suspended results in a hang. + */ + status = "disabled"; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&aic>; + interrupt-names = "phys", "virt"; + /* Note that A11 doesn't actually have a hypervisor (EL2 is not implemented). */ + interrupts = , + ; + }; +}; diff --git a/arch/arm64/boot/dts/arm/fvp-base-revc.dts b/arch/arm64/boot/dts/arm/fvp-base-revc.dts index 19973ab4ea6b53..9e10d7a6b5a2ce 100644 --- a/arch/arm64/boot/dts/arm/fvp-base-revc.dts +++ b/arch/arm64/boot/dts/arm/fvp-base-revc.dts @@ -233,7 +233,7 @@ pci: pci@40000000 { #interrupt-cells = <0x1>; compatible = "pci-host-ecam-generic"; device_type = "pci"; - bus-range = <0x0 0x1>; + bus-range = <0x0 0xff>; reg = <0x0 0x40000000 0x0 0x10000000>; ranges = <0x2000000 0x0 0x50000000 0x0 0x50000000 0x0 0x10000000>; interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>, diff --git a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi index 6e5a984c1d4ea1..26a29e5e5078d5 100644 --- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi @@ -67,7 +67,7 @@ cpu0: cpu@0 { l2_cache_l0: l2-cache-l0 { compatible = "cache"; cache-size = <0x80000>; - cache-line-size = <128>; + cache-line-size = <64>; cache-sets = <1024>; //512KiB(size)/64(line-size)=8192ways/8-way set cache-level = <2>; cache-unified; @@ -91,7 +91,7 @@ cpu1: cpu@1 { l2_cache_l1: l2-cache-l1 { compatible = "cache"; cache-size = <0x80000>; - cache-line-size = <128>; + cache-line-size = <64>; cache-sets = <1024>; //512KiB(size)/64(line-size)=8192ways/8-way set cache-level = <2>; cache-unified; @@ -115,7 +115,7 @@ cpu2: cpu@2 { l2_cache_l2: l2-cache-l2 { compatible = "cache"; cache-size = <0x80000>; - cache-line-size = <128>; + cache-line-size = <64>; cache-sets = <1024>; //512KiB(size)/64(line-size)=8192ways/8-way set cache-level = <2>; cache-unified; @@ -139,7 +139,7 @@ cpu3: cpu@3 { l2_cache_l3: l2-cache-l3 { compatible = "cache"; cache-size = <0x80000>; - cache-line-size = <128>; + cache-line-size = <64>; cache-sets = <1024>; //512KiB(size)/64(line-size)=8192ways/8-way set cache-level = <2>; cache-unified; diff --git a/arch/arm64/boot/dts/exynos/Makefile b/arch/arm64/boot/dts/exynos/Makefile index d7f2191c2cdbe9..7a934499b23589 100644 --- a/arch/arm64/boot/dts/exynos/Makefile +++ b/arch/arm64/boot/dts/exynos/Makefile @@ -7,5 +7,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += \ exynos7-espresso.dtb \ exynos7885-jackpotlte.dtb \ exynos850-e850-96.dtb \ + exynos8895-dreamlte.dtb \ + exynos990-c1s.dtb \ exynosautov9-sadk.dtb \ exynosautov920-sadk.dtb diff --git a/arch/arm64/boot/dts/exynos/exynos8895-dreamlte.dts b/arch/arm64/boot/dts/exynos/exynos8895-dreamlte.dts new file mode 100644 index 00000000000000..3a376ab2bb9ee4 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynos8895-dreamlte.dts @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Samsung Galaxy S8 (dreamlte/SM-G950F) device tree source + * + * Copyright (c) 2024, Ivaylo Ivanov + */ + +/dts-v1/; +#include "exynos8895.dtsi" +#include +#include +#include + +/ { + model = "Samsung Galaxy S8 (SM-G950F)"; + compatible = "samsung,dreamlte", "samsung,exynos8895"; + chassis-type = "handset"; + + chosen { + #address-cells = <2>; + #size-cells = <1>; + ranges; + + framebuffer: framebuffer@cc000000 { + compatible = "simple-framebuffer"; + reg = <0 0xcc000000 (1440 * 2960 * 4)>; + width = <1440>; + height = <2960>; + stride = <(1440 * 4)>; + format = "a8r8g8b8"; + }; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x3c800000>, + <0x0 0xc0000000 0x40000000>, + <0x8 0x80000000 0x80000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <1>; + ranges; + + ramoops@92000000 { + compatible = "ramoops"; + reg = <0 0x92000000 0x8000>; + record-size = <0x4000>; + console-size = <0x4000>; + }; + + cont_splash_mem: framebuffer@cc000000 { + reg = <0 0xcc000000 (1440 * 2960 * 4)>; + no-map; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&key_power &key_voldown &key_volup &key_wink>; + pinctrl-names = "default"; + + power-key { + label = "Power"; + linux,code = ; + gpios = <&gpa2 4 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + voldown-key { + label = "Volume Down"; + linux,code = ; + gpios = <&gpa0 4 GPIO_ACTIVE_LOW>; + }; + + volup-key { + label = "Volume Up"; + linux,code = ; + gpios = <&gpa0 3 GPIO_ACTIVE_LOW>; + }; + + /* Typically used for Bixby. Map it as a camera button for now */ + wink-key { + label = "Camera"; + linux,code = ; + gpios = <&gpa0 6 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; +}; + +&oscclk { + clock-frequency = <26000000>; +}; + +&pinctrl_alive { + key_power: key-power-pins { + samsung,pins = "gpa2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + key_voldown: key-voldown-pins { + samsung,pins = "gpa0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + key_volup: key-volup-pins { + samsung,pins = "gpa0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + key_wink: key-wink-pins { + samsung,pins = "gpa0-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; diff --git a/arch/arm64/boot/dts/exynos/exynos8895-pinctrl.dtsi b/arch/arm64/boot/dts/exynos/exynos8895-pinctrl.dtsi new file mode 100644 index 00000000000000..51e9c9c4b16681 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynos8895-pinctrl.dtsi @@ -0,0 +1,1094 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Samsung's Exynos 8895 SoC pin-mux and pin-config device tree source + * + * Copyright (c) 2024, Ivaylo Ivanov + */ + +#include +#include "exynos-pinctrl.h" + +&pinctrl_abox { + gph0: gph0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph1: gph1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph3: gph3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_alive { + gpa0: gpa0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa1: gpa1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa2: gpa2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpa3: gpa3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpa4: gpa4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + }; + + bt_hostwake: bt-hostwake-pins { + samsung,pins = "gpa2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + pcie_wake: pcie-wake-pins { + samsung,pins = "gpa3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart1_bus: uart1-bus-pins { + samsung,pins = "gpa4-4", "gpa4-3", "gpa4-2", "gpa4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + wlan_host_wake: wlan-host-wake-pins { + samsung,pins = "gpa0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; +}; + +&pinctrl_busc { + gpb2: gpb2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + hsi2c0_bus: hsi2c0-bus-pins { + samsung,pins = "gpb2-1", "gpb2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + speedy_bus: speedy-bus-pins { + samsung,pins = "gpb2-0"; + samsung,pin-function = ; + samsung,pin-con-pdn = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + +&pinctrl_fsys0 { + gpi0: gpi0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpi1: gpi1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + ufs_rst_n: ufs-rst-n-pins { + samsung,pins = "gpi0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + ufs_refclk_out: ufs-refclk-out-pins { + samsung,pins = "gpi0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; +}; + +&pinctrl_fsys1 { + gpj0: gpj0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpj1: gpj1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + bt_btwake: bt-btwake-pins { + samsung,pins = "gpj1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + bt_en: bt-en-pins { + samsung,pins ="gpj1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + cfg_wlanen: cfg-wlanen-pins { + samsung,pins = "gpj1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + }; + + sd2_clk: sd2-clk-pins { + samsung,pins = "gpj0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_cmd: sd2-cmd-pins { + samsung,pins = "gpj0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_bus1: sd2-bus-width1-pins { + samsung,pins = "gpj0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_bus4: sd2-bus-width4-pins { + samsung,pins = "gpj0-3", "gpj0-4", "gpj0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + /* For Drive strength swapping */ + sd2_clk_fast_slew_rate_1x: sd2-clk-fast-slew-rate-1x-pins { + samsung,pins = "gpj0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_2x: sd2-clk-fast-slew-rate-2x-pins { + samsung,pins = "gpj0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_3x: sd2-clk-fast-slew-rate-3x-pins { + samsung,pins = "gpj0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_4x: sd2-clk-fast-slew-rate-4x-pins { + samsung,pins = "gpj0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + +&pinctrl_peric0 { + gpb1: gpb1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpd0: gpd0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpd1: gpd1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpd2: gpd2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpd3: gpd3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe7: gpe7-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpf1: gpf1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + hsi2c5_bus: hsi2c5-bus-pins { + samsung,pins = "gpd1-1", "gpd1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c6_bus: hsi2c6-bus-pins { + samsung,pins = "gpd1-3", "gpd1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c7_bus: hsi2c7-bus-pins { + samsung,pins = "gpd1-5", "gpd1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c8_bus: hsi2c8-bus-pins { + samsung,pins = "gpd1-7", "gpd1-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c9_bus: hsi2c9-bus-pins { + samsung,pins = "gpd2-1", "gpd2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c10_bus: hsi2c10-bus-pins { + samsung,pins = "gpd2-3", "gpd2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c11_bus: hsi2c11-bus-pins { + samsung,pins = "gpd3-1", "gpd3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c12_bus: hsi2c12-bus-pins { + samsung,pins = "gpd3-3", "gpd3-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hs_i2c14_bus: hs-i2c14-bus-pins { + samsung,pins = "gpe6-3", "gpe6-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi2_bus: spi2-bus-pins { + samsung,pins = "gpd1-3", "gpd1-2", "gpd1-1", "gpd1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi2_cs: spi2-cs-pins { + samsung,pins = "gpd1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi3_bus: spi3-bus-pins { + samsung,pins = "gpd1-7", "gpd1-5", "gpd1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi3_cs: spi3-cs-pins { + samsung,pins = "gpd1-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_bus: spi4-bus-pins { + samsung,pins = "gpd2-3", "gpd2-1", "gpd2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_cs: spi4-cs-pins { + samsung,pins = "gpd2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi5_bus: spi5-bus-pins { + samsung,pins = "gpd3-3", "gpd3-1", "gpd3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi5_cs: spi5-cs-pins { + samsung,pins = "gpd3-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart0_bus: uart0-bus-pins { + samsung,pins = "gpd0-7", "gpd0-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart2_bus: uart2-bus-pins { + samsung,pins = "gpd1-3", "gpd1-2", "gpd1-1", "gpd1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart2_bus_dual: uart2-bus-dual-pins { + samsung,pins = "gpd1-1", "gpd1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart3_bus: uart3-bus-pins { + samsung,pins = "gpd1-7", "gpd1-6", "gpd1-5", "gpd1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart3_bus_dual: uart3-bus-dual-pins { + samsung,pins = "gpd1-5", "gpd1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart4_bus: uart4-bus-pins { + samsung,pins = "gpd2-3", "gpd2-2", "gpd2-1", "gpd2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart4_bus_dual: uart4-bus-dual-pins { + samsung,pins = "gpd2-1", "gpd2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart5_bus: uart5-bus-pins { + samsung,pins = "gpd3-3", "gpd3-2", "gpd3-1", "gpd3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart5_bus_dual: uart5-bus-dual-pins { + samsung,pins = "gpd3-1", "gpd3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_peric1 { + gpb0: gpb0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc0: gpc0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc1: gpc1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc2: gpc2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc3: gpc3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe1: gpe1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe2: gpe2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe3: gpe3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe4: gpe4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe5: gpe5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpe6: gpe6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpf0: gpf0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg0: gpg0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpk0: gpk0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + hrm_irq: hrm-irq-pins { + samsung,pins = "gpe6-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c1_bus: hsi2c1-bus-pins { + samsung,pins = "gpc2-1", "gpc2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c2_bus: hsi2c2-bus-pins { + samsung,pins = "gpc2-3", "gpc2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c3_bus: hsi2c3-bus-pins { + samsung,pins = "gpc2-5", "gpc2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c4_bus: hsi2c4-bus-pins { + samsung,pins = "gpc2-7", "gpc2-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c13_bus: hsi2c13-bus-pins { + samsung,pins = "gpe5-1", "gpe5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c14_bus: hsi2c14-bus-pins { + samsung,pins = "gpe5-3", "gpe5-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c15_bus: hsi2c15-bus-pins { + samsung,pins = "gpe1-1", "gpe1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c16_bus: hsi2c16-bus-pins { + samsung,pins = "gpe1-3", "gpe1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c17_bus: hsi2c17-bus-pins { + samsung,pins = "gpe1-5", "gpe1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c18_bus: hsi2c18-bus-pins { + samsung,pins = "gpe1-7", "gpe1-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c19_bus: hsi2c19-bus-pins { + samsung,pins = "gpe2-1", "gpe2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c20_bus: hsi2c20-bus-pins { + samsung,pins = "gpe2-3", "gpe2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c21_bus: hsi2c21-bus-pins { + samsung,pins = "gpe2-5", "gpe2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c22_bus: hsi2c22-bus-pins { + samsung,pins = "gpe2-7", "gpe2-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c23_bus: hsi2c23-bus-pins { + samsung,pins = "gpe3-1", "gpe3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c24_bus: hsi2c24-bus-pins { + samsung,pins = "gpe3-3", "gpe3-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c25_bus: hsi2c25-bus-pins { + samsung,pins = "gpe3-5", "gpe3-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c26_bus: hsi2c26-bus-pins { + samsung,pins = "gpe3-7", "gpe3-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c27_bus: hsi2c27-bus-pins { + samsung,pins = "gpe4-1", "gpe4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c28_bus: hsi2c28-bus-pins { + samsung,pins = "gpe4-3", "gpe4-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c29_bus: hsi2c29-bus-pins { + samsung,pins = "gpe4-5", "gpe4-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c30_bus: hsi2c30-bus-pins { + samsung,pins = "gpe4-7", "gpe4-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c31_bus: hsi2c31-bus-pins { + samsung,pins = "gpe5-5", "gpe5-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c32_bus: hsi2c32-bus-pins { + samsung,pins = "gpe5-7", "gpe5-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi0_bus: spi0-bus-pins { + samsung,pins = "gpc3-3", "gpc3-2", "gpc3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi0_cs: spi0-cs-pins { + samsung,pins = "gpc3-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi1_bus: spi1-bus-pins { + samsung,pins = "gpc3-7", "gpc3-6", "gpc3-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi1_cs: spi1-cs-pins { + samsung,pins = "gpc3-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi6_bus: spi6-bus-pins { + samsung,pins = "gpe5-3", "gpe5-1", "gpe5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi6_cs: spi6-cs-pins { + samsung,pins = "gpe5-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi7_bus: spi7-bus-pins { + samsung,pins = "gpe1-3", "gpe1-1", "gpe1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi7_cs: spi7-cs-pins { + samsung,pins = "gpe1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi8_bus: spi8-bus-pins { + samsung,pins = "gpe1-7", "gpe1-5", "gpe1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi8_cs: spi8-cs-pins { + samsung,pins = "gpe1-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi9_bus: spi9-bus-pins { + samsung,pins = "gpe2-3", "gpe2-1", "gpe2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi9_cs: spi9-cs-pins { + samsung,pins = "gpe2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi10_bus: spi10-bus-pins { + samsung,pins = "gpe2-7", "gpe2-5", "gpe2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi10_cs: spi10-cs-pins { + samsung,pins = "gpe2-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi11_bus: spi11-bus-pins { + samsung,pins = "gpe3-3", "gpe3-1", "gpe3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi11_cs: spi11-cs-pins { + samsung,pins = "gpe3-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi12_bus: spi12-bus-pins { + samsung,pins = "gpe3-7", "gpe3-5", "gpe3-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi12_cs: spi12-cs-pins { + samsung,pins = "gpe3-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi13_bus: spi13-bus-pins { + samsung,pins = "gpe4-3", "gpe4-1", "gpe4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi13_cs: spi13-cs-pins { + samsung,pins = "gpe4-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi14_bus: spi14-bus-pins { + samsung,pins = "gpe4-7", "gpe4-5", "gpe4-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi14_cs: spi14-cs-pins { + samsung,pins = "gpe4-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi15_bus: spi15-bus-pins { + samsung,pins = "gpe5-7", "gpe5-5", "gpe5-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi15_cs: spi15-cs-pins { + samsung,pins = "gpe5-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart6_bus: uart6-bus-pins { + samsung,pins = "gpe5-3", "gpe5-2", "gpe5-1", "gpe5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart6_bus_dual: uart6-bus-dual-pins { + samsung,pins = "gpe5-1", "gpe5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart7_bus: uart7-bus-pins { + samsung,pins = "gpe1-3", "gpe1-2", "gpe1-1", "gpe1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart7_bus_dual: uart7-bus-dual-pins { + samsung,pins = "gpe1-1", "gpe1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart8_bus: uart8-bus-pins { + samsung,pins = "gpe1-7", "gpe1-6", "gpe1-5", "gpe1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart8_bus_dual: uart8-bus-dual-pins { + samsung,pins = "gpe1-5", "gpe1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart9_bus: uart9-bus-pins { + samsung,pins = "gpe2-3", "gpe2-2", "gpe2-1", "gpe2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart9_bus_dual: uart9-bus-dual-pins { + samsung,pins = "gpe2-1", "gpe2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart10_bus: uart10-bus-pins { + samsung,pins = "gpe2-7", "gpe2-6", "gpe2-5", "gpe2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart10_bus_dual: uart10-bus-dual-pins { + samsung,pins = "gpe2-5", "gpe2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart11_bus: uart11-bus-pins { + samsung,pins = "gpe3-3", "gpe3-2", "gpe3-1", "gpe3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart11_bus_dual: uart11-bus-dual-pins { + samsung,pins = "gpe3-1", "gpe3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart12_bus: uart12-bus-pins { + samsung,pins = "gpe3-7", "gpe3-6", "gpe3-5", "gpe3-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart12_bus_dual: uart12-bus-dual-pins { + samsung,pins = "gpe3-5", "gpe3-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart13_bus: uart13-bus-pins { + samsung,pins = "gpe4-3", "gpe4-2", "gpe4-1", "gpe4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart13_bus_dual: uart13-bus-dual-pins { + samsung,pins = "gpe4-1", "gpe4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart14_bus: uart14-bus-pins { + samsung,pins = "gpe4-7", "gpe4-6", "gpe4-5", "gpe4-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart14_bus_dual: uart14-bus-dual-pins { + samsung,pins = "gpe4-5", "gpe4-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart15_bus: uart15-bus-pins { + samsung,pins = "gpe5-7", "gpe5-6", "gpe5-5", "gpe5-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart15_bus_dual: uart15-bus-dual-pins { + samsung,pins = "gpe5-5", "gpe5-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_vts { + gph2: gph2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/exynos/exynos8895.dtsi b/arch/arm64/boot/dts/exynos/exynos8895.dtsi new file mode 100644 index 00000000000000..9f9ac53598796c --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynos8895.dtsi @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Samsung's Exynos 8895 SoC device tree source + * + * Copyright (c) 2024, Ivaylo Ivanov + */ + +#include +#include + +/ { + compatible = "samsung,exynos8895"; + #address-cells = <2>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + aliases { + pinctrl0 = &pinctrl_alive; + pinctrl1 = &pinctrl_abox; + pinctrl2 = &pinctrl_vts; + pinctrl3 = &pinctrl_fsys0; + pinctrl4 = &pinctrl_fsys1; + pinctrl5 = &pinctrl_busc; + pinctrl6 = &pinctrl_peric0; + pinctrl7 = &pinctrl_peric1; + }; + + arm-a53-pmu { + compatible = "arm,cortex-a53-pmu"; + interrupts = , + , + , + ; + interrupt-affinity = <&cpu0>, + <&cpu1>, + <&cpu2>, + <&cpu3>; + }; + + /* There's no PMU model for the Mongoose cores */ + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + core1 { + cpu = <&cpu1>; + }; + core2 { + cpu = <&cpu2>; + }; + core3 { + cpu = <&cpu3>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu4>; + }; + core1 { + cpu = <&cpu5>; + }; + core2 { + cpu = <&cpu6>; + }; + core3 { + cpu = <&cpu7>; + }; + }; + }; + + cpu4: cpu@0 { + device_type = "cpu"; + compatible = "samsung,mongoose-m2"; + reg = <0x0>; + enable-method = "psci"; + }; + + cpu5: cpu@1 { + device_type = "cpu"; + compatible = "samsung,mongoose-m2"; + reg = <0x1>; + enable-method = "psci"; + }; + + cpu6: cpu@2 { + device_type = "cpu"; + compatible = "samsung,mongoose-m2"; + reg = <0x2>; + enable-method = "psci"; + }; + + cpu7: cpu@3 { + device_type = "cpu"; + compatible = "samsung,mongoose-m2"; + reg = <0x3>; + enable-method = "psci"; + }; + + cpu0: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x100>; + enable-method = "psci"; + }; + + cpu1: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x101>; + enable-method = "psci"; + }; + + cpu2: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x102>; + enable-method = "psci"; + }; + + cpu3: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x103>; + enable-method = "psci"; + }; + }; + + oscclk: osc-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "oscclk"; + }; + + psci { + compatible = "arm,psci"; + method = "smc"; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + cpu_suspend = <0xc4000001>; + }; + + soc: soc@0 { + compatible = "simple-bus"; + ranges = <0x0 0x0 0x0 0x20000000>; + + #address-cells = <1>; + #size-cells = <1>; + + chipid@10000000 { + compatible = "samsung,exynos8895-chipid", + "samsung,exynos850-chipid"; + reg = <0x10000000 0x24>; + }; + + cmu_peris: clock-controller@10010000 { + compatible = "samsung,exynos8895-cmu-peris"; + reg = <0x10010000 0x8000>; + #clock-cells = <1>; + clocks = <&oscclk>, + <&cmu_top CLK_DOUT_CMU_PERIS_BUS>; + clock-names = "oscclk", "bus"; + }; + + timer@10040000 { + compatible = "samsung,exynos8895-mct", + "samsung,exynos4210-mct"; + reg = <0x10040000 0x800>; + clocks = <&oscclk>, <&cmu_peris CLK_GOUT_PERIS_MCT_PCLK>; + clock-names = "fin_pll", "mct"; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + }; + + gic: interrupt-controller@10201000 { + compatible = "arm,gic-400"; + reg = <0x10201000 0x1000>, + <0x10202000 0x1000>, + <0x10204000 0x2000>, + <0x10206000 0x2000>; + #interrupt-cells = <3>; + interrupt-controller; + interrupts = ; + #address-cells = <0>; + #size-cells = <1>; + }; + + cmu_peric0: clock-controller@10400000 { + compatible = "samsung,exynos8895-cmu-peric0"; + reg = <0x10400000 0x8000>; + #clock-cells = <1>; + clocks = <&oscclk>, + <&cmu_top CLK_DOUT_CMU_PERIC0_BUS>, + <&cmu_top CLK_DOUT_CMU_PERIC0_UART_DBG>, + <&cmu_top CLK_DOUT_CMU_PERIC0_USI00>, + <&cmu_top CLK_DOUT_CMU_PERIC0_USI01>, + <&cmu_top CLK_DOUT_CMU_PERIC0_USI02>, + <&cmu_top CLK_DOUT_CMU_PERIC0_USI03>; + clock-names = "oscclk", "bus", "uart", "usi0", + "usi1", "usi2", "usi3"; + }; + + pinctrl_peric0: pinctrl@104d0000 { + compatible = "samsung,exynos8895-pinctrl"; + reg = <0x104d0000 0x1000>; + interrupts = ; + }; + + cmu_peric1: clock-controller@10800000 { + compatible = "samsung,exynos8895-cmu-peric1"; + reg = <0x10800000 0x8000>; + #clock-cells = <1>; + clocks = <&oscclk>, + <&cmu_top CLK_DOUT_CMU_PERIC1_BUS>, + <&cmu_top CLK_DOUT_CMU_PERIC1_SPEEDY2>, + <&cmu_top CLK_DOUT_CMU_PERIC1_SPI_CAM0>, + <&cmu_top CLK_DOUT_CMU_PERIC1_SPI_CAM1>, + <&cmu_top CLK_DOUT_CMU_PERIC1_UART_BT>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI04>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI05>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI06>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI07>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI08>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI09>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI10>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI11>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI12>, + <&cmu_top CLK_DOUT_CMU_PERIC1_USI13>; + clock-names = "oscclk", "bus", "speedy", "cam0", + "cam1", "uart", "usi4", "usi5", + "usi6", "usi7", "usi8", "usi9", + "usi10", "usi11", "usi12", "usi13"; + }; + + pinctrl_peric1: pinctrl@10980000 { + compatible = "samsung,exynos8895-pinctrl"; + reg = <0x10980000 0x1000>; + interrupts = ; + }; + + spi_0: spi@109d0000 { + compatible = "samsung,exynos8895-spi", + "samsung,exynos850-spi"; + reg = <0x109d0000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cmu_peric1 CLK_GOUT_PERIC1_SPI_CAM0_PCLK>, + <&cmu_peric1 CLK_GOUT_PERIC1_SPI_CAM0_SPI_EXT_CLK>; + clock-names = "spi", "spi_busclk0"; + interrupts = ; + pinctrl-0 = <&spi0_bus>; + pinctrl-names = "default"; + status = "disabled"; + }; + + spi_1: spi@109e0000 { + compatible = "samsung,exynos8895-spi", + "samsung,exynos850-spi"; + reg = <0x109e0000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&cmu_peric1 CLK_GOUT_PERIC1_SPI_CAM1_PCLK>, + <&cmu_peric1 CLK_GOUT_PERIC1_SPI_CAM1_SPI_EXT_CLK>; + clock-names = "spi", "spi_busclk0"; + interrupts = ; + pinctrl-0 = <&spi1_bus>; + pinctrl-names = "default"; + status = "disabled"; + }; + + cmu_fsys0: clock-controller@11000000 { + compatible = "samsung,exynos8895-cmu-fsys0"; + reg = <0x11000000 0x8000>; + #clock-cells = <1>; + clocks = <&oscclk>, + <&cmu_top CLK_DOUT_CMU_FSYS0_BUS>, + <&cmu_top CLK_DOUT_CMU_FSYS0_DPGTC>, + <&cmu_top CLK_DOUT_CMU_FSYS0_MMC_EMBD>, + <&cmu_top CLK_DOUT_CMU_FSYS0_UFS_EMBD>, + <&cmu_top CLK_DOUT_CMU_FSYS0_USBDRD30>; + clock-names = "oscclk", "bus", "dpgtc", "mmc", + "ufs", "usbdrd30"; + }; + + pinctrl_fsys0: pinctrl@11050000 { + compatible = "samsung,exynos8895-pinctrl"; + reg = <0x11050000 0x1000>; + interrupts = ; + }; + + cmu_fsys1: clock-controller@11400000 { + compatible = "samsung,exynos8895-cmu-fsys1"; + reg = <0x11400000 0x8000>; + #clock-cells = <1>; + clocks = <&oscclk>, + <&cmu_top CLK_DOUT_CMU_FSYS1_BUS>, + <&cmu_top CLK_DOUT_CMU_FSYS1_PCIE>, + <&cmu_top CLK_DOUT_CMU_FSYS1_UFS_CARD>, + <&cmu_top CLK_DOUT_CMU_FSYS1_MMC_CARD>; + clock-names = "oscclk", "bus", "pcie", "ufs", "mmc"; + }; + + pinctrl_fsys1: pinctrl@11430000 { + compatible = "samsung,exynos8895-pinctrl"; + reg = <0x11430000 0x1000>; + interrupts = ; + }; + + pinctrl_abox: pinctrl@13e60000 { + compatible = "samsung,exynos8895-pinctrl"; + reg = <0x13e60000 0x1000>; + }; + + pinctrl_vts: pinctrl@14080000 { + compatible = "samsung,exynos8895-pinctrl"; + reg = <0x14080000 0x1000>; + }; + + pinctrl_busc: pinctrl@15a30000 { + compatible = "samsung,exynos8895-pinctrl"; + reg = <0x15a30000 0x1000>; + interrupts = ; + }; + + cmu_top: clock-controller@15a80000 { + compatible = "samsung,exynos8895-cmu-top"; + reg = <0x15a80000 0x8000>; + #clock-cells = <1>; + clocks = <&oscclk>; + clock-names = "oscclk"; + }; + + pmu_system_controller: system-controller@16480000 { + compatible = "samsung,exynos8895-pmu", + "samsung,exynos7-pmu", "syscon"; + reg = <0x16480000 0x10000>; + }; + + pinctrl_alive: pinctrl@164b0000 { + compatible = "samsung,exynos8895-pinctrl"; + reg = <0x164b0000 0x1000>; + + wakeup-interrupt-controller { + compatible = "samsung,exynos8895-wakeup-eint", + "samsung,exynos7-wakeup-eint"; + interrupt-parent = <&gic>; + interrupts = ; + }; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + /* Hypervisor Virtual Timer interrupt is not wired to GIC */ + interrupts = , + , + , + ; + /* + * Non-updatable, broken stock Samsung bootloader does not + * configure CNTFRQ_EL0 + */ + clock-frequency = <26000000>; + }; +}; + +#include "exynos8895-pinctrl.dtsi" +#include "arm/samsung/exynos-syscon-restart.dtsi" diff --git a/arch/arm64/boot/dts/exynos/exynos990-c1s.dts b/arch/arm64/boot/dts/exynos/exynos990-c1s.dts new file mode 100644 index 00000000000000..36a6f1377e92b4 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynos990-c1s.dts @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Samsung Galaxy Note20 5G (c1s/SM-N981B) device tree source + * + * Copyright (c) 2024, Igor Belwon + */ + +/dts-v1/; +#include "exynos990.dtsi" +#include +#include +#include + +/ { + model = "Samsung Galaxy Note20"; + compatible = "samsung,c1s", "samsung,exynos990"; + + #address-cells = <2>; + #size-cells = <2>; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + framebuffer0: framebuffer@f1000000 { + compatible = "simple-framebuffer"; + reg = <0 0xf1000000 0 (1080 * 2400 * 4)>; + width = <1080>; + height = <2400>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + }; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x3ab00000>, + /* Memory hole */ + <0x0 0xc1200000 0x0 0x1ee00000>, + /* Memory hole */ + <0x0 0xe1900000 0x0 0x1e700000>, + /* Memory hole - last block */ + <0x8 0x80000000 0x1 0x7ec00000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + cont_splash_mem: framebuffer@f1000000 { + reg = <0 0xf1000000 0 0x13c6800>; + no-map; + }; + + abox_reserved: audio@f7fb0000 { + reg = <0 0xf7fb0000 0 0x2a50000>; + no-map; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&key_power &key_voldown &key_volup>; + pinctrl-names = "default"; + + power-key { + label = "Power"; + linux,code = ; + gpios = <&gpa2 4 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + voldown-key { + label = "Volume Down"; + linux,code = ; + gpios = <&gpa0 4 GPIO_ACTIVE_LOW>; + }; + + volup-key { + label = "Volume Up"; + linux,code = ; + gpios = <&gpa0 3 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&oscclk { + clock-frequency = <26000000>; +}; + +&pinctrl_alive { + key_power: key-power-pins { + samsung,pins = "gpa2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + key_voldown: key-voldown-pins { + samsung,pins = "gpa0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + key_volup: key-volup-pins { + samsung,pins = "gpa0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; diff --git a/arch/arm64/boot/dts/exynos/exynos990-pinctrl.dtsi b/arch/arm64/boot/dts/exynos/exynos990-pinctrl.dtsi new file mode 100644 index 00000000000000..a03d36458d7645 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynos990-pinctrl.dtsi @@ -0,0 +1,2195 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Samsung Exynos 990 pin-mux and pin-config device tree source + * + * Copyright (c) 2024, Igor Belwon + */ + +#include +#include "exynos-pinctrl.h" + +&pinctrl_alive { + gpa0: gpa0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa1: gpa1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa2: gpa2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa3: gpa3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa4: gpa4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + ; + }; + + gpq0: gpq0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + speedy_bus: speedy-bus-pins { + samsung,pins = "gpq0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + speedy1_bus: speedy1-bus-pins { + samsung,pins = "gpq0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + /* UART1 is also referred to as UART_BT in downstream. */ + uart1_bus_single: uart1-bus-pins { + samsung,pins = "gpq0-3", "gpq0-2", "gpq0-1", "gpq0-0"; + samsung,pin-function = ; + samsung,pin-drv = ; + samsung,pin-pud = ; + }; + + uart1_rxd_pull: uart1-bus-rxd-pins { + samsung,pins = "gpq0-0"; + samsung,pin-pud = ; + }; + + uart1_bus_rts: uart1-bus-rts-pins { + samsung,pins = "gpq0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart1_bus_tx_input: uart1-bus-tx-input-pins { + samsung,pins = "gpq0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart1_bus_tx_dat: uart1-bus-tx-dat-pins { + samsung,pins = "gpq0-1"; + }; + + uart1_bus_tx_con: uart1-bus-tx-con-pins { + samsung,pins = "gpq0-1"; + samsung,pin-function = ; + }; + + wlan_host_wake: wlan-host-wake-pins { + samsung,pins = "gpa0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_cmgp { + gpm0: gpm0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpm1: gpm1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpm2: gpm2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpm3: gpm3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpm4: gpm4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm5: gpm5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm6: gpm6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm7: gpm7-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm8: gpm8-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm9: gpm9-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm10: gpm10-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm11: gpm11-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm12: gpm12-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm13: gpm13-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm14: gpm14-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm15: gpm15-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm16: gpm16-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm17: gpm17-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm18: gpm18-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm19: gpm19-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm20: gpm20-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm21: gpm21-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm22: gpm22-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm23: gpm23-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm24: gpm24-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm25: gpm25-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm26: gpm26-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm27: gpm27-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm28: gpm28-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm29: gpm29-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm30: gpm30-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm31: gpm31-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm32: gpm32-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + gpm33: gpm33-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + hsi2c38_bus: hsi2c38-bus-pins { + samsung,pins = "gpm0-0", "gpm1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c39_bus: hsi2c39-bus-pins { + samsung,pins = "gpm2-0", "gpm3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c40_bus: hsi2c40-bus-pins { + samsung,pins = "gpm4-0", "gpm5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c41_bus: hsi2c41-bus-pins { + samsung,pins = "gpm6-0", "gpm7-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c42_bus: hsi2c42-bus-pins { + samsung,pins = "gpm8-0", "gpm9-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c43_bus: hsi2c43-bus-pins { + samsung,pins = "gpm10-0", "gpm11-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c44_bus: hsi2c44-bus-pins { + samsung,pins = "gpm12-0", "gpm13-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c45_bus: hsi2c45-bus-pins { + samsung,pins = "gpm14-0", "gpm15-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi19_bus: spi19-bus-pins { + samsung,pins = "gpm0-0", "gpm1-0", "gpm2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi19_cs: spi19-cs-pins { + samsung,pins = "gpm3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi19_cs_func: spi19-cs-func-pins { + samsung,pins = "gpm3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi20_bus: spi20-bus-pins { + samsung,pins = "gpm4-0", "gpm5-0", "gpm6-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi20_cs: spi20-cs-pins { + samsung,pins = "gpm7-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi20_cs_func: spi20-cs-func-pins { + samsung,pins = "gpm7-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi21_bus: spi21-bus-pins { + samsung,pins = "gpm8-0", "gpm9-0", "gpm10-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi21_cs: spi21-cs-pins { + samsung,pins = "gpm11-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi21_cs_func: spi21-cs-func-pins { + samsung,pins = "gpm11-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi22_bus: spi22-bus-pins { + samsung,pins = "gpm12-0", "gpm13-0", "gpm14-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi22_cs: spi22-cs-pins { + samsung,pins = "gpm15-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi22_cs_func: spi22-cs-func-pins { + samsung,pins = "gpm15-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart21_bus_single: uart21-bus-pins { + samsung,pins = "gpm0-0", "gpm1-0", "gpm2-0", "gpm3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart21_bus_dual: uart21-bus-dual-pins { + samsung,pins = "gpm0-0", "gpm1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart22_bus_single: uart22-bus-pins { + samsung,pins = "gpm4-0", "gpm5-0", "gpm6-0", "gpm7-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart22_bus_dual: uart22-bus-dual-pins { + samsung,pins = "gpm4-0", "gpm5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart23_bus_single: uart23-bus-pins { + samsung,pins = "gpm8-0", "gpm9-0", "gpm10-0", "gpm11-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart23_bus_dual: uart23-bus-dual-pins { + samsung,pins = "gpm8-0", "gpm9-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart24_bus_single: uart24-bus-pins { + samsung,pins = "gpm12-0", "gpm13-0", "gpm14-0", "gpm15-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart24_bus_dual: uart24-bus-dual-pins { + samsung,pins = "gpm12-0", "gpm13-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_hsi1 { + gpf0: gpf0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpf1: gpf1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpf2: gpf2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + pcie0_clkreq: pcie0-clkreq-pins { + samsung,pins = "gpf0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + pcie0_perst: pcie0-perst-pins { + samsung,pins = "gpf0-1"; + samsung,pin-function = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + }; + + pcie1_clkreq: pcie1-clkreq-pins { + samsung,pins = "gpf0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + pcie1_perst: pcie1-perst-pins { + samsung,pins = "gpf0-3"; + samsung,pin-function = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + }; + + ufs_rst_n: ufs-rst-n-pins { + samsung,pins = "gpf2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + ufs_refclk_out: ufs-refclk-out-pins { + samsung,pins = "gpf2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + sd2_clk: sd2-clk-pins { + samsung,pins = "gpf1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_cmd: sd2-cmd-pins { + samsung,pins = "gpf1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_bus1: sd2-bus-width1-pins { + samsung,pins = "gpf1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_bus4: sd2-bus-width4-pins { + samsung,pins = "gpf1-3", "gpf1-4", "gpf1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_1x: sd2-clk-fast-slew-rate-1x-pins { + samsung,pins = "gpf1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_1_5x: sd2-clk-fast-slew-rate-1-5x-pins { + samsung,pins = "gpf1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_2x: sd2-clk-fast-slew-rate-2x-pins { + samsung,pins = "gpf1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_2_5x: sd2-clk-fast-slew-rate-2-5x-pins { + samsung,pins = "gpf1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_3x: sd2-clk-fas-slew-rate-3x-pins { + samsung,pins = "gpf1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_4x: sd2-clk-fast-slew-rate-4x-pins { + samsung,pins = "gpf1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_pins_as_pdn: sd2-pins-as-pdn-pins { + samsung,pins = "gpf1-0", "gpf1-1", "gpf1-2", "gpf1-3", "gpf1-4", "gpf1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_hsi2 { + gpf3: gpf3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + pcie2_clkreq: pcie2-clkreq-pins { + samsung,pins = "gpf3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + pcie2_perst: pcie2-perst-pins { + samsung,pins = "gpf3-1"; + samsung,pin-function = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + }; +}; + +&pinctrl_peric0 { + gpg0: gpg0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp0: gpp0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp1: gpp1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp2: gpp2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp3: gpp3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp4: gpp4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + hsi2c0_bus: hsi2c0-bus-pins { + samsung,pins = "gpp0-0", "gpp0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c1_bus: hsi2c1-bus-pins { + samsung,pins = "gpp0-2", "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c2_bus: hsi2c2-bus-pins { + samsung,pins = "gpp0-4", "gpp0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c3_bus: hsi2c3-bus-pins { + samsung,pins = "gpp0-6", "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c4_bus: hsi2c4-bus-pins { + samsung,pins = "gpp1-0", "gpp1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + hsi2c5_bus: hsi2c5-bus-pins { + samsung,pins = "gpp1-2", "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c6_bus: hsi2c6-bus-pins { + samsung,pins = "gpp1-4", "gpp1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c7_bus: hsi2c7-bus-pins { + samsung,pins = "gpp1-6", "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c8_bus: hsi2c8-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c9_bus: hsi2c9-bus-pins { + samsung,pins = "gpp2-2", "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c10_bus: hsi2c10-bus-pins { + samsung,pins = "gpp2-4", "gpp2-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c11_bus: hsi2c11-bus-pins { + samsung,pins = "gpp2-6", "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c26_bus: hsi2c26-bus-pins { + samsung,pins = "gpp3-0", "gpp3-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c27_bus: hsi2c27-bus-pins { + samsung,pins = "gpp3-2", "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + hsi2c28_bus: hsi2c28-bus-pins { + samsung,pins = "gpp3-4", "gpp3-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c29_bus: hsi2c29-bus-pins { + samsung,pins = "gpp3-6", "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c30_bus: hsi2c30-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c31_bus: hsi2c31-bus-pins { + samsung,pins = "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi0_bus: spi0-bus-pins { + samsung,pins = "gpp0-2", "gpp0-1", "gpp0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi0_cs: spi0-cs-pins { + samsung,pins = "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi0_cs_func: spi0-cs-func-pins { + samsung,pins = "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi1_bus: spi1-bus-pins { + samsung,pins = "gpp0-6", "gpp0-5", "gpp0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi1_cs: spi1-cs-pins { + samsung,pins = "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi1_cs_func: spi1-cs-func-pins { + samsung,pins = "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi2_bus: spi2-bus-pins { + samsung,pins = "gpp1-2", "gpp1-1", "gpp1-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi2_cs: spi2-cs-pins { + samsung,pins = "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi2_cs_func: spi2-cs-func-pins { + samsung,pins = "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi3_bus: spi3-bus-pins { + samsung,pins = "gpp1-6", "gpp1-5", "gpp1-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi3_cs: spi3-cs-pins { + samsung,pins = "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi3_cs_func: spi3-cs-func-pins { + samsung,pins = "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_bus: spi4-bus-pins { + samsung,pins = "gpp2-2", "gpp2-1", "gpp2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_cs: spi4-cs-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_cs_func: spi4-cs-func-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_fp_inactive: spi4-fp-inactive-pins { + samsung,pins = "gpp2-3", "gpp2-2", "gpp2-1", "gpp2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_fp_cs_func_high: spi4-fp-cs-func-high-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi5_bus: spi5-bus-pins { + samsung,pins = "gpp2-6", "gpp2-5", "gpp2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi5_cs: spi5-cs-pins { + samsung,pins = "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi5_cs_func: spi5-cs-func-pins { + samsung,pins = "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi13_bus: spi13-bus-pins { + samsung,pins = "gpp3-2", "gpp3-1", "gpp3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi13_cs: spi13-cs-pins { + samsung,pins = "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi13_cs_func: spi13-cs-func-pins { + samsung,pins = "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi14_bus: spi14-bus-pins { + samsung,pins = "gpp3-6", "gpp3-5", "gpp3-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi14_cs: spi14-cs-pins { + samsung,pins = "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi14_cs_func: spi14-cs-func-pins { + samsung,pins = "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi15_bus: spi15-bus-pins { + samsung,pins = "gpp4-2", "gpp4-1", "gpp4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi15_cs: spi15-cs-pins { + samsung,pins = "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi15_cs_func: spi15-cs-func-pins { + samsung,pins = "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart0_bus: uart0-bus-pins { + samsung,pins = "gpp4-6", "gpp4-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart2_bus_single: uart2-bus-pins { + samsung,pins = "gpp0-0", "gpp0-1", "gpp0-2", "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart2_bus_dual: uart2-bus-dual-pins { + samsung,pins = "gpp0-0", "gpp0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart3_bus_single: uart3-bus-pins { + samsung,pins = "gpp0-4", "gpp0-5", "gpp0-6", "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart3_bus_dual: uart3-bus-dual-pins { + samsung,pins = "gpp0-4", "gpp0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart4_bus_single: uart4-bus-pins { + samsung,pins = "gpp1-0", "gpp1-1", "gpp1-2", "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart4_bus_dual: uart4-bus-dual-pins { + samsung,pins = "gpp1-0", "gpp1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart5_bus_single: uart5-bus-pins { + samsung,pins = "gpp1-4", "gpp1-5", "gpp1-6", "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart5_bus_dual: uart5-bus-dual-pins { + samsung,pins = "gpp1-4", "gpp1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart6_bus_single: uart6-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1", "gpp2-2", "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart6_bus_dual: uart6-bus-dual-pins { + samsung,pins = "gpp2-0", "gpp2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart7_bus_single: uart7-bus-pins { + samsung,pins = "gpp2-4", "gpp2-5", "gpp2-6", "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart7_bus_dual: uart7-bus-dual-pins { + samsung,pins = "gpp2-4", "gpp2-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart15_bus_single: uart15-bus-pins { + samsung,pins = "gpp3-0", "gpp3-1", "gpp3-2", "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart15_bus_dual: uart15-bus-dual-pins { + samsung,pins = "gpp3-0", "gpp3-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart16_bus_single: uart16-bus-pins { + samsung,pins = "gpp3-4", "gpp3-5", "gpp3-6", "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart16_bus_dual: uart16-bus-dual-pins { + samsung,pins = "gpp3-4", "gpp3-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart17_bus_single: uart17-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1", "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart17_bus_dual: uart17-bus-dual-pins { + samsung,pins = "gpp4-0", "gpp4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_peric1 { + gpb0: gpb0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb1: gpb1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb2: gpb2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpc0: gpc0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg1: gpg1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp5: gpp5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp6: gpp6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp7: gpp7-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp8: gpp8-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp9: gpp9-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + aud_i2s0_bus: aud-i2s0-bus-pins { + samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s0_idle: aud-i2s0-idle-pins { + samsung,pins = "gpb0-0", "gpb0-1", "gpb0-2", "gpb0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s1_bus: aud-i2s1-bus-pins { + samsung,pins = "gpb0-4", "gpb0-5", "gpb0-6", "gpb0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s1_idle: aud-i2s1-idle-pins { + samsung,pins = "gpb0-4", "gpb0-5", "gpb0-6", "gpb0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s2_bus: aud-i2s2-bus-pins { + samsung,pins = "gpb1-0", "gpb1-1", "gpb1-2", "gpb1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s2_idle: aud-i2s2-idle-pins { + samsung,pins = "gpb1-0", "gpb1-1", "gpb1-2", "gpb1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s3_bus: aud-i2s3-bus-pins { + samsung,pins = "gpb1-4", "gpb1-5", "gpb1-6", "gpb1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s3_idle: aud-i2s3-idle-pins { + samsung,pins = "gpb1-4", "gpb1-5", "gpb1-6", "gpb1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s4_bus: aud-i2s4-bus-pins { + samsung,pins = "gpb2-0", "gpb2-1", "gpb2-2", "gpb2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s4_pci: aud-i2s4-pci-pins { + samsung,pins = "gpb2-0", "gpb2-1", "gpb2-2", "gpb2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s4_idle: aud-i2s4-idle-pins { + samsung,pins = "gpb2-0", "gpb2-1", "gpb2-2", "gpb2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s5_bus: aud-i2s5-bus-pins { + samsung,pins = "gpb2-4", "gpb2-5", "gpb2-6", "gpb2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_i2s5_idle: aud-i2s5-idle-pins { + samsung,pins = "gpb2-4", "gpb2-5", "gpb2-6", "gpb2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_dsd_bus: aud-dsd-bus-pins { + samsung,pins = "gpb2-4", "gpb2-5", "gpb2-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + aud_dsd_idle: aud-dsd-idle-pins { + samsung,pins = "gpb2-4", "gpb2-5", "gpb2-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + cfg_wlanen: cfg-wlanen-pins { + samsung,pins = "gpb0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + cnss_wlan_en_active: cnss-wlan-en-active-pins { + samsung,pins = "gpb0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + cnss_wlan_en_sleep: cnss-wlan-en-sleep-pins { + samsung,pins = "gpb0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + decon_f_te_on: decon-f-te-on-pins { + samsung,pins = "gpc0-4"; + samsung,pin-function = <0xf>; + }; + + decon_f_te_off: decon-f-te-off-pins { + samsung,pins = "gpc0-4"; + samsung,pin-function = ; + }; + + decon_s_te_on: decon-s-te-on-pins { + samsung,pins = "gpc0-5"; + samsung,pin-function = <0xf>; + }; + + decon_s_te_off: decon-s-te-off-pins { + samsung,pins = "gpc0-5"; + samsung,pin-function = ; + }; + + hsi2c12_bus: hsi2c12-bus-pins { + samsung,pins = "gpp5-0", "gpp5-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c13_bus: hsi2c13-bus-pins { + samsung,pins = "gpp5-2", "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c14_bus: hsi2c14-bus-pins { + samsung,pins = "gpp5-4", "gpp5-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c15_bus: hsi2c15-bus-pins { + samsung,pins = "gpp5-6", "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c16_bus: hsi2c16-bus-pins { + samsung,pins = "gpp6-0", "gpp6-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c17_bus: hsi2c17-bus-pins { + samsung,pins = "gpp6-2", "gpp6-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c18_bus: hsi2c18-bus-pins { + samsung,pins = "gpp6-4", "gpp6-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c19_bus: hsi2c19-bus-pins { + samsung,pins = "gpp6-6", "gpp6-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c20_bus: hsi2c20-bus-pins { + samsung,pins = "gpp7-0", "gpp7-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c21_bus: hsi2c21-bus-pins { + samsung,pins = "gpp7-2", "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c22_bus: hsi2c22-bus-pins { + samsung,pins = "gpp7-4", "gpp7-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c23_bus: hsi2c23-bus-pins { + samsung,pins = "gpp7-6", "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c24_bus: hsi2c24-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c25_bus: hsi2c25-bus-pins { + samsung,pins = "gpp8-2", "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c32_bus: hsi2c32-bus-pins { + samsung,pins = "gpp8-4", "gpp8-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c33_bus: hsi2c33-bus-pins { + samsung,pins = "gpp8-6", "gpp8-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c34_bus: hsi2c34-bus-pins { + samsung,pins = "gpp9-0", "gpp9-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c35_bus: hsi2c35-bus-pins { + samsung,pins = "gpp9-2", "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c36_bus: hsi2c36-bus-pins { + samsung,pins = "gpp9-4", "gpp9-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c37_bus: hsi2c37-bus-pins { + samsung,pins = "gpp9-6", "gpp9-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk0_out: sensor-mclk0-out-pins { + samsung,pins = "gpc0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk1_out: sensor-mclk1-out-pins { + samsung,pins = "gpg1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk2_out: sensor-mclk2-out-pins { + samsung,pins = "gpc0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk3_out: sensor-mclk3-out-pins { + samsung,pins = "gpc0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk4_out: sensor-mclk4-out-pins { + samsung,pins = "gpc0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk5_out: sensor-mclk5-out-pins { + samsung,pins = "gpg1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk0_fn: sensor-mclk0-fn-pins { + samsung,pins = "gpc0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk1_fn: sensor-mclk1-fn-pins { + samsung,pins = "gpg1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk2_fn: sensor-mclk2-fn-pins { + samsung,pins = "gpc0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk3_fn: sensor-mclk3-fn-pins { + samsung,pins = "gpc0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk4_fn: sensor-mclk4-fn-pins { + samsung,pins = "gpc0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk5_fn: sensor-mclk5-fn-pins { + samsung,pins = "gpg1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi6_bus: spi6-bus-pins { + samsung,pins = "gpp5-2", "gpp5-1", "gpp5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi6_cs: spi6-cs-pins { + samsung,pins = "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi6_cs_func: spi6-cs-func-pins { + samsung,pins = "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi7_bus: spi7-bus-pins { + samsung,pins = "gpp5-6", "gpp5-5", "gpp5-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi7_cs: spi7-cs-pins { + samsung,pins = "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi7_cs_func: spi7-cs-func-pins { + samsung,pins = "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi8_bus: spi8-bus-pins { + samsung,pins = "gpp6-2", "gpp6-1", "gpp6-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi8_cs: spi8-cs-pins { + samsung,pins = "gpp6-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi8_cs_func: spi8-cs-func-pins { + samsung,pins = "gpp6-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi9_bus: spi9-bus-pins { + samsung,pins = "gpp6-6", "gpp6-5", "gpp6-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi9_cs: spi9-cs-pins { + samsung,pins = "gpp6-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi9_cs_func: spi9-cs-func-pins { + samsung,pins = "gpp6-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi10_bus: spi10-bus-pins { + samsung,pins = "gpp7-2", "gpp7-1", "gpp7-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi10_cs: spi10-cs-pins { + samsung,pins = "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi10_cs_func: spi10-cs-func-pins { + samsung,pins = "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi11_bus: spi11-bus-pins { + samsung,pins = "gpp7-6", "gpp7-5", "gpp7-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi11_cs: spi11-cs-pins { + samsung,pins = "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi11_cs_func: spi11-cs-func-pins { + samsung,pins = "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi12_bus: spi12-bus-pins { + samsung,pins = "gpp8-2", "gpp8-1", "gpp8-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi12_cs: spi12-cs-pins { + samsung,pins = "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi12_cs_func: spi12-cs-func-pins { + samsung,pins = "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi16_bus: spi16-bus-pins { + samsung,pins = "gpp8-6", "gpp8-5", "gpp8-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + spi16_cs: spi16-cs-pins { + samsung,pins = "gpp8-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi16_cs_func: spi16-cs-func-pins { + samsung,pins = "gpp8-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + spi17_bus: spi17-bus-pins { + samsung,pins = "gpp9-2", "gpp9-1", "gpp9-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi17_cs: spi17-cs-pins { + samsung,pins = "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi17_cs_func: spi17-cs-func-pins { + samsung,pins = "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi18_bus: spi18-bus-pins { + samsung,pins = "gpp9-6", "gpp9-5", "gpp9-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi18_cs: spi18-cs-pins { + samsung,pins = "gpp9-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi18_cs_func: spi18-cs-func-pins { + samsung,pins = "gpp9-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart8_bus_single: uart8-bus-pins { + samsung,pins = "gpp5-3", "gpp5-2", "gpp5-1", "gpp5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart8_bus_dual: uart8-bus-dual-pins { + samsung,pins = "gpp5-0", "gpp5-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart9_bus_single: uart9-bus-pins { + samsung,pins = "gpp5-7", "gpp5-6", "gpp5-5", "gpp5-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart9_bus_dual: uart9-bus-dual-pins { + samsung,pins = "gpp5-4", "gpp5-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart10_bus_single: uart10-bus-pins { + samsung,pins = "gpp6-3", "gpp6-2", "gpp6-1", "gpp6-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart10_bus_dual: uart10-bus-dual-pins { + samsung,pins = "gpp6-0", "gpp6-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart11_bus_single: uart11-bus-pins { + samsung,pins = "gpp6-7", "gpp6-6", "gpp6-5", "gpp6-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart11_bus_dual: uart11-bus-dual-pins { + samsung,pins = "gpp6-4", "gpp6-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart12_bus_single: uart12-bus-pins { + samsung,pins = "gpp7-3", "gpp7-2", "gpp7-1", "gpp7-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart12_bus_dual: uart12-bus-dual-pins { + samsung,pins = "gpp7-0", "gpp7-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart13_bus_single: uart13-bus-pins { + samsung,pins = "gpp7-7", "gpp7-6", "gpp7-5", "gpp7-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart13_bus_dual: uart13-bus-dual-pins { + samsung,pins = "gpp7-4", "gpp7-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart14_bus_single: uart14-bus-pins { + samsung,pins = "gpp8-3", "gpp8-2", "gpp8-1", "gpp8-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart14_bus_dual: uart14-bus-dual-pins { + samsung,pins = "gpp8-0", "gpp8-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart18_bus_single: uart18-bus-pins { + samsung,pins = "gpp8-7", "gpp8-6", "gpp8-5", "gpp8-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart18_bus_dual: uart18-bus-dual-pins { + samsung,pins = "gpp8-4", "gpp8-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart19_bus_single: uart19-bus-pins { + samsung,pins = "gpp9-3", "gpp9-2", "gpp9-1", "gpp9-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart19_bus_dual: uart19-bus-dual-pins { + samsung,pins = "gpp9-0", "gpp9-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart20_bus_single: uart20-bus-pins { + samsung,pins = "gpp9-7", "gpp9-6", "gpp9-5", "gpp9-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart20_bus_dual: uart20-bus-dual-pins { + samsung,pins = "gpp9-4", "gpp9-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_vts { + gpv0: gpv0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + amic_pdm: amic-pdm-pins { + samsung,pins = "gpv0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_bus_clk: dmic-bus-clk-pins { + samsung,pins = "gpv0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_bus_clk_idle: dmic-bus-clk-idle-pins { + samsung,pins = "gpv0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_bus_clk1: dmic-bus-clk1-pins { + samsung,pins = "gpv0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_bus_clk1_idle: dmic-bus-clk1-idle-pins { + samsung,pins = "gpv0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_bus_clk2: dmic-bus-clk2-pins { + samsung,pins = "gpv0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_bus_clk2_idle: dmic-bus-clk2-idle-pins { + samsung,pins = "gpv0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_pdm: dmic-pdm-pins { + samsung,pins = "gpv0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_pdm_idle: dmic-pdm-idle-pins { + samsung,pins = "gpv0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_pdm1_bus: dmic-pdm1-bus-pins { + samsung,pins = "gpv0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_pdm1_idle: dmic-pdm1-idle-pins { + samsung,pins = "gpv0-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_pdm2_bus: dmic-pdm2-bus-pins { + samsung,pins = "gpv0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + dmic_pdm2_idle: dmic-pdm2-idle-pins { + samsung,pins = "gpv0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; +}; diff --git a/arch/arm64/boot/dts/exynos/exynos990.dtsi b/arch/arm64/boot/dts/exynos/exynos990.dtsi new file mode 100644 index 00000000000000..c1986f00e4438b --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynos990.dtsi @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Samsung Exynos 990 SoC device tree source + * + * Copyright (c) 2024, Igor Belwon + */ + +#include + +/ { + compatible = "samsung,exynos990"; + #address-cells = <2>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + aliases { + pinctrl0 = &pinctrl_alive; + pinctrl1 = &pinctrl_cmgp; + pinctrl2 = &pinctrl_hsi1; + pinctrl3 = &pinctrl_hsi2; + pinctrl4 = &pinctrl_peric0; + pinctrl5 = &pinctrl_peric1; + pinctrl6 = &pinctrl_vts; + }; + + arm-a55-pmu { + compatible = "arm,cortex-a55-pmu"; + interrupts = , + , + , + ; + + interrupt-affinity = <&cpu0>, + <&cpu1>, + <&cpu2>, + <&cpu3>; + }; + + arm-a76-pmu { + compatible = "arm,cortex-a76-pmu"; + interrupts = , + ; + + interrupt-affinity = <&cpu4>, + <&cpu5>; + }; + + /* There's no PMU model for cluster2, which are the Mongoose cores. */ + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + + core2 { + cpu = <&cpu2>; + }; + + core3 { + cpu = <&cpu3>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu4>; + }; + + core1 { + cpu = <&cpu5>; + }; + }; + + cluster2 { + core0 { + cpu = <&cpu6>; + }; + + core1 { + cpu = <&cpu7>; + }; + }; + }; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0>; + enable-method = "psci"; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x1>; + enable-method = "psci"; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x2>; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x3>; + enable-method = "psci"; + }; + + cpu4: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0x4>; + enable-method = "psci"; + }; + + cpu5: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0x5>; + enable-method = "psci"; + }; + + cpu6: cpu@200 { + device_type = "cpu"; + compatible = "samsung,mongoose-m5"; + reg = <0x6>; + enable-method = "psci"; + }; + + cpu7: cpu@201 { + device_type = "cpu"; + compatible = "samsung,mongoose-m5"; + reg = <0x7>; + enable-method = "psci"; + }; + }; + + oscclk: clock-osc { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "oscclk"; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "hvc"; + }; + + soc: soc@0 { + compatible = "simple-bus"; + ranges = <0x0 0x0 0x0 0x20000000>; + + #address-cells = <1>; + #size-cells = <1>; + + chipid@10000000 { + compatible = "samsung,exynos990-chipid", + "samsung,exynos850-chipid"; + reg = <0x10000000 0x100>; + }; + + gic: interrupt-controller@10101000 { + compatible = "arm,gic-400"; + reg = <0x10101000 0x1000>, + <0x10102000 0x1000>, + <0x10104000 0x2000>, + <0x10106000 0x2000>; + #interrupt-cells = <3>; + interrupt-controller; + interrupts = ; + #address-cells = <0>; + #size-cells = <1>; + }; + + pinctrl_peric0: pinctrl@10430000 { + compatible = "samsung,exynos990-pinctrl"; + reg = <0x10430000 0x1000>; + interrupts = ; + }; + + pinctrl_peric1: pinctrl@10730000 { + compatible = "samsung,exynos990-pinctrl"; + reg = <0x10730000 0x1000>; + interrupts = ; + }; + + pinctrl_hsi1: pinctrl@13040000 { + compatible = "samsung,exynos990-pinctrl"; + reg = <0x13040000 0x1000>; + interrupts = ; + }; + + pinctrl_hsi2: pinctrl@13c30000 { + compatible = "samsung,exynos990-pinctrl"; + reg = <0x13c30000 0x1000>; + interrupts = ; + }; + + pinctrl_vts: pinctrl@15580000 { + compatible = "samsung,exynos990-pinctrl"; + reg = <0x15580000 0x1000>; + }; + + pinctrl_alive: pinctrl@15850000 { + compatible = "samsung,exynos990-pinctrl"; + reg = <0x15850000 0x1000>; + + wakeup-interrupt-controller { + compatible = "samsung,exynos990-wakeup-eint", + "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; + }; + }; + + pinctrl_cmgp: pinctrl@15c30000 { + compatible = "samsung,exynos990-pinctrl"; + reg = <0x15c30000 0x1000>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + + /* + * Non-updatable, broken stock Samsung bootloader does not + * configure CNTFRQ_EL0 + */ + clock-frequency = <26000000>; + }; +}; + +#include "exynos990-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/exynos/exynosautov920.dtsi b/arch/arm64/boot/dts/exynos/exynosautov920.dtsi index 91882b37fdb32b..c759134c909eaa 100644 --- a/arch/arm64/boot/dts/exynos/exynosautov920.dtsi +++ b/arch/arm64/boot/dts/exynos/exynosautov920.dtsi @@ -172,6 +172,17 @@ chipid@10000000 { reg = <0x10000000 0x24>; }; + cmu_misc: clock-controller@10020000 { + compatible = "samsung,exynosautov920-cmu-misc"; + reg = <0x10020000 0x8000>; + #clock-cells = <1>; + + clocks = <&xtcxo>, + <&cmu_top DOUT_CLKCMU_MISC_NOC>; + clock-names = "oscclk", + "noc"; + }; + gic: interrupt-controller@10400000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; @@ -247,6 +258,19 @@ pwm: pwm@109b0000 { status = "disabled"; }; + cmu_peric1: clock-controller@10c00000 { + compatible = "samsung,exynosautov920-cmu-peric1"; + reg = <0x10c00000 0x8000>; + #clock-cells = <1>; + + clocks = <&xtcxo>, + <&cmu_top DOUT_CLKCMU_PERIC1_NOC>, + <&cmu_top DOUT_CLKCMU_PERIC1_IP>; + clock-names = "oscclk", + "noc", + "ip"; + }; + syscon_peric1: syscon@10c20000 { compatible = "samsung,exynosautov920-peric1-sysreg", "syscon"; @@ -283,12 +307,38 @@ pmu_system_controller: system-controller@11860000 { reg = <0x11860000 0x10000>; }; + cmu_hsi0: clock-controller@16000000 { + compatible = "samsung,exynosautov920-cmu-hsi0"; + reg = <0x16000000 0x8000>; + #clock-cells = <1>; + + clocks = <&xtcxo>, + <&cmu_top DOUT_CLKCMU_HSI0_NOC>; + clock-names = "oscclk", + "noc"; + }; + pinctrl_hsi0: pinctrl@16040000 { compatible = "samsung,exynosautov920-pinctrl"; reg = <0x16040000 0x10000>; interrupts = ; }; + cmu_hsi1: clock-controller@16400000 { + compatible = "samsung,exynosautov920-cmu-hsi1"; + reg = <0x16400000 0x8000>; + #clock-cells = <1>; + + clocks = <&xtcxo>, + <&cmu_top DOUT_CLKCMU_HSI1_NOC>, + <&cmu_top DOUT_CLKCMU_HSI1_USBDRD>, + <&cmu_top DOUT_CLKCMU_HSI1_MMC_CARD>; + clock-names = "oscclk", + "noc", + "usbdrd", + "mmc_card"; + }; + pinctrl_hsi1: pinctrl@16450000 { compatible = "samsung,exynosautov920-pinctrl"; reg = <0x16450000 0x10000>; diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 9d3df8b218a2e4..42e6482a31cbe5 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -136,10 +136,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7903.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7904.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-ivy.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-ivy.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-yavia.dtb @@ -167,12 +169,22 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-beacon-kit.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-data-modul-edm-sbc.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-debix-model-a.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-debix-som-a-bmb-08.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-drc02.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk3.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-picoitx.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-icore-mx8mp-edimm2.2.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-iota2-lumpy.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-kontron-bl-osm-s.dtb + +imx8mp-kontron-dl-dtbs += imx8mp-kontron-bl-osm-s.dtb imx8mp-kontron-dl.dtbo +dtb-$(CONFIG_ARCH_MXC) += imx8mp-kontron-dl.dtb + +dtb-$(CONFIG_ARCH_MXC) += imx8mp-kontron-smarc-eval-carrier.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-msc-sm2s-ep1.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-navqp.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-nitrogen-smarc-universal-board.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb imx8mp-phyboard-pollux-rdk-no-eth-dtbs += imx8mp-phyboard-pollux-rdk.dtb imx8mp-phycore-no-eth.dtbo dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk-no-eth.dtb @@ -187,17 +199,22 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw72xx-2x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw73xx-2x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw74xx.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw75xx-2x.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw82xx-2x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-ivy.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-ivy.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-yavia.dtb imx8mp-evk-mx8-dlvds-lcd1-dtbs += imx8mp-evk.dtb imx8mp-evk-mx8-dlvds-lcd1.dtbo +imx8mp-evk-pcie-ep-dtbs += imx8mp-evk.dtb imx8mp-evk-pcie-ep.dtbo dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-mx8-dlvds-lcd1.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-pcie-ep.dtb imx8mp-tqma8mpql-mba8mpxl-lvds-dtbs += imx8mp-tqma8mpql-mba8mpxl.dtb imx8mp-tqma8mpql-mba8mpxl-lvds.dtbo imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01-dtbs += imx8mp-tqma8mpql-mba8mpxl.dtb imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtbo @@ -240,6 +257,10 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqp-mba8xx.dtb dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb + +imx93-9x9-qsb-i3c-dtbs += imx93-9x9-qsb.dtb imx93-9x9-qsb-i3c.dtbo +dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb-i3c.dtb + dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx93-14x14-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx93-kontron-bl-osm-s.dtb @@ -249,6 +270,10 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxla.dtb dtb-$(CONFIG_ARCH_MXC) += imx93-var-som-symphony.dtb dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk.dtb +imx8mm-kontron-dl-dtbs := imx8mm-kontron-bl.dtb imx8mm-kontron-dl.dtbo + +dtb-$(CONFIG_ARCH_MXC) += imx8mm-kontron-dl.dtb + imx8mm-venice-gw72xx-0x-imx219-dtbs := imx8mm-venice-gw72xx-0x.dtb imx8mm-venice-gw72xx-0x-imx219.dtbo imx8mm-venice-gw72xx-0x-rpidsi-dtbs := imx8mm-venice-gw72xx-0x.dtb imx8mm-venice-gw72xx-0x-rpidsi.dtbo imx8mm-venice-gw72xx-0x-rs232-rts-dtbs := imx8mm-venice-gw72xx-0x.dtb imx8mm-venice-gw72xx-0x-rs232-rts.dtbo diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts index bbdf989058ff77..ce59b94d8c2282 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts @@ -87,7 +87,7 @@ flash@1 { flash@2 { #address-cells = <1>; #size-cells = <1>; - compatible = "en25s64", "jedec,spi-nor"; + compatible = "jedec,spi-nor"; spi-cpol; spi-cpha; reg = <2>; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts index d9fac647f4327d..1d53b529af88fa 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-kontron-sl28-var3-ads2.dts @@ -19,8 +19,6 @@ / { pwm-fan { compatible = "pwm-fan"; - cooling-min-state = <0>; - cooling-max-state = <3>; #cooling-cells = <2>; pwms = <&sl28cpld_pwm0 0 4000000>; cooling-levels = <1 128 192 255>; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts index a1d9102ff32be9..736722b58e77f7 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts @@ -69,7 +69,7 @@ flash@1 { flash@2 { #address-cells = <1>; #size-cells = <1>; - compatible = "en25s64", "jedec,spi-nor"; + compatible = "jedec,spi-nor"; spi-cpol; spi-cpha; reg = <2>; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi index d32a52ab00a42a..e4b727070814f9 100644 --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-cex7.dtsi @@ -94,9 +94,6 @@ i2c@1 { fan-temperature-ctrlr@18 { compatible = "ti,amc6821"; reg = <0x18>; - cooling-min-state = <0>; - cooling-max-state = <9>; - #cooling-cells = <2>; }; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-rev2.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rev2.dtsi new file mode 100644 index 00000000000000..f54005e37924be --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-rev2.dtsi @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// +// Device Tree file for LX2160 REV2 +// +// Copyright 2025 NXP + +/dts-v1/; + +#include "fsl-lx2160a.dtsi" + +&pcie1 { + compatible = "fsl,lx2160ar2-pcie", "fsl,ls2088a-pcie"; + reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ + 0x80 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + + ranges = <0x81000000 0x0 0x00000000 0x80 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0x80 0x40000000 0x0 0x40000000>; + + interrupts = ; + interrupt-names = "intr"; + + /delete-property/ apio-wins; + /delete-property/ ppio-wins; +}; + +&pcie2 { + compatible = "fsl,lx2160ar2-pcie", "fsl,ls2088a-pcie"; + reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ + 0x88 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + + ranges = <0x81000000 0x0 0x00000000 0x88 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0x88 0x40000000 0x0 0x40000000>; + + interrupts = ; + interrupt-names = "intr"; + + /delete-property/ apio-wins; + /delete-property/ ppio-wins; +}; + +&pcie3 { + compatible = "fsl,lx2160ar2-pcie", "fsl,ls2088a-pcie"; + reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ + 0x90 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + + ranges = <0x81000000 0x0 0x00000000 0x90 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0x90 0x40000000 0x0 0x40000000>; + + interrupts = ; + interrupt-names = "intr"; + + /delete-property/ apio-wins; + /delete-property/ ppio-wins; +}; + + +&pcie4 { + compatible = "fsl,lx2160ar2-pcie", "fsl,ls2088a-pcie"; + reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ + 0x98 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + + ranges = <0x81000000 0x0 0x00000000 0x98 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0x98 0x40000000 0x0 0x40000000>; + + interrupts = ; + interrupt-names = "intr"; + + /delete-property/ apio-wins; + /delete-property/ ppio-wins; +}; + +&pcie5 { + compatible = "fsl,lx2160ar2-pcie", "fsl,ls2088a-pcie"; + reg = <0x00 0x03800000 0x0 0x00100000 /* controller registers */ + 0xa0 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + + ranges = <0x81000000 0x0 0x00000000 0xa0 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0xa0 0x40000000 0x0 0x40000000>; + + interrupts = ; + interrupt-names = "intr"; + + /delete-property/ apio-wins; + /delete-property/ ppio-wins; +}; + +&pcie6 { + compatible = "fsl,lx2160ar2-pcie", "fsl,ls2088a-pcie"; + reg = <0x00 0x03900000 0x0 0x00100000 /* controller registers */ + 0xa8 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + + ranges = <0x81000000 0x0 0x00000000 0xa8 0x00010000 0x0 0x00010000 + 0x82000000 0x0 0x40000000 0xa8 0x40000000 0x0 0x40000000>; + + interrupts = ; + interrupt-names = "intr"; + + /delete-property/ apio-wins; + /delete-property/ ppio-wins; +}; + +&soc { + pcie_ep1: pcie-ep@3400000 { + compatible = "fsl,lx2160ar2-pcie-ep"; + reg = <0x00 0x03400000 0x0 0x00100000 + 0x80 0x00000000 0x8 0x00000000>; + reg-names = "regs", "addr_space"; + num-ob-windows = <8>; + num-ib-windows = <8>; + status = "disabled"; + }; + + pcie_ep2: pcie-ep@3500000 { + compatible = "fsl,lx2160ar2-pcie-ep"; + reg = <0x00 0x03500000 0x0 0x00100000 + 0x88 0x00000000 0x8 0x00000000>; + reg-names = "regs", "addr_space"; + num-ob-windows = <8>; + num-ib-windows = <8>; + status = "disabled"; + }; + + pcie_ep3: pcie-ep@3600000 { + compatible = "fsl,lx2160ar2-pcie-ep"; + reg = <0x00 0x03600000 0x0 0x00100000 + 0x90 0x00000000 0x8 0x00000000>; + reg-names = "regs", "addr_space"; + num-ob-windows = <256>; + num-ib-windows = <24>; + status = "disabled"; + }; + + pcie_ep4: pcie-ep@3700000 { + compatible = "fsl,lx2160ar2-pcie-ep"; + reg = <0x00 0x03700000 0x0 0x00100000 + 0x98 0x00000000 0x8 0x00000000>; + reg-names = "regs", "addr_space"; + num-ob-windows = <8>; + num-ib-windows = <8>; + status = "disabled"; + }; + + + pcie_ep5: pcie-ep@3800000 { + compatible = "fsl,lx2160ar2-pcie-ep"; + reg = <0x00 0x03800000 0x0 0x00100000 + 0xa0 0x00000000 0x8 0x00000000>; + reg-names = "regs", "addr_space"; + num-ob-windows = <256>; + num-ib-windows = <24>; + status = "disabled"; + }; + + pcie_ep6: pcie-ep@3900000 { + compatible = "fsl,lx2160ar2-pcie-ep"; + reg = <0x00 0x03900000 0x0 0x00100000 + 0xa8 0x00000000 0x8 0x00000000>; + reg-names = "regs", "addr_space"; + num-ob-windows = <8>; + num-ib-windows = <8>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi index 927ecf66a74042..c9541403bcd823 100644 --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi @@ -614,7 +614,7 @@ cluster2-3-crit { }; }; - soc { + soc: soc { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.2.dtsi index f5c6a0164f3671..5862b24fb76443 100644 --- a/arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.2.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-apalis-eval-v1.2.dtsi @@ -51,6 +51,40 @@ reg_can2: regulator-can2 { regulator-name = "5V_SW_CAN2"; startup-delay-us = <10000>; }; + + sound-carrier { + compatible = "simple-audio-card"; + simple-audio-card,bitclock-master = <&codec_dai>; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&codec_dai>; + simple-audio-card,name = "apalis-nau8822"; + simple-audio-card,routing = + "Headphones", "LHP", + "Headphones", "RHP", + "Speaker", "LSPK", + "Speaker", "RSPK", + "Line Out", "AUXOUT1", + "Line Out", "AUXOUT2", + "LAUX", "Line In", + "RAUX", "Line In", + "LMICP", "Mic In", + "RMICP", "Mic In"; + simple-audio-card,widgets = + "Headphones", "Headphones", + "Line Out", "Line Out", + "Speaker", "Speaker", + "Microphone", "Mic In", + "Line", "Line In"; + + codec_dai: simple-audio-card,codec { + sound-dai = <&nau8822_1a>; + system-clock-frequency = <12288000>; + }; + + simple-audio-card,cpu { + sound-dai = <&sai0>; + }; + }; }; /* Apalis CAN1 */ @@ -69,6 +103,13 @@ &flexcan2 { &i2c2 { status = "okay"; + /* Audio Codec */ + nau8822_1a: audio-codec@1a { + compatible = "nuvoton,nau8822"; + reg = <0x1a>; + #sound-dai-cells = <0>; + }; + /* Power/Current Measurement Sensor */ hwmon@40 { compatible = "ti,ina219"; @@ -87,6 +128,18 @@ eeprom@57 { }; }; +&sai0 { + assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>, + <&sai0_lpcg IMX_LPCG_CLK_0>; + assigned-clock-rates = <786432000>, <49152000>, <12288000>, <49152000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai0>; + #sound-dai-cells = <0>; + status = "okay"; +}; + /* Apalis MMC1 */ &usdhc2 { pinctrl-0 = <&pinctrl_usdhc2_4bit>, <&pinctrl_mmc1_cd>; @@ -105,6 +158,15 @@ &usdhc3 { }; &iomuxc { + pinctrl-0 = <&pinctrl_cam1_gpios>, + <&pinctrl_esai0_gpios>, <&pinctrl_fec2_gpios>, + <&pinctrl_gpio3>, <&pinctrl_gpio4>, <&pinctrl_gpio_keys>, + <&pinctrl_gpio_usbh_oc_n>, <&pinctrl_lpuart1ctrl>, + <&pinctrl_lvds0_i2c0_gpio>, <&pinctrl_lvds1_i2c0_gpios>, + <&pinctrl_mipi_dsi_0_1_en>, <&pinctrl_mipi_dsi1_gpios>, + <&pinctrl_mlb_gpios>, <&pinctrl_qspi1a_gpios>, + <&pinctrl_sata1_act>, <&pinctrl_sim0_gpios>, + <&pinctrl_usdhc1_gpios>; pinctrl_enable_3v3_mmc: enable3v3mmcgrp { fsl,pins = ; /* MXM3_148 */ @@ -121,4 +183,11 @@ pinctrl_enable_can1_power: enablecan1powergrp { pinctrl_enable_can2_power: enablecan2powergrp { fsl,pins = ; /* MXM3_156 */ }; + + pinctrl_sai0: sai0grp { + fsl,pins = , /* MXM3_196 */ + , /* MXM3_200 */ + , /* MXM3_202 */ + ; /* MXM3_204 */ + }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-eval.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-eval.dtsi index deecb96a159610..dc127298715b3c 100644 --- a/arch/arm64/boot/dts/freescale/imx8-apalis-eval.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-apalis-eval.dtsi @@ -22,9 +22,13 @@ &adc1 { status = "okay"; }; -/* TODO: Audio Mixer */ +&amix { + status = "okay"; +}; -/* TODO: Asynchronous Sample Rate Converter (ASRC) */ +&asrc0 { + status = "okay"; +}; /* TODO: Display Controller */ @@ -104,13 +108,25 @@ &lsio_pwm3 { /* TODO: Apalis BKL1_PWM */ -/* TODO: Apalis DAP1 */ +/* Apalis DAP1 */ +&sai1 { + status = "okay"; +}; -/* TODO: Apalis Analogue Audio */ +&sai5 { + status = "okay"; +}; + +&sai5_lpcg { + status = "okay"; +}; /* TODO: Apalis SATA1 */ -/* TODO: Apalis SPDIF1 */ +/* Apalis SPDIF1 */ +&spdif0 { + status = "okay"; +}; /* TODO: Apalis USBH2, Apalis USBH3 and on-module Wi-Fi via on-module HSIC Hub */ @@ -119,4 +135,7 @@ &usbotg1 { status = "okay"; }; -/* TODO: Apalis USBH4 SuperSpeed */ +/* Apalis USBH4 SuperSpeed */ +&usbotg3_cdns3 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi index 5438923a905ceb..d4a1ad528f650d 100644 --- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.1.dtsi @@ -62,9 +62,13 @@ &adc1 { status = "okay"; }; -/* TODO: Audio Mixer */ +&amix { + status = "okay"; +}; -/* TODO: Asynchronous Sample Rate Converter (ASRC) */ +&asrc0 { + status = "okay"; +}; /* TODO: Display Controller */ @@ -191,13 +195,25 @@ &lsio_pwm3 { /* TODO: Apalis BKL1_PWM */ -/* TODO: Apalis DAP1 */ +/* Apalis DAP1 */ +&sai1 { + status = "okay"; +}; -/* TODO: Apalis Analogue Audio */ +&sai5 { + status = "okay"; +}; + +&sai5_lpcg { + status = "okay"; +}; /* TODO: Apalis SATA1 */ -/* TODO: Apalis SPDIF1 */ +/* Apalis SPDIF1 */ +&spdif0 { + status = "okay"; +}; /* TODO: Apalis USBH2, Apalis USBH3 and on-module Wi-Fi via on-module HSIC Hub */ @@ -206,7 +222,10 @@ &usbotg1 { status = "okay"; }; -/* TODO: Apalis USBH4 SuperSpeed */ +/* Apalis USBH4 SuperSpeed */ +&usbotg3_cdns3 { + status = "okay"; +}; /* Apalis MMC1 */ &usdhc2 { diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi index f6654fdcb14780..5e132c83e1b26b 100644 --- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi @@ -94,9 +94,13 @@ &adc1 { status = "okay"; }; -/* TODO: Audio Mixer */ +&amix { + status = "okay"; +}; -/* TODO: Asynchronous Sample Rate Converter (ASRC) */ +&asrc0 { + status = "okay"; +}; /* TODO: Display Controller */ @@ -240,13 +244,25 @@ &lsio_pwm3 { /* TODO: Apalis BKL1_PWM */ -/* TODO: Apalis DAP1 */ +/* Apalis DAP1 */ +&sai1 { + status = "okay"; +}; -/* TODO: Apalis Analogue Audio */ +&sai5 { + status = "okay"; +}; + +&sai5_lpcg { + status = "okay"; +}; /* TODO: Apalis SATA1 */ -/* TODO: Apalis SPDIF1 */ +/* Apalis SPDIF1 */ +&spdif0 { + status = "okay"; +}; /* TODO: Apalis USBH2, Apalis USBH3 and on-module Wi-Fi via on-module HSIC Hub */ @@ -255,7 +271,10 @@ &usbotg1 { status = "okay"; }; -/* TODO: Apalis USBH4 SuperSpeed */ +/* Apalis USBH4 SuperSpeed */ +&usbotg3_cdns3 { + status = "okay"; +}; /* Apalis MMC1 */ &usdhc2 { diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi index 160153853b6862..a3fc945aea1638 100644 --- a/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-apalis-v1.1.dtsi @@ -126,6 +126,13 @@ reg_usb_phy: regulator-usb-hsic1 { regulator-name = "usb-phy-dummy"; }; + reg_vref_1v8: regulator-vref-1v8 { + compatible = "regulator-fixed"; + regulator-name = "+V1.8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + reserved-memory { #address-cells = <2>; #size-cells = <2>; @@ -198,11 +205,32 @@ linux,cma { }; }; - /* TODO: Apalis Analogue Audio */ + sound { + compatible = "simple-audio-card"; + simple-audio-card,bitclock-master = <&dailink_master>; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&dailink_master>; + simple-audio-card,name = "apalis-imx8qm"; + + simple-audio-card,cpu { + sound-dai = <&sai1>; + }; + + dailink_master: simple-audio-card,codec { + sound-dai = <&sgtl5000>; + }; + }; /* TODO: HDMI Audio */ - /* TODO: Apalis SPDIF1 */ + /* Apalis SPDIF1 */ + sound-spdif { + compatible = "fsl,imx-audio-spdif"; + model = "imx-spdif"; + spdif-controller = <&spdif0>; + spdif-in; + spdif-out; + }; touchscreen: touchscreen { compatible = "toradex,vf50-touchscreen"; @@ -227,6 +255,10 @@ touchscreen: touchscreen { }; +&asrc0 { + fsl,asrc-rate = <48000>; +}; + &adc0 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_adc0>; @@ -239,6 +271,30 @@ &adc1 { /* TODO: Asynchronous Sample Rate Converter (ASRC) */ +&cpu_alert0 { + temperature = <95000>; +}; + +&cpu_alert1 { + temperature = <95000>; +}; + +&cpu_crit0 { + temperature = <105000>; +}; + +&cpu_crit1 { + temperature = <105000>; +}; + +&drc_alert0 { + temperature = <95000>; +}; + +&drc_crit0 { + temperature = <105000>; +}; + /* Apalis ETH1 */ &fec1 { pinctrl-names = "default", "sleep"; @@ -285,6 +341,22 @@ &flexcan3 { /* TODO: Apalis HDMI1 */ +&gpu_alert0 { + temperature = <95000>; +}; + +&gpu_alert1 { + temperature = <95000>; +}; + +&gpu_crit0 { + temperature = <105000>; +}; + +&gpu_crit1 { + temperature = <105000>; +}; + /* On-module I2C */ &i2c1 { pinctrl-names = "default"; @@ -294,8 +366,6 @@ &i2c1 { clock-frequency = <100000>; status = "okay"; - /* TODO: Audio Codec */ - /* USB3503A */ usb-hub@8 { compatible = "smsc,usb3503a"; @@ -308,6 +378,24 @@ usb-hub@8 { refclk-frequency = <25000000>; reset-gpios = <&lsio_gpio1 2 GPIO_ACTIVE_LOW>; }; + + /* On Module Audio Codec */ + sgtl5000: audio-codec@a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>, + <&mclkout0_lpcg IMX_LPCG_CLK_0>; + assigned-clock-rates = <786432000>, <49152000>, <12288000>, <12288000>; + clocks = <&mclkout0_lpcg IMX_LPCG_CLK_0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sgtl5000>; + #sound-dai-cells = <0>; + VDDA-supply = <®_module_3v3_avdd>; + VDDD-supply = <®_vref_1v8>; + VDDIO-supply = <®_module_3v3>; + }; }; /* Apalis I2C1 */ @@ -689,19 +777,48 @@ &mu2_m0 { /* TODO: Apalis BKL1_PWM */ -/* TODO: Apalis DAP1 */ - -/* TODO: Analogue Audio */ +/* Apalis DAP1 */ +&sai1 { + assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>, + <&sai1_lpcg IMX_LPCG_CLK_0>; + assigned-clock-rates = <786432000>, <49152000>, <12288000>, <49152000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai1>; + #sound-dai-cells = <0>; + status = "okay"; +}; /* TODO: Apalis SATA1 */ -/* TODO: Apalis SPDIF1 */ +/* Apalis SPDIF1 */ +&spdif0 { + assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>; + assigned-clock-rates = <786432000>, <49152000>, <12288000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spdif0>; + status = "okay"; +}; /* TODO: Thermal Zones */ /* TODO: Apalis USBH2, Apalis USBH3 and on-module Wi-Fi via on-module HSIC Hub */ -/* TODO: Apalis USBH4 */ +/* Apalis USBH4 */ +&usb3_phy { + status = "okay"; +}; + +&usbotg3 { + status = "okay"; +}; + +&usbotg3_cdns3 { + dr_mode = "host"; +}; /* Apalis USBO1 */ &usbphy1 { diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi index ff5df0fed9e96f..a60ebb718789fd 100644 --- a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi @@ -431,22 +431,19 @@ dsp_ram_lpcg: clock-controller@59590000 { }; dsp: dsp@596e8000 { - compatible = "fsl,imx8qxp-dsp"; + compatible = "fsl,imx8qxp-hifi4"; reg = <0x596e8000 0x88000>; clocks = <&dsp_lpcg IMX_LPCG_CLK_5>, <&dsp_ram_lpcg IMX_LPCG_CLK_4>, <&dsp_lpcg IMX_LPCG_CLK_7>; clock-names = "ipg", "ocram", "core"; - power-domains = <&pd IMX_SC_R_MU_13A>, - <&pd IMX_SC_R_MU_13B>, - <&pd IMX_SC_R_DSP>, - <&pd IMX_SC_R_DSP_RAM>; - mbox-names = "txdb0", "txdb1", - "rxdb0", "rxdb1"; - mboxes = <&lsio_mu13 2 0>, - <&lsio_mu13 2 1>, - <&lsio_mu13 3 0>, - <&lsio_mu13 3 1>; + power-domains = <&pd IMX_SC_R_MU_13B>, + <&pd IMX_SC_R_MU_2A>; + mbox-names = "tx", "rx", "rxdb"; + mboxes = <&lsio_mu13 0 0>, + <&lsio_mu13 1 0>, + <&lsio_mu13 3 0>; + firmware-name = "imx/dsp/hifi4.bin"; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi index a4a10ce03bfe0c..ce6ef160fd5506 100644 --- a/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-ss-conn.dtsi @@ -350,7 +350,7 @@ dma_apbh: dma-controller@5b810000 { power-domains = <&pd IMX_SC_R_NAND>; }; - gpmi: nand-controller@5b812000{ + gpmi: nand-controller@5b812000 { compatible = "fsl,imx8qxp-gpmi-nand"; reg = <0x5b812000 0x2000>, <0x5b814000 0x2000>; reg-names = "gpmi-nand", "bch"; diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-hsio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-hsio.dtsi new file mode 100644 index 00000000000000..70a8aa1a67911d --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8-ss-hsio.dtsi @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP + * + * Richard Zhu + */ +#include + +hsio_axi_clk: clock-hsio-axi { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <400000000>; + clock-output-names = "hsio_axi_clk"; +}; + +hsio_per_clk: clock-hsio-per { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <133333333>; + clock-output-names = "hsio_per_clk"; +}; + +hsio_refa_clk: clock-hsio-refa { + compatible = "gpio-gate-clock"; + clocks = <&xtal100m>; + #clock-cells = <0>; + enable-gpios = <&lsio_gpio4 27 GPIO_ACTIVE_LOW>; +}; + +hsio_refb_clk: clock-hsio-refb { + compatible = "gpio-gate-clock"; + clocks = <&xtal100m>; + #clock-cells = <0>; + enable-gpios = <&lsio_gpio4 1 GPIO_ACTIVE_LOW>; +}; + +xtal100m: clock-xtal100m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "xtal_100MHz"; +}; + +hsio_subsys: bus@5f000000 { + compatible = "simple-bus"; + ranges = <0x5f000000 0x0 0x5f000000 0x01000000>, + <0x80000000 0x0 0x70000000 0x10000000>; + #address-cells = <1>; + #size-cells = <1>; + dma-ranges = <0x80000000 0 0x80000000 0x80000000>; + + pcieb: pcie@5f010000 { + compatible = "fsl,imx8q-pcie"; + reg = <0x5f010000 0x10000>, + <0x8ff00000 0x80000>; + reg-names = "dbi", "config"; + ranges = <0x81000000 0 0x00000000 0x8ff80000 0 0x00010000>, + <0x82000000 0 0x80000000 0x80000000 0 0x0ff00000>; + #interrupt-cells = <1>; + interrupts = ; + interrupt-names = "msi"; + #address-cells = <3>; + #size-cells = <2>; + clocks = <&pcieb_lpcg IMX_LPCG_CLK_6>, + <&pcieb_lpcg IMX_LPCG_CLK_4>, + <&pcieb_lpcg IMX_LPCG_CLK_5>; + clock-names = "dbi", "mstr", "slv"; + bus-range = <0x00 0xff>; + device_type = "pci"; + interrupt-map = <0 0 0 1 &gic 0 105 4>, + <0 0 0 2 &gic 0 106 4>, + <0 0 0 3 &gic 0 107 4>, + <0 0 0 4 &gic 0 108 4>; + interrupt-map-mask = <0 0 0 0x7>; + num-lanes = <1>; + num-viewport = <4>; + power-domains = <&pd IMX_SC_R_PCIE_B>; + fsl,max-link-speed = <3>; + status = "disabled"; + }; + + pcieb_lpcg: clock-controller@5f060000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f060000 0x10000>; + clocks = <&hsio_axi_clk>, <&hsio_axi_clk>, <&hsio_axi_clk>; + #clock-cells = <1>; + clock-indices = , , ; + clock-output-names = "hsio_pcieb_mstr_axi_clk", + "hsio_pcieb_slv_axi_clk", + "hsio_pcieb_dbi_axi_clk"; + power-domains = <&pd IMX_SC_R_PCIE_B>; + }; + + phyx1_crr1_lpcg: clock-controller@5f0b0000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f0b0000 0x10000>; + clocks = <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = ; + clock-output-names = "hsio_phyx1_per_clk"; + power-domains = <&pd IMX_SC_R_SERDES_1>; + }; + + pcieb_crr3_lpcg: clock-controller@5f0d0000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f0d0000 0x10000>; + clocks = <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = ; + clock-output-names = "hsio_pcieb_per_clk"; + power-domains = <&pd IMX_SC_R_PCIE_B>; + }; + + misc_crr5_lpcg: clock-controller@5f0f0000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f0f0000 0x10000>; + clocks = <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = ; + clock-output-names = "hsio_misc_per_clk"; + power-domains = <&pd IMX_SC_R_HSIO_GPIO>; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts index 4caaecc1922771..6259186cd4d92e 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts @@ -182,6 +182,15 @@ mii_select: regulator-4 { regulator-always-on; }; + reg_pcieb: regulator-pcieb { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "reg_pcieb"; + gpio = <&pca6416_1 13 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + bt_sco_codec: audio-codec-bt { compatible = "linux,bt-sco"; #sound-dai-cells = <1>; @@ -567,6 +576,12 @@ &flexcan3 { status = "okay"; }; +&hsio_phy { + fsl,hsio-cfg = "pciea-x2-pcieb"; + fsl,refclk-pad-mode = "output"; + status = "okay"; +}; + &cm40_intmux { status = "disabled"; }; @@ -585,6 +600,16 @@ &lsio_gpio5 { status = "okay"; }; +&pcieb { + phys = <&hsio_phy 0 PHY_TYPE_PCIE 0>; + phy-names = "pcie-phy"; + pinctrl-0 = <&pinctrl_pcieb>; + pinctrl-names = "default"; + reset-gpio = <&lsio_gpio4 0 GPIO_ACTIVE_LOW>; + vpcie-supply = <®_pcieb>; + status = "okay"; +}; + &sai0 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sai0>; @@ -868,6 +893,14 @@ IMX8DXL_UART1_CTS_B_ADMA_UART1_CTS_B 0x06000020 >; }; + pinctrl_pcieb: pcieagrp { + fsl,pins = < + IMX8DXL_PCIE_CTRL0_PERST_B_LSIO_GPIO4_IO00 0x06000021 + IMX8DXL_PCIE_CTRL0_CLKREQ_B_LSIO_GPIO4_IO01 0x06000021 + IMX8DXL_PCIE_CTRL0_WAKE_B_LSIO_GPIO4_IO02 0x04000021 + >; + }; + pinctrl_sai0: sai0grp { fsl,pins = < IMX8DXL_SPI0_CS0_ADMA_SAI0_RXD 0x06000060 diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi index 1e02b04494e949..9b114bed084b8a 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi @@ -138,6 +138,10 @@ &gpmi { interrupts = ; }; +&usbphy1 { + compatible = "fsl,imx8dxl-usbphy", "fsl,imx7ulp-usbphy"; +}; + &usdhc1 { compatible = "fsl,imx8dxl-usdhc", "fsl,imx8qxp-usdhc"; interrupts = ; diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-hsio.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-hsio.dtsi new file mode 100644 index 00000000000000..afbe962d78ce1e --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-hsio.dtsi @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP + */ + +&hsio_subsys { + phyx1_lpcg: clock-controller@5f090000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f090000 0x10000>; + clocks = <&hsio_refb_clk>, <&hsio_per_clk>, + <&hsio_per_clk>, <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = , , + , ; + clock-output-names = "hsio_phyx1_pclk", + "hsio_phyx1_epcs_tx_clk", + "hsio_phyx1_epcs_rx_clk", + "hsio_phyx1_apb_clk"; + power-domains = <&pd IMX_SC_R_SERDES_1>; + }; + + hsio_phy: phy@5f1a0000 { + compatible = "fsl,imx8qxp-hsio"; + reg = <0x5f1a0000 0x10000>, + <0x5f120000 0x10000>, + <0x5f140000 0x10000>, + <0x5f160000 0x10000>; + reg-names = "reg", "phy", "ctrl", "misc"; + clocks = <&phyx1_lpcg IMX_LPCG_CLK_0>, + <&phyx1_lpcg IMX_LPCG_CLK_4>, + <&phyx1_crr1_lpcg IMX_LPCG_CLK_4>, + <&pcieb_crr3_lpcg IMX_LPCG_CLK_4>, + <&misc_crr5_lpcg IMX_LPCG_CLK_4>; + clock-names = "pclk0", "apb_pclk0", "phy0_crr", "ctl0_crr", + "misc_crr"; + #phy-cells = <3>; + power-domains = <&pd IMX_SC_R_SERDES_1>; + status = "disabled"; + }; +}; + +&pcieb { + #interrupt-cells = <1>; + interrupts = ; + interrupt-names = "msi"; + interrupt-map = <0 0 0 1 &gic 0 47 4>, + <0 0 0 2 &gic 0 48 4>, + <0 0 0 3 &gic 0 49 4>, + <0 0 0 4 &gic 0 50 4>; + interrupt-map-mask = <0 0 0 0x7>; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8dxl.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl.dtsi index 7e54cf20285808..a71d8b32c1920b 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl.dtsi @@ -30,6 +30,10 @@ aliases { gpio6 = &lsio_gpio6; gpio7 = &lsio_gpio7; mu1 = &lsio_mu1; + spi0 = &lpspi0; + spi1 = &lpspi1; + spi2 = &lpspi2; + spi3 = &lpspi3; }; cpus: cpus { @@ -237,12 +241,14 @@ xtal24m: clock-xtal24m { #include "imx8-ss-conn.dtsi" #include "imx8-ss-ddr.dtsi" #include "imx8-ss-lsio.dtsi" + #include "imx8-ss-hsio.dtsi" }; #include "imx8dxl-ss-adma.dtsi" #include "imx8dxl-ss-conn.dtsi" #include "imx8dxl-ss-lsio.dtsi" #include "imx8dxl-ss-ddr.dtsi" +#include "imx8dxl-ss-hsio.dtsi" &cm40_intmux { interrupts = , diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emtop-baseboard.dts b/arch/arm64/boot/dts/freescale/imx8mm-emtop-baseboard.dts index 7d2cb74c64eeee..90e638b8e92a95 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-emtop-baseboard.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-emtop-baseboard.dts @@ -1,6 +1,9 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright 2023 Emtop Embedded Solutions + * + * Author: Himanshu Bhavani + * Author: Tarang Raval */ /dts-v1/; @@ -11,6 +14,113 @@ / { model = "Emtop Embedded Solutions i.MX8M Mini Baseboard V1"; compatible = "ees,imx8mm-emtop-baseboard", "ees,imx8mm-emtop-som", "fsl,imx8mm"; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_otg>; + id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + + port { + high_speed_ep: endpoint { + remote-endpoint = <&usb_hs_ep>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_led>; + + led-1 { + label = "buzzer"; + gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + osc_can: clock-osc-can { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <16000000>; + clock-output-names = "osc-can"; + }; + + reg_audio: regulator-audio { + compatible = "regulator-fixed"; + regulator-name = "wm8904_supply"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + reg_wifi_vmmc: regulator-wifi-vmmc { + compatible = "regulator-fixed"; + regulator-name = "vmmc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 10 GPIO_ACTIVE_HIGH>; + enable-active-high; + startup-delay-us = <100>; + off-on-delay-us = <20000>; + }; + + sound-wm8904 { + compatible = "simple-audio-card"; + simple-audio-card,bitclock-master = <&dailink_master>; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&dailink_master>; + simple-audio-card,name = "wm8904-audio"; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "IN2L", "Line In Jack", + "IN2R", "Line In Jack", + "Headphone Jack", "MICBIAS", + "IN1L", "Headphone Jack"; + + simple-audio-card,widgets = + "Microphone","Headphone Jack", + "Headphone", "Headphone Jack", + "Line", "Line In Jack"; + + dailink_master: simple-audio-card,codec { + sound-dai = <&wm8904>; + }; + + simple-audio-card,cpu { + sound-dai = <&sai3>; + }; + }; + + sound-spdif { + compatible = "fsl,imx-audio-spdif"; + model = "imx-spdif"; + spdif-controller = <&spdif1>; + spdif-out; + spdif-in; + }; +}; + +/* CAN BUS */ +&ecspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + status = "okay"; + + can: can@0 { + compatible = "microchip,mcp2515"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_canbus>; + clocks = <&osc_can>; + interrupt-parent = <&gpio1>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <10000000>; + }; }; &fec1 { @@ -40,7 +150,135 @@ vddio: vddio-regulator { }; }; +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + wm8904: audio-codec@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + #sound-dai-cells = <0>; + clocks = <&clk IMX8MM_CLK_SAI3_ROOT>; + clock-names = "mclk"; + DCVDD-supply = <®_audio>; + DBVDD-supply = <®_audio>; + AVDD-supply = <®_audio>; + CPVDD-supply = <®_audio>; + MICVDD-supply = <®_audio>; + }; + + rtc@32 { + compatible = "epson,rx8025"; + reg = <0x32>; + }; +}; + +/* AUDIO */ +&sai3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai3>; + assigned-clocks = <&clk IMX8MM_CLK_SAI3>; + assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>; + assigned-clock-rates = <24576000>; + status = "okay"; +}; + +&spdif1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spdif1>; + assigned-clocks = <&clk IMX8MM_CLK_SPDIF1>; + assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>; + assigned-clock-rates = <24576000>; + clocks = <&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_24M>, + <&clk IMX8MM_CLK_SPDIF1>, <&clk IMX8MM_CLK_DUMMY>, + <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>, + <&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_DUMMY>, + <&clk IMX8MM_CLK_DUMMY>, <&clk IMX8MM_CLK_DUMMY>, + <&clk IMX8MM_AUDIO_PLL1_OUT>, <&clk IMX8MM_AUDIO_PLL2_OUT>; + clock-names = "core", "rxtx0", "rxtx1", "rxtx2", "rxtx3", + "rxtx4", "rxtx5", "rxtx6", "rxtx7", "spba", "pll8k", "pll11k"; + status = "okay"; +}; + +/* USBOTG */ +&usbotg1 { + dr_mode = "otg"; + usb-role-switch; + status = "okay"; + + port { + usb_hs_ep: endpoint { + remote-endpoint = <&high_speed_ep>; + }; + }; +}; + +&usbotg2 { + dr_mode = "host"; + status = "okay"; +}; + +/* Wifi */ +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>, <&pinctrl_usdhc1_gpio>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>, <&pinctrl_usdhc1_gpio>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>, <&pinctrl_usdhc1_gpio>; + bus-width = <4>; + vmmc-supply = <®_wifi_vmmc>; + cap-power-off-card; + keep-power-in-suspend; + non-removable; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + wifi: wifi@1 { + compatible = "brcm,bcm4329-fmac"; + reg = <1>; + interrupt-parent = <&gpio2>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "host-wake"; + }; +}; + +/* SD-card */ +&usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + bus-width = <4>; + status = "okay"; +}; + &iomuxc { + + pinctrl_canbus: canbusgrp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x14 + >; + }; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX8MM_IOMUXC_ECSPI2_SS0_ECSPI2_SS0 0x82 + MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI 0x82 + MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO 0x82 + MX8MM_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0x82 + >; + }; + + pinctrl_usb_otg: usbotggrp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x140 /* otg_id */ + MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x19 /* otg_vbus */ + >; + }; + pinctrl_fec1: fec1grp { fsl,pins = < MX8MM_IOMUXC_ENET_MDC_ENET1_MDC 0x3 @@ -60,4 +298,101 @@ MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f MX8MM_IOMUXC_SAI2_RXC_GPIO4_IO22 0x19 >; }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL 0x400001c3 + MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA 0x400001c3 + >; + }; + + pinctrl_sai3: sai3grp { + fsl,pins = < + MX8MM_IOMUXC_SAI3_TXFS_SAI3_TX_SYNC 0xd6 + MX8MM_IOMUXC_SAI3_TXC_SAI3_TX_BCLK 0xd6 + MX8MM_IOMUXC_SAI3_MCLK_SAI3_MCLK 0xd6 + MX8MM_IOMUXC_SAI3_TXD_SAI3_TX_DATA0 0xd6 + MX8MM_IOMUXC_SAI3_RXD_SAI3_RX_DATA0 0xd6 + >; + }; + + pinctrl_spdif1: spdif1grp { + fsl,pins = < + MX8MM_IOMUXC_SPDIF_TX_SPDIF1_OUT 0xd6 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x190 + MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD 0x1d0 + MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0 0x1d0 + MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1 0x1d0 + MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2 0x1d0 + MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3 0x1d0 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp{ + fsl,pins = < + MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x194 + MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD 0x1d4 + MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0 0x1d4 + MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1 0x1d4 + MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2 0x1d4 + MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3 0x1d4 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_SD1_CLK_USDHC1_CLK 0x196 + MX8MM_IOMUXC_SD1_CMD_USDHC1_CMD 0x1d6 + MX8MM_IOMUXC_SD1_DATA0_USDHC1_DATA0 0x1d6 + MX8MM_IOMUXC_SD1_DATA1_USDHC1_DATA1 0x1d6 + MX8MM_IOMUXC_SD1_DATA2_USDHC1_DATA2 0x1d6 + MX8MM_IOMUXC_SD1_DATA3_USDHC1_DATA3 0x1d6 + >; + }; + + pinctrl_usdhc1_gpio: usdhc1-gpiogrp { + fsl,pins = < + MX8MM_IOMUXC_SD1_RESET_B_GPIO2_IO10 0x41 /* wl_reg_on */ + MX8MM_IOMUXC_SD1_DATA7_GPIO2_IO9 0x41 /* wl_host_wake */ + MX8MM_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K 0x141 /* LP0: 32KHz */ + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x190 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d0 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d0 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d0 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d0 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x194 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d4 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d4 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d4 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d4 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d4 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_SD2_CLK_USDHC2_CLK 0x196 + MX8MM_IOMUXC_SD2_CMD_USDHC2_CMD 0x1d6 + MX8MM_IOMUXC_SD2_DATA0_USDHC2_DATA0 0x1d6 + MX8MM_IOMUXC_SD2_DATA1_USDHC2_DATA1 0x1d6 + MX8MM_IOMUXC_SD2_DATA2_USDHC2_DATA2 0x1d6 + MX8MM_IOMUXC_SD2_DATA3_USDHC2_DATA3 0x1d6 + >; + }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts index aab8e24216501e..a8ef4fba16a9e1 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-bl.dts @@ -25,6 +25,17 @@ osc_can: clock-osc-can { clock-output-names = "osc-can"; }; + hdmi-out { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_in_conn: endpoint { + remote-endpoint = <&bridge_out_conn>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -132,6 +143,86 @@ ethphy: ethernet-phy@0 { }; }; +&gpio4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio4>; + + dsi_mux_sel_hdmi: dsi-mux-sel-hdmi-hog { + gpio-hog; + gpios = <14 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "dsi-mux-sel"; + }; + + dsi_mux_sel_lvds: dsi-mux-sel-lvds-hog { + gpio-hog; + gpios = <14 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "dsi-mux-sel"; + status = "disabled"; + }; + + dsi-mux-oe-hog { + gpio-hog; + gpios = <15 GPIO_ACTIVE_LOW>; + output-high; + line-name = "dsi-mux-oe"; + }; +}; + +&i2c3 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + lvds: bridge@2c { + compatible = "ti,sn65dsi84"; + reg = <0x2c>; + enable-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sn65dsi84>; + status = "disabled"; + }; + + hdmi: hdmi@39 { + compatible = "adi,adv7535"; + reg = <0x39>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adv7535>; + adi,dsi-lanes = <4>; + interrupt-parent = <&gpio4>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + a2vdd-supply = <®_vdd_1v8>; + avdd-supply = <®_vdd_1v8>; + dvdd-supply = <®_vdd_1v8>; + pvdd-supply = <®_vdd_1v8>; + v1p2-supply = <®_vdd_1v8>; + v3p3-supply = <®_vdd_3v3>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + bridge_in_dsi_hdmi: endpoint { + remote-endpoint = <&mipi_dsi_out>; + }; + }; + + port@1 { + reg = <1>; + + bridge_out_conn: endpoint { + remote-endpoint = <&hdmi_in_conn>; + }; + }; + }; + }; +}; + &i2c4 { clock-frequency = <100000>; pinctrl-names = "default"; @@ -144,6 +235,19 @@ rx8900: rtc@32 { }; }; +&lcdif { + status = "okay"; +}; + +&mipi_dsi { + samsung,esc-clock-frequency = <54000000>; + status = "okay"; +}; + +&mipi_dsi_out { + remote-endpoint = <&bridge_in_dsi_hdmi>; +}; + &pwm2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm2>; @@ -207,6 +311,12 @@ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpio>; + pinctrl_adv7535: adv7535grp { + fsl,pins = < + MX8MM_IOMUXC_SAI1_TXD4_GPIO4_IO16 0x19 + >; + }; + pinctrl_can: cangrp { fsl,pins = < MX8MM_IOMUXC_SAI3_RXFS_GPIO4_IO28 0x19 @@ -277,6 +387,20 @@ MX8MM_IOMUXC_SAI3_MCLK_GPIO5_IO2 0x19 >; }; + pinctrl_gpio4: gpio4grp { + fsl,pins = < + MX8MM_IOMUXC_SAI1_TXD2_GPIO4_IO14 0x19 + MX8MM_IOMUXC_SAI1_TXD3_GPIO4_IO15 0x19 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL 0x40000083 + MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA 0x40000083 + >; + }; + pinctrl_i2c4: i2c4grp { fsl,pins = < MX8MM_IOMUXC_I2C4_SCL_I2C4_SCL 0x40000083 @@ -290,6 +414,13 @@ MX8MM_IOMUXC_SPDIF_RX_PWM2_OUT 0x19 >; }; + pinctrl_sn65dsi84: sn65dsi84grp { + fsl,pins = < + MX8MM_IOMUXC_SAI2_TXD0_GPIO4_IO26 0x19 + MX8MM_IOMUXC_SD2_WP_GPIO2_IO20 0x19 + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX8MM_IOMUXC_SAI2_RXC_UART1_DCE_RX 0x0 diff --git a/arch/arm64/boot/dts/freescale/imx8mm-kontron-dl.dtso b/arch/arm64/boot/dts/freescale/imx8mm-kontron-dl.dtso new file mode 100644 index 00000000000000..1db27731b581ce --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-kontron-dl.dtso @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Kontron Electronics GmbH + */ + +/dts-v1/; +/plugin/; + +#include +#include "imx8mm-pinfunc.h" + +&{/} { + compatible = "kontron,imx8mm-bl", "kontron,imx8mm-sl", "fsl,imx8mm"; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 50000 0>; + brightness-levels = <0 100>; + num-interpolated-steps = <100>; + default-brightness-level = <100>; + }; + + panel { + compatible = "jenson,bl-jt60050-01a", "panel-lvds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_panel>; + backlight = <&backlight>; + data-mapping = "vesa-24"; + enable-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; + height-mm = <86>; + width-mm = <154>; + + panel-timing { + clock-frequency = <51200000>; + hactive = <1024>; + vactive = <600>; + hsync-len = <1>; + hfront-porch = <160>; + hback-porch = <160>; + vsync-len = <1>; + vfront-porch = <12>; + vback-porch = <23>; + }; + + port { + panel_out_bridge: endpoint { + remote-endpoint = <&bridge_out_panel>; + }; + }; + }; +}; + +&dsi_mux_sel_hdmi { + status = "disabled"; +}; + +&dsi_mux_sel_lvds { + status = "okay"; +}; + +&mipi_dsi_out { + remote-endpoint = <&bridge_in_dsi_lvds>; +}; + +&gpio3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio3>; + + panel-rst-hog { + gpio-hog; + gpios = <20 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "panel-reset"; + }; + + panel-stby-hog { + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "panel-standby"; + }; + + panel-hinv-hog { + gpio-hog; + gpios = <24 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "panel-horizontal-invert"; + }; + + panel-vinv-hog { + gpio-hog; + gpios = <25 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "panel-vertical-invert"; + }; +}; + +&hdmi { + status = "disabled"; +}; + +&i2c2 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + touchscreen@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_touch>; + interrupt-parent = <&gpio3>; + interrupts = <22 8>; + reset-gpios = <&gpio3 23 0>; + irq-gpios = <&gpio3 22 0>; + }; +}; + +&lvds { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + bridge_in_dsi_lvds: endpoint { + remote-endpoint = <&mipi_dsi_out>; + data-lanes = <1 2>; + }; + }; + + port@2 { + reg = <2>; + + bridge_out_panel: endpoint { + remote-endpoint = <&panel_out_bridge>; + }; + }; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; + status = "okay"; +}; + +&iomuxc { + pinctrl_gpio3: gpio3grp { + fsl,pins = < + MX8MM_IOMUXC_SAI5_RXD3_GPIO3_IO24 0x19 + MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20 0x19 + MX8MM_IOMUXC_SAI5_RXD0_GPIO3_IO21 0x19 + MX8MM_IOMUXC_SAI5_MCLK_GPIO3_IO25 0x19 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MM_IOMUXC_I2C2_SCL_I2C2_SCL 0x40000083 + MX8MM_IOMUXC_I2C2_SDA_I2C2_SDA 0x40000083 + >; + }; + + pinctrl_panel: panelgrp { + fsl,pins = < + MX8MM_IOMUXC_SAI5_RXFS_GPIO3_IO19 0x19 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX8MM_IOMUXC_SPDIF_EXT_CLK_PWM1_OUT 0x6 + >; + }; + + pinctrl_touch: touchgrp { + fsl,pins = < + MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22 0x19 + MX8MM_IOMUXC_SAI5_RXD2_GPIO3_IO23 0x19 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts index 01b632b220dc74..b941c8c4f7bb44 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts @@ -75,6 +75,11 @@ expander2: gpio@27 { }; }; +&mipi_dsi { + samsung,burst-clock-frequency = <891000000>; + samsung,esc-clock-frequency = <20000000>; +}; + &pcie_phy { fsl,refclk-pad-mode = ; fsl,clkreq-unsupported; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi index 36803b038cd54a..5a3b1142ddf4b7 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw700x.dtsi @@ -9,6 +9,11 @@ #include / { + aliases { + rtc0 = &gsc_rtc; + rtc1 = &snvs_rtc; + }; + memory@40000000 { device_type = "memory"; reg = <0x0 0x40000000 0 0x80000000>; @@ -292,7 +297,7 @@ eeprom@53 { pagesize = <16>; }; - rtc@68 { + gsc_rtc: rtc@68 { compatible = "dallas,ds1672"; reg = <0x68>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dtso b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dtso index 9bee7159a67b57..b1a9f35e1dfa78 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dtso +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs232-rts.dtso @@ -15,10 +15,6 @@ /dts-v1/; /plugin/; -&{/} { - compatible = "gw,imx8mm-gw73xx-0x"; -}; - &gpio4 { rs485-en-hog { gpio-hog; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dtso b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dtso index e98f50bcec57fe..44ebc0a58c51af 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dtso +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs422.dtso @@ -18,10 +18,6 @@ /dts-v1/; /plugin/; -&{/} { - compatible = "gw,imx8mm-gw73xx-0x"; -}; - &gpio4 { rs485-en-hog { gpio-hog; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dtso b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dtso index e875ff4637bd51..2f8a7ac4087398 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dtso +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx-0x-rs485.dtso @@ -18,10 +18,6 @@ /dts-v1/; /plugin/; -&{/} { - compatible = "gw,imx8mm-gw73xx-0x"; -}; - &gpio4 { rs485-en-hog { gpio-hog; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw75xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw75xx.dtsi index 5eb92005195cfe..53004c4a13aad5 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw75xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw75xx.dtsi @@ -116,6 +116,16 @@ &i2c2 { pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; + accelerometer@19 { + compatible = "st,lis2de12"; + reg = <0x19>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_accel>; + interrupt-parent = <&gpio5>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + st,drdy-int-pin = <1>; + }; + eeprom@52 { compatible = "atmel,24c32"; reg = <0x52>; @@ -198,6 +208,12 @@ MX8MM_IOMUXC_SPDIF_RX_GPIO5_IO4 0x40000040 /* GPIOC */ >; }; + pinctrl_accel: accelgrp { + fsl,pins = < + MX8MM_IOMUXC_ECSPI1_MISO_GPIO5_IO8 0x159 + >; + }; + pinctrl_gpio_leds: gpioledgrp { fsl,pins = < MX8MM_IOMUXC_SAI1_RXFS_GPIO4_IO0 0x6 /* LEDG */ diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts index 35ae0faa815bc5..d8b67e12f7d747 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts @@ -22,6 +22,8 @@ aliases { ethernet2 = &lan2; ethernet3 = &lan3; ethernet4 = &lan4; + rtc0 = &gsc_rtc; + rtc1 = &snvs_rtc; usb0 = &usbotg1; usb1 = &usbotg2; }; @@ -497,7 +499,7 @@ eeprom@53 { pagesize = <16>; }; - rtc@68 { + gsc_rtc: rtc@68 { compatible = "dallas,ds1672"; reg = <0x68>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts index c11260c26d0b43..46d1ee0a4ee86b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts @@ -19,6 +19,8 @@ / { aliases { ethernet1 = ð1; + rtc0 = &gsc_rtc; + rtc1 = &snvs_rtc; usb0 = &usbotg1; usb1 = &usbotg2; }; @@ -564,7 +566,7 @@ eeprom@53 { pagesize = <16>; }; - rtc@68 { + gsc_rtc: rtc@68 { compatible = "dallas,ds1672"; reg = <0x68>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts index db1737bf637df1..c0aadff4e25b18 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7903.dts @@ -18,6 +18,8 @@ / { aliases { ethernet0 = &fec1; + rtc0 = &gsc_rtc; + rtc1 = &snvs_rtc; usb0 = &usbotg1; }; @@ -394,7 +396,7 @@ eeprom@53 { pagesize = <16>; }; - rtc@68 { + gsc_rtc: rtc@68 { compatible = "dallas,ds1672"; reg = <0x68>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts index 05489a31e7fd8d..86a610de84fe23 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7904.dts @@ -16,6 +16,11 @@ / { model = "Gateworks Venice GW7904 i.MX8MM board"; compatible = "gateworks,imx8mm-gw7904", "fsl,imx8mm"; + aliases { + rtc0 = &gsc_rtc; + rtc1 = &snvs_rtc; + }; + chosen { stdout-path = &uart2; }; @@ -438,7 +443,7 @@ eeprom@53 { pagesize = <16>; }; - rtc@68 { + gsc_rtc: rtc@68 { compatible = "dallas,ds1672"; reg = <0x68>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-ivy.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ivy.dtsi new file mode 100644 index 00000000000000..29075ff5eda63b --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ivy.dtsi @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + * + * Common dtsi for Verdin IMX8MM SoM on Ivy carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-mini-nano + * https://www.toradex.com/products/carrier-board/ivy-carrier-board + */ + +#include +#include + +/ { + /* AIN1 Voltage w/o AIN1_MODE gpio control */ + ain1_voltage_unmanaged: voltage-divider-ain1 { + compatible = "voltage-divider"; + #io-channel-cells = <1>; + io-channels = <&ivy_adc1 0>; + full-ohms = <19>; + output-ohms = <1>; + }; + + /* AIN1 Current w/o AIN1_MODE gpio control */ + ain1_current_unmanaged: current-sense-shunt-ain1 { + compatible = "current-sense-shunt"; + #io-channel-cells = <0>; + io-channels = <&ivy_adc1 1>; + shunt-resistor-micro-ohms = <100000000>; + }; + + /* AIN1_MODE - SODIMM 216 */ + ain1_mode_mux_ctrl: mux-controller-0 { + compatible = "gpio-mux"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio5>; + #mux-control-cells = <0>; + mux-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>; + }; + + ain1-voltage { + compatible = "io-channel-mux"; + channels = "ain1_voltage", ""; + io-channels = <&ain1_voltage_unmanaged 0>; + io-channel-names = "parent"; + mux-controls = <&ain1_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + ain1-current { + compatible = "io-channel-mux"; + channels = "", "ain1_current"; + io-channels = <&ain1_current_unmanaged>; + io-channel-names = "parent"; + mux-controls = <&ain1_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + /* AIN2 Voltage w/o AIN2_MODE gpio control */ + ain2_voltage_unmanaged: voltage-divider-ain2 { + compatible = "voltage-divider"; + #io-channel-cells = <1>; + io-channels = <&ivy_adc2 0>; + full-ohms = <19>; + output-ohms = <1>; + }; + + /* AIN2 Current w/o AIN2_MODE gpio control */ + ain2_current_unmanaged: current-sense-shunt-ain2 { + compatible = "current-sense-shunt"; + #io-channel-cells = <0>; + io-channels = <&ivy_adc2 1>; + shunt-resistor-micro-ohms = <100000000>; + }; + + /* AIN2_MODE - SODIMM 218 */ + ain2_mode_mux_ctrl: mux-controller-1 { + compatible = "gpio-mux"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio6>; + #mux-control-cells = <0>; + mux-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; + }; + + ain2-voltage { + compatible = "io-channel-mux"; + channels = "ain2_voltage", ""; + io-channels = <&ain2_voltage_unmanaged 0>; + io-channel-names = "parent"; + mux-controls = <&ain2_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + ain2-current { + compatible = "io-channel-mux"; + channels = "", "ain2_current"; + io-channels = <&ain2_current_unmanaged>; + io-channel-names = "parent"; + mux-controls = <&ain2_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ivy_leds>; + + /* D7 Blue - SODIMM 30 - LEDs.GPIO1 */ + led-0 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&gpio4 25 GPIO_ACTIVE_HIGH>; + }; + + /* D7 Green - SODIMM 32 - LEDs.GPIO2 */ + led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>; + }; + + /* D7 Red - SODIMM 34 - LEDs.GPIO3 */ + led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Blue - SODIMM 36 - LEDs.GPIO4 */ + led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&gpio4 23 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Green - SODIMM 54 - LEDs.GPIO5 */ + led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Red - SODIMM 44 - LEDs.GPIO6 */ + led-5 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>; + }; + + /* D9 Blue - SODIMM 46 - LEDs.GPIO7 */ + led-6 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <3>; + gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>; + }; + + /* D9 Red - SODIMM 48 - LEDs.GPIO8 */ + led-7 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <3>; + gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + }; + }; + + reg_3v2_ain1: regulator-3v2-ain1 { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3200000>; + regulator-min-microvolt = <3200000>; + regulator-name = "+3V2_AIN1"; + }; + + reg_3v2_ain2: regulator-3v2-ain2 { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3200000>; + regulator-min-microvolt = <3200000>; + regulator-name = "+3V2_AIN2"; + }; + + /* Ivy Power Supply Input Voltage */ + ivy-input-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_1 */ + io-channels = <&verdin_som_adc 7>; + full-ohms = <204700>; /* 200k + 4.7k */ + output-ohms = <4700>; + }; + + ivy-5v-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_2 */ + io-channels = <&verdin_som_adc 6>; + full-ohms = <39000>; /* 27k + 12k */ + output-ohms = <12000>; + }; + + ivy-3v3-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_3 */ + io-channels = <&verdin_som_adc 5>; + full-ohms = <54000>; /* 27k + 27k */ + output-ohms = <27000>; + }; + + ivy-1v8-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_4 */ + io-channels = <&verdin_som_adc 4>; + full-ohms = <39000>; /* 12k + 27k */ + output-ohms = <27000>; + }; +}; + +/* Verdin SPI_1 */ +&ecspi2 { + pinctrl-0 = <&pinctrl_ecspi2>, + <&pinctrl_gpio1>, + <&pinctrl_gpio4>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, + <&gpio3 4 GPIO_ACTIVE_LOW>, + <&gpio5 27 GPIO_ACTIVE_LOW>; + status = "okay"; + + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + spi-max-frequency = <18500000>; + }; + + fram@2 { + compatible = "fujitsu,mb85rs256", "atmel,at25"; + reg = <2>; + address-width = <16>; + size = <32768>; + spi-max-frequency = <33000000>; + pagesize = <1>; + }; +}; + +/* EEPROM on Ivy */ +&eeprom_carrier_board { + status = "okay"; +}; + +/* Verdin ETH_1 */ +&fec1 { + status = "okay"; +}; + +&gpio3 { + gpio-line-names = + "", /* 0 */ + "", + "REL3", /* SODIMM 64 */ + "", + "", + "", + "DIG_1", /* SODIMM 56 */ + "DIG_2", /* SODIMM 58 */ + "REL1", /* SODIMM 60 */ + "REL2", /* SODIMM 62 */ + "", /* 10 */ + "", + "", + "", + "REL4", /* SODIMM 66 */ + "", + "", + "", + "", + "", + "", /* 20 */ + "", + "", + "", + "", + ""; +}; + +&gpio5 { + gpio-line-names = + "", /* 0 */ + "", + "", + "", + "", + "GPIO2", /* Verdin GPIO_2 - SODIMM 208 */ + "", + "", + "", + "", + "", /* 10 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 20 */ + "", + "", + "", + "", + "", + "GPIO3", /* Verdin GPIO_3 - SODIMM 210 */ + "", + "", + ""; +}; + +/* Temperature sensor on Ivy */ +&hwmon_temp { + compatible = "ti,tmp1075"; + status = "okay"; +}; + +/* Verdin I2C_4 CSI */ +&i2c3 { + status = "okay"; + + ivy_adc1: adc@40 { + compatible = "ti,ads1119"; + reg = <0x40>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio7>; + interrupt-parent = <&gpio1>; + interrupts = <8 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <®_3v2_ain1>; + dvdd-supply = <®_3v2_ain1>; + vref-supply = <®_3v2_ain1>; + #address-cells = <1>; + #io-channel-cells = <1>; + #size-cells = <0>; + + /* AIN1 0-33V Voltage Input */ + channel@0 { + reg = <0>; + diff-channels = <0 1>; + }; + + /* AIN1 0-20mA Current Input */ + channel@1 { + reg = <1>; + diff-channels = <2 3>; + }; + }; + + ivy_adc2: adc@41 { + compatible = "ti,ads1119"; + reg = <0x41>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio8>; + interrupt-parent = <&gpio1>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <®_3v2_ain2>; + dvdd-supply = <®_3v2_ain2>; + vref-supply = <®_3v2_ain2>; + #address-cells = <1>; + #io-channel-cells = <1>; + #size-cells = <0>; + + /* AIN2 0-33V Voltage Input */ + channel@0 { + reg = <0>; + diff-channels = <0 1>; + }; + + /* AIN2 0-20mA Current Input */ + channel@1 { + reg = <1>; + diff-channels = <2 3>; + }; + }; +}; + +/* Verdin I2C_1 */ +&i2c4 { + status = "okay"; +}; + +/* Verdin PCIE_1 */ +&pcie0 { + status = "okay"; +}; + +&pcie_phy { + status = "okay"; +}; + +/* Verdin UART_3 */ +&uart1 { + status = "okay"; +}; + +/* Verdin UART_1 */ +&uart2 { + status = "okay"; +}; + +/* Verdin UART_2 */ +&uart3 { + linux,rs485-enabled-at-boot-time; + rs485-rx-during-tx; + status = "okay"; +}; + +/* Verdin USB_1*/ +&usbotg1 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usbotg2 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&usdhc2 { + status = "okay"; +}; + +&iomuxc { + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio2>, <&pinctrl_gpio3>, + <&pinctrl_ivy_dig_inputs>, <&pinctrl_ivy_relays>; + + pinctrl_ivy_dig_inputs: ivydiginputsgrp { + fsl,pins = + , /* SODIMM 56 */ + ; /* SODIMM 58 */ + }; + + pinctrl_ivy_leds: ivyledsgrp { + fsl,pins = + , /* SODIMM 30 */ + , /* SODIMM 32 */ + , /* SODIMM 34 */ + , /* SODIMM 36 */ + , /* SODIMM 44 */ + , /* SODIMM 46 */ + , /* SODIMM 48 */ + ; /* SODIMM 54 */ + }; + + pinctrl_ivy_relays: ivyrelaysgrp { + fsl,pins = + , /* SODIMM 60 */ + , /* SODIMM 62 */ + , /* SODIMM 64 */ + ; /* SODIMM 66 */ + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-ivy.dts b/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-ivy.dts new file mode 100644 index 00000000000000..82b34a12ee2b3b --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-ivy.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + */ + +/dts-v1/; + +#include "imx8mm-verdin.dtsi" +#include "imx8mm-verdin-nonwifi.dtsi" +#include "imx8mm-verdin-ivy.dtsi" + +/ { + model = "Toradex Verdin iMX8M Mini on Ivy"; + compatible = "toradex,verdin-imx8mm-nonwifi-ivy", + "toradex,verdin-imx8mm-nonwifi", + "toradex,verdin-imx8mm", + "fsl,imx8mm"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-ivy.dts b/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-ivy.dts new file mode 100644 index 00000000000000..3369ba852b5c0a --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-ivy.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + */ + +/dts-v1/; + +#include "imx8mm-verdin.dtsi" +#include "imx8mm-verdin-wifi.dtsi" +#include "imx8mm-verdin-ivy.dtsi" + +/ { + model = "Toradex Verdin iMX8M Mini WB on Ivy"; + compatible = "toradex,verdin-imx8mm-wifi-ivy", + "toradex,verdin-imx8mm-wifi", + "toradex,verdin-imx8mm", + "fsl,imx8mm"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi index 5fa39591419115..c528594ac4428e 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi @@ -162,7 +162,7 @@ reg_usdhc2_vmmc: regulator-usdhc2 { regulator-max-microvolt = <3300000>; regulator-min-microvolt = <3300000>; regulator-name = "+V3.3_SD"; - startup-delay-us = <2000>; + startup-delay-us = <20000>; }; reserved-memory { @@ -367,6 +367,7 @@ &i2c1 { pinctrl-1 = <&pinctrl_i2c1_gpio>; scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; status = "okay"; pca9450: pmic@25 { @@ -483,11 +484,12 @@ rtc_i2c: rtc@32 { reg = <0x32>; }; - adc@49 { + verdin_som_adc: adc@49 { compatible = "ti,ads1015"; reg = <0x49>; #address-cells = <1>; #size-cells = <0>; + #io-channel-cells = <1>; /* Verdin I2C_1 (ADC_4 - ADC_3) */ channel@0 { @@ -561,6 +563,7 @@ &i2c2 { pinctrl-1 = <&pinctrl_i2c2_gpio>; scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; status = "disabled"; }; @@ -574,6 +577,7 @@ &i2c3 { pinctrl-1 = <&pinctrl_i2c3_gpio>; scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; }; /* Verdin I2C_1 */ @@ -584,6 +588,7 @@ &i2c4 { pinctrl-1 = <&pinctrl_i2c4_gpio>; scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; gpio_expander_21: gpio-expander@21 { compatible = "nxp,pcal6416"; diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index 9535dedcef59b0..4de3bf22902b5b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -1375,9 +1375,11 @@ pcie0: pcie@33800000 { pcie0_ep: pcie-ep@33800000 { compatible = "fsl,imx8mm-pcie-ep"; - reg = <0x33800000 0x400000>, - <0x18000000 0x8000000>; - reg-names = "dbi", "addr_space"; + reg = <0x33800000 0x100000>, + <0x18000000 0x8000000>, + <0x33900000 0x100000>, + <0x33b00000 0x100000>; + reg-names = "dbi", "addr_space", "dbi2", "atu"; num-lanes = <1>; interrupts = ; interrupt-names = "dma"; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx-usbotg.dtso b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx-usbotg.dtso index 96db07fc9becea..1f2a0fe70a0a26 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx-usbotg.dtso +++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx-usbotg.dtso @@ -29,12 +29,37 @@ usb_dr_connector: endpoint { }; }; +/* + * rst_usb_hub_hog and sel_usb_hub_hog have property 'output-high', + * dt overlay don't support /delete-property/. Both 'output-low' and + * 'output-high' will be exist under hog nodes if overlay file set + * 'output-low'. Workaround is disable these hog and create new hog with + * 'output-low'. + */ + &rst_usb_hub_hog { - output-low; + status = "disabled"; +}; + +&expander0 { + rst-usb-low-hub-hog { + gpio-hog; + gpios = <13 0>; + output-low; + line-name = "RST_USB_HUB#"; + }; }; &sel_usb_hub_hog { - output-low; + status = "disabled"; +}; + +&gpio2 { + sel-usb-low-hub-hog { + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + output-low; + }; }; &usbotg1 { diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts index 433d8bba44255e..dc94d73f7106c1 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts @@ -64,6 +64,11 @@ expander2: gpio@27 { }; }; +&mipi_dsi { + samsung,burst-clock-frequency = <891000000>; + samsung,esc-clock-frequency = <20000000>; +}; + &sai3 { assigned-clocks = <&clk IMX8MN_CLK_SAI3>; assigned-clock-parents = <&clk IMX8MN_AUDIO_PLL1_OUT>; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts index 0b1fa04f1d6781..30c286b34aa535 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts +++ b/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts @@ -17,6 +17,8 @@ / { compatible = "gw,imx8mn-gw7902", "fsl,imx8mn"; aliases { + rtc0 = &gsc_rtc; + rtc1 = &snvs_rtc; usb0 = &usbotg1; }; @@ -562,7 +564,7 @@ eeprom@53 { pagesize = <16>; }; - rtc@68 { + gsc_rtc: rtc@68 { compatible = "dallas,ds1672"; reg = <0x68>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-drc02.dts b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-drc02.dts new file mode 100644 index 00000000000000..c6bf7fd9198140 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-drc02.dts @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2024 Marek Vasut + * + * DHCOM iMX8MP variant: + * DHCM-iMX8ML8-C160-R204-F1638-SPI16-E2-CAN2-RTC-I-01D2 + * DHCOM PCB number: 660-100 or newer + * DRC02 PCB number: 568-100 or newer + */ + +/dts-v1/; + +#include +#include +#include "imx8mp-dhcom-som.dtsi" + +/ { + model = "DH electronics i.MX8M Plus DHCOM on DRC02"; + compatible = "dh,imx8mp-dhcom-drc02", "dh,imx8mp-dhcom-som", + "fsl,imx8mp"; + + chosen { + stdout-path = &uart1; + }; +}; + +&eqos { /* First ethernet */ + pinctrl-0 = <&pinctrl_eqos_rmii>; + phy-handle = <ðphy0f>; + phy-mode = "rmii"; + + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_266M>, + <&clk IMX8MP_SYS_PLL2_100M>, + <&clk IMX8MP_SYS_PLL2_50M>; + assigned-clock-rates = <0>, <100000000>, <50000000>; +}; + +ðphy0g { /* Micrel KSZ9131RNXI */ + status = "disabled"; +}; + +ðphy0f { /* SMSC LAN8740Ai */ + status = "okay"; +}; + +&fec { /* Second ethernet */ + pinctrl-0 = <&pinctrl_fec_rmii>; + phy-handle = <ðphy1f>; + phy-mode = "rmii"; + status = "okay"; + + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_266M>, + <&clk IMX8MP_SYS_PLL2_100M>, + <&clk IMX8MP_SYS_PLL2_50M>, + <&clk IMX8MP_SYS_PLL2_50M>; + assigned-clock-rates = <0>, <100000000>, <50000000>, <0>; +}; + +ðphy1f { /* SMSC LAN8740Ai */ + status = "okay"; +}; + +&flexcan1 { + status = "okay"; +}; + +&flexcan2 { + status = "okay"; +}; + +&gpio1 { + gpio-line-names = + "DRC02-In1", "", "", "", "", "DHCOM-I", "DRC02-HW2", "DRC02-HW0", + "DHCOM-B", "DHCOM-A", "", "DHCOM-H", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", ""; + + /* + * NOTE: On DRC02, the RS485_RX_En is controlled by a separate + * GPIO line, however the i.MX8 UART driver assumes RX happens + * during TX anyway and that it only controls drive enable DE + * line. Hence, the RX is always enabled here. + */ + rs485-rx-en-hog { + gpio-hog; + gpios = <13 0>; /* GPIO Q */ + line-name = "rs485-rx-en"; + output-low; + }; +}; + +&gpio2 { + gpio-line-names = + "", "", "", "", "", "", "", "", + "DHCOM-O", "DHCOM-N", "", "SOM-HW1", "", "", "", "", + "", "", "", "", "DRC02-In2", "", "", "", + "", "", "", "", "", "", "", ""; +}; + +&gpio3 { + gpio-line-names = + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "SOM-HW0", "", + "", "", "", "", "", "", "SOM-MEM0", "SOM-MEM1", + "SOM-MEM2", "SOM-HW2", "", "", "", "", "", ""; +}; + +&gpio4 { + gpio-line-names = + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "SOM-HW1", "", "", "", "", + "", "", "", "DRC02-Out2", "", "", "", ""; +}; + +&gpio5 { + gpio-line-names = + "", "", "DHCOM-C", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "DHCOM-E", "DRC02-Out1", + "", "", "", "", "", "", "", ""; +}; + +/* No HS connector on this SoM variant, so no HDMI, PCIe and only USB HS. */ +&hdmi_blk_ctrl { + status = "disabled"; +}; + +&hdmi_pvi { + status = "disabled"; +}; + +&hdmi_tx { + status = "disabled"; +}; + +&hdmi_tx_phy { + status = "disabled"; +}; + +&i2c3 { + /* Resistive touch controller not populated on this one SoM variant. */ + touchscreen@49 { + status = "disabled"; + }; +}; + +&irqsteer_hdmi { + status = "disabled"; +}; + +&lcdif3 { + status = "disabled"; +}; + +&pcie_phy { + status = "disabled"; +}; + +&pcie { + status = "disabled"; +}; + +/* Console UART */ +&pinctrl_uart1 { + fsl,pins = < + /* No pull-ups on DRC02, enable in-SoC pull-ups */ + MX8MP_IOMUXC_SAI2_RXC__UART1_DCE_RX 0x149 + MX8MP_IOMUXC_SAI2_RXFS__UART1_DCE_TX 0x149 + >; +}; + +&pinctrl_uart3 { + fsl,pins = < + /* No pull-ups on DRC02, enable in-SoC pull-ups */ + MX8MP_IOMUXC_ECSPI1_SCLK__UART3_DCE_RX 0x149 + MX8MP_IOMUXC_ECSPI1_MOSI__UART3_DCE_TX 0x149 + >; +}; + +&uart1 { + /* + * Due to the use of CAN2 the signals for CAN2 Tx and Rx are routed to + * DHCOM UART1 RTS/CTS pins. Therefore this UART have to use DHCOM GPIOs + * for RTS/CTS. So configure DHCOM GPIO I as RTS and GPIO M as CTS. + */ + /delete-property/ uart-has-rtscts; + cts-gpios = <&gpio5 5 GPIO_ACTIVE_HIGH>; /* GPIO M */ + pinctrl-0 = <&pinctrl_uart1 &pinctrl_dhcom_i &pinctrl_dhcom_m>; + pinctrl-names = "default"; + rts-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; /* GPIO I */ +}; + +&uart3 { + /* + * On DRC02 this UART is used as RS485 interface and RS485_TX_En is + * controlled by DHCOM GPIO P. So remove RTS/CTS pins and the property + * uart-has-rtscts from this UART and add the DHCOM GPIO P pin via + * rts-gpios. The RS485_RX_En is controlled by DHCOM GPIO Q, see gpio1 + * node above. + */ + /delete-property/ uart-has-rtscts; + linux,rs485-enabled-at-boot-time; + pinctrl-0 = <&pinctrl_uart3 &pinctrl_dhcom_p &pinctrl_dhcom_q>; + pinctrl-names = "default"; + rts-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; /* GPIO P */ +}; + +/* No WiFi/BT chipset on this SoM variant. */ +&uart2 { + bluetooth { + status = "disabled"; + }; +}; + +/* USB_OTG port is not routed out on DRC02. */ +&usb3_0 { + status = "disabled"; +}; + +&usb_dwc3_0 { + status = "disabled"; +}; + +/* USB_HOST port has USB Hub connected to it, PWR/OC pins are unused */ +&usb3_1 { + fsl,disable-port-power-control; + fsl,permanently-attached; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + maximum-speed = "high-speed"; +}; + +/* No WiFi/BT chipset on this SoM variant. */ +&usdhc1 { + status = "disabled"; +}; + +&iomuxc { + /* + * GPIO I is connected to UART1_RTS + * GPIO M is connected to UART1_CTS + * GPIO P is connected to RS485_TX_En + * GPIO Q is connected to RS485_RX_En + */ + pinctrl-0 = <&pinctrl_hog_base + &pinctrl_dhcom_a &pinctrl_dhcom_b &pinctrl_dhcom_c + &pinctrl_dhcom_d &pinctrl_dhcom_e &pinctrl_dhcom_f + &pinctrl_dhcom_g &pinctrl_dhcom_h &pinctrl_dhcom_j + &pinctrl_dhcom_k &pinctrl_dhcom_l &pinctrl_dhcom_n + &pinctrl_dhcom_o &pinctrl_dhcom_r &pinctrl_dhcom_s + &pinctrl_dhcom_int>; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-picoitx.dts b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-picoitx.dts new file mode 100644 index 00000000000000..703cf0fb3d2be3 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-picoitx.dts @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023-2024 Marek Vasut + * + * DHCOM iMX8MP variant: + * DHCM-iMX8ML8-C160-R204-F1638-SPI16-E-SD-RTC-T-RGB-I-01D2 + * DHCOM PCB number: 660-200 or newer + * PicoITX PCB number: 487-600 or newer + */ + +/dts-v1/; + +#include +#include "imx8mp-dhcom-som.dtsi" + +/ { + model = "DH electronics i.MX8M Plus DHCOM PicoITX"; + compatible = "dh,imx8mp-dhcom-picoitx", "dh,imx8mp-dhcom-som", + "fsl,imx8mp"; + + chosen { + stdout-path = &uart1; + }; + + led { + compatible = "gpio-leds"; + + led-0 { + color = ; + default-state = "off"; + function = LED_FUNCTION_INDICATOR; + gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; /* GPIO I */ + pinctrl-0 = <&pinctrl_dhcom_i>; + pinctrl-names = "default"; + }; + }; +}; + +&eqos { /* First ethernet */ + pinctrl-0 = <&pinctrl_eqos_rmii>; + phy-handle = <ðphy0f>; + phy-mode = "rmii"; + + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_266M>, + <&clk IMX8MP_SYS_PLL2_100M>, + <&clk IMX8MP_SYS_PLL2_50M>; + assigned-clock-rates = <0>, <100000000>, <50000000>; +}; + +ðphy0g { /* Micrel KSZ9131RNXI */ + status = "disabled"; +}; + +ðphy0f { /* SMSC LAN8740Ai */ + status = "okay"; +}; + +&fec { + status = "disabled"; +}; + +&flexcan1 { + status = "okay"; +}; + +&gpio1 { + gpio-line-names = + "DHCOM-G", "", "", "", + "", "DHCOM-I", "PicoITX-HW0", "PicoITX-HW2", + "DHCOM-B", "DHCOM-A", "", "DHCOM-H", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", ""; +}; + +&gpio2 { + gpio-line-names = + "", "", "", "", "", "", "", "", + "", "", "", "PicoITX-HW1", "", "", "", "", + "", "", "", "", "DHCOM-INT", "", "", "", + "", "", "", "", "", "", "", ""; +}; + +&gpio4 { + gpio-line-names = + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "SOM-HW1", "", "", "", "", + "", "", "", "PicoITX-Out2", "", "", "", ""; +}; + +&gpio5 { + gpio-line-names = + "", "", "PicoITX-In2", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", + "", "", "PicoITX-In1", "PicoITX-Out1", + "", "", "", "", "", "", "", ""; +}; + +/* No HS connector on this SoM variant, so no HDMI, PCIe and only USB HS. */ +&hdmi_blk_ctrl { + status = "disabled"; +}; + +&hdmi_pvi { + status = "disabled"; +}; + +&hdmi_tx { + status = "disabled"; +}; + +&hdmi_tx_phy { + status = "disabled"; +}; + +&irqsteer_hdmi { + status = "disabled"; +}; + +&lcdif3 { + status = "disabled"; +}; + +&pcie_phy { + status = "disabled"; +}; + +&pcie { + status = "disabled"; +}; + +/* No WiFi/BT chipset on this SoM variant. */ +&uart2 { + bluetooth { + status = "disabled"; + }; +}; + +/* USB_OTG port is not routed out on PicoITX. */ +&usb3_0 { + status = "disabled"; +}; + +&usb_dwc3_0 { + status = "disabled"; +}; + +&usb3_1 { + fsl,over-current-active-low; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + maximum-speed = "high-speed"; +}; + +/* No WiFi/BT chipset on this SoM variant. */ +&usdhc1 { + status = "disabled"; +}; + +&iomuxc { + /* + * The following DHCOM GPIOs are used on this board. + * Therefore, they have been removed from the list below. + * I: yellow led + */ + pinctrl-0 = <&pinctrl_dhcom_a &pinctrl_dhcom_b &pinctrl_dhcom_c + &pinctrl_dhcom_d &pinctrl_dhcom_e &pinctrl_dhcom_f + &pinctrl_dhcom_g &pinctrl_dhcom_h &pinctrl_dhcom_j + &pinctrl_dhcom_k &pinctrl_dhcom_l &pinctrl_dhcom_m + &pinctrl_dhcom_n &pinctrl_dhcom_o &pinctrl_dhcom_p + &pinctrl_dhcom_q &pinctrl_dhcom_r &pinctrl_dhcom_s + &pinctrl_dhcom_int>; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-pcie-ep.dtso b/arch/arm64/boot/dts/freescale/imx8mp-evk-pcie-ep.dtso new file mode 100644 index 00000000000000..244e820699b50f --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-pcie-ep.dtso @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2024 NXP + */ + +/dts-v1/; +/plugin/; + +&pcie { + status = "disabled"; +}; + +&pcie_ep { + pinctrl-0 = <&pinctrl_pcie0>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-iota2-lumpy.dts b/arch/arm64/boot/dts/freescale/imx8mp-iota2-lumpy.dts new file mode 100644 index 00000000000000..f48cf22b423db5 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-iota2-lumpy.dts @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2023 Y Soft + */ + +/dts-v1/; + +#include "imx8mp.dtsi" + +/ { + compatible = "ysoft,imx8mp-iota2-lumpy", "fsl,imx8mp"; + model = "Y Soft i.MX8MPlus IOTA2 Lumpy board"; + + beeper { + compatible = "pwm-beeper"; + pwms = <&pwm4 0 500000 0>; + }; + + chosen { + stdout-path = &uart2; + }; + + gpio_keys: gpio-keys { + compatible = "gpio-keys"; + pinctrl-0 = <&pinctrl_gpio_keys>; + pinctrl-names = "default"; + + button-reset { + gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + label = "Factory RESET"; + linux,code = ; + }; + }; + + reg_usb_host: regulator-usb-host { + compatible = "regulator-fixed"; + pinctrl-0 = <&pinctrl_usb_host_vbus>; + pinctrl-names = "default"; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "usb-host"; + gpio = <&gpio1 14 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + memory@40000000 { + reg = <0x0 0x40000000 0 0x80000000>, + <0x1 0x00000000 0 0x80000000>; + device_type = "memory"; + }; +}; + +&A53_0 { + cpu-supply = <®_arm>; +}; + +&A53_1 { + cpu-supply = <®_arm>; +}; + +&A53_2 { + cpu-supply = <®_arm>; +}; + +&A53_3 { + cpu-supply = <®_arm>; +}; + +&eqos { + phy-handle = <ðphy0>; + phy-mode = "rgmii-id"; + pinctrl-0 = <&pinctrl_eqos>; + pinctrl-names = "default"; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@0 { + reg = <0>; + interrupts = <21 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&gpio3>; + pinctrl-0 = <&pinctrl_ethphy0>; + pinctrl-names = "default"; + reset-assert-us = <1000>; + reset-deassert-us = <1000>; + reset-gpios = <&gpio3 22 GPIO_ACTIVE_LOW>; + micrel,led-mode = <0>; + }; + }; +}; + +&fec { + fsl,magic-packet; + phy-handle = <ðphy1>; + phy-mode = "rgmii-id"; + pinctrl-0 = <&pinctrl_fec>; + pinctrl-names = "default"; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy1: ethernet-phy@0 { + reg = <0>; + interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&gpio3>; + pinctrl-0 = <&pinctrl_ethphy1>; + pinctrl-names = "default"; + reset-assert-us = <1000>; + reset-deassert-us = <1000>; + reset-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>; + micrel,led-mode = <0>; + }; + }; +}; + +&i2c1 { + clock-frequency = <400000>; + pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-names = "default"; + status = "okay"; + + pmic@25 { + compatible = "nxp,pca9450c"; + reg = <0x25>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&gpio1>; + pinctrl-0 = <&pinctrl_pmic>; + pinctrl-names = "default"; + + regulators { + BUCK1 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <720000>; + regulator-name = "BUCK1"; + regulator-ramp-delay = <3125>; + }; + + reg_arm: BUCK2 { + nxp,dvs-run-voltage = <950000>; + nxp,dvs-standby-voltage = <850000>; + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1025000>; + regulator-min-microvolt = <720000>; + regulator-name = "BUCK2"; + regulator-ramp-delay = <3125>; + }; + + BUCK4 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <3600000>; + regulator-min-microvolt = <3000000>; + regulator-name = "BUCK4"; + }; + + BUCK5 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1950000>; + regulator-min-microvolt = <1650000>; + regulator-name = "BUCK5"; + }; + + BUCK6 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1155000>; + regulator-min-microvolt = <1045000>; + regulator-name = "BUCK6"; + }; + + LDO1 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1950000>; + regulator-min-microvolt = <1650000>; + regulator-name = "LDO1"; + }; + + LDO3 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1890000>; + regulator-min-microvolt = <1710000>; + regulator-name = "LDO3"; + }; + + LDO4 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <950000>; + regulator-min-microvolt = <850000>; + regulator-name = "LDO4"; + }; + + LDO5 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <1800000>; + regulator-name = "LDO5"; + }; + }; + }; +}; + +&i2c2 { + clock-frequency = <400000>; + pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-names = "default"; + status = "okay"; + + rtc: rtc@68 { + compatible = "dallas,ds1341"; + reg = <0x68>; + }; +}; + +&pwm4 { + pinctrl-0 = <&pinctrl_pwm4>; + pinctrl-names = "default"; + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&pinctrl_uart2>; + pinctrl-names = "default"; + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&usb3_phy1 { + vbus-supply = <®_usb_host>; + status = "okay"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + status = "okay"; +}; + +&usdhc3 { + assigned-clocks = <&clk IMX8MP_CLK_USDHC3>; + assigned-clock-rates = <400000000>; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&wdog1 { + pinctrl-0 = <&pinctrl_wdog>; + pinctrl-names = "default"; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl_eqos: eqosgrp { + fsl,pins = < + MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x2 + MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x2 + MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x90 + MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x90 + MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x90 + MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x90 + MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x90 + MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x90 + MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x16 + MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x16 + MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x16 + MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x16 + MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x16 + MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x16 + >; + }; + + pinctrl_ethphy0: ethphy0grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD0__GPIO3_IO21 0x10 + MX8MP_IOMUXC_SAI5_RXD1__GPIO3_IO22 0x10 + >; + }; + + pinctrl_ethphy1: ethphy1grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXFS__GPIO3_IO19 0x10 + MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20 0x10 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC 0x2 + MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO 0x2 + MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0 0x90 + MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1 0x90 + MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2 0x90 + MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3 0x90 + MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC 0x90 + MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL 0x90 + MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0 0x16 + MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1 0x16 + MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2 0x16 + MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3 0x16 + MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL 0x16 + MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC 0x16 + >; + }; + + pinctrl_gpio_keys: gpiokeysgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x80 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c2 + MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c2 + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c2 + MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x400001c2 + >; + }; + + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_MCLK__PWM4_OUT 0x102 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x0 + MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x0 + >; + }; + + pinctrl_usb_host_vbus: usb1grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR 0x0 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x194 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d4 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d4 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d4 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d4 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d4 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d4 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d4 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d4 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d4 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x194 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x196 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d6 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d6 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d6 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d6 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d6 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d6 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d6 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d6 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d6 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x196 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x190 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d0 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d0 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d0 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d0 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d0 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d0 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d0 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d0 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d0 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x190 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B 0x166 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-bl-osm-s.dts b/arch/arm64/boot/dts/freescale/imx8mp-kontron-bl-osm-s.dts new file mode 100644 index 00000000000000..0eb9e726a9b819 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-bl-osm-s.dts @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright (C) 2022 Kontron Electronics GmbH + */ + +/dts-v1/; + +#include "imx8mp-kontron-osm-s.dtsi" + +/ { + model = "Kontron BL i.MX8MP OSM-S"; + compatible = "kontron,imx8mp-bl-osm-s", "kontron,imx8mp-osm-s", "fsl,imx8mp"; + + aliases { + ethernet0 = &fec; + ethernet1 = &eqos; + }; + + extcon_usbc: usbc { + compatible = "linux,extcon-usb-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb1_id>; + id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + + leds { + compatible = "gpio-leds"; + + led1 { + label = "led1"; + gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + + pwm-beeper { + compatible = "pwm-beeper"; + pwms = <&pwm2 0 5000 0>; + }; + + reg_vcc_panel: regulator-vcc-panel { + compatible = "regulator-fixed"; + gpio = <&gpio4 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "VCC_PANEL"; + }; +}; + +&ecspi2 { + status = "okay"; + + eeram@0 { + compatible = "microchip,48l640"; + reg = <0>; + spi-max-frequency = <20000000>; + }; +}; + +&eqos { /* Second ethernet (OSM-S ETH_B) */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos_rgmii>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy1>; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-id4f51.e91b"; + reg = <1>; + pinctrl-0 = <&pinctrl_ethphy1>; + pinctrl-names = "default"; + reset-assert-us = <10000>; + reset-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&fec { /* First ethernet (OSM-S ETH_A) */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet_rgmii>; + phy-connection-type = "rgmii-id"; + phy-handle = <ðphy0>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-id4f51.e91b"; + reg = <1>; + pinctrl-0 = <&pinctrl_ethphy0>; + pinctrl-names = "default"; + reset-assert-us = <10000>; + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&flexcan1 { + status = "okay"; +}; + +/* + * Rename SoM signals according to board usage: + * SDIO_A_PWR_EN -> CAN_ADDR2 + * SDIO_A_WP -> CAN_ADDR3 + */ +&gpio2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio2>; + gpio-line-names = "", "", "", "", "", "", "", "", "", "", "", "", + "SDIO_A_CD", "SDIO_A_CLK", "SDIO_A_CMD", "SDIO_A_D0", + "SDIO_A_D1", "SDIO_A_D2", "SDIO_A_D3", "CAN_ADDR2", + "CAN_ADDR3"; +}; + +/* + * Rename SoM signals according to board usage: + * SPI_A_WP -> CAN_ADDR0 + * SPI_A_HOLD -> CAN_ADDR1 + * GPIO_B_0 -> DIO1_OUT + * GPIO_B_1 -> DIO2_OUT + */ +&gpio3 { + gpio-line-names = "PCIE_WAKE", "PCIE_CLKREQ", "PCIE_A_PERST", "SDIO_B_D5", + "SDIO_B_D6", "SDIO_B_D7", "CAN_ADDR0", "CAN_ADDR1", + "UART_B_RTS", "UART_B_CTS", "SDIO_B_D0", "SDIO_B_D1", + "SDIO_B_D2", "SDIO_B_D3", "SDIO_B_WP", "SDIO_B_D4", + "PCIE_SM_ALERT", "SDIO_B_CLK", "SDIO_B_CMD", "DIO1_OUT", + "DIO2_OUT", "", "BOOT_SEL0", "BOOT_SEL1", + "", "", "SDIO_B_CD", "SDIO_B_PWR_EN", + "HDMI_CEC", "HDMI_HPD"; +}; + +/* + * Rename SoM signals according to board usage: + * GPIO_B_5 -> DIO2_IN + * GPIO_B_6 -> DIO3_IN + * GPIO_B_7 -> DIO4_IN + * GPIO_B_3 -> DIO4_OUT + * GPIO_B_4 -> DIO1_IN + * GPIO_B_2 -> DIO3_OUT + */ +&gpio4 { + gpio-line-names = "DIO2_IN", "DIO3_IN", "DIO4_IN", "GPIO_C_0", + "ETH_A_MDC", "ETH_A_MDIO", "ETH_A_RXD0", "ETH_A_RXD1", + "ETH_A_RXD2", "ETH_A_RXD3", "ETH_A_RX_DV", "ETH_A_RX_CLK", + "ETH_A_TXD0", "ETH_A_TXD1", "ETH_A_TXD2", "ETH_A_TXD3", + "ETH_A_TX_EN", "ETH_A_TX_CLK", "DIO4_OUT", "DIO1_IN", + "DIO3_OUT", "GPIO_A_6", "CAN_A_TX", "UART_A_CTS", + "UART_A_RTS", "CAN_A_RX", "CAN_B_TX", "CAN_B_RX", + "GPIO_A_7", "CARRIER_PWR_EN", "I2S_A_DATA_IN", "I2S_LRCLK"; +}; + +&hdmi_pvi { + status = "okay"; +}; + +&hdmi_tx { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi>; + ddc-i2c-bus = <&i2c2>; + status = "okay"; +}; + +&hdmi_tx_phy { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + gpio_expander_dio: io-expander@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "DIO1_OUT","DIO1_IN", "DIO2_OUT","DIO2_IN", + "DIO3_OUT","DIO3_IN", "DIO4_OUT","DIO4_IN"; + interrupt-parent = <&gpio3>; + interrupts = <19 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>; + }; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&lcdif3 { + status = "okay"; +}; + +&pwm2 { + status = "okay"; +}; + +®_usdhc2_vcc { + status = "disabled"; +}; + +&snvs_pwrkey { + status = "okay"; +}; + +&uart1 { + uart-has-rtscts; + status = "okay"; +}; + +&uart4 { + linux,rs485-enabled-at-boot-time; + uart-has-rtscts; + status = "okay"; +}; + +&usb_dwc3_0 { + adp-disable; + hnp-disable; + srp-disable; + dr_mode = "otg"; + extcon = <&extcon_usbc>; + usb-role-switch; + status = "okay"; +}; + +&usb_dwc3_1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_hub>; + #address-cells = <1>; + #size-cells = <0>; + dr_mode = "host"; + status = "okay"; + + usb-hub@1 { + compatible = "usb424,2514"; + reg = <1>; + reset-gpios = <&gpio3 14 GPIO_ACTIVE_LOW>; + }; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + fsl,disable-port-power-control; + fsl,permanently-attached; + status = "okay"; +}; + +&usb3_phy0 { + vbus-supply = <®_usb1_vbus>; + status = "okay"; +}; + +&usb3_phy1 { + status = "okay"; +}; + +&usdhc2 { + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; + vmmc-supply = <®_vdd_3v3>; + status = "okay"; +}; + +&iomuxc { + pinctrl_ethphy0: ethphy0grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x46 + >; + }; + + pinctrl_ethphy1: ethphy1grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00 0x46 + >; + }; + + pinctrl_gpio2: gpio2grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x46 + MX8MP_IOMUXC_SD2_WP__GPIO2_IO20 0x46 + >; + }; + + pinctrl_usb_hub: usbhubgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14 0x46 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso b/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso new file mode 100644 index 00000000000000..a3cba41d2b5312 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-dl.dtso @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright (C) 2023 Kontron Electronics GmbH + */ + +/dts-v1/; +/plugin/; + +#include +#include "imx8mp-pinfunc.h" + +&{/} { + model = "Kontron DL i.MX8MP OSM-S"; + compatible = "kontron,imx8mp-bl-osm-s", "kontron,imx8mp-osm-s", "fsl,imx8mp"; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 50000 0>; + brightness-levels = <0 100>; + num-interpolated-steps = <100>; + default-brightness-level = <100>; + }; + + panel { + compatible = "jenson,bl-jt60050-01a", "panel-lvds"; + backlight = <&backlight>; + data-mapping = "vesa-24"; + enable-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + power-supply = <®_vcc_panel>; + height-mm = <86>; + width-mm = <154>; + + panel-timing { + clock-frequency = <50000000>; + hactive = <1024>; + hback-porch = <160>; + hfront-porch = <160>; + hsync-len = <1>; + vactive = <600>; + vback-porch = <23>; + vfront-porch = <12>; + vsync-len = <1>; + }; + + port { + panel_in_lvds0: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + }; +}; + +&gpio4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio4>, <&pinctrl_panel_stby>; + + panel-rst-hog { + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "panel-reset"; + }; + + panel-stby-hog { + gpio-hog; + gpios = <28 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "panel-standby"; + }; +}; + +&i2c1 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + touchscreen@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; + interrupt-parent = <&gpio1>; + interrupts = <6 8>; + irq-gpios = <&gpio1 6 0>; + AVDD28-supply = <®_vcc_panel>; + VDDIO-supply = <®_vcc_panel>; + reset-gpios = <&gpio1 7 0>; + }; +}; + +&lcdif2 { + status = "okay"; +}; + +&ldb_lvds_ch0 { + remote-endpoint = <&panel_in_lvds0>; +}; + +&lvds_bridge { + status = "okay"; +}; + +&pwm1 { + status = "okay"; +}; + +&iomuxc { + pinctrl_panel_stby: panelstbygrp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28 0x19 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi new file mode 100644 index 00000000000000..e0e9f6f7616d92 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-osm-s.dtsi @@ -0,0 +1,908 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright (C) 2022 Kontron Electronics GmbH + */ + +#include +#include "imx8mp.dtsi" + +/ { + model = "Kontron OSM-S i.MX8MP"; + compatible = "kontron,imx8mp-osm-s", "fsl,imx8mp"; + + aliases { + rtc0 = &rv3028; + rtc1 = &snvs_rtc; + }; + + memory@40000000 { + device_type = "memory"; + /* + * There are multiple SoM flavors with different DDR sizes. + * The smallest is 1GB. For larger sizes the bootloader will + * update the reg property. + */ + reg = <0x0 0x40000000 0 0x80000000>; + }; + + chosen { + stdout-path = &uart3; + }; + + reg_usb1_vbus: regulator-usb1-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usb1_vbus>; + gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-name = "VBUS_USB_A"; + }; + + reg_usb2_vbus: regulator-usb2-vbus { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usb2_vbus>; + gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-name = "VBUS_USB_B"; + }; + + reg_usdhc2_vcc: regulator-usdhc2-vcc { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usdhc2_vcc>; + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "VCC_SDIO_A"; + }; + + reg_usdhc3_vcc: regulator-usdhc3-vcc { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usdhc3_vcc>; + gpio = <&gpio3 27 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "VCC_SDIO_B"; + }; + + reg_vdd_carrier: regulator-vdd-carrier { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_vdd_carrier>; + gpio = <&gpio3 16 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + regulator-boot-on; + regulator-name = "VDD_CARRIER"; + + regulator-state-standby { + regulator-on-in-suspend; + }; + + regulator-state-mem { + regulator-off-in-suspend; + }; + + regulator-state-disk { + regulator-off-in-suspend; + }; + }; +}; + +&A53_0 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_1 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_2 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_3 { + cpu-supply = <®_vdd_arm>; +}; + +&ecspi1 { /* OSM-S SPI_A */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; +}; + +&ecspi2 { /* OSM-S SPI_B */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; +}; + +&flexcan1 { /* OSM-S CAN_A */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; +}; + +&flexcan2 { /* OSM-S CAN_B */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; +}; + +&gpio1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio1>; + gpio-line-names = "GPIO_A_0", "GPIO_A_1", "", "", + "", "GPIO_A_2", "GPIO_A_3", "GPIO_A_4", + "GPIO_A_5", "USB_B_EN", "USB_A_ID", "USB_B_ID", + "USB_A_EN", "USB_A_OC","CAM_MCK", "USB_B_OC", + "ETH_B_MDC", "ETH_B_MDIO", "ETH_B_TXD3", "ETH_B_TXD2", + "ETH_B_TXD1", "ETH_B_TXD0", "ETH_B_TX_EN", "ETH_B_TX_CLK", + "ETH_B_RX_DV", "ETH_B_RX_CLK", "ETH_B_RXD0", "ETH_B_RXD1", + "ETH_B_RXD2", "ETH_B_RXD3"; +}; + +&gpio2 { + gpio-line-names = "", "", "", "", "", "", "", "", "", "", "", "", + "SDIO_A_CD", "SDIO_A_CLK", "SDIO_A_CMD", "SDIO_A_D0", + "SDIO_A_D1", "SDIO_A_D2", "SDIO_A_D3", "SDIO_A_PWR_EN", + "SDIO_A_WP"; +}; + +&gpio3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio3>; + gpio-line-names = "PCIE_WAKE", "PCIE_CLKREQ", "PCIE_A_PERST", "SDIO_B_D5", + "SDIO_B_D6", "SDIO_B_D7", "SPI_A_WP", "SPI_A_HOLD", + "UART_B_RTS", "UART_B_CTS", "SDIO_B_D0", "SDIO_B_D1", + "SDIO_B_D2", "SDIO_B_D3", "SDIO_B_WP", "SDIO_B_D4", + "PCIE_SM_ALERT", "SDIO_B_CLK", "SDIO_B_CMD", "GPIO_B_0", + "GPIO_B_1", "", "BOOT_SEL0", "BOOT_SEL1", + "", "", "SDIO_B_CD", "SDIO_B_PWR_EN", + "HDMI_CEC", "HDMI_HPD"; +}; + +&gpio4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio4>; + gpio-line-names = "GPIO_B_5", "GPIO_B_6", "GPIO_B_7", "GPIO_C_0", + "ETH_A_MDC", "ETH_A_MDIO", "ETH_A_RXD0", "ETH_A_RXD1", + "ETH_A_RXD2", "ETH_A_RXD3", "ETH_A_RX_DV", "ETH_A_RX_CLK", + "ETH_A_TXD0", "ETH_A_TXD1", "ETH_A_TXD2", "ETH_A_TXD3", + "ETH_A_TX_EN", "ETH_A_TX_CLK", "GPIO_B_3", "GPIO_B_4", + "GPIO_B_2", "GPIO_A_6", "CAN_A_TX", "UART_A_CTS", + "UART_A_RTS", "CAN_A_RX", "CAN_B_TX", "CAN_B_RX", + "GPIO_A_7", "CARRIER_PWR_EN", "I2S_A_DATA_IN", "I2S_LRCLK"; +}; + +&gpio5 { + gpio-line-names = "I2S_BITCLK", "I2S_A_DATA_OUT", "I2S_MCLK", "PWM_2", + "PWM_1", "PWM_0", "SPI_A_SCK", "SPI_A_SDO", + "SPI_A_SDI", "SPI_A_CS0", "SPI_B_SCK", "SPI_B_SDO", + "SPI_B_SDI", "SPI_B_CS0", "I2C_A_SCL", "I2C_A_SDA", + "I2C_B_SCL", "I2C_B_SDA", "PCIE_SMCLK", "PCIE_SMDAT", + "I2C_CAM_SCL", "I2C_CAM_SDA", "UART_A_RX", "UART_A_TX", + "UART_C_RX", "UART_C_TX", "UART_CON_RX", "UART_CON_TX", + "UART_B_RX", "UART_B_TX"; +}; + +&i2c1 { /* OSM-S I2C_A */ + clock-frequency = <400000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +}; + +&i2c2 { /* OSM-S I2C_B */ + clock-frequency = <400000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c2>; + pinctrl-1 = <&pinctrl_i2c2_gpio>; + scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +}; + +&i2c3 { /* OSM-S PCIe SMDAT/SMCLK */ + clock-frequency = <400000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c3>; + pinctrl-1 = <&pinctrl_i2c3_gpio>; + scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +}; + +&i2c4 { /* OSM-S I2C_CAM */ + clock-frequency = <400000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c4>; + pinctrl-1 = <&pinctrl_i2c4_gpio>; + scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; +}; + +&i2c5 { /* PMIC, EEPROM, RTC */ + clock-frequency = <400000>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c5>; + pinctrl-1 = <&pinctrl_i2c5_gpio>; + scl-gpios = <&gpio3 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio3 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + status = "okay"; + + pca9450: pmic@25 { + compatible = "nxp,pca9450c"; + reg = <0x25>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + nxp,i2c-lt-enable; + + regulators { + reg_vdd_soc: BUCK1 { /* dual phase with BUCK3 */ + regulator-name = "+0V8_VDD_SOC (BUCK1)"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <950000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + }; + + reg_vdd_arm: BUCK2 { + regulator-name = "+0V9_VDD_ARM (BUCK2)"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <950000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + nxp,dvs-run-voltage = <950000>; + nxp,dvs-standby-voltage = <850000>; + }; + + reg_vdd_3v3: BUCK4 { + regulator-name = "+3V3 (BUCK4)"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_vdd_1v8: BUCK5 { + regulator-name = "+1V8 (BUCK5)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_dram: BUCK6 { + regulator-name = "+1V1_NVCC_DRAM (BUCK6)"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_snvs: LDO1 { + regulator-name = "+1V8_NVCC_SNVS (LDO1)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_vdda: LDO3 { + regulator-name = "+1V8_VDDA (LDO3)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_sd: LDO5 { + regulator-name = "NVCC_SD (LDO5)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + + eeprom@50 { + compatible = "onnn,n24s64b", "atmel,24c64"; + reg = <0x50>; + pagesize = <32>; + size = <8192>; + num-addresses = <1>; + }; + + rv3028: rtc@52 { + compatible = "microcrystal,rv3028"; + reg = <0x52>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rtc>; + interrupts-extended = <&gpio3 24 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&pwm1 { /* OSM-S PWM_0 */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; +}; + +&pwm2 { /* OSM-S PWM_1 */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm2>; +}; + +&pwm3 { /* OSM-S PWM_2 */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm3>; +}; + +&sai3 { /* OSM-S I2S_A */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai3>; +}; + +&uart1 { /* OSM-S UART_A */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; +}; + +&uart2 { /* OSM-S UART_C */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; +}; + +&uart3 { /* OSM-S UART_CON */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "okay"; +}; + +&uart4 { /* OSM-S UART_B */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; +}; + +&usb3_0 { /* OSM-S USB_A */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb1_oc>; + fsl,over-current-active-low; +}; + +&usb3_1 { /* OSM-S USB_B */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb2_oc>; + fsl,over-current-active-low; +}; + +&usdhc1 { /* eMMC */ + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + vmmc-supply = <®_vdd_3v3>; + vqmmc-supply = <®_vdd_1v8>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&usdhc2 { /* OSM-S SDIO_A */ + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc2_wp>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc2_wp>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc2_wp>; + vmmc-supply = <®_usdhc2_vcc>; + vqmmc-supply = <®_nvcc_sd>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; +}; + +&usdhc3 { /* OSM-S SDIO_B */ + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>, <&pinctrl_usdhc3_gpio>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>, <&pinctrl_usdhc3_gpio>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>, <&pinctrl_usdhc3_gpio>; + vmmc-supply = <®_usdhc3_vcc>; + vqmmc-supply = <®_nvcc_sd>; + cd-gpios = <&gpio3 26 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio3 14 GPIO_ACTIVE_HIGH>; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl_csi_mck: csimckgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO14__CCM_CLKO1 0x59 /* CAM_MCK */ + >; + }; + + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO 0x44 /* SPI_A_SDI_(IO0) */ + MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI 0x44 /* SPI_A_SDO_(IO1) */ + MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK 0x44 /* SPI_A_SCK */ + MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09 0x40 /* SPI_A_CS0# */ + >; + }; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x44 /* SPI_B_SDI */ + MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x44 /* SPI_B_SDO */ + MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x44 /* SPI_B_SCK */ + MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13 0x40 /* SPI_B_CS0# */ + >; + }; + + pinctrl_enet_rgmii: enetrgmiigrp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC 0x3 /* ETH_MDC */ + MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO 0x3 /* ETH_MDIO */ + MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0 0x91 /* ETH_A_(S)(R)(G)MII_RXD0 */ + MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1 0x91 /* ETH_A_(S)(R)(G)MII_RXD1 */ + MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2 0x91 /* ETH_A_(R)(G)MII_RXD2 */ + MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3 0x91 /* ETH_A_(R)(G)MII_RXD3 */ + MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC 0x91 /* ETH_A_(R)(G)MII_RX_CLK */ + MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL 0x91 /* ETH_A_(R)(G)MII_RX_DV(_ER) */ + MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0 0x1f /* ETH_A_(S)(R)(G)MII_TXD0 */ + MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1 0x1f /* ETH_A_(S)(R)(G)MII_TXD1 */ + MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2 0x1f /* ETH_A_(S)(R)(G)MII_TXD2 */ + MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3 0x1f /* ETH_A_(S)(R)(G)MII_TXD3 */ + MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC 0x1f /* ETH_A_(R)(G)MII_TX_CLK */ + MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL 0x1f /* ETH_A_(R)(G)MII_TX_EN(_ER) */ + >; + }; + + pinctrl_eqos_rgmii: eqosrgmiigrp { + fsl,pins = < + MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC 0x3 /* ETH_B_MDC */ + MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO 0x3 /* ETH_B_MDIO */ + MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x91 /* ETH_B_(S)(R)(G)MII_RXD0 */ + MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x91 /* ETH_B_(S)(R)(G)MII_RXD1 */ + MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x91 /* ETH_B_(R)(G)MII_RXD2 */ + MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x91 /* ETH_B_(R)(G)MII_RXD3 */ + MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x91 /* ETH_B_(R)(G)MII_RX_CLK */ + MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x91 /* ETH_B_(R)(G)MII_RX_DV(_ER) */ + MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x1f /* ETH_B_(S)(R)(G)MII_TXD0 */ + MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x1f /* ETH_B_(S)(R)(G)MII_TXD1 */ + MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x1f /* ETH_B_(S)(R)(G)MII_TXD2 */ + MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x1f /* ETH_B_(S)(R)(G)MII_TXD3 */ + MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x1f /* ETH_B_(R)(G)MII_TX_CLK */ + MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x1f /* ETH_B_(R)(G)MII_TX_EN(_ER) */ + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_RXC__CAN1_TX 0x154 /* CAN_A_TX */ + MX8MP_IOMUXC_SAI2_TXC__CAN1_RX 0x154 /* CAN_A_RX */ + >; + }; + + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_TXD0__CAN2_TX 0x154 /* CAN_B_TX */ + MX8MP_IOMUXC_SAI2_MCLK__CAN2_RX 0x154 /* CAN_B_RX */ + >; + }; + + pinctrl_gpio1: gpio1grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00 0x19 /* GPIO_A_0 */ + MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x19 /* GPIO_A_1 */ + MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05 0x19 /* GPIO_A_2 */ + MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06 0x19 /* GPIO_A_3 */ + MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x19 /* GPIO_A_4 */ + MX8MP_IOMUXC_GPIO1_IO08__GPIO1_IO08 0x19 /* GPIO_A_5 */ + >; + }; + + pinctrl_gpio3: gpio3grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_CE0_B__GPIO3_IO01 0x19 /* GPIO_A_7 */ + MX8MP_IOMUXC_SAI5_RXFS__GPIO3_IO19 0x19 /* GPIO_B_0 */ + MX8MP_IOMUXC_SAI5_RXC__GPIO3_IO20 0x19 /* GPIO_B_1 */ + MX8MP_IOMUXC_SAI5_RXD1__GPIO3_IO22 0x19 /* BOOT_SEL0# */ + MX8MP_IOMUXC_SAI5_RXD2__GPIO3_IO23 0x19 /* BOOT_SEL1# */ + >; + }; + + pinctrl_gpio4: gpio4grp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_RXFS__GPIO4_IO00 0x19 /* GPIO_B_5 */ + MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01 0x19 /* GPIO_B_6 */ + MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02 0x19 /* GPIO_B_7 */ + MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x19 /* GPIO_C_0 */ + MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18 0x19 /* GPIO_B_3 */ + MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19 0x19 /* GPIO_B_4 */ + MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20 0x19 /* GPIO_B_2 */ + MX8MP_IOMUXC_SAI2_RXFS__GPIO4_IO21 0x19 /* GPIO_A_6 */ + >; + }; + + pinctrl_hdmi: hdmigrp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x19 /* HDMI_HPD */ + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x40000084 /* I2C_A_SCL */ + MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x40000084 /* I2C_A_SDA */ + >; + }; + + pinctrl_i2c1_gpio: i2c1gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__GPIO5_IO14 0x84 /* I2C_A_SCL */ + MX8MP_IOMUXC_I2C1_SDA__GPIO5_IO15 0x84 /* I2C_A_SDA */ + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x40000084 /* I2C_B_SCL */ + MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x40000084 /* I2C_B_SDA */ + >; + }; + + pinctrl_i2c2_gpio: i2c2gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16 0x84 /* I2C_B_SCL */ + MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17 0x84 /* I2C_B_SDA */ + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x40000084 /* PCIe_SMCLK */ + MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA 0x40000084 /* PCIe_SMDAT */ + >; + }; + + pinctrl_i2c3_gpio: i2c3gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_I2C3_SCL__GPIO5_IO18 0x84 /* PCIe_SMCLK */ + MX8MP_IOMUXC_I2C3_SDA__GPIO5_IO19 0x84 /* PCIe_SMDAT */ + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL 0x40000084 /* I2C_CAM_SCL/CSI_TX_P */ + MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x40000084 /* I2C_CAM_SDA/CSI_TX_N */ + >; + }; + + pinctrl_i2c4_gpio: i2c4gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_I2C4_SCL__GPIO5_IO20 0x84 /* I2C_CAM_SCL/CSI_TX_P */ + MX8MP_IOMUXC_I2C4_SDA__GPIO5_IO21 0x84 /* I2C_CAM_SDA/CSI_TX_N */ + >; + }; + + pinctrl_i2c5: i2c5grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD0__I2C5_SCL 0x40000084 + MX8MP_IOMUXC_SAI5_MCLK__I2C5_SDA 0x40000084 + >; + }; + + pinctrl_i2c5_gpio: i2c5gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD0__GPIO3_IO21 0x84 + MX8MP_IOMUXC_SAI5_MCLK__GPIO3_IO25 0x84 + >; + }; + + pinctrl_pcie: pciegrp { + fsl,pins = < + MX8MP_IOMUXC_UART4_RXD__PCIE_CLKREQ_B 0x19 /* PCIe_CLKREQ# */ + MX8MP_IOMUXC_NAND_CE1_B__GPIO3_IO02 0x19 /* PCIe_A_PERST# */ + MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00 0x19 /* PCIe_WAKE# */ + MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x19 /* PCIe_SM_ALERT */ + >; + }; + + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x1c0 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_EXT_CLK__PWM1_OUT 0x6 /* PWM_0 */ + >; + }; + + pinctrl_pwm2: pwm2grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_RX__PWM2_OUT 0x6 /* PWM_1 */ + >; + }; + + pinctrl_pwm3: pwm3grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_TX__PWM3_OUT 0x6 /* PWM_2 */ + >; + }; + + pinctrl_reg_usb1_vbus: regusb1vbusgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x19 /* USB_A_EN */ + >; + }; + + pinctrl_reg_usb2_vbus: regusb2vbusgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09 0x19 /* USB_B_EN */ + >; + }; + + pinctrl_reg_usdhc2_vcc: regusdhc2vccgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x19 /* SDIO_A_PWR_EN */ + >; + }; + + pinctrl_reg_usdhc3_vcc: regusdhc3vccgrp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_DDC_SDA__GPIO3_IO27 0x19 /* SDIO_B_PWR_EN */ + >; + }; + + pinctrl_reg_vdd_carrier: regvddcarriergrp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29 0x19 /* CARRIER_PWR_EN */ + >; + }; + + pinctrl_rtc: rtcgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD3__GPIO3_IO24 0x1c0 + >; + }; + + pinctrl_sai3: sai3grp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00 0xd6 /* I2S_A_DATA_IN */ + MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00 0xd6 /* I2S_A_DATA_OUT */ + MX8MP_IOMUXC_SAI3_RXFS__AUDIOMIX_SAI3_RX_DATA01 0xd6 /* I2S_B_DATA_IN */ + MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_DATA01 0xd6 /* I2S_B_DATA_OUT */ + MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK 0xd6 /* I2S_MCLK */ + MX8MP_IOMUXC_NAND_DATA01__AUDIOMIX_SAI3_TX_SYNC 0xd6 /* I2S_LRCLK */ + MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK 0xd6 /* I2S_BITCLK */ + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140 /* UART_A_RX */ + MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x140 /* UART_A_TX */ + MX8MP_IOMUXC_SAI2_RXD0__UART1_DCE_RTS 0x140 /* UART_A_CTS */ + MX8MP_IOMUXC_SAI2_TXFS__UART1_DCE_CTS 0x140 /* UART_A_RTS */ + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x140 /* UART_C_RX */ + MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x140 /* UART_C_TX */ + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX8MP_IOMUXC_UART3_RXD__UART3_DCE_RX 0x140 /* UART_CON_RX */ + MX8MP_IOMUXC_UART3_TXD__UART3_DCE_TX 0x140 /* UART_CON_TX */ + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_DATA00__UART4_DCE_RX 0x140 /* UART_B_RX */ + MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX 0x140 /* UART_B_TX */ + MX8MP_IOMUXC_NAND_DATA03__UART4_DCE_RTS 0x140 /* UART_B_CTS */ + MX8MP_IOMUXC_NAND_DATA02__UART4_DCE_CTS 0x140 /* UART_B_RTS */ + >; + }; + + pinctrl_usb1_id: usb1idgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10 0x1c4 /* USB_A_ID */ + >; + }; + + pinctrl_usb1_oc: usb1ocgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO13__USB1_OTG_OC 0x1c0 /* USB_A_OC# */ + >; + }; + + pinctrl_usb2_id: usb2idgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO11__USB2_OTG_ID 0x1c4 /* USB_B_ID */ + >; + }; + + pinctrl_usb2_oc: usb2ocgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO15__USB2_OTG_OC 0x1c0 /* USB_B_OC# */ + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x190 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d0 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d0 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d0 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d0 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d0 + MX8MP_IOMUXC_SD1_DATA4__USDHC1_DATA4 0x1d0 + MX8MP_IOMUXC_SD1_DATA5__USDHC1_DATA5 0x1d0 + MX8MP_IOMUXC_SD1_DATA6__USDHC1_DATA6 0x1d0 + MX8MP_IOMUXC_SD1_DATA7__USDHC1_DATA7 0x1d0 + MX8MP_IOMUXC_SD1_RESET_B__USDHC1_RESET_B 0x141 + MX8MP_IOMUXC_SD1_STROBE__USDHC1_STROBE 0x190 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x194 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d4 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d4 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d4 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d4 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d4 + MX8MP_IOMUXC_SD1_DATA4__USDHC1_DATA4 0x1d4 + MX8MP_IOMUXC_SD1_DATA5__USDHC1_DATA5 0x1d4 + MX8MP_IOMUXC_SD1_DATA6__USDHC1_DATA6 0x1d4 + MX8MP_IOMUXC_SD1_DATA7__USDHC1_DATA7 0x1d4 + MX8MP_IOMUXC_SD1_RESET_B__USDHC1_RESET_B 0x141 + MX8MP_IOMUXC_SD1_STROBE__USDHC1_STROBE 0x194 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x196 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d6 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d6 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d6 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d6 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d6 + MX8MP_IOMUXC_SD1_DATA4__USDHC1_DATA4 0x1d6 + MX8MP_IOMUXC_SD1_DATA5__USDHC1_DATA5 0x1d6 + MX8MP_IOMUXC_SD1_DATA6__USDHC1_DATA6 0x1d6 + MX8MP_IOMUXC_SD1_DATA7__USDHC1_DATA7 0x1d6 + MX8MP_IOMUXC_SD1_RESET_B__USDHC1_RESET_B 0x141 + MX8MP_IOMUXC_SD1_STROBE__USDHC1_STROBE 0x196 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190 /* SDIO_A_CLK */ + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d0 /* SDIO_A_CMD */ + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d0 /* SDIO_A_D0 */ + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0 /* SDIO_A_D1 */ + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0 /* SDIO_A_D2 */ + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0 /* SDIO_A_D3 */ + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0x1d0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x194 /* SDIO_A_CLK */ + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d4 /* SDIO_A_CMD */ + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d4 /* SDIO_A_D0 */ + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4 /* SDIO_A_D1 */ + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4 /* SDIO_A_D2 */ + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4 /* SDIO_A_D3 */ + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0x1d0 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x196 /* SDIO_A_CLK */ + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d6 /* SDIO_A_CMD */ + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d6 /* SDIO_A_D0 */ + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6 /* SDIO_A_D1 */ + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6 /* SDIO_A_D2 */ + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6 /* SDIO_A_D3 */ + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0x1d0 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12 0x19 /* SDIO_A_CD# */ + >; + }; + + pinctrl_usdhc2_wp: usdhc2wpgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_WP__USDHC2_WP 0x400000d6 /* SDIO_A_WP */ + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x190 /* SDIO_B_CLK */ + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d0 /* SDIO_B_CMD */ + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d0 /* SDIO_B_D0 */ + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d0 /* SDIO_B_D1 */ + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d0 /* SDIO_B_D2 */ + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d0 /* SDIO_B_D3 */ + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d0 /* SDIO_B_D4 */ + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d0 /* SDIO_B_D5 */ + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d0 /* SDIO_B_D6 */ + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d0 /* SDIO_B_D7 */ + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x194 /* SDIO_B_CLK */ + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d4 /* SDIO_B_CMD */ + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d4 /* SDIO_B_D0 */ + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d4 /* SDIO_B_D1 */ + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d4 /* SDIO_B_D2 */ + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d4 /* SDIO_B_D3 */ + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d4 /* SDIO_B_D4 */ + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d4 /* SDIO_B_D5 */ + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d4 /* SDIO_B_D6 */ + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d4 /* SDIO_B_D7 */ + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x196 /* SDIO_B_CLK */ + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d6 /* SDIO_B_CMD */ + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d6 /* SDIO_B_D0 */ + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d6 /* SDIO_B_D1 */ + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d6 /* SDIO_B_D2 */ + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d6 /* SDIO_B_D3 */ + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d6 /* SDIO_B_D4 */ + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d6 /* SDIO_B_D5 */ + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d6 /* SDIO_B_D6 */ + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d6 /* SDIO_B_D7 */ + >; + }; + + pinctrl_usdhc3_gpio: usdhc3gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_DDC_SCL__GPIO3_IO26 0x19 /* SDIO_B_CD# */ + MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14 0x19 /* SDIO_B_WP */ + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B 0xc6 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts new file mode 100644 index 00000000000000..2173a36ff69178 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc-eval-carrier.dts @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright (C) 2024 Kontron Electronics GmbH + */ + +/dts-v1/; + +#include +#include "imx8mp-kontron-smarc.dtsi" + +/ { + model = "Kontron SMARC Eval Carrier with i.MX8MP"; + compatible = "kontron,imx8mp-smarc-eval-carrier", "kontron,imx8mp-smarc", + "kontron,imx8mp-osm-s", "fsl,imx8mp"; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 50000 0>; + brightness-levels = <0 100>; + num-interpolated-steps = <100>; + default-brightness-level = <100>; + enable-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; + }; + + extcon_usbc: usbc { + compatible = "linux,extcon-usb-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb1_id>; + id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,bitclock-master = <&codec_dai>; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&codec_dai>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "imx8mp-wm8904"; + simple-audio-card,routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "IN2L", "Line In Jack", + "IN2R", "Line In Jack", + "Headphone Jack", "MICBIAS", + "IN1L", "Headphone Jack"; + simple-audio-card,widgets = + "Microphone", "Headphone Jack", + "Headphone", "Headphone Jack", + "Line", "Line In Jack"; + + codec_dai: simple-audio-card,codec { + clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>; + sound-dai = <&wm8904>; + }; + + simple-audio-card,cpu { + sound-dai = <&sai3>; + }; + }; + + regulator_can0: can0-regulator { + compatible = "regulator-fixed"; + regulator-name = "can0_en"; + gpio = <&expander_pm_out 6 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + regulator_can1: can1-regulator { + compatible = "regulator-fixed"; + regulator-name = "can1_en"; + gpio = <&expander_pm_out 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&ecspi1 { + status = "okay"; +}; + +&ecspi2 { + status = "okay"; +}; + +&eqos { + status = "okay"; +}; + +&fec { + status = "okay"; +}; + +&flexcan1 { + xceiver-supply = <®ulator_can0>; + status = "okay"; +}; + +&flexcan2 { + xceiver-supply = <®ulator_can1>; + status = "okay"; +}; + +&hdmi_pvi { + status = "okay"; +}; + +&hdmi_tx { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi>; + ddc-i2c-bus = <&i2c3>; + status = "okay"; +}; + +&hdmi_tx_phy { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + expander_pm_out: io-expander@22 { + compatible = "nxp,pca9554"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "EN_5V0_S0", "EN_3V3_S0", "EN_1V8_S0", + "EN_1V5_S0", "EN_12V0_PCIE", "EN_3V3_S5", + "CAN0_EN", "CAN1_EN"; + }; + + expander_pm_in: io-expander@24 { + compatible = "nxp,pca9554"; + reg = <0x24>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "PG_5V0_3V3_S0", "PG_5V0_3V3_S5", "PG_1V8_S0", + "PG_1V5_S0", "PG_BKLT_5V", "PG_BKLT_12V"; + }; +}; + +&i2c2 { + status = "okay"; + + wm8904: audio-codec@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + #sound-dai-cells = <0>; + clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI3_MCLK1>; + clock-names = "mclk"; + AVDD-supply = <®_vdd_1v8>; + CPVDD-supply = <®_vdd_1v8>; + DBVDD-supply = <®_vdd_1v8>; + DCVDD-supply = <®_vdd_1v8>; + MICVDD-supply = <®_vdd_3v3>; + }; + + expander_audio: io-expander@20 { + compatible = "nxp,pca9554"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "I2C_SEL_CODEC_LOOPBACK", "FPAH_PRESENCE", + "CODEC_OPTION_SW_I2S_HDA", "LINE_IN_JD", + "LINE_OUT_JD", "HEADPHONES_JD", "MIC_JD"; + }; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&lcdif3 { + status = "okay"; +}; + +&pcie_phy { + fsl,refclk-pad-mode = ; + fsl,clkreq-unsupported; + clocks = <&hsio_blk_ctrl>; + clock-names = "ref"; + status = "okay"; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie>; + reset-gpio = <&gpio3 2 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&pwm1 { + status = "okay"; +}; + +&sai3 { + assigned-clocks = <&clk IMX8MP_CLK_SAI3>; + assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; + assigned-clock-rates = <24576000>; + fsl,sai-mclk-direction-output; + status = "okay"; +}; + +&uart1 { + uart-has-rtscts; + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart4 { + uart-has-rtscts; + status = "okay"; +}; + +&usb_dwc3_0 { + adp-disable; + hnp-disable; + srp-disable; + dr_mode = "otg"; + extcon = <&extcon_usbc>; + usb-role-switch; + status = "okay"; +}; + +&usb_dwc3_1 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&usb3_phy0 { + vbus-supply = <®_usb1_vbus>; + status = "okay"; +}; + +&usb3_phy1 { + status = "okay"; +}; + +&usdhc2 { + vmmc-supply = <®_vdd_3v3>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc.dtsi new file mode 100644 index 00000000000000..1e831d9b8a9354 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-kontron-smarc.dtsi @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Copyright (C) 2024 Kontron Electronics GmbH + */ + +#include +#include "imx8mp-kontron-osm-s.dtsi" + +/ { + model = "Kontron SMARC i.MX8MP"; + compatible = "kontron,imx8mp-smarc", "kontron,imx8mp-osm-s", "fsl,imx8mp"; + + leds { + compatible = "gpio-leds"; + + led1 { + label = "led1"; + gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; +}; + +&ecspi1 { + status = "okay"; + + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <0>; + spi-max-frequency = <18500000>; + }; +}; + +&eqos { /* Second ethernet (OSM-S ETH_B) */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos_rgmii>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy1>; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-id4f51.e91b"; + reg = <1>; + pinctrl-0 = <&pinctrl_ethphy1>; + pinctrl-names = "default"; + reset-assert-us = <10000>; + reset-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&fec { /* First ethernet (OSM-S ETH_A) */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet_rgmii>; + phy-connection-type = "rgmii-id"; + phy-handle = <ðphy0>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-id4f51.e91b"; + reg = <1>; + pinctrl-0 = <&pinctrl_ethphy0>; + pinctrl-names = "default"; + reset-assert-us = <10000>; + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + }; + }; +}; + +/* + * Rename SoM signals according to SMARC module usage: + * GPIO_A_2 -> GPIO0 + * GPIO_A_3 -> GPIO1 + * GPIO_A_4 -> GPIO2 + * GPIO_A_5 -> GPIO3 + * USB_B_EN -> n.a. + * USB_B_ID -> n.a. + * USB_B_OC -> n.a. + */ +&gpio1 { + gpio-line-names = "GPIO_A_0", "GPIO_A_1", "", "", + "", "GPIO0", "GPIO1", "GPIO2", + "GPIO3", "", "USB_A_ID", "", + "USB_A_EN", "USB_A_OC","CAM_MCK", "", + "ETH_B_MDC", "ETH_B_MDIO", "ETH_B_TXD3", "ETH_B_TXD2", + "ETH_B_TXD1", "ETH_B_TXD0", "ETH_B_TX_EN", "ETH_B_TX_CLK", + "ETH_B_RX_DV", "ETH_B_RX_CLK", "ETH_B_RXD0", "ETH_B_RXD1", + "ETH_B_RXD2", "ETH_B_RXD3"; +}; + +/* + * Rename SoM signals according to SMARC module usage: + * SDIO_A_CD -> SDIO_CD + * SDIO_A_CLK -> SDIO_CK + * SDIO_A_CMD -> SDIO_CMD + * SDIO_A_D0 -> SDIO_D0 + * SDIO_A_D1 -> SDIO_D1 + * SDIO_A_D2 -> SDIO_D2 + * SDIO_A_D3 -> SDIO_D3 + * SDIO_A_PWR_EN -> SDIO_PWR_EN + * SDIO_A_WP -> SDIO_WP + */ +&gpio2 { + gpio-line-names = "", "", "", "", "", "", "", "", "", "", "", "", + "SDIO_CD", "SDIO_CK", "SDIO_CMD", "SDIO_D0", + "SDIO_D1", "SDIO_D2", "SDIO_D3", "SDIO_PWR_EN", + "SDIO_WP"; +}; + +/* + * Rename SoM signals according to SMARC module usage: + * PCIE_CLKREQ -> PCIE_A_CKREQ + * PCIE_A_PERST -> PCIE_A_RST + * SDIO_B_D5 -> n.a. + * SDIO_B_D6 -> n.a. + * SDIO_B_D7 -> n.a. + * SPI_A_WP -> n.a. + * SPI_A_HOLD -> n.a. + * UART_B_RTS -> SER2_RTS + * UART_B_CTS -> SER2_CTS + * SDIO_B_D0 -> GPIO8 + * SDIO_B_D1 -> GPIO9 + * SDIO_B_D2 -> GPIO10 + * SDIO_B_D3 -> GPIO11 + * SDIO_B_WP -> n.a. + * SDIO_B_D4 -> n.a. + * PCIE_SM_ALERT -> SMB_ALERT + * SDIO_B_CLK -> GPIO6 + * SDIO_B_CMD -> GPIO7 + * GPIO_B_0 -> LCD0_BKLT_EN + * GPIO_B_1 -> LCD1_BKLT_EN + * BOOT_SEL0 -> BOOT_SEL2 + * SDIO_B_CD -> n.a. + * SDIO_B_PWR_EN -> n.a. + * HDMI_CEC -> n.a. + * SDIO_B_PWR_EN -> n.a. + */ +&gpio3 { + pinctrl-0 = <&pinctrl_gpio3>, <&pinctrl_gpio3_smarc>; + gpio-line-names = "PCIE_WAKE", "PCIE_A_CKREQ", "PCIE_A_RST", "", + "", "", "", "", + "SER2_RTS", "SER2_CTS", "GPIO8", "GPIO9", + "GPIO10", "GPIO11", "", "", + "SMB_ALERT", "GPIO6", "GPIO7", "LCD0_BKLT_EN", + "LCD1_BKLT_EN", "", "BOOT_SEL2", "BOOT_SEL1", + "", "", "", "", + "", "HDMI_HPD"; +}; + +/* + * Rename SoM signals according to SMARC module usage: + * GPIO_B_5 -> n.a. + * GPIO_B_6 -> n.a. + * GPIO_B_7 -> n.a. + * GPIO_C_0 -> LED + * GPIO_B_3 -> ETH2_INT + * GPIO_B_4 -> USB_HUB_RST + * GPIO_B_2 -> ETH1_INT + * GPIO_A_6 -> GPIO4 + * CAN_A_TX -> CAN0_TX + * UART_A_CTS -> SER0_CTS + * UART_A_RTS -> SER0_RTS + * CAN_A_RX -> CAN0_RX + * CAN_B_TX -> CAN1_TX + * CAN_B_RX -> CAN1_RX + * GPIO_A_7 -> TEST + * I2S_A_DATA_IN -> I2S0_SDIN + * I2S_LRCLK -> I2S0_LRCK + */ +&gpio4 { + gpio-line-names = "", "", "", "LED", + "ETH_A_MDC", "ETH_A_MDIO", "ETH_A_RXD0", "ETH_A_RXD1", + "ETH_A_RXD2", "ETH_A_RXD3", "ETH_A_RX_DV", "ETH_A_RX_CLK", + "ETH_A_TXD0", "ETH_A_TXD1", "ETH_A_TXD2", "ETH_A_TXD3", + "ETH_A_TX_EN", "ETH_A_TX_CLK", "ETH2_INT", "USB_HUB_RST", + "ETH1_INT", "GPIO4", "CAN0_TX", "SER0_CTS", + "SER0_RTS", "CAN0_RX", "CAN1_TX", "CAN1_RX", + "TEST", "CARRIER_PWR_EN", "I2S0_SDIN", "I2S0_LRCK"; +}; + +/* + * Rename SoM signals according to SMARC module usage: + * I2S_BITCLK -> I2S0_CK + * I2S_A_DATA_OUT -> I2S0_SDOUT + * I2S_MCLK -> AUDIO_MCK + * PWM_2 -> GPIO5 + * PWM_1 -> LCD1_BKLT_PWM + * PWM_0 -> LCD0_BKLT_PWM + * SPI_A_SCK -> SPI0_CK + * SPI_A_SDO -> SPI0_DO + * SPI_A_SDI -> SPI0_DIN + * SPI_A_CS0 -> SPI0_CS0 + * SPI_B_SCK -> ESPI_CK + * SPI_B_SDO -> ESPI_IO_0 + * SPI_B_SDI -> ESPI_IO_1 + * SPI_B_CS0 -> ESPI_CS0 + * I2C_A_SCL -> I2C_PM_CK + * I2C_A_SDA -> I2C_PM_DAT + * I2C_B_SCL -> I2C_GP_CK + * I2C_B_SDA -> I2C_GP_DAT + * PCIE_SMCLK -> HDMI_CTRL_CK + * PCIE_SMDAT -> HDMI_CTRL_DAT + * I2C_CAM_SCL -> I2C_CAM1_CK + * I2C_CAM_SDA -> I2C_CAM1_DAT + * UART_A_RX -> SER0_RX + * UART_A_TX -> SER0_TX + * UART_C_RX -> SER3_RX + * UART_C_TX -> SER3_TX + * UART_CON_RX -> SER1_RX + * UART_CON_TX -> SER1_TX + * UART_B_RX -> SER2_RX + * UART_B_TX -> SER2_TX + */ +&gpio5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio5_smarc>; + gpio-line-names = "I2S0_CK", "I2S0_SDOUT", "AUDIO_MCK", "GPIO5", + "LCD1_BKLT_PWM", "LCD0_BKLT_PWM", "SPI0_CK", "SPI0_DO", + "SPI0_DIN", "SPI0_CS0", "ESPI_CK", "ESPI_IO_0", + "ESPI_IO_1", "ESPI_CS0", "I2C_PM_CK", "I2C_PM_DAT", + "I2C_GP_CK", "I2C_GP_DAT", "HDMI_CTRL_CK", "HDMI_CTRL_DAT", + "I2C_CAM1_CK", "I2C_CAM1_DAT", "SER0_RX", "SER0_TX", + "SER3_RX", "SER3_TX", "SER1_RX", "SER1_TX", + "SER2_RX", "SER2_TX"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + #address-cells = <1>; + #size-cells = <0>; + + usb-hub@1 { + compatible = "usb424,2514"; + reg = <1>; + reset-gpios = <&gpio4 19 GPIO_ACTIVE_LOW>; + }; +}; + +&usb3_1 { + fsl,disable-port-power-control; + fsl,permanently-attached; +}; + +&iomuxc { + pinctrl_ethphy0: ethphy0grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO01__GPIO1_IO01 0x46 + >; + }; + + pinctrl_ethphy1: ethphy1grp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO00__GPIO1_IO00 0x46 + >; + }; + + pinctrl_gpio3_smarc: gpio3smarcgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_DATA04__GPIO3_IO10 0x1d0 /* SMARC GPIO8 */ + MX8MP_IOMUXC_NAND_DATA05__GPIO3_IO11 0x1d0 /* SMARC GPIO9 */ + MX8MP_IOMUXC_NAND_DATA06__GPIO3_IO12 0x1d0 /* SMARC GPIO10 */ + MX8MP_IOMUXC_NAND_DATA07__GPIO3_IO13 0x1d0 /* SMARC GPIO11 */ + MX8MP_IOMUXC_NAND_WE_B__GPIO3_IO17 0x190 /* SMARC GPIO6 */ + MX8MP_IOMUXC_NAND_WP_B__GPIO3_IO18 0x1d0 /* SMARC GPIO7 */ + >; + }; + + pinctrl_gpio5_smarc: gpio5smarcgrp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04 0x1d0 /* SMARC GPIO5 */ + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts index 5fd1614982cd50..4a4f7c1adc23fe 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts @@ -18,6 +18,18 @@ chosen { stdout-path = &uart2; }; + hdmi-connector { + compatible = "hdmi-connector"; + label = "J15"; + type = "d"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_out>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -85,6 +97,28 @@ ethphy0: ethernet-phy@0 { }; }; +&hdmi_pvi { + status = "okay"; +}; + +&hdmi_tx { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hdmi>; + status = "okay"; + + ports { + port@1 { + hdmi_tx_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; +}; + +&hdmi_tx_phy { + status = "okay"; +}; + &i2c1 { clock-frequency = <400000>; pinctrl-names = "default"; @@ -213,6 +247,10 @@ rtc@53 { }; }; +&lcdif3 { + status = "okay"; +}; + &uart2 { /* console */ pinctrl-names = "default"; @@ -279,6 +317,15 @@ MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x19 >; }; + pinctrl_hdmi: hdmigrp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL 0x1c2 + MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA 0x1c2 + MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x10 + MX8MP_IOMUXC_HDMI_CEC__HDMIMIX_HDMI_CEC 0x10 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c3 diff --git a/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-smarc-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-smarc-som.dtsi new file mode 100644 index 00000000000000..5da0f1b3ed8aba --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-smarc-som.dtsi @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2023 Boundary Devices + * Copyright 2024 Silicon Signals Pvt. Ltd. + * + * Author : Bhavin Sharma + */ + +/dts-v1/; + +#include +#include "imx8mp.dtsi" + +/ { + model = "Boundary Device Nitrogen8MP SMARC SoM"; + compatible = "boundary,imx8mp-nitrogen-smarc-som", "fsl,imx8mp"; + + chosen { + stdout-path = &uart2; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_led>; + + led-0 { + function = LED_FUNCTION_POWER; + gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + + reg_usdhc2_vmmc: regulator-usdhc2-vmmc { + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&A53_0 { + cpu-supply = <&buck2>; +}; + +&A53_1 { + cpu-supply = <&buck2>; +}; + +&A53_2 { + cpu-supply = <&buck2>; +}; + +&A53_3 { + cpu-supply = <&buck2>; +}; + +&i2c1 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@25 { + compatible = "nxp,pca9450c"; + reg = <0x25>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupt-parent = <&gpio1>; + interrupts = <14 IRQ_TYPE_LEVEL_LOW>; + + regulators { + buck1: BUCK1 { + regulator-name = "BUCK1"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <2187500>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + }; + + buck2: BUCK2 { + regulator-name = "BUCK2"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <2187500>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + nxp,dvs-run-voltage = <950000>; + nxp,dvs-standby-voltage = <850000>; + }; + + buck4: BUCK4 { + regulator-name = "BUCK4"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + regulator-boot-on; + regulator-always-on; + }; + + buck5: BUCK5 { + regulator-name = "BUCK5"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + regulator-boot-on; + regulator-always-on; + }; + + buck6: BUCK6 { + regulator-name = "BUCK6"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1: LDO1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2: LDO2 { + regulator-name = "LDO2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1150000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3: LDO3 { + regulator-name = "LDO3"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo4: LDO4 { + regulator-name = "LDO4"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo5: LDO5 { + regulator-name = "LDO5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&i2c6 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c6>; + status = "okay"; + + mcp23018: gpio@20 { + compatible = "microchip,mcp23018"; + gpio-controller; + #gpio-cells = <0x2>; + reg = <0x20>; + interrupts-extended = <&gpio4 22 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <0x2>; + microchip,irq-mirror; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mcp23018>; + reset-gpios = <&gpio4 27 GPIO_ACTIVE_LOW>; + }; +}; + +/* Console */ +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +/* SD-card */ +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_usdhc2_vmmc>; + bus-width = <4>; + status = "okay"; +}; + +/* eMMC */ +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl_gpio_led: gpioledgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10 0x19 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c3 + MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c3 + >; + }; + + pinctrl_i2c6: i2c6grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXFS__I2C6_SCL 0x400001c3 + MX8MP_IOMUXC_SAI5_RXC__I2C6_SDA 0x400001c3 + >; + }; + + pinctrl_mcp23018: mcp23018grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x1c0 + MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27 0x100 + >; + }; + + pinctrl_pmic: pmicgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14 0x1c0 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x40 + MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x40 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x10 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x150 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x150 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x150 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x150 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x150 + MX8MP_IOMUXC_SD1_DATA4__USDHC1_DATA4 0x150 + MX8MP_IOMUXC_SD1_DATA5__USDHC1_DATA5 0x150 + MX8MP_IOMUXC_SD1_DATA6__USDHC1_DATA6 0x150 + MX8MP_IOMUXC_SD1_DATA7__USDHC1_DATA7 0x150 + MX8MP_IOMUXC_SD1_STROBE__USDHC1_STROBE 0x10 + MX8MP_IOMUXC_SD1_RESET_B__USDHC1_RESET_B 0x140 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x14 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x154 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x154 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x154 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x154 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x154 + MX8MP_IOMUXC_SD1_DATA4__USDHC1_DATA4 0x154 + MX8MP_IOMUXC_SD1_DATA5__USDHC1_DATA5 0x154 + MX8MP_IOMUXC_SD1_DATA6__USDHC1_DATA6 0x154 + MX8MP_IOMUXC_SD1_DATA7__USDHC1_DATA7 0x154 + MX8MP_IOMUXC_SD1_STROBE__USDHC1_STROBE 0x14 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x12 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x152 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x152 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x152 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x152 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x152 + MX8MP_IOMUXC_SD1_DATA4__USDHC1_DATA4 0x152 + MX8MP_IOMUXC_SD1_DATA5__USDHC1_DATA5 0x152 + MX8MP_IOMUXC_SD1_DATA6__USDHC1_DATA6 0x152 + MX8MP_IOMUXC_SD1_DATA7__USDHC1_DATA7 0x152 + MX8MP_IOMUXC_SD1_STROBE__USDHC1_STROBE 0x12 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d0 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d0 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x194 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d4 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d4 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x196 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d6 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d6 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B 0x140 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-smarc-universal-board.dts b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-smarc-universal-board.dts new file mode 100644 index 00000000000000..46b243218dc895 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-nitrogen-smarc-universal-board.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2023 Boundary Devices + * Copyright 2024 Silicon Signals Pvt. Ltd. + * + * Author : Bhavin Sharma + */ + +/dts-v1/; + +#include "imx8mp-nitrogen-smarc-som.dtsi" + +/ { + model = "Boundary Device Nitrogen8MP Universal SMARC Carrier Board"; + compatible = "boundary,imx8mp-nitrogen-smarc-universal-board", + "boundary,imx8mp-nitrogen-smarc-som", "fsl,imx8mp"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts index 9c102acb8052cb..43615230864227 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts @@ -9,6 +9,7 @@ #include #include #include +#include #include "imx8mp-phycore-som.dtsi" / { @@ -32,6 +33,16 @@ backlight_lvds: backlight { pwms = <&pwm3 0 50000 0>; }; + fan0: fan { + compatible = "gpio-fan"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fan>; + gpio-fan,speed-map = <0 0 + 13000 1>; + gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>; + #cooling-cells = <2>; + }; + panel1_lvds: panel-lvds { compatible = "edt,etml1010g3dra"; backlight = <&backlight_lvds>; @@ -111,6 +122,25 @@ reg_vcc_3v3_sw: regulator-vcc-3v3-sw { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; + + thermal-zones { + soc-thermal { + trips { + active1: trip2 { + temperature = <60000>; + hysteresis = <2000>; + type = "active"; + }; + }; + + cooling-maps { + map1 { + trip = <&active1>; + cooling-device = <&fan0 1 THERMAL_NO_LIMIT>; + }; + }; + }; + }; }; /* TPM */ @@ -334,15 +364,16 @@ &usdhc2 { &gpio1 { gpio-line-names = "", "", "X_PMIC_WDOG_B", "", - "PMIC_SD_VSEL", "", "", "", "", "", - "", "", "USB1_OTG_PWR", "", "", "X_nETHPHY_INT"; + "PMIC_SD_VSEL", "", "", "", "PCIe_nPERST", "LVDS1REG_EN", + "PCIe_nWAKE", "PCIe_nCLKREQ", "USB1_OTG_PWR", "", + "PCIe_nW_DISABLE"; }; &gpio2 { gpio-line-names = "", "", "", "", "", "", "", "", "", "", "", "", "X_SD2_CD_B", "", "", "", - "", "", "", "SD2_RESET_B"; + "", "", "", "SD2_RESET_B", "LVDS1_BL_EN"; }; &gpio3 { @@ -356,7 +387,12 @@ &gpio4 { gpio-line-names = "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "", "", "X_PMIC_IRQ_B", "", "nENET0_INT_PWDN"; + "", "", "X_PMIC_IRQ_B", "nRTC_INT", "nENET0_INT_PWDN"; +}; + +&gpio5 { + gpio-line-names = "", "", "", "", + "", "", "", "", "", "X_ECSPI1_SSO"; }; &iomuxc { @@ -389,6 +425,12 @@ MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20 0x10 >; }; + pinctrl_fan: fan0grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_RX__GPIO5_IO04 0x16 + >; + }; + pinctrl_flexcan1: flexcan1grp { fsl,pins = < MX8MP_IOMUXC_SAI5_RXD2__CAN1_RX 0x154 diff --git a/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi index a5ecdca8bc0ead..04f724c6ec210b 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-phycore-som.dtsi @@ -209,9 +209,7 @@ &wdog1 { }; &gpio1 { - gpio-line-names = "", "", "X_PMIC_WDOG_B", "", - "", "", "", "", "", "", - "", "", "", "", "", "X_nETHPHY_INT"; + gpio-line-names = "", "", "X_PMIC_WDOG_B"; }; &gpio4 { diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi index 6c75a5ecf56bb1..10713c34ff3977 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw702x.dtsi @@ -11,6 +11,8 @@ / { aliases { ethernet0 = &eqos; + rtc0 = &gsc_rtc; + rtc1 = &snvs_rtc; }; memory@40000000 { @@ -280,7 +282,7 @@ eeprom@53 { pagesize = <16>; }; - rtc@68 { + gsc_rtc: rtc@68 { compatible = "dallas,ds1672"; reg = <0x68>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts index d765b79728415e..6daa2313f87900 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts @@ -25,6 +25,8 @@ aliases { ethernet4 = &lan3; ethernet5 = &lan4; ethernet6 = &lan5; + rtc0 = &gsc_rtc; + rtc1 = &snvs_rtc; }; chosen { @@ -299,7 +301,7 @@ &gpio2 { &gpio3 { gpio-line-names = "", "", "", "", "", "", "m2_rst", "", - "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "m2_gpio10", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""; }; @@ -481,7 +483,7 @@ eeprom@53 { pagesize = <16>; }; - rtc@68 { + gsc_rtc: rtc@68 { compatible = "dallas,ds1672"; reg = <0x68>; }; @@ -816,6 +818,7 @@ MX8MP_IOMUXC_SD2_CLK__GPIO2_IO13 0x40000150 /* PCIE1_WDIS# */ MX8MP_IOMUXC_SD2_CMD__GPIO2_IO14 0x40000150 /* PCIE3_WDIS# */ MX8MP_IOMUXC_SD2_DATA3__GPIO2_IO18 0x40000150 /* PCIE2_WDIS# */ MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06 0x40000040 /* M2SKT_RST# */ + MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14 0x40000040 /* M2SKT_GPIO10 */ MX8MP_IOMUXC_SAI3_TXD__GPIO5_IO01 0x40000104 /* UART_TERM */ MX8MP_IOMUXC_SAI3_TXFS__GPIO4_IO31 0x40000104 /* UART_RS485 */ MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00 0x40000104 /* UART_HALF */ diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw75xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw75xx.dtsi index 0d40cb0f05f677..f90b293c85fcbd 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw75xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw75xx.dtsi @@ -104,6 +104,16 @@ &i2c2 { pinctrl-0 = <&pinctrl_i2c2>; status = "okay"; + accelerometer@19 { + compatible = "st,lis2de12"; + reg = <0x19>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_accel>; + interrupt-parent = <&gpio5>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + st,drdy-int-pin = <1>; + }; + eeprom@52 { compatible = "atmel,24c32"; reg = <0x52>; @@ -204,6 +214,12 @@ MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28 0x40000106 /* PCI_WDIS# */ >; }; + pinctrl_accel: accelgrp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI1_MISO__GPIO5_IO08 0x159 + >; + }; + pinctrl_gpio_leds: gpioledgrp { fsl,pins = < MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x6 /* LEDG */ diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw82xx-2x.dts b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw82xx-2x.dts new file mode 100644 index 00000000000000..5978133086304a --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw82xx-2x.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2024 Gateworks Corporation + */ + +/dts-v1/; + +#include "imx8mp.dtsi" +#include "imx8mp-venice-gw702x.dtsi" +#include "imx8mp-venice-gw82xx.dtsi" + +/ { + model = "Gateworks Venice GW82xx-2x i.MX8MP Development Kit"; + compatible = "gateworks,imx8mp-gw82xx-2x", "fsl,imx8mp"; + + chosen { + stdout-path = &uart2; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw82xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw82xx.dtsi new file mode 100644 index 00000000000000..2b86cc62a41a04 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw82xx.dtsi @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2024 Gateworks Corporation + */ + +#include +#include +#include + +/ { + aliases { + ethernet1 = ð1; + fsa1 = &fsa0; + fsa2 = &fsa1; + }; + + led-controller { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_leds>; + + led-0 { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&gpio4 1 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led-1 { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + }; + + pcie0_refclk: clock-pcie0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; + + pps { + compatible = "pps-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pps>; + gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; + }; + + reg_usb2_vbus: regulator-usb2 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usb2_en>; + regulator-name = "usb2_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio4 12 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_usdhc2_vmmc: regulator-usdhc2-vmmc { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2_vmmc>; + regulator-name = "VDD_3V3_SD"; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + off-on-delay-us = <12000>; + startup-delay-us = <100>; + }; +}; + +&ecspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi2>; + cs-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>, /* CS0 onboard TPM */ + <&gpio5 13 GPIO_ACTIVE_LOW>, /* CS1 off-board J32 SPI */ + <&gpio1 12 GPIO_ACTIVE_LOW>, /* CS3 off-board J52 FSA1 */ + <&gpio4 26 GPIO_ACTIVE_LOW>; /* CS2 off-board J51 FSA2 */ + status = "okay"; + + tpm@0 { + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; + reg = <0x0>; + spi-max-frequency = <10000000>; + }; +}; + +&flexcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can1>; + status = "okay"; +}; + +&flexcan2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can2>; + status = "okay"; +}; + +&gpio1 { + gpio-line-names = + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "fsa2_gpio1", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", ""; +}; + +&gpio4 { + gpio-line-names = + "", "", "", "", + "", "", "", "", + "dio1", "fsa1_gpio2", "", "dio0", + "", "", "", "", + "", "", "", "", + "", "", "rs485_en", "rs485_term", + "fsa2_gpio2", "fsa1_gpio1", "", "rs485_half", + "", "", "", ""; +}; + +&i2c2 { + accelerometer@19 { + compatible = "st,lis2de12"; + reg = <0x19>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_accel>; + interrupt-parent = <&gpio4>; + interrupts = <21 IRQ_TYPE_LEVEL_LOW>; + st,drdy-int-pin = <1>; + }; + + magnetometer@1e { + compatible = "st,lis2mdl"; + reg = <0x1e>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mag>; + interrupt-parent = <&gpio4>; + interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +&i2c3 { + i2c-mux@70 { + compatible = "nxp,pca9548"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + /* J30 */ + fsa1: i2c@0 { + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fsa2i2c>; + #address-cells = <1>; + #size-cells = <0>; + + gpio@20 { + compatible = "nxp,pca9555"; + reg = <0x20>; + interrupt-parent = <&gpio4>; + interrupts = <4 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; + + eeprom@54 { + compatible = "atmel,24c02"; + reg = <0x54>; + pagesize = <16>; + }; + + eeprom@55 { + compatible = "atmel,24c02"; + reg = <0x55>; + pagesize = <16>; + }; + }; + + /* J29 */ + fsa0: i2c@1 { + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fsa1i2c>; + #address-cells = <1>; + #size-cells = <0>; + + gpio@20 { + compatible = "nxp,pca9555"; + reg = <0x20>; + interrupt-parent = <&gpio4>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; + + eeprom@54 { + compatible = "atmel,24c02"; + reg = <0x54>; + pagesize = <16>; + }; + + eeprom@55 { + compatible = "atmel,24c02"; + reg = <0x55>; + pagesize = <16>; + }; + }; + + /* J33 */ + i2c@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&pcie_phy { + clocks = <&pcie0_refclk>; + clock-names = "ref"; + fsl,refclk-pad-mode = ; + fsl,clkreq-unsupported; + status = "okay"; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcie0>; + reset-gpio = <&gpio4 29 GPIO_ACTIVE_LOW>; + status = "okay"; + + pcie@0,0 { + reg = <0x0000 0 0 0 0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + pcie@0,0 { + reg = <0x0000 0 0 0 0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + pcie@7,0 { + reg = <0x3800 0 0 0 0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + eth1: ethernet@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; + }; +}; + +/* GPS */ +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +/* RS232 */ +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; +}; + +/* USB1 - FSA1 */ +&usb3_0 { + fsl,permanently-attached; + fsl,disable-port-power-control; + status = "okay"; +}; + +&usb3_phy0 { + status = "okay"; +}; + +&usb_dwc3_0 { + dr_mode = "host"; + status = "okay"; +}; + +/* USB2 - USB3.0 Hub */ +&usb3_1 { + fsl,permanently-attached; + fsl,disable-port-power-control; + status = "okay"; +}; + +&usb3_phy1 { + vbus-supply = <®_usb2_vbus>; + status = "okay"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; + status = "okay"; +}; + +/* SDIO 1.8V */ +&usdhc1 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc1>; + pinctrl-1 = <&pinctrl_usdhc1_100mhz>; + pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + bus-width = <4>; + non-removable; + status = "okay"; +}; + +/* microSD */ +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>; /* CD is active high */ + bus-width = <4>; + vmmc-supply = <®_usdhc2_vmmc>; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + + pinctrl_hog: hoggrp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_RXD6__GPIO4_IO08 0x40000146 /* DIO1 */ + MX8MP_IOMUXC_SAI1_TXC__GPIO4_IO11 0x40000146 /* DIO0 */ + MX8MP_IOMUXC_SAI2_MCLK__GPIO4_IO27 0x40000106 /* RS485_HALF */ + MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x40000106 /* RS485_EN */ + MX8MP_IOMUXC_SAI2_RXD0__GPIO4_IO23 0x40000106 /* RS485_TERM */ + >; + }; + + pinctrl_accel: accelgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_RXFS__GPIO4_IO21 0x150 /* IRQ# */ + >; + }; + + pinctrl_can1: can1grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_TX__CAN1_TX 0x154 + MX8MP_IOMUXC_SPDIF_RX__CAN1_RX 0x154 + >; + }; + + pinctrl_can2: can2grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD3__CAN2_TX 0x154 + MX8MP_IOMUXC_SAI5_MCLK__CAN2_RX 0x154 + >; + }; + + pinctrl_gpio_leds: gpioledgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_RXC__GPIO4_IO01 0x6 /* LEDG */ + MX8MP_IOMUXC_SAI1_RXD3__GPIO4_IO05 0x6 /* LEDR */ + >; + }; + + pinctrl_fsa1i2c: fsa1i2cgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_TXD2__GPIO4_IO14 0x1d0 /* FSA1_ALERT# */ + MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25 0x400001d0 /* FSA1_GPIO1 */ + MX8MP_IOMUXC_SAI1_RXD7__GPIO4_IO09 0x400001d0 /* FSA1_GPIO2 */ + >; + }; + + pinctrl_fsa2i2c: fsa2i2cgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_RXD2__GPIO4_IO04 0x1d0 /* FSA2_ALERT# */ + MX8MP_IOMUXC_GPIO1_IO13__GPIO1_IO13 0x400001d0 /* FSA2_GPIO1 */ + MX8MP_IOMUXC_SAI2_TXFS__GPIO4_IO24 0x400001d0 /* FSA2_GPIO2 */ + >; + }; + + pinctrl_mag: maggrp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28 0x140 /* IRQ# */ + >; + }; + + pinctrl_pcie0: pcie0grp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29 0x106 /* PERST# */ + >; + }; + + pinctrl_pps: ppsgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_RXD1__GPIO4_IO03 0x146 + >; + }; + + pinctrl_reg_usb2_en: regusb2grp { + fsl,pins = < + MX8MP_IOMUXC_SAI1_TXD0__GPIO4_IO12 0x146 /* USBHUB_RST# */ + >; + }; + + pinctrl_spi2: spi2grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0xd0 + MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0xd0 + MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0xd0 + MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13 0x140 /* J32_CS */ + MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10 0x140 /* TPM_CS */ + MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x140 /* FSA1_CS */ + MX8MP_IOMUXC_SAI2_TXD0__GPIO4_IO26 0x140 /* FSA2_CS */ + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140 + MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x140 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX 0x140 + MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX 0x140 + >; + }; + + pinctrl_usdhc1: usdhc1grp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x190 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d0 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d0 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d0 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d0 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d0 + >; + }; + + pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x194 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d4 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d4 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d4 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d4 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d4 + >; + }; + + pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD1_CLK__USDHC1_CLK 0x196 + MX8MP_IOMUXC_SD1_CMD__USDHC1_CMD 0x1d6 + MX8MP_IOMUXC_SD1_DATA0__USDHC1_DATA0 0x1d6 + MX8MP_IOMUXC_SD1_DATA1__USDHC1_DATA1 0x1d6 + MX8MP_IOMUXC_SD1_DATA2__USDHC1_DATA2 0x1d6 + MX8MP_IOMUXC_SD1_DATA3__USDHC1_DATA3 0x1d6 + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d0 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d0 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0 + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x194 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d4 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d4 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4 + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x196 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d6 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d6 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6 + MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1 + >; + }; + + pinctrl_usdhc2_vmmc: usdhc2-vmmc-grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x1d0 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12 0x1c4 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-ivy.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-ivy.dtsi new file mode 100644 index 00000000000000..db1b4ee7728c07 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-ivy.dtsi @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + * + * Common dtsi for Verdin IMX8MP SoM on Ivy carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-plus + * https://www.toradex.com/products/carrier-board/ivy-carrier-board + */ + +#include +#include +#include + +/ { + /* AIN1 Voltage w/o AIN1_MODE gpio control */ + ain1_voltage_unmanaged: voltage-divider-ain1 { + compatible = "voltage-divider"; + #io-channel-cells = <1>; + io-channels = <&ivy_adc1 0>; + full-ohms = <19>; + output-ohms = <1>; + }; + + /* AIN1 Current w/o AIN1_MODE gpio control */ + ain1_current_unmanaged: current-sense-shunt-ain1 { + compatible = "current-sense-shunt"; + #io-channel-cells = <0>; + io-channels = <&ivy_adc1 1>; + shunt-resistor-micro-ohms = <100000000>; + }; + + /* AIN1_MODE - SODIMM 216 */ + ain1_mode_mux_ctrl: mux-controller-0 { + compatible = "gpio-mux"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio5>; + #mux-control-cells = <0>; + mux-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + }; + + ain1-voltage { + compatible = "io-channel-mux"; + channels = "ain1_voltage", ""; + io-channels = <&ain1_voltage_unmanaged 0>; + io-channel-names = "parent"; + mux-controls = <&ain1_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + ain1-current { + compatible = "io-channel-mux"; + channels = "", "ain1_current"; + io-channels = <&ain1_current_unmanaged>; + io-channel-names = "parent"; + mux-controls = <&ain1_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + /* AIN2 Voltage w/o AIN2_MODE gpio control */ + ain2_voltage_unmanaged: voltage-divider-ain2 { + compatible = "voltage-divider"; + #io-channel-cells = <1>; + io-channels = <&ivy_adc2 0>; + full-ohms = <19>; + output-ohms = <1>; + }; + + /* AIN2 Current w/o AIN2_MODE gpio control */ + ain2_current_unmanaged: current-sense-shunt-ain2 { + compatible = "current-sense-shunt"; + #io-channel-cells = <0>; + io-channels = <&ivy_adc2 1>; + shunt-resistor-micro-ohms = <100000000>; + }; + + /* AIN2_MODE - SODIMM 218 */ + ain2_mode_mux_ctrl: mux-controller-1 { + compatible = "gpio-mux"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio6>; + #mux-control-cells = <0>; + mux-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; + }; + + ain2-voltage { + compatible = "io-channel-mux"; + channels = "ain2_voltage", ""; + io-channels = <&ain2_voltage_unmanaged 0>; + io-channel-names = "parent"; + mux-controls = <&ain2_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + ain2-current { + compatible = "io-channel-mux"; + channels = "", "ain2_current"; + io-channels = <&ain2_current_unmanaged>; + io-channel-names = "parent"; + mux-controls = <&ain2_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ivy_leds>; + + /* D7 Blue - SODIMM 30 - LEDs.GPIO1 */ + led-0 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&gpio3 25 GPIO_ACTIVE_HIGH>; + }; + + /* D7 Green - SODIMM 32 - LEDs.GPIO2 */ + led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>; + }; + + /* D7 Red - SODIMM 34 - LEDs.GPIO3 */ + led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Blue - SODIMM 36 - LEDs.GPIO4 */ + led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&gpio4 2 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Green - SODIMM 54 - LEDs.GPIO5 */ + led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Red - SODIMM 44 - LEDs.GPIO6 */ + led-5 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&gpio4 31 GPIO_ACTIVE_HIGH>; + }; + + /* D9 Blue - SODIMM 46 - LEDs.GPIO7 */ + led-6 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <3>; + gpios = <&gpio5 01 GPIO_ACTIVE_HIGH>; + }; + + /* D9 Red - SODIMM 48 - LEDs.GPIO8 */ + led-7 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <3>; + gpios = <&gpio4 30 GPIO_ACTIVE_HIGH>; + }; + }; + + reg_3v2_ain1: regulator-3v2-ain1 { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3200000>; + regulator-min-microvolt = <3200000>; + regulator-name = "+3V2_AIN1"; + }; + + reg_3v2_ain2: regulator-3v2-ain2 { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3200000>; + regulator-min-microvolt = <3200000>; + regulator-name = "+3V2_AIN2"; + }; + + /* Ivy Power Supply Input Voltage */ + ivy-input-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_1 */ + io-channels = <&verdin_som_adc 7>; + full-ohms = <204700>; /* 200k + 4.7k */ + output-ohms = <4700>; + }; + + ivy-5v-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_2 */ + io-channels = <&verdin_som_adc 6>; + full-ohms = <39000>; /* 27k + 12k */ + output-ohms = <12000>; + }; + + ivy-3v3-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_3 */ + io-channels = <&verdin_som_adc 5>; + full-ohms = <54000>; /* 27k + 27k */ + output-ohms = <27000>; + }; + + ivy-1v8-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_4 */ + io-channels = <&verdin_som_adc 4>; + full-ohms = <39000>; /* 12k + 27k */ + output-ohms = <27000>; + }; +}; + +/* Verdin SPI_1 */ +&ecspi1 { + pinctrl-0 = <&pinctrl_ecspi1>, + <&pinctrl_gpio1>, + <&pinctrl_gpio4>; + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, + <&gpio1 0 GPIO_ACTIVE_LOW>, + <&gpio1 6 GPIO_ACTIVE_LOW>; + status = "okay"; + + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + spi-max-frequency = <18500000>; + }; + + fram@2 { + compatible = "fujitsu,mb85rs256", "atmel,at25"; + reg = <2>; + address-width = <16>; + size = <32768>; + spi-max-frequency = <33000000>; + pagesize = <1>; + }; +}; + +/* EEPROM on Ivy */ +&eeprom_carrier_board { + status = "okay"; +}; + +/* Verdin ETH_1 */ +&eqos { + status = "okay"; +}; + +/* Verdin ETH_2 */ +&fec { + phy-handle = <ðphy2>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + +&verdin_eth2_mdio { + ethphy2: ethernet-phy@2 { + reg = <2>; + interrupt-parent = <&gpio4>; + interrupts = <18 IRQ_TYPE_LEVEL_LOW>; + ti,rx-internal-delay = ; + ti,tx-internal-delay = ; + }; +}; + +/* Verdin CAN_1 */ +&flexcan1 { + status = "okay"; +}; + +/* Verdin CAN_2 */ +&flexcan2 { + status = "okay"; +}; + +&gpio1 { + gpio-line-names = + "", /* 0 */ + "GPIO2", /* Verdin GPIO_2 - SODIMM 208 */ + "", + "", + "", + "GPIO3", /* Verdin GPIO_3 - SODIMM 210 */ + "", + "", + "", + "", + "", + "", /* 10 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 20 */ + "", + "", + "", + "", + "", + "", + "", + "", + ""; +}; + +&gpio3 { + gpio-line-names = + "", /* 0 */ + "", + "", + "", + "", + "", + "DIG_1", /* SODIMM 56 */ + "DIG_2", /* SODIMM 58 */ + "REL1", /* SODIMM 60 */ + "REL2", /* SODIMM 62 */ + "", /* 10 */ + "", + "", + "", + "REL4", /* SODIMM 66 */ + "", + "REL3", /* SODIMM 64 */ + "", + "", + "", + "", /* 20 */ + "", + "", + "", + "", + "", + "", + "", + "", + ""; +}; + +/* Temperature sensor on Ivy */ +&hwmon_temp { + compatible = "ti,tmp1075"; + status = "okay"; +}; + +/* Verdin I2C_4 CSI */ +&i2c3 { + status = "okay"; + + ivy_adc1: adc@40 { + compatible = "ti,ads1119"; + reg = <0x40>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio7>; + interrupt-parent = <&gpio4>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <®_3v2_ain1>; + dvdd-supply = <®_3v2_ain1>; + vref-supply = <®_3v2_ain1>; + #address-cells = <1>; + #io-channel-cells = <1>; + #size-cells = <0>; + + /* AIN1 0-33V Voltage Input */ + channel@0 { + reg = <0>; + diff-channels = <0 1>; + }; + + /* AIN1 0-20mA Current Input */ + channel@1 { + reg = <1>; + diff-channels = <2 3>; + }; + }; + + ivy_adc2: adc@41 { + compatible = "ti,ads1119"; + reg = <0x41>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio8>; + interrupt-parent = <&gpio4>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <®_3v2_ain2>; + dvdd-supply = <®_3v2_ain2>; + vref-supply = <®_3v2_ain2>; + #address-cells = <1>; + #io-channel-cells = <1>; + #size-cells = <0>; + + /* AIN2 0-33V Voltage Input */ + channel@0 { + reg = <0>; + diff-channels = <0 1>; + }; + + /* AIN2 0-20mA Current Input */ + channel@1 { + reg = <1>; + diff-channels = <2 3>; + }; + }; +}; + +/* Verdin I2C_1 */ +&i2c4 { + status = "okay"; +}; + +/* Verdin PCIE_1 */ +&pcie { + status = "okay"; +}; + +&pcie_phy { + status = "okay"; +}; + +/* Verdin UART_1 */ +&uart1 { + status = "okay"; +}; + +/* Verdin UART_2 */ +&uart2 { + linux,rs485-enabled-at-boot-time; + rs485-rx-during-tx; + status = "okay"; +}; + +/* Verdin UART_3 */ +&uart3 { + status = "okay"; +}; + +/* Verdin USB_1 */ +&usb3_0 { + status = "okay"; +}; + +&usb3_phy0 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usb3_1 { + status = "okay"; +}; + +&usb3_phy1 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&usdhc2 { + status = "okay"; +}; + +&iomuxc { + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio2>, <&pinctrl_gpio3>, + <&pinctrl_ivy_dig_inputs>, <&pinctrl_ivy_relays>; + + pinctrl_ivy_dig_inputs: ivydiginputsgrp { + fsl,pins = + , /* SODIMM 56 */ + ; /* SODIMM 58 */ + }; + + pinctrl_ivy_leds: ivyledsgrp { + fsl,pins = + , /* SODIMM 30 */ + , /* SODIMM 32 */ + , /* SODIMM 34 */ + , /* SODIMM 36 */ + , /* SODIMM 44 */ + , /* SODIMM 46 */ + , /* SODIMM 48 */ + ; /* SODIMM 54 */ + }; + + pinctrl_ivy_relays: ivyrelaysgrp { + fsl,pins = + , /* SODIMM 60 */ + , /* SODIMM 62 */ + , /* SODIMM 64 */ + ; /* SODIMM 66 */ + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-ivy.dts b/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-ivy.dts new file mode 100644 index 00000000000000..cb49690050ff3a --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-ivy.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + */ + +/dts-v1/; + +#include "imx8mp-verdin.dtsi" +#include "imx8mp-verdin-nonwifi.dtsi" +#include "imx8mp-verdin-ivy.dtsi" + +/ { + model = "Toradex Verdin iMX8M Plus on Ivy"; + compatible = "toradex,verdin-imx8mp-nonwifi-ivy", + "toradex,verdin-imx8mp-nonwifi", + "toradex,verdin-imx8mp", + "fsl,imx8mp"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-ivy.dts b/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-ivy.dts new file mode 100644 index 00000000000000..22b8fe70b36d52 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-ivy.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + */ + +/dts-v1/; + +#include "imx8mp-verdin.dtsi" +#include "imx8mp-verdin-wifi.dtsi" +#include "imx8mp-verdin-ivy.dtsi" + +/ { + model = "Toradex Verdin iMX8M Plus WB on Ivy"; + compatible = "toradex,verdin-imx8mp-wifi-ivy", + "toradex,verdin-imx8mp-wifi", + "toradex,verdin-imx8mp", + "fsl,imx8mp"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi index a19ad5ee7f792b..e3869efe4fd0c0 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi @@ -175,7 +175,7 @@ reg_usdhc2_vmmc: regulator-usdhc2 { regulator-max-microvolt = <3300000>; regulator-min-microvolt = <3300000>; regulator-name = "+V3.3_SD"; - startup-delay-us = <2000>; + startup-delay-us = <20000>; }; reserved-memory { @@ -320,7 +320,7 @@ &fec { pinctrl-0 = <&pinctrl_fec>; pinctrl-1 = <&pinctrl_fec_sleep>; - mdio { + verdin_eth2_mdio: mdio { #address-cells = <1>; #size-cells = <0>; @@ -478,6 +478,7 @@ &i2c1 { pinctrl-1 = <&pinctrl_i2c1_gpio>; scl-gpios = <&gpio5 14 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 15 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; status = "okay"; pca9450: pmic@25 { @@ -591,11 +592,12 @@ hwmon_temp_module: sensor@48 { vs-supply = <®_vdd_1v8>; }; - adc@49 { + verdin_som_adc: adc@49 { compatible = "ti,ads1015"; reg = <0x49>; #address-cells = <1>; #size-cells = <0>; + #io-channel-cells = <1>; /* Verdin I2C_1 (ADC_4 - ADC_3) */ channel@0 { @@ -669,6 +671,7 @@ &i2c2 { pinctrl-1 = <&pinctrl_i2c2_gpio>; scl-gpios = <&gpio5 16 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 17 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; atmel_mxt_ts_mezzanine: touch-mezzanine@4a { compatible = "atmel,maxtouch"; @@ -690,6 +693,7 @@ &i2c3 { pinctrl-1 = <&pinctrl_i2c3_gpio>; scl-gpios = <&gpio5 18 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 19 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; }; /* Verdin I2C_1 */ @@ -700,6 +704,7 @@ &i2c4 { pinctrl-1 = <&pinctrl_i2c4_gpio>; scl-gpios = <&gpio5 20 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio5 21 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; gpio_expander_21: gpio-expander@21 { compatible = "nxp,pcal6416"; @@ -788,6 +793,7 @@ &i2c5 { pinctrl-1 = <&pinctrl_i2c5_gpio>; scl-gpios = <&gpio3 26 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio3 27 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + single-master; }; /* Verdin PCIE_1 */ diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 40e847bc0b7f81..e0d3b8cba221e8 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -47,6 +47,20 @@ cpus { #address-cells = <1>; #size-cells = <0>; + idle-states { + entry-method = "psci"; + + cpu_pd_wait: cpu-pd-wait { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010033>; + local-timer-stop; + entry-latency-us = <1000>; + exit-latency-us = <700>; + min-residency-us = <2700>; + wakeup-latency-us = <1500>; + }; + }; + A53_0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; @@ -65,6 +79,7 @@ A53_0: cpu@0 { nvmem-cell-names = "speed_grade"; operating-points-v2 = <&a53_opp_table>; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; }; A53_1: cpu@1 { @@ -83,6 +98,7 @@ A53_1: cpu@1 { next-level-cache = <&A53_L2>; operating-points-v2 = <&a53_opp_table>; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; }; A53_2: cpu@2 { @@ -101,6 +117,7 @@ A53_2: cpu@2 { next-level-cache = <&A53_L2>; operating-points-v2 = <&a53_opp_table>; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; }; A53_3: cpu@3 { @@ -119,6 +136,7 @@ A53_3: cpu@3 { next-level-cache = <&A53_L2>; operating-points-v2 = <&a53_opp_table>; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; }; A53_L2: l2-cache0 { @@ -2176,8 +2194,11 @@ pcie: pcie@33800000 { pcie_ep: pcie-ep@33800000 { compatible = "fsl,imx8mp-pcie-ep"; - reg = <0x33800000 0x000400000>, <0x18000000 0x08000000>; - reg-names = "dbi", "addr_space"; + reg = <0x33800000 0x100000>, + <0x18000000 0x8000000>, + <0x33900000 0x100000>, + <0x33b00000 0x100000>; + reg-names = "dbi", "addr_space", "dbi2", "atu"; clocks = <&clk IMX8MP_CLK_HSIO_ROOT>, <&clk IMX8MP_CLK_HSIO_AXI>, <&clk IMX8MP_CLK_PCIE_ROOT>; diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi index e03186bbc41524..d51de8d899b2bd 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi @@ -1819,9 +1819,11 @@ pcie1: pcie@33c00000 { pcie1_ep: pcie-ep@33c00000 { compatible = "fsl,imx8mq-pcie-ep"; - reg = <0x33c00000 0x000400000>, - <0x20000000 0x08000000>; - reg-names = "dbi", "addr_space"; + reg = <0x33c00000 0x100000>, + <0x20000000 0x8000000>, + <0x33d00000 0x100000>, + <0x33f00000 0x100000>; + reg-names = "dbi", "addr_space", "dbi2", "atu"; num-lanes = <1>; interrupts = ; interrupt-names = "dma"; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts index 62203eed6a6cb1..50fd3370f7dce9 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qm-mek.dts @@ -92,6 +92,27 @@ vdevbuffer: memory@90400000 { reg = <0 0x90400000 0 0x100000>; no-map; }; + + dsp_reserved: memory@92400000 { + reg = <0 0x92400000 0 0x1000000>; + no-map; + }; + + dsp_vdev0vring0: memory@942f0000 { + reg = <0 0x942f0000 0 0x8000>; + no-map; + }; + + dsp_vdev0vring1: memory@942f8000 { + reg = <0 0x942f8000 0 0x8000>; + no-map; + }; + + dsp_vdev0buffer: memory@94300000 { + compatible = "shared-dma-pool"; + reg = <0 0x94300000 0 0x100000>; + no-map; + }; }; lvds_backlight0: backlight-lvds0 { @@ -181,6 +202,17 @@ reg_can2_stby: regulator-can2-stby { vin-supply = <®_can2_en>; }; + reg_pciea: regulator-pcie { + compatible = "regulator-fixed"; + pinctrl-0 = <&pinctrl_pciea_reg>; + pinctrl-names = "default"; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "mpcie_3v3"; + gpio = <&lsio_gpio1 13 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + reg_vref_1v8: regulator-adc-vref { compatible = "regulator-fixed"; regulator-name = "vref_1v8"; @@ -296,6 +328,12 @@ &cm41_intmux { status = "okay"; }; +&hsio_phy { + fsl,hsio-cfg = "pciea-pcieb-sata"; + fsl,refclk-pad-mode = "input"; + status = "okay"; +}; + &i2c0 { #address-cells = <1>; #size-cells = <0>; @@ -541,6 +579,25 @@ &fec2 { status = "okay"; }; +&pciea { + phys = <&hsio_phy 0 PHY_TYPE_PCIE 0>; + phy-names = "pcie-phy"; + pinctrl-0 = <&pinctrl_pciea>; + pinctrl-names = "default"; + reset-gpio = <&lsio_gpio4 29 GPIO_ACTIVE_LOW>; + vpcie-supply = <®_pciea>; + status = "okay"; +}; + +&pcieb { + phys = <&hsio_phy 1 PHY_TYPE_PCIE 1>; + phy-names = "pcie-phy"; + pinctrl-0 = <&pinctrl_pcieb>; + pinctrl-names = "default"; + reset-gpio = <&lsio_gpio5 0 GPIO_ACTIVE_LOW>; + status = "disabled"; +}; + &qm_pwm_lvds0 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm_lvds0>; @@ -640,6 +697,16 @@ &sai7 { status = "okay"; }; +&sata { + status = "okay"; +}; + +&vpu_dsp { + memory-region = <&dsp_vdev0buffer>, <&dsp_vdev0vring0>, + <&dsp_vdev0vring1>, <&dsp_reserved>; + status = "okay"; +}; + &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; @@ -829,6 +896,28 @@ IMX8QM_LVDS1_I2C1_SDA_LVDS1_I2C1_SDA 0xc600004c >; }; + pinctrl_pciea: pcieagrp { + fsl,pins = < + IMX8QM_PCIE_CTRL0_WAKE_B_LSIO_GPIO4_IO28 0x04000021 + IMX8QM_PCIE_CTRL0_PERST_B_LSIO_GPIO4_IO29 0x06000021 + IMX8QM_SCU_GPIO0_07_SCU_DSC_RTC_CLOCK_OUTPUT_32K 0x20 + >; + }; + + pinctrl_pciea_reg: pcieareggrp { + fsl,pins = < + IMX8QM_LVDS1_I2C0_SDA_LSIO_GPIO1_IO13 0x06000021 + >; + }; + + pinctrl_pcieb: pciebgrp { + fsl,pins = < + IMX8QM_PCIE_CTRL1_CLKREQ_B_HSIO_PCIE1_CLKREQ_B 0x06000021 + IMX8QM_PCIE_CTRL1_WAKE_B_LSIO_GPIO4_IO31 0x04000021 + IMX8QM_PCIE_CTRL1_PERST_B_LSIO_GPIO5_IO00 0x06000021 + >; + }; + pinctrl_pwm_lvds0: pwmlvds0grp { fsl,pins = < IMX8QM_LVDS0_GPIO00_LVDS0_PWM0_OUT 0x00000020 diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-audio.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-audio.dtsi index 3036af49fc8542..e24e639b98ee77 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-audio.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-audio.dtsi @@ -304,7 +304,7 @@ &dsp_ram_lpcg { }; /* edma2 called in imx8qm RM with the same address in edma0 of imx8qxp */ -&edma0{ +&edma0 { reg = <0x591f0000 0x150000>; dma-channels = <20>; dma-channel-mask = <0>; @@ -351,7 +351,7 @@ &edma0{ }; /* edma3 called in imx8qm RM with the same address in edma1 of imx8qxp */ -&edma1{ +&edma1 { reg = <0x599f0000 0xc0000>; dma-channels = <11>; dma-channel-mask = <0xc0>; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-conn.dtsi index 545e175c88b3e2..ccf9f510e0f88b 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-conn.dtsi @@ -4,6 +4,10 @@ * Dong Aisheng */ +&usbphy1 { + compatible = "fsl,imx8qm-usbphy", "fsl,imx7ulp-usbphy"; +}; + &fec1 { compatible = "fsl,imx8qm-fec", "fsl,imx6sx-fec"; iommus = <&smmu 0x12 0x7f80>; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi index aa9f28c4431d02..d4856b8590e0c5 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi @@ -4,6 +4,9 @@ * Dong Aisheng */ +/delete-node/ &adma_pwm; +/delete-node/ &adma_pwm_lpcg; + &dma_subsys { uart4_lpcg: clock-controller@5a4a0000 { compatible = "fsl,imx8qxp-lpcg"; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi new file mode 100644 index 00000000000000..b1d0189a172589 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-hsio.dtsi @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP + * Richard Zhu + */ + +&hsio_subsys { + compatible = "simple-bus"; + ranges = <0x5f000000 0x0 0x5f000000 0x01000000>, + <0x40000000 0x0 0x60000000 0x10000000>, + <0x80000000 0x0 0x70000000 0x10000000>; + #address-cells = <1>; + #size-cells = <1>; + + pciea: pcie@5f000000 { + compatible = "fsl,imx8q-pcie"; + reg = <0x5f000000 0x10000>, + <0x4ff00000 0x80000>; + reg-names = "dbi", "config"; + ranges = <0x81000000 0 0x00000000 0x4ff80000 0 0x00010000>, + <0x82000000 0 0x40000000 0x40000000 0 0x0ff00000>; + #interrupt-cells = <1>; + interrupts = ; + interrupt-names = "msi"; + #address-cells = <3>; + #size-cells = <2>; + clocks = <&pciea_lpcg IMX_LPCG_CLK_6>, + <&pciea_lpcg IMX_LPCG_CLK_4>, + <&pciea_lpcg IMX_LPCG_CLK_5>; + clock-names = "dbi", "mstr", "slv"; + bus-range = <0x00 0xff>; + device_type = "pci"; + interrupt-map = <0 0 0 1 &gic 0 73 4>, + <0 0 0 2 &gic 0 74 4>, + <0 0 0 3 &gic 0 75 4>, + <0 0 0 4 &gic 0 76 4>; + interrupt-map-mask = <0 0 0 0x7>; + num-lanes = <1>; + num-viewport = <4>; + power-domains = <&pd IMX_SC_R_PCIE_A>; + fsl,max-link-speed = <3>; + status = "disabled"; + }; + + pcieb: pcie@5f010000 { + compatible = "fsl,imx8q-pcie"; + reg = <0x5f010000 0x10000>, + <0x8ff00000 0x80000>; + reg-names = "dbi", "config"; + ranges = <0x81000000 0 0x00000000 0x8ff80000 0 0x00010000>, + <0x82000000 0 0x80000000 0x80000000 0 0x0ff00000>; + #interrupt-cells = <1>; + interrupts = ; + interrupt-names = "msi"; + #address-cells = <3>; + #size-cells = <2>; + clocks = <&pcieb_lpcg IMX_LPCG_CLK_6>, + <&pcieb_lpcg IMX_LPCG_CLK_4>, + <&pcieb_lpcg IMX_LPCG_CLK_5>; + clock-names = "dbi", "mstr", "slv"; + bus-range = <0x00 0xff>; + device_type = "pci"; + interrupt-map = <0 0 0 1 &gic 0 105 4>, + <0 0 0 2 &gic 0 106 4>, + <0 0 0 3 &gic 0 107 4>, + <0 0 0 4 &gic 0 108 4>; + interrupt-map-mask = <0 0 0 0x7>; + num-lanes = <1>; + num-viewport = <4>; + power-domains = <&pd IMX_SC_R_PCIE_B>; + fsl,max-link-speed = <3>; + status = "disabled"; + }; + + sata: sata@5f020000 { + compatible = "fsl,imx8qm-ahci"; + reg = <0x5f020000 0x10000>; + interrupts = ; + clocks = <&sata_lpcg IMX_LPCG_CLK_4>, + <&sata_crr4_lpcg IMX_LPCG_CLK_4>; + clock-names = "sata", "sata_ref"; + phy-names = "sata-phy", "cali-phy0", "cali-phy1"; + power-domains = <&pd IMX_SC_R_SATA_0>; + /* + * Since "REXT" pin is only present for first lane PHY + * and its calibration result will be stored, and shared + * by the PHY used by SATA. + * + * Add the calibration PHYs for SATA here, although only + * the third lane PHY is used by SATA. + */ + phys = <&hsio_phy 2 PHY_TYPE_SATA 0>, + <&hsio_phy 0 PHY_TYPE_PCIE 0>, + <&hsio_phy 1 PHY_TYPE_PCIE 1>; + status = "disabled"; + }; + + pciea_lpcg: clock-controller@5f050000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f050000 0x10000>; + clocks = <&hsio_axi_clk>, <&hsio_axi_clk>, <&hsio_axi_clk>; + #clock-cells = <1>; + clock-indices = , , ; + clock-output-names = "hsio_pciea_mstr_axi_clk", + "hsio_pciea_slv_axi_clk", + "hsio_pciea_dbi_axi_clk"; + power-domains = <&pd IMX_SC_R_PCIE_A>; + }; + + sata_lpcg: clock-controller@5f070000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f070000 0x10000>; + clocks = <&hsio_axi_clk>; + #clock-cells = <1>; + clock-indices = ; + clock-output-names = "hsio_sata_clk"; + power-domains = <&pd IMX_SC_R_SATA_0>; + }; + + phyx2_lpcg: clock-controller@5f080000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f080000 0x10000>; + clocks = <&hsio_refa_clk>, <&hsio_per_clk>, + <&hsio_refa_clk>, <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = , , + , ; + clock-output-names = "hsio_phyx2_pclk_0", + "hsio_phyx2_pclk_1", + "hsio_phyx2_apbclk_0", + "hsio_phyx2_apbclk_1"; + power-domains = <&pd IMX_SC_R_SERDES_0>; + }; + + phyx1_lpcg: clock-controller@5f090000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f090000 0x10000>; + clocks = <&hsio_refa_clk>, <&hsio_per_clk>, + <&hsio_per_clk>, <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = , , + , ; + clock-output-names = "hsio_phyx1_pclk", + "hsio_phyx1_epcs_tx_clk", + "hsio_phyx1_epcs_rx_clk", + "hsio_phyx1_apb_clk"; + power-domains = <&pd IMX_SC_R_SERDES_1>; + }; + + phyx2_crr0_lpcg: clock-controller@5f0a0000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f0a0000 0x10000>; + clocks = <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = ; + clock-output-names = "hsio_phyx2_per_clk"; + power-domains = <&pd IMX_SC_R_SERDES_0>; + }; + + pciea_crr2_lpcg: clock-controller@5f0c0000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f0c0000 0x10000>; + clocks = <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = ; + clock-output-names = "hsio_pciea_per_clk"; + power-domains = <&pd IMX_SC_R_PCIE_A>; + }; + + sata_crr4_lpcg: clock-controller@5f0e0000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f0e0000 0x10000>; + clocks = <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = ; + clock-output-names = "hsio_sata_per_clk"; + power-domains = <&pd IMX_SC_R_SATA_0>; + }; + + hsio_phy: phy@5f180000 { + compatible = "fsl,imx8qm-hsio"; + reg = <0x5f180000 0x30000>, + <0x5f110000 0x20000>, + <0x5f130000 0x30000>, + <0x5f160000 0x10000>; + reg-names = "reg", "phy", "ctrl", "misc"; + clocks = <&phyx2_lpcg IMX_LPCG_CLK_0>, + <&phyx2_lpcg IMX_LPCG_CLK_1>, + <&phyx2_lpcg IMX_LPCG_CLK_4>, + <&phyx2_lpcg IMX_LPCG_CLK_5>, + <&phyx1_lpcg IMX_LPCG_CLK_0>, + <&phyx1_lpcg IMX_LPCG_CLK_1>, + <&phyx1_lpcg IMX_LPCG_CLK_2>, + <&phyx1_lpcg IMX_LPCG_CLK_4>, + <&phyx2_crr0_lpcg IMX_LPCG_CLK_4>, + <&phyx1_crr1_lpcg IMX_LPCG_CLK_4>, + <&pciea_crr2_lpcg IMX_LPCG_CLK_4>, + <&pcieb_crr3_lpcg IMX_LPCG_CLK_4>, + <&sata_crr4_lpcg IMX_LPCG_CLK_4>, + <&misc_crr5_lpcg IMX_LPCG_CLK_4>; + clock-names = "pclk0", "pclk1", "apb_pclk0", "apb_pclk1", + "pclk2", "epcs_tx", "epcs_rx", "apb_pclk2", + "phy0_crr", "phy1_crr", "ctl0_crr", + "ctl1_crr", "ctl2_crr", "misc_crr"; + #phy-cells = <3>; + power-domains = <&pd IMX_SC_R_SERDES_0>, <&pd IMX_SC_R_SERDES_1>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qm.dtsi b/arch/arm64/boot/dts/freescale/imx8qm.dtsi index 3ee6e2869e3cf5..6fa31bc9ece8f9 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qm.dtsi @@ -24,6 +24,10 @@ aliases { serial1 = &lpuart1; serial2 = &lpuart2; serial3 = &lpuart3; + spi0 = &lpspi0; + spi1 = &lpspi1; + spi2 = &lpspi2; + spi3 = &lpspi3; vpu-core0 = &vpu_core0; vpu-core1 = &vpu_core1; vpu-core2 = &vpu_core2; @@ -581,6 +585,32 @@ mipi_pll_div2_clk: clock-controller-mipi-div2-pll { clock-output-names = "mipi_pll_div2_clk"; }; + vpu_subsys_dsp: bus@55000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x55000000 0x0 0x55000000 0x1000000>; + + vpu_dsp: dsp@556e8000 { + compatible = "fsl,imx8qm-hifi4"; + reg = <0x556e8000 0x88000>; + clocks = <&clk_dummy>, + <&clk_dummy>, + <&clk_dummy>; + clock-names = "ipg", "ocram", "core"; + power-domains = <&pd IMX_SC_R_MU_13B>, + <&pd IMX_SC_R_DSP>, + <&pd IMX_SC_R_DSP_RAM>, + <&pd IMX_SC_R_MU_2A>; + mboxes = <&lsio_mu13 0 0>, + <&lsio_mu13 1 0>, + <&lsio_mu13 3 0>; + mbox-names = "tx", "rx", "rxdb"; + firmware-name = "imx/dsp/hifi4.bin"; + status = "disabled"; + }; + }; + /* sorted in register address */ #include "imx8-ss-cm41.dtsi" #include "imx8-ss-audio.dtsi" @@ -594,6 +624,7 @@ mipi_pll_div2_clk: clock-controller-mipi-div2-pll { #include "imx8-ss-dma.dtsi" #include "imx8-ss-conn.dtsi" #include "imx8-ss-lsio.dtsi" + #include "imx8-ss-hsio.dtsi" }; #include "imx8qm-ss-img.dtsi" @@ -603,3 +634,6 @@ mipi_pll_div2_clk: clock-controller-mipi-div2-pll { #include "imx8qm-ss-audio.dtsi" #include "imx8qm-ss-lvds.dtsi" #include "imx8qm-ss-mipi.dtsi" +#include "imx8qm-ss-hsio.dtsi" + +/delete-node/ &dsp; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts index 936ba5ecdcac76..be79c793213a53 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts @@ -12,15 +12,52 @@ / { model = "Freescale i.MX8QXP MEK"; compatible = "fsl,imx8qxp-mek", "fsl,imx8qxp"; + bt_sco_codec: audio-codec-bt { + compatible = "linux,bt-sco"; + #sound-dai-cells = <1>; + }; + chosen { stdout-path = &lpuart0; }; + imx8x_cm4: imx8x-cm4 { + compatible = "fsl,imx8qxp-cm4"; + mbox-names = "tx", "rx", "rxdb"; + mboxes = <&lsio_mu5 0 1 + &lsio_mu5 1 1 + &lsio_mu5 3 1>; + memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, + <&vdev1vring0>, <&vdev1vring1>, <&rsc_table>; + power-domains = <&pd IMX_SC_R_M4_0_PID0>, + <&pd IMX_SC_R_M4_0_MU_1A>; + fsl,entry-address = <0x34fe0000>; + fsl,resource-id = ; + }; + memory@80000000 { device_type = "memory"; reg = <0x00000000 0x80000000 0 0x40000000>; }; + reserved-memory { + dsp_vdev0vring0: memory@942f0000 { + reg = <0 0x942f0000 0 0x8000>; + no-map; + }; + + dsp_vdev0vring1: memory@942f8000 { + reg = <0 0x942f8000 0 0x8000>; + no-map; + }; + + dsp_vdev0buffer: memory@94300000 { + compatible = "shared-dma-pool"; + reg = <0 0x94300000 0 0x100000>; + no-map; + }; + }; + reg_usdhc2_vmmc: usdhc2-vmmc { compatible = "regulator-fixed"; regulator-name = "SD1_SPWR"; @@ -45,6 +82,132 @@ usb3_data_ss: endpoint { }; }; + reg_pcieb: regulator-pcie { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "mpcie_3v3"; + gpio = <&pca9557_a 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_audio: regulator-audio { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "cs42888_supply"; + }; + + reg_can_en: regulator-can-en { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "can-en"; + gpio = <&pca6416 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_can_stby: regulator-can-stby { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "can-stby"; + gpio = <&pca6416 5 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_can_en>; + }; + + reg_usb_otg1_vbus: regulator-usbotg1-vbus { + compatible = "regulator-fixed"; + regulator-max-microvolt = <5000000>; + regulator-min-microvolt = <5000000>; + regulator-name = "usb_otg1_vbus"; + gpio = <&pca9557_b 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + vdev0vring0: memory@90000000 { + reg = <0 0x90000000 0 0x8000>; + no-map; + }; + + vdev0vring1: memory@90008000 { + reg = <0 0x90008000 0 0x8000>; + no-map; + }; + + vdev1vring0: memory@90010000 { + reg = <0 0x90010000 0 0x8000>; + no-map; + }; + + vdev1vring1: memory@90018000 { + reg = <0 0x90018000 0 0x8000>; + no-map; + }; + + rsc_table: memory@900ff000 { + reg = <0 0x900ff000 0 0x1000>; + no-map; + }; + + vdevbuffer: memory@90400000 { + compatible = "shared-dma-pool"; + reg = <0 0x90400000 0 0x100000>; + no-map; + }; + + gpu_reserved: memory@880000000 { + no-map; + reg = <0x8 0x80000000 0 0x10000000>; + }; + }; + + sound-bt-sco { + compatible = "simple-audio-card"; + simple-audio-card,bitclock-inversion; + simple-audio-card,bitclock-master = <&btcpu>; + simple-audio-card,format = "dsp_a"; + simple-audio-card,frame-master = <&btcpu>; + simple-audio-card,name = "bt-sco-audio"; + + simple-audio-card,codec { + sound-dai = <&bt_sco_codec 1>; + }; + + btcpu: simple-audio-card,cpu { + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <16>; + sound-dai = <&sai0>; + }; + }; + + sound-cs42888 { + compatible = "fsl,imx-audio-cs42888"; + audio-asrc = <&asrc0>; + audio-codec = <&cs42888>; + audio-cpu = <&esai0>; + audio-routing = + "Line Out Jack", "AOUT1L", + "Line Out Jack", "AOUT1R", + "Line Out Jack", "AOUT2L", + "Line Out Jack", "AOUT2R", + "Line Out Jack", "AOUT3L", + "Line Out Jack", "AOUT3R", + "Line Out Jack", "AOUT4L", + "Line Out Jack", "AOUT4R", + "AIN1L", "Line In Jack", + "AIN1R", "Line In Jack", + "AIN2L", "Line In Jack", + "AIN2R", "Line In Jack"; + model = "imx-cs42888"; + }; + sound-wm8960 { compatible = "fsl,imx-audio-wm8960"; model = "wm8960-audio"; @@ -62,8 +225,18 @@ sound-wm8960 { }; }; +&amix { + status = "okay"; +}; + +&asrc0 { + fsl,asrc-rate = <48000>; + status = "okay"; +}; + &dsp { - memory-region = <&dsp_reserved>; + memory-region = <&dsp_vdev0buffer>, <&dsp_vdev0vring0>, + <&dsp_vdev0vring1>, <&dsp_reserved>; status = "okay"; }; @@ -71,6 +244,19 @@ &dsp_reserved { status = "okay"; }; +&esai0 { + assigned-clocks = <&acm IMX_ADMA_ACM_ESAI0_MCLK_SEL>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>, + <&esai0_lpcg IMX_LPCG_CLK_0>; + assigned-clock-parents = <&aud_pll_div0_lpcg IMX_LPCG_CLK_0>; + assigned-clock-rates = <0>, <786432000>, <49152000>, <12288000>, <49152000>; + pinctrl-0 = <&pinctrl_esai0>; + pinctrl-names = "default"; + status = "okay"; +}; + &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec1>; @@ -240,12 +426,57 @@ pca6416: gpio@20 { gpio-controller; #gpio-cells = <2>; }; + + cs42888: audio-codec@48 { + compatible = "cirrus,cs42888"; + reg = <0x48>; + clocks = <&mclkout0_lpcg IMX_LPCG_CLK_0>; + clock-names = "mclk"; + assigned-clocks = <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_SLV_BUS>, + <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>, + <&mclkout0_lpcg IMX_LPCG_CLK_0>; + assigned-clock-rates = <786432000>, <49152000>, <12288000>, <12288000>; + reset-gpios = <&pca9557_b 1 GPIO_ACTIVE_LOW>; + VA-supply = <®_audio>; + VD-supply = <®_audio>; + VLC-supply = <®_audio>; + VLS-supply = <®_audio>; + }; }; &cm40_intmux { status = "okay"; }; +&hsio_phy { + fsl,hsio-cfg = "pciea-x2-pcieb"; + fsl,refclk-pad-mode = "input"; + status = "okay"; +}; + +&flexcan1 { + pinctrl-0 = <&pinctrl_flexcan1>; + pinctrl-names = "default"; + xceiver-supply = <®_can_stby>; + status = "okay"; +}; + +&flexcan2 { + pinctrl-0 = <&pinctrl_flexcan2>; + pinctrl-names = "default"; + xceiver-supply = <®_can_stby>; + status = "okay"; +}; + +&jpegdec { + status = "okay"; +}; + +&jpegenc { + status = "okay"; +}; + &lpuart0 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpuart0>; @@ -264,6 +495,10 @@ &lpuart3 { status = "okay"; }; +&lsio_mu5 { + status = "okay"; +}; + &mu_m0 { status = "okay"; }; @@ -272,6 +507,16 @@ &mu1_m0 { status = "okay"; }; +&pcieb { + phys = <&hsio_phy 0 PHY_TYPE_PCIE 0>; + phy-names = "pcie-phy"; + pinctrl-0 = <&pinctrl_pcieb>; + pinctrl-names = "default"; + reset-gpios = <&lsio_gpio4 0 GPIO_ACTIVE_LOW>; + vpcie-supply = <®_pcieb>; + status = "okay"; +}; + &scu_key { status = "okay"; }; @@ -384,6 +629,20 @@ &usb3_phy { status = "okay"; }; +&usbphy1 { + status = "okay"; +}; + +&usbotg1 { + adp-disable; + hnp-disable; + srp-disable; + disable-over-current; + power-active-high; + vbus-supply = <®_usb_otg1_vbus>; + status = "okay"; +}; + &usbotg3 { status = "okay"; }; @@ -434,6 +693,21 @@ IMX8QXP_ADC_IN0_LSIO_GPIO1_IO10 0xc600004c >; }; + pinctrl_esai0: esai0grp { + fsl,pins = < + IMX8QXP_ESAI0_FSR_ADMA_ESAI0_FSR 0xc6000040 + IMX8QXP_ESAI0_FST_ADMA_ESAI0_FST 0xc6000040 + IMX8QXP_ESAI0_SCKR_ADMA_ESAI0_SCKR 0xc6000040 + IMX8QXP_ESAI0_SCKT_ADMA_ESAI0_SCKT 0xc6000040 + IMX8QXP_ESAI0_TX0_ADMA_ESAI0_TX0 0xc6000040 + IMX8QXP_ESAI0_TX1_ADMA_ESAI0_TX1 0xc6000040 + IMX8QXP_ESAI0_TX2_RX3_ADMA_ESAI0_TX2_RX3 0xc6000040 + IMX8QXP_ESAI0_TX3_RX2_ADMA_ESAI0_TX3_RX2 0xc6000040 + IMX8QXP_ESAI0_TX4_RX1_ADMA_ESAI0_TX4_RX1 0xc6000040 + IMX8QXP_ESAI0_TX5_RX0_ADMA_ESAI0_TX5_RX0 0xc6000040 + >; + }; + pinctrl_fec1: fec1grp { fsl,pins = < IMX8QXP_ENET0_MDC_CONN_ENET0_MDC 0x06000020 @@ -453,6 +727,20 @@ IMX8QXP_ENET0_RGMII_RXD3_CONN_ENET0_RGMII_RXD3 0x06000020 >; }; + pinctrl_flexcan1: flexcan0grp { + fsl,pins = < + IMX8QXP_FLEXCAN0_TX_ADMA_FLEXCAN0_TX 0x21 + IMX8QXP_FLEXCAN0_RX_ADMA_FLEXCAN0_RX 0x21 + >; + }; + + pinctrl_flexcan2: flexcan1grp { + fsl,pins = < + IMX8QXP_FLEXCAN1_TX_ADMA_FLEXCAN1_TX 0x21 + IMX8QXP_FLEXCAN1_RX_ADMA_FLEXCAN1_RX 0x21 + >; + }; + pinctrl_ioexp_rst: ioexprstgrp { fsl,pins = < IMX8QXP_SPI2_SDO_LSIO_GPIO1_IO01 0x06000021 @@ -493,6 +781,14 @@ IMX8QXP_FLEXCAN2_RX_ADMA_UART3_RX 0x06000020 >; }; + pinctrl_pcieb: pcieagrp { + fsl,pins = < + IMX8QXP_PCIE_CTRL0_PERST_B_LSIO_GPIO4_IO00 0x06000021 + IMX8QXP_PCIE_CTRL0_CLKREQ_B_HSIO_PCIE0_CLKREQ_B 0x06000021 + IMX8QXP_PCIE_CTRL0_WAKE_B_LSIO_GPIO4_IO02 0x04000021 + >; + }; + pinctrl_typec: typecgrp { fsl,pins = < IMX8QXP_SPI2_SCK_LSIO_GPIO1_IO03 0x06000021 diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-conn.dtsi index 46da21af370269..4eb48ad487457a 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-conn.dtsi @@ -4,6 +4,10 @@ * Dong Aisheng */ +&usbphy1 { + compatible = "fsl,imx8qxp-usbphy", "fsl,imx7ulp-usbphy"; +}; + &usdhc1 { compatible = "fsl,imx8qxp-usdhc", "fsl,imx7d-usdhc"; }; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-hsio.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-hsio.dtsi new file mode 100644 index 00000000000000..47fc6e0cff4a1a --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-hsio.dtsi @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP + * Richard Zhu + */ + +&hsio_subsys { + phyx1_lpcg: clock-controller@5f090000 { + compatible = "fsl,imx8qxp-lpcg"; + reg = <0x5f090000 0x10000>; + clocks = <&hsio_refb_clk>, <&hsio_per_clk>, + <&hsio_per_clk>, <&hsio_per_clk>; + #clock-cells = <1>; + clock-indices = , , + , ; + clock-output-names = "hsio_phyx1_pclk", + "hsio_phyx1_epcs_tx_clk", + "hsio_phyx1_epcs_rx_clk", + "hsio_phyx1_apb_clk"; + power-domains = <&pd IMX_SC_R_SERDES_1>; + }; + + hsio_phy: phy@5f1a0000 { + compatible = "fsl,imx8qxp-hsio"; + reg = <0x5f1a0000 0x10000>, + <0x5f120000 0x10000>, + <0x5f140000 0x10000>, + <0x5f160000 0x10000>; + reg-names = "reg", "phy", "ctrl", "misc"; + clocks = <&phyx1_lpcg IMX_LPCG_CLK_0>, + <&phyx1_lpcg IMX_LPCG_CLK_1>, + <&phyx1_crr1_lpcg IMX_LPCG_CLK_4>, + <&pcieb_crr3_lpcg IMX_LPCG_CLK_4>, + <&misc_crr5_lpcg IMX_LPCG_CLK_4>; + clock-names = "pclk0", "apb_pclk0", "phy0_crr", "ctl0_crr", + "misc_crr"; + #phy-cells = <3>; + power-domains = <&pd IMX_SC_R_SERDES_1>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi index 0313f295de2e93..05138326f0a572 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi @@ -46,6 +46,10 @@ aliases { serial1 = &lpuart1; serial2 = &lpuart2; serial3 = &lpuart3; + spi0 = &lpspi0; + spi1 = &lpspi1; + spi2 = &lpspi2; + spi3 = &lpspi3; vpu-core0 = &vpu_core0; vpu-core1 = &vpu_core1; }; @@ -323,6 +327,7 @@ map0 { #include "imx8-ss-conn.dtsi" #include "imx8-ss-ddr.dtsi" #include "imx8-ss-lsio.dtsi" + #include "imx8-ss-hsio.dtsi" }; #include "imx8qxp-ss-img.dtsi" @@ -330,3 +335,4 @@ map0 { #include "imx8qxp-ss-adma.dtsi" #include "imx8qxp-ss-conn.dtsi" #include "imx8qxp-ss-lsio.dtsi" +#include "imx8qxp-ss-hsio.dtsi" diff --git a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts index e937e5f8fa8b28..290a49bea2f769 100644 --- a/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8ulp-evk.dts @@ -11,6 +11,11 @@ / { model = "NXP i.MX8ULP EVK"; compatible = "fsl,imx8ulp-evk", "fsl,imx8ulp"; + bt_sco_codec: bt-sco-codec { + #sound-dai-cells = <1>; + compatible = "linux,bt-sco"; + }; + chosen { stdout-path = &lpuart5; }; @@ -83,6 +88,37 @@ clock_ext_ts: clock-ext-ts { clock-output-names = "ext_ts_clk"; #clock-cells = <0>; }; + + sound-bt-sco { + compatible = "simple-audio-card"; + simple-audio-card,name = "bt-sco-audio"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,bitclock-inversion; + simple-audio-card,frame-master = <&btcpu>; + simple-audio-card,bitclock-master = <&btcpu>; + + btcpu: simple-audio-card,cpu { + sound-dai = <&sai5>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <16>; + }; + + simple-audio-card,codec { + sound-dai = <&bt_sco_codec 1>; + }; + }; + + sound-spdif { + compatible = "fsl,imx-audio-spdif"; + model = "imx-spdif"; + audio-cpu = <&spdif>; + audio-codec = <&spdif_out>; + }; + + spdif_out: spdif-out { + compatible = "linux,spdif-dit"; + #sound-dai-cells = <0>; + }; }; &cm33 { @@ -153,6 +189,25 @@ ptn5150_2: typec@3d { }; }; +&sai5 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_sai5>; + pinctrl-1 = <&pinctrl_sai5>; + assigned-clocks = <&cgc1 IMX8ULP_CLK_SAI5_SEL>; + assigned-clock-parents = <&cgc1 IMX8ULP_CLK_SPLL3_PFD1_DIV1>; + fsl,dataline = <1 0x08 0x01>; + status = "okay"; +}; + +&spdif { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_spdif>; + pinctrl-1 = <&pinctrl_spdif>; + assigned-clocks = <&cgc2 IMX8ULP_CLK_SPDIF_SEL>; + assigned-clock-parents = <&cgc1 IMX8ULP_CLK_SPLL3_PFD1_DIV1>; + status = "okay"; +}; + &usbotg1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usb1>; @@ -282,6 +337,21 @@ MX8ULP_PAD_PTE13__LPI2C7_SDA 0x20 >; }; + pinctrl_sai5: sai5grp { + fsl,pins = < + MX8ULP_PAD_PTF26__I2S5_TX_BCLK 0x43 + MX8ULP_PAD_PTF27__I2S5_TX_FS 0x43 + MX8ULP_PAD_PTF28__I2S5_TXD0 0x43 + MX8ULP_PAD_PTF24__I2S5_RXD3 0x43 + >; + }; + + pinctrl_spdif: spdifgrp { + fsl,pins = < + MX8ULP_PAD_PTF25__SPDIF_OUT1 0x43 + >; + }; + pinctrl_typec1: typec1grp { fsl,pins = < MX8ULP_PAD_PTF3__PTF3 0x3 diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi index 43f5437684448b..2562a35286c208 100644 --- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi @@ -28,6 +28,8 @@ aliases { serial1 = &lpuart5; serial2 = &lpuart6; serial3 = &lpuart7; + spi0 = &lpspi4; + spi1 = &lpspi5; }; cpus { @@ -212,6 +214,70 @@ per_bridge3: bus@29000000 { #size-cells = <1>; ranges; + edma1: dma-controller@29010000 { + compatible = "fsl,imx8ulp-edma"; + reg = <0x29010000 0x210000>; + #dma-cells = <3>; + dma-channels = <32>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&pcc3 IMX8ULP_CLK_DMA1_MP>, + <&pcc3 IMX8ULP_CLK_DMA1_CH0>, <&pcc3 IMX8ULP_CLK_DMA1_CH1>, + <&pcc3 IMX8ULP_CLK_DMA1_CH2>, <&pcc3 IMX8ULP_CLK_DMA1_CH3>, + <&pcc3 IMX8ULP_CLK_DMA1_CH4>, <&pcc3 IMX8ULP_CLK_DMA1_CH5>, + <&pcc3 IMX8ULP_CLK_DMA1_CH6>, <&pcc3 IMX8ULP_CLK_DMA1_CH7>, + <&pcc3 IMX8ULP_CLK_DMA1_CH8>, <&pcc3 IMX8ULP_CLK_DMA1_CH9>, + <&pcc3 IMX8ULP_CLK_DMA1_CH10>, <&pcc3 IMX8ULP_CLK_DMA1_CH11>, + <&pcc3 IMX8ULP_CLK_DMA1_CH12>, <&pcc3 IMX8ULP_CLK_DMA1_CH13>, + <&pcc3 IMX8ULP_CLK_DMA1_CH14>, <&pcc3 IMX8ULP_CLK_DMA1_CH15>, + <&pcc3 IMX8ULP_CLK_DMA1_CH16>, <&pcc3 IMX8ULP_CLK_DMA1_CH17>, + <&pcc3 IMX8ULP_CLK_DMA1_CH18>, <&pcc3 IMX8ULP_CLK_DMA1_CH19>, + <&pcc3 IMX8ULP_CLK_DMA1_CH20>, <&pcc3 IMX8ULP_CLK_DMA1_CH21>, + <&pcc3 IMX8ULP_CLK_DMA1_CH22>, <&pcc3 IMX8ULP_CLK_DMA1_CH23>, + <&pcc3 IMX8ULP_CLK_DMA1_CH24>, <&pcc3 IMX8ULP_CLK_DMA1_CH25>, + <&pcc3 IMX8ULP_CLK_DMA1_CH26>, <&pcc3 IMX8ULP_CLK_DMA1_CH27>, + <&pcc3 IMX8ULP_CLK_DMA1_CH28>, <&pcc3 IMX8ULP_CLK_DMA1_CH29>, + <&pcc3 IMX8ULP_CLK_DMA1_CH30>, <&pcc3 IMX8ULP_CLK_DMA1_CH31>; + clock-names = "dma", "ch00","ch01", "ch02", "ch03", + "ch04", "ch05", "ch06", "ch07", + "ch08", "ch09", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15", + "ch16", "ch17", "ch18", "ch19", + "ch20", "ch21", "ch22", "ch23", + "ch24", "ch25", "ch26", "ch27", + "ch28", "ch29", "ch30", "ch31"; + }; + mu: mailbox@29220000 { compatible = "fsl,imx8ulp-mu"; reg = <0x29220000 0x10000>; @@ -442,6 +508,36 @@ lpuart7: serial@29870000 { status = "disabled"; }; + sai4: sai@29880000 { + compatible = "fsl,imx8ulp-sai"; + reg = <0x29880000 0x10000>; + interrupts = ; + clocks = <&pcc4 IMX8ULP_CLK_SAI4>, <&cgc1 IMX8ULP_CLK_DUMMY>, + <&cgc1 IMX8ULP_CLK_SAI4_SEL>, <&cgc1 IMX8ULP_CLK_DUMMY>, + <&cgc1 IMX8ULP_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma1 67 0 1>, <&edma1 68 0 0>; + dma-names = "rx", "tx"; + #sound-dai-cells = <0>; + fsl,dataline = <0 0x03 0x03>; + status = "disabled"; + }; + + sai5: sai@29890000 { + compatible = "fsl,imx8ulp-sai"; + reg = <0x29890000 0x10000>; + interrupts = ; + clocks = <&pcc4 IMX8ULP_CLK_SAI5>, <&cgc1 IMX8ULP_CLK_DUMMY>, + <&cgc1 IMX8ULP_CLK_SAI5_SEL>, <&cgc1 IMX8ULP_CLK_DUMMY>, + <&cgc1 IMX8ULP_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma1 69 0 1>, <&edma1 70 0 0>; + dma-names = "rx", "tx"; + #sound-dai-cells = <0>; + fsl,dataline = <0 0x0f 0x0f>; + status = "disabled"; + }; + iomuxc1: pinctrl@298c0000 { compatible = "fsl,imx8ulp-iomuxc1"; reg = <0x298c0000 0x10000>; @@ -614,6 +710,70 @@ per_bridge5: bus@2d800000 { #size-cells = <1>; ranges; + edma2: dma-controller@2d800000 { + compatible = "fsl,imx8ulp-edma"; + reg = <0x2d800000 0x210000>; + #dma-cells = <3>; + dma-channels = <32>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&pcc5 IMX8ULP_CLK_DMA2_MP>, + <&pcc5 IMX8ULP_CLK_DMA2_CH0>, <&pcc5 IMX8ULP_CLK_DMA2_CH1>, + <&pcc5 IMX8ULP_CLK_DMA2_CH2>, <&pcc5 IMX8ULP_CLK_DMA2_CH3>, + <&pcc5 IMX8ULP_CLK_DMA2_CH4>, <&pcc5 IMX8ULP_CLK_DMA2_CH5>, + <&pcc5 IMX8ULP_CLK_DMA2_CH6>, <&pcc5 IMX8ULP_CLK_DMA2_CH7>, + <&pcc5 IMX8ULP_CLK_DMA2_CH8>, <&pcc5 IMX8ULP_CLK_DMA2_CH9>, + <&pcc5 IMX8ULP_CLK_DMA2_CH10>, <&pcc5 IMX8ULP_CLK_DMA2_CH11>, + <&pcc5 IMX8ULP_CLK_DMA2_CH12>, <&pcc5 IMX8ULP_CLK_DMA2_CH13>, + <&pcc5 IMX8ULP_CLK_DMA2_CH14>, <&pcc5 IMX8ULP_CLK_DMA2_CH15>, + <&pcc5 IMX8ULP_CLK_DMA2_CH16>, <&pcc5 IMX8ULP_CLK_DMA2_CH17>, + <&pcc5 IMX8ULP_CLK_DMA2_CH18>, <&pcc5 IMX8ULP_CLK_DMA2_CH19>, + <&pcc5 IMX8ULP_CLK_DMA2_CH20>, <&pcc5 IMX8ULP_CLK_DMA2_CH21>, + <&pcc5 IMX8ULP_CLK_DMA2_CH22>, <&pcc5 IMX8ULP_CLK_DMA2_CH23>, + <&pcc5 IMX8ULP_CLK_DMA2_CH24>, <&pcc5 IMX8ULP_CLK_DMA2_CH25>, + <&pcc5 IMX8ULP_CLK_DMA2_CH26>, <&pcc5 IMX8ULP_CLK_DMA2_CH27>, + <&pcc5 IMX8ULP_CLK_DMA2_CH28>, <&pcc5 IMX8ULP_CLK_DMA2_CH29>, + <&pcc5 IMX8ULP_CLK_DMA2_CH30>, <&pcc5 IMX8ULP_CLK_DMA2_CH31>; + clock-names = "dma", "ch00","ch01", "ch02", "ch03", + "ch04", "ch05", "ch06", "ch07", + "ch08", "ch09", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15", + "ch16", "ch17", "ch18", "ch19", + "ch20", "ch21", "ch22", "ch23", + "ch24", "ch25", "ch26", "ch27", + "ch28", "ch29", "ch30", "ch31"; + }; + cgc2: clock-controller@2da60000 { compatible = "fsl,imx8ulp-cgc2"; reg = <0x2da60000 0x10000>; @@ -626,6 +786,60 @@ pcc5: clock-controller@2da70000 { #clock-cells = <1>; #reset-cells = <1>; }; + + sai6: sai@2da90000 { + compatible = "fsl,imx8ulp-sai"; + reg = <0x2da90000 0x10000>; + interrupts = ; + clocks = <&pcc5 IMX8ULP_CLK_SAI6>, <&cgc1 IMX8ULP_CLK_DUMMY>, + <&cgc2 IMX8ULP_CLK_SAI6_SEL>, <&cgc1 IMX8ULP_CLK_DUMMY>, + <&cgc1 IMX8ULP_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma2 71 0 1>, <&edma2 72 0 0>; + dma-names = "rx", "tx"; + #sound-dai-cells = <0>; + fsl,dataline = <0 0x0f 0x0f>; + status = "disabled"; + }; + + sai7: sai@2daa0000 { + compatible = "fsl,imx8ulp-sai"; + reg = <0x2daa0000 0x10000>; + interrupts = ; + clocks = <&pcc5 IMX8ULP_CLK_SAI7>, <&cgc1 IMX8ULP_CLK_DUMMY>, + <&cgc2 IMX8ULP_CLK_SAI7_SEL>, <&cgc1 IMX8ULP_CLK_DUMMY>, + <&cgc1 IMX8ULP_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma2 73 0 1>, <&edma2 74 0 0>; + dma-names = "rx", "tx"; + #sound-dai-cells = <0>; + fsl,dataline = <0 0x0f 0x0f>; + status = "disabled"; + }; + + spdif: spdif@2dab0000 { + compatible = "fsl,imx8ulp-spdif"; + reg = <0x2dab0000 0x10000>; + interrupts = ; + clocks = <&pcc5 IMX8ULP_CLK_SPDIF>, /* core */ + <&sosc>, /* 0, extal */ + <&cgc2 IMX8ULP_CLK_SPDIF_SEL>, /* 1, tx */ + <&cgc1 IMX8ULP_CLK_DUMMY>, /* 2, tx1 */ + <&cgc1 IMX8ULP_CLK_DUMMY>, /* 3, tx2 */ + <&cgc1 IMX8ULP_CLK_DUMMY>, /* 4, tx3 */ + <&pcc5 IMX8ULP_CLK_SPDIF>, /* 5, sys */ + <&cgc1 IMX8ULP_CLK_DUMMY>, /* 6, tx4 */ + <&cgc1 IMX8ULP_CLK_DUMMY>, /* 7, tx5 */ + <&cgc1 IMX8ULP_CLK_DUMMY>; /* spba */ + clock-names = "core", "rxtx0", + "rxtx1", "rxtx2", + "rxtx3", "rxtx4", + "rxtx5", "rxtx6", + "rxtx7", "spba"; + dmas = <&edma2 75 0 5>, <&edma2 76 0 4>; + dma-names = "rx", "tx"; + status = "disabled"; + }; }; gpiod: gpio@2e200000 { diff --git a/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi b/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi index edba5b58241465..d5abfdb8ede2cd 100644 --- a/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8x-colibri.dtsi @@ -166,7 +166,7 @@ sgtl5000_a: audio-codec@a { }; /* Touch controller */ - touchscreen@2c { + ad7879_ts: touchscreen@2c { compatible = "adi,ad7879-1"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ad7879_int>; @@ -698,7 +698,7 @@ pinctrl_hog2: hog2grp { /* * This pin is used in the SCFW as a UART. Using it from - * Linux would require rewritting the SCFW board file. + * Linux would require rewriting the SCFW board file. */ pinctrl_hog_scfw: hogscfwgrp { fsl,pins = ; /* SODIMM 144 */ diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts index 8d036b3962e9d1..0e12dcd0d4d1a3 100644 --- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts @@ -78,6 +78,23 @@ reg_vref_1v8: regulator-adc-vref { regulator-max-microvolt = <1800000>; }; + reg_audio_pwr: regulator-audio-pwr { + compatible = "regulator-fixed"; + regulator-name = "audio-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&adp5585 1 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_can2_standby: regulator-can2-standby { + compatible = "regulator-fixed"; + regulator-name = "can2-stby"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&adp5585 6 GPIO_ACTIVE_LOW>; + }; + reg_usdhc2_vmmc: regulator-usdhc2 { compatible = "regulator-fixed"; pinctrl-names = "default"; @@ -139,6 +156,22 @@ cpu { }; }; + sound-wm8962 { + compatible = "fsl,imx-audio-wm8962"; + model = "wm8962-audio"; + audio-cpu = <&sai3>; + audio-codec = <&wm8962>; + hp-det-gpio = <&pcal6524 4 GPIO_ACTIVE_HIGH>; + audio-routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "Ext Spk", "SPKOUTL", + "Ext Spk", "SPKOUTR", + "AMIC", "MICBIAS", + "IN3R", "AMIC", + "IN1R", "AMIC"; + }; + sound-xcvr { compatible = "fsl,imx-audio-card"; model = "imx-audio-xcvr"; @@ -216,12 +249,41 @@ ethphy2: ethernet-phy@2 { }; }; +&flexcan2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can2_standby>; + status = "okay"; +}; + &lpi2c1 { clock-frequency = <400000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpi2c1>; status = "okay"; + wm8962: codec@1a { + compatible = "wlf,wm8962"; + reg = <0x1a>; + clocks = <&clk IMX93_CLK_SAI3_GATE>; + DCVDD-supply = <®_audio_pwr>; + DBVDD-supply = <®_audio_pwr>; + AVDD-supply = <®_audio_pwr>; + CPVDD-supply = <®_audio_pwr>; + MICVDD-supply = <®_audio_pwr>; + PLLVDD-supply = <®_audio_pwr>; + SPKVDD1-supply = <®_audio_pwr>; + SPKVDD2-supply = <®_audio_pwr>; + gpio-cfg = < + 0x0000 /* 0:Default */ + 0x0000 /* 1:Default */ + 0x0000 /* 2:FN_DMICCLK */ + 0x0000 /* 3:Default */ + 0x0000 /* 4:FN_DMICCDAT */ + 0x0000 /* 5:Default */ + >; + }; + inertial-meter@6a { compatible = "st,lsm6dso"; reg = <0x6a>; @@ -230,9 +292,8 @@ inertial-meter@6a { &lpi2c2 { clock-frequency = <400000>; - pinctrl-names = "default", "sleep"; + pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lpi2c2>; - pinctrl-1 = <&pinctrl_lpi2c2>; status = "okay"; pcal6524: gpio@22 { @@ -273,7 +334,7 @@ buck2: BUCK2 { regulator-ramp-delay = <3125>; }; - buck4: BUCK4{ + buck4: BUCK4 { regulator-name = "BUCK4"; regulator-min-microvolt = <1620000>; regulator-max-microvolt = <3400000>; @@ -281,7 +342,7 @@ buck4: BUCK4{ regulator-always-on; }; - buck5: BUCK5{ + buck5: BUCK5 { regulator-name = "BUCK5"; regulator-min-microvolt = <1620000>; regulator-max-microvolt = <3400000>; @@ -340,6 +401,14 @@ &lpi2c3 { pinctrl-0 = <&pinctrl_lpi2c3>; status = "okay"; + adp5585_isp: io-expander@34 { + compatible = "adi,adp5585-01", "adi,adp5585"; + reg = <0x34>; + gpio-controller; + #gpio-cells = <2>; + #pwm-cells = <3>; + }; + ptn5110: tcpc@50 { compatible = "nxp,ptn5110", "tcpci"; reg = <0x50>; @@ -455,6 +524,17 @@ &sai1 { status = "okay"; }; +&sai3 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_sai3>; + pinctrl-1 = <&pinctrl_sai3_sleep>; + assigned-clocks = <&clk IMX93_CLK_SAI3>; + assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>; + assigned-clock-rates = <12288000>; + fsl,sai-mclk-direction-output; + status = "okay"; +}; + &usbotg1 { dr_mode = "otg"; hnp-disable; @@ -614,6 +694,13 @@ MX93_PAD_ENET2_TX_CTL__GPIO4_IO20 0x51e >; }; + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX93_PAD_GPIO_IO25__CAN2_TX 0x139e + MX93_PAD_GPIO_IO27__CAN2_RX 0x139e + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX93_PAD_UART1_RXD__LPUART1_RX 0x31e @@ -748,6 +835,26 @@ MX93_PAD_SD2_RESET_B__GPIO3_IO07 0x31e >; }; + pinctrl_sai3: sai3grp { + fsl,pins = < + MX93_PAD_GPIO_IO26__SAI3_TX_SYNC 0x31e + MX93_PAD_GPIO_IO16__SAI3_TX_BCLK 0x31e + MX93_PAD_GPIO_IO17__SAI3_MCLK 0x31e + MX93_PAD_GPIO_IO19__SAI3_TX_DATA00 0x31e + MX93_PAD_GPIO_IO20__SAI3_RX_DATA00 0x31e + >; + }; + + pinctrl_sai3_sleep: sai3sleepgrp { + fsl,pins = < + MX93_PAD_GPIO_IO26__GPIO2_IO26 0x51e + MX93_PAD_GPIO_IO16__GPIO2_IO16 0x51e + MX93_PAD_GPIO_IO17__GPIO2_IO17 0x51e + MX93_PAD_GPIO_IO19__GPIO2_IO19 0x51e + MX93_PAD_GPIO_IO20__GPIO2_IO20 0x51e + >; + }; + pinctrl_spdif: spdifgrp { fsl,pins = < MX93_PAD_GPIO_IO22__SPDIF_IN 0x31e diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-i3c.dtso b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-i3c.dtso new file mode 100644 index 00000000000000..3fe6209a34236c --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-i3c.dtso @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2024 NXP + */ + +#include +#include +#include + +#include "imx93-pinfunc.h" + +/dts-v1/; +/plugin/; + +&lpi2c1 { + status = "disabled"; +}; + +&i3c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i3c1>; + #address-cells = <3>; + #size-cells = <0>; + i2c-scl-hz = <400000>; + status = "okay"; + + tcpc@50 { + compatible = "nxp,ptn5110", "tcpci"; + reg = <0x50 0x00 (I2C_FM | I2C_NO_FILTER_LOW_FREQUENCY)>; + interrupt-parent = <&gpio3>; + interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + power-role = "dual"; + data-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <15000000>; + self-powered; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + typec1_dr_sw: endpoint { + remote-endpoint = <&usb1_drd_sw>; + }; + }; + }; + }; + }; +}; + +&usb1_drd_sw { + remote-endpoint = <&typec1_dr_sw>; +}; + +&iomuxc { + pinctrl_i3c1: i3c1grp { + fsl,pins = < + MX93_PAD_I2C1_SCL__I3C1_SCL 0x40000186 + MX93_PAD_I2C1_SDA__I3C1_SDA 0x40000186 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts index f8a73612fa0514..20ec5b3c21f423 100644 --- a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts +++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts @@ -12,6 +12,11 @@ / { model = "NXP i.MX93 9x9 Quick Start Board"; compatible = "fsl,imx93-9x9-qsb", "fsl,imx93"; + bt_sco_codec: bt-sco-codec { + #sound-dai-cells = <1>; + compatible = "linux,bt-sco"; + }; + chosen { stdout-path = &lpuart1; }; @@ -68,6 +73,15 @@ reg_vref_1v8: regulator-adc-vref { regulator-max-microvolt = <1800000>; }; + reg_audio_pwr: regulator-audio-pwr { + compatible = "regulator-fixed"; + regulator-name = "audio-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&pcal6524 16 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + reg_rpi_3v3: regulator-rpi { compatible = "regulator-fixed"; regulator-name = "VDD_RPI_3V3"; @@ -88,6 +102,55 @@ reg_usdhc2_vmmc: regulator-usdhc2 { enable-active-high; off-on-delay-us = <12000>; }; + + sound-bt-sco { + compatible = "simple-audio-card"; + simple-audio-card,name = "bt-sco-audio"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,bitclock-inversion; + simple-audio-card,frame-master = <&btcpu>; + simple-audio-card,bitclock-master = <&btcpu>; + + btcpu: simple-audio-card,cpu { + sound-dai = <&sai1>; + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <16>; + }; + + simple-audio-card,codec { + sound-dai = <&bt_sco_codec 1>; + }; + }; + + sound-micfil { + compatible = "fsl,imx-audio-card"; + model = "micfil-audio"; + + pri-dai-link { + link-name = "micfil hifi"; + format = "i2s"; + + cpu { + sound-dai = <&micfil>; + }; + }; + }; + + sound-wm8962 { + compatible = "fsl,imx-audio-wm8962"; + model = "wm8962-audio"; + audio-cpu = <&sai3>; + audio-codec = <&wm8962>; + hp-det-gpio = <&pcal6524 4 GPIO_ACTIVE_HIGH>; + audio-routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "Ext Spk", "SPKOUTL", + "Ext Spk", "SPKOUTR", + "AMIC", "MICBIAS", + "IN3R", "AMIC", + "IN1R", "AMIC"; + }; }; &adc1 { @@ -136,6 +199,28 @@ &lpi2c1 { pinctrl-0 = <&pinctrl_lpi2c1>; status = "okay"; + wm8962: audio-codec@1a { + compatible = "wlf,wm8962"; + reg = <0x1a>; + clocks = <&clk IMX93_CLK_SAI3_GATE>; + DCVDD-supply = <®_audio_pwr>; + DBVDD-supply = <®_audio_pwr>; + AVDD-supply = <®_audio_pwr>; + CPVDD-supply = <®_audio_pwr>; + MICVDD-supply = <®_audio_pwr>; + PLLVDD-supply = <®_audio_pwr>; + SPKVDD1-supply = <®_audio_pwr>; + SPKVDD2-supply = <®_audio_pwr>; + gpio-cfg = < + 0x0000 /* 0:Default */ + 0x0000 /* 1:Default */ + 0x0000 /* 2:FN_DMICCLK */ + 0x0000 /* 3:Default */ + 0x0000 /* 4:FN_DMICCDAT */ + 0x0000 /* 5:Default */ + >; + }; + ptn5110: tcpc@50 { compatible = "nxp,ptn5110", "tcpci"; reg = <0x50>; @@ -194,6 +279,18 @@ pcal6524: gpio@22 { interrupts = <26 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pcal6524>; + + exp-sel-hog { + gpio-hog; + gpios = <22 GPIO_ACTIVE_HIGH>; + output-low; + }; + + mic-can-sel-hog { + gpio-hog; + gpios = <17 GPIO_ACTIVE_HIGH>; + output-low; + }; }; pmic@25 { @@ -221,7 +318,7 @@ buck2: BUCK2 { regulator-ramp-delay = <3125>; }; - buck4: BUCK4{ + buck4: BUCK4 { regulator-name = "BUCK4"; regulator-min-microvolt = <600000>; regulator-max-microvolt = <3400000>; @@ -229,7 +326,7 @@ buck4: BUCK4{ regulator-always-on; }; - buck5: BUCK5{ + buck5: BUCK5 { regulator-name = "BUCK5"; regulator-min-microvolt = <600000>; regulator-max-microvolt = <3400000>; @@ -278,6 +375,15 @@ &lpuart1 { /* console */ status = "okay"; }; +&micfil { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pdm>; + assigned-clocks = <&clk IMX93_CLK_PDM>; + assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>; + assigned-clock-rates = <49152000>; + status = "okay"; +}; + &mu1 { status = "okay"; }; @@ -286,6 +392,27 @@ &mu2 { status = "okay"; }; +&sai1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai1>; + assigned-clocks = <&clk IMX93_CLK_SAI1>; + assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>; + assigned-clock-rates = <12288000>; + fsl,sai-mclk-direction-output; + status = "okay"; +}; + +&sai3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai3>; + assigned-clocks = <&clk IMX93_CLK_SAI3>; + assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>; + assigned-clock-rates = <12288000>; + fsl,sai-mclk-direction-output; + fsl,sai-synchronous-rx; + status = "okay"; +}; + &usbotg1 { dr_mode = "otg"; hnp-disable; @@ -370,6 +497,14 @@ MX93_PAD_CCM_CLKO1__GPIO3_IO26 0x31e >; }; + pinctrl_pdm: pdmgrp { + fsl,pins = < + MX93_PAD_PDM_CLK__PDM_CLK 0x31e + MX93_PAD_PDM_BIT_STREAM0__PDM_BIT_STREAM00 0x31e + MX93_PAD_PDM_BIT_STREAM1__PDM_BIT_STREAM01 0x31e + >; + }; + pinctrl_uart1: uart1grp { fsl,pins = < MX93_PAD_UART1_RXD__LPUART1_RX 0x31e @@ -443,6 +578,25 @@ MX93_PAD_SD2_RESET_B__GPIO3_IO07 0x31e >; }; + pinctrl_sai1: sai1grp { + fsl,pins = < + MX93_PAD_SAI1_TXC__SAI1_TX_BCLK 0x31e + MX93_PAD_SAI1_TXFS__SAI1_TX_SYNC 0x31e + MX93_PAD_SAI1_TXD0__SAI1_TX_DATA00 0x31e + MX93_PAD_SAI1_RXD0__SAI1_RX_DATA00 0x31e + >; + }; + + pinctrl_sai3: sai3grp { + fsl,pins = < + MX93_PAD_GPIO_IO12__SAI3_RX_SYNC 0x31e + MX93_PAD_GPIO_IO18__SAI3_RX_BCLK 0x31e + MX93_PAD_GPIO_IO17__SAI3_MCLK 0x31e + MX93_PAD_GPIO_IO19__SAI3_TX_DATA00 0x31e + MX93_PAD_GPIO_IO20__SAI3_RX_DATA00 0x31e + >; + }; + pinctrl_usdhc2_gpio: usdhc2gpiogrp { fsl,pins = < MX93_PAD_SD2_CD_B__GPIO3_IO00 0x31e diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi index 04b9b3d31f4faf..688488de8cd288 100644 --- a/arch/arm64/boot/dts/freescale/imx93.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93.dtsi @@ -42,6 +42,14 @@ aliases { serial5 = &lpuart6; serial6 = &lpuart7; serial7 = &lpuart8; + spi0 = &lpspi1; + spi1 = &lpspi2; + spi2 = &lpspi3; + spi3 = &lpspi4; + spi4 = &lpspi5; + spi5 = &lpspi6; + spi6 = &lpspi7; + spi7 = &lpspi8; }; cpus { diff --git a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts index 37a1d4ca1b2079..6086cb7fa5a0e1 100644 --- a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts @@ -8,11 +8,33 @@ #include #include "imx95.dtsi" +#define FALLING_EDGE 1 +#define RISING_EDGE 2 + +#define BRD_SM_CTRL_SD3_WAKE 0x8000 /* PCAL6408A-0 */ +#define BRD_SM_CTRL_PCIE1_WAKE 0x8001 /* PCAL6408A-4 */ +#define BRD_SM_CTRL_BT_WAKE 0x8002 /* PCAL6408A-5 */ +#define BRD_SM_CTRL_PCIE2_WAKE 0x8003 /* PCAL6408A-6 */ +#define BRD_SM_CTRL_BUTTON 0x8004 /* PCAL6408A-7 */ + / { model = "NXP i.MX95 19X19 board"; compatible = "fsl,imx95-19x19-evk", "fsl,imx95"; aliases { + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; + gpio3 = &gpio4; + gpio4 = &gpio5; + i2c0 = &lpi2c1; + i2c1 = &lpi2c2; + i2c2 = &lpi2c3; + i2c3 = &lpi2c4; + i2c4 = &lpi2c5; + i2c5 = &lpi2c6; + i2c6 = &lpi2c7; + i2c7 = &lpi2c8; mmc0 = &usdhc1; mmc1 = &usdhc2; serial0 = &lpuart1; @@ -232,6 +254,42 @@ i2c4_gpio_expander_21: gpio@21 { }; }; +&lpi2c5 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lpi2c5>; + status = "okay"; + + i2c5_pcal6408: gpio@21 { + compatible = "nxp,pcal6408"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + vcc-supply = <®_3p3v>; + }; +}; + +&lpi2c6 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lpi2c6>; + status = "okay"; + + i2c6_pcal6416: gpio@21 { + compatible = "nxp,pcal6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gpio4>; + interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pcal6416>; + vcc-supply = <®_3p3v>; + }; +}; + &lpi2c7 { clock-frequency = <1000000>; pinctrl-names = "default"; @@ -357,6 +415,14 @@ &usdhc2 { status = "okay"; }; +&scmi_misc { + nxp,ctrl-ids = ; +}; + &wdog3 { fsl,ext-reset-output; status = "okay"; @@ -410,6 +476,20 @@ IMX95_PAD_GPIO_IO31__LPI2C4_SCL 0x40000b9e >; }; + pinctrl_lpi2c5: lpi2c5grp { + fsl,pins = < + IMX95_PAD_GPIO_IO22__LPI2C5_SDA 0x40000b9e + IMX95_PAD_GPIO_IO23__LPI2C5_SCL 0x40000b9e + >; + }; + + pinctrl_lpi2c6: lpi2c6grp { + fsl,pins = < + IMX95_PAD_GPIO_IO02__LPI2C6_SDA 0x40000b9e + IMX95_PAD_GPIO_IO03__LPI2C6_SCL 0x40000b9e + >; + }; + pinctrl_lpi2c7: lpi2c7grp { fsl,pins = < IMX95_PAD_GPIO_IO08__LPI2C7_SDA 0x40000b9e @@ -429,6 +509,12 @@ IMX95_PAD_GPIO_IO35__HSIOMIX_TOP_PCIE2_CLKREQ_B 0x4000031e >; }; + pinctrl_pcal6416: pcal6416grp { + fsl,pins = < + IMX95_PAD_CCM_CLKO3__GPIO4_IO_BIT28 0x31e + >; + }; + pinctrl_pdm: pdmgrp { fsl,pins = < IMX95_PAD_PDM_CLK__AONMIX_TOP_PDM_CLK 0x31e diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi index 03661e76550f4d..d10f62eacfe08d 100644 --- a/arch/arm64/boot/dts/freescale/imx95.dtsi +++ b/arch/arm64/boot/dts/freescale/imx95.dtsi @@ -22,12 +22,27 @@ cpus { #address-cells = <1>; #size-cells = <0>; + idle-states { + entry-method = "psci"; + + cpu_pd_wait: cpu-pd-wait { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010033>; + local-timer-stop; + entry-latency-us = <10000>; + exit-latency-us = <7000>; + min-residency-us = <27000>; + wakeup-latency-us = <15000>; + }; + }; + A55_0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0>; enable-method = "psci"; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; power-domains = <&scmi_perf IMX95_PERF_A55>; power-domain-names = "perf"; i-cache-size = <32768>; @@ -45,6 +60,7 @@ A55_1: cpu@100 { reg = <0x100>; enable-method = "psci"; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; power-domains = <&scmi_perf IMX95_PERF_A55>; power-domain-names = "perf"; i-cache-size = <32768>; @@ -62,6 +78,7 @@ A55_2: cpu@200 { reg = <0x200>; enable-method = "psci"; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; power-domains = <&scmi_perf IMX95_PERF_A55>; power-domain-names = "perf"; i-cache-size = <32768>; @@ -79,6 +96,7 @@ A55_3: cpu@300 { reg = <0x300>; enable-method = "psci"; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; power-domains = <&scmi_perf IMX95_PERF_A55>; power-domain-names = "perf"; i-cache-size = <32768>; @@ -98,6 +116,7 @@ A55_4: cpu@400 { power-domain-names = "perf"; enable-method = "psci"; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; i-cache-size = <32768>; i-cache-line-size = <64>; i-cache-sets = <128>; @@ -115,6 +134,7 @@ A55_5: cpu@500 { power-domain-names = "perf"; enable-method = "psci"; #cooling-cells = <2>; + cpu-idle-states = <&cpu_pd_wait>; i-cache-size = <32768>; i-cache-line-size = <64>; i-cache-sets = <128>; @@ -293,12 +313,17 @@ scmi { shmem = <&scmi_buf0>, <&scmi_buf1>; #address-cells = <1>; #size-cells = <0>; + arm,max-rx-timeout-ms = <5000>; scmi_devpd: protocol@11 { reg = <0x11>; #power-domain-cells = <1>; }; + scmi_sys_power: protocol@12 { + reg = <0x12>; + }; + scmi_perf: protocol@13 { reg = <0x13>; #power-domain-cells = <1>; @@ -318,6 +343,13 @@ scmi_iomuxc: protocol@19 { reg = <0x19>; }; + scmi_bbm: protocol@81 { + reg = <0x81>; + }; + + scmi_misc: protocol@84 { + reg = <0x84>; + }; }; }; @@ -334,13 +366,13 @@ a55-thermal { trips { cpu_alert0: trip0 { - temperature = <85000>; + temperature = <105000>; hysteresis = <2000>; type = "passive"; }; cpu_crit0: trip1 { - temperature = <95000>; + temperature = <125000>; hysteresis = <2000>; type = "critical"; }; @@ -359,6 +391,38 @@ map0 { }; }; }; + + ana-thermal { + polling-delay-passive = <250>; + polling-delay = <2000>; + thermal-sensors = <&scmi_sensor 0>; + trips { + ana_alert: trip0 { + temperature = <105000>; + hysteresis = <2000>; + type = "passive"; + }; + + ana_crit0: trip1 { + temperature = <125000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&ana_alert>; + cooling-device = + <&A55_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&A55_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&A55_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&A55_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&A55_4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&A55_5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; }; psci { diff --git a/arch/arm64/boot/dts/freescale/mba8mx.dtsi b/arch/arm64/boot/dts/freescale/mba8mx.dtsi index c60c7a9e54aff9..58e3865c28895b 100644 --- a/arch/arm64/boot/dts/freescale/mba8mx.dtsi +++ b/arch/arm64/boot/dts/freescale/mba8mx.dtsi @@ -100,7 +100,6 @@ panel: panel-lvds { port { panel_in_lvds: endpoint { - data-lanes = <1 2 3 4>; remote-endpoint = <&lvds_bridge_out>; }; }; @@ -318,11 +317,6 @@ lvds_bridge_out: endpoint { }; }; -&mipi_dsi { - samsung,burst-clock-frequency = <891000000>; - samsung,esc-clock-frequency = <20000000>; -}; - &mipi_dsi_out { data-lanes = <1 2 3 4>; remote-endpoint = <&lvds_bridge_in>; diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi index fa054bfe7d5c55..7be430b78c83d3 100644 --- a/arch/arm64/boot/dts/freescale/s32g2.dtsi +++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi @@ -162,6 +162,159 @@ jtag-grp4 { slew-rate = <166>; }; }; + + pinctrl_usdhc0: usdhc0grp-pins { + usdhc0-grp0 { + pinmux = <0x2e1>, + <0x381>; + output-enable; + bias-pull-down; + slew-rate = <150>; + }; + + usdhc0-grp1 { + pinmux = <0x2f1>, + <0x301>, + <0x311>, + <0x321>, + <0x331>, + <0x341>, + <0x351>, + <0x361>, + <0x371>; + output-enable; + input-enable; + bias-pull-up; + slew-rate = <150>; + }; + + usdhc0-grp2 { + pinmux = <0x391>; + output-enable; + slew-rate = <150>; + }; + + usdhc0-grp3 { + pinmux = <0x3a0>; + input-enable; + slew-rate = <150>; + }; + + usdhc0-grp4 { + pinmux = <0x2032>, + <0x2042>, + <0x2052>, + <0x2062>, + <0x2072>, + <0x2082>, + <0x2092>, + <0x20a2>, + <0x20b2>, + <0x20c2>; + }; + }; + + pinctrl_usdhc0_100mhz: usdhc0-100mhzgrp-pins { + usdhc0-100mhz-grp0 { + pinmux = <0x2e1>, + <0x381>; + output-enable; + bias-pull-down; + slew-rate = <150>; + }; + + usdhc0-100mhz-grp1 { + pinmux = <0x2f1>, + <0x301>, + <0x311>, + <0x321>, + <0x331>, + <0x341>, + <0x351>, + <0x361>, + <0x371>; + output-enable; + input-enable; + bias-pull-up; + slew-rate = <150>; + }; + + usdhc0-100mhz-grp2 { + pinmux = <0x391>; + output-enable; + slew-rate = <150>; + }; + + usdhc0-100mhz-grp3 { + pinmux = <0x3a0>; + input-enable; + slew-rate = <150>; + }; + + usdhc0-100mhz-grp4 { + pinmux = <0x2032>, + <0x2042>, + <0x2052>, + <0x2062>, + <0x2072>, + <0x2082>, + <0x2092>, + <0x20a2>, + <0x20b2>, + <0x20c2>; + }; + }; + + pinctrl_usdhc0_200mhz: usdhc0-200mhzgrp-pins { + usdhc0-200mhz-grp0 { + pinmux = <0x2e1>, + <0x381>; + output-enable; + bias-pull-down; + slew-rate = <208>; + }; + + usdhc0-200mhz-grp1 { + pinmux = <0x2f1>, + <0x301>, + <0x311>, + <0x321>, + <0x331>, + <0x341>, + <0x351>, + <0x361>, + <0x371>; + output-enable; + input-enable; + bias-pull-up; + slew-rate = <208>; + }; + + usdhc0-200mhz-grp2 { + pinmux = <0x391>; + output-enable; + slew-rate = <208>; + }; + + usdhc0-200mhz-grp3 { + pinmux = <0x3a0>; + input-enable; + slew-rate = <208>; + }; + + usdhc0-200mhz-grp4 { + pinmux = <0x2032>, + <0x2042>, + <0x2052>, + <0x2062>, + <0x2072>, + <0x2082>, + <0x2092>, + <0x20a2>, + <0x20b2>, + <0x20c2>; + }; + }; }; uart0: serial@401c8000 { diff --git a/arch/arm64/boot/dts/freescale/s32g274a-evb.dts b/arch/arm64/boot/dts/freescale/s32g274a-evb.dts index dbe498798bd912..b9a119eea2b746 100644 --- a/arch/arm64/boot/dts/freescale/s32g274a-evb.dts +++ b/arch/arm64/boot/dts/freescale/s32g274a-evb.dts @@ -34,6 +34,11 @@ &uart0 { }; &usdhc0 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc0>; + pinctrl-1 = <&pinctrl_usdhc0_100mhz>; + pinctrl-2 = <&pinctrl_usdhc0_200mhz>; disable-wp; + no-1-8-v; status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/s32g274a-rdb2.dts b/arch/arm64/boot/dts/freescale/s32g274a-rdb2.dts index ab1e5caaeae74e..aaa61a8ad0dac3 100644 --- a/arch/arm64/boot/dts/freescale/s32g274a-rdb2.dts +++ b/arch/arm64/boot/dts/freescale/s32g274a-rdb2.dts @@ -40,6 +40,19 @@ &uart1 { }; &usdhc0 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc0>; + pinctrl-1 = <&pinctrl_usdhc0_100mhz>; + pinctrl-2 = <&pinctrl_usdhc0_200mhz>; disable-wp; + /* Remove no-1-8-v to enable higher speed modes for SD card. + * However, this is not enough to enable HS400 or HS200 modes for eMMC. + * In this case, the position of the resistor R797 must be changed + * from A to B before removing the property. + * If the property is removed without changing the resistor position, + * HS*00 may be enabled, but the interface might be unstable because of + * the wrong VCCQ voltage applied to the eMMC. + */ + no-1-8-v; status = "okay"; }; diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi index b4226a9143c80e..6c572ffe37caf8 100644 --- a/arch/arm64/boot/dts/freescale/s32g3.dtsi +++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi @@ -219,6 +219,159 @@ jtag-grp4 { slew-rate = <166>; }; }; + + pinctrl_usdhc0: usdhc0grp-pins { + usdhc0-grp0 { + pinmux = <0x2e1>, + <0x381>; + output-enable; + bias-pull-down; + slew-rate = <150>; + }; + + usdhc0-grp1 { + pinmux = <0x2f1>, + <0x301>, + <0x311>, + <0x321>, + <0x331>, + <0x341>, + <0x351>, + <0x361>, + <0x371>; + output-enable; + input-enable; + bias-pull-up; + slew-rate = <150>; + }; + + usdhc0-grp2 { + pinmux = <0x391>; + output-enable; + slew-rate = <150>; + }; + + usdhc0-grp3 { + pinmux = <0x3a0>; + input-enable; + slew-rate = <150>; + }; + + usdhc0-grp4 { + pinmux = <0x2032>, + <0x2042>, + <0x2052>, + <0x2062>, + <0x2072>, + <0x2082>, + <0x2092>, + <0x20a2>, + <0x20b2>, + <0x20c2>; + }; + }; + + pinctrl_usdhc0_100mhz: usdhc0-100mhzgrp-pins { + usdhc0-100mhz-grp0 { + pinmux = <0x2e1>, + <0x381>; + output-enable; + bias-pull-down; + slew-rate = <150>; + }; + + usdhc0-100mhz-grp1 { + pinmux = <0x2f1>, + <0x301>, + <0x311>, + <0x321>, + <0x331>, + <0x341>, + <0x351>, + <0x361>, + <0x371>; + output-enable; + input-enable; + bias-pull-up; + slew-rate = <150>; + }; + + usdhc0-100mhz-grp2 { + pinmux = <0x391>; + output-enable; + slew-rate = <150>; + }; + + usdhc0-100mhz-grp3 { + pinmux = <0x3a0>; + input-enable; + slew-rate = <150>; + }; + + usdhc0-100mhz-grp4 { + pinmux = <0x2032>, + <0x2042>, + <0x2052>, + <0x2062>, + <0x2072>, + <0x2082>, + <0x2092>, + <0x20a2>, + <0x20b2>, + <0x20c2>; + }; + }; + + pinctrl_usdhc0_200mhz: usdhc0-200mhzgrp-pins { + usdhc0-200mhz-grp0 { + pinmux = <0x2e1>, + <0x381>; + output-enable; + bias-pull-down; + slew-rate = <208>; + }; + + usdhc0-200mhz-grp1 { + pinmux = <0x2f1>, + <0x301>, + <0x311>, + <0x321>, + <0x331>, + <0x341>, + <0x351>, + <0x361>, + <0x371>; + output-enable; + input-enable; + bias-pull-up; + slew-rate = <208>; + }; + + usdhc0-200mhz-grp2 { + pinmux = <0x391>; + output-enable; + slew-rate = <208>; + }; + + usdhc0-200mhz-grp3 { + pinmux = <0x3a0>; + input-enable; + slew-rate = <208>; + }; + + usdhc0-200mhz-grp4 { + pinmux = <0x2032>, + <0x2042>, + <0x2052>, + <0x2062>, + <0x2072>, + <0x2082>, + <0x2092>, + <0x20a2>, + <0x20b2>, + <0x20c2>; + }; + }; }; uart0: serial@401c8000 { diff --git a/arch/arm64/boot/dts/freescale/s32g399a-rdb3.dts b/arch/arm64/boot/dts/freescale/s32g399a-rdb3.dts index 176e5af191c84a..828e353455b54c 100644 --- a/arch/arm64/boot/dts/freescale/s32g399a-rdb3.dts +++ b/arch/arm64/boot/dts/freescale/s32g399a-rdb3.dts @@ -40,6 +40,10 @@ &uart1 { }; &usdhc0 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc0>; + pinctrl-1 = <&pinctrl_usdhc0_100mhz>; + pinctrl-2 = <&pinctrl_usdhc0_200mhz>; bus-width = <8>; disable-wp; status = "okay"; diff --git a/arch/arm64/boot/dts/lg/lg1312.dtsi b/arch/arm64/boot/dts/lg/lg1312.dtsi index b864ffa74ea8b6..bb0bcc6875dc9d 100644 --- a/arch/arm64/boot/dts/lg/lg1312.dtsi +++ b/arch/arm64/boot/dts/lg/lg1312.dtsi @@ -173,15 +173,15 @@ spi0: spi@fe800000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x0 0xfe800000 0x1000>; interrupts = ; - clocks = <&clk_bus>; - clock-names = "apb_pclk"; + clocks = <&clk_bus>, <&clk_bus>; + clock-names = "sspclk", "apb_pclk"; }; spi1: spi@fe900000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x0 0xfe900000 0x1000>; interrupts = ; - clocks = <&clk_bus>; - clock-names = "apb_pclk"; + clocks = <&clk_bus>, <&clk_bus>; + clock-names = "sspclk", "apb_pclk"; }; dmac0: dma-controller@c1128000 { compatible = "arm,pl330", "arm,primecell"; diff --git a/arch/arm64/boot/dts/lg/lg1313.dtsi b/arch/arm64/boot/dts/lg/lg1313.dtsi index 996fb39bb50c1f..c07d670bc4659d 100644 --- a/arch/arm64/boot/dts/lg/lg1313.dtsi +++ b/arch/arm64/boot/dts/lg/lg1313.dtsi @@ -173,15 +173,15 @@ spi0: spi@fe800000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x0 0xfe800000 0x1000>; interrupts = ; - clocks = <&clk_bus>; - clock-names = "apb_pclk"; + clocks = <&clk_bus>, <&clk_bus>; + clock-names = "sspclk", "apb_pclk"; }; spi1: spi@fe900000 { compatible = "arm,pl022", "arm,primecell"; reg = <0x0 0xfe900000 0x1000>; interrupts = ; - clocks = <&clk_bus>; - clock-names = "apb_pclk"; + clocks = <&clk_bus>, <&clk_bus>; + clock-names = "sspclk", "apb_pclk"; }; dmac0: dma-controller@c1128000 { compatible = "arm,pl330", "arm,primecell"; diff --git a/arch/arm64/boot/dts/marvell/armada-7040-db.dts b/arch/arm64/boot/dts/marvell/armada-7040-db.dts index 5e5baf6beea462..1e0ab35cc686b0 100644 --- a/arch/arm64/boot/dts/marvell/armada-7040-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-7040-db.dts @@ -214,7 +214,6 @@ &cp0_sata0 { sata-port@1 { phys = <&cp0_comphy3 1>; - phy-names = "cp0-sata0-1-phy"; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts b/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts index 40b7ee7ead72e2..7af949092b9134 100644 --- a/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts +++ b/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts @@ -433,13 +433,11 @@ &cp0_sata0 { /* 7 + 12 SATA connector (J24) */ sata-port@0 { phys = <&cp0_comphy2 0>; - phy-names = "cp0-sata0-0-phy"; }; /* M.2-2250 B-key (J39) */ sata-port@1 { phys = <&cp0_comphy3 1>; - phy-names = "cp0-sata0-1-phy"; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts b/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts index 67892f0d28633e..7005a32a6e1e78 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts @@ -475,7 +475,6 @@ &cp1_sata0 { sata-port@1 { phys = <&cp1_comphy0 1>; - phy-names = "cp1-sata0-1-phy"; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-db.dts b/arch/arm64/boot/dts/marvell/armada-8040-db.dts index 92897bd7e6cfd6..2ec19d364e626e 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-db.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-db.dts @@ -145,11 +145,9 @@ &cp0_sata0 { sata-port@0 { phys = <&cp0_comphy1 0>; - phy-names = "cp0-sata0-0-phy"; }; sata-port@1 { phys = <&cp0_comphy3 1>; - phy-names = "cp0-sata0-1-phy"; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi index c864df9ec84d1b..e88ff5b179c89a 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtsi @@ -245,7 +245,6 @@ &cp0_sata0 { /* CPM Lane 5 - U29 */ sata-port@1 { phys = <&cp0_comphy5 1>; - phy-names = "cp0-sata0-1-phy"; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-puzzle-m801.dts b/arch/arm64/boot/dts/marvell/armada-8040-puzzle-m801.dts index 42a60f3dd5d142..3e5e0651ce6815 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-puzzle-m801.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-puzzle-m801.dts @@ -408,12 +408,10 @@ &cp0_sata0 { sata-port@0 { phys = <&cp0_comphy2 0>; - phy-names = "cp0-sata0-0-phy"; }; sata-port@1 { phys = <&cp0_comphy5 1>; - phy-names = "cp0-sata0-1-phy"; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt6358.dtsi b/arch/arm64/boot/dts/mediatek/mt6358.dtsi index 641d452fbc0830..e23672a2eea4af 100644 --- a/arch/arm64/boot/dts/mediatek/mt6358.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt6358.dtsi @@ -15,12 +15,12 @@ pmic_adc: adc { #io-channel-cells = <1>; }; - mt6358codec: mt6358codec { + mt6358codec: audio-codec { compatible = "mediatek,mt6358-sound"; mediatek,dmic-mode = <0>; /* two-wires */ }; - mt6358regulator: mt6358regulator { + mt6358regulator: regulators { compatible = "mediatek,mt6358-regulator"; mt6358_vdram1_reg: buck_vdram1 { diff --git a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi index aa728331e876b7..c9649b81527687 100644 --- a/arch/arm64/boot/dts/mediatek/mt7988a.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -86,7 +86,7 @@ infracfg: clock-controller@10001000 { #clock-cells = <1>; }; - clock-controller@1001b000 { + topckgen: clock-controller@1001b000 { compatible = "mediatek,mt7988-topckgen", "syscon"; reg = <0 0x1001b000 0 0x1000>; #clock-cells = <1>; @@ -124,6 +124,39 @@ pwm@10048000 { status = "disabled"; }; + serial@11000000 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000000 0 0x100>; + interrupts = ; + interrupt-names = "uart", "wakeup"; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_52M_UART0_CK>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + serial@11000100 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000100 0 0x100>; + interrupts = ; + interrupt-names = "uart", "wakeup"; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_52M_UART1_CK>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + serial@11000200 { + compatible = "mediatek,mt7988-uart", "mediatek,mt6577-uart"; + reg = <0 0x11000200 0 0x100>; + interrupts = ; + interrupt-names = "uart", "wakeup"; + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_52M_UART2_CK>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + i2c@11003000 { compatible = "mediatek,mt7981-i2c"; reg = <0 0x11003000 0 0x1000>, @@ -198,6 +231,13 @@ clock-controller@11f40000 { #clock-cells = <1>; }; + efuse@11f50000 { + compatible = "mediatek,mt7988-efuse", "mediatek,efuse"; + reg = <0 0x11f50000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + }; + clock-controller@15000000 { compatible = "mediatek,mt7988-ethsys", "syscon"; reg = <0 0x15000000 0 0x1000>; diff --git a/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtsi b/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtsi index 8d1cbc92bce320..dfc5c2f0ddefd7 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtsi @@ -14,6 +14,7 @@ touchscreen2: touchscreen@34 { compatible = "melfas,mip4_ts"; reg = <0x34>; interrupts-extended = <&pio 88 IRQ_TYPE_LEVEL_LOW>; + status = "fail-needs-probe"; }; /* @@ -26,6 +27,7 @@ touchscreen3: touchscreen@20 { reg = <0x20>; hid-descr-addr = <0x0020>; interrupts-extended = <&pio 88 IRQ_TYPE_LEVEL_LOW>; + status = "fail-needs-probe"; }; /* Lenovo Ideapad C330 uses G2Touch touchscreen as a 2nd source touchscreen */ @@ -35,6 +37,7 @@ touchscreen@40 { hid-descr-addr = <0x0001>; interrupt-parent = <&pio>; interrupts = <88 IRQ_TYPE_LEVEL_LOW>; + status = "fail-needs-probe"; }; }; @@ -47,9 +50,20 @@ &i2c4 { trackpad2: trackpad@2c { compatible = "hid-over-i2c"; interrupts-extended = <&pio 117 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_irq>; reg = <0x2c>; hid-descr-addr = <0x0020>; + /* + * The trackpad needs a post-power-on delay of 100ms, + * but at time of writing, the power supply for it on + * this board is always on. The delay is therefore not + * added to avoid impacting the readiness of the + * trackpad. + */ + vdd-supply = <&mt6397_vgp6_reg>; wakeup-source; + status = "fail-needs-probe"; }; }; @@ -74,3 +88,11 @@ pins_wp { }; }; }; + +&touchscreen { + status = "fail-needs-probe"; +}; + +&trackpad { + status = "fail-needs-probe"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi b/arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi index b4d85147b77b0b..eee64461421f83 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi @@ -358,12 +358,12 @@ touchscreen: touchscreen@10 { &i2c4 { clock-frequency = <400000>; status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&trackpad_irq>; trackpad: trackpad@15 { compatible = "elan,ekth3000"; interrupts-extended = <&pio 117 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_irq>; reg = <0x15>; vcc-supply = <&mt6397_vgp6_reg>; wakeup-source; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts index 19c1e2bee494c9..20b71f2e7159ad 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-burnet.dts @@ -30,3 +30,6 @@ touchscreen@2c { }; }; +&i2c2 { + i2c-scl-internal-delay-ns = <4100>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-cozmo.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-cozmo.dts index f34964afe39b53..83bbcfe620835a 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-cozmo.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-cozmo.dts @@ -18,6 +18,8 @@ &i2c_tunnel { }; &i2c2 { + i2c-scl-internal-delay-ns = <25000>; + trackpad@2c { compatible = "hid-over-i2c"; reg = <0x2c>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts index 0b45aee2e29953..65860b33c01fe8 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts @@ -30,3 +30,6 @@ &qca_wifi { qcom,ath10k-calibration-variant = "GO_DAMU"; }; +&i2c2 { + i2c-scl-internal-delay-ns = <20000>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel.dtsi index bbe6c338f465ee..f9c1ec366b2660 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel.dtsi @@ -25,3 +25,6 @@ trackpad@2c { }; }; +&i2c2 { + i2c-scl-internal-delay-ns = <21500>; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi index 783c333107bcbf..49e053b932e76c 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi @@ -8,28 +8,32 @@ #include / { - pp1200_mipibrdg: pp1200-mipibrdg { + pp1000_mipibrdg: pp1000-mipibrdg { compatible = "regulator-fixed"; - regulator-name = "pp1200_mipibrdg"; + regulator-name = "pp1000_mipibrdg"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; pinctrl-names = "default"; - pinctrl-0 = <&pp1200_mipibrdg_en>; + pinctrl-0 = <&pp1000_mipibrdg_en>; enable-active-high; regulator-boot-on; gpio = <&pio 54 GPIO_ACTIVE_HIGH>; + vin-supply = <&pp1800_alw>; }; pp1800_mipibrdg: pp1800-mipibrdg { compatible = "regulator-fixed"; regulator-name = "pp1800_mipibrdg"; pinctrl-names = "default"; - pinctrl-0 = <&pp1800_lcd_en>; + pinctrl-0 = <&pp1800_mipibrdg_en>; enable-active-high; regulator-boot-on; gpio = <&pio 36 GPIO_ACTIVE_HIGH>; + vin-supply = <&pp1800_alw>; }; pp3300_panel: pp3300-panel { @@ -44,18 +48,20 @@ pp3300_panel: pp3300-panel { regulator-boot-on; gpio = <&pio 35 GPIO_ACTIVE_HIGH>; + vin-supply = <&pp3300_alw>; }; - vddio_mipibrdg: vddio-mipibrdg { + pp3300_mipibrdg: pp3300-mipibrdg { compatible = "regulator-fixed"; - regulator-name = "vddio_mipibrdg"; + regulator-name = "pp3300_mipibrdg"; pinctrl-names = "default"; - pinctrl-0 = <&vddio_mipibrdg_en>; + pinctrl-0 = <&pp3300_mipibrdg_en>; enable-active-high; regulator-boot-on; gpio = <&pio 37 GPIO_ACTIVE_HIGH>; + vin-supply = <&pp3300_alw>; }; volume_buttons: volume-buttons { @@ -146,9 +152,9 @@ anx_bridge: anx7625@58 { pinctrl-0 = <&anx7625_pins>; enable-gpios = <&pio 45 GPIO_ACTIVE_HIGH>; reset-gpios = <&pio 73 GPIO_ACTIVE_HIGH>; - vdd10-supply = <&pp1200_mipibrdg>; + vdd10-supply = <&pp1000_mipibrdg>; vdd18-supply = <&pp1800_mipibrdg>; - vdd33-supply = <&vddio_mipibrdg>; + vdd33-supply = <&pp3300_mipibrdg>; ports { #address-cells = <1>; @@ -391,14 +397,14 @@ &pio { "", ""; - pp1200_mipibrdg_en: pp1200-mipibrdg-en { + pp1000_mipibrdg_en: pp1000-mipibrdg-en { pins1 { pinmux = ; output-low; }; }; - pp1800_lcd_en: pp1800-lcd-en { + pp1800_mipibrdg_en: pp1800-mipibrdg-en { pins1 { pinmux = ; output-low; @@ -460,7 +466,7 @@ trackpad-int { }; }; - vddio_mipibrdg_en: vddio-mipibrdg-en { + pp3300_mipibrdg_en: pp3300-mipibrdg-en { pins1 { pinmux = ; output-low; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi index bfb9e42c8acaa7..ff02f63bac29b2 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi @@ -92,9 +92,9 @@ &i2c4 { clock-frequency = <400000>; vbus-supply = <&mt6358_vcn18_reg>; - eeprom@54 { + eeprom@50 { compatible = "atmel,24c32"; - reg = <0x54>; + reg = <0x50>; pagesize = <32>; vcc-supply = <&mt6358_vcn18_reg>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku32.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku32.dts index 05361008e8ac02..2b5a8d1f900e0d 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku32.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku32.dts @@ -23,7 +23,7 @@ touchscreen1: touchscreen@5d { interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&pio 156 GPIO_ACTIVE_LOW>; - vdd-supply = <&lcd_pp3300>; + vdd-supply = <&pp3300_alw>; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku38.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku38.dts index cf008ed828783a..75fadf2c7059ed 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku38.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku38.dts @@ -23,7 +23,7 @@ touchscreen1: touchscreen@5d { interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&pio 156 GPIO_ACTIVE_LOW>; - vdd-supply = <&lcd_pp3300>; + vdd-supply = <&pp3300_alw>; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi index 5c1bf6a1e47586..da6e767b4ceede 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi @@ -79,9 +79,9 @@ &i2c4 { clock-frequency = <400000>; vbus-supply = <&mt6358_vcn18_reg>; - eeprom@54 { + eeprom@50 { compatible = "atmel,24c64"; - reg = <0x54>; + reg = <0x50>; pagesize = <32>; vcc-supply = <&mt6358_vcn18_reg>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi index 0f5fa893a77426..8b56b8564ed7a2 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi @@ -88,9 +88,9 @@ &i2c4 { clock-frequency = <400000>; vbus-supply = <&mt6358_vcn18_reg>; - eeprom@54 { + eeprom@50 { compatible = "atmel,24c32"; - reg = <0x54>; + reg = <0x50>; pagesize = <32>; vcc-supply = <&mt6358_vcn18_reg>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi index 22924f61ec9ed2..4b974bb781b104 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi @@ -52,27 +52,6 @@ it6505_pp18_reg: regulator0 { vin-supply = <&pp1800_alw>; }; - lcd_pp3300: regulator1 { - compatible = "regulator-fixed"; - regulator-name = "lcd_pp3300"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; - }; - - mmc1_fixed_power: regulator3 { - compatible = "regulator-fixed"; - regulator-name = "mmc1_power"; - vin-supply = <&pp3300_alw>; - }; - - mmc1_fixed_io: regulator4 { - compatible = "regulator-fixed"; - regulator-name = "mmc1_io"; - vin-supply = <&pp1800_alw>; - }; - pp1800_alw: regulator5 { compatible = "regulator-fixed"; regulator-name = "pp1800_alw"; @@ -290,6 +269,11 @@ dsi_out: endpoint { }; }; +&dpi0 { + /* TODO Re-enable after DP to Type-C port muxing can be described */ + status = "disabled"; +}; + &gic { mediatek,broken-save-restore-fw; }; @@ -369,8 +353,8 @@ &mmc1 { pinctrl-names = "default", "state_uhs"; pinctrl-0 = <&mmc1_pins_default>; pinctrl-1 = <&mmc1_pins_uhs>; - vmmc-supply = <&mmc1_fixed_power>; - vqmmc-supply = <&mmc1_fixed_io>; + vmmc-supply = <&pp3300_alw>; + vqmmc-supply = <&pp1800_alw>; mmc-pwrseq = <&wifi_pwrseq>; bus-width = <4>; max-frequency = <200000000>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts index 1aa668c3ccf928..61a6f66914b86d 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts @@ -63,6 +63,18 @@ thermistor { pulldown-ohm = <0>; io-channels = <&auxadc 0>; }; + + connector { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "d"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_connector_out>; + }; + }; + }; }; &auxadc { @@ -120,6 +132,43 @@ &i2c6 { pinctrl-0 = <&i2c6_pins>; status = "okay"; clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + + it66121hdmitx: hdmitx@4c { + compatible = "ite,it66121"; + reg = <0x4c>; + pinctrl-names = "default"; + pinctrl-0 = <&ite_pins>; + reset-gpios = <&pio 160 GPIO_ACTIVE_LOW>; + interrupt-parent = <&pio>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + vcn33-supply = <&mt6358_vcn33_reg>; + vcn18-supply = <&mt6358_vcn18_reg>; + vrf12-supply = <&mt6358_vrf12_reg>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + it66121_in: endpoint { + bus-width = <12>; + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + hdmi_connector_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; }; &keyboard { @@ -362,6 +411,67 @@ pins_clk { input-enable; }; }; + + ite_pins: ite-pins { + pins-irq { + pinmux = ; + input-enable; + bias-pull-up; + }; + + pins-rst { + pinmux = ; + output-high; + }; + }; + + dpi_func_pins: dpi-func-pins { + pins-dpi { + pinmux = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + }; + + dpi_idle_pins: dpi-idle-pins { + pins-idle { + pinmux = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + }; }; &pmic { @@ -415,3 +525,16 @@ &scp { &dsi0 { status = "disabled"; }; + +&dpi0 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&dpi_func_pins>; + pinctrl-1 = <&dpi_idle_pins>; + status = "okay"; + + port { + dpi_out: endpoint { + remote-endpoint = <&it66121_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi index 266441e999f211..1afeeb1155f578 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi @@ -1845,6 +1845,10 @@ dpi0: dpi@14015000 { <&mmsys CLK_MM_DPI_MM>, <&apmixedsys CLK_APMIXED_TVDPLL>; clock-names = "pixel", "engine", "pll"; + + port { + dpi_out: endpoint { }; + }; }; mutex: mutex@14016000 { @@ -1974,6 +1978,23 @@ larb4: larb@17010000 { power-domains = <&spm MT8183_POWER_DOMAIN_VENC>; }; + vcodec_enc: vcodec@17020000 { + compatible = "mediatek,mt8183-vcodec-enc"; + reg = <0 0x17020000 0 0x1000>; + interrupts = ; + iommus = <&iommu M4U_PORT_VENC_REC>, + <&iommu M4U_PORT_VENC_BSDMA>, + <&iommu M4U_PORT_VENC_RD_COMV>, + <&iommu M4U_PORT_VENC_CUR_LUMA>, + <&iommu M4U_PORT_VENC_CUR_CHROMA>, + <&iommu M4U_PORT_VENC_REF_LUMA>, + <&iommu M4U_PORT_VENC_REF_CHROMA>; + mediatek,scp = <&scp>; + power-domains = <&spm MT8183_POWER_DOMAIN_VENC>; + clocks = <&vencsys CLK_VENC_VENC>; + clock-names = "venc_sel"; + }; + venc_jpg: jpeg-encoder@17030000 { compatible = "mediatek,mt8183-jpgenc", "mediatek,mtk-jpgenc"; reg = <0 0x17030000 0 0x1000>; diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola-voltorb.dtsi b/arch/arm64/boot/dts/mediatek/mt8186-corsola-voltorb.dtsi index 52ec58128d5615..b495a241b4432b 100644 --- a/arch/arm64/boot/dts/mediatek/mt8186-corsola-voltorb.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8186-corsola-voltorb.dtsi @@ -10,12 +10,6 @@ / { chassis-type = "laptop"; - - max98360a: max98360a { - compatible = "maxim,max98360a"; - sdmode-gpios = <&pio 150 GPIO_ACTIVE_HIGH>; - #sound-dai-cells = <0>; - }; }; &cpu6 { @@ -59,19 +53,14 @@ &cluster1_opp_15 { opp-hz = /bits/ 64 <2200000000>; }; -&rt1019p{ - status = "disabled"; -}; - &sound { compatible = "mediatek,mt8186-mt6366-rt5682s-max98360-sound"; - status = "okay"; +}; - spk-hdmi-playback-dai-link { - codec { - sound-dai = <&it6505dptx>, <&max98360a>; - }; - }; +&speaker_codec { + compatible = "maxim,max98360a"; + sdmode-gpios = <&pio 150 GPIO_ACTIVE_HIGH>; + /delete-property/ sdb-gpios; }; &spmi { diff --git a/arch/arm64/boot/dts/mediatek/mt8186-corsola.dtsi b/arch/arm64/boot/dts/mediatek/mt8186-corsola.dtsi index 682c6ad2574d00..cfcc7909dfe68d 100644 --- a/arch/arm64/boot/dts/mediatek/mt8186-corsola.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8186-corsola.dtsi @@ -259,15 +259,15 @@ spk-hdmi-playback-dai-link { mediatek,clk-provider = "cpu"; /* RT1019P and IT6505 connected to the same I2S line */ codec { - sound-dai = <&it6505dptx>, <&rt1019p>; + sound-dai = <&it6505dptx>, <&speaker_codec>; }; }; }; - rt1019p: speaker-codec { + speaker_codec: speaker-codec { compatible = "realtek,rt1019p"; pinctrl-names = "default"; - pinctrl-0 = <&rt1019p_pins_default>; + pinctrl-0 = <&speaker_codec_pins_default>; #sound-dai-cells = <0>; sdb-gpios = <&pio 150 GPIO_ACTIVE_HIGH>; }; @@ -423,7 +423,7 @@ it6505dptx: dp-bridge@5c { #sound-dai-cells = <0>; ovdd-supply = <&mt6366_vsim2_reg>; pwr18-supply = <&pp1800_dpbrdg_dx>; - reset-gpios = <&pio 177 GPIO_ACTIVE_HIGH>; + reset-gpios = <&pio 177 GPIO_ACTIVE_LOW>; ports { #address-cells = <1>; @@ -1179,7 +1179,7 @@ pins { }; }; - rt1019p_pins_default: rt1019p-default-pins { + speaker_codec_pins_default: speaker-codec-default-pins { pins-sdb { pinmux = ; output-low; @@ -1336,7 +1336,7 @@ mt6366_vgpu_reg: vgpu { regulator-allowed-modes = ; regulator-coupled-with = <&mt6366_vsram_gpu_reg>; - regulator-coupled-max-spread = <10000>; + regulator-coupled-max-spread = <100000>; }; mt6366_vproc11_reg: vproc11 { @@ -1545,7 +1545,7 @@ mt6366_vsram_gpu_reg: vsram-gpu { regulator-ramp-delay = <6250>; regulator-enable-ramp-delay = <240>; regulator-coupled-with = <&mt6366_vgpu_reg>; - regulator-coupled-max-spread = <10000>; + regulator-coupled-max-spread = <100000>; }; mt6366_vsram_others_reg: vsram-others { diff --git a/arch/arm64/boot/dts/mediatek/mt8186.dtsi b/arch/arm64/boot/dts/mediatek/mt8186.dtsi index 148c332018b0d8..d3c3c2a40adcdf 100644 --- a/arch/arm64/boot/dts/mediatek/mt8186.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8186.dtsi @@ -29,6 +29,13 @@ aliases { rdma1 = &rdma1; }; + fhctl: fhctl@1000ce00 { + compatible = "mediatek,mt8186-fhctl"; + clocks = <&apmixedsys CLK_APMIXED_TVDPLL>; + reg = <0 0x1000ce00 0 0x200>; + status = "disabled"; + }; + cci: cci { compatible = "mediatek,mt8186-cci"; clocks = <&mcusys CLK_MCU_ARMPLL_BUS_SEL>, diff --git a/arch/arm64/boot/dts/mediatek/mt8188-evb.dts b/arch/arm64/boot/dts/mediatek/mt8188-evb.dts index 68a82b49f7a3af..f89835ac36f36f 100644 --- a/arch/arm64/boot/dts/mediatek/mt8188-evb.dts +++ b/arch/arm64/boot/dts/mediatek/mt8188-evb.dts @@ -140,8 +140,6 @@ &mt6359_vrf12_ldo_reg { &nor_flash { pinctrl-names = "default"; pinctrl-0 = <&nor_pins_default>; - #address-cells = <1>; - #size-cells = <0>; status = "okay"; flash@0 { diff --git a/arch/arm64/boot/dts/mediatek/mt8188.dtsi b/arch/arm64/boot/dts/mediatek/mt8188.dtsi index cd27966d2e3c05..faccc7f16259a4 100644 --- a/arch/arm64/boot/dts/mediatek/mt8188.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8188.dtsi @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,37 @@ / { #address-cells = <2>; #size-cells = <2>; + aliases { + dp-intf0 = &dp_intf0; + dp-intf1 = &dp_intf1; + ethdr0 = ðdr0; + gce0 = &gce0; + gce1 = &gce1; + merge1 = &merge1; + merge2 = &merge2; + merge3 = &merge3; + merge4 = &merge4; + merge5 = &merge5; + mutex0 = &mutex0; + mutex1 = &mutex1; + padding0 = &padding0; + padding1 = &padding1; + padding2 = &padding2; + padding3 = &padding3; + padding4 = &padding4; + padding5 = &padding5; + padding6 = &padding6; + padding7 = &padding7; + vdo1-rdma0 = &vdo1_rdma0; + vdo1-rdma1 = &vdo1_rdma1; + vdo1-rdma2 = &vdo1_rdma2; + vdo1-rdma3 = &vdo1_rdma3; + vdo1-rdma4 = &vdo1_rdma4; + vdo1-rdma5 = &vdo1_rdma5; + vdo1-rdma6 = &vdo1_rdma6; + vdo1-rdma7 = &vdo1_rdma7; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -41,6 +73,7 @@ cpu0: cpu@0 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + performance-domains = <&performance 0>; #cooling-cells = <2>; }; @@ -59,6 +92,7 @@ cpu1: cpu@100 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + performance-domains = <&performance 0>; #cooling-cells = <2>; }; @@ -77,6 +111,7 @@ cpu2: cpu@200 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + performance-domains = <&performance 0>; #cooling-cells = <2>; }; @@ -95,6 +130,7 @@ cpu3: cpu@300 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + performance-domains = <&performance 0>; #cooling-cells = <2>; }; @@ -113,6 +149,7 @@ cpu4: cpu@400 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + performance-domains = <&performance 0>; #cooling-cells = <2>; }; @@ -131,6 +168,7 @@ cpu5: cpu@500 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + performance-domains = <&performance 0>; #cooling-cells = <2>; }; @@ -149,6 +187,7 @@ cpu6: cpu@600 { d-cache-line-size = <64>; d-cache-sets = <256>; next-level-cache = <&l2_1>; + performance-domains = <&performance 1>; #cooling-cells = <2>; }; @@ -167,6 +206,7 @@ cpu7: cpu@700 { d-cache-line-size = <64>; d-cache-sets = <256>; next-level-cache = <&l2_1>; + performance-domains = <&performance 1>; #cooling-cells = <2>; }; @@ -420,6 +460,11 @@ psci { method = "smc"; }; + sound: sound { + mediatek,platform = <&afe>; + status = "disabled"; + }; + thermal_zones: thermal-zones { cpu-little0-thermal { polling-delay = <1000>; @@ -878,8 +923,15 @@ soc { #address-cells = <2>; #size-cells = <2>; compatible = "simple-bus"; + dma-ranges = <0x0 0x0 0x0 0x0 0x4 0x0>; ranges; + performance: performance-controller@11bc10 { + compatible = "mediatek,cpufreq-hw"; + reg = <0 0x0011bc10 0 0x120>, <0 0x0011bd30 0 0x120>; + #performance-domain-cells = <1>; + }; + gic: interrupt-controller@c000000 { compatible = "arm,gic-v3"; #interrupt-cells = <4>; @@ -956,9 +1008,9 @@ mfg0: power-domain@MT8188_POWER_DOMAIN_MFG0 { #size-cells = <0>; #power-domain-cells = <1>; - power-domain@MT8188_POWER_DOMAIN_MFG1 { + mfg1: power-domain@MT8188_POWER_DOMAIN_MFG1 { reg = ; - clocks = <&topckgen CLK_APMIXED_MFGPLL>, + clocks = <&apmixedsys CLK_APMIXED_MFGPLL>, <&topckgen CLK_TOP_MFG_CORE_TMP>; clock-names = "mfg", "alt"; mediatek,infracfg = <&infracfg_ao>; @@ -1061,20 +1113,22 @@ power-domain@MT8188_POWER_DOMAIN_VPPSYS1 { #power-domain-cells = <0>; }; - power-domain@MT8188_POWER_DOMAIN_VDEC1 { - reg = ; - clocks = <&vdecsys CLK_VDEC2_LARB1>; - clock-names = "ss-vdec"; - mediatek,infracfg = <&infracfg_ao>; - #power-domain-cells = <0>; - }; - power-domain@MT8188_POWER_DOMAIN_VDEC0 { reg = ; clocks = <&vdecsys_soc CLK_VDEC1_SOC_LARB1>; - clock-names = "ss-vdec"; + clock-names = "ss-vdec1-soc-l1"; mediatek,infracfg = <&infracfg_ao>; - #power-domain-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <1>; + + power-domain@MT8188_POWER_DOMAIN_VDEC1 { + reg = ; + clocks = <&vdecsys CLK_VDEC2_LARB1>; + clock-names = "ss-vdec2-l1"; + mediatek,infracfg = <&infracfg_ao>; + #power-domain-cells = <0>; + }; }; cam_vcore: power-domain@MT8188_POWER_DOMAIN_CAM_VCORE { @@ -1291,6 +1345,25 @@ pwrap: pwrap@10024000 { clock-names = "spi", "wrap"; }; + spmi: spmi@10027000 { + compatible = "mediatek,mt8188-spmi", "mediatek,mt8195-spmi"; + reg = <0 0x10027000 0 0xe00>, <0 0x10029000 0 0x100>; + reg-names = "pmif", "spmimst"; + assigned-clocks = <&topckgen CLK_TOP_SPMI_M_MST>; + assigned-clock-parents = <&topckgen CLK_TOP_ULPOSC1_D10>; + clocks = <&infracfg_ao CLK_INFRA_AO_PMIC_AP>, + <&infracfg_ao CLK_INFRA_AO_PMIC_TMR>, + <&topckgen CLK_TOP_SPMI_M_MST>; + clock-names = "pmif_sys_ck", "pmif_tmr_ck", "spmimst_clk_mux"; + }; + + infra_iommu: iommu@10315000 { + compatible = "mediatek,mt8188-iommu-infra"; + reg = <0 0x10315000 0 0x1000>; + interrupts = ; + #iommu-cells = <1>; + }; + gce0: mailbox@10320000 { compatible = "mediatek,mt8188-gce"; reg = <0 0x10320000 0 0x4000>; @@ -1315,6 +1388,97 @@ scp: scp@10500000 { interrupts = ; }; + afe: audio-controller@10b10000 { + compatible = "mediatek,mt8188-afe"; + reg = <0 0x10b10000 0 0x10000>; + assigned-clocks = <&topckgen CLK_TOP_A1SYS_HP>; + assigned-clock-parents = <&clk26m>; + clocks = <&clk26m>, + <&apmixedsys CLK_APMIXED_APLL1>, + <&apmixedsys CLK_APMIXED_APLL2>, + <&topckgen CLK_TOP_APLL12_CK_DIV0>, + <&topckgen CLK_TOP_APLL12_CK_DIV1>, + <&topckgen CLK_TOP_APLL12_CK_DIV2>, + <&topckgen CLK_TOP_APLL12_CK_DIV3>, + <&topckgen CLK_TOP_APLL12_CK_DIV9>, + <&topckgen CLK_TOP_A1SYS_HP>, + <&topckgen CLK_TOP_AUD_INTBUS>, + <&topckgen CLK_TOP_AUDIO_H>, + <&topckgen CLK_TOP_AUDIO_LOCAL_BUS>, + <&topckgen CLK_TOP_DPTX>, + <&topckgen CLK_TOP_I2SO1>, + <&topckgen CLK_TOP_I2SO2>, + <&topckgen CLK_TOP_I2SI1>, + <&topckgen CLK_TOP_I2SI2>, + <&adsp_audio26m CLK_AUDIODSP_AUDIO26M>, + <&topckgen CLK_TOP_APLL1_D4>, + <&topckgen CLK_TOP_APLL2_D4>, + <&topckgen CLK_TOP_APLL12_CK_DIV4>, + <&topckgen CLK_TOP_A2SYS>, + <&topckgen CLK_TOP_AUD_IEC>; + clock-names = "clk26m", + "apll1", + "apll2", + "apll12_div0", + "apll12_div1", + "apll12_div2", + "apll12_div3", + "apll12_div9", + "top_a1sys_hp", + "top_aud_intbus", + "top_audio_h", + "top_audio_local_bus", + "top_dptx", + "top_i2so1", + "top_i2so2", + "top_i2si1", + "top_i2si2", + "adsp_audio_26m", + "apll1_d4", + "apll2_d4", + "apll12_div4", + "top_a2sys", + "top_aud_iec"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_AUDIO>; + resets = <&watchdog MT8188_TOPRGU_AUDIO_SW_RST>; + reset-names = "audiosys"; + mediatek,infracfg = <&infracfg_ao>; + mediatek,topckgen = <&topckgen>; + status = "disabled"; + }; + + adsp: adsp@10b80000 { + compatible = "mediatek,mt8188-dsp"; + reg = <0 0x10b80000 0 0x2000>, + <0 0x10d00000 0 0x80000>, + <0 0x10b8b000 0 0x100>, + <0 0x10b8f000 0 0x1000>; + reg-names = "cfg", "sram", "sec", "bus"; + assigned-clocks = <&topckgen CLK_TOP_ADSP>; + clocks = <&topckgen CLK_TOP_ADSP>, + <&topckgen CLK_TOP_AUDIO_LOCAL_BUS>; + clock-names = "audiodsp", "adsp_bus"; + mboxes = <&adsp_mailbox0>, <&adsp_mailbox1>; + mbox-names = "rx", "tx"; + power-domains = <&spm MT8188_POWER_DOMAIN_ADSP>; + status = "disabled"; + }; + + adsp_mailbox0: mailbox@10b86100 { + compatible = "mediatek,mt8188-adsp-mbox", "mediatek,mt8186-adsp-mbox"; + reg = <0 0x10b86100 0 0x1000>; + interrupts = ; + #mbox-cells = <0>; + }; + + adsp_mailbox1: mailbox@10b87100 { + compatible = "mediatek,mt8188-adsp-mbox", "mediatek,mt8186-adsp-mbox"; + reg = <0 0x10b87100 0 0x1000>; + interrupts = ; + #mbox-cells = <0>; + }; + adsp_audio26m: clock-controller@10b91100 { compatible = "mediatek,mt8188-adsp-audio26m"; reg = <0 0x10b91100 0 0x100>; @@ -1396,6 +1560,28 @@ lvts_ap: thermal-sensor@1100b000 { #thermal-sensor-cells = <1>; }; + disp_pwm0: pwm@1100e000 { + compatible = "mediatek,mt8188-disp-pwm", "mediatek,mt8183-disp-pwm"; + reg = <0 0x1100e000 0 0x1000>; + clocks = <&topckgen CLK_TOP_DISP_PWM0>, + <&infracfg_ao CLK_INFRA_AO_DISP_PWM>; + clock-names = "main", "mm"; + interrupts = ; + #pwm-cells = <2>; + status = "disabled"; + }; + + disp_pwm1: pwm@1100f000 { + compatible = "mediatek,mt8188-disp-pwm", "mediatek,mt8183-disp-pwm"; + reg = <0 0x1100f000 0 0x1000>; + clocks = <&topckgen CLK_TOP_DISP_PWM1>, + <&infracfg_ao CLK_INFRA_AO_DISP_PWM1>; + clock-names = "main", "mm"; + interrupts = ; + #pwm-cells = <2>; + status = "disabled"; + }; + spi1: spi@11010000 { compatible = "mediatek,mt8188-spi-ipm", "mediatek,spi-ipm"; #address-cells = <1>; @@ -1461,6 +1647,103 @@ spi5: spi@11019000 { status = "disabled"; }; + eth: ethernet@11021000 { + compatible = "mediatek,mt8188-gmac", "mediatek,mt8195-gmac", + "snps,dwmac-5.10a"; + reg = <0 0x11021000 0 0x4000>; + interrupts = ; + interrupt-names = "macirq"; + clocks = <&pericfg_ao CLK_PERI_AO_ETHERNET>, + <&pericfg_ao CLK_PERI_AO_ETHERNET_BUS>, + <&topckgen CLK_TOP_SNPS_ETH_250M>, + <&topckgen CLK_TOP_SNPS_ETH_62P4M_PTP>, + <&topckgen CLK_TOP_SNPS_ETH_50M_RMII>, + <&pericfg_ao CLK_PERI_AO_ETHERNET_MAC>; + clock-names = "axi", "apb", "mac_main", "ptp_ref", + "rmii_internal", "mac_cg"; + assigned-clocks = <&topckgen CLK_TOP_SNPS_ETH_250M>, + <&topckgen CLK_TOP_SNPS_ETH_62P4M_PTP>, + <&topckgen CLK_TOP_SNPS_ETH_50M_RMII>; + assigned-clock-parents = <&topckgen CLK_TOP_ETHPLL_D2>, + <&topckgen CLK_TOP_ETHPLL_D8>, + <&topckgen CLK_TOP_ETHPLL_D10>; + power-domains = <&spm MT8188_POWER_DOMAIN_ETHER>; + mediatek,pericfg = <&infracfg_ao>; + snps,axi-config = <&stmmac_axi_setup>; + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + snps,txpbl = <16>; + snps,rxpbl = <16>; + snps,clk-csr = <0>; + status = "disabled"; + + eth_mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + + stmmac_axi_setup: stmmac-axi-config { + snps,blen = <0 0 0 0 16 8 4>; + snps,rd_osr_lmt = <0x7>; + snps,wr_osr_lmt = <0x7>; + }; + + mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <4>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + }; + + queue1 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + }; + + queue2 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + }; + + queue3 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + }; + }; + + mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <4>; + snps,tx-sched-wrr; + + queue0 { + snps,dcb-algorithm; + snps,priority = <0x0>; + snps,weight = <0x10>; + }; + + queue1 { + snps,dcb-algorithm; + snps,priority = <0x1>; + snps,weight = <0x11>; + }; + + queue2 { + snps,dcb-algorithm; + snps,priority = <0x2>; + snps,weight = <0x12>; + }; + + queue3 { + snps,dcb-algorithm; + snps,priority = <0x3>; + snps,weight = <0x13>; + }; + }; + }; + xhci1: usb@11200000 { compatible = "mediatek,mt8188-xhci", "mediatek,mtk-xhci"; reg = <0 0x11200000 0 0x1000>, @@ -1606,6 +1889,54 @@ xhci0: usb@112b0000 { status = "disabled"; }; + pcie: pcie@112f0000 { + compatible = "mediatek,mt8188-pcie", "mediatek,mt8192-pcie"; + reg = <0 0x112f0000 0 0x2000>; + reg-names = "pcie-mac"; + ranges = <0x82000000 0 0x20000000 0 0x20000000 0 0x4000000>; + bus-range = <0 0xff>; + device_type = "pci"; + linux,pci-domain = <0>; + #address-cells = <3>; + #size-cells = <2>; + + clocks = <&infracfg_ao CLK_INFRA_AO_PCIE_PL_P_250M_P0>, + <&infracfg_ao CLK_INFRA_AO_PCIE_TL_26M>, + <&infracfg_ao CLK_INFRA_AO_PCIE_TL_96M>, + <&infracfg_ao CLK_INFRA_AO_PCIE_TL_32K>, + <&infracfg_ao CLK_INFRA_AO_PCIE_PERI_26M>, + <&pericfg_ao CLK_PERI_AO_PCIE_P0_FMEM>; + clock-names = "pl_250m", "tl_26m", "tl_96m", "tl_32k", + "peri_26m", "peri_mem"; + + #interrupt-cells = <1>; + interrupts = ; + interrupt-map = <0 0 0 1 &pcie_intc 0>, + <0 0 0 2 &pcie_intc 1>, + <0 0 0 3 &pcie_intc 2>, + <0 0 0 4 &pcie_intc 3>; + interrupt-map-mask = <0 0 0 7>; + + iommu-map = <0 &infra_iommu IFR_IOMMU_PORT_PCIE_0 0xffff>; + iommu-map-mask = <0>; + + phys = <&pcieport PHY_TYPE_PCIE>; + phy-names = "pcie-phy"; + + power-domains = <&spm MT8188_POWER_DOMAIN_PEXTP_MAC_P0>; + + resets = <&watchdog MT8188_TOPRGU_PCIE_SW_RST>; + reset-names = "mac"; + + status = "disabled"; + + pcie_intc: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + nor_flash: spi@1132c000 { compatible = "mediatek,mt8188-nor", "mediatek,mt8186-nor"; reg = <0 0x1132c000 0 0x1000>; @@ -1615,6 +1946,44 @@ nor_flash: spi@1132c000 { clock-names = "spi", "sf", "axi"; assigned-clocks = <&topckgen CLK_TOP_SPINOR>; interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + pciephy: t-phy@11c20700 { + compatible = "mediatek,mt8188-tphy", "mediatek,generic-tphy-v3"; + ranges = <0 0 0x11c20700 0x700>; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&spm MT8188_POWER_DOMAIN_PEXTP_PHY_TOP>; + status = "disabled"; + + pcieport: pcie-phy@0 { + reg = <0 0x700>; + clocks = <&topckgen CLK_TOP_CFGREG_F_PCIE_PHY_REF>; + clock-names = "ref"; + #phy-cells = <1>; + }; + }; + + mipi_tx_config0: dsi-phy@11c80000 { + compatible = "mediatek,mt8188-mipi-tx", "mediatek,mt8183-mipi-tx"; + reg = <0 0x11c80000 0 0x1000>; + clocks = <&clk26m>; + clock-output-names = "mipi_tx0_pll"; + #clock-cells = <0>; + #phy-cells = <0>; + status = "disabled"; + }; + + mipi_tx_config1: dsi-phy@11c90000 { + compatible = "mediatek,mt8188-mipi-tx", "mediatek,mt8183-mipi-tx"; + reg = <0 0x11c90000 0 0x1000>; + clocks = <&clk26m>; + clock-output-names = "mipi_tx0_pll"; + #clock-cells = <0>; + #phy-cells = <0>; status = "disabled"; }; @@ -1689,7 +2058,6 @@ u3port1: usb-phy@700 { <&clk26m>; clock-names = "ref", "da_ref"; #phy-cells = <1>; - status = "disabled"; }; }; @@ -1749,9 +2117,21 @@ efuse: efuse@11f20000 { #address-cells = <1>; #size-cells = <1>; + dp_calib_data: dp-calib@1a0 { + reg = <0x1a0 0xc>; + }; + lvts_efuse_data1: lvts1-calib@1ac { reg = <0x1ac 0x40>; }; + + socinfo-data1@7a0 { + reg = <0x7a0 0x4>; + }; + + socinfo-data2@7e0 { + reg = <0x7e0 0x4>; + }; }; gpu: gpu@13000000 { @@ -1778,12 +2158,43 @@ mfgcfg: clock-controller@13fbf000 { #clock-cells = <1>; }; - vppsys0: clock-controller@14000000 { - compatible = "mediatek,mt8188-vppsys0"; + vppsys0: syscon@14000000 { + compatible = "mediatek,mt8188-vppsys0", "syscon"; reg = <0 0x14000000 0 0x1000>; #clock-cells = <1>; }; + vpp_smi_common: smi@14012000 { + compatible = "mediatek,mt8188-smi-common-vpp"; + reg = <0 0x14012000 0 0x1000>; + clocks = <&vppsys0 CLK_VPP0_SMI_COMMON_LARB4>, + <&vppsys0 CLK_VPP0_SMI_SUB_COMMON_REORDER>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VPPSYS0>; + }; + + larb4: smi@14013000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x14013000 0 0x1000>; + clocks = <&vppsys0 CLK_VPP0_SMI_COMMON_LARB4>, + <&vppsys0 CLK_VPP0_SMI_COMMON_LARB4>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VPPSYS0>; + mediatek,larb-id = ; + mediatek,smi = <&vpp_smi_common>; + }; + + vpp_iommu: iommu@14018000 { + compatible = "mediatek,mt8188-iommu-vpp"; + reg = <0 0x14018000 0 0x5000>; + clocks = <&vppsys0 CLK_VPP0_SMI_IOMMU>; + clock-names = "bclk"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VPPSYS0>; + #iommu-cells = <1>; + mediatek,larbs = <&larb1 &larb3 &larb4 &larb6 &larb7 &larb23>; + }; + wpesys: clock-controller@14e00000 { compatible = "mediatek,mt8188-wpesys"; reg = <0 0x14e00000 0 0x1000>; @@ -1796,12 +2207,45 @@ wpesys_vpp0: clock-controller@14e02000 { #clock-cells = <1>; }; - vppsys1: clock-controller@14f00000 { - compatible = "mediatek,mt8188-vppsys1"; + larb7: smi@14e04000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x14e04000 0 0x1000>; + clocks = <&wpesys CLK_WPE_TOP_SMI_LARB7>, + <&wpesys CLK_WPE_TOP_SMI_LARB7>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_WPE>; + mediatek,larb-id = ; + mediatek,smi = <&vpp_smi_common>; + }; + + vppsys1: syscon@14f00000 { + compatible = "mediatek,mt8188-vppsys1", "syscon"; reg = <0 0x14f00000 0 0x1000>; #clock-cells = <1>; }; + larb5: smi@14f02000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x14f02000 0 0x1000>; + clocks = <&vppsys1 CLK_VPP1_GALS5>, + <&vppsys1 CLK_VPP1_LARB5>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VPPSYS1>; + mediatek,larb-id = ; + mediatek,smi = <&vdo_smi_common>; + }; + + larb6: smi@14f03000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x14f03000 0 0x1000>; + clocks = <&vppsys1 CLK_VPP1_GALS6>, + <&vppsys1 CLK_VPP1_LARB6>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VPPSYS1>; + mediatek,larb-id = ; + mediatek,smi = <&vpp_smi_common>; + }; + imgsys: clock-controller@15000000 { compatible = "mediatek,mt8188-imgsys"; reg = <0 0x15000000 0 0x1000>; @@ -1880,12 +2324,92 @@ ccusys: clock-controller@17200000 { #clock-cells = <1>; }; + video_decoder: video-decoder@18000000 { + compatible = "mediatek,mt8188-vcodec-dec"; + reg = <0 0x18000000 0 0x1000>, <0 0x18004000 0 0x1000>; + ranges = <0 0 0 0x18000000 0 0x26000>; + iommus = <&vpp_iommu M4U_PORT_L23_HW_VDEC_UFO_ENC_EXT>; + #address-cells = <2>; + #size-cells = <2>; + mediatek,scp = <&scp>; + + video-codec@10000 { + compatible = "mediatek,mtk-vcodec-lat"; + reg = <0 0x10000 0 0x800>; + assigned-clocks = <&topckgen CLK_TOP_VDEC>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D6>; + clocks = <&topckgen CLK_TOP_VDEC>, + <&vdecsys_soc CLK_VDEC1_SOC_VDEC>, + <&vdecsys_soc CLK_VDEC1_SOC_LAT>, + <&topckgen CLK_TOP_UNIVPLL_D6>; + clock-names = "sel", "vdec", "lat", "top"; + interrupts = ; + iommus = <&vpp_iommu M4U_PORT_L23_HW_VDEC_LAT0_VLD_EXT>, + <&vpp_iommu M4U_PORT_L23_HW_VDEC_LAT0_VLD2_EXT>, + <&vpp_iommu M4U_PORT_L23_HW_VDEC_LAT0_AVC_MV_EXT>, + <&vpp_iommu M4U_PORT_L23_HW_VDEC_LAT0_PRED_RD_EXT>, + <&vpp_iommu M4U_PORT_L23_HW_VDEC_LAT0_TILE_EXT>, + <&vpp_iommu M4U_PORT_L23_HW_VDEC_LAT0_WDMA_EXT>, + <&vpp_iommu M4U_PORT_L23_HW_VDEC_UFO_ENC_EXT>, + <&vpp_iommu M4U_PORT_L23_HW_VDEC_UFO_ENC_EXT_C>, + <&vpp_iommu M4U_PORT_L23_HW_VDEC_MC_EXT_C>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDEC0>; + }; + + video-codec@25000 { + compatible = "mediatek,mtk-vcodec-core"; + reg = <0 0x25000 0 0x1000>; + assigned-clocks = <&topckgen CLK_TOP_VDEC>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D6>; + clocks = <&topckgen CLK_TOP_VDEC>, + <&vdecsys CLK_VDEC2_VDEC>, + <&vdecsys CLK_VDEC2_LAT>, + <&topckgen CLK_TOP_UNIVPLL_D6>; + clock-names = "sel", "vdec", "lat", "top"; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L21_HW_VDEC_MC_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_UFO_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_PP_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_PRED_RD_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_PRED_WR_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_PPWRAP_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_TILE_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_VLD_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_VLD2_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_AVC_MV_EXT>, + <&vdo_iommu M4U_PORT_L21_HW_VDEC_UFO_EXT_C>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDEC1>; + }; + }; + + larb23: smi@1800d000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x1800d000 0 0x1000>; + clocks = <&vdecsys_soc CLK_VDEC1_SOC_LARB1>, + <&vdecsys_soc CLK_VDEC1_SOC_LARB1>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDEC0>; + mediatek,larb-id = ; + mediatek,smi = <&vpp_smi_common>; + }; + vdecsys_soc: clock-controller@1800f000 { compatible = "mediatek,mt8188-vdecsys-soc"; reg = <0 0x1800f000 0 0x1000>; #clock-cells = <1>; }; + larb21: smi@1802e000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x1802e000 0 0x1000>; + clocks = <&vdecsys CLK_VDEC2_LARB1>, + <&vdecsys CLK_VDEC2_LARB1>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDEC1>; + mediatek,larb-id = ; + mediatek,smi = <&vdo_smi_common>; + }; + vdecsys: clock-controller@1802f000 { compatible = "mediatek,mt8188-vdecsys"; reg = <0 0x1802f000 0 0x1000>; @@ -1898,14 +2422,249 @@ vencsys: clock-controller@1a000000 { #clock-cells = <1>; }; + larb19: smi@1a010000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x1a010000 0 0x1000>; + clocks = <&vencsys CLK_VENC1_VENC>, + <&vencsys CLK_VENC1_VENC>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VENC>; + mediatek,larb-id = ; + mediatek,smi = <&vdo_smi_common>; + }; + + video_encoder: video-encoder@1a020000 { + compatible = "mediatek,mt8188-vcodec-enc"; + reg = <0 0x1a020000 0 0x10000>; + #address-cells = <2>; + #size-cells = <2>; + assigned-clocks = <&topckgen CLK_TOP_VENC>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D4>; + clocks = <&vencsys CLK_VENC1_VENC>; + clock-names = "venc_sel"; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L19_VENC_RCPU>, + <&vdo_iommu M4U_PORT_L19_VENC_REC>, + <&vdo_iommu M4U_PORT_L19_VENC_BSDMA>, + <&vdo_iommu M4U_PORT_L19_VENC_SV_COMV>, + <&vdo_iommu M4U_PORT_L19_VENC_RD_COMV>, + <&vdo_iommu M4U_PORT_L19_VENC_CUR_LUMA>, + <&vdo_iommu M4U_PORT_L19_VENC_CUR_CHROMA>, + <&vdo_iommu M4U_PORT_L19_VENC_REF_LUMA>, + <&vdo_iommu M4U_PORT_L19_VENC_REF_CHROMA>, + <&vdo_iommu M4U_PORT_L19_VENC_SUB_W_LUMA>, + <&vdo_iommu M4U_PORT_L19_VENC_SUB_R_LUMA>; + power-domains = <&spm MT8188_POWER_DOMAIN_VENC>; + mediatek,scp = <&scp>; + }; + + jpeg_encoder: jpeg-encoder@1a030000 { + compatible = "mediatek,mt8188-jpgenc", "mediatek,mtk-jpgenc"; + reg = <0 0x1a030000 0 0x10000>; + clocks = <&vencsys CLK_VENC1_JPGENC>; + clock-names = "jpgenc"; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L19_JPGENC_Y_RDMA>, + <&vdo_iommu M4U_PORT_L19_JPGENC_C_RDMA>, + <&vdo_iommu M4U_PORT_L19_JPGENC_Q_TABLE>, + <&vdo_iommu M4U_PORT_L19_JPGENC_BSDMA>; + power-domains = <&spm MT8188_POWER_DOMAIN_VENC>; + }; + + jpeg_decoder: jpeg-decoder@1a040000 { + compatible = "mediatek,mt8188-jpgdec", "mediatek,mt2701-jpgdec"; + reg = <0 0x1a040000 0 0x10000>; + clocks = <&vencsys CLK_VENC1_LARB>, + <&vencsys CLK_VENC1_JPGDEC>; + clock-names = "jpgdec-smi", "jpgdec"; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L19_JPGDEC_WDMA_0>, + <&vdo_iommu M4U_PORT_L19_JPGDEC_BSDMA_0>, + <&vdo_iommu M4U_PORT_L19_JPGDEC_WDMA_1>, + <&vdo_iommu M4U_PORT_L19_JPGDEC_BSDMA_1>, + <&vdo_iommu M4U_PORT_L19_JPGDEC_HUFF_OFFSET_1>, + <&vdo_iommu M4U_PORT_L19_JPGDEC_HUFF_OFFSET_0>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDEC0>; + }; + + ovl0: ovl@1c000000 { + compatible = "mediatek,mt8188-disp-ovl", "mediatek,mt8183-disp-ovl"; + reg = <0 0x1c000000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_OVL0>; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L0_DISP_OVL0_RDMA0>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x0000 0x1000>; + }; + + rdma0: rdma@1c002000 { + compatible = "mediatek,mt8188-disp-rdma", "mediatek,mt8195-disp-rdma"; + reg = <0 0x1c002000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_RDMA0>; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L1_DISP_RDMA0>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x2000 0x1000>; + }; + + color0: color@1c003000 { + compatible = "mediatek,mt8188-disp-color", "mediatek,mt8173-disp-color"; + reg = <0 0x1c003000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_COLOR0>; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x3000 0x1000>; + }; + + ccorr0: ccorr@1c004000 { + compatible = "mediatek,mt8188-disp-ccorr", "mediatek,mt8192-disp-ccorr"; + reg = <0 0x1c004000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_CCORR0>; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x4000 0x1000>; + }; + + aal0: aal@1c005000 { + compatible = "mediatek,mt8188-disp-aal", "mediatek,mt8183-disp-aal"; + reg = <0 0x1c005000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_AAL0>; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x5000 0x1000>; + }; + + gamma0: gamma@1c006000 { + compatible = "mediatek,mt8188-disp-gamma", "mediatek,mt8195-disp-gamma"; + reg = <0 0x1c006000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_GAMMA0>; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x6000 0x1000>; + }; + + dither0: dither@1c007000 { + compatible = "mediatek,mt8188-disp-dither", "mediatek,mt8183-disp-dither"; + reg = <0 0x1c007000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_DITHER0>; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x7000 0x1000>; + }; + + disp_dsi0: dsi@1c008000 { + compatible = "mediatek,mt8188-dsi"; + reg = <0 0x1c008000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DSI0>, + <&vdosys0 CLK_VDO0_DSI0_DSI>, + <&mipi_tx_config0>; + clock-names = "engine", "digital", "hs"; + interrupts = ; + phys = <&mipi_tx_config0>; + phy-names = "dphy"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + resets = <&vdosys0 MT8188_VDO0_RST_DSI0>; + status = "disabled"; + }; + + disp_dsi1: dsi@1c012000 { + compatible = "mediatek,mt8188-dsi"; + reg = <0 0x1c012000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DSI1>, + <&vdosys0 CLK_VDO0_DSI1_DSI>, + <&mipi_tx_config1>; + clock-names = "engine", "digital", "hs"; + interrupts = ; + phys = <&mipi_tx_config1>; + phy-names = "dphy"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + resets = <&vdosys0 MT8188_VDO0_RST_DSI1>; + status = "disabled"; + }; + + dp_intf0: dp-intf@1c015000 { + compatible = "mediatek,mt8188-dp-intf"; + reg = <0 0x1c015000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DP_INTF0_DP_INTF>, + <&vdosys0 CLK_VDO0_DP_INTF0>, + <&apmixedsys CLK_APMIXED_TVDPLL1>; + clock-names = "pixel", "engine", "pll"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + status = "disabled"; + }; + + mutex0: mutex@1c016000 { + compatible = "mediatek,mt8188-disp-mutex"; + reg = <0 0x1c016000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_MUTEX0>; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c01XXXX 0x6000 0x1000>; + mediatek,gce-events = ; + }; + + postmask0: postmask@1c01a000 { + compatible = "mediatek,mt8188-disp-postmask", + "mediatek,mt8192-disp-postmask"; + reg = <0 0x1c01a000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_DISP_POSTMASK0>; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c01XXXX 0xa000 0x1000>; + }; + vdosys0: syscon@1c01d000 { compatible = "mediatek,mt8188-vdosys0", "syscon"; reg = <0 0x1c01d000 0 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; mboxes = <&gce0 0 CMDQ_THR_PRIO_4>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c01XXXX 0xd000 0x1000>; }; + larb0: smi@1c022000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x1c022000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_SMI_LARB>, + <&vdosys0 CLK_VDO0_SMI_LARB>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,larb-id = ; + mediatek,smi = <&vdo_smi_common>; + }; + + larb1: smi@1c023000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x1c023000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_SMI_LARB>, + <&vdosys0 CLK_VDO0_SMI_LARB>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + mediatek,larb-id = ; + mediatek,smi = <&vpp_smi_common>; + }; + + vdo_smi_common: smi@1c024000 { + compatible = "mediatek,mt8188-smi-common-vdo"; + reg = <0 0x1c024000 0 0x1000>; + clocks = <&vdosys0 CLK_VDO0_SMI_COMMON>, + <&vdosys0 CLK_VDO0_SMI_GALS>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + }; + + vdo_iommu: iommu@1c028000 { + compatible = "mediatek,mt8188-iommu-vdo"; + reg = <0 0x1c028000 0 0x5000>; + clocks = <&vdosys0 CLK_VDO0_SMI_IOMMU>; + clock-names = "bclk"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS0>; + #iommu-cells = <1>; + mediatek,larbs = <&larb0 &larb2 &larb5 &larb19 &larb21>; + }; + vdosys1: syscon@1c100000 { compatible = "mediatek,mt8188-vdosys1", "syscon"; reg = <0 0x1c100000 0 0x1000>; @@ -1914,5 +2673,336 @@ vdosys1: syscon@1c100000 { mboxes = <&gce0 1 CMDQ_THR_PRIO_4>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0 0x1000>; }; + + mutex1: mutex@1c101000 { + compatible = "mediatek,mt8188-disp-mutex"; + reg = <0 0x1c101000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_DISP_MUTEX>; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x1000 0x1000>; + mediatek,gce-events = ; + }; + + larb2: smi@1c102000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x1c102000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_SMI_LARB2>, + <&vdosys1 CLK_VDO1_SMI_LARB2>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,larb-id = ; + mediatek,smi = <&vdo_smi_common>; + }; + + larb3: smi@1c103000 { + compatible = "mediatek,mt8188-smi-larb"; + reg = <0 0x1c103000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_SMI_LARB3>, + <&vdosys1 CLK_VDO1_SMI_LARB3>; + clock-names = "apb", "smi"; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,larb-id = ; + mediatek,smi = <&vpp_smi_common>; + }; + + vdo1_rdma0: rdma@1c104000 { + compatible = "mediatek,mt8188-vdo1-rdma", "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c104000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_MDP_RDMA0>; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L2_MDP_RDMA0>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + #dma-cells = <1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x4000 0x1000>; + }; + + vdo1_rdma1: rdma@1c105000 { + compatible = "mediatek,mt8188-vdo1-rdma", "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c105000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_MDP_RDMA1>; + interrupts = ; + iommus = <&vpp_iommu M4U_PORT_L3_MDP_RDMA1>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + #dma-cells = <1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x5000 0x1000>; + }; + + vdo1_rdma2: rdma@1c106000 { + compatible = "mediatek,mt8188-vdo1-rdma", "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c106000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_MDP_RDMA2>; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L2_MDP_RDMA2>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + #dma-cells = <1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x6000 0x1000>; + }; + + vdo1_rdma3: rdma@1c107000 { + compatible = "mediatek,mt8188-vdo1-rdma", "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c107000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_MDP_RDMA3>; + interrupts = ; + iommus = <&vpp_iommu M4U_PORT_L3_MDP_RDMA3>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + #dma-cells = <1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x7000 0x1000>; + }; + + vdo1_rdma4: rdma@1c108000 { + compatible = "mediatek,mt8188-vdo1-rdma", "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c108000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_MDP_RDMA4>; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L2_MDP_RDMA4>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + #dma-cells = <1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x8000 0x1000>; + }; + + vdo1_rdma5: rdma@1c109000 { + compatible = "mediatek,mt8188-vdo1-rdma", "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c109000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_MDP_RDMA5>; + interrupts = ; + iommus = <&vpp_iommu M4U_PORT_L3_MDP_RDMA5>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + #dma-cells = <1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x9000 0x1000>; + }; + + vdo1_rdma6: rdma@1c10a000 { + compatible = "mediatek,mt8188-vdo1-rdma", "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c10a000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_MDP_RDMA6>; + interrupts = ; + iommus = <&vdo_iommu M4U_PORT_L2_MDP_RDMA6>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + #dma-cells = <1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xa000 0x1000>; + }; + + vdo1_rdma7: rdma@1c10b000 { + compatible = "mediatek,mt8188-vdo1-rdma", "mediatek,mt8195-vdo1-rdma"; + reg = <0 0x1c10b000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_MDP_RDMA7>; + interrupts = ; + iommus = <&vpp_iommu M4U_PORT_L3_MDP_RDMA7>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + #dma-cells = <1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xb000 0x1000>; + }; + + merge1: merge@1c10c000 { + compatible = "mediatek,mt8188-disp-merge", "mediatek,mt8195-disp-merge"; + reg = <0 0x1c10c000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_VPP_MERGE0>, + <&vdosys1 CLK_VDO1_MERGE0_DL_ASYNC>; + clock-names = "merge", "merge_async"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + resets = <&vdosys1 MT8188_VDO1_RST_MERGE0_DL_ASYNC>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xc000 0x1000>; + mediatek,merge-mute; + }; + + merge2: merge@1c10d000 { + compatible = "mediatek,mt8188-disp-merge", "mediatek,mt8195-disp-merge"; + reg = <0 0x1c10d000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_VPP_MERGE1>, + <&vdosys1 CLK_VDO1_MERGE1_DL_ASYNC>; + clock-names = "merge", "merge_async"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + resets = <&vdosys1 MT8188_VDO1_RST_MERGE1_DL_ASYNC>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xd000 0x1000>; + mediatek,merge-mute; + }; + + merge3: merge@1c10e000 { + compatible = "mediatek,mt8188-disp-merge", "mediatek,mt8195-disp-merge"; + reg = <0 0x1c10e000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_VPP_MERGE2>, + <&vdosys1 CLK_VDO1_MERGE2_DL_ASYNC>; + clock-names = "merge", "merge_async"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + resets = <&vdosys1 MT8188_VDO1_RST_MERGE2_DL_ASYNC>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xe000 0x1000>; + mediatek,merge-mute; + }; + + merge4: merge@1c10f000 { + compatible = "mediatek,mt8188-disp-merge", "mediatek,mt8195-disp-merge"; + reg = <0 0x1c10f000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_VPP_MERGE3>, + <&vdosys1 CLK_VDO1_MERGE3_DL_ASYNC>; + clock-names = "merge", "merge_async"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + resets = <&vdosys1 MT8188_VDO1_RST_MERGE3_DL_ASYNC>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xf000 0x1000>; + mediatek,merge-mute; + }; + + merge5: merge@1c110000 { + compatible = "mediatek,mt8188-disp-merge", "mediatek,mt8195-disp-merge"; + reg = <0 0x1c110000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_VPP_MERGE4>, + <&vdosys1 CLK_VDO1_MERGE4_DL_ASYNC>; + clock-names = "merge", "merge_async"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + resets = <&vdosys1 MT8188_VDO1_RST_MERGE4_DL_ASYNC>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0x0000 0x1000>; + mediatek,merge-fifo-en; + }; + + dp_intf1: dp-intf@1c113000 { + compatible = "mediatek,mt8188-dp-intf"; + reg = <0 0x1c113000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_DPINTF>, + <&vdosys1 CLK_VDO1_DP_INTF0_MMCK>, + <&apmixedsys CLK_APMIXED_TVDPLL2>; + clock-names = "pixel", "engine", "pll"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + status = "disabled"; + }; + + ethdr0: ethdr@1c114000 { + compatible = "mediatek,mt8188-disp-ethdr", "mediatek,mt8195-disp-ethdr"; + reg = <0 0x1c114000 0 0x1000>, + <0 0x1c115000 0 0x1000>, + <0 0x1c117000 0 0x1000>, + <0 0x1c119000 0 0x1000>, + <0 0x1c11a000 0 0x1000>, + <0 0x1c11b000 0 0x1000>, + <0 0x1c11c000 0 0x1000>; + reg-names = "mixer", "vdo_fe0", "vdo_fe1", "gfx_fe0", "gfx_fe1", + "vdo_be", "adl_ds"; + + clocks = <&vdosys1 CLK_VDO1_DISP_MIXER>, + <&vdosys1 CLK_VDO1_HDR_VDO_FE0>, + <&vdosys1 CLK_VDO1_HDR_VDO_FE1>, + <&vdosys1 CLK_VDO1_HDR_GFX_FE0>, + <&vdosys1 CLK_VDO1_HDR_GFX_FE1>, + <&vdosys1 CLK_VDO1_HDR_VDO_BE>, + <&vdosys1 CLK_VDO1_26M_SLOW>, + <&vdosys1 CLK_VDO1_HDR_VDO_FE0_DL_ASYNC>, + <&vdosys1 CLK_VDO1_HDR_VDO_FE1_DL_ASYNC>, + <&vdosys1 CLK_VDO1_HDR_GFX_FE0_DL_ASYNC>, + <&vdosys1 CLK_VDO1_HDR_GFX_FE1_DL_ASYNC>, + <&vdosys1 CLK_VDO1_HDR_VDO_BE_DL_ASYNC>, + <&topckgen CLK_TOP_ETHDR>; + clock-names = "mixer", "vdo_fe0", "vdo_fe1", "gfx_fe0", "gfx_fe1", + "vdo_be", "adl_ds", "vdo_fe0_async", "vdo_fe1_async", + "gfx_fe0_async", "gfx_fe1_async", "vdo_be_async", "ethdr_top"; + + interrupts = ; + iommus = <&vpp_iommu M4U_PORT_L3_HDR_DS_SMI>, + <&vpp_iommu M4U_PORT_L3_HDR_ADL_SMI>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + resets = <&vdosys1 MT8188_VDO1_RST_HDR_VDO_FE0_DL_ASYNC>, + <&vdosys1 MT8188_VDO1_RST_HDR_VDO_FE1_DL_ASYNC>, + <&vdosys1 MT8188_VDO1_RST_HDR_GFX_FE0_DL_ASYNC>, + <&vdosys1 MT8188_VDO1_RST_HDR_GFX_FE1_DL_ASYNC>, + <&vdosys1 MT8188_VDO1_RST_HDR_VDO_BE_DL_ASYNC>; + + mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0x4000 0x1000>, + <&gce0 SUBSYS_1c11XXXX 0x5000 0x1000>, + <&gce0 SUBSYS_1c11XXXX 0x7000 0x1000>, + <&gce0 SUBSYS_1c11XXXX 0x9000 0x1000>, + <&gce0 SUBSYS_1c11XXXX 0xa000 0x1000>, + <&gce0 SUBSYS_1c11XXXX 0xb000 0x1000>, + <&gce0 SUBSYS_1c11XXXX 0xc000 0x1000>; + }; + + padding0: padding@1c11d000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c11d000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING0>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0xd000 0x1000>; + }; + + padding1: padding@1c11e000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c11e000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING1>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0xe000 0x1000>; + }; + + padding2: padding@1c11f000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c11f000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING2>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0xf000 0x1000>; + }; + + padding3: padding@1c120000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c120000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING3>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c12XXXX 0x0000 0x1000>; + }; + + padding4: padding@1c121000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c121000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING4>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c12XXXX 0x1000 0x1000>; + }; + + padding5: padding@1c122000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c122000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING5>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c12XXXX 0x2000 0x1000>; + }; + + padding6: padding@1c123000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c123000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING6>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c12XXXX 0x3000 0x1000>; + }; + + padding7: padding@1c124000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c124000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING7>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c12XXXX 0x4000 0x1000>; + }; + + edp_tx: edp-tx@1c500000 { + compatible = "mediatek,mt8188-edp-tx"; + reg = <0 0x1c500000 0 0x8000>; + interrupts = ; + nvmem-cells = <&dp_calib_data>; + nvmem-cell-names = "dp_calibration_data"; + power-domains = <&spm MT8188_POWER_DOMAIN_EDP_TX>; + max-linkrate-mhz = <8100>; + status = "disabled"; + }; + + dp_tx: dp-tx@1c600000 { + compatible = "mediatek,mt8188-dp-tx"; + reg = <0 0x1c600000 0 0x8000>; + interrupts = ; + nvmem-cells = <&dp_calib_data>; + nvmem-cell-names = "dp_calibration_data"; + power-domains = <&spm MT8188_POWER_DOMAIN_DP_TX>; + max-linkrate-mhz = <5400>; + status = "disabled"; + }; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dts b/arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dts index 29aa87e938882f..8c485c3ced2c81 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dts +++ b/arch/arm64/boot/dts/mediatek/mt8192-asurada-spherion-r0.dts @@ -79,3 +79,14 @@ headset-codec { &touchscreen { compatible = "elan,ekth3500"; }; + +&i2c2 { + /* synaptics touchpad */ + trackpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + hid-descr-addr = <0x20>; + interrupts-extended = <&pio 15 IRQ_TYPE_LEVEL_LOW>; + wakeup-source; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi index 08d71ddf36683e..8dda8b63765bad 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi @@ -335,14 +335,12 @@ &i2c2 { clock-frequency = <400000>; clock-stretch-ns = <12600>; pinctrl-names = "default"; - pinctrl-0 = <&i2c2_pins>; + pinctrl-0 = <&i2c2_pins>, <&trackpad_pins>; trackpad@15 { compatible = "elan,ekth3000"; reg = <0x15>; interrupts-extended = <&pio 15 IRQ_TYPE_LEVEL_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&trackpad_pins>; vcc-supply = <&pp3300_u>; wakeup-source; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi index 75d56b2d5a3d34..2c7b2223ee76b1 100644 --- a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi @@ -438,7 +438,7 @@ audio_codec: codec@1a { /* Realtek RT5682i or RT5682s, sharing the same configuration */ reg = <0x1a>; interrupts-extended = <&pio 89 IRQ_TYPE_EDGE_BOTH>; - #sound-dai-cells = <0>; + #sound-dai-cells = <1>; realtek,jd-src = <1>; AVDD-supply = <&mt6359_vio18_ldo_reg>; @@ -1181,7 +1181,7 @@ hs-playback-dai-link { link-name = "ETDM1_OUT_BE"; mediatek,clk-provider = "cpu"; codec { - sound-dai = <&audio_codec>; + sound-dai = <&audio_codec 0>; }; }; @@ -1189,7 +1189,7 @@ hs-capture-dai-link { link-name = "ETDM2_IN_BE"; mediatek,clk-provider = "cpu"; codec { - sound-dai = <&audio_codec>; + sound-dai = <&audio_codec 0>; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi index e89ba384c4aafc..ade685ed2190b7 100644 --- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi @@ -487,7 +487,7 @@ topckgen: syscon@10000000 { }; infracfg_ao: syscon@10001000 { - compatible = "mediatek,mt8195-infracfg_ao", "syscon", "simple-mfd"; + compatible = "mediatek,mt8195-infracfg_ao", "syscon"; reg = <0 0x10001000 0 0x1000>; #clock-cells = <1>; #reset-cells = <1>; @@ -3331,11 +3331,9 @@ &larb19 &larb21 &larb24 &larb25 mutex1: mutex@1c101000 { compatible = "mediatek,mt8195-disp-mutex"; reg = <0 0x1c101000 0 0x1000>; - reg-names = "vdo1_mutex"; interrupts = ; power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; clocks = <&vdosys1 CLK_VDO1_DISP_MUTEX>; - clock-names = "vdo1_mutex"; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x1000 0x1000>; mediatek,gce-events = ; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8390-genio-700-evk.dts b/arch/arm64/boot/dts/mediatek/mt8390-genio-700-evk.dts index 1474bef7e754d0..13f2e0e3fa8ab6 100644 --- a/arch/arm64/boot/dts/mediatek/mt8390-genio-700-evk.dts +++ b/arch/arm64/boot/dts/mediatek/mt8390-genio-700-evk.dts @@ -23,6 +23,16 @@ / { "mediatek,mt8188"; aliases { + ethernet0 = ð + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + mmc0 = &mmc0; + mmc1 = &mmc1; serial0 = &uart0; }; @@ -87,109 +97,124 @@ vpu_mem: memory@57000000 { common_fixed_5v: regulator-0 { compatible = "regulator-fixed"; - regulator-name = "5v_en"; + regulator-name = "vdd_5v"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&pio 10 GPIO_ACTIVE_HIGH>; enable-active-high; regulator-always-on; + vin-supply = <®_vsys>; }; edp_panel_fixed_3v3: regulator-1 { compatible = "regulator-fixed"; - regulator-name = "edp_panel_3v3"; + regulator-name = "vedp_3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; enable-active-high; gpio = <&pio 15 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&edp_panel_3v3_en_pins>; + vin-supply = <®_vsys>; }; gpio_fixed_3v3: regulator-2 { compatible = "regulator-fixed"; - regulator-name = "gpio_3v3_en"; + regulator-name = "ext_3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&pio 9 GPIO_ACTIVE_HIGH>; enable-active-high; regulator-always-on; + vin-supply = <®_vsys>; }; + /* system wide 4.2V power rail from charger */ + reg_vsys: regulator-vsys { + compatible = "regulator-fixed"; + regulator-name = "vsys"; + regulator-always-on; + regulator-boot-on; + }; + + /* used by mmc2 */ sdio_fixed_1v8: regulator-3 { compatible = "regulator-fixed"; - regulator-name = "sdio_io"; + regulator-name = "vio18_conn"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; enable-active-high; regulator-always-on; }; + /* used by mmc2 */ sdio_fixed_3v3: regulator-4 { compatible = "regulator-fixed"; - regulator-name = "sdio_card"; + regulator-name = "wifi_3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&pio 74 GPIO_ACTIVE_HIGH>; enable-active-high; regulator-always-on; + vin-supply = <®_vsys>; }; touch0_fixed_3v3: regulator-5 { compatible = "regulator-fixed"; - regulator-name = "touch_3v3"; + regulator-name = "vio33_tp1"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&pio 119 GPIO_ACTIVE_HIGH>; enable-active-high; + vin-supply = <®_vsys>; }; usb_hub_fixed_3v3: regulator-6 { compatible = "regulator-fixed"; - regulator-name = "usb_hub_3v3"; + regulator-name = "vhub_3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&pio 112 GPIO_ACTIVE_HIGH>; /* HUB_3V3_EN */ startup-delay-us = <10000>; enable-active-high; + vin-supply = <®_vsys>; }; - usb_hub_reset_1v8: regulator-7 { - compatible = "regulator-fixed"; - regulator-name = "usb_hub_reset"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - gpio = <&pio 7 GPIO_ACTIVE_HIGH>; /* HUB_RESET */ - vin-supply = <&usb_hub_fixed_3v3>; - }; - - usb_p0_vbus: regulator-8 { + usb_p0_vbus: regulator-7 { compatible = "regulator-fixed"; - regulator-name = "usb_p0_vbus"; + regulator-name = "vbus_p0"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&pio 84 GPIO_ACTIVE_HIGH>; enable-active-high; + vin-supply = <®_vsys>; }; - usb_p1_vbus: regulator-9 { + usb_p1_vbus: regulator-8 { compatible = "regulator-fixed"; - regulator-name = "usb_p1_vbus"; + regulator-name = "vbus_p1"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; gpio = <&pio 87 GPIO_ACTIVE_HIGH>; enable-active-high; + vin-supply = <®_vsys>; }; - usb_p2_vbus: regulator-10 { + /* used by ssusb2 */ + usb_p2_vbus: regulator-9 { compatible = "regulator-fixed"; - regulator-name = "usb_p2_vbus"; + regulator-name = "wifi_3v3"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; enable-active-high; }; }; +&gpu { + mali-supply = <&mt6359_vproc2_buck_reg>; + status = "okay"; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; @@ -234,7 +259,6 @@ &i2c3 { &i2c4 { pinctrl-names = "default"; pinctrl-0 = <&i2c4_pins>; - pinctrl-1 = <&rt1715_int_pins>; clock-frequency = <1000000>; status = "okay"; }; @@ -253,6 +277,14 @@ &i2c6 { status = "okay"; }; +&mfg0 { + domain-supply = <&mt6359_vproc2_buck_reg>; +}; + +&mfg1 { + domain-supply = <&mt6359_vsram_others_ldo_reg>; +}; + &mmc0 { status = "okay"; pinctrl-names = "default", "state_uhs"; @@ -295,38 +327,65 @@ &mt6359_vbbck_ldo_reg { }; &mt6359_vcn18_ldo_reg { + regulator-name = "vcn18_pmu"; regulator-always-on; }; &mt6359_vcn33_2_bt_ldo_reg { + regulator-name = "vcn33_2_pmu"; regulator-always-on; }; &mt6359_vcore_buck_reg { + regulator-name = "dvdd_proc_l"; regulator-always-on; }; &mt6359_vgpu11_buck_reg { + regulator-name = "dvdd_core"; regulator-always-on; }; &mt6359_vpa_buck_reg { + regulator-name = "vpa_pmu"; regulator-max-microvolt = <3100000>; }; +&mt6359_vproc2_buck_reg { + /* The name "vgpu" is required by mtk-regulator-coupler */ + regulator-name = "vgpu"; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <800000>; + regulator-coupled-with = <&mt6359_vsram_others_ldo_reg>; + regulator-coupled-max-spread = <6250>; +}; + &mt6359_vpu_buck_reg { + regulator-name = "dvdd_adsp"; regulator-always-on; }; &mt6359_vrf12_ldo_reg { + regulator-name = "va12_abb2_pmu"; regulator-always-on; }; &mt6359_vsim1_ldo_reg { + regulator-name = "vsim1_pmu"; regulator-enable-ramp-delay = <480>; }; +&mt6359_vsram_others_ldo_reg { + /* The name "vsram_gpu" is required by mtk-regulator-coupler */ + regulator-name = "vsram_gpu"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <800000>; + regulator-coupled-with = <&mt6359_vproc2_buck_reg>; + regulator-coupled-max-spread = <6250>; +}; + &mt6359_vufs_ldo_reg { + regulator-name = "vufs18_pmu"; regulator-always-on; }; @@ -335,6 +394,16 @@ &mt6359codec { mediatek,mic-type-1 = <3>; /* DCC */ }; +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins_default>; + status = "okay"; +}; + +&pciephy { + status = "okay"; +}; + &pio { audio_default_pins: audio-default-pins { pins-cmd-dat { @@ -700,6 +769,15 @@ pins-rst { }; }; + pcie_pins_default: pcie-default { + mux { + pinmux = , + , + ; + bias-pull-up; + }; + }; + rt1715_int_pins: rt1715-int-pins { pins_cmd0_dat { pinmux = ; @@ -814,9 +892,39 @@ pins-wifi-enable { }; }; +ð { + phy-mode ="rgmii-id"; + phy-handle = <ðernet_phy0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <ð_default_pins>; + pinctrl-1 = <ð_sleep_pins>; + mediatek,mac-wol; + snps,reset-gpio = <&pio 147 GPIO_ACTIVE_HIGH>; + snps,reset-delays-us = <0 10000 10000>; + status = "okay"; +}; + +ð_mdio { + ethernet_phy0: ethernet-phy@1 { + compatible = "ethernet-phy-id001c.c916"; + reg = <0x1>; + }; +}; + &pmic { interrupt-parent = <&pio>; interrupts = <222 IRQ_TYPE_LEVEL_HIGH>; + + mt6359keys: keys { + compatible = "mediatek,mt6359-keys"; + mediatek,long-press-mode = <1>; + power-off-time-sec = <0>; + + power-key { + linux,keycodes = ; + wakeup-source; + }; + }; }; &scp { @@ -824,6 +932,15 @@ &scp { status = "okay"; }; +&spi2 { + pinctrl-0 = <&spi2_pins>; + pinctrl-names = "default"; + mediatek,pad-select = <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; +}; + &uart0 { pinctrl-0 = <&uart0_pins>; pinctrl-names = "default"; @@ -842,15 +959,6 @@ &uart2 { status = "okay"; }; -&spi2 { - pinctrl-0 = <&spi2_pins>; - pinctrl-names = "default"; - mediatek,pad-select = <0>; - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; -}; - &u3phy0 { status = "okay"; }; @@ -871,10 +979,28 @@ &xhci0 { &xhci1 { status = "okay"; vusb33-supply = <&mt6359_vusb_ldo_reg>; - vbus-supply = <&usb_hub_reset_1v8>; + #address-cells = <1>; + #size-cells = <0>; + + hub_2_0: hub@1 { + compatible = "usb451,8025"; + reg = <1>; + peer-hub = <&hub_3_0>; + reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>; + vdd-supply = <&usb_hub_fixed_3v3>; + }; + + hub_3_0: hub@2 { + compatible = "usb451,8027"; + reg = <2>; + peer-hub = <&hub_2_0>; + reset-gpios = <&pio 7 GPIO_ACTIVE_HIGH>; + vdd-supply = <&usb_hub_fixed_3v3>; + }; }; &xhci2 { status = "okay"; vusb33-supply = <&mt6359_vusb_ldo_reg>; + vbus-supply = <&sdio_fixed_3v3>; /* wifi_3v3 */ }; diff --git a/arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts b/arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts index 1ef6262b65c9ac..5f16fb82058056 100644 --- a/arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts +++ b/arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts @@ -187,13 +187,18 @@ mdio { compatible = "snps,dwmac-mdio"; #address-cells = <1>; #size-cells = <0>; - eth_phy0: eth-phy0@1 { + eth_phy0: ethernet-phy@1 { compatible = "ethernet-phy-id001c.c916"; reg = <0x1>; }; }; }; +&gpu { + mali-supply = <&mt6315_7_vbuck1>; + status = "okay"; +}; + &i2c0 { clock-frequency = <400000>; pinctrl-0 = <&i2c0_pins>; @@ -337,6 +342,10 @@ &mfg0 { domain-supply = <&mt6315_7_vbuck1>; }; +&mfg1 { + domain-supply = <&mt6359_vsram_others_ldo_reg>; +}; + &mmc0 { status = "okay"; pinctrl-names = "default", "state_uhs"; @@ -407,6 +416,12 @@ &mt6359_vrf12_ldo_reg { regulator-always-on; }; +/* for GPU SRAM */ +&mt6359_vsram_others_ldo_reg { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; +}; + &mt6359codec { mediatek,mic-type-0 = <1>; /* ACC */ mediatek,mic-type-1 = <3>; /* DCC */ @@ -839,8 +854,8 @@ regulators { mt6315_7_vbuck1: vbuck1 { regulator-compatible = "vbuck1"; regulator-name = "Vgpu"; - regulator-min-microvolt = <300000>; - regulator-max-microvolt = <1193750>; + regulator-min-microvolt = <546000>; + regulator-max-microvolt = <787000>; regulator-enable-ramp-delay = <256>; regulator-allowed-modes = <0 1 2>; }; diff --git a/arch/arm64/boot/dts/nvidia/Makefile b/arch/arm64/boot/dts/nvidia/Makefile index c38c809fe57710..0fbb8a494dba50 100644 --- a/arch/arm64/boot/dts/nvidia/Makefile +++ b/arch/arm64/boot/dts/nvidia/Makefile @@ -27,6 +27,7 @@ dtb-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra194-p3509-0000+p3668-0000.dtb dtb-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra194-p3509-0000+p3668-0001.dtb dtb-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra234-sim-vdk.dtb dtb-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra234-p3737-0000+p3701-0000.dtb +dtb-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra234-p3737-0000+p3701-0008.dtb dtb-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra234-p3740-0002+p3701-0008.dtb dtb-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra234-p3768-0000+p3767-0000.dtb dtb-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra234-p3768-0000+p3767-0005.dtb diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi index c00db75e391057..1c53ccc5e3cbf3 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi @@ -351,7 +351,7 @@ mmc@700b0200 { #size-cells = <0>; wifi@1 { - compatible = "brcm,bcm4354-fmac"; + compatible = "brcm,bcm4354-fmac", "brcm,bcm4329-fmac"; reg = <1>; interrupt-parent = <&gpio>; interrupts = ; diff --git a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts index 2e5b6b2c1f56ba..5aa6afd56cbc63 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts +++ b/arch/arm64/boot/dts/nvidia/tegra210-smaug.dts @@ -1362,6 +1362,19 @@ bluetooth { }; }; + i2c@7000c000 { + status = "okay"; + clock-frequency = <1000000>; + + touchscreen: i2c-hid-dev@20 { + compatible = "hid-over-i2c"; + reg = <0x20>; + hid-descr-addr = <0x0020>; + interrupt-parent = <&gpio>; + interrupts = ; + }; + }; + i2c@7000c400 { status = "okay"; clock-frequency = <1000000>; @@ -1385,6 +1398,11 @@ battery: bq27742@55 { reg = <0x55>; }; }; + + usbc_extcon0: extcon0 { + compatible = "google,extcon-usbc-cros-ec"; + google,usb-port-id = <0>; + }; }; }; @@ -1719,6 +1737,15 @@ audio-codec@2d { #gpio-cells = <2>; status = "okay"; }; + + tmp451: temperature-sensor@4c { + compatible = "ti,tmp451"; + reg = <0x4c>; + interrupt-parent = <&gpio>; + interrupts = ; + vcc-supply = <&pp1800>; + #thermal-sensor-cells = <1>; + }; }; pmc@7000e400 { diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi index 882b1d1f4ada8d..942e3a0f81ed76 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi @@ -1218,6 +1218,8 @@ mmc@700b0000 { nvidia,pad-autocal-pull-down-offset-3v3 = <0x7d>; nvidia,pad-autocal-pull-up-offset-1v8 = <0x7b>; nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>; + nvidia,pad-autocal-pull-up-offset-sdr104 = <0x0>; + nvidia,pad-autocal-pull-down-offset-sdr104 = <0x0>; nvidia,default-tap = <0x2>; nvidia,default-trim = <0x4>; assigned-clocks = <&tegra_car TEGRA210_CLK_SDMMC4>, diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts index 90f12277aede8b..4c0e96f9d4938e 100644 --- a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts +++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0000.dts @@ -1,551 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 /dts-v1/; -#include -#include -#include - +// Module files must be included first #include "tegra234-p3701-0000.dtsi" +#include "tegra234-p3737-0000+p3701.dtsi" / { model = "NVIDIA Jetson AGX Orin Developer Kit"; compatible = "nvidia,p3737-0000+p3701-0000", "nvidia,p3701-0000", "nvidia,tegra234"; - - aliases { - serial0 = &tcu; - serial1 = &uarta; - }; - - chosen { - bootargs = "console=ttyTCU0,115200n8"; - stdout-path = "serial0:115200n8"; - }; - - bus@0 { - aconnect@2900000 { - ahub@2900800 { - i2s@2901000 { - ports { - port@1 { - endpoint { - dai-format = "i2s"; - remote-endpoint = <&rt5640_ep>; - }; - }; - }; - }; - }; - }; - - serial@3100000 { - compatible = "nvidia,tegra194-hsuart"; - reset-names = "serial"; - status = "okay"; - }; - - i2c@3160000 { - status = "okay"; - - eeprom@56 { - compatible = "atmel,24c02"; - reg = <0x56>; - - label = "system"; - vcc-supply = <&vdd_1v8_sys>; - address-width = <8>; - pagesize = <8>; - size = <256>; - read-only; - }; - }; - - serial@31d0000 { - current-speed = <115200>; - status = "okay"; - }; - - i2c@31e0000 { - status = "okay"; - - audio-codec@1c { - compatible = "realtek,rt5640"; - reg = <0x1c>; - interrupt-parent = <&gpio>; - interrupts = ; - clocks = <&bpmp TEGRA234_CLK_AUD_MCLK>; - clock-names = "mclk"; - realtek,dmic1-data-pin = ; - realtek,dmic2-data-pin = ; - realtek,jack-detect-source = ; - sound-name-prefix = "CVB-RT"; - - port { - rt5640_ep: endpoint { - remote-endpoint = <&i2s1_dap>; - mclk-fs = <256>; - }; - }; - }; - }; - - pwm@3280000 { - status = "okay"; - }; - - pwm@32a0000 { - assigned-clocks = <&bpmp TEGRA234_CLK_PWM3>; - assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLP_OUT0>; - status = "okay"; - }; - - pwm@32c0000 { - status = "okay"; - }; - - pwm@32f0000 { - status = "okay"; - }; - - mmc@3400000 { - status = "okay"; - bus-width = <4>; - cd-gpios = <&gpio TEGRA234_MAIN_GPIO(G, 7) GPIO_ACTIVE_LOW>; - disable-wp; - }; - - hda@3510000 { - nvidia,model = "NVIDIA Jetson AGX Orin HDA"; - status = "okay"; - }; - - padctl@3520000 { - status = "okay"; - - pads { - usb2 { - lanes { - usb2-0 { - status = "okay"; - }; - - usb2-1 { - status = "okay"; - }; - - usb2-2 { - status = "okay"; - }; - - usb2-3 { - status = "okay"; - }; - }; - }; - - usb3 { - lanes { - usb3-0 { - status = "okay"; - }; - - usb3-1 { - status = "okay"; - }; - - usb3-2 { - status = "okay"; - }; - }; - }; - }; - - ports { - usb2-0 { - mode = "otg"; - usb-role-switch; - status = "okay"; - - port { - hs_typec_p1: endpoint { - remote-endpoint = <&hs_ucsi_ccg_p1>; - }; - }; - }; - - usb2-1 { - mode = "host"; - status = "okay"; - - port { - hs_typec_p0: endpoint { - remote-endpoint = <&hs_ucsi_ccg_p0>; - }; - }; - }; - - usb2-2 { - mode = "host"; - status = "okay"; - }; - - usb2-3 { - mode = "host"; - status = "okay"; - }; - - usb3-0 { - nvidia,usb2-companion = <1>; - status = "okay"; - - port { - ss_typec_p0: endpoint { - remote-endpoint = <&ss_ucsi_ccg_p0>; - }; - }; - }; - - usb3-1 { - nvidia,usb2-companion = <0>; - status = "okay"; - - port { - ss_typec_p1: endpoint { - remote-endpoint = <&ss_ucsi_ccg_p1>; - }; - }; - }; - - usb3-2 { - nvidia,usb2-companion = <3>; - status = "okay"; - }; - }; - }; - - usb@3550000 { - status = "okay"; - - phys = <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-0}>, - <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-1}>; - phy-names = "usb2-0", "usb3-0"; - }; - - usb@3610000 { - status = "okay"; - - phys = <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-0}>, - <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-1}>, - <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-2}>, - <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-3}>, - <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-0}>, - <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-1}>, - <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-2}>; - phy-names = "usb2-0", "usb2-1", "usb2-2", "usb2-3", - "usb3-0", "usb3-1", "usb3-2"; - }; - - ethernet@6800000 { - status = "okay"; - - phy-handle = <&mgbe0_phy>; - phy-mode = "10gbase-r"; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - - mgbe0_phy: phy@0 { - compatible = "ethernet-phy-ieee802.3-c45"; - reg = <0x0>; - - #phy-cells = <0>; - }; - }; - }; - - i2c@c240000 { - status = "okay"; - - typec@8 { - compatible = "cypress,cypd4226"; - reg = <0x08>; - interrupt-parent = <&gpio>; - interrupts = ; - firmware-name = "nvidia,jetson-agx-xavier"; - status = "okay"; - - #address-cells = <1>; - #size-cells = <0>; - - ccg_typec_con0: connector@0 { - compatible = "usb-c-connector"; - reg = <0>; - label = "USB-C"; - data-role = "host"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - hs_ucsi_ccg_p0: endpoint { - remote-endpoint = <&hs_typec_p0>; - }; - }; - - port@1 { - reg = <1>; - - ss_ucsi_ccg_p0: endpoint { - remote-endpoint = <&ss_typec_p0>; - }; - }; - }; - }; - - ccg_typec_con1: connector@1 { - compatible = "usb-c-connector"; - reg = <1>; - label = "USB-C"; - data-role = "dual"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - - hs_ucsi_ccg_p1: endpoint { - remote-endpoint = <&hs_typec_p1>; - }; - }; - - port@1 { - reg = <1>; - - ss_ucsi_ccg_p1: endpoint { - remote-endpoint = <&ss_typec_p1>; - }; - }; - }; - }; - }; - }; - - pcie@14100000 { - status = "okay"; - - vddio-pex-ctl-supply = <&vdd_1v8_ao>; - - phys = <&p2u_hsio_3>; - phy-names = "p2u-0"; - }; - - pcie@14160000 { - status = "okay"; - - vddio-pex-ctl-supply = <&vdd_1v8_ao>; - - phys = <&p2u_hsio_4>, <&p2u_hsio_5>, <&p2u_hsio_6>, - <&p2u_hsio_7>; - phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3"; - }; - - pcie@141a0000 { - status = "okay"; - - vddio-pex-ctl-supply = <&vdd_1v8_ls>; - vpcie3v3-supply = <&vdd_3v3_pcie>; - vpcie12v-supply = <&vdd_12v_pcie>; - - phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>, - <&p2u_nvhs_3>, <&p2u_nvhs_4>, <&p2u_nvhs_5>, - <&p2u_nvhs_6>, <&p2u_nvhs_7>; - phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3", "p2u-4", - "p2u-5", "p2u-6", "p2u-7"; - }; - - pcie-ep@141a0000 { - status = "disabled"; - - vddio-pex-ctl-supply = <&vdd_1v8_ls>; - - reset-gpios = <&gpio TEGRA234_MAIN_GPIO(AF, 1) GPIO_ACTIVE_LOW>; - - nvidia,refclk-select-gpios = <&gpio_aon - TEGRA234_AON_GPIO(AA, 4) - GPIO_ACTIVE_HIGH>; - - phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>, - <&p2u_nvhs_3>, <&p2u_nvhs_4>, <&p2u_nvhs_5>, - <&p2u_nvhs_6>, <&p2u_nvhs_7>; - phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3", "p2u-4", - "p2u-5", "p2u-6", "p2u-7"; - }; - }; - - gpio-keys { - compatible = "gpio-keys"; - status = "okay"; - - key-force-recovery { - label = "Force Recovery"; - gpios = <&gpio TEGRA234_MAIN_GPIO(G, 0) GPIO_ACTIVE_LOW>; - linux,input-type = ; - linux,code = ; - }; - - key-power { - label = "Power"; - gpios = <&gpio_aon TEGRA234_AON_GPIO(EE, 4) GPIO_ACTIVE_LOW>; - linux,input-type = ; - linux,code = ; - wakeup-event-action = ; - wakeup-source; - }; - - key-suspend { - label = "Suspend"; - gpios = <&gpio TEGRA234_MAIN_GPIO(G, 2) GPIO_ACTIVE_LOW>; - linux,input-type = ; - linux,code = ; - }; - }; - - fan: pwm-fan { - compatible = "pwm-fan"; - cooling-levels = <66 215 255>; - pwms = <&pwm3 0 45334>; - #cooling-cells = <2>; - }; - - serial { - status = "okay"; - }; - - sound { - compatible = "nvidia,tegra186-audio-graph-card"; - status = "okay"; - - dais = /* ADMAIF (FE) Ports */ - <&admaif0_port>, <&admaif1_port>, <&admaif2_port>, <&admaif3_port>, - <&admaif4_port>, <&admaif5_port>, <&admaif6_port>, <&admaif7_port>, - <&admaif8_port>, <&admaif9_port>, <&admaif10_port>, <&admaif11_port>, - <&admaif12_port>, <&admaif13_port>, <&admaif14_port>, <&admaif15_port>, - <&admaif16_port>, <&admaif17_port>, <&admaif18_port>, <&admaif19_port>, - /* XBAR Ports */ - <&xbar_i2s1_port>, <&xbar_i2s2_port>, <&xbar_i2s4_port>, - <&xbar_i2s6_port>, <&xbar_dmic3_port>, - <&xbar_sfc1_in_port>, <&xbar_sfc2_in_port>, - <&xbar_sfc3_in_port>, <&xbar_sfc4_in_port>, - <&xbar_mvc1_in_port>, <&xbar_mvc2_in_port>, - <&xbar_amx1_in1_port>, <&xbar_amx1_in2_port>, - <&xbar_amx1_in3_port>, <&xbar_amx1_in4_port>, - <&xbar_amx2_in1_port>, <&xbar_amx2_in2_port>, - <&xbar_amx2_in3_port>, <&xbar_amx2_in4_port>, - <&xbar_amx3_in1_port>, <&xbar_amx3_in2_port>, - <&xbar_amx3_in3_port>, <&xbar_amx3_in4_port>, - <&xbar_amx4_in1_port>, <&xbar_amx4_in2_port>, - <&xbar_amx4_in3_port>, <&xbar_amx4_in4_port>, - <&xbar_adx1_in_port>, <&xbar_adx2_in_port>, - <&xbar_adx3_in_port>, <&xbar_adx4_in_port>, - <&xbar_mix_in1_port>, <&xbar_mix_in2_port>, - <&xbar_mix_in3_port>, <&xbar_mix_in4_port>, - <&xbar_mix_in5_port>, <&xbar_mix_in6_port>, - <&xbar_mix_in7_port>, <&xbar_mix_in8_port>, - <&xbar_mix_in9_port>, <&xbar_mix_in10_port>, - <&xbar_asrc_in1_port>, <&xbar_asrc_in2_port>, - <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>, - <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>, - <&xbar_asrc_in7_port>, - <&xbar_ope1_in_port>, - /* HW accelerators */ - <&sfc1_out_port>, <&sfc2_out_port>, - <&sfc3_out_port>, <&sfc4_out_port>, - <&mvc1_out_port>, <&mvc2_out_port>, - <&amx1_out_port>, <&amx2_out_port>, - <&amx3_out_port>, <&amx4_out_port>, - <&adx1_out1_port>, <&adx1_out2_port>, - <&adx1_out3_port>, <&adx1_out4_port>, - <&adx2_out1_port>, <&adx2_out2_port>, - <&adx2_out3_port>, <&adx2_out4_port>, - <&adx3_out1_port>, <&adx3_out2_port>, - <&adx3_out3_port>, <&adx3_out4_port>, - <&adx4_out1_port>, <&adx4_out2_port>, - <&adx4_out3_port>, <&adx4_out4_port>, - <&mix_out1_port>, <&mix_out2_port>, <&mix_out3_port>, - <&mix_out4_port>, <&mix_out5_port>, - <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>, - <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>, - <&ope1_out_port>, - /* BE I/O Ports */ - <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>, - <&dmic3_port>; - - label = "NVIDIA Jetson AGX Orin APE"; - - widgets = "Microphone", "CVB-RT MIC Jack", - "Microphone", "CVB-RT MIC", - "Headphone", "CVB-RT HP Jack", - "Speaker", "CVB-RT SPK"; - - routing = /* I2S1 <-> RT5640 */ - "CVB-RT AIF1 Playback", "I2S1 DAP-Playback", - "I2S1 DAP-Capture", "CVB-RT AIF1 Capture", - /* RT5640 codec controls */ - "CVB-RT HP Jack", "CVB-RT HPOL", - "CVB-RT HP Jack", "CVB-RT HPOR", - "CVB-RT IN1P", "CVB-RT MIC Jack", - "CVB-RT IN2P", "CVB-RT MIC Jack", - "CVB-RT SPK", "CVB-RT SPOLP", - "CVB-RT SPK", "CVB-RT SPORP", - "CVB-RT DMIC1", "CVB-RT MIC", - "CVB-RT DMIC2", "CVB-RT MIC"; - }; - - thermal-zones { - tj-thermal { - cooling-maps { - map-active-0 { - cooling-device = <&fan 0 1>; - trip = <&tj_trip_active0>; - }; - - map-active-1 { - cooling-device = <&fan 1 2>; - trip = <&tj_trip_active1>; - }; - }; - }; - }; - - vdd_1v8_sys: regulator-vdd-1v8-sys { - compatible = "regulator-fixed"; - regulator-name = "VDD_1V8_SYS"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-always-on; - }; - - vdd_3v3_pcie: regulator-vdd-3v3-pcie { - compatible = "regulator-fixed"; - regulator-name = "VDD_3V3_PCIE"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - gpio = <&gpio TEGRA234_MAIN_GPIO(H, 4) GPIO_ACTIVE_HIGH>; - regulator-boot-on; - enable-active-high; - }; - - vdd_12v_pcie: regulator-vdd-12v-pcie { - compatible = "regulator-fixed"; - regulator-name = "VDD_12V_PCIE"; - regulator-min-microvolt = <12000000>; - regulator-max-microvolt = <12000000>; - gpio = <&gpio TEGRA234_MAIN_GPIO(A, 1) GPIO_ACTIVE_LOW>; - regulator-boot-on; - }; }; diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0008.dts b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0008.dts new file mode 100644 index 00000000000000..979f085691a1ce --- /dev/null +++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701-0008.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; + +// Module files must be included first +#include "tegra234-p3701-0008.dtsi" +#include "tegra234-p3737-0000+p3701.dtsi" + +/ { + model = "NVIDIA Jetson AGX Orin Developer Kit"; + compatible = "nvidia,p3737-0000+p3701-0008", "nvidia,p3701-0008", "nvidia,tegra234"; +}; diff --git a/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701.dtsi b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701.dtsi new file mode 100644 index 00000000000000..f6cad29355e67a --- /dev/null +++ b/arch/arm64/boot/dts/nvidia/tegra234-p3737-0000+p3701.dtsi @@ -0,0 +1,547 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include + +/ { + aliases { + serial0 = &tcu; + serial1 = &uarta; + }; + + chosen { + bootargs = "console=ttyTCU0,115200n8"; + stdout-path = "serial0:115200n8"; + }; + + bus@0 { + aconnect@2900000 { + ahub@2900800 { + i2s@2901000 { + ports { + port@1 { + endpoint { + dai-format = "i2s"; + remote-endpoint = <&rt5640_ep>; + }; + }; + }; + }; + }; + }; + + serial@3100000 { + compatible = "nvidia,tegra194-hsuart"; + reset-names = "serial"; + status = "okay"; + }; + + i2c@3160000 { + status = "okay"; + + eeprom@56 { + compatible = "atmel,24c02"; + reg = <0x56>; + + label = "system"; + vcc-supply = <&vdd_1v8_sys>; + address-width = <8>; + pagesize = <8>; + size = <256>; + read-only; + }; + }; + + serial@31d0000 { + current-speed = <115200>; + status = "okay"; + }; + + i2c@31e0000 { + status = "okay"; + + audio-codec@1c { + compatible = "realtek,rt5640"; + reg = <0x1c>; + interrupt-parent = <&gpio>; + interrupts = ; + clocks = <&bpmp TEGRA234_CLK_AUD_MCLK>; + clock-names = "mclk"; + realtek,dmic1-data-pin = ; + realtek,dmic2-data-pin = ; + realtek,jack-detect-source = ; + sound-name-prefix = "CVB-RT"; + + port { + rt5640_ep: endpoint { + remote-endpoint = <&i2s1_dap>; + mclk-fs = <256>; + }; + }; + }; + }; + + pwm@3280000 { + status = "okay"; + }; + + pwm@32a0000 { + assigned-clocks = <&bpmp TEGRA234_CLK_PWM3>; + assigned-clock-parents = <&bpmp TEGRA234_CLK_PLLP_OUT0>; + status = "okay"; + }; + + pwm@32c0000 { + status = "okay"; + }; + + pwm@32f0000 { + status = "okay"; + }; + + mmc@3400000 { + status = "okay"; + bus-width = <4>; + cd-gpios = <&gpio TEGRA234_MAIN_GPIO(G, 7) GPIO_ACTIVE_LOW>; + disable-wp; + }; + + hda@3510000 { + nvidia,model = "NVIDIA Jetson AGX Orin HDA"; + status = "okay"; + }; + + padctl@3520000 { + status = "okay"; + + pads { + usb2 { + lanes { + usb2-0 { + status = "okay"; + }; + + usb2-1 { + status = "okay"; + }; + + usb2-2 { + status = "okay"; + }; + + usb2-3 { + status = "okay"; + }; + }; + }; + + usb3 { + lanes { + usb3-0 { + status = "okay"; + }; + + usb3-1 { + status = "okay"; + }; + + usb3-2 { + status = "okay"; + }; + }; + }; + }; + + ports { + usb2-0 { + mode = "otg"; + usb-role-switch; + status = "okay"; + + port { + hs_typec_p1: endpoint { + remote-endpoint = <&hs_ucsi_ccg_p1>; + }; + }; + }; + + usb2-1 { + mode = "host"; + status = "okay"; + + port { + hs_typec_p0: endpoint { + remote-endpoint = <&hs_ucsi_ccg_p0>; + }; + }; + }; + + usb2-2 { + mode = "host"; + status = "okay"; + }; + + usb2-3 { + mode = "host"; + status = "okay"; + }; + + usb3-0 { + nvidia,usb2-companion = <1>; + status = "okay"; + + port { + ss_typec_p0: endpoint { + remote-endpoint = <&ss_ucsi_ccg_p0>; + }; + }; + }; + + usb3-1 { + nvidia,usb2-companion = <0>; + status = "okay"; + + port { + ss_typec_p1: endpoint { + remote-endpoint = <&ss_ucsi_ccg_p1>; + }; + }; + }; + + usb3-2 { + nvidia,usb2-companion = <3>; + status = "okay"; + }; + }; + }; + + usb@3550000 { + status = "okay"; + + phys = <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-0}>, + <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-1}>; + phy-names = "usb2-0", "usb3-0"; + }; + + usb@3610000 { + status = "okay"; + + phys = <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-0}>, + <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-1}>, + <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-2}>, + <&{/bus@0/padctl@3520000/pads/usb2/lanes/usb2-3}>, + <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-0}>, + <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-1}>, + <&{/bus@0/padctl@3520000/pads/usb3/lanes/usb3-2}>; + phy-names = "usb2-0", "usb2-1", "usb2-2", "usb2-3", + "usb3-0", "usb3-1", "usb3-2"; + }; + + ethernet@6800000 { + status = "okay"; + + phy-handle = <&mgbe0_phy>; + phy-mode = "10gbase-r"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + mgbe0_phy: phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0x0>; + + #phy-cells = <0>; + }; + }; + }; + + i2c@c240000 { + status = "okay"; + + typec@8 { + compatible = "cypress,cypd4226"; + reg = <0x08>; + interrupt-parent = <&gpio>; + interrupts = ; + firmware-name = "nvidia,jetson-agx-xavier"; + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + + ccg_typec_con0: connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + label = "USB-C"; + data-role = "host"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + hs_ucsi_ccg_p0: endpoint { + remote-endpoint = <&hs_typec_p0>; + }; + }; + + port@1 { + reg = <1>; + + ss_ucsi_ccg_p0: endpoint { + remote-endpoint = <&ss_typec_p0>; + }; + }; + }; + }; + + ccg_typec_con1: connector@1 { + compatible = "usb-c-connector"; + reg = <1>; + label = "USB-C"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + hs_ucsi_ccg_p1: endpoint { + remote-endpoint = <&hs_typec_p1>; + }; + }; + + port@1 { + reg = <1>; + + ss_ucsi_ccg_p1: endpoint { + remote-endpoint = <&ss_typec_p1>; + }; + }; + }; + }; + }; + }; + + pcie@14100000 { + status = "okay"; + + vddio-pex-ctl-supply = <&vdd_1v8_ao>; + + phys = <&p2u_hsio_3>; + phy-names = "p2u-0"; + }; + + pcie@14160000 { + status = "okay"; + + vddio-pex-ctl-supply = <&vdd_1v8_ao>; + + phys = <&p2u_hsio_4>, <&p2u_hsio_5>, <&p2u_hsio_6>, + <&p2u_hsio_7>; + phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3"; + }; + + pcie@141a0000 { + status = "okay"; + + vddio-pex-ctl-supply = <&vdd_1v8_ls>; + vpcie3v3-supply = <&vdd_3v3_pcie>; + vpcie12v-supply = <&vdd_12v_pcie>; + + phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>, + <&p2u_nvhs_3>, <&p2u_nvhs_4>, <&p2u_nvhs_5>, + <&p2u_nvhs_6>, <&p2u_nvhs_7>; + phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3", "p2u-4", + "p2u-5", "p2u-6", "p2u-7"; + }; + + pcie-ep@141a0000 { + status = "disabled"; + + vddio-pex-ctl-supply = <&vdd_1v8_ls>; + + reset-gpios = <&gpio TEGRA234_MAIN_GPIO(AF, 1) GPIO_ACTIVE_LOW>; + + nvidia,refclk-select-gpios = <&gpio_aon + TEGRA234_AON_GPIO(AA, 4) + GPIO_ACTIVE_HIGH>; + + phys = <&p2u_nvhs_0>, <&p2u_nvhs_1>, <&p2u_nvhs_2>, + <&p2u_nvhs_3>, <&p2u_nvhs_4>, <&p2u_nvhs_5>, + <&p2u_nvhs_6>, <&p2u_nvhs_7>; + phy-names = "p2u-0", "p2u-1", "p2u-2", "p2u-3", "p2u-4", + "p2u-5", "p2u-6", "p2u-7"; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + status = "okay"; + + key-force-recovery { + label = "Force Recovery"; + gpios = <&gpio TEGRA234_MAIN_GPIO(G, 0) GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + }; + + key-power { + label = "Power"; + gpios = <&gpio_aon TEGRA234_AON_GPIO(EE, 4) GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + wakeup-event-action = ; + wakeup-source; + }; + + key-suspend { + label = "Suspend"; + gpios = <&gpio TEGRA234_MAIN_GPIO(G, 2) GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + }; + }; + + fan: pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <66 215 255>; + pwms = <&pwm3 0 45334>; + #cooling-cells = <2>; + }; + + serial { + status = "okay"; + }; + + sound { + compatible = "nvidia,tegra186-audio-graph-card"; + status = "okay"; + + dais = /* ADMAIF (FE) Ports */ + <&admaif0_port>, <&admaif1_port>, <&admaif2_port>, <&admaif3_port>, + <&admaif4_port>, <&admaif5_port>, <&admaif6_port>, <&admaif7_port>, + <&admaif8_port>, <&admaif9_port>, <&admaif10_port>, <&admaif11_port>, + <&admaif12_port>, <&admaif13_port>, <&admaif14_port>, <&admaif15_port>, + <&admaif16_port>, <&admaif17_port>, <&admaif18_port>, <&admaif19_port>, + /* XBAR Ports */ + <&xbar_i2s1_port>, <&xbar_i2s2_port>, <&xbar_i2s4_port>, + <&xbar_i2s6_port>, <&xbar_dmic3_port>, + <&xbar_sfc1_in_port>, <&xbar_sfc2_in_port>, + <&xbar_sfc3_in_port>, <&xbar_sfc4_in_port>, + <&xbar_mvc1_in_port>, <&xbar_mvc2_in_port>, + <&xbar_amx1_in1_port>, <&xbar_amx1_in2_port>, + <&xbar_amx1_in3_port>, <&xbar_amx1_in4_port>, + <&xbar_amx2_in1_port>, <&xbar_amx2_in2_port>, + <&xbar_amx2_in3_port>, <&xbar_amx2_in4_port>, + <&xbar_amx3_in1_port>, <&xbar_amx3_in2_port>, + <&xbar_amx3_in3_port>, <&xbar_amx3_in4_port>, + <&xbar_amx4_in1_port>, <&xbar_amx4_in2_port>, + <&xbar_amx4_in3_port>, <&xbar_amx4_in4_port>, + <&xbar_adx1_in_port>, <&xbar_adx2_in_port>, + <&xbar_adx3_in_port>, <&xbar_adx4_in_port>, + <&xbar_mix_in1_port>, <&xbar_mix_in2_port>, + <&xbar_mix_in3_port>, <&xbar_mix_in4_port>, + <&xbar_mix_in5_port>, <&xbar_mix_in6_port>, + <&xbar_mix_in7_port>, <&xbar_mix_in8_port>, + <&xbar_mix_in9_port>, <&xbar_mix_in10_port>, + <&xbar_asrc_in1_port>, <&xbar_asrc_in2_port>, + <&xbar_asrc_in3_port>, <&xbar_asrc_in4_port>, + <&xbar_asrc_in5_port>, <&xbar_asrc_in6_port>, + <&xbar_asrc_in7_port>, + <&xbar_ope1_in_port>, + /* HW accelerators */ + <&sfc1_out_port>, <&sfc2_out_port>, + <&sfc3_out_port>, <&sfc4_out_port>, + <&mvc1_out_port>, <&mvc2_out_port>, + <&amx1_out_port>, <&amx2_out_port>, + <&amx3_out_port>, <&amx4_out_port>, + <&adx1_out1_port>, <&adx1_out2_port>, + <&adx1_out3_port>, <&adx1_out4_port>, + <&adx2_out1_port>, <&adx2_out2_port>, + <&adx2_out3_port>, <&adx2_out4_port>, + <&adx3_out1_port>, <&adx3_out2_port>, + <&adx3_out3_port>, <&adx3_out4_port>, + <&adx4_out1_port>, <&adx4_out2_port>, + <&adx4_out3_port>, <&adx4_out4_port>, + <&mix_out1_port>, <&mix_out2_port>, <&mix_out3_port>, + <&mix_out4_port>, <&mix_out5_port>, + <&asrc_out1_port>, <&asrc_out2_port>, <&asrc_out3_port>, + <&asrc_out4_port>, <&asrc_out5_port>, <&asrc_out6_port>, + <&ope1_out_port>, + /* BE I/O Ports */ + <&i2s1_port>, <&i2s2_port>, <&i2s4_port>, <&i2s6_port>, + <&dmic3_port>; + + label = "NVIDIA Jetson AGX Orin APE"; + + widgets = "Microphone", "CVB-RT MIC Jack", + "Microphone", "CVB-RT MIC", + "Headphone", "CVB-RT HP Jack", + "Speaker", "CVB-RT SPK"; + + routing = /* I2S1 <-> RT5640 */ + "CVB-RT AIF1 Playback", "I2S1 DAP-Playback", + "I2S1 DAP-Capture", "CVB-RT AIF1 Capture", + /* RT5640 codec controls */ + "CVB-RT HP Jack", "CVB-RT HPOL", + "CVB-RT HP Jack", "CVB-RT HPOR", + "CVB-RT IN1P", "CVB-RT MIC Jack", + "CVB-RT IN2P", "CVB-RT MIC Jack", + "CVB-RT SPK", "CVB-RT SPOLP", + "CVB-RT SPK", "CVB-RT SPORP", + "CVB-RT DMIC1", "CVB-RT MIC", + "CVB-RT DMIC2", "CVB-RT MIC"; + }; + + thermal-zones { + tj-thermal { + cooling-maps { + map-active-0 { + cooling-device = <&fan 0 1>; + trip = <&tj_trip_active0>; + }; + + map-active-1 { + cooling-device = <&fan 1 2>; + trip = <&tj_trip_active1>; + }; + }; + }; + }; + + vdd_1v8_sys: regulator-vdd-1v8-sys { + compatible = "regulator-fixed"; + regulator-name = "VDD_1V8_SYS"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vdd_3v3_pcie: regulator-vdd-3v3-pcie { + compatible = "regulator-fixed"; + regulator-name = "VDD_3V3_PCIE"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio TEGRA234_MAIN_GPIO(H, 4) GPIO_ACTIVE_HIGH>; + regulator-boot-on; + enable-active-high; + }; + + vdd_12v_pcie: regulator-vdd-12v-pcie { + compatible = "regulator-fixed"; + regulator-name = "VDD_12V_PCIE"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + gpio = <&gpio TEGRA234_MAIN_GPIO(A, 1) GPIO_ACTIVE_LOW>; + regulator-boot-on; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index ae002c7cf1268a..6ca8db4b8afe30 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -112,10 +112,15 @@ dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs8550-aim300-aiot.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcs9100-ride-r3.dtb dtb-$(CONFIG_ARCH_QCOM) += qdu1000-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb2210-rb1.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb4210-rb2.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb5165-rb5.dtb + +qrb5165-rb5-vision-mezzanine-dtbs := qrb5165-rb5.dtb qrb5165-rb5-vision-mezzanine.dtbo + dtb-$(CONFIG_ARCH_QCOM) += qrb5165-rb5-vision-mezzanine.dtb dtb-$(CONFIG_ARCH_QCOM) += qru1000-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += sa8155p-adp.dtb @@ -191,6 +196,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sc8180x-lenovo-flex-5g.dtb dtb-$(CONFIG_ARCH_QCOM) += sc8180x-primus.dtb dtb-$(CONFIG_ARCH_QCOM) += sc8280xp-crd.dtb dtb-$(CONFIG_ARCH_QCOM) += sc8280xp-lenovo-thinkpad-x13s.dtb +dtb-$(CONFIG_ARCH_QCOM) += sc8280xp-microsoft-arcata.dtb dtb-$(CONFIG_ARCH_QCOM) += sda660-inforce-ifc6560.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm450-lenovo-tbx605f.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm450-motorola-ali.dtb @@ -207,6 +213,9 @@ dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r1.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r2.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-cheza-r3.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-db845c.dtb + +sdm845-db845c-navigation-mezzanine-dtbs := sdm845-db845c.dtb sdm845-db845c-navigation-mezzanine.dtbo + dtb-$(CONFIG_ARCH_QCOM) += sdm845-db845c-navigation-mezzanine.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-lg-judyln.dtb dtb-$(CONFIG_ARCH_QCOM) += sdm845-lg-judyp.dtb @@ -235,6 +244,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm6375-sony-xperia-murray-pdx225.dtb dtb-$(CONFIG_ARCH_QCOM) += sm7125-xiaomi-curtana.dtb dtb-$(CONFIG_ARCH_QCOM) += sm7125-xiaomi-joyeuse.dtb dtb-$(CONFIG_ARCH_QCOM) += sm7225-fairphone-fp4.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm7325-nothing-spacewar.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8150-hdk.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8150-microsoft-surface-duo.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8150-mtp.dtb @@ -271,6 +281,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb dtb-$(CONFIG_ARCH_QCOM) += x1e78100-lenovo-thinkpad-t14s.dtb dtb-$(CONFIG_ARCH_QCOM) += x1e80100-asus-vivobook-s15.dtb dtb-$(CONFIG_ARCH_QCOM) += x1e80100-crd.dtb +dtb-$(CONFIG_ARCH_QCOM) += x1e80100-dell-xps13-9345.dtb dtb-$(CONFIG_ARCH_QCOM) += x1e80100-lenovo-yoga-slim7x.dtb dtb-$(CONFIG_ARCH_QCOM) += x1e80100-microsoft-romulus13.dtb dtb-$(CONFIG_ARCH_QCOM) += x1e80100-microsoft-romulus15.dtb diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 7e6e2c12197931..8914f2ef0bc47f 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -31,27 +31,27 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; operating-points-v2 = <&cpu_opp_table>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x1>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; operating-points-v2 = <&cpu_opp_table>; }; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x80000>; diff --git a/arch/arm64/boot/dts/qcom/ipq5332.dtsi b/arch/arm64/boot/dts/qcom/ipq5332.dtsi index 71328b22353114..d3c3e215a15cfc 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5332.dtsi @@ -31,47 +31,47 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; operating-points-v2 = <&cpu_opp_table>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x1>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; operating-points-v2 = <&cpu_opp_table>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x2>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; operating-points-v2 = <&cpu_opp_table>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x3>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; operating-points-v2 = <&cpu_opp_table>; }; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi index 8edd535a188f2d..dbf6716bcb59a0 100644 --- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi @@ -34,12 +34,12 @@ cpus: cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; clock-names = "cpu"; operating-points-v2 = <&cpu_opp_table>; @@ -47,12 +47,12 @@ CPU0: cpu@0 { #cooling-cells = <2>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; enable-method = "psci"; reg = <0x1>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; clock-names = "cpu"; operating-points-v2 = <&cpu_opp_table>; @@ -60,12 +60,12 @@ CPU1: cpu@1 { #cooling-cells = <2>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; enable-method = "psci"; reg = <0x2>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; clock-names = "cpu"; operating-points-v2 = <&cpu_opp_table>; @@ -73,12 +73,12 @@ CPU2: cpu@2 { #cooling-cells = <2>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; enable-method = "psci"; reg = <0x3>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; clock-names = "cpu"; operating-points-v2 = <&cpu_opp_table>; @@ -86,7 +86,7 @@ CPU3: cpu@3 { #cooling-cells = <2>; }; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; @@ -1015,10 +1015,10 @@ cpu_alert: cpu-passive { cooling-maps { map0 { trip = <&cpu_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi index 284a4553070faa..78e1992b749573 100644 --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi @@ -32,39 +32,39 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; enable-method = "psci"; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; enable-method = "psci"; reg = <0x1>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; enable-method = "psci"; reg = <0x2>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; enable-method = "psci"; reg = <0x3>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi index 08a82a5cf66758..d1fd35ebc4a28b 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi @@ -34,12 +34,12 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a73"; reg = <0x0>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; clock-names = "cpu"; operating-points-v2 = <&cpu_opp_table>; @@ -47,12 +47,12 @@ CPU0: cpu@0 { #cooling-cells = <2>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a73"; reg = <0x1>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; clock-names = "cpu"; operating-points-v2 = <&cpu_opp_table>; @@ -60,12 +60,12 @@ CPU1: cpu@1 { #cooling-cells = <2>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a73"; reg = <0x2>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; clock-names = "cpu"; operating-points-v2 = <&cpu_opp_table>; @@ -73,12 +73,12 @@ CPU2: cpu@2 { #cooling-cells = <2>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a73"; reg = <0x3>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; clock-names = "cpu"; operating-points-v2 = <&cpu_opp_table>; @@ -86,7 +86,7 @@ CPU3: cpu@3 { #cooling-cells = <2>; }; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; @@ -234,7 +234,7 @@ rng: rng@e3000 { }; mdio: mdio@90000 { - compatible = "qcom,ipq9574-mdio", "qcom,ipq4019-mdio"; + compatible = "qcom,ipq9574-mdio", "qcom,ipq4019-mdio"; reg = <0x00090000 0x64>; #address-cells = <1>; #size-cells = <0>; @@ -863,10 +863,10 @@ cpu0_alert: cpu-passive { cooling-maps { map0 { trip = <&cpu0_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -891,10 +891,10 @@ cpu1_alert: cpu-passive { cooling-maps { map0 { trip = <&cpu1_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -919,10 +919,10 @@ cpu2_alert: cpu-passive { cooling-maps { map0 { trip = <&cpu2_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -947,10 +947,10 @@ cpu3_alert: cpu-passive { cooling-maps { map0 { trip = <&cpu3_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt86518.dts b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt86518.dts index 3cfa80e38a9e3e..d6b03e08c34a39 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt86518.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt86518.dts @@ -57,7 +57,7 @@ &sound { widgets = "Speaker", "Speaker", "Headphone", "Headphones"; pin-switches = "Speaker", "Headphones"; - audio-routing = "Speaker", "Speaker Amp OUT", + audio-routing = "Speaker", "Speaker Amp OUT", "Speaker Amp IN", "HPH_R", "Headphones", "Headphones Switch OUTL", "Headphones", "Headphones Switch OUTR", diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 0ee44706b70ba3..5e558bcc9d8789 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -133,67 +133,67 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; enable-method = "psci"; clocks = <&apcs>; operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,acc = <&cpu0_acc>; qcom,saw = <&cpu0_saw>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x1>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; enable-method = "psci"; clocks = <&apcs>; operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; qcom,acc = <&cpu1_acc>; qcom,saw = <&cpu1_saw>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x2>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; enable-method = "psci"; clocks = <&apcs>; operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; qcom,acc = <&cpu2_acc>; qcom,saw = <&cpu2_saw>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x3>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; enable-method = "psci"; clocks = <&apcs>; operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; qcom,acc = <&cpu3_acc>; qcom,saw = <&cpu3_saw>; }; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; @@ -202,7 +202,7 @@ L2_0: l2-cache { idle-states { entry-method = "psci"; - CPU_SLEEP_0: cpu-sleep-0 { + cpu_sleep_0: cpu-sleep-0 { compatible = "arm,idle-state"; idle-state-name = "standalone-power-collapse"; arm,psci-suspend-param = <0x40000002>; @@ -215,7 +215,7 @@ CPU_SLEEP_0: cpu-sleep-0 { domain-idle-states { - CLUSTER_RET: cluster-retention { + cluster_ret: cluster-retention { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000012>; entry-latency-us = <500>; @@ -223,7 +223,7 @@ CLUSTER_RET: cluster-retention { min-residency-us = <2000>; }; - CLUSTER_PWRDN: cluster-gdhs { + cluster_pwrdn: cluster-gdhs { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000032>; entry-latency-us = <2000>; @@ -273,33 +273,33 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cluster { + cluster_pd: power-domain-cluster { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_RET>, <&CLUSTER_PWRDN>; + domain-idle-states = <&cluster_ret>, <&cluster_pwrdn>; }; }; @@ -823,7 +823,7 @@ debug0: debug@850000 { reg = <0x00850000 0x1000>; clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU0>; + cpu = <&cpu0>; status = "disabled"; }; @@ -832,7 +832,7 @@ debug1: debug@852000 { reg = <0x00852000 0x1000>; clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU1>; + cpu = <&cpu1>; status = "disabled"; }; @@ -841,7 +841,7 @@ debug2: debug@854000 { reg = <0x00854000 0x1000>; clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU2>; + cpu = <&cpu2>; status = "disabled"; }; @@ -850,7 +850,7 @@ debug3: debug@856000 { reg = <0x00856000 0x1000>; clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU3>; + cpu = <&cpu3>; status = "disabled"; }; @@ -864,7 +864,7 @@ cti12: cti@858000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU0>; + cpu = <&cpu0>; arm,cs-dev-assoc = <&etm0>; status = "disabled"; @@ -879,7 +879,7 @@ cti13: cti@859000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU1>; + cpu = <&cpu1>; arm,cs-dev-assoc = <&etm1>; status = "disabled"; @@ -894,7 +894,7 @@ cti14: cti@85a000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU2>; + cpu = <&cpu2>; arm,cs-dev-assoc = <&etm2>; status = "disabled"; @@ -909,7 +909,7 @@ cti15: cti@85b000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU3>; + cpu = <&cpu3>; arm,cs-dev-assoc = <&etm3>; status = "disabled"; @@ -923,7 +923,7 @@ etm0: etm@85c000 { clock-names = "apb_pclk", "atclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU0>; + cpu = <&cpu0>; status = "disabled"; @@ -944,7 +944,7 @@ etm1: etm@85d000 { clock-names = "apb_pclk", "atclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU1>; + cpu = <&cpu1>; status = "disabled"; @@ -965,7 +965,7 @@ etm2: etm@85e000 { clock-names = "apb_pclk", "atclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU2>; + cpu = <&cpu2>; status = "disabled"; @@ -986,7 +986,7 @@ etm3: etm@85f000 { clock-names = "apb_pclk", "atclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU3>; + cpu = <&cpu3>; status = "disabled"; @@ -2644,10 +2644,10 @@ cpu0_1_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu0_1_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2673,10 +2673,10 @@ cpu2_3_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu2_3_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8939.dtsi b/arch/arm64/boot/dts/qcom/msm8939.dtsi index 7af210789879af..7a6f1eeaa3fc43 100644 --- a/arch/arm64/boot/dts/qcom/msm8939.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8939.dtsi @@ -42,122 +42,122 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@100 { + cpu0: cpu@100 { compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "spin-table"; reg = <0x100>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; qcom,acc = <&acc0>; qcom,saw = <&saw0>; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; clocks = <&apcs1_mbox>; #cooling-cells = <2>; - L2_1: l2-cache { + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@101 { + cpu1: cpu@101 { compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "spin-table"; reg = <0x101>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; qcom,acc = <&acc1>; qcom,saw = <&saw1>; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; clocks = <&apcs1_mbox>; #cooling-cells = <2>; }; - CPU2: cpu@102 { + cpu2: cpu@102 { compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "spin-table"; reg = <0x102>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; qcom,acc = <&acc2>; qcom,saw = <&saw2>; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; clocks = <&apcs1_mbox>; #cooling-cells = <2>; }; - CPU3: cpu@103 { + cpu3: cpu@103 { compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "spin-table"; reg = <0x103>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; qcom,acc = <&acc3>; qcom,saw = <&saw3>; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; clocks = <&apcs1_mbox>; #cooling-cells = <2>; }; - CPU4: cpu@0 { + cpu4: cpu@0 { compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "spin-table"; reg = <0x0>; qcom,acc = <&acc4>; qcom,saw = <&saw4>; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; clocks = <&apcs0_mbox>; #cooling-cells = <2>; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU5: cpu@1 { + cpu5: cpu@1 { compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "spin-table"; reg = <0x1>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,acc = <&acc5>; qcom,saw = <&saw5>; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; clocks = <&apcs0_mbox>; #cooling-cells = <2>; }; - CPU6: cpu@2 { + cpu6: cpu@2 { compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "spin-table"; reg = <0x2>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,acc = <&acc6>; qcom,saw = <&saw6>; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; clocks = <&apcs0_mbox>; #cooling-cells = <2>; }; - CPU7: cpu@3 { + cpu7: cpu@3 { compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "spin-table"; reg = <0x3>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,acc = <&acc7>; qcom,saw = <&saw7>; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; clocks = <&apcs0_mbox>; #cooling-cells = <2>; }; idle-states { - CPU_SLEEP_0: cpu-sleep-0 { + cpu_sleep_0: cpu-sleep-0 { compatible = "arm,idle-state"; entry-latency-us = <130>; exit-latency-us = <150>; @@ -182,19 +182,19 @@ cpu-map { /* LITTLE (efficiency) cluster */ cluster0 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; @@ -202,19 +202,19 @@ core3 { /* Boot CPU is cluster 1 core 0 */ cluster1 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; }; @@ -2318,10 +2318,10 @@ cpu0_crit: trip1 { cooling-maps { map0 { trip = <&cpu0_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2348,10 +2348,10 @@ cpu1_crit: trip1 { cooling-maps { map0 { trip = <&cpu1_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2378,10 +2378,10 @@ cpu2_crit: trip1 { cooling-maps { map0 { trip = <&cpu2_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2408,10 +2408,10 @@ cpu3_crit: trip1 { cooling-maps { map0 { trip = <&cpu3_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2438,10 +2438,10 @@ cpu4567_crit: trip1 { cooling-maps { map0 { trip = <&cpu4567_alert>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index d20fd3d7c46e4f..af4c341e2533ef 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -38,125 +38,125 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x1>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x2>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x3>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; }; - CPU4: cpu@100 { + cpu4: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x100>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; #cooling-cells = <2>; }; - CPU5: cpu@101 { + cpu5: cpu@101 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x101>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; #cooling-cells = <2>; }; - CPU6: cpu@102 { + cpu6: cpu@102 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x102>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; #cooling-cells = <2>; }; - CPU7: cpu@103 { + cpu7: cpu@103 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x103>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; #cooling-cells = <2>; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; cluster1 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; - L2_0: l2-cache-0 { + l2_0: l2-cache-0 { compatible = "cache"; cache-level = <2>; cache-unified; }; - L2_1: l2-cache-1 { + l2_1: l2-cache-1 { compatible = "cache"; cache-level = <2>; cache-unified; @@ -1985,7 +1985,7 @@ cpu0_crit: crit { cooling-maps { map0 { trip = <&cpu0_alert>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2009,7 +2009,7 @@ cpu1_crit: crit { cooling-maps { map0 { trip = <&cpu1_alert>; - cooling-device = <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2033,7 +2033,7 @@ cpu2_crit: crit { cooling-maps { map0 { trip = <&cpu2_alert>; - cooling-device = <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2057,7 +2057,7 @@ cpu3_crit: crit { cooling-maps { map0 { trip = <&cpu3_alert>; - cooling-device = <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2079,7 +2079,7 @@ cpu4_crit: crit { cooling-maps { map0 { trip = <&cpu4_alert>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2101,7 +2101,7 @@ cpu5_crit: crit { cooling-maps { map0 { trip = <&cpu5_alert>; - cooling-device = <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2123,7 +2123,7 @@ cpu6_crit: crit { cooling-maps { map0 { trip = <&cpu6_alert>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2145,7 +2145,7 @@ cpu7_crit: crit { cooling-maps { map0 { trip = <&cpu7_alert>; - cooling-device = <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8976.dtsi b/arch/arm64/boot/dts/qcom/msm8976.dtsi index 06af6e5ec578ed..d036f31dfdca16 100644 --- a/arch/arm64/boot/dts/qcom/msm8976.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8976.dtsi @@ -31,7 +31,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0>; @@ -42,7 +42,7 @@ CPU0: cpu@0 { #cooling-cells = <2>; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x1>; @@ -53,7 +53,7 @@ CPU1: cpu@1 { #cooling-cells = <2>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x2>; @@ -64,7 +64,7 @@ CPU2: cpu@2 { #cooling-cells = <2>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x3>; @@ -75,7 +75,7 @@ CPU3: cpu@3 { #cooling-cells = <2>; }; - CPU4: cpu@100 { + cpu4: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a72"; reg = <0x100>; @@ -86,7 +86,7 @@ CPU4: cpu@100 { #cooling-cells = <2>; }; - CPU5: cpu@101 { + cpu5: cpu@101 { device_type = "cpu"; compatible = "arm,cortex-a72"; reg = <0x101>; @@ -97,7 +97,7 @@ CPU5: cpu@101 { #cooling-cells = <2>; }; - CPU6: cpu@102 { + cpu6: cpu@102 { device_type = "cpu"; compatible = "arm,cortex-a72"; reg = <0x102>; @@ -108,7 +108,7 @@ CPU6: cpu@102 { #cooling-cells = <2>; }; - CPU7: cpu@103 { + cpu7: cpu@103 { device_type = "cpu"; compatible = "arm,cortex-a72"; reg = <0x103>; @@ -122,37 +122,37 @@ CPU7: cpu@103 { cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; cluster1 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -1193,7 +1193,7 @@ opp-600000000 { apps_iommu: iommu@1ee0000 { compatible = "qcom,msm8976-iommu", "qcom,msm-iommu-v2"; reg = <0x01ee0000 0x3000>; - ranges = <0 0x01e20000 0x20000>; + ranges = <0 0x01e20000 0x20000>; clocks = <&gcc GCC_SMMU_CFG_CLK>, <&gcc GCC_APSS_TCU_CLK>; diff --git a/arch/arm64/boot/dts/qcom/msm8992-lg-h815.dts b/arch/arm64/boot/dts/qcom/msm8992-lg-h815.dts index 38b305816d2f76..4520d5d51a2998 100644 --- a/arch/arm64/boot/dts/qcom/msm8992-lg-h815.dts +++ b/arch/arm64/boot/dts/qcom/msm8992-lg-h815.dts @@ -91,27 +91,27 @@ key-vol-up { }; }; -&CPU0 { +&cpu0 { enable-method = "spin-table"; }; -&CPU1 { +&cpu1 { enable-method = "spin-table"; }; -&CPU2 { +&cpu2 { enable-method = "spin-table"; }; -&CPU3 { +&cpu3 { enable-method = "spin-table"; }; -&CPU4 { +&cpu4 { enable-method = "spin-table"; }; -&CPU5 { +&cpu5 { enable-method = "spin-table"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts b/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts index 133f9c2540bcab..d0290a20b888dd 100644 --- a/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts +++ b/arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts @@ -175,7 +175,7 @@ &blsp2_uart2 { }; &pm8994_spmi_regulators { - VDD_APC0: s8 { + s8 { regulator-min-microvolt = <680000>; regulator-max-microvolt = <1180000>; regulator-always-on; @@ -183,7 +183,7 @@ VDD_APC0: s8 { }; /* APC1 is 3-phase, but quoting downstream, s11 is "the gang leader" */ - VDD_APC1: s11 { + s11 { regulator-min-microvolt = <700000>; regulator-max-microvolt = <1225000>; regulator-always-on; diff --git a/arch/arm64/boot/dts/qcom/msm8992.dtsi b/arch/arm64/boot/dts/qcom/msm8992.dtsi index 02fc3795dbfd73..b2dc46c25fa243 100644 --- a/arch/arm64/boot/dts/qcom/msm8992.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8992.dtsi @@ -6,8 +6,8 @@ #include "msm8994.dtsi" /* 8992 only features 2 A57 cores. */ -/delete-node/ &CPU6; -/delete-node/ &CPU7; +/delete-node/ &cpu6; +/delete-node/ &cpu7; /delete-node/ &cpu6_map; /delete-node/ &cpu7_map; diff --git a/arch/arm64/boot/dts/qcom/msm8994.dtsi b/arch/arm64/boot/dts/qcom/msm8994.dtsi index fc2a7f13f690ee..1acb0f15951199 100644 --- a/arch/arm64/boot/dts/qcom/msm8994.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8994.dtsi @@ -43,114 +43,114 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x0>; enable-method = "psci"; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x1>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x2>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x3>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU4: cpu@100 { + cpu4: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a57"; reg = <0x0 0x100>; enable-method = "psci"; - next-level-cache = <&L2_1>; - L2_1: l2-cache { + next-level-cache = <&l2_1>; + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU5: cpu@101 { + cpu5: cpu@101 { device_type = "cpu"; compatible = "arm,cortex-a57"; reg = <0x0 0x101>; enable-method = "psci"; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; - CPU6: cpu@102 { + cpu6: cpu@102 { device_type = "cpu"; compatible = "arm,cortex-a57"; reg = <0x0 0x102>; enable-method = "psci"; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; - CPU7: cpu@103 { + cpu7: cpu@103 { device_type = "cpu"; compatible = "arm,cortex-a57"; reg = <0x0 0x103>; enable-method = "psci"; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; cluster1 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; cpu6_map: core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; cpu7_map: core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index e5966724f37c69..b379623c1b8a08 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -43,90 +43,90 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x0>; enable-method = "psci"; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; capacity-dmips-mhz = <1024>; clocks = <&kryocc 0>; interconnects = <&cbf MASTER_CBF_M4M &cbf SLAVE_CBF_M4M>; operating-points-v2 = <&cluster0_opp>; #cooling-cells = <2>; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x1>; enable-method = "psci"; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; capacity-dmips-mhz = <1024>; clocks = <&kryocc 0>; interconnects = <&cbf MASTER_CBF_M4M &cbf SLAVE_CBF_M4M>; operating-points-v2 = <&cluster0_opp>; #cooling-cells = <2>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU2: cpu@100 { + cpu2: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x100>; enable-method = "psci"; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; capacity-dmips-mhz = <1024>; clocks = <&kryocc 1>; interconnects = <&cbf MASTER_CBF_M4M &cbf SLAVE_CBF_M4M>; operating-points-v2 = <&cluster1_opp>; #cooling-cells = <2>; - next-level-cache = <&L2_1>; - L2_1: l2-cache { + next-level-cache = <&l2_1>; + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU3: cpu@101 { + cpu3: cpu@101 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x101>; enable-method = "psci"; - cpu-idle-states = <&CPU_SLEEP_0>; + cpu-idle-states = <&cpu_sleep_0>; capacity-dmips-mhz = <1024>; clocks = <&kryocc 1>; interconnects = <&cbf MASTER_CBF_M4M &cbf SLAVE_CBF_M4M>; operating-points-v2 = <&cluster1_opp>; #cooling-cells = <2>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; }; cluster1 { core0 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core1 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; }; @@ -134,7 +134,7 @@ core1 { idle-states { entry-method = "psci"; - CPU_SLEEP_0: cpu-sleep-0 { + cpu_sleep_0: cpu-sleep-0 { compatible = "arm,idle-state"; idle-state-name = "standalone-power-collapse"; arm,psci-suspend-param = <0x00000004>; @@ -2829,7 +2829,7 @@ debug@3810000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU0>; + cpu = <&cpu0>; }; etm@3840000 { @@ -2839,7 +2839,7 @@ etm@3840000 { clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU0>; + cpu = <&cpu0>; out-ports { port { @@ -2858,7 +2858,7 @@ debug@3910000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU1>; + cpu = <&cpu1>; }; etm@3940000 { @@ -2868,7 +2868,7 @@ etm@3940000 { clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU1>; + cpu = <&cpu1>; out-ports { port { @@ -2923,7 +2923,7 @@ debug@3a10000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU2>; + cpu = <&cpu2>; }; etm@3a40000 { @@ -2933,7 +2933,7 @@ etm@3a40000 { clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU2>; + cpu = <&cpu2>; out-ports { port { @@ -2952,7 +2952,7 @@ debug@3b10000 { clocks = <&rpmcc RPM_QDSS_CLK>; clock-names = "apb_pclk"; - cpu = <&CPU3>; + cpu = <&cpu3>; }; etm@3b40000 { @@ -2962,7 +2962,7 @@ etm@3b40000 { clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU3>; + cpu = <&cpu3>; out-ports { port { diff --git a/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi index 3b7172aa40374c..157c4f04564b71 100644 --- a/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998-clamshell.dtsi @@ -61,36 +61,36 @@ cts-pins { * not advertised as enabled in ACPI, and enabling it in DT can cause boot * hangs. */ -&CPU0 { - cpu-idle-states = <&LITTLE_CPU_SLEEP_1>; +&cpu0 { + cpu-idle-states = <&little_cpu_sleep_1>; }; -&CPU1 { - cpu-idle-states = <&LITTLE_CPU_SLEEP_1>; +&cpu1 { + cpu-idle-states = <&little_cpu_sleep_1>; }; -&CPU2 { - cpu-idle-states = <&LITTLE_CPU_SLEEP_1>; +&cpu2 { + cpu-idle-states = <&little_cpu_sleep_1>; }; -&CPU3 { - cpu-idle-states = <&LITTLE_CPU_SLEEP_1>; +&cpu3 { + cpu-idle-states = <&little_cpu_sleep_1>; }; -&CPU4 { - cpu-idle-states = <&BIG_CPU_SLEEP_1>; +&cpu4 { + cpu-idle-states = <&big_cpu_sleep_1>; }; -&CPU5 { - cpu-idle-states = <&BIG_CPU_SLEEP_1>; +&cpu5 { + cpu-idle-states = <&big_cpu_sleep_1>; }; -&CPU6 { - cpu-idle-states = <&BIG_CPU_SLEEP_1>; +&cpu6 { + cpu-idle-states = <&big_cpu_sleep_1>; }; -&CPU7 { - cpu-idle-states = <&BIG_CPU_SLEEP_1>; +&cpu7 { + cpu-idle-states = <&big_cpu_sleep_1>; }; /* @@ -128,6 +128,12 @@ pm8005_s1: s1 { /* VDD_GFX supply */ }; }; +&pm8998_resin { + linux,code = ; + + status = "okay"; +}; + &qusb2phy { status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts b/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts index a105143bee4a81..901f6ac0084db3 100644 --- a/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts +++ b/arch/arm64/boot/dts/qcom/msm8998-lenovo-miix-630.dts @@ -3,12 +3,45 @@ /dts-v1/; +#include #include "msm8998-clamshell.dtsi" / { model = "Lenovo Miix 630"; compatible = "lenovo,miix-630", "qcom,msm8998"; chassis-type = "convertible"; + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + + pinctrl-0 = <&vol_up_pin_a>; + pinctrl-names = "default"; + + key-vol-up { + label = "Volume Up"; + gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&blsp1_i2c5 { + clock-frequency = <400000>; + status = "okay"; + + touchscreen@10 { + compatible = "hid-over-i2c"; + reg = <0x10>; + hid-descr-addr = <0x1>; + + interrupts-extended = <&tlmm 125 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-0 = <&i2c5_hid_active>; + pinctrl-names = "default"; + }; }; &blsp1_i2c6 { @@ -27,11 +60,46 @@ keyboard@3a { }; }; +&pm8998_gpios { + vol_up_pin_a: vol-up-active-state { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,drive-strength = ; + }; +}; + +&remoteproc_adsp { + firmware-name = "qcom/msm8998/LENOVO/81F1/qcadsp8998.mbn"; + + status = "okay"; +}; + &remoteproc_mss { firmware-name = "qcom/msm8998/LENOVO/81F1/qcdsp1v28998.mbn", "qcom/msm8998/LENOVO/81F1/qcdsp28998.mbn"; }; +&remoteproc_slpi { + firmware-name = "qcom/msm8998/LENOVO/81F1/qcslpi8998.mbn"; + + status = "okay"; +}; + &sdhc2 { cd-gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>; }; + +&tlmm { + i2c5_hid_active: i2c5-hid-active-state { + pins = "gpio125"; + function = "gpio"; + bias-pull-up; + drive-strength = <2>; + }; +}; + +&wifi { + qcom,ath10k-calibration-variant = "Lenovo_Miix630"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index 9aa9c5cee355b2..c2caad85c668df 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -136,130 +136,130 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo280"; reg = <0x0 0x0>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + cpu-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "qcom,kryo280"; reg = <0x0 0x1>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; - next-level-cache = <&L2_0>; + cpu-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; + next-level-cache = <&l2_0>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "qcom,kryo280"; reg = <0x0 0x2>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; - next-level-cache = <&L2_0>; + cpu-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; + next-level-cache = <&l2_0>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "qcom,kryo280"; reg = <0x0 0x3>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; - next-level-cache = <&L2_0>; + cpu-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; + next-level-cache = <&l2_0>; }; - CPU4: cpu@100 { + cpu4: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo280"; reg = <0x0 0x100>; enable-method = "psci"; capacity-dmips-mhz = <1536>; - cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; - next-level-cache = <&L2_1>; - L2_1: l2-cache { + cpu-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; + next-level-cache = <&l2_1>; + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU5: cpu@101 { + cpu5: cpu@101 { device_type = "cpu"; compatible = "qcom,kryo280"; reg = <0x0 0x101>; enable-method = "psci"; capacity-dmips-mhz = <1536>; - cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; - next-level-cache = <&L2_1>; + cpu-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; + next-level-cache = <&l2_1>; }; - CPU6: cpu@102 { + cpu6: cpu@102 { device_type = "cpu"; compatible = "qcom,kryo280"; reg = <0x0 0x102>; enable-method = "psci"; capacity-dmips-mhz = <1536>; - cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; - next-level-cache = <&L2_1>; + cpu-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; + next-level-cache = <&l2_1>; }; - CPU7: cpu@103 { + cpu7: cpu@103 { device_type = "cpu"; compatible = "qcom,kryo280"; reg = <0x0 0x103>; enable-method = "psci"; capacity-dmips-mhz = <1536>; - cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; - next-level-cache = <&L2_1>; + cpu-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; + next-level-cache = <&l2_1>; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; cluster1 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -267,7 +267,7 @@ core3 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-retention"; /* CPU Retention (C2D), L2 Active */ @@ -277,7 +277,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { min-residency-us = <504>; }; - LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { + little_cpu_sleep_1: cpu-sleep-0-1 { compatible = "arm,idle-state"; idle-state-name = "little-power-collapse"; /* CPU + L2 Power Collapse (C3, D4) */ @@ -288,7 +288,7 @@ LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-retention"; /* CPU Retention (C2D), L2 Active */ @@ -298,7 +298,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { min-residency-us = <1302>; }; - BIG_CPU_SLEEP_1: cpu-sleep-1-1 { + big_cpu_sleep_1: cpu-sleep-1-1 { compatible = "arm,idle-state"; idle-state-name = "big-power-collapse"; /* CPU + L2 Power Collapse (C3, D4) */ @@ -1415,6 +1415,34 @@ blsp2_spi6_default: blsp2-spi6-default-state { drive-strength = <6>; bias-disable; }; + + hdmi_cec_default: hdmi-cec-default-state { + pins = "gpio31"; + function = "hdmi_cec"; + drive-strength = <2>; + bias-pull-up; + }; + + hdmi_ddc_default: hdmi-ddc-default-state { + pins = "gpio32", "gpio33"; + function = "hdmi_ddc"; + drive-strength = <2>; + bias-pull-up; + }; + + hdmi_hpd_default: hdmi-hpd-default-state { + pins = "gpio34"; + function = "hdmi_hot"; + drive-strength = <16>; + bias-pull-down; + }; + + hdmi_hpd_sleep: hdmi-hpd-sleep-state { + pins = "gpio34"; + function = "hdmi_hot"; + drive-strength = <2>; + bias-pull-down; + }; }; remoteproc_mss: remoteproc@4080000 { @@ -1846,7 +1874,7 @@ etm1: etm@7840000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU0>; + cpu = <&cpu0>; out-ports { port { @@ -1866,7 +1894,7 @@ etm2: etm@7940000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU1>; + cpu = <&cpu1>; out-ports { port { @@ -1886,7 +1914,7 @@ etm3: etm@7a40000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU2>; + cpu = <&cpu2>; out-ports { port { @@ -1906,7 +1934,7 @@ etm4: etm@7b40000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU3>; + cpu = <&cpu3>; out-ports { port { @@ -2040,7 +2068,7 @@ etm5: etm@7c40000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU4>; + cpu = <&cpu4>; out-ports { port { @@ -2059,7 +2087,7 @@ etm6: etm@7d40000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU5>; + cpu = <&cpu5>; out-ports { port { @@ -2078,7 +2106,7 @@ etm7: etm@7e40000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU6>; + cpu = <&cpu6>; out-ports { port { @@ -2097,7 +2125,7 @@ etm8: etm@7f40000 { clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; - cpu = <&CPU7>; + cpu = <&cpu7>; out-ports { port { @@ -2766,7 +2794,7 @@ mmcc: clock-controller@c8c0000 { <&mdss_dsi0_phy 0>, <&mdss_dsi1_phy 1>, <&mdss_dsi1_phy 0>, - <0>, + <&mdss_hdmi_phy 0>, <0>, <0>, <&gcc GCC_MMSS_GPLL0_DIV_CLK>; @@ -2871,6 +2899,14 @@ dpu_intf2_out: endpoint { remote-endpoint = <&mdss_dsi1_in>; }; }; + + port@2 { + reg = <2>; + + dpu_intf3_out: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; }; }; @@ -3026,6 +3062,96 @@ mdss_dsi1_phy: phy@c996400 { status = "disabled"; }; + + mdss_hdmi: hdmi-tx@c9a0000 { + compatible = "qcom,hdmi-tx-8998"; + reg = <0x0c9a0000 0x50c>, + <0x00780000 0x6220>, + <0x0c9e0000 0x2c>; + reg-names = "core_physical", + "qfprom_physical", + "hdcp_physical"; + + interrupt-parent = <&mdss>; + interrupts = <8>; + + clocks = <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_HDMI_CLK>, + <&mmcc MDSS_HDMI_DP_AHB_CLK>, + <&mmcc MDSS_EXTPCLK_CLK>, + <&mmcc MDSS_AXI_CLK>, + <&mmcc MNOC_AHB_CLK>, + <&mmcc MISC_AHB_CLK>; + clock-names = + "mdp_core", + "iface", + "core", + "alt_iface", + "extp", + "bus", + "mnoc", + "iface_mmss"; + + phys = <&mdss_hdmi_phy>; + #sound-dai-cells = <1>; + + pinctrl-0 = <&hdmi_hpd_default>, + <&hdmi_ddc_default>, + <&hdmi_cec_default>; + pinctrl-1 = <&hdmi_hpd_sleep>, + <&hdmi_ddc_default>, + <&hdmi_cec_default>; + pinctrl-names = "default", "sleep"; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + hdmi_in: endpoint { + remote-endpoint = <&dpu_intf3_out>; + }; + }; + + port@1 { + reg = <1>; + hdmi_out: endpoint { + }; + }; + }; + }; + + mdss_hdmi_phy: hdmi-phy@c9a0600 { + compatible = "qcom,hdmi-phy-8998"; + reg = <0x0c9a0600 0x18b>, + <0x0c9a0a00 0x38>, + <0x0c9a0c00 0x38>, + <0x0c9a0e00 0x38>, + <0x0c9a1000 0x38>, + <0x0c9a1200 0x0e8>; + reg-names = "hdmi_pll", + "hdmi_tx_l0", + "hdmi_tx_l1", + "hdmi_tx_l2", + "hdmi_tx_l3", + "hdmi_phy"; + + #clock-cells = <0>; + #phy-cells = <0>; + + clocks = <&mmcc MDSS_AHB_CLK>, + <&gcc GCC_HDMI_CLKREF_CLK>, + <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "iface", + "ref", + "xo"; + + status = "disabled"; + }; }; venus: video-codec@cc00000 { diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi index 79bc42ffb6a1ff..f0746123e594d5 100644 --- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi +++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi @@ -42,7 +42,7 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x0>; @@ -50,18 +50,18 @@ CPU0: cpu@0 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x1>; @@ -69,13 +69,13 @@ CPU1: cpu@1 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x2>; @@ -83,13 +83,13 @@ CPU2: cpu@2 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x3>; @@ -97,34 +97,34 @@ CPU3: cpu@3 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; }; domain-idle-states { - CLUSTER_SLEEP: cluster-sleep-0 { + cluster_sleep: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000043>; entry-latency-us = <800>; @@ -136,7 +136,7 @@ CLUSTER_SLEEP: cluster-sleep-0 { idle-states { entry-method = "psci"; - CPU_SLEEP: cpu-sleep-0 { + cpu_sleep: cpu-sleep-0 { compatible = "arm,idle-state"; idle-state-name = "power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -174,34 +174,34 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_SLEEP>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_sleep>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_SLEEP>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_sleep>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_SLEEP>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_sleep>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_SLEEP>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_sleep>; }; - CLUSTER_PD: power-domain-cpu-cluster { + cluster_pd: power-domain-cpu-cluster { #power-domain-cells = <0>; power-domains = <&mpm>; - domain-idle-states = <&CLUSTER_SLEEP>; + domain-idle-states = <&cluster_sleep>; }; }; @@ -2067,7 +2067,7 @@ lmh_cluster: lmh@f550800 { compatible = "qcom,qcm2290-lmh", "qcom,sm8150-lmh"; reg = <0x0 0x0f550800 0x0 0x400>; interrupts = ; - cpus = <&CPU0>; + cpus = <&cpu0>; qcom,lmh-temp-arm-millicelsius = <65000>; qcom,lmh-temp-low-millicelsius = <94500>; qcom,lmh-temp-high-millicelsius = <95000>; diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index 8ab30c01712e0b..fdc62f1b1c5a39 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -207,6 +207,20 @@ active-config0 { }; }; + mem-thermal { + polling-delay-passive = <0>; + + thermal-sensors = <&pm7250b_adc_tm 2>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + pm8008-thermal { polling-delay-passive = <100>; thermal-sensors = <&pm8008>; @@ -679,6 +693,9 @@ &ipa { }; &pm7250b_adc { + pinctrl-0 = <&pm7250b_adc_default>; + pinctrl-names = "default"; + channel@4d { reg = ; qcom,ratiometric; @@ -694,6 +711,14 @@ channel@4f { qcom,pre-scaling = <1 1>; label = "conn_therm"; }; + + channel@53 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "mem_therm"; + }; }; &pm7250b_adc_tm { @@ -712,6 +737,21 @@ conn-therm@1 { qcom,ratiometric; qcom,hw-settle-time-us = <200>; }; + + mem-therm@2 { + reg = <2>; + io-channels = <&pm7250b_adc ADC5_GPIO2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + +&pm7250b_gpios { + pm7250b_adc_default: adc-default-state { + pins = "gpio12"; + function = PMIC_GPIO_FUNC_NORMAL; + bias-high-impedance; + }; }; &pm7325_gpios { diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts index 84c45419cb8d13..c5fb153614e1f1 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -499,6 +499,14 @@ vreg_bob_3p296: bob { }; }; +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/qcm6490/a660_zap.mbn"; +}; + &mdss { status = "okay"; }; @@ -694,6 +702,25 @@ &uart5 { status = "okay"; }; +&ufs_mem_hc { + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + vcc-supply = <&vreg_l7b_2p952>; + vcc-max-microamp = <800000>; + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <900000>; + vccq2-supply = <&vreg_l9b_1p2>; + vccq2-max-microamp = <900000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l10c_0p88>; + vdda-pll-supply = <&vreg_l6b_1p2>; + + status = "okay"; +}; + &usb_1 { status = "okay"; }; @@ -720,4 +747,7 @@ &usb_1_qmpphy { &wifi { memory-region = <&wlan_fw_mem>; + qcom,ath11k-calibration-variant = "Qualcomm_qcm6490idp"; + + status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi index cddc16bac0cea4..215ba146207afd 100644 --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi @@ -36,13 +36,13 @@ cpus { #address-cells = <1>; #size-cells = <0>; - CPU0: cpu@100 { + cpu0: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x100>; enable-method = "psci"; - cpu-idle-states = <&CPU_SLEEP_0>; - next-level-cache = <&L2_0>; + cpu-idle-states = <&cpu_sleep_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; clocks = <&apcs_glb>; operating-points-v2 = <&cpu_opp_table>; @@ -50,13 +50,13 @@ CPU0: cpu@100 { power-domain-names = "cpr"; }; - CPU1: cpu@101 { + cpu1: cpu@101 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x101>; enable-method = "psci"; - cpu-idle-states = <&CPU_SLEEP_0>; - next-level-cache = <&L2_0>; + cpu-idle-states = <&cpu_sleep_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; clocks = <&apcs_glb>; operating-points-v2 = <&cpu_opp_table>; @@ -64,13 +64,13 @@ CPU1: cpu@101 { power-domain-names = "cpr"; }; - CPU2: cpu@102 { + cpu2: cpu@102 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x102>; enable-method = "psci"; - cpu-idle-states = <&CPU_SLEEP_0>; - next-level-cache = <&L2_0>; + cpu-idle-states = <&cpu_sleep_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; clocks = <&apcs_glb>; operating-points-v2 = <&cpu_opp_table>; @@ -78,13 +78,13 @@ CPU2: cpu@102 { power-domain-names = "cpr"; }; - CPU3: cpu@103 { + cpu3: cpu@103 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x103>; enable-method = "psci"; - cpu-idle-states = <&CPU_SLEEP_0>; - next-level-cache = <&L2_0>; + cpu-idle-states = <&cpu_sleep_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; clocks = <&apcs_glb>; operating-points-v2 = <&cpu_opp_table>; @@ -92,7 +92,7 @@ CPU3: cpu@103 { power-domain-names = "cpr"; }; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; @@ -101,7 +101,7 @@ L2_0: l2-cache { idle-states { entry-method = "psci"; - CPU_SLEEP_0: cpu-sleep-0 { + cpu_sleep_0: cpu-sleep-0 { compatible = "arm,idle-state"; idle-state-name = "standalone-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -1679,10 +1679,10 @@ cluster_crit: cluster-crit { cooling-maps { map0 { trip = <&cluster_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -1712,10 +1712,10 @@ cpu0_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu0_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -1745,10 +1745,10 @@ cpu1_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu1_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -1778,10 +1778,10 @@ cpu2_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu2_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -1811,10 +1811,10 @@ cpu3_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu3_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts index 0d45662b8028bf..27695bd5422055 100644 --- a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -9,6 +9,7 @@ #define PM7250B_SID 8 #define PM7250B_SID1 9 +#include #include #include "sc7280.dtsi" #include "pm7250b.dtsi" @@ -153,6 +154,20 @@ debug_vm_mem: debug-vm@d0600000 { }; }; + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&kypd_vol_up_n>; + pinctrl-names = "default"; + + key-volume-up { + label = "Volume Up"; + gpios = <&pm7325_gpios 6 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,can-disable; + }; + }; + pmic-glink { compatible = "qcom,qcm6490-pmic-glink", "qcom,pmic-glink"; @@ -557,6 +572,14 @@ &gpi_dma1 { status = "okay"; }; +&gpu { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/qcs6490/a660_zap.mbn"; +}; + &i2c0 { clock-frequency = <400000>; status = "okay"; @@ -598,6 +621,7 @@ lt9611_out: endpoint { }; &i2c1 { + clock-frequency = <100000>; status = "okay"; typec-mux@1c { @@ -684,10 +708,56 @@ &mdss_edp_phy { status = "okay"; }; +&pcie1 { + perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie1_reset_n>, <&pcie1_wake_n>; + pinctrl-names = "default"; + + iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, + <0x100 &apps_smmu 0x1c81 0x1>, + <0x208 &apps_smmu 0x1c84 0x1>, + <0x210 &apps_smmu 0x1c85 0x1>, + <0x218 &apps_smmu 0x1c86 0x1>, + <0x300 &apps_smmu 0x1c87 0x1>, + <0x400 &apps_smmu 0x1c88 0x1>, + <0x500 &apps_smmu 0x1c89 0x1>, + <0x501 &apps_smmu 0x1c90 0x1>; + + status = "okay"; +}; + +&pcie1_phy { + vdda-phy-supply = <&vreg_l10c_0p88>; + vdda-pll-supply = <&vreg_l6b_1p2>; + + status = "okay"; +}; + +&pm7325_gpios { + kypd_vol_up_n: kypd-vol-up-n-state { + pins = "gpio6"; + function = PMIC_GPIO_FUNC_NORMAL; + power-source = <1>; + bias-pull-up; + input-enable; + }; +}; + &pmk8350_rtc { status = "okay"; }; +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + linux,code = ; + + status = "okay"; +}; + &qupv3_id_0 { status = "okay"; }; @@ -707,7 +777,7 @@ &remoteproc_cdsp { }; &remoteproc_mpss { - firmware-name = "qcom/qcs6490/modem.mdt"; + firmware-name = "qcom/qcs6490/modem.mbn"; status = "okay"; }; @@ -716,6 +786,18 @@ &remoteproc_wpss { status = "okay"; }; +&sdhc_2 { + pinctrl-0 = <&sdc2_clk>, <&sdc2_cmd>, <&sdc2_data>, <&sd_cd>; + pinctrl-1 = <&sdc2_clk_sleep>, <&sdc2_cmd_sleep>, <&sdc2_data_sleep>, <&sd_cd>; + + vmmc-supply = <&vreg_l9c_2p96>; + vqmmc-supply = <&vreg_l6c_2p96>; + + cd-gpios = <&tlmm 91 GPIO_ACTIVE_LOW>; + + status = "okay"; +}; + &tlmm { gpio-reserved-ranges = <32 2>, /* ADSP */ <48 4>; /* NFC */ @@ -790,8 +872,15 @@ &ufs_mem_phy { status = "okay"; }; +&venus { + status = "okay"; +}; + &wifi { memory-region = <&wlan_fw_mem>; + qcom,ath11k-calibration-variant = "Qualcomm_rb3gen2"; + + status = "okay"; }; /* PINCTRL - ADDITIONS TO NODES IN PARENT DEVICE TREE FILES */ @@ -812,6 +901,21 @@ lt9611_rst_pin: lt9611-rst-state { }; }; +&sdc2_clk { + bias-disable; + drive-strength = <16>; +}; + +&sdc2_cmd { + bias-pull-up; + drive-strength = <10>; +}; + +&sdc2_data { + bias-pull-up; + drive-strength = <10>; +}; + &tlmm { lt9611_irq_pin: lt9611-irq-state { pins = "gpio24"; @@ -819,4 +923,25 @@ lt9611_irq_pin: lt9611-irq-state { drive-strength = <2>; bias-disable; }; + + pcie1_reset_n: pcie1-reset-n-state { + pins = "gpio2"; + function = "gpio"; + drive-strength = <16>; + output-low; + bias-disable; + }; + + pcie1_wake_n: pcie1-wake-n-state { + pins = "gpio3"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + sd_cd: sd-cd-state { + pins = "gpio91"; + function = "gpio"; + bias-pull-up; + }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs8550.dtsi b/arch/arm64/boot/dts/qcom/qcs8550.dtsi index 07b314834d88f7..f0acdd0b1e9384 100644 --- a/arch/arm64/boot/dts/qcom/qcs8550.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs8550.dtsi @@ -154,7 +154,7 @@ adspslpi_mem: adspslpi-region@9ea00000 { no-map; }; - mpss_dsm_mem: mpss_dsm_region@d4d00000 { + mpss_dsm_mem: mpss-dsm-region@d4d00000 { reg = <0x0 0xd4d00000 0x0 0x3300000>; no-map; }; diff --git a/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts b/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts new file mode 100644 index 00000000000000..759d1ec694b20e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs9100-ride-r3.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ +/dts-v1/; + +#include "sa8775p-ride-r3.dts" +/ { + model = "Qualcomm QCS9100 Ride Rev3"; + compatible = "qcom,qcs9100-ride-r3", "qcom,qcs9100", "qcom,sa8775p"; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs9100-ride.dts b/arch/arm64/boot/dts/qcom/qcs9100-ride.dts new file mode 100644 index 00000000000000..979462dfec30ec --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs9100-ride.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ +/dts-v1/; + +#include "sa8775p-ride.dts" +/ { + model = "Qualcomm QCS9100 Ride"; + compatible = "qcom,qcs9100-ride", "qcom,qcs9100", "qcom,sa8775p"; +}; diff --git a/arch/arm64/boot/dts/qcom/qdu1000.dtsi b/arch/arm64/boot/dts/qcom/qdu1000.dtsi index 642ca8f0236b39..47c0dd31aaf2e4 100644 --- a/arch/arm64/boot/dts/qcom/qdu1000.dtsi +++ b/arch/arm64/boot/dts/qcom/qdu1000.dtsi @@ -25,22 +25,22 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x0>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domains = <&cpufreq_hw 0>; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -48,76 +48,76 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x100>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; qcom,freq-domains = <&cpufreq_hw 0>; - next-level-cache = <&L2_100>; - L2_100: l2-cache { + next-level-cache = <&l2_100>; + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x200>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; qcom,freq-domains = <&cpufreq_hw 0>; - next-level-cache = <&L2_200>; - L2_200: l2-cache { + next-level-cache = <&l2_200>; + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x300>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; qcom,freq-domains = <&cpufreq_hw 0>; - next-level-cache = <&L2_300>; - L2_300: l2-cache { + next-level-cache = <&l2_300>; + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; }; @@ -126,7 +126,7 @@ core3 { idle-states { entry-method = "psci"; - CPU_OFF: cpu-sleep-0 { + cpu_off: cpu-sleep-0 { compatible = "arm,idle-state"; entry-latency-us = <274>; exit-latency-us = <480>; @@ -137,7 +137,7 @@ CPU_OFF: cpu-sleep-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; entry-latency-us = <584>; exit-latency-us = <2332>; @@ -145,7 +145,7 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { arm,psci-suspend-param = <0x41000044>; }; - CLUSTER_SLEEP_1: cluster-sleep-1 { + cluster_sleep_1: cluster-sleep-1 { compatible = "domain-idle-state"; entry-latency-us = <2893>; exit-latency-us = <4023>; @@ -187,33 +187,33 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_OFF>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_off>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_OFF>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_off>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_OFF>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_off>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_OFF>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_off>; }; - CLUSTER_PD: power-domain-cluster { + cluster_pd: power-domain-cluster { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0 &CLUSTER_SLEEP_1>; + domain-idle-states = <&cluster_sleep_0 &cluster_sleep_1>; }; }; @@ -921,7 +921,7 @@ usb_1_hsphy: phy@88e3000 { reg = <0x0 0x088e3000 0x0 0x120>; #phy-cells = <0>; - clocks =<&gcc GCC_USB2_CLKREF_EN>; + clocks = <&gcc GCC_USB2_CLKREF_EN>; clock-names = "ref"; resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; @@ -1412,6 +1412,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; intc: interrupt-controller@17200000 { @@ -1498,7 +1499,7 @@ apps_rsc: rsc@17a00000 { qcom,tcs-config = , , , ; label = "apps_rsc"; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts index e19790464a1159..7a789b41c2f188 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -24,7 +24,7 @@ chosen { }; clocks { - clk40M: can-clk { + clk40m: can-clk { compatible = "fixed-clock"; clock-frequency = <40000000>; #clock-cells = <0>; @@ -188,23 +188,23 @@ vph_pwr: regulator-vph-pwr { }; }; -&CPU_PD0 { +&cpu_pd0 { /delete-property/ power-domains; }; -&CPU_PD1 { +&cpu_pd1 { /delete-property/ power-domains; }; -&CPU_PD2 { +&cpu_pd2 { /delete-property/ power-domains; }; -&CPU_PD3 { +&cpu_pd3 { /delete-property/ power-domains; }; -/delete-node/ &CLUSTER_PD; +/delete-node/ &cluster_pd; &gpi_dma0 { status = "okay"; @@ -541,7 +541,7 @@ can@0 { compatible = "microchip,mcp2518fd"; reg = <0>; interrupts-extended = <&tlmm 39 IRQ_TYPE_LEVEL_LOW>; - clocks = <&clk40M>; + clocks = <&clk40m>; spi-max-frequency = <10000000>; vdd-supply = <&vdc_5v>; xceiver-supply = <&vdc_5v>; diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts index 1888d99d398b11..a9540e92d3e6fc 100644 --- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts @@ -25,7 +25,7 @@ chosen { }; clocks { - clk40M: can-clk { + clk40m: can-clk { compatible = "fixed-clock"; clock-frequency = <40000000>; #clock-cells = <0>; @@ -537,7 +537,7 @@ can@0 { compatible = "microchip,mcp2518fd"; reg = <0>; interrupts-extended = <&tlmm 39 IRQ_TYPE_LEVEL_LOW>; - clocks = <&clk40M>; + clocks = <&clk40m>; spi-max-frequency = <10000000>; vdd-supply = <&vdc_5v>; xceiver-supply = <&vdc_5v>; diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts deleted file mode 100644 index edc0e42ee01735..00000000000000 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Copyright (c) 2022, Linaro Ltd. - */ - -/dts-v1/; - -#include "qrb5165-rb5.dts" - -&camcc { - status = "okay"; -}; - -&camss { - vdda-phy-supply = <&vreg_l5a_0p88>; - vdda-pll-supply = <&vreg_l9a_1p2>; - status = "okay"; - - ports { - /* The port index denotes CSIPHY id i.e. csiphy2 */ - port@2 { - csiphy2_ep: endpoint { - clock-lanes = <7>; - data-lanes = <0 1 2 3>; - remote-endpoint = <&imx577_ep>; - }; - }; - }; -}; - -&cci1 { - status = "okay"; -}; - -&cci1_i2c0 { - camera@1a { - compatible = "sony,imx577"; - reg = <0x1a>; - - reset-gpios = <&tlmm 78 GPIO_ACTIVE_LOW>; - pinctrl-names = "default", "suspend"; - pinctrl-0 = <&cam2_default>; - pinctrl-1 = <&cam2_suspend>; - - clocks = <&camcc CAM_CC_MCLK2_CLK>; - assigned-clocks = <&camcc CAM_CC_MCLK2_CLK>; - assigned-clock-rates = <24000000>; - - dovdd-supply = <&vreg_l7f_1p8>; - avdd-supply = <&vdc_5v>; - dvdd-supply = <&vdc_5v>; - - port { - imx577_ep: endpoint { - clock-lanes = <1>; - link-frequencies = /bits/ 64 <600000000>; - data-lanes = <1 2 3 4>; - remote-endpoint = <&csiphy2_ep>; - }; - }; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dtso b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dtso new file mode 100644 index 00000000000000..ae256c713a3607 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dtso @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2022, Linaro Ltd. + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/ { + reserved-memory { + linux,cma { + compatible = "shared-dma-pool"; + size = <0x0 0x8000000>; + reusable; + linux,cma-default; + }; + }; +}; + +&camcc { + status = "okay"; +}; + +&camss { + vdda-phy-supply = <&vreg_l5a_0p88>; + vdda-pll-supply = <&vreg_l9a_1p2>; + status = "okay"; + + ports { + /* The port index denotes CSIPHY id i.e. csiphy2 */ + port@2 { + csiphy2_ep: endpoint { + clock-lanes = <7>; + data-lanes = <0 1 2 3>; + remote-endpoint = <&imx577_ep>; + }; + }; + }; +}; + +&cci1 { + status = "okay"; +}; + +&cci1_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@1a { + compatible = "sony,imx577"; + reg = <0x1a>; + + reset-gpios = <&tlmm 78 GPIO_ACTIVE_LOW>; + pinctrl-names = "default", "suspend"; + pinctrl-0 = <&cam2_default>; + pinctrl-1 = <&cam2_suspend>; + + clocks = <&camcc CAM_CC_MCLK2_CLK>; + assigned-clocks = <&camcc CAM_CC_MCLK2_CLK>; + assigned-clock-rates = <24000000>; + + dovdd-supply = <&vreg_l7f_1p8>; + avdd-supply = <&vdc_5v>; + dvdd-supply = <&vdc_5v>; + + port { + imx577_ep: endpoint { + link-frequencies = /bits/ 64 <600000000>; + data-lanes = <1 2 3 4>; + remote-endpoint = <&csiphy2_ep>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index ccff6cd73fdfab..52eef88e882c35 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -32,7 +32,7 @@ chosen { }; /* Fixed crystal oscillator dedicated to MCP2518FD */ - clk40M: can-clock { + clk40m: can-clock { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <40000000>; @@ -1118,7 +1118,7 @@ &spi0 { can@0 { compatible = "microchip,mcp2518fd"; reg = <0>; - clocks = <&clk40M>; + clocks = <&clk40m>; interrupts-extended = <&tlmm 15 IRQ_TYPE_LEVEL_LOW>; spi-max-frequency = <10000000>; vdd-supply = <&vdc_5v>; diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi index 0c1b21def4b62c..3fc62e12368969 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dtsi @@ -27,6 +27,83 @@ aliases { chosen { stdout-path = "serial0:115200n8"; }; + + vreg_conn_1p8: vreg_conn_1p8 { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_1p8"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pmm8654au_1_gpios 4 GPIO_ACTIVE_HIGH>; + }; + + vreg_conn_pa: vreg_conn_pa { + compatible = "regulator-fixed"; + regulator-name = "vreg_conn_pa"; + startup-delay-us = <4000>; + enable-active-high; + gpio = <&pmm8654au_1_gpios 6 GPIO_ACTIVE_HIGH>; + }; + + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_state>, <&wlan_en_state>; + + vddio-supply = <&vreg_conn_pa>; + vddaon-supply = <&vreg_l2c>; + vddpmu-supply = <&vreg_conn_1p8>; + vddrfa0p95-supply = <&vreg_l2c>; + vddrfa1p3-supply = <&vreg_l6e>; + vddrfa1p9-supply = <&vreg_s5a>; + vddpcie1p3-supply = <&vreg_l6e>; + vddpcie1p9-supply = <&vreg_s5a>; + + bt-enable-gpios = <&pmm8654au_1_gpios 8 GPIO_ACTIVE_HIGH>; + wlan-enable-gpios = <&pmm8654au_1_gpios 7 GPIO_ACTIVE_HIGH>; + + regulators { + vreg_pmu_rfa_cmn: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn"; + }; + + vreg_pmu_aon_0p59: ldo1 { + regulator-name = "vreg_pmu_aon_0p59"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p85: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p85"; + }; + + vreg_pmu_btcmx_0p85: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p85"; + }; + + vreg_pmu_rfa_0p8: ldo5 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo6 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p7: ldo7 { + regulator-name = "vreg_pmu_rfa_1p7"; + }; + + vreg_pmu_pcie_0p9: ldo8 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_pcie_1p8: ldo9 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + }; + }; }; &apps_rsc { @@ -453,6 +530,20 @@ &pmm8654au_1_gpios { "USB2_PWR_EN", "USB2_FAULT"; + wlan_en_state: wlan-en-state { + pins = "gpio7"; + function = "normal"; + output-low; + bias-pull-down; + }; + + bt_en_state: bt-en-state { + pins = "gpio8"; + function = "normal"; + output-low; + bias-pull-down; + }; + usb2_en_state: usb2-en-state { pins = "gpio9"; function = "normal"; @@ -702,6 +793,25 @@ &pcie1_phy { status = "okay"; }; +&pcieport0 { + wifi@0 { + compatible = "pci17cb,1101"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + qcom,ath11k-calibration-variant = "QC_SA8775P_Ride"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p7-supply = <&vreg_pmu_rfa_1p7>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + }; +}; + &remoteproc_adsp { firmware-name = "qcom/sa8775p/adsp.mbn"; status = "okay"; @@ -744,6 +854,17 @@ &uart17 { pinctrl-0 = <&qup_uart17_default>; pinctrl-names = "default"; status = "okay"; + + bluetooth { + compatible = "qcom,wcn6855-bt"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn>; + vddaon-supply = <&vreg_pmu_aon_0p59>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p85>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p7-supply = <&vreg_pmu_rfa_1p7>; + }; }; &ufs_mem_hc { diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi index e8dbc8d820a64f..9f315a51a7c14c 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause /* * Copyright (c) 2023, Linaro Limited + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -8,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -37,21 +39,21 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x0>; enable-method = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -59,72 +61,72 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x100>; enable-method = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - L2_1: l2-cache { + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x200>; enable-method = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; - next-level-cache = <&L2_2>; + next-level-cache = <&l2_2>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - L2_2: l2-cache { + l2_2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x300>; enable-method = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; - next-level-cache = <&L2_3>; + next-level-cache = <&l2_3>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - L2_3: l2-cache { + l2_3: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@10000 { + cpu4: cpu@10000 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x10000>; enable-method = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; - next-level-cache = <&L2_4>; + next-level-cache = <&l2_4>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - L2_4: l2-cache { + l2_4: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_1>; - L3_1: l3-cache { + next-level-cache = <&l3_1>; + l3_1: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -133,91 +135,91 @@ L3_1: l3-cache { }; }; - CPU5: cpu@10100 { + cpu5: cpu@10100 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x10100>; enable-method = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; - next-level-cache = <&L2_5>; + next-level-cache = <&l2_5>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - L2_5: l2-cache { + l2_5: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_1>; + next-level-cache = <&l3_1>; }; }; - CPU6: cpu@10200 { + cpu6: cpu@10200 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x10200>; enable-method = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; - next-level-cache = <&L2_6>; + next-level-cache = <&l2_6>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - L2_6: l2-cache { + l2_6: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_1>; + next-level-cache = <&l3_1>; }; }; - CPU7: cpu@10300 { + cpu7: cpu@10300 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x10300>; enable-method = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; - next-level-cache = <&L2_7>; + next-level-cache = <&l2_7>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - L2_7: l2-cache { + l2_7: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_1>; + next-level-cache = <&l3_1>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; cluster1 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -225,7 +227,7 @@ core3 { idle-states { entry-method = "psci"; - GOLD_CPU_SLEEP_0: cpu-sleep-0 { + gold_cpu_sleep_0: cpu-sleep-0 { compatible = "arm,idle-state"; idle-state-name = "gold-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -235,7 +237,7 @@ GOLD_CPU_SLEEP_0: cpu-sleep-0 { local-timer-stop; }; - GOLD_RAIL_CPU_SLEEP_0: cpu-sleep-1 { + gold_rail_cpu_sleep_0: cpu-sleep-1 { compatible = "arm,idle-state"; idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -247,7 +249,7 @@ GOLD_RAIL_CPU_SLEEP_0: cpu-sleep-1 { }; domain-idle-states { - CLUSTER_SLEEP_GOLD: cluster-sleep-0 { + cluster_sleep_gold: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <2752>; @@ -255,7 +257,7 @@ CLUSTER_SLEEP_GOLD: cluster-sleep-0 { min-residency-us = <6118>; }; - CLUSTER_SLEEP_APSS_RSC_PC: cluster-sleep-1 { + cluster_sleep_apss_rsc_pc: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x42000144>; entry-latency-us = <3263>; @@ -281,6 +283,7 @@ eud_in: endpoint { firmware { scm { compatible = "qcom,scm-sa8775p", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x13000>; memory-region = <&tz_ffi_mem>; }; }; @@ -393,77 +396,77 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_0_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>, - <&GOLD_RAIL_CPU_SLEEP_0>; + power-domains = <&cluster_0_pd>; + domain-idle-states = <&gold_cpu_sleep_0>, + <&gold_rail_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_0_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>, - <&GOLD_RAIL_CPU_SLEEP_0>; + power-domains = <&cluster_0_pd>; + domain-idle-states = <&gold_cpu_sleep_0>, + <&gold_rail_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_0_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>, - <&GOLD_RAIL_CPU_SLEEP_0>; + power-domains = <&cluster_0_pd>; + domain-idle-states = <&gold_cpu_sleep_0>, + <&gold_rail_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_0_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>, - <&GOLD_RAIL_CPU_SLEEP_0>; + power-domains = <&cluster_0_pd>; + domain-idle-states = <&gold_cpu_sleep_0>, + <&gold_rail_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_1_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>, - <&GOLD_RAIL_CPU_SLEEP_0>; + power-domains = <&cluster_1_pd>; + domain-idle-states = <&gold_cpu_sleep_0>, + <&gold_rail_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_1_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>, - <&GOLD_RAIL_CPU_SLEEP_0>; + power-domains = <&cluster_1_pd>; + domain-idle-states = <&gold_cpu_sleep_0>, + <&gold_rail_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_1_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>, - <&GOLD_RAIL_CPU_SLEEP_0>; + power-domains = <&cluster_1_pd>; + domain-idle-states = <&gold_cpu_sleep_0>, + <&gold_rail_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_1_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>, - <&GOLD_RAIL_CPU_SLEEP_0>; + power-domains = <&cluster_1_pd>; + domain-idle-states = <&gold_cpu_sleep_0>, + <&gold_rail_cpu_sleep_0>; }; - CLUSTER_0_PD: power-domain-cluster0 { + cluster_0_pd: power-domain-cluster0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_2_PD>; - domain-idle-states = <&CLUSTER_SLEEP_GOLD>; + power-domains = <&cluster_2_pd>; + domain-idle-states = <&cluster_sleep_gold>; }; - CLUSTER_1_PD: power-domain-cluster1 { + cluster_1_pd: power-domain-cluster1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_2_PD>; - domain-idle-states = <&CLUSTER_SLEEP_GOLD>; + power-domains = <&cluster_2_pd>; + domain-idle-states = <&cluster_sleep_gold>; }; - CLUSTER_2_PD: power-domain-cluster2 { + cluster_2_pd: power-domain-cluster2 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_APSS_RSC_PC>; + domain-idle-states = <&cluster_sleep_apss_rsc_pc>; }; }; @@ -851,6 +854,28 @@ ipcc: mailbox@408000 { #mbox-cells = <2>; }; + gpi_dma2: qcom,gpi-dma@800000 { + compatible = "qcom,sm6350-gpi-dma"; + reg = <0x0 0x00800000 0x0 0x60000>; + #dma-cells = <3>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <12>; + dma-channel-mask = <0xfff>; + iommus = <&apps_smmu 0x5b6 0x0>; + status = "disabled"; + }; + qupv3_id_2: geniqup@8c0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x008c0000 0x0 0x6000>; @@ -881,6 +906,10 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, + <&gpi_dma2 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -902,6 +931,25 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 0 QCOM_GPI_SPI>, + <&gpi_dma2 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart14: serial@880000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00880000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -923,6 +971,10 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, + <&gpi_dma2 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -944,6 +996,25 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 1 QCOM_GPI_SPI>, + <&gpi_dma2 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart15: serial@884000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00884000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -965,6 +1036,10 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, + <&gpi_dma2 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -984,11 +1059,30 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 2 QCOM_GPI_SPI>, + <&gpi_dma2 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; + uart16: serial@888000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00888000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; + status = "disabled"; + }; + i2c17: i2c@88c000 { compatible = "qcom,geni-i2c"; reg = <0x0 0x88c000 0x0 0x4000>; @@ -1007,6 +1101,10 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, + <&gpi_dma2 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1028,6 +1126,10 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 3 QCOM_GPI_SPI>, + <&gpi_dma2 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1062,6 +1164,10 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, + <&gpi_dma2 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1085,6 +1191,25 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 4 QCOM_GPI_SPI>, + <&gpi_dma2 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart18: serial@890000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00890000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -1106,6 +1231,10 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 5 QCOM_GPI_I2C>, + <&gpi_dma2 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1127,6 +1256,25 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 5 QCOM_GPI_SPI>, + <&gpi_dma2 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart19: serial@894000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00894000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -1148,6 +1296,10 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 6 QCOM_GPI_I2C>, + <&gpi_dma2 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1169,8 +1321,50 @@ &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma2 0 6 QCOM_GPI_SPI>, + <&gpi_dma2 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; status = "disabled"; }; + + uart20: serial@898000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00898000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; + status = "disabled"; + }; + + }; + + gpi_dma0: qcom,gpi-dma@900000 { + compatible = "qcom,sm6350-gpi-dma"; + reg = <0x0 0x00900000 0x0 0x60000>; + #dma-cells = <3>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + dma-channels = <12>; + dma-channel-mask = <0xfff>; + iommus = <&apps_smmu 0x416 0x0>; + status = "disabled"; }; qupv3_id_0: geniqup@9c0000 { @@ -1203,6 +1397,10 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, + <&gpi_dma0 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1224,6 +1422,25 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, + <&gpi_dma0 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart0: serial@980000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x980000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -1245,6 +1462,10 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, + <&gpi_dma0 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1266,6 +1487,25 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, + <&gpi_dma0 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart1: serial@984000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x984000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -1287,6 +1527,10 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, + <&gpi_dma0 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1308,6 +1552,25 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, + <&gpi_dma0 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart2: serial@988000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x988000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -1329,6 +1592,10 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, + <&gpi_dma0 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1350,6 +1617,25 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, + <&gpi_dma0 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart3: serial@98c000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x98c000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -1371,6 +1657,10 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, + <&gpi_dma0 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1392,6 +1682,25 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, + <&gpi_dma0 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart4: serial@990000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x990000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; + clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", "qup-config"; + power-domains = <&rpmhpd SA8775P_CX>; status = "disabled"; }; @@ -1413,6 +1722,10 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, + <&gpi_dma0 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1434,6 +1747,10 @@ &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, + <&gpi_dma0 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1453,6 +1770,28 @@ &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, }; }; + gpi_dma1: qcom,gpi-dma@a00000 { + compatible = "qcom,sm6350-gpi-dma"; + reg = <0x0 0x00a00000 0x0 0x60000>; + #dma-cells = <3>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + iommus = <&apps_smmu 0x456 0x0>; + dma-channels = <12>; + dma-channel-mask = <0xfff>; + status = "disabled"; + }; + qupv3_id_1: geniqup@ac0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0x00ac0000 0x0 0x6000>; @@ -1483,6 +1822,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, + <&gpi_dma1 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1504,6 +1847,26 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>, + <&gpi_dma1 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart7: serial@a80000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00a80000 0x0 0x4000>; + interrupts = ; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + interconnect-names = "qup-core", "qup-config"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>; + power-domains = <&rpmhpd SA8775P_CX>; + operating-points-v2 = <&qup_opp_table_100mhz>; status = "disabled"; }; @@ -1525,6 +1888,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, + <&gpi_dma1 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1546,6 +1913,26 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>, + <&gpi_dma1 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart8: serial@a84000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00a84000 0x0 0x4000>; + interrupts = ; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + interconnect-names = "qup-core", "qup-config"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>; + power-domains = <&rpmhpd SA8775P_CX>; + operating-points-v2 = <&qup_opp_table_100mhz>; status = "disabled"; }; @@ -1567,6 +1954,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, + <&gpi_dma1 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1588,6 +1979,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>, + <&gpi_dma1 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1624,6 +2019,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, + <&gpi_dma1 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1645,6 +2044,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>, + <&gpi_dma1 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1682,6 +2085,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, + <&gpi_dma1 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1703,6 +2110,26 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>, + <&gpi_dma1 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart11: serial@a90000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00a90000 0x0 0x4000>; + interrupts = ; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + interconnect-names = "qup-core", "qup-config"; + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>; + power-domains = <&rpmhpd SA8775P_CX>; + operating-points-v2 = <&qup_opp_table_100mhz>; status = "disabled"; }; @@ -1724,6 +2151,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, + <&gpi_dma1 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1745,6 +2176,10 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>, + <&gpi_dma1 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1781,10 +2216,29 @@ &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>, + <&gpi_dma1 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; + }; }; + gpi_dma3: qcom,gpi-dma@b00000 { + compatible = "qcom,sm6350-gpi-dma"; + reg = <0x0 0x00b00000 0x0 0x58000>; + #dma-cells = <3>; + interrupts = , + , + , + ; + iommus = <&apps_smmu 0x056 0x0>; + dma-channels = <4>; + dma-channel-mask = <0xf>; + status = "disabled"; + }; + qupv3_id_3: geniqup@bc0000 { compatible = "qcom,geni-se-qup"; reg = <0x0 0xbc0000 0x0 0x6000>; @@ -1815,6 +2269,10 @@ &config_noc SLAVE_QUP_3 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma3 0 0 QCOM_GPI_I2C>, + <&gpi_dma3 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; status = "disabled"; }; @@ -1836,6 +2294,26 @@ &config_noc SLAVE_QUP_3 QCOM_ICC_TAG_ALWAYS>, "qup-config", "qup-memory"; power-domains = <&rpmhpd SA8775P_CX>; + dmas = <&gpi_dma3 0 0 QCOM_GPI_SPI>, + <&gpi_dma3 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + status = "disabled"; + }; + + uart21: serial@b80000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x00b80000 0x0 0x4000>; + interrupts = ; + clock-names = "se"; + clocks = <&gcc GCC_QUPV3_WRAP3_S0_CLK>; + interconnect-names = "qup-core", "qup-config"; + interconnects = <&clk_virt MASTER_QUP_CORE_3 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_3 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_3 QCOM_ICC_TAG_ALWAYS>; + power-domains = <&rpmhpd SA8775P_CX>; + operating-points-v2 = <&qup_opp_table_100mhz>; status = "disabled"; }; }; @@ -1845,7 +2323,7 @@ rng: rng@10d2000 { reg = <0 0x010d2000 0 0x1000>; }; - ufs_mem_hc: ufs@1d84000 { + ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,sa8775p-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x01d84000 0x0 0x3000>; interrupts = ; @@ -1908,10 +2386,32 @@ ufs_mem_phy: phy@1d87000 { ice: crypto@1d88000 { compatible = "qcom,sa8775p-inline-crypto-engine", "qcom,inline-crypto-engine"; - reg = <0x0 0x01d88000 0x0 0x8000>; + reg = <0x0 0x01d88000 0x0 0x18000>; clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; }; + cryptobam: dma-controller@1dc4000 { + compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0"; + reg = <0x0 0x01dc4000 0x0 0x28000>; + interrupts = ; + #dma-cells = <1>; + qcom,ee = <0>; + qcom,controlled-remotely; + iommus = <&apps_smmu 0x480 0x00>, + <&apps_smmu 0x481 0x00>; + }; + + crypto: crypto@1dfa000 { + compatible = "qcom,sa8775p-qce", "qcom,qce"; + reg = <0x0 0x01dfa000 0x0 0x6000>; + dmas = <&cryptobam 4>, <&cryptobam 5>; + dma-names = "rx", "tx"; + iommus = <&apps_smmu 0x480 0x00>, + <&apps_smmu 0x481 0x00>; + interconnects = <&aggre2_noc MASTER_CRYPTO_CORE0 0 &mc_virt SLAVE_EBI1 0>; + interconnect-names = "memory"; + }; + stm: stm@4002000 { compatible = "arm,coresight-stm", "arm,primecell"; reg = <0x0 0x4002000 0x0 0x1000>, @@ -2382,7 +2882,7 @@ aoss_cti: cti@4b13000 { etm@6040000 { compatible = "arm,primecell"; reg = <0x0 0x6040000 0x0 0x1000>; - cpu = <&CPU0>; + cpu = <&cpu0>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2402,7 +2902,7 @@ etm0_out: endpoint { etm@6140000 { compatible = "arm,primecell"; reg = <0x0 0x6140000 0x0 0x1000>; - cpu = <&CPU1>; + cpu = <&cpu1>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2422,7 +2922,7 @@ etm1_out: endpoint { etm@6240000 { compatible = "arm,primecell"; reg = <0x0 0x6240000 0x0 0x1000>; - cpu = <&CPU2>; + cpu = <&cpu2>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2442,7 +2942,7 @@ etm2_out: endpoint { etm@6340000 { compatible = "arm,primecell"; reg = <0x0 0x6340000 0x0 0x1000>; - cpu = <&CPU3>; + cpu = <&cpu3>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2462,7 +2962,7 @@ etm3_out: endpoint { etm@6440000 { compatible = "arm,primecell"; reg = <0x0 0x6440000 0x0 0x1000>; - cpu = <&CPU4>; + cpu = <&cpu4>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2482,7 +2982,7 @@ etm4_out: endpoint { etm@6540000 { compatible = "arm,primecell"; reg = <0x0 0x6540000 0x0 0x1000>; - cpu = <&CPU5>; + cpu = <&cpu5>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2502,7 +3002,7 @@ etm5_out: endpoint { etm@6640000 { compatible = "arm,primecell"; reg = <0x0 0x6640000 0x0 0x1000>; - cpu = <&CPU6>; + cpu = <&cpu6>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2522,7 +3022,7 @@ etm6_out: endpoint { etm@6740000 { compatible = "arm,primecell"; reg = <0x0 0x6740000 0x0 0x1000>; - cpu = <&CPU7>; + cpu = <&cpu7>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3072,6 +3572,11 @@ tcsr_mutex: hwlock@1f40000 { #hwlock-cells = <1>; }; + tcsr: syscon@1fc0000 { + compatible = "qcom,sa8775p-tcsr", "syscon"; + reg = <0x0 0x1fc0000 0x0 0x30000>; + }; + gpucc: clock-controller@3d90000 { compatible = "qcom,sa8775p-gpucc"; reg = <0x0 0x03d90000 0x0 0xa000>; @@ -5570,7 +6075,7 @@ pcie0: pcie@1c00000 { status = "disabled"; - pcie@0 { + pcieport0: pcie@0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; bus-range = <0x01 0xff>; @@ -5624,6 +6129,7 @@ pcie0_ep: pcie-ep@1c00000 { phy-names = "pciephy"; max-link-speed = <3>; /* FIXME: Limiting the Gen speed due to stability issues */ num-lanes = <2>; + linux,pci-domain = <0>; status = "disabled"; }; @@ -5781,6 +6287,7 @@ pcie1_ep: pcie-ep@1c10000 { phy-names = "pciephy"; max-link-speed = <3>; /* FIXME: Limiting the Gen speed due to stability issues */ num-lanes = <4>; + linux,pci-domain = <1>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-firmware-tfa.dtsi b/arch/arm64/boot/dts/qcom/sc7180-firmware-tfa.dtsi index ee35a454dbf6f3..59162b3afcb841 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-firmware-tfa.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-firmware-tfa.dtsi @@ -6,82 +6,82 @@ * by Qualcomm firmware. */ -&CPU0 { +&cpu0 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU1 { +&cpu1 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU2 { +&cpu2 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU3 { +&cpu3 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU4 { +&cpu4 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU5 { +&cpu5 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU6 { +&cpu6 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&BIG_CPU_SLEEP_0 - &BIG_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&big_cpu_sleep_0 + &big_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU7 { +&cpu7 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&BIG_CPU_SLEEP_0 - &BIG_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&big_cpu_sleep_0 + &big_cpu_sleep_1 + &cluster_sleep_0>; }; /delete-node/ &domain_idle_states; &idle_states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "arm,idle-state"; idle-state-name = "cluster-power-down"; arm,psci-suspend-param = <0x40003444>; @@ -92,15 +92,15 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { }; }; -/delete-node/ &CPU_PD0; -/delete-node/ &CPU_PD1; -/delete-node/ &CPU_PD2; -/delete-node/ &CPU_PD3; -/delete-node/ &CPU_PD4; -/delete-node/ &CPU_PD5; -/delete-node/ &CPU_PD6; -/delete-node/ &CPU_PD7; -/delete-node/ &CLUSTER_PD; +/delete-node/ &cpu_pd0; +/delete-node/ &cpu_pd1; +/delete-node/ &cpu_pd2; +/delete-node/ &cpu_pd3; +/delete-node/ &cpu_pd4; +/delete-node/ &cpu_pd5; +/delete-node/ &cpu_pd6; +/delete-node/ &cpu_pd7; +/delete-node/ &cluster_pd; &apps_rsc { /delete-property/ power-domains; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi index 3c124bbe2f4c94..25b17b0425f24e 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-coachz.dtsi @@ -53,14 +53,14 @@ skin-temp-crit { cooling-maps { map0 { trip = <&skin_temp_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&skin_temp_alert1>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi index b2df22faafe889..f57976906d6304 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi @@ -71,14 +71,14 @@ skin-temp-crit { cooling-maps { map0 { trip = <&skin_temp_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&skin_temp_alert1>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi index af89d80426abbd..d4925be3b1fcf5 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-wormdingler.dtsi @@ -78,14 +78,14 @@ skin-temp-crit { cooling-maps { map0 { trip = <&skin_temp_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&skin_temp_alert1>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index b5ebf898032512..76fe314d2ad50d 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -77,28 +77,28 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo468"; reg = <0x0 0x0>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; capacity-dmips-mhz = <415>; dynamic-power-coefficient = <137>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 0>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -106,206 +106,206 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo468"; reg = <0x0 0x100>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; capacity-dmips-mhz = <415>; dynamic-power-coefficient = <137>; - next-level-cache = <&L2_100>; + next-level-cache = <&l2_100>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 0>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo468"; reg = <0x0 0x200>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; capacity-dmips-mhz = <415>; dynamic-power-coefficient = <137>; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 0>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo468"; reg = <0x0 0x300>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; capacity-dmips-mhz = <415>; dynamic-power-coefficient = <137>; - next-level-cache = <&L2_300>; + next-level-cache = <&l2_300>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 0>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo468"; reg = <0x0 0x400>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; capacity-dmips-mhz = <415>; dynamic-power-coefficient = <137>; - next-level-cache = <&L2_400>; + next-level-cache = <&l2_400>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 0>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo468"; reg = <0x0 0x500>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; capacity-dmips-mhz = <415>; dynamic-power-coefficient = <137>; - next-level-cache = <&L2_500>; + next-level-cache = <&l2_500>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 0>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo468"; reg = <0x0 0x600>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <480>; - next-level-cache = <&L2_600>; + next-level-cache = <&l2_600>; operating-points-v2 = <&cpu6_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 1>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo468"; reg = <0x0 0x700>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <480>; - next-level-cache = <&L2_700>; + next-level-cache = <&l2_700>; operating-points-v2 = <&cpu6_opp_table>; interconnects = <&gem_noc MASTER_APPSS_PROC 3 &mc_virt SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; qcom,freq-domain = <&cpufreq_hw 1>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -313,7 +313,7 @@ core7 { idle_states: idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-power-down"; arm,psci-suspend-param = <0x40000003>; @@ -323,7 +323,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { + little_cpu_sleep_1: cpu-sleep-0-1 { compatible = "arm,idle-state"; idle-state-name = "little-rail-power-down"; arm,psci-suspend-param = <0x40000004>; @@ -333,7 +333,7 @@ LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-power-down"; arm,psci-suspend-param = <0x40000003>; @@ -343,7 +343,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { local-timer-stop; }; - BIG_CPU_SLEEP_1: cpu-sleep-1-1 { + big_cpu_sleep_1: cpu-sleep-1-1 { compatible = "arm,idle-state"; idle-state-name = "big-rail-power-down"; arm,psci-suspend-param = <0x40000004>; @@ -355,27 +355,24 @@ BIG_CPU_SLEEP_1: cpu-sleep-1-1 { }; domain_idle_states: domain-idle-states { - CLUSTER_SLEEP_PC: cluster-sleep-0 { + cluster_sleep_pc: cluster-sleep-0 { compatible = "domain-idle-state"; - idle-state-name = "cluster-l3-power-collapse"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <2752>; exit-latency-us = <3048>; min-residency-us = <6118>; }; - CLUSTER_SLEEP_CX_RET: cluster-sleep-1 { + cluster_sleep_cx_ret: cluster-sleep-1 { compatible = "domain-idle-state"; - idle-state-name = "cluster-cx-retention"; arm,psci-suspend-param = <0x41001244>; entry-latency-us = <3638>; exit-latency-us = <4562>; min-residency-us = <8467>; }; - CLUSTER_AOSS_SLEEP: cluster-sleep-2 { + cluster_aoss_sleep: cluster-sleep-2 { compatible = "domain-idle-state"; - idle-state-name = "cluster-power-down"; arm,psci-suspend-param = <0x4100b244>; entry-latency-us = <3263>; exit-latency-us = <6562>; @@ -583,59 +580,59 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: cpu0 { + cpu_pd0: cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD1: cpu1 { + cpu_pd1: cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD2: cpu2 { + cpu_pd2: cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD3: cpu3 { + cpu_pd3: cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD4: cpu4 { + cpu_pd4: cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD5: cpu5 { + cpu_pd5: cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD6: cpu6 { + cpu_pd6: cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CPU_PD7: cpu7 { + cpu_pd7: cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CLUSTER_PD: cpu-cluster0 { + cluster_pd: cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_PC - &CLUSTER_SLEEP_CX_RET - &CLUSTER_AOSS_SLEEP>; + domain-idle-states = <&cluster_sleep_pc + &cluster_sleep_cx_ret + &cluster_aoss_sleep>; }; }; @@ -2546,7 +2543,7 @@ etm@7040000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07040000 0 0x1000>; - cpu = <&CPU0>; + cpu = <&cpu0>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2566,7 +2563,7 @@ etm@7140000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07140000 0 0x1000>; - cpu = <&CPU1>; + cpu = <&cpu1>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2586,7 +2583,7 @@ etm@7240000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07240000 0 0x1000>; - cpu = <&CPU2>; + cpu = <&cpu2>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2606,7 +2603,7 @@ etm@7340000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07340000 0 0x1000>; - cpu = <&CPU3>; + cpu = <&cpu3>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2626,7 +2623,7 @@ etm@7440000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07440000 0 0x1000>; - cpu = <&CPU4>; + cpu = <&cpu4>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2646,7 +2643,7 @@ etm@7540000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07540000 0 0x1000>; - cpu = <&CPU5>; + cpu = <&cpu5>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2666,7 +2663,7 @@ etm@7640000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07640000 0 0x1000>; - cpu = <&CPU6>; + cpu = <&cpu6>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -2686,7 +2683,7 @@ etm@7740000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07740000 0 0x1000>; - cpu = <&CPU7>; + cpu = <&cpu7>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3625,6 +3622,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; intc: interrupt-controller@17a00000 { @@ -3734,7 +3732,7 @@ apps_rsc: rsc@18200000 { , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; rpmhcc: clock-controller { compatible = "qcom,sc7180-rpmh-clk"; @@ -4063,21 +4061,21 @@ cpu0_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu0_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu0_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4111,21 +4109,21 @@ cpu1_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu1_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu1_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4159,21 +4157,21 @@ cpu2_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu2_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu2_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4207,21 +4205,21 @@ cpu3_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu3_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu3_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4255,21 +4253,21 @@ cpu4_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu4_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu4_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4303,21 +4301,21 @@ cpu5_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu5_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu5_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4351,13 +4349,13 @@ cpu6_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu6_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu6_alert1>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4391,13 +4389,13 @@ cpu7_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu7_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu7_alert1>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4431,13 +4429,13 @@ cpu8_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu8_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu8_alert1>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4471,13 +4469,13 @@ cpu9_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu9_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu9_alert1>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi index cecb3e89f7f7b2..8b4239f13748fe 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi @@ -29,7 +29,7 @@ / { cpus { domain_idle_states: domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x40003444>; entry-latency-us = <2752>; @@ -52,8 +52,12 @@ venus_mem: memory@8b200000 { }; }; -&CLUSTER_PD { - domain-idle-states = <&CLUSTER_SLEEP_0>; +&cluster_pd { + domain-idle-states = <&cluster_sleep_0>; +}; + +&gpu { + status = "okay"; }; &lpass_aon { diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 3d8410683402fd..55db1c83ef5517 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -193,15 +193,15 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x0>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; operating-points-v2 = <&cpu0_opp_table>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; @@ -209,12 +209,12 @@ CPU0: cpu@0 { <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -222,15 +222,15 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x100>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; - next-level-cache = <&L2_100>; + next-level-cache = <&l2_100>; operating-points-v2 = <&cpu0_opp_table>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; @@ -238,23 +238,23 @@ CPU1: cpu@100 { <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x200>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; operating-points-v2 = <&cpu0_opp_table>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; @@ -262,23 +262,23 @@ CPU2: cpu@200 { <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x300>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; - next-level-cache = <&L2_300>; + next-level-cache = <&l2_300>; operating-points-v2 = <&cpu0_opp_table>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; @@ -286,23 +286,23 @@ CPU3: cpu@300 { <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x400>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; - next-level-cache = <&L2_400>; + next-level-cache = <&l2_400>; operating-points-v2 = <&cpu4_opp_table>; capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <520>; @@ -310,23 +310,23 @@ CPU4: cpu@400 { <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x500>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; - next-level-cache = <&L2_500>; + next-level-cache = <&l2_500>; operating-points-v2 = <&cpu4_opp_table>; capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <520>; @@ -334,23 +334,23 @@ CPU5: cpu@500 { <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x600>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; - next-level-cache = <&L2_600>; + next-level-cache = <&l2_600>; operating-points-v2 = <&cpu4_opp_table>; capacity-dmips-mhz = <1946>; dynamic-power-coefficient = <520>; @@ -358,23 +358,23 @@ CPU6: cpu@600 { <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo"; reg = <0x0 0x700>; clocks = <&cpufreq_hw 2>; enable-method = "psci"; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; - next-level-cache = <&L2_700>; + next-level-cache = <&l2_700>; operating-points-v2 = <&cpu7_opp_table>; capacity-dmips-mhz = <1985>; dynamic-power-coefficient = <552>; @@ -382,46 +382,46 @@ CPU7: cpu@700 { <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; qcom,freq-domain = <&cpufreq_hw 2>; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -429,7 +429,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-power-down"; arm,psci-suspend-param = <0x40000003>; @@ -439,7 +439,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { + little_cpu_sleep_1: cpu-sleep-0-1 { compatible = "arm,idle-state"; idle-state-name = "little-rail-power-down"; arm,psci-suspend-param = <0x40000004>; @@ -449,7 +449,7 @@ LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-power-down"; arm,psci-suspend-param = <0x40000003>; @@ -459,7 +459,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { local-timer-stop; }; - BIG_CPU_SLEEP_1: cpu-sleep-1-1 { + big_cpu_sleep_1: cpu-sleep-1-1 { compatible = "arm,idle-state"; idle-state-name = "big-rail-power-down"; arm,psci-suspend-param = <0x40000004>; @@ -471,7 +471,7 @@ BIG_CPU_SLEEP_1: cpu-sleep-1-1 { }; domain_idle_states: domain-idle-states { - CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 { + cluster_sleep_apss_off: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <2752>; @@ -479,7 +479,7 @@ CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 { min-residency-us = <6118>; }; - CLUSTER_SLEEP_CX_RET: cluster-sleep-1 { + cluster_sleep_cx_ret: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41001344>; entry-latency-us = <3263>; @@ -487,7 +487,7 @@ CLUSTER_SLEEP_CX_RET: cluster-sleep-1 { min-residency-us = <8467>; }; - CLUSTER_SLEEP_LLCC_OFF: cluster-sleep-2 { + cluster_sleep_llcc_off: cluster-sleep-2 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100b344>; entry-latency-us = <3638>; @@ -845,8 +845,13 @@ wlan_smp2p_in: wlan-wpss-to-ap { }; }; - pmu { - compatible = "arm,armv8-pmuv3"; + pmu-a55 { + compatible = "arm,cortex-a55-pmu"; + interrupts = ; + }; + + pmu-a78 { + compatible = "arm,cortex-a78-pmu"; interrupts = ; }; @@ -854,57 +859,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CLUSTER_PD: power-domain-cluster { + cluster_pd: power-domain-cluster { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_APSS_OFF &CLUSTER_SLEEP_CX_RET &CLUSTER_SLEEP_LLCC_OFF>; + domain-idle-states = <&cluster_sleep_apss_off &cluster_sleep_cx_ret &cluster_sleep_llcc_off>; }; }; @@ -2318,7 +2323,7 @@ pcie1_phy: phy@1c0e000 { status = "disabled"; }; - ufs_mem_hc: ufs@1d84000 { + ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,sc7280-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x01d84000 0x0 0x3000>; @@ -2718,7 +2723,7 @@ slimbam: dma-controller@3a84000 { interrupts = ; #dma-cells = <1>; qcom,controlled-remotely; - num-channels = <31>; + num-channels = <31>; qcom,ee = <1>; qcom,num-ees = <2>; iommus = <&apps_smmu 0x1826 0x0>; @@ -2823,6 +2828,8 @@ gpu: gpu@3d00000 { nvmem-cells = <&gpu_speed_bin>; nvmem-cell-names = "speed_bin"; + status = "disabled"; + gpu_zap_shader: zap-shader { memory-region = <&gpu_zap_mem>; }; @@ -2834,14 +2841,14 @@ opp-315000000 { opp-hz = /bits/ 64 <315000000>; opp-level = ; opp-peak-kBps = <1804000>; - opp-supported-hw = <0x07>; + opp-supported-hw = <0x17>; }; opp-450000000 { opp-hz = /bits/ 64 <450000000>; opp-level = ; opp-peak-kBps = <4068000>; - opp-supported-hw = <0x07>; + opp-supported-hw = <0x17>; }; /* Only applicable for SKUs which has 550Mhz as Fmax */ @@ -2856,14 +2863,14 @@ opp-550000000-1 { opp-hz = /bits/ 64 <550000000>; opp-level = ; opp-peak-kBps = <6832000>; - opp-supported-hw = <0x06>; + opp-supported-hw = <0x16>; }; opp-608000000 { opp-hz = /bits/ 64 <608000000>; opp-level = ; opp-peak-kBps = <8368000>; - opp-supported-hw = <0x06>; + opp-supported-hw = <0x16>; }; opp-700000000 { @@ -3278,7 +3285,7 @@ etm@7040000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07040000 0 0x1000>; - cpu = <&CPU0>; + cpu = <&cpu0>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3298,7 +3305,7 @@ etm@7140000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07140000 0 0x1000>; - cpu = <&CPU1>; + cpu = <&cpu1>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3318,7 +3325,7 @@ etm@7240000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07240000 0 0x1000>; - cpu = <&CPU2>; + cpu = <&cpu2>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3338,7 +3345,7 @@ etm@7340000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07340000 0 0x1000>; - cpu = <&CPU3>; + cpu = <&cpu3>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3358,7 +3365,7 @@ etm@7440000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07440000 0 0x1000>; - cpu = <&CPU4>; + cpu = <&cpu4>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3378,7 +3385,7 @@ etm@7540000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07540000 0 0x1000>; - cpu = <&CPU5>; + cpu = <&cpu5>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3398,7 +3405,7 @@ etm@7640000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07640000 0 0x1000>; - cpu = <&CPU6>; + cpu = <&cpu6>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3418,7 +3425,7 @@ etm@7740000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07740000 0 0x1000>; - cpu = <&CPU7>; + cpu = <&cpu7>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -6057,7 +6064,7 @@ apps_rsc: rsc@18200000 { , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; @@ -6177,17 +6184,17 @@ cpu0_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu0_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu0_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6220,17 +6227,17 @@ cpu1_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu1_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu1_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6263,17 +6270,17 @@ cpu2_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu2_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu2_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6306,17 +6313,17 @@ cpu3_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu3_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu3_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6349,17 +6356,17 @@ cpu4_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu4_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu4_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6392,17 +6399,17 @@ cpu5_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu5_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu5_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6435,17 +6442,17 @@ cpu6_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu6_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu6_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6478,17 +6485,17 @@ cpu7_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu7_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu7_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6521,17 +6528,17 @@ cpu8_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu8_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu8_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6564,17 +6571,17 @@ cpu9_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu9_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu9_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6607,17 +6614,17 @@ cpu10_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu10_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu10_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6650,17 +6657,17 @@ cpu11_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu11_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu11_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi index 0e9429684dd97b..745a7d0b838104 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi @@ -42,28 +42,28 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x0>; enable-method = "psci"; capacity-dmips-mhz = <602>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 3 &mc_virt SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; #cooling-cells = <2>; clocks = <&cpufreq_hw 0>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -71,207 +71,207 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x100>; enable-method = "psci"; capacity-dmips-mhz = <602>; - next-level-cache = <&L2_100>; + next-level-cache = <&l2_100>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 3 &mc_virt SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; #cooling-cells = <2>; clocks = <&cpufreq_hw 0>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x200>; enable-method = "psci"; capacity-dmips-mhz = <602>; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 3 &mc_virt SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; #cooling-cells = <2>; clocks = <&cpufreq_hw 0>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x300>; enable-method = "psci"; capacity-dmips-mhz = <602>; - next-level-cache = <&L2_300>; + next-level-cache = <&l2_300>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 3 &mc_virt SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; #cooling-cells = <2>; clocks = <&cpufreq_hw 0>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-unified; cache-level = <2>; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x400>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_400>; + next-level-cache = <&l2_400>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 3 &mc_virt SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; #cooling-cells = <2>; clocks = <&cpufreq_hw 1>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-unified; cache-level = <2>; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x500>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_500>; + next-level-cache = <&l2_500>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 3 &mc_virt SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; #cooling-cells = <2>; clocks = <&cpufreq_hw 1>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-unified; cache-level = <2>; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x600>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_600>; + next-level-cache = <&l2_600>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 3 &mc_virt SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; #cooling-cells = <2>; clocks = <&cpufreq_hw 1>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-unified; cache-level = <2>; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x700>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_700>; + next-level-cache = <&l2_700>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 3 &mc_virt SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; #cooling-cells = <2>; clocks = <&cpufreq_hw 1>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-unified; cache-level = <2>; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -279,7 +279,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; arm,psci-suspend-param = <0x40000004>; entry-latency-us = <355>; @@ -288,7 +288,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; arm,psci-suspend-param = <0x40000004>; entry-latency-us = <2411>; @@ -299,7 +299,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 { + cluster_sleep_apss_off: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <3300>; @@ -307,7 +307,7 @@ CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 { min-residency-us = <6000>; }; - CLUSTER_SLEEP_AOSS_SLEEP: cluster-sleep-1 { + cluster_sleep_aoss_sleep: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100a344>; entry-latency-us = <3263>; @@ -541,57 +541,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_APSS_OFF &CLUSTER_SLEEP_AOSS_SLEEP>; + domain-idle-states = <&cluster_sleep_apss_off &cluster_sleep_aoss_sleep>; }; }; @@ -3662,7 +3662,7 @@ apps_smmu: iommu@15000000 { , , ; - + dma-coherent; }; remoteproc_adsp: remoteproc@17300000 { @@ -3790,7 +3790,7 @@ apps_rsc: rsc@18200000 { , ; label = "apps_rsc"; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; @@ -3868,7 +3868,7 @@ lmh@18350800 { compatible = "qcom,sc8180x-lmh"; reg = <0 0x18350800 0 0x400>; interrupts = ; - cpus = <&CPU4>; + cpus = <&cpu4>; qcom,lmh-temp-arm-millicelsius = <65000>; qcom,lmh-temp-low-millicelsius = <94500>; qcom,lmh-temp-high-millicelsius = <95000>; @@ -3880,7 +3880,7 @@ lmh@18358800 { compatible = "qcom,sc8180x-lmh"; reg = <0 0x18358800 0 0x400>; interrupts = ; - cpus = <&CPU0>; + cpus = <&cpu0>; qcom,lmh-temp-arm-millicelsius = <65000>; qcom,lmh-temp-low-millicelsius = <94500>; qcom,lmh-temp-high-millicelsius = <95000>; @@ -3889,7 +3889,7 @@ lmh@18358800 { }; cpufreq_hw: cpufreq@18323000 { - compatible = "qcom,cpufreq-hw"; + compatible = "qcom,sc8180x-cpufreq-hw", "qcom,cpufreq-hw"; reg = <0 0x18323000 0 0x1400>, <0 0x18325800 0 0x1400>; reg-names = "freq-domain0", "freq-domain1"; diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts index 6020582b0a59d7..75adaa19d1c3e0 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts @@ -20,6 +20,7 @@ aliases { i2c4 = &i2c4; i2c21 = &i2c21; serial0 = &uart17; + serial1 = &uart2; }; backlight: backlight { @@ -260,6 +261,70 @@ usb1_sbu_mux: endpoint { }; }; }; + + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + pinctrl-0 = <&bt_en>, <&wlan_en>; + pinctrl-names = "default"; + + wlan-enable-gpios = <&tlmm 134 GPIO_ACTIVE_HIGH>; + bt-enable-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>; + swctrl-gpios = <&tlmm 132 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&vreg_s10b>; + vddaon-supply = <&vreg_s12b>; + vddpmu-supply = <&vreg_s12b>; + vddpmumx-supply = <&vreg_s12b>; + vddpmucx-supply = <&vreg_s12b>; + vddrfa0p95-supply = <&vreg_s12b>; + vddrfa1p3-supply = <&vreg_s11b>; + vddrfa1p9-supply = <&vreg_s1c>; + vddpcie1p3-supply = <&vreg_s11b>; + vddpcie1p9-supply = <&vreg_s1c>; + + regulators { + vreg_pmu_rfa_cmn_0p8: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn_0p8"; + }; + + vreg_pmu_aon_0p8: ldo1 { + regulator-name = "vreg_pmu_aon_0p8"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p8: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p8"; + }; + + vreg_pmu_btcmx_0p8: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p8"; + }; + + vreg_pmu_pcie_1p8: ldo5 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + + vreg_pmu_pcie_0p9: ldo6 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_rfa_0p8: ldo7 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo8 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p7: ldo9 { + regulator-name = "vreg_pmu_rfa_1p7"; + }; + }; + }; }; &apps_rsc { @@ -269,6 +334,15 @@ regulators-0 { vdd-l3-l5-supply = <&vreg_s11b>; + vreg_s10b: smps10 { + regulator-name = "vreg_s10b"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-always-on; + regulator-boot-on; + }; + vreg_s11b: smps11 { regulator-name = "vreg_s11b"; regulator-min-microvolt = <1272000>; @@ -276,6 +350,13 @@ vreg_s11b: smps11 { regulator-initial-mode = ; }; + vreg_s12b: smps12 { + regulator-name = "vreg_s12b"; + regulator-min-microvolt = <984000>; + regulator-max-microvolt = <984000>; + regulator-initial-mode = ; + }; + vreg_l3b: ldo3 { regulator-name = "vreg_l3b"; regulator-min-microvolt = <1200000>; @@ -304,6 +385,13 @@ regulators-1 { compatible = "qcom,pm8350c-rpmh-regulators"; qcom,pmic-id = "c"; + vreg_s1c: smps1 { + regulator-name = "vreg_s1c"; + regulator-min-microvolt = <1888000>; + regulator-max-microvolt = <1888000>; + regulator-initial-mode = ; + }; + vreg_l1c: ldo1 { regulator-name = "vreg_l1c"; regulator-min-microvolt = <1800000>; @@ -583,6 +671,25 @@ &pcie4_phy { status = "okay"; }; +&pcie4_port0 { + wifi@0 { + compatible = "pci17cb,1103"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>; + vddaon-supply = <&vreg_pmu_aon_0p8>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p8>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + + qcom,ath11k-calibration-variant = "QC_8280XP_CRD"; + }; +}; + &pmc8280c_lpg { status = "okay"; }; @@ -643,6 +750,26 @@ &sdc2 { status = "okay"; }; +&uart2 { + pinctrl-0 = <&uart2_default>; + pinctrl-names = "default"; + + status = "okay"; + + bluetooth { + compatible = "qcom,wcn6855-bt"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>; + vddaon-supply = <&vreg_pmu_aon_0p8>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p8>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p8>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + }; +}; + &uart17 { compatible = "qcom,geni-debug-uart"; @@ -788,6 +915,13 @@ hastings_reg_en: hastings-reg-en-state { &tlmm { gpio-reserved-ranges = <74 6>, <83 4>, <125 2>, <128 2>, <154 7>; + bt_en: bt-en-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + edp_reg_en: edp-reg-en-state { pins = "gpio25"; function = "gpio"; @@ -981,6 +1115,34 @@ reset-n-pins { }; }; + uart2_default: uart2-default-state { + cts-pins { + pins = "gpio121"; + function = "qup2"; + bias-bus-hold; + }; + + rts-pins { + pins = "gpio122"; + function = "qup2"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio124"; + function = "qup2"; + bias-pull-up; + }; + + tx-pins { + pins = "gpio123"; + function = "qup2"; + drive-strength = <2>; + bias-disable; + }; + }; + usb0_sbu_default: usb0-sbu-state { oe-n-pins { pins = "gpio101"; @@ -1030,4 +1192,11 @@ mode-pins { output-high; }; }; + + wlan_en: wlan-en-state { + pins = "gpio134"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts index 6a28cab971891d..f3190f408f4b2c 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts @@ -346,18 +346,18 @@ skin-temp-crit { cooling-maps { map0 { trip = <&skin_temp_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&skin_temp_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -400,6 +400,70 @@ usb1_sbu_mux: endpoint { }; }; }; + + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + pinctrl-0 = <&bt_default>, <&wlan_en>; + pinctrl-names = "default"; + + wlan-enable-gpios = <&tlmm 134 GPIO_ACTIVE_HIGH>; + bt-enable-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>; + swctrl-gpios = <&tlmm 132 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&vreg_s10b>; + vddaon-supply = <&vreg_s12b>; + vddpmu-supply = <&vreg_s12b>; + vddpmumx-supply = <&vreg_s12b>; + vddpmucx-supply = <&vreg_s12b>; + vddrfa0p95-supply = <&vreg_s12b>; + vddrfa1p3-supply = <&vreg_s11b>; + vddrfa1p9-supply = <&vreg_s1c>; + vddpcie1p3-supply = <&vreg_s11b>; + vddpcie1p9-supply = <&vreg_s1c>; + + regulators { + vreg_pmu_rfa_cmn_0p8: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn_0p8"; + }; + + vreg_pmu_aon_0p8: ldo1 { + regulator-name = "vreg_pmu_aon_0p8"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p8: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p8"; + }; + + vreg_pmu_btcmx_0p8: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p8"; + }; + + vreg_pmu_pcie_1p8: ldo5 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + + vreg_pmu_pcie_0p9: ldo6 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_rfa_0p8: ldo7 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo8 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p7: ldo9 { + regulator-name = "vreg_pmu_rfa_1p7"; + }; + }; + }; }; &apps_rsc { @@ -426,7 +490,6 @@ vreg_s11b: smps11 { regulator-min-microvolt = <1272000>; regulator-max-microvolt = <1272000>; regulator-initial-mode = ; - regulator-always-on; }; vreg_s12b: smps12 { @@ -434,7 +497,6 @@ vreg_s12b: smps12 { regulator-min-microvolt = <984000>; regulator-max-microvolt = <984000>; regulator-initial-mode = ; - regulator-always-on; }; vreg_l1b: ldo1 { @@ -633,7 +695,6 @@ camera@10 { port { ov5675_ep: endpoint { - clock-lanes = <0>; data-lanes = <1 2>; link-frequencies = /bits/ 64 <450000000>; remote-endpoint = <&csiphy0_lanes01_ep>; @@ -927,6 +988,16 @@ wifi@0 { compatible = "pci17cb,1103"; reg = <0x10000 0x0 0x0 0x0 0x0>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>; + vddaon-supply = <&vreg_pmu_aon_0p8>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p8>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + qcom,ath11k-calibration-variant = "LE_X13S"; }; }; @@ -1258,20 +1329,16 @@ &uart2 { bluetooth { compatible = "qcom,wcn6855-bt"; - vddio-supply = <&vreg_s10b>; - vddbtcxmx-supply = <&vreg_s12b>; - vddrfacmn-supply = <&vreg_s12b>; - vddrfa0p8-supply = <&vreg_s12b>; - vddrfa1p2-supply = <&vreg_s11b>; - vddrfa1p7-supply = <&vreg_s1c>; + vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>; + vddaon-supply = <&vreg_pmu_aon_0p8>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p8>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p8>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; max-speed = <3200000>; - - enable-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>; - swctrl-gpios = <&tlmm 132 GPIO_ACTIVE_HIGH>; - - pinctrl-0 = <&bt_default>; - pinctrl-names = "default"; }; }; @@ -1761,4 +1828,11 @@ reset-pins { bias-disable; }; }; + + wlan_en: wlan-en-state { + pins = "gpio134"; + function = "gpio"; + drive-strength = <8>; + bias-pull-down; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-arcata.dts b/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-arcata.dts new file mode 100644 index 00000000000000..ae5daeac8fe284 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sc8280xp-microsoft-arcata.dts @@ -0,0 +1,1032 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2024, Jérôme de Bretagne + */ + +/dts-v1/; + +#include +#include + +#include "sc8280xp.dtsi" +#include "sc8280xp-pmics.dtsi" + +/ { + model = "Microsoft Surface Pro 9 5G"; + compatible = "microsoft,arcata", "qcom,sc8280xp"; + + aliases { + serial0 = &uart18; + serial1 = &uart2; + }; + + wcd938x: audio-codec { + compatible = "qcom,wcd9380-codec"; + + pinctrl-0 = <&wcd_default>; + pinctrl-names = "default"; + + reset-gpios = <&tlmm 106 GPIO_ACTIVE_LOW>; + + vdd-buck-supply = <&vreg_s10b>; + vdd-rxtx-supply = <&vreg_s10b>; + vdd-io-supply = <&vreg_s10b>; + vdd-mic-bias-supply = <&vreg_bob>; + + qcom,micbias1-microvolt = <1800000>; + qcom,micbias2-microvolt = <1800000>; + qcom,micbias3-microvolt = <1800000>; + qcom,micbias4-microvolt = <1800000>; + qcom,mbhc-buttons-vthreshold-microvolt = <75000 150000 237000 500000 500000 500000 500000 500000>; + qcom,mbhc-headset-vthreshold-microvolt = <1700000>; + qcom,mbhc-headphone-vthreshold-microvolt = <50000>; + qcom,rx-device = <&wcd_rx>; + qcom,tx-device = <&wcd_tx>; + + #sound-dai-cells = <1>; + }; + + pmic-glink { + compatible = "qcom,sc8280xp-pmic-glink", "qcom,pmic-glink"; + + #address-cells = <1>; + #size-cells = <0>; + + /* Left-side top port */ + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_con0_hs: endpoint { + remote-endpoint = <&usb_0_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_con0_ss: endpoint { + remote-endpoint = <&usb_0_qmpphy_out>; + }; + }; + + port@2 { + reg = <2>; + + pmic_glink_con0_sbu: endpoint { + remote-endpoint = <&usb0_sbu_mux>; + }; + }; + }; + }; + + /* Left-side bottom port */ + connector@1 { + compatible = "usb-c-connector"; + reg = <1>; + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_con1_hs: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_con1_ss: endpoint { + remote-endpoint = <&usb_1_qmpphy_out>; + }; + }; + + port@2 { + reg = <2>; + + pmic_glink_con1_sbu: endpoint { + remote-endpoint = <&usb1_sbu_mux>; + }; + }; + }; + }; + }; + + vreg_nvme: regulator-nvme { + compatible = "regulator-fixed"; + + regulator-name = "VCC3_SSD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&tlmm 135 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&nvme_reg_en>; + pinctrl-names = "default"; + + regulator-boot-on; + }; + + vreg_vph_pwr: regulator-vph-pwr { + compatible = "regulator-fixed"; + + regulator-name = "VPH_VCC3R9"; + regulator-min-microvolt = <3900000>; + regulator-max-microvolt = <3900000>; + + regulator-always-on; + }; + + vreg_wlan: regulator-wlan { + compatible = "regulator-fixed"; + + regulator-name = "VCC_WLAN_3R9"; + regulator-min-microvolt = <3900000>; + regulator-max-microvolt = <3900000>; + + gpio = <&pmr735a_gpios 1 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&hastings_reg_en>; + pinctrl-names = "default"; + + regulator-boot-on; + }; + + vreg_wwan: regulator-wwan { + compatible = "regulator-fixed"; + + regulator-name = "VCC3B_WAN"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&pmc8280_2_gpios 1 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&wwan_sw_en>; + pinctrl-names = "default"; + + regulator-boot-on; + }; + + reserved-memory { + gpu_mem: gpu-mem@8bf00000 { + reg = <0 0x8bf00000 0 0x2000>; + no-map; + }; + + linux,cma { + compatible = "shared-dma-pool"; + size = <0x0 0x8000000>; + reusable; + linux,cma-default; + }; + }; + + thermal-zones { + skin-temp-thermal { + polling-delay-passive = <250>; + + thermal-sensors = <&pmk8280_adc_tm 5>; + + trips { + skin_temp_alert0: trip-point0 { + temperature = <55000>; + hysteresis = <1000>; + type = "passive"; + }; + + skin_temp_alert1: trip-point1 { + temperature = <58000>; + hysteresis = <1000>; + type = "passive"; + }; + + skin-temp-crit { + temperature = <73000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&skin_temp_alert0>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + + map1 { + trip = <&skin_temp_alert1>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; + + usb0-sbu-mux { + compatible = "pericom,pi3usb102", "gpio-sbu-mux"; + + enable-gpios = <&tlmm 101 GPIO_ACTIVE_LOW>; + select-gpios = <&tlmm 164 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&usb0_sbu_default>; + pinctrl-names = "default"; + + mode-switch; + orientation-switch; + + port { + usb0_sbu_mux: endpoint { + remote-endpoint = <&pmic_glink_con0_sbu>; + }; + }; + }; + + usb1-sbu-mux { + compatible = "pericom,pi3usb102", "gpio-sbu-mux"; + + enable-gpios = <&tlmm 48 GPIO_ACTIVE_LOW>; + select-gpios = <&tlmm 47 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&usb1_sbu_default>; + pinctrl-names = "default"; + + mode-switch; + orientation-switch; + + port { + usb1_sbu_mux: endpoint { + remote-endpoint = <&pmic_glink_con1_sbu>; + }; + }; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8350-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-l1-l4-supply = <&vreg_s12b>; + vdd-l2-l7-supply = <&vreg_bob>; + vdd-l3-l5-supply = <&vreg_s11b>; + vdd-l6-l9-l10-supply = <&vreg_s12b>; + vdd-l8-supply = <&vreg_s12b>; + + vreg_s10b: smps10 { + regulator-name = "vreg_s10b"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-always-on; + }; + + vreg_s11b: smps11 { + regulator-name = "vreg_s11b"; + regulator-min-microvolt = <1272000>; + regulator-max-microvolt = <1272000>; + regulator-initial-mode = ; + regulator-always-on; + }; + + vreg_s12b: smps12 { + regulator-name = "vreg_s12b"; + regulator-min-microvolt = <984000>; + regulator-max-microvolt = <984000>; + regulator-initial-mode = ; + regulator-always-on; + }; + + vreg_l3b: ldo3 { + regulator-name = "vreg_l3b"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-boot-on; + }; + + vreg_l4b: ldo4 { + regulator-name = "vreg_l4b"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + }; + + vreg_l6b: ldo6 { + regulator-name = "vreg_l6b"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + regulator-boot-on; + regulator-always-on; // FIXME: VDD_A_EDP_0_0P9 + }; + }; + + regulators-1 { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-bob-supply = <&vreg_vph_pwr>; + vdd-l1-l12-supply = <&vreg_s1c>; + vdd-l2-l8-supply = <&vreg_s1c>; + vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>; + vdd-l6-l9-l11-supply = <&vreg_bob>; + vdd-l10-supply = <&vreg_s11b>; + + vreg_s1c: smps1 { + regulator-name = "vreg_s1c"; + regulator-min-microvolt = <1880000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + regulator-always-on; + }; + + vreg_l1c: ldo1 { + regulator-name = "vreg_l1c"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l12c: ldo12 { + regulator-name = "vreg_l12c"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l13c: ldo13 { + regulator-name = "vreg_l13c"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_bob: bob { + regulator-name = "vreg_bob"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + regulator-always-on; + }; + }; + + regulators-2 { + compatible = "qcom,pm8350-rpmh-regulators"; + qcom,pmic-id = "d"; + + vdd-l1-l4-supply = <&vreg_s11b>; + vdd-l2-l7-supply = <&vreg_bob>; + vdd-l3-l5-supply = <&vreg_s11b>; + vdd-l6-l9-l10-supply = <&vreg_s12b>; + vdd-l8-supply = <&vreg_s12b>; + + vreg_l3d: ldo3 { + regulator-name = "vreg_l3d"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l4d: ldo4 { + regulator-name = "vreg_l4d"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l6d: ldo6 { + regulator-name = "vreg_l6d"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l7d: ldo7 { + regulator-name = "vreg_l7d"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l9d: ldo9 { + regulator-name = "vreg_l9d"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + }; + }; +}; + +&dispcc0 { + status = "okay"; +}; + +&dispcc1 { + status = "okay"; +}; + +&gpu { + status = "okay"; + + zap-shader { + memory-region = <&gpu_mem>; + firmware-name = "qcom/sc8280xp/MICROSOFT/SurfacePro9/qcdxkmsuc8280.mbn"; + }; +}; + +&mdss0 { + status = "okay"; +}; + +&mdss0_dp0 { + status = "okay"; +}; + +&mdss0_dp0_out { + data-lanes = <0 1>; + remote-endpoint = <&usb_0_qmpphy_dp_in>; +}; + +&mdss0_dp1 { + status = "okay"; +}; + +&mdss0_dp1_out { + data-lanes = <0 1>; + remote-endpoint = <&usb_1_qmpphy_dp_in>; +}; + +&pcie2a { + perst-gpios = <&tlmm 143 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 145 GPIO_ACTIVE_LOW>; + + vddpe-3v3-supply = <&vreg_nvme>; + + pinctrl-0 = <&pcie2a_default>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie2a_phy { + vdda-phy-supply = <&vreg_l6d>; + vdda-pll-supply = <&vreg_l4d>; + + status = "okay"; +}; + +&pcie3a { + perst-gpios = <&tlmm 151 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>; + + vddpe-3v3-supply = <&vreg_wwan>; + + pinctrl-0 = <&pcie3a_default>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie3a_phy { + vdda-phy-supply = <&vreg_l6d>; + vdda-pll-supply = <&vreg_l4d>; + + status = "okay"; +}; + +&pcie4 { + max-link-speed = <2>; + + perst-gpios = <&tlmm 141 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 139 GPIO_ACTIVE_LOW>; + + vddpe-3v3-supply = <&vreg_wlan>; + + pinctrl-0 = <&pcie4_default>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie4_port0 { + wifi@0 { + compatible = "pci17cb,1103"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + qcom,ath11k-calibration-variant = "MS_SP9_5G"; + }; +}; + +&pcie4_phy { + vdda-phy-supply = <&vreg_l6d>; + vdda-pll-supply = <&vreg_l4d>; + + status = "okay"; +}; + +&pmk8280_pon_pwrkey { + status = "okay"; +}; + +&pmk8280_pon_resin { + status = "okay"; +}; + +&pmk8280_rtc { + nvmem-cells = <&rtc_offset>; + nvmem-cell-names = "offset"; + + status = "okay"; +}; + +&pmk8280_sdam_6 { + status = "okay"; + + rtc_offset: rtc-offset@bc { + reg = <0xbc 0x4>; + }; +}; + +&qup0 { + status = "okay"; +}; + +&qup1 { + status = "okay"; +}; + +&qup2 { + status = "okay"; +}; + +&remoteproc_adsp { + firmware-name = "qcom/sc8280xp/MICROSOFT/SurfacePro9/qcadsp8280.mbn"; + + status = "okay"; +}; + +&remoteproc_nsp0 { + firmware-name = "qcom/sc8280xp/MICROSOFT/SurfacePro9/qccdsp8280.mbn"; + + status = "okay"; +}; + +&rxmacro { + status = "okay"; +}; + +&sound { + compatible = "qcom,sc8280xp-sndcard"; + model = "SC8280XP-MICROSOFT-SURFACE-PRO-9-5G"; + audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "AMIC2", "MIC BIAS2", + "VA DMIC0", "MIC BIAS1", + "VA DMIC1", "MIC BIAS1", + "VA DMIC2", "MIC BIAS3", + "VA DMIC0", "VA MIC BIAS1", + "VA DMIC1", "VA MIC BIAS1", + "VA DMIC2", "VA MIC BIAS3", + "TX SWR_ADC1", "ADC2_OUTPUT"; + + wcd-playback-dai-link { + link-name = "WCD Playback"; + + cpu { + sound-dai = <&q6apmbedai RX_CODEC_DMA_RX_0>; + }; + + codec { + sound-dai = <&wcd938x 0>, <&swr1 0>, <&rxmacro 0>; + }; + + platform { + sound-dai = <&q6apm>; + }; + }; + + wcd-capture-dai-link { + link-name = "WCD Capture"; + + cpu { + sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>; + }; + + codec { + sound-dai = <&wcd938x 1>, <&swr2 0>, <&txmacro 0>; + }; + + platform { + sound-dai = <&q6apm>; + }; + }; + + wsa-dai-link { + link-name = "WSA Playback"; + + cpu { + sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>; + }; + + codec { + sound-dai = <&swr0 0>, <&wsamacro 0>; + }; + + platform { + sound-dai = <&q6apm>; + }; + }; + + va-dai-link { + link-name = "VA Capture"; + + cpu { + sound-dai = <&q6apmbedai VA_CODEC_DMA_TX_0>; + }; + + platform { + sound-dai = <&q6apm>; + }; + + codec { + sound-dai = <&vamacro 0>; + }; + }; +}; + +&swr0 { + status = "okay"; +}; + +&swr1 { + status = "okay"; + + wcd_rx: codec@0,4 { + compatible = "sdw20217010d00"; + reg = <0 4>; + qcom,rx-port-mapping = <1 2 3 4 5>; + }; +}; + +&swr2 { + status = "okay"; + + wcd_tx: codec@0,3 { + compatible = "sdw20217010d00"; + reg = <0 3>; + qcom,tx-port-mapping = <1 1 2 3>; + }; +}; + +&txmacro { + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2_default>; + pinctrl-names = "default"; + + status = "okay"; + + bluetooth { + compatible = "qcom,wcn6855-bt"; + + vddio-supply = <&vreg_s10b>; + vddbtcxmx-supply = <&vreg_s12b>; + vddrfacmn-supply = <&vreg_s12b>; + vddrfa0p8-supply = <&vreg_s12b>; + vddrfa1p2-supply = <&vreg_s11b>; + vddrfa1p7-supply = <&vreg_s1c>; + + max-speed = <3200000>; + + enable-gpios = <&tlmm 133 GPIO_ACTIVE_HIGH>; + swctrl-gpios = <&tlmm 132 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&bt_default>; + pinctrl-names = "default"; + }; +}; + +&uart18 { + status = "okay"; + + embedded-controller { + compatible = "microsoft,surface-sam"; + + interrupts-extended = <&tlmm 85 IRQ_TYPE_EDGE_RISING>; + + current-speed = <4000000>; + + pinctrl-0 = <&ssam_state>; + pinctrl-names = "default"; + }; +}; + +&usb_0 { + status = "okay"; +}; + +&usb_0_dwc3 { + dr_mode = "host"; +}; + +&usb_0_dwc3_hs { + remote-endpoint = <&pmic_glink_con0_hs>; +}; + +&usb_0_hsphy { + vdda-pll-supply = <&vreg_l9d>; + vdda18-supply = <&vreg_l1c>; + vdda33-supply = <&vreg_l7d>; + + status = "okay"; +}; + +&usb_0_qmpphy { + vdda-phy-supply = <&vreg_l9d>; + vdda-pll-supply = <&vreg_l4d>; + + orientation-switch; + + status = "okay"; +}; + +&usb_0_qmpphy_dp_in { + remote-endpoint = <&mdss0_dp0_out>; +}; + +&usb_0_qmpphy_out { + remote-endpoint = <&pmic_glink_con0_ss>; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "host"; +}; + +&usb_1_dwc3_hs { + remote-endpoint = <&pmic_glink_con1_hs>; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vreg_l4b>; + vdda18-supply = <&vreg_l1c>; + vdda33-supply = <&vreg_l13c>; + + status = "okay"; +}; + +&usb_1_qmpphy { + vdda-phy-supply = <&vreg_l4b>; + vdda-pll-supply = <&vreg_l3b>; + + orientation-switch; + + status = "okay"; +}; + +&usb_1_qmpphy_dp_in { + remote-endpoint = <&mdss0_dp1_out>; +}; + +&usb_1_qmpphy_out { + remote-endpoint = <&pmic_glink_con1_ss>; +}; + +&vamacro { + pinctrl-0 = <&dmic01_default>, <&dmic23_default>; + pinctrl-names = "default"; + + vdd-micb-supply = <&vreg_s10b>; + + qcom,dmic-sample-rate = <4800000>; + + status = "okay"; +}; + +&wsamacro { + status = "okay"; +}; + +&xo_board_clk { + clock-frequency = <38400000>; +}; + +/* PINCTRL */ + +&lpass_tlmm { + status = "okay"; +}; + +&pmc8280_2_gpios { + wwan_sw_en: wwan-sw-en-state { + pins = "gpio1"; + function = "normal"; + }; +}; + +&pmr735a_gpios { + hastings_reg_en: hastings-reg-en-state { + pins = "gpio1"; + function = "normal"; + }; +}; + +&tlmm { + bt_default: bt-default-state { + hstp-bt-en-pins { + pins = "gpio133"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + hstp-sw-ctrl-pins { + pins = "gpio132"; + function = "gpio"; + bias-pull-down; + }; + }; + + nvme_reg_en: nvme-reg-en-state { + pins = "gpio135"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + pcie2a_default: pcie2a-default-state { + clkreq-n-pins { + pins = "gpio142"; + function = "pcie2a_clkreq"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio143"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-n-pins { + pins = "gpio145"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie3a_default: pcie3a-default-state { + clkreq-n-pins { + pins = "gpio150"; + function = "pcie3a_clkreq"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio151"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-n-pins { + pins = "gpio148"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie4_default: pcie4-default-state { + clkreq-n-pins { + pins = "gpio140"; + function = "pcie4_clkreq"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio141"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-n-pins { + pins = "gpio139"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + + ssam_state: ssam-state-state { + pins = "gpio85"; + function = "gpio"; + bias-disable; + }; + + uart2_default: uart2-default-state { + cts-pins { + pins = "gpio121"; + function = "qup2"; + bias-bus-hold; + }; + + rts-pins { + pins = "gpio122"; + function = "qup2"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio124"; + function = "qup2"; + bias-pull-up; + }; + + tx-pins { + pins = "gpio123"; + function = "qup2"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb0_sbu_default: usb0-sbu-state { + oe-n-pins { + pins = "gpio101"; + function = "gpio"; + bias-disable; + drive-strength = <16>; + output-high; + }; + + sel-pins { + pins = "gpio164"; + function = "gpio"; + bias-disable; + drive-strength = <16>; + }; + }; + + usb1_sbu_default: usb1-sbu-state { + oe-n-pins { + pins = "gpio48"; + function = "gpio"; + bias-disable; + drive-strength = <16>; + output-high; + }; + + sel-pins { + pins = "gpio47"; + function = "gpio"; + bias-disable; + drive-strength = <16>; + }; + }; + + wcd_default: wcd-default-state { + reset-pins { + pins = "gpio106"; + function = "gpio"; + bias-disable; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index 80a57aa228397e..ef06d1ac084d32 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -44,7 +44,7 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a78c"; reg = <0x0 0x0>; @@ -52,19 +52,19 @@ CPU0: cpu@0 { enable-method = "psci"; capacity-dmips-mhz = <981>; dynamic-power-coefficient = <549>; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -72,7 +72,7 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a78c"; reg = <0x0 0x100>; @@ -80,22 +80,22 @@ CPU1: cpu@100 { enable-method = "psci"; capacity-dmips-mhz = <981>; dynamic-power-coefficient = <549>; - next-level-cache = <&L2_100>; - power-domains = <&CPU_PD1>; + next-level-cache = <&l2_100>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "arm,cortex-a78c"; reg = <0x0 0x200>; @@ -103,22 +103,22 @@ CPU2: cpu@200 { enable-method = "psci"; capacity-dmips-mhz = <981>; dynamic-power-coefficient = <549>; - next-level-cache = <&L2_200>; - power-domains = <&CPU_PD2>; + next-level-cache = <&l2_200>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "arm,cortex-a78c"; reg = <0x0 0x300>; @@ -126,22 +126,22 @@ CPU3: cpu@300 { enable-method = "psci"; capacity-dmips-mhz = <981>; dynamic-power-coefficient = <549>; - next-level-cache = <&L2_300>; - power-domains = <&CPU_PD3>; + next-level-cache = <&l2_300>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "arm,cortex-x1c"; reg = <0x0 0x400>; @@ -149,22 +149,22 @@ CPU4: cpu@400 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <590>; - next-level-cache = <&L2_400>; - power-domains = <&CPU_PD4>; + next-level-cache = <&l2_400>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "arm,cortex-x1c"; reg = <0x0 0x500>; @@ -172,22 +172,22 @@ CPU5: cpu@500 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <590>; - next-level-cache = <&L2_500>; - power-domains = <&CPU_PD5>; + next-level-cache = <&l2_500>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "arm,cortex-x1c"; reg = <0x0 0x600>; @@ -195,22 +195,22 @@ CPU6: cpu@600 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <590>; - next-level-cache = <&L2_600>; - power-domains = <&CPU_PD6>; + next-level-cache = <&l2_600>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "arm,cortex-x1c"; reg = <0x0 0x700>; @@ -218,53 +218,53 @@ CPU7: cpu@700 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <590>; - next-level-cache = <&L2_700>; - power-domains = <&CPU_PD7>; + next-level-cache = <&l2_700>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&epss_l3 MASTER_EPSS_L3_APPS &epss_l3 SLAVE_EPSS_L3_SHARED>; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -272,7 +272,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -282,7 +282,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -294,7 +294,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c344>; entry-latency-us = <3263>; @@ -593,57 +593,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>; + domain-idle-states = <&cluster_sleep_0>; }; }; @@ -1007,6 +1007,24 @@ spi18: spi@888000 { status = "disabled"; }; + uart18: serial@888000 { + compatible = "qcom,geni-uart"; + reg = <0 0x00888000 0 0x4000>; + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + interrupts = ; + operating-points-v2 = <&qup_opp_table_100mhz>; + power-domains = <&rpmhpd SC8280XP_CX>; + interconnects = <&clk_virt MASTER_QUP_CORE_2 0 &clk_virt SLAVE_QUP_CORE_2 0>, + <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_QUP_2 0>; + interconnect-names = "qup-core", "qup-config"; + + pinctrl-0 = <&qup_uart18_default>; + pinctrl-names = "default"; + + status = "disabled"; + }; + i2c19: i2c@88c000 { compatible = "qcom,geni-i2c"; reg = <0 0x0088c000 0 0x4000>; @@ -2294,7 +2312,7 @@ pcie2a_phy: phy@1c24000 { status = "disabled"; }; - ufs_mem_hc: ufs@1d84000 { + ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,sc8280xp-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0 0x01d84000 0 0x3000>; @@ -2360,7 +2378,7 @@ ufs_mem_phy: phy@1d87000 { status = "disabled"; }; - ufs_card_hc: ufs@1da4000 { + ufs_card_hc: ufshc@1da4000 { compatible = "qcom,sc8280xp-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0 0x01da4000 0 0x3000>; @@ -4871,6 +4889,36 @@ cci3_i2c1_sleep: cci3-i2c1-sleep-pins { bias-pull-down; }; }; + + qup_uart18_default: qup-uart18-default-state { + cts-pins { + pins = "gpio66"; + function = "qup18"; + drive-strength = <2>; + bias-disable; + }; + + rts-pins { + pins = "gpio67"; + function = "qup18"; + drive-strength = <2>; + bias-disable; + }; + + tx-pins { + pins = "gpio68"; + function = "qup18"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio69"; + function = "qup18"; + drive-strength = <2>; + bias-disable; + }; + }; }; apps_smmu: iommu@15000000 { @@ -5008,6 +5056,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; intc: interrupt-controller@17a00000 { @@ -5111,7 +5160,7 @@ apps_rsc: rsc@18200000 { qcom,tcs-config = , , , ; label = "apps_rsc"; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; diff --git a/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts b/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts index 60412281ab27de..d402f4c85b11d1 100644 --- a/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts +++ b/arch/arm64/boot/dts/qcom/sda660-inforce-ifc6560.dts @@ -104,12 +104,20 @@ vreg_l10a_1p8: vreg-l10a-regulator { compatible = "regulator-fixed"; regulator-name = "vreg_l10a_1p8"; regulator-min-microvolt = <1804000>; - regulator-max-microvolt = <1896000>; + regulator-max-microvolt = <1804000>; regulator-always-on; regulator-boot-on; }; }; +&adreno_gpu { + status = "okay"; +}; + +&adreno_gpu_zap { + firmware-name = "qcom/sda660/a512_zap.mbn"; +}; + &adsp_pil { firmware-name = "qcom/sda660/adsp.mbn"; }; @@ -244,6 +252,11 @@ &qusb2phy1 { vdda-phy-dpdm-supply = <&vreg_l7b_3p125>; }; +&remoteproc_mss { + firmware-name = "qcom/sda660/mba.mbn", "qcom/sda660/modem.mbn"; + status = "okay"; +}; + &rpm_requests { regulators-0 { compatible = "qcom,rpm-pm660-regulators"; @@ -283,6 +296,11 @@ vreg_l1a_1p225: l1 { regulator-allow-set-load; }; + vreg_l5a_0p8: l5 { + regulator-min-microvolt = <848000>; + regulator-max-microvolt = <848000>; + }; + vreg_l6a_1p3: l6 { regulator-min-microvolt = <1304000>; regulator-max-microvolt = <1368000>; @@ -481,3 +499,15 @@ &usb3_qmpphy { vdda-pll-supply = <&vreg_l10a_1p8>; status = "okay"; }; + +&wifi { + vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>; + vdd-1.8-xo-supply = <&vreg_l9a_1p8>; + vdd-1.3-rfa-supply = <&vreg_l6a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l19a_3p3>; + vdd-3.3-ch1-supply = <&vreg_l8b_3p3>; + + qcom,ath10k-calibration-variant = "Inforce_IFC6560"; + + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm450-lenovo-tbx605f.dts b/arch/arm64/boot/dts/qcom/sdm450-lenovo-tbx605f.dts index 175befc02b22f5..c509bbfe5d3e88 100644 --- a/arch/arm64/boot/dts/qcom/sdm450-lenovo-tbx605f.dts +++ b/arch/arm64/boot/dts/qcom/sdm450-lenovo-tbx605f.dts @@ -40,7 +40,7 @@ framebuffer@90001000 { }; reserved-memory { - other_ext_region@0 { + other-ext-region@0 { no-map; reg = <0x00 0x84500000 0x00 0x2300000>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index c8da5cb8d04e99..19420cfdadf151 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -49,170 +49,170 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@100 { + cpu0: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x100>; enable-method = "psci"; - cpu-idle-states = <&PERF_CPU_SLEEP_0 - &PERF_CPU_SLEEP_1 - &PERF_CLUSTER_SLEEP_0 - &PERF_CLUSTER_SLEEP_1 - &PERF_CLUSTER_SLEEP_2>; + cpu-idle-states = <&perf_cpu_sleep_0 + &perf_cpu_sleep_1 + &perf_cluster_sleep_0 + &perf_cluster_sleep_1 + &perf_cluster_sleep_2>; capacity-dmips-mhz = <1126>; #cooling-cells = <2>; - next-level-cache = <&L2_1>; - L2_1: l2-cache { + next-level-cache = <&l2_1>; + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@101 { + cpu1: cpu@101 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x101>; enable-method = "psci"; - cpu-idle-states = <&PERF_CPU_SLEEP_0 - &PERF_CPU_SLEEP_1 - &PERF_CLUSTER_SLEEP_0 - &PERF_CLUSTER_SLEEP_1 - &PERF_CLUSTER_SLEEP_2>; + cpu-idle-states = <&perf_cpu_sleep_0 + &perf_cpu_sleep_1 + &perf_cluster_sleep_0 + &perf_cluster_sleep_1 + &perf_cluster_sleep_2>; capacity-dmips-mhz = <1126>; #cooling-cells = <2>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; - CPU2: cpu@102 { + cpu2: cpu@102 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x102>; enable-method = "psci"; - cpu-idle-states = <&PERF_CPU_SLEEP_0 - &PERF_CPU_SLEEP_1 - &PERF_CLUSTER_SLEEP_0 - &PERF_CLUSTER_SLEEP_1 - &PERF_CLUSTER_SLEEP_2>; + cpu-idle-states = <&perf_cpu_sleep_0 + &perf_cpu_sleep_1 + &perf_cluster_sleep_0 + &perf_cluster_sleep_1 + &perf_cluster_sleep_2>; capacity-dmips-mhz = <1126>; #cooling-cells = <2>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; - CPU3: cpu@103 { + cpu3: cpu@103 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x103>; enable-method = "psci"; - cpu-idle-states = <&PERF_CPU_SLEEP_0 - &PERF_CPU_SLEEP_1 - &PERF_CLUSTER_SLEEP_0 - &PERF_CLUSTER_SLEEP_1 - &PERF_CLUSTER_SLEEP_2>; + cpu-idle-states = <&perf_cpu_sleep_0 + &perf_cpu_sleep_1 + &perf_cluster_sleep_0 + &perf_cluster_sleep_1 + &perf_cluster_sleep_2>; capacity-dmips-mhz = <1126>; #cooling-cells = <2>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; - CPU4: cpu@0 { + cpu4: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x0>; enable-method = "psci"; - cpu-idle-states = <&PWR_CPU_SLEEP_0 - &PWR_CPU_SLEEP_1 - &PWR_CLUSTER_SLEEP_0 - &PWR_CLUSTER_SLEEP_1 - &PWR_CLUSTER_SLEEP_2>; + cpu-idle-states = <&pwr_cpu_sleep_0 + &pwr_cpu_sleep_1 + &pwr_cluster_sleep_0 + &pwr_cluster_sleep_1 + &pwr_cluster_sleep_2>; capacity-dmips-mhz = <1024>; #cooling-cells = <2>; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU5: cpu@1 { + cpu5: cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x1>; enable-method = "psci"; - cpu-idle-states = <&PWR_CPU_SLEEP_0 - &PWR_CPU_SLEEP_1 - &PWR_CLUSTER_SLEEP_0 - &PWR_CLUSTER_SLEEP_1 - &PWR_CLUSTER_SLEEP_2>; + cpu-idle-states = <&pwr_cpu_sleep_0 + &pwr_cpu_sleep_1 + &pwr_cluster_sleep_0 + &pwr_cluster_sleep_1 + &pwr_cluster_sleep_2>; capacity-dmips-mhz = <1024>; #cooling-cells = <2>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU6: cpu@2 { + cpu6: cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x2>; enable-method = "psci"; - cpu-idle-states = <&PWR_CPU_SLEEP_0 - &PWR_CPU_SLEEP_1 - &PWR_CLUSTER_SLEEP_0 - &PWR_CLUSTER_SLEEP_1 - &PWR_CLUSTER_SLEEP_2>; + cpu-idle-states = <&pwr_cpu_sleep_0 + &pwr_cpu_sleep_1 + &pwr_cluster_sleep_0 + &pwr_cluster_sleep_1 + &pwr_cluster_sleep_2>; capacity-dmips-mhz = <1024>; #cooling-cells = <2>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU7: cpu@3 { + cpu7: cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a53"; reg = <0x0 0x3>; enable-method = "psci"; - cpu-idle-states = <&PWR_CPU_SLEEP_0 - &PWR_CPU_SLEEP_1 - &PWR_CLUSTER_SLEEP_0 - &PWR_CLUSTER_SLEEP_1 - &PWR_CLUSTER_SLEEP_2>; + cpu-idle-states = <&pwr_cpu_sleep_0 + &pwr_cpu_sleep_1 + &pwr_cluster_sleep_0 + &pwr_cluster_sleep_1 + &pwr_cluster_sleep_2>; capacity-dmips-mhz = <1024>; #cooling-cells = <2>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; cpu-map { cluster0 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; cluster1 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; }; @@ -220,7 +220,7 @@ core3 { idle-states { entry-method = "psci"; - PWR_CPU_SLEEP_0: cpu-sleep-0-0 { + pwr_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "pwr-retention"; arm,psci-suspend-param = <0x40000002>; @@ -229,7 +229,7 @@ PWR_CPU_SLEEP_0: cpu-sleep-0-0 { min-residency-us = <200>; }; - PWR_CPU_SLEEP_1: cpu-sleep-0-1 { + pwr_cpu_sleep_1: cpu-sleep-0-1 { compatible = "arm,idle-state"; idle-state-name = "pwr-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -239,7 +239,7 @@ PWR_CPU_SLEEP_1: cpu-sleep-0-1 { local-timer-stop; }; - PERF_CPU_SLEEP_0: cpu-sleep-1-0 { + perf_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "perf-retention"; arm,psci-suspend-param = <0x40000002>; @@ -248,7 +248,7 @@ PERF_CPU_SLEEP_0: cpu-sleep-1-0 { min-residency-us = <200>; }; - PERF_CPU_SLEEP_1: cpu-sleep-1-1 { + perf_cpu_sleep_1: cpu-sleep-1-1 { compatible = "arm,idle-state"; idle-state-name = "perf-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -258,7 +258,7 @@ PERF_CPU_SLEEP_1: cpu-sleep-1-1 { local-timer-stop; }; - PWR_CLUSTER_SLEEP_0: cluster-sleep-0-0 { + pwr_cluster_sleep_0: cluster-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "pwr-cluster-dynamic-retention"; arm,psci-suspend-param = <0x400000F2>; @@ -268,7 +268,7 @@ PWR_CLUSTER_SLEEP_0: cluster-sleep-0-0 { local-timer-stop; }; - PWR_CLUSTER_SLEEP_1: cluster-sleep-0-1 { + pwr_cluster_sleep_1: cluster-sleep-0-1 { compatible = "arm,idle-state"; idle-state-name = "pwr-cluster-retention"; arm,psci-suspend-param = <0x400000F3>; @@ -278,7 +278,7 @@ PWR_CLUSTER_SLEEP_1: cluster-sleep-0-1 { local-timer-stop; }; - PWR_CLUSTER_SLEEP_2: cluster-sleep-0-2 { + pwr_cluster_sleep_2: cluster-sleep-0-2 { compatible = "arm,idle-state"; idle-state-name = "pwr-cluster-retention"; arm,psci-suspend-param = <0x400000F4>; @@ -288,7 +288,7 @@ PWR_CLUSTER_SLEEP_2: cluster-sleep-0-2 { local-timer-stop; }; - PERF_CLUSTER_SLEEP_0: cluster-sleep-1-0 { + perf_cluster_sleep_0: cluster-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "perf-cluster-dynamic-retention"; arm,psci-suspend-param = <0x400000F2>; @@ -298,7 +298,7 @@ PERF_CLUSTER_SLEEP_0: cluster-sleep-1-0 { local-timer-stop; }; - PERF_CLUSTER_SLEEP_1: cluster-sleep-1-1 { + perf_cluster_sleep_1: cluster-sleep-1-1 { compatible = "arm,idle-state"; idle-state-name = "perf-cluster-retention"; arm,psci-suspend-param = <0x400000F3>; @@ -308,7 +308,7 @@ PERF_CLUSTER_SLEEP_1: cluster-sleep-1-1 { local-timer-stop; }; - PERF_CLUSTER_SLEEP_2: cluster-sleep-1-2 { + perf_cluster_sleep_2: cluster-sleep-1-2 { compatible = "arm,idle-state"; idle-state-name = "perf-cluster-retention"; arm,psci-suspend-param = <0x400000F4>; @@ -665,8 +665,6 @@ anoc2_smmu: iommu@16c0000 { , , ; - - status = "disabled"; }; a2noc: interconnect@1704000 { @@ -1150,6 +1148,10 @@ opp-160000000 { opp-supported-hw = <0xff>; }; }; + + adreno_gpu_zap: zap-shader { + memory-region = <&zap_shader_region>; + }; }; kgsl_smmu: iommu@5040000 { @@ -1186,8 +1188,6 @@ kgsl_smmu: iommu@5040000 { , , ; - - status = "disabled"; }; gpucc: clock-controller@5065000 { @@ -1203,7 +1203,6 @@ gpucc: clock-controller@5065000 { clock-names = "xo", "gcc_gpu_gpll0_clk", "gcc_gpu_gpll0_div_clk"; - status = "disabled"; }; lpass_smmu: iommu@5100000 { @@ -1233,8 +1232,6 @@ lpass_smmu: iommu@5100000 { , , ; - - status = "disabled"; }; sram@290000 { @@ -2415,6 +2412,33 @@ intc: interrupt-controller@17a00000 { redistributor-stride = <0x0 0x20000>; interrupts = ; }; + + wifi: wifi@18800000 { + compatible = "qcom,wcn3990-wifi"; + reg = <0x18800000 0x800000>; + reg-names = "membase"; + memory-region = <&wlan_msa_mem>; + clocks = <&rpmcc RPM_SMD_RF_CLK1_PIN>; + clock-names = "cxo_ref_clk_pin"; + interrupts = + , + , + , + , + , + , + , + , + , + , + , + ; + iommus = <&anoc2_smmu 0x1a00>, + <&anoc2_smmu 0x1a01>; + qcom,snoc-host-cap-8bit-quirk; + qcom,no-msa-ready-indicator; + status = "disabled"; + }; }; sound: sound { diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi index 95b025ea260bdb..40d86d91b67fa0 100644 --- a/arch/arm64/boot/dts/qcom/sdm632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi @@ -14,10 +14,10 @@ cpu0-thermal { cooling-maps { map0 { - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -42,40 +42,40 @@ cpu7-thermal { /* * SDM632 uses Kryo 250 instead of Cortex A53 - * CPU0-3 are efficiency cores, CPU4-7 are performance cores + * cpu0-3 are efficiency cores, cpu4-7 are performance cores */ -&CPU0 { +&cpu0 { compatible = "qcom,kryo250"; }; -&CPU1 { +&cpu1 { compatible = "qcom,kryo250"; }; -&CPU2 { +&cpu2 { compatible = "qcom,kryo250"; }; -&CPU3 { +&cpu3 { compatible = "qcom,kryo250"; }; -&CPU4 { +&cpu4 { compatible = "qcom,kryo250"; capacity-dmips-mhz = <1980>; }; -&CPU5 { +&cpu5 { compatible = "qcom,kryo250"; capacity-dmips-mhz = <1980>; }; -&CPU6 { +&cpu6 { compatible = "qcom,kryo250"; capacity-dmips-mhz = <1980>; }; -&CPU7 { +&cpu7 { compatible = "qcom,kryo250"; capacity-dmips-mhz = <1980>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm660.dtsi b/arch/arm64/boot/dts/qcom/sdm660.dtsi index f89b27c99f40cf..3164a4817e3267 100644 --- a/arch/arm64/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm660.dtsi @@ -85,49 +85,49 @@ opp-160000000 { }; }; -&CPU0 { +&cpu0 { compatible = "qcom,kryo260"; capacity-dmips-mhz = <1024>; /delete-property/ operating-points-v2; }; -&CPU1 { +&cpu1 { compatible = "qcom,kryo260"; capacity-dmips-mhz = <1024>; /delete-property/ operating-points-v2; }; -&CPU2 { +&cpu2 { compatible = "qcom,kryo260"; capacity-dmips-mhz = <1024>; /delete-property/ operating-points-v2; }; -&CPU3 { +&cpu3 { compatible = "qcom,kryo260"; capacity-dmips-mhz = <1024>; /delete-property/ operating-points-v2; }; -&CPU4 { +&cpu4 { compatible = "qcom,kryo260"; capacity-dmips-mhz = <640>; /delete-property/ operating-points-v2; }; -&CPU5 { +&cpu5 { compatible = "qcom,kryo260"; capacity-dmips-mhz = <640>; /delete-property/ operating-points-v2; }; -&CPU6 { +&cpu6 { compatible = "qcom,kryo260"; capacity-dmips-mhz = <640>; /delete-property/ operating-points-v2; }; -&CPU7 { +&cpu7 { compatible = "qcom,kryo260"; capacity-dmips-mhz = <640>; /delete-property/ operating-points-v2; diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 187c6698835d34..c93dd06c0b7d64 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -32,7 +32,7 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo360"; reg = <0x0 0x0>; @@ -43,15 +43,15 @@ CPU0: cpu@0 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_AMPSS_M0 3 &mem_noc SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; cache-level = <2>; cache-unified; - L3_0: l3-cache { + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -59,7 +59,7 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo360"; reg = <0x0 0x100>; @@ -70,18 +70,18 @@ CPU1: cpu@100 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_AMPSS_M0 3 &mem_noc SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; - next-level-cache = <&L2_100>; - L2_100: l2-cache { + next-level-cache = <&l2_100>; + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo360"; reg = <0x0 0x200>; @@ -92,18 +92,18 @@ CPU2: cpu@200 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_AMPSS_M0 3 &mem_noc SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; - next-level-cache = <&L2_200>; - L2_200: l2-cache { + next-level-cache = <&l2_200>; + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo360"; reg = <0x0 0x300>; @@ -114,18 +114,18 @@ CPU3: cpu@300 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_AMPSS_M0 3 &mem_noc SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; - next-level-cache = <&L2_300>; - L2_300: l2-cache { + next-level-cache = <&l2_300>; + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo360"; reg = <0x0 0x400>; @@ -136,18 +136,18 @@ CPU4: cpu@400 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_AMPSS_M0 3 &mem_noc SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; - next-level-cache = <&L2_400>; - L2_400: l2-cache { + next-level-cache = <&l2_400>; + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo360"; reg = <0x0 0x500>; @@ -158,18 +158,18 @@ CPU5: cpu@500 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_AMPSS_M0 3 &mem_noc SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; - next-level-cache = <&L2_500>; - L2_500: l2-cache { + next-level-cache = <&l2_500>; + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo360"; reg = <0x0 0x600>; @@ -180,18 +180,18 @@ CPU6: cpu@600 { operating-points-v2 = <&cpu6_opp_table>; interconnects = <&gladiator_noc MASTER_AMPSS_M0 3 &mem_noc SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; - next-level-cache = <&L2_600>; - L2_600: l2-cache { + next-level-cache = <&l2_600>; + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo360"; reg = <0x0 0x700>; @@ -202,49 +202,49 @@ CPU7: cpu@700 { operating-points-v2 = <&cpu6_opp_table>; interconnects = <&gladiator_noc MASTER_AMPSS_M0 3 &mem_noc SLAVE_EBI_CH0 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; - next-level-cache = <&L2_700>; - L2_700: l2-cache { + next-level-cache = <&l2_700>; + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -252,7 +252,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -262,7 +262,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -274,7 +274,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c244>; entry-latency-us = <3263>; @@ -429,57 +429,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cluster { + cluster_pd: power-domain-cluster { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>; + domain-idle-states = <&cluster_sleep_0>; }; }; @@ -1737,6 +1737,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; gladiator_noc: interconnect@17900000 { @@ -1762,7 +1763,7 @@ apps_rsc: rsc@179c0000 { , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi index e8276db9eabb29..743c339ba1081e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-cheza.dtsi @@ -164,7 +164,7 @@ &cpus { }; &cpu_idle_states { - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-power-down"; arm,psci-suspend-param = <0x40000003>; @@ -174,7 +174,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { + little_cpu_sleep_1: cpu-sleep-0-1 { compatible = "arm,idle-state"; idle-state-name = "little-rail-power-down"; arm,psci-suspend-param = <0x40000004>; @@ -184,7 +184,7 @@ LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-power-down"; arm,psci-suspend-param = <0x40000003>; @@ -194,7 +194,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { local-timer-stop; }; - BIG_CPU_SLEEP_1: cpu-sleep-1-1 { + big_cpu_sleep_1: cpu-sleep-1-1 { compatible = "arm,idle-state"; idle-state-name = "big-rail-power-down"; arm,psci-suspend-param = <0x40000004>; @@ -204,7 +204,7 @@ BIG_CPU_SLEEP_1: cpu-sleep-1-1 { local-timer-stop; }; - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "arm,idle-state"; idle-state-name = "cluster-power-down"; arm,psci-suspend-param = <0x400000F4>; @@ -215,68 +215,68 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { }; }; -&CPU0 { +&cpu0 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU1 { +&cpu1 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU2 { +&cpu2 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU3 { +&cpu3 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&LITTLE_CPU_SLEEP_0 - &LITTLE_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&little_cpu_sleep_0 + &little_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU4 { +&cpu4 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&BIG_CPU_SLEEP_0 - &BIG_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&big_cpu_sleep_0 + &big_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU5 { +&cpu5 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&BIG_CPU_SLEEP_0 - &BIG_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&big_cpu_sleep_0 + &big_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU6 { +&cpu6 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&BIG_CPU_SLEEP_0 - &BIG_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&big_cpu_sleep_0 + &big_cpu_sleep_1 + &cluster_sleep_0>; }; -&CPU7 { +&cpu7 { /delete-property/ power-domains; /delete-property/ power-domain-names; - cpu-idle-states = <&BIG_CPU_SLEEP_0 - &BIG_CPU_SLEEP_1 - &CLUSTER_SLEEP_0>; + cpu-idle-states = <&big_cpu_sleep_0 + &big_cpu_sleep_1 + &cluster_sleep_0>; }; &lmh_cluster0 { diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dts deleted file mode 100644 index a21caa6f3fa259..00000000000000 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dts +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2022, Linaro Ltd. - */ - -/dts-v1/; - -#include "sdm845-db845c.dts" - -&camss { - vdda-phy-supply = <&vreg_l1a_0p875>; - vdda-pll-supply = <&vreg_l26a_1p2>; - - status = "okay"; - - ports { - port@0 { - csiphy0_ep: endpoint { - data-lanes = <0 1 2 3>; - remote-endpoint = <&ov8856_ep>; - }; - }; - }; -}; - -&cci { - status = "okay"; -}; - -&cci_i2c0 { - camera@10 { - compatible = "ovti,ov8856"; - reg = <0x10>; - - /* CAM0_RST_N */ - reset-gpios = <&tlmm 9 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&cam0_default>; - - clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; - clock-names = "xvclk"; - clock-frequency = <19200000>; - - /* - * The &vreg_s4a_1p8 trace is powered on as a, - * so it is represented by a fixed regulator. - * - * The 2.8V vdda-supply and 1.2V vddd-supply regulators - * both have to be enabled through the power management - * gpios. - */ - dovdd-supply = <&vreg_lvs1a_1p8>; - avdd-supply = <&cam0_avdd_2v8>; - dvdd-supply = <&cam0_dvdd_1v2>; - - port { - ov8856_ep: endpoint { - link-frequencies = /bits/ 64 - <360000000 180000000>; - data-lanes = <1 2 3 4>; - remote-endpoint = <&csiphy0_ep>; - }; - }; - }; -}; - -&cci_i2c1 { - camera@60 { - compatible = "ovti,ov7251"; - - /* I2C address as per ov7251.txt linux documentation */ - reg = <0x60>; - - /* CAM3_RST_N */ - enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&cam3_default>; - - clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; - clock-names = "xclk"; - clock-frequency = <24000000>; - - /* - * The &vreg_s4a_1p8 trace always powered on. - * - * The 2.8V vdda-supply regulator is enabled when the - * vreg_s4a_1p8 trace is pulled high. - * It too is represented by a fixed regulator. - * - * No 1.2V vddd-supply regulator is used. - */ - vdddo-supply = <&vreg_lvs1a_1p8>; - vdda-supply = <&cam3_avdd_2v8>; - - status = "disabled"; - - port { - ov7251_ep: endpoint { - data-lanes = <0 1>; -/* remote-endpoint = <&csiphy3_ep>; */ - }; - }; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dtso b/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dtso new file mode 100644 index 00000000000000..0a87df806cafc8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c-navigation-mezzanine.dtso @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022, Linaro Ltd. + */ + +/dts-v1/; +/plugin/; + +#include +#include + +/ { + reserved-memory { + linux,cma { + compatible = "shared-dma-pool"; + size = <0x0 0x8000000>; + reusable; + linux,cma-default; + }; + }; +}; + +&camss { + vdda-phy-supply = <&vreg_l1a_0p875>; + vdda-pll-supply = <&vreg_l26a_1p2>; + + status = "okay"; + + ports { + port@0 { + csiphy0_ep: endpoint { + data-lanes = <0 1 2 3>; + remote-endpoint = <&ov8856_ep>; + }; + }; + }; +}; + +&cci { + status = "okay"; +}; + +&cci_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@10 { + compatible = "ovti,ov8856"; + reg = <0x10>; + + /* CAM0_RST_N */ + reset-gpios = <&tlmm 9 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&cam0_default>; + + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "xvclk"; + clock-frequency = <19200000>; + + /* + * The &vreg_s4a_1p8 trace is powered on as a, + * so it is represented by a fixed regulator. + * + * The 2.8V vdda-supply and 1.2V vddd-supply regulators + * both have to be enabled through the power management + * gpios. + */ + dovdd-supply = <&vreg_lvs1a_1p8>; + avdd-supply = <&cam0_avdd_2v8>; + dvdd-supply = <&cam0_dvdd_1v2>; + + port { + ov8856_ep: endpoint { + link-frequencies = /bits/ 64 + <360000000 180000000>; + data-lanes = <1 2 3 4>; + remote-endpoint = <&csiphy0_ep>; + }; + }; + }; +}; + +&cci_i2c1 { + #address-cells = <1>; + #size-cells = <0>; + + camera@60 { + compatible = "ovti,ov7251"; + + /* I2C address as per ov7251.txt linux documentation */ + reg = <0x60>; + + /* CAM3_RST_N */ + enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&cam3_default>; + + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "xclk"; + clock-frequency = <24000000>; + + /* + * The &vreg_s4a_1p8 trace always powered on. + * + * The 2.8V vdda-supply regulator is enabled when the + * vreg_s4a_1p8 trace is pulled high. + * It too is represented by a fixed regulator. + * + * No 1.2V vddd-supply regulator is used. + */ + vdddo-supply = <&vreg_lvs1a_1p8>; + vdda-supply = <&cam3_avdd_2v8>; + + status = "disabled"; + + port { + ov7251_ep: endpoint { + data-lanes = <0 1>; +/* remote-endpoint = <&csiphy3_ep>; */ + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts index 9a6d3d0c0ee43a..1cc0f571e1f7f3 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts @@ -31,7 +31,7 @@ chosen { }; /* Fixed crystal oscillator dedicated to MCP2517FD */ - clk40M: can-clock { + clk40m: can-clock { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <40000000>; @@ -863,7 +863,7 @@ &spi0 { can@0 { compatible = "microchip,mcp2517fd"; reg = <0>; - clocks = <&clk40M>; + clocks = <&clk40m>; interrupts-extended = <&tlmm 104 IRQ_TYPE_LEVEL_LOW>; spi-max-frequency = <10000000>; vdd-supply = <&vdc_5v>; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 54077549b9da7f..1ed794638a7cee 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -91,7 +91,7 @@ cpus: cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo385"; reg = <0x0 0x0>; @@ -103,16 +103,16 @@ CPU0: cpu@0 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; #cooling-cells = <2>; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -120,7 +120,7 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo385"; reg = <0x0 0x100>; @@ -132,19 +132,19 @@ CPU1: cpu@100 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; #cooling-cells = <2>; - next-level-cache = <&L2_100>; - L2_100: l2-cache { + next-level-cache = <&l2_100>; + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo385"; reg = <0x0 0x200>; @@ -156,19 +156,19 @@ CPU2: cpu@200 { operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; #cooling-cells = <2>; - next-level-cache = <&L2_200>; - L2_200: l2-cache { + next-level-cache = <&l2_200>; + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo385"; reg = <0x0 0x300>; @@ -181,18 +181,18 @@ CPU3: cpu@300 { interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; - next-level-cache = <&L2_300>; - L2_300: l2-cache { + next-level-cache = <&l2_300>; + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo385"; reg = <0x0 0x400>; @@ -204,19 +204,19 @@ CPU4: cpu@400 { operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; #cooling-cells = <2>; - next-level-cache = <&L2_400>; - L2_400: l2-cache { + next-level-cache = <&l2_400>; + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo385"; reg = <0x0 0x500>; @@ -228,19 +228,19 @@ CPU5: cpu@500 { operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; #cooling-cells = <2>; - next-level-cache = <&L2_500>; - L2_500: l2-cache { + next-level-cache = <&l2_500>; + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo385"; reg = <0x0 0x600>; @@ -252,19 +252,19 @@ CPU6: cpu@600 { operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; #cooling-cells = <2>; - next-level-cache = <&L2_600>; - L2_600: l2-cache { + next-level-cache = <&l2_600>; + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo385"; reg = <0x0 0x700>; @@ -276,50 +276,50 @@ CPU7: cpu@700 { operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gladiator_noc MASTER_APPSS_PROC 3 &mem_noc SLAVE_EBI1 3>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; #cooling-cells = <2>; - next-level-cache = <&L2_700>; - L2_700: l2-cache { + next-level-cache = <&l2_700>; + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -327,7 +327,7 @@ core7 { cpu_idle_states: idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -337,7 +337,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -349,7 +349,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c244>; entry-latency-us = <3263>; @@ -717,57 +717,57 @@ psci: psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cluster { + cluster_pd: power-domain-cluster { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>; + domain-idle-states = <&cluster_sleep_0>; }; }; @@ -3615,7 +3615,7 @@ etm@7040000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07040000 0 0x1000>; - cpu = <&CPU0>; + cpu = <&cpu0>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3635,7 +3635,7 @@ etm@7140000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07140000 0 0x1000>; - cpu = <&CPU1>; + cpu = <&cpu1>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3655,7 +3655,7 @@ etm@7240000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07240000 0 0x1000>; - cpu = <&CPU2>; + cpu = <&cpu2>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3675,7 +3675,7 @@ etm@7340000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07340000 0 0x1000>; - cpu = <&CPU3>; + cpu = <&cpu3>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3695,7 +3695,7 @@ etm@7440000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07440000 0 0x1000>; - cpu = <&CPU4>; + cpu = <&cpu4>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3715,7 +3715,7 @@ etm@7540000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07540000 0 0x1000>; - cpu = <&CPU5>; + cpu = <&cpu5>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3735,7 +3735,7 @@ etm@7640000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07640000 0 0x1000>; - cpu = <&CPU6>; + cpu = <&cpu6>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3755,7 +3755,7 @@ etm@7740000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07740000 0 0x1000>; - cpu = <&CPU7>; + cpu = <&cpu7>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3959,7 +3959,7 @@ lmh_cluster1: lmh@17d70800 { compatible = "qcom,sdm845-lmh"; reg = <0 0x17d70800 0 0x400>; interrupts = ; - cpus = <&CPU4>; + cpus = <&cpu4>; qcom,lmh-temp-arm-millicelsius = <65000>; qcom,lmh-temp-low-millicelsius = <94500>; qcom,lmh-temp-high-millicelsius = <95000>; @@ -3971,7 +3971,7 @@ lmh_cluster0: lmh@17d78800 { compatible = "qcom,sdm845-lmh"; reg = <0 0x17d78800 0 0x400>; interrupts = ; - cpus = <&CPU0>; + cpus = <&cpu0>; qcom,lmh-temp-arm-millicelsius = <65000>; qcom,lmh-temp-low-millicelsius = <94500>; qcom,lmh-temp-high-millicelsius = <95000>; @@ -5159,6 +5159,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; anoc_1_tbu: tbu@150c5000 { @@ -5277,7 +5278,7 @@ apps_rsc: rsc@179c0000 { , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; diff --git a/arch/arm64/boot/dts/qcom/sdx75.dtsi b/arch/arm64/boot/dts/qcom/sdx75.dtsi index 7cf3fcb469a868..5f7e59ecf1ca62 100644 --- a/arch/arm64/boot/dts/qcom/sdx75.dtsi +++ b/arch/arm64/boot/dts/qcom/sdx75.dtsi @@ -43,25 +43,25 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x0>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -69,85 +69,85 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x100>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_100>; + next-level-cache = <&l2_100>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x200>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x300>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_300>; + next-level-cache = <&l2_300>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; }; @@ -155,7 +155,7 @@ core3 { idle-states { entry-method = "psci"; - CPU_OFF: cpu-sleep-0 { + cpu_off: cpu-sleep-0 { compatible = "arm,idle-state"; entry-latency-us = <235>; exit-latency-us = <428>; @@ -164,7 +164,7 @@ CPU_OFF: cpu-sleep-0 { local-timer-stop; }; - CPU_RAIL_OFF: cpu-rail-sleep-1 { + cpu_rail_off: cpu-rail-sleep-1 { compatible = "arm,idle-state"; entry-latency-us = <800>; exit-latency-us = <750>; @@ -176,7 +176,7 @@ CPU_RAIL_OFF: cpu-rail-sleep-1 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <1050>; @@ -184,7 +184,7 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { min-residency-us = <5309>; }; - CLUSTER_SLEEP_1: cluster-sleep-1 { + cluster_sleep_1: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41001344>; entry-latency-us = <2761>; @@ -192,7 +192,7 @@ CLUSTER_SLEEP_1: cluster-sleep-1 { min-residency-us = <8467>; }; - CLUSTER_SLEEP_2: cluster-sleep-2 { + cluster_sleep_2: cluster-sleep-2 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100b344>; entry-latency-us = <2793>; @@ -235,33 +235,33 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_OFF &CPU_RAIL_OFF>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_off &cpu_rail_off>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_OFF &CPU_RAIL_OFF>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_off &cpu_rail_off>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_OFF &CPU_RAIL_OFF>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_off &cpu_rail_off>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&CPU_OFF &CPU_RAIL_OFF>; + power-domains = <&cluster_pd>; + domain-idle-states = <&cpu_off &cpu_rail_off>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0 &CLUSTER_SLEEP_1 &CLUSTER_SLEEP_2>; + domain-idle-states = <&cluster_sleep_0 &cluster_sleep_1 &cluster_sleep_2>; }; }; @@ -1444,7 +1444,7 @@ apps_rsc: rsc@17a00000 { , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; qcom,tcs-offset = <0xd00>; qcom,drv-id = <2>; qcom,tcs-config = , diff --git a/arch/arm64/boot/dts/qcom/sm4250.dtsi b/arch/arm64/boot/dts/qcom/sm4250.dtsi index c5add8f44fc0f2..a0ed61925e12d6 100644 --- a/arch/arm64/boot/dts/qcom/sm4250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm4250.dtsi @@ -5,34 +5,34 @@ #include "sm6115.dtsi" -&CPU0 { +&cpu0 { compatible = "qcom,kryo240"; }; -&CPU1 { +&cpu1 { compatible = "qcom,kryo240"; }; -&CPU2 { +&cpu2 { compatible = "qcom,kryo240"; }; -&CPU3 { +&cpu3 { compatible = "qcom,kryo240"; }; -&CPU4 { +&cpu4 { compatible = "qcom,kryo240"; }; -&CPU5 { +&cpu5 { compatible = "qcom,kryo240"; }; -&CPU6 { +&cpu6 { compatible = "qcom,kryo240"; }; -&CPU7 { +&cpu7 { compatible = "qcom,kryo240"; }; diff --git a/arch/arm64/boot/dts/qcom/sm4450.dtsi b/arch/arm64/boot/dts/qcom/sm4450.dtsi index 1e05cd00b635ee..a0de5fe16faae5 100644 --- a/arch/arm64/boot/dts/qcom/sm4450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm4450.dtsi @@ -46,25 +46,25 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x0>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; - L3_0: l3-cache { + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -72,178 +72,178 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x100>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_100>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_100>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x200>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_200>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_200>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x300>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_300>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_300>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x400>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_400>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_400>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x500>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_500>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_500>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "arm,cortex-a78"; reg = <0x0 0x600>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_600>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_600>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "arm,cortex-a78"; reg = <0x0 0x700>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_700>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_700>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -251,7 +251,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; arm,psci-suspend-param = <0x40000004>; entry-latency-us = <800>; @@ -260,7 +260,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; arm,psci-suspend-param = <0x40000004>; entry-latency-us = <600>; @@ -271,7 +271,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <1050>; @@ -279,7 +279,7 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { min-residency-us = <5309>; }; - CLUSTER_SLEEP_1: cluster-sleep-1 { + cluster_sleep_1: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41003344>; entry-latency-us = <1561>; @@ -309,57 +309,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>, <&CLUSTER_SLEEP_1>; + domain-idle-states = <&cluster_sleep_0>, <&cluster_sleep_1>; }; }; @@ -579,7 +579,7 @@ apps_rsc: rsc@17a00000 { qcom,drv-id = <2>; qcom,tcs-config = , , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi index 41216cc319d65e..9b23534c456bde 100644 --- a/arch/arm64/boot/dts/qcom/sm6115.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi @@ -40,7 +40,7 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x0>; @@ -48,18 +48,18 @@ CPU0: cpu@0 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x1>; @@ -67,13 +67,13 @@ CPU1: cpu@1 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x2>; @@ -81,13 +81,13 @@ CPU2: cpu@2 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x3>; @@ -95,13 +95,13 @@ CPU3: cpu@3 { capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; }; - CPU4: cpu@100 { + cpu4: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x100>; @@ -109,18 +109,18 @@ CPU4: cpu@100 { enable-method = "psci"; capacity-dmips-mhz = <1638>; dynamic-power-coefficient = <282>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; qcom,freq-domain = <&cpufreq_hw 1>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; - L2_1: l2-cache { + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU5: cpu@101 { + cpu5: cpu@101 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x101>; @@ -128,13 +128,13 @@ CPU5: cpu@101 { capacity-dmips-mhz = <1638>; dynamic-power-coefficient = <282>; enable-method = "psci"; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; qcom,freq-domain = <&cpufreq_hw 1>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; }; - CPU6: cpu@102 { + cpu6: cpu@102 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x102>; @@ -142,13 +142,13 @@ CPU6: cpu@102 { capacity-dmips-mhz = <1638>; dynamic-power-coefficient = <282>; enable-method = "psci"; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; qcom,freq-domain = <&cpufreq_hw 1>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; }; - CPU7: cpu@103 { + cpu7: cpu@103 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x103>; @@ -156,46 +156,46 @@ CPU7: cpu@103 { capacity-dmips-mhz = <1638>; dynamic-power-coefficient = <282>; enable-method = "psci"; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; qcom,freq-domain = <&cpufreq_hw 1>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; cluster1 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -203,7 +203,7 @@ core3 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "silver-rail-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -213,7 +213,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -225,7 +225,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_0_SLEEP_0: cluster-sleep-0-0 { + cluster_0_sleep_0: cluster-sleep-0-0 { /* GDHS */ compatible = "domain-idle-state"; arm,psci-suspend-param = <0x40000022>; @@ -234,7 +234,7 @@ CLUSTER_0_SLEEP_0: cluster-sleep-0-0 { min-residency-us = <782>; }; - CLUSTER_0_SLEEP_1: cluster-sleep-0-1 { + cluster_0_sleep_1: cluster-sleep-0-1 { /* Power Collapse */ compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; @@ -243,7 +243,7 @@ CLUSTER_0_SLEEP_1: cluster-sleep-0-1 { min-residency-us = <7376>; }; - CLUSTER_1_SLEEP_0: cluster-sleep-1-0 { + cluster_1_sleep_0: cluster-sleep-1-0 { /* GDHS */ compatible = "domain-idle-state"; arm,psci-suspend-param = <0x40000042>; @@ -252,7 +252,7 @@ CLUSTER_1_SLEEP_0: cluster-sleep-1-0 { min-residency-us = <660>; }; - CLUSTER_1_SLEEP_1: cluster-sleep-1-1 { + cluster_1_sleep_1: cluster-sleep-1-1 { /* Power Collapse */ compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; @@ -306,62 +306,62 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_0_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_0_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_0_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_0_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_0_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_0_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_0_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_0_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_1_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_1_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_1_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_1_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_1_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_1_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_1_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_1_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_0_PD: power-domain-cpu-cluster0 { + cluster_0_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_0_SLEEP_0>, <&CLUSTER_0_SLEEP_1>; + domain-idle-states = <&cluster_0_sleep_0>, <&cluster_0_sleep_1>; }; - CLUSTER_1_PD: power-domain-cpu-cluster1 { + cluster_1_pd: power-domain-cpu-cluster1 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_1_SLEEP_0>, <&CLUSTER_1_SLEEP_1>; + domain-idle-states = <&cluster_1_sleep_0>, <&cluster_1_sleep_1>; }; }; @@ -1178,7 +1178,7 @@ opp-202000000 { }; }; - ufs_mem_hc: ufs@4804000 { + ufs_mem_hc: ufshc@4804000 { compatible = "qcom,sm6115-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x04804000 0x0 0x3000>, <0x0 0x04810000 0x0 0x8000>; reg-names = "std", "ice"; @@ -2405,7 +2405,7 @@ etm@9040000 { clock-names = "apb_pclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU0>; + cpu = <&cpu0>; status = "disabled"; @@ -2426,7 +2426,7 @@ etm@9140000 { clock-names = "apb_pclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU1>; + cpu = <&cpu1>; status = "disabled"; @@ -2447,7 +2447,7 @@ etm@9240000 { clock-names = "apb_pclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU2>; + cpu = <&cpu2>; status = "disabled"; @@ -2468,7 +2468,7 @@ etm@9340000 { clock-names = "apb_pclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU3>; + cpu = <&cpu3>; status = "disabled"; @@ -2489,7 +2489,7 @@ etm@9440000 { clock-names = "apb_pclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU4>; + cpu = <&cpu4>; status = "disabled"; @@ -2510,7 +2510,7 @@ etm@9540000 { clock-names = "apb_pclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU5>; + cpu = <&cpu5>; status = "disabled"; @@ -2531,7 +2531,7 @@ etm@9640000 { clock-names = "apb_pclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU6>; + cpu = <&cpu6>; status = "disabled"; @@ -2552,7 +2552,7 @@ etm@9740000 { clock-names = "apb_pclk"; arm,coresight-loses-context-with-cpu; - cpu = <&CPU7>; + cpu = <&cpu7>; status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sm6125.dtsi b/arch/arm64/boot/dts/qcom/sm6125.dtsi index 133610d14fc41a..17d528d639343b 100644 --- a/arch/arm64/boot/dts/qcom/sm6125.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6125.dtsi @@ -37,122 +37,122 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x0>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_0>; - L2_0: l2-cache { + next-level-cache = <&l2_0>; + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@1 { + cpu1: cpu@1 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x1>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU2: cpu@2 { + cpu2: cpu@2 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x2>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU3: cpu@3 { + cpu3: cpu@3 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x3>; enable-method = "psci"; capacity-dmips-mhz = <1024>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; }; - CPU4: cpu@100 { + cpu4: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x100>; enable-method = "psci"; capacity-dmips-mhz = <1638>; - next-level-cache = <&L2_1>; - L2_1: l2-cache { + next-level-cache = <&l2_1>; + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU5: cpu@101 { + cpu5: cpu@101 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x101>; enable-method = "psci"; capacity-dmips-mhz = <1638>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; - CPU6: cpu@102 { + cpu6: cpu@102 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x102>; enable-method = "psci"; capacity-dmips-mhz = <1638>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; - CPU7: cpu@103 { + cpu7: cpu@103 { device_type = "cpu"; compatible = "qcom,kryo260"; reg = <0x0 0x103>; enable-method = "psci"; capacity-dmips-mhz = <1638>; - next-level-cache = <&L2_1>; + next-level-cache = <&l2_1>; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; cluster1 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -763,7 +763,7 @@ sdhc_2: mmc@4784000 { status = "disabled"; }; - ufs_mem_hc: ufs@4804000 { + ufs_mem_hc: ufshc@4804000 { compatible = "qcom,sm6125-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x04804000 0x3000>, <0x04810000 0x8000>; reg-names = "std", "ice"; diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi index 7986ddb30f6e8c..8d697280249fef 100644 --- a/arch/arm64/boot/dts/qcom/sm6350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi @@ -45,7 +45,7 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo560"; reg = <0x0 0x0>; @@ -53,21 +53,21 @@ CPU0: cpu@0 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ACTIVE_ONLY>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -75,7 +75,7 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo560"; reg = <0x0 0x100>; @@ -83,24 +83,24 @@ CPU1: cpu@100 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_100>; + next-level-cache = <&l2_100>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ACTIVE_ONLY>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo560"; reg = <0x0 0x200>; @@ -108,24 +108,24 @@ CPU2: cpu@200 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ACTIVE_ONLY>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo560"; reg = <0x0 0x300>; @@ -133,24 +133,24 @@ CPU3: cpu@300 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_300>; + next-level-cache = <&l2_300>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ACTIVE_ONLY>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo560"; reg = <0x0 0x400>; @@ -158,24 +158,24 @@ CPU4: cpu@400 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_400>; + next-level-cache = <&l2_400>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ACTIVE_ONLY>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo560"; reg = <0x0 0x500>; @@ -183,24 +183,24 @@ CPU5: cpu@500 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; - next-level-cache = <&L2_500>; + next-level-cache = <&l2_500>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ACTIVE_ONLY>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo560"; reg = <0x0 0x600>; @@ -208,24 +208,24 @@ CPU6: cpu@600 { enable-method = "psci"; capacity-dmips-mhz = <1894>; dynamic-power-coefficient = <703>; - next-level-cache = <&L2_600>; + next-level-cache = <&l2_600>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu6_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ACTIVE_ONLY>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo560"; reg = <0x0 0x700>; @@ -233,61 +233,61 @@ CPU7: cpu@700 { enable-method = "psci"; capacity-dmips-mhz = <1894>; dynamic-power-coefficient = <703>; - next-level-cache = <&L2_700>; + next-level-cache = <&l2_700>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu6_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ACTIVE_ONLY &clk_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ACTIVE_ONLY>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; domain-idle-states { - CLUSTER_SLEEP_PC: cluster-sleep-0 { + cluster_sleep_pc: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <2752>; @@ -295,7 +295,7 @@ CLUSTER_SLEEP_PC: cluster-sleep-0 { min-residency-us = <6118>; }; - CLUSTER_SLEEP_CX_RET: cluster-sleep-1 { + cluster_sleep_cx_ret: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41001244>; entry-latency-us = <3638>; @@ -303,7 +303,7 @@ CLUSTER_SLEEP_CX_RET: cluster-sleep-1 { min-residency-us = <8467>; }; - CLUSTER_AOSS_SLEEP: cluster-sleep-2 { + cluster_aoss_sleep: cluster-sleep-2 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100b244>; entry-latency-us = <3263>; @@ -315,7 +315,7 @@ CLUSTER_AOSS_SLEEP: cluster-sleep-2 { cpu_idle_states: idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -325,7 +325,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { + little_cpu_sleep_1: cpu-sleep-0-1 { compatible = "arm,idle-state"; idle-state-name = "little-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -335,7 +335,7 @@ LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -345,7 +345,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { local-timer-stop; }; - BIG_CPU_SLEEP_1: cpu-sleep-1-1 { + big_cpu_sleep_1: cpu-sleep-1-1 { compatible = "arm,idle-state"; idle-state-name = "big-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -504,59 +504,59 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_PC - &CLUSTER_SLEEP_CX_RET - &CLUSTER_AOSS_SLEEP>; + domain-idle-states = <&cluster_sleep_pc + &cluster_sleep_cx_ret + &cluster_aoss_sleep>; }; }; @@ -1136,7 +1136,7 @@ mmss_noc: interconnect@1740000 { qcom,bcm-voters = <&apps_bcm_voter>; }; - ufs_mem_hc: ufs@1d84000 { + ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,sm6350-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0 0x01d84000 0 0x3000>, @@ -1376,43 +1376,43 @@ gpu_opp_table: opp-table { opp-850000000 { opp-hz = /bits/ 64 <850000000>; opp-level = ; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x03>; }; opp-800000000 { opp-hz = /bits/ 64 <800000000>; opp-level = ; - opp-supported-hw = <0x04>; + opp-supported-hw = <0x07>; }; opp-650000000 { opp-hz = /bits/ 64 <650000000>; opp-level = ; - opp-supported-hw = <0x08>; + opp-supported-hw = <0x0f>; }; opp-565000000 { opp-hz = /bits/ 64 <565000000>; opp-level = ; - opp-supported-hw = <0x10>; + opp-supported-hw = <0x1f>; }; opp-430000000 { opp-hz = /bits/ 64 <430000000>; opp-level = ; - opp-supported-hw = <0xff>; + opp-supported-hw = <0x1f>; }; opp-355000000 { opp-hz = /bits/ 64 <355000000>; opp-level = ; - opp-supported-hw = <0xff>; + opp-supported-hw = <0x1f>; }; opp-253000000 { opp-hz = /bits/ 64 <253000000>; opp-level = ; - opp-supported-hw = <0xff>; + opp-supported-hw = <0x1f>; }; }; }; @@ -2685,6 +2685,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; intc: interrupt-controller@17a00000 { @@ -2776,7 +2777,7 @@ apps_rsc: rsc@18200000 { qcom,drv-id = <2>; qcom,tcs-config = , , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; rpmhcc: clock-controller { compatible = "qcom,sm6350-rpmh-clk"; @@ -2953,7 +2954,7 @@ cpu0-crit { cooling-maps { map0 { trip = <&cpu0_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -2978,7 +2979,7 @@ cpu1-crit { cooling-maps { map0 { trip = <&cpu1_alert0>; - cooling-device = <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3003,7 +3004,7 @@ cpu2-crit { cooling-maps { map0 { trip = <&cpu2_alert0>; - cooling-device = <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3028,7 +3029,7 @@ cpu3-crit { cooling-maps { map0 { trip = <&cpu3_alert0>; - cooling-device = <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3053,7 +3054,7 @@ cpu4-crit { cooling-maps { map0 { trip = <&cpu4_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3078,7 +3079,7 @@ cpu5-crit { cooling-maps { map0 { trip = <&cpu5_alert0>; - cooling-device = <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3103,7 +3104,7 @@ cpu6-left-crit { cooling-maps { map0 { trip = <&cpu6_left_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3128,7 +3129,7 @@ cpu6-right-crit { cooling-maps { map0 { trip = <&cpu6_right_alert0>; - cooling-device = <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3153,7 +3154,7 @@ cpu7-left-crit { cooling-maps { map0 { trip = <&cpu7_left_alert0>; - cooling-device = <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3178,7 +3179,7 @@ cpu7-right-crit { cooling-maps { map0 { trip = <&cpu7_right_alert0>; - cooling-device = <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6375.dtsi b/arch/arm64/boot/dts/qcom/sm6375.dtsi index 4d519dd6e7ef2f..e0b1c54e98c0e8 100644 --- a/arch/arm64/boot/dts/qcom/sm6375.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6375.dtsi @@ -38,25 +38,25 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo660"; reg = <0x0 0x0>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&cpucp_l3 MASTER_EPSS_L3_APPS &cpucp_l3 SLAVE_EPSS_L3_SHARED>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -64,185 +64,185 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo660"; reg = <0x0 0x100>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_100>; + next-level-cache = <&l2_100>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&cpucp_l3 MASTER_EPSS_L3_APPS &cpucp_l3 SLAVE_EPSS_L3_SHARED>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo660"; reg = <0x0 0x200>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&cpucp_l3 MASTER_EPSS_L3_APPS &cpucp_l3 SLAVE_EPSS_L3_SHARED>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo660"; reg = <0x0 0x300>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_300>; + next-level-cache = <&l2_300>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&cpucp_l3 MASTER_EPSS_L3_APPS &cpucp_l3 SLAVE_EPSS_L3_SHARED>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo660"; reg = <0x0 0x400>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_400>; + next-level-cache = <&l2_400>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&cpucp_l3 MASTER_EPSS_L3_APPS &cpucp_l3 SLAVE_EPSS_L3_SHARED>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo660"; reg = <0x0 0x500>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_500>; + next-level-cache = <&l2_500>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&cpucp_l3 MASTER_EPSS_L3_APPS &cpucp_l3 SLAVE_EPSS_L3_SHARED>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo660"; reg = <0x0 0x600>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_600>; + next-level-cache = <&l2_600>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu6_opp_table>; interconnects = <&cpucp_l3 MASTER_EPSS_L3_APPS &cpucp_l3 SLAVE_EPSS_L3_SHARED>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo660"; reg = <0x0 0x700>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_700>; + next-level-cache = <&l2_700>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu6_opp_table>; interconnects = <&cpucp_l3 MASTER_EPSS_L3_APPS &cpucp_l3 SLAVE_EPSS_L3_SHARED>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -250,7 +250,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "silver-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -260,7 +260,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { + little_cpu_sleep_1: cpu-sleep-0-1 { compatible = "arm,idle-state"; idle-state-name = "silver-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -270,7 +270,7 @@ LITTLE_CPU_SLEEP_1: cpu-sleep-0-1 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "gold-power-collapse"; arm,psci-suspend-param = <0x40000003>; @@ -280,7 +280,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { local-timer-stop; }; - BIG_CPU_SLEEP_1: cpu-sleep-1-1 { + big_cpu_sleep_1: cpu-sleep-1-1 { compatible = "arm,idle-state"; idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -292,7 +292,7 @@ BIG_CPU_SLEEP_1: cpu-sleep-1-1 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <2752>; @@ -455,58 +455,58 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0 &little_cpu_sleep_1>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0 &big_cpu_sleep_1>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; power-domains = <&mpm>; - domain-idle-states = <&CLUSTER_SLEEP_0>; + domain-idle-states = <&cluster_sleep_0>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm7125.dtsi b/arch/arm64/boot/dts/qcom/sm7125.dtsi index 12dd72859a433b..a53145a610a3c8 100644 --- a/arch/arm64/boot/dts/qcom/sm7125.dtsi +++ b/arch/arm64/boot/dts/qcom/sm7125.dtsi @@ -6,11 +6,11 @@ #include "sc7180.dtsi" /* SM7125 uses Kryo 465 instead of Kryo 468 */ -&CPU0 { compatible = "qcom,kryo465"; }; -&CPU1 { compatible = "qcom,kryo465"; }; -&CPU2 { compatible = "qcom,kryo465"; }; -&CPU3 { compatible = "qcom,kryo465"; }; -&CPU4 { compatible = "qcom,kryo465"; }; -&CPU5 { compatible = "qcom,kryo465"; }; -&CPU6 { compatible = "qcom,kryo465"; }; -&CPU7 { compatible = "qcom,kryo465"; }; +&cpu0 { compatible = "qcom,kryo465"; }; +&cpu1 { compatible = "qcom,kryo465"; }; +&cpu2 { compatible = "qcom,kryo465"; }; +&cpu3 { compatible = "qcom,kryo465"; }; +&cpu4 { compatible = "qcom,kryo465"; }; +&cpu5 { compatible = "qcom,kryo465"; }; +&cpu6 { compatible = "qcom,kryo465"; }; +&cpu7 { compatible = "qcom,kryo465"; }; diff --git a/arch/arm64/boot/dts/qcom/sm7225.dtsi b/arch/arm64/boot/dts/qcom/sm7225.dtsi index b7b4044e9bb0cb..a8ffdfb254fe61 100644 --- a/arch/arm64/boot/dts/qcom/sm7225.dtsi +++ b/arch/arm64/boot/dts/qcom/sm7225.dtsi @@ -6,14 +6,14 @@ #include "sm6350.dtsi" /* SM7225 uses Kryo 570 instead of Kryo 560 */ -&CPU0 { compatible = "qcom,kryo570"; }; -&CPU1 { compatible = "qcom,kryo570"; }; -&CPU2 { compatible = "qcom,kryo570"; }; -&CPU3 { compatible = "qcom,kryo570"; }; -&CPU4 { compatible = "qcom,kryo570"; }; -&CPU5 { compatible = "qcom,kryo570"; }; -&CPU6 { compatible = "qcom,kryo570"; }; -&CPU7 { compatible = "qcom,kryo570"; }; +&cpu0 { compatible = "qcom,kryo570"; }; +&cpu1 { compatible = "qcom,kryo570"; }; +&cpu2 { compatible = "qcom,kryo570"; }; +&cpu3 { compatible = "qcom,kryo570"; }; +&cpu4 { compatible = "qcom,kryo570"; }; +&cpu5 { compatible = "qcom,kryo570"; }; +&cpu6 { compatible = "qcom,kryo570"; }; +&cpu7 { compatible = "qcom,kryo570"; }; &cpu0_opp_table { opp-1804800000 { diff --git a/arch/arm64/boot/dts/qcom/sm7325-nothing-spacewar.dts b/arch/arm64/boot/dts/qcom/sm7325-nothing-spacewar.dts new file mode 100644 index 00000000000000..a5cda478bd78bf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm7325-nothing-spacewar.dts @@ -0,0 +1,1260 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2024, Eugene Lepshy + * Copyright (c) 2024, Danila Tikhonov + */ + +/dts-v1/; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm7325.dtsi" +#include "pm7325.dtsi" +#include "pm8350b.dtsi" /* PM7325B */ +#include "pm8350c.dtsi" /* PM7350C */ +#include "pmk8350.dtsi" /* PMK7325 */ + +/delete-node/ &rmtfs_mem; + +/ { + model = "Nothing Phone (1)"; + compatible = "nothing,spacewar", "qcom,sm7325"; + chassis-type = "handset"; + + aliases { + bluetooth0 = &bluetooth; + serial0 = &uart5; + serial1 = &uart7; + wifi0 = &wifi; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0:115200n8"; + + framebuffer0: framebuffer@e1000000 { + compatible = "simple-framebuffer"; + reg = <0x0 0xe1000000 0x0 (1080 * 2400 * 4)>; + width = <1080>; + height = <2400>; + stride = <(1080 * 4)>; + format = "a8r8g8b8"; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + power-domains = <&dispcc DISP_CC_MDSS_CORE_GDSC>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&kypd_volp_n>; + pinctrl-names = "default"; + + key-volume-up { + label = "Volume up"; + gpios = <&pm7325_gpios 6 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + pmic-glink { + compatible = "qcom,sm7325-pmic-glink", + "qcom,qcm6490-pmic-glink", + "qcom,pmic-glink"; + + #address-cells = <1>; + #size-cells = <0>; + + orientation-gpios = <&tlmm 140 GPIO_ACTIVE_HIGH>; + + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_hs_in: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_sbu: endpoint { + remote-endpoint = <&fsa4480_sbu_mux>; + }; + }; + }; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ramoops_mem: ramoops@83a00000 { + compatible = "ramoops"; + reg = <0x0 0x83a00000 0x0 0x400000>; + pmsg-size = <0x200000>; + mem-type = <2>; + console-size = <0x200000>; + }; + + cdsp_mem: cdsp@88f00000 { + reg = <0x0 0x88f00000 0x0 0x1e00000>; + no-map; + }; + + removed_mem: removed@c0000000 { + reg = <0x0 0xc0000000 0x0 0x5100000>; + no-map; + }; + + cont_splash_mem: cont-splash@e1000000 { + reg = <0x0 0xe1000000 0x0 (1080 * 2400 * 4)>; + no-map; + }; + + rmtfs_mem: rmtfs@f8500000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0xf8500000 0x0 0x600000>; + no-map; + + qcom,client-id = <1>; + qcom,vmid = , + ; + }; + }; + + thermal-zones { + camera-thermal { + polling-delay-passive = <0>; + thermal-sensors = <&pmk8350_adc_tm 2>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + chg-skin-thermal { + polling-delay-passive = <0>; + thermal-sensors = <&pmk8350_adc_tm 6>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + conn-thermal { + polling-delay-passive = <0>; + thermal-sensors = <&pmk8350_adc_tm 5>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-thermal { + polling-delay-passive = <0>; + thermal-sensors = <&pmk8350_adc_tm 1>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + rear-cam-thermal { + polling-delay-passive = <0>; + thermal-sensors = <&pmk8350_adc_tm 4>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + sdm-skin-thermal { + polling-delay-passive = <0>; + thermal-sensors = <&pmk8350_adc_tm 3>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-thermal { + polling-delay-passive = <0>; + thermal-sensors = <&pmk8350_adc_tm 0>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + + // S2B is really ebi.lvl but it's there for supply map completeness sake. + vreg_s2b_0p7: smpa3-regulator { + compatible = "regulator-fixed"; + regulator-name = "vreg_s2b_0p7"; + + regulator-min-microvolt = <65535>; + regulator-max-microvolt = <65535>; + regulator-always-on; + vin-supply = <&vph_pwr>; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm7325-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + + vdd-l1-l4-l12-l15-supply = <&vreg_s7b_0p952>; + vdd-l2-l7-supply = <&vreg_bob>; + vdd-l3-supply = <&vreg_s2b_0p7>; + vdd-l5-supply = <&vreg_s2b_0p7>; + vdd-l6-l9-l10-supply = <&vreg_s8b_1p256>; + vdd-l8-supply = <&vreg_s7b_0p952>; + vdd-l11-l17-l18-l19-supply = <&vreg_s1b_1p856>; + vdd-l13-supply = <&vreg_s7b_0p952>; + vdd-l14-l16-supply = <&vreg_s8b_1p256>; + + /* + * S2, L4-L5 are ARCs: + * S2 - ebi.lvl, + * L4 - lmx.lvl, + * l5 - lcx.lvl. + * + * L10 are unused. + */ + + vdd19_pmu_rfa_i: + vreg_s1b_1p856: smps1 { + regulator-name = "vreg_s1b_1p856"; + regulator-min-microvolt = <1840000>; + regulator-max-microvolt = <2040000>; + }; + + vdd_pmu_aon_i: + vdd09_pmu_rfa_i: + vdd095_mx_pmu: + vdd095_pmu_1: + vdd095_pmu_2: + vreg_s7b_0p952: smps7 { + regulator-name = "vreg_s7b_0p952"; + regulator-min-microvolt = <535000>; + regulator-max-microvolt = <1120000>; + }; + + vdd13_pmu_rfa_i: + vreg_s8b_1p256: smps8 { + regulator-name = "vreg_s8b_1p256"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1500000>; + regulator-initial-mode = ; + }; + + vreg_l1b_0p912: ldo1 { + regulator-name = "vreg_l1b_0p912"; + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <925000>; + regulator-initial-mode = ; + }; + + vdd_a_usbhs_3p1: + vreg_l2b_3p072: ldo2 { + regulator-name = "vreg_l2b_3p072"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vdd_io_ebi0_1: + vdd_io_ebi0_2: + vdd_io_ebi0_3: + vdd_io_ebi0_4: + vdd_io_ebi1_1: + vdd_io_ebi1_2: + vdd_io_ebi1_3: + vdd_io_ebi1_4: + vreg_l3b_0p6: ldo3 { + regulator-name = "vreg_l3b_0p6"; + regulator-min-microvolt = <312000>; + regulator-max-microvolt = <910000>; + regulator-initial-mode = ; + }; + + vdd_a_csi_01_1p2: + vdd_a_csi_23_1p2: + vdd_a_csi_4_1p2: + vdd_a_dsi_0_1p2: + vdd_a_qlink_0_1p2_ck: + vdd_a_qlink_1_1p2: + vdd_a_ufs_0_1p2: + vdd_vref_1p2_1: + vdd_vref_1p2_2: + vreg_l6b_1p2: ldo6 { + regulator-name = "vreg_l6b_1p2"; + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7b_2p96: ldo7 { + regulator-name = "vreg_l7b_2p96"; + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l8b_0p904: ldo8 { + regulator-name = "vreg_l8b_0p904"; + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <970000>; + regulator-initial-mode = ; + }; + + vdd_px10: + vreg_l9b_1p2: ldo9 { + regulator-name = "vreg_l9b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vddah_0: + vddah_1: + vddah_fbrx: + vddah_tx0: + vddah_tx0_1: + vddah_tx1: + vddah_tx1_1: + vreg_l11b_1p776: ldo11 { + regulator-name = "vreg_l11b_1p776"; + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vddal_dig0: + vddal_dig_1: + vddal_dig_2: + vddal_dig_xo: + vddal_gps_l1: + vddal_gps_l5: + vddal_icon: + vddal_rx: + vddal_rx0: + vddal_rx1: + vddal_rx2: + vddal_tx0: + vddal_tx0_1: + vddal_tx1: + vddal_tx1_2: + vreg_l12b_0p8: ldo12 { + regulator-name = "vreg_l12b_0p8"; + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vdd_cx1: + vdd_cx2: + vreg_l13b_0p8: ldo13 { + regulator-name = "vreg_l13b_0p8"; + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vdd_1p2: + vdd_lna: + vddam_fbrx: + vddam_rx_0: + vddam_rx_1: + vddam_rx0: + vddam_rx1: + vddam_rx2: + vddam_rxe_a: + vddam_rxe_b: + vddam_rxe_c: + vddam_rxe_d: + vddam_rxe_e: + vddam_tx0: + vddam_tx0_1: + vddam_tx1: + vddam_tx1_1: + vddam_xo: + vreg_l14b_1p2: ldo14 { + regulator-name = "vreg_l14b_1p2"; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vdd_mx: + vddmx_tx: + vdd_phy: + vreg_l15b_0p88: ldo15 { + regulator-name = "vreg_l15b_0p88"; + regulator-min-microvolt = <765000>; + regulator-max-microvolt = <1020000>; + regulator-initial-mode = ; + }; + + vreg_l16b_1p2: ldo16 { + regulator-name = "vreg_l16b_1p2"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vdd_buck: + vreg_l17b_1p8: ldo17 { + regulator-name = "vreg_l17b_1p8"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + }; + + vdd_px_wcd9385: + vdd_txrx: + vdd_px0: + vdd_px3: + vdd_px7: + vreg_l18b_1p8: ldo18 { + regulator-name = "vreg_l18b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vdd_1p8: + vdd_px_sdr735: + vdd_pxm: + vddio_px_1: + vddio_px_2: + vddio_px_3: + vdd18_io: + vddpx_ts: + vddpx_wl4otp: + vreg_l19b_1p8: ldo19 { + regulator-name = "vreg_l19b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + + vdd-l1-l12-supply = <&vreg_s1b_1p856>; + vdd-l2-l8-supply = <&vreg_s1b_1p856>; + vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob>; + vdd-l6-l9-l11-supply = <&vreg_bob>; + vdd-l10-supply = <&vreg_s7b_0p952>; + + vdd-bob-supply = <&vph_pwr>; + + /* + * S2, S5, S7, S10 are ARCs: + * S2 - cx.lvl, + * S5 - mss.lvl, + * S7 - gfx.lvl, + * S10 - mx.lvl. + */ + + vdd22_wlbtpa_ch0: + vdd22_wlbtpa_ch1: + vdd22_wlbtppa_ch0: + vdd22_wlbtppa_ch1: + vdd22_wlpa5g_ch0: + vdd22_wlpa5g_ch1: + vdd22_wlppa5g_ch0: + vdd22_wlppa5g_ch1: + vreg_s1c_2p2: smps1 { + regulator-name = "vreg_s1c_2p2"; + regulator-min-microvolt = <2190000>; + regulator-max-microvolt = <2210000>; + }; + + vdd_px1: + vreg_s9c_0p676: smps9 { + regulator-name = "vreg_s9c_0p676"; + regulator-min-microvolt = <1010000>; + regulator-max-microvolt = <1170000>; + }; + + vdd_a_apc_cs_1p8: + vdd_a_cxo_1p8: + vdd_a_gfx_cs_1p8: + vdd_a_qrefs_1p8: + vdd_a_turing_q6_cs_1p8: + vdd_a_usbhs_1p8: + vdd_qfprom: + vreg_l1c_1p8: ldo1 { + regulator-name = "vreg_l1c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l2c_1p8: ldo2 { + regulator-name = "vreg_l2c_1p8"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vdd_ts: + vreg_l3c_3p0: ldo3 { + regulator-name = "vreg_l3c_3p0"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3540000>; + regulator-initial-mode = ; + }; + + vdd_px5: + vreg_l4c_1p8_3p0: ldo4 { + regulator-name = "vreg_l4c_1p8_3p0"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vdd_px6: + vreg_l5c_1p8_3p0: ldo5 { + regulator-name = "vreg_l5c_1p8_3p0"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vdd_px2: + vreg_l6c_2p96: ldo6 { + regulator-name = "vreg_l6c_2p96"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vdd_sensor_3p3: + vreg_l7c_3p0: ldo7 { + regulator-name = "vreg_l7c_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vdd_sensor_1p8: + vreg_l8c_1p8: ldo8 { + regulator-name = "vreg_l8c_1p8"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p96: ldo9 { + regulator-name = "vreg_l9c_2p96"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vdd_a_csi_01_0p9: + vdd_a_csi_23_0p9: + vdd_a_csi_4_0p9: + vdd_a_dsi_0_0p9: + vdd_a_dsi_0_pll_0p9: + vdd_a_gnss_0p9: + vdd_a_qlink_0_0p9: + vdd_a_qlink_0_0p9_ck: + vdd_a_qlink_1_0p9: + vdd_a_qlink_1_0p9_ck: + vdd_a_qrefs_0p875_1: + vdd_a_qrefs_0p875_2: + vdd_a_qrefs_0p875_3: + vdd_a_qrefs_0p875_4: + vdd_a_qrefs_0p875_5: + vdd_a_qrefs_0p875_6: + vdd_a_qrefs_0p875_7: + vdd_a_qrefs_0p875_8: + vdd_a_qrefs_0p875_9: + vdd_a_ufs_0_core: + vdd_a_usbhs_core: + vdd_vref_0p9: + vreg_l10c_0p88: ldo10 { + regulator-name = "vreg_l10c_0p88"; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1050000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vdd_fm: + vdd_wlan_fem: + vreg_l11c_2p8: ldo11 { + regulator-name = "vreg_l11c_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vdd_io_oled: + vreg_l12c_1p8: ldo12 { + regulator-name = "vreg_l12c_1p8"; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vdd_oled: + vreg_l13c_3p0: ldo13 { + regulator-name = "vreg_l13c_3p0"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vdd_flash: + vdd_mic_bias: + vreg_bob: bob { + regulator-name = "vreg_bob"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + }; +}; + +&cci0 { + status = "okay"; +}; + +&cci0_i2c0 { + /* sony,imx471 (Front) */ +}; + +&cci1 { + status = "okay"; +}; + +&cci1_i2c0 { + /* samsung,s5kjn1 (Rear-aux UW) */ +}; + +&cci1_i2c1 { + /* sony,imx766 (Rear Wide) */ +}; + +&gcc { + protected-clocks = , + , + , + , + , + , + , + , + , + , + , + , + ; +}; + +&gpi_dma0 { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + +&gpu_zap_shader { + firmware-name = "qcom/sm7325/nothing/spacewar/a660_zap.mbn"; +}; + +&i2c1 { + clock-frequency = <100000>; + status = "okay"; + + /* awinic,aw21018 (Glyph LED) @ 20 */ + + typec-mux@42 { + compatible = "fcs,fsa4480"; + reg = <0x42>; + + vcc-supply = <&vreg_bob>; + + mode-switch; + orientation-switch; + + port { + fsa4480_sbu_mux: endpoint { + remote-endpoint = <&pmic_glink_sbu>; + }; + }; + }; +}; + +&i2c2 { + clock-frequency = <100000>; + status = "okay"; + + /* nxp,tfa9873 (EAR speaker codec) @ 34 */ + /* nxp,tfa9873 (Main speaker codec) @ 35 */ +}; + +&i2c9 { + clock-frequency = <1000000>; + status = "okay"; + + nfc@28 { + compatible = "nxp,pn553", + "nxp,nxp-nci-i2c"; + reg = <0x28>; + + interrupt-parent = <&tlmm>; + interrupts = <41 IRQ_TYPE_EDGE_RISING>; + + enable-gpios = <&tlmm 38 GPIO_ACTIVE_HIGH>; + firmware-gpios = <&tlmm 40 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&nfc_en>, + <&nfc_clk_req>, + <&nfc_dwl_req>, + <&nfc_int_req>; + pinctrl-names = "default"; + }; +}; + +&ipa { + qcom,gsi-loader = "self"; + memory-region = <&ipa_fw_mem>; + firmware-name = "qcom/sm7325/nothing/spacewar/ipa_fws.mbn"; + + status = "okay"; +}; + +/* MDSS remains disabled until the panel driver is present. */ +&mdss_dsi { + vdda-supply = <&vdd_a_dsi_0_1p2>; + + /* Visionox RM692E5 panel */ +}; + +&mdss_dsi_phy { + vdds-supply = <&vdd_a_dsi_0_0p9>; +}; + +&pm7325_gpios { + gpio-line-names = "NC", /* GPIO_1 */ + "PA_THERM3", + "PA_THERM4", + "NC", + "NC", + "KYPD_VOLP_N", + "NC", + "NC", + "NC", + "NC"; /* GPIO_10 */ + + kypd_volp_n: kypd-volp-n-state { + pins = "gpio6"; + function = PMIC_GPIO_FUNC_NORMAL; + bias-pull-up; + input-enable; + power-source = <1>; + }; +}; + +&pm8350c_flash { + status = "okay"; + + led-0 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <1>, <4>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; +}; + +&pmk8350_adc_tm { + status = "okay"; + + /* PMK8350 */ + xo-therm@0 { + reg = <0>; + io-channels = <&pmk8350_vadc PMK8350_ADC7_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + /* PM7325 */ + quiet-therm@1 { + reg = <1>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + cam-flash-therm@2 { + reg = <2>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + sdm-skin-therm@3 { + reg = <3>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM3_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + wide-rfc-therm@4 { + reg = <4>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM4_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + /* PM8350B */ + usb-conn-therm@5 { + reg = <5>; + io-channels = <&pmk8350_vadc PM8350B_ADC7_AMUX_THM4_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + chg-skin-therm@6 { + reg = <6>; + io-channels = <&pmk8350_vadc PM8350B_ADC7_GPIO2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + +&pmk8350_rtc { + status = "okay"; +}; + +&pmk8350_vadc { + /* PMK8350 */ + channel@44 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pmk8350_xo_therm"; + }; + + /* PM7325 */ + channel@144 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_quiet_therm"; + }; + + channel@145 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_cam_flash_therm"; + }; + + channel@146 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_sdm_skin_therm"; + }; + + channel@147 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_wide_rfc_therm"; + }; + + channel@14a { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_pa3_therm"; + }; + + channel@14b { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_pa4_therm"; + }; + + /* PM8350B */ + channel@344 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm8350b_batt_therm"; + }; + + channel@347 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm8350b_usb_conn_therm"; + }; + + channel@34b { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm8350b_chg_skin_therm"; + }; + + channel@34c { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm8350b_usb_therm2"; + }; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + linux,code = ; + status = "okay"; +}; + +&q6afedai { + dai@16 { + reg = ; + qcom,sd-lines = <1>; + }; +}; + +&q6asmdai { + dai@0 { + reg = <0>; + }; +}; + +&qfprom { + vcc-supply = <&vdd_qfprom>; +}; + +&qup_uart5_rx { + drive-strength = <2>; + bias-disable; +}; + +&qup_uart5_tx { + drive-strength = <2>; + bias-disable; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&remoteproc_adsp { + firmware-name = "qcom/sm7325/nothing/spacewar/adsp.mbn"; + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/sm7325/nothing/spacewar/cdsp.mbn"; + status = "okay"; +}; + +&remoteproc_mpss { + firmware-name = "qcom/sm7325/nothing/spacewar/modem.mbn"; + status = "okay"; +}; + +&remoteproc_wpss { + firmware-name = "qcom/sm7325/nothing/spacewar/wpss.mbn"; + status = "okay"; +}; + +&spi13 { + status = "okay"; + + /* focaltech,ft3680 (Touchscreen) @ 0 */ +}; + +&tlmm { + /* 56-59: Fingerprint reader (SPI) */ + gpio-reserved-ranges = <56 4>; + + bt_uart_sleep_cts: bt-uart-sleep-cts-state { + pins = "gpio28"; + function = "gpio"; + bias-bus-hold; + }; + + bt_uart_sleep_rts: bt-uart-sleep-rts-state { + pins = "gpio29"; + function = "gpio"; + bias-pull-down; + }; + + bt_uart_sleep_txd: bt-uart-sleep-txd-state { + pins = "gpio30"; + function = "gpio"; + bias-pull-up; + }; + + bt_uart_sleep_rxd: bt-uart-sleep-rxd-state { + pins = "gpio31"; + function = "gpio"; + bias-pull-up; + }; + + nfc_en: nfc-en-state { + pins = "gpio38"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + nfc_clk_req: nfc-clk-req-state { + pins = "gpio39"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + nfc_dwl_req: nfc-dwl-req-state { + pins = "gpio40"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + nfc_int_req: nfc-int-req-state { + pins = "gpio41"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + hst_bt_en: hst-bt-en-state { + pins = "gpio85"; + function = "gpio"; + output-low; + bias-disable; + }; + + hst_sw_ctrl: hst-sw-ctrl-state { + pins = "gpio86"; + function = "gpio"; + bias-pull-down; + }; +}; + +&uart5 { + status = "okay"; +}; + +&uart7 { + /delete-property/interrupts; + interrupts-extended = <&intc GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 31 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-1 = <&bt_uart_sleep_cts>, + <&bt_uart_sleep_rts>, + <&bt_uart_sleep_txd>, + <&bt_uart_sleep_rxd>; + pinctrl-names = "default", "sleep"; + + status = "okay"; + + bluetooth: bluetooth { + compatible = "qcom,wcn6750-bt"; + + pinctrl-0 = <&hst_bt_en>, + <&hst_sw_ctrl>; + pinctrl-names = "default"; + + enable-gpios = <&tlmm 85 GPIO_ACTIVE_HIGH>; + swctrl-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&vreg_l19b_1p8>; + vddaon-supply = <&vreg_s7b_0p952>; + vddbtcxmx-supply = <&vreg_s7b_0p952>; + vddrfacmn-supply = <&vreg_s7b_0p952>; + vddrfa0p8-supply = <&vreg_s7b_0p952>; + vddrfa1p7-supply = <&vdd19_pmu_rfa_i>; + vddrfa1p2-supply = <&vdd13_pmu_rfa_i>; + vddrfa2p2-supply = <&vreg_s1c_2p2>; + vddasd-supply = <&vreg_l11c_2p8>; + max-speed = <3200000>; + + qcom,local-bd-address-broken; + }; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l7b_2p96>; + vcc-max-microamp = <800000>; + /* + * Technically l9b enables an eLDO (supplied by s1b) which then powers + * VCCQ2 of the UFS. + */ + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <900000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vdd_a_ufs_0_core>; + vdda-pll-supply = <&vdd_a_ufs_0_1p2>; + status = "okay"; +}; + +&usb_1 { + /* USB 2.0 only */ + qcom,select-utmi-as-pipe-clk; + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "otg"; + usb-role-switch; + maximum-speed = "high-speed"; + /* Remove USB3 phy */ + phys = <&usb_1_hsphy>; + phy-names = "usb2-phy"; +}; + +&usb_1_dwc3_hs { + remote-endpoint = <&pmic_glink_hs_in>; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vdd_a_usbhs_core>; + vdda18-supply = <&vdd_a_usbhs_1p8>; + vdda33-supply = <&vdd_a_usbhs_3p1>; + status = "okay"; +}; + +&venus { + firmware-name = "qcom/sm7325/nothing/spacewar/vpu20_1v.mbn"; + status = "okay"; +}; + +&wifi { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm7325.dtsi b/arch/arm64/boot/dts/qcom/sm7325.dtsi new file mode 100644 index 00000000000000..85d34b53e5e9d1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm7325.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2024, Eugene Lepshy + * Copyright (c) 2024, Danila Tikhonov + */ + +#include "sc7280.dtsi" + +/* SM7325 uses Kryo 670 */ +&cpu0 { compatible = "qcom,kryo670"; }; +&cpu1 { compatible = "qcom,kryo670"; }; +&cpu2 { compatible = "qcom,kryo670"; }; +&cpu3 { compatible = "qcom,kryo670"; }; +&cpu4 { compatible = "qcom,kryo670"; }; +&cpu5 { compatible = "qcom,kryo670"; }; +&cpu6 { compatible = "qcom,kryo670"; }; +&cpu7 { compatible = "qcom,kryo670"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 27f87835bc5595..cedae8d03a519e 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -48,7 +48,7 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x0>; @@ -56,20 +56,20 @@ CPU0: cpu@0 { enable-method = "psci"; capacity-dmips-mhz = <488>; dynamic-power-coefficient = <232>; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -77,7 +77,7 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x100>; @@ -85,23 +85,23 @@ CPU1: cpu@100 { enable-method = "psci"; capacity-dmips-mhz = <488>; dynamic-power-coefficient = <232>; - next-level-cache = <&L2_100>; + next-level-cache = <&l2_100>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x200>; @@ -109,23 +109,23 @@ CPU2: cpu@200 { enable-method = "psci"; capacity-dmips-mhz = <488>; dynamic-power-coefficient = <232>; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x300>; @@ -133,23 +133,23 @@ CPU3: cpu@300 { enable-method = "psci"; capacity-dmips-mhz = <488>; dynamic-power-coefficient = <232>; - next-level-cache = <&L2_300>; + next-level-cache = <&l2_300>; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x400>; @@ -157,23 +157,23 @@ CPU4: cpu@400 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <369>; - next-level-cache = <&L2_400>; + next-level-cache = <&l2_400>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x500>; @@ -181,23 +181,23 @@ CPU5: cpu@500 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <369>; - next-level-cache = <&L2_500>; + next-level-cache = <&l2_500>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x600>; @@ -205,23 +205,23 @@ CPU6: cpu@600 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <369>; - next-level-cache = <&L2_600>; + next-level-cache = <&l2_600>; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x700>; @@ -229,54 +229,54 @@ CPU7: cpu@700 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <421>; - next-level-cache = <&L2_700>; + next-level-cache = <&l2_700>; qcom,freq-domain = <&cpufreq_hw 2>; operating-points-v2 = <&cpu7_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&osm_l3 MASTER_OSM_L3_APPS &osm_l3 SLAVE_OSM_L3>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -284,7 +284,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "little-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -294,7 +294,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "big-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -306,7 +306,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c244>; entry-latency-us = <3263>; @@ -628,57 +628,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>; + domain-idle-states = <&cluster_sleep_0>; }; }; @@ -3096,7 +3096,7 @@ etm@7040000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07040000 0 0x1000>; - cpu = <&CPU0>; + cpu = <&cpu0>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3116,7 +3116,7 @@ etm@7140000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07140000 0 0x1000>; - cpu = <&CPU1>; + cpu = <&cpu1>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3136,7 +3136,7 @@ etm@7240000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07240000 0 0x1000>; - cpu = <&CPU2>; + cpu = <&cpu2>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3156,7 +3156,7 @@ etm@7340000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07340000 0 0x1000>; - cpu = <&CPU3>; + cpu = <&cpu3>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3176,7 +3176,7 @@ etm@7440000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07440000 0 0x1000>; - cpu = <&CPU4>; + cpu = <&cpu4>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3196,7 +3196,7 @@ etm@7540000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07540000 0 0x1000>; - cpu = <&CPU5>; + cpu = <&cpu5>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3216,7 +3216,7 @@ etm@7640000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07640000 0 0x1000>; - cpu = <&CPU6>; + cpu = <&cpu6>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3236,7 +3236,7 @@ etm@7740000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07740000 0 0x1000>; - cpu = <&CPU7>; + cpu = <&cpu7>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -4296,6 +4296,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; remoteproc_adsp: remoteproc@17300000 { @@ -4457,7 +4458,7 @@ apps_rsc: rsc@18200000 { , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; rpmhcc: clock-controller { compatible = "qcom,sm8150-rpmh-clk"; @@ -4553,7 +4554,7 @@ lmh_cluster1: lmh@18350800 { compatible = "qcom,sm8150-lmh"; reg = <0 0x18350800 0 0x400>; interrupts = ; - cpus = <&CPU4>; + cpus = <&cpu4>; qcom,lmh-temp-arm-millicelsius = <60000>; qcom,lmh-temp-low-millicelsius = <84500>; qcom,lmh-temp-high-millicelsius = <85000>; @@ -4565,7 +4566,7 @@ lmh_cluster0: lmh@18358800 { compatible = "qcom,sm8150-lmh"; reg = <0 0x18358800 0 0x400>; interrupts = ; - cpus = <&CPU0>; + cpus = <&cpu0>; qcom,lmh-temp-arm-millicelsius = <60000>; qcom,lmh-temp-low-millicelsius = <84500>; qcom,lmh-temp-high-millicelsius = <85000>; @@ -4634,17 +4635,17 @@ cpu0_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu0_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu0_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4677,17 +4678,17 @@ cpu1_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu1_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu1_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4720,17 +4721,17 @@ cpu2_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu2_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu2_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4763,17 +4764,17 @@ cpu3_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu3_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu3_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4806,17 +4807,17 @@ cpu4_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu4_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu4_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4849,17 +4850,17 @@ cpu5_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu5_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu5_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4892,17 +4893,17 @@ cpu6_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu6_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu6_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4935,17 +4936,17 @@ cpu7_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu7_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu7_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4978,17 +4979,17 @@ cpu4_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu4_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu4_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -5021,17 +5022,17 @@ cpu5_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu5_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu5_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -5064,17 +5065,17 @@ cpu6_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu6_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu6_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -5107,17 +5108,17 @@ cpu7_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu7_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu7_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index 630f4eff20bf81..48318ed1ce98ab 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -93,7 +93,7 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x0>; @@ -101,21 +101,21 @@ CPU0: cpu@0 { enable-method = "psci"; capacity-dmips-mhz = <448>; dynamic-power-coefficient = <105>; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&epss_l3 MASTER_OSM_L3_APPS &epss_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x20000>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-size = <0x400000>; @@ -124,7 +124,7 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x100>; @@ -132,24 +132,24 @@ CPU1: cpu@100 { enable-method = "psci"; capacity-dmips-mhz = <448>; dynamic-power-coefficient = <105>; - next-level-cache = <&L2_100>; - power-domains = <&CPU_PD1>; + next-level-cache = <&l2_100>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&epss_l3 MASTER_OSM_L3_APPS &epss_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x20000>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x200>; @@ -157,24 +157,24 @@ CPU2: cpu@200 { enable-method = "psci"; capacity-dmips-mhz = <448>; dynamic-power-coefficient = <105>; - next-level-cache = <&L2_200>; - power-domains = <&CPU_PD2>; + next-level-cache = <&l2_200>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&epss_l3 MASTER_OSM_L3_APPS &epss_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x20000>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x300>; @@ -182,24 +182,24 @@ CPU3: cpu@300 { enable-method = "psci"; capacity-dmips-mhz = <448>; dynamic-power-coefficient = <105>; - next-level-cache = <&L2_300>; - power-domains = <&CPU_PD3>; + next-level-cache = <&l2_300>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; operating-points-v2 = <&cpu0_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&epss_l3 MASTER_OSM_L3_APPS &epss_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x20000>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x400>; @@ -207,24 +207,24 @@ CPU4: cpu@400 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <379>; - next-level-cache = <&L2_400>; - power-domains = <&CPU_PD4>; + next-level-cache = <&l2_400>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&epss_l3 MASTER_OSM_L3_APPS &epss_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x40000>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x500>; @@ -232,24 +232,24 @@ CPU5: cpu@500 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <379>; - next-level-cache = <&L2_500>; - power-domains = <&CPU_PD5>; + next-level-cache = <&l2_500>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&epss_l3 MASTER_OSM_L3_APPS &epss_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x40000>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x600>; @@ -257,24 +257,24 @@ CPU6: cpu@600 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <379>; - next-level-cache = <&L2_600>; - power-domains = <&CPU_PD6>; + next-level-cache = <&l2_600>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; operating-points-v2 = <&cpu4_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&epss_l3 MASTER_OSM_L3_APPS &epss_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x40000>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo485"; reg = <0x0 0x700>; @@ -282,55 +282,55 @@ CPU7: cpu@700 { enable-method = "psci"; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <444>; - next-level-cache = <&L2_700>; - power-domains = <&CPU_PD7>; + next-level-cache = <&l2_700>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 2>; operating-points-v2 = <&cpu7_opp_table>; interconnects = <&gem_noc MASTER_AMPSS_M0 0 &mc_virt SLAVE_EBI_CH0 0>, <&epss_l3 MASTER_OSM_L3_APPS &epss_l3 SLAVE_OSM_L3>; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-size = <0x80000>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -338,7 +338,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "silver-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -348,7 +348,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -360,7 +360,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c244>; entry-latency-us = <3264>; @@ -689,57 +689,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>; + domain-idle-states = <&cluster_sleep_0>; }; }; @@ -3522,7 +3522,7 @@ etm@7040000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07040000 0 0x1000>; - cpu = <&CPU0>; + cpu = <&cpu0>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3541,7 +3541,7 @@ etm@7140000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07140000 0 0x1000>; - cpu = <&CPU1>; + cpu = <&cpu1>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3560,7 +3560,7 @@ etm@7240000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07240000 0 0x1000>; - cpu = <&CPU2>; + cpu = <&cpu2>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3579,7 +3579,7 @@ etm@7340000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07340000 0 0x1000>; - cpu = <&CPU3>; + cpu = <&cpu3>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3598,7 +3598,7 @@ etm@7440000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07440000 0 0x1000>; - cpu = <&CPU4>; + cpu = <&cpu4>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3617,7 +3617,7 @@ etm@7540000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07540000 0 0x1000>; - cpu = <&CPU5>; + cpu = <&cpu5>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3636,7 +3636,7 @@ etm@7640000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07640000 0 0x1000>; - cpu = <&CPU6>; + cpu = <&cpu6>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -3655,7 +3655,7 @@ etm@7740000 { compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x07740000 0 0x1000>; - cpu = <&CPU7>; + cpu = <&cpu7>; clocks = <&aoss_qmp>; clock-names = "apb_pclk"; @@ -6165,7 +6165,7 @@ apps_rsc: rsc@18200000 { qcom,drv-id = <2>; qcom,tcs-config = , , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; rpmhcc: clock-controller { compatible = "qcom,sm8250-rpmh-clk"; @@ -6302,17 +6302,17 @@ cpu0_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu0_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu0_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6345,17 +6345,17 @@ cpu1_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu1_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu1_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6388,17 +6388,17 @@ cpu2_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu2_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu2_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6431,17 +6431,17 @@ cpu3_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu3_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu3_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6474,17 +6474,17 @@ cpu4_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu4_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu4_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6517,17 +6517,17 @@ cpu5_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu5_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu5_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6560,17 +6560,17 @@ cpu6_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu6_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu6_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6603,17 +6603,17 @@ cpu7_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu7_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu7_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6646,17 +6646,17 @@ cpu4_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu4_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu4_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6689,17 +6689,17 @@ cpu5_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu5_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu5_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6732,17 +6732,17 @@ cpu6_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu6_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu6_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -6775,17 +6775,17 @@ cpu7_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu7_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu7_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8350-hdk.dts b/arch/arm64/boot/dts/qcom/sm8350-hdk.dts index 895adce59e758c..796cbb58ef6e34 100644 --- a/arch/arm64/boot/dts/qcom/sm8350-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8350-hdk.dts @@ -382,10 +382,6 @@ &cdsp { firmware-name = "qcom/sm8350/cdsp.mbn"; }; -&dispcc { - status = "okay"; -}; - &mdss_dsi0 { vdda-supply = <&vreg_l6b_1p2>; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index 37a2aba0d4cae0..877905dfd861ed 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -51,23 +51,23 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x0>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -75,171 +75,171 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x100>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_100>; + next-level-cache = <&l2_100>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x200>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "arm,cortex-a55"; reg = <0x0 0x300>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_300>; + next-level-cache = <&l2_300>; qcom,freq-domain = <&cpufreq_hw 0>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "arm,cortex-a78"; reg = <0x0 0x400>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_400>; + next-level-cache = <&l2_400>; qcom,freq-domain = <&cpufreq_hw 1>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "arm,cortex-a78"; reg = <0x0 0x500>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_500>; + next-level-cache = <&l2_500>; qcom,freq-domain = <&cpufreq_hw 1>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "arm,cortex-a78"; reg = <0x0 0x600>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_600>; + next-level-cache = <&l2_600>; qcom,freq-domain = <&cpufreq_hw 1>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "arm,cortex-x1"; reg = <0x0 0x700>; clocks = <&cpufreq_hw 2>; enable-method = "psci"; - next-level-cache = <&L2_700>; + next-level-cache = <&l2_700>; qcom,freq-domain = <&cpufreq_hw 2>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -247,7 +247,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "silver-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -257,7 +257,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -269,7 +269,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 { + cluster_sleep_apss_off: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <2752>; @@ -277,7 +277,7 @@ CLUSTER_SLEEP_APSS_OFF: cluster-sleep-0 { min-residency-us = <6118>; }; - CLUSTER_SLEEP_AOSS_SLEEP: cluster-sleep-1 { + cluster_sleep_aoss_sleep: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c344>; entry-latency-us = <3263>; @@ -320,57 +320,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_APSS_OFF &CLUSTER_SLEEP_AOSS_SLEEP>; + domain-idle-states = <&cluster_sleep_apss_off &cluster_sleep_aoss_sleep>; }; }; @@ -3282,6 +3282,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; adsp: remoteproc@17300000 { @@ -3504,7 +3505,7 @@ apps_rsc: rsc@18200000 { qcom,drv-id = <2>; qcom,tcs-config = , , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; rpmhcc: clock-controller { compatible = "qcom,sm8350-rpmh-clk"; @@ -3728,17 +3729,17 @@ cpu0_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu0_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu0_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3771,17 +3772,17 @@ cpu1_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu1_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu1_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3814,17 +3815,17 @@ cpu2_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu2_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu2_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3857,17 +3858,17 @@ cpu3_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu3_alert0>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu3_alert1>; - cooling-device = <&CPU0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3900,17 +3901,17 @@ cpu4_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu4_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu4_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3943,17 +3944,17 @@ cpu5_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu5_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu5_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -3986,17 +3987,17 @@ cpu6_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu6_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu6_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4029,17 +4030,17 @@ cpu7_top_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu7_top_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu7_top_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4072,17 +4073,17 @@ cpu4_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu4_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu4_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4115,17 +4116,17 @@ cpu5_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu5_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu5_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4158,17 +4159,17 @@ cpu6_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu6_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu6_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; @@ -4201,17 +4202,17 @@ cpu7_bottom_crit: cpu-crit { cooling-maps { map0 { trip = <&cpu7_bottom_alert0>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map1 { trip = <&cpu7_bottom_alert1>; - cooling-device = <&CPU4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&CPU7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts index a754b8fe916756..2ff40a120aadf9 100644 --- a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts @@ -26,6 +26,7 @@ / { aliases { serial0 = &uart7; + serial1 = &uart20; }; wcd938x: audio-codec { @@ -247,6 +248,71 @@ active-config0 { }; }; + wcn6855-pmu { + compatible = "qcom,wcn6855-pmu"; + + pinctrl-0 = <&bt_en>, <&wlan_en>, <&xo_clk_default>; + pinctrl-names = "default"; + + wlan-enable-gpios = <&tlmm 80 GPIO_ACTIVE_HIGH>; + bt-enable-gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>; + swctrl-gpios = <&tlmm 82 GPIO_ACTIVE_HIGH>; + xo-clk-gpios = <&tlmm 204 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&vreg_s10b_1p8>; + vddaon-supply = <&vreg_s11b_0p95>; + vddpmu-supply = <&vreg_s12b_1p25>; + vddpmumx-supply = <&vreg_s2e_0p85>; + vddpmucx-supply = <&vreg_s11b_0p95>; + vddrfa0p95-supply = <&vreg_s11b_0p95>; + vddrfa1p3-supply = <&vreg_s12b_1p25>; + vddrfa1p9-supply = <&vreg_s1c_1p86>; + vddpcie1p3-supply = <&vreg_s12b_1p25>; + vddpcie1p9-supply = <&vreg_s1c_1p86>; + + regulators { + vreg_pmu_rfa_cmn_0p8: ldo0 { + regulator-name = "vreg_pmu_rfa_cmn_0p8"; + }; + + vreg_pmu_aon_0p8: ldo1 { + regulator-name = "vreg_pmu_aon_0p8"; + }; + + vreg_pmu_wlcx_0p8: ldo2 { + regulator-name = "vreg_pmu_wlcx_0p8"; + }; + + vreg_pmu_wlmx_0p8: ldo3 { + regulator-name = "vreg_pmu_wlmx_0p8"; + }; + + vreg_pmu_btcmx_0p8: ldo4 { + regulator-name = "vreg_pmu_btcmx_0p8"; + }; + + vreg_pmu_pcie_1p8: ldo5 { + regulator-name = "vreg_pmu_pcie_1p8"; + }; + + vreg_pmu_pcie_0p9: ldo6 { + regulator-name = "vreg_pmu_pcie_0p9"; + }; + + vreg_pmu_rfa_0p8: ldo7 { + regulator-name = "vreg_pmu_rfa_0p8"; + }; + + vreg_pmu_rfa_1p2: ldo8 { + regulator-name = "vreg_pmu_rfa_1p2"; + }; + + vreg_pmu_rfa_1p7: ldo9 { + regulator-name = "vreg_pmu_rfa_1p7"; + }; + }; + }; + vph_pwr: vph-pwr-regulator { compatible = "regulator-fixed"; regulator-name = "vph_pwr"; @@ -575,10 +641,6 @@ vreg_l7e_2p8: ldo7 { }; }; -&dispcc { - status = "okay"; -}; - &gpu { status = "okay"; @@ -689,6 +751,23 @@ &pcie0_phy { vdda-pll-supply = <&vreg_l6b_1p2>; }; +&pcieport0 { + wifi@0 { + compatible = "pci17cb,1103"; + reg = <0x10000 0x0 0x0 0x0 0x0>; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>; + vddaon-supply = <&vreg_pmu_aon_0p8>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p8>; + vddpcie1p8-supply = <&vreg_pmu_pcie_1p8>; + vddpcie0p9-supply = <&vreg_pmu_pcie_0p9>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + }; +}; + &pcie1 { status = "okay"; }; @@ -896,6 +975,10 @@ &qupv3_id_1 { status = "okay"; }; +&qupv3_id_2 { + status = "okay"; +}; + &sdhc_2 { cd-gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>; pinctrl-names = "default", "sleep"; @@ -1073,6 +1156,26 @@ &uart7 { status = "okay"; }; +&uart20 { + pinctrl-0 = <&uart20_default>; + pinctrl-names = "default"; + + status = "okay"; + + bluetooth { + compatible = "qcom,wcn6855-bt"; + + vddrfacmn-supply = <&vreg_pmu_rfa_cmn_0p8>; + vddaon-supply = <&vreg_pmu_aon_0p8>; + vddwlcx-supply = <&vreg_pmu_wlcx_0p8>; + vddwlmx-supply = <&vreg_pmu_wlmx_0p8>; + vddbtcmx-supply = <&vreg_pmu_btcmx_0p8>; + vddrfa0p8-supply = <&vreg_pmu_rfa_0p8>; + vddrfa1p2-supply = <&vreg_pmu_rfa_1p2>; + vddrfa1p8-supply = <&vreg_pmu_rfa_1p7>; + }; +}; + &ufs_mem_hc { status = "okay"; @@ -1134,6 +1237,14 @@ &vamacro { }; &tlmm { + bt_en: bt-en-state { + pins = "gpio81"; + function = "gpio"; + drive-strength = <16>; + output-low; + bias-pull-down; + }; + spkr_1_sd_n_active: spkr-1-sd-n-active-state { pins = "gpio1"; function = "gpio"; @@ -1157,4 +1268,46 @@ wcd_default: wcd-reset-n-active-state { bias-disable; output-low; }; + + wlan_en: wlan-en-state { + pins = "gpio80"; + function = "gpio"; + drive-strength = <16>; + output-low; + bias-pull-down; + }; + + uart20_default: uart20-default-state { + cts-pins { + pins = "gpio76"; + function = "qup20"; + bias-disable; + }; + + rts-pins { + pins = "gpio77"; + function = "qup20"; + bias-disable; + }; + + rx-pins { + pins = "gpio78"; + function = "qup20"; + bias-disable; + }; + + tx-pins { + pins = "gpio79"; + function = "qup20"; + bias-disable; + }; + }; + + xo_clk_default: xo-clk-state { + pins = "gpio204"; + function = "gpio"; + drive-strength = <16>; + output-low; + bias-pull-down; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8450-qrd.dts b/arch/arm64/boot/dts/qcom/sm8450-qrd.dts index 7b62ead68e7732..8c39fbcaad8028 100644 --- a/arch/arm64/boot/dts/qcom/sm8450-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8450-qrd.dts @@ -349,6 +349,10 @@ vreg_l6e_1p2: ldo6 { }; }; +&dispcc { + status = "disabled"; +}; + &pcie0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi index 17dbb67868aed3..cc1335a07a35c7 100644 --- a/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450-sony-xperia-nagara.dtsi @@ -468,6 +468,10 @@ pmr735a_l7: ldo7 { }; }; +&dispcc { + status = "disabled"; +}; + &gpi_dma0 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index 38cb524cc56893..53147aa6f7e4ac 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -51,23 +51,23 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,kryo780"; reg = <0x0 0x0>; enable-method = "psci"; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; clocks = <&cpufreq_hw 0>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -75,171 +75,171 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,kryo780"; reg = <0x0 0x100>; enable-method = "psci"; - next-level-cache = <&L2_100>; - power-domains = <&CPU_PD1>; + next-level-cache = <&l2_100>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; clocks = <&cpufreq_hw 0>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,kryo780"; reg = <0x0 0x200>; enable-method = "psci"; - next-level-cache = <&L2_200>; - power-domains = <&CPU_PD2>; + next-level-cache = <&l2_200>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; clocks = <&cpufreq_hw 0>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,kryo780"; reg = <0x0 0x300>; enable-method = "psci"; - next-level-cache = <&L2_300>; - power-domains = <&CPU_PD3>; + next-level-cache = <&l2_300>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; #cooling-cells = <2>; clocks = <&cpufreq_hw 0>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "qcom,kryo780"; reg = <0x0 0x400>; enable-method = "psci"; - next-level-cache = <&L2_400>; - power-domains = <&CPU_PD4>; + next-level-cache = <&l2_400>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; clocks = <&cpufreq_hw 1>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "qcom,kryo780"; reg = <0x0 0x500>; enable-method = "psci"; - next-level-cache = <&L2_500>; - power-domains = <&CPU_PD5>; + next-level-cache = <&l2_500>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; clocks = <&cpufreq_hw 1>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "qcom,kryo780"; reg = <0x0 0x600>; enable-method = "psci"; - next-level-cache = <&L2_600>; - power-domains = <&CPU_PD6>; + next-level-cache = <&l2_600>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; #cooling-cells = <2>; clocks = <&cpufreq_hw 1>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "qcom,kryo780"; reg = <0x0 0x700>; enable-method = "psci"; - next-level-cache = <&L2_700>; - power-domains = <&CPU_PD7>; + next-level-cache = <&l2_700>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 2>; #cooling-cells = <2>; clocks = <&cpufreq_hw 2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -247,7 +247,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "silver-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -257,7 +257,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -269,7 +269,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <1050>; @@ -277,7 +277,7 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { min-residency-us = <5309>; }; - CLUSTER_SLEEP_1: cluster-sleep-1 { + cluster_sleep_1: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c344>; entry-latency-us = <2700>; @@ -323,57 +323,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cpu-cluster0 { + cluster_pd: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>, <&CLUSTER_SLEEP_1>; + domain-idle-states = <&cluster_sleep_0>, <&cluster_sleep_1>; }; }; @@ -1787,7 +1787,8 @@ pcie0: pcie@1c00000 { , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", @@ -1795,7 +1796,8 @@ pcie0: pcie@1c00000 { "msi4", "msi5", "msi6", - "msi7"; + "msi7", + "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ @@ -1880,7 +1882,7 @@ opp-8000000 { }; }; - pcie@0 { + pcieport0: pcie@0 { device_type = "pci"; reg = <0x0 0x0 0x0 0x0 0x0>; bus-range = <0x01 0xff>; @@ -1949,7 +1951,8 @@ pcie1: pcie@1c08000 { , , , - ; + , + ; interrupt-names = "msi0", "msi1", "msi2", @@ -1957,7 +1960,8 @@ pcie1: pcie@1c08000 { "msi4", "msi5", "msi6", - "msi7"; + "msi7", + "global"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ @@ -3435,7 +3439,6 @@ dispcc: clock-controller@af00000 { #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; - status = "disabled"; }; pdc: interrupt-controller@b220000 { @@ -4257,6 +4260,7 @@ apps_smmu: iommu@15000000 { , , ; + dma-coherent; }; intc: interrupt-controller@17100000 { @@ -4354,7 +4358,7 @@ apps_rsc: rsc@17a00000 { qcom,drv-id = <2>; qcom,tcs-config = , , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; diff --git a/arch/arm64/boot/dts/qcom/sm8550-samsung-q5q.dts b/arch/arm64/boot/dts/qcom/sm8550-samsung-q5q.dts index 3d351e90bb3986..3c5d8d26704fd9 100644 --- a/arch/arm64/boot/dts/qcom/sm8550-samsung-q5q.dts +++ b/arch/arm64/boot/dts/qcom/sm8550-samsung-q5q.dts @@ -98,7 +98,7 @@ rmtfs_mem: rmtfs-region@d4a80000 { * The bootloader will only keep display hardware enabled * if this memory region is named exactly 'splash_region' */ - splash_region@b8000000 { + splash-region@b8000000 { reg = <0x0 0xb8000000 0x0 0x2b00000>; no-map; }; diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 9dc0ee3eb98f87..e7774d32fb6d22 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -64,25 +64,25 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a510"; reg = <0 0>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; - L3_0: l3-cache { + next-level-cache = <&l3_0>; + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -90,185 +90,185 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a510"; reg = <0 0x100>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_100>; - power-domains = <&CPU_PD1>; + next-level-cache = <&l2_100>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; #cooling-cells = <2>; - L2_100: l2-cache { + l2_100: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "arm,cortex-a510"; reg = <0 0x200>; clocks = <&cpufreq_hw 0>; enable-method = "psci"; - next-level-cache = <&L2_200>; - power-domains = <&CPU_PD2>; + next-level-cache = <&l2_200>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "arm,cortex-a715"; reg = <0 0x300>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_300>; - power-domains = <&CPU_PD3>; + next-level-cache = <&l2_300>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <270>; #cooling-cells = <2>; - L2_300: l2-cache { + l2_300: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "arm,cortex-a715"; reg = <0 0x400>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_400>; - power-domains = <&CPU_PD4>; + next-level-cache = <&l2_400>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <270>; #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "arm,cortex-a710"; reg = <0 0x500>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_500>; - power-domains = <&CPU_PD5>; + next-level-cache = <&l2_500>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <270>; #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "arm,cortex-a710"; reg = <0 0x600>; clocks = <&cpufreq_hw 1>; enable-method = "psci"; - next-level-cache = <&L2_600>; - power-domains = <&CPU_PD6>; + next-level-cache = <&l2_600>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 1>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <270>; #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "arm,cortex-x3"; reg = <0 0x700>; clocks = <&cpufreq_hw 2>; enable-method = "psci"; - next-level-cache = <&L2_700>; - power-domains = <&CPU_PD7>; + next-level-cache = <&l2_700>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; qcom,freq-domain = <&cpufreq_hw 2>; capacity-dmips-mhz = <1894>; dynamic-power-coefficient = <588>; #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -276,7 +276,7 @@ core7 { idle-states { entry-method = "psci"; - LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { + little_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "silver-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -286,7 +286,7 @@ LITTLE_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - BIG_CPU_SLEEP_0: cpu-sleep-1-0 { + big_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -296,7 +296,7 @@ BIG_CPU_SLEEP_0: cpu-sleep-1-0 { local-timer-stop; }; - PRIME_CPU_SLEEP_0: cpu-sleep-2-0 { + prime_cpu_sleep_0: cpu-sleep-2-0 { compatible = "arm,idle-state"; idle-state-name = "goldplus-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -308,7 +308,7 @@ PRIME_CPU_SLEEP_0: cpu-sleep-2-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <750>; @@ -316,7 +316,7 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { min-residency-us = <9144>; }; - CLUSTER_SLEEP_1: cluster-sleep-1 { + cluster_sleep_1: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c344>; entry-latency-us = <2800>; @@ -376,57 +376,57 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&LITTLE_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&little_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&big_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&PRIME_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&prime_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cluster { + cluster_pd: power-domain-cluster { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>, <&CLUSTER_SLEEP_1>; + domain-idle-states = <&cluster_sleep_0>, <&cluster_sleep_1>; }; }; @@ -1989,7 +1989,7 @@ ufs_mem_phy: phy@1d80000 { status = "disabled"; }; - ufs_mem_hc: ufs@1d84000 { + ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,sm8550-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x01d84000 0x0 0x3000>; @@ -2076,7 +2076,8 @@ opp-300000000 { ice: crypto@1d88000 { compatible = "qcom,sm8550-inline-crypto-engine", "qcom,inline-crypto-engine"; - reg = <0 0x01d88000 0 0x8000>; + reg = <0 0x01d88000 0 0x18000>; + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; }; @@ -4365,7 +4366,7 @@ apps_rsc: rsc@17a00000 { qcom,drv-id = <2>; qcom,tcs-config = , , , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; diff --git a/arch/arm64/boot/dts/qcom/sm8650-hdk.dts b/arch/arm64/boot/dts/qcom/sm8650-hdk.dts index 127c7aacd4fc31..f00bdff4280af2 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-hdk.dts @@ -814,10 +814,6 @@ vreg_l7n_3p3: ldo7 { }; }; -&dispcc { - status = "okay"; -}; - &gpi_dma1 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts index c63822f5b12789..0db2cb03f252d1 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts @@ -585,10 +585,6 @@ vreg_l7n_3p3: ldo7 { }; }; -&dispcc { - status = "okay"; -}; - &lpass_tlmm { spkr_1_sd_n_active: spkr-1-sd-n-active-state { pins = "gpio21"; diff --git a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts index 8ca0d28eba9bd0..c5e8c3c2df91a4 100644 --- a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts @@ -741,10 +741,6 @@ vreg_l7n_3p3: ldo7 { }; }; -&dispcc { - status = "okay"; -}; - &gpi_dma1 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index 01ac3769ffa62f..25e47505adcb79 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -68,18 +68,18 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a520"; reg = <0 0>; clocks = <&cpufreq_hw 0>; - power-domains = <&CPU_PD0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; @@ -87,13 +87,13 @@ CPU0: cpu@0 { #cooling-cells = <2>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; - L3_0: l3-cache { + l3_0: l3-cache { compatible = "cache"; cache-level = <3>; cache-unified; @@ -101,18 +101,18 @@ L3_0: l3-cache { }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "arm,cortex-a520"; reg = <0 0x100>; clocks = <&cpufreq_hw 0>; - power-domains = <&CPU_PD1>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; enable-method = "psci"; - next-level-cache = <&L2_0>; + next-level-cache = <&l2_0>; capacity-dmips-mhz = <1024>; dynamic-power-coefficient = <100>; @@ -121,18 +121,18 @@ CPU1: cpu@100 { #cooling-cells = <2>; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "arm,cortex-a720"; reg = <0 0x200>; clocks = <&cpufreq_hw 3>; - power-domains = <&CPU_PD2>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; enable-method = "psci"; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <238>; @@ -140,26 +140,26 @@ CPU2: cpu@200 { #cooling-cells = <2>; - L2_200: l2-cache { + l2_200: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "arm,cortex-a720"; reg = <0 0x300>; clocks = <&cpufreq_hw 3>; - power-domains = <&CPU_PD3>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; enable-method = "psci"; - next-level-cache = <&L2_200>; + next-level-cache = <&l2_200>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <238>; @@ -168,18 +168,18 @@ CPU3: cpu@300 { #cooling-cells = <2>; }; - CPU4: cpu@400 { + cpu4: cpu@400 { device_type = "cpu"; compatible = "arm,cortex-a720"; reg = <0 0x400>; clocks = <&cpufreq_hw 3>; - power-domains = <&CPU_PD4>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; enable-method = "psci"; - next-level-cache = <&L2_400>; + next-level-cache = <&l2_400>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <238>; @@ -187,26 +187,26 @@ CPU4: cpu@400 { #cooling-cells = <2>; - L2_400: l2-cache { + l2_400: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU5: cpu@500 { + cpu5: cpu@500 { device_type = "cpu"; compatible = "arm,cortex-a720"; reg = <0 0x500>; clocks = <&cpufreq_hw 1>; - power-domains = <&CPU_PD5>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; enable-method = "psci"; - next-level-cache = <&L2_500>; + next-level-cache = <&l2_500>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <238>; @@ -214,26 +214,26 @@ CPU5: cpu@500 { #cooling-cells = <2>; - L2_500: l2-cache { + l2_500: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU6: cpu@600 { + cpu6: cpu@600 { device_type = "cpu"; compatible = "arm,cortex-a720"; reg = <0 0x600>; clocks = <&cpufreq_hw 1>; - power-domains = <&CPU_PD6>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; enable-method = "psci"; - next-level-cache = <&L2_600>; + next-level-cache = <&l2_600>; capacity-dmips-mhz = <1792>; dynamic-power-coefficient = <238>; @@ -241,26 +241,26 @@ CPU6: cpu@600 { #cooling-cells = <2>; - L2_600: l2-cache { + l2_600: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; - CPU7: cpu@700 { + cpu7: cpu@700 { device_type = "cpu"; compatible = "arm,cortex-x4"; reg = <0 0x700>; clocks = <&cpufreq_hw 2>; - power-domains = <&CPU_PD7>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; enable-method = "psci"; - next-level-cache = <&L2_700>; + next-level-cache = <&l2_700>; capacity-dmips-mhz = <1894>; dynamic-power-coefficient = <588>; @@ -268,46 +268,46 @@ CPU7: cpu@700 { #cooling-cells = <2>; - L2_700: l2-cache { + l2_700: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; - next-level-cache = <&L3_0>; + next-level-cache = <&l3_0>; }; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; core4 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core5 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core6 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core7 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; }; @@ -315,7 +315,7 @@ core7 { idle-states { entry-method = "psci"; - SILVER_CPU_SLEEP_0: cpu-sleep-0-0 { + silver_cpu_sleep_0: cpu-sleep-0-0 { compatible = "arm,idle-state"; idle-state-name = "silver-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -325,7 +325,7 @@ SILVER_CPU_SLEEP_0: cpu-sleep-0-0 { local-timer-stop; }; - GOLD_CPU_SLEEP_0: cpu-sleep-1-0 { + gold_cpu_sleep_0: cpu-sleep-1-0 { compatible = "arm,idle-state"; idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -335,7 +335,7 @@ GOLD_CPU_SLEEP_0: cpu-sleep-1-0 { local-timer-stop; }; - GOLD_PLUS_CPU_SLEEP_0: cpu-sleep-2-0 { + gold_plus_cpu_sleep_0: cpu-sleep-2-0 { compatible = "arm,idle-state"; idle-state-name = "gold-plus-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; @@ -347,7 +347,7 @@ GOLD_PLUS_CPU_SLEEP_0: cpu-sleep-2-0 { }; domain-idle-states { - CLUSTER_SLEEP_0: cluster-sleep-0 { + cluster_sleep_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; entry-latency-us = <750>; @@ -355,7 +355,7 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { min-residency-us = <9144>; }; - CLUSTER_SLEEP_1: cluster-sleep-1 { + cluster_sleep_1: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c344>; entry-latency-us = <2800>; @@ -411,58 +411,58 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&SILVER_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&silver_cpu_sleep_0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&SILVER_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&silver_cpu_sleep_0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&SILVER_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&silver_cpu_sleep_0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&gold_cpu_sleep_0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&gold_cpu_sleep_0>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&gold_cpu_sleep_0>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&GOLD_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&gold_cpu_sleep_0>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD>; - domain-idle-states = <&GOLD_PLUS_CPU_SLEEP_0>; + power-domains = <&cluster_pd>; + domain-idle-states = <&gold_plus_cpu_sleep_0>; }; - CLUSTER_PD: power-domain-cluster { + cluster_pd: power-domain-cluster { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_SLEEP_0>, - <&CLUSTER_SLEEP_1>; + domain-idle-states = <&cluster_sleep_0>, + <&cluster_sleep_1>; }; }; @@ -2535,7 +2535,7 @@ ufs_mem_phy: phy@1d80000 { status = "disabled"; }; - ufs_mem_hc: ufs@1d84000 { + ufs_mem_hc: ufshc@1d84000 { compatible = "qcom,sm8650-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0 0x01d84000 0 0x3000>; @@ -2595,7 +2595,7 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, ice: crypto@1d88000 { compatible = "qcom,sm8650-inline-crypto-engine", "qcom,inline-crypto-engine"; - reg = <0 0x01d88000 0 0x8000>; + reg = <0 0x01d88000 0 0x18000>; clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; }; @@ -3841,8 +3841,6 @@ dispcc: clock-controller@af00000 { #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; - - status = "disabled"; }; usb_1_hsphy: phy@88e3000 { @@ -5083,7 +5081,7 @@ apps_rsc: rsc@17a00000 { , ; - power-domains = <&CLUSTER_PD>; + power-domains = <&cluster_pd>; qcom,tcs-offset = <0xd00>; qcom,drv-id = <2>; diff --git a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts index fdde988ae01ebd..975550139e1024 100644 --- a/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts +++ b/arch/arm64/boot/dts/qcom/x1e78100-lenovo-thinkpad-t14s.dts @@ -453,6 +453,9 @@ zap-shader { &i2c0 { clock-frequency = <400000>; + pinctrl-0 = <&qup_i2c0_data_clk>, <&tpad_default>; + pinctrl-names = "default"; + status = "okay"; /* ELAN06E2 or ELAN06E3 */ @@ -463,13 +466,19 @@ touchpad@15 { hid-descr-addr = <0x1>; interrupts-extended = <&tlmm 3 IRQ_TYPE_LEVEL_LOW>; - pinctrl-0 = <&tpad_default>; - pinctrl-names = "default"; - wakeup-source; }; - /* TODO: second-sourced SYNA8022 or SYNA8024 touchpad @ 0x2c */ + /* SYNA8022 or SYNA8024 */ + touchpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + + hid-descr-addr = <0x20>; + interrupts-extended = <&tlmm 3 IRQ_TYPE_LEVEL_LOW>; + + wakeup-source; + }; /* ELAN06F1 or SYNA06F2 */ keyboard@3a { @@ -764,10 +773,6 @@ &usb_1_ss0 { status = "okay"; }; -&usb_1_ss0_dwc3 { - dr_mode = "host"; -}; - &usb_1_ss0_dwc3_hs { remote-endpoint = <&pmic_glink_ss0_hs_in>; }; @@ -796,10 +801,6 @@ &usb_1_ss1 { status = "okay"; }; -&usb_1_ss1_dwc3 { - dr_mode = "host"; -}; - &usb_1_ss1_dwc3_hs { remote-endpoint = <&pmic_glink_ss1_hs_in>; }; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts index fb4a48a1e2a8a5..8515c254e15868 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-asus-vivobook-s15.dts @@ -94,17 +94,6 @@ linux,cma { }; }; - vph_pwr: vph-pwr-regulator { - compatible = "regulator-fixed"; - - regulator-name = "vph_pwr"; - regulator-min-microvolt = <3700000>; - regulator-max-microvolt = <3700000>; - - regulator-always-on; - regulator-boot-on; - }; - vreg_edp_3p3: regulator-edp-3p3 { compatible = "regulator-fixed"; @@ -137,6 +126,17 @@ vreg_nvme: regulator-nvme { regulator-boot-on; }; + + vph_pwr: regulator-vph-pwr { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; }; &apps_rsc { @@ -594,8 +594,6 @@ &usb_1_ss0_qmpphy { vdda-phy-supply = <&vreg_l3e_1p2>; vdda-pll-supply = <&vreg_l1j_0p8>; - orientation-switch; - status = "okay"; }; @@ -628,8 +626,6 @@ &usb_1_ss1_qmpphy { vdda-phy-supply = <&vreg_l3e_1p2>; vdda-pll-supply = <&vreg_l2d_0p9>; - orientation-switch; - status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts index c6e0356ed9a2a2..39f9d9cdc10d8e 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "x1e80100.dtsi" @@ -261,31 +262,37 @@ platform { }; }; - vph_pwr: vph-pwr-regulator { + vreg_edp_3p3: regulator-edp-3p3 { compatible = "regulator-fixed"; - regulator-name = "vph_pwr"; - regulator-min-microvolt = <3700000>; - regulator-max-microvolt = <3700000>; + regulator-name = "VREG_EDP_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&tlmm 70 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&edp_reg_en>; + pinctrl-names = "default"; - regulator-always-on; regulator-boot-on; }; - vreg_edp_3p3: regulator-edp-3p3 { + vreg_misc_3p3: regulator-misc-3p3 { compatible = "regulator-fixed"; - regulator-name = "VREG_EDP_3P3"; + regulator-name = "VREG_MISC_3P3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; - gpio = <&tlmm 70 GPIO_ACTIVE_HIGH>; + gpio = <&pm8550ve_8_gpios 6 GPIO_ACTIVE_HIGH>; enable-active-high; - pinctrl-0 = <&edp_reg_en>; pinctrl-names = "default"; + pinctrl-0 = <&misc_3p3_reg_en>; regulator-boot-on; + regulator-always-on; }; vreg_nvme: regulator-nvme { @@ -304,6 +311,17 @@ vreg_nvme: regulator-nvme { regulator-boot-on; }; + vph_pwr: regulator-vph-pwr { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; + vreg_wwan: regulator-wwan { compatible = "regulator-fixed"; @@ -691,6 +709,9 @@ touchpad@15 { hid-descr-addr = <0x1>; interrupts-extended = <&tlmm 3 IRQ_TYPE_LEVEL_LOW>; + vdd-supply = <&vreg_misc_3p3>; + vddl-supply = <&vreg_l12b_1p2>; + pinctrl-0 = <&tpad_default>; pinctrl-names = "default"; @@ -704,6 +725,9 @@ keyboard@3a { hid-descr-addr = <0x1>; interrupts-extended = <&tlmm 67 IRQ_TYPE_LEVEL_LOW>; + vdd-supply = <&vreg_misc_3p3>; + vddl-supply = <&vreg_l12b_1p2>; + pinctrl-0 = <&kybd_default>; pinctrl-names = "default"; @@ -723,6 +747,9 @@ touchscreen@10 { hid-descr-addr = <0x1>; interrupts-extended = <&tlmm 51 IRQ_TYPE_LEVEL_LOW>; + vdd-supply = <&vreg_misc_3p3>; + vddl-supply = <&vreg_l15b_1p8>; + pinctrl-0 = <&ts0_default>; pinctrl-names = "default"; }; @@ -856,6 +883,19 @@ &pcie6a_phy { status = "okay"; }; +&pm8550ve_8_gpios { + misc_3p3_reg_en: misc-3p3-reg-en-state { + pins = "gpio6"; + function = "normal"; + bias-disable; + input-disable; + output-enable; + drive-push-pull; + power-source = <1>; /* 1.8 V */ + qcom,drive-strength = ; + }; +}; + &pmc8380_3_gpios { edp_bl_en: edp-bl-en-state { pins = "gpio4"; @@ -1157,10 +1197,6 @@ &usb_1_ss0 { status = "okay"; }; -&usb_1_ss0_dwc3 { - dr_mode = "host"; -}; - &usb_1_ss0_dwc3_hs { remote-endpoint = <&pmic_glink_ss0_hs_in>; }; @@ -1189,10 +1225,6 @@ &usb_1_ss1 { status = "okay"; }; -&usb_1_ss1_dwc3 { - dr_mode = "host"; -}; - &usb_1_ss1_dwc3_hs { remote-endpoint = <&pmic_glink_ss1_hs_in>; }; @@ -1221,10 +1253,6 @@ &usb_1_ss2 { status = "okay"; }; -&usb_1_ss2_dwc3 { - dr_mode = "host"; -}; - &usb_1_ss2_dwc3_hs { remote-endpoint = <&pmic_glink_ss2_hs_in>; }; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts b/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts new file mode 100644 index 00000000000000..05624226faf9ee --- /dev/null +++ b/arch/arm64/boot/dts/qcom/x1e80100-dell-xps13-9345.dts @@ -0,0 +1,875 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2024 Aleksandrs Vinarskis + */ + +/dts-v1/; + +#include +#include +#include +#include +#include + +#include "x1e80100.dtsi" +#include "x1e80100-pmics.dtsi" + +/ { + model = "Dell XPS 13 9345"; + compatible = "dell,xps13-9345", "qcom,x1e80100"; + chassis-type = "laptop"; + + aliases { + serial0 = &uart21; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&hall_int_n_default>; + pinctrl-names = "default"; + + switch-lid { + gpios = <&tlmm 92 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + wakeup-source; + wakeup-event-action = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-names = "default"; + pinctrl-0 = <&cam_indicator_en>; + + led-camera-indicator { + label = "white:camera-indicator"; + function = LED_FUNCTION_INDICATOR; + color = ; + gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "none"; + default-state = "off"; + /* Reuse as a panic indicator until we get a "camera on" trigger */ + panic-indicator; + }; + }; + + pmic-glink { + compatible = "qcom,x1e80100-pmic-glink", + "qcom,sm8550-pmic-glink", + "qcom,pmic-glink"; + orientation-gpios = <&tlmm 121 GPIO_ACTIVE_HIGH>, + <&tlmm 123 GPIO_ACTIVE_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + + /* Right-side USB Type-C port */ + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_ss0_hs_in: endpoint { + remote-endpoint = <&usb_1_ss0_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_ss0_ss_in: endpoint { + remote-endpoint = <&usb_1_ss0_qmpphy_out>; + }; + }; + }; + }; + + /* Left-side USB Type-C port */ + connector@1 { + compatible = "usb-c-connector"; + reg = <1>; + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_ss1_hs_in: endpoint { + remote-endpoint = <&usb_1_ss1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_ss1_ss_in: endpoint { + remote-endpoint = <&usb_1_ss1_qmpphy_out>; + }; + }; + }; + }; + }; + + reserved-memory { + linux,cma { + compatible = "shared-dma-pool"; + size = <0x0 0x8000000>; + reusable; + linux,cma-default; + }; + }; + + vreg_edp_3p3: regulator-edp-3p3 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_EDP_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&tlmm 70 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&edp_reg_en>; + pinctrl-names = "default"; + + regulator-boot-on; + }; + + vreg_nvme: regulator-nvme { + compatible = "regulator-fixed"; + + regulator-name = "VREG_NVME_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&tlmm 18 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&nvme_reg_en>; + pinctrl-names = "default"; + + regulator-boot-on; + }; + + vreg_vph_pwr: regulator-vph-pwr { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + qcom,pmic-id = "b"; + vdd-bob1-supply = <&vreg_vph_pwr>; + vdd-bob2-supply = <&vreg_vph_pwr>; + vdd-l1-l4-l10-supply = <&vreg_s4c_1p8>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob2>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l12-supply = <&vreg_s5j_1p2>; + vdd-l15-supply = <&vreg_s4c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l4b_1p8: ldo4 { + regulator-name = "vreg_l4b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l8b_3p0: ldo8 { + regulator-name = "vreg_l8b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l9b_2p9: ldo9 { + regulator-name = "vreg_l9b_2p9"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l12b_1p2: ldo12 { + regulator-name = "vreg_l12b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l14b_3p0: ldo14 { + regulator-name = "vreg_l14b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "c"; + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s1f_0p7>; + + vreg_s4c_1p8: smps4 { + regulator-name = "vreg_s4c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l2c_0p8: ldo2 { + regulator-name = "vreg_l2c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l3c_0p9: ldo3 { + regulator-name = "vreg_l3c_0p9"; + regulator-min-microvolt = <920000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "d"; + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s4c_1p8>; + vdd-s1-supply = <&vreg_vph_pwr>; + + vreg_l1d_0p8: ldo1 { + regulator-name = "vreg_l1d_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l2d_0p9: ldo2 { + regulator-name = "vreg_l2d_0p9"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + }; + + vreg_l3d_1p8: ldo3 { + regulator-name = "vreg_l3d_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; + + regulators-3 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "e"; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s5j_1p2>; + + vreg_l2e_0p8: ldo2 { + regulator-name = "vreg_l2e_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l3e_1p2: ldo3 { + regulator-name = "vreg_l3e_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-4 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "f"; + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s5j_1p2>; + vdd-s1-supply = <&vreg_vph_pwr>; + + vreg_s1f_0p7: smps1 { + regulator-name = "vreg_s1f_0p7"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + }; + + regulators-6 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "i"; + vdd-l1-supply = <&vreg_s4c_1p8>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s1-supply = <&vreg_vph_pwr>; + vdd-s2-supply = <&vreg_vph_pwr>; + + vreg_s1i_0p9: smps1 { + regulator-name = "vreg_s1i_0p9"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_s2i_1p0: smps2 { + regulator-name = "vreg_s2i_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1i_1p8: ldo1 { + regulator-name = "vreg_l1i_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2i_1p2: ldo2 { + regulator-name = "vreg_l2i_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3i_0p8: ldo3 { + regulator-name = "vreg_l3i_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + }; + + regulators-7 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "j"; + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s5-supply = <&vreg_vph_pwr>; + + vreg_s5j_1p2: smps5 { + regulator-name = "vreg_s5j_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l1j_0p9: ldo1 { + regulator-name = "vreg_l1j_0p9"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + }; + + vreg_l2j_1p2: ldo2 { + regulator-name = "vreg_l2j_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1256000>; + regulator-initial-mode = ; + }; + + vreg_l3j_0p8: ldo3 { + regulator-name = "vreg_l3j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + }; +}; + +&gpu { + status = "okay"; + + zap-shader { + firmware-name = "qcom/x1e80100/dell/xps13-9345/qcdxkmsuc8380.mbn"; + }; +}; + +&i2c0 { + clock-frequency = <400000>; + status = "okay"; + + keyboard@5 { + compatible = "hid-over-i2c"; + reg = <0x5>; + + hid-descr-addr = <0x20>; + interrupts-extended = <&tlmm 67 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-0 = <&kybd_default>; + pinctrl-names = "default"; + + wakeup-source; + }; +}; + +&i2c3 { + clock-frequency = <400000>; + status = "disabled"; + /* PS8830 Retimer @0x8 */ + /* Unknown device @0x9 */ +}; + +&i2c5 { + clock-frequency = <100000>; + status = "disabled"; + /* EC @0x3b */ +}; + +&i2c7 { + clock-frequency = <400000>; + status = "disabled"; + /* PS8830 Retimer @0x8 */ + /* Unknown device @0x9 */ +}; + +&i2c8 { + clock-frequency = <400000>; + + status = "okay"; + + touchscreen@10 { + compatible = "hid-over-i2c"; + reg = <0x10>; + + hid-descr-addr = <0x1>; + interrupts-extended = <&tlmm 51 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-0 = <&ts0_default>; + pinctrl-names = "default"; + }; +}; + +&i2c9 { + clock-frequency = <400000>; + status = "disabled"; + /* USB3 retimer device @0x4f */ +}; + +&i2c17 { + clock-frequency = <400000>; + status = "okay"; + + touchpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + + hid-descr-addr = <0x20>; + interrupts-extended = <&tlmm 3 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-0 = <&tpad_default>; + pinctrl-names = "default"; + + wakeup-source; + }; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dp3 { + /delete-property/ #sound-dai-cells; + + status = "okay"; + + aux-bus { + panel { + compatible = "edp-panel"; + enable-gpios = <&tlmm 74 GPIO_ACTIVE_HIGH>; + power-supply = <&vreg_edp_3p3>; + + pinctrl-0 = <&edp_bl_en>; + pinctrl-names = "default"; + + port { + edp_panel_in: endpoint { + remote-endpoint = <&mdss_dp3_out>; + }; + }; + }; + }; + + ports { + port@1 { + reg = <1>; + + mdss_dp3_out: endpoint { + data-lanes = <0 1 2 3>; + link-frequencies = /bits/ 64 <1620000000 2700000000 5400000000 8100000000>; + + remote-endpoint = <&edp_panel_in>; + }; + }; + }; +}; + +&mdss_dp3_phy { + vdda-phy-supply = <&vreg_l3j_0p8>; + vdda-pll-supply = <&vreg_l2j_1p2>; + + status = "okay"; +}; + +&pcie4 { + perst-gpios = <&tlmm 146 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 148 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie4_default>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie4_phy { + vdda-phy-supply = <&vreg_l3i_0p8>; + vdda-pll-supply = <&vreg_l3e_1p2>; + + status = "okay"; +}; + +&pcie6a { + perst-gpios = <&tlmm 152 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 154 GPIO_ACTIVE_LOW>; + + vddpe-3v3-supply = <&vreg_nvme>; + + pinctrl-0 = <&pcie6a_default>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie6a_phy { + vdda-phy-supply = <&vreg_l1d_0p8>; + vdda-pll-supply = <&vreg_l2j_1p2>; + + status = "okay"; +}; + +&qupv3_0 { + status = "okay"; +}; + +&qupv3_1 { + status = "okay"; +}; + +&qupv3_2 { + status = "okay"; +}; + +&remoteproc_adsp { + firmware-name = "qcom/x1e80100/dell/xps13-9345/qcadsp8380.mbn", + "qcom/x1e80100/dell/xps13-9345/adsp_dtbs.elf"; + + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/x1e80100/dell/xps13-9345/qccdsp8380.mbn", + "qcom/x1e80100/dell/xps13-9345/cdsp_dtbs.elf"; + + status = "okay"; +}; + +&smb2360_0_eusb2_repeater { + vdd18-supply = <&vreg_l3d_1p8>; + vdd3-supply = <&vreg_l2b_3p0>; +}; + +&smb2360_1_eusb2_repeater { + vdd18-supply = <&vreg_l3d_1p8>; + vdd3-supply = <&vreg_l14b_3p0>; +}; + +&tlmm { + gpio-reserved-ranges = <44 4>, /* SPI11 (TPM) */ + <76 4>, /* SPI19 (TZ Protected) */ + <238 1>; /* UFS Reset */ + + cam_indicator_en: cam-indicator-en-state { + pins = "gpio110"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + edp_bl_en: edp-bl-en-state { + pins = "gpio74"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + edp_reg_en: edp-reg-en-state { + pins = "gpio70"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + hall_int_n_default: hall-int-n-state { + pins = "gpio92"; + function = "gpio"; + + bias-disable; + }; + + kybd_default: kybd-default-state { + pins = "gpio67"; + function = "gpio"; + bias-pull-up; + }; + + nvme_reg_en: nvme-reg-en-state { + pins = "gpio18"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + pcie4_default: pcie4-default-state { + clkreq-n-pins { + pins = "gpio147"; + function = "pcie4_clk"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio146"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-n-pins { + pins = "gpio148"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie6a_default: pcie6a-default-state { + clkreq-n-pins { + pins = "gpio153"; + function = "pcie6a_clk"; + drive-strength = <2>; + bias-pull-up; + }; + + perst-n-pins { + pins = "gpio152"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + wake-n-pins { + pins = "gpio154"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + tpad_default: tpad-default-state { + disable-pins { + pins = "gpio38"; + function = "gpio"; + output-high; + }; + + int-n-pins { + pins = "gpio3"; + function = "gpio"; + bias-pull-up; + }; + + reset-n-pins { + pins = "gpio52"; + function = "gpio"; + bias-disable; + }; + }; + + ts0_default: ts0-default-state { + disable-pins { + pins = "gpio75"; + function = "gpio"; + output-high; + }; + + int-n-pins { + pins = "gpio51"; + function = "gpio"; + bias-pull-up; + }; + + reset-n-pins { + /* Technically should be High-Z input */ + pins = "gpio48"; + function = "gpio"; + output-low; + drive-strength = <2>; + }; + }; +}; + +&uart21 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; + +&usb_1_ss0_hsphy { + vdd-supply = <&vreg_l3j_0p8>; + vdda12-supply = <&vreg_l2j_1p2>; + + phys = <&smb2360_0_eusb2_repeater>; + + status = "okay"; +}; + +&usb_1_ss0_qmpphy { + vdda-phy-supply = <&vreg_l3e_1p2>; + vdda-pll-supply = <&vreg_l1j_0p9>; + + status = "okay"; +}; + +&usb_1_ss0 { + status = "okay"; +}; + +&usb_1_ss0_dwc3 { + dr_mode = "host"; +}; + +&usb_1_ss0_dwc3_hs { + remote-endpoint = <&pmic_glink_ss0_hs_in>; +}; + +&usb_1_ss0_qmpphy_out { + remote-endpoint = <&pmic_glink_ss0_ss_in>; +}; + +&usb_1_ss1_hsphy { + vdd-supply = <&vreg_l3j_0p8>; + vdda12-supply = <&vreg_l2j_1p2>; + + phys = <&smb2360_1_eusb2_repeater>; + + status = "okay"; +}; + +&usb_1_ss1_qmpphy { + vdda-phy-supply = <&vreg_l3e_1p2>; + vdda-pll-supply = <&vreg_l2d_0p9>; + + status = "okay"; +}; + +&usb_1_ss1 { + status = "okay"; +}; + +&usb_1_ss1_dwc3 { + dr_mode = "host"; +}; + +&usb_1_ss1_dwc3_hs { + remote-endpoint = <&pmic_glink_ss1_hs_in>; +}; + +&usb_1_ss1_qmpphy_out { + remote-endpoint = <&pmic_glink_ss1_ss_in>; +}; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts index 0cdaff9c8cf0fc..ca5a808f2c7df6 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts +++ b/arch/arm64/boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts @@ -15,6 +15,14 @@ / { model = "Lenovo Yoga Slim 7x"; compatible = "lenovo,yoga-slim7x", "qcom,x1e80100"; + aliases { + serial0 = &uart21; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + pmic-glink { compatible = "qcom,x1e80100-pmic-glink", "qcom,sm8550-pmic-glink", @@ -166,17 +174,6 @@ platform { }; }; - vph_pwr: vph-pwr-regulator { - compatible = "regulator-fixed"; - - regulator-name = "vph_pwr"; - regulator-min-microvolt = <3700000>; - regulator-max-microvolt = <3700000>; - - regulator-always-on; - regulator-boot-on; - }; - vreg_edp_3p3: regulator-edp-3p3 { compatible = "regulator-fixed"; @@ -208,6 +205,17 @@ vreg_nvme: regulator-nvme { regulator-boot-on; }; + + vph_pwr: regulator-vph-pwr { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; }; &apps_rsc { @@ -885,6 +893,11 @@ reset-n-pins { }; +&uart21 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; + &usb_1_ss0_hsphy { vdd-supply = <&vreg_l3j_0p8>; vdda12-supply = <&vreg_l2j_1p2>; @@ -898,8 +911,6 @@ &usb_1_ss0_qmpphy { vdda-phy-supply = <&vreg_l3e_1p2>; vdda-pll-supply = <&vreg_l1j_0p8>; - orientation-switch; - status = "okay"; }; @@ -932,8 +943,6 @@ &usb_1_ss1_qmpphy { vdda-phy-supply = <&vreg_l3e_1p2>; vdda-pll-supply = <&vreg_l2d_0p9>; - orientation-switch; - status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi index cdb401767c4206..6835fdeef3aec1 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100-microsoft-romulus.dtsi @@ -4,6 +4,8 @@ */ #include +#include +#include #include #include @@ -30,6 +32,21 @@ backlight: backlight { pinctrl-names = "default"; }; + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&hall_int_n_default>; + pinctrl-names = "default"; + + switch-lid { + gpios = <&tlmm 2 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + wakeup-source; + wakeup-event-action = ; + }; + }; + leds { compatible = "gpio-leds"; @@ -125,17 +142,6 @@ linux,cma { }; }; - vph_pwr: vph-pwr-regulator { - compatible = "regulator-fixed"; - - regulator-name = "vph_pwr"; - regulator-min-microvolt = <3700000>; - regulator-max-microvolt = <3700000>; - - regulator-always-on; - regulator-boot-on; - }; - vreg_edp_3p3: regulator-edp-3p3 { compatible = "regulator-fixed"; @@ -167,6 +173,17 @@ vreg_nvme: regulator-nvme { regulator-boot-on; }; + + vph_pwr: regulator-vph-pwr { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; }; &apps_rsc { @@ -557,7 +574,17 @@ &i2c5 { status = "okay"; - /* Something @4f */ + ptn3222: redriver@4f { + compatible = "nxp,ptn3222"; + reg = <0x4f>; + + reset-gpios = <&tlmm 7 GPIO_ACTIVE_LOW>; + + vdd3v3-supply = <&vreg_l13b>; + vdd1v8-supply = <&vreg_l4b>; + + #phy-cells = <0>; + }; }; &i2c7 { @@ -568,7 +595,6 @@ &i2c7 { /* PS8830 USB retimer @8 */ }; - &mdss { status = "okay"; }; @@ -702,10 +728,25 @@ &smb2360_1_eusb2_repeater { vdd3-supply = <&vreg_l14b>; }; +&smb2360_2 { + status = "okay"; +}; + +&smb2360_2_eusb2_repeater { + vdd18-supply = <&vreg_l3d>; + vdd3-supply = <&vreg_l8b>; +}; + &tlmm { gpio-reserved-ranges = <44 4>, /* SPI (TPM) */ <238 1>; /* UFS Reset */ + hall_int_n_default: hall-int-n-state { + pins = "gpio2"; + function = "gpio"; + bias-disable; + }; + nvme_reg_en: nvme-reg-en-state { pins = "gpio18"; function = "gpio"; @@ -835,3 +876,40 @@ &usb_1_ss1_dwc3_hs { &usb_1_ss1_qmpphy_out { remote-endpoint = <&pmic_glink_ss1_ss_in>; }; + +/* MP0 goes to the Surface Connector, MP1 goes to the USB-A port */ +&usb_mp { + status = "okay"; +}; + +&usb_mp_hsphy0 { + vdd-supply = <&vreg_l2e>; + vdda12-supply = <&vreg_l2j>; + + phys = <&smb2360_2_eusb2_repeater>; + + status = "okay"; +}; + +&usb_mp_hsphy1 { + vdd-supply = <&vreg_l2e>; + vdda12-supply = <&vreg_l2j>; + + phys = <&ptn3222>; + + status = "okay"; +}; + +&usb_mp_qmpphy0 { + vdda-phy-supply = <&vreg_l3e>; + vdda-pll-supply = <&vreg_l3c>; + + status = "okay"; +}; + +&usb_mp_qmpphy1 { + vdda-phy-supply = <&vreg_l3e>; + vdda-pll-supply = <&vreg_l3c>; + + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi index 0510abc0edf0ff..88805629ed2bf0 100644 --- a/arch/arm64/boot/dts/qcom/x1e80100.dtsi +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -65,208 +65,208 @@ cpus { #address-cells = <2>; #size-cells = <0>; - CPU0: cpu@0 { + cpu0: cpu@0 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x0>; enable-method = "psci"; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD0>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd0>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; - L2_0: l2-cache { + l2_0: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU1: cpu@100 { + cpu1: cpu@100 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x100>; enable-method = "psci"; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD1>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd1>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; - CPU2: cpu@200 { + cpu2: cpu@200 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x200>; enable-method = "psci"; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD2>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd2>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; - CPU3: cpu@300 { + cpu3: cpu@300 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x300>; enable-method = "psci"; - next-level-cache = <&L2_0>; - power-domains = <&CPU_PD3>; + next-level-cache = <&l2_0>; + power-domains = <&cpu_pd3>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; - CPU4: cpu@10000 { + cpu4: cpu@10000 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x10000>; enable-method = "psci"; - next-level-cache = <&L2_1>; - power-domains = <&CPU_PD4>; + next-level-cache = <&l2_1>; + power-domains = <&cpu_pd4>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; - L2_1: l2-cache { + l2_1: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU5: cpu@10100 { + cpu5: cpu@10100 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x10100>; enable-method = "psci"; - next-level-cache = <&L2_1>; - power-domains = <&CPU_PD5>; + next-level-cache = <&l2_1>; + power-domains = <&cpu_pd5>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; - CPU6: cpu@10200 { + cpu6: cpu@10200 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x10200>; enable-method = "psci"; - next-level-cache = <&L2_1>; - power-domains = <&CPU_PD6>; + next-level-cache = <&l2_1>; + power-domains = <&cpu_pd6>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; - CPU7: cpu@10300 { + cpu7: cpu@10300 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x10300>; enable-method = "psci"; - next-level-cache = <&L2_1>; - power-domains = <&CPU_PD7>; + next-level-cache = <&l2_1>; + power-domains = <&cpu_pd7>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; - CPU8: cpu@20000 { + cpu8: cpu@20000 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x20000>; enable-method = "psci"; - next-level-cache = <&L2_2>; - power-domains = <&CPU_PD8>; + next-level-cache = <&l2_2>; + power-domains = <&cpu_pd8>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; - L2_2: l2-cache { + l2_2: l2-cache { compatible = "cache"; cache-level = <2>; cache-unified; }; }; - CPU9: cpu@20100 { + cpu9: cpu@20100 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x20100>; enable-method = "psci"; - next-level-cache = <&L2_2>; - power-domains = <&CPU_PD9>; + next-level-cache = <&l2_2>; + power-domains = <&cpu_pd9>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; - CPU10: cpu@20200 { + cpu10: cpu@20200 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x20200>; enable-method = "psci"; - next-level-cache = <&L2_2>; - power-domains = <&CPU_PD10>; + next-level-cache = <&l2_2>; + power-domains = <&cpu_pd10>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; - CPU11: cpu@20300 { + cpu11: cpu@20300 { device_type = "cpu"; compatible = "qcom,oryon"; reg = <0x0 0x20300>; enable-method = "psci"; - next-level-cache = <&L2_2>; - power-domains = <&CPU_PD11>; + next-level-cache = <&l2_2>; + power-domains = <&cpu_pd11>; power-domain-names = "psci"; - cpu-idle-states = <&CLUSTER_C4>; + cpu-idle-states = <&cluster_c4>; }; cpu-map { cluster0 { core0 { - cpu = <&CPU0>; + cpu = <&cpu0>; }; core1 { - cpu = <&CPU1>; + cpu = <&cpu1>; }; core2 { - cpu = <&CPU2>; + cpu = <&cpu2>; }; core3 { - cpu = <&CPU3>; + cpu = <&cpu3>; }; }; cluster1 { core0 { - cpu = <&CPU4>; + cpu = <&cpu4>; }; core1 { - cpu = <&CPU5>; + cpu = <&cpu5>; }; core2 { - cpu = <&CPU6>; + cpu = <&cpu6>; }; core3 { - cpu = <&CPU7>; + cpu = <&cpu7>; }; }; cluster2 { core0 { - cpu = <&CPU8>; + cpu = <&cpu8>; }; core1 { - cpu = <&CPU9>; + cpu = <&cpu9>; }; core2 { - cpu = <&CPU10>; + cpu = <&cpu10>; }; core3 { - cpu = <&CPU11>; + cpu = <&cpu11>; }; }; }; @@ -274,32 +274,30 @@ core3 { idle-states { entry-method = "psci"; - CLUSTER_C4: cpu-sleep-0 { + cluster_c4: cpu-sleep-0 { compatible = "arm,idle-state"; idle-state-name = "ret"; arm,psci-suspend-param = <0x00000004>; entry-latency-us = <180>; - exit-latency-us = <320>; - min-residency-us = <1000>; + exit-latency-us = <500>; + min-residency-us = <600>; }; }; domain-idle-states { - CLUSTER_CL4: cluster-sleep-0 { + cluster_cl4: cluster-sleep-0 { compatible = "domain-idle-state"; - idle-state-name = "l2-ret"; arm,psci-suspend-param = <0x01000044>; entry-latency-us = <350>; exit-latency-us = <500>; min-residency-us = <2500>; }; - CLUSTER_CL5: cluster-sleep-1 { + cluster_cl5: cluster-sleep-1 { compatible = "domain-idle-state"; - idle-state-name = "ret-pll-off"; arm,psci-suspend-param = <0x01000054>; entry-latency-us = <2200>; - exit-latency-us = <2500>; + exit-latency-us = <4000>; min-residency-us = <7000>; }; }; @@ -310,6 +308,7 @@ scm: scm { compatible = "qcom,scm-x1e80100", "qcom,scm"; interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + qcom,dload-mode = <&tcsr 0x19000>; }; }; @@ -340,85 +339,85 @@ psci { compatible = "arm,psci-1.0"; method = "smc"; - CPU_PD0: power-domain-cpu0 { + cpu_pd0: power-domain-cpu0 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD0>; + power-domains = <&cluster_pd0>; }; - CPU_PD1: power-domain-cpu1 { + cpu_pd1: power-domain-cpu1 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD0>; + power-domains = <&cluster_pd0>; }; - CPU_PD2: power-domain-cpu2 { + cpu_pd2: power-domain-cpu2 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD0>; + power-domains = <&cluster_pd0>; }; - CPU_PD3: power-domain-cpu3 { + cpu_pd3: power-domain-cpu3 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD0>; + power-domains = <&cluster_pd0>; }; - CPU_PD4: power-domain-cpu4 { + cpu_pd4: power-domain-cpu4 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD1>; + power-domains = <&cluster_pd1>; }; - CPU_PD5: power-domain-cpu5 { + cpu_pd5: power-domain-cpu5 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD1>; + power-domains = <&cluster_pd1>; }; - CPU_PD6: power-domain-cpu6 { + cpu_pd6: power-domain-cpu6 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD1>; + power-domains = <&cluster_pd1>; }; - CPU_PD7: power-domain-cpu7 { + cpu_pd7: power-domain-cpu7 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD1>; + power-domains = <&cluster_pd1>; }; - CPU_PD8: power-domain-cpu8 { + cpu_pd8: power-domain-cpu8 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD2>; + power-domains = <&cluster_pd2>; }; - CPU_PD9: power-domain-cpu9 { + cpu_pd9: power-domain-cpu9 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD2>; + power-domains = <&cluster_pd2>; }; - CPU_PD10: power-domain-cpu10 { + cpu_pd10: power-domain-cpu10 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD2>; + power-domains = <&cluster_pd2>; }; - CPU_PD11: power-domain-cpu11 { + cpu_pd11: power-domain-cpu11 { #power-domain-cells = <0>; - power-domains = <&CLUSTER_PD2>; + power-domains = <&cluster_pd2>; }; - CLUSTER_PD0: power-domain-cpu-cluster0 { + cluster_pd0: power-domain-cpu-cluster0 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; - power-domains = <&SYSTEM_PD>; + domain-idle-states = <&cluster_cl4>, <&cluster_cl5>; + power-domains = <&system_pd>; }; - CLUSTER_PD1: power-domain-cpu-cluster1 { + cluster_pd1: power-domain-cpu-cluster1 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; - power-domains = <&SYSTEM_PD>; + domain-idle-states = <&cluster_cl4>, <&cluster_cl5>; + power-domains = <&system_pd>; }; - CLUSTER_PD2: power-domain-cpu-cluster2 { + cluster_pd2: power-domain-cpu-cluster2 { #power-domain-cells = <0>; - domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; - power-domains = <&SYSTEM_PD>; + domain-idle-states = <&cluster_cl4>, <&cluster_cl5>; + power-domains = <&system_pd>; }; - SYSTEM_PD: power-domain-system { + system_pd: power-domain-system { #power-domain-cells = <0>; /* TODO: system-wide idle states */ }; @@ -2933,6 +2932,8 @@ pcie6a: pci@1bf8000 { linux,pci-domain = <6>; num-lanes = <4>; + msi-map = <0x0 &gic_its 0xe0000 0x10000>; + interrupts = , , , @@ -3182,6 +3183,8 @@ pcie4: pci@1c08000 { linux,pci-domain = <4>; num-lanes = <2>; + msi-map = <0x0 &gic_its 0xc0000 0x10000>; + interrupts = , , , @@ -3395,7 +3398,7 @@ gmu: gmu@3d6a000 { reg = <0x0 0x03d6a000 0x0 0x35000>, <0x0 0x03d50000 0x0 0x10000>, <0x0 0x0b280000 0x0 0x10000>; - reg-names = "gmu", "rscc", "gmu_pdc"; + reg-names = "gmu", "rscc", "gmu_pdc"; interrupts = , ; @@ -4063,6 +4066,8 @@ usb_1_ss2_dwc3: usb@a000000 { dma-coherent; + usb-role-switch; + ports { #address-cells = <1>; #size-cells = <0>; @@ -4316,6 +4321,8 @@ usb_1_ss0_dwc3: usb@a600000 { dma-coherent; + usb-role-switch; + ports { #address-cells = <1>; #size-cells = <0>; @@ -4414,6 +4421,8 @@ usb_1_ss1_dwc3: usb@a800000 { dma-coherent; + usb-role-switch; + ports { #address-cells = <1>; #size-cells = <0>; @@ -5747,12 +5756,14 @@ apps_smmu: iommu@15000000 { #iommu-cells = <2>; #global-interrupts = <1>; + + dma-coherent; }; intc: interrupt-controller@17000000 { compatible = "arm,gic-v3"; reg = <0 0x17000000 0 0x10000>, /* GICD */ - <0 0x17080000 0 0x480000>; /* GICR * 12 */ + <0 0x17080000 0 0x300000>; /* GICR * 12 */ interrupts = ; @@ -5772,8 +5783,6 @@ gic_its: msi-controller@17040000 { msi-controller; #msi-cells = <1>; - - status = "disabled"; }; }; @@ -5793,7 +5802,7 @@ apps_rsc: rsc@17500000 { , ; label = "apps_rsc"; - power-domains = <&SYSTEM_PD>; + power-domains = <&system_pd>; apps_bcm_voter: bcm-voter { compatible = "qcom,bcm-voter"; diff --git a/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi b/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi index 5a14f116f7a1ee..d55f2d7066ad8c 100644 --- a/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi +++ b/arch/arm64/boot/dts/renesas/beacon-renesom-baseboard.dtsi @@ -200,7 +200,7 @@ sound_card { widgets = "Microphone", "Mic Jack", "Line", "Line In Jack", "Headphone", "Headphone Jack"; - mic-det-gpio = <&gpio0 2 GPIO_ACTIVE_LOW>; + mic-det-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; routing = "Headphone Jack", "HPOUTL", "Headphone Jack", "HPOUTR", "IN3R", "MICBIAS", @@ -364,6 +364,8 @@ versaclock6_bb: clock-controller@6a { #clock-cells = <1>; clocks = <&x304_clk>; clock-names = "xin"; + idt,shutdown = <0>; + idt,output-enable-active = <0>; assigned-clocks = <&versaclock6_bb 1>, <&versaclock6_bb 2>, <&versaclock6_bb 3>, <&versaclock6_bb 4>; @@ -440,16 +442,14 @@ wm8962_endpoint: endpoint { touchscreen@26 { compatible = "ilitek,ili2117"; reg = <0x26>; - interrupt-parent = <&gpio5>; - interrupts = <9 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&gpio5 9 IRQ_TYPE_EDGE_RISING>; wakeup-source; }; hd3ss3220@47 { compatible = "ti,hd3ss3220"; reg = <0x47>; - interrupt-parent = <&gpio6>; - interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio6 4 IRQ_TYPE_LEVEL_LOW>; ports { #address-cells = <1>; diff --git a/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi b/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi index 68b04e56ae5623..43f88c199b7880 100644 --- a/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi +++ b/arch/arm64/boot/dts/renesas/beacon-renesom-som.dtsi @@ -62,8 +62,7 @@ phy0: ethernet-phy@0 { compatible = "ethernet-phy-id0022.1640", "ethernet-phy-ieee802.3-c22"; reg = <0>; - interrupt-parent = <&gpio2>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 11 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; }; }; @@ -131,8 +130,7 @@ pca9654: gpio@20 { pca9654_lte: gpio@21 { compatible = "onnn,pca9654"; reg = <0x21>; - interrupt-parent = <&gpio5>; - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio5 25 IRQ_TYPE_EDGE_FALLING>; interrupt-controller; #interrupt-cells = <2>; gpio-controller; @@ -166,6 +164,8 @@ versaclock5: versaclock_som@6a { #clock-cells = <1>; clocks = <&x304_clk>; clock-names = "xin"; + idt,shutdown = <0>; + idt,output-enable-active = <0>; /* du_dotclkin0, du_dotclkin2, usb_extal, avb_txcrefclk */ assigned-clocks = <&versaclock5 1>, <&versaclock5 2>, @@ -302,8 +302,7 @@ &sdhi2 { brcmf: bcrmf@1 { reg = <1>; compatible = "brcm,bcm4329-fmac"; - interrupt-parent = <&gpio1>; - interrupts = <27 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 27 IRQ_TYPE_LEVEL_LOW>; interrupt-names = "host-wake"; }; }; diff --git a/arch/arm64/boot/dts/renesas/cat875.dtsi b/arch/arm64/boot/dts/renesas/cat875.dtsi index 8c9da8b4bd60bf..191b051ecfd458 100644 --- a/arch/arm64/boot/dts/renesas/cat875.dtsi +++ b/arch/arm64/boot/dts/renesas/cat875.dtsi @@ -25,8 +25,7 @@ phy0: ethernet-phy@0 { compatible = "ethernet-phy-id001c.c915", "ethernet-phy-ieee802.3-c22"; reg = <0>; - interrupt-parent = <&gpio2>; - interrupts = <21 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 21 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm64/boot/dts/renesas/condor-common.dtsi b/arch/arm64/boot/dts/renesas/condor-common.dtsi index 8b7c0c34eadce5..375a56b20f267b 100644 --- a/arch/arm64/boot/dts/renesas/condor-common.dtsi +++ b/arch/arm64/boot/dts/renesas/condor-common.dtsi @@ -166,8 +166,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio4>; - interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio4 23 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>; }; }; @@ -196,8 +195,7 @@ io_expander1: gpio@21 { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 20 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <&d1_8v>; dvdd-supply = <&d1_8v>; pvdd-supply = <&d1_8v>; diff --git a/arch/arm64/boot/dts/renesas/draak.dtsi b/arch/arm64/boot/dts/renesas/draak.dtsi index 6f133f54ded54e..05712cd96d28bb 100644 --- a/arch/arm64/boot/dts/renesas/draak.dtsi +++ b/arch/arm64/boot/dts/renesas/draak.dtsi @@ -247,8 +247,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio5>; - interrupts = <19 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio5 19 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio5 18 GPIO_ACTIVE_LOW>; /* * TX clock internal delay mode is required for reliable @@ -368,8 +367,7 @@ hdmi-encoder@39 { compatible = "adi,adv7511w"; reg = <0x39>, <0x3f>, <0x3c>, <0x38>; reg-names = "main", "edid", "cec", "packet"; - interrupt-parent = <&gpio1>; - interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 28 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <®_1p8v>; dvdd-supply = <®_1p8v>; diff --git a/arch/arm64/boot/dts/renesas/ebisu.dtsi b/arch/arm64/boot/dts/renesas/ebisu.dtsi index cba2fde9dd3688..ab828365666005 100644 --- a/arch/arm64/boot/dts/renesas/ebisu.dtsi +++ b/arch/arm64/boot/dts/renesas/ebisu.dtsi @@ -314,8 +314,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio2>; - interrupts = <21 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 21 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; /* * TX clock internal delay mode is required for reliable @@ -393,15 +392,13 @@ io_expander: gpio@20 { reg = <0x20>; gpio-controller; #gpio-cells = <2>; - interrupt-parent = <&gpio2>; - interrupts = <22 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 22 IRQ_TYPE_LEVEL_LOW>; }; hdmi-encoder@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 1 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <®_1p8v>; dvdd-supply = <®_1p8v>; @@ -437,10 +434,9 @@ video-receiver@70 { compatible = "adi,adv7482"; reg = <0x70>; - interrupt-parent = <&gpio0>; + interrupts-extended = <&gpio0 7 IRQ_TYPE_LEVEL_LOW>, + <&gpio0 17 IRQ_TYPE_LEVEL_LOW>; interrupt-names = "intrq1", "intrq2"; - interrupts = <7 IRQ_TYPE_LEVEL_LOW>, - <17 IRQ_TYPE_LEVEL_LOW>; ports { #address-cells = <1>; @@ -517,8 +513,7 @@ pmic: pmic@30 { compatible = "rohm,bd9571mwv"; reg = <0x30>; - interrupt-parent = <&intc_ex>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&intc_ex 0 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; gpio-controller; diff --git a/arch/arm64/boot/dts/renesas/hihope-common.dtsi b/arch/arm64/boot/dts/renesas/hihope-common.dtsi index 83104af2813eb4..659ae1fed2faa1 100644 --- a/arch/arm64/boot/dts/renesas/hihope-common.dtsi +++ b/arch/arm64/boot/dts/renesas/hihope-common.dtsi @@ -198,6 +198,8 @@ versaclock5: clock-generator@6a { #clock-cells = <1>; clocks = <&x304_clk>; clock-names = "xin"; + idt,shutdown = <0>; + idt,output-enable-active = <1>; }; }; @@ -325,8 +327,7 @@ &sdhi2 { wlcore: wlcore@2 { compatible = "ti,wl1837"; reg = <2>; - interrupt-parent = <&gpio2>; - interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&gpio2 5 IRQ_TYPE_LEVEL_HIGH>; }; }; diff --git a/arch/arm64/boot/dts/renesas/hihope-rev2.dtsi b/arch/arm64/boot/dts/renesas/hihope-rev2.dtsi index 8e2db1d6ca81e2..25c55b32aafe5a 100644 --- a/arch/arm64/boot/dts/renesas/hihope-rev2.dtsi +++ b/arch/arm64/boot/dts/renesas/hihope-rev2.dtsi @@ -69,9 +69,6 @@ &rcar_sound { status = "okay"; - /* Single DAI */ - #sound-dai-cells = <0>; - rsnd_port: port { rsnd_endpoint: endpoint { remote-endpoint = <&dw_hdmi0_snd_in>; diff --git a/arch/arm64/boot/dts/renesas/hihope-rev4.dtsi b/arch/arm64/boot/dts/renesas/hihope-rev4.dtsi index 66f3affe046973..deb69c27277566 100644 --- a/arch/arm64/boot/dts/renesas/hihope-rev4.dtsi +++ b/arch/arm64/boot/dts/renesas/hihope-rev4.dtsi @@ -84,9 +84,6 @@ &rcar_sound { pinctrl-names = "default"; status = "okay"; - /* Single DAI */ - #sound-dai-cells = <0>; - /* audio_clkout0/1/2/3 */ #clock-cells = <1>; clock-frequency = <12288000 11289600>; diff --git a/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi b/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi index ad898c6db4e62d..4113710d55226d 100644 --- a/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi +++ b/arch/arm64/boot/dts/renesas/hihope-rzg2-ex.dtsi @@ -27,8 +27,7 @@ phy0: ethernet-phy@0 { compatible = "ethernet-phy-id001c.c915", "ethernet-phy-ieee802.3-c22"; reg = <0>; - interrupt-parent = <&gpio2>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 11 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts b/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts index 5a6ea08ffd2b27..b78dbd807d1557 100644 --- a/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts +++ b/arch/arm64/boot/dts/renesas/r8a774c0-cat874.dts @@ -208,8 +208,7 @@ &i2c0 { hd3ss3220@47 { compatible = "ti,hd3ss3220"; reg = <0x47>; - interrupt-parent = <&gpio6>; - interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio6 3 IRQ_TYPE_LEVEL_LOW>; ports { #address-cells = <1>; @@ -232,8 +231,7 @@ hd3ss3220_out_ep: endpoint { tda19988: tda19988@70 { compatible = "nxp,tda998x"; reg = <0x70>; - interrupt-parent = <&gpio1>; - interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 1 IRQ_TYPE_LEVEL_LOW>; video-ports = <0x234501>; @@ -414,8 +412,7 @@ &sdhi3 { wlcore: wlcore@2 { compatible = "ti,wl1837"; reg = <2>; - interrupt-parent = <&gpio1>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&gpio1 0 IRQ_TYPE_LEVEL_HIGH>; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle-function-expansion.dtso b/arch/arm64/boot/dts/renesas/r8a77970-eagle-function-expansion.dtso index 3aa243c5f04c80..9450d8ac94cbe9 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-eagle-function-expansion.dtso +++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle-function-expansion.dtso @@ -82,8 +82,7 @@ hdmi-decoder@4c { compatible = "adi,adv7612"; reg = <0x4c>, <0x50>, <0x52>, <0x54>, <0x56>, <0x58>; reg-names = "main", "afe", "rep", "edid", "hdmi", "cp"; - interrupt-parent = <&gpio3>; - interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 2 IRQ_TYPE_LEVEL_LOW>; default-input = <0>; ports { @@ -114,8 +113,8 @@ video-receiver@70 { 0x60 0x61 0x62 0x63 0x64 0x65>; reg-names = "main", "dpll", "cp", "hdmi", "edid", "repeater", "infoframe", "cbus", "cec", "sdp", "txa", "txb" ; - interrupt-parent = <&gpio3>; - interrupts = <03 IRQ_TYPE_LEVEL_LOW>, <04 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 3 IRQ_TYPE_LEVEL_LOW>, + <&gpio3 4 IRQ_TYPE_LEVEL_LOW>; interrupt-names = "intrq1", "intrq2"; ports { diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts index 0608dce92e4059..32f07aa2731678 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts @@ -111,8 +111,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio1>; - interrupts = <17 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 17 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; }; }; @@ -172,8 +171,7 @@ io_expander: gpio@20 { hdmi@39 { compatible = "adi,adv7511w"; reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 20 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <&d1p8>; dvdd-supply = <&d1p8>; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts index e36999e91af533..118e77f4477e38 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-v3msk.dts @@ -117,8 +117,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio1>; - interrupts = <17 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 17 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; }; }; @@ -149,8 +148,7 @@ hdmi@39 { compatible = "adi,adv7511w"; #sound-dai-cells = <0>; reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 20 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <&vcc_d1_8v>; dvdd-supply = <&vcc_d1_8v>; pvdd-supply = <&vcc_d1_8v>; diff --git a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts index 77d22df25fffac..b409a8d1737e62 100644 --- a/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts +++ b/arch/arm64/boot/dts/renesas/r8a77980-v3hsk.dts @@ -124,8 +124,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio4>; - interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio4 23 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>; }; }; @@ -141,8 +140,7 @@ hdmi@39 { compatible = "adi,adv7511w"; #sound-dai-cells = <0>; reg = <0x39>; - interrupt-parent = <&gpio1>; - interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio1 20 IRQ_TYPE_LEVEL_LOW>; avdd-supply = <&vcc1v8_d4>; dvdd-supply = <&vcc1v8_d4>; pvdd-supply = <&vcc1v8_d4>; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0-falcon-cpu.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-cpu.dtsi index 99b73e21c82c2b..e8c8fca48b6963 100644 --- a/arch/arm64/boot/dts/renesas/r8a779a0-falcon-cpu.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779a0-falcon-cpu.dtsi @@ -208,8 +208,7 @@ bridge@2c { clocks = <&sn65dsi86_refclk>; clock-names = "refclk"; - interrupt-parent = <&intc_ex>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&intc_ex 0 IRQ_TYPE_LEVEL_HIGH>; vccio-supply = <®_1p8v>; vpll-supply = <®_1p8v>; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0-falcon.dts b/arch/arm64/boot/dts/renesas/r8a779a0-falcon.dts index 63db822e5f4662..6bd580737f25d3 100644 --- a/arch/arm64/boot/dts/renesas/r8a779a0-falcon.dts +++ b/arch/arm64/boot/dts/renesas/r8a779a0-falcon.dts @@ -31,8 +31,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio4>; - interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio4 16 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi index 1f4ab27acc3398..7156b1a542e8a3 100644 --- a/arch/arm64/boot/dts/renesas/r8a779a0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779a0.dtsi @@ -245,6 +245,14 @@ gpio9: gpio@e6069980 { #interrupt-cells = <2>; }; + fuse: fuse@e6078800 { + compatible = "renesas,r8a779a0-efuse"; + reg = <0 0xe6078800 0 0x100>; + clocks = <&cpg CPG_MOD 916>; + power-domains = <&sysc R8A779A0_PD_ALWAYS_ON>; + resets = <&cpg 916>; + }; + cmt0: timer@e60f0000 { compatible = "renesas,r8a779a0-cmt0", "renesas,rcar-gen4-cmt0"; diff --git a/arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi index 4ed8d4c3790663..e03baefb6a98b0 100644 --- a/arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779f0-spider-cpu.dtsi @@ -171,7 +171,7 @@ &pcie0_clkref { }; &pciec0 { - reset-gpio = <&gpio_exp_20 0 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio_exp_20 0 GPIO_ACTIVE_LOW>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi index 33c1015e9ab38e..5d38669ed1ec34 100644 --- a/arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779f0-spider-ethernet.dtsi @@ -60,8 +60,7 @@ mdio { u101: ethernet-phy@1 { reg = <1>; compatible = "ethernet-phy-ieee802.3-c45"; - interrupt-parent = <&gpio3>; - interrupts = <10 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 10 IRQ_TYPE_LEVEL_LOW>; }; }; }; @@ -78,8 +77,7 @@ mdio { u201: ethernet-phy@2 { reg = <2>; compatible = "ethernet-phy-ieee802.3-c45"; - interrupt-parent = <&gpio3>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 11 IRQ_TYPE_LEVEL_LOW>; }; }; }; @@ -96,8 +94,7 @@ mdio { u301: ethernet-phy@3 { reg = <3>; compatible = "ethernet-phy-ieee802.3-c45"; - interrupt-parent = <&gpio3>; - interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 9 IRQ_TYPE_LEVEL_LOW>; }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi index 9629adb47d99f1..054498e54730b4 100644 --- a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi @@ -377,6 +377,14 @@ gpio3: gpio@e6051980 { #interrupt-cells = <2>; }; + fuse: fuse@e6078800 { + compatible = "renesas,r8a779f0-efuse"; + reg = <0 0xe6078800 0 0x200>; + clocks = <&cpg CPG_MOD 915>; + power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>; + resets = <&cpg 915>; + }; + cmt0: timer@e60f0000 { compatible = "renesas,r8a779f0-cmt0", "renesas,rcar-gen4-cmt0"; diff --git a/arch/arm64/boot/dts/renesas/r8a779f4-s4sk.dts b/arch/arm64/boot/dts/renesas/r8a779f4-s4sk.dts index fa910b85859e99..5d71d52f9c6547 100644 --- a/arch/arm64/boot/dts/renesas/r8a779f4-s4sk.dts +++ b/arch/arm64/boot/dts/renesas/r8a779f4-s4sk.dts @@ -197,8 +197,7 @@ mdio { ic99: ethernet-phy@1 { reg = <1>; compatible = "ethernet-phy-ieee802.3-c45"; - interrupt-parent = <&gpio3>; - interrupts = <10 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 10 IRQ_TYPE_LEVEL_LOW>; }; }; }; @@ -216,8 +215,7 @@ mdio { ic102: ethernet-phy@2 { reg = <2>; compatible = "ethernet-phy-ieee802.3-c45"; - interrupt-parent = <&gpio3>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio3 11 IRQ_TYPE_LEVEL_LOW>; }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi index 12900ebd098b0b..61c6b8022ffdc3 100644 --- a/arch/arm64/boot/dts/renesas/r8a779g0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779g0.dtsi @@ -477,6 +477,11 @@ tsc: thermal@e6198000 { #thermal-sensor-cells = <1>; }; + otp: otp@e61be000 { + compatible = "renesas,r8a779g0-otp"; + reg = <0 0xe61be000 0 0x1000>, <0 0xe61bf000 0 0x1000>; + }; + intc_ex: interrupt-controller@e61c0000 { compatible = "renesas,intc-ex-r8a779g0", "renesas,irqc"; #interrupt-cells = <2>; diff --git a/arch/arm64/boot/dts/renesas/r8a779g2-white-hawk-single.dts b/arch/arm64/boot/dts/renesas/r8a779g2-white-hawk-single.dts index 50a428572d9bd9..0062362b0ba068 100644 --- a/arch/arm64/boot/dts/renesas/r8a779g2-white-hawk-single.dts +++ b/arch/arm64/boot/dts/renesas/r8a779g2-white-hawk-single.dts @@ -70,8 +70,7 @@ phy3: ethernet-phy@0 { compatible = "ethernet-phy-id002b.0980", "ethernet-phy-ieee802.3-c22"; reg = <0>; - interrupt-parent = <&gpio4>; - interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio4 3 IRQ_TYPE_LEVEL_LOW>; }; }; }; diff --git a/arch/arm64/boot/dts/renesas/r8a779h0-gray-hawk-single.dts b/arch/arm64/boot/dts/renesas/r8a779h0-gray-hawk-single.dts index 9a1917b87f6138..58eabcc7e0e07f 100644 --- a/arch/arm64/boot/dts/renesas/r8a779h0-gray-hawk-single.dts +++ b/arch/arm64/boot/dts/renesas/r8a779h0-gray-hawk-single.dts @@ -126,6 +126,12 @@ memory@480000000 { reg = <0x4 0x80000000 0x1 0x80000000>; }; + pcie_clk: clk-9fgv0841-pci { + compatible = "fixed-clock"; + clock-frequency = <100000000>; + #clock-cells = <0>; + }; + reg_1p8v: regulator-1p8v { compatible = "regulator-fixed"; regulator-name = "fixed-1.8V"; @@ -175,8 +181,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio7>; - interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio7 5 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio7 10 GPIO_ACTIVE_LOW>; }; }; @@ -240,6 +245,16 @@ &i2c0 { status = "okay"; clock-frequency = <400000>; + io_expander_a: gpio@20 { + compatible = "onnn,pca9654"; + reg = <0x20>; + interrupts-extended = <&gpio0 0 IRQ_TYPE_LEVEL_LOW>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + eeprom@50 { compatible = "rohm,br24g01", "atmel,24c01"; label = "cpu-board"; @@ -309,6 +324,18 @@ &mmc0 { status = "okay"; }; +&pcie0_clkref { + compatible = "gpio-gate-clock"; + clocks = <&pcie_clk>; + enable-gpios = <&gpio4 21 GPIO_ACTIVE_LOW>; + /delete-property/ clock-frequency; +}; + +&pciec0 { + reset-gpios = <&io_expander_a 0 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + &pfc { pinctrl-0 = <&scif_clk_pins>, <&scif_clk2_pins>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/renesas/r8a779h0.dtsi b/arch/arm64/boot/dts/renesas/r8a779h0.dtsi index 12d8be3fd579cb..facfff4b9cdca1 100644 --- a/arch/arm64/boot/dts/renesas/r8a779h0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779h0.dtsi @@ -147,6 +147,13 @@ extalr_clk: extalr-clk { clock-frequency = <0>; }; + pcie0_clkref: pcie0-clkref { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board */ + clock-frequency = <0>; + }; + pmu-a76 { compatible = "arm,cortex-a76-pmu"; interrupts-extended = <&gic GIC_PPI 7 IRQ_TYPE_LEVEL_LOW>; @@ -417,6 +424,11 @@ tsc: thermal@e6198000 { #thermal-sensor-cells = <1>; }; + otp: otp@e61be000 { + compatible = "renesas,r8a779h0-otp"; + reg = <0 0xe61be000 0 0x1000>, <0 0xe61bf000 0 0x1000>; + }; + intc_ex: interrupt-controller@e61c0000 { compatible = "renesas,intc-ex-r8a779h0", "renesas,irqc"; #interrupt-cells = <2>; @@ -643,6 +655,66 @@ hscif3: serial@e66a0000 { status = "disabled"; }; + pciec0: pcie@e65d0000 { + compatible = "renesas,r8a779h0-pcie", + "renesas,rcar-gen4-pcie"; + reg = <0 0xe65d0000 0 0x1000>, <0 0xe65d2000 0 0x0800>, + <0 0xe65d3000 0 0x2000>, <0 0xe65d5000 0 0x1200>, + <0 0xe65d6200 0 0x0e00>, <0 0xe65d7000 0 0x0400>, + <0 0xfe000000 0 0x400000>; + reg-names = "dbi", "dbi2", "atu", "dma", "app", "phy", "config"; + interrupts = , + , + , + ; + interrupt-names = "msi", "dma", "sft_ce", "app"; + clocks = <&cpg CPG_MOD 624>, <&pcie0_clkref>; + clock-names = "core", "ref"; + power-domains = <&sysc R8A779H0_PD_A2PCIPHY>; + resets = <&cpg 624>; + reset-names = "pwr"; + max-link-speed = <4>; + num-lanes = <2>; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x00 0xff>; + device_type = "pci"; + ranges = <0x01000000 0 0x00000000 0 0xfe000000 0 0x00400000>, + <0x02000000 0 0x30000000 0 0x30000000 0 0x10000000>; + dma-ranges = <0x42000000 0 0x00000000 0 0x00000000 1 0x00000000>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &gic GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>; + snps,enable-cdm-check; + status = "disabled"; + }; + + pciec0_ep: pcie-ep@e65d0000 { + compatible = "renesas,r8a779h0-pcie-ep", + "renesas,rcar-gen4-pcie-ep"; + reg = <0 0xe65d0000 0 0x2000>, <0 0xe65d2000 0 0x1000>, + <0 0xe65d3000 0 0x2000>, <0 0xe65d5000 0 0x1200>, + <0 0xe65d6200 0 0x0e00>, <0 0xe65d7000 0 0x0400>, + <0 0xfe000000 0 0x400000>; + reg-names = "dbi", "dbi2", "atu", "dma", "app", "phy", "addr_space"; + interrupts = , + , + ; + interrupt-names = "dma", "sft_ce", "app"; + clocks = <&cpg CPG_MOD 624>, <&pcie0_clkref>; + clock-names = "core", "ref"; + power-domains = <&sysc R8A779H0_PD_A2PCIPHY>; + resets = <&cpg 624>; + reset-names = "pwr"; + max-link-speed = <4>; + num-lanes = <2>; + max-functions = /bits/ 8 <2>; + status = "disabled"; + }; + canfd: can@e6660000 { compatible = "renesas,r8a779h0-canfd", "renesas,rcar-gen4-canfd"; diff --git a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi index 067a26a66c24ca..be8a0a768c65b4 100644 --- a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi @@ -7,6 +7,7 @@ #include #include +#include / { compatible = "renesas,r9a08g045"; @@ -72,6 +73,32 @@ scif0: serial@1004b800 { status = "disabled"; }; + rtc: rtc@1004ec00 { + compatible = "renesas,r9a08g045-rtca3", "renesas,rz-rtca3"; + reg = <0 0x1004ec00 0 0x400>; + interrupts = , + , + ; + interrupt-names = "alarm", "period", "carry"; + clocks = <&cpg CPG_MOD R9A08G045_VBAT_BCLK>, <&vbattb VBATTB_VBATTCLK>; + clock-names = "bus", "counter"; + power-domains = <&cpg>; + resets = <&cpg R9A08G045_VBAT_BRESETN>; + status = "disabled"; + }; + + vbattb: clock-controller@1005c000 { + compatible = "renesas,r9a08g045-vbattb"; + reg = <0 0x1005c000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD R9A08G045_VBAT_BCLK>, <&vbattb_xtal>; + clock-names = "bclk", "rtx"; + #clock-cells = <1>; + power-domains = <&cpg>; + resets = <&cpg R9A08G045_VBAT_BRESETN>; + status = "disabled"; + }; + i2c0: i2c@10090000 { compatible = "renesas,riic-r9a08g045", "renesas,riic-r9a09g057"; reg = <0 0x10090000 0 0x400>; @@ -425,4 +452,11 @@ timer { interrupt-names = "sec-phys", "phys", "virt", "hyp-phys", "hyp-virt"; }; + + vbattb_xtal: vbattb-xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + /* This value must be overridden by the board. */ + clock-frequency = <0>; + }; }; diff --git a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi index 1ad5a1b6917fee..1c550b22b164ed 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi @@ -20,6 +20,39 @@ audio_extal_clk: audio-clk { clock-frequency = <0>; }; + /* + * The default cluster table is based on the assumption that the PLLCA55 clock + * frequency is set to 1.7GHz. The PLLCA55 clock frequency can be set to + * 1.7/1.6/1.5/1.1 GHz based on the BOOTPLLCA_0/1 pins (and additionally can be + * clocked to 1.8GHz as well). The table below should be overridden in the board + * DTS based on the PLLCA55 clock frequency. + */ + cluster0_opp: opp-table-0 { + compatible = "operating-points-v2"; + + opp-1700000000 { + opp-hz = /bits/ 64 <1700000000>; + opp-microvolt = <900000>; + clock-latency-ns = <300000>; + }; + opp-850000000 { + opp-hz = /bits/ 64 <850000000>; + opp-microvolt = <800000>; + clock-latency-ns = <300000>; + }; + opp-425000000 { + opp-hz = /bits/ 64 <425000000>; + opp-microvolt = <800000>; + clock-latency-ns = <300000>; + }; + opp-212500000 { + opp-hz = /bits/ 64 <212500000>; + opp-microvolt = <800000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -30,6 +63,8 @@ cpu0: cpu@0 { device_type = "cpu"; next-level-cache = <&L3_CA55>; enable-method = "psci"; + clocks = <&cpg CPG_CORE R9A09G057_CA55_0_CORE_CLK0>; + operating-points-v2 = <&cluster0_opp>; }; cpu1: cpu@100 { @@ -38,6 +73,8 @@ cpu1: cpu@100 { device_type = "cpu"; next-level-cache = <&L3_CA55>; enable-method = "psci"; + clocks = <&cpg CPG_CORE R9A09G057_CA55_0_CORE_CLK1>; + operating-points-v2 = <&cluster0_opp>; }; cpu2: cpu@200 { @@ -46,6 +83,8 @@ cpu2: cpu@200 { device_type = "cpu"; next-level-cache = <&L3_CA55>; enable-method = "psci"; + clocks = <&cpg CPG_CORE R9A09G057_CA55_0_CORE_CLK2>; + operating-points-v2 = <&cluster0_opp>; }; cpu3: cpu@300 { @@ -54,6 +93,8 @@ cpu3: cpu@300 { device_type = "cpu"; next-level-cache = <&L3_CA55>; enable-method = "psci"; + clocks = <&cpg CPG_CORE R9A09G057_CA55_0_CORE_CLK3>; + operating-points-v2 = <&cluster0_opp>; }; L3_CA55: cache-controller-0 { @@ -90,6 +131,95 @@ soc: soc { #size-cells = <2>; ranges; + icu: interrupt-controller@10400000 { + compatible = "renesas,r9a09g057-icu"; + reg = <0 0x10400000 0 0x10000>; + #interrupt-cells = <2>; + #address-cells = <0>; + interrupt-controller; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "nmi", + "port_irq0", "port_irq1", "port_irq2", + "port_irq3", "port_irq4", "port_irq5", + "port_irq6", "port_irq7", "port_irq8", + "port_irq9", "port_irq10", "port_irq11", + "port_irq12", "port_irq13", "port_irq14", + "port_irq15", + "tint0", "tint1", "tint2", "tint3", + "tint4", "tint5", "tint6", "tint7", + "tint8", "tint9", "tint10", "tint11", + "tint12", "tint13", "tint14", "tint15", + "tint16", "tint17", "tint18", "tint19", + "tint20", "tint21", "tint22", "tint23", + "tint24", "tint25", "tint26", "tint27", + "tint28", "tint29", "tint30", "tint31", + "int-ca55-0", "int-ca55-1", + "int-ca55-2", "int-ca55-3", + "icu-error-ca55", + "gpt-u0-gtciada", "gpt-u0-gtciadb", + "gpt-u1-gtciada", "gpt-u1-gtciadb"; + clocks = <&cpg CPG_MOD 0x5>; + power-domains = <&cpg>; + resets = <&cpg 0x36>; + }; + pinctrl: pinctrl@10410000 { compatible = "renesas,r9a09g057-pinctrl"; reg = <0 0x10410000 0 0x10000>; @@ -99,6 +229,7 @@ pinctrl: pinctrl@10410000 { gpio-ranges = <&pinctrl 0 0 96>; #interrupt-cells = <2>; interrupt-controller; + interrupt-parent = <&icu>; power-domains = <&cpg>; resets = <&cpg 0xa5>, <&cpg 0xa6>; }; diff --git a/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi index 83f5642d0d35c2..21cf198b3c1717 100644 --- a/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi @@ -102,8 +102,7 @@ phy0: ethernet-phy@7 { compatible = "ethernet-phy-id0022.1640", "ethernet-phy-ieee802.3-c22"; reg = <7>; - interrupt-parent = <&irqc>; - interrupts = ; + interrupts-extended = <&irqc RZG2L_IRQ2 IRQ_TYPE_LEVEL_LOW>; rxc-skew-psec = <2400>; txc-skew-psec = <2400>; rxdv-skew-psec = <0>; @@ -130,8 +129,7 @@ phy1: ethernet-phy@7 { compatible = "ethernet-phy-id0022.1640", "ethernet-phy-ieee802.3-c22"; reg = <7>; - interrupt-parent = <&irqc>; - interrupts = ; + interrupts-extended = <&irqc RZG2L_IRQ3 IRQ_TYPE_LEVEL_LOW>; rxc-skew-psec = <2400>; txc-skew-psec = <2400>; rxdv-skew-psec = <0>; @@ -341,11 +339,18 @@ partitions { #address-cells = <1>; #size-cells = <1>; - boot@0 { - reg = <0x00000000 0x2000000>; - read-only; + partition@0 { + label = "bl2"; + reg = <0x00000000 0x0001d000>; }; - user@2000000 { + + partition@1d000 { /* fip is at offset 0x200 */ + label = "fip"; + reg = <0x0001d000 0x1fe3000>; + }; + + partition@2000000 { + label = "user"; reg = <0x2000000 0x2000000>; }; }; diff --git a/arch/arm64/boot/dts/renesas/rzg2l-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg2l-smarc.dtsi index ee3d96fdb6168b..789f7b0b5ebcad 100644 --- a/arch/arm64/boot/dts/renesas/rzg2l-smarc.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2l-smarc.dtsi @@ -64,8 +64,7 @@ adv7535: hdmi@3d { compatible = "adi,adv7535"; reg = <0x3d>; - interrupt-parent = <&pinctrl>; - interrupts = ; + interrupts-extended = <&pinctrl RZG2L_GPIO(2, 1) IRQ_TYPE_EDGE_FALLING>; clocks = <&osc1>; clock-names = "cec"; avdd-supply = <®_1p8v>; diff --git a/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi index b4ef5ea8a9e345..9aa729fbdce099 100644 --- a/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi @@ -82,8 +82,7 @@ phy0: ethernet-phy@7 { compatible = "ethernet-phy-id0022.1640", "ethernet-phy-ieee802.3-c22"; reg = <7>; - interrupt-parent = <&irqc>; - interrupts = ; + interrupts-extended = <&irqc RZG2L_IRQ0 IRQ_TYPE_LEVEL_LOW>; rxc-skew-psec = <2400>; txc-skew-psec = <2400>; rxdv-skew-psec = <0>; @@ -259,11 +258,18 @@ partitions { #address-cells = <1>; #size-cells = <1>; - boot@0 { - reg = <0x00000000 0x2000000>; - read-only; + partition@0 { + label = "bl2"; + reg = <0x00000000 0x0001d000>; }; - user@2000000 { + + partition@1d000 { /* fip is at offset 0x200 */ + label = "fip"; + reg = <0x0001d000 0x1fe3000>; + }; + + partition@2000000 { + label = "user"; reg = <0x2000000 0x2000000>; }; }; diff --git a/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi index 377849cbb462ea..345b779e4f6015 100644 --- a/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2lc-smarc.dtsi @@ -86,8 +86,7 @@ adv7535: hdmi@3d { compatible = "adi,adv7535"; reg = <0x3d>; - interrupt-parent = <&pinctrl>; - interrupts = ; + interrupts-extended = <&pinctrl RZG2L_GPIO(43, 1) IRQ_TYPE_EDGE_FALLING>; clocks = <&osc1>; clock-names = "cec"; avdd-supply = <®_1p8v>; diff --git a/arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi index 79443fb3f58103..cd4275d86935ba 100644 --- a/arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2ul-smarc-som.dtsi @@ -78,8 +78,7 @@ phy0: ethernet-phy@7 { compatible = "ethernet-phy-id0022.1640", "ethernet-phy-ieee802.3-c22"; reg = <7>; - interrupt-parent = <&irqc>; - interrupts = ; + interrupts-extended = <&irqc RZG2L_IRQ2 IRQ_TYPE_LEVEL_LOW>; rxc-skew-psec = <2400>; txc-skew-psec = <2400>; rxdv-skew-psec = <0>; @@ -107,8 +106,7 @@ phy1: ethernet-phy@7 { compatible = "ethernet-phy-id0022.1640", "ethernet-phy-ieee802.3-c22"; reg = <7>; - interrupt-parent = <&irqc>; - interrupts = ; + interrupts-extended = <&irqc RZG2L_IRQ7 IRQ_TYPE_LEVEL_LOW>; rxc-skew-psec = <2400>; txc-skew-psec = <2400>; rxdv-skew-psec = <0>; @@ -201,6 +199,12 @@ irq { }; }; + qspi0_pins: qspi0 { + pins = "QSPI0_IO0", "QSPI0_IO1", "QSPI0_IO2", "QSPI0_IO3", + "QSPI0_SPCLK", "QSPI0_SSL"; + power-source = <1800>; + }; + sdhi0_emmc_pins: sd0emmc { sd0_emmc_data { pins = "SD0_DATA0", "SD0_DATA1", "SD0_DATA2", "SD0_DATA3", @@ -252,6 +256,45 @@ sd0_mux_uhs { }; }; +&sbc { + pinctrl-0 = <&qspi0_pins>; + pinctrl-names = "default"; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + + spi-cpol; + spi-cpha; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl2"; + reg = <0x00000000 0x0001d000>; + }; + + partition@1d000 { /* fip is at offset 0x200 */ + label = "fip"; + reg = <0x0001d000 0x7e3000>; + }; + + partition@800000 { + label = "user"; + reg = <0x800000 0x800000>; + }; + }; + }; +}; + #if (SW_SW0_DEV_SEL) &sdhi0 { pinctrl-0 = <&sdhi0_emmc_pins>; diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi index 21bfa4e03972ff..2ed01d391554b5 100644 --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi @@ -5,6 +5,7 @@ * Copyright (C) 2023 Renesas Electronics Corp. */ +#include #include #include @@ -103,8 +104,7 @@ ð0 { phy0: ethernet-phy@7 { reg = <7>; - interrupt-parent = <&pinctrl>; - interrupts = ; + interrupts-extended = <&pinctrl RZG2L_GPIO(12, 0) IRQ_TYPE_EDGE_FALLING>; rxc-skew-psec = <0>; txc-skew-psec = <0>; rxdv-skew-psec = <0>; @@ -129,8 +129,7 @@ ð1 { phy1: ethernet-phy@7 { reg = <7>; - interrupt-parent = <&pinctrl>; - interrupts = ; + interrupts-extended = <&pinctrl RZG2L_GPIO(12, 1) IRQ_TYPE_EDGE_FALLING>; rxc-skew-psec = <0>; txc-skew-psec = <0>; rxdv-skew-psec = <0>; @@ -346,6 +345,21 @@ mux { }; }; +&rtc { + status = "okay"; +}; + +&vbattb { + assigned-clocks = <&vbattb VBATTB_MUX>; + assigned-clock-parents = <&vbattb VBATTB_XC>; + quartz-load-femtofarads = <12500>; + status = "okay"; +}; + +&vbattb_xtal { + clock-frequency = <32768>; +}; + &wdt0 { timeout-sec = <60>; status = "okay"; diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi index 7945d44e6ee159..4509151344c430 100644 --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi @@ -20,8 +20,7 @@ keys { compatible = "gpio-keys"; key-1 { - interrupts = ; - interrupt-parent = <&pinctrl>; + interrupts-extended = <&pinctrl RZG2L_GPIO(18, 0) IRQ_TYPE_EDGE_FALLING>; linux,code = ; label = "USER_SW1"; wakeup-source; @@ -29,8 +28,7 @@ key-1 { }; key-2 { - interrupts = ; - interrupt-parent = <&pinctrl>; + interrupts-extended = <&pinctrl RZG2L_GPIO(0, 1) IRQ_TYPE_EDGE_FALLING>; linux,code = ; label = "USER_SW2"; wakeup-source; @@ -38,8 +36,7 @@ key-2 { }; key-3 { - interrupts = ; - interrupt-parent = <&pinctrl>; + interrupts-extended = <&pinctrl RZG2L_GPIO(0, 3) IRQ_TYPE_EDGE_FALLING>; linux,code = ; label = "USER_SW3"; wakeup-source; diff --git a/arch/arm64/boot/dts/renesas/salvator-common.dtsi b/arch/arm64/boot/dts/renesas/salvator-common.dtsi index 1eb4883b321970..06c7e9746304f5 100644 --- a/arch/arm64/boot/dts/renesas/salvator-common.dtsi +++ b/arch/arm64/boot/dts/renesas/salvator-common.dtsi @@ -353,8 +353,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio2>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 11 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; }; }; @@ -531,10 +530,9 @@ video-receiver@70 { reg-names = "main", "dpll", "cp", "hdmi", "edid", "repeater", "infoframe", "cbus", "cec", "sdp", "txa", "txb" ; - interrupt-parent = <&gpio6>; + interrupts-extended = <&gpio6 30 IRQ_TYPE_LEVEL_LOW>, + <&gpio6 31 IRQ_TYPE_LEVEL_LOW>; interrupt-names = "intrq1", "intrq2"; - interrupts = <30 IRQ_TYPE_LEVEL_LOW>, - <31 IRQ_TYPE_LEVEL_LOW>; ports { #address-cells = <1>; @@ -604,8 +602,7 @@ pmic: pmic@30 { compatible = "rohm,bd9571mwv"; reg = <0x30>; - interrupt-parent = <&intc_ex>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&intc_ex 0 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; gpio-controller; diff --git a/arch/arm64/boot/dts/renesas/salvator-x.dtsi b/arch/arm64/boot/dts/renesas/salvator-x.dtsi index ddee50e64632d9..5920932cbc2f6c 100644 --- a/arch/arm64/boot/dts/renesas/salvator-x.dtsi +++ b/arch/arm64/boot/dts/renesas/salvator-x.dtsi @@ -25,5 +25,7 @@ versaclock5: clock-generator@6a { #clock-cells = <1>; clocks = <&x23_clk>; clock-names = "xin"; + idt,shutdown = <0>; + idt,output-enable-active = <1>; }; }; diff --git a/arch/arm64/boot/dts/renesas/salvator-xs.dtsi b/arch/arm64/boot/dts/renesas/salvator-xs.dtsi index 08b925624e1292..1d18dedb1ff039 100644 --- a/arch/arm64/boot/dts/renesas/salvator-xs.dtsi +++ b/arch/arm64/boot/dts/renesas/salvator-xs.dtsi @@ -25,6 +25,8 @@ versaclock6: clock-generator@6a { #clock-cells = <1>; clocks = <&x23_clk>; clock-names = "xin"; + idt,shutdown = <0>; + idt,output-enable-active = <1>; }; }; diff --git a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi index 431b37bf566192..5c211ed83049d5 100644 --- a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi +++ b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi @@ -150,8 +150,7 @@ hdmi@3d { pinctrl-0 = <&hdmi1_pins>; pinctrl-names = "default"; - interrupt-parent = <&gpio2>; - interrupts = <14 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 14 IRQ_TYPE_LEVEL_LOW>; clocks = <&cs2000>; clock-names = "cec"; @@ -236,8 +235,7 @@ gpio_exp_74: gpio@74 { #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent = <&gpio6>; - interrupts = <8 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio6 8 IRQ_TYPE_EDGE_FALLING>; audio-out-off-hog { gpio-hog; @@ -297,8 +295,7 @@ gpio_exp_75: gpio@75 { #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent = <&gpio6>; - interrupts = <4 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio6 4 IRQ_TYPE_EDGE_FALLING>; }; }; @@ -318,8 +315,7 @@ gpio_exp_76: gpio@76 { #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent = <&gpio7>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio7 3 IRQ_TYPE_EDGE_FALLING>; }; gpio_exp_77: gpio@77 { @@ -329,8 +325,7 @@ gpio_exp_77: gpio@77 { #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent = <&gpio5>; - interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio5 9 IRQ_TYPE_EDGE_FALLING>; }; }; @@ -449,8 +444,7 @@ &sdhi3 { wlcore: wlcore@2 { compatible = "ti,wl1837"; reg = <2>; - interrupt-parent = <&gpio1>; - interrupts = <25 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&gpio1 25 IRQ_TYPE_EDGE_FALLING>; }; }; diff --git a/arch/arm64/boot/dts/renesas/ulcb.dtsi b/arch/arm64/boot/dts/renesas/ulcb.dtsi index a2f66f91604849..cb11abba7befe4 100644 --- a/arch/arm64/boot/dts/renesas/ulcb.dtsi +++ b/arch/arm64/boot/dts/renesas/ulcb.dtsi @@ -150,8 +150,7 @@ phy0: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio2>; - interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio2 11 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; }; }; @@ -234,6 +233,8 @@ versaclock5: clock-generator@6a { #clock-cells = <1>; clocks = <&x23_clk>; clock-names = "xin"; + idt,shutdown = <0>; + idt,output-enable-active = <1>; }; }; @@ -248,8 +249,7 @@ pmic: pmic@30 { compatible = "rohm,bd9571mwv"; reg = <0x30>; - interrupt-parent = <&intc_ex>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&intc_ex 0 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; gpio-controller; diff --git a/arch/arm64/boot/dts/renesas/white-hawk-cpu-common.dtsi b/arch/arm64/boot/dts/renesas/white-hawk-cpu-common.dtsi index 3845b413bd24cd..f24814d7c924ed 100644 --- a/arch/arm64/boot/dts/renesas/white-hawk-cpu-common.dtsi +++ b/arch/arm64/boot/dts/renesas/white-hawk-cpu-common.dtsi @@ -167,8 +167,7 @@ avb0_phy: ethernet-phy@0 { "ethernet-phy-ieee802.3-c22"; rxc-skew-ps = <1500>; reg = <0>; - interrupt-parent = <&gpio7>; - interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio7 5 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&gpio7 10 GPIO_ACTIVE_LOW>; }; }; @@ -216,8 +215,7 @@ &i2c0 { io_expander_a: gpio@20 { compatible = "onnn,pca9654"; reg = <0x20>; - interrupt-parent = <&gpio0>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio0 0 IRQ_TYPE_LEVEL_LOW>; gpio-controller; #gpio-cells = <2>; interrupt-controller; @@ -240,14 +238,16 @@ &i2c1 { clock-frequency = <400000>; bridge@2c { + pinctrl-0 = <&irq0_pins>; + pinctrl-names = "default"; + compatible = "ti,sn65dsi86"; reg = <0x2c>; clocks = <&sn65dsi86_refclk>; clock-names = "refclk"; - interrupt-parent = <&intc_ex>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&intc_ex 0 IRQ_TYPE_LEVEL_HIGH>; enable-gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>; @@ -302,7 +302,7 @@ &pcie0_clkref { }; &pciec0 { - reset-gpio = <&io_expander_a 0 GPIO_ACTIVE_LOW>; + reset-gpios = <&io_expander_a 0 GPIO_ACTIVE_LOW>; status = "okay"; }; @@ -344,6 +344,11 @@ i2c1_pins: i2c1 { function = "i2c1"; }; + irq0_pins: irq0 { + groups = "intc_ex_irq0_a"; + function = "intc_ex"; + }; + keys_pins: keys { pins = "GP_5_0", "GP_5_1", "GP_5_2"; bias-pull-up; diff --git a/arch/arm64/boot/dts/renesas/white-hawk-ethernet.dtsi b/arch/arm64/boot/dts/renesas/white-hawk-ethernet.dtsi index 595ec4ff4cdd01..ad94bf3f5e6c42 100644 --- a/arch/arm64/boot/dts/renesas/white-hawk-ethernet.dtsi +++ b/arch/arm64/boot/dts/renesas/white-hawk-ethernet.dtsi @@ -29,8 +29,7 @@ mdio { avb1_phy: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <0>; - interrupt-parent = <&gpio6>; - interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio6 3 IRQ_TYPE_LEVEL_LOW>; }; }; }; @@ -51,8 +50,7 @@ mdio { avb2_phy: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; reg = <0>; - interrupt-parent = <&gpio5>; - interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&gpio5 4 IRQ_TYPE_LEVEL_LOW>; }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 09423070c99282..86cc418a2255cd 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -5,6 +5,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-engicam-px30-core-ctouch2-of10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-engicam-px30-core-edimm2.2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-firefly-jd4-core-mb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += px30-ringneck-haikou.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-bpi-p2-pro.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-evb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-roc-cc.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-rock-pi-s.dtb @@ -76,6 +77,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rockpro64.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-sapphire-excavator.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399pro-rock-pi-n10.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-radxa-e20c.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg-arc-d.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg-arc-s.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg353p.dtb @@ -91,6 +93,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinetab2-v0.1.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinetab2-v2.0.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rgb10max3.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rgb20sx.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rgb30.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rk2023.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-x55.dtb @@ -107,6 +110,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-soquartz-model-a.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-box-demo.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-lckfb-tspi.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-lubancat-1.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-nanopi-r3s.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-bpi-r2-pro.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-fastrhino-r66s.dtb @@ -124,7 +128,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-rock-3b.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-display-vz.dtbo dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-io-expander.dtbo +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-armsom-sige5.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-sige7.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-w3.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-genbook.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb @@ -146,11 +152,14 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-toybrick-x0.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-turing-rk1.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-coolpi-4b.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-gameforce-ace.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-indiedroid-nova.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-khadas-edge2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-nanopi-r6s.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-nanopi-r6c.dtb -dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-rock-5a.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-odroid-m2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-5.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-orangepi-5b.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-rock-5a.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-rock-5c.dtb diff --git a/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi b/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi index 5b4e223851659f..1edfd643b25ae8 100644 --- a/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi @@ -12,7 +12,7 @@ aliases { mmc2 = &sdio; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; /* +5V */ regulator-always-on; @@ -42,7 +42,7 @@ vcc3v3_btreg: vcc3v3-btreg { states = <3300000 0x0>; }; - vcc3v3_rf_aux_mod: vcc3v3-rf-aux-mod { + vcc3v3_rf_aux_mod: regulator-vcc3v3-rf-aux-mod { compatible = "regulator-fixed"; regulator-name = "vcc3v3_rf_aux_mod"; regulator-min-microvolt = <3300000>; diff --git a/arch/arm64/boot/dts/rockchip/px30-engicam-px30-core.dtsi b/arch/arm64/boot/dts/rockchip/px30-engicam-px30-core.dtsi index 5eecbefa8a336e..dd715d22d4d25e 100644 --- a/arch/arm64/boot/dts/rockchip/px30-engicam-px30-core.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-engicam-px30-core.dtsi @@ -50,7 +50,7 @@ rk809: pmic@20 { interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <1>; clock-output-names = "rk808-clkout1", "rk808-clkout2"; diff --git a/arch/arm64/boot/dts/rockchip/px30-evb.dts b/arch/arm64/boot/dts/rockchip/px30-evb.dts index 0a90a88fc66497..d93aaac7a42f15 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb.dts +++ b/arch/arm64/boot/dts/rockchip/px30-evb.dts @@ -89,7 +89,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; /* GPIO3_A4 */ }; - vcc5v0_sys: vccsys { + vcc5v0_sys: regulator-vccsys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -189,7 +189,7 @@ rk809: pmic@20 { interrupts = <7 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <0>; clock-output-names = "xin32k"; diff --git a/arch/arm64/boot/dts/rockchip/px30-firefly-jd4-core-mb.dts b/arch/arm64/boot/dts/rockchip/px30-firefly-jd4-core-mb.dts index d03e6aef54dc07..5e3c10d825a04c 100644 --- a/arch/arm64/boot/dts/rockchip/px30-firefly-jd4-core-mb.dts +++ b/arch/arm64/boot/dts/rockchip/px30-firefly-jd4-core-mb.dts @@ -24,7 +24,7 @@ chosen { stdout-path = "serial2:115200n8"; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -85,7 +85,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; /* GPIO3_A4 */ }; - vcc5v0_baseboard: vcc5v0-baseboard-regulator { + vcc5v0_baseboard: regulator-vcc5v0-baseboard { compatible = "regulator-fixed"; regulator-name = "vcc5v0_baseboard"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/px30-firefly-jd4-core.dtsi b/arch/arm64/boot/dts/rockchip/px30-firefly-jd4-core.dtsi index f18d7eb9a9c7b2..1ad0e52a64ab70 100644 --- a/arch/arm64/boot/dts/rockchip/px30-firefly-jd4-core.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-firefly-jd4-core.dtsi @@ -17,7 +17,7 @@ emmc_pwrseq: emmc-pwrseq { reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -70,7 +70,7 @@ rk809: pmic@20 { interrupts = <7 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <0>; clock-output-names = "xin32k"; diff --git a/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts b/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts index ae398acdcf45e6..e4517f47d519cc 100644 --- a/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts +++ b/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts @@ -90,7 +90,7 @@ sgtl5000_clk: sgtl5000-oscillator { clock-frequency = <24576000>; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -99,7 +99,7 @@ dc_12v: dc-12v-regulator { regulator-max-microvolt = <12000000>; }; - vcc3v3_baseboard: vcc3v3-baseboard-regulator { + vcc3v3_baseboard: regulator-vcc3v3-baseboard { compatible = "regulator-fixed"; regulator-name = "vcc3v3_baseboard"; regulator-always-on; @@ -109,7 +109,7 @@ vcc3v3_baseboard: vcc3v3-baseboard-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_baseboard: vcc5v0-baseboard-regulator { + vcc5v0_baseboard: regulator-vcc5v0-baseboard { compatible = "regulator-fixed"; regulator-name = "vcc5v0_baseboard"; regulator-always-on; @@ -119,7 +119,7 @@ vcc5v0_baseboard: vcc5v0-baseboard-regulator { vin-supply = <&dc_12v>; }; - vdda_codec: vdda-codec-regulator { + vdda_codec: regulator-vdda-codec { compatible = "regulator-fixed"; regulator-name = "vdda_codec"; regulator-boot-on; @@ -128,7 +128,7 @@ vdda_codec: vdda-codec-regulator { vin-supply = <&vcc5v0_baseboard>; }; - vddd_codec: vddd-codec-regulator { + vddd_codec: regulator-vddd-codec { compatible = "regulator-fixed"; regulator-name = "vddd_codec"; regulator-boot-on; diff --git a/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi b/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi index b7163ed74232d7..ae050cc6cd050f 100644 --- a/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi @@ -9,12 +9,19 @@ / { aliases { + i2c10 = &i2c10; mmc0 = &emmc; mmc1 = &sdio; rtc0 = &rtc_twi; rtc1 = &rk809; }; + /* allows userspace to control the gate of the ATtiny UPDI pass FET via sysfs */ + attiny-updi-gate-regulator { + compatible = "regulator-output"; + vout-supply = <&vg_attiny_updi>; + }; + emmc_pwrseq: emmc-pwrseq { compatible = "mmc-pwrseq-emmc"; pinctrl-0 = <&emmc_reset>; @@ -36,7 +43,7 @@ module_led: led-0 { }; }; - vcc5v0_sys: vccsys-regulator { + vcc5v0_sys: regulator-vccsys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -126,7 +133,7 @@ rk809: pmic@20 { pinctrl-names = "default"; #clock-cells = <0>; clock-output-names = "xin32k"; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc5v0_sys>; @@ -280,6 +287,11 @@ regulator-state-mem { regulator-suspend-microvolt = <1800000>; }; }; + + /* supplies the gate of the ATtiny UPDI pass FET */ + vg_attiny_updi: SWITCH_REG1 { + regulator-name = "vg_attiny_updi"; + }; }; }; }; @@ -291,14 +303,25 @@ &i2c1 { clock-frequency = <400000>; fan: fan@18 { - compatible = "ti,amc6821"; + compatible = "tsd,mule", "ti,amc6821"; reg = <0x18>; - #cooling-cells = <2>; - }; - rtc_twi: rtc@6f { - compatible = "isil,isl1208"; - reg = <0x6f>; + i2c-mux { + compatible = "tsd,mule-i2c-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2c10: i2c@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + rtc_twi: rtc@6f { + compatible = "isil,isl1208"; + reg = <0x6f>; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3308-bpi-p2-pro.dts b/arch/arm64/boot/dts/rockchip/rk3308-bpi-p2-pro.dts new file mode 100644 index 00000000000000..2f7b09b7f43f44 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3308-bpi-p2-pro.dts @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include "rk3308.dtsi" + +/ { + model = "Banana Pi P2 Pro (RK3308) Board"; + compatible = "sinovoip,rk3308-bpi-p2pro", "rockchip,rk3308"; + + aliases { + ethernet0 = &gmac; + mmc0 = &emmc; + mmc1 = &sdmmc; + mmc2 = &sdio; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + + button-recovery { + label = "Recovery"; + linux,code = ; + press-threshold-microvolt = <10000>; + }; + }; + + analog-sound { + compatible = "audio-graph-card"; + label = "rockchip,rk3308"; + + dais = <&i2s_8ch_2_p0>; + pinctrl-names = "default"; + pinctrl-0 = <&phone_ctl>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_en0>, <&led_en1>; + + blue-led { + color = ; + default-state = "on"; + function = LED_FUNCTION_POWER; + gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; + label = "blue:power"; + linux,default-trigger = "default-on"; + }; + + green-led { + color = ; + default-state = "on"; + function = LED_FUNCTION_HEARTBEAT; + gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; + label = "green:heartbeat"; + linux,default-trigger = "heartbeat"; + }; + }; + + vdd_log: regulator-1v04-vdd-log { + compatible = "regulator-fixed"; + regulator-name = "vdd_log"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1040000>; + regulator-max-microvolt = <1040000>; + vin-supply = <&vcc_in>; + }; + + vcc_ddr: regulator-1v5-vcc-ddr { + compatible = "regulator-fixed"; + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + vin-supply = <&vcc_in>; + }; + + vcc_1v8: regulator-1v8-vcc { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_io>; + }; + + vcc_io: regulator-3v3-vcc-io { + compatible = "regulator-fixed"; + regulator-name = "vcc_io"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_in>; + }; + + vcc_in: regulator-5v0-vcc-in { + compatible = "regulator-fixed"; + regulator-name = "vcc_in"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vdd_core: regulator-vdd-core { + compatible = "pwm-regulator"; + pwms = <&pwm0 0 5000 1>; + pwm-supply = <&vcc_in>; + regulator-name = "vdd_core"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <827000>; + regulator-max-microvolt = <1340000>; + regulator-settling-time-up-us = <250>; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-0 = <&wifi_reg_on>; + pinctrl-names = "default"; + reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; + }; +}; + +&codec { + status = "okay"; + + port { + codec_p0_0: endpoint { + remote-endpoint = <&i2s_8ch_2_p0_0>; + }; + }; +}; + +&cpu0 { + cpu-supply = <&vdd_core>; +}; + +&emmc { + cap-mmc-highspeed; + mmc-hs200-1_8v; + no-sd; + no-sdio; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd &emmc_pwren>; + status = "okay"; +}; + +&gmac { + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&mac_clkin>; + clock_in_out = "input"; + phy-handle = <&rtl8201f>; + phy-supply = <&vcc_io>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + + rtl8201f: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&mac_rst>; + reset-assert-us = <50000>; + reset-deassert-us = <50000>; + reset-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&i2s_8ch_2 { + #sound-dai-cells = <0>; + status = "okay"; + + i2s_8ch_2_p0: port { + i2s_8ch_2_p0_0: endpoint { + dai-format = "i2s"; + mclk-fs = <256>; + remote-endpoint = <&codec_p0_0>; + }; + }; +}; + +&io_domains { + vccio0-supply = <&vcc_io>; + vccio1-supply = <&vcc_io>; + vccio2-supply = <&vcc_io>; + vccio3-supply = <&vcc_io>; + vccio4-supply = <&vcc_1v8>; + vccio5-supply = <&vcc_io>; + status = "okay"; +}; + +&pinctrl { + pinctrl-names = "default"; + pinctrl-0 = <&rtc_32k>; + + bt { + bt_reg_on: bt-reg-on { + rockchip,pins = <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_wake_host: bt-wake-host { + rockchip,pins = <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + host_wake_bt: host-wake-bt { + rockchip,pins = <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + gmac { + mac_rst: mac-rst { + rockchip,pins = <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + leds { + led_en0: led-en0 { + rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + led_en1: led-en1 { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sound { + phone_ctl: phone-ctl { + rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + wifi { + wifi_reg_on: wifi-reg-on { + rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wifi_wake_host: wifi-wake-host { + rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; +}; + +&pwm0 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_pin_pull_down>; + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8>; + status = "okay"; +}; + +/* WIFI part of the AP6256 connected with SDIO */ +&sdio { + #address-cells = <1>; + #size-cells = <0>; + cap-sd-highspeed; + cap-sdio-irq; + disable-wp; + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + no-mmc; + no-sd; + non-removable; + sd-uhs-sdr104; + status = "okay"; + + ap6256: wifi@1 { + compatible = "brcm,bcm43456-fmac", "brcm,bcm4329-fmac"; + reg = <1>; + interrupt-parent = <&gpio0>; + interrupts = ; + interrupt-names = "host-wake"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_wake_host>; + }; +}; + +&sdmmc { + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + vmmc-supply = <&vcc_io>; + status = "okay"; +}; + +&u2phy { + status = "okay"; +}; + +&u2phy_host { + status = "okay"; +}; + +&u2phy_otg { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +/* BT part of the AP6256 connected with UART */ +&uart4 { + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "brcm,bcm4345c5"; + clocks = <&cru SCLK_RTC32K>; + clock-names = "lpo"; + interrupt-parent = <&gpio4>; + interrupts = ; + interrupt-names = "host-wakeup"; + device-wakeup-gpios = <&gpio4 RK_PB2 GPIO_ACTIVE_HIGH>; + shutdown-gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_HIGH>; + max-speed = <1500000>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_reg_on &bt_wake_host &host_wake_bt>; + vbat-supply = <&vcc_io>; + vddio-supply = <&vcc_1v8>; + }; +}; + +&usb20_otg { + dr_mode = "peripheral"; + status = "okay"; +}; + +&usb_host_ehci { + status = "okay"; +}; + +&usb_host_ohci { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3308-evb.dts b/arch/arm64/boot/dts/rockchip/rk3308-evb.dts index 184b84fdde075a..3f1aafe2dc139a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3308-evb.dts @@ -84,7 +84,7 @@ key-power { }; }; - vcc12v_dcin: vcc12v-dcin { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-min-microvolt = <12000000>; @@ -93,7 +93,7 @@ vcc12v_dcin: vcc12v-dcin { regulator-boot-on; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-min-microvolt = <5000000>; @@ -103,7 +103,7 @@ vcc5v0_sys: vcc5v0-sys { vin-supply = <&vcc12v_dcin>; }; - vccio_sdio: vcc_1v8: vcc-1v8 { + vccio_sdio: vcc_1v8: regulator-vcc-1v8 { compatible = "regulator-fixed"; regulator-name = "vcc_1v8"; regulator-min-microvolt = <1800000>; @@ -113,7 +113,7 @@ vccio_sdio: vcc_1v8: vcc-1v8 { vin-supply = <&vcc_io>; }; - vcc_ddr: vcc-ddr { + vcc_ddr: regulator-vcc-ddr { compatible = "regulator-fixed"; regulator-name = "vcc_ddr"; regulator-min-microvolt = <1500000>; @@ -123,7 +123,7 @@ vcc_ddr: vcc-ddr { vin-supply = <&vcc5v0_sys>; }; - vcc_io: vcc-io { + vcc_io: regulator-vcc-io { compatible = "regulator-fixed"; regulator-name = "vcc_io"; regulator-min-microvolt = <3300000>; @@ -133,7 +133,7 @@ vcc_io: vcc-io { vin-supply = <&vcc5v0_sys>; }; - vccio_flash: vccio-flash { + vccio_flash: regulator-vccio-flash { compatible = "regulator-fixed"; regulator-name = "vccio_flash"; regulator-min-microvolt = <3300000>; @@ -143,7 +143,7 @@ vccio_flash: vccio-flash { vin-supply = <&vcc_io>; }; - vcc5v0_host: vcc5v0-host { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; enable-active-high; @@ -153,7 +153,7 @@ vcc5v0_host: vcc5v0-host { vin-supply = <&vcc5v0_sys>; }; - vdd_core: vdd-core { + vdd_core: regulator-vdd-core { compatible = "pwm-regulator"; pwms = <&pwm0 0 5000 1>; regulator-name = "vdd_core"; @@ -165,7 +165,7 @@ vdd_core: vdd-core { pwm-supply = <&vcc5v0_sys>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "regulator-fixed"; regulator-name = "vdd_log"; regulator-min-microvolt = <1050000>; @@ -175,7 +175,7 @@ vdd_log: vdd-log { vin-supply = <&vcc5v0_sys>; }; - vdd_1v0: vdd-1v0 { + vdd_1v0: regulator-vdd-1v0 { compatible = "regulator-fixed"; regulator-name = "vdd_1v0"; regulator-min-microvolt = <1000000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts index d9e191ad1d77e0..629121de5a13d6 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3308-roc-cc.dts @@ -49,7 +49,7 @@ user_led: led-1 { }; }; - typec_vcc5v: typec-vcc5v { + typec_vcc5v: regulator-typec-vcc5v { compatible = "regulator-fixed"; regulator-name = "typec_vcc5v"; regulator-min-microvolt = <5000000>; @@ -58,7 +58,7 @@ typec_vcc5v: typec-vcc5v { regulator-boot-on; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-min-microvolt = <5000000>; @@ -68,7 +68,7 @@ vcc5v0_sys: vcc5v0-sys { vin-supply = <&typec_vcc5v>; }; - vcc_io: vcc-io { + vcc_io: regulator-vcc-io { compatible = "regulator-fixed"; regulator-name = "vcc_io"; regulator-min-microvolt = <3300000>; @@ -89,7 +89,7 @@ vcc_sdmmc: vcc-sdmmc { vin-supply = <&vcc5v0_sys>; }; - vcc_sd: vcc-sd { + vcc_sd: regulator-vcc-sd { compatible = "regulator-fixed"; gpio = <&gpio4 RK_PD6 GPIO_ACTIVE_LOW>; regulator-name = "vcc_sd"; @@ -100,7 +100,7 @@ vcc_sd: vcc-sd { vin-supply = <&vcc_io>; }; - vdd_core: vdd-core { + vdd_core: regulator-vdd-core { compatible = "pwm-regulator"; pwms = <&pwm0 0 5000 1>; regulator-name = "vdd_core"; @@ -112,7 +112,7 @@ vdd_core: vdd-core { pwm-supply = <&vcc5v0_sys>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "regulator-fixed"; regulator-name = "vdd_log"; regulator-min-microvolt = <1050000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts b/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts index 62d18ca769a107..7a32972bc24965 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts @@ -55,7 +55,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; }; - vcc_1v8: vcc-1v8 { + vcc_1v8: regulator-vcc-1v8 { compatible = "regulator-fixed"; regulator-name = "vcc_1v8"; regulator-always-on; @@ -65,7 +65,7 @@ vcc_1v8: vcc-1v8 { vin-supply = <&vcc_io>; }; - vcc_io: vcc-io { + vcc_io: regulator-vcc-io { compatible = "regulator-fixed"; regulator-name = "vcc_io"; regulator-always-on; @@ -75,7 +75,7 @@ vcc_io: vcc-io { vin-supply = <&vcc5v0_sys>; }; - vcc_ddr: vcc-ddr { + vcc_ddr: regulator-vcc-ddr { compatible = "regulator-fixed"; regulator-name = "vcc_ddr"; regulator-always-on; @@ -85,7 +85,7 @@ vcc_ddr: vcc-ddr { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_otg: vcc5v0-otg { + vcc5v0_otg: regulator-vcc5v0-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -96,7 +96,7 @@ vcc5v0_otg: vcc5v0-otg { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -105,7 +105,7 @@ vcc5v0_sys: vcc5v0-sys { regulator-max-microvolt = <5000000>; }; - vdd_core: vdd-core { + vdd_core: regulator-vdd-core { compatible = "pwm-regulator"; pwms = <&pwm0 0 5000 1>; pwm-supply = <&vcc5v0_sys>; @@ -117,7 +117,7 @@ vdd_core: vdd-core { regulator-boot-on; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "regulator-fixed"; regulator-name = "vdd_log"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts b/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts index c7b1862fca6a0f..a94114fb7cc1d1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts @@ -78,7 +78,7 @@ spdif_out: spdif-out { }; /* Power tree */ - vccio_1v8: vccio-1v8-regulator { + vccio_1v8: regulator-vccio-1v8 { compatible = "regulator-fixed"; regulator-name = "vccio_1v8"; regulator-min-microvolt = <1800000>; @@ -86,7 +86,7 @@ vccio_1v8: vccio-1v8-regulator { regulator-always-on; }; - vccio_3v3: vccio-3v3-regulator { + vccio_3v3: regulator-vccio-3v3 { compatible = "regulator-fixed"; regulator-name = "vccio_3v3"; regulator-min-microvolt = <3300000>; @@ -94,7 +94,7 @@ vccio_3v3: vccio-3v3-regulator { regulator-always-on; }; - vcc_otg_vbus: otg-vbus-regulator { + vcc_otg_vbus: regulator-otg-vbus { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; pinctrl-0 = <&otg_vbus_drv>; @@ -105,7 +105,7 @@ vcc_otg_vbus: otg-vbus-regulator { enable-active-high; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; pinctrl-0 = <&sdmmc0m1_pin>; @@ -116,7 +116,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vccio_3v3>; }; - vdd_arm: vdd-arm { + vdd_arm: regulator-vdd-arm { compatible = "pwm-regulator"; pwms = <&pwm0 0 5000 1>; regulator-name = "vdd_arm"; @@ -127,7 +127,7 @@ vdd_arm: vdd-arm { regulator-boot-on; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm1 0 5000 1>; regulator-name = "vdd_log"; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dtsi index b6d041dbed94af..150fadcb0b3c39 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dtsi @@ -49,7 +49,7 @@ rk817-sound { compatible = "simple-audio-card"; simple-audio-card,name = "rk817_int"; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", @@ -70,7 +70,7 @@ simple-audio-card,cpu { }; }; - vccsys: vccsys { + vccsys: regulator-vccsys { compatible = "regulator-fixed"; regulator-name = "vcc3v8_sys"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-gameforce-chi.dts b/arch/arm64/boot/dts/rockchip/rk3326-gameforce-chi.dts index 579261b3a474b9..10e6ab724ac451 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-gameforce-chi.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-gameforce-chi.dts @@ -245,7 +245,7 @@ sound { simple-audio-card,name = "rk817_ext"; simple-audio-card,aux-devs = <&spk_amp>; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", @@ -292,7 +292,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; }; - vccsys: vccsys-regulator { + vccsys: regulator-vccsys { compatible = "regulator-fixed"; regulator-name = "vcc3v8_sys"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go.dtsi index 80fc53c807a42c..446a1a6c12e7eb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go.dtsi @@ -144,7 +144,7 @@ rk817-sound { compatible = "simple-audio-card"; simple-audio-card,name = "rk817_int"; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", @@ -165,7 +165,7 @@ simple-audio-card,cpu { }; }; - vccsys: vccsys { + vccsys: regulator-vccsys { compatible = "regulator-fixed"; regulator-name = "vcc3v8_sys"; regulator-always-on; @@ -173,7 +173,7 @@ vccsys: vccsys { regulator-max-microvolt = <3800000>; }; - vcc_host: vcc_host { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; regulator-name = "vcc_host"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts index 824183e515da64..8dfeaf1f8eb0d3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts @@ -36,7 +36,7 @@ gmac_clkin: external-gmac-clock { #clock-cells = <0>; }; - vcc_host_5v: usb3-current-switch { + vcc_host_5v: regulator-usb3-current-switch { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; @@ -46,7 +46,7 @@ vcc_host_5v: usb3-current-switch { vin-supply = <&vcc_sys>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -159,7 +159,7 @@ pmic@18 { interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts index 1eef5504445fa9..3707df6acf1fcb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts @@ -21,7 +21,7 @@ chosen { stdout-path = "serial2:1500000n8"; }; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -44,7 +44,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio1 18 GPIO_ACTIVE_LOW>; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio0 30 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -55,7 +55,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -65,7 +65,7 @@ vcc_sys: vcc-sys { vin-supply = <&dc_12v>; }; - vcc_phy: vcc-phy-regulator { + vcc_phy: regulator-vcc-phy { compatible = "regulator-fixed"; regulator-name = "vcc_phy"; regulator-always-on; @@ -121,7 +121,7 @@ rk805: pmic@18 { #gpio-cells = <2>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2.dtsi b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2.dtsi new file mode 100644 index 00000000000000..1715d311e1f2d3 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2.dtsi @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 David Bauer + */ + +/dts-v1/; + +#include +#include +#include "rk3328.dtsi" + +/ { + aliases { + ethernet0 = &gmac2io; + ethernet1 = &rtl8153; + mmc0 = &sdmmc; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + gmac_clk: gmac-clock { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "gmac_clkin"; + #clock-cells = <0>; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&reset_button_pin>; + pinctrl-names = "default"; + + key-reset { + label = "reset"; + gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <50>; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>; + pinctrl-names = "default"; + + lan_led: led-0 { + gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>; + label = "nanopi-r2s:green:lan"; + }; + + sys_led: led-1 { + gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; + label = "nanopi-r2s:red:sys"; + default-state = "on"; + }; + + wan_led: led-2 { + gpios = <&gpio2 RK_PC2 GPIO_ACTIVE_HIGH>; + label = "nanopi-r2s:green:wan"; + }; + }; + + vcc_io_sdio: regulator-sdmmcio { + compatible = "regulator-gpio"; + enable-active-high; + gpios = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&sdio_vcc_pin>; + pinctrl-names = "default"; + regulator-name = "vcc_io_sdio"; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-settling-time-us = <5000>; + regulator-type = "voltage"; + startup-delay-us = <2000>; + states = <1800000 0x1>, + <3300000 0x0>; + vin-supply = <&vcc_io_33>; + }; + + vcc_sd: regulator-sdmmc { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&sdmmc0m1_pin>; + pinctrl-names = "default"; + regulator-name = "vcc_sd"; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_io_33>; + }; + + vdd_5v: regulator-vdd-5v { + compatible = "regulator-fixed"; + regulator-name = "vdd_5v"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vdd_5v_lan: regulator-vdd-5v-lan { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&lan_vdd_pin>; + pinctrl-names = "default"; + regulator-name = "vdd_5v_lan"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vdd_5v>; + }; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&cpu2 { + cpu-supply = <&vdd_arm>; +}; + +&cpu3 { + cpu-supply = <&vdd_arm>; +}; + +&display_subsystem { + status = "disabled"; +}; + +&gmac2io { + assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; + assigned-clock-parents = <&gmac_clk>, <&gmac_clk>; + clock_in_out = "input"; + phy-mode = "rgmii"; + phy-supply = <&vcc_io_33>; + pinctrl-0 = <&rgmiim1_pins>; + pinctrl-names = "default"; + snps,aal; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&i2c1 { + status = "okay"; + + rk805: pmic@18 { + compatible = "rockchip,rk805"; + reg = <0x18>; + interrupt-parent = <&gpio1>; + interrupts = <24 IRQ_TYPE_LEVEL_LOW>; + #clock-cells = <1>; + clock-output-names = "xin32k", "rk805-clkout2"; + gpio-controller; + #gpio-cells = <2>; + pinctrl-0 = <&pmic_int_l>; + pinctrl-names = "default"; + system-power-controller; + wakeup-source; + + vcc1-supply = <&vdd_5v>; + vcc2-supply = <&vdd_5v>; + vcc3-supply = <&vdd_5v>; + vcc4-supply = <&vdd_5v>; + vcc5-supply = <&vcc_io_33>; + vcc6-supply = <&vdd_5v>; + + regulators { + vdd_log: DCDC_REG1 { + regulator-name = "vdd_log"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vdd_arm: DCDC_REG2 { + regulator-name = "vdd_arm"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <950000>; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_io_33: DCDC_REG4 { + regulator-name = "vcc_io_33"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_18: LDO_REG1 { + regulator-name = "vcc_18"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc18_emmc: LDO_REG2 { + regulator-name = "vcc18_emmc"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_10: LDO_REG3 { + regulator-name = "vdd_10"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + }; + }; +}; + +&io_domains { + pmuio-supply = <&vcc_io_33>; + vccio1-supply = <&vcc_io_33>; + vccio2-supply = <&vcc18_emmc>; + vccio3-supply = <&vcc_io_sdio>; + vccio4-supply = <&vcc_18>; + vccio5-supply = <&vcc_io_33>; + vccio6-supply = <&vcc_io_33>; + status = "okay"; +}; + +&pinctrl { + button { + reset_button_pin: reset-button-pin { + rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + gmac2io { + eth_phy_reset_pin: eth-phy-reset-pin { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + leds { + lan_led_pin: lan-led-pin { + rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + sys_led_pin: sys-led-pin { + rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wan_led_pin: wan-led-pin { + rockchip,pins = <2 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + lan { + lan_vdd_pin: lan-vdd-pin { + rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sd { + sdio_vcc_pin: sdio-vcc-pin { + rockchip,pins = <1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm2 { + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-sd-highspeed; + disable-wp; + pinctrl-0 = <&sdmmc0_clk>, <&sdmmc0_cmd>, <&sdmmc0_dectn>, <&sdmmc0_bus4>; + pinctrl-names = "default"; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + vmmc-supply = <&vcc_sd>; + vqmmc-supply = <&vcc_io_sdio>; + status = "okay"; +}; + +&tsadc { + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; + status = "okay"; +}; + +&u2phy { + status = "okay"; +}; + +&u2phy_host { + status = "okay"; +}; + +&u2phy_otg { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb20_otg { + status = "okay"; + dr_mode = "host"; +}; + +&usbdrd3 { + dr_mode = "host"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + /* Second port is for USB 3.0 */ + rtl8153: device@2 { + compatible = "usbbda,8153"; + reg = <2>; + }; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c-plus.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c-plus.dts index 16a1958e457277..3709ba30bbd445 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c-plus.dts @@ -7,7 +7,8 @@ */ /dts-v1/; -#include "rk3328-nanopi-r2c.dts" + +#include "rk3328-nanopi-r2c.dtsi" / { model = "FriendlyElec NanoPi R2C Plus"; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c.dts index a07a26b944a0b3..e8ab773dc245b7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c.dts @@ -7,34 +7,10 @@ */ /dts-v1/; -#include "rk3328-nanopi-r2s.dts" + +#include "rk3328-nanopi-r2c.dtsi" / { model = "FriendlyElec NanoPi R2C"; compatible = "friendlyarm,nanopi-r2c", "rockchip,rk3328"; }; - -&gmac2io { - phy-handle = <&yt8521s>; - tx_delay = <0x22>; - rx_delay = <0x12>; - - mdio { - /delete-node/ ethernet-phy@1; - - yt8521s: ethernet-phy@3 { - compatible = "ethernet-phy-ieee802.3-c22"; - reg = <3>; - - motorcomm,clk-out-frequency-hz = <125000000>; - motorcomm,keep-pll-enabled; - motorcomm,auto-sleep-disabled; - - pinctrl-0 = <ð_phy_reset_pin>; - pinctrl-names = "default"; - reset-assert-us = <10000>; - reset-deassert-us = <50000>; - reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; - }; - }; -}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c.dtsi b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c.dtsi new file mode 100644 index 00000000000000..3b0457de2a9892 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2c.dtsi @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2021 FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyarm.com) + * + * Copyright (c) 2021-2023 Tianling Shen + */ + +/dts-v1/; + +#include "rk3328-nanopi-r2.dtsi" + +&gmac2io { + phy-handle = <&yt8521s>; + tx_delay = <0x22>; + rx_delay = <0x12>; + status = "okay"; + + mdio { + yt8521s: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <3>; + + motorcomm,clk-out-frequency-hz = <125000000>; + motorcomm,keep-pll-enabled; + motorcomm,auto-sleep-disabled; + + pinctrl-0 = <ð_phy_reset_pin>; + pinctrl-names = "default"; + reset-assert-us = <10000>; + reset-deassert-us = <50000>; + reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts index 4b9ced67742d26..f72b1518c14f87 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s-plus.dts @@ -7,7 +7,8 @@ */ /dts-v1/; -#include "rk3328-nanopi-r2s.dts" + +#include "rk3328-nanopi-r2s.dtsi" / { compatible = "friendlyarm,nanopi-r2s-plus", "rockchip,rk3328"; @@ -28,3 +29,20 @@ &emmc { pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; status = "okay"; }; + +&gmac2io { + phy-handle = <&rtl8211e>; + tx_delay = <0x24>; + rx_delay = <0x18>; + + mdio { + rtl8211e: ethernet-phy@1 { + reg = <1>; + pinctrl-0 = <ð_phy_reset_pin>; + pinctrl-names = "default"; + reset-assert-us = <10000>; + reset-deassert-us = <50000>; + reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts index a4399da7d8b1ad..8579f22a194265 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts @@ -5,406 +5,9 @@ /dts-v1/; -#include -#include -#include "rk3328.dtsi" +#include "rk3328-nanopi-r2s.dtsi" / { model = "FriendlyElec NanoPi R2S"; compatible = "friendlyarm,nanopi-r2s", "rockchip,rk3328"; - - aliases { - ethernet0 = &gmac2io; - ethernet1 = &rtl8153; - mmc0 = &sdmmc; - }; - - chosen { - stdout-path = "serial2:1500000n8"; - }; - - gmac_clk: gmac-clock { - compatible = "fixed-clock"; - clock-frequency = <125000000>; - clock-output-names = "gmac_clkin"; - #clock-cells = <0>; - }; - - keys { - compatible = "gpio-keys"; - pinctrl-0 = <&reset_button_pin>; - pinctrl-names = "default"; - - key-reset { - label = "reset"; - gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>; - linux,code = ; - debounce-interval = <50>; - }; - }; - - leds { - compatible = "gpio-leds"; - pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>; - pinctrl-names = "default"; - - lan_led: led-0 { - gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>; - label = "nanopi-r2s:green:lan"; - }; - - sys_led: led-1 { - gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; - label = "nanopi-r2s:red:sys"; - default-state = "on"; - }; - - wan_led: led-2 { - gpios = <&gpio2 RK_PC2 GPIO_ACTIVE_HIGH>; - label = "nanopi-r2s:green:wan"; - }; - }; - - vcc_io_sdio: sdmmcio-regulator { - compatible = "regulator-gpio"; - enable-active-high; - gpios = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>; - pinctrl-0 = <&sdio_vcc_pin>; - pinctrl-names = "default"; - regulator-name = "vcc_io_sdio"; - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-settling-time-us = <5000>; - regulator-type = "voltage"; - startup-delay-us = <2000>; - states = <1800000 0x1>, - <3300000 0x0>; - vin-supply = <&vcc_io_33>; - }; - - vcc_sd: sdmmc-regulator { - compatible = "regulator-fixed"; - gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; - pinctrl-0 = <&sdmmc0m1_pin>; - pinctrl-names = "default"; - regulator-name = "vcc_sd"; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - vin-supply = <&vcc_io_33>; - }; - - vdd_5v: vdd-5v { - compatible = "regulator-fixed"; - regulator-name = "vdd_5v"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - - vdd_5v_lan: vdd-5v-lan { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; - pinctrl-0 = <&lan_vdd_pin>; - pinctrl-names = "default"; - regulator-name = "vdd_5v_lan"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vdd_5v>; - }; -}; - -&cpu0 { - cpu-supply = <&vdd_arm>; -}; - -&cpu1 { - cpu-supply = <&vdd_arm>; -}; - -&cpu2 { - cpu-supply = <&vdd_arm>; -}; - -&cpu3 { - cpu-supply = <&vdd_arm>; -}; - -&display_subsystem { - status = "disabled"; -}; - -&gmac2io { - assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; - assigned-clock-parents = <&gmac_clk>, <&gmac_clk>; - clock_in_out = "input"; - phy-handle = <&rtl8211e>; - phy-mode = "rgmii"; - phy-supply = <&vcc_io_33>; - pinctrl-0 = <&rgmiim1_pins>; - pinctrl-names = "default"; - rx_delay = <0x18>; - snps,aal; - tx_delay = <0x24>; - status = "okay"; - - mdio { - compatible = "snps,dwmac-mdio"; - #address-cells = <1>; - #size-cells = <0>; - - rtl8211e: ethernet-phy@1 { - reg = <1>; - pinctrl-0 = <ð_phy_reset_pin>; - pinctrl-names = "default"; - reset-assert-us = <10000>; - reset-deassert-us = <50000>; - reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; - }; - }; -}; - -&i2c1 { - status = "okay"; - - rk805: pmic@18 { - compatible = "rockchip,rk805"; - reg = <0x18>; - interrupt-parent = <&gpio1>; - interrupts = <24 IRQ_TYPE_LEVEL_LOW>; - #clock-cells = <1>; - clock-output-names = "xin32k", "rk805-clkout2"; - gpio-controller; - #gpio-cells = <2>; - pinctrl-0 = <&pmic_int_l>; - pinctrl-names = "default"; - rockchip,system-power-controller; - wakeup-source; - - vcc1-supply = <&vdd_5v>; - vcc2-supply = <&vdd_5v>; - vcc3-supply = <&vdd_5v>; - vcc4-supply = <&vdd_5v>; - vcc5-supply = <&vcc_io_33>; - vcc6-supply = <&vdd_5v>; - - regulators { - vdd_log: DCDC_REG1 { - regulator-name = "vdd_log"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <712500>; - regulator-max-microvolt = <1450000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vdd_arm: DCDC_REG2 { - regulator-name = "vdd_arm"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <712500>; - regulator-max-microvolt = <1450000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <950000>; - }; - }; - - vcc_ddr: DCDC_REG3 { - regulator-name = "vcc_ddr"; - regulator-always-on; - regulator-boot-on; - - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_io_33: DCDC_REG4 { - regulator-name = "vcc_io_33"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vcc_18: LDO_REG1 { - regulator-name = "vcc_18"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vcc18_emmc: LDO_REG2 { - regulator-name = "vcc18_emmc"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd_10: LDO_REG3 { - regulator-name = "vdd_10"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - }; - }; -}; - -&io_domains { - pmuio-supply = <&vcc_io_33>; - vccio1-supply = <&vcc_io_33>; - vccio2-supply = <&vcc18_emmc>; - vccio3-supply = <&vcc_io_sdio>; - vccio4-supply = <&vcc_18>; - vccio5-supply = <&vcc_io_33>; - vccio6-supply = <&vcc_io_33>; - status = "okay"; -}; - -&pinctrl { - button { - reset_button_pin: reset-button-pin { - rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - gmac2io { - eth_phy_reset_pin: eth-phy-reset-pin { - rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; - - leds { - lan_led_pin: lan-led-pin { - rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - sys_led_pin: sys-led-pin { - rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - wan_led_pin: wan-led-pin { - rockchip,pins = <2 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - lan { - lan_vdd_pin: lan-vdd-pin { - rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - pmic { - pmic_int_l: pmic-int-l { - rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; - - sd { - sdio_vcc_pin: sdio-vcc-pin { - rockchip,pins = <1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; -}; - -&pwm2 { - status = "okay"; -}; - -&sdmmc { - bus-width = <4>; - cap-sd-highspeed; - disable-wp; - pinctrl-0 = <&sdmmc0_clk>, <&sdmmc0_cmd>, <&sdmmc0_dectn>, <&sdmmc0_bus4>; - pinctrl-names = "default"; - sd-uhs-sdr12; - sd-uhs-sdr25; - sd-uhs-sdr50; - sd-uhs-sdr104; - vmmc-supply = <&vcc_sd>; - vqmmc-supply = <&vcc_io_sdio>; - status = "okay"; -}; - -&tsadc { - rockchip,hw-tshut-mode = <0>; - rockchip,hw-tshut-polarity = <0>; - status = "okay"; -}; - -&u2phy { - status = "okay"; -}; - -&u2phy_host { - status = "okay"; -}; - -&u2phy_otg { - status = "okay"; -}; - -&uart2 { - status = "okay"; -}; - -&usb20_otg { - status = "okay"; - dr_mode = "host"; -}; - -&usbdrd3 { - dr_mode = "host"; - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - - /* Second port is for USB 3.0 */ - rtl8153: device@2 { - compatible = "usbbda,8153"; - reg = <2>; - }; -}; - -&usb_host0_ehci { - status = "okay"; -}; - -&usb_host0_ohci { - status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dtsi b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dtsi new file mode 100644 index 00000000000000..308e526c28611c --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dtsi @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * (C) Copyright 2018 FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyarm.com) + * + * (C) Copyright 2016 Rockchip Electronics Co., Ltd + */ + +/dts-v1/; + +#include "rk3328-nanopi-r2.dtsi" + +&gmac2io { + phy-handle = <&rtl8211e>; + tx_delay = <0x24>; + rx_delay = <0x18>; + status = "okay"; + + mdio { + rtl8211e: ethernet-phy@1 { + reg = <1>; + pinctrl-0 = <ð_phy_reset_pin>; + pinctrl-names = "default"; + reset-assert-us = <10000>; + reset-deassert-us = <50000>; + reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts index 4237f2ee8fee33..67c246ad8b8c0d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts @@ -7,7 +7,8 @@ */ /dts-v1/; -#include "rk3328-orangepi-r1-plus.dts" + +#include "rk3328-orangepi-r1-plus.dtsi" / { model = "Xunlong Orange Pi R1 Plus LTS"; @@ -18,10 +19,9 @@ &gmac2io { phy-handle = <&yt8531c>; tx_delay = <0x19>; rx_delay = <0x05>; + status = "okay"; mdio { - /delete-node/ ethernet-phy@1; - yt8531c: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dts b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dts index f20662929c7713..324a8e951f7e49 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dts @@ -6,127 +6,20 @@ /dts-v1/; -#include -#include -#include "rk3328.dtsi" +#include "rk3328-orangepi-r1-plus.dtsi" / { model = "Xunlong Orange Pi R1 Plus"; compatible = "xunlong,orangepi-r1-plus", "rockchip,rk3328"; - - aliases { - ethernet0 = &gmac2io; - ethernet1 = &rtl8153; - mmc0 = &sdmmc; - }; - - chosen { - stdout-path = "serial2:1500000n8"; - }; - - gmac_clk: gmac-clock { - compatible = "fixed-clock"; - clock-frequency = <125000000>; - clock-output-names = "gmac_clkin"; - #clock-cells = <0>; - }; - - leds { - compatible = "gpio-leds"; - pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>; - pinctrl-names = "default"; - - led-0 { - function = LED_FUNCTION_LAN; - color = ; - gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>; - }; - - led-1 { - function = LED_FUNCTION_STATUS; - color = ; - gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "heartbeat"; - }; - - led-2 { - function = LED_FUNCTION_WAN; - color = ; - gpios = <&gpio2 RK_PC2 GPIO_ACTIVE_HIGH>; - }; - }; - - vcc_sd: sdmmc-regulator { - compatible = "regulator-fixed"; - gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; - pinctrl-0 = <&sdmmc0m1_pin>; - pinctrl-names = "default"; - regulator-name = "vcc_sd"; - regulator-boot-on; - vin-supply = <&vcc_io>; - }; - - vcc_sys: vcc-sys-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc_sys"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - - vdd_5v_lan: vdd-5v-lan-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; - pinctrl-0 = <&lan_vdd_pin>; - pinctrl-names = "default"; - regulator-name = "vdd_5v_lan"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vcc_sys>; - }; -}; - -&cpu0 { - cpu-supply = <&vdd_arm>; -}; - -&cpu1 { - cpu-supply = <&vdd_arm>; -}; - -&cpu2 { - cpu-supply = <&vdd_arm>; -}; - -&cpu3 { - cpu-supply = <&vdd_arm>; -}; - -&display_subsystem { - status = "disabled"; }; &gmac2io { - assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; - assigned-clock-parents = <&gmac_clk>, <&gmac_clk>; - clock_in_out = "input"; phy-handle = <&rtl8211e>; - phy-mode = "rgmii"; - phy-supply = <&vcc_io>; - pinctrl-0 = <&rgmiim1_pins>; - pinctrl-names = "default"; - snps,aal; - rx_delay = <0x18>; tx_delay = <0x24>; + rx_delay = <0x18>; status = "okay"; mdio { - compatible = "snps,dwmac-mdio"; - #address-cells = <1>; - #size-cells = <0>; - rtl8211e: ethernet-phy@1 { reg = <1>; pinctrl-0 = <ð_phy_reset_pin>; @@ -137,238 +30,3 @@ rtl8211e: ethernet-phy@1 { }; }; }; - -&i2c1 { - status = "okay"; - - rk805: pmic@18 { - compatible = "rockchip,rk805"; - reg = <0x18>; - interrupt-parent = <&gpio1>; - interrupts = <24 IRQ_TYPE_LEVEL_LOW>; - #clock-cells = <1>; - clock-output-names = "xin32k", "rk805-clkout2"; - gpio-controller; - #gpio-cells = <2>; - pinctrl-0 = <&pmic_int_l>; - pinctrl-names = "default"; - rockchip,system-power-controller; - wakeup-source; - - vcc1-supply = <&vcc_sys>; - vcc2-supply = <&vcc_sys>; - vcc3-supply = <&vcc_sys>; - vcc4-supply = <&vcc_sys>; - vcc5-supply = <&vcc_io>; - vcc6-supply = <&vcc_sys>; - - regulators { - vdd_log: DCDC_REG1 { - regulator-name = "vdd_log"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <712500>; - regulator-max-microvolt = <1450000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vdd_arm: DCDC_REG2 { - regulator-name = "vdd_arm"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <712500>; - regulator-max-microvolt = <1450000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <950000>; - }; - }; - - vcc_ddr: DCDC_REG3 { - regulator-name = "vcc_ddr"; - regulator-always-on; - regulator-boot-on; - - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_io: DCDC_REG4 { - regulator-name = "vcc_io"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vcc_18: LDO_REG1 { - regulator-name = "vcc_18"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vcc18_emmc: LDO_REG2 { - regulator-name = "vcc18_emmc"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd_10: LDO_REG3 { - regulator-name = "vdd_10"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - }; - }; -}; - -&io_domains { - pmuio-supply = <&vcc_io>; - vccio1-supply = <&vcc_io>; - vccio2-supply = <&vcc18_emmc>; - vccio3-supply = <&vcc_io>; - vccio4-supply = <&vcc_io>; - vccio5-supply = <&vcc_io>; - vccio6-supply = <&vcc_io>; - status = "okay"; -}; - -&pinctrl { - gmac2io { - eth_phy_reset_pin: eth-phy-reset-pin { - rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; - }; - }; - - leds { - lan_led_pin: lan-led-pin { - rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - sys_led_pin: sys-led-pin { - rockchip,pins = <3 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - wan_led_pin: wan-led-pin { - rockchip,pins = <2 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - lan { - lan_vdd_pin: lan-vdd-pin { - rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - pmic { - pmic_int_l: pmic-int-l { - rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; -}; - -&pwm2 { - status = "okay"; -}; - -&sdmmc { - bus-width = <4>; - cap-sd-highspeed; - disable-wp; - pinctrl-0 = <&sdmmc0_clk>, <&sdmmc0_cmd>, <&sdmmc0_dectn>, <&sdmmc0_bus4>; - pinctrl-names = "default"; - vmmc-supply = <&vcc_sd>; - status = "okay"; -}; - -&spi0 { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - }; -}; - -&tsadc { - rockchip,hw-tshut-mode = <0>; - rockchip,hw-tshut-polarity = <0>; - status = "okay"; -}; - -&u2phy { - status = "okay"; -}; - -&u2phy_host { - status = "okay"; -}; - -&u2phy_otg { - status = "okay"; -}; - -&uart2 { - status = "okay"; -}; - -&usb20_otg { - dr_mode = "host"; - status = "okay"; -}; - -&usbdrd3 { - dr_mode = "host"; - status = "okay"; - #address-cells = <1>; - #size-cells = <0>; - - /* Second port is for USB 3.0 */ - rtl8153: device@2 { - compatible = "usbbda,8153"; - reg = <2>; - }; -}; - -&usb_host0_ehci { - status = "okay"; -}; - -&usb_host0_ohci { - status = "okay"; -}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dtsi b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dtsi new file mode 100644 index 00000000000000..82021ffb0a49c2 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dtsi @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Based on rk3328-nanopi-r2s.dts, which is: + * Copyright (c) 2020 David Bauer + */ + +/dts-v1/; + +#include +#include +#include "rk3328.dtsi" + +/ { + aliases { + ethernet0 = &gmac2io; + ethernet1 = &rtl8153; + mmc0 = &sdmmc; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + gmac_clk: gmac-clock { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "gmac_clkin"; + #clock-cells = <0>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>; + pinctrl-names = "default"; + + led-0 { + function = LED_FUNCTION_LAN; + color = ; + gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>; + }; + + led-1 { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + led-2 { + function = LED_FUNCTION_WAN; + color = ; + gpios = <&gpio2 RK_PC2 GPIO_ACTIVE_HIGH>; + }; + }; + + vcc_sd: regulator-sdmmc { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&sdmmc0m1_pin>; + pinctrl-names = "default"; + regulator-name = "vcc_sd"; + regulator-boot-on; + vin-supply = <&vcc_io>; + }; + + vcc_sys: regulator-vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vdd_5v_lan: regulator-vdd-5v-lan { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&lan_vdd_pin>; + pinctrl-names = "default"; + regulator-name = "vdd_5v_lan"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc_sys>; + }; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&cpu2 { + cpu-supply = <&vdd_arm>; +}; + +&cpu3 { + cpu-supply = <&vdd_arm>; +}; + +&display_subsystem { + status = "disabled"; +}; + +&gmac2io { + assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; + assigned-clock-parents = <&gmac_clk>, <&gmac_clk>; + clock_in_out = "input"; + phy-mode = "rgmii"; + phy-supply = <&vcc_io>; + pinctrl-0 = <&rgmiim1_pins>; + pinctrl-names = "default"; + snps,aal; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; +}; + +&i2c1 { + status = "okay"; + + rk805: pmic@18 { + compatible = "rockchip,rk805"; + reg = <0x18>; + interrupt-parent = <&gpio1>; + interrupts = <24 IRQ_TYPE_LEVEL_LOW>; + #clock-cells = <1>; + clock-output-names = "xin32k", "rk805-clkout2"; + gpio-controller; + #gpio-cells = <2>; + pinctrl-0 = <&pmic_int_l>; + pinctrl-names = "default"; + system-power-controller; + wakeup-source; + + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_io>; + vcc6-supply = <&vcc_sys>; + + regulators { + vdd_log: DCDC_REG1 { + regulator-name = "vdd_log"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vdd_arm: DCDC_REG2 { + regulator-name = "vdd_arm"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <950000>; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_io: DCDC_REG4 { + regulator-name = "vcc_io"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_18: LDO_REG1 { + regulator-name = "vcc_18"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc18_emmc: LDO_REG2 { + regulator-name = "vcc18_emmc"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_10: LDO_REG3 { + regulator-name = "vdd_10"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + }; + }; +}; + +&io_domains { + pmuio-supply = <&vcc_io>; + vccio1-supply = <&vcc_io>; + vccio2-supply = <&vcc18_emmc>; + vccio3-supply = <&vcc_io>; + vccio4-supply = <&vcc_io>; + vccio5-supply = <&vcc_io>; + vccio6-supply = <&vcc_io>; + status = "okay"; +}; + +&pinctrl { + gmac2io { + eth_phy_reset_pin: eth-phy-reset-pin { + rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + leds { + lan_led_pin: lan-led-pin { + rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + sys_led_pin: sys-led-pin { + rockchip,pins = <3 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wan_led_pin: wan-led-pin { + rockchip,pins = <2 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + lan { + lan_vdd_pin: lan-vdd-pin { + rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm2 { + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-sd-highspeed; + disable-wp; + pinctrl-0 = <&sdmmc0_clk>, <&sdmmc0_cmd>, <&sdmmc0_dectn>, <&sdmmc0_bus4>; + pinctrl-names = "default"; + vmmc-supply = <&vcc_sd>; + status = "okay"; +}; + +&spi0 { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + }; +}; + +&tsadc { + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; + status = "okay"; +}; + +&u2phy { + status = "okay"; +}; + +&u2phy_host { + status = "okay"; +}; + +&u2phy_otg { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb20_otg { + dr_mode = "host"; + status = "okay"; +}; + +&usbdrd3 { + dr_mode = "host"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + /* Second port is for USB 3.0 */ + rtl8153: device@2 { + compatible = "usbbda,8153"; + reg = <2>; + }; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts index 414897a57e7570..1ea4b2a95a0962 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts @@ -4,381 +4,24 @@ */ /dts-v1/; -#include "rk3328.dtsi" + +#include +#include "rk3328-roc.dtsi" / { - model = "Firefly roc-rk3328-cc"; + model = "Firefly ROC-RK3328-CC"; compatible = "firefly,roc-rk3328-cc", "rockchip,rk3328"; - - aliases { - ethernet0 = &gmac2io; - mmc0 = &sdmmc; - mmc1 = &emmc; - }; - - chosen { - stdout-path = "serial2:1500000n8"; - }; - - gmac_clkin: external-gmac-clock { - compatible = "fixed-clock"; - clock-frequency = <125000000>; - clock-output-names = "gmac_clkin"; - #clock-cells = <0>; - }; - - dc_12v: dc-12v { - compatible = "regulator-fixed"; - regulator-name = "dc_12v"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <12000000>; - regulator-max-microvolt = <12000000>; - }; - - vcc_sd: sdmmc-regulator { - compatible = "regulator-fixed"; - gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc0m1_pin>; - regulator-boot-on; - regulator-name = "vcc_sd"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - vin-supply = <&vcc_io>; - }; - - vcc_sdio: sdmmcio-regulator { - compatible = "regulator-gpio"; - gpios = <&grf_gpio 0 GPIO_ACTIVE_HIGH>; - states = <1800000 0x1>, - <3300000 0x0>; - regulator-name = "vcc_sdio"; - regulator-type = "voltage"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - vin-supply = <&vcc_sys>; - }; - - vcc_host1_5v: vcc_otg_5v: vcc-host1-5v-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&usb20_host_drv>; - regulator-name = "vcc_host1_5v"; - regulator-always-on; - vin-supply = <&vcc_sys>; - }; - - vcc_sys: vcc-sys { - compatible = "regulator-fixed"; - regulator-name = "vcc_sys"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - vin-supply = <&dc_12v>; - }; - - vcc_phy: vcc-phy-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc_phy"; - regulator-always-on; - regulator-boot-on; - }; - - leds { - compatible = "gpio-leds"; - - power_led: led-0 { - label = "firefly:blue:power"; - linux,default-trigger = "heartbeat"; - gpios = <&rk805 1 GPIO_ACTIVE_LOW>; - default-state = "on"; - }; - - user_led: led-1 { - label = "firefly:yellow:user"; - linux,default-trigger = "mmc1"; - gpios = <&rk805 0 GPIO_ACTIVE_LOW>; - default-state = "off"; - }; - }; -}; - -&analog_sound { - status = "okay"; -}; - -&codec { - status = "okay"; -}; - -&cpu0 { - cpu-supply = <&vdd_arm>; -}; - -&cpu1 { - cpu-supply = <&vdd_arm>; -}; - -&cpu2 { - cpu-supply = <&vdd_arm>; -}; - -&cpu3 { - cpu-supply = <&vdd_arm>; -}; - -&emmc { - bus-width = <8>; - cap-mmc-highspeed; - max-frequency = <150000000>; - mmc-ddr-1_8v; - mmc-hs200-1_8v; - non-removable; - pinctrl-names = "default"; - pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; - vmmc-supply = <&vcc_io>; - vqmmc-supply = <&vcc18_emmc>; - status = "okay"; -}; - -&gmac2io { - assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; - assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>; - clock_in_out = "input"; - phy-supply = <&vcc_phy>; - phy-mode = "rgmii"; - pinctrl-names = "default"; - pinctrl-0 = <&rgmiim1_pins>; - snps,aal; - snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; - snps,reset-active-low; - snps,reset-delays-us = <0 10000 50000>; - snps,rxpbl = <0x4>; - snps,txpbl = <0x4>; - tx_delay = <0x24>; - rx_delay = <0x18>; - status = "okay"; -}; - -&hdmi { - status = "okay"; -}; - -&hdmiphy { - status = "okay"; -}; - -&hdmi_sound { - status = "okay"; -}; - -&i2c1 { - status = "okay"; - - rk805: pmic@18 { - compatible = "rockchip,rk805"; - reg = <0x18>; - interrupt-parent = <&gpio1>; - interrupts = <24 IRQ_TYPE_LEVEL_LOW>; - #clock-cells = <1>; - clock-output-names = "xin32k", "rk805-clkout2"; - gpio-controller; - #gpio-cells = <2>; - pinctrl-names = "default"; - pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; - wakeup-source; - - vcc1-supply = <&vcc_sys>; - vcc2-supply = <&vcc_sys>; - vcc3-supply = <&vcc_sys>; - vcc4-supply = <&vcc_sys>; - vcc5-supply = <&vcc_io>; - vcc6-supply = <&vcc_io>; - - regulators { - vdd_logic: DCDC_REG1 { - regulator-name = "vdd_logic"; - regulator-min-microvolt = <712500>; - regulator-max-microvolt = <1450000>; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - - vdd_arm: DCDC_REG2 { - regulator-name = "vdd_arm"; - regulator-min-microvolt = <712500>; - regulator-max-microvolt = <1450000>; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <950000>; - }; - }; - - vcc_ddr: DCDC_REG3 { - regulator-name = "vcc_ddr"; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_io: DCDC_REG4 { - regulator-name = "vcc_io"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vcc_18: LDO_REG1 { - regulator-name = "vcc_18"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vcc18_emmc: LDO_REG2 { - regulator-name = "vcc18_emmc"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd_10: LDO_REG3 { - regulator-name = "vdd_10"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; - regulator-always-on; - regulator-boot-on; - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1000000>; - }; - }; - }; - }; -}; - -&i2s0 { - status = "okay"; -}; - -&i2s1 { - status = "okay"; -}; - -&io_domains { - status = "okay"; - - vccio1-supply = <&vcc_io>; - vccio2-supply = <&vcc18_emmc>; - vccio3-supply = <&vcc_sdio>; - vccio4-supply = <&vcc_18>; - vccio5-supply = <&vcc_io>; - vccio6-supply = <&vcc_io>; - pmuio-supply = <&vcc_io>; -}; - -&pinctrl { - pmic { - pmic_int_l: pmic-int-l { - rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; - - usb2 { - usb20_host_drv: usb20-host-drv { - rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; -}; - -&sdmmc { - bus-width = <4>; - cap-mmc-highspeed; - cap-sd-highspeed; - disable-wp; - max-frequency = <150000000>; - pinctrl-names = "default"; - pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>; - sd-uhs-sdr12; - sd-uhs-sdr25; - sd-uhs-sdr50; - sd-uhs-sdr104; - vmmc-supply = <&vcc_sd>; - vqmmc-supply = <&vcc_sdio>; - status = "okay"; -}; - -&tsadc { - status = "okay"; -}; - -&u2phy { - status = "okay"; -}; - -&u2phy_host { - status = "okay"; -}; - -&u2phy_otg { - status = "okay"; -}; - -&uart2 { - status = "okay"; -}; - -&usb20_otg { - dr_mode = "host"; - status = "okay"; -}; - -&usbdrd3 { - dr_mode = "host"; - status = "okay"; -}; - -&usb_host0_ehci { - status = "okay"; }; -&usb_host0_ohci { - status = "okay"; +&rk805 { + interrupt-parent = <&gpio1>; + interrupts = <24 IRQ_TYPE_LEVEL_LOW>; }; -&vop { - status = "okay"; +&vcc_host1_5v { + gpio = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; }; -&vop_mmu { - status = "okay"; +&vcc_sdio { + gpios = <&grf_gpio 0 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-pc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-pc.dts index e3e3984d01d406..329d03172433e6 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-roc-pc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-pc.dts @@ -4,8 +4,7 @@ /dts-v1/; #include - -#include "rk3328-roc-cc.dts" +#include "rk3328-roc.dtsi" / { model = "Firefly ROC-RK3328-PC"; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi b/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi new file mode 100644 index 00000000000000..b5bd5e7d574857 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3328-roc.dtsi @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2017 T-Chip Intelligent Technology Co., Ltd + */ + +/dts-v1/; + +#include "rk3328.dtsi" + +/ { + aliases { + ethernet0 = &gmac2io; + mmc0 = &sdmmc; + mmc1 = &emmc; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + gmac_clkin: external-gmac-clock { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "gmac_clkin"; + #clock-cells = <0>; + }; + + dc_12v: regulator-dc-12v { + compatible = "regulator-fixed"; + regulator-name = "dc_12v"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc_sd: regulator-sdmmc { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc0m1_pin>; + regulator-boot-on; + regulator-name = "vcc_sd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_io>; + }; + + vcc_sdio: regulator-sdmmcio { + compatible = "regulator-gpio"; + states = <1800000 0x1>, <3300000 0x0>; + regulator-name = "vcc_sdio"; + regulator-type = "voltage"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + vin-supply = <&vcc_sys>; + }; + + vcc_host1_5v: vcc_otg_5v: regulator-vcc-host1-5v { + compatible = "regulator-fixed"; + enable-active-high; + pinctrl-names = "default"; + pinctrl-0 = <&usb20_host_drv>; + regulator-name = "vcc_host1_5v"; + regulator-always-on; + vin-supply = <&vcc_sys>; + }; + + vcc_sys: regulator-vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_12v>; + }; + + vcc_phy: regulator-vcc-phy { + compatible = "regulator-fixed"; + regulator-name = "vcc_phy"; + regulator-always-on; + regulator-boot-on; + }; + + leds { + compatible = "gpio-leds"; + + power_led: led-0 { + label = "firefly:blue:power"; + linux,default-trigger = "heartbeat"; + gpios = <&rk805 1 GPIO_ACTIVE_LOW>; + default-state = "on"; + }; + + user_led: led-1 { + label = "firefly:yellow:user"; + linux,default-trigger = "mmc1"; + gpios = <&rk805 0 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + }; +}; + +&analog_sound { + status = "okay"; +}; + +&codec { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&cpu2 { + cpu-supply = <&vdd_arm>; +}; + +&cpu3 { + cpu-supply = <&vdd_arm>; +}; + +&emmc { + bus-width = <8>; + cap-mmc-highspeed; + max-frequency = <150000000>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; + vmmc-supply = <&vcc_io>; + vqmmc-supply = <&vcc18_emmc>; + status = "okay"; +}; + +&gmac2io { + assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>; + assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>; + clock_in_out = "input"; + phy-supply = <&vcc_phy>; + phy-mode = "rgmii"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmiim1_pins>; + snps,aal; + snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 50000>; + snps,rxpbl = <0x4>; + snps,txpbl = <0x4>; + tx_delay = <0x24>; + rx_delay = <0x18>; + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&hdmiphy { + status = "okay"; +}; + +&hdmi_sound { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + rk805: pmic@18 { + compatible = "rockchip,rk805"; + reg = <0x18>; + #clock-cells = <1>; + clock-output-names = "xin32k", "rk805-clkout2"; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>; + system-power-controller; + wakeup-source; + + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_io>; + vcc6-supply = <&vcc_io>; + + regulators { + vdd_logic: DCDC_REG1 { + regulator-name = "vdd_logic"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vdd_arm: DCDC_REG2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <950000>; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_io: DCDC_REG4 { + regulator-name = "vcc_io"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_18: LDO_REG1 { + regulator-name = "vcc_18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc18_emmc: LDO_REG2 { + regulator-name = "vcc18_emmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_10: LDO_REG3 { + regulator-name = "vdd_10"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + }; + }; +}; + +&i2s0 { + status = "okay"; +}; + +&i2s1 { + status = "okay"; +}; + +&io_domains { + status = "okay"; + + vccio1-supply = <&vcc_io>; + vccio2-supply = <&vcc18_emmc>; + vccio3-supply = <&vcc_sdio>; + vccio4-supply = <&vcc_18>; + vccio5-supply = <&vcc_io>; + vccio6-supply = <&vcc_io>; + pmuio-supply = <&vcc_io>; +}; + +&pinctrl { + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + usb2 { + usb20_host_drv: usb20-host-drv { + rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + vmmc-supply = <&vcc_sd>; + vqmmc-supply = <&vcc_sdio>; + status = "okay"; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy { + status = "okay"; +}; + +&u2phy_host { + status = "okay"; +}; + +&u2phy_otg { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb20_otg { + dr_mode = "host"; + status = "okay"; +}; + +&usbdrd3 { + dr_mode = "host"; + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts index 3e08e2fd0a7828..425de197ddb8aa 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts @@ -64,7 +64,7 @@ led-0 { }; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -74,7 +74,7 @@ vcc_sd: sdmmc-regulator { vin-supply = <&vcc_io>; }; - vcc_host_5v: vcc-host-5v-regulator { + vcc_host_5v: regulator-vcc-host-5v { compatible = "regulator-fixed"; gpio = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -86,7 +86,7 @@ vcc_host_5v: vcc-host-5v-regulator { vin-supply = <&vcc_sys>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -95,7 +95,7 @@ vcc_sys: vcc-sys { regulator-max-microvolt = <5000000>; }; - vcc_wifi: vcc-wifi-regulator { + vcc_wifi: regulator-vcc-wifi { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -249,7 +249,7 @@ rk805: pmic@18 { #gpio-cells = <2>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts index 90fef766f3ae14..745d3e99641850 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts @@ -27,7 +27,7 @@ gmac_clkin: external-gmac-clock { #clock-cells = <0>; }; - vcc_sd: sdmmc-regulator { + vcc_sd: regulator-sdmmc { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -39,7 +39,7 @@ vcc_sd: sdmmc-regulator { }; /* Common enable line for all of the rails mentioned in the labels */ - vcc_host_5v: vcc_host1_5v: vcc_otg_5v: vcc-host-5v-regulator { + vcc_host_5v: vcc_host1_5v: vcc_otg_5v: regulator-vcc-host-5v { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -50,7 +50,7 @@ vcc_host_5v: vcc_host1_5v: vcc_otg_5v: vcc-host-5v-regulator { vin-supply = <&vcc_sys>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -181,7 +181,7 @@ rk805: pmic@18 { #gpio-cells = <2>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index c01a4cad48f30e..0597de415fe06f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -812,8 +812,10 @@ hdmiphy: phy@ff430000 { }; cru: clock-controller@ff440000 { - compatible = "rockchip,rk3328-cru", "rockchip,cru", "syscon"; + compatible = "rockchip,rk3328-cru"; reg = <0x0 0xff440000 0x0 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; rockchip,grf = <&grf>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi index e5c0dbf794ae7e..8662494a44d5e4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi @@ -85,7 +85,7 @@ key-power { }; /* supplies both host and otg */ - vcc_host: vcc-host-regulator { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>; @@ -97,7 +97,7 @@ vcc_host: vcc-host-regulator { vin-supply = <&vcc_sys>; }; - vcc_lan: vcc-lan-regulator { + vcc_lan: regulator-vcc-lan { compatible = "regulator-fixed"; regulator-name = "vcc_lan"; regulator-min-microvolt = <3300000>; @@ -107,7 +107,7 @@ vcc_lan: vcc-lan-regulator { vin-supply = <&vcc_io>; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts index 029b8e22e709ff..445ec20d6df863 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts @@ -68,7 +68,7 @@ red_led: led-1 { }; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -113,7 +113,7 @@ rk808: pmic@1b { pinctrl-0 = <&pmic_int>, <&pmic_sleep>; interrupt-parent = <&gpio0>; interrupts = ; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc_sys>; vcc2-supply = <&vcc_sys>; vcc3-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts b/arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts index e0cc4da7f392da..b99bb0a5f9006b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-lba3368.dts @@ -47,7 +47,7 @@ button-recovery { analog-sound { compatible = "audio-graph-card"; dais = <&i2s_8ch_p0>; - hp-det-gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; + hp-det-gpios = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; label = "alc5640"; routing = "Mic Jack", "MICBIAS1", "IN1P", "Mic Jack", @@ -64,7 +64,7 @@ analog-sound { pinctrl-0 = <&hp_det>; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-min-microvolt = <12000000>; @@ -80,7 +80,7 @@ ext_gmac: gmac-clk { #clock-cells = <0>; }; - hub_avdd: hub-avdd-regulator { + hub_avdd: regulator-hub-avdd { compatible = "regulator-fixed"; regulator-name = "hub_avdd"; regulator-min-microvolt = <3300000>; @@ -111,7 +111,7 @@ sdio_pwrseq: sdio-pwrseq { pinctrl-0 = <&wifi_reg_on>; }; - vcc_host: vcc-host-regulator { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; gpio = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>; regulator-name = "vcc_host"; @@ -124,7 +124,7 @@ vcc_host: vcc-host-regulator { regulator-always-on; }; - vcc_lan: vcc-lan-regulator { + vcc_lan: regulator-vcc-lan { compatible = "regulator-fixed"; regulator-name = "vcc_lan"; regulator-min-microvolt = <3300000>; @@ -133,7 +133,7 @@ vcc_lan: vcc-lan-regulator { regulator-always-on; }; - vcc_otg: vcc-otg-regulator { + vcc_otg: regulator-vcc-otg { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; regulator-name = "vcc_otg"; @@ -146,7 +146,7 @@ vcc_otg: vcc-otg-regulator { regulator-always-on; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -156,7 +156,7 @@ vcc_sys: vcc-sys-regulator { regulator-boot-on; }; - vdd10_usb: vdd10-usb-regulator { + vdd10_usb: regulator-vdd10-usb { compatible = "regulator-fixed"; regulator-name = "vdd10_usb"; regulator-min-microvolt = <1000000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts index cae01d35b93d91..ab70ee5f561a29 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-lion-haikou.dts @@ -38,7 +38,7 @@ sd_card_led: led-3 { }; }; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -47,7 +47,7 @@ dc_12v: dc-12v { regulator-max-microvolt = <12000000>; }; - vcc3v3_baseboard: vcc3v3-baseboard { + vcc3v3_baseboard: regulator-vcc3v3-baseboard { compatible = "regulator-fixed"; regulator-name = "vcc3v3_baseboard"; regulator-always-on; @@ -57,7 +57,7 @@ vcc3v3_baseboard: vcc3v3-baseboard { vin-supply = <&dc_12v>; }; - vcc5v0_otg: vcc5v0-otg-regulator { + vcc5v0_otg: regulator-vcc5v0-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PD4 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi index ab3fda69a1fb7b..8ccc3184a83628 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi @@ -96,7 +96,7 @@ module_led2: led-2 { }; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -178,7 +178,7 @@ rk808: pmic@1b { #clock-cells = <1>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>, <&pmic_sleep>; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc_sys>; vcc2-supply = <&vcc_sys>; vcc3-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts index 23ae2d9de38226..abef858e7cea5d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts @@ -73,7 +73,7 @@ blue_led: led-1 { }; }; - vcc_18: vcc18-regulator { + vcc_18: regulator-vcc18 { compatible = "regulator-fixed"; regulator-name = "vcc_18"; regulator-min-microvolt = <1800000>; @@ -84,7 +84,7 @@ vcc_18: vcc18-regulator { }; /* supplies both host and otg */ - vcc_host: vcc-host-regulator { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -95,7 +95,7 @@ vcc_host: vcc-host-regulator { vin-supply = <&vcc_sys>; }; - vcc_io: vcc-io-regulator { + vcc_io: regulator-vcc-io { compatible = "regulator-fixed"; regulator-name = "vcc_io"; regulator-min-microvolt = <3300000>; @@ -105,7 +105,7 @@ vcc_io: vcc-io-regulator { vin-supply = <&vcc_sys>; }; - vcc_lan: vcc-lan-regulator { + vcc_lan: regulator-vcc-lan { compatible = "regulator-fixed"; regulator-name = "vcc_lan"; regulator-min-microvolt = <3300000>; @@ -115,7 +115,7 @@ vcc_lan: vcc-lan-regulator { vin-supply = <&vcc_io>; }; - vcc_sd: vcc-sd-regulator { + vcc_sd: regulator-vcc-sd { compatible = "regulator-fixed"; regulator-name = "vcc_sd"; gpio = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>; @@ -124,7 +124,7 @@ vcc_sd: vcc-sd-regulator { vin-supply = <&vcc_io>; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -133,7 +133,7 @@ vcc_sys: vcc-sys-regulator { regulator-boot-on; }; - vccio_sd: vcc-io-sd-regulator { + vccio_sd: regulator-vcc-io-sd { compatible = "regulator-fixed"; regulator-name = "vccio_sd"; regulator-min-microvolt = <1800000>; @@ -143,7 +143,7 @@ vccio_sd: vcc-io-sd-regulator { vin-supply = <&vcc_io>; }; - vccio_wl: vccio-wl-regulator { + vccio_wl: regulator-vccio-wl { compatible = "regulator-fixed"; regulator-name = "vccio_wl"; regulator-min-microvolt = <3300000>; @@ -153,7 +153,7 @@ vccio_wl: vccio-wl-regulator { vin-supply = <&vcc_io>; }; - vdd_10: vdd-10-regulator { + vdd_10: regulator-vdd-10 { compatible = "regulator-fixed"; regulator-name = "vdd_10"; regulator-min-microvolt = <1000000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts b/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts index 29df84b81552ea..5132ffe014ff53 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-px5-evb.dts @@ -38,7 +38,7 @@ key-power { }; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -73,7 +73,7 @@ rk808: pmic@1b { interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>, <&pmic_sleep>; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc_sys>; vcc2-supply = <&vcc_sys>; vcc3-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts index 7f14206d53c396..b73100c6d1822e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts @@ -79,7 +79,7 @@ sdio_pwrseq: sdio-pwrseq { <&gpio3 RK_PA4 GPIO_ACTIVE_LOW>; }; - vcc_18: vcc18-regulator { + vcc_18: regulator-vcc18 { compatible = "regulator-fixed"; regulator-name = "vcc_18"; regulator-min-microvolt = <1800000>; @@ -90,7 +90,7 @@ vcc_18: vcc18-regulator { }; /* supplies both host and otg */ - vcc_host: vcc-host-regulator { + vcc_host: regulator-vcc-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA4 GPIO_ACTIVE_HIGH>; @@ -102,7 +102,7 @@ vcc_host: vcc-host-regulator { vin-supply = <&vcc_sys>; }; - vcc_io: vcc-io-regulator { + vcc_io: regulator-vcc-io { compatible = "regulator-fixed"; regulator-name = "vcc_io"; regulator-min-microvolt = <3300000>; @@ -112,7 +112,7 @@ vcc_io: vcc-io-regulator { vin-supply = <&vcc_sys>; }; - vcc_lan: vcc-lan-regulator { + vcc_lan: regulator-vcc-lan { compatible = "regulator-fixed"; regulator-name = "vcc_lan"; regulator-min-microvolt = <3300000>; @@ -122,7 +122,7 @@ vcc_lan: vcc-lan-regulator { vin-supply = <&vcc_io>; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -131,7 +131,7 @@ vcc_sys: vcc-sys-regulator { regulator-boot-on; }; - vccio_wl: vccio-wl-regulator { + vccio_wl: regulator-vccio-wl { compatible = "regulator-fixed"; regulator-name = "vccio_wl"; regulator-min-microvolt = <3300000>; @@ -141,7 +141,7 @@ vccio_wl: vccio-wl-regulator { vin-supply = <&vcc_io>; }; - vdd_10: vdd-10-regulator { + vdd_10: regulator-vdd-10 { compatible = "regulator-fixed"; regulator-name = "vdd_10"; regulator-min-microvolt = <1000000>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts b/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts index 4feb78797982ba..b90bf26b58be73 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts @@ -66,7 +66,7 @@ clkin_gmac: external-gmac-clock { #clock-cells = <0>; }; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -168,7 +168,7 @@ sdio_pwrseq: sdio-pwrseq { }; /* switched by pmic_sleep */ - vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { + vcc1v8_s3: vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s3"; regulator-always-on; @@ -178,7 +178,7 @@ vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { vin-supply = <&vcc_1v8>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -188,7 +188,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&dc_12v>; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -199,7 +199,7 @@ vcc5v0_sys: vcc5v0-sys { }; /* For USB3.0 Port1/2 */ - vcc5v0_host1: vcc5v0-host1-regulator { + vcc5v0_host1: regulator-vcc5v0-host1 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -211,7 +211,7 @@ vcc5v0_host1: vcc5v0-host1-regulator { }; /* For USB2.0 Port1/2 */ - vcc5v0_host3: vcc5v0-host3-regulator { + vcc5v0_host3: regulator-vcc5v0-host3 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; @@ -222,7 +222,7 @@ vcc5v0_host3: vcc5v0-host3-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_typec: vcc5v0-typec-regulator { + vcc5v0_typec: regulator-vcc5v0-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -233,7 +233,7 @@ vcc5v0_typec: vcc5v0-typec-regulator { vin-supply = <&vcc3v3_sys>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "regulator-fixed"; regulator-name = "vdd_log"; regulator-always-on; @@ -309,7 +309,7 @@ rk808: pmic@1b { interrupts = <21 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <1>; clock-output-names = "xin32k", "rk808-clkout2"; @@ -545,7 +545,7 @@ rt5651: audio-codec@1a { reg = <0x1a>; clocks = <&cru SCLK_I2S_8CH_OUT>; clock-names = "mclk"; - hp-det-gpio = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>; + hp-det-gpios = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>; spk-con-gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; #sound-dai-cells = <0>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index 54e67d2dac092d..9ea91f90c67a12 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts @@ -75,7 +75,7 @@ clkin_gmac: external-gmac-clock { #clock-cells = <0>; }; - vdd_center: vdd-center { + vdd_center: regulator-vdd-center { compatible = "pwm-regulator"; pwms = <&pwm3 0 25000 0>; regulator-name = "vdd_center"; @@ -86,7 +86,7 @@ vdd_center: vdd-center { status = "okay"; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -95,7 +95,7 @@ vcc3v3_sys: vcc3v3-sys { regulator-max-microvolt = <3300000>; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -104,7 +104,7 @@ vcc5v0_sys: vcc5v0-sys { regulator-max-microvolt = <5000000>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>; @@ -114,14 +114,14 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc_phy: vcc-phy-regulator { + vcc_phy: regulator-vcc-phy { compatible = "regulator-fixed"; regulator-name = "vcc_phy"; regulator-always-on; regulator-boot-on; }; - vcc_phy: vcc-phy-regulator { + vcc_phy: regulator-vcc-phy { compatible = "regulator-fixed"; regulator-name = "vcc_phy"; regulator-always-on; @@ -178,7 +178,7 @@ rk808: pmic@1b { interrupts = <21 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <1>; clock-output-names = "rk808-clkout1", "rk808-clkout2"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts index f4491317a1b032..0568dfa140b329 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts @@ -72,7 +72,7 @@ clkin_gmac: external-gmac-clock { #clock-cells = <0>; }; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -178,7 +178,7 @@ dit_p0_0: endpoint { }; /* switched by pmic_sleep */ - vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { + vcc1v8_s3: vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s3"; regulator-always-on; @@ -188,7 +188,7 @@ vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { vin-supply = <&vcc_1v8>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>; @@ -200,7 +200,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&dc_12v>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -211,7 +211,7 @@ vcc3v3_sys: vcc3v3-sys { }; /* Actually 3 regulators (host0, 1, 2) controlled by the same gpio */ - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; @@ -222,7 +222,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc_sys>; }; - vcc5v0_typec: vcc5v0-typec-regulator { + vcc5v0_typec: regulator-vcc5v0-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -233,7 +233,7 @@ vcc5v0_typec: vcc5v0-typec-regulator { vin-supply = <&vcc_sys>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -243,7 +243,7 @@ vcc_sys: vcc-sys { vin-supply = <&dc_12v>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc_sys>; @@ -326,7 +326,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi index cacbad35cfc854..988e6ca32fac94 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi @@ -8,7 +8,7 @@ #include "rk3399-gru.dtsi" / { - pp900_ap: pp900-ap { + pp900_ap: regulator-pp900-ap { compatible = "regulator-fixed"; regulator-name = "pp900_ap"; @@ -29,7 +29,7 @@ pp900_usb: pp900-ap { pp900_pcie: pp900-ap { }; - pp3000: pp3000 { + pp3000: regulator-pp3000 { compatible = "regulator-fixed"; regulator-name = "pp3000"; pinctrl-names = "default"; @@ -46,7 +46,7 @@ pp3000: pp3000 { vin-supply = <&ppvar_sys>; }; - ppvar_centerlogic_pwm: ppvar-centerlogic-pwm { + ppvar_centerlogic_pwm: regulator-ppvar-centerlogic-pwm { compatible = "pwm-regulator"; regulator-name = "ppvar_centerlogic_pwm"; @@ -78,7 +78,7 @@ ppvar_centerlogic: ppvar-centerlogic { }; /* Schematics call this PPVAR even though it's fixed */ - ppvar_logic: ppvar-logic { + ppvar_logic: regulator-ppvar-logic { compatible = "regulator-fixed"; regulator-name = "ppvar_logic"; @@ -91,7 +91,7 @@ ppvar_logic: ppvar-logic { vin-supply = <&ppvar_sys>; }; - pp1800_audio: pp1800-audio { + pp1800_audio: regulator-pp1800-audio { compatible = "regulator-fixed"; regulator-name = "pp1800_audio"; pinctrl-names = "default"; @@ -107,7 +107,7 @@ pp1800_audio: pp1800-audio { }; /* gpio is shared with pp3300_wifi_bt */ - pp1800_pcie: pp1800-pcie { + pp1800_pcie: regulator-pp1800-pcie { compatible = "regulator-fixed"; regulator-name = "pp1800_pcie"; pinctrl-names = "default"; @@ -129,7 +129,7 @@ pp1800_pcie: pp1800-pcie { pp3000_ap: pp3000_emmc: pp3000 { }; - pp1500_ap_io: pp1500-ap-io { + pp1500_ap_io: regulator-pp1500-ap-io { compatible = "regulator-fixed"; regulator-name = "pp1500_ap_io"; pinctrl-names = "default"; @@ -146,7 +146,7 @@ pp1500_ap_io: pp1500-ap-io { vin-supply = <&pp1800>; }; - pp3300_disp: pp3300-disp { + pp3300_disp: regulator-pp3300-disp { compatible = "regulator-fixed"; regulator-name = "pp3300_disp"; pinctrl-names = "default"; @@ -164,7 +164,7 @@ pp3300_usb: pp3300 { }; /* gpio is shared with pp1800_pcie and pinctrl is set there */ - pp3300_wifi_bt: pp3300-wifi-bt { + pp3300_wifi_bt: regulator-pp3300-wifi-bt { compatible = "regulator-fixed"; regulator-name = "pp3300_wifi_bt"; @@ -180,7 +180,7 @@ pp3300_wifi_bt: pp3300-wifi-bt { * With some stretching of the imagination, we can call the 1.8V * regulator a supply. */ - wlan_pd_n: wlan-pd-n { + wlan_pd_n: regulator-wlan-pd-n { compatible = "regulator-fixed"; regulator-name = "wlan_pd_n"; pinctrl-names = "default"; @@ -550,7 +550,7 @@ &usbdrd_dwc3_1 { }; &pinctrl { - discrete-regulators { + discretes { pp1500_en: pp1500-en { rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts index 2cc9b3386c16ff..7b907c80dd32b2 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-kevin.dts @@ -28,7 +28,7 @@ / { /* Power tree */ - p3_3v_dig: p3-3v-dig { + p3_3v_dig: regulator-p3-3v-dig { compatible = "regulator-fixed"; regulator-name = "p3.3v_dig"; pinctrl-names = "default"; @@ -314,7 +314,7 @@ cpu1_dig_pdct_l: cpu1-dig-pdct-l { }; }; - discrete-regulators { + discretes { cpu3_pen_pwr_en: cpu3-pen-pwr-en { rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi index d5e035823eb5e4..19b23b43896583 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi @@ -13,7 +13,7 @@ /{ /* Power tree */ /* ppvar_sys children, sorted by name */ - pp1250_s3: pp1250-s3 { + pp1250_s3: regulator-pp1250-s3 { compatible = "regulator-fixed"; regulator-name = "pp1250_s3"; @@ -26,7 +26,7 @@ pp1250_s3: pp1250-s3 { vin-supply = <&ppvar_sys>; }; - pp1250_cam: pp1250-dvdd { + pp1250_cam: regulator-pp1250-dvdd { compatible = "regulator-fixed"; regulator-name = "pp1250_dvdd"; pinctrl-names = "default"; @@ -42,7 +42,7 @@ pp1250_cam: pp1250-dvdd { vin-supply = <&pp1250_s3>; }; - pp900_s0: pp900-s0 { + pp900_s0: regulator-pp900-s0 { compatible = "regulator-fixed"; regulator-name = "pp900_s0"; @@ -55,7 +55,7 @@ pp900_s0: pp900-s0 { vin-supply = <&ppvar_sys>; }; - ppvarn_lcd: ppvarn-lcd { + ppvarn_lcd: regulator-ppvarn-lcd { compatible = "regulator-fixed"; regulator-name = "ppvarn_lcd"; pinctrl-names = "default"; @@ -66,7 +66,7 @@ ppvarn_lcd: ppvarn-lcd { vin-supply = <&ppvar_sys>; }; - ppvarp_lcd: ppvarp-lcd { + ppvarp_lcd: regulator-ppvarp-lcd { compatible = "regulator-fixed"; regulator-name = "ppvarp_lcd"; pinctrl-names = "default"; @@ -78,7 +78,7 @@ ppvarp_lcd: ppvarp-lcd { }; /* pp1800 children, sorted by name */ - pp900_s3: pp900-s3 { + pp900_s3: regulator-pp900-s3 { compatible = "regulator-fixed"; regulator-name = "pp900_s3"; @@ -96,7 +96,7 @@ pp1800_s3: pp1800 { }; /* pp3300 children, sorted by name */ - pp2800_cam: pp2800-avdd { + pp2800_cam: regulator-pp2800-avdd { compatible = "regulator-fixed"; regulator-name = "pp2800_avdd"; pinctrl-names = "default"; @@ -127,7 +127,7 @@ pp3300_s3: pp3300 { * the boot process it also enables its supply regulator bt_3v3, * which changes BT_EN to high. */ - bt_3v3: bt-3v3 { + bt_3v3: regulator-bt-3v3 { compatible = "regulator-fixed"; regulator-name = "bt_3v3"; pinctrl-names = "default"; @@ -138,7 +138,7 @@ bt_3v3: bt-3v3 { vin-supply = <&pp3300_s3>; }; - wlan_3v3: wlan-3v3 { + wlan_3v3: regulator-wlan-3v3 { compatible = "regulator-fixed"; regulator-name = "wlan_3v3"; pinctrl-names = "default"; @@ -833,7 +833,7 @@ pen_reset_l: pen-reset-l { }; }; - discrete-regulators { + discretes { display_rst_l: display-rst-l { rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_down>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi index 776c0eec04d7f5..6d9e60b01225e5 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi @@ -42,14 +42,14 @@ chosen { * schematic. */ - ppvar_sys: ppvar-sys { + ppvar_sys: regulator-ppvar-sys { compatible = "regulator-fixed"; regulator-name = "ppvar_sys"; regulator-always-on; regulator-boot-on; }; - pp1200_lpddr: pp1200-lpddr { + pp1200_lpddr: regulator-pp1200-lpddr { compatible = "regulator-fixed"; regulator-name = "pp1200_lpddr"; @@ -62,7 +62,7 @@ pp1200_lpddr: pp1200-lpddr { vin-supply = <&ppvar_sys>; }; - pp1800: pp1800 { + pp1800: regulator-pp1800 { compatible = "regulator-fixed"; regulator-name = "pp1800"; @@ -75,7 +75,7 @@ pp1800: pp1800 { vin-supply = <&ppvar_sys>; }; - pp3300: pp3300 { + pp3300: regulator-pp3300 { compatible = "regulator-fixed"; regulator-name = "pp3300"; @@ -88,7 +88,7 @@ pp3300: pp3300 { vin-supply = <&ppvar_sys>; }; - pp5000: pp5000 { + pp5000: regulator-pp5000 { compatible = "regulator-fixed"; regulator-name = "pp5000"; @@ -101,7 +101,7 @@ pp5000: pp5000 { vin-supply = <&ppvar_sys>; }; - ppvar_bigcpu_pwm: ppvar-bigcpu-pwm { + ppvar_bigcpu_pwm: regulator-ppvar-bigcpu-pwm { compatible = "pwm-regulator"; regulator-name = "ppvar_bigcpu_pwm"; @@ -130,7 +130,7 @@ ppvar_bigcpu: ppvar-bigcpu { regulator-settling-time-up-us = <322>; }; - ppvar_litcpu_pwm: ppvar-litcpu-pwm { + ppvar_litcpu_pwm: regulator-ppvar-litcpu-pwm { compatible = "pwm-regulator"; regulator-name = "ppvar_litcpu_pwm"; @@ -159,7 +159,7 @@ ppvar_litcpu: ppvar-litcpu { regulator-settling-time-up-us = <384>; }; - ppvar_gpu_pwm: ppvar-gpu-pwm { + ppvar_gpu_pwm: regulator-ppvar-gpu-pwm { compatible = "pwm-regulator"; regulator-name = "ppvar_gpu_pwm"; @@ -224,7 +224,7 @@ pp1800_pmu: pp1800 { pp1800_usb: pp1800 { }; - pp3000_sd_slot: pp3000-sd-slot { + pp3000_sd_slot: regulator-pp3000-sd-slot { compatible = "regulator-fixed"; regulator-name = "pp3000_sd_slot"; pinctrl-names = "default"; @@ -724,7 +724,7 @@ ec_ap_int_l: ec-ap-int-l { }; }; - discrete-regulators { + discretes { sd_io_pwr_en: sd-io-pwr-en { rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts index 5a02502d21cd89..81c4fcb30f39c9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts @@ -27,7 +27,7 @@ clkin_gmac: external-gmac-clock { #clock-cells = <0>; }; - dc_5v: dc-5v { + dc_5v: regulator-dc-5v { compatible = "regulator-fixed"; regulator-name = "dc_5v"; regulator-always-on; @@ -56,7 +56,7 @@ power_led: led-0 { }; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-min-microvolt = <5000000>; @@ -65,14 +65,14 @@ vcc_sys: vcc-sys { vin-supply = <&dc_5v>; }; - vcc_phy: vcc-phy-regulator { + vcc_phy: regulator-vcc-phy { compatible = "regulator-fixed"; regulator-name = "vcc_phy"; regulator-always-on; regulator-boot-on; }; - vcc1v8_s0: vcc1v8-s0 { + vcc1v8_s0: regulator-vcc1v8-s0 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s0"; regulator-min-microvolt = <1800000>; @@ -80,7 +80,7 @@ vcc1v8_s0: vcc1v8-s0 { regulator-always-on; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-min-microvolt = <3300000>; @@ -89,7 +89,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&vcc_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>; @@ -99,7 +99,7 @@ vcc5v0_host: vcc5v0-host-regulator { regulator-always-on; }; - vcc5v0_typec: vcc5v0-typec-regulator { + vcc5v0_typec: regulator-vcc5v0-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -110,7 +110,7 @@ vcc5v0_typec: vcc5v0-typec-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_usb: vcc5v0-usb { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -120,7 +120,7 @@ vcc5v0_usb: vcc5v0-usb { vin-supply = <&dc_5v>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc_sys>; @@ -252,7 +252,7 @@ rk808: pmic@1b { interrupts = <21 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <1>; clock-output-names = "xin32k", "rtc_clko_wifi"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi index c772985ae4e51c..880c2408495273 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge.dtsi @@ -45,7 +45,7 @@ sdio_pwrseq: sdio-pwrseq { }; /* switched by pmic_sleep */ - vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { + vcc1v8_s3: vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s3"; regulator-always-on; @@ -55,7 +55,7 @@ vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { vin-supply = <&vcc_1v8>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; regulator-always-on; @@ -66,7 +66,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { }; /* Actually 3 regulators (host0, 1, 2) controlled by the same gpio */ - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>; @@ -77,7 +77,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vsys_5v0>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vsys_3v3>; @@ -88,14 +88,14 @@ vdd_log: vdd-log { regulator-max-microvolt = <1400000>; }; - vsys: vsys { + vsys: regulator-vsys { compatible = "regulator-fixed"; regulator-name = "vsys"; regulator-always-on; regulator-boot-on; }; - vsys_3v3: vsys-3v3 { + vsys_3v3: regulator-vsys-3v3 { compatible = "regulator-fixed"; regulator-name = "vsys_3v3"; regulator-always-on; @@ -105,7 +105,7 @@ vsys_3v3: vsys-3v3 { vin-supply = <&vsys>; }; - vsys_5v0: vsys-5v0 { + vsys_5v0: regulator-vsys-5v0 { compatible = "regulator-fixed"; regulator-name = "vsys_5v0"; regulator-always-on; @@ -315,7 +315,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vsys_3v3>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts index b0c1fb0b704e7e..e7d4a2f9a95eaa 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts @@ -23,7 +23,7 @@ aliases { mmc1 = &sdhci; }; - avdd_0v9_s0: avdd-0v9-s0 { + avdd_0v9_s0: regulator-avdd-0v9-s0 { compatible = "regulator-fixed"; regulator-name = "avdd_0v9_s0"; regulator-always-on; @@ -33,7 +33,7 @@ avdd_0v9_s0: avdd-0v9-s0 { vin-supply = <&vcc1v8_sys_s3>; }; - avdd_1v8_s0: avdd-1v8-s0 { + avdd_1v8_s0: regulator-avdd-1v8-s0 { compatible = "regulator-fixed"; regulator-name = "avdd_1v8_s0"; regulator-always-on; @@ -86,7 +86,7 @@ led-1 { }; }; - hdd_a_power: hdd-a-power { + hdd_a_power: regulator-hdd-a-power { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; @@ -98,7 +98,7 @@ hdd_a_power: hdd-a-power { startup-delay-us = <2000000>; }; - hdd_b_power: hdd-b-power { + hdd_b_power: regulator-hdd-b-power { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>; @@ -110,7 +110,7 @@ hdd_b_power: hdd-b-power { startup-delay-us = <2000000>; }; - pcie_power: pcie-power { + pcie_power: regulator-pcie-power { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>; @@ -122,7 +122,7 @@ pcie_power: pcie-power { vin-supply = <&vcc5v0_perdev>; }; - usblan_power: usblan-power { + usblan_power: regulator-usblan-power { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; @@ -134,7 +134,7 @@ usblan_power: usblan-power { vin-supply = <&vcc5v0_usb>; }; - vcc1v8_sys_s0: vcc1v8-sys-s0 { + vcc1v8_sys_s0: regulator-vcc1v8-sys-s0 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_sys_s0"; regulator-always-on; @@ -144,7 +144,7 @@ vcc1v8_sys_s0: vcc1v8-sys-s0 { vin-supply = <&vcc1v8_sys_s3>; }; - vcc3v0_sd: vcc3v0-sd { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; @@ -157,7 +157,7 @@ vcc3v0_sd: vcc3v0-sd { vin-supply = <&vcc3v3_sys_s3>; }; - vcc3v3_sys_s3: vcc_lan: vcc3v3-sys-s3 { + vcc3v3_sys_s3: vcc_lan: regulator-vcc3v3-sys-s3 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys_s3"; regulator-always-on; @@ -171,7 +171,7 @@ regulator-state-mem { }; }; - vcc5v0_perdev: vcc5v0-perdev { + vcc5v0_perdev: regulator-vcc5v0-perdev { compatible = "regulator-fixed"; regulator-name = "vcc5v0_perdev"; regulator-always-on; @@ -181,7 +181,7 @@ vcc5v0_perdev: vcc5v0-perdev { vin-supply = <&vcc12v_dcin_bkup>; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -195,7 +195,7 @@ regulator-state-mem { }; }; - vcc5v0_usb: vcc5v0-usb { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; @@ -209,7 +209,7 @@ vcc5v0_usb: vcc5v0-usb { vin-supply = <&vcc5v0_perdev>; }; - vcc12v_dcin: vcc12v-dcin { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -218,7 +218,7 @@ vcc12v_dcin: vcc12v-dcin { regulator-max-microvolt = <12000000>; }; - vcc12v_dcin_bkup: vcc12v-dcin-bkup { + vcc12v_dcin_bkup: regulator-vcc12v-dcin-bkup { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin_bkup"; regulator-always-on; @@ -309,7 +309,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc5v0_sys>; vcc2-supply = <&vcc5v0_sys>; vcc3-supply = <&vcc5v0_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts index f12b1eb0057536..2cdc2013c32006 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts @@ -40,7 +40,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>; }; - dc5v_adp: dc5v-adp { + dc5v_adp: regulator-dc5v-adp { compatible = "regulator-fixed"; regulator-name = "dc5v_adapter"; regulator-always-on; @@ -49,7 +49,7 @@ dc5v_adp: dc5v-adp { regulator-max-microvolt = <5000000>; }; - vcc3v3_lan: vcc3v3-lan { + vcc3v3_lan: regulator-vcc3v3-lan { compatible = "regulator-fixed"; regulator-name = "vcc3v3_lan"; regulator-always-on; @@ -59,7 +59,7 @@ vcc3v3_lan: vcc3v3-lan { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -69,7 +69,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host0: vcc5v0_host1: vcc5v0-host { + vcc5v0_host0: vcc5v0_host1: regulator-vcc5v0-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; regulator-boot-on; @@ -79,7 +79,7 @@ vcc5v0_host0: vcc5v0_host1: vcc5v0-host { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host3: vcc5v0-host3 { + vcc5v0_host3: regulator-vcc5v0-host3 { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host3"; enable-active-high; @@ -90,7 +90,7 @@ vcc5v0_host3: vcc5v0-host3 { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -100,7 +100,7 @@ vcc5v0_sys: vcc5v0-sys { vin-supply = <&dc5v_adp>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc5v0_sys>; @@ -187,7 +187,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc5v0_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts index 3bf8f959e42c44..e5fc05cc64bd97 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopc-t4.dts @@ -15,7 +15,7 @@ / { model = "FriendlyElec NanoPC-T4"; compatible = "friendlyarm,nanopc-t4", "rockchip,rk3399"; - vcc12v0_sys: vcc12v0-sys { + vcc12v0_sys: regulator-vcc12v0-sys { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -24,7 +24,7 @@ vcc12v0_sys: vcc12v0-sys { regulator-name = "vcc12v0_sys"; }; - vcc5v0_host0: vcc5v0-host0 { + vcc5v0_host0: regulator-vcc5v0-host0 { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4.dts index 60358ab8c7dfcc..e091b20c2d1f20 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4.dts @@ -10,57 +10,14 @@ */ /dts-v1/; -#include "rk3399-nanopi4.dtsi" + +#include "rk3399-nanopi-m4.dtsi" / { model = "FriendlyElec NanoPi M4"; compatible = "friendlyarm,nanopi-m4", "rockchip,rk3399"; - - vdd_5v: vdd-5v { - compatible = "regulator-fixed"; - regulator-name = "vdd_5v"; - regulator-always-on; - regulator-boot-on; - }; - - vcc5v0_core: vcc5v0-core { - compatible = "regulator-fixed"; - regulator-name = "vcc5v0_core"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vdd_5v>; - }; - - vcc5v0_usb1: vcc5v0-usb1 { - compatible = "regulator-fixed"; - regulator-name = "vcc5v0_usb1"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vcc5v0_sys>; - }; - - vcc5v0_usb2: vcc5v0-usb2 { - compatible = "regulator-fixed"; - regulator-name = "vcc5v0_usb2"; - regulator-always-on; - regulator-boot-on; - vin-supply = <&vcc5v0_sys>; - }; -}; - -&vcc3v3_sys { - vin-supply = <&vcc5v0_core>; }; &u2phy0_host { phy-supply = <&vcc5v0_usb1>; }; - -&u2phy1_host { - phy-supply = <&vcc5v0_usb2>; -}; - -&vbus_typec { - regulator-always-on; - vin-supply = <&vdd_5v>; -}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4.dtsi new file mode 100644 index 00000000000000..1ac6bc14082365 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4.dtsi @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * FriendlyElec NanoPi M4 board device tree source + * + * Copyright (c) 2018 FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyarm.com) + * + * Copyright (c) 2018 Collabora Ltd. + * Copyright (c) 2019 Arm Ltd. + */ + +/dts-v1/; + +#include "rk3399-nanopi4.dtsi" + +/ { + vdd_5v: regulator-vdd-5v { + compatible = "regulator-fixed"; + regulator-name = "vdd_5v"; + regulator-always-on; + regulator-boot-on; + }; + + vcc5v0_core: regulator-vcc5v0-core { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_core"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vdd_5v>; + }; + + vcc5v0_usb1: regulator-vcc5v0-usb1 { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usb1"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_usb2: regulator-vcc5v0-usb2 { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usb2"; + regulator-always-on; + regulator-boot-on; + vin-supply = <&vcc5v0_sys>; + }; +}; + +&vcc3v3_sys { + vin-supply = <&vcc5v0_core>; +}; + +&u2phy1_host { + phy-supply = <&vcc5v0_usb2>; +}; + +&vbus_typec { + regulator-always-on; + vin-supply = <&vdd_5v>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts index 65cb21837b0cac..d03ce6fa5bf65e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-m4b.dts @@ -6,7 +6,8 @@ */ /dts-v1/; -#include "rk3399-nanopi-m4.dts" + +#include "rk3399-nanopi-m4.dtsi" / { model = "FriendlyElec NanoPi M4B"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-neo4.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-neo4.dts index 195410b089b94a..3ae645edeb62e2 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-neo4.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-neo4.dts @@ -12,14 +12,14 @@ / { model = "FriendlyARM NanoPi NEO4"; compatible = "friendlyarm,nanopi-neo4", "rockchip,rk3399"; - vdd_5v: vdd-5v { + vdd_5v: regulator-vdd-5v { compatible = "regulator-fixed"; regulator-name = "vdd_5v"; regulator-always-on; regulator-boot-on; }; - vcc5v0_core: vcc5v0-core { + vcc5v0_core: regulator-vcc5v0-core { compatible = "regulator-fixed"; regulator-name = "vcc5v0_core"; regulator-always-on; @@ -27,7 +27,7 @@ vcc5v0_core: vcc5v0-core { vin-supply = <&vdd_5v>; }; - vcc5v0_usb1: vcc5v0-usb1 { + vcc5v0_usb1: regulator-vcc5v0-usb1 { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb1"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s-enterprise.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s-enterprise.dts index a23d11ca0eb6af..b76f9896207660 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s-enterprise.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s-enterprise.dts @@ -1,7 +1,8 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) /dts-v1/; -#include "rk3399-nanopi-r4s.dts" + +#include "rk3399-nanopi-r4s.dtsi" / { model = "FriendlyElec NanoPi R4S Enterprise Edition"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts index fe5b526100107a..ec3883f6221e85 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dts @@ -1,133 +1,13 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* - * FriendlyElec NanoPC-T4 board device tree source - * * Copyright (c) 2020 FriendlyElec Computer Tech. Co., Ltd. - * (http://www.friendlyarm.com) - * - * Copyright (c) 2018 Collabora Ltd. - * - * Copyright (c) 2020 Jensen Huang - * Copyright (c) 2020 Marty Jones - * Copyright (c) 2021 Tianling Shen */ /dts-v1/; -#include "rk3399-nanopi4.dtsi" + +#include "rk3399-nanopi-r4s.dtsi" / { model = "FriendlyElec NanoPi R4S"; compatible = "friendlyarm,nanopi-r4s", "rockchip,rk3399"; - - /delete-node/ display-subsystem; - - gpio-leds { - pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>; - - /delete-node/ led-0; - - lan_led: led-lan { - gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>; - label = "green:lan"; - }; - - sys_led: led-sys { - gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; - label = "red:power"; - default-state = "on"; - }; - - wan_led: led-wan { - gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; - label = "green:wan"; - }; - }; - - gpio-keys { - pinctrl-0 = <&reset_button_pin>; - - /delete-node/ key-power; - - key-reset { - debounce-interval = <50>; - gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>; - label = "reset"; - linux,code = ; - }; - }; - - vdd_5v: vdd-5v { - compatible = "regulator-fixed"; - regulator-name = "vdd_5v"; - regulator-always-on; - regulator-boot-on; - }; -}; - -&emmc_phy { - status = "disabled"; -}; - -&i2c4 { - status = "disabled"; -}; - -&pcie0 { - max-link-speed = <1>; - num-lanes = <1>; - vpcie3v3-supply = <&vcc3v3_sys>; -}; - -&pinctrl { - gpio-leds { - /delete-node/ status-led-pin; - - lan_led_pin: lan-led-pin { - rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - sys_led_pin: sys-led-pin { - rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - wan_led_pin: wan-led-pin { - rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - rockchip-key { - /delete-node/ power-key; - - reset_button_pin: reset-button-pin { - rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; -}; - -&sdhci { - status = "disabled"; -}; - -&sdio0 { - status = "disabled"; -}; - -&u2phy0_host { - phy-supply = <&vdd_5v>; -}; - -&u2phy1_host { - status = "disabled"; -}; - -&uart0 { - status = "disabled"; -}; - -&usbdrd_dwc3_0 { - dr_mode = "host"; -}; - -&vcc3v3_sys { - vin-supply = <&vcc5v0_sys>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi new file mode 100644 index 00000000000000..b1c9bd0e63ef34 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * FriendlyElec NanoPC-R4 board device tree source + * + * Copyright (c) 2020 FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyarm.com) + * + * Copyright (c) 2018 Collabora Ltd. + * + * Copyright (c) 2020 Jensen Huang + * Copyright (c) 2020 Marty Jones + * Copyright (c) 2021 Tianling Shen + */ + +/dts-v1/; + +#include "rk3399-nanopi4.dtsi" + +/ { + /delete-node/ display-subsystem; + + gpio-leds { + pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>; + + /delete-node/ led-0; + + lan_led: led-lan { + gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>; + label = "green:lan"; + }; + + sys_led: led-sys { + gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; + label = "red:power"; + default-state = "on"; + }; + + wan_led: led-wan { + gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; + label = "green:wan"; + }; + }; + + gpio-keys { + pinctrl-0 = <&reset_button_pin>; + + /delete-node/ key-power; + + key-reset { + debounce-interval = <50>; + gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>; + label = "reset"; + linux,code = ; + }; + }; + + vdd_5v: regulator-vdd-5v { + compatible = "regulator-fixed"; + regulator-name = "vdd_5v"; + regulator-always-on; + regulator-boot-on; + }; +}; + +&emmc_phy { + status = "disabled"; +}; + +&i2c4 { + status = "disabled"; +}; + +&pcie0 { + max-link-speed = <1>; + num-lanes = <1>; + vpcie3v3-supply = <&vcc3v3_sys>; +}; + +&pinctrl { + gpio-leds { + /delete-node/ status-led-pin; + + lan_led_pin: lan-led-pin { + rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + sys_led_pin: sys-led-pin { + rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wan_led_pin: wan-led-pin { + rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + rockchip-key { + /delete-node/ power-key; + + reset_button_pin: reset-button-pin { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&sdhci { + status = "disabled"; +}; + +&sdio0 { + status = "disabled"; +}; + +&u2phy0_host { + phy-supply = <&vdd_5v>; +}; + +&u2phy1_host { + status = "disabled"; +}; + +&uart0 { + status = "disabled"; +}; + +&usbdrd_dwc3_0 { + dr_mode = "host"; +}; + +&vcc3v3_sys { + vin-supply = <&vcc5v0_sys>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi index 7debc4a1b5faa5..b169be06d4d1f7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi @@ -34,7 +34,7 @@ clkin_gmac: external-gmac-clock { #clock-cells = <0>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -43,7 +43,7 @@ vcc3v3_sys: vcc3v3-sys { regulator-name = "vcc3v3_sys"; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -54,7 +54,7 @@ vcc5v0_sys: vcc5v0-sys { }; /* switched by pmic_sleep */ - vcc1v8_s3: vcc1v8-s3 { + vcc1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -64,7 +64,7 @@ vcc1v8_s3: vcc1v8-s3 { vin-supply = <&vcc_1v8>; }; - vcc3v0_sd: vcc3v0-sd { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; @@ -81,7 +81,7 @@ vcc3v0_sd: vcc3v0-sd { * Really, this is supplied by vcc_1v8, and vcc1v8_s3 only * drives the enable pin, but we can't quite model that. */ - vcca0v9_s3: vcca0v9-s3 { + vcca0v9_s3: regulator-vcca0v9-s3 { compatible = "regulator-fixed"; regulator-min-microvolt = <900000>; regulator-max-microvolt = <900000>; @@ -90,7 +90,7 @@ vcca0v9_s3: vcca0v9-s3 { }; /* As above, actually supplied by vcc3v3_sys */ - vcca1v8_s3: vcca1v8-s3 { + vcca1v8_s3: regulator-vcca1v8-s3 { compatible = "regulator-fixed"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -98,7 +98,7 @@ vcca1v8_s3: vcca1v8-s3 { vin-supply = <&vcc1v8_s3>; }; - vbus_typec: vbus-typec { + vbus_typec: regulator-vbus-typec { compatible = "regulator-fixed"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; @@ -269,7 +269,7 @@ rk808: pmic@1b { interrupts = <21 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>, <&ap_pwroff>, <&clk_32k>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-op1.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-op1.dtsi index b24bff51151367..c4f4f1ff6117b3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-op1.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-op1.dtsi @@ -12,32 +12,32 @@ cluster0_opp: opp-table-0 { opp00 { opp-hz = /bits/ 64 <408000000>; - opp-microvolt = <800000>; + opp-microvolt = <800000 800000 1150000>; clock-latency-ns = <40000>; }; opp01 { opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <825000>; + opp-microvolt = <825000 825000 1150000>; }; opp02 { opp-hz = /bits/ 64 <816000000>; - opp-microvolt = <850000>; + opp-microvolt = <850000 850000 1150000>; }; opp03 { opp-hz = /bits/ 64 <1008000000>; - opp-microvolt = <900000>; + opp-microvolt = <900000 900000 1150000>; }; opp04 { opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <975000>; + opp-microvolt = <975000 975000 1150000>; }; opp05 { opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <1100000>; + opp-microvolt = <1100000 1100000 1150000>; }; opp06 { opp-hz = /bits/ 64 <1512000000>; - opp-microvolt = <1150000>; + opp-microvolt = <1150000 1150000 1150000>; }; }; @@ -47,40 +47,40 @@ cluster1_opp: opp-table-1 { opp00 { opp-hz = /bits/ 64 <408000000>; - opp-microvolt = <800000>; + opp-microvolt = <800000 800000 1250000>; clock-latency-ns = <40000>; }; opp01 { opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <800000>; + opp-microvolt = <800000 800000 1250000>; }; opp02 { opp-hz = /bits/ 64 <816000000>; - opp-microvolt = <825000>; + opp-microvolt = <825000 825000 1250000>; }; opp03 { opp-hz = /bits/ 64 <1008000000>; - opp-microvolt = <850000>; + opp-microvolt = <850000 850000 1250000>; }; opp04 { opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <900000>; + opp-microvolt = <900000 900000 1250000>; }; opp05 { opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <975000>; + opp-microvolt = <975000 975000 1250000>; }; opp06 { opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <1050000>; + opp-microvolt = <1050000 1050000 1250000>; }; opp07 { opp-hz = /bits/ 64 <1800000000>; - opp-microvolt = <1150000>; + opp-microvolt = <1150000 1150000 1250000>; }; opp08 { opp-hz = /bits/ 64 <2016000000>; - opp-microvolt = <1250000>; + opp-microvolt = <1250000 1250000 1250000>; }; }; @@ -89,27 +89,27 @@ gpu_opp_table: opp-table-2 { opp00 { opp-hz = /bits/ 64 <200000000>; - opp-microvolt = <800000>; + opp-microvolt = <800000 800000 1075000>; }; opp01 { opp-hz = /bits/ 64 <297000000>; - opp-microvolt = <800000>; + opp-microvolt = <800000 800000 1075000>; }; opp02 { opp-hz = /bits/ 64 <400000000>; - opp-microvolt = <825000>; + opp-microvolt = <825000 825000 1075000>; }; opp03 { opp-hz = /bits/ 64 <500000000>; - opp-microvolt = <850000>; + opp-microvolt = <850000 850000 1075000>; }; opp04 { opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <925000>; + opp-microvolt = <925000 925000 1075000>; }; opp05 { opp-hz = /bits/ 64 <800000000>; - opp-microvolt = <1075000>; + opp-microvolt = <1075000 1075000 1075000>; }; }; @@ -118,19 +118,19 @@ dmc_opp_table: opp-table-3 { opp00 { opp-hz = /bits/ 64 <400000000>; - opp-microvolt = <900000>; + opp-microvolt = <900000 900000 925000>; }; opp01 { opp-hz = /bits/ 64 <666000000>; - opp-microvolt = <900000>; + opp-microvolt = <900000 900000 925000>; }; opp02 { opp-hz = /bits/ 64 <800000000>; - opp-microvolt = <900000>; + opp-microvolt = <900000 900000 925000>; }; opp03 { opp-hz = /bits/ 64 <928000000>; - opp-microvolt = <925000>; + opp-microvolt = <925000 925000 925000>; }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts index 07ec33f3f55fae..2ddd4da155976a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts @@ -65,7 +65,7 @@ button-menu { }; }; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -100,7 +100,7 @@ sdio_pwrseq: sdio-pwrseq { }; /* switched by pmic_sleep */ - vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { + vcc1v8_s3: vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s3"; regulator-always-on; @@ -110,7 +110,7 @@ vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { vin-supply = <&vcc_1v8>; }; - vcc3v0_sd: vcc3v0-sd { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; @@ -123,7 +123,7 @@ vcc3v0_sd: vcc3v0-sd { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -133,7 +133,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&vcc_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>; @@ -144,7 +144,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc_sys>; }; - vbus_typec: vbus-typec-regulator { + vbus_typec: regulator-vbus-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -154,7 +154,7 @@ vbus_typec: vbus-typec-regulator { vin-supply = <&vcc_sys>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -164,7 +164,7 @@ vcc_sys: vcc-sys { vin-supply = <&dc_12v>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc_sys>; @@ -262,7 +262,7 @@ rk808: pmic@1b { clock-output-names = "rtc_clko_soc", "rtc_clko_wifi"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts index a5a7e374bc5947..5473070823cb12 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts @@ -150,7 +150,7 @@ es8316-sound { "Speaker", "Speaker Amplifier OUTL", "Speaker", "Speaker Amplifier OUTR"; - simple-audio-card,hp-det-gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; simple-audio-card,aux-devs = <&speaker_amp>; simple-audio-card,pin-switches = "Speaker"; @@ -172,7 +172,7 @@ speaker_amp: speaker-amplifier { /* Power tree */ /* Root power source */ - vcc_sysin: vcc-sysin { + vcc_sysin: regulator-vcc-sysin { compatible = "regulator-fixed"; regulator-name = "vcc_sysin"; regulator-always-on; @@ -181,7 +181,7 @@ vcc_sysin: vcc-sysin { /* Regulators supplied by vcc_sysin */ /* LCD backlight supply */ - vcc_12v: vcc-12v { + vcc_12v: regulator-vcc-12v { compatible = "regulator-fixed"; regulator-name = "vcc_12v"; regulator-always-on; @@ -196,7 +196,7 @@ regulator-state-mem { }; /* Main 3.3 V supply */ - vcc3v3_sys: wifi_bat: vcc3v3-sys { + vcc3v3_sys: wifi_bat: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -211,7 +211,7 @@ regulator-state-mem { }; /* 5 V USB power supply */ - vcc5v0_usb: pa_5v: vcc5v0-usb-regulator { + vcc5v0_usb: pa_5v: regulator-vcc5v0-usb { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>; @@ -229,7 +229,7 @@ regulator-state-mem { }; /* RK3399 logic supply */ - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc_sysin>; @@ -246,7 +246,7 @@ regulator-state-mem { /* Regulators supplied by vcc3v3_sys */ /* 0.9 V supply, always on */ - vcc_0v9: vcc-0v9 { + vcc_0v9: regulator-vcc-0v9 { compatible = "regulator-fixed"; regulator-name = "vcc_0v9"; regulator-always-on; @@ -257,7 +257,7 @@ vcc_0v9: vcc-0v9 { }; /* S3 1.8 V supply, switched by vcc1v8_s3 */ - vcca1v8_s3: vcc1v8-s3 { + vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcca1v8_s3"; regulator-always-on; @@ -268,7 +268,7 @@ vcca1v8_s3: vcc1v8-s3 { }; /* micro SD card power */ - vcc3v0_sd: vcc3v0-sd { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; @@ -286,7 +286,7 @@ regulator-state-mem { }; /* LCD panel power, called VCC3V3_S0 in schematic */ - vcc3v3_panel: vcc3v3-panel { + vcc3v3_panel: regulator-vcc3v3-panel { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; @@ -305,7 +305,7 @@ regulator-state-mem { }; /* M.2 adapter power, switched by vcc1v8_s3 */ - vcc3v3_ssd: vcc3v3-ssd { + vcc3v3_ssd: regulator-vcc3v3-ssd { compatible = "regulator-fixed"; regulator-name = "vcc3v3_ssd"; regulator-min-microvolt = <3300000>; @@ -315,7 +315,7 @@ vcc3v3_ssd: vcc3v3-ssd { /* Regulators supplied by vcc5v0_usb */ /* USB 3 port power supply regulator */ - vcc5v0_otg: vcc5v0-otg { + vcc5v0_otg: regulator-vcc5v0-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>; @@ -334,7 +334,7 @@ regulator-state-mem { /* Regulators supplied by vcc5v0_usb */ /* Type C port power supply regulator */ - vbus_5vout: vbus_typec: vbus-5vout { + vbus_5vout: vbus_typec: regulator-vbus-5vout { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -352,7 +352,7 @@ regulator-state-mem { /* Regulators supplied by vcc_1v8 */ /* Primary 0.9 V LDO */ - vcca0v9_s3: vcca0v9-s3 { + vcca0v9_s3: regulator-vcca0v9-s3 { compatible = "regulator-fixed"; regulator-name = "vcc0v9_s3"; regulator-min-microvolt = <5000000>; @@ -447,7 +447,7 @@ rk808: pmic@1b { interrupts = <10 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l_pin>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc_sysin>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts index 09a016ea8c7650..04ba4c4565d0a2 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts @@ -13,7 +13,7 @@ #include #include #include -#include "rk3399.dtsi" +#include "rk3399-s.dtsi" / { model = "Pine64 PinePhone Pro"; @@ -97,14 +97,14 @@ multi-led { leds = <&led_red>, <&led_green>, <&led_blue>; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; regulator-boot-on; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -114,7 +114,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc_sys>; }; - vcca1v8_s3: vcc1v8-s3-regulator { + vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcca1v8_s3"; regulator-min-microvolt = <1800000>; @@ -124,7 +124,7 @@ vcca1v8_s3: vcc1v8-s3-regulator { regulator-boot-on; }; - vcc1v8_codec: vcc1v8-codec-regulator { + vcc1v8_codec: regulator-vcc1v8-codec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PA4 GPIO_ACTIVE_HIGH>; @@ -158,7 +158,7 @@ wifi_pwrseq: sdio-wifi-pwrseq { }; /* MIPI DSI panel 1.8v supply */ - vcc1v8_lcd: vcc1v8-lcd { + vcc1v8_lcd: regulator-vcc1v8-lcd { compatible = "regulator-fixed"; enable-active-high; regulator-name = "vcc1v8_lcd"; @@ -169,7 +169,7 @@ vcc1v8_lcd: vcc1v8-lcd { }; /* MIPI DSI panel 2.8v supply */ - vcc2v8_lcd: vcc2v8-lcd { + vcc2v8_lcd: regulator-vcc2v8-lcd { compatible = "regulator-fixed"; enable-active-high; regulator-name = "vcc2v8_lcd"; @@ -241,7 +241,7 @@ rk818: pmic@1c { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc_sys>; @@ -454,27 +454,6 @@ mpu6500@68 { }; }; -&cluster0_opp { - opp04 { - status = "disabled"; - }; - - opp05 { - status = "disabled"; - }; -}; - -&cluster1_opp { - opp06 { - opp-hz = /bits/ 64 <1500000000>; - opp-microvolt = <1100000 1100000 1150000>; - }; - - opp07 { - status = "disabled"; - }; -}; - &io_domains { bt656-supply = <&vcc1v8_dvp>; audio-supply = <&vcca1v8_codec>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts index f6f15946579ebf..947bbd62a6b09c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts @@ -30,6 +30,12 @@ button-batlow-n { linux,code = ; }; + button-pwrbtn-n { + gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_LOW>; + label = "PWRBTN#"; + linux,code = ; + }; + button-slp-btn-n { gpios = <&gpio0 RK_PB3 GPIO_ACTIVE_LOW>; label = "SLP_BTN#"; @@ -85,7 +91,7 @@ sgtl5000_clk: sgtl5000-oscillator { clock-frequency = <24576000>; }; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -94,7 +100,7 @@ dc_12v: dc-12v { regulator-max-microvolt = <12000000>; }; - vcc3v3_baseboard: vcc3v3-baseboard { + vcc3v3_baseboard: regulator-vcc3v3-baseboard { compatible = "regulator-fixed"; regulator-name = "vcc3v3_baseboard"; regulator-always-on; @@ -104,7 +110,7 @@ vcc3v3_baseboard: vcc3v3-baseboard { vin-supply = <&dc_12v>; }; - vcc5v0_baseboard: vcc5v0-baseboard { + vcc5v0_baseboard: regulator-vcc5v0-baseboard { compatible = "regulator-fixed"; regulator-name = "vcc5v0_baseboard"; regulator-always-on; @@ -114,7 +120,7 @@ vcc5v0_baseboard: vcc5v0-baseboard { vin-supply = <&dc_12v>; }; - vcc5v0_otg: vcc5v0-otg-regulator { + vcc5v0_otg: regulator-vcc5v0-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>; @@ -124,7 +130,7 @@ vcc5v0_otg: vcc5v0-otg-regulator { regulator-always-on; }; - vdda_codec: vdda-codec { + vdda_codec: regulator-vdda-codec { compatible = "regulator-fixed"; regulator-name = "vdda_codec"; regulator-boot-on; @@ -133,7 +139,7 @@ vdda_codec: vdda-codec { vin-supply = <&vcc5v0_baseboard>; }; - vddd_codec: vddd-codec { + vddd_codec: regulator-vddd-codec { compatible = "regulator-fixed"; regulator-name = "vddd_codec"; regulator-boot-on; @@ -203,6 +209,8 @@ &pinctrl { buttons { haikou_keys_pin: haikou-keys-pin { rockchip,pins = + /* PWRBTN# */ + <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, /* LID_BTN */ <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>, /* BATLOW# */ diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi index 650b1ba9c19213..d12e661dfd9917 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi @@ -9,6 +9,7 @@ / { aliases { ethernet0 = &gmac; + i2c10 = &i2c10; mmc0 = &sdhci; }; @@ -39,7 +40,7 @@ clkin_gmac: external-gmac-clock { #clock-cells = <0>; }; - vcc1v2_phy: vcc1v2-phy { + vcc1v2_phy: regulator-vcc1v2-phy { compatible = "regulator-fixed"; regulator-name = "vcc1v2_phy"; regulator-always-on; @@ -49,7 +50,7 @@ vcc1v2_phy: vcc1v2-phy { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -59,7 +60,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -69,7 +70,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -78,7 +79,7 @@ vcc5v0_sys: vcc5v0-sys { regulator-max-microvolt = <5000000>; }; - vcca_0v9: vcca-0v9-regulator { + vcca_0v9: regulator-vcca-0v9 { compatible = "regulator-fixed"; regulator-name = "vcca_0v9"; regulator-always-on; @@ -88,7 +89,7 @@ vcca_0v9: vcca-0v9-regulator { vin-supply = <&vcc_1v8>; }; - vcca_1v8: vcca-1v8-regulator { + vcca_1v8: regulator-vcca-1v8 { compatible = "regulator-fixed"; regulator-name = "vcca_1v8"; regulator-always-on; @@ -98,7 +99,7 @@ vcca_1v8: vcca-1v8-regulator { vin-supply = <&vcc3v3_sys>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc5v0_sys>; @@ -205,7 +206,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc5v0_sys>; @@ -393,14 +394,25 @@ &i2c7 { clock-frequency = <400000>; fan: fan@18 { - compatible = "ti,amc6821"; + compatible = "tsd,mule", "ti,amc6821"; reg = <0x18>; - #cooling-cells = <2>; - }; - rtc_twi: rtc@6f { - compatible = "isil,isl1208"; - reg = <0x6f>; + i2c-mux { + compatible = "tsd,mule-i2c-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2c10: i2c@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + rtc_twi: rtc@6f { + compatible = "isil,isl1208"; + reg = <0x6f>; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts index 9447c8724b65a9..ce057e2db242a6 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-mezzanine.dts @@ -16,7 +16,7 @@ aliases { }; /* MP8009 PoE PD */ - poe_12v: poe-12v { + poe_12v: regulator-poe-12v { compatible = "regulator-fixed"; regulator-name = "poe_12v"; regulator-always-on; @@ -25,7 +25,7 @@ poe_12v: poe-12v { regulator-max-microvolt = <12000000>; }; - vcc3v3_ngff: vcc3v3-ngff { + vcc3v3_ngff: regulator-vcc3v3-ngff { compatible = "regulator-fixed"; regulator-name = "vcc3v3_ngff"; enable-active-high; @@ -39,7 +39,7 @@ vcc3v3_ngff: vcc3v3-ngff { vin-supply = <&sys_12v>; }; - vcc3v3_pcie: vcc3v3-pcie { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; enable-active-high; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts index 2f06bfdd70bf5e..e2e9279fa267df 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc-plus.dts @@ -26,7 +26,7 @@ / { model = "Firefly ROC-RK3399-PC-PLUS Board"; compatible = "firefly,roc-rk3399-pc-plus", "rockchip,rk3399"; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -51,7 +51,7 @@ es8388-sound { "Headphone Amp INR", "ROUT2", "Headphones", "Headphone Amp OUTL", "Headphones", "Headphone Amp OUTR"; - simple-audio-card,hp-det-gpio = <&gpio2 RK_PA6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_HIGH>; simple-audio-card,aux-devs = <&headphones_amp>; simple-audio-card,pin-switches = "Headphones"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi index d95b1cde1fc396..0393da25cdfb11 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi @@ -113,7 +113,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>; }; - vcc_vbus_typec0: vcc-vbus-typec0 { + vcc_vbus_typec0: regulator-vcc-vbus-typec0 { compatible = "regulator-fixed"; regulator-name = "vcc_vbus_typec0"; regulator-always-on; @@ -122,7 +122,7 @@ vcc_vbus_typec0: vcc-vbus-typec0 { regulator-max-microvolt = <5000000>; }; - sys_12v: sys-12v { + sys_12v: regulator-sys-12v { compatible = "regulator-fixed"; regulator-name = "sys_12v"; regulator-always-on; @@ -131,7 +131,7 @@ sys_12v: sys-12v { }; /* switched by pmic_sleep */ - vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { + vcc1v8_s3: vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s3"; regulator-always-on; @@ -141,7 +141,7 @@ vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { vin-supply = <&vcc_1v8>; }; - vcc3v0_sd: vcc3v0-sd { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD6 GPIO_ACTIVE_HIGH>; @@ -154,7 +154,7 @@ vcc3v0_sd: vcc3v0-sd { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -164,7 +164,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&sys_12v>; }; - vcca_0v9: vcca-0v9 { + vcca_0v9: regulator-vcca-0v9 { compatible = "regulator-fixed"; regulator-name = "vcca_0v9"; regulator-always-on; @@ -175,7 +175,7 @@ vcca_0v9: vcca-0v9 { }; /* Actually 3 regulators (host0, 1, 2) controlled by the same gpio */ - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; @@ -185,7 +185,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc_sys>; }; - vcc_vbus_typec1: vcc-vbus-typec1 { + vcc_vbus_typec1: regulator-vcc-vbus-typec1 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>; @@ -196,7 +196,7 @@ vcc_vbus_typec1: vcc-vbus-typec1 { vin-supply = <&vcc_sys>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio2 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -209,7 +209,7 @@ vcc_sys: vcc-sys { vin-supply = <&sys_12v>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; regulator-name = "vdd_log"; @@ -298,7 +298,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts index 475d57f64d58f5..15da5c80d25dec 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts @@ -76,7 +76,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>; }; - vcc_3v3: vcc-3v3-regulator { + vcc_3v3: regulator-vcc-3v3 { compatible = "regulator-fixed"; regulator-name = "vcc_3v3"; regulator-always-on; @@ -86,7 +86,7 @@ vcc_3v3: vcc-3v3-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_phy1: vcc3v3-phy1-regulator { + vcc3v3_phy1: regulator-vcc3v3-phy1 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_phy1"; regulator-always-on; @@ -96,7 +96,7 @@ vcc3v3_phy1: vcc3v3-phy1-regulator { vin-supply = <&vcc_3v3>; }; - vcc5v0_host1: vcc5v0-host-regulator { + vcc5v0_host1: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PD6 GPIO_ACTIVE_HIGH>; @@ -108,7 +108,7 @@ vcc5v0_host1: vcc5v0-host-regulator { vin-supply = <&vcc5v0_host0_s0>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -117,7 +117,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { regulator-max-microvolt = <5000000>; }; - vcc5v0_typec: vcc5v0-typec-regulator { + vcc5v0_typec: regulator-vcc5v0-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -129,7 +129,7 @@ vcc5v0_typec: vcc5v0-typec-regulator { vin-supply = <&vcc5v0_sys>; }; - vdd_log: vdd-log-regulator { + vdd_log: regulator-vdd-log { compatible = "regulator-fixed"; regulator-name = "vdd_log"; regulator-always-on; @@ -220,7 +220,7 @@ rk809: pmic@20 { clock-output-names = "rk808-clkout1", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>, <&i2s_8ch_mclk>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; wakeup-source; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi index 9666504cd1c146..541dca12bf1a1f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi @@ -72,7 +72,7 @@ dit_p0_0: endpoint { }; }; - vbus_typec: vbus-typec-regulator { + vbus_typec: regulator-vbus-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -83,7 +83,7 @@ vbus_typec: vbus-typec-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc12v_dcin: dc-12v { + vcc12v_dcin: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -92,7 +92,7 @@ vcc12v_dcin: dc-12v { regulator-max-microvolt = <12000000>; }; - vcc3v3_lan: vcc3v3-lan-regulator { + vcc3v3_lan: regulator-vcc3v3-lan { compatible = "regulator-fixed"; regulator-name = "vcc3v3_lan"; regulator-always-on; @@ -102,7 +102,7 @@ vcc3v3_lan: vcc3v3-lan-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio2 RK_PD2 GPIO_ACTIVE_HIGH>; @@ -114,7 +114,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -124,7 +124,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>; @@ -135,7 +135,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc-sys { + vcc5v0_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -145,7 +145,7 @@ vcc5v0_sys: vcc-sys { vin-supply = <&vcc12v_dcin>; }; - vcc_0v9: vcc-0v9 { + vcc_0v9: regulator-vcc-0v9 { compatible = "regulator-fixed"; regulator-name = "vcc_0v9"; regulator-always-on; @@ -155,7 +155,7 @@ vcc_0v9: vcc-0v9 { vin-supply = <&vcc3v3_sys>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc5v0_sys>; @@ -245,7 +245,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc5v0_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4a-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4a-plus.dts index 725ac3c1f6f650..4fc9c13dbec123 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4a-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4a-plus.dts @@ -21,5 +21,5 @@ &es8316 { }; &sound { - hp-det-gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; + hp-det-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b-plus.dts index 682e8b7297c180..9c741d1a3047e7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4b-plus.dts @@ -39,7 +39,7 @@ brcmf: wifi@1 { }; &sound { - hp-det-gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; + hp-det-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; }; &uart0 { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4c.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4c.dts index 82ad2ca6b5c2fc..5dc5505b58e2ee 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4c.dts @@ -40,7 +40,7 @@ brcmf: wifi@1 { }; &sound { - hp-det-gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; + hp-det-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; }; &spi1 { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi index ab890e7b6c59ca..7b1086682d1198 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock960.dtsi @@ -24,7 +24,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>; }; - vcc12v_dcin: vcc12v-dcin { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-min-microvolt = <12000000>; @@ -33,7 +33,7 @@ vcc12v_dcin: vcc12v-dcin { regulator-boot-on; }; - vcc1v8_s0: vcc1v8-s0 { + vcc1v8_s0: regulator-vcc1v8-s0 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s0"; regulator-min-microvolt = <1800000>; @@ -41,7 +41,7 @@ vcc1v8_s0: vcc1v8-s0 { regulator-always-on; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-min-microvolt = <5000000>; @@ -50,7 +50,7 @@ vcc5v0_sys: vcc5v0-sys { vin-supply = <&vcc12v_dcin>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-min-microvolt = <3300000>; @@ -59,7 +59,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; enable-active-high; pinctrl-names = "default"; @@ -71,7 +71,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; pinctrl-names = "default"; @@ -83,7 +83,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc_0v9: vcc-0v9 { + vcc_0v9: regulator-vcc-0v9 { compatible = "regulator-fixed"; regulator-name = "vcc_0v9"; regulator-always-on; @@ -186,7 +186,7 @@ rk808: pmic@1b { interrupts = <21 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <1>; clock-output-names = "xin32k", "rk808-clkout2"; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi index 11d99d8b34a2be..69a9d617064959 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi @@ -116,7 +116,7 @@ dit_p0_0: endpoint { }; }; - avdd: avdd-regulator { + avdd: regulator-avdd { compatible = "regulator-fixed"; regulator-name = "avdd"; regulator-min-microvolt = <11000000>; @@ -124,7 +124,7 @@ avdd: avdd-regulator { vin-supply = <&vcc3v3_s0>; }; - vcc12v_dcin: vcc12v-dcin { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -134,7 +134,7 @@ vcc12v_dcin: vcc12v-dcin { }; /* switched by pmic_sleep */ - vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { + vcc1v8_s3: vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s3"; regulator-always-on; @@ -145,7 +145,7 @@ vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { }; /* micro SD card power */ - vcc3v0_sd: vcc3v0-sd { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; @@ -162,7 +162,7 @@ regulator-state-mem { }; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PD0 GPIO_ACTIVE_HIGH>; @@ -174,7 +174,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -185,7 +185,7 @@ vcc3v3_sys: vcc3v3-sys { }; /* Actually 3 regulators (host0, 1, 2) controlled by the same gpio */ - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>; @@ -196,7 +196,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_typec: vcc5v0-typec-regulator { + vcc5v0_typec: regulator-vcc5v0-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -207,7 +207,7 @@ vcc5v0_typec: vcc5v0-typec-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -217,7 +217,7 @@ vcc5v0_sys: vcc5v0-sys { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usb: vcc5v0-usb { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -227,7 +227,7 @@ vcc5v0_usb: vcc5v0-usb { vin-supply = <&vcc12v_dcin>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc5v0_sys>; @@ -342,7 +342,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc5v0_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-s.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-s.dtsi new file mode 100644 index 00000000000000..e54f451af9f3d8 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3399-s.dtsi @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2016-2017 Fuzhou Rockchip Electronics Co., Ltd + */ + +#include "rk3399-base.dtsi" + +/ { + cluster0_opp: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <825000 825000 1250000>; + clock-latency-ns = <40000>; + }; + opp01 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <825000 825000 1250000>; + }; + opp02 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <850000 850000 1250000>; + }; + opp03 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <925000 925000 1250000>; + }; + }; + + cluster1_opp: opp-table-1 { + compatible = "operating-points-v2"; + opp-shared; + + opp00 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <825000 825000 1250000>; + clock-latency-ns = <40000>; + }; + opp01 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <825000 825000 1250000>; + }; + opp02 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <825000 825000 1250000>; + }; + opp03 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <875000 875000 1250000>; + }; + opp04 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <950000 950000 1250000>; + }; + opp05 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <1025000 1025000 1250000>; + }; + opp06 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1100000 1100000 1150000>; + }; + }; + + gpu_opp_table: opp-table-2 { + compatible = "operating-points-v2"; + + opp00 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <825000 825000 1150000>; + }; + opp01 { + opp-hz = /bits/ 64 <297000000>; + opp-microvolt = <825000 825000 1150000>; + }; + opp02 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <825000 825000 1150000>; + }; + opp03 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <875000 875000 1150000>; + }; + opp04 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <925000 925000 1150000>; + }; + opp05 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1100000 1100000 1150000>; + }; + }; +}; + +&cpu_l0 { + operating-points-v2 = <&cluster0_opp>; +}; + +&cpu_l1 { + operating-points-v2 = <&cluster0_opp>; +}; + +&cpu_l2 { + operating-points-v2 = <&cluster0_opp>; +}; + +&cpu_l3 { + operating-points-v2 = <&cluster0_opp>; +}; + +&cpu_b0 { + operating-points-v2 = <&cluster1_opp>; +}; + +&cpu_b1 { + operating-points-v2 = <&cluster1_opp>; +}; + +&gpu { + operating-points-v2 = <&gpu_opp_table>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts index 31ea3d0182c062..fdaa8472b7a720 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire-excavator.dts @@ -167,7 +167,7 @@ rt5651: rt5651@1a { reg = <0x1a>; clocks = <&cru SCLK_I2S_8CH_OUT>; clock-names = "mclk"; - hp-det-gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_LOW>; + hp-det-gpios = <&gpio4 RK_PC4 GPIO_ACTIVE_LOW>; spk-con-gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; #sound-dai-cells = <0>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi index 31832aae9ab6d3..e5c4addb483782 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi @@ -27,7 +27,7 @@ clkin_gmac: external-gmac-clock { #clock-cells = <0>; }; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -66,7 +66,7 @@ key-power { }; /* switched by pmic_sleep */ - vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { + vcc1v8_s3: vcca1v8_s3: regulator-vcc1v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcc1v8_s3"; regulator-always-on; @@ -76,7 +76,7 @@ vcc1v8_s3: vcca1v8_s3: vcc1v8-s3 { vin-supply = <&vcc_1v8>; }; - vcc3v0_sd: vcc3v0-sd { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; @@ -89,7 +89,7 @@ vcc3v0_sd: vcc3v0-sd { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -99,7 +99,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&vcc_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD1 GPIO_ACTIVE_HIGH>; @@ -110,7 +110,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc_sys>; }; - vcc5v0_typec0: vcc5v0-typec0-regulator { + vcc5v0_typec0: regulator-vcc5v0-typec0 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio2 RK_PA0 GPIO_ACTIVE_HIGH>; @@ -120,7 +120,7 @@ vcc5v0_typec0: vcc5v0-typec0-regulator { vin-supply = <&vcc_sys>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -130,7 +130,7 @@ vcc_sys: vcc-sys { vin-supply = <&dc_12v>; }; - vdd_log: vdd-log { + vdd_log: regulator-vdd-log { compatible = "pwm-regulator"; pwms = <&pwm2 0 25000 1>; pwm-supply = <&vcc_sys>; @@ -233,7 +233,7 @@ rk808: pmic@1b { clock-output-names = "xin32k", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi index 8823c924dc1d64..64e6ba3457397a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi @@ -18,7 +18,7 @@ aliases { mmc1 = &sdmmc; }; - vcc3v3_pcie: vcc-pcie-regulator { + vcc3v3_pcie: regulator-vcc-pcie { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD4 GPIO_ACTIVE_HIGH>; @@ -78,7 +78,7 @@ rk809: pmic@20 { clock-output-names = "rk808-clkout1", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc5v0_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3528-radxa-e20c.dts b/arch/arm64/boot/dts/rockchip/rk3528-radxa-e20c.dts new file mode 100644 index 00000000000000..d2cdb63d4a9d79 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3528-radxa-e20c.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd + * Copyright (c) 2024 Radxa Limited + * Copyright (c) 2024 Yao Zi + */ + +/dts-v1/; +#include "rk3528.dtsi" + +/ { + model = "Radxa E20C"; + compatible = "radxa,e20c", "rockchip,rk3528"; + + chosen { + stdout-path = "serial0:1500000n8"; + }; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3528.dtsi b/arch/arm64/boot/dts/rockchip/rk3528.dtsi new file mode 100644 index 00000000000000..e58faa985aa4d7 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3528.dtsi @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Rockchip Electronics Co., Ltd. + * Copyright (c) 2024 Yao Zi + */ + +#include +#include + +/ { + compatible = "rockchip,rk3528"; + + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + core1 { + cpu = <&cpu1>; + }; + core2 { + cpu = <&cpu2>; + }; + core3 { + cpu = <&cpu3>; + }; + }; + }; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + reg = <0x0>; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + reg = <0x1>; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu2: cpu@2 { + compatible = "arm,cortex-a53"; + reg = <0x2>; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu3: cpu@3 { + compatible = "arm,cortex-a53"; + reg = <0x3>; + device_type = "cpu"; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + xin24m: clock-xin24m { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "xin24m"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + ranges = <0x0 0xfe000000 0x0 0xfe000000 0x0 0x2000000>; + #address-cells = <2>; + #size-cells = <2>; + + gic: interrupt-controller@fed01000 { + compatible = "arm,gic-400"; + reg = <0x0 0xfed01000 0 0x1000>, + <0x0 0xfed02000 0 0x2000>, + <0x0 0xfed04000 0 0x2000>, + <0x0 0xfed06000 0 0x2000>; + interrupts = ; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <3>; + }; + + uart0: serial@ff9f0000 { + compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff9f0000 0x0 0x100>; + clock-frequency = <24000000>; + interrupts = ; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart1: serial@ff9f8000 { + compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff9f8000 0x0 0x100>; + interrupts = ; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart2: serial@ffa00000 { + compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; + reg = <0x0 0xffa00000 0x0 0x100>; + interrupts = ; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart3: serial@ffa08000 { + compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; + reg = <0x0 0xffa08000 0x0 0x100>; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart4: serial@ffa10000 { + compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; + reg = <0x0 0xffa10000 0x0 0x100>; + interrupts = ; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart5: serial@ffa18000 { + compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; + reg = <0x0 0xffa18000 0x0 0x100>; + interrupts = ; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart6: serial@ffa20000 { + compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; + reg = <0x0 0xffa20000 0x0 0x100>; + interrupts = ; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart7: serial@ffa28000 { + compatible = "rockchip,rk3528-uart", "snps,dw-apb-uart"; + reg = <0x0 0xffa28000 0x0 0x100>; + interrupts = ; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc.dtsi index a4a60e4a53d431..0aa2694552ae5e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg-arc.dtsi @@ -41,7 +41,7 @@ sound { simple-audio-card,name = "rk817_ext"; simple-audio-card,aux-devs = <&spk_amp>; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts index 9816a4ed4599e8..b80b6b593ce423 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353p.dts @@ -43,7 +43,7 @@ sound { simple-audio-card,name = "rk817_ext"; simple-audio-card,aux-devs = <&spk_amp>; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353ps.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353ps.dts index ca5284e4807d80..4fb712fe918c96 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353ps.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353ps.dts @@ -42,7 +42,7 @@ sound { simple-audio-card,name = "rk817_ext"; simple-audio-card,aux-devs = <&spk_amp>; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts index a79a5614bcc885..01588bebf9cc20 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353v.dts @@ -42,7 +42,7 @@ sound { compatible = "simple-audio-card"; simple-audio-card,name = "rk817_int"; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353vs.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353vs.dts index 90da43855d1cbc..5a30e3918c0441 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353vs.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg353vs.dts @@ -41,7 +41,7 @@ sound { compatible = "simple-audio-card"; simple-audio-card,name = "rk817_int"; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", diff --git a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts index 74cf313e063555..4dcc0ea4cf0f02 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-anbernic-rg503.dts @@ -132,7 +132,7 @@ sound { simple-audio-card,name = "rk817_ext"; simple-audio-card,aux-devs = <&spk_amp>; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", diff --git a/arch/arm64/boot/dts/rockchip/rk3566-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-base.dtsi new file mode 100644 index 00000000000000..e56e0b6ba9411a --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566-base.dtsi @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +#include "rk356x-base.dtsi" + +/ { + compatible = "rockchip,rk3566"; +}; + +&pipegrf { + compatible = "rockchip,rk3566-pipe-grf", "syscon"; +}; + +&power { + power-domain@RK3568_PD_PIPE { + reg = ; + clocks = <&cru PCLK_PIPE>; + pm_qos = <&qos_pcie2x1>, + <&qos_sata1>, + <&qos_sata2>, + <&qos_usb3_0>, + <&qos_usb3_1>; + #power-domain-cells = <0>; + }; +}; + +&usb_host0_xhci { + phys = <&usb2phy0_otg>; + phy-names = "usb2-phy"; + extcon = <&usb2phy0>; + maximum-speed = "high-speed"; +}; + +&vop { + compatible = "rockchip,rk3566-vop"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts index 7cd91f8000cb0d..ed65d312044460 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-lckfb-tspi.dts @@ -245,7 +245,7 @@ rk809: pmic@20 { interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>, <&i2s1m0_mclk>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; wakeup-source; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts b/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts index 9a2f59a351dee5..61dd71c259aac1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts @@ -52,7 +52,7 @@ sys_led: sys-led { }; }; - usb_5v: usb-5v-regulator { + usb_5v: regulator-usb-5v { compatible = "regulator-fixed"; regulator-name = "usb_5v"; regulator-always-on; @@ -61,7 +61,7 @@ usb_5v: usb-5v-regulator { regulator-max-microvolt = <5000000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -71,7 +71,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&usb_5v>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -81,7 +81,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; regulator-min-microvolt = <3300000>; @@ -92,7 +92,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb20_host: vcc5v0-usb20-host-regulator { + vcc5v0_usb20_host: regulator-vcc5v0-usb20-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio2 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -102,7 +102,7 @@ vcc5v0_usb20_host: vcc5v0-usb20-host-regulator { regulator-always-on; }; - vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { + vcc5v0_usb30_host: regulator-vcc5v0-usb30-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; @@ -197,7 +197,7 @@ rk809: pmic@20 { pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-nanopi-r3s.dts b/arch/arm64/boot/dts/rockchip/rk3566-nanopi-r3s.dts new file mode 100644 index 00000000000000..fb1f65c8688334 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566-nanopi-r3s.dts @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + * + * Copyright (c) 2024 FriendlyElec Computer Tech. Co., Ltd. + * (http://www.friendlyelec.com) + * + * Copyright (c) 2024 Tianling Shen + */ + +/dts-v1/; +#include +#include +#include +#include +#include +#include "rk3566.dtsi" + +/ { + model = "FriendlyElec NanoPi R3S"; + compatible = "friendlyarm,nanopi-r3s", "rockchip,rk3566"; + + aliases { + ethernet0 = &gmac1; + mmc0 = &sdhci; + mmc1 = &sdmmc0; + }; + + chosen: chosen { + stdout-path = "serial2:1500000n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&reset_button_pin>; + + button-reset { + label = "reset"; + gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <50>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&power_led_pin>, <&lan_led_pin>, <&wan_led_pin>; + + power_led: led-0 { + color = ; + function = LED_FUNCTION_POWER; + gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + lan_led: led-1 { + color = ; + function = LED_FUNCTION_LAN; + gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_HIGH>; + }; + + wan_led: led-2 { + color = ; + function = LED_FUNCTION_WAN; + gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_HIGH>; + }; + }; + + vcc3v3_sys: regulator-vcc3v3-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_sys: regulator-vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vdd_usbc>; + }; + + vcc5v0_usb: regulator-vcc5v0_usb { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_usb_host_en>; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; + + vdd_usbc: regulator-vdd-usbc { + compatible = "regulator-fixed"; + regulator-name = "vdd_usbc"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; +}; + +&combphy1 { + status = "okay"; +}; + +&combphy2 { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu1 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu2 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu3 { + cpu-supply = <&vdd_cpu>; +}; + +&gmac1 { + assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1>; + assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru CLK_MAC1_2TOP>; + assigned-clock-rates = <0>, <125000000>; + clock_in_out = "output"; + phy-mode = "rgmii-id"; + phy-handle = <&rgmii_phy1>; + pinctrl-names = "default"; + pinctrl-0 = <&gmac1m0_miim + &gmac1m0_tx_bus2_level3 + &gmac1m0_rx_bus2 + &gmac1m0_rgmii_clk_level2 + &gmac1m0_rgmii_bus_level3>; + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu>; + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + vdd_cpu: regulator@1c { + compatible = "tcs,tcs4525"; + reg = <0x1c>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1150000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + rk809: pmic@20 { + compatible = "rockchip,rk809"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = ; + #clock-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int>; + system-power-controller; + vcc1-supply = <&vcc3v3_sys>; + vcc2-supply = <&vcc3v3_sys>; + vcc3-supply = <&vcc3v3_sys>; + vcc4-supply = <&vcc3v3_sys>; + vcc5-supply = <&vcc3v3_sys>; + vcc6-supply = <&vcc3v3_sys>; + vcc7-supply = <&vcc3v3_sys>; + vcc8-supply = <&vcc3v3_sys>; + vcc9-supply = <&vcc3v3_sys>; + wakeup-source; + + regulators { + vdd_logic: DCDC_REG1 { + regulator-name = "vdd_logic"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_gpu: DCDC_REG2 { + regulator-name = "vdd_gpu"; + regulator-always-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vdd_npu: DCDC_REG4 { + regulator-name = "vdd_npu"; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8: DCDC_REG5 { + regulator-name = "vcc_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda0v9_image: LDO_REG1 { + regulator-name = "vdda0v9_image"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <950000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda_0v9: LDO_REG2 { + regulator-name = "vdda_0v9"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda0v9_pmu: LDO_REG3 { + regulator-name = "vdda0v9_pmu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vccio_acodec: LDO_REG4 { + regulator-name = "vccio_acodec"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd: LDO_REG5 { + regulator-name = "vccio_sd"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_pmu: LDO_REG6 { + regulator-name = "vcc3v3_pmu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcca_1v8: LDO_REG7 { + regulator-name = "vcca_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca1v8_pmu: LDO_REG8 { + regulator-name = "vcca1v8_pmu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcca1v8_image: LDO_REG9 { + regulator-name = "vcca1v8_image"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3: SWITCH_REG1 { + regulator-name = "vcc_3v3"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_sd: SWITCH_REG2 { + regulator-name = "vcc3v3_sd"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&i2c1 { + status = "okay"; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "hym8563"; + pinctrl-names = "default"; + pinctrl-0 = <&hym8563_int>; + interrupt-parent = <&gpio0>; + interrupts = ; + wakeup-source; + }; +}; + +&mdio1 { + rgmii_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + interrupt-parent = <&gpio4>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <ð_phy_reset_pin>; + reset-assert-us = <20000>; + reset-deassert-us = <100000>; + reset-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_LOW>; + }; +}; + +&pcie2x1 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_reset_h>; + reset-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&pinctrl { + gpio-leds { + lan_led_pin: lan-led-pin { + rockchip,pins = <3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + power_led_pin: power-led-pin { + rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wan_led_pin: wan-led-pin { + rockchip,pins = <3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + gmac { + eth_phy_reset_pin: eth-phy-reset-pin { + rockchip,pins = <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + pcie { + pcie_reset_h: pcie-reset-h { + rockchip,pins = <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + pmic { + pmic_int: pmic-int { + rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + rockchip-key { + reset_button_pin: reset-button-pin { + rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + rtc { + hym8563_int: hym8563-int { + rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + usb { + vcc5v0_usb_host_en: vcc5v0-usb-host-en { + rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pmu_io_domains { + pmuio1-supply = <&vcc3v3_pmu>; + pmuio2-supply = <&vcc3v3_pmu>; + vccio1-supply = <&vccio_acodec>; + vccio2-supply = <&vcc_1v8>; + vccio3-supply = <&vccio_sd>; + vccio4-supply = <&vcc_3v3>; + vccio5-supply = <&vcc_1v8>; + vccio6-supply = <&vcc_3v3>; + vccio7-supply = <&vcc_3v3>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + max-frequency = <200000000>; + mmc-hs200-1_8v; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd &emmc_datastrobe>; + status = "okay"; +}; + +&sdmmc0 { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + no-sdio; + no-mmc; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>; + sd-uhs-sdr50; + vmmc-supply = <&vcc3v3_sd>; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&tsadc { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb2phy0 { + status = "okay"; +}; + +&usb2phy0_host { + phy-supply = <&vcc5v0_usb>; + status = "okay"; +}; + +&usb2phy0_otg { + status = "okay"; +}; + +&usb_host0_xhci { + extcon = <&usb2phy0>; + status = "okay"; +}; + +&usb_host1_xhci { + status = "okay"; +}; + +&vop { + assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>; + assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>; + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi index 0131f2cdd312f3..2d3ae154482248 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-pinenote.dtsi @@ -129,7 +129,7 @@ link1_codec: codec { }; }; - vbat_4g: vbat-4g { + vbat_4g: regulator-vbat-4g { compatible = "regulator-fixed"; regulator-name = "vbat_4g"; regulator-min-microvolt = <3800000>; @@ -138,7 +138,7 @@ vbat_4g: vbat-4g { vin-supply = <&vbat_4g_en>; }; - vcc_1v8: vcc-1v8 { + vcc_1v8: regulator-vcc-1v8 { compatible = "regulator-fixed"; regulator-name = "vcc_1v8"; regulator-always-on; @@ -148,7 +148,7 @@ vcc_1v8: vcc-1v8 { vin-supply = <&vcc_1v8_en>; }; - vcc_bat: vcc-bat { + vcc_bat: regulator-vcc-bat { compatible = "regulator-fixed"; regulator-name = "vcc_bat"; regulator-always-on; @@ -156,7 +156,7 @@ vcc_bat: vcc-bat { regulator-max-microvolt = <3800000>; }; - vcc_hall_3v3: vcc-hall-3v3 { + vcc_hall_3v3: regulator-vcc-hall-3v3 { compatible = "regulator-fixed"; regulator-name = "vcc_hall_3v3"; regulator-always-on; @@ -165,7 +165,7 @@ vcc_hall_3v3: vcc-hall-3v3 { vin-supply = <&vcc_sys>; }; - vcc_sys: vcc-sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -174,7 +174,7 @@ vcc_sys: vcc-sys { vin-supply = <&vcc_bat>; }; - vcc_wl: vcc-wl { + vcc_wl: regulator-vcc-wl { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; @@ -186,7 +186,7 @@ vcc_wl: vcc-wl { vin-supply = <&vcc_bat>; }; - vdda_0v9: vdda-0v9 { + vdda_0v9: regulator-vdda-0v9 { compatible = "regulator-fixed"; regulator-name = "vdda_0v9"; regulator-always-on; @@ -244,7 +244,7 @@ rk817: pmic@20 { #clock-cells = <1>; pinctrl-0 = <&i2s1m0_mclk>, <&pmic_int_l>, <&pmic_sleep>; pinctrl-names = "default"; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; wakeup-source; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-pinetab2.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-pinetab2.dtsi index db40281eafbe5d..26cf765a72973a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-pinetab2.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-pinetab2.dtsi @@ -121,7 +121,7 @@ rk817-sound { "Internal Speakers", "Speaker Amplifier OUTR", "Speaker Amplifier INL", "HPOL", "Speaker Amplifier INR", "HPOR"; - simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>; + simple-audio-card,hp-det-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>; simple-audio-card,aux-devs = <&speaker_amp>; simple-audio-card,pin-switches = "Internal Speakers"; @@ -143,7 +143,7 @@ speaker_amp: speaker-amplifier { VCC-supply = <&vcc_bat>; }; - vcc_3v3: vcc-3v3-regulator { + vcc_3v3: regulator-vcc-3v3 { compatible = "regulator-fixed"; regulator-name = "vcc_3v3"; regulator-always-on; @@ -153,7 +153,7 @@ vcc_3v3: vcc-3v3-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_minipcie: vcc3v3-minipcie-regulator { + vcc3v3_minipcie: regulator-vcc3v3-minipcie { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PC3 GPIO_ACTIVE_HIGH>; @@ -165,7 +165,7 @@ vcc3v3_minipcie: vcc3v3-minipcie-regulator { vin-supply = <&vcc_sys>; }; - vcc3v3_sd: vcc3v3-sd-regulator { + vcc3v3_sd: regulator-vcc3v3-sd { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -176,7 +176,7 @@ vcc3v3_sd: vcc3v3-sd-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc5v0_flashled: vcc5v0-flashled-regulator { + vcc5v0_flashled: regulator-vcc5v0-flashled { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -188,7 +188,7 @@ vcc5v0_flashled: vcc5v0-flashled-regulator { vin-supply = <&vcc5v_midu>; }; - vcc5v0_usb_host0: vcc5v0-usb-host0-regulator { + vcc5v0_usb_host0: regulator-vcc5v0-usb-host0 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_HIGH>; @@ -200,7 +200,7 @@ vcc5v0_usb_host0: vcc5v0-usb-host0-regulator { vin-supply = <&vcc5v_midu>; }; - vcc5v0_usb_host2: vcc5v0-usb-host2-regulator { + vcc5v0_usb_host2: regulator-vcc5v0-usb-host2 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -212,14 +212,14 @@ vcc5v0_usb_host2: vcc5v0-usb-host2-regulator { vin-supply = <&vcc5v_midu>; }; - vcc_bat: vcc-bat-regulator { + vcc_bat: regulator-vcc-bat { compatible = "regulator-fixed"; regulator-name = "vcc_bat"; regulator-always-on; regulator-boot-on; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -227,7 +227,7 @@ vcc_sys: vcc-sys-regulator { vin-supply = <&vcc_bat>; }; - vdd1v2_dvp: vdd1v2-dvp-regulator { + vdd1v2_dvp: regulator-vdd1v2-dvp { compatible = "regulator-fixed"; regulator-name = "vdd1v2_dvp"; regulator-min-microvolt = <1200000>; @@ -370,7 +370,7 @@ rk817: pmic@20 { #clock-cells = <1>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>, <&i2s1m0_mclk>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; wakeup-source; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb20sx.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb20sx.dts new file mode 100644 index 00000000000000..9b70026ce4a58b --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb20sx.dts @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include "rk3566-powkiddy-rk2023.dtsi" + +/ { + model = "Powkiddy RGB20SX"; + compatible = "powkiddy,rgb20sx", "rockchip,rk3566"; + + chosen: chosen { + stdout-path = "serial2:1500000n8"; + }; + + adc_keys: adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <60>; + + /* + * Button is labelled as FN, but according to input + * guidelines it should be mode. + */ + button-mode { + label = "MODE"; + linux,code = ; + press-threshold-microvolt = <1750>; + }; + }; +}; + +&battery { + charge-full-design-microamp-hours = <5000000>; +}; + +&bluetooth { + compatible = "realtek,rtl8723ds-bt"; +}; + +&cru { + assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>, + <&pmucru PLL_PPLL>, <&cru PLL_VPLL>; + assigned-clock-rates = <32768>, <1200000000>, + <200000000>, <292500000>; +}; + +&dsi0 { + panel: panel@0 { + compatible = "powkiddy,rgb30-panel"; + reg = <0>; + backlight = <&backlight>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_rst>; + reset-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>; + vcc-supply = <&vcc3v3_lcd0_n>; + iovcc-supply = <&vcc3v3_lcd0_n>; + + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; + }; + }; +}; + +&i2c0 { + vdd_cpu: regulator@1c { + compatible = "tcs,tcs4525"; + reg = <0x1c>; + fcs,suspend-voltage-selector = <1>; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1390000>; + regulator-name = "vdd_cpu"; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sys>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&uart2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-x55.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-x55.dts index 5a648db41f355e..e274f7bf9dfb3d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-x55.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-x55.dts @@ -269,7 +269,7 @@ sound { simple-audio-card,name = "rk817_ext"; simple-audio-card,aux-devs = <&spk_amp>; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Microphone", "Mic Jack", diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts index 37a1303d9a34f7..98e75df8b15823 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts @@ -117,7 +117,7 @@ simple-audio-card,codec { }; }; - vcc12v_dcin: vcc12v_dcin { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -130,7 +130,7 @@ vcc12v_dcin: vcc12v_dcin { * With no battery attached, also feeds vcc_bat+ * via ON/OFF_BAT jumper */ - vbus: vbus { + vbus: regulator-vbus { compatible = "regulator-fixed"; regulator-name = "vbus"; regulator-always-on; @@ -140,7 +140,7 @@ vbus: vbus { vin-supply = <&vcc12v_dcin>; }; - vcc3v3_pcie_p: vcc3v3-pcie-p-regulator { + vcc3v3_pcie_p: regulator-vcc3v3-pcie-p { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; @@ -152,7 +152,7 @@ vcc3v3_pcie_p: vcc3v3-pcie-p-regulator { vin-supply = <&vcc_3v3>; }; - vcc5v0_usb: vcc5v0_usb { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -166,7 +166,7 @@ vcc5v0_usb: vcc5v0_usb { * the host ports are sourced from vcc5v0_usb * the otg port is sourced from vcc5v0_midu */ - vcc5v0_usb20_host: vcc5v0_usb20_host { + vcc5v0_usb20_host: regulator-vcc5v0-usb20-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>; @@ -178,7 +178,7 @@ vcc5v0_usb20_host: vcc5v0_usb20_host { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_usb20_otg: vcc5v0_usb20_otg { + vcc5v0_usb20_otg: regulator-vcc5v0-usb20-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>; @@ -188,7 +188,7 @@ vcc5v0_usb20_otg: vcc5v0_usb20_otg { vin-supply = <&dcdc_boost>; }; - vcc3v3_sd: vcc3v3_sd { + vcc3v3_sd: regulator-vcc3v3-sd { compatible = "regulator-fixed"; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; @@ -201,7 +201,7 @@ vcc3v3_sd: vcc3v3_sd { }; /* sourced from vbus and vcc_bat+ via rk817 sw5 */ - vcc_sys: vcc_sys { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -212,7 +212,7 @@ vcc_sys: vcc_sys { }; /* sourced from vcc_sys, sdio module operates internally at 3.3v */ - vcc_wl: vcc_wl { + vcc_wl: regulator-vcc-wl { compatible = "regulator-fixed"; regulator-name = "vcc_wl"; regulator-always-on; @@ -347,7 +347,7 @@ rk817: pmic@20 { #clock-cells = <1>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>, <&i2s1m0_mclk>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; wakeup-source; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts index c164074ddf54c9..24928a129446e2 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts @@ -81,7 +81,7 @@ sdio_pwrseq: sdio-pwrseq { power-off-delay-us = <5000000>; }; - vcc3v3_pcie_p: vcc3v3-pcie-p-regulator { + vcc3v3_pcie_p: regulator-vcc3v3-pcie-p { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -93,7 +93,7 @@ vcc3v3_pcie_p: vcc3v3-pcie-p-regulator { vin-supply = <&vcc_3v3>; }; - vcc5v0_in: vcc5v0-in-regulator { + vcc5v0_in: regulator-vcc5v0-in { compatible = "regulator-fixed"; regulator-name = "vcc5v0_in"; regulator-always-on; @@ -102,7 +102,7 @@ vcc5v0_in: vcc5v0-in-regulator { regulator-max-microvolt = <5000000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -112,7 +112,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc5v0_in>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-min-microvolt = <3300000>; @@ -121,7 +121,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { + vcc5v0_usb30_host: regulator-vcc5v0-usb30-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb30_host"; enable-active-high; @@ -134,7 +134,7 @@ vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb_otg"; enable-active-high; @@ -255,7 +255,7 @@ rk809: pmic@20 { pinctrl-names = "default"; pinctrl-0 = <&pmic_int>, <&i2s1m0_mclk>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; wakeup-source; #clock-cells = <1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3-io.dts b/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3-io.dts index 3ae24e39450a2d..b5b253f04cdf52 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3-io.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3-io.dts @@ -53,7 +53,7 @@ led-1 { }; }; - vcc5v0_usb30: vcc5v0-usb30-regulator { + vcc5v0_usb30: regulator-vcc5v0-usb30 { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb30"; enable-active-high; @@ -66,7 +66,7 @@ vcc5v0_usb30: vcc5v0-usb30-regulator { vin-supply = <&vcc_sys>; }; - vcca1v8_image: vcca1v8-image-regulator { + vcca1v8_image: regulator-vcca1v8-image { compatible = "regulator-fixed"; regulator-name = "vcca1v8_image"; regulator-always-on; @@ -76,7 +76,7 @@ vcca1v8_image: vcca1v8-image-regulator { vin-supply = <&vcc_1v8_p>; }; - vdda0v9_image: vdda0v9-image-regulator { + vdda0v9_image: regulator-vdda0v9-image { compatible = "regulator-fixed"; regulator-name = "vcca0v9_image"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi index 1e36f73840dad2..8453f06c261ca7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3.dtsi @@ -28,7 +28,7 @@ led-0 { }; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -37,7 +37,7 @@ vcc_sys: vcc-sys-regulator { regulator-max-microvolt = <5000000>; }; - vcc_1v8: vcc-1v8-regulator { + vcc_1v8: regulator-vcc-1v8 { compatible = "regulator-fixed"; regulator-name = "vcc_1v8"; regulator-always-on; @@ -47,7 +47,7 @@ vcc_1v8: vcc-1v8-regulator { vin-supply = <&vcc_1v8_p>; }; - vcc_3v3: vcc-3v3-regulator { + vcc_3v3: regulator-vcc-3v3 { compatible = "regulator-fixed"; regulator-name = "vcc_3v3"; regulator-always-on; @@ -57,7 +57,7 @@ vcc_3v3: vcc-3v3-regulator { vin-supply = <&vcc3v3_sys>; }; - vcca_1v8: vcca-1v8-regulator { + vcca_1v8: regulator-vcca-1v8 { compatible = "regulator-fixed"; regulator-name = "vcca_1v8"; regulator-always-on; @@ -127,7 +127,7 @@ rk817: pmic@20 { interrupts = ; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-radxa-zero-3.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-radxa-zero-3.dtsi index de390d92c35e30..1ee5d96a46a1b9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-radxa-zero-3.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-radxa-zero-3.dtsi @@ -3,7 +3,7 @@ #include #include #include -#include "rk3566.dtsi" +#include "rk3566t.dtsi" / { chosen { diff --git a/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts b/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts index 67e7801bd48964..7e499064e03579 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts @@ -80,7 +80,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>; }; - usb_5v: usb-5v-regulator { + usb_5v: regulator-usb-5v { compatible = "regulator-fixed"; regulator-name = "usb_5v"; regulator-always-on; @@ -89,7 +89,7 @@ usb_5v: usb-5v-regulator { regulator-max-microvolt = <5000000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -99,7 +99,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&usb_5v>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>; @@ -111,7 +111,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-min-microvolt = <3300000>; @@ -120,7 +120,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { + vcc5v0_usb30_host: regulator-vcc5v0-usb30-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb30_host"; enable-active-high; @@ -133,7 +133,7 @@ vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb_otg"; enable-active-high; @@ -253,7 +253,7 @@ rk809: pmic@20 { clocks = <&cru I2S1_MCLKOUT_TX>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>, <&i2s1m0_mclk>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; #clock-cells = <1>; #sound-dai-cells = <0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts b/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts index f2cc086e5001a6..53e71528e4c4c7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-rock-3c.dts @@ -5,7 +5,7 @@ #include #include #include -#include "rk3566.dtsi" +#include "rk3566t.dtsi" / { model = "Radxa ROCK 3C"; @@ -64,7 +64,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_LOW>; }; - vcc5v_dcin: vcc5v-dcin-regulator { + vcc5v_dcin: regulator-vcc5v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc5v_dcin"; regulator-always-on; @@ -73,7 +73,7 @@ vcc5v_dcin: vcc5v-dcin-regulator { regulator-max-microvolt = <5000000>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -85,7 +85,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -95,7 +95,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -105,7 +105,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc5v_dcin>; }; - vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { + vcc5v0_usb30_host: regulator-vcc5v0-usb30-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -117,7 +117,7 @@ vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; @@ -129,7 +129,7 @@ vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc_cam: vcc-cam-regulator { + vcc_cam: regulator-vcc-cam { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>; @@ -145,7 +145,7 @@ regulator-state-mem { }; }; - vcc_mipi: vcc-mipi-regulator { + vcc_mipi: regulator-vcc-mipi { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts index fdbb4a6a19d85b..b64d0c957ef63f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts @@ -18,7 +18,7 @@ aliases { }; /* labeled VCC3V0_SD in schematic to not conflict with PMIC regulator */ - vcc3v0_sd: vcc3v0-sd-regulator { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; regulator-name = "vcc3v0_sd"; regulator-always-on; @@ -29,7 +29,7 @@ vcc3v0_sd: vcc3v0-sd-regulator { }; /* labeled VCC_SSD in schematic */ - vcc3v3_pcie_p: vcc3v3-pcie-regulator { + vcc3v3_pcie_p: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie_p"; regulator-always-on; @@ -39,7 +39,7 @@ vcc3v3_pcie_p: vcc3v3-pcie-regulator { vin-supply = <&vbus>; }; - vcc5v_dcin: vcc5v-dcin-regulator { + vcc5v_dcin: regulator-vcc5v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc5v_dcin"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts index 2b6f0df477b67f..38155316846dfe 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts @@ -13,7 +13,7 @@ aliases { }; /* labeled +12v in schematic */ - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -23,7 +23,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { }; /* labeled +5v in schematic */ - vcc_5v: vcc-5v-regulator { + vcc_5v: regulator-vcc-5v { compatible = "regulator-fixed"; regulator-name = "vcc_5v"; regulator-always-on; @@ -33,7 +33,7 @@ vcc_5v: vcc-5v-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc_sd_pwr: vcc-sd-pwr-regulator { + vcc_sd_pwr: regulator-vcc-sd-pwr { compatible = "regulator-fixed"; regulator-name = "vcc_sd_pwr"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts index 9a6a63277c3dca..2e130eef54df9e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts @@ -13,7 +13,7 @@ aliases { }; /* labeled DCIN_12V in schematic */ - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -22,7 +22,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -36,7 +36,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { * Labelled VCC3V0_SD in schematic to not conflict with PMIC * regulator, it's 3.3v in actuality */ - vcc3v0_sd: vcc3v0-sd-regulator { + vcc3v0_sd: regulator-vcc3v0-sd { compatible = "regulator-fixed"; regulator-name = "vcc3v0_sd"; regulator-always-on; @@ -46,7 +46,7 @@ vcc3v0_sd: vcc3v0-sd-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; regulator-always-on; @@ -56,7 +56,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc12v_pcie: vcc12v-pcie-regulator { + vcc12v_pcie: regulator-vcc12v-pcie { compatible = "regulator-fixed"; regulator-name = "vcc12v_pcie"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi index e42c474ef4ad2d..6b9aa0e1ad2102 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi @@ -74,7 +74,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio2 RK_PC2 GPIO_ACTIVE_LOW>; }; - vbus: vbus-regulator { + vbus: regulator-vbus { compatible = "regulator-fixed"; regulator-name = "vbus"; regulator-always-on; @@ -84,7 +84,7 @@ vbus: vbus-regulator { }; /* sourced from vbus, vbus is provided by the carrier board */ - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -94,7 +94,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vbus>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -213,7 +213,7 @@ rk809: pmic@20 { clock-output-names = "rk808-clkout1", "rk808-clkout2"; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566.dtsi b/arch/arm64/boot/dts/rockchip/rk3566.dtsi index 6c4b17d27bdc52..3fcca79279f7cd 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566.dtsi @@ -1,35 +1,107 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) -#include "rk356x.dtsi" +#include "rk3566-base.dtsi" / { - compatible = "rockchip,rk3566"; + cpu0_opp_table: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + opp-suspend; + }; + + opp-1104000000 { + opp-hz = /bits/ 64 <1104000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-1416000000 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <1025000 1025000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <1100000 1100000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <1150000 1150000 1150000>; + clock-latency-ns = <40000>; + }; + }; + + gpu_opp_table: opp-table-1 { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1000000>; + }; + + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <950000 950000 1000000>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1000000 1000000 1000000>; + }; + }; }; -&pipegrf { - compatible = "rockchip,rk3566-pipe-grf", "syscon"; +&cpu0 { + operating-points-v2 = <&cpu0_opp_table>; }; -&power { - power-domain@RK3568_PD_PIPE { - reg = ; - clocks = <&cru PCLK_PIPE>; - pm_qos = <&qos_pcie2x1>, - <&qos_sata1>, - <&qos_sata2>, - <&qos_usb3_0>, - <&qos_usb3_1>; - #power-domain-cells = <0>; - }; +&cpu1 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&cpu2 { + operating-points-v2 = <&cpu0_opp_table>; }; -&usb_host0_xhci { - phys = <&usb2phy0_otg>; - phy-names = "usb2-phy"; - extcon = <&usb2phy0>; - maximum-speed = "high-speed"; +&cpu3 { + operating-points-v2 = <&cpu0_opp_table>; }; -&vop { - compatible = "rockchip,rk3566-vop"; +&gpu { + operating-points-v2 = <&gpu_opp_table>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3566t.dtsi b/arch/arm64/boot/dts/rockchip/rk3566t.dtsi new file mode 100644 index 00000000000000..cd89bd3b125b84 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566t.dtsi @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +#include "rk3566-base.dtsi" + +/ { + cpu0_opp_table: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + opp-suspend; + }; + + opp-1104000000 { + opp-hz = /bits/ 64 <1104000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-1416000000 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <1025000 1025000 1150000>; + clock-latency-ns = <40000>; + }; + }; + + gpu_opp_table: opp-table-1 { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1000000>; + }; + + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <950000 950000 1000000>; + }; + }; +}; + +&cpu0 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&cpu1 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&cpu2 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&cpu3 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&gpu { + operating-points-v2 = <&gpu_opp_table>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts b/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts index c87fad2c34cba3..4d3ebe50b90ba3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts @@ -46,7 +46,7 @@ green_led: led-1 { }; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -73,7 +73,7 @@ ir-receiver { pinctrl-0 = <&ir_receiver_pin>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -83,7 +83,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -93,7 +93,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&dc_12v>; }; - pcie30_avdd0v9: pcie30-avdd0v9-regulator { + pcie30_avdd0v9: regulator-pcie30-avdd0v9 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd0v9"; regulator-always-on; @@ -103,7 +103,7 @@ pcie30_avdd0v9: pcie30-avdd0v9-regulator { vin-supply = <&vcc3v3_sys>; }; - pcie30_avdd1v8: pcie30-avdd1v8-regulator { + pcie30_avdd1v8: regulator-pcie30-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-always-on; @@ -114,7 +114,7 @@ pcie30_avdd1v8: pcie30-avdd1v8-regulator { }; /* pi6c pcie clock generator feeds both ports */ - vcc3v3_pi6c_05: vcc3v3-pi6c-05-regulator { + vcc3v3_pi6c_05: regulator-vcc3v3-pi6c-05 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; regulator-min-microvolt = <3300000>; @@ -126,7 +126,7 @@ vcc3v3_pi6c_05: vcc3v3-pi6c-05-regulator { }; /* actually fed by vcc3v3_sys, dependent on pi6c clock generator */ - vcc3v3_minipcie: vcc3v3-minipcie-regulator { + vcc3v3_minipcie: regulator-vcc3v3-minipcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_minipcie"; regulator-min-microvolt = <3300000>; @@ -140,7 +140,7 @@ vcc3v3_minipcie: vcc3v3-minipcie-regulator { }; /* actually fed by vcc3v3_sys, dependent on pi6c clock generator */ - vcc3v3_ngff: vcc3v3-ngff-regulator { + vcc3v3_ngff: regulator-vcc3v3-ngff { compatible = "regulator-fixed"; regulator-name = "vcc3v3_ngff"; regulator-min-microvolt = <3300000>; @@ -153,7 +153,7 @@ vcc3v3_ngff: vcc3v3-ngff-regulator { vin-supply = <&vcc3v3_pi6c_05>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -163,7 +163,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_usb_host: vcc5v0-usb-host-regulator { + vcc5v0_usb_host: regulator-vcc5v0-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -175,7 +175,7 @@ vcc5v0_usb_host: vcc5v0-usb-host-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -291,7 +291,7 @@ rk809: pmic@20 { #clock-cells = <1>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc3v3_sys>; vcc2-supply = <&vcc3v3_sys>; vcc3-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts index 8c3ab07d380797..b073a4d03e4fbc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-evb1-v10.dts @@ -26,7 +26,7 @@ chosen: chosen { stdout-path = "serial2:1500000n8"; }; - dc_12v: dc-12v { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -73,7 +73,7 @@ simple-audio-card,codec { }; }; - vcc3v3_sys: vcc3v3-sys { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -83,7 +83,7 @@ vcc3v3_sys: vcc3v3-sys { vin-supply = <&dc_12v>; }; - vcc5v0_sys: vcc5v0-sys { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -93,7 +93,7 @@ vcc5v0_sys: vcc5v0-sys { vin-supply = <&dc_12v>; }; - vcc5v0_usb: vcc5v0-usb { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -103,7 +103,7 @@ vcc5v0_usb: vcc5v0-usb { vin-supply = <&dc_12v>; }; - vcc5v0_usb_host: vcc5v0-usb-host { + vcc5v0_usb_host: regulator-vcc5v0-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -115,7 +115,7 @@ vcc5v0_usb_host: vcc5v0-usb-host { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -127,7 +127,7 @@ vcc5v0_usb_otg: vcc5v0-usb-otg { vin-supply = <&vcc5v0_usb>; }; - vcc3v3_lcd0_n: vcc3v3-lcd0-n { + vcc3v3_lcd0_n: regulator-vcc3v3-lcd0-n { compatible = "regulator-fixed"; regulator-name = "vcc3v3_lcd0_n"; regulator-min-microvolt = <3300000>; @@ -143,7 +143,7 @@ regulator-state-mem { }; }; - vcc3v3_lcd1_n: vcc3v3-lcd1-n { + vcc3v3_lcd1_n: regulator-vcc3v3-lcd1-n { compatible = "regulator-fixed"; regulator-name = "vcc3v3_lcd1_n"; regulator-min-microvolt = <3300000>; @@ -275,7 +275,7 @@ rk809: pmic@20 { clocks = <&cru I2S1_MCLKOUT_TX>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>, <&i2s1m0_mclk>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; vcc1-supply = <&vcc3v3_sys>; vcc2-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dtsi index 25c49bdbadbcba..b0ac1e58a352c4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568-fastrhino-r66s.dtsi @@ -39,7 +39,7 @@ status_led: led-status { }; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -48,7 +48,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; regulator-always-on; @@ -58,7 +58,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -68,7 +68,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -78,7 +78,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -152,7 +152,7 @@ rk809: pmic@20 { #clock-cells = <1>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc3v3_sys>; vcc2-supply = <&vcc3v3_sys>; vcc3-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts b/arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts index b505a4537ee8ca..a7fe5655a85d66 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-lubancat-2.dts @@ -51,7 +51,7 @@ hdmi_con_in: endpoint { }; }; - dc_5v: dc-5v-regulator { + dc_5v: regulator-dc-5v { compatible = "regulator-fixed"; regulator-name = "dc_5v"; regulator-always-on; @@ -60,7 +60,7 @@ dc_5v: dc-5v-regulator { regulator-max-microvolt = <5000000>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -70,7 +70,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -80,7 +80,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&dc_5v>; }; - vcc3v3_m2_pcie: vcc3v3-m2-pcie-regulator { + vcc3v3_m2_pcie: regulator-vcc3v3-m2-pcie { compatible = "regulator-fixed"; regulator-name = "m2_pcie_3v3"; enable-active-high; @@ -93,7 +93,7 @@ vcc3v3_m2_pcie: vcc3v3-m2-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_mini_pcie: vcc3v3-mini-pcie-regulator { + vcc3v3_mini_pcie: regulator-vcc3v3-mini-pcie { compatible = "regulator-fixed"; regulator-name = "minipcie_3v3"; enable-active-high; @@ -106,7 +106,7 @@ vcc3v3_mini_pcie: vcc3v3-mini-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb20_host: vcc5v0-usb20-host-regulator { + vcc5v0_usb20_host: regulator-vcc5v0-usb20-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb20_host"; enable-active-high; @@ -115,7 +115,7 @@ vcc5v0_usb20_host: vcc5v0-usb20-host-regulator { pinctrl-names = "default"; }; - vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { + vcc5v0_usb30_host: regulator-vcc5v0-usb30-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb30_host"; enable-active-high; @@ -124,7 +124,7 @@ vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { pinctrl-names = "default"; }; - vcc5v0_otg_vbus: vcc5v0-otg-vbus-regulator { + vcc5v0_otg_vbus: regulator-vcc5v0-otg-vbus { compatible = "regulator-fixed"; regulator-name = "vcc5v0_otg_vbus"; enable-active-high; @@ -223,7 +223,7 @@ rk809: pmic@20 { clocks = <&cru I2S1_MCLKOUT_TX>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; vcc1-supply = <&vcc3v3_sys>; vcc2-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-nanopi-r5s.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-nanopi-r5s.dtsi index 93189f83064006..00c479aa18711a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-nanopi-r5s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568-nanopi-r5s.dtsi @@ -35,7 +35,7 @@ hdmi_con_in: endpoint { }; }; - vdd_usbc: vdd-usbc-regulator { + vdd_usbc: regulator-vdd-usbc { compatible = "regulator-fixed"; regulator-name = "vdd_usbc"; regulator-always-on; @@ -44,7 +44,7 @@ vdd_usbc: vdd-usbc-regulator { regulator-max-microvolt = <5000000>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -54,7 +54,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vdd_usbc>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -64,7 +64,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vdd_usbc>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; regulator-min-microvolt = <3300000>; @@ -75,7 +75,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -85,7 +85,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&vdd_usbc>; }; - vcc5v0_usb_host: vcc5v0-usb-host-regulator { + vcc5v0_usb_host: regulator-vcc5v0-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -99,7 +99,7 @@ vcc5v0_usb_host: vcc5v0-usb-host-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -111,7 +111,7 @@ vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { vin-supply = <&vcc5v0_usb>; }; - pcie30_avdd0v9: pcie30-avdd0v9-regulator { + pcie30_avdd0v9: regulator-pcie30-avdd0v9 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd0v9"; regulator-always-on; @@ -121,7 +121,7 @@ pcie30_avdd0v9: pcie30-avdd0v9-regulator { vin-supply = <&vcc3v3_sys>; }; - pcie30_avdd1v8: pcie30-avdd1v8-regulator { + pcie30_avdd1v8: regulator-pcie30-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-always-on; @@ -215,7 +215,7 @@ rk809: pmic@20 { #clock-cells = <1>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc3v3_sys>; vcc2-supply = <&vcc3v3_sys>; vcc3-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts b/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts index 6a02db4f073f29..0f844806ec542e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-odroid-m1.dts @@ -29,7 +29,7 @@ chosen { stdout-path = "serial2:1500000n8"; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -84,7 +84,7 @@ rk809-sound { pinctrl-0 = <&hp_det_pin>; simple-audio-card,name = "Analog RK817"; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,widgets = "Headphone", "Headphones", @@ -103,7 +103,7 @@ simple-audio-card,codec { }; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; enable-active-high; @@ -116,7 +116,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -126,7 +126,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -136,7 +136,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_usb_host: vcc5v0-usb-host-regulator { + vcc5v0_usb_host: regulator-vcc5v0-usb-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb_host"; enable-active-high; @@ -148,7 +148,7 @@ vcc5v0_usb_host: vcc5v0-usb-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb_otg"; enable-active-high; @@ -273,7 +273,7 @@ rk809: pmic@20 { clocks = <&cru I2S1_MCLKOUT_TX>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>, <&i2s1m0_mclk>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; vcc1-supply = <&vcc3v3_sys>; vcc2-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-radxa-cm3i.dtsi b/arch/arm64/boot/dts/rockchip/rk3568-radxa-cm3i.dtsi index 19d309654bdb41..729e38b9f620eb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-radxa-cm3i.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568-radxa-cm3i.dtsi @@ -29,7 +29,7 @@ led_user: led-0 { }; }; - pcie30_avdd0v9: pcie30-avdd0v9-regulator { + pcie30_avdd0v9: regulator-pcie30-avdd0v9 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd0v9"; regulator-always-on; @@ -39,7 +39,7 @@ pcie30_avdd0v9: pcie30-avdd0v9-regulator { vin-supply = <&vcc3v3_sys>; }; - pcie30_avdd1v8: pcie30-avdd1v8-regulator { + pcie30_avdd1v8: regulator-pcie30-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-always-on; @@ -49,7 +49,7 @@ pcie30_avdd1v8: pcie30-avdd1v8-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -59,7 +59,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v_input>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -70,7 +70,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { }; /* labeled +5v_input in schematic */ - vcc5v_input: vcc5v-input-regulator { + vcc5v_input: regulator-vcc5v-input { compatible = "regulator-fixed"; regulator-name = "vcc5v_input"; regulator-always-on; @@ -141,7 +141,7 @@ rk809: pmic@20 { #clock-cells = <1>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; wakeup-source; vcc1-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts b/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts index 84a0789fad96ad..98cfa3abb80936 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts @@ -16,6 +16,7 @@ pwm-leds { multi-led { color = ; + function = LED_FUNCTION_STATUS; max-brightness = <255>; led-red { @@ -35,7 +36,7 @@ led-blue { }; }; - vbus_typec: vbus-typec-regulator { + vbus_typec: regulator-vbus-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>; @@ -50,7 +51,7 @@ vbus_typec: vbus-typec-regulator { /* actually fed by vcc5v0_sys, dependent * on pi6c clock generator */ - vcc3v3_minipcie: vcc3v3-minipcie-regulator { + vcc3v3_minipcie: regulator-vcc3v3-minipcie { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>; @@ -62,7 +63,7 @@ vcc3v3_minipcie: vcc3v3-minipcie-regulator { vin-supply = <&vcc3v3_pi6c_05>; }; - vcc3v3_ngff: vcc3v3-ngff-regulator { + vcc3v3_ngff: regulator-vcc3v3-ngff { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>; @@ -74,7 +75,7 @@ vcc3v3_ngff: vcc3v3-ngff-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie30x1: vcc3v3-pcie30x1-regulator { + vcc3v3_pcie30x1: regulator-vcc3v3-pcie30x1 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -86,7 +87,7 @@ vcc3v3_pcie30x1: vcc3v3-pcie30x1-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pi6c_05: vcc3v3-pi6c-05-regulator { + vcc3v3_pi6c_05: regulator-vcc3v3-pi6c-05 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; @@ -123,7 +124,7 @@ &pcie30phy { &pcie3x1 { num-lanes = <1>; pinctrl-names = "default"; - pinctrl-0 = <&pcie30x1m0_pins>; + pinctrl-0 = <&pcie30x1_reset_h>; reset-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>; vpcie3v3-supply = <&vcc3v3_minipcie>; status = "okay"; @@ -148,6 +149,10 @@ pcie30x1_enable_h: pcie30x1-enable-h { rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; }; + pcie30x1_reset_h: pcie30x1-reset-h { + rockchip,pins = <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + pcie30x2_reset_h: pcie30x2-reset-h { rockchip,pins = <2 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts b/arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts index 2fa89a0eeafcda..60faa0c80cd775 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-roc-pc.dts @@ -25,7 +25,7 @@ chosen: chosen { stdout-path = "serial2:1500000n8"; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -73,7 +73,7 @@ hdmi_con_in: endpoint { }; }; - pcie30_avdd0v9: pcie30-avdd0v9-regulator { + pcie30_avdd0v9: regulator-pcie30-avdd0v9 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd0v9"; regulator-always-on; @@ -83,7 +83,7 @@ pcie30_avdd0v9: pcie30-avdd0v9-regulator { vin-supply = <&vcc3v3_sys>; }; - pcie30_avdd1v8: pcie30-avdd1v8-regulator { + pcie30_avdd1v8: regulator-pcie30-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-always-on; @@ -93,7 +93,7 @@ pcie30_avdd1v8: pcie30-avdd1v8-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -103,7 +103,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&dc_12v>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie"; enable-active-high; @@ -116,7 +116,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -126,7 +126,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -136,7 +136,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; enable-active-high; @@ -147,7 +147,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_otg: vcc5v0-otg-regulator { + vcc5v0_otg: regulator-vcc5v0-otg { compatible = "regulator-fixed"; regulator-name = "vcc5v0_otg"; enable-active-high; @@ -255,7 +255,7 @@ rk809: pmic@20 { #clock-cells = <1>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc3v3_sys>; vcc2-supply = <&vcc3v3_sys>; vcc3-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts b/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts index 59f1403b4fa566..ac79140a9ecd63 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-rock-3a.dts @@ -79,14 +79,14 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio3 RK_PD4 GPIO_ACTIVE_LOW>; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; regulator-boot-on; }; - pcie30_avdd0v9: pcie30-avdd0v9-regulator { + pcie30_avdd0v9: regulator-pcie30-avdd0v9 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd0v9"; regulator-always-on; @@ -96,7 +96,7 @@ pcie30_avdd0v9: pcie30-avdd0v9-regulator { vin-supply = <&vcc3v3_sys>; }; - pcie30_avdd1v8: pcie30-avdd1v8-regulator { + pcie30_avdd1v8: regulator-pcie30-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-always-on; @@ -107,7 +107,7 @@ pcie30_avdd1v8: pcie30-avdd1v8-regulator { }; /* pi6c pcie clock generator */ - vcc3v3_pi6c_03: vcc3v3-pi6c-03-regulator { + vcc3v3_pi6c_03: regulator-vcc3v3-pi6c-03 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pi6c_03"; regulator-always-on; @@ -117,7 +117,7 @@ vcc3v3_pi6c_03: vcc3v3-pi6c-03-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { + vcc3v3_pcie: regulator-vcc3v3-pcie { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio0 RK_PD4 GPIO_ACTIVE_HIGH>; @@ -129,7 +129,7 @@ vcc3v3_pcie: vcc3v3-pcie-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -139,7 +139,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -149,7 +149,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -159,7 +159,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usb_host: vcc5v0-usb-host-regulator { + vcc5v0_usb_host: regulator-vcc5v0-usb-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -171,7 +171,7 @@ vcc5v0_usb_host: vcc5v0-usb-host-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_usb_hub: vcc5v0-usb-hub-regulator { + vcc5v0_usb_hub: regulator-vcc5v0-usb-hub { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>; @@ -182,7 +182,7 @@ vcc5v0_usb_hub: vcc5v0-usb-hub-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { + vcc5v0_usb_otg: regulator-vcc5v0-usb-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -194,7 +194,7 @@ vcc5v0_usb_otg: vcc5v0-usb-otg-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc_cam: vcc-cam-regulator { + vcc_cam: regulator-vcc-cam { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>; @@ -210,7 +210,7 @@ regulator-state-mem { }; }; - vcc_mipi: vcc-mipi-regulator { + vcc_mipi: regulator-vcc-mipi { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; @@ -333,7 +333,7 @@ rk809: pmic@20 { clocks = <&cru I2S1_MCLKOUT_TX>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int>, <&i2s1m0_mclk>; - rockchip,system-power-controller; + system-power-controller; #sound-dai-cells = <0>; vcc1-supply = <&vcc3v3_sys>; vcc2-supply = <&vcc3v3_sys>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5-io-expander.dtso b/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5-io-expander.dtso index ebcaeafc3800d0..048933de2943e4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5-io-expander.dtso +++ b/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5-io-expander.dtso @@ -21,7 +21,7 @@ gmac0_clkin: external-gmac0-clock { #clock-cells = <0>; }; - usb_host_vbus: usb-host-vbus-regulator { + usb_host_vbus: regulator-usb-host-vbus { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; @@ -33,7 +33,7 @@ usb_host_vbus: usb-host-vbus-regulator { vin-supply = <&vcc5v_in>; }; - vcc1v8_eth: vcc1v8-eth-regulator { + vcc1v8_eth: regulator-vcc1v8-eth { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; @@ -47,9 +47,8 @@ vcc1v8_eth: vcc1v8-eth-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_eth: vcc3v3-eth-regulator { + vcc3v3_eth: regulator-vcc3v3-eth { compatible = "regulator-fixed"; - enable-active-low; gpio = <&gpio0 RK_PC0 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&vcc3v3_eth_enn>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5.dts b/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5.dts index 170b14f92f51b5..e8243c90854277 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5.dts +++ b/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5.dts @@ -39,7 +39,7 @@ hdmi_tx_in: endpoint { }; }; - hdmi_tx_5v: hdmi-tx-5v-regulator { + hdmi_tx_5v: regulator-hdmi-tx-5v { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -70,7 +70,7 @@ simple-audio-card,codec { }; }; - vcc12v_cam: vcc12v-cam-regulator { + vcc12v_cam: regulator-vcc12v-cam { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>; @@ -82,7 +82,7 @@ vcc12v_cam: vcc12v-cam-regulator { vin-supply = <&vcc12v_in>; }; - vcc12v_in: vcc12v-in-regulator { + vcc12v_in: regulator-vcc12v-in { compatible = "regulator-fixed"; regulator-name = "12v_in"; regulator-always-on; @@ -91,7 +91,7 @@ vcc12v_in: vcc12v-in-regulator { regulator-max-microvolt = <12000000>; }; - vcc3v8_cam: vcc3v8-cam-regulator { + vcc3v8_cam: regulator-vcc3v8-cam { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>; @@ -103,7 +103,7 @@ vcc3v8_cam: vcc3v8-cam-regulator { vin-supply = <&vcc5v_in>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "3v3_sys"; regulator-always-on; @@ -113,7 +113,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v_in>; }; - vcc5v_in: vcc5v-in-regulator { + vcc5v_in: regulator-vcc5v-in { compatible = "regulator-fixed"; regulator-name = "5v_in"; regulator-always-on; @@ -178,7 +178,7 @@ rk809: pmic@20 { #clock-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&pmic_int_l>; - rockchip,system-power-controller; + system-power-controller; vcc1-supply = <&vcc5v_in>; vcc2-supply = <&vcc5v_in>; vcc3-supply = <&vcc5v_in>; diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index 0946310e8c1248..ecaefe208e3e51 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -3,11 +3,99 @@ * Copyright (c) 2021 Rockchip Electronics Co., Ltd. */ -#include "rk356x.dtsi" +#include "rk356x-base.dtsi" / { compatible = "rockchip,rk3568"; + cpu0_opp_table: opp-table-0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <850000 850000 1150000>; + clock-latency-ns = <40000>; + opp-suspend; + }; + + opp-1104000000 { + opp-hz = /bits/ 64 <1104000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-1416000000 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <1025000 1025000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <1100000 1100000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <1150000 1150000 1150000>; + clock-latency-ns = <40000>; + }; + + opp-1992000000 { + opp-hz = /bits/ 64 <1992000000>; + opp-microvolt = <1150000 1150000 1150000>; + clock-latency-ns = <40000>; + }; + }; + + gpu_opp_table: opp-table-1 { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <850000 850000 1000000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1000000>; + }; + + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <950000 950000 1000000>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1000000 1000000 1000000>; + }; + }; + sata0: sata@fc000000 { compatible = "rockchip,rk3568-dwc-ahci", "snps,dwc-ahci"; reg = <0 0xfc000000 0 0x1000>; @@ -269,11 +357,24 @@ combphy0: phy@fe820000 { }; }; -&cpu0_opp_table { - opp-1992000000 { - opp-hz = /bits/ 64 <1992000000>; - opp-microvolt = <1150000 1150000 1150000>; - }; +&cpu0 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&cpu1 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&cpu2 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&cpu3 { + operating-points-v2 = <&cpu0_opp_table>; +}; + +&gpu { + operating-points-v2 = <&gpu_opp_table>; }; &pipegrf { diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi new file mode 100644 index 00000000000000..62be06f3b86375 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi @@ -0,0 +1,1856 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2021 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; + serial8 = &uart8; + serial9 = &uart9; + spi0 = &spi0; + spi1 = &spi1; + spi2 = &spi2; + spi3 = &spi3; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + clocks = <&scmi_clk 0>; + #cooling-cells = <2>; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l3_cache>; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x100>; + #cooling-cells = <2>; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l3_cache>; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x200>; + #cooling-cells = <2>; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l3_cache>; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x300>; + #cooling-cells = <2>; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l3_cache>; + }; + }; + + /* + * There are no private per-core L2 caches, but only the + * L3 cache that appears to the CPU cores as L2 caches + */ + l3_cache: l3-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x80000>; + cache-line-size = <64>; + cache-sets = <512>; + }; + + display_subsystem: display-subsystem { + compatible = "rockchip,display-subsystem"; + ports = <&vop_out>; + }; + + firmware { + scmi: scmi { + compatible = "arm,scmi-smc"; + arm,smc-id = <0x82000010>; + shmem = <&scmi_shmem>; + #address-cells = <1>; + #size-cells = <0>; + + scmi_clk: protocol@14 { + reg = <0x14>; + #clock-cells = <1>; + }; + }; + }; + + hdmi_sound: hdmi-sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "HDMI"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; + status = "disabled"; + + simple-audio-card,codec { + sound-dai = <&hdmi>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s0_8ch>; + }; + }; + + pmu { + compatible = "arm,cortex-a55-pmu"; + interrupts = , + , + , + ; + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + arm,no-tick-in-suspend; + }; + + xin24m: xin24m { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "xin24m"; + #clock-cells = <0>; + }; + + xin32k: xin32k { + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "xin32k"; + pinctrl-0 = <&clk32k_out0>; + pinctrl-names = "default"; + #clock-cells = <0>; + }; + + sram@10f000 { + compatible = "mmio-sram"; + reg = <0x0 0x0010f000 0x0 0x100>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x0010f000 0x100>; + + scmi_shmem: sram@0 { + compatible = "arm,scmi-shmem"; + reg = <0x0 0x100>; + }; + }; + + sata1: sata@fc400000 { + compatible = "rockchip,rk3568-dwc-ahci", "snps,dwc-ahci"; + reg = <0 0xfc400000 0 0x1000>; + clocks = <&cru ACLK_SATA1>, <&cru CLK_SATA1_PMALIVE>, + <&cru CLK_SATA1_RXOOB>; + clock-names = "sata", "pmalive", "rxoob"; + interrupts = ; + phys = <&combphy1 PHY_TYPE_SATA>; + phy-names = "sata-phy"; + ports-implemented = <0x1>; + power-domains = <&power RK3568_PD_PIPE>; + status = "disabled"; + }; + + sata2: sata@fc800000 { + compatible = "rockchip,rk3568-dwc-ahci", "snps,dwc-ahci"; + reg = <0 0xfc800000 0 0x1000>; + clocks = <&cru ACLK_SATA2>, <&cru CLK_SATA2_PMALIVE>, + <&cru CLK_SATA2_RXOOB>; + clock-names = "sata", "pmalive", "rxoob"; + interrupts = ; + phys = <&combphy2 PHY_TYPE_SATA>; + phy-names = "sata-phy"; + ports-implemented = <0x1>; + power-domains = <&power RK3568_PD_PIPE>; + status = "disabled"; + }; + + usb_host0_xhci: usb@fcc00000 { + compatible = "rockchip,rk3568-dwc3", "snps,dwc3"; + reg = <0x0 0xfcc00000 0x0 0x400000>; + interrupts = ; + clocks = <&cru CLK_USB3OTG0_REF>, <&cru CLK_USB3OTG0_SUSPEND>, + <&cru ACLK_USB3OTG0>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk"; + dr_mode = "otg"; + phy_type = "utmi_wide"; + power-domains = <&power RK3568_PD_PIPE>; + resets = <&cru SRST_USB3OTG0>; + snps,dis_u2_susphy_quirk; + status = "disabled"; + }; + + usb_host1_xhci: usb@fd000000 { + compatible = "rockchip,rk3568-dwc3", "snps,dwc3"; + reg = <0x0 0xfd000000 0x0 0x400000>; + interrupts = ; + clocks = <&cru CLK_USB3OTG1_REF>, <&cru CLK_USB3OTG1_SUSPEND>, + <&cru ACLK_USB3OTG1>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk"; + dr_mode = "host"; + phys = <&usb2phy0_host>, <&combphy1 PHY_TYPE_USB3>; + phy-names = "usb2-phy", "usb3-phy"; + phy_type = "utmi_wide"; + power-domains = <&power RK3568_PD_PIPE>; + resets = <&cru SRST_USB3OTG1>; + snps,dis_u2_susphy_quirk; + status = "disabled"; + }; + + gic: interrupt-controller@fd400000 { + compatible = "arm,gic-v3"; + reg = <0x0 0xfd400000 0 0x10000>, /* GICD */ + <0x0 0xfd460000 0 0x80000>; /* GICR */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + mbi-alias = <0x0 0xfd410000>; + mbi-ranges = <296 24>; + msi-controller; + }; + + usb_host0_ehci: usb@fd800000 { + compatible = "generic-ehci"; + reg = <0x0 0xfd800000 0x0 0x40000>; + interrupts = ; + clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>, + <&cru PCLK_USB>; + phys = <&usb2phy1_otg>; + phy-names = "usb"; + status = "disabled"; + }; + + usb_host0_ohci: usb@fd840000 { + compatible = "generic-ohci"; + reg = <0x0 0xfd840000 0x0 0x40000>; + interrupts = ; + clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>, + <&cru PCLK_USB>; + phys = <&usb2phy1_otg>; + phy-names = "usb"; + status = "disabled"; + }; + + usb_host1_ehci: usb@fd880000 { + compatible = "generic-ehci"; + reg = <0x0 0xfd880000 0x0 0x40000>; + interrupts = ; + clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>, + <&cru PCLK_USB>; + phys = <&usb2phy1_host>; + phy-names = "usb"; + status = "disabled"; + }; + + usb_host1_ohci: usb@fd8c0000 { + compatible = "generic-ohci"; + reg = <0x0 0xfd8c0000 0x0 0x40000>; + interrupts = ; + clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>, + <&cru PCLK_USB>; + phys = <&usb2phy1_host>; + phy-names = "usb"; + status = "disabled"; + }; + + pmugrf: syscon@fdc20000 { + compatible = "rockchip,rk3568-pmugrf", "syscon", "simple-mfd"; + reg = <0x0 0xfdc20000 0x0 0x10000>; + + pmu_io_domains: io-domains { + compatible = "rockchip,rk3568-pmu-io-voltage-domain"; + status = "disabled"; + }; + }; + + pipegrf: syscon@fdc50000 { + reg = <0x0 0xfdc50000 0x0 0x1000>; + }; + + grf: syscon@fdc60000 { + compatible = "rockchip,rk3568-grf", "syscon", "simple-mfd"; + reg = <0x0 0xfdc60000 0x0 0x10000>; + }; + + pipe_phy_grf1: syscon@fdc80000 { + compatible = "rockchip,rk3568-pipe-phy-grf", "syscon"; + reg = <0x0 0xfdc80000 0x0 0x1000>; + }; + + pipe_phy_grf2: syscon@fdc90000 { + compatible = "rockchip,rk3568-pipe-phy-grf", "syscon"; + reg = <0x0 0xfdc90000 0x0 0x1000>; + }; + + usb2phy0_grf: syscon@fdca0000 { + compatible = "rockchip,rk3568-usb2phy-grf", "syscon"; + reg = <0x0 0xfdca0000 0x0 0x8000>; + }; + + usb2phy1_grf: syscon@fdca8000 { + compatible = "rockchip,rk3568-usb2phy-grf", "syscon"; + reg = <0x0 0xfdca8000 0x0 0x8000>; + }; + + pmucru: clock-controller@fdd00000 { + compatible = "rockchip,rk3568-pmucru"; + reg = <0x0 0xfdd00000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cru: clock-controller@fdd20000 { + compatible = "rockchip,rk3568-cru"; + reg = <0x0 0xfdd20000 0x0 0x1000>; + clocks = <&xin24m>; + clock-names = "xin24m"; + #clock-cells = <1>; + #reset-cells = <1>; + assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>, <&pmucru PLL_PPLL>; + assigned-clock-rates = <32768>, <1200000000>, <200000000>; + assigned-clock-parents = <&pmucru CLK_RTC32K_FRAC>; + rockchip,grf = <&grf>; + }; + + i2c0: i2c@fdd40000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfdd40000 0x0 0x1000>; + interrupts = ; + clocks = <&pmucru CLK_I2C0>, <&pmucru PCLK_I2C0>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart0: serial@fdd50000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfdd50000 0x0 0x100>; + interrupts = ; + clocks = <&pmucru SCLK_UART0>, <&pmucru PCLK_UART0>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 0>, <&dmac0 1>; + pinctrl-0 = <&uart0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + pwm0: pwm@fdd70000 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfdd70000 0x0 0x10>; + clocks = <&pmucru CLK_PWM0>, <&pmucru PCLK_PWM0>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm0m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm1: pwm@fdd70010 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfdd70010 0x0 0x10>; + clocks = <&pmucru CLK_PWM0>, <&pmucru PCLK_PWM0>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm1m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm2: pwm@fdd70020 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfdd70020 0x0 0x10>; + clocks = <&pmucru CLK_PWM0>, <&pmucru PCLK_PWM0>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm2m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm3: pwm@fdd70030 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfdd70030 0x0 0x10>; + clocks = <&pmucru CLK_PWM0>, <&pmucru PCLK_PWM0>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm3_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pmu: power-management@fdd90000 { + compatible = "rockchip,rk3568-pmu", "syscon", "simple-mfd"; + reg = <0x0 0xfdd90000 0x0 0x1000>; + + power: power-controller { + compatible = "rockchip,rk3568-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + /* These power domains are grouped by VD_GPU */ + power-domain@RK3568_PD_GPU { + reg = ; + clocks = <&cru ACLK_GPU_PRE>, + <&cru PCLK_GPU_PRE>; + pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; + }; + + /* These power domains are grouped by VD_LOGIC */ + power-domain@RK3568_PD_VI { + reg = ; + clocks = <&cru HCLK_VI>, + <&cru PCLK_VI>; + pm_qos = <&qos_isp>, + <&qos_vicap0>, + <&qos_vicap1>; + #power-domain-cells = <0>; + }; + + power-domain@RK3568_PD_VO { + reg = ; + clocks = <&cru HCLK_VO>, + <&cru PCLK_VO>, + <&cru ACLK_VOP_PRE>; + pm_qos = <&qos_hdcp>, + <&qos_vop_m0>, + <&qos_vop_m1>; + #power-domain-cells = <0>; + }; + + power-domain@RK3568_PD_RGA { + reg = ; + clocks = <&cru HCLK_RGA_PRE>, + <&cru PCLK_RGA_PRE>; + pm_qos = <&qos_ebc>, + <&qos_iep>, + <&qos_jpeg_dec>, + <&qos_jpeg_enc>, + <&qos_rga_rd>, + <&qos_rga_wr>; + #power-domain-cells = <0>; + }; + + power-domain@RK3568_PD_VPU { + reg = ; + clocks = <&cru HCLK_VPU_PRE>; + pm_qos = <&qos_vpu>; + #power-domain-cells = <0>; + }; + + power-domain@RK3568_PD_RKVDEC { + clocks = <&cru HCLK_RKVDEC_PRE>; + reg = ; + pm_qos = <&qos_rkvdec>; + #power-domain-cells = <0>; + }; + + power-domain@RK3568_PD_RKVENC { + reg = ; + clocks = <&cru HCLK_RKVENC_PRE>; + pm_qos = <&qos_rkvenc_rd_m0>, + <&qos_rkvenc_rd_m1>, + <&qos_rkvenc_wr_m0>; + #power-domain-cells = <0>; + }; + }; + }; + + gpu: gpu@fde60000 { + compatible = "rockchip,rk3568-mali", "arm,mali-bifrost"; + reg = <0x0 0xfde60000 0x0 0x4000>; + interrupts = , + , + ; + interrupt-names = "job", "mmu", "gpu"; + clocks = <&scmi_clk 1>, <&cru CLK_GPU>; + clock-names = "gpu", "bus"; + #cooling-cells = <2>; + power-domains = <&power RK3568_PD_GPU>; + status = "disabled"; + }; + + vpu: video-codec@fdea0400 { + compatible = "rockchip,rk3568-vpu"; + reg = <0x0 0xfdea0000 0x0 0x800>; + interrupts = ; + interrupt-names = "vdpu"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + clock-names = "aclk", "hclk"; + iommus = <&vdpu_mmu>; + power-domains = <&power RK3568_PD_VPU>; + }; + + vdpu_mmu: iommu@fdea0800 { + compatible = "rockchip,rk3568-iommu"; + reg = <0x0 0xfdea0800 0x0 0x40>; + interrupts = ; + clock-names = "aclk", "iface"; + clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; + power-domains = <&power RK3568_PD_VPU>; + #iommu-cells = <0>; + }; + + rga: rga@fdeb0000 { + compatible = "rockchip,rk3568-rga", "rockchip,rk3288-rga"; + reg = <0x0 0xfdeb0000 0x0 0x180>; + interrupts = ; + clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru CLK_RGA_CORE>; + clock-names = "aclk", "hclk", "sclk"; + resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>; + reset-names = "core", "axi", "ahb"; + power-domains = <&power RK3568_PD_RGA>; + }; + + vepu: video-codec@fdee0000 { + compatible = "rockchip,rk3568-vepu"; + reg = <0x0 0xfdee0000 0x0 0x800>; + interrupts = ; + clocks = <&cru ACLK_JENC>, <&cru HCLK_JENC>; + clock-names = "aclk", "hclk"; + iommus = <&vepu_mmu>; + power-domains = <&power RK3568_PD_RGA>; + }; + + vepu_mmu: iommu@fdee0800 { + compatible = "rockchip,rk3568-iommu"; + reg = <0x0 0xfdee0800 0x0 0x40>; + interrupts = ; + clocks = <&cru ACLK_JENC>, <&cru HCLK_JENC>; + clock-names = "aclk", "iface"; + power-domains = <&power RK3568_PD_RGA>; + #iommu-cells = <0>; + }; + + sdmmc2: mmc@fe000000 { + compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x0 0xfe000000 0x0 0x4000>; + interrupts = ; + clocks = <&cru HCLK_SDMMC2>, <&cru CLK_SDMMC2>, + <&cru SCLK_SDMMC2_DRV>, <&cru SCLK_SDMMC2_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + max-frequency = <150000000>; + resets = <&cru SRST_SDMMC2>; + reset-names = "reset"; + status = "disabled"; + }; + + gmac1: ethernet@fe010000 { + compatible = "rockchip,rk3568-gmac", "snps,dwmac-4.20a"; + reg = <0x0 0xfe010000 0x0 0x10000>; + interrupts = , + ; + interrupt-names = "macirq", "eth_wake_irq"; + clocks = <&cru SCLK_GMAC1>, <&cru SCLK_GMAC1_RX_TX>, + <&cru SCLK_GMAC1_RX_TX>, <&cru CLK_MAC1_REFOUT>, + <&cru ACLK_GMAC1>, <&cru PCLK_GMAC1>, + <&cru SCLK_GMAC1_RX_TX>, <&cru CLK_GMAC1_PTP_REF>; + clock-names = "stmmaceth", "mac_clk_rx", + "mac_clk_tx", "clk_mac_refout", + "aclk_mac", "pclk_mac", + "clk_mac_speed", "ptp_ref"; + resets = <&cru SRST_A_GMAC1>; + reset-names = "stmmaceth"; + rockchip,grf = <&grf>; + snps,axi-config = <&gmac1_stmmac_axi_setup>; + snps,mixed-burst; + snps,mtl-rx-config = <&gmac1_mtl_rx_setup>; + snps,mtl-tx-config = <&gmac1_mtl_tx_setup>; + snps,tso; + status = "disabled"; + + mdio1: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + }; + + gmac1_stmmac_axi_setup: stmmac-axi-config { + snps,blen = <0 0 0 0 16 8 4>; + snps,rd_osr_lmt = <8>; + snps,wr_osr_lmt = <4>; + }; + + gmac1_mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <1>; + queue0 {}; + }; + + gmac1_mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <1>; + queue0 {}; + }; + }; + + vop: vop@fe040000 { + reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>; + reg-names = "vop", "gamma-lut"; + interrupts = ; + clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>, + <&cru DCLK_VOP1>, <&cru DCLK_VOP2>; + clock-names = "aclk", "hclk", "dclk_vp0", "dclk_vp1", "dclk_vp2"; + iommus = <&vop_mmu>; + power-domains = <&power RK3568_PD_VO>; + rockchip,grf = <&grf>; + status = "disabled"; + + vop_out: ports { + #address-cells = <1>; + #size-cells = <0>; + + vp0: port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + vp1: port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + + vp2: port@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + vop_mmu: iommu@fe043e00 { + compatible = "rockchip,rk3568-iommu"; + reg = <0x0 0xfe043e00 0x0 0x100>, <0x0 0xfe043f00 0x0 0x100>; + interrupts = ; + clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>; + clock-names = "aclk", "iface"; + #iommu-cells = <0>; + power-domains = <&power RK3568_PD_VO>; + status = "disabled"; + }; + + dsi0: dsi@fe060000 { + compatible = "rockchip,rk3568-mipi-dsi", "snps,dw-mipi-dsi"; + reg = <0x00 0xfe060000 0x00 0x10000>; + interrupts = ; + clock-names = "pclk"; + clocks = <&cru PCLK_DSITX_0>; + phy-names = "dphy"; + phys = <&dsi_dphy0>; + power-domains = <&power RK3568_PD_VO>; + reset-names = "apb"; + resets = <&cru SRST_P_DSITX_0>; + rockchip,grf = <&grf>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + dsi0_in: port@0 { + reg = <0>; + }; + + dsi0_out: port@1 { + reg = <1>; + }; + }; + }; + + dsi1: dsi@fe070000 { + compatible = "rockchip,rk3568-mipi-dsi", "snps,dw-mipi-dsi"; + reg = <0x0 0xfe070000 0x0 0x10000>; + interrupts = ; + clock-names = "pclk"; + clocks = <&cru PCLK_DSITX_1>; + phy-names = "dphy"; + phys = <&dsi_dphy1>; + power-domains = <&power RK3568_PD_VO>; + reset-names = "apb"; + resets = <&cru SRST_P_DSITX_1>; + rockchip,grf = <&grf>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + dsi1_in: port@0 { + reg = <0>; + }; + + dsi1_out: port@1 { + reg = <1>; + }; + }; + }; + + hdmi: hdmi@fe0a0000 { + compatible = "rockchip,rk3568-dw-hdmi"; + reg = <0x0 0xfe0a0000 0x0 0x20000>; + interrupts = ; + clocks = <&cru PCLK_HDMI_HOST>, + <&cru CLK_HDMI_SFR>, + <&cru CLK_HDMI_CEC>, + <&pmucru CLK_HDMI_REF>, + <&cru HCLK_VO>; + clock-names = "iahb", "isfr", "cec", "ref"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>; + power-domains = <&power RK3568_PD_VO>; + reg-io-width = <4>; + rockchip,grf = <&grf>; + #sound-dai-cells = <0>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_in: port@0 { + reg = <0>; + }; + + hdmi_out: port@1 { + reg = <1>; + }; + }; + }; + + qos_gpu: qos@fe128000 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe128000 0x0 0x20>; + }; + + qos_rkvenc_rd_m0: qos@fe138080 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe138080 0x0 0x20>; + }; + + qos_rkvenc_rd_m1: qos@fe138100 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe138100 0x0 0x20>; + }; + + qos_rkvenc_wr_m0: qos@fe138180 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe138180 0x0 0x20>; + }; + + qos_isp: qos@fe148000 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe148000 0x0 0x20>; + }; + + qos_vicap0: qos@fe148080 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe148080 0x0 0x20>; + }; + + qos_vicap1: qos@fe148100 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe148100 0x0 0x20>; + }; + + qos_vpu: qos@fe150000 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe150000 0x0 0x20>; + }; + + qos_ebc: qos@fe158000 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe158000 0x0 0x20>; + }; + + qos_iep: qos@fe158100 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe158100 0x0 0x20>; + }; + + qos_jpeg_dec: qos@fe158180 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe158180 0x0 0x20>; + }; + + qos_jpeg_enc: qos@fe158200 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe158200 0x0 0x20>; + }; + + qos_rga_rd: qos@fe158280 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe158280 0x0 0x20>; + }; + + qos_rga_wr: qos@fe158300 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe158300 0x0 0x20>; + }; + + qos_npu: qos@fe180000 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe180000 0x0 0x20>; + }; + + qos_pcie2x1: qos@fe190000 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe190000 0x0 0x20>; + }; + + qos_sata1: qos@fe190280 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe190280 0x0 0x20>; + }; + + qos_sata2: qos@fe190300 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe190300 0x0 0x20>; + }; + + qos_usb3_0: qos@fe190380 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe190380 0x0 0x20>; + }; + + qos_usb3_1: qos@fe190400 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe190400 0x0 0x20>; + }; + + qos_rkvdec: qos@fe198000 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe198000 0x0 0x20>; + }; + + qos_hdcp: qos@fe1a8000 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe1a8000 0x0 0x20>; + }; + + qos_vop_m0: qos@fe1a8080 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe1a8080 0x0 0x20>; + }; + + qos_vop_m1: qos@fe1a8100 { + compatible = "rockchip,rk3568-qos", "syscon"; + reg = <0x0 0xfe1a8100 0x0 0x20>; + }; + + dfi: dfi@fe230000 { + compatible = "rockchip,rk3568-dfi"; + reg = <0x00 0xfe230000 0x00 0x400>; + interrupts = ; + rockchip,pmu = <&pmugrf>; + }; + + pcie2x1: pcie@fe260000 { + compatible = "rockchip,rk3568-pcie"; + reg = <0x3 0xc0000000 0x0 0x00400000>, + <0x0 0xfe260000 0x0 0x00010000>, + <0x0 0xf4000000 0x0 0x00100000>; + reg-names = "dbi", "apb", "config"; + interrupts = , + , + , + , + ; + interrupt-names = "sys", "pmc", "msg", "legacy", "err"; + bus-range = <0x0 0xf>; + clocks = <&cru ACLK_PCIE20_MST>, <&cru ACLK_PCIE20_SLV>, + <&cru ACLK_PCIE20_DBI>, <&cru PCLK_PCIE20>, + <&cru CLK_PCIE20_AUX_NDFT>; + clock-names = "aclk_mst", "aclk_slv", + "aclk_dbi", "pclk", "aux"; + device_type = "pci"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc 0>, + <0 0 0 2 &pcie_intc 1>, + <0 0 0 3 &pcie_intc 2>, + <0 0 0 4 &pcie_intc 3>; + linux,pci-domain = <0>; + num-ib-windows = <6>; + num-ob-windows = <2>; + max-link-speed = <2>; + msi-map = <0x0 &gic 0x0 0x1000>; + num-lanes = <1>; + phys = <&combphy2 PHY_TYPE_PCIE>; + phy-names = "pcie-phy"; + power-domains = <&power RK3568_PD_PIPE>; + ranges = <0x01000000 0x0 0xf4100000 0x0 0xf4100000 0x0 0x00100000>, + <0x02000000 0x0 0xf4200000 0x0 0xf4200000 0x0 0x01e00000>, + <0x03000000 0x0 0x40000000 0x3 0x00000000 0x0 0x40000000>; + resets = <&cru SRST_PCIE20_POWERUP>; + reset-names = "pipe"; + #address-cells = <3>; + #size-cells = <2>; + status = "disabled"; + + pcie_intc: legacy-interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + interrupt-parent = <&gic>; + interrupts = ; + }; + }; + + sdmmc0: mmc@fe2b0000 { + compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x0 0xfe2b0000 0x0 0x4000>; + interrupts = ; + clocks = <&cru HCLK_SDMMC0>, <&cru CLK_SDMMC0>, + <&cru SCLK_SDMMC0_DRV>, <&cru SCLK_SDMMC0_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + max-frequency = <150000000>; + resets = <&cru SRST_SDMMC0>; + reset-names = "reset"; + status = "disabled"; + }; + + sdmmc1: mmc@fe2c0000 { + compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; + reg = <0x0 0xfe2c0000 0x0 0x4000>; + interrupts = ; + clocks = <&cru HCLK_SDMMC1>, <&cru CLK_SDMMC1>, + <&cru SCLK_SDMMC1_DRV>, <&cru SCLK_SDMMC1_SAMPLE>; + clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; + fifo-depth = <0x100>; + max-frequency = <150000000>; + resets = <&cru SRST_SDMMC1>; + reset-names = "reset"; + status = "disabled"; + }; + + sfc: spi@fe300000 { + compatible = "rockchip,sfc"; + reg = <0x0 0xfe300000 0x0 0x4000>; + interrupts = ; + clocks = <&cru SCLK_SFC>, <&cru HCLK_SFC>; + clock-names = "clk_sfc", "hclk_sfc"; + pinctrl-0 = <&fspi_pins>; + pinctrl-names = "default"; + status = "disabled"; + }; + + sdhci: mmc@fe310000 { + compatible = "rockchip,rk3568-dwcmshc"; + reg = <0x0 0xfe310000 0x0 0x10000>; + interrupts = ; + assigned-clocks = <&cru BCLK_EMMC>, <&cru TCLK_EMMC>; + assigned-clock-rates = <200000000>, <24000000>; + clocks = <&cru CCLK_EMMC>, <&cru HCLK_EMMC>, + <&cru ACLK_EMMC>, <&cru BCLK_EMMC>, + <&cru TCLK_EMMC>; + clock-names = "core", "bus", "axi", "block", "timer"; + status = "disabled"; + }; + + rng: rng@fe388000 { + compatible = "rockchip,rk3568-rng"; + reg = <0x0 0xfe388000 0x0 0x4000>; + clocks = <&cru CLK_TRNG_NS>, <&cru HCLK_TRNG_NS>; + clock-names = "core", "ahb"; + resets = <&cru SRST_TRNG_NS>; + status = "disabled"; + }; + + i2s0_8ch: i2s@fe400000 { + compatible = "rockchip,rk3568-i2s-tdm"; + reg = <0x0 0xfe400000 0x0 0x1000>; + interrupts = ; + assigned-clocks = <&cru CLK_I2S0_8CH_TX_SRC>, <&cru CLK_I2S0_8CH_RX_SRC>; + assigned-clock-rates = <1188000000>, <1188000000>; + clocks = <&cru MCLK_I2S0_8CH_TX>, <&cru MCLK_I2S0_8CH_RX>, <&cru HCLK_I2S0_8CH>; + clock-names = "mclk_tx", "mclk_rx", "hclk"; + dmas = <&dmac1 0>; + dma-names = "tx"; + resets = <&cru SRST_M_I2S0_8CH_TX>, <&cru SRST_M_I2S0_8CH_RX>; + reset-names = "tx-m", "rx-m"; + rockchip,grf = <&grf>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + i2s1_8ch: i2s@fe410000 { + compatible = "rockchip,rk3568-i2s-tdm"; + reg = <0x0 0xfe410000 0x0 0x1000>; + interrupts = ; + assigned-clocks = <&cru CLK_I2S1_8CH_TX_SRC>, <&cru CLK_I2S1_8CH_RX_SRC>; + assigned-clock-rates = <1188000000>, <1188000000>; + clocks = <&cru MCLK_I2S1_8CH_TX>, <&cru MCLK_I2S1_8CH_RX>, + <&cru HCLK_I2S1_8CH>; + clock-names = "mclk_tx", "mclk_rx", "hclk"; + dmas = <&dmac1 3>, <&dmac1 2>; + dma-names = "rx", "tx"; + resets = <&cru SRST_M_I2S1_8CH_TX>, <&cru SRST_M_I2S1_8CH_RX>; + reset-names = "tx-m", "rx-m"; + rockchip,grf = <&grf>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1m0_sclktx &i2s1m0_sclkrx + &i2s1m0_lrcktx &i2s1m0_lrckrx + &i2s1m0_sdi0 &i2s1m0_sdi1 + &i2s1m0_sdi2 &i2s1m0_sdi3 + &i2s1m0_sdo0 &i2s1m0_sdo1 + &i2s1m0_sdo2 &i2s1m0_sdo3>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + i2s2_2ch: i2s@fe420000 { + compatible = "rockchip,rk3568-i2s-tdm"; + reg = <0x0 0xfe420000 0x0 0x1000>; + interrupts = ; + assigned-clocks = <&cru CLK_I2S2_2CH_SRC>; + assigned-clock-rates = <1188000000>; + clocks = <&cru MCLK_I2S2_2CH>, <&cru MCLK_I2S2_2CH>, <&cru HCLK_I2S2_2CH>; + clock-names = "mclk_tx", "mclk_rx", "hclk"; + dmas = <&dmac1 4>, <&dmac1 5>; + dma-names = "tx", "rx"; + resets = <&cru SRST_M_I2S2_2CH>; + reset-names = "tx-m"; + rockchip,grf = <&grf>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s2m0_sclktx + &i2s2m0_lrcktx + &i2s2m0_sdi + &i2s2m0_sdo>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + i2s3_2ch: i2s@fe430000 { + compatible = "rockchip,rk3568-i2s-tdm"; + reg = <0x0 0xfe430000 0x0 0x1000>; + interrupts = ; + clocks = <&cru MCLK_I2S3_2CH_TX>, <&cru MCLK_I2S3_2CH_RX>, + <&cru HCLK_I2S3_2CH>; + clock-names = "mclk_tx", "mclk_rx", "hclk"; + dmas = <&dmac1 6>, <&dmac1 7>; + dma-names = "tx", "rx"; + resets = <&cru SRST_M_I2S3_2CH_TX>, <&cru SRST_M_I2S3_2CH_RX>; + reset-names = "tx-m", "rx-m"; + rockchip,grf = <&grf>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + pdm: pdm@fe440000 { + compatible = "rockchip,rk3568-pdm"; + reg = <0x0 0xfe440000 0x0 0x1000>; + interrupts = ; + clocks = <&cru MCLK_PDM>, <&cru HCLK_PDM>; + clock-names = "pdm_clk", "pdm_hclk"; + dmas = <&dmac1 9>; + dma-names = "rx"; + pinctrl-0 = <&pdmm0_clk + &pdmm0_clk1 + &pdmm0_sdi0 + &pdmm0_sdi1 + &pdmm0_sdi2 + &pdmm0_sdi3>; + pinctrl-names = "default"; + resets = <&cru SRST_M_PDM>; + reset-names = "pdm-m"; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + spdif: spdif@fe460000 { + compatible = "rockchip,rk3568-spdif"; + reg = <0x0 0xfe460000 0x0 0x1000>; + interrupts = ; + clock-names = "mclk", "hclk"; + clocks = <&cru MCLK_SPDIF_8CH>, <&cru HCLK_SPDIF_8CH>; + dmas = <&dmac1 1>; + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spdifm0_tx>; + #sound-dai-cells = <0>; + status = "disabled"; + }; + + dmac0: dma-controller@fe530000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0xfe530000 0x0 0x4000>; + interrupts = , + ; + arm,pl330-periph-burst; + clocks = <&cru ACLK_BUS>; + clock-names = "apb_pclk"; + #dma-cells = <1>; + }; + + dmac1: dma-controller@fe550000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0xfe550000 0x0 0x4000>; + interrupts = , + ; + arm,pl330-periph-burst; + clocks = <&cru ACLK_BUS>; + clock-names = "apb_pclk"; + #dma-cells = <1>; + }; + + i2c1: i2c@fe5a0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5a0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C1>, <&cru PCLK_I2C1>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c1_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@fe5b0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5b0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C2>, <&cru PCLK_I2C2>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c2m0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@fe5c0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5c0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C3>, <&cru PCLK_I2C3>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c3m0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@fe5d0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5d0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C4>, <&cru PCLK_I2C4>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c4m0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c5: i2c@fe5e0000 { + compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0xfe5e0000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_I2C5>, <&cru PCLK_I2C5>; + clock-names = "i2c", "pclk"; + pinctrl-0 = <&i2c5m0_xfer>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + wdt: watchdog@fe600000 { + compatible = "rockchip,rk3568-wdt", "snps,dw-wdt"; + reg = <0x0 0xfe600000 0x0 0x100>; + interrupts = ; + clocks = <&cru TCLK_WDT_NS>, <&cru PCLK_WDT_NS>; + clock-names = "tclk", "pclk"; + }; + + spi0: spi@fe610000 { + compatible = "rockchip,rk3568-spi", "rockchip,rk3066-spi"; + reg = <0x0 0xfe610000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_SPI0>, <&cru PCLK_SPI0>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac0 20>, <&dmac0 21>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0m0_cs0 &spi0m0_cs1 &spi0m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@fe620000 { + compatible = "rockchip,rk3568-spi", "rockchip,rk3066-spi"; + reg = <0x0 0xfe620000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_SPI1>, <&cru PCLK_SPI1>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac0 22>, <&dmac0 23>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi1m0_cs0 &spi1m0_cs1 &spi1m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@fe630000 { + compatible = "rockchip,rk3568-spi", "rockchip,rk3066-spi"; + reg = <0x0 0xfe630000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_SPI2>, <&cru PCLK_SPI2>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac0 24>, <&dmac0 25>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m0_cs0 &spi2m0_cs1 &spi2m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi3: spi@fe640000 { + compatible = "rockchip,rk3568-spi", "rockchip,rk3066-spi"; + reg = <0x0 0xfe640000 0x0 0x1000>; + interrupts = ; + clocks = <&cru CLK_SPI3>, <&cru PCLK_SPI3>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac0 26>, <&dmac0 27>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi3m0_cs0 &spi3m0_cs1 &spi3m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart1: serial@fe650000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe650000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 2>, <&dmac0 3>; + pinctrl-0 = <&uart1m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart2: serial@fe660000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe660000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 4>, <&dmac0 5>; + pinctrl-0 = <&uart2m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart3: serial@fe670000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe670000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 6>, <&dmac0 7>; + pinctrl-0 = <&uart3m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart4: serial@fe680000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe680000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 8>, <&dmac0 9>; + pinctrl-0 = <&uart4m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart5: serial@fe690000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe690000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART5>, <&cru PCLK_UART5>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 10>, <&dmac0 11>; + pinctrl-0 = <&uart5m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart6: serial@fe6a0000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe6a0000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART6>, <&cru PCLK_UART6>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 12>, <&dmac0 13>; + pinctrl-0 = <&uart6m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart7: serial@fe6b0000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe6b0000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART7>, <&cru PCLK_UART7>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 14>, <&dmac0 15>; + pinctrl-0 = <&uart7m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart8: serial@fe6c0000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe6c0000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART8>, <&cru PCLK_UART8>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 16>, <&dmac0 17>; + pinctrl-0 = <&uart8m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + uart9: serial@fe6d0000 { + compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; + reg = <0x0 0xfe6d0000 0x0 0x100>; + interrupts = ; + clocks = <&cru SCLK_UART9>, <&cru PCLK_UART9>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 18>, <&dmac0 19>; + pinctrl-0 = <&uart9m0_xfer>; + pinctrl-names = "default"; + reg-io-width = <4>; + reg-shift = <2>; + status = "disabled"; + }; + + thermal_zones: thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <100>; + polling-delay = <1000>; + + thermal-sensors = <&tsadc 0>; + + trips { + cpu_alert0: cpu_alert0 { + temperature = <70000>; + hysteresis = <2000>; + type = "passive"; + }; + cpu_alert1: cpu_alert1 { + temperature = <75000>; + hysteresis = <2000>; + type = "passive"; + }; + cpu_crit: cpu_crit { + temperature = <95000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert0>; + cooling-device = + <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + gpu_thermal: gpu-thermal { + polling-delay-passive = <20>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + thermal-sensors = <&tsadc 1>; + + trips { + gpu_threshold: gpu-threshold { + temperature = <70000>; + hysteresis = <2000>; + type = "passive"; + }; + gpu_target: gpu-target { + temperature = <75000>; + hysteresis = <2000>; + type = "passive"; + }; + gpu_crit: gpu-crit { + temperature = <95000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&gpu_target>; + cooling-device = + <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + }; + + tsadc: tsadc@fe710000 { + compatible = "rockchip,rk3568-tsadc"; + reg = <0x0 0xfe710000 0x0 0x100>; + interrupts = ; + assigned-clocks = <&cru CLK_TSADC_TSEN>, <&cru CLK_TSADC>; + assigned-clock-rates = <17000000>, <700000>; + clocks = <&cru CLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + resets = <&cru SRST_P_TSADC>, <&cru SRST_TSADC>, + <&cru SRST_TSADCPHY>; + rockchip,grf = <&grf>; + rockchip,hw-tshut-temp = <95000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&tsadc_shutorg>; + pinctrl-1 = <&tsadc_pin>; + #thermal-sensor-cells = <1>; + status = "disabled"; + }; + + saradc: saradc@fe720000 { + compatible = "rockchip,rk3568-saradc", "rockchip,rk3399-saradc"; + reg = <0x0 0xfe720000 0x0 0x100>; + interrupts = ; + clocks = <&cru CLK_SARADC>, <&cru PCLK_SARADC>; + clock-names = "saradc", "apb_pclk"; + resets = <&cru SRST_P_SARADC>; + reset-names = "saradc-apb"; + #io-channel-cells = <1>; + status = "disabled"; + }; + + pwm4: pwm@fe6e0000 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe6e0000 0x0 0x10>; + clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm4_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm5: pwm@fe6e0010 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe6e0010 0x0 0x10>; + clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm5_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm6: pwm@fe6e0020 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe6e0020 0x0 0x10>; + clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm6_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm7: pwm@fe6e0030 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe6e0030 0x0 0x10>; + clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm7_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm8: pwm@fe6f0000 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe6f0000 0x0 0x10>; + clocks = <&cru CLK_PWM2>, <&cru PCLK_PWM2>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm8m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm9: pwm@fe6f0010 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe6f0010 0x0 0x10>; + clocks = <&cru CLK_PWM2>, <&cru PCLK_PWM2>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm9m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm10: pwm@fe6f0020 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe6f0020 0x0 0x10>; + clocks = <&cru CLK_PWM2>, <&cru PCLK_PWM2>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm10m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm11: pwm@fe6f0030 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe6f0030 0x0 0x10>; + clocks = <&cru CLK_PWM2>, <&cru PCLK_PWM2>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm11m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm12: pwm@fe700000 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe700000 0x0 0x10>; + clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm12m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm13: pwm@fe700010 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe700010 0x0 0x10>; + clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm13m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm14: pwm@fe700020 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe700020 0x0 0x10>; + clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm14m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm15: pwm@fe700030 { + compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; + reg = <0x0 0xfe700030 0x0 0x10>; + clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; + clock-names = "pwm", "pclk"; + pinctrl-0 = <&pwm15m0_pins>; + pinctrl-names = "default"; + #pwm-cells = <3>; + status = "disabled"; + }; + + combphy1: phy@fe830000 { + compatible = "rockchip,rk3568-naneng-combphy"; + reg = <0x0 0xfe830000 0x0 0x100>; + clocks = <&pmucru CLK_PCIEPHY1_REF>, + <&cru PCLK_PIPEPHY1>, + <&cru PCLK_PIPE>; + clock-names = "ref", "apb", "pipe"; + assigned-clocks = <&pmucru CLK_PCIEPHY1_REF>; + assigned-clock-rates = <100000000>; + resets = <&cru SRST_PIPEPHY1>; + rockchip,pipe-grf = <&pipegrf>; + rockchip,pipe-phy-grf = <&pipe_phy_grf1>; + #phy-cells = <1>; + status = "disabled"; + }; + + combphy2: phy@fe840000 { + compatible = "rockchip,rk3568-naneng-combphy"; + reg = <0x0 0xfe840000 0x0 0x100>; + clocks = <&pmucru CLK_PCIEPHY2_REF>, + <&cru PCLK_PIPEPHY2>, + <&cru PCLK_PIPE>; + clock-names = "ref", "apb", "pipe"; + assigned-clocks = <&pmucru CLK_PCIEPHY2_REF>; + assigned-clock-rates = <100000000>; + resets = <&cru SRST_PIPEPHY2>; + rockchip,pipe-grf = <&pipegrf>; + rockchip,pipe-phy-grf = <&pipe_phy_grf2>; + #phy-cells = <1>; + status = "disabled"; + }; + + csi_dphy: phy@fe870000 { + compatible = "rockchip,rk3568-csi-dphy"; + reg = <0x0 0xfe870000 0x0 0x10000>; + clocks = <&cru PCLK_MIPICSIPHY>; + clock-names = "pclk"; + #phy-cells = <0>; + resets = <&cru SRST_P_MIPICSIPHY>; + reset-names = "apb"; + rockchip,grf = <&grf>; + status = "disabled"; + }; + + dsi_dphy0: mipi-dphy@fe850000 { + compatible = "rockchip,rk3568-dsi-dphy"; + reg = <0x0 0xfe850000 0x0 0x10000>; + clock-names = "ref", "pclk"; + clocks = <&pmucru CLK_MIPIDSIPHY0_REF>, <&cru PCLK_MIPIDSIPHY0>; + #phy-cells = <0>; + power-domains = <&power RK3568_PD_VO>; + reset-names = "apb"; + resets = <&cru SRST_P_MIPIDSIPHY0>; + status = "disabled"; + }; + + dsi_dphy1: mipi-dphy@fe860000 { + compatible = "rockchip,rk3568-dsi-dphy"; + reg = <0x0 0xfe860000 0x0 0x10000>; + clock-names = "ref", "pclk"; + clocks = <&pmucru CLK_MIPIDSIPHY1_REF>, <&cru PCLK_MIPIDSIPHY1>; + #phy-cells = <0>; + power-domains = <&power RK3568_PD_VO>; + reset-names = "apb"; + resets = <&cru SRST_P_MIPIDSIPHY1>; + status = "disabled"; + }; + + usb2phy0: usb2phy@fe8a0000 { + compatible = "rockchip,rk3568-usb2phy"; + reg = <0x0 0xfe8a0000 0x0 0x10000>; + clocks = <&pmucru CLK_USBPHY0_REF>; + clock-names = "phyclk"; + clock-output-names = "clk_usbphy0_480m"; + interrupts = ; + rockchip,usbgrf = <&usb2phy0_grf>; + #clock-cells = <0>; + status = "disabled"; + + usb2phy0_host: host-port { + #phy-cells = <0>; + status = "disabled"; + }; + + usb2phy0_otg: otg-port { + #phy-cells = <0>; + status = "disabled"; + }; + }; + + usb2phy1: usb2phy@fe8b0000 { + compatible = "rockchip,rk3568-usb2phy"; + reg = <0x0 0xfe8b0000 0x0 0x10000>; + clocks = <&pmucru CLK_USBPHY1_REF>; + clock-names = "phyclk"; + clock-output-names = "clk_usbphy1_480m"; + interrupts = ; + rockchip,usbgrf = <&usb2phy1_grf>; + #clock-cells = <0>; + status = "disabled"; + + usb2phy1_host: host-port { + #phy-cells = <0>; + status = "disabled"; + }; + + usb2phy1_otg: otg-port { + #phy-cells = <0>; + status = "disabled"; + }; + }; + + pinctrl: pinctrl { + compatible = "rockchip,rk3568-pinctrl"; + rockchip,grf = <&grf>; + rockchip,pmu = <&pmugrf>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gpio0: gpio@fdd60000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfdd60000 0x0 0x100>; + interrupts = ; + clocks = <&pmucru PCLK_GPIO0>, <&pmucru DBCLK_GPIO0>; + gpio-controller; + gpio-ranges = <&pinctrl 0 0 32>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@fe740000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfe740000 0x0 0x100>; + interrupts = ; + clocks = <&cru PCLK_GPIO1>, <&cru DBCLK_GPIO1>; + gpio-controller; + gpio-ranges = <&pinctrl 0 32 32>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@fe750000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfe750000 0x0 0x100>; + interrupts = ; + clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>; + gpio-controller; + gpio-ranges = <&pinctrl 0 64 32>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@fe760000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfe760000 0x0 0x100>; + interrupts = ; + clocks = <&cru PCLK_GPIO3>, <&cru DBCLK_GPIO3>; + gpio-controller; + gpio-ranges = <&pinctrl 0 96 32>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio4: gpio@fe770000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0xfe770000 0x0 0x100>; + interrupts = ; + clocks = <&cru PCLK_GPIO4>, <&cru DBCLK_GPIO4>; + gpio-controller; + gpio-ranges = <&pinctrl 0 128 32>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; + +#include "rk3568-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi deleted file mode 100644 index 0ee0ada6f0ab0f..00000000000000 --- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi +++ /dev/null @@ -1,1937 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* - * Copyright (c) 2021 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/ { - interrupt-parent = <&gic>; - #address-cells = <2>; - #size-cells = <2>; - - aliases { - gpio0 = &gpio0; - gpio1 = &gpio1; - gpio2 = &gpio2; - gpio3 = &gpio3; - gpio4 = &gpio4; - i2c0 = &i2c0; - i2c1 = &i2c1; - i2c2 = &i2c2; - i2c3 = &i2c3; - i2c4 = &i2c4; - i2c5 = &i2c5; - serial0 = &uart0; - serial1 = &uart1; - serial2 = &uart2; - serial3 = &uart3; - serial4 = &uart4; - serial5 = &uart5; - serial6 = &uart6; - serial7 = &uart7; - serial8 = &uart8; - serial9 = &uart9; - spi0 = &spi0; - spi1 = &spi1; - spi2 = &spi2; - spi3 = &spi3; - }; - - cpus { - #address-cells = <2>; - #size-cells = <0>; - - cpu0: cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a55"; - reg = <0x0 0x0>; - clocks = <&scmi_clk 0>; - #cooling-cells = <2>; - enable-method = "psci"; - operating-points-v2 = <&cpu0_opp_table>; - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <128>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; - next-level-cache = <&l3_cache>; - }; - - cpu1: cpu@100 { - device_type = "cpu"; - compatible = "arm,cortex-a55"; - reg = <0x0 0x100>; - #cooling-cells = <2>; - enable-method = "psci"; - operating-points-v2 = <&cpu0_opp_table>; - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <128>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; - next-level-cache = <&l3_cache>; - }; - - cpu2: cpu@200 { - device_type = "cpu"; - compatible = "arm,cortex-a55"; - reg = <0x0 0x200>; - #cooling-cells = <2>; - enable-method = "psci"; - operating-points-v2 = <&cpu0_opp_table>; - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <128>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; - next-level-cache = <&l3_cache>; - }; - - cpu3: cpu@300 { - device_type = "cpu"; - compatible = "arm,cortex-a55"; - reg = <0x0 0x300>; - #cooling-cells = <2>; - enable-method = "psci"; - operating-points-v2 = <&cpu0_opp_table>; - i-cache-size = <0x8000>; - i-cache-line-size = <64>; - i-cache-sets = <128>; - d-cache-size = <0x8000>; - d-cache-line-size = <64>; - d-cache-sets = <128>; - next-level-cache = <&l3_cache>; - }; - }; - - /* - * There are no private per-core L2 caches, but only the - * L3 cache that appears to the CPU cores as L2 caches - */ - l3_cache: l3-cache { - compatible = "cache"; - cache-level = <2>; - cache-unified; - cache-size = <0x80000>; - cache-line-size = <64>; - cache-sets = <512>; - }; - - cpu0_opp_table: opp-table-0 { - compatible = "operating-points-v2"; - opp-shared; - - opp-408000000 { - opp-hz = /bits/ 64 <408000000>; - opp-microvolt = <900000 900000 1150000>; - clock-latency-ns = <40000>; - }; - - opp-600000000 { - opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <900000 900000 1150000>; - }; - - opp-816000000 { - opp-hz = /bits/ 64 <816000000>; - opp-microvolt = <900000 900000 1150000>; - opp-suspend; - }; - - opp-1104000000 { - opp-hz = /bits/ 64 <1104000000>; - opp-microvolt = <900000 900000 1150000>; - }; - - opp-1416000000 { - opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <900000 900000 1150000>; - }; - - opp-1608000000 { - opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <975000 975000 1150000>; - }; - - opp-1800000000 { - opp-hz = /bits/ 64 <1800000000>; - opp-microvolt = <1050000 1050000 1150000>; - }; - }; - - display_subsystem: display-subsystem { - compatible = "rockchip,display-subsystem"; - ports = <&vop_out>; - }; - - firmware { - scmi: scmi { - compatible = "arm,scmi-smc"; - arm,smc-id = <0x82000010>; - shmem = <&scmi_shmem>; - #address-cells = <1>; - #size-cells = <0>; - - scmi_clk: protocol@14 { - reg = <0x14>; - #clock-cells = <1>; - }; - }; - }; - - gpu_opp_table: opp-table-1 { - compatible = "operating-points-v2"; - - opp-200000000 { - opp-hz = /bits/ 64 <200000000>; - opp-microvolt = <850000 850000 1000000>; - }; - - opp-300000000 { - opp-hz = /bits/ 64 <300000000>; - opp-microvolt = <850000 850000 1000000>; - }; - - opp-400000000 { - opp-hz = /bits/ 64 <400000000>; - opp-microvolt = <850000 850000 1000000>; - }; - - opp-600000000 { - opp-hz = /bits/ 64 <600000000>; - opp-microvolt = <900000 900000 1000000>; - }; - - opp-700000000 { - opp-hz = /bits/ 64 <700000000>; - opp-microvolt = <950000 950000 1000000>; - }; - - opp-800000000 { - opp-hz = /bits/ 64 <800000000>; - opp-microvolt = <1000000 1000000 1000000>; - }; - }; - - hdmi_sound: hdmi-sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "HDMI"; - simple-audio-card,format = "i2s"; - simple-audio-card,mclk-fs = <256>; - status = "disabled"; - - simple-audio-card,codec { - sound-dai = <&hdmi>; - }; - - simple-audio-card,cpu { - sound-dai = <&i2s0_8ch>; - }; - }; - - pmu { - compatible = "arm,cortex-a55-pmu"; - interrupts = , - , - , - ; - interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; - }; - - psci { - compatible = "arm,psci-1.0"; - method = "smc"; - }; - - timer { - compatible = "arm,armv8-timer"; - interrupts = , - , - , - ; - arm,no-tick-in-suspend; - }; - - xin24m: xin24m { - compatible = "fixed-clock"; - clock-frequency = <24000000>; - clock-output-names = "xin24m"; - #clock-cells = <0>; - }; - - xin32k: xin32k { - compatible = "fixed-clock"; - clock-frequency = <32768>; - clock-output-names = "xin32k"; - pinctrl-0 = <&clk32k_out0>; - pinctrl-names = "default"; - #clock-cells = <0>; - }; - - sram@10f000 { - compatible = "mmio-sram"; - reg = <0x0 0x0010f000 0x0 0x100>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 0x0 0x0010f000 0x100>; - - scmi_shmem: sram@0 { - compatible = "arm,scmi-shmem"; - reg = <0x0 0x100>; - }; - }; - - sata1: sata@fc400000 { - compatible = "rockchip,rk3568-dwc-ahci", "snps,dwc-ahci"; - reg = <0 0xfc400000 0 0x1000>; - clocks = <&cru ACLK_SATA1>, <&cru CLK_SATA1_PMALIVE>, - <&cru CLK_SATA1_RXOOB>; - clock-names = "sata", "pmalive", "rxoob"; - interrupts = ; - phys = <&combphy1 PHY_TYPE_SATA>; - phy-names = "sata-phy"; - ports-implemented = <0x1>; - power-domains = <&power RK3568_PD_PIPE>; - status = "disabled"; - }; - - sata2: sata@fc800000 { - compatible = "rockchip,rk3568-dwc-ahci", "snps,dwc-ahci"; - reg = <0 0xfc800000 0 0x1000>; - clocks = <&cru ACLK_SATA2>, <&cru CLK_SATA2_PMALIVE>, - <&cru CLK_SATA2_RXOOB>; - clock-names = "sata", "pmalive", "rxoob"; - interrupts = ; - phys = <&combphy2 PHY_TYPE_SATA>; - phy-names = "sata-phy"; - ports-implemented = <0x1>; - power-domains = <&power RK3568_PD_PIPE>; - status = "disabled"; - }; - - usb_host0_xhci: usb@fcc00000 { - compatible = "rockchip,rk3568-dwc3", "snps,dwc3"; - reg = <0x0 0xfcc00000 0x0 0x400000>; - interrupts = ; - clocks = <&cru CLK_USB3OTG0_REF>, <&cru CLK_USB3OTG0_SUSPEND>, - <&cru ACLK_USB3OTG0>; - clock-names = "ref_clk", "suspend_clk", - "bus_clk"; - dr_mode = "otg"; - phy_type = "utmi_wide"; - power-domains = <&power RK3568_PD_PIPE>; - resets = <&cru SRST_USB3OTG0>; - snps,dis_u2_susphy_quirk; - status = "disabled"; - }; - - usb_host1_xhci: usb@fd000000 { - compatible = "rockchip,rk3568-dwc3", "snps,dwc3"; - reg = <0x0 0xfd000000 0x0 0x400000>; - interrupts = ; - clocks = <&cru CLK_USB3OTG1_REF>, <&cru CLK_USB3OTG1_SUSPEND>, - <&cru ACLK_USB3OTG1>; - clock-names = "ref_clk", "suspend_clk", - "bus_clk"; - dr_mode = "host"; - phys = <&usb2phy0_host>, <&combphy1 PHY_TYPE_USB3>; - phy-names = "usb2-phy", "usb3-phy"; - phy_type = "utmi_wide"; - power-domains = <&power RK3568_PD_PIPE>; - resets = <&cru SRST_USB3OTG1>; - snps,dis_u2_susphy_quirk; - status = "disabled"; - }; - - gic: interrupt-controller@fd400000 { - compatible = "arm,gic-v3"; - reg = <0x0 0xfd400000 0 0x10000>, /* GICD */ - <0x0 0xfd460000 0 0x80000>; /* GICR */ - interrupts = ; - interrupt-controller; - #interrupt-cells = <3>; - mbi-alias = <0x0 0xfd410000>; - mbi-ranges = <296 24>; - msi-controller; - }; - - usb_host0_ehci: usb@fd800000 { - compatible = "generic-ehci"; - reg = <0x0 0xfd800000 0x0 0x40000>; - interrupts = ; - clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>, - <&cru PCLK_USB>; - phys = <&usb2phy1_otg>; - phy-names = "usb"; - status = "disabled"; - }; - - usb_host0_ohci: usb@fd840000 { - compatible = "generic-ohci"; - reg = <0x0 0xfd840000 0x0 0x40000>; - interrupts = ; - clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>, - <&cru PCLK_USB>; - phys = <&usb2phy1_otg>; - phy-names = "usb"; - status = "disabled"; - }; - - usb_host1_ehci: usb@fd880000 { - compatible = "generic-ehci"; - reg = <0x0 0xfd880000 0x0 0x40000>; - interrupts = ; - clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>, - <&cru PCLK_USB>; - phys = <&usb2phy1_host>; - phy-names = "usb"; - status = "disabled"; - }; - - usb_host1_ohci: usb@fd8c0000 { - compatible = "generic-ohci"; - reg = <0x0 0xfd8c0000 0x0 0x40000>; - interrupts = ; - clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>, - <&cru PCLK_USB>; - phys = <&usb2phy1_host>; - phy-names = "usb"; - status = "disabled"; - }; - - pmugrf: syscon@fdc20000 { - compatible = "rockchip,rk3568-pmugrf", "syscon", "simple-mfd"; - reg = <0x0 0xfdc20000 0x0 0x10000>; - - pmu_io_domains: io-domains { - compatible = "rockchip,rk3568-pmu-io-voltage-domain"; - status = "disabled"; - }; - }; - - pipegrf: syscon@fdc50000 { - reg = <0x0 0xfdc50000 0x0 0x1000>; - }; - - grf: syscon@fdc60000 { - compatible = "rockchip,rk3568-grf", "syscon", "simple-mfd"; - reg = <0x0 0xfdc60000 0x0 0x10000>; - }; - - pipe_phy_grf1: syscon@fdc80000 { - compatible = "rockchip,rk3568-pipe-phy-grf", "syscon"; - reg = <0x0 0xfdc80000 0x0 0x1000>; - }; - - pipe_phy_grf2: syscon@fdc90000 { - compatible = "rockchip,rk3568-pipe-phy-grf", "syscon"; - reg = <0x0 0xfdc90000 0x0 0x1000>; - }; - - usb2phy0_grf: syscon@fdca0000 { - compatible = "rockchip,rk3568-usb2phy-grf", "syscon"; - reg = <0x0 0xfdca0000 0x0 0x8000>; - }; - - usb2phy1_grf: syscon@fdca8000 { - compatible = "rockchip,rk3568-usb2phy-grf", "syscon"; - reg = <0x0 0xfdca8000 0x0 0x8000>; - }; - - pmucru: clock-controller@fdd00000 { - compatible = "rockchip,rk3568-pmucru"; - reg = <0x0 0xfdd00000 0x0 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - }; - - cru: clock-controller@fdd20000 { - compatible = "rockchip,rk3568-cru"; - reg = <0x0 0xfdd20000 0x0 0x1000>; - clocks = <&xin24m>; - clock-names = "xin24m"; - #clock-cells = <1>; - #reset-cells = <1>; - assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>, <&pmucru PLL_PPLL>; - assigned-clock-rates = <32768>, <1200000000>, <200000000>; - assigned-clock-parents = <&pmucru CLK_RTC32K_FRAC>; - rockchip,grf = <&grf>; - }; - - i2c0: i2c@fdd40000 { - compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; - reg = <0x0 0xfdd40000 0x0 0x1000>; - interrupts = ; - clocks = <&pmucru CLK_I2C0>, <&pmucru PCLK_I2C0>; - clock-names = "i2c", "pclk"; - pinctrl-0 = <&i2c0_xfer>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - uart0: serial@fdd50000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfdd50000 0x0 0x100>; - interrupts = ; - clocks = <&pmucru SCLK_UART0>, <&pmucru PCLK_UART0>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 0>, <&dmac0 1>; - pinctrl-0 = <&uart0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - pwm0: pwm@fdd70000 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfdd70000 0x0 0x10>; - clocks = <&pmucru CLK_PWM0>, <&pmucru PCLK_PWM0>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm0m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm1: pwm@fdd70010 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfdd70010 0x0 0x10>; - clocks = <&pmucru CLK_PWM0>, <&pmucru PCLK_PWM0>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm1m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm2: pwm@fdd70020 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfdd70020 0x0 0x10>; - clocks = <&pmucru CLK_PWM0>, <&pmucru PCLK_PWM0>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm2m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm3: pwm@fdd70030 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfdd70030 0x0 0x10>; - clocks = <&pmucru CLK_PWM0>, <&pmucru PCLK_PWM0>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm3_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pmu: power-management@fdd90000 { - compatible = "rockchip,rk3568-pmu", "syscon", "simple-mfd"; - reg = <0x0 0xfdd90000 0x0 0x1000>; - - power: power-controller { - compatible = "rockchip,rk3568-power-controller"; - #power-domain-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - - /* These power domains are grouped by VD_GPU */ - power-domain@RK3568_PD_GPU { - reg = ; - clocks = <&cru ACLK_GPU_PRE>, - <&cru PCLK_GPU_PRE>; - pm_qos = <&qos_gpu>; - #power-domain-cells = <0>; - }; - - /* These power domains are grouped by VD_LOGIC */ - power-domain@RK3568_PD_VI { - reg = ; - clocks = <&cru HCLK_VI>, - <&cru PCLK_VI>; - pm_qos = <&qos_isp>, - <&qos_vicap0>, - <&qos_vicap1>; - #power-domain-cells = <0>; - }; - - power-domain@RK3568_PD_VO { - reg = ; - clocks = <&cru HCLK_VO>, - <&cru PCLK_VO>, - <&cru ACLK_VOP_PRE>; - pm_qos = <&qos_hdcp>, - <&qos_vop_m0>, - <&qos_vop_m1>; - #power-domain-cells = <0>; - }; - - power-domain@RK3568_PD_RGA { - reg = ; - clocks = <&cru HCLK_RGA_PRE>, - <&cru PCLK_RGA_PRE>; - pm_qos = <&qos_ebc>, - <&qos_iep>, - <&qos_jpeg_dec>, - <&qos_jpeg_enc>, - <&qos_rga_rd>, - <&qos_rga_wr>; - #power-domain-cells = <0>; - }; - - power-domain@RK3568_PD_VPU { - reg = ; - clocks = <&cru HCLK_VPU_PRE>; - pm_qos = <&qos_vpu>; - #power-domain-cells = <0>; - }; - - power-domain@RK3568_PD_RKVDEC { - clocks = <&cru HCLK_RKVDEC_PRE>; - reg = ; - pm_qos = <&qos_rkvdec>; - #power-domain-cells = <0>; - }; - - power-domain@RK3568_PD_RKVENC { - reg = ; - clocks = <&cru HCLK_RKVENC_PRE>; - pm_qos = <&qos_rkvenc_rd_m0>, - <&qos_rkvenc_rd_m1>, - <&qos_rkvenc_wr_m0>; - #power-domain-cells = <0>; - }; - }; - }; - - gpu: gpu@fde60000 { - compatible = "rockchip,rk3568-mali", "arm,mali-bifrost"; - reg = <0x0 0xfde60000 0x0 0x4000>; - interrupts = , - , - ; - interrupt-names = "job", "mmu", "gpu"; - clocks = <&scmi_clk 1>, <&cru CLK_GPU>; - clock-names = "gpu", "bus"; - #cooling-cells = <2>; - operating-points-v2 = <&gpu_opp_table>; - power-domains = <&power RK3568_PD_GPU>; - status = "disabled"; - }; - - vpu: video-codec@fdea0400 { - compatible = "rockchip,rk3568-vpu"; - reg = <0x0 0xfdea0000 0x0 0x800>; - interrupts = ; - interrupt-names = "vdpu"; - clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; - clock-names = "aclk", "hclk"; - iommus = <&vdpu_mmu>; - power-domains = <&power RK3568_PD_VPU>; - }; - - vdpu_mmu: iommu@fdea0800 { - compatible = "rockchip,rk3568-iommu"; - reg = <0x0 0xfdea0800 0x0 0x40>; - interrupts = ; - clock-names = "aclk", "iface"; - clocks = <&cru ACLK_VPU>, <&cru HCLK_VPU>; - power-domains = <&power RK3568_PD_VPU>; - #iommu-cells = <0>; - }; - - rga: rga@fdeb0000 { - compatible = "rockchip,rk3568-rga", "rockchip,rk3288-rga"; - reg = <0x0 0xfdeb0000 0x0 0x180>; - interrupts = ; - clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru CLK_RGA_CORE>; - clock-names = "aclk", "hclk", "sclk"; - resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>; - reset-names = "core", "axi", "ahb"; - power-domains = <&power RK3568_PD_RGA>; - }; - - vepu: video-codec@fdee0000 { - compatible = "rockchip,rk3568-vepu"; - reg = <0x0 0xfdee0000 0x0 0x800>; - interrupts = ; - clocks = <&cru ACLK_JENC>, <&cru HCLK_JENC>; - clock-names = "aclk", "hclk"; - iommus = <&vepu_mmu>; - power-domains = <&power RK3568_PD_RGA>; - }; - - vepu_mmu: iommu@fdee0800 { - compatible = "rockchip,rk3568-iommu"; - reg = <0x0 0xfdee0800 0x0 0x40>; - interrupts = ; - clocks = <&cru ACLK_JENC>, <&cru HCLK_JENC>; - clock-names = "aclk", "iface"; - power-domains = <&power RK3568_PD_RGA>; - #iommu-cells = <0>; - }; - - sdmmc2: mmc@fe000000 { - compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; - reg = <0x0 0xfe000000 0x0 0x4000>; - interrupts = ; - clocks = <&cru HCLK_SDMMC2>, <&cru CLK_SDMMC2>, - <&cru SCLK_SDMMC2_DRV>, <&cru SCLK_SDMMC2_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - max-frequency = <150000000>; - resets = <&cru SRST_SDMMC2>; - reset-names = "reset"; - status = "disabled"; - }; - - gmac1: ethernet@fe010000 { - compatible = "rockchip,rk3568-gmac", "snps,dwmac-4.20a"; - reg = <0x0 0xfe010000 0x0 0x10000>; - interrupts = , - ; - interrupt-names = "macirq", "eth_wake_irq"; - clocks = <&cru SCLK_GMAC1>, <&cru SCLK_GMAC1_RX_TX>, - <&cru SCLK_GMAC1_RX_TX>, <&cru CLK_MAC1_REFOUT>, - <&cru ACLK_GMAC1>, <&cru PCLK_GMAC1>, - <&cru SCLK_GMAC1_RX_TX>, <&cru CLK_GMAC1_PTP_REF>; - clock-names = "stmmaceth", "mac_clk_rx", - "mac_clk_tx", "clk_mac_refout", - "aclk_mac", "pclk_mac", - "clk_mac_speed", "ptp_ref"; - resets = <&cru SRST_A_GMAC1>; - reset-names = "stmmaceth"; - rockchip,grf = <&grf>; - snps,axi-config = <&gmac1_stmmac_axi_setup>; - snps,mixed-burst; - snps,mtl-rx-config = <&gmac1_mtl_rx_setup>; - snps,mtl-tx-config = <&gmac1_mtl_tx_setup>; - snps,tso; - status = "disabled"; - - mdio1: mdio { - compatible = "snps,dwmac-mdio"; - #address-cells = <0x1>; - #size-cells = <0x0>; - }; - - gmac1_stmmac_axi_setup: stmmac-axi-config { - snps,blen = <0 0 0 0 16 8 4>; - snps,rd_osr_lmt = <8>; - snps,wr_osr_lmt = <4>; - }; - - gmac1_mtl_rx_setup: rx-queues-config { - snps,rx-queues-to-use = <1>; - queue0 {}; - }; - - gmac1_mtl_tx_setup: tx-queues-config { - snps,tx-queues-to-use = <1>; - queue0 {}; - }; - }; - - vop: vop@fe040000 { - reg = <0x0 0xfe040000 0x0 0x3000>, <0x0 0xfe044000 0x0 0x1000>; - reg-names = "vop", "gamma-lut"; - interrupts = ; - clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>, <&cru DCLK_VOP0>, - <&cru DCLK_VOP1>, <&cru DCLK_VOP2>; - clock-names = "aclk", "hclk", "dclk_vp0", "dclk_vp1", "dclk_vp2"; - iommus = <&vop_mmu>; - power-domains = <&power RK3568_PD_VO>; - rockchip,grf = <&grf>; - status = "disabled"; - - vop_out: ports { - #address-cells = <1>; - #size-cells = <0>; - - vp0: port@0 { - reg = <0>; - #address-cells = <1>; - #size-cells = <0>; - }; - - vp1: port@1 { - reg = <1>; - #address-cells = <1>; - #size-cells = <0>; - }; - - vp2: port@2 { - reg = <2>; - #address-cells = <1>; - #size-cells = <0>; - }; - }; - }; - - vop_mmu: iommu@fe043e00 { - compatible = "rockchip,rk3568-iommu"; - reg = <0x0 0xfe043e00 0x0 0x100>, <0x0 0xfe043f00 0x0 0x100>; - interrupts = ; - clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>; - clock-names = "aclk", "iface"; - #iommu-cells = <0>; - power-domains = <&power RK3568_PD_VO>; - status = "disabled"; - }; - - dsi0: dsi@fe060000 { - compatible = "rockchip,rk3568-mipi-dsi", "snps,dw-mipi-dsi"; - reg = <0x00 0xfe060000 0x00 0x10000>; - interrupts = ; - clock-names = "pclk"; - clocks = <&cru PCLK_DSITX_0>; - phy-names = "dphy"; - phys = <&dsi_dphy0>; - power-domains = <&power RK3568_PD_VO>; - reset-names = "apb"; - resets = <&cru SRST_P_DSITX_0>; - rockchip,grf = <&grf>; - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - dsi0_in: port@0 { - reg = <0>; - }; - - dsi0_out: port@1 { - reg = <1>; - }; - }; - }; - - dsi1: dsi@fe070000 { - compatible = "rockchip,rk3568-mipi-dsi", "snps,dw-mipi-dsi"; - reg = <0x0 0xfe070000 0x0 0x10000>; - interrupts = ; - clock-names = "pclk"; - clocks = <&cru PCLK_DSITX_1>; - phy-names = "dphy"; - phys = <&dsi_dphy1>; - power-domains = <&power RK3568_PD_VO>; - reset-names = "apb"; - resets = <&cru SRST_P_DSITX_1>; - rockchip,grf = <&grf>; - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - dsi1_in: port@0 { - reg = <0>; - }; - - dsi1_out: port@1 { - reg = <1>; - }; - }; - }; - - hdmi: hdmi@fe0a0000 { - compatible = "rockchip,rk3568-dw-hdmi"; - reg = <0x0 0xfe0a0000 0x0 0x20000>; - interrupts = ; - clocks = <&cru PCLK_HDMI_HOST>, - <&cru CLK_HDMI_SFR>, - <&cru CLK_HDMI_CEC>, - <&pmucru CLK_HDMI_REF>, - <&cru HCLK_VO>; - clock-names = "iahb", "isfr", "cec", "ref"; - pinctrl-names = "default"; - pinctrl-0 = <&hdmitx_scl &hdmitx_sda &hdmitxm0_cec>; - power-domains = <&power RK3568_PD_VO>; - reg-io-width = <4>; - rockchip,grf = <&grf>; - #sound-dai-cells = <0>; - status = "disabled"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - hdmi_in: port@0 { - reg = <0>; - }; - - hdmi_out: port@1 { - reg = <1>; - }; - }; - }; - - qos_gpu: qos@fe128000 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe128000 0x0 0x20>; - }; - - qos_rkvenc_rd_m0: qos@fe138080 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe138080 0x0 0x20>; - }; - - qos_rkvenc_rd_m1: qos@fe138100 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe138100 0x0 0x20>; - }; - - qos_rkvenc_wr_m0: qos@fe138180 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe138180 0x0 0x20>; - }; - - qos_isp: qos@fe148000 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe148000 0x0 0x20>; - }; - - qos_vicap0: qos@fe148080 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe148080 0x0 0x20>; - }; - - qos_vicap1: qos@fe148100 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe148100 0x0 0x20>; - }; - - qos_vpu: qos@fe150000 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe150000 0x0 0x20>; - }; - - qos_ebc: qos@fe158000 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe158000 0x0 0x20>; - }; - - qos_iep: qos@fe158100 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe158100 0x0 0x20>; - }; - - qos_jpeg_dec: qos@fe158180 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe158180 0x0 0x20>; - }; - - qos_jpeg_enc: qos@fe158200 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe158200 0x0 0x20>; - }; - - qos_rga_rd: qos@fe158280 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe158280 0x0 0x20>; - }; - - qos_rga_wr: qos@fe158300 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe158300 0x0 0x20>; - }; - - qos_npu: qos@fe180000 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe180000 0x0 0x20>; - }; - - qos_pcie2x1: qos@fe190000 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe190000 0x0 0x20>; - }; - - qos_sata1: qos@fe190280 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe190280 0x0 0x20>; - }; - - qos_sata2: qos@fe190300 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe190300 0x0 0x20>; - }; - - qos_usb3_0: qos@fe190380 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe190380 0x0 0x20>; - }; - - qos_usb3_1: qos@fe190400 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe190400 0x0 0x20>; - }; - - qos_rkvdec: qos@fe198000 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe198000 0x0 0x20>; - }; - - qos_hdcp: qos@fe1a8000 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe1a8000 0x0 0x20>; - }; - - qos_vop_m0: qos@fe1a8080 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe1a8080 0x0 0x20>; - }; - - qos_vop_m1: qos@fe1a8100 { - compatible = "rockchip,rk3568-qos", "syscon"; - reg = <0x0 0xfe1a8100 0x0 0x20>; - }; - - dfi: dfi@fe230000 { - compatible = "rockchip,rk3568-dfi"; - reg = <0x00 0xfe230000 0x00 0x400>; - interrupts = ; - rockchip,pmu = <&pmugrf>; - }; - - pcie2x1: pcie@fe260000 { - compatible = "rockchip,rk3568-pcie"; - reg = <0x3 0xc0000000 0x0 0x00400000>, - <0x0 0xfe260000 0x0 0x00010000>, - <0x0 0xf4000000 0x0 0x00100000>; - reg-names = "dbi", "apb", "config"; - interrupts = , - , - , - , - ; - interrupt-names = "sys", "pmc", "msg", "legacy", "err"; - bus-range = <0x0 0xf>; - clocks = <&cru ACLK_PCIE20_MST>, <&cru ACLK_PCIE20_SLV>, - <&cru ACLK_PCIE20_DBI>, <&cru PCLK_PCIE20>, - <&cru CLK_PCIE20_AUX_NDFT>; - clock-names = "aclk_mst", "aclk_slv", - "aclk_dbi", "pclk", "aux"; - device_type = "pci"; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 7>; - interrupt-map = <0 0 0 1 &pcie_intc 0>, - <0 0 0 2 &pcie_intc 1>, - <0 0 0 3 &pcie_intc 2>, - <0 0 0 4 &pcie_intc 3>; - linux,pci-domain = <0>; - num-ib-windows = <6>; - num-ob-windows = <2>; - max-link-speed = <2>; - msi-map = <0x0 &gic 0x0 0x1000>; - num-lanes = <1>; - phys = <&combphy2 PHY_TYPE_PCIE>; - phy-names = "pcie-phy"; - power-domains = <&power RK3568_PD_PIPE>; - ranges = <0x01000000 0x0 0xf4100000 0x0 0xf4100000 0x0 0x00100000>, - <0x02000000 0x0 0xf4200000 0x0 0xf4200000 0x0 0x01e00000>, - <0x03000000 0x0 0x40000000 0x3 0x00000000 0x0 0x40000000>; - resets = <&cru SRST_PCIE20_POWERUP>; - reset-names = "pipe"; - #address-cells = <3>; - #size-cells = <2>; - status = "disabled"; - - pcie_intc: legacy-interrupt-controller { - #address-cells = <0>; - #interrupt-cells = <1>; - interrupt-controller; - interrupt-parent = <&gic>; - interrupts = ; - }; - }; - - sdmmc0: mmc@fe2b0000 { - compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; - reg = <0x0 0xfe2b0000 0x0 0x4000>; - interrupts = ; - clocks = <&cru HCLK_SDMMC0>, <&cru CLK_SDMMC0>, - <&cru SCLK_SDMMC0_DRV>, <&cru SCLK_SDMMC0_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - max-frequency = <150000000>; - resets = <&cru SRST_SDMMC0>; - reset-names = "reset"; - status = "disabled"; - }; - - sdmmc1: mmc@fe2c0000 { - compatible = "rockchip,rk3568-dw-mshc", "rockchip,rk3288-dw-mshc"; - reg = <0x0 0xfe2c0000 0x0 0x4000>; - interrupts = ; - clocks = <&cru HCLK_SDMMC1>, <&cru CLK_SDMMC1>, - <&cru SCLK_SDMMC1_DRV>, <&cru SCLK_SDMMC1_SAMPLE>; - clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - fifo-depth = <0x100>; - max-frequency = <150000000>; - resets = <&cru SRST_SDMMC1>; - reset-names = "reset"; - status = "disabled"; - }; - - sfc: spi@fe300000 { - compatible = "rockchip,sfc"; - reg = <0x0 0xfe300000 0x0 0x4000>; - interrupts = ; - clocks = <&cru SCLK_SFC>, <&cru HCLK_SFC>; - clock-names = "clk_sfc", "hclk_sfc"; - pinctrl-0 = <&fspi_pins>; - pinctrl-names = "default"; - status = "disabled"; - }; - - sdhci: mmc@fe310000 { - compatible = "rockchip,rk3568-dwcmshc"; - reg = <0x0 0xfe310000 0x0 0x10000>; - interrupts = ; - assigned-clocks = <&cru BCLK_EMMC>, <&cru TCLK_EMMC>; - assigned-clock-rates = <200000000>, <24000000>; - clocks = <&cru CCLK_EMMC>, <&cru HCLK_EMMC>, - <&cru ACLK_EMMC>, <&cru BCLK_EMMC>, - <&cru TCLK_EMMC>; - clock-names = "core", "bus", "axi", "block", "timer"; - status = "disabled"; - }; - - rng: rng@fe388000 { - compatible = "rockchip,rk3568-rng"; - reg = <0x0 0xfe388000 0x0 0x4000>; - clocks = <&cru CLK_TRNG_NS>, <&cru HCLK_TRNG_NS>; - clock-names = "core", "ahb"; - resets = <&cru SRST_TRNG_NS>; - status = "disabled"; - }; - - i2s0_8ch: i2s@fe400000 { - compatible = "rockchip,rk3568-i2s-tdm"; - reg = <0x0 0xfe400000 0x0 0x1000>; - interrupts = ; - assigned-clocks = <&cru CLK_I2S0_8CH_TX_SRC>, <&cru CLK_I2S0_8CH_RX_SRC>; - assigned-clock-rates = <1188000000>, <1188000000>; - clocks = <&cru MCLK_I2S0_8CH_TX>, <&cru MCLK_I2S0_8CH_RX>, <&cru HCLK_I2S0_8CH>; - clock-names = "mclk_tx", "mclk_rx", "hclk"; - dmas = <&dmac1 0>; - dma-names = "tx"; - resets = <&cru SRST_M_I2S0_8CH_TX>, <&cru SRST_M_I2S0_8CH_RX>; - reset-names = "tx-m", "rx-m"; - rockchip,grf = <&grf>; - #sound-dai-cells = <0>; - status = "disabled"; - }; - - i2s1_8ch: i2s@fe410000 { - compatible = "rockchip,rk3568-i2s-tdm"; - reg = <0x0 0xfe410000 0x0 0x1000>; - interrupts = ; - assigned-clocks = <&cru CLK_I2S1_8CH_TX_SRC>, <&cru CLK_I2S1_8CH_RX_SRC>; - assigned-clock-rates = <1188000000>, <1188000000>; - clocks = <&cru MCLK_I2S1_8CH_TX>, <&cru MCLK_I2S1_8CH_RX>, - <&cru HCLK_I2S1_8CH>; - clock-names = "mclk_tx", "mclk_rx", "hclk"; - dmas = <&dmac1 3>, <&dmac1 2>; - dma-names = "rx", "tx"; - resets = <&cru SRST_M_I2S1_8CH_TX>, <&cru SRST_M_I2S1_8CH_RX>; - reset-names = "tx-m", "rx-m"; - rockchip,grf = <&grf>; - pinctrl-names = "default"; - pinctrl-0 = <&i2s1m0_sclktx &i2s1m0_sclkrx - &i2s1m0_lrcktx &i2s1m0_lrckrx - &i2s1m0_sdi0 &i2s1m0_sdi1 - &i2s1m0_sdi2 &i2s1m0_sdi3 - &i2s1m0_sdo0 &i2s1m0_sdo1 - &i2s1m0_sdo2 &i2s1m0_sdo3>; - #sound-dai-cells = <0>; - status = "disabled"; - }; - - i2s2_2ch: i2s@fe420000 { - compatible = "rockchip,rk3568-i2s-tdm"; - reg = <0x0 0xfe420000 0x0 0x1000>; - interrupts = ; - assigned-clocks = <&cru CLK_I2S2_2CH_SRC>; - assigned-clock-rates = <1188000000>; - clocks = <&cru MCLK_I2S2_2CH>, <&cru MCLK_I2S2_2CH>, <&cru HCLK_I2S2_2CH>; - clock-names = "mclk_tx", "mclk_rx", "hclk"; - dmas = <&dmac1 4>, <&dmac1 5>; - dma-names = "tx", "rx"; - resets = <&cru SRST_M_I2S2_2CH>; - reset-names = "tx-m"; - rockchip,grf = <&grf>; - pinctrl-names = "default"; - pinctrl-0 = <&i2s2m0_sclktx - &i2s2m0_lrcktx - &i2s2m0_sdi - &i2s2m0_sdo>; - #sound-dai-cells = <0>; - status = "disabled"; - }; - - i2s3_2ch: i2s@fe430000 { - compatible = "rockchip,rk3568-i2s-tdm"; - reg = <0x0 0xfe430000 0x0 0x1000>; - interrupts = ; - clocks = <&cru MCLK_I2S3_2CH_TX>, <&cru MCLK_I2S3_2CH_RX>, - <&cru HCLK_I2S3_2CH>; - clock-names = "mclk_tx", "mclk_rx", "hclk"; - dmas = <&dmac1 6>, <&dmac1 7>; - dma-names = "tx", "rx"; - resets = <&cru SRST_M_I2S3_2CH_TX>, <&cru SRST_M_I2S3_2CH_RX>; - reset-names = "tx-m", "rx-m"; - rockchip,grf = <&grf>; - #sound-dai-cells = <0>; - status = "disabled"; - }; - - pdm: pdm@fe440000 { - compatible = "rockchip,rk3568-pdm"; - reg = <0x0 0xfe440000 0x0 0x1000>; - interrupts = ; - clocks = <&cru MCLK_PDM>, <&cru HCLK_PDM>; - clock-names = "pdm_clk", "pdm_hclk"; - dmas = <&dmac1 9>; - dma-names = "rx"; - pinctrl-0 = <&pdmm0_clk - &pdmm0_clk1 - &pdmm0_sdi0 - &pdmm0_sdi1 - &pdmm0_sdi2 - &pdmm0_sdi3>; - pinctrl-names = "default"; - resets = <&cru SRST_M_PDM>; - reset-names = "pdm-m"; - #sound-dai-cells = <0>; - status = "disabled"; - }; - - spdif: spdif@fe460000 { - compatible = "rockchip,rk3568-spdif"; - reg = <0x0 0xfe460000 0x0 0x1000>; - interrupts = ; - clock-names = "mclk", "hclk"; - clocks = <&cru MCLK_SPDIF_8CH>, <&cru HCLK_SPDIF_8CH>; - dmas = <&dmac1 1>; - dma-names = "tx"; - pinctrl-names = "default"; - pinctrl-0 = <&spdifm0_tx>; - #sound-dai-cells = <0>; - status = "disabled"; - }; - - dmac0: dma-controller@fe530000 { - compatible = "arm,pl330", "arm,primecell"; - reg = <0x0 0xfe530000 0x0 0x4000>; - interrupts = , - ; - arm,pl330-periph-burst; - clocks = <&cru ACLK_BUS>; - clock-names = "apb_pclk"; - #dma-cells = <1>; - }; - - dmac1: dma-controller@fe550000 { - compatible = "arm,pl330", "arm,primecell"; - reg = <0x0 0xfe550000 0x0 0x4000>; - interrupts = , - ; - arm,pl330-periph-burst; - clocks = <&cru ACLK_BUS>; - clock-names = "apb_pclk"; - #dma-cells = <1>; - }; - - i2c1: i2c@fe5a0000 { - compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; - reg = <0x0 0xfe5a0000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_I2C1>, <&cru PCLK_I2C1>; - clock-names = "i2c", "pclk"; - pinctrl-0 = <&i2c1_xfer>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c2: i2c@fe5b0000 { - compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; - reg = <0x0 0xfe5b0000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_I2C2>, <&cru PCLK_I2C2>; - clock-names = "i2c", "pclk"; - pinctrl-0 = <&i2c2m0_xfer>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c3: i2c@fe5c0000 { - compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; - reg = <0x0 0xfe5c0000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_I2C3>, <&cru PCLK_I2C3>; - clock-names = "i2c", "pclk"; - pinctrl-0 = <&i2c3m0_xfer>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c4: i2c@fe5d0000 { - compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; - reg = <0x0 0xfe5d0000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_I2C4>, <&cru PCLK_I2C4>; - clock-names = "i2c", "pclk"; - pinctrl-0 = <&i2c4m0_xfer>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c5: i2c@fe5e0000 { - compatible = "rockchip,rk3568-i2c", "rockchip,rk3399-i2c"; - reg = <0x0 0xfe5e0000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_I2C5>, <&cru PCLK_I2C5>; - clock-names = "i2c", "pclk"; - pinctrl-0 = <&i2c5m0_xfer>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - wdt: watchdog@fe600000 { - compatible = "rockchip,rk3568-wdt", "snps,dw-wdt"; - reg = <0x0 0xfe600000 0x0 0x100>; - interrupts = ; - clocks = <&cru TCLK_WDT_NS>, <&cru PCLK_WDT_NS>; - clock-names = "tclk", "pclk"; - }; - - spi0: spi@fe610000 { - compatible = "rockchip,rk3568-spi", "rockchip,rk3066-spi"; - reg = <0x0 0xfe610000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_SPI0>, <&cru PCLK_SPI0>; - clock-names = "spiclk", "apb_pclk"; - dmas = <&dmac0 20>, <&dmac0 21>; - dma-names = "tx", "rx"; - pinctrl-names = "default"; - pinctrl-0 = <&spi0m0_cs0 &spi0m0_cs1 &spi0m0_pins>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi1: spi@fe620000 { - compatible = "rockchip,rk3568-spi", "rockchip,rk3066-spi"; - reg = <0x0 0xfe620000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_SPI1>, <&cru PCLK_SPI1>; - clock-names = "spiclk", "apb_pclk"; - dmas = <&dmac0 22>, <&dmac0 23>; - dma-names = "tx", "rx"; - pinctrl-names = "default"; - pinctrl-0 = <&spi1m0_cs0 &spi1m0_cs1 &spi1m0_pins>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi2: spi@fe630000 { - compatible = "rockchip,rk3568-spi", "rockchip,rk3066-spi"; - reg = <0x0 0xfe630000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_SPI2>, <&cru PCLK_SPI2>; - clock-names = "spiclk", "apb_pclk"; - dmas = <&dmac0 24>, <&dmac0 25>; - dma-names = "tx", "rx"; - pinctrl-names = "default"; - pinctrl-0 = <&spi2m0_cs0 &spi2m0_cs1 &spi2m0_pins>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi3: spi@fe640000 { - compatible = "rockchip,rk3568-spi", "rockchip,rk3066-spi"; - reg = <0x0 0xfe640000 0x0 0x1000>; - interrupts = ; - clocks = <&cru CLK_SPI3>, <&cru PCLK_SPI3>; - clock-names = "spiclk", "apb_pclk"; - dmas = <&dmac0 26>, <&dmac0 27>; - dma-names = "tx", "rx"; - pinctrl-names = "default"; - pinctrl-0 = <&spi3m0_cs0 &spi3m0_cs1 &spi3m0_pins>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - uart1: serial@fe650000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe650000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 2>, <&dmac0 3>; - pinctrl-0 = <&uart1m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - uart2: serial@fe660000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe660000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 4>, <&dmac0 5>; - pinctrl-0 = <&uart2m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - uart3: serial@fe670000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe670000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 6>, <&dmac0 7>; - pinctrl-0 = <&uart3m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - uart4: serial@fe680000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe680000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 8>, <&dmac0 9>; - pinctrl-0 = <&uart4m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - uart5: serial@fe690000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe690000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART5>, <&cru PCLK_UART5>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 10>, <&dmac0 11>; - pinctrl-0 = <&uart5m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - uart6: serial@fe6a0000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe6a0000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART6>, <&cru PCLK_UART6>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 12>, <&dmac0 13>; - pinctrl-0 = <&uart6m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - uart7: serial@fe6b0000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe6b0000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART7>, <&cru PCLK_UART7>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 14>, <&dmac0 15>; - pinctrl-0 = <&uart7m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - uart8: serial@fe6c0000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe6c0000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART8>, <&cru PCLK_UART8>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 16>, <&dmac0 17>; - pinctrl-0 = <&uart8m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - uart9: serial@fe6d0000 { - compatible = "rockchip,rk3568-uart", "snps,dw-apb-uart"; - reg = <0x0 0xfe6d0000 0x0 0x100>; - interrupts = ; - clocks = <&cru SCLK_UART9>, <&cru PCLK_UART9>; - clock-names = "baudclk", "apb_pclk"; - dmas = <&dmac0 18>, <&dmac0 19>; - pinctrl-0 = <&uart9m0_xfer>; - pinctrl-names = "default"; - reg-io-width = <4>; - reg-shift = <2>; - status = "disabled"; - }; - - thermal_zones: thermal-zones { - cpu_thermal: cpu-thermal { - polling-delay-passive = <100>; - polling-delay = <1000>; - - thermal-sensors = <&tsadc 0>; - - trips { - cpu_alert0: cpu_alert0 { - temperature = <70000>; - hysteresis = <2000>; - type = "passive"; - }; - cpu_alert1: cpu_alert1 { - temperature = <75000>; - hysteresis = <2000>; - type = "passive"; - }; - cpu_crit: cpu_crit { - temperature = <95000>; - hysteresis = <2000>; - type = "critical"; - }; - }; - - cooling-maps { - map0 { - trip = <&cpu_alert0>; - cooling-device = - <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, - <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; - }; - }; - }; - - gpu_thermal: gpu-thermal { - polling-delay-passive = <20>; /* milliseconds */ - polling-delay = <1000>; /* milliseconds */ - - thermal-sensors = <&tsadc 1>; - - trips { - gpu_threshold: gpu-threshold { - temperature = <70000>; - hysteresis = <2000>; - type = "passive"; - }; - gpu_target: gpu-target { - temperature = <75000>; - hysteresis = <2000>; - type = "passive"; - }; - gpu_crit: gpu-crit { - temperature = <95000>; - hysteresis = <2000>; - type = "critical"; - }; - }; - - cooling-maps { - map0 { - trip = <&gpu_target>; - cooling-device = - <&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; - }; - }; - }; - }; - - tsadc: tsadc@fe710000 { - compatible = "rockchip,rk3568-tsadc"; - reg = <0x0 0xfe710000 0x0 0x100>; - interrupts = ; - assigned-clocks = <&cru CLK_TSADC_TSEN>, <&cru CLK_TSADC>; - assigned-clock-rates = <17000000>, <700000>; - clocks = <&cru CLK_TSADC>, <&cru PCLK_TSADC>; - clock-names = "tsadc", "apb_pclk"; - resets = <&cru SRST_P_TSADC>, <&cru SRST_TSADC>, - <&cru SRST_TSADCPHY>; - rockchip,grf = <&grf>; - rockchip,hw-tshut-temp = <95000>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&tsadc_shutorg>; - pinctrl-1 = <&tsadc_pin>; - #thermal-sensor-cells = <1>; - status = "disabled"; - }; - - saradc: saradc@fe720000 { - compatible = "rockchip,rk3568-saradc", "rockchip,rk3399-saradc"; - reg = <0x0 0xfe720000 0x0 0x100>; - interrupts = ; - clocks = <&cru CLK_SARADC>, <&cru PCLK_SARADC>; - clock-names = "saradc", "apb_pclk"; - resets = <&cru SRST_P_SARADC>; - reset-names = "saradc-apb"; - #io-channel-cells = <1>; - status = "disabled"; - }; - - pwm4: pwm@fe6e0000 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe6e0000 0x0 0x10>; - clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm4_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm5: pwm@fe6e0010 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe6e0010 0x0 0x10>; - clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm5_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm6: pwm@fe6e0020 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe6e0020 0x0 0x10>; - clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm6_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm7: pwm@fe6e0030 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe6e0030 0x0 0x10>; - clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm7_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm8: pwm@fe6f0000 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe6f0000 0x0 0x10>; - clocks = <&cru CLK_PWM2>, <&cru PCLK_PWM2>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm8m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm9: pwm@fe6f0010 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe6f0010 0x0 0x10>; - clocks = <&cru CLK_PWM2>, <&cru PCLK_PWM2>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm9m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm10: pwm@fe6f0020 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe6f0020 0x0 0x10>; - clocks = <&cru CLK_PWM2>, <&cru PCLK_PWM2>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm10m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm11: pwm@fe6f0030 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe6f0030 0x0 0x10>; - clocks = <&cru CLK_PWM2>, <&cru PCLK_PWM2>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm11m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm12: pwm@fe700000 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe700000 0x0 0x10>; - clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm12m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm13: pwm@fe700010 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe700010 0x0 0x10>; - clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm13m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm14: pwm@fe700020 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe700020 0x0 0x10>; - clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm14m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - pwm15: pwm@fe700030 { - compatible = "rockchip,rk3568-pwm", "rockchip,rk3328-pwm"; - reg = <0x0 0xfe700030 0x0 0x10>; - clocks = <&cru CLK_PWM3>, <&cru PCLK_PWM3>; - clock-names = "pwm", "pclk"; - pinctrl-0 = <&pwm15m0_pins>; - pinctrl-names = "default"; - #pwm-cells = <3>; - status = "disabled"; - }; - - combphy1: phy@fe830000 { - compatible = "rockchip,rk3568-naneng-combphy"; - reg = <0x0 0xfe830000 0x0 0x100>; - clocks = <&pmucru CLK_PCIEPHY1_REF>, - <&cru PCLK_PIPEPHY1>, - <&cru PCLK_PIPE>; - clock-names = "ref", "apb", "pipe"; - assigned-clocks = <&pmucru CLK_PCIEPHY1_REF>; - assigned-clock-rates = <100000000>; - resets = <&cru SRST_PIPEPHY1>; - rockchip,pipe-grf = <&pipegrf>; - rockchip,pipe-phy-grf = <&pipe_phy_grf1>; - #phy-cells = <1>; - status = "disabled"; - }; - - combphy2: phy@fe840000 { - compatible = "rockchip,rk3568-naneng-combphy"; - reg = <0x0 0xfe840000 0x0 0x100>; - clocks = <&pmucru CLK_PCIEPHY2_REF>, - <&cru PCLK_PIPEPHY2>, - <&cru PCLK_PIPE>; - clock-names = "ref", "apb", "pipe"; - assigned-clocks = <&pmucru CLK_PCIEPHY2_REF>; - assigned-clock-rates = <100000000>; - resets = <&cru SRST_PIPEPHY2>; - rockchip,pipe-grf = <&pipegrf>; - rockchip,pipe-phy-grf = <&pipe_phy_grf2>; - #phy-cells = <1>; - status = "disabled"; - }; - - csi_dphy: phy@fe870000 { - compatible = "rockchip,rk3568-csi-dphy"; - reg = <0x0 0xfe870000 0x0 0x10000>; - clocks = <&cru PCLK_MIPICSIPHY>; - clock-names = "pclk"; - #phy-cells = <0>; - resets = <&cru SRST_P_MIPICSIPHY>; - reset-names = "apb"; - rockchip,grf = <&grf>; - status = "disabled"; - }; - - dsi_dphy0: mipi-dphy@fe850000 { - compatible = "rockchip,rk3568-dsi-dphy"; - reg = <0x0 0xfe850000 0x0 0x10000>; - clock-names = "ref", "pclk"; - clocks = <&pmucru CLK_MIPIDSIPHY0_REF>, <&cru PCLK_MIPIDSIPHY0>; - #phy-cells = <0>; - power-domains = <&power RK3568_PD_VO>; - reset-names = "apb"; - resets = <&cru SRST_P_MIPIDSIPHY0>; - status = "disabled"; - }; - - dsi_dphy1: mipi-dphy@fe860000 { - compatible = "rockchip,rk3568-dsi-dphy"; - reg = <0x0 0xfe860000 0x0 0x10000>; - clock-names = "ref", "pclk"; - clocks = <&pmucru CLK_MIPIDSIPHY1_REF>, <&cru PCLK_MIPIDSIPHY1>; - #phy-cells = <0>; - power-domains = <&power RK3568_PD_VO>; - reset-names = "apb"; - resets = <&cru SRST_P_MIPIDSIPHY1>; - status = "disabled"; - }; - - usb2phy0: usb2phy@fe8a0000 { - compatible = "rockchip,rk3568-usb2phy"; - reg = <0x0 0xfe8a0000 0x0 0x10000>; - clocks = <&pmucru CLK_USBPHY0_REF>; - clock-names = "phyclk"; - clock-output-names = "clk_usbphy0_480m"; - interrupts = ; - rockchip,usbgrf = <&usb2phy0_grf>; - #clock-cells = <0>; - status = "disabled"; - - usb2phy0_host: host-port { - #phy-cells = <0>; - status = "disabled"; - }; - - usb2phy0_otg: otg-port { - #phy-cells = <0>; - status = "disabled"; - }; - }; - - usb2phy1: usb2phy@fe8b0000 { - compatible = "rockchip,rk3568-usb2phy"; - reg = <0x0 0xfe8b0000 0x0 0x10000>; - clocks = <&pmucru CLK_USBPHY1_REF>; - clock-names = "phyclk"; - clock-output-names = "clk_usbphy1_480m"; - interrupts = ; - rockchip,usbgrf = <&usb2phy1_grf>; - #clock-cells = <0>; - status = "disabled"; - - usb2phy1_host: host-port { - #phy-cells = <0>; - status = "disabled"; - }; - - usb2phy1_otg: otg-port { - #phy-cells = <0>; - status = "disabled"; - }; - }; - - pinctrl: pinctrl { - compatible = "rockchip,rk3568-pinctrl"; - rockchip,grf = <&grf>; - rockchip,pmu = <&pmugrf>; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - gpio0: gpio@fdd60000 { - compatible = "rockchip,gpio-bank"; - reg = <0x0 0xfdd60000 0x0 0x100>; - interrupts = ; - clocks = <&pmucru PCLK_GPIO0>, <&pmucru DBCLK_GPIO0>; - gpio-controller; - gpio-ranges = <&pinctrl 0 0 32>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio1: gpio@fe740000 { - compatible = "rockchip,gpio-bank"; - reg = <0x0 0xfe740000 0x0 0x100>; - interrupts = ; - clocks = <&cru PCLK_GPIO1>, <&cru DBCLK_GPIO1>; - gpio-controller; - gpio-ranges = <&pinctrl 0 32 32>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio2: gpio@fe750000 { - compatible = "rockchip,gpio-bank"; - reg = <0x0 0xfe750000 0x0 0x100>; - interrupts = ; - clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>; - gpio-controller; - gpio-ranges = <&pinctrl 0 64 32>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio3: gpio@fe760000 { - compatible = "rockchip,gpio-bank"; - reg = <0x0 0xfe760000 0x0 0x100>; - interrupts = ; - clocks = <&cru PCLK_GPIO3>, <&cru DBCLK_GPIO3>; - gpio-controller; - gpio-ranges = <&pinctrl 0 96 32>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - gpio4: gpio@fe770000 { - compatible = "rockchip,gpio-bank"; - reg = <0x0 0xfe770000 0x0 0x100>; - interrupts = ; - clocks = <&cru PCLK_GPIO4>, <&cru DBCLK_GPIO4>; - gpio-controller; - gpio-ranges = <&pinctrl 0 128 32>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - }; -}; - -#include "rk3568-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts new file mode 100644 index 00000000000000..7c7331936a7fd5 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3576-armsom-sige5.dts @@ -0,0 +1,658 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include +#include +#include +#include +#include +#include "rk3576.dtsi" + +/ { + model = "ArmSoM Sige5"; + compatible = "armsom,sige5", "rockchip,rk3576"; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + }; + + chosen { + stdout-path = "serial0:1500000n8"; + }; + + leds: leds { + compatible = "gpio-leds"; + + green_led: green-led { + color = ; + function = LED_FUNCTION_HEARTBEAT; + gpios = <&gpio4 RK_PB2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + red_led: red-led { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + }; + + vcc_12v0_dcin: regulator-vcc-12v0-dcin { + compatible = "regulator-fixed"; + regulator-name = "vcc_12v0_dcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc_5v0_sys>; + }; + + vcc_1v2_ufs_vccq_s0: regulator-vcc-1v2-ufs-vccq-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v2_ufs_vccq_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + vin-supply = <&vcc_5v0_sys>; + }; + + vcc_1v8_s0: regulator-vcc-1v8-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v8_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_1v8_s3>; + }; + + vcc_1v8_ufs_vccq2_s0: regulator-vcc-1v8-ufs-vccq2-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v8_ufs_vccq2_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc_1v8_s3>; + }; + + vcc_2v0_pldo_s3: regulator-vcc-2v0-pldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_2v0_pldo_s3"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + vin-supply = <&vcc_5v0_sys>; + }; + + vcc_3v3_pcie: regulator-vcc-3v3-pcie { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_pcie"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + enable-active-high; + gpio = <&gpio3 RK_PD6 GPIO_ACTIVE_HIGH>; + startup-delay-us = <5000>; + vin-supply = <&vcc_5v0_sys>; + }; + + vcc_3v3_rtc_s5: regulator-vcc-3v3-rtc-s5 { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_rtc_s5"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_5v0_sys>; + }; + + vcc_3v3_s0: regulator-vcc-3v3-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc_5v0_sys: regulator-vcc-5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc_5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_12v0_dcin>; + }; + + vcc_5v0_device: regulator-vcc-5v0-device { + compatible = "regulator-fixed"; + regulator-name = "vcc_5v0_device"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_12v0_dcin>; + }; + + vcc_3v3_ufs_s0: regulator-vcc-ufs-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_ufs_s0"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_5v0_sys>; + }; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&gmac0 { + phy-mode = "rgmii-id"; + clock_in_out = "output"; + + snps,reset-gpio = <&gpio2 RK_PB5 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + snps,reset-delays-us = <0 20000 100000>; + + pinctrl-names = "default"; + pinctrl-0 = <ð0m0_miim + ð0m0_tx_bus2 + ð0m0_rx_bus2 + ð0m0_rgmii_clk + ð0m0_rgmii_bus + ðm0_clk0_25m_out>; + + phy-handle = <&rgmii_phy0>; + status = "okay"; +}; + +&gmac1 { + phy-mode = "rgmii-id"; + clock_in_out = "output"; + + snps,reset-gpio = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + snps,reset-delays-us = <0 20000 100000>; + + pinctrl-names = "default"; + pinctrl-0 = <ð1m0_miim + ð1m0_tx_bus2 + ð1m0_rx_bus2 + ð1m0_rgmii_clk + ð1m0_rgmii_bus + ðm0_clk1_25m_out>; + + phy-handle = <&rgmii_phy1>; + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + pmic@23 { + compatible = "rockchip,rk806"; + reg = <0x23>; + + interrupt-parent = <&gpio0>; + interrupts = <6 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + + system-power-controller; + + vcc1-supply = <&vcc_5v0_sys>; + vcc2-supply = <&vcc_5v0_sys>; + vcc3-supply = <&vcc_5v0_sys>; + vcc4-supply = <&vcc_5v0_sys>; + vcc5-supply = <&vcc_5v0_sys>; + vcc6-supply = <&vcc_5v0_sys>; + vcc7-supply = <&vcc_5v0_sys>; + vcc8-supply = <&vcc_5v0_sys>; + vcc9-supply = <&vcc_5v0_sys>; + vcc10-supply = <&vcc_5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc_5v0_sys>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcc_5v0_sys>; + + gpio-controller; + #gpio-cells = <2>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + rk806_dvs1_slp: dvs1-slp-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun1"; + }; + + rk806_dvs1_pwrdn: dvs1-pwrdn-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun2"; + }; + + rk806_dvs1_rst: dvs1-rst-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun3"; + }; + + rk806_dvs2_slp: dvs2-slp-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun1"; + }; + + rk806_dvs2_pwrdn: dvs2-pwrdn-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun2"; + }; + + rk806_dvs2_rst: dvs2-rst-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun3"; + }; + + rk806_dvs2_dvs: dvs2-dvs-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun4"; + }; + + rk806_dvs2_gpio: dvs2-gpio-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun5"; + }; + + rk806_dvs3_slp: dvs3-slp-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun1"; + }; + + rk806_dvs3_pwrdn: dvs3-pwrdn-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun2"; + }; + + rk806_dvs3_rst: dvs3-rst-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun3"; + }; + + rk806_dvs3_dvs: dvs3-dvs-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun4"; + }; + + rk806_dvs3_gpio: dvs3-gpio-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun5"; + }; + + regulators { + vdd_cpu_big_s0: dcdc-reg1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_cpu_big_s0"; + regulator-enable-ramp-delay = <400>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_npu_s0: dcdc-reg2 { + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_npu_s0"; + regulator-enable-ramp-delay = <400>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: dcdc-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_cpu_lit_s0"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vcc_3v3_s3: dcdc-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_3v3_s3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vdd_gpu_s0: dcdc-reg5 { + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_gpu_s0"; + regulator-enable-ramp-delay = <400>; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vddq_ddr_s0: dcdc-reg6 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vddq_ddr_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_logic_s0: dcdc-reg7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <800000>; + regulator-name = "vdd_logic_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8_s3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg9 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vdd2_ddr_s3"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg10 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vdd_ddr_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca_1v8_s0: pldo-reg1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca_1v8_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca1v8_pldo2_s0: pldo-reg2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca1v8_pldo2_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda_1v2_s0: pldo-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-name = "vdda_1v2_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca_3v3_s0: pldo-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcca_3v3_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca1v8_pldo6_s3: pldo-reg6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca1v8_pldo6_s3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "vdd_0v75_s3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_ddr_pll_s0: nldo-reg2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-name = "vdda_ddr_pll_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda0v75_hdmi_s0: nldo-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <837500>; + regulator-max-microvolt = <837500>; + regulator-name = "vdda0v75_hdmi_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda_0v85_s0: nldo-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-name = "vdda_0v85_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda_0v75_s0: nldo-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "vdda_0v75_s0"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&i2c2 { + status = "okay"; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + clock-output-names = "hym8563"; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&hym8563_int>; + wakeup-source; + #clock-cells = <0>; + }; +}; + +&mdio0 { + rgmii_phy0: phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + clocks = <&cru REFCLKO25M_GMAC0_OUT>; + }; +}; + +&mdio1 { + rgmii_phy1: phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + clocks = <&cru REFCLKO25M_GMAC1_OUT>; + }; +}; + +&pinctrl { + headphone { + hp_det: hp-det { + rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + hym8563 { + hym8563_int: hym8563-int { + rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + leds { + led_rgb_r: led-red-en { + rockchip,pins = <4 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + led_rgb_g: led-green-en { + rockchip,pins = <4 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&sdhci { + bus-width = <8>; + full-pwr-cycle-in-suspend; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + no-sdio; + no-sd; + non-removable; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + max-frequency = <200000000>; + no-sdio; + no-mmc; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&uart0 { + pinctrl-0 = <&uart0m0_xfer>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-pinctrl.dtsi new file mode 100644 index 00000000000000..0b0851a7e4ea9e --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3576-pinctrl.dtsi @@ -0,0 +1,5775 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +#include +#include "rockchip-pinconf.dtsi" + +/* + * This file is auto generated by pin2dts tool, please keep these code + * by adding changes at end of this file. + */ +&pinctrl { + aupll_clk { + /omit-if-no-ref/ + aupll_clkm0_pins: aupll_clkm0-pins { + rockchip,pins = + /* aupll_clk_in_m0 */ + <0 RK_PA0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + aupll_clkm1_pins: aupll_clkm1-pins { + rockchip,pins = + /* aupll_clk_in_m1 */ + <0 RK_PB0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + aupll_clkm2_pins: aupll_clkm2-pins { + rockchip,pins = + /* aupll_clk_in_m2 */ + <4 RK_PA2 3 &pcfg_pull_none>; + }; + }; + + cam_clk0 { + /omit-if-no-ref/ + cam_clk0m0_clk0: cam_clk0m0-clk0 { + rockchip,pins = + /* cam_clk0_out_m0 */ + <3 RK_PD7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + cam_clk0m1_clk0: cam_clk0m1-clk0 { + rockchip,pins = + /* cam_clk0_out_m1 */ + <2 RK_PD2 1 &pcfg_pull_none>; + }; + }; + + cam_clk1 { + /omit-if-no-ref/ + cam_clk1m0_clk1: cam_clk1m0-clk1 { + rockchip,pins = + /* cam_clk1_out_m0 */ + <4 RK_PA0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + cam_clk1m1_clk1: cam_clk1m1-clk1 { + rockchip,pins = + /* cam_clk1_out_m1 */ + <2 RK_PD6 1 &pcfg_pull_none>; + }; + }; + + cam_clk2 { + /omit-if-no-ref/ + cam_clk2m0_clk2: cam_clk2m0-clk2 { + rockchip,pins = + /* cam_clk2_out_m0 */ + <4 RK_PA1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + cam_clk2m1_clk2: cam_clk2m1-clk2 { + rockchip,pins = + /* cam_clk2_out_m1 */ + <2 RK_PD7 1 &pcfg_pull_none>; + }; + }; + + can0 { + /omit-if-no-ref/ + can0m0_pins: can0m0-pins { + rockchip,pins = + /* can0_rx_m0 */ + <2 RK_PA0 13 &pcfg_pull_none>, + /* can0_tx_m0 */ + <2 RK_PA1 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can0m1_pins: can0m1-pins { + rockchip,pins = + /* can0_rx_m1 */ + <4 RK_PC3 12 &pcfg_pull_none>, + /* can0_tx_m1 */ + <4 RK_PC2 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can0m2_pins: can0m2-pins { + rockchip,pins = + /* can0_rx_m2 */ + <4 RK_PA6 13 &pcfg_pull_none>, + /* can0_tx_m2 */ + <4 RK_PA4 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can0m3_pins: can0m3-pins { + rockchip,pins = + /* can0_rx_m3 */ + <3 RK_PC1 12 &pcfg_pull_none>, + /* can0_tx_m3 */ + <3 RK_PC4 12 &pcfg_pull_none>; + }; + }; + + can1 { + /omit-if-no-ref/ + can1m0_pins: can1m0-pins { + rockchip,pins = + /* can1_rx_m0 */ + <2 RK_PA2 13 &pcfg_pull_none>, + /* can1_tx_m0 */ + <2 RK_PA3 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can1m1_pins: can1m1-pins { + rockchip,pins = + /* can1_rx_m1 */ + <4 RK_PC7 13 &pcfg_pull_none>, + /* can1_tx_m1 */ + <4 RK_PC6 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can1m2_pins: can1m2-pins { + rockchip,pins = + /* can1_rx_m2 */ + <4 RK_PB4 13 &pcfg_pull_none>, + /* can1_tx_m2 */ + <4 RK_PB5 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + can1m3_pins: can1m3-pins { + rockchip,pins = + /* can1_rx_m3 */ + <3 RK_PA3 11 &pcfg_pull_none>, + /* can1_tx_m3 */ + <3 RK_PA2 11 &pcfg_pull_none>; + }; + }; + + clk0_32k { + /omit-if-no-ref/ + clk0_32k_pins: clk0_32k-pins { + rockchip,pins = + /* clk0_32k_out */ + <0 RK_PA2 10 &pcfg_pull_none>; + }; + }; + + clk1_32k { + /omit-if-no-ref/ + clk1_32k_pins: clk1_32k-pins { + rockchip,pins = + /* clk1_32k_out */ + <1 RK_PD5 13 &pcfg_pull_none>; + }; + }; + + clk_32k { + /omit-if-no-ref/ + clk_32k_pins: clk_32k-pins { + rockchip,pins = + /* clk_32k_in */ + <0 RK_PA2 9 &pcfg_pull_none>; + }; + }; + + cpubig { + /omit-if-no-ref/ + cpubig_pins: cpubig-pins { + rockchip,pins = + /* cpubig_avs */ + <0 RK_PD2 11 &pcfg_pull_none>; + }; + }; + + cpulit { + /omit-if-no-ref/ + cpulit_pins: cpulit-pins { + rockchip,pins = + /* cpulit_avs */ + <0 RK_PC0 11 &pcfg_pull_none>; + }; + }; + + debug0_test { + /omit-if-no-ref/ + debug0_test_pins: debug0_test-pins { + rockchip,pins = + /* debug0_test_out */ + <1 RK_PC4 7 &pcfg_pull_none>; + }; + }; + + debug1_test { + /omit-if-no-ref/ + debug1_test_pins: debug1_test-pins { + rockchip,pins = + /* debug1_test_out */ + <1 RK_PC5 7 &pcfg_pull_none>; + }; + }; + + debug2_test { + /omit-if-no-ref/ + debug2_test_pins: debug2_test-pins { + rockchip,pins = + /* debug2_test_out */ + <1 RK_PC6 7 &pcfg_pull_none>; + }; + }; + + debug3_test { + /omit-if-no-ref/ + debug3_test_pins: debug3_test-pins { + rockchip,pins = + /* debug3_test_out */ + <1 RK_PC7 7 &pcfg_pull_none>; + }; + }; + + debug4_test { + /omit-if-no-ref/ + debug4_test_pins: debug4_test-pins { + rockchip,pins = + /* debug4_test_out */ + <1 RK_PD0 7 &pcfg_pull_none>; + }; + }; + + debug5_test { + /omit-if-no-ref/ + debug5_test_pins: debug5_test-pins { + rockchip,pins = + /* debug5_test_out */ + <1 RK_PD1 7 &pcfg_pull_none>; + }; + }; + + debug6_test { + /omit-if-no-ref/ + debug6_test_pins: debug6_test-pins { + rockchip,pins = + /* debug6_test_out */ + <1 RK_PD2 7 &pcfg_pull_none>; + }; + }; + + debug7_test { + /omit-if-no-ref/ + debug7_test_pins: debug7_test-pins { + rockchip,pins = + /* debug7_test_out */ + <1 RK_PD3 7 &pcfg_pull_none>; + }; + }; + + dp { + /omit-if-no-ref/ + dpm0_pins: dpm0-pins { + rockchip,pins = + /* dp_hpdin_m0 */ + <4 RK_PC4 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dpm1_pins: dpm1-pins { + rockchip,pins = + /* dp_hpdin_m1 */ + <0 RK_PC5 9 &pcfg_pull_none>; + }; + }; + + dsm_aud { + /omit-if-no-ref/ + dsm_audm0_ln: dsm_audm0-ln { + rockchip,pins = + /* dsm_aud_ln_m0 */ + <2 RK_PA1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm0_lp: dsm_audm0-lp { + rockchip,pins = + /* dsm_aud_lp_m0 */ + <2 RK_PA0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm0_rn: dsm_audm0-rn { + rockchip,pins = + /* dsm_aud_rn_m0 */ + <2 RK_PA3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm0_rp: dsm_audm0-rp { + rockchip,pins = + /* dsm_aud_rp_m0 */ + <2 RK_PA2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm1_ln: dsm_audm1-ln { + rockchip,pins = + /* dsm_aud_ln_m1 */ + <4 RK_PC1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm1_lp: dsm_audm1-lp { + rockchip,pins = + /* dsm_aud_lp_m1 */ + <4 RK_PC0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm1_rn: dsm_audm1-rn { + rockchip,pins = + /* dsm_aud_rn_m1 */ + <4 RK_PC3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm1_rp: dsm_audm1-rp { + rockchip,pins = + /* dsm_aud_rp_m1 */ + <4 RK_PC2 1 &pcfg_pull_none>; + }; + }; + + dsmc { + /omit-if-no-ref/ + dsmc_clkn: dsmc-clkn { + rockchip,pins = + /* dsmc_clkn */ + <3 RK_PD6 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_clkp: dsmc-clkp { + rockchip,pins = + /* dsmc_clkp */ + <3 RK_PD5 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_csn0: dsmc-csn0 { + rockchip,pins = + /* dsmc_csn0 */ + <3 RK_PD3 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_csn1: dsmc-csn1 { + rockchip,pins = + /* dsmc_csn1 */ + <3 RK_PB0 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_csn2: dsmc-csn2 { + rockchip,pins = + /* dsmc_csn2 */ + <3 RK_PD1 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_csn3: dsmc-csn3 { + rockchip,pins = + /* dsmc_csn3 */ + <3 RK_PD2 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data0: dsmc-data0 { + rockchip,pins = + /* dsmc_data0 */ + <3 RK_PD4 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data1: dsmc-data1 { + rockchip,pins = + /* dsmc_data1 */ + <3 RK_PD0 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data2: dsmc-data2 { + rockchip,pins = + /* dsmc_data2 */ + <3 RK_PC7 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data3: dsmc-data3 { + rockchip,pins = + /* dsmc_data3 */ + <3 RK_PC6 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data4: dsmc-data4 { + rockchip,pins = + /* dsmc_data4 */ + <3 RK_PC5 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data5: dsmc-data5 { + rockchip,pins = + /* dsmc_data5 */ + <3 RK_PC4 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data6: dsmc-data6 { + rockchip,pins = + /* dsmc_data6 */ + <3 RK_PC1 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data7: dsmc-data7 { + rockchip,pins = + /* dsmc_data7 */ + <3 RK_PC0 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data8: dsmc-data8 { + rockchip,pins = + /* dsmc_data8 */ + <3 RK_PB5 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data9: dsmc-data9 { + rockchip,pins = + /* dsmc_data9 */ + <3 RK_PB4 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data10: dsmc-data10 { + rockchip,pins = + /* dsmc_data10 */ + <3 RK_PB3 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data11: dsmc-data11 { + rockchip,pins = + /* dsmc_data11 */ + <3 RK_PB2 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data12: dsmc-data12 { + rockchip,pins = + /* dsmc_data12 */ + <3 RK_PB1 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data13: dsmc-data13 { + rockchip,pins = + /* dsmc_data13 */ + <3 RK_PA7 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data14: dsmc-data14 { + rockchip,pins = + /* dsmc_data14 */ + <3 RK_PA6 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_data15: dsmc-data15 { + rockchip,pins = + /* dsmc_data15 */ + <3 RK_PA5 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_dqs0: dsmc-dqs0 { + rockchip,pins = + /* dsmc_dqs0 */ + <3 RK_PB7 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_dqs1: dsmc-dqs1 { + rockchip,pins = + /* dsmc_dqs1 */ + <3 RK_PB6 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_int0: dsmc-int0 { + rockchip,pins = + /* dsmc_int0 */ + <4 RK_PA0 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_int1: dsmc-int1 { + rockchip,pins = + /* dsmc_int1 */ + <3 RK_PC2 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_int2: dsmc-int2 { + rockchip,pins = + /* dsmc_int2 */ + <4 RK_PA1 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_int3: dsmc-int3 { + rockchip,pins = + /* dsmc_int3 */ + <3 RK_PC3 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_rdyn: dsmc-rdyn { + rockchip,pins = + /* dsmc_rdyn */ + <3 RK_PA4 5 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + dsmc_resetn: dsmc-resetn { + rockchip,pins = + /* dsmc_resetn */ + <3 RK_PD7 5 &pcfg_pull_none>; + }; + }; + + dsmc_testclk { + /omit-if-no-ref/ + dsmc_testclk_out: dsmc-testclk-out { + rockchip,pins = + /* dsmc_testclk_out */ + <3 RK_PC2 7 &pcfg_pull_none>; + }; + }; + + dsmc_testdata { + /omit-if-no-ref/ + dsmc_testdata_out: dsmc-testdata-out { + rockchip,pins = + /* dsmc_testdata_out */ + <3 RK_PC3 7 &pcfg_pull_none>; + }; + }; + + edp_tx { + /omit-if-no-ref/ + edp_txm0_pins: edp_txm0-pins { + rockchip,pins = + /* edp_tx_hpdin_m0 */ + <4 RK_PC1 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + edp_txm1_pins: edp_txm1-pins { + rockchip,pins = + /* edp_tx_hpdin_m1 */ + <0 RK_PB6 10 &pcfg_pull_none>; + }; + }; + + emmc { + /omit-if-no-ref/ + emmc_rstnout: emmc-rstnout { + rockchip,pins = + /* emmc_rstn */ + <1 RK_PB3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + emmc_bus8: emmc-bus8 { + rockchip,pins = + /* emmc_d0 */ + <1 RK_PA0 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d1 */ + <1 RK_PA1 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d2 */ + <1 RK_PA2 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d3 */ + <1 RK_PA3 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d4 */ + <1 RK_PA4 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d5 */ + <1 RK_PA5 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d6 */ + <1 RK_PA6 1 &pcfg_pull_up_drv_level_2>, + /* emmc_d7 */ + <1 RK_PA7 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + emmc_clk: emmc-clk { + rockchip,pins = + /* emmc_clk */ + <1 RK_PB1 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + emmc_cmd: emmc-cmd { + rockchip,pins = + /* emmc_cmd */ + <1 RK_PB0 1 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + emmc_strb: emmc-strb { + rockchip,pins = + /* emmc_strb */ + <1 RK_PB2 1 &pcfg_pull_none>; + }; + }; + + emmc_testclk { + /omit-if-no-ref/ + emmc_testclk_test: emmc_testclk-test { + rockchip,pins = + /* emmc_testclk_out */ + <1 RK_PB3 6 &pcfg_pull_none>; + }; + }; + + emmc_testdata { + /omit-if-no-ref/ + emmc_testdata_test: emmc_testdata-test { + rockchip,pins = + /* emmc_testdata_out */ + <1 RK_PB7 5 &pcfg_pull_none>; + }; + }; + + eth0 { + /omit-if-no-ref/ + eth0m0_miim: eth0m0-miim { + rockchip,pins = + /* eth0_mdc_m0 */ + <3 RK_PA6 3 &pcfg_pull_none>, + /* eth0_mdio_m0 */ + <3 RK_PA5 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m0_rx_bus2: eth0m0-rx_bus2 { + rockchip,pins = + /* eth0_rxctl_m0 */ + <3 RK_PA7 3 &pcfg_pull_none>, + /* eth0_rxd0_m0 */ + <3 RK_PB2 3 &pcfg_pull_none>, + /* eth0_rxd1_m0 */ + <3 RK_PB1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m0_tx_bus2: eth0m0-tx_bus2 { + rockchip,pins = + /* eth0_txctl_m0 */ + <3 RK_PB3 3 &pcfg_pull_none>, + /* eth0_txd0_m0 */ + <3 RK_PB5 3 &pcfg_pull_none>, + /* eth0_txd1_m0 */ + <3 RK_PB4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m0_rgmii_clk: eth0m0-rgmii_clk { + rockchip,pins = + /* eth0_rxclk_m0 */ + <3 RK_PD1 3 &pcfg_pull_none>, + /* eth0_txclk_m0 */ + <3 RK_PB6 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m0_rgmii_bus: eth0m0-rgmii_bus { + rockchip,pins = + /* eth0_rxd2_m0 */ + <3 RK_PD3 3 &pcfg_pull_none>, + /* eth0_rxd3_m0 */ + <3 RK_PD2 3 &pcfg_pull_none>, + /* eth0_txd2_m0 */ + <3 RK_PC3 3 &pcfg_pull_none>, + /* eth0_txd3_m0 */ + <3 RK_PC2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m0_mclk: eth0m0-mclk { + rockchip,pins = + /* eth0m0_mclk */ + <3 RK_PB0 3 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + eth0m0_ppsclk: eth0m0-ppsclk { + rockchip,pins = + /* eth0m0_ppsclk */ + <3 RK_PC0 3 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + eth0m0_ppstrig: eth0m0-ppstrig { + rockchip,pins = + /* eth0m0_ppstrig */ + <3 RK_PB7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m1_miim: eth0m1-miim { + rockchip,pins = + /* eth0_mdc_m1 */ + <3 RK_PA1 3 &pcfg_pull_none>, + /* eth0_mdio_m1 */ + <3 RK_PA0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m1_rx_bus2: eth0m1-rx_bus2 { + rockchip,pins = + /* eth0_rxctl_m1 */ + <3 RK_PA2 3 &pcfg_pull_none>, + /* eth0_rxd0_m1 */ + <2 RK_PA6 3 &pcfg_pull_none>, + /* eth0_rxd1_m1 */ + <3 RK_PA3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m1_tx_bus2: eth0m1-tx_bus2 { + rockchip,pins = + /* eth0_txctl_m1 */ + <2 RK_PA7 3 &pcfg_pull_none>, + /* eth0_txd0_m1 */ + <2 RK_PB1 3 &pcfg_pull_none>, + /* eth0_txd1_m1 */ + <2 RK_PB0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m1_rgmii_clk: eth0m1-rgmii_clk { + rockchip,pins = + /* eth0_rxclk_m1 */ + <2 RK_PB5 3 &pcfg_pull_none>, + /* eth0_txclk_m1 */ + <2 RK_PB3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m1_rgmii_bus: eth0m1-rgmii_bus { + rockchip,pins = + /* eth0_rxd2_m1 */ + <2 RK_PB7 3 &pcfg_pull_none>, + /* eth0_rxd3_m1 */ + <2 RK_PB6 3 &pcfg_pull_none>, + /* eth0_txd2_m1 */ + <2 RK_PB4 3 &pcfg_pull_none>, + /* eth0_txd3_m1 */ + <2 RK_PB2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m1_mclk: eth0m1-mclk { + rockchip,pins = + /* eth0m1_mclk */ + <2 RK_PD6 3 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + eth0m1_ppsclk: eth0m1-ppsclk { + rockchip,pins = + /* eth0m1_ppsclk */ + <2 RK_PC1 3 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + eth0m1_ppstrig: eth0m1-ppstrig { + rockchip,pins = + /* eth0m1_ppstrig */ + <2 RK_PC2 3 &pcfg_pull_none>; + }; + }; + + eth1 { + /omit-if-no-ref/ + eth1m0_miim: eth1m0-miim { + rockchip,pins = + /* eth1_mdc_m0 */ + <2 RK_PD4 2 &pcfg_pull_none>, + /* eth1_mdio_m0 */ + <2 RK_PD5 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m0_rx_bus2: eth1m0-rx_bus2 { + rockchip,pins = + /* eth1_rxctl_m0 */ + <2 RK_PD3 2 &pcfg_pull_none>, + /* eth1_rxd0_m0 */ + <2 RK_PD1 2 &pcfg_pull_none>, + /* eth1_rxd1_m0 */ + <2 RK_PD2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m0_tx_bus2: eth1m0-tx_bus2 { + rockchip,pins = + /* eth1_txctl_m0 */ + <2 RK_PD0 2 &pcfg_pull_none>, + /* eth1_txd0_m0 */ + <2 RK_PC6 2 &pcfg_pull_none>, + /* eth1_txd1_m0 */ + <2 RK_PC7 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m0_rgmii_clk: eth1m0-rgmii_clk { + rockchip,pins = + /* eth1_rxclk_m0 */ + <2 RK_PC2 2 &pcfg_pull_none>, + /* eth1_txclk_m0 */ + <2 RK_PC5 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m0_rgmii_bus: eth1m0-rgmii_bus { + rockchip,pins = + /* eth1_rxd2_m0 */ + <2 RK_PC0 2 &pcfg_pull_none>, + /* eth1_rxd3_m0 */ + <2 RK_PC1 2 &pcfg_pull_none>, + /* eth1_txd2_m0 */ + <2 RK_PC3 2 &pcfg_pull_none>, + /* eth1_txd3_m0 */ + <2 RK_PC4 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m0_mclk: eth1m0-mclk { + rockchip,pins = + /* eth1m0_mclk */ + <2 RK_PD7 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + eth1m0_ppsclk: eth1m0-ppsclk { + rockchip,pins = + /* eth1m0_ppsclk */ + <3 RK_PA2 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + eth1m0_ppstrig: eth1m0-ppstrig { + rockchip,pins = + /* eth1m0_ppstrig */ + <3 RK_PA1 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m1_miim: eth1m1-miim { + rockchip,pins = + /* eth1_mdc_m1 */ + <1 RK_PD2 1 &pcfg_pull_none>, + /* eth1_mdio_m1 */ + <1 RK_PD3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m1_rx_bus2: eth1m1-rx_bus2 { + rockchip,pins = + /* eth1_rxctl_m1 */ + <1 RK_PD1 1 &pcfg_pull_none>, + /* eth1_rxd0_m1 */ + <1 RK_PC7 1 &pcfg_pull_none>, + /* eth1_rxd1_m1 */ + <1 RK_PD0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m1_tx_bus2: eth1m1-tx_bus2 { + rockchip,pins = + /* eth1_txctl_m1 */ + <1 RK_PC6 1 &pcfg_pull_none>, + /* eth1_txd0_m1 */ + <1 RK_PC4 1 &pcfg_pull_none>, + /* eth1_txd1_m1 */ + <1 RK_PC5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m1_rgmii_clk: eth1m1-rgmii_clk { + rockchip,pins = + /* eth1_rxclk_m1 */ + <1 RK_PB6 1 &pcfg_pull_none>, + /* eth1_txclk_m1 */ + <1 RK_PC1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m1_rgmii_bus: eth1m1-rgmii_bus { + rockchip,pins = + /* eth1_rxd2_m1 */ + <1 RK_PB4 1 &pcfg_pull_none>, + /* eth1_rxd3_m1 */ + <1 RK_PB5 1 &pcfg_pull_none>, + /* eth1_txd2_m1 */ + <1 RK_PB7 1 &pcfg_pull_none>, + /* eth1_txd3_m1 */ + <1 RK_PC0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m1_mclk: eth1m1-mclk { + rockchip,pins = + /* eth1m1_mclk */ + <1 RK_PD4 1 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + eth1m1_ppsclk: eth1m1-ppsclk { + rockchip,pins = + /* eth1m1_ppsclk */ + <1 RK_PC2 1 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + eth1m1_ppstrig: eth1m1-ppstrig { + rockchip,pins = + /* eth1m1_ppstrig */ + <1 RK_PC3 1 &pcfg_pull_none>; + }; + }; + + eth0_ptp { + /omit-if-no-ref/ + eth0m0_ptp_refclk: eth0m0-ptp-refclk { + rockchip,pins = + /* eth0m0_ptp_refclk */ + <3 RK_PC1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0m1_ptp_refclk: eth0m1-ptp-refclk { + rockchip,pins = + /* eth0m1_ptp_refclk */ + <2 RK_PC0 3 &pcfg_pull_none>; + }; + }; + + eth0_testrxclk { + /omit-if-no-ref/ + eth0_testrxclkm0_test: eth0_testrxclkm0-test { + rockchip,pins = + /* eth0_testrxclk_out_m0 */ + <3 RK_PC7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0_testrxclkm1_test: eth0_testrxclkm1-test { + rockchip,pins = + /* eth0_testrxclk_out_m1 */ + <2 RK_PC5 6 &pcfg_pull_none>; + }; + }; + + eth0_testrxd { + /omit-if-no-ref/ + eth0_testrxdm0_test: eth0_testrxdm0-test { + rockchip,pins = + /* eth0_testrxd_out_m0 */ + <3 RK_PD0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth0_testrxdm1_test: eth0_testrxdm1-test { + rockchip,pins = + /* eth0_testrxd_out_m1 */ + <2 RK_PC4 6 &pcfg_pull_none>; + }; + }; + + eth1_ptp { + /omit-if-no-ref/ + eth1m0_ptp_refclk: eth1m0-ptp-refclk { + rockchip,pins = + /* eth1m0_ptp_refclk */ + <3 RK_PA3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1m1_ptp_refclk: eth1m1-ptp-refclk { + rockchip,pins = + /* eth1m1_ptp_refclk */ + <2 RK_PB6 2 &pcfg_pull_none>; + }; + }; + + eth1_testrxclk { + /omit-if-no-ref/ + eth1_testrxclkm0_test: eth1_testrxclkm0-test { + rockchip,pins = + /* eth1_testrxclk_out_m0 */ + <3 RK_PA1 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1_testrxclkm1_test: eth1_testrxclkm1-test { + rockchip,pins = + /* eth1_testrxclk_out_m1 */ + <1 RK_PC3 6 &pcfg_pull_none>; + }; + }; + + eth1_testrxd { + /omit-if-no-ref/ + eth1_testrxdm0_test: eth1_testrxdm0-test { + rockchip,pins = + /* eth1_testrxd_out_m0 */ + <3 RK_PA0 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + eth1_testrxdm1_test: eth1_testrxdm1-test { + rockchip,pins = + /* eth1_testrxd_out_m1 */ + <1 RK_PC2 6 &pcfg_pull_none>; + }; + }; + + eth_clk0_25m { + /omit-if-no-ref/ + ethm0_clk0_25m_out: ethm0-clk0-25m-out { + rockchip,pins = + /* ethm0_clk0_25m_out */ + <3 RK_PA4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + ethm1_clk0_25m_out: ethm1-clk0-25m-out { + rockchip,pins = + /* ethm1_clk0_25m_out */ + <2 RK_PD7 3 &pcfg_pull_none>; + }; + }; + + eth_clk1_25m { + /omit-if-no-ref/ + ethm0_clk1_25m_out: ethm0-clk1-25m-out { + rockchip,pins = + /* ethm0_clk1_25m_out */ + <2 RK_PD6 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + ethm1_clk1_25m_out: ethm1-clk1-25m-out { + rockchip,pins = + /* ethm1_clk1_25m_out */ + <1 RK_PD5 1 &pcfg_pull_none>; + }; + }; + + flexbus0 { + /omit-if-no-ref/ + flexbus0m0_csn: flexbus0m0-csn { + rockchip,pins = + /* flexbus0_csn_m0 */ + <3 RK_PA4 8 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m0_d13: flexbus0m0-d13 { + rockchip,pins = + /* flexbus0_d13_m0 */ + <4 RK_PA0 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m0_d14: flexbus0m0-d14 { + rockchip,pins = + /* flexbus0_d14_m0 */ + <4 RK_PA1 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m0_d15: flexbus0m0-d15 { + rockchip,pins = + /* flexbus0_d15_m0 */ + <3 RK_PD7 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m1_csn: flexbus0m1-csn { + rockchip,pins = + /* flexbus0_csn_m1 */ + <4 RK_PA1 8 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m1_d13: flexbus0m1-d13 { + rockchip,pins = + /* flexbus0_d13_m1 */ + <4 RK_PA4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m1_d14: flexbus0m1-d14 { + rockchip,pins = + /* flexbus0_d14_m1 */ + <4 RK_PA6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m1_d15: flexbus0m1-d15 { + rockchip,pins = + /* flexbus0_d15_m1 */ + <4 RK_PB5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m2_csn: flexbus0m2-csn { + rockchip,pins = + /* flexbus0_csn_m2 */ + <3 RK_PC3 8 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m3_csn: flexbus0m3-csn { + rockchip,pins = + /* flexbus0_csn_m3 */ + <3 RK_PD2 8 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0m4_csn: flexbus0m4-csn { + rockchip,pins = + /* flexbus0_csn_m4 */ + <4 RK_PB4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_clk: flexbus0-clk { + rockchip,pins = + /* flexbus0_clk */ + <3 RK_PB6 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d10: flexbus0-d10 { + rockchip,pins = + /* flexbus0_d10 */ + <3 RK_PC3 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d11: flexbus0-d11 { + rockchip,pins = + /* flexbus0_d11 */ + <3 RK_PD1 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d12: flexbus0-d12 { + rockchip,pins = + /* flexbus0_d12 */ + <3 RK_PD2 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d0: flexbus0-d0 { + rockchip,pins = + /* flexbus0_d0 */ + <3 RK_PB5 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d1: flexbus0-d1 { + rockchip,pins = + /* flexbus0_d1 */ + <3 RK_PB4 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d2: flexbus0-d2 { + rockchip,pins = + /* flexbus0_d2 */ + <3 RK_PB3 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d3: flexbus0-d3 { + rockchip,pins = + /* flexbus0_d3 */ + <3 RK_PB2 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d4: flexbus0-d4 { + rockchip,pins = + /* flexbus0_d4 */ + <3 RK_PB1 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d5: flexbus0-d5 { + rockchip,pins = + /* flexbus0_d5 */ + <3 RK_PA7 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d6: flexbus0-d6 { + rockchip,pins = + /* flexbus0_d6 */ + <3 RK_PA6 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d7: flexbus0-d7 { + rockchip,pins = + /* flexbus0_d7 */ + <3 RK_PA5 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d8: flexbus0-d8 { + rockchip,pins = + /* flexbus0_d8 */ + <3 RK_PB0 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus0_d9: flexbus0-d9 { + rockchip,pins = + /* flexbus0_d9 */ + <3 RK_PC2 6 &pcfg_pull_none>; + }; + }; + + flexbus1 { + /omit-if-no-ref/ + flexbus1m0_csn: flexbus1m0-csn { + rockchip,pins = + /* flexbus1_csn_m0 */ + <3 RK_PB7 8 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m0_d12: flexbus1m0-d12 { + rockchip,pins = + /* flexbus1_d12_m0 */ + <3 RK_PD7 7 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m0_d13: flexbus1m0-d13 { + rockchip,pins = + /* flexbus1_d13_m0 */ + <4 RK_PA1 7 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m0_d14: flexbus1m0-d14 { + rockchip,pins = + /* flexbus1_d14_m0 */ + <4 RK_PA0 7 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m0_d15: flexbus1m0-d15 { + rockchip,pins = + /* flexbus1_d15_m0 */ + <3 RK_PD2 7 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m1_csn: flexbus1m1-csn { + rockchip,pins = + /* flexbus1_csn_m1 */ + <3 RK_PD7 8 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m1_d12: flexbus1m1-d12 { + rockchip,pins = + /* flexbus1_d12_m1 */ + <4 RK_PA5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m1_d13: flexbus1m1-d13 { + rockchip,pins = + /* flexbus1_d13_m1 */ + <4 RK_PB0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m1_d14: flexbus1m1-d14 { + rockchip,pins = + /* flexbus1_d14_m1 */ + <4 RK_PB1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m1_d15: flexbus1m1-d15 { + rockchip,pins = + /* flexbus1_d15_m1 */ + <4 RK_PB2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m2_csn: flexbus1m2-csn { + rockchip,pins = + /* flexbus1_csn_m2 */ + <3 RK_PD1 8 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m3_csn: flexbus1m3-csn { + rockchip,pins = + /* flexbus1_csn_m3 */ + <4 RK_PA0 8 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1m4_csn: flexbus1m4-csn { + rockchip,pins = + /* flexbus1_csn_m4 */ + <4 RK_PA3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_clk: flexbus1-clk { + rockchip,pins = + /* flexbus1_clk */ + <3 RK_PD6 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d10: flexbus1-d10 { + rockchip,pins = + /* flexbus1_d10 */ + <3 RK_PB7 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d11: flexbus1-d11 { + rockchip,pins = + /* flexbus1_d11 */ + <3 RK_PA4 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d0: flexbus1-d0 { + rockchip,pins = + /* flexbus1_d0 */ + <3 RK_PD5 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d1: flexbus1-d1 { + rockchip,pins = + /* flexbus1_d1 */ + <3 RK_PD4 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d2: flexbus1-d2 { + rockchip,pins = + /* flexbus1_d2 */ + <3 RK_PD3 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d3: flexbus1-d3 { + rockchip,pins = + /* flexbus1_d3 */ + <3 RK_PD0 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d4: flexbus1-d4 { + rockchip,pins = + /* flexbus1_d4 */ + <3 RK_PC7 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d5: flexbus1-d5 { + rockchip,pins = + /* flexbus1_d5 */ + <3 RK_PC6 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d6: flexbus1-d6 { + rockchip,pins = + /* flexbus1_d6 */ + <3 RK_PC5 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d7: flexbus1-d7 { + rockchip,pins = + /* flexbus1_d7 */ + <3 RK_PC4 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d8: flexbus1-d8 { + rockchip,pins = + /* flexbus1_d8 */ + <3 RK_PC1 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + flexbus1_d9: flexbus1-d9 { + rockchip,pins = + /* flexbus1_d9 */ + <3 RK_PC0 6 &pcfg_pull_none>; + }; + }; + + flexbus0_testclk { + /omit-if-no-ref/ + flexbus0_testclk_testclk: flexbus0_testclk-testclk { + rockchip,pins = + /* flexbus0_testclk_out */ + <2 RK_PA3 6 &pcfg_pull_none>; + }; + }; + + flexbus0_testdata { + /omit-if-no-ref/ + flexbus0_testdata_testdata: flexbus0_testdata-testdata { + rockchip,pins = + /* flexbus0_testdata_out */ + <2 RK_PA2 6 &pcfg_pull_none>; + }; + }; + + flexbus1_testclk { + /omit-if-no-ref/ + flexbus1_testclk_testclk: flexbus1_testclk-testclk { + rockchip,pins = + /* flexbus1_testclk_out */ + <2 RK_PA5 6 &pcfg_pull_none>; + }; + }; + + flexbus1_testdata { + /omit-if-no-ref/ + flexbus1_testdata_testdata: flexbus1_testdata-testdata { + rockchip,pins = + /* flexbus1_testdata_out */ + <2 RK_PA4 6 &pcfg_pull_none>; + }; + }; + + fspi0 { + /omit-if-no-ref/ + fspi0_pins: fspi0-pins { + rockchip,pins = + /* fspi0_clk */ + <1 RK_PB1 2 &pcfg_pull_none>, + /* fspi0_d0 */ + <1 RK_PA0 2 &pcfg_pull_none>, + /* fspi0_d1 */ + <1 RK_PA1 2 &pcfg_pull_none>, + /* fspi0_d2 */ + <1 RK_PA2 2 &pcfg_pull_none>, + /* fspi0_d3 */ + <1 RK_PA3 2 &pcfg_pull_none>, + /* fspi0_d4 */ + <1 RK_PA4 2 &pcfg_pull_none>, + /* fspi0_d5 */ + <1 RK_PA5 2 &pcfg_pull_none>, + /* fspi0_d6 */ + <1 RK_PA6 2 &pcfg_pull_none>, + /* fspi0_d7 */ + <1 RK_PA7 2 &pcfg_pull_none>, + /* fspi0_dqs */ + <1 RK_PB2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + fspi0_csn0: fspi0-csn0 { + rockchip,pins = + /* fspi0_csn0 */ + <1 RK_PB3 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + fspi0_csn1: fspi0-csn1 { + rockchip,pins = + /* fspi0_csn1 */ + <1 RK_PB0 2 &pcfg_pull_none>; + }; + }; + + fspi1 { + /omit-if-no-ref/ + fspi1m0_pins: fspi1m0-pins { + rockchip,pins = + /* fspi1_clk_m0 */ + <2 RK_PA5 2 &pcfg_pull_none>, + /* fspi1_d0_m0 */ + <2 RK_PA0 2 &pcfg_pull_none>, + /* fspi1_d1_m0 */ + <2 RK_PA1 2 &pcfg_pull_none>, + /* fspi1_d2_m0 */ + <2 RK_PA2 2 &pcfg_pull_none>, + /* fspi1_d3_m0 */ + <2 RK_PA3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + fspi1m0_csn0: fspi1m0-csn0 { + rockchip,pins = + /* fspi1m0_csn0 */ + <2 RK_PA4 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + fspi1m1_pins: fspi1m1-pins { + rockchip,pins = + /* fspi1_clk_m1 */ + <1 RK_PD5 3 &pcfg_pull_none>, + /* fspi1_d0_m1 */ + <1 RK_PC4 3 &pcfg_pull_none>, + /* fspi1_d1_m1 */ + <1 RK_PC5 3 &pcfg_pull_none>, + /* fspi1_d2_m1 */ + <1 RK_PC6 3 &pcfg_pull_none>, + /* fspi1_d3_m1 */ + <1 RK_PC7 3 &pcfg_pull_none>, + /* fspi1_d4_m1 */ + <1 RK_PD0 3 &pcfg_pull_none>, + /* fspi1_d5_m1 */ + <1 RK_PD1 3 &pcfg_pull_none>, + /* fspi1_d6_m1 */ + <1 RK_PD2 3 &pcfg_pull_none>, + /* fspi1_d7_m1 */ + <1 RK_PD3 3 &pcfg_pull_none>, + /* fspi1_dqs_m1 */ + <1 RK_PD4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + fspi1m1_csn0: fspi1m1-csn0 { + rockchip,pins = + /* fspi1m1_csn0 */ + <1 RK_PC3 3 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + fspi1m1_csn1: fspi1m1-csn1 { + rockchip,pins = + /* fspi1m1_csn1 */ + <1 RK_PC2 3 &pcfg_pull_none>; + }; + }; + + fspi0_testclk { + /omit-if-no-ref/ + fspi0_testclk_test: fspi0_testclk-test { + rockchip,pins = + /* fspi0_testclk_out */ + <1 RK_PB0 6 &pcfg_pull_none>; + }; + }; + + fspi0_testdata { + /omit-if-no-ref/ + fspi0_testdata_test: fspi0_testdata-test { + rockchip,pins = + /* fspi0_testdata_out */ + <1 RK_PB7 6 &pcfg_pull_none>; + }; + }; + + fspi1_testclk { + /omit-if-no-ref/ + fspi1_testclkm1_test: fspi1_testclkm1-test { + rockchip,pins = + /* fspi1_testclk_out_m1 */ + <1 RK_PC1 7 &pcfg_pull_none>; + }; + }; + + fspi1_testdata { + /omit-if-no-ref/ + fspi1_testdatam1_test: fspi1_testdatam1-test { + rockchip,pins = + /* fspi1_testdata_out_m1 */ + <1 RK_PB7 7 &pcfg_pull_none>; + }; + }; + + gpu { + /omit-if-no-ref/ + gpu_pins: gpu-pins { + rockchip,pins = + /* gpu_avs */ + <0 RK_PD3 11 &pcfg_pull_none>; + }; + }; + + hdmi_tx { + /omit-if-no-ref/ + hdmi_txm0_pins: hdmi_txm0-pins { + rockchip,pins = + /* hdmi_tx_cec_m0 */ + <4 RK_PC0 9 &pcfg_pull_none>, + /* hdmi_tx_hpdin_m0 */ + <4 RK_PC1 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + hdmi_txm1_pins: hdmi_txm1-pins { + rockchip,pins = + /* hdmi_tx_cec_m1 */ + <0 RK_PC3 9 &pcfg_pull_none>, + /* hdmi_tx_hpdin_m1 */ + <0 RK_PB6 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + hdmi_tx_scl: hdmi-tx-scl { + rockchip,pins = + /* hdmi_tx_scl */ + <4 RK_PC2 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + hdmi_tx_sda: hdmi-tx-sda { + rockchip,pins = + /* hdmi_tx_sda */ + <4 RK_PC3 9 &pcfg_pull_none>; + }; + }; + + i2c0 { + /omit-if-no-ref/ + i2c0m0_xfer: i2c0m0-xfer { + rockchip,pins = + /* i2c0_scl_m0 */ + <0 RK_PB0 11 &pcfg_pull_none_smt>, + /* i2c0_sda_m0 */ + <0 RK_PB1 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c0m1_xfer: i2c0m1-xfer { + rockchip,pins = + /* i2c0_scl_m1 */ + <0 RK_PC1 9 &pcfg_pull_none_smt>, + /* i2c0_sda_m1 */ + <0 RK_PC2 9 &pcfg_pull_none_smt>; + }; + }; + + i2c1 { + /omit-if-no-ref/ + i2c1m0_xfer: i2c1m0-xfer { + rockchip,pins = + /* i2c1_scl_m0 */ + <0 RK_PB2 11 &pcfg_pull_none_smt>, + /* i2c1_sda_m0 */ + <0 RK_PB3 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c1m1_xfer: i2c1m1-xfer { + rockchip,pins = + /* i2c1_scl_m1 */ + <0 RK_PB4 9 &pcfg_pull_none_smt>, + /* i2c1_sda_m1 */ + <0 RK_PB5 9 &pcfg_pull_none_smt>; + }; + }; + + i2c2 { + /omit-if-no-ref/ + i2c2m0_xfer: i2c2m0-xfer { + rockchip,pins = + /* i2c2_scl_m0 */ + <0 RK_PB7 9 &pcfg_pull_none_smt>, + /* i2c2_sda_m0 */ + <0 RK_PC0 9 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c2m1_xfer: i2c2m1-xfer { + rockchip,pins = + /* i2c2_scl_m1 */ + <1 RK_PA0 10 &pcfg_pull_none_smt>, + /* i2c2_sda_m1 */ + <1 RK_PA1 10 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c2m2_xfer: i2c2m2-xfer { + rockchip,pins = + /* i2c2_scl_m2 */ + <4 RK_PA3 11 &pcfg_pull_none_smt>, + /* i2c2_sda_m2 */ + <4 RK_PA5 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c2m3_xfer: i2c2m3-xfer { + rockchip,pins = + /* i2c2_scl_m3 */ + <4 RK_PC2 11 &pcfg_pull_none_smt>, + /* i2c2_sda_m3 */ + <4 RK_PC3 11 &pcfg_pull_none_smt>; + }; + }; + + i2c3 { + /omit-if-no-ref/ + i2c3m0_xfer: i2c3m0-xfer { + rockchip,pins = + /* i2c3_scl_m0 */ + <4 RK_PB5 11 &pcfg_pull_none_smt>, + /* i2c3_sda_m0 */ + <4 RK_PB4 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c3m1_xfer: i2c3m1-xfer { + rockchip,pins = + /* i2c3_scl_m1 */ + <0 RK_PC6 9 &pcfg_pull_none_smt>, + /* i2c3_sda_m1 */ + <0 RK_PC7 9 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c3m2_xfer: i2c3m2-xfer { + rockchip,pins = + /* i2c3_scl_m2 */ + <3 RK_PD4 11 &pcfg_pull_none_smt>, + /* i2c3_sda_m2 */ + <3 RK_PD5 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c3m3_xfer: i2c3m3-xfer { + rockchip,pins = + /* i2c3_scl_m3 */ + <4 RK_PC4 11 &pcfg_pull_none_smt>, + /* i2c3_sda_m3 */ + <4 RK_PC5 11 &pcfg_pull_none_smt>; + }; + }; + + i2c4 { + /omit-if-no-ref/ + i2c4m0_xfer: i2c4m0-xfer { + rockchip,pins = + /* i2c4_scl_m0 */ + <0 RK_PD2 9 &pcfg_pull_none_smt>, + /* i2c4_sda_m0 */ + <0 RK_PD3 9 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c4m1_xfer: i2c4m1-xfer { + rockchip,pins = + /* i2c4_scl_m1 */ + <4 RK_PA4 11 &pcfg_pull_none_smt>, + /* i2c4_sda_m1 */ + <4 RK_PA6 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c4m2_xfer: i2c4m2-xfer { + rockchip,pins = + /* i2c4_scl_m2 */ + <2 RK_PA6 11 &pcfg_pull_none_smt>, + /* i2c4_sda_m2 */ + <2 RK_PA7 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c4m3_xfer: i2c4m3-xfer { + rockchip,pins = + /* i2c4_scl_m3 */ + <3 RK_PC0 11 &pcfg_pull_none_smt>, + /* i2c4_sda_m3 */ + <3 RK_PB7 11 &pcfg_pull_none_smt>; + }; + }; + + i2c5 { + /omit-if-no-ref/ + i2c5m0_xfer: i2c5m0-xfer { + rockchip,pins = + /* i2c5_scl_m0 */ + <2 RK_PA5 11 &pcfg_pull_none_smt>, + /* i2c5_sda_m0 */ + <2 RK_PA4 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c5m1_xfer: i2c5m1-xfer { + rockchip,pins = + /* i2c5_scl_m1 */ + <1 RK_PD4 10 &pcfg_pull_none_smt>, + /* i2c5_sda_m1 */ + <1 RK_PD5 10 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c5m2_xfer: i2c5m2-xfer { + rockchip,pins = + /* i2c5_scl_m2 */ + <2 RK_PC6 11 &pcfg_pull_none_smt>, + /* i2c5_sda_m2 */ + <2 RK_PC7 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c5m3_xfer: i2c5m3-xfer { + rockchip,pins = + /* i2c5_scl_m3 */ + <3 RK_PC4 11 &pcfg_pull_none_smt>, + /* i2c5_sda_m3 */ + <3 RK_PC1 11 &pcfg_pull_none_smt>; + }; + }; + + i2c6 { + /omit-if-no-ref/ + i2c6m0_xfer: i2c6m0-xfer { + rockchip,pins = + /* i2c6_scl_m0 */ + <0 RK_PA2 11 &pcfg_pull_none_smt>, + /* i2c6_sda_m0 */ + <0 RK_PA5 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c6m1_xfer: i2c6m1-xfer { + rockchip,pins = + /* i2c6_scl_m1 */ + <1 RK_PC2 10 &pcfg_pull_none_smt>, + /* i2c6_sda_m1 */ + <1 RK_PC3 10 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c6m2_xfer: i2c6m2-xfer { + rockchip,pins = + /* i2c6_scl_m2 */ + <2 RK_PD0 11 &pcfg_pull_none_smt>, + /* i2c6_sda_m2 */ + <2 RK_PD1 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c6m3_xfer: i2c6m3-xfer { + rockchip,pins = + /* i2c6_scl_m3 */ + <4 RK_PC6 11 &pcfg_pull_none_smt>, + /* i2c6_sda_m3 */ + <4 RK_PC7 11 &pcfg_pull_none_smt>; + }; + }; + + i2c7 { + /omit-if-no-ref/ + i2c7m0_xfer: i2c7m0-xfer { + rockchip,pins = + /* i2c7_scl_m0 */ + <1 RK_PB0 10 &pcfg_pull_none_smt>, + /* i2c7_sda_m0 */ + <1 RK_PB3 10 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c7m1_xfer: i2c7m1-xfer { + rockchip,pins = + /* i2c7_scl_m1 */ + <3 RK_PA0 11 &pcfg_pull_none_smt>, + /* i2c7_sda_m1 */ + <3 RK_PA1 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c7m2_xfer: i2c7m2-xfer { + rockchip,pins = + /* i2c7_scl_m2 */ + <4 RK_PA0 11 &pcfg_pull_none_smt>, + /* i2c7_sda_m2 */ + <4 RK_PA1 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c7m3_xfer: i2c7m3-xfer { + rockchip,pins = + /* i2c7_scl_m3 */ + <4 RK_PC0 11 &pcfg_pull_none_smt>, + /* i2c7_sda_m3 */ + <4 RK_PC1 11 &pcfg_pull_none_smt>; + }; + }; + + i2c8 { + /omit-if-no-ref/ + i2c8m0_xfer: i2c8m0-xfer { + rockchip,pins = + /* i2c8_scl_m0 */ + <2 RK_PA0 11 &pcfg_pull_none_smt>, + /* i2c8_sda_m0 */ + <2 RK_PA1 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c8m1_xfer: i2c8m1-xfer { + rockchip,pins = + /* i2c8_scl_m1 */ + <1 RK_PC6 10 &pcfg_pull_none_smt>, + /* i2c8_sda_m1 */ + <1 RK_PC7 10 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c8m2_xfer: i2c8m2-xfer { + rockchip,pins = + /* i2c8_scl_m2 */ + <2 RK_PB6 11 &pcfg_pull_none_smt>, + /* i2c8_sda_m2 */ + <2 RK_PB7 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c8m3_xfer: i2c8m3-xfer { + rockchip,pins = + /* i2c8_scl_m3 */ + <3 RK_PB3 11 &pcfg_pull_none_smt>, + /* i2c8_sda_m3 */ + <3 RK_PB2 11 &pcfg_pull_none_smt>; + }; + }; + + i2c9 { + /omit-if-no-ref/ + i2c9m0_xfer: i2c9m0-xfer { + rockchip,pins = + /* i2c9_scl_m0 */ + <1 RK_PA5 10 &pcfg_pull_none_smt>, + /* i2c9_sda_m0 */ + <1 RK_PA6 10 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c9m1_xfer: i2c9m1-xfer { + rockchip,pins = + /* i2c9_scl_m1 */ + <1 RK_PB5 10 &pcfg_pull_none_smt>, + /* i2c9_sda_m1 */ + <1 RK_PB4 10 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c9m2_xfer: i2c9m2-xfer { + rockchip,pins = + /* i2c9_scl_m2 */ + <2 RK_PD5 11 &pcfg_pull_none_smt>, + /* i2c9_sda_m2 */ + <2 RK_PD4 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i2c9m3_xfer: i2c9m3-xfer { + rockchip,pins = + /* i2c9_scl_m3 */ + <3 RK_PC2 11 &pcfg_pull_none_smt>, + /* i2c9_sda_m3 */ + <3 RK_PC3 11 &pcfg_pull_none_smt>; + }; + }; + + i3c0 { + /omit-if-no-ref/ + i3c0m0_xfer: i3c0m0-xfer { + rockchip,pins = + /* i3c0_scl_m0 */ + <0 RK_PC1 11 &pcfg_pull_none_smt>, + /* i3c0_sda_m0 */ + <0 RK_PC2 11 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i3c0m1_xfer: i3c0m1-xfer { + rockchip,pins = + /* i3c0_scl_m1 */ + <1 RK_PD2 10 &pcfg_pull_none_smt>, + /* i3c0_sda_m1 */ + <1 RK_PD3 10 &pcfg_pull_none_smt>; + }; + }; + + i3c1 { + /omit-if-no-ref/ + i3c1m0_xfer: i3c1m0-xfer { + rockchip,pins = + /* i3c1_scl_m0 */ + <2 RK_PD2 12 &pcfg_pull_none_smt>, + /* i3c1_sda_m0 */ + <2 RK_PD3 12 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i3c1m1_xfer: i3c1m1-xfer { + rockchip,pins = + /* i3c1_scl_m1 */ + <2 RK_PA2 14 &pcfg_pull_none_smt>, + /* i3c1_sda_m1 */ + <2 RK_PA3 14 &pcfg_pull_none_smt>; + }; + + /omit-if-no-ref/ + i3c1m2_xfer: i3c1m2-xfer { + rockchip,pins = + /* i3c1_scl_m2 */ + <3 RK_PD3 11 &pcfg_pull_none_smt>, + /* i3c1_sda_m2 */ + <3 RK_PD2 11 &pcfg_pull_none_smt>; + }; + }; + + i3c0_sda { + /omit-if-no-ref/ + i3c0_sdam0_pu: i3c0_sdam0-pu { + rockchip,pins = + /* i3c0_sda_pu_m0 */ + <0 RK_PC5 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i3c0_sdam1_pu: i3c0_sdam1-pu { + rockchip,pins = + /* i3c0_sda_pu_m1 */ + <1 RK_PD1 10 &pcfg_pull_none>; + }; + }; + + i3c1_sda { + /omit-if-no-ref/ + i3c1_sdam0_pu: i3c1_sdam0-pu { + rockchip,pins = + /* i3c1_sda_pu_m0 */ + <2 RK_PD6 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i3c1_sdam1_pu: i3c1_sdam1-pu { + rockchip,pins = + /* i3c1_sda_pu_m1 */ + <2 RK_PA5 14 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + i3c1_sdam2_pu: i3c1_sdam2-pu { + rockchip,pins = + /* i3c1_sda_pu_m2 */ + <3 RK_PD1 11 &pcfg_pull_none>; + }; + }; + + isp_flash { + /omit-if-no-ref/ + isp_flashm0_pins: isp_flashm0-pins { + rockchip,pins = + /* isp_flash_trigout_m0 */ + <2 RK_PD5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + isp_flashm1_pins: isp_flashm1-pins { + rockchip,pins = + /* isp_flash_trigout_m1 */ + <4 RK_PC5 1 &pcfg_pull_none>; + }; + }; + + isp_prelight { + /omit-if-no-ref/ + isp_prelightm0_pins: isp_prelightm0-pins { + rockchip,pins = + /* isp_prelight_trig_m0 */ + <2 RK_PD4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + isp_prelightm1_pins: isp_prelightm1-pins { + rockchip,pins = + /* isp_prelight_trig_m1 */ + <4 RK_PC4 1 &pcfg_pull_none>; + }; + }; + + jtag { + /omit-if-no-ref/ + jtagm0_pins: jtagm0-pins { + rockchip,pins = + /* jtag_tck_m0 */ + <2 RK_PA2 9 &pcfg_pull_none>, + /* jtag_tms_m0 */ + <2 RK_PA3 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + jtagm1_pins: jtagm1-pins { + rockchip,pins = + /* jtag_tck_m1 */ + <0 RK_PD4 10 &pcfg_pull_none>, + /* jtag_tms_m1 */ + <0 RK_PD5 10 &pcfg_pull_none>; + }; + }; + + mipi { + /omit-if-no-ref/ + mipim0_pins: mipim0-pins { + rockchip,pins = + /* mipi_te_m0 */ + <4 RK_PB2 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + mipim1_pins: mipim1-pins { + rockchip,pins = + /* mipi_te_m1 */ + <3 RK_PA2 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + mipim2_pins: mipim2-pins { + rockchip,pins = + /* mipi_te_m2 */ + <4 RK_PA0 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + mipim3_pins: mipim3-pins { + rockchip,pins = + /* mipi_te_m3 */ + <1 RK_PB3 11 &pcfg_pull_none>; + }; + }; + + npu { + /omit-if-no-ref/ + npu_pins: npu-pins { + rockchip,pins = + /* npu_avs */ + <0 RK_PB7 11 &pcfg_pull_none>; + }; + }; + + pcie0 { + /omit-if-no-ref/ + pcie0m0_pins: pcie0m0-pins { + rockchip,pins = + /* pcie21_port0_clkreq_m0 */ + <2 RK_PB2 11 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + pcie0m1_pins: pcie0m1-pins { + rockchip,pins = + /* pcie0_clkreq_m1 */ + <1 RK_PB6 12 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + pcie0m2_pins: pcie0m2-pins { + rockchip,pins = + /* pcie0_clkreq_m2 */ + <4 RK_PB5 12 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + pcie0m3_pins: pcie0m3-pins { + rockchip,pins = + /* pcie0_clkreq_m3 */ + <4 RK_PC6 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + pcie0_buttonrst: pcie21-port0-buttonrst { + rockchip,pins = + /* pcie0_buttonrst */ + <1 RK_PC4 12 &pcfg_pull_none>; + }; + }; + + pcie1 { + /omit-if-no-ref/ + pcie1m0_pins: pcie1m0-pins { + rockchip,pins = + /* pcie1_clkreq_m0 */ + <2 RK_PB3 11 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + pcie1m1_pins: pcie1m1-pins { + rockchip,pins = + /* pcie1_clkreq_m1 */ + <1 RK_PB4 12 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + pcie1m2_pins: pcie1m2-pins { + rockchip,pins = + /* pcie1_clkreq_m2 */ + <4 RK_PA5 12 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + pcie1m3_pins: pcie1m3-pins { + rockchip,pins = + /* pcie1_clkreq_m3 */ + <4 RK_PC1 10 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + pcie1_buttonrst: pcie21-port1-buttonrst { + rockchip,pins = + /* pcie1_buttonrst */ + <1 RK_PC5 12 &pcfg_pull_none>; + }; + }; + + pdm0 { + /omit-if-no-ref/ + pdm0m0_clk0: pdm0m0-clk0 { + rockchip,pins = + /* pdm0_clk0_m0 */ + <0 RK_PC4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m0_clk1: pdm0m0-clk1 { + rockchip,pins = + /* pdm0_clk1_m0 */ + <0 RK_PC3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m0_sdi0: pdm0m0-sdi0 { + rockchip,pins = + /* pdm0_sdi0_m0 */ + <0 RK_PD0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m0_sdi1: pdm0m0-sdi1 { + rockchip,pins = + /* pdm0_sdi1_m0 */ + <0 RK_PD1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m0_sdi2: pdm0m0-sdi2 { + rockchip,pins = + /* pdm0_sdi2_m0 */ + <0 RK_PD2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m0_sdi3: pdm0m0-sdi3 { + rockchip,pins = + /* pdm0_sdi3_m0 */ + <0 RK_PD3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m1_clk0: pdm0m1-clk0 { + rockchip,pins = + /* pdm0_clk0_m1 */ + <1 RK_PB1 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m1_clk1: pdm0m1-clk1 { + rockchip,pins = + /* pdm0_clk1_m1 */ + <1 RK_PA6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m1_sdi0: pdm0m1-sdi0 { + rockchip,pins = + /* pdm0_sdi0_m1 */ + <1 RK_PB2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m1_sdi1: pdm0m1-sdi1 { + rockchip,pins = + /* pdm0_sdi1_m1 */ + <1 RK_PA3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m1_sdi2: pdm0m1-sdi2 { + rockchip,pins = + /* pdm0_sdi2_m1 */ + <1 RK_PA5 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m1_sdi3: pdm0m1-sdi3 { + rockchip,pins = + /* pdm0_sdi3_m1 */ + <1 RK_PA2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m2_clk0: pdm0m2-clk0 { + rockchip,pins = + /* pdm0_clk0_m2 */ + <1 RK_PC1 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m2_clk1: pdm0m2-clk1 { + rockchip,pins = + /* pdm0_clk1_m2 */ + <1 RK_PD5 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m2_sdi0: pdm0m2-sdi0 { + rockchip,pins = + /* pdm0_sdi0_m2 */ + <1 RK_PC6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m2_sdi1: pdm0m2-sdi1 { + rockchip,pins = + /* pdm0_sdi1_m2 */ + <1 RK_PC7 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m2_sdi2: pdm0m2-sdi2 { + rockchip,pins = + /* pdm0_sdi2_m2 */ + <1 RK_PC0 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m2_sdi3: pdm0m2-sdi3 { + rockchip,pins = + /* pdm0_sdi3_m2 */ + <1 RK_PD4 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m3_clk0: pdm0m3-clk0 { + rockchip,pins = + /* pdm0_clk0_m3 */ + <2 RK_PB5 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m3_clk1: pdm0m3-clk1 { + rockchip,pins = + /* pdm0_clk1_m3 */ + <2 RK_PB3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m3_sdi0: pdm0m3-sdi0 { + rockchip,pins = + /* pdm0_sdi0_m3 */ + <2 RK_PB4 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m3_sdi1: pdm0m3-sdi1 { + rockchip,pins = + /* pdm0_sdi1_m3 */ + <2 RK_PB2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m3_sdi2: pdm0m3-sdi2 { + rockchip,pins = + /* pdm0_sdi2_m3 */ + <2 RK_PB1 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm0m3_sdi3: pdm0m3-sdi3 { + rockchip,pins = + /* pdm0_sdi3_m3 */ + <2 RK_PB0 5 &pcfg_pull_none>; + }; + }; + + pdm1 { + /omit-if-no-ref/ + pdm1m0_clk0: pdm1m0-clk0 { + rockchip,pins = + /* pdm1_clk0_m0 */ + <2 RK_PC5 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m0_clk1: pdm1m0-clk1 { + rockchip,pins = + /* pdm1_clk1_m0 */ + <2 RK_PC1 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m0_sdi0: pdm1m0-sdi0 { + rockchip,pins = + /* pdm1_sdi0_m0 */ + <2 RK_PC4 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m0_sdi1: pdm1m0-sdi1 { + rockchip,pins = + /* pdm1_sdi1_m0 */ + <2 RK_PC0 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m0_sdi2: pdm1m0-sdi2 { + rockchip,pins = + /* pdm1_sdi2_m0 */ + <2 RK_PC2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m0_sdi3: pdm1m0-sdi3 { + rockchip,pins = + /* pdm1_sdi3_m0 */ + <2 RK_PC3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m1_clk0: pdm1m1-clk0 { + rockchip,pins = + /* pdm1_clk0_m1 */ + <4 RK_PA6 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m1_clk1: pdm1m1-clk1 { + rockchip,pins = + /* pdm1_clk1_m1 */ + <4 RK_PB0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m1_sdi0: pdm1m1-sdi0 { + rockchip,pins = + /* pdm1_sdi0_m1 */ + <4 RK_PB3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m1_sdi1: pdm1m1-sdi1 { + rockchip,pins = + /* pdm1_sdi1_m1 */ + <4 RK_PB2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m1_sdi2: pdm1m1-sdi2 { + rockchip,pins = + /* pdm1_sdi2_m1 */ + <4 RK_PB1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m1_sdi3: pdm1m1-sdi3 { + rockchip,pins = + /* pdm1_sdi3_m1 */ + <4 RK_PA4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m2_clk0: pdm1m2-clk0 { + rockchip,pins = + /* pdm1_clk0_m2 */ + <3 RK_PB1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m2_clk1: pdm1m2-clk1 { + rockchip,pins = + /* pdm1_clk1_m2 */ + <3 RK_PA7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m2_sdi0: pdm1m2-sdi0 { + rockchip,pins = + /* pdm1_sdi0_m2 */ + <3 RK_PB3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m2_sdi1: pdm1m2-sdi1 { + rockchip,pins = + /* pdm1_sdi1_m2 */ + <3 RK_PB2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m2_sdi2: pdm1m2-sdi2 { + rockchip,pins = + /* pdm1_sdi2_m2 */ + <3 RK_PA6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pdm1m2_sdi3: pdm1m2-sdi3 { + rockchip,pins = + /* pdm1_sdi3_m2 */ + <3 RK_PA5 4 &pcfg_pull_none>; + }; + }; + + pmu_debug_test { + /omit-if-no-ref/ + pmu_debug_test_pins: pmu_debug_test-pins { + rockchip,pins = + /* pmu_debug_test_out */ + <0 RK_PB0 2 &pcfg_pull_none>; + }; + }; + + pwm0 { + /omit-if-no-ref/ + pwm0m0_ch0: pwm0m0-ch0 { + rockchip,pins = + /* pwm0_ch0_m0 */ + <0 RK_PC4 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm0m0_ch1: pwm0m0-ch1 { + rockchip,pins = + /* pwm0_ch1_m0 */ + <0 RK_PC3 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm0m1_ch0: pwm0m1-ch0 { + rockchip,pins = + /* pwm0_ch0_m1 */ + <1 RK_PC0 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm0m1_ch1: pwm0m1-ch1 { + rockchip,pins = + /* pwm0_ch1_m1 */ + <4 RK_PC1 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm0m2_ch0: pwm0m2-ch0 { + rockchip,pins = + /* pwm0_ch0_m2 */ + <2 RK_PC3 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm0m2_ch1: pwm0m2-ch1 { + rockchip,pins = + /* pwm0_ch1_m2 */ + <2 RK_PC7 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm0m3_ch0: pwm0m3-ch0 { + rockchip,pins = + /* pwm0_ch0_m3 */ + <3 RK_PB0 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm0m3_ch1: pwm0m3-ch1 { + rockchip,pins = + /* pwm0_ch1_m3 */ + <3 RK_PB6 12 &pcfg_pull_none_drv_level_2>; + }; + }; + + pwm1 { + /omit-if-no-ref/ + pwm1m0_ch0: pwm1m0-ch0 { + rockchip,pins = + /* pwm1_ch0_m0 */ + <0 RK_PB4 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m0_ch1: pwm1m0-ch1 { + rockchip,pins = + /* pwm1_ch1_m0 */ + <0 RK_PB5 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m0_ch2: pwm1m0-ch2 { + rockchip,pins = + /* pwm1_ch2_m0 */ + <0 RK_PB6 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m0_ch3: pwm1m0-ch3 { + rockchip,pins = + /* pwm1_ch3_m0 */ + <0 RK_PC0 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m0_ch4: pwm1m0-ch4 { + rockchip,pins = + /* pwm1_ch4_m0 */ + <0 RK_PB7 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m0_ch5: pwm1m0-ch5 { + rockchip,pins = + /* pwm1_ch5_m0 */ + <0 RK_PD2 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m1_ch0: pwm1m1-ch0 { + rockchip,pins = + /* pwm1_ch0_m1 */ + <1 RK_PB4 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m1_ch1: pwm1m1-ch1 { + rockchip,pins = + /* pwm1_ch1_m1 */ + <1 RK_PB5 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m1_ch2: pwm1m1-ch2 { + rockchip,pins = + /* pwm1_ch2_m1 */ + <1 RK_PC2 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m1_ch3: pwm1m1-ch3 { + rockchip,pins = + /* pwm1_ch3_m1 */ + <1 RK_PD2 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m1_ch4: pwm1m1-ch4 { + rockchip,pins = + /* pwm1_ch4_m1 */ + <1 RK_PD3 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m1_ch5: pwm1m1-ch5 { + rockchip,pins = + /* pwm1_ch5_m1 */ + <4 RK_PC0 14 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m2_ch0: pwm1m2-ch0 { + rockchip,pins = + /* pwm1_ch0_m2 */ + <2 RK_PC0 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m2_ch1: pwm1m2-ch1 { + rockchip,pins = + /* pwm1_ch1_m2 */ + <2 RK_PC1 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m2_ch2: pwm1m2-ch2 { + rockchip,pins = + /* pwm1_ch2_m2 */ + <2 RK_PC2 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m2_ch3: pwm1m2-ch3 { + rockchip,pins = + /* pwm1_ch3_m2 */ + <2 RK_PC4 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m2_ch4: pwm1m2-ch4 { + rockchip,pins = + /* pwm1_ch4_m2 */ + <2 RK_PC5 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m2_ch5: pwm1m2-ch5 { + rockchip,pins = + /* pwm1_ch5_m2 */ + <2 RK_PC6 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m3_ch0: pwm1m3-ch0 { + rockchip,pins = + /* pwm1_ch0_m3 */ + <3 RK_PA4 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m3_ch1: pwm1m3-ch1 { + rockchip,pins = + /* pwm1_ch1_m3 */ + <3 RK_PA5 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m3_ch2: pwm1m3-ch2 { + rockchip,pins = + /* pwm1_ch2_m3 */ + <3 RK_PA6 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m3_ch3: pwm1m3-ch3 { + rockchip,pins = + /* pwm1_ch3_m3 */ + <3 RK_PB1 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m3_ch4: pwm1m3-ch4 { + rockchip,pins = + /* pwm1_ch4_m3 */ + <3 RK_PB4 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pwm1m3_ch5: pwm1m3-ch5 { + rockchip,pins = + /* pwm1_ch5_m3 */ + <3 RK_PB5 12 &pcfg_pull_none>; + }; + }; + + pwm2 { + /omit-if-no-ref/ + pwm2m0_ch0: pwm2m0-ch0 { + rockchip,pins = + /* pwm2_ch0_m0 */ + <0 RK_PD3 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m0_ch1: pwm2m0-ch1 { + rockchip,pins = + /* pwm2_ch1_m0 */ + <1 RK_PB3 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m0_ch2: pwm2m0-ch2 { + rockchip,pins = + /* pwm2_ch2_m0 */ + <2 RK_PA0 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m0_ch3: pwm2m0-ch3 { + rockchip,pins = + /* pwm2_ch3_m0 */ + <2 RK_PA1 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m0_ch4: pwm2m0-ch4 { + rockchip,pins = + /* pwm2_ch4_m0 */ + <2 RK_PA4 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m0_ch5: pwm2m0-ch5 { + rockchip,pins = + /* pwm2_ch5_m0 */ + <4 RK_PA2 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m0_ch6: pwm2m0-ch6 { + rockchip,pins = + /* pwm2_ch6_m0 */ + <4 RK_PA7 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m0_ch7: pwm2m0-ch7 { + rockchip,pins = + /* pwm2_ch7_m0 */ + <4 RK_PB3 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m1_ch0: pwm2m1-ch0 { + rockchip,pins = + /* pwm2_ch0_m1 */ + <4 RK_PC2 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m1_ch1: pwm2m1-ch1 { + rockchip,pins = + /* pwm2_ch1_m1 */ + <4 RK_PC3 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m1_ch2: pwm2m1-ch2 { + rockchip,pins = + /* pwm2_ch2_m1 */ + <4 RK_PC6 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m1_ch3: pwm2m1-ch3 { + rockchip,pins = + /* pwm2_ch3_m1 */ + <4 RK_PC7 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m1_ch4: pwm2m1-ch4 { + rockchip,pins = + /* pwm2_ch4_m1 */ + <4 RK_PA3 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m1_ch5: pwm2m1-ch5 { + rockchip,pins = + /* pwm2_ch5_m1 */ + <4 RK_PC5 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m1_ch6: pwm2m1-ch6 { + rockchip,pins = + /* pwm2_ch6_m1 */ + <4 RK_PC4 14 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m1_ch7: pwm2m1-ch7 { + rockchip,pins = + /* pwm2_ch7_m1 */ + <1 RK_PB1 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m2_ch0: pwm2m2-ch0 { + rockchip,pins = + /* pwm2_ch0_m2 */ + <2 RK_PD0 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m2_ch1: pwm2m2-ch1 { + rockchip,pins = + /* pwm2_ch1_m2 */ + <2 RK_PD1 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m2_ch2: pwm2m2-ch2 { + rockchip,pins = + /* pwm2_ch2_m2 */ + <2 RK_PD2 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m2_ch3: pwm2m2-ch3 { + rockchip,pins = + /* pwm2_ch3_m2 */ + <2 RK_PD3 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m2_ch4: pwm2m2-ch4 { + rockchip,pins = + /* pwm2_ch4_m2 */ + <2 RK_PD4 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m2_ch5: pwm2m2-ch5 { + rockchip,pins = + /* pwm2_ch5_m2 */ + <2 RK_PD5 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m2_ch6: pwm2m2-ch6 { + rockchip,pins = + /* pwm2_ch6_m2 */ + <2 RK_PD6 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m2_ch7: pwm2m2-ch7 { + rockchip,pins = + /* pwm2_ch7_m2 */ + <2 RK_PD7 13 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m3_ch0: pwm2m3-ch0 { + rockchip,pins = + /* pwm2_ch0_m3 */ + <3 RK_PC2 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m3_ch1: pwm2m3-ch1 { + rockchip,pins = + /* pwm2_ch1_m3 */ + <3 RK_PC3 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m3_ch2: pwm2m3-ch2 { + rockchip,pins = + /* pwm2_ch2_m3 */ + <3 RK_PC5 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m3_ch3: pwm2m3-ch3 { + rockchip,pins = + /* pwm2_ch3_m3 */ + <3 RK_PD0 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m3_ch4: pwm2m3-ch4 { + rockchip,pins = + /* pwm2_ch4_m3 */ + <3 RK_PD2 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m3_ch5: pwm2m3-ch5 { + rockchip,pins = + /* pwm2_ch5_m3 */ + <3 RK_PD3 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m3_ch6: pwm2m3-ch6 { + rockchip,pins = + /* pwm2_ch6_m3 */ + <3 RK_PD6 12 &pcfg_pull_none_drv_level_2>; + }; + + /omit-if-no-ref/ + pwm2m3_ch7: pwm2m3-ch7 { + rockchip,pins = + /* pwm2_ch7_m3 */ + <3 RK_PD7 12 &pcfg_pull_none_drv_level_2>; + }; + }; + + ref_clk0 { + /omit-if-no-ref/ + ref_clk0_clk0: ref_clk0-clk0 { + rockchip,pins = + /* ref_clk0_out */ + <0 RK_PA0 1 &pcfg_pull_none>; + }; + }; + + ref_clk1 { + /omit-if-no-ref/ + ref_clk1_clk1: ref_clk1-clk1 { + rockchip,pins = + /* ref_clk1_out */ + <0 RK_PB4 1 &pcfg_pull_none>; + }; + }; + + ref_clk2 { + /omit-if-no-ref/ + ref_clk2_clk2: ref_clk2-clk2 { + rockchip,pins = + /* ref_clk2_out */ + <0 RK_PB5 1 &pcfg_pull_none>; + }; + }; + + sai0 { + /omit-if-no-ref/ + sai0m0_lrck: sai0m0-lrck { + rockchip,pins = + /* sai0_lrck_m0 */ + <2 RK_PB7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_mclk: sai0m0-mclk { + rockchip,pins = + /* sai0_mclk_m0 */ + <2 RK_PB5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sclk: sai0m0-sclk { + rockchip,pins = + /* sai0_sclk_m0 */ + <2 RK_PB6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sdi0: sai0m0-sdi0 { + rockchip,pins = + /* sai0_sdi0_m0 */ + <2 RK_PB0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sdi1: sai0m0-sdi1 { + rockchip,pins = + /* sai0_sdi1_m0 */ + <2 RK_PB1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sdi2: sai0m0-sdi2 { + rockchip,pins = + /* sai0_sdi2_m0 */ + <2 RK_PB2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sdi3: sai0m0-sdi3 { + rockchip,pins = + /* sai0_sdi3_m0 */ + <2 RK_PB4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sdo0: sai0m0-sdo0 { + rockchip,pins = + /* sai0_sdo0_m0 */ + <2 RK_PA6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sdo1: sai0m0-sdo1 { + rockchip,pins = + /* sai0_sdo1_m0 */ + <2 RK_PA7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sdo2: sai0m0-sdo2 { + rockchip,pins = + /* sai0_sdo2_m0 */ + <2 RK_PB3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m0_sdo3: sai0m0-sdo3 { + rockchip,pins = + /* sai0_sdo3_m0 */ + <2 RK_PD7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_lrck: sai0m1-lrck { + rockchip,pins = + /* sai0_lrck_m1 */ + <0 RK_PC7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_mclk: sai0m1-mclk { + rockchip,pins = + /* sai0_mclk_m1 */ + <0 RK_PC4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sclk: sai0m1-sclk { + rockchip,pins = + /* sai0_sclk_m1 */ + <0 RK_PC6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sdi0: sai0m1-sdi0 { + rockchip,pins = + /* sai0_sdi0_m1 */ + <0 RK_PD0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sdi1: sai0m1-sdi1 { + rockchip,pins = + /* sai0_sdi1_m1 */ + <0 RK_PD1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sdi2: sai0m1-sdi2 { + rockchip,pins = + /* sai0_sdi2_m1 */ + <0 RK_PD2 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sdi3: sai0m1-sdi3 { + rockchip,pins = + /* sai0_sdi3_m1 */ + <0 RK_PD3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sdo0: sai0m1-sdo0 { + rockchip,pins = + /* sai0_sdo0_m1 */ + <0 RK_PC5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sdo1: sai0m1-sdo1 { + rockchip,pins = + /* sai0_sdo1_m1 */ + <0 RK_PD3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sdo2: sai0m1-sdo2 { + rockchip,pins = + /* sai0_sdo2_m1 */ + <0 RK_PD2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m1_sdo3: sai0m1-sdo3 { + rockchip,pins = + /* sai0_sdo3_m1 */ + <0 RK_PD1 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_lrck: sai0m2-lrck { + rockchip,pins = + /* sai0_lrck_m2 */ + <1 RK_PA1 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_mclk: sai0m2-mclk { + rockchip,pins = + /* sai0_mclk_m2 */ + <1 RK_PA4 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sclk: sai0m2-sclk { + rockchip,pins = + /* sai0_sclk_m2 */ + <1 RK_PA0 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sdi0: sai0m2-sdi0 { + rockchip,pins = + /* sai0_sdi0_m2 */ + <1 RK_PB2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sdi1: sai0m2-sdi1 { + rockchip,pins = + /* sai0_sdi1_m2 */ + <1 RK_PB1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sdi2: sai0m2-sdi2 { + rockchip,pins = + /* sai0_sdi2_m2 */ + <1 RK_PA3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sdi3: sai0m2-sdi3 { + rockchip,pins = + /* sai0_sdi3_m2 */ + <1 RK_PA2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sdo0: sai0m2-sdo0 { + rockchip,pins = + /* sai0_sdo0_m2 */ + <1 RK_PA7 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sdo1: sai0m2-sdo1 { + rockchip,pins = + /* sai0_sdo1_m2 */ + <1 RK_PA2 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sdo2: sai0m2-sdo2 { + rockchip,pins = + /* sai0_sdo2_m2 */ + <1 RK_PA3 3 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai0m2_sdo3: sai0m2-sdo3 { + rockchip,pins = + /* sai0_sdo3_m2 */ + <1 RK_PB1 3 &pcfg_pull_none>; + }; + }; + + sai1 { + /omit-if-no-ref/ + sai1m0_lrck: sai1m0-lrck { + rockchip,pins = + /* sai1_lrck_m0 */ + <4 RK_PA5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_mclk: sai1m0-mclk { + rockchip,pins = + /* sai1_mclk_m0 */ + <4 RK_PA2 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sclk: sai1m0-sclk { + rockchip,pins = + /* sai1_sclk_m0 */ + <4 RK_PA3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sdi0: sai1m0-sdi0 { + rockchip,pins = + /* sai1_sdi0_m0 */ + <4 RK_PB3 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sdi1: sai1m0-sdi1 { + rockchip,pins = + /* sai1_sdi1_m0 */ + <4 RK_PB2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sdi2: sai1m0-sdi2 { + rockchip,pins = + /* sai1_sdi2_m0 */ + <4 RK_PB1 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sdi3: sai1m0-sdi3 { + rockchip,pins = + /* sai1_sdi3_m0 */ + <4 RK_PB0 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sdo0: sai1m0-sdo0 { + rockchip,pins = + /* sai1_sdo0_m0 */ + <4 RK_PA7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sdo1: sai1m0-sdo1 { + rockchip,pins = + /* sai1_sdo1_m0 */ + <4 RK_PB0 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sdo2: sai1m0-sdo2 { + rockchip,pins = + /* sai1_sdo2_m0 */ + <4 RK_PB1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m0_sdo3: sai1m0-sdo3 { + rockchip,pins = + /* sai1_sdo3_m0 */ + <4 RK_PB2 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_lrck: sai1m1-lrck { + rockchip,pins = + /* sai1_lrck_m1 */ + <3 RK_PC6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_mclk: sai1m1-mclk { + rockchip,pins = + /* sai1_mclk_m1 */ + <3 RK_PD0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sclk: sai1m1-sclk { + rockchip,pins = + /* sai1_sclk_m1 */ + <3 RK_PC7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sdi0: sai1m1-sdi0 { + rockchip,pins = + /* sai1_sdi0_m1 */ + <3 RK_PB7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sdi1: sai1m1-sdi1 { + rockchip,pins = + /* sai1_sdi1_m1 */ + <3 RK_PD4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sdi2: sai1m1-sdi2 { + rockchip,pins = + /* sai1_sdi2_m1 */ + <3 RK_PD5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sdi3: sai1m1-sdi3 { + rockchip,pins = + /* sai1_sdi3_m1 */ + <3 RK_PD6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sdo0: sai1m1-sdo0 { + rockchip,pins = + /* sai1_sdo0_m1 */ + <3 RK_PC5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sdo1: sai1m1-sdo1 { + rockchip,pins = + /* sai1_sdo1_m1 */ + <3 RK_PC4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sdo2: sai1m1-sdo2 { + rockchip,pins = + /* sai1_sdo2_m1 */ + <3 RK_PC1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai1m1_sdo3: sai1m1-sdo3 { + rockchip,pins = + /* sai1_sdo3_m1 */ + <3 RK_PC0 4 &pcfg_pull_none>; + }; + }; + + sai2 { + /omit-if-no-ref/ + sai2m0_lrck: sai2m0-lrck { + rockchip,pins = + /* sai2_lrck_m0 */ + <1 RK_PD2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m0_mclk: sai2m0-mclk { + rockchip,pins = + /* sai2_mclk_m0 */ + <1 RK_PD4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m0_sclk: sai2m0-sclk { + rockchip,pins = + /* sai2_sclk_m0 */ + <1 RK_PD1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m0_sdi: sai2m0-sdi { + rockchip,pins = + /* sai2m0_sdi */ + <1 RK_PD3 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai2m0_sdo: sai2m0-sdo { + rockchip,pins = + /* sai2m0_sdo */ + <1 RK_PD0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m1_lrck: sai2m1-lrck { + rockchip,pins = + /* sai2_lrck_m1 */ + <2 RK_PC3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m1_mclk: sai2m1-mclk { + rockchip,pins = + /* sai2_mclk_m1 */ + <2 RK_PC1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m1_sclk: sai2m1-sclk { + rockchip,pins = + /* sai2_sclk_m1 */ + <2 RK_PC2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m1_sdi: sai2m1-sdi { + rockchip,pins = + /* sai2m1_sdi */ + <2 RK_PC5 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai2m1_sdo: sai2m1-sdo { + rockchip,pins = + /* sai2m1_sdo */ + <2 RK_PC4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m2_lrck: sai2m2-lrck { + rockchip,pins = + /* sai2_lrck_m2 */ + <3 RK_PC3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m2_mclk: sai2m2-mclk { + rockchip,pins = + /* sai2_mclk_m2 */ + <3 RK_PD1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m2_sclk: sai2m2-sclk { + rockchip,pins = + /* sai2_sclk_m2 */ + <3 RK_PC2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai2m2_sdi: sai2m2-sdi { + rockchip,pins = + /* sai2m2_sdi */ + <3 RK_PD2 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai2m2_sdo: sai2m2-sdo { + rockchip,pins = + /* sai2m2_sdo */ + <3 RK_PD3 4 &pcfg_pull_none>; + }; + }; + + sai3 { + /omit-if-no-ref/ + sai3m0_lrck: sai3m0-lrck { + rockchip,pins = + /* sai3_lrck_m0 */ + <1 RK_PA6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m0_mclk: sai3m0-mclk { + rockchip,pins = + /* sai3_mclk_m0 */ + <1 RK_PA4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m0_sclk: sai3m0-sclk { + rockchip,pins = + /* sai3_sclk_m0 */ + <1 RK_PA5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m0_sdi: sai3m0-sdi { + rockchip,pins = + /* sai3m0_sdi */ + <1 RK_PA7 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai3m0_sdo: sai3m0-sdo { + rockchip,pins = + /* sai3m0_sdo */ + <1 RK_PB2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m1_lrck: sai3m1-lrck { + rockchip,pins = + /* sai3_lrck_m1 */ + <1 RK_PB5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m1_mclk: sai3m1-mclk { + rockchip,pins = + /* sai3_mclk_m1 */ + <1 RK_PC1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m1_sclk: sai3m1-sclk { + rockchip,pins = + /* sai3_sclk_m1 */ + <1 RK_PB4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m1_sdi: sai3m1-sdi { + rockchip,pins = + /* sai3m1_sdi */ + <1 RK_PB7 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai3m1_sdo: sai3m1-sdo { + rockchip,pins = + /* sai3m1_sdo */ + <1 RK_PB6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m2_lrck: sai3m2-lrck { + rockchip,pins = + /* sai3_lrck_m2 */ + <3 RK_PA1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m2_mclk: sai3m2-mclk { + rockchip,pins = + /* sai3_mclk_m2 */ + <2 RK_PD6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m2_sclk: sai3m2-sclk { + rockchip,pins = + /* sai3_sclk_m2 */ + <3 RK_PA0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m2_sdi: sai3m2-sdi { + rockchip,pins = + /* sai3m2_sdi */ + <3 RK_PA3 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai3m2_sdo: sai3m2-sdo { + rockchip,pins = + /* sai3m2_sdo */ + <3 RK_PA2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m3_lrck: sai3m3-lrck { + rockchip,pins = + /* sai3_lrck_m3 */ + <2 RK_PA2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m3_mclk: sai3m3-mclk { + rockchip,pins = + /* sai3_mclk_m3 */ + <2 RK_PA1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m3_sclk: sai3m3-sclk { + rockchip,pins = + /* sai3_sclk_m3 */ + <2 RK_PA5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai3m3_sdi: sai3m3-sdi { + rockchip,pins = + /* sai3m3_sdi */ + <2 RK_PA3 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai3m3_sdo: sai3m3-sdo { + rockchip,pins = + /* sai3m3_sdo */ + <2 RK_PA4 4 &pcfg_pull_none>; + }; + }; + + sai4 { + /omit-if-no-ref/ + sai4m0_lrck: sai4m0-lrck { + rockchip,pins = + /* sai4_lrck_m0 */ + <4 RK_PA6 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m0_mclk: sai4m0-mclk { + rockchip,pins = + /* sai4_mclk_m0 */ + <4 RK_PA2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m0_sclk: sai4m0-sclk { + rockchip,pins = + /* sai4_sclk_m0 */ + <4 RK_PA4 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m0_sdi: sai4m0-sdi { + rockchip,pins = + /* sai4m0_sdi */ + <4 RK_PA7 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai4m0_sdo: sai4m0-sdo { + rockchip,pins = + /* sai4m0_sdo */ + <4 RK_PB3 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m1_lrck: sai4m1-lrck { + rockchip,pins = + /* sai4_lrck_m1 */ + <4 RK_PA0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m1_mclk: sai4m1-mclk { + rockchip,pins = + /* sai4_mclk_m1 */ + <3 RK_PB0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m1_sclk: sai4m1-sclk { + rockchip,pins = + /* sai4_sclk_m1 */ + <3 RK_PD7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m1_sdi: sai4m1-sdi { + rockchip,pins = + /* sai4m1_sdi */ + <3 RK_PA4 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai4m1_sdo: sai4m1-sdo { + rockchip,pins = + /* sai4m1_sdo */ + <4 RK_PA1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m2_lrck: sai4m2-lrck { + rockchip,pins = + /* sai4_lrck_m2 */ + <4 RK_PC4 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m2_mclk: sai4m2-mclk { + rockchip,pins = + /* sai4_mclk_m2 */ + <4 RK_PC0 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m2_sclk: sai4m2-sclk { + rockchip,pins = + /* sai4_sclk_m2 */ + <4 RK_PC7 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m2_sdi: sai4m2-sdi { + rockchip,pins = + /* sai4m2_sdi */ + <4 RK_PC6 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai4m2_sdo: sai4m2-sdo { + rockchip,pins = + /* sai4m2_sdo */ + <4 RK_PC5 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m3_lrck: sai4m3-lrck { + rockchip,pins = + /* sai4_lrck_m3 */ + <2 RK_PC7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m3_mclk: sai4m3-mclk { + rockchip,pins = + /* sai4_mclk_m3 */ + <2 RK_PD2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m3_sclk: sai4m3-sclk { + rockchip,pins = + /* sai4_sclk_m3 */ + <2 RK_PC6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sai4m3_sdi: sai4m3-sdi { + rockchip,pins = + /* sai4m3_sdi */ + <2 RK_PD0 4 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + sai4m3_sdo: sai4m3-sdo { + rockchip,pins = + /* sai4m3_sdo */ + <2 RK_PD1 4 &pcfg_pull_none>; + }; + }; + + sata30 { + /omit-if-no-ref/ + sata30_sata: sata30-sata { + rockchip,pins = + /* sata30_cpdet */ + <1 RK_PC7 12 &pcfg_pull_none>, + /* sata30_cppod */ + <1 RK_PC6 12 &pcfg_pull_none>, + /* sata30_mpswit */ + <1 RK_PD5 12 &pcfg_pull_none>; + }; + }; + + sata30_port0 { + /omit-if-no-ref/ + sata30_port0m0_port0: sata30_port0m0-port0 { + rockchip,pins = + /* sata30_port0_actled_m0 */ + <2 RK_PB4 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sata30_port0m1_port0: sata30_port0m1-port0 { + rockchip,pins = + /* sata30_port0_actled_m1 */ + <4 RK_PC6 10 &pcfg_pull_none>; + }; + }; + + sata30_port1 { + /omit-if-no-ref/ + sata30_port1m0_port1: sata30_port1m0-port1 { + rockchip,pins = + /* sata30_port1_actled_m0 */ + <2 RK_PB5 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sata30_port1m1_port1: sata30_port1m1-port1 { + rockchip,pins = + /* sata30_port1_actled_m1 */ + <4 RK_PC5 10 &pcfg_pull_none>; + }; + }; + + sdmmc0 { + /omit-if-no-ref/ + sdmmc0_bus4: sdmmc0-bus4 { + rockchip,pins = + /* sdmmc0_d0 */ + <2 RK_PA0 1 &pcfg_pull_up_drv_level_3>, + /* sdmmc0_d1 */ + <2 RK_PA1 1 &pcfg_pull_up_drv_level_3>, + /* sdmmc0_d2 */ + <2 RK_PA2 1 &pcfg_pull_up_drv_level_3>, + /* sdmmc0_d3 */ + <2 RK_PA3 1 &pcfg_pull_up_drv_level_3>; + }; + + /omit-if-no-ref/ + sdmmc0_clk: sdmmc0-clk { + rockchip,pins = + /* sdmmc0_clk */ + <2 RK_PA5 1 &pcfg_pull_up_drv_level_3>; + }; + + /omit-if-no-ref/ + sdmmc0_cmd: sdmmc0-cmd { + rockchip,pins = + /* sdmmc0_cmd */ + <2 RK_PA4 1 &pcfg_pull_up_drv_level_3>; + }; + + /omit-if-no-ref/ + sdmmc0_det: sdmmc0-det { + rockchip,pins = + /* sdmmc0_detn */ + <0 RK_PA7 1 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + sdmmc0_pwren: sdmmc0-pwren { + rockchip,pins = + /* sdmmc0_pwren */ + <0 RK_PB6 1 &pcfg_pull_none>; + }; + }; + + sdmmc1 { + /omit-if-no-ref/ + sdmmc1m0_bus4: sdmmc1m0-bus4 { + rockchip,pins = + /* sdmmc1_d0_m0 */ + <1 RK_PB4 2 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d1_m0 */ + <1 RK_PB5 2 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d2_m0 */ + <1 RK_PB6 2 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d3_m0 */ + <1 RK_PB7 2 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1m0_clk: sdmmc1m0-clk { + rockchip,pins = + /* sdmmc1_clk_m0 */ + <1 RK_PC1 2 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1m0_cmd: sdmmc1m0-cmd { + rockchip,pins = + /* sdmmc1_cmd_m0 */ + <1 RK_PC0 2 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1m0_det: sdmmc1m0-det { + rockchip,pins = + /* sdmmc1_detn_m0 */ + <1 RK_PC3 2 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + sdmmc1m0_pwren: sdmmc1m0-pwren { + rockchip,pins = + /* sdmmc1m0_pwren */ + <1 RK_PC2 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sdmmc1m1_bus4: sdmmc1m1-bus4 { + rockchip,pins = + /* sdmmc1_d0_m1 */ + <2 RK_PA6 2 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d1_m1 */ + <2 RK_PA7 2 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d2_m1 */ + <2 RK_PB0 2 &pcfg_pull_up_drv_level_2>, + /* sdmmc1_d3_m1 */ + <2 RK_PB1 2 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1m1_clk: sdmmc1m1-clk { + rockchip,pins = + /* sdmmc1_clk_m1 */ + <2 RK_PB3 2 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1m1_cmd: sdmmc1m1-cmd { + rockchip,pins = + /* sdmmc1_cmd_m1 */ + <2 RK_PB2 2 &pcfg_pull_up_drv_level_2>; + }; + + /omit-if-no-ref/ + sdmmc1m1_det: sdmmc1m1-det { + rockchip,pins = + /* sdmmc1_detn_m1 */ + <2 RK_PB5 2 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + sdmmc1m1_pwren: sdmmc1m1-pwren { + rockchip,pins = + /* sdmmc1m1_pwren */ + <2 RK_PB4 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + sdmmc1m2_det: sdmmc1m2-det { + rockchip,pins = + /* sdmmc1_detn_m2 */ + <0 RK_PB6 2 &pcfg_pull_up>; + }; + }; + + sdmmc0_testclk { + /omit-if-no-ref/ + sdmmc0_testclk_test: sdmmc0_testclk-test { + rockchip,pins = + /* sdmmc0_testclk_out */ + <1 RK_PC4 6 &pcfg_pull_none>; + }; + }; + + sdmmc0_testdata { + /omit-if-no-ref/ + sdmmc0_testdata_test: sdmmc0_testdata-test { + rockchip,pins = + /* sdmmc0_testdata_out */ + <1 RK_PC5 6 &pcfg_pull_none>; + }; + }; + + sdmmc1_testclk { + /omit-if-no-ref/ + sdmmc1_testclkm0_test: sdmmc1_testclkm0-test { + rockchip,pins = + /* sdmmc1_testclk_out_m0 */ + <1 RK_PC4 5 &pcfg_pull_none>; + }; + }; + + sdmmc1_testdata { + /omit-if-no-ref/ + sdmmc1_testdatam0_test: sdmmc1_testdatam0-test { + rockchip,pins = + /* sdmmc1_testdata_out_m0 */ + <1 RK_PC5 5 &pcfg_pull_none>; + }; + }; + + spdif { + /omit-if-no-ref/ + spdifm0_rx0: spdifm0-rx0 { + rockchip,pins = + /* spdif_rx0_m0 */ + <4 RK_PB4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm0_rx1: spdifm0-rx1 { + rockchip,pins = + /* spdif_rx1_m0 */ + <3 RK_PB4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm0_tx0: spdifm0-tx0 { + rockchip,pins = + /* spdif_tx0_m0 */ + <4 RK_PB5 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm0_tx1: spdifm0-tx1 { + rockchip,pins = + /* spdif_tx1_m0 */ + <3 RK_PB5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm1_rx0: spdifm1-rx0 { + rockchip,pins = + /* spdif_rx0_m1 */ + <4 RK_PA0 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm1_rx1: spdifm1-rx1 { + rockchip,pins = + /* spdif_rx1_m1 */ + <3 RK_PA2 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm1_tx0: spdifm1-tx0 { + rockchip,pins = + /* spdif_tx0_m1 */ + <4 RK_PA1 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm1_tx1: spdifm1-tx1 { + rockchip,pins = + /* spdif_tx1_m1 */ + <3 RK_PA3 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm2_rx0: spdifm2-rx0 { + rockchip,pins = + /* spdif_rx0_m2 */ + <2 RK_PD6 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm2_rx1: spdifm2-rx1 { + rockchip,pins = + /* spdif_rx1_m2 */ + <1 RK_PD4 6 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm2_tx0: spdifm2-tx0 { + rockchip,pins = + /* spdif_tx0_m2 */ + <2 RK_PD7 5 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spdifm2_tx1: spdifm2-tx1 { + rockchip,pins = + /* spdif_tx1_m2 */ + <1 RK_PD5 6 &pcfg_pull_none>; + }; + }; + + spi0 { + /omit-if-no-ref/ + spi0m0_pins: spi0m0-pins { + rockchip,pins = + /* spi0_clk_m0 */ + <0 RK_PC7 11 &pcfg_pull_none>, + /* spi0_miso_m0 */ + <0 RK_PD1 11 &pcfg_pull_none>, + /* spi0_mosi_m0 */ + <0 RK_PD0 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m0_csn0: spi0m0-csn0 { + rockchip,pins = + /* spi0m0_csn0 */ + <0 RK_PC6 11 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi0m0_csn1: spi0m0-csn1 { + rockchip,pins = + /* spi0m0_csn1 */ + <0 RK_PC3 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m1_pins: spi0m1-pins { + rockchip,pins = + /* spi0_clk_m1 */ + <2 RK_PA5 12 &pcfg_pull_none>, + /* spi0_miso_m1 */ + <2 RK_PA1 12 &pcfg_pull_none>, + /* spi0_mosi_m1 */ + <2 RK_PA0 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m1_csn0: spi0m1-csn0 { + rockchip,pins = + /* spi0m1_csn0 */ + <2 RK_PA4 12 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi0m1_csn1: spi0m1-csn1 { + rockchip,pins = + /* spi0m1_csn1 */ + <2 RK_PA2 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m2_pins: spi0m2-pins { + rockchip,pins = + /* spi0_clk_m2 */ + <1 RK_PA7 9 &pcfg_pull_none>, + /* spi0_miso_m2 */ + <1 RK_PA6 9 &pcfg_pull_none>, + /* spi0_mosi_m2 */ + <1 RK_PA5 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi0m2_csn0: spi0m2-csn0 { + rockchip,pins = + /* spi0m2_csn0 */ + <1 RK_PA4 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi0m2_csn1: spi0m2-csn1 { + rockchip,pins = + /* spi0m2_csn1 */ + <1 RK_PB2 9 &pcfg_pull_none>; + }; + }; + + spi1 { + /omit-if-no-ref/ + spi1m0_pins: spi1m0-pins { + rockchip,pins = + /* spi1_clk_m0 */ + <1 RK_PB4 11 &pcfg_pull_none>, + /* spi1_miso_m0 */ + <1 RK_PB6 11 &pcfg_pull_none>, + /* spi1_mosi_m0 */ + <1 RK_PB5 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m0_csn0: spi1m0-csn0 { + rockchip,pins = + /* spi1m0_csn0 */ + <1 RK_PB7 11 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi1m0_csn1: spi1m0-csn1 { + rockchip,pins = + /* spi1m0_csn1 */ + <1 RK_PC0 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m1_pins: spi1m1-pins { + rockchip,pins = + /* spi1_clk_m1 */ + <2 RK_PC5 10 &pcfg_pull_none>, + /* spi1_miso_m1 */ + <2 RK_PC3 10 &pcfg_pull_none>, + /* spi1_mosi_m1 */ + <2 RK_PC2 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m1_csn0: spi1m1-csn0 { + rockchip,pins = + /* spi1m1_csn0 */ + <2 RK_PC4 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi1m1_csn1: spi1m1-csn1 { + rockchip,pins = + /* spi1m1_csn1 */ + <2 RK_PC1 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m2_pins: spi1m2-pins { + rockchip,pins = + /* spi1_clk_m2 */ + <3 RK_PC7 10 &pcfg_pull_none>, + /* spi1_miso_m2 */ + <3 RK_PC5 10 &pcfg_pull_none>, + /* spi1_mosi_m2 */ + <3 RK_PC6 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi1m2_csn0: spi1m2-csn0 { + rockchip,pins = + /* spi1m2_csn0 */ + <3 RK_PD0 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi1m2_csn1: spi1m2-csn1 { + rockchip,pins = + /* spi1m2_csn1 */ + <4 RK_PA0 10 &pcfg_pull_none>; + }; + }; + + spi2 { + /omit-if-no-ref/ + spi2m0_pins: spi2m0-pins { + rockchip,pins = + /* spi2_clk_m0 */ + <0 RK_PB2 9 &pcfg_pull_none>, + /* spi2_miso_m0 */ + <0 RK_PB1 9 &pcfg_pull_none>, + /* spi2_mosi_m0 */ + <0 RK_PB3 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m0_csn0: spi2m0-csn0 { + rockchip,pins = + /* spi2m0_csn0 */ + <0 RK_PB0 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi2m0_csn1: spi2m0-csn1 { + rockchip,pins = + /* spi2m0_csn1 */ + <0 RK_PA7 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m1_pins: spi2m1-pins { + rockchip,pins = + /* spi2_clk_m1 */ + <1 RK_PD5 11 &pcfg_pull_none>, + /* spi2_miso_m1 */ + <1 RK_PC5 11 &pcfg_pull_none>, + /* spi2_mosi_m1 */ + <1 RK_PC4 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m1_csn0: spi2m1-csn0 { + rockchip,pins = + /* spi2m1_csn0 */ + <1 RK_PC3 11 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi2m1_csn1: spi2m1-csn1 { + rockchip,pins = + /* spi2m1_csn1 */ + <1 RK_PC2 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m2_pins: spi2m2-pins { + rockchip,pins = + /* spi2_clk_m2 */ + <3 RK_PA4 10 &pcfg_pull_none>, + /* spi2_miso_m2 */ + <3 RK_PC1 10 &pcfg_pull_none>, + /* spi2_mosi_m2 */ + <3 RK_PB0 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi2m2_csn0: spi2m2-csn0 { + rockchip,pins = + /* spi2m2_csn0 */ + <3 RK_PC4 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi2m2_csn1: spi2m2-csn1 { + rockchip,pins = + /* spi2m2_csn1 */ + <3 RK_PA5 10 &pcfg_pull_none>; + }; + }; + + spi3 { + /omit-if-no-ref/ + spi3m0_pins: spi3m0-pins { + rockchip,pins = + /* spi3_clk_m0 */ + <3 RK_PA0 10 &pcfg_pull_none>, + /* spi3_miso_m0 */ + <3 RK_PA2 10 &pcfg_pull_none>, + /* spi3_mosi_m0 */ + <3 RK_PA1 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m0_csn0: spi3m0-csn0 { + rockchip,pins = + /* spi3m0_csn0 */ + <3 RK_PA3 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi3m0_csn1: spi3m0-csn1 { + rockchip,pins = + /* spi3m0_csn1 */ + <2 RK_PD7 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m1_pins: spi3m1-pins { + rockchip,pins = + /* spi3_clk_m1 */ + <3 RK_PD4 10 &pcfg_pull_none>, + /* spi3_miso_m1 */ + <3 RK_PD5 10 &pcfg_pull_none>, + /* spi3_mosi_m1 */ + <3 RK_PD6 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m1_csn0: spi3m1-csn0 { + rockchip,pins = + /* spi3m1_csn0 */ + <3 RK_PB6 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi3m1_csn1: spi3m1-csn1 { + rockchip,pins = + /* spi3m1_csn1 */ + <3 RK_PD7 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m2_pins: spi3m2-pins { + rockchip,pins = + /* spi3_clk_m2 */ + <4 RK_PA7 9 &pcfg_pull_none>, + /* spi3_miso_m2 */ + <4 RK_PA6 9 &pcfg_pull_none>, + /* spi3_mosi_m2 */ + <4 RK_PA4 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi3m2_csn0: spi3m2-csn0 { + rockchip,pins = + /* spi3m2_csn0 */ + <4 RK_PA3 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi3m2_csn1: spi3m2-csn1 { + rockchip,pins = + /* spi3m2_csn1 */ + <4 RK_PB3 10 &pcfg_pull_none>; + }; + }; + + spi4 { + /omit-if-no-ref/ + spi4m0_pins: spi4m0-pins { + rockchip,pins = + /* spi4_clk_m0 */ + <4 RK_PC7 12 &pcfg_pull_none>, + /* spi4_miso_m0 */ + <4 RK_PC6 12 &pcfg_pull_none>, + /* spi4_mosi_m0 */ + <4 RK_PC5 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi4m0_csn0: spi4m0-csn0 { + rockchip,pins = + /* spi4m0_csn0 */ + <4 RK_PC4 12 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi4m0_csn1: spi4m0-csn1 { + rockchip,pins = + /* spi4m0_csn1 */ + <4 RK_PC0 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi4m1_pins: spi4m1-pins { + rockchip,pins = + /* spi4_clk_m1 */ + <3 RK_PD1 10 &pcfg_pull_none>, + /* spi4_miso_m1 */ + <3 RK_PC2 10 &pcfg_pull_none>, + /* spi4_mosi_m1 */ + <3 RK_PC3 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi4m1_csn0: spi4m1-csn0 { + rockchip,pins = + /* spi4m1_csn0 */ + <3 RK_PB1 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi4m1_csn1: spi4m1-csn1 { + rockchip,pins = + /* spi4m1_csn1 */ + <3 RK_PD2 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi4m2_pins: spi4m2-pins { + rockchip,pins = + /* spi4_clk_m2 */ + <4 RK_PB0 9 &pcfg_pull_none>, + /* spi4_miso_m2 */ + <4 RK_PB2 9 &pcfg_pull_none>, + /* spi4_mosi_m2 */ + <4 RK_PB1 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi4m2_csn0: spi4m2-csn0 { + rockchip,pins = + /* spi4m2_csn0 */ + <4 RK_PB3 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi4m2_csn1: spi4m2-csn1 { + rockchip,pins = + /* spi4m2_csn1 */ + <4 RK_PA5 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi4m3_pins: spi4m3-pins { + rockchip,pins = + /* spi4_clk_m3 */ + <2 RK_PB3 10 &pcfg_pull_none>, + /* spi4_miso_m3 */ + <2 RK_PB5 10 &pcfg_pull_none>, + /* spi4_mosi_m3 */ + <2 RK_PB4 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + spi4m3_csn0: spi4m3-csn0 { + rockchip,pins = + /* spi4m3_csn0 */ + <2 RK_PB2 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + spi4m3_csn1: spi4m3-csn1 { + rockchip,pins = + /* spi4m3_csn1 */ + <2 RK_PA6 10 &pcfg_pull_none>; + }; + }; + + test_clk { + /omit-if-no-ref/ + test_clk_pins: test_clk-pins { + rockchip,pins = + /* test_clk_out */ + <2 RK_PA5 5 &pcfg_pull_none>; + }; + }; + + tsadc { + /omit-if-no-ref/ + tsadcm0_pins: tsadcm0-pins { + rockchip,pins = + /* tsadc_ctrl_m0 */ + <0 RK_PA1 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + tsadcm1_pins: tsadcm1-pins { + rockchip,pins = + /* tsadc_ctrl_m1 */ + <0 RK_PA3 10 &pcfg_pull_none>; + }; + }; + + tsadc_ctrl { + /omit-if-no-ref/ + tsadc_ctrl_pins: tsadc_ctrl-pins { + rockchip,pins = + /* tsadc_ctrl_org */ + <0 RK_PA1 10 &pcfg_pull_none>; + }; + }; + + uart0 { + /omit-if-no-ref/ + uart0m0_xfer: uart0m0-xfer { + rockchip,pins = + /* uart0_rx_m0 */ + <0 RK_PD5 9 &pcfg_pull_up>, + /* uart0_tx_m0 */ + <0 RK_PD4 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart0m1_xfer: uart0m1-xfer { + rockchip,pins = + /* uart0_rx_m1 */ + <2 RK_PA0 9 &pcfg_pull_up>, + /* uart0_tx_m1 */ + <2 RK_PA1 9 &pcfg_pull_up>; + }; + }; + + uart1 { + /omit-if-no-ref/ + uart1m0_xfer: uart1m0-xfer { + rockchip,pins = + /* uart1_rx_m0 */ + <0 RK_PC0 10 &pcfg_pull_up>, + /* uart1_tx_m0 */ + <0 RK_PB7 10 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart1m0_ctsn: uart1m0-ctsn { + rockchip,pins = + /* uart1m0_ctsn */ + <0 RK_PD2 13 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart1m0_rtsn: uart1m0-rtsn { + rockchip,pins = + /* uart1m0_rtsn */ + <0 RK_PD3 13 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart1m1_xfer: uart1m1-xfer { + rockchip,pins = + /* uart1_rx_m1 */ + <2 RK_PB1 9 &pcfg_pull_up>, + /* uart1_tx_m1 */ + <2 RK_PB0 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart1m1_ctsn: uart1m1-ctsn { + rockchip,pins = + /* uart1m1_ctsn */ + <2 RK_PB2 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart1m1_rtsn: uart1m1-rtsn { + rockchip,pins = + /* uart1m1_rtsn */ + <2 RK_PB3 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart1m2_xfer: uart1m2-xfer { + rockchip,pins = + /* uart1_rx_m2 */ + <3 RK_PA6 9 &pcfg_pull_up>, + /* uart1_tx_m2 */ + <3 RK_PA7 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart1m2_ctsn: uart1m2-ctsn { + rockchip,pins = + /* uart1m2_ctsn */ + <3 RK_PA4 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart1m2_rtsn: uart1m2-rtsn { + rockchip,pins = + /* uart1m2_rtsn */ + <3 RK_PA5 9 &pcfg_pull_none>; + }; + }; + + uart2 { + /omit-if-no-ref/ + uart2m0_xfer: uart2m0-xfer { + rockchip,pins = + /* uart2_rx_m0 */ + <1 RK_PC7 9 &pcfg_pull_up>, + /* uart2_tx_m0 */ + <1 RK_PC6 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart2m0_ctsn: uart2m0-ctsn { + rockchip,pins = + /* uart2m0_ctsn */ + <1 RK_PC5 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart2m0_rtsn: uart2m0-rtsn { + rockchip,pins = + /* uart2m0_rtsn */ + <1 RK_PC4 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart2m1_xfer: uart2m1-xfer { + rockchip,pins = + /* uart2_rx_m1 */ + <4 RK_PB4 10 &pcfg_pull_up>, + /* uart2_tx_m1 */ + <4 RK_PB5 10 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart2m1_ctsn: uart2m1-ctsn { + rockchip,pins = + /* uart2m1_ctsn */ + <4 RK_PB1 12 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart2m1_rtsn: uart2m1-rtsn { + rockchip,pins = + /* uart2m1_rtsn */ + <4 RK_PB0 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart2m2_xfer: uart2m2-xfer { + rockchip,pins = + /* uart2_rx_m2 */ + <3 RK_PB7 9 &pcfg_pull_up>, + /* uart2_tx_m2 */ + <3 RK_PC0 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart2m2_ctsn: uart2m2-ctsn { + rockchip,pins = + /* uart2m2_ctsn */ + <3 RK_PD3 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart2m2_rtsn: uart2m2-rtsn { + rockchip,pins = + /* uart2m2_rtsn */ + <3 RK_PD2 9 &pcfg_pull_none>; + }; + }; + + uart3 { + /omit-if-no-ref/ + uart3m0_xfer: uart3m0-xfer { + rockchip,pins = + /* uart3_rx_m0 */ + <3 RK_PA1 9 &pcfg_pull_up>, + /* uart3_tx_m0 */ + <3 RK_PA0 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart3m0_ctsn: uart3m0-ctsn { + rockchip,pins = + /* uart3m0_ctsn */ + <3 RK_PA2 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart3m0_rtsn: uart3m0-rtsn { + rockchip,pins = + /* uart3m0_rtsn */ + <3 RK_PA3 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart3m1_xfer: uart3m1-xfer { + rockchip,pins = + /* uart3_rx_m1 */ + <4 RK_PA1 9 &pcfg_pull_up>, + /* uart3_tx_m1 */ + <4 RK_PA0 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart3m1_ctsn: uart3m1-ctsn { + rockchip,pins = + /* uart3m1_ctsn */ + <3 RK_PB7 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart3m1_rtsn: uart3m1-rtsn { + rockchip,pins = + /* uart3m1_rtsn */ + <3 RK_PC0 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart3m2_xfer: uart3m2-xfer { + rockchip,pins = + /* uart3_rx_m2 */ + <1 RK_PC1 9 &pcfg_pull_up>, + /* uart3_tx_m2 */ + <1 RK_PC0 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart3m2_ctsn: uart3m2-ctsn { + rockchip,pins = + /* uart3m2_ctsn */ + <1 RK_PB6 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart3m2_rtsn: uart3m2-rtsn { + rockchip,pins = + /* uart3m2_rtsn */ + <1 RK_PB7 9 &pcfg_pull_none>; + }; + }; + + uart4 { + /omit-if-no-ref/ + uart4m0_xfer: uart4m0-xfer { + rockchip,pins = + /* uart4_rx_m0 */ + <2 RK_PD1 9 &pcfg_pull_up>, + /* uart4_tx_m0 */ + <2 RK_PD0 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart4m0_ctsn: uart4m0-ctsn { + rockchip,pins = + /* uart4m0_ctsn */ + <2 RK_PC6 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart4m0_rtsn: uart4m0-rtsn { + rockchip,pins = + /* uart4m0_rtsn */ + <2 RK_PC7 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart4m1_xfer: uart4m1-xfer { + rockchip,pins = + /* uart4_rx_m1 */ + <1 RK_PC5 9 &pcfg_pull_up>, + /* uart4_tx_m1 */ + <1 RK_PC4 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart4m1_ctsn: uart4m1-ctsn { + rockchip,pins = + /* uart4m1_ctsn */ + <1 RK_PC3 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart4m1_rtsn: uart4m1-rtsn { + rockchip,pins = + /* uart4m1_rtsn */ + <1 RK_PC2 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart4m2_xfer: uart4m2-xfer { + rockchip,pins = + /* uart4_rx_m2 */ + <0 RK_PB5 10 &pcfg_pull_up>, + /* uart4_tx_m2 */ + <0 RK_PB4 10 &pcfg_pull_up>; + }; + }; + + uart5 { + /omit-if-no-ref/ + uart5m0_xfer: uart5m0-xfer { + rockchip,pins = + /* uart5_rx_m0 */ + <3 RK_PD4 9 &pcfg_pull_up>, + /* uart5_tx_m0 */ + <3 RK_PD5 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart5m0_ctsn: uart5m0-ctsn { + rockchip,pins = + /* uart5m0_ctsn */ + <3 RK_PD6 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart5m0_rtsn: uart5m0-rtsn { + rockchip,pins = + /* uart5m0_rtsn */ + <3 RK_PD7 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart5m1_xfer: uart5m1-xfer { + rockchip,pins = + /* uart5_rx_m1 */ + <4 RK_PB1 10 &pcfg_pull_up>, + /* uart5_tx_m1 */ + <4 RK_PB0 10 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart5m1_ctsn: uart5m1-ctsn { + rockchip,pins = + /* uart5m1_ctsn */ + <4 RK_PA5 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart5m1_rtsn: uart5m1-rtsn { + rockchip,pins = + /* uart5m1_rtsn */ + <4 RK_PA3 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart5m2_xfer: uart5m2-xfer { + rockchip,pins = + /* uart5_rx_m2 */ + <2 RK_PA4 9 &pcfg_pull_up>, + /* uart5_tx_m2 */ + <2 RK_PA5 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart5m2_ctsn: uart5m2-ctsn { + rockchip,pins = + /* uart5m2_ctsn */ + <2 RK_PA3 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart5m2_rtsn: uart5m2-rtsn { + rockchip,pins = + /* uart5m2_rtsn */ + <2 RK_PA2 10 &pcfg_pull_none>; + }; + }; + + uart6 { + /omit-if-no-ref/ + uart6m0_xfer: uart6m0-xfer { + rockchip,pins = + /* uart6_rx_m0 */ + <4 RK_PA6 10 &pcfg_pull_up>, + /* uart6_tx_m0 */ + <4 RK_PA4 10 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart6m0_ctsn: uart6m0-ctsn { + rockchip,pins = + /* uart6m0_ctsn */ + <4 RK_PB1 11 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart6m0_rtsn: uart6m0-rtsn { + rockchip,pins = + /* uart6m0_rtsn */ + <4 RK_PB0 11 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart6m1_xfer: uart6m1-xfer { + rockchip,pins = + /* uart6_rx_m1 */ + <2 RK_PD3 9 &pcfg_pull_up>, + /* uart6_tx_m1 */ + <2 RK_PD2 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart6m1_ctsn: uart6m1-ctsn { + rockchip,pins = + /* uart6m1_ctsn */ + <2 RK_PD5 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart6m1_rtsn: uart6m1-rtsn { + rockchip,pins = + /* uart6m1_rtsn */ + <2 RK_PD4 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart6m2_xfer: uart6m2-xfer { + rockchip,pins = + /* uart6_rx_m2 */ + <1 RK_PB3 9 &pcfg_pull_up>, + /* uart6_tx_m2 */ + <1 RK_PB0 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart6m2_ctsn: uart6m2-ctsn { + rockchip,pins = + /* uart6m2_ctsn */ + <1 RK_PA3 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart6m2_rtsn: uart6m2-rtsn { + rockchip,pins = + /* uart6m2_rtsn */ + <1 RK_PA2 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart6m3_xfer: uart6m3-xfer { + rockchip,pins = + /* uart6_rx_m3 */ + <4 RK_PC5 13 &pcfg_pull_up>, + /* uart6_tx_m3 */ + <4 RK_PC4 13 &pcfg_pull_up>; + }; + }; + + uart7 { + /omit-if-no-ref/ + uart7m0_xfer: uart7m0-xfer { + rockchip,pins = + /* uart7_rx_m0 */ + <2 RK_PB7 9 &pcfg_pull_up>, + /* uart7_tx_m0 */ + <2 RK_PB6 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart7m0_ctsn: uart7m0-ctsn { + rockchip,pins = + /* uart7m0_ctsn */ + <2 RK_PB4 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart7m0_rtsn: uart7m0-rtsn { + rockchip,pins = + /* uart7m0_rtsn */ + <2 RK_PB5 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart7m1_xfer: uart7m1-xfer { + rockchip,pins = + /* uart7_rx_m1 */ + <1 RK_PA3 9 &pcfg_pull_up>, + /* uart7_tx_m1 */ + <1 RK_PA2 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart7m1_ctsn: uart7m1-ctsn { + rockchip,pins = + /* uart7m1_ctsn */ + <1 RK_PA1 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart7m1_rtsn: uart7m1-rtsn { + rockchip,pins = + /* uart7m1_rtsn */ + <1 RK_PA0 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart7m2_xfer: uart7m2-xfer { + rockchip,pins = + /* uart7_rx_m2 */ + <2 RK_PA0 10 &pcfg_pull_up>, + /* uart7_tx_m2 */ + <2 RK_PA1 10 &pcfg_pull_up>; + }; + }; + + uart8 { + /omit-if-no-ref/ + uart8m0_xfer: uart8m0-xfer { + rockchip,pins = + /* uart8_rx_m0 */ + <3 RK_PC5 9 &pcfg_pull_up>, + /* uart8_tx_m0 */ + <3 RK_PC6 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart8m0_ctsn: uart8m0-ctsn { + rockchip,pins = + /* uart8m0_ctsn */ + <3 RK_PD0 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart8m0_rtsn: uart8m0-rtsn { + rockchip,pins = + /* uart8m0_rtsn */ + <3 RK_PC7 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart8m1_xfer: uart8m1-xfer { + rockchip,pins = + /* uart8_rx_m1 */ + <2 RK_PA7 9 &pcfg_pull_up>, + /* uart8_tx_m1 */ + <2 RK_PA6 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart8m1_ctsn: uart8m1-ctsn { + rockchip,pins = + /* uart8m1_ctsn */ + <2 RK_PB7 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart8m1_rtsn: uart8m1-rtsn { + rockchip,pins = + /* uart8m1_rtsn */ + <2 RK_PB6 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart8m2_xfer: uart8m2-xfer { + rockchip,pins = + /* uart8_rx_m2 */ + <0 RK_PC2 10 &pcfg_pull_up>, + /* uart8_tx_m2 */ + <0 RK_PC1 10 &pcfg_pull_up>; + }; + }; + + uart9 { + /omit-if-no-ref/ + uart9m0_xfer: uart9m0-xfer { + rockchip,pins = + /* uart9_rx_m0 */ + <2 RK_PC0 9 &pcfg_pull_up>, + /* uart9_tx_m0 */ + <2 RK_PC1 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart9m0_ctsn: uart9m0-ctsn { + rockchip,pins = + /* uart9m0_ctsn */ + <2 RK_PD7 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart9m0_rtsn: uart9m0-rtsn { + rockchip,pins = + /* uart9m0_rtsn */ + <2 RK_PD6 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart9m1_xfer: uart9m1-xfer { + rockchip,pins = + /* uart9_rx_m1 */ + <3 RK_PB2 9 &pcfg_pull_up>, + /* uart9_tx_m1 */ + <3 RK_PB3 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart9m1_ctsn: uart9m1-ctsn { + rockchip,pins = + /* uart9m1_ctsn */ + <3 RK_PB5 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart9m1_rtsn: uart9m1-rtsn { + rockchip,pins = + /* uart9m1_rtsn */ + <3 RK_PB4 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart9m2_xfer: uart9m2-xfer { + rockchip,pins = + /* uart9_rx_m2 */ + <4 RK_PC3 13 &pcfg_pull_up>, + /* uart9_tx_m2 */ + <4 RK_PC2 13 &pcfg_pull_up>; + }; + }; + + uart10 { + /omit-if-no-ref/ + uart10m0_xfer: uart10m0-xfer { + rockchip,pins = + /* uart10_rx_m0 */ + <3 RK_PB0 9 &pcfg_pull_up>, + /* uart10_tx_m0 */ + <3 RK_PB1 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart10m0_ctsn: uart10m0-ctsn { + rockchip,pins = + /* uart10m0_ctsn */ + <3 RK_PA6 10 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart10m0_rtsn: uart10m0-rtsn { + rockchip,pins = + /* uart10m0_rtsn */ + <3 RK_PA7 10 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart10m1_xfer: uart10m1-xfer { + rockchip,pins = + /* uart10_rx_m1 */ + <1 RK_PD1 9 &pcfg_pull_up>, + /* uart10_tx_m1 */ + <1 RK_PD0 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart10m1_ctsn: uart10m1-ctsn { + rockchip,pins = + /* uart10m1_ctsn */ + <1 RK_PD5 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart10m1_rtsn: uart10m1-rtsn { + rockchip,pins = + /* uart10m1_rtsn */ + <1 RK_PD4 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart10m2_xfer: uart10m2-xfer { + rockchip,pins = + /* uart10_rx_m2 */ + <0 RK_PC5 10 &pcfg_pull_up>, + /* uart10_tx_m2 */ + <0 RK_PC4 10 &pcfg_pull_up>; + }; + }; + + uart11 { + /omit-if-no-ref/ + uart11m0_xfer: uart11m0-xfer { + rockchip,pins = + /* uart11_rx_m0 */ + <3 RK_PC1 9 &pcfg_pull_up>, + /* uart11_tx_m0 */ + <3 RK_PC4 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart11m0_ctsn: uart11m0-ctsn { + rockchip,pins = + /* uart11m0_ctsn */ + <3 RK_PC3 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart11m0_rtsn: uart11m0-rtsn { + rockchip,pins = + /* uart11m0_rtsn */ + <3 RK_PC2 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart11m1_xfer: uart11m1-xfer { + rockchip,pins = + /* uart11_rx_m1 */ + <2 RK_PC5 9 &pcfg_pull_up>, + /* uart11_tx_m1 */ + <2 RK_PC4 9 &pcfg_pull_up>; + }; + + /omit-if-no-ref/ + uart11m1_ctsn: uart11m1-ctsn { + rockchip,pins = + /* uart11m1_ctsn */ + <2 RK_PC2 9 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + uart11m1_rtsn: uart11m1-rtsn { + rockchip,pins = + /* uart11m1_rtsn */ + <2 RK_PC3 9 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + uart11m2_xfer: uart11m2-xfer { + rockchip,pins = + /* uart11_rx_m2 */ + <4 RK_PC1 13 &pcfg_pull_up>, + /* uart11_tx_m2 */ + <4 RK_PC0 13 &pcfg_pull_up>; + }; + }; + + ufs { + /omit-if-no-ref/ + ufs_refclk: ufs-refclk { + rockchip,pins = + /* ufs_refclk */ + <4 RK_PD1 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + ufs_rst: ufs-rst { + rockchip,pins = + /* ufs_rstn */ + <4 RK_PD0 1 &pcfg_pull_none>; + }; + }; + + ufs_testdata0 { + /omit-if-no-ref/ + ufs_testdata0_test: ufs_testdata0-test { + rockchip,pins = + /* ufs_testdata0_out */ + <4 RK_PC4 4 &pcfg_pull_none>; + }; + }; + + ufs_testdata1 { + /omit-if-no-ref/ + ufs_testdata1_test: ufs_testdata1-test { + rockchip,pins = + /* ufs_testdata1_out */ + <4 RK_PC5 4 &pcfg_pull_none>; + }; + }; + + ufs_testdata2 { + /omit-if-no-ref/ + ufs_testdata2_test: ufs_testdata2-test { + rockchip,pins = + /* ufs_testdata2_out */ + <4 RK_PC6 4 &pcfg_pull_none>; + }; + }; + + ufs_testdata3 { + /omit-if-no-ref/ + ufs_testdata3_test: ufs_testdata3-test { + rockchip,pins = + /* ufs_testdata3_out */ + <4 RK_PC7 4 &pcfg_pull_none>; + }; + }; + + vi_cif { + /omit-if-no-ref/ + vi_cif_pins: vi_cif-pins { + rockchip,pins = + /* vi_cif_clki */ + <3 RK_PA3 1 &pcfg_pull_none>, + /* vi_cif_clko */ + <3 RK_PA2 1 &pcfg_pull_none>, + /* vi_cif_d0 */ + <2 RK_PC5 1 &pcfg_pull_none>, + /* vi_cif_d1 */ + <2 RK_PC4 1 &pcfg_pull_none>, + /* vi_cif_d2 */ + <2 RK_PC3 1 &pcfg_pull_none>, + /* vi_cif_d3 */ + <2 RK_PC2 1 &pcfg_pull_none>, + /* vi_cif_d4 */ + <2 RK_PC1 1 &pcfg_pull_none>, + /* vi_cif_d5 */ + <2 RK_PC0 1 &pcfg_pull_none>, + /* vi_cif_d6 */ + <2 RK_PB7 1 &pcfg_pull_none>, + /* vi_cif_d7 */ + <2 RK_PB6 1 &pcfg_pull_none>, + /* vi_cif_d8 */ + <2 RK_PB5 1 &pcfg_pull_none>, + /* vi_cif_d9 */ + <2 RK_PB4 1 &pcfg_pull_none>, + /* vi_cif_d10 */ + <2 RK_PB3 1 &pcfg_pull_none>, + /* vi_cif_d11 */ + <2 RK_PB2 1 &pcfg_pull_none>, + /* vi_cif_d12 */ + <2 RK_PB1 1 &pcfg_pull_none>, + /* vi_cif_d13 */ + <2 RK_PB0 1 &pcfg_pull_none>, + /* vi_cif_d14 */ + <2 RK_PA7 1 &pcfg_pull_none>, + /* vi_cif_d15 */ + <2 RK_PA6 1 &pcfg_pull_none>, + /* vi_cif_href */ + <3 RK_PA0 1 &pcfg_pull_none>, + /* vi_cif_vsync */ + <3 RK_PA1 1 &pcfg_pull_none>; + }; + }; + + vo_lcdc { + /omit-if-no-ref/ + vo_lcdc_pins: vo_lcdc-pins { + rockchip,pins = + /* vo_lcdc_clk */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* vo_lcdc_d0 */ + <3 RK_PD3 1 &pcfg_pull_none>, + /* vo_lcdc_d1 */ + <3 RK_PD2 1 &pcfg_pull_none>, + /* vo_lcdc_d2 */ + <3 RK_PD1 1 &pcfg_pull_none>, + /* vo_lcdc_d3 */ + <3 RK_PD0 1 &pcfg_pull_none>, + /* vo_lcdc_d4 */ + <3 RK_PC7 1 &pcfg_pull_none>, + /* vo_lcdc_d5 */ + <3 RK_PC6 1 &pcfg_pull_none>, + /* vo_lcdc_d6 */ + <3 RK_PC5 1 &pcfg_pull_none>, + /* vo_lcdc_d7 */ + <3 RK_PC4 1 &pcfg_pull_none>, + /* vo_lcdc_d8 */ + <3 RK_PC3 1 &pcfg_pull_none>, + /* vo_lcdc_d9 */ + <3 RK_PC2 1 &pcfg_pull_none>, + /* vo_lcdc_d10 */ + <3 RK_PC1 1 &pcfg_pull_none>, + /* vo_lcdc_d11 */ + <3 RK_PC0 1 &pcfg_pull_none>, + /* vo_lcdc_d12 */ + <3 RK_PB7 1 &pcfg_pull_none>, + /* vo_lcdc_d13 */ + <3 RK_PB6 1 &pcfg_pull_none>, + /* vo_lcdc_d14 */ + <3 RK_PB5 1 &pcfg_pull_none>, + /* vo_lcdc_d15 */ + <3 RK_PB4 1 &pcfg_pull_none>, + /* vo_lcdc_d16 */ + <3 RK_PB3 1 &pcfg_pull_none>, + /* vo_lcdc_d17 */ + <3 RK_PB2 1 &pcfg_pull_none>, + /* vo_lcdc_d18 */ + <3 RK_PB1 1 &pcfg_pull_none>, + /* vo_lcdc_d19 */ + <3 RK_PB0 1 &pcfg_pull_none>, + /* vo_lcdc_d20 */ + <3 RK_PA7 1 &pcfg_pull_none>, + /* vo_lcdc_d21 */ + <3 RK_PA6 1 &pcfg_pull_none>, + /* vo_lcdc_d22 */ + <3 RK_PA5 1 &pcfg_pull_none>, + /* vo_lcdc_d23 */ + <3 RK_PA4 1 &pcfg_pull_none>, + /* vo_lcdc_den */ + <3 RK_PD4 1 &pcfg_pull_none>, + /* vo_lcdc_hsync */ + <3 RK_PD5 1 &pcfg_pull_none>, + /* vo_lcdc_vsync */ + <3 RK_PD6 1 &pcfg_pull_none>; + }; + }; + + vo_post { + /omit-if-no-ref/ + vo_post_pins: vo_post-pins { + rockchip,pins = + /* vo_post_empty */ + <4 RK_PA1 1 &pcfg_pull_none>; + }; + }; + + vp0_sync { + /omit-if-no-ref/ + vp0_sync_pins: vp0_sync-pins { + rockchip,pins = + /* vp0_sync_out */ + <4 RK_PC5 3 &pcfg_pull_none>; + }; + }; + + vp1_sync { + /omit-if-no-ref/ + vp1_sync_pins: vp1_sync-pins { + rockchip,pins = + /* vp1_sync_out */ + <4 RK_PC6 3 &pcfg_pull_none>; + }; + }; + + vp2_sync { + /omit-if-no-ref/ + vp2_sync_pins: vp2_sync-pins { + rockchip,pins = + /* vp2_sync_out */ + <4 RK_PC7 3 &pcfg_pull_none>; + }; + }; +}; + +/* + * This part is edited handly. + */ +&pinctrl { + pmic { + /omit-if-no-ref/ + pmic_pins: pmic-pins { + rockchip,pins = + /* pmic_int */ + <0 RK_PA6 9 &pcfg_pull_up>, + /* pmic_sleep */ + <0 RK_PA4 9 &pcfg_pull_none>; + }; + }; + + vo { + /omit-if-no-ref/ + bt1120_pins: bt1120-pins { + rockchip,pins = + /* vo_lcdc_clk */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* vo_lcdc_d3 */ + <3 RK_PD0 1 &pcfg_pull_none>, + /* vo_lcdc_d4 */ + <3 RK_PC7 1 &pcfg_pull_none>, + /* vo_lcdc_d5 */ + <3 RK_PC6 1 &pcfg_pull_none>, + /* vo_lcdc_d6 */ + <3 RK_PC5 1 &pcfg_pull_none>, + /* vo_lcdc_d7 */ + <3 RK_PC4 1 &pcfg_pull_none>, + /* vo_lcdc_d10 */ + <3 RK_PC1 1 &pcfg_pull_none>, + /* vo_lcdc_d11 */ + <3 RK_PC0 1 &pcfg_pull_none>, + /* vo_lcdc_d12 */ + <3 RK_PB7 1 &pcfg_pull_none>, + /* vo_lcdc_d13 */ + <3 RK_PB6 1 &pcfg_pull_none>, + /* vo_lcdc_d14 */ + <3 RK_PB5 1 &pcfg_pull_none>, + /* vo_lcdc_d15 */ + <3 RK_PB4 1 &pcfg_pull_none>, + /* vo_lcdc_d19 */ + <3 RK_PB0 1 &pcfg_pull_none>, + /* vo_lcdc_d20 */ + <3 RK_PA7 1 &pcfg_pull_none>, + /* vo_lcdc_d21 */ + <3 RK_PA6 1 &pcfg_pull_none>, + /* vo_lcdc_d22 */ + <3 RK_PA5 1 &pcfg_pull_none>, + /* vo_lcdc_d23 */ + <3 RK_PA4 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + bt656_pins: bt656-pins { + rockchip,pins = + /* vo_lcdc_clk */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* vo_lcdc_d3 */ + <3 RK_PD0 1 &pcfg_pull_none>, + /* vo_lcdc_d4 */ + <3 RK_PC7 1 &pcfg_pull_none>, + /* vo_lcdc_d5 */ + <3 RK_PC6 1 &pcfg_pull_none>, + /* vo_lcdc_d6 */ + <3 RK_PC5 1 &pcfg_pull_none>, + /* vo_lcdc_d7 */ + <3 RK_PC4 1 &pcfg_pull_none>, + /* vo_lcdc_d10 */ + <3 RK_PC1 1 &pcfg_pull_none>, + /* vo_lcdc_d11 */ + <3 RK_PC0 1 &pcfg_pull_none>, + /* vo_lcdc_d12 */ + <3 RK_PB7 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + rgb3x8_pins_m0: rgb3x8-pins-m0 { + rockchip,pins = + /* vo_lcdc_clk */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* vo_lcdc_d3 */ + <3 RK_PD0 1 &pcfg_pull_none>, + /* vo_lcdc_d4 */ + <3 RK_PC7 1 &pcfg_pull_none>, + /* vo_lcdc_d5 */ + <3 RK_PC6 1 &pcfg_pull_none>, + /* vo_lcdc_d6 */ + <3 RK_PC5 1 &pcfg_pull_none>, + /* vo_lcdc_d7 */ + <3 RK_PC4 1 &pcfg_pull_none>, + /* vo_lcdc_d10 */ + <3 RK_PC1 1 &pcfg_pull_none>, + /* vo_lcdc_d11 */ + <3 RK_PC0 1 &pcfg_pull_none>, + /* vo_lcdc_d12 */ + <3 RK_PB7 1 &pcfg_pull_none>, + /* vo_lcdc_den */ + <3 RK_PD4 1 &pcfg_pull_none>, + /* vo_lcdc_hsync */ + <3 RK_PD5 1 &pcfg_pull_none>, + /* vo_lcdc_vsync */ + <3 RK_PD6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + rgb3x8_pins_m1: rgb3x8-pins-m1 { + rockchip,pins = + /* vo_lcdc_clk */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* vo_lcdc_d13 */ + <3 RK_PB6 1 &pcfg_pull_none>, + /* vo_lcdc_d14 */ + <3 RK_PB5 1 &pcfg_pull_none>, + /* vo_lcdc_d15 */ + <3 RK_PB4 1 &pcfg_pull_none>, + /* vo_lcdc_d19 */ + <3 RK_PB0 1 &pcfg_pull_none>, + /* vo_lcdc_d20 */ + <3 RK_PA7 1 &pcfg_pull_none>, + /* vo_lcdc_d21 */ + <3 RK_PA6 1 &pcfg_pull_none>, + /* vo_lcdc_d22 */ + <3 RK_PA5 1 &pcfg_pull_none>, + /* vo_lcdc_d23 */ + <3 RK_PA4 1 &pcfg_pull_none>, + /* vo_lcdc_den */ + <3 RK_PD4 1 &pcfg_pull_none>, + /* vo_lcdc_hsync */ + <3 RK_PD5 1 &pcfg_pull_none>, + /* vo_lcdc_vsync */ + <3 RK_PD6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + rgb565_pins: rgb565-pins { + rockchip,pins = + /* vo_lcdc_clk */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* vo_lcdc_d3 */ + <3 RK_PD0 1 &pcfg_pull_none>, + /* vo_lcdc_d4 */ + <3 RK_PC7 1 &pcfg_pull_none>, + /* vo_lcdc_d5 */ + <3 RK_PC6 1 &pcfg_pull_none>, + /* vo_lcdc_d6 */ + <3 RK_PC5 1 &pcfg_pull_none>, + /* vo_lcdc_d7 */ + <3 RK_PC4 1 &pcfg_pull_none>, + /* vo_lcdc_d10 */ + <3 RK_PC1 1 &pcfg_pull_none>, + /* vo_lcdc_d11 */ + <3 RK_PC0 1 &pcfg_pull_none>, + /* vo_lcdc_d12 */ + <3 RK_PB7 1 &pcfg_pull_none>, + /* vo_lcdc_d13 */ + <3 RK_PB6 1 &pcfg_pull_none>, + /* vo_lcdc_d14 */ + <3 RK_PB5 1 &pcfg_pull_none>, + /* vo_lcdc_d15 */ + <3 RK_PB4 1 &pcfg_pull_none>, + /* vo_lcdc_d19 */ + <3 RK_PB0 1 &pcfg_pull_none>, + /* vo_lcdc_d20 */ + <3 RK_PA7 1 &pcfg_pull_none>, + /* vo_lcdc_d21 */ + <3 RK_PA6 1 &pcfg_pull_none>, + /* vo_lcdc_d22 */ + <3 RK_PA5 1 &pcfg_pull_none>, + /* vo_lcdc_d23 */ + <3 RK_PA4 1 &pcfg_pull_none>, + /* vo_lcdc_den */ + <3 RK_PD4 1 &pcfg_pull_none>, + /* vo_lcdc_hsync */ + <3 RK_PD5 1 &pcfg_pull_none>, + /* vo_lcdc_vsync */ + <3 RK_PD6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + rgb666_pins: rgb666-pins { + rockchip,pins = + /* vo_lcdc_clk */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* vo_lcdc_d2 */ + <3 RK_PD1 1 &pcfg_pull_none>, + /* vo_lcdc_d3 */ + <3 RK_PD0 1 &pcfg_pull_none>, + /* vo_lcdc_d4 */ + <3 RK_PC7 1 &pcfg_pull_none>, + /* vo_lcdc_d5 */ + <3 RK_PC6 1 &pcfg_pull_none>, + /* vo_lcdc_d6 */ + <3 RK_PC5 1 &pcfg_pull_none>, + /* vo_lcdc_d7 */ + <3 RK_PC4 1 &pcfg_pull_none>, + /* vo_lcdc_d10 */ + <3 RK_PC1 1 &pcfg_pull_none>, + /* vo_lcdc_d11 */ + <3 RK_PC0 1 &pcfg_pull_none>, + /* vo_lcdc_d12 */ + <3 RK_PB7 1 &pcfg_pull_none>, + /* vo_lcdc_d13 */ + <3 RK_PB6 1 &pcfg_pull_none>, + /* vo_lcdc_d14 */ + <3 RK_PB5 1 &pcfg_pull_none>, + /* vo_lcdc_d15 */ + <3 RK_PB4 1 &pcfg_pull_none>, + /* vo_lcdc_d18 */ + <3 RK_PB1 1 &pcfg_pull_none>, + /* vo_lcdc_d19 */ + <3 RK_PB0 1 &pcfg_pull_none>, + /* vo_lcdc_d20 */ + <3 RK_PA7 1 &pcfg_pull_none>, + /* vo_lcdc_d21 */ + <3 RK_PA6 1 &pcfg_pull_none>, + /* vo_lcdc_d22 */ + <3 RK_PA5 1 &pcfg_pull_none>, + /* vo_lcdc_d23 */ + <3 RK_PA4 1 &pcfg_pull_none>, + /* vo_lcdc_den */ + <3 RK_PD4 1 &pcfg_pull_none>, + /* vo_lcdc_hsync */ + <3 RK_PD5 1 &pcfg_pull_none>, + /* vo_lcdc_vsync */ + <3 RK_PD6 1 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + rgb888_pins: rgb888-pins { + rockchip,pins = + /* vo_lcdc_clk */ + <3 RK_PD7 1 &pcfg_pull_none>, + /* vo_lcdc_d0 */ + <3 RK_PD3 1 &pcfg_pull_none>, + /* vo_lcdc_d1 */ + <3 RK_PD2 1 &pcfg_pull_none>, + /* vo_lcdc_d2 */ + <3 RK_PD1 1 &pcfg_pull_none>, + /* vo_lcdc_d3 */ + <3 RK_PD0 1 &pcfg_pull_none>, + /* vo_lcdc_d4 */ + <3 RK_PC7 1 &pcfg_pull_none>, + /* vo_lcdc_d5 */ + <3 RK_PC6 1 &pcfg_pull_none>, + /* vo_lcdc_d6 */ + <3 RK_PC5 1 &pcfg_pull_none>, + /* vo_lcdc_d7 */ + <3 RK_PC4 1 &pcfg_pull_none>, + /* vo_lcdc_d8 */ + <3 RK_PC3 1 &pcfg_pull_none>, + /* vo_lcdc_d9 */ + <3 RK_PC2 1 &pcfg_pull_none>, + /* vo_lcdc_d10 */ + <3 RK_PC1 1 &pcfg_pull_none>, + /* vo_lcdc_d11 */ + <3 RK_PC0 1 &pcfg_pull_none>, + /* vo_lcdc_d12 */ + <3 RK_PB7 1 &pcfg_pull_none>, + /* vo_lcdc_d13 */ + <3 RK_PB6 1 &pcfg_pull_none>, + /* vo_lcdc_d14 */ + <3 RK_PB5 1 &pcfg_pull_none>, + /* vo_lcdc_d15 */ + <3 RK_PB4 1 &pcfg_pull_none>, + /* vo_lcdc_d16 */ + <3 RK_PB3 1 &pcfg_pull_none>, + /* vo_lcdc_d17 */ + <3 RK_PB2 1 &pcfg_pull_none>, + /* vo_lcdc_d18 */ + <3 RK_PB1 1 &pcfg_pull_none>, + /* vo_lcdc_d19 */ + <3 RK_PB0 1 &pcfg_pull_none>, + /* vo_lcdc_d20 */ + <3 RK_PA7 1 &pcfg_pull_none>, + /* vo_lcdc_d21 */ + <3 RK_PA6 1 &pcfg_pull_none>, + /* vo_lcdc_d22 */ + <3 RK_PA5 1 &pcfg_pull_none>, + /* vo_lcdc_d23 */ + <3 RK_PA4 1 &pcfg_pull_none>, + /* vo_lcdc_den */ + <3 RK_PD4 1 &pcfg_pull_none>, + /* vo_lcdc_hsync */ + <3 RK_PD5 1 &pcfg_pull_none>, + /* vo_lcdc_vsync */ + <3 RK_PD6 1 &pcfg_pull_none>; + }; + }; + + vo_ebc { + /omit-if-no-ref/ + vo_ebc_pins: vo_ebc-pins { + rockchip,pins = + /* vo_ebc_gdclk */ + <3 RK_PD5 2 &pcfg_pull_none>, + /* vo_ebc_gdoe */ + <3 RK_PA6 2 &pcfg_pull_none>, + /* vo_ebc_gdsp */ + <3 RK_PA5 2 &pcfg_pull_none>, + /* vo_ebc_sdce0 */ + <3 RK_PB3 2 &pcfg_pull_none>, + /* vo_ebc_sdclk */ + <3 RK_PD6 2 &pcfg_pull_none>, + /* vo_ebc_sddo0 */ + <3 RK_PD3 2 &pcfg_pull_none>, + /* vo_ebc_sddo1 */ + <3 RK_PD2 2 &pcfg_pull_none>, + /* vo_ebc_sddo2 */ + <3 RK_PD1 2 &pcfg_pull_none>, + /* vo_ebc_sddo3 */ + <3 RK_PD0 2 &pcfg_pull_none>, + /* vo_ebc_sddo4 */ + <3 RK_PC7 2 &pcfg_pull_none>, + /* vo_ebc_sddo5 */ + <3 RK_PC6 2 &pcfg_pull_none>, + /* vo_ebc_sddo6 */ + <3 RK_PC5 2 &pcfg_pull_none>, + /* vo_ebc_sddo7 */ + <3 RK_PC4 2 &pcfg_pull_none>, + /* vo_ebc_sddo8 */ + <3 RK_PC3 2 &pcfg_pull_none>, + /* vo_ebc_sddo9 */ + <3 RK_PC2 2 &pcfg_pull_none>, + /* vo_ebc_sddo10 */ + <3 RK_PC1 2 &pcfg_pull_none>, + /* vo_ebc_sddo11 */ + <3 RK_PC0 2 &pcfg_pull_none>, + /* vo_ebc_sddo12 */ + <3 RK_PB7 2 &pcfg_pull_none>, + /* vo_ebc_sddo13 */ + <3 RK_PB6 2 &pcfg_pull_none>, + /* vo_ebc_sddo14 */ + <3 RK_PB5 2 &pcfg_pull_none>, + /* vo_ebc_sddo15 */ + <3 RK_PB4 2 &pcfg_pull_none>, + /* vo_ebc_sdle */ + <3 RK_PD4 2 &pcfg_pull_none>, + /* vo_ebc_sdoe */ + <3 RK_PD7 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + vo_ebc_extern: vo_ebc-extern { + rockchip,pins = + /* vo_ebc_sdce1 */ + <3 RK_PB2 2 &pcfg_pull_none>, + /* vo_ebc_sdce2 */ + <3 RK_PB1 2 &pcfg_pull_none>, + /* vo_ebc_sdce3 */ + <3 RK_PB0 2 &pcfg_pull_none>, + /* vo_ebc_sdshr */ + <3 RK_PA4 2 &pcfg_pull_none>, + /* vo_ebc_vcom */ + <3 RK_PA7 2 &pcfg_pull_none>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi new file mode 100644 index 00000000000000..436232ffe4d1c7 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -0,0 +1,1678 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + compatible = "rockchip,rk3576"; + + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + i2c7 = &i2c7; + i2c8 = &i2c8; + i2c9 = &i2c9; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; + serial8 = &uart8; + serial9 = &uart9; + serial10 = &uart10; + serial11 = &uart11; + spi0 = &spi0; + spi1 = &spi1; + spi2 = &spi2; + spi3 = &spi3; + spi4 = &spi4; + }; + + xin32k: clock-xin32k { + compatible = "fixed-clock"; + clock-frequency = <32768>; + clock-output-names = "xin32k"; + #clock-cells = <0>; + }; + + xin24m: clock-xin24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + clock-output-names = "xin24m"; + }; + + spll: clock-spll { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <702000000>; + clock-output-names = "spll"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu_l0>; + }; + core1 { + cpu = <&cpu_l1>; + }; + core2 { + cpu = <&cpu_l2>; + }; + core3 { + cpu = <&cpu_l3>; + }; + }; + cluster1 { + core0 { + cpu = <&cpu_b0>; + }; + core1 { + cpu = <&cpu_b1>; + }; + core2 { + cpu = <&cpu_b2>; + }; + core3 { + cpu = <&cpu_b3>; + }; + }; + }; + + cpu_l0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x0>; + enable-method = "psci"; + capacity-dmips-mhz = <485>; + clocks = <&scmi_clk ARMCLK_L>; + operating-points-v2 = <&cluster0_opp_table>; + #cooling-cells = <2>; + dynamic-power-coefficient = <120>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu_l1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1>; + enable-method = "psci"; + capacity-dmips-mhz = <485>; + clocks = <&scmi_clk ARMCLK_L>; + operating-points-v2 = <&cluster0_opp_table>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu_l2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x2>; + enable-method = "psci"; + capacity-dmips-mhz = <485>; + clocks = <&scmi_clk ARMCLK_L>; + operating-points-v2 = <&cluster0_opp_table>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu_l3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x3>; + enable-method = "psci"; + capacity-dmips-mhz = <485>; + clocks = <&scmi_clk ARMCLK_L>; + operating-points-v2 = <&cluster0_opp_table>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu_b0: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x100>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + clocks = <&scmi_clk ARMCLK_B>; + operating-points-v2 = <&cluster1_opp_table>; + #cooling-cells = <2>; + dynamic-power-coefficient = <320>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu_b1: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x101>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + clocks = <&scmi_clk ARMCLK_B>; + operating-points-v2 = <&cluster1_opp_table>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu_b2: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x102>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + clocks = <&scmi_clk ARMCLK_B>; + operating-points-v2 = <&cluster1_opp_table>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu_b3: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a72"; + reg = <0x103>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + clocks = <&scmi_clk ARMCLK_B>; + operating-points-v2 = <&cluster1_opp_table>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + idle-states { + entry-method = "psci"; + + CPU_SLEEP: cpu-sleep { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010000>; + entry-latency-us = <120>; + exit-latency-us = <250>; + min-residency-us = <900>; + local-timer-stop; + }; + }; + }; + + cluster0_opp_table: opp-table-cluster0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-1008000000 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-1416000000 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <725000 725000 950000>; + clock-latency-ns = <40000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <750000 750000 950000>; + clock-latency-ns = <40000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <825000 825000 950000>; + clock-latency-ns = <40000>; + opp-suspend; + }; + + opp-2016000000 { + opp-hz = /bits/ 64 <2016000000>; + opp-microvolt = <900000 900000 950000>; + clock-latency-ns = <40000>; + }; + + opp-2208000000 { + opp-hz = /bits/ 64 <2208000000>; + opp-microvolt = <950000 950000 950000>; + clock-latency-ns = <40000>; + }; + }; + + cluster1_opp_table: opp-table-cluster1 { + compatible = "operating-points-v2"; + opp-shared; + + opp-408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + opp-suspend; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-1008000000 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <700000 700000 950000>; + clock-latency-ns = <40000>; + }; + + opp-1416000000 { + opp-hz = /bits/ 64 <1416000000>; + opp-microvolt = <712500 712500 950000>; + clock-latency-ns = <40000>; + }; + + opp-1608000000 { + opp-hz = /bits/ 64 <1608000000>; + opp-microvolt = <737500 737500 950000>; + clock-latency-ns = <40000>; + }; + + opp-1800000000 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <800000 800000 950000>; + clock-latency-ns = <40000>; + }; + + opp-2016000000 { + opp-hz = /bits/ 64 <2016000000>; + opp-microvolt = <862500 862500 950000>; + clock-latency-ns = <40000>; + }; + + opp-2208000000 { + opp-hz = /bits/ 64 <2208000000>; + opp-microvolt = <925000 925000 950000>; + clock-latency-ns = <40000>; + }; + + opp-2304000000 { + opp-hz = /bits/ 64 <2304000000>; + opp-microvolt = <950000 950000 950000>; + clock-latency-ns = <40000>; + }; + }; + + gpu_opp_table: opp-table-gpu { + compatible = "operating-points-v2"; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <700000 700000 850000>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <700000 700000 850000>; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <700000 700000 850000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <700000 700000 850000>; + }; + + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <725000 725000 850000>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <775000 775000 850000>; + }; + + opp-900000000 { + opp-hz = /bits/ 64 <900000000>; + opp-microvolt = <825000 825000 850000>; + }; + + opp-950000000 { + opp-hz = /bits/ 64 <950000000>; + opp-microvolt = <850000 850000 850000>; + }; + }; + + firmware { + scmi: scmi { + compatible = "arm,scmi-smc"; + arm,smc-id = <0x82000010>; + shmem = <&scmi_shmem>; + #address-cells = <1>; + #size-cells = <0>; + + scmi_clk: protocol@14 { + reg = <0x14>; + #clock-cells = <1>; + }; + }; + }; + + pmu_a53: pmu-a53 { + compatible = "arm,cortex-a53-pmu"; + interrupts = , + , + , + ; + interrupt-affinity = <&cpu_l0>, <&cpu_l1>, <&cpu_l2>, <&cpu_l3>; + }; + + pmu_a72: pmu-a72 { + compatible = "arm,cortex-a72-pmu"; + interrupts = , + , + , + ; + interrupt-affinity = <&cpu_b0>, <&cpu_b1>, <&cpu_b2>, <&cpu_b3>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + sys_grf: syscon@2600a000 { + compatible = "rockchip,rk3576-sys-grf", "syscon"; + reg = <0x0 0x2600a000 0x0 0x2000>; + }; + + bigcore_grf: syscon@2600c000 { + compatible = "rockchip,rk3576-bigcore-grf", "syscon"; + reg = <0x0 0x2600c000 0x0 0x2000>; + }; + + litcore_grf: syscon@2600e000 { + compatible = "rockchip,rk3576-litcore-grf", "syscon"; + reg = <0x0 0x2600e000 0x0 0x2000>; + }; + + cci_grf: syscon@26010000 { + compatible = "rockchip,rk3576-cci-grf", "syscon"; + reg = <0x0 0x26010000 0x0 0x2000>; + }; + + gpu_grf: syscon@26016000 { + compatible = "rockchip,rk3576-gpu-grf", "syscon"; + reg = <0x0 0x26016000 0x0 0x2000>; + }; + + npu_grf: syscon@26018000 { + compatible = "rockchip,rk3576-npu-grf", "syscon"; + reg = <0x0 0x26018000 0x0 0x2000>; + }; + + vo0_grf: syscon@2601a000 { + compatible = "rockchip,rk3576-vo0-grf", "syscon"; + reg = <0x0 0x2601a000 0x0 0x2000>; + }; + + usb_grf: syscon@2601e000 { + compatible = "rockchip,rk3576-usb-grf", "syscon"; + reg = <0x0 0x2601e000 0x0 0x1000>; + }; + + php_grf: syscon@26020000 { + compatible = "rockchip,rk3576-php-grf", "syscon"; + reg = <0x0 0x26020000 0x0 0x2000>; + }; + + pmu0_grf: syscon@26024000 { + compatible = "rockchip,rk3576-pmu0-grf", "syscon", "simple-mfd"; + reg = <0x0 0x26024000 0x0 0x1000>; + }; + + pmu1_grf: syscon@26026000 { + compatible = "rockchip,rk3576-pmu1-grf", "syscon"; + reg = <0x0 0x26026000 0x0 0x1000>; + }; + + pipe_phy0_grf: syscon@26028000 { + compatible = "rockchip,rk3576-pipe-phy-grf", "syscon"; + reg = <0x0 0x26028000 0x0 0x2000>; + }; + + pipe_phy1_grf: syscon@2602a000 { + compatible = "rockchip,rk3576-pipe-phy-grf", "syscon"; + reg = <0x0 0x2602a000 0x0 0x2000>; + }; + + usbdpphy_grf: syscon@2602c000 { + compatible = "rockchip,rk3576-usbdpphy-grf", "syscon"; + reg = <0x0 0x2602c000 0x0 0x2000>; + }; + + sdgmac_grf: syscon@26038000 { + compatible = "rockchip,rk3576-sdgmac-grf", "syscon"; + reg = <0x0 0x26038000 0x0 0x1000>; + }; + + ioc_grf: syscon@26040000 { + compatible = "rockchip,rk3576-ioc-grf", "syscon", "simple-mfd"; + reg = <0x0 0x26040000 0x0 0xc000>; + }; + + cru: clock-controller@27200000 { + compatible = "rockchip,rk3576-cru"; + reg = <0x0 0x27200000 0x0 0x50000>; + #clock-cells = <1>; + #reset-cells = <1>; + + assigned-clocks = + <&cru CLK_AUDIO_FRAC_1_SRC>, + <&cru PLL_GPLL>, <&cru PLL_CPLL>, + <&cru PLL_AUPLL>, <&cru CLK_UART_FRAC_0>, + <&cru CLK_UART_FRAC_1>, <&cru CLK_UART_FRAC_2>, + <&cru CLK_AUDIO_FRAC_0>, <&cru CLK_AUDIO_FRAC_1>, + <&cru CLK_CPLL_DIV2>, <&cru CLK_CPLL_DIV4>, + <&cru CLK_CPLL_DIV10>, <&cru FCLK_DDR_CM0_CORE>, + <&cru ACLK_PHP_ROOT>; + assigned-clock-parents = <&cru PLL_AUPLL>; + assigned-clock-rates = + <0>, + <1188000000>, <1000000000>, + <786432000>, <18432000>, + <96000000>, <128000000>, + <45158400>, <49152000>, + <500000000>, <250000000>, + <100000000>, <500000000>, + <250000000>; + }; + + i2c0: i2c@27300000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x27300000 0x0 0x1000>; + clocks = <&cru CLK_I2C0>, <&cru PCLK_I2C0>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c0m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart1: serial@27310000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x27310000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 8>, <&dmac0 9>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&uart1m0_xfer>; + status = "disabled"; + }; + + pmu: power-management@27380000 { + compatible = "rockchip,rk3576-pmu", "syscon", "simple-mfd"; + reg = <0x0 0x27380000 0x0 0x800>; + + power: power-controller { + compatible = "rockchip,rk3576-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3576_PD_NPU { + reg = ; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3576_PD_NPUTOP { + reg = ; + clocks = <&cru ACLK_RKNN0>, + <&cru ACLK_RKNN1>, + <&cru ACLK_RKNN_CBUF>, + <&cru CLK_RKNN_DSU0>, + <&cru HCLK_RKNN_CBUF>, + <&cru HCLK_RKNN_ROOT>, + <&cru HCLK_NPU_CM0_ROOT>, + <&cru PCLK_NPUTOP_ROOT>; + pm_qos = <&qos_npu_mcu>, + <&qos_npu_nsp0>, + <&qos_npu_nsp1>, + <&qos_npu_m0ro>, + <&qos_npu_m1ro>; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3576_PD_NPU0 { + reg = ; + clocks = <&cru HCLK_RKNN_ROOT>, + <&cru ACLK_RKNN0>; + pm_qos = <&qos_npu_m0>; + #power-domain-cells = <0>; + }; + power-domain@RK3576_PD_NPU1 { + reg = ; + clocks = <&cru HCLK_RKNN_ROOT>, + <&cru ACLK_RKNN1>; + pm_qos = <&qos_npu_m1>; + #power-domain-cells = <0>; + }; + }; + }; + + power-domain@RK3576_PD_GPU { + reg = ; + clocks = <&cru CLK_GPU>, <&cru PCLK_GPU_ROOT>; + pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; + }; + + power-domain@RK3576_PD_NVM { + reg = ; + clocks = <&cru ACLK_EMMC>, <&cru HCLK_EMMC>; + pm_qos = <&qos_emmc>, + <&qos_fspi0>; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3576_PD_SDGMAC { + reg = ; + clocks = <&cru ACLK_HSGPIO>, + <&cru ACLK_GMAC0>, + <&cru ACLK_GMAC1>, + <&cru CCLK_SRC_SDIO>, + <&cru CCLK_SRC_SDMMC0>, + <&cru HCLK_HSGPIO>, + <&cru HCLK_SDIO>, + <&cru HCLK_SDMMC0>, + <&cru PCLK_SDGMAC_ROOT>; + pm_qos = <&qos_fspi1>, + <&qos_gmac0>, + <&qos_gmac1>, + <&qos_sdio>, + <&qos_sdmmc>, + <&qos_flexbus>; + #power-domain-cells = <0>; + }; + }; + + power-domain@RK3576_PD_PHP { + reg = ; + clocks = <&cru ACLK_PHP_ROOT>, + <&cru PCLK_PHP_ROOT>, + <&cru ACLK_MMU0>, + <&cru ACLK_MMU1>; + pm_qos = <&qos_mmu0>, + <&qos_mmu1>; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3576_PD_SUBPHP { + reg = ; + #power-domain-cells = <0>; + }; + }; + + power-domain@RK3576_PD_AUDIO { + reg = ; + #power-domain-cells = <0>; + }; + + power-domain@RK3576_PD_VEPU1 { + reg = ; + clocks = <&cru ACLK_VEPU1>, + <&cru HCLK_VEPU1>; + pm_qos = <&qos_vepu1>; + #power-domain-cells = <0>; + }; + + power-domain@RK3576_PD_VPU { + reg = ; + clocks = <&cru ACLK_EBC>, + <&cru HCLK_EBC>, + <&cru ACLK_JPEG>, + <&cru HCLK_JPEG>, + <&cru ACLK_RGA2E_0>, + <&cru HCLK_RGA2E_0>, + <&cru ACLK_RGA2E_1>, + <&cru HCLK_RGA2E_1>, + <&cru ACLK_VDPP>, + <&cru HCLK_VDPP>; + pm_qos = <&qos_ebc>, + <&qos_jpeg>, + <&qos_rga0>, + <&qos_rga1>, + <&qos_vdpp>; + #power-domain-cells = <0>; + }; + + power-domain@RK3576_PD_VDEC { + reg = ; + clocks = <&cru ACLK_RKVDEC_ROOT>, + <&cru HCLK_RKVDEC>; + pm_qos = <&qos_rkvdec>; + #power-domain-cells = <0>; + }; + + power-domain@RK3576_PD_VI { + reg = ; + clocks = <&cru ACLK_VICAP>, + <&cru HCLK_VICAP>, + <&cru DCLK_VICAP>, + <&cru ACLK_VI_ROOT>, + <&cru HCLK_VI_ROOT>, + <&cru PCLK_VI_ROOT>, + <&cru CLK_ISP_CORE>, + <&cru ACLK_ISP>, + <&cru HCLK_ISP>, + <&cru CLK_CORE_VPSS>, + <&cru ACLK_VPSS>, + <&cru HCLK_VPSS>; + pm_qos = <&qos_isp_mro>, + <&qos_isp_mwo>, + <&qos_vicap_m0>, + <&qos_vpss_mro>, + <&qos_vpss_mwo>; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3576_PD_VEPU0 { + reg = ; + clocks = <&cru ACLK_VEPU0>, + <&cru HCLK_VEPU0>; + pm_qos = <&qos_vepu0>; + #power-domain-cells = <0>; + }; + }; + + power-domain@RK3576_PD_VOP { + reg = ; + clocks = <&cru ACLK_VOP>, + <&cru HCLK_VOP>, + <&cru HCLK_VOP_ROOT>, + <&cru PCLK_VOP_ROOT>; + pm_qos = <&qos_vop_m0>, + <&qos_vop_m1ro>; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3576_PD_USB { + reg = ; + clocks = <&cru PCLK_PHP_ROOT>, + <&cru ACLK_USB_ROOT>, + <&cru ACLK_MMU2>, + <&cru ACLK_SLV_MMU2>, + <&cru ACLK_UFS_SYS>; + pm_qos = <&qos_mmu2>, + <&qos_ufshc>; + #power-domain-cells = <0>; + }; + + power-domain@RK3576_PD_VO0 { + reg = ; + clocks = <&cru ACLK_HDCP0>, + <&cru HCLK_HDCP0>, + <&cru ACLK_VO0_ROOT>, + <&cru PCLK_VO0_ROOT>, + <&cru HCLK_VOP_ROOT>; + pm_qos = <&qos_hdcp0>; + #power-domain-cells = <0>; + }; + + power-domain@RK3576_PD_VO1 { + reg = ; + clocks = <&cru ACLK_HDCP1>, + <&cru HCLK_HDCP1>, + <&cru ACLK_VO1_ROOT>, + <&cru PCLK_VO1_ROOT>, + <&cru HCLK_VOP_ROOT>; + pm_qos = <&qos_hdcp1>; + #power-domain-cells = <0>; + }; + }; + }; + }; + + gpu: gpu@27800000 { + compatible = "rockchip,rk3576-mali", "arm,mali-bifrost"; + reg = <0x0 0x27800000 0x0 0x200000>; + assigned-clocks = <&scmi_clk CLK_GPU>; + assigned-clock-rates = <198000000>; + clocks = <&cru CLK_GPU>; + clock-names = "core"; + dynamic-power-coefficient = <1625>; + interrupts = , + , + ; + interrupt-names = "job", "mmu", "gpu"; + operating-points-v2 = <&gpu_opp_table>; + power-domains = <&power RK3576_PD_GPU>; + #cooling-cells = <2>; + status = "disabled"; + }; + + qos_hdcp1: qos@27f02000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f02000 0x0 0x20>; + }; + + qos_fspi1: qos@27f04000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f04000 0x0 0x20>; + }; + + qos_gmac0: qos@27f04080 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f04080 0x0 0x20>; + }; + + qos_gmac1: qos@27f04100 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f04100 0x0 0x20>; + }; + + qos_sdio: qos@27f04180 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f04180 0x0 0x20>; + }; + + qos_sdmmc: qos@27f04200 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f04200 0x0 0x20>; + }; + + qos_flexbus: qos@27f04280 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f04280 0x0 0x20>; + }; + + qos_gpu: qos@27f05000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f05000 0x0 0x20>; + }; + + qos_vepu1: qos@27f06000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f06000 0x0 0x20>; + }; + + qos_npu_mcu: qos@27f08000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f08000 0x0 0x20>; + }; + + qos_npu_nsp0: qos@27f08080 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f08080 0x0 0x20>; + }; + + qos_npu_nsp1: qos@27f08100 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f08100 0x0 0x20>; + }; + + qos_emmc: qos@27f09000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f09000 0x0 0x20>; + }; + + qos_fspi0: qos@27f09080 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f09080 0x0 0x20>; + }; + + qos_mmu0: qos@27f0a000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f0a000 0x0 0x20>; + }; + + qos_mmu1: qos@27f0a080 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f0a080 0x0 0x20>; + }; + + qos_rkvdec: qos@27f0c000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f0c000 0x0 0x20>; + }; + + qos_crypto: qos@27f0d000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f0d000 0x0 0x20>; + }; + + qos_mmu2: qos@27f0e000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f0e000 0x0 0x20>; + }; + + qos_ufshc: qos@27f0e080 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f0e080 0x0 0x20>; + }; + + qos_vepu0: qos@27f0f000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f0f000 0x0 0x20>; + }; + + qos_isp_mro: qos@27f10000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f10000 0x0 0x20>; + }; + + qos_isp_mwo: qos@27f10080 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f10080 0x0 0x20>; + }; + + qos_vicap_m0: qos@27f10100 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f10100 0x0 0x20>; + }; + + qos_vpss_mro: qos@27f10180 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f10180 0x0 0x20>; + }; + + qos_vpss_mwo: qos@27f10200 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f10200 0x0 0x20>; + }; + + qos_hdcp0: qos@27f11000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f11000 0x0 0x20>; + }; + + qos_vop_m0: qos@27f12800 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f12800 0x0 0x20>; + }; + + qos_vop_m1ro: qos@27f12880 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f12880 0x0 0x20>; + }; + + qos_ebc: qos@27f13000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f13000 0x0 0x20>; + }; + + qos_rga0: qos@27f13080 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f13080 0x0 0x20>; + }; + + qos_rga1: qos@27f13100 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f13100 0x0 0x20>; + }; + + qos_jpeg: qos@27f13180 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f13180 0x0 0x20>; + }; + + qos_vdpp: qos@27f13200 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f13200 0x0 0x20>; + }; + + qos_npu_m0: qos@27f20000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f20000 0x0 0x20>; + }; + + qos_npu_m1: qos@27f21000 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f21000 0x0 0x20>; + }; + + qos_npu_m0ro: qos@27f22080 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f22080 0x0 0x20>; + }; + + qos_npu_m1ro: qos@27f22100 { + compatible = "rockchip,rk3576-qos", "syscon"; + reg = <0x0 0x27f22100 0x0 0x20>; + }; + + gmac0: ethernet@2a220000 { + compatible = "rockchip,rk3576-gmac", "snps,dwmac-4.20a"; + reg = <0x0 0x2a220000 0x0 0x10000>; + clocks = <&cru CLK_GMAC0_125M_SRC>, <&cru CLK_GMAC0_RMII_CRU>, + <&cru PCLK_GMAC0>, <&cru ACLK_GMAC0>, + <&cru CLK_GMAC0_PTP_REF>; + clock-names = "stmmaceth", "clk_mac_ref", + "pclk_mac", "aclk_mac", + "ptp_ref"; + interrupts = , + ; + interrupt-names = "macirq", "eth_wake_irq"; + power-domains = <&power RK3576_PD_SDGMAC>; + resets = <&cru SRST_A_GMAC0>; + reset-names = "stmmaceth"; + rockchip,grf = <&sdgmac_grf>; + rockchip,php-grf = <&ioc_grf>; + snps,axi-config = <&gmac0_stmmac_axi_setup>; + snps,mixed-burst; + snps,mtl-rx-config = <&gmac0_mtl_rx_setup>; + snps,mtl-tx-config = <&gmac0_mtl_tx_setup>; + snps,tso; + status = "disabled"; + + mdio0: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + }; + + gmac0_stmmac_axi_setup: stmmac-axi-config { + snps,blen = <0 0 0 0 16 8 4>; + snps,rd_osr_lmt = <8>; + snps,wr_osr_lmt = <4>; + }; + + gmac0_mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <1>; + queue0 {}; + }; + + gmac0_mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <1>; + queue0 {}; + }; + }; + + gmac1: ethernet@2a230000 { + compatible = "rockchip,rk3576-gmac", "snps,dwmac-4.20a"; + reg = <0x0 0x2a230000 0x0 0x10000>; + clocks = <&cru CLK_GMAC1_125M_SRC>, <&cru CLK_GMAC1_RMII_CRU>, + <&cru PCLK_GMAC1>, <&cru ACLK_GMAC1>, + <&cru CLK_GMAC1_PTP_REF>; + clock-names = "stmmaceth", "clk_mac_ref", + "pclk_mac", "aclk_mac", + "ptp_ref"; + interrupts = , + ; + interrupt-names = "macirq", "eth_wake_irq"; + power-domains = <&power RK3576_PD_SDGMAC>; + resets = <&cru SRST_A_GMAC1>; + reset-names = "stmmaceth"; + rockchip,grf = <&sdgmac_grf>; + rockchip,php-grf = <&ioc_grf>; + snps,axi-config = <&gmac1_stmmac_axi_setup>; + snps,mixed-burst; + snps,mtl-rx-config = <&gmac1_mtl_rx_setup>; + snps,mtl-tx-config = <&gmac1_mtl_tx_setup>; + snps,tso; + status = "disabled"; + + mdio1: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + }; + + gmac1_stmmac_axi_setup: stmmac-axi-config { + snps,blen = <0 0 0 0 16 8 4>; + snps,rd_osr_lmt = <8>; + snps,wr_osr_lmt = <4>; + }; + + gmac1_mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <1>; + queue0 {}; + }; + + gmac1_mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <1>; + queue0 {}; + }; + }; + + sdmmc: mmc@2a310000 { + compatible = "rockchip,rk3576-dw-mshc"; + reg = <0x0 0x2a310000 0x0 0x4000>; + clocks = <&cru HCLK_SDMMC0>, <&cru CCLK_SRC_SDMMC0>; + clock-names = "biu", "ciu"; + fifo-depth = <0x100>; + interrupts = ; + max-frequency = <200000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4 &sdmmc0_pwren>; + power-domains = <&power RK3576_PD_SDGMAC>; + resets = <&cru SRST_H_SDMMC0>; + reset-names = "reset"; + status = "disabled"; + }; + + sdhci: mmc@2a330000 { + compatible = "rockchip,rk3576-dwcmshc", "rockchip,rk3588-dwcmshc"; + reg = <0x0 0x2a330000 0x0 0x10000>; + assigned-clocks = <&cru BCLK_EMMC>, <&cru TCLK_EMMC>, <&cru CCLK_SRC_EMMC>; + assigned-clock-rates = <200000000>, <24000000>, <200000000>; + clocks = <&cru CCLK_SRC_EMMC>, <&cru HCLK_EMMC>, + <&cru ACLK_EMMC>, <&cru BCLK_EMMC>, + <&cru TCLK_EMMC>; + clock-names = "core", "bus", "axi", "block", "timer"; + interrupts = ; + max-frequency = <200000000>; + pinctrl-0 = <&emmc_rstnout>, <&emmc_bus8>, <&emmc_clk>, + <&emmc_cmd>, <&emmc_strb>; + pinctrl-names = "default"; + power-domains = <&power RK3576_PD_NVM>; + resets = <&cru SRST_C_EMMC>, <&cru SRST_H_EMMC>, + <&cru SRST_A_EMMC>, <&cru SRST_B_EMMC>, + <&cru SRST_T_EMMC>; + reset-names = "core", "bus", "axi", "block", "timer"; + supports-cqe; + status = "disabled"; + }; + + gic: interrupt-controller@2a701000 { + compatible = "arm,gic-400"; + reg = <0x0 0x2a701000 0 0x10000>, + <0x0 0x2a702000 0 0x10000>, + <0x0 0x2a704000 0 0x10000>, + <0x0 0x2a706000 0 0x10000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + }; + + dmac0: dma-controller@2ab90000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0x2ab90000 0x0 0x4000>; + arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC0>; + clock-names = "apb_pclk"; + interrupts = , + ; + #dma-cells = <1>; + }; + + dmac1: dma-controller@2abb0000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0x2abb0000 0x0 0x4000>; + arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC1>; + clock-names = "apb_pclk"; + interrupts = , + ; + #dma-cells = <1>; + }; + + dmac2: dma-controller@2abd0000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0x2abd0000 0x0 0x4000>; + arm,pl330-periph-burst; + clocks = <&cru ACLK_DMAC2>; + clock-names = "apb_pclk"; + interrupts = , + ; + #dma-cells = <1>; + }; + + i2c1: i2c@2ac40000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2ac40000 0x0 0x1000>; + clocks = <&cru CLK_I2C1>, <&cru PCLK_I2C1>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c1m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@2ac50000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2ac50000 0x0 0x1000>; + clocks = <&cru CLK_I2C2>, <&cru PCLK_I2C2>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@2ac60000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2ac60000 0x0 0x1000>; + clocks = <&cru CLK_I2C3>, <&cru PCLK_I2C3>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c3m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@2ac70000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2ac70000 0x0 0x1000>; + clocks = <&cru CLK_I2C4>, <&cru PCLK_I2C4>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c4m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c5: i2c@2ac80000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2ac80000 0x0 0x1000>; + clocks = <&cru CLK_I2C5>, <&cru PCLK_I2C5>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c5m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + + i2c6: i2c@2ac90000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2ac90000 0x0 0x1000>; + clocks = <&cru CLK_I2C6>, <&cru PCLK_I2C6>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c6m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c7: i2c@2aca0000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2aca0000 0x0 0x1000>; + clocks = <&cru CLK_I2C7>, <&cru PCLK_I2C7>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c7m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c8: i2c@2acb0000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2acb0000 0x0 0x1000>; + clocks = <&cru CLK_I2C8>, <&cru PCLK_I2C8>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c8m0_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + timer0: timer@2acc0000 { + compatible = "rockchip,rk3576-timer", "rockchip,rk3288-timer"; + reg = <0x0 0x2acc0000 0x0 0x20>; + clocks = <&cru PCLK_BUSTIMER0>, <&cru CLK_TIMER0>; + clock-names = "pclk", "timer"; + interrupts = ; + }; + + wdt: watchdog@2ace0000 { + compatible = "rockchip,rk3576-wdt", "snps,dw-wdt"; + reg = <0x0 0x2ace0000 0x0 0x100>; + clocks = <&cru TCLK_WDT0>, <&cru PCLK_WDT0>; + clock-names = "tclk", "pclk"; + interrupts = ; + status = "disabled"; + }; + + spi0: spi@2acf0000 { + compatible = "rockchip,rk3576-spi", "rockchip,rk3066-spi"; + reg = <0x0 0x2acf0000 0x0 0x1000>; + clocks = <&cru CLK_SPI0>, <&cru PCLK_SPI0>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac0 14>, <&dmac0 15>; + dma-names = "tx", "rx"; + interrupts = ; + num-cs = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&spi0m0_csn0 &spi0m0_csn1 &spi0m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi1: spi@2ad00000 { + compatible = "rockchip,rk3576-spi", "rockchip,rk3066-spi"; + reg = <0x0 0x2ad00000 0x0 0x1000>; + clocks = <&cru CLK_SPI1>, <&cru PCLK_SPI1>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac0 16>, <&dmac0 17>; + dma-names = "tx", "rx"; + interrupts = ; + num-cs = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&spi1m0_csn0 &spi1m0_csn1 &spi1m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi2: spi@2ad10000 { + compatible = "rockchip,rk3576-spi", "rockchip,rk3066-spi"; + reg = <0x0 0x2ad10000 0x0 0x1000>; + clocks = <&cru CLK_SPI2>, <&cru PCLK_SPI2>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac1 15>, <&dmac1 16>; + dma-names = "tx", "rx"; + interrupts = ; + num-cs = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m0_csn0 &spi2m0_csn1 &spi2m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi3: spi@2ad20000 { + compatible = "rockchip,rk3576-spi", "rockchip,rk3066-spi"; + reg = <0x0 0x2ad20000 0x0 0x1000>; + clocks = <&cru CLK_SPI3>, <&cru PCLK_SPI3>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac1 17>, <&dmac1 18>; + dma-names = "tx", "rx"; + interrupts = ; + num-cs = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&spi3m0_csn0 &spi3m0_csn1 &spi3m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi4: spi@2ad30000 { + compatible = "rockchip,rk3576-spi", "rockchip,rk3066-spi"; + reg = <0x0 0x2ad30000 0x0 0x1000>; + clocks = <&cru CLK_SPI4>, <&cru PCLK_SPI4>; + clock-names = "spiclk", "apb_pclk"; + dmas = <&dmac2 12>, <&dmac2 13>; + dma-names = "tx", "rx"; + interrupts = ; + num-cs = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&spi4m0_csn0 &spi4m0_csn1 &spi4m0_pins>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart0: serial@2ad40000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2ad40000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 6>, <&dmac0 7>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-0 = <&uart0m0_xfer>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart2: serial@2ad50000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2ad50000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 10>, <&dmac0 11>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&uart2m0_xfer>; + status = "disabled"; + }; + + uart3: serial@2ad60000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2ad60000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART3>, <&cru PCLK_UART3>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac0 12>, <&dmac0 13>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-0 = <&uart3m0_xfer>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart4: serial@2ad70000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2ad70000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART4>, <&cru PCLK_UART4>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac1 9>, <&dmac1 10>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-0 = <&uart4m0_xfer>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart5: serial@2ad80000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2ad80000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART5>, <&cru PCLK_UART5>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac1 11>, <&dmac1 12>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-0 = <&uart5m0_xfer>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart6: serial@2ad90000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2ad90000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART6>, <&cru PCLK_UART6>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac1 13>, <&dmac1 14>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-0 = <&uart6m0_xfer>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart7: serial@2ada0000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2ada0000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART7>, <&cru PCLK_UART7>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac2 6>, <&dmac2 7>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-0 = <&uart7m0_xfer>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart8: serial@2adb0000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2adb0000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART8>, <&cru PCLK_UART8>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac2 8>, <&dmac2 9>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-0 = <&uart8m0_xfer>; + pinctrl-names = "default"; + status = "disabled"; + }; + + uart9: serial@2adc0000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2adc0000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART9>, <&cru PCLK_UART9>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac2 10>, <&dmac2 11>; + dma-names = "tx", "rx"; + interrupts = ; + pinctrl-0 = <&uart9m0_xfer>; + pinctrl-names = "default"; + status = "disabled"; + }; + + saradc: adc@2ae00000 { + compatible = "rockchip,rk3576-saradc", "rockchip,rk3588-saradc"; + reg = <0x0 0x2ae00000 0x0 0x10000>; + clocks = <&cru CLK_SARADC>, <&cru PCLK_SARADC>; + clock-names = "saradc", "apb_pclk"; + interrupts = ; + resets = <&cru SRST_P_SARADC>; + reset-names = "saradc-apb"; + #io-channel-cells = <1>; + status = "disabled"; + }; + + i2c9: i2c@2ae80000 { + compatible = "rockchip,rk3576-i2c", "rockchip,rk3399-i2c"; + reg = <0x0 0x2ae80000 0x0 0x1000>; + clocks = <&cru CLK_I2C9>, <&cru PCLK_I2C9>; + clock-names = "i2c", "pclk"; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2c9m0_xfer>; + resets = <&cru SRST_I2C9>, <&cru SRST_P_I2C9>; + reset-names = "i2c", "apb"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart10: serial@2afc0000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2afc0000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART10>, <&cru PCLK_UART10>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac2 21>, <&dmac2 22>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&uart10m0_xfer>; + status = "disabled"; + }; + + uart11: serial@2afd0000 { + compatible = "rockchip,rk3576-uart", "snps,dw-apb-uart"; + reg = <0x0 0x2afd0000 0x0 0x100>; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART11>, <&cru PCLK_UART11>; + clock-names = "baudclk", "apb_pclk"; + dmas = <&dmac2 23>, <&dmac2 24>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&uart11m0_xfer>; + status = "disabled"; + }; + + sram: sram@3ff88000 { + compatible = "mmio-sram"; + reg = <0x0 0x3ff88000 0x0 0x78000>; + ranges = <0x0 0x0 0x3ff88000 0x78000>; + #address-cells = <1>; + #size-cells = <1>; + + /* start address and size should be 4k align */ + rkvdec_sram: rkvdec-sram@0 { + reg = <0x0 0x78000>; + }; + }; + + scmi_shmem: scmi-shmem@4010f000 { + compatible = "arm,scmi-shmem"; + reg = <0x0 0x4010f000 0x0 0x100>; + }; + + pinctrl: pinctrl { + compatible = "rockchip,rk3576-pinctrl"; + rockchip,grf = <&ioc_grf>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gpio0: gpio@27320000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0x27320000 0x0 0x200>; + clocks = <&cru PCLK_GPIO0>, <&cru DBCLK_GPIO0>; + gpio-controller; + gpio-ranges = <&pinctrl 0 0 32>; + interrupts = ; + interrupt-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; + }; + + gpio1: gpio@2ae10000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0x2ae10000 0x0 0x200>; + clocks = <&cru PCLK_GPIO1>, <&cru DBCLK_GPIO1>; + gpio-controller; + gpio-ranges = <&pinctrl 0 32 32>; + interrupts = ; + interrupt-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; + }; + + gpio2: gpio@2ae20000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0x2ae20000 0x0 0x200>; + clocks = <&cru PCLK_GPIO2>, <&cru DBCLK_GPIO2>; + gpio-controller; + gpio-ranges = <&pinctrl 0 64 32>; + interrupts = ; + interrupt-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; + }; + + gpio3: gpio@2ae30000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0x2ae30000 0x0 0x200>; + clocks = <&cru PCLK_GPIO3>, <&cru DBCLK_GPIO3>; + gpio-controller; + gpio-ranges = <&pinctrl 0 96 32>; + interrupts = ; + interrupt-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; + }; + + gpio4: gpio@2ae40000 { + compatible = "rockchip,gpio-bank"; + reg = <0x0 0x2ae40000 0x0 0x200>; + clocks = <&cru PCLK_GPIO4>, <&cru DBCLK_GPIO4>; + gpio-controller; + gpio-ranges = <&pinctrl 0 128 32>; + interrupts = ; + interrupt-controller; + #gpio-cells = <2>; + #interrupt-cells = <2>; + }; + }; + }; +}; + +#include "rk3576-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/rockchip/rk3588-armsom-lm7.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-armsom-lm7.dtsi new file mode 100644 index 00000000000000..a3138d2d384c62 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-armsom-lm7.dtsi @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include "rk3588.dtsi" + +/ { + compatible = "armsom,lm7", "rockchip,rk3588"; + + aliases { + mmc0 = &sdhci; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + vcc5v0_sys: regulator-vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc5v0_sys>; + }; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_b3 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&saradc { + vref-supply = <&avcc_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + no-sdio; + no-sd; + non-removable; + status = "okay"; +}; + +&spi2 { + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + status = "okay"; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0x0>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + system-power-controller; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc5v0_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc5v0_sys>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcc5v0_sys>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 { + regulator-name = "vdd_gpu_s0"; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 { + regulator-name = "vdd_cpu_lit_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_log_s0: dcdc-reg3 { + regulator-name = "vdd_log_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 { + regulator-name = "vdd_vdenc_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-name = "vdd_ddr_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg6 { + regulator-name = "vdd2_ddr_s3"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-name = "vdd_2v0_pldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-name = "vcc_3v3_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-name = "vddq_ddr_s0"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg10 { + regulator-name = "vcc_1v8_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avcc_1v8_s0: pldo-reg1 { + regulator-name = "avcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s0: pldo-reg2 { + regulator-name = "vcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avdd_1v2_s0: pldo-reg3 { + regulator-name = "avdd_1v2_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3_s0: pldo-reg4 { + regulator-name = "vcc_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-name = "vccio_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-name = "pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-name = "vdd_0v75_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_ddr_pll_s0: nldo-reg2 { + regulator-name = "vdd_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + avdd_0v75_s0: nldo-reg3 { + regulator-name = "avdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v85_s0: nldo-reg4 { + regulator-name = "vdd_0v85_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-name = "vdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts index c667704ba985e4..08f09053a06646 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-armsom-sige7.dts @@ -23,7 +23,7 @@ analog-sound { compatible = "audio-graph-card"; dais = <&i2s0_8ch_p0>; label = "rk3588-es8316"; - hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; + hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&hp_detect>; routing = "MIC2", "Mic Jack", @@ -61,7 +61,7 @@ fan: pwm-fan { #cooling-cells = <2>; }; - vcc3v3_pcie2x1l2: vcc3v3-pcie2x1l2-regulator { + vcc3v3_pcie2x1l2: regulator-vcc3v3-pcie2x1l2 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie2x1l2"; regulator-min-microvolt = <3300000>; @@ -70,7 +70,7 @@ vcc3v3_pcie2x1l2: vcc3v3-pcie2x1l2-regulator { vin-supply = <&vcc_3v3_s3>; }; - vcc3v3_pcie30: vcc3v3-pcie30-regulator { + vcc3v3_pcie30: regulator-vcc3v3-pcie30 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>; @@ -81,7 +81,7 @@ vcc3v3_pcie30: vcc3v3-pcie30-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; regulator-boot-on; @@ -95,7 +95,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -104,7 +104,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { regulator-max-microvolt = <5000000>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-armsom-w3.dts b/arch/arm64/boot/dts/rockchip/rk3588-armsom-w3.dts new file mode 100644 index 00000000000000..779cd1b1798ce0 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-armsom-w3.dts @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include "rk3588-armsom-lm7.dtsi" + +/ { + model = "ArmSoM W3"; + compatible = "armsom,w3", "armsom,lm7", "rockchip,rk3588"; + + aliases { + mmc1 = &sdmmc; + mmc2 = &sdio; + }; + + analog-sound { + compatible = "audio-graph-card"; + label = "rk3588-es8316"; + + widgets = "Microphone", "Mic Jack", + "Headphone", "Headphones"; + + routing = "MIC2", "Mic Jack", + "Headphones", "HPOL", + "Headphones", "HPOR"; + + dais = <&i2s0_8ch_p0>; + hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&hp_detect>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_rgb_b>; + + led-rgb-b { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + led-rgb-r { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&gpio4 RK_PC5 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "none"; + }; + }; + + fan: pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <0 120 150 180 210 240 255>; + fan-supply = <&vcc5v0_sys>; + pwms = <&pwm1 0 50000 0>; + #cooling-cells = <2>; + }; + + rfkill { + compatible = "rfkill-gpio"; + label = "rfkill-pcie-wlan"; + radio-type = "wlan"; + shutdown-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; + }; + + rfkill-bt { + compatible = "rfkill-gpio"; + label = "rfkill-m2-bt"; + radio-type = "bluetooth"; + shutdown-gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_HIGH>; + }; + + vcc3v3_pcie2x1l0: regulator-vcc3v3-pcie2x1l0 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_0_vcc3v3_en>; + regulator-name = "vcc3v3_pcie2x1l0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <50000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc3v3_pcie2x1l2: regulator-vcc3v3-pcie2x1l2 { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_pcie2x1l2"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <5000>; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc3v3_pcie30: regulator-vcc3v3-pcie30 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie3_vcc3v3_en>; + regulator-name = "vcc3v3_pcie30"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <5000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_host: regulator-vcc5v0-host { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_host"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + enable-active-high; + gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_host_en>; + vin-supply = <&vcc5v0_sys>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy1_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +&i2c6 { + status = "okay"; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "hym8563"; + pinctrl-names = "default"; + pinctrl-0 = <&hym8563_int>; + interrupt-parent = <&gpio0>; + interrupts = ; + wakeup-source; + }; +}; + +&i2c7 { + status = "okay"; + + es8316: audio-codec@11 { + compatible = "everest,es8316"; + reg = <0x11>; + clocks = <&cru I2S0_8CH_MCLKOUT>; + clock-names = "mclk"; + assigned-clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clock-rates = <12288000>; + #sound-dai-cells = <0>; + + port { + es8316_p0_0: endpoint { + remote-endpoint = <&i2s0_8ch_p0_0>; + }; + }; + }; +}; + +&i2s0_8ch { + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_lrck + &i2s0_mclk + &i2s0_sclk + &i2s0_sdi0 + &i2s0_sdo0>; + status = "okay"; + + i2s0_8ch_p0: port { + i2s0_8ch_p0_0: endpoint { + dai-format = "i2s"; + mclk-fs = <256>; + remote-endpoint = <&es8316_p0_0>; + }; + }; +}; + +&package_thermal { + polling-delay = <1000>; + + trips { + package_fan0: package-fan0 { + temperature = <55000>; + hysteresis = <2000>; + type = "active"; + }; + + package_fan1: package-fan1 { + temperature = <65000>; + hysteresis = <2000>; + type = "active"; + }; + }; + + cooling-maps { + map0 { + trip = <&package_fan0>; + cooling-device = <&fan THERMAL_NO_LIMIT 1>; + }; + + map1 { + trip = <&package_fan1>; + cooling-device = <&fan 2 THERMAL_NO_LIMIT>; + }; + }; +}; + +&pcie2x1l0 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_0_rst>; + reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_pcie2x1l0>; + status = "okay"; +}; + +&pcie2x1l2 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_2_rst>; + reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_pcie2x1l2>; + status = "okay"; +}; + +&pcie30phy { + status = "okay"; +}; + +&pcie3x4 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie3_rst>; + reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_pcie30>; + status = "okay"; +}; + +&pinctrl { + hym8563 { + hym8563_int: hym8563-int { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + leds { + led_rgb_b: led-rgb-b { + rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sound { + hp_detect: hp-detect { + rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pcie2 { + pcie2_0_rst: pcie2-0-rst { + rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + pcie2_0_vcc3v3_en: pcie2-0-vcc-en { + rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + pcie2_2_rst: pcie2-2-rst { + rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pcie3 { + pcie3_rst: pcie3-rst { + rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + pcie3_vcc3v3_en: pcie3-vcc3v3-en { + rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + vcc5v0_host_en: vcc5v0-host-en { + rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm1 { + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; + disable-wp; + max-frequency = <200000000>; + no-sdio; + no-mmc; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&sdio { + bus-width = <4>; + cap-sdio-irq; + disable-wp; + keep-power-in-suspend; + max-frequency = <200000000>; + no-sd; + no-mmc; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdiom0_pins>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + vmmc-supply = <&vcc3v3_pcie2x1l0>; + vqmmc-supply = <&vcc_1v8_s3>; + wakeup-source; + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +&uart6 { + pinctrl-names = "default"; + pinctrl-0 = <&uart6m1_xfer &uart6m1_ctsn &uart6m1_rtsn>; + status = "okay"; +}; + +&u2phy1 { + status = "okay"; +}; + +&u2phy1_otg { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy2_host { + /* connected to USB hub, which is powered by vcc5v0_sys */ + phy-supply = <&vcc5v0_sys>; + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy3_host { + phy-supply = <&vcc5v0_host>; + status = "okay"; +}; + +&usbdp_phy1 { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usb_host1_xhci { + dr_mode = "host"; + status = "okay"; +}; + +&usb_host2_xhci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi index d1368418502a5d..7f874c77410c91 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base-pinctrl.dtsi @@ -1612,23 +1612,43 @@ npu_pins: npu-pins { pcie20x1 { /omit-if-no-ref/ - pcie20x1m0_pins: pcie20x1m0-pins { + pcie20x1m0_clkreqn: pcie20x1m0-clkreqn { rockchip,pins = /* pcie20x1_2_clkreqn_m0 */ - <3 RK_PC7 4 &pcfg_pull_none>, + <3 RK_PC7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie20x1m0_perstn: pcie20x1m0-perstn { + rockchip,pins = /* pcie20x1_2_perstn_m0 */ - <3 RK_PD1 4 &pcfg_pull_none>, + <3 RK_PD1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie20x1m0_waken: pcie20x1m0-waken { + rockchip,pins = /* pcie20x1_2_waken_m0 */ <3 RK_PD0 4 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie20x1m1_pins: pcie20x1m1-pins { + pcie20x1m1_clkreqn: pcie20x1m1-clkreqn { rockchip,pins = /* pcie20x1_2_clkreqn_m1 */ - <4 RK_PB7 4 &pcfg_pull_none>, + <4 RK_PB7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie20x1m1_perstn: pcie20x1m1-perstn { + rockchip,pins = /* pcie20x1_2_perstn_m1 */ - <4 RK_PC1 4 &pcfg_pull_none>, + <4 RK_PC1 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie20x1m1_waken: pcie20x1m1-waken { + rockchip,pins = /* pcie20x1_2_waken_m1 */ <4 RK_PC0 4 &pcfg_pull_none>; }; @@ -1654,52 +1674,127 @@ pcie30phy_pins: pcie30phy-pins { pcie30x1 { /omit-if-no-ref/ - pcie30x1m0_pins: pcie30x1m0-pins { + pcie30x1m0_0_clkreqn: pcie30x1m0-0-clkreqn { rockchip,pins = /* pcie30x1_0_clkreqn_m0 */ - <0 RK_PC0 12 &pcfg_pull_none>, + <0 RK_PC0 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m0_0_perstn: pcie30x1m0-0-perstn { + rockchip,pins = /* pcie30x1_0_perstn_m0 */ - <0 RK_PC5 12 &pcfg_pull_none>, + <0 RK_PC5 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m0_0_waken: pcie30x1m0-0-waken { + rockchip,pins = /* pcie30x1_0_waken_m0 */ - <0 RK_PC4 12 &pcfg_pull_none>, + <0 RK_PC4 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m0_1_clkreqn: pcie30x1m0-1-clkreqn { + rockchip,pins = /* pcie30x1_1_clkreqn_m0 */ - <0 RK_PB5 12 &pcfg_pull_none>, + <0 RK_PB5 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m0_1_perstn: pcie30x1m0-1-perstn { + rockchip,pins = /* pcie30x1_1_perstn_m0 */ - <0 RK_PB7 12 &pcfg_pull_none>, + <0 RK_PB7 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m0_1_waken: pcie30x1m0-1-waken { + rockchip,pins = /* pcie30x1_1_waken_m0 */ <0 RK_PB6 12 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie30x1m1_pins: pcie30x1m1-pins { + pcie30x1m1_0_clkreqn: pcie30x1m1-0-clkreqn { rockchip,pins = /* pcie30x1_0_clkreqn_m1 */ - <4 RK_PA3 4 &pcfg_pull_none>, + <4 RK_PA3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m1_0_perstn: pcie30x1m1-0-perstn { + rockchip,pins = /* pcie30x1_0_perstn_m1 */ - <4 RK_PA5 4 &pcfg_pull_none>, + <4 RK_PA5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m1_0_waken: pcie30x1m1-0-waken { + rockchip,pins = /* pcie30x1_0_waken_m1 */ - <4 RK_PA4 4 &pcfg_pull_none>, + <4 RK_PA4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m1_1_clkreqn: pcie30x1m1-1-clkreqn { + rockchip,pins = /* pcie30x1_1_clkreqn_m1 */ - <4 RK_PA0 4 &pcfg_pull_none>, + <4 RK_PA0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m1_1_perstn: pcie30x1m1-1-perstn { + rockchip,pins = /* pcie30x1_1_perstn_m1 */ - <4 RK_PA2 4 &pcfg_pull_none>, + <4 RK_PA2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m1_1_waken: pcie30x1m1-1-waken { + rockchip,pins = /* pcie30x1_1_waken_m1 */ <4 RK_PA1 4 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie30x1m2_pins: pcie30x1m2-pins { + pcie30x1m2_0_clkreqn: pcie30x1m2-0-clkreqn { rockchip,pins = /* pcie30x1_0_clkreqn_m2 */ - <1 RK_PB5 4 &pcfg_pull_none>, + <1 RK_PB5 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m2_0_perstn: pcie30x1m2-0-perstn { + rockchip,pins = /* pcie30x1_0_perstn_m2 */ - <1 RK_PB4 4 &pcfg_pull_none>, + <1 RK_PB4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m2_0_waken: pcie30x1m2-0-waken { + rockchip,pins = /* pcie30x1_0_waken_m2 */ - <1 RK_PB3 4 &pcfg_pull_none>, + <1 RK_PB3 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m2_1_clkreqn: pcie30x1m2-1-clkreqn { + rockchip,pins = /* pcie30x1_1_clkreqn_m2 */ - <1 RK_PA0 4 &pcfg_pull_none>, + <1 RK_PA0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m2_1_perstn: pcie30x1m2-1-perstn { + rockchip,pins = /* pcie30x1_1_perstn_m2 */ - <1 RK_PA7 4 &pcfg_pull_none>, + <1 RK_PA7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x1m2_1_waken: pcie30x1m2-1-waken { + rockchip,pins = /* pcie30x1_1_waken_m2 */ <1 RK_PA1 4 &pcfg_pull_none>; }; @@ -1721,45 +1816,85 @@ pcie30x1_1_button_rstn: pcie30x1-1-button-rstn { pcie30x2 { /omit-if-no-ref/ - pcie30x2m0_pins: pcie30x2m0-pins { + pcie30x2m0_clkreqn: pcie30x2m0-clkreqn { rockchip,pins = /* pcie30x2_clkreqn_m0 */ - <0 RK_PD1 12 &pcfg_pull_none>, + <0 RK_PD1 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m0_perstn: pcie30x2m0-perstn { + rockchip,pins = /* pcie30x2_perstn_m0 */ - <0 RK_PD4 12 &pcfg_pull_none>, + <0 RK_PD4 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m0_waken: pcie30x2m0-waken { + rockchip,pins = /* pcie30x2_waken_m0 */ <0 RK_PD2 12 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie30x2m1_pins: pcie30x2m1-pins { + pcie30x2m1_clkreqn: pcie30x2m1-clkreqn { rockchip,pins = /* pcie30x2_clkreqn_m1 */ - <4 RK_PA6 4 &pcfg_pull_none>, + <4 RK_PA6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m1_perstn: pcie30x2m1-perstn { + rockchip,pins = /* pcie30x2_perstn_m1 */ - <4 RK_PB0 4 &pcfg_pull_none>, + <4 RK_PB0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m1_waken: pcie30x2m1-waken { + rockchip,pins = /* pcie30x2_waken_m1 */ <4 RK_PA7 4 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie30x2m2_pins: pcie30x2m2-pins { + pcie30x2m2_clkreqn: pcie30x2m2-clkreqn { rockchip,pins = /* pcie30x2_clkreqn_m2 */ - <3 RK_PD2 4 &pcfg_pull_none>, + <3 RK_PD2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m2_perstn: pcie30x2m2-perstn { + rockchip,pins = /* pcie30x2_perstn_m2 */ - <3 RK_PD4 4 &pcfg_pull_none>, + <3 RK_PD4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m2_waken: pcie30x2m2-waken { + rockchip,pins = /* pcie30x2_waken_m2 */ <3 RK_PD3 4 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie30x2m3_pins: pcie30x2m3-pins { + pcie30x2m3_clkreqn: pcie30x2m3-clkreqn { rockchip,pins = /* pcie30x2_clkreqn_m3 */ - <1 RK_PD7 4 &pcfg_pull_none>, + <1 RK_PD7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m3_perstn: pcie30x2m3-perstn { + rockchip,pins = /* pcie30x2_perstn_m3 */ - <1 RK_PB7 4 &pcfg_pull_none>, + <1 RK_PB7 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x2m3_waken: pcie30x2m3-waken { + rockchip,pins = /* pcie30x2_waken_m3 */ <1 RK_PB6 4 &pcfg_pull_none>; }; @@ -1774,45 +1909,85 @@ pcie30x2_button_rstn: pcie30x2-button-rstn { pcie30x4 { /omit-if-no-ref/ - pcie30x4m0_pins: pcie30x4m0-pins { + pcie30x4m0_clkreqn: pcie30x4m0-clkreqn { rockchip,pins = /* pcie30x4_clkreqn_m0 */ - <0 RK_PC6 12 &pcfg_pull_none>, + <0 RK_PC6 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x4m0_perstn: pcie30x4m0-perstn { + rockchip,pins = /* pcie30x4_perstn_m0 */ - <0 RK_PD0 12 &pcfg_pull_none>, + <0 RK_PD0 12 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x4m0_waken: pcie30x4m0-waken { + rockchip,pins = /* pcie30x4_waken_m0 */ <0 RK_PC7 12 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie30x4m1_pins: pcie30x4m1-pins { + pcie30x4m1_clkreqn: pcie30x4m1-clkreqn { rockchip,pins = /* pcie30x4_clkreqn_m1 */ - <4 RK_PB4 4 &pcfg_pull_none>, + <4 RK_PB4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x4m1_perstn: pcie30x4m1-perstn { + rockchip,pins = /* pcie30x4_perstn_m1 */ - <4 RK_PB6 4 &pcfg_pull_none>, + <4 RK_PB6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x4m1_waken: pcie30x4m1-waken { + rockchip,pins = /* pcie30x4_waken_m1 */ <4 RK_PB5 4 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie30x4m2_pins: pcie30x4m2-pins { + pcie30x4m2_clkreqn: pcie30x4m2-clkreqn { rockchip,pins = /* pcie30x4_clkreqn_m2 */ - <3 RK_PC4 4 &pcfg_pull_none>, + <3 RK_PC4 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x4m2_perstn: pcie30x4m2-perstn { + rockchip,pins = /* pcie30x4_perstn_m2 */ - <3 RK_PC6 4 &pcfg_pull_none>, + <3 RK_PC6 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x4m2_waken: pcie30x4m2-waken { + rockchip,pins = /* pcie30x4_waken_m2 */ <3 RK_PC5 4 &pcfg_pull_none>; }; /omit-if-no-ref/ - pcie30x4m3_pins: pcie30x4m3-pins { + pcie30x4m3_clkreqn: pcie30x4m3-clkreqn { rockchip,pins = /* pcie30x4_clkreqn_m3 */ - <1 RK_PB0 4 &pcfg_pull_none>, + <1 RK_PB0 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x4m3_perstn: pcie30x4m3-perstn { + rockchip,pins = /* pcie30x4_perstn_m3 */ - <1 RK_PB2 4 &pcfg_pull_none>, + <1 RK_PB2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + pcie30x4m3_waken: pcie30x4m3-waken { + rockchip,pins = /* pcie30x4_waken_m3 */ <1 RK_PB1 4 &pcfg_pull_none>; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi index fc67585b64b7ba..a337f3fb8377e4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi @@ -1370,6 +1370,47 @@ i2s9_8ch: i2s@fddfc000 { status = "disabled"; }; + hdmi0: hdmi@fde80000 { + compatible = "rockchip,rk3588-dw-hdmi-qp"; + reg = <0x0 0xfde80000 0x0 0x20000>; + clocks = <&cru PCLK_HDMITX0>, + <&cru CLK_HDMITX0_EARC>, + <&cru CLK_HDMITX0_REF>, + <&cru MCLK_I2S5_8CH_TX>, + <&cru CLK_HDMIHDP0>, + <&cru HCLK_VO1>; + clock-names = "pclk", "earc", "ref", "aud", "hdp", "hclk_vo1"; + interrupts = , + , + , + , + ; + interrupt-names = "avp", "cec", "earc", "main", "hpd"; + phys = <&hdptxphy_hdmi0>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmim0_tx0_cec &hdmim0_tx0_hpd + &hdmim0_tx0_scl &hdmim0_tx0_sda>; + power-domains = <&power RK3588_PD_VO1>; + resets = <&cru SRST_HDMITX0_REF>, <&cru SRST_HDMIHDP0>; + reset-names = "ref", "hdp"; + rockchip,grf = <&sys_grf>; + rockchip,vo-grf = <&vo1_grf>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + hdmi0_in: port@0 { + reg = <0>; + }; + + hdmi0_out: port@1 { + reg = <1>; + }; + }; + }; + qos_gpu_m0: qos@fdf35000 { compatible = "rockchip,rk3588-qos", "syscon"; reg = <0x0 0xfdf35000 0x0 0x20>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts index a4946cdc3bb34e..9d525c8ff725b9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include #include "rk3588-coolpi-cm5.dtsi" / { @@ -22,6 +23,17 @@ backlight: backlight { pwms = <&pwm2 0 25000 0>; }; + hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + leds: leds { compatible = "gpio-leds"; @@ -33,7 +45,7 @@ green_led: led-0 { }; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -42,7 +54,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -52,7 +64,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -62,7 +74,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc3v3_lcd: vcc3v3-lcd-regulator { + vcc3v3_lcd: regulator-vcc3v3-lcd { compatible = "regulator-fixed"; regulator-name = "vcc3v3_lcd"; enable-active-high; @@ -72,7 +84,7 @@ vcc3v3_lcd: vcc3v3-lcd-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc5v0_usb_host1: vcc5v0_usb_host2: vcc5v0-usb-host-regulator { + vcc5v0_usb_host1: vcc5v0_usb_host2: regulator-vcc5v0-usb-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; regulator-boot-on; @@ -86,7 +98,7 @@ vcc5v0_usb_host1: vcc5v0_usb_host2: vcc5v0-usb-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_usb30_otg: vcc5v0-usb30-otg-regulator { + vcc5v0_usb30_otg: regulator-vcc5v0-usb30-otg { compatible = "regulator-fixed"; regulator-name = "vcc5v0_otg"; regulator-boot-on; @@ -101,6 +113,26 @@ vcc5v0_usb30_otg: vcc5v0-usb30-otg-regulator { }; }; +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + /* M.2 E-Key */ &pcie2x1l1 { reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; @@ -214,3 +246,18 @@ &usb_host1_ehci { &usb_host1_ohci { status = "okay"; }; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts index 6418286efe40d3..92f0ed83c99022 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-genbook.dts @@ -7,6 +7,7 @@ /dts-v1/; #include +#include #include "rk3588-coolpi-cm5.dtsi" / { @@ -35,6 +36,17 @@ charger: dc-charger { gpios = <&gpio1 RK_PC0 GPIO_ACTIVE_LOW>; }; + hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + leds: leds { compatible = "gpio-leds"; @@ -58,7 +70,7 @@ charging_red: led-2 { }; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -67,7 +79,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc_sys: vcc-sys-regulator { + vcc_sys: regulator-vcc-sys { compatible = "regulator-fixed"; regulator-name = "vcc_sys"; regulator-always-on; @@ -77,7 +89,7 @@ vcc_sys: vcc-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -87,7 +99,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -97,7 +109,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_lcd: vcc3v3-lcd-regulator { + vcc3v3_lcd: regulator-vcc3v3-lcd { compatible = "regulator-fixed"; regulator-name = "vcc3v3_lcd"; enable-active-high; @@ -107,7 +119,7 @@ vcc3v3_lcd: vcc3v3-lcd-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-boot-on; @@ -121,7 +133,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&vcc_sys>; }; - vcc5v0_usb_host0: vcc5v0_usb30_host: vcc5v0-usb-host-regulator { + vcc5v0_usb_host0: vcc5v0_usb30_host: regulator-vcc5v0-usb-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; regulator-boot-on; @@ -136,6 +148,28 @@ vcc5v0_usb_host0: vcc5v0_usb30_host: vcc5v0-usb-host-regulator { }; }; +/* HDMI CEC is not used */ +&hdmi0 { + pinctrl-0 = <&hdmim0_tx0_hpd &hdmim0_tx0_scl &hdmim0_tx0_sda>; + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c4 { status = "okay"; pinctrl-names = "default"; @@ -347,3 +381,18 @@ &usb_host1_xhci { dr_mode = "host"; status = "okay"; }; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi index fde8b228f2c7c9..71ed680621b880 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi @@ -36,7 +36,7 @@ chosen { stdout-path = "serial2:1500000n8"; }; - avdd0v85_pcie20: avdd0v85-pcie20-regulator { + avdd0v85_pcie20: regulator-avdd0v85-pcie20 { compatible = "regulator-fixed"; regulator-name = "avdd0v85_pcie20"; regulator-boot-on; @@ -46,7 +46,7 @@ avdd0v85_pcie20: avdd0v85-pcie20-regulator { vin-supply = <&vdd_0v85_s0>; }; - avdd1v8_pcie20: avdd1v8-pcie20-regulator { + avdd1v8_pcie20: regulator-avdd1v8-pcie20 { compatible = "regulator-fixed"; regulator-name = "avdd1v8_pcie20"; regulator-boot-on; @@ -56,7 +56,7 @@ avdd1v8_pcie20: avdd1v8-pcie20-regulator { vin-supply = <&avcc_1v8_s0>; }; - avdd0v75_pcie30: avdd0v75-pcie30-regulator { + avdd0v75_pcie30: regulator-avdd0v75-pcie30 { compatible = "regulator-fixed"; regulator-name = "avdd0v75_pcie30"; regulator-boot-on; @@ -66,7 +66,7 @@ avdd0v75_pcie30: avdd0v75-pcie30-regulator { vin-supply = <&avdd_0v75_s0>; }; - pcie30_avdd1v8: avdd1v8-pcie30-regulator { + pcie30_avdd1v8: regulator-avdd1v8-pcie30 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-boot-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-common.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-common.dtsi index 03fd193be253da..5e72d0eff0e0f0 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-common.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-common.dtsi @@ -24,7 +24,7 @@ led_user: led-0 { }; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -33,7 +33,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -43,7 +43,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtsi index 7b131789835812..05ae9bdcfbbdeb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dtsi @@ -10,7 +10,7 @@ chosen { stdout-path = "serial2:1500000n8"; }; - vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { + vcc3v3_pcie2x1l0: regulator-vcc3v3-pcie2x1l0 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie2x1l0"; regulator-min-microvolt = <3300000>; @@ -19,7 +19,7 @@ vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { vin-supply = <&vcc_3v3_s3>; }; - vcc3v3_pcie3x2: vcc3v3-pcie3x2-regulator { + vcc3v3_pcie3x2: regulator-vcc3v3-pcie3x2 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio2 RK_PC4 GPIO_ACTIVE_HIGH>; /* PCIE_4G_PWEN */ @@ -32,7 +32,7 @@ vcc3v3_pcie3x2: vcc3v3-pcie3x2-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie3x4: vcc3v3-pcie3x4-regulator { + vcc3v3_pcie3x4: regulator-vcc3v3-pcie3x4 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio2 RK_PC5 GPIO_ACTIVE_HIGH>; /* PCIE30x4_PWREN_H */ @@ -45,7 +45,7 @@ vcc3v3_pcie3x4: vcc3v3-pcie3x4-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PC7 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-wifi.dtso b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-wifi.dtso index e9a3855e875297..2128ffcc3616a6 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-wifi.dtso +++ b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-wifi.dtso @@ -14,7 +14,7 @@ #include &{/} { - vcc3v3_pcie2x1l1: vcc3v3-pcie2x1l1-regulator { + vcc3v3_pcie2x1l1: regulator-vcc3v3-pcie2x1l1 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>; /* WIFI_3V3_EN */ diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts index 00f660d50127f7..d6e464cdc53612 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "rk3588.dtsi" @@ -66,7 +67,7 @@ analog-sound { simple-audio-card,bitclock-master = <&masterdai>; simple-audio-card,format = "i2s"; simple-audio-card,frame-master = <&masterdai>; - simple-audio-card,hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; + simple-audio-card,hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; simple-audio-card,mclk-fs = <256>; simple-audio-card,pin-switches = "Headphones", "Speaker"; simple-audio-card,routing = @@ -120,7 +121,18 @@ backlight: backlight { pwms = <&pwm2 0 25000 0>; }; - pcie20_avdd0v85: pcie20-avdd0v85-regulator { + hdmi0-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + + pcie20_avdd0v85: regulator-pcie20-avdd0v85 { compatible = "regulator-fixed"; regulator-name = "pcie20_avdd0v85"; regulator-always-on; @@ -130,7 +142,7 @@ pcie20_avdd0v85: pcie20-avdd0v85-regulator { vin-supply = <&avdd_0v85_s0>; }; - pcie20_avdd1v8: pcie20-avdd1v8-regulator { + pcie20_avdd1v8: regulator-pcie20-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie20_avdd1v8"; regulator-always-on; @@ -140,7 +152,7 @@ pcie20_avdd1v8: pcie20-avdd1v8-regulator { vin-supply = <&avcc_1v8_s0>; }; - pcie30_avdd0v75: pcie30-avdd0v75-regulator { + pcie30_avdd0v75: regulator-pcie30-avdd0v75 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd0v75"; regulator-always-on; @@ -150,7 +162,7 @@ pcie30_avdd0v75: pcie30-avdd0v75-regulator { vin-supply = <&avdd_0v75_s0>; }; - pcie30_avdd1v8: pcie30-avdd1v8-regulator { + pcie30_avdd1v8: regulator-pcie30-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-always-on; @@ -160,7 +172,7 @@ pcie30_avdd1v8: pcie30-avdd1v8-regulator { vin-supply = <&avcc_1v8_s0>; }; - vbus5v0_typec: vbus5v0-typec-regulator { + vbus5v0_typec: regulator-vbus5v0-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>; @@ -172,7 +184,7 @@ vbus5v0_typec: vbus5v0-typec-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -181,7 +193,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc3v3_pcie30: vcc3v3-pcie30-regulator { + vcc3v3_pcie30: regulator-vcc3v3-pcie30 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie30"; regulator-min-microvolt = <3300000>; @@ -194,7 +206,7 @@ vcc3v3_pcie30: vcc3v3-pcie30-regulator { pinctrl-0 = <&vcc3v3_pcie30_en>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; regulator-boot-on; @@ -208,7 +220,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -218,7 +230,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usbdcin: vcc5v0-usbdcin-regulator { + vcc5v0_usbdcin: regulator-vcc5v0-usbdcin { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usbdcin"; regulator-always-on; @@ -228,7 +240,7 @@ vcc5v0_usbdcin: vcc5v0-usbdcin-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -300,6 +312,26 @@ &gpu { status = "okay"; }; +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c2 { status = "okay"; @@ -1256,3 +1288,18 @@ &usb_host1_xhci { dr_mode = "host"; status = "okay"; }; + +&vop_mmu { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-fet3588-c.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-fet3588-c.dtsi index 47e64d547ea9c7..39005131738923 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-fet3588-c.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-fet3588-c.dtsi @@ -29,7 +29,7 @@ io-led { }; }; - pcie20_avdd0v85: pcie20-avdd0v85-regulator { + pcie20_avdd0v85: regulator-pcie20-avdd0v85 { compatible = "regulator-fixed"; regulator-name = "pcie20_avdd0v85"; regulator-always-on; @@ -39,7 +39,7 @@ pcie20_avdd0v85: pcie20-avdd0v85-regulator { vin-supply = <&vdd_0v85_s0>; }; - pcie20_avdd1v8: pcie20-avdd1v8-regulator { + pcie20_avdd1v8: regulator-pcie20-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie20_avdd1v8"; regulator-always-on; @@ -49,7 +49,7 @@ pcie20_avdd1v8: pcie20-avdd1v8-regulator { vin-supply = <&avcc_1v8_s0>; }; - pcie30_avdd0v75: pcie30-avdd0v75-regulator { + pcie30_avdd0v75: regulator-pcie30-avdd0v75 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd0v75"; regulator-always-on; @@ -59,7 +59,7 @@ pcie30_avdd0v75: pcie30-avdd0v75-regulator { vin-supply = <&avdd_0v75_s0>; }; - pcie30_avdd1v8: pcie30-avdd1v8-regulator { + pcie30_avdd1v8: regulator-pcie30-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-always-on; @@ -69,7 +69,7 @@ pcie30_avdd1v8: pcie30-avdd1v8-regulator { vin-supply = <&avcc_1v8_s0>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; @@ -79,7 +79,7 @@ vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc4v0_sys: vcc4v0-sys-regulator { + vcc4v0_sys: regulator-vcc4v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc4v0_sys"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts index 83103e4c7216fd..b3a04ca370bb92 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-friendlyelec-cm3588-nas.dts @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "rk3588-friendlyelec-cm3588.dtsi" @@ -38,7 +39,7 @@ analog-sound { pinctrl-0 = <&headphone_detect>; simple-audio-card,format = "i2s"; - simple-audio-card,hp-det-gpio = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>; + simple-audio-card,hp-det-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>; simple-audio-card,mclk-fs = <256>; simple-audio-card,name = "realtek,rt5616-codec"; @@ -89,6 +90,17 @@ button-user { }; }; + hdmi0-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + ir-receiver { compatible = "gpio-ir-receiver"; gpios = <&gpio0 RK_PD4 GPIO_ACTIVE_LOW>; @@ -307,6 +319,26 @@ &gpio4 { "", "", "", ""; }; +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + /* Connected to MIPI-DSI0 */ &i2c5 { pinctrl-names = "default"; @@ -776,3 +808,18 @@ usbdp_phy0_dp_altmode_mux: endpoint@1 { &usbdp_phy1 { status = "okay"; }; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts index 31d2f8994f8513..90f823b2c2191d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "rk3588.dtsi" @@ -32,6 +33,7 @@ button-bios-disable { aliases { ethernet0 = &gmac0; + i2c10 = &i2c10; mmc0 = &sdhci; mmc1 = &sdmmc; rtc0 = &rtc_twi; @@ -42,7 +44,7 @@ chosen { }; /* DCIN is 12-24V but standard is 12V */ - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -58,6 +60,17 @@ emmc_pwrseq: emmc-pwrseq { reset-gpios = <&gpio2 RK_PA3 GPIO_ACTIVE_HIGH>; }; + hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -98,7 +111,7 @@ pps { gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; @@ -108,7 +121,7 @@ vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc_1v2_s3: vcc-1v2-s3-regulator { + vcc_1v2_s3: regulator-vcc-1v2-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v2_s3"; regulator-always-on; @@ -119,7 +132,7 @@ vcc_1v2_s3: vcc-1v2-s3-regulator { }; /* Exposed on P14 and P15 */ - vcc_2v8_s3: vcc-2v8-s3-regulator { + vcc_2v8_s3: regulator-vcc-2v8-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_2v8_s3"; regulator-always-on; @@ -129,7 +142,7 @@ vcc_2v8_s3: vcc-2v8-s3-regulator { vin-supply = <&vcc_3v3_s3>; }; - vcc_5v0_usb_a: vcc-5v0-usb-a-regulator { + vcc_5v0_usb_a: regulator-vcc-5v0-usb-a { compatible = "regulator-fixed"; regulator-name = "usb_a_vcc"; regulator-min-microvolt = <5000000>; @@ -139,7 +152,7 @@ vcc_5v0_usb_a: vcc-5v0-usb-a-regulator { enable-active-high; }; - vcc_5v0_usb_c1: vcc-5v0-usb-c1-regulator { + vcc_5v0_usb_c1: regulator-vcc-5v0-usb-c1 { compatible = "regulator-fixed"; regulator-name = "5v_usbc1"; regulator-min-microvolt = <5000000>; @@ -149,7 +162,7 @@ vcc_5v0_usb_c1: vcc-5v0-usb-c1-regulator { enable-active-high; }; - vcc_5v0_usb_c2: vcc-5v0-usb-c2-regulator { + vcc_5v0_usb_c2: regulator-vcc-5v0-usb-c2 { compatible = "regulator-fixed"; regulator-name = "5v_usbc2"; regulator-min-microvolt = <5000000>; @@ -159,7 +172,7 @@ vcc_5v0_usb_c2: vcc-5v0-usb-c2-regulator { enable-active-high; }; - vcc3v3_mdot2: vcc3v3-mdot2-regulator { + vcc3v3_mdot2: regulator-vcc3v3-mdot2 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_mdot2"; regulator-always-on; @@ -169,7 +182,7 @@ vcc3v3_mdot2: vcc3v3-mdot2-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -179,7 +192,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -271,13 +284,53 @@ &gpu { status = "okay"; }; +&hdmi0 { + /* No CEC on Jaguar */ + pinctrl-names = "default"; + pinctrl-0 = <&hdmim0_tx0_hpd &hdmim0_tx0_scl &hdmim0_tx0_sda>; + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c0 { pinctrl-0 = <&i2c0m2_xfer>; status = "okay"; fan@18 { - compatible = "ti,amc6821"; + compatible = "tsd,mule", "ti,amc6821"; reg = <0x18>; + + i2c-mux { + compatible = "tsd,mule-i2c-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2c10: i2c@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + rtc_twi: rtc@6f { + compatible = "isil,isl1208"; + reg = <0x6f>; + }; + }; + }; }; vdd_npu_s0: regulator@42 { @@ -313,11 +366,6 @@ regulator-state-mem { regulator-off-in-suspend; }; }; - - rtc_twi: rtc@6f { - compatible = "isil,isl1208"; - reg = <0x6f>; - }; }; &i2c1 { @@ -864,3 +912,18 @@ &usb_host1_ehci { &usb_host1_ohci { status = "okay"; }; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts index 2d92bbb4027d3a..ff855064be0818 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts @@ -15,7 +15,7 @@ / { compatible = "friendlyarm,nanopc-t6-lts", "rockchip,rk3588"; /* provide power for on-board USB 2.0 hub */ - vcc5v0_usb20_host: vcc5v0-usb20-host-regulator { + vcc5v0_usb20_host: regulator-vcc5v0-usb20-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts index 92321c1d3ff10e..40290a81bb9d6c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts @@ -14,7 +14,7 @@ / { model = "FriendlyElec NanoPC-T6"; compatible = "friendlyarm,nanopc-t6", "rockchip,rk3588"; - vdd_4g_3v3: vdd-4g-3v3-regulator { + vdd_4g_3v3: regulator-vdd-4g-3v3 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi index fc131789b4c327..cb350727d11680 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "rk3588.dtsi" @@ -40,6 +41,17 @@ chosen { stdout-path = "serial2:1500000n8"; }; + hdmi0-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + ir-receiver { compatible = "gpio-ir-receiver"; gpios = <&gpio0 RK_PD4 GPIO_ACTIVE_LOW>; @@ -75,7 +87,7 @@ sound { simple-audio-card,format = "i2s"; simple-audio-card,mclk-fs = <256>; - simple-audio-card,hp-det-gpio = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>; + simple-audio-card,hp-det-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>; simple-audio-card,widgets = "Headphone", "Headphones", @@ -94,7 +106,7 @@ simple-audio-card,codec { }; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -104,7 +116,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { }; /* vcc5v0_sys powers peripherals */ - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -115,7 +127,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { }; /* vcc4v0_sys powers the RK806, RK860's */ - vcc4v0_sys: vcc4v0-sys-regulator { + vcc4v0_sys: regulator-vcc4v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc4v0_sys"; regulator-always-on; @@ -125,7 +137,7 @@ vcc4v0_sys: vcc4v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc-1v1-nldo-s3"; regulator-always-on; @@ -135,7 +147,7 @@ vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { vin-supply = <&vcc4v0_sys>; }; - vcc_3v3_pcie20: vcc3v3-pcie20-regulator { + vcc_3v3_pcie20: regulator-vcc3v3-pcie20 { compatible = "regulator-fixed"; regulator-name = "vcc_3v3_pcie20"; regulator-always-on; @@ -145,7 +157,7 @@ vcc_3v3_pcie20: vcc3v3-pcie20-regulator { vin-supply = <&vcc_3v3_s3>; }; - vbus5v0_typec: vbus5v0-typec-regulator { + vbus5v0_typec: regulator-vbus5v0-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; @@ -159,7 +171,21 @@ vbus5v0_typec: vbus5v0-typec-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { + vbus5v0_usb: regulator-vbus5v0-usb { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb5v_pwren>; + regulator-always-on; + regulator-boot-on; + regulator-name = "vbus5v0_usb"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc3v3_pcie2x1l0: regulator-vcc3v3-pcie2x1l0 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>; @@ -171,7 +197,7 @@ vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie30: vcc3v3-pcie30-regulator { + vcc3v3_pcie30: regulator-vcc3v3-pcie30 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio2 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -183,7 +209,7 @@ vcc3v3_pcie30: vcc3v3-pcie30-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_sd_s0: vcc3v3-sd-s0-regulator { + vcc3v3_sd_s0: regulator-vcc3v3-sd-s0 { compatible = "regulator-fixed"; gpio = <&gpio4 RK_PA5 GPIO_ACTIVE_LOW>; regulator-boot-on; @@ -318,6 +344,26 @@ &gpu { status = "okay"; }; +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0m2_xfer>; @@ -575,6 +621,10 @@ typec5v_pwren: typec5v-pwren { rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; }; + usb5v_pwren: usb5v_pwren { + rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + usbc0_int: usbc0-int { rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; }; @@ -973,6 +1023,14 @@ &u2phy0_otg { status = "okay"; }; +&u2phy1 { + status = "okay"; +}; + +&u2phy1_otg { + status = "okay"; +}; + &u2phy2_host { status = "okay"; }; @@ -1012,6 +1070,11 @@ usbdp_phy0_typec_sbu: endpoint@1 { }; }; +&usbdp_phy1 { + phy-supply = <&vbus5v0_usb>; + status = "okay"; +}; + &usb_host0_ehci { status = "okay"; }; @@ -1032,6 +1095,11 @@ usb_host0_xhci_drd_sw: endpoint { }; }; +&usb_host1_xhci { + dr_mode = "host"; + status = "okay"; +}; + &usb_host1_ehci { status = "okay"; }; @@ -1039,3 +1107,18 @@ &usb_host1_ehci { &usb_host1_ohci { status = "okay"; }; + +&vop_mmu { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-ok3588-c.dts b/arch/arm64/boot/dts/rockchip/rk3588-ok3588-c.dts index c2a08bdf09e839..1c0851b45eb8ee 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-ok3588-c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-ok3588-c.dts @@ -75,7 +75,7 @@ sound { simple-audio-card,bitclock-master = <&masterdai>; simple-audio-card,format = "i2s"; simple-audio-card,frame-master = <&masterdai>; - simple-audio-card,hp-det-gpio = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>; + simple-audio-card,hp-det-gpios = <&gpio1 RK_PB2 GPIO_ACTIVE_HIGH>; simple-audio-card,mclk-fs = <256>; simple-audio-card,pin-switches = "Headphones", "Speaker"; simple-audio-card,widgets = @@ -100,7 +100,7 @@ masterdai: simple-audio-card,codec { }; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -109,7 +109,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc1v8_sys: vcc1v8-sys-regulator { + vcc1v8_sys: regulator-vcc1v8-sys { compatible = "regulator-fixed"; regulator-name = "vcc1v8_sys"; regulator-always-on; @@ -119,7 +119,7 @@ vcc1v8_sys: vcc1v8-sys-regulator { vin-supply = <&vcc3v3_sys>; }; - vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { + vcc3v3_pcie2x1l0: regulator-vcc3v3-pcie2x1l0 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie2x1l0"; regulator-min-microvolt = <3300000>; @@ -128,7 +128,7 @@ vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie2x1l2: vcc3v3-pcie2x1l2-regulator { + vcc3v3_pcie2x1l2: regulator-vcc3v3-pcie2x1l2 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie2x1l2"; regulator-min-microvolt = <3300000>; @@ -137,7 +137,7 @@ vcc3v3_pcie2x1l2: vcc3v3-pcie2x1l2-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie30: vcc3v3_pcie30-regulator { + vcc3v3_pcie30: regulator-vcc3v3_pcie30 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie30"; regulator-always-on; @@ -147,7 +147,7 @@ vcc3v3_pcie30: vcc3v3_pcie30-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_sys: vcc3v3-sys-regulator { + vcc3v3_sys: regulator-vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; regulator-always-on; @@ -157,7 +157,7 @@ vcc3v3_sys: vcc3v3-sys-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts index dd4c79bcad87f0..9f5a38b290bf6f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "rk3588.dtsi" @@ -85,6 +86,17 @@ led { }; }; + hdmi0-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + fan: pwm-fan { compatible = "pwm-fan"; cooling-levels = <0 70 75 80 100>; @@ -120,7 +132,7 @@ sound { simple-audio-card,aux-devs = <&speaker_amp>, <&headphone_amp>; simple-audio-card,format = "i2s"; simple-audio-card,mclk-fs = <256>; - simple-audio-card,hp-det-gpio = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>; + simple-audio-card,hp-det-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>; simple-audio-card,bitclock-master = <&daicpu>; simple-audio-card,frame-master = <&daicpu>; /*TODO: SARADC_IN3 is used as MIC detection / key input */ @@ -165,7 +177,7 @@ daicodec: simple-audio-card,codec { }; }; - vcc3v3_pcie30: vcc3v3-pcie30-regulator { + vcc3v3_pcie30: regulator-vcc3v3-pcie30 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio2 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -176,7 +188,7 @@ vcc3v3_pcie30: vcc3v3-pcie30-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie_eth: vcc3v3-pcie-eth-regulator { + vcc3v3_pcie_eth: regulator-vcc3v3-pcie-eth { compatible = "regulator-fixed"; gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>; regulator-name = "vcc3v3_pcie_eth"; @@ -186,7 +198,7 @@ vcc3v3_pcie_eth: vcc3v3-pcie-eth-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_wf: vcc3v3-wf-regulator { + vcc3v3_wf: regulator-vcc3v3-wf { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio2 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -197,7 +209,7 @@ vcc3v3_wf: vcc3v3-wf-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -206,7 +218,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { regulator-max-microvolt = <5000000>; }; - vcc5v0_usb20: vcc5v0-usb20-regulator { + vcc5v0_usb20: regulator-vcc5v0-usb20 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_HIGH>; @@ -263,6 +275,31 @@ &cpu_l3 { cpu-supply = <&vdd_cpu_lit_s0>; }; +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0m2_xfer>; @@ -357,6 +394,36 @@ &i2s2m0_sdi status = "okay"; }; +&package_thermal { + polling-delay = <1000>; + + cooling-maps { + map0 { + trip = <&package_fan0>; + cooling-device = <&fan THERMAL_NO_LIMIT 1>; + }; + + map1 { + trip = <&package_fan1>; + cooling-device = <&fan 2 THERMAL_NO_LIMIT>; + }; + }; + + trips { + package_fan0: package-fan0 { + temperature = <55000>; + hysteresis = <2000>; + type = "active"; + }; + + package_fan1: package-fan1 { + temperature = <65000>; + hysteresis = <2000>; + type = "active"; + }; + }; +}; + /* phy1 - M.KEY socket */ &pcie2x1l0 { reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -852,3 +919,18 @@ &usb_host1_ehci { &usb_host1_ohci { status = "okay"; }; + +&vop_mmu { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts index b38dab009cccaa..088cfade6f6f14 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts @@ -104,7 +104,7 @@ sound { simple-audio-card,aux-devs = <&speaker_amp>, <&headphone_amp>; simple-audio-card,format = "i2s"; simple-audio-card,mclk-fs = <256>; - simple-audio-card,hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; + simple-audio-card,hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; simple-audio-card,bitclock-master = <&daicpu>; simple-audio-card,frame-master = <&daicpu>; /* SARADC_IN3 is used as MIC detection / key input */ @@ -149,7 +149,7 @@ daicodec: simple-audio-card,codec { }; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -158,7 +158,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc3v3_bt: vcc3v3-bt-regulator { + vcc3v3_bt: regulator-vcc3v3-bt { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>; @@ -169,7 +169,7 @@ vcc3v3_bt: vcc3v3-bt-regulator { vin-supply = <&vcc_3v3_s0>; }; - vcc3v3_pcie30: vcc3v3-pcie30-regulator { + vcc3v3_pcie30: regulator-vcc3v3-pcie30 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_HIGH>; @@ -180,7 +180,7 @@ vcc3v3_pcie30: vcc3v3-pcie30-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc3v3_wf: vcc3v3-wf-regulator { + vcc3v3_wf: regulator-vcc3v3-wf { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_HIGH>; @@ -191,7 +191,7 @@ vcc3v3_wf: vcc3v3-wf-regulator { vin-supply = <&vcc_3v3_s0>; }; - vcc4v0_sys: vcc4v0-sys-regulator { + vcc4v0_sys: regulator-vcc4v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc4v0_sys"; regulator-always-on; @@ -201,7 +201,7 @@ vcc4v0_sys: vcc4v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>; @@ -215,7 +215,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts index d0b922b8d67e85..6d68f70284e450 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts @@ -46,7 +46,7 @@ analog-sound { compatible = "audio-graph-card"; label = "rk3588-es8316"; dais = <&i2s0_8ch_p0>; - hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; + hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&hp_detect>; routing = "MIC2", "Mic Jack", @@ -72,6 +72,15 @@ hdd-led2 { }; }; + /* Unnamed gated oscillator: 100MHz,3.3V,3225 */ + pcie30_port0_refclk: pcie30_port1_refclk: pcie-oscillator { + compatible = "gated-fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "pcie30_refclk"; + vdd-supply = <&vcc3v3_pi6c_05>; + }; + fan0: pwm-fan { compatible = "pwm-fan"; #cooling-cells = <2>; @@ -146,13 +155,14 @@ vcc3v3_lan: vcc3v3_lan_phy2: regulator-vcc3v3-lan { vin-supply = <&vcc_3v3_s3>; }; - vcc3v3_mkey: regulator-vcc3v3-mkey { + /* The PCIE30x4_PWREN_H controls two regulators */ + vcc3v3_mkey: vcc3v3_pi6c_05: regulator-vcc3v3-pi6c-05 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pcie30x4_pwren_h>; - regulator-name = "vcc3v3_mkey"; + regulator-name = "vcc3v3_pi6c_05"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; startup-delay-us = <5000>; @@ -513,6 +523,18 @@ &pcie30phy { /* ASMedia ASM1164 Sata controller */ &pcie3x2 { + /* + * The board has a "pcie_refclk" oscillator that needs enabling, + * so add it to the list of clocks. + */ + clocks = <&cru ACLK_PCIE_2L_MSTR>, <&cru ACLK_PCIE_2L_SLV>, + <&cru ACLK_PCIE_2L_DBI>, <&cru PCLK_PCIE_2L>, + <&cru CLK_PCIE_AUX1>, <&cru CLK_PCIE2L_PIPE>, + <&pcie30_port1_refclk>; + clock-names = "aclk_mst", "aclk_slv", + "aclk_dbi", "pclk", + "aux", "pipe", + "ref"; pinctrl-names = "default"; pinctrl-0 = <&pcie30x2_perstn_m1_l>; reset-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>; @@ -522,6 +544,18 @@ &pcie3x2 { /* M.2 M.key */ &pcie3x4 { + /* + * The board has a "pcie_refclk" oscillator that needs enabling, + * so add it to the list of clocks. + */ + clocks = <&cru ACLK_PCIE_4L_MSTR>, <&cru ACLK_PCIE_4L_SLV>, + <&cru ACLK_PCIE_4L_DBI>, <&cru PCLK_PCIE_4L>, + <&cru CLK_PCIE_AUX0>, <&cru CLK_PCIE4L_PIPE>, + <&pcie30_port0_refclk>; + clock-names = "aclk_mst", "aclk_slv", + "aclk_dbi", "pclk", + "aux", "pipe", + "ref"; num-lanes = <2>; pinctrl-names = "default"; pinctrl-0 = <&pcie30x4_perstn_m1_l>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts index 6bd06e46a101d0..c44d001da16978 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts @@ -4,6 +4,7 @@ #include #include +#include #include "rk3588.dtsi" / { @@ -32,11 +33,22 @@ analog-sound { "Headphones", "HPOR"; dais = <&i2s0_8ch_p0>; - hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; + hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&hp_detect>; }; + hdmi0-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -72,7 +84,7 @@ rfkill-bt { shutdown-gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_HIGH>; }; - vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { + vcc3v3_pcie2x1l0: regulator-vcc3v3-pcie2x1l0 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; @@ -87,7 +99,7 @@ vcc3v3_pcie2x1l0: vcc3v3-pcie2x1l0-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_pcie2x1l2: vcc3v3-pcie2x1l2-regulator { + vcc3v3_pcie2x1l2: regulator-vcc3v3-pcie2x1l2 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie2x1l2"; regulator-min-microvolt = <3300000>; @@ -96,7 +108,7 @@ vcc3v3_pcie2x1l2: vcc3v3-pcie2x1l2-regulator { vin-supply = <&vcc_3v3_s3>; }; - vcc3v3_pcie30: vcc3v3-pcie30-regulator { + vcc3v3_pcie30: regulator-vcc3v3-pcie30 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio1 RK_PA4 GPIO_ACTIVE_HIGH>; @@ -109,7 +121,7 @@ vcc3v3_pcie30: vcc3v3-pcie30-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; regulator-boot-on; @@ -123,7 +135,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -132,7 +144,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { regulator-max-microvolt = <5000000>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; @@ -192,6 +204,26 @@ &gpu { status = "okay"; }; +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0m2_xfer>; @@ -858,3 +890,18 @@ &usb_host1_xhci { &usb_host2_xhci { status = "okay"; }; + +&vop_mmu { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts index e4b7a0a4444bf9..3187b4918a300d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-tiger-haikou.dts @@ -5,6 +5,7 @@ /dts-v1/; #include +#include #include "rk3588-tiger.dtsi" / { @@ -20,7 +21,7 @@ chosen { stdout-path = "serial2:115200n8"; }; - dc_12v: dc-12v-regulator { + dc_12v: regulator-dc-12v { compatible = "regulator-fixed"; regulator-name = "dc_12v"; regulator-always-on; @@ -61,6 +62,17 @@ switch-lid-btn-n { }; }; + hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + i2s3-sound { compatible = "simple-audio-card"; simple-audio-card,format = "i2s"; @@ -84,7 +96,7 @@ sgtl5000_clk: sgtl5000-oscillator { clock-frequency = <24576000>; }; - vcc3v3_baseboard: vcc3v3-baseboard-regulator { + vcc3v3_baseboard: regulator-vcc3v3-baseboard { compatible = "regulator-fixed"; regulator-name = "vcc3v3_baseboard"; regulator-always-on; @@ -94,7 +106,7 @@ vcc3v3_baseboard: vcc3v3-baseboard-regulator { vin-supply = <&dc_12v>; }; - vcc3v3_low_noise: vcc3v3-low-noise-regulator { + vcc3v3_low_noise: regulator-vcc3v3-low-noise { compatible = "regulator-fixed"; regulator-name = "vcc3v3_low_noise"; regulator-boot-on; @@ -103,7 +115,7 @@ vcc3v3_low_noise: vcc3v3-low-noise-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_baseboard: vcc5v0-baseboard-regulator { + vcc5v0_baseboard: regulator-vcc5v0-baseboard { compatible = "regulator-fixed"; regulator-name = "vcc5v0_baseboard"; regulator-always-on; @@ -113,7 +125,7 @@ vcc5v0_baseboard: vcc5v0-baseboard-regulator { vin-supply = <&dc_12v>; }; - vcc5v0_otg: vcc5v0-otg-regulator { + vcc5v0_otg: regulator-vcc5v0-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio1 RK_PB5 GPIO_ACTIVE_HIGH>; @@ -123,7 +135,7 @@ vcc5v0_otg: vcc5v0-otg-regulator { regulator-always-on; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -133,7 +145,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&dc_12v>; }; - vddd_audio_1v6: vddd-audio-1v6-regulator { + vddd_audio_1v6: regulator-vddd-audio-1v6 { compatible = "regulator-fixed"; regulator-name = "vddd_audio_1v6"; regulator-boot-on; @@ -155,6 +167,32 @@ &gmac0 { status = "okay"; }; +&hdmi0 { + /* + * While HDMI-CEC is present on the Q7 connector, it is not + * connected on Haikou itself. + */ + pinctrl-names = "default"; + pinctrl-0 = <&hdmim0_tx0_hpd &hdmim1_tx0_scl &hdmim1_tx0_sda>; + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c1 { status = "okay"; @@ -321,3 +359,18 @@ &usb_host1_xhci { &usb_host2_xhci { status = "okay"; }; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi index 615094bb8ba380..81a6a05ce13b68 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi @@ -12,6 +12,7 @@ / { compatible = "tsd,rk3588-tiger", "rockchip,rk3588"; aliases { + i2c10 = &i2c10; mmc0 = &sdhci; rtc0 = &rtc_twi; }; @@ -64,7 +65,7 @@ pcie_refclk: pcie-refclk-clock { enable-gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>; /* PCIE30X4_CLKREQN_M1_L */ }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; @@ -74,7 +75,7 @@ vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc_1v2_s3: vcc-1v2-s3-regulator { + vcc_1v2_s3: regulator-vcc-1v2-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v2_s3"; regulator-always-on; @@ -84,7 +85,7 @@ vcc_1v2_s3: vcc-1v2-s3-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -152,6 +153,12 @@ &gpu { status = "okay"; }; +&hdmi0 { + pinctrl-names = "default"; + pinctrl-0 = <&hdmim1_tx0_cec &hdmim0_tx0_hpd &hdmim1_tx0_scl + &hdmim1_tx0_sda>; +}; + &i2c1 { pinctrl-0 = <&i2c1m0_xfer>; }; @@ -224,13 +231,25 @@ &i2c6 { status = "okay"; fan@18 { - compatible = "ti,amc6821"; + compatible = "tsd,mule", "ti,amc6821"; reg = <0x18>; - }; - rtc_twi: rtc@6f { - compatible = "isil,isl1208"; - reg = <0x6f>; + i2c-mux { + compatible = "tsd,mule-i2c-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2c10: i2c@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + rtc_twi: rtc@6f { + compatible = "isil,isl1208"; + reg = <0x6f>; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts index 328dcb894ccb2d..3cbee5b974700d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-toybrick-x0.dts @@ -61,7 +61,7 @@ backlight: backlight { pwms = <&pwm2 0 25000 0>; }; - pcie20_avdd0v85: pcie20-avdd0v85-regulator { + pcie20_avdd0v85: regulator-pcie20-avdd0v85 { compatible = "regulator-fixed"; regulator-name = "pcie20_avdd0v85"; regulator-always-on; @@ -71,7 +71,7 @@ pcie20_avdd0v85: pcie20-avdd0v85-regulator { vin-supply = <&vdd_0v85_s0>; }; - pcie20_avdd1v8: pcie20-avdd1v8-regulator { + pcie20_avdd1v8: regulator-pcie20-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie20_avdd1v8"; regulator-always-on; @@ -81,7 +81,7 @@ pcie20_avdd1v8: pcie20-avdd1v8-regulator { vin-supply = <&avcc_1v8_s0>; }; - pcie30_avdd0v75: pcie30-avdd0v75-regulator { + pcie30_avdd0v75: regulator-pcie30-avdd0v75 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd0v75"; regulator-always-on; @@ -91,7 +91,7 @@ pcie30_avdd0v75: pcie30-avdd0v75-regulator { vin-supply = <&avdd_0v75_s0>; }; - pcie30_avdd1v8: pcie30-avdd1v8-regulator { + pcie30_avdd1v8: regulator-pcie30-avdd1v8 { compatible = "regulator-fixed"; regulator-name = "pcie30_avdd1v8"; regulator-always-on; @@ -101,7 +101,7 @@ pcie30_avdd1v8: pcie30-avdd1v8-regulator { vin-supply = <&avcc_1v8_s0>; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -110,7 +110,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>; @@ -124,7 +124,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -134,7 +134,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usbdcin: vcc5v0-usbdcin-regulator { + vcc5v0_usbdcin: regulator-vcc5v0-usbdcin { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usbdcin"; regulator-always-on; @@ -144,7 +144,7 @@ vcc5v0_usbdcin: vcc5v0-usbdcin-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -154,7 +154,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&vcc5v0_usbdcin>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi index 432133251e318b..6bc46734cc1407 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi @@ -33,7 +33,7 @@ fan: pwm-fan { #cooling-cells = <2>; }; - vcc3v3_pcie30: vcc3v3-pcie30-regulator { + vcc3v3_pcie30: regulator-vcc3v3-pcie30 { compatible = "regulator-fixed"; regulator-name = "vcc3v3_pcie30"; regulator-min-microvolt = <3300000>; @@ -45,7 +45,7 @@ vcc3v3_pcie30: vcc3v3-pcie30-regulator { startup-delay-us = <5000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -54,7 +54,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { regulator-max-microvolt = <5000000>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; @@ -116,6 +116,11 @@ &gmac1_rgmii_clk status = "okay"; }; +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0m2_xfer>; @@ -208,10 +213,63 @@ rgmii_phy: ethernet-phy@1 { }; }; +&package_thermal { + trips { + package_active1: trip-active1 { + temperature = <45000>; + hysteresis = <5000>; + type = "active"; + }; + package_active2: trip-active2 { + temperature = <50000>; + hysteresis = <5000>; + type = "active"; + }; + package_active3: trip-active3 { + temperature = <60000>; + hysteresis = <5000>; + type = "active"; + }; + package_active4: trip-active4 { + temperature = <70000>; + hysteresis = <5000>; + type = "active"; + }; + package_active5: trip-active5 { + temperature = <80000>; + hysteresis = <5000>; + type = "active"; + }; + }; + + cooling-maps { + map1 { + trip = <&package_active1>; + cooling-device = <&fan 1 1>; + }; + map2 { + trip = <&package_active2>; + cooling-device = <&fan 2 2>; + }; + map3 { + trip = <&package_active3>; + cooling-device = <&fan 3 3>; + }; + map4 { + trip = <&package_active4>; + cooling-device = <&fan 4 4>; + }; + map5 { + trip = <&package_active5>; + cooling-device = <&fan 5 5>; + }; + }; +}; + &pcie2x1l1 { linux,pci-domain = <1>; pinctrl-names = "default"; - pinctrl-0 = <&pcie2_reset>; + pinctrl-0 = <&pcie2_reset>, <&pcie30x1m1_0_clkreqn>, <&pcie30x1m1_0_waken>; reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; status = "okay"; }; @@ -223,7 +281,7 @@ &pcie30phy { &pcie3x4 { linux,pci-domain = <0>; pinctrl-names = "default"; - pinctrl-0 = <&pcie3_reset>; + pinctrl-0 = <&pcie3_reset>, <&pcie30x4m1_clkreqn>, <&pcie30x4m1_waken>; reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; vpcie3v3-supply = <&vcc3v3_pcie30>; status = "okay"; @@ -334,6 +392,17 @@ rk806_dvs3_null: dvs3-null-pins { regulators { vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 { + /* + * RK3588's GPU power domain cannot be enabled + * without this regulator active, but it + * doesn't have to be on when the GPU PD is + * disabled. Because the PD binding does not + * currently allow us to express this + * relationship, we have no choice but to do + * this instead: + */ + regulator-always-on; + regulator-boot-on; regulator-min-microvolt = <550000>; regulator-max-microvolt = <950000>; @@ -614,3 +683,68 @@ &uart9 { pinctrl-0 = <&uart9m0_xfer>; status = "okay"; }; + +/* USB 0: USB 2.0 only, OTG-capable */ +&u2phy0 { + status = "okay"; +}; + +&u2phy0_otg { + status = "okay"; +}; + +&usbdp_phy0 { + /* + * TODO: On the RK1, USBDP0 drives the DisplayPort pins and is not + * involved in this USB2-only bus. The bus controller (below) needs to + * know that it doesn't have a USB3 port so it can ignore any + * USB3-related signals. This is handled in hardware by updating the + * GRFs corresponding to that bus controller. Alas, Linux currently + * puts the code to do that in the USBDP driver, so USBDP0 must be + * enabled for now. + */ + rockchip,dp-lane-mux = <0 1 2 3>; /* "No USB lanes" */ + status = "okay"; +}; + +&usb_host0_xhci { + extcon = <&u2phy0>; + maximum-speed = "high-speed"; + status = "okay"; +}; + +/* USB 1: USB 3.0, host only */ +&u2phy1 { + status = "okay"; +}; + +&u2phy1_otg { + status = "okay"; +}; + +&usbdp_phy1 { + status = "okay"; +}; + +&usb_host1_xhci { + dr_mode = "host"; + extcon = <&u2phy1>; + status = "okay"; +}; + +/* USB 2: USB 2.0, host only */ +&u2phy2 { + status = "okay"; +}; + +&u2phy2_host { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts index 074c316a9a694f..9c394f733bbfbb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts @@ -11,6 +11,7 @@ #include #include #include +#include #include "rk3588s.dtsi" / { @@ -38,6 +39,17 @@ chosen { stdout-path = "serial2:1500000n8"; }; + hdmi-con { + compatible = "hdmi-connector"; + type = "d"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + leds: leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -75,7 +87,7 @@ sdio_pwrseq: sdio-pwrseq { reset-gpios = <&gpio0 RK_PC7 GPIO_ACTIVE_LOW>; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -84,7 +96,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -94,7 +106,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usbdcin: vcc5v0-usbdcin-regulator { + vcc5v0_usbdcin: regulator-vcc5v0-usbdcin { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usbdcin"; regulator-always-on; @@ -104,7 +116,7 @@ vcc5v0_usbdcin: vcc5v0-usbdcin-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-name = "vcc5v0_usb"; regulator-always-on; @@ -114,7 +126,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&vcc5v0_usbdcin>; }; - avdd0v85_pcie20: avdd0v85-pcie20-regulator { + avdd0v85_pcie20: regulator-avdd0v85-pcie20 { compatible = "regulator-fixed"; regulator-name = "avdd0v85_pcie20"; regulator-boot-on; @@ -124,7 +136,7 @@ avdd0v85_pcie20: avdd0v85-pcie20-regulator { vin-supply = <&vdd_0v85_s0>; }; - avdd1v8_pcie20: avdd1v8-pcie20-regulator { + avdd1v8_pcie20: regulator-avdd1v8-pcie20 { compatible = "regulator-fixed"; regulator-name = "avdd1v8_pcie20"; regulator-boot-on; @@ -134,7 +146,7 @@ avdd1v8_pcie20: avdd1v8-pcie20-regulator { vin-supply = <&avcc_1v8_s0>; }; - vcc3v3_mipi: vcc3v3-mipi-regulator { + vcc3v3_mipi: regulator-vcc3v3-mipi { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PC2 GPIO_ACTIVE_HIGH>; @@ -144,7 +156,7 @@ vcc3v3_mipi: vcc3v3-mipi-regulator { vin-supply = <&vcc_3v3_s3>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; @@ -158,7 +170,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_otg: vcc5v0-otg-regulator { + vcc5v0_otg: regulator-vcc5v0-otg { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>; @@ -172,7 +184,7 @@ vcc5v0_otg: vcc5v0-otg-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; @@ -208,6 +220,26 @@ &gpu { status = "okay"; }; +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c0 { pinctrl-0 = <&i2c0m2_xfer>; status = "okay"; @@ -815,3 +847,18 @@ &usb_host1_ehci { &usb_host1_ohci { status = "okay"; }; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588s-evb1-v10.dts new file mode 100644 index 00000000000000..bc4077575beb62 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588s-evb1-v10.dts @@ -0,0 +1,1170 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include +#include +#include +#include +#include "rk3588s.dtsi" + +/ { + model = "Rockchip RK3588S EVB1 V10 Board"; + compatible = "rockchip,rk3588s-evb1-v10", "rockchip,rk3588s"; + + aliases { + mmc0 = &sdhci; + mmc1 = &sdmmc; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + + button-escape { + label = "Escape"; + linux,code = ; + press-threshold-microvolt = <1235000>; + }; + + button-menu { + label = "Menu"; + linux,code = ; + press-threshold-microvolt = <890000>; + }; + + button-vol-up { + label = "Volume Up"; + linux,code = ; + press-threshold-microvolt = <17000>; + }; + + button-vol-down { + label = "Volume Down"; + linux,code = ; + press-threshold-microvolt = <417000>; + }; + }; + + amp_headphone: amplifier-headphone { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&headphone_amplifier_en>; + sound-name-prefix = "Headphones Amplifier"; + }; + + amp_speaker: amplifier-speaker { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&speaker_amplifier_en>; + sound-name-prefix = "Speaker Amplifier"; + }; + + analog-sound { + compatible = "simple-audio-card"; + pinctrl-names = "default"; + pinctrl-0 = <&hp_detect>; + simple-audio-card,name = "RK3588 EVB1 Audio"; + simple-audio-card,aux-devs = <&_headphone>, <&_speaker>; + simple-audio-card,bitclock-master = <&masterdai>; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&masterdai>; + simple-audio-card,hp-det-gpio = <&gpio1 RK_PD0 GPIO_ACTIVE_LOW>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,pin-switches = "Headphones", "Speaker"; + simple-audio-card,routing = + "Speaker Amplifier INL", "LOUT2", + "Speaker Amplifier INR", "ROUT2", + "Speaker", "Speaker Amplifier OUTL", + "Speaker", "Speaker Amplifier OUTR", + "Headphones Amplifier INL", "LOUT1", + "Headphones Amplifier INR", "ROUT1", + "Headphones", "Headphones Amplifier OUTL", + "Headphones", "Headphones Amplifier OUTR", + "LINPUT1", "Onboard Microphone", + "RINPUT1", "Onboard Microphone", + "LINPUT2", "Microphone Jack", + "RINPUT2", "Microphone Jack"; + simple-audio-card,widgets = + "Microphone", "Microphone Jack", + "Microphone", "Onboard Microphone", + "Headphone", "Headphones", + "Speaker", "Speaker"; + + simple-audio-card,cpu { + sound-dai = <&i2s0_8ch>; + }; + + masterdai: simple-audio-card,codec { + sound-dai = <&es8388>; + system-clock-frequency = <12288000>; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + power-supply = <&vcc3v3_lcd_edp>; + pwms = <&pwm12 0 25000 0>; + }; + + combophy_avdd0v85: regulator-combophy-avdd0v85 { + compatible = "regulator-fixed"; + regulator-name = "combophy_avdd0v85"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + vin-supply = <&vdd_0v85_s0>; + }; + + combophy_avdd1v8: regulator-combophy-avdd1v8 { + compatible = "regulator-fixed"; + regulator-name = "combophy_avdd1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&avcc_1v8_s0>; + }; + + vbus5v0_typec: regulator-vbus5v0-typec { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&typec5v_pwren>; + regulator-name = "vbus5v0_typec"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usb>; + }; + + vcc12v_dcin: regulator-vcc12v-dcin { + compatible = "regulator-fixed"; + regulator-name = "vcc12v_dcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc3v3_lcd_edp: regulator-vcc3v3-lcd-edp { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio1 RK_PA5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc3v3_lcd_edp_en>; + regulator-name = "vcc3v3_lcd_edp"; + regulator-boot-on; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc3v3_pcie20: regulator-vcc3v3-pcie20 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc3v3_pcie20_en>; + regulator-name = "vcc3v3_pcie20"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + startup-delay-us = <5000>; + vin-supply = <&vcc12v_dcin>; + }; + + vcc5v0_host: regulator-vcc5v0-host { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_host_en>; + regulator-name = "vcc5v0_host"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usb>; + }; + + vcc5v0_sys: regulator-vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; + + vcc5v0_usb: regulator-vcc5v0-usb { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usbdcin>; + }; + + vcc5v0_usbdcin: regulator-vcc5v0-usbdcin { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usbdcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +&i2c3 { + status = "okay"; + + es8388: audio-codec@11 { + compatible = "everest,es8388"; + reg = <0x11>; + clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clock-rates = <12288000>; + AVDD-supply = <&avcc_1v8_s0>; + DVDD-supply = <&avcc_1v8_s0>; + HPVDD-supply = <&vcc_3v3_s0>; + PVDD-supply = <&vcc_3v3_s0>; + #sound-dai-cells = <0>; + }; +}; + +&i2c8 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c8m2_xfer>; + status = "okay"; + + usbc0: usb-typec@22 { + compatible = "fcs,fusb302"; + reg = <0x22>; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&usbc0_int>; + vbus-supply = <&vbus5v0_typec>; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + op-sink-microwatt = <1000000>; + power-role = "dual"; + sink-pdos = + ; + source-pdos = + ; + try-power-role = "source"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usbc0_orien_sw: endpoint { + remote-endpoint = <&usbdp_phy0_orientation_switch>; + }; + }; + + port@1 { + reg = <1>; + + usbc0_role_sw: endpoint { + remote-endpoint = <&dwc3_0_role_switch>; + }; + }; + + port@2 { + reg = <2>; + + dp_altmode_mux: endpoint { + remote-endpoint = <&usbdp_phy0_dp_altmode_mux>; + }; + }; + }; + }; + }; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "hym8563"; + pinctrl-names = "default"; + pinctrl-0 = <&hym8563_int>; + interrupt-parent = <&gpio0>; + interrupts = ; + wakeup-source; + }; +}; + +&pcie2x1l1 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_1_rst>; + reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_pcie20>; + status = "okay"; +}; + +&pcie2x1l2 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_2_rst>; + reset-gpios = <&gpio4 RK_PC1 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&pinctrl { + audio { + hp_detect: headphone-detect { + rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + headphone_amplifier_en: headphone-amplifier-en { + rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + speaker_amplifier_en: speaker-amplifier-en { + rockchip,pins = <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + hym8563 { + hym8563_int: hym8563-int { + rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + lcd-edp { + vcc3v3_lcd_edp_en: vcc3v3-lcd-edp-en { + rockchip,pins = <1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pcie2 { + pcie2_1_rst: pcie2-1-rst { + rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + pcie2_2_rst: pcie2-2-rst { + rockchip,pins = <4 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + vcc3v3_pcie20_en: vcc3v3-pcie20-en { + rockchip,pins = <4 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + vcc5v0_host_en: vcc5v0-host-en { + rockchip,pins = <1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb-typec { + typec5v_pwren: typec5v-pwren { + rockchip,pins = <1 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + usbc0_int: usbc0-int { + rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm12 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + no-sdio; + no-sd; + non-removable; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; + disable-wp; + max-frequency = <150000000>; + no-mmc; + no-sdio; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_sd_s0>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&spi2 { + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <2>; + status = "okay"; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0x0>; + #gpio-cells = <2>; + gpio-controller; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + system-power-controller; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc5v0_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc5v0_sys>; + vcc13-supply = <&vcc5v0_sys>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcc5v0_sys>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: dcdc-reg1 { + regulator-name = "vdd_gpu_s0"; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_npu_s0: dcdc-reg2 { + regulator-name = "vdd_npu_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_log_s0: dcdc-reg3 { + regulator-name = "vdd_log_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: dcdc-reg4 { + regulator-name = "vdd_vdenc_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_gpu_mem_s0: dcdc-reg5 { + regulator-name = "vdd_gpu_mem_s0"; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_npu_mem_s0: dcdc-reg6 { + regulator-name = "vdd_npu_mem_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-name = "vdd_2v0_pldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vdd_vdenc_mem_s0: dcdc-reg8 { + regulator-name = "vdd_vdenc_mem_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd2_ddr_s3: dcdc-reg9 { + regulator-name = "vdd2_ddr_s3"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_1v1_nldo_s3: dcdc-reg10 { + regulator-name = "vcc_1v1_nldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1100000>; + }; + }; + + avcc_1v8_s0: pldo-reg1 { + regulator-name = "avcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd1_1v8_ddr_s3: pldo-reg2 { + regulator-name = "vdd1_1v8_ddr_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_1v8_s3: pldo-reg3 { + regulator-name = "vcc_1v8_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_3v3_s0: pldo-reg4 { + regulator-name = "vcc_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-name = "vccio_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + master_pldo6_s3: pldo-reg6 { + regulator-name = "master_pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-name = "vdd_0v75_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd2l_0v9_ddr_s3: nldo-reg2 { + regulator-name = "vdd2l_0v9_ddr_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + master_nldo3: nldo-reg3 { + regulator-name = "master_nldo3"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + avdd_0v75_s0: nldo-reg4 { + regulator-name = "avdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v85_s0: nldo-reg5 { + regulator-name = "vdd_0v85_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; + + pmic@1 { + compatible = "rockchip,rk806"; + reg = <0x01>; + #gpio-cells = <2>; + gpio-controller; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&rk806_slave_dvs1_null>, <&rk806_slave_dvs2_null>, + <&rk806_slave_dvs3_null>; + spi-max-frequency = <1000000>; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc5v0_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc5v0_sys>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_2v0_pldo_s3>; + vcca-supply = <&vcc5v0_sys>; + + rk806_slave_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_slave_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_slave_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_cpu_big1_s0: dcdc-reg1 { + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-coupled-with = <&vdd_cpu_big1_mem_s0>; + regulator-coupled-max-spread = <10000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big0_s0: dcdc-reg2 { + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-coupled-with = <&vdd_cpu_big0_mem_s0>; + regulator-coupled-max-spread = <10000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: dcdc-reg3 { + regulator-name = "vdd_cpu_lit_s0"; + regulator-always-on; + regulator-boot-on; + regulator-coupled-with = <&vdd_cpu_lit_mem_s0>; + regulator-coupled-max-spread = <10000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3_s3: dcdc-reg4 { + regulator-name = "vcc_3v3_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vdd_cpu_big1_mem_s0: dcdc-reg5 { + regulator-name = "vdd_cpu_big1_mem_s0"; + regulator-always-on; + regulator-boot-on; + regulator-coupled-with = <&vdd_cpu_big1_s0>; + regulator-coupled-max-spread = <10000>; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + + vdd_cpu_big0_mem_s0: dcdc-reg6 { + regulator-name = "vdd_cpu_big0_mem_s0"; + regulator-always-on; + regulator-boot-on; + regulator-coupled-with = <&vdd_cpu_big0_s0>; + regulator-coupled-max-spread = <10000>; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s0: dcdc-reg7 { + regulator-name = "vcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_mem_s0: dcdc-reg8 { + regulator-name = "vdd_cpu_lit_mem_s0"; + regulator-always-on; + regulator-boot-on; + regulator-coupled-with = <&vdd_cpu_lit_s0>; + regulator-coupled-max-spread = <10000>; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-name = "vddq_ddr_s0"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg10 { + regulator-name = "vdd_ddr_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_cam_s0: pldo-reg1 { + regulator-name = "vcc_1v8_cam_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + avdd1v8_ddr_pll_s0: pldo-reg2 { + regulator-name = "avdd1v8_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_1v8_pll_s0: pldo-reg3 { + regulator-name = "vdd_1v8_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3_sd_s0: pldo-reg4 { + regulator-name = "vcc_3v3_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_2v8_cam_s0: pldo-reg5 { + regulator-name = "vcc_2v8_cam_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-name = "pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_pll_s0: nldo-reg1 { + regulator-name = "vdd_0v75_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_pll_s0: nldo-reg2 { + regulator-name = "vdd_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + slave_nldo3: nldo-reg3 { + regulator-name = "slave_nldo3"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + avdd_1v2_cam_s0: nldo-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-ramp-delay = <12500>; + regulator-name = "avdd_1v2_cam_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + avdd_1v2_s0: nldo-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-ramp-delay = <12500>; + regulator-name = "avdd_1v2_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy0_otg { + status = "okay"; +}; + +&u2phy2_host { + phy-supply = <&vcc5v0_host>; + status = "okay"; +}; + +&u2phy3_host { + phy-supply = <&vcc5v0_host>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host0_xhci { + usb-role-switch; + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + dwc3_0_role_switch: endpoint@0 { + reg = <0>; + remote-endpoint = <&usbc0_role_sw>; + }; + }; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usbdp_phy0 { + mode-switch; + orientation-switch; + sbu1-dc-gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>; + sbu2-dc-gpios = <&gpio1 RK_PB7 GPIO_ACTIVE_HIGH>; + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + usbdp_phy0_orientation_switch: endpoint@0 { + reg = <0>; + remote-endpoint = <&usbc0_orien_sw>; + }; + + usbdp_phy0_dp_altmode_mux: endpoint@1 { + reg = <1>; + remote-endpoint = <&dp_altmode_mux>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts index 467f69594089bf..812bba0aef1a8b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-gameforce-ace.dts @@ -122,7 +122,7 @@ analog-sound { simple-audio-card,bitclock-master = <&masterdai>; simple-audio-card,format = "i2s"; simple-audio-card,frame-master = <&masterdai>; - simple-audio-card,hp-det-gpio = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>; + simple-audio-card,hp-det-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>; simple-audio-card,mclk-fs = <256>; simple-audio-card,name = "rockchip,es8388-codec"; simple-audio-card,pin-switches = "Headphones", "Speaker"; @@ -346,7 +346,7 @@ amp_speaker: speaker-amplifier { VCC-supply = <&vcc5v0_spk>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -356,7 +356,7 @@ vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc3v3_lcd0_n: vcc3v3-lcd0-n-regulator { + vcc3v3_lcd0_n: regulator-vcc3v3-lcd0-n { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; @@ -371,7 +371,7 @@ regulator-state-mem { }; }; - vcc_3v3_sd_s0: vcc-3v3-sd-s0-regulator { + vcc_3v3_sd_s0: regulator-vcc-3v3-sd-s0 { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>; @@ -383,7 +383,7 @@ vcc_3v3_sd_s0: vcc-3v3-sd-s0-regulator { vin-supply = <&vcc_3v3_s3>; }; - vcc5v0_spk: vcc5v0-spk-regulator { + vcc5v0_spk: regulator-vcc5v0-spk { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; @@ -398,7 +398,7 @@ regulator-state-mem { }; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts index 8ba111d9283fef..4a3aa80f2226fd 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "rk3588s.dtsi" @@ -50,6 +51,17 @@ chosen { stdout-path = "serial2:1500000n8"; }; + hdmi0-con { + compatible = "hdmi-connector"; + type = "d"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + sdio_pwrseq: sdio-pwrseq { compatible = "mmc-pwrseq-simple"; clock-names = "ext_clock"; @@ -62,7 +74,7 @@ sdio_pwrseq: sdio-pwrseq { sound { compatible = "audio-graph-card"; - label = "rockchip,es8388-codec"; + label = "rockchip,es8388"; widgets = "Microphone", "Mic Jack", "Headphone", "Headphones"; routing = "LINPUT2", "Mic Jack", @@ -71,7 +83,7 @@ sound { dais = <&i2s0_8ch_p0>; }; - vbus5v0_typec: vbus5v0-typec-regulator { + vbus5v0_typec: regulator-vbus5v0-typec { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; @@ -83,7 +95,7 @@ vbus5v0_typec: vbus5v0-typec-regulator { vin-supply = <&vcc5v0_usb>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -94,7 +106,7 @@ vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { }; /* Regulator is enabled whenever vcc_1v8_s0 is above 1.6v */ - vcc_3v3_s0: vcc-3v3-s0-regulator { + vcc_3v3_s0: regulator-vcc-3v3-s0 { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -108,7 +120,7 @@ regulator-state-mem { }; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -117,7 +129,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { regulator-name = "vcc5v0_sys"; }; - vcc5v0_usb: vcc5v0-usb-regulator { + vcc5v0_usb: regulator-vcc5v0-usb { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -127,7 +139,7 @@ vcc5v0_usb: vcc5v0-usb-regulator { vin-supply = <&vcc5v0_usbdcin>; }; - vcc5v0_usbdcin: vcc5v0-usbdcin-regulator { + vcc5v0_usbdcin: regulator-vcc5v0-usbdcin { compatible = "regulator-fixed"; regulator-always-on; regulator-boot-on; @@ -242,6 +254,34 @@ &gpio4 { "", "", "", ""; }; +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&hdmi0 { + pinctrl-0 = <&hdmim0_tx0_scl>, <&hdmim0_tx0_sda>, + <&hdmim0_tx0_hpd>, <&hdmim0_tx0_cec>; + pinctrl-names = "default"; + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c0 { pinctrl-0 = <&i2c0m2_xfer>; pinctrl-names = "default"; @@ -918,3 +958,18 @@ usbdp_phy0_dp_altmode_mux: endpoint@1 { }; }; }; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts index dbddfc3bb46417..ac48e7fd3923f4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts @@ -76,7 +76,7 @@ blue_led: led-2 { }; }; - vcc3v3_pcie_wl: vcc3v3-pcie-wl-regulator { + vcc3v3_pcie_wl: regulator-vcc3v3-pcie-wl { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>; @@ -89,7 +89,7 @@ vcc3v3_pcie_wl: vcc3v3-pcie-wl-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; regulator-boot-on; @@ -103,7 +103,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -112,7 +112,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { regulator-max-microvolt = <5000000>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; @@ -122,7 +122,7 @@ vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { vin-supply = <&vcc5v0_sys>; }; - vdd_3v3_sd: vdd-3v3-sd-regulator { + vdd_3v3_sd: regulator-vdd-3v3-sd { compatible = "regulator-fixed"; regulator-name = "vdd_3v3_sd"; gpios = <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>; @@ -283,6 +283,22 @@ &pcie2x1l2 { reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; vpcie3v3-supply = <&vcc3v3_pcie_wl>; status = "okay"; + + pcie@0,0 { + reg = <0x400000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + device_type = "pci"; + bus-range = <0x40 0x4f>; + + wifi: wifi@0,0 { + compatible = "pci14e4,449d"; + reg = <0x410000 0 0 0 0>; + clocks = <&hym8563>; + clock-names = "lpo"; + }; + }; }; &pwm11 { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi new file mode 100644 index 00000000000000..76a6e8e517e948 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6.dtsi @@ -0,0 +1,812 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include +#include "rk3588s.dtsi" + +/ { + aliases { + ethernet0 = &gmac1; + mmc0 = &sdmmc; + mmc1 = &sdhci; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + + button-maskrom { + label = "Maskrom"; + linux,code = ; + press-threshold-microvolt = <1800>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key1_pin>; + + button-user { + label = "User"; + linux,code = ; + gpios = <&gpio1 RK_PC0 GPIO_ACTIVE_LOW>; + debounce-interval = <50>; + }; + }; + + hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + sys_led: led-0 { + label = "sys_led"; + gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + pinctrl-names = "default"; + pinctrl-0 = <&sys_led_pin>; + }; + + wan_led: led-1 { + label = "wan_led"; + gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&wan_led_pin>; + }; + + lan1_led: led-2 { + label = "lan1_led"; + gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lan1_led_pin>; + }; + + lan2_led: led-3 { + gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lan2_led_pin>; + }; + }; + + vcc5v0_sys: regulator-vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc_3v3_s0: regulator-vcc-3v3-s0 { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_3v3_s0"; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc_3v3_sd_s0: regulator-vcc-3v3-sd-s0 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&sd_s0_pwr>; + regulator-name = "vcc_3v3_sd_s0"; + regulator-boot-on; + regulator-max-microvolt = <3000000>; + regulator-min-microvolt = <3000000>; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc_3v3_pcie20: regulator-vcc3v3-pcie20 { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_pcie20"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc5v0_usb: regulator-vcc5v0-usb { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_usb_otg0: regulator-vcc5v0-usb-otg0 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&typec5v_pwren>; + regulator-name = "vcc5v0_usb_otg0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usb>; + }; + + vcc5v0_host_20: regulator-vcc5v0-host-20 { + compatible = "regulator-fixed"; + enable-active-high; + gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_host20_en>; + regulator-name = "vcc5v0_host_20"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usb>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_b3 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&gmac1 { + clock_in_out = "output"; + phy-handle = <&rgmii_phy1>; + phy-mode = "rgmii-rxid"; + pinctrl-0 = <&gmac1_miim + &gmac1_tx_bus2 + &gmac1_rx_bus2 + &gmac1_rgmii_clk + &gmac1_rgmii_bus>; + pinctrl-names = "default"; + tx_delay = <0x42>; + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c2 { + status = "okay"; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + regulator-boot-on; + regulator-always-on; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c6 { + clock-frequency = <200000>; + pinctrl-names = "default"; + pinctrl-0 = <&i2c6m0_xfer>; + status = "okay"; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "hym8563"; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_int>; + interrupt-parent = <&gpio0>; + interrupts = ; + wakeup-source; + }; +}; + +&mdio1 { + rgmii_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-id001c.c916"; + reg = <0x1>; + pinctrl-names = "default"; + pinctrl-0 = <&rtl8211f_rst>; + reset-assert-us = <20000>; + reset-deassert-us = <100000>; + reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; + }; +}; + +&pcie2x1l1 { + reset-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc_3v3_pcie20>; + status = "okay"; +}; + +&pcie2x1l2 { + reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc_3v3_pcie20>; + status = "okay"; +}; + +&pinctrl { + gpio-key { + key1_pin: key1-pin { + rockchip,pins = <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + gpio-leds { + sys_led_pin: sys-led-pin { + rockchip,pins = + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + wan_led_pin: wan-led-pin { + rockchip,pins = + <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + lan1_led_pin: lan1-led-pin { + rockchip,pins = + <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + lan2_led_pin: lan2-led-pin { + rockchip,pins = + <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + hym8563 { + rtc_int: rtc-int { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdmmc { + sd_s0_pwr: sd-s0-pwr { + rockchip,pins = <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + usb { + typec5v_pwren: typec5v-pwren { + rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + vcc5v0_host20_en: vcc5v0-host20-en { + rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + rtl8211f { + rtl8211f_rst: rtl8211f-rst { + rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&saradc { + vref-supply = <&avcc_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + no-sdio; + no-sd; + non-removable; + mmc-hs200-1_8v; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-sd-highspeed; + disable-wp; + max-frequency = <150000000>; + no-mmc; + no-sdio; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_sd_s0>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&spi2 { + status = "okay"; + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + num-cs = <1>; + + pmic@0 { + compatible = "rockchip,rk806"; + spi-max-frequency = <1000000>; + reg = <0x0>; + + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + + system-power-controller; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc5v0_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc5v0_sys>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcc5v0_sys>; + + gpio-controller; + #gpio-cells = <2>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 { + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_gpu_s0"; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_cpu_lit_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_log_s0: dcdc-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_log_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_vdenc_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_ddr_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg6 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vdd2_ddr_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_2v0_pldo_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_3v3_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vddq_ddr_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg10 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avcc_1v8_s0: pldo-reg1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "avcc_1v8_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_1v8_s0: pldo-reg2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avdd_1v2_s0: pldo-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-name = "avdd_1v2_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + avcc_3v3_s0: pldo-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + regulator-name = "avcc_3v3_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + regulator-name = "vccio_sd_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "pldo6_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "vdd_0v75_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + avdd_ddr_pll_s0: nldo-reg2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-name = "avdd_ddr_pll_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + avdd_0v75_s0: nldo-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "avdd_0v75_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + avdd_0v85_s0: nldo-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-name = "avdd_0v85_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "vdd_0v75_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy2_host { + phy-supply = <&vcc5v0_host_20>; + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dts b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dts index 497bbb57071f4e..ccc5e462751766 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6c.dts @@ -2,7 +2,7 @@ /dts-v1/; -#include "rk3588s-nanopi-r6s.dts" +#include "rk3588s-nanopi-r6.dtsi" / { model = "FriendlyElec NanoPi R6C"; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dts b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dts index 4fa644ae510ca2..9c3e0b0daaacb9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-nanopi-r6s.dts @@ -2,763 +2,13 @@ /dts-v1/; -#include -#include -#include -#include "rk3588s.dtsi" +#include "rk3588s-nanopi-r6.dtsi" / { model = "FriendlyElec NanoPi R6S"; compatible = "friendlyarm,nanopi-r6s", "rockchip,rk3588s"; - - aliases { - ethernet0 = &gmac1; - mmc0 = &sdmmc; - mmc1 = &sdhci; - }; - - chosen { - stdout-path = "serial2:1500000n8"; - }; - - adc-keys { - compatible = "adc-keys"; - io-channels = <&saradc 0>; - io-channel-names = "buttons"; - keyup-threshold-microvolt = <1800000>; - poll-interval = <100>; - - button-maskrom { - label = "Maskrom"; - linux,code = ; - press-threshold-microvolt = <1800>; - }; - }; - - gpio-keys { - compatible = "gpio-keys"; - pinctrl-names = "default"; - pinctrl-0 = <&key1_pin>; - - button-user { - label = "User"; - linux,code = ; - gpios = <&gpio1 RK_PC0 GPIO_ACTIVE_LOW>; - debounce-interval = <50>; - }; - }; - - leds { - compatible = "gpio-leds"; - - sys_led: led-0 { - label = "sys_led"; - gpios = <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "heartbeat"; - pinctrl-names = "default"; - pinctrl-0 = <&sys_led_pin>; - }; - - wan_led: led-1 { - label = "wan_led"; - gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&wan_led_pin>; - }; - - lan1_led: led-2 { - label = "lan1_led"; - gpios = <&gpio1 RK_PC3 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&lan1_led_pin>; - }; - - lan2_led: led-3 { - label = "lan2_led"; - gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&lan2_led_pin>; - }; - }; - - vcc5v0_sys: vcc5v0-sys-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc5v0_sys"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc_1v1_nldo_s3"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <1100000>; - vin-supply = <&vcc5v0_sys>; - }; - - vcc_3v3_s0: vcc-3v3-s0-regulator { - compatible = "regulator-fixed"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vcc_3v3_s0"; - vin-supply = <&vcc_3v3_s3>; - }; - - vcc_3v3_sd_s0: vcc-3v3-sd-s0-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&sd_s0_pwr>; - regulator-name = "vcc_3v3_sd_s0"; - regulator-boot-on; - regulator-max-microvolt = <3000000>; - regulator-min-microvolt = <3000000>; - vin-supply = <&vcc_3v3_s3>; - }; - - vcc_3v3_pcie20: vcc3v3-pcie20-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc_3v3_pcie20"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - vin-supply = <&vcc_3v3_s3>; - }; - - vcc5v0_usb: vcc5v0-usb-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc5v0_usb"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - vin-supply = <&vcc5v0_sys>; - }; - - vcc5v0_usb_otg0: vcc5v0-usb-otg0-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&typec5v_pwren>; - regulator-name = "vcc5v0_usb_otg0"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - vin-supply = <&vcc5v0_usb>; - }; - - vcc5v0_host_20: vcc5v0-host-20-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&vcc5v0_host20_en>; - regulator-name = "vcc5v0_host_20"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - vin-supply = <&vcc5v0_usb>; - }; -}; - -&combphy0_ps { - status = "okay"; -}; - -&combphy2_psu { - status = "okay"; -}; - -&cpu_b0 { - cpu-supply = <&vdd_cpu_big0_s0>; -}; - -&cpu_b1 { - cpu-supply = <&vdd_cpu_big0_s0>; -}; - -&cpu_b2 { - cpu-supply = <&vdd_cpu_big1_s0>; -}; - -&cpu_b3 { - cpu-supply = <&vdd_cpu_big1_s0>; -}; - -&cpu_l0 { - cpu-supply = <&vdd_cpu_lit_s0>; -}; - -&cpu_l1 { - cpu-supply = <&vdd_cpu_lit_s0>; -}; - -&cpu_l2 { - cpu-supply = <&vdd_cpu_lit_s0>; -}; - -&cpu_l3 { - cpu-supply = <&vdd_cpu_lit_s0>; -}; - -&gmac1 { - clock_in_out = "output"; - phy-handle = <&rgmii_phy1>; - phy-mode = "rgmii-rxid"; - pinctrl-0 = <&gmac1_miim - &gmac1_tx_bus2 - &gmac1_rx_bus2 - &gmac1_rgmii_clk - &gmac1_rgmii_bus>; - pinctrl-names = "default"; - tx_delay = <0x42>; - status = "okay"; -}; - -&i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; - status = "okay"; - - vdd_cpu_big0_s0: regulator@42 { - compatible = "rockchip,rk8602"; - reg = <0x42>; - fcs,suspend-voltage-selector = <1>; - regulator-name = "vdd_cpu_big0_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <2300>; - vin-supply = <&vcc5v0_sys>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_cpu_big1_s0: regulator@43 { - compatible = "rockchip,rk8603", "rockchip,rk8602"; - reg = <0x43>; - fcs,suspend-voltage-selector = <1>; - regulator-name = "vdd_cpu_big1_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <2300>; - vin-supply = <&vcc5v0_sys>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; -}; - -&i2c2 { - status = "okay"; - - vdd_npu_s0: regulator@42 { - compatible = "rockchip,rk8602"; - reg = <0x42>; - fcs,suspend-voltage-selector = <1>; - regulator-name = "vdd_npu_s0"; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <2300>; - regulator-boot-on; - regulator-always-on; - vin-supply = <&vcc5v0_sys>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; -}; - -&i2c6 { - clock-frequency = <200000>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c6m0_xfer>; - status = "okay"; - - hym8563: rtc@51 { - compatible = "haoyu,hym8563"; - reg = <0x51>; - #clock-cells = <0>; - clock-output-names = "hym8563"; - pinctrl-names = "default"; - pinctrl-0 = <&rtc_int>; - interrupt-parent = <&gpio0>; - interrupts = ; - wakeup-source; - }; -}; - -&mdio1 { - rgmii_phy1: ethernet-phy@1 { - compatible = "ethernet-phy-id001c.c916"; - reg = <0x1>; - pinctrl-names = "default"; - pinctrl-0 = <&rtl8211f_rst>; - reset-assert-us = <20000>; - reset-deassert-us = <100000>; - reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; - }; -}; - -&pcie2x1l1 { - reset-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; - vpcie3v3-supply = <&vcc_3v3_pcie20>; - status = "okay"; -}; - -&pcie2x1l2 { - reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; - vpcie3v3-supply = <&vcc_3v3_pcie20>; - status = "okay"; -}; - -&pinctrl { - gpio-key { - key1_pin: key1-pin { - rockchip,pins = <1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; - - gpio-leds { - sys_led_pin: sys-led-pin { - rockchip,pins = - <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - wan_led_pin: wan-led-pin { - rockchip,pins = - <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - lan1_led_pin: lan1-led-pin { - rockchip,pins = - <1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - lan2_led_pin: lan2-led-pin { - rockchip,pins = - <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - hym8563 { - rtc_int: rtc-int { - rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; - - sdmmc { - sd_s0_pwr: sd-s0-pwr { - rockchip,pins = <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>; - }; - }; - - usb { - typec5v_pwren: typec5v-pwren { - rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - - vcc5v0_host20_en: vcc5v0-host20-en { - rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - rtl8211f { - rtl8211f_rst: rtl8211f-rst { - rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; -}; - -&saradc { - vref-supply = <&avcc_1v8_s0>; - status = "okay"; -}; - -&sdhci { - bus-width = <8>; - no-sdio; - no-sd; - non-removable; - mmc-hs200-1_8v; - status = "okay"; -}; - -&sdmmc { - bus-width = <4>; - cap-sd-highspeed; - disable-wp; - max-frequency = <150000000>; - no-mmc; - no-sdio; - sd-uhs-sdr104; - vmmc-supply = <&vcc_3v3_sd_s0>; - vqmmc-supply = <&vccio_sd_s0>; - status = "okay"; -}; - -&spi2 { - status = "okay"; - assigned-clocks = <&cru CLK_SPI2>; - assigned-clock-rates = <200000000>; - pinctrl-names = "default"; - pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; - num-cs = <1>; - - pmic@0 { - compatible = "rockchip,rk806"; - spi-max-frequency = <1000000>; - reg = <0x0>; - - interrupt-parent = <&gpio0>; - interrupts = <7 IRQ_TYPE_LEVEL_LOW>; - - pinctrl-names = "default"; - pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, - <&rk806_dvs2_null>, <&rk806_dvs3_null>; - - system-power-controller; - - vcc1-supply = <&vcc5v0_sys>; - vcc2-supply = <&vcc5v0_sys>; - vcc3-supply = <&vcc5v0_sys>; - vcc4-supply = <&vcc5v0_sys>; - vcc5-supply = <&vcc5v0_sys>; - vcc6-supply = <&vcc5v0_sys>; - vcc7-supply = <&vcc5v0_sys>; - vcc8-supply = <&vcc5v0_sys>; - vcc9-supply = <&vcc5v0_sys>; - vcc10-supply = <&vcc5v0_sys>; - vcc11-supply = <&vcc_2v0_pldo_s3>; - vcc12-supply = <&vcc5v0_sys>; - vcc13-supply = <&vcc_1v1_nldo_s3>; - vcc14-supply = <&vcc_1v1_nldo_s3>; - vcca-supply = <&vcc5v0_sys>; - - gpio-controller; - #gpio-cells = <2>; - - rk806_dvs1_null: dvs1-null-pins { - pins = "gpio_pwrctrl1"; - function = "pin_fun0"; - }; - - rk806_dvs2_null: dvs2-null-pins { - pins = "gpio_pwrctrl2"; - function = "pin_fun0"; - }; - - rk806_dvs3_null: dvs3-null-pins { - pins = "gpio_pwrctrl3"; - function = "pin_fun0"; - }; - - regulators { - vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 { - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; - regulator-name = "vdd_gpu_s0"; - regulator-enable-ramp-delay = <400>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; - regulator-name = "vdd_cpu_lit_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_log_s0: dcdc-reg3 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <750000>; - regulator-ramp-delay = <12500>; - regulator-name = "vdd_log_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <750000>; - }; - }; - - vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; - regulator-name = "vdd_vdenc_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_ddr_s0: dcdc-reg5 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <900000>; - regulator-ramp-delay = <12500>; - regulator-name = "vdd_ddr_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <850000>; - }; - }; - - vdd2_ddr_s3: dcdc-reg6 { - regulator-always-on; - regulator-boot-on; - regulator-name = "vdd2_ddr_s3"; - - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_2v0_pldo_s3: dcdc-reg7 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <2000000>; - regulator-max-microvolt = <2000000>; - regulator-ramp-delay = <12500>; - regulator-name = "vdd_2v0_pldo_s3"; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <2000000>; - }; - }; - - vcc_3v3_s3: dcdc-reg8 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-name = "vcc_3v3_s3"; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vddq_ddr_s0: dcdc-reg9 { - regulator-always-on; - regulator-boot-on; - regulator-name = "vddq_ddr_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vcc_1v8_s3: dcdc-reg10 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-name = "vcc_1v8_s3"; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - avcc_1v8_s0: pldo-reg1 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-name = "avcc_1v8_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vcc_1v8_s0: pldo-reg2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-name = "vcc_1v8_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - avdd_1v2_s0: pldo-reg3 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - regulator-name = "avdd_1v2_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - avcc_3v3_s0: pldo-reg4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-ramp-delay = <12500>; - regulator-name = "avcc_3v3_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vccio_sd_s0: pldo-reg5 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-ramp-delay = <12500>; - regulator-name = "vccio_sd_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - pldo6_s3: pldo-reg6 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-name = "pldo6_s3"; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd_0v75_s3: nldo-reg1 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <750000>; - regulator-name = "vdd_0v75_s3"; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <750000>; - }; - }; - - avdd_ddr_pll_s0: nldo-reg2 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <850000>; - regulator-name = "avdd_ddr_pll_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <850000>; - }; - }; - - avdd_0v75_s0: nldo-reg3 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <750000>; - regulator-name = "avdd_0v75_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - avdd_0v85_s0: nldo-reg4 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <850000>; - regulator-name = "avdd_0v85_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_0v75_s0: nldo-reg5 { - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <750000>; - regulator-name = "vdd_0v75_s0"; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - }; - }; -}; - -&tsadc { - status = "okay"; -}; - -&u2phy2 { - status = "okay"; -}; - -&u2phy2_host { - phy-supply = <&vcc5v0_host_20>; - status = "okay"; -}; - -&uart2 { - pinctrl-0 = <&uart2m0_xfer>; - status = "okay"; -}; - -&usb_host0_ehci { - status = "okay"; }; -&usb_host0_ohci { - status = "okay"; +&lan2_led { + label = "lan2_led"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts b/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts index 63d91236ba9ff9..8f034c6d494c4a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-odroid-m2.dts @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "rk3588s.dtsi" @@ -22,6 +23,17 @@ chosen { stdout-path = "serial2:1500000n8"; }; + hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -236,6 +248,26 @@ &gpu { status = "okay"; }; +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0m2_xfer>; @@ -901,3 +933,18 @@ usbdp_phy0_dp_altmode_mux: endpoint@1 { }; }; }; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts index feea6b20a6bf54..ad6d04793b0ac7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts @@ -2,85 +2,13 @@ /dts-v1/; -#include -#include -#include -#include -#include -#include "rk3588s.dtsi" +#include "rk3588s-orangepi-5.dtsi" / { model = "Xunlong Orange Pi 5"; compatible = "xunlong,orangepi-5", "rockchip,rk3588s"; - aliases { - ethernet0 = &gmac1; - mmc0 = &sdmmc; - }; - - chosen { - stdout-path = "serial2:1500000n8"; - }; - - adc-keys { - compatible = "adc-keys"; - io-channels = <&saradc 1>; - io-channel-names = "buttons"; - keyup-threshold-microvolt = <1800000>; - poll-interval = <100>; - - button-recovery { - label = "Recovery"; - linux,code = ; - press-threshold-microvolt = <1800>; - }; - }; - - leds { - compatible = "gpio-leds"; - pinctrl-names = "default"; - pinctrl-0 = <&leds_gpio>; - - led-1 { - gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_HIGH>; - label = "status_led"; - linux,default-trigger = "heartbeat"; - }; - }; - - vbus_typec: vbus-typec-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&typec5v_pwren>; - regulator-name = "vbus_typec"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - vin-supply = <&vcc5v0_sys>; - }; - - vcc5v0_sys: vcc5v0-sys-regulator { - compatible = "regulator-fixed"; - regulator-name = "vcc5v0_sys"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - }; - - vcc_3v3_sd_s0: vcc-3v3-sd-s0-regulator { - compatible = "regulator-fixed"; - enable-active-low; - gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_LOW>; - regulator-name = "vcc_3v3_sd_s0"; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - vin-supply = <&vcc_3v3_s3>; - }; - - vcc3v3_pcie20: vcc3v3-pcie20-regulator { + vcc3v3_pcie20: regulator-vcc3v3-pcie20 { compatible = "regulator-fixed"; enable-active-high; gpios = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; @@ -93,674 +21,12 @@ vcc3v3_pcie20: vcc3v3-pcie20-regulator { }; }; -&combphy0_ps { - status = "okay"; -}; - -&combphy2_psu { - status = "okay"; -}; - -&cpu_b0 { - cpu-supply = <&vdd_cpu_big0_s0>; -}; - -&cpu_b1 { - cpu-supply = <&vdd_cpu_big0_s0>; -}; - -&cpu_b2 { - cpu-supply = <&vdd_cpu_big1_s0>; -}; - -&cpu_b3 { - cpu-supply = <&vdd_cpu_big1_s0>; -}; - -&cpu_l0 { - cpu-supply = <&vdd_cpu_lit_s0>; -}; - -&cpu_l1 { - cpu-supply = <&vdd_cpu_lit_s0>; -}; - -&cpu_l2 { - cpu-supply = <&vdd_cpu_lit_s0>; -}; - -&cpu_l3 { - cpu-supply = <&vdd_cpu_lit_s0>; -}; - -&gmac1 { - clock_in_out = "output"; - phy-handle = <&rgmii_phy1>; - phy-mode = "rgmii-rxid"; - pinctrl-0 = <&gmac1_miim - &gmac1_tx_bus2 - &gmac1_rx_bus2 - &gmac1_rgmii_clk - &gmac1_rgmii_bus>; - pinctrl-names = "default"; - tx_delay = <0x42>; - status = "okay"; -}; - -&gpu { - mali-supply = <&vdd_gpu_s0>; - status = "okay"; -}; - -&i2c0 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c0m2_xfer>; - status = "okay"; - - vdd_cpu_big0_s0: regulator@42 { - compatible = "rockchip,rk8602"; - reg = <0x42>; - fcs,suspend-voltage-selector = <1>; - regulator-name = "vdd_cpu_big0_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <2300>; - vin-supply = <&vcc5v0_sys>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_cpu_big1_s0: regulator@43 { - compatible = "rockchip,rk8603", "rockchip,rk8602"; - reg = <0x43>; - fcs,suspend-voltage-selector = <1>; - regulator-name = "vdd_cpu_big1_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <1050000>; - regulator-ramp-delay = <2300>; - vin-supply = <&vcc5v0_sys>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; -}; - -&i2c2 { - status = "okay"; - - vdd_npu_s0: regulator@42 { - compatible = "rockchip,rk8602"; - reg = <0x42>; - fcs,suspend-voltage-selector = <1>; - regulator-name = "vdd_npu_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <2300>; - vin-supply = <&vcc5v0_sys>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; -}; - -&i2c6 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c6m3_xfer>; - status = "okay"; - - usbc0: usb-typec@22 { - compatible = "fcs,fusb302"; - reg = <0x22>; - interrupt-parent = <&gpio0>; - interrupts = ; - pinctrl-names = "default"; - pinctrl-0 = <&usbc0_int>; - vbus-supply = <&vbus_typec>; - status = "okay"; - - usb_con: connector { - compatible = "usb-c-connector"; - label = "USB-C"; - data-role = "dual"; - op-sink-microwatt = <1000000>; - power-role = "dual"; - sink-pdos = - ; - source-pdos = - ; - try-power-role = "source"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - usbc0_hs: endpoint { - remote-endpoint = <&usb_host0_xhci_drd_sw>; - }; - }; - - port@1 { - reg = <1>; - usbc0_ss: endpoint { - remote-endpoint = <&usbdp_phy0_typec_ss>; - }; - }; - - port@2 { - reg = <2>; - usbc0_sbu: endpoint { - remote-endpoint = <&usbdp_phy0_typec_sbu>; - }; - }; - }; - }; - }; - - hym8563: rtc@51 { - compatible = "haoyu,hym8563"; - reg = <0x51>; - #clock-cells = <0>; - clock-output-names = "hym8563"; - pinctrl-names = "default"; - pinctrl-0 = <&hym8563_int>; - interrupt-parent = <&gpio0>; - interrupts = ; - wakeup-source; - }; -}; - -&mdio1 { - rgmii_phy1: ethernet-phy@1 { - compatible = "ethernet-phy-ieee802.3-c22"; - reg = <0x1>; - reset-assert-us = <20000>; - reset-deassert-us = <100000>; - reset-gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>; - }; -}; - &pcie2x1l2 { reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; vpcie3v3-supply = <&vcc3v3_pcie20>; status = "okay"; }; -&pinctrl { - gpio-func { - leds_gpio: leds-gpio { - rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - hym8563 { - hym8563_int: hym8563-int { - rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - - usb-typec { - usbc0_int: usbc0-int { - rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; - }; - - typec5v_pwren: typec5v-pwren { - rockchip,pins = <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; -}; - -&saradc { - vref-supply = <&avcc_1v8_s0>; - status = "okay"; -}; - -&sdmmc { - bus-width = <4>; - cap-sd-highspeed; - disable-wp; - max-frequency = <150000000>; - no-mmc; - no-sdio; - sd-uhs-sdr104; - vmmc-supply = <&vcc_3v3_sd_s0>; - vqmmc-supply = <&vccio_sd_s0>; - status = "okay"; -}; - &sfc { - pinctrl-names = "default"; - pinctrl-0 = <&fspim0_pins>; - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0x0>; - spi-max-frequency = <100000000>; - spi-rx-bus-width = <4>; - spi-tx-bus-width = <1>; - }; -}; - -&spi2 { - status = "okay"; - assigned-clocks = <&cru CLK_SPI2>; - assigned-clock-rates = <200000000>; - num-cs = <1>; - pinctrl-names = "default"; - pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; - - pmic@0 { - compatible = "rockchip,rk806"; - reg = <0x0>; - interrupt-parent = <&gpio0>; - interrupts = <7 IRQ_TYPE_LEVEL_LOW>; - pinctrl-names = "default"; - pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, - <&rk806_dvs2_null>, <&rk806_dvs3_null>; - spi-max-frequency = <1000000>; - system-power-controller; - - vcc1-supply = <&vcc5v0_sys>; - vcc2-supply = <&vcc5v0_sys>; - vcc3-supply = <&vcc5v0_sys>; - vcc4-supply = <&vcc5v0_sys>; - vcc5-supply = <&vcc5v0_sys>; - vcc6-supply = <&vcc5v0_sys>; - vcc7-supply = <&vcc5v0_sys>; - vcc8-supply = <&vcc5v0_sys>; - vcc9-supply = <&vcc5v0_sys>; - vcc10-supply = <&vcc5v0_sys>; - vcc11-supply = <&vcc_2v0_pldo_s3>; - vcc12-supply = <&vcc5v0_sys>; - vcc13-supply = <&vcc_1v1_nldo_s3>; - vcc14-supply = <&vcc_1v1_nldo_s3>; - vcca-supply = <&vcc5v0_sys>; - - gpio-controller; - #gpio-cells = <2>; - - rk806_dvs1_null: dvs1-null-pins { - pins = "gpio_pwrctrl1"; - function = "pin_fun0"; - }; - - rk806_dvs2_null: dvs2-null-pins { - pins = "gpio_pwrctrl2"; - function = "pin_fun0"; - }; - - rk806_dvs3_null: dvs3-null-pins { - pins = "gpio_pwrctrl3"; - function = "pin_fun0"; - }; - - regulators { - vdd_gpu_s0: dcdc-reg1 { - regulator-name = "vdd_gpu_s0"; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; - regulator-enable-ramp-delay = <400>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_cpu_lit_s0: dcdc-reg2 { - regulator-name = "vdd_cpu_lit_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_log_s0: dcdc-reg3 { - regulator-name = "vdd_log_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <750000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <750000>; - }; - }; - - vdd_vdenc_s0: dcdc-reg4 { - regulator-name = "vdd_vdenc_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <550000>; - regulator-max-microvolt = <950000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_ddr_s0: dcdc-reg5 { - regulator-name = "vdd_ddr_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <675000>; - regulator-max-microvolt = <900000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <850000>; - }; - }; - - vcc_1v1_nldo_s3: vdd2_ddr_s3: dcdc-reg6 { - regulator-name = "vdd2_ddr_s3"; - regulator-always-on; - regulator-boot-on; - regulator-max-microvolt = <1100000>; - regulator-min-microvolt = <1100000>; - - regulator-state-mem { - regulator-on-in-suspend; - }; - }; - - vcc_2v0_pldo_s3: dcdc-reg7 { - regulator-name = "vdd_2v0_pldo_s3"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <2000000>; - regulator-max-microvolt = <2000000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <2000000>; - }; - }; - - vcc_3v3_s3: dcdc-reg8 { - regulator-name = "vcc_3v3_s3"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <3300000>; - }; - }; - - vddq_ddr_s0: dcdc-reg9 { - regulator-name = "vddq_ddr_s0"; - regulator-always-on; - regulator-boot-on; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vcc_1v8_s3: dcdc-reg10 { - regulator-name = "vcc_1v8_s3"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - avcc_1v8_s0: pldo-reg1 { - regulator-name = "avcc_1v8_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vcc_1v8_s0: pldo-reg2 { - regulator-name = "vcc_1v8_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - avdd_1v2_s0: pldo-reg3 { - regulator-name = "avdd_1v2_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vcc_3v3_s0: pldo-reg4 { - regulator-name = "vcc_3v3_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vccio_sd_s0: pldo-reg5 { - regulator-name = "vccio_sd_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-ramp-delay = <12500>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - pldo6_s3: pldo-reg6 { - regulator-name = "pldo6_s3"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <1800000>; - }; - }; - - vdd_0v75_s3: nldo-reg1 { - regulator-name = "vdd_0v75_s3"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <750000>; - - regulator-state-mem { - regulator-on-in-suspend; - regulator-suspend-microvolt = <750000>; - }; - }; - - vdd_ddr_pll_s0: nldo-reg2 { - regulator-name = "vdd_ddr_pll_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <850000>; - - regulator-state-mem { - regulator-off-in-suspend; - regulator-suspend-microvolt = <850000>; - }; - }; - - avdd_0v75_s0: nldo-reg3 { - regulator-name = "avdd_0v75_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <750000>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_0v85_s0: nldo-reg4 { - regulator-name = "vdd_0v85_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <850000>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - - vdd_0v75_s0: nldo-reg5 { - regulator-name = "vdd_0v75_s0"; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <750000>; - - regulator-state-mem { - regulator-off-in-suspend; - }; - }; - }; - }; -}; - -&tsadc { - status = "okay"; -}; - -&u2phy0 { - status = "okay"; -}; - -&u2phy0_otg { - status = "okay"; -}; - -&u2phy2 { - status = "okay"; -}; - -&u2phy2_host { - status = "okay"; -}; - -&u2phy3 { - status = "okay"; -}; - -&u2phy3_host { - status = "okay"; -}; - -&uart2 { - pinctrl-0 = <&uart2m0_xfer>; - status = "okay"; -}; - -&usbdp_phy0 { - mode-switch; - orientation-switch; - sbu1-dc-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; - sbu2-dc-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; - status = "okay"; - - port { - #address-cells = <1>; - #size-cells = <0>; - - usbdp_phy0_typec_ss: endpoint@0 { - reg = <0>; - remote-endpoint = <&usbc0_ss>; - }; - - usbdp_phy0_typec_sbu: endpoint@1 { - reg = <1>; - remote-endpoint = <&usbc0_sbu>; - }; - }; -}; - -&usb_host0_ehci { - status = "okay"; -}; - -&usb_host0_ohci { - status = "okay"; -}; - -&usb_host0_xhci { - dr_mode = "otg"; - usb-role-switch; - status = "okay"; - - port { - usb_host0_xhci_drd_sw: endpoint { - remote-endpoint = <&usbc0_hs>; - }; - }; -}; - -&usb_host1_ehci { - status = "okay"; -}; - -&usb_host1_ohci { - status = "okay"; -}; - -&usb_host2_xhci { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi new file mode 100644 index 00000000000000..d86aeacca238d9 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dtsi @@ -0,0 +1,866 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include +#include +#include +#include "rk3588s.dtsi" + +/ { + aliases { + ethernet0 = &gmac1; + mmc0 = &sdmmc; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + + button-recovery { + label = "Recovery"; + linux,code = ; + press-threshold-microvolt = <1800>; + }; + }; + + analog-sound { + compatible = "simple-audio-card"; + pinctrl-names = "default"; + pinctrl-0 = <&hp_detect>; + simple-audio-card,name = "rockchip,es8388"; + simple-audio-card,bitclock-master = <&masterdai>; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&masterdai>; + simple-audio-card,hp-det-gpios = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,pin-switches = "Headphones"; + simple-audio-card,routing = + "Headphones", "LOUT1", + "Headphones", "ROUT1", + "LINPUT1", "Microphone Jack", + "RINPUT1", "Microphone Jack", + "LINPUT2", "Onboard Microphone", + "RINPUT2", "Onboard Microphone"; + simple-audio-card,widgets = + "Microphone", "Microphone Jack", + "Microphone", "Onboard Microphone", + "Headphone", "Headphones"; + + simple-audio-card,cpu { + sound-dai = <&i2s1_8ch>; + }; + + masterdai: simple-audio-card,codec { + sound-dai = <&es8388>; + system-clock-frequency = <12288000>; + }; + }; + + hdmi0-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + + pwm-leds { + compatible = "pwm-leds"; + + led { + color = ; + function = LED_FUNCTION_STATUS; + linux,default-trigger = "heartbeat"; + max-brightness = <255>; + pwms = <&pwm0 0 25000 0>; + }; + }; + + vbus_typec: regulator-vbus-typec { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&typec5v_pwren>; + regulator-name = "vbus_typec"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_sys: regulator-vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vcc_3v3_sd_s0: regulator-vcc-3v3-sd-s0 { + compatible = "regulator-fixed"; + gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_LOW>; + regulator-name = "vcc_3v3_sd_s0"; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_s3>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_b3 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&gmac1 { + clock_in_out = "output"; + phy-handle = <&rgmii_phy1>; + phy-mode = "rgmii-rxid"; + pinctrl-0 = <&gmac1_miim + &gmac1_tx_bus2 + &gmac1_rx_bus2 + &gmac1_rgmii_clk + &gmac1_rgmii_bus>; + pinctrl-names = "default"; + tx_delay = <0x42>; + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&hdmi0 { + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c2 { + status = "okay"; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c6 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c6m3_xfer>; + status = "okay"; + + es8388: audio-codec@10 { + compatible = "everest,es8388"; + reg = <0x10>; + clocks = <&cru I2S1_8CH_MCLKOUT>; + AVDD-supply = <&vcc_3v3_s0>; + DVDD-supply = <&vcc_1v8_s0>; + HPVDD-supply = <&vcc_3v3_s0>; + PVDD-supply = <&vcc_3v3_s0>; + assigned-clocks = <&cru I2S1_8CH_MCLKOUT>; + assigned-clock-rates = <12288000>; + #sound-dai-cells = <0>; + }; + + usbc0: usb-typec@22 { + compatible = "fcs,fusb302"; + reg = <0x22>; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&usbc0_int>; + vbus-supply = <&vbus_typec>; + status = "okay"; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + op-sink-microwatt = <1000000>; + power-role = "dual"; + sink-pdos = + ; + source-pdos = + ; + try-power-role = "source"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + usbc0_hs: endpoint { + remote-endpoint = <&usb_host0_xhci_drd_sw>; + }; + }; + + port@1 { + reg = <1>; + usbc0_ss: endpoint { + remote-endpoint = <&usbdp_phy0_typec_ss>; + }; + }; + + port@2 { + reg = <2>; + usbc0_sbu: endpoint { + remote-endpoint = <&usbdp_phy0_typec_sbu>; + }; + }; + }; + }; + }; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "hym8563"; + pinctrl-names = "default"; + pinctrl-0 = <&hym8563_int>; + interrupt-parent = <&gpio0>; + interrupts = ; + wakeup-source; + }; +}; + +&i2s1_8ch { + rockchip,i2s-tx-route = <3 2 1 0>; + rockchip,i2s-rx-route = <1 3 2 0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1m0_sclk + &i2s1m0_mclk + &i2s1m0_lrck + &i2s1m0_sdi1 + &i2s1m0_sdo3>; + status = "okay"; +}; + +&mdio1 { + rgmii_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + reset-assert-us = <20000>; + reset-deassert-us = <100000>; + reset-gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>; + }; +}; + +&pinctrl { + hym8563 { + hym8563_int: hym8563-int { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sound { + hp_detect: hp-detect { + rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb-typec { + usbc0_int: usbc0-int { + rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + typec5v_pwren: typec5v-pwren { + rockchip,pins = <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm0 { + pinctrl-0 = <&pwm0m2_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&saradc { + vref-supply = <&avcc_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + no-sdio; + no-sd; + non-removable; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + status = "disabled"; +}; + +&sdmmc { + bus-width = <4>; + cap-sd-highspeed; + disable-wp; + max-frequency = <150000000>; + no-mmc; + no-sdio; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_sd_s0>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&sfc { + pinctrl-names = "default"; + pinctrl-0 = <&fspim0_pins>; + status = "disabled"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + spi-max-frequency = <100000000>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <1>; + }; +}; + +&spi2 { + status = "okay"; + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0x0>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + system-power-controller; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc5v0_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc5v0_sys>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcc5v0_sys>; + + gpio-controller; + #gpio-cells = <2>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: dcdc-reg1 { + regulator-name = "vdd_gpu_s0"; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: dcdc-reg2 { + regulator-name = "vdd_cpu_lit_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_log_s0: dcdc-reg3 { + regulator-name = "vdd_log_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: dcdc-reg4 { + regulator-name = "vdd_vdenc_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-name = "vdd_ddr_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vcc_1v1_nldo_s3: vdd2_ddr_s3: dcdc-reg6 { + regulator-name = "vdd2_ddr_s3"; + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1100000>; + regulator-min-microvolt = <1100000>; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-name = "vdd_2v0_pldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-name = "vcc_3v3_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-name = "vddq_ddr_s0"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg10 { + regulator-name = "vcc_1v8_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avcc_1v8_s0: pldo-reg1 { + regulator-name = "avcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s0: pldo-reg2 { + regulator-name = "vcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avdd_1v2_s0: pldo-reg3 { + regulator-name = "avdd_1v2_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3_s0: pldo-reg4 { + regulator-name = "vcc_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-name = "vccio_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-name = "pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-name = "vdd_0v75_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_ddr_pll_s0: nldo-reg2 { + regulator-name = "vdd_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + avdd_0v75_s0: nldo-reg3 { + regulator-name = "avdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v85_s0: nldo-reg4 { + regulator-name = "vdd_0v85_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-name = "vdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy0_otg { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy2_host { + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy3_host { + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +&usbdp_phy0 { + mode-switch; + orientation-switch; + sbu1-dc-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>; + sbu2-dc-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; + status = "okay"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + usbdp_phy0_typec_ss: endpoint@0 { + reg = <0>; + remote-endpoint = <&usbc0_ss>; + }; + + usbdp_phy0_typec_sbu: endpoint@1 { + reg = <1>; + remote-endpoint = <&usbc0_sbu>; + }; + }; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host0_xhci { + dr_mode = "otg"; + usb-role-switch; + status = "okay"; + + port { + usb_host0_xhci_drd_sw: endpoint { + remote-endpoint = <&usbc0_hs>; + }; + }; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usb_host2_xhci { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dts new file mode 100644 index 00000000000000..d21ec320d2950f --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5b.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include "rk3588s-orangepi-5.dtsi" + +/ { + model = "Xunlong Orange Pi 5B"; + compatible = "xunlong,orangepi-5b", "rockchip,rk3588s"; + + aliases { + mmc0 = &sdhci; + mmc1 = &sdmmc; + }; +}; + +&sdhci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts index 294b99dd50da20..70a43432bdc57d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts @@ -5,6 +5,7 @@ #include #include #include +#include #include "rk3588s.dtsi" / { @@ -35,6 +36,17 @@ chosen { stdout-path = "serial2:1500000n8"; }; + hdmi0-con { + compatible = "hdmi-connector"; + type = "d"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -56,7 +68,7 @@ fan: pwm-fan { #cooling-cells = <2>; }; - vcc12v_dcin: vcc12v-dcin-regulator { + vcc12v_dcin: regulator-vcc12v-dcin { compatible = "regulator-fixed"; regulator-name = "vcc12v_dcin"; regulator-always-on; @@ -65,7 +77,7 @@ vcc12v_dcin: vcc12v-dcin-regulator { regulator-max-microvolt = <12000000>; }; - vcc3v3_wf: vcc3v3-wf-regulator { + vcc3v3_wf: regulator-vcc3v3-wf { compatible = "regulator-fixed"; regulator-name = "vcc3v3_wf"; regulator-min-microvolt = <3300000>; @@ -77,7 +89,7 @@ vcc3v3_wf: vcc3v3-wf-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_host: vcc5v0-host-regulator { + vcc5v0_host: regulator-vcc5v0-host { compatible = "regulator-fixed"; regulator-name = "vcc5v0_host"; regulator-boot-on; @@ -91,7 +103,7 @@ vcc5v0_host: vcc5v0-host-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc5v0_sys: vcc5v0-sys-regulator { + vcc5v0_sys: regulator-vcc5v0-sys { compatible = "regulator-fixed"; regulator-name = "vcc5v0_sys"; regulator-always-on; @@ -101,7 +113,7 @@ vcc5v0_sys: vcc5v0-sys-regulator { vin-supply = <&vcc12v_dcin>; }; - vcc_5v0: vcc-5v0-regulator { + vcc_5v0: regulator-vcc-5v0 { compatible = "regulator-fixed"; regulator-name = "vcc_5v0"; regulator-min-microvolt = <5000000>; @@ -115,7 +127,7 @@ vcc_5v0: vcc-5v0-regulator { vin-supply = <&vcc5v0_sys>; }; - vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { compatible = "regulator-fixed"; regulator-name = "vcc_1v1_nldo_s3"; regulator-always-on; @@ -166,6 +178,11 @@ &cpu_l3 { cpu-supply = <&vdd_cpu_lit_s0>; }; +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + &i2c0 { pinctrl-names = "default"; pinctrl-0 = <&i2c0m2_xfer>; @@ -296,6 +313,31 @@ &gmac1_rgmii_clk status = "okay"; }; +&hdmi0 { + pinctrl-names = "default"; + pinctrl-0 = <&hdmim0_tx0_cec + &hdmim1_tx0_hpd + &hdmim0_tx0_scl + &hdmim0_tx0_sda>; + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + &mdio1 { rgmii_phy1: ethernet-phy@1 { /* RTL8211F */ @@ -310,7 +352,7 @@ rgmii_phy1: ethernet-phy@1 { }; &pcie2x1l2 { - pinctrl-0 = <&pcie20x1m0_pins>; + pinctrl-0 = <&pcie2_reset>, <&pcie20x1m0_clkreqn>, <&pcie20x1m0_waken>; pinctrl-names = "default"; reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; vpcie3v3-supply = <&vcc3v3_wf>; @@ -328,6 +370,10 @@ pcie { pow_en: pow-en { rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; }; + + pcie2_reset: pcie2-reset { + rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>; + }; }; power { @@ -784,3 +830,18 @@ &usb_host1_ohci { &usb_host2_xhci { status = "okay"; }; + +&vop_mmu { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts new file mode 100644 index 00000000000000..9b14d5383cdc16 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5c.dts @@ -0,0 +1,920 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2024 Radxa Computer (Shenzhen) Co., Ltd. + */ + +/dts-v1/; + +#include +#include +#include +#include +#include "rk3588s.dtsi" + +/ { + model = "Radxa ROCK 5C"; + compatible = "radxa,rock-5c", "rockchip,rk3588s"; + + aliases { + ethernet0 = &gmac1; + mmc0 = &sdhci; + mmc1 = &sdmmc; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + analog-sound { + compatible = "audio-graph-card"; + label = "rk3588-es8316"; + dais = <&i2s0_8ch_p0>; + routing = "MIC2", "Mic Jack", + "Headphones", "HPOL", + "Headphones", "HPOR"; + widgets = "Microphone", "Mic Jack", + "Headphone", "Headphones"; + }; + + hdmi0-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi0_con_in: endpoint { + remote-endpoint = <&hdmi0_out_con>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + + led-0 { + color = ; + default-state = "on"; + function = LED_FUNCTION_POWER; + gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; + }; + + led-1 { + color = ; + default-state = "on"; + function = LED_FUNCTION_HEARTBEAT; + gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + + fan { + compatible = "pwm-fan"; + #cooling-cells = <2>; + cooling-levels = <0 64 128 192 255>; + fan-supply = <&vcc_5v0>; + pwms = <&pwm3 0 10000 0>; + }; + + pcie2x1l2_3v3: regulator-pcie2x1l2-3v3 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pow_en>; + regulator-name = "pcie2x1l2_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_sysin>; + }; + + vcc5v_dcin: regulator-vcc5v-dcin { + compatible = "regulator-fixed"; + regulator-name = "vcc5v_dcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vcc5v0_usb_host: regulator-vcc5v0-usb-host { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_host_pwren_h>; + regulator-name = "vcc5v0_usb_host"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + vcc5v0_usb_otg0: regulator-vcc5v0-usb-otg0 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PD4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_otg_pwren_h>; + regulator-name = "vcc5v0_usb_otg0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc_sysin>; + }; + + vcc_3v3_pmu: regulator-vcc-3v3-pmu { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_pmu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc_3v3_s0: regulator-vcc-3v3-s0 { + compatible = "regulator-fixed"; + regulator-name = "vcc_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_1v8_s0>; + }; + + vcc_5v0: regulator-vcc-5v0 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc_5v0_pwren_h>; + regulator-name = "vcc_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_sysin>; + }; + + vcc_sysin: regulator-vcc-sysin { + compatible = "regulator-fixed"; + regulator-name = "vcc_sysin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v_dcin>; + }; + + vcca: regulator-vcca { + compatible = "regulator-fixed"; + regulator-name = "vcca"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <4000000>; + vin-supply = <&vcc_sysin>; + }; + + vdd_3v3: regulator-vdd-3v3 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_wifi_pwr>; + regulator-name = "vdd_3v3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_s3>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_b3 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&gmac1 { + phy-handle = <&rgmii_phy1>; + phy-mode = "rgmii-id"; + phy-supply = <&vcc_3v3_s0>; + pinctrl-0 = <&gmac1_miim + &gmac1_tx_bus2 + &gmac1_rx_bus2 + &gmac1_rgmii_clk + &gmac1_rgmii_bus + &gmac1_clkinout>; + pinctrl-names = "default"; + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu_s0>; + status = "okay"; +}; + +&hdmi0 { + pinctrl-names = "default"; + pinctrl-0 = <&hdmim0_tx0_cec + &hdmim1_tx0_hpd + &hdmim0_tx0_scl + &hdmim0_tx0_sda>; + status = "okay"; +}; + +&hdmi0_in { + hdmi0_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi0>; + }; +}; + +&hdmi0_out { + hdmi0_out_con: endpoint { + remote-endpoint = <&hdmi0_con_in>; + }; +}; + +&hdptxphy_hdmi0 { + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + eeprom@50 { + compatible = "belling,bl24c16a", "atmel,24c16"; + reg = <0x50>; + pagesize = <16>; + vcc-supply = <&vcc_3v3_pmu>; + }; +}; + +&i2c2 { + status = "okay"; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sysin>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c5m2_xfer>; + status = "okay"; + + rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + #clock-cells = <0>; + clock-output-names = "rtcic_32kout"; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&rtc_int_l>; + }; +}; + +&i2c7 { + status = "okay"; + + audio-codec@11 { + compatible = "everest,es8316"; + reg = <0x11>; + assigned-clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clock-rates = <12288000>; + clocks = <&cru I2S0_8CH_MCLKOUT>; + clock-names = "mclk"; + #sound-dai-cells = <0>; + + port { + es8316_p0_0: endpoint { + remote-endpoint = <&i2s0_8ch_p0_0>; + }; + }; + }; +}; + +&i2s0_8ch { + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_lrck + &i2s0_mclk + &i2s0_sclk + &i2s0_sdi0 + &i2s0_sdo0>; + status = "okay"; + + i2s0_8ch_p0: port { + i2s0_8ch_p0_0: endpoint { + dai-format = "i2s"; + mclk-fs = <256>; + remote-endpoint = <&es8316_p0_0>; + }; + }; +}; + +&mdio1 { + rgmii_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-id001c.c916"; + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&gmac1_rstn>; + reset-assert-us = <20000>; + reset-deassert-us = <100000>; + reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>; + }; +}; + +&pcie2x1l2 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie20x1_2_perstn_m0>; + reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&pcie2x1l2_3v3>; + status = "okay"; +}; + +&pinctrl { + leds { + led_pins: led-pins { + rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>, + <3 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + mdio { + gmac1_rstn: gmac1-rstn { + rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pcie { + pcie20x1_2_perstn_m0: pcie20x1-2-perstn-m0 { + rockchip,pins = <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + pow_en: pow-en { + rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + rtc { + rtc_int_l: rtc-int-l { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + usb_host_pwren_h: usb-host-pwren-h { + rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + usb_otg_pwren_h: usb-otg-pwren-h { + rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + usb_wifi_pwr: usb-wifi-pwr { + rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + vcc_5v0_pwren_h: vcc-5v0-pwren-h { + rockchip,pins = <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm3 { + pinctrl-names = "default"; + pinctrl-0 = <&pwm3m1_pins>; + status = "okay"; +}; + +&saradc { + vref-supply = <&vcca_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + no-sdio; + no-sd; + non-removable; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + no-sdio; + no-mmc; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&sfc { + pinctrl-names = "default"; + pinctrl-0 = <&fspim0_pins>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <104000000>; + spi-rx-bus-width = <4>; + spi-tx-bus-width = <1>; + }; +}; + +&spi2 { + status = "okay"; + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + system-power-controller; + + vcc1-supply = <&vcc_sysin>; + vcc2-supply = <&vcc_sysin>; + vcc3-supply = <&vcc_sysin>; + vcc4-supply = <&vcc_sysin>; + vcc5-supply = <&vcc_sysin>; + vcc6-supply = <&vcc_sysin>; + vcc7-supply = <&vcc_sysin>; + vcc8-supply = <&vcc_sysin>; + vcc9-supply = <&vcc_sysin>; + vcc10-supply = <&vcc_sysin>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc_sysin>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcca>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl1"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: dcdc-reg1 { + regulator-name = "vdd_gpu_s0"; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: dcdc-reg2 { + regulator-name = "vdd_cpu_lit_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_logic_s0: dcdc-reg3 { + regulator-name = "vdd_logic_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: dcdc-reg4 { + regulator-name = "vdd_vdenc_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-name = "vdd_ddr_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg6 { + regulator-name = "vdd2_ddr_s3"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-name = "vdd_2v0_pldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-name = "vcc_3v3_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-name = "vddq_ddr_s0"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_pmu_ddr_s3: dcdc-reg10 { + regulator-name = "vcc1v8_pmu_ddr_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_1v8_s0: pldo-reg1 { + regulator-name = "vcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcca_1v8_s0: pldo-reg2 { + regulator-name = "vcca_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdda_1v2_s0: pldo-reg3 { + regulator-name = "vdda_1v2_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca_3v3_s0: pldo-reg4 { + regulator-name = "vcca_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-name = "vccio_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-name = "pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-name = "vdd_0v75_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_ddr_pll_s0: nldo-reg2 { + regulator-name = "vdda_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdda_0v75_s0: nldo-reg3 { + regulator-name = "vdda_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda_0v85_s0: nldo-reg4 { + regulator-name = "vdda_0v85_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-name = "vdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy0 { + status = "okay"; +}; + +&u2phy0_otg { + phy-supply = <&vcc5v0_usb_otg0>; + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy2_host { + /* connected to USB hub, which is powered by vcc_5v0 */ + phy-supply = <&vcc_5v0>; + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy3_host { + phy-supply = <&vcc5v0_usb_host>; + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +&usbdp_phy0 { + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_xhci { + dr_mode = "host"; + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usb_host2_xhci { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vop { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi0: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi0_in_vp0>; + }; +}; diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi index 1167cf63d7e87a..6fe12e3bd7dd9e 100644 --- a/arch/arm64/boot/dts/st/stm32mp251.dtsi +++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi @@ -245,6 +245,9 @@ spi2: spi@400b0000 { interrupts = ; clocks = <&rcc CK_KER_SPI2>; resets = <&rcc SPI2_R>; + dmas = <&hpdma 51 0x20 0x3012>, + <&hpdma 52 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 23>; status = "disabled"; }; @@ -257,6 +260,9 @@ spi3: spi@400c0000 { interrupts = ; clocks = <&rcc CK_KER_SPI3>; resets = <&rcc SPI3_R>; + dmas = <&hpdma 53 0x20 0x3012>, + <&hpdma 54 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 24>; status = "disabled"; }; @@ -266,6 +272,9 @@ usart2: serial@400e0000 { reg = <0x400e0000 0x400>; interrupts = ; clocks = <&rcc CK_KER_USART2>; + dmas = <&hpdma 11 0x20 0x10012>, + <&hpdma 12 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 32>; status = "disabled"; }; @@ -275,6 +284,9 @@ usart3: serial@400f0000 { reg = <0x400f0000 0x400>; interrupts = ; clocks = <&rcc CK_KER_USART3>; + dmas = <&hpdma 13 0x20 0x10012>, + <&hpdma 14 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 33>; status = "disabled"; }; @@ -284,6 +296,9 @@ uart4: serial@40100000 { reg = <0x40100000 0x400>; interrupts = ; clocks = <&rcc CK_KER_UART4>; + dmas = <&hpdma 15 0x20 0x10012>, + <&hpdma 16 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 34>; status = "disabled"; }; @@ -293,6 +308,9 @@ uart5: serial@40110000 { reg = <0x40110000 0x400>; interrupts = ; clocks = <&rcc CK_KER_UART5>; + dmas = <&hpdma 17 0x20 0x10012>, + <&hpdma 18 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 35>; status = "disabled"; }; @@ -306,6 +324,9 @@ i2c1: i2c@40120000 { resets = <&rcc I2C1_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&hpdma 27 0x20 0x3012>, + <&hpdma 28 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 41>; status = "disabled"; }; @@ -319,6 +340,9 @@ i2c2: i2c@40130000 { resets = <&rcc I2C2_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&hpdma 30 0x20 0x3012>, + <&hpdma 31 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 42>; status = "disabled"; }; @@ -332,6 +356,9 @@ i2c3: i2c@40140000 { resets = <&rcc I2C3_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&hpdma 33 0x20 0x3012>, + <&hpdma 34 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 43>; status = "disabled"; }; @@ -345,6 +372,9 @@ i2c4: i2c@40150000 { resets = <&rcc I2C4_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&hpdma 36 0x20 0x3012>, + <&hpdma 37 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 44>; status = "disabled"; }; @@ -358,6 +388,9 @@ i2c5: i2c@40160000 { resets = <&rcc I2C5_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&hpdma 39 0x20 0x3012>, + <&hpdma 40 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 45>; status = "disabled"; }; @@ -371,6 +404,9 @@ i2c6: i2c@40170000 { resets = <&rcc I2C6_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&hpdma 42 0x20 0x3012>, + <&hpdma 43 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 46>; status = "disabled"; }; @@ -384,6 +420,9 @@ i2c7: i2c@40180000 { resets = <&rcc I2C7_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&hpdma 45 0x20 0x3012>, + <&hpdma 46 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 47>; status = "disabled"; }; @@ -393,6 +432,9 @@ usart6: serial@40220000 { reg = <0x40220000 0x400>; interrupts = ; clocks = <&rcc CK_KER_USART6>; + dmas = <&hpdma 19 0x20 0x10012>, + <&hpdma 20 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 36>; status = "disabled"; }; @@ -405,6 +447,9 @@ spi1: spi@40230000 { interrupts = ; clocks = <&rcc CK_KER_SPI1>; resets = <&rcc SPI1_R>; + dmas = <&hpdma 49 0x20 0x3012>, + <&hpdma 50 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 22>; status = "disabled"; }; @@ -417,6 +462,9 @@ spi4: spi@40240000 { interrupts = ; clocks = <&rcc CK_KER_SPI4>; resets = <&rcc SPI4_R>; + dmas = <&hpdma 55 0x20 0x3012>, + <&hpdma 56 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 25>; status = "disabled"; }; @@ -429,6 +477,9 @@ spi5: spi@40280000 { interrupts = ; clocks = <&rcc CK_KER_SPI5>; resets = <&rcc SPI5_R>; + dmas = <&hpdma 57 0x20 0x3012>, + <&hpdma 58 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 26>; status = "disabled"; }; @@ -438,6 +489,9 @@ uart9: serial@402c0000 { reg = <0x402c0000 0x400>; interrupts = ; clocks = <&rcc CK_KER_UART9>; + dmas = <&hpdma 25 0x20 0x10012>, + <&hpdma 26 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 39>; status = "disabled"; }; @@ -447,6 +501,9 @@ usart1: serial@40330000 { reg = <0x40330000 0x400>; interrupts = ; clocks = <&rcc CK_KER_USART1>; + dmas = <&hpdma 9 0x20 0x10012>, + <&hpdma 10 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 31>; status = "disabled"; }; @@ -459,6 +516,9 @@ spi6: spi@40350000 { interrupts = ; clocks = <&rcc CK_KER_SPI6>; resets = <&rcc SPI6_R>; + dmas = <&hpdma 59 0x20 0x3012>, + <&hpdma 60 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 27>; status = "disabled"; }; @@ -471,6 +531,9 @@ spi7: spi@40360000 { interrupts = ; clocks = <&rcc CK_KER_SPI7>; resets = <&rcc SPI7_R>; + dmas = <&hpdma 61 0x20 0x3012>, + <&hpdma 62 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 28>; status = "disabled"; }; @@ -480,6 +543,9 @@ uart7: serial@40370000 { reg = <0x40370000 0x400>; interrupts = ; clocks = <&rcc CK_KER_UART7>; + dmas = <&hpdma 21 0x20 0x10012>, + <&hpdma 22 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 37>; status = "disabled"; }; @@ -489,10 +555,23 @@ uart8: serial@40380000 { reg = <0x40380000 0x400>; interrupts = ; clocks = <&rcc CK_KER_UART8>; + dmas = <&hpdma 23 0x20 0x10012>, + <&hpdma 24 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 38>; status = "disabled"; }; + rng: rng@42020000 { + compatible = "st,stm32mp25-rng"; + reg = <0x42020000 0x400>; + clocks = <&clk_rcbsec>, <&rcc CK_BUS_RNG>; + clock-names = "core", "bus"; + resets = <&rcc RNG_R>; + access-controllers = <&rifsc 92>; + status = "disabled"; + }; + spi8: spi@46020000 { #address-cells = <1>; #size-cells = <0>; @@ -501,6 +580,9 @@ spi8: spi@46020000 { interrupts = ; clocks = <&rcc CK_KER_SPI8>; resets = <&rcc SPI8_R>; + dmas = <&hpdma 171 0x20 0x3012>, + <&hpdma 172 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 29>; status = "disabled"; }; @@ -514,6 +596,9 @@ i2c8: i2c@46040000 { resets = <&rcc I2C8_R>; #address-cells = <1>; #size-cells = <0>; + dmas = <&hpdma 168 0x20 0x3012>, + <&hpdma 169 0x20 0x3021>; + dma-names = "rx", "tx"; access-controllers = <&rifsc 48>; status = "disabled"; }; @@ -916,6 +1001,16 @@ gpiok: gpio@442e0000 { }; }; + rtc: rtc@46000000 { + compatible = "st,stm32mp25-rtc"; + reg = <0x46000000 0x400>; + clocks = <&scmi_clk CK_SCMI_RTC>, + <&scmi_clk CK_SCMI_RTCCK>; + clock-names = "pclk", "rtc_ck"; + interrupts-extended = <&exti2 17 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + pinctrl_z: pinctrl@46200000 { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts index 214191a8322b81..6f393b08278914 100644 --- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts +++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts @@ -93,6 +93,10 @@ &i2c8 { status = "disabled"; }; +&rtc { + status = "okay"; +}; + &scmi_regu { scmi_vddio1: regulator@0 { regulator-min-microvolt = <1800000>; @@ -157,6 +161,8 @@ &usart2 { pinctrl-0 = <&usart2_pins_a>; pinctrl-1 = <&usart2_idle_pins_a>; pinctrl-2 = <&usart2_sleep_pins_a>; + /delete-property/dmas; + /delete-property/dma-names; status = "okay"; }; diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index bcd392c3206e50..f71360f14f233c 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -16,13 +16,14 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-ivy.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-ivy.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-yavia.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-1-4-ghz-opp.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62x-phyboard-lyra-gpio-fan.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk-nand.dtbo @@ -48,6 +49,7 @@ k3-am642-hummingboard-t-usb3-dtbs := \ dtb-$(CONFIG_ARCH_K3) += k3-am642-evm.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-evm-icssg1-dualemac.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am642-evm-icssg1-dualemac-mii.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am642-evm-pcie0-ep.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am642-hummingboard-t.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-hummingboard-t-pcie.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-hummingboard-t-usb3.dtb @@ -96,6 +98,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am654-pcie-usb3.dtbo # Boards with J7200 SoC k3-j7200-evm-dtbs := k3-j7200-common-proc-board.dtb k3-j7200-evm-quad-port-eth-exp.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j7200-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j7200-evm-pcie1-ep.dtbo # Boards with J721e SoC k3-j721e-evm-dtbs := k3-j721e-common-proc-board.dtb k3-j721e-evm-quad-port-eth-exp.dtbo @@ -126,13 +129,14 @@ dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-pcie0-pcie1-ep.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-quad-port-eth-exp1.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-usxgmii-exp1-exp2.dtbo +# Boards with J742S2 SoC +dtb-$(CONFIG_ARCH_K3) += k3-j742s2-evm.dtb + # Build time test only, enabled by CONFIG_OF_ALL_DTBS k3-am625-beagleplay-csi2-ov5640-dtbs := k3-am625-beagleplay.dtb \ k3-am625-beagleplay-csi2-ov5640.dtbo k3-am625-beagleplay-csi2-tevi-ov5640-dtbs := k3-am625-beagleplay.dtb \ k3-am625-beagleplay-csi2-tevi-ov5640.dtbo -k3-am625-phyboard-lyra-1-4-ghz-opp.dtbs := k3-am625-phyboard-lyra-rdk.dtb \ - k3-am625-phyboard-lyra-1-4-ghz-opp.dtbo k3-am625-phyboard-lyra-disable-eth-phy-dtbs := k3-am625-phyboard-lyra-rdk.dtb \ k3-am6xx-phycore-disable-eth-phy.dtbo k3-am625-phyboard-lyra-disable-rtc-dtbs := k3-am625-phyboard-lyra-rdk.dtb \ @@ -168,6 +172,8 @@ k3-am642-evm-icssg1-dualemac-dtbs := \ k3-am642-evm.dtb k3-am642-evm-icssg1-dualemac.dtbo k3-am642-evm-icssg1-dualemac-mii-dtbs := \ k3-am642-evm.dtb k3-am642-evm-icssg1-dualemac-mii.dtbo +k3-am642-evm-pcie0-ep-dtbs := \ + k3-am642-evm.dtb k3-am642-evm-pcie0-ep.dtbo k3-am642-phyboard-electra-disable-eth-phy-dtbs := \ k3-am642-phyboard-electra-rdk.dtb k3-am6xx-phycore-disable-eth-phy.dtbo k3-am642-phyboard-electra-disable-rtc-dtbs := \ @@ -188,6 +194,8 @@ k3-am68-sk-base-board-csi2-dual-imx219-dtbs := k3-am68-sk-base-board.dtb \ k3-j721e-sk-csi2-dual-imx219.dtbo k3-am69-sk-csi2-dual-imx219-dtbs := k3-am69-sk.dtb \ k3-j721e-sk-csi2-dual-imx219.dtbo +k3-j7200-evm-pcie1-ep-dtbs := k3-j7200-common-proc-board.dtb \ + k3-j7200-evm-pcie1-ep.dtbo k3-j721e-common-proc-board-infotainment-dtbs := k3-j721e-common-proc-board.dtb \ k3-j721e-common-proc-board-infotainment.dtbo k3-j721e-evm-pcie0-ep-dtbs := k3-j721e-common-proc-board.dtb \ @@ -217,10 +225,12 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ k3-am62p5-sk-csi2-tevi-ov5640.dtb \ k3-am642-evm-icssg1-dualemac.dtb \ k3-am642-evm-icssg1-dualemac-mii.dtb \ + k3-am642-evm-pcie0-ep.dtb \ k3-am642-tqma64xxl-mbax4xxl-sdcard.dtb \ k3-am642-tqma64xxl-mbax4xxl-wlan.dtb \ k3-am68-sk-base-board-csi2-dual-imx219.dtb \ k3-am69-sk-csi2-dual-imx219.dtb \ + k3-j7200-evm-pcie1-ep.dtbo \ k3-j721e-common-proc-board-infotainment.dtb \ k3-j721e-evm-pcie0-ep.dtb \ k3-j721e-sk-csi2-dual-imx219.dtb \ @@ -243,7 +253,9 @@ DTC_FLAGS_k3-am642-tqma64xxl-mbax4xxl += -@ DTC_FLAGS_k3-am6548-iot2050-advanced-m2 += -@ DTC_FLAGS_k3-am68-sk-base-board += -@ DTC_FLAGS_k3-am69-sk += -@ +DTC_FLAGS_k3-j7200-common-proc-board += -@ DTC_FLAGS_k3-j721e-common-proc-board += -@ DTC_FLAGS_k3-j721e-sk += -@ DTC_FLAGS_k3-j721s2-common-proc-board += -@ DTC_FLAGS_k3-j784s4-evm += -@ +DTC_FLAGS_k3-j742s2-evm += -@ diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi index 5b92aef5b284b7..7cd727d10a5f27 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi @@ -561,10 +561,9 @@ sdhci0: mmc@fa10000 { ti,clkbuf-sel = <0x7>; ti,otap-del-sel-legacy = <0x0>; ti,otap-del-sel-mmc-hs = <0x0>; - ti,otap-del-sel-ddr52 = <0x5>; - ti,otap-del-sel-hs200 = <0x5>; - ti,itap-del-sel-legacy = <0xa>; - ti,itap-del-sel-mmc-hs = <0x1>; + ti,otap-del-sel-hs200 = <0x6>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-mmc-hs = <0x0>; status = "disabled"; }; @@ -577,17 +576,17 @@ sdhci1: mmc@fa00000 { clock-names = "clk_ahb", "clk_xin"; bus-width = <4>; ti,clkbuf-sel = <0x7>; - ti,otap-del-sel-legacy = <0x8>; + ti,otap-del-sel-legacy = <0x0>; ti,otap-del-sel-sd-hs = <0x0>; - ti,otap-del-sel-sdr12 = <0x0>; - ti,otap-del-sel-sdr25 = <0x0>; - ti,otap-del-sel-sdr50 = <0x8>; - ti,otap-del-sel-sdr104 = <0x7>; - ti,otap-del-sel-ddr50 = <0x4>; - ti,itap-del-sel-legacy = <0xa>; - ti,itap-del-sel-sd-hs = <0x1>; - ti,itap-del-sel-sdr12 = <0xa>; - ti,itap-del-sel-sdr25 = <0x1>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-sdr104 = <0x6>; + ti,otap-del-sel-ddr50 = <0x9>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-sd-hs = <0x0>; + ti,itap-del-sel-sdr12 = <0x0>; + ti,itap-del-sel-sdr25 = <0x0>; status = "disabled"; }; @@ -600,17 +599,17 @@ sdhci2: mmc@fa20000 { clock-names = "clk_ahb", "clk_xin"; bus-width = <4>; ti,clkbuf-sel = <0x7>; - ti,otap-del-sel-legacy = <0x8>; + ti,otap-del-sel-legacy = <0x0>; ti,otap-del-sel-sd-hs = <0x0>; - ti,otap-del-sel-sdr12 = <0x0>; - ti,otap-del-sel-sdr25 = <0x0>; - ti,otap-del-sel-sdr50 = <0x8>; - ti,otap-del-sel-sdr104 = <0x7>; - ti,otap-del-sel-ddr50 = <0x8>; - ti,itap-del-sel-legacy = <0xa>; - ti,itap-del-sel-sd-hs = <0xa>; - ti,itap-del-sel-sdr12 = <0xa>; - ti,itap-del-sel-sdr25 = <0x1>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-sdr104 = <0x6>; + ti,otap-del-sel-ddr50 = <0x9>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-sd-hs = <0x0>; + ti,itap-del-sel-sdr12 = <0x0>; + ti,itap-del-sel-sdr25 = <0x0>; status = "disabled"; }; @@ -843,6 +842,33 @@ ecap2: pwm@23120000 { status = "disabled"; }; + eqep0: counter@23200000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23200000 0x00 0x100>; + power-domains = <&k3_pds 59 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 59 0>; + interrupts = ; + status = "disabled"; + }; + + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + + eqep2: counter@23220000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23220000 0x00 0x100>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 62 0>; + interrupts = ; + status = "disabled"; + }; + main_mcan0: can@20701000 { compatible = "bosch,m_can"; reg = <0x00 0x20701000 0x00 0x200>, diff --git a/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi index bb43a411f59b28..68e906796aefeb 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-mcu.dtsi @@ -174,4 +174,17 @@ mcu_mcan1: can@4e18000 { bosch,mram-cfg = <0x0 128 64 64 64 64 32 32>; status = "disabled"; }; + + mcu_m4fss: m4fss@5000000 { + compatible = "ti,am64-m4fss"; + reg = <0x00 0x5000000 0x00 0x30000>, + <0x00 0x5040000 0x00 0x10000>; + reg-names = "iram", "dram"; + resets = <&k3_reset 9 1>; + firmware-name = "am62-mcu-m4f0_0-fw"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <9>; + ti,sci-proc-ids = <0x18 0xff>; + status = "disabled"; + }; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi index 43488cc8bcb1e1..5952874fe429bf 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-phycore-som.dtsi @@ -45,6 +45,18 @@ ramoops@9ca00000 { pmsg-size = <0x8000>; }; + mcu_m4fss_dma_memory_region: m4f-dma-memory@9cb00000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9cb00000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@9cc00000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9cc00000 0x00 0xe00000>; + no-map; + }; + secure_tfa_ddr: tfa@9e780000 { reg = <0x00 0x9e780000 0x00 0x80000>; alignment = <0x1000>; @@ -173,6 +185,13 @@ AM62X_IOPAD(0x01f4, PIN_INPUT, 0) /* (D16) EXTINTn */ }; }; +&a53_opp_table { + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-supported-hw = <0x01 0x0004>; + }; +}; + &cpsw3g { pinctrl-names = "default"; pinctrl-0 = <&main_rgmii1_pins_default>; @@ -196,6 +215,13 @@ cpsw3g_phy1: ethernet-phy@1 { }; }; +&mailbox0_cluster0 { + mbox_m4_0: mbox-m4-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + &main_i2c0 { pinctrl-names = "default"; pinctrl-0 = <&main_i2c0_pins_default>; @@ -226,8 +252,8 @@ pmic@30 { regulators { vdd_core: buck1 { regulator-name = "VDD_CORE"; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <750000>; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; regulator-boot-on; regulator-always-on; }; @@ -295,6 +321,13 @@ i2c_som_rtc: rtc@52 { }; }; +&mcu_m4fss { + mboxes = <&mailbox0_cluster0 &mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + status = "okay"; +}; + &ospi0 { pinctrl-names = "default"; pinctrl-0 = <&ospi0_pins_default>; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-ivy.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-ivy.dtsi new file mode 100644 index 00000000000000..71c29eab0eee77 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-ivy.dtsi @@ -0,0 +1,655 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + * + * Common dtsi for Verdin AM62 SoM on Ivy carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/ivy-carrier-board + */ + +#include +#include +#include + +/ { + /* AIN1 Voltage w/o AIN1_MODE gpio control */ + ain1_voltage_unmanaged: voltage-divider-ain1 { + compatible = "voltage-divider"; + #io-channel-cells = <1>; + io-channels = <&ivy_adc1 0>; + full-ohms = <19>; + output-ohms = <1>; + }; + + /* AIN1 Current w/o AIN1_MODE gpio control */ + ain1_current_unmanaged: current-sense-shunt-ain1 { + compatible = "current-sense-shunt"; + #io-channel-cells = <0>; + io-channels = <&ivy_adc1 1>; + shunt-resistor-micro-ohms = <100000000>; + }; + + /* AIN1_MODE - SODIMM 216 */ + ain1_mode_mux_ctrl: mux-controller-0 { + compatible = "gpio-mux"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_5>; + #mux-control-cells = <0>; + mux-gpios = <&main_gpio0 40 GPIO_ACTIVE_HIGH>; + }; + + ain1-voltage { + compatible = "io-channel-mux"; + channels = "ain1_voltage", ""; + io-channels = <&ain1_voltage_unmanaged 0>; + io-channel-names = "parent"; + mux-controls = <&ain1_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + ain1-current { + compatible = "io-channel-mux"; + channels = "", "ain1_current"; + io-channels = <&ain1_current_unmanaged>; + io-channel-names = "parent"; + mux-controls = <&ain1_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + /* AIN2 Voltage w/o AIN2_MODE gpio control */ + ain2_voltage_unmanaged: voltage-divider-ain2 { + compatible = "voltage-divider"; + #io-channel-cells = <1>; + io-channels = <&ivy_adc2 0>; + full-ohms = <19>; + output-ohms = <1>; + }; + + /* AIN2 Current w/o AIN2_MODE gpio control */ + ain2_current_unmanaged: current-sense-shunt-ain2 { + compatible = "current-sense-shunt"; + #io-channel-cells = <0>; + io-channels = <&ivy_adc2 1>; + shunt-resistor-micro-ohms = <100000000>; + }; + + /* AIN2_MODE - SODIMM 218 */ + ain2_mode_mux_ctrl: mux-controller-1 { + compatible = "gpio-mux"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_6>; + #mux-control-cells = <0>; + mux-gpios = <&main_gpio0 36 GPIO_ACTIVE_HIGH>; + }; + + ain2-voltage { + compatible = "io-channel-mux"; + channels = "ain2_voltage", ""; + io-channels = <&ain2_voltage_unmanaged 0>; + io-channel-names = "parent"; + mux-controls = <&ain2_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + ain2-current { + compatible = "io-channel-mux"; + channels = "", "ain2_current"; + io-channels = <&ain2_current_unmanaged>; + io-channel-names = "parent"; + mux-controls = <&ain2_mode_mux_ctrl>; + settle-time-us = <1000>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ivy_leds>; + + /* D7 Blue - SODIMM 30 - LEDs.GPIO1 */ + led-0 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&main_gpio1 11 GPIO_ACTIVE_HIGH>; + }; + + /* D7 Green - SODIMM 32 - LEDs.GPIO2 */ + led-1 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&main_gpio1 12 GPIO_ACTIVE_HIGH>; + }; + + /* D7 Red - SODIMM 34 - LEDs.GPIO3 */ + led-2 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <1>; + gpios = <&main_gpio1 10 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Blue - SODIMM 36 - LEDs.GPIO4 */ + led-3 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&main_gpio1 9 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Green - SODIMM 54 - LEDs.GPIO5 */ + led-4 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&main_gpio0 11 GPIO_ACTIVE_HIGH>; + }; + + /* D8 Red - SODIMM 44 - LEDs.GPIO6 */ + led-5 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <2>; + gpios = <&main_gpio0 37 GPIO_ACTIVE_HIGH>; + }; + + /* D9 Blue - SODIMM 46 - LEDs.GPIO7 */ + led-6 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <3>; + gpios = <&main_gpio0 34 GPIO_ACTIVE_HIGH>; + }; + + /* D9 Red - SODIMM 48 - LEDs.GPIO8 */ + led-7 { + color = ; + default-state = "off"; + function = LED_FUNCTION_STATUS; + function-enumerator = <3>; + gpios = <&main_gpio0 33 GPIO_ACTIVE_HIGH>; + }; + }; + + reg_3v2_ain1: regulator-3v2-ain1 { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3200000>; + regulator-min-microvolt = <3200000>; + regulator-name = "+3V2_AIN1"; + }; + + reg_3v2_ain2: regulator-3v2-ain2 { + compatible = "regulator-fixed"; + regulator-max-microvolt = <3200000>; + regulator-min-microvolt = <3200000>; + regulator-name = "+3V2_AIN2"; + }; + + /* Ivy Power Supply Input Voltage */ + ivy-input-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_1 */ + io-channels = <&verdin_som_adc 7>; + full-ohms = <204700>; /* 200K + 4.7K */ + output-ohms = <4700>; + }; + + ivy-5v-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_2 */ + io-channels = <&verdin_som_adc 6>; + full-ohms = <39000>; /* 27K + 12K */ + output-ohms = <12000>; + }; + + ivy-3v3-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_3 */ + io-channels = <&verdin_som_adc 5>; + full-ohms = <54000>; /* 27K + 27K */ + output-ohms = <27000>; + }; + + ivy-1v8-voltage { + compatible = "voltage-divider"; + /* Verdin ADC_4 */ + io-channels = <&verdin_som_adc 4>; + full-ohms = <39000>; /* 12K + 27K */ + output-ohms = <27000>; + }; +}; + +&main_pmx0 { + pinctrl_ivy_leds: ivy-leds-default-pins { + pinctrl-single,pins = + , /* (B18) MCASP0_AXR1.GPIO1_9 */ /* SODIMM 36 */ + , /* (B20) MCASP0_AXR0.GPIO1_10 */ /* SODIMM 34 */ + , /* (A19) MCASP0_ACLKX.GPIO1_11 */ /* SODIMM 30 */ + , /* (A20) MCASP0_AFSX.GPIO1_12 */ /* SODIMM 32 */ + , /* (L17) GPMC0_OEn_REn.GPIO0_33 */ /* SODIMM 48 */ + , /* (R18) GPMC0_WAIT0.GPIO0_37 */ /* SODIMM 44 */ + , /* (L25) GPMC0_WEn.GPIO0_34 */ /* SODIMM 46 */ + ; /* (F23) OSPI0_CSn0.GPIO0_11 */ /* SODIMM 54 */ + }; +}; + +/* Verdin ETH */ +&cpsw3g { + status = "okay"; +}; + +/* MDIO, shared by Verdin ETH_1 (On-module PHY) and Verdin ETH_2_RGMII */ +&cpsw3g_mdio { + status = "okay"; + + cpsw3g_phy1: ethernet-phy@2 { + reg = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eth2_rgmii_int>; + interrupt-parent = <&main_gpio0>; + interrupts = <38 IRQ_TYPE_EDGE_FALLING>; + ti,rx-internal-delay = ; + }; +}; + +/* Verdin ETH_1*/ +&cpsw_port1 { + status = "okay"; +}; + +/* Verdin ETH_2_RGMII */ +&cpsw_port2 { + phy-handle = <&cpsw3g_phy1>; + phy-mode = "rgmii-rxid"; + status = "okay"; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ctrl_sleep_moci>, + <&pinctrl_qspi1_cs2_gpio>, + <&pinctrl_qspi1_io0_gpio>, + <&pinctrl_qspi1_io1_gpio>, + <&pinctrl_qspi1_io2_gpio>, + <&pinctrl_qspi1_io3_gpio>; + gpio-line-names = + "", /* 0 */ + "", + "", + "DIGI_1", /* SODIMM 56 */ + "DIGI_2", /* SODIMM 58 */ + "REL1", /* SODIMM 60 */ + "REL2", /* SODIMM 62 */ + "", + "", + "", + "", /* 10 */ + "", + "REL3", /* SODIMM 64 */ + "", + "", + "", + "", + "", + "", + "", + "", /* 20 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 30 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 40 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 50 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 60 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 70 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 80 */ + "", + "", + "", + "", + "", + ""; +}; + +&main_gpio1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi1_dqs_gpio>; + gpio-line-names = + "", /* 0 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 10 */ + "", + "", + "", + "", + "", + "", + "", + "REL4", /* SODIMM 66 */ + "", + "", /* 20 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 30 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 40 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 50 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 60 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 70 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", /* 80 */ + "", + "", + "", + "", + "", + "", + ""; +}; + +/* Verdin I2C_1 */ +&main_i2c1 { + status = "okay"; + + temperature-sensor@4f { + compatible = "ti,tmp1075"; + reg = <0x4f>; + }; + + eeprom@57 { + compatible = "st,24c02", "atmel,24c02"; + reg = <0x57>; + pagesize = <16>; + }; +}; + +/* Verdin I2C_4 CSI */ +&main_i2c3 { + status = "okay"; + + ivy_adc1: adc@40 { + compatible = "ti,ads1119"; + reg = <0x40>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_7>; + interrupt-parent = <&main_gpio0>; + interrupts = <41 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <®_3v2_ain1>; + dvdd-supply = <®_3v2_ain1>; + vref-supply = <®_3v2_ain1>; + #address-cells = <1>; + #io-channel-cells = <1>; + #size-cells = <0>; + + /* AIN1 0-33V Voltage Input */ + channel@0 { + reg = <0>; + diff-channels = <0 1>; + }; + + /* AIN1 0-20mA Current Input */ + channel@1 { + reg = <1>; + diff-channels = <2 3>; + }; + }; + + ivy_adc2: adc@41 { + compatible = "ti,ads1119"; + reg = <0x41>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_8>; + interrupt-parent = <&main_gpio0>; + interrupts = <42 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <®_3v2_ain2>; + dvdd-supply = <®_3v2_ain2>; + vref-supply = <®_3v2_ain2>; + #address-cells = <1>; + #io-channel-cells = <1>; + #size-cells = <0>; + + /* AIN2 0-33V Voltage Input */ + channel@0 { + reg = <0>; + diff-channels = <0 1>; + }; + + /* AIN2 0-20mA Current Input */ + channel@1 { + reg = <1>; + diff-channels = <2 3>; + }; + }; +}; + +/* Verdin CAN_1 */ +&main_mcan0 { + status = "okay"; +}; + +/* Verdin SPI_1 */ +&main_spi1 { + pinctrl-0 = <&pinctrl_spi1>, + <&pinctrl_spi1_cs0>, + <&pinctrl_gpio_1>, + <&pinctrl_gpio_4>; + cs-gpios = <0>, + <&mcu_gpio0 1 GPIO_ACTIVE_LOW>, + <&mcu_gpio0 4 GPIO_ACTIVE_LOW>; + status = "okay"; + + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + spi-max-frequency = <18500000>; + }; + + fram@2 { + compatible = "fujitsu,mb85rs256", "atmel,at25"; + reg = <2>; + address-width = <16>; + size = <32768>; + spi-max-frequency = <33000000>; + pagesize = <1>; + }; +}; + +/* Verdin UART_3 */ +&main_uart0 { + status = "okay"; +}; + +/* Verdin UART_1 */ +&main_uart1 { + status = "okay"; +}; + +&mcu_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_2>, + <&pinctrl_gpio_3>, + <&pinctrl_pcie_1_reset>; + gpio-line-names = + "", + "", + "GPIO2", /* Verdin GPIO_2 - SODIMM 208 */ + "GPIO3", /* Verdin GPIO_3 - SODIMM 210 */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + ""; +}; + +/* Verdin CAN_2 */ +&mcu_mcan0 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&sdhci1 { + status = "okay"; +}; + +/* Verdin USB_1*/ +&usbss0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usbss1 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +/* Verdin PCIE_1_RESET# */ +&verdin_pcie_1_reset_hog { + status = "okay"; +}; + +/* Verdin UART_2 */ +&wkup_uart0 { + linux,rs485-enabled-at-boot-time; + rs485-rts-active-low; + rs485-rx-during-tx; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi index 5bef31b8577be5..1ea8f64b1b3bd3 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi @@ -160,7 +160,7 @@ reg_sdhc1_vmmc: regulator-sdhci1 { regulator-max-microvolt = <3300000>; regulator-min-microvolt = <3300000>; regulator-name = "+V3.3_SD"; - startup-delay-us = <2000>; + startup-delay-us = <20000>; }; reg_sdhc1_vqmmc: regulator-sdhci1-vqmmc { @@ -1131,6 +1131,11 @@ port@1 { }; }; + tpm@2e { + compatible = "st,st33ktpm2xi2c", "tcg,tpm-tis-i2c"; + reg = <0x2e>; + }; + pmic@30 { compatible = "ti,tps65219"; reg = <0x30>; @@ -1219,11 +1224,12 @@ sensor@48 { reg = <0x48>; }; - adc@49 { - compatible = "ti,ads1015"; + verdin_som_adc: adc@49 { + compatible = "ti,tla2024"; reg = <0x49>; #address-cells = <1>; #size-cells = <0>; + #io-channel-cells = <1>; /* Verdin PMIC_I2C (ADC_4 - ADC_3) */ channel@0 { diff --git a/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi index e0afafd532a5c6..9b8a1f85aa15ca 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-wakeup.dtsi @@ -8,9 +8,9 @@ #include &cbass_wakeup { - wkup_conf: syscon@43000000 { + wkup_conf: bus@43000000 { bootph-all; - compatible = "syscon", "simple-mfd"; + compatible = "simple-bus"; reg = <0x00 0x43000000 0x00 0x20000>; #address-cells = <1>; #size-cells = <1>; @@ -22,6 +22,11 @@ chipid: chipid@14 { reg = <0x14 0x4>; }; + opp_efuse_table: syscon@18 { + compatible = "ti,am62-opp-efuse-table", "syscon"; + reg = <0x18 0x4>; + }; + cpsw_mac_syscon: ethernet-mac-syscon@200 { compatible = "ti,am62p-cpsw-mac-efuse", "syscon"; reg = <0x200 0x8>; diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts index a1cd47d7f5e304..ee96f4f6deb006 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts @@ -419,6 +419,12 @@ AM62X_IOPAD(0x01a8, PIN_INPUT, 7) /* (D20) MCASP0_AFSX.GPIO1_12 */ >; }; + mikrobus_pwm_pins_default: mikrobus-pwm-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x01a4, PIN_INPUT, 2) /* (B20) MCASP0_ACLKX.ECAP2_IN_APWM_OUT */ + >; + }; + main_uart0_pins_default: main-uart0-default-pins { bootph-all; pinctrl-single,pins = < @@ -926,3 +932,9 @@ &mcasp1 { 0 0 0 0 >; }; + +&ecap2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mikrobus_pwm_pins_default>; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-1-4-ghz-opp.dtso b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-1-4-ghz-opp.dtso deleted file mode 100644 index 6ec6d57ec49cdc..00000000000000 --- a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-1-4-ghz-opp.dtso +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT -/* - * Copyright (C) 2024 PHYTEC America LLC - * Author: Nathan Morrisson - */ - -/dts-v1/; -/plugin/; - -&vdd_core { - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <850000>; -}; - -&a53_opp_table { - opp-1400000000 { - opp-hz = /bits/ 64 <1400000000>; - opp-supported-hw = <0x01 0x0004>; - }; -}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-ivy.dts b/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-ivy.dts new file mode 100644 index 00000000000000..48798bf3da4ffe --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-ivy.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/ivy-carrier-board + */ + +/dts-v1/; + +#include "k3-am625.dtsi" +#include "k3-am62-verdin.dtsi" +#include "k3-am62-verdin-nonwifi.dtsi" +#include "k3-am62-verdin-ivy.dtsi" + +/ { + model = "Toradex Verdin AM62 on Ivy Board"; + compatible = "toradex,verdin-am62-nonwifi-ivy", + "toradex,verdin-am62-nonwifi", + "toradex,verdin-am62", + "ti,am625"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-ivy.dts b/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-ivy.dts new file mode 100644 index 00000000000000..d96d8a0ebd8661 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-ivy.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2024 Toradex + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/ivy-carrier-board + */ + +/dts-v1/; + +#include "k3-am625.dtsi" +#include "k3-am62-verdin.dtsi" +#include "k3-am62-verdin-wifi.dtsi" +#include "k3-am62-verdin-ivy.dtsi" + +/ { + model = "Toradex Verdin AM62 WB on Ivy Board"; + compatible = "toradex,verdin-am62-wifi-ivy", + "toradex,verdin-am62-wifi", + "toradex,verdin-am62", + "ti,am625"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625.dtsi b/arch/arm64/boot/dts/ti/k3-am625.dtsi index c3d1db47dc9f35..c249883a8a8d84 100644 --- a/arch/arm64/boot/dts/ti/k3-am625.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am625.dtsi @@ -108,7 +108,7 @@ cpu3: cpu@3 { a53_opp_table: opp-table { compatible = "operating-points-v2-ti-cpu"; opp-shared; - syscon = <&wkup_conf>; + syscon = <&opp_efuse_table>; opp-200000000 { opp-hz = /bits/ 64 <200000000>; diff --git a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi index 16a578ae2b412f..a93e2cd7b8c74a 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi @@ -943,6 +943,33 @@ ecap2: pwm@23120000 { status = "disabled"; }; + eqep0: counter@23200000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23200000 0x00 0x100>; + power-domains = <&k3_pds 59 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 59 0>; + interrupts = ; + status = "disabled"; + }; + + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + + eqep2: counter@23220000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23220000 0x00 0x100>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 62 0>; + interrupts = ; + status = "disabled"; + }; + mcasp0: audio-controller@2b00000 { compatible = "ti,am33xx-mcasp-audio"; reg = <0x00 0x02b00000 0x00 0x2000>, diff --git a/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi index f5ac101a04dfa0..0b1dd5390cd3f4 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a-wakeup.dtsi @@ -17,6 +17,11 @@ chipid: chipid@14 { reg = <0x14 0x4>; }; + opp_efuse_table: syscon@18 { + compatible = "ti,am62-opp-efuse-table", "syscon"; + reg = <0x18 0x4>; + }; + cpsw_mac_syscon: ethernet-mac-syscon@200 { compatible = "ti,am62p-cpsw-mac-efuse", "syscon"; reg = <0x200 0x8>; diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-phyboard-lyra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-phyboard-lyra-rdk.dts index 3b93409b23e7fe..77e5fef618bae9 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a7-phyboard-lyra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62a7-phyboard-lyra-rdk.dts @@ -16,3 +16,7 @@ / { "phytec,am62a-phycore-som", "ti,am62a7"; model = "PHYTEC phyBOARD-Lyra AM62A7"; }; + +&cpsw3g_phy3 { + ti,rx-internal-delay = ; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts index 67faf46d7a35a5..a6f0d87a50d8a7 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts @@ -68,6 +68,15 @@ wkup_r5fss0_core0_memory_region: r5f-dma-memory@9c900000 { }; }; + opp-table { + /* Requires VDD_CORE at 0v85 */ + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-supported-hw = <0x01 0x0004>; + clock-latency-ns = <6000000>; + }; + }; + vmain_pd: regulator-0 { /* TPS25750 PD CONTROLLER OUTPUT */ compatible = "regulator-fixed"; diff --git a/arch/arm64/boot/dts/ti/k3-am62a7.dtsi b/arch/arm64/boot/dts/ti/k3-am62a7.dtsi index f86a23404e6dde..6c99221beb6bd8 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a7.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a7.dtsi @@ -48,6 +48,8 @@ cpu0: cpu@0 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&L2_0>; + operating-points-v2 = <&a53_opp_table>; + clocks = <&k3_clks 135 0>; }; cpu1: cpu@1 { @@ -62,6 +64,8 @@ cpu1: cpu@1 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&L2_0>; + operating-points-v2 = <&a53_opp_table>; + clocks = <&k3_clks 136 0>; }; cpu2: cpu@2 { @@ -76,6 +80,8 @@ cpu2: cpu@2 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&L2_0>; + operating-points-v2 = <&a53_opp_table>; + clocks = <&k3_clks 137 0>; }; cpu3: cpu@3 { @@ -90,6 +96,51 @@ cpu3: cpu@3 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&L2_0>; + operating-points-v2 = <&a53_opp_table>; + clocks = <&k3_clks 138 0>; + }; + }; + + a53_opp_table: opp-table { + compatible = "operating-points-v2-ti-cpu"; + opp-shared; + syscon = <&opp_efuse_table>; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-supported-hw = <0x01 0x0006>; + clock-latency-ns = <6000000>; + }; + + opp-1250000000 { + opp-hz = /bits/ 64 <1250000000>; + opp-supported-hw = <0x01 0x0004>; + clock-latency-ns = <6000000>; + opp-suspend; }; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi index 9b6f5137910837..41e1c24b114414 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-main.dtsi @@ -827,6 +827,33 @@ ecap2: pwm@23120000 { status = "disabled"; }; + eqep0: counter@23200000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23200000 0x00 0x100>; + power-domains = <&k3_pds 59 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 59 0>; + interrupts = ; + status = "disabled"; + }; + + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + + eqep2: counter@23220000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23220000 0x00 0x100>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 62 0>; + interrupts = ; + status = "disabled"; + }; + main_mcan0: can@20701000 { compatible = "bosch,m_can"; reg = <0x00 0x20701000 0x00 0x200>, diff --git a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-wakeup.dtsi index 315d0092e73664..6f32135f00a551 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62p-j722s-common-wakeup.dtsi @@ -20,6 +20,11 @@ chipid: chipid@14 { bootph-all; }; + opp_efuse_table: syscon@18 { + compatible = "ti,am62-opp-efuse-table", "syscon"; + reg = <0x18 0x4>; + }; + cpsw_mac_syscon: ethernet-mac-syscon@200 { compatible = "ti,am62p-cpsw-mac-efuse", "syscon"; reg = <0x200 0x8>; diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts index 3efa12bb725462..7f3dc39e12bc9c 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts @@ -128,6 +128,15 @@ led-0 { }; }; + opp-table { + /* Requires VDD_CORE at 0v85 */ + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-supported-hw = <0x01 0x0004>; + clock-latency-ns = <6000000>; + }; + }; + tlv320_mclk: clk-0 { #clock-cells = <0>; compatible = "fixed-clock"; diff --git a/arch/arm64/boot/dts/ti/k3-am62p5.dtsi b/arch/arm64/boot/dts/ti/k3-am62p5.dtsi index 41f479dca45556..140587d02e88e9 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p5.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62p5.dtsi @@ -47,6 +47,7 @@ cpu0: cpu@0 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + operating-points-v2 = <&a53_opp_table>; clocks = <&k3_clks 135 0>; }; @@ -62,6 +63,7 @@ cpu1: cpu@1 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + operating-points-v2 = <&a53_opp_table>; clocks = <&k3_clks 136 0>; }; @@ -77,6 +79,7 @@ cpu2: cpu@2 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + operating-points-v2 = <&a53_opp_table>; clocks = <&k3_clks 137 0>; }; @@ -92,10 +95,54 @@ cpu3: cpu@3 { d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&l2_0>; + operating-points-v2 = <&a53_opp_table>; clocks = <&k3_clks 138 0>; }; }; + a53_opp_table: opp-table { + compatible = "operating-points-v2-ti-cpu"; + opp-shared; + syscon = <&opp_efuse_table>; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-supported-hw = <0x01 0x0007>; + clock-latency-ns = <6000000>; + }; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-supported-hw = <0x01 0x0006>; + clock-latency-ns = <6000000>; + }; + + opp-1250000000 { + opp-hz = /bits/ 64 <1250000000>; + opp-supported-hw = <0x01 0x0004>; + clock-latency-ns = <6000000>; + opp-suspend; + }; + }; + l2_0: l2-cache0 { compatible = "cache"; cache-unified; diff --git a/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra.dtsi index e4633af87eb9c5..d364c247833f4c 100644 --- a/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62x-phyboard-lyra.dtsi @@ -82,8 +82,8 @@ simple-audio-card,cpu { }; sound_master: simple-audio-card,codec { - sound-dai = <&audio_codec>; - clocks = <&audio_refclk1>; + sound-dai = <&audio_codec>; + clocks = <&audio_refclk1>; }; }; @@ -433,8 +433,6 @@ &mcasp2 { 0 0 0 0 0 0 0 0 >; - tx-num-evt = <32>; - rx-num-evt = <32>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi index 44ff67b6bf1e48..6957b3e44c82f1 100644 --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi @@ -56,6 +56,18 @@ linux,cma { linux,cma-default; }; + mcu_m4fss_dma_memory_region: m4f-dma-memory@9cb00000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9cb00000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@9cc00000 { + compatible = "shared-dma-pool"; + reg = <0x00 0x9cc00000 0x00 0xe00000>; + no-map; + }; + secure_tfa_ddr: tfa@9e780000 { reg = <0x00 0x9e780000 0x00 0x80000>; alignment = <0x1000>; @@ -464,6 +476,13 @@ mbox_m4_0: mbox-m4-0 { }; }; +&mcu_m4fss { + mboxes = <&mailbox0_cluster0 &mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + status = "okay"; +}; + &usbss0 { bootph-all; status = "okay"; diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi index 7eae18399caa6e..c66289a4362bbc 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -1175,6 +1175,33 @@ ecap2: pwm@23120000 { status = "disabled"; }; + eqep0: counter@23200000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23200000 0x00 0x100>; + power-domains = <&k3_pds 59 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 59 0>; + interrupts = ; + status = "disabled"; + }; + + eqep1: counter@23210000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23210000 0x00 0x100>; + power-domains = <&k3_pds 60 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 60 0>; + interrupts = ; + status = "disabled"; + }; + + eqep2: counter@23220000 { + compatible = "ti,am62-eqep"; + reg = <0x00 0x23220000 0x00 0x100>; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 62 0>; + interrupts = ; + status = "disabled"; + }; + main_rti0: watchdog@e000000 { compatible = "ti,j7-rti-wdt"; reg = <0x00 0xe000000 0x00 0x100>; @@ -1261,6 +1288,11 @@ icssg0_mii_g_rt: mii-g-rt@33000 { reg = <0x33000 0x1000>; }; + icssg0_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg0_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; @@ -1426,6 +1458,11 @@ icssg1_mii_g_rt: mii-g-rt@33000 { reg = <0x33000 0x1000>; }; + icssg1_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg1_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; diff --git a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi index ad4bed5d3f9eb2..a243c981e85357 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-mcu.dtsi @@ -161,4 +161,17 @@ mcu_esm: esm@4100000 { /* Interrupt sources: esm0_cfg, esm0_hi, esm0_low, mrti0 */ ti,esm-pins = <0>, <1>, <2>, <85>; }; + + mcu_m4fss: m4fss@5000000 { + compatible = "ti,am64-m4fss"; + reg = <0x00 0x5000000 0x00 0x30000>, + <0x00 0x5040000 0x00 0x10000>; + reg-names = "iram", "dram"; + resets = <&k3_reset 9 1>; + firmware-name = "am64-mcu-m4f0_0-fw"; + ti,sci = <&dmsc>; + ti,sci-dev-id = <9>; + ti,sci-proc-ids = <0x18 0xff>; + status = "disabled"; + }; }; diff --git a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi index 6bece2fb4e9531..99a6fdfaa7fb82 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi @@ -87,6 +87,18 @@ main_r5fss1_core1_memory_region: r5f-memory@a3100000 { reg = <0x00 0xa3100000 0x00 0xf00000>; no-map; }; + + mcu_m4fss_dma_memory_region: m4f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; }; leds { @@ -240,6 +252,15 @@ mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { }; }; +&mailbox0_cluster6 { + status = "okay"; + + mbox_m4_0: mbox-m4-0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; +}; + &main_i2c0 { status = "okay"; pinctrl-names = "default"; @@ -333,6 +354,13 @@ &main_r5fss1_core1 { <&main_r5fss1_core1_memory_region>; }; +&mcu_m4fss { + mboxes = <&mailbox0_cluster6 &mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + status = "okay"; +}; + &ospi0 { status = "okay"; pinctrl-names = "default"; @@ -354,7 +382,6 @@ serial_flash: flash@0 { &sdhci0 { status = "okay"; - bus-width = <8>; non-removable; ti,driver-strength-ohm = <50>; disable-wp; diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm-pcie0-ep.dtso b/arch/arm64/boot/dts/ti/k3-am642-evm-pcie0-ep.dtso new file mode 100644 index 00000000000000..6b029539e0dbb4 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am642-evm-pcie0-ep.dtso @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for enabling PCIE0 instance in Endpoint Configuration with the + * AM642 EVM. + * + * AM642 EVM Product Link: https://www.ti.com/tool/TMDS64EVM + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +/* + * Since Root Complex and Endpoint modes are mutually exclusive + * disable Root Complex mode. + */ +&pcie0_rc { + status = "disabled"; +}; + +&cbass_main { + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic500>; + + pcie0_ep: pcie-ep@f102000 { + compatible = "ti,am64-pcie-ep", "ti,j721e-pcie-ep"; + reg = <0x00 0x0f102000 0x00 0x1000>, + <0x00 0x0f100000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x68000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + max-link-speed = <2>; + num-lanes = <1>; + power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 114 0>; + clock-names = "fck"; + max-functions = /bits/ 8 <1>; + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + ti,syscon-pcie-ctrl = <&main_conf 0x4070>; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts index 97ca16f00cd260..f8ec40523254ba 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts @@ -101,6 +101,18 @@ main_r5fss1_core1_memory_region: r5f-memory@a3100000 { no-map; }; + mcu_m4fss_dma_memory_region: m4f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + rtos_ipc_memory_region: ipc-memories@a5000000 { reg = <0x00 0xa5000000 0x00 0x00800000>; alignment = <0x1000>; @@ -253,6 +265,7 @@ icssg1_eth: icssg1-eth { ti,mii-g-rt = <&icssg1_mii_g_rt>; ti,mii-rt = <&icssg1_mii_rt>; ti,iep = <&icssg1_iep0>, <&icssg1_iep1>; + ti,pa-stats = <&icssg1_pa_stats>; interrupt-parent = <&icssg1_intc>; interrupts = <24 0 2>, <25 1 3>; interrupt-names = "tx_ts0", "tx_ts1"; @@ -450,7 +463,7 @@ AM64X_IOPAD(0x0158, PIN_INPUT, 0) /* (AA6) PRG1_MDIO0_MDIO */ >; }; - icssg1_rgmii1_pins_default: icssg1-rgmii1-default-pins{ + icssg1_rgmii1_pins_default: icssg1-rgmii1-default-pins { pinctrl-single,pins = < AM64X_IOPAD(0x00b8, PIN_INPUT, 2) /* (Y7) PRG1_PRU0_GPO0.PRG1_RGMII1_RD0 */ AM64X_IOPAD(0x00bc, PIN_INPUT, 2) /* (U8) PRG1_PRU0_GPO1.PRG1_RGMII1_RD1 */ @@ -776,6 +789,13 @@ &main_r5fss1_core1 { <&main_r5fss1_core1_memory_region>; }; +&mcu_m4fss { + mboxes = <&mailbox0_cluster6 &mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + status = "okay"; +}; + &serdes_ln_ctrl { idle-states = ; }; diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts index 60285d736e07a3..bc8e1ce11047bb 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts @@ -344,6 +344,10 @@ icssg0_phy2: ethernet-phy@2 { }; }; +&i2c_som_rtc { + trickle-resistor-ohms = <3000>; +}; + &main_i2c1 { status = "okay"; pinctrl-names = "default"; @@ -423,7 +427,6 @@ &sdhci1 { vmmc-supply = <&vcc_3v3_mmc>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; - bus-width = <4>; disable-wp; no-1-8-v; }; diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts index 86369525259c3e..33e421ec18abbc 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts @@ -99,6 +99,18 @@ main_r5fss1_core1_memory_region: r5f-memory@a3100000 { no-map; }; + mcu_m4fss_dma_memory_region: m4f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + mcu_m4fss_memory_region: m4f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + rtos_ipc_memory_region: ipc-memories@a5000000 { reg = <0x00 0xa5000000 0x00 0x00800000>; alignment = <0x1000>; @@ -357,6 +369,16 @@ main_ecap0_pins_default: main-ecap0-default-pins { AM64X_IOPAD(0x0270, PIN_INPUT, 0) /* (D18) ECAP0_IN_APWM_OUT */ >; }; + + main_eqep0_pins_default: main-eqep0-default-pins { + pinctrl-single,pins = < + AM64X_IOPAD(0x00a0, PIN_INPUT, 3) /* (N16) GPMC0_WPn.EQEP0_A */ + AM64X_IOPAD(0x00a4, PIN_INPUT, 3) /* (N17) GPMC0_DIR.EQEP0_B */ + AM64X_IOPAD(0x00ac, PIN_INPUT, 3) /* (R20) GPMC0_CSn1.EQEP0_I */ + AM64X_IOPAD(0x00a8, PIN_INPUT, 3) /* (R19) GPMC0_CSn0.EQEP0_S */ + >; + }; + main_wlan_en_pins_default: main-wlan-en-default-pins { pinctrl-single,pins = < AM64X_IOPAD(0x00c4, PIN_OUTPUT_PULLUP, 7) /* (V8) GPIO0_48 */ @@ -681,9 +703,23 @@ &main_r5fss1_core1 { <&main_r5fss1_core1_memory_region>; }; +&mcu_m4fss { + mboxes = <&mailbox0_cluster6 &mbox_m4_0>; + memory-region = <&mcu_m4fss_dma_memory_region>, + <&mcu_m4fss_memory_region>; + status = "okay"; +}; + &ecap0 { status = "okay"; /* PWM is available on Pin 1 of header J3 */ pinctrl-names = "default"; pinctrl-0 = <&main_ecap0_pins_default>; }; + +&eqep0 { + status = "okay"; + /* EQEP0 A & B available on pins 18 & 22 of J4 header */ + pinctrl-names = "default"; + pinctrl-0 = <&main_eqep0_pins_default>; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index 1f1af7ea233053..94a812a1355baf 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -1167,6 +1167,11 @@ icssg0_mii_g_rt: mii-g-rt@33000 { reg = <0x33000 0x1000>; }; + icssg0_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg0_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; @@ -1333,6 +1338,11 @@ icssg1_mii_g_rt: mii-g-rt@33000 { reg = <0x33000 0x1000>; }; + icssg1_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg1_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; @@ -1499,6 +1509,11 @@ icssg2_mii_g_rt: mii-g-rt@33000 { reg = <0x33000 0x1000>; }; + icssg2_pa_stats: pa-stats@2c000 { + compatible = "ti,pruss-pa-st", "syscon"; + reg = <0x2c000 0x1000>; + }; + icssg2_intc: interrupt-controller@20000 { compatible = "ti,icssg-intc"; reg = <0x20000 0x2000>; diff --git a/arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso b/arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso index 0a6e75265ba929..66bb0b913d4969 100644 --- a/arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso +++ b/arch/arm64/boot/dts/ti/k3-am654-icssg2.dtso @@ -41,6 +41,7 @@ icssg2_eth: icssg2-eth { ti,mii-g-rt = <&icssg2_mii_g_rt>; ti,mii-rt = <&icssg2_mii_rt>; + ti,pa-stats = <&icssg2_pa_stats>; ti,iep = <&icssg2_iep0>, <&icssg2_iep1>; interrupt-parent = <&icssg2_intc>; diff --git a/arch/arm64/boot/dts/ti/k3-am654-idk.dtso b/arch/arm64/boot/dts/ti/k3-am654-idk.dtso index b0ce2cb2fdc8e1..6cb44dae9f90ac 100644 --- a/arch/arm64/boot/dts/ti/k3-am654-idk.dtso +++ b/arch/arm64/boot/dts/ti/k3-am654-idk.dtso @@ -43,6 +43,7 @@ icssg0_eth: icssg0-eth { ti,mii-g-rt = <&icssg0_mii_g_rt>; ti,mii-rt = <&icssg0_mii_rt>; + ti,pa-stats = <&icssg0_pa_stats>; ti,iep = <&icssg0_iep0>, <&icssg0_iep1>; interrupt-parent = <&icssg0_intc>; @@ -109,6 +110,7 @@ icssg1_eth: icssg1-eth { ti,mii-g-rt = <&icssg1_mii_g_rt>; ti,mii-rt = <&icssg1_mii_rt>; + ti,pa-stats = <&icssg1_pa_stats>; ti,iep = <&icssg1_iep0>, <&icssg1_iep1>; interrupt-parent = <&icssg1_intc>; diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts index d5ceab79536ca4..11522b36e0cece 100644 --- a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts @@ -184,6 +184,7 @@ main_uart8_pins_default: main-uart8-default-pins { J721S2_IOPAD(0x0d0, PIN_INPUT, 11) /* (AF26) SPI0_CS1.UART8_RXD */ J721S2_IOPAD(0x0d4, PIN_OUTPUT, 11) /* (AH27) SPI0_CLK.UART8_TXD */ >; + bootph-all; }; main_i2c0_pins_default: main-i2c0-default-pins { @@ -211,6 +212,7 @@ J721S2_IOPAD(0x0f4, PIN_INPUT, 0) /* (R24) MMC1_DAT2 */ J721S2_IOPAD(0x0f0, PIN_INPUT, 0) /* (R22) MMC1_DAT3 */ J721S2_IOPAD(0x0e8, PIN_INPUT, 8) /* (AE25) TIMER_IO0.MMC1_SDCD */ >; + bootph-all; }; vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { @@ -313,6 +315,7 @@ J721S2_WKUP_IOPAD(0x074, PIN_OUTPUT, 0) /* (F28) WKUP_GPIO0_7.WKUP_UART0_RTSn */ J721S2_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (D28) WKUP_UART0_RXD */ J721S2_WKUP_IOPAD(0x04c, PIN_OUTPUT, 0) /* (D27) WKUP_UART0_TXD */ >; + bootph-all; }; mcu_cpsw_pins_default: mcu-cpsw-default-pins { @@ -372,6 +375,7 @@ mcu_uart0_pins_default: mcu-uart0-default-pins { J721S2_WKUP_IOPAD(0x08c, PIN_INPUT, 0) /* (C24) WKUP_GPIO0_13.MCU_UART0_RXD */ J721S2_WKUP_IOPAD(0x088, PIN_OUTPUT, 0) /* (C25) WKUP_GPIO0_12.MCU_UART0_TXD */ >; + bootph-all; }; mcu_rpi_header_gpio0_pins0_default: mcu-rpi-header-gpio0-default-pins-0 { @@ -413,6 +417,7 @@ &wkup_uart0 { status = "reserved"; pinctrl-names = "default"; pinctrl-0 = <&wkup_uart0_pins_default>; + bootph-all; }; &wkup_i2c0 { @@ -495,6 +500,7 @@ &mcu_uart0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&mcu_uart0_pins_default>; + bootph-all; }; &main_uart8 { @@ -503,6 +509,7 @@ &main_uart8 { pinctrl-0 = <&main_uart8_pins_default>; /* Shared with TFA on this platform */ power-domains = <&k3_pds 357 TI_SCI_PD_SHARED>; + bootph-all; }; &main_i2c0 { @@ -597,6 +604,7 @@ &main_sdhci1 { disable-wp; vmmc-supply = <&vdd_mmc1>; vqmmc-supply = <&vdd_sd_dv>; + bootph-all; }; &mcu_cpsw { diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi b/arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi index 5bc0d2fb4b8f39..4ca2d4e2fb9b06 100644 --- a/arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-som.dtsi @@ -156,6 +156,7 @@ wkup_i2c0_pins_default: wkup-i2c0-default-pins { J721S2_WKUP_IOPAD(0x098, PIN_INPUT, 0) /* (H24) WKUP_I2C0_SCL */ J721S2_WKUP_IOPAD(0x09c, PIN_INPUT, 0) /* (H27) WKUP_I2C0_SDA */ >; + bootph-all; }; }; @@ -169,6 +170,7 @@ eeprom@51 { /* AT24C512C-MAHM-T */ compatible = "atmel,24c512"; reg = <0x51>; + bootph-all; }; }; @@ -190,7 +192,6 @@ flash@0 { cdns,read-delay = <4>; partitions { - bootph-all; compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; @@ -226,9 +227,9 @@ partition@800000 { }; partition@3fc0000 { - bootph-pre-ram; label = "ospi.phypattern"; reg = <0x3fc0000 0x40000>; + bootph-all; }; }; }; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts index 6593c5da82c064..db43e7e10b76db 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts +++ b/arch/arm64/boot/dts/ti/k3-j7200-common-proc-board.dts @@ -129,6 +129,7 @@ J721E_WKUP_IOPAD(0x94, PIN_OUTPUT, 0) /* (E21) MCU_UART0_RTSn */ J721E_WKUP_IOPAD(0x8c, PIN_INPUT, 0) /* (D20) MCU_UART0_RXD */ J721E_WKUP_IOPAD(0x88, PIN_OUTPUT, 0) /* (D19) MCU_UART0_TXD */ >; + bootph-all; }; wkup_uart0_pins_default: wkup-uart0-default-pins { @@ -136,6 +137,7 @@ wkup_uart0_pins_default: wkup-uart0-default-pins { J721E_WKUP_IOPAD(0x48, PIN_INPUT, 0) /* (B14) WKUP_UART0_RXD */ J721E_WKUP_IOPAD(0x4c, PIN_OUTPUT, 0) /* (A14) WKUP_UART0_TXD */ >; + bootph-all; }; mcu_cpsw_pins_default: mcu-cpsw-default-pins { @@ -204,6 +206,7 @@ J721E_IOPAD(0xb4, PIN_OUTPUT, 0) /* (T17) UART0_TXD */ J721E_IOPAD(0xc0, PIN_INPUT, 2) /* (W3) SPI0_CS0.UART0_CTSn */ J721E_IOPAD(0xc4, PIN_OUTPUT, 2) /* (U5) SPI0_CS1.UART0_RTSn */ >; + bootph-all; }; main_uart1_pins_default: main-uart1-default-pins { @@ -238,6 +241,7 @@ J721E_IOPAD(0xf0, PIN_INPUT, 0) /* (N20) MMC1_DAT2 */ J721E_IOPAD(0xec, PIN_INPUT, 0) /* (N19) MMC1_DAT3 */ J721E_IOPAD(0xe4, PIN_INPUT, 8) /* (V1) TIMER_IO0.MMC1_SDCD */ >; + bootph-all; }; vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { @@ -254,11 +258,12 @@ J721E_IOPAD(0x38, PIN_OUTPUT, 0) /* (Y21) MCAN3_TX */ }; }; -&main_pmx1 { +&main_pmx2 { main_usbss0_pins_default: main-usbss0-default-pins { pinctrl-single,pins = < J721E_IOPAD(0x04, PIN_OUTPUT, 0) /* (T4) USB0_DRVVBUS */ >; + bootph-all; }; }; @@ -267,12 +272,14 @@ &wkup_uart0 { status = "reserved"; pinctrl-names = "default"; pinctrl-0 = <&wkup_uart0_pins_default>; + bootph-all; }; &mcu_uart0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&mcu_uart0_pins_default>; + bootph-all; }; &main_uart0 { @@ -281,6 +288,7 @@ &main_uart0 { power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>; pinctrl-names = "default"; pinctrl-0 = <&main_uart0_pins_default>; + bootph-all; }; &main_uart1 { @@ -379,6 +387,7 @@ &main_sdhci0 { /* eMMC */ status = "okay"; non-removable; + bootph-all; ti,driver-strength-ohm = <50>; disable-wp; }; @@ -390,6 +399,7 @@ &main_sdhci1 { pinctrl-names = "default"; vmmc-supply = <&vdd_mmc1>; vqmmc-supply = <&vdd_sd_dv>; + bootph-all; ti,driver-strength-ohm = <50>; disable-wp; }; @@ -401,11 +411,13 @@ &serdes_ln_ctrl { &usb_serdes_mux { idle-states = <1>; /* USB0 to SERDES lane 3 */ + bootph-all; }; &usbss0 { pinctrl-names = "default"; pinctrl-0 = <&main_usbss0_pins_default>; + bootph-all; ti,vbus-divider; ti,usb2-only; }; @@ -413,6 +425,7 @@ &usbss0 { &usb0 { dr_mode = "otg"; maximum-speed = "high-speed"; + bootph-all; }; &tscadc0 { diff --git a/arch/arm64/boot/dts/ti/k3-j7200-evm-pcie1-ep.dtso b/arch/arm64/boot/dts/ti/k3-j7200-evm-pcie1-ep.dtso new file mode 100644 index 00000000000000..3cc315a0e0844d --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j7200-evm-pcie1-ep.dtso @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/** + * DT Overlay for enabling PCIE1 instance in Endpoint Configuration with the + * J7 common processor board. + * + * J7 Common Processor Board Product Link: https://www.ti.com/tool/J721EXCPXEVM + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +/* + * Since Root Complex and Endpoint modes are mutually exclusive + * disable Root Complex mode. + */ +&pcie1_rc { + status = "disabled"; +}; + +&cbass_main { + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic500>; + + pcie1_ep: pcie-ep@2910000 { + compatible = "ti,j7200-pcie-ep", "ti,j721e-pcie-ep"; + reg = <0x00 0x02910000 0x00 0x1000>, + <0x00 0x02917000 0x00 0x400>, + <0x00 0x0d800000 0x00 0x00800000>, + <0x00 0x18000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + max-link-speed = <3>; + num-lanes = <2>; + power-domains = <&k3_pds 240 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 240 6>; + clock-names = "fck"; + max-functions = /bits/ 8 <6>; + max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>; + dma-coherent; + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + ti,syscon-pcie-ctrl = <&scm_conf 0x4074>; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi index 9386bf3ef9f684..5ab510a0605fd4 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi @@ -136,6 +136,7 @@ secure_proxy_main: mailbox@32c00000 { <0x00 0x32800000 0x00 0x100000>; interrupt-names = "rx_011"; interrupts = ; + bootph-all; }; hwspinlock: spinlock@30e00000 { @@ -426,10 +427,28 @@ main_pmx0: pinctrl@11c000 { pinctrl-single,function-mask = <0xffffffff>; }; - main_pmx1: pinctrl@11c11c { + main_pmx1: pinctrl@11c110 { compatible = "ti,j7200-padconf", "pinctrl-single"; /* Proxy 0 addressing */ - reg = <0x00 0x11c11c 0x00 0xc>; + reg = <0x00 0x11c110 0x00 0x004>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + main_pmx2: pinctrl@11c11c { + compatible = "ti,j7200-padconf", "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x11c11c 0x00 0x00c>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + main_pmx3: pinctrl@11c164 { + compatible = "ti,j7200-padconf", "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x11c164 0x00 0x008>; #pinctrl-cells = <1>; pinctrl-single,register-width = <32>; pinctrl-single,function-mask = <0xffffffff>; @@ -1145,7 +1164,7 @@ main_spi0: spi@2100000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 266 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 266 1>; + clocks = <&k3_clks 266 4>; status = "disabled"; }; @@ -1156,7 +1175,7 @@ main_spi1: spi@2110000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 267 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 267 1>; + clocks = <&k3_clks 267 4>; status = "disabled"; }; @@ -1167,7 +1186,7 @@ main_spi2: spi@2120000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 268 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 268 1>; + clocks = <&k3_clks 268 4>; status = "disabled"; }; @@ -1178,7 +1197,7 @@ main_spi3: spi@2130000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 269 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 269 1>; + clocks = <&k3_clks 269 4>; status = "disabled"; }; @@ -1189,7 +1208,7 @@ main_spi4: spi@2140000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 270 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 270 1>; + clocks = <&k3_clks 270 2>; status = "disabled"; }; @@ -1200,7 +1219,7 @@ main_spi5: spi@2150000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 271 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 271 1>; + clocks = <&k3_clks 271 4>; status = "disabled"; }; @@ -1211,7 +1230,7 @@ main_spi6: spi@2160000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 272 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 272 1>; + clocks = <&k3_clks 272 4>; status = "disabled"; }; @@ -1222,7 +1241,7 @@ main_spi7: spi@2170000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 273 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 273 1>; + clocks = <&k3_clks 273 4>; status = "disabled"; }; @@ -1527,6 +1546,7 @@ main_r5fss0_core1: r5f@5d00000 { main_esm: esm@700000 { compatible = "ti,j721e-esm"; reg = <0x0 0x700000 0x0 0x1000>; + bootph-pre-ram; ti,esm-pins = <656>, <657>; }; }; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi index 5097d192c2b208..6a845386587465 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi @@ -21,16 +21,19 @@ dmsc: system-controller@44083000 { k3_pds: power-controller { compatible = "ti,sci-pm-domain"; #power-domain-cells = <2>; + bootph-all; }; k3_clks: clock-controller { compatible = "ti,k2g-sci-clk"; #clock-cells = <2>; + bootph-all; }; k3_reset: reset-controller { compatible = "ti,sci-reset"; #reset-cells = <2>; + bootph-all; }; }; @@ -44,6 +47,7 @@ mcu_timer0: timer@40400000 { assigned-clocks = <&k3_clks 35 1>; assigned-clock-parents = <&k3_clks 35 2>; power-domains = <&k3_pds 35 TI_SCI_PD_EXCLUSIVE>; + bootph-pre-ram; ti,timer-pwm; }; @@ -191,6 +195,7 @@ wkup_conf: bus@43000000 { chipid: chipid@14 { compatible = "ti,am654-chipid"; reg = <0x14 0x4>; + bootph-all; }; }; @@ -344,6 +349,7 @@ mcu_ringacc: ringacc@2b800000 { <0x00 0x28440000 0x00 0x40000>; reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg"; + bootph-all; ti,num-rings = <286>; ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */ ti,sci = <&dmsc>; @@ -363,6 +369,7 @@ mcu_udmap: dma-controller@285c0000 { "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; + bootph-all; ti,sci = <&dmsc>; ti,sci-dev-id = <236>; @@ -383,6 +390,8 @@ secure_proxy_mcu: mailbox@2a480000 { reg = <0x0 0x2a480000 0x0 0x80000>, <0x0 0x2a380000 0x0 0x80000>, <0x0 0x2a400000 0x0 0x80000>; + bootph-pre-ram; + /* * Marked Disabled: * Node is incomplete as it is meant for bootloaders and @@ -494,7 +503,7 @@ mcu_spi0: spi@40300000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 274 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 274 0>; + clocks = <&k3_clks 274 4>; status = "disabled"; }; @@ -505,7 +514,7 @@ mcu_spi1: spi@40310000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 275 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 275 0>; + clocks = <&k3_clks 275 4>; status = "disabled"; }; @@ -516,7 +525,7 @@ mcu_spi2: spi@40320000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 276 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 276 0>; + clocks = <&k3_clks 276 2>; status = "disabled"; }; @@ -534,6 +543,7 @@ hbmc_mux: mux-controller@47000004 { reg = <0x00 0x47000004 0x00 0x4>; #mux-control-cells = <1>; mux-reg-masks = <0x0 0x2>; /* HBMC select */ + bootph-all; }; hbmc: hyperbus@47034000 { @@ -652,6 +662,7 @@ wkup_vtm0: temperature-sensor@42040000 { <0x00 0x42050000 0x00 0x350>; power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>; #thermal-sensor-cells = <1>; + bootph-pre-ram; }; mcu_esm: esm@40800000 { diff --git a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi index e78b4622a7d1ff..291ab9bb414d78 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi @@ -121,6 +121,7 @@ J721E_WKUP_IOPAD(0x20, PIN_INPUT, 1) /* (B8) MCU_OSPI0_D5.MCU_HYPERBUS0_DQ5 */ J721E_WKUP_IOPAD(0x24, PIN_INPUT, 1) /* (A8) MCU_OSPI0_D6.MCU_HYPERBUS0_DQ6 */ J721E_WKUP_IOPAD(0x28, PIN_INPUT, 1) /* (A7) MCU_OSPI0_D7.MCU_HYPERBUS0_DQ7 */ >; + bootph-all; }; mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins { @@ -137,6 +138,7 @@ J721E_WKUP_IOPAD(0x0024, PIN_INPUT, 0) /* MCU_OSPI0_D6 */ J721E_WKUP_IOPAD(0x0028, PIN_INPUT, 0) /* MCU_OSPI0_D7 */ J721E_WKUP_IOPAD(0x0008, PIN_INPUT, 0) /* MCU_OSPI0_DQS */ >; + bootph-all; }; }; @@ -146,6 +148,7 @@ wkup_i2c0_pins_default: wkup-i2c0-default-pins { J721E_WKUP_IOPAD(0x98, PIN_INPUT_PULLUP, 0) /* (F20) WKUP_I2C0_SCL */ J721E_WKUP_IOPAD(0x9c, PIN_INPUT_PULLUP, 0) /* (H21) WKUP_I2C0_SDA */ >; + bootph-all; }; }; @@ -186,6 +189,7 @@ &hbmc { flash@0,0 { compatible = "cypress,hyperflash", "cfi-flash"; reg = <0x00 0x00 0x4000000>; + bootph-all; partitions { compatible = "fixed-partitions"; @@ -347,6 +351,7 @@ bucka1: buck1 { regulator-max-microvolt = <1800000>; regulator-boot-on; regulator-always-on; + bootph-all; }; bucka2: buck2 { @@ -520,6 +525,7 @@ partition@800000 { partition@3fc0000 { label = "ospi.phypattern"; reg = <0x3fc0000 0x40000>; + bootph-all; }; }; }; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts index 8230d53cd69609..4c1e02a4e7a25c 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts +++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts @@ -193,6 +193,7 @@ J721E_IOPAD(0x1c0, PIN_OUTPUT, 1) /* (AA2) SPI0_CS0.UART0_RTSn */ J721E_IOPAD(0x1e8, PIN_INPUT, 0) /* (AB2) UART0_RXD */ J721E_IOPAD(0x1ec, PIN_OUTPUT, 0) /* (AB3) UART0_TXD */ >; + bootph-all; }; main_uart1_pins_default: main-uart1-default-pins { @@ -234,6 +235,7 @@ J721E_IOPAD(0x240, PIN_INPUT, 0) /* (R26) MMC1_DAT3 */ J721E_IOPAD(0x258, PIN_INPUT, 0) /* (P23) MMC1_SDCD */ J721E_IOPAD(0x25c, PIN_INPUT, 0) /* (R28) MMC1_SDWP */ >; + bootph-all; }; vdd_sd_dv_alt_pins_default: vdd-sd-dv-alt-default-pins { @@ -247,6 +249,7 @@ main_usbss0_pins_default: main-usbss0-default-pins { J721E_IOPAD(0x290, PIN_OUTPUT, 0) /* (U6) USB0_DRVVBUS */ J721E_IOPAD(0x210, PIN_INPUT, 7) /* (W3) MCAN1_RX.GPIO1_3 */ >; + bootph-all; }; main_usbss1_pins_default: main-usbss1-default-pins { @@ -342,6 +345,7 @@ wkup_uart0_pins_default: wkup-uart0-default-pins { J721E_WKUP_IOPAD(0xa0, PIN_INPUT, 0) /* (J29) WKUP_UART0_RXD */ J721E_WKUP_IOPAD(0xa4, PIN_OUTPUT, 0) /* (J28) WKUP_UART0_TXD */ >; + bootph-all; }; mcu_uart0_pins_default: mcu-uart0-default-pins { @@ -351,6 +355,7 @@ J721E_WKUP_IOPAD(0xec, PIN_OUTPUT, 0) /* (J27) WKUP_GPIO0_15.MCU_UART0_RTSn */ J721E_WKUP_IOPAD(0xe4, PIN_INPUT, 0) /* (H28) WKUP_GPIO0_13.MCU_UART0_RXD */ J721E_WKUP_IOPAD(0xe0, PIN_OUTPUT, 0) /* (G29) WKUP_GPIO0_12.MCU_UART0_TXD */ >; + bootph-all; }; sw11_button_pins_default: sw11-button-default-pins { @@ -370,6 +375,7 @@ J721E_WKUP_IOPAD(0x4c, PIN_INPUT, 0) /* (C23) MCU_OSPI1_D3 */ J721E_WKUP_IOPAD(0x3c, PIN_INPUT, 0) /* (B23) MCU_OSPI1_DQS */ J721E_WKUP_IOPAD(0x38, PIN_INPUT, 0) /* (A23) MCU_OSPI1_LBCLKO */ >; + bootph-all; }; mcu_cpsw_pins_default: mcu-cpsw-default-pins { @@ -435,12 +441,14 @@ &wkup_uart0 { status = "reserved"; pinctrl-names = "default"; pinctrl-0 = <&wkup_uart0_pins_default>; + bootph-all; }; &mcu_uart0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&mcu_uart0_pins_default>; + bootph-all; }; &main_uart0 { @@ -449,6 +457,7 @@ &main_uart0 { pinctrl-0 = <&main_uart0_pins_default>; /* Shared with ATF on this platform */ power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>; + bootph-all; }; &main_uart1 { @@ -487,6 +496,7 @@ &main_sdhci0 { /* eMMC */ status = "okay"; non-removable; + bootph-all; ti,driver-strength-ohm = <50>; disable-wp; }; @@ -498,12 +508,14 @@ &main_sdhci1 { vqmmc-supply = <&vdd_sd_dv_alt>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; + bootph-all; ti,driver-strength-ohm = <50>; disable-wp; }; &usb_serdes_mux { idle-states = <1>, <0>; /* USB0 to SERDES3, USB1 to SERDES1 */ + bootph-all; }; &serdes_ln_ctrl { @@ -513,6 +525,7 @@ &serdes_ln_ctrl { , , , , , ; + bootph-all; }; &serdes_wiz3 { @@ -533,6 +546,7 @@ serdes3_usb_link: phy@0 { &usbss0 { pinctrl-names = "default"; pinctrl-0 = <&main_usbss0_pins_default>; + bootph-all; ti,vbus-divider; }; @@ -541,6 +555,7 @@ &usb0 { maximum-speed = "super-speed"; phys = <&serdes3_usb_link>; phy-names = "cdns3,usb3-phy"; + bootph-all; }; &usbss1 { @@ -613,6 +628,7 @@ partition@800000 { partition@3fe0000 { label = "qspi.phypattern"; reg = <0x3fe0000 0x20000>; + bootph-all; }; }; }; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi index 0da785be80ff47..af3d730154ac54 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi @@ -226,6 +226,7 @@ secure_proxy_main: mailbox@32c00000 { <0x00 0x32800000 0x00 0x100000>; interrupt-names = "rx_011"; interrupts = ; + bootph-all; }; smmu0: iommu@36600000 { @@ -2853,6 +2854,7 @@ main_spi7: spi@2170000 { main_esm: esm@700000 { compatible = "ti,j721e-esm"; reg = <0x0 0x700000 0x0 0x1000>; + bootph-pre-ram; ti,esm-pins = <344>, <345>; }; }; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi index 3731ffb4a5c963..b02142b2b460d1 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi @@ -21,16 +21,19 @@ dmsc: system-controller@44083000 { k3_pds: power-controller { compatible = "ti,sci-pm-domain"; #power-domain-cells = <2>; + bootph-all; }; k3_clks: clock-controller { compatible = "ti,k2g-sci-clk"; #clock-cells = <2>; + bootph-all; }; k3_reset: reset-controller { compatible = "ti,sci-reset"; #reset-cells = <2>; + bootph-all; }; }; @@ -61,6 +64,7 @@ wkup_conf: bus@43000000 { chipid: chipid@14 { compatible = "ti,am654-chipid"; reg = <0x14 0x4>; + bootph-all; }; }; @@ -112,6 +116,7 @@ mcu_timer0: timer@40400000 { assigned-clocks = <&k3_clks 35 1>; assigned-clock-parents = <&k3_clks 35 2>; power-domains = <&k3_pds 35 TI_SCI_PD_EXCLUSIVE>; + bootph-pre-ram; ti,timer-pwm; /* Non-MPU Firmware usage */ status = "reserved"; @@ -362,6 +367,7 @@ hbmc_mux: mux-controller@47000004 { reg = <0x00 0x47000004 0x00 0x4>; #mux-control-cells = <1>; mux-reg-masks = <0x0 0x2>; /* HBMC select */ + bootph-all; }; hbmc: hyperbus@47034000 { @@ -470,6 +476,7 @@ mcu_ringacc: ringacc@2b800000 { <0x0 0x2a500000 0x0 0x40000>, <0x0 0x28440000 0x0 0x40000>; reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg"; + bootph-all; ti,num-rings = <286>; ti,sci-rm-range-gp-rings = <0x1>; /* GP ring range */ ti,sci = <&dmsc>; @@ -489,6 +496,7 @@ mcu_udmap: dma-controller@285c0000 { "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; + bootph-all; ti,sci = <&dmsc>; ti,sci-dev-id = <236>; @@ -509,6 +517,7 @@ secure_proxy_mcu: mailbox@2a480000 { reg = <0x0 0x2a480000 0x0 0x80000>, <0x0 0x2a380000 0x0 0x80000>, <0x0 0x2a400000 0x0 0x80000>; + bootph-pre-ram; /* * Marked Disabled: * Node is incomplete as it is meant for bootloaders and @@ -654,7 +663,7 @@ mcu_spi0: spi@40300000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 274 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 274 0>; + clocks = <&k3_clks 274 1>; status = "disabled"; }; @@ -665,7 +674,7 @@ mcu_spi1: spi@40310000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 275 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 275 0>; + clocks = <&k3_clks 275 1>; status = "disabled"; }; @@ -676,7 +685,7 @@ mcu_spi2: spi@40320000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 276 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 276 0>; + clocks = <&k3_clks 276 1>; status = "disabled"; }; @@ -687,6 +696,7 @@ wkup_vtm0: temperature-sensor@42040000 { <0x00 0x43000300 0x00 0x10>; power-domains = <&k3_pds 154 TI_SCI_PD_EXCLUSIVE>; #thermal-sensor-cells = <1>; + bootph-pre-ram; }; mcu_esm: esm@40800000 { diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts index 6285e8d94ddeb7..69b3d1ed8a21c2 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts @@ -346,6 +346,7 @@ J721E_IOPAD(0x244, PIN_INPUT, 0) /* (R25) MMC1_DAT2 */ J721E_IOPAD(0x240, PIN_INPUT, 0) /* (R26) MMC1_DAT3 */ J721E_IOPAD(0x258, PIN_INPUT, 0) /* (P23) MMC1_SDCD */ >; + bootph-all; }; main_uart0_pins_default: main-uart0-default-pins { @@ -355,6 +356,7 @@ J721E_IOPAD(0x1f4, PIN_OUTPUT, 0) /* (AB1) UART0_RTSn */ J721E_IOPAD(0x1e8, PIN_INPUT, 0) /* (AB2) UART0_RXD */ J721E_IOPAD(0x1ec, PIN_OUTPUT, 0) /* (AB3) UART0_TXD */ >; + bootph-all; }; main_uart1_pins_default: main-uart1-default-pins { @@ -390,12 +392,14 @@ main_usbss0_pins_default: main-usbss0-default-pins { J721E_IOPAD(0x290, PIN_OUTPUT, 0) /* (U6) USB0_DRVVBUS */ J721E_IOPAD(0x210, PIN_INPUT, 7) /* (W3) MCAN1_RX.GPIO1_3 */ >; + bootph-all; }; main_usbss1_pins_default: main-usbss1-default-pins { pinctrl-single,pins = < J721E_IOPAD(0x214, PIN_OUTPUT, 4) /* (V4) MCAN1_TX.USB1_DRVVBUS */ >; + bootph-all; }; main_csi_mux_sel_pins_default: main-csi-mux-sel-default-pins { @@ -594,6 +598,7 @@ J721E_WKUP_IOPAD(0x24, PIN_INPUT, 0) /* (B22) MCU_OSPI0_D6 */ J721E_WKUP_IOPAD(0x28, PIN_INPUT, 0) /* (G21) MCU_OSPI0_D7 */ J721E_WKUP_IOPAD(0x8, PIN_INPUT, 0) /* (D21) MCU_OSPI0_DQS */ >; + bootph-all; }; vdd_mmc1_en_pins_default: vdd-mmc1-en-default-pins { @@ -622,6 +627,7 @@ J721E_WKUP_IOPAD(0xf4, PIN_OUTPUT, 2)/* (D25) MCU_I3C0_SDA.MCU_UART0_RTSn */ J721E_WKUP_IOPAD(0xe4, PIN_INPUT, 0) /* (H28) WKUP_GPIO0_13.MCU_UART0_RXD */ J721E_WKUP_IOPAD(0xe0, PIN_OUTPUT, 0)/* (G29) WKUP_GPIO0_12.MCU_UART0_TXD */ >; + bootph-all; }; wkup_i2c0_pins_default: wkup-i2c0-default-pins { @@ -629,6 +635,7 @@ wkup_i2c0_pins_default: wkup-i2c0-default-pins { J721E_WKUP_IOPAD(0xf8, PIN_INPUT_PULLUP, 0) /* (J25) WKUP_I2C0_SCL */ J721E_WKUP_IOPAD(0xfc, PIN_INPUT_PULLUP, 0) /* (H24) WKUP_I2C0_SDA */ >; + bootph-all; }; mcu_mcan0_pins_default: mcu-mcan0-default-pins { @@ -657,6 +664,7 @@ &wkup_uart0 { status = "reserved"; pinctrl-names = "default"; pinctrl-0 = <&wkup_uart0_pins_default>; + bootph-all; }; &wkup_i2c0 { @@ -821,6 +829,7 @@ &mcu_uart0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&mcu_uart0_pins_default>; + bootph-all; }; &main_uart0 { @@ -829,6 +838,7 @@ &main_uart0 { pinctrl-0 = <&main_uart0_pins_default>; /* Shared with ATF on this platform */ power-domains = <&k3_pds 146 TI_SCI_PD_SHARED>; + bootph-all; }; &main_uart1 { @@ -844,6 +854,7 @@ &main_sdhci1 { vqmmc-supply = <&vdd_sd_dv_alt>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; + bootph-all; ti,driver-strength-ohm = <50>; disable-wp; }; @@ -908,6 +919,7 @@ partition@800000 { partition@3fc0000 { label = "ospi.phypattern"; reg = <0x3fc0000 0x40000>; + bootph-all; }; }; }; @@ -1003,6 +1015,7 @@ &wkup_gpio0 { &usb_serdes_mux { idle-states = <1>, <1>; /* USB0 to SERDES3, USB1 to SERDES2 */ + bootph-all; }; &serdes_ln_ctrl { @@ -1012,6 +1025,7 @@ &serdes_ln_ctrl { , , , , , ; + bootph-all; }; &serdes_wiz3 { @@ -1050,6 +1064,7 @@ &mhdp { &usbss0 { pinctrl-names = "default"; pinctrl-0 = <&main_usbss0_pins_default>; + bootph-all; ti,vbus-divider; }; @@ -1058,6 +1073,7 @@ &usb0 { maximum-speed = "super-speed"; phys = <&serdes3_usb_link>; phy-names = "cdns3,usb3-phy"; + bootph-all; }; &serdes2 { @@ -1073,6 +1089,7 @@ serdes2_usb_link: phy@1 { &usbss1 { pinctrl-names = "default"; pinctrl-0 = <&main_usbss1_pins_default>; + bootph-all; ti,vbus-divider; }; @@ -1081,6 +1098,7 @@ &usb1 { maximum-speed = "super-speed"; phys = <&serdes2_usb_link>; phy-names = "cdns3,usb3-phy"; + bootph-all; }; &mcu_cpsw { diff --git a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi index cef47c67493fcc..0722f6361cc8b0 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi @@ -151,6 +151,7 @@ wkup_i2c0_pins_default: wkup-i2c0-default-pins { J721E_WKUP_IOPAD(0xf8, PIN_INPUT_PULLUP, 0) /* (J25) WKUP_I2C0_SCL */ J721E_WKUP_IOPAD(0xfc, PIN_INPUT_PULLUP, 0) /* (H24) WKUP_I2C0_SDA */ >; + bootph-all; }; pmic_irq_pins_default: pmic-irq-default-pins { @@ -173,6 +174,7 @@ J721E_WKUP_IOPAD(0x0024, PIN_INPUT, 0) /* MCU_OSPI0_D6 */ J721E_WKUP_IOPAD(0x0028, PIN_INPUT, 0) /* MCU_OSPI0_D7 */ J721E_WKUP_IOPAD(0x002c, PIN_OUTPUT, 0) /* MCU_OSPI0_CSn0 */ >; + bootph-all; }; mcu_fss0_hpb0_pins_default: mcu-fss0-hpb0-default-pins { @@ -192,6 +194,7 @@ J721E_WKUP_IOPAD(0x20, PIN_INPUT, 1) /* MCU_HYPERBUS0_DQ5 */ J721E_WKUP_IOPAD(0x24, PIN_INPUT, 1) /* MCU_HYPERBUS0_DQ6 */ J721E_WKUP_IOPAD(0x28, PIN_INPUT, 1) /* MCU_HYPERBUS0_DQ7 */ >; + bootph-all; }; }; @@ -422,6 +425,7 @@ partition@800000 { partition@3fe0000 { label = "ospi.phypattern"; reg = <0x3fe0000 0x20000>; + bootph-all; }; }; }; @@ -440,6 +444,7 @@ &hbmc { flash@0,0 { compatible = "cypress,hyperflash", "cfi-flash"; reg = <0x00 0x00 0x4000000>; + bootph-all; partitions { compatible = "fixed-partitions"; diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts index c5a0b7cbb14f88..e2fc1288ed0766 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts +++ b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts @@ -138,6 +138,7 @@ J721S2_IOPAD(0x044, PIN_OUTPUT, 14) /* (Y26) MCASP0_AXR1.UART8_RTSn */ J721S2_IOPAD(0x0d0, PIN_INPUT, 11) /* (AF26) SPI0_CS1.UART8_RXD */ J721S2_IOPAD(0x0d4, PIN_OUTPUT, 11) /* (AH27) SPI0_CLK.UART8_TXD */ >; + bootph-all; }; main_i2c3_pins_default: main-i2c3-default-pins { @@ -165,6 +166,7 @@ J721S2_IOPAD(0x0f4, PIN_INPUT, 0) /* (R24) MMC1_DAT2 */ J721S2_IOPAD(0x0f0, PIN_INPUT, 0) /* (R22) MMC1_DAT3 */ J721S2_IOPAD(0x0e8, PIN_INPUT, 8) /* (AE25) TIMER_IO0.MMC1_SDCD */ >; + bootph-all; }; vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { @@ -177,6 +179,7 @@ main_usbss0_pins_default: main-usbss0-default-pins { pinctrl-single,pins = < J721S2_IOPAD(0x0ec, PIN_OUTPUT, 6) /* (AG25) TIMER_IO1.USB0_DRVVBUS */ >; + bootph-all; }; main_mcan3_pins_default: main-mcan3-default-pins { @@ -200,6 +203,7 @@ wkup_uart0_pins_default: wkup-uart0-default-pins { J721S2_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (D28) WKUP_UART0_RXD */ J721S2_WKUP_IOPAD(0x04c, PIN_OUTPUT, 0) /* (D27) WKUP_UART0_TXD */ >; + bootph-all; }; mcu_uart0_pins_default: mcu-uart0-default-pins { @@ -209,6 +213,7 @@ J721S2_WKUP_IOPAD(0x094, PIN_OUTPUT, 0) /* (D25) WKUP_GPIO0_15.MCU_UART0_RTSn */ J721S2_WKUP_IOPAD(0x08c, PIN_INPUT, 0) /* (C24) WKUP_GPIO0_13.MCU_UART0_RXD */ J721S2_WKUP_IOPAD(0x088, PIN_OUTPUT, 0) /* (C25) WKUP_GPIO0_12.MCU_UART0_TXD */ >; + bootph-all; }; mcu_cpsw_pins_default: mcu-cpsw-default-pins { @@ -301,6 +306,7 @@ J721S2_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (A20) MCU_OSPI1_D3 */ J721S2_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (B19) MCU_OSPI1_DQS */ J721S2_WKUP_IOPAD(0x00c, PIN_INPUT, 0) /* (B20) MCU_OSPI1_LBCLKO */ >; + bootph-all; }; }; @@ -316,12 +322,14 @@ &wkup_uart0 { status = "reserved"; pinctrl-names = "default"; pinctrl-0 = <&wkup_uart0_pins_default>; + bootph-all; }; &mcu_uart0 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&mcu_uart0_pins_default>; + bootph-all; }; &main_uart8 { @@ -330,6 +338,7 @@ &main_uart8 { pinctrl-0 = <&main_uart8_pins_default>; /* Shared with TFA on this platform */ power-domains = <&k3_pds 357 TI_SCI_PD_SHARED>; + bootph-all; }; &main_i2c0 { @@ -383,6 +392,7 @@ &main_sdhci0 { /* eMMC */ status = "okay"; non-removable; + bootph-all; ti,driver-strength-ohm = <50>; disable-wp; }; @@ -395,6 +405,7 @@ &main_sdhci1 { disable-wp; vmmc-supply = <&vdd_mmc1>; vqmmc-supply = <&vdd_sd_dv>; + bootph-all; }; &mcu_cpsw { @@ -444,6 +455,7 @@ &usbss0 { status = "okay"; pinctrl-0 = <&main_usbss0_pins_default>; pinctrl-names = "default"; + bootph-all; ti,vbus-divider; ti,usb2-only; }; @@ -451,6 +463,7 @@ &usbss0 { &usb0 { dr_mode = "otg"; maximum-speed = "high-speed"; + bootph-all; }; &ospi1 { @@ -464,6 +477,7 @@ flash@0 { spi-tx-bus-width = <1>; spi-rx-bus-width = <4>; spi-max-frequency = <40000000>; + bootph-all; cdns,tshsl-ns = <60>; cdns,tsd2d-ns = <60>; cdns,tchsh-ns = <60>; diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi index 9ed6949b40e9df..92bf48fdbeba45 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi @@ -816,6 +816,7 @@ secure_proxy_main: mailbox@32c00000 { <0x00 0x32800000 0x00 0x100000>; interrupt-names = "rx_011"; interrupts = ; + bootph-all; }; hwspinlock: spinlock@30e00000 { @@ -1708,7 +1709,7 @@ main_spi0: spi@2100000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 339 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 339 1>; + clocks = <&k3_clks 339 2>; status = "disabled"; }; @@ -1719,7 +1720,7 @@ main_spi1: spi@2110000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 340 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 340 1>; + clocks = <&k3_clks 340 2>; status = "disabled"; }; @@ -1730,7 +1731,7 @@ main_spi2: spi@2120000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 341 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 341 1>; + clocks = <&k3_clks 341 2>; status = "disabled"; }; @@ -1741,7 +1742,7 @@ main_spi3: spi@2130000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 342 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 342 1>; + clocks = <&k3_clks 342 2>; status = "disabled"; }; @@ -1752,7 +1753,7 @@ main_spi4: spi@2140000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 343 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 343 1>; + clocks = <&k3_clks 343 2>; status = "disabled"; }; @@ -1763,7 +1764,7 @@ main_spi5: spi@2150000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 344 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 344 1>; + clocks = <&k3_clks 344 2>; status = "disabled"; }; @@ -1774,7 +1775,7 @@ main_spi6: spi@2160000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 345 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 345 1>; + clocks = <&k3_clks 345 2>; status = "disabled"; }; @@ -1785,7 +1786,7 @@ main_spi7: spi@2170000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 346 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 346 1>; + clocks = <&k3_clks 346 2>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi index 9d96b19d0e7cf5..bc31266126d084 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi @@ -21,16 +21,19 @@ sms: system-controller@44083000 { k3_pds: power-controller { compatible = "ti,sci-pm-domain"; #power-domain-cells = <2>; + bootph-all; }; k3_clks: clock-controller { compatible = "ti,k2g-sci-clk"; #clock-cells = <2>; + bootph-all; }; k3_reset: reset-controller { compatible = "ti,sci-reset"; #reset-cells = <2>; + bootph-all; }; }; @@ -43,6 +46,7 @@ wkup_conf: bus@43000000 { chipid: chipid@14 { compatible = "ti,am654-chipid"; reg = <0x14 0x4>; + bootph-all; }; }; @@ -53,6 +57,8 @@ secure_proxy_sa3: mailbox@43600000 { reg = <0x00 0x43600000 0x00 0x10000>, <0x00 0x44880000 0x00 0x20000>, <0x00 0x44860000 0x00 0x20000>; + bootph-pre-ram; + /* * Marked Disabled: * Node is incomplete as it is meant for bootloaders and @@ -167,6 +173,7 @@ mcu_timer0: timer@40400000 { assigned-clocks = <&k3_clks 35 1>; assigned-clock-parents = <&k3_clks 35 2>; power-domains = <&k3_pds 35 TI_SCI_PD_EXCLUSIVE>; + bootph-pre-ram; ti,timer-pwm; /* Non-MPU Firmware usage */ status = "reserved"; @@ -361,6 +368,7 @@ wkup_i2c0: i2c@42120000 { clocks = <&k3_clks 223 1>; clock-names = "fck"; power-domains = <&k3_pds 223 TI_SCI_PD_EXCLUSIVE>; + bootph-all; status = "disabled"; }; @@ -425,7 +433,7 @@ mcu_spi0: spi@40300000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 347 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 347 0>; + clocks = <&k3_clks 347 2>; status = "disabled"; }; @@ -436,7 +444,7 @@ mcu_spi1: spi@40310000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 348 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 348 0>; + clocks = <&k3_clks 348 2>; status = "disabled"; }; @@ -447,7 +455,7 @@ mcu_spi2: spi@40320000 { #address-cells = <1>; #size-cells = <0>; power-domains = <&k3_pds 349 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 349 0>; + clocks = <&k3_clks 349 2>; status = "disabled"; }; @@ -469,6 +477,7 @@ mcu_ringacc: ringacc@2b800000 { <0x0 0x2a500000 0x0 0x40000>, <0x0 0x28440000 0x0 0x40000>; reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg"; + bootph-all; ti,num-rings = <286>; ti,sci-rm-range-gp-rings = <0x1>; ti,sci = <&sms>; @@ -488,6 +497,7 @@ mcu_udmap: dma-controller@285c0000 { "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; + bootph-all; ti,sci = <&sms>; ti,sci-dev-id = <273>; @@ -507,6 +517,8 @@ secure_proxy_mcu: mailbox@2a480000 { reg = <0x00 0x2a480000 0x00 0x80000>, <0x00 0x2a380000 0x00 0x80000>, <0x00 0x2a400000 0x00 0x80000>; + bootph-pre-ram; + /* * Marked Disabled: * Node is incomplete as it is meant for bootloaders and @@ -667,6 +679,7 @@ wkup_vtm0: temperature-sensor@42040000 { <0x00 0x42050000 0x0 0x350>; power-domains = <&k3_pds 180 TI_SCI_PD_SHARED>; #thermal-sensor-cells = <1>; + bootph-pre-ram; }; mcu_r5fss0: r5fss@41000000 { diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi index 89252e4a5f1bc2..b3a0385ed3d86c 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi @@ -170,6 +170,7 @@ J721S2_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (F20) MCU_OSPI0_D7 */ J721S2_WKUP_IOPAD(0x008, PIN_INPUT, 0) /* (E18) MCU_OSPI0_DQS */ J721S2_WKUP_IOPAD(0x004, PIN_INPUT, 0) /* (E20) MCU_OSPI0_LBCLKO */ >; + bootph-all; }; }; @@ -188,6 +189,7 @@ wkup_i2c0_pins_default: wkup-i2c0-default-pins { J721S2_WKUP_IOPAD(0x98, PIN_INPUT, 0) /* (H24) WKUP_I2C0_SCL */ J721S2_WKUP_IOPAD(0x9c, PIN_INPUT, 0) /* (H27) WKUP_I2C0_SDA */ >; + bootph-pre-ram; }; }; @@ -440,6 +442,7 @@ flash@0 { spi-tx-bus-width = <8>; spi-rx-bus-width = <8>; spi-max-frequency = <25000000>; + bootph-all; cdns,tshsl-ns = <60>; cdns,tsd2d-ns = <60>; cdns,tchsh-ns = <60>; diff --git a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi index ed6f4ba08afca1..3ac2d45a055857 100644 --- a/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j722s-main.dtsi @@ -135,7 +135,7 @@ usbss1: usb@f920000 { ranges; status = "disabled"; - usb1: usb@31200000{ + usb1: usb@31200000 { compatible = "cdns,usb3"; reg = <0x00 0x31200000 0x00 0x10000>, <0x00 0x31210000 0x00 0x10000>, diff --git a/arch/arm64/boot/dts/ti/k3-j742s2-evm.dts b/arch/arm64/boot/dts/ti/k3-j742s2-evm.dts new file mode 100644 index 00000000000000..fcb7f05d7faf54 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j742s2-evm.dts @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + * EVM Board Schematics: https://www.ti.com/lit/zip/SPAC001 + */ + +/dts-v1/; + +#include +#include +#include "k3-j742s2.dtsi" +#include "k3-j784s4-j742s2-evm-common.dtsi" + +/ { + model = "Texas Instruments J742S2 EVM"; + compatible = "ti,j742s2-evm", "ti,j742s2"; + + memory@80000000 { + /* 16G RAM */ + reg = <0x00000000 0x80000000 0x00000000 0x80000000>, + <0x00000008 0x80000000 0x00000003 0x80000000>; + device_type = "memory"; + bootph-all; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j742s2-main.dtsi b/arch/arm64/boot/dts/ti/k3-j742s2-main.dtsi new file mode 100644 index 00000000000000..b320c27f7afea9 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j742s2-main.dtsi @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Device Tree Source for J742S2 SoC Family + * + * TRM: https://www.ti.com/lit/pdf/spruje3 + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +&c71_0 { + firmware-name = "j742s2-c71_0-fw"; +}; + +&c71_1 { + firmware-name = "j742s2-c71_1-fw"; +}; + +&c71_2 { + firmware-name = "j742s2-c71_2-fw"; +}; + +&main_r5fss0_core0 { + firmware-name = "j742s2-main-r5f0_0-fw"; +}; + +&main_r5fss0_core1 { + firmware-name = "j742s2-main-r5f0_1-fw"; +}; + +&main_r5fss1_core0 { + firmware-name = "j742s2-main-r5f1_0-fw"; +}; + +&main_r5fss1_core1 { + firmware-name = "j742s2-main-r5f1_1-fw"; +}; + +&main_r5fss2_core0 { + firmware-name = "j742s2-main-r5f2_0-fw"; +}; + +&main_r5fss2_core1 { + firmware-name = "j742s2-main-r5f2_1-fw"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j742s2.dtsi b/arch/arm64/boot/dts/ti/k3-j742s2.dtsi new file mode 100644 index 00000000000000..7a72f82f56d688 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j742s2.dtsi @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Device Tree Source for J742S2 SoC Family + * + * TRM: https://www.ti.com/lit/pdf/spruje3 + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + */ +#include "k3-j784s4-j742s2-common.dtsi" + +/ { + model = "Texas Instruments K3 J742S2 SoC"; + compatible = "ti,j742s2"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0: cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + + core2 { + cpu = <&cpu2>; + }; + + core3 { + cpu = <&cpu3>; + }; + }; + }; + + cpu0: cpu@0 { + compatible = "arm,cortex-a72"; + reg = <0x000>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&L2_0>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a72"; + reg = <0x001>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&L2_0>; + }; + + cpu2: cpu@2 { + compatible = "arm,cortex-a72"; + reg = <0x002>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&L2_0>; + }; + + cpu3: cpu@3 { + compatible = "arm,cortex-a72"; + reg = <0x003>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&L2_0>; + }; + }; +}; + +#include "k3-j742s2-main.dtsi" diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts index 6695ebbcb4d0b1..a84bde08f85e4a 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts @@ -10,176 +10,23 @@ #include #include #include "k3-j784s4.dtsi" +#include "k3-j784s4-j742s2-evm-common.dtsi" / { compatible = "ti,j784s4-evm", "ti,j784s4"; model = "Texas Instruments J784S4 EVM"; - chosen { - stdout-path = "serial2:115200n8"; - }; - - aliases { - serial0 = &wkup_uart0; - serial1 = &mcu_uart0; - serial2 = &main_uart8; - mmc0 = &main_sdhci0; - mmc1 = &main_sdhci1; - i2c0 = &wkup_i2c0; - i2c3 = &main_i2c0; - ethernet0 = &mcu_cpsw_port1; - ethernet1 = &main_cpsw1_port1; - }; - memory@80000000 { - device_type = "memory"; - bootph-all; /* 32G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x80000000>, <0x00000008 0x80000000 0x00000007 0x80000000>; + device_type = "memory"; + bootph-all; }; reserved_memory: reserved-memory { #address-cells = <2>; #size-cells = <2>; - ranges; - - secure_ddr: optee@9e800000 { - reg = <0x00 0x9e800000 0x00 0x01800000>; - no-map; - }; - - mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa0000000 0x00 0x100000>; - no-map; - }; - - mcu_r5fss0_core0_memory_region: r5f-memory@a0100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa0100000 0x00 0xf00000>; - no-map; - }; - - mcu_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa1000000 0x00 0x100000>; - no-map; - }; - - mcu_r5fss0_core1_memory_region: r5f-memory@a1100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa1100000 0x00 0xf00000>; - no-map; - }; - - main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a2000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa2000000 0x00 0x100000>; - no-map; - }; - - main_r5fss0_core0_memory_region: r5f-memory@a2100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa2100000 0x00 0xf00000>; - no-map; - }; - - main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a3000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa3000000 0x00 0x100000>; - no-map; - }; - - main_r5fss0_core1_memory_region: r5f-memory@a3100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa3100000 0x00 0xf00000>; - no-map; - }; - - main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a4000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa4000000 0x00 0x100000>; - no-map; - }; - - main_r5fss1_core0_memory_region: r5f-memory@a4100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa4100000 0x00 0xf00000>; - no-map; - }; - - main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a5000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa5000000 0x00 0x100000>; - no-map; - }; - - main_r5fss1_core1_memory_region: r5f-memory@a5100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa5100000 0x00 0xf00000>; - no-map; - }; - - main_r5fss2_core0_dma_memory_region: r5f-dma-memory@a6000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa6000000 0x00 0x100000>; - no-map; - }; - - main_r5fss2_core0_memory_region: r5f-memory@a6100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa6100000 0x00 0xf00000>; - no-map; - }; - - main_r5fss2_core1_dma_memory_region: r5f-dma-memory@a7000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa7000000 0x00 0x100000>; - no-map; - }; - - main_r5fss2_core1_memory_region: r5f-memory@a7100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa7100000 0x00 0xf00000>; - no-map; - }; - - c71_0_dma_memory_region: c71-dma-memory@a8000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa8000000 0x00 0x100000>; - no-map; - }; - - c71_0_memory_region: c71-memory@a8100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa8100000 0x00 0xf00000>; - no-map; - }; - - c71_1_dma_memory_region: c71-dma-memory@a9000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa9000000 0x00 0x100000>; - no-map; - }; - - c71_1_memory_region: c71-memory@a9100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xa9100000 0x00 0xf00000>; - no-map; - }; - - c71_2_dma_memory_region: c71-dma-memory@aa000000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xaa000000 0x00 0x100000>; - no-map; - }; - - c71_2_memory_region: c71-memory@aa100000 { - compatible = "shared-dma-pool"; - reg = <0x00 0xaa100000 0x00 0xf00000>; - no-map; - }; c71_3_dma_memory_region: c71-dma-memory@ab000000 { compatible = "shared-dma-pool"; @@ -193,1339 +40,18 @@ c71_3_memory_region: c71-memory@ab100000 { no-map; }; }; - - evm_12v0: regulator-evm12v0 { - /* main supply */ - compatible = "regulator-fixed"; - regulator-name = "evm_12v0"; - regulator-min-microvolt = <12000000>; - regulator-max-microvolt = <12000000>; - regulator-always-on; - regulator-boot-on; - }; - - vsys_3v3: regulator-vsys3v3 { - /* Output of LM5140 */ - compatible = "regulator-fixed"; - regulator-name = "vsys_3v3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - vin-supply = <&evm_12v0>; - regulator-always-on; - regulator-boot-on; - }; - - vsys_5v0: regulator-vsys5v0 { - /* Output of LM5140 */ - compatible = "regulator-fixed"; - regulator-name = "vsys_5v0"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - vin-supply = <&evm_12v0>; - regulator-always-on; - regulator-boot-on; - }; - - vdd_mmc1: regulator-sd { - /* Output of TPS22918 */ - compatible = "regulator-fixed"; - regulator-name = "vdd_mmc1"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - enable-active-high; - vin-supply = <&vsys_3v3>; - gpio = <&exp2 2 GPIO_ACTIVE_HIGH>; - }; - - vdd_sd_dv: regulator-TLV71033 { - /* Output of TLV71033 */ - compatible = "regulator-gpio"; - regulator-name = "tlv71033"; - pinctrl-names = "default"; - pinctrl-0 = <&vdd_sd_dv_pins_default>; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - vin-supply = <&vsys_5v0>; - gpios = <&main_gpio0 8 GPIO_ACTIVE_HIGH>; - states = <1800000 0x0>, - <3300000 0x1>; - }; - - dp0_pwr_3v3: regulator-dp0-prw { - compatible = "regulator-fixed"; - regulator-name = "dp0-pwr"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - gpio = <&exp4 0 GPIO_ACTIVE_HIGH>; - enable-active-high; - }; - - dp0: connector-dp0 { - compatible = "dp-connector"; - label = "DP0"; - type = "full-size"; - dp-pwr-supply = <&dp0_pwr_3v3>; - - port { - dp0_connector_in: endpoint { - remote-endpoint = <&dp0_out>; - }; - }; - }; - - transceiver0: can-phy0 { - compatible = "ti,tcan1042"; - #phy-cells = <0>; - max-bitrate = <5000000>; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_mcan0_gpio_pins_default>; - standby-gpios = <&wkup_gpio0 69 GPIO_ACTIVE_HIGH>; - }; - - transceiver1: can-phy1 { - compatible = "ti,tcan1042"; - #phy-cells = <0>; - max-bitrate = <5000000>; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_mcan1_gpio_pins_default>; - standby-gpios = <&wkup_gpio0 2 GPIO_ACTIVE_HIGH>; - }; - - transceiver2: can-phy2 { - /* standby pin has been grounded by default */ - compatible = "ti,tcan1042"; - #phy-cells = <0>; - max-bitrate = <5000000>; - }; - - transceiver3: can-phy3 { - compatible = "ti,tcan1042"; - #phy-cells = <0>; - max-bitrate = <5000000>; - standby-gpios = <&exp2 7 GPIO_ACTIVE_HIGH>; - mux-states = <&mux1 1>; - }; - - mux1: mux-controller { - compatible = "gpio-mux"; - #mux-state-cells = <1>; - mux-gpios = <&exp2 14 GPIO_ACTIVE_HIGH>; - idle-state = <1>; - }; - - codec_audio: sound { - compatible = "ti,j7200-cpb-audio"; - model = "j784s4-cpb"; - - ti,cpb-mcasp = <&mcasp0>; - ti,cpb-codec = <&pcm3168a_1>; - - clocks = <&k3_clks 265 0>, <&k3_clks 265 1>, - <&k3_clks 157 34>, <&k3_clks 157 63>; - clock-names = "cpb-mcasp-auxclk", "cpb-mcasp-auxclk-48000", - "cpb-codec-scki", "cpb-codec-scki-48000"; - }; -}; - -&wkup_gpio0 { - status = "okay"; -}; - -&main_pmx0 { - bootph-all; - main_cpsw2g_default_pins: main-cpsw2g-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x0b8, PIN_INPUT, 6) /* (AC34) MCASP1_ACLKX.RGMII1_RD0 */ - J784S4_IOPAD(0x0a0, PIN_INPUT, 6) /* (AD34) MCASP0_AXR12.RGMII1_RD1 */ - J784S4_IOPAD(0x0a4, PIN_INPUT, 6) /* (AJ36) MCASP0_AXR13.RGMII1_RD2 */ - J784S4_IOPAD(0x0a8, PIN_INPUT, 6) /* (AF34) MCASP0_AXR14.RGMII1_RD3 */ - J784S4_IOPAD(0x0b0, PIN_INPUT, 6) /* (AL33) MCASP1_AXR3.RGMII1_RXC */ - J784S4_IOPAD(0x0ac, PIN_INPUT, 6) /* (AE34) MCASP0_AXR15.RGMII1_RX_CTL */ - J784S4_IOPAD(0x08c, PIN_INPUT, 6) /* (AE35) MCASP0_AXR7.RGMII1_TD0 */ - J784S4_IOPAD(0x090, PIN_INPUT, 6) /* (AC35) MCASP0_AXR8.RGMII1_TD1 */ - J784S4_IOPAD(0x094, PIN_INPUT, 6) /* (AG35) MCASP0_AXR9.RGMII1_TD2 */ - J784S4_IOPAD(0x098, PIN_INPUT, 6) /* (AH36) MCASP0_AXR10.RGMII1_TD3 */ - J784S4_IOPAD(0x0b4, PIN_INPUT, 6) /* (AL34) MCASP1_AXR4.RGMII1_TXC */ - J784S4_IOPAD(0x09c, PIN_INPUT, 6) /* (AF35) MCASP0_AXR11.RGMII1_TX_CTL */ - >; - }; - - main_cpsw2g_mdio_default_pins: main-cpsw2g-mdio-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x0c0, PIN_INPUT, 6) /* (AD38) MCASP1_AXR0.MDIO0_MDC */ - J784S4_IOPAD(0x0bc, PIN_INPUT, 6) /* (AD33) MCASP1_AFSX.MDIO0_MDIO */ - >; - }; - - main_uart8_pins_default: main-uart8-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_IOPAD(0x040, PIN_INPUT, 14) /* (AF37) MCASP0_AXR0.UART8_CTSn */ - J784S4_IOPAD(0x044, PIN_OUTPUT, 14) /* (AG37) MCASP0_AXR1.UART8_RTSn */ - J784S4_IOPAD(0x0d0, PIN_INPUT, 11) /* (AP38) SPI0_CS1.UART8_RXD */ - J784S4_IOPAD(0x0d4, PIN_OUTPUT, 11) /* (AN38) SPI0_CLK.UART8_TXD */ - >; - }; - - main_i2c0_pins_default: main-i2c0-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x0e0, PIN_INPUT_PULLUP, 0) /* (AN36) I2C0_SCL */ - J784S4_IOPAD(0x0e4, PIN_INPUT_PULLUP, 0) /* (AP37) I2C0_SDA */ - >; - }; - - main_i2c5_pins_default: main-i2c5-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x01c, PIN_INPUT, 8) /* (AG34) MCAN15_TX.I2C5_SCL */ - J784S4_IOPAD(0x018, PIN_INPUT, 8) /* (AK36) MCAN14_RX.I2C5_SDA */ - >; - }; - - main_mmc1_pins_default: main-mmc1-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_IOPAD(0x104, PIN_INPUT, 0) /* (AB38) MMC1_CLK */ - J784S4_IOPAD(0x108, PIN_INPUT, 0) /* (AB36) MMC1_CMD */ - J784S4_IOPAD(0x100, PIN_INPUT, 0) /* (No Pin) MMC1_CLKLB */ - J784S4_IOPAD(0x0fc, PIN_INPUT, 0) /* (AA33) MMC1_DAT0 */ - J784S4_IOPAD(0x0f8, PIN_INPUT, 0) /* (AB34) MMC1_DAT1 */ - J784S4_IOPAD(0x0f4, PIN_INPUT, 0) /* (AA32) MMC1_DAT2 */ - J784S4_IOPAD(0x0f0, PIN_INPUT, 0) /* (AC38) MMC1_DAT3 */ - J784S4_IOPAD(0x0e8, PIN_INPUT, 8) /* (AR38) TIMER_IO0.MMC1_SDCD */ - >; - }; - - vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x020, PIN_INPUT, 7) /* (AJ35) MCAN15_RX.GPIO0_8 */ - >; - }; - - dp0_pins_default: dp0-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x0cc, PIN_INPUT, 12) /* (AM37) SPI0_CS0.DP0_HPD */ - >; - }; - - main_i2c4_pins_default: main-i2c4-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x014, PIN_INPUT_PULLUP, 8) /* (AG33) MCAN14_TX.I2C4_SCL */ - J784S4_IOPAD(0x010, PIN_INPUT_PULLUP, 8) /* (AH33) MCAN13_RX.I2C4_SDA */ - >; - }; - - main_mcan4_pins_default: main-mcan4-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x088, PIN_INPUT, 0) /* (AF36) MCAN4_RX */ - J784S4_IOPAD(0x084, PIN_OUTPUT, 0) /* (AG38) MCAN4_TX */ - >; - }; - - main_mcan16_pins_default: main-mcan16-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x028, PIN_INPUT, 0) /* (AE33) MCAN16_RX */ - J784S4_IOPAD(0x024, PIN_OUTPUT, 0) /* (AH34) MCAN16_TX */ - >; - }; - - main_usbss0_pins_default: main-usbss0-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_IOPAD(0x0ec, PIN_OUTPUT, 6) /* (AN37) TIMER_IO1.USB0_DRVVBUS */ - >; - }; - - main_i2c3_pins_default: main-i2c3-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x064, PIN_INPUT, 13) /* (AF38) MCAN0_TX.I2C3_SCL */ - J784S4_IOPAD(0x060, PIN_INPUT, 13) /* (AE36) MCASP2_AXR1.I2C3_SDA */ - >; - }; - - main_mcasp0_pins_default: main-mcasp0-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x038, PIN_OUTPUT_PULLDOWN, 1) /* (AK35) MCASP0_ACLKX */ - J784S4_IOPAD(0x03c, PIN_OUTPUT_PULLDOWN, 1) /* (AK38) MCASP0_AFSX */ - J784S4_IOPAD(0x07c, PIN_OUTPUT_PULLDOWN, 1) /* (AJ38) MCASP0_AXR3 */ - J784S4_IOPAD(0x080, PIN_INPUT_PULLDOWN, 1) /* (AK34) MCASP0_AXR4 */ - >; - }; - - audio_ext_refclk1_pins_default: audio-ext-refclk1-default-pins { - pinctrl-single,pins = < - J784S4_IOPAD(0x078, PIN_OUTPUT, 1) /* (AH37) MCAN2_RX.AUDIO_EXT_REFCLK1 */ - >; - }; -}; - -&wkup_pmx2 { - bootph-all; - wkup_uart0_pins_default: wkup-uart0-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (K35) WKUP_UART0_RXD */ - J784S4_WKUP_IOPAD(0x04c, PIN_OUTPUT, 0) /* (K34) WKUP_UART0_TXD */ - >; - }; - - wkup_i2c0_pins_default: wkup-i2c0-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x98, PIN_INPUT, 0) /* (N33) WKUP_I2C0_SCL */ - J784S4_WKUP_IOPAD(0x9c, PIN_INPUT, 0) /* (N35) WKUP_I2C0_SDA */ - >; - }; - - mcu_uart0_pins_default: mcu-uart0-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x090, PIN_INPUT, 0) /* (H37) WKUP_GPIO0_14.MCU_UART0_CTSn */ - J784S4_WKUP_IOPAD(0x094, PIN_OUTPUT, 0) /* (K37) WKUP_GPIO0_15.MCU_UART0_RTSn */ - J784S4_WKUP_IOPAD(0x08c, PIN_INPUT, 0) /* (K38) WKUP_GPIO0_13.MCU_UART0_RXD */ - J784S4_WKUP_IOPAD(0x088, PIN_OUTPUT, 0) /* (J37) WKUP_GPIO0_12.MCU_UART0_TXD */ - >; - }; - - mcu_cpsw_pins_default: mcu-cpsw-default-pins { - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x02c, PIN_INPUT, 0) /* (A35) MCU_RGMII1_RD0 */ - J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (B36) MCU_RGMII1_RD1 */ - J784S4_WKUP_IOPAD(0x024, PIN_INPUT, 0) /* (C36) MCU_RGMII1_RD2 */ - J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (D36) MCU_RGMII1_RD3 */ - J784S4_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (B37) MCU_RGMII1_RXC */ - J784S4_WKUP_IOPAD(0x004, PIN_INPUT, 0) /* (C37) MCU_RGMII1_RX_CTL */ - J784S4_WKUP_IOPAD(0x014, PIN_OUTPUT, 0) /* (D37) MCU_RGMII1_TD0 */ - J784S4_WKUP_IOPAD(0x010, PIN_OUTPUT, 0) /* (D38) MCU_RGMII1_TD1 */ - J784S4_WKUP_IOPAD(0x00c, PIN_OUTPUT, 0) /* (E37) MCU_RGMII1_TD2 */ - J784S4_WKUP_IOPAD(0x008, PIN_OUTPUT, 0) /* (E38) MCU_RGMII1_TD3 */ - J784S4_WKUP_IOPAD(0x018, PIN_OUTPUT, 0) /* (E36) MCU_RGMII1_TXC */ - J784S4_WKUP_IOPAD(0x000, PIN_OUTPUT, 0) /* (C38) MCU_RGMII1_TX_CTL */ - >; - }; - - mcu_mdio_pins_default: mcu-mdio-default-pins { - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x034, PIN_OUTPUT, 0) /* (A36) MCU_MDIO0_MDC */ - J784S4_WKUP_IOPAD(0x030, PIN_INPUT, 0) /* (B35) MCU_MDIO0_MDIO */ - >; - }; - - mcu_adc0_pins_default: mcu-adc0-default-pins { - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x0cc, PIN_INPUT, 0) /* (P36) MCU_ADC0_AIN0 */ - J784S4_WKUP_IOPAD(0x0d0, PIN_INPUT, 0) /* (V36) MCU_ADC0_AIN1 */ - J784S4_WKUP_IOPAD(0x0d4, PIN_INPUT, 0) /* (T34) MCU_ADC0_AIN2 */ - J784S4_WKUP_IOPAD(0x0d8, PIN_INPUT, 0) /* (T36) MCU_ADC0_AIN3 */ - J784S4_WKUP_IOPAD(0x0dc, PIN_INPUT, 0) /* (P34) MCU_ADC0_AIN4 */ - J784S4_WKUP_IOPAD(0x0e0, PIN_INPUT, 0) /* (R37) MCU_ADC0_AIN5 */ - J784S4_WKUP_IOPAD(0x0e4, PIN_INPUT, 0) /* (R33) MCU_ADC0_AIN6 */ - J784S4_WKUP_IOPAD(0x0e8, PIN_INPUT, 0) /* (V38) MCU_ADC0_AIN7 */ - >; - }; - - mcu_adc1_pins_default: mcu-adc1-default-pins { - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x0ec, PIN_INPUT, 0) /* (Y38) MCU_ADC1_AIN0 */ - J784S4_WKUP_IOPAD(0x0f0, PIN_INPUT, 0) /* (Y34) MCU_ADC1_AIN1 */ - J784S4_WKUP_IOPAD(0x0f4, PIN_INPUT, 0) /* (V34) MCU_ADC1_AIN2 */ - J784S4_WKUP_IOPAD(0x0f8, PIN_INPUT, 0) /* (W37) MCU_ADC1_AIN3 */ - J784S4_WKUP_IOPAD(0x0fc, PIN_INPUT, 0) /* (AA37) MCU_ADC1_AIN4 */ - J784S4_WKUP_IOPAD(0x100, PIN_INPUT, 0) /* (W33) MCU_ADC1_AIN5 */ - J784S4_WKUP_IOPAD(0x104, PIN_INPUT, 0) /* (U33) MCU_ADC1_AIN6 */ - J784S4_WKUP_IOPAD(0x108, PIN_INPUT, 0) /* (Y36) MCU_ADC1_AIN7 */ - >; - }; - - mcu_mcan0_pins_default: mcu-mcan0-default-pins { - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x050, PIN_OUTPUT, 0) /* (K33) MCU_MCAN0_TX */ - J784S4_WKUP_IOPAD(0x054, PIN_INPUT, 0) /* (F38) MCU_MCAN0_RX */ - >; - }; - - mcu_mcan1_pins_default: mcu-mcan1-default-pins { - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x068, PIN_OUTPUT, 0) /* (H35) WKUP_GPIO0_4.MCU_MCAN1_TX */ - J784S4_WKUP_IOPAD(0x06c, PIN_INPUT, 0) /* (K36) WKUP_GPIO0_5.MCU_MCAN1_RX */ - >; - }; - - mcu_mcan0_gpio_pins_default: mcu-mcan0-gpio-default-pins { - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x040, PIN_INPUT, 7) /* (J38) MCU_SPI0_D1.WKUP_GPIO0_69 */ - >; - }; - - mcu_mcan1_gpio_pins_default: mcu-mcan1-gpio-default-pins { - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x060, PIN_INPUT, 7) /* (J35) WKUP_GPIO0_2 */ - >; - }; }; -&wkup_pmx1 { - status = "okay"; - - pmic_irq_pins_default: pmic-irq-default-pins { - pinctrl-single,pins = < - /* (G33) MCU_OSPI1_CSn1.WKUP_GPIO0_39 */ - J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 7) - >; - }; -}; - -&wkup_pmx0 { - bootph-all; - mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x000, PIN_OUTPUT, 0) /* (E32) MCU_OSPI0_CLK */ - J784S4_WKUP_IOPAD(0x02c, PIN_OUTPUT, 0) /* (A32) MCU_OSPI0_CSn0 */ - J784S4_WKUP_IOPAD(0x00c, PIN_INPUT, 0) /* (B33) MCU_OSPI0_D0 */ - J784S4_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (B32) MCU_OSPI0_D1 */ - J784S4_WKUP_IOPAD(0x014, PIN_INPUT, 0) /* (C33) MCU_OSPI0_D2 */ - J784S4_WKUP_IOPAD(0x018, PIN_INPUT, 0) /* (C35) MCU_OSPI0_D3 */ - J784S4_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (D33) MCU_OSPI0_D4 */ - J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (D34) MCU_OSPI0_D5 */ - J784S4_WKUP_IOPAD(0x024, PIN_INPUT, 0) /* (E34) MCU_OSPI0_D6 */ - J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (E33) MCU_OSPI0_D7 */ - J784S4_WKUP_IOPAD(0x008, PIN_INPUT, 0) /* (C34) MCU_OSPI0_DQS */ - >; - }; -}; - -&wkup_pmx1 { - bootph-all; - mcu_fss0_ospi0_1_pins_default: mcu-fss0-ospi0-1-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x004, PIN_OUTPUT, 6) /* (C32) MCU_OSPI0_ECC_FAIL */ - J784S4_WKUP_IOPAD(0x000, PIN_OUTPUT, 6) /* (B34) MCU_OSPI0_RESET_OUT0 */ - >; - }; - - mcu_fss0_ospi1_pins_default: mcu-fss0-ospi1-default-pins { - bootph-all; - pinctrl-single,pins = < - J784S4_WKUP_IOPAD(0x008, PIN_OUTPUT, 0) /* (F32) MCU_OSPI1_CLK */ - J784S4_WKUP_IOPAD(0x024, PIN_OUTPUT, 0) /* (G32) MCU_OSPI1_CSn0 */ - J784S4_WKUP_IOPAD(0x014, PIN_INPUT, 0) /* (E35) MCU_OSPI1_D0 */ - J784S4_WKUP_IOPAD(0x018, PIN_INPUT, 0) /* (D31) MCU_OSPI1_D1 */ - J784S4_WKUP_IOPAD(0x01C, PIN_INPUT, 0) /* (G31) MCU_OSPI1_D2 */ - J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (F33) MCU_OSPI1_D3 */ - J784S4_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (F31) MCU_OSPI1_DQS */ - J784S4_WKUP_IOPAD(0x00C, PIN_INPUT, 0) /* (C31) MCU_OSPI1_LBCLKO */ - >; - }; -}; - -&wkup_uart0 { - /* Firmware usage */ - status = "reserved"; - pinctrl-names = "default"; - pinctrl-0 = <&wkup_uart0_pins_default>; -}; - -&wkup_i2c0 { - bootph-all; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&wkup_i2c0_pins_default>; - clock-frequency = <400000>; - - eeprom@50 { - /* CAV24C256WE-GT3 */ - compatible = "atmel,24c256"; - reg = <0x50>; - }; - - tps659413: pmic@48 { - compatible = "ti,tps6594-q1"; - reg = <0x48>; - system-power-controller; - pinctrl-names = "default"; - pinctrl-0 = <&pmic_irq_pins_default>; - interrupt-parent = <&wkup_gpio0>; - interrupts = <39 IRQ_TYPE_EDGE_FALLING>; - gpio-controller; - #gpio-cells = <2>; - ti,primary-pmic; - buck12-supply = <&vsys_3v3>; - buck3-supply = <&vsys_3v3>; - buck4-supply = <&vsys_3v3>; - buck5-supply = <&vsys_3v3>; - ldo1-supply = <&vsys_3v3>; - ldo2-supply = <&vsys_3v3>; - ldo3-supply = <&vsys_3v3>; - ldo4-supply = <&vsys_3v3>; - - regulators { - bucka12: buck12 { - regulator-name = "vdd_ddr_1v1"; - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <1100000>; - regulator-boot-on; - regulator-always-on; - }; - - bucka3: buck3 { - regulator-name = "vdd_ram_0v85"; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <850000>; - regulator-boot-on; - regulator-always-on; - }; - - bucka4: buck4 { - regulator-name = "vdd_io_1v8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-always-on; - }; - - bucka5: buck5 { - regulator-name = "vdd_mcu_0v85"; - regulator-min-microvolt = <850000>; - regulator-max-microvolt = <850000>; - regulator-boot-on; - regulator-always-on; - }; - - ldoa1: ldo1 { - regulator-name = "vdd_mcuio_1v8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-always-on; - }; - - ldoa2: ldo2 { - regulator-name = "vdd_mcuio_3v3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - regulator-always-on; - }; - - ldoa3: ldo3 { - regulator-name = "vds_dll_0v8"; - regulator-min-microvolt = <800000>; - regulator-max-microvolt = <800000>; - regulator-boot-on; - regulator-always-on; - }; - - ldoa4: ldo4 { - regulator-name = "vda_mcu_1v8"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-boot-on; - regulator-always-on; - }; - }; - }; - - tps62873a: regulator@40 { - compatible = "ti,tps62873"; - reg = <0x40>; - bootph-pre-ram; - regulator-name = "VDD_CPU_AVS"; - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1330000>; - regulator-boot-on; - regulator-always-on; - }; - - tps62873b: regulator@43 { - compatible = "ti,tps62873"; - reg = <0x43>; - regulator-name = "VDD_CORE_0V8"; - regulator-min-microvolt = <760000>; - regulator-max-microvolt = <840000>; - regulator-boot-on; - regulator-always-on; +&mailbox0_cluster5 { + mbox_c71_3: mbox-c71-3 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; }; }; -&mcu_uart0 { - bootph-all; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_uart0_pins_default>; -}; - -&main_uart8 { - bootph-all; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&main_uart8_pins_default>; -}; - -&ufs_wrapper { - status = "okay"; -}; - -&fss { - bootph-all; - status = "okay"; -}; - -&ospi0 { - bootph-all; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_fss0_ospi0_pins_default>, <&mcu_fss0_ospi0_1_pins_default>; - - flash@0 { - bootph-all; - compatible = "jedec,spi-nor"; - reg = <0x0>; - spi-tx-bus-width = <8>; - spi-rx-bus-width = <8>; - spi-max-frequency = <25000000>; - cdns,tshsl-ns = <60>; - cdns,tsd2d-ns = <60>; - cdns,tchsh-ns = <60>; - cdns,tslch-ns = <60>; - cdns,read-delay = <4>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "ospi.tiboot3"; - reg = <0x0 0x80000>; - }; - - partition@80000 { - label = "ospi.tispl"; - reg = <0x80000 0x200000>; - }; - - partition@280000 { - label = "ospi.u-boot"; - reg = <0x280000 0x400000>; - }; - - partition@680000 { - label = "ospi.env"; - reg = <0x680000 0x40000>; - }; - - partition@6c0000 { - label = "ospi.env.backup"; - reg = <0x6c0000 0x40000>; - }; - - partition@800000 { - label = "ospi.rootfs"; - reg = <0x800000 0x37c0000>; - }; - - partition@3fc0000 { - bootph-all; - label = "ospi.phypattern"; - reg = <0x3fc0000 0x40000>; - }; - }; - }; -}; - -&ospi1 { - bootph-all; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_fss0_ospi1_pins_default>; - - flash@0 { - bootph-all; - compatible = "jedec,spi-nor"; - reg = <0x0>; - spi-tx-bus-width = <1>; - spi-rx-bus-width = <4>; - spi-max-frequency = <40000000>; - cdns,tshsl-ns = <60>; - cdns,tsd2d-ns = <60>; - cdns,tchsh-ns = <60>; - cdns,tslch-ns = <60>; - cdns,read-delay = <2>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "qspi.tiboot3"; - reg = <0x0 0x80000>; - }; - - partition@80000 { - label = "qspi.tispl"; - reg = <0x80000 0x200000>; - }; - - partition@280000 { - label = "qspi.u-boot"; - reg = <0x280000 0x400000>; - }; - - partition@680000 { - label = "qspi.env"; - reg = <0x680000 0x40000>; - }; - - partition@6c0000 { - label = "qspi.env.backup"; - reg = <0x6c0000 0x40000>; - }; - - partition@800000 { - label = "qspi.rootfs"; - reg = <0x800000 0x37c0000>; - }; - - partition@3fc0000 { - bootph-all; - label = "qspi.phypattern"; - reg = <0x3fc0000 0x40000>; - }; - }; - - }; -}; - -&main_i2c0 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&main_i2c0_pins_default>; - - clock-frequency = <400000>; - - exp1: gpio@20 { - compatible = "ti,tca6416"; - reg = <0x20>; - gpio-controller; - #gpio-cells = <2>; - gpio-line-names = "PCIE1_2L_MODE_SEL", "PCIE1_4L_PERSTZ", "PCIE1_2L_RC_RSTZ", - "PCIE1_2L_EP_RST_EN", "PCIE0_4L_MODE_SEL", "PCIE0_4L_PERSTZ", - "PCIE0_4L_RC_RSTZ", "PCIE0_4L_EP_RST_EN", "PCIE1_4L_PRSNT#", - "PCIE0_4L_PRSNT#", "CDCI1_OE1/OE4", "CDCI1_OE2/OE3", - "AUDIO_MUX_SEL", "EXP_MUX2", "EXP_MUX3", "GESI_EXP_PHY_RSTZ"; - - p12-hog { - /* P12 - AUDIO_MUX_SEL */ - gpio-hog; - gpios = <12 GPIO_ACTIVE_HIGH>; - output-low; - line-name = "AUDIO_MUX_SEL"; - }; - }; - - exp2: gpio@22 { - compatible = "ti,tca6424"; - reg = <0x22>; - gpio-controller; - #gpio-cells = <2>; - gpio-line-names = "R_GPIO_RGMII1_RST", "ENET2_I2CMUX_SEL", "GPIO_USD_PWR_EN", - "USBC_PWR_EN", "USBC_MODE_SEL1", "USBC_MODE_SEL0", - "GPIO_LIN_EN", "R_CAN_STB", "CTRL_PM_I2C_OE#", - "ENET2_EXP_PWRDN", "ENET2_EXP_SPARE2", "CDCI2_RSTZ", - "USB2.0_MUX_SEL", "CANUART_MUX_SEL0", "CANUART_MUX2_SEL1", - "CANUART_MUX1_SEL1", "ENET1_EXP_PWRDN", "ENET1_EXP_RESETZ", - "ENET1_I2CMUX_SEL", "ENET1_EXP_SPARE2", "ENET2_EXP_RESETZ", - "USER_INPUT1", "USER_LED1", "USER_LED2"; - - p13-hog { - /* P13 - CANUART_MUX_SEL0 */ - gpio-hog; - gpios = <13 GPIO_ACTIVE_HIGH>; - output-high; - line-name = "CANUART_MUX_SEL0"; - }; - - p15-hog { - /* P15 - CANUART_MUX1_SEL1 */ - gpio-hog; - gpios = <15 GPIO_ACTIVE_HIGH>; - output-high; - line-name = "CANUART_MUX1_SEL1"; - }; - }; -}; - -&main_i2c5 { - pinctrl-names = "default"; - pinctrl-0 = <&main_i2c5_pins_default>; - clock-frequency = <400000>; - status = "okay"; - - exp5: gpio@20 { - compatible = "ti,tca6408"; - reg = <0x20>; - gpio-controller; - #gpio-cells = <2>; - gpio-line-names = "CSI2_EXP_RSTZ", "CSI2_EXP_A_GPIO0", - "CSI2_EXP_A_GPIO1", "CSI2_EXP_A_GPIO3", - "CSI2_EXP_B_GPIO1", "CSI2_EXP_B_GPIO2", - "CSI2_EXP_B_GPIO3", "CSI2_EXP_B_GPIO4"; - }; -}; - -&main_sdhci0 { - bootph-all; - /* eMMC */ - status = "okay"; - non-removable; - ti,driver-strength-ohm = <50>; - disable-wp; -}; - -&main_sdhci1 { - bootph-all; - /* SD card */ - status = "okay"; - pinctrl-0 = <&main_mmc1_pins_default>; - pinctrl-names = "default"; - disable-wp; - vmmc-supply = <&vdd_mmc1>; - vqmmc-supply = <&vdd_sd_dv>; -}; - -&main_gpio0 { - status = "okay"; -}; - -&mcu_cpsw { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_cpsw_pins_default>; -}; - -&davinci_mdio { - pinctrl-names = "default"; - pinctrl-0 = <&mcu_mdio_pins_default>; - - mcu_phy0: ethernet-phy@0 { - reg = <0>; - ti,rx-internal-delay = ; - ti,fifo-depth = ; - ti,min-output-impedance; - }; -}; - -&mcu_cpsw_port1 { - status = "okay"; - phy-mode = "rgmii-rxid"; - phy-handle = <&mcu_phy0>; -}; - -&main_cpsw1 { - pinctrl-names = "default"; - pinctrl-0 = <&main_cpsw2g_default_pins>; - status = "okay"; -}; - -&main_cpsw1_mdio { - pinctrl-names = "default"; - pinctrl-0 = <&main_cpsw2g_mdio_default_pins>; - status = "okay"; - - main_cpsw1_phy0: ethernet-phy@0 { - reg = <0>; - ti,rx-internal-delay = ; - ti,fifo-depth = ; - ti,min-output-impedance; - }; -}; - -&main_cpsw1_port1 { - phy-mode = "rgmii-rxid"; - phy-handle = <&main_cpsw1_phy0>; - status = "okay"; -}; - -&mailbox0_cluster0 { - status = "okay"; - interrupts = <436>; - - mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 { - ti,mbox-rx = <0 0 0>; - ti,mbox-tx = <1 0 0>; - }; - - mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 { - ti,mbox-rx = <2 0 0>; - ti,mbox-tx = <3 0 0>; - }; -}; - -&mailbox0_cluster1 { - status = "okay"; - interrupts = <432>; - - mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { - ti,mbox-rx = <0 0 0>; - ti,mbox-tx = <1 0 0>; - }; - - mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { - ti,mbox-rx = <2 0 0>; - ti,mbox-tx = <3 0 0>; - }; -}; - -&mailbox0_cluster2 { - status = "okay"; - interrupts = <428>; - - mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { - ti,mbox-rx = <0 0 0>; - ti,mbox-tx = <1 0 0>; - }; - - mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { - ti,mbox-rx = <2 0 0>; - ti,mbox-tx = <3 0 0>; - }; -}; - -&mailbox0_cluster3 { - status = "okay"; - interrupts = <424>; - - mbox_main_r5fss2_core0: mbox-main-r5fss2-core0 { - ti,mbox-rx = <0 0 0>; - ti,mbox-tx = <1 0 0>; - }; - - mbox_main_r5fss2_core1: mbox-main-r5fss2-core1 { - ti,mbox-rx = <2 0 0>; - ti,mbox-tx = <3 0 0>; - }; -}; - -&mailbox0_cluster4 { - status = "okay"; - interrupts = <420>; - - mbox_c71_0: mbox-c71-0 { - ti,mbox-rx = <0 0 0>; - ti,mbox-tx = <1 0 0>; - }; - - mbox_c71_1: mbox-c71-1 { - ti,mbox-rx = <2 0 0>; - ti,mbox-tx = <3 0 0>; - }; -}; - -&mailbox0_cluster5 { - status = "okay"; - interrupts = <416>; - - mbox_c71_2: mbox-c71-2 { - ti,mbox-rx = <0 0 0>; - ti,mbox-tx = <1 0 0>; - }; - - mbox_c71_3: mbox-c71-3 { - ti,mbox-rx = <2 0 0>; - ti,mbox-tx = <3 0 0>; - }; -}; - -&mcu_r5fss0_core0 { - status = "okay"; - mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; - memory-region = <&mcu_r5fss0_core0_dma_memory_region>, - <&mcu_r5fss0_core0_memory_region>; -}; - -&mcu_r5fss0_core1 { - status = "okay"; - mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; - memory-region = <&mcu_r5fss0_core1_dma_memory_region>, - <&mcu_r5fss0_core1_memory_region>; -}; - -&main_r5fss0 { - ti,cluster-mode = <0>; -}; - -&main_r5fss1 { - ti,cluster-mode = <0>; -}; - -&main_r5fss2 { - ti,cluster-mode = <0>; -}; - -/* Timers are used by Remoteproc firmware */ -&main_timer0 { - status = "reserved"; -}; - -&main_timer1 { - status = "reserved"; -}; - -&main_timer2 { - status = "reserved"; -}; - -&main_timer3 { - status = "reserved"; -}; - -&main_timer4 { - status = "reserved"; -}; - -&main_timer5 { - status = "reserved"; -}; - -&main_timer6 { - status = "reserved"; -}; - -&main_timer7 { - status = "reserved"; -}; - -&main_timer8 { - status = "reserved"; -}; - -&main_timer9 { - status = "reserved"; -}; - -&main_r5fss0_core0 { - status = "okay"; - mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; - memory-region = <&main_r5fss0_core0_dma_memory_region>, - <&main_r5fss0_core0_memory_region>; -}; - -&main_r5fss0_core1 { - status = "okay"; - mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; - memory-region = <&main_r5fss0_core1_dma_memory_region>, - <&main_r5fss0_core1_memory_region>; -}; - -&main_r5fss1_core0 { - status = "okay"; - mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>; - memory-region = <&main_r5fss1_core0_dma_memory_region>, - <&main_r5fss1_core0_memory_region>; -}; - -&main_r5fss1_core1 { - status = "okay"; - mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>; - memory-region = <&main_r5fss1_core1_dma_memory_region>, - <&main_r5fss1_core1_memory_region>; -}; - -&main_r5fss2_core0 { - status = "okay"; - mboxes = <&mailbox0_cluster3 &mbox_main_r5fss2_core0>; - memory-region = <&main_r5fss2_core0_dma_memory_region>, - <&main_r5fss2_core0_memory_region>; -}; - -&main_r5fss2_core1 { - status = "okay"; - mboxes = <&mailbox0_cluster3 &mbox_main_r5fss2_core1>; - memory-region = <&main_r5fss2_core1_dma_memory_region>, - <&main_r5fss2_core1_memory_region>; -}; - -&c71_0 { - status = "okay"; - mboxes = <&mailbox0_cluster4 &mbox_c71_0>; - memory-region = <&c71_0_dma_memory_region>, - <&c71_0_memory_region>; -}; - -&c71_1 { - status = "okay"; - mboxes = <&mailbox0_cluster4 &mbox_c71_1>; - memory-region = <&c71_1_dma_memory_region>, - <&c71_1_memory_region>; -}; - -&c71_2 { - status = "okay"; - mboxes = <&mailbox0_cluster5 &mbox_c71_2>; - memory-region = <&c71_2_dma_memory_region>, - <&c71_2_memory_region>; -}; - &c71_3 { - status = "okay"; mboxes = <&mailbox0_cluster5 &mbox_c71_3>; memory-region = <&c71_3_dma_memory_region>, <&c71_3_memory_region>; -}; - -&tscadc0 { - pinctrl-0 = <&mcu_adc0_pins_default>; - pinctrl-names = "default"; - status = "okay"; - adc { - ti,adc-channels = <0 1 2 3 4 5 6 7>; - }; -}; - -&tscadc1 { - pinctrl-0 = <&mcu_adc1_pins_default>; - pinctrl-names = "default"; - status = "okay"; - adc { - ti,adc-channels = <0 1 2 3 4 5 6 7>; - }; -}; - -&serdes_refclk { - status = "okay"; - clock-frequency = <100000000>; -}; - -&dss { - status = "okay"; - assigned-clocks = <&k3_clks 218 2>, - <&k3_clks 218 5>, - <&k3_clks 218 14>, - <&k3_clks 218 18>; - assigned-clock-parents = <&k3_clks 218 3>, - <&k3_clks 218 7>, - <&k3_clks 218 16>, - <&k3_clks 218 22>; -}; - -&serdes0 { - status = "okay"; - - serdes0_pcie1_link: phy@0 { - reg = <0>; - cdns,num-lanes = <2>; - #phy-cells = <0>; - cdns,phy-type = ; - resets = <&serdes_wiz0 1>, <&serdes_wiz0 2>; - }; - - serdes0_usb_link: phy@3 { - reg = <3>; - cdns,num-lanes = <1>; - #phy-cells = <0>; - cdns,phy-type = ; - resets = <&serdes_wiz0 4>; - }; -}; - -&serdes_wiz0 { - status = "okay"; -}; - -&usb_serdes_mux { - idle-states = <0>; /* USB0 to SERDES lane 3 */ -}; - -&usbss0 { - status = "okay"; - pinctrl-0 = <&main_usbss0_pins_default>; - pinctrl-names = "default"; - ti,vbus-divider; -}; - -&usb0 { - dr_mode = "otg"; - maximum-speed = "super-speed"; - phys = <&serdes0_usb_link>; - phy-names = "cdns3,usb3-phy"; -}; - -&serdes_wiz4 { - status = "okay"; -}; - -&serdes4 { - status = "okay"; - serdes4_dp_link: phy@0 { - reg = <0>; - cdns,num-lanes = <4>; - #phy-cells = <0>; - cdns,phy-type = ; - resets = <&serdes_wiz4 1>, <&serdes_wiz4 2>, - <&serdes_wiz4 3>, <&serdes_wiz4 4>; - }; -}; - -&mhdp { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&dp0_pins_default>; - phys = <&serdes4_dp_link>; - phy-names = "dpphy"; -}; - -&dss_ports { - /* DP */ - port { - dpi0_out: endpoint { - remote-endpoint = <&dp0_in>; - }; - }; -}; - -&main_i2c4 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&main_i2c4_pins_default>; - clock-frequency = <400000>; - - exp4: gpio@20 { - compatible = "ti,tca6408"; - reg = <0x20>; - gpio-controller; - #gpio-cells = <2>; - }; -}; - -&dp0_ports { - port@0 { - reg = <0>; - - dp0_in: endpoint { - remote-endpoint = <&dpi0_out>; - }; - }; - - port@4 { - reg = <4>; - - dp0_out: endpoint { - remote-endpoint = <&dp0_connector_in>; - }; - }; -}; - -&mcu_mcan0 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_mcan0_pins_default>; - phys = <&transceiver0>; -}; - -&mcu_mcan1 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_mcan1_pins_default>; - phys = <&transceiver1>; -}; - -&main_mcan16 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&main_mcan16_pins_default>; - phys = <&transceiver2>; -}; - -&main_mcan4 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&main_mcan4_pins_default>; - phys = <&transceiver3>; -}; - -&pcie1_rc { - status = "okay"; - num-lanes = <2>; - reset-gpios = <&exp1 2 GPIO_ACTIVE_HIGH>; - phys = <&serdes0_pcie1_link>; - phy-names = "pcie-phy"; -}; - -&serdes1 { - status = "okay"; - - serdes1_pcie0_link: phy@0 { - reg = <0>; - cdns,num-lanes = <4>; - #phy-cells = <0>; - cdns,phy-type = ; - resets = <&serdes_wiz1 1>, <&serdes_wiz1 2>, - <&serdes_wiz1 3>, <&serdes_wiz1 4>; - }; -}; - -&serdes_wiz1 { - status = "okay"; -}; - -&pcie0_rc { - status = "okay"; - reset-gpios = <&exp1 6 GPIO_ACTIVE_HIGH>; - phys = <&serdes1_pcie0_link>; - phy-names = "pcie-phy"; -}; - -&k3_clks { - /* Confiure AUDIO_EXT_REFCLK1 pin as output */ - pinctrl-names = "default"; - pinctrl-0 = <&audio_ext_refclk1_pins_default>; -}; - -&main_i2c3 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&main_i2c3_pins_default>; - clock-frequency = <400000>; - - exp3: gpio@20 { - compatible = "ti,tca6408"; - reg = <0x20>; - gpio-controller; - #gpio-cells = <2>; - }; - - pcm3168a_1: audio-codec@44 { - compatible = "ti,pcm3168a"; - reg = <0x44>; - #sound-dai-cells = <1>; - reset-gpios = <&exp3 0 GPIO_ACTIVE_LOW>; - clocks = <&audio_refclk1>; - clock-names = "scki"; - VDD1-supply = <&vsys_3v3>; - VDD2-supply = <&vsys_3v3>; - VCCAD1-supply = <&vsys_5v0>; - VCCAD2-supply = <&vsys_5v0>; - VCCDA1-supply = <&vsys_5v0>; - VCCDA2-supply = <&vsys_5v0>; - }; -}; - -&mcasp0 { status = "okay"; - #sound-dai-cells = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&main_mcasp0_pins_default>; - op-mode = <0>; /* MCASP_IIS_MODE */ - tdm-slots = <2>; - auxclk-fs-ratio = <256>; - serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ - 0 0 0 1 - 2 0 0 0 - 0 0 0 0 - 0 0 0 0 - >; }; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-common.dtsi new file mode 100644 index 00000000000000..1dceff119a4707 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-common.dtsi @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Device Tree Source for J784S4 and J742S2 SoC Family + * + * TRM (j784s4) (SPRUJ43 JULY 2022): https://www.ti.com/lit/zip/spruj52 + * TRM (j742s2): https://www.ti.com/lit/pdf/spruje3 + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#include +#include +#include + +#include "k3-pinctrl.h" + +/ { + interrupt-parent = <&gic500>; + #address-cells = <2>; + #size-cells = <2>; + + L2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x200000>; + cache-line-size = <64>; + cache-sets = <1024>; + next-level-cache = <&msmc_l3>; + }; + + L2_1: l2-cache1 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x200000>; + cache-line-size = <64>; + cache-sets = <1024>; + next-level-cache = <&msmc_l3>; + }; + + msmc_l3: l3-cache0 { + compatible = "cache"; + cache-level = <3>; + cache-unified; + }; + + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + + psci: psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + }; + + a72_timer0: timer-cl0-cpu0 { + compatible = "arm,armv8-timer"; + interrupts = , /* cntpsirq */ + , /* cntpnsirq */ + , /* cntvirq */ + ; /* cnthpirq */ + }; + + pmu: pmu { + compatible = "arm,cortex-a72-pmu"; + /* Recommendation from GIC500 TRM Table A.3 */ + interrupts = ; + }; + + cbass_main: bus@100000 { + bootph-all; + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */ + <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */ + <0x00 0x00700000 0x00 0x00700000 0x00 0x00001000>, /* ESM */ + <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals */ + <0x00 0x04210000 0x00 0x04210000 0x00 0x00010000>, /* VPU0 */ + <0x00 0x04220000 0x00 0x04220000 0x00 0x00010000>, /* VPU1 */ + <0x00 0x0d000000 0x00 0x0d000000 0x00 0x00800000>, /* PCIe0 Core*/ + <0x00 0x0d800000 0x00 0x0d800000 0x00 0x00800000>, /* PCIe1 Core*/ + <0x00 0x0e000000 0x00 0x0e000000 0x00 0x00800000>, /* PCIe2 Core*/ + <0x00 0x0e800000 0x00 0x0e800000 0x00 0x00800000>, /* PCIe3 Core*/ + <0x00 0x10000000 0x00 0x10000000 0x00 0x08000000>, /* PCIe0 DAT0 */ + <0x00 0x18000000 0x00 0x18000000 0x00 0x08000000>, /* PCIe1 DAT0 */ + <0x00 0x64800000 0x00 0x64800000 0x00 0x0070c000>, /* C71_1 */ + <0x00 0x65800000 0x00 0x65800000 0x00 0x0070c000>, /* C71_2 */ + <0x00 0x66800000 0x00 0x66800000 0x00 0x0070c000>, /* C71_3 */ + <0x00 0x67800000 0x00 0x67800000 0x00 0x0070c000>, /* C71_4 */ + <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ + <0x00 0x70000000 0x00 0x70000000 0x00 0x00400000>, /* MSMC RAM */ + <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>, /* MAIN NAVSS */ + <0x40 0x00000000 0x40 0x00000000 0x01 0x00000000>, /* PCIe0 DAT1 */ + <0x41 0x00000000 0x41 0x00000000 0x01 0x00000000>, /* PCIe1 DAT1 */ + <0x42 0x00000000 0x42 0x00000000 0x01 0x00000000>, /* PCIe2 DAT1 */ + <0x43 0x00000000 0x43 0x00000000 0x01 0x00000000>, /* PCIe3 DAT1 */ + <0x44 0x00000000 0x44 0x00000000 0x00 0x08000000>, /* PCIe2 DAT0 */ + <0x44 0x10000000 0x44 0x10000000 0x00 0x08000000>, /* PCIe3 DAT0 */ + <0x4e 0x20000000 0x4e 0x20000000 0x00 0x00080000>, /* GPU */ + + /* MCUSS_WKUP Range */ + <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, + <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, + <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, + <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, + <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, + <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, + <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, + <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, + <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, + <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, + <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, + <0x04 0x00000000 0x04 0x00000000 0x04 0x00000000>; + + cbass_mcu_wakeup: bus@28380000 { + bootph-all; + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, /* MCU NAVSS*/ + <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, /* First peripheral window */ + <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, /* CTRL_MMR0 */ + <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, /* MCU R5F Core0 */ + <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, /* MCU R5F Core1 */ + <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, /* MCU SRAM */ + <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, /* WKUP peripheral window */ + <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, /* MMRs, remaining NAVSS */ + <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, /* CPSW */ + <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, /* OSPI register space */ + <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, /* FSS data region 1 */ + <0x04 0x00000000 0x04 0x00000000 0x04 0x00000000>; /* FSS data region 0/3 */ + }; + }; + + thermal_zones: thermal-zones { + #include "k3-j784s4-j742s2-thermal-common.dtsi" + }; +}; + +/* Now include peripherals from each bus segment */ +#include "k3-j784s4-j742s2-main-common.dtsi" +#include "k3-j784s4-j742s2-mcu-wakeup-common.dtsi" diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi new file mode 100644 index 00000000000000..b2e2b9f507a982 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-evm-common.dtsi @@ -0,0 +1,1481 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + * + * EVM Board Schematics(j784s4): https://www.ti.com/lit/zip/sprr458 + * EVM Board Schematics(j742s2): https://www.ti.com/lit/zip/SPAC001 + */ +/ { + chosen { + stdout-path = "serial2:115200n8"; + }; + + aliases { + serial0 = &wkup_uart0; + serial1 = &mcu_uart0; + serial2 = &main_uart8; + mmc0 = &main_sdhci0; + mmc1 = &main_sdhci1; + i2c0 = &wkup_i2c0; + i2c3 = &main_i2c0; + ethernet0 = &mcu_cpsw_port1; + ethernet1 = &main_cpsw1_port1; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + secure_ddr: optee@9e800000 { + reg = <0x00 0x9e800000 0x00 0x01800000>; + no-map; + }; + + mcu_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + mcu_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + mcu_r5fss0_core1_memory_region: r5f-memory@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: r5f-memory@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core1_memory_region: r5f-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a4000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core0_memory_region: r5f-memory@a4100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa4100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a5000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core1_memory_region: r5f-memory@a5100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa5100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss2_core0_dma_memory_region: r5f-dma-memory@a6000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6000000 0x00 0x100000>; + no-map; + }; + + main_r5fss2_core0_memory_region: r5f-memory@a6100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa6100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss2_core1_dma_memory_region: r5f-dma-memory@a7000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7000000 0x00 0x100000>; + no-map; + }; + + main_r5fss2_core1_memory_region: r5f-memory@a7100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa7100000 0x00 0xf00000>; + no-map; + }; + + c71_0_dma_memory_region: c71-dma-memory@a8000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa8000000 0x00 0x100000>; + no-map; + }; + + c71_0_memory_region: c71-memory@a8100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa8100000 0x00 0xf00000>; + no-map; + }; + + c71_1_dma_memory_region: c71-dma-memory@a9000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa9000000 0x00 0x100000>; + no-map; + }; + + c71_1_memory_region: c71-memory@a9100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa9100000 0x00 0xf00000>; + no-map; + }; + + c71_2_dma_memory_region: c71-dma-memory@aa000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xaa000000 0x00 0x100000>; + no-map; + }; + + c71_2_memory_region: c71-memory@aa100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xaa100000 0x00 0xf00000>; + no-map; + }; + }; + + evm_12v0: regulator-evm12v0 { + /* main supply */ + compatible = "regulator-fixed"; + regulator-name = "evm_12v0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_3v3: regulator-vsys3v3 { + /* Output of LM5140 */ + compatible = "regulator-fixed"; + regulator-name = "vsys_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&evm_12v0>; + regulator-always-on; + regulator-boot-on; + }; + + vsys_5v0: regulator-vsys5v0 { + /* Output of LM5140 */ + compatible = "regulator-fixed"; + regulator-name = "vsys_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&evm_12v0>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_mmc1: regulator-sd { + /* Output of TPS22918 */ + compatible = "regulator-fixed"; + regulator-name = "vdd_mmc1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + enable-active-high; + vin-supply = <&vsys_3v3>; + gpio = <&exp2 2 GPIO_ACTIVE_HIGH>; + }; + + vdd_sd_dv: regulator-TLV71033 { + /* Output of TLV71033 */ + compatible = "regulator-gpio"; + regulator-name = "tlv71033"; + pinctrl-names = "default"; + pinctrl-0 = <&vdd_sd_dv_pins_default>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + vin-supply = <&vsys_5v0>; + gpios = <&main_gpio0 8 GPIO_ACTIVE_HIGH>; + states = <1800000 0x0>, + <3300000 0x1>; + }; + + dp0_pwr_3v3: regulator-dp0-prw { + compatible = "regulator-fixed"; + regulator-name = "dp0-pwr"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&exp4 0 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + dp0: connector-dp0 { + compatible = "dp-connector"; + label = "DP0"; + type = "full-size"; + dp-pwr-supply = <&dp0_pwr_3v3>; + + port { + dp0_connector_in: endpoint { + remote-endpoint = <&dp0_out>; + }; + }; + }; + + transceiver0: can-phy0 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_gpio_pins_default>; + standby-gpios = <&wkup_gpio0 69 GPIO_ACTIVE_HIGH>; + }; + + transceiver1: can-phy1 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_gpio_pins_default>; + standby-gpios = <&wkup_gpio0 2 GPIO_ACTIVE_HIGH>; + }; + + transceiver2: can-phy2 { + /* standby pin has been grounded by default */ + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + }; + + transceiver3: can-phy3 { + compatible = "ti,tcan1042"; + #phy-cells = <0>; + max-bitrate = <5000000>; + standby-gpios = <&exp2 7 GPIO_ACTIVE_HIGH>; + mux-states = <&mux1 1>; + }; + + mux1: mux-controller { + compatible = "gpio-mux"; + #mux-state-cells = <1>; + mux-gpios = <&exp2 14 GPIO_ACTIVE_HIGH>; + idle-state = <1>; + }; + + codec_audio: sound { + compatible = "ti,j7200-cpb-audio"; + model = "j784s4-cpb"; + + ti,cpb-mcasp = <&mcasp0>; + ti,cpb-codec = <&pcm3168a_1>; + + clocks = <&k3_clks 265 0>, <&k3_clks 265 1>, + <&k3_clks 157 34>, <&k3_clks 157 63>; + clock-names = "cpb-mcasp-auxclk", "cpb-mcasp-auxclk-48000", + "cpb-codec-scki", "cpb-codec-scki-48000"; + }; +}; + +&wkup_gpio0 { + status = "okay"; +}; + +&main_pmx0 { + main_cpsw2g_default_pins: main-cpsw2g-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0b8, PIN_INPUT, 6) /* (AC34) MCASP1_ACLKX.RGMII1_RD0 */ + J784S4_IOPAD(0x0a0, PIN_INPUT, 6) /* (AD34) MCASP0_AXR12.RGMII1_RD1 */ + J784S4_IOPAD(0x0a4, PIN_INPUT, 6) /* (AJ36) MCASP0_AXR13.RGMII1_RD2 */ + J784S4_IOPAD(0x0a8, PIN_INPUT, 6) /* (AF34) MCASP0_AXR14.RGMII1_RD3 */ + J784S4_IOPAD(0x0b0, PIN_INPUT, 6) /* (AL33) MCASP1_AXR3.RGMII1_RXC */ + J784S4_IOPAD(0x0ac, PIN_INPUT, 6) /* (AE34) MCASP0_AXR15.RGMII1_RX_CTL */ + J784S4_IOPAD(0x08c, PIN_INPUT, 6) /* (AE35) MCASP0_AXR7.RGMII1_TD0 */ + J784S4_IOPAD(0x090, PIN_INPUT, 6) /* (AC35) MCASP0_AXR8.RGMII1_TD1 */ + J784S4_IOPAD(0x094, PIN_INPUT, 6) /* (AG35) MCASP0_AXR9.RGMII1_TD2 */ + J784S4_IOPAD(0x098, PIN_INPUT, 6) /* (AH36) MCASP0_AXR10.RGMII1_TD3 */ + J784S4_IOPAD(0x0b4, PIN_INPUT, 6) /* (AL34) MCASP1_AXR4.RGMII1_TXC */ + J784S4_IOPAD(0x09c, PIN_INPUT, 6) /* (AF35) MCASP0_AXR11.RGMII1_TX_CTL */ + >; + }; + + main_cpsw2g_mdio_default_pins: main-cpsw2g-mdio-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0c0, PIN_INPUT, 6) /* (AD38) MCASP1_AXR0.MDIO0_MDC */ + J784S4_IOPAD(0x0bc, PIN_INPUT, 6) /* (AD33) MCASP1_AFSX.MDIO0_MDIO */ + >; + }; + + main_uart8_pins_default: main-uart8-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_IOPAD(0x040, PIN_INPUT, 14) /* (AF37) MCASP0_AXR0.UART8_CTSn */ + J784S4_IOPAD(0x044, PIN_OUTPUT, 14) /* (AG37) MCASP0_AXR1.UART8_RTSn */ + J784S4_IOPAD(0x0d0, PIN_INPUT, 11) /* (AP38) SPI0_CS1.UART8_RXD */ + J784S4_IOPAD(0x0d4, PIN_OUTPUT, 11) /* (AN38) SPI0_CLK.UART8_TXD */ + >; + }; + + main_i2c0_pins_default: main-i2c0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0e0, PIN_INPUT_PULLUP, 0) /* (AN36) I2C0_SCL */ + J784S4_IOPAD(0x0e4, PIN_INPUT_PULLUP, 0) /* (AP37) I2C0_SDA */ + >; + }; + + main_i2c5_pins_default: main-i2c5-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x01c, PIN_INPUT, 8) /* (AG34) MCAN15_TX.I2C5_SCL */ + J784S4_IOPAD(0x018, PIN_INPUT, 8) /* (AK36) MCAN14_RX.I2C5_SDA */ + >; + }; + + main_mmc1_pins_default: main-mmc1-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_IOPAD(0x104, PIN_INPUT, 0) /* (AB38) MMC1_CLK */ + J784S4_IOPAD(0x108, PIN_INPUT, 0) /* (AB36) MMC1_CMD */ + J784S4_IOPAD(0x100, PIN_INPUT, 0) /* (No Pin) MMC1_CLKLB */ + J784S4_IOPAD(0x0fc, PIN_INPUT, 0) /* (AA33) MMC1_DAT0 */ + J784S4_IOPAD(0x0f8, PIN_INPUT, 0) /* (AB34) MMC1_DAT1 */ + J784S4_IOPAD(0x0f4, PIN_INPUT, 0) /* (AA32) MMC1_DAT2 */ + J784S4_IOPAD(0x0f0, PIN_INPUT, 0) /* (AC38) MMC1_DAT3 */ + J784S4_IOPAD(0x0e8, PIN_INPUT, 8) /* (AR38) TIMER_IO0.MMC1_SDCD */ + >; + }; + + vdd_sd_dv_pins_default: vdd-sd-dv-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x020, PIN_INPUT, 7) /* (AJ35) MCAN15_RX.GPIO0_8 */ + >; + }; + + dp0_pins_default: dp0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x0cc, PIN_INPUT, 12) /* (AM37) SPI0_CS0.DP0_HPD */ + >; + }; + + main_i2c4_pins_default: main-i2c4-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x014, PIN_INPUT_PULLUP, 8) /* (AG33) MCAN14_TX.I2C4_SCL */ + J784S4_IOPAD(0x010, PIN_INPUT_PULLUP, 8) /* (AH33) MCAN13_RX.I2C4_SDA */ + >; + }; + + main_mcan4_pins_default: main-mcan4-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x088, PIN_INPUT, 0) /* (AF36) MCAN4_RX */ + J784S4_IOPAD(0x084, PIN_OUTPUT, 0) /* (AG38) MCAN4_TX */ + >; + }; + + main_mcan16_pins_default: main-mcan16-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x028, PIN_INPUT, 0) /* (AE33) MCAN16_RX */ + J784S4_IOPAD(0x024, PIN_OUTPUT, 0) /* (AH34) MCAN16_TX */ + >; + }; + + main_usbss0_pins_default: main-usbss0-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_IOPAD(0x0ec, PIN_OUTPUT, 6) /* (AN37) TIMER_IO1.USB0_DRVVBUS */ + >; + }; + + main_i2c3_pins_default: main-i2c3-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x064, PIN_INPUT, 13) /* (AF38) MCAN0_TX.I2C3_SCL */ + J784S4_IOPAD(0x060, PIN_INPUT, 13) /* (AE36) MCASP2_AXR1.I2C3_SDA */ + >; + }; + + main_mcasp0_pins_default: main-mcasp0-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x038, PIN_OUTPUT_PULLDOWN, 1) /* (AK35) MCASP0_ACLKX */ + J784S4_IOPAD(0x03c, PIN_OUTPUT_PULLDOWN, 1) /* (AK38) MCASP0_AFSX */ + J784S4_IOPAD(0x07c, PIN_OUTPUT_PULLDOWN, 1) /* (AJ38) MCASP0_AXR3 */ + J784S4_IOPAD(0x080, PIN_INPUT_PULLDOWN, 1) /* (AK34) MCASP0_AXR4 */ + >; + }; + + audio_ext_refclk1_pins_default: audio-ext-refclk1-default-pins { + pinctrl-single,pins = < + J784S4_IOPAD(0x078, PIN_OUTPUT, 1) /* (AH37) MCAN2_RX.AUDIO_EXT_REFCLK1 */ + >; + }; +}; + +&wkup_pmx2 { + wkup_uart0_pins_default: wkup-uart0-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x048, PIN_INPUT, 0) /* (K35) WKUP_UART0_RXD */ + J784S4_WKUP_IOPAD(0x04c, PIN_OUTPUT, 0) /* (K34) WKUP_UART0_TXD */ + >; + }; + + wkup_i2c0_pins_default: wkup-i2c0-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x98, PIN_INPUT, 0) /* (N33) WKUP_I2C0_SCL */ + J784S4_WKUP_IOPAD(0x9c, PIN_INPUT, 0) /* (N35) WKUP_I2C0_SDA */ + >; + }; + + mcu_uart0_pins_default: mcu-uart0-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x090, PIN_INPUT, 0) /* (H37) WKUP_GPIO0_14.MCU_UART0_CTSn */ + J784S4_WKUP_IOPAD(0x094, PIN_OUTPUT, 0) /* (K37) WKUP_GPIO0_15.MCU_UART0_RTSn */ + J784S4_WKUP_IOPAD(0x08c, PIN_INPUT, 0) /* (K38) WKUP_GPIO0_13.MCU_UART0_RXD */ + J784S4_WKUP_IOPAD(0x088, PIN_OUTPUT, 0) /* (J37) WKUP_GPIO0_12.MCU_UART0_TXD */ + >; + }; + + mcu_cpsw_pins_default: mcu-cpsw-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x02c, PIN_INPUT, 0) /* (A35) MCU_RGMII1_RD0 */ + J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (B36) MCU_RGMII1_RD1 */ + J784S4_WKUP_IOPAD(0x024, PIN_INPUT, 0) /* (C36) MCU_RGMII1_RD2 */ + J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (D36) MCU_RGMII1_RD3 */ + J784S4_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (B37) MCU_RGMII1_RXC */ + J784S4_WKUP_IOPAD(0x004, PIN_INPUT, 0) /* (C37) MCU_RGMII1_RX_CTL */ + J784S4_WKUP_IOPAD(0x014, PIN_OUTPUT, 0) /* (D37) MCU_RGMII1_TD0 */ + J784S4_WKUP_IOPAD(0x010, PIN_OUTPUT, 0) /* (D38) MCU_RGMII1_TD1 */ + J784S4_WKUP_IOPAD(0x00c, PIN_OUTPUT, 0) /* (E37) MCU_RGMII1_TD2 */ + J784S4_WKUP_IOPAD(0x008, PIN_OUTPUT, 0) /* (E38) MCU_RGMII1_TD3 */ + J784S4_WKUP_IOPAD(0x018, PIN_OUTPUT, 0) /* (E36) MCU_RGMII1_TXC */ + J784S4_WKUP_IOPAD(0x000, PIN_OUTPUT, 0) /* (C38) MCU_RGMII1_TX_CTL */ + >; + }; + + mcu_mdio_pins_default: mcu-mdio-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x034, PIN_OUTPUT, 0) /* (A36) MCU_MDIO0_MDC */ + J784S4_WKUP_IOPAD(0x030, PIN_INPUT, 0) /* (B35) MCU_MDIO0_MDIO */ + >; + }; + + mcu_adc0_pins_default: mcu-adc0-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x0cc, PIN_INPUT, 0) /* (P36) MCU_ADC0_AIN0 */ + J784S4_WKUP_IOPAD(0x0d0, PIN_INPUT, 0) /* (V36) MCU_ADC0_AIN1 */ + J784S4_WKUP_IOPAD(0x0d4, PIN_INPUT, 0) /* (T34) MCU_ADC0_AIN2 */ + J784S4_WKUP_IOPAD(0x0d8, PIN_INPUT, 0) /* (T36) MCU_ADC0_AIN3 */ + J784S4_WKUP_IOPAD(0x0dc, PIN_INPUT, 0) /* (P34) MCU_ADC0_AIN4 */ + J784S4_WKUP_IOPAD(0x0e0, PIN_INPUT, 0) /* (R37) MCU_ADC0_AIN5 */ + J784S4_WKUP_IOPAD(0x0e4, PIN_INPUT, 0) /* (R33) MCU_ADC0_AIN6 */ + J784S4_WKUP_IOPAD(0x0e8, PIN_INPUT, 0) /* (V38) MCU_ADC0_AIN7 */ + >; + }; + + mcu_adc1_pins_default: mcu-adc1-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x0ec, PIN_INPUT, 0) /* (Y38) MCU_ADC1_AIN0 */ + J784S4_WKUP_IOPAD(0x0f0, PIN_INPUT, 0) /* (Y34) MCU_ADC1_AIN1 */ + J784S4_WKUP_IOPAD(0x0f4, PIN_INPUT, 0) /* (V34) MCU_ADC1_AIN2 */ + J784S4_WKUP_IOPAD(0x0f8, PIN_INPUT, 0) /* (W37) MCU_ADC1_AIN3 */ + J784S4_WKUP_IOPAD(0x0fc, PIN_INPUT, 0) /* (AA37) MCU_ADC1_AIN4 */ + J784S4_WKUP_IOPAD(0x100, PIN_INPUT, 0) /* (W33) MCU_ADC1_AIN5 */ + J784S4_WKUP_IOPAD(0x104, PIN_INPUT, 0) /* (U33) MCU_ADC1_AIN6 */ + J784S4_WKUP_IOPAD(0x108, PIN_INPUT, 0) /* (Y36) MCU_ADC1_AIN7 */ + >; + }; + + mcu_mcan0_pins_default: mcu-mcan0-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x050, PIN_OUTPUT, 0) /* (K33) MCU_MCAN0_TX */ + J784S4_WKUP_IOPAD(0x054, PIN_INPUT, 0) /* (F38) MCU_MCAN0_RX */ + >; + }; + + mcu_mcan1_pins_default: mcu-mcan1-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x068, PIN_OUTPUT, 0) /* (H35) WKUP_GPIO0_4.MCU_MCAN1_TX */ + J784S4_WKUP_IOPAD(0x06c, PIN_INPUT, 0) /* (K36) WKUP_GPIO0_5.MCU_MCAN1_RX */ + >; + }; + + mcu_mcan0_gpio_pins_default: mcu-mcan0-gpio-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x040, PIN_INPUT, 7) /* (J38) MCU_SPI0_D1.WKUP_GPIO0_69 */ + >; + }; + + mcu_mcan1_gpio_pins_default: mcu-mcan1-gpio-default-pins { + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x060, PIN_INPUT, 7) /* (J35) WKUP_GPIO0_2 */ + >; + }; +}; + +&wkup_pmx1 { + status = "okay"; + + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + /* (G33) MCU_OSPI1_CSn1.WKUP_GPIO0_39 */ + J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 7) + >; + }; +}; + +&wkup_pmx0 { + mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x000, PIN_OUTPUT, 0) /* (E32) MCU_OSPI0_CLK */ + J784S4_WKUP_IOPAD(0x02c, PIN_OUTPUT, 0) /* (A32) MCU_OSPI0_CSn0 */ + J784S4_WKUP_IOPAD(0x00c, PIN_INPUT, 0) /* (B33) MCU_OSPI0_D0 */ + J784S4_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (B32) MCU_OSPI0_D1 */ + J784S4_WKUP_IOPAD(0x014, PIN_INPUT, 0) /* (C33) MCU_OSPI0_D2 */ + J784S4_WKUP_IOPAD(0x018, PIN_INPUT, 0) /* (C35) MCU_OSPI0_D3 */ + J784S4_WKUP_IOPAD(0x01c, PIN_INPUT, 0) /* (D33) MCU_OSPI0_D4 */ + J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (D34) MCU_OSPI0_D5 */ + J784S4_WKUP_IOPAD(0x024, PIN_INPUT, 0) /* (E34) MCU_OSPI0_D6 */ + J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 0) /* (E33) MCU_OSPI0_D7 */ + J784S4_WKUP_IOPAD(0x008, PIN_INPUT, 0) /* (C34) MCU_OSPI0_DQS */ + >; + }; +}; + +&wkup_pmx1 { + mcu_fss0_ospi0_1_pins_default: mcu-fss0-ospi0-1-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x004, PIN_OUTPUT, 6) /* (C32) MCU_OSPI0_ECC_FAIL */ + J784S4_WKUP_IOPAD(0x000, PIN_OUTPUT, 6) /* (B34) MCU_OSPI0_RESET_OUT0 */ + >; + }; + + mcu_fss0_ospi1_pins_default: mcu-fss0-ospi1-default-pins { + bootph-all; + pinctrl-single,pins = < + J784S4_WKUP_IOPAD(0x008, PIN_OUTPUT, 0) /* (F32) MCU_OSPI1_CLK */ + J784S4_WKUP_IOPAD(0x024, PIN_OUTPUT, 0) /* (G32) MCU_OSPI1_CSn0 */ + J784S4_WKUP_IOPAD(0x014, PIN_INPUT, 0) /* (E35) MCU_OSPI1_D0 */ + J784S4_WKUP_IOPAD(0x018, PIN_INPUT, 0) /* (D31) MCU_OSPI1_D1 */ + J784S4_WKUP_IOPAD(0x01C, PIN_INPUT, 0) /* (G31) MCU_OSPI1_D2 */ + J784S4_WKUP_IOPAD(0x020, PIN_INPUT, 0) /* (F33) MCU_OSPI1_D3 */ + J784S4_WKUP_IOPAD(0x010, PIN_INPUT, 0) /* (F31) MCU_OSPI1_DQS */ + J784S4_WKUP_IOPAD(0x00C, PIN_INPUT, 0) /* (C31) MCU_OSPI1_LBCLKO */ + >; + }; +}; + +&wkup_uart0 { + /* Firmware usage */ + status = "reserved"; + pinctrl-names = "default"; + pinctrl-0 = <&wkup_uart0_pins_default>; +}; + +&wkup_i2c0 { + bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&wkup_i2c0_pins_default>; + clock-frequency = <400000>; + + eeprom@50 { + /* CAV24C256WE-GT3 */ + compatible = "atmel,24c256"; + reg = <0x50>; + }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck12-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka12: buck12 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka3: buck3 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vds_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps62873a: regulator@40 { + compatible = "ti,tps62873"; + reg = <0x40>; + bootph-pre-ram; + regulator-name = "VDD_CPU_AVS"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1330000>; + regulator-boot-on; + regulator-always-on; + }; + + tps62873b: regulator@43 { + compatible = "ti,tps62873"; + reg = <0x43>; + regulator-name = "VDD_CORE_0V8"; + regulator-min-microvolt = <760000>; + regulator-max-microvolt = <840000>; + regulator-boot-on; + regulator-always-on; + }; +}; + +&mcu_uart0 { + bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_uart0_pins_default>; +}; + +&main_uart8 { + bootph-all; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_uart8_pins_default>; +}; + +&ufs_wrapper { + status = "okay"; +}; + +&fss { + status = "okay"; +}; + +&ospi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_fss0_ospi0_pins_default>, <&mcu_fss0_ospi0_1_pins_default>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <8>; + spi-rx-bus-width = <8>; + spi-max-frequency = <25000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "ospi.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "ospi.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "ospi.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "ospi.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "ospi.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@800000 { + label = "ospi.rootfs"; + reg = <0x800000 0x37c0000>; + }; + + partition@3fc0000 { + bootph-all; + label = "ospi.phypattern"; + reg = <0x3fc0000 0x40000>; + }; + }; + }; +}; + +&ospi1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_fss0_ospi1_pins_default>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <40000000>; + cdns,tshsl-ns = <60>; + cdns,tsd2d-ns = <60>; + cdns,tchsh-ns = <60>; + cdns,tslch-ns = <60>; + cdns,read-delay = <2>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "qspi.tiboot3"; + reg = <0x0 0x80000>; + }; + + partition@80000 { + label = "qspi.tispl"; + reg = <0x80000 0x200000>; + }; + + partition@280000 { + label = "qspi.u-boot"; + reg = <0x280000 0x400000>; + }; + + partition@680000 { + label = "qspi.env"; + reg = <0x680000 0x40000>; + }; + + partition@6c0000 { + label = "qspi.env.backup"; + reg = <0x6c0000 0x40000>; + }; + + partition@800000 { + label = "qspi.rootfs"; + reg = <0x800000 0x37c0000>; + }; + + partition@3fc0000 { + bootph-all; + label = "qspi.phypattern"; + reg = <0x3fc0000 0x40000>; + }; + }; + + }; +}; + +&main_i2c0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c0_pins_default>; + + clock-frequency = <400000>; + + exp1: gpio@20 { + compatible = "ti,tca6416"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "PCIE1_2L_MODE_SEL", "PCIE1_4L_PERSTZ", "PCIE1_2L_RC_RSTZ", + "PCIE1_2L_EP_RST_EN", "PCIE0_4L_MODE_SEL", "PCIE0_4L_PERSTZ", + "PCIE0_4L_RC_RSTZ", "PCIE0_4L_EP_RST_EN", "PCIE1_4L_PRSNT#", + "PCIE0_4L_PRSNT#", "CDCI1_OE1/OE4", "CDCI1_OE2/OE3", + "AUDIO_MUX_SEL", "EXP_MUX2", "EXP_MUX3", "GESI_EXP_PHY_RSTZ"; + + p12-hog { + /* P12 - AUDIO_MUX_SEL */ + gpio-hog; + gpios = <12 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "AUDIO_MUX_SEL"; + }; + }; + + exp2: gpio@22 { + compatible = "ti,tca6424"; + reg = <0x22>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "R_GPIO_RGMII1_RST", "ENET2_I2CMUX_SEL", "GPIO_USD_PWR_EN", + "USBC_PWR_EN", "USBC_MODE_SEL1", "USBC_MODE_SEL0", + "GPIO_LIN_EN", "R_CAN_STB", "CTRL_PM_I2C_OE#", + "ENET2_EXP_PWRDN", "ENET2_EXP_SPARE2", "CDCI2_RSTZ", + "USB2.0_MUX_SEL", "CANUART_MUX_SEL0", "CANUART_MUX2_SEL1", + "CANUART_MUX1_SEL1", "ENET1_EXP_PWRDN", "ENET1_EXP_RESETZ", + "ENET1_I2CMUX_SEL", "ENET1_EXP_SPARE2", "ENET2_EXP_RESETZ", + "USER_INPUT1", "USER_LED1", "USER_LED2"; + + p13-hog { + /* P13 - CANUART_MUX_SEL0 */ + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CANUART_MUX_SEL0"; + }; + + p15-hog { + /* P15 - CANUART_MUX1_SEL1 */ + gpio-hog; + gpios = <15 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CANUART_MUX1_SEL1"; + }; + }; +}; + +&main_i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c5_pins_default>; + clock-frequency = <400000>; + status = "okay"; + + exp5: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "CSI2_EXP_RSTZ", "CSI2_EXP_A_GPIO0", + "CSI2_EXP_A_GPIO1", "CSI2_EXP_A_GPIO3", + "CSI2_EXP_B_GPIO1", "CSI2_EXP_B_GPIO2", + "CSI2_EXP_B_GPIO3", "CSI2_EXP_B_GPIO4"; + }; +}; + +&main_sdhci0 { + bootph-all; + /* eMMC */ + status = "okay"; + non-removable; + ti,driver-strength-ohm = <50>; + disable-wp; +}; + +&main_sdhci1 { + bootph-all; + /* SD card */ + status = "okay"; + pinctrl-0 = <&main_mmc1_pins_default>; + pinctrl-names = "default"; + disable-wp; + vmmc-supply = <&vdd_mmc1>; + vqmmc-supply = <&vdd_sd_dv>; +}; + +&main_gpio0 { + status = "okay"; +}; + +&mcu_cpsw { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_cpsw_pins_default>; +}; + +&davinci_mdio { + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mdio_pins_default>; + + mcu_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + ti,min-output-impedance; + }; +}; + +&mcu_cpsw_port1 { + status = "okay"; + phy-mode = "rgmii-rxid"; + phy-handle = <&mcu_phy0>; +}; + +&main_cpsw1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_cpsw2g_default_pins>; + status = "okay"; +}; + +&main_cpsw1_mdio { + pinctrl-names = "default"; + pinctrl-0 = <&main_cpsw2g_mdio_default_pins>; + status = "okay"; + + main_cpsw1_phy0: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + ti,min-output-impedance; + }; +}; + +&main_cpsw1_port1 { + phy-mode = "rgmii-rxid"; + phy-handle = <&main_cpsw1_phy0>; + status = "okay"; +}; + +&mailbox0_cluster0 { + status = "okay"; + interrupts = <436>; + + mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster1 { + status = "okay"; + interrupts = <432>; + + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster2 { + status = "okay"; + interrupts = <428>; + + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster3 { + status = "okay"; + interrupts = <424>; + + mbox_main_r5fss2_core0: mbox-main-r5fss2-core0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_main_r5fss2_core1: mbox-main-r5fss2-core1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster4 { + status = "okay"; + interrupts = <420>; + + mbox_c71_0: mbox-c71-0 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; + + mbox_c71_1: mbox-c71-1 { + ti,mbox-rx = <2 0 0>; + ti,mbox-tx = <3 0 0>; + }; +}; + +&mailbox0_cluster5 { + status = "okay"; + interrupts = <416>; + + mbox_c71_2: mbox-c71-2 { + ti,mbox-rx = <0 0 0>; + ti,mbox-tx = <1 0 0>; + }; +}; + +&mcu_r5fss0_core0 { + status = "okay"; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core0>; + memory-region = <&mcu_r5fss0_core0_dma_memory_region>, + <&mcu_r5fss0_core0_memory_region>; +}; + +&mcu_r5fss0_core1 { + status = "okay"; + mboxes = <&mailbox0_cluster0 &mbox_mcu_r5fss0_core1>; + memory-region = <&mcu_r5fss0_core1_dma_memory_region>, + <&mcu_r5fss0_core1_memory_region>; +}; + +&main_r5fss0 { + ti,cluster-mode = <0>; +}; + +&main_r5fss1 { + ti,cluster-mode = <0>; +}; + +&main_r5fss2 { + ti,cluster-mode = <0>; +}; + +/* Timers are used by Remoteproc firmware */ +&main_timer0 { + status = "reserved"; +}; + +&main_timer1 { + status = "reserved"; +}; + +&main_timer2 { + status = "reserved"; +}; + +&main_timer3 { + status = "reserved"; +}; + +&main_timer4 { + status = "reserved"; +}; + +&main_timer5 { + status = "reserved"; +}; + +&main_timer6 { + status = "reserved"; +}; + +&main_timer7 { + status = "reserved"; +}; + +&main_timer8 { + status = "reserved"; +}; + +&main_timer9 { + status = "reserved"; +}; + +&main_r5fss0_core0 { + status = "okay"; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&main_r5fss0_core1 { + status = "okay"; + mboxes = <&mailbox0_cluster1 &mbox_main_r5fss0_core1>; + memory-region = <&main_r5fss0_core1_dma_memory_region>, + <&main_r5fss0_core1_memory_region>; +}; + +&main_r5fss1_core0 { + status = "okay"; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core0>; + memory-region = <&main_r5fss1_core0_dma_memory_region>, + <&main_r5fss1_core0_memory_region>; +}; + +&main_r5fss1_core1 { + status = "okay"; + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss1_core1>; + memory-region = <&main_r5fss1_core1_dma_memory_region>, + <&main_r5fss1_core1_memory_region>; +}; + +&main_r5fss2_core0 { + status = "okay"; + mboxes = <&mailbox0_cluster3 &mbox_main_r5fss2_core0>; + memory-region = <&main_r5fss2_core0_dma_memory_region>, + <&main_r5fss2_core0_memory_region>; +}; + +&main_r5fss2_core1 { + status = "okay"; + mboxes = <&mailbox0_cluster3 &mbox_main_r5fss2_core1>; + memory-region = <&main_r5fss2_core1_dma_memory_region>, + <&main_r5fss2_core1_memory_region>; +}; + +&c71_0 { + status = "okay"; + mboxes = <&mailbox0_cluster4 &mbox_c71_0>; + memory-region = <&c71_0_dma_memory_region>, + <&c71_0_memory_region>; +}; + +&c71_1 { + status = "okay"; + mboxes = <&mailbox0_cluster4 &mbox_c71_1>; + memory-region = <&c71_1_dma_memory_region>, + <&c71_1_memory_region>; +}; + +&c71_2 { + status = "okay"; + mboxes = <&mailbox0_cluster5 &mbox_c71_2>; + memory-region = <&c71_2_dma_memory_region>, + <&c71_2_memory_region>; +}; + +&tscadc0 { + pinctrl-0 = <&mcu_adc0_pins_default>; + pinctrl-names = "default"; + status = "okay"; + adc { + ti,adc-channels = <0 1 2 3 4 5 6 7>; + }; +}; + +&tscadc1 { + pinctrl-0 = <&mcu_adc1_pins_default>; + pinctrl-names = "default"; + status = "okay"; + adc { + ti,adc-channels = <0 1 2 3 4 5 6 7>; + }; +}; + +&serdes_refclk { + status = "okay"; + clock-frequency = <100000000>; +}; + +&dss { + status = "okay"; + assigned-clocks = <&k3_clks 218 2>, + <&k3_clks 218 5>, + <&k3_clks 218 14>, + <&k3_clks 218 18>; + assigned-clock-parents = <&k3_clks 218 3>, + <&k3_clks 218 7>, + <&k3_clks 218 16>, + <&k3_clks 218 22>; +}; + +&serdes0 { + status = "okay"; + + serdes0_pcie1_link: phy@0 { + reg = <0>; + cdns,num-lanes = <2>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 1>, <&serdes_wiz0 2>; + }; + + serdes0_usb_link: phy@3 { + reg = <3>; + cdns,num-lanes = <1>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz0 4>; + }; +}; + +&serdes_wiz0 { + status = "okay"; +}; + +&usb_serdes_mux { + idle-states = <0>; /* USB0 to SERDES lane 3 */ +}; + +&usbss0 { + status = "okay"; + pinctrl-0 = <&main_usbss0_pins_default>; + pinctrl-names = "default"; + ti,vbus-divider; +}; + +&usb0 { + dr_mode = "otg"; + maximum-speed = "super-speed"; + phys = <&serdes0_usb_link>; + phy-names = "cdns3,usb3-phy"; +}; + +&serdes_wiz4 { + status = "okay"; +}; + +&serdes4 { + status = "okay"; + serdes4_dp_link: phy@0 { + reg = <0>; + cdns,num-lanes = <4>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz4 1>, <&serdes_wiz4 2>, + <&serdes_wiz4 3>, <&serdes_wiz4 4>; + }; +}; + +&mhdp { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&dp0_pins_default>; + phys = <&serdes4_dp_link>; + phy-names = "dpphy"; +}; + +&dss_ports { + /* DP */ + port { + dpi0_out: endpoint { + remote-endpoint = <&dp0_in>; + }; + }; +}; + +&main_i2c4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c4_pins_default>; + clock-frequency = <400000>; + + exp4: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; +}; + +&dp0_ports { + port@0 { + reg = <0>; + + dp0_in: endpoint { + remote-endpoint = <&dpi0_out>; + }; + }; + + port@4 { + reg = <4>; + + dp0_out: endpoint { + remote-endpoint = <&dp0_connector_in>; + }; + }; +}; + +&mcu_mcan0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan0_pins_default>; + phys = <&transceiver0>; +}; + +&mcu_mcan1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&mcu_mcan1_pins_default>; + phys = <&transceiver1>; +}; + +&main_mcan16 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan16_pins_default>; + phys = <&transceiver2>; +}; + +&main_mcan4 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcan4_pins_default>; + phys = <&transceiver3>; +}; + +&pcie1_rc { + status = "okay"; + num-lanes = <2>; + reset-gpios = <&exp1 2 GPIO_ACTIVE_HIGH>; + phys = <&serdes0_pcie1_link>; + phy-names = "pcie-phy"; +}; + +&serdes1 { + status = "okay"; + + serdes1_pcie0_link: phy@0 { + reg = <0>; + cdns,num-lanes = <4>; + #phy-cells = <0>; + cdns,phy-type = ; + resets = <&serdes_wiz1 1>, <&serdes_wiz1 2>, + <&serdes_wiz1 3>, <&serdes_wiz1 4>; + }; +}; + +&serdes_wiz1 { + status = "okay"; +}; + +&pcie0_rc { + status = "okay"; + reset-gpios = <&exp1 6 GPIO_ACTIVE_HIGH>; + phys = <&serdes1_pcie0_link>; + phy-names = "pcie-phy"; +}; + +&k3_clks { + /* Confiure AUDIO_EXT_REFCLK1 pin as output */ + pinctrl-names = "default"; + pinctrl-0 = <&audio_ext_refclk1_pins_default>; +}; + +&main_i2c3 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c3_pins_default>; + clock-frequency = <400000>; + + exp3: gpio@20 { + compatible = "ti,tca6408"; + reg = <0x20>; + gpio-controller; + #gpio-cells = <2>; + }; + + pcm3168a_1: audio-codec@44 { + compatible = "ti,pcm3168a"; + reg = <0x44>; + #sound-dai-cells = <1>; + reset-gpios = <&exp3 0 GPIO_ACTIVE_LOW>; + clocks = <&audio_refclk1>; + clock-names = "scki"; + VDD1-supply = <&vsys_3v3>; + VDD2-supply = <&vsys_3v3>; + VCCAD1-supply = <&vsys_5v0>; + VCCAD2-supply = <&vsys_5v0>; + VCCDA1-supply = <&vsys_5v0>; + VCCDA2-supply = <&vsys_5v0>; + }; +}; + +&mcasp0 { + status = "okay"; + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&main_mcasp0_pins_default>; + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + auxclk-fs-ratio = <256>; + serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */ + 0 0 0 1 + 2 0 0 0 + 0 0 0 0 + 0 0 0 0 + >; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi new file mode 100644 index 00000000000000..7721852c1f68a2 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-main-common.dtsi @@ -0,0 +1,2671 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Device Tree Source for J784S4 and J742S2 SoC Family Main Domain peripherals + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include +#include +#include + +#include "k3-serdes.h" + +/ { + serdes_refclk: clock-serdes { + #clock-cells = <0>; + compatible = "fixed-clock"; + /* To be enabled when serdes_wiz* is functional */ + status = "disabled"; + }; +}; + +&cbass_main { + /* + * MSMC is configured by bootloaders and a runtime fixup is done in the + * DT for this node + */ + msmc_ram: sram@70000000 { + compatible = "mmio-sram"; + reg = <0x00 0x70000000 0x00 0x800000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00 0x00 0x70000000 0x800000>; + + atf-sram@0 { + reg = <0x00 0x20000>; + }; + + tifs-sram@1f0000 { + reg = <0x1f0000 0x10000>; + }; + + l3cache-sram@200000 { + reg = <0x200000 0x200000>; + }; + }; + + scm_conf: bus@100000 { + compatible = "simple-bus"; + reg = <0x00 0x00100000 0x00 0x1c000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x00 0x00 0x00100000 0x1c000>; + + cpsw1_phy_gmii_sel: phy@4034 { + compatible = "ti,am654-phy-gmii-sel"; + reg = <0x4034 0x4>; + #phy-cells = <1>; + }; + + cpsw0_phy_gmii_sel: phy@4044 { + compatible = "ti,j784s4-cpsw9g-phy-gmii-sel"; + reg = <0x4044 0x20>; + #phy-cells = <1>; + ti,qsgmii-main-ports = <7>, <7>; + }; + + pcie0_ctrl: pcie0-ctrl@4070 { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x4070 0x4>; + }; + + pcie1_ctrl: pcie1-ctrl@4074 { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x4074 0x4>; + }; + + serdes_ln_ctrl: mux-controller@4080 { + compatible = "reg-mux"; + reg = <0x00004080 0x30>; + #mux-control-cells = <1>; + mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */ + <0x8 0x3>, <0xc 0x3>, /* SERDES0 lane2/3 select */ + <0x10 0x3>, <0x14 0x3>, /* SERDES1 lane0/1 select */ + <0x18 0x3>, <0x1c 0x3>, /* SERDES1 lane2/3 select */ + <0x20 0x3>, <0x24 0x3>, /* SERDES2 lane0/1 select */ + <0x28 0x3>, <0x2c 0x3>; /* SERDES2 lane2/3 select */ + idle-states = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + usb_serdes_mux: mux-controller@4000 { + compatible = "reg-mux"; + reg = <0x4000 0x4>; + #mux-control-cells = <1>; + mux-reg-masks = <0x0 0x8000000>; /* USB0 to SERDES0 lane 3 mux */ + }; + + ehrpwm_tbclk: clock-controller@4140 { + compatible = "ti,am654-ehrpwm-tbclk"; + reg = <0x4140 0x18>; + #clock-cells = <1>; + }; + + audio_refclk1: clock@82e4 { + compatible = "ti,am62-audio-refclk"; + reg = <0x82e4 0x4>; + clocks = <&k3_clks 157 34>; + assigned-clocks = <&k3_clks 157 34>; + assigned-clock-parents = <&k3_clks 157 63>; + #clock-cells = <0>; + }; + }; + + main_ehrpwm0: pwm@3000000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + reg = <0x00 0x3000000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 0>, <&k3_clks 219 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 219 TI_SCI_PD_EXCLUSIVE>; + #pwm-cells = <3>; + status = "disabled"; + }; + + main_ehrpwm1: pwm@3010000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + reg = <0x00 0x3010000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 1>, <&k3_clks 220 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 220 TI_SCI_PD_EXCLUSIVE>; + #pwm-cells = <3>; + status = "disabled"; + }; + + main_ehrpwm2: pwm@3020000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + reg = <0x00 0x3020000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 2>, <&k3_clks 221 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 221 TI_SCI_PD_EXCLUSIVE>; + #pwm-cells = <3>; + status = "disabled"; + }; + + main_ehrpwm3: pwm@3030000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + reg = <0x00 0x3030000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 3>, <&k3_clks 222 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 222 TI_SCI_PD_EXCLUSIVE>; + #pwm-cells = <3>; + status = "disabled"; + }; + + main_ehrpwm4: pwm@3040000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + reg = <0x00 0x3040000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 4>, <&k3_clks 223 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 223 TI_SCI_PD_EXCLUSIVE>; + #pwm-cells = <3>; + status = "disabled"; + }; + + main_ehrpwm5: pwm@3050000 { + compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; + reg = <0x00 0x3050000 0x00 0x100>; + clocks = <&ehrpwm_tbclk 5>, <&k3_clks 224 0>; + clock-names = "tbclk", "fck"; + power-domains = <&k3_pds 224 TI_SCI_PD_EXCLUSIVE>; + #pwm-cells = <3>; + status = "disabled"; + }; + + gic500: interrupt-controller@1800000 { + compatible = "arm,gic-v3"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00 0x01800000 0x00 0x200000>, /* GICD */ + <0x00 0x01900000 0x00 0x100000>, /* GICR */ + <0x00 0x6f000000 0x00 0x2000>, /* GICC */ + <0x00 0x6f010000 0x00 0x1000>, /* GICH */ + <0x00 0x6f020000 0x00 0x2000>; /* GICV */ + + /* vcpumntirq: virtual CPU interface maintenance interrupt */ + interrupts = ; + + gic_its: msi-controller@1820000 { + compatible = "arm,gic-v3-its"; + reg = <0x00 0x01820000 0x00 0x10000>; + socionext,synquacer-pre-its = <0x1000000 0x400000>; + msi-controller; + #msi-cells = <1>; + }; + }; + + main_gpio_intr: interrupt-controller@a00000 { + compatible = "ti,sci-intr"; + reg = <0x00 0x00a00000 0x00 0x800>; + ti,intr-trigger-type = <1>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&sms>; + ti,sci-dev-id = <10>; + ti,interrupt-ranges = <8 392 56>; + }; + + main_pmx0: pinctrl@11c000 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x11c000 0x00 0x120>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + /* TIMERIO pad input CTRLMMR_TIMER*_CTRL registers */ + main_timerio_input: pinctrl@104200 { + compatible = "pinctrl-single"; + reg = <0x00 0x104200 0x00 0x50>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x00000007>; + }; + + /* TIMERIO pad output CTCTRLMMR_TIMERIO*_CTRL registers */ + main_timerio_output: pinctrl@104280 { + compatible = "pinctrl-single"; + reg = <0x00 0x104280 0x00 0x20>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x0000001f>; + }; + + main_crypto: crypto@4e00000 { + compatible = "ti,j721e-sa2ul"; + reg = <0x00 0x4e00000 0x00 0x1200>; + power-domains = <&k3_pds 369 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x04e00000 0x00 0x04e00000 0x00 0x30000>; + + dmas = <&main_udmap 0xca40>, <&main_udmap 0x4a40>, + <&main_udmap 0x4a41>; + dma-names = "tx", "rx1", "rx2"; + + rng: rng@4e10000 { + compatible = "inside-secure,safexcel-eip76"; + reg = <0x00 0x4e10000 0x00 0x7d>; + interrupts = ; + }; + }; + + main_timer0: timer@2400000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2400000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 97 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 97 2>; + assigned-clock-parents = <&k3_clks 97 3>; + power-domains = <&k3_pds 97 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer1: timer@2410000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2410000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 98 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 98 2>; + assigned-clock-parents = <&k3_clks 98 3>; + power-domains = <&k3_pds 98 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer2: timer@2420000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2420000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 99 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 99 2>; + assigned-clock-parents = <&k3_clks 99 3>; + power-domains = <&k3_pds 99 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer3: timer@2430000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2430000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 100 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 100 2>; + assigned-clock-parents = <&k3_clks 100 3>; + power-domains = <&k3_pds 100 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer4: timer@2440000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2440000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 101 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 101 2>; + assigned-clock-parents = <&k3_clks 101 3>; + power-domains = <&k3_pds 101 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer5: timer@2450000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2450000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 102 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 102 2>; + assigned-clock-parents = <&k3_clks 102 3>; + power-domains = <&k3_pds 102 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer6: timer@2460000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2460000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 103 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 103 2>; + assigned-clock-parents = <&k3_clks 103 3>; + power-domains = <&k3_pds 103 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer7: timer@2470000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2470000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 104 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 104 2>; + assigned-clock-parents = <&k3_clks 104 3>; + power-domains = <&k3_pds 104 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer8: timer@2480000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2480000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 105 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 105 2>; + assigned-clock-parents = <&k3_clks 105 3>; + power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer9: timer@2490000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2490000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 106 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 106 2>; + assigned-clock-parents = <&k3_clks 106 3>; + power-domains = <&k3_pds 106 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer10: timer@24a0000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x24a0000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 107 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 107 2>; + assigned-clock-parents = <&k3_clks 107 3>; + power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer11: timer@24b0000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x24b0000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 108 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 108 2>; + assigned-clock-parents = <&k3_clks 108 3>; + power-domains = <&k3_pds 108 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer12: timer@24c0000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x24c0000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 109 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 109 2>; + assigned-clock-parents = <&k3_clks 109 3>; + power-domains = <&k3_pds 109 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer13: timer@24d0000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x24d0000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 110 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 110 2>; + assigned-clock-parents = <&k3_clks 110 3>; + power-domains = <&k3_pds 110 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer14: timer@24e0000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x24e0000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 111 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 111 2>; + assigned-clock-parents = <&k3_clks 111 3>; + power-domains = <&k3_pds 111 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer15: timer@24f0000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x24f0000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 112 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 112 2>; + assigned-clock-parents = <&k3_clks 112 3>; + power-domains = <&k3_pds 112 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer16: timer@2500000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2500000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 113 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 113 2>; + assigned-clock-parents = <&k3_clks 113 3>; + power-domains = <&k3_pds 113 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer17: timer@2510000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2510000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 114 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 114 2>; + assigned-clock-parents = <&k3_clks 114 3>; + power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer18: timer@2520000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2520000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 115 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 115 2>; + assigned-clock-parents = <&k3_clks 115 3>; + power-domains = <&k3_pds 115 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_timer19: timer@2530000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x2530000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 116 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 116 2>; + assigned-clock-parents = <&k3_clks 116 3>; + power-domains = <&k3_pds 116 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + }; + + main_uart0: serial@2800000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02800000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 146 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart1: serial@2810000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02810000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 388 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 388 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart2: serial@2820000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02820000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 389 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 389 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart3: serial@2830000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02830000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 390 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 390 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart4: serial@2840000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02840000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 391 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 391 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart5: serial@2850000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02850000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 392 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 392 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart6: serial@2860000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02860000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 393 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 393 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart7: serial@2870000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02870000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 394 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 394 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart8: serial@2880000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02880000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 395 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 395 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_uart9: serial@2890000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x02890000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 396 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 396 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_gpio0: gpio@600000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x00 0x00600000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <145>, <146>, <147>, <148>, <149>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <66>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 163 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 163 0>; + clock-names = "gpio"; + status = "disabled"; + }; + + main_gpio2: gpio@610000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x00 0x00610000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <154>, <155>, <156>, <157>, <158>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <66>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 164 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 164 0>; + clock-names = "gpio"; + status = "disabled"; + }; + + main_gpio4: gpio@620000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x00 0x00620000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <163>, <164>, <165>, <166>, <167>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <66>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 165 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 165 0>; + clock-names = "gpio"; + status = "disabled"; + }; + + main_gpio6: gpio@630000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x00 0x00630000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&main_gpio_intr>; + interrupts = <172>, <173>, <174>, <175>, <176>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <66>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 166 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 166 0>; + clock-names = "gpio"; + status = "disabled"; + }; + + usbss0: usb@4104000 { + bootph-all; + compatible = "ti,j721e-usb"; + reg = <0x00 0x4104000 0x00 0x100>; + dma-coherent; + power-domains = <&k3_pds 398 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 398 21>, <&k3_clks 398 2>; + clock-names = "ref", "lpm"; + assigned-clocks = <&k3_clks 398 21>; /* USB2_REFCLK */ + assigned-clock-parents = <&k3_clks 398 22>; /* HFOSC0 */ + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; /* Needs lane config */ + + usb0: usb@6000000 { + bootph-all; + compatible = "cdns,usb3"; + reg = <0x00 0x6000000 0x00 0x10000>, + <0x00 0x6010000 0x00 0x10000>, + <0x00 0x6020000 0x00 0x10000>; + reg-names = "otg", "xhci", "dev"; + interrupts = , /* irq.0 */ + , /* irq.6 */ + ; /* otgirq.0 */ + interrupt-names = "host", + "peripheral", + "otg"; + }; + }; + + main_i2c0: i2c@2000000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x02000000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 270 2>; + clock-names = "fck"; + power-domains = <&k3_pds 270 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_i2c1: i2c@2010000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x02010000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 271 2>; + clock-names = "fck"; + power-domains = <&k3_pds 271 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_i2c2: i2c@2020000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x02020000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 272 2>; + clock-names = "fck"; + power-domains = <&k3_pds 272 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_i2c3: i2c@2030000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x02030000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 273 2>; + clock-names = "fck"; + power-domains = <&k3_pds 273 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_i2c4: i2c@2040000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x02040000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 274 2>; + clock-names = "fck"; + power-domains = <&k3_pds 274 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_i2c5: i2c@2050000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x02050000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 275 2>; + clock-names = "fck"; + power-domains = <&k3_pds 275 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + main_i2c6: i2c@2060000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x02060000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 276 2>; + clock-names = "fck"; + power-domains = <&k3_pds 276 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + ti_csi2rx0: ticsi2rx@4500000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x04500000 0x00 0x00001000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x4940 0>; + dma-names = "rx0"; + power-domains = <&k3_pds 72 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@4504000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x04504000 0x00 0x00001000>; + clocks = <&k3_clks 72 2>, <&k3_clks 72 0>, <&k3_clks 72 2>, + <&k3_clks 72 2>, <&k3_clks 72 3>, <&k3_clks 72 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + ti_csi2rx1: ticsi2rx@4510000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x04510000 0x00 0x1000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x4960 0>; + dma-names = "rx0"; + power-domains = <&k3_pds 73 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx1: csi-bridge@4514000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x04514000 0x00 0x00001000>; + clocks = <&k3_clks 73 2>, <&k3_clks 73 0>, <&k3_clks 73 2>, + <&k3_clks 73 2>, <&k3_clks 73 3>, <&k3_clks 73 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy1>; + phy-names = "dphy"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi1_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi1_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi1_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi1_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + ti_csi2rx2: ticsi2rx@4520000 { + compatible = "ti,j721e-csi2rx-shim"; + reg = <0x00 0x04520000 0x00 0x00001000>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + dmas = <&main_bcdma_csi 0 0x4980 0>; + dma-names = "rx0"; + power-domains = <&k3_pds 74 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + cdns_csi2rx2: csi-bridge@4524000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x04524000 0x00 0x00001000>; + clocks = <&k3_clks 74 2>, <&k3_clks 74 0>, <&k3_clks 74 2>, + <&k3_clks 74 2>, <&k3_clks 74 3>, <&k3_clks 74 3>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy2>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi2_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi2_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi2_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi2_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@4580000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x04580000 0x00 0x00001100>; + #phy-cells = <0>; + power-domains = <&k3_pds 212 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dphy1: phy@4590000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x04590000 0x00 0x00001100>; + #phy-cells = <0>; + power-domains = <&k3_pds 213 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + dphy2: phy@45a0000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x045a0000 0x00 0x00001100>; + #phy-cells = <0>; + power-domains = <&k3_pds 214 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + vpu0: video-codec@4210000 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x00 0x4210000 0x00 0x10000>; + interrupts = ; + clocks = <&k3_clks 241 2>; + power-domains = <&k3_pds 241 TI_SCI_PD_EXCLUSIVE>; + }; + + vpu1: video-codec@4220000 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x00 0x4220000 0x00 0x10000>; + interrupts = ; + clocks = <&k3_clks 242 2>; + power-domains = <&k3_pds 242 TI_SCI_PD_EXCLUSIVE>; + }; + + main_sdhci0: mmc@4f80000 { + compatible = "ti,j721e-sdhci-8bit"; + reg = <0x00 0x04f80000 0x00 0x1000>, + <0x00 0x04f88000 0x00 0x400>; + interrupts = ; + power-domains = <&k3_pds 140 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 140 1>, <&k3_clks 140 2>; + clock-names = "clk_ahb", "clk_xin"; + assigned-clocks = <&k3_clks 140 2>; + assigned-clock-parents = <&k3_clks 140 3>; + bus-width = <8>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-mmc-hs = <0x0>; + ti,otap-del-sel-ddr52 = <0x6>; + ti,otap-del-sel-hs200 = <0x8>; + ti,otap-del-sel-hs400 = <0x5>; + ti,itap-del-sel-legacy = <0x10>; + ti,itap-del-sel-mmc-hs = <0xa>; + ti,strobe-sel = <0x77>; + ti,clkbuf-sel = <0x7>; + ti,trm-icp = <0x8>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + dma-coherent; + status = "disabled"; + }; + + main_sdhci1: mmc@4fb0000 { + compatible = "ti,j721e-sdhci-4bit"; + reg = <0x00 0x04fb0000 0x00 0x1000>, + <0x00 0x04fb8000 0x00 0x400>; + interrupts = ; + power-domains = <&k3_pds 141 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 141 3>, <&k3_clks 141 4>; + clock-names = "clk_ahb", "clk_xin"; + assigned-clocks = <&k3_clks 141 4>; + assigned-clock-parents = <&k3_clks 141 5>; + bus-width = <4>; + ti,otap-del-sel-legacy = <0x0>; + ti,otap-del-sel-sd-hs = <0x0>; + ti,otap-del-sel-sdr12 = <0xf>; + ti,otap-del-sel-sdr25 = <0xf>; + ti,otap-del-sel-sdr50 = <0xc>; + ti,otap-del-sel-sdr104 = <0x5>; + ti,otap-del-sel-ddr50 = <0xc>; + ti,itap-del-sel-legacy = <0x0>; + ti,itap-del-sel-sd-hs = <0x0>; + ti,itap-del-sel-sdr12 = <0x0>; + ti,itap-del-sel-sdr25 = <0x0>; + ti,itap-del-sel-ddr50 = <0x2>; + ti,clkbuf-sel = <0x7>; + ti,trm-icp = <0x8>; + dma-coherent; + status = "disabled"; + }; + + pcie0_rc: pcie@2900000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02900000 0x00 0x1000>, + <0x00 0x02907000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x10000000 0x00 0x00001000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x0>; + max-link-speed = <3>; + num-lanes = <4>; + power-domains = <&k3_pds 332 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 332 0>; + clock-names = "fck"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb012>; + msi-map = <0x0 &gic_its 0x0 0x10000>; + dma-coherent; + ranges = <0x01000000 0x0 0x10001000 0x0 0x10001000 0x0 0x0010000>, + <0x02000000 0x0 0x10011000 0x0 0x10011000 0x0 0x7fef000>; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + status = "disabled"; + }; + + pcie1_rc: pcie@2910000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02910000 0x00 0x1000>, + <0x00 0x02917000 0x00 0x400>, + <0x00 0x0d800000 0x00 0x00800000>, + <0x00 0x18000000 0x00 0x00001000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + ti,syscon-pcie-ctrl = <&pcie1_ctrl 0x0>; + max-link-speed = <3>; + num-lanes = <4>; + power-domains = <&k3_pds 333 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 333 0>; + clock-names = "fck"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb012>; + msi-map = <0x0 &gic_its 0x10000 0x10000>; + dma-coherent; + ranges = <0x01000000 0x0 0x18001000 0x00 0x18001000 0x0 0x0010000>, + <0x02000000 0x0 0x18011000 0x00 0x18011000 0x0 0x7fef000>; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + status = "disabled"; + }; + + serdes_wiz0: wiz@5060000 { + compatible = "ti,j784s4-wiz-10g"; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 404 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 404 2>, <&k3_clks 404 6>, <&serdes_refclk>, <&k3_clks 404 5>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; + assigned-clocks = <&k3_clks 404 6>; + assigned-clock-parents = <&k3_clks 404 10>; + num-lanes = <4>; + #reset-cells = <1>; + #clock-cells = <1>; + ranges = <0x5060000 0x00 0x5060000 0x10000>; + status = "disabled"; + + serdes0: serdes@5060000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x05060000 0x010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz0 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz0 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz0 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz0 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 404 6>, + <&k3_clks 404 6>, + <&k3_clks 404 6>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + status = "disabled"; + }; + }; + + serdes_wiz1: wiz@5070000 { + compatible = "ti,j784s4-wiz-10g"; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 405 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 405 2>, <&k3_clks 405 6>, <&serdes_refclk>, <&k3_clks 405 5>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; + assigned-clocks = <&k3_clks 405 6>; + assigned-clock-parents = <&k3_clks 405 10>; + num-lanes = <4>; + #reset-cells = <1>; + #clock-cells = <1>; + ranges = <0x05070000 0x00 0x05070000 0x10000>; + status = "disabled"; + + serdes1: serdes@5070000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x05070000 0x010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz1 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz1 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz1 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz1 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz1 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz1 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 405 6>, + <&k3_clks 405 6>, + <&k3_clks 405 6>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + status = "disabled"; + }; + }; + + serdes_wiz4: wiz@5050000 { + compatible = "ti,j784s4-wiz-10g"; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 407 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 407 2>, <&k3_clks 407 6>, <&serdes_refclk>, <&k3_clks 407 5>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; + assigned-clocks = <&k3_clks 407 6>; + assigned-clock-parents = <&k3_clks 407 10>; + num-lanes = <4>; + #reset-cells = <1>; + #clock-cells = <1>; + ranges = <0x05050000 0x00 0x05050000 0x10000>, + <0xa030a00 0x00 0xa030a00 0x40>; /* DPTX PHY */ + status = "disabled"; + + serdes4: serdes@5050000 { + /* + * Note: we also map DPTX PHY registers as the Torrent + * needs to manage those. + */ + compatible = "ti,j721e-serdes-10g"; + reg = <0x05050000 0x010000>, + <0x0a030a00 0x40>; /* DPTX PHY */ + reg-names = "torrent_phy"; + resets = <&serdes_wiz4 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz4 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz4 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz4 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz4 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz4 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 407 6>, + <&k3_clks 407 6>, + <&k3_clks 407 6>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + status = "disabled"; + }; + }; + + main_navss: bus@30000000 { + bootph-all; + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>; + ti,sci-dev-id = <280>; + dma-coherent; + dma-ranges; + + main_navss_intr: interrupt-controller@310e0000 { + compatible = "ti,sci-intr"; + reg = <0x00 0x310e0000 0x00 0x4000>; + ti,intr-trigger-type = <4>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&sms>; + ti,sci-dev-id = <283>; + ti,interrupt-ranges = <0 64 64>, + <64 448 64>, + <128 672 64>; + }; + + main_udmass_inta: msi-controller@33d00000 { + compatible = "ti,sci-inta"; + reg = <0x00 0x33d00000 0x00 0x100000>; + interrupt-controller; + #interrupt-cells = <0>; + interrupt-parent = <&main_navss_intr>; + msi-controller; + ti,sci = <&sms>; + ti,sci-dev-id = <321>; + ti,interrupt-ranges = <0 0 256>; + ti,unmapped-event-sources = <&main_bcdma_csi>; + }; + + secure_proxy_main: mailbox@32c00000 { + bootph-all; + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x32c00000 0x00 0x100000>, + <0x00 0x32400000 0x00 0x100000>, + <0x00 0x32800000 0x00 0x100000>; + interrupt-names = "rx_011"; + interrupts = ; + }; + + hwspinlock: hwlock@30e00000 { + compatible = "ti,am654-hwspinlock"; + reg = <0x00 0x30e00000 0x00 0x1000>; + #hwlock-cells = <1>; + }; + + mailbox0_cluster0: mailbox@31f80000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f80000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster1: mailbox@31f81000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f81000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster2: mailbox@31f82000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f82000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster3: mailbox@31f83000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f83000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster4: mailbox@31f84000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f84000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster5: mailbox@31f85000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f85000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster6: mailbox@31f86000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f86000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster7: mailbox@31f87000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f87000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster8: mailbox@31f88000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f88000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster9: mailbox@31f89000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f89000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster10: mailbox@31f8a000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f8a000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox0_cluster11: mailbox@31f8b000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f8b000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster0: mailbox@31f90000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f90000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster1: mailbox@31f91000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f91000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster2: mailbox@31f92000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f92000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster3: mailbox@31f93000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f93000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster4: mailbox@31f94000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f94000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster5: mailbox@31f95000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f95000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster6: mailbox@31f96000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f96000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster7: mailbox@31f97000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f97000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster8: mailbox@31f98000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f98000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster9: mailbox@31f99000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f99000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster10: mailbox@31f9a000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f9a000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + mailbox1_cluster11: mailbox@31f9b000 { + compatible = "ti,am654-mailbox"; + reg = <0x00 0x31f9b000 0x00 0x200>; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <16>; + interrupt-parent = <&main_navss_intr>; + status = "disabled"; + }; + + main_ringacc: ringacc@3c000000 { + compatible = "ti,am654-navss-ringacc"; + reg = <0x00 0x3c000000 0x00 0x400000>, + <0x00 0x38000000 0x00 0x400000>, + <0x00 0x31120000 0x00 0x100>, + <0x00 0x33000000 0x00 0x40000>, + <0x00 0x31080000 0x00 0x40000>; + reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg"; + ti,num-rings = <1024>; + ti,sci-rm-range-gp-rings = <0x1>; + ti,sci = <&sms>; + ti,sci-dev-id = <315>; + msi-parent = <&main_udmass_inta>; + }; + + main_udmap: dma-controller@31150000 { + compatible = "ti,j721e-navss-main-udmap"; + reg = <0x00 0x31150000 0x00 0x100>, + <0x00 0x34000000 0x00 0x80000>, + <0x00 0x35000000 0x00 0x200000>, + <0x00 0x30b00000 0x00 0x20000>, + <0x00 0x30c00000 0x00 0x8000>, + <0x00 0x30d00000 0x00 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; + msi-parent = <&main_udmass_inta>; + #dma-cells = <1>; + + ti,sci = <&sms>; + ti,sci-dev-id = <319>; + ti,ringacc = <&main_ringacc>; + + ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */ + <0x0f>, /* TX_HCHAN */ + <0x10>; /* TX_UHCHAN */ + ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */ + <0x0b>, /* RX_HCHAN */ + <0x0c>; /* RX_UHCHAN */ + ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ + }; + + main_bcdma_csi: dma-controller@311a0000 { + compatible = "ti,j721s2-dmss-bcdma-csi"; + reg = <0x00 0x311a0000 0x00 0x100>, + <0x00 0x35d00000 0x00 0x20000>, + <0x00 0x35c00000 0x00 0x10000>, + <0x00 0x35e00000 0x00 0x80000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + msi-parent = <&main_udmass_inta>; + #dma-cells = <3>; + ti,sci = <&sms>; + ti,sci-dev-id = <281>; + ti,sci-rm-range-rchan = <0x21>; + ti,sci-rm-range-tchan = <0x22>; + }; + + cpts@310d0000 { + compatible = "ti,j721e-cpts"; + reg = <0x00 0x310d0000 0x00 0x400>; + reg-names = "cpts"; + clocks = <&k3_clks 282 0>; + clock-names = "cpts"; + assigned-clocks = <&k3_clks 62 3>; /* CPTS_RFT_CLK */ + assigned-clock-parents = <&k3_clks 62 5>; /* MAIN_0_HSDIV6_CLK */ + interrupts-extended = <&main_navss_intr 391>; + interrupt-names = "cpts"; + ti,cpts-periodic-outputs = <6>; + ti,cpts-ext-ts-inputs = <8>; + }; + }; + + main_cpsw0: ethernet@c000000 { + compatible = "ti,j784s4-cpswxg-nuss"; + reg = <0x00 0xc000000 0x00 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x00 0x00 0x00 0xc000000 0x00 0x200000>; + #address-cells = <2>; + #size-cells = <2>; + dma-coherent; + clocks = <&k3_clks 64 0>; + clock-names = "fck"; + power-domains = <&k3_pds 64 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&main_udmap 0xca00>, + <&main_udmap 0xca01>, + <&main_udmap 0xca02>, + <&main_udmap 0xca03>, + <&main_udmap 0xca04>, + <&main_udmap 0xca05>, + <&main_udmap 0xca06>, + <&main_udmap 0xca07>, + <&main_udmap 0x4a00>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + + status = "disabled"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + main_cpsw0_port1: port@1 { + reg = <1>; + label = "port1"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port2: port@2 { + reg = <2>; + label = "port2"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port3: port@3 { + reg = <3>; + label = "port3"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port4: port@4 { + reg = <4>; + label = "port4"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port5: port@5 { + reg = <5>; + label = "port5"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port6: port@6 { + reg = <6>; + label = "port6"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port7: port@7 { + reg = <7>; + label = "port7"; + ti,mac-only; + status = "disabled"; + }; + + main_cpsw0_port8: port@8 { + reg = <8>; + label = "port8"; + ti,mac-only; + status = "disabled"; + }; + }; + + main_cpsw0_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; + reg = <0x00 0xf00 0x00 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 64 0>; + clock-names = "fck"; + bus_freq = <1000000>; + status = "disabled"; + }; + + cpts@3d000 { + compatible = "ti,am65-cpts"; + reg = <0x00 0x3d000 0x00 0x400>; + clocks = <&k3_clks 64 3>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + }; + + main_cpsw1: ethernet@c200000 { + compatible = "ti,j721e-cpsw-nuss"; + reg = <0x00 0xc200000 0x00 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x00 0x00 0x00 0xc200000 0x00 0x200000>; + #address-cells = <2>; + #size-cells = <2>; + dma-coherent; + clocks = <&k3_clks 62 0>; + clock-names = "fck"; + power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&main_udmap 0xc640>, + <&main_udmap 0xc641>, + <&main_udmap 0xc642>, + <&main_udmap 0xc643>, + <&main_udmap 0xc644>, + <&main_udmap 0xc645>, + <&main_udmap 0xc646>, + <&main_udmap 0xc647>, + <&main_udmap 0x4640>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + + status = "disabled"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + main_cpsw1_port1: port@1 { + reg = <1>; + label = "port1"; + phys = <&cpsw1_phy_gmii_sel 1>; + ti,mac-only; + status = "disabled"; + }; + }; + + main_cpsw1_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio", "ti,davinci_mdio"; + reg = <0x00 0xf00 0x00 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 62 0>; + clock-names = "fck"; + bus_freq = <1000000>; + status = "disabled"; + }; + + cpts@3d000 { + compatible = "ti,am65-cpts"; + reg = <0x00 0x3d000 0x00 0x400>; + clocks = <&k3_clks 62 3>; + clock-names = "cpts"; + interrupts-extended = <&gic500 GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + }; + + main_mcan0: can@2701000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02701000 0x00 0x200>, + <0x00 0x02708000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 245 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 245 6>, <&k3_clks 245 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan1: can@2711000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02711000 0x00 0x200>, + <0x00 0x02718000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 246 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 246 6>, <&k3_clks 246 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan2: can@2721000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02721000 0x00 0x200>, + <0x00 0x02728000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 247 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 247 6>, <&k3_clks 247 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan3: can@2731000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02731000 0x00 0x200>, + <0x00 0x02738000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 248 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 248 6>, <&k3_clks 248 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan4: can@2741000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02741000 0x00 0x200>, + <0x00 0x02748000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 249 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 249 6>, <&k3_clks 249 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan5: can@2751000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02751000 0x00 0x200>, + <0x00 0x02758000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 250 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 250 6>, <&k3_clks 250 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan6: can@2761000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02761000 0x00 0x200>, + <0x00 0x02768000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 251 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 251 6>, <&k3_clks 251 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan7: can@2771000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02771000 0x00 0x200>, + <0x00 0x02778000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 252 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 252 6>, <&k3_clks 252 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan8: can@2781000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02781000 0x00 0x200>, + <0x00 0x02788000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 253 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 253 6>, <&k3_clks 253 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan9: can@2791000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02791000 0x00 0x200>, + <0x00 0x02798000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 254 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 254 6>, <&k3_clks 254 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan10: can@27a1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x027a1000 0x00 0x200>, + <0x00 0x027a8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 255 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 255 6>, <&k3_clks 255 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan11: can@27b1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x027b1000 0x00 0x200>, + <0x00 0x027b8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 256 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 256 6>, <&k3_clks 256 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan12: can@27c1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x027c1000 0x00 0x200>, + <0x00 0x027c8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 257 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 257 6>, <&k3_clks 257 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan13: can@27d1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x027d1000 0x00 0x200>, + <0x00 0x027d8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 258 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 258 6>, <&k3_clks 258 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan14: can@2681000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02681000 0x00 0x200>, + <0x00 0x02688000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 259 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 259 6>, <&k3_clks 259 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan15: can@2691000 { + compatible = "bosch,m_can"; + reg = <0x00 0x02691000 0x00 0x200>, + <0x00 0x02698000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 260 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 260 6>, <&k3_clks 260 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan16: can@26a1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x026a1000 0x00 0x200>, + <0x00 0x026a8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 261 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 261 6>, <&k3_clks 261 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_mcan17: can@26b1000 { + compatible = "bosch,m_can"; + reg = <0x00 0x026b1000 0x00 0x200>, + <0x00 0x026b8000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 262 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 262 6>, <&k3_clks 262 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + main_spi0: spi@2100000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x02100000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 376 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 376 1>; + status = "disabled"; + }; + + main_spi1: spi@2110000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x02110000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 377 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 377 1>; + status = "disabled"; + }; + + main_spi2: spi@2120000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x02120000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 378 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 378 1>; + status = "disabled"; + }; + + main_spi3: spi@2130000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x02130000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 379 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 379 1>; + status = "disabled"; + }; + + main_spi4: spi@2140000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x02140000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 380 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 380 1>; + status = "disabled"; + }; + + main_spi5: spi@2150000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x02150000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 381 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 381 1>; + status = "disabled"; + }; + + main_spi6: spi@2160000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x02160000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 382 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 382 1>; + status = "disabled"; + }; + + main_spi7: spi@2170000 { + compatible = "ti,am654-mcspi","ti,omap4-mcspi"; + reg = <0x00 0x02170000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 383 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 383 1>; + status = "disabled"; + }; + + ufs_wrapper: ufs-wrapper@4e80000 { + compatible = "ti,j721e-ufs"; + reg = <0x00 0x4e80000 0x00 0x100>; + power-domains = <&k3_pds 387 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 387 3>; + assigned-clocks = <&k3_clks 387 3>; + assigned-clock-parents = <&k3_clks 387 6>; + ranges; + #address-cells = <2>; + #size-cells = <2>; + status = "disabled"; + + ufs@4e84000 { + compatible = "cdns,ufshc-m31-16nm", "jedec,ufs-2.0"; + reg = <0x00 0x4e84000 0x00 0x10000>; + interrupts = ; + freq-table-hz = <250000000 250000000>, <19200000 19200000>, + <19200000 19200000>; + clocks = <&k3_clks 387 1>, <&k3_clks 387 3>, <&k3_clks 387 3>; + clock-names = "core_clk", "phy_clk", "ref_clk"; + dma-coherent; + }; + }; + + main_r5fss0: r5fss@5c00000 { + compatible = "ti,j721s2-r5fss"; + ti,cluster-mode = <1>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5c00000 0x00 0x5c00000 0x20000>, + <0x5d00000 0x00 0x5d00000 0x20000>; + power-domains = <&k3_pds 336 TI_SCI_PD_EXCLUSIVE>; + + main_r5fss0_core0: r5f@5c00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5c00000 0x00010000>, + <0x5c10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <339>; + ti,sci-proc-ids = <0x06 0xff>; + resets = <&k3_reset 339 1>; + firmware-name = "j784s4-main-r5f0_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + main_r5fss0_core1: r5f@5d00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5d00000 0x00010000>, + <0x5d10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <340>; + ti,sci-proc-ids = <0x07 0xff>; + resets = <&k3_reset 340 1>; + firmware-name = "j784s4-main-r5f0_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + main_r5fss1: r5fss@5e00000 { + compatible = "ti,j721s2-r5fss"; + ti,cluster-mode = <1>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5e00000 0x00 0x5e00000 0x20000>, + <0x5f00000 0x00 0x5f00000 0x20000>; + power-domains = <&k3_pds 337 TI_SCI_PD_EXCLUSIVE>; + + main_r5fss1_core0: r5f@5e00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5e00000 0x00010000>, + <0x5e10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <341>; + ti,sci-proc-ids = <0x08 0xff>; + resets = <&k3_reset 341 1>; + firmware-name = "j784s4-main-r5f1_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + main_r5fss1_core1: r5f@5f00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5f00000 0x00010000>, + <0x5f10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <342>; + ti,sci-proc-ids = <0x09 0xff>; + resets = <&k3_reset 342 1>; + firmware-name = "j784s4-main-r5f1_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + main_r5fss2: r5fss@5900000 { + compatible = "ti,j721s2-r5fss"; + ti,cluster-mode = <1>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x5900000 0x00 0x5900000 0x20000>, + <0x5a00000 0x00 0x5a00000 0x20000>; + power-domains = <&k3_pds 338 TI_SCI_PD_EXCLUSIVE>; + + main_r5fss2_core0: r5f@5900000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5900000 0x00010000>, + <0x5910000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <343>; + ti,sci-proc-ids = <0x0a 0xff>; + resets = <&k3_reset 343 1>; + firmware-name = "j784s4-main-r5f2_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + main_r5fss2_core1: r5f@5a00000 { + compatible = "ti,j721s2-r5f"; + reg = <0x5a00000 0x00010000>, + <0x5a10000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <344>; + ti,sci-proc-ids = <0x0b 0xff>; + resets = <&k3_reset 344 1>; + firmware-name = "j784s4-main-r5f2_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + c71_0: dsp@64800000 { + compatible = "ti,j721s2-c71-dsp"; + reg = <0x00 0x64800000 0x00 0x00080000>, + <0x00 0x64e00000 0x00 0x0000c000>; + reg-names = "l2sram", "l1dram"; + ti,sci = <&sms>; + ti,sci-dev-id = <30>; + ti,sci-proc-ids = <0x30 0xff>; + resets = <&k3_reset 30 1>; + firmware-name = "j784s4-c71_0-fw"; + status = "disabled"; + }; + + c71_1: dsp@65800000 { + compatible = "ti,j721s2-c71-dsp"; + reg = <0x00 0x65800000 0x00 0x00080000>, + <0x00 0x65e00000 0x00 0x0000c000>; + reg-names = "l2sram", "l1dram"; + ti,sci = <&sms>; + ti,sci-dev-id = <33>; + ti,sci-proc-ids = <0x31 0xff>; + resets = <&k3_reset 33 1>; + firmware-name = "j784s4-c71_1-fw"; + status = "disabled"; + }; + + c71_2: dsp@66800000 { + compatible = "ti,j721s2-c71-dsp"; + reg = <0x00 0x66800000 0x00 0x00080000>, + <0x00 0x66e00000 0x00 0x0000c000>; + reg-names = "l2sram", "l1dram"; + ti,sci = <&sms>; + ti,sci-dev-id = <37>; + ti,sci-proc-ids = <0x32 0xff>; + resets = <&k3_reset 37 1>; + firmware-name = "j784s4-c71_2-fw"; + status = "disabled"; + }; + + main_esm: esm@700000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x700000 0x00 0x1000>; + ti,esm-pins = <688>, <689>, <690>, <691>, <692>, <693>, <694>, + <695>; + bootph-pre-ram; + }; + + watchdog0: watchdog@2200000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2200000 0x00 0x100>; + clocks = <&k3_clks 348 0>; + power-domains = <&k3_pds 348 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 348 0>; + assigned-clock-parents = <&k3_clks 348 4>; + }; + + watchdog1: watchdog@2210000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2210000 0x00 0x100>; + clocks = <&k3_clks 349 0>; + power-domains = <&k3_pds 349 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 349 0>; + assigned-clock-parents = <&k3_clks 349 4>; + }; + + watchdog2: watchdog@2220000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2220000 0x00 0x100>; + clocks = <&k3_clks 350 0>; + power-domains = <&k3_pds 350 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 350 0>; + assigned-clock-parents = <&k3_clks 350 4>; + }; + + watchdog3: watchdog@2230000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2230000 0x00 0x100>; + clocks = <&k3_clks 351 0>; + power-domains = <&k3_pds 351 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 351 0>; + assigned-clock-parents = <&k3_clks 351 4>; + }; + + watchdog4: watchdog@2240000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2240000 0x00 0x100>; + clocks = <&k3_clks 352 0>; + power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 352 0>; + assigned-clock-parents = <&k3_clks 352 4>; + }; + + watchdog5: watchdog@2250000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2250000 0x00 0x100>; + clocks = <&k3_clks 353 0>; + power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 353 0>; + assigned-clock-parents = <&k3_clks 353 4>; + }; + + watchdog6: watchdog@2260000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2260000 0x00 0x100>; + clocks = <&k3_clks 354 0>; + power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 354 0>; + assigned-clock-parents = <&k3_clks 354 4>; + }; + + watchdog7: watchdog@2270000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2270000 0x00 0x100>; + clocks = <&k3_clks 355 0>; + power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 355 0>; + assigned-clock-parents = <&k3_clks 355 4>; + }; + + /* + * The following RTI instances are coupled with MCU R5Fs, c7x and + * GPU so keeping them reserved as these will be used by their + * respective firmware + */ + watchdog8: watchdog@22f0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x22f0000 0x00 0x100>; + clocks = <&k3_clks 360 0>; + power-domains = <&k3_pds 360 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 360 0>; + assigned-clock-parents = <&k3_clks 360 4>; + /* reserved for GPU */ + status = "reserved"; + }; + + watchdog9: watchdog@2300000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2300000 0x00 0x100>; + clocks = <&k3_clks 356 0>; + power-domains = <&k3_pds 356 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 356 0>; + assigned-clock-parents = <&k3_clks 356 4>; + /* reserved for C7X_0 DSP */ + status = "reserved"; + }; + + watchdog10: watchdog@2310000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2310000 0x00 0x100>; + clocks = <&k3_clks 357 0>; + power-domains = <&k3_pds 357 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 357 0>; + assigned-clock-parents = <&k3_clks 357 4>; + /* reserved for C7X_1 DSP */ + status = "reserved"; + }; + + watchdog11: watchdog@2320000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2320000 0x00 0x100>; + clocks = <&k3_clks 358 0>; + power-domains = <&k3_pds 358 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 358 0>; + assigned-clock-parents = <&k3_clks 358 4>; + /* reserved for C7X_2 DSP */ + status = "reserved"; + }; + + watchdog12: watchdog@2330000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2330000 0x00 0x100>; + clocks = <&k3_clks 359 0>; + power-domains = <&k3_pds 359 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 359 0>; + assigned-clock-parents = <&k3_clks 359 4>; + /* reserved for C7X_3 DSP */ + status = "reserved"; + }; + + watchdog13: watchdog@23c0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23c0000 0x00 0x100>; + clocks = <&k3_clks 361 0>; + power-domains = <&k3_pds 361 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 361 0>; + assigned-clock-parents = <&k3_clks 361 4>; + /* reserved for MAIN_R5F0_0 */ + status = "reserved"; + }; + + watchdog14: watchdog@23d0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23d0000 0x00 0x100>; + clocks = <&k3_clks 362 0>; + power-domains = <&k3_pds 362 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 362 0>; + assigned-clock-parents = <&k3_clks 362 4>; + /* reserved for MAIN_R5F0_1 */ + status = "reserved"; + }; + + watchdog15: watchdog@23e0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23e0000 0x00 0x100>; + clocks = <&k3_clks 363 0>; + power-domains = <&k3_pds 363 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 363 0>; + assigned-clock-parents = <&k3_clks 363 4>; + /* reserved for MAIN_R5F1_0 */ + status = "reserved"; + }; + + watchdog16: watchdog@23f0000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x23f0000 0x00 0x100>; + clocks = <&k3_clks 364 0>; + power-domains = <&k3_pds 364 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 364 0>; + assigned-clock-parents = <&k3_clks 364 4>; + /* reserved for MAIN_R5F1_1 */ + status = "reserved"; + }; + + watchdog17: watchdog@2540000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2540000 0x00 0x100>; + clocks = <&k3_clks 365 0>; + power-domains = <&k3_pds 365 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 365 0>; + assigned-clock-parents = <&k3_clks 366 4>; + /* reserved for MAIN_R5F2_0 */ + status = "reserved"; + }; + + watchdog18: watchdog@2550000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x2550000 0x00 0x100>; + clocks = <&k3_clks 366 0>; + power-domains = <&k3_pds 366 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 366 0>; + assigned-clock-parents = <&k3_clks 366 4>; + /* reserved for MAIN_R5F2_1 */ + status = "reserved"; + }; + + mhdp: bridge@a000000 { + compatible = "ti,j721e-mhdp8546"; + reg = <0x0 0xa000000 0x0 0x30a00>, + <0x0 0x4f40000 0x0 0x20>; + reg-names = "mhdptx", "j721e-intg"; + clocks = <&k3_clks 217 11>; + interrupt-parent = <&gic500>; + interrupts = ; + power-domains = <&k3_pds 217 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + + dp0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + /* Remote-endpoints are on the boards so + * ports are defined in the platform dt file. + */ + }; + }; + + dss: dss@4a00000 { + compatible = "ti,j721e-dss"; + reg = <0x00 0x04a00000 0x00 0x10000>, /* common_m */ + <0x00 0x04a10000 0x00 0x10000>, /* common_s0*/ + <0x00 0x04b00000 0x00 0x10000>, /* common_s1*/ + <0x00 0x04b10000 0x00 0x10000>, /* common_s2*/ + <0x00 0x04a20000 0x00 0x10000>, /* vidl1 */ + <0x00 0x04a30000 0x00 0x10000>, /* vidl2 */ + <0x00 0x04a50000 0x00 0x10000>, /* vid1 */ + <0x00 0x04a60000 0x00 0x10000>, /* vid2 */ + <0x00 0x04a70000 0x00 0x10000>, /* ovr1 */ + <0x00 0x04a90000 0x00 0x10000>, /* ovr2 */ + <0x00 0x04ab0000 0x00 0x10000>, /* ovr3 */ + <0x00 0x04ad0000 0x00 0x10000>, /* ovr4 */ + <0x00 0x04a80000 0x00 0x10000>, /* vp1 */ + <0x00 0x04aa0000 0x00 0x10000>, /* vp1 */ + <0x00 0x04ac0000 0x00 0x10000>, /* vp1 */ + <0x00 0x04ae0000 0x00 0x10000>, /* vp4 */ + <0x00 0x04af0000 0x00 0x10000>; /* wb */ + reg-names = "common_m", "common_s0", + "common_s1", "common_s2", + "vidl1", "vidl2","vid1","vid2", + "ovr1", "ovr2", "ovr3", "ovr4", + "vp1", "vp2", "vp3", "vp4", + "wb"; + clocks = <&k3_clks 218 0>, + <&k3_clks 218 2>, + <&k3_clks 218 5>, + <&k3_clks 218 14>, + <&k3_clks 218 18>; + clock-names = "fck", "vp1", "vp2", "vp3", "vp4"; + power-domains = <&k3_pds 218 TI_SCI_PD_EXCLUSIVE>; + interrupts = , + , + , + ; + interrupt-names = "common_m", + "common_s0", + "common_s1", + "common_s2"; + status = "disabled"; + + dss_ports: ports { + /* Ports that DSS drives are platform specific + * so they are defined in platform dt file. + */ + }; + }; + + mcasp0: mcasp@2b00000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b00000 0x00 0x2000>, + <0x00 0x02b08000 0x00 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc400>, <&main_udmap 0x4400>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 265 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 265 0>; + assigned-clock-parents = <&k3_clks 265 1>; + power-domains = <&k3_pds 265 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp1: mcasp@2b10000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b10000 0x00 0x2000>, + <0x00 0x02b18000 0x00 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc401>, <&main_udmap 0x4401>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 266 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 266 0>; + assigned-clock-parents = <&k3_clks 266 1>; + power-domains = <&k3_pds 266 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp2: mcasp@2b20000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b20000 0x00 0x2000>, + <0x00 0x02b28000 0x00 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc402>, <&main_udmap 0x4402>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 267 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 267 0>; + assigned-clock-parents = <&k3_clks 267 1>; + power-domains = <&k3_pds 267 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp3: mcasp@2b30000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b30000 0x00 0x2000>, + <0x00 0x02b38000 0x00 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc403>, <&main_udmap 0x4403>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 268 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 268 0>; + assigned-clock-parents = <&k3_clks 268 1>; + power-domains = <&k3_pds 268 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcasp4: mcasp@2b40000 { + compatible = "ti,am33xx-mcasp-audio"; + reg = <0x00 0x02b40000 0x00 0x2000>, + <0x00 0x02b48000 0x00 0x1000>; + reg-names = "mpu","dat"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + dmas = <&main_udmap 0xc404>, <&main_udmap 0x4404>; + dma-names = "tx", "rx"; + clocks = <&k3_clks 269 0>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 269 0>; + assigned-clock-parents = <&k3_clks 269 1>; + power-domains = <&k3_pds 269 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-mcu-wakeup-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-mcu-wakeup-common.dtsi new file mode 100644 index 00000000000000..9638130caece5c --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-mcu-wakeup-common.dtsi @@ -0,0 +1,762 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Device Tree Source for J784S4 and J742S2 SoC Family MCU/WAKEUP Domain peripherals + * + * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +&cbass_mcu_wakeup { + sms: system-controller@44083000 { + compatible = "ti,k2g-sci"; + ti,host-id = <12>; + + mbox-names = "rx", "tx"; + + mboxes = <&secure_proxy_main 11>, + <&secure_proxy_main 13>; + + reg-names = "debug_messages"; + reg = <0x00 0x44083000 0x00 0x1000>; + + k3_pds: power-controller { + bootph-all; + compatible = "ti,sci-pm-domain"; + #power-domain-cells = <2>; + }; + + k3_clks: clock-controller { + bootph-all; + compatible = "ti,k2g-sci-clk"; + #clock-cells = <2>; + }; + + k3_reset: reset-controller { + bootph-all; + compatible = "ti,sci-reset"; + #reset-cells = <2>; + }; + }; + + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + bootph-all; + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; + }; + + secure_proxy_sa3: mailbox@43600000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x43600000 0x00 0x10000>, + <0x00 0x44880000 0x00 0x20000>, + <0x00 0x44860000 0x00 0x20000>; + bootph-pre-ram; + + /* + * Marked Disabled: + * Node is incomplete as it is meant for bootloaders and + * firmware on non-MPU processors + */ + status = "disabled"; + }; + + mcu_ram: sram@41c00000 { + compatible = "mmio-sram"; + reg = <0x00 0x41c00000 0x00 0x100000>; + ranges = <0x00 0x00 0x41c00000 0x100000>; + #address-cells = <1>; + #size-cells = <1>; + }; + + wkup_pmx0: pinctrl@4301c000 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x4301c000 0x00 0x034>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + wkup_pmx1: pinctrl@4301c038 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x4301c038 0x00 0x02c>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + wkup_pmx2: pinctrl@4301c068 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x4301c068 0x00 0x120>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + wkup_pmx3: pinctrl@4301c190 { + compatible = "pinctrl-single"; + /* Proxy 0 addressing */ + reg = <0x00 0x4301c190 0x00 0x004>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0xffffffff>; + }; + + wkup_gpio_intr: interrupt-controller@42200000 { + compatible = "ti,sci-intr"; + reg = <0x00 0x42200000 0x00 0x400>; + ti,intr-trigger-type = <1>; + interrupt-controller; + interrupt-parent = <&gic500>; + #interrupt-cells = <1>; + ti,sci = <&sms>; + ti,sci-dev-id = <177>; + ti,interrupt-ranges = <16 960 16>; + }; + + /* MCU_TIMERIO pad input CTRLMMR_MCU_TIMER*_CTRL registers */ + mcu_timerio_input: pinctrl@40f04200 { + compatible = "pinctrl-single"; + reg = <0x00 0x40f04200 0x00 0x28>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x0000000f>; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + /* MCU_TIMERIO pad output CTRLMMR_MCU_TIMERIO*_CTRL registers */ + mcu_timerio_output: pinctrl@40f04280 { + compatible = "pinctrl-single"; + reg = <0x00 0x40f04280 0x00 0x28>; + #pinctrl-cells = <1>; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x0000000f>; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_conf: bus@40f00000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x40f00000 0x20000>; + + cpsw_mac_syscon: ethernet-mac-syscon@200 { + compatible = "ti,am62p-cpsw-mac-efuse", "syscon"; + reg = <0x200 0x8>; + }; + + phy_gmii_sel: phy@4040 { + compatible = "ti,am654-phy-gmii-sel"; + reg = <0x4040 0x4>; + #phy-cells = <1>; + }; + }; + + mcu_timer0: timer@40400000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40400000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 35 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 35 2>; + assigned-clock-parents = <&k3_clks 35 3>; + power-domains = <&k3_pds 35 TI_SCI_PD_EXCLUSIVE>; + bootph-all; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer1: timer@40410000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40410000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 117 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 117 2>; + assigned-clock-parents = <&k3_clks 117 3>; + power-domains = <&k3_pds 117 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer2: timer@40420000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40420000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 118 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 118 2>; + assigned-clock-parents = <&k3_clks 118 3>; + power-domains = <&k3_pds 118 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer3: timer@40430000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40430000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 119 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 119 2>; + assigned-clock-parents = <&k3_clks 119 3>; + power-domains = <&k3_pds 119 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer4: timer@40440000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40440000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 120 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 120 2>; + assigned-clock-parents = <&k3_clks 120 3>; + power-domains = <&k3_pds 120 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer5: timer@40450000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40450000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 121 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 121 2>; + assigned-clock-parents = <&k3_clks 121 3>; + power-domains = <&k3_pds 121 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer6: timer@40460000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40460000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 122 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 122 2>; + assigned-clock-parents = <&k3_clks 122 3>; + power-domains = <&k3_pds 122 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer7: timer@40470000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40470000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 123 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 123 2>; + assigned-clock-parents = <&k3_clks 123 3>; + power-domains = <&k3_pds 123 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer8: timer@40480000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40480000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 124 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 124 2>; + assigned-clock-parents = <&k3_clks 124 3>; + power-domains = <&k3_pds 124 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + mcu_timer9: timer@40490000 { + compatible = "ti,am654-timer"; + reg = <0x00 0x40490000 0x00 0x400>; + interrupts = ; + clocks = <&k3_clks 125 2>; + clock-names = "fck"; + assigned-clocks = <&k3_clks 125 2>; + assigned-clock-parents = <&k3_clks 125 3>; + power-domains = <&k3_pds 125 TI_SCI_PD_EXCLUSIVE>; + ti,timer-pwm; + /* Non-MPU Firmware usage */ + status = "reserved"; + }; + + wkup_uart0: serial@42300000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x42300000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 397 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 397 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcu_uart0: serial@40a00000 { + compatible = "ti,j721e-uart", "ti,am654-uart"; + reg = <0x00 0x40a00000 0x00 0x200>; + interrupts = ; + clocks = <&k3_clks 149 0>; + clock-names = "fclk"; + power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + wkup_gpio0: gpio@42110000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x00 0x42110000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&wkup_gpio_intr>; + interrupts = <103>, <104>, <105>, <106>, <107>, <108>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <89>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 167 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 167 0>; + clock-names = "gpio"; + status = "disabled"; + }; + + wkup_gpio1: gpio@42100000 { + compatible = "ti,j721e-gpio", "ti,keystone-gpio"; + reg = <0x00 0x42100000 0x00 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&wkup_gpio_intr>; + interrupts = <112>, <113>, <114>, <115>, <116>, <117>; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <89>; + ti,davinci-gpio-unbanked = <0>; + power-domains = <&k3_pds 168 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 168 0>; + clock-names = "gpio"; + status = "disabled"; + }; + + wkup_i2c0: i2c@42120000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x42120000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 279 2>; + clock-names = "fck"; + power-domains = <&k3_pds 279 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcu_i2c0: i2c@40b00000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x40b00000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 277 2>; + clock-names = "fck"; + power-domains = <&k3_pds 277 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcu_i2c1: i2c@40b10000 { + compatible = "ti,j721e-i2c", "ti,omap4-i2c"; + reg = <0x00 0x40b10000 0x00 0x100>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 278 2>; + clock-names = "fck"; + power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + + mcu_mcan0: can@40528000 { + compatible = "bosch,m_can"; + reg = <0x00 0x40528000 0x00 0x200>, + <0x00 0x40500000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 263 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 263 6>, <&k3_clks 263 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + mcu_mcan1: can@40568000 { + compatible = "bosch,m_can"; + reg = <0x00 0x40568000 0x00 0x200>, + <0x00 0x40540000 0x00 0x8000>; + reg-names = "m_can", "message_ram"; + power-domains = <&k3_pds 264 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 264 6>, <&k3_clks 264 1>; + clock-names = "hclk", "cclk"; + interrupts = , + ; + interrupt-names = "int0", "int1"; + bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; + status = "disabled"; + }; + + mcu_spi0: spi@40300000 { + compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; + reg = <0x00 0x040300000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 384 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 384 0>; + status = "disabled"; + }; + + mcu_spi1: spi@40310000 { + compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; + reg = <0x00 0x040310000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 385 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 385 0>; + status = "disabled"; + }; + + mcu_spi2: spi@40320000 { + compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; + reg = <0x00 0x040320000 0x00 0x400>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + power-domains = <&k3_pds 386 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 386 0>; + status = "disabled"; + }; + + mcu_navss: bus@28380000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>; + ti,sci-dev-id = <323>; + dma-coherent; + dma-ranges; + + mcu_ringacc: ringacc@2b800000 { + bootph-all; + compatible = "ti,am654-navss-ringacc"; + reg = <0x00 0x2b800000 0x00 0x400000>, + <0x00 0x2b000000 0x00 0x400000>, + <0x00 0x28590000 0x00 0x100>, + <0x00 0x2a500000 0x00 0x40000>, + <0x00 0x28440000 0x00 0x40000>; + reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg"; + ti,num-rings = <286>; + ti,sci-rm-range-gp-rings = <0x1>; + ti,sci = <&sms>; + ti,sci-dev-id = <328>; + msi-parent = <&main_udmass_inta>; + }; + + mcu_udmap: dma-controller@285c0000 { + bootph-all; + compatible = "ti,j721e-navss-mcu-udmap"; + reg = <0x00 0x285c0000 0x00 0x100>, + <0x00 0x2a800000 0x00 0x40000>, + <0x00 0x2aa00000 0x00 0x40000>, + <0x00 0x284a0000 0x00 0x4000>, + <0x00 0x284c0000 0x00 0x4000>, + <0x00 0x28400000 0x00 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; + msi-parent = <&main_udmass_inta>; + #dma-cells = <1>; + + ti,sci = <&sms>; + ti,sci-dev-id = <329>; + ti,ringacc = <&mcu_ringacc>; + ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */ + <0x0f>; /* TX_HCHAN */ + ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */ + <0x0b>; /* RX_HCHAN */ + ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ + }; + }; + + secure_proxy_mcu: mailbox@2a480000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x00 0x2a480000 0x00 0x80000>, + <0x00 0x2a380000 0x00 0x80000>, + <0x00 0x2a400000 0x00 0x80000>; + bootph-pre-ram; + + /* + * Marked Disabled: + * Node is incomplete as it is meant for bootloaders and + * firmware on non-MPU processors + */ + status = "disabled"; + }; + + mcu_cpsw: ethernet@46000000 { + compatible = "ti,j721e-cpsw-nuss"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x00 0x46000000 0x00 0x200000>; + reg-names = "cpsw_nuss"; + ranges = <0x00 0x00 0x00 0x46000000 0x00 0x200000>; + dma-coherent; + clocks = <&k3_clks 63 0>; + clock-names = "fck"; + power-domains = <&k3_pds 63 TI_SCI_PD_EXCLUSIVE>; + + dmas = <&mcu_udmap 0xf000>, + <&mcu_udmap 0xf001>, + <&mcu_udmap 0xf002>, + <&mcu_udmap 0xf003>, + <&mcu_udmap 0xf004>, + <&mcu_udmap 0xf005>, + <&mcu_udmap 0xf006>, + <&mcu_udmap 0xf007>, + <&mcu_udmap 0x7000>; + dma-names = "tx0", "tx1", "tx2", "tx3", + "tx4", "tx5", "tx6", "tx7", + "rx"; + status = "disabled"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + mcu_cpsw_port1: port@1 { + reg = <1>; + ti,mac-only; + label = "port1"; + ti,syscon-efuse = <&cpsw_mac_syscon 0x0>; + phys = <&phy_gmii_sel 1>; + }; + }; + + davinci_mdio: mdio@f00 { + compatible = "ti,cpsw-mdio","ti,davinci_mdio"; + reg = <0x00 0xf00 0x00 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&k3_clks 63 0>; + clock-names = "fck"; + bus_freq = <1000000>; + }; + + cpts@3d000 { + compatible = "ti,am65-cpts"; + reg = <0x00 0x3d000 0x00 0x400>; + clocks = <&k3_clks 63 3>; + clock-names = "cpts"; + assigned-clocks = <&k3_clks 63 3>; /* CPTS_RFT_CLK */ + assigned-clock-parents = <&k3_clks 63 5>; /* MAIN_0_HSDIV6_CLK */ + interrupts-extended = <&gic500 GIC_SPI 858 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpts"; + ti,cpts-ext-ts-inputs = <4>; + ti,cpts-periodic-outputs = <2>; + }; + }; + + mcu_r5fss0: r5fss@41000000 { + compatible = "ti,j721s2-r5fss"; + ti,cluster-mode = <1>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x41000000 0x00 0x41000000 0x20000>, + <0x41400000 0x00 0x41400000 0x20000>; + power-domains = <&k3_pds 345 TI_SCI_PD_EXCLUSIVE>; + + mcu_r5fss0_core0: r5f@41000000 { + compatible = "ti,j721s2-r5f"; + reg = <0x41000000 0x00010000>, + <0x41010000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <346>; + ti,sci-proc-ids = <0x01 0xff>; + resets = <&k3_reset 346 1>; + firmware-name = "j784s4-mcu-r5f0_0-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + + mcu_r5fss0_core1: r5f@41400000 { + compatible = "ti,j721s2-r5f"; + reg = <0x41400000 0x00010000>, + <0x41410000 0x00010000>; + reg-names = "atcm", "btcm"; + ti,sci = <&sms>; + ti,sci-dev-id = <347>; + ti,sci-proc-ids = <0x02 0xff>; + resets = <&k3_reset 347 1>; + firmware-name = "j784s4-mcu-r5f0_1-fw"; + ti,atcm-enable = <1>; + ti,btcm-enable = <1>; + ti,loczrama = <1>; + }; + }; + + wkup_vtm0: temperature-sensor@42040000 { + compatible = "ti,j7200-vtm"; + reg = <0x00 0x42040000 0x00 0x350>, + <0x00 0x42050000 0x00 0x350>; + power-domains = <&k3_pds 243 TI_SCI_PD_SHARED>; + #thermal-sensor-cells = <1>; + bootph-pre-ram; + }; + + tscadc0: tscadc@40200000 { + compatible = "ti,am3359-tscadc"; + reg = <0x00 0x40200000 0x00 0x1000>; + interrupts = ; + power-domains = <&k3_pds 0 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 0 0>; + assigned-clocks = <&k3_clks 0 2>; + assigned-clock-rates = <60000000>; + clock-names = "fck"; + dmas = <&main_udmap 0x7400>, + <&main_udmap 0x7401>; + dma-names = "fifo0", "fifo1"; + status = "disabled"; + + adc { + #io-channel-cells = <1>; + compatible = "ti,am3359-adc"; + }; + }; + + tscadc1: tscadc@40210000 { + compatible = "ti,am3359-tscadc"; + reg = <0x00 0x40210000 0x00 0x1000>; + interrupts = ; + power-domains = <&k3_pds 1 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 1 0>; + assigned-clocks = <&k3_clks 1 2>; + assigned-clock-rates = <60000000>; + clock-names = "fck"; + dmas = <&main_udmap 0x7402>, + <&main_udmap 0x7403>; + dma-names = "fifo0", "fifo1"; + status = "disabled"; + + adc { + #io-channel-cells = <1>; + compatible = "ti,am3359-adc"; + }; + }; + + fss: bus@47000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x00 0x47000000 0x00 0x47000000 0x00 0x00000100>, /* FSS Control */ + <0x00 0x47040000 0x00 0x47040000 0x00 0x00000100>, /* OSPI0 Control */ + <0x00 0x47050000 0x00 0x47050000 0x00 0x00000100>, /* OSPI1 Control */ + <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, /* FSS data region 1 */ + <0x04 0x00000000 0x04 0x00000000 0x04 0x00000000>; /* FSS data region 0/3 */ + + ospi0: spi@47040000 { + compatible = "ti,am654-ospi", "cdns,qspi-nor"; + reg = <0x00 0x47040000 0x00 0x100>, + <0x05 0x00000000 0x01 0x00000000>; + interrupts = ; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x0>; + clocks = <&k3_clks 161 7>; + assigned-clocks = <&k3_clks 161 7>; + assigned-clock-parents = <&k3_clks 161 9>; + assigned-clock-rates = <166666666>; + power-domains = <&k3_pds 161 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + ospi1: spi@47050000 { + compatible = "ti,am654-ospi", "cdns,qspi-nor"; + reg = <0x00 0x47050000 0x00 0x100>, + <0x07 0x00000000 0x01 0x00000000>; + interrupts = ; + cdns,fifo-depth = <256>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x0>; + clocks = <&k3_clks 162 7>; + power-domains = <&k3_pds 162 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; + + mcu_esm: esm@40800000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x40800000 0x00 0x1000>; + ti,esm-pins = <95>; + bootph-pre-ram; + }; + + wkup_esm: esm@42080000 { + compatible = "ti,j721e-esm"; + reg = <0x00 0x42080000 0x00 0x1000>; + ti,esm-pins = <63>; + bootph-pre-ram; + }; + + /* + * The 2 RTI instances are couple with MCU R5Fs so keeping them + * reserved as these will be used by their respective firmware + */ + mcu_watchdog0: watchdog@40600000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x40600000 0x00 0x100>; + clocks = <&k3_clks 367 1>; + power-domains = <&k3_pds 367 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 367 0>; + assigned-clock-parents = <&k3_clks 367 4>; + /* reserved for MCU_R5F0_0 */ + status = "reserved"; + }; + + mcu_watchdog1: watchdog@40610000 { + compatible = "ti,j7-rti-wdt"; + reg = <0x00 0x40610000 0x00 0x100>; + clocks = <&k3_clks 368 1>; + power-domains = <&k3_pds 368 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 368 0>; + assigned-clock-parents = <&k3_clks 368 4>; + /* reserved for MCU_R5F0_1 */ + status = "reserved"; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-thermal-common.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-thermal-common.dtsi new file mode 100644 index 00000000000000..e3ef61c1658f4b --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j784s4-j742s2-thermal-common.dtsi @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include + +wkup0_thermal: wkup0-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <500>; /* milliseconds */ + thermal-sensors = <&wkup_vtm0 0>; + + trips { + wkup0_crit: wkup0-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; +}; + +wkup1_thermal: wkup1-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <500>; /* milliseconds */ + thermal-sensors = <&wkup_vtm0 1>; + + trips { + wkup1_crit: wkup1-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; +}; + +main0_thermal: main0-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <500>; /* milliseconds */ + thermal-sensors = <&wkup_vtm0 2>; + + trips { + main0_crit: main0-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; +}; + +main1_thermal: main1-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <500>; /* milliseconds */ + thermal-sensors = <&wkup_vtm0 3>; + + trips { + main1_crit: main1-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; +}; + +main2_thermal: main2-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <500>; /* milliseconds */ + thermal-sensors = <&wkup_vtm0 4>; + + trips { + main2_crit: main2-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; +}; + +main3_thermal: main3-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <500>; /* milliseconds */ + thermal-sensors = <&wkup_vtm0 5>; + + trips { + main3_crit: main3-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; +}; + +main4_thermal: main4-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <500>; /* milliseconds */ + thermal-sensors = <&wkup_vtm0 6>; + + trips { + main4_crit: main4-crit { + temperature = <125000>; /* milliCelsius */ + hysteresis = <2000>; /* milliCelsius */ + type = "critical"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi index e73bb750b09ad5..0160fe0da98388 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi @@ -5,2781 +5,124 @@ * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ */ -#include -#include -#include - -#include "k3-serdes.h" - -/ { - serdes_refclk: clock-serdes { - #clock-cells = <0>; - compatible = "fixed-clock"; - /* To be enabled when serdes_wiz* is functional */ - status = "disabled"; - }; -}; - -&cbass_main { - msmc_ram: sram@70000000 { - compatible = "mmio-sram"; - reg = <0x00 0x70000000 0x00 0x800000>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x00 0x00 0x70000000 0x800000>; - - atf-sram@0 { - reg = <0x00 0x20000>; - }; - - tifs-sram@1f0000 { - reg = <0x1f0000 0x10000>; - }; - - l3cache-sram@200000 { - reg = <0x200000 0x200000>; - }; - }; - - scm_conf: bus@100000 { - compatible = "simple-bus"; - reg = <0x00 0x00100000 0x00 0x1c000>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x00 0x00 0x00100000 0x1c000>; - - cpsw1_phy_gmii_sel: phy@4034 { - compatible = "ti,am654-phy-gmii-sel"; - reg = <0x4034 0x4>; - #phy-cells = <1>; - }; - - cpsw0_phy_gmii_sel: phy@4044 { - compatible = "ti,j784s4-cpsw9g-phy-gmii-sel"; - reg = <0x4044 0x20>; - #phy-cells = <1>; - ti,qsgmii-main-ports = <7>, <7>; - }; - - pcie0_ctrl: pcie0-ctrl@4070 { - compatible = "ti,j784s4-pcie-ctrl", "syscon"; - reg = <0x4070 0x4>; - }; - - pcie1_ctrl: pcie1-ctrl@4074 { - compatible = "ti,j784s4-pcie-ctrl", "syscon"; - reg = <0x4074 0x4>; - }; - - pcie2_ctrl: pcie2-ctrl@4078 { - compatible = "ti,j784s4-pcie-ctrl", "syscon"; - reg = <0x4078 0x4>; - }; - - pcie3_ctrl: pcie3-ctrl@407c { - compatible = "ti,j784s4-pcie-ctrl", "syscon"; - reg = <0x407c 0x4>; - }; - - serdes_ln_ctrl: mux-controller@4080 { - compatible = "reg-mux"; - reg = <0x00004080 0x30>; - #mux-control-cells = <1>; - mux-reg-masks = <0x0 0x3>, <0x4 0x3>, /* SERDES0 lane0/1 select */ - <0x8 0x3>, <0xc 0x3>, /* SERDES0 lane2/3 select */ - <0x10 0x3>, <0x14 0x3>, /* SERDES1 lane0/1 select */ - <0x18 0x3>, <0x1c 0x3>, /* SERDES1 lane2/3 select */ - <0x20 0x3>, <0x24 0x3>, /* SERDES2 lane0/1 select */ - <0x28 0x3>, <0x2c 0x3>; /* SERDES2 lane2/3 select */ - idle-states = , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; - }; - - usb_serdes_mux: mux-controller@4000 { - compatible = "reg-mux"; - reg = <0x4000 0x4>; - #mux-control-cells = <1>; - mux-reg-masks = <0x0 0x8000000>; /* USB0 to SERDES0 lane 3 mux */ - }; - - ehrpwm_tbclk: clock-controller@4140 { - compatible = "ti,am654-ehrpwm-tbclk"; - reg = <0x4140 0x18>; - #clock-cells = <1>; - }; - - audio_refclk1: clock@82e4 { - compatible = "ti,am62-audio-refclk"; - reg = <0x82e4 0x4>; - clocks = <&k3_clks 157 34>; - assigned-clocks = <&k3_clks 157 34>; - assigned-clock-parents = <&k3_clks 157 63>; - #clock-cells = <0>; - }; - }; - - main_ehrpwm0: pwm@3000000 { - compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; - reg = <0x00 0x3000000 0x00 0x100>; - clocks = <&ehrpwm_tbclk 0>, <&k3_clks 219 0>; - clock-names = "tbclk", "fck"; - power-domains = <&k3_pds 219 TI_SCI_PD_EXCLUSIVE>; - #pwm-cells = <3>; - status = "disabled"; - }; - - main_ehrpwm1: pwm@3010000 { - compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; - reg = <0x00 0x3010000 0x00 0x100>; - clocks = <&ehrpwm_tbclk 1>, <&k3_clks 220 0>; - clock-names = "tbclk", "fck"; - power-domains = <&k3_pds 220 TI_SCI_PD_EXCLUSIVE>; - #pwm-cells = <3>; - status = "disabled"; - }; - - main_ehrpwm2: pwm@3020000 { - compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; - reg = <0x00 0x3020000 0x00 0x100>; - clocks = <&ehrpwm_tbclk 2>, <&k3_clks 221 0>; - clock-names = "tbclk", "fck"; - power-domains = <&k3_pds 221 TI_SCI_PD_EXCLUSIVE>; - #pwm-cells = <3>; - status = "disabled"; - }; - - main_ehrpwm3: pwm@3030000 { - compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; - reg = <0x00 0x3030000 0x00 0x100>; - clocks = <&ehrpwm_tbclk 3>, <&k3_clks 222 0>; - clock-names = "tbclk", "fck"; - power-domains = <&k3_pds 222 TI_SCI_PD_EXCLUSIVE>; - #pwm-cells = <3>; - status = "disabled"; - }; - - main_ehrpwm4: pwm@3040000 { - compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; - reg = <0x00 0x3040000 0x00 0x100>; - clocks = <&ehrpwm_tbclk 4>, <&k3_clks 223 0>; - clock-names = "tbclk", "fck"; - power-domains = <&k3_pds 223 TI_SCI_PD_EXCLUSIVE>; - #pwm-cells = <3>; - status = "disabled"; - }; - - main_ehrpwm5: pwm@3050000 { - compatible = "ti,am654-ehrpwm", "ti,am3352-ehrpwm"; - reg = <0x00 0x3050000 0x00 0x100>; - clocks = <&ehrpwm_tbclk 5>, <&k3_clks 224 0>; - clock-names = "tbclk", "fck"; - power-domains = <&k3_pds 224 TI_SCI_PD_EXCLUSIVE>; - #pwm-cells = <3>; - status = "disabled"; - }; - - gic500: interrupt-controller@1800000 { - compatible = "arm,gic-v3"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - #interrupt-cells = <3>; - interrupt-controller; - reg = <0x00 0x01800000 0x00 0x200000>, /* GICD */ - <0x00 0x01900000 0x00 0x100000>, /* GICR */ - <0x00 0x6f000000 0x00 0x2000>, /* GICC */ - <0x00 0x6f010000 0x00 0x1000>, /* GICH */ - <0x00 0x6f020000 0x00 0x2000>; /* GICV */ - - /* vcpumntirq: virtual CPU interface maintenance interrupt */ - interrupts = ; - - gic_its: msi-controller@1820000 { - compatible = "arm,gic-v3-its"; - reg = <0x00 0x01820000 0x00 0x10000>; - socionext,synquacer-pre-its = <0x1000000 0x400000>; - msi-controller; - #msi-cells = <1>; - }; - }; - - main_gpio_intr: interrupt-controller@a00000 { - compatible = "ti,sci-intr"; - reg = <0x00 0x00a00000 0x00 0x800>; - ti,intr-trigger-type = <1>; - interrupt-controller; - interrupt-parent = <&gic500>; - #interrupt-cells = <1>; - ti,sci = <&sms>; - ti,sci-dev-id = <10>; - ti,interrupt-ranges = <8 392 56>; - }; - - main_pmx0: pinctrl@11c000 { - compatible = "pinctrl-single"; - /* Proxy 0 addressing */ - reg = <0x00 0x11c000 0x00 0x120>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0xffffffff>; - }; - - /* TIMERIO pad input CTRLMMR_TIMER*_CTRL registers */ - main_timerio_input: pinctrl@104200 { - compatible = "pinctrl-single"; - reg = <0x00 0x104200 0x00 0x50>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0x00000007>; - }; - - /* TIMERIO pad output CTCTRLMMR_TIMERIO*_CTRL registers */ - main_timerio_output: pinctrl@104280 { - compatible = "pinctrl-single"; - reg = <0x00 0x104280 0x00 0x20>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0x0000001f>; - }; - - main_crypto: crypto@4e00000 { - compatible = "ti,j721e-sa2ul"; - reg = <0x00 0x4e00000 0x00 0x1200>; - power-domains = <&k3_pds 369 TI_SCI_PD_EXCLUSIVE>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x00 0x04e00000 0x00 0x04e00000 0x00 0x30000>; - - dmas = <&main_udmap 0xca40>, <&main_udmap 0x4a40>, - <&main_udmap 0x4a41>; - dma-names = "tx", "rx1", "rx2"; - - rng: rng@4e10000 { - compatible = "inside-secure,safexcel-eip76"; - reg = <0x00 0x4e10000 0x00 0x7d>; - interrupts = ; - }; - }; - - main_timer0: timer@2400000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2400000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 97 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 97 2>; - assigned-clock-parents = <&k3_clks 97 3>; - power-domains = <&k3_pds 97 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer1: timer@2410000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2410000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 98 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 98 2>; - assigned-clock-parents = <&k3_clks 98 3>; - power-domains = <&k3_pds 98 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer2: timer@2420000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2420000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 99 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 99 2>; - assigned-clock-parents = <&k3_clks 99 3>; - power-domains = <&k3_pds 99 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer3: timer@2430000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2430000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 100 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 100 2>; - assigned-clock-parents = <&k3_clks 100 3>; - power-domains = <&k3_pds 100 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer4: timer@2440000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2440000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 101 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 101 2>; - assigned-clock-parents = <&k3_clks 101 3>; - power-domains = <&k3_pds 101 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer5: timer@2450000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2450000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 102 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 102 2>; - assigned-clock-parents = <&k3_clks 102 3>; - power-domains = <&k3_pds 102 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer6: timer@2460000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2460000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 103 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 103 2>; - assigned-clock-parents = <&k3_clks 103 3>; - power-domains = <&k3_pds 103 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer7: timer@2470000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2470000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 104 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 104 2>; - assigned-clock-parents = <&k3_clks 104 3>; - power-domains = <&k3_pds 104 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer8: timer@2480000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2480000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 105 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 105 2>; - assigned-clock-parents = <&k3_clks 105 3>; - power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer9: timer@2490000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2490000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 106 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 106 2>; - assigned-clock-parents = <&k3_clks 106 3>; - power-domains = <&k3_pds 106 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer10: timer@24a0000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x24a0000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 107 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 107 2>; - assigned-clock-parents = <&k3_clks 107 3>; - power-domains = <&k3_pds 107 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer11: timer@24b0000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x24b0000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 108 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 108 2>; - assigned-clock-parents = <&k3_clks 108 3>; - power-domains = <&k3_pds 108 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer12: timer@24c0000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x24c0000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 109 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 109 2>; - assigned-clock-parents = <&k3_clks 109 3>; - power-domains = <&k3_pds 109 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer13: timer@24d0000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x24d0000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 110 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 110 2>; - assigned-clock-parents = <&k3_clks 110 3>; - power-domains = <&k3_pds 110 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer14: timer@24e0000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x24e0000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 111 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 111 2>; - assigned-clock-parents = <&k3_clks 111 3>; - power-domains = <&k3_pds 111 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer15: timer@24f0000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x24f0000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 112 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 112 2>; - assigned-clock-parents = <&k3_clks 112 3>; - power-domains = <&k3_pds 112 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer16: timer@2500000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2500000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 113 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 113 2>; - assigned-clock-parents = <&k3_clks 113 3>; - power-domains = <&k3_pds 113 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer17: timer@2510000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2510000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 114 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 114 2>; - assigned-clock-parents = <&k3_clks 114 3>; - power-domains = <&k3_pds 114 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer18: timer@2520000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2520000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 115 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 115 2>; - assigned-clock-parents = <&k3_clks 115 3>; - power-domains = <&k3_pds 115 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_timer19: timer@2530000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x2530000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 116 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 116 2>; - assigned-clock-parents = <&k3_clks 116 3>; - power-domains = <&k3_pds 116 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - }; - - main_uart0: serial@2800000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02800000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 146 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 146 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart1: serial@2810000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02810000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 388 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 388 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart2: serial@2820000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02820000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 389 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 389 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart3: serial@2830000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02830000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 390 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 390 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart4: serial@2840000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02840000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 391 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 391 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart5: serial@2850000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02850000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 392 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 392 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart6: serial@2860000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02860000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 393 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 393 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart7: serial@2870000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02870000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 394 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 394 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart8: serial@2880000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02880000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 395 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 395 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_uart9: serial@2890000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x02890000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 396 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 396 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_gpio0: gpio@600000 { - compatible = "ti,j721e-gpio", "ti,keystone-gpio"; - reg = <0x00 0x00600000 0x00 0x100>; - gpio-controller; - #gpio-cells = <2>; - interrupt-parent = <&main_gpio_intr>; - interrupts = <145>, <146>, <147>, <148>, <149>; - interrupt-controller; - #interrupt-cells = <2>; - ti,ngpio = <66>; - ti,davinci-gpio-unbanked = <0>; - power-domains = <&k3_pds 163 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 163 0>; - clock-names = "gpio"; - status = "disabled"; - }; - - main_gpio2: gpio@610000 { - compatible = "ti,j721e-gpio", "ti,keystone-gpio"; - reg = <0x00 0x00610000 0x00 0x100>; - gpio-controller; - #gpio-cells = <2>; - interrupt-parent = <&main_gpio_intr>; - interrupts = <154>, <155>, <156>, <157>, <158>; - interrupt-controller; - #interrupt-cells = <2>; - ti,ngpio = <66>; - ti,davinci-gpio-unbanked = <0>; - power-domains = <&k3_pds 164 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 164 0>; - clock-names = "gpio"; - status = "disabled"; - }; - - main_gpio4: gpio@620000 { - compatible = "ti,j721e-gpio", "ti,keystone-gpio"; - reg = <0x00 0x00620000 0x00 0x100>; - gpio-controller; - #gpio-cells = <2>; - interrupt-parent = <&main_gpio_intr>; - interrupts = <163>, <164>, <165>, <166>, <167>; - interrupt-controller; - #interrupt-cells = <2>; - ti,ngpio = <66>; - ti,davinci-gpio-unbanked = <0>; - power-domains = <&k3_pds 165 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 165 0>; - clock-names = "gpio"; - status = "disabled"; - }; - - main_gpio6: gpio@630000 { - compatible = "ti,j721e-gpio", "ti,keystone-gpio"; - reg = <0x00 0x00630000 0x00 0x100>; - gpio-controller; - #gpio-cells = <2>; - interrupt-parent = <&main_gpio_intr>; - interrupts = <172>, <173>, <174>, <175>, <176>; - interrupt-controller; - #interrupt-cells = <2>; - ti,ngpio = <66>; - ti,davinci-gpio-unbanked = <0>; - power-domains = <&k3_pds 166 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 166 0>; - clock-names = "gpio"; - status = "disabled"; - }; - - usbss0: usb@4104000 { - bootph-all; - compatible = "ti,j721e-usb"; - reg = <0x00 0x4104000 0x00 0x100>; - dma-coherent; - power-domains = <&k3_pds 398 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 398 21>, <&k3_clks 398 2>; - clock-names = "ref", "lpm"; - assigned-clocks = <&k3_clks 398 21>; /* USB2_REFCLK */ - assigned-clock-parents = <&k3_clks 398 22>; /* HFOSC0 */ - #address-cells = <2>; - #size-cells = <2>; - ranges; - - status = "disabled"; /* Needs lane config */ - - usb0: usb@6000000 { - bootph-all; - compatible = "cdns,usb3"; - reg = <0x00 0x6000000 0x00 0x10000>, - <0x00 0x6010000 0x00 0x10000>, - <0x00 0x6020000 0x00 0x10000>; - reg-names = "otg", "xhci", "dev"; - interrupts = , /* irq.0 */ - , /* irq.6 */ - ; /* otgirq.0 */ - interrupt-names = "host", - "peripheral", - "otg"; - }; - }; - - main_i2c0: i2c@2000000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x02000000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 270 2>; - clock-names = "fck"; - power-domains = <&k3_pds 270 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_i2c1: i2c@2010000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x02010000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 271 2>; - clock-names = "fck"; - power-domains = <&k3_pds 271 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_i2c2: i2c@2020000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x02020000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 272 2>; - clock-names = "fck"; - power-domains = <&k3_pds 272 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_i2c3: i2c@2030000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x02030000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 273 2>; - clock-names = "fck"; - power-domains = <&k3_pds 273 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_i2c4: i2c@2040000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x02040000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 274 2>; - clock-names = "fck"; - power-domains = <&k3_pds 274 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_i2c5: i2c@2050000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x02050000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 275 2>; - clock-names = "fck"; - power-domains = <&k3_pds 275 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - main_i2c6: i2c@2060000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x02060000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 276 2>; - clock-names = "fck"; - power-domains = <&k3_pds 276 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - ti_csi2rx0: ticsi2rx@4500000 { - compatible = "ti,j721e-csi2rx-shim"; - reg = <0x00 0x04500000 0x00 0x00001000>; - ranges; - #address-cells = <2>; - #size-cells = <2>; - dmas = <&main_bcdma_csi 0 0x4940 0>; - dma-names = "rx0"; - power-domains = <&k3_pds 72 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - - cdns_csi2rx0: csi-bridge@4504000 { - compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; - reg = <0x00 0x04504000 0x00 0x00001000>; - clocks = <&k3_clks 72 2>, <&k3_clks 72 0>, <&k3_clks 72 2>, - <&k3_clks 72 2>, <&k3_clks 72 3>, <&k3_clks 72 3>; - clock-names = "sys_clk", "p_clk", "pixel_if0_clk", - "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; - phys = <&dphy0>; - phy-names = "dphy"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - csi0_port0: port@0 { - reg = <0>; - status = "disabled"; - }; - - csi0_port1: port@1 { - reg = <1>; - status = "disabled"; - }; - - csi0_port2: port@2 { - reg = <2>; - status = "disabled"; - }; - - csi0_port3: port@3 { - reg = <3>; - status = "disabled"; - }; - - csi0_port4: port@4 { - reg = <4>; - status = "disabled"; - }; - }; - }; - }; - - ti_csi2rx1: ticsi2rx@4510000 { - compatible = "ti,j721e-csi2rx-shim"; - reg = <0x00 0x04510000 0x00 0x1000>; - ranges; - #address-cells = <2>; - #size-cells = <2>; - dmas = <&main_bcdma_csi 0 0x4960 0>; - dma-names = "rx0"; - power-domains = <&k3_pds 73 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - - cdns_csi2rx1: csi-bridge@4514000 { - compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; - reg = <0x00 0x04514000 0x00 0x00001000>; - clocks = <&k3_clks 73 2>, <&k3_clks 73 0>, <&k3_clks 73 2>, - <&k3_clks 73 2>, <&k3_clks 73 3>, <&k3_clks 73 3>; - clock-names = "sys_clk", "p_clk", "pixel_if0_clk", - "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; - phys = <&dphy1>; - phy-names = "dphy"; - ports { - #address-cells = <1>; - #size-cells = <0>; - - csi1_port0: port@0 { - reg = <0>; - status = "disabled"; - }; - - csi1_port1: port@1 { - reg = <1>; - status = "disabled"; - }; - - csi1_port2: port@2 { - reg = <2>; - status = "disabled"; - }; - - csi1_port3: port@3 { - reg = <3>; - status = "disabled"; - }; - - csi1_port4: port@4 { - reg = <4>; - status = "disabled"; - }; - }; - }; - }; - - ti_csi2rx2: ticsi2rx@4520000 { - compatible = "ti,j721e-csi2rx-shim"; - reg = <0x00 0x04520000 0x00 0x00001000>; - ranges; - #address-cells = <2>; - #size-cells = <2>; - dmas = <&main_bcdma_csi 0 0x4980 0>; - dma-names = "rx0"; - power-domains = <&k3_pds 74 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - - cdns_csi2rx2: csi-bridge@4524000 { - compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; - reg = <0x00 0x04524000 0x00 0x00001000>; - clocks = <&k3_clks 74 2>, <&k3_clks 74 0>, <&k3_clks 74 2>, - <&k3_clks 74 2>, <&k3_clks 74 3>, <&k3_clks 74 3>; - clock-names = "sys_clk", "p_clk", "pixel_if0_clk", - "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; - phys = <&dphy2>; - phy-names = "dphy"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - csi2_port0: port@0 { - reg = <0>; - status = "disabled"; - }; - - csi2_port1: port@1 { - reg = <1>; - status = "disabled"; - }; - - csi2_port2: port@2 { - reg = <2>; - status = "disabled"; - }; - - csi2_port3: port@3 { - reg = <3>; - status = "disabled"; - }; - - csi2_port4: port@4 { - reg = <4>; - status = "disabled"; - }; - }; - }; - }; - - dphy0: phy@4580000 { - compatible = "cdns,dphy-rx"; - reg = <0x00 0x04580000 0x00 0x00001100>; - #phy-cells = <0>; - power-domains = <&k3_pds 212 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - dphy1: phy@4590000 { - compatible = "cdns,dphy-rx"; - reg = <0x00 0x04590000 0x00 0x00001100>; - #phy-cells = <0>; - power-domains = <&k3_pds 213 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - dphy2: phy@45a0000 { - compatible = "cdns,dphy-rx"; - reg = <0x00 0x045a0000 0x00 0x00001100>; - #phy-cells = <0>; - power-domains = <&k3_pds 214 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - vpu0: video-codec@4210000 { - compatible = "ti,j721s2-wave521c", "cnm,wave521c"; - reg = <0x00 0x4210000 0x00 0x10000>; - interrupts = ; - clocks = <&k3_clks 241 2>; - power-domains = <&k3_pds 241 TI_SCI_PD_EXCLUSIVE>; - }; - - vpu1: video-codec@4220000 { - compatible = "ti,j721s2-wave521c", "cnm,wave521c"; - reg = <0x00 0x4220000 0x00 0x10000>; - interrupts = ; - clocks = <&k3_clks 242 2>; - power-domains = <&k3_pds 242 TI_SCI_PD_EXCLUSIVE>; - }; - - main_sdhci0: mmc@4f80000 { - compatible = "ti,j721e-sdhci-8bit"; - reg = <0x00 0x04f80000 0x00 0x1000>, - <0x00 0x04f88000 0x00 0x400>; - interrupts = ; - power-domains = <&k3_pds 140 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 140 1>, <&k3_clks 140 2>; - clock-names = "clk_ahb", "clk_xin"; - assigned-clocks = <&k3_clks 140 2>; - assigned-clock-parents = <&k3_clks 140 3>; - bus-width = <8>; - ti,otap-del-sel-legacy = <0x0>; - ti,otap-del-sel-mmc-hs = <0x0>; - ti,otap-del-sel-ddr52 = <0x6>; - ti,otap-del-sel-hs200 = <0x8>; - ti,otap-del-sel-hs400 = <0x5>; - ti,itap-del-sel-legacy = <0x10>; - ti,itap-del-sel-mmc-hs = <0xa>; - ti,strobe-sel = <0x77>; - ti,clkbuf-sel = <0x7>; - ti,trm-icp = <0x8>; - mmc-ddr-1_8v; - mmc-hs200-1_8v; - mmc-hs400-1_8v; - dma-coherent; - status = "disabled"; - }; - - main_sdhci1: mmc@4fb0000 { - compatible = "ti,j721e-sdhci-4bit"; - reg = <0x00 0x04fb0000 0x00 0x1000>, - <0x00 0x04fb8000 0x00 0x400>; - interrupts = ; - power-domains = <&k3_pds 141 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 141 3>, <&k3_clks 141 4>; - clock-names = "clk_ahb", "clk_xin"; - assigned-clocks = <&k3_clks 141 4>; - assigned-clock-parents = <&k3_clks 141 5>; - bus-width = <4>; - ti,otap-del-sel-legacy = <0x0>; - ti,otap-del-sel-sd-hs = <0x0>; - ti,otap-del-sel-sdr12 = <0xf>; - ti,otap-del-sel-sdr25 = <0xf>; - ti,otap-del-sel-sdr50 = <0xc>; - ti,otap-del-sel-sdr104 = <0x5>; - ti,otap-del-sel-ddr50 = <0xc>; - ti,itap-del-sel-legacy = <0x0>; - ti,itap-del-sel-sd-hs = <0x0>; - ti,itap-del-sel-sdr12 = <0x0>; - ti,itap-del-sel-sdr25 = <0x0>; - ti,itap-del-sel-ddr50 = <0x2>; - ti,clkbuf-sel = <0x7>; - ti,trm-icp = <0x8>; - dma-coherent; - status = "disabled"; - }; - - pcie0_rc: pcie@2900000 { - compatible = "ti,j784s4-pcie-host"; - reg = <0x00 0x02900000 0x00 0x1000>, - <0x00 0x02907000 0x00 0x400>, - <0x00 0x0d000000 0x00 0x00800000>, - <0x00 0x10000000 0x00 0x00001000>; - reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; - interrupt-names = "link_state"; - interrupts = ; - device_type = "pci"; - ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x0>; - max-link-speed = <3>; - num-lanes = <4>; - power-domains = <&k3_pds 332 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 332 0>; - clock-names = "fck"; - #address-cells = <3>; - #size-cells = <2>; - bus-range = <0x0 0xff>; - vendor-id = <0x104c>; - device-id = <0xb012>; - msi-map = <0x0 &gic_its 0x0 0x10000>; - dma-coherent; - ranges = <0x01000000 0x0 0x10001000 0x0 0x10001000 0x0 0x0010000>, - <0x02000000 0x0 0x10011000 0x0 0x10011000 0x0 0x7fef000>; - dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; - status = "disabled"; - }; - - pcie1_rc: pcie@2910000 { - compatible = "ti,j784s4-pcie-host"; - reg = <0x00 0x02910000 0x00 0x1000>, - <0x00 0x02917000 0x00 0x400>, - <0x00 0x0d800000 0x00 0x00800000>, - <0x00 0x18000000 0x00 0x00001000>; - reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; - interrupt-names = "link_state"; - interrupts = ; - device_type = "pci"; - ti,syscon-pcie-ctrl = <&pcie1_ctrl 0x0>; - max-link-speed = <3>; - num-lanes = <4>; - power-domains = <&k3_pds 333 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 333 0>; - clock-names = "fck"; - #address-cells = <3>; - #size-cells = <2>; - bus-range = <0x0 0xff>; - vendor-id = <0x104c>; - device-id = <0xb012>; - msi-map = <0x0 &gic_its 0x10000 0x10000>; - dma-coherent; - ranges = <0x01000000 0x0 0x18001000 0x00 0x18001000 0x0 0x0010000>, - <0x02000000 0x0 0x18011000 0x00 0x18011000 0x0 0x7fef000>; - dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; - status = "disabled"; - }; - - pcie2_rc: pcie@2920000 { - compatible = "ti,j784s4-pcie-host"; - reg = <0x00 0x02920000 0x00 0x1000>, - <0x00 0x02927000 0x00 0x400>, - <0x00 0x0e000000 0x00 0x00800000>, - <0x44 0x00000000 0x00 0x00001000>; - reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; - interrupt-names = "link_state"; - interrupts = ; - device_type = "pci"; - ti,syscon-pcie-ctrl = <&pcie2_ctrl 0x0>; - max-link-speed = <3>; - num-lanes = <2>; - power-domains = <&k3_pds 334 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 334 0>; - clock-names = "fck"; - #address-cells = <3>; - #size-cells = <2>; - bus-range = <0x0 0xff>; - vendor-id = <0x104c>; - device-id = <0xb012>; - msi-map = <0x0 &gic_its 0x20000 0x10000>; - dma-coherent; - ranges = <0x01000000 0x0 0x00001000 0x44 0x00001000 0x0 0x0010000>, - <0x02000000 0x0 0x00011000 0x44 0x00011000 0x0 0x7fef000>; - dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; - status = "disabled"; - }; - - pcie3_rc: pcie@2930000 { - compatible = "ti,j784s4-pcie-host"; - reg = <0x00 0x02930000 0x00 0x1000>, - <0x00 0x02937000 0x00 0x400>, - <0x00 0x0e800000 0x00 0x00800000>, - <0x44 0x10000000 0x00 0x00001000>; - reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; - interrupt-names = "link_state"; - interrupts = ; - device_type = "pci"; - ti,syscon-pcie-ctrl = <&pcie3_ctrl 0x0>; - max-link-speed = <3>; - num-lanes = <2>; - power-domains = <&k3_pds 335 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 335 0>; - clock-names = "fck"; - #address-cells = <3>; - #size-cells = <2>; - bus-range = <0x0 0xff>; - vendor-id = <0x104c>; - device-id = <0xb012>; - msi-map = <0x0 &gic_its 0x30000 0x10000>; - dma-coherent; - ranges = <0x01000000 0x0 0x00001000 0x44 0x10001000 0x0 0x0010000>, - <0x02000000 0x0 0x00011000 0x44 0x10011000 0x0 0x7fef000>; - dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; - status = "disabled"; - }; - - serdes_wiz0: wiz@5060000 { - compatible = "ti,j784s4-wiz-10g"; - #address-cells = <1>; - #size-cells = <1>; - power-domains = <&k3_pds 404 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 404 2>, <&k3_clks 404 6>, <&serdes_refclk>, <&k3_clks 404 5>; - clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; - assigned-clocks = <&k3_clks 404 6>; - assigned-clock-parents = <&k3_clks 404 10>; - num-lanes = <4>; - #reset-cells = <1>; - #clock-cells = <1>; - ranges = <0x5060000 0x00 0x5060000 0x10000>; - status = "disabled"; - - serdes0: serdes@5060000 { - compatible = "ti,j721e-serdes-10g"; - reg = <0x05060000 0x010000>; - reg-names = "torrent_phy"; - resets = <&serdes_wiz0 0>; - reset-names = "torrent_reset"; - clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, - <&serdes_wiz0 TI_WIZ_PHY_EN_REFCLK>; - clock-names = "refclk", "phy_en_refclk"; - assigned-clocks = <&serdes_wiz0 TI_WIZ_PLL0_REFCLK>, - <&serdes_wiz0 TI_WIZ_PLL1_REFCLK>, - <&serdes_wiz0 TI_WIZ_REFCLK_DIG>; - assigned-clock-parents = <&k3_clks 404 6>, - <&k3_clks 404 6>, - <&k3_clks 404 6>; - #address-cells = <1>; - #size-cells = <0>; - #clock-cells = <1>; - status = "disabled"; - }; - }; - - serdes_wiz1: wiz@5070000 { - compatible = "ti,j784s4-wiz-10g"; - #address-cells = <1>; - #size-cells = <1>; - power-domains = <&k3_pds 405 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 405 2>, <&k3_clks 405 6>, <&serdes_refclk>, <&k3_clks 405 5>; - clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; - assigned-clocks = <&k3_clks 405 6>; - assigned-clock-parents = <&k3_clks 405 10>; - num-lanes = <4>; - #reset-cells = <1>; - #clock-cells = <1>; - ranges = <0x05070000 0x00 0x05070000 0x10000>; - status = "disabled"; - - serdes1: serdes@5070000 { - compatible = "ti,j721e-serdes-10g"; - reg = <0x05070000 0x010000>; - reg-names = "torrent_phy"; - resets = <&serdes_wiz1 0>; - reset-names = "torrent_reset"; - clocks = <&serdes_wiz1 TI_WIZ_PLL0_REFCLK>, - <&serdes_wiz1 TI_WIZ_PHY_EN_REFCLK>; - clock-names = "refclk", "phy_en_refclk"; - assigned-clocks = <&serdes_wiz1 TI_WIZ_PLL0_REFCLK>, - <&serdes_wiz1 TI_WIZ_PLL1_REFCLK>, - <&serdes_wiz1 TI_WIZ_REFCLK_DIG>; - assigned-clock-parents = <&k3_clks 405 6>, - <&k3_clks 405 6>, - <&k3_clks 405 6>; - #address-cells = <1>; - #size-cells = <0>; - #clock-cells = <1>; - status = "disabled"; - }; - }; - - serdes_wiz2: wiz@5020000 { - compatible = "ti,j784s4-wiz-10g"; - #address-cells = <1>; - #size-cells = <1>; - power-domains = <&k3_pds 406 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 406 2>, <&k3_clks 406 6>, <&serdes_refclk>, <&k3_clks 406 5>; - clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; - assigned-clocks = <&k3_clks 406 6>; - assigned-clock-parents = <&k3_clks 406 10>; - num-lanes = <4>; - #reset-cells = <1>; - #clock-cells = <1>; - ranges = <0x05020000 0x00 0x05020000 0x10000>; - status = "disabled"; - - serdes2: serdes@5020000 { - compatible = "ti,j721e-serdes-10g"; - reg = <0x05020000 0x010000>; - reg-names = "torrent_phy"; - resets = <&serdes_wiz2 0>; - reset-names = "torrent_reset"; - clocks = <&serdes_wiz2 TI_WIZ_PLL0_REFCLK>, - <&serdes_wiz2 TI_WIZ_PHY_EN_REFCLK>; - clock-names = "refclk", "phy_en_refclk"; - assigned-clocks = <&serdes_wiz2 TI_WIZ_PLL0_REFCLK>, - <&serdes_wiz2 TI_WIZ_PLL1_REFCLK>, - <&serdes_wiz2 TI_WIZ_REFCLK_DIG>; - assigned-clock-parents = <&k3_clks 406 6>, - <&k3_clks 406 6>, - <&k3_clks 406 6>; - #address-cells = <1>; - #size-cells = <0>; - #clock-cells = <1>; - status = "disabled"; - }; - }; - - serdes_wiz4: wiz@5050000 { - compatible = "ti,j784s4-wiz-10g"; - #address-cells = <1>; - #size-cells = <1>; - power-domains = <&k3_pds 407 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 407 2>, <&k3_clks 407 6>, <&serdes_refclk>, <&k3_clks 407 5>; - clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; - assigned-clocks = <&k3_clks 407 6>; - assigned-clock-parents = <&k3_clks 407 10>; - num-lanes = <4>; - #reset-cells = <1>; - #clock-cells = <1>; - ranges = <0x05050000 0x00 0x05050000 0x10000>, - <0xa030a00 0x00 0xa030a00 0x40>; /* DPTX PHY */ - status = "disabled"; - - serdes4: serdes@5050000 { - /* - * Note: we also map DPTX PHY registers as the Torrent - * needs to manage those. - */ - compatible = "ti,j721e-serdes-10g"; - reg = <0x05050000 0x010000>, - <0x0a030a00 0x40>; /* DPTX PHY */ - reg-names = "torrent_phy"; - resets = <&serdes_wiz4 0>; - reset-names = "torrent_reset"; - clocks = <&serdes_wiz4 TI_WIZ_PLL0_REFCLK>, - <&serdes_wiz4 TI_WIZ_PHY_EN_REFCLK>; - clock-names = "refclk", "phy_en_refclk"; - assigned-clocks = <&serdes_wiz4 TI_WIZ_PLL0_REFCLK>, - <&serdes_wiz4 TI_WIZ_PLL1_REFCLK>, - <&serdes_wiz4 TI_WIZ_REFCLK_DIG>; - assigned-clock-parents = <&k3_clks 407 6>, - <&k3_clks 407 6>, - <&k3_clks 407 6>; - #address-cells = <1>; - #size-cells = <0>; - #clock-cells = <1>; - status = "disabled"; - }; - }; - - main_navss: bus@30000000 { - bootph-all; - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>; - ti,sci-dev-id = <280>; - dma-coherent; - dma-ranges; - - main_navss_intr: interrupt-controller@310e0000 { - compatible = "ti,sci-intr"; - reg = <0x00 0x310e0000 0x00 0x4000>; - ti,intr-trigger-type = <4>; - interrupt-controller; - interrupt-parent = <&gic500>; - #interrupt-cells = <1>; - ti,sci = <&sms>; - ti,sci-dev-id = <283>; - ti,interrupt-ranges = <0 64 64>, - <64 448 64>, - <128 672 64>; - }; - - main_udmass_inta: msi-controller@33d00000 { - compatible = "ti,sci-inta"; - reg = <0x00 0x33d00000 0x00 0x100000>; - interrupt-controller; - #interrupt-cells = <0>; - interrupt-parent = <&main_navss_intr>; - msi-controller; - ti,sci = <&sms>; - ti,sci-dev-id = <321>; - ti,interrupt-ranges = <0 0 256>; - ti,unmapped-event-sources = <&main_bcdma_csi>; - }; - - secure_proxy_main: mailbox@32c00000 { - bootph-all; - compatible = "ti,am654-secure-proxy"; - #mbox-cells = <1>; - reg-names = "target_data", "rt", "scfg"; - reg = <0x00 0x32c00000 0x00 0x100000>, - <0x00 0x32400000 0x00 0x100000>, - <0x00 0x32800000 0x00 0x100000>; - interrupt-names = "rx_011"; - interrupts = ; - }; - - hwspinlock: hwlock@30e00000 { - compatible = "ti,am654-hwspinlock"; - reg = <0x00 0x30e00000 0x00 0x1000>; - #hwlock-cells = <1>; - }; - - mailbox0_cluster0: mailbox@31f80000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f80000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster1: mailbox@31f81000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f81000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster2: mailbox@31f82000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f82000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster3: mailbox@31f83000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f83000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster4: mailbox@31f84000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f84000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster5: mailbox@31f85000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f85000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster6: mailbox@31f86000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f86000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster7: mailbox@31f87000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f87000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster8: mailbox@31f88000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f88000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster9: mailbox@31f89000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f89000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster10: mailbox@31f8a000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f8a000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox0_cluster11: mailbox@31f8b000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f8b000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster0: mailbox@31f90000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f90000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster1: mailbox@31f91000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f91000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster2: mailbox@31f92000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f92000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster3: mailbox@31f93000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f93000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster4: mailbox@31f94000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f94000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster5: mailbox@31f95000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f95000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster6: mailbox@31f96000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f96000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster7: mailbox@31f97000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f97000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster8: mailbox@31f98000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f98000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster9: mailbox@31f99000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f99000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster10: mailbox@31f9a000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f9a000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - mailbox1_cluster11: mailbox@31f9b000 { - compatible = "ti,am654-mailbox"; - reg = <0x00 0x31f9b000 0x00 0x200>; - #mbox-cells = <1>; - ti,mbox-num-users = <4>; - ti,mbox-num-fifos = <16>; - interrupt-parent = <&main_navss_intr>; - status = "disabled"; - }; - - main_ringacc: ringacc@3c000000 { - compatible = "ti,am654-navss-ringacc"; - reg = <0x00 0x3c000000 0x00 0x400000>, - <0x00 0x38000000 0x00 0x400000>, - <0x00 0x31120000 0x00 0x100>, - <0x00 0x33000000 0x00 0x40000>, - <0x00 0x31080000 0x00 0x40000>; - reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg"; - ti,num-rings = <1024>; - ti,sci-rm-range-gp-rings = <0x1>; - ti,sci = <&sms>; - ti,sci-dev-id = <315>; - msi-parent = <&main_udmass_inta>; - }; - - main_udmap: dma-controller@31150000 { - compatible = "ti,j721e-navss-main-udmap"; - reg = <0x00 0x31150000 0x00 0x100>, - <0x00 0x34000000 0x00 0x80000>, - <0x00 0x35000000 0x00 0x200000>, - <0x00 0x30b00000 0x00 0x20000>, - <0x00 0x30c00000 0x00 0x8000>, - <0x00 0x30d00000 0x00 0x4000>; - reg-names = "gcfg", "rchanrt", "tchanrt", - "tchan", "rchan", "rflow"; - msi-parent = <&main_udmass_inta>; - #dma-cells = <1>; - - ti,sci = <&sms>; - ti,sci-dev-id = <319>; - ti,ringacc = <&main_ringacc>; - - ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */ - <0x0f>, /* TX_HCHAN */ - <0x10>; /* TX_UHCHAN */ - ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */ - <0x0b>, /* RX_HCHAN */ - <0x0c>; /* RX_UHCHAN */ - ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ - }; - - main_bcdma_csi: dma-controller@311a0000 { - compatible = "ti,j721s2-dmss-bcdma-csi"; - reg = <0x00 0x311a0000 0x00 0x100>, - <0x00 0x35d00000 0x00 0x20000>, - <0x00 0x35c00000 0x00 0x10000>, - <0x00 0x35e00000 0x00 0x80000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; - msi-parent = <&main_udmass_inta>; - #dma-cells = <3>; - ti,sci = <&sms>; - ti,sci-dev-id = <281>; - ti,sci-rm-range-rchan = <0x21>; - ti,sci-rm-range-tchan = <0x22>; - }; - - cpts@310d0000 { - compatible = "ti,j721e-cpts"; - reg = <0x00 0x310d0000 0x00 0x400>; - reg-names = "cpts"; - clocks = <&k3_clks 282 0>; - clock-names = "cpts"; - assigned-clocks = <&k3_clks 62 3>; /* CPTS_RFT_CLK */ - assigned-clock-parents = <&k3_clks 62 5>; /* MAIN_0_HSDIV6_CLK */ - interrupts-extended = <&main_navss_intr 391>; - interrupt-names = "cpts"; - ti,cpts-periodic-outputs = <6>; - ti,cpts-ext-ts-inputs = <8>; - }; - }; - - main_cpsw0: ethernet@c000000 { - compatible = "ti,j784s4-cpswxg-nuss"; - reg = <0x00 0xc000000 0x00 0x200000>; - reg-names = "cpsw_nuss"; - ranges = <0x00 0x00 0x00 0xc000000 0x00 0x200000>; - #address-cells = <2>; - #size-cells = <2>; - dma-coherent; - clocks = <&k3_clks 64 0>; - clock-names = "fck"; - power-domains = <&k3_pds 64 TI_SCI_PD_EXCLUSIVE>; - - dmas = <&main_udmap 0xca00>, - <&main_udmap 0xca01>, - <&main_udmap 0xca02>, - <&main_udmap 0xca03>, - <&main_udmap 0xca04>, - <&main_udmap 0xca05>, - <&main_udmap 0xca06>, - <&main_udmap 0xca07>, - <&main_udmap 0x4a00>; - dma-names = "tx0", "tx1", "tx2", "tx3", - "tx4", "tx5", "tx6", "tx7", - "rx"; - - status = "disabled"; - - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - - main_cpsw0_port1: port@1 { - reg = <1>; - label = "port1"; - ti,mac-only; - status = "disabled"; - }; - - main_cpsw0_port2: port@2 { - reg = <2>; - label = "port2"; - ti,mac-only; - status = "disabled"; - }; - - main_cpsw0_port3: port@3 { - reg = <3>; - label = "port3"; - ti,mac-only; - status = "disabled"; - }; - - main_cpsw0_port4: port@4 { - reg = <4>; - label = "port4"; - ti,mac-only; - status = "disabled"; - }; - - main_cpsw0_port5: port@5 { - reg = <5>; - label = "port5"; - ti,mac-only; - status = "disabled"; - }; - - main_cpsw0_port6: port@6 { - reg = <6>; - label = "port6"; - ti,mac-only; - status = "disabled"; - }; - - main_cpsw0_port7: port@7 { - reg = <7>; - label = "port7"; - ti,mac-only; - status = "disabled"; - }; - - main_cpsw0_port8: port@8 { - reg = <8>; - label = "port8"; - ti,mac-only; - status = "disabled"; - }; - }; - - main_cpsw0_mdio: mdio@f00 { - compatible = "ti,cpsw-mdio","ti,davinci_mdio"; - reg = <0x00 0xf00 0x00 0x100>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 64 0>; - clock-names = "fck"; - bus_freq = <1000000>; - status = "disabled"; - }; - - cpts@3d000 { - compatible = "ti,am65-cpts"; - reg = <0x00 0x3d000 0x00 0x400>; - clocks = <&k3_clks 64 3>; - clock-names = "cpts"; - interrupts-extended = <&gic500 GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "cpts"; - ti,cpts-ext-ts-inputs = <4>; - ti,cpts-periodic-outputs = <2>; - }; - }; - - main_cpsw1: ethernet@c200000 { - compatible = "ti,j721e-cpsw-nuss"; - reg = <0x00 0xc200000 0x00 0x200000>; - reg-names = "cpsw_nuss"; - ranges = <0x00 0x00 0x00 0xc200000 0x00 0x200000>; - #address-cells = <2>; - #size-cells = <2>; - dma-coherent; - clocks = <&k3_clks 62 0>; - clock-names = "fck"; - power-domains = <&k3_pds 62 TI_SCI_PD_EXCLUSIVE>; - - dmas = <&main_udmap 0xc640>, - <&main_udmap 0xc641>, - <&main_udmap 0xc642>, - <&main_udmap 0xc643>, - <&main_udmap 0xc644>, - <&main_udmap 0xc645>, - <&main_udmap 0xc646>, - <&main_udmap 0xc647>, - <&main_udmap 0x4640>; - dma-names = "tx0", "tx1", "tx2", "tx3", - "tx4", "tx5", "tx6", "tx7", - "rx"; - - status = "disabled"; - - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - - main_cpsw1_port1: port@1 { - reg = <1>; - label = "port1"; - phys = <&cpsw1_phy_gmii_sel 1>; - ti,mac-only; - status = "disabled"; - }; - }; - - main_cpsw1_mdio: mdio@f00 { - compatible = "ti,cpsw-mdio", "ti,davinci_mdio"; - reg = <0x00 0xf00 0x00 0x100>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 62 0>; - clock-names = "fck"; - bus_freq = <1000000>; - status = "disabled"; - }; - - cpts@3d000 { - compatible = "ti,am65-cpts"; - reg = <0x00 0x3d000 0x00 0x400>; - clocks = <&k3_clks 62 3>; - clock-names = "cpts"; - interrupts-extended = <&gic500 GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "cpts"; - ti,cpts-ext-ts-inputs = <4>; - ti,cpts-periodic-outputs = <2>; - }; - }; - - main_mcan0: can@2701000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02701000 0x00 0x200>, - <0x00 0x02708000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 245 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 245 6>, <&k3_clks 245 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan1: can@2711000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02711000 0x00 0x200>, - <0x00 0x02718000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 246 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 246 6>, <&k3_clks 246 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan2: can@2721000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02721000 0x00 0x200>, - <0x00 0x02728000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 247 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 247 6>, <&k3_clks 247 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan3: can@2731000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02731000 0x00 0x200>, - <0x00 0x02738000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 248 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 248 6>, <&k3_clks 248 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan4: can@2741000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02741000 0x00 0x200>, - <0x00 0x02748000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 249 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 249 6>, <&k3_clks 249 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan5: can@2751000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02751000 0x00 0x200>, - <0x00 0x02758000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 250 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 250 6>, <&k3_clks 250 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan6: can@2761000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02761000 0x00 0x200>, - <0x00 0x02768000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 251 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 251 6>, <&k3_clks 251 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan7: can@2771000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02771000 0x00 0x200>, - <0x00 0x02778000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 252 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 252 6>, <&k3_clks 252 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan8: can@2781000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02781000 0x00 0x200>, - <0x00 0x02788000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 253 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 253 6>, <&k3_clks 253 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan9: can@2791000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02791000 0x00 0x200>, - <0x00 0x02798000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 254 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 254 6>, <&k3_clks 254 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan10: can@27a1000 { - compatible = "bosch,m_can"; - reg = <0x00 0x027a1000 0x00 0x200>, - <0x00 0x027a8000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 255 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 255 6>, <&k3_clks 255 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan11: can@27b1000 { - compatible = "bosch,m_can"; - reg = <0x00 0x027b1000 0x00 0x200>, - <0x00 0x027b8000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 256 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 256 6>, <&k3_clks 256 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan12: can@27c1000 { - compatible = "bosch,m_can"; - reg = <0x00 0x027c1000 0x00 0x200>, - <0x00 0x027c8000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 257 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 257 6>, <&k3_clks 257 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan13: can@27d1000 { - compatible = "bosch,m_can"; - reg = <0x00 0x027d1000 0x00 0x200>, - <0x00 0x027d8000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 258 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 258 6>, <&k3_clks 258 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan14: can@2681000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02681000 0x00 0x200>, - <0x00 0x02688000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 259 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 259 6>, <&k3_clks 259 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan15: can@2691000 { - compatible = "bosch,m_can"; - reg = <0x00 0x02691000 0x00 0x200>, - <0x00 0x02698000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 260 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 260 6>, <&k3_clks 260 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan16: can@26a1000 { - compatible = "bosch,m_can"; - reg = <0x00 0x026a1000 0x00 0x200>, - <0x00 0x026a8000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 261 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 261 6>, <&k3_clks 261 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_mcan17: can@26b1000 { - compatible = "bosch,m_can"; - reg = <0x00 0x026b1000 0x00 0x200>, - <0x00 0x026b8000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 262 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 262 6>, <&k3_clks 262 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - main_spi0: spi@2100000 { - compatible = "ti,am654-mcspi","ti,omap4-mcspi"; - reg = <0x00 0x02100000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 376 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 376 1>; - status = "disabled"; - }; - - main_spi1: spi@2110000 { - compatible = "ti,am654-mcspi","ti,omap4-mcspi"; - reg = <0x00 0x02110000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 377 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 377 1>; - status = "disabled"; - }; - - main_spi2: spi@2120000 { - compatible = "ti,am654-mcspi","ti,omap4-mcspi"; - reg = <0x00 0x02120000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 378 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 378 1>; - status = "disabled"; - }; - - main_spi3: spi@2130000 { - compatible = "ti,am654-mcspi","ti,omap4-mcspi"; - reg = <0x00 0x02130000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 379 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 379 1>; - status = "disabled"; - }; - - main_spi4: spi@2140000 { - compatible = "ti,am654-mcspi","ti,omap4-mcspi"; - reg = <0x00 0x02140000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 380 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 380 1>; - status = "disabled"; - }; - - main_spi5: spi@2150000 { - compatible = "ti,am654-mcspi","ti,omap4-mcspi"; - reg = <0x00 0x02150000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 381 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 381 1>; - status = "disabled"; - }; - - main_spi6: spi@2160000 { - compatible = "ti,am654-mcspi","ti,omap4-mcspi"; - reg = <0x00 0x02160000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 382 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 382 1>; - status = "disabled"; - }; - - main_spi7: spi@2170000 { - compatible = "ti,am654-mcspi","ti,omap4-mcspi"; - reg = <0x00 0x02170000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 383 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 383 1>; - status = "disabled"; - }; - - ufs_wrapper: ufs-wrapper@4e80000 { - compatible = "ti,j721e-ufs"; - reg = <0x00 0x4e80000 0x00 0x100>; - power-domains = <&k3_pds 387 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 387 3>; - assigned-clocks = <&k3_clks 387 3>; - assigned-clock-parents = <&k3_clks 387 6>; - ranges; - #address-cells = <2>; - #size-cells = <2>; - status = "disabled"; - - ufs@4e84000 { - compatible = "cdns,ufshc-m31-16nm", "jedec,ufs-2.0"; - reg = <0x00 0x4e84000 0x00 0x10000>; - interrupts = ; - freq-table-hz = <250000000 250000000>, <19200000 19200000>, - <19200000 19200000>; - clocks = <&k3_clks 387 1>, <&k3_clks 387 3>, <&k3_clks 387 3>; - clock-names = "core_clk", "phy_clk", "ref_clk"; - dma-coherent; - }; - }; - - main_r5fss0: r5fss@5c00000 { - compatible = "ti,j721s2-r5fss"; - ti,cluster-mode = <1>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x5c00000 0x00 0x5c00000 0x20000>, - <0x5d00000 0x00 0x5d00000 0x20000>; - power-domains = <&k3_pds 336 TI_SCI_PD_EXCLUSIVE>; - - main_r5fss0_core0: r5f@5c00000 { - compatible = "ti,j721s2-r5f"; - reg = <0x5c00000 0x00010000>, - <0x5c10000 0x00010000>; - reg-names = "atcm", "btcm"; - ti,sci = <&sms>; - ti,sci-dev-id = <339>; - ti,sci-proc-ids = <0x06 0xff>; - resets = <&k3_reset 339 1>; - firmware-name = "j784s4-main-r5f0_0-fw"; - ti,atcm-enable = <1>; - ti,btcm-enable = <1>; - ti,loczrama = <1>; - }; - - main_r5fss0_core1: r5f@5d00000 { - compatible = "ti,j721s2-r5f"; - reg = <0x5d00000 0x00010000>, - <0x5d10000 0x00010000>; - reg-names = "atcm", "btcm"; - ti,sci = <&sms>; - ti,sci-dev-id = <340>; - ti,sci-proc-ids = <0x07 0xff>; - resets = <&k3_reset 340 1>; - firmware-name = "j784s4-main-r5f0_1-fw"; - ti,atcm-enable = <1>; - ti,btcm-enable = <1>; - ti,loczrama = <1>; - }; - }; - - main_r5fss1: r5fss@5e00000 { - compatible = "ti,j721s2-r5fss"; - ti,cluster-mode = <1>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x5e00000 0x00 0x5e00000 0x20000>, - <0x5f00000 0x00 0x5f00000 0x20000>; - power-domains = <&k3_pds 337 TI_SCI_PD_EXCLUSIVE>; - - main_r5fss1_core0: r5f@5e00000 { - compatible = "ti,j721s2-r5f"; - reg = <0x5e00000 0x00010000>, - <0x5e10000 0x00010000>; - reg-names = "atcm", "btcm"; - ti,sci = <&sms>; - ti,sci-dev-id = <341>; - ti,sci-proc-ids = <0x08 0xff>; - resets = <&k3_reset 341 1>; - firmware-name = "j784s4-main-r5f1_0-fw"; - ti,atcm-enable = <1>; - ti,btcm-enable = <1>; - ti,loczrama = <1>; - }; - - main_r5fss1_core1: r5f@5f00000 { - compatible = "ti,j721s2-r5f"; - reg = <0x5f00000 0x00010000>, - <0x5f10000 0x00010000>; - reg-names = "atcm", "btcm"; - ti,sci = <&sms>; - ti,sci-dev-id = <342>; - ti,sci-proc-ids = <0x09 0xff>; - resets = <&k3_reset 342 1>; - firmware-name = "j784s4-main-r5f1_1-fw"; - ti,atcm-enable = <1>; - ti,btcm-enable = <1>; - ti,loczrama = <1>; - }; - }; - - main_r5fss2: r5fss@5900000 { - compatible = "ti,j721s2-r5fss"; - ti,cluster-mode = <1>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x5900000 0x00 0x5900000 0x20000>, - <0x5a00000 0x00 0x5a00000 0x20000>; - power-domains = <&k3_pds 338 TI_SCI_PD_EXCLUSIVE>; - - main_r5fss2_core0: r5f@5900000 { - compatible = "ti,j721s2-r5f"; - reg = <0x5900000 0x00010000>, - <0x5910000 0x00010000>; - reg-names = "atcm", "btcm"; - ti,sci = <&sms>; - ti,sci-dev-id = <343>; - ti,sci-proc-ids = <0x0a 0xff>; - resets = <&k3_reset 343 1>; - firmware-name = "j784s4-main-r5f2_0-fw"; - ti,atcm-enable = <1>; - ti,btcm-enable = <1>; - ti,loczrama = <1>; - }; - - main_r5fss2_core1: r5f@5a00000 { - compatible = "ti,j721s2-r5f"; - reg = <0x5a00000 0x00010000>, - <0x5a10000 0x00010000>; - reg-names = "atcm", "btcm"; - ti,sci = <&sms>; - ti,sci-dev-id = <344>; - ti,sci-proc-ids = <0x0b 0xff>; - resets = <&k3_reset 344 1>; - firmware-name = "j784s4-main-r5f2_1-fw"; - ti,atcm-enable = <1>; - ti,btcm-enable = <1>; - ti,loczrama = <1>; - }; - }; - - c71_0: dsp@64800000 { - compatible = "ti,j721s2-c71-dsp"; - reg = <0x00 0x64800000 0x00 0x00080000>, - <0x00 0x64e00000 0x00 0x0000c000>; - reg-names = "l2sram", "l1dram"; - ti,sci = <&sms>; - ti,sci-dev-id = <30>; - ti,sci-proc-ids = <0x30 0xff>; - resets = <&k3_reset 30 1>; - firmware-name = "j784s4-c71_0-fw"; - status = "disabled"; - }; - - c71_1: dsp@65800000 { - compatible = "ti,j721s2-c71-dsp"; - reg = <0x00 0x65800000 0x00 0x00080000>, - <0x00 0x65e00000 0x00 0x0000c000>; - reg-names = "l2sram", "l1dram"; - ti,sci = <&sms>; - ti,sci-dev-id = <33>; - ti,sci-proc-ids = <0x31 0xff>; - resets = <&k3_reset 33 1>; - firmware-name = "j784s4-c71_1-fw"; - status = "disabled"; - }; - - c71_2: dsp@66800000 { - compatible = "ti,j721s2-c71-dsp"; - reg = <0x00 0x66800000 0x00 0x00080000>, - <0x00 0x66e00000 0x00 0x0000c000>; - reg-names = "l2sram", "l1dram"; - ti,sci = <&sms>; - ti,sci-dev-id = <37>; - ti,sci-proc-ids = <0x32 0xff>; - resets = <&k3_reset 37 1>; - firmware-name = "j784s4-c71_2-fw"; - status = "disabled"; - }; - +&cbass_main { c71_3: dsp@67800000 { compatible = "ti,j721s2-c71-dsp"; reg = <0x00 0x67800000 0x00 0x00080000>, <0x00 0x67e00000 0x00 0x0000c000>; reg-names = "l2sram", "l1dram"; + resets = <&k3_reset 40 1>; + firmware-name = "j784s4-c71_3-fw"; ti,sci = <&sms>; ti,sci-dev-id = <40>; ti,sci-proc-ids = <0x33 0xff>; - resets = <&k3_reset 40 1>; - firmware-name = "j784s4-c71_3-fw"; - status = "disabled"; - }; - - main_esm: esm@700000 { - compatible = "ti,j721e-esm"; - reg = <0x00 0x700000 0x00 0x1000>; - ti,esm-pins = <688>, <689>, <690>, <691>, <692>, <693>, <694>, - <695>; - bootph-pre-ram; - }; - - watchdog0: watchdog@2200000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2200000 0x00 0x100>; - clocks = <&k3_clks 348 0>; - power-domains = <&k3_pds 348 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 348 0>; - assigned-clock-parents = <&k3_clks 348 4>; - }; - - watchdog1: watchdog@2210000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2210000 0x00 0x100>; - clocks = <&k3_clks 349 0>; - power-domains = <&k3_pds 349 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 349 0>; - assigned-clock-parents = <&k3_clks 349 4>; - }; - - watchdog2: watchdog@2220000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2220000 0x00 0x100>; - clocks = <&k3_clks 350 0>; - power-domains = <&k3_pds 350 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 350 0>; - assigned-clock-parents = <&k3_clks 350 4>; - }; - - watchdog3: watchdog@2230000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2230000 0x00 0x100>; - clocks = <&k3_clks 351 0>; - power-domains = <&k3_pds 351 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 351 0>; - assigned-clock-parents = <&k3_clks 351 4>; - }; - - watchdog4: watchdog@2240000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2240000 0x00 0x100>; - clocks = <&k3_clks 352 0>; - power-domains = <&k3_pds 352 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 352 0>; - assigned-clock-parents = <&k3_clks 352 4>; - }; - - watchdog5: watchdog@2250000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2250000 0x00 0x100>; - clocks = <&k3_clks 353 0>; - power-domains = <&k3_pds 353 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 353 0>; - assigned-clock-parents = <&k3_clks 353 4>; - }; - - watchdog6: watchdog@2260000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2260000 0x00 0x100>; - clocks = <&k3_clks 354 0>; - power-domains = <&k3_pds 354 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 354 0>; - assigned-clock-parents = <&k3_clks 354 4>; - }; - - watchdog7: watchdog@2270000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2270000 0x00 0x100>; - clocks = <&k3_clks 355 0>; - power-domains = <&k3_pds 355 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 355 0>; - assigned-clock-parents = <&k3_clks 355 4>; - }; - - /* - * The following RTI instances are coupled with MCU R5Fs, c7x and - * GPU so keeping them reserved as these will be used by their - * respective firmware - */ - watchdog8: watchdog@22f0000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x22f0000 0x00 0x100>; - clocks = <&k3_clks 360 0>; - power-domains = <&k3_pds 360 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 360 0>; - assigned-clock-parents = <&k3_clks 360 4>; - /* reserved for GPU */ - status = "reserved"; - }; - - watchdog9: watchdog@2300000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2300000 0x00 0x100>; - clocks = <&k3_clks 356 0>; - power-domains = <&k3_pds 356 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 356 0>; - assigned-clock-parents = <&k3_clks 356 4>; - /* reserved for C7X_0 DSP */ - status = "reserved"; - }; - - watchdog10: watchdog@2310000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2310000 0x00 0x100>; - clocks = <&k3_clks 357 0>; - power-domains = <&k3_pds 357 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 357 0>; - assigned-clock-parents = <&k3_clks 357 4>; - /* reserved for C7X_1 DSP */ - status = "reserved"; - }; - - watchdog11: watchdog@2320000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2320000 0x00 0x100>; - clocks = <&k3_clks 358 0>; - power-domains = <&k3_pds 358 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 358 0>; - assigned-clock-parents = <&k3_clks 358 4>; - /* reserved for C7X_2 DSP */ - status = "reserved"; - }; - - watchdog12: watchdog@2330000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2330000 0x00 0x100>; - clocks = <&k3_clks 359 0>; - power-domains = <&k3_pds 359 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 359 0>; - assigned-clock-parents = <&k3_clks 359 4>; - /* reserved for C7X_3 DSP */ - status = "reserved"; - }; - - watchdog13: watchdog@23c0000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x23c0000 0x00 0x100>; - clocks = <&k3_clks 361 0>; - power-domains = <&k3_pds 361 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 361 0>; - assigned-clock-parents = <&k3_clks 361 4>; - /* reserved for MAIN_R5F0_0 */ - status = "reserved"; - }; - - watchdog14: watchdog@23d0000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x23d0000 0x00 0x100>; - clocks = <&k3_clks 362 0>; - power-domains = <&k3_pds 362 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 362 0>; - assigned-clock-parents = <&k3_clks 362 4>; - /* reserved for MAIN_R5F0_1 */ - status = "reserved"; - }; - - watchdog15: watchdog@23e0000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x23e0000 0x00 0x100>; - clocks = <&k3_clks 363 0>; - power-domains = <&k3_pds 363 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 363 0>; - assigned-clock-parents = <&k3_clks 363 4>; - /* reserved for MAIN_R5F1_0 */ - status = "reserved"; - }; - - watchdog16: watchdog@23f0000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x23f0000 0x00 0x100>; - clocks = <&k3_clks 364 0>; - power-domains = <&k3_pds 364 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 364 0>; - assigned-clock-parents = <&k3_clks 364 4>; - /* reserved for MAIN_R5F1_1 */ - status = "reserved"; - }; - - watchdog17: watchdog@2540000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2540000 0x00 0x100>; - clocks = <&k3_clks 365 0>; - power-domains = <&k3_pds 365 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 365 0>; - assigned-clock-parents = <&k3_clks 366 4>; - /* reserved for MAIN_R5F2_0 */ - status = "reserved"; - }; - - watchdog18: watchdog@2550000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x2550000 0x00 0x100>; - clocks = <&k3_clks 366 0>; - power-domains = <&k3_pds 366 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 366 0>; - assigned-clock-parents = <&k3_clks 366 4>; - /* reserved for MAIN_R5F2_1 */ - status = "reserved"; - }; - - mhdp: bridge@a000000 { - compatible = "ti,j721e-mhdp8546"; - reg = <0x0 0xa000000 0x0 0x30a00>, - <0x0 0x4f40000 0x0 0x20>; - reg-names = "mhdptx", "j721e-intg"; - clocks = <&k3_clks 217 11>; - interrupt-parent = <&gic500>; - interrupts = ; - power-domains = <&k3_pds 217 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - - dp0_ports: ports { - #address-cells = <1>; - #size-cells = <0>; - /* Remote-endpoints are on the boards so - * ports are defined in the platform dt file. - */ - }; - }; - - dss: dss@4a00000 { - compatible = "ti,j721e-dss"; - reg = <0x00 0x04a00000 0x00 0x10000>, /* common_m */ - <0x00 0x04a10000 0x00 0x10000>, /* common_s0*/ - <0x00 0x04b00000 0x00 0x10000>, /* common_s1*/ - <0x00 0x04b10000 0x00 0x10000>, /* common_s2*/ - <0x00 0x04a20000 0x00 0x10000>, /* vidl1 */ - <0x00 0x04a30000 0x00 0x10000>, /* vidl2 */ - <0x00 0x04a50000 0x00 0x10000>, /* vid1 */ - <0x00 0x04a60000 0x00 0x10000>, /* vid2 */ - <0x00 0x04a70000 0x00 0x10000>, /* ovr1 */ - <0x00 0x04a90000 0x00 0x10000>, /* ovr2 */ - <0x00 0x04ab0000 0x00 0x10000>, /* ovr3 */ - <0x00 0x04ad0000 0x00 0x10000>, /* ovr4 */ - <0x00 0x04a80000 0x00 0x10000>, /* vp1 */ - <0x00 0x04aa0000 0x00 0x10000>, /* vp1 */ - <0x00 0x04ac0000 0x00 0x10000>, /* vp1 */ - <0x00 0x04ae0000 0x00 0x10000>, /* vp4 */ - <0x00 0x04af0000 0x00 0x10000>; /* wb */ - reg-names = "common_m", "common_s0", - "common_s1", "common_s2", - "vidl1", "vidl2","vid1","vid2", - "ovr1", "ovr2", "ovr3", "ovr4", - "vp1", "vp2", "vp3", "vp4", - "wb"; - clocks = <&k3_clks 218 0>, - <&k3_clks 218 2>, - <&k3_clks 218 5>, - <&k3_clks 218 14>, - <&k3_clks 218 18>; - clock-names = "fck", "vp1", "vp2", "vp3", "vp4"; - power-domains = <&k3_pds 218 TI_SCI_PD_EXCLUSIVE>; - interrupts = , - , - , - ; - interrupt-names = "common_m", - "common_s0", - "common_s1", - "common_s2"; status = "disabled"; - - dss_ports: ports { - /* Ports that DSS drives are platform specific - * so they are defined in platform dt file. - */ - }; }; - mcasp0: mcasp@2b00000 { - compatible = "ti,am33xx-mcasp-audio"; - reg = <0x00 0x02b00000 0x00 0x2000>, - <0x00 0x02b08000 0x00 0x1000>; - reg-names = "mpu","dat"; - interrupts = , - ; - interrupt-names = "tx", "rx"; - dmas = <&main_udmap 0xc400>, <&main_udmap 0x4400>; - dma-names = "tx", "rx"; - clocks = <&k3_clks 265 0>; + pcie2_rc: pcie@2920000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02920000 0x00 0x1000>, + <0x00 0x02927000 0x00 0x400>, + <0x00 0x0e000000 0x00 0x00800000>, + <0x44 0x00000000 0x00 0x00001000>; + ranges = <0x01000000 0x0 0x00001000 0x44 0x00001000 0x0 0x0010000>, + <0x02000000 0x0 0x00011000 0x44 0x00011000 0x0 0x7fef000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + max-link-speed = <3>; + num-lanes = <2>; + power-domains = <&k3_pds 334 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 334 0>; clock-names = "fck"; - assigned-clocks = <&k3_clks 265 0>; - assigned-clock-parents = <&k3_clks 265 1>; - power-domains = <&k3_pds 265 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb012>; + msi-map = <0x0 &gic_its 0x20000 0x10000>; + dma-coherent; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + ti,syscon-pcie-ctrl = <&pcie2_ctrl 0x0>; status = "disabled"; }; - mcasp1: mcasp@2b10000 { - compatible = "ti,am33xx-mcasp-audio"; - reg = <0x00 0x02b10000 0x00 0x2000>, - <0x00 0x02b18000 0x00 0x1000>; - reg-names = "mpu","dat"; - interrupts = , - ; - interrupt-names = "tx", "rx"; - dmas = <&main_udmap 0xc401>, <&main_udmap 0x4401>; - dma-names = "tx", "rx"; - clocks = <&k3_clks 266 0>; + pcie3_rc: pcie@2930000 { + compatible = "ti,j784s4-pcie-host"; + reg = <0x00 0x02930000 0x00 0x1000>, + <0x00 0x02937000 0x00 0x400>, + <0x00 0x0e800000 0x00 0x00800000>, + <0x44 0x10000000 0x00 0x00001000>; + ranges = <0x01000000 0x0 0x00001000 0x44 0x10001000 0x0 0x0010000>, + <0x02000000 0x0 0x00011000 0x44 0x10011000 0x0 0x7fef000>; + reg-names = "intd_cfg", "user_cfg", "reg", "cfg"; + interrupt-names = "link_state"; + interrupts = ; + device_type = "pci"; + max-link-speed = <3>; + num-lanes = <2>; + power-domains = <&k3_pds 335 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 335 0>; clock-names = "fck"; - assigned-clocks = <&k3_clks 266 0>; - assigned-clock-parents = <&k3_clks 266 1>; - power-domains = <&k3_pds 266 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + vendor-id = <0x104c>; + device-id = <0xb012>; + msi-map = <0x0 &gic_its 0x30000 0x10000>; + dma-coherent; + dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x10000 0x0>; + ti,syscon-pcie-ctrl = <&pcie3_ctrl 0x0>; status = "disabled"; }; - mcasp2: mcasp@2b20000 { - compatible = "ti,am33xx-mcasp-audio"; - reg = <0x00 0x02b20000 0x00 0x2000>, - <0x00 0x02b28000 0x00 0x1000>; - reg-names = "mpu","dat"; - interrupts = , - ; - interrupt-names = "tx", "rx"; - dmas = <&main_udmap 0xc402>, <&main_udmap 0x4402>; - dma-names = "tx", "rx"; - clocks = <&k3_clks 267 0>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 267 0>; - assigned-clock-parents = <&k3_clks 267 1>; - power-domains = <&k3_pds 267 TI_SCI_PD_EXCLUSIVE>; + serdes_wiz2: wiz@5020000 { + compatible = "ti,j784s4-wiz-10g"; + ranges = <0x05020000 0x00 0x05020000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + power-domains = <&k3_pds 406 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 406 2>, <&k3_clks 406 6>, <&serdes_refclk>, <&k3_clks 406 5>; + clock-names = "fck", "core_ref_clk", "ext_ref_clk", "core_ref1_clk"; + assigned-clocks = <&k3_clks 406 6>; + assigned-clock-parents = <&k3_clks 406 10>; + num-lanes = <4>; + #reset-cells = <1>; + #clock-cells = <1>; status = "disabled"; + + serdes2: serdes@5020000 { + compatible = "ti,j721e-serdes-10g"; + reg = <0x05020000 0x010000>; + reg-names = "torrent_phy"; + resets = <&serdes_wiz2 0>; + reset-names = "torrent_reset"; + clocks = <&serdes_wiz2 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz2 TI_WIZ_PHY_EN_REFCLK>; + clock-names = "refclk", "phy_en_refclk"; + assigned-clocks = <&serdes_wiz2 TI_WIZ_PLL0_REFCLK>, + <&serdes_wiz2 TI_WIZ_PLL1_REFCLK>, + <&serdes_wiz2 TI_WIZ_REFCLK_DIG>; + assigned-clock-parents = <&k3_clks 406 6>, + <&k3_clks 406 6>, + <&k3_clks 406 6>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + status = "disabled"; + }; }; +}; - mcasp3: mcasp@2b30000 { - compatible = "ti,am33xx-mcasp-audio"; - reg = <0x00 0x02b30000 0x00 0x2000>, - <0x00 0x02b38000 0x00 0x1000>; - reg-names = "mpu","dat"; - interrupts = , - ; - interrupt-names = "tx", "rx"; - dmas = <&main_udmap 0xc403>, <&main_udmap 0x4403>; - dma-names = "tx", "rx"; - clocks = <&k3_clks 268 0>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 268 0>; - assigned-clock-parents = <&k3_clks 268 1>; - power-domains = <&k3_pds 268 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; +&scm_conf { + pcie2_ctrl: pcie2-ctrl@4078 { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x4078 0x4>; }; - mcasp4: mcasp@2b40000 { - compatible = "ti,am33xx-mcasp-audio"; - reg = <0x00 0x02b40000 0x00 0x2000>, - <0x00 0x02b48000 0x00 0x1000>; - reg-names = "mpu","dat"; - interrupts = , - ; - interrupt-names = "tx", "rx"; - dmas = <&main_udmap 0xc404>, <&main_udmap 0x4404>; - dma-names = "tx", "rx"; - clocks = <&k3_clks 269 0>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 269 0>; - assigned-clock-parents = <&k3_clks 269 1>; - power-domains = <&k3_pds 269 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; + pcie3_ctrl: pcie3-ctrl@407c { + compatible = "ti,j784s4-pcie-ctrl", "syscon"; + reg = <0x407c 0x4>; }; }; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi deleted file mode 100644 index f603380fc91cf4..00000000000000 --- a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi +++ /dev/null @@ -1,760 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT -/* - * Device Tree Source for J784S4 SoC Family MCU/WAKEUP Domain peripherals - * - * Copyright (C) 2022-2024 Texas Instruments Incorporated - https://www.ti.com/ - */ - -&cbass_mcu_wakeup { - sms: system-controller@44083000 { - bootph-all; - compatible = "ti,k2g-sci"; - ti,host-id = <12>; - - mbox-names = "rx", "tx"; - - mboxes = <&secure_proxy_main 11>, - <&secure_proxy_main 13>; - - reg-names = "debug_messages"; - reg = <0x00 0x44083000 0x00 0x1000>; - - k3_pds: power-controller { - bootph-all; - compatible = "ti,sci-pm-domain"; - #power-domain-cells = <2>; - }; - - k3_clks: clock-controller { - bootph-all; - compatible = "ti,k2g-sci-clk"; - #clock-cells = <2>; - }; - - k3_reset: reset-controller { - bootph-all; - compatible = "ti,sci-reset"; - #reset-cells = <2>; - }; - }; - - wkup_conf: bus@43000000 { - bootph-all; - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x00 0x43000000 0x20000>; - - chipid: chipid@14 { - bootph-all; - compatible = "ti,am654-chipid"; - reg = <0x14 0x4>; - }; - }; - - secure_proxy_sa3: mailbox@43600000 { - compatible = "ti,am654-secure-proxy"; - #mbox-cells = <1>; - reg-names = "target_data", "rt", "scfg"; - reg = <0x00 0x43600000 0x00 0x10000>, - <0x00 0x44880000 0x00 0x20000>, - <0x00 0x44860000 0x00 0x20000>; - /* - * Marked Disabled: - * Node is incomplete as it is meant for bootloaders and - * firmware on non-MPU processors - */ - status = "disabled"; - }; - - mcu_ram: sram@41c00000 { - compatible = "mmio-sram"; - reg = <0x00 0x41c00000 0x00 0x100000>; - ranges = <0x00 0x00 0x41c00000 0x100000>; - #address-cells = <1>; - #size-cells = <1>; - }; - - wkup_pmx0: pinctrl@4301c000 { - compatible = "pinctrl-single"; - /* Proxy 0 addressing */ - reg = <0x00 0x4301c000 0x00 0x034>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0xffffffff>; - }; - - wkup_pmx1: pinctrl@4301c038 { - compatible = "pinctrl-single"; - /* Proxy 0 addressing */ - reg = <0x00 0x4301c038 0x00 0x02c>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0xffffffff>; - }; - - wkup_pmx2: pinctrl@4301c068 { - compatible = "pinctrl-single"; - /* Proxy 0 addressing */ - reg = <0x00 0x4301c068 0x00 0x120>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0xffffffff>; - }; - - wkup_pmx3: pinctrl@4301c190 { - compatible = "pinctrl-single"; - /* Proxy 0 addressing */ - reg = <0x00 0x4301c190 0x00 0x004>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0xffffffff>; - }; - - wkup_gpio_intr: interrupt-controller@42200000 { - compatible = "ti,sci-intr"; - reg = <0x00 0x42200000 0x00 0x400>; - ti,intr-trigger-type = <1>; - interrupt-controller; - interrupt-parent = <&gic500>; - #interrupt-cells = <1>; - ti,sci = <&sms>; - ti,sci-dev-id = <177>; - ti,interrupt-ranges = <16 960 16>; - }; - - /* MCU_TIMERIO pad input CTRLMMR_MCU_TIMER*_CTRL registers */ - mcu_timerio_input: pinctrl@40f04200 { - compatible = "pinctrl-single"; - reg = <0x00 0x40f04200 0x00 0x28>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0x0000000f>; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - /* MCU_TIMERIO pad output CTRLMMR_MCU_TIMERIO*_CTRL registers */ - mcu_timerio_output: pinctrl@40f04280 { - compatible = "pinctrl-single"; - reg = <0x00 0x40f04280 0x00 0x28>; - #pinctrl-cells = <1>; - pinctrl-single,register-width = <32>; - pinctrl-single,function-mask = <0x0000000f>; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_conf: bus@40f00000 { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x0 0x0 0x40f00000 0x20000>; - - cpsw_mac_syscon: ethernet-mac-syscon@200 { - compatible = "ti,am62p-cpsw-mac-efuse", "syscon"; - reg = <0x200 0x8>; - }; - - phy_gmii_sel: phy@4040 { - compatible = "ti,am654-phy-gmii-sel"; - reg = <0x4040 0x4>; - #phy-cells = <1>; - }; - }; - - mcu_timer0: timer@40400000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40400000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 35 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 35 2>; - assigned-clock-parents = <&k3_clks 35 3>; - power-domains = <&k3_pds 35 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer1: timer@40410000 { - bootph-all; - compatible = "ti,am654-timer"; - reg = <0x00 0x40410000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 117 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 117 2>; - assigned-clock-parents = <&k3_clks 117 3>; - power-domains = <&k3_pds 117 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer2: timer@40420000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40420000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 118 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 118 2>; - assigned-clock-parents = <&k3_clks 118 3>; - power-domains = <&k3_pds 118 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer3: timer@40430000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40430000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 119 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 119 2>; - assigned-clock-parents = <&k3_clks 119 3>; - power-domains = <&k3_pds 119 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer4: timer@40440000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40440000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 120 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 120 2>; - assigned-clock-parents = <&k3_clks 120 3>; - power-domains = <&k3_pds 120 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer5: timer@40450000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40450000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 121 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 121 2>; - assigned-clock-parents = <&k3_clks 121 3>; - power-domains = <&k3_pds 121 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer6: timer@40460000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40460000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 122 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 122 2>; - assigned-clock-parents = <&k3_clks 122 3>; - power-domains = <&k3_pds 122 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer7: timer@40470000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40470000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 123 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 123 2>; - assigned-clock-parents = <&k3_clks 123 3>; - power-domains = <&k3_pds 123 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer8: timer@40480000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40480000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 124 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 124 2>; - assigned-clock-parents = <&k3_clks 124 3>; - power-domains = <&k3_pds 124 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - mcu_timer9: timer@40490000 { - compatible = "ti,am654-timer"; - reg = <0x00 0x40490000 0x00 0x400>; - interrupts = ; - clocks = <&k3_clks 125 2>; - clock-names = "fck"; - assigned-clocks = <&k3_clks 125 2>; - assigned-clock-parents = <&k3_clks 125 3>; - power-domains = <&k3_pds 125 TI_SCI_PD_EXCLUSIVE>; - ti,timer-pwm; - /* Non-MPU Firmware usage */ - status = "reserved"; - }; - - wkup_uart0: serial@42300000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x42300000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 397 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 397 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - mcu_uart0: serial@40a00000 { - compatible = "ti,j721e-uart", "ti,am654-uart"; - reg = <0x00 0x40a00000 0x00 0x200>; - interrupts = ; - clocks = <&k3_clks 149 0>; - clock-names = "fclk"; - power-domains = <&k3_pds 149 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - wkup_gpio0: gpio@42110000 { - compatible = "ti,j721e-gpio", "ti,keystone-gpio"; - reg = <0x00 0x42110000 0x00 0x100>; - gpio-controller; - #gpio-cells = <2>; - interrupt-parent = <&wkup_gpio_intr>; - interrupts = <103>, <104>, <105>, <106>, <107>, <108>; - interrupt-controller; - #interrupt-cells = <2>; - ti,ngpio = <89>; - ti,davinci-gpio-unbanked = <0>; - power-domains = <&k3_pds 167 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 167 0>; - clock-names = "gpio"; - status = "disabled"; - }; - - wkup_gpio1: gpio@42100000 { - compatible = "ti,j721e-gpio", "ti,keystone-gpio"; - reg = <0x00 0x42100000 0x00 0x100>; - gpio-controller; - #gpio-cells = <2>; - interrupt-parent = <&wkup_gpio_intr>; - interrupts = <112>, <113>, <114>, <115>, <116>, <117>; - interrupt-controller; - #interrupt-cells = <2>; - ti,ngpio = <89>; - ti,davinci-gpio-unbanked = <0>; - power-domains = <&k3_pds 168 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 168 0>; - clock-names = "gpio"; - status = "disabled"; - }; - - wkup_i2c0: i2c@42120000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x42120000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 279 2>; - clock-names = "fck"; - power-domains = <&k3_pds 279 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - mcu_i2c0: i2c@40b00000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x40b00000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 277 2>; - clock-names = "fck"; - power-domains = <&k3_pds 277 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - mcu_i2c1: i2c@40b10000 { - compatible = "ti,j721e-i2c", "ti,omap4-i2c"; - reg = <0x00 0x40b10000 0x00 0x100>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 278 2>; - clock-names = "fck"; - power-domains = <&k3_pds 278 TI_SCI_PD_EXCLUSIVE>; - status = "disabled"; - }; - - mcu_mcan0: can@40528000 { - compatible = "bosch,m_can"; - reg = <0x00 0x40528000 0x00 0x200>, - <0x00 0x40500000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 263 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 263 6>, <&k3_clks 263 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - mcu_mcan1: can@40568000 { - compatible = "bosch,m_can"; - reg = <0x00 0x40568000 0x00 0x200>, - <0x00 0x40540000 0x00 0x8000>; - reg-names = "m_can", "message_ram"; - power-domains = <&k3_pds 264 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 264 6>, <&k3_clks 264 1>; - clock-names = "hclk", "cclk"; - interrupts = , - ; - interrupt-names = "int0", "int1"; - bosch,mram-cfg = <0x00 128 64 64 64 64 32 32>; - status = "disabled"; - }; - - mcu_spi0: spi@40300000 { - compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; - reg = <0x00 0x040300000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 384 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 384 0>; - status = "disabled"; - }; - - mcu_spi1: spi@40310000 { - compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; - reg = <0x00 0x040310000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 385 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 385 0>; - status = "disabled"; - }; - - mcu_spi2: spi@40320000 { - compatible = "ti,am654-mcspi", "ti,omap4-mcspi"; - reg = <0x00 0x040320000 0x00 0x400>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - power-domains = <&k3_pds 386 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 386 0>; - status = "disabled"; - }; - - mcu_navss: bus@28380000 { - bootph-all; - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>; - ti,sci-dev-id = <323>; - dma-coherent; - dma-ranges; - - mcu_ringacc: ringacc@2b800000 { - bootph-all; - compatible = "ti,am654-navss-ringacc"; - reg = <0x00 0x2b800000 0x00 0x400000>, - <0x00 0x2b000000 0x00 0x400000>, - <0x00 0x28590000 0x00 0x100>, - <0x00 0x2a500000 0x00 0x40000>, - <0x00 0x28440000 0x00 0x40000>; - reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg"; - ti,num-rings = <286>; - ti,sci-rm-range-gp-rings = <0x1>; - ti,sci = <&sms>; - ti,sci-dev-id = <328>; - msi-parent = <&main_udmass_inta>; - }; - - mcu_udmap: dma-controller@285c0000 { - bootph-all; - compatible = "ti,j721e-navss-mcu-udmap"; - reg = <0x00 0x285c0000 0x00 0x100>, - <0x00 0x2a800000 0x00 0x40000>, - <0x00 0x2aa00000 0x00 0x40000>, - <0x00 0x284a0000 0x00 0x4000>, - <0x00 0x284c0000 0x00 0x4000>, - <0x00 0x28400000 0x00 0x2000>; - reg-names = "gcfg", "rchanrt", "tchanrt", - "tchan", "rchan", "rflow"; - msi-parent = <&main_udmass_inta>; - #dma-cells = <1>; - - ti,sci = <&sms>; - ti,sci-dev-id = <329>; - ti,ringacc = <&mcu_ringacc>; - ti,sci-rm-range-tchan = <0x0d>, /* TX_CHAN */ - <0x0f>; /* TX_HCHAN */ - ti,sci-rm-range-rchan = <0x0a>, /* RX_CHAN */ - <0x0b>; /* RX_HCHAN */ - ti,sci-rm-range-rflow = <0x00>; /* GP RFLOW */ - }; - }; - - secure_proxy_mcu: mailbox@2a480000 { - compatible = "ti,am654-secure-proxy"; - #mbox-cells = <1>; - reg-names = "target_data", "rt", "scfg"; - reg = <0x00 0x2a480000 0x00 0x80000>, - <0x00 0x2a380000 0x00 0x80000>, - <0x00 0x2a400000 0x00 0x80000>; - /* - * Marked Disabled: - * Node is incomplete as it is meant for bootloaders and - * firmware on non-MPU processors - */ - status = "disabled"; - }; - - mcu_cpsw: ethernet@46000000 { - compatible = "ti,j721e-cpsw-nuss"; - #address-cells = <2>; - #size-cells = <2>; - reg = <0x00 0x46000000 0x00 0x200000>; - reg-names = "cpsw_nuss"; - ranges = <0x00 0x00 0x00 0x46000000 0x00 0x200000>; - dma-coherent; - clocks = <&k3_clks 63 0>; - clock-names = "fck"; - power-domains = <&k3_pds 63 TI_SCI_PD_EXCLUSIVE>; - - dmas = <&mcu_udmap 0xf000>, - <&mcu_udmap 0xf001>, - <&mcu_udmap 0xf002>, - <&mcu_udmap 0xf003>, - <&mcu_udmap 0xf004>, - <&mcu_udmap 0xf005>, - <&mcu_udmap 0xf006>, - <&mcu_udmap 0xf007>, - <&mcu_udmap 0x7000>; - dma-names = "tx0", "tx1", "tx2", "tx3", - "tx4", "tx5", "tx6", "tx7", - "rx"; - status = "disabled"; - - ethernet-ports { - #address-cells = <1>; - #size-cells = <0>; - - mcu_cpsw_port1: port@1 { - reg = <1>; - ti,mac-only; - label = "port1"; - ti,syscon-efuse = <&cpsw_mac_syscon 0x0>; - phys = <&phy_gmii_sel 1>; - }; - }; - - davinci_mdio: mdio@f00 { - compatible = "ti,cpsw-mdio","ti,davinci_mdio"; - reg = <0x00 0xf00 0x00 0x100>; - #address-cells = <1>; - #size-cells = <0>; - clocks = <&k3_clks 63 0>; - clock-names = "fck"; - bus_freq = <1000000>; - }; - - cpts@3d000 { - compatible = "ti,am65-cpts"; - reg = <0x00 0x3d000 0x00 0x400>; - clocks = <&k3_clks 63 3>; - clock-names = "cpts"; - assigned-clocks = <&k3_clks 63 3>; /* CPTS_RFT_CLK */ - assigned-clock-parents = <&k3_clks 63 5>; /* MAIN_0_HSDIV6_CLK */ - interrupts-extended = <&gic500 GIC_SPI 858 IRQ_TYPE_LEVEL_HIGH>; - interrupt-names = "cpts"; - ti,cpts-ext-ts-inputs = <4>; - ti,cpts-periodic-outputs = <2>; - }; - }; - - mcu_r5fss0: r5fss@41000000 { - compatible = "ti,j721s2-r5fss"; - ti,cluster-mode = <1>; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0x41000000 0x00 0x41000000 0x20000>, - <0x41400000 0x00 0x41400000 0x20000>; - power-domains = <&k3_pds 345 TI_SCI_PD_EXCLUSIVE>; - - mcu_r5fss0_core0: r5f@41000000 { - compatible = "ti,j721s2-r5f"; - reg = <0x41000000 0x00010000>, - <0x41010000 0x00010000>; - reg-names = "atcm", "btcm"; - ti,sci = <&sms>; - ti,sci-dev-id = <346>; - ti,sci-proc-ids = <0x01 0xff>; - resets = <&k3_reset 346 1>; - firmware-name = "j784s4-mcu-r5f0_0-fw"; - ti,atcm-enable = <1>; - ti,btcm-enable = <1>; - ti,loczrama = <1>; - }; - - mcu_r5fss0_core1: r5f@41400000 { - compatible = "ti,j721s2-r5f"; - reg = <0x41400000 0x00010000>, - <0x41410000 0x00010000>; - reg-names = "atcm", "btcm"; - ti,sci = <&sms>; - ti,sci-dev-id = <347>; - ti,sci-proc-ids = <0x02 0xff>; - resets = <&k3_reset 347 1>; - firmware-name = "j784s4-mcu-r5f0_1-fw"; - ti,atcm-enable = <1>; - ti,btcm-enable = <1>; - ti,loczrama = <1>; - }; - }; - - wkup_vtm0: temperature-sensor@42040000 { - compatible = "ti,j7200-vtm"; - reg = <0x00 0x42040000 0x00 0x350>, - <0x00 0x42050000 0x00 0x350>; - power-domains = <&k3_pds 243 TI_SCI_PD_SHARED>; - #thermal-sensor-cells = <1>; - }; - - tscadc0: tscadc@40200000 { - compatible = "ti,am3359-tscadc"; - reg = <0x00 0x40200000 0x00 0x1000>; - interrupts = ; - power-domains = <&k3_pds 0 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 0 0>; - assigned-clocks = <&k3_clks 0 2>; - assigned-clock-rates = <60000000>; - clock-names = "fck"; - dmas = <&main_udmap 0x7400>, - <&main_udmap 0x7401>; - dma-names = "fifo0", "fifo1"; - status = "disabled"; - - adc { - #io-channel-cells = <1>; - compatible = "ti,am3359-adc"; - }; - }; - - tscadc1: tscadc@40210000 { - compatible = "ti,am3359-tscadc"; - reg = <0x00 0x40210000 0x00 0x1000>; - interrupts = ; - power-domains = <&k3_pds 1 TI_SCI_PD_EXCLUSIVE>; - clocks = <&k3_clks 1 0>; - assigned-clocks = <&k3_clks 1 2>; - assigned-clock-rates = <60000000>; - clock-names = "fck"; - dmas = <&main_udmap 0x7402>, - <&main_udmap 0x7403>; - dma-names = "fifo0", "fifo1"; - status = "disabled"; - - adc { - #io-channel-cells = <1>; - compatible = "ti,am3359-adc"; - }; - }; - - fss: bus@47000000 { - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x00 0x47000000 0x00 0x47000000 0x00 0x00000100>, /* FSS Control */ - <0x00 0x47040000 0x00 0x47040000 0x00 0x00000100>, /* OSPI0 Control */ - <0x00 0x47050000 0x00 0x47050000 0x00 0x00000100>, /* OSPI1 Control */ - <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, /* FSS data region 1 */ - <0x04 0x00000000 0x04 0x00000000 0x04 0x00000000>; /* FSS data region 0/3 */ - - ospi0: spi@47040000 { - compatible = "ti,am654-ospi", "cdns,qspi-nor"; - reg = <0x00 0x47040000 0x00 0x100>, - <0x05 0x00000000 0x01 0x00000000>; - interrupts = ; - cdns,fifo-depth = <256>; - cdns,fifo-width = <4>; - cdns,trigger-address = <0x0>; - clocks = <&k3_clks 161 7>; - assigned-clocks = <&k3_clks 161 7>; - assigned-clock-parents = <&k3_clks 161 9>; - assigned-clock-rates = <166666666>; - power-domains = <&k3_pds 161 TI_SCI_PD_EXCLUSIVE>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - ospi1: spi@47050000 { - compatible = "ti,am654-ospi", "cdns,qspi-nor"; - reg = <0x00 0x47050000 0x00 0x100>, - <0x07 0x00000000 0x01 0x00000000>; - interrupts = ; - cdns,fifo-depth = <256>; - cdns,fifo-width = <4>; - cdns,trigger-address = <0x0>; - clocks = <&k3_clks 162 7>; - power-domains = <&k3_pds 162 TI_SCI_PD_EXCLUSIVE>; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - }; - - mcu_esm: esm@40800000 { - compatible = "ti,j721e-esm"; - reg = <0x00 0x40800000 0x00 0x1000>; - ti,esm-pins = <95>; - bootph-pre-ram; - }; - - wkup_esm: esm@42080000 { - compatible = "ti,j721e-esm"; - reg = <0x00 0x42080000 0x00 0x1000>; - ti,esm-pins = <63>; - bootph-pre-ram; - }; - - /* - * The 2 RTI instances are couple with MCU R5Fs so keeping them - * reserved as these will be used by their respective firmware - */ - mcu_watchdog0: watchdog@40600000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x40600000 0x00 0x100>; - clocks = <&k3_clks 367 1>; - power-domains = <&k3_pds 367 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 367 0>; - assigned-clock-parents = <&k3_clks 367 4>; - /* reserved for MCU_R5F0_0 */ - status = "reserved"; - }; - - mcu_watchdog1: watchdog@40610000 { - compatible = "ti,j7-rti-wdt"; - reg = <0x00 0x40610000 0x00 0x100>; - clocks = <&k3_clks 368 1>; - power-domains = <&k3_pds 368 TI_SCI_PD_EXCLUSIVE>; - assigned-clocks = <&k3_clks 368 0>; - assigned-clock-parents = <&k3_clks 368 4>; - /* reserved for MCU_R5F0_1 */ - status = "reserved"; - }; -}; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-thermal.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-thermal.dtsi deleted file mode 100644 index e3ef61c1658f4b..00000000000000 --- a/arch/arm64/boot/dts/ti/k3-j784s4-thermal.dtsi +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT -/* - * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ - */ - -#include - -wkup0_thermal: wkup0-thermal { - polling-delay-passive = <250>; /* milliseconds */ - polling-delay = <500>; /* milliseconds */ - thermal-sensors = <&wkup_vtm0 0>; - - trips { - wkup0_crit: wkup0-crit { - temperature = <125000>; /* milliCelsius */ - hysteresis = <2000>; /* milliCelsius */ - type = "critical"; - }; - }; -}; - -wkup1_thermal: wkup1-thermal { - polling-delay-passive = <250>; /* milliseconds */ - polling-delay = <500>; /* milliseconds */ - thermal-sensors = <&wkup_vtm0 1>; - - trips { - wkup1_crit: wkup1-crit { - temperature = <125000>; /* milliCelsius */ - hysteresis = <2000>; /* milliCelsius */ - type = "critical"; - }; - }; -}; - -main0_thermal: main0-thermal { - polling-delay-passive = <250>; /* milliseconds */ - polling-delay = <500>; /* milliseconds */ - thermal-sensors = <&wkup_vtm0 2>; - - trips { - main0_crit: main0-crit { - temperature = <125000>; /* milliCelsius */ - hysteresis = <2000>; /* milliCelsius */ - type = "critical"; - }; - }; -}; - -main1_thermal: main1-thermal { - polling-delay-passive = <250>; /* milliseconds */ - polling-delay = <500>; /* milliseconds */ - thermal-sensors = <&wkup_vtm0 3>; - - trips { - main1_crit: main1-crit { - temperature = <125000>; /* milliCelsius */ - hysteresis = <2000>; /* milliCelsius */ - type = "critical"; - }; - }; -}; - -main2_thermal: main2-thermal { - polling-delay-passive = <250>; /* milliseconds */ - polling-delay = <500>; /* milliseconds */ - thermal-sensors = <&wkup_vtm0 4>; - - trips { - main2_crit: main2-crit { - temperature = <125000>; /* milliCelsius */ - hysteresis = <2000>; /* milliCelsius */ - type = "critical"; - }; - }; -}; - -main3_thermal: main3-thermal { - polling-delay-passive = <250>; /* milliseconds */ - polling-delay = <500>; /* milliseconds */ - thermal-sensors = <&wkup_vtm0 5>; - - trips { - main3_crit: main3-crit { - temperature = <125000>; /* milliCelsius */ - hysteresis = <2000>; /* milliCelsius */ - type = "critical"; - }; - }; -}; - -main4_thermal: main4-thermal { - polling-delay-passive = <250>; /* milliseconds */ - polling-delay = <500>; /* milliseconds */ - thermal-sensors = <&wkup_vtm0 6>; - - trips { - main4_crit: main4-crit { - temperature = <125000>; /* milliCelsius */ - hysteresis = <2000>; /* milliCelsius */ - type = "critical"; - }; - }; -}; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4.dtsi index 5e84c6b4f5ad48..f5afa32157cb80 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4.dtsi @@ -8,18 +8,11 @@ * */ -#include -#include -#include - -#include "k3-pinctrl.h" +#include "k3-j784s4-j742s2-common.dtsi" / { model = "Texas Instruments K3 J784S4 SoC"; compatible = "ti,j784s4"; - interrupt-parent = <&gic500>; - #address-cells = <2>; - #size-cells = <2>; cpus { #address-cells = <1>; @@ -174,130 +167,6 @@ cpu7: cpu@103 { next-level-cache = <&L2_1>; }; }; - - L2_0: l2-cache0 { - compatible = "cache"; - cache-level = <2>; - cache-unified; - cache-size = <0x200000>; - cache-line-size = <64>; - cache-sets = <1024>; - next-level-cache = <&msmc_l3>; - }; - - L2_1: l2-cache1 { - compatible = "cache"; - cache-level = <2>; - cache-unified; - cache-size = <0x200000>; - cache-line-size = <64>; - cache-sets = <1024>; - next-level-cache = <&msmc_l3>; - }; - - msmc_l3: l3-cache0 { - compatible = "cache"; - cache-level = <3>; - cache-unified; - }; - - firmware { - optee { - compatible = "linaro,optee-tz"; - method = "smc"; - }; - - psci: psci { - compatible = "arm,psci-1.0"; - method = "smc"; - }; - }; - - a72_timer0: timer-cl0-cpu0 { - compatible = "arm,armv8-timer"; - interrupts = , /* cntpsirq */ - , /* cntpnsirq */ - , /* cntvirq */ - ; /* cnthpirq */ - }; - - pmu: pmu { - compatible = "arm,cortex-a72-pmu"; - /* Recommendation from GIC500 TRM Table A.3 */ - interrupts = ; - }; - - cbass_main: bus@100000 { - bootph-all; - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */ - <0x00 0x00600000 0x00 0x00600000 0x00 0x00031100>, /* GPIO */ - <0x00 0x00700000 0x00 0x00700000 0x00 0x00001000>, /* ESM */ - <0x00 0x01000000 0x00 0x01000000 0x00 0x0d000000>, /* Most peripherals */ - <0x00 0x04210000 0x00 0x04210000 0x00 0x00010000>, /* VPU0 */ - <0x00 0x04220000 0x00 0x04220000 0x00 0x00010000>, /* VPU1 */ - <0x00 0x0d000000 0x00 0x0d000000 0x00 0x00800000>, /* PCIe0 Core*/ - <0x00 0x0d800000 0x00 0x0d800000 0x00 0x00800000>, /* PCIe1 Core*/ - <0x00 0x0e000000 0x00 0x0e000000 0x00 0x00800000>, /* PCIe2 Core*/ - <0x00 0x0e800000 0x00 0x0e800000 0x00 0x00800000>, /* PCIe3 Core*/ - <0x00 0x10000000 0x00 0x10000000 0x00 0x08000000>, /* PCIe0 DAT0 */ - <0x00 0x18000000 0x00 0x18000000 0x00 0x08000000>, /* PCIe1 DAT0 */ - <0x00 0x64800000 0x00 0x64800000 0x00 0x0070c000>, /* C71_1 */ - <0x00 0x65800000 0x00 0x65800000 0x00 0x0070c000>, /* C71_2 */ - <0x00 0x66800000 0x00 0x66800000 0x00 0x0070c000>, /* C71_3 */ - <0x00 0x67800000 0x00 0x67800000 0x00 0x0070c000>, /* C71_4 */ - <0x00 0x6f000000 0x00 0x6f000000 0x00 0x00310000>, /* A72 PERIPHBASE */ - <0x00 0x70000000 0x00 0x70000000 0x00 0x00400000>, /* MSMC RAM */ - <0x00 0x30000000 0x00 0x30000000 0x00 0x0c400000>, /* MAIN NAVSS */ - <0x40 0x00000000 0x40 0x00000000 0x01 0x00000000>, /* PCIe0 DAT1 */ - <0x41 0x00000000 0x41 0x00000000 0x01 0x00000000>, /* PCIe1 DAT1 */ - <0x42 0x00000000 0x42 0x00000000 0x01 0x00000000>, /* PCIe2 DAT1 */ - <0x43 0x00000000 0x43 0x00000000 0x01 0x00000000>, /* PCIe3 DAT1 */ - <0x44 0x00000000 0x44 0x00000000 0x00 0x08000000>, /* PCIe2 DAT0 */ - <0x44 0x10000000 0x44 0x10000000 0x00 0x08000000>, /* PCIe3 DAT0 */ - <0x4e 0x20000000 0x4e 0x20000000 0x00 0x00080000>, /* GPU */ - - /* MCUSS_WKUP Range */ - <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, - <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, - <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, - <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, - <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, - <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, - <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, - <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, - <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, - <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, - <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, - <0x04 0x00000000 0x04 0x00000000 0x04 0x00000000>; - - cbass_mcu_wakeup: bus@28380000 { - bootph-all; - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x00 0x28380000 0x00 0x28380000 0x00 0x03880000>, /* MCU NAVSS*/ - <0x00 0x40200000 0x00 0x40200000 0x00 0x00998400>, /* First peripheral window */ - <0x00 0x40f00000 0x00 0x40f00000 0x00 0x00020000>, /* CTRL_MMR0 */ - <0x00 0x41000000 0x00 0x41000000 0x00 0x00020000>, /* MCU R5F Core0 */ - <0x00 0x41400000 0x00 0x41400000 0x00 0x00020000>, /* MCU R5F Core1 */ - <0x00 0x41c00000 0x00 0x41c00000 0x00 0x00100000>, /* MCU SRAM */ - <0x00 0x42040000 0x00 0x42040000 0x00 0x03ac2400>, /* WKUP peripheral window */ - <0x00 0x45100000 0x00 0x45100000 0x00 0x00c24000>, /* MMRs, remaining NAVSS */ - <0x00 0x46000000 0x00 0x46000000 0x00 0x00200000>, /* CPSW */ - <0x00 0x47000000 0x00 0x47000000 0x00 0x00068400>, /* OSPI register space */ - <0x00 0x50000000 0x00 0x50000000 0x00 0x10000000>, /* FSS data region 1 */ - <0x04 0x00000000 0x04 0x00000000 0x04 0x00000000>; /* FSS data region 0/3 */ - }; - }; - - thermal_zones: thermal-zones { - #include "k3-j784s4-thermal.dtsi" - }; }; -/* Now include peripherals from each bus segment */ #include "k3-j784s4-main.dtsi" -#include "k3-j784s4-mcu-wakeup.dtsi" diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.dts index 86e6c49905606c..bfa7ea6b9224ae 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.dts @@ -90,20 +90,6 @@ ds36-led { }; }; - ams { - compatible = "iio-hwmon"; - io-channels = <&xilinx_ams 0>, <&xilinx_ams 1>, <&xilinx_ams 2>, - <&xilinx_ams 3>, <&xilinx_ams 4>, <&xilinx_ams 5>, - <&xilinx_ams 6>, <&xilinx_ams 7>, <&xilinx_ams 8>, - <&xilinx_ams 9>, <&xilinx_ams 10>, <&xilinx_ams 11>, - <&xilinx_ams 12>, <&xilinx_ams 13>, <&xilinx_ams 14>, - <&xilinx_ams 15>, <&xilinx_ams 16>, <&xilinx_ams 17>, - <&xilinx_ams 18>, <&xilinx_ams 19>, <&xilinx_ams 20>, - <&xilinx_ams 21>, <&xilinx_ams 22>, <&xilinx_ams 23>, - <&xilinx_ams 24>, <&xilinx_ams 25>, <&xilinx_ams 26>, - <&xilinx_ams 27>, <&xilinx_ams 28>, <&xilinx_ams 29>; - }; - pwm-fan { compatible = "pwm-fan"; status = "okay"; @@ -366,10 +352,6 @@ &gpio { "", "", "", ""; /* 170 - 173 */ }; -&xilinx_ams { - status = "okay"; -}; - &ams_ps { status = "okay"; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts index c5945067cd5729..62c2503a502a4f 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts @@ -590,10 +590,6 @@ &watchdog0 { status = "okay"; }; -&xilinx_ams { - status = "okay"; -}; - &ams_ps { status = "okay"; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts index d2175f3dd09920..7e26489a1539a6 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts @@ -1028,10 +1028,6 @@ &watchdog0 { status = "okay"; }; -&xilinx_ams { - status = "okay"; -}; - &ams_ps { status = "okay"; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts index b1eca1bb6a633c..eb2090673ec18d 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts @@ -511,10 +511,6 @@ &watchdog0 { status = "okay"; }; -&xilinx_ams { - status = "okay"; -}; - &ams_ps { status = "okay"; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts index ddc74d963a05ed..4694d0a841f160 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts @@ -523,10 +523,6 @@ &watchdog0 { status = "okay"; }; -&xilinx_ams { - status = "okay"; -}; - &ams_ps { status = "okay"; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index b1b31dcf6291b0..467f084c6469da 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include / { compatible = "xlnx,zynqmp"; @@ -36,6 +37,7 @@ cpus { #size-cells = <0>; cpu0: cpu@0 { + #cooling-cells = <2>; compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "psci"; @@ -46,6 +48,7 @@ cpu0: cpu@0 { }; cpu1: cpu@1 { + #cooling-cells = <2>; compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "psci"; @@ -56,6 +59,7 @@ cpu1: cpu@1 { }; cpu2: cpu@2 { + #cooling-cells = <2>; compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "psci"; @@ -66,6 +70,7 @@ cpu2: cpu@2 { }; cpu3: cpu@3 { + #cooling-cells = <2>; compatible = "arm,cortex-a53"; device_type = "cpu"; enable-method = "psci"; @@ -392,6 +397,101 @@ r5f@1 { }; }; + ams { + compatible = "iio-hwmon"; + io-channels = <&xilinx_ams 0>, <&xilinx_ams 1>, <&xilinx_ams 2>, + <&xilinx_ams 3>, <&xilinx_ams 4>, <&xilinx_ams 5>, + <&xilinx_ams 6>, <&xilinx_ams 7>, <&xilinx_ams 8>, + <&xilinx_ams 9>, <&xilinx_ams 10>, <&xilinx_ams 11>, + <&xilinx_ams 12>, <&xilinx_ams 13>, <&xilinx_ams 14>, + <&xilinx_ams 15>, <&xilinx_ams 16>, <&xilinx_ams 17>, + <&xilinx_ams 18>, <&xilinx_ams 19>, <&xilinx_ams 20>, + <&xilinx_ams 21>, <&xilinx_ams 22>, <&xilinx_ams 23>, + <&xilinx_ams 24>, <&xilinx_ams 25>, <&xilinx_ams 26>, + <&xilinx_ams 27>, <&xilinx_ams 28>, <&xilinx_ams 29>; + }; + + + tsens_apu: thermal-sensor-apu { + compatible = "generic-adc-thermal"; + #thermal-sensor-cells = <0>; + io-channels = <&xilinx_ams 7>; + io-channel-names = "sensor-channel"; + }; + + tsens_rpu: thermal-sensor-rpu { + compatible = "generic-adc-thermal"; + #thermal-sensor-cells = <0>; + io-channels = <&xilinx_ams 8>; + io-channel-names = "sensor-channel"; + }; + + tsens_pl: thermal-sensor-pl { + compatible = "generic-adc-thermal"; + #thermal-sensor-cells = <0>; + io-channels = <&xilinx_ams 20>; + io-channel-names = "sensor-channel"; + }; + + thermal-zones { + apu-thermal { + polling-delay-passive = <1000>; + polling-delay = <5000>; + thermal-sensors = <&tsens_apu>; + + trips { + apu_passive: passive { + temperature = <93000>; + hysteresis = <3500>; + type = "passive"; + }; + + apu_critical: critical { + temperature = <96500>; + hysteresis = <3500>; + type = "critical"; + }; + }; + + cooling-maps { + map { + trip = <&apu_passive>; + cooling-device = + <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + rpu-thermal { + polling-delay = <10000>; + thermal-sensors = <&tsens_rpu>; + + trips { + critical { + temperature = <96500>; + hysteresis = <3500>; + type = "critical"; + }; + }; + }; + + pl-thermal { + polling-delay = <10000>; + thermal-sensors = <&tsens_pl>; + + trips { + critical { + temperature = <96500>; + hysteresis = <3500>; + type = "critical"; + }; + }; + }; + }; + amba: axi { compatible = "simple-bus"; bootph-all; @@ -1157,7 +1257,6 @@ lpd_watchdog: watchdog@ff150000 { xilinx_ams: ams@ffa50000 { compatible = "xlnx,zynqmp-ams"; - status = "disabled"; interrupt-parent = <&gic>; interrupts = ; reg = <0x0 0xffa50000 0x0 0x800>; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 5fdbfea7a5b295..c62831e6158633 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -659,6 +659,7 @@ CONFIG_GPIO_MAX732X=y CONFIG_GPIO_PCA953X=y CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_ADP5585=m +CONFIG_GPIO_PCF857X=m CONFIG_GPIO_BD9571MWV=m CONFIG_GPIO_MAX77620=y CONFIG_GPIO_SL28CPLD=m @@ -1221,6 +1222,7 @@ CONFIG_RTC_DRV_IMX_SC=m CONFIG_RTC_DRV_MT6397=m CONFIG_RTC_DRV_XGENE=y CONFIG_RTC_DRV_TI_K3=m +CONFIG_RTC_DRV_RENESAS_RTCA3=m CONFIG_DMADEVICES=y CONFIG_DMA_BCM2835=y CONFIG_DMA_SUN6I=m @@ -1323,6 +1325,7 @@ CONFIG_MSM_MMCC_8998=m CONFIG_QCM_GCC_2290=y CONFIG_QCM_DISPCC_2290=m CONFIG_QCS_GCC_404=y +CONFIG_SC_CAMCC_7280=m CONFIG_QDU_GCC_1000=y CONFIG_SC_CAMCC_8280XP=m CONFIG_SC_DISPCC_7280=m @@ -1336,6 +1339,8 @@ CONFIG_SC_GCC_8280XP=y CONFIG_SC_GPUCC_7280=m CONFIG_SC_GPUCC_8280XP=m CONFIG_SC_LPASSCC_8280XP=m +CONFIG_SC_LPASS_CORECC_7280=m +CONFIG_SC_VIDEOCC_7280=m CONFIG_SDM_CAMCC_845=m CONFIG_SDM_GPUCC_845=y CONFIG_SDM_VIDEOCC_845=y @@ -1367,6 +1372,7 @@ CONFIG_SM_VIDEOCC_8250=y CONFIG_QCOM_HFPLL=y CONFIG_CLK_GFM_LPASS_SM8250=m CONFIG_CLK_RCAR_USB2_CLOCK_SEL=y +CONFIG_CLK_RENESAS_VBATTB=m CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_TEGRA186_TIMER=y @@ -1472,6 +1478,7 @@ CONFIG_ARM_MEDIATEK_CCI_DEVFREQ=m CONFIG_EXTCON_PTN5150=m CONFIG_EXTCON_USB_GPIO=y CONFIG_EXTCON_USBC_CROS_EC=y +CONFIG_FSL_IFC=y CONFIG_RENESAS_RPCIF=m CONFIG_IIO=y CONFIG_EXYNOS_ADC=y diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index a523b519700f51..a2b5d6f20f4d15 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -18,7 +18,7 @@ #include "aes-ce-setkey.h" -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); static int num_rounds(struct crypto_aes_ctx *ctx) { diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c index a147e847a5a181..b0150999743f68 100644 --- a/arch/arm64/crypto/aes-glue.c +++ b/arch/arm64/crypto/aes-glue.c @@ -1048,7 +1048,7 @@ static int __init aes_init(void) #ifdef USE_V8_CRYPTO_EXTENSIONS module_cpu_feature_match(AES, aes_init); -EXPORT_SYMBOL_NS(ce_aes_mac_update, CRYPTO_INTERNAL); +EXPORT_SYMBOL_NS(ce_aes_mac_update, "CRYPTO_INTERNAL"); #else module_init(aes_init); EXPORT_SYMBOL(neon_aes_ecb_encrypt); diff --git a/arch/arm64/crypto/crct10dif-ce-core.S b/arch/arm64/crypto/crct10dif-ce-core.S index 5604de61d06d04..87dd6d46224d8c 100644 --- a/arch/arm64/crypto/crct10dif-ce-core.S +++ b/arch/arm64/crypto/crct10dif-ce-core.S @@ -1,8 +1,11 @@ // // Accelerated CRC-T10DIF using arm64 NEON and Crypto Extensions instructions // -// Copyright (C) 2016 Linaro Ltd -// Copyright (C) 2019 Google LLC +// Copyright (C) 2016 Linaro Ltd +// Copyright (C) 2019-2024 Google LLC +// +// Authors: Ard Biesheuvel +// Eric Biggers // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as @@ -71,161 +74,117 @@ init_crc .req w0 buf .req x1 len .req x2 - fold_consts_ptr .req x3 + fold_consts_ptr .req x5 fold_consts .req v10 - ad .req v14 - - k00_16 .req v15 - k32_48 .req v16 - t3 .req v17 t4 .req v18 t5 .req v19 t6 .req v20 t7 .req v21 t8 .req v22 - t9 .req v23 - perm1 .req v24 - perm2 .req v25 - perm3 .req v26 - perm4 .req v27 - - bd1 .req v28 - bd2 .req v29 - bd3 .req v30 - bd4 .req v31 - - .macro __pmull_init_p64 - .endm + perm .req v27 - .macro __pmull_pre_p64, bd + .macro pmull16x64_p64, a16, b64, c64 + pmull2 \c64\().1q, \a16\().2d, \b64\().2d + pmull \b64\().1q, \a16\().1d, \b64\().1d .endm - .macro __pmull_init_p8 - // k00_16 := 0x0000000000000000_000000000000ffff - // k32_48 := 0x00000000ffffffff_0000ffffffffffff - movi k32_48.2d, #0xffffffff - mov k32_48.h[2], k32_48.h[0] - ushr k00_16.2d, k32_48.2d, #32 - - // prepare the permutation vectors - mov_q x5, 0x080f0e0d0c0b0a09 - movi perm4.8b, #8 - dup perm1.2d, x5 - eor perm1.16b, perm1.16b, perm4.16b - ushr perm2.2d, perm1.2d, #8 - ushr perm3.2d, perm1.2d, #16 - ushr perm4.2d, perm1.2d, #24 - sli perm2.2d, perm1.2d, #56 - sli perm3.2d, perm1.2d, #48 - sli perm4.2d, perm1.2d, #40 + /* + * Pairwise long polynomial multiplication of two 16-bit values + * + * { w0, w1 }, { y0, y1 } + * + * by two 64-bit values + * + * { x0, x1, x2, x3, x4, x5, x6, x7 }, { z0, z1, z2, z3, z4, z5, z6, z7 } + * + * where each vector element is a byte, ordered from least to most + * significant. + * + * This can be implemented using 8x8 long polynomial multiplication, by + * reorganizing the input so that each pairwise 8x8 multiplication + * produces one of the terms from the decomposition below, and + * combining the results of each rank and shifting them into place. + * + * Rank + * 0 w0*x0 ^ | y0*z0 ^ + * 1 (w0*x1 ^ w1*x0) << 8 ^ | (y0*z1 ^ y1*z0) << 8 ^ + * 2 (w0*x2 ^ w1*x1) << 16 ^ | (y0*z2 ^ y1*z1) << 16 ^ + * 3 (w0*x3 ^ w1*x2) << 24 ^ | (y0*z3 ^ y1*z2) << 24 ^ + * 4 (w0*x4 ^ w1*x3) << 32 ^ | (y0*z4 ^ y1*z3) << 32 ^ + * 5 (w0*x5 ^ w1*x4) << 40 ^ | (y0*z5 ^ y1*z4) << 40 ^ + * 6 (w0*x6 ^ w1*x5) << 48 ^ | (y0*z6 ^ y1*z5) << 48 ^ + * 7 (w0*x7 ^ w1*x6) << 56 ^ | (y0*z7 ^ y1*z6) << 56 ^ + * 8 w1*x7 << 64 | y1*z7 << 64 + * + * The inputs can be reorganized into + * + * { w0, w0, w0, w0, y0, y0, y0, y0 }, { w1, w1, w1, w1, y1, y1, y1, y1 } + * { x0, x2, x4, x6, z0, z2, z4, z6 }, { x1, x3, x5, x7, z1, z3, z5, z7 } + * + * and after performing 8x8->16 bit long polynomial multiplication of + * each of the halves of the first vector with those of the second one, + * we obtain the following four vectors of 16-bit elements: + * + * a := { w0*x0, w0*x2, w0*x4, w0*x6 }, { y0*z0, y0*z2, y0*z4, y0*z6 } + * b := { w0*x1, w0*x3, w0*x5, w0*x7 }, { y0*z1, y0*z3, y0*z5, y0*z7 } + * c := { w1*x0, w1*x2, w1*x4, w1*x6 }, { y1*z0, y1*z2, y1*z4, y1*z6 } + * d := { w1*x1, w1*x3, w1*x5, w1*x7 }, { y1*z1, y1*z3, y1*z5, y1*z7 } + * + * Results b and c can be XORed together, as the vector elements have + * matching ranks. Then, the final XOR (*) can be pulled forward, and + * applied between the halves of each of the remaining three vectors, + * which are then shifted into place, and combined to produce two + * 80-bit results. + * + * (*) NOTE: the 16x64 bit polynomial multiply below is not equivalent + * to the 64x64 bit one above, but XOR'ing the outputs together will + * produce the expected result, and this is sufficient in the context of + * this algorithm. + */ + .macro pmull16x64_p8, a16, b64, c64 + ext t7.16b, \b64\().16b, \b64\().16b, #1 + tbl t5.16b, {\a16\().16b}, perm.16b + uzp1 t7.16b, \b64\().16b, t7.16b + bl __pmull_p8_16x64 + ext \b64\().16b, t4.16b, t4.16b, #15 + eor \c64\().16b, t8.16b, t5.16b .endm - .macro __pmull_pre_p8, bd - tbl bd1.16b, {\bd\().16b}, perm1.16b - tbl bd2.16b, {\bd\().16b}, perm2.16b - tbl bd3.16b, {\bd\().16b}, perm3.16b - tbl bd4.16b, {\bd\().16b}, perm4.16b - .endm - -SYM_FUNC_START_LOCAL(__pmull_p8_core) -.L__pmull_p8_core: - ext t4.8b, ad.8b, ad.8b, #1 // A1 - ext t5.8b, ad.8b, ad.8b, #2 // A2 - ext t6.8b, ad.8b, ad.8b, #3 // A3 - - pmull t4.8h, t4.8b, fold_consts.8b // F = A1*B - pmull t8.8h, ad.8b, bd1.8b // E = A*B1 - pmull t5.8h, t5.8b, fold_consts.8b // H = A2*B - pmull t7.8h, ad.8b, bd2.8b // G = A*B2 - pmull t6.8h, t6.8b, fold_consts.8b // J = A3*B - pmull t9.8h, ad.8b, bd3.8b // I = A*B3 - pmull t3.8h, ad.8b, bd4.8b // K = A*B4 - b 0f - -.L__pmull_p8_core2: - tbl t4.16b, {ad.16b}, perm1.16b // A1 - tbl t5.16b, {ad.16b}, perm2.16b // A2 - tbl t6.16b, {ad.16b}, perm3.16b // A3 - - pmull2 t4.8h, t4.16b, fold_consts.16b // F = A1*B - pmull2 t8.8h, ad.16b, bd1.16b // E = A*B1 - pmull2 t5.8h, t5.16b, fold_consts.16b // H = A2*B - pmull2 t7.8h, ad.16b, bd2.16b // G = A*B2 - pmull2 t6.8h, t6.16b, fold_consts.16b // J = A3*B - pmull2 t9.8h, ad.16b, bd3.16b // I = A*B3 - pmull2 t3.8h, ad.16b, bd4.16b // K = A*B4 - -0: eor t4.16b, t4.16b, t8.16b // L = E + F - eor t5.16b, t5.16b, t7.16b // M = G + H - eor t6.16b, t6.16b, t9.16b // N = I + J - - uzp1 t8.2d, t4.2d, t5.2d - uzp2 t4.2d, t4.2d, t5.2d - uzp1 t7.2d, t6.2d, t3.2d - uzp2 t6.2d, t6.2d, t3.2d - - // t4 = (L) (P0 + P1) << 8 - // t5 = (M) (P2 + P3) << 16 - eor t8.16b, t8.16b, t4.16b - and t4.16b, t4.16b, k32_48.16b - - // t6 = (N) (P4 + P5) << 24 - // t7 = (K) (P6 + P7) << 32 - eor t7.16b, t7.16b, t6.16b - and t6.16b, t6.16b, k00_16.16b - - eor t8.16b, t8.16b, t4.16b - eor t7.16b, t7.16b, t6.16b - - zip2 t5.2d, t8.2d, t4.2d - zip1 t4.2d, t8.2d, t4.2d - zip2 t3.2d, t7.2d, t6.2d - zip1 t6.2d, t7.2d, t6.2d - - ext t4.16b, t4.16b, t4.16b, #15 +SYM_FUNC_START_LOCAL(__pmull_p8_16x64) + ext t6.16b, t5.16b, t5.16b, #8 + + pmull t3.8h, t7.8b, t5.8b + pmull t4.8h, t7.8b, t6.8b + pmull2 t5.8h, t7.16b, t5.16b + pmull2 t6.8h, t7.16b, t6.16b + + ext t8.16b, t3.16b, t3.16b, #8 + eor t4.16b, t4.16b, t6.16b + ext t7.16b, t5.16b, t5.16b, #8 + ext t6.16b, t4.16b, t4.16b, #8 + eor t8.8b, t8.8b, t3.8b + eor t5.8b, t5.8b, t7.8b + eor t4.8b, t4.8b, t6.8b ext t5.16b, t5.16b, t5.16b, #14 - ext t6.16b, t6.16b, t6.16b, #13 - ext t3.16b, t3.16b, t3.16b, #12 - - eor t4.16b, t4.16b, t5.16b - eor t6.16b, t6.16b, t3.16b ret -SYM_FUNC_END(__pmull_p8_core) +SYM_FUNC_END(__pmull_p8_16x64) - .macro __pmull_p8, rq, ad, bd, i - .ifnc \bd, fold_consts - .err - .endif - mov ad.16b, \ad\().16b - .ifb \i - pmull \rq\().8h, \ad\().8b, \bd\().8b // D = A*B - .else - pmull2 \rq\().8h, \ad\().16b, \bd\().16b // D = A*B - .endif - - bl .L__pmull_p8_core\i - - eor \rq\().16b, \rq\().16b, t4.16b - eor \rq\().16b, \rq\().16b, t6.16b - .endm // Fold reg1, reg2 into the next 32 data bytes, storing the result back // into reg1, reg2. .macro fold_32_bytes, p, reg1, reg2 ldp q11, q12, [buf], #0x20 - __pmull_\p v8, \reg1, fold_consts, 2 - __pmull_\p \reg1, \reg1, fold_consts + pmull16x64_\p fold_consts, \reg1, v8 CPU_LE( rev64 v11.16b, v11.16b ) CPU_LE( rev64 v12.16b, v12.16b ) - __pmull_\p v9, \reg2, fold_consts, 2 - __pmull_\p \reg2, \reg2, fold_consts + pmull16x64_\p fold_consts, \reg2, v9 CPU_LE( ext v11.16b, v11.16b, v11.16b, #8 ) CPU_LE( ext v12.16b, v12.16b, v12.16b, #8 ) @@ -238,26 +197,15 @@ CPU_LE( ext v12.16b, v12.16b, v12.16b, #8 ) // Fold src_reg into dst_reg, optionally loading the next fold constants .macro fold_16_bytes, p, src_reg, dst_reg, load_next_consts - __pmull_\p v8, \src_reg, fold_consts - __pmull_\p \src_reg, \src_reg, fold_consts, 2 + pmull16x64_\p fold_consts, \src_reg, v8 .ifnb \load_next_consts ld1 {fold_consts.2d}, [fold_consts_ptr], #16 - __pmull_pre_\p fold_consts .endif eor \dst_reg\().16b, \dst_reg\().16b, v8.16b eor \dst_reg\().16b, \dst_reg\().16b, \src_reg\().16b .endm - .macro __pmull_p64, rd, rn, rm, n - .ifb \n - pmull \rd\().1q, \rn\().1d, \rm\().1d - .else - pmull2 \rd\().1q, \rn\().2d, \rm\().2d - .endif - .endm - .macro crc_t10dif_pmull, p - __pmull_init_\p // For sizes less than 256 bytes, we can't fold 128 bytes at a time. cmp len, #256 @@ -296,7 +244,6 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) // Load the constants for folding across 128 bytes. ld1 {fold_consts.2d}, [fold_consts_ptr] - __pmull_pre_\p fold_consts // Subtract 128 for the 128 data bytes just consumed. Subtract another // 128 to simplify the termination condition of the following loop. @@ -318,7 +265,6 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) // Fold across 64 bytes. add fold_consts_ptr, fold_consts_ptr, #16 ld1 {fold_consts.2d}, [fold_consts_ptr], #16 - __pmull_pre_\p fold_consts fold_16_bytes \p, v0, v4 fold_16_bytes \p, v1, v5 fold_16_bytes \p, v2, v6 @@ -339,8 +285,7 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) // into them, storing the result back into v7. b.lt .Lfold_16_bytes_loop_done_\@ .Lfold_16_bytes_loop_\@: - __pmull_\p v8, v7, fold_consts - __pmull_\p v7, v7, fold_consts, 2 + pmull16x64_\p fold_consts, v7, v8 eor v7.16b, v7.16b, v8.16b ldr q0, [buf], #16 CPU_LE( rev64 v0.16b, v0.16b ) @@ -387,51 +332,10 @@ CPU_LE( ext v0.16b, v0.16b, v0.16b, #8 ) bsl v2.16b, v1.16b, v0.16b // Fold the first chunk into the second chunk, storing the result in v7. - __pmull_\p v0, v3, fold_consts - __pmull_\p v7, v3, fold_consts, 2 - eor v7.16b, v7.16b, v0.16b + pmull16x64_\p fold_consts, v3, v0 + eor v7.16b, v3.16b, v0.16b eor v7.16b, v7.16b, v2.16b - -.Lreduce_final_16_bytes_\@: - // Reduce the 128-bit value M(x), stored in v7, to the final 16-bit CRC. - - movi v2.16b, #0 // init zero register - - // Load 'x^48 * (x^48 mod G(x))' and 'x^48 * (x^80 mod G(x))'. - ld1 {fold_consts.2d}, [fold_consts_ptr], #16 - __pmull_pre_\p fold_consts - - // Fold the high 64 bits into the low 64 bits, while also multiplying by - // x^64. This produces a 128-bit value congruent to x^64 * M(x) and - // whose low 48 bits are 0. - ext v0.16b, v2.16b, v7.16b, #8 - __pmull_\p v7, v7, fold_consts, 2 // high bits * x^48 * (x^80 mod G(x)) - eor v0.16b, v0.16b, v7.16b // + low bits * x^64 - - // Fold the high 32 bits into the low 96 bits. This produces a 96-bit - // value congruent to x^64 * M(x) and whose low 48 bits are 0. - ext v1.16b, v0.16b, v2.16b, #12 // extract high 32 bits - mov v0.s[3], v2.s[0] // zero high 32 bits - __pmull_\p v1, v1, fold_consts // high 32 bits * x^48 * (x^48 mod G(x)) - eor v0.16b, v0.16b, v1.16b // + low bits - - // Load G(x) and floor(x^48 / G(x)). - ld1 {fold_consts.2d}, [fold_consts_ptr] - __pmull_pre_\p fold_consts - - // Use Barrett reduction to compute the final CRC value. - __pmull_\p v1, v0, fold_consts, 2 // high 32 bits * floor(x^48 / G(x)) - ushr v1.2d, v1.2d, #32 // /= x^32 - __pmull_\p v1, v1, fold_consts // *= G(x) - ushr v0.2d, v0.2d, #48 - eor v0.16b, v0.16b, v1.16b // + low 16 nonzero bits - // Final CRC value (x^16 * M(x)) mod G(x) is in low 16 bits of v0. - - umov w0, v0.h[0] - .ifc \p, p8 - frame_pop - .endif - ret + b .Lreduce_final_16_bytes_\@ .Lless_than_256_bytes_\@: // Checksumming a buffer of length 16...255 bytes @@ -450,7 +354,6 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) // Load the fold-across-16-bytes constants. ld1 {fold_consts.2d}, [fold_consts_ptr], #16 - __pmull_pre_\p fold_consts cmp len, #16 b.eq .Lreduce_final_16_bytes_\@ // len == 16 @@ -458,6 +361,8 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) b.ge .Lfold_16_bytes_loop_\@ // 32 <= len <= 255 add len, len, #16 b .Lhandle_partial_segment_\@ // 17 <= len <= 31 + +.Lreduce_final_16_bytes_\@: .endm // @@ -467,7 +372,22 @@ CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) // SYM_FUNC_START(crc_t10dif_pmull_p8) frame_push 1 + + // Compose { 0,0,0,0, 8,8,8,8, 1,1,1,1, 9,9,9,9 } + movi perm.4h, #8, lsl #8 + orr perm.2s, #1, lsl #16 + orr perm.2s, #1, lsl #24 + zip1 perm.16b, perm.16b, perm.16b + zip1 perm.16b, perm.16b, perm.16b + crc_t10dif_pmull p8 + +CPU_LE( rev64 v7.16b, v7.16b ) +CPU_LE( ext v7.16b, v7.16b, v7.16b, #8 ) + str q7, [x3] + + frame_pop + ret SYM_FUNC_END(crc_t10dif_pmull_p8) .align 5 @@ -478,6 +398,41 @@ SYM_FUNC_END(crc_t10dif_pmull_p8) // SYM_FUNC_START(crc_t10dif_pmull_p64) crc_t10dif_pmull p64 + + // Reduce the 128-bit value M(x), stored in v7, to the final 16-bit CRC. + + movi v2.16b, #0 // init zero register + + // Load 'x^48 * (x^48 mod G(x))' and 'x^48 * (x^80 mod G(x))'. + ld1 {fold_consts.2d}, [fold_consts_ptr], #16 + + // Fold the high 64 bits into the low 64 bits, while also multiplying by + // x^64. This produces a 128-bit value congruent to x^64 * M(x) and + // whose low 48 bits are 0. + ext v0.16b, v2.16b, v7.16b, #8 + pmull2 v7.1q, v7.2d, fold_consts.2d // high bits * x^48 * (x^80 mod G(x)) + eor v0.16b, v0.16b, v7.16b // + low bits * x^64 + + // Fold the high 32 bits into the low 96 bits. This produces a 96-bit + // value congruent to x^64 * M(x) and whose low 48 bits are 0. + ext v1.16b, v0.16b, v2.16b, #12 // extract high 32 bits + mov v0.s[3], v2.s[0] // zero high 32 bits + pmull v1.1q, v1.1d, fold_consts.1d // high 32 bits * x^48 * (x^48 mod G(x)) + eor v0.16b, v0.16b, v1.16b // + low bits + + // Load G(x) and floor(x^48 / G(x)). + ld1 {fold_consts.2d}, [fold_consts_ptr] + + // Use Barrett reduction to compute the final CRC value. + pmull2 v1.1q, v0.2d, fold_consts.2d // high 32 bits * floor(x^48 / G(x)) + ushr v1.2d, v1.2d, #32 // /= x^32 + pmull v1.1q, v1.1d, fold_consts.1d // *= G(x) + ushr v0.2d, v0.2d, #48 + eor v0.16b, v0.16b, v1.16b // + low 16 nonzero bits + // Final CRC value (x^16 * M(x)) mod G(x) is in low 16 bits of v0. + + umov w0, v0.h[0] + ret SYM_FUNC_END(crc_t10dif_pmull_p64) .section ".rodata", "a" diff --git a/arch/arm64/crypto/crct10dif-ce-glue.c b/arch/arm64/crypto/crct10dif-ce-glue.c index 606d25c559ed88..08bcbd884395f4 100644 --- a/arch/arm64/crypto/crct10dif-ce-glue.c +++ b/arch/arm64/crypto/crct10dif-ce-glue.c @@ -20,7 +20,8 @@ #define CRC_T10DIF_PMULL_CHUNK_SIZE 16U -asmlinkage u16 crc_t10dif_pmull_p8(u16 init_crc, const u8 *buf, size_t len); +asmlinkage void crc_t10dif_pmull_p8(u16 init_crc, const u8 *buf, size_t len, + u8 out[16]); asmlinkage u16 crc_t10dif_pmull_p64(u16 init_crc, const u8 *buf, size_t len); static int crct10dif_init(struct shash_desc *desc) @@ -34,25 +35,21 @@ static int crct10dif_init(struct shash_desc *desc) static int crct10dif_update_pmull_p8(struct shash_desc *desc, const u8 *data, unsigned int length) { - u16 *crc = shash_desc_ctx(desc); - - if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) { - do { - unsigned int chunk = length; - - if (chunk > SZ_4K + CRC_T10DIF_PMULL_CHUNK_SIZE) - chunk = SZ_4K; - - kernel_neon_begin(); - *crc = crc_t10dif_pmull_p8(*crc, data, chunk); - kernel_neon_end(); - data += chunk; - length -= chunk; - } while (length); - } else { - *crc = crc_t10dif_generic(*crc, data, length); + u16 *crcp = shash_desc_ctx(desc); + u16 crc = *crcp; + u8 buf[16]; + + if (length > CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) { + kernel_neon_begin(); + crc_t10dif_pmull_p8(crc, data, length, buf); + kernel_neon_end(); + + crc = 0; + data = buf; + length = sizeof(buf); } + *crcp = crc_t10dif_generic(crc, data, length); return 0; } @@ -62,18 +59,9 @@ static int crct10dif_update_pmull_p64(struct shash_desc *desc, const u8 *data, u16 *crc = shash_desc_ctx(desc); if (length >= CRC_T10DIF_PMULL_CHUNK_SIZE && crypto_simd_usable()) { - do { - unsigned int chunk = length; - - if (chunk > SZ_4K + CRC_T10DIF_PMULL_CHUNK_SIZE) - chunk = SZ_4K; - - kernel_neon_begin(); - *crc = crc_t10dif_pmull_p64(*crc, data, chunk); - kernel_neon_end(); - data += chunk; - length -= chunk; - } while (length); + kernel_neon_begin(); + *crc = crc_t10dif_pmull_p64(*crc, data, length); + kernel_neon_end(); } else { *crc = crc_t10dif_generic(*crc, data, length); } diff --git a/arch/arm64/include/asm/arm_pmuv3.h b/arch/arm64/include/asm/arm_pmuv3.h index 468a049bc63b59..8a777dec8d88ab 100644 --- a/arch/arm64/include/asm/arm_pmuv3.h +++ b/arch/arm64/include/asm/arm_pmuv3.h @@ -152,6 +152,11 @@ static inline void write_pmuserenr(u32 val) write_sysreg(val, pmuserenr_el0); } +static inline void write_pmuacr(u64 val) +{ + write_sysreg_s(val, SYS_PMUACR_EL1); +} + static inline u64 read_pmceid0(void) { return read_sysreg(pmceid0_el0); @@ -178,4 +183,9 @@ static inline bool is_pmuv3p5(int pmuver) return pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P5; } +static inline bool is_pmuv3p9(int pmuver) +{ + return pmuver >= ID_AA64DFR0_EL1_PMUVer_V3P9; +} + #endif diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index bc0b0d75acef7b..3d8d534a7a77c2 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -248,13 +248,6 @@ alternative_endif ldr \dst, [\dst, \tmp] .endm -/* - * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm) - */ - .macro vma_vm_mm, rd, rn - ldr \rd, [\rn, #VMA_VM_MM] - .endm - /* * read_ctr - read CTR_EL0. If the system has mismatched register fields, * provide the system wide safe value from arm64_ftr_reg_ctrel0.sys_val diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h index 9b73fd0cd72124..81e4157f92b741 100644 --- a/arch/arm64/include/asm/cpu.h +++ b/arch/arm64/include/asm/cpu.h @@ -46,6 +46,7 @@ struct cpuinfo_arm64 { u64 reg_revidr; u64 reg_gmid; u64 reg_smidr; + u64 reg_mpamidr; u64 reg_id_aa64dfr0; u64 reg_id_aa64dfr1; diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index a6e5b07b64fd55..cbbf70e0f20485 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -42,6 +42,10 @@ cpucap_is_possible(const unsigned int cap) return IS_ENABLED(CONFIG_ARM64_BTI); case ARM64_HAS_TLB_RANGE: return IS_ENABLED(CONFIG_ARM64_TLB_RANGE); + case ARM64_HAS_S1POE: + return IS_ENABLED(CONFIG_ARM64_POE); + case ARM64_HAS_GCS: + return IS_ENABLED(CONFIG_ARM64_GCS); case ARM64_UNMAP_KERNEL_AT_EL0: return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0); case ARM64_WORKAROUND_843419: @@ -60,6 +64,11 @@ cpucap_is_possible(const unsigned int cap) return IS_ENABLED(CONFIG_ARM64_WORKAROUND_REPEAT_TLBI); case ARM64_WORKAROUND_SPECULATIVE_SSBS: return IS_ENABLED(CONFIG_ARM64_ERRATUM_3194386); + case ARM64_MPAM: + /* + * KVM MPAM support doesn't rely on the host kernel supporting MPAM. + */ + return true; } return true; diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 3d261cc123c1e2..8b4e5a3cd24c80 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -12,7 +12,7 @@ #include #include -#define MAX_CPU_FEATURES 128 +#define MAX_CPU_FEATURES 192 #define cpu_feature(x) KERNEL_HWCAP_ ## x #define ARM64_SW_FEATURE_OVERRIDE_NOKASLR 0 @@ -438,6 +438,7 @@ void cpu_set_feature(unsigned int num); bool cpu_have_feature(unsigned int num); unsigned long cpu_get_elf_hwcap(void); unsigned long cpu_get_elf_hwcap2(void); +unsigned long cpu_get_elf_hwcap3(void); #define cpu_set_named_feature(name) cpu_set_feature(cpu_feature(name)) #define cpu_have_named_feature(name) cpu_have_feature(cpu_feature(name)) @@ -612,6 +613,13 @@ static inline bool id_aa64pfr1_sme(u64 pfr1) return val > 0; } +static inline bool id_aa64pfr0_mpam(u64 pfr0) +{ + u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_MPAM_SHIFT); + + return val > 0; +} + static inline bool id_aa64pfr1_mte(u64 pfr1) { u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_EL1_MTE_SHIFT); @@ -834,8 +842,28 @@ static inline bool system_supports_lpa2(void) static inline bool system_supports_poe(void) { - return IS_ENABLED(CONFIG_ARM64_POE) && - alternative_has_cap_unlikely(ARM64_HAS_S1POE); + return alternative_has_cap_unlikely(ARM64_HAS_S1POE); +} + +static inline bool system_supports_gcs(void) +{ + return alternative_has_cap_unlikely(ARM64_HAS_GCS); +} + +static inline bool system_supports_haft(void) +{ + return IS_ENABLED(CONFIG_ARM64_HAFT) && + cpus_have_final_cap(ARM64_HAFT); +} + +static __always_inline bool system_supports_mpam(void) +{ + return alternative_has_cap_unlikely(ARM64_MPAM); +} + +static __always_inline bool system_supports_mpam_hcr(void) +{ + return alternative_has_cap_unlikely(ARM64_MPAM_HCR); } int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); diff --git a/arch/arm64/include/asm/daifflags.h b/arch/arm64/include/asm/daifflags.h index 55f57dfa8e2fe0..fbb5c99eb2f9d6 100644 --- a/arch/arm64/include/asm/daifflags.h +++ b/arch/arm64/include/asm/daifflags.h @@ -132,7 +132,7 @@ static inline void local_daif_inherit(struct pt_regs *regs) trace_hardirqs_on(); if (system_uses_irq_prio_masking()) - gic_write_pmr(regs->pmr_save); + gic_write_pmr(regs->pmr); /* * We can't use local_daif_restore(regs->pstate) here as diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index 13d437bcbf58c2..8f6ba31b865828 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -105,6 +105,7 @@ void kernel_enable_single_step(struct pt_regs *regs); void kernel_disable_single_step(void); int kernel_active_single_step(void); void kernel_rewind_single_step(struct pt_regs *regs); +void kernel_fastforward_single_step(struct pt_regs *regs); #ifdef CONFIG_HAVE_HW_BREAKPOINT int reinstall_suspended_bps(struct pt_regs *regs); diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h index e0ffdf13a18b3f..4ef52d7245bbb7 100644 --- a/arch/arm64/include/asm/el2_setup.h +++ b/arch/arm64/include/asm/el2_setup.h @@ -27,6 +27,14 @@ ubfx x0, x0, #ID_AA64MMFR1_EL1_HCX_SHIFT, #4 cbz x0, .Lskip_hcrx_\@ mov_q x0, HCRX_HOST_FLAGS + + /* Enable GCS if supported */ + mrs_s x1, SYS_ID_AA64PFR1_EL1 + ubfx x1, x1, #ID_AA64PFR1_EL1_GCS_SHIFT, #4 + cbz x1, .Lset_hcrx_\@ + orr x0, x0, #HCRX_EL2_GCSEn + +.Lset_hcrx_\@: msr_s SYS_HCRX_EL2, x0 .Lskip_hcrx_\@: .endm @@ -79,7 +87,7 @@ 1 << PMSCR_EL2_PA_SHIFT) msr_s SYS_PMSCR_EL2, x0 // addresses and physical counter .Lskip_spe_el2_\@: - mov x0, #(MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT) + mov x0, #MDCR_EL2_E2PB_MASK orr x2, x2, x0 // If we don't have VHE, then // use EL1&0 translation. @@ -92,7 +100,7 @@ and x0, x0, TRBIDR_EL1_P cbnz x0, .Lskip_trace_\@ // If TRBE is available at EL2 - mov x0, #(MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT) + mov x0, #MDCR_EL2_E2TB_MASK orr x2, x2, x0 // allow the EL1&0 translation // to own it. @@ -200,6 +208,16 @@ orr x0, x0, #HFGxTR_EL2_nPOR_EL0 .Lskip_poe_fgt_\@: + /* GCS depends on PIE so we don't check it if PIE is absent */ + mrs_s x1, SYS_ID_AA64PFR1_EL1 + ubfx x1, x1, #ID_AA64PFR1_EL1_GCS_SHIFT, #4 + cbz x1, .Lset_fgt_\@ + + /* Disable traps of access to GCS registers at EL0 and EL1 */ + orr x0, x0, #HFGxTR_EL2_nGCS_EL1_MASK + orr x0, x0, #HFGxTR_EL2_nGCS_EL0_MASK + +.Lset_fgt_\@: msr_s SYS_HFGRTR_EL2, x0 msr_s SYS_HFGWTR_EL2, x0 msr_s SYS_HFGITR_EL2, xzr @@ -215,11 +233,35 @@ .Lskip_fgt_\@: .endm +.macro __init_el2_gcs + mrs_s x1, SYS_ID_AA64PFR1_EL1 + ubfx x1, x1, #ID_AA64PFR1_EL1_GCS_SHIFT, #4 + cbz x1, .Lskip_gcs_\@ + + /* Ensure GCS is not enabled when we start trying to do BLs */ + msr_s SYS_GCSCR_EL1, xzr + msr_s SYS_GCSCRE0_EL1, xzr +.Lskip_gcs_\@: +.endm + .macro __init_el2_nvhe_prepare_eret mov x0, #INIT_PSTATE_EL1 msr spsr_el2, x0 .endm +.macro __init_el2_mpam + /* Memory Partitioning And Monitoring: disable EL2 traps */ + mrs x1, id_aa64pfr0_el1 + ubfx x0, x1, #ID_AA64PFR0_EL1_MPAM_SHIFT, #4 + cbz x0, .Lskip_mpam_\@ // skip if no MPAM + msr_s SYS_MPAM2_EL2, xzr // use the default partition + // and disable lower traps + mrs_s x0, SYS_MPAMIDR_EL1 + tbz x0, #MPAMIDR_EL1_HAS_HCR_SHIFT, .Lskip_mpam_\@ // skip if no MPAMHCR reg + msr_s SYS_MPAMHCR_EL2, xzr // clear TRAP_MPAMIDR_EL1 -> EL2 +.Lskip_mpam_\@: +.endm + /** * Initialize EL2 registers to sane values. This should be called early on all * cores that were booted in EL2. Note that everything gets initialised as @@ -237,9 +279,11 @@ __init_el2_stage2 __init_el2_gicv3 __init_el2_hstr + __init_el2_mpam __init_el2_nvhe_idregs __init_el2_cptr __init_el2_fgt + __init_el2_gcs .endm #ifndef __KVM_NVHE_HYPERVISOR__ diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index da6d2c1c0b030c..d1b1a33f9a8b0d 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -51,7 +51,8 @@ #define ESR_ELx_EC_FP_EXC32 UL(0x28) /* Unallocated EC: 0x29 - 0x2B */ #define ESR_ELx_EC_FP_EXC64 UL(0x2C) -/* Unallocated EC: 0x2D - 0x2E */ +#define ESR_ELx_EC_GCS UL(0x2D) +/* Unallocated EC: 0x2E */ #define ESR_ELx_EC_SERROR UL(0x2F) #define ESR_ELx_EC_BREAKPT_LOW UL(0x30) #define ESR_ELx_EC_BREAKPT_CUR UL(0x31) @@ -386,6 +387,31 @@ #define ESR_ELx_MOPS_ISS_SRCREG(esr) (((esr) & (UL(0x1f) << 5)) >> 5) #define ESR_ELx_MOPS_ISS_SIZEREG(esr) (((esr) & (UL(0x1f) << 0)) >> 0) +/* ISS field definitions for GCS */ +#define ESR_ELx_ExType_SHIFT (20) +#define ESR_ELx_ExType_MASK GENMASK(23, 20) +#define ESR_ELx_Raddr_SHIFT (10) +#define ESR_ELx_Raddr_MASK GENMASK(14, 10) +#define ESR_ELx_Rn_SHIFT (5) +#define ESR_ELx_Rn_MASK GENMASK(9, 5) +#define ESR_ELx_Rvalue_SHIFT 5 +#define ESR_ELx_Rvalue_MASK GENMASK(9, 5) +#define ESR_ELx_IT_SHIFT (0) +#define ESR_ELx_IT_MASK GENMASK(4, 0) + +#define ESR_ELx_ExType_DATA_CHECK 0 +#define ESR_ELx_ExType_EXLOCK 1 +#define ESR_ELx_ExType_STR 2 + +#define ESR_ELx_IT_RET 0 +#define ESR_ELx_IT_GCSPOPM 1 +#define ESR_ELx_IT_RET_KEYA 2 +#define ESR_ELx_IT_RET_KEYB 3 +#define ESR_ELx_IT_GCSSS1 4 +#define ESR_ELx_IT_GCSSS2 5 +#define ESR_ELx_IT_GCSPOPCX 6 +#define ESR_ELx_IT_GCSPOPX 7 + #ifndef __ASSEMBLY__ #include diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h index f296662590c7f8..d48fc16584cd31 100644 --- a/arch/arm64/include/asm/exception.h +++ b/arch/arm64/include/asm/exception.h @@ -57,6 +57,8 @@ void do_el0_undef(struct pt_regs *regs, unsigned long esr); void do_el1_undef(struct pt_regs *regs, unsigned long esr); void do_el0_bti(struct pt_regs *regs); void do_el1_bti(struct pt_regs *regs, unsigned long esr); +void do_el0_gcs(struct pt_regs *regs, unsigned long esr); +void do_el1_gcs(struct pt_regs *regs, unsigned long esr); void do_debug_exception(unsigned long addr_if_watchpoint, unsigned long esr, struct pt_regs *regs); void do_fpsimd_acc(unsigned long esr, struct pt_regs *regs); @@ -73,6 +75,7 @@ void do_el0_svc_compat(struct pt_regs *regs); void do_el0_fpac(struct pt_regs *regs, unsigned long esr); void do_el1_fpac(struct pt_regs *regs, unsigned long esr); void do_el0_mops(struct pt_regs *regs, unsigned long esr); +void do_el1_mops(struct pt_regs *regs, unsigned long esr); void do_serror(struct pt_regs *regs, unsigned long esr); void do_signal(struct pt_regs *regs); diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h index dc9cf0bd2a4cba..5ccff4de7f0916 100644 --- a/arch/arm64/include/asm/ftrace.h +++ b/arch/arm64/include/asm/ftrace.h @@ -54,8 +54,11 @@ extern void return_to_handler(void); unsigned long ftrace_call_adjust(unsigned long addr); #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS +#define HAVE_ARCH_FTRACE_REGS struct dyn_ftrace; struct ftrace_ops; +struct ftrace_regs; +#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) #define arch_ftrace_get_regs(regs) NULL @@ -63,7 +66,7 @@ struct ftrace_ops; * Note: sizeof(struct ftrace_regs) must be a multiple of 16 to ensure correct * stack alignment */ -struct ftrace_regs { +struct __arch_ftrace_regs { /* x0 - x8 */ unsigned long regs[9]; @@ -83,47 +86,47 @@ struct ftrace_regs { static __always_inline unsigned long ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs) { - return fregs->pc; + return arch_ftrace_regs(fregs)->pc; } static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long pc) { - fregs->pc = pc; + arch_ftrace_regs(fregs)->pc = pc; } static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs) { - return fregs->sp; + return arch_ftrace_regs(fregs)->sp; } static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs, unsigned int n) { if (n < 8) - return fregs->regs[n]; + return arch_ftrace_regs(fregs)->regs[n]; return 0; } static __always_inline unsigned long ftrace_regs_get_return_value(const struct ftrace_regs *fregs) { - return fregs->regs[0]; + return arch_ftrace_regs(fregs)->regs[0]; } static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs, unsigned long ret) { - fregs->regs[0] = ret; + arch_ftrace_regs(fregs)->regs[0] = ret; } static __always_inline void ftrace_override_function_with_return(struct ftrace_regs *fregs) { - fregs->pc = fregs->lr; + arch_ftrace_regs(fregs)->pc = arch_ftrace_regs(fregs)->lr; } int ftrace_regs_query_register_offset(const char *name); @@ -143,7 +146,7 @@ static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, * The ftrace trampoline will return to this address instead of the * instrumented function. */ - fregs->direct_tramp = addr; + arch_ftrace_regs(fregs)->direct_tramp = addr; } #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ diff --git a/arch/arm64/include/asm/gcs.h b/arch/arm64/include/asm/gcs.h new file mode 100644 index 00000000000000..f50660603ecf5d --- /dev/null +++ b/arch/arm64/include/asm/gcs.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 ARM Ltd. + */ +#ifndef __ASM_GCS_H +#define __ASM_GCS_H + +#include +#include + +struct kernel_clone_args; +struct ksignal; + +static inline void gcsb_dsync(void) +{ + asm volatile(".inst 0xd503227f" : : : "memory"); +} + +static inline void gcsstr(u64 *addr, u64 val) +{ + register u64 *_addr __asm__ ("x0") = addr; + register long _val __asm__ ("x1") = val; + + /* GCSSTTR x1, x0 */ + asm volatile( + ".inst 0xd91f1c01\n" + : + : "rZ" (_val), "r" (_addr) + : "memory"); +} + +static inline void gcsss1(u64 Xt) +{ + asm volatile ( + "sys #3, C7, C7, #2, %0\n" + : + : "rZ" (Xt) + : "memory"); +} + +static inline u64 gcsss2(void) +{ + u64 Xt; + + asm volatile( + "SYSL %0, #3, C7, C7, #3\n" + : "=r" (Xt) + : + : "memory"); + + return Xt; +} + +#define PR_SHADOW_STACK_SUPPORTED_STATUS_MASK \ + (PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE | PR_SHADOW_STACK_PUSH) + +#ifdef CONFIG_ARM64_GCS + +static inline bool task_gcs_el0_enabled(struct task_struct *task) +{ + return current->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE; +} + +void gcs_set_el0_mode(struct task_struct *task); +void gcs_free(struct task_struct *task); +void gcs_preserve_current_state(void); +unsigned long gcs_alloc_thread_stack(struct task_struct *tsk, + const struct kernel_clone_args *args); + +static inline int gcs_check_locked(struct task_struct *task, + unsigned long new_val) +{ + unsigned long cur_val = task->thread.gcs_el0_mode; + + cur_val &= task->thread.gcs_el0_locked; + new_val &= task->thread.gcs_el0_locked; + + if (cur_val != new_val) + return -EBUSY; + + return 0; +} + +#else + +static inline bool task_gcs_el0_enabled(struct task_struct *task) +{ + return false; +} + +static inline void gcs_set_el0_mode(struct task_struct *task) { } +static inline void gcs_free(struct task_struct *task) { } +static inline void gcs_preserve_current_state(void) { } +static inline unsigned long gcs_alloc_thread_stack(struct task_struct *tsk, + const struct kernel_clone_args *args) +{ + return -ENOTSUPP; +} +static inline int gcs_check_locked(struct task_struct *task, + unsigned long new_val) +{ + return 0; +} + +#endif + +#endif diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h index 293f880865e8d0..c6dff3e69539b4 100644 --- a/arch/arm64/include/asm/hugetlb.h +++ b/arch/arm64/include/asm/hugetlb.h @@ -11,6 +11,7 @@ #define __ASM_HUGETLB_H #include +#include #include #ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION @@ -21,6 +22,13 @@ extern bool arch_hugetlb_migration_supported(struct hstate *h); static inline void arch_clear_hugetlb_flags(struct folio *folio) { clear_bit(PG_dcache_clean, &folio->flags); + +#ifdef CONFIG_ARM64_MTE + if (system_supports_mte()) { + clear_bit(PG_mte_tagged, &folio->flags); + clear_bit(PG_mte_lock, &folio->flags); + } +#endif } #define arch_clear_hugetlb_flags arch_clear_hugetlb_flags diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h index a775adddecf256..2b6c61c608e2cd 100644 --- a/arch/arm64/include/asm/hwcap.h +++ b/arch/arm64/include/asm/hwcap.h @@ -92,6 +92,7 @@ #define KERNEL_HWCAP_SB __khwcap_feature(SB) #define KERNEL_HWCAP_PACA __khwcap_feature(PACA) #define KERNEL_HWCAP_PACG __khwcap_feature(PACG) +#define KERNEL_HWCAP_GCS __khwcap_feature(GCS) #define __khwcap2_feature(x) (const_ilog2(HWCAP2_ ## x) + 64) #define KERNEL_HWCAP_DCPODP __khwcap2_feature(DCPODP) @@ -159,17 +160,21 @@ #define KERNEL_HWCAP_SME_SF8DP2 __khwcap2_feature(SME_SF8DP2) #define KERNEL_HWCAP_POE __khwcap2_feature(POE) +#define __khwcap3_feature(x) (const_ilog2(HWCAP3_ ## x) + 128) + /* * This yields a mask that user programs can use to figure out what * instruction set this cpu supports. */ #define ELF_HWCAP cpu_get_elf_hwcap() #define ELF_HWCAP2 cpu_get_elf_hwcap2() +#define ELF_HWCAP3 cpu_get_elf_hwcap3() #ifdef CONFIG_COMPAT #define COMPAT_ELF_HWCAP (compat_elf_hwcap) #define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2) -extern unsigned int compat_elf_hwcap, compat_elf_hwcap2; +#define COMPAT_ELF_HWCAP3 (compat_elf_hwcap3) +extern unsigned int compat_elf_hwcap, compat_elf_hwcap2, compat_elf_hwcap3; #endif enum { diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h index 8c0a36f72d6fcd..e390c432f546e5 100644 --- a/arch/arm64/include/asm/insn.h +++ b/arch/arm64/include/asm/insn.h @@ -353,6 +353,7 @@ __AARCH64_INSN_FUNCS(ldrsw_lit, 0xFF000000, 0x98000000) __AARCH64_INSN_FUNCS(exclusive, 0x3F800000, 0x08000000) __AARCH64_INSN_FUNCS(load_ex, 0x3F400000, 0x08400000) __AARCH64_INSN_FUNCS(store_ex, 0x3F400000, 0x08000000) +__AARCH64_INSN_FUNCS(mops, 0x3B200C00, 0x19000400) __AARCH64_INSN_FUNCS(stp, 0x7FC00000, 0x29000000) __AARCH64_INSN_FUNCS(ldp, 0x7FC00000, 0x29400000) __AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000) @@ -575,6 +576,11 @@ static __always_inline u32 aarch64_insn_gen_nop(void) return aarch64_insn_gen_hint(AARCH64_INSN_HINT_NOP); } +static __always_inline bool aarch64_insn_is_nop(u32 insn) +{ + return insn == aarch64_insn_gen_nop(); +} + u32 aarch64_insn_gen_branch_reg(enum aarch64_insn_register reg, enum aarch64_insn_branch_type type); u32 aarch64_insn_gen_load_store_reg(enum aarch64_insn_register reg, diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 1ada23a6ec1900..76ebbdc6ffddd8 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -17,6 +17,7 @@ #include #include #include +#include /* * Generic IO read/write. These perform native-endian accesses. @@ -128,17 +129,6 @@ static __always_inline u64 __raw_readq(const volatile void __iomem *addr) #define IO_SPACE_LIMIT (PCI_IO_SIZE - 1) #define PCI_IOBASE ((void __iomem *)PCI_IO_START) -/* - * String version of I/O memory access operations. - */ -extern void __memcpy_fromio(void *, const volatile void __iomem *, size_t); -extern void __memcpy_toio(volatile void __iomem *, const void *, size_t); -extern void __memset_io(volatile void __iomem *, int, size_t); - -#define memset_io(c,v,l) __memset_io((c),(v),(l)) -#define memcpy_fromio(a,c,l) __memcpy_fromio((a),(c),(l)) -#define memcpy_toio(c,a,l) __memcpy_toio((c),(a),(l)) - /* * The ARM64 iowrite implementation is intended to support drivers that want to * use write combining. For instance PCI drivers using write combining with a 64 @@ -318,4 +308,11 @@ extern bool arch_memremap_can_ram_remap(resource_size_t offset, size_t size, unsigned long flags); #define arch_memremap_can_ram_remap arch_memremap_can_ram_remap +static inline bool arm64_is_protected_mmio(phys_addr_t phys_addr, size_t size) +{ + if (unlikely(is_realm_world())) + return __arm64_is_protected_mmio(phys_addr, size); + return false; +} + #endif /* __ASM_IO_H */ diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h index a0a5bbae7229e8..424ed421cd9797 100644 --- a/arch/arm64/include/asm/jump_label.h +++ b/arch/arm64/include/asm/jump_label.h @@ -19,10 +19,14 @@ #define JUMP_TABLE_ENTRY(key, label) \ ".pushsection __jump_table, \"aw\"\n\t" \ ".align 3\n\t" \ - ".long 1b - ., %l["#label"] - .\n\t" \ - ".quad %c0 - .\n\t" \ - ".popsection\n\t" \ - : : "i"(key) : : label + ".long 1b - ., " label " - .\n\t" \ + ".quad " key " - .\n\t" \ + ".popsection\n\t" + +/* This macro is also expanded on the Rust side. */ +#define ARCH_STATIC_BRANCH_ASM(key, label) \ + "1: nop\n\t" \ + JUMP_TABLE_ENTRY(key, label) static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) @@ -30,8 +34,8 @@ static __always_inline bool arch_static_branch(struct static_key * const key, char *k = &((char *)key)[branch]; asm goto( - "1: nop \n\t" - JUMP_TABLE_ENTRY(k, l_yes) + ARCH_STATIC_BRANCH_ASM("%c0", "%l[l_yes]") + : : "i"(k) : : l_yes ); return false; @@ -43,9 +47,11 @@ static __always_inline bool arch_static_branch_jump(struct static_key * const ke const bool branch) { char *k = &((char *)key)[branch]; + asm goto( "1: b %l[l_yes] \n\t" - JUMP_TABLE_ENTRY(k, l_yes) + JUMP_TABLE_ENTRY("%c0", "%l[l_yes]") + : : "i"(k) : : l_yes ); return false; l_yes: diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h index bf05a77873a491..fd5a08450b12a4 100644 --- a/arch/arm64/include/asm/kernel-pgtable.h +++ b/arch/arm64/include/asm/kernel-pgtable.h @@ -26,7 +26,6 @@ #define SWAPPER_SKIP_LEVEL 0 #endif #define SWAPPER_BLOCK_SIZE (UL(1) << SWAPPER_BLOCK_SHIFT) -#define SWAPPER_TABLE_SHIFT (SWAPPER_BLOCK_SHIFT + PAGE_SHIFT - 3) #define SWAPPER_PGTABLE_LEVELS (CONFIG_PGTABLE_LEVELS - SWAPPER_SKIP_LEVEL) #define INIT_IDMAP_PGTABLE_LEVELS (IDMAP_LEVELS - SWAPPER_SKIP_LEVEL) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 109a85ee691007..3e0f0de1d2da86 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -103,6 +103,7 @@ #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H) #define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En | HCRX_EL2_EnFPM) +#define MPAMHCR_HOST_FLAGS 0 /* TCR_EL2 Registers bits */ #define TCR_EL2_DS (1UL << 32) @@ -311,35 +312,6 @@ GENMASK(19, 18) | \ GENMASK(15, 0)) -/* Hyp Debug Configuration Register bits */ -#define MDCR_EL2_E2TB_MASK (UL(0x3)) -#define MDCR_EL2_E2TB_SHIFT (UL(24)) -#define MDCR_EL2_HPMFZS (UL(1) << 36) -#define MDCR_EL2_HPMFZO (UL(1) << 29) -#define MDCR_EL2_MTPME (UL(1) << 28) -#define MDCR_EL2_TDCC (UL(1) << 27) -#define MDCR_EL2_HLP (UL(1) << 26) -#define MDCR_EL2_HCCD (UL(1) << 23) -#define MDCR_EL2_TTRF (UL(1) << 19) -#define MDCR_EL2_HPMD (UL(1) << 17) -#define MDCR_EL2_TPMS (UL(1) << 14) -#define MDCR_EL2_E2PB_MASK (UL(0x3)) -#define MDCR_EL2_E2PB_SHIFT (UL(12)) -#define MDCR_EL2_TDRA (UL(1) << 11) -#define MDCR_EL2_TDOSA (UL(1) << 10) -#define MDCR_EL2_TDA (UL(1) << 9) -#define MDCR_EL2_TDE (UL(1) << 8) -#define MDCR_EL2_HPME (UL(1) << 7) -#define MDCR_EL2_TPM (UL(1) << 6) -#define MDCR_EL2_TPMCR (UL(1) << 5) -#define MDCR_EL2_HPMN_MASK (UL(0x1F)) -#define MDCR_EL2_RES0 (GENMASK(63, 37) | \ - GENMASK(35, 30) | \ - GENMASK(25, 24) | \ - GENMASK(22, 20) | \ - BIT(18) | \ - GENMASK(16, 15)) - /* * FGT register definitions * diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 67afac659231ed..ca259034431353 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -76,7 +76,6 @@ enum __kvm_host_smccc_func { __KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff, __KVM_HOST_SMCCC_FUNC___vgic_v3_save_vmcr_aprs, __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs, - __KVM_HOST_SMCCC_FUNC___pkvm_vcpu_init_traps, __KVM_HOST_SMCCC_FUNC___pkvm_init_vm, __KVM_HOST_SMCCC_FUNC___pkvm_init_vcpu, __KVM_HOST_SMCCC_FUNC___pkvm_teardown_vm, diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index a601a9305b104f..cf811009a33c9e 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -225,6 +225,11 @@ static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu) return vcpu_has_nv(vcpu) && __is_hyp_ctxt(&vcpu->arch.ctxt); } +static inline bool vcpu_is_host_el0(const struct kvm_vcpu *vcpu) +{ + return is_hyp_ctxt(vcpu) && !vcpu_is_el2(vcpu); +} + /* * The layout of SPSR for an AArch32 state is different when observed from an * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32 @@ -693,4 +698,8 @@ static inline bool guest_hyp_sve_traps_enabled(const struct kvm_vcpu *vcpu) return __guest_hyp_cptr_xen_trap_enabled(vcpu, ZEN); } +static inline void kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu) +{ + vcpu_set_flag(vcpu, GUEST_HAS_PTRAUTH); +} #endif /* __ARM64_KVM_EMULATE_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index bf64fed9820ea0..e18e9244d17a4f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -74,8 +74,6 @@ enum kvm_mode kvm_get_mode(void); static inline enum kvm_mode kvm_get_mode(void) { return KVM_MODE_NONE; }; #endif -DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use); - extern unsigned int __ro_after_init kvm_sve_max_vl; extern unsigned int __ro_after_init kvm_host_sve_max_vl; int __init kvm_arm_init_sve(void); @@ -374,7 +372,7 @@ struct kvm_arch { u64 ctr_el0; - /* Masks for VNCR-baked sysregs */ + /* Masks for VNCR-backed and general EL2 sysregs */ struct kvm_sysreg_masks *sysreg_masks; /* @@ -408,6 +406,9 @@ struct kvm_vcpu_fault_info { r = __VNCR_START__ + ((VNCR_ ## r) / 8), \ __after_##r = __MAX__(__before_##r - 1, r) +#define MARKER(m) \ + m, __after_##m = m - 1 + enum vcpu_sysreg { __INVALID_SYSREG__, /* 0 is reserved as an invalid value */ MPIDR_EL1, /* MultiProcessor Affinity Register */ @@ -468,13 +469,15 @@ enum vcpu_sysreg { /* EL2 registers */ SCTLR_EL2, /* System Control Register (EL2) */ ACTLR_EL2, /* Auxiliary Control Register (EL2) */ - MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */ CPTR_EL2, /* Architectural Feature Trap Register (EL2) */ HACR_EL2, /* Hypervisor Auxiliary Control Register */ ZCR_EL2, /* SVE Control Register (EL2) */ TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */ TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */ TCR_EL2, /* Translation Control Register (EL2) */ + PIRE0_EL2, /* Permission Indirection Register 0 (EL2) */ + PIR_EL2, /* Permission Indirection Register 1 (EL2) */ + POR_EL2, /* Permission Overlay Register 2 (EL2) */ SPSR_EL2, /* EL2 saved program status register */ ELR_EL2, /* EL2 exception link register */ AFSR0_EL2, /* Auxiliary Fault Status Register 0 (EL2) */ @@ -494,7 +497,13 @@ enum vcpu_sysreg { CNTHV_CTL_EL2, CNTHV_CVAL_EL2, - __VNCR_START__, /* Any VNCR-capable reg goes after this point */ + /* Anything from this can be RES0/RES1 sanitised */ + MARKER(__SANITISED_REG_START__), + TCR2_EL2, /* Extended Translation Control Register (EL2) */ + MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */ + + /* Any VNCR-capable reg goes after this point */ + MARKER(__VNCR_START__), VNCR(SCTLR_EL1),/* System Control Register */ VNCR(ACTLR_EL1),/* Auxiliary Control Register */ @@ -554,7 +563,7 @@ struct kvm_sysreg_masks { struct { u64 res0; u64 res1; - } mask[NR_SYS_REGS - __VNCR_START__]; + } mask[NR_SYS_REGS - __SANITISED_REG_START__]; }; struct kvm_cpu_context { @@ -1002,13 +1011,13 @@ static inline u64 *___ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r) #define ctxt_sys_reg(c,r) (*__ctxt_sys_reg(c,r)) -u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *, enum vcpu_sysreg); +u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64); #define __vcpu_sys_reg(v,r) \ (*({ \ const struct kvm_cpu_context *ctxt = &(v)->arch.ctxt; \ u64 *__r = __ctxt_sys_reg(ctxt, (r)); \ - if (vcpu_has_nv((v)) && (r) >= __VNCR_START__) \ - *__r = kvm_vcpu_sanitise_vncr_reg((v), (r)); \ + if (vcpu_has_nv((v)) && (r) >= __SANITISED_REG_START__) \ + *__r = kvm_vcpu_apply_reg_masks((v), (r), *__r);\ __r; \ })) @@ -1037,6 +1046,10 @@ static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val) case TTBR0_EL1: *val = read_sysreg_s(SYS_TTBR0_EL12); break; case TTBR1_EL1: *val = read_sysreg_s(SYS_TTBR1_EL12); break; case TCR_EL1: *val = read_sysreg_s(SYS_TCR_EL12); break; + case TCR2_EL1: *val = read_sysreg_s(SYS_TCR2_EL12); break; + case PIR_EL1: *val = read_sysreg_s(SYS_PIR_EL12); break; + case PIRE0_EL1: *val = read_sysreg_s(SYS_PIRE0_EL12); break; + case POR_EL1: *val = read_sysreg_s(SYS_POR_EL12); break; case ESR_EL1: *val = read_sysreg_s(SYS_ESR_EL12); break; case AFSR0_EL1: *val = read_sysreg_s(SYS_AFSR0_EL12); break; case AFSR1_EL1: *val = read_sysreg_s(SYS_AFSR1_EL12); break; @@ -1083,6 +1096,10 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg) case TTBR0_EL1: write_sysreg_s(val, SYS_TTBR0_EL12); break; case TTBR1_EL1: write_sysreg_s(val, SYS_TTBR1_EL12); break; case TCR_EL1: write_sysreg_s(val, SYS_TCR_EL12); break; + case TCR2_EL1: write_sysreg_s(val, SYS_TCR2_EL12); break; + case PIR_EL1: write_sysreg_s(val, SYS_PIR_EL12); break; + case PIRE0_EL1: write_sysreg_s(val, SYS_PIRE0_EL12); break; + case POR_EL1: write_sysreg_s(val, SYS_POR_EL12); break; case ESR_EL1: write_sysreg_s(val, SYS_ESR_EL12); break; case AFSR0_EL1: write_sysreg_s(val, SYS_AFSR0_EL12); break; case AFSR1_EL1: write_sysreg_s(val, SYS_AFSR1_EL12); break; @@ -1140,7 +1157,7 @@ int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu, void kvm_arm_halt_guest(struct kvm *kvm); void kvm_arm_resume_guest(struct kvm *kvm); -#define vcpu_has_run_once(vcpu) !!rcu_access_pointer((vcpu)->pid) +#define vcpu_has_run_once(vcpu) (!!READ_ONCE((vcpu)->pid)) #ifndef __KVM_NVHE_HYPERVISOR__ #define kvm_call_hyp_nvhe(f, ...) \ @@ -1503,4 +1520,13 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val); (system_supports_fpmr() && \ kvm_has_feat((k), ID_AA64PFR2_EL1, FPMR, IMP)) +#define kvm_has_tcr2(k) \ + (kvm_has_feat((k), ID_AA64MMFR3_EL1, TCRX, IMP)) + +#define kvm_has_s1pie(k) \ + (kvm_has_feat((k), ID_AA64MMFR3_EL1, S1PIE, IMP)) + +#define kvm_has_s1poe(k) \ + (kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP)) + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h index 03f4c3d7839c2c..aab04097b5054a 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -674,10 +674,8 @@ int kvm_pgtable_stage2_wrprotect(struct kvm_pgtable *pgt, u64 addr, u64 size); * * If there is a valid, leaf page-table entry used to translate @addr, then * set the access flag in that entry. - * - * Return: The old page-table entry prior to setting the flag, 0 on failure. */ -kvm_pte_t kvm_pgtable_stage2_mkyoung(struct kvm_pgtable *pgt, u64 addr); +void kvm_pgtable_stage2_mkyoung(struct kvm_pgtable *pgt, u64 addr); /** * kvm_pgtable_stage2_test_clear_young() - Test and optionally clear the access diff --git a/arch/arm64/include/asm/mem_encrypt.h b/arch/arm64/include/asm/mem_encrypt.h index b0c9a86b13a46e..f8f78f622dd2c9 100644 --- a/arch/arm64/include/asm/mem_encrypt.h +++ b/arch/arm64/include/asm/mem_encrypt.h @@ -2,6 +2,8 @@ #ifndef __ASM_MEM_ENCRYPT_H #define __ASM_MEM_ENCRYPT_H +#include + struct arm64_mem_crypt_ops { int (*encrypt)(unsigned long addr, int numpages); int (*decrypt)(unsigned long addr, int numpages); @@ -12,4 +14,11 @@ int arm64_mem_crypt_ops_register(const struct arm64_mem_crypt_ops *ops); int set_memory_encrypted(unsigned long addr, int numpages); int set_memory_decrypted(unsigned long addr, int numpages); +int realm_register_memory_enc_ops(void); + +static inline bool force_dma_unencrypted(struct device *dev) +{ + return is_realm_world(); +} + #endif /* __ASM_MEM_ENCRYPT_H */ diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 0480c61dbb4f30..8b9f33cf561bb3 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -110,7 +110,7 @@ #define PAGE_END (_PAGE_END(VA_BITS_MIN)) #endif /* CONFIG_KASAN */ -#define PHYSMEM_END __pa(PAGE_END - 1) +#define DIRECT_MAP_PHYSMEM_END __pa(PAGE_END - 1) #define MIN_THREAD_SHIFT (14 + KASAN_THREAD_SHIFT) @@ -353,12 +353,6 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x); #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET) #define __phys_to_kimg(x) ((unsigned long)((x) + kimage_voffset)) -/* - * Convert a page to/from a physical address - */ -#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) -#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) - /* * Note: Drivers should NOT use these. They are the wrong * translation for translating DMA addresses. Use the driver diff --git a/arch/arm64/include/asm/mman.h b/arch/arm64/include/asm/mman.h index 798d965760d434..21df8bbd2668a2 100644 --- a/arch/arm64/include/asm/mman.h +++ b/arch/arm64/include/asm/mman.h @@ -7,6 +7,7 @@ #ifndef BUILD_VDSO #include #include +#include #include #include @@ -41,9 +42,12 @@ static inline unsigned long arch_calc_vm_flag_bits(struct file *file, * backed by tags-capable memory. The vm_flags may be overridden by a * filesystem supporting MTE (RAM-based). */ - if (system_supports_mte() && - ((flags & MAP_ANONYMOUS) || shmem_file(file))) - return VM_MTE_ALLOWED; + if (system_supports_mte()) { + if (flags & (MAP_ANONYMOUS | MAP_HUGETLB)) + return VM_MTE_ALLOWED; + if (shmem_file(file) || is_file_hugepages(file)) + return VM_MTE_ALLOWED; + } return 0; } @@ -66,11 +70,26 @@ static inline bool arch_validate_prot(unsigned long prot, static inline bool arch_validate_flags(unsigned long vm_flags) { - if (!system_supports_mte()) - return true; + if (system_supports_mte()) { + /* + * only allow VM_MTE if VM_MTE_ALLOWED has been set + * previously + */ + if ((vm_flags & VM_MTE) && !(vm_flags & VM_MTE_ALLOWED)) + return false; + } + + if (system_supports_gcs() && (vm_flags & VM_SHADOW_STACK)) { + /* An executable GCS isn't a good idea. */ + if (vm_flags & VM_EXEC) + return false; + + /* The memory management core should prevent this */ + VM_WARN_ON(vm_flags & VM_SHARED); + } + + return true; - /* only allow VM_MTE if VM_MTE_ALLOWED has been set previously */ - return !(vm_flags & VM_MTE) || (vm_flags & VM_MTE_ALLOWED); } #define arch_validate_flags(vm_flags) arch_validate_flags(vm_flags) diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index 7c09d47e09cb54..48b3d9553b675c 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -311,6 +312,14 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, return por_el0_allows_pkey(vma_pkey(vma), write, execute); } +#define deactivate_mm deactivate_mm +static inline void deactivate_mm(struct task_struct *tsk, + struct mm_struct *mm) +{ + gcs_free(tsk); +} + + #include #endif /* !__ASSEMBLY__ */ diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h index 0f84518632b4a6..6567df8ec8ca81 100644 --- a/arch/arm64/include/asm/mte.h +++ b/arch/arm64/include/asm/mte.h @@ -41,6 +41,8 @@ void mte_free_tag_storage(char *storage); static inline void set_page_mte_tagged(struct page *page) { + VM_WARN_ON_ONCE(folio_test_hugetlb(page_folio(page))); + /* * Ensure that the tags written prior to this function are visible * before the page flags update. @@ -53,6 +55,8 @@ static inline bool page_mte_tagged(struct page *page) { bool ret = test_bit(PG_mte_tagged, &page->flags); + VM_WARN_ON_ONCE(folio_test_hugetlb(page_folio(page))); + /* * If the page is tagged, ensure ordering with a likely subsequent * read of the tags. @@ -76,6 +80,8 @@ static inline bool page_mte_tagged(struct page *page) */ static inline bool try_page_mte_tagging(struct page *page) { + VM_WARN_ON_ONCE(folio_test_hugetlb(page_folio(page))); + if (!test_and_set_bit(PG_mte_lock, &page->flags)) return true; @@ -157,6 +163,67 @@ static inline int mte_ptrace_copy_tags(struct task_struct *child, #endif /* CONFIG_ARM64_MTE */ +#if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_ARM64_MTE) +static inline void folio_set_hugetlb_mte_tagged(struct folio *folio) +{ + VM_WARN_ON_ONCE(!folio_test_hugetlb(folio)); + + /* + * Ensure that the tags written prior to this function are visible + * before the folio flags update. + */ + smp_wmb(); + set_bit(PG_mte_tagged, &folio->flags); + +} + +static inline bool folio_test_hugetlb_mte_tagged(struct folio *folio) +{ + bool ret = test_bit(PG_mte_tagged, &folio->flags); + + VM_WARN_ON_ONCE(!folio_test_hugetlb(folio)); + + /* + * If the folio is tagged, ensure ordering with a likely subsequent + * read of the tags. + */ + if (ret) + smp_rmb(); + return ret; +} + +static inline bool folio_try_hugetlb_mte_tagging(struct folio *folio) +{ + VM_WARN_ON_ONCE(!folio_test_hugetlb(folio)); + + if (!test_and_set_bit(PG_mte_lock, &folio->flags)) + return true; + + /* + * The tags are either being initialised or may have been initialised + * already. Check if the PG_mte_tagged flag has been set or wait + * otherwise. + */ + smp_cond_load_acquire(&folio->flags, VAL & (1UL << PG_mte_tagged)); + + return false; +} +#else +static inline void folio_set_hugetlb_mte_tagged(struct folio *folio) +{ +} + +static inline bool folio_test_hugetlb_mte_tagged(struct folio *folio) +{ + return false; +} + +static inline bool folio_try_hugetlb_mte_tagging(struct folio *folio) +{ + return false; +} +#endif + static inline void mte_disable_tco_entry(struct task_struct *task) { if (!system_supports_mte()) diff --git a/arch/arm64/include/asm/page-def.h b/arch/arm64/include/asm/page-def.h index 792e9fe881dcf5..d402e08442ee24 100644 --- a/arch/arm64/include/asm/page-def.h +++ b/arch/arm64/include/asm/page-def.h @@ -10,9 +10,6 @@ #include -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #endif /* __ASM_PAGE_DEF_H */ diff --git a/arch/arm64/include/asm/patching.h b/arch/arm64/include/asm/patching.h deleted file mode 100644 index 587bdb91ab7a64..00000000000000 --- a/arch/arm64/include/asm/patching.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef __ASM_PATCHING_H -#define __ASM_PATCHING_H - -#include - -int aarch64_insn_read(void *addr, u32 *insnp); -int aarch64_insn_write(void *addr, u32 insn); - -int aarch64_insn_write_literal_u64(void *addr, u64 val); -void *aarch64_insn_set(void *dst, u32 insn, size_t len); -void *aarch64_insn_copy(void *dst, void *src, size_t len); - -int aarch64_insn_patch_text_nosync(void *addr, u32 insn); -int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); - -#endif /* __ASM_PATCHING_H */ diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index eb7071c9eb343c..ee45b4e773470e 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -10,10 +10,6 @@ #include #ifdef CONFIG_PERF_EVENTS -struct pt_regs; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) #define perf_arch_bpf_user_pt_regs(regs) ®s->user_regs #endif diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h index 8ff5f2a2579e4d..e75422864d1bd6 100644 --- a/arch/arm64/include/asm/pgalloc.h +++ b/arch/arm64/include/asm/pgalloc.h @@ -28,7 +28,7 @@ static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot) static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp) { - pudval_t pudval = PUD_TYPE_TABLE; + pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_AF; pudval |= (mm == &init_mm) ? PUD_TABLE_UXN : PUD_TABLE_PXN; __pud_populate(pudp, __pa(pmdp), pudval); @@ -50,7 +50,7 @@ static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot) static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4dp, pud_t *pudp) { - p4dval_t p4dval = P4D_TYPE_TABLE; + p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_AF; p4dval |= (mm == &init_mm) ? P4D_TABLE_UXN : P4D_TABLE_PXN; __p4d_populate(p4dp, __pa(pudp), p4dval); @@ -79,7 +79,7 @@ static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t p4dp, pgdval_t prot) static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgdp, p4d_t *p4dp) { - pgdval_t pgdval = PGD_TYPE_TABLE; + pgdval_t pgdval = PGD_TYPE_TABLE | PGD_TABLE_AF; pgdval |= (mm == &init_mm) ? PGD_TABLE_UXN : PGD_TABLE_PXN; __pgd_populate(pgdp, __pa(p4dp), pgdval); @@ -127,14 +127,16 @@ static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) { VM_BUG_ON(mm && mm != &init_mm); - __pmd_populate(pmdp, __pa(ptep), PMD_TYPE_TABLE | PMD_TABLE_UXN); + __pmd_populate(pmdp, __pa(ptep), + PMD_TYPE_TABLE | PMD_TABLE_AF | PMD_TABLE_UXN); } static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep) { VM_BUG_ON(mm == &init_mm); - __pmd_populate(pmdp, page_to_phys(ptep), PMD_TYPE_TABLE | PMD_TABLE_PXN); + __pmd_populate(pmdp, page_to_phys(ptep), + PMD_TYPE_TABLE | PMD_TABLE_AF | PMD_TABLE_PXN); } #endif diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index fd330c1db289a6..c78a988cca93a5 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -99,6 +99,7 @@ #define PGD_TYPE_TABLE (_AT(pgdval_t, 3) << 0) #define PGD_TABLE_BIT (_AT(pgdval_t, 1) << 1) #define PGD_TYPE_MASK (_AT(pgdval_t, 3) << 0) +#define PGD_TABLE_AF (_AT(pgdval_t, 1) << 10) /* Ignored if no FEAT_HAFT */ #define PGD_TABLE_PXN (_AT(pgdval_t, 1) << 59) #define PGD_TABLE_UXN (_AT(pgdval_t, 1) << 60) @@ -110,6 +111,7 @@ #define P4D_TYPE_MASK (_AT(p4dval_t, 3) << 0) #define P4D_TYPE_SECT (_AT(p4dval_t, 1) << 0) #define P4D_SECT_RDONLY (_AT(p4dval_t, 1) << 7) /* AP[2] */ +#define P4D_TABLE_AF (_AT(p4dval_t, 1) << 10) /* Ignored if no FEAT_HAFT */ #define P4D_TABLE_PXN (_AT(p4dval_t, 1) << 59) #define P4D_TABLE_UXN (_AT(p4dval_t, 1) << 60) @@ -121,6 +123,7 @@ #define PUD_TYPE_MASK (_AT(pudval_t, 3) << 0) #define PUD_TYPE_SECT (_AT(pudval_t, 1) << 0) #define PUD_SECT_RDONLY (_AT(pudval_t, 1) << 7) /* AP[2] */ +#define PUD_TABLE_AF (_AT(pudval_t, 1) << 10) /* Ignored if no FEAT_HAFT */ #define PUD_TABLE_PXN (_AT(pudval_t, 1) << 59) #define PUD_TABLE_UXN (_AT(pudval_t, 1) << 60) @@ -131,6 +134,7 @@ #define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0) #define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0) #define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1) +#define PMD_TABLE_AF (_AT(pmdval_t, 1) << 10) /* Ignored if no FEAT_HAFT */ /* * Section diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index 2a11d0c10760b9..9f9cf13bbd95e7 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -35,7 +35,6 @@ #endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */ #define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) -#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_MAYBE_NG | PTE_MAYBE_SHARED | PTE_AF) #define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_MAYBE_NG | PMD_MAYBE_SHARED | PMD_SECT_AF) @@ -68,8 +67,12 @@ #include #include +#include extern bool arm64_use_ng_mappings; +extern unsigned long prot_ns_shared; + +#define PROT_NS_SHARED (is_realm_world() ? prot_ns_shared : 0) #define PTE_MAYBE_NG (arm64_use_ng_mappings ? PTE_NG : 0) #define PMD_MAYBE_NG (arm64_use_ng_mappings ? PMD_SECT_NG : 0) @@ -144,15 +147,23 @@ static inline bool __pure lpa2_is_enabled(void) /* 6: PTE_PXN | PTE_WRITE */ /* 7: PAGE_SHARED_EXEC PTE_PXN | PTE_WRITE | PTE_USER */ /* 8: PAGE_KERNEL_ROX PTE_UXN */ -/* 9: PTE_UXN | PTE_USER */ +/* 9: PAGE_GCS_RO PTE_UXN | PTE_USER */ /* a: PAGE_KERNEL_EXEC PTE_UXN | PTE_WRITE */ -/* b: PTE_UXN | PTE_WRITE | PTE_USER */ +/* b: PAGE_GCS PTE_UXN | PTE_WRITE | PTE_USER */ /* c: PAGE_KERNEL_RO PTE_UXN | PTE_PXN */ /* d: PAGE_READONLY PTE_UXN | PTE_PXN | PTE_USER */ /* e: PAGE_KERNEL PTE_UXN | PTE_PXN | PTE_WRITE */ /* f: PAGE_SHARED PTE_UXN | PTE_PXN | PTE_WRITE | PTE_USER */ +#define _PAGE_GCS (_PAGE_DEFAULT | PTE_NG | PTE_UXN | PTE_WRITE | PTE_USER) +#define _PAGE_GCS_RO (_PAGE_DEFAULT | PTE_NG | PTE_UXN | PTE_USER) + +#define PAGE_GCS __pgprot(_PAGE_GCS) +#define PAGE_GCS_RO __pgprot(_PAGE_GCS_RO) + #define PIE_E0 ( \ + PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS), PIE_GCS) | \ + PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS_RO), PIE_R) | \ PIRx_ELx_PERM(pte_pi_index(_PAGE_EXECONLY), PIE_X_O) | \ PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY_EXEC), PIE_RX_O) | \ PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED_EXEC), PIE_RWX_O) | \ @@ -160,6 +171,8 @@ static inline bool __pure lpa2_is_enabled(void) PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED), PIE_RW_O)) #define PIE_E1 ( \ + PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS), PIE_NONE_O) | \ + PIRx_ELx_PERM(pte_pi_index(_PAGE_GCS_RO), PIE_NONE_O) | \ PIRx_ELx_PERM(pte_pi_index(_PAGE_EXECONLY), PIE_NONE_O) | \ PIRx_ELx_PERM(pte_pi_index(_PAGE_READONLY_EXEC), PIE_R) | \ PIRx_ELx_PERM(pte_pi_index(_PAGE_SHARED_EXEC), PIE_RW) | \ diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index c329ea061dc988..6986345b537ab2 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -265,8 +265,7 @@ static inline pte_t pte_mkspecial(pte_t pte) static inline pte_t pte_mkcont(pte_t pte) { - pte = set_pte_bit(pte, __pgprot(PTE_CONT)); - return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE)); + return set_pte_bit(pte, __pgprot(PTE_CONT)); } static inline pte_t pte_mknoncont(pte_t pte) @@ -338,7 +337,7 @@ static inline pte_t __ptep_get(pte_t *ptep) } extern void __sync_icache_dcache(pte_t pteval); -bool pgattr_change_is_safe(u64 old, u64 new); +bool pgattr_change_is_safe(pteval_t old, pteval_t new); /* * PTE bits configuration in the presence of hardware Dirty Bit Management @@ -438,11 +437,6 @@ static inline void __set_ptes(struct mm_struct *mm, } } -/* - * Huge pte definitions. - */ -#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT)) - /* * Hugetlb definitions. */ @@ -684,6 +678,11 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr, #define pgprot_nx(prot) \ __pgprot_modify(prot, PTE_MAYBE_GP, PTE_PXN) +#define pgprot_decrypted(prot) \ + __pgprot_modify(prot, PROT_NS_SHARED, PROT_NS_SHARED) +#define pgprot_encrypted(prot) \ + __pgprot_modify(prot, PROT_NS_SHARED, 0) + /* * Mark the prot value as uncacheable and unbufferable. */ @@ -927,6 +926,9 @@ static inline phys_addr_t p4d_page_paddr(p4d_t p4d) static inline pud_t *p4d_to_folded_pud(p4d_t *p4dp, unsigned long addr) { + /* Ensure that 'p4dp' indexes a page table according to 'addr' */ + VM_BUG_ON(((addr >> P4D_SHIFT) ^ ((u64)p4dp >> 3)) % PTRS_PER_P4D); + return (pud_t *)PTR_ALIGN_DOWN(p4dp, PAGE_SIZE) + pud_index(addr); } @@ -1051,6 +1053,9 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd) static inline p4d_t *pgd_to_folded_p4d(pgd_t *pgdp, unsigned long addr) { + /* Ensure that 'pgdp' indexes a page table according to 'addr' */ + VM_BUG_ON(((addr >> PGDIR_SHIFT) ^ ((u64)pgdp >> 3)) % PTRS_PER_PGD); + return (p4d_t *)PTR_ALIGN_DOWN(pgdp, PAGE_SIZE) + p4d_index(addr); } @@ -1259,15 +1264,17 @@ static inline int __ptep_clear_flush_young(struct vm_area_struct *vma, return young; } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) #define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) { + /* Operation applies to PMD table entry only if FEAT_HAFT is enabled */ + VM_WARN_ON(pmd_table(READ_ONCE(*pmdp)) && !system_supports_haft()); return __ptep_test_and_clear_young(vma, address, (pte_t *)pmdp); } -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */ static inline pte_t __ptep_get_and_clear(struct mm_struct *mm, unsigned long address, pte_t *ptep) @@ -1502,6 +1509,10 @@ static inline void update_mmu_cache_range(struct vm_fault *vmf, */ #define arch_has_hw_pte_young cpu_has_hw_af +#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +#define arch_has_hw_nonleaf_pmd_young system_supports_haft +#endif + /* * Experimentally, it's cheap to set the access flag in hardware and we * benefit from prefaulting mappings as 'old' to start with. diff --git a/arch/arm64/include/asm/probes.h b/arch/arm64/include/asm/probes.h index 006946745352ef..d4936888630940 100644 --- a/arch/arm64/include/asm/probes.h +++ b/arch/arm64/include/asm/probes.h @@ -9,21 +9,18 @@ #include -typedef u32 probe_opcode_t; typedef void (probes_handler_t) (u32 opcode, long addr, struct pt_regs *); -/* architecture specific copy of original instruction */ struct arch_probe_insn { - probe_opcode_t *insn; - pstate_check_t *pstate_cc; probes_handler_t *handler; - /* restore address after step xol */ - unsigned long restore; }; #ifdef CONFIG_KPROBES -typedef u32 kprobe_opcode_t; +typedef __le32 kprobe_opcode_t; struct arch_specific_insn { struct arch_probe_insn api; + kprobe_opcode_t *xol_insn; + /* restore address after step xol */ + unsigned long xol_restore; }; #endif diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 1438424f006437..1bf1a3b16e8864 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -185,6 +185,13 @@ struct thread_struct { u64 svcr; u64 tpidr2_el0; u64 por_el0; +#ifdef CONFIG_ARM64_GCS + unsigned int gcs_el0_mode; + unsigned int gcs_el0_locked; + u64 gcspr_el0; + u64 gcs_base; + u64 gcs_size; +#endif }; static inline unsigned int thread_get_vl(struct thread_struct *thread, @@ -285,22 +292,44 @@ void tls_preserve_current_state(void); .fpsimd_cpu = NR_CPUS, \ } -static inline void start_thread_common(struct pt_regs *regs, unsigned long pc) +static inline void start_thread_common(struct pt_regs *regs, unsigned long pc, + unsigned long pstate) { - s32 previous_syscall = regs->syscallno; - memset(regs, 0, sizeof(*regs)); - regs->syscallno = previous_syscall; - regs->pc = pc; + /* + * Ensure all GPRs are zeroed, and initialize PC + PSTATE. + * The SP (or compat SP) will be initialized later. + */ + regs->user_regs = (struct user_pt_regs) { + .pc = pc, + .pstate = pstate, + }; + /* + * To allow the syscalls:sys_exit_execve tracepoint we need to preserve + * syscallno, but do not need orig_x0 or the original GPRs. + */ + regs->orig_x0 = 0; + + /* + * An exec from a kernel thread won't have an existing PMR value. + */ if (system_uses_irq_prio_masking()) - regs->pmr_save = GIC_PRIO_IRQON; + regs->pmr = GIC_PRIO_IRQON; + + /* + * The pt_regs::stackframe field must remain valid throughout this + * function as a stacktrace can be taken at any time. Any user or + * kernel task should have a valid final frame. + */ + WARN_ON_ONCE(regs->stackframe.record.fp != 0); + WARN_ON_ONCE(regs->stackframe.record.lr != 0); + WARN_ON_ONCE(regs->stackframe.type != FRAME_META_TYPE_FINAL); } static inline void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - start_thread_common(regs, pc); - regs->pstate = PSR_MODE_EL0t; + start_thread_common(regs, pc, PSR_MODE_EL0t); spectre_v4_enable_task_mitigation(current); regs->sp = sp; } @@ -309,15 +338,13 @@ static inline void start_thread(struct pt_regs *regs, unsigned long pc, static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) { - start_thread_common(regs, pc); - regs->pstate = PSR_AA32_MODE_USR; + unsigned long pstate = PSR_AA32_MODE_USR; if (pc & 1) - regs->pstate |= PSR_AA32_T_BIT; - -#ifdef __AARCH64EB__ - regs->pstate |= PSR_AA32_E_BIT; -#endif + pstate |= PSR_AA32_T_BIT; + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + pstate |= PSR_AA32_E_BIT; + start_thread_common(regs, pc, pstate); spectre_v4_enable_task_mitigation(current); regs->compat_sp = sp; } diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index 0abe975d68a8e4..47ff8654c5ec1e 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -98,6 +98,8 @@ #include #include +#include + /* sizeof(struct user) for AArch32 */ #define COMPAT_USER_SZ 296 @@ -149,8 +151,7 @@ static inline unsigned long pstate_to_compat_psr(const unsigned long pstate) /* * This struct defines the way the registers are stored on the stack during an - * exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for - * stack alignment). struct user_pt_regs must form a prefix of struct pt_regs. + * exception. struct user_pt_regs must form a prefix of struct pt_regs. */ struct pt_regs { union { @@ -163,23 +164,20 @@ struct pt_regs { }; }; u64 orig_x0; -#ifdef __AARCH64EB__ - u32 unused2; - s32 syscallno; -#else s32 syscallno; - u32 unused2; -#endif + u32 pmr; + u64 sdei_ttbr1; - /* Only valid when ARM64_HAS_GIC_PRIO_MASKING is enabled. */ - u64 pmr_save; - u64 stackframe[2]; + struct frame_record_meta stackframe; /* Only valid for some EL1 exceptions. */ u64 lockdep_hardirqs; u64 exit_rcu; }; +/* For correct stack alignment, pt_regs has to be a multiple of 16 bytes. */ +static_assert(IS_ALIGNED(sizeof(struct pt_regs), 16)); + static inline bool in_syscall(struct pt_regs const *regs) { return regs->syscallno != NO_SYSCALL; @@ -213,7 +211,7 @@ static inline void forget_syscall(struct pt_regs *regs) #define irqs_priority_unmasked(regs) \ (system_uses_irq_prio_masking() ? \ - (regs)->pmr_save == GIC_PRIO_IRQON : \ + (regs)->pmr == GIC_PRIO_IRQON : \ true) #define interrupts_enabled(regs) \ diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h new file mode 100644 index 00000000000000..188cbb9b23f576 --- /dev/null +++ b/arch/arm64/include/asm/rsi.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 ARM Ltd. + */ + +#ifndef __ASM_RSI_H_ +#define __ASM_RSI_H_ + +#include +#include +#include + +DECLARE_STATIC_KEY_FALSE(rsi_present); + +void __init arm64_rsi_init(void); + +bool __arm64_is_protected_mmio(phys_addr_t base, size_t size); + +static inline bool is_realm_world(void) +{ + return static_branch_unlikely(&rsi_present); +} + +static inline int rsi_set_memory_range(phys_addr_t start, phys_addr_t end, + enum ripas state, unsigned long flags) +{ + unsigned long ret; + phys_addr_t top; + + while (start != end) { + ret = rsi_set_addr_range_state(start, end, state, flags, &top); + if (ret || top < start || top > end) + return -EINVAL; + start = top; + } + + return 0; +} + +/* + * Convert the specified range to RAM. Do not use this if you rely on the + * contents of a page that may already be in RAM state. + */ +static inline int rsi_set_memory_range_protected(phys_addr_t start, + phys_addr_t end) +{ + return rsi_set_memory_range(start, end, RSI_RIPAS_RAM, + RSI_CHANGE_DESTROYED); +} + +/* + * Convert the specified range to RAM. Do not convert any pages that may have + * been DESTROYED, without our permission. + */ +static inline int rsi_set_memory_range_protected_safe(phys_addr_t start, + phys_addr_t end) +{ + return rsi_set_memory_range(start, end, RSI_RIPAS_RAM, + RSI_NO_CHANGE_DESTROYED); +} + +static inline int rsi_set_memory_range_shared(phys_addr_t start, + phys_addr_t end) +{ + return rsi_set_memory_range(start, end, RSI_RIPAS_EMPTY, + RSI_CHANGE_DESTROYED); +} +#endif /* __ASM_RSI_H_ */ diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h new file mode 100644 index 00000000000000..e6a211001bd38e --- /dev/null +++ b/arch/arm64/include/asm/rsi_cmds.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 ARM Ltd. + */ + +#ifndef __ASM_RSI_CMDS_H +#define __ASM_RSI_CMDS_H + +#include + +#include + +#define RSI_GRANULE_SHIFT 12 +#define RSI_GRANULE_SIZE (_AC(1, UL) << RSI_GRANULE_SHIFT) + +enum ripas { + RSI_RIPAS_EMPTY = 0, + RSI_RIPAS_RAM = 1, + RSI_RIPAS_DESTROYED = 2, + RSI_RIPAS_DEV = 3, +}; + +static inline unsigned long rsi_request_version(unsigned long req, + unsigned long *out_lower, + unsigned long *out_higher) +{ + struct arm_smccc_res res; + + arm_smccc_smc(SMC_RSI_ABI_VERSION, req, 0, 0, 0, 0, 0, 0, &res); + + if (out_lower) + *out_lower = res.a1; + if (out_higher) + *out_higher = res.a2; + + return res.a0; +} + +static inline unsigned long rsi_get_realm_config(struct realm_config *cfg) +{ + struct arm_smccc_res res; + + arm_smccc_smc(SMC_RSI_REALM_CONFIG, virt_to_phys(cfg), + 0, 0, 0, 0, 0, 0, &res); + return res.a0; +} + +static inline unsigned long rsi_ipa_state_get(phys_addr_t start, + phys_addr_t end, + enum ripas *state, + phys_addr_t *top) +{ + struct arm_smccc_res res; + + arm_smccc_smc(SMC_RSI_IPA_STATE_GET, + start, end, 0, 0, 0, 0, 0, + &res); + + if (res.a0 == RSI_SUCCESS) { + if (top) + *top = res.a1; + if (state) + *state = res.a2; + } + + return res.a0; +} + +static inline long rsi_set_addr_range_state(phys_addr_t start, + phys_addr_t end, + enum ripas state, + unsigned long flags, + phys_addr_t *top) +{ + struct arm_smccc_res res; + + arm_smccc_smc(SMC_RSI_IPA_STATE_SET, start, end, state, + flags, 0, 0, 0, &res); + + if (top) + *top = res.a1; + + if (res.a2 != RSI_ACCEPT) + return -EPERM; + + return res.a0; +} + +/** + * rsi_attestation_token_init - Initialise the operation to retrieve an + * attestation token. + * + * @challenge: The challenge data to be used in the attestation token + * generation. + * @size: Size of the challenge data in bytes. + * + * Initialises the attestation token generation and returns an upper bound + * on the attestation token size that can be used to allocate an adequate + * buffer. The caller is expected to subsequently call + * rsi_attestation_token_continue() to retrieve the attestation token data on + * the same CPU. + * + * Returns: + * On success, returns the upper limit of the attestation report size. + * Otherwise, -EINVAL + */ +static inline long +rsi_attestation_token_init(const u8 *challenge, unsigned long size) +{ + struct arm_smccc_1_2_regs regs = { 0 }; + + /* The challenge must be at least 32bytes and at most 64bytes */ + if (!challenge || size < 32 || size > 64) + return -EINVAL; + + regs.a0 = SMC_RSI_ATTESTATION_TOKEN_INIT; + memcpy(®s.a1, challenge, size); + arm_smccc_1_2_smc(®s, ®s); + + if (regs.a0 == RSI_SUCCESS) + return regs.a1; + + return -EINVAL; +} + +/** + * rsi_attestation_token_continue - Continue the operation to retrieve an + * attestation token. + * + * @granule: {I}PA of the Granule to which the token will be written. + * @offset: Offset within Granule to start of buffer in bytes. + * @size: The size of the buffer. + * @len: The number of bytes written to the buffer. + * + * Retrieves up to a RSI_GRANULE_SIZE worth of token data per call. The caller + * is expected to call rsi_attestation_token_init() before calling this + * function to retrieve the attestation token. + * + * Return: + * * %RSI_SUCCESS - Attestation token retrieved successfully. + * * %RSI_INCOMPLETE - Token generation is not complete. + * * %RSI_ERROR_INPUT - A parameter was not valid. + * * %RSI_ERROR_STATE - Attestation not in progress. + */ +static inline unsigned long rsi_attestation_token_continue(phys_addr_t granule, + unsigned long offset, + unsigned long size, + unsigned long *len) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(SMC_RSI_ATTESTATION_TOKEN_CONTINUE, + granule, offset, size, 0, &res); + + if (len) + *len = res.a1; + return res.a0; +} + +#endif /* __ASM_RSI_CMDS_H */ diff --git a/arch/arm64/include/asm/rsi_smc.h b/arch/arm64/include/asm/rsi_smc.h new file mode 100644 index 00000000000000..6cb070eca9e9b2 --- /dev/null +++ b/arch/arm64/include/asm/rsi_smc.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 ARM Ltd. + */ + +#ifndef __ASM_RSI_SMC_H_ +#define __ASM_RSI_SMC_H_ + +#include + +/* + * This file describes the Realm Services Interface (RSI) Application Binary + * Interface (ABI) for SMC calls made from within the Realm to the RMM and + * serviced by the RMM. + */ + +/* + * The major version number of the RSI implementation. This is increased when + * the binary format or semantics of the SMC calls change. + */ +#define RSI_ABI_VERSION_MAJOR UL(1) + +/* + * The minor version number of the RSI implementation. This is increased when + * a bug is fixed, or a feature is added without breaking binary compatibility. + */ +#define RSI_ABI_VERSION_MINOR UL(0) + +#define RSI_ABI_VERSION ((RSI_ABI_VERSION_MAJOR << 16) | \ + RSI_ABI_VERSION_MINOR) + +#define RSI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16) +#define RSI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF) + +#define RSI_SUCCESS UL(0) +#define RSI_ERROR_INPUT UL(1) +#define RSI_ERROR_STATE UL(2) +#define RSI_INCOMPLETE UL(3) +#define RSI_ERROR_UNKNOWN UL(4) + +#define SMC_RSI_FID(n) ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD, \ + n) + +/* + * Returns RSI version. + * + * arg1 == Requested interface revision + * ret0 == Status / error + * ret1 == Lower implemented interface revision + * ret2 == Higher implemented interface revision + */ +#define SMC_RSI_ABI_VERSION SMC_RSI_FID(0x190) + +/* + * Read feature register. + * + * arg1 == Feature register index + * ret0 == Status / error + * ret1 == Feature register value + */ +#define SMC_RSI_FEATURES SMC_RSI_FID(0x191) + +/* + * Read measurement for the current Realm. + * + * arg1 == Index, which measurements slot to read + * ret0 == Status / error + * ret1 == Measurement value, bytes: 0 - 7 + * ret2 == Measurement value, bytes: 8 - 15 + * ret3 == Measurement value, bytes: 16 - 23 + * ret4 == Measurement value, bytes: 24 - 31 + * ret5 == Measurement value, bytes: 32 - 39 + * ret6 == Measurement value, bytes: 40 - 47 + * ret7 == Measurement value, bytes: 48 - 55 + * ret8 == Measurement value, bytes: 56 - 63 + */ +#define SMC_RSI_MEASUREMENT_READ SMC_RSI_FID(0x192) + +/* + * Extend Realm Extensible Measurement (REM) value. + * + * arg1 == Index, which measurements slot to extend + * arg2 == Size of realm measurement in bytes, max 64 bytes + * arg3 == Measurement value, bytes: 0 - 7 + * arg4 == Measurement value, bytes: 8 - 15 + * arg5 == Measurement value, bytes: 16 - 23 + * arg6 == Measurement value, bytes: 24 - 31 + * arg7 == Measurement value, bytes: 32 - 39 + * arg8 == Measurement value, bytes: 40 - 47 + * arg9 == Measurement value, bytes: 48 - 55 + * arg10 == Measurement value, bytes: 56 - 63 + * ret0 == Status / error + */ +#define SMC_RSI_MEASUREMENT_EXTEND SMC_RSI_FID(0x193) + +/* + * Initialize the operation to retrieve an attestation token. + * + * arg1 == Challenge value, bytes: 0 - 7 + * arg2 == Challenge value, bytes: 8 - 15 + * arg3 == Challenge value, bytes: 16 - 23 + * arg4 == Challenge value, bytes: 24 - 31 + * arg5 == Challenge value, bytes: 32 - 39 + * arg6 == Challenge value, bytes: 40 - 47 + * arg7 == Challenge value, bytes: 48 - 55 + * arg8 == Challenge value, bytes: 56 - 63 + * ret0 == Status / error + * ret1 == Upper bound of token size in bytes + */ +#define SMC_RSI_ATTESTATION_TOKEN_INIT SMC_RSI_FID(0x194) + +/* + * Continue the operation to retrieve an attestation token. + * + * arg1 == The IPA of token buffer + * arg2 == Offset within the granule of the token buffer + * arg3 == Size of the granule buffer + * ret0 == Status / error + * ret1 == Length of token bytes copied to the granule buffer + */ +#define SMC_RSI_ATTESTATION_TOKEN_CONTINUE SMC_RSI_FID(0x195) + +#ifndef __ASSEMBLY__ + +struct realm_config { + union { + struct { + unsigned long ipa_bits; /* Width of IPA in bits */ + unsigned long hash_algo; /* Hash algorithm */ + }; + u8 pad[0x200]; + }; + union { + u8 rpv[64]; /* Realm Personalization Value */ + u8 pad2[0xe00]; + }; + /* + * The RMM requires the configuration structure to be aligned to a 4k + * boundary, ensure this happens by aligning this structure. + */ +} __aligned(0x1000); + +#endif /* __ASSEMBLY__ */ + +/* + * Read configuration for the current Realm. + * + * arg1 == struct realm_config addr + * ret0 == Status / error + */ +#define SMC_RSI_REALM_CONFIG SMC_RSI_FID(0x196) + +/* + * Request RIPAS of a target IPA range to be changed to a specified value. + * + * arg1 == Base IPA address of target region + * arg2 == Top of the region + * arg3 == RIPAS value + * arg4 == flags + * ret0 == Status / error + * ret1 == Top of modified IPA range + * ret2 == Whether the Host accepted or rejected the request + */ +#define SMC_RSI_IPA_STATE_SET SMC_RSI_FID(0x197) + +#define RSI_NO_CHANGE_DESTROYED UL(0) +#define RSI_CHANGE_DESTROYED UL(1) + +#define RSI_ACCEPT UL(0) +#define RSI_REJECT UL(1) + +/* + * Get RIPAS of a target IPA range. + * + * arg1 == Base IPA of target region + * arg2 == End of target IPA region + * ret0 == Status / error + * ret1 == Top of IPA region which has the reported RIPAS value + * ret2 == RIPAS value + */ +#define SMC_RSI_IPA_STATE_GET SMC_RSI_FID(0x198) + +/* + * Make a Host call. + * + * arg1 == IPA of host call structure + * ret0 == Status / error + */ +#define SMC_RSI_HOST_CALL SMC_RSI_FID(0x199) + +#endif /* __ASM_RSI_SMC_H_ */ diff --git a/arch/arm64/include/asm/scs.h b/arch/arm64/include/asm/scs.h index 2e010ea76be2f5..a76f9b387a269e 100644 --- a/arch/arm64/include/asm/scs.h +++ b/arch/arm64/include/asm/scs.h @@ -46,8 +46,14 @@ static inline void dynamic_scs_init(void) static inline void dynamic_scs_init(void) {} #endif +enum { + EDYNSCS_INVALID_CIE_HEADER = 1, + EDYNSCS_INVALID_CIE_SDATA_SIZE = 2, + EDYNSCS_INVALID_FDE_AUGM_DATA_SIZE = 3, + EDYNSCS_INVALID_CFA_OPCODE = 4, +}; + int __pi_scs_patch(const u8 eh_frame[], int size); -asmlinkage void __pi_scs_patch_vmlinux(void); #endif /* __ASSEMBLY __ */ diff --git a/arch/arm64/include/asm/set_memory.h b/arch/arm64/include/asm/set_memory.h index 917761feeffdda..90f61b17275e1b 100644 --- a/arch/arm64/include/asm/set_memory.h +++ b/arch/arm64/include/asm/set_memory.h @@ -13,6 +13,10 @@ int set_memory_valid(unsigned long addr, int numpages, int enable); int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page); +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid); bool kernel_page_present(struct page *page); +int set_memory_encrypted(unsigned long addr, int numpages); +int set_memory_decrypted(unsigned long addr, int numpages); + #endif /* _ASM_ARM64_SET_MEMORY_H */ diff --git a/arch/arm64/include/asm/spinlock_types.h b/arch/arm64/include/asm/spinlock_types.h index 11ab1c07769779..7cde3d8bd0addc 100644 --- a/arch/arm64/include/asm/spinlock_types.h +++ b/arch/arm64/include/asm/spinlock_types.h @@ -6,7 +6,7 @@ #define __ASM_SPINLOCK_TYPES_H #if !defined(__LINUX_SPINLOCK_TYPES_RAW_H) && !defined(__ASM_SPINLOCK_H) -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif #include diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index f63dc654e545f4..821a8fdd31af47 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -60,13 +60,27 @@ static inline void unwind_init_common(struct unwind_state *state) state->stack = stackinfo_get_unknown(); } -static struct stack_info *unwind_find_next_stack(const struct unwind_state *state, - unsigned long sp, - unsigned long size) +/** + * unwind_find_stack() - Find the accessible stack which entirely contains an + * object. + * + * @state: the current unwind state. + * @sp: the base address of the object. + * @size: the size of the object. + * + * Return: a pointer to the relevant stack_info if found; NULL otherwise. + */ +static struct stack_info *unwind_find_stack(struct unwind_state *state, + unsigned long sp, + unsigned long size) { - for (int i = 0; i < state->nr_stacks; i++) { - struct stack_info *info = &state->stacks[i]; + struct stack_info *info = &state->stack; + if (stackinfo_on_stack(info, sp, size)) + return info; + + for (int i = 0; i < state->nr_stacks; i++) { + info = &state->stacks[i]; if (stackinfo_on_stack(info, sp, size)) return info; } @@ -75,36 +89,31 @@ static struct stack_info *unwind_find_next_stack(const struct unwind_state *stat } /** - * unwind_consume_stack() - Check if an object is on an accessible stack, - * updating stack boundaries so that future unwind steps cannot consume this - * object again. + * unwind_consume_stack() - Update stack boundaries so that future unwind steps + * cannot consume this object again. * * @state: the current unwind state. + * @info: the stack_info of the stack containing the object. * @sp: the base address of the object. * @size: the size of the object. * * Return: 0 upon success, an error code otherwise. */ -static inline int unwind_consume_stack(struct unwind_state *state, - unsigned long sp, - unsigned long size) +static inline void unwind_consume_stack(struct unwind_state *state, + struct stack_info *info, + unsigned long sp, + unsigned long size) { - struct stack_info *next; - - if (stackinfo_on_stack(&state->stack, sp, size)) - goto found; - - next = unwind_find_next_stack(state, sp, size); - if (!next) - return -EINVAL; + struct stack_info tmp; /* * Stack transitions are strictly one-way, and once we've * transitioned from one stack to another, it's never valid to * unwind back to the old stack. * - * Remove the current stack from the list of stacks so that it cannot - * be found on a subsequent transition. + * Destroy the old stack info so that it cannot be found upon a + * subsequent transition. If the stack has not changed, we'll + * immediately restore the current stack info. * * Note that stacks can nest in several valid orders, e.g. * @@ -115,16 +124,15 @@ static inline int unwind_consume_stack(struct unwind_state *state, * ... so we do not check the specific order of stack * transitions. */ - state->stack = *next; - *next = stackinfo_get_unknown(); + tmp = *info; + *info = stackinfo_get_unknown(); + state->stack = tmp; -found: /* * Future unwind steps can only consume stack above this frame record. * Update the current stack to start immediately above it. */ state->stack.low = sp + size; - return 0; } /** @@ -137,21 +145,25 @@ static inline int unwind_consume_stack(struct unwind_state *state, static inline int unwind_next_frame_record(struct unwind_state *state) { + struct stack_info *info; + struct frame_record *record; unsigned long fp = state->fp; - int err; if (fp & 0x7) return -EINVAL; - err = unwind_consume_stack(state, fp, 16); - if (err) - return err; + info = unwind_find_stack(state, fp, sizeof(*record)); + if (!info) + return -EINVAL; + + unwind_consume_stack(state, info, fp, sizeof(*record)); /* * Record this frame record's values. */ - state->fp = READ_ONCE(*(unsigned long *)(fp)); - state->pc = READ_ONCE(*(unsigned long *)(fp + 8)); + record = (struct frame_record *)fp; + state->fp = READ_ONCE(record->fp); + state->pc = READ_ONCE(record->lr); return 0; } diff --git a/arch/arm64/include/asm/stacktrace/frame.h b/arch/arm64/include/asm/stacktrace/frame.h new file mode 100644 index 00000000000000..0ee0f6ba0fd864 --- /dev/null +++ b/arch/arm64/include/asm/stacktrace/frame.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __ASM_STACKTRACE_FRAME_H +#define __ASM_STACKTRACE_FRAME_H + +/* + * - FRAME_META_TYPE_NONE + * + * This value is reserved. + * + * - FRAME_META_TYPE_FINAL + * + * The record is the last entry on the stack. + * Unwinding should terminate successfully. + * + * - FRAME_META_TYPE_PT_REGS + * + * The record is embedded within a struct pt_regs, recording the registers at + * an arbitrary point in time. + * Unwinding should consume pt_regs::pc, followed by pt_regs::lr. + * + * Note: all other values are reserved and should result in unwinding + * terminating with an error. + */ +#define FRAME_META_TYPE_NONE 0 +#define FRAME_META_TYPE_FINAL 1 +#define FRAME_META_TYPE_PT_REGS 2 + +#ifndef __ASSEMBLY__ +/* + * A standard AAPCS64 frame record. + */ +struct frame_record { + u64 fp; + u64 lr; +}; + +/* + * A metadata frame record indicating a special unwind. + * The record::{fp,lr} fields must be zero to indicate the presence of + * metadata. + */ +struct frame_record_meta { + struct frame_record record; + u64 type; +}; +#endif /* __ASSEMBLY */ + +#endif /* __ASM_STACKTRACE_FRAME_H */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 9ea97dddefc405..b8303a83c0bff5 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -542,18 +542,6 @@ #define SYS_MAIR_EL2 sys_reg(3, 4, 10, 2, 0) #define SYS_AMAIR_EL2 sys_reg(3, 4, 10, 3, 0) -#define SYS_MPAMHCR_EL2 sys_reg(3, 4, 10, 4, 0) -#define SYS_MPAMVPMV_EL2 sys_reg(3, 4, 10, 4, 1) -#define SYS_MPAM2_EL2 sys_reg(3, 4, 10, 5, 0) -#define __SYS__MPAMVPMx_EL2(x) sys_reg(3, 4, 10, 6, x) -#define SYS_MPAMVPM0_EL2 __SYS__MPAMVPMx_EL2(0) -#define SYS_MPAMVPM1_EL2 __SYS__MPAMVPMx_EL2(1) -#define SYS_MPAMVPM2_EL2 __SYS__MPAMVPMx_EL2(2) -#define SYS_MPAMVPM3_EL2 __SYS__MPAMVPMx_EL2(3) -#define SYS_MPAMVPM4_EL2 __SYS__MPAMVPMx_EL2(4) -#define SYS_MPAMVPM5_EL2 __SYS__MPAMVPMx_EL2(5) -#define SYS_MPAMVPM6_EL2 __SYS__MPAMVPMx_EL2(6) -#define SYS_MPAMVPM7_EL2 __SYS__MPAMVPMx_EL2(7) #define SYS_VBAR_EL2 sys_reg(3, 4, 12, 0, 0) #define SYS_RVBAR_EL2 sys_reg(3, 4, 12, 0, 1) @@ -1101,6 +1089,26 @@ /* Initial value for Permission Overlay Extension for EL0 */ #define POR_EL0_INIT POE_RXW +/* + * Definitions for Guarded Control Stack + */ + +#define GCS_CAP_ADDR_MASK GENMASK(63, 12) +#define GCS_CAP_ADDR_SHIFT 12 +#define GCS_CAP_ADDR_WIDTH 52 +#define GCS_CAP_ADDR(x) FIELD_GET(GCS_CAP_ADDR_MASK, x) + +#define GCS_CAP_TOKEN_MASK GENMASK(11, 0) +#define GCS_CAP_TOKEN_SHIFT 0 +#define GCS_CAP_TOKEN_WIDTH 12 +#define GCS_CAP_TOKEN(x) FIELD_GET(GCS_CAP_TOKEN_MASK, x) + +#define GCS_CAP_VALID_TOKEN 0x1 +#define GCS_CAP_IN_PROGRESS_TOKEN 0x5 + +#define GCS_CAP(x) ((((unsigned long)x) & GCS_CAP_ADDR_MASK) | \ + GCS_CAP_VALID_TOKEN) + #define ARM64_FEATURE_FIELD_BITS 4 /* Defined for compatibility only, do not add new users. */ diff --git a/arch/arm64/include/asm/text-patching.h b/arch/arm64/include/asm/text-patching.h new file mode 100644 index 00000000000000..587bdb91ab7a64 --- /dev/null +++ b/arch/arm64/include/asm/text-patching.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __ASM_PATCHING_H +#define __ASM_PATCHING_H + +#include + +int aarch64_insn_read(void *addr, u32 *insnp); +int aarch64_insn_write(void *addr, u32 insn); + +int aarch64_insn_write_literal_u64(void *addr, u64 val); +void *aarch64_insn_set(void *dst, u32 insn, size_t len); +void *aarch64_insn_copy(void *dst, void *src, size_t len); + +int aarch64_insn_patch_text_nosync(void *addr, u32 insn); +int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); + +#endif /* __ASM_PATCHING_H */ diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index 95fbc8c0560798..bc94e036a26b99 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -431,6 +431,23 @@ do { \ #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false, kvm_lpa2_is_enabled()); +static inline bool __flush_tlb_range_limit_excess(unsigned long start, + unsigned long end, unsigned long pages, unsigned long stride) +{ + /* + * When the system does not support TLB range based flush + * operation, (MAX_DVM_OPS - 1) pages can be handled. But + * with TLB range based operation, MAX_TLBI_RANGE_PAGES + * pages can be handled. + */ + if ((!system_supports_tlb_range() && + (end - start) >= (MAX_DVM_OPS * stride)) || + pages > MAX_TLBI_RANGE_PAGES) + return true; + + return false; +} + static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, unsigned long start, unsigned long end, unsigned long stride, bool last_level, @@ -442,15 +459,7 @@ static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, end = round_up(end, stride); pages = (end - start) >> PAGE_SHIFT; - /* - * When not uses TLB range ops, we can handle up to - * (MAX_DVM_OPS - 1) pages; - * When uses TLB range ops, we can handle up to - * MAX_TLBI_RANGE_PAGES pages. - */ - if ((!system_supports_tlb_range() && - (end - start) >= (MAX_DVM_OPS * stride)) || - pages > MAX_TLBI_RANGE_PAGES) { + if (__flush_tlb_range_limit_excess(start, end, pages, stride)) { flush_tlb_mm(vma->vm_mm); return; } @@ -492,19 +501,21 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - unsigned long addr; + const unsigned long stride = PAGE_SIZE; + unsigned long pages; - if ((end - start) > (MAX_DVM_OPS * PAGE_SIZE)) { + start = round_down(start, stride); + end = round_up(end, stride); + pages = (end - start) >> PAGE_SHIFT; + + if (__flush_tlb_range_limit_excess(start, end, pages, stride)) { flush_tlb_all(); return; } - start = __TLBI_VADDR(start, 0); - end = __TLBI_VADDR(end, 0); - dsb(ishst); - for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) - __tlbi(vaale1is, addr); + __flush_tlb_range_op(vaale1is, start, pages, stride, 0, + TLBI_TTL_UNKNOWN, false, lpa2_is_enabled()); dsb(ish); isb(); } diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 1aa4ecb73429fe..5b91803201ef88 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -502,4 +502,44 @@ static inline size_t probe_subpage_writeable(const char __user *uaddr, #endif /* CONFIG_ARCH_HAS_SUBPAGE_FAULTS */ +#ifdef CONFIG_ARM64_GCS + +static inline int gcssttr(unsigned long __user *addr, unsigned long val) +{ + register unsigned long __user *_addr __asm__ ("x0") = addr; + register unsigned long _val __asm__ ("x1") = val; + int err = 0; + + /* GCSSTTR x1, x0 */ + asm volatile( + "1: .inst 0xd91f1c01\n" + "2: \n" + _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0) + : "+r" (err) + : "rZ" (_val), "r" (_addr) + : "memory"); + + return err; +} + +static inline void put_user_gcs(unsigned long val, unsigned long __user *addr, + int *err) +{ + int ret; + + if (!access_ok((char __user *)addr, sizeof(u64))) { + *err = -EFAULT; + return; + } + + uaccess_ttbr0_enable(); + ret = gcssttr(addr, val); + if (ret != 0) + *err = ret; + uaccess_ttbr0_disable(); +} + + +#endif /* CONFIG_ARM64_GCS */ + #endif /* __ASM_UACCESS_H */ diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h index 4305995c8f82f4..3e3c3fdb184274 100644 --- a/arch/arm64/include/asm/vdso.h +++ b/arch/arm64/include/asm/vdso.h @@ -5,13 +5,6 @@ #ifndef __ASM_VDSO_H #define __ASM_VDSO_H -/* - * Default link address for the vDSO. - * Since we randomise the VDSO mapping, there's little point in trying - * to prelink this. - */ -#define VDSO_LBASE 0x0 - #define __VVAR_PAGES 2 #ifndef __ASSEMBLY__ @@ -20,7 +13,7 @@ #define VDSO_SYMBOL(base, name) \ ({ \ - (void *)(vdso_offset_##name - VDSO_LBASE + (unsigned long)(base)); \ + (void *)(vdso_offset_##name + (unsigned long)(base)); \ }) extern char vdso_start[], vdso_end[]; diff --git a/arch/arm64/include/asm/vdso/vsyscall.h b/arch/arm64/include/asm/vdso/vsyscall.h index 5b6d0dd3cef548..eea51946d45a2f 100644 --- a/arch/arm64/include/asm/vdso/vsyscall.h +++ b/arch/arm64/include/asm/vdso/vsyscall.h @@ -6,7 +6,6 @@ #ifndef __ASSEMBLY__ -#include #include enum vvar_pages { @@ -37,7 +36,7 @@ struct vdso_rng_data *__arm64_get_k_vdso_rnd_data(void) #define __arch_get_k_vdso_rng_data __arm64_get_k_vdso_rnd_data static __always_inline -void __arm64_update_vsyscall(struct vdso_data *vdata, struct timekeeper *tk) +void __arm64_update_vsyscall(struct vdso_data *vdata) { vdata[CS_HRES_COARSE].mask = VDSO_PRECISION_MASK; vdata[CS_RAW].mask = VDSO_PRECISION_MASK; diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h index 06f8ec0906a6e9..4f9bbd4d6c2671 100644 --- a/arch/arm64/include/asm/vncr_mapping.h +++ b/arch/arm64/include/asm/vncr_mapping.h @@ -50,7 +50,6 @@ #define VNCR_VBAR_EL1 0x250 #define VNCR_TCR2_EL1 0x270 #define VNCR_PIRE0_EL1 0x290 -#define VNCR_PIRE0_EL2 0x298 #define VNCR_PIR_EL1 0x2A0 #define VNCR_POR_EL1 0x2A8 #define VNCR_ICH_LR0_EL2 0x400 diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h index 055381b2c61595..48d46b768eaec4 100644 --- a/arch/arm64/include/uapi/asm/hwcap.h +++ b/arch/arm64/include/uapi/asm/hwcap.h @@ -21,7 +21,7 @@ * HWCAP flags - for AT_HWCAP * * Bits 62 and 63 are reserved for use by libc. - * Bits 32-61 are unallocated for potential use by libc. + * Bits 33-61 are unallocated for potential use by libc. */ #define HWCAP_FP (1 << 0) #define HWCAP_ASIMD (1 << 1) @@ -55,6 +55,7 @@ #define HWCAP_SB (1 << 29) #define HWCAP_PACA (1 << 30) #define HWCAP_PACG (1UL << 31) +#define HWCAP_GCS (1UL << 32) /* * HWCAP2 flags - for AT_HWCAP2 @@ -124,4 +125,8 @@ #define HWCAP2_SME_SF8DP2 (1UL << 62) #define HWCAP2_POE (1UL << 63) +/* + * HWCAP3 flags - for AT_HWCAP3 + */ + #endif /* _UAPI__ASM_HWCAP_H */ diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 964df31da9751c..66736ff04011e0 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -484,6 +484,12 @@ enum { */ #define KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2 (1ULL << 0) +/* + * Shutdown caused by a PSCI v1.3 SYSTEM_OFF2 call. + * Valid only when the system event has a type of KVM_SYSTEM_EVENT_SHUTDOWN. + */ +#define KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2 (1ULL << 0) + /* run->fail_entry.hardware_entry_failure_reason codes. */ #define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0) diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index 7fa2f7036aa785..0f39ba4f3efd4a 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h @@ -324,6 +324,14 @@ struct user_za_header { #define ZA_PT_SIZE(vq) \ (ZA_PT_ZA_OFFSET + ZA_PT_ZA_SIZE(vq)) +/* GCS state (NT_ARM_GCS) */ + +struct user_gcs { + __u64 features_enabled; + __u64 features_locked; + __u64 gcspr_el0; +}; + #endif /* __ASSEMBLY__ */ #endif /* _UAPI__ASM_PTRACE_H */ diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h index bb7af77a30a726..d42f7a92238b9d 100644 --- a/arch/arm64/include/uapi/asm/sigcontext.h +++ b/arch/arm64/include/uapi/asm/sigcontext.h @@ -183,6 +183,15 @@ struct zt_context { __u16 __reserved[3]; }; +#define GCS_MAGIC 0x47435300 + +struct gcs_context { + struct _aarch64_ctx head; + __u64 gcspr; + __u64 features_enabled; + __u64 reserved; +}; + #endif /* !__ASSEMBLY__ */ #include diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 2b112f3b75109a..71c29a2a2f190f 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -33,7 +33,8 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ return_address.o cpuinfo.o cpu_errata.o \ cpufeature.o alternative.o cacheinfo.o \ smp.o smp_spin_table.o topology.o smccc-call.o \ - syscall.o proton-pack.o idle.o patching.o pi/ + syscall.o proton-pack.o idle.o patching.o pi/ \ + rsi.o obj-$(CONFIG_COMPAT) += sys32.o signal32.o \ sys_compat.o diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index b21dd24b8efc3b..29bf85dacffe1c 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -12,15 +12,12 @@ #include #include #include -#include #include -#include #include #include #include #include #include -#include #include #include #include @@ -28,8 +25,6 @@ int main(void) { - DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); - BLANK(); DEFINE(TSK_TI_CPU, offsetof(struct task_struct, thread_info.cpu)); DEFINE(TSK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags)); DEFINE(TSK_TI_PREEMPT, offsetof(struct task_struct, thread_info.preempt_count)); @@ -79,45 +74,27 @@ int main(void) DEFINE(S_PSTATE, offsetof(struct pt_regs, pstate)); DEFINE(S_SYSCALLNO, offsetof(struct pt_regs, syscallno)); DEFINE(S_SDEI_TTBR1, offsetof(struct pt_regs, sdei_ttbr1)); - DEFINE(S_PMR_SAVE, offsetof(struct pt_regs, pmr_save)); + DEFINE(S_PMR, offsetof(struct pt_regs, pmr)); DEFINE(S_STACKFRAME, offsetof(struct pt_regs, stackframe)); + DEFINE(S_STACKFRAME_TYPE, offsetof(struct pt_regs, stackframe.type)); DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs)); BLANK(); #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS - DEFINE(FREGS_X0, offsetof(struct ftrace_regs, regs[0])); - DEFINE(FREGS_X2, offsetof(struct ftrace_regs, regs[2])); - DEFINE(FREGS_X4, offsetof(struct ftrace_regs, regs[4])); - DEFINE(FREGS_X6, offsetof(struct ftrace_regs, regs[6])); - DEFINE(FREGS_X8, offsetof(struct ftrace_regs, regs[8])); - DEFINE(FREGS_FP, offsetof(struct ftrace_regs, fp)); - DEFINE(FREGS_LR, offsetof(struct ftrace_regs, lr)); - DEFINE(FREGS_SP, offsetof(struct ftrace_regs, sp)); - DEFINE(FREGS_PC, offsetof(struct ftrace_regs, pc)); + DEFINE(FREGS_X0, offsetof(struct __arch_ftrace_regs, regs[0])); + DEFINE(FREGS_X2, offsetof(struct __arch_ftrace_regs, regs[2])); + DEFINE(FREGS_X4, offsetof(struct __arch_ftrace_regs, regs[4])); + DEFINE(FREGS_X6, offsetof(struct __arch_ftrace_regs, regs[6])); + DEFINE(FREGS_X8, offsetof(struct __arch_ftrace_regs, regs[8])); + DEFINE(FREGS_FP, offsetof(struct __arch_ftrace_regs, fp)); + DEFINE(FREGS_LR, offsetof(struct __arch_ftrace_regs, lr)); + DEFINE(FREGS_SP, offsetof(struct __arch_ftrace_regs, sp)); + DEFINE(FREGS_PC, offsetof(struct __arch_ftrace_regs, pc)); #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS - DEFINE(FREGS_DIRECT_TRAMP, offsetof(struct ftrace_regs, direct_tramp)); -#endif - DEFINE(FREGS_SIZE, sizeof(struct ftrace_regs)); - BLANK(); + DEFINE(FREGS_DIRECT_TRAMP, offsetof(struct __arch_ftrace_regs, direct_tramp)); #endif -#ifdef CONFIG_COMPAT - DEFINE(COMPAT_SIGFRAME_REGS_OFFSET, offsetof(struct compat_sigframe, uc.uc_mcontext.arm_r0)); - DEFINE(COMPAT_RT_SIGFRAME_REGS_OFFSET, offsetof(struct compat_rt_sigframe, sig.uc.uc_mcontext.arm_r0)); + DEFINE(FREGS_SIZE, sizeof(struct __arch_ftrace_regs)); BLANK(); #endif - DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter)); - BLANK(); - DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm)); - DEFINE(VMA_VM_FLAGS, offsetof(struct vm_area_struct, vm_flags)); - BLANK(); - DEFINE(VM_EXEC, VM_EXEC); - BLANK(); - DEFINE(PAGE_SZ, PAGE_SIZE); - BLANK(); - DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE); - DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE); - BLANK(); - DEFINE(PREEMPT_DISABLE_OFFSET, PREEMPT_DISABLE_OFFSET); - BLANK(); DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); BLANK(); DEFINE(FTR_OVR_VAL_OFFSET, offsetof(struct arm64_ftr_override, val)); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 718728a85430fa..6ce71f444ed84f 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -103,6 +103,7 @@ static DECLARE_BITMAP(elf_hwcap, MAX_CPU_FEATURES) __read_mostly; COMPAT_HWCAP_LPAE) unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT; unsigned int compat_elf_hwcap2 __read_mostly; +unsigned int compat_elf_hwcap3 __read_mostly; #endif DECLARE_BITMAP(system_cpucaps, ARM64_NCAPS); @@ -228,6 +229,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar0[] = { }; static const struct arm64_ftr_bits ftr_id_aa64isar1[] = { + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_XS_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_I8MM_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_DGH_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR1_EL1_BF16_SHIFT, 4, 0), @@ -291,6 +293,8 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = { }; static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = { + ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_GCS), + FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_EL1_GCS_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SME), FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_EL1_SME_SHIFT, 4, 0), ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR1_EL1_MPAM_frac_SHIFT, 4, 0), @@ -684,6 +688,14 @@ static const struct arm64_ftr_bits ftr_id_dfr1[] = { ARM64_FTR_END, }; +static const struct arm64_ftr_bits ftr_mpamidr[] = { + ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, MPAMIDR_EL1_PMG_MAX_SHIFT, MPAMIDR_EL1_PMG_MAX_WIDTH, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, MPAMIDR_EL1_VPMR_MAX_SHIFT, MPAMIDR_EL1_VPMR_MAX_WIDTH, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, MPAMIDR_EL1_HAS_HCR_SHIFT, 1, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, MPAMIDR_EL1_PARTID_MAX_SHIFT, MPAMIDR_EL1_PARTID_MAX_WIDTH, 0), + ARM64_FTR_END, +}; + /* * Common ftr bits for a 32bit register with all hidden, strict * attributes, with 4bit feature fields and a default safe value of @@ -804,6 +816,9 @@ static const struct __ftr_reg_entry { ARM64_FTR_REG(SYS_ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3), ARM64_FTR_REG(SYS_ID_AA64MMFR4_EL1, ftr_id_aa64mmfr4), + /* Op1 = 0, CRn = 10, CRm = 4 */ + ARM64_FTR_REG(SYS_MPAMIDR_EL1, ftr_mpamidr), + /* Op1 = 1, CRn = 0, CRm = 0 */ ARM64_FTR_REG(SYS_GMID_EL1, ftr_gmid), @@ -1163,6 +1178,9 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info) cpacr_restore(cpacr); } + if (id_aa64pfr0_mpam(info->reg_id_aa64pfr0)) + init_cpu_ftr_reg(SYS_MPAMIDR_EL1, info->reg_mpamidr); + if (id_aa64pfr1_mte(info->reg_id_aa64pfr1)) init_cpu_ftr_reg(SYS_GMID_EL1, info->reg_gmid); } @@ -1419,6 +1437,11 @@ void update_cpu_features(int cpu, cpacr_restore(cpacr); } + if (id_aa64pfr0_mpam(info->reg_id_aa64pfr0)) { + taint |= check_update_ftr_reg(SYS_MPAMIDR_EL1, cpu, + info->reg_mpamidr, boot->reg_mpamidr); + } + /* * The kernel uses the LDGM/STGM instructions and the number of tags * they read/write depends on the GMID_EL1.BS field. Check that the @@ -2358,6 +2381,14 @@ static void cpu_enable_poe(const struct arm64_cpu_capabilities *__unused) } #endif +#ifdef CONFIG_ARM64_GCS +static void cpu_enable_gcs(const struct arm64_cpu_capabilities *__unused) +{ + /* GCSPR_EL0 is always readable */ + write_sysreg_s(GCSCRE0_EL1_nTR, SYS_GCSCRE0_EL1); +} +#endif + /* Internal helper functions to match cpu capability type */ static bool cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap) @@ -2377,6 +2408,36 @@ cpucap_panic_on_conflict(const struct arm64_cpu_capabilities *cap) return !!(cap->type & ARM64_CPUCAP_PANIC_ON_CONFLICT); } +static bool +test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope) +{ + if (!has_cpuid_feature(entry, scope)) + return false; + + /* Check firmware actually enabled MPAM on this cpu. */ + return (read_sysreg_s(SYS_MPAM1_EL1) & MPAM1_EL1_MPAMEN); +} + +static void +cpu_enable_mpam(const struct arm64_cpu_capabilities *entry) +{ + /* + * Access by the kernel (at EL1) should use the reserved PARTID + * which is configured unrestricted. This avoids priority-inversion + * where latency sensitive tasks have to wait for a task that has + * been throttled to release the lock. + */ + write_sysreg_s(0, SYS_MPAM1_EL1); +} + +static bool +test_has_mpam_hcr(const struct arm64_cpu_capabilities *entry, int scope) +{ + u64 idr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1); + + return idr & MPAMIDR_EL1_HAS_HCR; +} + static const struct arm64_cpu_capabilities arm64_features[] = { { .capability = ARM64_ALWAYS_BOOT, @@ -2590,6 +2651,21 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .cpus = &dbm_cpus, ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, DBM) }, +#endif +#ifdef CONFIG_ARM64_HAFT + { + .desc = "Hardware managed Access Flag for Table Descriptors", + /* + * Contrary to the page/block access flag, the table access flag + * cannot be emulated in software (no access fault will occur). + * Therefore this should be used only if it's supported system + * wide. + */ + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .capability = ARM64_HAFT, + .matches = has_cpuid_feature, + ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HAFT) + }, #endif { .desc = "CRC32 instructions", @@ -2873,6 +2949,20 @@ static const struct arm64_cpu_capabilities arm64_features[] = { #endif }, #endif + { + .desc = "Memory Partitioning And Monitoring", + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .capability = ARM64_MPAM, + .matches = test_has_mpam, + .cpu_enable = cpu_enable_mpam, + ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, MPAM, 1) + }, + { + .desc = "Memory Partitioning And Monitoring Virtualisation", + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .capability = ARM64_MPAM_HCR, + .matches = test_has_mpam_hcr, + }, { .desc = "NV1", .capability = ARM64_HAS_HCR_NV1, @@ -2889,6 +2979,16 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .cpu_enable = cpu_enable_poe, ARM64_CPUID_FIELDS(ID_AA64MMFR3_EL1, S1POE, IMP) }, +#endif +#ifdef CONFIG_ARM64_GCS + { + .desc = "Guarded Control Stack (GCS)", + .capability = ARM64_HAS_GCS, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .cpu_enable = cpu_enable_gcs, + .matches = has_cpuid_feature, + ARM64_CPUID_FIELDS(ID_AA64PFR1_EL1, GCS, IMP) + }, #endif {}, }; @@ -3005,6 +3105,9 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = { HWCAP_CAP(ID_AA64ZFR0_EL1, I8MM, IMP, CAP_HWCAP, KERNEL_HWCAP_SVEI8MM), HWCAP_CAP(ID_AA64ZFR0_EL1, F32MM, IMP, CAP_HWCAP, KERNEL_HWCAP_SVEF32MM), HWCAP_CAP(ID_AA64ZFR0_EL1, F64MM, IMP, CAP_HWCAP, KERNEL_HWCAP_SVEF64MM), +#endif +#ifdef CONFIG_ARM64_GCS + HWCAP_CAP(ID_AA64PFR1_EL1, GCS, IMP, CAP_HWCAP, KERNEL_HWCAP_GCS), #endif HWCAP_CAP(ID_AA64PFR1_EL1, SSBS, SSBS2, CAP_HWCAP, KERNEL_HWCAP_SSBS), #ifdef CONFIG_ARM64_BTI @@ -3396,6 +3499,36 @@ static void verify_hyp_capabilities(void) } } +static void verify_mpam_capabilities(void) +{ + u64 cpu_idr = read_cpuid(ID_AA64PFR0_EL1); + u64 sys_idr = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); + u16 cpu_partid_max, cpu_pmg_max, sys_partid_max, sys_pmg_max; + + if (FIELD_GET(ID_AA64PFR0_EL1_MPAM_MASK, cpu_idr) != + FIELD_GET(ID_AA64PFR0_EL1_MPAM_MASK, sys_idr)) { + pr_crit("CPU%d: MPAM version mismatch\n", smp_processor_id()); + cpu_die_early(); + } + + cpu_idr = read_cpuid(MPAMIDR_EL1); + sys_idr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1); + if (FIELD_GET(MPAMIDR_EL1_HAS_HCR, cpu_idr) != + FIELD_GET(MPAMIDR_EL1_HAS_HCR, sys_idr)) { + pr_crit("CPU%d: Missing MPAM HCR\n", smp_processor_id()); + cpu_die_early(); + } + + cpu_partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, cpu_idr); + cpu_pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, cpu_idr); + sys_partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, sys_idr); + sys_pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, sys_idr); + if (cpu_partid_max < sys_partid_max || cpu_pmg_max < sys_pmg_max) { + pr_crit("CPU%d: MPAM PARTID/PMG max values are mismatched\n", smp_processor_id()); + cpu_die_early(); + } +} + /* * Run through the enabled system capabilities and enable() it on this CPU. * The capabilities were decided based on the available CPUs at the boot time. @@ -3422,6 +3555,9 @@ static void verify_local_cpu_capabilities(void) if (is_hyp_mode_available()) verify_hyp_capabilities(); + + if (system_supports_mpam()) + verify_mpam_capabilities(); } void check_local_cpu_capabilities(void) @@ -3499,6 +3635,11 @@ unsigned long cpu_get_elf_hwcap2(void) return elf_hwcap[1]; } +unsigned long cpu_get_elf_hwcap3(void) +{ + return elf_hwcap[2]; +} + static void __init setup_boot_cpu_capabilities(void) { /* diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 44718d0482b3b4..d79e88fccdfce4 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -80,6 +80,7 @@ static const char *const hwcap_str[] = { [KERNEL_HWCAP_SB] = "sb", [KERNEL_HWCAP_PACA] = "paca", [KERNEL_HWCAP_PACG] = "pacg", + [KERNEL_HWCAP_GCS] = "gcs", [KERNEL_HWCAP_DCPODP] = "dcpodp", [KERNEL_HWCAP_SVE2] = "sve2", [KERNEL_HWCAP_SVEAES] = "sveaes", @@ -478,6 +479,9 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) __cpuinfo_store_cpu_32bit(&info->aarch32); + if (id_aa64pfr0_mpam(info->reg_id_aa64pfr0)) + info->reg_mpamidr = read_cpuid(MPAMIDR_EL1); + cpuinfo_detect_icache_policy(info); } diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index 024a7b245056a8..58f047de3e1c5e 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -303,7 +303,6 @@ static int call_break_hook(struct pt_regs *regs, unsigned long esr) { struct break_hook *hook; struct list_head *list; - int (*fn)(struct pt_regs *regs, unsigned long esr) = NULL; list = user_mode(regs) ? &user_break_hook : &kernel_break_hook; @@ -313,10 +312,10 @@ static int call_break_hook(struct pt_regs *regs, unsigned long esr) */ list_for_each_entry_rcu(hook, list, node) { if ((esr_brk_comment(esr) & ~hook->mask) == hook->imm) - fn = hook->fn; + return hook->fn(regs, esr); } - return fn ? fn(regs, esr) : DBG_HOOK_ERROR; + return DBG_HOOK_ERROR; } NOKPROBE_SYMBOL(call_break_hook); @@ -441,6 +440,11 @@ void kernel_rewind_single_step(struct pt_regs *regs) set_regs_spsr_ss(regs); } +void kernel_fastforward_single_step(struct pt_regs *regs) +{ + clear_regs_spsr_ss(regs); +} + /* ptrace API */ void user_enable_single_step(struct task_struct *task) { diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 712718aed5dd9e..1d25d8899dbf7f 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c @@ -34,8 +34,16 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md) u64 attr = md->attribute; u32 type = md->type; - if (type == EFI_MEMORY_MAPPED_IO) - return PROT_DEVICE_nGnRE; + if (type == EFI_MEMORY_MAPPED_IO) { + pgprot_t prot = __pgprot(PROT_DEVICE_nGnRE); + + if (arm64_is_protected_mmio(md->phys_addr, + md->num_pages << EFI_PAGE_SHIFT)) + prot = pgprot_encrypted(prot); + else + prot = pgprot_decrypted(prot); + return pgprot_val(prot); + } if (region_is_misaligned(md)) { static bool __initdata code_is_misaligned; diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c index 3fcd9d080bf2a9..b260ddc4d3e9ad 100644 --- a/arch/arm64/kernel/entry-common.c +++ b/arch/arm64/kernel/entry-common.c @@ -463,6 +463,24 @@ static void noinstr el1_bti(struct pt_regs *regs, unsigned long esr) exit_to_kernel_mode(regs); } +static void noinstr el1_gcs(struct pt_regs *regs, unsigned long esr) +{ + enter_from_kernel_mode(regs); + local_daif_inherit(regs); + do_el1_gcs(regs, esr); + local_daif_mask(); + exit_to_kernel_mode(regs); +} + +static void noinstr el1_mops(struct pt_regs *regs, unsigned long esr) +{ + enter_from_kernel_mode(regs); + local_daif_inherit(regs); + do_el1_mops(regs, esr); + local_daif_mask(); + exit_to_kernel_mode(regs); +} + static void noinstr el1_dbg(struct pt_regs *regs, unsigned long esr) { unsigned long far = read_sysreg(far_el1); @@ -505,6 +523,12 @@ asmlinkage void noinstr el1h_64_sync_handler(struct pt_regs *regs) case ESR_ELx_EC_BTI: el1_bti(regs, esr); break; + case ESR_ELx_EC_GCS: + el1_gcs(regs, esr); + break; + case ESR_ELx_EC_MOPS: + el1_mops(regs, esr); + break; case ESR_ELx_EC_BREAKPT_CUR: case ESR_ELx_EC_SOFTSTP_CUR: case ESR_ELx_EC_WATCHPT_CUR: @@ -684,6 +708,14 @@ static void noinstr el0_mops(struct pt_regs *regs, unsigned long esr) exit_to_user_mode(regs); } +static void noinstr el0_gcs(struct pt_regs *regs, unsigned long esr) +{ + enter_from_user_mode(regs); + local_daif_restore(DAIF_PROCCTX); + do_el0_gcs(regs, esr); + exit_to_user_mode(regs); +} + static void noinstr el0_inv(struct pt_regs *regs, unsigned long esr) { enter_from_user_mode(regs); @@ -766,6 +798,9 @@ asmlinkage void noinstr el0t_64_sync_handler(struct pt_regs *regs) case ESR_ELx_EC_MOPS: el0_mops(regs, esr); break; + case ESR_ELx_EC_GCS: + el0_gcs(regs, esr); + break; case ESR_ELx_EC_BREAKPT_LOW: case ESR_ELx_EC_SOFTSTP_LOW: case ESR_ELx_EC_WATCHPT_LOW: diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 7ef0e127b149fc..5ae2a34b50bda5 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -284,15 +285,16 @@ alternative_else_nop_endif stp lr, x21, [sp, #S_LR] /* - * For exceptions from EL0, create a final frame record. - * For exceptions from EL1, create a synthetic frame record so the - * interrupted code shows up in the backtrace. + * Create a metadata frame record. The unwinder will use this to + * identify and unwind exception boundaries. */ - .if \el == 0 stp xzr, xzr, [sp, #S_STACKFRAME] + .if \el == 0 + mov x0, #FRAME_META_TYPE_FINAL .else - stp x29, x22, [sp, #S_STACKFRAME] + mov x0, #FRAME_META_TYPE_PT_REGS .endif + str x0, [sp, #S_STACKFRAME_TYPE] add x29, sp, #S_STACKFRAME #ifdef CONFIG_ARM64_SW_TTBR0_PAN @@ -315,7 +317,7 @@ alternative_if_not ARM64_HAS_GIC_PRIO_MASKING alternative_else_nop_endif mrs_s x20, SYS_ICC_PMR_EL1 - str x20, [sp, #S_PMR_SAVE] + str w20, [sp, #S_PMR] mov x20, #GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET msr_s SYS_ICC_PMR_EL1, x20 @@ -342,7 +344,7 @@ alternative_if_not ARM64_HAS_GIC_PRIO_MASKING b .Lskip_pmr_restore\@ alternative_else_nop_endif - ldr x20, [sp, #S_PMR_SAVE] + ldr w20, [sp, #S_PMR] msr_s SYS_ICC_PMR_EL1, x20 /* Ensure priority change is seen by redistributor */ diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 6d21971ae5594f..8c4c1a2186cc51 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -386,7 +386,7 @@ static void task_fpsimd_load(void) * fpsimd_save_user_state() or memory corruption, we * should always record an explicit format * when we save. We always at least have the - * memory allocated for FPSMID registers so + * memory allocated for FPSIMD registers so * try that and hope for the best. */ WARN_ON_ONCE(1); diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c index a650f5e11fc5d8..245cb419ca24da 100644 --- a/arch/arm64/kernel/ftrace.c +++ b/arch/arm64/kernel/ftrace.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS struct fregs_offset { @@ -23,10 +23,10 @@ struct fregs_offset { int offset; }; -#define FREGS_OFFSET(n, field) \ -{ \ - .name = n, \ - .offset = offsetof(struct ftrace_regs, field), \ +#define FREGS_OFFSET(n, field) \ +{ \ + .name = n, \ + .offset = offsetof(struct __arch_ftrace_regs, field), \ } static const struct fregs_offset fregs_offsets[] = { @@ -481,7 +481,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent, void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { - prepare_ftrace_return(ip, &fregs->lr, fregs->fp); + prepare_ftrace_return(ip, &arch_ftrace_regs(fregs)->lr, arch_ftrace_regs(fregs)->fp); } #else /* diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index cb68adcabe0789..5ab1970ee54367 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -199,6 +200,8 @@ SYM_CODE_END(preserve_boot_args) sub sp, sp, #PT_REGS_SIZE stp xzr, xzr, [sp, #S_STACKFRAME] + mov \tmp1, #FRAME_META_TYPE_FINAL + str \tmp1, [sp, #S_STACKFRAME_TYPE] add x29, sp, #S_STACKFRAME scs_load_current diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index 7b11d84f533c9b..18749e9a6c2da4 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -266,9 +266,15 @@ static int swsusp_mte_save_tags(void) max_zone_pfn = zone_end_pfn(zone); for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) { struct page *page = pfn_to_online_page(pfn); + struct folio *folio; if (!page) continue; + folio = page_folio(page); + + if (folio_test_hugetlb(folio) && + !folio_test_hugetlb_mte_tagged(folio)) + continue; if (!page_mte_tagged(page)) continue; diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S index 65f76064c86b24..ae990da1eae5a9 100644 --- a/arch/arm64/kernel/hyp-stub.S +++ b/arch/arm64/kernel/hyp-stub.S @@ -114,8 +114,8 @@ SYM_CODE_START_LOCAL(__finalise_el2) // Use EL2 translations for SPE & TRBE and disable access from EL1 mrs x0, mdcr_el2 - bic x0, x0, #(MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT) - bic x0, x0, #(MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT) + bic x0, x0, #MDCR_EL2_E2PB_MASK + bic x0, x0, #MDCR_EL2_E2TB_MASK msr mdcr_el2, x0 // Transfer the MM state from EL1 to EL2 diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c index ef48089fbfe1a4..fe86ada23c7d43 100644 --- a/arch/arm64/kernel/io.c +++ b/arch/arm64/kernel/io.c @@ -9,34 +9,6 @@ #include #include -/* - * Copy data from IO memory space to "real" memory space. - */ -void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) -{ - while (count && !IS_ALIGNED((unsigned long)from, 8)) { - *(u8 *)to = __raw_readb(from); - from++; - to++; - count--; - } - - while (count >= 8) { - *(u64 *)to = __raw_readq(from); - from += 8; - to += 8; - count -= 8; - } - - while (count) { - *(u8 *)to = __raw_readb(from); - from++; - to++; - count--; - } -} -EXPORT_SYMBOL(__memcpy_fromio); - /* * This generates a memcpy that works on a from/to address which is aligned to * bits. Count is in terms of the number of bits sized quantities to copy. It @@ -78,62 +50,3 @@ void __iowrite32_copy_full(void __iomem *to, const void *from, size_t count) dgh(); } EXPORT_SYMBOL(__iowrite32_copy_full); - -/* - * Copy data from "real" memory space to IO memory space. - */ -void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) -{ - while (count && !IS_ALIGNED((unsigned long)to, 8)) { - __raw_writeb(*(u8 *)from, to); - from++; - to++; - count--; - } - - while (count >= 8) { - __raw_writeq(*(u64 *)from, to); - from += 8; - to += 8; - count -= 8; - } - - while (count) { - __raw_writeb(*(u8 *)from, to); - from++; - to++; - count--; - } -} -EXPORT_SYMBOL(__memcpy_toio); - -/* - * "memset" on IO memory space. - */ -void __memset_io(volatile void __iomem *dst, int c, size_t count) -{ - u64 qc = (u8)c; - - qc |= qc << 8; - qc |= qc << 16; - qc |= qc << 32; - - while (count && !IS_ALIGNED((unsigned long)dst, 8)) { - __raw_writeb(c, dst); - dst++; - count--; - } - - while (count >= 8) { - __raw_writeq(qc, dst); - dst += 8; - count -= 8; - } - - while (count) { - __raw_writeb(c, dst); - dst++; - count--; - } -} -EXPORT_SYMBOL(__memset_io); diff --git a/arch/arm64/kernel/jump_label.c b/arch/arm64/kernel/jump_label.c index f63ea915d6ad25..b345425193d288 100644 --- a/arch/arm64/kernel/jump_label.c +++ b/arch/arm64/kernel/jump_label.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include bool arch_jump_label_transform_queue(struct jump_entry *entry, enum jump_label_type type) diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c index 4e1f983df3d1c2..f3c4d3a8a20f93 100644 --- a/arch/arm64/kernel/kgdb.c +++ b/arch/arm64/kernel/kgdb.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index 36b25af5632430..06bb680bfe975c 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -462,14 +462,20 @@ int module_finalize(const Elf_Ehdr *hdr, struct module *me) { const Elf_Shdr *s; + int ret; + s = find_section(hdr, sechdrs, ".altinstructions"); if (s) apply_alternatives_module((void *)s->sh_addr, s->sh_size); if (scs_is_dynamic()) { s = find_section(hdr, sechdrs, ".init.eh_frame"); - if (s) - __pi_scs_patch((void *)s->sh_addr, s->sh_size); + if (s) { + ret = __pi_scs_patch((void *)s->sh_addr, s->sh_size); + if (ret) + pr_err("module %s: error occurred during dynamic SCS patching (%d)\n", + me->name, ret); + } } return module_init_ftrace_plt(hdr, sechdrs, me); diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c index 6174671be7c18d..2fbfd27ff5f293 100644 --- a/arch/arm64/kernel/mte.c +++ b/arch/arm64/kernel/mte.c @@ -38,7 +38,24 @@ EXPORT_SYMBOL_GPL(mte_async_or_asymm_mode); void mte_sync_tags(pte_t pte, unsigned int nr_pages) { struct page *page = pte_page(pte); - unsigned int i; + struct folio *folio = page_folio(page); + unsigned long i; + + if (folio_test_hugetlb(folio)) { + unsigned long nr = folio_nr_pages(folio); + + /* Hugetlb MTE flags are set for head page only */ + if (folio_try_hugetlb_mte_tagging(folio)) { + for (i = 0; i < nr; i++, page++) + mte_clear_page_tags(page_address(page)); + folio_set_hugetlb_mte_tagged(folio); + } + + /* ensure the tags are visible before the PTE is set */ + smp_wmb(); + + return; + } /* if PG_mte_tagged is set, tags have already been initialised */ for (i = 0; i < nr_pages; i++, page++) { @@ -410,6 +427,7 @@ static int __access_remote_tags(struct mm_struct *mm, unsigned long addr, void *maddr; struct page *page = get_user_page_vma_remote(mm, addr, gup_flags, &vma); + struct folio *folio; if (IS_ERR(page)) { err = PTR_ERR(page); @@ -428,7 +446,12 @@ static int __access_remote_tags(struct mm_struct *mm, unsigned long addr, put_page(page); break; } - WARN_ON_ONCE(!page_mte_tagged(page)); + + folio = page_folio(page); + if (folio_test_hugetlb(folio)) + WARN_ON_ONCE(!folio_test_hugetlb_mte_tagged(folio)); + else + WARN_ON_ONCE(!page_mte_tagged(page)); /* limit access to the end of the page */ offset = offset_in_page(addr); diff --git a/arch/arm64/kernel/patching.c b/arch/arm64/kernel/patching.c index 945df74005c701..1041bc67a3eee0 100644 --- a/arch/arm64/kernel/patching.c +++ b/arch/arm64/kernel/patching.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include static DEFINE_RAW_SPINLOCK(patch_lock); @@ -30,20 +30,17 @@ static bool is_image_text(unsigned long addr) static void __kprobes *patch_map(void *addr, int fixmap) { - unsigned long uintaddr = (uintptr_t) addr; - bool image = is_image_text(uintaddr); - struct page *page; + phys_addr_t phys; - if (image) - page = phys_to_page(__pa_symbol(addr)); - else if (IS_ENABLED(CONFIG_EXECMEM)) - page = vmalloc_to_page(addr); - else - return addr; + if (is_image_text((unsigned long)addr)) { + phys = __pa_symbol(addr); + } else { + struct page *page = vmalloc_to_page(addr); + BUG_ON(!page); + phys = page_to_phys(page) + offset_in_page(addr); + } - BUG_ON(!page); - return (void *)set_fixmap_offset(fixmap, page_to_phys(page) + - (uintaddr & ~PAGE_MASK)); + return (void *)set_fixmap_offset(fixmap, phys); } static void __kprobes patch_unmap(int fixmap) diff --git a/arch/arm64/kernel/perf_callchain.c b/arch/arm64/kernel/perf_callchain.c index e8ed5673f48174..9b7f26b128b518 100644 --- a/arch/arm64/kernel/perf_callchain.c +++ b/arch/arm64/kernel/perf_callchain.c @@ -38,31 +38,3 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, arch_stack_walk(callchain_trace, entry, current, regs); } - -unsigned long perf_instruction_pointer(struct pt_regs *regs) -{ - if (perf_guest_state()) - return perf_guest_get_ip(); - - return instruction_pointer(regs); -} - -unsigned long perf_misc_flags(struct pt_regs *regs) -{ - unsigned int guest_state = perf_guest_state(); - int misc = 0; - - if (guest_state) { - if (guest_state & PERF_GUEST_USER) - misc |= PERF_RECORD_MISC_GUEST_USER; - else - misc |= PERF_RECORD_MISC_GUEST_KERNEL; - } else { - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - } - - return misc; -} diff --git a/arch/arm64/kernel/pi/idreg-override.c b/arch/arm64/kernel/pi/idreg-override.c index 29d4b6244a6f63..22159251eb3a6a 100644 --- a/arch/arm64/kernel/pi/idreg-override.c +++ b/arch/arm64/kernel/pi/idreg-override.c @@ -38,6 +38,15 @@ struct ftr_set_desc { #define FIELD(n, s, f) { .name = n, .shift = s, .width = 4, .filter = f } +static const struct ftr_set_desc mmfr0 __prel64_initconst = { + .name = "id_aa64mmfr0", + .override = &id_aa64mmfr0_override, + .fields = { + FIELD("ecv", ID_AA64MMFR0_EL1_ECV_SHIFT, NULL), + {} + }, +}; + static bool __init mmfr1_vh_filter(u64 val) { /* @@ -133,6 +142,7 @@ static const struct ftr_set_desc pfr1 __prel64_initconst = { .override = &id_aa64pfr1_override, .fields = { FIELD("bt", ID_AA64PFR1_EL1_BT_SHIFT, NULL ), + FIELD("gcs", ID_AA64PFR1_EL1_GCS_SHIFT, NULL), FIELD("mte", ID_AA64PFR1_EL1_MTE_SHIFT, NULL), FIELD("sme", ID_AA64PFR1_EL1_SME_SHIFT, pfr1_sme_filter), {} @@ -196,6 +206,7 @@ static const struct ftr_set_desc sw_features __prel64_initconst = { static const PREL64(const struct ftr_set_desc, reg) regs[] __prel64_initconst = { + { &mmfr0 }, { &mmfr1 }, { &mmfr2 }, { &pfr0 }, @@ -215,6 +226,7 @@ static const struct { { "arm64.nosve", "id_aa64pfr0.sve=0" }, { "arm64.nosme", "id_aa64pfr1.sme=0" }, { "arm64.nobti", "id_aa64pfr1.bt=0" }, + { "arm64.nogcs", "id_aa64pfr1.gcs=0" }, { "arm64.nopauth", "id_aa64isar1.gpi=0 id_aa64isar1.gpa=0 " "id_aa64isar1.api=0 id_aa64isar1.apa=0 " diff --git a/arch/arm64/kernel/pi/map_range.c b/arch/arm64/kernel/pi/map_range.c index 5410b2cac59074..2b69e3beeef80a 100644 --- a/arch/arm64/kernel/pi/map_range.c +++ b/arch/arm64/kernel/pi/map_range.c @@ -30,7 +30,7 @@ void __init map_range(u64 *pte, u64 start, u64 end, u64 pa, pgprot_t prot, int level, pte_t *tbl, bool may_use_cont, u64 va_offset) { u64 cmask = (level == 3) ? CONT_PTE_SIZE - 1 : U64_MAX; - u64 protval = pgprot_val(prot) & ~PTE_TYPE_MASK; + pteval_t protval = pgprot_val(prot) & ~PTE_TYPE_MASK; int lshift = (3 - level) * (PAGE_SHIFT - 3); u64 lmask = (PAGE_SIZE << lshift) - 1; diff --git a/arch/arm64/kernel/pi/patch-scs.c b/arch/arm64/kernel/pi/patch-scs.c index 49d8b40e61bc05..55d0cd64ef71e6 100644 --- a/arch/arm64/kernel/pi/patch-scs.c +++ b/arch/arm64/kernel/pi/patch-scs.c @@ -50,6 +50,10 @@ bool dynamic_scs_is_enabled; #define DW_CFA_GNU_negative_offset_extended 0x2f #define DW_CFA_hi_user 0x3f +#define DW_EH_PE_sdata4 0x0b +#define DW_EH_PE_sdata8 0x0c +#define DW_EH_PE_pcrel 0x10 + enum { PACIASP = 0xd503233f, AUTIASP = 0xd50323bf, @@ -120,7 +124,12 @@ struct eh_frame { union { struct { // CIE u8 version; - u8 augmentation_string[]; + u8 augmentation_string[3]; + u8 code_alignment_factor; + u8 data_alignment_factor; + u8 return_address_register; + u8 augmentation_data_size; + u8 fde_pointer_format; }; struct { // FDE @@ -128,29 +137,38 @@ struct eh_frame { s32 range; u8 opcodes[]; }; + + struct { // FDE + s64 initial_loc64; + s64 range64; + u8 opcodes64[]; + }; }; }; static int scs_handle_fde_frame(const struct eh_frame *frame, - bool fde_has_augmentation_data, int code_alignment_factor, + bool use_sdata8, bool dry_run) { int size = frame->size - offsetof(struct eh_frame, opcodes) + 4; u64 loc = (u64)offset_to_ptr(&frame->initial_loc); const u8 *opcode = frame->opcodes; + int l; - if (fde_has_augmentation_data) { - int l; + if (use_sdata8) { + loc = (u64)&frame->initial_loc64 + frame->initial_loc64; + opcode = frame->opcodes64; + size -= 8; + } - // assume single byte uleb128_t - if (WARN_ON(*opcode & BIT(7))) - return -ENOEXEC; + // assume single byte uleb128_t for augmentation data size + if (*opcode & BIT(7)) + return EDYNSCS_INVALID_FDE_AUGM_DATA_SIZE; - l = *opcode++; - opcode += l; - size -= l + 1; - } + l = *opcode++; + opcode += l; + size -= l + 1; /* * Starting from 'loc', apply the CFA opcodes that advance the location @@ -201,7 +219,7 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, break; default: - return -ENOEXEC; + return EDYNSCS_INVALID_CFA_OPCODE; } } return 0; @@ -209,12 +227,12 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, int scs_patch(const u8 eh_frame[], int size) { + int code_alignment_factor = 1; + bool fde_use_sdata8 = false; const u8 *p = eh_frame; while (size > 4) { const struct eh_frame *frame = (const void *)p; - bool fde_has_augmentation_data = true; - int code_alignment_factor = 1; int ret; if (frame->size == 0 || @@ -223,28 +241,47 @@ int scs_patch(const u8 eh_frame[], int size) break; if (frame->cie_id_or_pointer == 0) { - const u8 *p = frame->augmentation_string; - - /* a 'z' in the augmentation string must come first */ - fde_has_augmentation_data = *p == 'z'; + /* + * Require presence of augmentation data (z) with a + * specifier for the size of the FDE initial_loc and + * range fields (R), and nothing else. + */ + if (strcmp(frame->augmentation_string, "zR")) + return EDYNSCS_INVALID_CIE_HEADER; /* * The code alignment factor is a uleb128 encoded field * but given that the only sensible values are 1 or 4, - * there is no point in decoding the whole thing. + * there is no point in decoding the whole thing. Also + * sanity check the size of the data alignment factor + * field, and the values of the return address register + * and augmentation data size fields. */ - p += strlen(p) + 1; - if (!WARN_ON(*p & BIT(7))) - code_alignment_factor = *p; + if ((frame->code_alignment_factor & BIT(7)) || + (frame->data_alignment_factor & BIT(7)) || + frame->return_address_register != 30 || + frame->augmentation_data_size != 1) + return EDYNSCS_INVALID_CIE_HEADER; + + code_alignment_factor = frame->code_alignment_factor; + + switch (frame->fde_pointer_format) { + case DW_EH_PE_pcrel | DW_EH_PE_sdata4: + fde_use_sdata8 = false; + break; + case DW_EH_PE_pcrel | DW_EH_PE_sdata8: + fde_use_sdata8 = true; + break; + default: + return EDYNSCS_INVALID_CIE_SDATA_SIZE; + } } else { - ret = scs_handle_fde_frame(frame, - fde_has_augmentation_data, - code_alignment_factor, - true); + ret = scs_handle_fde_frame(frame, code_alignment_factor, + fde_use_sdata8, true); if (ret) return ret; - scs_handle_fde_frame(frame, fde_has_augmentation_data, - code_alignment_factor, false); + scs_handle_fde_frame(frame, code_alignment_factor, + fde_use_sdata8, false); } p += sizeof(frame->size) + frame->size; diff --git a/arch/arm64/kernel/probes/decode-insn.c b/arch/arm64/kernel/probes/decode-insn.c index 3496d6169e59b2..6438bf62e753f3 100644 --- a/arch/arm64/kernel/probes/decode-insn.c +++ b/arch/arm64/kernel/probes/decode-insn.c @@ -58,10 +58,13 @@ static bool __kprobes aarch64_insn_is_steppable(u32 insn) * Instructions which load PC relative literals are not going to work * when executed from an XOL slot. Instructions doing an exclusive * load/store are not going to complete successfully when single-step - * exception handling happens in the middle of the sequence. + * exception handling happens in the middle of the sequence. Memory + * copy/set instructions require that all three instructions be placed + * consecutively in memory. */ if (aarch64_insn_uses_literal(insn) || - aarch64_insn_is_exclusive(insn)) + aarch64_insn_is_exclusive(insn) || + aarch64_insn_is_mops(insn)) return false; return true; @@ -73,8 +76,17 @@ static bool __kprobes aarch64_insn_is_steppable(u32 insn) * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. */ enum probe_insn __kprobes -arm_probe_decode_insn(probe_opcode_t insn, struct arch_probe_insn *api) +arm_probe_decode_insn(u32 insn, struct arch_probe_insn *api) { + /* + * While 'nop' instruction can execute in the out-of-line slot, + * simulating them in breakpoint handling offers better performance. + */ + if (aarch64_insn_is_nop(insn)) { + api->handler = simulate_nop; + return INSN_GOOD_NO_SLOT; + } + /* * Instructions reading or modifying the PC won't work from the XOL * slot. @@ -133,8 +145,8 @@ enum probe_insn __kprobes arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi) { enum probe_insn decoded; - probe_opcode_t insn = le32_to_cpu(*addr); - probe_opcode_t *scan_end = NULL; + u32 insn = le32_to_cpu(*addr); + kprobe_opcode_t *scan_end = NULL; unsigned long size = 0, offset = 0; struct arch_probe_insn *api = &asi->api; diff --git a/arch/arm64/kernel/probes/decode-insn.h b/arch/arm64/kernel/probes/decode-insn.h index 8b758c5a206222..0e4195de820619 100644 --- a/arch/arm64/kernel/probes/decode-insn.h +++ b/arch/arm64/kernel/probes/decode-insn.h @@ -28,6 +28,6 @@ enum probe_insn __kprobes arm_kprobe_decode_insn(kprobe_opcode_t *addr, struct arch_specific_insn *asi); #endif enum probe_insn __kprobes -arm_probe_decode_insn(probe_opcode_t insn, struct arch_probe_insn *asi); +arm_probe_decode_insn(u32 insn, struct arch_probe_insn *asi); #endif /* _ARM_KERNEL_KPROBES_ARM64_H */ diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c index 4268678d0e86cc..d9e462eafb95e6 100644 --- a/arch/arm64/kernel/probes/kprobes.c +++ b/arch/arm64/kernel/probes/kprobes.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -43,7 +43,7 @@ post_kprobe_handler(struct kprobe *, struct kprobe_ctlblk *, struct pt_regs *); static void __kprobes arch_prepare_ss_slot(struct kprobe *p) { - kprobe_opcode_t *addr = p->ainsn.api.insn; + kprobe_opcode_t *addr = p->ainsn.xol_insn; /* * Prepare insn slot, Mark Rutland points out it depends on a coupe of @@ -64,20 +64,20 @@ static void __kprobes arch_prepare_ss_slot(struct kprobe *p) * the BRK exception handler, so it is unnecessary to generate * Contex-Synchronization-Event via ISB again. */ - aarch64_insn_patch_text_nosync(addr, p->opcode); + aarch64_insn_patch_text_nosync(addr, le32_to_cpu(p->opcode)); aarch64_insn_patch_text_nosync(addr + 1, BRK64_OPCODE_KPROBES_SS); /* * Needs restoring of return address after stepping xol. */ - p->ainsn.api.restore = (unsigned long) p->addr + + p->ainsn.xol_restore = (unsigned long) p->addr + sizeof(kprobe_opcode_t); } static void __kprobes arch_prepare_simulate(struct kprobe *p) { /* This instructions is not executed xol. No need to adjust the PC */ - p->ainsn.api.restore = 0; + p->ainsn.xol_restore = 0; } static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs) @@ -85,7 +85,7 @@ static void __kprobes arch_simulate_insn(struct kprobe *p, struct pt_regs *regs) struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); if (p->ainsn.api.handler) - p->ainsn.api.handler((u32)p->opcode, (long)p->addr, regs); + p->ainsn.api.handler(le32_to_cpu(p->opcode), (long)p->addr, regs); /* single step simulated, now go for post processing */ post_kprobe_handler(p, kcb, regs); @@ -99,7 +99,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) return -EINVAL; /* copy instruction */ - p->opcode = le32_to_cpu(*p->addr); + p->opcode = *p->addr; if (search_exception_tables(probe_addr)) return -EINVAL; @@ -110,18 +110,18 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) return -EINVAL; case INSN_GOOD_NO_SLOT: /* insn need simulation */ - p->ainsn.api.insn = NULL; + p->ainsn.xol_insn = NULL; break; case INSN_GOOD: /* instruction uses slot */ - p->ainsn.api.insn = get_insn_slot(); - if (!p->ainsn.api.insn) + p->ainsn.xol_insn = get_insn_slot(); + if (!p->ainsn.xol_insn) return -ENOMEM; break; } /* prepare the instruction */ - if (p->ainsn.api.insn) + if (p->ainsn.xol_insn) arch_prepare_ss_slot(p); else arch_prepare_simulate(p); @@ -142,15 +142,16 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) void __kprobes arch_disarm_kprobe(struct kprobe *p) { void *addr = p->addr; + u32 insn = le32_to_cpu(p->opcode); - aarch64_insn_patch_text(&addr, &p->opcode, 1); + aarch64_insn_patch_text(&addr, &insn, 1); } void __kprobes arch_remove_kprobe(struct kprobe *p) { - if (p->ainsn.api.insn) { - free_insn_slot(p->ainsn.api.insn, 0); - p->ainsn.api.insn = NULL; + if (p->ainsn.xol_insn) { + free_insn_slot(p->ainsn.xol_insn, 0); + p->ainsn.xol_insn = NULL; } } @@ -205,9 +206,9 @@ static void __kprobes setup_singlestep(struct kprobe *p, } - if (p->ainsn.api.insn) { + if (p->ainsn.xol_insn) { /* prepare for single stepping */ - slot = (unsigned long)p->ainsn.api.insn; + slot = (unsigned long)p->ainsn.xol_insn; kprobes_save_local_irqflag(kcb, regs); instruction_pointer_set(regs, slot); @@ -245,8 +246,8 @@ static void __kprobes post_kprobe_handler(struct kprobe *cur, struct kprobe_ctlblk *kcb, struct pt_regs *regs) { /* return addr restore if non-branching insn */ - if (cur->ainsn.api.restore != 0) - instruction_pointer_set(regs, cur->ainsn.api.restore); + if (cur->ainsn.xol_restore != 0) + instruction_pointer_set(regs, cur->ainsn.xol_restore); /* restore back original saved kprobe variables and continue */ if (kcb->kprobe_status == KPROBE_REENTER) { @@ -348,7 +349,7 @@ kprobe_breakpoint_ss_handler(struct pt_regs *regs, unsigned long esr) struct kprobe *cur = kprobe_running(); if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS | KPROBE_REENTER)) && - ((unsigned long)&cur->ainsn.api.insn[1] == addr)) { + ((unsigned long)&cur->ainsn.xol_insn[1] == addr)) { kprobes_restore_local_irqflag(kcb, regs); post_kprobe_handler(cur, kcb, regs); diff --git a/arch/arm64/kernel/probes/simulate-insn.c b/arch/arm64/kernel/probes/simulate-insn.c index b65334ab79d2b0..4c6d2d712fbd3c 100644 --- a/arch/arm64/kernel/probes/simulate-insn.c +++ b/arch/arm64/kernel/probes/simulate-insn.c @@ -196,3 +196,9 @@ simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs) instruction_pointer_set(regs, instruction_pointer(regs) + 4); } + +void __kprobes +simulate_nop(u32 opcode, long addr, struct pt_regs *regs) +{ + arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE); +} diff --git a/arch/arm64/kernel/probes/simulate-insn.h b/arch/arm64/kernel/probes/simulate-insn.h index e065dc92218e83..efb2803ec943d6 100644 --- a/arch/arm64/kernel/probes/simulate-insn.h +++ b/arch/arm64/kernel/probes/simulate-insn.h @@ -16,5 +16,6 @@ void simulate_cbz_cbnz(u32 opcode, long addr, struct pt_regs *regs); void simulate_tbz_tbnz(u32 opcode, long addr, struct pt_regs *regs); void simulate_ldr_literal(u32 opcode, long addr, struct pt_regs *regs); void simulate_ldrsw_literal(u32 opcode, long addr, struct pt_regs *regs); +void simulate_nop(u32 opcode, long addr, struct pt_regs *regs); #endif /* _ARM_KERNEL_KPROBES_SIMULATE_INSN_H */ diff --git a/arch/arm64/kernel/probes/uprobes.c b/arch/arm64/kernel/probes/uprobes.c index a2f137a595fc1c..cb3d05af36e3d0 100644 --- a/arch/arm64/kernel/probes/uprobes.c +++ b/arch/arm64/kernel/probes/uprobes.c @@ -17,12 +17,20 @@ void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, void *xol_page_kaddr = kmap_atomic(page); void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK); + /* + * Initial cache maintenance of the xol page done via set_pte_at(). + * Subsequent CMOs only needed if the xol slot changes. + */ + if (!memcmp(dst, src, len)) + goto done; + /* Initialize the slot */ memcpy(dst, src, len); /* flush caches (dcache/icache) */ sync_icache_aliases((unsigned long)dst, (unsigned long)dst + len); +done: kunmap_atomic(xol_page_kaddr); } @@ -34,7 +42,7 @@ unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) { - probe_opcode_t insn; + u32 insn; /* TODO: Currently we do not support AARCH32 instruction probing */ if (mm->context.flags & MMCF_AARCH32) @@ -102,7 +110,7 @@ bool arch_uprobe_xol_was_trapped(struct task_struct *t) bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) { - probe_opcode_t insn; + u32 insn; unsigned long addr; if (!auprobe->simulate) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 3e7c8c8195c3c9..2968a33bb3bc16 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -227,7 +228,7 @@ void __show_regs(struct pt_regs *regs) printk("sp : %016llx\n", sp); if (system_uses_irq_prio_masking()) - printk("pmr_save: %08llx\n", regs->pmr_save); + printk("pmr: %08x\n", regs->pmr); i = top_reg; @@ -280,6 +281,51 @@ static void flush_poe(void) write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0); } +#ifdef CONFIG_ARM64_GCS + +static void flush_gcs(void) +{ + if (!system_supports_gcs()) + return; + + gcs_free(current); + current->thread.gcs_el0_mode = 0; + write_sysreg_s(GCSCRE0_EL1_nTR, SYS_GCSCRE0_EL1); + write_sysreg_s(0, SYS_GCSPR_EL0); +} + +static int copy_thread_gcs(struct task_struct *p, + const struct kernel_clone_args *args) +{ + unsigned long gcs; + + if (!system_supports_gcs()) + return 0; + + p->thread.gcs_base = 0; + p->thread.gcs_size = 0; + + gcs = gcs_alloc_thread_stack(p, args); + if (IS_ERR_VALUE(gcs)) + return PTR_ERR((void *)gcs); + + p->thread.gcs_el0_mode = current->thread.gcs_el0_mode; + p->thread.gcs_el0_locked = current->thread.gcs_el0_locked; + + return 0; +} + +#else + +static void flush_gcs(void) { } +static int copy_thread_gcs(struct task_struct *p, + const struct kernel_clone_args *args) +{ + return 0; +} + +#endif + void flush_thread(void) { fpsimd_flush_thread(); @@ -287,11 +333,13 @@ void flush_thread(void) flush_ptrace_hw_breakpoint(current); flush_tagged_addr_state(); flush_poe(); + flush_gcs(); } void arch_release_task_struct(struct task_struct *tsk) { fpsimd_release_task(tsk); + gcs_free(tsk); } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) @@ -355,6 +403,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) unsigned long stack_start = args->stack; unsigned long tls = args->tls; struct pt_regs *childregs = task_pt_regs(p); + int ret; memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); @@ -399,6 +448,10 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) p->thread.uw.tp_value = tls; p->thread.tpidr2_el0 = 0; } + + ret = copy_thread_gcs(p, args); + if (ret != 0) + return ret; } else { /* * A kthread has no context to ERET to, so ensure any buggy @@ -409,6 +462,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) */ memset(childregs, 0, sizeof(struct pt_regs)); childregs->pstate = PSR_MODE_EL1h | PSR_IL_BIT; + childregs->stackframe.type = FRAME_META_TYPE_FINAL; p->thread.cpu_context.x19 = (unsigned long)args->fn; p->thread.cpu_context.x20 = (unsigned long)args->fn_arg; @@ -422,7 +476,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) * For the benefit of the unwinder, set up childregs->stackframe * as the final frame for the new task. */ - p->thread.cpu_context.fp = (unsigned long)childregs->stackframe; + p->thread.cpu_context.fp = (unsigned long)&childregs->stackframe; ptrace_hw_copy_thread(p); @@ -442,7 +496,7 @@ static void tls_thread_switch(struct task_struct *next) if (is_compat_thread(task_thread_info(next))) write_sysreg(next->thread.uw.tp_value, tpidrro_el0); - else if (!arm64_kernel_unmapped_at_el0()) + else write_sysreg(0, tpidrro_el0); write_sysreg(*task_user_tls(next), tpidr_el0); @@ -487,6 +541,46 @@ static void entry_task_switch(struct task_struct *next) __this_cpu_write(__entry_task, next); } +#ifdef CONFIG_ARM64_GCS + +void gcs_preserve_current_state(void) +{ + current->thread.gcspr_el0 = read_sysreg_s(SYS_GCSPR_EL0); +} + +static void gcs_thread_switch(struct task_struct *next) +{ + if (!system_supports_gcs()) + return; + + /* GCSPR_EL0 is always readable */ + gcs_preserve_current_state(); + write_sysreg_s(next->thread.gcspr_el0, SYS_GCSPR_EL0); + + if (current->thread.gcs_el0_mode != next->thread.gcs_el0_mode) + gcs_set_el0_mode(next); + + /* + * Ensure that GCS memory effects of the 'prev' thread are + * ordered before other memory accesses with release semantics + * (or preceded by a DMB) on the current PE. In addition, any + * memory accesses with acquire semantics (or succeeded by a + * DMB) are ordered before GCS memory effects of the 'next' + * thread. This will ensure that the GCS memory effects are + * visible to other PEs in case of migration. + */ + if (task_gcs_el0_enabled(current) || task_gcs_el0_enabled(next)) + gcsb_dsync(); +} + +#else + +static void gcs_thread_switch(struct task_struct *next) +{ +} + +#endif + /* * Handle sysreg updates for ARM erratum 1418040 which affects the 32bit view of * CNTVCT, various other errata which require trapping all CNTVCT{,_EL0} @@ -583,6 +677,7 @@ struct task_struct *__switch_to(struct task_struct *prev, cntkctl_thread_switch(prev, next); ptrauth_thread_switch_user(next); permission_overlay_switch(next); + gcs_thread_switch(next); /* * Complete any pending TLB or cache maintenance on this CPU in case diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index b756578aeaeea1..f79b0d5f71ac94 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -719,6 +720,8 @@ static int fpmr_set(struct task_struct *target, const struct user_regset *regset if (!system_supports_fpmr()) return -EINVAL; + fpmr = target->thread.uw.fpmr; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpmr, 0, count); if (ret) return ret; @@ -898,7 +901,11 @@ static int sve_set_common(struct task_struct *target, if (ret) goto out; - /* Actual VL set may be less than the user asked for: */ + /* + * Actual VL set may be different from what the user asked + * for, or we may have configured the _ONEXEC VL not the + * current VL: + */ vq = sve_vq_from_vl(task_get_vl(target, type)); /* Enter/exit streaming mode */ @@ -1125,7 +1132,11 @@ static int za_set(struct task_struct *target, if (ret) goto out; - /* Actual VL set may be less than the user asked for: */ + /* + * Actual VL set may be different from what the user asked + * for, or we may have configured the _ONEXEC rather than + * current VL: + */ vq = sve_vq_from_vl(task_get_sme_vl(target)); /* Ensure there is some SVE storage for streaming mode */ @@ -1418,7 +1429,7 @@ static int tagged_addr_ctrl_get(struct task_struct *target, { long ctrl = get_tagged_addr_ctrl(target); - if (IS_ERR_VALUE(ctrl)) + if (WARN_ON_ONCE(IS_ERR_VALUE(ctrl))) return ctrl; return membuf_write(&to, &ctrl, sizeof(ctrl)); @@ -1432,6 +1443,10 @@ static int tagged_addr_ctrl_set(struct task_struct *target, const struct int ret; long ctrl; + ctrl = get_tagged_addr_ctrl(target); + if (WARN_ON_ONCE(IS_ERR_VALUE(ctrl))) + return ctrl; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 0, -1); if (ret) return ret; @@ -1463,6 +1478,8 @@ static int poe_set(struct task_struct *target, const struct if (!system_supports_poe()) return -EINVAL; + ctrl = target->thread.por_el0; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 0, -1); if (ret) return ret; @@ -1473,6 +1490,66 @@ static int poe_set(struct task_struct *target, const struct } #endif +#ifdef CONFIG_ARM64_GCS +static void task_gcs_to_user(struct user_gcs *user_gcs, + const struct task_struct *target) +{ + user_gcs->features_enabled = target->thread.gcs_el0_mode; + user_gcs->features_locked = target->thread.gcs_el0_locked; + user_gcs->gcspr_el0 = target->thread.gcspr_el0; +} + +static void task_gcs_from_user(struct task_struct *target, + const struct user_gcs *user_gcs) +{ + target->thread.gcs_el0_mode = user_gcs->features_enabled; + target->thread.gcs_el0_locked = user_gcs->features_locked; + target->thread.gcspr_el0 = user_gcs->gcspr_el0; +} + +static int gcs_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + struct user_gcs user_gcs; + + if (!system_supports_gcs()) + return -EINVAL; + + if (target == current) + gcs_preserve_current_state(); + + task_gcs_to_user(&user_gcs, target); + + return membuf_write(&to, &user_gcs, sizeof(user_gcs)); +} + +static int gcs_set(struct task_struct *target, const struct + user_regset *regset, unsigned int pos, + unsigned int count, const void *kbuf, const + void __user *ubuf) +{ + int ret; + struct user_gcs user_gcs; + + if (!system_supports_gcs()) + return -EINVAL; + + task_gcs_to_user(&user_gcs, target); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_gcs, 0, -1); + if (ret) + return ret; + + if (user_gcs.features_enabled & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK) + return -EINVAL; + + task_gcs_from_user(target, &user_gcs); + + return 0; +} +#endif + enum aarch64_regset { REGSET_GPR, REGSET_FPR, @@ -1503,7 +1580,10 @@ enum aarch64_regset { REGSET_TAGGED_ADDR_CTRL, #endif #ifdef CONFIG_ARM64_POE - REGSET_POE + REGSET_POE, +#endif +#ifdef CONFIG_ARM64_GCS + REGSET_GCS, #endif }; @@ -1674,6 +1754,16 @@ static const struct user_regset aarch64_regsets[] = { .set = poe_set, }, #endif +#ifdef CONFIG_ARM64_GCS + [REGSET_GCS] = { + .core_note_type = NT_ARM_GCS, + .n = sizeof(struct user_gcs) / sizeof(u64), + .size = sizeof(u64), + .align = sizeof(u64), + .regset_get = gcs_get, + .set = gcs_set, + }, +#endif }; static const struct user_regset_view user_aarch64_view = { diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c new file mode 100644 index 00000000000000..3031f25c32ef75 --- /dev/null +++ b/arch/arm64/kernel/rsi.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 ARM Ltd. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct realm_config config; + +unsigned long prot_ns_shared; +EXPORT_SYMBOL(prot_ns_shared); + +DEFINE_STATIC_KEY_FALSE_RO(rsi_present); +EXPORT_SYMBOL(rsi_present); + +bool cc_platform_has(enum cc_attr attr) +{ + switch (attr) { + case CC_ATTR_MEM_ENCRYPT: + return is_realm_world(); + default: + return false; + } +} +EXPORT_SYMBOL_GPL(cc_platform_has); + +static bool rsi_version_matches(void) +{ + unsigned long ver_lower, ver_higher; + unsigned long ret = rsi_request_version(RSI_ABI_VERSION, + &ver_lower, + &ver_higher); + + if (ret == SMCCC_RET_NOT_SUPPORTED) + return false; + + if (ret != RSI_SUCCESS) { + pr_err("RME: RMM doesn't support RSI version %lu.%lu. Supported range: %lu.%lu-%lu.%lu\n", + RSI_ABI_VERSION_MAJOR, RSI_ABI_VERSION_MINOR, + RSI_ABI_VERSION_GET_MAJOR(ver_lower), + RSI_ABI_VERSION_GET_MINOR(ver_lower), + RSI_ABI_VERSION_GET_MAJOR(ver_higher), + RSI_ABI_VERSION_GET_MINOR(ver_higher)); + return false; + } + + pr_info("RME: Using RSI version %lu.%lu\n", + RSI_ABI_VERSION_GET_MAJOR(ver_lower), + RSI_ABI_VERSION_GET_MINOR(ver_lower)); + + return true; +} + +static void __init arm64_rsi_setup_memory(void) +{ + u64 i; + phys_addr_t start, end; + + /* + * Iterate over the available memory ranges and convert the state to + * protected memory. We should take extra care to ensure that we DO NOT + * permit any "DESTROYED" pages to be converted to "RAM". + * + * panic() is used because if the attempt to switch the memory to + * protected has failed here, then future accesses to the memory are + * simply going to be reflected as a SEA (Synchronous External Abort) + * which we can't handle. Bailing out early prevents the guest limping + * on and dying later. + */ + for_each_mem_range(i, &start, &end) { + if (rsi_set_memory_range_protected_safe(start, end)) { + panic("Failed to set memory range to protected: %pa-%pa", + &start, &end); + } + } +} + +bool __arm64_is_protected_mmio(phys_addr_t base, size_t size) +{ + enum ripas ripas; + phys_addr_t end, top; + + /* Overflow ? */ + if (WARN_ON(base + size <= base)) + return false; + + end = ALIGN(base + size, RSI_GRANULE_SIZE); + base = ALIGN_DOWN(base, RSI_GRANULE_SIZE); + + while (base < end) { + if (WARN_ON(rsi_ipa_state_get(base, end, &ripas, &top))) + break; + if (WARN_ON(top <= base)) + break; + if (ripas != RSI_RIPAS_DEV) + break; + base = top; + } + + return base >= end; +} +EXPORT_SYMBOL(__arm64_is_protected_mmio); + +static int realm_ioremap_hook(phys_addr_t phys, size_t size, pgprot_t *prot) +{ + if (__arm64_is_protected_mmio(phys, size)) + *prot = pgprot_encrypted(*prot); + else + *prot = pgprot_decrypted(*prot); + + return 0; +} + +void __init arm64_rsi_init(void) +{ + if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC) + return; + if (!rsi_version_matches()) + return; + if (WARN_ON(rsi_get_realm_config(&config))) + return; + prot_ns_shared = BIT(config.ipa_bits - 1); + + if (arm64_ioremap_prot_hook_register(realm_ioremap_hook)) + return; + + if (realm_register_memory_enc_ops()) + return; + + arm64_rsi_setup_memory(); + + static_branch_enable(&rsi_present); +} + diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index b22d28ec80284b..4f613e8e07452d 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -175,7 +176,11 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) if (dt_virt) memblock_reserve(dt_phys, size); - if (!dt_virt || !early_init_dt_scan(dt_virt)) { + /* + * dt_virt is a fixmap address, hence __pa(dt_virt) can't be used. + * Pass dt_phys directly. + */ + if (!early_init_dt_scan(dt_virt, dt_phys)) { pr_crit("\n" "Error: invalid device tree blob at physical address %pa (virtual address 0x%px)\n" "The dtb must be 8-byte aligned and must not exceed 2 MB in size\n" @@ -351,6 +356,8 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p) else psci_acpi_init(); + arm64_rsi_init(); + init_bootcpu_ops(); smp_init_cpus(); smp_build_mpidr_hash(); diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index c7d311d8b92a2e..99ea26d400ffeb 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include #include +#define GCS_SIGNAL_CAP(addr) (((unsigned long)addr) & GCS_CAP_ADDR_MASK) + /* * Do a signal return; undo the signal stack. These are aligned to 128-bit. */ @@ -43,11 +46,6 @@ struct rt_sigframe { struct ucontext uc; }; -struct frame_record { - u64 fp; - u64 lr; -}; - struct rt_sigframe_user_layout { struct rt_sigframe __user *sigframe; struct frame_record __user *next_frame; @@ -57,6 +55,7 @@ struct rt_sigframe_user_layout { unsigned long fpsimd_offset; unsigned long esr_offset; + unsigned long gcs_offset; unsigned long sve_offset; unsigned long tpidr2_offset; unsigned long za_offset; @@ -79,7 +78,6 @@ struct user_access_state { u64 por_el0; }; -#define BASE_SIGFRAME_SIZE round_up(sizeof(struct rt_sigframe), 16) #define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16) #define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16) @@ -242,6 +240,8 @@ struct user_ctxs { u32 fpmr_size; struct poe_context __user *poe; u32 poe_size; + struct gcs_context __user *gcs; + u32 gcs_size; }; static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) @@ -689,6 +689,82 @@ extern int restore_zt_context(struct user_ctxs *user); #endif /* ! CONFIG_ARM64_SME */ +#ifdef CONFIG_ARM64_GCS + +static int preserve_gcs_context(struct gcs_context __user *ctx) +{ + int err = 0; + u64 gcspr = read_sysreg_s(SYS_GCSPR_EL0); + + /* + * If GCS is enabled we will add a cap token to the frame, + * include it in the GCSPR_EL0 we report to support stack + * switching via sigreturn if GCS is enabled. We do not allow + * enabling via sigreturn so the token is only relevant for + * threads with GCS enabled. + */ + if (task_gcs_el0_enabled(current)) + gcspr -= 8; + + __put_user_error(GCS_MAGIC, &ctx->head.magic, err); + __put_user_error(sizeof(*ctx), &ctx->head.size, err); + __put_user_error(gcspr, &ctx->gcspr, err); + __put_user_error(0, &ctx->reserved, err); + __put_user_error(current->thread.gcs_el0_mode, + &ctx->features_enabled, err); + + return err; +} + +static int restore_gcs_context(struct user_ctxs *user) +{ + u64 gcspr, enabled; + int err = 0; + + if (user->gcs_size != sizeof(*user->gcs)) + return -EINVAL; + + __get_user_error(gcspr, &user->gcs->gcspr, err); + __get_user_error(enabled, &user->gcs->features_enabled, err); + if (err) + return err; + + /* Don't allow unknown modes */ + if (enabled & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK) + return -EINVAL; + + err = gcs_check_locked(current, enabled); + if (err != 0) + return err; + + /* Don't allow enabling */ + if (!task_gcs_el0_enabled(current) && + (enabled & PR_SHADOW_STACK_ENABLE)) + return -EINVAL; + + /* If we are disabling disable everything */ + if (!(enabled & PR_SHADOW_STACK_ENABLE)) + enabled = 0; + + current->thread.gcs_el0_mode = enabled; + + /* + * We let userspace set GCSPR_EL0 to anything here, we will + * validate later in gcs_restore_signal(). + */ + write_sysreg_s(gcspr, SYS_GCSPR_EL0); + + return 0; +} + +#else /* ! CONFIG_ARM64_GCS */ + +/* Turn any non-optimised out attempts to use these into a link error: */ +extern int preserve_gcs_context(void __user *ctx); +extern int restore_gcs_context(struct user_ctxs *user); + +#endif /* ! CONFIG_ARM64_GCS */ + static int parse_user_sigframe(struct user_ctxs *user, struct rt_sigframe __user *sf) { @@ -707,6 +783,7 @@ static int parse_user_sigframe(struct user_ctxs *user, user->zt = NULL; user->fpmr = NULL; user->poe = NULL; + user->gcs = NULL; if (!IS_ALIGNED((unsigned long)base, 16)) goto invalid; @@ -823,6 +900,17 @@ static int parse_user_sigframe(struct user_ctxs *user, user->fpmr_size = size; break; + case GCS_MAGIC: + if (!system_supports_gcs()) + goto invalid; + + if (user->gcs) + goto invalid; + + user->gcs = (struct gcs_context __user *)head; + user->gcs_size = size; + break; + case EXTRA_MAGIC: if (have_extra_context) goto invalid; @@ -943,6 +1031,9 @@ static int restore_sigframe(struct pt_regs *regs, err = restore_fpsimd_context(&user); } + if (err == 0 && system_supports_gcs() && user.gcs) + err = restore_gcs_context(&user); + if (err == 0 && system_supports_tpidr2() && user.tpidr2) err = restore_tpidr2_context(&user); @@ -961,6 +1052,58 @@ static int restore_sigframe(struct pt_regs *regs, return err; } +#ifdef CONFIG_ARM64_GCS +static int gcs_restore_signal(void) +{ + u64 gcspr_el0, cap; + int ret; + + if (!system_supports_gcs()) + return 0; + + if (!(current->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE)) + return 0; + + gcspr_el0 = read_sysreg_s(SYS_GCSPR_EL0); + + /* + * Ensure that any changes to the GCS done via GCS operations + * are visible to the normal reads we do to validate the + * token. + */ + gcsb_dsync(); + + /* + * GCSPR_EL0 should be pointing at a capped GCS, read the cap. + * We don't enforce that this is in a GCS page, if it is not + * then faults will be generated on GCS operations - the main + * concern is to protect GCS pages. + */ + ret = copy_from_user(&cap, (unsigned long __user *)gcspr_el0, + sizeof(cap)); + if (ret) + return -EFAULT; + + /* + * Check that the cap is the actual GCS before replacing it. + */ + if (cap != GCS_SIGNAL_CAP(gcspr_el0)) + return -EINVAL; + + /* Invalidate the token to prevent reuse */ + put_user_gcs(0, (unsigned long __user *)gcspr_el0, &ret); + if (ret != 0) + return -EFAULT; + + write_sysreg_s(gcspr_el0 + 8, SYS_GCSPR_EL0); + + return 0; +} + +#else +static int gcs_restore_signal(void) { return 0; } +#endif + SYSCALL_DEFINE0(rt_sigreturn) { struct pt_regs *regs = current_pt_regs(); @@ -985,6 +1128,9 @@ SYSCALL_DEFINE0(rt_sigreturn) if (restore_sigframe(regs, frame, &ua_state)) goto badframe; + if (gcs_restore_signal()) + goto badframe; + if (restore_altstack(&frame->uc.uc_stack)) goto badframe; @@ -1024,6 +1170,15 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user, return err; } +#ifdef CONFIG_ARM64_GCS + if (system_supports_gcs() && (add_all || current->thread.gcspr_el0)) { + err = sigframe_alloc(user, &user->gcs_offset, + sizeof(struct gcs_context)); + if (err) + return err; + } +#endif + if (system_supports_sve() || system_supports_sme()) { unsigned int vq = 0; @@ -1132,6 +1287,12 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user, __put_user_error(current->thread.fault_code, &esr_ctx->esr, err); } + if (system_supports_gcs() && err == 0 && user->gcs_offset) { + struct gcs_context __user *gcs_ctx = + apply_user_offset(user, user->gcs_offset); + err |= preserve_gcs_context(gcs_ctx); + } + /* Scalable Vector Extension state (including streaming), if present */ if ((system_supports_sve() || system_supports_sme()) && err == 0 && user->sve_offset) { @@ -1154,7 +1315,7 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user, err |= preserve_fpmr_context(fpmr_ctx); } - if (system_supports_poe() && err == 0 && user->poe_offset) { + if (system_supports_poe() && err == 0) { struct poe_context __user *poe_ctx = apply_user_offset(user, user->poe_offset); @@ -1249,15 +1410,81 @@ static int get_sigframe(struct rt_sigframe_user_layout *user, return 0; } -static void setup_return(struct pt_regs *regs, struct k_sigaction *ka, +#ifdef CONFIG_ARM64_GCS + +static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig) +{ + u64 gcspr_el0; + int ret = 0; + + if (!system_supports_gcs()) + return 0; + + if (!task_gcs_el0_enabled(current)) + return 0; + + /* + * We are entering a signal handler, current register state is + * active. + */ + gcspr_el0 = read_sysreg_s(SYS_GCSPR_EL0); + + /* + * Push a cap and the GCS entry for the trampoline onto the GCS. + */ + put_user_gcs((unsigned long)sigtramp, + (unsigned long __user *)(gcspr_el0 - 16), &ret); + put_user_gcs(GCS_SIGNAL_CAP(gcspr_el0 - 8), + (unsigned long __user *)(gcspr_el0 - 8), &ret); + if (ret != 0) + return ret; + + gcspr_el0 -= 16; + write_sysreg_s(gcspr_el0, SYS_GCSPR_EL0); + + return 0; +} +#else + +static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig) +{ + return 0; +} + +#endif + +static int setup_return(struct pt_regs *regs, struct ksignal *ksig, struct rt_sigframe_user_layout *user, int usig) { __sigrestore_t sigtramp; + int err; + + if (ksig->ka.sa.sa_flags & SA_RESTORER) + sigtramp = ksig->ka.sa.sa_restorer; + else + sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp); + + err = gcs_signal_entry(sigtramp, ksig); + if (err) + return err; + + /* + * We must not fail from this point onwards. We are going to update + * registers, including SP, in order to invoke the signal handler. If + * we failed and attempted to deliver a nested SIGSEGV to a handler + * after that point, the subsequent sigreturn would end up restoring + * the (partial) state for the original signal handler. + */ regs->regs[0] = usig; + if (ksig->ka.sa.sa_flags & SA_SIGINFO) { + regs->regs[1] = (unsigned long)&user->sigframe->info; + regs->regs[2] = (unsigned long)&user->sigframe->uc; + } regs->sp = (unsigned long)user->sigframe; regs->regs[29] = (unsigned long)&user->next_frame->fp; - regs->pc = (unsigned long)ka->sa.sa_handler; + regs->regs[30] = (unsigned long)sigtramp; + regs->pc = (unsigned long)ksig->ka.sa.sa_handler; /* * Signal delivery is a (wacky) indirect function call in @@ -1297,12 +1524,7 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka, sme_smstop(); } - if (ka->sa.sa_flags & SA_RESTORER) - sigtramp = ka->sa.sa_restorer; - else - sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp); - - regs->regs[30] = (unsigned long)sigtramp; + return 0; } static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, @@ -1326,14 +1548,16 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, err |= __save_altstack(&frame->uc.uc_stack, regs->sp); err |= setup_sigframe(&user, regs, set, &ua_state); - if (err == 0) { - setup_return(regs, &ksig->ka, &user, usig); - if (ksig->ka.sa.sa_flags & SA_SIGINFO) { - err |= copy_siginfo_to_user(&frame->info, &ksig->info); - regs->regs[1] = (unsigned long)&frame->info; - regs->regs[2] = (unsigned long)&frame->uc; - } - } + if (ksig->ka.sa.sa_flags & SA_SIGINFO) + err |= copy_siginfo_to_user(&frame->info, &ksig->info); + + if (err == 0) + err = setup_return(regs, ksig, &user, usig); + + /* + * We must not fail if setup_return() succeeded - see comment at the + * beginning of setup_return(). + */ if (err == 0) set_handler_user_access_state(); diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 2729faaee4b4c2..1d9d51d7627fd4 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -20,6 +20,22 @@ #include #include +enum kunwind_source { + KUNWIND_SOURCE_UNKNOWN, + KUNWIND_SOURCE_FRAME, + KUNWIND_SOURCE_CALLER, + KUNWIND_SOURCE_TASK, + KUNWIND_SOURCE_REGS_PC, +}; + +union unwind_flags { + unsigned long all; + struct { + unsigned long fgraph : 1, + kretprobe : 1; + }; +}; + /* * Kernel unwind state * @@ -37,6 +53,9 @@ struct kunwind_state { #ifdef CONFIG_KRETPROBES struct llist_node *kr_cur; #endif + enum kunwind_source source; + union unwind_flags flags; + struct pt_regs *regs; }; static __always_inline void @@ -45,6 +64,9 @@ kunwind_init(struct kunwind_state *state, { unwind_init_common(&state->common); state->task = task; + state->source = KUNWIND_SOURCE_UNKNOWN; + state->flags.all = 0; + state->regs = NULL; } /* @@ -60,8 +82,10 @@ kunwind_init_from_regs(struct kunwind_state *state, { kunwind_init(state, current); + state->regs = regs; state->common.fp = regs->regs[29]; state->common.pc = regs->pc; + state->source = KUNWIND_SOURCE_REGS_PC; } /* @@ -79,6 +103,7 @@ kunwind_init_from_caller(struct kunwind_state *state) state->common.fp = (unsigned long)__builtin_frame_address(1); state->common.pc = (unsigned long)__builtin_return_address(0); + state->source = KUNWIND_SOURCE_CALLER; } /* @@ -99,6 +124,7 @@ kunwind_init_from_task(struct kunwind_state *state, state->common.fp = thread_saved_fp(task); state->common.pc = thread_saved_pc(task); + state->source = KUNWIND_SOURCE_TASK; } static __always_inline int @@ -111,9 +137,12 @@ kunwind_recover_return_address(struct kunwind_state *state) orig_pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, state->common.pc, (void *)state->common.fp); - if (WARN_ON_ONCE(state->common.pc == orig_pc)) + if (state->common.pc == orig_pc) { + WARN_ON_ONCE(state->task == current); return -EINVAL; + } state->common.pc = orig_pc; + state->flags.fgraph = 1; } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ @@ -124,12 +153,95 @@ kunwind_recover_return_address(struct kunwind_state *state) (void *)state->common.fp, &state->kr_cur); state->common.pc = orig_pc; + state->flags.kretprobe = 1; } #endif /* CONFIG_KRETPROBES */ return 0; } +static __always_inline +int kunwind_next_regs_pc(struct kunwind_state *state) +{ + struct stack_info *info; + unsigned long fp = state->common.fp; + struct pt_regs *regs; + + regs = container_of((u64 *)fp, struct pt_regs, stackframe.record.fp); + + info = unwind_find_stack(&state->common, (unsigned long)regs, sizeof(*regs)); + if (!info) + return -EINVAL; + + unwind_consume_stack(&state->common, info, (unsigned long)regs, + sizeof(*regs)); + + state->regs = regs; + state->common.pc = regs->pc; + state->common.fp = regs->regs[29]; + state->regs = NULL; + state->source = KUNWIND_SOURCE_REGS_PC; + return 0; +} + +static __always_inline int +kunwind_next_frame_record_meta(struct kunwind_state *state) +{ + struct task_struct *tsk = state->task; + unsigned long fp = state->common.fp; + struct frame_record_meta *meta; + struct stack_info *info; + + info = unwind_find_stack(&state->common, fp, sizeof(*meta)); + if (!info) + return -EINVAL; + + meta = (struct frame_record_meta *)fp; + switch (READ_ONCE(meta->type)) { + case FRAME_META_TYPE_FINAL: + if (meta == &task_pt_regs(tsk)->stackframe) + return -ENOENT; + WARN_ON_ONCE(tsk == current); + return -EINVAL; + case FRAME_META_TYPE_PT_REGS: + return kunwind_next_regs_pc(state); + default: + WARN_ON_ONCE(tsk == current); + return -EINVAL; + } +} + +static __always_inline int +kunwind_next_frame_record(struct kunwind_state *state) +{ + unsigned long fp = state->common.fp; + struct frame_record *record; + struct stack_info *info; + unsigned long new_fp, new_pc; + + if (fp & 0x7) + return -EINVAL; + + info = unwind_find_stack(&state->common, fp, sizeof(*record)); + if (!info) + return -EINVAL; + + record = (struct frame_record *)fp; + new_fp = READ_ONCE(record->fp); + new_pc = READ_ONCE(record->lr); + + if (!new_fp && !new_pc) + return kunwind_next_frame_record_meta(state); + + unwind_consume_stack(&state->common, info, fp, sizeof(*record)); + + state->common.fp = new_fp; + state->common.pc = new_pc; + state->source = KUNWIND_SOURCE_FRAME; + + return 0; +} + /* * Unwind from one frame record (A) to the next frame record (B). * @@ -140,15 +252,21 @@ kunwind_recover_return_address(struct kunwind_state *state) static __always_inline int kunwind_next(struct kunwind_state *state) { - struct task_struct *tsk = state->task; - unsigned long fp = state->common.fp; int err; - /* Final frame; nothing to unwind */ - if (fp == (unsigned long)task_pt_regs(tsk)->stackframe) - return -ENOENT; + state->flags.all = 0; + + switch (state->source) { + case KUNWIND_SOURCE_FRAME: + case KUNWIND_SOURCE_CALLER: + case KUNWIND_SOURCE_TASK: + case KUNWIND_SOURCE_REGS_PC: + err = kunwind_next_frame_record(state); + break; + default: + err = -EINVAL; + } - err = unwind_next_frame_record(&state->common); if (err) return err; @@ -294,10 +412,32 @@ noinline noinstr void arch_bpf_stack_walk(bool (*consume_entry)(void *cookie, u6 kunwind_stack_walk(arch_bpf_unwind_consume_entry, &data, current, NULL); } -static bool dump_backtrace_entry(void *arg, unsigned long where) +static const char *state_source_string(const struct kunwind_state *state) { + switch (state->source) { + case KUNWIND_SOURCE_FRAME: return NULL; + case KUNWIND_SOURCE_CALLER: return "C"; + case KUNWIND_SOURCE_TASK: return "T"; + case KUNWIND_SOURCE_REGS_PC: return "P"; + default: return "U"; + } +} + +static bool dump_backtrace_entry(const struct kunwind_state *state, void *arg) +{ + const char *source = state_source_string(state); + union unwind_flags flags = state->flags; + bool has_info = source || flags.all; char *loglvl = arg; - printk("%s %pSb\n", loglvl, (void *)where); + + printk("%s %pSb%s%s%s%s%s\n", loglvl, + (void *)state->common.pc, + has_info ? " (" : "", + source ? source : "", + flags.fgraph ? "F" : "", + flags.kretprobe ? "K" : "", + has_info ? ")" : ""); + return true; } @@ -316,7 +456,7 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, return; printk("%sCall trace:\n", loglvl); - arch_stack_walk(dump_backtrace_entry, (void *)loglvl, tsk, regs); + kunwind_stack_walk(dump_backtrace_entry, (void *)loglvl, tsk, regs); put_task_stack(tsk); } diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 563cbce1112696..4e26bd356a482b 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -506,6 +506,16 @@ void do_el1_bti(struct pt_regs *regs, unsigned long esr) die("Oops - BTI", regs, esr); } +void do_el0_gcs(struct pt_regs *regs, unsigned long esr) +{ + force_signal_inject(SIGSEGV, SEGV_CPERR, regs->pc, 0); +} + +void do_el1_gcs(struct pt_regs *regs, unsigned long esr) +{ + die("Oops - GCS", regs, esr); +} + void do_el0_fpac(struct pt_regs *regs, unsigned long esr) { force_signal_inject(SIGILL, ILL_ILLOPN, regs->pc, esr); @@ -531,6 +541,13 @@ void do_el0_mops(struct pt_regs *regs, unsigned long esr) user_fastforward_single_step(current); } +void do_el1_mops(struct pt_regs *regs, unsigned long esr) +{ + arm64_mops_reset_regs(®s->user_regs, esr); + + kernel_fastforward_single_step(regs); +} + #define __user_cache_maint(insn, address, res) \ if (address >= TASK_SIZE_MAX) { \ res = -EFAULT; \ @@ -852,6 +869,7 @@ static const char *esr_class_str[] = { [ESR_ELx_EC_MOPS] = "MOPS", [ESR_ELx_EC_FP_EXC32] = "FP (AArch32)", [ESR_ELx_EC_FP_EXC64] = "FP (AArch64)", + [ESR_ELx_EC_GCS] = "Guarded Control Stack", [ESR_ELx_EC_SERROR] = "SError", [ESR_ELx_EC_BREAKPT_LOW] = "Breakpoint (lower EL)", [ESR_ELx_EC_BREAKPT_CUR] = "Breakpoint (current EL)", diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index 706c9c3a7a50a4..e8ed8e5b713b52 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -39,8 +38,6 @@ struct vdso_abi_info { const char *vdso_code_start; const char *vdso_code_end; unsigned long vdso_pages; - /* Data Mapping */ - struct vm_special_mapping *dm; /* Code Mapping */ struct vm_special_mapping *cm; }; @@ -113,6 +110,8 @@ struct vdso_data *arch_get_vdso_data(void *vvar_page) return (struct vdso_data *)(vvar_page); } +static const struct vm_special_mapping vvar_map; + /* * The vvar mapping contains data for a specific time namespace, so when a task * changes namespace we must unmap its vvar data for the old namespace. @@ -129,12 +128,8 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns) mmap_read_lock(mm); for_each_vma(vmi, vma) { - if (vma_is_special_mapping(vma, vdso_info[VDSO_ABI_AA64].dm)) - zap_vma_pages(vma); -#ifdef CONFIG_COMPAT_VDSO - if (vma_is_special_mapping(vma, vdso_info[VDSO_ABI_AA32].dm)) + if (vma_is_special_mapping(vma, &vvar_map)) zap_vma_pages(vma); -#endif } mmap_read_unlock(mm); @@ -176,6 +171,11 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, return vmf_insert_pfn(vma, vmf->address, pfn); } +static const struct vm_special_mapping vvar_map = { + .name = "[vvar]", + .fault = vvar_fault, +}; + static int __setup_additional_pages(enum vdso_abi abi, struct mm_struct *mm, struct linux_binprm *bprm, @@ -199,7 +199,7 @@ static int __setup_additional_pages(enum vdso_abi abi, ret = _install_special_mapping(mm, vdso_base, VVAR_NR_PAGES * PAGE_SIZE, VM_READ|VM_MAYREAD|VM_PFNMAP, - vdso_info[abi].dm); + &vvar_map); if (IS_ERR(ret)) goto up_fail; @@ -229,7 +229,6 @@ static int __setup_additional_pages(enum vdso_abi abi, enum aarch32_map { AA32_MAP_VECTORS, /* kuser helpers */ AA32_MAP_SIGPAGE, - AA32_MAP_VVAR, AA32_MAP_VDSO, }; @@ -254,10 +253,6 @@ static struct vm_special_mapping aarch32_vdso_maps[] = { .pages = &aarch32_sig_page, .mremap = aarch32_sigpage_mremap, }, - [AA32_MAP_VVAR] = { - .name = "[vvar]", - .fault = vvar_fault, - }, [AA32_MAP_VDSO] = { .name = "[vdso]", .mremap = vdso_mremap, @@ -307,7 +302,6 @@ static int __init __aarch32_alloc_vdso_pages(void) if (!IS_ENABLED(CONFIG_COMPAT_VDSO)) return 0; - vdso_info[VDSO_ABI_AA32].dm = &aarch32_vdso_maps[AA32_MAP_VVAR]; vdso_info[VDSO_ABI_AA32].cm = &aarch32_vdso_maps[AA32_MAP_VDSO]; return __vdso_init(VDSO_ABI_AA32); @@ -402,26 +396,14 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) } #endif /* CONFIG_COMPAT */ -enum aarch64_map { - AA64_MAP_VVAR, - AA64_MAP_VDSO, -}; - -static struct vm_special_mapping aarch64_vdso_maps[] __ro_after_init = { - [AA64_MAP_VVAR] = { - .name = "[vvar]", - .fault = vvar_fault, - }, - [AA64_MAP_VDSO] = { - .name = "[vdso]", - .mremap = vdso_mremap, - }, +static struct vm_special_mapping aarch64_vdso_map __ro_after_init = { + .name = "[vdso]", + .mremap = vdso_mremap, }; static int __init vdso_init(void) { - vdso_info[VDSO_ABI_AA64].dm = &aarch64_vdso_maps[AA64_MAP_VVAR]; - vdso_info[VDSO_ABI_AA64].cm = &aarch64_vdso_maps[AA64_MAP_VDSO]; + vdso_info[VDSO_ABI_AA64].cm = &aarch64_vdso_map; return __vdso_init(VDSO_ABI_AA64); } diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S index f204a9ddc83359..4ec32e86a8da22 100644 --- a/arch/arm64/kernel/vdso/vdso.lds.S +++ b/arch/arm64/kernel/vdso/vdso.lds.S @@ -25,7 +25,7 @@ SECTIONS #ifdef CONFIG_TIME_NS PROVIDE(_timens_data = _vdso_data + PAGE_SIZE); #endif - . = VDSO_LBASE + SIZEOF_HEADERS; + . = SIZEOF_HEADERS; .hash : { *(.hash) } :text .gnu.hash : { *(.gnu.hash) } diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S index 8d95d7d35057d2..732702a187e9e8 100644 --- a/arch/arm64/kernel/vdso32/vdso.lds.S +++ b/arch/arm64/kernel/vdso32/vdso.lds.S @@ -22,7 +22,7 @@ SECTIONS #ifdef CONFIG_TIME_NS PROVIDE_HIDDEN(_timens_data = _vdso_data + PAGE_SIZE); #endif - . = VDSO_LBASE + SIZEOF_HEADERS; + . = SIZEOF_HEADERS; .hash : { *(.hash) } :text .gnu.hash : { *(.gnu.hash) } diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 58d89d997d050f..f84c71f04d9ea9 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -287,6 +287,9 @@ SECTIONS __initdata_end = .; __init_end = .; + .data.rel.ro : { *(.data.rel.ro) } + ASSERT(SIZEOF(.data.rel.ro) == 0, "Unexpected RELRO detected!") + _data = .; _sdata = .; RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_ALIGN) @@ -343,9 +346,6 @@ SECTIONS *(.plt) *(.plt.*) *(.iplt) *(.igot .igot.plt) } ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!") - - .data.rel.ro : { *(.data.rel.ro) } - ASSERT(SIZEOF(.data.rel.ro) == 0, "Unexpected RELRO detected!") } #include "image-vars.h" diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 879982b1cc739e..1215df59041856 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -206,8 +206,7 @@ void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map) static inline bool userspace_irqchip(struct kvm *kvm) { - return static_branch_unlikely(&userspace_irqchip_in_use) && - unlikely(!irqchip_in_kernel(kvm)); + return unlikely(!irqchip_in_kernel(kvm)); } static void soft_timer_start(struct hrtimer *hrt, u64 ns) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 48cafb65d6acff..a102c3aebdbc41 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -69,7 +69,6 @@ DECLARE_KVM_NVHE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt); static bool vgic_present, kvm_arm_initialised; static DEFINE_PER_CPU(unsigned char, kvm_hyp_initialized); -DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use); bool is_kvm_arm_initialised(void) { @@ -503,9 +502,6 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { - if (vcpu_has_run_once(vcpu) && unlikely(!irqchip_in_kernel(vcpu->kvm))) - static_branch_dec(&userspace_irqchip_in_use); - kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache); kvm_timer_vcpu_terminate(vcpu); kvm_pmu_vcpu_destroy(vcpu); @@ -848,22 +844,6 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) return ret; } - if (!irqchip_in_kernel(kvm)) { - /* - * Tell the rest of the code that there are userspace irqchip - * VMs in the wild. - */ - static_branch_inc(&userspace_irqchip_in_use); - } - - /* - * Initialize traps for protected VMs. - * NOTE: Move to run in EL2 directly, rather than via a hypercall, once - * the code is in place for first run initialization at EL2. - */ - if (kvm_vm_is_protected(kvm)) - kvm_call_hyp_nvhe(__pkvm_vcpu_init_traps, vcpu); - mutex_lock(&kvm->arch.config_lock); set_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &kvm->arch.flags); mutex_unlock(&kvm->arch.config_lock); @@ -1077,7 +1057,7 @@ static bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu, int *ret) * state gets updated in kvm_timer_update_run and * kvm_pmu_update_run below). */ - if (static_branch_unlikely(&userspace_irqchip_in_use)) { + if (unlikely(!irqchip_in_kernel(vcpu->kvm))) { if (kvm_timer_should_notify_user(vcpu) || kvm_pmu_should_notify_user(vcpu)) { *ret = -EINTR; @@ -1199,7 +1179,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) vcpu->mode = OUTSIDE_GUEST_MODE; isb(); /* Ensure work in x_flush_hwstate is committed */ kvm_pmu_sync_hwstate(vcpu); - if (static_branch_unlikely(&userspace_irqchip_in_use)) + if (unlikely(!irqchip_in_kernel(vcpu->kvm))) kvm_timer_sync_user(vcpu); kvm_vgic_sync_hwstate(vcpu); local_irq_enable(); @@ -1245,7 +1225,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) * we don't want vtimer interrupts to race with syncing the * timer virtual interrupt state. */ - if (static_branch_unlikely(&userspace_irqchip_in_use)) + if (unlikely(!irqchip_in_kernel(vcpu->kvm))) kvm_timer_sync_user(vcpu); kvm_arch_vcpu_ctxsync_fp(vcpu); diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c index 39f0e87a340e82..3d7eb395e33ddb 100644 --- a/arch/arm64/kvm/at.c +++ b/arch/arm64/kvm/at.c @@ -24,6 +24,9 @@ struct s1_walk_info { unsigned int txsz; int sl; bool hpd; + bool e0poe; + bool poe; + bool pan; bool be; bool s2; }; @@ -37,6 +40,16 @@ struct s1_walk_result { u8 APTable; bool UXNTable; bool PXNTable; + bool uwxn; + bool uov; + bool ur; + bool uw; + bool ux; + bool pwxn; + bool pov; + bool pr; + bool pw; + bool px; }; struct { u8 fst; @@ -87,6 +100,51 @@ static enum trans_regime compute_translation_regime(struct kvm_vcpu *vcpu, u32 o } } +static bool s1pie_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime) +{ + if (!kvm_has_s1pie(vcpu->kvm)) + return false; + + switch (regime) { + case TR_EL2: + case TR_EL20: + return vcpu_read_sys_reg(vcpu, TCR2_EL2) & TCR2_EL2_PIE; + case TR_EL10: + return (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) && + (__vcpu_sys_reg(vcpu, TCR2_EL1) & TCR2_EL1x_PIE); + default: + BUG(); + } +} + +static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi) +{ + u64 val; + + if (!kvm_has_s1poe(vcpu->kvm)) { + wi->poe = wi->e0poe = false; + return; + } + + switch (wi->regime) { + case TR_EL2: + case TR_EL20: + val = vcpu_read_sys_reg(vcpu, TCR2_EL2); + wi->poe = val & TCR2_EL2_POE; + wi->e0poe = (wi->regime == TR_EL20) && (val & TCR2_EL2_E0POE); + break; + case TR_EL10: + if (__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_TCR2En) { + wi->poe = wi->e0poe = false; + return; + } + + val = __vcpu_sys_reg(vcpu, TCR2_EL1); + wi->poe = val & TCR2_EL1x_POE; + wi->e0poe = val & TCR2_EL1x_E0POE; + } +} + static int setup_s1_walk(struct kvm_vcpu *vcpu, u32 op, struct s1_walk_info *wi, struct s1_walk_result *wr, u64 va) { @@ -98,6 +156,8 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, u32 op, struct s1_walk_info *wi, wi->regime = compute_translation_regime(vcpu, op); as_el0 = (op == OP_AT_S1E0R || op == OP_AT_S1E0W); + wi->pan = (op == OP_AT_S1E1RP || op == OP_AT_S1E1WP) && + (*vcpu_cpsr(vcpu) & PSR_PAN_BIT); va55 = va & BIT(55); @@ -180,6 +240,14 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, u32 op, struct s1_walk_info *wi, (va55 ? FIELD_GET(TCR_HPD1, tcr) : FIELD_GET(TCR_HPD0, tcr))); + /* R_JHSVW */ + wi->hpd |= s1pie_enabled(vcpu, wi->regime); + + /* Do we have POE? */ + compute_s1poe(vcpu, wi); + + /* R_BVXDG */ + wi->hpd |= (wi->poe || wi->e0poe); /* Someone was silly enough to encode TG0/TG1 differently */ if (va55) { @@ -412,6 +480,11 @@ struct mmu_config { u64 ttbr1; u64 tcr; u64 mair; + u64 tcr2; + u64 pir; + u64 pire0; + u64 por_el0; + u64 por_el1; u64 sctlr; u64 vttbr; u64 vtcr; @@ -424,6 +497,17 @@ static void __mmu_config_save(struct mmu_config *config) config->ttbr1 = read_sysreg_el1(SYS_TTBR1); config->tcr = read_sysreg_el1(SYS_TCR); config->mair = read_sysreg_el1(SYS_MAIR); + if (cpus_have_final_cap(ARM64_HAS_TCR2)) { + config->tcr2 = read_sysreg_el1(SYS_TCR2); + if (cpus_have_final_cap(ARM64_HAS_S1PIE)) { + config->pir = read_sysreg_el1(SYS_PIR); + config->pire0 = read_sysreg_el1(SYS_PIRE0); + } + if (system_supports_poe()) { + config->por_el1 = read_sysreg_el1(SYS_POR); + config->por_el0 = read_sysreg_s(SYS_POR_EL0); + } + } config->sctlr = read_sysreg_el1(SYS_SCTLR); config->vttbr = read_sysreg(vttbr_el2); config->vtcr = read_sysreg(vtcr_el2); @@ -444,6 +528,17 @@ static void __mmu_config_restore(struct mmu_config *config) write_sysreg_el1(config->ttbr1, SYS_TTBR1); write_sysreg_el1(config->tcr, SYS_TCR); write_sysreg_el1(config->mair, SYS_MAIR); + if (cpus_have_final_cap(ARM64_HAS_TCR2)) { + write_sysreg_el1(config->tcr2, SYS_TCR2); + if (cpus_have_final_cap(ARM64_HAS_S1PIE)) { + write_sysreg_el1(config->pir, SYS_PIR); + write_sysreg_el1(config->pire0, SYS_PIRE0); + } + if (system_supports_poe()) { + write_sysreg_el1(config->por_el1, SYS_POR); + write_sysreg_s(config->por_el0, SYS_POR_EL0); + } + } write_sysreg_el1(config->sctlr, SYS_SCTLR); write_sysreg(config->vttbr, vttbr_el2); write_sysreg(config->vtcr, vtcr_el2); @@ -644,8 +739,15 @@ static u64 compute_par_s12(struct kvm_vcpu *vcpu, u64 s1_par, final_attr = s1_parattr; break; default: - /* MemAttr[2]=0, Device from S2 */ - final_attr = s2_memattr & GENMASK(1,0) << 2; + /* + * MemAttr[2]=0, Device from S2. + * + * FWB does not influence the way that stage 1 + * memory types and attributes are combined + * with stage 2 Device type and attributes. + */ + final_attr = min(s2_memattr_to_attr(s2_memattr), + s1_parattr); } } else { /* Combination of R_HMNDG, R_TNHFM and R_GQFSF */ @@ -739,6 +841,9 @@ static bool pan3_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime) if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, PAN, PAN3)) return false; + if (s1pie_enabled(vcpu, regime)) + return true; + if (regime == TR_EL10) sctlr = vcpu_read_sys_reg(vcpu, SCTLR_EL1); else @@ -747,111 +852,343 @@ static bool pan3_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime) return sctlr & SCTLR_EL1_EPAN; } -static u64 handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr) +static void compute_s1_direct_permissions(struct kvm_vcpu *vcpu, + struct s1_walk_info *wi, + struct s1_walk_result *wr) { - bool perm_fail, ur, uw, ux, pr, pw, px; - struct s1_walk_result wr = {}; - struct s1_walk_info wi = {}; - int ret, idx; + bool wxn; - ret = setup_s1_walk(vcpu, op, &wi, &wr, vaddr); - if (ret) - goto compute_par; - - if (wr.level == S1_MMU_DISABLED) - goto compute_par; - - idx = srcu_read_lock(&vcpu->kvm->srcu); - - ret = walk_s1(vcpu, &wi, &wr, vaddr); - - srcu_read_unlock(&vcpu->kvm->srcu, idx); - - if (ret) - goto compute_par; - - /* FIXME: revisit when adding indirect permission support */ - /* AArch64.S1DirectBasePermissions() */ - if (wi.regime != TR_EL2) { - switch (FIELD_GET(PTE_USER | PTE_RDONLY, wr.desc)) { + /* Non-hierarchical part of AArch64.S1DirectBasePermissions() */ + if (wi->regime != TR_EL2) { + switch (FIELD_GET(PTE_USER | PTE_RDONLY, wr->desc)) { case 0b00: - pr = pw = true; - ur = uw = false; + wr->pr = wr->pw = true; + wr->ur = wr->uw = false; break; case 0b01: - pr = pw = ur = uw = true; + wr->pr = wr->pw = wr->ur = wr->uw = true; break; case 0b10: - pr = true; - pw = ur = uw = false; + wr->pr = true; + wr->pw = wr->ur = wr->uw = false; break; case 0b11: - pr = ur = true; - pw = uw = false; + wr->pr = wr->ur = true; + wr->pw = wr->uw = false; break; } - switch (wr.APTable) { + /* We don't use px for anything yet, but hey... */ + wr->px = !((wr->desc & PTE_PXN) || wr->uw); + wr->ux = !(wr->desc & PTE_UXN); + } else { + wr->ur = wr->uw = wr->ux = false; + + if (!(wr->desc & PTE_RDONLY)) { + wr->pr = wr->pw = true; + } else { + wr->pr = true; + wr->pw = false; + } + + /* XN maps to UXN */ + wr->px = !(wr->desc & PTE_UXN); + } + + switch (wi->regime) { + case TR_EL2: + case TR_EL20: + wxn = (vcpu_read_sys_reg(vcpu, SCTLR_EL2) & SCTLR_ELx_WXN); + break; + case TR_EL10: + wxn = (__vcpu_sys_reg(vcpu, SCTLR_EL1) & SCTLR_ELx_WXN); + break; + } + + wr->pwxn = wr->uwxn = wxn; + wr->pov = wi->poe; + wr->uov = wi->e0poe; +} + +static void compute_s1_hierarchical_permissions(struct kvm_vcpu *vcpu, + struct s1_walk_info *wi, + struct s1_walk_result *wr) +{ + /* Hierarchical part of AArch64.S1DirectBasePermissions() */ + if (wi->regime != TR_EL2) { + switch (wr->APTable) { case 0b00: break; case 0b01: - ur = uw = false; + wr->ur = wr->uw = false; break; case 0b10: - pw = uw = false; + wr->pw = wr->uw = false; break; case 0b11: - pw = ur = uw = false; + wr->pw = wr->ur = wr->uw = false; break; } - /* We don't use px for anything yet, but hey... */ - px = !((wr.desc & PTE_PXN) || wr.PXNTable || uw); - ux = !((wr.desc & PTE_UXN) || wr.UXNTable); + wr->px &= !wr->PXNTable; + wr->ux &= !wr->UXNTable; + } else { + if (wr->APTable & BIT(1)) + wr->pw = false; + + /* XN maps to UXN */ + wr->px &= !wr->UXNTable; + } +} - if (op == OP_AT_S1E1RP || op == OP_AT_S1E1WP) { - bool pan; +#define perm_idx(v, r, i) ((vcpu_read_sys_reg((v), (r)) >> ((i) * 4)) & 0xf) + +#define set_priv_perms(wr, r, w, x) \ + do { \ + (wr)->pr = (r); \ + (wr)->pw = (w); \ + (wr)->px = (x); \ + } while (0) + +#define set_unpriv_perms(wr, r, w, x) \ + do { \ + (wr)->ur = (r); \ + (wr)->uw = (w); \ + (wr)->ux = (x); \ + } while (0) + +#define set_priv_wxn(wr, v) \ + do { \ + (wr)->pwxn = (v); \ + } while (0) + +#define set_unpriv_wxn(wr, v) \ + do { \ + (wr)->uwxn = (v); \ + } while (0) + +/* Similar to AArch64.S1IndirectBasePermissions(), without GCS */ +#define set_perms(w, wr, ip) \ + do { \ + /* R_LLZDZ */ \ + switch ((ip)) { \ + case 0b0000: \ + set_ ## w ## _perms((wr), false, false, false); \ + break; \ + case 0b0001: \ + set_ ## w ## _perms((wr), true , false, false); \ + break; \ + case 0b0010: \ + set_ ## w ## _perms((wr), false, false, true ); \ + break; \ + case 0b0011: \ + set_ ## w ## _perms((wr), true , false, true ); \ + break; \ + case 0b0100: \ + set_ ## w ## _perms((wr), false, false, false); \ + break; \ + case 0b0101: \ + set_ ## w ## _perms((wr), true , true , false); \ + break; \ + case 0b0110: \ + set_ ## w ## _perms((wr), true , true , true ); \ + break; \ + case 0b0111: \ + set_ ## w ## _perms((wr), true , true , true ); \ + break; \ + case 0b1000: \ + set_ ## w ## _perms((wr), true , false, false); \ + break; \ + case 0b1001: \ + set_ ## w ## _perms((wr), true , false, false); \ + break; \ + case 0b1010: \ + set_ ## w ## _perms((wr), true , false, true ); \ + break; \ + case 0b1011: \ + set_ ## w ## _perms((wr), false, false, false); \ + break; \ + case 0b1100: \ + set_ ## w ## _perms((wr), true , true , false); \ + break; \ + case 0b1101: \ + set_ ## w ## _perms((wr), false, false, false); \ + break; \ + case 0b1110: \ + set_ ## w ## _perms((wr), true , true , true ); \ + break; \ + case 0b1111: \ + set_ ## w ## _perms((wr), false, false, false); \ + break; \ + } \ + \ + /* R_HJYGR */ \ + set_ ## w ## _wxn((wr), ((ip) == 0b0110)); \ + \ + } while (0) + +static void compute_s1_indirect_permissions(struct kvm_vcpu *vcpu, + struct s1_walk_info *wi, + struct s1_walk_result *wr) +{ + u8 up, pp, idx; - pan = *vcpu_cpsr(vcpu) & PSR_PAN_BIT; - pan &= ur || uw || (pan3_enabled(vcpu, wi.regime) && ux); - pw &= !pan; - pr &= !pan; - } - } else { - ur = uw = ux = false; + idx = pte_pi_index(wr->desc); - if (!(wr.desc & PTE_RDONLY)) { - pr = pw = true; - } else { - pr = true; - pw = false; - } + switch (wi->regime) { + case TR_EL10: + pp = perm_idx(vcpu, PIR_EL1, idx); + up = perm_idx(vcpu, PIRE0_EL1, idx); + break; + case TR_EL20: + pp = perm_idx(vcpu, PIR_EL2, idx); + up = perm_idx(vcpu, PIRE0_EL2, idx); + break; + case TR_EL2: + pp = perm_idx(vcpu, PIR_EL2, idx); + up = 0; + break; + } - if (wr.APTable & BIT(1)) - pw = false; + set_perms(priv, wr, pp); - /* XN maps to UXN */ - px = !((wr.desc & PTE_UXN) || wr.UXNTable); + if (wi->regime != TR_EL2) + set_perms(unpriv, wr, up); + else + set_unpriv_perms(wr, false, false, false); + + wr->pov = wi->poe && !(pp & BIT(3)); + wr->uov = wi->e0poe && !(up & BIT(3)); + + /* R_VFPJF */ + if (wr->px && wr->uw) { + set_priv_perms(wr, false, false, false); + set_unpriv_perms(wr, false, false, false); + } +} + +static void compute_s1_overlay_permissions(struct kvm_vcpu *vcpu, + struct s1_walk_info *wi, + struct s1_walk_result *wr) +{ + u8 idx, pov_perms, uov_perms; + + idx = FIELD_GET(PTE_PO_IDX_MASK, wr->desc); + + switch (wi->regime) { + case TR_EL10: + pov_perms = perm_idx(vcpu, POR_EL1, idx); + uov_perms = perm_idx(vcpu, POR_EL0, idx); + break; + case TR_EL20: + pov_perms = perm_idx(vcpu, POR_EL2, idx); + uov_perms = perm_idx(vcpu, POR_EL0, idx); + break; + case TR_EL2: + pov_perms = perm_idx(vcpu, POR_EL2, idx); + uov_perms = 0; + break; + } + + if (pov_perms & ~POE_RXW) + pov_perms = POE_NONE; + + if (wi->poe && wr->pov) { + wr->pr &= pov_perms & POE_R; + wr->px &= pov_perms & POE_X; + wr->pw &= pov_perms & POE_W; + } + + if (uov_perms & ~POE_RXW) + uov_perms = POE_NONE; + + if (wi->e0poe && wr->uov) { + wr->ur &= uov_perms & POE_R; + wr->ux &= uov_perms & POE_X; + wr->uw &= uov_perms & POE_W; } +} + +static void compute_s1_permissions(struct kvm_vcpu *vcpu, + struct s1_walk_info *wi, + struct s1_walk_result *wr) +{ + bool pan; + + if (!s1pie_enabled(vcpu, wi->regime)) + compute_s1_direct_permissions(vcpu, wi, wr); + else + compute_s1_indirect_permissions(vcpu, wi, wr); + + if (!wi->hpd) + compute_s1_hierarchical_permissions(vcpu, wi, wr); + + if (wi->poe || wi->e0poe) + compute_s1_overlay_permissions(vcpu, wi, wr); + + /* R_QXXPC */ + if (wr->pwxn) { + if (!wr->pov && wr->pw) + wr->px = false; + if (wr->pov && wr->px) + wr->pw = false; + } + + /* R_NPBXC */ + if (wr->uwxn) { + if (!wr->uov && wr->uw) + wr->ux = false; + if (wr->uov && wr->ux) + wr->uw = false; + } + + pan = wi->pan && (wr->ur || wr->uw || + (pan3_enabled(vcpu, wi->regime) && wr->ux)); + wr->pw &= !pan; + wr->pr &= !pan; +} - perm_fail = false; +static u64 handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr) +{ + struct s1_walk_result wr = {}; + struct s1_walk_info wi = {}; + bool perm_fail = false; + int ret, idx; + + ret = setup_s1_walk(vcpu, op, &wi, &wr, vaddr); + if (ret) + goto compute_par; + + if (wr.level == S1_MMU_DISABLED) + goto compute_par; + + idx = srcu_read_lock(&vcpu->kvm->srcu); + + ret = walk_s1(vcpu, &wi, &wr, vaddr); + + srcu_read_unlock(&vcpu->kvm->srcu, idx); + + if (ret) + goto compute_par; + + compute_s1_permissions(vcpu, &wi, &wr); switch (op) { case OP_AT_S1E1RP: case OP_AT_S1E1R: case OP_AT_S1E2R: - perm_fail = !pr; + perm_fail = !wr.pr; break; case OP_AT_S1E1WP: case OP_AT_S1E1W: case OP_AT_S1E2W: - perm_fail = !pw; + perm_fail = !wr.pw; break; case OP_AT_S1E0R: - perm_fail = !ur; + perm_fail = !wr.ur; break; case OP_AT_S1E0W: - perm_fail = !uw; + perm_fail = !wr.uw; break; case OP_AT_S1E1A: case OP_AT_S1E2A: @@ -914,6 +1251,17 @@ static u64 __kvm_at_s1e01_fast(struct kvm_vcpu *vcpu, u32 op, u64 vaddr) write_sysreg_el1(vcpu_read_sys_reg(vcpu, TTBR1_EL1), SYS_TTBR1); write_sysreg_el1(vcpu_read_sys_reg(vcpu, TCR_EL1), SYS_TCR); write_sysreg_el1(vcpu_read_sys_reg(vcpu, MAIR_EL1), SYS_MAIR); + if (kvm_has_tcr2(vcpu->kvm)) { + write_sysreg_el1(vcpu_read_sys_reg(vcpu, TCR2_EL1), SYS_TCR2); + if (kvm_has_s1pie(vcpu->kvm)) { + write_sysreg_el1(vcpu_read_sys_reg(vcpu, PIR_EL1), SYS_PIR); + write_sysreg_el1(vcpu_read_sys_reg(vcpu, PIRE0_EL1), SYS_PIRE0); + } + if (kvm_has_s1poe(vcpu->kvm)) { + write_sysreg_el1(vcpu_read_sys_reg(vcpu, POR_EL1), SYS_POR); + write_sysreg_s(vcpu_read_sys_reg(vcpu, POR_EL0), SYS_POR_EL0); + } + } write_sysreg_el1(vcpu_read_sys_reg(vcpu, SCTLR_EL1), SYS_SCTLR); __load_stage2(mmu, mmu->arch); @@ -992,12 +1340,9 @@ void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr) * switching context behind everybody's back, disable interrupts... */ scoped_guard(write_lock_irqsave, &vcpu->kvm->mmu_lock) { - struct kvm_s2_mmu *mmu; u64 val, hcr; bool fail; - mmu = &vcpu->kvm->arch.mmu; - val = hcr = read_sysreg(hcr_el2); val &= ~HCR_TGE; val |= HCR_VM; diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 05b6435d02a97f..1ffbfd1c3cf2ec 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -16,9 +16,13 @@ enum trap_behaviour { BEHAVE_HANDLE_LOCALLY = 0, + BEHAVE_FORWARD_READ = BIT(0), BEHAVE_FORWARD_WRITE = BIT(1), - BEHAVE_FORWARD_ANY = BEHAVE_FORWARD_READ | BEHAVE_FORWARD_WRITE, + BEHAVE_FORWARD_RW = BEHAVE_FORWARD_READ | BEHAVE_FORWARD_WRITE, + + /* Traps that take effect in Host EL0, this is rare! */ + BEHAVE_FORWARD_IN_HOST_EL0 = BIT(2), }; struct trap_bits { @@ -79,7 +83,6 @@ enum cgt_group_id { CGT_MDCR_E2TB, CGT_MDCR_TDCC, - CGT_CPACR_E0POE, CGT_CPTR_TAM, CGT_CPTR_TCPAC, @@ -106,6 +109,7 @@ enum cgt_group_id { CGT_HCR_TPU_TOCU, CGT_HCR_NV1_nNV2_ENSCXT, CGT_MDCR_TPM_TPMCR, + CGT_MDCR_TPM_HPMN, CGT_MDCR_TDE_TDA, CGT_MDCR_TDE_TDOSA, CGT_MDCR_TDE_TDRA, @@ -122,6 +126,7 @@ enum cgt_group_id { CGT_CNTHCTL_EL1PTEN, CGT_CPTR_TTA, + CGT_MDCR_HPMN, /* Must be last */ __NR_CGT_GROUP_IDS__ @@ -138,7 +143,7 @@ static const struct trap_bits coarse_trap_bits[] = { .index = HCR_EL2, .value = HCR_TID2, .mask = HCR_TID2, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TID3] = { .index = HCR_EL2, @@ -162,37 +167,37 @@ static const struct trap_bits coarse_trap_bits[] = { .index = HCR_EL2, .value = HCR_TIDCP, .mask = HCR_TIDCP, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TACR] = { .index = HCR_EL2, .value = HCR_TACR, .mask = HCR_TACR, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TSW] = { .index = HCR_EL2, .value = HCR_TSW, .mask = HCR_TSW, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TPC] = { /* Also called TCPC when FEAT_DPB is implemented */ .index = HCR_EL2, .value = HCR_TPC, .mask = HCR_TPC, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TPU] = { .index = HCR_EL2, .value = HCR_TPU, .mask = HCR_TPU, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TTLB] = { .index = HCR_EL2, .value = HCR_TTLB, .mask = HCR_TTLB, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TVM] = { .index = HCR_EL2, @@ -204,7 +209,7 @@ static const struct trap_bits coarse_trap_bits[] = { .index = HCR_EL2, .value = HCR_TDZ, .mask = HCR_TDZ, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TRVM] = { .index = HCR_EL2, @@ -216,205 +221,201 @@ static const struct trap_bits coarse_trap_bits[] = { .index = HCR_EL2, .value = HCR_TLOR, .mask = HCR_TLOR, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TERR] = { .index = HCR_EL2, .value = HCR_TERR, .mask = HCR_TERR, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_APK] = { .index = HCR_EL2, .value = 0, .mask = HCR_APK, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_NV] = { .index = HCR_EL2, .value = HCR_NV, .mask = HCR_NV, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_NV_nNV2] = { .index = HCR_EL2, .value = HCR_NV, .mask = HCR_NV | HCR_NV2, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_NV1_nNV2] = { .index = HCR_EL2, .value = HCR_NV | HCR_NV1, .mask = HCR_NV | HCR_NV1 | HCR_NV2, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_AT] = { .index = HCR_EL2, .value = HCR_AT, .mask = HCR_AT, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_nFIEN] = { .index = HCR_EL2, .value = 0, .mask = HCR_FIEN, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TID4] = { .index = HCR_EL2, .value = HCR_TID4, .mask = HCR_TID4, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TICAB] = { .index = HCR_EL2, .value = HCR_TICAB, .mask = HCR_TICAB, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TOCU] = { .index = HCR_EL2, .value = HCR_TOCU, .mask = HCR_TOCU, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_ENSCXT] = { .index = HCR_EL2, .value = 0, .mask = HCR_ENSCXT, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TTLBIS] = { .index = HCR_EL2, .value = HCR_TTLBIS, .mask = HCR_TTLBIS, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCR_TTLBOS] = { .index = HCR_EL2, .value = HCR_TTLBOS, .mask = HCR_TTLBOS, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_TPMCR] = { .index = MDCR_EL2, .value = MDCR_EL2_TPMCR, .mask = MDCR_EL2_TPMCR, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW | + BEHAVE_FORWARD_IN_HOST_EL0, }, [CGT_MDCR_TPM] = { .index = MDCR_EL2, .value = MDCR_EL2_TPM, .mask = MDCR_EL2_TPM, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW | + BEHAVE_FORWARD_IN_HOST_EL0, }, [CGT_MDCR_TDE] = { .index = MDCR_EL2, .value = MDCR_EL2_TDE, .mask = MDCR_EL2_TDE, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_TDA] = { .index = MDCR_EL2, .value = MDCR_EL2_TDA, .mask = MDCR_EL2_TDA, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_TDOSA] = { .index = MDCR_EL2, .value = MDCR_EL2_TDOSA, .mask = MDCR_EL2_TDOSA, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_TDRA] = { .index = MDCR_EL2, .value = MDCR_EL2_TDRA, .mask = MDCR_EL2_TDRA, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_E2PB] = { .index = MDCR_EL2, .value = 0, .mask = BIT(MDCR_EL2_E2PB_SHIFT), - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_TPMS] = { .index = MDCR_EL2, .value = MDCR_EL2_TPMS, .mask = MDCR_EL2_TPMS, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_TTRF] = { .index = MDCR_EL2, .value = MDCR_EL2_TTRF, .mask = MDCR_EL2_TTRF, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_E2TB] = { .index = MDCR_EL2, .value = 0, .mask = BIT(MDCR_EL2_E2TB_SHIFT), - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_MDCR_TDCC] = { .index = MDCR_EL2, .value = MDCR_EL2_TDCC, .mask = MDCR_EL2_TDCC, - .behaviour = BEHAVE_FORWARD_ANY, - }, - [CGT_CPACR_E0POE] = { - .index = CPTR_EL2, - .value = CPACR_ELx_E0POE, - .mask = CPACR_ELx_E0POE, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_CPTR_TAM] = { .index = CPTR_EL2, .value = CPTR_EL2_TAM, .mask = CPTR_EL2_TAM, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_CPTR_TCPAC] = { .index = CPTR_EL2, .value = CPTR_EL2_TCPAC, .mask = CPTR_EL2_TCPAC, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCRX_EnFPM] = { .index = HCRX_EL2, .value = 0, .mask = HCRX_EL2_EnFPM, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_HCRX_TCR2En] = { .index = HCRX_EL2, .value = 0, .mask = HCRX_EL2_TCR2En, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_ICH_HCR_TC] = { .index = ICH_HCR_EL2, .value = ICH_HCR_TC, .mask = ICH_HCR_TC, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_ICH_HCR_TALL0] = { .index = ICH_HCR_EL2, .value = ICH_HCR_TALL0, .mask = ICH_HCR_TALL0, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_ICH_HCR_TALL1] = { .index = ICH_HCR_EL2, .value = ICH_HCR_TALL1, .mask = ICH_HCR_TALL1, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, [CGT_ICH_HCR_TDIR] = { .index = ICH_HCR_EL2, .value = ICH_HCR_TDIR, .mask = ICH_HCR_TDIR, - .behaviour = BEHAVE_FORWARD_ANY, + .behaviour = BEHAVE_FORWARD_RW, }, }; @@ -435,6 +436,7 @@ static const enum cgt_group_id *coarse_control_combo[] = { MCB(CGT_HCR_TPU_TOCU, CGT_HCR_TPU, CGT_HCR_TOCU), MCB(CGT_HCR_NV1_nNV2_ENSCXT, CGT_HCR_NV1_nNV2, CGT_HCR_ENSCXT), MCB(CGT_MDCR_TPM_TPMCR, CGT_MDCR_TPM, CGT_MDCR_TPMCR), + MCB(CGT_MDCR_TPM_HPMN, CGT_MDCR_TPM, CGT_MDCR_HPMN), MCB(CGT_MDCR_TDE_TDA, CGT_MDCR_TDE, CGT_MDCR_TDA), MCB(CGT_MDCR_TDE_TDOSA, CGT_MDCR_TDE, CGT_MDCR_TDOSA), MCB(CGT_MDCR_TDE_TDRA, CGT_MDCR_TDE, CGT_MDCR_TDRA), @@ -474,7 +476,7 @@ static enum trap_behaviour check_cnthctl_el1pcten(struct kvm_vcpu *vcpu) if (get_sanitized_cnthctl(vcpu) & (CNTHCTL_EL1PCTEN << 10)) return BEHAVE_HANDLE_LOCALLY; - return BEHAVE_FORWARD_ANY; + return BEHAVE_FORWARD_RW; } static enum trap_behaviour check_cnthctl_el1pten(struct kvm_vcpu *vcpu) @@ -482,7 +484,7 @@ static enum trap_behaviour check_cnthctl_el1pten(struct kvm_vcpu *vcpu) if (get_sanitized_cnthctl(vcpu) & (CNTHCTL_EL1PCEN << 10)) return BEHAVE_HANDLE_LOCALLY; - return BEHAVE_FORWARD_ANY; + return BEHAVE_FORWARD_RW; } static enum trap_behaviour check_cptr_tta(struct kvm_vcpu *vcpu) @@ -493,7 +495,35 @@ static enum trap_behaviour check_cptr_tta(struct kvm_vcpu *vcpu) val = translate_cptr_el2_to_cpacr_el1(val); if (val & CPACR_ELx_TTA) - return BEHAVE_FORWARD_ANY; + return BEHAVE_FORWARD_RW; + + return BEHAVE_HANDLE_LOCALLY; +} + +static enum trap_behaviour check_mdcr_hpmn(struct kvm_vcpu *vcpu) +{ + u32 sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu)); + unsigned int idx; + + + switch (sysreg) { + case SYS_PMEVTYPERn_EL0(0) ... SYS_PMEVTYPERn_EL0(30): + case SYS_PMEVCNTRn_EL0(0) ... SYS_PMEVCNTRn_EL0(30): + idx = (sys_reg_CRm(sysreg) & 0x3) << 3 | sys_reg_Op2(sysreg); + break; + case SYS_PMXEVTYPER_EL0: + case SYS_PMXEVCNTR_EL0: + idx = SYS_FIELD_GET(PMSELR_EL0, SEL, + __vcpu_sys_reg(vcpu, PMSELR_EL0)); + break; + default: + /* Someone used this trap helper for something else... */ + KVM_BUG_ON(1, vcpu->kvm); + return BEHAVE_HANDLE_LOCALLY; + } + + if (kvm_pmu_counter_is_hyp(vcpu, idx)) + return BEHAVE_FORWARD_RW | BEHAVE_FORWARD_IN_HOST_EL0; return BEHAVE_HANDLE_LOCALLY; } @@ -505,6 +535,7 @@ static const complex_condition_check ccc[] = { CCC(CGT_CNTHCTL_EL1PCTEN, check_cnthctl_el1pcten), CCC(CGT_CNTHCTL_EL1PTEN, check_cnthctl_el1pten), CCC(CGT_CPTR_TTA, check_cptr_tta), + CCC(CGT_MDCR_HPMN, check_mdcr_hpmn), }; /* @@ -711,6 +742,10 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = { SR_TRAP(SYS_MAIR_EL1, CGT_HCR_TVM_TRVM), SR_TRAP(SYS_AMAIR_EL1, CGT_HCR_TVM_TRVM), SR_TRAP(SYS_CONTEXTIDR_EL1, CGT_HCR_TVM_TRVM), + SR_TRAP(SYS_PIR_EL1, CGT_HCR_TVM_TRVM), + SR_TRAP(SYS_PIRE0_EL1, CGT_HCR_TVM_TRVM), + SR_TRAP(SYS_POR_EL0, CGT_HCR_TVM_TRVM), + SR_TRAP(SYS_POR_EL1, CGT_HCR_TVM_TRVM), SR_TRAP(SYS_TCR2_EL1, CGT_HCR_TVM_TRVM_HCRX_TCR2En), SR_TRAP(SYS_DC_ZVA, CGT_HCR_TDZ), SR_TRAP(SYS_DC_GVA, CGT_HCR_TDZ), @@ -919,77 +954,77 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = { SR_TRAP(SYS_PMOVSCLR_EL0, CGT_MDCR_TPM), SR_TRAP(SYS_PMCEID0_EL0, CGT_MDCR_TPM), SR_TRAP(SYS_PMCEID1_EL0, CGT_MDCR_TPM), - SR_TRAP(SYS_PMXEVTYPER_EL0, CGT_MDCR_TPM), + SR_TRAP(SYS_PMXEVTYPER_EL0, CGT_MDCR_TPM_HPMN), SR_TRAP(SYS_PMSWINC_EL0, CGT_MDCR_TPM), SR_TRAP(SYS_PMSELR_EL0, CGT_MDCR_TPM), - SR_TRAP(SYS_PMXEVCNTR_EL0, CGT_MDCR_TPM), + SR_TRAP(SYS_PMXEVCNTR_EL0, CGT_MDCR_TPM_HPMN), SR_TRAP(SYS_PMCCNTR_EL0, CGT_MDCR_TPM), SR_TRAP(SYS_PMUSERENR_EL0, CGT_MDCR_TPM), SR_TRAP(SYS_PMINTENSET_EL1, CGT_MDCR_TPM), SR_TRAP(SYS_PMINTENCLR_EL1, CGT_MDCR_TPM), SR_TRAP(SYS_PMMIR_EL1, CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(0), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(1), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(2), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(3), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(4), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(5), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(6), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(7), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(8), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(9), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(10), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(11), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(12), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(13), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(14), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(15), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(16), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(17), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(18), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(19), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(20), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(21), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(22), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(23), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(24), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(25), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(26), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(27), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(28), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(29), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVCNTRn_EL0(30), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(0), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(1), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(2), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(3), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(4), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(5), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(6), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(7), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(8), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(9), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(10), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(11), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(12), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(13), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(14), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(15), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(16), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(17), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(18), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(19), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(20), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(21), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(22), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(23), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(24), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(25), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(26), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(27), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(28), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(29), CGT_MDCR_TPM), - SR_TRAP(SYS_PMEVTYPERn_EL0(30), CGT_MDCR_TPM), + SR_TRAP(SYS_PMEVCNTRn_EL0(0), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(1), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(2), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(3), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(4), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(5), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(6), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(7), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(8), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(9), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(10), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(11), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(12), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(13), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(14), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(15), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(16), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(17), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(18), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(19), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(20), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(21), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(22), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(23), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(24), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(25), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(26), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(27), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(28), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(29), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVCNTRn_EL0(30), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(0), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(1), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(2), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(3), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(4), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(5), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(6), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(7), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(8), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(9), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(10), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(11), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(12), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(13), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(14), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(15), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(16), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(17), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(18), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(19), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(20), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(21), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(22), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(23), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(24), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(25), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(26), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(27), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(28), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(29), CGT_MDCR_TPM_HPMN), + SR_TRAP(SYS_PMEVTYPERn_EL0(30), CGT_MDCR_TPM_HPMN), SR_TRAP(SYS_PMCCFILTR_EL0, CGT_MDCR_TPM), SR_TRAP(SYS_MDCCSR_EL0, CGT_MDCR_TDCC_TDE_TDA), SR_TRAP(SYS_MDCCINT_EL1, CGT_MDCR_TDCC_TDE_TDA), @@ -1141,7 +1176,6 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = { SR_TRAP(SYS_AMEVTYPER1_EL0(13), CGT_CPTR_TAM), SR_TRAP(SYS_AMEVTYPER1_EL0(14), CGT_CPTR_TAM), SR_TRAP(SYS_AMEVTYPER1_EL0(15), CGT_CPTR_TAM), - SR_TRAP(SYS_POR_EL0, CGT_CPACR_E0POE), /* op0=2, op1=1, and CRn<0b1000 */ SR_RANGE_TRAP(sys_reg(2, 1, 0, 0, 0), sys_reg(2, 1, 7, 15, 7), CGT_CPTR_TTA), @@ -2021,7 +2055,8 @@ int __init populate_nv_trap_config(void) cgids = coarse_control_combo[id - __MULTIPLE_CONTROL_BITS__]; for (int i = 0; cgids[i] != __RESERVED__; i++) { - if (cgids[i] >= __MULTIPLE_CONTROL_BITS__) { + if (cgids[i] >= __MULTIPLE_CONTROL_BITS__ && + cgids[i] < __COMPLEX_CONDITIONS__) { kvm_err("Recursive MCB %d/%d\n", id, cgids[i]); ret = -EINVAL; } @@ -2126,11 +2161,19 @@ static u64 kvm_get_sysreg_res0(struct kvm *kvm, enum vcpu_sysreg sr) return masks->mask[sr - __VNCR_START__].res0; } -static bool check_fgt_bit(struct kvm *kvm, bool is_read, +static bool check_fgt_bit(struct kvm_vcpu *vcpu, bool is_read, u64 val, const union trap_config tc) { + struct kvm *kvm = vcpu->kvm; enum vcpu_sysreg sr; + /* + * KVM doesn't know about any FGTs that apply to the host, and hopefully + * that'll remain the case. + */ + if (is_hyp_ctxt(vcpu)) + return false; + if (tc.pol) return (val & BIT(tc.bit)); @@ -2207,7 +2250,15 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index) * If we're not nesting, immediately return to the caller, with the * sysreg index, should we have it. */ - if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu)) + if (!vcpu_has_nv(vcpu)) + goto local; + + /* + * There are a few traps that take effect InHost, but are constrained + * to EL0. Don't bother with computing the trap behaviour if the vCPU + * isn't in EL0. + */ + if (is_hyp_ctxt(vcpu) && !vcpu_is_host_el0(vcpu)) goto local; switch ((enum fgt_group_id)tc.fgt) { @@ -2253,12 +2304,14 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index) goto local; } - if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(vcpu->kvm, is_read, - val, tc)) + if (tc.fgt != __NO_FGT_GROUP__ && check_fgt_bit(vcpu, is_read, val, tc)) goto inject; b = compute_trap_behaviour(vcpu, tc); + if (!(b & BEHAVE_FORWARD_IN_HOST_EL0) && vcpu_is_host_el0(vcpu)) + goto local; + if (((b & BEHAVE_FORWARD_READ) && is_read) || ((b & BEHAVE_FORWARD_WRITE) && !is_read)) goto inject; @@ -2393,6 +2446,8 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu) kvm_arch_vcpu_load(vcpu, smp_processor_id()); preempt_enable(); + + kvm_pmu_nested_transition(vcpu); } static void kvm_inject_el2_exception(struct kvm_vcpu *vcpu, u64 esr_el2, @@ -2475,6 +2530,8 @@ static int kvm_inject_nested(struct kvm_vcpu *vcpu, u64 esr_el2, kvm_arch_vcpu_load(vcpu, smp_processor_id()); preempt_enable(); + kvm_pmu_nested_transition(vcpu); + return 1; } diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 962f985977c2d7..12dad841f2a512 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -1051,50 +1051,58 @@ int kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, } while (length > 0) { - kvm_pfn_t pfn = gfn_to_pfn_prot(kvm, gfn, write, NULL); + struct page *page = __gfn_to_page(kvm, gfn, write); void *maddr; unsigned long num_tags; - struct page *page; + struct folio *folio; - if (is_error_noslot_pfn(pfn)) { + if (!page) { ret = -EFAULT; goto out; } - page = pfn_to_online_page(pfn); - if (!page) { + if (!pfn_to_online_page(page_to_pfn(page))) { /* Reject ZONE_DEVICE memory */ - kvm_release_pfn_clean(pfn); + kvm_release_page_unused(page); ret = -EFAULT; goto out; } + folio = page_folio(page); maddr = page_address(page); if (!write) { - if (page_mte_tagged(page)) + if ((folio_test_hugetlb(folio) && + folio_test_hugetlb_mte_tagged(folio)) || + page_mte_tagged(page)) num_tags = mte_copy_tags_to_user(tags, maddr, MTE_GRANULES_PER_PAGE); else /* No tags in memory, so write zeros */ num_tags = MTE_GRANULES_PER_PAGE - clear_user(tags, MTE_GRANULES_PER_PAGE); - kvm_release_pfn_clean(pfn); + kvm_release_page_clean(page); } else { /* * Only locking to serialise with a concurrent * __set_ptes() in the VMM but still overriding the * tags, hence ignoring the return value. */ - try_page_mte_tagging(page); + if (folio_test_hugetlb(folio)) + folio_try_hugetlb_mte_tagging(folio); + else + try_page_mte_tagging(page); num_tags = mte_copy_tags_from_user(maddr, tags, MTE_GRANULES_PER_PAGE); /* uaccess failed, don't leave stale tags */ if (num_tags != MTE_GRANULES_PER_PAGE) mte_clear_page_tags(maddr); - set_page_mte_tagged(page); + if (folio_test_hugetlb(folio)) + folio_set_hugetlb_mte_tagged(folio); + else + set_page_mte_tagged(page); - kvm_release_pfn_dirty(pfn); + kvm_release_page_dirty(page); } if (num_tags != MTE_GRANULES_PER_PAGE) { diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index 5310fe1da6165b..34f53707892dfe 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -204,6 +204,35 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu) __deactivate_fgt(hctxt, vcpu, kvm, HAFGRTR_EL2); } +static inline void __activate_traps_mpam(struct kvm_vcpu *vcpu) +{ + u64 r = MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1; + + if (!system_supports_mpam()) + return; + + /* trap guest access to MPAMIDR_EL1 */ + if (system_supports_mpam_hcr()) { + write_sysreg_s(MPAMHCR_EL2_TRAP_MPAMIDR_EL1, SYS_MPAMHCR_EL2); + } else { + /* From v1.1 TIDR can trap MPAMIDR, set it unconditionally */ + r |= MPAM2_EL2_TIDR; + } + + write_sysreg_s(r, SYS_MPAM2_EL2); +} + +static inline void __deactivate_traps_mpam(void) +{ + if (!system_supports_mpam()) + return; + + write_sysreg_s(0, SYS_MPAM2_EL2); + + if (system_supports_mpam_hcr()) + write_sysreg_s(MPAMHCR_HOST_FLAGS, SYS_MPAMHCR_EL2); +} + static inline void __activate_traps_common(struct kvm_vcpu *vcpu) { /* Trap on AArch32 cp15 c15 (impdef sysregs) accesses (EL1 or EL0) */ @@ -244,6 +273,7 @@ static inline void __activate_traps_common(struct kvm_vcpu *vcpu) } __activate_traps_hfgxtr(vcpu); + __activate_traps_mpam(vcpu); } static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu) @@ -263,6 +293,7 @@ static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu) write_sysreg_s(HCRX_HOST_FLAGS, SYS_HCRX_EL2); __deactivate_traps_hfgxtr(vcpu); + __deactivate_traps_mpam(); } static inline void ___activate_traps(struct kvm_vcpu *vcpu, u64 hcr) diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h index 1579a3c08a36b9..a651c43ad679fc 100644 --- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h @@ -58,7 +58,7 @@ static inline bool ctxt_has_s1pie(struct kvm_cpu_context *ctxt) return false; vcpu = ctxt_to_vcpu(ctxt); - return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, S1PIE, IMP); + return kvm_has_s1pie(kern_hyp_va(vcpu->kvm)); } static inline bool ctxt_has_tcrx(struct kvm_cpu_context *ctxt) @@ -69,7 +69,7 @@ static inline bool ctxt_has_tcrx(struct kvm_cpu_context *ctxt) return false; vcpu = ctxt_to_vcpu(ctxt); - return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, TCRX, IMP); + return kvm_has_tcr2(kern_hyp_va(vcpu->kvm)); } static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt) @@ -80,7 +80,7 @@ static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt) return false; vcpu = ctxt_to_vcpu(ctxt); - return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, S1POE, IMP); + return kvm_has_s1poe(kern_hyp_va(vcpu->kvm)); } static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt) @@ -152,9 +152,10 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt) write_sysreg(ctxt_sys_reg(ctxt, TPIDRRO_EL0), tpidrro_el0); } -static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt) +static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt, + u64 mpidr) { - write_sysreg(ctxt_sys_reg(ctxt, MPIDR_EL1), vmpidr_el2); + write_sysreg(mpidr, vmpidr_el2); if (has_vhe() || !cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) { diff --git a/arch/arm64/kvm/hyp/include/nvhe/trap_handler.h b/arch/arm64/kvm/hyp/include/nvhe/trap_handler.h index 45a84f0ade04bd..1e6d995968a1fb 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/trap_handler.h +++ b/arch/arm64/kvm/hyp/include/nvhe/trap_handler.h @@ -15,6 +15,4 @@ #define DECLARE_REG(type, name, ctxt, reg) \ type name = (type)cpu_reg(ctxt, (reg)) -void __pkvm_vcpu_init_traps(struct kvm_vcpu *vcpu); - #endif /* __ARM64_KVM_NVHE_TRAP_HANDLER_H__ */ diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index fefc89209f9e41..6aa0b13d86e581 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -105,8 +105,10 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) hyp_vcpu->vcpu.arch.hw_mmu = host_vcpu->arch.hw_mmu; - hyp_vcpu->vcpu.arch.hcr_el2 = host_vcpu->arch.hcr_el2; hyp_vcpu->vcpu.arch.mdcr_el2 = host_vcpu->arch.mdcr_el2; + hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWI | HCR_TWE); + hyp_vcpu->vcpu.arch.hcr_el2 |= READ_ONCE(host_vcpu->arch.hcr_el2) & + (HCR_TWI | HCR_TWE); hyp_vcpu->vcpu.arch.iflags = host_vcpu->arch.iflags; @@ -349,13 +351,6 @@ static void handle___pkvm_prot_finalize(struct kvm_cpu_context *host_ctxt) cpu_reg(host_ctxt, 1) = __pkvm_prot_finalize(); } -static void handle___pkvm_vcpu_init_traps(struct kvm_cpu_context *host_ctxt) -{ - DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1); - - __pkvm_vcpu_init_traps(kern_hyp_va(vcpu)); -} - static void handle___pkvm_init_vm(struct kvm_cpu_context *host_ctxt) { DECLARE_REG(struct kvm *, host_kvm, host_ctxt, 1); @@ -411,7 +406,6 @@ static const hcall_t host_hcall[] = { HANDLE_FUNC(__kvm_timer_set_cntvoff), HANDLE_FUNC(__vgic_v3_save_vmcr_aprs), HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs), - HANDLE_FUNC(__pkvm_vcpu_init_traps), HANDLE_FUNC(__pkvm_init_vm), HANDLE_FUNC(__pkvm_init_vcpu), HANDLE_FUNC(__pkvm_teardown_vm), diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 077d4098548d2c..071993c16de81c 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -6,6 +6,9 @@ #include #include + +#include + #include #include #include @@ -123,7 +126,7 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu) /* Trap SPE */ if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMSVer), feature_ids)) { mdcr_set |= MDCR_EL2_TPMS; - mdcr_clear |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT; + mdcr_clear |= MDCR_EL2_E2PB_MASK; } /* Trap Trace Filter */ @@ -140,7 +143,7 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu) /* Trap External Trace */ if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_ExtTrcBuff), feature_ids)) - mdcr_clear |= MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT; + mdcr_clear |= MDCR_EL2_E2TB_MASK; vcpu->arch.mdcr_el2 |= mdcr_set; vcpu->arch.mdcr_el2 &= ~mdcr_clear; @@ -201,11 +204,46 @@ static void pvm_init_trap_regs(struct kvm_vcpu *vcpu) } } +static void pkvm_vcpu_reset_hcr(struct kvm_vcpu *vcpu) +{ + vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS; + + if (has_hvhe()) + vcpu->arch.hcr_el2 |= HCR_E2H; + + if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN)) { + /* route synchronous external abort exceptions to EL2 */ + vcpu->arch.hcr_el2 |= HCR_TEA; + /* trap error record accesses */ + vcpu->arch.hcr_el2 |= HCR_TERR; + } + + if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB)) + vcpu->arch.hcr_el2 |= HCR_FWB; + + if (cpus_have_final_cap(ARM64_HAS_EVT) && + !cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE)) + vcpu->arch.hcr_el2 |= HCR_TID4; + else + vcpu->arch.hcr_el2 |= HCR_TID2; + + if (vcpu_has_ptrauth(vcpu)) + vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK); +} + /* * Initialize trap register values in protected mode. */ -void __pkvm_vcpu_init_traps(struct kvm_vcpu *vcpu) +static void pkvm_vcpu_init_traps(struct kvm_vcpu *vcpu) { + vcpu->arch.cptr_el2 = kvm_get_reset_cptr_el2(vcpu); + vcpu->arch.mdcr_el2 = 0; + + pkvm_vcpu_reset_hcr(vcpu); + + if ((!vcpu_is_protected(vcpu))) + return; + pvm_init_trap_regs(vcpu); pvm_init_traps_aa64pfr0(vcpu); pvm_init_traps_aa64pfr1(vcpu); @@ -289,6 +327,65 @@ void pkvm_put_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) hyp_spin_unlock(&vm_table_lock); } +static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struct kvm *host_kvm) +{ + struct kvm *kvm = &hyp_vm->kvm; + DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES); + + /* No restrictions for non-protected VMs. */ + if (!kvm_vm_is_protected(kvm)) { + bitmap_copy(kvm->arch.vcpu_features, + host_kvm->arch.vcpu_features, + KVM_VCPU_MAX_FEATURES); + return; + } + + bitmap_zero(allowed_features, KVM_VCPU_MAX_FEATURES); + + /* + * For protected VMs, always allow: + * - CPU starting in poweroff state + * - PSCI v0.2 + */ + set_bit(KVM_ARM_VCPU_POWER_OFF, allowed_features); + set_bit(KVM_ARM_VCPU_PSCI_0_2, allowed_features); + + /* + * Check if remaining features are allowed: + * - Performance Monitoring + * - Scalable Vectors + * - Pointer Authentication + */ + if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_PMUVer), PVM_ID_AA64DFR0_ALLOW)) + set_bit(KVM_ARM_VCPU_PMU_V3, allowed_features); + + if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR0_EL1_SVE), PVM_ID_AA64PFR0_ALLOW)) + set_bit(KVM_ARM_VCPU_SVE, allowed_features); + + if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API), PVM_ID_AA64ISAR1_RESTRICT_UNSIGNED) && + FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA), PVM_ID_AA64ISAR1_RESTRICT_UNSIGNED)) + set_bit(KVM_ARM_VCPU_PTRAUTH_ADDRESS, allowed_features); + + if (FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI), PVM_ID_AA64ISAR1_ALLOW) && + FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA), PVM_ID_AA64ISAR1_ALLOW)) + set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features); + + bitmap_and(kvm->arch.vcpu_features, host_kvm->arch.vcpu_features, + allowed_features, KVM_VCPU_MAX_FEATURES); +} + +static void pkvm_vcpu_init_ptrauth(struct pkvm_hyp_vcpu *hyp_vcpu) +{ + struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu; + + if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_PTRAUTH_ADDRESS) || + vcpu_has_feature(vcpu, KVM_ARM_VCPU_PTRAUTH_GENERIC)) { + kvm_vcpu_enable_ptrauth(vcpu); + } else { + vcpu_clear_flag(&hyp_vcpu->vcpu, GUEST_HAS_PTRAUTH); + } +} + static void unpin_host_vcpu(struct kvm_vcpu *host_vcpu) { if (host_vcpu) @@ -310,6 +407,18 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm, hyp_vm->host_kvm = host_kvm; hyp_vm->kvm.created_vcpus = nr_vcpus; hyp_vm->kvm.arch.mmu.vtcr = host_mmu.arch.mmu.vtcr; + hyp_vm->kvm.arch.pkvm.enabled = READ_ONCE(host_kvm->arch.pkvm.enabled); + pkvm_init_features_from_host(hyp_vm, host_kvm); +} + +static void pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *host_vcpu) +{ + struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu; + + if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) { + vcpu_clear_flag(vcpu, GUEST_HAS_SVE); + vcpu_clear_flag(vcpu, VCPU_SVE_FINALIZED); + } } static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, @@ -335,6 +444,11 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, hyp_vcpu->vcpu.arch.hw_mmu = &hyp_vm->kvm.arch.mmu; hyp_vcpu->vcpu.arch.cflags = READ_ONCE(host_vcpu->arch.cflags); + hyp_vcpu->vcpu.arch.mp_state.mp_state = KVM_MP_STATE_STOPPED; + + pkvm_vcpu_init_sve(hyp_vcpu, host_vcpu); + pkvm_vcpu_init_ptrauth(hyp_vcpu); + pkvm_vcpu_init_traps(&hyp_vcpu->vcpu); done: if (ret) unpin_host_vcpu(host_vcpu); diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c index dfe8fe0f7eaff0..9c2ce1e0e99a55 100644 --- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c +++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c @@ -265,6 +265,8 @@ static unsigned long psci_1_0_handler(u64 func_id, struct kvm_cpu_context *host_ case PSCI_1_0_FN_PSCI_FEATURES: case PSCI_1_0_FN_SET_SUSPEND_MODE: case PSCI_1_1_FN64_SYSTEM_RESET2: + case PSCI_1_3_FN_SYSTEM_OFF2: + case PSCI_1_3_FN64_SYSTEM_OFF2: return psci_forward(host_ctxt); case PSCI_1_0_FN64_SYSTEM_SUSPEND: return psci_system_suspend(func_id, host_ctxt); diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index 174007f3faddd9..cbdd18cd3f9843 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -95,7 +95,6 @@ static int recreate_hyp_mappings(phys_addr_t phys, unsigned long size, { void *start, *end, *virt = hyp_phys_to_virt(phys); unsigned long pgt_size = hyp_s1_pgtable_pages() << PAGE_SHIFT; - enum kvm_pgtable_prot prot; int ret, i; /* Recreate the hyp page-table using the early page allocator */ @@ -147,24 +146,7 @@ static int recreate_hyp_mappings(phys_addr_t phys, unsigned long size, return ret; } - pkvm_create_host_sve_mappings(); - - /* - * Map the host sections RO in the hypervisor, but transfer the - * ownership from the host to the hypervisor itself to make sure they - * can't be donated or shared with another entity. - * - * The ownership transition requires matching changes in the host - * stage-2. This will be done later (see finalize_host_mappings()) once - * the hyp_vmemmap is addressable. - */ - prot = pkvm_mkstate(PAGE_HYP_RO, PKVM_PAGE_SHARED_OWNED); - ret = pkvm_create_mappings(&kvm_vgic_global_state, - &kvm_vgic_global_state + 1, prot); - if (ret) - return ret; - - return 0; + return pkvm_create_host_sve_mappings(); } static void update_nvhe_init_params(void) diff --git a/arch/arm64/kvm/hyp/nvhe/sysreg-sr.c b/arch/arm64/kvm/hyp/nvhe/sysreg-sr.c index 29305022bc048f..dba101565de367 100644 --- a/arch/arm64/kvm/hyp/nvhe/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/nvhe/sysreg-sr.c @@ -28,7 +28,7 @@ void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt) void __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt) { - __sysreg_restore_el1_state(ctxt); + __sysreg_restore_el1_state(ctxt, ctxt_sys_reg(ctxt, MPIDR_EL1)); __sysreg_restore_common_state(ctxt); __sysreg_restore_user_state(ctxt); __sysreg_restore_el2_return_state(ctxt); diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index b11bcebac908a7..40bd559665404d 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -1245,19 +1245,16 @@ int kvm_pgtable_stage2_wrprotect(struct kvm_pgtable *pgt, u64 addr, u64 size) NULL, NULL, 0); } -kvm_pte_t kvm_pgtable_stage2_mkyoung(struct kvm_pgtable *pgt, u64 addr) +void kvm_pgtable_stage2_mkyoung(struct kvm_pgtable *pgt, u64 addr) { - kvm_pte_t pte = 0; int ret; ret = stage2_update_leaf_attrs(pgt, addr, 1, KVM_PTE_LEAF_ATTR_LO_S2_AF, 0, - &pte, NULL, + NULL, NULL, KVM_PGTABLE_WALK_HANDLE_FAULT | KVM_PGTABLE_WALK_SHARED); if (!ret) dsb(ishst); - - return pte; } struct stage2_age_data { diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c index 18d4677002b1a6..3f9741e51d41bf 100644 --- a/arch/arm64/kvm/hyp/vgic-v3-sr.c +++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c @@ -1012,9 +1012,6 @@ static void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT; /* IDbits */ val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT; - /* SEIS */ - if (kvm_vgic_global_state.ich_vtr_el2 & ICH_VTR_SEIS_MASK) - val |= BIT(ICC_CTLR_EL1_SEIS_SHIFT); /* A3V */ val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT; /* EOImode */ diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c index e12bd7d6d2dcef..5f78a39053a793 100644 --- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c @@ -15,6 +15,131 @@ #include #include +static void __sysreg_save_vel2_state(struct kvm_vcpu *vcpu) +{ + /* These registers are common with EL1 */ + __vcpu_sys_reg(vcpu, PAR_EL1) = read_sysreg(par_el1); + __vcpu_sys_reg(vcpu, TPIDR_EL1) = read_sysreg(tpidr_el1); + + __vcpu_sys_reg(vcpu, ESR_EL2) = read_sysreg_el1(SYS_ESR); + __vcpu_sys_reg(vcpu, AFSR0_EL2) = read_sysreg_el1(SYS_AFSR0); + __vcpu_sys_reg(vcpu, AFSR1_EL2) = read_sysreg_el1(SYS_AFSR1); + __vcpu_sys_reg(vcpu, FAR_EL2) = read_sysreg_el1(SYS_FAR); + __vcpu_sys_reg(vcpu, MAIR_EL2) = read_sysreg_el1(SYS_MAIR); + __vcpu_sys_reg(vcpu, VBAR_EL2) = read_sysreg_el1(SYS_VBAR); + __vcpu_sys_reg(vcpu, CONTEXTIDR_EL2) = read_sysreg_el1(SYS_CONTEXTIDR); + __vcpu_sys_reg(vcpu, AMAIR_EL2) = read_sysreg_el1(SYS_AMAIR); + + /* + * In VHE mode those registers are compatible between EL1 and EL2, + * and the guest uses the _EL1 versions on the CPU naturally. + * So we save them into their _EL2 versions here. + * For nVHE mode we trap accesses to those registers, so our + * _EL2 copy in sys_regs[] is always up-to-date and we don't need + * to save anything here. + */ + if (vcpu_el2_e2h_is_set(vcpu)) { + u64 val; + + /* + * We don't save CPTR_EL2, as accesses to CPACR_EL1 + * are always trapped, ensuring that the in-memory + * copy is always up-to-date. A small blessing... + */ + __vcpu_sys_reg(vcpu, SCTLR_EL2) = read_sysreg_el1(SYS_SCTLR); + __vcpu_sys_reg(vcpu, TTBR0_EL2) = read_sysreg_el1(SYS_TTBR0); + __vcpu_sys_reg(vcpu, TTBR1_EL2) = read_sysreg_el1(SYS_TTBR1); + __vcpu_sys_reg(vcpu, TCR_EL2) = read_sysreg_el1(SYS_TCR); + + if (ctxt_has_tcrx(&vcpu->arch.ctxt)) { + __vcpu_sys_reg(vcpu, TCR2_EL2) = read_sysreg_el1(SYS_TCR2); + + if (ctxt_has_s1pie(&vcpu->arch.ctxt)) { + __vcpu_sys_reg(vcpu, PIRE0_EL2) = read_sysreg_el1(SYS_PIRE0); + __vcpu_sys_reg(vcpu, PIR_EL2) = read_sysreg_el1(SYS_PIR); + } + + if (ctxt_has_s1poe(&vcpu->arch.ctxt)) + __vcpu_sys_reg(vcpu, POR_EL2) = read_sysreg_el1(SYS_POR); + } + + /* + * The EL1 view of CNTKCTL_EL1 has a bunch of RES0 bits where + * the interesting CNTHCTL_EL2 bits live. So preserve these + * bits when reading back the guest-visible value. + */ + val = read_sysreg_el1(SYS_CNTKCTL); + val &= CNTKCTL_VALID_BITS; + __vcpu_sys_reg(vcpu, CNTHCTL_EL2) &= ~CNTKCTL_VALID_BITS; + __vcpu_sys_reg(vcpu, CNTHCTL_EL2) |= val; + } + + __vcpu_sys_reg(vcpu, SP_EL2) = read_sysreg(sp_el1); + __vcpu_sys_reg(vcpu, ELR_EL2) = read_sysreg_el1(SYS_ELR); + __vcpu_sys_reg(vcpu, SPSR_EL2) = read_sysreg_el1(SYS_SPSR); +} + +static void __sysreg_restore_vel2_state(struct kvm_vcpu *vcpu) +{ + u64 val; + + /* These registers are common with EL1 */ + write_sysreg(__vcpu_sys_reg(vcpu, PAR_EL1), par_el1); + write_sysreg(__vcpu_sys_reg(vcpu, TPIDR_EL1), tpidr_el1); + + write_sysreg(__vcpu_sys_reg(vcpu, MPIDR_EL1), vmpidr_el2); + write_sysreg_el1(__vcpu_sys_reg(vcpu, MAIR_EL2), SYS_MAIR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, VBAR_EL2), SYS_VBAR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, CONTEXTIDR_EL2), SYS_CONTEXTIDR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, AMAIR_EL2), SYS_AMAIR); + + if (vcpu_el2_e2h_is_set(vcpu)) { + /* + * In VHE mode those registers are compatible between + * EL1 and EL2. + */ + write_sysreg_el1(__vcpu_sys_reg(vcpu, SCTLR_EL2), SYS_SCTLR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, CPTR_EL2), SYS_CPACR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, TTBR0_EL2), SYS_TTBR0); + write_sysreg_el1(__vcpu_sys_reg(vcpu, TTBR1_EL2), SYS_TTBR1); + write_sysreg_el1(__vcpu_sys_reg(vcpu, TCR_EL2), SYS_TCR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, CNTHCTL_EL2), SYS_CNTKCTL); + } else { + /* + * CNTHCTL_EL2 only affects EL1 when running nVHE, so + * no need to restore it. + */ + val = translate_sctlr_el2_to_sctlr_el1(__vcpu_sys_reg(vcpu, SCTLR_EL2)); + write_sysreg_el1(val, SYS_SCTLR); + val = translate_cptr_el2_to_cpacr_el1(__vcpu_sys_reg(vcpu, CPTR_EL2)); + write_sysreg_el1(val, SYS_CPACR); + val = translate_ttbr0_el2_to_ttbr0_el1(__vcpu_sys_reg(vcpu, TTBR0_EL2)); + write_sysreg_el1(val, SYS_TTBR0); + val = translate_tcr_el2_to_tcr_el1(__vcpu_sys_reg(vcpu, TCR_EL2)); + write_sysreg_el1(val, SYS_TCR); + } + + if (ctxt_has_tcrx(&vcpu->arch.ctxt)) { + write_sysreg_el1(__vcpu_sys_reg(vcpu, TCR2_EL2), SYS_TCR2); + + if (ctxt_has_s1pie(&vcpu->arch.ctxt)) { + write_sysreg_el1(__vcpu_sys_reg(vcpu, PIR_EL2), SYS_PIR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, PIRE0_EL2), SYS_PIRE0); + } + + if (ctxt_has_s1poe(&vcpu->arch.ctxt)) + write_sysreg_el1(__vcpu_sys_reg(vcpu, POR_EL2), SYS_POR); + } + + write_sysreg_el1(__vcpu_sys_reg(vcpu, ESR_EL2), SYS_ESR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, AFSR0_EL2), SYS_AFSR0); + write_sysreg_el1(__vcpu_sys_reg(vcpu, AFSR1_EL2), SYS_AFSR1); + write_sysreg_el1(__vcpu_sys_reg(vcpu, FAR_EL2), SYS_FAR); + write_sysreg(__vcpu_sys_reg(vcpu, SP_EL2), sp_el1); + write_sysreg_el1(__vcpu_sys_reg(vcpu, ELR_EL2), SYS_ELR); + write_sysreg_el1(__vcpu_sys_reg(vcpu, SPSR_EL2), SYS_SPSR); +} + /* * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and * pstate, which are handled as part of the el2 return state) on every @@ -66,6 +191,7 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu) { struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt; struct kvm_cpu_context *host_ctxt; + u64 mpidr; host_ctxt = host_data_ptr(host_ctxt); __sysreg_save_user_state(host_ctxt); @@ -89,7 +215,29 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu) */ __sysreg32_restore_state(vcpu); __sysreg_restore_user_state(guest_ctxt); - __sysreg_restore_el1_state(guest_ctxt); + + if (unlikely(__is_hyp_ctxt(guest_ctxt))) { + __sysreg_restore_vel2_state(vcpu); + } else { + if (vcpu_has_nv(vcpu)) { + /* + * Use the guest hypervisor's VPIDR_EL2 when in a + * nested state. The hardware value of MIDR_EL1 gets + * restored on put. + */ + write_sysreg(ctxt_sys_reg(guest_ctxt, VPIDR_EL2), vpidr_el2); + + /* + * As we're restoring a nested guest, set the value + * provided by the guest hypervisor. + */ + mpidr = ctxt_sys_reg(guest_ctxt, VMPIDR_EL2); + } else { + mpidr = ctxt_sys_reg(guest_ctxt, MPIDR_EL1); + } + + __sysreg_restore_el1_state(guest_ctxt, mpidr); + } vcpu_set_flag(vcpu, SYSREGS_ON_CPU); } @@ -112,12 +260,20 @@ void __vcpu_put_switch_sysregs(struct kvm_vcpu *vcpu) host_ctxt = host_data_ptr(host_ctxt); - __sysreg_save_el1_state(guest_ctxt); + if (unlikely(__is_hyp_ctxt(guest_ctxt))) + __sysreg_save_vel2_state(vcpu); + else + __sysreg_save_el1_state(guest_ctxt); + __sysreg_save_user_state(guest_ctxt); __sysreg32_save_state(vcpu); /* Restore host user state */ __sysreg_restore_user_state(host_ctxt); + /* If leaving a nesting guest, restore MIDR_EL1 default view */ + if (vcpu_has_nv(vcpu)) + write_sysreg(read_cpuid_id(), vpidr_el2); + vcpu_clear_flag(vcpu, SYSREGS_ON_CPU); } diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index ee6573befb8134..27ce4cb449049d 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -575,6 +575,8 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) case KVM_ARM_PSCI_0_2: case KVM_ARM_PSCI_1_0: case KVM_ARM_PSCI_1_1: + case KVM_ARM_PSCI_1_2: + case KVM_ARM_PSCI_1_3: if (!wants_02) return -EINVAL; vcpu->kvm->arch.psci_version = val; diff --git a/arch/arm64/kvm/mmio.c b/arch/arm64/kvm/mmio.c index cd6b7b83e2c370..ab365e839874e5 100644 --- a/arch/arm64/kvm/mmio.c +++ b/arch/arm64/kvm/mmio.c @@ -72,6 +72,31 @@ unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len) return data; } +static bool kvm_pending_sync_exception(struct kvm_vcpu *vcpu) +{ + if (!vcpu_get_flag(vcpu, PENDING_EXCEPTION)) + return false; + + if (vcpu_el1_is_32bit(vcpu)) { + switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) { + case unpack_vcpu_flag(EXCEPT_AA32_UND): + case unpack_vcpu_flag(EXCEPT_AA32_IABT): + case unpack_vcpu_flag(EXCEPT_AA32_DABT): + return true; + default: + return false; + } + } else { + switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) { + case unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC): + case unpack_vcpu_flag(EXCEPT_AA64_EL2_SYNC): + return true; + default: + return false; + } + } +} + /** * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation * or in-kernel IO emulation @@ -84,8 +109,11 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu) unsigned int len; int mask; - /* Detect an already handled MMIO return */ - if (unlikely(!vcpu->mmio_needed)) + /* + * Detect if the MMIO return was already handled or if userspace aborted + * the MMIO access. + */ + if (unlikely(!vcpu->mmio_needed || kvm_pending_sync_exception(vcpu))) return 1; vcpu->mmio_needed = 0; diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 0f7658aefa1a3d..c9d46ad57e52d3 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1402,10 +1402,21 @@ static void sanitise_mte_tags(struct kvm *kvm, kvm_pfn_t pfn, { unsigned long i, nr_pages = size >> PAGE_SHIFT; struct page *page = pfn_to_page(pfn); + struct folio *folio = page_folio(page); if (!kvm_has_mte(kvm)) return; + if (folio_test_hugetlb(folio)) { + /* Hugetlb has MTE flags set on head page only */ + if (folio_try_hugetlb_mte_tagging(folio)) { + for (i = 0; i < nr_pages; i++, page++) + mte_clear_page_tags(page_address(page)); + folio_set_hugetlb_mte_tagged(folio); + } + return; + } + for (i = 0; i < nr_pages; i++, page++) { if (try_page_mte_tagging(page)) { mte_clear_page_tags(page_address(page)); @@ -1440,6 +1451,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, long vma_pagesize, fault_granule; enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R; struct kvm_pgtable *pgt; + struct page *page; if (fault_is_perm) fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu); @@ -1561,7 +1573,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, /* * Read mmu_invalidate_seq so that KVM can detect if the results of - * vma_lookup() or __gfn_to_pfn_memslot() become stale prior to + * vma_lookup() or __kvm_faultin_pfn() become stale prior to * acquiring kvm->mmu_lock. * * Rely on mmap_read_unlock() for an implicit smp_rmb(), which pairs @@ -1570,8 +1582,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, mmu_seq = vcpu->kvm->mmu_invalidate_seq; mmap_read_unlock(current->mm); - pfn = __gfn_to_pfn_memslot(memslot, gfn, false, false, NULL, - write_fault, &writable, NULL); + pfn = __kvm_faultin_pfn(memslot, gfn, write_fault ? FOLL_WRITE : 0, + &writable, &page); if (pfn == KVM_PFN_ERR_HWPOISON) { kvm_send_hwpoison_signal(hva, vma_shift); return 0; @@ -1584,7 +1596,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, * If the page was identified as device early by looking at * the VMA flags, vma_pagesize is already representing the * largest quantity we can map. If instead it was mapped - * via gfn_to_pfn_prot(), vma_pagesize is set to PAGE_SIZE + * via __kvm_faultin_pfn(), vma_pagesize is set to PAGE_SIZE * and must not be upgraded. * * In both cases, we don't let transparent_hugepage_adjust() @@ -1693,33 +1705,27 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, } out_unlock: + kvm_release_faultin_page(kvm, page, !!ret, writable); read_unlock(&kvm->mmu_lock); /* Mark the page dirty only if the fault is handled successfully */ - if (writable && !ret) { - kvm_set_pfn_dirty(pfn); + if (writable && !ret) mark_page_dirty_in_slot(kvm, memslot, gfn); - } - kvm_release_pfn_clean(pfn); return ret != -EAGAIN ? ret : 0; } /* Resolve the access fault by making the page young again. */ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) { - kvm_pte_t pte; struct kvm_s2_mmu *mmu; trace_kvm_access_fault(fault_ipa); read_lock(&vcpu->kvm->mmu_lock); mmu = vcpu->arch.hw_mmu; - pte = kvm_pgtable_stage2_mkyoung(mmu->pgt, fault_ipa); + kvm_pgtable_stage2_mkyoung(mmu->pgt, fault_ipa); read_unlock(&vcpu->kvm->mmu_lock); - - if (kvm_pte_valid(pte)) - kvm_set_pfn_accessed(kvm_pte_to_pfn(pte)); } /** diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index c4b17d90fc49d6..9b36218b48def4 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -917,12 +917,13 @@ static void limit_nv_id_regs(struct kvm *kvm) ID_AA64MMFR4_EL1_E2H0_NI_NV1); kvm_set_vm_id_reg(kvm, SYS_ID_AA64MMFR4_EL1, val); - /* Only limited support for PMU, Debug, BPs and WPs */ + /* Only limited support for PMU, Debug, BPs, WPs, and HPMN0 */ val = kvm_read_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1); val &= (NV_FTR(DFR0, PMUVer) | NV_FTR(DFR0, WRPs) | NV_FTR(DFR0, BRPs) | - NV_FTR(DFR0, DebugVer)); + NV_FTR(DFR0, DebugVer) | + NV_FTR(DFR0, HPMN0)); /* Cap Debug to ARMv8.1 */ tmp = FIELD_GET(NV_FTR(DFR0, DebugVer), val); @@ -933,15 +934,15 @@ static void limit_nv_id_regs(struct kvm *kvm) kvm_set_vm_id_reg(kvm, SYS_ID_AA64DFR0_EL1, val); } -u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg sr) +u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *vcpu, + enum vcpu_sysreg sr, u64 v) { - u64 v = ctxt_sys_reg(&vcpu->arch.ctxt, sr); struct kvm_sysreg_masks *masks; masks = vcpu->kvm->arch.sysreg_masks; if (masks) { - sr -= __VNCR_START__; + sr -= __SANITISED_REG_START__; v &= ~masks->mask[sr].res0; v |= masks->mask[sr].res1; @@ -950,9 +951,13 @@ u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *vcpu, enum vcpu_sysreg sr) return v; } -static void set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u64 res1) +static __always_inline void set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u64 res1) { - int i = sr - __VNCR_START__; + int i = sr - __SANITISED_REG_START__; + + BUILD_BUG_ON(!__builtin_constant_p(sr)); + BUILD_BUG_ON(sr < __SANITISED_REG_START__); + BUILD_BUG_ON(sr >= NR_SYS_REGS); kvm->arch.sysreg_masks->mask[i].res0 = res0; kvm->arch.sysreg_masks->mask[i].res1 = res1; @@ -1050,7 +1055,7 @@ int kvm_init_nv_sysregs(struct kvm *kvm) res0 |= HCRX_EL2_PTTWI; if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, SCTLRX, IMP)) res0 |= HCRX_EL2_SCTLR2En; - if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, TCRX, IMP)) + if (!kvm_has_tcr2(kvm)) res0 |= HCRX_EL2_TCR2En; if (!kvm_has_feat(kvm, ID_AA64ISAR2_EL1, MOPS, IMP)) res0 |= (HCRX_EL2_MSCEn | HCRX_EL2_MCE2); @@ -1101,9 +1106,9 @@ int kvm_init_nv_sysregs(struct kvm *kvm) res0 |= (HFGxTR_EL2_nSMPRI_EL1 | HFGxTR_EL2_nTPIDR2_EL0); if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, THE, IMP)) res0 |= HFGxTR_EL2_nRCWMASK_EL1; - if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1PIE, IMP)) + if (!kvm_has_s1pie(kvm)) res0 |= (HFGxTR_EL2_nPIRE0_EL1 | HFGxTR_EL2_nPIR_EL1); - if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1POE, IMP)) + if (!kvm_has_s1poe(kvm)) res0 |= (HFGxTR_EL2_nPOR_EL0 | HFGxTR_EL2_nPOR_EL1); if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S2POE, IMP)) res0 |= HFGxTR_EL2_nS2POR_EL1; @@ -1200,6 +1205,28 @@ int kvm_init_nv_sysregs(struct kvm *kvm) res0 |= ~(res0 | res1); set_sysreg_masks(kvm, HAFGRTR_EL2, res0, res1); + /* TCR2_EL2 */ + res0 = TCR2_EL2_RES0; + res1 = TCR2_EL2_RES1; + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, D128, IMP)) + res0 |= (TCR2_EL2_DisCH0 | TCR2_EL2_DisCH1 | TCR2_EL2_D128); + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, MEC, IMP)) + res0 |= TCR2_EL2_AMEC1 | TCR2_EL2_AMEC0; + if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, HAFDBS, HAFT)) + res0 |= TCR2_EL2_HAFT; + if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, THE, IMP)) + res0 |= TCR2_EL2_PTTWI | TCR2_EL2_PnCH; + if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, AIE, IMP)) + res0 |= TCR2_EL2_AIE; + if (!kvm_has_s1poe(kvm)) + res0 |= TCR2_EL2_POE | TCR2_EL2_E0POE; + if (!kvm_has_s1pie(kvm)) + res0 |= TCR2_EL2_PIE; + if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, VH, IMP)) + res0 |= (TCR2_EL2_E0POE | TCR2_EL2_D128 | + TCR2_EL2_AMEC1 | TCR2_EL2_DisCH0 | TCR2_EL2_DisCH1); + set_sysreg_masks(kvm, TCR2_EL2, res0, res1); + /* SCTLR_EL1 */ res0 = SCTLR_EL1_RES0; res1 = SCTLR_EL1_RES1; @@ -1207,6 +1234,43 @@ int kvm_init_nv_sysregs(struct kvm *kvm) res0 |= SCTLR_EL1_EPAN; set_sysreg_masks(kvm, SCTLR_EL1, res0, res1); + /* MDCR_EL2 */ + res0 = MDCR_EL2_RES0; + res1 = MDCR_EL2_RES1; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, IMP)) + res0 |= (MDCR_EL2_HPMN | MDCR_EL2_TPMCR | + MDCR_EL2_TPM | MDCR_EL2_HPME); + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSVer, IMP)) + res0 |= MDCR_EL2_E2PB | MDCR_EL2_TPMS; + if (!kvm_has_feat(kvm, ID_AA64DFR1_EL1, SPMU, IMP)) + res0 |= MDCR_EL2_EnSPM; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, V3P1)) + res0 |= MDCR_EL2_HPMD; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceFilt, IMP)) + res0 |= MDCR_EL2_TTRF; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, V3P5)) + res0 |= MDCR_EL2_HCCD | MDCR_EL2_HLP; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, TraceBuffer, IMP)) + res0 |= MDCR_EL2_E2TB; + if (!kvm_has_feat(kvm, ID_AA64MMFR0_EL1, FGT, IMP)) + res0 |= MDCR_EL2_TDCC; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, MTPMU, IMP) || + kvm_has_feat(kvm, ID_AA64PFR0_EL1, EL3, IMP)) + res0 |= MDCR_EL2_MTPME; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMUVer, V3P7)) + res0 |= MDCR_EL2_HPMFZO; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSS, IMP)) + res0 |= MDCR_EL2_PMSSE; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, PMSVer, V1P2)) + res0 |= MDCR_EL2_HPMFZS; + if (!kvm_has_feat(kvm, ID_AA64DFR1_EL1, EBEP, IMP)) + res0 |= MDCR_EL2_PMEE; + if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, DebugVer, V8P9)) + res0 |= MDCR_EL2_EBWE; + if (!kvm_has_feat(kvm, ID_AA64DFR2_EL1, STEP, IMP)) + res0 |= MDCR_EL2_EnSTEPOP; + set_sysreg_masks(kvm, MDCR_EL2, res0, res1); + return 0; } diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index ac36c438b8c18c..456102bc0b555b 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -89,7 +89,11 @@ static bool kvm_pmc_is_64bit(struct kvm_pmc *pmc) static bool kvm_pmc_has_64bit_overflow(struct kvm_pmc *pmc) { - u64 val = kvm_vcpu_read_pmcr(kvm_pmc_to_vcpu(pmc)); + struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc); + u64 val = kvm_vcpu_read_pmcr(vcpu); + + if (kvm_pmu_counter_is_hyp(vcpu, pmc->idx)) + return __vcpu_sys_reg(vcpu, MDCR_EL2) & MDCR_EL2_HLP; return (pmc->idx < ARMV8_PMU_CYCLE_IDX && (val & ARMV8_PMU_PMCR_LP)) || (pmc->idx == ARMV8_PMU_CYCLE_IDX && (val & ARMV8_PMU_PMCR_LC)); @@ -111,6 +115,11 @@ static u32 counter_index_to_evtreg(u64 idx) return (idx == ARMV8_PMU_CYCLE_IDX) ? PMCCFILTR_EL0 : PMEVTYPER0_EL0 + idx; } +static u64 kvm_pmc_read_evtreg(const struct kvm_pmc *pmc) +{ + return __vcpu_sys_reg(kvm_pmc_to_vcpu(pmc), counter_index_to_evtreg(pmc->idx)); +} + static u64 kvm_pmu_get_pmc_value(struct kvm_pmc *pmc) { struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc); @@ -244,7 +253,7 @@ void kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu) */ void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) { - unsigned long mask = kvm_pmu_valid_counter_mask(vcpu); + unsigned long mask = kvm_pmu_implemented_counter_mask(vcpu); int i; for_each_set_bit(i, &mask, 32) @@ -265,7 +274,50 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) irq_work_sync(&vcpu->arch.pmu.overflow_work); } -u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu) +static u64 kvm_pmu_hyp_counter_mask(struct kvm_vcpu *vcpu) +{ + unsigned int hpmn, n; + + if (!vcpu_has_nv(vcpu)) + return 0; + + hpmn = SYS_FIELD_GET(MDCR_EL2, HPMN, __vcpu_sys_reg(vcpu, MDCR_EL2)); + n = vcpu->kvm->arch.pmcr_n; + + /* + * Programming HPMN to a value greater than PMCR_EL0.N is + * CONSTRAINED UNPREDICTABLE. Make the implementation choice that an + * UNKNOWN number of counters (in our case, zero) are reserved for EL2. + */ + if (hpmn >= n) + return 0; + + /* + * Programming HPMN=0 is CONSTRAINED UNPREDICTABLE if FEAT_HPMN0 isn't + * implemented. Since KVM's ability to emulate HPMN=0 does not directly + * depend on hardware (all PMU registers are trapped), make the + * implementation choice that all counters are included in the second + * range reserved for EL2/EL3. + */ + return GENMASK(n - 1, hpmn); +} + +bool kvm_pmu_counter_is_hyp(struct kvm_vcpu *vcpu, unsigned int idx) +{ + return kvm_pmu_hyp_counter_mask(vcpu) & BIT(idx); +} + +u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu) +{ + u64 mask = kvm_pmu_implemented_counter_mask(vcpu); + + if (!vcpu_has_nv(vcpu) || vcpu_is_el2(vcpu)) + return mask; + + return mask & ~kvm_pmu_hyp_counter_mask(vcpu); +} + +u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu) { u64 val = FIELD_GET(ARMV8_PMU_PMCR_N, kvm_vcpu_read_pmcr(vcpu)); @@ -336,15 +388,30 @@ void kvm_pmu_disable_counter_mask(struct kvm_vcpu *vcpu, u64 val) } } -static u64 kvm_pmu_overflow_status(struct kvm_vcpu *vcpu) +/* + * Returns the PMU overflow state, which is true if there exists an event + * counter where the values of the global enable control, PMOVSSET_EL0[n], and + * PMINTENSET_EL1[n] are all 1. + */ +static bool kvm_pmu_overflow_status(struct kvm_vcpu *vcpu) { - u64 reg = 0; + u64 reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0); - if ((kvm_vcpu_read_pmcr(vcpu) & ARMV8_PMU_PMCR_E)) { - reg = __vcpu_sys_reg(vcpu, PMOVSSET_EL0); - reg &= __vcpu_sys_reg(vcpu, PMCNTENSET_EL0); - reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1); - } + reg &= __vcpu_sys_reg(vcpu, PMINTENSET_EL1); + + /* + * PMCR_EL0.E is the global enable control for event counters available + * to EL0 and EL1. + */ + if (!(kvm_vcpu_read_pmcr(vcpu) & ARMV8_PMU_PMCR_E)) + reg &= kvm_pmu_hyp_counter_mask(vcpu); + + /* + * Otherwise, MDCR_EL2.HPME is the global enable control for event + * counters reserved for EL2. + */ + if (!(vcpu_read_sys_reg(vcpu, MDCR_EL2) & MDCR_EL2_HPME)) + reg &= ~kvm_pmu_hyp_counter_mask(vcpu); return reg; } @@ -357,7 +424,7 @@ static void kvm_pmu_update_state(struct kvm_vcpu *vcpu) if (!kvm_vcpu_has_pmu(vcpu)) return; - overflow = !!kvm_pmu_overflow_status(vcpu); + overflow = kvm_pmu_overflow_status(vcpu); if (pmu->irq_level == overflow) return; @@ -574,7 +641,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) kvm_pmu_set_counter_value(vcpu, ARMV8_PMU_CYCLE_IDX, 0); if (val & ARMV8_PMU_PMCR_P) { - unsigned long mask = kvm_pmu_valid_counter_mask(vcpu); + unsigned long mask = kvm_pmu_accessible_counter_mask(vcpu); mask &= ~BIT(ARMV8_PMU_CYCLE_IDX); for_each_set_bit(i, &mask, 32) kvm_pmu_set_pmc_value(kvm_vcpu_idx_to_pmc(vcpu, i), 0, true); @@ -585,8 +652,44 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pmc) { struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc); - return (kvm_vcpu_read_pmcr(vcpu) & ARMV8_PMU_PMCR_E) && - (__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(pmc->idx)); + unsigned int mdcr = __vcpu_sys_reg(vcpu, MDCR_EL2); + + if (!(__vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(pmc->idx))) + return false; + + if (kvm_pmu_counter_is_hyp(vcpu, pmc->idx)) + return mdcr & MDCR_EL2_HPME; + + return kvm_vcpu_read_pmcr(vcpu) & ARMV8_PMU_PMCR_E; +} + +static bool kvm_pmc_counts_at_el0(struct kvm_pmc *pmc) +{ + u64 evtreg = kvm_pmc_read_evtreg(pmc); + bool nsu = evtreg & ARMV8_PMU_EXCLUDE_NS_EL0; + bool u = evtreg & ARMV8_PMU_EXCLUDE_EL0; + + return u == nsu; +} + +static bool kvm_pmc_counts_at_el1(struct kvm_pmc *pmc) +{ + u64 evtreg = kvm_pmc_read_evtreg(pmc); + bool nsk = evtreg & ARMV8_PMU_EXCLUDE_NS_EL1; + bool p = evtreg & ARMV8_PMU_EXCLUDE_EL1; + + return p == nsk; +} + +static bool kvm_pmc_counts_at_el2(struct kvm_pmc *pmc) +{ + struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc); + u64 mdcr = __vcpu_sys_reg(vcpu, MDCR_EL2); + + if (!kvm_pmu_counter_is_hyp(vcpu, pmc->idx) && (mdcr & MDCR_EL2_HPMD)) + return false; + + return kvm_pmc_read_evtreg(pmc) & ARMV8_PMU_INCLUDE_EL2; } /** @@ -599,17 +702,15 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc) struct arm_pmu *arm_pmu = vcpu->kvm->arch.arm_pmu; struct perf_event *event; struct perf_event_attr attr; - u64 eventsel, reg, data; - bool p, u, nsk, nsu; + u64 eventsel, evtreg; - reg = counter_index_to_evtreg(pmc->idx); - data = __vcpu_sys_reg(vcpu, reg); + evtreg = kvm_pmc_read_evtreg(pmc); kvm_pmu_stop_counter(pmc); if (pmc->idx == ARMV8_PMU_CYCLE_IDX) eventsel = ARMV8_PMUV3_PERFCTR_CPU_CYCLES; else - eventsel = data & kvm_pmu_event_mask(vcpu->kvm); + eventsel = evtreg & kvm_pmu_event_mask(vcpu->kvm); /* * Neither SW increment nor chained events need to be backed @@ -627,22 +728,25 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc) !test_bit(eventsel, vcpu->kvm->arch.pmu_filter)) return; - p = data & ARMV8_PMU_EXCLUDE_EL1; - u = data & ARMV8_PMU_EXCLUDE_EL0; - nsk = data & ARMV8_PMU_EXCLUDE_NS_EL1; - nsu = data & ARMV8_PMU_EXCLUDE_NS_EL0; - memset(&attr, 0, sizeof(struct perf_event_attr)); attr.type = arm_pmu->pmu.type; attr.size = sizeof(attr); attr.pinned = 1; attr.disabled = !kvm_pmu_counter_is_enabled(pmc); - attr.exclude_user = (u != nsu); - attr.exclude_kernel = (p != nsk); + attr.exclude_user = !kvm_pmc_counts_at_el0(pmc); attr.exclude_hv = 1; /* Don't count EL2 events */ attr.exclude_host = 1; /* Don't count host events */ attr.config = eventsel; + /* + * Filter events at EL1 (i.e. vEL2) when in a hyp context based on the + * guest's EL2 filter. + */ + if (unlikely(is_hyp_ctxt(vcpu))) + attr.exclude_kernel = !kvm_pmc_counts_at_el2(pmc); + else + attr.exclude_kernel = !kvm_pmc_counts_at_el1(pmc); + /* * If counting with a 64bit counter, advertise it to the perf * code, carefully dealing with the initial sample period @@ -804,7 +908,7 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1) void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu) { - u64 mask = kvm_pmu_valid_counter_mask(vcpu); + u64 mask = kvm_pmu_implemented_counter_mask(vcpu); kvm_pmu_handle_pmcr(vcpu, kvm_vcpu_read_pmcr(vcpu)); @@ -1139,3 +1243,32 @@ u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu) return u64_replace_bits(pmcr, vcpu->kvm->arch.pmcr_n, ARMV8_PMU_PMCR_N); } + +void kvm_pmu_nested_transition(struct kvm_vcpu *vcpu) +{ + bool reprogrammed = false; + unsigned long mask; + int i; + + if (!kvm_vcpu_has_pmu(vcpu)) + return; + + mask = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0); + for_each_set_bit(i, &mask, 32) { + struct kvm_pmc *pmc = kvm_vcpu_idx_to_pmc(vcpu, i); + + /* + * We only need to reconfigure events where the filter is + * different at EL1 vs. EL2, as we're multiplexing the true EL1 + * event filter bit for nested. + */ + if (kvm_pmc_counts_at_el1(pmc) == kvm_pmc_counts_at_el2(pmc)) + continue; + + kvm_pmu_create_perf_event(pmc); + reprogrammed = true; + } + + if (reprogrammed) + kvm_vcpu_pmu_restore_guest(vcpu); +} diff --git a/arch/arm64/kvm/psci.c b/arch/arm64/kvm/psci.c index 1f69b667332b2b..3b5dbe9a0a0ea0 100644 --- a/arch/arm64/kvm/psci.c +++ b/arch/arm64/kvm/psci.c @@ -194,6 +194,12 @@ static void kvm_psci_system_off(struct kvm_vcpu *vcpu) kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN, 0); } +static void kvm_psci_system_off2(struct kvm_vcpu *vcpu) +{ + kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN, + KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2); +} + static void kvm_psci_system_reset(struct kvm_vcpu *vcpu) { kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET, 0); @@ -322,7 +328,7 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor) switch(psci_fn) { case PSCI_0_2_FN_PSCI_VERSION: - val = minor == 0 ? KVM_ARM_PSCI_1_0 : KVM_ARM_PSCI_1_1; + val = PSCI_VERSION(1, minor); break; case PSCI_1_0_FN_PSCI_FEATURES: arg = smccc_get_arg1(vcpu); @@ -358,6 +364,11 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor) if (minor >= 1) val = 0; break; + case PSCI_1_3_FN_SYSTEM_OFF2: + case PSCI_1_3_FN64_SYSTEM_OFF2: + if (minor >= 3) + val = PSCI_1_3_OFF_TYPE_HIBERNATE_OFF; + break; } break; case PSCI_1_0_FN_SYSTEM_SUSPEND: @@ -392,6 +403,33 @@ static int kvm_psci_1_x_call(struct kvm_vcpu *vcpu, u32 minor) break; } break; + case PSCI_1_3_FN_SYSTEM_OFF2: + kvm_psci_narrow_to_32bit(vcpu); + fallthrough; + case PSCI_1_3_FN64_SYSTEM_OFF2: + if (minor < 3) + break; + + arg = smccc_get_arg1(vcpu); + /* + * SYSTEM_OFF2 defaults to HIBERNATE_OFF if arg1 is zero. arg2 + * must be zero. + */ + if ((arg && arg != PSCI_1_3_OFF_TYPE_HIBERNATE_OFF) || + smccc_get_arg2(vcpu) != 0) { + val = PSCI_RET_INVALID_PARAMS; + break; + } + kvm_psci_system_off2(vcpu); + /* + * We shouldn't be going back to the guest after receiving a + * SYSTEM_OFF2 request. Preload a return value of + * INTERNAL_FAILURE should userspace ignore the exit and resume + * the vCPU. + */ + val = PSCI_RET_INTERNAL_FAILURE; + ret = 0; + break; default: return kvm_psci_0_2_call(vcpu); } @@ -449,6 +487,10 @@ int kvm_psci_call(struct kvm_vcpu *vcpu) } switch (version) { + case KVM_ARM_PSCI_1_3: + return kvm_psci_1_x_call(vcpu, 3); + case KVM_ARM_PSCI_1_2: + return kvm_psci_1_x_call(vcpu, 2); case KVM_ARM_PSCI_1_1: return kvm_psci_1_x_call(vcpu, 1); case KVM_ARM_PSCI_1_0: diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 0b0ae5ae7bc2a1..470524b31951ec 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -167,11 +167,6 @@ static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu) memset(vcpu->arch.sve_state, 0, vcpu_sve_state_size(vcpu)); } -static void kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu) -{ - vcpu_set_flag(vcpu, GUEST_HAS_PTRAUTH); -} - /** * kvm_reset_vcpu - sets core registers and sys_regs to reset value * @vcpu: The VCPU pointer diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index ff8c4e1b847ed4..e2a5c2918d9e5a 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -110,6 +110,14 @@ static bool get_el2_to_el1_mapping(unsigned int reg, PURE_EL2_SYSREG( RVBAR_EL2 ); PURE_EL2_SYSREG( TPIDR_EL2 ); PURE_EL2_SYSREG( HPFAR_EL2 ); + PURE_EL2_SYSREG( HCRX_EL2 ); + PURE_EL2_SYSREG( HFGRTR_EL2 ); + PURE_EL2_SYSREG( HFGWTR_EL2 ); + PURE_EL2_SYSREG( HFGITR_EL2 ); + PURE_EL2_SYSREG( HDFGRTR_EL2 ); + PURE_EL2_SYSREG( HDFGWTR_EL2 ); + PURE_EL2_SYSREG( HAFGRTR_EL2 ); + PURE_EL2_SYSREG( CNTVOFF_EL2 ); PURE_EL2_SYSREG( CNTHCTL_EL2 ); MAPPED_EL2_SYSREG(SCTLR_EL2, SCTLR_EL1, translate_sctlr_el2_to_sctlr_el1 ); @@ -126,10 +134,15 @@ static bool get_el2_to_el1_mapping(unsigned int reg, MAPPED_EL2_SYSREG(ESR_EL2, ESR_EL1, NULL ); MAPPED_EL2_SYSREG(FAR_EL2, FAR_EL1, NULL ); MAPPED_EL2_SYSREG(MAIR_EL2, MAIR_EL1, NULL ); + MAPPED_EL2_SYSREG(TCR2_EL2, TCR2_EL1, NULL ); + MAPPED_EL2_SYSREG(PIR_EL2, PIR_EL1, NULL ); + MAPPED_EL2_SYSREG(PIRE0_EL2, PIRE0_EL1, NULL ); + MAPPED_EL2_SYSREG(POR_EL2, POR_EL1, NULL ); MAPPED_EL2_SYSREG(AMAIR_EL2, AMAIR_EL1, NULL ); MAPPED_EL2_SYSREG(ELR_EL2, ELR_EL1, NULL ); MAPPED_EL2_SYSREG(SPSR_EL2, SPSR_EL1, NULL ); MAPPED_EL2_SYSREG(ZCR_EL2, ZCR_EL1, NULL ); + MAPPED_EL2_SYSREG(CONTEXTIDR_EL2, CONTEXTIDR_EL1, NULL ); default: return false; } @@ -148,6 +161,21 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg) if (!is_hyp_ctxt(vcpu)) goto memory_read; + /* + * CNTHCTL_EL2 requires some special treatment to + * account for the bits that can be set via CNTKCTL_EL1. + */ + switch (reg) { + case CNTHCTL_EL2: + if (vcpu_el2_e2h_is_set(vcpu)) { + val = read_sysreg_el1(SYS_CNTKCTL); + val &= CNTKCTL_VALID_BITS; + val |= __vcpu_sys_reg(vcpu, reg) & ~CNTKCTL_VALID_BITS; + return val; + } + break; + } + /* * If this register does not have an EL1 counterpart, * then read the stored EL2 version. @@ -165,6 +193,9 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg) /* Get the current version of the EL1 counterpart. */ WARN_ON(!__vcpu_read_sys_reg_from_cpu(el1r, &val)); + if (reg >= __SANITISED_REG_START__) + val = kvm_vcpu_apply_reg_masks(vcpu, reg, val); + return val; } @@ -198,6 +229,19 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg) */ __vcpu_sys_reg(vcpu, reg) = val; + switch (reg) { + case CNTHCTL_EL2: + /* + * If E2H=0, CNHTCTL_EL2 is a pure shadow register. + * Otherwise, some of the bits are backed by + * CNTKCTL_EL1, while the rest is kept in memory. + * Yes, this is fun stuff. + */ + if (vcpu_el2_e2h_is_set(vcpu)) + write_sysreg_el1(val, SYS_CNTKCTL); + return; + } + /* No EL1 counterpart? We're done here.? */ if (reg == el1r) return; @@ -390,10 +434,6 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu, bool was_enabled = vcpu_has_cache_enabled(vcpu); u64 val, mask, shift; - if (reg_to_encoding(r) == SYS_TCR2_EL1 && - !kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, TCRX, IMP)) - return undef_access(vcpu, p, r); - BUG_ON(!p->is_write); get_access_mask(r, &mask, &shift); @@ -1128,7 +1168,7 @@ static int set_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 va { bool set; - val &= kvm_pmu_valid_counter_mask(vcpu); + val &= kvm_pmu_accessible_counter_mask(vcpu); switch (r->reg) { case PMOVSSET_EL0: @@ -1151,7 +1191,7 @@ static int set_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 va static int get_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 *val) { - u64 mask = kvm_pmu_valid_counter_mask(vcpu); + u64 mask = kvm_pmu_accessible_counter_mask(vcpu); *val = __vcpu_sys_reg(vcpu, r->reg) & mask; return 0; @@ -1165,7 +1205,7 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p, if (pmu_access_el0_disabled(vcpu)) return false; - mask = kvm_pmu_valid_counter_mask(vcpu); + mask = kvm_pmu_accessible_counter_mask(vcpu); if (p->is_write) { val = p->regval & mask; if (r->Op2 & 0x1) { @@ -1188,7 +1228,7 @@ static bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { - u64 mask = kvm_pmu_valid_counter_mask(vcpu); + u64 mask = kvm_pmu_accessible_counter_mask(vcpu); if (check_pmu_access_disabled(vcpu, 0)) return false; @@ -1212,7 +1252,7 @@ static bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { - u64 mask = kvm_pmu_valid_counter_mask(vcpu); + u64 mask = kvm_pmu_accessible_counter_mask(vcpu); if (pmu_access_el0_disabled(vcpu)) return false; @@ -1242,7 +1282,7 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p, if (pmu_write_swinc_el0_disabled(vcpu)) return false; - mask = kvm_pmu_valid_counter_mask(vcpu); + mask = kvm_pmu_accessible_counter_mask(vcpu); kvm_pmu_software_increment(vcpu, p->regval & mask); return true; } @@ -1509,6 +1549,9 @@ static u8 pmuver_to_perfmon(u8 pmuver) } } +static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val); +static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val); + /* Read a sanitised cpufeature ID register by sys_reg_desc */ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) @@ -1522,6 +1565,12 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, val = read_sanitised_ftr_reg(id); switch (id) { + case SYS_ID_AA64DFR0_EL1: + val = sanitise_id_aa64dfr0_el1(vcpu, val); + break; + case SYS_ID_AA64PFR0_EL1: + val = sanitise_id_aa64pfr0_el1(vcpu, val); + break; case SYS_ID_AA64PFR1_EL1: if (!kvm_has_mte(vcpu->kvm)) val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE); @@ -1535,6 +1584,7 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTEX); val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_DF2); val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_PFAR); + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MPAM_frac); break; case SYS_ID_AA64PFR2_EL1: /* We only expose FPMR */ @@ -1692,11 +1742,8 @@ static unsigned int fp8_visibility(const struct kvm_vcpu *vcpu, return REG_HIDDEN; } -static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, - const struct sys_reg_desc *rd) +static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val) { - u64 val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); - if (!vcpu_has_sve(vcpu)) val &= ~ID_AA64PFR0_EL1_SVE_MASK; @@ -1724,6 +1771,13 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, val &= ~ID_AA64PFR0_EL1_AMU_MASK; + /* + * MPAM is disabled by default as KVM also needs a set of PARTID to + * program the MPAMVPMx_EL2 PARTID remapping registers with. But some + * older kernels let the guest see the ID bit. + */ + val &= ~ID_AA64PFR0_EL1_MPAM_MASK; + return val; } @@ -1737,11 +1791,8 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, (val); \ }) -static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu, - const struct sys_reg_desc *rd) +static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val) { - u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1); - val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8); /* @@ -1834,6 +1885,70 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu, return set_id_reg(vcpu, rd, val); } +static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, u64 user_val) +{ + u64 hw_val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); + u64 mpam_mask = ID_AA64PFR0_EL1_MPAM_MASK; + + /* + * Commit 011e5f5bf529f ("arm64/cpufeature: Add remaining feature bits + * in ID_AA64PFR0 register") exposed the MPAM field of AA64PFR0_EL1 to + * guests, but didn't add trap handling. KVM doesn't support MPAM and + * always returns an UNDEF for these registers. The guest must see 0 + * for this field. + * + * But KVM must also accept values from user-space that were provided + * by KVM. On CPUs that support MPAM, permit user-space to write + * the sanitizied value to ID_AA64PFR0_EL1.MPAM, but ignore this field. + */ + if ((hw_val & mpam_mask) == (user_val & mpam_mask)) + user_val &= ~ID_AA64PFR0_EL1_MPAM_MASK; + + return set_id_reg(vcpu, rd, user_val); +} + +static int set_id_aa64pfr1_el1(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, u64 user_val) +{ + u64 hw_val = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1); + u64 mpam_mask = ID_AA64PFR1_EL1_MPAM_frac_MASK; + + /* See set_id_aa64pfr0_el1 for comment about MPAM */ + if ((hw_val & mpam_mask) == (user_val & mpam_mask)) + user_val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK; + + return set_id_reg(vcpu, rd, user_val); +} + +static int set_ctr_el0(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, u64 user_val) +{ + u8 user_L1Ip = SYS_FIELD_GET(CTR_EL0, L1Ip, user_val); + + /* + * Both AIVIVT (0b01) and VPIPT (0b00) are documented as reserved. + * Hence only allow to set VIPT(0b10) or PIPT(0b11) for L1Ip based + * on what hardware reports. + * + * Using a VIPT software model on PIPT will lead to over invalidation, + * but still correct. Hence, we can allow downgrading PIPT to VIPT, + * but not the other way around. This is handled via arm64_ftr_safe_value() + * as CTR_EL0 ftr_bits has L1Ip field with type FTR_EXACT and safe value + * set as VIPT. + */ + switch (user_L1Ip) { + case CTR_EL0_L1Ip_RESERVED_VPIPT: + case CTR_EL0_L1Ip_RESERVED_AIVIVT: + return -EINVAL; + case CTR_EL0_L1Ip_VIPT: + case CTR_EL0_L1Ip_PIPT: + return set_id_reg(vcpu, rd, user_val); + default: + return -ENOENT; + } +} + /* * cpufeature ID register user accessors * @@ -2104,6 +2219,15 @@ static bool bad_redir_trap(struct kvm_vcpu *vcpu, .val = v, \ } +#define EL2_REG_FILTERED(name, acc, rst, v, filter) { \ + SYS_DESC(SYS_##name), \ + .access = acc, \ + .reset = rst, \ + .reg = name, \ + .visibility = filter, \ + .val = v, \ +} + #define EL2_REG_VNCR(name, rst, v) EL2_REG(name, bad_vncr_trap, rst, v) #define EL2_REG_REDIR(name, rst, v) EL2_REG(name, bad_redir_trap, rst, v) @@ -2150,6 +2274,15 @@ static bool bad_redir_trap(struct kvm_vcpu *vcpu, .val = mask, \ } +/* sys_reg_desc initialiser for cpufeature ID registers that need filtering */ +#define ID_FILTERED(sysreg, name, mask) { \ + ID_DESC(sysreg), \ + .set_user = set_##name, \ + .visibility = id_visibility, \ + .reset = kvm_read_sanitised_id_reg, \ + .val = (mask), \ +} + /* * sys_reg_desc initialiser for architecturally unallocated cpufeature ID * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2 @@ -2236,16 +2369,18 @@ static u64 reset_hcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) return __vcpu_sys_reg(vcpu, r->reg) = val; } +static unsigned int __el2_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + unsigned int (*fn)(const struct kvm_vcpu *, + const struct sys_reg_desc *)) +{ + return el2_visibility(vcpu, rd) ?: fn(vcpu, rd); +} + static unsigned int sve_el2_visibility(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd) { - unsigned int r; - - r = el2_visibility(vcpu, rd); - if (r) - return r; - - return sve_visibility(vcpu, rd); + return __el2_visibility(vcpu, rd, sve_visibility); } static bool access_zcr_el2(struct kvm_vcpu *vcpu, @@ -2273,12 +2408,48 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu, static unsigned int s1poe_visibility(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd) { - if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, S1POE, IMP)) + if (kvm_has_s1poe(vcpu->kvm)) + return 0; + + return REG_HIDDEN; +} + +static unsigned int s1poe_el2_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + return __el2_visibility(vcpu, rd, s1poe_visibility); +} + +static unsigned int tcr2_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + if (kvm_has_tcr2(vcpu->kvm)) + return 0; + + return REG_HIDDEN; +} + +static unsigned int tcr2_el2_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + return __el2_visibility(vcpu, rd, tcr2_visibility); +} + +static unsigned int s1pie_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + if (kvm_has_s1pie(vcpu->kvm)) return 0; return REG_HIDDEN; } +static unsigned int s1pie_el2_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + return __el2_visibility(vcpu, rd, s1pie_visibility); +} + /* * Architected system registers. * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2 @@ -2374,18 +2545,15 @@ static const struct sys_reg_desc sys_reg_descs[] = { /* AArch64 ID registers */ /* CRm=4 */ - { SYS_DESC(SYS_ID_AA64PFR0_EL1), - .access = access_id_reg, - .get_user = get_id_reg, - .set_user = set_id_reg, - .reset = read_sanitised_id_aa64pfr0_el1, - .val = ~(ID_AA64PFR0_EL1_AMU | - ID_AA64PFR0_EL1_MPAM | - ID_AA64PFR0_EL1_SVE | - ID_AA64PFR0_EL1_RAS | - ID_AA64PFR0_EL1_AdvSIMD | - ID_AA64PFR0_EL1_FP), }, - ID_WRITABLE(ID_AA64PFR1_EL1, ~(ID_AA64PFR1_EL1_PFAR | + ID_FILTERED(ID_AA64PFR0_EL1, id_aa64pfr0_el1, + ~(ID_AA64PFR0_EL1_AMU | + ID_AA64PFR0_EL1_MPAM | + ID_AA64PFR0_EL1_SVE | + ID_AA64PFR0_EL1_RAS | + ID_AA64PFR0_EL1_AdvSIMD | + ID_AA64PFR0_EL1_FP)), + ID_FILTERED(ID_AA64PFR1_EL1, id_aa64pfr1_el1, + ~(ID_AA64PFR1_EL1_PFAR | ID_AA64PFR1_EL1_DF2 | ID_AA64PFR1_EL1_MTEX | ID_AA64PFR1_EL1_THE | @@ -2406,11 +2574,6 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_WRITABLE(ID_AA64FPFR0_EL1, ~ID_AA64FPFR0_EL1_RES0), /* CRm=5 */ - { SYS_DESC(SYS_ID_AA64DFR0_EL1), - .access = access_id_reg, - .get_user = get_id_reg, - .set_user = set_id_aa64dfr0_el1, - .reset = read_sanitised_id_aa64dfr0_el1, /* * Prior to FEAT_Debugv8.9, the architecture defines context-aware * breakpoints (CTX_CMPs) as the highest numbered breakpoints (BRPs). @@ -2423,10 +2586,11 @@ static const struct sys_reg_desc sys_reg_descs[] = { * See DDI0487K.a, section D2.8.3 Breakpoint types and linking * of breakpoints for more details. */ - .val = ID_AA64DFR0_EL1_DoubleLock_MASK | - ID_AA64DFR0_EL1_WRPs_MASK | - ID_AA64DFR0_EL1_PMUVer_MASK | - ID_AA64DFR0_EL1_DebugVer_MASK, }, + ID_FILTERED(ID_AA64DFR0_EL1, id_aa64dfr0_el1, + ID_AA64DFR0_EL1_DoubleLock_MASK | + ID_AA64DFR0_EL1_WRPs_MASK | + ID_AA64DFR0_EL1_PMUVer_MASK | + ID_AA64DFR0_EL1_DebugVer_MASK), ID_SANITISED(ID_AA64DFR1_EL1), ID_UNALLOCATED(5,2), ID_UNALLOCATED(5,3), @@ -2454,7 +2618,8 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_WRITABLE(ID_AA64MMFR0_EL1, ~(ID_AA64MMFR0_EL1_RES0 | ID_AA64MMFR0_EL1_TGRAN4_2 | ID_AA64MMFR0_EL1_TGRAN64_2 | - ID_AA64MMFR0_EL1_TGRAN16_2)), + ID_AA64MMFR0_EL1_TGRAN16_2 | + ID_AA64MMFR0_EL1_ASIDBITS)), ID_WRITABLE(ID_AA64MMFR1_EL1, ~(ID_AA64MMFR1_EL1_RES0 | ID_AA64MMFR1_EL1_HCX | ID_AA64MMFR1_EL1_TWED | @@ -2489,7 +2654,8 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 }, { SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 }, { SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 }, - { SYS_DESC(SYS_TCR2_EL1), access_vm_reg, reset_val, TCR2_EL1, 0 }, + { SYS_DESC(SYS_TCR2_EL1), access_vm_reg, reset_val, TCR2_EL1, 0, + .visibility = tcr2_visibility }, PTRAUTH_KEY(APIA), PTRAUTH_KEY(APIB), @@ -2543,8 +2709,10 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_PMMIR_EL1), trap_raz_wi }, { SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 }, - { SYS_DESC(SYS_PIRE0_EL1), NULL, reset_unknown, PIRE0_EL1 }, - { SYS_DESC(SYS_PIR_EL1), NULL, reset_unknown, PIR_EL1 }, + { SYS_DESC(SYS_PIRE0_EL1), NULL, reset_unknown, PIRE0_EL1, + .visibility = s1pie_visibility }, + { SYS_DESC(SYS_PIR_EL1), NULL, reset_unknown, PIR_EL1, + .visibility = s1pie_visibility }, { SYS_DESC(SYS_POR_EL1), NULL, reset_unknown, POR_EL1, .visibility = s1poe_visibility }, { SYS_DESC(SYS_AMAIR_EL1), access_vm_reg, reset_amair_el1, AMAIR_EL1 }, @@ -2553,8 +2721,11 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_LOREA_EL1), trap_loregion }, { SYS_DESC(SYS_LORN_EL1), trap_loregion }, { SYS_DESC(SYS_LORC_EL1), trap_loregion }, + { SYS_DESC(SYS_MPAMIDR_EL1), undef_access }, { SYS_DESC(SYS_LORID_EL1), trap_loregion }, + { SYS_DESC(SYS_MPAM1_EL1), undef_access }, + { SYS_DESC(SYS_MPAM0_EL1), undef_access }, { SYS_DESC(SYS_VBAR_EL1), access_rw, reset_val, VBAR_EL1, 0 }, { SYS_DESC(SYS_DISR_EL1), NULL, reset_val, DISR_EL1, 0 }, @@ -2599,10 +2770,12 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_CCSIDR2_EL1), undef_access }, { SYS_DESC(SYS_SMIDR_EL1), undef_access }, { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 }, - ID_WRITABLE(CTR_EL0, CTR_EL0_DIC_MASK | - CTR_EL0_IDC_MASK | - CTR_EL0_DminLine_MASK | - CTR_EL0_IminLine_MASK), + ID_FILTERED(CTR_EL0, ctr_el0, + CTR_EL0_DIC_MASK | + CTR_EL0_IDC_MASK | + CTR_EL0_DminLine_MASK | + CTR_EL0_L1Ip_MASK | + CTR_EL0_IminLine_MASK), { SYS_DESC(SYS_SVCR), undef_access, reset_val, SVCR, 0, .visibility = sme_visibility }, { SYS_DESC(SYS_FPMR), undef_access, reset_val, FPMR, 0, .visibility = fp8_visibility }, @@ -2818,14 +2991,16 @@ static const struct sys_reg_desc sys_reg_descs[] = { EL2_REG_VNCR(HFGITR_EL2, reset_val, 0), EL2_REG_VNCR(HACR_EL2, reset_val, 0), - { SYS_DESC(SYS_ZCR_EL2), .access = access_zcr_el2, .reset = reset_val, - .visibility = sve_el2_visibility, .reg = ZCR_EL2 }, + EL2_REG_FILTERED(ZCR_EL2, access_zcr_el2, reset_val, 0, + sve_el2_visibility), EL2_REG_VNCR(HCRX_EL2, reset_val, 0), EL2_REG(TTBR0_EL2, access_rw, reset_val, 0), EL2_REG(TTBR1_EL2, access_rw, reset_val, 0), EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1), + EL2_REG_FILTERED(TCR2_EL2, access_rw, reset_val, TCR2_EL2_RES1, + tcr2_el2_visibility), EL2_REG_VNCR(VTTBR_EL2, reset_val, 0), EL2_REG_VNCR(VTCR_EL2, reset_val, 0), @@ -2853,7 +3028,24 @@ static const struct sys_reg_desc sys_reg_descs[] = { EL2_REG(HPFAR_EL2, access_rw, reset_val, 0), EL2_REG(MAIR_EL2, access_rw, reset_val, 0), + EL2_REG_FILTERED(PIRE0_EL2, access_rw, reset_val, 0, + s1pie_el2_visibility), + EL2_REG_FILTERED(PIR_EL2, access_rw, reset_val, 0, + s1pie_el2_visibility), + EL2_REG_FILTERED(POR_EL2, access_rw, reset_val, 0, + s1poe_el2_visibility), EL2_REG(AMAIR_EL2, access_rw, reset_val, 0), + { SYS_DESC(SYS_MPAMHCR_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPMV_EL2), undef_access }, + { SYS_DESC(SYS_MPAM2_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPM0_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPM1_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPM2_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPM3_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPM4_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPM5_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPM6_EL2), undef_access }, + { SYS_DESC(SYS_MPAMVPM7_EL2), undef_access }, EL2_REG(VBAR_EL2, access_rw, reset_val, 0), EL2_REG(RVBAR_EL2, access_rw, reset_val, 0), @@ -4719,7 +4911,7 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu) if (kvm_has_feat(kvm, ID_AA64ISAR2_EL1, MOPS, IMP)) vcpu->arch.hcrx_el2 |= (HCRX_EL2_MSCEn | HCRX_EL2_MCE2); - if (kvm_has_feat(kvm, ID_AA64MMFR3_EL1, TCRX, IMP)) + if (kvm_has_tcr2(kvm)) vcpu->arch.hcrx_el2 |= HCRX_EL2_TCR2En; if (kvm_has_fpmr(kvm)) @@ -4769,11 +4961,11 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu) kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_ATS1E1RP | HFGITR_EL2_ATS1E1WP); - if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1PIE, IMP)) + if (!kvm_has_s1pie(kvm)) kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nPIRE0_EL1 | HFGxTR_EL2_nPIR_EL1); - if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1POE, IMP)) + if (!kvm_has_s1poe(kvm)) kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nPOR_EL1 | HFGxTR_EL2_nPOR_EL0); diff --git a/arch/arm64/kvm/vgic/vgic-debug.c b/arch/arm64/kvm/vgic/vgic-debug.c index e1397ab2072a57..afb018528bc3be 100644 --- a/arch/arm64/kvm/vgic/vgic-debug.c +++ b/arch/arm64/kvm/vgic/vgic-debug.c @@ -287,7 +287,10 @@ static int vgic_debug_show(struct seq_file *s, void *v) * Expect this to succeed, as iter_mark_lpis() takes a reference on * every LPI to be visited. */ - irq = vgic_get_irq(kvm, vcpu, iter->intid); + if (iter->intid < VGIC_NR_PRIVATE_IRQS) + irq = vgic_get_vcpu_irq(vcpu, iter->intid); + else + irq = vgic_get_irq(kvm, iter->intid); if (WARN_ON_ONCE(!irq)) return -EINVAL; diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 48c952563e85fd..bc7e22ab5d8122 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -322,7 +322,7 @@ int vgic_init(struct kvm *kvm) goto out; for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) { - struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, i); switch (dist->vgic_model) { case KVM_DEV_TYPE_ARM_VGIC_V3: diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index ba945ba78cc7d7..fb96802799c6fe 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -31,6 +31,41 @@ static int vgic_its_commit_v0(struct vgic_its *its); static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq, struct kvm_vcpu *filter_vcpu, bool needs_inv); +#define vgic_its_read_entry_lock(i, g, valp, t) \ + ({ \ + int __sz = vgic_its_get_abi(i)->t##_esz; \ + struct kvm *__k = (i)->dev->kvm; \ + int __ret; \ + \ + BUILD_BUG_ON(NR_ITS_ABIS == 1 && \ + sizeof(*(valp)) != ABI_0_ESZ); \ + if (NR_ITS_ABIS > 1 && \ + KVM_BUG_ON(__sz != sizeof(*(valp)), __k)) \ + __ret = -EINVAL; \ + else \ + __ret = kvm_read_guest_lock(__k, (g), \ + valp, __sz); \ + __ret; \ + }) + +#define vgic_its_write_entry_lock(i, g, val, t) \ + ({ \ + int __sz = vgic_its_get_abi(i)->t##_esz; \ + struct kvm *__k = (i)->dev->kvm; \ + typeof(val) __v = (val); \ + int __ret; \ + \ + BUILD_BUG_ON(NR_ITS_ABIS == 1 && \ + sizeof(__v) != ABI_0_ESZ); \ + if (NR_ITS_ABIS > 1 && \ + KVM_BUG_ON(__sz != sizeof(__v), __k)) \ + __ret = -EINVAL; \ + else \ + __ret = vgic_write_guest_lock(__k, (g), \ + &__v, __sz); \ + __ret; \ + }) + /* * Creates a new (reference to a) struct vgic_irq for a given LPI. * If this LPI is already mapped on another ITS, we increase its refcount @@ -42,7 +77,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid, struct kvm_vcpu *vcpu) { struct vgic_dist *dist = &kvm->arch.vgic; - struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intid), *oldirq; + struct vgic_irq *irq = vgic_get_irq(kvm, intid), *oldirq; unsigned long flags; int ret; @@ -419,7 +454,7 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu) last_byte_offset = byte_offset; } - irq = vgic_get_irq(vcpu->kvm, NULL, intid); + irq = vgic_get_irq(vcpu->kvm, intid); if (!irq) continue; @@ -573,12 +608,22 @@ static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its, lockdep_assert_held(&its->its_lock); vgic_get_irq_kref(irq); + old = xa_store(&its->translation_cache, cache_key, irq, GFP_KERNEL_ACCOUNT); + + /* + * Put the reference taken on @irq if the store fails. Intentionally do + * not return the error as the translation cache is best effort. + */ + if (xa_is_err(old)) { + vgic_put_irq(kvm, irq); + return; + } + /* * We could have raced with another CPU caching the same * translation behind our back, ensure we don't leak a * reference if that is the case. */ - old = xa_store(&its->translation_cache, cache_key, irq, GFP_KERNEL_ACCOUNT); if (old) vgic_put_irq(kvm, old); } @@ -782,6 +827,9 @@ static int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its, ite = find_ite(its, device_id, event_id); if (ite && its_is_collection_mapped(ite->collection)) { + struct its_device *device = find_its_device(its, device_id); + int ite_esz = vgic_its_get_abi(its)->ite_esz; + gpa_t gpa = device->itt_addr + ite->event_id * ite_esz; /* * Though the spec talks about removing the pending state, we * don't bother here since we clear the ITTE anyway and the @@ -790,7 +838,8 @@ static int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its, vgic_its_invalidate_cache(its); its_free_ite(kvm, ite); - return 0; + + return vgic_its_write_entry_lock(its, gpa, 0ULL, ite); } return E_ITS_DISCARD_UNMAPPED_INTERRUPT; @@ -1140,8 +1189,9 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its, u8 num_eventid_bits = its_cmd_get_size(its_cmd); gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd); struct its_device *device; + gpa_t gpa; - if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL)) + if (!vgic_its_check_id(its, its->baser_device_table, device_id, &gpa)) return E_ITS_MAPD_DEVICE_OOR; if (valid && num_eventid_bits > VITS_TYPER_IDBITS) @@ -1162,7 +1212,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its, * is an error, so we are done in any case. */ if (!valid) - return 0; + return vgic_its_write_entry_lock(its, gpa, 0ULL, dte); device = vgic_its_alloc_device(its, device_id, itt_addr, num_eventid_bits); @@ -1282,7 +1332,7 @@ int vgic_its_invall(struct kvm_vcpu *vcpu) unsigned long intid; xa_for_each(&dist->lpi_xa, intid, irq) { - irq = vgic_get_irq(kvm, NULL, intid); + irq = vgic_get_irq(kvm, intid); if (!irq) continue; @@ -1348,7 +1398,7 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its, return 0; xa_for_each(&dist->lpi_xa, intid, irq) { - irq = vgic_get_irq(kvm, NULL, intid); + irq = vgic_get_irq(kvm, intid); if (!irq) continue; @@ -2084,9 +2134,8 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz, * vgic_its_save_ite - Save an interrupt translation entry at @gpa */ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev, - struct its_ite *ite, gpa_t gpa, int ite_esz) + struct its_ite *ite, gpa_t gpa) { - struct kvm *kvm = its->dev->kvm; u32 next_offset; u64 val; @@ -2095,7 +2144,8 @@ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev, ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) | ite->collection->collection_id; val = cpu_to_le64(val); - return vgic_write_guest_lock(kvm, gpa, &val, ite_esz); + + return vgic_its_write_entry_lock(its, gpa, val, ite); } /** @@ -2195,7 +2245,7 @@ static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device) if (ite->irq->hw && !kvm_vgic_global_state.has_gicv4_1) return -EACCES; - ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz); + ret = vgic_its_save_ite(its, device, ite, gpa); if (ret) return ret; } @@ -2234,12 +2284,10 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev) * @its: ITS handle * @dev: ITS device * @ptr: GPA - * @dte_esz: device table entry size */ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev, - gpa_t ptr, int dte_esz) + gpa_t ptr) { - struct kvm *kvm = its->dev->kvm; u64 val, itt_addr_field; u32 next_offset; @@ -2250,7 +2298,8 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev, (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) | (dev->num_eventid_bits - 1)); val = cpu_to_le64(val); - return vgic_write_guest_lock(kvm, ptr, &val, dte_esz); + + return vgic_its_write_entry_lock(its, ptr, val, dte); } /** @@ -2326,10 +2375,8 @@ static int vgic_its_device_cmp(void *priv, const struct list_head *a, */ static int vgic_its_save_device_tables(struct vgic_its *its) { - const struct vgic_its_abi *abi = vgic_its_get_abi(its); u64 baser = its->baser_device_table; struct its_device *dev; - int dte_esz = abi->dte_esz; if (!(baser & GITS_BASER_VALID)) return 0; @@ -2348,7 +2395,7 @@ static int vgic_its_save_device_tables(struct vgic_its *its) if (ret) return ret; - ret = vgic_its_save_dte(its, dev, eaddr, dte_esz); + ret = vgic_its_save_dte(its, dev, eaddr); if (ret) return ret; } @@ -2429,7 +2476,7 @@ static int vgic_its_restore_device_tables(struct vgic_its *its) static int vgic_its_save_cte(struct vgic_its *its, struct its_collection *collection, - gpa_t gpa, int esz) + gpa_t gpa) { u64 val; @@ -2437,7 +2484,8 @@ static int vgic_its_save_cte(struct vgic_its *its, ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) | collection->collection_id); val = cpu_to_le64(val); - return vgic_write_guest_lock(its->dev->kvm, gpa, &val, esz); + + return vgic_its_write_entry_lock(its, gpa, val, cte); } /* @@ -2445,7 +2493,7 @@ static int vgic_its_save_cte(struct vgic_its *its, * Return +1 on success, 0 if the entry was invalid (which should be * interpreted as end-of-table), and a negative error value for generic errors. */ -static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz) +static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa) { struct its_collection *collection; struct kvm *kvm = its->dev->kvm; @@ -2453,8 +2501,7 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz) u64 val; int ret; - BUG_ON(esz > sizeof(val)); - ret = kvm_read_guest_lock(kvm, gpa, &val, esz); + ret = vgic_its_read_entry_lock(its, gpa, &val, cte); if (ret) return ret; val = le64_to_cpu(val); @@ -2492,7 +2539,6 @@ static int vgic_its_save_collection_table(struct vgic_its *its) u64 baser = its->baser_coll_table; gpa_t gpa = GITS_BASER_ADDR_48_to_52(baser); struct its_collection *collection; - u64 val; size_t max_size, filled = 0; int ret, cte_esz = abi->cte_esz; @@ -2502,7 +2548,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its) max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; list_for_each_entry(collection, &its->collection_list, coll_list) { - ret = vgic_its_save_cte(its, collection, gpa, cte_esz); + ret = vgic_its_save_cte(its, collection, gpa); if (ret) return ret; gpa += cte_esz; @@ -2516,10 +2562,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its) * table is not fully filled, add a last dummy element * with valid bit unset */ - val = 0; - BUG_ON(cte_esz > sizeof(val)); - ret = vgic_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz); - return ret; + return vgic_its_write_entry_lock(its, gpa, 0ULL, cte); } /* @@ -2544,7 +2587,7 @@ static int vgic_its_restore_collection_table(struct vgic_its *its) max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; while (read < max_size) { - ret = vgic_its_restore_cte(its, gpa, cte_esz); + ret = vgic_its_restore_cte(its, gpa); if (ret <= 0) break; gpa += cte_esz; diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v2.c b/arch/arm64/kvm/vgic/vgic-mmio-v2.c index e070cda86e12ff..f25fccb1f8e63c 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v2.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v2.c @@ -148,7 +148,7 @@ static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu, if (!(targets & (1U << c))) continue; - irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid); + irq = vgic_get_vcpu_irq(vcpu, intid); raw_spin_lock_irqsave(&irq->irq_lock, flags); irq->pending_latch = true; @@ -167,7 +167,7 @@ static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu, u64 val = 0; for (i = 0; i < len; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); val |= (u64)irq->targets << (i * 8); @@ -191,7 +191,7 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu, return; for (i = 0; i < len; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i); + struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, intid + i); int target; raw_spin_lock_irqsave(&irq->irq_lock, flags); @@ -213,7 +213,7 @@ static unsigned long vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu, u64 val = 0; for (i = 0; i < len; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); val |= (u64)irq->source << (i * 8); @@ -231,7 +231,7 @@ static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu, unsigned long flags; for (i = 0; i < len; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); @@ -253,7 +253,7 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu, unsigned long flags; for (i = 0; i < len; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index 9e50928f5d7dfd..ae4c0593d11455 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -194,7 +194,7 @@ static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len) { int intid = VGIC_ADDR_TO_INTID(addr, 64); - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid); + struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, intid); unsigned long ret = 0; if (!irq) @@ -220,7 +220,7 @@ static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu, if (addr & 4) return; - irq = vgic_get_irq(vcpu->kvm, NULL, intid); + irq = vgic_get_irq(vcpu->kvm, intid); if (!irq) return; @@ -530,6 +530,7 @@ static void vgic_mmio_write_invlpi(struct kvm_vcpu *vcpu, unsigned long val) { struct vgic_irq *irq; + u32 intid; /* * If the guest wrote only to the upper 32bit part of the @@ -541,9 +542,13 @@ static void vgic_mmio_write_invlpi(struct kvm_vcpu *vcpu, if ((addr & 4) || !vgic_lpis_enabled(vcpu)) return; + intid = lower_32_bits(val); + if (intid < VGIC_MIN_LPI) + return; + vgic_set_rdist_busy(vcpu, true); - irq = vgic_get_irq(vcpu->kvm, NULL, lower_32_bits(val)); + irq = vgic_get_irq(vcpu->kvm, intid); if (irq) { vgic_its_inv_lpi(vcpu->kvm, irq); vgic_put_irq(vcpu->kvm, irq); @@ -1020,7 +1025,7 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr) static void vgic_v3_queue_sgi(struct kvm_vcpu *vcpu, u32 sgi, bool allow_group1) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, sgi); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, sgi); unsigned long flags; raw_spin_lock_irqsave(&irq->irq_lock, flags); diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c index cf76523a219456..e416e433baff3e 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.c +++ b/arch/arm64/kvm/vgic/vgic-mmio.c @@ -50,7 +50,7 @@ unsigned long vgic_mmio_read_group(struct kvm_vcpu *vcpu, /* Loop over all IRQs affected by this read */ for (i = 0; i < len * 8; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); if (irq->group) value |= BIT(i); @@ -74,7 +74,7 @@ void vgic_mmio_write_group(struct kvm_vcpu *vcpu, gpa_t addr, unsigned long flags; for (i = 0; i < len * 8; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); irq->group = !!(val & BIT(i)); @@ -102,7 +102,7 @@ unsigned long vgic_mmio_read_enable(struct kvm_vcpu *vcpu, /* Loop over all IRQs affected by this read */ for (i = 0; i < len * 8; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); if (irq->enabled) value |= (1U << i); @@ -122,7 +122,7 @@ void vgic_mmio_write_senable(struct kvm_vcpu *vcpu, unsigned long flags; for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); if (irq->hw && vgic_irq_is_sgi(irq->intid)) { @@ -171,7 +171,7 @@ void vgic_mmio_write_cenable(struct kvm_vcpu *vcpu, unsigned long flags; for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); if (irq->hw && vgic_irq_is_sgi(irq->intid) && irq->enabled) @@ -193,7 +193,7 @@ int vgic_uaccess_write_senable(struct kvm_vcpu *vcpu, unsigned long flags; for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); irq->enabled = true; @@ -214,7 +214,7 @@ int vgic_uaccess_write_cenable(struct kvm_vcpu *vcpu, unsigned long flags; for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); irq->enabled = false; @@ -236,7 +236,7 @@ static unsigned long __read_pending(struct kvm_vcpu *vcpu, /* Loop over all IRQs affected by this read */ for (i = 0; i < len * 8; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); unsigned long flags; bool val; @@ -309,7 +309,7 @@ static void __set_pending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len, unsigned long flags; for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); /* GICD_ISPENDR0 SGI bits are WI when written from the guest. */ if (is_vgic_v2_sgi(vcpu, irq) && !is_user) { @@ -395,7 +395,7 @@ static void __clear_pending(struct kvm_vcpu *vcpu, unsigned long flags; for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); /* GICD_ICPENDR0 SGI bits are WI when written from the guest. */ if (is_vgic_v2_sgi(vcpu, irq) && !is_user) { @@ -494,7 +494,7 @@ static unsigned long __vgic_mmio_read_active(struct kvm_vcpu *vcpu, /* Loop over all IRQs affected by this read */ for (i = 0; i < len * 8; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); /* * Even for HW interrupts, don't evaluate the HW state as @@ -598,7 +598,7 @@ static void __vgic_mmio_write_cactive(struct kvm_vcpu *vcpu, int i; for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); vgic_mmio_change_active(vcpu, irq, false); vgic_put_irq(vcpu->kvm, irq); } @@ -635,7 +635,7 @@ static void __vgic_mmio_write_sactive(struct kvm_vcpu *vcpu, int i; for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); vgic_mmio_change_active(vcpu, irq, true); vgic_put_irq(vcpu->kvm, irq); } @@ -672,7 +672,7 @@ unsigned long vgic_mmio_read_priority(struct kvm_vcpu *vcpu, u64 val = 0; for (i = 0; i < len; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); val |= (u64)irq->priority << (i * 8); @@ -698,7 +698,7 @@ void vgic_mmio_write_priority(struct kvm_vcpu *vcpu, unsigned long flags; for (i = 0; i < len; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); /* Narrow the priority range to what we actually support */ @@ -719,7 +719,7 @@ unsigned long vgic_mmio_read_config(struct kvm_vcpu *vcpu, int i; for (i = 0; i < len * 4; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i); if (irq->config == VGIC_CONFIG_EDGE) value |= (2U << (i * 2)); @@ -750,7 +750,7 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu, if (intid + i < VGIC_NR_PRIVATE_IRQS) continue; - irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + irq = vgic_get_irq(vcpu->kvm, intid + i); raw_spin_lock_irqsave(&irq->irq_lock, flags); if (test_bit(i * 2 + 1, &val)) @@ -775,7 +775,7 @@ u32 vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid) if ((intid + i) < VGIC_NR_SGIS || (intid + i) >= nr_irqs) continue; - irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + irq = vgic_get_vcpu_irq(vcpu, intid + i); if (irq->config == VGIC_CONFIG_LEVEL && irq->line_level) val |= (1U << i); @@ -799,7 +799,7 @@ void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid, if ((intid + i) < VGIC_NR_SGIS || (intid + i) >= nr_irqs) continue; - irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); + irq = vgic_get_vcpu_irq(vcpu, intid + i); /* * Line level is set irrespective of irq type diff --git a/arch/arm64/kvm/vgic/vgic-v2.c b/arch/arm64/kvm/vgic/vgic-v2.c index ae5a44d5702d14..381673f03c395d 100644 --- a/arch/arm64/kvm/vgic/vgic-v2.c +++ b/arch/arm64/kvm/vgic/vgic-v2.c @@ -72,7 +72,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu) kvm_notify_acked_irq(vcpu->kvm, 0, intid - VGIC_NR_PRIVATE_IRQS); - irq = vgic_get_irq(vcpu->kvm, vcpu, intid); + irq = vgic_get_vcpu_irq(vcpu, intid); raw_spin_lock(&irq->irq_lock); diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c index b217b256853c2a..f267bc2486a18e 100644 --- a/arch/arm64/kvm/vgic/vgic-v3.c +++ b/arch/arm64/kvm/vgic/vgic-v3.c @@ -65,7 +65,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu) kvm_notify_acked_irq(vcpu->kvm, 0, intid - VGIC_NR_PRIVATE_IRQS); - irq = vgic_get_irq(vcpu->kvm, vcpu, intid); + irq = vgic_get_vcpu_irq(vcpu, intid); if (!irq) /* An LPI could have been unmapped. */ continue; diff --git a/arch/arm64/kvm/vgic/vgic-v4.c b/arch/arm64/kvm/vgic/vgic-v4.c index 74a67ad87f29de..eedecbbbcf31bb 100644 --- a/arch/arm64/kvm/vgic/vgic-v4.c +++ b/arch/arm64/kvm/vgic/vgic-v4.c @@ -123,7 +123,7 @@ static void vgic_v4_enable_vsgis(struct kvm_vcpu *vcpu) * IRQ. The SGI code will do its magic. */ for (i = 0; i < VGIC_NR_SGIS; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, i); struct irq_desc *desc; unsigned long flags; int ret; @@ -160,7 +160,7 @@ static void vgic_v4_disable_vsgis(struct kvm_vcpu *vcpu) int i; for (i = 0; i < VGIC_NR_SGIS; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, i); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, i); struct irq_desc *desc; unsigned long flags; int ret; diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index f50274fd558156..cc8c6b9b5dd8b1 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -84,17 +84,11 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid) * struct vgic_irq. It also increases the refcount, so any caller is expected * to call vgic_put_irq() once it's finished with this IRQ. */ -struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu, - u32 intid) +struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid) { - /* SGIs and PPIs */ - if (intid <= VGIC_MAX_PRIVATE) { - intid = array_index_nospec(intid, VGIC_MAX_PRIVATE + 1); - return &vcpu->arch.vgic_cpu.private_irqs[intid]; - } - /* SPIs */ - if (intid < (kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)) { + if (intid >= VGIC_NR_PRIVATE_IRQS && + intid < (kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)) { intid = array_index_nospec(intid, kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS); return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS]; } @@ -106,6 +100,20 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu, return NULL; } +struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid) +{ + if (WARN_ON(!vcpu)) + return NULL; + + /* SGIs and PPIs */ + if (intid < VGIC_NR_PRIVATE_IRQS) { + intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS); + return &vcpu->arch.vgic_cpu.private_irqs[intid]; + } + + return vgic_get_irq(vcpu->kvm, intid); +} + /* * We can't do anything in here, because we lack the kvm pointer to * lock and remove the item from the lpi_list. So we keep this function @@ -437,7 +445,10 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu, trace_vgic_update_irq_pending(vcpu ? vcpu->vcpu_idx : 0, intid, level); - irq = vgic_get_irq(kvm, vcpu, intid); + if (intid < VGIC_NR_PRIVATE_IRQS) + irq = vgic_get_vcpu_irq(vcpu, intid); + else + irq = vgic_get_irq(kvm, intid); if (!irq) return -EINVAL; @@ -499,7 +510,7 @@ static inline void kvm_vgic_unmap_irq(struct vgic_irq *irq) int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq, u32 vintid, struct irq_ops *ops) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, vintid); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, vintid); unsigned long flags; int ret; @@ -524,7 +535,7 @@ int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq, */ void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, vintid); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, vintid); unsigned long flags; if (!irq->hw) @@ -547,7 +558,7 @@ int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid) if (!vgic_initialized(vcpu->kvm)) return -EAGAIN; - irq = vgic_get_irq(vcpu->kvm, vcpu, vintid); + irq = vgic_get_vcpu_irq(vcpu, vintid); BUG_ON(!irq); raw_spin_lock_irqsave(&irq->irq_lock, flags); @@ -560,7 +571,7 @@ int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid) int kvm_vgic_get_map(struct kvm_vcpu *vcpu, unsigned int vintid) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, vintid); + struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, vintid); unsigned long flags; int ret = -1; @@ -596,7 +607,7 @@ int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner) if (!irq_is_ppi(intid) && !vgic_valid_spi(vcpu->kvm, intid)) return -EINVAL; - irq = vgic_get_irq(vcpu->kvm, vcpu, intid); + irq = vgic_get_vcpu_irq(vcpu, intid); raw_spin_lock_irqsave(&irq->irq_lock, flags); if (irq->owner && irq->owner != owner) ret = -EEXIST; @@ -1008,7 +1019,7 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int vintid) if (!vgic_initialized(vcpu->kvm)) return false; - irq = vgic_get_irq(vcpu->kvm, vcpu, vintid); + irq = vgic_get_vcpu_irq(vcpu, vintid); raw_spin_lock_irqsave(&irq->irq_lock, flags); map_is_active = irq->hw && irq->active; raw_spin_unlock_irqrestore(&irq->irq_lock, flags); diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index f2486b4d9f9566..122d95b4e2845a 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -179,8 +179,8 @@ int vgic_v2_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, const struct vgic_register_region * vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev, gpa_t addr, int len); -struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu, - u32 intid); +struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid); +struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid); void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq); bool vgic_get_phys_line_level(struct vgic_irq *irq); void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending); diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile index 13e6a2829116ca..8e882f479d9814 100644 --- a/arch/arm64/lib/Makefile +++ b/arch/arm64/lib/Makefile @@ -13,7 +13,7 @@ endif lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o -obj-$(CONFIG_CRC32) += crc32.o +obj-$(CONFIG_CRC32) += crc32.o crc32-glue.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S index ebde40e7fa2b2f..bd6f7d5eb6eb65 100644 --- a/arch/arm64/lib/clear_page.S +++ b/arch/arm64/lib/clear_page.S @@ -15,6 +15,19 @@ * x0 - dest */ SYM_FUNC_START(__pi_clear_page) +#ifdef CONFIG_AS_HAS_MOPS + .arch_extension mops +alternative_if_not ARM64_HAS_MOPS + b .Lno_mops +alternative_else_nop_endif + + mov x1, #PAGE_SIZE + setpn [x0]!, x1!, xzr + setmn [x0]!, x1!, xzr + seten [x0]!, x1!, xzr + ret +.Lno_mops: +#endif mrs x1, dczid_el0 tbnz x1, #4, 2f /* Branch if DC ZVA is prohibited */ and w1, w1, #0xf diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S index 6a56d7cf309da5..e6374e7e55110f 100644 --- a/arch/arm64/lib/copy_page.S +++ b/arch/arm64/lib/copy_page.S @@ -18,6 +18,19 @@ * x1 - src */ SYM_FUNC_START(__pi_copy_page) +#ifdef CONFIG_AS_HAS_MOPS + .arch_extension mops +alternative_if_not ARM64_HAS_MOPS + b .Lno_mops +alternative_else_nop_endif + + mov x2, #PAGE_SIZE + cpypwn [x0]!, [x1]!, x2! + cpymwn [x0]!, [x1]!, x2! + cpyewn [x0]!, [x1]!, x2! + ret +.Lno_mops: +#endif ldp x2, x3, [x1] ldp x4, x5, [x1, #16] ldp x6, x7, [x1, #32] diff --git a/arch/arm64/lib/crc32-glue.c b/arch/arm64/lib/crc32-glue.c new file mode 100644 index 00000000000000..295ae3e6b997ad --- /dev/null +++ b/arch/arm64/lib/crc32-glue.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +#include +#include +#include +#include + +#include + +// The minimum input length to consider the 4-way interleaved code path +static const size_t min_len = 1024; + +asmlinkage u32 crc32_le_arm64(u32 crc, unsigned char const *p, size_t len); +asmlinkage u32 crc32c_le_arm64(u32 crc, unsigned char const *p, size_t len); +asmlinkage u32 crc32_be_arm64(u32 crc, unsigned char const *p, size_t len); + +asmlinkage u32 crc32_le_arm64_4way(u32 crc, unsigned char const *p, size_t len); +asmlinkage u32 crc32c_le_arm64_4way(u32 crc, unsigned char const *p, size_t len); +asmlinkage u32 crc32_be_arm64_4way(u32 crc, unsigned char const *p, size_t len); + +u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len) +{ + if (!alternative_has_cap_likely(ARM64_HAS_CRC32)) + return crc32_le_base(crc, p, len); + + if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) { + kernel_neon_begin(); + crc = crc32_le_arm64_4way(crc, p, len); + kernel_neon_end(); + + p += round_down(len, 64); + len %= 64; + + if (!len) + return crc; + } + + return crc32_le_arm64(crc, p, len); +} + +u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len) +{ + if (!alternative_has_cap_likely(ARM64_HAS_CRC32)) + return __crc32c_le_base(crc, p, len); + + if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) { + kernel_neon_begin(); + crc = crc32c_le_arm64_4way(crc, p, len); + kernel_neon_end(); + + p += round_down(len, 64); + len %= 64; + + if (!len) + return crc; + } + + return crc32c_le_arm64(crc, p, len); +} + +u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len) +{ + if (!alternative_has_cap_likely(ARM64_HAS_CRC32)) + return crc32_be_base(crc, p, len); + + if (len >= min_len && cpu_have_named_feature(PMULL) && crypto_simd_usable()) { + kernel_neon_begin(); + crc = crc32_be_arm64_4way(crc, p, len); + kernel_neon_end(); + + p += round_down(len, 64); + len %= 64; + + if (!len) + return crc; + } + + return crc32_be_arm64(crc, p, len); +} diff --git a/arch/arm64/lib/crc32.S b/arch/arm64/lib/crc32.S index 8340dccff46ff9..68825317460fc6 100644 --- a/arch/arm64/lib/crc32.S +++ b/arch/arm64/lib/crc32.S @@ -1,54 +1,60 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Accelerated CRC32(C) using AArch64 CRC instructions + * Accelerated CRC32(C) using AArch64 CRC and PMULL instructions * - * Copyright (C) 2016 - 2018 Linaro Ltd + * Copyright (C) 2016 - 2018 Linaro Ltd. + * Copyright (C) 2024 Google LLC + * + * Author: Ard Biesheuvel */ #include -#include #include - .arch armv8-a+crc + .cpu generic+crc+crypto - .macro byteorder, reg, be - .if \be -CPU_LE( rev \reg, \reg ) - .else -CPU_BE( rev \reg, \reg ) - .endif + .macro bitle, reg .endm - .macro byteorder16, reg, be - .if \be -CPU_LE( rev16 \reg, \reg ) - .else -CPU_BE( rev16 \reg, \reg ) - .endif + .macro bitbe, reg + rbit \reg, \reg .endm - .macro bitorder, reg, be - .if \be - rbit \reg, \reg - .endif + .macro bytele, reg .endm - .macro bitorder16, reg, be - .if \be + .macro bytebe, reg rbit \reg, \reg - lsr \reg, \reg, #16 - .endif + lsr \reg, \reg, #24 .endm - .macro bitorder8, reg, be - .if \be + .macro hwordle, reg +CPU_BE( rev16 \reg, \reg ) + .endm + + .macro hwordbe, reg +CPU_LE( rev \reg, \reg ) rbit \reg, \reg - lsr \reg, \reg, #24 - .endif +CPU_BE( lsr \reg, \reg, #16 ) + .endm + + .macro le, regs:vararg + .irp r, \regs +CPU_BE( rev \r, \r ) + .endr .endm - .macro __crc32, c, be=0 - bitorder w0, \be + .macro be, regs:vararg + .irp r, \regs +CPU_LE( rev \r, \r ) + .endr + .irp r, \regs + rbit \r, \r + .endr + .endm + + .macro __crc32, c, order=le + bit\order w0 cmp x2, #16 b.lt 8f // less than 16 bytes @@ -61,14 +67,7 @@ CPU_BE( rev16 \reg, \reg ) add x8, x8, x1 add x1, x1, x7 ldp x5, x6, [x8] - byteorder x3, \be - byteorder x4, \be - byteorder x5, \be - byteorder x6, \be - bitorder x3, \be - bitorder x4, \be - bitorder x5, \be - bitorder x6, \be + \order x3, x4, x5, x6 tst x7, #8 crc32\c\()x w8, w0, x3 @@ -96,65 +95,268 @@ CPU_BE( rev16 \reg, \reg ) 32: ldp x3, x4, [x1], #32 sub x2, x2, #32 ldp x5, x6, [x1, #-16] - byteorder x3, \be - byteorder x4, \be - byteorder x5, \be - byteorder x6, \be - bitorder x3, \be - bitorder x4, \be - bitorder x5, \be - bitorder x6, \be + \order x3, x4, x5, x6 crc32\c\()x w0, w0, x3 crc32\c\()x w0, w0, x4 crc32\c\()x w0, w0, x5 crc32\c\()x w0, w0, x6 cbnz x2, 32b -0: bitorder w0, \be +0: bit\order w0 ret 8: tbz x2, #3, 4f ldr x3, [x1], #8 - byteorder x3, \be - bitorder x3, \be + \order x3 crc32\c\()x w0, w0, x3 4: tbz x2, #2, 2f ldr w3, [x1], #4 - byteorder w3, \be - bitorder w3, \be + \order w3 crc32\c\()w w0, w0, w3 2: tbz x2, #1, 1f ldrh w3, [x1], #2 - byteorder16 w3, \be - bitorder16 w3, \be + hword\order w3 crc32\c\()h w0, w0, w3 1: tbz x2, #0, 0f ldrb w3, [x1] - bitorder8 w3, \be + byte\order w3 crc32\c\()b w0, w0, w3 -0: bitorder w0, \be +0: bit\order w0 ret .endm .align 5 -SYM_FUNC_START(crc32_le) -alternative_if_not ARM64_HAS_CRC32 - b crc32_le_base -alternative_else_nop_endif +SYM_FUNC_START(crc32_le_arm64) __crc32 -SYM_FUNC_END(crc32_le) +SYM_FUNC_END(crc32_le_arm64) .align 5 -SYM_FUNC_START(__crc32c_le) -alternative_if_not ARM64_HAS_CRC32 - b __crc32c_le_base -alternative_else_nop_endif +SYM_FUNC_START(crc32c_le_arm64) __crc32 c -SYM_FUNC_END(__crc32c_le) +SYM_FUNC_END(crc32c_le_arm64) .align 5 -SYM_FUNC_START(crc32_be) -alternative_if_not ARM64_HAS_CRC32 - b crc32_be_base -alternative_else_nop_endif - __crc32 be=1 -SYM_FUNC_END(crc32_be) +SYM_FUNC_START(crc32_be_arm64) + __crc32 order=be +SYM_FUNC_END(crc32_be_arm64) + + in .req x1 + len .req x2 + + /* + * w0: input CRC at entry, output CRC at exit + * x1: pointer to input buffer + * x2: length of input in bytes + */ + .macro crc4way, insn, table, order=le + bit\order w0 + lsr len, len, #6 // len := # of 64-byte blocks + + /* Process up to 64 blocks of 64 bytes at a time */ +.La\@: mov x3, #64 + cmp len, #64 + csel x3, x3, len, hi // x3 := min(len, 64) + sub len, len, x3 + + /* Divide the input into 4 contiguous blocks */ + add x4, x3, x3, lsl #1 // x4 := 3 * x3 + add x7, in, x3, lsl #4 // x7 := in + 16 * x3 + add x8, in, x3, lsl #5 // x8 := in + 32 * x3 + add x9, in, x4, lsl #4 // x9 := in + 16 * x4 + + /* Load the folding coefficients from the lookup table */ + adr_l x5, \table - 12 // entry 0 omitted + add x5, x5, x4, lsl #2 // x5 += 12 * x3 + ldp s0, s1, [x5] + ldr s2, [x5, #8] + + /* Zero init partial CRCs for this iteration */ + mov w4, wzr + mov w5, wzr + mov w6, wzr + mov x17, xzr + +.Lb\@: sub x3, x3, #1 + \insn w6, w6, x17 + ldp x10, x11, [in], #16 + ldp x12, x13, [x7], #16 + ldp x14, x15, [x8], #16 + ldp x16, x17, [x9], #16 + + \order x10, x11, x12, x13, x14, x15, x16, x17 + + /* Apply the CRC transform to 4 16-byte blocks in parallel */ + \insn w0, w0, x10 + \insn w4, w4, x12 + \insn w5, w5, x14 + \insn w6, w6, x16 + \insn w0, w0, x11 + \insn w4, w4, x13 + \insn w5, w5, x15 + cbnz x3, .Lb\@ + + /* Combine the 4 partial results into w0 */ + mov v3.d[0], x0 + mov v4.d[0], x4 + mov v5.d[0], x5 + pmull v0.1q, v0.1d, v3.1d + pmull v1.1q, v1.1d, v4.1d + pmull v2.1q, v2.1d, v5.1d + eor v0.8b, v0.8b, v1.8b + eor v0.8b, v0.8b, v2.8b + mov x5, v0.d[0] + eor x5, x5, x17 + \insn w0, w6, x5 + + mov in, x9 + cbnz len, .La\@ + + bit\order w0 + ret + .endm + + .align 5 +SYM_FUNC_START(crc32c_le_arm64_4way) + crc4way crc32cx, .L0 +SYM_FUNC_END(crc32c_le_arm64_4way) + + .align 5 +SYM_FUNC_START(crc32_le_arm64_4way) + crc4way crc32x, .L1 +SYM_FUNC_END(crc32_le_arm64_4way) + + .align 5 +SYM_FUNC_START(crc32_be_arm64_4way) + crc4way crc32x, .L1, be +SYM_FUNC_END(crc32_be_arm64_4way) + + .section .rodata, "a", %progbits + .align 6 +.L0: .long 0xddc0152b, 0xba4fc28e, 0x493c7d27 + .long 0x0715ce53, 0x9e4addf8, 0xba4fc28e + .long 0xc96cfdc0, 0x0715ce53, 0xddc0152b + .long 0xab7aff2a, 0x0d3b6092, 0x9e4addf8 + .long 0x299847d5, 0x878a92a7, 0x39d3b296 + .long 0xb6dd949b, 0xab7aff2a, 0x0715ce53 + .long 0xa60ce07b, 0x83348832, 0x47db8317 + .long 0xd270f1a2, 0xb9e02b86, 0x0d3b6092 + .long 0x65863b64, 0xb6dd949b, 0xc96cfdc0 + .long 0xb3e32c28, 0xbac2fd7b, 0x878a92a7 + .long 0xf285651c, 0xce7f39f4, 0xdaece73e + .long 0x271d9844, 0xd270f1a2, 0xab7aff2a + .long 0x6cb08e5c, 0x2b3cac5d, 0x2162d385 + .long 0xcec3662e, 0x1b03397f, 0x83348832 + .long 0x8227bb8a, 0xb3e32c28, 0x299847d5 + .long 0xd7a4825c, 0xdd7e3b0c, 0xb9e02b86 + .long 0xf6076544, 0x10746f3c, 0x18b33a4e + .long 0x98d8d9cb, 0x271d9844, 0xb6dd949b + .long 0x57a3d037, 0x93a5f730, 0x78d9ccb7 + .long 0x3771e98f, 0x6b749fb2, 0xbac2fd7b + .long 0xe0ac139e, 0xcec3662e, 0xa60ce07b + .long 0x6f345e45, 0xe6fc4e6a, 0xce7f39f4 + .long 0xa2b73df1, 0xb0cd4768, 0x61d82e56 + .long 0x86d8e4d2, 0xd7a4825c, 0xd270f1a2 + .long 0xa90fd27a, 0x0167d312, 0xc619809d + .long 0xca6ef3ac, 0x26f6a60a, 0x2b3cac5d + .long 0x4597456a, 0x98d8d9cb, 0x65863b64 + .long 0xc9c8b782, 0x68bce87a, 0x1b03397f + .long 0x62ec6c6d, 0x6956fc3b, 0xebb883bd + .long 0x2342001e, 0x3771e98f, 0xb3e32c28 + .long 0xe8b6368b, 0x2178513a, 0x064f7f26 + .long 0x9ef68d35, 0x170076fa, 0xdd7e3b0c + .long 0x0b0bf8ca, 0x6f345e45, 0xf285651c + .long 0x02ee03b2, 0xff0dba97, 0x10746f3c + .long 0x135c83fd, 0xf872e54c, 0xc7a68855 + .long 0x00bcf5f6, 0x86d8e4d2, 0x271d9844 + .long 0x58ca5f00, 0x5bb8f1bc, 0x8e766a0c + .long 0xded288f8, 0xb3af077a, 0x93a5f730 + .long 0x37170390, 0xca6ef3ac, 0x6cb08e5c + .long 0xf48642e9, 0xdd66cbbb, 0x6b749fb2 + .long 0xb25b29f2, 0xe9e28eb4, 0x1393e203 + .long 0x45cddf4e, 0xc9c8b782, 0xcec3662e + .long 0xdfd94fb2, 0x93e106a4, 0x96c515bb + .long 0x021ac5ef, 0xd813b325, 0xe6fc4e6a + .long 0x8e1450f7, 0x2342001e, 0x8227bb8a + .long 0xe0cdcf86, 0x6d9a4957, 0xb0cd4768 + .long 0x613eee91, 0xd2c3ed1a, 0x39c7ff35 + .long 0xbedc6ba1, 0x9ef68d35, 0xd7a4825c + .long 0x0cd1526a, 0xf2271e60, 0x0ab3844b + .long 0xd6c3a807, 0x2664fd8b, 0x0167d312 + .long 0x1d31175f, 0x02ee03b2, 0xf6076544 + .long 0x4be7fd90, 0x363bd6b3, 0x26f6a60a + .long 0x6eeed1c9, 0x5fabe670, 0xa741c1bf + .long 0xb3a6da94, 0x00bcf5f6, 0x98d8d9cb + .long 0x2e7d11a7, 0x17f27698, 0x49c3cc9c + .long 0x889774e1, 0xaa7c7ad5, 0x68bce87a + .long 0x8a074012, 0xded288f8, 0x57a3d037 + .long 0xbd0bb25f, 0x6d390dec, 0x6956fc3b + .long 0x3be3c09b, 0x6353c1cc, 0x42d98888 + .long 0x465a4eee, 0xf48642e9, 0x3771e98f + .long 0x2e5f3c8c, 0xdd35bc8d, 0xb42ae3d9 + .long 0xa52f58ec, 0x9a5ede41, 0x2178513a + .long 0x47972100, 0x45cddf4e, 0xe0ac139e + .long 0x359674f7, 0xa51b6135, 0x170076fa + +.L1: .long 0xaf449247, 0x81256527, 0xccaa009e + .long 0x57c54819, 0x1d9513d7, 0x81256527 + .long 0x3f41287a, 0x57c54819, 0xaf449247 + .long 0xf5e48c85, 0x910eeec1, 0x1d9513d7 + .long 0x1f0c2cdd, 0x9026d5b1, 0xae0b5394 + .long 0x71d54a59, 0xf5e48c85, 0x57c54819 + .long 0x1c63267b, 0xfe807bbd, 0x0cbec0ed + .long 0xd31343ea, 0xe95c1271, 0x910eeec1 + .long 0xf9d9c7ee, 0x71d54a59, 0x3f41287a + .long 0x9ee62949, 0xcec97417, 0x9026d5b1 + .long 0xa55d1514, 0xf183c71b, 0xd1df2327 + .long 0x21aa2b26, 0xd31343ea, 0xf5e48c85 + .long 0x9d842b80, 0xeea395c4, 0x3c656ced + .long 0xd8110ff1, 0xcd669a40, 0xfe807bbd + .long 0x3f9e9356, 0x9ee62949, 0x1f0c2cdd + .long 0x1d6708a0, 0x0c30f51d, 0xe95c1271 + .long 0xef82aa68, 0xdb3935ea, 0xb918a347 + .long 0xd14bcc9b, 0x21aa2b26, 0x71d54a59 + .long 0x99cce860, 0x356d209f, 0xff6f2fc2 + .long 0xd8af8e46, 0xc352f6de, 0xcec97417 + .long 0xf1996890, 0xd8110ff1, 0x1c63267b + .long 0x631bc508, 0xe95c7216, 0xf183c71b + .long 0x8511c306, 0x8e031a19, 0x9b9bdbd0 + .long 0xdb3839f3, 0x1d6708a0, 0xd31343ea + .long 0x7a92fffb, 0xf7003835, 0x4470ac44 + .long 0x6ce68f2a, 0x00eba0c8, 0xeea395c4 + .long 0x4caaa263, 0xd14bcc9b, 0xf9d9c7ee + .long 0xb46f7cff, 0x9a1b53c8, 0xcd669a40 + .long 0x60290934, 0x81b6f443, 0x6d40f445 + .long 0x8e976a7d, 0xd8af8e46, 0x9ee62949 + .long 0xdcf5088a, 0x9dbdc100, 0x145575d5 + .long 0x1753ab84, 0xbbf2f6d6, 0x0c30f51d + .long 0x255b139e, 0x631bc508, 0xa55d1514 + .long 0xd784eaa8, 0xce26786c, 0xdb3935ea + .long 0x6d2c864a, 0x8068c345, 0x2586d334 + .long 0x02072e24, 0xdb3839f3, 0x21aa2b26 + .long 0x06689b0a, 0x5efd72f5, 0xe0575528 + .long 0x1e52f5ea, 0x4117915b, 0x356d209f + .long 0x1d3d1db6, 0x6ce68f2a, 0x9d842b80 + .long 0x3796455c, 0xb8e0e4a8, 0xc352f6de + .long 0xdf3a4eb3, 0xc55a2330, 0xb84ffa9c + .long 0x28ae0976, 0xb46f7cff, 0xd8110ff1 + .long 0x9764bc8d, 0xd7e7a22c, 0x712510f0 + .long 0x13a13e18, 0x3e9a43cd, 0xe95c7216 + .long 0xb8ee242e, 0x8e976a7d, 0x3f9e9356 + .long 0x0c540e7b, 0x753c81ff, 0x8e031a19 + .long 0x9924c781, 0xb9220208, 0x3edcde65 + .long 0x3954de39, 0x1753ab84, 0x1d6708a0 + .long 0xf32238b5, 0xbec81497, 0x9e70b943 + .long 0xbbd2cd2c, 0x0925d861, 0xf7003835 + .long 0xcc401304, 0xd784eaa8, 0xef82aa68 + .long 0x4987e684, 0x6044fbb0, 0x00eba0c8 + .long 0x3aa11427, 0x18fe3b4a, 0x87441142 + .long 0x297aad60, 0x02072e24, 0xd14bcc9b + .long 0xf60c5e51, 0x6ef6f487, 0x5b7fdd0a + .long 0x632d78c5, 0x3fc33de4, 0x9a1b53c8 + .long 0x25b8822a, 0x1e52f5ea, 0x99cce860 + .long 0xd4fc84bc, 0x1af62fb8, 0x81b6f443 + .long 0x5690aa32, 0xa91fdefb, 0x688a110e + .long 0x1357a093, 0x3796455c, 0xd8af8e46 + .long 0x798fdd33, 0xaaa18a37, 0x357b9517 + .long 0xc2815395, 0x54d42691, 0x9dbdc100 + .long 0x21cfc0f7, 0x28ae0976, 0xf1996890 + .long 0xa0decef3, 0x7b4aa8b7, 0xbbf2f6d6 diff --git a/arch/arm64/lib/memcpy.S b/arch/arm64/lib/memcpy.S index 4ab48d49c45156..9b99106fb95f1c 100644 --- a/arch/arm64/lib/memcpy.S +++ b/arch/arm64/lib/memcpy.S @@ -57,7 +57,7 @@ The loop tail is handled by always copying 64 bytes from the end. */ -SYM_FUNC_START(__pi_memcpy) +SYM_FUNC_START_LOCAL(__pi_memcpy_generic) add srcend, src, count add dstend, dstin, count cmp count, 128 @@ -238,7 +238,24 @@ L(copy64_from_start): stp B_l, B_h, [dstin, 16] stp C_l, C_h, [dstin] ret +SYM_FUNC_END(__pi_memcpy_generic) + +#ifdef CONFIG_AS_HAS_MOPS + .arch_extension mops +SYM_FUNC_START(__pi_memcpy) +alternative_if_not ARM64_HAS_MOPS + b __pi_memcpy_generic +alternative_else_nop_endif + + mov dst, dstin + cpyp [dst]!, [src]!, count! + cpym [dst]!, [src]!, count! + cpye [dst]!, [src]!, count! + ret SYM_FUNC_END(__pi_memcpy) +#else +SYM_FUNC_ALIAS(__pi_memcpy, __pi_memcpy_generic) +#endif SYM_FUNC_ALIAS(__memcpy, __pi_memcpy) EXPORT_SYMBOL(__memcpy) diff --git a/arch/arm64/lib/memset.S b/arch/arm64/lib/memset.S index a5aebe82ad73b9..97157da65ec6b6 100644 --- a/arch/arm64/lib/memset.S +++ b/arch/arm64/lib/memset.S @@ -26,6 +26,7 @@ */ dstin .req x0 +val_x .req x1 val .req w1 count .req x2 tmp1 .req x3 @@ -42,7 +43,7 @@ dst .req x8 tmp3w .req w9 tmp3 .req x9 -SYM_FUNC_START(__pi_memset) +SYM_FUNC_START_LOCAL(__pi_memset_generic) mov dst, dstin /* Preserve return value. */ and A_lw, val, #255 orr A_lw, A_lw, A_lw, lsl #8 @@ -201,7 +202,24 @@ SYM_FUNC_START(__pi_memset) ands count, count, zva_bits_x b.ne .Ltail_maybe_long ret +SYM_FUNC_END(__pi_memset_generic) + +#ifdef CONFIG_AS_HAS_MOPS + .arch_extension mops +SYM_FUNC_START(__pi_memset) +alternative_if_not ARM64_HAS_MOPS + b __pi_memset_generic +alternative_else_nop_endif + + mov dst, dstin + setp [dst]!, count!, val_x + setm [dst]!, count!, val_x + sete [dst]!, count!, val_x + ret SYM_FUNC_END(__pi_memset) +#else +SYM_FUNC_ALIAS(__pi_memset, __pi_memset_generic) +#endif SYM_FUNC_ALIAS(__memset, __pi_memset) EXPORT_SYMBOL(__memset) diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile index 2fc8c6dd04070b..fc92170a8f377c 100644 --- a/arch/arm64/mm/Makefile +++ b/arch/arm64/mm/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_TRANS_TABLE) += trans_pgd.o obj-$(CONFIG_TRANS_TABLE) += trans_pgd-asm.o obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o obj-$(CONFIG_ARM64_MTE) += mteswap.o +obj-$(CONFIG_ARM64_GCS) += gcs.o KASAN_SANITIZE_physaddr.o += n obj-$(CONFIG_KASAN) += kasan_init.o diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index 188197590fc9ce..b2ac062463273f 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -32,9 +32,9 @@ static unsigned long nr_pinned_asids; static unsigned long *pinned_asid_map; #define ASID_MASK (~GENMASK(asid_bits - 1, 0)) -#define ASID_FIRST_VERSION (1UL << asid_bits) +#define ASID_FIRST_VERSION (1UL << 16) -#define NUM_USER_ASIDS ASID_FIRST_VERSION +#define NUM_USER_ASIDS (1UL << asid_bits) #define ctxid2asid(asid) ((asid) & ~ASID_MASK) #define asid2ctxid(asid, genid) ((asid) | (genid)) diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c index a7bb20055ce094..a86c897017df08 100644 --- a/arch/arm64/mm/copypage.c +++ b/arch/arm64/mm/copypage.c @@ -18,15 +18,42 @@ void copy_highpage(struct page *to, struct page *from) { void *kto = page_address(to); void *kfrom = page_address(from); + struct folio *src = page_folio(from); + struct folio *dst = page_folio(to); + unsigned int i, nr_pages; copy_page(kto, kfrom); if (kasan_hw_tags_enabled()) page_kasan_tag_reset(to); - if (system_supports_mte() && page_mte_tagged(from)) { + if (!system_supports_mte()) + return; + + if (folio_test_hugetlb(src)) { + if (!folio_test_hugetlb_mte_tagged(src) || + from != folio_page(src, 0)) + return; + + WARN_ON_ONCE(!folio_try_hugetlb_mte_tagging(dst)); + + /* + * Populate tags for all subpages. + * + * Don't assume the first page is head page since + * huge page copy may start from any subpage. + */ + nr_pages = folio_nr_pages(src); + for (i = 0; i < nr_pages; i++) { + kfrom = page_address(folio_page(src, i)); + kto = page_address(folio_page(dst, i)); + mte_copy_page_tags(kto, kfrom); + } + folio_set_hugetlb_mte_tagged(dst); + } else if (page_mte_tagged(from)) { /* 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); set_page_mte_tagged(to); } diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 8b281cf308b30f..ef63651099a9dc 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -504,6 +504,14 @@ static bool fault_from_pkey(unsigned long esr, struct vm_area_struct *vma, false); } +static bool is_gcs_fault(unsigned long esr) +{ + if (!esr_is_data_abort(esr)) + return false; + + return ESR_ELx_ISS2(esr) & ESR_ELx_GCS; +} + static bool is_el0_instruction_abort(unsigned long esr) { return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_LOW; @@ -518,6 +526,23 @@ static bool is_write_abort(unsigned long esr) return (esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM); } +static bool is_invalid_gcs_access(struct vm_area_struct *vma, u64 esr) +{ + if (!system_supports_gcs()) + return false; + + if (unlikely(is_gcs_fault(esr))) { + /* GCS accesses must be performed on a GCS page */ + if (!(vma->vm_flags & VM_SHADOW_STACK)) + return true; + } else if (unlikely(vma->vm_flags & VM_SHADOW_STACK)) { + /* Only GCS operations can write to a GCS page */ + return esr_is_data_abort(esr) && is_write_abort(esr); + } + + return false; +} + static int __kprobes do_page_fault(unsigned long far, unsigned long esr, struct pt_regs *regs) { @@ -554,6 +579,14 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr, /* It was exec fault */ vm_flags = VM_EXEC; mm_flags |= FAULT_FLAG_INSTRUCTION; + } else if (is_gcs_fault(esr)) { + /* + * The GCS permission on a page implies both read and + * write so always handle any GCS fault as a write fault, + * we need to trigger CoW even for GCS reads. + */ + vm_flags = VM_WRITE; + mm_flags |= FAULT_FLAG_WRITE; } else if (is_write_abort(esr)) { /* It was write fault */ vm_flags = VM_WRITE; @@ -587,6 +620,13 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr, if (!vma) goto lock_mmap; + if (is_invalid_gcs_access(vma, esr)) { + vma_end_read(vma); + fault = 0; + si_code = SEGV_ACCERR; + goto bad_area; + } + if (!(vma->vm_flags & vm_flags)) { vma_end_read(vma); fault = 0; @@ -983,7 +1023,7 @@ struct folio *vma_alloc_zeroed_movable_folio(struct vm_area_struct *vma, if (vma->vm_flags & VM_MTE) flags |= __GFP_ZEROTAGS; - return vma_alloc_folio(flags, 0, vma, vaddr, false); + return vma_alloc_folio(flags, 0, vma, vaddr); } void tag_clear_highpage(struct page *page) diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c index de1e09d986ad23..c5c5425791da72 100644 --- a/arch/arm64/mm/fixmap.c +++ b/arch/arm64/mm/fixmap.c @@ -47,7 +47,8 @@ static void __init early_fixmap_init_pte(pmd_t *pmdp, unsigned long addr) if (pmd_none(pmd)) { ptep = bm_pte[BM_PTE_TABLE_IDX(addr)]; - __pmd_populate(pmdp, __pa_symbol(ptep), PMD_TYPE_TABLE); + __pmd_populate(pmdp, __pa_symbol(ptep), + PMD_TYPE_TABLE | PMD_TABLE_AF); } } @@ -59,7 +60,8 @@ static void __init early_fixmap_init_pmd(pud_t *pudp, unsigned long addr, pmd_t *pmdp; if (pud_none(pud)) - __pud_populate(pudp, __pa_symbol(bm_pmd), PUD_TYPE_TABLE); + __pud_populate(pudp, __pa_symbol(bm_pmd), + PUD_TYPE_TABLE | PUD_TABLE_AF); pmdp = pmd_offset_kimg(pudp, addr); do { @@ -86,7 +88,8 @@ static void __init early_fixmap_init_pud(p4d_t *p4dp, unsigned long addr, } if (p4d_none(p4d)) - __p4d_populate(p4dp, __pa_symbol(bm_pud), P4D_TYPE_TABLE); + __p4d_populate(p4dp, __pa_symbol(bm_pud), + P4D_TYPE_TABLE | P4D_TABLE_AF); pudp = pud_offset_kimg(p4dp, addr); early_fixmap_init_pmd(pudp, addr, end); diff --git a/arch/arm64/mm/gcs.c b/arch/arm64/mm/gcs.c new file mode 100644 index 00000000000000..5c46ec527b1cda --- /dev/null +++ b/arch/arm64/mm/gcs.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include + +#include +#include +#include +#include + +static unsigned long alloc_gcs(unsigned long addr, unsigned long size) +{ + int flags = MAP_ANONYMOUS | MAP_PRIVATE; + struct mm_struct *mm = current->mm; + unsigned long mapped_addr, unused; + + if (addr) + flags |= MAP_FIXED_NOREPLACE; + + mmap_write_lock(mm); + mapped_addr = do_mmap(NULL, addr, size, PROT_READ, flags, + VM_SHADOW_STACK | VM_WRITE, 0, &unused, NULL); + mmap_write_unlock(mm); + + return mapped_addr; +} + +static unsigned long gcs_size(unsigned long size) +{ + if (size) + return PAGE_ALIGN(size); + + /* Allocate RLIMIT_STACK/2 with limits of PAGE_SIZE..2G */ + size = PAGE_ALIGN(min_t(unsigned long long, + rlimit(RLIMIT_STACK) / 2, SZ_2G)); + return max(PAGE_SIZE, size); +} + +unsigned long gcs_alloc_thread_stack(struct task_struct *tsk, + const struct kernel_clone_args *args) +{ + unsigned long addr, size; + + if (!system_supports_gcs()) + return 0; + + if (!task_gcs_el0_enabled(tsk)) + return 0; + + if ((args->flags & (CLONE_VFORK | CLONE_VM)) != CLONE_VM) { + tsk->thread.gcspr_el0 = read_sysreg_s(SYS_GCSPR_EL0); + return 0; + } + + size = args->stack_size / 2; + + size = gcs_size(size); + addr = alloc_gcs(0, size); + if (IS_ERR_VALUE(addr)) + return addr; + + tsk->thread.gcs_base = addr; + tsk->thread.gcs_size = size; + tsk->thread.gcspr_el0 = addr + size - sizeof(u64); + + return addr; +} + +SYSCALL_DEFINE3(map_shadow_stack, unsigned long, addr, unsigned long, size, unsigned int, flags) +{ + unsigned long alloc_size; + unsigned long __user *cap_ptr; + unsigned long cap_val; + int ret = 0; + int cap_offset; + + if (!system_supports_gcs()) + return -EOPNOTSUPP; + + if (flags & ~(SHADOW_STACK_SET_TOKEN | SHADOW_STACK_SET_MARKER)) + return -EINVAL; + + if (!PAGE_ALIGNED(addr)) + return -EINVAL; + + if (size == 8 || !IS_ALIGNED(size, 8)) + return -EINVAL; + + /* + * An overflow would result in attempting to write the restore token + * to the wrong location. Not catastrophic, but just return the right + * error code and block it. + */ + alloc_size = PAGE_ALIGN(size); + if (alloc_size < size) + return -EOVERFLOW; + + addr = alloc_gcs(addr, alloc_size); + if (IS_ERR_VALUE(addr)) + return addr; + + /* + * Put a cap token at the end of the allocated region so it + * can be switched to. + */ + if (flags & SHADOW_STACK_SET_TOKEN) { + /* Leave an extra empty frame as a top of stack marker? */ + if (flags & SHADOW_STACK_SET_MARKER) + cap_offset = 2; + else + cap_offset = 1; + + cap_ptr = (unsigned long __user *)(addr + size - + (cap_offset * sizeof(unsigned long))); + cap_val = GCS_CAP(cap_ptr); + + put_user_gcs(cap_val, cap_ptr, &ret); + if (ret != 0) { + vm_munmap(addr, size); + return -EFAULT; + } + + /* + * Ensure the new cap is ordered before standard + * memory accesses to the same location. + */ + gcsb_dsync(); + } + + return addr; +} + +/* + * Apply the GCS mode configured for the specified task to the + * hardware. + */ +void gcs_set_el0_mode(struct task_struct *task) +{ + u64 gcscre0_el1 = GCSCRE0_EL1_nTR; + + if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE) + gcscre0_el1 |= GCSCRE0_EL1_RVCHKEN | GCSCRE0_EL1_PCRSEL; + + if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_WRITE) + gcscre0_el1 |= GCSCRE0_EL1_STREn; + + if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_PUSH) + gcscre0_el1 |= GCSCRE0_EL1_PUSHMEn; + + write_sysreg_s(gcscre0_el1, SYS_GCSCRE0_EL1); +} + +void gcs_free(struct task_struct *task) +{ + if (!system_supports_gcs()) + return; + + /* + * When fork() with CLONE_VM fails, the child (tsk) already + * has a GCS allocated, and exit_thread() calls this function + * to free it. In this case the parent (current) and the + * child share the same mm struct. + */ + if (!task->mm || task->mm != current->mm) + return; + + if (task->thread.gcs_base) + vm_munmap(task->thread.gcs_base, task->thread.gcs_size); + + task->thread.gcspr_el0 = 0; + task->thread.gcs_base = 0; + task->thread.gcs_size = 0; +} + +int arch_set_shadow_stack_status(struct task_struct *task, unsigned long arg) +{ + unsigned long gcs, size; + int ret; + + if (!system_supports_gcs()) + return -EINVAL; + + if (is_compat_thread(task_thread_info(task))) + return -EINVAL; + + /* Reject unknown flags */ + if (arg & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK) + return -EINVAL; + + ret = gcs_check_locked(task, arg); + if (ret != 0) + return ret; + + /* If we are enabling GCS then make sure we have a stack */ + if (arg & PR_SHADOW_STACK_ENABLE && + !task_gcs_el0_enabled(task)) { + /* Do not allow GCS to be reenabled */ + if (task->thread.gcs_base || task->thread.gcspr_el0) + return -EINVAL; + + if (task != current) + return -EBUSY; + + size = gcs_size(0); + gcs = alloc_gcs(0, size); + if (!gcs) + return -ENOMEM; + + task->thread.gcspr_el0 = gcs + size - sizeof(u64); + task->thread.gcs_base = gcs; + task->thread.gcs_size = size; + if (task == current) + write_sysreg_s(task->thread.gcspr_el0, + SYS_GCSPR_EL0); + } + + task->thread.gcs_el0_mode = arg; + if (task == current) + gcs_set_el0_mode(task); + + return 0; +} + +int arch_get_shadow_stack_status(struct task_struct *task, + unsigned long __user *arg) +{ + if (!system_supports_gcs()) + return -EINVAL; + + if (is_compat_thread(task_thread_info(task))) + return -EINVAL; + + return put_user(task->thread.gcs_el0_mode, arg); +} + +int arch_lock_shadow_stack_status(struct task_struct *task, + unsigned long arg) +{ + if (!system_supports_gcs()) + return -EINVAL; + + if (is_compat_thread(task_thread_info(task))) + return -EINVAL; + + /* + * We support locking unknown bits so applications can prevent + * any changes in a future proof manner. + */ + task->thread.gcs_el0_locked |= arg; + + return 0; +} diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c index 5f1e2103888b76..3215adf48a1b6c 100644 --- a/arch/arm64/mm/hugetlbpage.c +++ b/arch/arm64/mm/hugetlbpage.c @@ -361,14 +361,25 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags) { size_t pagesize = 1UL << shift; - entry = pte_mkhuge(entry); - if (pagesize == CONT_PTE_SIZE) { - entry = pte_mkcont(entry); - } else if (pagesize == CONT_PMD_SIZE) { + switch (pagesize) { +#ifndef __PAGETABLE_PMD_FOLDED + case PUD_SIZE: + entry = pud_pte(pud_mkhuge(pte_pud(entry))); + break; +#endif + case CONT_PMD_SIZE: entry = pmd_pte(pmd_mkcont(pte_pmd(entry))); - } else if (pagesize != PUD_SIZE && pagesize != PMD_SIZE) { + fallthrough; + case PMD_SIZE: + entry = pmd_pte(pmd_mkhuge(pte_pmd(entry))); + break; + case CONT_PTE_SIZE: + entry = pte_mkcont(entry); + break; + default: pr_warn("%s: unrecognized huge page size 0x%lx\n", __func__, pagesize); + break; } return entry; } diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 27a32ff15412aa..ccdef53872a0bf 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -116,15 +117,6 @@ static void __init arch_reserve_crashkernel(void) static phys_addr_t __init max_zone_phys(phys_addr_t zone_limit) { - /** - * Information we get from firmware (e.g. DT dma-ranges) describe DMA - * bus constraints. Devices using DMA might have their own limitations. - * Some of them rely on DMA zone in low 32-bit memory. Keep low RAM - * DMA zone on platforms that have RAM there. - */ - if (memblock_start_of_DRAM() < U32_MAX) - zone_limit = min(zone_limit, U32_MAX); - return min(zone_limit, memblock_end_of_DRAM() - 1) + 1; } @@ -140,6 +132,14 @@ static void __init zone_sizes_init(void) acpi_zone_dma_limit = acpi_iort_dma_get_max_cpu_address(); dt_zone_dma_limit = of_dma_get_max_cpu_address(NULL); zone_dma_limit = min(dt_zone_dma_limit, acpi_zone_dma_limit); + /* + * Information we get from firmware (e.g. DT dma-ranges) describe DMA + * bus constraints. Devices using DMA might have their own limitations. + * Some of them rely on DMA zone in low 32-bit memory. Keep low RAM + * DMA zone on platforms that have RAM there. + */ + if (memblock_start_of_DRAM() < U32_MAX) + zone_dma_limit = min(zone_dma_limit, U32_MAX); arm64_dma_phys_limit = max_zone_phys(zone_dma_limit); max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit); #endif @@ -366,8 +366,14 @@ void __init bootmem_init(void) */ void __init mem_init(void) { + unsigned int flags = SWIOTLB_VERBOSE; bool swiotlb = max_pfn > PFN_DOWN(arm64_dma_phys_limit); + if (is_realm_world()) { + swiotlb = true; + flags |= SWIOTLB_FORCE; + } + if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) && !swiotlb) { /* * If no bouncing needed for ZONE_DMA, reduce the swiotlb @@ -379,7 +385,8 @@ void __init mem_init(void) swiotlb = true; } - swiotlb_init(swiotlb, SWIOTLB_VERBOSE); + swiotlb_init(swiotlb, flags); + swiotlb_update_mem_attributes(); /* this will put all unused low memory onto the freelists */ memblock_free_all(); diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c index 7e3ad97e27d80d..07aeab8a760652 100644 --- a/arch/arm64/mm/mmap.c +++ b/arch/arm64/mm/mmap.c @@ -83,8 +83,15 @@ arch_initcall(adjust_protection_map); pgprot_t vm_get_page_prot(unsigned long vm_flags) { - pteval_t prot = pgprot_val(protection_map[vm_flags & + pteval_t prot; + + /* Short circuit GCS to avoid bloating the table. */ + if (system_supports_gcs() && (vm_flags & VM_SHADOW_STACK)) { + prot = _PAGE_GCS_RO; + } else { + prot = pgprot_val(protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]); + } if (vm_flags & VM_ARM64_BTI) prot |= PTE_GP; diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index e55b02fbddc8f3..e2739b69e11bd8 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -119,7 +119,7 @@ static phys_addr_t __init early_pgtable_alloc(int shift) return phys; } -bool pgattr_change_is_safe(u64 old, u64 new) +bool pgattr_change_is_safe(pteval_t old, pteval_t new) { /* * The following mapping attributes may be updated in live @@ -201,7 +201,7 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr, BUG_ON(pmd_sect(pmd)); if (pmd_none(pmd)) { - pmdval_t pmdval = PMD_TYPE_TABLE | PMD_TABLE_UXN; + pmdval_t pmdval = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF; phys_addr_t pte_phys; if (flags & NO_EXEC_MAPPINGS) @@ -288,7 +288,7 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr, */ BUG_ON(pud_sect(pud)); if (pud_none(pud)) { - pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_UXN; + pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF; phys_addr_t pmd_phys; if (flags & NO_EXEC_MAPPINGS) @@ -333,7 +333,7 @@ static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end, pud_t *pudp; if (p4d_none(p4d)) { - p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_UXN; + p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_UXN | P4D_TABLE_AF; phys_addr_t pud_phys; if (flags & NO_EXEC_MAPPINGS) @@ -391,7 +391,7 @@ static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end, p4d_t *p4dp; if (pgd_none(pgd)) { - pgdval_t pgdval = PGD_TYPE_TABLE | PGD_TABLE_UXN; + pgdval_t pgdval = PGD_TYPE_TABLE | PGD_TABLE_UXN | PGD_TABLE_AF; phys_addr_t p4d_phys; if (flags & NO_EXEC_MAPPINGS) diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c index 0e270a1c51e645..39fd1f7ff02aa0 100644 --- a/arch/arm64/mm/pageattr.c +++ b/arch/arm64/mm/pageattr.c @@ -5,10 +5,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -23,14 +25,16 @@ bool rodata_full __ro_after_init = IS_ENABLED(CONFIG_RODATA_FULL_DEFAULT_ENABLED bool can_set_direct_map(void) { /* - * rodata_full and DEBUG_PAGEALLOC require linear map to be - * mapped at page granularity, so that it is possible to + * rodata_full, DEBUG_PAGEALLOC and a Realm guest all require linear + * map to be mapped at page granularity, so that it is possible to * protect/unprotect single pages. * * KFENCE pool requires page-granular mapping if initialized late. + * + * Realms need to make pages shared/protected at page granularity. */ return rodata_full || debug_pagealloc_enabled() || - arm64_kfence_can_set_direct_map(); + arm64_kfence_can_set_direct_map() || is_realm_world(); } static int change_page_range(pte_t *ptep, unsigned long addr, void *data) @@ -60,7 +64,13 @@ static int __change_memory_common(unsigned long start, unsigned long size, ret = apply_to_page_range(&init_mm, start, size, change_page_range, &data); - flush_tlb_kernel_range(start, start + size); + /* + * If the memory is being made valid without changing any other bits + * then a TLBI isn't required as a non-valid entry cannot be cached in + * the TLB. + */ + if (pgprot_val(set_mask) != PTE_VALID || pgprot_val(clear_mask)) + flush_tlb_kernel_range(start, start + size); return ret; } @@ -192,7 +202,103 @@ int set_direct_map_default_noflush(struct page *page) PAGE_SIZE, change_page_range, &data); } +static int __set_memory_enc_dec(unsigned long addr, + int numpages, + bool encrypt) +{ + unsigned long set_prot = 0, clear_prot = 0; + phys_addr_t start, end; + int ret; + + if (!is_realm_world()) + return 0; + + if (!__is_lm_address(addr)) + return -EINVAL; + + start = __virt_to_phys(addr); + end = start + numpages * PAGE_SIZE; + + if (encrypt) + clear_prot = PROT_NS_SHARED; + else + set_prot = PROT_NS_SHARED; + + /* + * Break the mapping before we make any changes to avoid stale TLB + * entries or Synchronous External Aborts caused by RIPAS_EMPTY + */ + ret = __change_memory_common(addr, PAGE_SIZE * numpages, + __pgprot(set_prot), + __pgprot(clear_prot | PTE_VALID)); + + if (ret) + return ret; + + if (encrypt) + ret = rsi_set_memory_range_protected(start, end); + else + ret = rsi_set_memory_range_shared(start, end); + + if (ret) + return ret; + + return __change_memory_common(addr, PAGE_SIZE * numpages, + __pgprot(PTE_VALID), + __pgprot(0)); +} + +static int realm_set_memory_encrypted(unsigned long addr, int numpages) +{ + int ret = __set_memory_enc_dec(addr, numpages, true); + + /* + * If the request to change state fails, then the only sensible cause + * of action for the caller is to leak the memory + */ + WARN(ret, "Failed to encrypt memory, %d pages will be leaked", + numpages); + + return ret; +} + +static int realm_set_memory_decrypted(unsigned long addr, int numpages) +{ + int ret = __set_memory_enc_dec(addr, numpages, false); + + WARN(ret, "Failed to decrypt memory, %d pages will be leaked", + numpages); + + return ret; +} + +static const struct arm64_mem_crypt_ops realm_crypt_ops = { + .encrypt = realm_set_memory_encrypted, + .decrypt = realm_set_memory_decrypted, +}; + +int realm_register_memory_enc_ops(void) +{ + return arm64_mem_crypt_ops_register(&realm_crypt_ops); +} + +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid) +{ + unsigned long addr = (unsigned long)page_address(page); + + if (!can_set_direct_map()) + return 0; + + return set_memory_valid(addr, nr, valid); +} + #ifdef CONFIG_DEBUG_PAGEALLOC +/* + * This is - apart from the return value - doing the same + * thing as the new set_direct_map_valid_noflush() function. + * + * Unify? Explain the conceptual differences? + */ void __kernel_map_pages(struct page *page, int numpages, int enable) { if (!can_set_direct_map()) diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 8abdc7fed3210d..b8edc5765441e6 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -465,10 +465,12 @@ SYM_FUNC_START(__cpu_setup) */ mair .req x17 tcr .req x16 + tcr2 .req x15 mov_q mair, MAIR_EL1_SET mov_q tcr, TCR_T0SZ(IDMAP_VA_BITS) | TCR_T1SZ(VA_BITS_MIN) | TCR_CACHE_FLAGS | \ TCR_SHARED | TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \ TCR_TBI0 | TCR_A1 | TCR_KASAN_SW_FLAGS | TCR_MTE_FLAGS + mov tcr2, xzr tcr_clear_errata_bits tcr, x9, x5 @@ -493,9 +495,14 @@ alternative_else_nop_endif * via capabilities. */ mrs x9, ID_AA64MMFR1_EL1 - and x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK + ubfx x9, x9, ID_AA64MMFR1_EL1_HAFDBS_SHIFT, #4 cbz x9, 1f orr tcr, tcr, #TCR_HA // hardware Access flag update +#ifdef CONFIG_ARM64_HAFT + cmp x9, ID_AA64MMFR1_EL1_HAFDBS_HAFT + b.lt 1f + orr tcr2, tcr2, TCR2_EL1x_HAFT +#endif /* CONFIG_ARM64_HAFT */ 1: #endif /* CONFIG_ARM64_HW_AFDBM */ msr mair_el1, mair @@ -525,11 +532,16 @@ alternative_else_nop_endif #undef PTE_MAYBE_NG #undef PTE_MAYBE_SHARED - mov x0, TCR2_EL1x_PIE - msr REG_TCR2_EL1, x0 + orr tcr2, tcr2, TCR2_EL1x_PIE .Lskip_indirection: + mrs_s x1, SYS_ID_AA64MMFR3_EL1 + ubfx x1, x1, #ID_AA64MMFR3_EL1_TCRX_SHIFT, #4 + cbz x1, 1f + msr REG_TCR2_EL1, tcr2 +1: + /* * Prepare SCTLR */ @@ -538,4 +550,5 @@ alternative_else_nop_endif .unreq mair .unreq tcr + .unreq tcr2 SYM_FUNC_END(__cpu_setup) diff --git a/arch/arm64/mm/ptdump.c b/arch/arm64/mm/ptdump.c index 264c5f9b97d866..688fbe0271ca4d 100644 --- a/arch/arm64/mm/ptdump.c +++ b/arch/arm64/mm/ptdump.c @@ -80,10 +80,10 @@ static const struct ptdump_prot_bits pte_bits[] = { .set = "CON", .clear = " ", }, { - .mask = PTE_TABLE_BIT, - .val = PTE_TABLE_BIT, - .set = " ", - .clear = "BLK", + .mask = PTE_TABLE_BIT | PTE_VALID, + .val = PTE_VALID, + .set = "BLK", + .clear = " ", }, { .mask = PTE_UXN, .val = PTE_UXN, diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 5db82bfc9dc115..66708b95493a43 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include "bpf_jit.h" @@ -2094,6 +2094,12 @@ static void restore_args(struct jit_ctx *ctx, int args_off, int nregs) } } +static bool is_struct_ops_tramp(const struct bpf_tramp_links *fentry_links) +{ + return fentry_links->nr_links == 1 && + fentry_links->links[0]->link.type == BPF_LINK_TYPE_STRUCT_OPS; +} + /* Based on the x86's implementation of arch_prepare_bpf_trampoline(). * * bpf prog and function entry before bpf trampoline hooked: @@ -2123,6 +2129,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN]; bool save_ret; __le32 **branches = NULL; + bool is_struct_ops = is_struct_ops_tramp(fentry); /* trampoline stack layout: * [ parent ip ] @@ -2191,11 +2198,14 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, */ emit_bti(A64_BTI_JC, ctx); - /* frame for parent function */ - emit(A64_PUSH(A64_FP, A64_R(9), A64_SP), ctx); - emit(A64_MOV(1, A64_FP, A64_SP), ctx); + /* x9 is not set for struct_ops */ + if (!is_struct_ops) { + /* frame for parent function */ + emit(A64_PUSH(A64_FP, A64_R(9), A64_SP), ctx); + emit(A64_MOV(1, A64_FP, A64_SP), ctx); + } - /* frame for patched function */ + /* frame for patched function for tracing, or caller for struct_ops */ emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx); emit(A64_MOV(1, A64_FP, A64_SP), ctx); @@ -2289,19 +2299,24 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, /* reset SP */ emit(A64_MOV(1, A64_SP, A64_FP), ctx); - /* pop frames */ - emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx); - emit(A64_POP(A64_FP, A64_R(9), A64_SP), ctx); - - if (flags & BPF_TRAMP_F_SKIP_FRAME) { - /* skip patched function, return to parent */ - emit(A64_MOV(1, A64_LR, A64_R(9)), ctx); - emit(A64_RET(A64_R(9)), ctx); + if (is_struct_ops) { + emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx); + emit(A64_RET(A64_LR), ctx); } else { - /* return to patched function */ - emit(A64_MOV(1, A64_R(10), A64_LR), ctx); - emit(A64_MOV(1, A64_LR, A64_R(9)), ctx); - emit(A64_RET(A64_R(10)), ctx); + /* pop frames */ + emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx); + emit(A64_POP(A64_FP, A64_R(9), A64_SP), ctx); + + if (flags & BPF_TRAMP_F_SKIP_FRAME) { + /* skip patched function, return to parent */ + emit(A64_MOV(1, A64_LR, A64_R(9)), ctx); + emit(A64_RET(A64_R(9)), ctx); + } else { + /* return to patched function */ + emit(A64_MOV(1, A64_R(10), A64_LR), ctx); + emit(A64_MOV(1, A64_LR, A64_R(9)), ctx); + emit(A64_RET(A64_R(10)), ctx); + } } kfree(branches); diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index eedb5acc21ed98..eb17f59e543c49 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -29,6 +29,7 @@ HAS_EVT HAS_FPMR HAS_FGT HAS_FPSIMD +HAS_GCS HAS_GENERIC_AUTH HAS_GENERIC_AUTH_ARCH_QARMA3 HAS_GENERIC_AUTH_ARCH_QARMA5 @@ -56,10 +57,13 @@ HAS_TLB_RANGE HAS_VA52 HAS_VIRT_HOST_EXTN HAS_WFXT +HAFT HW_DBM KVM_HVHE KVM_PROTECTED_MODE MISMATCHED_CACHE_TYPE +MPAM +MPAM_HCR MTE MTE_ASYMM SME diff --git a/arch/arm64/tools/syscall_32.tbl b/arch/arm64/tools/syscall_32.tbl index 9a37930d4e26f0..69a829912a05eb 100644 --- a/arch/arm64/tools/syscall_32.tbl +++ b/arch/arm64/tools/syscall_32.tbl @@ -474,3 +474,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg index 8d637ac4b7c6b9..b081b54d6d227e 100644 --- a/arch/arm64/tools/sysreg +++ b/arch/arm64/tools/sysreg @@ -1200,7 +1200,7 @@ UnsignedEnum 55:52 BRBE 0b0001 IMP 0b0010 BRBE_V1P1 EndEnum -Enum 51:48 MTPMU +SignedEnum 51:48 MTPMU 0b0000 NI_IMPDEF 0b0001 IMP 0b1111 NI @@ -1208,6 +1208,7 @@ EndEnum UnsignedEnum 47:44 TraceBuffer 0b0000 NI 0b0001 IMP + 0b0010 TRBE_V1P1 EndEnum UnsignedEnum 43:40 TraceFilt 0b0000 NI @@ -1224,11 +1225,18 @@ UnsignedEnum 35:32 PMSVer 0b0011 V1P2 0b0100 V1P3 0b0101 V1P4 + 0b0110 V1P5 EndEnum Field 31:28 CTX_CMPs -Res0 27:24 +UnsignedEnum 27:24 SEBEP + 0b0000 NI + 0b0001 IMP +EndEnum Field 23:20 WRPs -Res0 19:16 +UnsignedEnum 19:16 PMSS + 0b0000 NI + 0b0001 IMP +EndEnum Field 15:12 BRPs UnsignedEnum 11:8 PMUVer 0b0000 NI @@ -1238,6 +1246,7 @@ UnsignedEnum 11:8 PMUVer 0b0110 V3P5 0b0111 V3P7 0b1000 V3P8 + 0b1001 V3P9 0b1111 IMP_DEF EndEnum UnsignedEnum 7:4 TraceVer @@ -1287,6 +1296,32 @@ Field 15:8 BRPs Field 7:0 SYSPMUID EndSysreg +Sysreg ID_AA64DFR2_EL1 3 0 0 5 2 +Res0 63:28 +UnsignedEnum 27:24 TRBE_EXC + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 23:20 SPE_nVM + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 19:16 SPE_EXC + 0b0000 NI + 0b0001 IMP +EndEnum +Res0 15:8 +UnsignedEnum 7:4 BWE + 0b0000 NI + 0b0001 FEAT_BWE + 0b0002 FEAT_BWE2 +EndEnum +UnsignedEnum 3:0 STEP + 0b0000 NI + 0b0001 IMP +EndEnum +EndSysreg + Sysreg ID_AA64AFR0_EL1 3 0 0 5 4 Res0 63:32 Field 31:28 IMPDEF7 @@ -1648,6 +1683,8 @@ EndEnum UnsignedEnum 39:36 ETS 0b0000 NI 0b0001 IMP + 0b0010 ETS2 + 0b0011 ETS3 EndEnum UnsignedEnum 35:32 TWED 0b0000 NI @@ -1688,6 +1725,8 @@ UnsignedEnum 3:0 HAFDBS 0b0000 NI 0b0001 AF 0b0010 DBM + 0b0011 HAFT + 0b0100 HDBSS EndEnum EndSysreg @@ -2178,6 +2217,13 @@ Field 4 P Field 3:0 ALIGN EndSysreg +Sysreg PMUACR_EL1 3 0 9 14 4 +Res0 63:33 +Field 32 F0 +Field 31 C +Field 30:0 P +EndSysreg + Sysreg PMSELR_EL0 3 3 9 12 5 Res0 63:5 Field 4:0 SEL @@ -2388,6 +2434,41 @@ Field 1 AFSR1_EL1 Field 0 AFSR0_EL1 EndSysregFields +Sysreg MDCR_EL2 3 4 1 1 1 +Res0 63:51 +Field 50 EnSTEPOP +Res0 49:44 +Field 43 EBWE +Res0 42 +Field 41:40 PMEE +Res0 39:37 +Field 36 HPMFZS +Res0 35:32 +Field 31:30 PMSSE +Field 29 HPMFZO +Field 28 MTPME +Field 27 TDCC +Field 26 HLP +Field 25:24 E2TB +Field 23 HCCD +Res0 22:20 +Field 19 TTRF +Res0 18 +Field 17 HPMD +Res0 16 +Field 15 EnSPM +Field 14 TPMS +Field 13:12 E2PB +Field 11 TDRA +Field 10 TDOSA +Field 9 TDA +Field 8 TDE +Field 7 HPME +Field 6 TPM +Field 5 TPMCR +Field 4:0 HPMN +EndSysreg + Sysreg HFGRTR_EL2 3 4 1 1 4 Fields HFGxTR_EL2 EndSysreg @@ -2737,6 +2818,126 @@ Field 1 E2SPE Field 0 E0HSPE EndSysreg +Sysreg MPAMHCR_EL2 3 4 10 4 0 +Res0 63:32 +Field 31 TRAP_MPAMIDR_EL1 +Res0 30:9 +Field 8 GSTAPP_PLK +Res0 7:2 +Field 1 EL1_VPMEN +Field 0 EL0_VPMEN +EndSysreg + +Sysreg MPAMVPMV_EL2 3 4 10 4 1 +Res0 63:32 +Field 31 VPM_V31 +Field 30 VPM_V30 +Field 29 VPM_V29 +Field 28 VPM_V28 +Field 27 VPM_V27 +Field 26 VPM_V26 +Field 25 VPM_V25 +Field 24 VPM_V24 +Field 23 VPM_V23 +Field 22 VPM_V22 +Field 21 VPM_V21 +Field 20 VPM_V20 +Field 19 VPM_V19 +Field 18 VPM_V18 +Field 17 VPM_V17 +Field 16 VPM_V16 +Field 15 VPM_V15 +Field 14 VPM_V14 +Field 13 VPM_V13 +Field 12 VPM_V12 +Field 11 VPM_V11 +Field 10 VPM_V10 +Field 9 VPM_V9 +Field 8 VPM_V8 +Field 7 VPM_V7 +Field 6 VPM_V6 +Field 5 VPM_V5 +Field 4 VPM_V4 +Field 3 VPM_V3 +Field 2 VPM_V2 +Field 1 VPM_V1 +Field 0 VPM_V0 +EndSysreg + +Sysreg MPAM2_EL2 3 4 10 5 0 +Field 63 MPAMEN +Res0 62:59 +Field 58 TIDR +Res0 57 +Field 56 ALTSP_HFC +Field 55 ALTSP_EL2 +Field 54 ALTSP_FRCD +Res0 53:51 +Field 50 EnMPAMSM +Field 49 TRAPMPAM0EL1 +Field 48 TRAPMPAM1EL1 +Field 47:40 PMG_D +Field 39:32 PMG_I +Field 31:16 PARTID_D +Field 15:0 PARTID_I +EndSysreg + +Sysreg MPAMVPM0_EL2 3 4 10 6 0 +Field 63:48 PhyPARTID3 +Field 47:32 PhyPARTID2 +Field 31:16 PhyPARTID1 +Field 15:0 PhyPARTID0 +EndSysreg + +Sysreg MPAMVPM1_EL2 3 4 10 6 1 +Field 63:48 PhyPARTID7 +Field 47:32 PhyPARTID6 +Field 31:16 PhyPARTID5 +Field 15:0 PhyPARTID4 +EndSysreg + +Sysreg MPAMVPM2_EL2 3 4 10 6 2 +Field 63:48 PhyPARTID11 +Field 47:32 PhyPARTID10 +Field 31:16 PhyPARTID9 +Field 15:0 PhyPARTID8 +EndSysreg + +Sysreg MPAMVPM3_EL2 3 4 10 6 3 +Field 63:48 PhyPARTID15 +Field 47:32 PhyPARTID14 +Field 31:16 PhyPARTID13 +Field 15:0 PhyPARTID12 +EndSysreg + +Sysreg MPAMVPM4_EL2 3 4 10 6 4 +Field 63:48 PhyPARTID19 +Field 47:32 PhyPARTID18 +Field 31:16 PhyPARTID17 +Field 15:0 PhyPARTID16 +EndSysreg + +Sysreg MPAMVPM5_EL2 3 4 10 6 5 +Field 63:48 PhyPARTID23 +Field 47:32 PhyPARTID22 +Field 31:16 PhyPARTID21 +Field 15:0 PhyPARTID20 +EndSysreg + +Sysreg MPAMVPM6_EL2 3 4 10 6 6 +Field 63:48 PhyPARTID27 +Field 47:32 PhyPARTID26 +Field 31:16 PhyPARTID25 +Field 15:0 PhyPARTID24 +EndSysreg + +Sysreg MPAMVPM7_EL2 3 4 10 6 7 +Field 63:48 PhyPARTID31 +Field 47:32 PhyPARTID30 +Field 31:16 PhyPARTID29 +Field 15:0 PhyPARTID28 +EndSysreg + Sysreg CONTEXTIDR_EL2 3 4 13 0 1 Fields CONTEXTIDR_ELx EndSysreg @@ -2769,6 +2970,10 @@ Sysreg FAR_EL12 3 5 6 0 0 Field 63:0 ADDR EndSysreg +Sysreg MPAM1_EL12 3 5 10 5 0 +Fields MPAM1_ELx +EndSysreg + Sysreg CONTEXTIDR_EL12 3 5 13 0 1 Fields CONTEXTIDR_ELx EndSysreg @@ -2819,8 +3024,7 @@ Field 13 AMEC1 Field 12 AMEC0 Field 11 HAFT Field 10 PTTWI -Field 9:8 SKL1 -Field 7:6 SKL0 +Res0 9:6 Field 5 D128 Field 4 AIE Field 3 POE @@ -2883,6 +3087,10 @@ Sysreg PIRE0_EL12 3 5 10 2 2 Fields PIRx_ELx EndSysreg +Sysreg PIRE0_EL2 3 4 10 2 2 +Fields PIRx_ELx +EndSysreg + Sysreg PIR_EL1 3 0 10 2 3 Fields PIRx_ELx EndSysreg @@ -2903,6 +3111,10 @@ Sysreg POR_EL1 3 0 10 2 4 Fields PIRx_ELx EndSysreg +Sysreg POR_EL2 3 4 10 2 4 +Fields PIRx_ELx +EndSysreg + Sysreg POR_EL12 3 5 10 2 4 Fields PIRx_ELx EndSysreg @@ -2941,6 +3153,22 @@ Res0 1 Field 0 EN EndSysreg +Sysreg MPAMIDR_EL1 3 0 10 4 4 +Res0 63:62 +Field 61 HAS_SDEFLT +Field 60 HAS_FORCE_NS +Field 59 SP4 +Field 58 HAS_TIDR +Field 57 HAS_ALTSP +Res0 56:40 +Field 39:32 PMG_MAX +Res0 31:21 +Field 20:18 VPMR_MAX +Field 17 HAS_HCR +Res0 16 +Field 15:0 PARTID_MAX +EndSysreg + Sysreg LORID_EL1 3 0 10 4 7 Res0 63:24 Field 23:16 LD @@ -2948,6 +3176,27 @@ Res0 15:8 Field 7:0 LR EndSysreg +Sysreg MPAM1_EL1 3 0 10 5 0 +Field 63 MPAMEN +Res0 62:61 +Field 60 FORCED_NS +Res0 59:55 +Field 54 ALTSP_FRCD +Res0 53:48 +Field 47:40 PMG_D +Field 39:32 PMG_I +Field 31:16 PARTID_D +Field 15:0 PARTID_I +EndSysreg + +Sysreg MPAM0_EL1 3 0 10 5 1 +Res0 63:48 +Field 47:40 PMG_D +Field 39:32 PMG_I +Field 31:16 PARTID_D +Field 15:0 PARTID_I +EndSysreg + Sysreg ISR_EL1 3 0 12 1 0 Res0 63:11 Field 10 IS diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index 5479707eb5d10d..acc431c331b08e 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -64,9 +64,6 @@ config CSKY select GENERIC_IRQ_MULTI_HANDLER select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD - select GENERIC_TIME_VSYSCALL - select GENERIC_VDSO_32 - select GENERIC_GETTIMEOFDAY select GX6605S_TIMER if CPU_CK610 select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_AUDITSYSCALL @@ -80,7 +77,6 @@ config CSKY select HAVE_DEBUG_KMEMLEAK select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_REGS - select HAVE_GENERIC_VDSO select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_ERROR_INJECTION diff --git a/arch/csky/include/asm/Kbuild b/arch/csky/include/asm/Kbuild index 9a9bc65b57a9d7..3a5c7f6e5aacbe 100644 --- a/arch/csky/include/asm/Kbuild +++ b/arch/csky/include/asm/Kbuild @@ -11,3 +11,4 @@ generic-y += qspinlock.h generic-y += parport.h generic-y += user.h generic-y += vmlinux.lds.h +generic-y += text-patching.h diff --git a/arch/csky/include/asm/io.h b/arch/csky/include/asm/io.h index 4725bb977b0f4f..ed53f0b4738808 100644 --- a/arch/csky/include/asm/io.h +++ b/arch/csky/include/asm/io.h @@ -31,17 +31,6 @@ #define writel(v,c) ({ wmb(); writel_relaxed((v),(c)); mb(); }) #endif -/* - * String version of I/O memory access operations. - */ -extern void __memcpy_fromio(void *, const volatile void __iomem *, size_t); -extern void __memcpy_toio(volatile void __iomem *, const void *, size_t); -extern void __memset_io(volatile void __iomem *, int, size_t); - -#define memset_io(c,v,l) __memset_io((c),(v),(l)) -#define memcpy_fromio(a,c,l) __memcpy_fromio((a),(c),(l)) -#define memcpy_toio(c,a,l) __memcpy_toio((c),(a),(l)) - /* * I/O memory mapping functions. */ diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h index 0ca6c408c07f27..4911d0892b71d7 100644 --- a/arch/csky/include/asm/page.h +++ b/arch/csky/include/asm/page.h @@ -7,12 +7,8 @@ #include #include -/* - * PAGE_SHIFT determines the page size: 4KB - */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE - 1)) +#include + #define THREAD_SIZE (PAGE_SIZE * 2) #define THREAD_MASK (~(THREAD_SIZE - 1)) #define THREAD_SHIFT (PAGE_SHIFT + 1) @@ -43,9 +39,6 @@ extern void *memcpy(void *to, const void *from, size_t l); #define clear_page(page) memset((page), 0, PAGE_SIZE) #define copy_page(to, from) memcpy((to), (from), PAGE_SIZE) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) -#define phys_to_page(paddr) (pfn_to_page(PFN_DOWN(paddr))) - struct page; #include diff --git a/arch/csky/include/asm/vdso/clocksource.h b/arch/csky/include/asm/vdso/clocksource.h deleted file mode 100644 index dfca7b4724b798..00000000000000 --- a/arch/csky/include/asm/vdso/clocksource.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __ASM_VDSO_CSKY_CLOCKSOURCE_H -#define __ASM_VDSO_CSKY_CLOCKSOURCE_H - -#define VDSO_ARCH_CLOCKMODES \ - VDSO_CLOCKMODE_ARCHTIMER - -#endif /* __ASM_VDSO_CSKY_CLOCKSOURCE_H */ diff --git a/arch/csky/include/asm/vdso/gettimeofday.h b/arch/csky/include/asm/vdso/gettimeofday.h deleted file mode 100644 index 6c4f1446944f94..00000000000000 --- a/arch/csky/include/asm/vdso/gettimeofday.h +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __ASM_VDSO_CSKY_GETTIMEOFDAY_H -#define __ASM_VDSO_CSKY_GETTIMEOFDAY_H - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -#define VDSO_HAS_CLOCK_GETRES 1 - -static __always_inline -int gettimeofday_fallback(struct __kernel_old_timeval *_tv, - struct timezone *_tz) -{ - register struct __kernel_old_timeval *tv asm("a0") = _tv; - register struct timezone *tz asm("a1") = _tz; - register long ret asm("a0"); - register long nr asm(syscallid) = __NR_gettimeofday; - - asm volatile ("trap 0\n" - : "=r" (ret) - : "r"(tv), "r"(tz), "r"(nr) - : "memory"); - - return ret; -} - -static __always_inline -long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) -{ - register clockid_t clkid asm("a0") = _clkid; - register struct __kernel_timespec *ts asm("a1") = _ts; - register long ret asm("a0"); - register long nr asm(syscallid) = __NR_clock_gettime64; - - asm volatile ("trap 0\n" - : "=r" (ret) - : "r"(clkid), "r"(ts), "r"(nr) - : "memory"); - - return ret; -} - -static __always_inline -long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) -{ - register clockid_t clkid asm("a0") = _clkid; - register struct old_timespec32 *ts asm("a1") = _ts; - register long ret asm("a0"); - register long nr asm(syscallid) = __NR_clock_gettime; - - asm volatile ("trap 0\n" - : "=r" (ret) - : "r"(clkid), "r"(ts), "r"(nr) - : "memory"); - - return ret; -} - -static __always_inline -int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) -{ - register clockid_t clkid asm("a0") = _clkid; - register struct __kernel_timespec *ts asm("a1") = _ts; - register long ret asm("a0"); - register long nr asm(syscallid) = __NR_clock_getres_time64; - - asm volatile ("trap 0\n" - : "=r" (ret) - : "r"(clkid), "r"(ts), "r"(nr) - : "memory"); - - return ret; -} - -static __always_inline -int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts) -{ - register clockid_t clkid asm("a0") = _clkid; - register struct old_timespec32 *ts asm("a1") = _ts; - register long ret asm("a0"); - register long nr asm(syscallid) = __NR_clock_getres; - - asm volatile ("trap 0\n" - : "=r" (ret) - : "r"(clkid), "r"(ts), "r"(nr) - : "memory"); - - return ret; -} - -uint64_t csky_pmu_read_cc(void); -static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, - const struct vdso_data *vd) -{ -#ifdef CONFIG_CSKY_PMU_V1 - return csky_pmu_read_cc(); -#else - return 0; -#endif -} - -static __always_inline const struct vdso_data *__arch_get_vdso_data(void) -{ - return _vdso_data; -} - -#endif /* !__ASSEMBLY__ */ - -#endif /* __ASM_VDSO_CSKY_GETTIMEOFDAY_H */ diff --git a/arch/csky/include/asm/vdso/processor.h b/arch/csky/include/asm/vdso/processor.h deleted file mode 100644 index 39a6b561d0cc84..00000000000000 --- a/arch/csky/include/asm/vdso/processor.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#ifndef __ASM_VDSO_CSKY_PROCESSOR_H -#define __ASM_VDSO_CSKY_PROCESSOR_H - -#ifndef __ASSEMBLY__ - -#define cpu_relax() barrier() - -#endif /* __ASSEMBLY__ */ - -#endif /* __ASM_VDSO_CSKY_PROCESSOR_H */ diff --git a/arch/csky/include/asm/vdso/vsyscall.h b/arch/csky/include/asm/vdso/vsyscall.h deleted file mode 100644 index c276211a7c4d56..00000000000000 --- a/arch/csky/include/asm/vdso/vsyscall.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __ASM_VDSO_CSKY_VSYSCALL_H -#define __ASM_VDSO_CSKY_VSYSCALL_H - -#ifndef __ASSEMBLY__ - -#include - -extern struct vdso_data *vdso_data; - -static __always_inline struct vdso_data *__csky_get_k_vdso_data(void) -{ - return vdso_data; -} -#define __arch_get_k_vdso_data __csky_get_k_vdso_data - -#include - -#endif /* !__ASSEMBLY__ */ - -#endif /* __ASM_VDSO_CSKY_VSYSCALL_H */ diff --git a/arch/csky/kernel/Makefile b/arch/csky/kernel/Makefile index 8a868316b912bf..de1c3472e8f07a 100644 --- a/arch/csky/kernel/Makefile +++ b/arch/csky/kernel/Makefile @@ -2,7 +2,7 @@ extra-y := vmlinux.lds obj-y += head.o entry.o atomic.o signal.o traps.o irq.o time.o vdso.o vdso/ -obj-y += power.o syscall.o syscall_table.o setup.o io.o +obj-y += power.o syscall.o syscall_table.o setup.o obj-y += process.o cpu-probe.o ptrace.o stacktrace.o obj-y += probes/ diff --git a/arch/csky/kernel/io.c b/arch/csky/kernel/io.c deleted file mode 100644 index 5883f13fa2b18a..00000000000000 --- a/arch/csky/kernel/io.c +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include - -/* - * Copy data from IO memory space to "real" memory space. - */ -void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) -{ - while (count && !IS_ALIGNED((unsigned long)from, 4)) { - *(u8 *)to = __raw_readb(from); - from++; - to++; - count--; - } - - while (count >= 4) { - *(u32 *)to = __raw_readl(from); - from += 4; - to += 4; - count -= 4; - } - - while (count) { - *(u8 *)to = __raw_readb(from); - from++; - to++; - count--; - } -} -EXPORT_SYMBOL(__memcpy_fromio); - -/* - * Copy data from "real" memory space to IO memory space. - */ -void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) -{ - while (count && !IS_ALIGNED((unsigned long)to, 4)) { - __raw_writeb(*(u8 *)from, to); - from++; - to++; - count--; - } - - while (count >= 4) { - __raw_writel(*(u32 *)from, to); - from += 4; - to += 4; - count -= 4; - } - - while (count) { - __raw_writeb(*(u8 *)from, to); - from++; - to++; - count--; - } -} -EXPORT_SYMBOL(__memcpy_toio); - -/* - * "memset" on IO memory space. - */ -void __memset_io(volatile void __iomem *dst, int c, size_t count) -{ - u32 qc = (u8)c; - - qc |= qc << 8; - qc |= qc << 16; - - while (count && !IS_ALIGNED((unsigned long)dst, 4)) { - __raw_writeb(c, dst); - dst++; - count--; - } - - while (count >= 4) { - __raw_writel(qc, dst); - dst += 4; - count -= 4; - } - - while (count) { - __raw_writeb(c, dst); - dst++; - count--; - } -} -EXPORT_SYMBOL(__memset_io); diff --git a/arch/csky/kernel/setup.c b/arch/csky/kernel/setup.c index 51012e90780d6b..fe715b707fd0a4 100644 --- a/arch/csky/kernel/setup.c +++ b/arch/csky/kernel/setup.c @@ -112,9 +112,9 @@ asmlinkage __visible void __init csky_start(unsigned int unused, pre_trap_init(); if (dtb_start == NULL) - early_init_dt_scan(__dtb_start); + early_init_dt_scan(__dtb_start, __pa(dtb_start)); else - early_init_dt_scan(dtb_start); + early_init_dt_scan(dtb_start, __pa(dtb_start)); start_kernel(); diff --git a/arch/csky/kernel/vdso.c b/arch/csky/kernel/vdso.c index 5c9ef63c29f1d9..c54d019d66bcaf 100644 --- a/arch/csky/kernel/vdso.c +++ b/arch/csky/kernel/vdso.c @@ -8,23 +8,19 @@ #include #include -#include extern char vdso_start[], vdso_end[]; static unsigned int vdso_pages; static struct page **vdso_pagelist; -static union vdso_data_store vdso_data_store __page_aligned_data; -struct vdso_data *vdso_data = vdso_data_store.data; - static int __init vdso_init(void) { unsigned int i; vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; vdso_pagelist = - kcalloc(vdso_pages + 1, sizeof(struct page *), GFP_KERNEL); + kcalloc(vdso_pages, sizeof(struct page *), GFP_KERNEL); if (unlikely(vdso_pagelist == NULL)) { pr_err("vdso: pagelist allocation failed\n"); return -ENOMEM; @@ -36,7 +32,6 @@ static int __init vdso_init(void) pg = virt_to_page(vdso_start + (i << PAGE_SHIFT)); vdso_pagelist[i] = pg; } - vdso_pagelist[i] = virt_to_page(vdso_data); return 0; } @@ -52,11 +47,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, static struct vm_special_mapping vdso_mapping = { .name = "[vdso]", }; - static struct vm_special_mapping vvar_mapping = { - .name = "[vvar]", - }; - vdso_len = (vdso_pages + 1) << PAGE_SHIFT; + vdso_len = vdso_pages << PAGE_SHIFT; mmap_write_lock(mm); vdso_base = get_unmapped_area(NULL, 0, vdso_len, 0, 0); @@ -85,27 +77,8 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, } vdso_base += (vdso_pages << PAGE_SHIFT); - vvar_mapping.pages = &vdso_pagelist[vdso_pages]; - vma = _install_special_mapping(mm, vdso_base, PAGE_SIZE, - (VM_READ | VM_MAYREAD), &vvar_mapping); - - if (IS_ERR(vma)) { - ret = PTR_ERR(vma); - mm->context.vdso = NULL; - goto end; - } ret = 0; end: mmap_write_unlock(mm); return ret; } - -const char *arch_vma_name(struct vm_area_struct *vma) -{ - if (vma->vm_mm && (vma->vm_start == (long)vma->vm_mm->context.vdso)) - return "[vdso]"; - if (vma->vm_mm && (vma->vm_start == - (long)vma->vm_mm->context.vdso + PAGE_SIZE)) - return "[vdso_data]"; - return NULL; -} diff --git a/arch/csky/kernel/vdso/Makefile b/arch/csky/kernel/vdso/Makefile index bc2261f5a8d439..069ef0b17fe523 100644 --- a/arch/csky/kernel/vdso/Makefile +++ b/arch/csky/kernel/vdso/Makefile @@ -5,7 +5,6 @@ include $(srctree)/lib/vdso/Makefile # Symbols present in the vdso vdso-syms += rt_sigreturn -vdso-syms += vgettimeofday # Files to link into the vdso obj-vdso = $(patsubst %, %.o, $(vdso-syms)) note.o diff --git a/arch/csky/kernel/vdso/vdso.lds.S b/arch/csky/kernel/vdso/vdso.lds.S index 590a6c79fff7d7..8d226252d4394e 100644 --- a/arch/csky/kernel/vdso/vdso.lds.S +++ b/arch/csky/kernel/vdso/vdso.lds.S @@ -49,10 +49,6 @@ VERSION LINUX_5.10 { global: __vdso_rt_sigreturn; - __vdso_clock_gettime; - __vdso_clock_gettime64; - __vdso_gettimeofday; - __vdso_clock_getres; local: *; }; } diff --git a/arch/csky/kernel/vdso/vgettimeofday.c b/arch/csky/kernel/vdso/vgettimeofday.c deleted file mode 100644 index 55af30e8375288..00000000000000 --- a/arch/csky/kernel/vdso/vgettimeofday.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include -#include -#include - -extern -int __vdso_clock_gettime(clockid_t clock, - struct old_timespec32 *ts) -{ - return __cvdso_clock_gettime32(clock, ts); -} - -int __vdso_clock_gettime64(clockid_t clock, - struct __kernel_timespec *ts) -{ - return __cvdso_clock_gettime(clock, ts); -} - -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, - struct timezone *tz) -{ - return __cvdso_gettimeofday(tv, tz); -} - -int __vdso_clock_getres(clockid_t clock_id, - struct old_timespec32 *res) -{ - return __cvdso_clock_getres_time32(clock_id, res); -} diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig index e233b5efa2761e..3eb51fbe804ea2 100644 --- a/arch/hexagon/Kconfig +++ b/arch/hexagon/Kconfig @@ -30,8 +30,6 @@ config HEXAGON select HAVE_ARCH_KGDB select HAVE_ARCH_TRACEHOOK select NEED_SG_DMA_LENGTH - select NO_IOPORT_MAP - select GENERIC_IOMAP select GENERIC_IOREMAP select GENERIC_SMP_IDLE_THREAD select STACKTRACE_SUPPORT @@ -59,6 +57,9 @@ config EARLY_PRINTK config MMU def_bool y +config NO_IOPORT_MAP + def_bool y + config GENERIC_CSUM def_bool y diff --git a/arch/hexagon/Makefile b/arch/hexagon/Makefile index 92d005958dfb23..ff172cbe5881a0 100644 --- a/arch/hexagon/Makefile +++ b/arch/hexagon/Makefile @@ -32,3 +32,9 @@ KBUILD_LDFLAGS += $(ldflags-y) TIR_NAME := r19 KBUILD_CFLAGS += -ffixed-$(TIR_NAME) -DTHREADINFO_REG=$(TIR_NAME) -D__linux__ KBUILD_AFLAGS += -DTHREADINFO_REG=$(TIR_NAME) + +# Disable HexagonConstExtenders pass for LLVM versions prior to 19.1.0 +# https://github.com/llvm/llvm-project/issues/99714 +ifneq ($(call clang-min-version, 190100),y) +KBUILD_CFLAGS += -mllvm -hexagon-cext=false +endif diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild index 8c1a78c8f5271e..1efa1e993d4b9a 100644 --- a/arch/hexagon/include/asm/Kbuild +++ b/arch/hexagon/include/asm/Kbuild @@ -5,3 +5,4 @@ generic-y += extable.h generic-y += iomap.h generic-y += kvm_para.h generic-y += mcs_spinlock.h +generic-y += text-patching.h diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index 522d321ea85a75..83b2eb5de60c45 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -8,38 +8,13 @@ #ifndef _ASM_IO_H #define _ASM_IO_H -#ifdef __KERNEL__ - #include -#include #include #include -/* - * We don't have PCI yet. - * _IO_BASE is pointing at what should be unused virtual space. - */ -#define IO_SPACE_LIMIT 0xffff -#define _IO_BASE ((void __iomem *)0xfe000000) - -#define IOMEM(x) ((void __force __iomem *)(x)) - extern int remap_area_pages(unsigned long start, unsigned long phys_addr, unsigned long end, unsigned long flags); -/* Defined in lib/io.c, needed for smc91x driver. */ -extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen); -extern void __raw_writesw(void __iomem *addr, const void *data, int wordlen); - -extern void __raw_readsl(const void __iomem *addr, void *data, int wordlen); -extern void __raw_writesl(void __iomem *addr, const void *data, int wordlen); - -#define readsw(p, d, l) __raw_readsw(p, d, l) -#define writesw(p, d, l) __raw_writesw(p, d, l) - -#define readsl(p, d, l) __raw_readsl(p, d, l) -#define writesl(p, d, l) __raw_writesl(p, d, l) - /* * virt_to_phys - map virtual address to physical * @address: address to map @@ -58,21 +33,12 @@ static inline void *phys_to_virt(unsigned long address) return __va(address); } -/* - * IO port access primitives. Hexagon doesn't have special IO access - * instructions; all I/O is memory mapped. - * - * in/out are used for "ports", but we don't have "port instructions", - * so these are really just memory mapped too. - */ - /* * readb - read byte from memory mapped device * @addr: pointer to memory * - * Operates on "I/O bus memory space" */ -static inline u8 readb(const volatile void __iomem *addr) +static inline u8 __raw_readb(const volatile void __iomem *addr) { u8 val; asm volatile( @@ -82,8 +48,9 @@ static inline u8 readb(const volatile void __iomem *addr) ); return val; } +#define __raw_readb __raw_readb -static inline u16 readw(const volatile void __iomem *addr) +static inline u16 __raw_readw(const volatile void __iomem *addr) { u16 val; asm volatile( @@ -93,8 +60,9 @@ static inline u16 readw(const volatile void __iomem *addr) ); return val; } +#define __raw_readw __raw_readw -static inline u32 readl(const volatile void __iomem *addr) +static inline u32 __raw_readl(const volatile void __iomem *addr) { u32 val; asm volatile( @@ -104,6 +72,7 @@ static inline u32 readl(const volatile void __iomem *addr) ); return val; } +#define __raw_readl __raw_readl /* * writeb - write a byte to a memory location @@ -111,7 +80,7 @@ static inline u32 readl(const volatile void __iomem *addr) * @addr: pointer to memory * */ -static inline void writeb(u8 data, volatile void __iomem *addr) +static inline void __raw_writeb(u8 data, volatile void __iomem *addr) { asm volatile( "memb(%0) = %1;" @@ -120,8 +89,9 @@ static inline void writeb(u8 data, volatile void __iomem *addr) : "memory" ); } +#define __raw_writeb __raw_writeb -static inline void writew(u16 data, volatile void __iomem *addr) +static inline void __raw_writew(u16 data, volatile void __iomem *addr) { asm volatile( "memh(%0) = %1;" @@ -131,8 +101,9 @@ static inline void writew(u16 data, volatile void __iomem *addr) ); } +#define __raw_writew __raw_writew -static inline void writel(u32 data, volatile void __iomem *addr) +static inline void __raw_writel(u32 data, volatile void __iomem *addr) { asm volatile( "memw(%0) = %1;" @@ -141,26 +112,7 @@ static inline void writel(u32 data, volatile void __iomem *addr) : "memory" ); } - -#define __raw_writeb writeb -#define __raw_writew writew -#define __raw_writel writel - -#define __raw_readb readb -#define __raw_readw readw -#define __raw_readl readl - -/* - * http://comments.gmane.org/gmane.linux.ports.arm.kernel/117626 - */ - -#define readb_relaxed __raw_readb -#define readw_relaxed __raw_readw -#define readl_relaxed __raw_readl - -#define writeb_relaxed __raw_writeb -#define writew_relaxed __raw_writew -#define writel_relaxed __raw_writel +#define __raw_writel __raw_writel /* * I/O memory mapping functions. @@ -168,140 +120,6 @@ static inline void writel(u32 data, volatile void __iomem *addr) #define _PAGE_IOREMAP (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ (__HEXAGON_C_DEV << 6)) -#define __raw_writel writel - -static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, - int count) -{ - memcpy(dst, (void *) src, count); -} - -static inline void memcpy_toio(volatile void __iomem *dst, const void *src, - int count) -{ - memcpy((void *) dst, src, count); -} - -static inline void memset_io(volatile void __iomem *addr, int value, - size_t size) -{ - memset((void __force *)addr, value, size); -} - -#define PCI_IO_ADDR (volatile void __iomem *) - -/* - * inb - read byte from I/O port or something - * @port: address in I/O space - * - * Operates on "I/O bus I/O space" - */ -static inline u8 inb(unsigned long port) -{ - return readb(_IO_BASE + (port & IO_SPACE_LIMIT)); -} - -static inline u16 inw(unsigned long port) -{ - return readw(_IO_BASE + (port & IO_SPACE_LIMIT)); -} - -static inline u32 inl(unsigned long port) -{ - return readl(_IO_BASE + (port & IO_SPACE_LIMIT)); -} - -/* - * outb - write a byte to a memory location - * @data: data to write to - * @addr: address in I/O space - */ -static inline void outb(u8 data, unsigned long port) -{ - writeb(data, _IO_BASE + (port & IO_SPACE_LIMIT)); -} - -static inline void outw(u16 data, unsigned long port) -{ - writew(data, _IO_BASE + (port & IO_SPACE_LIMIT)); -} - -static inline void outl(u32 data, unsigned long port) -{ - writel(data, _IO_BASE + (port & IO_SPACE_LIMIT)); -} - -#define outb_p outb -#define outw_p outw -#define outl_p outl - -#define inb_p inb -#define inw_p inw -#define inl_p inl - -static inline void insb(unsigned long port, void *buffer, int count) -{ - if (count) { - u8 *buf = buffer; - do { - u8 x = inb(port); - *buf++ = x; - } while (--count); - } -} - -static inline void insw(unsigned long port, void *buffer, int count) -{ - if (count) { - u16 *buf = buffer; - do { - u16 x = inw(port); - *buf++ = x; - } while (--count); - } -} - -static inline void insl(unsigned long port, void *buffer, int count) -{ - if (count) { - u32 *buf = buffer; - do { - u32 x = inw(port); - *buf++ = x; - } while (--count); - } -} - -static inline void outsb(unsigned long port, const void *buffer, int count) -{ - if (count) { - const u8 *buf = buffer; - do { - outb(*buf++, port); - } while (--count); - } -} - -static inline void outsw(unsigned long port, const void *buffer, int count) -{ - if (count) { - const u16 *buf = buffer; - do { - outw(*buf++, port); - } while (--count); - } -} - -static inline void outsl(unsigned long port, const void *buffer, int count) -{ - if (count) { - const u32 *buf = buffer; - do { - outl(*buf++, port); - } while (--count); - } -} - /* * These defines are necessary to use the generic io.h for filling in * the missing parts of the API contract. This is because the platform @@ -310,23 +128,6 @@ static inline void outsl(unsigned long port, const void *buffer, int count) */ #define virt_to_phys virt_to_phys #define phys_to_virt phys_to_virt -#define memset_io memset_io -#define memcpy_fromio memcpy_fromio -#define memcpy_toio memcpy_toio -#define readb readb -#define readw readw -#define readl readl -#define writeb writeb -#define writew writew -#define writel writel -#define insb insb -#define insw insw -#define insl insl -#define outsb outsb -#define outsw outsw -#define outsl outsl #include -#endif /* __KERNEL__ */ - #endif diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h index 8a6af57274c2db..137ba7c5de4811 100644 --- a/arch/hexagon/include/asm/page.h +++ b/arch/hexagon/include/asm/page.h @@ -45,9 +45,7 @@ #define HVM_HUGEPAGE_SIZE 0x5 #endif -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) +#include #ifdef __KERNEL__ #ifndef __ASSEMBLY__ @@ -118,12 +116,6 @@ static inline void clear_page(void *page) #define clear_user_page(page, vaddr, pg) clear_page(page) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) -/* - * page_to_phys - convert page to physical address - * @page - pointer to page entry in mem_map - */ -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - static inline unsigned long virt_to_pfn(const void *kaddr) { return __pa(kaddr) >> PAGE_SHIFT; diff --git a/arch/hexagon/include/asm/spinlock_types.h b/arch/hexagon/include/asm/spinlock_types.h index d5f66495b670f2..63add2d863e819 100644 --- a/arch/hexagon/include/asm/spinlock_types.h +++ b/arch/hexagon/include/asm/spinlock_types.h @@ -9,7 +9,7 @@ #define _ASM_SPINLOCK_TYPES_H #ifndef __LINUX_SPINLOCK_TYPES_RAW_H -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif typedef struct { diff --git a/arch/hexagon/lib/Makefile b/arch/hexagon/lib/Makefile index a64641e89d5fe7..107894c0910ed2 100644 --- a/arch/hexagon/lib/Makefile +++ b/arch/hexagon/lib/Makefile @@ -2,5 +2,5 @@ # # Makefile for hexagon-specific library files. # -obj-y = checksum.o io.o memcpy.o memset.o memcpy_likely_aligned.o \ +obj-y = checksum.o memcpy.o memset.o memcpy_likely_aligned.o \ divsi3.o modsi3.o udivsi3.o umodsi3.o diff --git a/arch/hexagon/lib/io.c b/arch/hexagon/lib/io.c deleted file mode 100644 index 55f75392857b00..00000000000000 --- a/arch/hexagon/lib/io.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * I/O access functions for Hexagon - * - * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. - */ - -#include - -/* These are all FIFO routines! */ - -/* - * __raw_readsw - read words a short at a time - * @addr: source address - * @data: data address - * @len: number of shorts to read - */ -void __raw_readsw(const void __iomem *addr, void *data, int len) -{ - const volatile short int *src = (short int *) addr; - short int *dst = (short int *) data; - - if ((u32)data & 0x1) - panic("unaligned pointer to readsw"); - - while (len-- > 0) - *dst++ = *src; - -} -EXPORT_SYMBOL(__raw_readsw); - -/* - * __raw_writesw - read words a short at a time - * @addr: source address - * @data: data address - * @len: number of shorts to read - */ -void __raw_writesw(void __iomem *addr, const void *data, int len) -{ - const short int *src = (short int *)data; - volatile short int *dst = (short int *)addr; - - if ((u32)data & 0x1) - panic("unaligned pointer to writesw"); - - while (len-- > 0) - *dst = *src++; - - -} -EXPORT_SYMBOL(__raw_writesw); - -/* Pretty sure len is pre-adjusted for the length of the access already */ -void __raw_readsl(const void __iomem *addr, void *data, int len) -{ - const volatile long *src = (long *) addr; - long *dst = (long *) data; - - if ((u32)data & 0x3) - panic("unaligned pointer to readsl"); - - while (len-- > 0) - *dst++ = *src; - - -} -EXPORT_SYMBOL(__raw_readsl); - -void __raw_writesl(void __iomem *addr, const void *data, int len) -{ - const long *src = (long *)data; - volatile long *dst = (long *)addr; - - if ((u32)data & 0x3) - panic("unaligned pointer to writesl"); - - while (len-- > 0) - *dst = *src++; - - -} -EXPORT_SYMBOL(__raw_writesl); diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index d9fce0fd475a04..dae3a9104ca658 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -23,6 +23,7 @@ config LOONGARCH select ARCH_HAS_KERNEL_FPU_SUPPORT if CPU_HAS_FPU select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + select ARCH_HAS_PREEMPT_LAZY select ARCH_HAS_PTE_DEVMAP select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SET_MEMORY @@ -66,6 +67,7 @@ config LOONGARCH select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_LTO_CLANG_THIN select ARCH_SUPPORTS_NUMA_BALANCING + select ARCH_SUPPORTS_RT select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_QUEUED_RWLOCKS @@ -155,6 +157,7 @@ config LOONGARCH select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select HAVE_POSIX_CPU_TIMERS_TASK_WORK select HAVE_PREEMPT_DYNAMIC_KEY select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE if UNWINDER_ORC diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index ae3f80622f4c60..567bd122a9ee47 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -59,7 +59,7 @@ endif ifdef CONFIG_64BIT ld-emul = $(64bit-emul) -cflags-y += -mabi=lp64s +cflags-y += -mabi=lp64s -mcmodel=normal endif cflags-y += -pipe $(CC_FLAGS_NO_FPU) @@ -104,7 +104,7 @@ ifdef CONFIG_OBJTOOL KBUILD_CFLAGS += -fno-jump-tables endif -KBUILD_RUSTFLAGS += --target=loongarch64-unknown-none-softfloat +KBUILD_RUSTFLAGS += --target=loongarch64-unknown-none-softfloat -Ccode-model=small KBUILD_RUSTFLAGS_KERNEL += -Zdirect-access-external-data=yes KBUILD_RUSTFLAGS_MODULE += -Zdirect-access-external-data=no diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi index 92180140eb56e4..8dff2aa5241717 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -266,7 +266,7 @@ dma-controller@1fe00c10 { status = "disabled"; }; - dma-controller@1fe00c20 { + apbdma2: dma-controller@1fe00c20 { compatible = "loongson,ls2k1000-apbdma"; reg = <0x0 0x1fe00c20 0x0 0x8>; interrupt-parent = <&liointc1>; @@ -276,7 +276,7 @@ dma-controller@1fe00c20 { status = "disabled"; }; - dma-controller@1fe00c30 { + apbdma3: dma-controller@1fe00c30 { compatible = "loongson,ls2k1000-apbdma"; reg = <0x0 0x1fe00c30 0x0 0x8>; interrupt-parent = <&liointc1>; @@ -352,6 +352,19 @@ rtc0: rtc@1fe27800 { status = "disabled"; }; + i2s: i2s@1fe2d000 { + compatible = "loongson,ls2k1000-i2s"; + reg = <0 0x1fe2d000 0 0x14>, + <0 0x1fe00438 0 0x8>; + interrupt-parent = <&liointc0>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + dmas = <&apbdma2 0>, <&apbdma3 0>; + dma-names = "tx", "rx"; + #sound-dai-cells = <0>; + status = "disabled"; + }; + spi0: spi@1fff0220 { compatible = "loongson,ls2k1000-spi"; reg = <0x0 0x1fff0220 0x0 0x10>; diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi index 0953c57078256d..b4ff55a33e90b9 100644 --- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi @@ -173,6 +173,22 @@ rtc0: rtc@100d0100 { status = "disabled"; }; + i2c@1fe00120 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1fe00120 0x0 0x8>; + interrupt-parent = <&liointc>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + i2c@1fe00130 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1fe00130 0x0 0x8>; + interrupt-parent = <&liointc>; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + uart0: serial@1fe001e0 { compatible = "ns16550a"; reg = <0x0 0x1fe001e0 0x0 0x10>; @@ -243,9 +259,11 @@ display@6,1 { status = "disabled"; }; - hda@7,0 { + i2s@7,0 { reg = <0x3800 0x0 0x0 0x0 0x0>; - interrupts = <58 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <78 IRQ_TYPE_LEVEL_HIGH>, + <79 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tx", "rx"; interrupt-parent = <&pic>; status = "disabled"; }; diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig index 75b366407a60a3..4dffc90192f781 100644 --- a/arch/loongarch/configs/loongson3_defconfig +++ b/arch/loongarch/configs/loongson3_defconfig @@ -1,4 +1,5 @@ # CONFIG_LOCALVERSION_AUTO is not set +CONFIG_KERNEL_ZSTD=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_NO_HZ=y @@ -70,6 +71,14 @@ CONFIG_ACPI_IPMI=m CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_PCI_SLOT=y CONFIG_ACPI_HOTPLUG_MEMORY=y +CONFIG_ACPI_BGRT=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_LOONGSON3_CPUFREQ=m CONFIG_VIRTUALIZATION=y CONFIG_KVM=m CONFIG_JUMP_LABEL=y @@ -78,6 +87,9 @@ CONFIG_MODULE_FORCE_LOAD=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_MODULE_COMPRESS=y +CONFIG_MODULE_COMPRESS_ZSTD=y +CONFIG_MODULE_DECOMPRESS=y CONFIG_BLK_DEV_ZONED=y CONFIG_BLK_DEV_THROTTLING=y CONFIG_BLK_WBT=y @@ -85,6 +97,8 @@ CONFIG_BLK_CGROUP_IOLATENCY=y CONFIG_BLK_CGROUP_FC_APPID=y CONFIG_BLK_CGROUP_IOCOST=y CONFIG_BLK_CGROUP_IOPRIO=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y CONFIG_PARTITION_ADVANCED=y CONFIG_BSD_DISKLABEL=y CONFIG_UNIXWARE_DISKLABEL=y @@ -413,7 +427,16 @@ CONFIG_PARPORT_PC=y CONFIG_PARPORT_SERIAL=y CONFIG_PARPORT_PC_FIFO=y CONFIG_ZRAM=m +CONFIG_ZRAM_BACKEND_LZ4=y +CONFIG_ZRAM_BACKEND_LZ4HC=y +CONFIG_ZRAM_BACKEND_ZSTD=y +CONFIG_ZRAM_BACKEND_DEFLATE=y +CONFIG_ZRAM_BACKEND_842=y +CONFIG_ZRAM_BACKEND_LZO=y CONFIG_ZRAM_DEF_COMP_ZSTD=y +CONFIG_ZRAM_WRITEBACK=y +CONFIG_ZRAM_MEMORY_TRACKING=y +CONFIG_ZRAM_MULTI_COMP=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_DRBD=m CONFIG_BLK_DEV_NBD=m @@ -433,6 +456,9 @@ CONFIG_NVME_TARGET_RDMA=m CONFIG_NVME_TARGET_FC=m CONFIG_NVME_TARGET_TCP=m CONFIG_EEPROM_AT24=m +CONFIG_PVPANIC=y +CONFIG_PVPANIC_MMIO=m +CONFIG_PVPANIC_PCI=m CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y CONFIG_CHR_DEV_SG=y @@ -470,12 +496,10 @@ CONFIG_PATA_ATIIXP=y CONFIG_PATA_PCMCIA=m CONFIG_MD=y CONFIG_BLK_DEV_MD=m -CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID10=m CONFIG_MD_RAID456=m -CONFIG_MD_MULTIPATH=m CONFIG_BCACHE=m CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=m @@ -489,6 +513,16 @@ 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_INIT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=m +CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_INTEGRITY=m +CONFIG_DM_ZONED=m +CONFIG_DM_VDO=m CONFIG_TARGET_CORE=m CONFIG_TCM_IBLOCK=m CONFIG_TCM_FILEIO=m @@ -500,6 +534,13 @@ CONFIG_NETDEVICES=y CONFIG_BONDING=m CONFIG_DUMMY=y CONFIG_WIREGUARD=m +CONFIG_IFB=m +CONFIG_NET_TEAM=m +CONFIG_NET_TEAM_MODE_BROADCAST=m +CONFIG_NET_TEAM_MODE_ROUNDROBIN=m +CONFIG_NET_TEAM_MODE_RANDOM=m +CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m +CONFIG_NET_TEAM_MODE_LOADBALANCE=m CONFIG_MACVLAN=m CONFIG_MACVTAP=m CONFIG_IPVLAN=m @@ -580,12 +621,14 @@ CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m CONFIG_USB_RTL8150=m CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m # CONFIG_USB_NET_AX8817X is not set # CONFIG_USB_NET_AX88179_178A is not set CONFIG_USB_NET_CDC_EEM=m CONFIG_USB_NET_HUAWEI_CDC_NCM=m CONFIG_USB_NET_CDC_MBIM=m # CONFIG_USB_NET_NET1080 is not set +CONFIG_USB_NET_RNDIS_HOST=m # CONFIG_USB_BELKIN is not set # CONFIG_USB_ARMLINUX is not set # CONFIG_USB_NET_ZAURUS is not set @@ -594,10 +637,11 @@ CONFIG_ATH9K_HTC=m CONFIG_IWLWIFI=m CONFIG_IWLDVM=m CONFIG_IWLMVM=m -CONFIG_HOSTAP=m CONFIG_MT7601U=m CONFIG_RT2X00=m CONFIG_RT2800USB=m +CONFIG_RTL8180=m +CONFIG_RTL8187=m CONFIG_RTL8192CE=m CONFIG_RTL8192SE=m CONFIG_RTL8192DE=m @@ -607,18 +651,26 @@ CONFIG_RTL8188EE=m CONFIG_RTL8192EE=m CONFIG_RTL8821AE=m CONFIG_RTL8192CU=m +CONFIG_RTL8192DU=m # CONFIG_RTLWIFI_DEBUG is not set CONFIG_RTL8XXXU=m CONFIG_RTW88=m CONFIG_RTW88_8822BE=m +CONFIG_RTW88_8822BU=m CONFIG_RTW88_8822CE=m +CONFIG_RTW88_8822CU=m CONFIG_RTW88_8723DE=m +CONFIG_RTW88_8723DU=m CONFIG_RTW88_8821CE=m +CONFIG_RTW88_8821CU=m CONFIG_RTW89=m +CONFIG_RTW89_8851BE=m CONFIG_RTW89_8852AE=m +CONFIG_RTW89_8852BE=m +CONFIG_RTW89_8852BTE=m CONFIG_RTW89_8852CE=m +CONFIG_RTW89_8922AE=m CONFIG_ZD1211RW=m -CONFIG_USB_NET_RNDIS_WLAN=m CONFIG_USB4_NET=m CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_MOUSEDEV_PSAUX=y @@ -651,6 +703,9 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_PIIX4=y +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_I2C_DESIGNWARE_SLAVE=y +CONFIG_I2C_DESIGNWARE_PCI=y CONFIG_I2C_GPIO=y CONFIG_I2C_LS2X=y CONFIG_SPI=y @@ -727,11 +782,22 @@ CONFIG_SND_HDA_CODEC_CONEXANT=y CONFIG_SND_USB_AUDIO=m CONFIG_SND_SOC=m CONFIG_SND_SOC_LOONGSON_CARD=m +CONFIG_SND_SOC_ES7134=m +CONFIG_SND_SOC_ES7241=m +CONFIG_SND_SOC_ES8311=m +CONFIG_SND_SOC_ES8316=m +CONFIG_SND_SOC_ES8323=m +CONFIG_SND_SOC_ES8326=m +CONFIG_SND_SOC_ES8328_I2C=m +CONFIG_SND_SOC_ES8328_SPI=m +CONFIG_SND_SOC_UDA1334=m +CONFIG_SND_SOC_UDA1342=m CONFIG_SND_VIRTIO=m CONFIG_HIDRAW=y CONFIG_UHID=m CONFIG_HID_A4TECH=m CONFIG_HID_CHERRY=m +CONFIG_HID_ELAN=m CONFIG_HID_LOGITECH=m CONFIG_HID_LOGITECH_DJ=m CONFIG_LOGITECH_FF=y @@ -740,7 +806,11 @@ CONFIG_LOGIG940_FF=y CONFIG_HID_MICROSOFT=m CONFIG_HID_MULTITOUCH=m CONFIG_HID_SUNPLUS=m +CONFIG_HID_WACOM=m CONFIG_USB_HIDDEV=y +CONFIG_I2C_HID_ACPI=m +CONFIG_I2C_HID_OF=m +CONFIG_I2C_HID_OF_ELAN=m CONFIG_USB=y CONFIG_USB_OTG=y CONFIG_USB_MON=y @@ -775,7 +845,7 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_EFI=y CONFIG_RTC_DRV_LOONGSON=y CONFIG_DMADEVICES=y -CONFIG_LS2X_APB_DMA=y +CONFIG_LOONGSON2_APB_DMA=y CONFIG_UDMABUF=y CONFIG_DMABUF_HEAPS=y CONFIG_DMABUF_HEAPS_SYSTEM=y @@ -852,6 +922,9 @@ CONFIG_F2FS_FS=m CONFIG_F2FS_FS_SECURITY=y CONFIG_F2FS_CHECK_FS=y CONFIG_F2FS_FS_COMPRESSION=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y CONFIG_FANOTIFY=y CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y CONFIG_QUOTA=y @@ -904,16 +977,14 @@ CONFIG_SQUASHFS_ZSTD=y CONFIG_MINIX_FS=m CONFIG_ROMFS_FS=m CONFIG_PSTORE=m -CONFIG_PSTORE_LZO_COMPRESS=m -CONFIG_PSTORE_LZ4_COMPRESS=m -CONFIG_PSTORE_LZ4HC_COMPRESS=m -CONFIG_PSTORE_842_COMPRESS=y -CONFIG_PSTORE_ZSTD_COMPRESS=y -CONFIG_PSTORE_ZSTD_COMPRESS_DEFAULT=y +CONFIG_PSTORE_COMPRESS=y CONFIG_SYSV_FS=m CONFIG_UFS_FS=m CONFIG_EROFS_FS=m CONFIG_EROFS_FS_ZIP_LZMA=y +CONFIG_EROFS_FS_ZIP_DEFLATE=y +CONFIG_EROFS_FS_ZIP_ZSTD=y +CONFIG_EROFS_FS_ONDEMAND=y CONFIG_EROFS_FS_PCPU_KTHREAD=y CONFIG_NFS_FS=y CONFIG_NFS_V3_ACL=y diff --git a/arch/loongarch/include/asm/Kbuild b/arch/loongarch/include/asm/Kbuild index 5b5a6c90e6e207..80ddb5edb8455c 100644 --- a/arch/loongarch/include/asm/Kbuild +++ b/arch/loongarch/include/asm/Kbuild @@ -11,3 +11,4 @@ generic-y += ioctl.h generic-y += mmzone.h generic-y += statfs.h generic-y += param.h +generic-y += text-patching.h diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h index c0a682808e0707..8f13eaeaa32511 100644 --- a/arch/loongarch/include/asm/ftrace.h +++ b/arch/loongarch/include/asm/ftrace.h @@ -44,40 +44,19 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent); #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS struct ftrace_ops; -struct ftrace_regs { - struct pt_regs regs; -}; +#include static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) { - return &fregs->regs; -} - -static __always_inline unsigned long -ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs) -{ - return instruction_pointer(&fregs->regs); + return &arch_ftrace_regs(fregs)->regs; } static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) { - instruction_pointer_set(&fregs->regs, ip); + instruction_pointer_set(&arch_ftrace_regs(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); @@ -90,7 +69,7 @@ __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) } #define arch_ftrace_set_direct_caller(fregs, addr) \ - __arch_ftrace_set_direct_caller(&(fregs)->regs, addr) + __arch_ftrace_set_direct_caller(&arch_ftrace_regs(fregs)->regs, addr) #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ #endif diff --git a/arch/loongarch/include/asm/hugetlb.h b/arch/loongarch/include/asm/hugetlb.h index 5da32c00d483fb..c8e4057734d0de 100644 --- a/arch/loongarch/include/asm/hugetlb.h +++ b/arch/loongarch/include/asm/hugetlb.h @@ -16,12 +16,7 @@ static inline int prepare_hugepage_range(struct file *file, unsigned long len) { unsigned long task_size = STACK_TOP; - struct hstate *h = hstate_file(file); - if (len & ~huge_page_mask(h)) - return -EINVAL; - if (addr & ~huge_page_mask(h)) - return -EINVAL; if (len > task_size) return -ENOMEM; if (task_size - len < addr) @@ -29,6 +24,16 @@ static inline int prepare_hugepage_range(struct file *file, return 0; } +#define __HAVE_ARCH_HUGE_PTE_CLEAR +static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, unsigned long sz) +{ + pte_t clear; + + pte_val(clear) = (unsigned long)invalid_pte_table; + set_pte_at(mm, addr, ptep, clear); +} + #define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h index 944482063f14e3..3089785ca97e78 100644 --- a/arch/loongarch/include/asm/inst.h +++ b/arch/loongarch/include/asm/inst.h @@ -683,7 +683,17 @@ DEF_EMIT_REG2I16_FORMAT(blt, blt_op) DEF_EMIT_REG2I16_FORMAT(bge, bge_op) DEF_EMIT_REG2I16_FORMAT(bltu, bltu_op) DEF_EMIT_REG2I16_FORMAT(bgeu, bgeu_op) -DEF_EMIT_REG2I16_FORMAT(jirl, jirl_op) + +static inline void emit_jirl(union loongarch_instruction *insn, + enum loongarch_gpr rd, + enum loongarch_gpr rj, + int offset) +{ + insn->reg2i16_format.opcode = jirl_op; + insn->reg2i16_format.immediate = offset; + insn->reg2i16_format.rd = rd; + insn->reg2i16_format.rj = rj; +} #define DEF_EMIT_REG2BSTRD_FORMAT(NAME, OP) \ static inline void emit_##NAME(union loongarch_instruction *insn, \ diff --git a/arch/loongarch/include/asm/io.h b/arch/loongarch/include/asm/io.h index 5e95a60df1808a..e77a56eaf90604 100644 --- a/arch/loongarch/include/asm/io.h +++ b/arch/loongarch/include/asm/io.h @@ -62,16 +62,6 @@ static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size, #define mmiowb() wmb() -/* - * String version of I/O memory access operations. - */ -extern void __memset_io(volatile void __iomem *dst, int c, size_t count); -extern void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count); -extern void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count); -#define memset_io(c, v, l) __memset_io((c), (v), (l)) -#define memcpy_fromio(a, c, l) __memcpy_fromio((a), (c), (l)) -#define memcpy_toio(c, a, l) __memcpy_toio((c), (a), (l)) - #define __io_aw() mmiowb() #ifdef CONFIG_KFENCE diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h index 9c2ca785faa9bd..a0ca84da8541d5 100644 --- a/arch/loongarch/include/asm/irq.h +++ b/arch/loongarch/include/asm/irq.h @@ -65,6 +65,7 @@ extern struct acpi_vector_group pch_group[MAX_IO_PICS]; extern struct acpi_vector_group msi_group[MAX_IO_PICS]; #define CORES_PER_EIO_NODE 4 +#define CORES_PER_VEIO_NODE 256 #define LOONGSON_CPU_UART0_VEC 10 /* CPU UART0 */ #define LOONGSON_CPU_THSENS_VEC 14 /* CPU Thsens */ diff --git a/arch/loongarch/include/asm/jump_label.h b/arch/loongarch/include/asm/jump_label.h index 29acfe3de3faae..8a924bd69d1966 100644 --- a/arch/loongarch/include/asm/jump_label.h +++ b/arch/loongarch/include/asm/jump_label.h @@ -13,18 +13,22 @@ #define JUMP_LABEL_NOP_SIZE 4 -#define JUMP_TABLE_ENTRY \ +/* This macro is also expanded on the Rust side. */ +#define JUMP_TABLE_ENTRY(key, label) \ ".pushsection __jump_table, \"aw\" \n\t" \ ".align 3 \n\t" \ - ".long 1b - ., %l[l_yes] - . \n\t" \ - ".quad %0 - . \n\t" \ + ".long 1b - ., " label " - . \n\t" \ + ".quad " key " - . \n\t" \ ".popsection \n\t" +#define ARCH_STATIC_BRANCH_ASM(key, label) \ + "1: nop \n\t" \ + JUMP_TABLE_ENTRY(key, label) + static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) { asm goto( - "1: nop \n\t" - JUMP_TABLE_ENTRY + ARCH_STATIC_BRANCH_ASM("%0", "%l[l_yes]") : : "i"(&((char *)key)[branch]) : : l_yes); return false; @@ -37,7 +41,7 @@ static __always_inline bool arch_static_branch_jump(struct static_key * const ke { asm goto( "1: b %l[l_yes] \n\t" - JUMP_TABLE_ENTRY + JUMP_TABLE_ENTRY("%0", "%l[l_yes]") : : "i"(&((char *)key)[branch]) : : l_yes); return false; diff --git a/arch/loongarch/include/asm/kvm_eiointc.h b/arch/loongarch/include/asm/kvm_eiointc.h new file mode 100644 index 00000000000000..a3a40aba8acf29 --- /dev/null +++ b/arch/loongarch/include/asm/kvm_eiointc.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_KVM_EIOINTC_H +#define __ASM_KVM_EIOINTC_H + +#include + +#define EIOINTC_IRQS 256 +#define EIOINTC_ROUTE_MAX_VCPUS 256 +#define EIOINTC_IRQS_U8_NUMS (EIOINTC_IRQS / 8) +#define EIOINTC_IRQS_U16_NUMS (EIOINTC_IRQS_U8_NUMS / 2) +#define EIOINTC_IRQS_U32_NUMS (EIOINTC_IRQS_U8_NUMS / 4) +#define EIOINTC_IRQS_U64_NUMS (EIOINTC_IRQS_U8_NUMS / 8) +/* map to ipnum per 32 irqs */ +#define EIOINTC_IRQS_NODETYPE_COUNT 16 + +#define EIOINTC_BASE 0x1400 +#define EIOINTC_SIZE 0x900 + +#define EIOINTC_NODETYPE_START 0xa0 +#define EIOINTC_NODETYPE_END 0xbf +#define EIOINTC_IPMAP_START 0xc0 +#define EIOINTC_IPMAP_END 0xc7 +#define EIOINTC_ENABLE_START 0x200 +#define EIOINTC_ENABLE_END 0x21f +#define EIOINTC_BOUNCE_START 0x280 +#define EIOINTC_BOUNCE_END 0x29f +#define EIOINTC_ISR_START 0x300 +#define EIOINTC_ISR_END 0x31f +#define EIOINTC_COREISR_START 0x400 +#define EIOINTC_COREISR_END 0x41f +#define EIOINTC_COREMAP_START 0x800 +#define EIOINTC_COREMAP_END 0x8ff + +#define EIOINTC_VIRT_BASE (0x40000000) +#define EIOINTC_VIRT_SIZE (0x1000) + +#define EIOINTC_VIRT_FEATURES (0x0) +#define EIOINTC_HAS_VIRT_EXTENSION (0) +#define EIOINTC_HAS_ENABLE_OPTION (1) +#define EIOINTC_HAS_INT_ENCODE (2) +#define EIOINTC_HAS_CPU_ENCODE (3) +#define EIOINTC_VIRT_HAS_FEATURES ((1U << EIOINTC_HAS_VIRT_EXTENSION) \ + | (1U << EIOINTC_HAS_ENABLE_OPTION) \ + | (1U << EIOINTC_HAS_INT_ENCODE) \ + | (1U << EIOINTC_HAS_CPU_ENCODE)) +#define EIOINTC_VIRT_CONFIG (0x4) +#define EIOINTC_ENABLE (1) +#define EIOINTC_ENABLE_INT_ENCODE (2) +#define EIOINTC_ENABLE_CPU_ENCODE (3) + +#define LOONGSON_IP_NUM 8 + +struct loongarch_eiointc { + spinlock_t lock; + struct kvm *kvm; + struct kvm_io_device device; + struct kvm_io_device device_vext; + uint32_t num_cpu; + uint32_t features; + uint32_t status; + + /* hardware state */ + union nodetype { + u64 reg_u64[EIOINTC_IRQS_NODETYPE_COUNT / 4]; + u32 reg_u32[EIOINTC_IRQS_NODETYPE_COUNT / 2]; + u16 reg_u16[EIOINTC_IRQS_NODETYPE_COUNT]; + u8 reg_u8[EIOINTC_IRQS_NODETYPE_COUNT * 2]; + } nodetype; + + /* one bit shows the state of one irq */ + union bounce { + u64 reg_u64[EIOINTC_IRQS_U64_NUMS]; + u32 reg_u32[EIOINTC_IRQS_U32_NUMS]; + u16 reg_u16[EIOINTC_IRQS_U16_NUMS]; + u8 reg_u8[EIOINTC_IRQS_U8_NUMS]; + } bounce; + + union isr { + u64 reg_u64[EIOINTC_IRQS_U64_NUMS]; + u32 reg_u32[EIOINTC_IRQS_U32_NUMS]; + u16 reg_u16[EIOINTC_IRQS_U16_NUMS]; + u8 reg_u8[EIOINTC_IRQS_U8_NUMS]; + } isr; + union coreisr { + u64 reg_u64[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U64_NUMS]; + u32 reg_u32[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U32_NUMS]; + u16 reg_u16[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U16_NUMS]; + u8 reg_u8[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U8_NUMS]; + } coreisr; + union enable { + u64 reg_u64[EIOINTC_IRQS_U64_NUMS]; + u32 reg_u32[EIOINTC_IRQS_U32_NUMS]; + u16 reg_u16[EIOINTC_IRQS_U16_NUMS]; + u8 reg_u8[EIOINTC_IRQS_U8_NUMS]; + } enable; + + /* use one byte to config ipmap for 32 irqs at once */ + union ipmap { + u64 reg_u64; + u32 reg_u32[EIOINTC_IRQS_U32_NUMS / 4]; + u16 reg_u16[EIOINTC_IRQS_U16_NUMS / 4]; + u8 reg_u8[EIOINTC_IRQS_U8_NUMS / 4]; + } ipmap; + /* use one byte to config coremap for one irq */ + union coremap { + u64 reg_u64[EIOINTC_IRQS / 8]; + u32 reg_u32[EIOINTC_IRQS / 4]; + u16 reg_u16[EIOINTC_IRQS / 2]; + u8 reg_u8[EIOINTC_IRQS]; + } coremap; + + DECLARE_BITMAP(sw_coreisr[EIOINTC_ROUTE_MAX_VCPUS][LOONGSON_IP_NUM], EIOINTC_IRQS); + uint8_t sw_coremap[EIOINTC_IRQS]; +}; + +int kvm_loongarch_register_eiointc_device(void); +void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level); + +#endif /* __ASM_KVM_EIOINTC_H */ diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h index d6bb72424027aa..7b8367c39da85f 100644 --- a/arch/loongarch/include/asm/kvm_host.h +++ b/arch/loongarch/include/asm/kvm_host.h @@ -18,8 +18,13 @@ #include #include +#include +#include +#include #include +#define __KVM_HAVE_ARCH_INTC_INITIALIZED + /* Loongarch KVM register ids */ #define KVM_GET_IOC_CSR_IDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT) #define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT) @@ -44,6 +49,12 @@ struct kvm_vm_stat { struct kvm_vm_stat_generic generic; u64 pages; u64 hugepages; + u64 ipi_read_exits; + u64 ipi_write_exits; + u64 eiointc_read_exits; + u64 eiointc_write_exits; + u64 pch_pic_read_exits; + u64 pch_pic_write_exits; }; struct kvm_vcpu_stat { @@ -84,7 +95,7 @@ struct kvm_world_switch { * * For LOONGARCH_CSR_CPUID register, max CPUID size if 512 * For IPI hardware, max destination CPUID size 1024 - * For extioi interrupt controller, max destination CPUID size is 256 + * For eiointc interrupt controller, max destination CPUID size is 256 * For msgint interrupt controller, max supported CPUID size is 65536 * * Currently max CPUID is defined as 256 for KVM hypervisor, in future @@ -117,6 +128,9 @@ struct kvm_arch { s64 time_offset; struct kvm_context __percpu *vmcs; + struct loongarch_ipi *ipi; + struct loongarch_eiointc *eiointc; + struct loongarch_pch_pic *pch_pic; }; #define CSR_MAX_NUMS 0x800 @@ -221,6 +235,8 @@ struct kvm_vcpu_arch { int last_sched_cpu; /* mp state */ struct kvm_mp_state mp_state; + /* ipi state */ + struct ipi_state ipi_state; /* cpucfg */ u32 cpucfg[KVM_MAX_CPUCFG_REGS]; diff --git a/arch/loongarch/include/asm/kvm_ipi.h b/arch/loongarch/include/asm/kvm_ipi.h new file mode 100644 index 00000000000000..060163dfb4a380 --- /dev/null +++ b/arch/loongarch/include/asm/kvm_ipi.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_KVM_IPI_H +#define __ASM_KVM_IPI_H + +#include + +#define LARCH_INT_IPI 12 + +struct loongarch_ipi { + spinlock_t lock; + struct kvm *kvm; + struct kvm_io_device device; +}; + +struct ipi_state { + spinlock_t lock; + uint32_t status; + uint32_t en; + uint32_t set; + uint32_t clear; + uint64_t buf[4]; +}; + +#define IOCSR_IPI_BASE 0x1000 +#define IOCSR_IPI_SIZE 0x160 + +#define IOCSR_IPI_STATUS 0x000 +#define IOCSR_IPI_EN 0x004 +#define IOCSR_IPI_SET 0x008 +#define IOCSR_IPI_CLEAR 0x00c +#define IOCSR_IPI_BUF_20 0x020 +#define IOCSR_IPI_BUF_28 0x028 +#define IOCSR_IPI_BUF_30 0x030 +#define IOCSR_IPI_BUF_38 0x038 +#define IOCSR_IPI_SEND 0x040 +#define IOCSR_MAIL_SEND 0x048 +#define IOCSR_ANY_SEND 0x158 + +int kvm_loongarch_register_ipi_device(void); + +#endif diff --git a/arch/loongarch/include/asm/kvm_pch_pic.h b/arch/loongarch/include/asm/kvm_pch_pic.h new file mode 100644 index 00000000000000..e6df6a4c1c7052 --- /dev/null +++ b/arch/loongarch/include/asm/kvm_pch_pic.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */ + +#ifndef __ASM_KVM_PCH_PIC_H +#define __ASM_KVM_PCH_PIC_H + +#include + +#define PCH_PIC_SIZE 0x3e8 + +#define PCH_PIC_INT_ID_START 0x0 +#define PCH_PIC_INT_ID_END 0x7 +#define PCH_PIC_MASK_START 0x20 +#define PCH_PIC_MASK_END 0x27 +#define PCH_PIC_HTMSI_EN_START 0x40 +#define PCH_PIC_HTMSI_EN_END 0x47 +#define PCH_PIC_EDGE_START 0x60 +#define PCH_PIC_EDGE_END 0x67 +#define PCH_PIC_CLEAR_START 0x80 +#define PCH_PIC_CLEAR_END 0x87 +#define PCH_PIC_AUTO_CTRL0_START 0xc0 +#define PCH_PIC_AUTO_CTRL0_END 0xc7 +#define PCH_PIC_AUTO_CTRL1_START 0xe0 +#define PCH_PIC_AUTO_CTRL1_END 0xe7 +#define PCH_PIC_ROUTE_ENTRY_START 0x100 +#define PCH_PIC_ROUTE_ENTRY_END 0x13f +#define PCH_PIC_HTMSI_VEC_START 0x200 +#define PCH_PIC_HTMSI_VEC_END 0x23f +#define PCH_PIC_INT_IRR_START 0x380 +#define PCH_PIC_INT_IRR_END 0x38f +#define PCH_PIC_INT_ISR_START 0x3a0 +#define PCH_PIC_INT_ISR_END 0x3af +#define PCH_PIC_POLARITY_START 0x3e0 +#define PCH_PIC_POLARITY_END 0x3e7 +#define PCH_PIC_INT_ID_VAL 0x7000000UL +#define PCH_PIC_INT_ID_VER 0x1UL + +struct loongarch_pch_pic { + spinlock_t lock; + struct kvm *kvm; + struct kvm_io_device device; + uint64_t mask; /* 1:disable irq, 0:enable irq */ + uint64_t htmsi_en; /* 1:msi */ + uint64_t edge; /* 1:edge triggered, 0:level triggered */ + uint64_t auto_ctrl0; /* only use default value 00b */ + uint64_t auto_ctrl1; /* only use default value 00b */ + uint64_t last_intirr; /* edge detection */ + uint64_t irr; /* interrupt request register */ + uint64_t isr; /* interrupt service register */ + uint64_t polarity; /* 0: high level trigger, 1: low level trigger */ + uint8_t route_entry[64]; /* default value 0, route to int0: eiointc */ + uint8_t htmsi_vector[64]; /* irq route table for routing to eiointc */ + uint64_t pch_pic_base; +}; + +int kvm_loongarch_register_pch_pic_device(void); +void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level); +void pch_msi_set_irq(struct kvm *kvm, int irq, int level); + +#endif /* __ASM_KVM_PCH_PIC_H */ diff --git a/arch/loongarch/include/asm/page.h b/arch/loongarch/include/asm/page.h index 8f21567a3188b4..7368f12b7cb1ec 100644 --- a/arch/loongarch/include/asm/page.h +++ b/arch/loongarch/include/asm/page.h @@ -8,12 +8,7 @@ #include #include -/* - * PAGE_SHIFT determines the page size - */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE - 1)) +#include #define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3) #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) @@ -81,9 +76,6 @@ struct page *tlb_virt_to_page(unsigned long kaddr); #define pfn_to_phys(pfn) __pfn_to_phys(pfn) #define phys_to_pfn(paddr) __phys_to_pfn(paddr) -#define page_to_phys(page) pfn_to_phys(page_to_pfn(page)) -#define phys_to_page(paddr) pfn_to_page(phys_to_pfn(paddr)) - #ifndef CONFIG_KFENCE #define page_to_virt(page) __va(page_to_phys(page)) diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h index 20714b73f14c8e..da346733a1daed 100644 --- a/arch/loongarch/include/asm/pgtable.h +++ b/arch/loongarch/include/asm/pgtable.h @@ -268,8 +268,11 @@ extern void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pm */ extern void pgd_init(void *addr); extern void pud_init(void *addr); +#define pud_init pud_init extern void pmd_init(void *addr); +#define pmd_init pmd_init extern void kernel_pte_init(void *addr); +#define kernel_pte_init kernel_pte_init /* * Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that diff --git a/arch/loongarch/include/asm/set_memory.h b/arch/loongarch/include/asm/set_memory.h index d70505b6676cb3..55dfaefd02c8a6 100644 --- a/arch/loongarch/include/asm/set_memory.h +++ b/arch/loongarch/include/asm/set_memory.h @@ -17,5 +17,6 @@ int set_memory_rw(unsigned long addr, int numpages); bool kernel_page_present(struct page *page); int set_direct_map_default_noflush(struct page *page); int set_direct_map_invalid_noflush(struct page *page); +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid); #endif /* _ASM_LOONGARCH_SET_MEMORY_H */ diff --git a/arch/loongarch/include/asm/thread_info.h b/arch/loongarch/include/asm/thread_info.h index 8bf0e6f5154668..4f5a9441754e39 100644 --- a/arch/loongarch/include/asm/thread_info.h +++ b/arch/loongarch/include/asm/thread_info.h @@ -66,8 +66,9 @@ register unsigned long current_stack_pointer __asm__("$sp"); * - pending work-to-be-done flags are in LSW * - other flags in MSW */ -#define TIF_SIGPENDING 1 /* signal pending */ -#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ +#define TIF_NEED_RESCHED 0 /* rescheduling necessary */ +#define TIF_NEED_RESCHED_LAZY 1 /* lazy rescheduling necessary */ +#define TIF_SIGPENDING 2 /* signal pending */ #define TIF_NOTIFY_RESUME 3 /* callback before returning to user */ #define TIF_NOTIFY_SIGNAL 4 /* signal notifications exist */ #define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */ @@ -88,8 +89,9 @@ register unsigned long current_stack_pointer __asm__("$sp"); #define TIF_LBT_CTX_LIVE 20 /* LBT context must be preserved */ #define TIF_PATCH_PENDING 21 /* pending live patching update */ -#define _TIF_SIGPENDING (1< #include extern struct vdso_data *vdso_data; extern struct vdso_rng_data *vdso_rng_data; -/* - * Update the vDSO data page to keep in sync with kernel timekeeping. - */ static __always_inline struct vdso_data *__loongarch_get_k_vdso_data(void) { diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h index 70d89070bfeb46..5f354f5c684701 100644 --- a/arch/loongarch/include/uapi/asm/kvm.h +++ b/arch/loongarch/include/uapi/asm/kvm.h @@ -8,6 +8,8 @@ #include +#define __KVM_HAVE_IRQ_LINE + /* * KVM LoongArch specific structures and definitions. * @@ -132,4 +134,22 @@ struct kvm_iocsr_entry { #define KVM_IRQCHIP_NUM_PINS 64 #define KVM_MAX_CORES 256 +#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000001 + +#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000002 + +#define KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS 0x40000003 +#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU 0x0 +#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE 0x1 +#define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE 0x2 + +#define KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL 0x40000004 +#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU 0x0 +#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE 0x1 +#define KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED 0x3 + +#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 +#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000006 +#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 + #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index c9bfeda89e4076..9497968ee158ff 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -8,7 +8,7 @@ OBJECT_FILES_NON_STANDARD_head.o := y extra-y := vmlinux.lds obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \ - traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \ + traps.o irq.o idle.o process.o dma.o mem.o reset.o switch.o \ elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \ alternative.o unwind.o diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c index bee9f7a3108f0e..049c5c3e370cbb 100644 --- a/arch/loongarch/kernel/asm-offsets.c +++ b/arch/loongarch/kernel/asm-offsets.c @@ -14,6 +14,7 @@ #include #include #include +#include static void __used output_ptreg_defines(void) { @@ -321,3 +322,11 @@ static void __used output_kvm_defines(void) OFFSET(KVM_GPGD, kvm, arch.pgd); BLANK(); } + +static void __used output_vdso_defines(void) +{ + COMMENT("LoongArch vDSO offsets."); + + DEFINE(__VVAR_PAGES, VVAR_NR_PAGES); + BLANK(); +} diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c index 2bf86aeda874c7..de21e72759eebc 100644 --- a/arch/loongarch/kernel/efi.c +++ b/arch/loongarch/kernel/efi.c @@ -95,7 +95,7 @@ static void __init init_screen_info(void) memset(si, 0, sizeof(*si)); early_memunmap(si, sizeof(*si)); - memblock_reserve(screen_info.lfb_base, screen_info.lfb_size); + memblock_reserve(__screen_info_lfb_base(&screen_info), screen_info.lfb_size); } void __init efi_init(void) diff --git a/arch/loongarch/kernel/ftrace_dyn.c b/arch/loongarch/kernel/ftrace_dyn.c index bff058317062e3..18056229e22e4d 100644 --- a/arch/loongarch/kernel/ftrace_dyn.c +++ b/arch/loongarch/kernel/ftrace_dyn.c @@ -241,7 +241,7 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent) void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { - struct pt_regs *regs = &fregs->regs; + struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; unsigned long *parent = (unsigned long *)®s->regs[1]; prepare_ftrace_return(ip, (unsigned long *)parent); diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c index 3050329556d118..14d7d700bcb98f 100644 --- a/arch/loongarch/kernel/inst.c +++ b/arch/loongarch/kernel/inst.c @@ -332,7 +332,7 @@ u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm) return INSN_BREAK; } - emit_jirl(&insn, rj, rd, imm >> 2); + emit_jirl(&insn, rd, rj, imm >> 2); return insn.word; } diff --git a/arch/loongarch/kernel/io.c b/arch/loongarch/kernel/io.c deleted file mode 100644 index cb85bda5a6ada9..00000000000000 --- a/arch/loongarch/kernel/io.c +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2020-2022 Loongson Technology Corporation Limited - */ -#include -#include -#include - -/* - * Copy data from IO memory space to "real" memory space. - */ -void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) -{ - while (count && !IS_ALIGNED((unsigned long)from, 8)) { - *(u8 *)to = __raw_readb(from); - from++; - to++; - count--; - } - - while (count >= 8) { - *(u64 *)to = __raw_readq(from); - from += 8; - to += 8; - count -= 8; - } - - while (count) { - *(u8 *)to = __raw_readb(from); - from++; - to++; - count--; - } -} -EXPORT_SYMBOL(__memcpy_fromio); - -/* - * Copy data from "real" memory space to IO memory space. - */ -void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) -{ - while (count && !IS_ALIGNED((unsigned long)to, 8)) { - __raw_writeb(*(u8 *)from, to); - from++; - to++; - count--; - } - - while (count >= 8) { - __raw_writeq(*(u64 *)from, to); - from += 8; - to += 8; - count -= 8; - } - - while (count) { - __raw_writeb(*(u8 *)from, to); - from++; - to++; - count--; - } -} -EXPORT_SYMBOL(__memcpy_toio); - -/* - * "memset" on IO memory space. - */ -void __memset_io(volatile void __iomem *dst, int c, size_t count) -{ - u64 qc = (u8)c; - - qc |= qc << 8; - qc |= qc << 16; - qc |= qc << 32; - - while (count && !IS_ALIGNED((unsigned long)dst, 8)) { - __raw_writeb(c, dst); - dst++; - count--; - } - - while (count >= 8) { - __raw_writeq(qc, dst); - dst += 8; - count -= 8; - } - - while (count) { - __raw_writeb(c, dst); - dst++; - count--; - } -} -EXPORT_SYMBOL(__memset_io); diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c index d129039b368b09..80946cafaec1b2 100644 --- a/arch/loongarch/kernel/irq.c +++ b/arch/loongarch/kernel/irq.c @@ -92,9 +92,9 @@ int __init arch_probe_nr_irqs(void) int nr_io_pics = bitmap_weight(loongson_sysconf.cores_io_master, NR_CPUS); if (!cpu_has_avecint) - nr_irqs = (64 + NR_VECTORS * nr_io_pics); + irq_set_nr_irqs(64 + NR_VECTORS * nr_io_pics); else - nr_irqs = (64 + NR_VECTORS * (nr_cpu_ids + nr_io_pics)); + irq_set_nr_irqs(64 + NR_VECTORS * (nr_cpu_ids + nr_io_pics)); return NR_IRQS_LEGACY; } diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c index cbd3c09a93c14c..56934fe58170e0 100644 --- a/arch/loongarch/kernel/setup.c +++ b/arch/loongarch/kernel/setup.c @@ -291,7 +291,7 @@ static void __init fdt_setup(void) if (!fdt_pointer || fdt_check_header(fdt_pointer)) return; - early_init_dt_scan(fdt_pointer); + early_init_dt_scan(fdt_pointer, __pa(fdt_pointer)); early_init_fdt_reserve_self(); max_low_pfn = PFN_PHYS(memblock_end_of_DRAM()); diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index 5d59e9ce2772d8..fbf747447f13fd 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -82,7 +82,7 @@ void show_ipi_list(struct seq_file *p, int prec) for (i = 0; i < NR_IPI; i++) { seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i, prec >= 4 ? " " : ""); for_each_online_cpu(cpu) - seq_printf(p, "%10u ", per_cpu(irq_stat, cpu).ipi_irqs[i]); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, cpu).ipi_irqs[i], 10); seq_printf(p, " LoongArch %d %s\n", i + 1, ipi_types[i]); } } diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c index 46d7d40c87e38e..a07d7eff4dc5fb 100644 --- a/arch/loongarch/kernel/time.c +++ b/arch/loongarch/kernel/time.c @@ -127,7 +127,11 @@ void sync_counter(void) int constant_clockevent_init(void) { unsigned int cpu = smp_processor_id(); - unsigned long min_delta = 0x600; +#ifdef CONFIG_PREEMPT_RT + unsigned long min_delta = 100; +#else + unsigned long min_delta = 1000; +#endif unsigned long max_delta = (1UL << 48) - 1; struct clock_event_device *cd; static int irq = 0, timer_irq_installed = 0; diff --git a/arch/loongarch/kernel/vdso.c b/arch/loongarch/kernel/vdso.c index 2c0d852ca5366b..05e5fbac102a90 100644 --- a/arch/loongarch/kernel/vdso.c +++ b/arch/loongarch/kernel/vdso.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig index 248744b4d086d1..97a811077ac3af 100644 --- a/arch/loongarch/kvm/Kconfig +++ b/arch/loongarch/kvm/Kconfig @@ -21,13 +21,16 @@ config KVM tristate "Kernel-based Virtual Machine (KVM) support" depends on AS_HAS_LVZ_EXTENSION select HAVE_KVM_DIRTY_RING_ACQ_REL + select HAVE_KVM_IRQ_ROUTING + select HAVE_KVM_IRQCHIP + select HAVE_KVM_MSI + select HAVE_KVM_READONLY_MEM select HAVE_KVM_VCPU_ASYNC_IOCTL select KVM_COMMON select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_GENERIC_HARDWARE_ENABLING select KVM_GENERIC_MMU_NOTIFIER select KVM_MMIO - select HAVE_KVM_READONLY_MEM select KVM_XFER_TO_GUEST_WORK select SCHED_INFO help diff --git a/arch/loongarch/kvm/Makefile b/arch/loongarch/kvm/Makefile index b2f4cbe01ae804..3a01292f71cc2b 100644 --- a/arch/loongarch/kvm/Makefile +++ b/arch/loongarch/kvm/Makefile @@ -18,5 +18,9 @@ kvm-y += timer.o kvm-y += tlb.o kvm-y += vcpu.o kvm-y += vm.o +kvm-y += intc/ipi.o +kvm-y += intc/eiointc.o +kvm-y += intc/pch_pic.o +kvm-y += irqfd.o CFLAGS_exit.o += $(call cc-option,-Wno-override-init,) diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c index 90894f70ff4a50..a7893bd01e732a 100644 --- a/arch/loongarch/kvm/exit.c +++ b/arch/loongarch/kvm/exit.c @@ -156,8 +156,8 @@ static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst) int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) { - int ret; - unsigned long val; + int idx, ret; + unsigned long *val; u32 addr, rd, rj, opcode; /* @@ -167,9 +167,9 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) rj = inst.reg2_format.rj; opcode = inst.reg2_format.opcode; addr = vcpu->arch.gprs[rj]; - ret = EMULATE_DO_IOCSR; run->iocsr_io.phys_addr = addr; run->iocsr_io.is_write = 0; + val = &vcpu->arch.gprs[rd]; /* LoongArch is Little endian */ switch (opcode) { @@ -202,16 +202,33 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) run->iocsr_io.is_write = 1; break; default: - ret = EMULATE_FAIL; - break; + return EMULATE_FAIL; } - if (ret == EMULATE_DO_IOCSR) { - if (run->iocsr_io.is_write) { - val = vcpu->arch.gprs[rd]; - memcpy(run->iocsr_io.data, &val, run->iocsr_io.len); + if (run->iocsr_io.is_write) { + idx = srcu_read_lock(&vcpu->kvm->srcu); + ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val); + srcu_read_unlock(&vcpu->kvm->srcu, idx); + if (ret == 0) + ret = EMULATE_DONE; + else { + ret = EMULATE_DO_IOCSR; + /* Save data and let user space to write it */ + memcpy(run->iocsr_io.data, val, run->iocsr_io.len); } - vcpu->arch.io_gpr = rd; + trace_kvm_iocsr(KVM_TRACE_IOCSR_WRITE, run->iocsr_io.len, addr, val); + } else { + idx = srcu_read_lock(&vcpu->kvm->srcu); + ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val); + srcu_read_unlock(&vcpu->kvm->srcu, idx); + if (ret == 0) + ret = EMULATE_DONE; + else { + ret = EMULATE_DO_IOCSR; + /* Save register id for iocsr read completion */ + vcpu->arch.io_gpr = rd; + } + trace_kvm_iocsr(KVM_TRACE_IOCSR_READ, run->iocsr_io.len, addr, NULL); } return ret; @@ -349,7 +366,7 @@ static int kvm_handle_gspr(struct kvm_vcpu *vcpu) int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst) { - int ret; + int idx, ret; unsigned int op8, opcode, rd; struct kvm_run *run = vcpu->run; @@ -447,19 +464,35 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst) } if (ret == EMULATE_DO_MMIO) { + trace_kvm_mmio(KVM_TRACE_MMIO_READ, run->mmio.len, run->mmio.phys_addr, NULL); + + /* + * If mmio device such as PCH-PIC is emulated in KVM, + * it need not return to user space to handle the mmio + * exception. + */ + idx = srcu_read_lock(&vcpu->kvm->srcu); + ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, vcpu->arch.badv, + run->mmio.len, &vcpu->arch.gprs[rd]); + srcu_read_unlock(&vcpu->kvm->srcu, idx); + if (!ret) { + update_pc(&vcpu->arch); + vcpu->mmio_needed = 0; + return EMULATE_DONE; + } + /* Set for kvm_complete_mmio_read() use */ vcpu->arch.io_gpr = rd; run->mmio.is_write = 0; vcpu->mmio_is_write = 0; - trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, run->mmio.len, - run->mmio.phys_addr, NULL); - } else { - kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", - inst.word, vcpu->arch.pc, vcpu->arch.badv); - kvm_arch_vcpu_dump_regs(vcpu); - vcpu->mmio_needed = 0; + return EMULATE_DO_MMIO; } + kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", + inst.word, vcpu->arch.pc, vcpu->arch.badv); + kvm_arch_vcpu_dump_regs(vcpu); + vcpu->mmio_needed = 0; + return ret; } @@ -507,7 +540,7 @@ int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run) int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst) { - int ret; + int idx, ret; unsigned int rd, op8, opcode; unsigned long curr_pc, rd_val = 0; struct kvm_run *run = vcpu->run; @@ -600,19 +633,31 @@ int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst) } if (ret == EMULATE_DO_MMIO) { + trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, run->mmio.len, run->mmio.phys_addr, data); + + /* + * If mmio device such as PCH-PIC is emulated in KVM, + * it need not return to user space to handle the mmio + * exception. + */ + idx = srcu_read_lock(&vcpu->kvm->srcu); + ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, vcpu->arch.badv, run->mmio.len, data); + srcu_read_unlock(&vcpu->kvm->srcu, idx); + if (!ret) + return EMULATE_DONE; + run->mmio.is_write = 1; vcpu->mmio_needed = 1; vcpu->mmio_is_write = 1; - trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, run->mmio.len, - run->mmio.phys_addr, data); - } else { - vcpu->arch.pc = curr_pc; - kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", - inst.word, vcpu->arch.pc, vcpu->arch.badv); - kvm_arch_vcpu_dump_regs(vcpu); - /* Rollback PC if emulation was unsuccessful */ + return EMULATE_DO_MMIO; } + vcpu->arch.pc = curr_pc; + kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", + inst.word, vcpu->arch.pc, vcpu->arch.badv); + kvm_arch_vcpu_dump_regs(vcpu); + /* Rollback PC if emulation was unsuccessful */ + return ret; } diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c new file mode 100644 index 00000000000000..f39929d7bf8a24 --- /dev/null +++ b/arch/loongarch/kvm/intc/eiointc.c @@ -0,0 +1,1027 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */ + +#include +#include +#include + +static void eiointc_set_sw_coreisr(struct loongarch_eiointc *s) +{ + int ipnum, cpu, irq_index, irq_mask, irq; + + for (irq = 0; irq < EIOINTC_IRQS; irq++) { + ipnum = s->ipmap.reg_u8[irq / 32]; + if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) { + ipnum = count_trailing_zeros(ipnum); + ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0; + } + irq_index = irq / 32; + irq_mask = BIT(irq & 0x1f); + + cpu = s->coremap.reg_u8[irq]; + if (!!(s->coreisr.reg_u32[cpu][irq_index] & irq_mask)) + set_bit(irq, s->sw_coreisr[cpu][ipnum]); + else + clear_bit(irq, s->sw_coreisr[cpu][ipnum]); + } +} + +static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level) +{ + int ipnum, cpu, found, irq_index, irq_mask; + struct kvm_vcpu *vcpu; + struct kvm_interrupt vcpu_irq; + + ipnum = s->ipmap.reg_u8[irq / 32]; + if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) { + ipnum = count_trailing_zeros(ipnum); + ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0; + } + + cpu = s->sw_coremap[irq]; + vcpu = kvm_get_vcpu(s->kvm, cpu); + irq_index = irq / 32; + irq_mask = BIT(irq & 0x1f); + + if (level) { + /* if not enable return false */ + if (((s->enable.reg_u32[irq_index]) & irq_mask) == 0) + return; + s->coreisr.reg_u32[cpu][irq_index] |= irq_mask; + found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS); + set_bit(irq, s->sw_coreisr[cpu][ipnum]); + } else { + s->coreisr.reg_u32[cpu][irq_index] &= ~irq_mask; + clear_bit(irq, s->sw_coreisr[cpu][ipnum]); + found = find_first_bit(s->sw_coreisr[cpu][ipnum], EIOINTC_IRQS); + } + + if (found < EIOINTC_IRQS) + return; /* other irq is handling, needn't update parent irq */ + + vcpu_irq.irq = level ? (INT_HWI0 + ipnum) : -(INT_HWI0 + ipnum); + kvm_vcpu_ioctl_interrupt(vcpu, &vcpu_irq); +} + +static inline void eiointc_update_sw_coremap(struct loongarch_eiointc *s, + int irq, void *pvalue, u32 len, bool notify) +{ + int i, cpu; + u64 val = *(u64 *)pvalue; + + for (i = 0; i < len; i++) { + cpu = val & 0xff; + val = val >> 8; + + if (!(s->status & BIT(EIOINTC_ENABLE_CPU_ENCODE))) { + cpu = ffs(cpu) - 1; + cpu = (cpu >= 4) ? 0 : cpu; + } + + if (s->sw_coremap[irq + i] == cpu) + continue; + + if (notify && test_bit(irq + i, (unsigned long *)s->isr.reg_u8)) { + /* lower irq at old cpu and raise irq at new cpu */ + eiointc_update_irq(s, irq + i, 0); + s->sw_coremap[irq + i] = cpu; + eiointc_update_irq(s, irq + i, 1); + } else { + s->sw_coremap[irq + i] = cpu; + } + } +} + +void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level) +{ + unsigned long flags; + unsigned long *isr = (unsigned long *)s->isr.reg_u8; + + level ? set_bit(irq, isr) : clear_bit(irq, isr); + spin_lock_irqsave(&s->lock, flags); + eiointc_update_irq(s, irq, level); + spin_unlock_irqrestore(&s->lock, flags); +} + +static inline void eiointc_enable_irq(struct kvm_vcpu *vcpu, + struct loongarch_eiointc *s, int index, u8 mask, int level) +{ + u8 val; + int irq; + + val = mask & s->isr.reg_u8[index]; + irq = ffs(val); + while (irq != 0) { + /* + * enable bit change from 0 to 1, + * need to update irq by pending bits + */ + eiointc_update_irq(s, irq - 1 + index * 8, level); + val &= ~BIT(irq - 1); + irq = ffs(val); + } +} + +static int loongarch_eiointc_readb(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s, + gpa_t addr, int len, void *val) +{ + int index, ret = 0; + u8 data = 0; + gpa_t offset; + + offset = addr - EIOINTC_BASE; + switch (offset) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + index = offset - EIOINTC_NODETYPE_START; + data = s->nodetype.reg_u8[index]; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + index = offset - EIOINTC_IPMAP_START; + data = s->ipmap.reg_u8[index]; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + index = offset - EIOINTC_ENABLE_START; + data = s->enable.reg_u8[index]; + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + index = offset - EIOINTC_BOUNCE_START; + data = s->bounce.reg_u8[index]; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + index = offset - EIOINTC_COREISR_START; + data = s->coreisr.reg_u8[vcpu->vcpu_id][index]; + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + index = offset - EIOINTC_COREMAP_START; + data = s->coremap.reg_u8[index]; + break; + default: + ret = -EINVAL; + break; + } + *(u8 *)val = data; + + return ret; +} + +static int loongarch_eiointc_readw(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s, + gpa_t addr, int len, void *val) +{ + int index, ret = 0; + u16 data = 0; + gpa_t offset; + + offset = addr - EIOINTC_BASE; + switch (offset) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + index = (offset - EIOINTC_NODETYPE_START) >> 1; + data = s->nodetype.reg_u16[index]; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + index = (offset - EIOINTC_IPMAP_START) >> 1; + data = s->ipmap.reg_u16[index]; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + index = (offset - EIOINTC_ENABLE_START) >> 1; + data = s->enable.reg_u16[index]; + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + index = (offset - EIOINTC_BOUNCE_START) >> 1; + data = s->bounce.reg_u16[index]; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + index = (offset - EIOINTC_COREISR_START) >> 1; + data = s->coreisr.reg_u16[vcpu->vcpu_id][index]; + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + index = (offset - EIOINTC_COREMAP_START) >> 1; + data = s->coremap.reg_u16[index]; + break; + default: + ret = -EINVAL; + break; + } + *(u16 *)val = data; + + return ret; +} + +static int loongarch_eiointc_readl(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s, + gpa_t addr, int len, void *val) +{ + int index, ret = 0; + u32 data = 0; + gpa_t offset; + + offset = addr - EIOINTC_BASE; + switch (offset) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + index = (offset - EIOINTC_NODETYPE_START) >> 2; + data = s->nodetype.reg_u32[index]; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + index = (offset - EIOINTC_IPMAP_START) >> 2; + data = s->ipmap.reg_u32[index]; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + index = (offset - EIOINTC_ENABLE_START) >> 2; + data = s->enable.reg_u32[index]; + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + index = (offset - EIOINTC_BOUNCE_START) >> 2; + data = s->bounce.reg_u32[index]; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + index = (offset - EIOINTC_COREISR_START) >> 2; + data = s->coreisr.reg_u32[vcpu->vcpu_id][index]; + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + index = (offset - EIOINTC_COREMAP_START) >> 2; + data = s->coremap.reg_u32[index]; + break; + default: + ret = -EINVAL; + break; + } + *(u32 *)val = data; + + return ret; +} + +static int loongarch_eiointc_readq(struct kvm_vcpu *vcpu, struct loongarch_eiointc *s, + gpa_t addr, int len, void *val) +{ + int index, ret = 0; + u64 data = 0; + gpa_t offset; + + offset = addr - EIOINTC_BASE; + switch (offset) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + index = (offset - EIOINTC_NODETYPE_START) >> 3; + data = s->nodetype.reg_u64[index]; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + index = (offset - EIOINTC_IPMAP_START) >> 3; + data = s->ipmap.reg_u64; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + index = (offset - EIOINTC_ENABLE_START) >> 3; + data = s->enable.reg_u64[index]; + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + index = (offset - EIOINTC_BOUNCE_START) >> 3; + data = s->bounce.reg_u64[index]; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + index = (offset - EIOINTC_COREISR_START) >> 3; + data = s->coreisr.reg_u64[vcpu->vcpu_id][index]; + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + index = (offset - EIOINTC_COREMAP_START) >> 3; + data = s->coremap.reg_u64[index]; + break; + default: + ret = -EINVAL; + break; + } + *(u64 *)val = data; + + return ret; +} + +static int kvm_eiointc_read(struct kvm_vcpu *vcpu, + struct kvm_io_device *dev, + gpa_t addr, int len, void *val) +{ + int ret = -EINVAL; + unsigned long flags; + struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; + + if (!eiointc) { + kvm_err("%s: eiointc irqchip not valid!\n", __func__); + return -EINVAL; + } + + vcpu->kvm->stat.eiointc_read_exits++; + spin_lock_irqsave(&eiointc->lock, flags); + switch (len) { + case 1: + ret = loongarch_eiointc_readb(vcpu, eiointc, addr, len, val); + break; + case 2: + ret = loongarch_eiointc_readw(vcpu, eiointc, addr, len, val); + break; + case 4: + ret = loongarch_eiointc_readl(vcpu, eiointc, addr, len, val); + break; + case 8: + ret = loongarch_eiointc_readq(vcpu, eiointc, addr, len, val); + break; + default: + WARN_ONCE(1, "%s: Abnormal address access: addr 0x%llx, size %d\n", + __func__, addr, len); + } + spin_unlock_irqrestore(&eiointc->lock, flags); + + return ret; +} + +static int loongarch_eiointc_writeb(struct kvm_vcpu *vcpu, + struct loongarch_eiointc *s, + gpa_t addr, int len, const void *val) +{ + int index, irq, bits, ret = 0; + u8 cpu; + u8 data, old_data; + u8 coreisr, old_coreisr; + gpa_t offset; + + data = *(u8 *)val; + offset = addr - EIOINTC_BASE; + + switch (offset) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + index = (offset - EIOINTC_NODETYPE_START); + s->nodetype.reg_u8[index] = data; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + /* + * ipmap cannot be set at runtime, can be set only at the beginning + * of irqchip driver, need not update upper irq level + */ + index = (offset - EIOINTC_IPMAP_START); + s->ipmap.reg_u8[index] = data; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + index = (offset - EIOINTC_ENABLE_START); + old_data = s->enable.reg_u8[index]; + s->enable.reg_u8[index] = data; + /* + * 1: enable irq. + * update irq when isr is set. + */ + data = s->enable.reg_u8[index] & ~old_data & s->isr.reg_u8[index]; + eiointc_enable_irq(vcpu, s, index, data, 1); + /* + * 0: disable irq. + * update irq when isr is set. + */ + data = ~s->enable.reg_u8[index] & old_data & s->isr.reg_u8[index]; + eiointc_enable_irq(vcpu, s, index, data, 0); + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + /* do not emulate hw bounced irq routing */ + index = offset - EIOINTC_BOUNCE_START; + s->bounce.reg_u8[index] = data; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + index = (offset - EIOINTC_COREISR_START); + /* use attrs to get current cpu index */ + cpu = vcpu->vcpu_id; + coreisr = data; + old_coreisr = s->coreisr.reg_u8[cpu][index]; + /* write 1 to clear interrupt */ + s->coreisr.reg_u8[cpu][index] = old_coreisr & ~coreisr; + coreisr &= old_coreisr; + bits = sizeof(data) * 8; + irq = find_first_bit((void *)&coreisr, bits); + while (irq < bits) { + eiointc_update_irq(s, irq + index * bits, 0); + bitmap_clear((void *)&coreisr, irq, 1); + irq = find_first_bit((void *)&coreisr, bits); + } + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + irq = offset - EIOINTC_COREMAP_START; + index = irq; + s->coremap.reg_u8[index] = data; + eiointc_update_sw_coremap(s, irq, (void *)&data, sizeof(data), true); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int loongarch_eiointc_writew(struct kvm_vcpu *vcpu, + struct loongarch_eiointc *s, + gpa_t addr, int len, const void *val) +{ + int i, index, irq, bits, ret = 0; + u8 cpu; + u16 data, old_data; + u16 coreisr, old_coreisr; + gpa_t offset; + + data = *(u16 *)val; + offset = addr - EIOINTC_BASE; + + switch (offset) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + index = (offset - EIOINTC_NODETYPE_START) >> 1; + s->nodetype.reg_u16[index] = data; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + /* + * ipmap cannot be set at runtime, can be set only at the beginning + * of irqchip driver, need not update upper irq level + */ + index = (offset - EIOINTC_IPMAP_START) >> 1; + s->ipmap.reg_u16[index] = data; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + index = (offset - EIOINTC_ENABLE_START) >> 1; + old_data = s->enable.reg_u32[index]; + s->enable.reg_u16[index] = data; + /* + * 1: enable irq. + * update irq when isr is set. + */ + data = s->enable.reg_u16[index] & ~old_data & s->isr.reg_u16[index]; + index = index << 1; + for (i = 0; i < sizeof(data); i++) { + u8 mask = (data >> (i * 8)) & 0xff; + eiointc_enable_irq(vcpu, s, index + i, mask, 1); + } + /* + * 0: disable irq. + * update irq when isr is set. + */ + data = ~s->enable.reg_u16[index] & old_data & s->isr.reg_u16[index]; + for (i = 0; i < sizeof(data); i++) { + u8 mask = (data >> (i * 8)) & 0xff; + eiointc_enable_irq(vcpu, s, index, mask, 0); + } + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + /* do not emulate hw bounced irq routing */ + index = (offset - EIOINTC_BOUNCE_START) >> 1; + s->bounce.reg_u16[index] = data; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + index = (offset - EIOINTC_COREISR_START) >> 1; + /* use attrs to get current cpu index */ + cpu = vcpu->vcpu_id; + coreisr = data; + old_coreisr = s->coreisr.reg_u16[cpu][index]; + /* write 1 to clear interrupt */ + s->coreisr.reg_u16[cpu][index] = old_coreisr & ~coreisr; + coreisr &= old_coreisr; + bits = sizeof(data) * 8; + irq = find_first_bit((void *)&coreisr, bits); + while (irq < bits) { + eiointc_update_irq(s, irq + index * bits, 0); + bitmap_clear((void *)&coreisr, irq, 1); + irq = find_first_bit((void *)&coreisr, bits); + } + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + irq = offset - EIOINTC_COREMAP_START; + index = irq >> 1; + s->coremap.reg_u16[index] = data; + eiointc_update_sw_coremap(s, irq, (void *)&data, sizeof(data), true); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int loongarch_eiointc_writel(struct kvm_vcpu *vcpu, + struct loongarch_eiointc *s, + gpa_t addr, int len, const void *val) +{ + int i, index, irq, bits, ret = 0; + u8 cpu; + u32 data, old_data; + u32 coreisr, old_coreisr; + gpa_t offset; + + data = *(u32 *)val; + offset = addr - EIOINTC_BASE; + + switch (offset) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + index = (offset - EIOINTC_NODETYPE_START) >> 2; + s->nodetype.reg_u32[index] = data; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + /* + * ipmap cannot be set at runtime, can be set only at the beginning + * of irqchip driver, need not update upper irq level + */ + index = (offset - EIOINTC_IPMAP_START) >> 2; + s->ipmap.reg_u32[index] = data; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + index = (offset - EIOINTC_ENABLE_START) >> 2; + old_data = s->enable.reg_u32[index]; + s->enable.reg_u32[index] = data; + /* + * 1: enable irq. + * update irq when isr is set. + */ + data = s->enable.reg_u32[index] & ~old_data & s->isr.reg_u32[index]; + index = index << 2; + for (i = 0; i < sizeof(data); i++) { + u8 mask = (data >> (i * 8)) & 0xff; + eiointc_enable_irq(vcpu, s, index + i, mask, 1); + } + /* + * 0: disable irq. + * update irq when isr is set. + */ + data = ~s->enable.reg_u32[index] & old_data & s->isr.reg_u32[index]; + for (i = 0; i < sizeof(data); i++) { + u8 mask = (data >> (i * 8)) & 0xff; + eiointc_enable_irq(vcpu, s, index, mask, 0); + } + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + /* do not emulate hw bounced irq routing */ + index = (offset - EIOINTC_BOUNCE_START) >> 2; + s->bounce.reg_u32[index] = data; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + index = (offset - EIOINTC_COREISR_START) >> 2; + /* use attrs to get current cpu index */ + cpu = vcpu->vcpu_id; + coreisr = data; + old_coreisr = s->coreisr.reg_u32[cpu][index]; + /* write 1 to clear interrupt */ + s->coreisr.reg_u32[cpu][index] = old_coreisr & ~coreisr; + coreisr &= old_coreisr; + bits = sizeof(data) * 8; + irq = find_first_bit((void *)&coreisr, bits); + while (irq < bits) { + eiointc_update_irq(s, irq + index * bits, 0); + bitmap_clear((void *)&coreisr, irq, 1); + irq = find_first_bit((void *)&coreisr, bits); + } + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + irq = offset - EIOINTC_COREMAP_START; + index = irq >> 2; + s->coremap.reg_u32[index] = data; + eiointc_update_sw_coremap(s, irq, (void *)&data, sizeof(data), true); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu, + struct loongarch_eiointc *s, + gpa_t addr, int len, const void *val) +{ + int i, index, irq, bits, ret = 0; + u8 cpu; + u64 data, old_data; + u64 coreisr, old_coreisr; + gpa_t offset; + + data = *(u64 *)val; + offset = addr - EIOINTC_BASE; + + switch (offset) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + index = (offset - EIOINTC_NODETYPE_START) >> 3; + s->nodetype.reg_u64[index] = data; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + /* + * ipmap cannot be set at runtime, can be set only at the beginning + * of irqchip driver, need not update upper irq level + */ + index = (offset - EIOINTC_IPMAP_START) >> 3; + s->ipmap.reg_u64 = data; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + index = (offset - EIOINTC_ENABLE_START) >> 3; + old_data = s->enable.reg_u64[index]; + s->enable.reg_u64[index] = data; + /* + * 1: enable irq. + * update irq when isr is set. + */ + data = s->enable.reg_u64[index] & ~old_data & s->isr.reg_u64[index]; + index = index << 3; + for (i = 0; i < sizeof(data); i++) { + u8 mask = (data >> (i * 8)) & 0xff; + eiointc_enable_irq(vcpu, s, index + i, mask, 1); + } + /* + * 0: disable irq. + * update irq when isr is set. + */ + data = ~s->enable.reg_u64[index] & old_data & s->isr.reg_u64[index]; + for (i = 0; i < sizeof(data); i++) { + u8 mask = (data >> (i * 8)) & 0xff; + eiointc_enable_irq(vcpu, s, index, mask, 0); + } + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + /* do not emulate hw bounced irq routing */ + index = (offset - EIOINTC_BOUNCE_START) >> 3; + s->bounce.reg_u64[index] = data; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + index = (offset - EIOINTC_COREISR_START) >> 3; + /* use attrs to get current cpu index */ + cpu = vcpu->vcpu_id; + coreisr = data; + old_coreisr = s->coreisr.reg_u64[cpu][index]; + /* write 1 to clear interrupt */ + s->coreisr.reg_u64[cpu][index] = old_coreisr & ~coreisr; + coreisr &= old_coreisr; + bits = sizeof(data) * 8; + irq = find_first_bit((void *)&coreisr, bits); + while (irq < bits) { + eiointc_update_irq(s, irq + index * bits, 0); + bitmap_clear((void *)&coreisr, irq, 1); + irq = find_first_bit((void *)&coreisr, bits); + } + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + irq = offset - EIOINTC_COREMAP_START; + index = irq >> 3; + s->coremap.reg_u64[index] = data; + eiointc_update_sw_coremap(s, irq, (void *)&data, sizeof(data), true); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int kvm_eiointc_write(struct kvm_vcpu *vcpu, + struct kvm_io_device *dev, + gpa_t addr, int len, const void *val) +{ + int ret = -EINVAL; + unsigned long flags; + struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; + + if (!eiointc) { + kvm_err("%s: eiointc irqchip not valid!\n", __func__); + return -EINVAL; + } + + vcpu->kvm->stat.eiointc_write_exits++; + spin_lock_irqsave(&eiointc->lock, flags); + switch (len) { + case 1: + ret = loongarch_eiointc_writeb(vcpu, eiointc, addr, len, val); + break; + case 2: + ret = loongarch_eiointc_writew(vcpu, eiointc, addr, len, val); + break; + case 4: + ret = loongarch_eiointc_writel(vcpu, eiointc, addr, len, val); + break; + case 8: + ret = loongarch_eiointc_writeq(vcpu, eiointc, addr, len, val); + break; + default: + WARN_ONCE(1, "%s: Abnormal address access: addr 0x%llx, size %d\n", + __func__, addr, len); + } + spin_unlock_irqrestore(&eiointc->lock, flags); + + return ret; +} + +static const struct kvm_io_device_ops kvm_eiointc_ops = { + .read = kvm_eiointc_read, + .write = kvm_eiointc_write, +}; + +static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu, + struct kvm_io_device *dev, + gpa_t addr, int len, void *val) +{ + unsigned long flags; + u32 *data = val; + struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; + + if (!eiointc) { + kvm_err("%s: eiointc irqchip not valid!\n", __func__); + return -EINVAL; + } + + addr -= EIOINTC_VIRT_BASE; + spin_lock_irqsave(&eiointc->lock, flags); + switch (addr) { + case EIOINTC_VIRT_FEATURES: + *data = eiointc->features; + break; + case EIOINTC_VIRT_CONFIG: + *data = eiointc->status; + break; + default: + break; + } + spin_unlock_irqrestore(&eiointc->lock, flags); + + return 0; +} + +static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu, + struct kvm_io_device *dev, + gpa_t addr, int len, const void *val) +{ + int ret = 0; + unsigned long flags; + u32 value = *(u32 *)val; + struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; + + if (!eiointc) { + kvm_err("%s: eiointc irqchip not valid!\n", __func__); + return -EINVAL; + } + + addr -= EIOINTC_VIRT_BASE; + spin_lock_irqsave(&eiointc->lock, flags); + switch (addr) { + case EIOINTC_VIRT_FEATURES: + ret = -EPERM; + break; + case EIOINTC_VIRT_CONFIG: + /* + * eiointc features can only be set at disabled status + */ + if ((eiointc->status & BIT(EIOINTC_ENABLE)) && value) { + ret = -EPERM; + break; + } + eiointc->status = value & eiointc->features; + break; + default: + break; + } + spin_unlock_irqrestore(&eiointc->lock, flags); + + return ret; +} + +static const struct kvm_io_device_ops kvm_eiointc_virt_ops = { + .read = kvm_eiointc_virt_read, + .write = kvm_eiointc_virt_write, +}; + +static int kvm_eiointc_ctrl_access(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + int ret = 0; + unsigned long flags; + unsigned long type = (unsigned long)attr->attr; + u32 i, start_irq; + void __user *data; + struct loongarch_eiointc *s = dev->kvm->arch.eiointc; + + data = (void __user *)attr->addr; + spin_lock_irqsave(&s->lock, flags); + switch (type) { + case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU: + if (copy_from_user(&s->num_cpu, data, 4)) + ret = -EFAULT; + break; + case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE: + if (copy_from_user(&s->features, data, 4)) + ret = -EFAULT; + if (!(s->features & BIT(EIOINTC_HAS_VIRT_EXTENSION))) + s->status |= BIT(EIOINTC_ENABLE); + break; + case KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED: + eiointc_set_sw_coreisr(s); + for (i = 0; i < (EIOINTC_IRQS / 4); i++) { + start_irq = i * 4; + eiointc_update_sw_coremap(s, start_irq, + (void *)&s->coremap.reg_u32[i], sizeof(u32), false); + } + break; + default: + break; + } + spin_unlock_irqrestore(&s->lock, flags); + + return ret; +} + +static int kvm_eiointc_regs_access(struct kvm_device *dev, + struct kvm_device_attr *attr, + bool is_write) +{ + int addr, cpuid, offset, ret = 0; + unsigned long flags; + void *p = NULL; + void __user *data; + struct loongarch_eiointc *s; + + s = dev->kvm->arch.eiointc; + addr = attr->attr; + cpuid = addr >> 16; + addr &= 0xffff; + data = (void __user *)attr->addr; + switch (addr) { + case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: + offset = (addr - EIOINTC_NODETYPE_START) / 4; + p = &s->nodetype.reg_u32[offset]; + break; + case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: + offset = (addr - EIOINTC_IPMAP_START) / 4; + p = &s->ipmap.reg_u32[offset]; + break; + case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END: + offset = (addr - EIOINTC_ENABLE_START) / 4; + p = &s->enable.reg_u32[offset]; + break; + case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: + offset = (addr - EIOINTC_BOUNCE_START) / 4; + p = &s->bounce.reg_u32[offset]; + break; + case EIOINTC_ISR_START ... EIOINTC_ISR_END: + offset = (addr - EIOINTC_ISR_START) / 4; + p = &s->isr.reg_u32[offset]; + break; + case EIOINTC_COREISR_START ... EIOINTC_COREISR_END: + offset = (addr - EIOINTC_COREISR_START) / 4; + p = &s->coreisr.reg_u32[cpuid][offset]; + break; + case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END: + offset = (addr - EIOINTC_COREMAP_START) / 4; + p = &s->coremap.reg_u32[offset]; + break; + default: + kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr); + return -EINVAL; + } + + spin_lock_irqsave(&s->lock, flags); + if (is_write) { + if (copy_from_user(p, data, 4)) + ret = -EFAULT; + } else { + if (copy_to_user(data, p, 4)) + ret = -EFAULT; + } + spin_unlock_irqrestore(&s->lock, flags); + + return ret; +} + +static int kvm_eiointc_sw_status_access(struct kvm_device *dev, + struct kvm_device_attr *attr, + bool is_write) +{ + int addr, ret = 0; + unsigned long flags; + void *p = NULL; + void __user *data; + struct loongarch_eiointc *s; + + s = dev->kvm->arch.eiointc; + addr = attr->attr; + addr &= 0xffff; + + data = (void __user *)attr->addr; + switch (addr) { + case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU: + p = &s->num_cpu; + break; + case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE: + p = &s->features; + break; + case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE: + p = &s->status; + break; + default: + kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr); + return -EINVAL; + } + spin_lock_irqsave(&s->lock, flags); + if (is_write) { + if (copy_from_user(p, data, 4)) + ret = -EFAULT; + } else { + if (copy_to_user(data, p, 4)) + ret = -EFAULT; + } + spin_unlock_irqrestore(&s->lock, flags); + + return ret; +} + +static int kvm_eiointc_get_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + switch (attr->group) { + case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS: + return kvm_eiointc_regs_access(dev, attr, false); + case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS: + return kvm_eiointc_sw_status_access(dev, attr, false); + default: + return -EINVAL; + } +} + +static int kvm_eiointc_set_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + switch (attr->group) { + case KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL: + return kvm_eiointc_ctrl_access(dev, attr); + case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS: + return kvm_eiointc_regs_access(dev, attr, true); + case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS: + return kvm_eiointc_sw_status_access(dev, attr, true); + default: + return -EINVAL; + } +} + +static int kvm_eiointc_create(struct kvm_device *dev, u32 type) +{ + int ret; + struct loongarch_eiointc *s; + struct kvm_io_device *device, *device1; + struct kvm *kvm = dev->kvm; + + /* eiointc has been created */ + if (kvm->arch.eiointc) + return -EINVAL; + + s = kzalloc(sizeof(struct loongarch_eiointc), GFP_KERNEL); + if (!s) + return -ENOMEM; + + spin_lock_init(&s->lock); + s->kvm = kvm; + + /* + * Initialize IOCSR device + */ + device = &s->device; + kvm_iodevice_init(device, &kvm_eiointc_ops); + mutex_lock(&kvm->slots_lock); + ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, + EIOINTC_BASE, EIOINTC_SIZE, device); + mutex_unlock(&kvm->slots_lock); + if (ret < 0) { + kfree(s); + return ret; + } + + device1 = &s->device_vext; + kvm_iodevice_init(device1, &kvm_eiointc_virt_ops); + ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, + EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, device1); + if (ret < 0) { + kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device); + kfree(s); + return ret; + } + kvm->arch.eiointc = s; + + return 0; +} + +static void kvm_eiointc_destroy(struct kvm_device *dev) +{ + struct kvm *kvm; + struct loongarch_eiointc *eiointc; + + if (!dev || !dev->kvm || !dev->kvm->arch.eiointc) + return; + + kvm = dev->kvm; + eiointc = kvm->arch.eiointc; + kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device); + kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext); + kfree(eiointc); +} + +static struct kvm_device_ops kvm_eiointc_dev_ops = { + .name = "kvm-loongarch-eiointc", + .create = kvm_eiointc_create, + .destroy = kvm_eiointc_destroy, + .set_attr = kvm_eiointc_set_attr, + .get_attr = kvm_eiointc_get_attr, +}; + +int kvm_loongarch_register_eiointc_device(void) +{ + return kvm_register_device_ops(&kvm_eiointc_dev_ops, KVM_DEV_TYPE_LOONGARCH_EIOINTC); +} diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c new file mode 100644 index 00000000000000..93f4acd445236e --- /dev/null +++ b/arch/loongarch/kvm/intc/ipi.c @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */ + +#include +#include +#include + +static void ipi_send(struct kvm *kvm, uint64_t data) +{ + int cpu, action; + uint32_t status; + struct kvm_vcpu *vcpu; + struct kvm_interrupt irq; + + cpu = ((data & 0xffffffff) >> 16) & 0x3ff; + vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); + if (unlikely(vcpu == NULL)) { + kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + return; + } + + action = BIT(data & 0x1f); + spin_lock(&vcpu->arch.ipi_state.lock); + status = vcpu->arch.ipi_state.status; + vcpu->arch.ipi_state.status |= action; + spin_unlock(&vcpu->arch.ipi_state.lock); + if (status == 0) { + irq.irq = LARCH_INT_IPI; + kvm_vcpu_ioctl_interrupt(vcpu, &irq); + } +} + +static void ipi_clear(struct kvm_vcpu *vcpu, uint64_t data) +{ + uint32_t status; + struct kvm_interrupt irq; + + spin_lock(&vcpu->arch.ipi_state.lock); + vcpu->arch.ipi_state.status &= ~data; + status = vcpu->arch.ipi_state.status; + spin_unlock(&vcpu->arch.ipi_state.lock); + if (status == 0) { + irq.irq = -LARCH_INT_IPI; + kvm_vcpu_ioctl_interrupt(vcpu, &irq); + } +} + +static uint64_t read_mailbox(struct kvm_vcpu *vcpu, int offset, int len) +{ + uint64_t data = 0; + + spin_lock(&vcpu->arch.ipi_state.lock); + data = *(ulong *)((void *)vcpu->arch.ipi_state.buf + (offset - 0x20)); + spin_unlock(&vcpu->arch.ipi_state.lock); + + switch (len) { + case 1: + return data & 0xff; + case 2: + return data & 0xffff; + case 4: + return data & 0xffffffff; + case 8: + return data; + default: + kvm_err("%s: unknown data len: %d\n", __func__, len); + return 0; + } +} + +static void write_mailbox(struct kvm_vcpu *vcpu, int offset, uint64_t data, int len) +{ + void *pbuf; + + spin_lock(&vcpu->arch.ipi_state.lock); + pbuf = (void *)vcpu->arch.ipi_state.buf + (offset - 0x20); + + switch (len) { + case 1: + *(unsigned char *)pbuf = (unsigned char)data; + break; + case 2: + *(unsigned short *)pbuf = (unsigned short)data; + break; + case 4: + *(unsigned int *)pbuf = (unsigned int)data; + break; + case 8: + *(unsigned long *)pbuf = (unsigned long)data; + break; + default: + kvm_err("%s: unknown data len: %d\n", __func__, len); + } + spin_unlock(&vcpu->arch.ipi_state.lock); +} + +static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) +{ + int i, idx, ret; + uint32_t val = 0, mask = 0; + + /* + * Bit 27-30 is mask for byte writing. + * If the mask is 0, we need not to do anything. + */ + if ((data >> 27) & 0xf) { + /* Read the old val */ + idx = srcu_read_lock(&vcpu->kvm->srcu); + ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val); + srcu_read_unlock(&vcpu->kvm->srcu, idx); + if (unlikely(ret)) { + kvm_err("%s: : read date from addr %llx failed\n", __func__, addr); + return ret; + } + /* Construct the mask by scanning the bit 27-30 */ + for (i = 0; i < 4; i++) { + if (data & (BIT(27 + i))) + mask |= (0xff << (i * 8)); + } + /* Save the old part of val */ + val &= mask; + } + val |= ((uint32_t)(data >> 32) & ~mask); + idx = srcu_read_lock(&vcpu->kvm->srcu); + ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val); + srcu_read_unlock(&vcpu->kvm->srcu, idx); + if (unlikely(ret)) + kvm_err("%s: : write date to addr %llx failed\n", __func__, addr); + + return ret; +} + +static int mail_send(struct kvm *kvm, uint64_t data) +{ + int cpu, mailbox, offset; + struct kvm_vcpu *vcpu; + + cpu = ((data & 0xffffffff) >> 16) & 0x3ff; + vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); + if (unlikely(vcpu == NULL)) { + kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + return -EINVAL; + } + mailbox = ((data & 0xffffffff) >> 2) & 0x7; + offset = IOCSR_IPI_BASE + IOCSR_IPI_BUF_20 + mailbox * 4; + + return send_ipi_data(vcpu, offset, data); +} + +static int any_send(struct kvm *kvm, uint64_t data) +{ + int cpu, offset; + struct kvm_vcpu *vcpu; + + cpu = ((data & 0xffffffff) >> 16) & 0x3ff; + vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); + if (unlikely(vcpu == NULL)) { + kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + return -EINVAL; + } + offset = data & 0xffff; + + return send_ipi_data(vcpu, offset, data); +} + +static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *val) +{ + int ret = 0; + uint32_t offset; + uint64_t res = 0; + + offset = (uint32_t)(addr & 0x1ff); + WARN_ON_ONCE(offset & (len - 1)); + + switch (offset) { + case IOCSR_IPI_STATUS: + spin_lock(&vcpu->arch.ipi_state.lock); + res = vcpu->arch.ipi_state.status; + spin_unlock(&vcpu->arch.ipi_state.lock); + break; + case IOCSR_IPI_EN: + spin_lock(&vcpu->arch.ipi_state.lock); + res = vcpu->arch.ipi_state.en; + spin_unlock(&vcpu->arch.ipi_state.lock); + break; + case IOCSR_IPI_SET: + res = 0; + break; + case IOCSR_IPI_CLEAR: + res = 0; + break; + case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7: + if (offset + len > IOCSR_IPI_BUF_38 + 8) { + kvm_err("%s: invalid offset or len: offset = %d, len = %d\n", + __func__, offset, len); + ret = -EINVAL; + break; + } + res = read_mailbox(vcpu, offset, len); + break; + default: + kvm_err("%s: unknown addr: %llx\n", __func__, addr); + ret = -EINVAL; + break; + } + *(uint64_t *)val = res; + + return ret; +} + +static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, const void *val) +{ + int ret = 0; + uint64_t data; + uint32_t offset; + + data = *(uint64_t *)val; + + offset = (uint32_t)(addr & 0x1ff); + WARN_ON_ONCE(offset & (len - 1)); + + switch (offset) { + case IOCSR_IPI_STATUS: + ret = -EINVAL; + break; + case IOCSR_IPI_EN: + spin_lock(&vcpu->arch.ipi_state.lock); + vcpu->arch.ipi_state.en = data; + spin_unlock(&vcpu->arch.ipi_state.lock); + break; + case IOCSR_IPI_SET: + ret = -EINVAL; + break; + case IOCSR_IPI_CLEAR: + /* Just clear the status of the current vcpu */ + ipi_clear(vcpu, data); + break; + case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7: + if (offset + len > IOCSR_IPI_BUF_38 + 8) { + kvm_err("%s: invalid offset or len: offset = %d, len = %d\n", + __func__, offset, len); + ret = -EINVAL; + break; + } + write_mailbox(vcpu, offset, data, len); + break; + case IOCSR_IPI_SEND: + ipi_send(vcpu->kvm, data); + break; + case IOCSR_MAIL_SEND: + ret = mail_send(vcpu->kvm, *(uint64_t *)val); + break; + case IOCSR_ANY_SEND: + ret = any_send(vcpu->kvm, *(uint64_t *)val); + break; + default: + kvm_err("%s: unknown addr: %llx\n", __func__, addr); + ret = -EINVAL; + break; + } + + return ret; +} + +static int kvm_ipi_read(struct kvm_vcpu *vcpu, + struct kvm_io_device *dev, + gpa_t addr, int len, void *val) +{ + int ret; + struct loongarch_ipi *ipi; + + ipi = vcpu->kvm->arch.ipi; + if (!ipi) { + kvm_err("%s: ipi irqchip not valid!\n", __func__); + return -EINVAL; + } + ipi->kvm->stat.ipi_read_exits++; + ret = loongarch_ipi_readl(vcpu, addr, len, val); + + return ret; +} + +static int kvm_ipi_write(struct kvm_vcpu *vcpu, + struct kvm_io_device *dev, + gpa_t addr, int len, const void *val) +{ + int ret; + struct loongarch_ipi *ipi; + + ipi = vcpu->kvm->arch.ipi; + if (!ipi) { + kvm_err("%s: ipi irqchip not valid!\n", __func__); + return -EINVAL; + } + ipi->kvm->stat.ipi_write_exits++; + ret = loongarch_ipi_writel(vcpu, addr, len, val); + + return ret; +} + +static const struct kvm_io_device_ops kvm_ipi_ops = { + .read = kvm_ipi_read, + .write = kvm_ipi_write, +}; + +static int kvm_ipi_regs_access(struct kvm_device *dev, + struct kvm_device_attr *attr, + bool is_write) +{ + int len = 4; + int cpu, addr; + uint64_t val; + void *p = NULL; + struct kvm_vcpu *vcpu; + + cpu = (attr->attr >> 16) & 0x3ff; + addr = attr->attr & 0xff; + + vcpu = kvm_get_vcpu(dev->kvm, cpu); + if (unlikely(vcpu == NULL)) { + kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + return -EINVAL; + } + + switch (addr) { + case IOCSR_IPI_STATUS: + p = &vcpu->arch.ipi_state.status; + break; + case IOCSR_IPI_EN: + p = &vcpu->arch.ipi_state.en; + break; + case IOCSR_IPI_SET: + p = &vcpu->arch.ipi_state.set; + break; + case IOCSR_IPI_CLEAR: + p = &vcpu->arch.ipi_state.clear; + break; + case IOCSR_IPI_BUF_20: + p = &vcpu->arch.ipi_state.buf[0]; + len = 8; + break; + case IOCSR_IPI_BUF_28: + p = &vcpu->arch.ipi_state.buf[1]; + len = 8; + break; + case IOCSR_IPI_BUF_30: + p = &vcpu->arch.ipi_state.buf[2]; + len = 8; + break; + case IOCSR_IPI_BUF_38: + p = &vcpu->arch.ipi_state.buf[3]; + len = 8; + break; + default: + kvm_err("%s: unknown ipi register, addr = %d\n", __func__, addr); + return -EINVAL; + } + + if (is_write) { + if (len == 4) { + if (get_user(val, (uint32_t __user *)attr->addr)) + return -EFAULT; + *(uint32_t *)p = (uint32_t)val; + } else if (len == 8) { + if (get_user(val, (uint64_t __user *)attr->addr)) + return -EFAULT; + *(uint64_t *)p = val; + } + } else { + if (len == 4) { + val = *(uint32_t *)p; + return put_user(val, (uint32_t __user *)attr->addr); + } else if (len == 8) { + val = *(uint64_t *)p; + return put_user(val, (uint64_t __user *)attr->addr); + } + } + + return 0; +} + +static int kvm_ipi_get_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + switch (attr->group) { + case KVM_DEV_LOONGARCH_IPI_GRP_REGS: + return kvm_ipi_regs_access(dev, attr, false); + default: + kvm_err("%s: unknown group (%d)\n", __func__, attr->group); + return -EINVAL; + } +} + +static int kvm_ipi_set_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + switch (attr->group) { + case KVM_DEV_LOONGARCH_IPI_GRP_REGS: + return kvm_ipi_regs_access(dev, attr, true); + default: + kvm_err("%s: unknown group (%d)\n", __func__, attr->group); + return -EINVAL; + } +} + +static int kvm_ipi_create(struct kvm_device *dev, u32 type) +{ + int ret; + struct kvm *kvm; + struct kvm_io_device *device; + struct loongarch_ipi *s; + + if (!dev) { + kvm_err("%s: kvm_device ptr is invalid!\n", __func__); + return -EINVAL; + } + + kvm = dev->kvm; + if (kvm->arch.ipi) { + kvm_err("%s: LoongArch IPI has already been created!\n", __func__); + return -EINVAL; + } + + s = kzalloc(sizeof(struct loongarch_ipi), GFP_KERNEL); + if (!s) + return -ENOMEM; + + spin_lock_init(&s->lock); + s->kvm = kvm; + + /* + * Initialize IOCSR device + */ + device = &s->device; + kvm_iodevice_init(device, &kvm_ipi_ops); + mutex_lock(&kvm->slots_lock); + ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, IOCSR_IPI_BASE, IOCSR_IPI_SIZE, device); + mutex_unlock(&kvm->slots_lock); + if (ret < 0) { + kvm_err("%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret); + goto err; + } + + kvm->arch.ipi = s; + return 0; + +err: + kfree(s); + return -EFAULT; +} + +static void kvm_ipi_destroy(struct kvm_device *dev) +{ + struct kvm *kvm; + struct loongarch_ipi *ipi; + + if (!dev || !dev->kvm || !dev->kvm->arch.ipi) + return; + + kvm = dev->kvm; + ipi = kvm->arch.ipi; + kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device); + kfree(ipi); +} + +static struct kvm_device_ops kvm_ipi_dev_ops = { + .name = "kvm-loongarch-ipi", + .create = kvm_ipi_create, + .destroy = kvm_ipi_destroy, + .set_attr = kvm_ipi_set_attr, + .get_attr = kvm_ipi_get_attr, +}; + +int kvm_loongarch_register_ipi_device(void) +{ + return kvm_register_device_ops(&kvm_ipi_dev_ops, KVM_DEV_TYPE_LOONGARCH_IPI); +} diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c new file mode 100644 index 00000000000000..08fce845f66803 --- /dev/null +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -0,0 +1,519 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */ + +#include +#include +#include +#include + +/* update the isr according to irq level and route irq to eiointc */ +static void pch_pic_update_irq(struct loongarch_pch_pic *s, int irq, int level) +{ + u64 mask = BIT(irq); + + /* + * set isr and route irq to eiointc and + * the route table is in htmsi_vector[] + */ + if (level) { + if (mask & s->irr & ~s->mask) { + s->isr |= mask; + irq = s->htmsi_vector[irq]; + eiointc_set_irq(s->kvm->arch.eiointc, irq, level); + } + } else { + if (mask & s->isr & ~s->irr) { + s->isr &= ~mask; + irq = s->htmsi_vector[irq]; + eiointc_set_irq(s->kvm->arch.eiointc, irq, level); + } + } +} + +/* update batch irqs, the irq_mask is a bitmap of irqs */ +static void pch_pic_update_batch_irqs(struct loongarch_pch_pic *s, u64 irq_mask, int level) +{ + int irq, bits; + + /* find each irq by irqs bitmap and update each irq */ + bits = sizeof(irq_mask) * 8; + irq = find_first_bit((void *)&irq_mask, bits); + while (irq < bits) { + pch_pic_update_irq(s, irq, level); + bitmap_clear((void *)&irq_mask, irq, 1); + irq = find_first_bit((void *)&irq_mask, bits); + } +} + +/* called when a irq is triggered in pch pic */ +void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level) +{ + u64 mask = BIT(irq); + + spin_lock(&s->lock); + if (level) + s->irr |= mask; /* set irr */ + else { + /* + * In edge triggered mode, 0 does not mean to clear irq + * The irr register variable is cleared when cpu writes to the + * PCH_PIC_CLEAR_START address area + */ + if (s->edge & mask) { + spin_unlock(&s->lock); + return; + } + s->irr &= ~mask; + } + pch_pic_update_irq(s, irq, level); + spin_unlock(&s->lock); +} + +/* msi irq handler */ +void pch_msi_set_irq(struct kvm *kvm, int irq, int level) +{ + eiointc_set_irq(kvm->arch.eiointc, irq, level); +} + +/* + * pch pic register is 64-bit, but it is accessed by 32-bit, + * so we use high to get whether low or high 32 bits we want + * to read. + */ +static u32 pch_pic_read_reg(u64 *s, int high) +{ + u64 val = *s; + + /* read the high 32 bits when high is 1 */ + return high ? (u32)(val >> 32) : (u32)val; +} + +/* + * pch pic register is 64-bit, but it is accessed by 32-bit, + * so we use high to get whether low or high 32 bits we want + * to write. + */ +static u32 pch_pic_write_reg(u64 *s, int high, u32 v) +{ + u64 val = *s, data = v; + + if (high) { + /* + * Clear val high 32 bits + * Write the high 32 bits when the high is 1 + */ + *s = (val << 32 >> 32) | (data << 32); + val >>= 32; + } else + /* + * Clear val low 32 bits + * Write the low 32 bits when the high is 0 + */ + *s = (val >> 32 << 32) | v; + + return (u32)val; +} + +static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val) +{ + int offset, index, ret = 0; + u32 data = 0; + u64 int_id = 0; + + offset = addr - s->pch_pic_base; + + spin_lock(&s->lock); + switch (offset) { + case PCH_PIC_INT_ID_START ... PCH_PIC_INT_ID_END: + /* int id version */ + int_id |= (u64)PCH_PIC_INT_ID_VER << 32; + /* irq number */ + int_id |= (u64)31 << (32 + 16); + /* int id value */ + int_id |= PCH_PIC_INT_ID_VAL; + *(u64 *)val = int_id; + break; + case PCH_PIC_MASK_START ... PCH_PIC_MASK_END: + offset -= PCH_PIC_MASK_START; + index = offset >> 2; + /* read mask reg */ + data = pch_pic_read_reg(&s->mask, index); + *(u32 *)val = data; + break; + case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END: + offset -= PCH_PIC_HTMSI_EN_START; + index = offset >> 2; + /* read htmsi enable reg */ + data = pch_pic_read_reg(&s->htmsi_en, index); + *(u32 *)val = data; + break; + case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END: + offset -= PCH_PIC_EDGE_START; + index = offset >> 2; + /* read edge enable reg */ + data = pch_pic_read_reg(&s->edge, index); + *(u32 *)val = data; + break; + case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END: + case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END: + /* we only use default mode: fixed interrupt distribution mode */ + *(u32 *)val = 0; + break; + case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END: + /* only route to int0: eiointc */ + *(u8 *)val = 1; + break; + case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END: + offset -= PCH_PIC_HTMSI_VEC_START; + /* read htmsi vector */ + data = s->htmsi_vector[offset]; + *(u8 *)val = data; + break; + case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END: + /* we only use defalut value 0: high level triggered */ + *(u32 *)val = 0; + break; + default: + ret = -EINVAL; + } + spin_unlock(&s->lock); + + return ret; +} + +static int kvm_pch_pic_read(struct kvm_vcpu *vcpu, + struct kvm_io_device *dev, + gpa_t addr, int len, void *val) +{ + int ret; + struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic; + + if (!s) { + kvm_err("%s: pch pic irqchip not valid!\n", __func__); + return -EINVAL; + } + + /* statistics of pch pic reading */ + vcpu->kvm->stat.pch_pic_read_exits++; + ret = loongarch_pch_pic_read(s, addr, len, val); + + return ret; +} + +static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr, + int len, const void *val) +{ + int ret; + u32 old, data, offset, index; + u64 irq; + + ret = 0; + data = *(u32 *)val; + offset = addr - s->pch_pic_base; + + spin_lock(&s->lock); + switch (offset) { + case PCH_PIC_MASK_START ... PCH_PIC_MASK_END: + offset -= PCH_PIC_MASK_START; + /* get whether high or low 32 bits we want to write */ + index = offset >> 2; + old = pch_pic_write_reg(&s->mask, index, data); + /* enable irq when mask value change to 0 */ + irq = (old & ~data) << (32 * index); + pch_pic_update_batch_irqs(s, irq, 1); + /* disable irq when mask value change to 1 */ + irq = (~old & data) << (32 * index); + pch_pic_update_batch_irqs(s, irq, 0); + break; + case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END: + offset -= PCH_PIC_HTMSI_EN_START; + index = offset >> 2; + pch_pic_write_reg(&s->htmsi_en, index, data); + break; + case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END: + offset -= PCH_PIC_EDGE_START; + index = offset >> 2; + /* 1: edge triggered, 0: level triggered */ + pch_pic_write_reg(&s->edge, index, data); + break; + case PCH_PIC_CLEAR_START ... PCH_PIC_CLEAR_END: + offset -= PCH_PIC_CLEAR_START; + index = offset >> 2; + /* write 1 to clear edge irq */ + old = pch_pic_read_reg(&s->irr, index); + /* + * get the irq bitmap which is edge triggered and + * already set and to be cleared + */ + irq = old & pch_pic_read_reg(&s->edge, index) & data; + /* write irr to the new state where irqs have been cleared */ + pch_pic_write_reg(&s->irr, index, old & ~irq); + /* update cleared irqs */ + pch_pic_update_batch_irqs(s, irq, 0); + break; + case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END: + offset -= PCH_PIC_AUTO_CTRL0_START; + index = offset >> 2; + /* we only use default mode: fixed interrupt distribution mode */ + pch_pic_write_reg(&s->auto_ctrl0, index, 0); + break; + case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END: + offset -= PCH_PIC_AUTO_CTRL1_START; + index = offset >> 2; + /* we only use default mode: fixed interrupt distribution mode */ + pch_pic_write_reg(&s->auto_ctrl1, index, 0); + break; + case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END: + offset -= PCH_PIC_ROUTE_ENTRY_START; + /* only route to int0: eiointc */ + s->route_entry[offset] = 1; + break; + case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END: + /* route table to eiointc */ + offset -= PCH_PIC_HTMSI_VEC_START; + s->htmsi_vector[offset] = (u8)data; + break; + case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END: + offset -= PCH_PIC_POLARITY_START; + index = offset >> 2; + /* we only use defalut value 0: high level triggered */ + pch_pic_write_reg(&s->polarity, index, 0); + break; + default: + ret = -EINVAL; + break; + } + spin_unlock(&s->lock); + + return ret; +} + +static int kvm_pch_pic_write(struct kvm_vcpu *vcpu, + struct kvm_io_device *dev, + gpa_t addr, int len, const void *val) +{ + int ret; + struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic; + + if (!s) { + kvm_err("%s: pch pic irqchip not valid!\n", __func__); + return -EINVAL; + } + + /* statistics of pch pic writing */ + vcpu->kvm->stat.pch_pic_write_exits++; + ret = loongarch_pch_pic_write(s, addr, len, val); + + return ret; +} + +static const struct kvm_io_device_ops kvm_pch_pic_ops = { + .read = kvm_pch_pic_read, + .write = kvm_pch_pic_write, +}; + +static int kvm_pch_pic_init(struct kvm_device *dev, u64 addr) +{ + int ret; + struct kvm *kvm = dev->kvm; + struct kvm_io_device *device; + struct loongarch_pch_pic *s = dev->kvm->arch.pch_pic; + + s->pch_pic_base = addr; + device = &s->device; + /* init device by pch pic writing and reading ops */ + kvm_iodevice_init(device, &kvm_pch_pic_ops); + mutex_lock(&kvm->slots_lock); + /* register pch pic device */ + ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, addr, PCH_PIC_SIZE, device); + mutex_unlock(&kvm->slots_lock); + + return (ret < 0) ? -EFAULT : 0; +} + +/* used by user space to get or set pch pic registers */ +static int kvm_pch_pic_regs_access(struct kvm_device *dev, + struct kvm_device_attr *attr, + bool is_write) +{ + int addr, offset, len = 8, ret = 0; + void __user *data; + void *p = NULL; + struct loongarch_pch_pic *s; + + s = dev->kvm->arch.pch_pic; + addr = attr->attr; + data = (void __user *)attr->addr; + + /* get pointer to pch pic register by addr */ + switch (addr) { + case PCH_PIC_MASK_START: + p = &s->mask; + break; + case PCH_PIC_HTMSI_EN_START: + p = &s->htmsi_en; + break; + case PCH_PIC_EDGE_START: + p = &s->edge; + break; + case PCH_PIC_AUTO_CTRL0_START: + p = &s->auto_ctrl0; + break; + case PCH_PIC_AUTO_CTRL1_START: + p = &s->auto_ctrl1; + break; + case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END: + offset = addr - PCH_PIC_ROUTE_ENTRY_START; + p = &s->route_entry[offset]; + len = 1; + break; + case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END: + offset = addr - PCH_PIC_HTMSI_VEC_START; + p = &s->htmsi_vector[offset]; + len = 1; + break; + case PCH_PIC_INT_IRR_START: + p = &s->irr; + break; + case PCH_PIC_INT_ISR_START: + p = &s->isr; + break; + case PCH_PIC_POLARITY_START: + p = &s->polarity; + break; + default: + return -EINVAL; + } + + spin_lock(&s->lock); + /* write or read value according to is_write */ + if (is_write) { + if (copy_from_user(p, data, len)) + ret = -EFAULT; + } else { + if (copy_to_user(data, p, len)) + ret = -EFAULT; + } + spin_unlock(&s->lock); + + return ret; +} + +static int kvm_pch_pic_get_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + switch (attr->group) { + case KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS: + return kvm_pch_pic_regs_access(dev, attr, false); + default: + return -EINVAL; + } +} + +static int kvm_pch_pic_set_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) +{ + u64 addr; + void __user *uaddr = (void __user *)(long)attr->addr; + + switch (attr->group) { + case KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL: + switch (attr->attr) { + case KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT: + if (copy_from_user(&addr, uaddr, sizeof(addr))) + return -EFAULT; + + if (!dev->kvm->arch.pch_pic) { + kvm_err("%s: please create pch_pic irqchip first!\n", __func__); + return -ENODEV; + } + + return kvm_pch_pic_init(dev, addr); + default: + kvm_err("%s: unknown group (%d) attr (%lld)\n", __func__, attr->group, + attr->attr); + return -EINVAL; + } + case KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS: + return kvm_pch_pic_regs_access(dev, attr, true); + default: + return -EINVAL; + } +} + +static int kvm_setup_default_irq_routing(struct kvm *kvm) +{ + int i, ret; + u32 nr = KVM_IRQCHIP_NUM_PINS; + struct kvm_irq_routing_entry *entries; + + entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < nr; i++) { + entries[i].gsi = i; + entries[i].type = KVM_IRQ_ROUTING_IRQCHIP; + entries[i].u.irqchip.irqchip = 0; + entries[i].u.irqchip.pin = i; + } + ret = kvm_set_irq_routing(kvm, entries, nr, 0); + kfree(entries); + + return ret; +} + +static int kvm_pch_pic_create(struct kvm_device *dev, u32 type) +{ + int ret; + struct kvm *kvm = dev->kvm; + struct loongarch_pch_pic *s; + + /* pch pic should not has been created */ + if (kvm->arch.pch_pic) + return -EINVAL; + + ret = kvm_setup_default_irq_routing(kvm); + if (ret) + return -ENOMEM; + + s = kzalloc(sizeof(struct loongarch_pch_pic), GFP_KERNEL); + if (!s) + return -ENOMEM; + + spin_lock_init(&s->lock); + s->kvm = kvm; + kvm->arch.pch_pic = s; + + return 0; +} + +static void kvm_pch_pic_destroy(struct kvm_device *dev) +{ + struct kvm *kvm; + struct loongarch_pch_pic *s; + + if (!dev || !dev->kvm || !dev->kvm->arch.pch_pic) + return; + + kvm = dev->kvm; + s = kvm->arch.pch_pic; + /* unregister pch pic device and free it's memory */ + kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &s->device); + kfree(s); +} + +static struct kvm_device_ops kvm_pch_pic_dev_ops = { + .name = "kvm-loongarch-pch-pic", + .create = kvm_pch_pic_create, + .destroy = kvm_pch_pic_destroy, + .set_attr = kvm_pch_pic_set_attr, + .get_attr = kvm_pch_pic_get_attr, +}; + +int kvm_loongarch_register_pch_pic_device(void) +{ + return kvm_register_device_ops(&kvm_pch_pic_dev_ops, KVM_DEV_TYPE_LOONGARCH_PCHPIC); +} diff --git a/arch/loongarch/kvm/irqfd.c b/arch/loongarch/kvm/irqfd.c new file mode 100644 index 00000000000000..9a39627aecf07b --- /dev/null +++ b/arch/loongarch/kvm/irqfd.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Loongson Technology Corporation Limited + */ + +#include +#include +#include + +static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, int irq_source_id, int level, bool line_status) +{ + /* PCH-PIC pin (0 ~ 64) <---> GSI (0 ~ 64) */ + pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level); + + return 0; +} + +/* + * kvm_set_msi: inject the MSI corresponding to the + * MSI routing entry + * + * This is the entry point for irqfd MSI injection + * and userspace MSI injection. + */ +int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, int irq_source_id, int level, bool line_status) +{ + if (!level) + return -1; + + pch_msi_set_irq(kvm, e->msi.data, level); + + return 0; +} + +/* + * kvm_set_routing_entry: populate a kvm routing entry + * from a user routing entry + * + * @kvm: the VM this entry is applied to + * @e: kvm kernel routing entry handle + * @ue: user api routing entry handle + * return 0 on success, -EINVAL on errors. + */ +int kvm_set_routing_entry(struct kvm *kvm, + struct kvm_kernel_irq_routing_entry *e, + const struct kvm_irq_routing_entry *ue) +{ + switch (ue->type) { + case KVM_IRQ_ROUTING_IRQCHIP: + e->set = kvm_set_pic_irq; + e->irqchip.irqchip = ue->u.irqchip.irqchip; + e->irqchip.pin = ue->u.irqchip.pin; + + if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) + return -EINVAL; + + return 0; + case KVM_IRQ_ROUTING_MSI: + e->set = kvm_set_msi; + e->msi.address_lo = ue->u.msi.address_lo; + e->msi.address_hi = ue->u.msi.address_hi; + e->msi.data = ue->u.msi.data; + return 0; + default: + return -EINVAL; + } +} + +int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, int irq_source_id, int level, bool line_status) +{ + switch (e->type) { + case KVM_IRQ_ROUTING_IRQCHIP: + pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level); + return 0; + case KVM_IRQ_ROUTING_MSI: + pch_msi_set_irq(kvm, e->msi.data, level); + return 0; + default: + return -EWOULDBLOCK; + } +} + +bool kvm_arch_intc_initialized(struct kvm *kvm) +{ + return kvm_arch_irqchip_in_kernel(kvm); +} diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c index 27e9b94c0a0b6e..396fed2665a517 100644 --- a/arch/loongarch/kvm/main.c +++ b/arch/loongarch/kvm/main.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "trace.h" unsigned long vpid_mask; @@ -313,7 +315,7 @@ void kvm_arch_disable_virtualization_cpu(void) static int kvm_loongarch_env_init(void) { - int cpu, order; + int cpu, order, ret; void *addr; struct kvm_context *context; @@ -368,7 +370,20 @@ static int kvm_loongarch_env_init(void) kvm_init_gcsr_flag(); - return 0; + /* Register LoongArch IPI interrupt controller interface. */ + ret = kvm_loongarch_register_ipi_device(); + if (ret) + return ret; + + /* Register LoongArch EIOINTC interrupt controller interface. */ + ret = kvm_loongarch_register_eiointc_device(); + if (ret) + return ret; + + /* Register LoongArch PCH-PIC interrupt controller interface. */ + ret = kvm_loongarch_register_pch_pic_device(); + + return ret; } static void kvm_loongarch_env_exit(void) diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c index 28681dfb4b8597..4d203294767c5a 100644 --- a/arch/loongarch/kvm/mmu.c +++ b/arch/loongarch/kvm/mmu.c @@ -552,12 +552,10 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) { int ret = 0; - kvm_pfn_t pfn = 0; kvm_pte_t *ptep, changed, new; gfn_t gfn = gpa >> PAGE_SHIFT; struct kvm *kvm = vcpu->kvm; struct kvm_memory_slot *slot; - struct page *page; spin_lock(&kvm->mmu_lock); @@ -570,8 +568,6 @@ static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool writ /* Track access to pages marked old */ new = kvm_pte_mkyoung(*ptep); - /* call kvm_set_pfn_accessed() after unlock */ - if (write && !kvm_pte_dirty(new)) { if (!kvm_pte_write(new)) { ret = -EFAULT; @@ -595,26 +591,14 @@ static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool writ } changed = new ^ (*ptep); - if (changed) { + if (changed) kvm_set_pte(ptep, new); - pfn = kvm_pte_pfn(new); - page = kvm_pfn_to_refcounted_page(pfn); - if (page) - get_page(page); - } + spin_unlock(&kvm->mmu_lock); - if (changed) { - if (kvm_pte_young(changed)) - kvm_set_pfn_accessed(pfn); + if (kvm_pte_dirty(changed)) + mark_page_dirty(kvm, gfn); - if (kvm_pte_dirty(changed)) { - mark_page_dirty(kvm, gfn); - kvm_set_pfn_dirty(pfn); - } - if (page) - put_page(page); - } return ret; out: spin_unlock(&kvm->mmu_lock); @@ -796,6 +780,7 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) struct kvm *kvm = vcpu->kvm; struct kvm_memory_slot *memslot; struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache; + struct page *page; /* Try the fast path to handle old / clean pages */ srcu_idx = srcu_read_lock(&kvm->srcu); @@ -823,7 +808,7 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) mmu_seq = kvm->mmu_invalidate_seq; /* * Ensure the read of mmu_invalidate_seq isn't reordered with PTE reads in - * gfn_to_pfn_prot() (which calls get_user_pages()), so that we don't + * kvm_faultin_pfn() (which calls get_user_pages()), so that we don't * risk the page we get a reference to getting unmapped before we have a * chance to grab the mmu_lock without mmu_invalidate_retry() noticing. * @@ -835,7 +820,7 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) smp_rmb(); /* Slow path - ask KVM core whether we can access this GPA */ - pfn = gfn_to_pfn_prot(kvm, gfn, write, &writeable); + pfn = kvm_faultin_pfn(vcpu, gfn, write, &writeable, &page); if (is_error_noslot_pfn(pfn)) { err = -EFAULT; goto out; @@ -847,10 +832,10 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) /* * This can happen when mappings are changed asynchronously, but * also synchronously if a COW is triggered by - * gfn_to_pfn_prot(). + * kvm_faultin_pfn(). */ spin_unlock(&kvm->mmu_lock); - kvm_release_pfn_clean(pfn); + kvm_release_page_unused(page); if (retry_no > 100) { retry_no = 0; schedule(); @@ -915,14 +900,13 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) else ++kvm->stat.pages; kvm_set_pte(ptep, new_pte); + + kvm_release_faultin_page(kvm, page, false, writeable); spin_unlock(&kvm->mmu_lock); - if (prot_bits & _PAGE_DIRTY) { + if (prot_bits & _PAGE_DIRTY) mark_page_dirty_in_slot(kvm, memslot, gfn); - kvm_set_pfn_dirty(pfn); - } - kvm_release_pfn_clean(pfn); out: srcu_read_unlock(&kvm->srcu, srcu_idx); return err; diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index 174734a23d0ac8..d18a4a2704150e 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -240,7 +240,7 @@ static void kvm_late_check_requests(struct kvm_vcpu *vcpu) */ static int kvm_enter_guest_check(struct kvm_vcpu *vcpu) { - int ret; + int idx, ret; /* * Check conditions before entering the guest @@ -249,7 +249,9 @@ static int kvm_enter_guest_check(struct kvm_vcpu *vcpu) if (ret < 0) return ret; + idx = srcu_read_lock(&vcpu->kvm->srcu); ret = kvm_check_requests(vcpu); + srcu_read_unlock(&vcpu->kvm->srcu, idx); return ret; } @@ -1475,6 +1477,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) /* Init */ vcpu->arch.last_sched_cpu = -1; + /* Init ipi_state lock */ + spin_lock_init(&vcpu->arch.ipi_state.lock); + /* * Initialize guest register state to valid architectural reset state. */ diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c index 4ba734aaef87a7..b8b3e1972d6eaa 100644 --- a/arch/loongarch/kvm/vm.c +++ b/arch/loongarch/kvm/vm.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include const struct _kvm_stats_desc kvm_vm_stats_desc[] = { KVM_GENERIC_VM_STATS(), @@ -76,6 +78,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) int r; switch (ext) { + case KVM_CAP_IRQCHIP: case KVM_CAP_ONE_REG: case KVM_CAP_ENABLE_CAP: case KVM_CAP_READONLY_MEM: @@ -161,6 +164,8 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) struct kvm_device_attr attr; switch (ioctl) { + case KVM_CREATE_IRQCHIP: + return 0; case KVM_HAS_DEVICE_ATTR: if (copy_from_user(&attr, argp, sizeof(attr))) return -EFAULT; @@ -170,3 +175,19 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) return -ENOIOCTLCMD; } } + +int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, bool line_status) +{ + if (!kvm_arch_irqchip_in_kernel(kvm)) + return -ENXIO; + + irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, + irq_event->irq, irq_event->level, line_status); + + return 0; +} + +bool kvm_arch_irqchip_in_kernel(struct kvm *kvm) +{ + return (kvm->arch.ipi && kvm->arch.eiointc && kvm->arch.pch_pic); +} diff --git a/arch/loongarch/mm/pageattr.c b/arch/loongarch/mm/pageattr.c index ffd8d76021d470..bf867824844400 100644 --- a/arch/loongarch/mm/pageattr.c +++ b/arch/loongarch/mm/pageattr.c @@ -216,3 +216,22 @@ int set_direct_map_invalid_noflush(struct page *page) return __set_memory(addr, 1, __pgprot(0), __pgprot(_PAGE_PRESENT | _PAGE_VALID)); } + +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid) +{ + unsigned long addr = (unsigned long)page_address(page); + pgprot_t set, clear; + + if (addr < vm_map_base) + return 0; + + if (valid) { + set = PAGE_KERNEL; + clear = __pgprot(0); + } else { + set = __pgprot(0); + clear = __pgprot(_PAGE_PRESENT | _PAGE_VALID); + } + + return __set_memory(addr, 1, set, clear); +} diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c index 5ac9beb5f0935e..3b427b319db21d 100644 --- a/arch/loongarch/mm/tlb.c +++ b/arch/loongarch/mm/tlb.c @@ -289,7 +289,7 @@ static void setup_tlb_handler(int cpu) /* Avoid lockdep warning */ rcutree_report_cpu_starting(cpu); -#ifdef CONFIG_NUMA +#if defined(CONFIG_NUMA) && !defined(CONFIG_PREEMPT_RT) vec_sz = sizeof(exception_handlers); if (pcpu_handlers[cpu]) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 7dbefd4ba21071..ea357a3edc0943 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -179,15 +179,15 @@ static void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call) if (!is_tail_call) { /* Set return value */ - move_reg(ctx, LOONGARCH_GPR_A0, regmap[BPF_REG_0]); + emit_insn(ctx, addiw, LOONGARCH_GPR_A0, regmap[BPF_REG_0], 0); /* Return to the caller */ - emit_insn(ctx, jirl, LOONGARCH_GPR_RA, LOONGARCH_GPR_ZERO, 0); + emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_RA, 0); } else { /* * Call the next bpf prog and skip the first instruction * of TCC initialization. */ - emit_insn(ctx, jirl, LOONGARCH_GPR_T3, LOONGARCH_GPR_ZERO, 1); + emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_T3, 1); } } @@ -904,7 +904,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext return ret; move_addr(ctx, t1, func_addr); - emit_insn(ctx, jirl, t1, LOONGARCH_GPR_RA, 0); + emit_insn(ctx, jirl, LOONGARCH_GPR_RA, t1, 0); move_reg(ctx, regmap[BPF_REG_0], LOONGARCH_GPR_A0); break; diff --git a/arch/loongarch/vdso/Makefile b/arch/loongarch/vdso/Makefile index 40c1175823d61d..fdde1bcd4e2663 100644 --- a/arch/loongarch/vdso/Makefile +++ b/arch/loongarch/vdso/Makefile @@ -19,7 +19,7 @@ ccflags-vdso := \ cflags-vdso := $(ccflags-vdso) \ -isystem $(shell $(CC) -print-file-name=include) \ $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ - -O2 -g -fno-strict-aliasing -fno-common -fno-builtin \ + -std=gnu11 -O2 -g -fno-strict-aliasing -fno-common -fno-builtin \ -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \ $(call cc-option, -fno-asynchronous-unwind-tables) \ $(call cc-option, -fno-stack-protector) diff --git a/arch/loongarch/vdso/vdso.lds.S b/arch/loongarch/vdso/vdso.lds.S index 6b441bde4026ea..160cfaef2de45b 100644 --- a/arch/loongarch/vdso/vdso.lds.S +++ b/arch/loongarch/vdso/vdso.lds.S @@ -3,6 +3,8 @@ * Author: Huacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited */ +#include +#include OUTPUT_FORMAT("elf64-loongarch", "elf64-loongarch", "elf64-loongarch") @@ -10,7 +12,11 @@ OUTPUT_ARCH(loongarch) SECTIONS { - PROVIDE(_start = .); + PROVIDE(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE); +#ifdef CONFIG_TIME_NS + PROVIDE(_timens_data = _vdso_data + PAGE_SIZE); +#endif + PROVIDE(_loongarch_data = _vdso_data + 2 * PAGE_SIZE); . = SIZEOF_HEADERS; .hash : { *(.hash) } :text diff --git a/arch/loongarch/vdso/vgetcpu.c b/arch/loongarch/vdso/vgetcpu.c index 9e445be39763ae..0db51258b2a7ca 100644 --- a/arch/loongarch/vdso/vgetcpu.c +++ b/arch/loongarch/vdso/vgetcpu.c @@ -21,7 +21,7 @@ static __always_inline int read_cpu_id(void) static __always_inline const struct vdso_pcpu_data *get_pcpu_data(void) { - return (struct vdso_pcpu_data *)(get_vdso_data() + VVAR_LOONGARCH_PAGES_START * PAGE_SIZE); + return _loongarch_data.pdata; } extern diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index cc26df907bfe3c..7c4f7bcc89d763 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -84,24 +84,23 @@ config MMU support by paged memory management. If unsure, say 'Y'. config MMU_MOTOROLA - bool + def_bool MMU && M68KCLASSIC select HAVE_PAGE_SIZE_4KB config MMU_COLDFIRE + def_bool MMU && COLDFIRE select HAVE_PAGE_SIZE_8KB - bool config MMU_SUN3 - bool + def_bool MMU && SUN3 select HAVE_PAGE_SIZE_8KB - depends on MMU && !MMU_MOTOROLA && !MMU_COLDFIRE config ARCH_SUPPORTS_KEXEC - def_bool M68KCLASSIC && MMU + def_bool (M68KCLASSIC || SUN3) && MMU config BOOTINFO_PROC bool "Export bootinfo in procfs" - depends on KEXEC && M68KCLASSIC + depends on KEXEC && (M68KCLASSIC || SUN3) help Say Y to export the bootinfo used to boot the kernel in a "bootinfo" file in procfs. This is useful with kexec. diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu index c777a129768a09..c9a7e602d8a4da 100644 --- a/arch/m68k/Kconfig.cpu +++ b/arch/m68k/Kconfig.cpu @@ -2,7 +2,7 @@ comment "Processor Type" choice - prompt "CPU family support" + prompt "CPU/machine family support" default M68KCLASSIC if MMU default COLDFIRE if !MMU help @@ -19,8 +19,9 @@ choice processor, select COLDFIRE. config M68KCLASSIC - bool "Classic M68K CPU family support" + bool "Classic M68K CPU/machine family support" select HAVE_ARCH_PFN_VALID + select M68020 if MMU && !(M68030 || M68040 || M68060) config COLDFIRE bool "Coldfire CPU family support" @@ -32,13 +33,23 @@ config COLDFIRE select HAVE_LEGACY_CLK select HAVE_PAGE_SIZE_8KB if !MMU -endchoice +config SUN3 + bool "Sun3 machine support" + depends on MMU + select HAVE_ARCH_PFN_VALID + select LEGACY_TIMER_TICK + select NO_DMA + select M68020 + help + This option enables support for the Sun 3 series of workstations + (3/50, 3/60, 3/1xx, 3/2xx systems). These use a classic 68020 CPU + but the custom memory management unit makes them incompatible with + all other classic m68k machines, including Sun 3x. -if M68KCLASSIC +endchoice config M68000 - def_bool y - depends on !MMU + def_bool M68KCLASSIC && !MMU select CPU_HAS_NO_BITFIELDS select CPU_HAS_NO_CAS select CPU_HAS_NO_MULDIV64 @@ -56,7 +67,7 @@ config M68000 a paging MMU. config M68020 - bool "68020 support" + bool "68020 support" if M68KCLASSIC depends on MMU select FPU select CPU_HAS_ADDRESS_SPACES @@ -66,9 +77,10 @@ config M68020 68851 MMU (Memory Management Unit) to run Linux/m68k, except on the Sun 3, which provides its own version. +if M68KCLASSIC && MMU + config M68030 bool "68030 support" - depends on MMU && !MMU_SUN3 select FPU select CPU_HAS_ADDRESS_SPACES help @@ -78,7 +90,6 @@ config M68030 config M68040 bool "68040 support" - depends on MMU && !MMU_SUN3 select FPU select CPU_HAS_ADDRESS_SPACES help @@ -89,13 +100,14 @@ config M68040 config M68060 bool "68060 support" - depends on MMU && !MMU_SUN3 select FPU select CPU_HAS_ADDRESS_SPACES help If you anticipate running this kernel on a computer with a MC68060 processor, say Y. Otherwise, say N. +endif # M68KCLASSIC + config M68328 bool depends on !MMU @@ -117,8 +129,6 @@ config M68VZ328 help Motorola 68VZ328 processor support. -endif # M68KCLASSIC - if COLDFIRE choice @@ -325,7 +335,7 @@ comment "Processor Specific Options" config M68KFPU_EMU bool "Math emulation support" - depends on M68KCLASSIC && FPU + depends on (M68KCLASSIC || SUN3) && FPU help At some point in the future, this will cause floating-point math instructions to be emulated by the kernel on machines that lack a diff --git a/arch/m68k/Kconfig.machine b/arch/m68k/Kconfig.machine index d06b1c5d9b0c4d..de39f23b180ee2 100644 --- a/arch/m68k/Kconfig.machine +++ b/arch/m68k/Kconfig.machine @@ -6,7 +6,6 @@ if M68KCLASSIC config AMIGA bool "Amiga support" depends on MMU - select MMU_MOTOROLA if MMU select LEGACY_TIMER_TICK help This option enables support for the Amiga series of computers. If @@ -16,7 +15,6 @@ config AMIGA config ATARI bool "Atari support" depends on MMU - select MMU_MOTOROLA if MMU select HAVE_ARCH_NVRAM_OPS select LEGACY_TIMER_TICK help @@ -31,7 +29,6 @@ config ATARI_KBD_CORE config MAC bool "Macintosh support" depends on MMU - select MMU_MOTOROLA if MMU select HAVE_ARCH_NVRAM_OPS select HAVE_PATA_PLATFORM select LEGACY_TIMER_TICK @@ -44,7 +41,6 @@ config MAC config APOLLO bool "Apollo support" depends on MMU - select MMU_MOTOROLA if MMU select LEGACY_TIMER_TICK help Say Y here if you want to run Linux on an MC680x0-based Apollo @@ -53,7 +49,6 @@ config APOLLO config VME bool "VME (Motorola and BVM) support" depends on MMU - select MMU_MOTOROLA if MMU help Say Y here if you want to build a kernel for a 680x0 based VME board. Boards currently supported include Motorola boards MVME147, @@ -97,7 +92,6 @@ config BVME6000 config HP300 bool "HP9000/300 and HP9000/400 support" depends on MMU - select MMU_MOTOROLA if MMU select LEGACY_TIMER_TICK help This option enables support for the HP9000/300 and HP9000/400 series @@ -110,7 +104,6 @@ config SUN3X bool "Sun3x support" depends on MMU select LEGACY_TIMER_TICK - select MMU_MOTOROLA if MMU select M68030 help This option enables support for the Sun 3x series of workstations. @@ -124,7 +117,6 @@ config SUN3X config Q40 bool "Q40/Q60 support" depends on MMU - select MMU_MOTOROLA if MMU select LEGACY_TIMER_TICK help The Q40 is a Motorola 68040-based successor to the Sinclair QL @@ -133,22 +125,6 @@ config Q40 Q60. Select your CPU below. For 68LC060 don't forget to enable FPU emulation. -config SUN3 - bool "Sun3 support" - depends on MMU - depends on !MMU_MOTOROLA - select MMU_SUN3 if MMU - select LEGACY_TIMER_TICK - select NO_DMA - select M68020 - help - This option enables support for the Sun 3 series of workstations - (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires - that all other hardware types must be disabled, as Sun 3 kernels - are incompatible with all other m68k targets (including Sun 3x!). - - If you don't want to compile a kernel exclusively for a Sun 3, say N. - config VIRT bool "Virtual M68k Machine support" depends on MMU @@ -157,7 +133,6 @@ config VIRT select GOLDFISH_TIMER select GOLDFISH_TTY select M68040 - select MMU_MOTOROLA if MMU select RTC_CLASS select RTC_DRV_GOLDFISH select TTY diff --git a/arch/m68k/coldfire/device.c b/arch/m68k/coldfire/device.c index 7dab46728aedaf..b6958ec2a220cf 100644 --- a/arch/m68k/coldfire/device.c +++ b/arch/m68k/coldfire/device.c @@ -93,7 +93,7 @@ static struct platform_device mcf_uart = { .dev.platform_data = mcf_uart_platform_data, }; -#if IS_ENABLED(CONFIG_FEC) +#ifdef MCFFEC_BASE0 #ifdef CONFIG_M5441x #define FEC_NAME "enet-fec" @@ -145,6 +145,7 @@ static struct platform_device mcf_fec0 = { .platform_data = FEC_PDATA, } }; +#endif /* MCFFEC_BASE0 */ #ifdef MCFFEC_BASE1 static struct resource mcf_fec1_resources[] = { @@ -182,7 +183,6 @@ static struct platform_device mcf_fec1 = { } }; #endif /* MCFFEC_BASE1 */ -#endif /* CONFIG_FEC */ #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) /* @@ -624,12 +624,12 @@ static struct platform_device mcf_flexcan0 = { static struct platform_device *mcf_devices[] __initdata = { &mcf_uart, -#if IS_ENABLED(CONFIG_FEC) +#ifdef MCFFEC_BASE0 &mcf_fec0, +#endif #ifdef MCFFEC_BASE1 &mcf_fec1, #endif -#endif #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) &mcf_qspi, #endif diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index d01dc47d52ea2f..c705247e7b5b3d 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -449,7 +449,6 @@ CONFIG_RTC_DRV_RP5C01=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -620,6 +619,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index 46808e581d7b47..6d62b9187a58af 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -406,7 +406,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -577,6 +576,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 4469a7839c9d1a..c3c644df852d28 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -426,7 +426,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -597,6 +596,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index c0719322c02837..20261f8196918f 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -398,7 +398,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -569,6 +568,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 8d429e63f8f214..ce4fe93a0f7019 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -408,7 +408,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -579,6 +578,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index bafd33da27c110..040ae75f47c395 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -425,7 +425,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -596,6 +595,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index 6f5ca3f85ea160..20d877cb4e308b 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -503,6 +503,7 @@ CONFIG_UHID=m # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y # CONFIG_RTC_NVMEM is not set +CONFIG_RTC_DRV_M48T59=m CONFIG_RTC_DRV_MSM6242=m CONFIG_RTC_DRV_RP5C01=m CONFIG_RTC_DRV_GENERIC=m @@ -511,7 +512,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -682,6 +682,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index d16b328c71363f..5e1c8d0d3da57d 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -391,13 +391,13 @@ CONFIG_UHID=m # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y # CONFIG_RTC_NVMEM is not set +CONFIG_RTC_DRV_M48T59=y CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_VHOST_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -568,6 +568,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index 80f6c15a5ed5c8..5d1409e6a13773 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -392,13 +392,13 @@ CONFIG_UHID=m # CONFIG_USB_SUPPORT is not set CONFIG_RTC_CLASS=y # CONFIG_RTC_NVMEM is not set +CONFIG_RTC_DRV_M48T59=y CONFIG_RTC_DRV_GENERIC=m # CONFIG_VIRTIO_MENU is not set # CONFIG_VHOST_MENU is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -569,6 +569,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index 0e81589f0ee26d..e4c30e2b9bbb87 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -415,7 +415,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -586,6 +585,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index 8cd785290339db..980843a9ea1eed 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -396,7 +396,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -566,6 +565,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index 78035369f60f1b..38681cc6b598c5 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -396,7 +396,6 @@ CONFIG_RTC_DRV_GENERIC=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_DAX=m CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set @@ -567,6 +566,7 @@ CONFIG_KUNIT_ALL_TESTS=m CONFIG_TEST_DHRY=m CONFIG_TEST_MIN_HEAP=m CONFIG_TEST_DIV64=m +CONFIG_TEST_MULDIV64=m CONFIG_REED_SOLOMON_TEST=m CONFIG_ATOMIC64_SELFTEST=m CONFIG_ASYNC_RAID6_TEST=m diff --git a/arch/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild index 0dbf9c5c6faeb3..b282e0dd8dc10e 100644 --- a/arch/m68k/include/asm/Kbuild +++ b/arch/m68k/include/asm/Kbuild @@ -4,3 +4,4 @@ generic-y += extable.h generic-y += kvm_para.h generic-y += mcs_spinlock.h generic-y += spinlock.h +generic-y += text-patching.h diff --git a/arch/m68k/include/asm/irq.h b/arch/m68k/include/asm/irq.h index 14992fde734016..2263e92d418ab7 100644 --- a/arch/m68k/include/asm/irq.h +++ b/arch/m68k/include/asm/irq.h @@ -28,10 +28,8 @@ #define NR_IRQS 32 #elif defined(CONFIG_APOLLO) #define NR_IRQS 24 -#elif defined(CONFIG_HP300) +#else /* CONFIG_HP300 etc. */ #define NR_IRQS 8 -#else -#define NR_IRQS 0 #endif #if defined(CONFIG_M68020) || defined(CONFIG_M68030) || \ diff --git a/arch/m68k/include/asm/mcfgpio.h b/arch/m68k/include/asm/mcfgpio.h index 019f244395464d..9c91ecdafc4539 100644 --- a/arch/m68k/include/asm/mcfgpio.h +++ b/arch/m68k/include/asm/mcfgpio.h @@ -136,7 +136,7 @@ static inline void gpio_free(unsigned gpio) * read-modify-write as well as those controlled by the EPORT and GPIO modules. */ #define MCFGPIO_SCR_START 40 -#elif defined(CONFIGM5441x) +#elif defined(CONFIG_M5441x) /* The m5441x EPORT doesn't have its own GPIO port, uses PORT C */ #define MCFGPIO_SCR_START 0 #else diff --git a/arch/m68k/include/asm/mvme147hw.h b/arch/m68k/include/asm/mvme147hw.h index e28eb1c0e0bfb3..6ad93bac06f9d9 100644 --- a/arch/m68k/include/asm/mvme147hw.h +++ b/arch/m68k/include/asm/mvme147hw.h @@ -4,24 +4,7 @@ #include -typedef struct { - unsigned char - ctrl, - bcd_sec, - bcd_min, - bcd_hr, - bcd_dow, - bcd_dom, - bcd_mth, - bcd_year; -} MK48T02; - -#define RTC_WRITE 0x80 -#define RTC_READ 0x40 -#define RTC_STOP 0x20 - -#define m147_rtc ((MK48T02 * volatile)0xfffe07f8) - +#define MVME147_RTC_BASE 0xfffe0000 struct pcc_regs { volatile u_long dma_tadr; @@ -93,8 +76,8 @@ struct pcc_regs { #define M147_SCC_B_ADDR 0xfffe3000 #define M147_SCC_PCLK 5000000 -#define MVME147_IRQ_SCSI_PORT (IRQ_USER+0x45) -#define MVME147_IRQ_SCSI_DMA (IRQ_USER+0x46) +#define MVME147_IRQ_SCSI_PORT (IRQ_USER + 5) +#define MVME147_IRQ_SCSI_DMA (IRQ_USER + 6) /* SCC interrupts, for MVME147 */ diff --git a/arch/m68k/include/asm/mvme16xhw.h b/arch/m68k/include/asm/mvme16xhw.h index cc7f5ae1220ff7..ff1126a51fbeca 100644 --- a/arch/m68k/include/asm/mvme16xhw.h +++ b/arch/m68k/include/asm/mvme16xhw.h @@ -24,23 +24,7 @@ typedef struct { #define mvmelp ((*(volatile MVMElpPtr)(MVME_LPR_BASE))) -typedef struct { - unsigned char - ctrl, - bcd_sec, - bcd_min, - bcd_hr, - bcd_dow, - bcd_dom, - bcd_mth, - bcd_year; -} MK48T08_t, *MK48T08ptr_t; - -#define RTC_WRITE 0x80 -#define RTC_READ 0x40 -#define RTC_STOP 0x20 - -#define MVME_RTC_BASE 0xfffc1ff8 +#define MVME_RTC_BASE 0xfffc0000 #define MVME_I596_BASE 0xfff46000 diff --git a/arch/m68k/include/asm/page.h b/arch/m68k/include/asm/page.h index 8cfb84b4997514..b173ba27d36f14 100644 --- a/arch/m68k/include/asm/page.h +++ b/arch/m68k/include/asm/page.h @@ -6,10 +6,8 @@ #include #include -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include + #define PAGE_OFFSET (PAGE_OFFSET_RAW) #ifndef __ASSEMBLY__ diff --git a/arch/m68k/include/asm/page_no.h b/arch/m68k/include/asm/page_no.h index af3a10973233cf..63c0e706084b1e 100644 --- a/arch/m68k/include/asm/page_no.h +++ b/arch/m68k/include/asm/page_no.h @@ -14,7 +14,7 @@ extern unsigned long memory_end; #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define vma_alloc_zeroed_movable_folio(vma, vaddr) \ - vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false) + vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr) #define __pa(vaddr) ((unsigned long)(vaddr)) #define __va(paddr) ((void *)((unsigned long)(paddr))) diff --git a/arch/m68k/include/asm/virtconvert.h b/arch/m68k/include/asm/virtconvert.h index 0a27905b0036ff..32e27bddb7d430 100644 --- a/arch/m68k/include/asm/virtconvert.h +++ b/arch/m68k/include/asm/virtconvert.h @@ -28,9 +28,6 @@ static inline void *phys_to_virt(unsigned long address) return __va(address); } -/* Permanent address of a page. */ -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - /* * IO bus memory addresses are 1:1 with the physical address, * deprecated globally but still used on two machines. diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index f335bf3268a108..6c732ed3998b71 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -5,16 +5,8 @@ extra-y += vmlinux.lds -obj-$(CONFIG_AMIGA) := head.o -obj-$(CONFIG_ATARI) := head.o -obj-$(CONFIG_MAC) := head.o -obj-$(CONFIG_APOLLO) := head.o -obj-$(CONFIG_VME) := head.o -obj-$(CONFIG_HP300) := head.o -obj-$(CONFIG_Q40) := head.o -obj-$(CONFIG_SUN3X) := head.o -obj-$(CONFIG_VIRT) := head.o -obj-$(CONFIG_SUN3) := sun3-head.o +obj-$(CONFIG_MMU_MOTOROLA) := head.o +obj-$(CONFIG_SUN3) := sun3-head.o obj-y += entry.o irq.o module.o process.o ptrace.o obj-y += setup.o signal.o sys_m68k.o syscalltable.o time.o traps.o diff --git a/arch/m68k/kernel/early_printk.c b/arch/m68k/kernel/early_printk.c index 3cc944df04f65e..f11ef9f1f56fcf 100644 --- a/arch/m68k/kernel/early_printk.c +++ b/arch/m68k/kernel/early_printk.c @@ -13,6 +13,7 @@ #include +#include "../mvme147/mvme147.h" #include "../mvme16x/mvme16x.h" asmlinkage void __init debug_cons_nputs(const char *s, unsigned n); @@ -22,7 +23,9 @@ static void __ref debug_cons_write(struct console *c, { #if !(defined(CONFIG_SUN3) || defined(CONFIG_M68000) || \ defined(CONFIG_COLDFIRE)) - if (MACH_IS_MVME16x) + if (MACH_IS_MVME147) + mvme147_scc_write(c, s, n); + else if (MACH_IS_MVME16x) mvme16x_cons_write(c, s, n); else debug_cons_nputs(s, n); diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c index 10310b04f77d8d..15c1a595a1de0b 100644 --- a/arch/m68k/kernel/setup_mm.c +++ b/arch/m68k/kernel/setup_mm.c @@ -249,7 +249,11 @@ void __init setup_arch(char **cmdline_p) process_uboot_commandline(&m68k_command_line[0], CL_SIZE); *cmdline_p = m68k_command_line; memcpy(boot_command_line, *cmdline_p, CL_SIZE); - + /* + * Initialise the static keys early as they may be enabled by the + * cpufeature code and early parameters. + */ + jump_label_init(); parse_early_param(); switch (m68k_machtype) { diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl index 22a3cbd4c60298..f5ed71f1910d09 100644 --- a/arch/m68k/kernel/syscalls/syscall.tbl +++ b/arch/m68k/kernel/syscalls/syscall.tbl @@ -462,3 +462,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index a97600b2af5021..acd4c2da562bf0 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -62,7 +62,7 @@ void timer_heartbeat(void) } #endif /* CONFIG_HEARTBEAT */ -#ifdef CONFIG_M68KCLASSIC +#if defined(CONFIG_M68KCLASSIC) || defined(CONFIG_SUN3) /* machine dependent timer functions */ int (*mach_hwclk) (int, struct rtc_time*); EXPORT_SYMBOL(mach_hwclk); @@ -149,7 +149,7 @@ static int __init rtc_init(void) module_init(rtc_init); #endif /* CONFIG_RTC_DRV_GENERIC */ -#endif /* CONFIG M68KCLASSIC */ +#endif /* CONFIG_M68KCLASSIC || SUN3 */ void __init time_init(void) { diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 53d0cf343d90f9..d2f25e8895e5a5 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -383,7 +383,7 @@ static inline void bus_error030 (struct frame *fp) fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); if (ssw & DF) pr_debug("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", + str_read_write(ssw & RW), fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc); @@ -419,7 +419,7 @@ static inline void bus_error030 (struct frame *fp) } pr_err("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", + str_read_write(ssw & RW), fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc); } @@ -455,7 +455,7 @@ static inline void bus_error030 (struct frame *fp) pr_debug("*** unexpected busfault type=%#04x\n", buserr_type); pr_debug("invalid %s access at %#lx from pc %#lx\n", - !(ssw & RW) ? "write" : "read", addr, + str_read_write(ssw & RW), addr, fp->ptregs.pc); die_if_kernel ("Oops", &fp->ptregs, buserr_type); force_sig (SIGBUS); @@ -514,7 +514,7 @@ static inline void bus_error030 (struct frame *fp) fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); if (ssw & DF) pr_debug("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", + str_read_write(ssw & RW), fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc); @@ -548,7 +548,7 @@ static inline void bus_error030 (struct frame *fp) /* We might have an exception table for this PC */ if (ssw & 4 && !search_exception_tables(fp->ptregs.pc)) { pr_err("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", + str_read_write(ssw & RW), fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc); goto buserr; @@ -564,7 +564,7 @@ static inline void bus_error030 (struct frame *fp) mmusr); } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { pr_err("invalid %s access at %#lx from pc %#lx\n", - !(ssw & RW) ? "write" : "read", addr, + str_read_write(ssw & RW), addr, fp->ptregs.pc); die_if_kernel("Oops",&fp->ptregs,mmusr); force_sig(SIGSEGV); @@ -575,7 +575,7 @@ static inline void bus_error030 (struct frame *fp) #endif pr_err("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", - !(ssw & RW) ? "write" : "read", addr, + str_read_write(ssw & RW), addr, fp->ptregs.pc, ssw); asm volatile ("ptestr #1,%1@,#0\n\t" "pmove %%psr,%0" @@ -991,7 +991,7 @@ static void bad_super_trap(struct frame *fp) fp->ptregs.pc + 4 : fp->un.fmtb.baddr); if (ssw & DF) pr_err("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", + str_read_write(ssw & RW), fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc); } diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index 8b5dc07f0811f2..3054d3857efa2b 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -19,8 +19,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -32,16 +33,13 @@ #include #include +#include "mvme147.h" static void mvme147_get_model(char *model); -extern void mvme147_sched_init(void); -extern int mvme147_hwclk (int, struct rtc_time *); +static void __init mvme147_sched_init(void); extern void mvme147_reset (void); -static int bcd2int (unsigned char b); - - int __init mvme147_parse_bootinfo(const struct bi_record *bi) { uint16_t tag = be16_to_cpu(bi->tag); @@ -79,7 +77,6 @@ void __init config_mvme147(void) { mach_sched_init = mvme147_sched_init; mach_init_IRQ = mvme147_init_IRQ; - mach_hwclk = mvme147_hwclk; mach_reset = mvme147_reset; mach_get_model = mvme147_get_model; @@ -88,6 +85,28 @@ void __init config_mvme147(void) vme_brdtype = VME_TYPE_MVME147; } +static struct resource m48t59_rsrc[] = { + DEFINE_RES_MEM(MVME147_RTC_BASE, 0x800), +}; + +static struct m48t59_plat_data m48t59_data = { + .type = M48T59RTC_TYPE_M48T02, + .yy_offset = 70, +}; + +static int __init mvme147_platform_init(void) +{ + if (!MACH_IS_MVME147) + return 0; + + platform_device_register_resndata(NULL, "rtc-m48t59", -1, + m48t59_rsrc, ARRAY_SIZE(m48t59_rsrc), + &m48t59_data, sizeof(m48t59_data)); + return 0; +} + +arch_initcall(mvme147_platform_init); + static u64 mvme147_read_clk(struct clocksource *cs); static struct clocksource mvme147_clk = { @@ -123,7 +142,7 @@ static irqreturn_t mvme147_timer_int (int irq, void *dev_id) } -void mvme147_sched_init (void) +static void __init mvme147_sched_init(void) { if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, IRQF_TIMER, "timer 1", NULL)) @@ -161,27 +180,31 @@ static u64 mvme147_read_clk(struct clocksource *cs) return ticks; } -static int bcd2int (unsigned char b) +static void scc_delay(void) +{ + __asm__ __volatile__ ("nop; nop;"); +} + +static void scc_write(char ch) { - return ((b>>4)*10 + (b&15)); + do { + scc_delay(); + } while (!(in_8(M147_SCC_A_ADDR) & BIT(2))); + scc_delay(); + out_8(M147_SCC_A_ADDR, 8); + scc_delay(); + out_8(M147_SCC_A_ADDR, ch); } -int mvme147_hwclk(int op, struct rtc_time *t) +void mvme147_scc_write(struct console *co, const char *str, unsigned int count) { - if (!op) { - m147_rtc->ctrl = RTC_READ; - t->tm_year = bcd2int (m147_rtc->bcd_year); - t->tm_mon = bcd2int(m147_rtc->bcd_mth) - 1; - t->tm_mday = bcd2int (m147_rtc->bcd_dom); - t->tm_hour = bcd2int (m147_rtc->bcd_hr); - t->tm_min = bcd2int (m147_rtc->bcd_min); - t->tm_sec = bcd2int (m147_rtc->bcd_sec); - m147_rtc->ctrl = 0; - if (t->tm_year < 70) - t->tm_year += 100; - } else { - /* FIXME Setting the time is not yet supported */ - return -EOPNOTSUPP; + unsigned long flags; + + local_irq_save(flags); + while (count--) { + if (*str == '\n') + scc_write('\r'); + scc_write(*str++); } - return 0; + local_irq_restore(flags); } diff --git a/arch/m68k/mvme147/mvme147.h b/arch/m68k/mvme147/mvme147.h new file mode 100644 index 00000000000000..140bc98b0102aa --- /dev/null +++ b/arch/m68k/mvme147/mvme147.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +struct console; + +/* config.c */ +void mvme147_scc_write(struct console *co, const char *str, unsigned int count); diff --git a/arch/m68k/mvme16x/Makefile b/arch/m68k/mvme16x/Makefile index a8a368c2cbea5c..02f9e4ad8209a6 100644 --- a/arch/m68k/mvme16x/Makefile +++ b/arch/m68k/mvme16x/Makefile @@ -3,4 +3,4 @@ # Makefile for Linux arch/m68k/mvme16x source directory # -obj-y := config.o rtc.o +obj-y := config.o diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index d1fbd1704d6582..99768fe8da73aa 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -21,9 +21,10 @@ #include #include #include -#include #include #include +#include +#include #include #include @@ -39,16 +40,10 @@ extern t_bdid mvme_bdid; -static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE; - static void mvme16x_get_model(char *model); extern void mvme16x_sched_init(void); -extern int mvme16x_hwclk (int, struct rtc_time *); extern void mvme16x_reset (void); -int bcd2int (unsigned char b); - - unsigned short mvme16x_config; EXPORT_SYMBOL(mvme16x_config); @@ -268,7 +263,6 @@ void __init config_mvme16x(void) mach_sched_init = mvme16x_sched_init; mach_init_IRQ = mvme16x_init_IRQ; - mach_hwclk = mvme16x_hwclk; mach_reset = mvme16x_reset; mach_get_model = mvme16x_get_model; mach_get_hardware_list = mvme16x_get_hardware_list; @@ -312,6 +306,28 @@ void __init config_mvme16x(void) } } +static struct resource m48t59_rsrc[] = { + DEFINE_RES_MEM(MVME_RTC_BASE, 0x2000), +}; + +static struct m48t59_plat_data m48t59_data = { + .type = M48T59RTC_TYPE_M48T08, + .yy_offset = 70, +}; + +static int __init mvme16x_platform_init(void) +{ + if (!MACH_IS_MVME16x) + return 0; + + platform_device_register_resndata(NULL, "rtc-m48t59", -1, + m48t59_rsrc, ARRAY_SIZE(m48t59_rsrc), + &m48t59_data, sizeof(m48t59_data)); + return 0; +} + +arch_initcall(mvme16x_platform_init); + static irqreturn_t mvme16x_abort_int (int irq, void *dev_id) { unsigned long *new = (unsigned long *)vectors; @@ -426,28 +442,3 @@ static u64 mvme16x_read_clk(struct clocksource *cs) return ticks; } - -int bcd2int (unsigned char b) -{ - return ((b>>4)*10 + (b&15)); -} - -int mvme16x_hwclk(int op, struct rtc_time *t) -{ - if (!op) { - rtc->ctrl = RTC_READ; - t->tm_year = bcd2int (rtc->bcd_year); - t->tm_mon = bcd2int(rtc->bcd_mth) - 1; - t->tm_mday = bcd2int (rtc->bcd_dom); - t->tm_hour = bcd2int (rtc->bcd_hr); - t->tm_min = bcd2int (rtc->bcd_min); - t->tm_sec = bcd2int (rtc->bcd_sec); - rtc->ctrl = 0; - if (t->tm_year < 70) - t->tm_year += 100; - } else { - /* FIXME Setting the time is not yet supported */ - return -EOPNOTSUPP; - } - return 0; -} diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c deleted file mode 100644 index ccbaae1125e6f1..00000000000000 --- a/arch/m68k/mvme16x/rtc.c +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Real Time Clock interface for Linux on the MVME16x - * - * Based on the PC driver by Paul Gortmaker. - */ - -#define RTC_VERSION "1.00" - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For struct rtc_time and ioctls, etc */ -#include -#include - -#include -#include -#include - -/* - * We sponge a minor off of the misc major. No need slurping - * up another valuable major dev number for this. If you add - * an ioctl, make sure you don't conflict with SPARC's RTC - * ioctls. - */ - -static const unsigned char days_in_mo[] = -{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -static atomic_t rtc_ready = ATOMIC_INIT(1); - -static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - volatile MK48T08ptr_t rtc = (MK48T08ptr_t)MVME_RTC_BASE; - unsigned long flags; - struct rtc_time wtime; - void __user *argp = (void __user *)arg; - - switch (cmd) { - case RTC_RD_TIME: /* Read the time/date from RTC */ - { - local_irq_save(flags); - /* Ensure clock and real-time-mode-register are accessible */ - rtc->ctrl = RTC_READ; - memset(&wtime, 0, sizeof(struct rtc_time)); - wtime.tm_sec = bcd2bin(rtc->bcd_sec); - wtime.tm_min = bcd2bin(rtc->bcd_min); - wtime.tm_hour = bcd2bin(rtc->bcd_hr); - wtime.tm_mday = bcd2bin(rtc->bcd_dom); - wtime.tm_mon = bcd2bin(rtc->bcd_mth)-1; - wtime.tm_year = bcd2bin(rtc->bcd_year); - if (wtime.tm_year < 70) - wtime.tm_year += 100; - wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1; - rtc->ctrl = 0; - local_irq_restore(flags); - return copy_to_user(argp, &wtime, sizeof wtime) ? - -EFAULT : 0; - } - case RTC_SET_TIME: /* Set the RTC */ - { - struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned int yrs; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (copy_from_user(&rtc_tm, argp, sizeof(struct rtc_time))) - return -EFAULT; - - yrs = rtc_tm.tm_year; - if (yrs < 1900) - yrs += 1900; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - - if ((mon > 12) || (day == 0)) - return -EINVAL; - - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; - - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; - - if (yrs >= 2070) - return -EINVAL; - - local_irq_save(flags); - rtc->ctrl = RTC_WRITE; - - rtc->bcd_sec = bin2bcd(sec); - rtc->bcd_min = bin2bcd(min); - rtc->bcd_hr = bin2bcd(hrs); - rtc->bcd_dom = bin2bcd(day); - rtc->bcd_mth = bin2bcd(mon); - rtc->bcd_year = bin2bcd(yrs%100); - - rtc->ctrl = 0; - local_irq_restore(flags); - return 0; - } - default: - return -EINVAL; - } -} - -/* - * We enforce only one user at a time here with the open/close. - */ -static int rtc_open(struct inode *inode, struct file *file) -{ - if( !atomic_dec_and_test(&rtc_ready) ) - { - atomic_inc( &rtc_ready ); - return -EBUSY; - } - return 0; -} - -static int rtc_release(struct inode *inode, struct file *file) -{ - atomic_inc( &rtc_ready ); - return 0; -} - -/* - * The various file operations we support. - */ - -static const struct file_operations rtc_fops = { - .unlocked_ioctl = rtc_ioctl, - .open = rtc_open, - .release = rtc_release, - .llseek = noop_llseek, -}; - -static struct miscdevice rtc_dev= -{ - .minor = RTC_MINOR, - .name = "rtc", - .fops = &rtc_fops -}; - -static int __init rtc_MK48T08_init(void) -{ - if (!MACH_IS_MVME16x) - return -ENODEV; - - pr_info("MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION); - return misc_register(&rtc_dev); -} -device_initcall(rtc_MK48T08_init); diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild index a055f5dbe00a31..7178f990e8b3d1 100644 --- a/arch/microblaze/include/asm/Kbuild +++ b/arch/microblaze/include/asm/Kbuild @@ -8,3 +8,4 @@ generic-y += parport.h generic-y += syscalls.h generic-y += tlb.h generic-y += user.h +generic-y += text-patching.h diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h index 8810f4f1c3b02d..90fc9c81debda7 100644 --- a/arch/microblaze/include/asm/page.h +++ b/arch/microblaze/include/asm/page.h @@ -19,10 +19,7 @@ #ifdef __KERNEL__ -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #define LOAD_OFFSET ASM_CONST((CONFIG_KERNEL_START-CONFIG_KERNEL_BASE_ADDR)) @@ -101,7 +98,6 @@ extern int page_is_ram(unsigned long pfn); # define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) # define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) -# define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) # define ARCH_PFN_OFFSET (memory_start >> PAGE_SHIFT) # endif /* __ASSEMBLY__ */ diff --git a/arch/microblaze/include/uapi/asm/setup.h b/arch/microblaze/include/uapi/asm/setup.h index 6831794e6f2c2d..16c56807f86a2d 100644 --- a/arch/microblaze/include/uapi/asm/setup.h +++ b/arch/microblaze/include/uapi/asm/setup.h @@ -14,7 +14,4 @@ #define COMMAND_LINE_SIZE 256 -# ifndef __ASSEMBLY__ - -# endif /* __ASSEMBLY__ */ #endif /* _UAPI_ASM_MICROBLAZE_SETUP_H */ diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c index 9581d194d9e479..37cb2898216bbd 100644 --- a/arch/microblaze/kernel/cpu/mb.c +++ b/arch/microblaze/kernel/cpu/mb.c @@ -66,10 +66,10 @@ static int show_cpuinfo(struct seq_file *m, void *v) " MSR:\t\t%s\n" " PCMP:\t\t%s\n" " DIV:\t\t%s\n", - (cpuinfo.use_instr & PVR0_USE_BARREL_MASK) ? "yes" : "no", - (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) ? "yes" : "no", - (cpuinfo.use_instr & PVR2_USE_PCMP_INSTR) ? "yes" : "no", - (cpuinfo.use_instr & PVR0_USE_DIV_MASK) ? "yes" : "no"); + str_yes_no(cpuinfo.use_instr & PVR0_USE_BARREL_MASK), + str_yes_no(cpuinfo.use_instr & PVR2_USE_MSR_INSTR), + str_yes_no(cpuinfo.use_instr & PVR2_USE_PCMP_INSTR), + str_yes_no(cpuinfo.use_instr & PVR0_USE_DIV_MASK)); seq_printf(m, " MMU:\t\t%x\n", cpuinfo.mmu); @@ -120,7 +120,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "HW-Debug:\t%s\n", - cpuinfo.hw_debug ? "yes" : "no"); + str_yes_no(cpuinfo.hw_debug)); seq_printf(m, "PVR-USR1:\t%02x\n" diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c index c892e173ec990b..a8553f54152b76 100644 --- a/arch/microblaze/kernel/microblaze_ksyms.c +++ b/arch/microblaze/kernel/microblaze_ksyms.c @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef CONFIG_FUNCTION_TRACER extern void _mcount(void); @@ -46,3 +47,12 @@ extern void __udivsi3(void); EXPORT_SYMBOL(__udivsi3); extern void __umodsi3(void); EXPORT_SYMBOL(__umodsi3); + +#ifdef CONFIG_MB_MANAGER +extern void xmb_manager_register(uintptr_t phys_baseaddr, u32 cr_val, + void (*callback)(void *data), + void *priv, void (*reset_callback)(void *data)); +EXPORT_SYMBOL(xmb_manager_register); +extern asmlinkage void xmb_inject_err(void); +EXPORT_SYMBOL(xmb_inject_err); +#endif diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c index e424c796e297c5..76ac4cfdfb42ce 100644 --- a/arch/microblaze/kernel/prom.c +++ b/arch/microblaze/kernel/prom.c @@ -18,7 +18,7 @@ void __init early_init_devtree(void *params) { pr_debug(" -> early_init_devtree(%p)\n", params); - early_init_dt_scan(params); + early_init_dt_scan(params, __pa(params)); if (!strlen(boot_command_line)) strscpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl index 2b81a6bd78b292..680f568b77f2cb 100644 --- a/arch/microblaze/kernel/syscalls/syscall.tbl +++ b/arch/microblaze/kernel/syscalls/syscall.tbl @@ -468,3 +468,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/arch/mips/boot/dts/brcm/bcm6358.dtsi b/arch/mips/boot/dts/brcm/bcm6358.dtsi index 777c4379ed03c6..5e487f66c34306 100644 --- a/arch/mips/boot/dts/brcm/bcm6358.dtsi +++ b/arch/mips/boot/dts/brcm/bcm6358.dtsi @@ -13,6 +13,7 @@ cpus { #size-cells = <0>; mips-hpt-frequency = <150000000>; + brcm,bmips-cbr-reg = <0xff400000>; cpu@0 { compatible = "brcm,bmips4350"; diff --git a/arch/mips/boot/dts/brcm/bcm6368.dtsi b/arch/mips/boot/dts/brcm/bcm6368.dtsi index fc15e200877d79..087f3295a14b40 100644 --- a/arch/mips/boot/dts/brcm/bcm6368.dtsi +++ b/arch/mips/boot/dts/brcm/bcm6368.dtsi @@ -13,6 +13,7 @@ cpus { #size-cells = <0>; mips-hpt-frequency = <200000000>; + brcm,bmips-cbr-reg = <0xff400000>; cpu@0 { compatible = "brcm,bmips4350"; diff --git a/arch/mips/boot/dts/loongson/ls7a-pch.dtsi b/arch/mips/boot/dts/loongson/ls7a-pch.dtsi index cce9428afc41fc..ee71045883e7e7 100644 --- a/arch/mips/boot/dts/loongson/ls7a-pch.dtsi +++ b/arch/mips/boot/dts/loongson/ls7a-pch.dtsi @@ -70,7 +70,6 @@ pci@1a000000 { device_type = "pci"; #address-cells = <3>; #size-cells = <2>; - #interrupt-cells = <2>; msi-parent = <&msi>; reg = <0 0x1a000000 0 0x02000000>, @@ -234,7 +233,7 @@ phy1: ethernet-phy@1 { }; }; - pci_bridge@9,0 { + pcie@9,0 { compatible = "pci0014,7a19.1", "pci0014,7a19", "pciclass060400", @@ -244,12 +243,16 @@ pci_bridge@9,0 { interrupts = <32 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 32 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@a,0 { + pcie@a,0 { compatible = "pci0014,7a09.1", "pci0014,7a09", "pciclass060400", @@ -259,12 +262,16 @@ pci_bridge@a,0 { interrupts = <33 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 33 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@b,0 { + pcie@b,0 { compatible = "pci0014,7a09.1", "pci0014,7a09", "pciclass060400", @@ -274,12 +281,16 @@ pci_bridge@b,0 { interrupts = <34 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 34 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@c,0 { + pcie@c,0 { compatible = "pci0014,7a09.1", "pci0014,7a09", "pciclass060400", @@ -289,12 +300,16 @@ pci_bridge@c,0 { interrupts = <35 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 35 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@d,0 { + pcie@d,0 { compatible = "pci0014,7a19.1", "pci0014,7a19", "pciclass060400", @@ -304,12 +319,16 @@ pci_bridge@d,0 { interrupts = <36 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 36 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@e,0 { + pcie@e,0 { compatible = "pci0014,7a09.1", "pci0014,7a09", "pciclass060400", @@ -319,12 +338,16 @@ pci_bridge@e,0 { interrupts = <37 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 37 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@f,0 { + pcie@f,0 { compatible = "pci0014,7a29.1", "pci0014,7a29", "pciclass060400", @@ -334,12 +357,16 @@ pci_bridge@f,0 { interrupts = <40 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 40 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@10,0 { + pcie@10,0 { compatible = "pci0014,7a19.1", "pci0014,7a19", "pciclass060400", @@ -349,12 +376,16 @@ pci_bridge@10,0 { interrupts = <41 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 41 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@11,0 { + pcie@11,0 { compatible = "pci0014,7a29.1", "pci0014,7a29", "pciclass060400", @@ -364,12 +395,16 @@ pci_bridge@11,0 { interrupts = <42 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 42 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@12,0 { + pcie@12,0 { compatible = "pci0014,7a19.1", "pci0014,7a19", "pciclass060400", @@ -379,12 +414,16 @@ pci_bridge@12,0 { interrupts = <43 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 43 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@13,0 { + pcie@13,0 { compatible = "pci0014,7a29.1", "pci0014,7a29", "pciclass060400", @@ -394,12 +433,16 @@ pci_bridge@13,0 { interrupts = <38 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 38 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; - pci_bridge@14,0 { + pcie@14,0 { compatible = "pci0014,7a19.1", "pci0014,7a19", "pciclass060400", @@ -409,9 +452,13 @@ pci_bridge@14,0 { interrupts = <39 IRQ_TYPE_LEVEL_HIGH>; interrupt-parent = <&pic>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; interrupt-map = <0 0 0 0 &pic 39 IRQ_TYPE_LEVEL_HIGH>; + ranges; }; }; diff --git a/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi b/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi deleted file mode 100644 index 17a342cc744e57..00000000000000 --- a/arch/mips/boot/dts/mobileye/eyeq5-clocks.dtsi +++ /dev/null @@ -1,270 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -/* - * Copyright 2023 Mobileye Vision Technologies Ltd. - */ - -#include - -/ { - /* Fixed clock */ - xtal: xtal { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <30000000>; - }; - -/* PLL_CPU derivatives */ - occ_cpu: occ-cpu { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_CPU>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - si_css0_ref_clk: si-css0-ref-clk { /* gate ClkRstGen_si_css0_ref */ - compatible = "fixed-factor-clock"; - clocks = <&occ_cpu>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - cpc_clk: cpc-clk { - compatible = "fixed-factor-clock"; - clocks = <&si_css0_ref_clk>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - core0_clk: core0-clk { - compatible = "fixed-factor-clock"; - clocks = <&si_css0_ref_clk>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - core1_clk: core1-clk { - compatible = "fixed-factor-clock"; - clocks = <&si_css0_ref_clk>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - core2_clk: core2-clk { - compatible = "fixed-factor-clock"; - clocks = <&si_css0_ref_clk>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - core3_clk: core3-clk { - compatible = "fixed-factor-clock"; - clocks = <&si_css0_ref_clk>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - cm_clk: cm-clk { - compatible = "fixed-factor-clock"; - clocks = <&si_css0_ref_clk>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - mem_clk: mem-clk { - compatible = "fixed-factor-clock"; - clocks = <&si_css0_ref_clk>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - occ_isram: occ-isram { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_CPU>; - #clock-cells = <0>; - clock-div = <2>; - clock-mult = <1>; - }; - isram_clk: isram-clk { /* gate ClkRstGen_isram */ - compatible = "fixed-factor-clock"; - clocks = <&occ_isram>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - occ_dbu: occ-dbu { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_CPU>; - #clock-cells = <0>; - clock-div = <10>; - clock-mult = <1>; - }; - si_dbu_tp_pclk: si-dbu-tp-pclk { /* gate ClkRstGen_dbu */ - compatible = "fixed-factor-clock"; - clocks = <&occ_dbu>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; -/* PLL_VDI derivatives */ - occ_vdi: occ-vdi { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_VDI>; - #clock-cells = <0>; - clock-div = <2>; - clock-mult = <1>; - }; - vdi_clk: vdi-clk { /* gate ClkRstGen_vdi */ - compatible = "fixed-factor-clock"; - clocks = <&occ_vdi>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - occ_can_ser: occ-can-ser { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_VDI>; - #clock-cells = <0>; - clock-div = <16>; - clock-mult = <1>; - }; - can_ser_clk: can-ser-clk { /* gate ClkRstGen_can_ser */ - compatible = "fixed-factor-clock"; - clocks = <&occ_can_ser>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - i2c_ser_clk: i2c-ser-clk { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_VDI>; - #clock-cells = <0>; - clock-div = <20>; - clock-mult = <1>; - }; -/* PLL_PER derivatives */ - occ_periph: occ-periph { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_PER>; - #clock-cells = <0>; - clock-div = <16>; - clock-mult = <1>; - }; - periph_clk: periph-clk { - compatible = "fixed-factor-clock"; - clocks = <&occ_periph>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - can_clk: can-clk { - compatible = "fixed-factor-clock"; - clocks = <&occ_periph>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - spi_clk: spi-clk { - compatible = "fixed-factor-clock"; - clocks = <&occ_periph>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - uart_clk: uart-clk { - compatible = "fixed-factor-clock"; - clocks = <&occ_periph>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - i2c_clk: i2c-clk { - compatible = "fixed-factor-clock"; - clocks = <&occ_periph>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - clock-output-names = "i2c_clk"; - }; - timer_clk: timer-clk { - compatible = "fixed-factor-clock"; - clocks = <&occ_periph>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - clock-output-names = "timer_clk"; - }; - gpio_clk: gpio-clk { - compatible = "fixed-factor-clock"; - clocks = <&occ_periph>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - clock-output-names = "gpio_clk"; - }; - emmc_sys_clk: emmc-sys-clk { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_PER>; - #clock-cells = <0>; - clock-div = <10>; - clock-mult = <1>; - clock-output-names = "emmc_sys_clk"; - }; - ccf_ctrl_clk: ccf-ctrl-clk { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_PER>; - #clock-cells = <0>; - clock-div = <4>; - clock-mult = <1>; - clock-output-names = "ccf_ctrl_clk"; - }; - occ_mjpeg_core: occ-mjpeg-core { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_PER>; - #clock-cells = <0>; - clock-div = <2>; - clock-mult = <1>; - clock-output-names = "occ_mjpeg_core"; - }; - hsm_clk: hsm-clk { /* gate ClkRstGen_hsm */ - compatible = "fixed-factor-clock"; - clocks = <&occ_mjpeg_core>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - clock-output-names = "hsm_clk"; - }; - mjpeg_core_clk: mjpeg-core-clk { /* gate ClkRstGen_mjpeg_gen */ - compatible = "fixed-factor-clock"; - clocks = <&occ_mjpeg_core>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - clock-output-names = "mjpeg_core_clk"; - }; - fcmu_a_clk: fcmu-a-clk { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_PER>; - #clock-cells = <0>; - clock-div = <20>; - clock-mult = <1>; - clock-output-names = "fcmu_a_clk"; - }; - occ_pci_sys: occ-pci-sys { - compatible = "fixed-factor-clock"; - clocks = <&olb EQ5C_PLL_PER>; - #clock-cells = <0>; - clock-div = <8>; - clock-mult = <1>; - clock-output-names = "occ_pci_sys"; - }; - pclk: pclk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <250000000>; /* 250MHz */ - }; - tsu_clk: tsu-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <125000000>; /* 125MHz */ - }; -}; diff --git a/arch/mips/boot/dts/mobileye/eyeq5.dtsi b/arch/mips/boot/dts/mobileye/eyeq5.dtsi index 0708771c193d06..5d73e8320b8efc 100644 --- a/arch/mips/boot/dts/mobileye/eyeq5.dtsi +++ b/arch/mips/boot/dts/mobileye/eyeq5.dtsi @@ -5,7 +5,7 @@ #include -#include "eyeq5-clocks.dtsi" +#include / { #address-cells = <2>; @@ -17,7 +17,7 @@ cpu@0 { device_type = "cpu"; compatible = "img,i6500"; reg = <0>; - clocks = <&core0_clk>; + clocks = <&olb EQ5C_CPU_CORE0>; }; }; @@ -64,6 +64,24 @@ cpu_intc: interrupt-controller { #interrupt-cells = <1>; }; + xtal: xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <30000000>; + }; + + pclk: pclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <250000000>; /* 250MHz */ + }; + + tsu_clk: tsu-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; /* 125MHz */ + }; + soc: soc { #address-cells = <2>; #size-cells = <2>; @@ -76,7 +94,7 @@ uart0: serial@800000 { reg-io-width = <4>; interrupt-parent = <&gic>; interrupts = ; - clocks = <&uart_clk>, <&occ_periph>; + clocks = <&olb EQ5C_PER_UART>, <&olb EQ5C_PER_OCC>; clock-names = "uartclk", "apb_pclk"; resets = <&olb 0 10>; pinctrl-names = "default"; @@ -89,7 +107,7 @@ uart1: serial@900000 { reg-io-width = <4>; interrupt-parent = <&gic>; interrupts = ; - clocks = <&uart_clk>, <&occ_periph>; + clocks = <&olb EQ5C_PER_UART>, <&olb EQ5C_PER_OCC>; clock-names = "uartclk", "apb_pclk"; resets = <&olb 0 11>; pinctrl-names = "default"; @@ -102,7 +120,7 @@ uart2: serial@a00000 { reg-io-width = <4>; interrupt-parent = <&gic>; interrupts = ; - clocks = <&uart_clk>, <&occ_periph>; + clocks = <&olb EQ5C_PER_UART>, <&olb EQ5C_PER_OCC>; clock-names = "uartclk", "apb_pclk"; resets = <&olb 0 12>; pinctrl-names = "default"; @@ -135,7 +153,7 @@ gic: interrupt-controller@140000 { timer { compatible = "mti,gic-timer"; interrupts = ; - clocks = <&core0_clk>; + clocks = <&olb EQ5C_CPU_CORE0>; }; }; }; diff --git a/arch/mips/boot/dts/mobileye/eyeq6h-epm6.dts b/arch/mips/boot/dts/mobileye/eyeq6h-epm6.dts index ebc0d363fbf826..59a3e95050eb9c 100644 --- a/arch/mips/boot/dts/mobileye/eyeq6h-epm6.dts +++ b/arch/mips/boot/dts/mobileye/eyeq6h-epm6.dts @@ -8,7 +8,7 @@ #include "eyeq6h.dtsi" / { - compatible = "mobileye,eyeq6-epm6", "mobileye,eyeq6"; + compatible = "mobileye,eyeq6h-epm6", "mobileye,eyeq6h"; model = "Mobile EyeQ6H MP6 Evaluation board"; chosen { diff --git a/arch/mips/boot/dts/mobileye/eyeq6h-fixed-clocks.dtsi b/arch/mips/boot/dts/mobileye/eyeq6h-fixed-clocks.dtsi deleted file mode 100644 index 5fa99e06fde7e8..00000000000000 --- a/arch/mips/boot/dts/mobileye/eyeq6h-fixed-clocks.dtsi +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -/* - * Copyright 2023 Mobileye Vision Technologies Ltd. - */ - -#include - -/ { - xtal: clock-30000000 { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <30000000>; - }; - - pll_west: clock-2000000000-west { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <2000000000>; - }; - - pll_cpu: clock-2000000000-cpu { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <2000000000>; - }; - - /* pll-cpu derivatives */ - occ_cpu: clock-2000000000-occ-cpu { - compatible = "fixed-factor-clock"; - clocks = <&pll_cpu>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - - /* pll-west derivatives */ - occ_periph_w: clock-200000000 { - compatible = "fixed-factor-clock"; - clocks = <&pll_west>; - #clock-cells = <0>; - clock-div = <10>; - clock-mult = <1>; - }; - uart_clk: clock-200000000-uart { - compatible = "fixed-factor-clock"; - clocks = <&occ_periph_w>; - #clock-cells = <0>; - clock-div = <1>; - clock-mult = <1>; - }; - -}; diff --git a/arch/mips/boot/dts/mobileye/eyeq6h.dtsi b/arch/mips/boot/dts/mobileye/eyeq6h.dtsi index 1db3c3cda2e395..4a1a43f351d396 100644 --- a/arch/mips/boot/dts/mobileye/eyeq6h.dtsi +++ b/arch/mips/boot/dts/mobileye/eyeq6h.dtsi @@ -5,7 +5,7 @@ #include -#include "eyeq6h-fixed-clocks.dtsi" +#include / { #address-cells = <2>; @@ -17,7 +17,7 @@ cpu@0 { device_type = "cpu"; compatible = "img,i6500"; reg = <0>; - clocks = <&occ_cpu>; + clocks = <&olb_central EQ6HC_CENTRAL_CPU_OCC>; }; }; @@ -32,19 +32,42 @@ cpu_intc: interrupt-controller { #interrupt-cells = <1>; }; + xtal: clock-30000000 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <30000000>; + }; + soc: soc { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <2>; ranges; + olb_acc: system-controller@d2003000 { + compatible = "mobileye,eyeq6h-acc-olb", "syscon"; + reg = <0x0 0xd2003000 0x0 0x1000>; + #reset-cells = <1>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + + olb_central: system-controller@d3100000 { + compatible = "mobileye,eyeq6h-central-olb", "syscon"; + reg = <0x0 0xd3100000 0x0 0x1000>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + uart0: serial@d3331000 { compatible = "arm,pl011", "arm,primecell"; reg = <0 0xd3331000 0x0 0x1000>; reg-io-width = <4>; interrupt-parent = <&gic>; interrupts = ; - clocks = <&occ_periph_w>, <&occ_periph_w>; + clocks = <&olb_west EQ6HC_WEST_PER_UART>, <&olb_west EQ6HC_WEST_PER_OCC>; clock-names = "uartclk", "apb_pclk"; }; @@ -56,6 +79,15 @@ pinctrl_west: pinctrl@d3337000 { pinctrl-single,function-mask = <0xffff>; }; + olb_west: system-controller@d3338000 { + compatible = "mobileye,eyeq6h-west-olb", "syscon"; + reg = <0x0 0xd3338000 0x0 0x1000>; + #reset-cells = <1>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + pinctrl_east: pinctrl@d3357000 { compatible = "pinctrl-single"; reg = <0x0 0xd3357000 0x0 0xb0>; @@ -64,6 +96,23 @@ pinctrl_east: pinctrl@d3357000 { pinctrl-single,function-mask = <0xffff>; }; + olb_east: system-controller@d3358000 { + compatible = "mobileye,eyeq6h-east-olb", "syscon"; + reg = <0x0 0xd3358000 0x0 0x1000>; + #reset-cells = <1>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + + olb_south: system-controller@d8013000 { + compatible = "mobileye,eyeq6h-south-olb", "syscon"; + reg = <0x0 0xd8013000 0x0 0x1000>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + pinctrl_south: pinctrl@d8014000 { compatible = "pinctrl-single"; reg = <0x0 0xd8014000 0x0 0xf8>; @@ -72,6 +121,22 @@ pinctrl_south: pinctrl@d8014000 { pinctrl-single,function-mask = <0xffff>; }; + olb_ddr0: system-controller@e4080000 { + compatible = "mobileye,eyeq6h-ddr0-olb", "syscon"; + reg = <0x0 0xe4080000 0x0 0x1000>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + + olb_ddr1: system-controller@e4081000 { + compatible = "mobileye,eyeq6h-ddr1-olb", "syscon"; + reg = <0x0 0xe4081000 0x0 0x1000>; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "ref"; + }; + gic: interrupt-controller@f0920000 { compatible = "mti,gic"; reg = <0x0 0xf0920000 0x0 0x20000>; @@ -89,7 +154,7 @@ gic: interrupt-controller@f0920000 { timer { compatible = "mti,gic-timer"; interrupts = ; - clocks = <&occ_cpu>; + clocks = <&olb_central EQ6HC_CENTRAL_CPU_OCC>; }; }; }; diff --git a/arch/mips/boot/dts/realtek/cameo-rtl9302c-2x-rtl8224-2xge.dts b/arch/mips/boot/dts/realtek/cameo-rtl9302c-2x-rtl8224-2xge.dts index 77d2566545f269..6789bf3740446e 100644 --- a/arch/mips/boot/dts/realtek/cameo-rtl9302c-2x-rtl8224-2xge.dts +++ b/arch/mips/boot/dts/realtek/cameo-rtl9302c-2x-rtl8224-2xge.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /dts-v1/; -#include "rtl930x.dtsi" +#include "rtl9302c.dtsi" #include #include diff --git a/arch/mips/boot/dts/realtek/rtl9302c.dtsi b/arch/mips/boot/dts/realtek/rtl9302c.dtsi new file mode 100644 index 00000000000000..8690433af4981b --- /dev/null +++ b/arch/mips/boot/dts/realtek/rtl9302c.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause + +#include "rtl930x.dtsi" + +&switch0 { + compatible = "realtek,rtl9302c-switch", "syscon", "simple-mfd"; +}; + +&i2c0 { + compatible = "realtek,rtl9302c-i2c", "realtek,rtl9301-i2c"; +}; + +&i2c1 { + compatible = "realtek,rtl9302c-i2c", "realtek,rtl9301-i2c"; +}; diff --git a/arch/mips/boot/dts/realtek/rtl930x.dtsi b/arch/mips/boot/dts/realtek/rtl930x.dtsi index f271940f82bea1..17577457d15986 100644 --- a/arch/mips/boot/dts/realtek/rtl930x.dtsi +++ b/arch/mips/boot/dts/realtek/rtl930x.dtsi @@ -29,9 +29,40 @@ lx_clk: clock-175mhz { #clock-cells = <0>; clock-frequency = <175000000>; }; + + switch0: switch@1b000000 { + compatible = "realtek,rtl9301-switch", "syscon", "simple-mfd"; + reg = <0x1b000000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + + reboot@c { + compatible = "syscon-reboot"; + reg = <0x0c 0x4>; + value = <0x01>; + }; + + i2c0: i2c@36c { + compatible = "realtek,rtl9301-i2c"; + reg = <0x36c 0x14>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@388 { + compatible = "realtek,rtl9301-i2c"; + reg = <0x388 0x14>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; }; &soc { + ranges = <0x0 0x18000000 0x20000>; + intc: interrupt-controller@3000 { compatible = "realtek,rtl9300-intc", "realtek,rtl-intc"; reg = <0x3000 0x18>, <0x3018 0x18>; @@ -59,6 +90,17 @@ timer0: timer@3200 { interrupts = <7>, <8>, <9>, <10>, <11>; clocks = <&lx_clk>; }; + + snand: spi@1a400 { + compatible = "realtek,rtl9301-snand"; + reg = <0x1a400 0x44>; + interrupt-parent = <&intc>; + interrupts = <19>; + clocks = <&lx_clk>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; &uart0 { diff --git a/arch/mips/configs/loongson3_defconfig b/arch/mips/configs/loongson3_defconfig index 78f4987520664b..98844b457b7f4c 100644 --- a/arch/mips/configs/loongson3_defconfig +++ b/arch/mips/configs/loongson3_defconfig @@ -5,6 +5,8 @@ CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y CONFIG_PREEMPT=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y @@ -22,18 +24,16 @@ CONFIG_CGROUP_CPUACCT=y CONFIG_NAMESPACES=y CONFIG_USER_NS=y CONFIG_SCHED_AUTOGROUP=y -CONFIG_SYSFS_DEPRECATED=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y -CONFIG_BPF_SYSCALL=y CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y +CONFIG_KEXEC=y CONFIG_MACH_LOONGSON64=y CONFIG_CPU_HAS_MSA=y CONFIG_NUMA=y CONFIG_NR_CPUS=16 CONFIG_HZ_256=y -CONFIG_KEXEC=y CONFIG_MIPS32_O32=y CONFIG_MIPS32_N32=y CONFIG_VIRTUALIZATION=y @@ -47,15 +47,12 @@ CONFIG_MODVERSIONS=y CONFIG_PARTITION_ADVANCED=y CONFIG_MQ_IOSCHED_DEADLINE=m CONFIG_IOSCHED_BFQ=y -CONFIG_BFQ_GROUP_IOSCHED=y CONFIG_BINFMT_MISC=m CONFIG_KSM=y CONFIG_NET=y CONFIG_PACKET=y -CONFIG_UNIX=y CONFIG_XFRM_USER=y CONFIG_NET_KEY=y -CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y @@ -106,7 +103,6 @@ CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_TTL=m CONFIG_IP_NF_RAW=m CONFIG_IP_NF_SECURITY=m -CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_NF_TABLES_IPV6=y @@ -128,7 +124,6 @@ CONFIG_L2TP=m CONFIG_BRIDGE=m CONFIG_VSOCKETS=m CONFIG_VIRTIO_VSOCKETS=m -CONFIG_BPF_JIT=y CONFIG_CFG80211=m CONFIG_CFG80211_WEXT=y CONFIG_MAC80211=m @@ -146,6 +141,7 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_VIRTIO_BLK=y +CONFIG_BLK_DEV_NVME=m CONFIG_RAID_ATTRS=m CONFIG_BLK_DEV_SD=y CONFIG_BLK_DEV_SR=y @@ -167,12 +163,10 @@ CONFIG_SATA_AHCI=y CONFIG_PATA_ATIIXP=y CONFIG_MD=y CONFIG_BLK_DEV_MD=m -CONFIG_MD_LINEAR=m CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID10=m CONFIG_MD_RAID456=m -CONFIG_MD_MULTIPATH=m CONFIG_BLK_DEV_DM=m CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m @@ -196,7 +190,6 @@ CONFIG_VIRTIO_NET=m # CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_VENDOR_ATHEROS is not set # CONFIG_NET_VENDOR_BROADCOM is not set -# CONFIG_NET_VENDOR_BROCADE is not set # CONFIG_NET_VENDOR_CHELSIO is not set # CONFIG_NET_VENDOR_CIRRUS is not set # CONFIG_NET_VENDOR_CISCO is not set @@ -216,6 +209,7 @@ CONFIG_IXGBE=y # CONFIG_NET_VENDOR_NVIDIA is not set # CONFIG_NET_VENDOR_OKI is not set # CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_BROCADE is not set # CONFIG_NET_VENDOR_RDC is not set CONFIG_8139CP=m CONFIG_8139TOO=m @@ -242,7 +236,6 @@ CONFIG_PPPOL2TP=m CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m CONFIG_ATH9K=m -CONFIG_HOSTAP=m CONFIG_INPUT_SPARSEKMAP=y CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_MOUSEDEV_PSAUX=y @@ -276,23 +269,20 @@ CONFIG_MEDIA_SUPPORT=m CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_DRM=y +CONFIG_DRM_RADEON=m CONFIG_DRM_AMDGPU=m CONFIG_DRM_AMDGPU_SI=y CONFIG_DRM_AMDGPU_CIK=y CONFIG_DRM_AMDGPU_USERPTR=y CONFIG_DRM_AMD_ACP=y -CONFIG_DRM_AMD_DC=y CONFIG_DRM_AMD_DC_SI=y CONFIG_DRM_AST=m -CONFIG_DRM_RADEON=m CONFIG_DRM_QXL=y CONFIG_DRM_VIRTIO_GPU=y CONFIG_FB=y CONFIG_FB_RADEON=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_LCD_PLATFORM=m -# CONFIG_VGA_CONSOLE is not set -CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_LOGO=y CONFIG_SOUND=y @@ -350,13 +340,11 @@ CONFIG_EXT3_FS_SECURITY=y CONFIG_XFS_FS=y CONFIG_XFS_POSIX_ACL=y CONFIG_QUOTA=y -# CONFIG_PRINT_QUOTA_WARNING is not set CONFIG_QFMT_V1=m CONFIG_QFMT_V2=m CONFIG_AUTOFS_FS=y CONFIG_FUSE_FS=m CONFIG_VIRTIO_FS=m -CONFIG_NETFS_SUPPORT=m CONFIG_FSCACHE=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y @@ -391,23 +379,21 @@ CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_PATH=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_SECURITY_SELINUX_DISABLE=y CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_SERPENT=m CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_DEFLATE=m CONFIG_PRINTK_TIME=y CONFIG_STRIP_ASM_SYMS=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_FS=y # CONFIG_SCHED_DEBUG is not set -# CONFIG_DEBUG_PREEMPT is not set CONFIG_FUNCTION_TRACER=y CONFIG_FTRACE_SYSCALLS=y CONFIG_CMDLINE_BOOL=y diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 935585d8bb26ce..8e98c07964371b 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -275,7 +275,6 @@ CONFIG_DM9102=m CONFIG_ULI526X=m CONFIG_PCMCIA_XIRCOM=m CONFIG_DL2K=m -CONFIG_SUNDANCE=m CONFIG_PCMCIA_FMVJ18X=m CONFIG_E100=m CONFIG_E1000=m diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index 7ba67a0d6c97b2..684569b2ecd6b5 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -13,3 +13,4 @@ generic-y += parport.h generic-y += qrwlock.h generic-y += qspinlock.h generic-y += user.h +generic-y += text-patching.h diff --git a/arch/mips/include/asm/hugetlb.h b/arch/mips/include/asm/hugetlb.h index fd69c88085542e..d0a86ce83de915 100644 --- a/arch/mips/include/asm/hugetlb.h +++ b/arch/mips/include/asm/hugetlb.h @@ -17,12 +17,7 @@ static inline int prepare_hugepage_range(struct file *file, unsigned long len) { unsigned long task_size = STACK_TOP; - struct hstate *h = hstate_file(file); - if (len & ~huge_page_mask(h)) - return -EINVAL; - if (addr & ~huge_page_mask(h)) - return -EINVAL; if (len > task_size) return -ENOMEM; if (task_size - len < addr) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index af58d6ae06b85e..0bddb568af7c1c 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -125,11 +125,6 @@ static inline unsigned long isa_virt_to_bus(volatile void *address) return virt_to_phys(address); } -/* - * Change "struct page" to physical address. - */ -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) - void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size, unsigned long prot_val); void iounmap(const volatile void __iomem *addr); diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 1e782275850a36..23ce951f445bb0 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -326,7 +326,9 @@ GCR_CX_ACCESSOR_RW(32, 0x018, other) /* GCR_Cx_RESET_BASE - Configure where powered up cores will fetch from */ GCR_CX_ACCESSOR_RW(32, 0x020, reset_base) +GCR_CX_ACCESSOR_RW(64, 0x020, reset64_base) #define CM_GCR_Cx_RESET_BASE_BEVEXCBASE GENMASK(31, 12) +#define CM_GCR_Cx_RESET64_BASE_BEVEXCBASE GENMASK_ULL(47, 12) #define CM_GCR_Cx_RESET_BASE_MODE BIT(1) /* GCR_Cx_ID - Identify the current core */ diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index 4609cb0326cf31..bc3e3484c1bfa9 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -14,12 +14,7 @@ #include #include -/* - * PAGE_SHIFT determines the page size - */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) +#include /* * This is used for calculating the real page sizes diff --git a/arch/mips/include/asm/pgtable-64.h b/arch/mips/include/asm/pgtable-64.h index 401c1d9e4409a1..6e854bb11f37de 100644 --- a/arch/mips/include/asm/pgtable-64.h +++ b/arch/mips/include/asm/pgtable-64.h @@ -317,7 +317,9 @@ static inline pmd_t *pud_pgtable(pud_t pud) */ extern void pgd_init(void *addr); extern void pud_init(void *addr); +#define pud_init pud_init extern void pmd_init(void *addr); +#define pmd_init pmd_init /* * Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index a4374b4cb88fd8..d6ccd534402133 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -97,7 +97,7 @@ do { \ } \ } while (0) #else -# define __sanitize_fcr31(next) +# define __sanitize_fcr31(next) do { (void) (next); } while (0) #endif /* diff --git a/arch/mips/include/asm/vdso/vsyscall.h b/arch/mips/include/asm/vdso/vsyscall.h index 47168aaf1eff05..a4582870aaea49 100644 --- a/arch/mips/include/asm/vdso/vsyscall.h +++ b/arch/mips/include/asm/vdso/vsyscall.h @@ -4,7 +4,6 @@ #ifndef __ASSEMBLY__ -#include #include extern struct vdso_data *vdso_data; diff --git a/arch/mips/include/asm/vga.h b/arch/mips/include/asm/vga.h index 0136e03666989a..491c2b5aeb8162 100644 --- a/arch/mips/include/asm/vga.h +++ b/arch/mips/include/asm/vga.h @@ -47,10 +47,6 @@ static inline void scr_memsetw(u16 *s, u16 v, unsigned int count) memset16(s, cpu_to_le16(v), count / 2); } -#define scr_memcpyw(d, s, c) memcpy(d, s, c) -#define scr_memmovew(d, s, c) memmove(d, s, c) -#define VT_BUF_HAVE_MEMCPYW -#define VT_BUF_HAVE_MEMMOVEW #define VT_BUF_HAVE_MEMSETW #endif /* _ASM_VGA_H */ diff --git a/arch/mips/include/uapi/asm/mman.h b/arch/mips/include/uapi/asm/mman.h index 9c48d9a21aa01f..b700dae28c482d 100644 --- a/arch/mips/include/uapi/asm/mman.h +++ b/arch/mips/include/uapi/asm/mman.h @@ -105,6 +105,9 @@ #define MADV_COLLAPSE 25 /* Synchronous hugepage collapse */ +#define MADV_GUARD_INSTALL 102 /* fatal signal on access to range */ +#define MADV_GUARD_REMOVE 103 /* unguard range */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h index 8ab7582291abf2..d118d47315801b 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -157,6 +157,8 @@ #define SCM_DEVMEM_DMABUF SO_DEVMEM_DMABUF #define SO_DEVMEM_DONTNEED 80 +#define SCM_TS_OPT_ID 81 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index b825ed4476c702..e3ff6179c99f9b 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -59,6 +59,7 @@ #endif .endm + __HEAD #ifndef CONFIG_NO_EXCEPT_FILL /* * Reserved space for exception handlers. diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 8eba5a1ed664c4..8f0a0001540c7b 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -66,24 +66,23 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "BogoMIPS\t\t: %u.%02u\n", cpu_data[n].udelay_val / (500000/HZ), (cpu_data[n].udelay_val / (5000/HZ)) % 100); - seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no"); + seq_printf(m, "wait instruction\t: %s\n", str_yes_no(cpu_wait)); seq_printf(m, "microsecond timers\t: %s\n", - cpu_has_counter ? "yes" : "no"); + str_yes_no(cpu_has_counter)); seq_printf(m, "tlb_entries\t\t: %d\n", cpu_data[n].tlbsize); seq_printf(m, "extra interrupt vector\t: %s\n", - cpu_has_divec ? "yes" : "no"); - seq_printf(m, "hardware watchpoint\t: %s", - cpu_has_watch ? "yes, " : "no\n"); + str_yes_no(cpu_has_divec)); + seq_printf(m, "hardware watchpoint\t: %s", str_yes_no(cpu_has_watch)); if (cpu_has_watch) { - seq_printf(m, "count: %d, address/irw mask: [", + seq_printf(m, ", count: %d, address/irw mask: [", cpu_data[n].watch_reg_count); for (i = 0; i < cpu_data[n].watch_reg_count; i++) seq_printf(m, "%s0x%04x", i ? ", " : "", cpu_data[n].watch_reg_masks[i]); - seq_puts(m, "]\n"); + seq_puts(m, "]"); } - seq_puts(m, "isa\t\t\t:"); + seq_puts(m, "\nisa\t\t\t:"); if (cpu_has_mips_1) seq_puts(m, " mips1"); if (cpu_has_mips_2) @@ -155,7 +154,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) if (cpu_has_mmips) { seq_printf(m, "micromips kernel\t: %s\n", - (read_c0_config3() & MIPS_CONF3_ISA_OE) ? "yes" : "no"); + str_yes_no(read_c0_config3() & MIPS_CONF3_ISA_OE)); } seq_puts(m, "Options implemented\t:"); diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index 6062e6fa589a87..4fd6da0a06c372 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -41,7 +41,7 @@ char *mips_get_machine_name(void) void __init __dt_setup_arch(void *bph) { - if (!early_init_dt_scan(bph)) + if (!early_init_dt_scan(bph, __pa(bph))) return; mips_set_machine_name(of_flat_dt_get_machine_name()); diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c index 7eeeaf1ff95d26..cda7983e7c18d4 100644 --- a/arch/mips/kernel/relocate.c +++ b/arch/mips/kernel/relocate.c @@ -337,7 +337,7 @@ void *__init relocate_kernel(void) #if defined(CONFIG_USE_OF) /* Deal with the device tree */ fdt = plat_get_fdt(); - early_init_dt_scan(fdt); + early_init_dt_scan(fdt, __pa(fdt)); if (boot_command_line[0]) { /* Boot command line was passed in device tree */ strscpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c index 395622c373258f..82c8f9b9573cc3 100644 --- a/arch/mips/kernel/smp-cps.c +++ b/arch/mips/kernel/smp-cps.c @@ -37,7 +37,7 @@ enum label_id { UASM_L_LA(_not_nmi) static DECLARE_BITMAP(core_power, NR_CPUS); -static uint32_t core_entry_reg; +static u64 core_entry_reg; static phys_addr_t cps_vec_pa; struct core_boot_config *mips_cps_core_bootcfg; @@ -94,6 +94,20 @@ static void __init *mips_cps_build_core_entry(void *addr) return p; } +static bool __init check_64bit_reset(void) +{ + bool cx_64bit_reset = false; + + mips_cm_lock_other(0, 0, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL); + write_gcr_co_reset64_base(CM_GCR_Cx_RESET64_BASE_BEVEXCBASE); + if ((read_gcr_co_reset64_base() & CM_GCR_Cx_RESET64_BASE_BEVEXCBASE) == + CM_GCR_Cx_RESET64_BASE_BEVEXCBASE) + cx_64bit_reset = true; + mips_cm_unlock_other(); + + return cx_64bit_reset; +} + static int __init allocate_cps_vecs(void) { /* Try to allocate in KSEG1 first */ @@ -105,11 +119,23 @@ static int __init allocate_cps_vecs(void) CM_GCR_Cx_RESET_BASE_BEVEXCBASE; if (!cps_vec_pa && mips_cm_is64) { - cps_vec_pa = memblock_phys_alloc_range(BEV_VEC_SIZE, BEV_VEC_ALIGN, - 0x0, SZ_4G - 1); - if (cps_vec_pa) - core_entry_reg = (cps_vec_pa & CM_GCR_Cx_RESET_BASE_BEVEXCBASE) | + phys_addr_t end; + + if (check_64bit_reset()) { + pr_info("VP Local Reset Exception Base support 47 bits address\n"); + end = MEMBLOCK_ALLOC_ANYWHERE; + } else { + end = SZ_4G - 1; + } + cps_vec_pa = memblock_phys_alloc_range(BEV_VEC_SIZE, BEV_VEC_ALIGN, 0, end); + if (cps_vec_pa) { + if (check_64bit_reset()) + core_entry_reg = (cps_vec_pa & CM_GCR_Cx_RESET64_BASE_BEVEXCBASE) | + CM_GCR_Cx_RESET_BASE_MODE; + else + core_entry_reg = (cps_vec_pa & CM_GCR_Cx_RESET_BASE_BEVEXCBASE) | CM_GCR_Cx_RESET_BASE_MODE; + } } if (!cps_vec_pa) @@ -308,7 +334,10 @@ static void boot_core(unsigned int core, unsigned int vpe_id) mips_cm_lock_other(0, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL); /* Set its reset vector */ - write_gcr_co_reset_base(core_entry_reg); + if (mips_cm_is64) + write_gcr_co_reset64_base(core_entry_reg); + else + write_gcr_co_reset_base(core_entry_reg); /* Ensure its coherency is disabled */ write_gcr_co_coherence(0); @@ -411,7 +440,10 @@ static int cps_boot_secondary(int cpu, struct task_struct *idle) if (cpu_has_vp) { mips_cm_lock_other(0, core, vpe_id, CM_GCR_Cx_OTHER_BLOCK_LOCAL); - write_gcr_co_reset_base(core_entry_reg); + if (mips_cm_is64) + write_gcr_co_reset64_base(core_entry_reg); + else + write_gcr_co_reset_base(core_entry_reg); mips_cm_unlock_other(); } diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl index 953f5b7dc723f6..0b9b7e25b69ad5 100644 --- a/arch/mips/kernel/syscalls/syscall_n32.tbl +++ b/arch/mips/kernel/syscalls/syscall_n32.tbl @@ -401,3 +401,7 @@ 460 n32 lsm_set_self_attr sys_lsm_set_self_attr 461 n32 lsm_list_modules sys_lsm_list_modules 462 n32 mseal sys_mseal +463 n32 setxattrat sys_setxattrat +464 n32 getxattrat sys_getxattrat +465 n32 listxattrat sys_listxattrat +466 n32 removexattrat sys_removexattrat diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl index 1464c6be6eb3c7..c844cd5cda620b 100644 --- a/arch/mips/kernel/syscalls/syscall_n64.tbl +++ b/arch/mips/kernel/syscalls/syscall_n64.tbl @@ -377,3 +377,7 @@ 460 n64 lsm_set_self_attr sys_lsm_set_self_attr 461 n64 lsm_list_modules sys_lsm_list_modules 462 n64 mseal sys_mseal +463 n64 setxattrat sys_setxattrat +464 n64 getxattrat sys_getxattrat +465 n64 listxattrat sys_listxattrat +466 n64 removexattrat sys_removexattrat diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl index 2439a2491cffe3..349b8aad1159f4 100644 --- a/arch/mips/kernel/syscalls/syscall_o32.tbl +++ b/arch/mips/kernel/syscalls/syscall_o32.tbl @@ -450,3 +450,7 @@ 460 o32 lsm_set_self_attr sys_lsm_set_self_attr 461 o32 lsm_list_modules sys_lsm_list_modules 462 o32 mseal sys_mseal +463 o32 setxattrat sys_setxattrat +464 o32 getxattrat sys_getxattrat +465 o32 listxattrat sys_listxattrat +466 o32 removexattrat sys_removexattrat diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index dda36fa26307e2..4c8e3c0aa21047 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 9ff55cb80a6457..2b708fac8d2c17 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -61,6 +61,7 @@ SECTIONS /* read-only */ _text = .; /* Text and read-only data */ .text : { + HEAD_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXT diff --git a/arch/mips/kvm/mmu.c b/arch/mips/kvm/mmu.c index c17157e700c034..d2c3b6b41f1817 100644 --- a/arch/mips/kvm/mmu.c +++ b/arch/mips/kvm/mmu.c @@ -484,8 +484,6 @@ static int _kvm_mips_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, struct kvm *kvm = vcpu->kvm; gfn_t gfn = gpa >> PAGE_SHIFT; pte_t *ptep; - kvm_pfn_t pfn = 0; /* silence bogus GCC warning */ - bool pfn_valid = false; int ret = 0; spin_lock(&kvm->mmu_lock); @@ -498,12 +496,9 @@ static int _kvm_mips_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, } /* Track access to pages marked old */ - if (!pte_young(*ptep)) { + if (!pte_young(*ptep)) set_pte(ptep, pte_mkyoung(*ptep)); - pfn = pte_pfn(*ptep); - pfn_valid = true; - /* call kvm_set_pfn_accessed() after unlock */ - } + if (write_fault && !pte_dirty(*ptep)) { if (!pte_write(*ptep)) { ret = -EFAULT; @@ -512,9 +507,7 @@ static int _kvm_mips_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, /* Track dirtying of writeable pages */ set_pte(ptep, pte_mkdirty(*ptep)); - pfn = pte_pfn(*ptep); mark_page_dirty(kvm, gfn); - kvm_set_pfn_dirty(pfn); } if (out_entry) @@ -524,8 +517,6 @@ static int _kvm_mips_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, out: spin_unlock(&kvm->mmu_lock); - if (pfn_valid) - kvm_set_pfn_accessed(pfn); return ret; } @@ -566,6 +557,7 @@ static int kvm_mips_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool writeable; unsigned long prot_bits; unsigned long mmu_seq; + struct page *page; /* Try the fast path to handle old / clean pages */ srcu_idx = srcu_read_lock(&kvm->srcu); @@ -587,7 +579,7 @@ static int kvm_mips_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, mmu_seq = kvm->mmu_invalidate_seq; /* * Ensure the read of mmu_invalidate_seq isn't reordered with PTE reads - * in gfn_to_pfn_prot() (which calls get_user_pages()), so that we don't + * in kvm_faultin_pfn() (which calls get_user_pages()), so that we don't * risk the page we get a reference to getting unmapped before we have a * chance to grab the mmu_lock without mmu_invalidate_retry() noticing. * @@ -599,7 +591,7 @@ static int kvm_mips_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, smp_rmb(); /* Slow path - ask KVM core whether we can access this GPA */ - pfn = gfn_to_pfn_prot(kvm, gfn, write_fault, &writeable); + pfn = kvm_faultin_pfn(vcpu, gfn, write_fault, &writeable, &page); if (is_error_noslot_pfn(pfn)) { err = -EFAULT; goto out; @@ -611,10 +603,10 @@ static int kvm_mips_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, /* * This can happen when mappings are changed asynchronously, but * also synchronously if a COW is triggered by - * gfn_to_pfn_prot(). + * kvm_faultin_pfn(). */ spin_unlock(&kvm->mmu_lock); - kvm_release_pfn_clean(pfn); + kvm_release_page_unused(page); goto retry; } @@ -628,7 +620,6 @@ static int kvm_mips_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, if (write_fault) { prot_bits |= __WRITEABLE; mark_page_dirty(kvm, gfn); - kvm_set_pfn_dirty(pfn); } } entry = pfn_pte(pfn, __pgprot(prot_bits)); @@ -642,9 +633,8 @@ static int kvm_mips_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, if (out_buddy) *out_buddy = *ptep_buddy(ptep); + kvm_release_faultin_page(kvm, page, false, writeable); spin_unlock(&kvm->mmu_lock); - kvm_release_pfn_clean(pfn); - kvm_set_pfn_accessed(pfn); out: srcu_read_unlock(&kvm->srcu, srcu_idx); return err; diff --git a/arch/mips/pci/pci-xtalk-bridge.c b/arch/mips/pci/pci-xtalk-bridge.c index 45ddbaa6c12379..dae856fb3e5bb2 100644 --- a/arch/mips/pci/pci-xtalk-bridge.c +++ b/arch/mips/pci/pci-xtalk-bridge.c @@ -749,7 +749,7 @@ static void bridge_remove(struct platform_device *pdev) static struct platform_driver bridge_driver = { .probe = bridge_probe, - .remove_new = bridge_remove, + .remove = bridge_remove, .driver = { .name = "xtalk-bridge", } diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig index 08c012a2591f9d..910d059ec70b77 100644 --- a/arch/mips/ralink/Kconfig +++ b/arch/mips/ralink/Kconfig @@ -1,13 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 if RALINK -config CLKEVT_RT3352 - bool - depends on SOC_RT305X || SOC_MT7620 - default y - select TIMER_OF - select CLKSRC_MMIO - config RALINK_ILL_ACC bool depends on SOC_RT305X diff --git a/arch/mips/ralink/Makefile b/arch/mips/ralink/Makefile index 26fabbdea1f1e3..0c109eae195359 100644 --- a/arch/mips/ralink/Makefile +++ b/arch/mips/ralink/Makefile @@ -10,8 +10,6 @@ ifndef CONFIG_MIPS_GIC obj-y += clk.o timer.o endif -obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o - obj-$(CONFIG_RALINK_ILL_ACC) += ill_acc.o obj-$(CONFIG_IRQ_INTC) += irq.o diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c deleted file mode 100644 index 269d4877d120e8..00000000000000 --- a/arch/mips/ralink/cevt-rt3352.c +++ /dev/null @@ -1,153 +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) 2013 by John Crispin - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SYSTICK_FREQ (50 * 1000) - -#define SYSTICK_CONFIG 0x00 -#define SYSTICK_COMPARE 0x04 -#define SYSTICK_COUNT 0x08 - -/* route systick irq to mips irq 7 instead of the r4k-timer */ -#define CFG_EXT_STK_EN 0x2 -/* enable the counter */ -#define CFG_CNT_EN 0x1 - -struct systick_device { - void __iomem *membase; - struct clock_event_device dev; - int irq_requested; - int freq_scale; -}; - -static int systick_set_oneshot(struct clock_event_device *evt); -static int systick_shutdown(struct clock_event_device *evt); - -static int systick_next_event(unsigned long delta, - struct clock_event_device *evt) -{ - struct systick_device *sdev; - u32 count; - - sdev = container_of(evt, struct systick_device, dev); - count = ioread32(sdev->membase + SYSTICK_COUNT); - count = (count + delta) % SYSTICK_FREQ; - iowrite32(count, sdev->membase + SYSTICK_COMPARE); - - return 0; -} - -static void systick_event_handler(struct clock_event_device *dev) -{ - /* noting to do here */ -} - -static irqreturn_t systick_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *dev = (struct clock_event_device *) dev_id; - - dev->event_handler(dev); - - return IRQ_HANDLED; -} - -static struct systick_device systick = { - .dev = { - /* - * cevt-r4k uses 300, make sure systick - * gets used if available - */ - .rating = 310, - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = systick_next_event, - .set_state_shutdown = systick_shutdown, - .set_state_oneshot = systick_set_oneshot, - .event_handler = systick_event_handler, - }, -}; - -static int systick_shutdown(struct clock_event_device *evt) -{ - struct systick_device *sdev; - - sdev = container_of(evt, struct systick_device, dev); - - if (sdev->irq_requested) - free_irq(systick.dev.irq, &systick.dev); - sdev->irq_requested = 0; - iowrite32(0, systick.membase + SYSTICK_CONFIG); - - return 0; -} - -static int systick_set_oneshot(struct clock_event_device *evt) -{ - const char *name = systick.dev.name; - struct systick_device *sdev; - int irq = systick.dev.irq; - - sdev = container_of(evt, struct systick_device, dev); - - if (!sdev->irq_requested) { - if (request_irq(irq, systick_interrupt, - IRQF_PERCPU | IRQF_TIMER, name, &systick.dev)) - pr_err("Failed to request irq %d (%s)\n", irq, name); - } - sdev->irq_requested = 1; - iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, - systick.membase + SYSTICK_CONFIG); - - return 0; -} - -static int __init ralink_systick_init(struct device_node *np) -{ - int ret; - - systick.membase = of_iomap(np, 0); - if (!systick.membase) - return -ENXIO; - - systick.dev.name = np->name; - clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60); - systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev); - systick.dev.max_delta_ticks = 0x7fff; - systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); - systick.dev.min_delta_ticks = 0x3; - systick.dev.irq = irq_of_parse_and_map(np, 0); - if (!systick.dev.irq) { - pr_err("%pOFn: request_irq failed", np); - return -EINVAL; - } - - ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, - SYSTICK_FREQ, 301, 16, - clocksource_mmio_readl_up); - if (ret) - return ret; - - clockevents_register_device(&systick.dev); - - pr_info("%pOFn: running - mult: %d, shift: %d\n", - np, systick.dev.mult, systick.dev.shift); - - return 0; -} - -TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); diff --git a/arch/mips/sgi-ip22/ip22-gio.c b/arch/mips/sgi-ip22/ip22-gio.c index d20eec742bfaab..5893ea4e382cae 100644 --- a/arch/mips/sgi-ip22/ip22-gio.c +++ b/arch/mips/sgi-ip22/ip22-gio.c @@ -165,9 +165,8 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { struct gio_device *gio_dev = to_gio_device(dev); - int len = snprintf(buf, PAGE_SIZE, "gio:%x\n", gio_dev->id.id); - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; + return sysfs_emit(buf, "gio:%x\n", gio_dev->id.id); } static DEVICE_ATTR_RO(modalias); @@ -177,7 +176,7 @@ static ssize_t name_show(struct device *dev, struct gio_device *giodev; giodev = to_gio_device(dev); - return sprintf(buf, "%s", giodev->name); + return sysfs_emit(buf, "%s\n", giodev->name); } static DEVICE_ATTR_RO(name); @@ -187,7 +186,7 @@ static ssize_t id_show(struct device *dev, struct gio_device *giodev; giodev = to_gio_device(dev); - return sprintf(buf, "%x", giodev->id.id); + return sysfs_emit(buf, "%x\n", giodev->id.id); } static DEVICE_ATTR_RO(id); diff --git a/arch/mips/vdso/genvdso.c b/arch/mips/vdso/genvdso.c index 09e30eb4be8605..d47412ea6e6736 100644 --- a/arch/mips/vdso/genvdso.c +++ b/arch/mips/vdso/genvdso.c @@ -270,7 +270,7 @@ int main(int argc, char **argv) /* Write out the stripped VDSO data. */ fprintf(out_file, - "static unsigned char vdso_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t", + "static unsigned char vdso_image_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t", vdso_size); for (i = 0; i < vdso_size; i++) { if (!(i % 10)) @@ -286,7 +286,7 @@ int main(int argc, char **argv) fprintf(out_file, "struct mips_vdso_image vdso_image%s%s = {\n", (vdso_name[0]) ? "_" : "", vdso_name); - fprintf(out_file, "\t.data = vdso_data,\n"); + fprintf(out_file, "\t.data = vdso_image_data,\n"); fprintf(out_file, "\t.size = PAGE_ALIGN(%zu),\n", vdso_size); fprintf(out_file, "\t.mapping = {\n"); fprintf(out_file, "\t\t.name = \"[vdso]\",\n"); diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild index 0d09829ed14454..28004301c236f7 100644 --- a/arch/nios2/include/asm/Kbuild +++ b/arch/nios2/include/asm/Kbuild @@ -7,3 +7,4 @@ generic-y += kvm_para.h generic-y += mcs_spinlock.h generic-y += spinlock.h generic-y += user.h +generic-y += text-patching.h diff --git a/arch/nios2/include/asm/io.h b/arch/nios2/include/asm/io.h index 746853ac7d8d38..36e3550673b34b 100644 --- a/arch/nios2/include/asm/io.h +++ b/arch/nios2/include/asm/io.h @@ -28,9 +28,6 @@ void __iomem *ioremap(unsigned long physaddr, unsigned long size); void iounmap(void __iomem *addr); -/* Pages to physical address... */ -#define page_to_phys(page) virt_to_phys(page_to_virt(page)) - /* Macros used for converting between virtual and physical mappings. */ #define phys_to_virt(vaddr) \ ((void *)((unsigned long)(vaddr) | CONFIG_NIOS2_KERNEL_REGION_BASE)) diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h index 0722f88e63cc7c..2897ec1b74f618 100644 --- a/arch/nios2/include/asm/page.h +++ b/arch/nios2/include/asm/page.h @@ -18,12 +18,7 @@ #include #include -/* - * PAGE_SHIFT determines the page size - */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE - 1)) +#include /* * PAGE_OFFSET -- the first address of the first page of memory. diff --git a/arch/nios2/kernel/prom.c b/arch/nios2/kernel/prom.c index 9a8393e6b4a85e..db049249766fc2 100644 --- a/arch/nios2/kernel/prom.c +++ b/arch/nios2/kernel/prom.c @@ -27,7 +27,7 @@ void __init early_init_devtree(void *params) if (be32_to_cpup((__be32 *)CONFIG_NIOS2_DTB_PHYS_ADDR) == OF_DT_HEADER) { params = (void *)CONFIG_NIOS2_DTB_PHYS_ADDR; - early_init_dt_scan(params); + early_init_dt_scan(params, __pa(params)); return; } #endif @@ -37,5 +37,5 @@ void __init early_init_devtree(void *params) params = (void *)__dtb_start; #endif - early_init_dt_scan(params); + early_init_dt_scan(params, __pa(params)); } diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig index 69c0258700b28a..3279ef457c573a 100644 --- a/arch/openrisc/Kconfig +++ b/arch/openrisc/Kconfig @@ -65,6 +65,9 @@ config STACKTRACE_SUPPORT config LOCKDEP_SUPPORT def_bool y +config FIX_EARLYCON_MEM + def_bool y + menu "Processor type and features" choice diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild index cef49d60d74c0f..2b1a6b00cdac0a 100644 --- a/arch/openrisc/include/asm/Kbuild +++ b/arch/openrisc/include/asm/Kbuild @@ -9,3 +9,4 @@ generic-y += spinlock.h generic-y += qrwlock_types.h generic-y += qrwlock.h generic-y += user.h +generic-y += text-patching.h diff --git a/arch/openrisc/include/asm/fixmap.h b/arch/openrisc/include/asm/fixmap.h index ecdb98a5839f7c..aaa6a26a3e9215 100644 --- a/arch/openrisc/include/asm/fixmap.h +++ b/arch/openrisc/include/asm/fixmap.h @@ -26,29 +26,18 @@ #include #include -/* - * On OpenRISC we use these special fixed_addresses for doing ioremap - * early in the boot process before memory initialization is complete. - * This is used, in particular, by the early serial console code. - * - * It's not really 'fixmap', per se, but fits loosely into the same - * paradigm. - */ enum fixed_addresses { - /* - * FIX_IOREMAP entries are useful for mapping physical address - * space before ioremap() is useable, e.g. really early in boot - * before kmalloc() is working. - */ -#define FIX_N_IOREMAPS 32 - FIX_IOREMAP_BEGIN, - FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1, + FIX_EARLYCON_MEM_BASE, __end_of_fixed_addresses }; #define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) /* FIXADDR_BOTTOM might be a better name here... */ #define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) +#define FIXMAP_PAGE_IO PAGE_KERNEL_NOCACHE + +extern void __set_fixmap(enum fixed_addresses idx, + phys_addr_t phys, pgprot_t flags); #include diff --git a/arch/openrisc/include/asm/page.h b/arch/openrisc/include/asm/page.h index 1d5913f67c312f..c589e96035e15e 100644 --- a/arch/openrisc/include/asm/page.h +++ b/arch/openrisc/include/asm/page.h @@ -15,16 +15,7 @@ #ifndef __ASM_OPENRISC_PAGE_H #define __ASM_OPENRISC_PAGE_H - -/* PAGE_SHIFT determines the page size */ - -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#ifdef __ASSEMBLY__ -#define PAGE_SIZE (1 << PAGE_SHIFT) -#else -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#endif -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #define PAGE_OFFSET 0xc0000000 #define KERNELBASE PAGE_OFFSET @@ -80,8 +71,6 @@ static inline unsigned long virt_to_pfn(const void *kaddr) #define virt_to_page(addr) \ (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)) -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) - #define virt_addr_valid(kaddr) (pfn_valid(virt_to_pfn(kaddr))) #endif /* __ASSEMBLY__ */ diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index 440711d7bf40e3..ce6f2b08a35edc 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -239,6 +239,8 @@ handler: ;\ /* =====================================================[ exceptions] === */ + __REF + /* ---[ 0x100: RESET exception ]----------------------------------------- */ EXCEPTION_ENTRY(_tng_kernel_start) diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S index 439e00f81e5dde..bd760066f1cdc4 100644 --- a/arch/openrisc/kernel/head.S +++ b/arch/openrisc/kernel/head.S @@ -26,15 +26,15 @@ #include #include -#define tophys(rd,rs) \ - l.movhi rd,hi(-KERNELBASE) ;\ +#define tophys(rd,rs) \ + l.movhi rd,hi(-KERNELBASE) ;\ l.add rd,rd,rs -#define CLEAR_GPR(gpr) \ +#define CLEAR_GPR(gpr) \ l.movhi gpr,0x0 -#define LOAD_SYMBOL_2_GPR(gpr,symbol) \ - l.movhi gpr,hi(symbol) ;\ +#define LOAD_SYMBOL_2_GPR(gpr,symbol) \ + l.movhi gpr,hi(symbol) ;\ l.ori gpr,gpr,lo(symbol) @@ -326,21 +326,21 @@ l.addi r1,r1,-(INT_FRAME_SIZE) ;\ /* r1 is KSP, r30 is __pa(KSP) */ ;\ tophys (r30,r1) ;\ - l.sw PT_GPR12(r30),r12 ;\ + l.sw PT_GPR12(r30),r12 ;\ l.mfspr r12,r0,SPR_EPCR_BASE ;\ l.sw PT_PC(r30),r12 ;\ l.mfspr r12,r0,SPR_ESR_BASE ;\ l.sw PT_SR(r30),r12 ;\ /* save r31 */ ;\ EXCEPTION_T_LOAD_GPR30(r12) ;\ - l.sw PT_GPR30(r30),r12 ;\ + l.sw PT_GPR30(r30),r12 ;\ /* save r10 as was prior to exception */ ;\ EXCEPTION_T_LOAD_GPR10(r12) ;\ - l.sw PT_GPR10(r30),r12 ;\ - /* save PT_SP as was prior to exception */ ;\ + l.sw PT_GPR10(r30),r12 ;\ + /* save PT_SP as was prior to exception */ ;\ EXCEPTION_T_LOAD_SP(r12) ;\ l.sw PT_SP(r30),r12 ;\ - l.sw PT_GPR13(r30),r13 ;\ + l.sw PT_GPR13(r30),r13 ;\ /* --> */ ;\ /* save exception r4, set r4 = EA */ ;\ l.sw PT_GPR4(r30),r4 ;\ @@ -357,6 +357,8 @@ /* =====================================================[ exceptions] === */ + __HEAD + /* ---[ 0x100: RESET exception ]----------------------------------------- */ .org 0x100 /* Jump to .init code at _start which lives in the .head section @@ -394,7 +396,7 @@ _dispatch_do_ipage_fault: .org 0x500 EXCEPTION_HANDLE(_timer_handler) -/* ---[ 0x600: Alignment exception ]-------------------------------------- */ +/* ---[ 0x600: Alignment exception ]------------------------------------- */ .org 0x600 EXCEPTION_HANDLE(_alignment_handler) @@ -424,7 +426,7 @@ _dispatch_do_ipage_fault: .org 0xc00 EXCEPTION_HANDLE(_sys_call_handler) -/* ---[ 0xd00: Floating point exception ]--------------------------------- */ +/* ---[ 0xd00: Floating point exception ]-------------------------------- */ .org 0xd00 EXCEPTION_HANDLE(_fpe_trap_handler) @@ -506,10 +508,10 @@ _dispatch_do_ipage_fault: /* .text*/ -/* This early stuff belongs in HEAD, but some of the functions below definitely +/* This early stuff belongs in the .init.text section, but some of the functions below definitely * don't... */ - __HEAD + __INIT .global _start _start: /* Init r0 to zero as per spec */ @@ -816,7 +818,7 @@ secondary_start: #endif -/* ========================================[ cache ]=== */ +/* ==========================================================[ cache ]=== */ /* alignment here so we don't change memory offsets with * memory controller defined diff --git a/arch/openrisc/kernel/prom.c b/arch/openrisc/kernel/prom.c index 19e6008bf114c6..e424e9bd12a793 100644 --- a/arch/openrisc/kernel/prom.c +++ b/arch/openrisc/kernel/prom.c @@ -22,6 +22,6 @@ void __init early_init_devtree(void *params) { - early_init_dt_scan(params); + early_init_dt_scan(params, __pa(params)); memblock_allow_resize(); } diff --git a/arch/openrisc/kernel/vmlinux.lds.S b/arch/openrisc/kernel/vmlinux.lds.S index bc13060478373d..049bff45f61265 100644 --- a/arch/openrisc/kernel/vmlinux.lds.S +++ b/arch/openrisc/kernel/vmlinux.lds.S @@ -50,6 +50,7 @@ SECTIONS .text : AT(ADDR(.text) - LOAD_OFFSET) { _stext = .; + HEAD_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXT @@ -83,8 +84,6 @@ SECTIONS . = ALIGN(PAGE_SIZE); __init_begin = .; - HEAD_TEXT_SECTION - /* Page aligned */ INIT_TEXT_SECTION(PAGE_SIZE) diff --git a/arch/openrisc/mm/init.c b/arch/openrisc/mm/init.c index 1dcd78c8f0e99b..d0cb1a0126f95d 100644 --- a/arch/openrisc/mm/init.c +++ b/arch/openrisc/mm/init.c @@ -207,6 +207,43 @@ void __init mem_init(void) return; } +static int __init map_page(unsigned long va, phys_addr_t pa, pgprot_t prot) +{ + p4d_t *p4d; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + p4d = p4d_offset(pgd_offset_k(va), va); + pud = pud_offset(p4d, va); + pmd = pmd_offset(pud, va); + pte = pte_alloc_kernel(pmd, va); + + if (pte == NULL) + return -ENOMEM; + + if (pgprot_val(prot)) + set_pte_at(&init_mm, va, pte, pfn_pte(pa >> PAGE_SHIFT, prot)); + else + pte_clear(&init_mm, va, pte); + + local_flush_tlb_page(NULL, va); + return 0; +} + +void __init __set_fixmap(enum fixed_addresses idx, + phys_addr_t phys, pgprot_t prot) +{ + unsigned long address = __fix_to_virt(idx); + + if (idx >= __end_of_fixed_addresses) { + BUG(); + return; + } + + map_page(address, phys, prot); +} + static const pgprot_t protection_map[16] = { [VM_NONE] = PAGE_NONE, [VM_READ] = PAGE_READONLY_X, diff --git a/arch/parisc/include/asm/hugetlb.h b/arch/parisc/include/asm/hugetlb.h index 72daacc472a0a3..5b3a5429f71b31 100644 --- a/arch/parisc/include/asm/hugetlb.h +++ b/arch/parisc/include/asm/hugetlb.h @@ -12,21 +12,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); -/* - * If the arch doesn't supply something else, assume that hugepage - * size aligned regions are ok without further preparation. - */ -#define __HAVE_ARCH_PREPARE_HUGEPAGE_RANGE -static inline int prepare_hugepage_range(struct file *file, - unsigned long addr, unsigned long len) -{ - if (len & ~HPAGE_MASK) - return -EINVAL; - if (addr & ~HPAGE_MASK) - return -EINVAL; - return 0; -} - #define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h index 4bea2e95798f02..7fd44709263077 100644 --- a/arch/parisc/include/asm/page.h +++ b/arch/parisc/include/asm/page.h @@ -4,9 +4,7 @@ #include -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA @@ -168,7 +166,6 @@ extern int npmem_ranges; #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #include diff --git a/arch/parisc/include/asm/patch.h b/arch/parisc/include/asm/patch.h deleted file mode 100644 index 400d84c6e504d8..00000000000000 --- a/arch/parisc/include/asm/patch.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _PARISC_KERNEL_PATCH_H -#define _PARISC_KERNEL_PATCH_H - -/* stop machine and patch kernel text */ -void patch_text(void *addr, unsigned int insn); -void patch_text_multiple(void *addr, u32 *insn, unsigned int len); - -/* patch kernel text with machine already stopped (e.g. in kgdb) */ -void __patch_text(void *addr, u32 insn); -void __patch_text_multiple(void *addr, u32 *insn, unsigned int len); - -#endif diff --git a/arch/parisc/include/asm/text-patching.h b/arch/parisc/include/asm/text-patching.h new file mode 100644 index 00000000000000..400d84c6e504d8 --- /dev/null +++ b/arch/parisc/include/asm/text-patching.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _PARISC_KERNEL_PATCH_H +#define _PARISC_KERNEL_PATCH_H + +/* stop machine and patch kernel text */ +void patch_text(void *addr, unsigned int insn); +void patch_text_multiple(void *addr, u32 *insn, unsigned int len); + +/* patch kernel text with machine already stopped (e.g. in kgdb) */ +void __patch_text(void *addr, u32 insn); +void __patch_text_multiple(void *addr, u32 *insn, unsigned int len); + +#endif diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h index 68c44f99bc931b..b6a709506987e0 100644 --- a/arch/parisc/include/uapi/asm/mman.h +++ b/arch/parisc/include/uapi/asm/mman.h @@ -75,6 +75,9 @@ #define MADV_HWPOISON 100 /* poison a page for testing */ #define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */ +#define MADV_GUARD_INSTALL 102 /* fatal signal on access to range */ +#define MADV_GUARD_REMOVE 103 /* unguard range */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index 38fc0b188e0842..d268d69bfcd27e 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -138,6 +138,8 @@ #define SCM_DEVMEM_DMABUF SO_DEVMEM_DMABUF #define SO_DEVMEM_DONTNEED 80 +#define SCM_TS_OPT_ID 0x404C + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c index c91f9c2e61ed25..10fd5b3e63e757 100644 --- a/arch/parisc/kernel/ftrace.c +++ b/arch/parisc/kernel/ftrace.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #define __hot __section(".text.hot") @@ -87,7 +87,7 @@ int ftrace_enable_ftrace_graph_caller(void) int ftrace_disable_ftrace_graph_caller(void) { - static_key_enable(&ftrace_graph_enable.key); + static_key_disable(&ftrace_graph_enable.key); return 0; } #endif diff --git a/arch/parisc/kernel/jump_label.c b/arch/parisc/kernel/jump_label.c index e253b134500d13..ea51f15bf0e647 100644 --- a/arch/parisc/kernel/jump_label.c +++ b/arch/parisc/kernel/jump_label.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include static inline int reassemble_17(int as17) { diff --git a/arch/parisc/kernel/kgdb.c b/arch/parisc/kernel/kgdb.c index b16fa9bac5f44c..fee81f877525ee 100644 --- a/arch/parisc/kernel/kgdb.c +++ b/arch/parisc/kernel/kgdb.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include const struct kgdb_arch arch_kgdb_ops = { diff --git a/arch/parisc/kernel/kprobes.c b/arch/parisc/kernel/kprobes.c index 6e0b86652f30d6..9255adba67a36f 100644 --- a/arch/parisc/kernel/kprobes.c +++ b/arch/parisc/kernel/kprobes.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); diff --git a/arch/parisc/kernel/patch.c b/arch/parisc/kernel/patch.c index e59574f65e641a..35dd764b871e0b 100644 --- a/arch/parisc/kernel/patch.c +++ b/arch/parisc/kernel/patch.c @@ -13,7 +13,7 @@ #include #include -#include +#include struct patch { void *addr; diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl index 66dc406b12e448..d9fc94c869657f 100644 --- a/arch/parisc/kernel/syscalls/syscall.tbl +++ b/arch/parisc/kernel/syscalls/syscall.tbl @@ -461,3 +461,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c index 4818f3db84a5c5..59d8c15d81bd09 100644 --- a/arch/parisc/lib/checksum.c +++ b/arch/parisc/lib/checksum.c @@ -25,15 +25,6 @@ : "=r"(_t) \ : "r"(_r), "0"(_t)); -static inline unsigned short from32to16(unsigned int x) -{ - /* 32 bits --> 16 bits + carry */ - x = (x & 0xffff) + (x >> 16); - /* 16 bits + carry --> 16 bits including carry */ - x = (x & 0xffff) + (x >> 16); - return (unsigned short)x; -} - static inline unsigned int do_csum(const unsigned char * buff, int len) { int odd, count; @@ -85,7 +76,7 @@ static inline unsigned int do_csum(const unsigned char * buff, int len) } if (len & 1) result += le16_to_cpu(*buff); - result = from32to16(result); + result = csum_from32to16(result); if (odd) result = swab16(result); out: @@ -102,7 +93,7 @@ __wsum csum_partial(const void *buff, int len, __wsum sum) { unsigned int result = do_csum(buff, len); addc(result, sum); - return (__force __wsum)from32to16(result); + return (__force __wsum)csum_from32to16(result); } EXPORT_SYMBOL(csum_partial); diff --git a/arch/parisc/mm/hugetlbpage.c b/arch/parisc/mm/hugetlbpage.c index aa664f7ddb6398..e9d18cf25b792b 100644 --- a/arch/parisc/mm/hugetlbpage.c +++ b/arch/parisc/mm/hugetlbpage.c @@ -21,27 +21,6 @@ #include -unsigned long -hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - - if (len & ~huge_page_mask(h)) - return -EINVAL; - if (len > TASK_SIZE) - return -ENOMEM; - - if (flags & MAP_FIXED) - if (prepare_hugepage_range(file, addr, len)) - return -EINVAL; - - if (addr) - addr = ALIGN(addr, huge_page_size(h)); - - /* we need to make sure the colouring is OK */ - return arch_get_unmapped_area(file, addr, len, pgoff, flags, 0); -} pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma, diff --git a/arch/powerpc/Kbuild b/arch/powerpc/Kbuild index 571f260b08423c..b010ccb071b6d6 100644 --- a/arch/powerpc/Kbuild +++ b/arch/powerpc/Kbuild @@ -19,4 +19,4 @@ obj-$(CONFIG_KEXEC_CORE) += kexec/ obj-$(CONFIG_KEXEC_FILE) += purgatory/ # for cleaning -subdir- += boot +subdir- += boot tools diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1a2ff0276365b4..a0ce777f97063b 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -234,6 +234,8 @@ config PPC select HAVE_DEBUG_STACKOVERFLOW select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE_WITH_ARGS if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32 + select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS if PPC_FTRACE_OUT_OF_LINE || (PPC32 && ARCH_USING_PATCHABLE_FUNCTION_ENTRY) + select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS if HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS select HAVE_DYNAMIC_FTRACE_WITH_REGS if ARCH_USING_PATCHABLE_FUNCTION_ENTRY || MPROFILE_KERNEL || PPC32 select HAVE_EBPF_JIT select HAVE_EFFICIENT_UNALIGNED_ACCESS @@ -243,7 +245,7 @@ config PPC select HAVE_FUNCTION_DESCRIPTORS if PPC64_ELF_ABI_V1 select HAVE_FUNCTION_ERROR_INJECTION select HAVE_FUNCTION_GRAPH_TRACER - select HAVE_FUNCTION_TRACER if PPC64 || (PPC32 && CC_IS_GCC) + select HAVE_FUNCTION_TRACER if !COMPILE_TEST && (PPC64 || (PPC32 && CC_IS_GCC)) select HAVE_GCC_PLUGINS if GCC_VERSION >= 50200 # plugin support on gcc <= 5.1 is buggy on PPC select HAVE_GENERIC_VDSO select HAVE_HARDLOCKUP_DETECTOR_ARCH if PPC_BOOK3S_64 && SMP @@ -273,10 +275,12 @@ config PPC select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE select HAVE_RSEQ + select HAVE_SAMPLE_FTRACE_DIRECT if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + select HAVE_SAMPLE_FTRACE_DIRECT_MULTI if HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS select HAVE_SETUP_PER_CPU_AREA if PPC64 select HAVE_SOFTIRQ_ON_OWN_STACK - select HAVE_STACKPROTECTOR if PPC32 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r2) - select HAVE_STACKPROTECTOR if PPC64 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r13) + select HAVE_STACKPROTECTOR if PPC32 && $(cc-option,$(m32-flag) -mstack-protector-guard=tls -mstack-protector-guard-reg=r2 -mstack-protector-guard-offset=0) + select HAVE_STACKPROTECTOR if PPC64 && $(cc-option,$(m64-flag) -mstack-protector-guard=tls -mstack-protector-guard-reg=r13 -mstack-protector-guard-offset=0) select HAVE_STATIC_CALL if PPC32 select HAVE_SYSCALL_TRACEPOINTS select HAVE_VIRT_CPU_ACCOUNTING @@ -569,6 +573,22 @@ config ARCH_USING_PATCHABLE_FUNCTION_ENTRY def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh $(CC) -mlittle-endian) if PPC64 && CPU_LITTLE_ENDIAN def_bool $(success,$(srctree)/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh $(CC) -mbig-endian) if PPC64 && CPU_BIG_ENDIAN +config PPC_FTRACE_OUT_OF_LINE + def_bool PPC64 && ARCH_USING_PATCHABLE_FUNCTION_ENTRY + select ARCH_WANTS_PRE_LINK_VMLINUX + +config PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE + int "Number of ftrace out-of-line stubs to reserve within .text" + depends on PPC_FTRACE_OUT_OF_LINE + default 32768 + help + Number of stubs to reserve for use by ftrace. This space is + reserved within .text, and is distinct from any additional space + added at the end of .text before the final vmlinux link. Set to + zero to have stubs only be generated at the end of vmlinux (only + if the size of vmlinux is less than 32MB). Set to a higher value + if building vmlinux larger than 48MB. + config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && (PPC_PSERIES || \ @@ -1302,6 +1322,14 @@ config MODULES_SIZE endmenu +config PPC64_PROC_SYSTEMCFG + def_bool y + depends on PPC64 && PROC_FS + help + This option enables the presence of /proc/ppc64/systemcfg through + which the systemcfg page can be accessed. + This interface only exists for backwards-compatibility. + if PPC64 # This value must have zeroes in the bottom 60 bits otherwise lots will break config PAGE_OFFSET diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 0bbec4afc0d597..20d05605fa83ff 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -223,12 +223,6 @@ config PPC_EARLY_DEBUG_RTAS_CONSOLE help Select this to enable early debugging via the RTAS console. -config PPC_EARLY_DEBUG_MAPLE - bool "Maple real mode" - depends on PPC_MAPLE - help - Select this to enable early debugging for Maple. - config PPC_EARLY_DEBUG_PAS_REALMODE bool "PA Semi real mode" depends on PPC_PASEMI diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index bbfe4a1f06ef9d..f3804103c56ccf 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -62,14 +62,14 @@ KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o endif ifdef CONFIG_CPU_LITTLE_ENDIAN -KBUILD_CFLAGS += -mlittle-endian +KBUILD_CPPFLAGS += -mlittle-endian KBUILD_LDFLAGS += -EL LDEMULATION := lppc GNUTARGET := powerpcle MULTIPLEWORD := -mno-multiple KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-save-toc-indirect) else -KBUILD_CFLAGS += $(call cc-option,-mbig-endian) +KBUILD_CPPFLAGS += $(call cc-option,-mbig-endian) KBUILD_LDFLAGS += -EB LDEMULATION := ppc GNUTARGET := powerpc @@ -95,18 +95,11 @@ aflags-$(CONFIG_CPU_BIG_ENDIAN) += $(call cc-option,-mbig-endian) aflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -mlittle-endian ifeq ($(HAS_BIARCH),y) -KBUILD_CFLAGS += -m$(BITS) +KBUILD_CPPFLAGS += -m$(BITS) KBUILD_AFLAGS += -m$(BITS) KBUILD_LDFLAGS += -m elf$(BITS)$(LDEMULATION) endif -cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard=tls -ifdef CONFIG_PPC64 -cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard-reg=r13 -else -cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard-reg=r2 -endif - LDFLAGS_vmlinux-y := -Bstatic LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) += -z notext @@ -155,7 +148,15 @@ CC_FLAGS_NO_FPU := $(call cc-option,-msoft-float) ifdef CONFIG_FUNCTION_TRACER ifdef CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY +ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +CC_FLAGS_FTRACE := -fpatchable-function-entry=1 +else +ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS # PPC32 only +CC_FLAGS_FTRACE := -fpatchable-function-entry=3,1 +else CC_FLAGS_FTRACE := -fpatchable-function-entry=2 +endif +endif else CC_FLAGS_FTRACE := -pg ifdef CONFIG_MPROFILE_KERNEL @@ -175,7 +176,6 @@ KBUILD_CPPFLAGS += -I $(srctree)/arch/powerpc $(asinstr) KBUILD_AFLAGS += $(AFLAGS-y) KBUILD_CFLAGS += $(CC_FLAGS_NO_FPU) KBUILD_CFLAGS += $(CFLAGS-y) -CPP = $(CC) -E $(KBUILD_CFLAGS) CHECKFLAGS += -m$(BITS) -D__powerpc__ -D__powerpc$(BITS)__ ifdef CONFIG_CPU_BIG_ENDIAN @@ -359,7 +359,7 @@ define archhelp echo ' install - Install kernel using' echo ' (your) ~/bin/$(INSTALLKERNEL) or' echo ' (distribution) /sbin/$(INSTALLKERNEL) or' - echo ' install to $$(INSTALL_PATH) and run lilo' + echo ' install to $$(INSTALL_PATH)' echo ' *_defconfig - Select default config from arch/powerpc/configs' echo '' echo ' Targets with
embed a device tree blob inside the image' @@ -402,9 +402,13 @@ prepare: stack_protector_prepare PHONY += stack_protector_prepare stack_protector_prepare: prepare0 ifdef CONFIG_PPC64 - $(eval KBUILD_CFLAGS += -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' include/generated/asm-offsets.h)) + $(eval KBUILD_CFLAGS += -mstack-protector-guard=tls -mstack-protector-guard-reg=r13 \ + -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "PACA_CANARY") print $$3;}' \ + $(objtree)/include/generated/asm-offsets.h)) else - $(eval KBUILD_CFLAGS += -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' include/generated/asm-offsets.h)) + $(eval KBUILD_CFLAGS += -mstack-protector-guard=tls -mstack-protector-guard-reg=r2 \ + -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' \ + $(objtree)/include/generated/asm-offsets.h)) endif endif diff --git a/arch/powerpc/Makefile.postlink b/arch/powerpc/Makefile.postlink index ae5a4256b03d89..bb601be3617369 100644 --- a/arch/powerpc/Makefile.postlink +++ b/arch/powerpc/Makefile.postlink @@ -24,6 +24,9 @@ else $(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/relocs_check.sh "$(OBJDUMP)" "$(NM)" "$@" endif +quiet_cmd_ftrace_check = CHKFTRC $@ + cmd_ftrace_check = $(CONFIG_SHELL) $(srctree)/arch/powerpc/tools/ftrace_check.sh "$(NM)" "$@" + # `@true` prevents complaint when there is nothing to be done vmlinux: FORCE @@ -34,6 +37,11 @@ endif ifdef CONFIG_RELOCATABLE $(call if_changed,relocs_check) endif +ifdef CONFIG_FUNCTION_TRACER +ifndef CONFIG_PPC64_ELF_ABI_V1 + $(call cmd,ftrace_check) +endif +endif clean: rm -f .tmp_symbols.txt diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore index a4716d138cfc05..5a867f23fe7f71 100644 --- a/arch/powerpc/boot/.gitignore +++ b/arch/powerpc/boot/.gitignore @@ -30,7 +30,6 @@ zImage.coff zImage.epapr zImage.holly zImage.*lds -zImage.maple zImage.miboot zImage.pmac zImage.pseries diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index fa8518067d38ee..1ff6ad4f6cd277 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -276,7 +276,6 @@ quiet_cmd_wrap = WRAP $@ image-$(CONFIG_PPC_PSERIES) += zImage.pseries image-$(CONFIG_PPC_POWERNV) += zImage.pseries -image-$(CONFIG_PPC_MAPLE) += zImage.maple image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries image-$(CONFIG_PPC_PS3) += dtbImage.ps3 image-$(CONFIG_PPC_CHRP) += zImage.chrp @@ -444,7 +443,7 @@ $(obj)/zImage.initrd: $(addprefix $(obj)/, $(initrd-y)) clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \ zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \ zImage.miboot zImage.pmac zImage.pseries \ - zImage.maple simpleImage.* otheros.bld + simpleImage.* otheros.bld # clean up files cached by wrapper clean-kernel-base := vmlinux.strip vmlinux.bin diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index b1f5549a3c9c40..1db60fe13802db 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -271,11 +271,6 @@ pseries) fi make_space=n ;; -maple) - platformo="$object/of.o $object/epapr.o" - link_address='0x400000' - make_space=n - ;; pmac|chrp) platformo="$object/of.o $object/epapr.o" make_space=n @@ -517,7 +512,7 @@ fi # post-processing needed for some platforms case "$platform" in -pseries|chrp|maple) +pseries|chrp) $objbin/addnote "$ofile" ;; coff) diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig deleted file mode 100644 index c821a97f4a8995..00000000000000 --- a/arch/powerpc/configs/maple_defconfig +++ /dev/null @@ -1,111 +0,0 @@ -CONFIG_PPC64=y -CONFIG_SMP=y -CONFIG_NR_CPUS=4 -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -# CONFIG_COMPAT_BRK is not set -CONFIG_PROFILING=y -CONFIG_KPROBES=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_PARTITION_ADVANCED=y -CONFIG_MAC_PARTITION=y -# CONFIG_PPC_POWERNV is not set -# CONFIG_PPC_PSERIES is not set -# CONFIG_PPC_PMAC is not set -CONFIG_PPC_MAPLE=y -CONFIG_UDBG_RTAS_CONSOLE=y -CONFIG_GEN_RTC=y -CONFIG_KEXEC=y -CONFIG_IRQ_ALL_CPUS=y -CONFIG_PPC_4K_PAGES=y -CONFIG_PCI_MSI=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_IPV6 is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=8192 -# CONFIG_SCSI_PROC_FS is not set -CONFIG_BLK_DEV_SD=y -CONFIG_BLK_DEV_SR=y -CONFIG_CHR_DEV_SG=y -CONFIG_SCSI_IPR=y -CONFIG_ATA=y -CONFIG_PATA_AMD=y -CONFIG_ATA_GENERIC=y -CONFIG_NETDEVICES=y -CONFIG_AMD8111_ETH=y -CONFIG_TIGON3=y -CONFIG_E1000=y -CONFIG_USB_PEGASUS=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_HVC_RTAS=y -# CONFIG_HW_RANDOM is not set -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_AMD8111=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_HID_GYRATION=y -CONFIG_HID_PANTHERLORD=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SUNPLUS=y -CONFIG_USB=y -CONFIG_USB_MON=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_ROOT_HUB_TT=y -# CONFIG_USB_EHCI_HCD_PPC_OF is not set -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_UHCI_HCD=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_CYPRESS_M8=m -CONFIG_USB_SERIAL_GARMIN=m -CONFIG_USB_SERIAL_IPW=m -CONFIG_USB_SERIAL_KEYSPAN=y -CONFIG_USB_SERIAL_TI=m -CONFIG_EXT2_FS=y -CONFIG_EXT4_FS=y -CONFIG_FS_DAX=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_HUGETLBFS=y -CONFIG_CRAMFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_DEFAULT="utf-8" -CONFIG_NLS_UTF8=y -CONFIG_CRC_CCITT=y -CONFIG_CRC_T10DIF=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_KERNEL=y -CONFIG_DEBUG_STACK_USAGE=y -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_XMON=y -CONFIG_XMON_DEFAULT=y -CONFIG_BOOTX_TEXT=y -CONFIG_CRYPTO_ECB=m -CONFIG_CRYPTO_PCBC=m -# CONFIG_CRYPTO_HW is not set -CONFIG_PRINTK_TIME=y diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig index 57ded82c284095..e8b3f67bf3f56b 100644 --- a/arch/powerpc/configs/pmac32_defconfig +++ b/arch/powerpc/configs/pmac32_defconfig @@ -208,6 +208,7 @@ CONFIG_FB_ATY=y CONFIG_FB_ATY_CT=y CONFIG_FB_ATY_GX=y CONFIG_FB_3DFX=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index a5e3e7f97f4d72..f39c0d000c4386 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -44,7 +44,6 @@ CONFIG_PPC_SMLPAR=y CONFIG_IBMEBUS=y CONFIG_PAPR_SCM=m CONFIG_PPC_SVM=y -CONFIG_PPC_MAPLE=y CONFIG_PPC_PASEMI=y CONFIG_PPC_PASEMI_IOMMU=y CONFIG_PPC_PS3=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index c06344db0eb37b..ca0c90e9583790 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -435,7 +435,6 @@ CONFIG_DM9102=m CONFIG_ULI526X=m CONFIG_PCMCIA_XIRCOM=m CONFIG_DL2K=m -CONFIG_SUNDANCE=m CONFIG_S2IO=m CONFIG_FEC_MPC52xx=m CONFIG_GIANFAR=m @@ -717,6 +716,7 @@ CONFIG_FB_TRIDENT=m CONFIG_FB_SM501=m CONFIG_FB_IBM_GXT4500=y CONFIG_LCD_PLATFORM=m +CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_LOGO=y diff --git a/arch/powerpc/crypto/Kconfig b/arch/powerpc/crypto/Kconfig index 46a4c85e85e245..951a4372646115 100644 --- a/arch/powerpc/crypto/Kconfig +++ b/arch/powerpc/crypto/Kconfig @@ -107,12 +107,12 @@ config CRYPTO_AES_PPC_SPE config CRYPTO_AES_GCM_P10 tristate "Stitched AES/GCM acceleration support on P10 or later CPU (PPC)" - depends on BROKEN depends on PPC64 && CPU_LITTLE_ENDIAN && VSX select CRYPTO_LIB_AES select CRYPTO_ALGAPI select CRYPTO_AEAD select CRYPTO_SKCIPHER + select CRYPTO_SIMD help AEAD cipher: AES cipher algorithms (FIPS-197) GCM (Galois/Counter Mode) authenticated encryption mode (NIST SP800-38D) diff --git a/arch/powerpc/crypto/aes-gcm-p10-glue.c b/arch/powerpc/crypto/aes-gcm-p10-glue.c index f66ad56e765f04..f37b3d13fc5309 100644 --- a/arch/powerpc/crypto/aes-gcm-p10-glue.c +++ b/arch/powerpc/crypto/aes-gcm-p10-glue.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #define PPC_ALIGN 16 #define GCM_IV_SIZE 12 +#define RFC4106_NONCE_SIZE 4 MODULE_DESCRIPTION("PPC64le AES-GCM with Stitched implementation"); MODULE_AUTHOR("Danny Tsen base.tfm; struct p10_aes_gcm_ctx *ctx = crypto_tfm_ctx(tfm); @@ -210,7 +218,6 @@ static int p10_aes_gcm_crypt(struct aead_request *req, int enc) struct skcipher_walk walk; u8 *assocmem = NULL; u8 *assoc; - unsigned int assoclen = req->assoclen; unsigned int cryptlen = req->cryptlen; unsigned char ivbuf[AES_BLOCK_SIZE+PPC_ALIGN]; unsigned char *iv = PTR_ALIGN((void *)ivbuf, PPC_ALIGN); @@ -218,11 +225,12 @@ static int p10_aes_gcm_crypt(struct aead_request *req, int enc) unsigned long auth_tag_len = crypto_aead_authsize(__crypto_aead_cast(tfm)); u8 otag[16]; int total_processed = 0; + int nbytes; memset(databuf, 0, sizeof(databuf)); memset(hashbuf, 0, sizeof(hashbuf)); memset(ivbuf, 0, sizeof(ivbuf)); - memcpy(iv, req->iv, GCM_IV_SIZE); + memcpy(iv, riv, GCM_IV_SIZE); /* Linearize assoc, if not already linear */ if (req->src->length >= assoclen && req->src->length) { @@ -257,19 +265,25 @@ static int p10_aes_gcm_crypt(struct aead_request *req, int enc) if (ret) return ret; - while (walk.nbytes > 0 && ret == 0) { + while ((nbytes = walk.nbytes) > 0 && ret == 0) { + u8 *src = walk.src.virt.addr; + u8 *dst = walk.dst.virt.addr; + u8 buf[AES_BLOCK_SIZE]; + + if (unlikely(nbytes > 0 && nbytes < AES_BLOCK_SIZE)) + src = dst = memcpy(buf, src, nbytes); vsx_begin(); if (enc) - aes_p10_gcm_encrypt(walk.src.virt.addr, - walk.dst.virt.addr, - walk.nbytes, + aes_p10_gcm_encrypt(src, dst, nbytes, &ctx->enc_key, gctx->iv, hash->Htable); else - aes_p10_gcm_decrypt(walk.src.virt.addr, - walk.dst.virt.addr, - walk.nbytes, + aes_p10_gcm_decrypt(src, dst, nbytes, &ctx->enc_key, gctx->iv, hash->Htable); + + if (unlikely(nbytes > 0 && nbytes < AES_BLOCK_SIZE)) + memcpy(walk.dst.virt.addr, buf, nbytes); + vsx_end(); total_processed += walk.nbytes; @@ -281,6 +295,7 @@ static int p10_aes_gcm_crypt(struct aead_request *req, int enc) /* Finalize hash */ vsx_begin(); + gcm_update(gctx->iv, hash->Htable); finish_tag(gctx, hash, total_processed); vsx_end(); @@ -302,17 +317,63 @@ static int p10_aes_gcm_crypt(struct aead_request *req, int enc) return 0; } +static int rfc4106_setkey(struct crypto_aead *tfm, const u8 *inkey, + unsigned int keylen) +{ + struct p10_aes_gcm_ctx *ctx = crypto_aead_ctx(tfm); + int err; + + keylen -= RFC4106_NONCE_SIZE; + err = p10_aes_gcm_setkey(tfm, inkey, keylen); + if (err) + return err; + + memcpy(ctx->nonce, inkey + keylen, RFC4106_NONCE_SIZE); + return 0; +} + +static int rfc4106_setauthsize(struct crypto_aead *tfm, unsigned int authsize) +{ + return crypto_rfc4106_check_authsize(authsize); +} + +static int rfc4106_encrypt(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct p10_aes_gcm_ctx *ctx = crypto_aead_ctx(aead); + u8 iv[AES_BLOCK_SIZE]; + + memcpy(iv, ctx->nonce, RFC4106_NONCE_SIZE); + memcpy(iv + RFC4106_NONCE_SIZE, req->iv, GCM_RFC4106_IV_SIZE); + + return crypto_ipsec_check_assoclen(req->assoclen) ?: + p10_aes_gcm_crypt(req, iv, req->assoclen - GCM_RFC4106_IV_SIZE, 1); +} + +static int rfc4106_decrypt(struct aead_request *req) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct p10_aes_gcm_ctx *ctx = crypto_aead_ctx(aead); + u8 iv[AES_BLOCK_SIZE]; + + memcpy(iv, ctx->nonce, RFC4106_NONCE_SIZE); + memcpy(iv + RFC4106_NONCE_SIZE, req->iv, GCM_RFC4106_IV_SIZE); + + return crypto_ipsec_check_assoclen(req->assoclen) ?: + p10_aes_gcm_crypt(req, iv, req->assoclen - GCM_RFC4106_IV_SIZE, 0); +} + static int p10_aes_gcm_encrypt(struct aead_request *req) { - return p10_aes_gcm_crypt(req, 1); + return p10_aes_gcm_crypt(req, req->iv, req->assoclen, 1); } static int p10_aes_gcm_decrypt(struct aead_request *req) { - return p10_aes_gcm_crypt(req, 0); + return p10_aes_gcm_crypt(req, req->iv, req->assoclen, 0); } -static struct aead_alg gcm_aes_alg = { +static struct aead_alg gcm_aes_algs[] = {{ .ivsize = GCM_IV_SIZE, .maxauthsize = 16, @@ -321,23 +382,57 @@ static struct aead_alg gcm_aes_alg = { .encrypt = p10_aes_gcm_encrypt, .decrypt = p10_aes_gcm_decrypt, - .base.cra_name = "gcm(aes)", - .base.cra_driver_name = "aes_gcm_p10", + .base.cra_name = "__gcm(aes)", + .base.cra_driver_name = "__aes_gcm_p10", .base.cra_priority = 2100, .base.cra_blocksize = 1, - .base.cra_ctxsize = sizeof(struct p10_aes_gcm_ctx), + .base.cra_ctxsize = sizeof(struct p10_aes_gcm_ctx)+ + 4 * sizeof(u64[2]), .base.cra_module = THIS_MODULE, -}; + .base.cra_flags = CRYPTO_ALG_INTERNAL, +}, { + .ivsize = GCM_RFC4106_IV_SIZE, + .maxauthsize = 16, + .setkey = rfc4106_setkey, + .setauthsize = rfc4106_setauthsize, + .encrypt = rfc4106_encrypt, + .decrypt = rfc4106_decrypt, + + .base.cra_name = "__rfc4106(gcm(aes))", + .base.cra_driver_name = "__rfc4106_aes_gcm_p10", + .base.cra_priority = 2100, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct p10_aes_gcm_ctx) + + 4 * sizeof(u64[2]), + .base.cra_module = THIS_MODULE, + .base.cra_flags = CRYPTO_ALG_INTERNAL, +}}; + +static struct simd_aead_alg *p10_simd_aeads[ARRAY_SIZE(gcm_aes_algs)]; static int __init p10_init(void) { - return crypto_register_aead(&gcm_aes_alg); + int ret; + + if (!cpu_has_feature(CPU_FTR_ARCH_31)) + return 0; + + ret = simd_register_aeads_compat(gcm_aes_algs, + ARRAY_SIZE(gcm_aes_algs), + p10_simd_aeads); + if (ret) { + simd_unregister_aeads(gcm_aes_algs, ARRAY_SIZE(gcm_aes_algs), + p10_simd_aeads); + return ret; + } + return 0; } static void __exit p10_exit(void) { - crypto_unregister_aead(&gcm_aes_alg); + simd_unregister_aeads(gcm_aes_algs, ARRAY_SIZE(gcm_aes_algs), + p10_simd_aeads); } -module_cpu_feature_match(PPC_MODULE_FEATURE_P10, p10_init); +module_init(p10_init); module_exit(p10_exit); diff --git a/arch/powerpc/crypto/aes-gcm-p10.S b/arch/powerpc/crypto/aes-gcm-p10.S index a51f4b2653082e..89f50eef351210 100644 --- a/arch/powerpc/crypto/aes-gcm-p10.S +++ b/arch/powerpc/crypto/aes-gcm-p10.S @@ -1,42 +1,42 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ - # - # Accelerated AES-GCM stitched implementation for ppc64le. - # - # Copyright 2022- IBM Inc. All rights reserved - # - #=================================================================================== - # Written by Danny Tsen - # - # GHASH is based on the Karatsuba multiplication method. - # - # Xi xor X1 - # - # X1 * H^4 + X2 * H^3 + x3 * H^2 + X4 * H = - # (X1.h * H4.h + xX.l * H4.l + X1 * H4) + - # (X2.h * H3.h + X2.l * H3.l + X2 * H3) + - # (X3.h * H2.h + X3.l * H2.l + X3 * H2) + - # (X4.h * H.h + X4.l * H.l + X4 * H) - # - # Xi = v0 - # H Poly = v2 - # Hash keys = v3 - v14 - # ( H.l, H, H.h) - # ( H^2.l, H^2, H^2.h) - # ( H^3.l, H^3, H^3.h) - # ( H^4.l, H^4, H^4.h) - # - # v30 is IV - # v31 - counter 1 - # - # AES used, - # vs0 - vs14 for round keys - # v15, v16, v17, v18, v19, v20, v21, v22 for 8 blocks (encrypted) - # - # This implementation uses stitched AES-GCM approach to improve overall performance. - # AES is implemented with 8x blocks and GHASH is using 2 4x blocks. - # - # =================================================================================== - # +# +# Accelerated AES-GCM stitched implementation for ppc64le. +# +# Copyright 2024- IBM Inc. +# +#=================================================================================== +# Written by Danny Tsen +# +# GHASH is based on the Karatsuba multiplication method. +# +# Xi xor X1 +# +# X1 * H^4 + X2 * H^3 + x3 * H^2 + X4 * H = +# (X1.h * H4.h + xX.l * H4.l + X1 * H4) + +# (X2.h * H3.h + X2.l * H3.l + X2 * H3) + +# (X3.h * H2.h + X3.l * H2.l + X3 * H2) + +# (X4.h * H.h + X4.l * H.l + X4 * H) +# +# Xi = v0 +# H Poly = v2 +# Hash keys = v3 - v14 +# ( H.l, H, H.h) +# ( H^2.l, H^2, H^2.h) +# ( H^3.l, H^3, H^3.h) +# ( H^4.l, H^4, H^4.h) +# +# v30 is IV +# v31 - counter 1 +# +# AES used, +# vs0 - round key 0 +# v15, v16, v17, v18, v19, v20, v21, v22 for 8 blocks (encrypted) +# +# This implementation uses stitched AES-GCM approach to improve overall performance. +# AES is implemented with 8x blocks and GHASH is using 2 4x blocks. +# +# =================================================================================== +# #include #include @@ -44,483 +44,224 @@ .machine "any" .text - # 4x loops - # v15 - v18 - input states - # vs1 - vs9 - round keys - # -.macro Loop_aes_middle4x - xxlor 19+32, 1, 1 - xxlor 20+32, 2, 2 - xxlor 21+32, 3, 3 - xxlor 22+32, 4, 4 - - vcipher 15, 15, 19 - vcipher 16, 16, 19 - vcipher 17, 17, 19 - vcipher 18, 18, 19 - - vcipher 15, 15, 20 - vcipher 16, 16, 20 - vcipher 17, 17, 20 - vcipher 18, 18, 20 - - vcipher 15, 15, 21 - vcipher 16, 16, 21 - vcipher 17, 17, 21 - vcipher 18, 18, 21 - - vcipher 15, 15, 22 - vcipher 16, 16, 22 - vcipher 17, 17, 22 - vcipher 18, 18, 22 - - xxlor 19+32, 5, 5 - xxlor 20+32, 6, 6 - xxlor 21+32, 7, 7 - xxlor 22+32, 8, 8 - - vcipher 15, 15, 19 - vcipher 16, 16, 19 - vcipher 17, 17, 19 - vcipher 18, 18, 19 - - vcipher 15, 15, 20 - vcipher 16, 16, 20 - vcipher 17, 17, 20 - vcipher 18, 18, 20 - - vcipher 15, 15, 21 - vcipher 16, 16, 21 - vcipher 17, 17, 21 - vcipher 18, 18, 21 - - vcipher 15, 15, 22 - vcipher 16, 16, 22 - vcipher 17, 17, 22 - vcipher 18, 18, 22 - - xxlor 23+32, 9, 9 - vcipher 15, 15, 23 - vcipher 16, 16, 23 - vcipher 17, 17, 23 - vcipher 18, 18, 23 +.macro SAVE_GPR GPR OFFSET FRAME + std \GPR,\OFFSET(\FRAME) .endm - # 8x loops - # v15 - v22 - input states - # vs1 - vs9 - round keys - # -.macro Loop_aes_middle8x - xxlor 23+32, 1, 1 - xxlor 24+32, 2, 2 - xxlor 25+32, 3, 3 - xxlor 26+32, 4, 4 - - vcipher 15, 15, 23 - vcipher 16, 16, 23 - vcipher 17, 17, 23 - vcipher 18, 18, 23 - vcipher 19, 19, 23 - vcipher 20, 20, 23 - vcipher 21, 21, 23 - vcipher 22, 22, 23 - - vcipher 15, 15, 24 - vcipher 16, 16, 24 - vcipher 17, 17, 24 - vcipher 18, 18, 24 - vcipher 19, 19, 24 - vcipher 20, 20, 24 - vcipher 21, 21, 24 - vcipher 22, 22, 24 - - vcipher 15, 15, 25 - vcipher 16, 16, 25 - vcipher 17, 17, 25 - vcipher 18, 18, 25 - vcipher 19, 19, 25 - vcipher 20, 20, 25 - vcipher 21, 21, 25 - vcipher 22, 22, 25 - - vcipher 15, 15, 26 - vcipher 16, 16, 26 - vcipher 17, 17, 26 - vcipher 18, 18, 26 - vcipher 19, 19, 26 - vcipher 20, 20, 26 - vcipher 21, 21, 26 - vcipher 22, 22, 26 - - xxlor 23+32, 5, 5 - xxlor 24+32, 6, 6 - xxlor 25+32, 7, 7 - xxlor 26+32, 8, 8 - - vcipher 15, 15, 23 - vcipher 16, 16, 23 - vcipher 17, 17, 23 - vcipher 18, 18, 23 - vcipher 19, 19, 23 - vcipher 20, 20, 23 - vcipher 21, 21, 23 - vcipher 22, 22, 23 - - vcipher 15, 15, 24 - vcipher 16, 16, 24 - vcipher 17, 17, 24 - vcipher 18, 18, 24 - vcipher 19, 19, 24 - vcipher 20, 20, 24 - vcipher 21, 21, 24 - vcipher 22, 22, 24 - - vcipher 15, 15, 25 - vcipher 16, 16, 25 - vcipher 17, 17, 25 - vcipher 18, 18, 25 - vcipher 19, 19, 25 - vcipher 20, 20, 25 - vcipher 21, 21, 25 - vcipher 22, 22, 25 - - vcipher 15, 15, 26 - vcipher 16, 16, 26 - vcipher 17, 17, 26 - vcipher 18, 18, 26 - vcipher 19, 19, 26 - vcipher 20, 20, 26 - vcipher 21, 21, 26 - vcipher 22, 22, 26 - - xxlor 23+32, 9, 9 - vcipher 15, 15, 23 - vcipher 16, 16, 23 - vcipher 17, 17, 23 - vcipher 18, 18, 23 - vcipher 19, 19, 23 - vcipher 20, 20, 23 - vcipher 21, 21, 23 - vcipher 22, 22, 23 +.macro SAVE_VRS VRS OFFSET FRAME + stxv \VRS+32, \OFFSET(\FRAME) .endm -.macro Loop_aes_middle_1x - xxlor 19+32, 1, 1 - xxlor 20+32, 2, 2 - xxlor 21+32, 3, 3 - xxlor 22+32, 4, 4 - - vcipher 15, 15, 19 - vcipher 15, 15, 20 - vcipher 15, 15, 21 - vcipher 15, 15, 22 - - xxlor 19+32, 5, 5 - xxlor 20+32, 6, 6 - xxlor 21+32, 7, 7 - xxlor 22+32, 8, 8 - - vcipher 15, 15, 19 - vcipher 15, 15, 20 - vcipher 15, 15, 21 - vcipher 15, 15, 22 - - xxlor 19+32, 9, 9 - vcipher 15, 15, 19 +.macro RESTORE_GPR GPR OFFSET FRAME + ld \GPR,\OFFSET(\FRAME) .endm - # - # Compute 4x hash values based on Karatsuba method. - # -.macro ppc_aes_gcm_ghash - vxor 15, 15, 0 - - vpmsumd 23, 12, 15 # H4.L * X.L - vpmsumd 24, 9, 16 - vpmsumd 25, 6, 17 - vpmsumd 26, 3, 18 - - vxor 23, 23, 24 - vxor 23, 23, 25 - vxor 23, 23, 26 # L - - vpmsumd 24, 13, 15 # H4.L * X.H + H4.H * X.L - vpmsumd 25, 10, 16 # H3.L * X1.H + H3.H * X1.L - vpmsumd 26, 7, 17 - vpmsumd 27, 4, 18 - - vxor 24, 24, 25 - vxor 24, 24, 26 - vxor 24, 24, 27 # M - - # sum hash and reduction with H Poly - vpmsumd 28, 23, 2 # reduction - - vxor 29, 29, 29 - vsldoi 26, 24, 29, 8 # mL - vsldoi 29, 29, 24, 8 # mH - vxor 23, 23, 26 # mL + L - - vsldoi 23, 23, 23, 8 # swap - vxor 23, 23, 28 - - vpmsumd 24, 14, 15 # H4.H * X.H - vpmsumd 25, 11, 16 - vpmsumd 26, 8, 17 - vpmsumd 27, 5, 18 - - vxor 24, 24, 25 - vxor 24, 24, 26 - vxor 24, 24, 27 - - vxor 24, 24, 29 - - # sum hash and reduction with H Poly - vsldoi 27, 23, 23, 8 # swap - vpmsumd 23, 23, 2 - vxor 27, 27, 24 - vxor 23, 23, 27 - - xxlor 32, 23+32, 23+32 # update hash - +.macro RESTORE_VRS VRS OFFSET FRAME + lxv \VRS+32, \OFFSET(\FRAME) .endm - # - # Combine two 4x ghash - # v15 - v22 - input blocks - # -.macro ppc_aes_gcm_ghash2_4x - # first 4x hash - vxor 15, 15, 0 # Xi + X - - vpmsumd 23, 12, 15 # H4.L * X.L - vpmsumd 24, 9, 16 - vpmsumd 25, 6, 17 - vpmsumd 26, 3, 18 - - vxor 23, 23, 24 - vxor 23, 23, 25 - vxor 23, 23, 26 # L - - vpmsumd 24, 13, 15 # H4.L * X.H + H4.H * X.L - vpmsumd 25, 10, 16 # H3.L * X1.H + H3.H * X1.L - vpmsumd 26, 7, 17 - vpmsumd 27, 4, 18 - - vxor 24, 24, 25 - vxor 24, 24, 26 - - # sum hash and reduction with H Poly - vpmsumd 28, 23, 2 # reduction - - vxor 29, 29, 29 - - vxor 24, 24, 27 # M - vsldoi 26, 24, 29, 8 # mL - vsldoi 29, 29, 24, 8 # mH - vxor 23, 23, 26 # mL + L - - vsldoi 23, 23, 23, 8 # swap - vxor 23, 23, 28 +.macro SAVE_REGS + mflr 0 + std 0, 16(1) + stdu 1,-512(1) + + SAVE_GPR 14, 112, 1 + SAVE_GPR 15, 120, 1 + SAVE_GPR 16, 128, 1 + SAVE_GPR 17, 136, 1 + SAVE_GPR 18, 144, 1 + SAVE_GPR 19, 152, 1 + SAVE_GPR 20, 160, 1 + SAVE_GPR 21, 168, 1 + SAVE_GPR 22, 176, 1 + SAVE_GPR 23, 184, 1 + SAVE_GPR 24, 192, 1 + + addi 9, 1, 256 + SAVE_VRS 20, 0, 9 + SAVE_VRS 21, 16, 9 + SAVE_VRS 22, 32, 9 + SAVE_VRS 23, 48, 9 + SAVE_VRS 24, 64, 9 + SAVE_VRS 25, 80, 9 + SAVE_VRS 26, 96, 9 + SAVE_VRS 27, 112, 9 + SAVE_VRS 28, 128, 9 + SAVE_VRS 29, 144, 9 + SAVE_VRS 30, 160, 9 + SAVE_VRS 31, 176, 9 +.endm # SAVE_REGS - vpmsumd 24, 14, 15 # H4.H * X.H - vpmsumd 25, 11, 16 - vpmsumd 26, 8, 17 - vpmsumd 27, 5, 18 +.macro RESTORE_REGS + addi 9, 1, 256 + RESTORE_VRS 20, 0, 9 + RESTORE_VRS 21, 16, 9 + RESTORE_VRS 22, 32, 9 + RESTORE_VRS 23, 48, 9 + RESTORE_VRS 24, 64, 9 + RESTORE_VRS 25, 80, 9 + RESTORE_VRS 26, 96, 9 + RESTORE_VRS 27, 112, 9 + RESTORE_VRS 28, 128, 9 + RESTORE_VRS 29, 144, 9 + RESTORE_VRS 30, 160, 9 + RESTORE_VRS 31, 176, 9 + + RESTORE_GPR 14, 112, 1 + RESTORE_GPR 15, 120, 1 + RESTORE_GPR 16, 128, 1 + RESTORE_GPR 17, 136, 1 + RESTORE_GPR 18, 144, 1 + RESTORE_GPR 19, 152, 1 + RESTORE_GPR 20, 160, 1 + RESTORE_GPR 21, 168, 1 + RESTORE_GPR 22, 176, 1 + RESTORE_GPR 23, 184, 1 + RESTORE_GPR 24, 192, 1 + + addi 1, 1, 512 + ld 0, 16(1) + mtlr 0 +.endm # RESTORE_REGS + +# 4x loops +.macro AES_CIPHER_4x _VCIPHER ST r + \_VCIPHER \ST, \ST, \r + \_VCIPHER \ST+1, \ST+1, \r + \_VCIPHER \ST+2, \ST+2, \r + \_VCIPHER \ST+3, \ST+3, \r +.endm - vxor 24, 24, 25 - vxor 24, 24, 26 - vxor 24, 24, 27 # H +# 8x loops +.macro AES_CIPHER_8x _VCIPHER ST r + \_VCIPHER \ST, \ST, \r + \_VCIPHER \ST+1, \ST+1, \r + \_VCIPHER \ST+2, \ST+2, \r + \_VCIPHER \ST+3, \ST+3, \r + \_VCIPHER \ST+4, \ST+4, \r + \_VCIPHER \ST+5, \ST+5, \r + \_VCIPHER \ST+6, \ST+6, \r + \_VCIPHER \ST+7, \ST+7, \r +.endm - vxor 24, 24, 29 # H + mH +.macro LOOP_8AES_STATE + xxlor 32+23, 1, 1 + xxlor 32+24, 2, 2 + xxlor 32+25, 3, 3 + xxlor 32+26, 4, 4 + AES_CIPHER_8x vcipher, 15, 23 + AES_CIPHER_8x vcipher, 15, 24 + AES_CIPHER_8x vcipher, 15, 25 + AES_CIPHER_8x vcipher, 15, 26 + xxlor 32+23, 5, 5 + xxlor 32+24, 6, 6 + xxlor 32+25, 7, 7 + xxlor 32+26, 8, 8 + AES_CIPHER_8x vcipher, 15, 23 + AES_CIPHER_8x vcipher, 15, 24 + AES_CIPHER_8x vcipher, 15, 25 + AES_CIPHER_8x vcipher, 15, 26 +.endm - # sum hash and reduction with H Poly - vsldoi 27, 23, 23, 8 # swap - vpmsumd 23, 23, 2 - vxor 27, 27, 24 - vxor 27, 23, 27 # 1st Xi - - # 2nd 4x hash - vpmsumd 24, 9, 20 - vpmsumd 25, 6, 21 - vpmsumd 26, 3, 22 - vxor 19, 19, 27 # Xi + X - vpmsumd 23, 12, 19 # H4.L * X.L - - vxor 23, 23, 24 - vxor 23, 23, 25 - vxor 23, 23, 26 # L - - vpmsumd 24, 13, 19 # H4.L * X.H + H4.H * X.L - vpmsumd 25, 10, 20 # H3.L * X1.H + H3.H * X1.L - vpmsumd 26, 7, 21 - vpmsumd 27, 4, 22 - - vxor 24, 24, 25 - vxor 24, 24, 26 +# +# PPC_GHASH4x(H, S1, S2, S3, S4): Compute 4x hash values based on Karatsuba method. +# H: returning digest +# S#: states +# +# S1 should xor with the previous digest +# +# Xi = v0 +# H Poly = v2 +# Hash keys = v3 - v14 +# Scratch: v23 - v29 +# +.macro PPC_GHASH4x H S1 S2 S3 S4 + + vpmsumd 23, 12, \S1 # H4.L * X.L + vpmsumd 24, 9, \S2 + vpmsumd 25, 6, \S3 + vpmsumd 26, 3, \S4 + + vpmsumd 27, 13, \S1 # H4.L * X.H + H4.H * X.L + vpmsumd 28, 10, \S2 # H3.L * X1.H + H3.H * X1.L + + vxor 23, 23, 24 + vxor 23, 23, 25 + vxor 23, 23, 26 # L + + vxor 24, 27, 28 + vpmsumd 25, 7, \S3 + vpmsumd 26, 4, \S4 + + vxor 24, 24, 25 + vxor 24, 24, 26 # M # sum hash and reduction with H Poly - vpmsumd 28, 23, 2 # reduction - - vxor 29, 29, 29 + vpmsumd 28, 23, 2 # reduction - vxor 24, 24, 27 # M - vsldoi 26, 24, 29, 8 # mL - vsldoi 29, 29, 24, 8 # mH - vxor 23, 23, 26 # mL + L + vxor 1, 1, 1 + vsldoi 25, 24, 1, 8 # mL + vsldoi 1, 1, 24, 8 # mH + vxor 23, 23, 25 # mL + L - vsldoi 23, 23, 23, 8 # swap - vxor 23, 23, 28 + # This performs swap and xor like, + # vsldoi 23, 23, 23, 8 # swap + # vxor 23, 23, 28 + xxlor 32+25, 10, 10 + vpermxor 23, 23, 28, 25 - vpmsumd 24, 14, 19 # H4.H * X.H - vpmsumd 25, 11, 20 - vpmsumd 26, 8, 21 - vpmsumd 27, 5, 22 + vpmsumd 26, 14, \S1 # H4.H * X.H + vpmsumd 27, 11, \S2 + vpmsumd 28, 8, \S3 + vpmsumd 29, 5, \S4 - vxor 24, 24, 25 - vxor 24, 24, 26 - vxor 24, 24, 27 # H + vxor 24, 26, 27 + vxor 24, 24, 28 + vxor 24, 24, 29 - vxor 24, 24, 29 # H + mH + vxor 24, 24, 1 # sum hash and reduction with H Poly - vsldoi 27, 23, 23, 8 # swap - vpmsumd 23, 23, 2 - vxor 27, 27, 24 - vxor 23, 23, 27 - - xxlor 32, 23+32, 23+32 # update hash - + vsldoi 25, 23, 23, 8 # swap + vpmsumd 23, 23, 2 + vxor 27, 25, 24 + vxor \H, 23, 27 .endm - # - # Compute update single hash - # -.macro ppc_update_hash_1x - vxor 28, 28, 0 - - vxor 19, 19, 19 +# +# Compute update single ghash +# scratch: v1, v22..v27 +# +.macro PPC_GHASH1x H S1 - vpmsumd 22, 3, 28 # L - vpmsumd 23, 4, 28 # M - vpmsumd 24, 5, 28 # H + vxor 1, 1, 1 - vpmsumd 27, 22, 2 # reduction + vpmsumd 22, 3, \S1 # L + vpmsumd 23, 4, \S1 # M + vpmsumd 24, 5, \S1 # H - vsldoi 25, 23, 19, 8 # mL - vsldoi 26, 19, 23, 8 # mH - vxor 22, 22, 25 # LL + LL - vxor 24, 24, 26 # HH + HH + vpmsumd 27, 22, 2 # reduction - vsldoi 22, 22, 22, 8 # swap - vxor 22, 22, 27 + vsldoi 25, 23, 1, 8 # mL + vsldoi 26, 1, 23, 8 # mH + vxor 22, 22, 25 # LL + LL + vxor 24, 24, 26 # HH + HH - vsldoi 20, 22, 22, 8 # swap - vpmsumd 22, 22, 2 # reduction - vxor 20, 20, 24 - vxor 22, 22, 20 + xxlor 32+25, 10, 10 + vpermxor 22, 22, 27, 25 - vmr 0, 22 # update hash - -.endm - -.macro SAVE_REGS - stdu 1,-640(1) - mflr 0 - - std 14,112(1) - std 15,120(1) - std 16,128(1) - std 17,136(1) - std 18,144(1) - std 19,152(1) - std 20,160(1) - std 21,168(1) - li 9, 256 - stvx 20, 9, 1 - addi 9, 9, 16 - stvx 21, 9, 1 - addi 9, 9, 16 - stvx 22, 9, 1 - addi 9, 9, 16 - stvx 23, 9, 1 - addi 9, 9, 16 - stvx 24, 9, 1 - addi 9, 9, 16 - stvx 25, 9, 1 - addi 9, 9, 16 - stvx 26, 9, 1 - addi 9, 9, 16 - stvx 27, 9, 1 - addi 9, 9, 16 - stvx 28, 9, 1 - addi 9, 9, 16 - stvx 29, 9, 1 - addi 9, 9, 16 - stvx 30, 9, 1 - addi 9, 9, 16 - stvx 31, 9, 1 - stxv 14, 464(1) - stxv 15, 480(1) - stxv 16, 496(1) - stxv 17, 512(1) - stxv 18, 528(1) - stxv 19, 544(1) - stxv 20, 560(1) - stxv 21, 576(1) - stxv 22, 592(1) - std 0, 656(1) -.endm - -.macro RESTORE_REGS - lxv 14, 464(1) - lxv 15, 480(1) - lxv 16, 496(1) - lxv 17, 512(1) - lxv 18, 528(1) - lxv 19, 544(1) - lxv 20, 560(1) - lxv 21, 576(1) - lxv 22, 592(1) - li 9, 256 - lvx 20, 9, 1 - addi 9, 9, 16 - lvx 21, 9, 1 - addi 9, 9, 16 - lvx 22, 9, 1 - addi 9, 9, 16 - lvx 23, 9, 1 - addi 9, 9, 16 - lvx 24, 9, 1 - addi 9, 9, 16 - lvx 25, 9, 1 - addi 9, 9, 16 - lvx 26, 9, 1 - addi 9, 9, 16 - lvx 27, 9, 1 - addi 9, 9, 16 - lvx 28, 9, 1 - addi 9, 9, 16 - lvx 29, 9, 1 - addi 9, 9, 16 - lvx 30, 9, 1 - addi 9, 9, 16 - lvx 31, 9, 1 - - ld 0, 656(1) - ld 14,112(1) - ld 15,120(1) - ld 16,128(1) - ld 17,136(1) - ld 18,144(1) - ld 19,152(1) - ld 20,160(1) - ld 21,168(1) - - mtlr 0 - addi 1, 1, 640 + vsldoi 23, 22, 22, 8 # swap + vpmsumd 22, 22, 2 # reduction + vxor 23, 23, 24 + vxor \H, 22, 23 .endm +# +# LOAD_HASH_TABLE +# Xi = v0 +# H Poly = v2 +# Hash keys = v3 - v14 +# .macro LOAD_HASH_TABLE # Load Xi lxvb16x 32, 0, 8 # load Xi @@ -557,657 +298,434 @@ lxvd2x 14+32, 10, 8 # H^4h .endm - # - # aes_p10_gcm_encrypt (const void *inp, void *out, size_t len, - # const char *rk, unsigned char iv[16], void *Xip); - # - # r3 - inp - # r4 - out - # r5 - len - # r6 - AES round keys - # r7 - iv and other data - # r8 - Xi, HPoli, hash keys - # - # rounds is at offset 240 in rk - # Xi is at 0 in gcm_table (Xip). - # -_GLOBAL(aes_p10_gcm_encrypt) -.align 5 - - SAVE_REGS - - LOAD_HASH_TABLE - - # initialize ICB: GHASH( IV ), IV - r7 - lxvb16x 30+32, 0, 7 # load IV - v30 - - mr 12, 5 # length - li 11, 0 # block index - - # counter 1 - vxor 31, 31, 31 - vspltisb 22, 1 - vsldoi 31, 31, 22,1 # counter 1 - - # load round key to VSR - lxv 0, 0(6) - lxv 1, 0x10(6) - lxv 2, 0x20(6) - lxv 3, 0x30(6) - lxv 4, 0x40(6) - lxv 5, 0x50(6) - lxv 6, 0x60(6) - lxv 7, 0x70(6) - lxv 8, 0x80(6) - lxv 9, 0x90(6) - lxv 10, 0xa0(6) - - # load rounds - 10 (128), 12 (192), 14 (256) - lwz 9,240(6) - - # - # vxor state, state, w # addroundkey - xxlor 32+29, 0, 0 - vxor 15, 30, 29 # IV + round key - add round key 0 - - cmpdi 9, 10 - beq Loop_aes_gcm_8x - - # load 2 more round keys (v11, v12) - lxv 11, 0xb0(6) - lxv 12, 0xc0(6) - - cmpdi 9, 12 - beq Loop_aes_gcm_8x - - # load 2 more round keys (v11, v12, v13, v14) - lxv 13, 0xd0(6) - lxv 14, 0xe0(6) - cmpdi 9, 14 - beq Loop_aes_gcm_8x - - b aes_gcm_out - -.align 5 -Loop_aes_gcm_8x: - mr 14, 3 - mr 9, 4 - - # - # check partial block - # -Continue_partial_check: - ld 15, 56(7) - cmpdi 15, 0 - beq Continue - bgt Final_block - cmpdi 15, 16 - blt Final_block - -Continue: - # n blcoks - li 10, 128 - divdu 10, 12, 10 # n 128 bytes-blocks - cmpdi 10, 0 - beq Loop_last_block - - vaddudm 30, 30, 31 # IV + counter - vxor 16, 30, 29 - vaddudm 30, 30, 31 - vxor 17, 30, 29 - vaddudm 30, 30, 31 - vxor 18, 30, 29 - vaddudm 30, 30, 31 - vxor 19, 30, 29 - vaddudm 30, 30, 31 - vxor 20, 30, 29 - vaddudm 30, 30, 31 - vxor 21, 30, 29 - vaddudm 30, 30, 31 - vxor 22, 30, 29 - - mtctr 10 - - li 15, 16 - li 16, 32 - li 17, 48 - li 18, 64 - li 19, 80 - li 20, 96 - li 21, 112 - - lwz 10, 240(6) - -Loop_8x_block: - - lxvb16x 15, 0, 14 # load block - lxvb16x 16, 15, 14 # load block - lxvb16x 17, 16, 14 # load block - lxvb16x 18, 17, 14 # load block - lxvb16x 19, 18, 14 # load block - lxvb16x 20, 19, 14 # load block - lxvb16x 21, 20, 14 # load block - lxvb16x 22, 21, 14 # load block - addi 14, 14, 128 - - Loop_aes_middle8x - - xxlor 23+32, 10, 10 - - cmpdi 10, 10 - beq Do_next_ghash - - # 192 bits - xxlor 24+32, 11, 11 - - vcipher 15, 15, 23 - vcipher 16, 16, 23 - vcipher 17, 17, 23 - vcipher 18, 18, 23 - vcipher 19, 19, 23 - vcipher 20, 20, 23 - vcipher 21, 21, 23 - vcipher 22, 22, 23 - - vcipher 15, 15, 24 - vcipher 16, 16, 24 - vcipher 17, 17, 24 - vcipher 18, 18, 24 - vcipher 19, 19, 24 - vcipher 20, 20, 24 - vcipher 21, 21, 24 - vcipher 22, 22, 24 - - xxlor 23+32, 12, 12 - - cmpdi 10, 12 - beq Do_next_ghash - - # 256 bits - xxlor 24+32, 13, 13 - - vcipher 15, 15, 23 - vcipher 16, 16, 23 - vcipher 17, 17, 23 - vcipher 18, 18, 23 - vcipher 19, 19, 23 - vcipher 20, 20, 23 - vcipher 21, 21, 23 - vcipher 22, 22, 23 - - vcipher 15, 15, 24 - vcipher 16, 16, 24 - vcipher 17, 17, 24 - vcipher 18, 18, 24 - vcipher 19, 19, 24 - vcipher 20, 20, 24 - vcipher 21, 21, 24 - vcipher 22, 22, 24 - - xxlor 23+32, 14, 14 - - cmpdi 10, 14 - beq Do_next_ghash - b aes_gcm_out - -Do_next_ghash: - - # - # last round - vcipherlast 15, 15, 23 - vcipherlast 16, 16, 23 - - xxlxor 47, 47, 15 - stxvb16x 47, 0, 9 # store output - xxlxor 48, 48, 16 - stxvb16x 48, 15, 9 # store output - - vcipherlast 17, 17, 23 - vcipherlast 18, 18, 23 - - xxlxor 49, 49, 17 - stxvb16x 49, 16, 9 # store output - xxlxor 50, 50, 18 - stxvb16x 50, 17, 9 # store output - - vcipherlast 19, 19, 23 - vcipherlast 20, 20, 23 - - xxlxor 51, 51, 19 - stxvb16x 51, 18, 9 # store output - xxlxor 52, 52, 20 - stxvb16x 52, 19, 9 # store output - - vcipherlast 21, 21, 23 - vcipherlast 22, 22, 23 - - xxlxor 53, 53, 21 - stxvb16x 53, 20, 9 # store output - xxlxor 54, 54, 22 - stxvb16x 54, 21, 9 # store output - - addi 9, 9, 128 - - # ghash here - ppc_aes_gcm_ghash2_4x - - xxlor 27+32, 0, 0 - vaddudm 30, 30, 31 # IV + counter - vmr 29, 30 - vxor 15, 30, 27 # add round key - vaddudm 30, 30, 31 - vxor 16, 30, 27 - vaddudm 30, 30, 31 - vxor 17, 30, 27 - vaddudm 30, 30, 31 - vxor 18, 30, 27 - vaddudm 30, 30, 31 - vxor 19, 30, 27 - vaddudm 30, 30, 31 - vxor 20, 30, 27 - vaddudm 30, 30, 31 - vxor 21, 30, 27 - vaddudm 30, 30, 31 - vxor 22, 30, 27 - - addi 12, 12, -128 - addi 11, 11, 128 - - bdnz Loop_8x_block - - vmr 30, 29 - stxvb16x 30+32, 0, 7 # update IV - -Loop_last_block: - cmpdi 12, 0 - beq aes_gcm_out - - # loop last few blocks +################################################################################ +# Compute AES and ghash one block at a time. +# r23: AES rounds +# v30: current IV +# vs0: roundkey 0 +# +################################################################################ +SYM_FUNC_START_LOCAL(aes_gcm_crypt_1x) + + cmpdi 5, 16 + bge __More_1x + blr +__More_1x: li 10, 16 - divdu 10, 12, 10 - - mtctr 10 - - lwz 10, 240(6) - - cmpdi 12, 16 - blt Final_block - -Next_rem_block: - lxvb16x 15, 0, 14 # load block - - Loop_aes_middle_1x - - xxlor 23+32, 10, 10 - - cmpdi 10, 10 - beq Do_next_1x - - # 192 bits - xxlor 24+32, 11, 11 - - vcipher 15, 15, 23 - vcipher 15, 15, 24 - - xxlor 23+32, 12, 12 + divdu 12, 5, 10 + + xxlxor 32+15, 32+30, 0 + + # Pre-load 8 AES rounds to scratch vectors. + xxlor 32+16, 1, 1 + xxlor 32+17, 2, 2 + xxlor 32+18, 3, 3 + xxlor 32+19, 4, 4 + xxlor 32+20, 5, 5 + xxlor 32+21, 6, 6 + xxlor 32+28, 7, 7 + xxlor 32+29, 8, 8 + lwz 23, 240(6) # n rounds + addi 22, 23, -9 # remaing AES rounds - cmpdi 10, 12 - beq Do_next_1x - - # 256 bits - xxlor 24+32, 13, 13 - - vcipher 15, 15, 23 - vcipher 15, 15, 24 - - xxlor 23+32, 14, 14 - - cmpdi 10, 14 - beq Do_next_1x - -Do_next_1x: - vcipherlast 15, 15, 23 - - xxlxor 47, 47, 15 - stxvb16x 47, 0, 9 # store output - addi 14, 14, 16 - addi 9, 9, 16 - - vmr 28, 15 - ppc_update_hash_1x - - addi 12, 12, -16 - addi 11, 11, 16 - xxlor 19+32, 0, 0 - vaddudm 30, 30, 31 # IV + counter - vxor 15, 30, 19 # add round key - - bdnz Next_rem_block - - li 15, 0 - std 15, 56(7) # clear partial? - stxvb16x 30+32, 0, 7 # update IV cmpdi 12, 0 - beq aes_gcm_out - -Final_block: - lwz 10, 240(6) - Loop_aes_middle_1x - - xxlor 23+32, 10, 10 - - cmpdi 10, 10 - beq Do_final_1x - - # 192 bits - xxlor 24+32, 11, 11 - - vcipher 15, 15, 23 - vcipher 15, 15, 24 - - xxlor 23+32, 12, 12 - - cmpdi 10, 12 - beq Do_final_1x - - # 256 bits - xxlor 24+32, 13, 13 - - vcipher 15, 15, 23 - vcipher 15, 15, 24 + bgt __Loop_1x + blr - xxlor 23+32, 14, 14 +__Loop_1x: + mtctr 22 + addi 10, 6, 144 + vcipher 15, 15, 16 + vcipher 15, 15, 17 + vcipher 15, 15, 18 + vcipher 15, 15, 19 + vcipher 15, 15, 20 + vcipher 15, 15, 21 + vcipher 15, 15, 28 + vcipher 15, 15, 29 - cmpdi 10, 14 - beq Do_final_1x +__Loop_aes_1state: + lxv 32+1, 0(10) + vcipher 15, 15, 1 + addi 10, 10, 16 + bdnz __Loop_aes_1state + lxv 32+1, 0(10) # last round key + lxvb16x 11, 0, 14 # load input block + vcipherlast 15, 15, 1 + + xxlxor 32+15, 32+15, 11 + stxvb16x 32+15, 0, 9 # store output + addi 14, 14, 16 + addi 9, 9, 16 -Do_final_1x: - vcipherlast 15, 15, 23 + cmpdi 24, 0 # decrypt? + bne __Encrypt_1x + xxlor 15+32, 11, 11 +__Encrypt_1x: + vxor 15, 15, 0 + PPC_GHASH1x 0, 15 - # check partial block - li 21, 0 # encrypt - ld 15, 56(7) # partial? - cmpdi 15, 0 - beq Normal_block - bl Do_partial_block + addi 5, 5, -16 + addi 11, 11, 16 + vadduwm 30, 30, 31 # IV + counter + xxlxor 32+15, 32+30, 0 + addi 12, 12, -1 cmpdi 12, 0 - ble aes_gcm_out + bgt __Loop_1x - b Continue_partial_check - -Normal_block: - lxvb16x 15, 0, 14 # load last block - xxlxor 47, 47, 15 - - # create partial block mask - li 15, 16 - sub 15, 15, 12 # index to the mask - - vspltisb 16, -1 # first 16 bytes - 0xffff...ff - vspltisb 17, 0 # second 16 bytes - 0x0000...00 - li 10, 192 - stvx 16, 10, 1 + stxvb16x 32+30, 0, 7 # update IV + stxvb16x 32+0, 0, 8 # update Xi + blr +SYM_FUNC_END(aes_gcm_crypt_1x) + +################################################################################ +# Process a normal partial block when we come here. +# Compute partial mask, Load and store partial block to stack. +# Update partial_len and pblock. +# pblock is (encrypted ^ AES state) for encrypt +# and (input ^ AES state) for decrypt. +# +################################################################################ +SYM_FUNC_START_LOCAL(__Process_partial) + + # create partial mask + vspltisb 16, -1 + li 12, 16 + sub 12, 12, 5 + sldi 12, 12, 3 + mtvsrdd 32+17, 0, 12 + vslo 16, 16, 17 # partial block mask + + lxvb16x 11, 0, 14 # load partial block + xxland 11, 11, 32+16 + + # AES crypt partial + xxlxor 32+15, 32+30, 0 + lwz 23, 240(6) # n rounds + addi 22, 23, -1 # loop - 1 + mtctr 22 + addi 10, 6, 16 + +__Loop_aes_pstate: + lxv 32+1, 0(10) + vcipher 15, 15, 1 addi 10, 10, 16 - stvx 17, 10, 1 - - addi 10, 1, 192 - lxvb16x 16, 15, 10 # load partial block mask - xxland 47, 47, 16 - - vmr 28, 15 - ppc_update_hash_1x + bdnz __Loop_aes_pstate + lxv 32+1, 0(10) # last round key + vcipherlast 15, 15, 1 - # * should store only the remaining bytes. - bl Write_partial_block - - stxvb16x 30+32, 0, 7 # update IV - std 12, 56(7) # update partial? - li 16, 16 + xxlxor 32+15, 32+15, 11 + vand 15, 15, 16 - stxvb16x 32, 0, 8 # write out Xi - stxvb16x 32, 16, 8 # write out Xi - b aes_gcm_out - - # - # Compute data mask - # -.macro GEN_MASK _mask _start _end - vspltisb 16, -1 # first 16 bytes - 0xffff...ff - vspltisb 17, 0 # second 16 bytes - 0x0000...00 - li 10, 192 - stxvb16x 17+32, 10, 1 - add 10, 10, \_start - stxvb16x 16+32, 10, 1 - add 10, 10, \_end - stxvb16x 17+32, 10, 1 - - addi 10, 1, 192 - lxvb16x \_mask, 0, 10 # load partial block mask -.endm + # AES crypt output v15 + # Write partial + li 10, 224 + stxvb16x 15+32, 10, 1 # write v15 to stack + addi 10, 1, 223 + addi 12, 9, -1 + mtctr 5 # partial block len +__Write_partial: + lbzu 22, 1(10) + stbu 22, 1(12) + bdnz __Write_partial + + cmpdi 24, 0 # decrypt? + bne __Encrypt_partial + xxlor 32+15, 11, 11 # decrypt using the input block +__Encrypt_partial: + #vxor 15, 15, 0 # ^ previous hash + #PPC_GHASH1x 0, 15 + + add 14, 14, 5 + add 9, 9, 5 + std 5, 56(7) # update partial + sub 11, 11, 5 + li 5, 0 # done last byte - # - # Handle multiple partial blocks for encrypt and decrypt - # operations. - # -SYM_FUNC_START_LOCAL(Do_partial_block) - add 17, 15, 5 - cmpdi 17, 16 - bgt Big_block - GEN_MASK 18, 15, 5 - b _Partial -SYM_FUNC_END(Do_partial_block) -Big_block: + # + # Don't increase IV since this is the last partial. + # It should get updated in gcm_update if no more data blocks. + #vadduwm 30, 30, 31 # increase IV + stxvb16x 32+30, 0, 7 # update IV + li 10, 64 + stxvb16x 32+0, 0, 8 # Update X1 + stxvb16x 32+15, 10, 7 # Update pblock + blr +SYM_FUNC_END(__Process_partial) + +################################################################################ +# Combine partial blocks and ghash when we come here. +# +# The partial block has to be shifted to the right location to encrypt/decrypt +# and compute ghash if combing the previous partial block is needed. +# - Compute ghash for a full block. Clear Partial_len and pblock. Update IV. +# Write Xi. +# - Don't compute ghash if not full block. gcm_update will take care of it +# is the last block. Update Partial_len and pblock. +# +################################################################################ +SYM_FUNC_START_LOCAL(__Combine_partial) + + ld 12, 56(7) + mr 21, 5 # these bytes to be processed + + li 17, 0 li 16, 16 - GEN_MASK 18, 15, 16 - -_Partial: - lxvb16x 17+32, 0, 14 # load last block - sldi 16, 15, 3 - mtvsrdd 32+16, 0, 16 - vsro 17, 17, 16 - xxlxor 47, 47, 17+32 - xxland 47, 47, 18 - - vxor 0, 0, 0 # clear Xi - vmr 28, 15 - - cmpdi 21, 0 # encrypt/decrypt ops? - beq Skip_decrypt - xxland 32+28, 32+17, 18 - -Skip_decrypt: - - ppc_update_hash_1x + sub 22, 16, 12 # bytes to complete a block + sub 17, 22, 5 # remaining bytes in a block + cmpdi 5, 16 + ble __Inp_msg_less16 + li 17, 0 + mr 21, 22 + b __Combine_continue +__Inp_msg_less16: + cmpd 22, 5 + bgt __Combine_continue + li 17, 0 + mr 21, 22 # these bytes to be processed + +__Combine_continue: + # load msg and shift to the proper location and mask + vspltisb 16, -1 + sldi 15, 12, 3 + mtvsrdd 32+17, 0, 15 + vslo 16, 16, 17 + vsro 16, 16, 17 + sldi 15, 17, 3 + mtvsrdd 32+17, 0, 15 + vsro 16, 16, 17 + vslo 16, 16, 17 # mask + + lxvb16x 32+19, 0, 14 # load partial block + sldi 15, 12, 3 + mtvsrdd 32+17, 0, 15 + vsro 19, 19, 17 # 0x00..xxxx??..?? + sldi 15, 17, 3 + mtvsrdd 32+17, 0, 15 + vsro 19, 19, 17 # 0x00..xxxx + vslo 19, 19, 17 # shift back to form 0x00..xxxx00..00 + + # AES crypt partial + xxlxor 32+15, 32+30, 0 + lwz 23, 240(6) # n rounds + addi 22, 23, -1 # loop - 1 + mtctr 22 + addi 10, 6, 16 + +__Loop_aes_cpstate: + lxv 32+1, 0(10) + vcipher 15, 15, 1 + addi 10, 10, 16 + bdnz __Loop_aes_cpstate + lxv 32+1, 0(10) # last round key + vcipherlast 15, 15, 1 - li 16, 16 - lxvb16x 32+29, 16, 8 - vxor 0, 0, 29 - stxvb16x 32, 0, 8 # save Xi - stxvb16x 32, 16, 8 # save Xi - - # store partial block - # loop the rest of the stream if any - sldi 16, 15, 3 - mtvsrdd 32+16, 0, 16 - vslo 15, 15, 16 - #stxvb16x 15+32, 0, 9 # last block + vxor 15, 15, 19 + vand 15, 15, 16 - li 16, 16 - sub 17, 16, 15 # 16 - partial - - add 16, 15, 5 - cmpdi 16, 16 - bgt Larger_16 - mr 17, 5 -Larger_16: - - # write partial - li 10, 192 - stxvb16x 15+32, 10, 1 # save current block - - addi 10, 9, -1 - addi 16, 1, 191 - mtctr 17 # move partial byte count - -Write_last_partial: - lbzu 18, 1(16) - stbu 18, 1(10) - bdnz Write_last_partial - # Complete loop partial - - add 14, 14, 17 - add 9, 9, 17 - sub 12, 12, 17 - add 11, 11, 17 - - add 15, 15, 5 - cmpdi 15, 16 - blt Save_partial - - vaddudm 30, 30, 31 - stxvb16x 30+32, 0, 7 # update IV - xxlor 32+29, 0, 0 - vxor 15, 30, 29 # IV + round key - add round key 0 - li 15, 0 - std 15, 56(7) # partial done - clear - b Partial_done -Save_partial: - std 15, 56(7) # partial - -Partial_done: + # AES crypt output v15 + # Write partial + li 10, 224 + stxvb16x 15+32, 10, 1 # write v15 to stack + addi 10, 1, 223 + add 10, 10, 12 # add offset + addi 15, 9, -1 + mtctr 21 # partial block len +__Write_combine_partial: + lbzu 22, 1(10) + stbu 22, 1(15) + bdnz __Write_combine_partial + + add 14, 14, 21 + add 11, 11, 21 + add 9, 9, 21 + sub 5, 5, 21 + + # Encrypt/Decrypt? + cmpdi 24, 0 # decrypt? + bne __Encrypt_combine_partial + vmr 15, 19 # decrypt using the input block + +__Encrypt_combine_partial: + # + # Update partial flag and combine ghash. +__Update_partial_ghash: + li 10, 64 + lxvb16x 32+17, 10, 7 # load previous pblock + add 12, 12, 21 # combined pprocessed + vxor 15, 15, 17 # combined pblock + + cmpdi 12, 16 + beq __Clear_partial_flag + std 12, 56(7) # update partial len + stxvb16x 32+15, 10, 7 # Update current pblock blr - # - # Write partial block - # r9 - output - # r12 - remaining bytes - # v15 - partial input data - # -SYM_FUNC_START_LOCAL(Write_partial_block) - li 10, 192 - stxvb16x 15+32, 10, 1 # last block - - addi 10, 9, -1 - addi 16, 1, 191 - - mtctr 12 # remaining bytes - li 15, 0 - -Write_last_byte: - lbzu 14, 1(16) - stbu 14, 1(10) - bdnz Write_last_byte +__Clear_partial_flag: + li 12, 0 + std 12, 56(7) + # Update IV and ghash here + vadduwm 30, 30, 31 # increase IV + stxvb16x 32+30, 0, 7 # update IV + + # v15 either is either (input blockor encrypted)^(AES state) + vxor 15, 15, 0 + PPC_GHASH1x 0, 15 + stxvb16x 32+0, 10, 7 # update pblock for debug? + stxvb16x 32+0, 0, 8 # update Xi blr -SYM_FUNC_END(Write_partial_block) +SYM_FUNC_END(__Combine_partial) -aes_gcm_out: - # out = state - stxvb16x 32, 0, 8 # write out Xi - add 3, 11, 12 # return count +################################################################################ +# gcm_update(iv, Xi) - compute last hash +# +################################################################################ +SYM_FUNC_START(gcm_update) - RESTORE_REGS - blr + ld 10, 56(3) + cmpdi 10, 0 + beq __no_update - # - # 8x Decrypt - # -_GLOBAL(aes_p10_gcm_decrypt) -.align 5 + lxvb16x 32, 0, 4 # load Xi + # load Hash - h^4, h^3, h^2, h + li 10, 32 + lxvd2x 2+32, 10, 4 # H Poli + li 10, 48 + lxvd2x 3+32, 10, 4 # Hl + li 10, 64 + lxvd2x 4+32, 10, 4 # H + li 10, 80 + lxvd2x 5+32, 10, 4 # Hh + + addis 11, 2, permx@toc@ha + addi 11, 11, permx@toc@l + lxv 10, 0(11) # vs10: vpermxor vector + + li 9, 64 + lxvb16x 32+6, 9, 3 # load pblock + vxor 6, 6, 0 + + vxor 1, 1, 1 + vpmsumd 12, 3, 6 # L + vpmsumd 13, 4, 6 # M + vpmsumd 14, 5, 6 # H + vpmsumd 17, 12, 2 # reduction + vsldoi 15, 13, 1, 8 # mL + vsldoi 16, 1, 13, 8 # mH + vxor 12, 12, 15 # LL + LL + vxor 14, 14, 16 # HH + HH + xxlor 32+15, 10, 10 + vpermxor 12, 12, 17, 15 + vsldoi 13, 12, 12, 8 # swap + vpmsumd 12, 12, 2 # reduction + vxor 13, 13, 14 + vxor 7, 12, 13 + + #vxor 0, 0, 0 + #stxvb16x 32+0, 9, 3 + li 10, 0 + std 10, 56(3) + stxvb16x 32+7, 0, 4 + +__no_update: + blr +SYM_FUNC_END(gcm_update) + +################################################################################ +# aes_p10_gcm_encrypt (const void *inp, void *out, size_t len, +# const char *rk, unsigned char iv[16], void *Xip); +# +# r3 - inp +# r4 - out +# r5 - len +# r6 - AES round keys +# r7 - iv and other data +# r8 - Xi, HPoli, hash keys +# +# rounds is at offset 240 in rk +# Xi is at 0 in gcm_table (Xip). +# +################################################################################ +SYM_FUNC_START(aes_p10_gcm_encrypt) + + cmpdi 5, 0 + ble __Invalid_msg_len SAVE_REGS - LOAD_HASH_TABLE # initialize ICB: GHASH( IV ), IV - r7 lxvb16x 30+32, 0, 7 # load IV - v30 - mr 12, 5 # length - li 11, 0 # block index + mr 14, 3 + mr 9, 4 # counter 1 vxor 31, 31, 31 vspltisb 22, 1 vsldoi 31, 31, 22,1 # counter 1 - # load round key to VSR - lxv 0, 0(6) - lxv 1, 0x10(6) - lxv 2, 0x20(6) - lxv 3, 0x30(6) - lxv 4, 0x40(6) - lxv 5, 0x50(6) - lxv 6, 0x60(6) - lxv 7, 0x70(6) - lxv 8, 0x80(6) - lxv 9, 0x90(6) - lxv 10, 0xa0(6) + addis 11, 2, permx@toc@ha + addi 11, 11, permx@toc@l + lxv 10, 0(11) # vs10: vpermxor vector + li 11, 0 + + # load 9 round keys to VSR + lxv 0, 0(6) # round key 0 + lxv 1, 16(6) # round key 1 + lxv 2, 32(6) # round key 2 + lxv 3, 48(6) # round key 3 + lxv 4, 64(6) # round key 4 + lxv 5, 80(6) # round key 5 + lxv 6, 96(6) # round key 6 + lxv 7, 112(6) # round key 7 + lxv 8, 128(6) # round key 8 # load rounds - 10 (128), 12 (192), 14 (256) - lwz 9,240(6) + lwz 23, 240(6) # n rounds + li 24, 1 # encrypt +__Process_encrypt: # - # vxor state, state, w # addroundkey - xxlor 32+29, 0, 0 - vxor 15, 30, 29 # IV + round key - add round key 0 - - cmpdi 9, 10 - beq Loop_aes_gcm_8x_dec - - # load 2 more round keys (v11, v12) - lxv 11, 0xb0(6) - lxv 12, 0xc0(6) - - cmpdi 9, 12 - beq Loop_aes_gcm_8x_dec - - # load 2 more round keys (v11, v12, v13, v14) - lxv 13, 0xd0(6) - lxv 14, 0xe0(6) - cmpdi 9, 14 - beq Loop_aes_gcm_8x_dec + # Process different blocks + # + ld 12, 56(7) + cmpdi 12, 0 + bgt __Do_combine_enc + cmpdi 5, 128 + blt __Process_more_enc + +# +# Process 8x AES/GCM blocks +# +__Process_8x_enc: + # 8x blcoks + li 10, 128 + divdu 12, 5, 10 # n 128 bytes-blocks - b aes_gcm_out + addi 12, 12, -1 # loop - 1 -.align 5 -Loop_aes_gcm_8x_dec: - mr 14, 3 - mr 9, 4 + vmr 15, 30 # first state: IV + vadduwm 16, 15, 31 # state + counter + vadduwm 17, 16, 31 + vadduwm 18, 17, 31 + vadduwm 19, 18, 31 + vadduwm 20, 19, 31 + vadduwm 21, 20, 31 + vadduwm 22, 21, 31 + xxlor 9, 32+22, 32+22 # save last state - # - # check partial block - # -Continue_partial_check_dec: - ld 15, 56(7) - cmpdi 15, 0 - beq Continue_dec - bgt Final_block_dec - cmpdi 15, 16 - blt Final_block_dec - -Continue_dec: - # n blcoks - li 10, 128 - divdu 10, 12, 10 # n 128 bytes-blocks - cmpdi 10, 0 - beq Loop_last_block_dec - - vaddudm 30, 30, 31 # IV + counter - vxor 16, 30, 29 - vaddudm 30, 30, 31 - vxor 17, 30, 29 - vaddudm 30, 30, 31 - vxor 18, 30, 29 - vaddudm 30, 30, 31 - vxor 19, 30, 29 - vaddudm 30, 30, 31 - vxor 20, 30, 29 - vaddudm 30, 30, 31 - vxor 21, 30, 29 - vaddudm 30, 30, 31 - vxor 22, 30, 29 - - mtctr 10 + # vxor state, state, w # addroundkey + xxlor 32+29, 0, 0 + vxor 15, 15, 29 # IV + round key - add round key 0 + vxor 16, 16, 29 + vxor 17, 17, 29 + vxor 18, 18, 29 + vxor 19, 19, 29 + vxor 20, 20, 29 + vxor 21, 21, 29 + vxor 22, 22, 29 li 15, 16 li 16, 32 @@ -1217,305 +735,502 @@ Continue_dec: li 20, 96 li 21, 112 - lwz 10, 240(6) - -Loop_8x_block_dec: - - lxvb16x 15, 0, 14 # load block - lxvb16x 16, 15, 14 # load block - lxvb16x 17, 16, 14 # load block - lxvb16x 18, 17, 14 # load block - lxvb16x 19, 18, 14 # load block - lxvb16x 20, 19, 14 # load block - lxvb16x 21, 20, 14 # load block - lxvb16x 22, 21, 14 # load block - addi 14, 14, 128 - - Loop_aes_middle8x - - xxlor 23+32, 10, 10 - - cmpdi 10, 10 - beq Do_next_ghash_dec - - # 192 bits - xxlor 24+32, 11, 11 - - vcipher 15, 15, 23 - vcipher 16, 16, 23 - vcipher 17, 17, 23 - vcipher 18, 18, 23 - vcipher 19, 19, 23 - vcipher 20, 20, 23 - vcipher 21, 21, 23 - vcipher 22, 22, 23 - - vcipher 15, 15, 24 - vcipher 16, 16, 24 - vcipher 17, 17, 24 - vcipher 18, 18, 24 - vcipher 19, 19, 24 - vcipher 20, 20, 24 - vcipher 21, 21, 24 - vcipher 22, 22, 24 - - xxlor 23+32, 12, 12 - - cmpdi 10, 12 - beq Do_next_ghash_dec - - # 256 bits - xxlor 24+32, 13, 13 - - vcipher 15, 15, 23 - vcipher 16, 16, 23 - vcipher 17, 17, 23 - vcipher 18, 18, 23 - vcipher 19, 19, 23 - vcipher 20, 20, 23 - vcipher 21, 21, 23 - vcipher 22, 22, 23 - - vcipher 15, 15, 24 - vcipher 16, 16, 24 - vcipher 17, 17, 24 - vcipher 18, 18, 24 - vcipher 19, 19, 24 - vcipher 20, 20, 24 - vcipher 21, 21, 24 - vcipher 22, 22, 24 - - xxlor 23+32, 14, 14 - - cmpdi 10, 14 - beq Do_next_ghash_dec - b aes_gcm_out + # + # Pre-compute first 8 AES state and leave 1/3/5 more rounds + # for the loop. + # + addi 22, 23, -9 # process 8 keys + mtctr 22 # AES key loop + addi 10, 6, 144 -Do_next_ghash_dec: + LOOP_8AES_STATE # process 8 AES keys - # - # last round - vcipherlast 15, 15, 23 - vcipherlast 16, 16, 23 - - xxlxor 47, 47, 15 - stxvb16x 47, 0, 9 # store output - xxlxor 48, 48, 16 - stxvb16x 48, 15, 9 # store output - - vcipherlast 17, 17, 23 - vcipherlast 18, 18, 23 - - xxlxor 49, 49, 17 - stxvb16x 49, 16, 9 # store output - xxlxor 50, 50, 18 - stxvb16x 50, 17, 9 # store output - - vcipherlast 19, 19, 23 - vcipherlast 20, 20, 23 - - xxlxor 51, 51, 19 - stxvb16x 51, 18, 9 # store output - xxlxor 52, 52, 20 - stxvb16x 52, 19, 9 # store output - - vcipherlast 21, 21, 23 - vcipherlast 22, 22, 23 - - xxlxor 53, 53, 21 - stxvb16x 53, 20, 9 # store output - xxlxor 54, 54, 22 - stxvb16x 54, 21, 9 # store output - - addi 9, 9, 128 - - xxlor 15+32, 15, 15 - xxlor 16+32, 16, 16 - xxlor 17+32, 17, 17 - xxlor 18+32, 18, 18 - xxlor 19+32, 19, 19 - xxlor 20+32, 20, 20 - xxlor 21+32, 21, 21 - xxlor 22+32, 22, 22 +__PreLoop_aes_state: + lxv 32+1, 0(10) # round key + AES_CIPHER_8x vcipher 15 1 + addi 10, 10, 16 + bdnz __PreLoop_aes_state + lxv 32+1, 0(10) # last round key (v1) + + cmpdi 12, 0 # Only one loop (8 block) + beq __Finish_ghash + +# +# Loop 8x blocks and compute ghash +# +__Loop_8x_block_enc: + vcipherlast 15, 15, 1 + vcipherlast 16, 16, 1 + vcipherlast 17, 17, 1 + vcipherlast 18, 18, 1 + vcipherlast 19, 19, 1 + vcipherlast 20, 20, 1 + vcipherlast 21, 21, 1 + vcipherlast 22, 22, 1 + + lxvb16x 32+23, 0, 14 # load block + lxvb16x 32+24, 15, 14 # load block + lxvb16x 32+25, 16, 14 # load block + lxvb16x 32+26, 17, 14 # load block + lxvb16x 32+27, 18, 14 # load block + lxvb16x 32+28, 19, 14 # load block + lxvb16x 32+29, 20, 14 # load block + lxvb16x 32+30, 21, 14 # load block + addi 14, 14, 128 + + vxor 15, 15, 23 + vxor 16, 16, 24 + vxor 17, 17, 25 + vxor 18, 18, 26 + vxor 19, 19, 27 + vxor 20, 20, 28 + vxor 21, 21, 29 + vxor 22, 22, 30 + + stxvb16x 47, 0, 9 # store output + stxvb16x 48, 15, 9 # store output + stxvb16x 49, 16, 9 # store output + stxvb16x 50, 17, 9 # store output + stxvb16x 51, 18, 9 # store output + stxvb16x 52, 19, 9 # store output + stxvb16x 53, 20, 9 # store output + stxvb16x 54, 21, 9 # store output + addi 9, 9, 128 # ghash here - ppc_aes_gcm_ghash2_4x - - xxlor 27+32, 0, 0 - vaddudm 30, 30, 31 # IV + counter - vmr 29, 30 - vxor 15, 30, 27 # add round key - vaddudm 30, 30, 31 - vxor 16, 30, 27 - vaddudm 30, 30, 31 - vxor 17, 30, 27 - vaddudm 30, 30, 31 - vxor 18, 30, 27 - vaddudm 30, 30, 31 - vxor 19, 30, 27 - vaddudm 30, 30, 31 - vxor 20, 30, 27 - vaddudm 30, 30, 31 - vxor 21, 30, 27 - vaddudm 30, 30, 31 - vxor 22, 30, 27 - - addi 12, 12, -128 + vxor 15, 15, 0 + PPC_GHASH4x 0, 15, 16, 17, 18 + + vxor 19, 19, 0 + PPC_GHASH4x 0, 19, 20, 21, 22 + + xxlor 32+15, 9, 9 # last state + vadduwm 15, 15, 31 # state + counter + vadduwm 16, 15, 31 + vadduwm 17, 16, 31 + vadduwm 18, 17, 31 + vadduwm 19, 18, 31 + vadduwm 20, 19, 31 + vadduwm 21, 20, 31 + vadduwm 22, 21, 31 + xxlor 9, 32+22, 32+22 # save last state + + xxlor 32+27, 0, 0 # restore roundkey 0 + vxor 15, 15, 27 # IV + round key - add round key 0 + vxor 16, 16, 27 + vxor 17, 17, 27 + vxor 18, 18, 27 + vxor 19, 19, 27 + vxor 20, 20, 27 + vxor 21, 21, 27 + vxor 22, 22, 27 + + addi 5, 5, -128 addi 11, 11, 128 - bdnz Loop_8x_block_dec - - vmr 30, 29 - stxvb16x 30+32, 0, 7 # update IV - -Loop_last_block_dec: - cmpdi 12, 0 - beq aes_gcm_out - - # loop last few blocks - li 10, 16 - divdu 10, 12, 10 - - mtctr 10 - - lwz 10, 240(6) - - cmpdi 12, 16 - blt Final_block_dec - -Next_rem_block_dec: - lxvb16x 15, 0, 14 # load block - - Loop_aes_middle_1x - - xxlor 23+32, 10, 10 + LOOP_8AES_STATE # process 8 AES keys + mtctr 22 # AES key loop + addi 10, 6, 144 +__LastLoop_aes_state: + lxv 32+1, 0(10) # round key + AES_CIPHER_8x vcipher 15 1 + addi 10, 10, 16 + bdnz __LastLoop_aes_state + lxv 32+1, 0(10) # last round key (v1) - cmpdi 10, 10 - beq Do_next_1x_dec + addi 12, 12, -1 + cmpdi 12, 0 + bne __Loop_8x_block_enc + +__Finish_ghash: + vcipherlast 15, 15, 1 + vcipherlast 16, 16, 1 + vcipherlast 17, 17, 1 + vcipherlast 18, 18, 1 + vcipherlast 19, 19, 1 + vcipherlast 20, 20, 1 + vcipherlast 21, 21, 1 + vcipherlast 22, 22, 1 + + lxvb16x 32+23, 0, 14 # load block + lxvb16x 32+24, 15, 14 # load block + lxvb16x 32+25, 16, 14 # load block + lxvb16x 32+26, 17, 14 # load block + lxvb16x 32+27, 18, 14 # load block + lxvb16x 32+28, 19, 14 # load block + lxvb16x 32+29, 20, 14 # load block + lxvb16x 32+30, 21, 14 # load block + addi 14, 14, 128 + + vxor 15, 15, 23 + vxor 16, 16, 24 + vxor 17, 17, 25 + vxor 18, 18, 26 + vxor 19, 19, 27 + vxor 20, 20, 28 + vxor 21, 21, 29 + vxor 22, 22, 30 + + stxvb16x 47, 0, 9 # store output + stxvb16x 48, 15, 9 # store output + stxvb16x 49, 16, 9 # store output + stxvb16x 50, 17, 9 # store output + stxvb16x 51, 18, 9 # store output + stxvb16x 52, 19, 9 # store output + stxvb16x 53, 20, 9 # store output + stxvb16x 54, 21, 9 # store output + addi 9, 9, 128 + + vxor 15, 15, 0 + PPC_GHASH4x 0, 15, 16, 17, 18 + + vxor 19, 19, 0 + PPC_GHASH4x 0, 19, 20, 21, 22 + + xxlor 30+32, 9, 9 # last ctr + vadduwm 30, 30, 31 # increase ctr + stxvb16x 32+30, 0, 7 # update IV + stxvb16x 32+0, 0, 8 # update Xi + + addi 5, 5, -128 + addi 11, 11, 128 - # 192 bits - xxlor 24+32, 11, 11 + # + # Done 8x blocks + # - vcipher 15, 15, 23 - vcipher 15, 15, 24 + cmpdi 5, 0 + beq aes_gcm_out - xxlor 23+32, 12, 12 +__Process_more_enc: + li 24, 1 # encrypt + bl aes_gcm_crypt_1x + cmpdi 5, 0 + beq aes_gcm_out - cmpdi 10, 12 - beq Do_next_1x_dec + bl __Process_partial + cmpdi 5, 0 + beq aes_gcm_out +__Do_combine_enc: + bl __Combine_partial + cmpdi 5, 0 + bgt __Process_encrypt + b aes_gcm_out - # 256 bits - xxlor 24+32, 13, 13 +SYM_FUNC_END(aes_p10_gcm_encrypt) - vcipher 15, 15, 23 - vcipher 15, 15, 24 +################################################################################ +# aes_p10_gcm_decrypt (const void *inp, void *out, size_t len, +# const char *rk, unsigned char iv[16], void *Xip); +# 8x Decrypt +# +################################################################################ +SYM_FUNC_START(aes_p10_gcm_decrypt) - xxlor 23+32, 14, 14 + cmpdi 5, 0 + ble __Invalid_msg_len - cmpdi 10, 14 - beq Do_next_1x_dec + SAVE_REGS + LOAD_HASH_TABLE -Do_next_1x_dec: - vcipherlast 15, 15, 23 + # initialize ICB: GHASH( IV ), IV - r7 + lxvb16x 30+32, 0, 7 # load IV - v30 - xxlxor 47, 47, 15 - stxvb16x 47, 0, 9 # store output - addi 14, 14, 16 - addi 9, 9, 16 + mr 14, 3 + mr 9, 4 - xxlor 28+32, 15, 15 - #vmr 28, 15 - ppc_update_hash_1x + # counter 1 + vxor 31, 31, 31 + vspltisb 22, 1 + vsldoi 31, 31, 22,1 # counter 1 - addi 12, 12, -16 - addi 11, 11, 16 - xxlor 19+32, 0, 0 - vaddudm 30, 30, 31 # IV + counter - vxor 15, 30, 19 # add round key + addis 11, 2, permx@toc@ha + addi 11, 11, permx@toc@l + lxv 10, 0(11) # vs10: vpermxor vector + li 11, 0 + + # load 9 round keys to VSR + lxv 0, 0(6) # round key 0 + lxv 1, 16(6) # round key 1 + lxv 2, 32(6) # round key 2 + lxv 3, 48(6) # round key 3 + lxv 4, 64(6) # round key 4 + lxv 5, 80(6) # round key 5 + lxv 6, 96(6) # round key 6 + lxv 7, 112(6) # round key 7 + lxv 8, 128(6) # round key 8 - bdnz Next_rem_block_dec + # load rounds - 10 (128), 12 (192), 14 (256) + lwz 23, 240(6) # n rounds + li 24, 0 # decrypt - li 15, 0 - std 15, 56(7) # clear partial? - stxvb16x 30+32, 0, 7 # update IV +__Process_decrypt: + # + # Process different blocks + # + ld 12, 56(7) cmpdi 12, 0 - beq aes_gcm_out - -Final_block_dec: - lwz 10, 240(6) - Loop_aes_middle_1x - - xxlor 23+32, 10, 10 - - cmpdi 10, 10 - beq Do_final_1x_dec + bgt __Do_combine_dec + cmpdi 5, 128 + blt __Process_more_dec + +# +# Process 8x AES/GCM blocks +# +__Process_8x_dec: + # 8x blcoks + li 10, 128 + divdu 12, 5, 10 # n 128 bytes-blocks - # 192 bits - xxlor 24+32, 11, 11 + addi 12, 12, -1 # loop - 1 - vcipher 15, 15, 23 - vcipher 15, 15, 24 + vmr 15, 30 # first state: IV + vadduwm 16, 15, 31 # state + counter + vadduwm 17, 16, 31 + vadduwm 18, 17, 31 + vadduwm 19, 18, 31 + vadduwm 20, 19, 31 + vadduwm 21, 20, 31 + vadduwm 22, 21, 31 + xxlor 9, 32+22, 32+22 # save last state - xxlor 23+32, 12, 12 + # vxor state, state, w # addroundkey + xxlor 32+29, 0, 0 + vxor 15, 15, 29 # IV + round key - add round key 0 + vxor 16, 16, 29 + vxor 17, 17, 29 + vxor 18, 18, 29 + vxor 19, 19, 29 + vxor 20, 20, 29 + vxor 21, 21, 29 + vxor 22, 22, 29 - cmpdi 10, 12 - beq Do_final_1x_dec + li 15, 16 + li 16, 32 + li 17, 48 + li 18, 64 + li 19, 80 + li 20, 96 + li 21, 112 - # 256 bits - xxlor 24+32, 13, 13 + # + # Pre-compute first 8 AES state and leave 1/3/5 more rounds + # for the loop. + # + addi 22, 23, -9 # process 8 keys + mtctr 22 # AES key loop + addi 10, 6, 144 - vcipher 15, 15, 23 - vcipher 15, 15, 24 + LOOP_8AES_STATE # process 8 AES keys - xxlor 23+32, 14, 14 +__PreLoop_aes_state_dec: + lxv 32+1, 0(10) # round key + AES_CIPHER_8x vcipher 15 1 + addi 10, 10, 16 + bdnz __PreLoop_aes_state_dec + lxv 32+1, 0(10) # last round key (v1) + + cmpdi 12, 0 # Only one loop (8 block) + beq __Finish_ghash_dec + +# +# Loop 8x blocks and compute ghash +# +__Loop_8x_block_dec: + vcipherlast 15, 15, 1 + vcipherlast 16, 16, 1 + vcipherlast 17, 17, 1 + vcipherlast 18, 18, 1 + vcipherlast 19, 19, 1 + vcipherlast 20, 20, 1 + vcipherlast 21, 21, 1 + vcipherlast 22, 22, 1 + + lxvb16x 32+23, 0, 14 # load block + lxvb16x 32+24, 15, 14 # load block + lxvb16x 32+25, 16, 14 # load block + lxvb16x 32+26, 17, 14 # load block + lxvb16x 32+27, 18, 14 # load block + lxvb16x 32+28, 19, 14 # load block + lxvb16x 32+29, 20, 14 # load block + lxvb16x 32+30, 21, 14 # load block + addi 14, 14, 128 + + vxor 15, 15, 23 + vxor 16, 16, 24 + vxor 17, 17, 25 + vxor 18, 18, 26 + vxor 19, 19, 27 + vxor 20, 20, 28 + vxor 21, 21, 29 + vxor 22, 22, 30 + + stxvb16x 47, 0, 9 # store output + stxvb16x 48, 15, 9 # store output + stxvb16x 49, 16, 9 # store output + stxvb16x 50, 17, 9 # store output + stxvb16x 51, 18, 9 # store output + stxvb16x 52, 19, 9 # store output + stxvb16x 53, 20, 9 # store output + stxvb16x 54, 21, 9 # store output + + addi 9, 9, 128 + + vmr 15, 23 + vmr 16, 24 + vmr 17, 25 + vmr 18, 26 + vmr 19, 27 + vmr 20, 28 + vmr 21, 29 + vmr 22, 30 - cmpdi 10, 14 - beq Do_final_1x_dec + # ghash here + vxor 15, 15, 0 + PPC_GHASH4x 0, 15, 16, 17, 18 + + vxor 19, 19, 0 + PPC_GHASH4x 0, 19, 20, 21, 22 + + xxlor 32+15, 9, 9 # last state + vadduwm 15, 15, 31 # state + counter + vadduwm 16, 15, 31 + vadduwm 17, 16, 31 + vadduwm 18, 17, 31 + vadduwm 19, 18, 31 + vadduwm 20, 19, 31 + vadduwm 21, 20, 31 + vadduwm 22, 21, 31 + xxlor 9, 32+22, 32+22 # save last state + + xxlor 32+27, 0, 0 # restore roundkey 0 + vxor 15, 15, 27 # IV + round key - add round key 0 + vxor 16, 16, 27 + vxor 17, 17, 27 + vxor 18, 18, 27 + vxor 19, 19, 27 + vxor 20, 20, 27 + vxor 21, 21, 27 + vxor 22, 22, 27 + + addi 5, 5, -128 + addi 11, 11, 128 -Do_final_1x_dec: - vcipherlast 15, 15, 23 + LOOP_8AES_STATE # process 8 AES keys + mtctr 22 # AES key loop + addi 10, 6, 144 +__LastLoop_aes_state_dec: + lxv 32+1, 0(10) # round key + AES_CIPHER_8x vcipher 15 1 + addi 10, 10, 16 + bdnz __LastLoop_aes_state_dec + lxv 32+1, 0(10) # last round key (v1) - # check partial block - li 21, 1 # decrypt - ld 15, 56(7) # partial? - cmpdi 15, 0 - beq Normal_block_dec - bl Do_partial_block + addi 12, 12, -1 cmpdi 12, 0 - ble aes_gcm_out - - b Continue_partial_check_dec + bne __Loop_8x_block_dec + +__Finish_ghash_dec: + vcipherlast 15, 15, 1 + vcipherlast 16, 16, 1 + vcipherlast 17, 17, 1 + vcipherlast 18, 18, 1 + vcipherlast 19, 19, 1 + vcipherlast 20, 20, 1 + vcipherlast 21, 21, 1 + vcipherlast 22, 22, 1 + + lxvb16x 32+23, 0, 14 # load block + lxvb16x 32+24, 15, 14 # load block + lxvb16x 32+25, 16, 14 # load block + lxvb16x 32+26, 17, 14 # load block + lxvb16x 32+27, 18, 14 # load block + lxvb16x 32+28, 19, 14 # load block + lxvb16x 32+29, 20, 14 # load block + lxvb16x 32+30, 21, 14 # load block + addi 14, 14, 128 + + vxor 15, 15, 23 + vxor 16, 16, 24 + vxor 17, 17, 25 + vxor 18, 18, 26 + vxor 19, 19, 27 + vxor 20, 20, 28 + vxor 21, 21, 29 + vxor 22, 22, 30 + + stxvb16x 47, 0, 9 # store output + stxvb16x 48, 15, 9 # store output + stxvb16x 49, 16, 9 # store output + stxvb16x 50, 17, 9 # store output + stxvb16x 51, 18, 9 # store output + stxvb16x 52, 19, 9 # store output + stxvb16x 53, 20, 9 # store output + stxvb16x 54, 21, 9 # store output + addi 9, 9, 128 + + #vmr 15, 23 + vxor 15, 23, 0 + vmr 16, 24 + vmr 17, 25 + vmr 18, 26 + vmr 19, 27 + vmr 20, 28 + vmr 21, 29 + vmr 22, 30 + + #vxor 15, 15, 0 + PPC_GHASH4x 0, 15, 16, 17, 18 + + vxor 19, 19, 0 + PPC_GHASH4x 0, 19, 20, 21, 22 + + xxlor 30+32, 9, 9 # last ctr + vadduwm 30, 30, 31 # increase ctr + stxvb16x 32+30, 0, 7 # update IV + stxvb16x 32+0, 0, 8 # update Xi + + addi 5, 5, -128 + addi 11, 11, 128 -Normal_block_dec: - lxvb16x 15, 0, 14 # load last block - xxlxor 47, 47, 15 + # + # Done 8x blocks + # - # create partial block mask - li 15, 16 - sub 15, 15, 12 # index to the mask + cmpdi 5, 0 + beq aes_gcm_out - vspltisb 16, -1 # first 16 bytes - 0xffff...ff - vspltisb 17, 0 # second 16 bytes - 0x0000...00 - li 10, 192 - stvx 16, 10, 1 - addi 10, 10, 16 - stvx 17, 10, 1 +__Process_more_dec: + li 24, 0 # decrypt + bl aes_gcm_crypt_1x + cmpdi 5, 0 + beq aes_gcm_out - addi 10, 1, 192 - lxvb16x 16, 15, 10 # load partial block mask - xxland 47, 47, 16 + bl __Process_partial + cmpdi 5, 0 + beq aes_gcm_out +__Do_combine_dec: + bl __Combine_partial + cmpdi 5, 0 + bgt __Process_decrypt + b aes_gcm_out +SYM_FUNC_END(aes_p10_gcm_decrypt) - xxland 32+28, 15, 16 - #vmr 28, 15 - ppc_update_hash_1x +SYM_FUNC_START_LOCAL(aes_gcm_out) - # * should store only the remaining bytes. - bl Write_partial_block + mr 3, 11 # return count - stxvb16x 30+32, 0, 7 # update IV - std 12, 56(7) # update partial? - li 16, 16 + RESTORE_REGS + blr - stxvb16x 32, 0, 8 # write out Xi - stxvb16x 32, 16, 8 # write out Xi - b aes_gcm_out +__Invalid_msg_len: + li 3, 0 + blr +SYM_FUNC_END(aes_gcm_out) + +SYM_DATA_START_LOCAL(PERMX) +.align 4 +# for vector permute and xor +permx: +.long 0x4c5d6e7f, 0x08192a3b, 0xc4d5e6f7, 0x8091a2b3 +SYM_DATA_END(permx) diff --git a/arch/powerpc/crypto/vmx.c b/arch/powerpc/crypto/vmx.c index 7eb713cc87c8ca..0b725e826388fe 100644 --- a/arch/powerpc/crypto/vmx.c +++ b/arch/powerpc/crypto/vmx.c @@ -74,4 +74,4 @@ MODULE_DESCRIPTION("IBM VMX cryptographic acceleration instructions " "support on Power 8"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0.0"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h deleted file mode 100644 index e7f14720f63072..00000000000000 --- a/arch/powerpc/include/asm/code-patching.h +++ /dev/null @@ -1,275 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _ASM_POWERPC_CODE_PATCHING_H -#define _ASM_POWERPC_CODE_PATCHING_H - -/* - * Copyright 2008, Michael Ellerman, IBM Corporation. - */ - -#include -#include -#include -#include -#include -#include - -/* Flags for create_branch: - * "b" == create_branch(addr, target, 0); - * "ba" == create_branch(addr, target, BRANCH_ABSOLUTE); - * "bl" == create_branch(addr, target, BRANCH_SET_LINK); - * "bla" == create_branch(addr, target, BRANCH_ABSOLUTE | BRANCH_SET_LINK); - */ -#define BRANCH_SET_LINK 0x1 -#define BRANCH_ABSOLUTE 0x2 - -/* - * Powerpc branch instruction is : - * - * 0 6 30 31 - * +---------+----------------+---+---+ - * | opcode | LI |AA |LK | - * +---------+----------------+---+---+ - * Where AA = 0 and LK = 0 - * - * LI is a signed 24 bits integer. The real branch offset is computed - * by: imm32 = SignExtend(LI:'0b00', 32); - * - * So the maximum forward branch should be: - * (0x007fffff << 2) = 0x01fffffc = 0x1fffffc - * The maximum backward branch should be: - * (0xff800000 << 2) = 0xfe000000 = -0x2000000 - */ -static inline bool is_offset_in_branch_range(long offset) -{ - return (offset >= -0x2000000 && offset <= 0x1fffffc && !(offset & 0x3)); -} - -static inline bool is_offset_in_cond_branch_range(long offset) -{ - return offset >= -0x8000 && offset <= 0x7fff && !(offset & 0x3); -} - -static inline int create_branch(ppc_inst_t *instr, const u32 *addr, - unsigned long target, int flags) -{ - long offset; - - *instr = ppc_inst(0); - offset = target; - if (! (flags & BRANCH_ABSOLUTE)) - offset = offset - (unsigned long)addr; - - /* Check we can represent the target in the instruction format */ - if (!is_offset_in_branch_range(offset)) - return 1; - - /* Mask out the flags and target, so they don't step on each other. */ - *instr = ppc_inst(0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC)); - - return 0; -} - -int create_cond_branch(ppc_inst_t *instr, const u32 *addr, - unsigned long target, int flags); -int patch_branch(u32 *addr, unsigned long target, int flags); -int patch_instruction(u32 *addr, ppc_inst_t instr); -int raw_patch_instruction(u32 *addr, ppc_inst_t instr); -int patch_instructions(u32 *addr, u32 *code, size_t len, bool repeat_instr); - -/* - * The data patching functions patch_uint() and patch_ulong(), etc., must be - * called on aligned addresses. - * - * The instruction patching functions patch_instruction() and similar must be - * called on addresses satisfying instruction alignment requirements. - */ - -#ifdef CONFIG_PPC64 - -int patch_uint(void *addr, unsigned int val); -int patch_ulong(void *addr, unsigned long val); - -#define patch_u64 patch_ulong - -#else - -static inline int patch_uint(void *addr, unsigned int val) -{ - if (!IS_ALIGNED((unsigned long)addr, sizeof(unsigned int))) - return -EINVAL; - - return patch_instruction(addr, ppc_inst(val)); -} - -static inline int patch_ulong(void *addr, unsigned long val) -{ - if (!IS_ALIGNED((unsigned long)addr, sizeof(unsigned long))) - return -EINVAL; - - return patch_instruction(addr, ppc_inst(val)); -} - -#endif - -#define patch_u32 patch_uint - -static inline unsigned long patch_site_addr(s32 *site) -{ - return (unsigned long)site + *site; -} - -static inline int patch_instruction_site(s32 *site, ppc_inst_t instr) -{ - return patch_instruction((u32 *)patch_site_addr(site), instr); -} - -static inline int patch_branch_site(s32 *site, unsigned long target, int flags) -{ - return patch_branch((u32 *)patch_site_addr(site), target, flags); -} - -static inline int modify_instruction(unsigned int *addr, unsigned int clr, - unsigned int set) -{ - return patch_instruction(addr, ppc_inst((*addr & ~clr) | set)); -} - -static inline int modify_instruction_site(s32 *site, unsigned int clr, unsigned int set) -{ - return modify_instruction((unsigned int *)patch_site_addr(site), clr, set); -} - -static inline unsigned int branch_opcode(ppc_inst_t instr) -{ - return ppc_inst_primary_opcode(instr) & 0x3F; -} - -static inline int instr_is_branch_iform(ppc_inst_t instr) -{ - return branch_opcode(instr) == 18; -} - -static inline int instr_is_branch_bform(ppc_inst_t instr) -{ - return branch_opcode(instr) == 16; -} - -int instr_is_relative_branch(ppc_inst_t instr); -int instr_is_relative_link_branch(ppc_inst_t instr); -unsigned long branch_target(const u32 *instr); -int translate_branch(ppc_inst_t *instr, const u32 *dest, const u32 *src); -bool is_conditional_branch(ppc_inst_t instr); - -#define OP_RT_RA_MASK 0xffff0000UL -#define LIS_R2 (PPC_RAW_LIS(_R2, 0)) -#define ADDIS_R2_R12 (PPC_RAW_ADDIS(_R2, _R12, 0)) -#define ADDI_R2_R2 (PPC_RAW_ADDI(_R2, _R2, 0)) - - -static inline unsigned long ppc_function_entry(void *func) -{ -#ifdef CONFIG_PPC64_ELF_ABI_V2 - u32 *insn = func; - - /* - * A PPC64 ABIv2 function may have a local and a global entry - * point. We need to use the local entry point when patching - * functions, so identify and step over the global entry point - * sequence. - * - * The global entry point sequence is always of the form: - * - * addis r2,r12,XXXX - * addi r2,r2,XXXX - * - * A linker optimisation may convert the addis to lis: - * - * lis r2,XXXX - * addi r2,r2,XXXX - */ - if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || - ((*insn & OP_RT_RA_MASK) == LIS_R2)) && - ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2)) - return (unsigned long)(insn + 2); - else - return (unsigned long)func; -#elif defined(CONFIG_PPC64_ELF_ABI_V1) - /* - * On PPC64 ABIv1 the function pointer actually points to the - * function's descriptor. The first entry in the descriptor is the - * address of the function text. - */ - return ((struct func_desc *)func)->addr; -#else - return (unsigned long)func; -#endif -} - -static inline unsigned long ppc_global_function_entry(void *func) -{ -#ifdef CONFIG_PPC64_ELF_ABI_V2 - /* PPC64 ABIv2 the global entry point is at the address */ - return (unsigned long)func; -#else - /* All other cases there is no change vs ppc_function_entry() */ - return ppc_function_entry(func); -#endif -} - -/* - * Wrapper around kallsyms_lookup() to return function entry address: - * - For ABIv1, we lookup the dot variant. - * - For ABIv2, we return the local entry point. - */ -static inline unsigned long ppc_kallsyms_lookup_name(const char *name) -{ - unsigned long addr; -#ifdef CONFIG_PPC64_ELF_ABI_V1 - /* check for dot variant */ - char dot_name[1 + KSYM_NAME_LEN]; - bool dot_appended = false; - - if (strnlen(name, KSYM_NAME_LEN) >= KSYM_NAME_LEN) - return 0; - - if (name[0] != '.') { - dot_name[0] = '.'; - dot_name[1] = '\0'; - strlcat(dot_name, name, sizeof(dot_name)); - dot_appended = true; - } else { - dot_name[0] = '\0'; - strlcat(dot_name, name, sizeof(dot_name)); - } - addr = kallsyms_lookup_name(dot_name); - if (!addr && dot_appended) - /* Let's try the original non-dot symbol lookup */ - addr = kallsyms_lookup_name(name); -#elif defined(CONFIG_PPC64_ELF_ABI_V2) - addr = kallsyms_lookup_name(name); - if (addr) - addr = ppc_function_entry((void *)addr); -#else - addr = kallsyms_lookup_name(name); -#endif - return addr; -} - -/* - * Some instruction encodings commonly used in dynamic ftracing - * and function live patching. - */ - -/* This must match the definition of STK_GOT in */ -#ifdef CONFIG_PPC64_ELF_ABI_V2 -#define R2_STACK_OFFSET 24 -#else -#define R2_STACK_OFFSET 40 -#endif - -#define PPC_INST_LD_TOC PPC_RAW_LD(_R2, _R1, R2_STACK_OFFSET) - -/* usually preceded by a mflr r0 */ -#define PPC_INST_STD_LR PPC_RAW_STD(_R0, _R1, PPC_LR_STKOFF) - -#endif /* _ASM_POWERPC_CODE_PATCHING_H */ diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 201218faed614b..29a529d2ab8b44 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -193,6 +193,7 @@ static inline void cpu_feature_keys_init(void) { } #define CPU_FTR_ARCH_31 LONG_ASM_CONST(0x0004000000000000) #define CPU_FTR_DAWR1 LONG_ASM_CONST(0x0008000000000000) #define CPU_FTR_DEXCR_NPHIE LONG_ASM_CONST(0x0010000000000000) +#define CPU_FTR_P11_PVR LONG_ASM_CONST(0x0020000000000000) #ifndef __ASSEMBLY__ @@ -454,7 +455,7 @@ static inline void cpu_feature_keys_init(void) { } CPU_FTR_DAWR | CPU_FTR_DAWR1 | \ CPU_FTR_DEXCR_NPHIE) -#define CPU_FTRS_POWER11 CPU_FTRS_POWER10 +#define CPU_FTRS_POWER11 (CPU_FTRS_POWER10 | CPU_FTR_P11_PVR) #define CPU_FTRS_CELL (CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ @@ -475,7 +476,7 @@ static inline void cpu_feature_keys_init(void) { } (CPU_FTRS_POWER7 | CPU_FTRS_POWER8E | CPU_FTRS_POWER8 | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_VSX_COMP | CPU_FTRS_POWER9 | \ CPU_FTRS_POWER9_DD2_1 | CPU_FTRS_POWER9_DD2_2 | \ - CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10) + CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11) #else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | \ @@ -483,7 +484,7 @@ static inline void cpu_feature_keys_init(void) { } CPU_FTRS_POWER8 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \ CPU_FTR_VSX_COMP | CPU_FTR_ALTIVEC_COMP | CPU_FTRS_POWER9 | \ CPU_FTRS_POWER9_DD2_1 | CPU_FTRS_POWER9_DD2_2 | \ - CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10) + CPU_FTRS_POWER9_DD2_3 | CPU_FTRS_POWER10 | CPU_FTRS_POWER11) #endif /* CONFIG_CPU_LITTLE_ENDIAN */ #endif #else @@ -547,7 +548,7 @@ enum { (CPU_FTRS_POSSIBLE & ~CPU_FTR_HVMODE & ~CPU_FTR_DBELL & \ CPU_FTRS_POWER7 & CPU_FTRS_POWER8E & CPU_FTRS_POWER8 & \ CPU_FTRS_POWER9 & CPU_FTRS_POWER9_DD2_1 & CPU_FTRS_POWER9_DD2_2 & \ - CPU_FTRS_POWER10 & CPU_FTRS_DT_CPU_BASE) + CPU_FTRS_POWER10 & CPU_FTRS_POWER11 & CPU_FTRS_DT_CPU_BASE) #else #define CPU_FTRS_ALWAYS \ (CPU_FTRS_PPC970 & CPU_FTRS_POWER5 & \ @@ -555,7 +556,7 @@ enum { CPU_FTRS_PA6T & CPU_FTRS_POWER8 & CPU_FTRS_POWER8E & \ ~CPU_FTR_HVMODE & ~CPU_FTR_DBELL & CPU_FTRS_POSSIBLE & \ CPU_FTRS_POWER9 & CPU_FTRS_POWER9_DD2_1 & CPU_FTRS_POWER9_DD2_2 & \ - CPU_FTRS_POWER10 & CPU_FTRS_DT_CPU_BASE) + CPU_FTRS_POWER10 & CPU_FTRS_POWER11 & CPU_FTRS_DT_CPU_BASE) #endif /* CONFIG_CPU_LITTLE_ENDIAN */ #endif #else diff --git a/arch/powerpc/include/asm/dtl.h b/arch/powerpc/include/asm/dtl.h index d6f43d149f8dcb..a5c21bc623cb00 100644 --- a/arch/powerpc/include/asm/dtl.h +++ b/arch/powerpc/include/asm/dtl.h @@ -1,8 +1,8 @@ #ifndef _ASM_POWERPC_DTL_H #define _ASM_POWERPC_DTL_H +#include #include -#include /* * Layout of entries in the hypervisor's dispatch trace log buffer. @@ -35,7 +35,7 @@ struct dtl_entry { #define DTL_LOG_ALL (DTL_LOG_CEDE | DTL_LOG_PREEMPT | DTL_LOG_FAULT) extern struct kmem_cache *dtl_cache; -extern rwlock_t dtl_access_lock; +extern struct rw_semaphore dtl_access_lock; extern void register_dtl_buffer(int cpu); extern void alloc_dtl_buffers(unsigned long *time_limit); diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h index ef40c9b6972a6e..a48f54dde4f656 100644 --- a/arch/powerpc/include/asm/fadump.h +++ b/arch/powerpc/include/asm/fadump.h @@ -19,6 +19,7 @@ extern int is_fadump_active(void); extern int should_fadump_crash(void); extern void crash_fadump(struct pt_regs *, const char *); extern void fadump_cleanup(void); +void fadump_setup_param_area(void); extern void fadump_append_bootargs(void); #else /* CONFIG_FA_DUMP */ @@ -26,6 +27,7 @@ static inline int is_fadump_active(void) { return 0; } static inline int should_fadump_crash(void) { return 0; } static inline void crash_fadump(struct pt_regs *regs, const char *str) { } static inline void fadump_cleanup(void) { } +static inline void fadump_setup_param_area(void) { } static inline void fadump_append_bootargs(void) { } #endif /* !CONFIG_FA_DUMP */ @@ -34,4 +36,11 @@ extern int early_init_dt_scan_fw_dump(unsigned long node, const char *uname, int depth, void *data); extern int fadump_reserve_mem(void); #endif + +#if defined(CONFIG_FA_DUMP) && defined(CONFIG_CMA) +void fadump_cma_init(void); +#else +static inline void fadump_cma_init(void) { } +#endif + #endif /* _ASM_POWERPC_FADUMP_H */ diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h index 559560286e6d01..db481b336bca44 100644 --- a/arch/powerpc/include/asm/ftrace.h +++ b/arch/powerpc/include/asm/ftrace.h @@ -24,7 +24,10 @@ unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip, struct module; struct dyn_ftrace; struct dyn_arch_ftrace { - struct module *mod; +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + /* pointer to the associated out-of-line stub */ + unsigned long ool_stub; +#endif }; #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS @@ -32,42 +35,21 @@ struct dyn_arch_ftrace { int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); #define ftrace_init_nop ftrace_init_nop -struct ftrace_regs { - struct pt_regs regs; -}; +#include static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) { /* We clear regs.msr in ftrace_call */ - return fregs->regs.msr ? &fregs->regs : NULL; + return arch_ftrace_regs(fregs)->regs.msr ? &arch_ftrace_regs(fregs)->regs : NULL; } static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) { - regs_set_return_ip(&fregs->regs, ip); + regs_set_return_ip(&arch_ftrace_regs(fregs)->regs, ip); } -static __always_inline unsigned long -ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs) -{ - return instruction_pointer(&fregs->regs); -} - -#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) - struct ftrace_ops; #define ftrace_graph_func ftrace_graph_func @@ -131,8 +113,36 @@ static inline u8 this_cpu_get_ftrace_enabled(void) { return 1; } #ifdef CONFIG_FUNCTION_TRACER extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[]; +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +struct ftrace_ool_stub { +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + struct ftrace_ops *ftrace_op; +#endif + u32 insn[4]; +} __aligned(sizeof(unsigned long)); +extern struct ftrace_ool_stub ftrace_ool_stub_text_end[], ftrace_ool_stub_text[], + ftrace_ool_stub_inittext[]; +extern unsigned int ftrace_ool_stub_text_end_count, ftrace_ool_stub_text_count, + ftrace_ool_stub_inittext_count; +#endif void ftrace_free_init_tramp(void); unsigned long ftrace_call_adjust(unsigned long addr); + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +/* + * When an ftrace registered caller is tracing a function that is also set by a + * register_ftrace_direct() call, it needs to be differentiated in the + * ftrace_caller trampoline so that the direct call can be invoked after the + * other ftrace ops. To do this, place the direct caller in the orig_gpr3 field + * of pt_regs. This tells ftrace_caller that there's a direct caller. + */ +static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr) +{ + struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; + + regs->orig_gpr3 = addr; +} +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ #else static inline void ftrace_free_init_tramp(void) { } static inline unsigned long ftrace_call_adjust(unsigned long addr) { return addr; } diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index 7a8495660c2f8d..65d1f291393d24 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -495,6 +495,7 @@ #define H_GUEST_CAP_COPY_MEM (1UL<<(63-0)) #define H_GUEST_CAP_POWER9 (1UL<<(63-1)) #define H_GUEST_CAP_POWER10 (1UL<<(63-2)) +#define H_GUEST_CAP_POWER11 (1UL<<(63-3)) #define H_GUEST_CAP_BITMAP2 (1UL<<(63-63)) #ifndef __ASSEMBLY__ diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 52e1b1d15ff63a..fd92ac4501693c 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -969,18 +969,6 @@ static inline void * phys_to_virt(unsigned long address) } #define phys_to_virt phys_to_virt -/* - * Change "struct page" to physical address. - */ -static inline phys_addr_t page_to_phys(struct page *page) -{ - unsigned long pfn = page_to_pfn(page); - - WARN_ON(IS_ENABLED(CONFIG_DEBUG_VIRTUAL) && !pfn_valid(pfn)); - - return PFN_PHYS(pfn); -} - /* * 32 bits still uses virt_to_bus() for its implementation of DMA * mappings se we have to keep it defined here. We also have some old diff --git a/arch/powerpc/include/asm/kfence.h b/arch/powerpc/include/asm/kfence.h index fab124ada1c7f2..1f7cab58ab2cb2 100644 --- a/arch/powerpc/include/asm/kfence.h +++ b/arch/powerpc/include/asm/kfence.h @@ -15,7 +15,7 @@ #define ARCH_FUNC_PREFIX "." #endif -#ifdef CONFIG_KFENCE +extern bool kfence_early_init; extern bool kfence_disabled; static inline void disable_kfence(void) @@ -27,7 +27,11 @@ static inline bool arch_kfence_init_pool(void) { return !kfence_disabled; } -#endif + +static inline bool kfence_early_init_enabled(void) +{ + return IS_ENABLED(CONFIG_KFENCE) && kfence_early_init; +} #ifdef CONFIG_PPC64 static inline bool kfence_protect_page(unsigned long addr, bool protect) diff --git a/arch/powerpc/include/asm/kprobes.h b/arch/powerpc/include/asm/kprobes.h index 4525a9c68260d9..dfe2e5ad3b216c 100644 --- a/arch/powerpc/include/asm/kprobes.h +++ b/arch/powerpc/include/asm/kprobes.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include #ifdef CONFIG_KPROBES #define __ARCH_WANT_KPROBES_INSN_SLOT diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 10618622d7efc9..e1ff291ba89106 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -203,7 +203,7 @@ extern bool kvmppc_hv_handle_set_rc(struct kvm *kvm, bool nested, extern int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, unsigned long gpa, struct kvm_memory_slot *memslot, - bool writing, bool kvm_ro, + bool writing, pte_t *inserted_pte, unsigned int *levelp); extern int kvmppc_init_vm_radix(struct kvm *kvm); extern void kvmppc_free_radix(struct kvm *kvm); @@ -235,7 +235,7 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr); extern int kvmppc_emulate_paired_single(struct kvm_vcpu *vcpu); extern kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, - bool writing, bool *writable); + bool writing, bool *writable, struct page **page); extern void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev, unsigned long *rmap, long pte_index, int realmode); extern void kvmppc_update_dirty_map(const struct kvm_memory_slot *memslot, diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 2ef9a5f4e5d14c..b936e174eefd1c 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -684,10 +684,16 @@ int kvmhv_nestedv2_set_ptbl_entry(unsigned long lpid, u64 dw0, u64 dw1); int kvmhv_nestedv2_parse_output(struct kvm_vcpu *vcpu); int kvmhv_nestedv2_set_vpa(struct kvm_vcpu *vcpu, unsigned long vpa); -int kmvhv_counters_tracepoint_regfunc(void); -void kmvhv_counters_tracepoint_unregfunc(void); +int kvmhv_counters_tracepoint_regfunc(void); +void kvmhv_counters_tracepoint_unregfunc(void); int kvmhv_get_l2_counters_status(void); void kvmhv_set_l2_counters_status(int cpu, bool status); +u64 kvmhv_get_l1_to_l2_cs_time(void); +u64 kvmhv_get_l2_to_l1_cs_time(void); +u64 kvmhv_get_l2_runtime_agg(void); +u64 kvmhv_get_l1_to_l2_cs_time_vcpu(void); +u64 kvmhv_get_l2_to_l1_cs_time_vcpu(void); +u64 kvmhv_get_l2_runtime_agg_vcpu(void); #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 37e581c5b20131..6e1108f8fce6fa 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -871,6 +871,11 @@ struct kvm_vcpu_arch { struct kvmhv_tb_accumulator cede_time; /* time napping inside guest */ #endif #endif /* CONFIG_KVM_BOOK3S_HV_EXIT_TIMING */ +#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE + u64 l1_to_l2_cs; + u64 l2_to_l1_cs; + u64 l2_runtime_agg; +#endif }; #define VCPU_FPR(vcpu, i) (vcpu)->arch.fp.fpr[i][TS_FPROFFSET] diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 1862f94335ee89..3298eec123a325 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -4,20 +4,24 @@ #ifdef __KERNEL__ #include -#include #include -#include #include +#include + +#include struct pt_regs; struct pci_bus; +struct device; struct device_node; struct iommu_table; struct rtc_time; struct file; +struct pci_dev; struct pci_controller; struct kimage; struct pci_host_bridge; +struct seq_file; struct machdep_calls { const char *name; diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index 300c777cc30759..e1ee5026ac4af4 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h @@ -35,9 +35,11 @@ struct mod_arch_specific { bool toc_fixed; /* Have we fixed up .TOC.? */ #endif +#ifdef CONFIG_PPC64_ELF_ABI_V1 /* For module function descriptor dereference */ unsigned long start_opd; unsigned long end_opd; +#endif #else /* powerpc64 */ /* Indices of PLT sections within module. */ unsigned int core_plt_section; @@ -47,6 +49,11 @@ struct mod_arch_specific { #ifdef CONFIG_DYNAMIC_FTRACE unsigned long tramp; unsigned long tramp_regs; +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + struct ftrace_ool_stub *ool_stubs; + unsigned int ool_stub_count; + unsigned int ool_stub_index; +#endif #endif }; diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index 83d0a4fc5f755a..af9a2628d1df05 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h @@ -21,8 +21,7 @@ * page size. When using 64K pages however, whether we are really supporting * 64K pages in HW or not is irrelevant to those definitions. */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT) +#include #ifndef __ASSEMBLY__ #ifndef CONFIG_HUGETLB_PAGE @@ -41,13 +40,6 @@ extern unsigned int hpage_shift; #define HUGE_MAX_HSTATE (MMU_PAGE_COUNT-1) #endif -/* - * Subtle: (1 << PAGE_SHIFT) is an int, not an unsigned long. So if we - * assign PAGE_MASK to a larger type it gets extended the way we want - * (i.e. with 1s in the high bits) - */ -#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) - /* * KERNELBASE is the virtual address of the start of the kernel, it's often * the same as PAGE_OFFSET, but _might not be_. diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index 5995614e906298..af0f46e2373bd7 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h @@ -102,8 +102,8 @@ struct power_pmu { int __init register_power_pmu(struct power_pmu *pmu); struct pt_regs; -extern unsigned long perf_misc_flags(struct pt_regs *regs); -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); extern unsigned long int read_bhrb(int n); /* @@ -111,7 +111,7 @@ extern unsigned long int read_bhrb(int n); * if we have hardware PMU support. */ #ifdef CONFIG_PPC_PERF_CTRS -#define perf_misc_flags(regs) perf_misc_flags(regs) +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #endif /* diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index b98a9e982c03b4..4312bcb913a422 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h @@ -587,12 +587,26 @@ #define PPC_RAW_MTSPR(spr, d) (0x7c0003a6 | ___PPC_RS(d) | __PPC_SPR(spr)) #define PPC_RAW_EIEIO() (0x7c0006ac) +/* bcl 20,31,$+4 */ +#define PPC_RAW_BCL4() (0x429f0005) #define PPC_RAW_BRANCH(offset) (0x48000000 | PPC_LI(offset)) #define PPC_RAW_BL(offset) (0x48000001 | PPC_LI(offset)) #define PPC_RAW_TW(t0, a, b) (0x7c000008 | ___PPC_RS(t0) | ___PPC_RA(a) | ___PPC_RB(b)) #define PPC_RAW_TRAP() PPC_RAW_TW(31, 0, 0) #define PPC_RAW_SETB(t, bfa) (0x7c000100 | ___PPC_RT(t) | ___PPC_RA((bfa) << 2)) +#ifdef CONFIG_PPC32 +#define PPC_RAW_STL PPC_RAW_STW +#define PPC_RAW_STLU PPC_RAW_STWU +#define PPC_RAW_LL PPC_RAW_LWZ +#define PPC_RAW_CMPLI PPC_RAW_CMPWI +#else +#define PPC_RAW_STL PPC_RAW_STD +#define PPC_RAW_STLU PPC_RAW_STDU +#define PPC_RAW_LL PPC_RAW_LD +#define PPC_RAW_CMPLI PPC_RAW_CMPDI +#endif + /* Deal with instructions that older assemblers aren't aware of */ #define PPC_BCCTR_FLUSH stringify_in_c(.long PPC_INST_BCCTR_FLUSH) #define PPC_CP_ABORT stringify_in_c(.long PPC_RAW_CP_ABORT) diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h index 9a025b776a4b37..9c8d5747755dae 100644 --- a/arch/powerpc/include/asm/set_memory.h +++ b/arch/powerpc/include/asm/set_memory.h @@ -12,37 +12,37 @@ int change_memory_attr(unsigned long addr, int numpages, long action); -static inline int set_memory_ro(unsigned long addr, int numpages) +static inline int __must_check set_memory_ro(unsigned long addr, int numpages) { return change_memory_attr(addr, numpages, SET_MEMORY_RO); } -static inline int set_memory_rw(unsigned long addr, int numpages) +static inline int __must_check set_memory_rw(unsigned long addr, int numpages) { return change_memory_attr(addr, numpages, SET_MEMORY_RW); } -static inline int set_memory_nx(unsigned long addr, int numpages) +static inline int __must_check set_memory_nx(unsigned long addr, int numpages) { return change_memory_attr(addr, numpages, SET_MEMORY_NX); } -static inline int set_memory_x(unsigned long addr, int numpages) +static inline int __must_check set_memory_x(unsigned long addr, int numpages) { return change_memory_attr(addr, numpages, SET_MEMORY_X); } -static inline int set_memory_np(unsigned long addr, int numpages) +static inline int __must_check set_memory_np(unsigned long addr, int numpages) { return change_memory_attr(addr, numpages, SET_MEMORY_NP); } -static inline int set_memory_p(unsigned long addr, int numpages) +static inline int __must_check set_memory_p(unsigned long addr, int numpages) { return change_memory_attr(addr, numpages, SET_MEMORY_P); } -static inline int set_memory_rox(unsigned long addr, int numpages) +static inline int __must_check set_memory_rox(unsigned long addr, int numpages) { return change_memory_attr(addr, numpages, SET_MEMORY_ROX); } diff --git a/arch/powerpc/include/asm/simple_spinlock_types.h b/arch/powerpc/include/asm/simple_spinlock_types.h index 08243338069d29..391fc19f727236 100644 --- a/arch/powerpc/include/asm/simple_spinlock_types.h +++ b/arch/powerpc/include/asm/simple_spinlock_types.h @@ -3,7 +3,7 @@ #define _ASM_POWERPC_SIMPLE_SPINLOCK_TYPES_H #ifndef __LINUX_SPINLOCK_TYPES_RAW_H -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif typedef struct { diff --git a/arch/powerpc/include/asm/spinlock_types.h b/arch/powerpc/include/asm/spinlock_types.h index 40b01446cf755e..569765fa16bc4e 100644 --- a/arch/powerpc/include/asm/spinlock_types.h +++ b/arch/powerpc/include/asm/spinlock_types.h @@ -3,7 +3,7 @@ #define _ASM_POWERPC_SPINLOCK_TYPES_H #ifndef __LINUX_SPINLOCK_TYPES_RAW_H -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif #ifdef CONFIG_PPC_QUEUED_SPINLOCKS diff --git a/arch/powerpc/include/asm/spu_priv1.h b/arch/powerpc/include/asm/spu_priv1.h index 2167d756e6d59a..6fee411d973d91 100644 --- a/arch/powerpc/include/asm/spu_priv1.h +++ b/arch/powerpc/include/asm/spu_priv1.h @@ -216,7 +216,6 @@ spu_disable_spu (struct spu_context *ctx) */ extern const struct spu_priv1_ops spu_priv1_mmio_ops; -extern const struct spu_priv1_ops spu_priv1_beat_ops; extern const struct spu_management_ops spu_management_of_ops; diff --git a/arch/powerpc/include/asm/sstep.h b/arch/powerpc/include/asm/sstep.h index 50950deedb8734..e3d0e714ff280e 100644 --- a/arch/powerpc/include/asm/sstep.h +++ b/arch/powerpc/include/asm/sstep.h @@ -173,9 +173,4 @@ int emulate_step(struct pt_regs *regs, ppc_inst_t instr); */ extern int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op); -extern void emulate_vsx_load(struct instruction_op *op, union vsx_reg *reg, - const void *mem, bool cross_endian); -extern void emulate_vsx_store(struct instruction_op *op, - const union vsx_reg *reg, void *mem, - bool cross_endian); extern int emulate_dcbz(unsigned long ea, struct pt_regs *regs); diff --git a/arch/powerpc/include/asm/systemcfg.h b/arch/powerpc/include/asm/systemcfg.h new file mode 100644 index 00000000000000..2f9b1d6a5c98d1 --- /dev/null +++ b/arch/powerpc/include/asm/systemcfg.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _SYSTEMCFG_H +#define _SYSTEMCFG_H + +/* + * Copyright (C) 2002 Peter Bergner , IBM + * Copyright (C) 2005 Benjamin Herrenschmidy , + * IBM Corp. + */ + +#ifdef CONFIG_PPC64 + +/* + * If the major version changes we are incompatible. + * Minor version changes are a hint. + */ +#define SYSTEMCFG_MAJOR 1 +#define SYSTEMCFG_MINOR 1 + +#include + +struct systemcfg { + __u8 eye_catcher[16]; /* Eyecatcher: SYSTEMCFG:PPC64 0x00 */ + struct { /* Systemcfg version numbers */ + __u32 major; /* Major number 0x10 */ + __u32 minor; /* Minor number 0x14 */ + } version; + + /* Note about the platform flags: it now only contains the lpar + * bit. The actual platform number is dead and buried + */ + __u32 platform; /* Platform flags 0x18 */ + __u32 processor; /* Processor type 0x1C */ + __u64 processorCount; /* # of physical processors 0x20 */ + __u64 physicalMemorySize; /* Size of real memory(B) 0x28 */ + __u64 tb_orig_stamp; /* (NU) Timebase at boot 0x30 */ + __u64 tb_ticks_per_sec; /* Timebase tics / sec 0x38 */ + __u64 tb_to_xs; /* (NU) Inverse of TB to 2^20 0x40 */ + __u64 stamp_xsec; /* (NU) 0x48 */ + __u64 tb_update_count; /* (NU) Timebase atomicity ctr 0x50 */ + __u32 tz_minuteswest; /* (NU) Min. west of Greenwich 0x58 */ + __u32 tz_dsttime; /* (NU) Type of dst correction 0x5C */ + __u32 dcache_size; /* L1 d-cache size 0x60 */ + __u32 dcache_line_size; /* L1 d-cache line size 0x64 */ + __u32 icache_size; /* L1 i-cache size 0x68 */ + __u32 icache_line_size; /* L1 i-cache line size 0x6C */ +}; + +extern struct systemcfg *systemcfg; + +#endif /* CONFIG_PPC64 */ +#endif /* _SYSTEMCFG_H */ diff --git a/arch/powerpc/include/asm/text-patching.h b/arch/powerpc/include/asm/text-patching.h new file mode 100644 index 00000000000000..e7f14720f63072 --- /dev/null +++ b/arch/powerpc/include/asm/text-patching.h @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _ASM_POWERPC_CODE_PATCHING_H +#define _ASM_POWERPC_CODE_PATCHING_H + +/* + * Copyright 2008, Michael Ellerman, IBM Corporation. + */ + +#include +#include +#include +#include +#include +#include + +/* Flags for create_branch: + * "b" == create_branch(addr, target, 0); + * "ba" == create_branch(addr, target, BRANCH_ABSOLUTE); + * "bl" == create_branch(addr, target, BRANCH_SET_LINK); + * "bla" == create_branch(addr, target, BRANCH_ABSOLUTE | BRANCH_SET_LINK); + */ +#define BRANCH_SET_LINK 0x1 +#define BRANCH_ABSOLUTE 0x2 + +/* + * Powerpc branch instruction is : + * + * 0 6 30 31 + * +---------+----------------+---+---+ + * | opcode | LI |AA |LK | + * +---------+----------------+---+---+ + * Where AA = 0 and LK = 0 + * + * LI is a signed 24 bits integer. The real branch offset is computed + * by: imm32 = SignExtend(LI:'0b00', 32); + * + * So the maximum forward branch should be: + * (0x007fffff << 2) = 0x01fffffc = 0x1fffffc + * The maximum backward branch should be: + * (0xff800000 << 2) = 0xfe000000 = -0x2000000 + */ +static inline bool is_offset_in_branch_range(long offset) +{ + return (offset >= -0x2000000 && offset <= 0x1fffffc && !(offset & 0x3)); +} + +static inline bool is_offset_in_cond_branch_range(long offset) +{ + return offset >= -0x8000 && offset <= 0x7fff && !(offset & 0x3); +} + +static inline int create_branch(ppc_inst_t *instr, const u32 *addr, + unsigned long target, int flags) +{ + long offset; + + *instr = ppc_inst(0); + offset = target; + if (! (flags & BRANCH_ABSOLUTE)) + offset = offset - (unsigned long)addr; + + /* Check we can represent the target in the instruction format */ + if (!is_offset_in_branch_range(offset)) + return 1; + + /* Mask out the flags and target, so they don't step on each other. */ + *instr = ppc_inst(0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC)); + + return 0; +} + +int create_cond_branch(ppc_inst_t *instr, const u32 *addr, + unsigned long target, int flags); +int patch_branch(u32 *addr, unsigned long target, int flags); +int patch_instruction(u32 *addr, ppc_inst_t instr); +int raw_patch_instruction(u32 *addr, ppc_inst_t instr); +int patch_instructions(u32 *addr, u32 *code, size_t len, bool repeat_instr); + +/* + * The data patching functions patch_uint() and patch_ulong(), etc., must be + * called on aligned addresses. + * + * The instruction patching functions patch_instruction() and similar must be + * called on addresses satisfying instruction alignment requirements. + */ + +#ifdef CONFIG_PPC64 + +int patch_uint(void *addr, unsigned int val); +int patch_ulong(void *addr, unsigned long val); + +#define patch_u64 patch_ulong + +#else + +static inline int patch_uint(void *addr, unsigned int val) +{ + if (!IS_ALIGNED((unsigned long)addr, sizeof(unsigned int))) + return -EINVAL; + + return patch_instruction(addr, ppc_inst(val)); +} + +static inline int patch_ulong(void *addr, unsigned long val) +{ + if (!IS_ALIGNED((unsigned long)addr, sizeof(unsigned long))) + return -EINVAL; + + return patch_instruction(addr, ppc_inst(val)); +} + +#endif + +#define patch_u32 patch_uint + +static inline unsigned long patch_site_addr(s32 *site) +{ + return (unsigned long)site + *site; +} + +static inline int patch_instruction_site(s32 *site, ppc_inst_t instr) +{ + return patch_instruction((u32 *)patch_site_addr(site), instr); +} + +static inline int patch_branch_site(s32 *site, unsigned long target, int flags) +{ + return patch_branch((u32 *)patch_site_addr(site), target, flags); +} + +static inline int modify_instruction(unsigned int *addr, unsigned int clr, + unsigned int set) +{ + return patch_instruction(addr, ppc_inst((*addr & ~clr) | set)); +} + +static inline int modify_instruction_site(s32 *site, unsigned int clr, unsigned int set) +{ + return modify_instruction((unsigned int *)patch_site_addr(site), clr, set); +} + +static inline unsigned int branch_opcode(ppc_inst_t instr) +{ + return ppc_inst_primary_opcode(instr) & 0x3F; +} + +static inline int instr_is_branch_iform(ppc_inst_t instr) +{ + return branch_opcode(instr) == 18; +} + +static inline int instr_is_branch_bform(ppc_inst_t instr) +{ + return branch_opcode(instr) == 16; +} + +int instr_is_relative_branch(ppc_inst_t instr); +int instr_is_relative_link_branch(ppc_inst_t instr); +unsigned long branch_target(const u32 *instr); +int translate_branch(ppc_inst_t *instr, const u32 *dest, const u32 *src); +bool is_conditional_branch(ppc_inst_t instr); + +#define OP_RT_RA_MASK 0xffff0000UL +#define LIS_R2 (PPC_RAW_LIS(_R2, 0)) +#define ADDIS_R2_R12 (PPC_RAW_ADDIS(_R2, _R12, 0)) +#define ADDI_R2_R2 (PPC_RAW_ADDI(_R2, _R2, 0)) + + +static inline unsigned long ppc_function_entry(void *func) +{ +#ifdef CONFIG_PPC64_ELF_ABI_V2 + u32 *insn = func; + + /* + * A PPC64 ABIv2 function may have a local and a global entry + * point. We need to use the local entry point when patching + * functions, so identify and step over the global entry point + * sequence. + * + * The global entry point sequence is always of the form: + * + * addis r2,r12,XXXX + * addi r2,r2,XXXX + * + * A linker optimisation may convert the addis to lis: + * + * lis r2,XXXX + * addi r2,r2,XXXX + */ + if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || + ((*insn & OP_RT_RA_MASK) == LIS_R2)) && + ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2)) + return (unsigned long)(insn + 2); + else + return (unsigned long)func; +#elif defined(CONFIG_PPC64_ELF_ABI_V1) + /* + * On PPC64 ABIv1 the function pointer actually points to the + * function's descriptor. The first entry in the descriptor is the + * address of the function text. + */ + return ((struct func_desc *)func)->addr; +#else + return (unsigned long)func; +#endif +} + +static inline unsigned long ppc_global_function_entry(void *func) +{ +#ifdef CONFIG_PPC64_ELF_ABI_V2 + /* PPC64 ABIv2 the global entry point is at the address */ + return (unsigned long)func; +#else + /* All other cases there is no change vs ppc_function_entry() */ + return ppc_function_entry(func); +#endif +} + +/* + * Wrapper around kallsyms_lookup() to return function entry address: + * - For ABIv1, we lookup the dot variant. + * - For ABIv2, we return the local entry point. + */ +static inline unsigned long ppc_kallsyms_lookup_name(const char *name) +{ + unsigned long addr; +#ifdef CONFIG_PPC64_ELF_ABI_V1 + /* check for dot variant */ + char dot_name[1 + KSYM_NAME_LEN]; + bool dot_appended = false; + + if (strnlen(name, KSYM_NAME_LEN) >= KSYM_NAME_LEN) + return 0; + + if (name[0] != '.') { + dot_name[0] = '.'; + dot_name[1] = '\0'; + strlcat(dot_name, name, sizeof(dot_name)); + dot_appended = true; + } else { + dot_name[0] = '\0'; + strlcat(dot_name, name, sizeof(dot_name)); + } + addr = kallsyms_lookup_name(dot_name); + if (!addr && dot_appended) + /* Let's try the original non-dot symbol lookup */ + addr = kallsyms_lookup_name(name); +#elif defined(CONFIG_PPC64_ELF_ABI_V2) + addr = kallsyms_lookup_name(name); + if (addr) + addr = ppc_function_entry((void *)addr); +#else + addr = kallsyms_lookup_name(name); +#endif + return addr; +} + +/* + * Some instruction encodings commonly used in dynamic ftracing + * and function live patching. + */ + +/* This must match the definition of STK_GOT in */ +#ifdef CONFIG_PPC64_ELF_ABI_V2 +#define R2_STACK_OFFSET 24 +#else +#define R2_STACK_OFFSET 40 +#endif + +#define PPC_INST_LD_TOC PPC_RAW_LD(_R2, _R1, R2_STACK_OFFSET) + +/* usually preceded by a mflr r0 */ +#define PPC_INST_STD_LR PPC_RAW_STD(_R0, _R1, PPC_LR_STKOFF) + +#endif /* _ASM_POWERPC_CODE_PATCHING_H */ diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h index 289023f7a65671..a8681b12864fd9 100644 --- a/arch/powerpc/include/asm/udbg.h +++ b/arch/powerpc/include/asm/udbg.h @@ -38,7 +38,6 @@ void __init udbg_early_init(void); void __init udbg_init_debug_lpar(void); void __init udbg_init_debug_lpar_hvsi(void); void __init udbg_init_pmac_realmode(void); -void __init udbg_init_maple_realmode(void); void __init udbg_init_pas_realmode(void); void __init udbg_init_rtas_panel(void); void __init udbg_init_rtas_console(void); diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h index 7650b6ce14c85a..8d972bc98b55fe 100644 --- a/arch/powerpc/include/asm/vdso.h +++ b/arch/powerpc/include/asm/vdso.h @@ -25,6 +25,7 @@ int vdso_getcpu_init(void); #ifdef __VDSO64__ #define V_FUNCTION_BEGIN(name) \ .globl name; \ + .type name,@function; \ name: \ #define V_FUNCTION_END(name) \ diff --git a/arch/powerpc/include/asm/vdso/getrandom.h b/arch/powerpc/include/asm/vdso/getrandom.h index 501d6bb14e8a72..80ce0709725eb8 100644 --- a/arch/powerpc/include/asm/vdso/getrandom.h +++ b/arch/powerpc/include/asm/vdso/getrandom.h @@ -7,6 +7,8 @@ #ifndef __ASSEMBLY__ +#include + static __always_inline int do_syscall_3(const unsigned long _r0, const unsigned long _r3, const unsigned long _r4, const unsigned long _r5) { @@ -43,11 +45,21 @@ static __always_inline ssize_t getrandom_syscall(void *buffer, size_t len, unsig static __always_inline struct vdso_rng_data *__arch_get_vdso_rng_data(void) { - return NULL; + struct vdso_arch_data *data; + + asm ( + " bcl 20, 31, .+4 ;" + "0: mflr %0 ;" + " addis %0, %0, (_vdso_datapage - 0b)@ha ;" + " addi %0, %0, (_vdso_datapage - 0b)@l ;" + : "=r" (data) : : "lr" + ); + + return &data->rng_data; } ssize_t __c_kernel_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, - size_t opaque_len, const struct vdso_rng_data *vd); + size_t opaque_len); #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/include/asm/vdso/vsyscall.h b/arch/powerpc/include/asm/vdso/vsyscall.h index 92f480d8cc6dcb..48560a11955956 100644 --- a/arch/powerpc/include/asm/vdso/vsyscall.h +++ b/arch/powerpc/include/asm/vdso/vsyscall.h @@ -4,12 +4,8 @@ #ifndef __ASSEMBLY__ -#include #include -/* - * Update the vDSO data page to keep in sync with kernel timekeeping. - */ static __always_inline struct vdso_data *__arch_get_k_vdso_data(void) { diff --git a/arch/powerpc/include/asm/vdso_datapage.h b/arch/powerpc/include/asm/vdso_datapage.h index 248dee138f7bf5..a202f5b6347953 100644 --- a/arch/powerpc/include/asm/vdso_datapage.h +++ b/arch/powerpc/include/asm/vdso_datapage.h @@ -9,29 +9,6 @@ * IBM Corp. */ - -/* - * Note about this structure: - * - * This structure was historically called systemcfg and exposed to - * userland via /proc/ppc64/systemcfg. Unfortunately, this became an - * ABI issue as some proprietary software started relying on being able - * to mmap() it, thus we have to keep the base layout at least for a - * few kernel versions. - * - * However, since ppc32 doesn't suffer from this backward handicap, - * a simpler version of the data structure is used there with only the - * fields actually used by the vDSO. - * - */ - -/* - * If the major version changes we are incompatible. - * Minor version changes are a hint. - */ -#define SYSTEMCFG_MAJOR 1 -#define SYSTEMCFG_MINOR 1 - #ifndef __ASSEMBLY__ #include @@ -40,41 +17,10 @@ #define SYSCALL_MAP_SIZE ((NR_syscalls + 31) / 32) -/* - * So here is the ppc64 backward compatible version - */ - #ifdef CONFIG_PPC64 struct vdso_arch_data { - __u8 eye_catcher[16]; /* Eyecatcher: SYSTEMCFG:PPC64 0x00 */ - struct { /* Systemcfg version numbers */ - __u32 major; /* Major number 0x10 */ - __u32 minor; /* Minor number 0x14 */ - } version; - - /* Note about the platform flags: it now only contains the lpar - * bit. The actual platform number is dead and buried - */ - __u32 platform; /* Platform flags 0x18 */ - __u32 processor; /* Processor type 0x1C */ - __u64 processorCount; /* # of physical processors 0x20 */ - __u64 physicalMemorySize; /* Size of real memory(B) 0x28 */ - __u64 tb_orig_stamp; /* (NU) Timebase at boot 0x30 */ - __u64 tb_ticks_per_sec; /* Timebase tics / sec 0x38 */ - __u64 tb_to_xs; /* (NU) Inverse of TB to 2^20 0x40 */ - __u64 stamp_xsec; /* (NU) 0x48 */ - __u64 tb_update_count; /* (NU) Timebase atomicity ctr 0x50 */ - __u32 tz_minuteswest; /* (NU) Min. west of Greenwich 0x58 */ - __u32 tz_dsttime; /* (NU) Type of dst correction 0x5C */ - __u32 dcache_size; /* L1 d-cache size 0x60 */ - __u32 dcache_line_size; /* L1 d-cache line size 0x64 */ - __u32 icache_size; /* L1 i-cache size 0x68 */ - __u32 icache_line_size; /* L1 i-cache line size 0x6C */ - - /* those additional ones don't have to be located anywhere - * special as they were not part of the original systemcfg - */ + __u64 tb_ticks_per_sec; /* Timebase tics / sec */ __u32 dcache_block_size; /* L1 d-cache block size */ __u32 icache_block_size; /* L1 i-cache block size */ __u32 dcache_log_block_size; /* L1 d-cache log block size */ @@ -82,21 +28,20 @@ struct vdso_arch_data { __u32 syscall_map[SYSCALL_MAP_SIZE]; /* Map of syscalls */ __u32 compat_syscall_map[SYSCALL_MAP_SIZE]; /* Map of compat syscalls */ - struct vdso_data data[CS_BASES]; struct vdso_rng_data rng_data; + + struct vdso_data data[CS_BASES] __aligned(1 << CONFIG_PAGE_SHIFT); }; #else /* CONFIG_PPC64 */ -/* - * And here is the simpler 32 bits version - */ struct vdso_arch_data { - __u64 tb_ticks_per_sec; /* Timebase tics / sec 0x38 */ + __u64 tb_ticks_per_sec; /* Timebase tics / sec */ __u32 syscall_map[SYSCALL_MAP_SIZE]; /* Map of syscalls */ __u32 compat_syscall_map[0]; /* No compat syscalls on PPC32 */ - struct vdso_data data[CS_BASES]; struct vdso_rng_data rng_data; + + struct vdso_data data[CS_BASES] __aligned(1 << CONFIG_PAGE_SHIFT); }; #endif /* CONFIG_PPC64 */ @@ -105,29 +50,17 @@ extern struct vdso_arch_data *vdso_data; #else /* __ASSEMBLY__ */ -.macro get_datapage ptr +.macro get_datapage ptr offset=0 bcl 20, 31, .+4 999: mflr \ptr - addis \ptr, \ptr, (_vdso_datapage - 999b)@ha - addi \ptr, \ptr, (_vdso_datapage - 999b)@l + addis \ptr, \ptr, (_vdso_datapage - 999b + \offset)@ha + addi \ptr, \ptr, (_vdso_datapage - 999b + \offset)@l .endm #include #include -.macro get_realdatapage ptr scratch - get_datapage \ptr -#ifdef CONFIG_TIME_NS - lwz \scratch, VDSO_CLOCKMODE_OFFSET(\ptr) - xoris \scratch, \scratch, VDSO_CLOCKMODE_TIMENS@h - xori \scratch, \scratch, VDSO_CLOCKMODE_TIMENS@l - cntlzw \scratch, \scratch - rlwinm \scratch, \scratch, PAGE_SHIFT - 5, 1 << PAGE_SHIFT - add \ptr, \ptr, \scratch -#endif -.endm - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/vga.h b/arch/powerpc/include/asm/vga.h index fcf721682a7119..f2dc40e1c52ae1 100644 --- a/arch/powerpc/include/asm/vga.h +++ b/arch/powerpc/include/asm/vga.h @@ -40,11 +40,6 @@ static inline void scr_memsetw(u16 *s, u16 v, unsigned int n) memset16(s, cpu_to_le16(v), n / 2); } -#define VT_BUF_HAVE_MEMCPYW -#define VT_BUF_HAVE_MEMMOVEW -#define scr_memcpyw memcpy -#define scr_memmovew memmove - #endif /* !CONFIG_VGA_CONSOLE && !CONFIG_MDA_CONSOLE */ #ifdef __powerpc64__ diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 131a8cc10dbe8d..7a390bd4f4af3c 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -335,7 +335,6 @@ int main(void) /* datapage offsets for use by vdso */ OFFSET(VDSO_DATA_OFFSET, vdso_arch_data, data); - OFFSET(VDSO_RNG_DATA_OFFSET, vdso_arch_data, rng_data); OFFSET(CFG_TB_TICKS_PER_SEC, vdso_arch_data, tb_ticks_per_sec); #ifdef CONFIG_PPC64 OFFSET(CFG_ICACHE_BLOCKSZ, vdso_arch_data, icache_block_size); @@ -347,8 +346,6 @@ int main(void) #else OFFSET(CFG_SYSCALL_MAP32, vdso_arch_data, syscall_map); #endif - OFFSET(VDSO_CLOCKMODE_OFFSET, vdso_arch_data, data[0].clock_mode); - DEFINE(VDSO_CLOCKMODE_TIMENS, VDSO_CLOCKMODE_TIMENS); #ifdef CONFIG_BUG DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); @@ -597,7 +594,6 @@ int main(void) HSTATE_FIELD(HSTATE_DABR, dabr); HSTATE_FIELD(HSTATE_DECEXP, dec_expires); HSTATE_FIELD(HSTATE_SPLIT_MODE, kvm_split_mode); - DEFINE(IPI_PRIORITY, IPI_PRIORITY); OFFSET(KVM_SPLIT_RPR, kvm_split_mode, rpr); OFFSET(KVM_SPLIT_PMMAR, kvm_split_mode, pmmar); OFFSET(KVM_SPLIT_LDBAR, kvm_split_mode, ldbar); @@ -677,5 +673,16 @@ int main(void) DEFINE(BPT_SIZE, BPT_SIZE); #endif +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + DEFINE(FTRACE_OOL_STUB_SIZE, sizeof(struct ftrace_ool_stub)); +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + OFFSET(FTRACE_OPS_FUNC, ftrace_ops, func); +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + OFFSET(FTRACE_OPS_DIRECT_CALL, ftrace_ops, direct_call); +#endif +#endif + return 0; } diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 2086fa6cdc25bf..103b6605dd68f8 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index af4263594eb2c9..1bee15c013e75f 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -867,7 +867,7 @@ bool __init dt_cpu_ftrs_init(void *fdt) using_dt_cpu_ftrs = false; /* Setup and verify the FDT, if it fails we just bail */ - if (!early_init_dt_verify(fdt)) + if (!early_init_dt_verify(fdt, __pa(fdt))) return false; if (!of_scan_flat_dt(fdt_find_cpu_features, NULL)) diff --git a/arch/powerpc/kernel/epapr_paravirt.c b/arch/powerpc/kernel/epapr_paravirt.c index d4b8aff2081567..247ab2acaccca9 100644 --- a/arch/powerpc/kernel/epapr_paravirt.c +++ b/arch/powerpc/kernel/epapr_paravirt.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index a612e7513a4f8a..4b371c738213c9 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -78,26 +78,38 @@ static struct cma *fadump_cma; * But for some reason even if it fails we still have the memory reservation * with us and we can still continue doing fadump. */ -static int __init fadump_cma_init(void) +void __init fadump_cma_init(void) { - unsigned long long base, size; + unsigned long long base, size, end; int rc; - if (!fw_dump.fadump_enabled) - return 0; - + if (!fw_dump.fadump_supported || !fw_dump.fadump_enabled || + fw_dump.dump_active) + return; /* * Do not use CMA if user has provided fadump=nocma kernel parameter. - * Return 1 to continue with fadump old behaviour. */ - if (fw_dump.nocma) - return 1; + if (fw_dump.nocma || !fw_dump.boot_memory_size) + return; + /* + * [base, end) should be reserved during early init in + * fadump_reserve_mem(). No need to check this here as + * cma_init_reserved_mem() already checks for overlap. + * Here we give the aligned chunk of this reserved memory to CMA. + */ base = fw_dump.reserve_dump_area_start; size = fw_dump.boot_memory_size; + end = base + size; - if (!size) - return 0; + base = ALIGN(base, CMA_MIN_ALIGNMENT_BYTES); + end = ALIGN_DOWN(end, CMA_MIN_ALIGNMENT_BYTES); + size = end - base; + + if (end <= base) { + pr_warn("%s: Too less memory to give to CMA\n", __func__); + return; + } rc = cma_init_reserved_mem(base, size, 0, "fadump_cma", &fadump_cma); if (rc) { @@ -108,7 +120,7 @@ static int __init fadump_cma_init(void) * blocked from production system usage. Hence return 1, * so that we can continue with fadump. */ - return 1; + return; } /* @@ -120,15 +132,13 @@ static int __init fadump_cma_init(void) /* * So we now have successfully initialized cma area for fadump. */ - pr_info("Initialized 0x%lx bytes cma area at %ldMB from 0x%lx " + pr_info("Initialized [0x%llx, %luMB] cma area from [0x%lx, %luMB] " "bytes of memory reserved for firmware-assisted dump\n", - cma_get_size(fadump_cma), - (unsigned long)cma_get_base(fadump_cma) >> 20, - fw_dump.reserve_dump_area_size); - return 1; + cma_get_base(fadump_cma), cma_get_size(fadump_cma) >> 20, + fw_dump.reserve_dump_area_start, + fw_dump.boot_memory_size >> 20); + return; } -#else -static int __init fadump_cma_init(void) { return 1; } #endif /* CONFIG_CMA */ /* @@ -143,7 +153,7 @@ void __init fadump_append_bootargs(void) if (!fw_dump.dump_active || !fw_dump.param_area_supported || !fw_dump.param_area) return; - if (fw_dump.param_area >= fw_dump.boot_mem_top) { + if (fw_dump.param_area < fw_dump.boot_mem_top) { if (memblock_reserve(fw_dump.param_area, COMMAND_LINE_SIZE)) { pr_warn("WARNING: Can't use additional parameters area!\n"); fw_dump.param_area = 0; @@ -558,13 +568,6 @@ int __init fadump_reserve_mem(void) if (!fw_dump.dump_active) { fw_dump.boot_memory_size = PAGE_ALIGN(fadump_calculate_reserve_size()); -#ifdef CONFIG_CMA - if (!fw_dump.nocma) { - fw_dump.boot_memory_size = - ALIGN(fw_dump.boot_memory_size, - CMA_MIN_ALIGNMENT_BYTES); - } -#endif bootmem_min = fw_dump.ops->fadump_get_bootmem_min(); if (fw_dump.boot_memory_size < bootmem_min) { @@ -637,8 +640,6 @@ int __init fadump_reserve_mem(void) pr_info("Reserved %lldMB of memory at %#016llx (System RAM: %lldMB)\n", (size >> 20), base, (memblock_phys_mem_size() >> 20)); - - ret = fadump_cma_init(); } return ret; @@ -1586,6 +1587,12 @@ static void __init fadump_init_files(void) return; } + if (fw_dump.param_area) { + rc = sysfs_create_file(fadump_kobj, &bootargs_append_attr.attr); + if (rc) + pr_err("unable to create bootargs_append sysfs file (%d)\n", rc); + } + debugfs_create_file("fadump_region", 0444, arch_debugfs_dir, NULL, &fadump_region_fops); @@ -1740,7 +1747,7 @@ static void __init fadump_process(void) * Reserve memory to store additional parameters to be passed * for fadump/capture kernel. */ -static void __init fadump_setup_param_area(void) +void __init fadump_setup_param_area(void) { phys_addr_t range_start, range_end; @@ -1748,7 +1755,7 @@ static void __init fadump_setup_param_area(void) return; /* This memory can't be used by PFW or bootloader as it is shared across kernels */ - if (radix_enabled()) { + if (early_radix_enabled()) { /* * Anywhere in the upper half should be good enough as all memory * is accessible in real mode. @@ -1776,12 +1783,12 @@ static void __init fadump_setup_param_area(void) COMMAND_LINE_SIZE, range_start, range_end); - if (!fw_dump.param_area || sysfs_create_file(fadump_kobj, &bootargs_append_attr.attr)) { + if (!fw_dump.param_area) { pr_warn("WARNING: Could not setup area to pass additional parameters!\n"); return; } - memset(phys_to_virt(fw_dump.param_area), 0, COMMAND_LINE_SIZE); + memset((void *)fw_dump.param_area, 0, COMMAND_LINE_SIZE); } /* @@ -1807,7 +1814,6 @@ int __init setup_fadump(void) } /* Initialize the kernel dump memory structure and register with f/w */ else if (fw_dump.reserve_dump_area_size) { - fadump_setup_param_area(); fw_dump.ops->fadump_init_mem_struct(&fw_dump); register_fadump(); } diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 2e1600a8bbbbf6..a0e8b998c9b527 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -89,69 +89,69 @@ int arch_show_interrupts(struct seq_file *p, int prec) #if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT) if (tau_initialized) { - seq_printf(p, "%*s: ", prec, "TAU"); + seq_printf(p, "%*s:", prec, "TAU"); for_each_online_cpu(j) - seq_printf(p, "%10u ", tau_interrupts(j)); + seq_put_decimal_ull_width(p, " ", tau_interrupts(j), 10); seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n"); } #endif /* CONFIG_PPC32 && CONFIG_TAU_INT */ - seq_printf(p, "%*s: ", prec, "LOC"); + seq_printf(p, "%*s:", prec, "LOC"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_event); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).timer_irqs_event, 10); seq_printf(p, " Local timer interrupts for timer event device\n"); - seq_printf(p, "%*s: ", prec, "BCT"); + seq_printf(p, "%*s:", prec, "BCT"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).broadcast_irqs_event); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).broadcast_irqs_event, 10); seq_printf(p, " Broadcast timer interrupts for timer event device\n"); - seq_printf(p, "%*s: ", prec, "LOC"); + seq_printf(p, "%*s:", prec, "LOC"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_others); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).timer_irqs_others, 10); seq_printf(p, " Local timer interrupts for others\n"); - seq_printf(p, "%*s: ", prec, "SPU"); + seq_printf(p, "%*s:", prec, "SPU"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).spurious_irqs, 10); seq_printf(p, " Spurious interrupts\n"); - seq_printf(p, "%*s: ", prec, "PMI"); + seq_printf(p, "%*s:", prec, "PMI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).pmu_irqs, 10); seq_printf(p, " Performance monitoring interrupts\n"); - seq_printf(p, "%*s: ", prec, "MCE"); + seq_printf(p, "%*s:", prec, "MCE"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).mce_exceptions); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).mce_exceptions, 10); seq_printf(p, " Machine check exceptions\n"); #ifdef CONFIG_PPC_BOOK3S_64 if (cpu_has_feature(CPU_FTR_HVMODE)) { - seq_printf(p, "%*s: ", prec, "HMI"); + seq_printf(p, "%*s:", prec, "HMI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", paca_ptrs[j]->hmi_irqs); + seq_put_decimal_ull_width(p, " ", paca_ptrs[j]->hmi_irqs, 10); seq_printf(p, " Hypervisor Maintenance Interrupts\n"); } #endif - seq_printf(p, "%*s: ", prec, "NMI"); + seq_printf(p, "%*s:", prec, "NMI"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).sreset_irqs); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).sreset_irqs, 10); seq_printf(p, " System Reset interrupts\n"); #ifdef CONFIG_PPC_WATCHDOG - seq_printf(p, "%*s: ", prec, "WDG"); + seq_printf(p, "%*s:", prec, "WDG"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).soft_nmi_irqs); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).soft_nmi_irqs, 10); seq_printf(p, " Watchdog soft-NMI interrupts\n"); #endif #ifdef CONFIG_PPC_DOORBELL if (cpu_has_feature(CPU_FTR_DBELL)) { - seq_printf(p, "%*s: ", prec, "DBL"); + seq_printf(p, "%*s:", prec, "DBL"); for_each_online_cpu(j) - seq_printf(p, "%10u ", per_cpu(irq_stat, j).doorbell_irqs); + seq_put_decimal_ull_width(p, " ", per_cpu(irq_stat, j).doorbell_irqs, 10); seq_printf(p, " Doorbell interrupts\n"); } #endif diff --git a/arch/powerpc/kernel/jump_label.c b/arch/powerpc/kernel/jump_label.c index 5277cf582c1611..2659e1ac860465 100644 --- a/arch/powerpc/kernel/jump_label.c +++ b/arch/powerpc/kernel/jump_label.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include void arch_jump_label_transform(struct jump_entry *entry, diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 7a8bc03a00af09..5081334b7bd217 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index f8aa91bc3b1759..c0d9f12cb4416c 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -105,24 +105,22 @@ kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset) return addr; } -static bool arch_kprobe_on_func_entry(unsigned long offset) +static bool arch_kprobe_on_func_entry(unsigned long addr, unsigned long offset) { -#ifdef CONFIG_PPC64_ELF_ABI_V2 -#ifdef CONFIG_KPROBES_ON_FTRACE - return offset <= 16; -#else - return offset <= 8; -#endif -#else + unsigned long ip = ftrace_location(addr); + + if (ip) + return offset <= (ip - addr); + if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2) && !IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) + return offset <= 8; return !offset; -#endif } /* XXX try and fold the magic of kprobe_lookup_name() in this */ kprobe_opcode_t *arch_adjust_kprobe_addr(unsigned long addr, unsigned long offset, bool *on_func_entry) { - *on_func_entry = arch_kprobe_on_func_entry(offset); + *on_func_entry = arch_kprobe_on_func_entry(addr, offset); return (kprobe_opcode_t *)(addr + offset); } diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 91123e102db40e..a997c7f43dc019 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -74,7 +74,7 @@ _GLOBAL(rmci_off) blr #endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */ -#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) +#ifdef CONFIG_PPC_PMAC /* * Do an IO access in real mode @@ -137,7 +137,7 @@ _GLOBAL(real_writeb) sync isync blr -#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ +#endif // CONFIG_PPC_PMAC #ifdef CONFIG_PPC_PASEMI @@ -174,7 +174,7 @@ _GLOBAL(real_205_writeb) #endif /* CONFIG_PPC_PASEMI */ -#if defined(CONFIG_CPU_FREQ_PMAC64) || defined(CONFIG_CPU_FREQ_MAPLE) +#ifdef CONFIG_CPU_FREQ_PMAC64 /* * SCOM access functions for 970 (FX only for now) * @@ -243,7 +243,7 @@ _GLOBAL(scom970_write) /* restore interrupts */ mtmsrd r5,1 blr -#endif /* CONFIG_CPU_FREQ_PMAC64 || CONFIG_CPU_FREQ_MAPLE */ +#endif // CONFIG_CPU_FREQ_PMAC64 /* kexec_wait(phys_cpu) * diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index 816a63fd71fbfb..f930e3395a7f27 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include /* Count how many different relocations (different symbol, different addend) */ diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index e9bab599d0c274..45dac7b46aa3cd 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -205,7 +205,9 @@ static int relacmp(const void *_x, const void *_y) /* Get size of potential trampolines required. */ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, - const Elf64_Shdr *sechdrs) + const Elf64_Shdr *sechdrs, + char *secstrings, + struct module *me) { /* One extra reloc so it's always 0-addr terminated */ unsigned long relocs = 1; @@ -241,13 +243,25 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, } } -#ifdef CONFIG_DYNAMIC_FTRACE - /* make the trampoline to the ftrace_caller */ - relocs++; -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS - /* an additional one for ftrace_regs_caller */ - relocs++; -#endif + /* stubs for ftrace_caller and ftrace_regs_caller */ + relocs += IS_ENABLED(CONFIG_DYNAMIC_FTRACE) + IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS); + +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + /* stubs for the function tracer */ + for (i = 1; i < hdr->e_shnum; i++) { + if (!strcmp(secstrings + sechdrs[i].sh_name, "__patchable_function_entries")) { + me->arch.ool_stub_count = sechdrs[i].sh_size / sizeof(unsigned long); + me->arch.ool_stub_index = 0; + relocs += roundup(me->arch.ool_stub_count * sizeof(struct ftrace_ool_stub), + sizeof(struct ppc64_stub_entry)) / + sizeof(struct ppc64_stub_entry); + break; + } + } + if (i == hdr->e_shnum) { + pr_err("%s: doesn't contain __patchable_function_entries.\n", me->name); + return -ENOEXEC; + } #endif pr_debug("Looks like a total of %lu stubs, max\n", relocs); @@ -460,7 +474,7 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr, #endif /* Override the stubs size */ - sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs); + sechdrs[me->arch.stubs_section].sh_size = get_stubs_size(hdr, sechdrs, secstrings, me); return 0; } @@ -1085,6 +1099,37 @@ int module_trampoline_target(struct module *mod, unsigned long addr, return 0; } +static int setup_ftrace_ool_stubs(const Elf64_Shdr *sechdrs, unsigned long addr, struct module *me) +{ +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + unsigned int i, total_stubs, num_stubs; + struct ppc64_stub_entry *stub; + + total_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*stub); + num_stubs = roundup(me->arch.ool_stub_count * sizeof(struct ftrace_ool_stub), + sizeof(struct ppc64_stub_entry)) / sizeof(struct ppc64_stub_entry); + + /* Find the next available entry */ + stub = (void *)sechdrs[me->arch.stubs_section].sh_addr; + for (i = 0; stub_func_addr(stub[i].funcdata); i++) + if (WARN_ON(i >= total_stubs)) + return -1; + + if (WARN_ON(i + num_stubs > total_stubs)) + return -1; + + stub += i; + me->arch.ool_stubs = (struct ftrace_ool_stub *)stub; + + /* reserve stubs */ + for (i = 0; i < num_stubs; i++) + if (patch_u32((void *)&stub->funcdata, PPC_RAW_NOP())) + return -1; +#endif + + return 0; +} + int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sechdrs) { mod->arch.tramp = stub_for_addr(sechdrs, @@ -1103,6 +1148,9 @@ int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sechdrs) if (!mod->arch.tramp) return -ENOENT; + if (setup_ftrace_ool_stubs(sechdrs, mod->arch.tramp, mod)) + return -ENOENT; + return 0; } #endif diff --git a/arch/powerpc/kernel/optprobes.c b/arch/powerpc/kernel/optprobes.c index c0b351d61058f7..2e83702bf9ba67 100644 --- a/arch/powerpc/kernel/optprobes.c +++ b/arch/powerpc/kernel/optprobes.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/proc_powerpc.c b/arch/powerpc/kernel/proc_powerpc.c index b109cd7b5d01fb..3816a2bf2b844f 100644 --- a/arch/powerpc/kernel/proc_powerpc.c +++ b/arch/powerpc/kernel/proc_powerpc.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -12,9 +13,10 @@ #include #include #include +#include #include -#ifdef CONFIG_PPC64 +#ifdef CONFIG_PPC64_PROC_SYSTEMCFG static loff_t page_map_seek(struct file *file, loff_t off, int whence) { @@ -33,10 +35,9 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) if ((vma->vm_end - vma->vm_start) > PAGE_SIZE) return -EINVAL; - remap_pfn_range(vma, vma->vm_start, - __pa(pde_data(file_inode(file))) >> PAGE_SHIFT, - PAGE_SIZE, vma->vm_page_prot); - return 0; + return remap_pfn_range(vma, vma->vm_start, + __pa(pde_data(file_inode(file))) >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot); } static const struct proc_ops page_map_proc_ops = { @@ -45,13 +46,35 @@ static const struct proc_ops page_map_proc_ops = { .proc_mmap = page_map_mmap, }; +static union { + struct systemcfg data; + u8 page[PAGE_SIZE]; +} systemcfg_data_store __page_aligned_data; +struct systemcfg *systemcfg = &systemcfg_data_store.data; static int __init proc_ppc64_init(void) { struct proc_dir_entry *pde; + strcpy((char *)systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); + systemcfg->version.major = SYSTEMCFG_MAJOR; + systemcfg->version.minor = SYSTEMCFG_MINOR; + systemcfg->processor = mfspr(SPRN_PVR); + /* + * Fake the old platform number for pSeries and add + * in LPAR bit if necessary + */ + systemcfg->platform = 0x100; + if (firmware_has_feature(FW_FEATURE_LPAR)) + systemcfg->platform |= 1; + systemcfg->physicalMemorySize = memblock_phys_mem_size(); + systemcfg->dcache_size = ppc64_caches.l1d.size; + systemcfg->dcache_line_size = ppc64_caches.l1d.line_size; + systemcfg->icache_size = ppc64_caches.l1i.size; + systemcfg->icache_line_size = ppc64_caches.l1i.line_size; + pde = proc_create_data("powerpc/systemcfg", S_IFREG | 0444, NULL, - &page_map_proc_ops, vdso_data); + &page_map_proc_ops, systemcfg); if (!pde) return 1; proc_set_size(pde, PAGE_SIZE); @@ -60,7 +83,7 @@ static int __init proc_ppc64_init(void) } __initcall(proc_ppc64_init); -#endif /* CONFIG_PPC64 */ +#endif /* CONFIG_PPC64_PROC_SYSTEMCFG */ /* * Create the ppc64 and ppc64/rtas directories early. This allows us to diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index ff61a3e7984cec..7b739b9a91ab90 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -54,7 +54,7 @@ #include #include #endif -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 0be07ed407c703..e0059842a1c64b 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -791,7 +791,7 @@ void __init early_init_devtree(void *params) DBG(" -> early_init_devtree(%px)\n", params); /* Too early to BUG_ON(), do it by hand */ - if (!early_init_dt_verify(params)) + if (!early_init_dt_verify(params, __pa(params))) panic("BUG: Failed verifying flat device tree, bad version?"); of_scan_flat_dt(early_init_dt_scan_model, NULL); @@ -908,6 +908,9 @@ void __init early_init_devtree(void *params) mmu_early_init_devtree(); + /* Setup param area for passing additional parameters to fadump capture kernel. */ + fadump_setup_param_area(); + #ifdef CONFIG_PPC_POWERNV /* Scan and build the list of machine check recoverable ranges */ of_scan_flat_dt(early_init_dt_scan_recoverable_ranges, NULL); diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index fbb68fc28ed3a5..8e776ba394978e 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -2792,90 +2792,6 @@ static void __init flatten_device_tree(void) dt_struct_start, dt_struct_end); } -#ifdef CONFIG_PPC_MAPLE -/* PIBS Version 1.05.0000 04/26/2005 has an incorrect /ht/isa/ranges property. - * The values are bad, and it doesn't even have the right number of cells. */ -static void __init fixup_device_tree_maple(void) -{ - phandle isa; - u32 rloc = 0x01002000; /* IO space; PCI device = 4 */ - u32 isa_ranges[6]; - char *name; - - name = "/ht@0/isa@4"; - isa = call_prom("finddevice", 1, 1, ADDR(name)); - if (!PHANDLE_VALID(isa)) { - name = "/ht@0/isa@6"; - isa = call_prom("finddevice", 1, 1, ADDR(name)); - rloc = 0x01003000; /* IO space; PCI device = 6 */ - } - if (!PHANDLE_VALID(isa)) - return; - - if (prom_getproplen(isa, "ranges") != 12) - return; - if (prom_getprop(isa, "ranges", isa_ranges, sizeof(isa_ranges)) - == PROM_ERROR) - return; - - if (isa_ranges[0] != 0x1 || - isa_ranges[1] != 0xf4000000 || - isa_ranges[2] != 0x00010000) - return; - - prom_printf("Fixing up bogus ISA range on Maple/Apache...\n"); - - isa_ranges[0] = 0x1; - isa_ranges[1] = 0x0; - isa_ranges[2] = rloc; - isa_ranges[3] = 0x0; - isa_ranges[4] = 0x0; - isa_ranges[5] = 0x00010000; - prom_setprop(isa, name, "ranges", - isa_ranges, sizeof(isa_ranges)); -} - -#define CPC925_MC_START 0xf8000000 -#define CPC925_MC_LENGTH 0x1000000 -/* The values for memory-controller don't have right number of cells */ -static void __init fixup_device_tree_maple_memory_controller(void) -{ - phandle mc; - u32 mc_reg[4]; - char *name = "/hostbridge@f8000000"; - u32 ac, sc; - - mc = call_prom("finddevice", 1, 1, ADDR(name)); - if (!PHANDLE_VALID(mc)) - return; - - if (prom_getproplen(mc, "reg") != 8) - return; - - prom_getprop(prom.root, "#address-cells", &ac, sizeof(ac)); - prom_getprop(prom.root, "#size-cells", &sc, sizeof(sc)); - if ((ac != 2) || (sc != 2)) - return; - - if (prom_getprop(mc, "reg", mc_reg, sizeof(mc_reg)) == PROM_ERROR) - return; - - if (mc_reg[0] != CPC925_MC_START || mc_reg[1] != CPC925_MC_LENGTH) - return; - - prom_printf("Fixing up bogus hostbridge on Maple...\n"); - - mc_reg[0] = 0x0; - mc_reg[1] = CPC925_MC_START; - mc_reg[2] = 0x0; - mc_reg[3] = CPC925_MC_LENGTH; - prom_setprop(mc, name, "reg", mc_reg, sizeof(mc_reg)); -} -#else -#define fixup_device_tree_maple() -#define fixup_device_tree_maple_memory_controller() -#endif - #ifdef CONFIG_PPC_CHRP /* * Pegasos and BriQ lacks the "ranges" property in the isa node @@ -2932,7 +2848,7 @@ static void __init fixup_device_tree_chrp(void) #endif #if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC) -static void __init fixup_device_tree_pmac(void) +static void __init fixup_device_tree_pmac64(void) { phandle u3, i2c, mpic; u32 u3_rev; @@ -2972,7 +2888,31 @@ static void __init fixup_device_tree_pmac(void) &parent, sizeof(parent)); } #else -#define fixup_device_tree_pmac() +#define fixup_device_tree_pmac64() +#endif + +#ifdef CONFIG_PPC_PMAC +static void __init fixup_device_tree_pmac(void) +{ + __be32 val = 1; + char type[8]; + phandle node; + + // Some pmacs are missing #size-cells on escc nodes + for (node = 0; prom_next_node(&node); ) { + type[0] = '\0'; + prom_getprop(node, "device_type", type, sizeof(type)); + if (prom_strcmp(type, "escc")) + continue; + + if (prom_getproplen(node, "#size-cells") != PROM_ERROR) + continue; + + prom_setprop(node, NULL, "#size-cells", &val, sizeof(val)); + } +} +#else +static inline void fixup_device_tree_pmac(void) { } #endif #ifdef CONFIG_PPC_EFIKA @@ -3193,10 +3133,9 @@ static inline void fixup_device_tree_pasemi(void) { } static void __init fixup_device_tree(void) { - fixup_device_tree_maple(); - fixup_device_tree_maple_memory_controller(); fixup_device_tree_chrp(); fixup_device_tree_pmac(); + fixup_device_tree_pmac64(); fixup_device_tree_efika(); fixup_device_tree_pasemi(); } diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index f7e86e09c49fa1..d31c9799cab283 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -1390,21 +1390,14 @@ bool __ref rtas_busy_delay(int status) */ ms = clamp(ms, 1U, 1000U); /* - * The delay hint is an order-of-magnitude suggestion, not - * a minimum. It is fine, possibly even advantageous, for - * us to pause for less time than hinted. For small values, - * use usleep_range() to ensure we don't sleep much longer - * than actually needed. - * - * See Documentation/timers/timers-howto.rst for - * explanation of the threshold used here. In effect we use - * usleep_range() for 9900 and 9901, msleep() for - * 9902-9905. + * The delay hint is an order-of-magnitude suggestion, not a + * minimum. It is fine, possibly even advantageous, for us to + * pause for less time than hinted. To make sure pause time will + * not be way longer than requested independent of HZ + * configuration, use fsleep(). See fsleep() for details of + * used sleeping functions. */ - if (ms <= 20) - usleep_range(ms * 100, ms * 1000); - else - msleep(ms); + fsleep(ms * 1000); break; case RTAS_BUSY: ret = true; diff --git a/arch/powerpc/kernel/secure_boot.c b/arch/powerpc/kernel/secure_boot.c index 9e0efb657f3937..3a28795b4ed82e 100644 --- a/arch/powerpc/kernel/secure_boot.c +++ b/arch/powerpc/kernel/secure_boot.c @@ -5,6 +5,7 @@ */ #include #include +#include #include static struct device_node *get_ppc_fw_sb_node(void) @@ -38,7 +39,7 @@ bool is_ppc_secureboot_enabled(void) of_node_put(node); out: - pr_info("Secure boot mode %s\n", enabled ? "enabled" : "disabled"); + pr_info("Secure boot mode %s\n", str_enabled_disabled(enabled)); return enabled; } @@ -62,7 +63,7 @@ bool is_ppc_trustedboot_enabled(void) of_node_put(node); out: - pr_info("Trusted boot mode %s\n", enabled ? "enabled" : "disabled"); + pr_info("Trusted boot mode %s\n", str_enabled_disabled(enabled)); return enabled; } diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c index 4856e1a5161ccc..fbb7ebd8aa08bc 100644 --- a/arch/powerpc/kernel/security.c +++ b/arch/powerpc/kernel/security.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 943430077375a4..6fa179448c3397 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -67,6 +67,7 @@ #include #include #include +#include #include "setup.h" @@ -560,7 +561,9 @@ void __init smp_setup_cpu_maps(void) out: of_node_put(dn); } - vdso_data->processorCount = num_present_cpus(); +#endif +#ifdef CONFIG_PPC64_PROC_SYSTEMCFG + systemcfg->processorCount = num_present_cpus(); #endif /* CONFIG_PPC64 */ /* Initialize CPU <=> thread mapping/ @@ -997,9 +1000,11 @@ void __init setup_arch(char **cmdline_p) initmem_init(); /* - * Reserve large chunks of memory for use by CMA for KVM and hugetlb. These must - * be called after initmem_init(), so that pageblock_order is initialised. + * Reserve large chunks of memory for use by CMA for fadump, KVM and + * hugetlb. These must be called after initmem_init(), so that + * pageblock_order is initialised. */ + fadump_cma_init(); kvm_cma_reserve(); gigantic_hugetlb_cma_reserve(); diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index e515c1f7d8d33b..75dbf3e0d9c4bc 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 22f83fbbc762ac..e67f3048611fcd 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include #include #include @@ -920,6 +920,7 @@ static int __init disable_hardlockup_detector(void) hardlockup_detector_disable(); #else if (firmware_has_feature(FW_FEATURE_LPAR)) { + check_kvm_guest(); if (is_kvm_guest()) hardlockup_detector_disable(); } diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 4ab9b8cee77a1a..5ac7084eebc0b8 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -61,6 +61,7 @@ #include #include #include +#include #include @@ -1186,8 +1187,8 @@ int generic_cpu_disable(void) return -EBUSY; set_cpu_online(cpu, false); -#ifdef CONFIG_PPC64 - vdso_data->processorCount--; +#ifdef CONFIG_PPC64_PROC_SYSTEMCFG + systemcfg->processorCount--; #endif /* Update affinity of all IRQs previously aimed at this CPU */ irq_migrate_all_off_this_cpu(); @@ -1642,10 +1643,12 @@ void start_secondary(void *unused) secondary_cpu_time_init(); -#ifdef CONFIG_PPC64 +#ifdef CONFIG_PPC64_PROC_SYSTEMCFG if (system_state == SYSTEM_RUNNING) - vdso_data->processorCount++; + systemcfg->processorCount++; +#endif +#ifdef CONFIG_PPC64 vdso_getcpu_init(); #endif set_numa_node(numa_cpu_lookup_table[cpu]); diff --git a/arch/powerpc/kernel/static_call.c b/arch/powerpc/kernel/static_call.c index 1502b7e439cafb..7cfd0710e7579e 100644 --- a/arch/powerpc/kernel/static_call.c +++ b/arch/powerpc/kernel/static_call.c @@ -2,7 +2,7 @@ #include #include -#include +#include void arch_static_call_transform(void *site, void *tramp, void *func, bool tail) { diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl index ebae8415dfbbab..d8b4ab78bef076 100644 --- a/arch/powerpc/kernel/syscalls/syscall.tbl +++ b/arch/powerpc/kernel/syscalls/syscall.tbl @@ -553,3 +553,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index b842c83ab497d0..6b3dd6decdf900 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 0ff9f038e800db..0727332ad86fbc 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -71,11 +71,11 @@ #include #include #include +#include /* powerpc clocksource/clockevent code */ #include -#include static u64 timebase_read(struct clocksource *); static struct clocksource clocksource_timebase = { @@ -951,6 +951,9 @@ void __init time_init(void) } vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; +#ifdef CONFIG_PPC64_PROC_SYSTEMCFG + systemcfg->tb_ticks_per_sec = tb_ticks_per_sec; +#endif /* initialise and enable the large decrementer (if we have one) */ set_decrementer_max(); diff --git a/arch/powerpc/kernel/trace/Makefile b/arch/powerpc/kernel/trace/Makefile index 125f4ca588b98a..d6c3885453bda3 100644 --- a/arch/powerpc/kernel/trace/Makefile +++ b/arch/powerpc/kernel/trace/Makefile @@ -9,12 +9,15 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_ftrace_64_pg.o = $(CC_FLAGS_FTRACE) endif -obj32-$(CONFIG_FUNCTION_TRACER) += ftrace.o ftrace_entry.o -ifdef CONFIG_MPROFILE_KERNEL -obj64-$(CONFIG_FUNCTION_TRACER) += ftrace.o ftrace_entry.o +ifdef CONFIG_FUNCTION_TRACER +obj32-y += ftrace.o ftrace_entry.o +ifeq ($(CONFIG_MPROFILE_KERNEL)$(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY),) +obj64-y += ftrace_64_pg.o ftrace_64_pg_entry.o else -obj64-$(CONFIG_FUNCTION_TRACER) += ftrace_64_pg.o ftrace_64_pg_entry.o +obj64-y += ftrace.o ftrace_entry.o +endif endif + obj-$(CONFIG_TRACING) += trace_clock.o obj-$(CONFIG_PPC64) += $(obj64-y) diff --git a/arch/powerpc/kernel/trace/ftrace.c b/arch/powerpc/kernel/trace/ftrace.c index d8d6b4fd9a14cb..5ccd791761e8fd 100644 --- a/arch/powerpc/kernel/trace/ftrace.c +++ b/arch/powerpc/kernel/trace/ftrace.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -37,8 +37,12 @@ unsigned long ftrace_call_adjust(unsigned long addr) if (addr >= (unsigned long)__exittext_begin && addr < (unsigned long)__exittext_end) return 0; - if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) + if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY) && + !IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) { addr += MCOUNT_INSN_SIZE; + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) + addr += MCOUNT_INSN_SIZE; + } return addr; } @@ -82,7 +86,7 @@ static inline int ftrace_modify_code(unsigned long ip, ppc_inst_t old, ppc_inst_ { int ret = ftrace_validate_inst(ip, old); - if (!ret) + if (!ret && !ppc_inst_equal(old, new)) ret = patch_instruction((u32 *)ip, new); return ret; @@ -106,28 +110,68 @@ static unsigned long find_ftrace_tramp(unsigned long ip) return 0; } +#ifdef CONFIG_MODULES +static unsigned long ftrace_lookup_module_stub(unsigned long ip, unsigned long addr) +{ + struct module *mod = NULL; + + preempt_disable(); + mod = __module_text_address(ip); + preempt_enable(); + + if (!mod) + pr_err("No module loaded at addr=%lx\n", ip); + + return (addr == (unsigned long)ftrace_caller ? mod->arch.tramp : mod->arch.tramp_regs); +} +#else +static unsigned long ftrace_lookup_module_stub(unsigned long ip, unsigned long addr) +{ + return 0; +} +#endif + +static unsigned long ftrace_get_ool_stub(struct dyn_ftrace *rec) +{ +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + return rec->arch.ool_stub; +#else + BUILD_BUG(); +#endif +} + static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_inst_t *call_inst) { - unsigned long ip = rec->ip; + unsigned long ip; unsigned long stub; - if (is_offset_in_branch_range(addr - ip)) { + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) + ip = ftrace_get_ool_stub(rec) + MCOUNT_INSN_SIZE; /* second instruction in stub */ + else + ip = rec->ip; + + if (!is_offset_in_branch_range(addr - ip) && addr != FTRACE_ADDR && + addr != FTRACE_REGS_ADDR) { + /* This can only happen with ftrace direct */ + if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS)) { + pr_err("0x%lx (0x%lx): Unexpected target address 0x%lx\n", + ip, rec->ip, addr); + return -EINVAL; + } + addr = FTRACE_ADDR; + } + + if (is_offset_in_branch_range(addr - ip)) /* Within range */ stub = addr; -#ifdef CONFIG_MODULES - } else if (rec->arch.mod) { - /* Module code would be going to one of the module stubs */ - stub = (addr == (unsigned long)ftrace_caller ? rec->arch.mod->arch.tramp : - rec->arch.mod->arch.tramp_regs); -#endif - } else if (core_kernel_text(ip)) { + else if (core_kernel_text(ip)) /* We would be branching to one of our ftrace stubs */ stub = find_ftrace_tramp(ip); - if (!stub) { - pr_err("0x%lx: No ftrace stubs reachable\n", ip); - return -EINVAL; - } - } else { + else + stub = ftrace_lookup_module_stub(ip, addr); + + if (!stub) { + pr_err("0x%lx (0x%lx): No ftrace stubs reachable\n", ip, rec->ip); return -EINVAL; } @@ -135,6 +179,145 @@ static int ftrace_get_call_inst(struct dyn_ftrace *rec, unsigned long addr, ppc_ return 0; } +static int ftrace_init_ool_stub(struct module *mod, struct dyn_ftrace *rec) +{ +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + static int ool_stub_text_index, ool_stub_text_end_index, ool_stub_inittext_index; + int ret = 0, ool_stub_count, *ool_stub_index; + ppc_inst_t inst; + /* + * See ftrace_entry.S if changing the below instruction sequence, as we rely on + * decoding the last branch instruction here to recover the correct function ip. + */ + struct ftrace_ool_stub *ool_stub, ool_stub_template = { + .insn = { + PPC_RAW_MFLR(_R0), + PPC_RAW_NOP(), /* bl ftrace_caller */ + PPC_RAW_MTLR(_R0), + PPC_RAW_NOP() /* b rec->ip + 4 */ + } + }; + + WARN_ON(rec->arch.ool_stub); + + if (is_kernel_inittext(rec->ip)) { + ool_stub = ftrace_ool_stub_inittext; + ool_stub_index = &ool_stub_inittext_index; + ool_stub_count = ftrace_ool_stub_inittext_count; + } else if (is_kernel_text(rec->ip)) { + /* + * ftrace records are sorted, so we first use up the stub area within .text + * (ftrace_ool_stub_text) before using the area at the end of .text + * (ftrace_ool_stub_text_end), unless the stub is out of range of the record. + */ + if (ool_stub_text_index >= ftrace_ool_stub_text_count || + !is_offset_in_branch_range((long)rec->ip - + (long)&ftrace_ool_stub_text[ool_stub_text_index])) { + ool_stub = ftrace_ool_stub_text_end; + ool_stub_index = &ool_stub_text_end_index; + ool_stub_count = ftrace_ool_stub_text_end_count; + } else { + ool_stub = ftrace_ool_stub_text; + ool_stub_index = &ool_stub_text_index; + ool_stub_count = ftrace_ool_stub_text_count; + } +#ifdef CONFIG_MODULES + } else if (mod) { + ool_stub = mod->arch.ool_stubs; + ool_stub_index = &mod->arch.ool_stub_index; + ool_stub_count = mod->arch.ool_stub_count; +#endif + } else { + return -EINVAL; + } + + ool_stub += (*ool_stub_index)++; + + if (WARN_ON(*ool_stub_index > ool_stub_count)) + return -EINVAL; + + if (!is_offset_in_branch_range((long)rec->ip - (long)&ool_stub->insn[0]) || + !is_offset_in_branch_range((long)(rec->ip + MCOUNT_INSN_SIZE) - + (long)&ool_stub->insn[3])) { + pr_err("%s: ftrace ool stub out of range (%p -> %p).\n", + __func__, (void *)rec->ip, (void *)&ool_stub->insn[0]); + return -EINVAL; + } + + rec->arch.ool_stub = (unsigned long)&ool_stub->insn[0]; + + /* bl ftrace_caller */ + if (!mod) + ret = ftrace_get_call_inst(rec, (unsigned long)ftrace_caller, &inst); +#ifdef CONFIG_MODULES + else + /* + * We can't use ftrace_get_call_inst() since that uses + * __module_text_address(rec->ip) to look up the module. + * But, since the module is not fully formed at this stage, + * the lookup fails. We know the target though, so generate + * the branch inst directly. + */ + inst = ftrace_create_branch_inst(ftrace_get_ool_stub(rec) + MCOUNT_INSN_SIZE, + mod->arch.tramp, 1); +#endif + ool_stub_template.insn[1] = ppc_inst_val(inst); + + /* b rec->ip + 4 */ + if (!ret && create_branch(&inst, &ool_stub->insn[3], rec->ip + MCOUNT_INSN_SIZE, 0)) + return -EINVAL; + ool_stub_template.insn[3] = ppc_inst_val(inst); + + if (!ret) + ret = patch_instructions((u32 *)ool_stub, (u32 *)&ool_stub_template, + sizeof(ool_stub_template), false); + + return ret; +#else /* !CONFIG_PPC_FTRACE_OUT_OF_LINE */ + BUILD_BUG(); +#endif +} + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS +static const struct ftrace_ops *powerpc_rec_get_ops(struct dyn_ftrace *rec) +{ + const struct ftrace_ops *ops = NULL; + + if (rec->flags & FTRACE_FL_CALL_OPS_EN) { + ops = ftrace_find_unique_ops(rec); + WARN_ON_ONCE(!ops); + } + + if (!ops) + ops = &ftrace_list_ops; + + return ops; +} + +static int ftrace_rec_set_ops(struct dyn_ftrace *rec, const struct ftrace_ops *ops) +{ + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) + return patch_ulong((void *)(ftrace_get_ool_stub(rec) - sizeof(unsigned long)), + (unsigned long)ops); + else + return patch_ulong((void *)(rec->ip - MCOUNT_INSN_SIZE - sizeof(unsigned long)), + (unsigned long)ops); +} + +static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) +{ + return ftrace_rec_set_ops(rec, &ftrace_nop_ops); +} + +static int ftrace_rec_update_ops(struct dyn_ftrace *rec) +{ + return ftrace_rec_set_ops(rec, powerpc_rec_get_ops(rec)); +} +#else +static int ftrace_rec_set_nop_ops(struct dyn_ftrace *rec) { return 0; } +static int ftrace_rec_update_ops(struct dyn_ftrace *rec) { return 0; } +#endif + #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr) { @@ -147,18 +330,33 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { ppc_inst_t old, new; - int ret; + unsigned long ip = rec->ip; + int ret = 0; /* This can only ever be called during module load */ - if (WARN_ON(!IS_ENABLED(CONFIG_MODULES) || core_kernel_text(rec->ip))) + if (WARN_ON(!IS_ENABLED(CONFIG_MODULES) || core_kernel_text(ip))) return -EINVAL; old = ppc_inst(PPC_RAW_NOP()); - ret = ftrace_get_call_inst(rec, addr, &new); + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) { + ip = ftrace_get_ool_stub(rec) + MCOUNT_INSN_SIZE; /* second instruction in stub */ + ret = ftrace_get_call_inst(rec, (unsigned long)ftrace_caller, &old); + } + + ret |= ftrace_get_call_inst(rec, addr, &new); + + if (!ret) + ret = ftrace_modify_code(ip, old, new); + + ret = ftrace_rec_update_ops(rec); if (ret) return ret; - return ftrace_modify_code(rec->ip, old, new); + if (!ret && IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) + ret = ftrace_modify_code(rec->ip, ppc_inst(PPC_RAW_NOP()), + ppc_inst(PPC_RAW_BRANCH((long)ftrace_get_ool_stub(rec) - (long)rec->ip))); + + return ret; } int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) @@ -191,6 +389,13 @@ void ftrace_replace_code(int enable) new_addr = ftrace_get_addr_new(rec); update = ftrace_update_record(rec, enable); + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE) && update != FTRACE_UPDATE_IGNORE) { + ip = ftrace_get_ool_stub(rec) + MCOUNT_INSN_SIZE; + ret = ftrace_get_call_inst(rec, (unsigned long)ftrace_caller, &nop_inst); + if (ret) + goto out; + } + switch (update) { case FTRACE_UPDATE_IGNORE: default: @@ -198,16 +403,19 @@ void ftrace_replace_code(int enable) case FTRACE_UPDATE_MODIFY_CALL: ret = ftrace_get_call_inst(rec, new_addr, &new_call_inst); ret |= ftrace_get_call_inst(rec, addr, &call_inst); + ret |= ftrace_rec_update_ops(rec); old = call_inst; new = new_call_inst; break; case FTRACE_UPDATE_MAKE_NOP: ret = ftrace_get_call_inst(rec, addr, &call_inst); + ret |= ftrace_rec_set_nop_ops(rec); old = call_inst; new = nop_inst; break; case FTRACE_UPDATE_MAKE_CALL: ret = ftrace_get_call_inst(rec, new_addr, &call_inst); + ret |= ftrace_rec_update_ops(rec); old = nop_inst; new = call_inst; break; @@ -215,6 +423,24 @@ void ftrace_replace_code(int enable) if (!ret) ret = ftrace_modify_code(ip, old, new); + + if (!ret && IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE) && + (update == FTRACE_UPDATE_MAKE_NOP || update == FTRACE_UPDATE_MAKE_CALL)) { + /* Update the actual ftrace location */ + call_inst = ppc_inst(PPC_RAW_BRANCH((long)ftrace_get_ool_stub(rec) - + (long)rec->ip)); + nop_inst = ppc_inst(PPC_RAW_NOP()); + ip = rec->ip; + + if (update == FTRACE_UPDATE_MAKE_NOP) + ret = ftrace_modify_code(ip, call_inst, nop_inst); + else + ret = ftrace_modify_code(ip, nop_inst, call_inst); + + if (ret) + goto out; + } + if (ret) goto out; } @@ -234,20 +460,27 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) /* Verify instructions surrounding the ftrace location */ if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) { /* Expect nops */ - ret = ftrace_validate_inst(ip - 4, ppc_inst(PPC_RAW_NOP())); + if (!IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) + ret = ftrace_validate_inst(ip - 4, ppc_inst(PPC_RAW_NOP())); if (!ret) ret = ftrace_validate_inst(ip, ppc_inst(PPC_RAW_NOP())); } else if (IS_ENABLED(CONFIG_PPC32)) { /* Expected sequence: 'mflr r0', 'stw r0,4(r1)', 'bl _mcount' */ ret = ftrace_validate_inst(ip - 8, ppc_inst(PPC_RAW_MFLR(_R0))); - if (!ret) - ret = ftrace_validate_inst(ip - 4, ppc_inst(PPC_RAW_STW(_R0, _R1, 4))); + if (ret) + return ret; + ret = ftrace_modify_code(ip - 4, ppc_inst(PPC_RAW_STW(_R0, _R1, 4)), + ppc_inst(PPC_RAW_NOP())); } else if (IS_ENABLED(CONFIG_MPROFILE_KERNEL)) { /* Expected sequence: 'mflr r0', ['std r0,16(r1)'], 'bl _mcount' */ ret = ftrace_read_inst(ip - 4, &old); if (!ret && !ppc_inst_equal(old, ppc_inst(PPC_RAW_MFLR(_R0)))) { + /* Gcc v5.x emit the additional 'std' instruction, gcc v6.x don't */ ret = ftrace_validate_inst(ip - 8, ppc_inst(PPC_RAW_MFLR(_R0))); - ret |= ftrace_validate_inst(ip - 4, ppc_inst(PPC_RAW_STD(_R0, _R1, 16))); + if (ret) + return ret; + ret = ftrace_modify_code(ip - 4, ppc_inst(PPC_RAW_STD(_R0, _R1, 16)), + ppc_inst(PPC_RAW_NOP())); } } else { return -EINVAL; @@ -256,13 +489,9 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) if (ret) return ret; - if (!core_kernel_text(ip)) { - if (!mod) { - pr_err("0x%lx: No module provided for non-kernel address\n", ip); - return -EFAULT; - } - rec->arch.mod = mod; - } + /* Set up out-of-line stub */ + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) + return ftrace_init_ool_stub(mod, rec); /* Nop-out the ftrace location */ new = ppc_inst(PPC_RAW_NOP()); @@ -302,6 +531,13 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ppc_inst_t old, new; int ret; + /* + * When using CALL_OPS, the function to call is associated with the + * call site, and we don't have a global function pointer to update. + */ + if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS)) + return 0; + old = ppc_inst_read((u32 *)&ftrace_call); new = ftrace_create_branch_inst(ip, ppc_function_entry(func), 1); ret = ftrace_modify_code(ip, old, new); @@ -421,7 +657,7 @@ int __init ftrace_dyn_arch_init(void) void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { - unsigned long sp = fregs->regs.gpr[1]; + unsigned long sp = arch_ftrace_regs(fregs)->regs.gpr[1]; int bit; if (unlikely(ftrace_graph_is_dead())) @@ -439,6 +675,6 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, ftrace_test_recursion_unlock(bit); out: - fregs->regs.link = parent_ip; + arch_ftrace_regs(fregs)->regs.link = parent_ip; } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/powerpc/kernel/trace/ftrace_64_pg.c b/arch/powerpc/kernel/trace/ftrace_64_pg.c index 12fab1803bcf45..98787376eb87c3 100644 --- a/arch/powerpc/kernel/trace/ftrace_64_pg.c +++ b/arch/powerpc/kernel/trace/ftrace_64_pg.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -116,6 +116,20 @@ static unsigned long find_bl_target(unsigned long ip, ppc_inst_t op) } #ifdef CONFIG_MODULES +static struct module *ftrace_lookup_module(struct dyn_ftrace *rec) +{ + struct module *mod; + + preempt_disable(); + mod = __module_text_address(rec->ip); + preempt_enable(); + + if (!mod) + pr_err("No module loaded at addr=%lx\n", rec->ip); + + return mod; +} + static int __ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) @@ -124,6 +138,12 @@ __ftrace_make_nop(struct module *mod, unsigned long ip = rec->ip; ppc_inst_t op, pop; + if (!mod) { + mod = ftrace_lookup_module(rec); + if (!mod) + return -EINVAL; + } + /* read where this goes */ if (copy_inst_from_kernel_nofault(&op, (void *)ip)) { pr_err("Fetching opcode failed.\n"); @@ -366,27 +386,6 @@ int ftrace_make_nop(struct module *mod, return -EINVAL; } - /* - * Out of range jumps are called from modules. - * We should either already have a pointer to the module - * or it has been passed in. - */ - if (!rec->arch.mod) { - if (!mod) { - pr_err("No module loaded addr=%lx\n", addr); - return -EFAULT; - } - rec->arch.mod = mod; - } else if (mod) { - if (mod != rec->arch.mod) { - pr_err("Record mod %p not equal to passed in mod %p\n", - rec->arch.mod, mod); - return -EINVAL; - } - /* nothing to do if mod == rec->arch.mod */ - } else - mod = rec->arch.mod; - return __ftrace_make_nop(mod, rec, addr); } @@ -411,7 +410,10 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ppc_inst_t op[2]; void *ip = (void *)rec->ip; unsigned long entry, ptr, tramp; - struct module *mod = rec->arch.mod; + struct module *mod = ftrace_lookup_module(rec); + + if (!mod) + return -EINVAL; /* read where this goes */ if (copy_inst_from_kernel_nofault(op, ip)) @@ -533,16 +535,6 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) return -EINVAL; } - /* - * Out of range jumps are called from modules. - * Being that we are converting from nop, it had better - * already have a module defined. - */ - if (!rec->arch.mod) { - pr_err("No module loaded\n"); - return -EINVAL; - } - return __ftrace_make_call(rec, addr); } @@ -555,7 +547,10 @@ __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, ppc_inst_t op; unsigned long ip = rec->ip; unsigned long entry, ptr, tramp; - struct module *mod = rec->arch.mod; + struct module *mod = ftrace_lookup_module(rec); + + if (!mod) + return -EINVAL; /* If we never set up ftrace trampolines, then bail */ if (!mod->arch.tramp || !mod->arch.tramp_regs) { @@ -668,14 +663,6 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, return -EINVAL; } - /* - * Out of range jumps are called from modules. - */ - if (!rec->arch.mod) { - pr_err("No module loaded\n"); - return -EINVAL; - } - return __ftrace_modify_call(rec, old_addr, addr); } #endif @@ -829,7 +816,7 @@ __prepare_ftrace_return(unsigned long parent, unsigned long ip, unsigned long sp void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { - fregs->regs.link = __prepare_ftrace_return(parent_ip, ip, fregs->regs.gpr[1]); + arch_ftrace_regs(fregs)->regs.link = __prepare_ftrace_return(parent_ip, ip, arch_ftrace_regs(fregs)->regs.gpr[1]); } #else unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip, diff --git a/arch/powerpc/kernel/trace/ftrace_entry.S b/arch/powerpc/kernel/trace/ftrace_entry.S index 76dbe9fd2c0f22..2c1b24100eca29 100644 --- a/arch/powerpc/kernel/trace/ftrace_entry.S +++ b/arch/powerpc/kernel/trace/ftrace_entry.S @@ -39,13 +39,37 @@ /* Create our stack frame + pt_regs */ PPC_STLU r1,-SWITCH_FRAME_SIZE(r1) + .if \allregs == 1 + SAVE_GPRS(11, 12, r1) + .endif + + /* Get the _mcount() call site out of LR */ + mflr r11 + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + /* Load the ftrace_op */ + PPC_LL r12, -(MCOUNT_INSN_SIZE*2 + SZL)(r11) + + /* Load direct_call from the ftrace_op */ + PPC_LL r12, FTRACE_OPS_DIRECT_CALL(r12) + PPC_LCMPI r12, 0 + .if \allregs == 1 + bne .Lftrace_direct_call_regs + .else + bne .Lftrace_direct_call + .endif +#endif + + /* Save the previous LR in pt_regs->link */ + PPC_STL r0, _LINK(r1) + /* Also save it in A's stack frame */ + PPC_STL r0, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE+LRSAVE(r1) + /* Save all gprs to pt_regs */ SAVE_GPR(0, r1) SAVE_GPRS(3, 10, r1) #ifdef CONFIG_PPC64 - /* Save the original return address in A's stack frame */ - std r0, LRSAVE+SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE(r1) /* Ok to continue? */ lbz r3, PACA_FTRACE_ENABLED(r13) cmpdi r3, 0 @@ -54,9 +78,9 @@ .if \allregs == 1 SAVE_GPR(2, r1) - SAVE_GPRS(11, 31, r1) + SAVE_GPRS(13, 31, r1) .else -#ifdef CONFIG_LIVEPATCH_64 +#if defined(CONFIG_LIVEPATCH_64) || defined(CONFIG_PPC_FTRACE_OUT_OF_LINE) SAVE_GPR(14, r1) #endif .endif @@ -67,80 +91,143 @@ .if \allregs == 1 /* Load special regs for save below */ + mfcr r7 mfmsr r8 mfctr r9 mfxer r10 - mfcr r11 .else /* Clear MSR to flag as ftrace_caller versus frace_regs_caller */ li r8, 0 .endif - /* Get the _mcount() call site out of LR */ - mflr r7 - /* Save it as pt_regs->nip */ - PPC_STL r7, _NIP(r1) - /* Also save it in B's stackframe header for proper unwind */ - PPC_STL r7, LRSAVE+SWITCH_FRAME_SIZE(r1) - /* Save the read LR in pt_regs->link */ - PPC_STL r0, _LINK(r1) - #ifdef CONFIG_PPC64 /* Save callee's TOC in the ABI compliant location */ std r2, STK_GOT(r1) LOAD_PACA_TOC() /* get kernel TOC in r2 */ +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + /* r11 points to the instruction following the call to ftrace */ + PPC_LL r5, -(MCOUNT_INSN_SIZE*2 + SZL)(r11) + PPC_LL r12, FTRACE_OPS_FUNC(r5) + mtctr r12 +#else /* !CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS */ +#ifdef CONFIG_PPC64 LOAD_REG_ADDR(r3, function_trace_op) ld r5,0(r3) #else lis r3,function_trace_op@ha lwz r5,function_trace_op@l(r3) #endif - -#ifdef CONFIG_LIVEPATCH_64 - mr r14, r7 /* remember old NIP */ #endif - /* Calculate ip from nip-4 into r3 for call below */ - subi r3, r7, MCOUNT_INSN_SIZE - - /* Put the original return address in r4 as parent_ip */ - mr r4, r0 - /* Save special regs */ PPC_STL r8, _MSR(r1) .if \allregs == 1 + PPC_STL r7, _CCR(r1) PPC_STL r9, _CTR(r1) PPC_STL r10, _XER(r1) - PPC_STL r11, _CCR(r1) .endif +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + /* Clear orig_gpr3 to later detect ftrace_direct call */ + li r7, 0 + PPC_STL r7, ORIG_GPR3(r1) +#endif + +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + /* Save our real return address in nvr for return */ + .if \allregs == 0 + SAVE_GPR(15, r1) + .endif + mr r15, r11 + /* + * We want the ftrace location in the function, but our lr (in r11) + * points at the 'mtlr r0' instruction in the out of line stub. To + * recover the ftrace location, we read the branch instruction in the + * stub, and adjust our lr by the branch offset. + * + * See ftrace_init_ool_stub() for the profile sequence. + */ + lwz r8, MCOUNT_INSN_SIZE(r11) + slwi r8, r8, 6 + srawi r8, r8, 6 + add r3, r11, r8 + /* + * Override our nip to point past the branch in the original function. + * This allows reliable stack trace and the ftrace stack tracer to work as-is. + */ + addi r11, r3, MCOUNT_INSN_SIZE +#else + /* Calculate ip from nip-4 into r3 for call below */ + subi r3, r11, MCOUNT_INSN_SIZE +#endif + + /* Save NIP as pt_regs->nip */ + PPC_STL r11, _NIP(r1) + /* Also save it in B's stackframe header for proper unwind */ + PPC_STL r11, LRSAVE+SWITCH_FRAME_SIZE(r1) +#if defined(CONFIG_LIVEPATCH_64) || defined(CONFIG_PPC_FTRACE_OUT_OF_LINE) + mr r14, r11 /* remember old NIP */ +#endif + + /* Put the original return address in r4 as parent_ip */ + mr r4, r0 + /* Load &pt_regs in r6 for call below */ addi r6, r1, STACK_INT_FRAME_REGS .endm .macro ftrace_regs_exit allregs - /* Load ctr with the possibly modified NIP */ - PPC_LL r3, _NIP(r1) +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + /* Check orig_gpr3 to detect ftrace_direct call */ + PPC_LL r3, ORIG_GPR3(r1) + PPC_LCMPI cr1, r3, 0 mtctr r3 +#endif + /* Restore possibly modified LR */ + PPC_LL r0, _LINK(r1) + +#ifndef CONFIG_PPC_FTRACE_OUT_OF_LINE + /* Load ctr with the possibly modified NIP */ + PPC_LL r3, _NIP(r1) #ifdef CONFIG_LIVEPATCH_64 cmpd r14, r3 /* has NIP been altered? */ #endif +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + beq cr1,2f + mtlr r3 + b 3f +#endif +2: mtctr r3 + mtlr r0 +3: + +#else /* !CONFIG_PPC_FTRACE_OUT_OF_LINE */ + /* Load LR with the possibly modified NIP */ + PPC_LL r3, _NIP(r1) + cmpd r14, r3 /* has NIP been altered? */ + bne- 1f + + mr r3, r15 + .if \allregs == 0 + REST_GPR(15, r1) + .endif +1: mtlr r3 +#endif + /* Restore gprs */ .if \allregs == 1 REST_GPRS(2, 31, r1) .else REST_GPRS(3, 10, r1) -#ifdef CONFIG_LIVEPATCH_64 +#if defined(CONFIG_LIVEPATCH_64) || defined(CONFIG_PPC_FTRACE_OUT_OF_LINE) REST_GPR(14, r1) #endif .endif - /* Restore possibly modified LR */ - PPC_LL r0, _LINK(r1) - mtlr r0 - #ifdef CONFIG_PPC64 /* Restore callee's TOC */ ld r2, STK_GOT(r1) @@ -153,23 +240,46 @@ /* Based on the cmpd above, if the NIP was altered handle livepatch */ bne- livepatch_handler #endif - bctr /* jump after _mcount site */ + + /* jump after _mcount site */ +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS + bnectr cr1 +#endif + /* + * Return with blr to keep the link stack balanced. The function profiling sequence + * uses 'mtlr r0' to restore LR. + */ + blr +#else + bctr +#endif .endm -_GLOBAL(ftrace_regs_caller) - ftrace_regs_entry 1 - /* ftrace_call(r3, r4, r5, r6) */ +.macro ftrace_regs_func allregs +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS + bctrl +#else + .if \allregs == 1 .globl ftrace_regs_call ftrace_regs_call: + .else +.globl ftrace_call +ftrace_call: + .endif + /* ftrace_call(r3, r4, r5, r6) */ bl ftrace_stub +#endif +.endm + +_GLOBAL(ftrace_regs_caller) + ftrace_regs_entry 1 + ftrace_regs_func 1 ftrace_regs_exit 1 _GLOBAL(ftrace_caller) ftrace_regs_entry 0 - /* ftrace_call(r3, r4, r5, r6) */ -.globl ftrace_call -ftrace_call: - bl ftrace_stub + ftrace_regs_func 0 ftrace_regs_exit 0 _GLOBAL(ftrace_stub) @@ -177,6 +287,11 @@ _GLOBAL(ftrace_stub) #ifdef CONFIG_PPC64 ftrace_no_trace: +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE + REST_GPR(3, r1) + addi r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE + blr +#else mflr r3 mtctr r3 REST_GPR(3, r1) @@ -184,6 +299,22 @@ ftrace_no_trace: mtlr r0 bctr #endif +#endif + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +.Lftrace_direct_call_regs: + mtctr r12 + REST_GPRS(11, 12, r1) + addi r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE + bctr +.Lftrace_direct_call: + mtctr r12 + addi r1, r1, SWITCH_FRAME_SIZE+STACK_FRAME_MIN_SIZE + bctr +SYM_FUNC_START(ftrace_stub_direct_tramp) + blr +SYM_FUNC_END(ftrace_stub_direct_tramp) +#endif #ifdef CONFIG_LIVEPATCH_64 /* @@ -194,11 +325,17 @@ ftrace_no_trace: * We get here when a function A, calls another function B, but B has * been live patched with a new function C. * - * On entry: - * - we have no stack frame and can not allocate one + * On entry, we have no stack frame and can not allocate one. + * + * With PPC_FTRACE_OUT_OF_LINE=n, on entry: * - LR points back to the original caller (in A) * - CTR holds the new NIP in C * - r0, r11 & r12 are free + * + * With PPC_FTRACE_OUT_OF_LINE=y, on entry: + * - r0 points back to the original caller (in A) + * - LR holds the new NIP in C + * - r11 & r12 are free */ livepatch_handler: ld r12, PACA_THREAD_INFO(r13) @@ -208,18 +345,23 @@ livepatch_handler: addi r11, r11, 24 std r11, TI_livepatch_sp(r12) - /* Save toc & real LR on livepatch stack */ - std r2, -24(r11) - mflr r12 - std r12, -16(r11) - /* Store stack end marker */ lis r12, STACK_END_MAGIC@h ori r12, r12, STACK_END_MAGIC@l std r12, -8(r11) - /* Put ctr in r12 for global entry and branch there */ + /* Save toc & real LR on livepatch stack */ + std r2, -24(r11) +#ifndef CONFIG_PPC_FTRACE_OUT_OF_LINE + mflr r12 + std r12, -16(r11) mfctr r12 +#else + std r0, -16(r11) + mflr r12 + /* Put ctr in r12 for global entry and branch there */ + mtctr r12 +#endif bctrl /* @@ -308,6 +450,14 @@ _GLOBAL(return_to_handler) blr #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +SYM_DATA(ftrace_ool_stub_text_count, .long CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE) + +SYM_START(ftrace_ool_stub_text, SYM_L_GLOBAL, .balign SZL) + .space CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE * FTRACE_OOL_STUB_SIZE +SYM_CODE_END(ftrace_ool_stub_text) +#endif + .pushsection ".tramp.ftrace.text","aw",@progbits; .globl ftrace_tramp_text ftrace_tramp_text: diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 4b99208f5adcdb..0a72a537f879e5 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c @@ -39,9 +39,6 @@ void __init udbg_early_init(void) #elif defined(CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE) /* RTAS console debug */ udbg_init_rtas_console(); -#elif defined(CONFIG_PPC_EARLY_DEBUG_MAPLE) - /* Maple real mode debug */ - udbg_init_maple_realmode(); #elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE) udbg_init_pas_realmode(); #elif defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 313802aff5713c..dfe8ed2192e8e8 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -205,29 +205,6 @@ void __init udbg_uart_init_mmio(void __iomem *addr, unsigned int stride) udbg_use_uart(); } -#ifdef CONFIG_PPC_MAPLE - -#define UDBG_UART_MAPLE_ADDR ((void __iomem *)0xf40003f8) - -static u8 udbg_uart_in_maple(unsigned int reg) -{ - return real_readb(UDBG_UART_MAPLE_ADDR + reg); -} - -static void udbg_uart_out_maple(unsigned int reg, u8 val) -{ - real_writeb(val, UDBG_UART_MAPLE_ADDR + reg); -} - -void __init udbg_init_maple_realmode(void) -{ - udbg_uart_in = udbg_uart_in_maple; - udbg_uart_out = udbg_uart_out_maple; - udbg_use_uart(); -} - -#endif /* CONFIG_PPC_MAPLE */ - #ifdef CONFIG_PPC_PASEMI #define UDBG_UART_PAS_ADDR ((void __iomem *)0xfcff03f8UL) diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index ee4b9d676cff54..43379365ce1b37 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -48,12 +47,13 @@ long sys_ni_syscall(void); */ static union { struct vdso_arch_data data; - u8 page[PAGE_SIZE]; + u8 page[2 * PAGE_SIZE]; } vdso_data_store __page_aligned_data; struct vdso_arch_data *vdso_data = &vdso_data_store.data; enum vvar_pages { - VVAR_DATA_PAGE_OFFSET, + VVAR_BASE_PAGE_OFFSET, + VVAR_TIME_PAGE_OFFSET, VVAR_TIMENS_PAGE_OFFSET, VVAR_NR_PAGES, }; @@ -119,7 +119,7 @@ static struct vm_special_mapping vdso64_spec __ro_after_init = { #ifdef CONFIG_TIME_NS struct vdso_data *arch_get_vdso_data(void *vvar_page) { - return ((struct vdso_arch_data *)vvar_page)->data; + return vvar_page; } /* @@ -153,11 +153,14 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, unsigned long pfn; switch (vmf->pgoff) { - case VVAR_DATA_PAGE_OFFSET: + case VVAR_BASE_PAGE_OFFSET: + pfn = virt_to_pfn(vdso_data); + break; + case VVAR_TIME_PAGE_OFFSET: if (timens_page) pfn = page_to_pfn(timens_page); else - pfn = virt_to_pfn(vdso_data); + pfn = virt_to_pfn(vdso_data->data); break; #ifdef CONFIG_TIME_NS case VVAR_TIMENS_PAGE_OFFSET: @@ -170,7 +173,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, */ if (!timens_page) return VM_FAULT_SIGBUS; - pfn = virt_to_pfn(vdso_data); + pfn = virt_to_pfn(vdso_data->data); break; #endif /* CONFIG_TIME_NS */ default: @@ -349,25 +352,6 @@ static struct page ** __init vdso_setup_pages(void *start, void *end) static int __init vdso_init(void) { #ifdef CONFIG_PPC64 - /* - * Fill up the "systemcfg" stuff for backward compatibility - */ - strcpy((char *)vdso_data->eye_catcher, "SYSTEMCFG:PPC64"); - vdso_data->version.major = SYSTEMCFG_MAJOR; - vdso_data->version.minor = SYSTEMCFG_MINOR; - vdso_data->processor = mfspr(SPRN_PVR); - /* - * Fake the old platform number for pSeries and add - * in LPAR bit if necessary - */ - vdso_data->platform = 0x100; - if (firmware_has_feature(FW_FEATURE_LPAR)) - vdso_data->platform |= 1; - vdso_data->physicalMemorySize = memblock_phys_mem_size(); - vdso_data->dcache_size = ppc64_caches.l1d.size; - vdso_data->dcache_line_size = ppc64_caches.l1d.line_size; - vdso_data->icache_size = ppc64_caches.l1i.size; - vdso_data->icache_line_size = ppc64_caches.l1i.line_size; vdso_data->dcache_block_size = ppc64_caches.l1d.block_size; vdso_data->icache_block_size = ppc64_caches.l1i.block_size; vdso_data->dcache_log_block_size = ppc64_caches.l1d.log_block_size; diff --git a/arch/powerpc/kernel/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile index 31ca5a5470047e..0e3ed6fb199fff 100644 --- a/arch/powerpc/kernel/vdso/Makefile +++ b/arch/powerpc/kernel/vdso/Makefile @@ -50,14 +50,18 @@ ldflags-$(CONFIG_LD_IS_LLD) += $(call cc-option,--ld-path=$(LD),-fuse-ld=lld) ldflags-$(CONFIG_LD_ORPHAN_WARN) += -Wl,--orphan-handling=$(CONFIG_LD_ORPHAN_WARN_LEVEL) # Filter flags that clang will warn are unused for linking -ldflags-y += $(filter-out $(CC_AUTO_VAR_INIT_ZERO_ENABLER) $(CC_FLAGS_FTRACE) -Wa$(comma)%, $(KBUILD_CFLAGS)) +ldflags-y += $(filter-out $(CC_AUTO_VAR_INIT_ZERO_ENABLER) $(CC_FLAGS_FTRACE) -Wa$(comma)%, $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)) CC32FLAGS := -m32 CC32FLAGSREMOVE := -mcmodel=medium -mabi=elfv1 -mabi=elfv2 -mcall-aixdesc - # This flag is supported by clang for 64-bit but not 32-bit so it will cause - # an unused command line flag warning for this file. ifdef CONFIG_CC_IS_CLANG +# This flag is supported by clang for 64-bit but not 32-bit so it will cause +# an unused command line flag warning for this file. CC32FLAGSREMOVE += -fno-stack-clash-protection +# -mstack-protector-guard values from the 64-bit build are not valid for the +# 32-bit one. clang validates the values passed to these arguments during +# parsing, even when -fno-stack-protector is passed afterwards. +CC32FLAGSREMOVE += -mstack-protector-guard% endif LD32FLAGS := -Wl,-soname=linux-vdso32.so.1 AS32FLAGS := -D__VDSO32__ diff --git a/arch/powerpc/kernel/vdso/cacheflush.S b/arch/powerpc/kernel/vdso/cacheflush.S index 3b2479bd2f9a1d..0085ae464dac9c 100644 --- a/arch/powerpc/kernel/vdso/cacheflush.S +++ b/arch/powerpc/kernel/vdso/cacheflush.S @@ -30,7 +30,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) #ifdef CONFIG_PPC64 mflr r12 .cfi_register lr,r12 - get_realdatapage r10, r11 + get_datapage r10 mtlr r12 .cfi_restore lr #endif diff --git a/arch/powerpc/kernel/vdso/datapage.S b/arch/powerpc/kernel/vdso/datapage.S index 2b19b6201a33a8..db8e167f01667e 100644 --- a/arch/powerpc/kernel/vdso/datapage.S +++ b/arch/powerpc/kernel/vdso/datapage.S @@ -28,7 +28,7 @@ V_FUNCTION_BEGIN(__kernel_get_syscall_map) mflr r12 .cfi_register lr,r12 mr. r4,r3 - get_realdatapage r3, r11 + get_datapage r3 mtlr r12 #ifdef __powerpc64__ addi r3,r3,CFG_SYSCALL_MAP64 @@ -52,7 +52,7 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq) .cfi_startproc mflr r12 .cfi_register lr,r12 - get_realdatapage r3, r11 + get_datapage r3 #ifndef __powerpc64__ lwz r4,(CFG_TB_TICKS_PER_SEC + 4)(r3) #endif diff --git a/arch/powerpc/kernel/vdso/getrandom.S b/arch/powerpc/kernel/vdso/getrandom.S index f3bbf931931ca2..a80d9fb436f7ee 100644 --- a/arch/powerpc/kernel/vdso/getrandom.S +++ b/arch/powerpc/kernel/vdso/getrandom.S @@ -31,8 +31,6 @@ PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT #endif - get_realdatapage r8, r11 - addi r8, r8, VDSO_RNG_DATA_OFFSET bl CFUNC(DOTSYM(\funct)) PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) #ifdef __powerpc64__ diff --git a/arch/powerpc/kernel/vdso/gettimeofday.S b/arch/powerpc/kernel/vdso/gettimeofday.S index 5540d7021fa25c..5333848322ca61 100644 --- a/arch/powerpc/kernel/vdso/gettimeofday.S +++ b/arch/powerpc/kernel/vdso/gettimeofday.S @@ -32,11 +32,10 @@ PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT #endif - get_datapage r5 .ifeq \call_time - addi r5, r5, VDSO_DATA_OFFSET + get_datapage r5 VDSO_DATA_OFFSET .else - addi r4, r5, VDSO_DATA_OFFSET + get_datapage r4 VDSO_DATA_OFFSET .endif bl CFUNC(DOTSYM(\funct)) PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) diff --git a/arch/powerpc/kernel/vdso/vdso32.lds.S b/arch/powerpc/kernel/vdso/vdso32.lds.S index 7b41d5d256e814..1a1b0b6d681a99 100644 --- a/arch/powerpc/kernel/vdso/vdso32.lds.S +++ b/arch/powerpc/kernel/vdso/vdso32.lds.S @@ -16,7 +16,7 @@ OUTPUT_ARCH(powerpc:common) SECTIONS { - PROVIDE(_vdso_datapage = . - 2 * PAGE_SIZE); + PROVIDE(_vdso_datapage = . - 3 * PAGE_SIZE); . = SIZEOF_HEADERS; .hash : { *(.hash) } :text diff --git a/arch/powerpc/kernel/vdso/vdso64.lds.S b/arch/powerpc/kernel/vdso/vdso64.lds.S index 9481e4b892ed13..e21b5506cad62b 100644 --- a/arch/powerpc/kernel/vdso/vdso64.lds.S +++ b/arch/powerpc/kernel/vdso/vdso64.lds.S @@ -16,7 +16,7 @@ OUTPUT_ARCH(powerpc:common64) SECTIONS { - PROVIDE(_vdso_datapage = . - 2 * PAGE_SIZE); + PROVIDE(_vdso_datapage = . - 3 * PAGE_SIZE); . = SIZEOF_HEADERS; .hash : { *(.hash) } :text diff --git a/arch/powerpc/kernel/vdso/vgetrandom.c b/arch/powerpc/kernel/vdso/vgetrandom.c index 5f855d45fb7bf9..cc79b960a5413b 100644 --- a/arch/powerpc/kernel/vdso/vgetrandom.c +++ b/arch/powerpc/kernel/vdso/vgetrandom.c @@ -8,7 +8,7 @@ #include ssize_t __c_kernel_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, - size_t opaque_len, const struct vdso_rng_data *vd) + size_t opaque_len) { - return __cvdso_getrandom_data(vd, buffer, len, flags, opaque_state, opaque_len); + return __cvdso_getrandom(buffer, len, flags, opaque_state, opaque_len); } diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 7ab4e2fb28b1e3..b4c9decc7a75ce 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -265,14 +265,13 @@ SECTIONS .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { _sinittext = .; INIT_TEXT - + *(.tramp.ftrace.init); /* *.init.text might be RO so we must ensure this section ends on * a page boundary. */ . = ALIGN(PAGE_SIZE); _einittext = .; - *(.tramp.ftrace.init); } :text /* .exit.text is discarded at runtime, not link time, diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c index 9738adabeb1fee..dc65c139115772 100644 --- a/arch/powerpc/kexec/file_load_64.c +++ b/arch/powerpc/kexec/file_load_64.c @@ -736,13 +736,18 @@ int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, if (dn) { u64 val; - of_property_read_u64(dn, "opal-base-address", &val); + ret = of_property_read_u64(dn, "opal-base-address", &val); + if (ret) + goto out; + ret = kexec_purgatory_get_set_symbol(image, "opal_base", &val, sizeof(val), false); if (ret) goto out; - of_property_read_u64(dn, "opal-entry-address", &val); + ret = of_property_read_u64(dn, "opal-entry-address", &val); + if (ret) + goto out; ret = kexec_purgatory_get_set_symbol(image, "opal_entry", &val, sizeof(val), false); } diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index ff6c3837395752..d79c5d1098c05c 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -422,7 +422,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu) EXPORT_SYMBOL_GPL(kvmppc_core_prepare_to_enter); kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing, - bool *writable) + bool *writable, struct page **page) { ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM; gfn_t gfn = gpa >> PAGE_SHIFT; @@ -437,13 +437,14 @@ kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing, kvm_pfn_t pfn; pfn = (kvm_pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT; - get_page(pfn_to_page(pfn)); + *page = pfn_to_page(pfn); + get_page(*page); if (writable) *writable = true; return pfn; } - return gfn_to_pfn_prot(vcpu->kvm, gfn, writing, writable); + return kvm_faultin_pfn(vcpu, gfn, writing, writable, page); } EXPORT_SYMBOL_GPL(kvmppc_gpa_to_pfn); diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c index 4b3a8d80cfa354..5b7212edbb1313 100644 --- a/arch/powerpc/kvm/book3s_32_mmu_host.c +++ b/arch/powerpc/kvm/book3s_32_mmu_host.c @@ -130,6 +130,7 @@ extern char etext[]; int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, bool iswrite) { + struct page *page; kvm_pfn_t hpaddr; u64 vpn; u64 vsid; @@ -145,7 +146,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, bool writable; /* Get host physical address for gpa */ - hpaddr = kvmppc_gpa_to_pfn(vcpu, orig_pte->raddr, iswrite, &writable); + hpaddr = kvmppc_gpa_to_pfn(vcpu, orig_pte->raddr, iswrite, &writable, &page); if (is_error_noslot_pfn(hpaddr)) { printk(KERN_INFO "Couldn't get guest page for gpa %lx!\n", orig_pte->raddr); @@ -232,7 +233,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, pte = kvmppc_mmu_hpte_cache_next(vcpu); if (!pte) { - kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT); + kvm_release_page_unused(page); r = -EAGAIN; goto out; } @@ -250,7 +251,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, kvmppc_mmu_hpte_cache_map(vcpu, pte); - kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT); + kvm_release_page_clean(page); out: return r; } diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c index bc6a381b534637..be20aee6fd7d09 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_host.c +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c @@ -88,13 +88,14 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, struct hpte_cache *cpte; unsigned long gfn = orig_pte->raddr >> PAGE_SHIFT; unsigned long pfn; + struct page *page; /* used to check for invalidations in progress */ mmu_seq = kvm->mmu_invalidate_seq; smp_rmb(); /* Get host physical address for gpa */ - pfn = kvmppc_gpa_to_pfn(vcpu, orig_pte->raddr, iswrite, &writable); + pfn = kvmppc_gpa_to_pfn(vcpu, orig_pte->raddr, iswrite, &writable, &page); if (is_error_noslot_pfn(pfn)) { printk(KERN_INFO "Couldn't get guest page for gpa %lx!\n", orig_pte->raddr); @@ -121,13 +122,10 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, vpn = hpt_vpn(orig_pte->eaddr, map->host_vsid, MMU_SEGSIZE_256M); - kvm_set_pfn_accessed(pfn); if (!orig_pte->may_write || !writable) rflags |= PP_RXRX; - else { + else mark_page_dirty(vcpu->kvm, gfn); - kvm_set_pfn_dirty(pfn); - } if (!orig_pte->may_execute) rflags |= HPTE_R_N; @@ -202,8 +200,10 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, } out_unlock: + /* FIXME: Don't unconditionally pass unused=false. */ + kvm_release_faultin_page(kvm, page, false, + orig_pte->may_write && writable); spin_unlock(&kvm->mmu_lock); - kvm_release_pfn_clean(pfn); if (cpte) kvmppc_mmu_hpte_cache_free(cpte); diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 1b51b1c4713bf2..f305395cf26e7b 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -603,27 +603,10 @@ int kvmppc_book3s_hv_page_fault(struct kvm_vcpu *vcpu, write_ok = writing; hva = gfn_to_hva_memslot(memslot, gfn); - /* - * Do a fast check first, since __gfn_to_pfn_memslot doesn't - * do it with !atomic && !async, which is how we call it. - * We always ask for write permission since the common case - * is that the page is writable. - */ - if (get_user_page_fast_only(hva, FOLL_WRITE, &page)) { - write_ok = true; - } else { - /* Call KVM generic code to do the slow-path check */ - pfn = __gfn_to_pfn_memslot(memslot, gfn, false, false, NULL, - writing, &write_ok, NULL); - if (is_error_noslot_pfn(pfn)) - return -EFAULT; - page = NULL; - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (PageReserved(page)) - page = NULL; - } - } + pfn = __kvm_faultin_pfn(memslot, gfn, writing ? FOLL_WRITE : 0, + &write_ok, &page); + if (is_error_noslot_pfn(pfn)) + return -EFAULT; /* * Read the PTE from the process' radix tree and use that diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 408d98f8a51479..b3e6e73d6a0884 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -821,7 +821,7 @@ bool kvmppc_hv_handle_set_rc(struct kvm *kvm, bool nested, bool writing, int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, unsigned long gpa, struct kvm_memory_slot *memslot, - bool writing, bool kvm_ro, + bool writing, pte_t *inserted_pte, unsigned int *levelp) { struct kvm *kvm = vcpu->kvm; @@ -829,40 +829,21 @@ int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, unsigned long mmu_seq; unsigned long hva, gfn = gpa >> PAGE_SHIFT; bool upgrade_write = false; - bool *upgrade_p = &upgrade_write; pte_t pte, *ptep; unsigned int shift, level; int ret; bool large_enable; + kvm_pfn_t pfn; /* used to check for invalidations in progress */ mmu_seq = kvm->mmu_invalidate_seq; smp_rmb(); - /* - * Do a fast check first, since __gfn_to_pfn_memslot doesn't - * do it with !atomic && !async, which is how we call it. - * We always ask for write permission since the common case - * is that the page is writable. - */ hva = gfn_to_hva_memslot(memslot, gfn); - if (!kvm_ro && get_user_page_fast_only(hva, FOLL_WRITE, &page)) { - upgrade_write = true; - } else { - unsigned long pfn; - - /* Call KVM generic code to do the slow-path check */ - pfn = __gfn_to_pfn_memslot(memslot, gfn, false, false, NULL, - writing, upgrade_p, NULL); - if (is_error_noslot_pfn(pfn)) - return -EFAULT; - page = NULL; - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (PageReserved(page)) - page = NULL; - } - } + pfn = __kvm_faultin_pfn(memslot, gfn, writing ? FOLL_WRITE : 0, + &upgrade_write, &page); + if (is_error_noslot_pfn(pfn)) + return -EFAULT; /* * Read the PTE from the process' radix tree and use that @@ -950,7 +931,6 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot; long ret; bool writing = !!(dsisr & DSISR_ISSTORE); - bool kvm_ro = false; /* Check for unusual errors */ if (dsisr & DSISR_UNSUPP_MMU) { @@ -1003,7 +983,6 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, ea, DSISR_ISSTORE | DSISR_PROTFAULT); return RESUME_GUEST; } - kvm_ro = true; } /* Failed to set the reference/change bits */ @@ -1021,7 +1000,7 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, /* Try to insert a pte */ ret = kvmppc_book3s_instantiate_page(vcpu, gpa, memslot, writing, - kvm_ro, NULL, NULL); + NULL, NULL); if (ret == 0 || ret == -EAGAIN) ret = RESUME_GUEST; diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 34c0adb9fdbf2b..742aa58a7c7e36 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -115,10 +115,9 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, struct iommu_table_group *table_group; long i; struct kvmppc_spapr_tce_iommu_table *stit; - struct fd f; + CLASS(fd, f)(tablefd); - f = fdget(tablefd); - if (!fd_file(f)) + if (fd_empty(f)) return -EBADF; rcu_read_lock(); @@ -130,16 +129,12 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, } rcu_read_unlock(); - if (!found) { - fdput(f); + if (!found) return -EINVAL; - } table_group = iommu_group_get_iommudata(grp); - if (WARN_ON(!table_group)) { - fdput(f); + if (WARN_ON(!table_group)) return -EFAULT; - } for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { struct iommu_table *tbltmp = table_group->tables[i]; @@ -160,10 +155,8 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, break; } } - if (!tbl) { - fdput(f); + if (!tbl) return -EINVAL; - } rcu_read_lock(); list_for_each_entry_rcu(stit, &stt->iommu_tables, next) { @@ -174,7 +167,6 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, /* stit is being destroyed */ iommu_tce_table_put(tbl); rcu_read_unlock(); - fdput(f); return -ENOTTY; } /* @@ -182,7 +174,6 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, * its KVM reference counter and can return. */ rcu_read_unlock(); - fdput(f); return 0; } rcu_read_unlock(); @@ -190,7 +181,6 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, stit = kzalloc(sizeof(*stit), GFP_KERNEL); if (!stit) { iommu_tce_table_put(tbl); - fdput(f); return -ENOMEM; } @@ -199,7 +189,6 @@ long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, list_add_rcu(&stit->next, &stt->iommu_tables); - fdput(f); return 0; } diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index ad8dc4ccdaab9e..25429905ae90f3 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -400,7 +400,10 @@ static inline unsigned long map_pcr_to_cap(unsigned long pcr) cap = H_GUEST_CAP_POWER9; break; case PCR_ARCH_31: - cap = H_GUEST_CAP_POWER10; + if (cpu_has_feature(CPU_FTR_P11_PVR)) + cap = H_GUEST_CAP_POWER11; + else + cap = H_GUEST_CAP_POWER10; break; default: break; @@ -415,7 +418,7 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) struct kvmppc_vcore *vc = vcpu->arch.vcore; /* We can (emulate) our own architecture version and anything older */ - if (cpu_has_feature(CPU_FTR_ARCH_31)) + if (cpu_has_feature(CPU_FTR_P11_PVR) || cpu_has_feature(CPU_FTR_ARCH_31)) host_pcr_bit = PCR_ARCH_31; else if (cpu_has_feature(CPU_FTR_ARCH_300)) host_pcr_bit = PCR_ARCH_300; @@ -2060,36 +2063,9 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) fallthrough; /* go to facility unavailable handler */ #endif - case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: { - u64 cause = vcpu->arch.hfscr >> 56; - - /* - * Only pass HFU interrupts to the L1 if the facility is - * permitted but disabled by the L1's HFSCR, otherwise - * the interrupt does not make sense to the L1 so turn - * it into a HEAI. - */ - 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, &pinst); - vcpu->arch.emul_inst = ppc_inst_val(pinst); - if (r != EMULATE_DONE) - r = RESUME_GUEST; - else - r = RESUME_HOST; - } else { - r = RESUME_HOST; - } - + case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: + r = RESUME_HOST; break; - } case BOOK3S_INTERRUPT_HV_RM_HARD: vcpu->arch.trap = 0; @@ -4153,8 +4129,9 @@ void kvmhv_set_l2_counters_status(int cpu, bool status) else lppaca_of(cpu).l2_counters_enable = 0; } +EXPORT_SYMBOL(kvmhv_set_l2_counters_status); -int kmvhv_counters_tracepoint_regfunc(void) +int kvmhv_counters_tracepoint_regfunc(void) { int cpu; @@ -4164,7 +4141,7 @@ int kmvhv_counters_tracepoint_regfunc(void) return 0; } -void kmvhv_counters_tracepoint_unregfunc(void) +void kvmhv_counters_tracepoint_unregfunc(void) { int cpu; @@ -4190,7 +4167,73 @@ static void do_trace_nested_cs_time(struct kvm_vcpu *vcpu) *l1_to_l2_cs_ptr = l1_to_l2_ns; *l2_to_l1_cs_ptr = l2_to_l1_ns; *l2_runtime_agg_ptr = l2_runtime_ns; + vcpu->arch.l1_to_l2_cs = l1_to_l2_ns; + vcpu->arch.l2_to_l1_cs = l2_to_l1_ns; + vcpu->arch.l2_runtime_agg = l2_runtime_ns; +} + +u64 kvmhv_get_l1_to_l2_cs_time(void) +{ + return tb_to_ns(be64_to_cpu(get_lppaca()->l1_to_l2_cs_tb)); +} +EXPORT_SYMBOL(kvmhv_get_l1_to_l2_cs_time); + +u64 kvmhv_get_l2_to_l1_cs_time(void) +{ + return tb_to_ns(be64_to_cpu(get_lppaca()->l2_to_l1_cs_tb)); +} +EXPORT_SYMBOL(kvmhv_get_l2_to_l1_cs_time); + +u64 kvmhv_get_l2_runtime_agg(void) +{ + return tb_to_ns(be64_to_cpu(get_lppaca()->l2_runtime_tb)); +} +EXPORT_SYMBOL(kvmhv_get_l2_runtime_agg); + +u64 kvmhv_get_l1_to_l2_cs_time_vcpu(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vcpu_arch *arch; + + vcpu = local_paca->kvm_hstate.kvm_vcpu; + if (vcpu) { + arch = &vcpu->arch; + return arch->l1_to_l2_cs; + } else { + return 0; + } } +EXPORT_SYMBOL(kvmhv_get_l1_to_l2_cs_time_vcpu); + +u64 kvmhv_get_l2_to_l1_cs_time_vcpu(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vcpu_arch *arch; + + vcpu = local_paca->kvm_hstate.kvm_vcpu; + if (vcpu) { + arch = &vcpu->arch; + return arch->l2_to_l1_cs; + } else { + return 0; + } +} +EXPORT_SYMBOL(kvmhv_get_l2_to_l1_cs_time_vcpu); + +u64 kvmhv_get_l2_runtime_agg_vcpu(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vcpu_arch *arch; + + vcpu = local_paca->kvm_hstate.kvm_vcpu; + if (vcpu) { + arch = &vcpu->arch; + return arch->l2_runtime_agg; + } else { + return 0; + } +} +EXPORT_SYMBOL(kvmhv_get_l2_runtime_agg_vcpu); #else int kvmhv_get_l2_counters_status(void) @@ -4309,6 +4352,15 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns } hvregs.hdec_expiry = time_limit; + /* + * hvregs has the doorbell status, so zero it here which + * enables us to receive doorbells when H_ENTER_NESTED is + * in progress for this vCPU + */ + + if (vcpu->arch.doorbell_request) + vcpu->arch.doorbell_request = 0; + /* * When setting DEC, we must always deal with irq_work_raise * via NMI vs setting DEC. The problem occurs right as we @@ -4912,7 +4964,6 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, lpcr &= ~LPCR_MER; } } else if (vcpu->arch.pending_exceptions || - vcpu->arch.doorbell_request || xive_interrupt_pending(vcpu)) { vcpu->arch.ret = RESUME_HOST; goto out; diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 05f5220960c63b..5f8c2321cfb520 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -32,7 +32,7 @@ void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) struct kvmppc_vcore *vc = vcpu->arch.vcore; hr->pcr = vc->pcr | PCR_MASK; - hr->dpdes = vc->dpdes; + hr->dpdes = vcpu->arch.doorbell_request; hr->hfscr = vcpu->arch.hfscr; hr->tb_offset = vc->tb_offset; hr->dawr0 = vcpu->arch.dawr0; @@ -105,7 +105,7 @@ static void save_hv_return_state(struct kvm_vcpu *vcpu, { struct kvmppc_vcore *vc = vcpu->arch.vcore; - hr->dpdes = vc->dpdes; + hr->dpdes = vcpu->arch.doorbell_request; hr->purr = vcpu->arch.purr; hr->spurr = vcpu->arch.spurr; hr->ic = vcpu->arch.ic; @@ -143,7 +143,7 @@ static void restore_hv_regs(struct kvm_vcpu *vcpu, const struct hv_guest_state * struct kvmppc_vcore *vc = vcpu->arch.vcore; vc->pcr = hr->pcr | PCR_MASK; - vc->dpdes = hr->dpdes; + vcpu->arch.doorbell_request = hr->dpdes; vcpu->arch.hfscr = hr->hfscr; vcpu->arch.dawr0 = hr->dawr0; vcpu->arch.dawrx0 = hr->dawrx0; @@ -170,7 +170,13 @@ void kvmhv_restore_hv_return_state(struct kvm_vcpu *vcpu, { struct kvmppc_vcore *vc = vcpu->arch.vcore; - vc->dpdes = hr->dpdes; + /* + * This L2 vCPU might have received a doorbell while H_ENTER_NESTED was being handled. + * Make sure we preserve the doorbell if it was either: + * a) Sent after H_ENTER_NESTED was called on this vCPU (arch.doorbell_request would be 1) + * b) Doorbell was not handled and L2 exited for some other reason (hr->dpdes would be 1) + */ + vcpu->arch.doorbell_request = vcpu->arch.doorbell_request | hr->dpdes; vcpu->arch.hfscr = hr->hfscr; vcpu->arch.purr = hr->purr; vcpu->arch.spurr = hr->spurr; @@ -445,6 +451,8 @@ long kvmhv_nested_init(void) if (rc == H_SUCCESS) { unsigned long capabilities = 0; + if (cpu_has_feature(CPU_FTR_P11_PVR)) + capabilities |= H_GUEST_CAP_POWER11; if (cpu_has_feature(CPU_FTR_ARCH_31)) capabilities |= H_GUEST_CAP_POWER10; if (cpu_has_feature(CPU_FTR_ARCH_300)) @@ -1527,7 +1535,6 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, unsigned long n_gpa, gpa, gfn, perm = 0UL; unsigned int shift, l1_shift, level; bool writing = !!(dsisr & DSISR_ISSTORE); - bool kvm_ro = false; long int ret; if (!gp->l1_gr_to_hr) { @@ -1607,7 +1614,6 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, ea, DSISR_ISSTORE | DSISR_PROTFAULT); return RESUME_GUEST; } - kvm_ro = true; } /* 2. Find the host pte for this L1 guest real address */ @@ -1629,7 +1635,7 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, if (!pte_present(pte) || (writing && !(pte_val(pte) & _PAGE_WRITE))) { /* No suitable pte found -> try to insert a mapping */ ret = kvmppc_book3s_instantiate_page(vcpu, gpa, memslot, - writing, kvm_ro, &pte, &level); + writing, &pte, &level); if (ret == -EAGAIN) return RESUME_GUEST; else if (ret) diff --git a/arch/powerpc/kvm/book3s_hv_nestedv2.c b/arch/powerpc/kvm/book3s_hv_nestedv2.c index eeecea8f202b36..e5c7ce1fb7612e 100644 --- a/arch/powerpc/kvm/book3s_hv_nestedv2.c +++ b/arch/powerpc/kvm/book3s_hv_nestedv2.c @@ -370,7 +370,9 @@ static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb, * default to L1's PVR. */ if (!vcpu->arch.vcore->arch_compat) { - if (cpu_has_feature(CPU_FTR_ARCH_31)) + if (cpu_has_feature(CPU_FTR_P11_PVR)) + arch_compat = PVR_ARCH_31_P11; + else if (cpu_has_feature(CPU_FTR_ARCH_31)) arch_compat = PVR_ARCH_31; else if (cpu_has_feature(CPU_FTR_ARCH_300)) arch_compat = PVR_ARCH_300; diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c b/arch/powerpc/kvm/book3s_hv_uvmem.c index 92f33115144b28..3a6592a31a10a4 100644 --- a/arch/powerpc/kvm/book3s_hv_uvmem.c +++ b/arch/powerpc/kvm/book3s_hv_uvmem.c @@ -879,9 +879,8 @@ static unsigned long kvmppc_share_page(struct kvm *kvm, unsigned long gpa, { int ret = H_PARAMETER; - struct page *uvmem_page; + struct page *page, *uvmem_page; struct kvmppc_uvmem_page_pvt *pvt; - unsigned long pfn; unsigned long gfn = gpa >> page_shift; int srcu_idx; unsigned long uvmem_pfn; @@ -901,8 +900,8 @@ static unsigned long kvmppc_share_page(struct kvm *kvm, unsigned long gpa, retry: mutex_unlock(&kvm->arch.uvmem_lock); - pfn = gfn_to_pfn(kvm, gfn); - if (is_error_noslot_pfn(pfn)) + page = gfn_to_page(kvm, gfn); + if (!page) goto out; mutex_lock(&kvm->arch.uvmem_lock); @@ -911,16 +910,16 @@ static unsigned long kvmppc_share_page(struct kvm *kvm, unsigned long gpa, pvt = uvmem_page->zone_device_data; pvt->skip_page_out = true; pvt->remove_gfn = false; /* it continues to be a valid GFN */ - kvm_release_pfn_clean(pfn); + kvm_release_page_unused(page); goto retry; } - if (!uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0, + if (!uv_page_in(kvm->arch.lpid, page_to_pfn(page) << page_shift, gpa, 0, page_shift)) { kvmppc_gfn_shared(gfn, kvm); ret = H_SUCCESS; } - kvm_release_pfn_clean(pfn); + kvm_release_page_clean(page); mutex_unlock(&kvm->arch.uvmem_lock); out: srcu_read_unlock(&kvm->srcu, srcu_idx); @@ -1083,21 +1082,21 @@ kvmppc_h_svm_page_out(struct kvm *kvm, unsigned long gpa, int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn) { - unsigned long pfn; + struct page *page; int ret = U_SUCCESS; - pfn = gfn_to_pfn(kvm, gfn); - if (is_error_noslot_pfn(pfn)) + page = gfn_to_page(kvm, gfn); + if (!page) return -EFAULT; mutex_lock(&kvm->arch.uvmem_lock); if (kvmppc_gfn_is_uvmem_pfn(gfn, kvm, NULL)) goto out; - ret = uv_page_in(kvm->arch.lpid, pfn << PAGE_SHIFT, gfn << PAGE_SHIFT, - 0, PAGE_SHIFT); + ret = uv_page_in(kvm->arch.lpid, page_to_pfn(page) << PAGE_SHIFT, + gfn << PAGE_SHIFT, 0, PAGE_SHIFT); out: - kvm_release_pfn_clean(pfn); + kvm_release_page_clean(page); mutex_unlock(&kvm->arch.uvmem_lock); return (ret == U_SUCCESS) ? RESUME_GUEST : -EFAULT; } diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c index ce79ac33e8d3b9..d904e13e069bcc 100644 --- a/arch/powerpc/kvm/book3s_mmu_hpte.c +++ b/arch/powerpc/kvm/book3s_mmu_hpte.c @@ -92,12 +92,6 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte) spin_unlock(&vcpu3s->mmu_lock); } -static void free_pte_rcu(struct rcu_head *head) -{ - struct hpte_cache *pte = container_of(head, struct hpte_cache, rcu_head); - kmem_cache_free(hpte_cache, pte); -} - static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) { struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); @@ -126,7 +120,7 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) spin_unlock(&vcpu3s->mmu_lock); - call_rcu(&pte->rcu_head, free_pte_rcu); + kfree_rcu(pte, rcu_head); } static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu) diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 7b8ae509328fe1..83bcdc80ce51ad 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -639,29 +639,27 @@ static void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr) */ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) { - struct page *hpage; + struct kvm_host_map map; u64 hpage_offset; u32 *page; - int i; + int i, r; - hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT); - if (is_error_page(hpage)) + r = kvm_vcpu_map(vcpu, pte->raddr >> PAGE_SHIFT, &map); + if (r) return; hpage_offset = pte->raddr & ~PAGE_MASK; hpage_offset &= ~0xFFFULL; hpage_offset /= 4; - get_page(hpage); - page = kmap_atomic(hpage); + page = map.hva; /* patch dcbz into reserved instruction, so we trap */ for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) if ((be32_to_cpu(page[i]) & 0xff0007ff) == INS_DCBZ) page[i] &= cpu_to_be32(0xfffffff7); - kunmap_atomic(page); - put_page(hpage); + kvm_vcpu_unmap(vcpu, &map); } static bool kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa) diff --git a/arch/powerpc/kvm/book3s_xive_native.c b/arch/powerpc/kvm/book3s_xive_native.c index 6e2ebbd8aaace8..d9bf1bc3ff6105 100644 --- a/arch/powerpc/kvm/book3s_xive_native.c +++ b/arch/powerpc/kvm/book3s_xive_native.c @@ -654,7 +654,7 @@ static int kvmppc_xive_native_set_queue_config(struct kvmppc_xive *xive, } page = gfn_to_page(kvm, gfn); - if (is_error_page(page)) { + if (!page) { srcu_read_unlock(&kvm->srcu, srcu_idx); pr_err("Couldn't get queue page %llx!\n", kvm_eq.qaddr); return -EINVAL; diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c index c664fdec75b1ab..e5a145b578a476 100644 --- a/arch/powerpc/kvm/e500_mmu_host.c +++ b/arch/powerpc/kvm/e500_mmu_host.c @@ -242,7 +242,7 @@ static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe) return tlbe->mas7_3 & (MAS3_SW|MAS3_UW); } -static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref, +static inline bool kvmppc_e500_ref_setup(struct tlbe_ref *ref, struct kvm_book3e_206_tlb_entry *gtlbe, kvm_pfn_t pfn, unsigned int wimg) { @@ -252,11 +252,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref, /* Use guest supplied MAS2_G and MAS2_E */ ref->flags |= (gtlbe->mas2 & MAS2_ATTRIB_MASK) | wimg; - /* Mark the page accessed */ - kvm_set_pfn_accessed(pfn); - - if (tlbe_is_writable(gtlbe)) - kvm_set_pfn_dirty(pfn); + return tlbe_is_writable(gtlbe); } static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref) @@ -326,6 +322,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, { struct kvm_memory_slot *slot; unsigned long pfn = 0; /* silence GCC warning */ + struct page *page = NULL; unsigned long hva; int pfnmap = 0; int tsize = BOOK3E_PAGESZ_4K; @@ -337,6 +334,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, unsigned int wimg = 0; pgd_t *pgdir; unsigned long flags; + bool writable = false; /* used to check for invalidations in progress */ mmu_seq = kvm->mmu_invalidate_seq; @@ -446,7 +444,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, if (likely(!pfnmap)) { tsize_pages = 1UL << (tsize + 10 - PAGE_SHIFT); - pfn = gfn_to_pfn_memslot(slot, gfn); + pfn = __kvm_faultin_pfn(slot, gfn, FOLL_WRITE, NULL, &page); if (is_error_noslot_pfn(pfn)) { if (printk_ratelimit()) pr_err("%s: real page not found for gfn %lx\n", @@ -490,7 +488,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, goto out; } } - kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg); + writable = kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg); kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize, ref, gvaddr, stlbe); @@ -499,11 +497,8 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, kvmppc_mmu_flush_icache(pfn); out: + kvm_release_faultin_page(kvm, page, !!ret, writable); spin_unlock(&kvm->mmu_lock); - - /* Drop refcount on page, so that mmu notifiers can clear it */ - kvm_release_pfn_clean(pfn); - return ret; } diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index f14329989e9a71..ce1d91eed231bc 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -612,9 +612,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = 8 | 4 | 2 | 1; } break; - case KVM_CAP_PPC_RMA: - r = 0; - break; case KVM_CAP_PPC_HWRNG: r = kvmppc_hwrng_present(); break; @@ -1933,12 +1930,11 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, #endif #ifdef CONFIG_KVM_MPIC case KVM_CAP_IRQ_MPIC: { - struct fd f; + CLASS(fd, f)(cap->args[0]); struct kvm_device *dev; r = -EBADF; - f = fdget(cap->args[0]); - if (!fd_file(f)) + if (fd_empty(f)) break; r = -EPERM; @@ -1946,18 +1942,16 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, if (dev) r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); - fdput(f); break; } #endif #ifdef CONFIG_KVM_XICS case KVM_CAP_IRQ_XICS: { - struct fd f; + CLASS(fd, f)(cap->args[0]); struct kvm_device *dev; r = -EBADF; - f = fdget(cap->args[0]); - if (!fd_file(f)) + if (fd_empty(f)) break; r = -EPERM; @@ -1968,34 +1962,27 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, else r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]); } - - fdput(f); break; } #endif /* CONFIG_KVM_XICS */ #ifdef CONFIG_KVM_XIVE case KVM_CAP_PPC_IRQ_XIVE: { - struct fd f; + CLASS(fd, f)(cap->args[0]); struct kvm_device *dev; r = -EBADF; - f = fdget(cap->args[0]); - if (!fd_file(f)) + if (fd_empty(f)) break; r = -ENXIO; - if (!xive_enabled()) { - fdput(f); + if (!xive_enabled()) break; - } r = -EPERM; dev = kvm_device_from_filp(fd_file(f)); if (dev) r = kvmppc_xive_native_connect_vcpu(dev, vcpu, cap->args[1]); - - fdput(f); break; } #endif /* CONFIG_KVM_XIVE */ diff --git a/arch/powerpc/kvm/trace_hv.h b/arch/powerpc/kvm/trace_hv.h index 77ebc724e6cdf4..35fccaa575cc15 100644 --- a/arch/powerpc/kvm/trace_hv.h +++ b/arch/powerpc/kvm/trace_hv.h @@ -538,7 +538,7 @@ TRACE_EVENT_FN_COND(kvmppc_vcpu_stats, TP_printk("VCPU %d: l1_to_l2_cs_time=%llu ns l2_to_l1_cs_time=%llu ns l2_runtime=%llu ns", __entry->vcpu_id, __entry->l1_to_l2_cs, __entry->l2_to_l1_cs, __entry->l2_runtime), - kmvhv_counters_tracepoint_regfunc, kmvhv_counters_tracepoint_unregfunc + kvmhv_counters_tracepoint_regfunc, kvmhv_counters_tracepoint_unregfunc ); #endif #endif /* _TRACE_KVM_HV_H */ diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index acdab294b340a8..af97fbb3c257ef 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include static int __patch_mem(void *exec_addr, unsigned long val, void *patch_addr, bool is_dword) diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index b7201ba50b2ea5..587c8cf1230fbd 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index e65f3fb68d06ba..ac3ee19531d8ac 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -780,8 +780,8 @@ static nokprobe_inline int emulate_stq(struct pt_regs *regs, unsigned long ea, #endif /* __powerpc64 */ #ifdef CONFIG_VSX -void emulate_vsx_load(struct instruction_op *op, union vsx_reg *reg, - const void *mem, bool rev) +static nokprobe_inline void emulate_vsx_load(struct instruction_op *op, union vsx_reg *reg, + const void *mem, bool rev) { int size, read_size; int i, j; @@ -863,11 +863,9 @@ void emulate_vsx_load(struct instruction_op *op, union vsx_reg *reg, break; } } -EXPORT_SYMBOL_GPL(emulate_vsx_load); -NOKPROBE_SYMBOL(emulate_vsx_load); -void emulate_vsx_store(struct instruction_op *op, const union vsx_reg *reg, - void *mem, bool rev) +static nokprobe_inline void emulate_vsx_store(struct instruction_op *op, const union vsx_reg *reg, + void *mem, bool rev) { int size, write_size; int i, j; @@ -955,8 +953,6 @@ void emulate_vsx_store(struct instruction_op *op, const union vsx_reg *reg, break; } } -EXPORT_SYMBOL_GPL(emulate_vsx_store); -NOKPROBE_SYMBOL(emulate_vsx_store); static nokprobe_inline int do_vsx_load(struct instruction_op *op, unsigned long ea, struct pt_regs *regs, diff --git a/arch/powerpc/lib/test-code-patching.c b/arch/powerpc/lib/test-code-patching.c index 8cd3b32f805b0f..1440d99630b339 100644 --- a/arch/powerpc/lib/test-code-patching.c +++ b/arch/powerpc/lib/test-code-patching.c @@ -6,7 +6,7 @@ #include #include -#include +#include static int __init instr_is_branch_to_addr(const u32 *instr, unsigned long addr) { diff --git a/arch/powerpc/lib/test_emulate_step.c b/arch/powerpc/lib/test_emulate_step.c index 23c7805fb7b3bd..66b5b4fa168649 100644 --- a/arch/powerpc/lib/test_emulate_step.c +++ b/arch/powerpc/lib/test_emulate_step.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #define MAX_SUBTESTS 16 diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c index 2db167f4233f7b..6978344edcb4b5 100644 --- a/arch/powerpc/mm/book3s32/mmu.c +++ b/arch/powerpc/mm/book3s32/mmu.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/mm/book3s64/hash_utils.c b/arch/powerpc/mm/book3s64/hash_utils.c index e1eadd03f13390..c8b4fa71d4a707 100644 --- a/arch/powerpc/mm/book3s64/hash_utils.c +++ b/arch/powerpc/mm/book3s64/hash_utils.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -57,7 +58,7 @@ #include #include #include -#include +#include #include #include #include @@ -66,6 +67,7 @@ #include #include #include +#include #include @@ -123,8 +125,6 @@ EXPORT_SYMBOL_GPL(mmu_slb_size); #ifdef CONFIG_PPC_64K_PAGES int mmu_ci_restrictions; #endif -static u8 *linear_map_hash_slots; -static unsigned long linear_map_hash_count; struct mmu_hash_ops mmu_hash_ops __ro_after_init; EXPORT_SYMBOL(mmu_hash_ops); @@ -273,6 +273,270 @@ void hash__tlbiel_all(unsigned int action) WARN(1, "%s called on pre-POWER7 CPU\n", __func__); } +#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) +static void kernel_map_linear_page(unsigned long vaddr, unsigned long idx, + u8 *slots, raw_spinlock_t *lock) +{ + unsigned long hash; + unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); + unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize); + unsigned long mode = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL), HPTE_USE_KERNEL_KEY); + long ret; + + hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); + + /* Don't create HPTE entries for bad address */ + if (!vsid) + return; + + if (slots[idx] & 0x80) + return; + + ret = hpte_insert_repeating(hash, vpn, __pa(vaddr), mode, + HPTE_V_BOLTED, + mmu_linear_psize, mmu_kernel_ssize); + + BUG_ON (ret < 0); + raw_spin_lock(lock); + BUG_ON(slots[idx] & 0x80); + slots[idx] = ret | 0x80; + raw_spin_unlock(lock); +} + +static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long idx, + u8 *slots, raw_spinlock_t *lock) +{ + unsigned long hash, hslot, slot; + unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); + unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize); + + hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); + raw_spin_lock(lock); + if (!(slots[idx] & 0x80)) { + raw_spin_unlock(lock); + return; + } + hslot = slots[idx] & 0x7f; + slots[idx] = 0; + raw_spin_unlock(lock); + if (hslot & _PTEIDX_SECONDARY) + hash = ~hash; + slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; + slot += hslot & _PTEIDX_GROUP_IX; + mmu_hash_ops.hpte_invalidate(slot, vpn, mmu_linear_psize, + mmu_linear_psize, + mmu_kernel_ssize, 0); +} +#endif + +static inline bool hash_supports_debug_pagealloc(void) +{ + unsigned long max_hash_count = ppc64_rma_size / 4; + unsigned long linear_map_count = memblock_end_of_DRAM() >> PAGE_SHIFT; + + if (!debug_pagealloc_enabled() || linear_map_count > max_hash_count) + return false; + return true; +} + +#ifdef CONFIG_DEBUG_PAGEALLOC +static u8 *linear_map_hash_slots; +static unsigned long linear_map_hash_count; +static DEFINE_RAW_SPINLOCK(linear_map_hash_lock); +static void hash_debug_pagealloc_alloc_slots(void) +{ + if (!hash_supports_debug_pagealloc()) + return; + + linear_map_hash_count = memblock_end_of_DRAM() >> PAGE_SHIFT; + linear_map_hash_slots = memblock_alloc_try_nid( + linear_map_hash_count, 1, MEMBLOCK_LOW_LIMIT, + ppc64_rma_size, NUMA_NO_NODE); + if (!linear_map_hash_slots) + panic("%s: Failed to allocate %lu bytes max_addr=%pa\n", + __func__, linear_map_hash_count, &ppc64_rma_size); +} + +static inline void hash_debug_pagealloc_add_slot(phys_addr_t paddr, + int slot) +{ + if (!debug_pagealloc_enabled() || !linear_map_hash_count) + return; + if ((paddr >> PAGE_SHIFT) < linear_map_hash_count) + linear_map_hash_slots[paddr >> PAGE_SHIFT] = slot | 0x80; +} + +static int hash_debug_pagealloc_map_pages(struct page *page, int numpages, + int enable) +{ + unsigned long flags, vaddr, lmi; + int i; + + if (!debug_pagealloc_enabled() || !linear_map_hash_count) + return 0; + + local_irq_save(flags); + for (i = 0; i < numpages; i++, page++) { + vaddr = (unsigned long)page_address(page); + lmi = __pa(vaddr) >> PAGE_SHIFT; + if (lmi >= linear_map_hash_count) + continue; + if (enable) + kernel_map_linear_page(vaddr, lmi, + linear_map_hash_slots, &linear_map_hash_lock); + else + kernel_unmap_linear_page(vaddr, lmi, + linear_map_hash_slots, &linear_map_hash_lock); + } + local_irq_restore(flags); + return 0; +} + +#else /* CONFIG_DEBUG_PAGEALLOC */ +static inline void hash_debug_pagealloc_alloc_slots(void) {} +static inline void hash_debug_pagealloc_add_slot(phys_addr_t paddr, int slot) {} +static int __maybe_unused +hash_debug_pagealloc_map_pages(struct page *page, int numpages, int enable) +{ + return 0; +} +#endif /* CONFIG_DEBUG_PAGEALLOC */ + +#ifdef CONFIG_KFENCE +static u8 *linear_map_kf_hash_slots; +static unsigned long linear_map_kf_hash_count; +static DEFINE_RAW_SPINLOCK(linear_map_kf_hash_lock); + +static phys_addr_t kfence_pool; + +static inline void hash_kfence_alloc_pool(void) +{ + if (!kfence_early_init_enabled()) + goto err; + + /* allocate linear map for kfence within RMA region */ + linear_map_kf_hash_count = KFENCE_POOL_SIZE >> PAGE_SHIFT; + linear_map_kf_hash_slots = memblock_alloc_try_nid( + linear_map_kf_hash_count, 1, + MEMBLOCK_LOW_LIMIT, ppc64_rma_size, + NUMA_NO_NODE); + if (!linear_map_kf_hash_slots) { + pr_err("%s: memblock for linear map (%lu) failed\n", __func__, + linear_map_kf_hash_count); + goto err; + } + + /* allocate kfence pool early */ + kfence_pool = memblock_phys_alloc_range(KFENCE_POOL_SIZE, PAGE_SIZE, + MEMBLOCK_LOW_LIMIT, MEMBLOCK_ALLOC_ANYWHERE); + if (!kfence_pool) { + pr_err("%s: memblock for kfence pool (%lu) failed\n", __func__, + KFENCE_POOL_SIZE); + memblock_free(linear_map_kf_hash_slots, + linear_map_kf_hash_count); + linear_map_kf_hash_count = 0; + goto err; + } + memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE); + + return; +err: + pr_info("Disabling kfence\n"); + disable_kfence(); +} + +static inline void hash_kfence_map_pool(void) +{ + unsigned long kfence_pool_start, kfence_pool_end; + unsigned long prot = pgprot_val(PAGE_KERNEL); + + if (!kfence_pool) + return; + + kfence_pool_start = (unsigned long) __va(kfence_pool); + kfence_pool_end = kfence_pool_start + KFENCE_POOL_SIZE; + __kfence_pool = (char *) kfence_pool_start; + BUG_ON(htab_bolt_mapping(kfence_pool_start, kfence_pool_end, + kfence_pool, prot, mmu_linear_psize, + mmu_kernel_ssize)); + memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE); +} + +static inline void hash_kfence_add_slot(phys_addr_t paddr, int slot) +{ + unsigned long vaddr = (unsigned long) __va(paddr); + unsigned long lmi = (vaddr - (unsigned long)__kfence_pool) + >> PAGE_SHIFT; + + if (!kfence_pool) + return; + BUG_ON(!is_kfence_address((void *)vaddr)); + BUG_ON(lmi >= linear_map_kf_hash_count); + linear_map_kf_hash_slots[lmi] = slot | 0x80; +} + +static int hash_kfence_map_pages(struct page *page, int numpages, int enable) +{ + unsigned long flags, vaddr, lmi; + int i; + + WARN_ON_ONCE(!linear_map_kf_hash_count); + local_irq_save(flags); + for (i = 0; i < numpages; i++, page++) { + vaddr = (unsigned long)page_address(page); + lmi = (vaddr - (unsigned long)__kfence_pool) >> PAGE_SHIFT; + + /* Ideally this should never happen */ + if (lmi >= linear_map_kf_hash_count) { + WARN_ON_ONCE(1); + continue; + } + + if (enable) + kernel_map_linear_page(vaddr, lmi, + linear_map_kf_hash_slots, + &linear_map_kf_hash_lock); + else + kernel_unmap_linear_page(vaddr, lmi, + linear_map_kf_hash_slots, + &linear_map_kf_hash_lock); + } + local_irq_restore(flags); + return 0; +} +#else +static inline void hash_kfence_alloc_pool(void) {} +static inline void hash_kfence_map_pool(void) {} +static inline void hash_kfence_add_slot(phys_addr_t paddr, int slot) {} +static int __maybe_unused +hash_kfence_map_pages(struct page *page, int numpages, int enable) +{ + return 0; +} +#endif + +#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) +int hash__kernel_map_pages(struct page *page, int numpages, int enable) +{ + void *vaddr = page_address(page); + + if (is_kfence_address(vaddr)) + return hash_kfence_map_pages(page, numpages, enable); + else + return hash_debug_pagealloc_map_pages(page, numpages, enable); +} + +static void hash_linear_map_add_slot(phys_addr_t paddr, int slot) +{ + if (is_kfence_address(__va(paddr))) + hash_kfence_add_slot(paddr, slot); + else + hash_debug_pagealloc_add_slot(paddr, slot); +} +#else +static void hash_linear_map_add_slot(phys_addr_t paddr, int slot) {} +#endif + /* * 'R' and 'C' update notes: * - Under pHyp or KVM, the updatepp path will not set C, thus it *will* @@ -431,9 +695,8 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, break; cond_resched(); - if (debug_pagealloc_enabled_or_kfence() && - (paddr >> PAGE_SHIFT) < linear_map_hash_count) - linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80; + /* add slot info in debug_pagealloc / kfence linear map */ + hash_linear_map_add_slot(paddr, ret); } return ret < 0 ? ret : 0; } @@ -814,7 +1077,7 @@ static void __init htab_init_page_sizes(void) bool aligned = true; init_hpte_page_sizes(); - if (!debug_pagealloc_enabled_or_kfence()) { + if (!hash_supports_debug_pagealloc() && !kfence_early_init_enabled()) { /* * Pick a size for the linear mapping. Currently, we only * support 16M, 1M and 4K which is the default @@ -1134,16 +1397,8 @@ static void __init htab_initialize(void) prot = pgprot_val(PAGE_KERNEL); - if (debug_pagealloc_enabled_or_kfence()) { - linear_map_hash_count = memblock_end_of_DRAM() >> PAGE_SHIFT; - linear_map_hash_slots = memblock_alloc_try_nid( - linear_map_hash_count, 1, MEMBLOCK_LOW_LIMIT, - ppc64_rma_size, NUMA_NO_NODE); - if (!linear_map_hash_slots) - panic("%s: Failed to allocate %lu bytes max_addr=%pa\n", - __func__, linear_map_hash_count, &ppc64_rma_size); - } - + hash_debug_pagealloc_alloc_slots(); + hash_kfence_alloc_pool(); /* create bolted the linear mapping in the hash table */ for_each_mem_range(i, &base, &end) { size = end - base; @@ -1160,6 +1415,7 @@ static void __init htab_initialize(void) BUG_ON(htab_bolt_mapping(base, base + size, __pa(base), prot, mmu_linear_psize, mmu_kernel_ssize)); } + hash_kfence_map_pool(); memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE); /* @@ -2120,82 +2376,6 @@ void hpt_do_stress(unsigned long ea, unsigned long hpte_group) } } -#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) -static DEFINE_RAW_SPINLOCK(linear_map_hash_lock); - -static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi) -{ - unsigned long hash; - unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); - unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize); - unsigned long mode = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL), HPTE_USE_KERNEL_KEY); - long ret; - - hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); - - /* Don't create HPTE entries for bad address */ - if (!vsid) - return; - - if (linear_map_hash_slots[lmi] & 0x80) - return; - - ret = hpte_insert_repeating(hash, vpn, __pa(vaddr), mode, - HPTE_V_BOLTED, - mmu_linear_psize, mmu_kernel_ssize); - - BUG_ON (ret < 0); - raw_spin_lock(&linear_map_hash_lock); - BUG_ON(linear_map_hash_slots[lmi] & 0x80); - linear_map_hash_slots[lmi] = ret | 0x80; - raw_spin_unlock(&linear_map_hash_lock); -} - -static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi) -{ - unsigned long hash, hidx, slot; - unsigned long vsid = get_kernel_vsid(vaddr, mmu_kernel_ssize); - unsigned long vpn = hpt_vpn(vaddr, vsid, mmu_kernel_ssize); - - hash = hpt_hash(vpn, PAGE_SHIFT, mmu_kernel_ssize); - raw_spin_lock(&linear_map_hash_lock); - if (!(linear_map_hash_slots[lmi] & 0x80)) { - raw_spin_unlock(&linear_map_hash_lock); - return; - } - hidx = linear_map_hash_slots[lmi] & 0x7f; - linear_map_hash_slots[lmi] = 0; - raw_spin_unlock(&linear_map_hash_lock); - if (hidx & _PTEIDX_SECONDARY) - hash = ~hash; - slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; - slot += hidx & _PTEIDX_GROUP_IX; - mmu_hash_ops.hpte_invalidate(slot, vpn, mmu_linear_psize, - mmu_linear_psize, - mmu_kernel_ssize, 0); -} - -int hash__kernel_map_pages(struct page *page, int numpages, int enable) -{ - unsigned long flags, vaddr, lmi; - int i; - - local_irq_save(flags); - for (i = 0; i < numpages; i++, page++) { - vaddr = (unsigned long)page_address(page); - lmi = __pa(vaddr) >> PAGE_SHIFT; - if (lmi >= linear_map_hash_count) - continue; - if (enable) - kernel_map_linear_page(vaddr, lmi); - else - kernel_unmap_linear_page(vaddr, lmi); - } - local_irq_restore(flags); - return 0; -} -#endif /* CONFIG_DEBUG_PAGEALLOC || CONFIG_KFENCE */ - void hash__setup_initial_memory_limit(phys_addr_t first_memblock_base, phys_addr_t first_memblock_size) { diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c index 5a4a7536904319..3745425280808b 100644 --- a/arch/powerpc/mm/book3s64/pgtable.c +++ b/arch/powerpc/mm/book3s64/pgtable.c @@ -37,6 +37,19 @@ EXPORT_SYMBOL(__pmd_frag_nr); unsigned long __pmd_frag_size_shift; EXPORT_SYMBOL(__pmd_frag_size_shift); +#ifdef CONFIG_KFENCE +extern bool kfence_early_init; +static int __init parse_kfence_early_init(char *arg) +{ + int val; + + if (get_option(&arg, &val)) + kfence_early_init = !!val; + return 0; +} +early_param("kfence.sample_interval", parse_kfence_early_init); +#endif + #ifdef CONFIG_TRANSPARENT_HUGEPAGE /* * This is called when relaxing access to a hugepage. It's also called in the page diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c index b0d927009af83c..311e2112d782ea 100644 --- a/arch/powerpc/mm/book3s64/radix_pgtable.c +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c @@ -363,18 +363,6 @@ static int __meminit create_physical_mapping(unsigned long start, } #ifdef CONFIG_KFENCE -static bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL; - -static int __init parse_kfence_early_init(char *arg) -{ - int val; - - if (get_option(&arg, &val)) - kfence_early_init = !!val; - return 0; -} -early_param("kfence.sample_interval", parse_kfence_early_init); - static inline phys_addr_t alloc_kfence_pool(void) { phys_addr_t kfence_pool; diff --git a/arch/powerpc/mm/book3s64/slb.c b/arch/powerpc/mm/book3s64/slb.c index f2708c8629a527..6b783552403c60 100644 --- a/arch/powerpc/mm/book3s64/slb.c +++ b/arch/powerpc/mm/book3s64/slb.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include "internal.h" diff --git a/arch/powerpc/mm/book3s64/slice.c b/arch/powerpc/mm/book3s64/slice.c index 87307d0fc3b813..bc9a39821d1c6b 100644 --- a/arch/powerpc/mm/book3s64/slice.c +++ b/arch/powerpc/mm/book3s64/slice.c @@ -633,6 +633,20 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, } EXPORT_SYMBOL_GPL(slice_get_unmapped_area); +#ifdef CONFIG_HUGETLB_PAGE +static int file_to_psize(struct file *file) +{ + struct hstate *hstate = hstate_file(file); + + return shift_to_mmu_psize(huge_page_shift(hstate)); +} +#else +static int file_to_psize(struct file *file) +{ + return 0; +} +#endif + unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, @@ -640,11 +654,17 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long flags, vm_flags_t vm_flags) { + unsigned int psize; + if (radix_enabled()) return generic_get_unmapped_area(filp, addr, len, pgoff, flags, vm_flags); - return slice_get_unmapped_area(addr, len, flags, - mm_ctx_user_psize(¤t->mm->context), 0); + if (filp && is_file_hugepages(filp)) + psize = file_to_psize(filp); + else + psize = mm_ctx_user_psize(¤t->mm->context); + + return slice_get_unmapped_area(addr, len, flags, psize, 0); } unsigned long arch_get_unmapped_area_topdown(struct file *filp, @@ -654,11 +674,17 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp, const unsigned long flags, vm_flags_t vm_flags) { + unsigned int psize; + if (radix_enabled()) return generic_get_unmapped_area_topdown(filp, addr0, len, pgoff, flags, vm_flags); - return slice_get_unmapped_area(addr0, len, flags, - mm_ctx_user_psize(¤t->mm->context), 1); + if (filp && is_file_hugepages(filp)) + psize = file_to_psize(filp); + else + psize = mm_ctx_user_psize(¤t->mm->context); + + return slice_get_unmapped_area(addr0, len, flags, psize, 1); } unsigned int notrace get_slice_psize(struct mm_struct *mm, unsigned long addr) @@ -788,20 +814,4 @@ unsigned long vma_mmu_pagesize(struct vm_area_struct *vma) return 1UL << mmu_psize_to_shift(get_slice_psize(vma->vm_mm, vma->vm_start)); } - -static int file_to_psize(struct file *file) -{ - struct hstate *hstate = hstate_file(file); - return shift_to_mmu_psize(huge_page_shift(hstate)); -} - -unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, - unsigned long flags) -{ - if (radix_enabled()) - return generic_hugetlb_get_unmapped_area(file, addr, len, pgoff, flags); - - return slice_get_unmapped_area(addr, len, flags, file_to_psize(file), 1); -} #endif diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 81c77ddce2e30a..c156fe0d53c378 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -439,10 +439,16 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address, /* * The kernel should never take an execute fault nor should it * take a page fault to a kernel address or a page fault to a user - * address outside of dedicated places + * address outside of dedicated places. + * + * Rather than kfence directly reporting false negatives, search whether + * the NIP belongs to the fixup table for cases where fault could come + * from functions like copy_from_kernel_nofault(). */ if (unlikely(!is_user && bad_kernel_fault(regs, error_code, address, is_write))) { - if (kfence_handle_page_fault(address, is_write, regs)) + if (is_kfence_address((void *)address) && + !search_exception_tables(instruction_pointer(regs)) && + kfence_handle_page_fault(address, is_write, regs)) return 0; return SIGSEGV; diff --git a/arch/powerpc/mm/init-common.c b/arch/powerpc/mm/init-common.c index 2978fcbe307eab..745097554bea00 100644 --- a/arch/powerpc/mm/init-common.c +++ b/arch/powerpc/mm/init-common.c @@ -33,6 +33,7 @@ bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP); bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP); #ifdef CONFIG_KFENCE bool __ro_after_init kfence_disabled; +bool __ro_after_init kfence_early_init = !!CONFIG_KFENCE_SAMPLE_INTERVAL; #endif static int __init parse_nosmep(char *p) diff --git a/arch/powerpc/mm/kasan/init_32.c b/arch/powerpc/mm/kasan/init_32.c index aa9aa11927b2f8..03666d790a5351 100644 --- a/arch/powerpc/mm/kasan/init_32.c +++ b/arch/powerpc/mm/kasan/init_32.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include static pgprot_t __init kasan_prot_ro(void) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 1221c561b43a0b..c7708c8fad299b 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/mm/nohash/44x.c b/arch/powerpc/mm/nohash/44x.c index 1beae802bb1c0d..6d10c6d8be7192 100644 --- a/arch/powerpc/mm/nohash/44x.c +++ b/arch/powerpc/mm/nohash/44x.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/mm/nohash/book3e_pgtable.c b/arch/powerpc/mm/nohash/book3e_pgtable.c index ad2a7c26f2a00b..062e8785c1bb64 100644 --- a/arch/powerpc/mm/nohash/book3e_pgtable.c +++ b/arch/powerpc/mm/nohash/book3e_pgtable.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include diff --git a/arch/powerpc/mm/nohash/tlb.c b/arch/powerpc/mm/nohash/tlb.c index b653a7be4cb1d3..0a650742f3a008 100644 --- a/arch/powerpc/mm/nohash/tlb.c +++ b/arch/powerpc/mm/nohash/tlb.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/mm/nohash/tlb_64e.c b/arch/powerpc/mm/nohash/tlb_64e.c index d26656b07b72cd..4f925adf269597 100644 --- a/arch/powerpc/mm/nohash/tlb_64e.c +++ b/arch/powerpc/mm/nohash/tlb_64e.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 7316396e452d8d..61df5aed798943 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c @@ -398,7 +398,7 @@ void assert_pte_locked(struct mm_struct *mm, unsigned long addr) */ if (pmd_none(*pmd)) return; - pte = pte_offset_map_nolock(mm, pmd, addr, &ptl); + pte = pte_offset_map_ro_nolock(mm, pmd, addr, &ptl); BUG_ON(!pte); assert_spin_locked(ptl); pte_unmap(pte); diff --git a/arch/powerpc/net/bpf_jit.h b/arch/powerpc/net/bpf_jit.h index cdea5dccaefe73..6beacaec63d303 100644 --- a/arch/powerpc/net/bpf_jit.h +++ b/arch/powerpc/net/bpf_jit.h @@ -12,6 +12,7 @@ #include #include +#include #ifdef CONFIG_PPC64_ELF_ABI_V1 #define FUNCTION_DESCR_SIZE 24 @@ -21,6 +22,9 @@ #define CTX_NIA(ctx) ((unsigned long)ctx->idx * 4) +#define SZL sizeof(unsigned long) +#define BPF_INSN_SAFETY 64 + #define PLANT_INSTR(d, idx, instr) \ do { if (d) { (d)[idx] = instr; } idx++; } while (0) #define EMIT(instr) PLANT_INSTR(image, ctx->idx, instr) @@ -81,6 +85,18 @@ EMIT(PPC_RAW_ORI(d, d, (uintptr_t)(i) & \ 0xffff)); \ } } while (0) +#define PPC_LI_ADDR PPC_LI64 + +#ifndef CONFIG_PPC_KERNEL_PCREL +#define PPC64_LOAD_PACA() \ + EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc))) +#else +#define PPC64_LOAD_PACA() do {} while (0) +#endif +#else +#define PPC_LI64(d, i) BUILD_BUG() +#define PPC_LI_ADDR PPC_LI32 +#define PPC64_LOAD_PACA() BUILD_BUG() #endif /* @@ -165,6 +181,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code u32 *addrs, int pass, bool extra_pass); void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx); void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx); +void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx); void bpf_jit_realloc_regs(struct codegen_context *ctx); int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr); diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index 2a36cc2e7e9e21..2991bb171a9bbe 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -18,15 +18,85 @@ #include #include -#include +#include #include "bpf_jit.h" +/* These offsets are from bpf prog end and stay the same across progs */ +static int bpf_jit_ool_stub, bpf_jit_long_branch_stub; + static void bpf_jit_fill_ill_insns(void *area, unsigned int size) { memset32(area, BREAKPOINT_INSTRUCTION, size / 4); } +void dummy_tramp(void); + +asm ( +" .pushsection .text, \"ax\", @progbits ;" +" .global dummy_tramp ;" +" .type dummy_tramp, @function ;" +"dummy_tramp: ;" +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +" blr ;" +#else +/* LR is always in r11, so we don't need a 'mflr r11' here */ +" mtctr 11 ;" +" mtlr 0 ;" +" bctr ;" +#endif +" .size dummy_tramp, .-dummy_tramp ;" +" .popsection ;" +); + +void bpf_jit_build_fentry_stubs(u32 *image, struct codegen_context *ctx) +{ + int ool_stub_idx, long_branch_stub_idx; + + /* + * Out-of-line stub: + * mflr r0 + * [b|bl] tramp + * mtlr r0 // only with CONFIG_PPC_FTRACE_OUT_OF_LINE + * b bpf_func + 4 + */ + ool_stub_idx = ctx->idx; + EMIT(PPC_RAW_MFLR(_R0)); + EMIT(PPC_RAW_NOP()); + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) + EMIT(PPC_RAW_MTLR(_R0)); + WARN_ON_ONCE(!is_offset_in_branch_range(4 - (long)ctx->idx * 4)); + EMIT(PPC_RAW_BRANCH(4 - (long)ctx->idx * 4)); + + /* + * Long branch stub: + * .long + * mflr r11 + * bcl 20,31,$+4 + * mflr r12 + * ld r12, -8-SZL(r12) + * mtctr r12 + * mtlr r11 // needed to retain ftrace ABI + * bctr + */ + if (image) + *((unsigned long *)&image[ctx->idx]) = (unsigned long)dummy_tramp; + ctx->idx += SZL / 4; + long_branch_stub_idx = ctx->idx; + EMIT(PPC_RAW_MFLR(_R11)); + EMIT(PPC_RAW_BCL4()); + EMIT(PPC_RAW_MFLR(_R12)); + EMIT(PPC_RAW_LL(_R12, _R12, -8-SZL)); + EMIT(PPC_RAW_MTCTR(_R12)); + EMIT(PPC_RAW_MTLR(_R11)); + EMIT(PPC_RAW_BCTR()); + + if (!bpf_jit_ool_stub) { + bpf_jit_ool_stub = (ctx->idx - ool_stub_idx) * 4; + bpf_jit_long_branch_stub = (ctx->idx - long_branch_stub_idx) * 4; + } +} + int bpf_jit_emit_exit_insn(u32 *image, struct codegen_context *ctx, int tmp_reg, long exit_addr) { if (!exit_addr || is_offset_in_branch_range(exit_addr - (ctx->idx * 4))) { @@ -222,7 +292,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) fp->bpf_func = (void *)fimage; fp->jited = 1; - fp->jited_len = proglen + FUNCTION_DESCR_SIZE; + fp->jited_len = cgctx.idx * 4 + FUNCTION_DESCR_SIZE; if (!fp->is_func || extra_pass) { if (bpf_jit_binary_pack_finalize(fhdr, hdr)) { @@ -369,3 +439,778 @@ bool bpf_jit_supports_far_kfunc_call(void) { return IS_ENABLED(CONFIG_PPC64); } + +void *arch_alloc_bpf_trampoline(unsigned int size) +{ + return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns); +} + +void arch_free_bpf_trampoline(void *image, unsigned int size) +{ + bpf_prog_pack_free(image, size); +} + +int arch_protect_bpf_trampoline(void *image, unsigned int size) +{ + return 0; +} + +static int invoke_bpf_prog(u32 *image, u32 *ro_image, struct codegen_context *ctx, + struct bpf_tramp_link *l, int regs_off, int retval_off, + int run_ctx_off, bool save_ret) +{ + struct bpf_prog *p = l->link.prog; + ppc_inst_t branch_insn; + u32 jmp_idx; + int ret = 0; + + /* Save cookie */ + if (IS_ENABLED(CONFIG_PPC64)) { + PPC_LI64(_R3, l->cookie); + EMIT(PPC_RAW_STD(_R3, _R1, run_ctx_off + offsetof(struct bpf_tramp_run_ctx, + bpf_cookie))); + } else { + PPC_LI32(_R3, l->cookie >> 32); + PPC_LI32(_R4, l->cookie); + EMIT(PPC_RAW_STW(_R3, _R1, + run_ctx_off + offsetof(struct bpf_tramp_run_ctx, bpf_cookie))); + EMIT(PPC_RAW_STW(_R4, _R1, + run_ctx_off + offsetof(struct bpf_tramp_run_ctx, bpf_cookie) + 4)); + } + + /* __bpf_prog_enter(p, &bpf_tramp_run_ctx) */ + PPC_LI_ADDR(_R3, p); + EMIT(PPC_RAW_MR(_R25, _R3)); + EMIT(PPC_RAW_ADDI(_R4, _R1, run_ctx_off)); + ret = bpf_jit_emit_func_call_rel(image, ro_image, ctx, + (unsigned long)bpf_trampoline_enter(p)); + if (ret) + return ret; + + /* Remember prog start time returned by __bpf_prog_enter */ + EMIT(PPC_RAW_MR(_R26, _R3)); + + /* + * if (__bpf_prog_enter(p) == 0) + * goto skip_exec_of_prog; + * + * Emit a nop to be later patched with conditional branch, once offset is known + */ + EMIT(PPC_RAW_CMPLI(_R3, 0)); + jmp_idx = ctx->idx; + EMIT(PPC_RAW_NOP()); + + /* p->bpf_func(ctx) */ + EMIT(PPC_RAW_ADDI(_R3, _R1, regs_off)); + if (!p->jited) + PPC_LI_ADDR(_R4, (unsigned long)p->insnsi); + if (!create_branch(&branch_insn, (u32 *)&ro_image[ctx->idx], (unsigned long)p->bpf_func, + BRANCH_SET_LINK)) { + if (image) + image[ctx->idx] = ppc_inst_val(branch_insn); + ctx->idx++; + } else { + EMIT(PPC_RAW_LL(_R12, _R25, offsetof(struct bpf_prog, bpf_func))); + EMIT(PPC_RAW_MTCTR(_R12)); + EMIT(PPC_RAW_BCTRL()); + } + + if (save_ret) + EMIT(PPC_RAW_STL(_R3, _R1, retval_off)); + + /* Fix up branch */ + if (image) { + if (create_cond_branch(&branch_insn, &image[jmp_idx], + (unsigned long)&image[ctx->idx], COND_EQ << 16)) + return -EINVAL; + image[jmp_idx] = ppc_inst_val(branch_insn); + } + + /* __bpf_prog_exit(p, start_time, &bpf_tramp_run_ctx) */ + EMIT(PPC_RAW_MR(_R3, _R25)); + EMIT(PPC_RAW_MR(_R4, _R26)); + EMIT(PPC_RAW_ADDI(_R5, _R1, run_ctx_off)); + ret = bpf_jit_emit_func_call_rel(image, ro_image, ctx, + (unsigned long)bpf_trampoline_exit(p)); + + return ret; +} + +static int invoke_bpf_mod_ret(u32 *image, u32 *ro_image, struct codegen_context *ctx, + struct bpf_tramp_links *tl, int regs_off, int retval_off, + int run_ctx_off, u32 *branches) +{ + int i; + + /* + * The first fmod_ret program will receive a garbage return value. + * Set this to 0 to avoid confusing the program. + */ + EMIT(PPC_RAW_LI(_R3, 0)); + EMIT(PPC_RAW_STL(_R3, _R1, retval_off)); + for (i = 0; i < tl->nr_links; i++) { + if (invoke_bpf_prog(image, ro_image, ctx, tl->links[i], regs_off, retval_off, + run_ctx_off, true)) + return -EINVAL; + + /* + * mod_ret prog stored return value after prog ctx. Emit: + * if (*(u64 *)(ret_val) != 0) + * goto do_fexit; + */ + EMIT(PPC_RAW_LL(_R3, _R1, retval_off)); + EMIT(PPC_RAW_CMPLI(_R3, 0)); + + /* + * Save the location of the branch and generate a nop, which is + * replaced with a conditional jump once do_fexit (i.e. the + * start of the fexit invocation) is finalized. + */ + branches[i] = ctx->idx; + EMIT(PPC_RAW_NOP()); + } + + return 0; +} + +static void bpf_trampoline_setup_tail_call_cnt(u32 *image, struct codegen_context *ctx, + int func_frame_offset, int r4_off) +{ + if (IS_ENABLED(CONFIG_PPC64)) { + /* See bpf_jit_stack_tailcallcnt() */ + int tailcallcnt_offset = 6 * 8; + + EMIT(PPC_RAW_LL(_R3, _R1, func_frame_offset - tailcallcnt_offset)); + EMIT(PPC_RAW_STL(_R3, _R1, -tailcallcnt_offset)); + } else { + /* See bpf_jit_stack_offsetof() and BPF_PPC_TC */ + EMIT(PPC_RAW_LL(_R4, _R1, r4_off)); + } +} + +static void bpf_trampoline_restore_tail_call_cnt(u32 *image, struct codegen_context *ctx, + int func_frame_offset, int r4_off) +{ + if (IS_ENABLED(CONFIG_PPC64)) { + /* See bpf_jit_stack_tailcallcnt() */ + int tailcallcnt_offset = 6 * 8; + + EMIT(PPC_RAW_LL(_R3, _R1, -tailcallcnt_offset)); + EMIT(PPC_RAW_STL(_R3, _R1, func_frame_offset - tailcallcnt_offset)); + } else { + /* See bpf_jit_stack_offsetof() and BPF_PPC_TC */ + EMIT(PPC_RAW_STL(_R4, _R1, r4_off)); + } +} + +static void bpf_trampoline_save_args(u32 *image, struct codegen_context *ctx, int func_frame_offset, + int nr_regs, int regs_off) +{ + int param_save_area_offset; + + param_save_area_offset = func_frame_offset; /* the two frames we alloted */ + param_save_area_offset += STACK_FRAME_MIN_SIZE; /* param save area is past frame header */ + + for (int i = 0; i < nr_regs; i++) { + if (i < 8) { + EMIT(PPC_RAW_STL(_R3 + i, _R1, regs_off + i * SZL)); + } else { + EMIT(PPC_RAW_LL(_R3, _R1, param_save_area_offset + i * SZL)); + EMIT(PPC_RAW_STL(_R3, _R1, regs_off + i * SZL)); + } + } +} + +/* Used when restoring just the register parameters when returning back */ +static void bpf_trampoline_restore_args_regs(u32 *image, struct codegen_context *ctx, + int nr_regs, int regs_off) +{ + for (int i = 0; i < nr_regs && i < 8; i++) + EMIT(PPC_RAW_LL(_R3 + i, _R1, regs_off + i * SZL)); +} + +/* Used when we call into the traced function. Replicate parameter save area */ +static void bpf_trampoline_restore_args_stack(u32 *image, struct codegen_context *ctx, + int func_frame_offset, int nr_regs, int regs_off) +{ + int param_save_area_offset; + + param_save_area_offset = func_frame_offset; /* the two frames we alloted */ + param_save_area_offset += STACK_FRAME_MIN_SIZE; /* param save area is past frame header */ + + for (int i = 8; i < nr_regs; i++) { + EMIT(PPC_RAW_LL(_R3, _R1, param_save_area_offset + i * SZL)); + EMIT(PPC_RAW_STL(_R3, _R1, STACK_FRAME_MIN_SIZE + i * SZL)); + } + bpf_trampoline_restore_args_regs(image, ctx, nr_regs, regs_off); +} + +static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_image, + void *rw_image_end, void *ro_image, + const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, + void *func_addr) +{ + int regs_off, nregs_off, ip_off, run_ctx_off, retval_off, nvr_off, alt_lr_off, r4_off = 0; + int i, ret, nr_regs, bpf_frame_size = 0, bpf_dummy_frame_size = 0, func_frame_offset; + struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN]; + struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; + struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT]; + struct codegen_context codegen_ctx, *ctx; + u32 *image = (u32 *)rw_image; + ppc_inst_t branch_insn; + u32 *branches = NULL; + bool save_ret; + + if (IS_ENABLED(CONFIG_PPC32)) + return -EOPNOTSUPP; + + nr_regs = m->nr_args; + /* Extra registers for struct arguments */ + for (i = 0; i < m->nr_args; i++) + if (m->arg_size[i] > SZL) + nr_regs += round_up(m->arg_size[i], SZL) / SZL - 1; + + if (nr_regs > MAX_BPF_FUNC_ARGS) + return -EOPNOTSUPP; + + ctx = &codegen_ctx; + memset(ctx, 0, sizeof(*ctx)); + + /* + * Generated stack layout: + * + * func prev back chain [ back chain ] + * [ ] + * bpf prog redzone/tailcallcnt [ ... ] 64 bytes (64-bit powerpc) + * [ ] -- + * LR save area [ r0 save (64-bit) ] | header + * [ r0 save (32-bit) ] | + * dummy frame for unwind [ back chain 1 ] -- + * [ padding ] align stack frame + * r4_off [ r4 (tailcallcnt) ] optional - 32-bit powerpc + * alt_lr_off [ real lr (ool stub)] optional - actual lr + * [ r26 ] + * nvr_off [ r25 ] nvr save area + * retval_off [ return value ] + * [ reg argN ] + * [ ... ] + * regs_off [ reg_arg1 ] prog ctx context + * nregs_off [ args count ] + * ip_off [ traced function ] + * [ ... ] + * run_ctx_off [ bpf_tramp_run_ctx ] + * [ reg argN ] + * [ ... ] + * param_save_area [ reg_arg1 ] min 8 doublewords, per ABI + * [ TOC save (64-bit) ] -- + * [ LR save (64-bit) ] | header + * [ LR save (32-bit) ] | + * bpf trampoline frame [ back chain 2 ] -- + * + */ + + /* Minimum stack frame header */ + bpf_frame_size = STACK_FRAME_MIN_SIZE; + + /* + * Room for parameter save area. + * + * As per the ABI, this is required if we call into the traced + * function (BPF_TRAMP_F_CALL_ORIG): + * - if the function takes more than 8 arguments for the rest to spill onto the stack + * - or, if the function has variadic arguments + * - or, if this functions's prototype was not available to the caller + * + * Reserve space for at least 8 registers for now. This can be optimized later. + */ + bpf_frame_size += (nr_regs > 8 ? nr_regs : 8) * SZL; + + /* Room for struct bpf_tramp_run_ctx */ + run_ctx_off = bpf_frame_size; + bpf_frame_size += round_up(sizeof(struct bpf_tramp_run_ctx), SZL); + + /* Room for IP address argument */ + ip_off = bpf_frame_size; + if (flags & BPF_TRAMP_F_IP_ARG) + bpf_frame_size += SZL; + + /* Room for args count */ + nregs_off = bpf_frame_size; + bpf_frame_size += SZL; + + /* Room for args */ + regs_off = bpf_frame_size; + bpf_frame_size += nr_regs * SZL; + + /* Room for return value of func_addr or fentry prog */ + retval_off = bpf_frame_size; + save_ret = flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET); + if (save_ret) + bpf_frame_size += SZL; + + /* Room for nvr save area */ + nvr_off = bpf_frame_size; + bpf_frame_size += 2 * SZL; + + /* Optional save area for actual LR in case of ool ftrace */ + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) { + alt_lr_off = bpf_frame_size; + bpf_frame_size += SZL; + } + + if (IS_ENABLED(CONFIG_PPC32)) { + if (nr_regs < 2) { + r4_off = bpf_frame_size; + bpf_frame_size += SZL; + } else { + r4_off = regs_off + SZL; + } + } + + /* Padding to align stack frame, if any */ + bpf_frame_size = round_up(bpf_frame_size, SZL * 2); + + /* Dummy frame size for proper unwind - includes 64-bytes red zone for 64-bit powerpc */ + bpf_dummy_frame_size = STACK_FRAME_MIN_SIZE + 64; + + /* Offset to the traced function's stack frame */ + func_frame_offset = bpf_dummy_frame_size + bpf_frame_size; + + /* Create dummy frame for unwind, store original return value */ + EMIT(PPC_RAW_STL(_R0, _R1, PPC_LR_STKOFF)); + /* Protect red zone where tail call count goes */ + EMIT(PPC_RAW_STLU(_R1, _R1, -bpf_dummy_frame_size)); + + /* Create our stack frame */ + EMIT(PPC_RAW_STLU(_R1, _R1, -bpf_frame_size)); + + /* 64-bit: Save TOC and load kernel TOC */ + if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2) && !IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) { + EMIT(PPC_RAW_STD(_R2, _R1, 24)); + PPC64_LOAD_PACA(); + } + + /* 32-bit: save tail call count in r4 */ + if (IS_ENABLED(CONFIG_PPC32) && nr_regs < 2) + EMIT(PPC_RAW_STL(_R4, _R1, r4_off)); + + bpf_trampoline_save_args(image, ctx, func_frame_offset, nr_regs, regs_off); + + /* Save our return address */ + EMIT(PPC_RAW_MFLR(_R3)); + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) + EMIT(PPC_RAW_STL(_R3, _R1, alt_lr_off)); + else + EMIT(PPC_RAW_STL(_R3, _R1, bpf_frame_size + PPC_LR_STKOFF)); + + /* + * Save ip address of the traced function. + * We could recover this from LR, but we will need to address for OOL trampoline, + * and optional GEP area. + */ + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE) || flags & BPF_TRAMP_F_IP_ARG) { + EMIT(PPC_RAW_LWZ(_R4, _R3, 4)); + EMIT(PPC_RAW_SLWI(_R4, _R4, 6)); + EMIT(PPC_RAW_SRAWI(_R4, _R4, 6)); + EMIT(PPC_RAW_ADD(_R3, _R3, _R4)); + EMIT(PPC_RAW_ADDI(_R3, _R3, 4)); + } + + if (flags & BPF_TRAMP_F_IP_ARG) + EMIT(PPC_RAW_STL(_R3, _R1, ip_off)); + + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) + /* Fake our LR for unwind */ + EMIT(PPC_RAW_STL(_R3, _R1, bpf_frame_size + PPC_LR_STKOFF)); + + /* Save function arg count -- see bpf_get_func_arg_cnt() */ + EMIT(PPC_RAW_LI(_R3, nr_regs)); + EMIT(PPC_RAW_STL(_R3, _R1, nregs_off)); + + /* Save nv regs */ + EMIT(PPC_RAW_STL(_R25, _R1, nvr_off)); + EMIT(PPC_RAW_STL(_R26, _R1, nvr_off + SZL)); + + if (flags & BPF_TRAMP_F_CALL_ORIG) { + PPC_LI_ADDR(_R3, (unsigned long)im); + ret = bpf_jit_emit_func_call_rel(image, ro_image, ctx, + (unsigned long)__bpf_tramp_enter); + if (ret) + return ret; + } + + for (i = 0; i < fentry->nr_links; i++) + if (invoke_bpf_prog(image, ro_image, ctx, fentry->links[i], regs_off, retval_off, + run_ctx_off, flags & BPF_TRAMP_F_RET_FENTRY_RET)) + return -EINVAL; + + if (fmod_ret->nr_links) { + branches = kcalloc(fmod_ret->nr_links, sizeof(u32), GFP_KERNEL); + if (!branches) + return -ENOMEM; + + if (invoke_bpf_mod_ret(image, ro_image, ctx, fmod_ret, regs_off, retval_off, + run_ctx_off, branches)) { + ret = -EINVAL; + goto cleanup; + } + } + + /* Call the traced function */ + if (flags & BPF_TRAMP_F_CALL_ORIG) { + /* + * The address in LR save area points to the correct point in the original function + * with both PPC_FTRACE_OUT_OF_LINE as well as with traditional ftrace instruction + * sequence + */ + EMIT(PPC_RAW_LL(_R3, _R1, bpf_frame_size + PPC_LR_STKOFF)); + EMIT(PPC_RAW_MTCTR(_R3)); + + /* Replicate tail_call_cnt before calling the original BPF prog */ + if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) + bpf_trampoline_setup_tail_call_cnt(image, ctx, func_frame_offset, r4_off); + + /* Restore args */ + bpf_trampoline_restore_args_stack(image, ctx, func_frame_offset, nr_regs, regs_off); + + /* Restore TOC for 64-bit */ + if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2) && !IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) + EMIT(PPC_RAW_LD(_R2, _R1, 24)); + EMIT(PPC_RAW_BCTRL()); + if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2) && !IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) + PPC64_LOAD_PACA(); + + /* Store return value for bpf prog to access */ + EMIT(PPC_RAW_STL(_R3, _R1, retval_off)); + + /* Restore updated tail_call_cnt */ + if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) + bpf_trampoline_restore_tail_call_cnt(image, ctx, func_frame_offset, r4_off); + + /* Reserve space to patch branch instruction to skip fexit progs */ + im->ip_after_call = &((u32 *)ro_image)[ctx->idx]; + EMIT(PPC_RAW_NOP()); + } + + /* Update branches saved in invoke_bpf_mod_ret with address of do_fexit */ + for (i = 0; i < fmod_ret->nr_links && image; i++) { + if (create_cond_branch(&branch_insn, &image[branches[i]], + (unsigned long)&image[ctx->idx], COND_NE << 16)) { + ret = -EINVAL; + goto cleanup; + } + + image[branches[i]] = ppc_inst_val(branch_insn); + } + + for (i = 0; i < fexit->nr_links; i++) + if (invoke_bpf_prog(image, ro_image, ctx, fexit->links[i], regs_off, retval_off, + run_ctx_off, false)) { + ret = -EINVAL; + goto cleanup; + } + + if (flags & BPF_TRAMP_F_CALL_ORIG) { + im->ip_epilogue = &((u32 *)ro_image)[ctx->idx]; + PPC_LI_ADDR(_R3, im); + ret = bpf_jit_emit_func_call_rel(image, ro_image, ctx, + (unsigned long)__bpf_tramp_exit); + if (ret) + goto cleanup; + } + + if (flags & BPF_TRAMP_F_RESTORE_REGS) + bpf_trampoline_restore_args_regs(image, ctx, nr_regs, regs_off); + + /* Restore return value of func_addr or fentry prog */ + if (save_ret) + EMIT(PPC_RAW_LL(_R3, _R1, retval_off)); + + /* Restore nv regs */ + EMIT(PPC_RAW_LL(_R26, _R1, nvr_off + SZL)); + EMIT(PPC_RAW_LL(_R25, _R1, nvr_off)); + + /* Epilogue */ + if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2) && !IS_ENABLED(CONFIG_PPC_KERNEL_PCREL)) + EMIT(PPC_RAW_LD(_R2, _R1, 24)); + if (flags & BPF_TRAMP_F_SKIP_FRAME) { + /* Skip the traced function and return to parent */ + EMIT(PPC_RAW_ADDI(_R1, _R1, func_frame_offset)); + EMIT(PPC_RAW_LL(_R0, _R1, PPC_LR_STKOFF)); + EMIT(PPC_RAW_MTLR(_R0)); + EMIT(PPC_RAW_BLR()); + } else { + if (IS_ENABLED(CONFIG_PPC_FTRACE_OUT_OF_LINE)) { + EMIT(PPC_RAW_LL(_R0, _R1, alt_lr_off)); + EMIT(PPC_RAW_MTLR(_R0)); + EMIT(PPC_RAW_ADDI(_R1, _R1, func_frame_offset)); + EMIT(PPC_RAW_LL(_R0, _R1, PPC_LR_STKOFF)); + EMIT(PPC_RAW_BLR()); + } else { + EMIT(PPC_RAW_LL(_R0, _R1, bpf_frame_size + PPC_LR_STKOFF)); + EMIT(PPC_RAW_MTCTR(_R0)); + EMIT(PPC_RAW_ADDI(_R1, _R1, func_frame_offset)); + EMIT(PPC_RAW_LL(_R0, _R1, PPC_LR_STKOFF)); + EMIT(PPC_RAW_MTLR(_R0)); + EMIT(PPC_RAW_BCTR()); + } + } + + /* Make sure the trampoline generation logic doesn't overflow */ + if (image && WARN_ON_ONCE(&image[ctx->idx] > (u32 *)rw_image_end - BPF_INSN_SAFETY)) { + ret = -EFAULT; + goto cleanup; + } + ret = ctx->idx * 4 + BPF_INSN_SAFETY * 4; + +cleanup: + kfree(branches); + return ret; +} + +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) +{ + struct bpf_tramp_image im; + void *image; + int ret; + + /* + * Allocate a temporary buffer for __arch_prepare_bpf_trampoline(). + * This will NOT cause fragmentation in direct map, as we do not + * call set_memory_*() on this buffer. + * + * We cannot use kvmalloc here, because we need image to be in + * module memory range. + */ + image = bpf_jit_alloc_exec(PAGE_SIZE); + if (!image) + return -ENOMEM; + + ret = __arch_prepare_bpf_trampoline(&im, image, image + PAGE_SIZE, image, + m, flags, tlinks, func_addr); + bpf_jit_free_exec(image); + + return ret; +} + +int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, + const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, + void *func_addr) +{ + u32 size = image_end - image; + void *rw_image, *tmp; + int ret; + + /* + * rw_image doesn't need to be in module memory range, so we can + * use kvmalloc. + */ + rw_image = kvmalloc(size, GFP_KERNEL); + if (!rw_image) + return -ENOMEM; + + ret = __arch_prepare_bpf_trampoline(im, rw_image, rw_image + size, image, m, + flags, tlinks, func_addr); + if (ret < 0) + goto out; + + if (bpf_jit_enable > 1) + bpf_jit_dump(1, ret - BPF_INSN_SAFETY * 4, 1, rw_image); + + tmp = bpf_arch_text_copy(image, rw_image, size); + if (IS_ERR(tmp)) + ret = PTR_ERR(tmp); + +out: + kvfree(rw_image); + return ret; +} + +static int bpf_modify_inst(void *ip, ppc_inst_t old_inst, ppc_inst_t new_inst) +{ + ppc_inst_t org_inst; + + if (copy_inst_from_kernel_nofault(&org_inst, ip)) { + pr_err("0x%lx: fetching instruction failed\n", (unsigned long)ip); + return -EFAULT; + } + + if (!ppc_inst_equal(org_inst, old_inst)) { + pr_err("0x%lx: expected (%08lx) != found (%08lx)\n", + (unsigned long)ip, ppc_inst_as_ulong(old_inst), ppc_inst_as_ulong(org_inst)); + return -EINVAL; + } + + if (ppc_inst_equal(old_inst, new_inst)) + return 0; + + return patch_instruction(ip, new_inst); +} + +static void do_isync(void *info __maybe_unused) +{ + isync(); +} + +/* + * A 3-step process for bpf prog entry: + * 1. At bpf prog entry, a single nop/b: + * bpf_func: + * [nop|b] ool_stub + * 2. Out-of-line stub: + * ool_stub: + * mflr r0 + * [b|bl] / + * mtlr r0 // CONFIG_PPC_FTRACE_OUT_OF_LINE only + * b bpf_func + 4 + * 3. Long branch stub: + * long_branch_stub: + * .long / + * mflr r11 + * bcl 20,31,$+4 + * mflr r12 + * ld r12, -16(r12) + * mtctr r12 + * mtlr r11 // needed to retain ftrace ABI + * bctr + * + * dummy_tramp is used to reduce synchronization requirements. + * + * When attaching a bpf trampoline to a bpf prog, we do not need any + * synchronization here since we always have a valid branch target regardless + * of the order in which the above stores are seen. dummy_tramp ensures that + * the long_branch stub goes to a valid destination on other cpus, even when + * the branch to the long_branch stub is seen before the updated trampoline + * address. + * + * However, when detaching a bpf trampoline from a bpf prog, or if changing + * the bpf trampoline address, we need synchronization to ensure that other + * cpus can no longer branch into the older trampoline so that it can be + * safely freed. bpf_tramp_image_put() uses rcu_tasks to ensure all cpus + * make forward progress, but we still need to ensure that other cpus + * execute isync (or some CSI) so that they don't go back into the + * trampoline again. + */ +int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type, + void *old_addr, void *new_addr) +{ + unsigned long bpf_func, bpf_func_end, size, offset; + ppc_inst_t old_inst, new_inst; + int ret = 0, branch_flags; + char name[KSYM_NAME_LEN]; + + if (IS_ENABLED(CONFIG_PPC32)) + return -EOPNOTSUPP; + + bpf_func = (unsigned long)ip; + branch_flags = poke_type == BPF_MOD_CALL ? BRANCH_SET_LINK : 0; + + /* We currently only support poking bpf programs */ + if (!__bpf_address_lookup(bpf_func, &size, &offset, name)) { + pr_err("%s (0x%lx): kernel/modules are not supported\n", __func__, bpf_func); + return -EOPNOTSUPP; + } + + /* + * If we are not poking at bpf prog entry, then we are simply patching in/out + * an unconditional branch instruction at im->ip_after_call + */ + if (offset) { + if (poke_type != BPF_MOD_JUMP) { + pr_err("%s (0x%lx): calls are not supported in bpf prog body\n", __func__, + bpf_func); + return -EOPNOTSUPP; + } + old_inst = ppc_inst(PPC_RAW_NOP()); + if (old_addr) + if (create_branch(&old_inst, ip, (unsigned long)old_addr, 0)) + return -ERANGE; + new_inst = ppc_inst(PPC_RAW_NOP()); + if (new_addr) + if (create_branch(&new_inst, ip, (unsigned long)new_addr, 0)) + return -ERANGE; + mutex_lock(&text_mutex); + ret = bpf_modify_inst(ip, old_inst, new_inst); + mutex_unlock(&text_mutex); + + /* Make sure all cpus see the new instruction */ + smp_call_function(do_isync, NULL, 1); + return ret; + } + + bpf_func_end = bpf_func + size; + + /* Address of the jmp/call instruction in the out-of-line stub */ + ip = (void *)(bpf_func_end - bpf_jit_ool_stub + 4); + + if (!is_offset_in_branch_range((long)ip - 4 - bpf_func)) { + pr_err("%s (0x%lx): bpf prog too large, ool stub out of branch range\n", __func__, + bpf_func); + return -ERANGE; + } + + old_inst = ppc_inst(PPC_RAW_NOP()); + if (old_addr) { + if (is_offset_in_branch_range(ip - old_addr)) + create_branch(&old_inst, ip, (unsigned long)old_addr, branch_flags); + else + create_branch(&old_inst, ip, bpf_func_end - bpf_jit_long_branch_stub, + branch_flags); + } + new_inst = ppc_inst(PPC_RAW_NOP()); + if (new_addr) { + if (is_offset_in_branch_range(ip - new_addr)) + create_branch(&new_inst, ip, (unsigned long)new_addr, branch_flags); + else + create_branch(&new_inst, ip, bpf_func_end - bpf_jit_long_branch_stub, + branch_flags); + } + + mutex_lock(&text_mutex); + + /* + * 1. Update the address in the long branch stub: + * If new_addr is out of range, we will have to use the long branch stub, so patch new_addr + * here. Otherwise, revert to dummy_tramp, but only if we had patched old_addr here. + */ + if ((new_addr && !is_offset_in_branch_range(new_addr - ip)) || + (old_addr && !is_offset_in_branch_range(old_addr - ip))) + ret = patch_ulong((void *)(bpf_func_end - bpf_jit_long_branch_stub - SZL), + (new_addr && !is_offset_in_branch_range(new_addr - ip)) ? + (unsigned long)new_addr : (unsigned long)dummy_tramp); + if (ret) + goto out; + + /* 2. Update the branch/call in the out-of-line stub */ + ret = bpf_modify_inst(ip, old_inst, new_inst); + if (ret) + goto out; + + /* 3. Update instruction at bpf prog entry */ + ip = (void *)bpf_func; + if (!old_addr || !new_addr) { + if (!old_addr) { + old_inst = ppc_inst(PPC_RAW_NOP()); + create_branch(&new_inst, ip, bpf_func_end - bpf_jit_ool_stub, 0); + } else { + new_inst = ppc_inst(PPC_RAW_NOP()); + create_branch(&old_inst, ip, bpf_func_end - bpf_jit_ool_stub, 0); + } + ret = bpf_modify_inst(ip, old_inst, new_inst); + } + +out: + mutex_unlock(&text_mutex); + + /* + * Sync only if we are not attaching a trampoline to a bpf prog so the older + * trampoline can be freed safely. + */ + if (old_addr) + smp_call_function(do_isync, NULL, 1); + + return ret; +} diff --git a/arch/powerpc/net/bpf_jit_comp32.c b/arch/powerpc/net/bpf_jit_comp32.c index a0c4f1bde83e86..c4db278dae3609 100644 --- a/arch/powerpc/net/bpf_jit_comp32.c +++ b/arch/powerpc/net/bpf_jit_comp32.c @@ -127,13 +127,16 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) { int i; + /* Instruction for trampoline attach */ + EMIT(PPC_RAW_NOP()); + /* Initialize tail_call_cnt, to be skipped if we do tail calls. */ if (ctx->seen & SEEN_TAILCALL) EMIT(PPC_RAW_LI(_R4, 0)); else EMIT(PPC_RAW_NOP()); -#define BPF_TAILCALL_PROLOGUE_SIZE 4 +#define BPF_TAILCALL_PROLOGUE_SIZE 8 if (bpf_has_stack_frame(ctx)) EMIT(PPC_RAW_STWU(_R1, _R1, -BPF_PPC_STACKFRAME(ctx))); @@ -198,6 +201,8 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) bpf_jit_emit_common_epilogue(image, ctx); EMIT(PPC_RAW_BLR()); + + bpf_jit_build_fentry_stubs(image, ctx); } /* Relative offset needs to be calculated based on final image location */ diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index 2cbcdf93cc1978..233703b06d7c97 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -84,7 +84,7 @@ static inline bool bpf_has_stack_frame(struct codegen_context *ctx) } /* - * When not setting up our own stackframe, the redzone usage is: + * When not setting up our own stackframe, the redzone (288 bytes) usage is: * * [ prev sp ] <------------- * [ ... ] | @@ -92,7 +92,7 @@ static inline bool bpf_has_stack_frame(struct codegen_context *ctx) * [ nv gpr save area ] 5*8 * [ tail_call_cnt ] 8 * [ local_tmp_var ] 16 - * [ unused red zone ] 208 bytes protected + * [ unused red zone ] 224 */ static int bpf_jit_stack_local(struct codegen_context *ctx) { @@ -126,6 +126,9 @@ void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) { int i; + /* Instruction for trampoline attach */ + EMIT(PPC_RAW_NOP()); + #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))); @@ -200,16 +203,26 @@ void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) EMIT(PPC_RAW_MR(_R3, bpf_to_ppc(BPF_REG_0))); EMIT(PPC_RAW_BLR()); + + bpf_jit_build_fentry_stubs(image, ctx); } -static int -bpf_jit_emit_func_call_hlp(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func) +int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func) { unsigned long func_addr = func ? ppc_function_entry((void *)func) : 0; long reladdr; - if (WARN_ON_ONCE(!kernel_text_address(func_addr))) - return -EINVAL; + /* bpf to bpf call, func is not known in the initial pass. Emit 5 nops as a placeholder */ + if (!func) { + for (int i = 0; i < 5; i++) + EMIT(PPC_RAW_NOP()); + /* elfv1 needs an additional instruction to load addr from descriptor */ + if (IS_ENABLED(CONFIG_PPC64_ELF_ABI_V1)) + EMIT(PPC_RAW_NOP()); + EMIT(PPC_RAW_MTCTR(_R12)); + EMIT(PPC_RAW_BCTRL()); + return 0; + } #ifdef CONFIG_PPC_KERNEL_PCREL reladdr = func_addr - local_paca->kernelbase; @@ -266,7 +279,8 @@ bpf_jit_emit_func_call_hlp(u32 *image, u32 *fimage, struct codegen_context *ctx, * We can clobber r2 since we get called through a * function pointer (so caller will save/restore r2). */ - EMIT(PPC_RAW_LD(_R2, bpf_to_ppc(TMP_REG_2), 8)); + if (is_module_text_address(func_addr)) + EMIT(PPC_RAW_LD(_R2, bpf_to_ppc(TMP_REG_2), 8)); } else { PPC_LI64(_R12, func); EMIT(PPC_RAW_MTCTR(_R12)); @@ -276,46 +290,14 @@ bpf_jit_emit_func_call_hlp(u32 *image, u32 *fimage, struct codegen_context *ctx, * Load r2 with kernel TOC as kernel TOC is used if function address falls * within core kernel text. */ - EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc))); + if (is_module_text_address(func_addr)) + EMIT(PPC_RAW_LD(_R2, _R13, offsetof(struct paca_struct, kernel_toc))); } #endif return 0; } -int bpf_jit_emit_func_call_rel(u32 *image, u32 *fimage, struct codegen_context *ctx, u64 func) -{ - unsigned int i, ctx_idx = ctx->idx; - - if (WARN_ON_ONCE(func && is_module_text_address(func))) - return -EINVAL; - - /* skip past descriptor if elf v1 */ - func += FUNCTION_DESCR_SIZE; - - /* Load function address into r12 */ - PPC_LI64(_R12, func); - - /* For bpf-to-bpf function calls, the callee's address is unknown - * until the last extra pass. As seen above, we use PPC_LI64() to - * load the callee's address, but this may optimize the number of - * instructions required based on the nature of the address. - * - * Since we don't want the number of instructions emitted to increase, - * we pad the optimized PPC_LI64() call with NOPs to guarantee that - * we always have a five-instruction sequence, which is the maximum - * that PPC_LI64() can emit. - */ - if (!image) - for (i = ctx->idx - ctx_idx; i < 5; i++) - EMIT(PPC_RAW_NOP()); - - EMIT(PPC_RAW_MTCTR(_R12)); - EMIT(PPC_RAW_BCTRL()); - - return 0; -} - static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out) { /* @@ -326,7 +308,7 @@ static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 o */ int b2p_bpf_array = bpf_to_ppc(BPF_REG_2); int b2p_index = bpf_to_ppc(BPF_REG_3); - int bpf_tailcall_prologue_size = 8; + int bpf_tailcall_prologue_size = 12; if (!IS_ENABLED(CONFIG_PPC_KERNEL_PCREL) && IS_ENABLED(CONFIG_PPC64_ELF_ABI_V2)) bpf_tailcall_prologue_size += 4; /* skip past the toc load */ @@ -1102,11 +1084,7 @@ int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct code if (ret < 0) return ret; - if (func_addr_fixed) - ret = bpf_jit_emit_func_call_hlp(image, fimage, ctx, func_addr); - else - ret = bpf_jit_emit_func_call_rel(image, fimage, ctx, func_addr); - + ret = bpf_jit_emit_func_call_rel(image, fimage, ctx, func_addr); if (ret) return ret; diff --git a/arch/powerpc/perf/8xx-pmu.c b/arch/powerpc/perf/8xx-pmu.c index 308a2e40d7be99..1d2972229e3a7e 100644 --- a/arch/powerpc/perf/8xx-pmu.c +++ b/arch/powerpc/perf/8xx-pmu.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #define PERF_8xx_ID_CPU_CYCLES 1 diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile index 4f53d0b97539bb..ac2cf58d62dbbc 100644 --- a/arch/powerpc/perf/Makefile +++ b/arch/powerpc/perf/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o obj-$(CONFIG_HV_PERF_CTRS) += hv-24x7.o hv-gpci.o hv-common.o +obj-$(CONFIG_VPA_PMU) += vpa-pmu.o + obj-$(CONFIG_PPC_8xx) += 8xx-pmu.o obj-$(CONFIG_PPC64) += $(obj64-y) diff --git a/arch/powerpc/perf/callchain.c b/arch/powerpc/perf/callchain.c index 6b4434dd0ff307..26aa26482c9ac0 100644 --- a/arch/powerpc/perf/callchain.c +++ b/arch/powerpc/perf/callchain.c @@ -51,7 +51,7 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re lr = regs->link; sp = regs->gpr[1]; - perf_callchain_store(entry, perf_instruction_pointer(regs)); + perf_callchain_store(entry, perf_arch_instruction_pointer(regs)); if (!validate_sp(sp, current)) return; diff --git a/arch/powerpc/perf/callchain_32.c b/arch/powerpc/perf/callchain_32.c index ea8cfe3806dce3..ddcc2d8aa64a55 100644 --- a/arch/powerpc/perf/callchain_32.c +++ b/arch/powerpc/perf/callchain_32.c @@ -139,7 +139,7 @@ void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry, long level = 0; unsigned int __user *fp, *uregs; - next_ip = perf_instruction_pointer(regs); + next_ip = perf_arch_instruction_pointer(regs); lr = regs->link; sp = regs->gpr[1]; perf_callchain_store(entry, next_ip); diff --git a/arch/powerpc/perf/callchain_64.c b/arch/powerpc/perf/callchain_64.c index 488e8a21a11ea5..115d1c105e8a84 100644 --- a/arch/powerpc/perf/callchain_64.c +++ b/arch/powerpc/perf/callchain_64.c @@ -74,7 +74,7 @@ void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry, struct signal_frame_64 __user *sigframe; unsigned long __user *fp, *uregs; - next_ip = perf_instruction_pointer(regs); + next_ip = perf_arch_instruction_pointer(regs); lr = regs->link; sp = regs->gpr[1]; perf_callchain_store(entry, next_ip); diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 42867469752d73..2b79171ee185be 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -2332,7 +2332,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, * Called from generic code to get the misc flags (i.e. processor mode) * for an event_id. */ -unsigned long perf_misc_flags(struct pt_regs *regs) +unsigned long perf_arch_misc_flags(struct pt_regs *regs) { u32 flags = perf_get_misc_flags(regs); @@ -2346,7 +2346,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs) * Called from generic code to get the instruction pointer * for an event_id. */ -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { unsigned long siar = mfspr(SPRN_SIAR); diff --git a/arch/powerpc/perf/vpa-pmu.c b/arch/powerpc/perf/vpa-pmu.c new file mode 100644 index 00000000000000..6a5bfd2a13b5aa --- /dev/null +++ b/arch/powerpc/perf/vpa-pmu.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Performance monitoring support for Virtual Processor Area(VPA) based counters + * + * Copyright (C) 2024 IBM Corporation + */ +#define pr_fmt(fmt) "vpa_pmu: " fmt + +#include +#include +#include +#include + +#define MODULE_VERS "1.0" +#define MODULE_NAME "pseries_vpa_pmu" + +#define EVENT(_name, _code) enum{_name = _code} + +#define VPA_PMU_EVENT_VAR(_id) event_attr_##_id +#define VPA_PMU_EVENT_PTR(_id) (&event_attr_##_id.attr.attr) + +static ssize_t vpa_pmu_events_sysfs_show(struct device *dev, + struct device_attribute *attr, char *page) +{ + struct perf_pmu_events_attr *pmu_attr; + + pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); + + return sprintf(page, "event=0x%02llx\n", pmu_attr->id); +} + +#define VPA_PMU_EVENT_ATTR(_name, _id) \ + PMU_EVENT_ATTR(_name, VPA_PMU_EVENT_VAR(_id), _id, \ + vpa_pmu_events_sysfs_show) + +EVENT(L1_TO_L2_CS_LAT, 0x1); +EVENT(L2_TO_L1_CS_LAT, 0x2); +EVENT(L2_RUNTIME_AGG, 0x3); + +VPA_PMU_EVENT_ATTR(l1_to_l2_lat, L1_TO_L2_CS_LAT); +VPA_PMU_EVENT_ATTR(l2_to_l1_lat, L2_TO_L1_CS_LAT); +VPA_PMU_EVENT_ATTR(l2_runtime_agg, L2_RUNTIME_AGG); + +static struct attribute *vpa_pmu_events_attr[] = { + VPA_PMU_EVENT_PTR(L1_TO_L2_CS_LAT), + VPA_PMU_EVENT_PTR(L2_TO_L1_CS_LAT), + VPA_PMU_EVENT_PTR(L2_RUNTIME_AGG), + NULL +}; + +static const struct attribute_group vpa_pmu_events_group = { + .name = "events", + .attrs = vpa_pmu_events_attr, +}; + +PMU_FORMAT_ATTR(event, "config:0-31"); +static struct attribute *vpa_pmu_format_attr[] = { + &format_attr_event.attr, + NULL, +}; + +static struct attribute_group vpa_pmu_format_group = { + .name = "format", + .attrs = vpa_pmu_format_attr, +}; + +static const struct attribute_group *vpa_pmu_attr_groups[] = { + &vpa_pmu_events_group, + &vpa_pmu_format_group, + NULL +}; + +static int vpa_pmu_event_init(struct perf_event *event) +{ + if (event->attr.type != event->pmu->type) + return -ENOENT; + + /* it does not support event sampling mode */ + if (is_sampling_event(event)) + return -EOPNOTSUPP; + + /* no branch sampling */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + + /* Invalid event code */ + if ((event->attr.config <= 0) || (event->attr.config > 3)) + return -EINVAL; + + return 0; +} + +static unsigned long get_counter_data(struct perf_event *event) +{ + unsigned int config = event->attr.config; + u64 data; + + switch (config) { + case L1_TO_L2_CS_LAT: + if (event->attach_state & PERF_ATTACH_TASK) + data = kvmhv_get_l1_to_l2_cs_time_vcpu(); + else + data = kvmhv_get_l1_to_l2_cs_time(); + break; + case L2_TO_L1_CS_LAT: + if (event->attach_state & PERF_ATTACH_TASK) + data = kvmhv_get_l2_to_l1_cs_time_vcpu(); + else + data = kvmhv_get_l2_to_l1_cs_time(); + break; + case L2_RUNTIME_AGG: + if (event->attach_state & PERF_ATTACH_TASK) + data = kvmhv_get_l2_runtime_agg_vcpu(); + else + data = kvmhv_get_l2_runtime_agg(); + break; + default: + data = 0; + break; + } + + return data; +} + +static int vpa_pmu_add(struct perf_event *event, int flags) +{ + u64 data; + + kvmhv_set_l2_counters_status(smp_processor_id(), true); + + data = get_counter_data(event); + local64_set(&event->hw.prev_count, data); + + return 0; +} + +static void vpa_pmu_read(struct perf_event *event) +{ + u64 prev_data, new_data, final_data; + + prev_data = local64_read(&event->hw.prev_count); + new_data = get_counter_data(event); + final_data = new_data - prev_data; + + local64_add(final_data, &event->count); +} + +static void vpa_pmu_del(struct perf_event *event, int flags) +{ + vpa_pmu_read(event); + + /* + * Disable vpa counter accumulation + */ + kvmhv_set_l2_counters_status(smp_processor_id(), false); +} + +static struct pmu vpa_pmu = { + .task_ctx_nr = perf_sw_context, + .name = "vpa_pmu", + .event_init = vpa_pmu_event_init, + .add = vpa_pmu_add, + .del = vpa_pmu_del, + .read = vpa_pmu_read, + .attr_groups = vpa_pmu_attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT, +}; + +static int __init pseries_vpa_pmu_init(void) +{ + /* + * List of current Linux on Power platforms and + * this driver is supported only in PowerVM LPAR + * (L1) platform. + * + * Enabled Linux on Power Platforms + * ---------------------------------------- + * [X] PowerVM LPAR (L1) + * [ ] KVM Guest On PowerVM KoP(L2) + * [ ] Baremetal(PowerNV) + * [ ] KVM Guest On PowerNV + */ + if (!firmware_has_feature(FW_FEATURE_LPAR) || is_kvm_guest()) + return -ENODEV; + + perf_pmu_register(&vpa_pmu, vpa_pmu.name, -1); + pr_info("Virtual Processor Area PMU registered.\n"); + + return 0; +} + +static void __exit pseries_vpa_pmu_cleanup(void) +{ + perf_pmu_unregister(&vpa_pmu); + pr_info("Virtual Processor Area PMU unregistered.\n"); +} + +module_init(pseries_vpa_pmu_init); +module_exit(pseries_vpa_pmu_cleanup); +MODULE_DESCRIPTION("Perf Driver for pSeries VPA pmu counter"); +MODULE_AUTHOR("Kajol Jain "); +MODULE_AUTHOR("Madhavan Srinivasan "); +MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/platforms/44x/pci.c b/arch/powerpc/platforms/44x/pci.c index db6d33ca753f1b..364aeb86ab64ea 100644 --- a/arch/powerpc/platforms/44x/pci.c +++ b/arch/powerpc/platforms/44x/pci.c @@ -94,10 +94,8 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, struct resource *res) { u64 size; - const u32 *ranges; - int rlen; - int pna = of_n_addr_cells(hose->dn); - int np = pna + 5; + struct of_range_parser parser; + struct of_range range; /* Default */ res->start = 0; @@ -105,18 +103,15 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, res->end = size - 1; res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; - /* Get dma-ranges property */ - ranges = of_get_property(hose->dn, "dma-ranges", &rlen); - if (ranges == NULL) + if (of_pci_dma_range_parser_init(&parser, hose->dn)) goto out; - /* Walk it */ - while ((rlen -= np * 4) >= 0) { - u32 pci_space = ranges[0]; - u64 pci_addr = of_read_number(ranges + 1, 2); - u64 cpu_addr = of_translate_dma_address(hose->dn, ranges + 3); - size = of_read_number(ranges + pna + 3, 2); - ranges += np; + for_each_of_range(&parser, &range) { + u32 pci_space = range.flags; + u64 pci_addr = range.bus_addr; + u64 cpu_addr = range.cpu_addr; + size = range.size; + if (cpu_addr == OF_BAD_ADDR || size == 0) continue; diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 37a67120f257ca..a7172f9ebaad95 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c index 3dc65ce1f175de..8f918916e6318d 100644 --- a/arch/powerpc/platforms/82xx/ep8248e.c +++ b/arch/powerpc/platforms/82xx/ep8248e.c @@ -128,7 +128,7 @@ static int ep8248e_mdio_probe(struct platform_device *ofdev) bus->name = "ep8248e-mdio-bitbang"; bus->parent = &ofdev->dev; - snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); + snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res.start); ret = of_mdiobus_register(bus, ofdev->dev.of_node); if (ret) diff --git a/arch/powerpc/platforms/82xx/km82xx.c b/arch/powerpc/platforms/82xx/km82xx.c index c86da3f2b74bd8..99f0f0f4187672 100644 --- a/arch/powerpc/platforms/82xx/km82xx.c +++ b/arch/powerpc/platforms/82xx/km82xx.c @@ -27,15 +27,15 @@ static void __init km82xx_pic_init(void) { - struct device_node *np = of_find_compatible_node(NULL, NULL, - "fsl,pq2-pic"); + struct device_node *np __free(device_node); + np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic"); + if (!np) { pr_err("PIC init: can not find cpm-pic node\n"); return; } cpm2_pic_init(np); - of_node_put(np); } struct cpm_pin { diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 9315a3b69d6dfb..604c1b4b6d45c1 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -40,27 +40,6 @@ config BSC9132_QDS and dual StarCore SC3850 DSP cores. Manufacturer : Freescale Semiconductor, Inc -config MPC8540_ADS - bool "Freescale MPC8540 ADS" - select DEFAULT_UIMAGE - help - This option enables support for the MPC 8540 ADS board - -config MPC8560_ADS - bool "Freescale MPC8560 ADS" - select DEFAULT_UIMAGE - select CPM2 - help - This option enables support for the MPC 8560 ADS board - -config MPC85xx_CDS - bool "Freescale MPC85xx CDS" - select DEFAULT_UIMAGE - select PPC_I8259 - select HAVE_RAPIDIO - help - This option enables support for the MPC85xx CDS board - config MPC85xx_MDS bool "Freescale MPC8568 MDS / MPC8569 MDS / P1021 MDS" select DEFAULT_UIMAGE diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index e52b848b64b79a..32fa5fb557c035 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c index 8a7e55acf090fd..9be33e41af6dba 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 1112a583161919..a454149ae02fc0 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -7,7 +7,6 @@ source "arch/powerpc/platforms/chrp/Kconfig" source "arch/powerpc/platforms/512x/Kconfig" source "arch/powerpc/platforms/52xx/Kconfig" source "arch/powerpc/platforms/powermac/Kconfig" -source "arch/powerpc/platforms/maple/Kconfig" source "arch/powerpc/platforms/pasemi/Kconfig" source "arch/powerpc/platforms/ps3/Kconfig" source "arch/powerpc/platforms/cell/Kconfig" diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 786d374bff3170..3cee4a842736de 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_FSL_SOC_BOOKE) += 85xx/ obj-$(CONFIG_PPC_86xx) += 86xx/ obj-$(CONFIG_PPC_POWERNV) += powernv/ obj-$(CONFIG_PPC_PSERIES) += pseries/ -obj-$(CONFIG_PPC_MAPLE) += maple/ obj-$(CONFIG_PPC_PASEMI) += pasemi/ obj-$(CONFIG_PPC_CELL) += cell/ obj-$(CONFIG_PPC_PS3) += ps3/ diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 28dc86744cac26..d243f7fd89825c 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -112,7 +112,7 @@ static void axon_msi_cascade(struct irq_desc *desc) pr_devel("axon_msi: woff %x roff %x msi %x\n", write_offset, msic->read_offset, msi); - if (msi < nr_irqs && irq_get_chip_data(msi) == msic) { + if (msi < irq_get_nr_irqs() && irq_get_chip_data(msi) == msic) { generic_handle_irq(msi); msic->fifo_virt[idx] = cpu_to_le32(0xffffffff); } else { diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 4cd9c0de22c2bd..62c9679b8ca33f 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -779,58 +779,41 @@ static int __init cell_iommu_init_disabled(void) static u64 cell_iommu_get_fixed_address(struct device *dev) { - u64 cpu_addr, size, best_size, dev_addr = OF_BAD_ADDR; + u64 best_size, dev_addr = OF_BAD_ADDR; struct device_node *np; - const u32 *ranges = NULL; - int i, len, best, naddr, nsize, pna, range_size; + struct of_range_parser parser; + struct of_range range; /* We can be called for platform devices that have no of_node */ np = of_node_get(dev->of_node); if (!np) goto out; - while (1) { - naddr = of_n_addr_cells(np); - nsize = of_n_size_cells(np); - np = of_get_next_parent(np); - if (!np) - break; - - ranges = of_get_property(np, "dma-ranges", &len); + while ((np = of_get_next_parent(np))) { + if (of_pci_dma_range_parser_init(&parser, np)) + continue; - /* Ignore empty ranges, they imply no translation required */ - if (ranges && len > 0) + if (of_range_count(&parser)) break; } - if (!ranges) { + if (!np) { dev_dbg(dev, "iommu: no dma-ranges found\n"); goto out; } - len /= sizeof(u32); - - pna = of_n_addr_cells(np); - range_size = naddr + nsize + pna; - - /* dma-ranges format: - * child addr : naddr cells - * parent addr : pna cells - * size : nsize cells - */ - for (i = 0, best = -1, best_size = 0; i < len; i += range_size) { - cpu_addr = of_translate_dma_address(np, ranges + i + naddr); - size = of_read_number(ranges + i + naddr + pna, nsize); + best_size = 0; + for_each_of_range(&parser, &range) { + if (!range.cpu_addr) + continue; - if (cpu_addr == 0 && size > best_size) { - best = i; - best_size = size; + if (range.size > best_size) { + best_size = range.size; + dev_addr = range.bus_addr; } } - if (best >= 0) { - dev_addr = of_read_number(ranges + best, naddr); - } else + if (!best_size) dev_dbg(dev, "iommu: no suitable range found!\n"); out: diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index fee638fd897026..0e8f20ecca088f 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include "interrupt.h" #include diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c index cd7d42fc12a67d..000894e07b027d 100644 --- a/arch/powerpc/platforms/cell/spu_syscalls.c +++ b/arch/powerpc/platforms/cell/spu_syscalls.c @@ -36,6 +36,9 @@ static inline struct spufs_calls *spufs_calls_get(void) static inline void spufs_calls_put(struct spufs_calls *calls) { + if (!calls) + return; + BUG_ON(calls != spufs_calls); /* we don't need to rcu this, as we hold a reference to the module */ @@ -53,82 +56,55 @@ static inline void spufs_calls_put(struct spufs_calls *calls) { } #endif /* CONFIG_SPU_FS_MODULE */ +DEFINE_CLASS(spufs_calls, struct spufs_calls *, spufs_calls_put(_T), spufs_calls_get(), void) + SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, umode_t, mode, int, neighbor_fd) { - long ret; - struct spufs_calls *calls; - - calls = spufs_calls_get(); + CLASS(spufs_calls, calls)(); if (!calls) return -ENOSYS; if (flags & SPU_CREATE_AFFINITY_SPU) { - struct fd neighbor = fdget(neighbor_fd); - ret = -EBADF; - if (fd_file(neighbor)) { - ret = calls->create_thread(name, flags, mode, fd_file(neighbor)); - fdput(neighbor); - } - } else - ret = calls->create_thread(name, flags, mode, NULL); - - spufs_calls_put(calls); - return ret; + CLASS(fd, neighbor)(neighbor_fd); + if (fd_empty(neighbor)) + return -EBADF; + return calls->create_thread(name, flags, mode, fd_file(neighbor)); + } else { + return calls->create_thread(name, flags, mode, NULL); + } } SYSCALL_DEFINE3(spu_run,int, fd, __u32 __user *, unpc, __u32 __user *, ustatus) { - long ret; - struct fd arg; - struct spufs_calls *calls; - - calls = spufs_calls_get(); + CLASS(spufs_calls, calls)(); if (!calls) return -ENOSYS; - ret = -EBADF; - arg = fdget(fd); - if (fd_file(arg)) { - ret = calls->spu_run(fd_file(arg), unpc, ustatus); - fdput(arg); - } + CLASS(fd, arg)(fd); + if (fd_empty(arg)) + return -EBADF; - spufs_calls_put(calls); - return ret; + return calls->spu_run(fd_file(arg), unpc, ustatus); } #ifdef CONFIG_COREDUMP int elf_coredump_extra_notes_size(void) { - struct spufs_calls *calls; - int ret; - - calls = spufs_calls_get(); + CLASS(spufs_calls, calls)(); if (!calls) return 0; - ret = calls->coredump_extra_notes_size(); - - spufs_calls_put(calls); - - return ret; + return calls->coredump_extra_notes_size(); } int elf_coredump_extra_notes_write(struct coredump_params *cprm) { - struct spufs_calls *calls; - int ret; - - calls = spufs_calls_get(); + CLASS(spufs_calls, calls)(); if (!calls) return 0; - ret = calls->coredump_extra_notes_write(cprm); - - spufs_calls_put(calls); - - return ret; + return calls->coredump_extra_notes_write(cprm); } #endif diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 18daafbe2e65ee..301ee7d8b7df02 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -73,9 +73,7 @@ static struct spu_context *coredump_next_context(int *fd) return NULL; *fd = n - 1; - rcu_read_lock(); - file = lookup_fdget_rcu(*fd); - rcu_read_unlock(); + file = fget_raw(*fd); if (file) { ctx = SPUFS_I(file_inode(file))->i_ctx; get_spu_context(ctx); diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index e265f026eee2a9..4012f206ec63d7 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c index 00bec0f051be10..5ca41972ef2214 100644 --- a/arch/powerpc/platforms/embedded6xx/mvme5100.c +++ b/arch/powerpc/platforms/embedded6xx/mvme5100.c @@ -14,6 +14,7 @@ #include #include +#include #include #include diff --git a/arch/powerpc/platforms/maple/Kconfig b/arch/powerpc/platforms/maple/Kconfig deleted file mode 100644 index 4c058cc57c9011..00000000000000 --- a/arch/powerpc/platforms/maple/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config PPC_MAPLE - depends on PPC64 && PPC_BOOK3S && CPU_BIG_ENDIAN - bool "Maple 970FX Evaluation Board" - select FORCE_PCI - select MPIC - select U3_DART - select MPIC_U3_HT_IRQS - select GENERIC_TBSYNC - select PPC_UDBG_16550 - select PPC_970_NAP - select PPC_64S_HASH_MMU - select PPC_HASH_MMU_NATIVE - select PPC_RTAS - select MMIO_NVRAM - select ATA_NONSTANDARD if ATA - help - This option enables support for the Maple 970FX Evaluation Board. - For more information, refer to diff --git a/arch/powerpc/platforms/maple/Makefile b/arch/powerpc/platforms/maple/Makefile deleted file mode 100644 index 19f35ab828a7e8..00000000000000 --- a/arch/powerpc/platforms/maple/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-y += setup.o pci.o time.o diff --git a/arch/powerpc/platforms/maple/maple.h b/arch/powerpc/platforms/maple/maple.h deleted file mode 100644 index 8ddbaa4ebd0b43..00000000000000 --- a/arch/powerpc/platforms/maple/maple.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Declarations for maple-specific code. - * - * Maple is the name of a PPC970 evaluation board. - */ -extern int maple_set_rtc_time(struct rtc_time *tm); -extern void maple_get_rtc_time(struct rtc_time *tm); -extern time64_t maple_get_boot_time(void); -extern void maple_pci_init(void); -extern void maple_pci_irq_fixup(struct pci_dev *dev); -extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel); - -extern struct pci_controller_ops maple_pci_controller_ops; diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c deleted file mode 100644 index b9ff37c7f6f019..00000000000000 --- a/arch/powerpc/platforms/maple/pci.c +++ /dev/null @@ -1,672 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), - * IBM Corp. - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "maple.h" - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static struct pci_controller *u3_agp, *u3_ht, *u4_pcie; - -static int __init fixup_one_level_bus_range(struct device_node *node, int higher) -{ - for (; node; node = node->sibling) { - const int *bus_range; - const unsigned int *class_code; - int len; - - /* For PCI<->PCI bridges or CardBus bridges, we go down */ - class_code = of_get_property(node, "class-code", NULL); - if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && - (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) - continue; - bus_range = of_get_property(node, "bus-range", &len); - if (bus_range != NULL && len > 2 * sizeof(int)) { - if (bus_range[1] > higher) - higher = bus_range[1]; - } - higher = fixup_one_level_bus_range(node->child, higher); - } - return higher; -} - -/* This routine fixes the "bus-range" property of all bridges in the - * system since they tend to have their "last" member wrong on macs - * - * Note that the bus numbers manipulated here are OF bus numbers, they - * are not Linux bus numbers. - */ -static void __init fixup_bus_range(struct device_node *bridge) -{ - int *bus_range; - struct property *prop; - int len; - - /* Lookup the "bus-range" property for the hose */ - prop = of_find_property(bridge, "bus-range", &len); - if (prop == NULL || prop->value == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %pOF\n", - bridge); - return; - } - bus_range = prop->value; - bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); -} - - -static unsigned long u3_agp_cfa0(u8 devfn, u8 off) -{ - return (1 << (unsigned long)PCI_SLOT(devfn)) | - ((unsigned long)PCI_FUNC(devfn) << 8) | - ((unsigned long)off & 0xFCUL); -} - -static unsigned long u3_agp_cfa1(u8 bus, u8 devfn, u8 off) -{ - return ((unsigned long)bus << 16) | - ((unsigned long)devfn << 8) | - ((unsigned long)off & 0xFCUL) | - 1UL; -} - -static volatile void __iomem *u3_agp_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, u8 offset) -{ - unsigned int caddr; - - if (bus == hose->first_busno) { - if (dev_fn < (11 << 3)) - return NULL; - caddr = u3_agp_cfa0(dev_fn, offset); - } else - caddr = u3_agp_cfa1(bus, dev_fn, offset); - - /* Uninorth will return garbage if we don't read back the value ! */ - do { - out_le32(hose->cfg_addr, caddr); - } while (in_le32(hose->cfg_addr) != caddr); - - offset &= 0x07; - return hose->cfg_data + offset; -} - -static int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_agp_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8(addr); - break; - case 2: - *val = in_le16(addr); - break; - default: - *val = in_le32(addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - addr = u3_agp_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8(addr, val); - break; - case 2: - out_le16(addr, val); - break; - default: - out_le32(addr, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops u3_agp_pci_ops = -{ - .read = u3_agp_read_config, - .write = u3_agp_write_config, -}; - -static unsigned long u3_ht_cfa0(u8 devfn, u8 off) -{ - return (devfn << 8) | off; -} - -static unsigned long u3_ht_cfa1(u8 bus, u8 devfn, u8 off) -{ - return u3_ht_cfa0(devfn, off) + (bus << 16) + 0x01000000UL; -} - -static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose, - u8 bus, u8 devfn, u8 offset) -{ - if (bus == hose->first_busno) { - if (PCI_SLOT(devfn) == 0) - return NULL; - return hose->cfg_data + u3_ht_cfa0(devfn, offset); - } else - return hose->cfg_data + u3_ht_cfa1(bus, devfn, offset); -} - -static int u3_ht_root_read_config(struct pci_controller *hose, u8 offset, - int len, u32 *val) -{ - volatile void __iomem *addr; - - addr = hose->cfg_addr; - addr += ((offset & ~3) << 2) + (4 - len - (offset & 3)); - - switch (len) { - case 1: - *val = in_8(addr); - break; - case 2: - *val = in_be16(addr); - break; - default: - *val = in_be32(addr); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int u3_ht_root_write_config(struct pci_controller *hose, u8 offset, - int len, u32 val) -{ - volatile void __iomem *addr; - - addr = hose->cfg_addr + ((offset & ~3) << 2) + (4 - len - (offset & 3)); - - if (offset >= PCI_BASE_ADDRESS_0 && offset < PCI_CAPABILITY_LIST) - return PCIBIOS_SUCCESSFUL; - - switch (len) { - case 1: - out_8(addr, val); - break; - case 2: - out_be16(addr, val); - break; - default: - out_be32(addr, val); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0)) - return u3_ht_root_read_config(hose, offset, len, val); - - if (offset > 0xff) - return PCIBIOS_BAD_REGISTER_NUMBER; - - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8(addr); - break; - case 2: - *val = in_le16(addr); - break; - default: - *val = in_le32(addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (bus->number == hose->first_busno && devfn == PCI_DEVFN(0, 0)) - return u3_ht_root_write_config(hose, offset, len, val); - - if (offset > 0xff) - return PCIBIOS_BAD_REGISTER_NUMBER; - - addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8(addr, val); - break; - case 2: - out_le16(addr, val); - break; - default: - out_le32(addr, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops u3_ht_pci_ops = -{ - .read = u3_ht_read_config, - .write = u3_ht_write_config, -}; - -static unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off) -{ - return (1 << PCI_SLOT(devfn)) | - (PCI_FUNC(devfn) << 8) | - ((off >> 8) << 28) | - (off & 0xfcu); -} - -static unsigned int u4_pcie_cfa1(unsigned int bus, unsigned int devfn, - unsigned int off) -{ - return (bus << 16) | - (devfn << 8) | - ((off >> 8) << 28) | - (off & 0xfcu) | 1u; -} - -static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose, - u8 bus, u8 dev_fn, int offset) -{ - unsigned int caddr; - - if (bus == hose->first_busno) - caddr = u4_pcie_cfa0(dev_fn, offset); - else - caddr = u4_pcie_cfa1(bus, dev_fn, offset); - - /* Uninorth will return garbage if we don't read back the value ! */ - do { - out_le32(hose->cfg_addr, caddr); - } while (in_le32(hose->cfg_addr) != caddr); - - offset &= 0x03; - return hose->cfg_data + offset; -} - -static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 *val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x1000) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - *val = in_8(addr); - break; - case 2: - *val = in_le16(addr); - break; - default: - *val = in_le32(addr); - break; - } - return PCIBIOS_SUCCESSFUL; -} -static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn, - int offset, int len, u32 val) -{ - struct pci_controller *hose; - volatile void __iomem *addr; - - hose = pci_bus_to_host(bus); - if (hose == NULL) - return PCIBIOS_DEVICE_NOT_FOUND; - if (offset >= 0x1000) - return PCIBIOS_BAD_REGISTER_NUMBER; - addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset); - if (!addr) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - switch (len) { - case 1: - out_8(addr, val); - break; - case 2: - out_le16(addr, val); - break; - default: - out_le32(addr, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops u4_pcie_pci_ops = -{ - .read = u4_pcie_read_config, - .write = u4_pcie_write_config, -}; - -static void __init setup_u3_agp(struct pci_controller* hose) -{ - /* On G5, we move AGP up to high bus number so we don't need - * to reassign bus numbers for HT. If we ever have P2P bridges - * on AGP, we'll have to move pci_assign_all_buses to the - * pci_controller structure so we enable it for AGP and not for - * HT childs. - * We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead - */ - hose->first_busno = 0xf0; - hose->last_busno = 0xff; - hose->ops = &u3_agp_pci_ops; - hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); - hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); - - u3_agp = hose; -} - -static void __init setup_u4_pcie(struct pci_controller* hose) -{ - /* We currently only implement the "non-atomic" config space, to - * be optimised later. - */ - hose->ops = &u4_pcie_pci_ops; - hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); - hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); - - u4_pcie = hose; -} - -static void __init setup_u3_ht(struct pci_controller* hose) -{ - hose->ops = &u3_ht_pci_ops; - - /* We hard code the address because of the different size of - * the reg address cell, we shall fix that by killing struct - * reg_property and using some accessor functions instead - */ - hose->cfg_data = ioremap(0xf2000000, 0x02000000); - hose->cfg_addr = ioremap(0xf8070000, 0x1000); - - hose->first_busno = 0; - hose->last_busno = 0xef; - - u3_ht = hose; -} - -static int __init maple_add_bridge(struct device_node *dev) -{ - int len; - struct pci_controller *hose; - char* disp_name; - const int *bus_range; - int primary = 1; - - DBG("Adding PCI host bridge %pOF\n", dev); - - bus_range = of_get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %pOF, assume bus 0\n", - dev); - } - - hose = pcibios_alloc_controller(dev); - if (hose == NULL) - return -ENOMEM; - hose->first_busno = bus_range ? bus_range[0] : 0; - hose->last_busno = bus_range ? bus_range[1] : 0xff; - hose->controller_ops = maple_pci_controller_ops; - - disp_name = NULL; - if (of_device_is_compatible(dev, "u3-agp")) { - setup_u3_agp(hose); - disp_name = "U3-AGP"; - primary = 0; - } else if (of_device_is_compatible(dev, "u3-ht")) { - setup_u3_ht(hose); - disp_name = "U3-HT"; - primary = 1; - } else if (of_device_is_compatible(dev, "u4-pcie")) { - setup_u4_pcie(hose); - disp_name = "U4-PCIE"; - primary = 0; - } - printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", - disp_name, hose->first_busno, hose->last_busno); - - /* Interpret the "ranges" property */ - /* This also maps the I/O region and sets isa_io/mem_base */ - pci_process_bridge_OF_ranges(hose, dev, primary); - - /* Fixup "bus-range" OF property */ - fixup_bus_range(dev); - - /* Check for legacy IOs */ - isa_bridge_find_early(hose); - - /* create pci_dn's for DT nodes under this PHB */ - pci_devs_phb_init_dynamic(hose); - - return 0; -} - - -void maple_pci_irq_fixup(struct pci_dev *dev) -{ - DBG(" -> maple_pci_irq_fixup\n"); - - /* Fixup IRQ for PCIe host */ - if (u4_pcie != NULL && dev->bus->number == 0 && - pci_bus_to_host(dev->bus) == u4_pcie) { - printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n"); - dev->irq = irq_create_mapping(NULL, 1); - if (dev->irq) - irq_set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW); - } - - /* Hide AMD8111 IDE interrupt when in legacy mode so - * the driver calls pci_get_legacy_ide_irq() - */ - if (dev->vendor == PCI_VENDOR_ID_AMD && - dev->device == PCI_DEVICE_ID_AMD_8111_IDE && - (dev->class & 5) != 5) { - dev->irq = 0; - } - - DBG(" <- maple_pci_irq_fixup\n"); -} - -static int maple_pci_root_bridge_prepare(struct pci_host_bridge *bridge) -{ - struct pci_controller *hose = pci_bus_to_host(bridge->bus); - struct device_node *np, *child; - - if (hose != u3_agp) - return 0; - - /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We - * assume there is no P2P bridge on the AGP bus, which should be a - * safe assumptions hopefully. - */ - np = hose->dn; - PCI_DN(np)->busno = 0xf0; - for_each_child_of_node(np, child) - PCI_DN(child)->busno = 0xf0; - - return 0; -} - -void __init maple_pci_init(void) -{ - struct device_node *np, *root; - struct device_node *ht = NULL; - - /* Probe root PCI hosts, that is on U3 the AGP host and the - * HyperTransport host. That one is actually "kept" around - * and actually added last as its resource management relies - * on the AGP resources to have been setup first - */ - root = of_find_node_by_path("/"); - if (root == NULL) { - printk(KERN_CRIT "maple_find_bridges: can't find root of device tree\n"); - return; - } - for_each_child_of_node(root, np) { - if (!of_node_is_type(np, "pci") && !of_node_is_type(np, "ht")) - continue; - if ((of_device_is_compatible(np, "u4-pcie") || - of_device_is_compatible(np, "u3-agp")) && - maple_add_bridge(np) == 0) - of_node_get(np); - - if (of_device_is_compatible(np, "u3-ht")) { - of_node_get(np); - ht = np; - } - } - of_node_put(root); - - /* Now setup the HyperTransport host if we found any - */ - if (ht && maple_add_bridge(ht) != 0) - of_node_put(ht); - - ppc_md.pcibios_root_bridge_prepare = maple_pci_root_bridge_prepare; - - /* Tell pci.c to not change any resource allocations. */ - pci_add_flags(PCI_PROBE_ONLY); -} - -int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel) -{ - struct device_node *np; - unsigned int defirq = channel ? 15 : 14; - unsigned int irq; - - if (pdev->vendor != PCI_VENDOR_ID_AMD || - pdev->device != PCI_DEVICE_ID_AMD_8111_IDE) - return defirq; - - np = pci_device_to_OF_node(pdev); - if (np == NULL) { - printk("Failed to locate OF node for IDE %s\n", - pci_name(pdev)); - return defirq; - } - irq = irq_of_parse_and_map(np, channel & 0x1); - if (!irq) { - printk("Failed to map onboard IDE interrupt for channel %d\n", - channel); - return defirq; - } - return irq; -} - -static void quirk_ipr_msi(struct pci_dev *dev) -{ - /* Something prevents MSIs from the IPR from working on Bimini, - * and the driver has no smarts to recover. So disable MSI - * on it for now. */ - - if (machine_is(maple)) { - dev->no_msi = 1; - dev_info(&dev->dev, "Quirk disabled MSI\n"); - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - quirk_ipr_msi); - -struct pci_controller_ops maple_pci_controller_ops = { -}; diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c deleted file mode 100644 index f329a03edf4a6c..00000000000000 --- a/arch/powerpc/platforms/maple/setup.c +++ /dev/null @@ -1,363 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Maple (970 eval board) setup code - * - * (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org), - * IBM Corp. - */ - -#undef DEBUG - -#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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "maple.h" - -#ifdef DEBUG -#define DBG(fmt...) udbg_printf(fmt) -#else -#define DBG(fmt...) -#endif - -static unsigned long maple_find_nvram_base(void) -{ - struct device_node *rtcs; - unsigned long result = 0; - - /* find NVRAM device */ - rtcs = of_find_compatible_node(NULL, "nvram", "AMD8111"); - if (rtcs) { - struct resource r; - if (of_address_to_resource(rtcs, 0, &r)) { - printk(KERN_EMERG "Maple: Unable to translate NVRAM" - " address\n"); - goto bail; - } - if (!(r.flags & IORESOURCE_IO)) { - printk(KERN_EMERG "Maple: NVRAM address isn't PIO!\n"); - goto bail; - } - result = r.start; - } else - printk(KERN_EMERG "Maple: Unable to find NVRAM\n"); - bail: - of_node_put(rtcs); - return result; -} - -static void __noreturn maple_restart(char *cmd) -{ - unsigned int maple_nvram_base; - const unsigned int *maple_nvram_offset, *maple_nvram_command; - struct device_node *sp; - - maple_nvram_base = maple_find_nvram_base(); - if (maple_nvram_base == 0) - goto fail; - - /* find service processor device */ - sp = of_find_node_by_name(NULL, "service-processor"); - if (!sp) { - printk(KERN_EMERG "Maple: Unable to find Service Processor\n"); - goto fail; - } - maple_nvram_offset = of_get_property(sp, "restart-addr", NULL); - maple_nvram_command = of_get_property(sp, "restart-value", NULL); - of_node_put(sp); - - /* send command */ - outb_p(*maple_nvram_command, maple_nvram_base + *maple_nvram_offset); - for (;;) ; - fail: - printk(KERN_EMERG "Maple: Manual Restart Required\n"); - for (;;) ; -} - -static void __noreturn maple_power_off(void) -{ - unsigned int maple_nvram_base; - const unsigned int *maple_nvram_offset, *maple_nvram_command; - struct device_node *sp; - - maple_nvram_base = maple_find_nvram_base(); - if (maple_nvram_base == 0) - goto fail; - - /* find service processor device */ - sp = of_find_node_by_name(NULL, "service-processor"); - if (!sp) { - printk(KERN_EMERG "Maple: Unable to find Service Processor\n"); - goto fail; - } - maple_nvram_offset = of_get_property(sp, "power-off-addr", NULL); - maple_nvram_command = of_get_property(sp, "power-off-value", NULL); - of_node_put(sp); - - /* send command */ - outb_p(*maple_nvram_command, maple_nvram_base + *maple_nvram_offset); - for (;;) ; - fail: - printk(KERN_EMERG "Maple: Manual Power-Down Required\n"); - for (;;) ; -} - -static void __noreturn maple_halt(void) -{ - maple_power_off(); -} - -#ifdef CONFIG_SMP -static struct smp_ops_t maple_smp_ops = { - .probe = smp_mpic_probe, - .message_pass = smp_mpic_message_pass, - .kick_cpu = smp_generic_kick_cpu, - .setup_cpu = smp_mpic_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, -}; -#endif /* CONFIG_SMP */ - -static void __init maple_use_rtas_reboot_and_halt_if_present(void) -{ - if (rtas_function_implemented(RTAS_FN_SYSTEM_REBOOT) && - rtas_function_implemented(RTAS_FN_POWER_OFF)) { - ppc_md.restart = rtas_restart; - pm_power_off = rtas_power_off; - ppc_md.halt = rtas_halt; - } -} - -static void __init maple_setup_arch(void) -{ - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000; - - /* Setup SMP callback */ -#ifdef CONFIG_SMP - smp_ops = &maple_smp_ops; -#endif - maple_use_rtas_reboot_and_halt_if_present(); - - printk(KERN_DEBUG "Using native/NAP idle loop\n"); - - mmio_nvram_init(); -} - -/* - * This is almost identical to pSeries and CHRP. We need to make that - * code generic at one point, with appropriate bits in the device-tree to - * identify the presence of an HT APIC - */ -static void __init maple_init_IRQ(void) -{ - struct device_node *root, *np, *mpic_node = NULL; - const unsigned int *opprop; - unsigned long openpic_addr = 0; - int naddr, n, i, opplen, has_isus = 0; - struct mpic *mpic; - unsigned int flags = 0; - - /* Locate MPIC in the device-tree. Note that there is a bug - * in Maple device-tree where the type of the controller is - * open-pic and not interrupt-controller - */ - - for_each_node_by_type(np, "interrupt-controller") - if (of_device_is_compatible(np, "open-pic")) { - mpic_node = np; - break; - } - if (mpic_node == NULL) - for_each_node_by_type(np, "open-pic") { - mpic_node = np; - break; - } - if (mpic_node == NULL) { - printk(KERN_ERR - "Failed to locate the MPIC interrupt controller\n"); - return; - } - - /* Find address list in /platform-open-pic */ - root = of_find_node_by_path("/"); - naddr = of_n_addr_cells(root); - opprop = of_get_property(root, "platform-open-pic", &opplen); - if (opprop) { - openpic_addr = of_read_number(opprop, naddr); - has_isus = (opplen > naddr); - printk(KERN_DEBUG "OpenPIC addr: %lx, has ISUs: %d\n", - openpic_addr, has_isus); - } - - BUG_ON(openpic_addr == 0); - - /* Check for a big endian MPIC */ - if (of_property_read_bool(np, "big-endian")) - flags |= MPIC_BIG_ENDIAN; - - /* XXX Maple specific bits */ - flags |= MPIC_U3_HT_IRQS; - /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */ - flags |= MPIC_BIG_ENDIAN; - - /* Setup the openpic driver. More device-tree junks, we hard code no - * ISUs for now. I'll have to revisit some stuffs with the folks doing - * the firmware for those - */ - mpic = mpic_alloc(mpic_node, openpic_addr, flags, - /*has_isus ? 16 :*/ 0, 0, " MPIC "); - BUG_ON(mpic == NULL); - - /* Add ISUs */ - opplen /= sizeof(u32); - for (n = 0, i = naddr; i < opplen; i += naddr, n++) { - unsigned long isuaddr = of_read_number(opprop + i, naddr); - mpic_assign_isu(mpic, n, isuaddr); - } - - /* All ISUs are setup, complete initialization */ - mpic_init(mpic); - ppc_md.get_irq = mpic_get_irq; - of_node_put(mpic_node); - of_node_put(root); -} - -static void __init maple_progress(char *s, unsigned short hex) -{ - printk("*** %04x : %s\n", hex, s ? s : ""); -} - - -/* - * Called very early, MMU is off, device-tree isn't unflattened - */ -static int __init maple_probe(void) -{ - if (!of_machine_is_compatible("Momentum,Maple") && - !of_machine_is_compatible("Momentum,Apache")) - return 0; - - pm_power_off = maple_power_off; - - iommu_init_early_dart(&maple_pci_controller_ops); - - return 1; -} - -#ifdef CONFIG_EDAC -/* - * Register a platform device for CPC925 memory controller on - * all boards with U3H (CPC925) bridge. - */ -static int __init maple_cpc925_edac_setup(void) -{ - struct platform_device *pdev; - struct device_node *np = NULL; - struct resource r; - int ret; - volatile void __iomem *mem; - u32 rev; - - np = of_find_node_by_type(NULL, "memory-controller"); - if (!np) { - printk(KERN_ERR "%s: Unable to find memory-controller node\n", - __func__); - return -ENODEV; - } - - ret = of_address_to_resource(np, 0, &r); - of_node_put(np); - - if (ret < 0) { - printk(KERN_ERR "%s: Unable to get memory-controller reg\n", - __func__); - return -ENODEV; - } - - mem = ioremap(r.start, resource_size(&r)); - if (!mem) { - printk(KERN_ERR "%s: Unable to map memory-controller memory\n", - __func__); - return -ENOMEM; - } - - rev = __raw_readl(mem); - iounmap(mem); - - if (rev < 0x34 || rev > 0x3f) { /* U3H */ - printk(KERN_ERR "%s: Non-CPC925(U3H) bridge revision: %02x\n", - __func__, rev); - return 0; - } - - pdev = platform_device_register_simple("cpc925_edac", 0, &r, 1); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - printk(KERN_INFO "%s: CPC925 platform device created\n", __func__); - - return 0; -} -machine_device_initcall(maple, maple_cpc925_edac_setup); -#endif - -define_machine(maple) { - .name = "Maple", - .probe = maple_probe, - .setup_arch = maple_setup_arch, - .discover_phbs = maple_pci_init, - .init_IRQ = maple_init_IRQ, - .pci_irq_fixup = maple_pci_irq_fixup, - .pci_get_legacy_ide_irq = maple_pci_get_legacy_ide_irq, - .restart = maple_restart, - .halt = maple_halt, - .get_boot_time = maple_get_boot_time, - .set_rtc_time = maple_set_rtc_time, - .get_rtc_time = maple_get_rtc_time, - .progress = maple_progress, - .power_save = power4_idle, -}; diff --git a/arch/powerpc/platforms/maple/time.c b/arch/powerpc/platforms/maple/time.c deleted file mode 100644 index 91606411d2e08b..00000000000000 --- a/arch/powerpc/platforms/maple/time.c +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org), - * IBM Corp. - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "maple.h" - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static int maple_rtc_addr; - -static int maple_clock_read(int addr) -{ - outb_p(addr, maple_rtc_addr); - return inb_p(maple_rtc_addr+1); -} - -static void maple_clock_write(unsigned long val, int addr) -{ - outb_p(addr, maple_rtc_addr); - outb_p(val, maple_rtc_addr+1); -} - -void maple_get_rtc_time(struct rtc_time *tm) -{ - do { - tm->tm_sec = maple_clock_read(RTC_SECONDS); - tm->tm_min = maple_clock_read(RTC_MINUTES); - tm->tm_hour = maple_clock_read(RTC_HOURS); - tm->tm_mday = maple_clock_read(RTC_DAY_OF_MONTH); - tm->tm_mon = maple_clock_read(RTC_MONTH); - tm->tm_year = maple_clock_read(RTC_YEAR); - } while (tm->tm_sec != maple_clock_read(RTC_SECONDS)); - - if (!(maple_clock_read(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) { - tm->tm_sec = bcd2bin(tm->tm_sec); - tm->tm_min = bcd2bin(tm->tm_min); - tm->tm_hour = bcd2bin(tm->tm_hour); - tm->tm_mday = bcd2bin(tm->tm_mday); - tm->tm_mon = bcd2bin(tm->tm_mon); - tm->tm_year = bcd2bin(tm->tm_year); - } - if ((tm->tm_year + 1900) < 1970) - tm->tm_year += 100; - - tm->tm_wday = -1; -} - -int maple_set_rtc_time(struct rtc_time *tm) -{ - unsigned char save_control, save_freq_select; - int sec, min, hour, mon, mday, year; - - spin_lock(&rtc_lock); - - save_control = maple_clock_read(RTC_CONTROL); /* tell the clock it's being set */ - - maple_clock_write((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = maple_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */ - - maple_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - sec = tm->tm_sec; - min = tm->tm_min; - hour = tm->tm_hour; - mon = tm->tm_mon; - mday = tm->tm_mday; - year = tm->tm_year; - - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - sec = bin2bcd(sec); - min = bin2bcd(min); - hour = bin2bcd(hour); - mon = bin2bcd(mon); - mday = bin2bcd(mday); - year = bin2bcd(year); - } - maple_clock_write(sec, RTC_SECONDS); - maple_clock_write(min, RTC_MINUTES); - maple_clock_write(hour, RTC_HOURS); - maple_clock_write(mon, RTC_MONTH); - maple_clock_write(mday, RTC_DAY_OF_MONTH); - maple_clock_write(year, RTC_YEAR); - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - maple_clock_write(save_control, RTC_CONTROL); - maple_clock_write(save_freq_select, RTC_FREQ_SELECT); - - spin_unlock(&rtc_lock); - - return 0; -} - -static struct resource rtc_iores = { - .name = "rtc", - .flags = IORESOURCE_IO | IORESOURCE_BUSY, -}; - -time64_t __init maple_get_boot_time(void) -{ - struct rtc_time tm; - struct device_node *rtcs; - - rtcs = of_find_compatible_node(NULL, "rtc", "pnpPNP,b00"); - if (rtcs) { - struct resource r; - if (of_address_to_resource(rtcs, 0, &r)) { - printk(KERN_EMERG "Maple: Unable to translate RTC" - " address\n"); - goto bail; - } - if (!(r.flags & IORESOURCE_IO)) { - printk(KERN_EMERG "Maple: RTC address isn't PIO!\n"); - goto bail; - } - maple_rtc_addr = r.start; - printk(KERN_INFO "Maple: Found RTC at IO 0x%x\n", - maple_rtc_addr); - } - bail: - of_node_put(rtcs); - if (maple_rtc_addr == 0) { - maple_rtc_addr = RTC_PORT(0); /* legacy address */ - printk(KERN_INFO "Maple: No device node for RTC, assuming " - "legacy address (0x%x)\n", maple_rtc_addr); - } - - rtc_iores.start = maple_rtc_addr; - rtc_iores.end = maple_rtc_addr + 7; - request_resource(&ioport_resource, &rtc_iores); - - maple_get_rtc_time(&tm); - return rtc_tm_to_time64(&tm); -} - diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c index 12bc01353bd3c6..79741370c40c64 100644 --- a/arch/powerpc/platforms/powermac/backlight.c +++ b/arch/powerpc/platforms/powermac/backlight.c @@ -57,18 +57,10 @@ struct backlight_device *pmac_backlight; int pmac_has_backlight_type(const char *type) { struct device_node* bk_node = of_find_node_by_name(NULL, "backlight"); + int i = of_property_match_string(bk_node, "backlight-control", type); - if (bk_node) { - const char *prop = of_get_property(bk_node, - "backlight-control", NULL); - if (prop && strncmp(prop, type, strlen(type)) == 0) { - of_node_put(bk_node); - return 1; - } - of_node_put(bk_node); - } - - return 0; + of_node_put(bk_node); + return i >= 0; } static void pmac_backlight_key_worker(struct work_struct *work) diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index d21b681f52fb0e..09e7fe24fac10b 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/powernv/idle.c b/arch/powerpc/platforms/powernv/idle.c index ad41dffe4d9291..d98b933e4984c2 100644 --- a/arch/powerpc/platforms/powernv/idle.c +++ b/arch/powerpc/platforms/powernv/idle.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index 8f14f0581a21b1..8f41ef364fc6f7 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -36,6 +36,7 @@ #include #include #include +#include #include "powernv.h" @@ -136,7 +137,9 @@ static int pnv_smp_cpu_disable(void) * the generic fixup_irqs. --BenH. */ set_cpu_online(cpu, false); - vdso_data->processorCount--; +#ifdef CONFIG_PPC64_PROC_SYSTEMCFG + systemcfg->processorCount--; +#endif if (cpu == boot_cpuid) boot_cpuid = cpumask_any(cpu_online_mask); if (xive_enabled()) diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index b18e1c92e554ce..61722133eb2d3f 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -178,7 +178,7 @@ static int __init ps3_setup_gelic_device( return result; } -static int __ref ps3_setup_uhc_device( +static int __init ps3_setup_uhc_device( const struct ps3_repository_device *repo, enum ps3_match_id match_id, enum ps3_interrupt_type interrupt_type, enum ps3_reg_type reg_type) { diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 49871427f599d1..af3fe9f04f24cc 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -378,9 +378,9 @@ int ps3_send_event_locally(unsigned int virq) /** * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. + * @dev: The system bus device instance. * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be * serviced on. - * @dev: The system bus device instance. * @virq: The assigned Linux virq. * * An event irq represents a virtual device interrupt. The interrupt_id diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 1abe33fbe52905..b8c030eab1384e 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c @@ -940,7 +940,7 @@ int __init ps3_repository_read_vuart_sysmgr_port(unsigned int *port) /** * ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area. - * address: lpar address of cell_ext_os_area + * @lpar_addr: lpar address of cell_ext_os_area * @size: size of cell_ext_os_area */ diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index b9a7d9bae687e8..afbaabf182d013 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c @@ -453,10 +453,9 @@ static ssize_t modalias_show(struct device *_dev, struct device_attribute *a, char *buf) { struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); - int len = snprintf(buf, PAGE_SIZE, "ps3:%d:%d\n", dev->match_id, - dev->match_sub_id); - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; + return sysfs_emit(buf, "ps3:%d:%d\n", dev->match_id, + dev->match_sub_id); } static DEVICE_ATTR_RO(modalias); diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index afc0f6a6133726..42fc66e97539b6 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -140,6 +140,20 @@ config HV_PERF_CTRS If unsure, select Y. +config VPA_PMU + tristate "VPA PMU events" + depends on KVM_BOOK3S_64_HV && HV_PERF_CTRS + help + Enable access to the VPA PMU counters via perf. This enables + code that support measurement for KVM on PowerVM(KoP) feature. + PAPR hypervisor has introduced three new counters in the VPA area + of LPAR CPUs for KVM L2 guest observability. Two for context switches + from host to guest and vice versa, and one counter for getting + the total time spent inside the KVM guest. This config enables code + that access these software counters via perf. + + If unsure, Select N. + config IBMVIO depends on PPC_PSERIES bool diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 8cb9d36ea49159..f293588b8c7b51 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -191,7 +191,7 @@ static int dtl_enable(struct dtl *dtl) return -EBUSY; /* ensure there are no other conflicting dtl users */ - if (!read_trylock(&dtl_access_lock)) + if (!down_read_trylock(&dtl_access_lock)) return -EBUSY; n_entries = dtl_buf_entries; @@ -199,7 +199,7 @@ static int dtl_enable(struct dtl *dtl) if (!buf) { printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", __func__, dtl->cpu); - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); return -ENOMEM; } @@ -217,7 +217,7 @@ static int dtl_enable(struct dtl *dtl) spin_unlock(&dtl->lock); if (rc) { - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); kmem_cache_free(dtl_cache, buf); } @@ -232,7 +232,7 @@ static void dtl_disable(struct dtl *dtl) dtl->buf = NULL; dtl->buf_entries = 0; spin_unlock(&dtl->lock); - read_unlock(&dtl_access_lock); + up_read(&dtl_access_lock); } /* file interface */ diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 6838a0fcda296b..bc6926dbf14890 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "pseries.h" @@ -83,7 +84,9 @@ static int pseries_cpu_disable(void) int cpu = smp_processor_id(); set_cpu_online(cpu, false); - vdso_data->processorCount--; +#ifdef CONFIG_PPC64_PROC_SYSTEMCFG + systemcfg->processorCount--; +#endif /*fix boot_cpuid here*/ if (cpu == boot_cpuid) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index c1d8bee8f7018c..6a415febc53b74 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -169,7 +170,7 @@ struct vcpu_dispatch_data { */ #define NR_CPUS_H NR_CPUS -DEFINE_RWLOCK(dtl_access_lock); +DECLARE_RWSEM(dtl_access_lock); static DEFINE_PER_CPU(struct vcpu_dispatch_data, vcpu_disp_data); static DEFINE_PER_CPU(u64, dtl_entry_ridx); static DEFINE_PER_CPU(struct dtl_worker, dtl_workers); @@ -463,7 +464,7 @@ static int dtl_worker_enable(unsigned long *time_limit) { int rc = 0, state; - if (!write_trylock(&dtl_access_lock)) { + if (!down_write_trylock(&dtl_access_lock)) { rc = -EBUSY; goto out; } @@ -479,7 +480,7 @@ static int dtl_worker_enable(unsigned long *time_limit) pr_err("vcpudispatch_stats: unable to setup workqueue for DTL processing\n"); free_dtl_buffers(time_limit); reset_global_dtl_mask(); - write_unlock(&dtl_access_lock); + up_write(&dtl_access_lock); rc = -EINVAL; goto out; } @@ -494,7 +495,7 @@ static void dtl_worker_disable(unsigned long *time_limit) cpuhp_remove_state(dtl_worker_state); free_dtl_buffers(time_limit); reset_global_dtl_mask(); - write_unlock(&dtl_access_lock); + up_write(&dtl_access_lock); } static ssize_t vcpudispatch_stats_write(struct file *file, const char __user *p, diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c index 62da20f9700a97..cc22924f159f50 100644 --- a/arch/powerpc/platforms/pseries/lparcfg.c +++ b/arch/powerpc/platforms/pseries/lparcfg.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -530,7 +529,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v) lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL); if (lrdrp == NULL) { - partition_potential_processors = vdso_data->processorCount; + partition_potential_processors = num_possible_cpus(); } else { partition_potential_processors = be32_to_cpup(lrdrp + 4); } @@ -553,7 +552,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v) } else { /* non SPLPAR case */ seq_printf(m, "system_active_processors=%d\n", - partition_potential_processors); + partition_active_processors); seq_printf(m, "system_potential_processors=%d\n", partition_potential_processors); diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 6dfb55b52d363d..fdc2f7f38dc9a1 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/arch/powerpc/platforms/pseries/papr_scm.c b/arch/powerpc/platforms/pseries/papr_scm.c index 9e297f88adc5d9..f84ac9fbe203c1 100644 --- a/arch/powerpc/platforms/pseries/papr_scm.c +++ b/arch/powerpc/platforms/pseries/papr_scm.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c index 4a595493d28ae3..b1667ed05f9882 100644 --- a/arch/powerpc/platforms/pseries/plpks.c +++ b/arch/powerpc/platforms/pseries/plpks.c @@ -683,7 +683,7 @@ void __init plpks_early_init_devtree(void) out: fdt_nop_property(fdt, chosen_node, "ibm,plpks-pw"); // Since we've cleared the password, we must update the FDT checksum - early_init_dt_verify(fdt); + early_init_dt_verify(fdt, __pa(fdt)); } static __init int pseries_plpks_init(void) diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index c597711ef20a2b..db99725e752bd5 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/platforms/pseries/svm.c b/arch/powerpc/platforms/pseries/svm.c index 3b4045d508ec84..384c9dc1899abd 100644 --- a/arch/powerpc/platforms/pseries/svm.c +++ b/arch/powerpc/platforms/pseries/svm.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c index fa01818c1972cf..a6c388bdf5d08c 100644 --- a/arch/powerpc/sysdev/xive/common.c +++ b/arch/powerpc/sysdev/xive/common.c @@ -726,7 +726,7 @@ static int xive_irq_set_affinity(struct irq_data *d, pr_debug("%s: irq %d/0x%x\n", __func__, d->irq, hw_irq); /* Is this valid ? */ - if (cpumask_any_and(cpumask, cpu_online_mask) >= nr_cpu_ids) + if (!cpumask_intersects(cpumask, cpu_online_mask)) return -EINVAL; /* diff --git a/arch/powerpc/sysdev/xive/spapr.c b/arch/powerpc/sysdev/xive/spapr.c index f2fa985a2c7712..5aedbe3e8e6a24 100644 --- a/arch/powerpc/sysdev/xive/spapr.c +++ b/arch/powerpc/sysdev/xive/spapr.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/arch/powerpc/tools/.gitignore b/arch/powerpc/tools/.gitignore new file mode 100644 index 00000000000000..ec380a14a09aa9 --- /dev/null +++ b/arch/powerpc/tools/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +/vmlinux.arch.S diff --git a/arch/powerpc/tools/Makefile b/arch/powerpc/tools/Makefile new file mode 100644 index 00000000000000..e1f7afcd9fdfd9 --- /dev/null +++ b/arch/powerpc/tools/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +quiet_cmd_gen_ftrace_ool_stubs = GEN $@ + cmd_gen_ftrace_ool_stubs = $< "$(CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE)" "$(CONFIG_64BIT)" \ + "$(OBJDUMP)" vmlinux.o $@ + +$(obj)/vmlinux.arch.S: $(src)/ftrace-gen-ool-stubs.sh vmlinux.o FORCE + $(call if_changed,gen_ftrace_ool_stubs) + +targets += vmlinux.arch.S diff --git a/arch/powerpc/tools/ftrace-gen-ool-stubs.sh b/arch/powerpc/tools/ftrace-gen-ool-stubs.sh new file mode 100755 index 00000000000000..bac186bdf64a7e --- /dev/null +++ b/arch/powerpc/tools/ftrace-gen-ool-stubs.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later + +# Error out on error +set -e + +num_ool_stubs_text_builtin="$1" +is_64bit="$2" +objdump="$3" +vmlinux_o="$4" +arch_vmlinux_S="$5" + +RELOCATION=R_PPC64_ADDR64 +if [ -z "$is_64bit" ]; then + RELOCATION=R_PPC_ADDR32 +fi + +num_ool_stubs_total=$($objdump -r -j __patchable_function_entries "$vmlinux_o" | + grep -c "$RELOCATION") +num_ool_stubs_inittext=$($objdump -r -j __patchable_function_entries "$vmlinux_o" | + grep -e ".init.text" -e ".text.startup" | grep -c "$RELOCATION") +num_ool_stubs_text=$((num_ool_stubs_total - num_ool_stubs_inittext)) + +if [ "$num_ool_stubs_text" -gt "$num_ool_stubs_text_builtin" ]; then + num_ool_stubs_text_end=$((num_ool_stubs_text - num_ool_stubs_text_builtin)) +else + num_ool_stubs_text_end=0 +fi + +cat > "$arch_vmlinux_S" < +#include +#include + +.pushsection .tramp.ftrace.text,"aw" +SYM_DATA(ftrace_ool_stub_text_end_count, .long $num_ool_stubs_text_end) + +SYM_START(ftrace_ool_stub_text_end, SYM_L_GLOBAL, .balign SZL) +#if $num_ool_stubs_text_end + .space $num_ool_stubs_text_end * FTRACE_OOL_STUB_SIZE +#endif +SYM_CODE_END(ftrace_ool_stub_text_end) +.popsection + +.pushsection .tramp.ftrace.init,"aw" +SYM_DATA(ftrace_ool_stub_inittext_count, .long $num_ool_stubs_inittext) + +SYM_START(ftrace_ool_stub_inittext, SYM_L_GLOBAL, .balign SZL) + .space $num_ool_stubs_inittext * FTRACE_OOL_STUB_SIZE +SYM_CODE_END(ftrace_ool_stub_inittext) +.popsection +EOF diff --git a/arch/powerpc/tools/ftrace_check.sh b/arch/powerpc/tools/ftrace_check.sh new file mode 100755 index 00000000000000..405e7e3066175f --- /dev/null +++ b/arch/powerpc/tools/ftrace_check.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-or-later +# +# This script checks vmlinux to ensure that all functions can call ftrace_caller() either directly, +# or through the stub, ftrace_tramp_text, at the end of kernel text. + +# Error out if any command fails +set -e + +# Allow for verbose output +if [ "$V" = "1" ]; then + set -x +fi + +if [ $# -lt 2 ]; then + echo "$0 [path to nm] [path to vmlinux]" 1>&2 + exit 1 +fi + +# Have Kbuild supply the path to nm so we handle cross compilation. +nm="$1" +vmlinux="$2" + +stext_addr=$($nm "$vmlinux" | grep -e " [TA] _stext$" | \ + cut -d' ' -f1 | tr '[:lower:]' '[:upper:]') +ftrace_caller_addr=$($nm "$vmlinux" | grep -e " T ftrace_caller$" | \ + cut -d' ' -f1 | tr '[:lower:]' '[:upper:]') +ftrace_tramp_addr=$($nm "$vmlinux" | grep -e " T ftrace_tramp_text$" | \ + cut -d' ' -f1 | tr '[:lower:]' '[:upper:]') + +ftrace_caller_offset=$(echo "ibase=16;$ftrace_caller_addr - $stext_addr" | bc) +ftrace_tramp_offset=$(echo "ibase=16;$ftrace_tramp_addr - $ftrace_caller_addr" | bc) +sz_32m=$(printf "%d" 0x2000000) +sz_64m=$(printf "%d" 0x4000000) + +# ftrace_caller - _stext < 32M +if [ "$ftrace_caller_offset" -ge "$sz_32m" ]; then + echo "ERROR: ftrace_caller (0x$ftrace_caller_addr) is beyond 32MiB of _stext" 1>&2 + echo "ERROR: consider disabling CONFIG_FUNCTION_TRACER, or reducing the size \ + of kernel text" 1>&2 + exit 1 +fi + +# ftrace_tramp_text - ftrace_caller < 64M +if [ "$ftrace_tramp_offset" -ge "$sz_64m" ]; then + echo "ERROR: kernel text extends beyond 64MiB from ftrace_caller" 1>&2 + echo "ERROR: consider disabling CONFIG_FUNCTION_TRACER, or reducing the size \ + of kernel text" 1>&2 + exit 1 +fi diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index e6cddbb2305f8d..f4e841a3645859 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include #include @@ -3662,7 +3662,7 @@ symbol_lookup(void) int type = inchar(); unsigned long addr, cpu; void __percpu *ptr = NULL; - static char tmp[64]; + static char tmp[KSYM_NAME_LEN]; switch (type) { case 'a': @@ -3671,7 +3671,7 @@ symbol_lookup(void) termch = 0; break; case 's': - getstring(tmp, 64); + getstring(tmp, KSYM_NAME_LEN); if (setjmp(bus_error_jmp) == 0) { catch_memory_errors = 1; sync(); @@ -3686,7 +3686,7 @@ symbol_lookup(void) termch = 0; break; case 'p': - getstring(tmp, 64); + getstring(tmp, KSYM_NAME_LEN); if (setjmp(bus_error_jmp) == 0) { catch_memory_errors = 1; sync(); diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index fa8f2da87a0a83..d4a7ca0388c071 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -32,6 +32,7 @@ config RISCV select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_GIGANTIC_PAGE + select ARCH_HAS_HW_PTE_YOUNG select ARCH_HAS_KCOV select ARCH_HAS_KERNEL_FPU_SUPPORT if 64BIT && FPU select ARCH_HAS_MEMBARRIER_CALLBACKS @@ -39,6 +40,7 @@ config RISCV select ARCH_HAS_MMIOWB select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PMEM_API + select ARCH_HAS_PREEMPT_LAZY select ARCH_HAS_PREPARE_SYNC_CORE_CMD select ARCH_HAS_PTE_DEVMAP if 64BIT && MMU select ARCH_HAS_PTE_SPECIAL @@ -50,7 +52,7 @@ config RISCV select ARCH_HAS_SYSCALL_WRAPPER select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_UBSAN - select ARCH_HAS_VDSO_DATA + select ARCH_HAS_VDSO_TIME_DATA select ARCH_KEEP_MEMBLOCK if ACPI select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE if 64BIT && MMU select ARCH_OPTIONAL_KERNEL_RWX if ARCH_HAS_STRICT_KERNEL_RWX @@ -82,6 +84,7 @@ config RISCV select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP select ARCH_WANTS_NO_INSTR select ARCH_WANTS_THP_SWAP if HAVE_ARCH_TRANSPARENT_HUGEPAGE + select ARCH_WEAK_RELEASE_ACQUIRE if ARCH_USE_QUEUED_SPINLOCKS select BINFMT_FLAT_NO_DATA_START_OFFSET if !MMU select BUILDTIME_TABLE_SORT if MMU select CLINT_TIMER if RISCV_M_MODE @@ -115,6 +118,7 @@ config RISCV select GENERIC_VDSO_TIME_NS if HAVE_GENERIC_VDSO select HARDIRQS_SW_RESEND select HAS_IOPORT if MMU + select HAVE_ALIGNED_STRUCT_PAGE select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_HUGE_VMALLOC if HAVE_ARCH_HUGE_VMAP select HAVE_ARCH_HUGE_VMAP if MMU && 64BIT @@ -506,6 +510,39 @@ config NODES_SHIFT Specify the maximum number of NUMA Nodes available on the target system. Increases memory reserved to accommodate various tables. +choice + prompt "RISC-V spinlock type" + default RISCV_COMBO_SPINLOCKS + +config RISCV_TICKET_SPINLOCKS + bool "Using ticket spinlock" + +config RISCV_QUEUED_SPINLOCKS + bool "Using queued spinlock" + depends on SMP && MMU && NONPORTABLE + select ARCH_USE_QUEUED_SPINLOCKS + help + The queued spinlock implementation requires the forward progress + guarantee of cmpxchg()/xchg() atomic operations: CAS with Zabha or + LR/SC with Ziccrse provide such guarantee. + + Select this if and only if Zabha or Ziccrse is available on your + platform, RISCV_QUEUED_SPINLOCKS must not be selected for platforms + without one of those extensions. + + If unsure, select RISCV_COMBO_SPINLOCKS, which will use qspinlocks + when supported and otherwise ticket spinlocks. + +config RISCV_COMBO_SPINLOCKS + bool "Using combo spinlock" + depends on SMP && MMU + select ARCH_USE_QUEUED_SPINLOCKS + help + Embed both queued spinlock and ticket lock so that the spinlock + implementation can be chosen at runtime. + +endchoice + config RISCV_ALTERNATIVE bool depends on !XIP_KERNEL @@ -531,6 +568,17 @@ config RISCV_ISA_C If you don't know what to do here, say Y. +config RISCV_ISA_SUPM + bool "Supm extension for userspace pointer masking" + depends on 64BIT + default y + help + Add support for pointer masking in userspace (Supm) when the + underlying hardware extension (Smnpm or Ssnpm) is detected at boot. + + If this option is disabled, userspace will be unable to use + the prctl(PR_{SET,GET}_TAGGED_ADDR_CTRL) API. + config RISCV_ISA_SVNAPOT bool "Svnapot extension support for supervisor mode NAPOT pages" depends on 64BIT && MMU @@ -632,6 +680,40 @@ config RISCV_ISA_ZAWRS use of these instructions in the kernel when the Zawrs extension is detected at boot. +config TOOLCHAIN_HAS_ZABHA + bool + default y + depends on !64BIT || $(cc-option,-mabi=lp64 -march=rv64ima_zabha) + depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zabha) + depends on AS_HAS_OPTION_ARCH + +config RISCV_ISA_ZABHA + bool "Zabha extension support for atomic byte/halfword operations" + depends on TOOLCHAIN_HAS_ZABHA + depends on RISCV_ALTERNATIVE + default y + help + Enable the use of the Zabha ISA-extension to implement kernel + byte/halfword atomic memory operations when it is detected at boot. + + If you don't know what to do here, say Y. + +config TOOLCHAIN_HAS_ZACAS + bool + default y + depends on !64BIT || $(cc-option,-mabi=lp64 -march=rv64ima_zacas) + depends on !32BIT || $(cc-option,-mabi=ilp32 -march=rv32ima_zacas) + depends on AS_HAS_OPTION_ARCH + +config RISCV_ISA_ZACAS + bool "Zacas extension support for atomic CAS" + depends on TOOLCHAIN_HAS_ZACAS + depends on RISCV_ALTERNATIVE + default y + help + Enable the use of the Zacas ISA-extension to implement kernel atomic + cmpxchg operations when it is detected at boot. + If you don't know what to do here, say Y. config TOOLCHAIN_HAS_ZBB @@ -785,10 +867,24 @@ config THREAD_SIZE_ORDER config RISCV_MISALIGNED bool + help + Embed support for detecting and emulating misaligned + scalar or vector loads and stores. + +config RISCV_SCALAR_MISALIGNED + bool + select RISCV_MISALIGNED select SYSCTL_ARCH_UNALIGN_ALLOW help Embed support for emulating misaligned loads and stores. +config RISCV_VECTOR_MISALIGNED + bool + select RISCV_MISALIGNED + depends on RISCV_ISA_V + help + Enable detecting support for vector misaligned loads and stores. + choice prompt "Unaligned Accesses Support" default RISCV_PROBE_UNALIGNED_ACCESS @@ -800,7 +896,7 @@ choice config RISCV_PROBE_UNALIGNED_ACCESS bool "Probe for hardware unaligned access support" - select RISCV_MISALIGNED + select RISCV_SCALAR_MISALIGNED help During boot, the kernel will run a series of tests to determine the speed of unaligned accesses. This probing will dynamically determine @@ -811,7 +907,7 @@ config RISCV_PROBE_UNALIGNED_ACCESS config RISCV_EMULATED_UNALIGNED_ACCESS bool "Emulate unaligned access where system support is missing" - select RISCV_MISALIGNED + select RISCV_SCALAR_MISALIGNED help If unaligned memory accesses trap into the kernel as they are not supported by the system, the kernel will emulate the unaligned @@ -840,6 +936,46 @@ config RISCV_EFFICIENT_UNALIGNED_ACCESS endchoice +choice + prompt "Vector unaligned Accesses Support" + depends on RISCV_ISA_V + default RISCV_PROBE_VECTOR_UNALIGNED_ACCESS + help + This determines the level of support for vector unaligned accesses. This + information is used by the kernel to perform optimizations. It is also + exposed to user space via the hwprobe syscall. The hardware will be + probed at boot by default. + +config RISCV_PROBE_VECTOR_UNALIGNED_ACCESS + bool "Probe speed of vector unaligned accesses" + select RISCV_VECTOR_MISALIGNED + depends on RISCV_ISA_V + help + During boot, the kernel will run a series of tests to determine the + speed of vector unaligned accesses if they are supported. This probing + will dynamically determine the speed of vector unaligned accesses on + the underlying system if they are supported. + +config RISCV_SLOW_VECTOR_UNALIGNED_ACCESS + bool "Assume the system supports slow vector unaligned memory accesses" + depends on NONPORTABLE + help + Assume that the system supports slow vector unaligned memory accesses. The + kernel and userspace programs may not be able to run at all on systems + that do not support unaligned memory accesses. + +config RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS + bool "Assume the system supports fast vector unaligned memory accesses" + depends on NONPORTABLE + help + Assume that the system supports fast vector unaligned memory accesses. When + enabled, this option improves the performance of the kernel on such + systems. However, the kernel and userspace programs will run much more + slowly, or will not be able to run at all, on systems that do not + support efficient unaligned memory accesses. + +endchoice + source "arch/riscv/Kconfig.vendor" endmenu # "Platform type" diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index d469db9f46f426..13fbc0f9423879 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -82,6 +82,12 @@ else riscv-march-$(CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI) := $(riscv-march-y)_zicsr_zifencei endif +# Check if the toolchain supports Zacas +riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZACAS) := $(riscv-march-y)_zacas + +# Check if the toolchain supports Zabha +riscv-march-$(CONFIG_TOOLCHAIN_HAS_ZABHA) := $(riscv-march-y)_zabha + # Remove F,D,V from isa string for all. Keep extensions between "fd" and "v" by # matching non-v and non-multi-letter extensions out with the filter ([^v_]*) KBUILD_CFLAGS += -march=$(shell echo $(riscv-march-y) | sed -E 's/(rv32ima|rv64ima)fd([^v_]*)v?/\1\2/') @@ -129,7 +135,7 @@ stack_protector_prepare: prepare0 -mstack-protector-guard-reg=tp \ -mstack-protector-guard-offset=$(shell \ awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \ - include/generated/asm-offsets.h)) + $(objtree)/include/generated/asm-offsets.h)) endif # arch specific predefines for sparse diff --git a/arch/riscv/boot/dts/renesas/rzfive-smarc-som.dtsi b/arch/riscv/boot/dts/renesas/rzfive-smarc-som.dtsi index 5e808242649ec1..86b2f15375ecad 100644 --- a/arch/riscv/boot/dts/renesas/rzfive-smarc-som.dtsi +++ b/arch/riscv/boot/dts/renesas/rzfive-smarc-som.dtsi @@ -6,3 +6,7 @@ */ #include + +&sbc { + status = "disabled"; +}; diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile index 57ad82a61ea6fc..47d4243a8f35a7 100644 --- a/arch/riscv/boot/dts/sophgo/Makefile +++ b/arch/riscv/boot/dts/sophgo/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_SOPHGO) += cv1800b-milkv-duo.dtb dtb-$(CONFIG_ARCH_SOPHGO) += cv1812h-huashan-pi.dtb +dtb-$(CONFIG_ARCH_SOPHGO) += sg2002-licheerv-nano-b.dtb dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb diff --git a/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts b/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts index 375ff2661b6e25..9feb520eaec41b 100644 --- a/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts +++ b/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts @@ -39,7 +39,54 @@ &osc { clock-frequency = <25000000>; }; +&pinctrl { + uart0_cfg: uart0-cfg { + uart0-pins { + pinmux = , + ; + bias-pull-up; + drive-strength-microamp = <10800>; + power-source = <3300>; + }; + }; + + sdhci0_cfg: sdhci0-cfg { + sdhci0-clk-pins { + pinmux = ; + bias-pull-up; + drive-strength-microamp = <16100>; + power-source = <3300>; + }; + + sdhci0-cmd-pins { + pinmux = ; + bias-pull-up; + drive-strength-microamp = <10800>; + power-source = <3300>; + }; + + sdhci0-data-pins { + pinmux = , + , + , + ; + bias-pull-up; + drive-strength-microamp = <10800>; + power-source = <3300>; + }; + + sdhci0-cd-pins { + pinmux = ; + bias-pull-up; + drive-strength-microamp = <10800>; + power-source = <3300>; + }; + }; +}; + &sdhci0 { + pinctrl-0 = <&sdhci0_cfg>; + pinctrl-names = "default"; status = "okay"; bus-width = <4>; no-1-8-v; @@ -49,5 +96,7 @@ &sdhci0 { }; &uart0 { + pinctrl-0 = <&uart0_cfg>; + pinctrl-names = "default"; status = "okay"; }; diff --git a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi index ec9530972ae2bb..aa1f5df100f074 100644 --- a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +++ b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi @@ -3,6 +3,7 @@ * Copyright (C) 2023 Jisheng Zhang */ +#include #include "cv18xx.dtsi" / { @@ -12,6 +13,15 @@ memory@80000000 { device_type = "memory"; reg = <0x80000000 0x4000000>; }; + + soc { + pinctrl: pinctrl@3001000 { + compatible = "sophgo,cv1800b-pinctrl"; + reg = <0x03001000 0x1000>, + <0x05027000 0x1000>; + reg-names = "sys", "rtc"; + }; + }; }; &plic { diff --git a/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts b/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts index 7b5f57853690b3..26b57e15adc123 100644 --- a/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts +++ b/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts @@ -43,6 +43,18 @@ &osc { clock-frequency = <25000000>; }; +&emmc { + status = "okay"; + bus-width = <4>; + max-frequency = <200000000>; + mmc-ddr-1_8v; + mmc-ddr-3_3v; + mmc-hs200-1_8v; + no-sd; + no-sdio; + non-removable; +}; + &sdhci0 { status = "okay"; bus-width = <4>; @@ -52,6 +64,17 @@ &sdhci0 { disable-wp; }; +&sdhci1 { + status = "okay"; + bus-width = <4>; + cap-sdio-irq; + max-frequency = <50000000>; + no-mmc; + no-sd; + disable-wp; + non-removable; +}; + &uart0 { status = "okay"; }; diff --git a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi index 7fa4c1e2d1da45..8a1b95c5116bf6 100644 --- a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi +++ b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi @@ -4,7 +4,9 @@ */ #include +#include #include "cv18xx.dtsi" +#include "cv181x.dtsi" / { compatible = "sophgo,cv1812h"; @@ -13,6 +15,15 @@ memory@80000000 { device_type = "memory"; reg = <0x80000000 0x10000000>; }; + + soc { + pinctrl: pinctrl@3001000 { + compatible = "sophgo,cv1812h-pinctrl"; + reg = <0x03001000 0x1000>, + <0x05027000 0x1000>; + reg-names = "sys", "rtc"; + }; + }; }; &plic { diff --git a/arch/riscv/boot/dts/sophgo/cv181x.dtsi b/arch/riscv/boot/dts/sophgo/cv181x.dtsi new file mode 100644 index 00000000000000..5fd14dd1b14fca --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/cv181x.dtsi @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2024 Inochi Amaoto + */ + +#include +#include + +/ { + soc { + emmc: mmc@4300000 { + compatible = "sophgo,cv1800b-dwcmshc"; + reg = <0x4300000 0x1000>; + interrupts = <34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_AXI4_EMMC>, + <&clk CLK_EMMC>; + clock-names = "core", "bus"; + status = "disabled"; + }; + }; +}; diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi index b724fb6d9689ef..c18822ec849f35 100644 --- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi @@ -133,6 +133,28 @@ portd: gpio-controller@0 { }; }; + saradc: adc@30f0000 { + compatible = "sophgo,cv1800b-saradc"; + reg = <0x030f0000 0x1000>; + clocks = <&clk CLK_SARADC>; + interrupts = <100 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + channel@0 { + reg = <0>; + }; + + channel@1 { + reg = <1>; + }; + + channel@2 { + reg = <2>; + }; + }; + i2c0: i2c@4000000 { compatible = "snps,designware-i2c"; reg = <0x04000000 0x10000>; @@ -297,6 +319,16 @@ sdhci0: mmc@4310000 { status = "disabled"; }; + sdhci1: mmc@4320000 { + compatible = "sophgo,cv1800b-dwcmshc"; + reg = <0x4320000 0x1000>; + interrupts = <38 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_AXI4_SD1>, + <&clk CLK_SD1>; + clock-names = "core", "bus"; + status = "disabled"; + }; + dmac: dma-controller@4330000 { compatible = "snps,axi-dma-1.01a"; reg = <0x04330000 0x1000>; diff --git a/arch/riscv/boot/dts/sophgo/sg2002-licheerv-nano-b.dts b/arch/riscv/boot/dts/sophgo/sg2002-licheerv-nano-b.dts new file mode 100644 index 00000000000000..86a712b953a5ac --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/sg2002-licheerv-nano-b.dts @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2024 Thomas Bonnefille + */ + +/dts-v1/; + +#include "sg2002.dtsi" + +/ { + model = "LicheeRV Nano B"; + compatible = "sipeed,licheerv-nano-b", "sipeed,licheerv-nano", "sophgo,sg2002"; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; +}; + +&osc { + clock-frequency = <25000000>; +}; + +&pinctrl { + uart0_cfg: uart0-cfg { + uart0-pins { + pinmux = , + ; + bias-pull-up; + drive-strength-microamp = <10800>; + power-source = <3300>; + }; + }; + + sdhci0_cfg: sdhci0-cfg { + sdhci0-clk-pins { + pinmux = ; + bias-pull-up; + drive-strength-microamp = <16100>; + power-source = <3300>; + }; + + sdhci0-cmd-pins { + pinmux = ; + bias-pull-up; + drive-strength-microamp = <10800>; + power-source = <3300>; + }; + + sdhci0-data-pins { + pinmux = , + , + , + ; + bias-pull-up; + drive-strength-microamp = <10800>; + power-source = <3300>; + }; + + sdhci0-cd-pins { + pinmux = ; + bias-pull-up; + drive-strength-microamp = <10800>; + power-source = <3300>; + }; + }; +}; + +&sdhci0 { + pinctrl-0 = <&sdhci0_cfg>; + pinctrl-names = "default"; + status = "okay"; + bus-width = <4>; + no-1-8-v; + no-mmc; + no-sdio; + disable-wp; +}; + +&uart0 { + pinctrl-0 = <&uart0_cfg>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/sophgo/sg2002.dtsi b/arch/riscv/boot/dts/sophgo/sg2002.dtsi new file mode 100644 index 00000000000000..7f79de33163c86 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/sg2002.dtsi @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2024 Thomas Bonnefille + */ + +#include +#include +#include "cv18xx.dtsi" +#include "cv181x.dtsi" + +/ { + compatible = "sophgo,sg2002"; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; + + soc { + pinctrl: pinctrl@3001000 { + compatible = "sophgo,sg2002-pinctrl"; + reg = <0x03001000 0x1000>, + <0x05027000 0x1000>; + reg-names = "sys", "rtc"; + }; + }; +}; + +&plic { + compatible = "sophgo,sg2002-plic", "thead,c900-plic"; +}; + +&clint { + compatible = "sophgo,sg2002-clint", "thead,c900-clint"; +}; + +&clk { + compatible = "sophgo,sg2000-clk"; +}; + +&sdhci0 { + compatible = "sophgo,sg2002-dwcmshc"; +}; diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts index a3f9d6f2256659..be596d01ff8d33 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts @@ -5,6 +5,9 @@ #include "sg2042.dtsi" +#include +#include + / { model = "Milk-V Pioneer"; compatible = "milkv,pioneer", "sophgo,sg2042"; @@ -12,6 +15,18 @@ / { chosen { stdout-path = "serial0"; }; + + gpio-power { + compatible = "gpio-keys"; + + key-power { + label = "Power Key"; + linux,code = ; + gpios = <&port0a 22 GPIO_ACTIVE_HIGH>; + linux,input-type = ; + debounce-interval = <100>; + }; + }; }; &cgi_main { diff --git a/arch/riscv/boot/dts/starfive/Makefile b/arch/riscv/boot/dts/starfive/Makefile index 7a163a7d6ba32d..b3bb12f78e7d5e 100644 --- a/arch/riscv/boot/dts/starfive/Makefile +++ b/arch/riscv/boot/dts/starfive/Makefile @@ -8,6 +8,7 @@ DTC_FLAGS_jh7110-starfive-visionfive-2-v1.3b := -@ dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-beaglev-starlight.dtb dtb-$(CONFIG_ARCH_STARFIVE) += jh7100-starfive-visionfive-v1.dtb +dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-deepcomputing-fml13v01.dtb dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-milkv-mars.dtb dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-pine64-star64.dtb dtb-$(CONFIG_ARCH_STARFIVE) += jh7110-starfive-visionfive-2-v1.2a.dtb diff --git a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi index d6c55f1cc96a92..48fb5091b81766 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi @@ -174,7 +174,6 @@ csi2rx_to_camss: endpoint { &gmac0 { phy-handle = <&phy0>; phy-mode = "rgmii-id"; - status = "okay"; mdio { #address-cells = <1>; @@ -194,7 +193,6 @@ &i2c0 { i2c-scl-falling-time-ns = <510>; pinctrl-names = "default"; pinctrl-0 = <&i2c0_pins>; - status = "okay"; }; &i2c2 { @@ -309,7 +307,6 @@ &pcie1 { &pwmdac { pinctrl-names = "default"; pinctrl-0 = <&pwmdac_pins>; - status = "okay"; }; &qspi { @@ -348,13 +345,11 @@ uboot@100000 { &pwm { pinctrl-names = "default"; pinctrl-0 = <&pwm_pins>; - status = "okay"; }; &spi0 { pinctrl-names = "default"; pinctrl-0 = <&spi0_pins>; - status = "okay"; spi_dev0: spi@0 { compatible = "rohm,dh2228fv"; @@ -640,11 +635,6 @@ &uart0 { status = "okay"; }; -&usb0 { - dr_mode = "peripheral"; - status = "okay"; -}; - &U74_1 { cpu-supply = <&vdd_cpu>; }; diff --git a/arch/riscv/boot/dts/starfive/jh7110-deepcomputing-fml13v01.dts b/arch/riscv/boot/dts/starfive/jh7110-deepcomputing-fml13v01.dts new file mode 100644 index 00000000000000..30b0715196b666 --- /dev/null +++ b/arch/riscv/boot/dts/starfive/jh7110-deepcomputing-fml13v01.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * Copyright (C) 2024 DeepComputing (HK) Limited + */ + +/dts-v1/; +#include "jh7110-common.dtsi" + +/ { + model = "DeepComputing FML13V01"; + compatible = "deepcomputing,fml13v01", "starfive,jh7110"; +}; + +&usb0 { + dr_mode = "host"; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts b/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts index 5cb9e99e1dacd5..0d248b671d4bbe 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts +++ b/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts @@ -15,6 +15,11 @@ &gmac0 { starfive,tx-use-rgmii-clk; assigned-clocks = <&aoncrg JH7110_AONCLK_GMAC0_TX>; assigned-clock-parents = <&aoncrg JH7110_AONCLK_GMAC0_RMII_RTX>; + status = "okay"; +}; + +&i2c0 { + status = "okay"; }; &pcie0 { @@ -35,3 +40,20 @@ &phy0 { rx-internal-delay-ps = <1500>; tx-internal-delay-ps = <1500>; }; + +&pwm { + status = "okay"; +}; + +&pwmdac { + status = "okay"; +}; + +&spi0 { + status = "okay"; +}; + +&usb0 { + dr_mode = "peripheral"; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts b/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts index 8e39fdc73ecb81..fe4a490ecc6113 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts +++ b/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts @@ -18,6 +18,7 @@ &gmac0 { starfive,tx-use-rgmii-clk; assigned-clocks = <&aoncrg JH7110_AONCLK_GMAC0_TX>; assigned-clock-parents = <&aoncrg JH7110_AONCLK_GMAC0_RMII_RTX>; + status = "okay"; }; &gmac1 { @@ -39,6 +40,10 @@ phy1: ethernet-phy@1 { }; }; +&i2c0 { + status = "okay"; +}; + &pcie1 { status = "okay"; }; @@ -62,3 +67,20 @@ &phy1 { motorcomm,tx-clk-10-inverted; motorcomm,tx-clk-100-inverted; }; + +&pwm { + status = "okay"; +}; + +&pwmdac { + status = "okay"; +}; + +&spi0 { + status = "okay"; +}; + +&usb0 { + dr_mode = "peripheral"; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi index 18f38fc790a4d1..5f14afb2c24dcf 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi @@ -13,6 +13,10 @@ aliases { }; }; +&gmac0 { + status = "okay"; +}; + &gmac1 { phy-handle = <&phy1>; phy-mode = "rgmii-id"; @@ -29,6 +33,10 @@ phy1: ethernet-phy@1 { }; }; +&i2c0 { + status = "okay"; +}; + &mmc0 { non-removable; }; @@ -40,3 +48,20 @@ &pcie0 { &pcie1 { status = "okay"; }; + +&pwm { + status = "okay"; +}; + +&pwmdac { + status = "okay"; +}; + +&spi0 { + status = "okay"; +}; + +&usb0 { + dr_mode = "peripheral"; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts index 497d961456f3a1..21c33f165ba91b 100644 --- a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts +++ b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts @@ -7,16 +7,21 @@ /dts-v1/; #include "th1520.dtsi" +#include +#include / { model = "BeagleV Ahead"; compatible = "beagle,beaglev-ahead", "thead,th1520"; aliases { + ethernet0 = &gmac0; gpio0 = &gpio0; gpio1 = &gpio1; gpio2 = &gpio2; gpio3 = &gpio3; + gpio4 = &gpio4; + gpio5 = &aogpio; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -33,7 +38,42 @@ chosen { memory@0 { device_type = "memory"; reg = <0x0 0x00000000 0x1 0x00000000>; + }; + + leds { + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + compatible = "gpio-leds"; + + led-1 { + gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; + color = ; + label = "led1"; + }; + + led-2 { + gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>; + color = ; + label = "led2"; + }; + led-3 { + gpios = <&gpio4 10 GPIO_ACTIVE_HIGH>; + color = ; + label = "led3"; + }; + + led-4 { + gpios = <&gpio4 11 GPIO_ACTIVE_HIGH>; + color = ; + label = "led4"; + }; + + led-5 { + gpios = <&gpio4 12 GPIO_ACTIVE_HIGH>; + color = ; + label = "led5"; + }; }; }; @@ -59,6 +99,137 @@ &emmc { status = "okay"; }; +&gmac0 { + pinctrl-names = "default"; + pinctrl-0 = <&gmac0_pins>; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + +&mdio0 { + phy0: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&gpio3>; + interrupts = <22 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio3 21 GPIO_ACTIVE_LOW>; + reset-delay-us = <10000>; + reset-post-delay-us = <50000>; + }; +}; + +&padctrl_aosys { + led_pins: led-0 { + led-pins { + pins = "AUDIO_PA8", /* GPIO4_8 */ + "AUDIO_PA9", /* GPIO4_9 */ + "AUDIO_PA10", /* GPIO4_10 */ + "AUDIO_PA11", /* GPIO4_11 */ + "AUDIO_PA12"; /* GPIO4_12 */ + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; +}; + +&padctrl0_apsys { + gmac0_pins: gmac0-0 { + tx-pins { + pins = "GMAC0_TX_CLK", + "GMAC0_TXEN", + "GMAC0_TXD0", + "GMAC0_TXD1", + "GMAC0_TXD2", + "GMAC0_TXD3"; + function = "gmac0"; + bias-disable; + drive-strength = <25>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GMAC0_RX_CLK", + "GMAC0_RXDV", + "GMAC0_RXD0", + "GMAC0_RXD1", + "GMAC0_RXD2", + "GMAC0_RXD3"; + function = "gmac0"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-disable; + slew-rate = <0>; + }; + + mdc-pins { + pins = "GMAC0_MDC"; + function = "gmac0"; + bias-disable; + drive-strength = <13>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + mdio-pins { + pins = "GMAC0_MDIO"; + function = "gmac0"; + bias-disable; + drive-strength = <13>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + + phy-reset-pins { + pins = "GMAC0_COL"; /* GPIO3_21 */ + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + phy-interrupt-pins { + pins = "GMAC0_CRS"; /* GPIO3_22 */ + function = "gpio"; + bias-pull-up; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; + + uart0_pins: uart0-0 { + tx-pins { + pins = "UART0_TXD"; + function = "uart"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "UART0_RXD"; + function = "uart"; + bias-pull-up; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; +}; + &sdio0 { bus-width = <4>; max-frequency = <198000000>; @@ -66,9 +237,7 @@ &sdio0 { }; &uart0 { - status = "okay"; -}; - -&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; status = "okay"; }; diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi index 78977bdbbe3d31..8e76b63e0100aa 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi @@ -11,6 +11,11 @@ / { model = "Sipeed Lichee Module 4A"; compatible = "sipeed,lichee-module-4a", "thead,th1520"; + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + }; + memory@0 { device_type = "memory"; reg = <0x0 0x00000000 0x2 0x00000000>; @@ -25,6 +30,12 @@ &osc_32k { clock-frequency = <32768>; }; +&aogpio { + gpio-line-names = "", "", "", + "GPIO00", + "GPIO04"; +}; + &dmac0 { status = "okay"; }; @@ -39,6 +50,153 @@ &emmc { status = "okay"; }; +&gmac0 { + pinctrl-names = "default"; + pinctrl-0 = <&gmac0_pins>, <&mdio0_pins>; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + +&gmac1 { + pinctrl-names = "default"; + pinctrl-0 = <&gmac1_pins>; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + +&gpio0 { + gpio-line-names = "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", + "GPIO07", + "GPIO08", + "", + "GPIO01", + "GPIO02"; +}; + +&gpio1 { + gpio-line-names = "", "", "", + "GPIO11", + "GPIO12", + "GPIO13", + "GPIO14", + "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", + "GPIO06"; +}; + +&gpio2 { + gpio-line-names = "GPIO03", + "GPIO05"; +}; + +&gpio3 { + gpio-line-names = "", "", + "GPIO09", + "GPIO10"; +}; + +&mdio0 { + phy0: ethernet-phy@1 { + reg = <1>; + }; + + phy1: ethernet-phy@2 { + reg = <2>; + }; +}; + +&padctrl0_apsys { + gmac0_pins: gmac0-0 { + tx-pins { + pins = "GMAC0_TX_CLK", + "GMAC0_TXEN", + "GMAC0_TXD0", + "GMAC0_TXD1", + "GMAC0_TXD2", + "GMAC0_TXD3"; + function = "gmac0"; + bias-disable; + drive-strength = <25>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GMAC0_RX_CLK", + "GMAC0_RXDV", + "GMAC0_RXD0", + "GMAC0_RXD1", + "GMAC0_RXD2", + "GMAC0_RXD3"; + function = "gmac0"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + + gmac1_pins: gmac1-0 { + tx-pins { + pins = "GPIO2_18", /* GMAC1_TX_CLK */ + "GPIO2_20", /* GMAC1_TXEN */ + "GPIO2_21", /* GMAC1_TXD0 */ + "GPIO2_22", /* GMAC1_TXD1 */ + "GPIO2_23", /* GMAC1_TXD2 */ + "GPIO2_24"; /* GMAC1_TXD3 */ + function = "gmac1"; + bias-disable; + drive-strength = <25>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "GPIO2_19", /* GMAC1_RX_CLK */ + "GPIO2_25", /* GMAC1_RXDV */ + "GPIO2_30", /* GMAC1_RXD0 */ + "GPIO2_31", /* GMAC1_RXD1 */ + "GPIO3_0", /* GMAC1_RXD2 */ + "GPIO3_1"; /* GMAC1_RXD3 */ + function = "gmac1"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-disable; + slew-rate = <0>; + }; + }; + + mdio0_pins: mdio0-0 { + mdc-pins { + pins = "GMAC0_MDC"; + function = "gmac0"; + bias-disable; + drive-strength = <13>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + mdio-pins { + pins = "GMAC0_MDIO"; + function = "gmac0"; + bias-disable; + drive-strength = <13>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; +}; + &sdio0 { bus-width = <4>; max-frequency = <198000000>; diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts index 7738d2895c5acc..4020c727f09e8e 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts +++ b/arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts @@ -14,6 +14,8 @@ aliases { gpio1 = &gpio1; gpio2 = &gpio2; gpio3 = &gpio3; + gpio4 = &gpio4; + gpio5 = &aogpio; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -28,10 +30,32 @@ chosen { }; }; -&uart0 { - status = "okay"; +&padctrl0_apsys { + uart0_pins: uart0-0 { + tx-pins { + pins = "UART0_TXD"; + function = "uart"; + bias-disable; + drive-strength = <3>; + input-disable; + input-schmitt-disable; + slew-rate = <0>; + }; + + rx-pins { + pins = "UART0_RXD"; + function = "uart"; + bias-disable; + drive-strength = <1>; + input-enable; + input-schmitt-enable; + slew-rate = <0>; + }; + }; }; -&spi0 { +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; status = "okay"; }; diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index 6992060e6a54d2..acfe030e803a00 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -216,6 +216,19 @@ osc_32k: 32k-oscillator { #clock-cells = <0>; }; + aonsys_clk: clock-73728000 { + compatible = "fixed-clock"; + clock-frequency = <73728000>; + clock-output-names = "aonsys_clk"; + #clock-cells = <0>; + }; + + stmmac_axi_config: stmmac-axi-config { + snps,wr_osr_lmt = <15>; + snps,rd_osr_lmt = <15>; + snps,blen = <0 0 64 32 0 0 0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&plic>; @@ -267,6 +280,50 @@ uart0: serial@ffe7014000 { status = "disabled"; }; + gmac1: ethernet@ffe7060000 { + compatible = "thead,th1520-gmac", "snps,dwmac-3.70a"; + reg = <0xff 0xe7060000 0x0 0x2000>, <0xff 0xec004000 0x0 0x1000>; + reg-names = "dwmac", "apb"; + interrupts = <67 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + clocks = <&clk CLK_GMAC_AXI>, <&clk CLK_GMAC1>; + clock-names = "stmmaceth", "pclk"; + snps,pbl = <32>; + snps,fixed-burst; + snps,multicast-filter-bins = <64>; + snps,perfect-filter-entries = <32>; + snps,axi-config = <&stmmac_axi_config>; + status = "disabled"; + + mdio1: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + gmac0: ethernet@ffe7070000 { + compatible = "thead,th1520-gmac", "snps,dwmac-3.70a"; + reg = <0xff 0xe7070000 0x0 0x2000>, <0xff 0xec003000 0x0 0x1000>; + reg-names = "dwmac", "apb"; + interrupts = <66 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + clocks = <&clk CLK_GMAC_AXI>, <&clk CLK_GMAC0>; + clock-names = "stmmaceth", "pclk"; + snps,pbl = <32>; + snps,fixed-burst; + snps,multicast-filter-bins = <64>; + snps,perfect-filter-entries = <32>; + snps,axi-config = <&stmmac_axi_config>; + status = "disabled"; + + mdio0: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + emmc: mmc@ffe7080000 { compatible = "thead,th1520-dwcmshc"; reg = <0xff 0xe7080000 0x0 0x10000>; @@ -316,18 +373,20 @@ uart3: serial@ffe7f04000 { status = "disabled"; }; - gpio2: gpio@ffe7f34000 { + gpio@ffe7f34000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xe7f34000 0x0 0x1000>; #address-cells = <1>; #size-cells = <0>; clocks = <&clk CLK_GPIO2>; + clock-names = "bus"; - portc: gpio-controller@0 { + gpio2: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; ngpios = <32>; + gpio-ranges = <&padctrl0_apsys 0 0 32>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; @@ -335,18 +394,20 @@ portc: gpio-controller@0 { }; }; - gpio3: gpio@ffe7f38000 { + gpio@ffe7f38000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xe7f38000 0x0 0x1000>; #address-cells = <1>; #size-cells = <0>; clocks = <&clk CLK_GPIO3>; + clock-names = "bus"; - portd: gpio-controller@0 { + gpio3: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - ngpios = <32>; + ngpios = <23>; + gpio-ranges = <&padctrl0_apsys 0 32 23>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; @@ -354,18 +415,27 @@ portd: gpio-controller@0 { }; }; - gpio0: gpio@ffec005000 { + padctrl1_apsys: pinctrl@ffe7f3c000 { + compatible = "thead,th1520-pinctrl"; + reg = <0xff 0xe7f3c000 0x0 0x1000>; + clocks = <&clk CLK_PADCTRL1>; + thead,pad-group = <2>; + }; + + gpio@ffec005000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xec005000 0x0 0x1000>; #address-cells = <1>; #size-cells = <0>; clocks = <&clk CLK_GPIO0>; + clock-names = "bus"; - porta: gpio-controller@0 { + gpio0: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; ngpios = <32>; + gpio-ranges = <&padctrl1_apsys 0 0 32>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; @@ -373,18 +443,20 @@ porta: gpio-controller@0 { }; }; - gpio1: gpio@ffec006000 { + gpio@ffec006000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xec006000 0x0 0x1000>; #address-cells = <1>; #size-cells = <0>; clocks = <&clk CLK_GPIO1>; + clock-names = "bus"; - portb: gpio-controller@0 { + gpio1: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - ngpios = <32>; + ngpios = <31>; + gpio-ranges = <&padctrl1_apsys 0 32 31>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; @@ -392,6 +464,13 @@ portb: gpio-controller@0 { }; }; + padctrl0_apsys: pinctrl@ffec007000 { + compatible = "thead,th1520-pinctrl"; + reg = <0xff 0xec007000 0x0 0x1000>; + clocks = <&clk CLK_PADCTRL0>; + thead,pad-group = <3>; + }; + uart2: serial@ffec010000 { compatible = "snps,dw-apb-uart"; reg = <0xff 0xec010000 0x0 0x4000>; @@ -520,17 +599,18 @@ timer7: timer@ffffc3303c { status = "disabled"; }; - ao_gpio0: gpio@fffff41000 { + gpio@fffff41000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xfff41000 0x0 0x1000>; #address-cells = <1>; #size-cells = <0>; - porte: gpio-controller@0 { + aogpio: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - ngpios = <32>; + ngpios = <16>; + gpio-ranges = <&padctrl_aosys 0 9 16>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; @@ -538,17 +618,25 @@ porte: gpio-controller@0 { }; }; - ao_gpio1: gpio@fffff52000 { + padctrl_aosys: pinctrl@fffff4a000 { + compatible = "thead,th1520-pinctrl"; + reg = <0xff 0xfff4a000 0x0 0x2000>; + clocks = <&aonsys_clk>; + thead,pad-group = <1>; + }; + + gpio@fffff52000 { compatible = "snps,dw-apb-gpio"; reg = <0xff 0xfff52000 0x0 0x1000>; #address-cells = <1>; #size-cells = <0>; - portf: gpio-controller@0 { + gpio4: gpio-controller@0 { compatible = "snps,dw-apb-gpio-port"; gpio-controller; #gpio-cells = <2>; - ngpios = <32>; + ngpios = <23>; + gpio-ranges = <&padctrl_aosys 0 25 22>, <&padctrl_aosys 22 7 1>; reg = <0>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index 2341393cfac1ae..b4a37345703eb3 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -167,6 +167,7 @@ CONFIG_PINCTRL_SOPHGO_CV1800B=y CONFIG_PINCTRL_SOPHGO_CV1812H=y CONFIG_PINCTRL_SOPHGO_SG2000=y CONFIG_PINCTRL_SOPHGO_SG2002=y +CONFIG_GPIO_DWAPB=y CONFIG_GPIO_SIFIVE=y CONFIG_POWER_RESET_GPIO_RESTART=y CONFIG_SENSORS_SFCTEMP=m @@ -256,6 +257,7 @@ CONFIG_RPMSG_CTRL=y CONFIG_RPMSG_VIRTIO=y CONFIG_PM_DEVFREQ=y CONFIG_IIO=y +CONFIG_THEAD_C900_ACLINT_SSWI=y CONFIG_PHY_SUN4I_USB=m CONFIG_PHY_STARFIVE_JH7110_DPHY_RX=m CONFIG_PHY_STARFIVE_JH7110_PCIE=m @@ -301,7 +303,6 @@ CONFIG_DEBUG_MEMORY_INIT=y CONFIG_DEBUG_PER_CPU_MAPS=y CONFIG_SOFTLOCKUP_DETECTOR=y CONFIG_WQ_WATCHDOG=y -CONFIG_DEBUG_TIMEKEEPING=y CONFIG_DEBUG_RT_MUTEXES=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y diff --git a/arch/riscv/errata/andes/errata.c b/arch/riscv/errata/andes/errata.c index fc1a34faa5f3bc..dcc9d1ee5ffd30 100644 --- a/arch/riscv/errata/andes/errata.c +++ b/arch/riscv/errata/andes/errata.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/riscv/errata/sifive/errata.c b/arch/riscv/errata/sifive/errata.c index cea3b96ade11a6..38aac2c47845a0 100644 --- a/arch/riscv/errata/sifive/errata.c +++ b/arch/riscv/errata/sifive/errata.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c index f5120e07c31826..e24770a779323f 100644 --- a/arch/riscv/errata/thead/errata.c +++ b/arch/riscv/errata/thead/errata.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild index 1461af12da6e2b..de13d5a234f882 100644 --- a/arch/riscv/include/asm/Kbuild +++ b/arch/riscv/include/asm/Kbuild @@ -6,10 +6,12 @@ generic-y += early_ioremap.h generic-y += flat.h generic-y += kvm_para.h generic-y += mmzone.h +generic-y += mcs_spinlock.h generic-y += parport.h -generic-y += spinlock.h generic-y += spinlock_types.h +generic-y += ticket_spinlock.h generic-y += qrwlock.h generic-y += qrwlock_types.h +generic-y += qspinlock.h generic-y += user.h generic-y += vmlinux.lds.h diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index ebbce134917ccd..4cadc56220feac 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h @@ -12,30 +12,43 @@ #include #include #include - -#define __arch_xchg_masked(sc_sfx, prepend, append, r, p, n) \ -({ \ - u32 *__ptr32b = (u32 *)((ulong)(p) & ~0x3); \ - ulong __s = ((ulong)(p) & (0x4 - sizeof(*p))) * BITS_PER_BYTE; \ - ulong __mask = GENMASK(((sizeof(*p)) * BITS_PER_BYTE) - 1, 0) \ - << __s; \ - ulong __newx = (ulong)(n) << __s; \ - ulong __retx; \ - ulong __rc; \ - \ - __asm__ __volatile__ ( \ - prepend \ - "0: lr.w %0, %2\n" \ - " and %1, %0, %z4\n" \ - " or %1, %1, %z3\n" \ - " sc.w" sc_sfx " %1, %1, %2\n" \ - " bnez %1, 0b\n" \ - append \ - : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \ - : "rJ" (__newx), "rJ" (~__mask) \ - : "memory"); \ - \ - r = (__typeof__(*(p)))((__retx & __mask) >> __s); \ +#include + +#define __arch_xchg_masked(sc_sfx, swap_sfx, prepend, sc_append, \ + swap_append, r, p, n) \ +({ \ + if (IS_ENABLED(CONFIG_RISCV_ISA_ZABHA) && \ + riscv_has_extension_unlikely(RISCV_ISA_EXT_ZABHA)) { \ + __asm__ __volatile__ ( \ + prepend \ + " amoswap" swap_sfx " %0, %z2, %1\n" \ + swap_append \ + : "=&r" (r), "+A" (*(p)) \ + : "rJ" (n) \ + : "memory"); \ + } else { \ + u32 *__ptr32b = (u32 *)((ulong)(p) & ~0x3); \ + ulong __s = ((ulong)(p) & (0x4 - sizeof(*p))) * BITS_PER_BYTE; \ + ulong __mask = GENMASK(((sizeof(*p)) * BITS_PER_BYTE) - 1, 0) \ + << __s; \ + ulong __newx = (ulong)(n) << __s; \ + ulong __retx; \ + ulong __rc; \ + \ + __asm__ __volatile__ ( \ + prepend \ + "0: lr.w %0, %2\n" \ + " and %1, %0, %z4\n" \ + " or %1, %1, %z3\n" \ + " sc.w" sc_sfx " %1, %1, %2\n" \ + " bnez %1, 0b\n" \ + sc_append \ + : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \ + : "rJ" (__newx), "rJ" (~__mask) \ + : "memory"); \ + \ + r = (__typeof__(*(p)))((__retx & __mask) >> __s); \ + } \ }) #define __arch_xchg(sfx, prepend, append, r, p, n) \ @@ -58,8 +71,13 @@ \ switch (sizeof(*__ptr)) { \ case 1: \ + __arch_xchg_masked(sc_sfx, ".b" swap_sfx, \ + prepend, sc_append, swap_append, \ + __ret, __ptr, __new); \ + break; \ case 2: \ - __arch_xchg_masked(sc_sfx, prepend, sc_append, \ + __arch_xchg_masked(sc_sfx, ".h" swap_sfx, \ + prepend, sc_append, swap_append, \ __ret, __ptr, __new); \ break; \ case 4: \ @@ -106,55 +124,90 @@ * store NEW in MEM. Return the initial value in MEM. Success is * indicated by comparing RETURN with OLD. */ - -#define __arch_cmpxchg_masked(sc_sfx, prepend, append, r, p, o, n) \ -({ \ - u32 *__ptr32b = (u32 *)((ulong)(p) & ~0x3); \ - ulong __s = ((ulong)(p) & (0x4 - sizeof(*p))) * BITS_PER_BYTE; \ - ulong __mask = GENMASK(((sizeof(*p)) * BITS_PER_BYTE) - 1, 0) \ - << __s; \ - ulong __newx = (ulong)(n) << __s; \ - ulong __oldx = (ulong)(o) << __s; \ - ulong __retx; \ - ulong __rc; \ - \ - __asm__ __volatile__ ( \ - prepend \ - "0: lr.w %0, %2\n" \ - " and %1, %0, %z5\n" \ - " bne %1, %z3, 1f\n" \ - " and %1, %0, %z6\n" \ - " or %1, %1, %z4\n" \ - " sc.w" sc_sfx " %1, %1, %2\n" \ - " bnez %1, 0b\n" \ - append \ - "1:\n" \ - : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \ - : "rJ" ((long)__oldx), "rJ" (__newx), \ - "rJ" (__mask), "rJ" (~__mask) \ - : "memory"); \ - \ - r = (__typeof__(*(p)))((__retx & __mask) >> __s); \ +#define __arch_cmpxchg_masked(sc_sfx, cas_sfx, \ + sc_prepend, sc_append, \ + cas_prepend, cas_append, \ + r, p, o, n) \ +({ \ + if (IS_ENABLED(CONFIG_RISCV_ISA_ZABHA) && \ + IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) && \ + riscv_has_extension_unlikely(RISCV_ISA_EXT_ZABHA) && \ + riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)) { \ + r = o; \ + \ + __asm__ __volatile__ ( \ + cas_prepend \ + " amocas" cas_sfx " %0, %z2, %1\n" \ + cas_append \ + : "+&r" (r), "+A" (*(p)) \ + : "rJ" (n) \ + : "memory"); \ + } else { \ + u32 *__ptr32b = (u32 *)((ulong)(p) & ~0x3); \ + ulong __s = ((ulong)(p) & (0x4 - sizeof(*p))) * BITS_PER_BYTE; \ + ulong __mask = GENMASK(((sizeof(*p)) * BITS_PER_BYTE) - 1, 0) \ + << __s; \ + ulong __newx = (ulong)(n) << __s; \ + ulong __oldx = (ulong)(o) << __s; \ + ulong __retx; \ + ulong __rc; \ + \ + __asm__ __volatile__ ( \ + sc_prepend \ + "0: lr.w %0, %2\n" \ + " and %1, %0, %z5\n" \ + " bne %1, %z3, 1f\n" \ + " and %1, %0, %z6\n" \ + " or %1, %1, %z4\n" \ + " sc.w" sc_sfx " %1, %1, %2\n" \ + " bnez %1, 0b\n" \ + sc_append \ + "1:\n" \ + : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \ + : "rJ" ((long)__oldx), "rJ" (__newx), \ + "rJ" (__mask), "rJ" (~__mask) \ + : "memory"); \ + \ + r = (__typeof__(*(p)))((__retx & __mask) >> __s); \ + } \ }) -#define __arch_cmpxchg(lr_sfx, sc_sfx, prepend, append, r, p, co, o, n) \ +#define __arch_cmpxchg(lr_sfx, sc_sfx, cas_sfx, \ + sc_prepend, sc_append, \ + cas_prepend, cas_append, \ + r, p, co, o, n) \ ({ \ - register unsigned int __rc; \ + if (IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) && \ + riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS)) { \ + r = o; \ \ - __asm__ __volatile__ ( \ - prepend \ - "0: lr" lr_sfx " %0, %2\n" \ - " bne %0, %z3, 1f\n" \ - " sc" sc_sfx " %1, %z4, %2\n" \ - " bnez %1, 0b\n" \ - append \ - "1:\n" \ - : "=&r" (r), "=&r" (__rc), "+A" (*(p)) \ - : "rJ" (co o), "rJ" (n) \ - : "memory"); \ + __asm__ __volatile__ ( \ + cas_prepend \ + " amocas" cas_sfx " %0, %z2, %1\n" \ + cas_append \ + : "+&r" (r), "+A" (*(p)) \ + : "rJ" (n) \ + : "memory"); \ + } else { \ + register unsigned int __rc; \ + \ + __asm__ __volatile__ ( \ + sc_prepend \ + "0: lr" lr_sfx " %0, %2\n" \ + " bne %0, %z3, 1f\n" \ + " sc" sc_sfx " %1, %z4, %2\n" \ + " bnez %1, 0b\n" \ + sc_append \ + "1:\n" \ + : "=&r" (r), "=&r" (__rc), "+A" (*(p)) \ + : "rJ" (co o), "rJ" (n) \ + : "memory"); \ + } \ }) -#define _arch_cmpxchg(ptr, old, new, sc_sfx, prepend, append) \ +#define _arch_cmpxchg(ptr, old, new, sc_sfx, cas_sfx, \ + sc_prepend, sc_append, \ + cas_prepend, cas_append) \ ({ \ __typeof__(ptr) __ptr = (ptr); \ __typeof__(*(__ptr)) __old = (old); \ @@ -163,17 +216,28 @@ \ switch (sizeof(*__ptr)) { \ case 1: \ + __arch_cmpxchg_masked(sc_sfx, ".b" cas_sfx, \ + sc_prepend, sc_append, \ + cas_prepend, cas_append, \ + __ret, __ptr, __old, __new); \ + break; \ case 2: \ - __arch_cmpxchg_masked(sc_sfx, prepend, append, \ - __ret, __ptr, __old, __new); \ + __arch_cmpxchg_masked(sc_sfx, ".h" cas_sfx, \ + sc_prepend, sc_append, \ + cas_prepend, cas_append, \ + __ret, __ptr, __old, __new); \ break; \ case 4: \ - __arch_cmpxchg(".w", ".w" sc_sfx, prepend, append, \ - __ret, __ptr, (long), __old, __new); \ + __arch_cmpxchg(".w", ".w" sc_sfx, ".w" cas_sfx, \ + sc_prepend, sc_append, \ + cas_prepend, cas_append, \ + __ret, __ptr, (long), __old, __new); \ break; \ case 8: \ - __arch_cmpxchg(".d", ".d" sc_sfx, prepend, append, \ - __ret, __ptr, /**/, __old, __new); \ + __arch_cmpxchg(".d", ".d" sc_sfx, ".d" cas_sfx, \ + sc_prepend, sc_append, \ + cas_prepend, cas_append, \ + __ret, __ptr, /**/, __old, __new); \ break; \ default: \ BUILD_BUG(); \ @@ -181,17 +245,40 @@ (__typeof__(*(__ptr)))__ret; \ }) +/* + * These macros are here to improve the readability of the arch_cmpxchg_XXX() + * macros. + */ +#define SC_SFX(x) x +#define CAS_SFX(x) x +#define SC_PREPEND(x) x +#define SC_APPEND(x) x +#define CAS_PREPEND(x) x +#define CAS_APPEND(x) x + #define arch_cmpxchg_relaxed(ptr, o, n) \ - _arch_cmpxchg((ptr), (o), (n), "", "", "") + _arch_cmpxchg((ptr), (o), (n), \ + SC_SFX(""), CAS_SFX(""), \ + SC_PREPEND(""), SC_APPEND(""), \ + CAS_PREPEND(""), CAS_APPEND("")) #define arch_cmpxchg_acquire(ptr, o, n) \ - _arch_cmpxchg((ptr), (o), (n), "", "", RISCV_ACQUIRE_BARRIER) + _arch_cmpxchg((ptr), (o), (n), \ + SC_SFX(""), CAS_SFX(""), \ + SC_PREPEND(""), SC_APPEND(RISCV_ACQUIRE_BARRIER), \ + CAS_PREPEND(""), CAS_APPEND(RISCV_ACQUIRE_BARRIER)) #define arch_cmpxchg_release(ptr, o, n) \ - _arch_cmpxchg((ptr), (o), (n), "", RISCV_RELEASE_BARRIER, "") + _arch_cmpxchg((ptr), (o), (n), \ + SC_SFX(""), CAS_SFX(""), \ + SC_PREPEND(RISCV_RELEASE_BARRIER), SC_APPEND(""), \ + CAS_PREPEND(RISCV_RELEASE_BARRIER), CAS_APPEND("")) #define arch_cmpxchg(ptr, o, n) \ - _arch_cmpxchg((ptr), (o), (n), ".rl", "", " fence rw, rw\n") + _arch_cmpxchg((ptr), (o), (n), \ + SC_SFX(".rl"), CAS_SFX(".aqrl"), \ + SC_PREPEND(""), SC_APPEND(RISCV_FULL_BARRIER), \ + CAS_PREPEND(""), CAS_APPEND("")) #define arch_cmpxchg_local(ptr, o, n) \ arch_cmpxchg_relaxed((ptr), (o), (n)) @@ -226,6 +313,44 @@ arch_cmpxchg_release((ptr), (o), (n)); \ }) +#if defined(CONFIG_64BIT) && defined(CONFIG_RISCV_ISA_ZACAS) + +#define system_has_cmpxchg128() riscv_has_extension_unlikely(RISCV_ISA_EXT_ZACAS) + +union __u128_halves { + u128 full; + struct { + u64 low, high; + }; +}; + +#define __arch_cmpxchg128(p, o, n, cas_sfx) \ +({ \ + __typeof__(*(p)) __o = (o); \ + union __u128_halves __hn = { .full = (n) }; \ + union __u128_halves __ho = { .full = (__o) }; \ + register unsigned long t1 asm ("t1") = __hn.low; \ + register unsigned long t2 asm ("t2") = __hn.high; \ + register unsigned long t3 asm ("t3") = __ho.low; \ + register unsigned long t4 asm ("t4") = __ho.high; \ + \ + __asm__ __volatile__ ( \ + " amocas.q" cas_sfx " %0, %z3, %2" \ + : "+&r" (t3), "+&r" (t4), "+A" (*(p)) \ + : "rJ" (t1), "rJ" (t2) \ + : "memory"); \ + \ + ((u128)t4 << 64) | t3; \ +}) + +#define arch_cmpxchg128(ptr, o, n) \ + __arch_cmpxchg128((ptr), (o), (n), ".aqrl") + +#define arch_cmpxchg128_local(ptr, o, n) \ + __arch_cmpxchg128((ptr), (o), (n), "") + +#endif /* CONFIG_64BIT && CONFIG_RISCV_ISA_ZACAS */ + #ifdef CONFIG_RISCV_ISA_ZAWRS /* * Despite wrs.nto being "WRS-with-no-timeout", in the absence of changes to @@ -245,6 +370,11 @@ static __always_inline void __cmpwait(volatile void *ptr, : : : : no_zawrs); switch (size) { + case 1: + fallthrough; + case 2: + /* RISC-V doesn't have lr instructions on byte and half-word. */ + goto no_zawrs; case 4: asm volatile( " lr.w %0, %1\n" diff --git a/arch/riscv/include/asm/compat.h b/arch/riscv/include/asm/compat.h index aa103530a5c83a..6081327e55f5b6 100644 --- a/arch/riscv/include/asm/compat.h +++ b/arch/riscv/include/asm/compat.h @@ -9,7 +9,6 @@ */ #include #include -#include #include static inline int is_compat_task(void) diff --git a/arch/riscv/include/asm/cpufeature-macros.h b/arch/riscv/include/asm/cpufeature-macros.h new file mode 100644 index 00000000000000..a8103edbf51f82 --- /dev/null +++ b/arch/riscv/include/asm/cpufeature-macros.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2022-2024 Rivos, Inc + */ + +#ifndef _ASM_CPUFEATURE_MACROS_H +#define _ASM_CPUFEATURE_MACROS_H + +#include +#include + +#define STANDARD_EXT 0 + +bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit); +#define riscv_isa_extension_available(isa_bitmap, ext) \ + __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext) + +static __always_inline bool __riscv_has_extension_likely(const unsigned long vendor, + const unsigned long ext) +{ + asm goto(ALTERNATIVE("j %l[l_no]", "nop", %[vendor], %[ext], 1) + : + : [vendor] "i" (vendor), [ext] "i" (ext) + : + : l_no); + + return true; +l_no: + return false; +} + +static __always_inline bool __riscv_has_extension_unlikely(const unsigned long vendor, + const unsigned long ext) +{ + asm goto(ALTERNATIVE("nop", "j %l[l_yes]", %[vendor], %[ext], 1) + : + : [vendor] "i" (vendor), [ext] "i" (ext) + : + : l_yes); + + return false; +l_yes: + return true; +} + +static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext) +{ + compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); + + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) + return __riscv_has_extension_unlikely(STANDARD_EXT, ext); + + return __riscv_isa_extension_available(NULL, ext); +} + +static __always_inline bool riscv_has_extension_likely(const unsigned long ext) +{ + compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); + + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) + return __riscv_has_extension_likely(STANDARD_EXT, ext); + + return __riscv_isa_extension_available(NULL, ext); +} + +#endif /* _ASM_CPUFEATURE_MACROS_H */ diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index 45f9c1171a486a..4bd054c54c21a3 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -8,9 +8,12 @@ #include #include +#include +#include +#include +#include #include -#include -#include +#include /* * These are probed via a device_initcall(), via either the SBI or directly @@ -31,7 +34,7 @@ DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo); /* Per-cpu ISA extensions. */ extern struct riscv_isainfo hart_isa[NR_CPUS]; -void riscv_user_isa_enable(void); +void __init riscv_user_isa_enable(void); #define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \ .name = #_name, \ @@ -58,8 +61,9 @@ void riscv_user_isa_enable(void); #define __RISCV_ISA_EXT_SUPERSET_VALIDATE(_name, _id, _sub_exts, _validate) \ _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate) -#if defined(CONFIG_RISCV_MISALIGNED) bool check_unaligned_access_emulated_all_cpus(void); +#if defined(CONFIG_RISCV_SCALAR_MISALIGNED) +void check_unaligned_access_emulated(struct work_struct *work __always_unused); void unaligned_emulation_finish(void); bool unaligned_ctl_available(void); DECLARE_PER_CPU(long, misaligned_access_speed); @@ -70,6 +74,12 @@ static inline bool unaligned_ctl_available(void) } #endif +bool check_vector_unaligned_access_emulated_all_cpus(void); +#if defined(CONFIG_RISCV_VECTOR_MISALIGNED) +void check_vector_unaligned_access_emulated(struct work_struct *work __always_unused); +DECLARE_PER_CPU(long, vector_misaligned_access); +#endif + #if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS) DECLARE_STATIC_KEY_FALSE(fast_unaligned_access_speed_key); @@ -103,61 +113,6 @@ extern const size_t riscv_isa_ext_count; extern bool riscv_isa_fallback; unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap); - -#define STANDARD_EXT 0 - -bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit); -#define riscv_isa_extension_available(isa_bitmap, ext) \ - __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext) - -static __always_inline bool __riscv_has_extension_likely(const unsigned long vendor, - const unsigned long ext) -{ - asm goto(ALTERNATIVE("j %l[l_no]", "nop", %[vendor], %[ext], 1) - : - : [vendor] "i" (vendor), [ext] "i" (ext) - : - : l_no); - - return true; -l_no: - return false; -} - -static __always_inline bool __riscv_has_extension_unlikely(const unsigned long vendor, - const unsigned long ext) -{ - asm goto(ALTERNATIVE("nop", "j %l[l_yes]", %[vendor], %[ext], 1) - : - : [vendor] "i" (vendor), [ext] "i" (ext) - : - : l_yes); - - return false; -l_yes: - return true; -} - -static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext) -{ - compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); - - if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) - return __riscv_has_extension_unlikely(STANDARD_EXT, ext); - - return __riscv_isa_extension_available(NULL, ext); -} - -static __always_inline bool riscv_has_extension_likely(const unsigned long ext) -{ - compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); - - if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) - return __riscv_has_extension_likely(STANDARD_EXT, ext); - - return __riscv_isa_extension_available(NULL, ext); -} - static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext) { compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX"); diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 25966995da04e0..37bdea65bbd8a1 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -119,6 +119,10 @@ /* HSTATUS flags */ #ifdef CONFIG_64BIT +#define HSTATUS_HUPMM _AC(0x3000000000000, UL) +#define HSTATUS_HUPMM_PMLEN_0 _AC(0x0000000000000, UL) +#define HSTATUS_HUPMM_PMLEN_7 _AC(0x2000000000000, UL) +#define HSTATUS_HUPMM_PMLEN_16 _AC(0x3000000000000, UL) #define HSTATUS_VSXL _AC(0x300000000, UL) #define HSTATUS_VSXL_SHIFT 32 #endif @@ -195,6 +199,11 @@ /* xENVCFG flags */ #define ENVCFG_STCE (_AC(1, ULL) << 63) #define ENVCFG_PBMTE (_AC(1, ULL) << 62) +#define ENVCFG_ADUE (_AC(1, ULL) << 61) +#define ENVCFG_PMM (_AC(0x3, ULL) << 32) +#define ENVCFG_PMM_PMLEN_0 (_AC(0x0, ULL) << 32) +#define ENVCFG_PMM_PMLEN_7 (_AC(0x2, ULL) << 32) +#define ENVCFG_PMM_PMLEN_16 (_AC(0x3, ULL) << 32) #define ENVCFG_CBZE (_AC(1, UL) << 7) #define ENVCFG_CBCFE (_AC(1, UL) << 6) #define ENVCFG_CBIE_SHIFT 4 @@ -216,6 +225,12 @@ #define SMSTATEEN0_SSTATEEN0_SHIFT 63 #define SMSTATEEN0_SSTATEEN0 (_ULL(1) << SMSTATEEN0_SSTATEEN0_SHIFT) +/* mseccfg bits */ +#define MSECCFG_PMM ENVCFG_PMM +#define MSECCFG_PMM_PMLEN_0 ENVCFG_PMM_PMLEN_0 +#define MSECCFG_PMM_PMLEN_7 ENVCFG_PMM_PMLEN_7 +#define MSECCFG_PMM_PMLEN_16 ENVCFG_PMM_PMLEN_16 + /* symbolic CSR names: */ #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 @@ -382,6 +397,8 @@ #define CSR_MIP 0x344 #define CSR_PMPCFG0 0x3a0 #define CSR_PMPADDR0 0x3b0 +#define CSR_MSECCFG 0x747 +#define CSR_MSECCFGH 0x757 #define CSR_MVENDORID 0xf11 #define CSR_MARCHID 0xf12 #define CSR_MIMPID 0xf13 diff --git a/arch/riscv/include/asm/entry-common.h b/arch/riscv/include/asm/entry-common.h index 2293e535f8659a..b28ccc6cdeea49 100644 --- a/arch/riscv/include/asm/entry-common.h +++ b/arch/riscv/include/asm/entry-common.h @@ -33,6 +33,7 @@ static inline int handle_misaligned_load(struct pt_regs *regs) { return -1; } + static inline int handle_misaligned_store(struct pt_regs *regs) { return -1; diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 2cddd79ff21b1e..3d66437a102972 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -125,8 +125,12 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS #define arch_ftrace_get_regs(regs) NULL +#define HAVE_ARCH_FTRACE_REGS struct ftrace_ops; -struct ftrace_regs { +struct ftrace_regs; +#define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs)) + +struct __arch_ftrace_regs { unsigned long epc; unsigned long ra; unsigned long sp; @@ -150,42 +154,42 @@ struct ftrace_regs { static __always_inline unsigned long ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs) { - return fregs->epc; + return arch_ftrace_regs(fregs)->epc; } static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long pc) { - fregs->epc = pc; + arch_ftrace_regs(fregs)->epc = pc; } static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs) { - return fregs->sp; + return arch_ftrace_regs(fregs)->sp; } static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs, unsigned int n) { if (n < 8) - return fregs->args[n]; + return arch_ftrace_regs(fregs)->args[n]; return 0; } static __always_inline unsigned long ftrace_regs_get_return_value(const struct ftrace_regs *fregs) { - return fregs->a0; + return arch_ftrace_regs(fregs)->a0; } static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs, unsigned long ret) { - fregs->a0 = ret; + arch_ftrace_regs(fregs)->a0 = ret; } static __always_inline void ftrace_override_function_with_return(struct ftrace_regs *fregs) { - fregs->epc = fregs->ra; + arch_ftrace_regs(fregs)->epc = arch_ftrace_regs(fregs)->ra; } int ftrace_regs_query_register_offset(const char *name); @@ -196,7 +200,7 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr) { - fregs->t1 = addr; + arch_ftrace_regs(fregs)->t1 = addr; } #endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index 46d9de54179ed4..869da082252a46 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -93,6 +93,13 @@ #define RISCV_ISA_EXT_ZCMOP 84 #define RISCV_ISA_EXT_ZAWRS 85 #define RISCV_ISA_EXT_SVVPTC 86 +#define RISCV_ISA_EXT_SMMPM 87 +#define RISCV_ISA_EXT_SMNPM 88 +#define RISCV_ISA_EXT_SSNPM 89 +#define RISCV_ISA_EXT_ZABHA 90 +#define RISCV_ISA_EXT_ZICCRSE 91 +#define RISCV_ISA_EXT_SVADE 92 +#define RISCV_ISA_EXT_SVADU 93 #define RISCV_ISA_EXT_XLINUXENVCFG 127 @@ -101,8 +108,10 @@ #ifdef CONFIG_RISCV_M_MODE #define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SMAIA +#define RISCV_ISA_EXT_SUPM RISCV_ISA_EXT_SMNPM #else #define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SSAIA +#define RISCV_ISA_EXT_SUPM RISCV_ISA_EXT_SSNPM #endif #endif /* _ASM_RISCV_HWCAP_H */ diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h index ffb9484531af7e..1ce1df6d0ff3c6 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -8,7 +8,7 @@ #include -#define RISCV_HWPROBE_MAX_KEY 9 +#define RISCV_HWPROBE_MAX_KEY 10 static inline bool riscv_hwprobe_key_is_valid(__s64 key) { diff --git a/arch/riscv/include/asm/jump_label.h b/arch/riscv/include/asm/jump_label.h index 1c768d02bd0c2a..87a71cc6d146ce 100644 --- a/arch/riscv/include/asm/jump_label.h +++ b/arch/riscv/include/asm/jump_label.h @@ -16,21 +16,28 @@ #define JUMP_LABEL_NOP_SIZE 4 +#define JUMP_TABLE_ENTRY(key, label) \ + ".pushsection __jump_table, \"aw\" \n\t" \ + ".align " RISCV_LGPTR " \n\t" \ + ".long 1b - ., " label " - . \n\t" \ + "" RISCV_PTR " " key " - . \n\t" \ + ".popsection \n\t" + +/* This macro is also expanded on the Rust side. */ +#define ARCH_STATIC_BRANCH_ASM(key, label) \ + " .align 2 \n\t" \ + " .option push \n\t" \ + " .option norelax \n\t" \ + " .option norvc \n\t" \ + "1: nop \n\t" \ + " .option pop \n\t" \ + JUMP_TABLE_ENTRY(key, label) + static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) { asm goto( - " .align 2 \n\t" - " .option push \n\t" - " .option norelax \n\t" - " .option norvc \n\t" - "1: nop \n\t" - " .option pop \n\t" - " .pushsection __jump_table, \"aw\" \n\t" - " .align " RISCV_LGPTR " \n\t" - " .long 1b - ., %l[label] - . \n\t" - " " RISCV_PTR " %0 - . \n\t" - " .popsection \n\t" + ARCH_STATIC_BRANCH_ASM("%0", "%l[label]") : : "i"(&((char *)key)[branch]) : : label); return false; @@ -38,21 +45,20 @@ static __always_inline bool arch_static_branch(struct static_key * const key, return true; } +#define ARCH_STATIC_BRANCH_JUMP_ASM(key, label) \ + " .align 2 \n\t" \ + " .option push \n\t" \ + " .option norelax \n\t" \ + " .option norvc \n\t" \ + "1: j " label " \n\t" \ + " .option pop \n\t" \ + JUMP_TABLE_ENTRY(key, label) + static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) { asm goto( - " .align 2 \n\t" - " .option push \n\t" - " .option norelax \n\t" - " .option norvc \n\t" - "1: j %l[label] \n\t" - " .option pop \n\t" - " .pushsection __jump_table, \"aw\" \n\t" - " .align " RISCV_LGPTR " \n\t" - " .long 1b - ., %l[label] - . \n\t" - " " RISCV_PTR " %0 - . \n\t" - " .popsection \n\t" + ARCH_STATIC_BRANCH_JUMP_ASM("%0", "%l[label]") : : "i"(&((char *)key)[branch]) : : label); return false; diff --git a/arch/riscv/include/asm/kfence.h b/arch/riscv/include/asm/kfence.h index 7388edd88986f9..d08bf7fb3aee61 100644 --- a/arch/riscv/include/asm/kfence.h +++ b/arch/riscv/include/asm/kfence.h @@ -22,7 +22,9 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) else set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT)); - flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + preempt_disable(); + local_flush_tlb_kernel_range(addr, addr + PAGE_SIZE); + preempt_enable(); return true; } diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 2e2254fd2a2aae..35eab6e0f4ae0e 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -286,6 +286,16 @@ struct kvm_vcpu_arch { } sta; }; +/* + * Returns true if a Performance Monitoring Interrupt (PMI), a.k.a. perf event, + * arrived in guest context. For riscv, any event that arrives while a vCPU is + * loaded is considered to be "in guest". + */ +static inline bool kvm_arch_pmi_in_guest(struct kvm_vcpu *vcpu) +{ + return IS_ENABLED(CONFIG_GUEST_PERF_EVENTS) && !!vcpu; +} + static inline void kvm_arch_sync_events(struct kvm *kvm) {} #define KVM_RISCV_GSTAGE_TLB_MIN_ORDER 12 diff --git a/arch/riscv/include/asm/kvm_nacl.h b/arch/riscv/include/asm/kvm_nacl.h new file mode 100644 index 00000000000000..4124d5e06a0ff1 --- /dev/null +++ b/arch/riscv/include/asm/kvm_nacl.h @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 Ventana Micro Systems Inc. + */ + +#ifndef __KVM_NACL_H +#define __KVM_NACL_H + +#include +#include +#include +#include +#include + +struct kvm_vcpu_arch; + +DECLARE_STATIC_KEY_FALSE(kvm_riscv_nacl_available); +#define kvm_riscv_nacl_available() \ + static_branch_unlikely(&kvm_riscv_nacl_available) + +DECLARE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_csr_available); +#define kvm_riscv_nacl_sync_csr_available() \ + static_branch_unlikely(&kvm_riscv_nacl_sync_csr_available) + +DECLARE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_hfence_available); +#define kvm_riscv_nacl_sync_hfence_available() \ + static_branch_unlikely(&kvm_riscv_nacl_sync_hfence_available) + +DECLARE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_sret_available); +#define kvm_riscv_nacl_sync_sret_available() \ + static_branch_unlikely(&kvm_riscv_nacl_sync_sret_available) + +DECLARE_STATIC_KEY_FALSE(kvm_riscv_nacl_autoswap_csr_available); +#define kvm_riscv_nacl_autoswap_csr_available() \ + static_branch_unlikely(&kvm_riscv_nacl_autoswap_csr_available) + +struct kvm_riscv_nacl { + void *shmem; + phys_addr_t shmem_phys; +}; +DECLARE_PER_CPU(struct kvm_riscv_nacl, kvm_riscv_nacl); + +void __kvm_riscv_nacl_hfence(void *shmem, + unsigned long control, + unsigned long page_num, + unsigned long page_count); + +void __kvm_riscv_nacl_switch_to(struct kvm_vcpu_arch *vcpu_arch, + unsigned long sbi_ext_id, + unsigned long sbi_func_id); + +int kvm_riscv_nacl_enable(void); + +void kvm_riscv_nacl_disable(void); + +void kvm_riscv_nacl_exit(void); + +int kvm_riscv_nacl_init(void); + +#ifdef CONFIG_32BIT +#define lelong_to_cpu(__x) le32_to_cpu(__x) +#define cpu_to_lelong(__x) cpu_to_le32(__x) +#else +#define lelong_to_cpu(__x) le64_to_cpu(__x) +#define cpu_to_lelong(__x) cpu_to_le64(__x) +#endif + +#define nacl_shmem() \ + this_cpu_ptr(&kvm_riscv_nacl)->shmem + +#define nacl_scratch_read_long(__shmem, __offset) \ +({ \ + unsigned long *__p = (__shmem) + \ + SBI_NACL_SHMEM_SCRATCH_OFFSET + \ + (__offset); \ + lelong_to_cpu(*__p); \ +}) + +#define nacl_scratch_write_long(__shmem, __offset, __val) \ +do { \ + unsigned long *__p = (__shmem) + \ + SBI_NACL_SHMEM_SCRATCH_OFFSET + \ + (__offset); \ + *__p = cpu_to_lelong(__val); \ +} while (0) + +#define nacl_scratch_write_longs(__shmem, __offset, __array, __count) \ +do { \ + unsigned int __i; \ + unsigned long *__p = (__shmem) + \ + SBI_NACL_SHMEM_SCRATCH_OFFSET + \ + (__offset); \ + for (__i = 0; __i < (__count); __i++) \ + __p[__i] = cpu_to_lelong((__array)[__i]); \ +} while (0) + +#define nacl_sync_hfence(__e) \ + sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_SYNC_HFENCE, \ + (__e), 0, 0, 0, 0, 0) + +#define nacl_hfence_mkconfig(__type, __order, __vmid, __asid) \ +({ \ + unsigned long __c = SBI_NACL_SHMEM_HFENCE_CONFIG_PEND; \ + __c |= ((__type) & SBI_NACL_SHMEM_HFENCE_CONFIG_TYPE_MASK) \ + << SBI_NACL_SHMEM_HFENCE_CONFIG_TYPE_SHIFT; \ + __c |= (((__order) - SBI_NACL_SHMEM_HFENCE_ORDER_BASE) & \ + SBI_NACL_SHMEM_HFENCE_CONFIG_ORDER_MASK) \ + << SBI_NACL_SHMEM_HFENCE_CONFIG_ORDER_SHIFT; \ + __c |= ((__vmid) & SBI_NACL_SHMEM_HFENCE_CONFIG_VMID_MASK) \ + << SBI_NACL_SHMEM_HFENCE_CONFIG_VMID_SHIFT; \ + __c |= ((__asid) & SBI_NACL_SHMEM_HFENCE_CONFIG_ASID_MASK); \ + __c; \ +}) + +#define nacl_hfence_mkpnum(__order, __addr) \ + ((__addr) >> (__order)) + +#define nacl_hfence_mkpcount(__order, __size) \ + ((__size) >> (__order)) + +#define nacl_hfence_gvma(__shmem, __gpa, __gpsz, __order) \ +__kvm_riscv_nacl_hfence(__shmem, \ + nacl_hfence_mkconfig(SBI_NACL_SHMEM_HFENCE_TYPE_GVMA, \ + __order, 0, 0), \ + nacl_hfence_mkpnum(__order, __gpa), \ + nacl_hfence_mkpcount(__order, __gpsz)) + +#define nacl_hfence_gvma_all(__shmem) \ +__kvm_riscv_nacl_hfence(__shmem, \ + nacl_hfence_mkconfig(SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_ALL, \ + 0, 0, 0), 0, 0) + +#define nacl_hfence_gvma_vmid(__shmem, __vmid, __gpa, __gpsz, __order) \ +__kvm_riscv_nacl_hfence(__shmem, \ + nacl_hfence_mkconfig(SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_VMID, \ + __order, __vmid, 0), \ + nacl_hfence_mkpnum(__order, __gpa), \ + nacl_hfence_mkpcount(__order, __gpsz)) + +#define nacl_hfence_gvma_vmid_all(__shmem, __vmid) \ +__kvm_riscv_nacl_hfence(__shmem, \ + nacl_hfence_mkconfig(SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_VMID_ALL, \ + 0, __vmid, 0), 0, 0) + +#define nacl_hfence_vvma(__shmem, __vmid, __gva, __gvsz, __order) \ +__kvm_riscv_nacl_hfence(__shmem, \ + nacl_hfence_mkconfig(SBI_NACL_SHMEM_HFENCE_TYPE_VVMA, \ + __order, __vmid, 0), \ + nacl_hfence_mkpnum(__order, __gva), \ + nacl_hfence_mkpcount(__order, __gvsz)) + +#define nacl_hfence_vvma_all(__shmem, __vmid) \ +__kvm_riscv_nacl_hfence(__shmem, \ + nacl_hfence_mkconfig(SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ALL, \ + 0, __vmid, 0), 0, 0) + +#define nacl_hfence_vvma_asid(__shmem, __vmid, __asid, __gva, __gvsz, __order)\ +__kvm_riscv_nacl_hfence(__shmem, \ + nacl_hfence_mkconfig(SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ASID, \ + __order, __vmid, __asid), \ + nacl_hfence_mkpnum(__order, __gva), \ + nacl_hfence_mkpcount(__order, __gvsz)) + +#define nacl_hfence_vvma_asid_all(__shmem, __vmid, __asid) \ +__kvm_riscv_nacl_hfence(__shmem, \ + nacl_hfence_mkconfig(SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ASID_ALL, \ + 0, __vmid, __asid), 0, 0) + +#define nacl_csr_read(__shmem, __csr) \ +({ \ + unsigned long *__a = (__shmem) + SBI_NACL_SHMEM_CSR_OFFSET; \ + lelong_to_cpu(__a[SBI_NACL_SHMEM_CSR_INDEX(__csr)]); \ +}) + +#define nacl_csr_write(__shmem, __csr, __val) \ +do { \ + void *__s = (__shmem); \ + unsigned int __i = SBI_NACL_SHMEM_CSR_INDEX(__csr); \ + unsigned long *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET; \ + u8 *__b = (__s) + SBI_NACL_SHMEM_DBITMAP_OFFSET; \ + __a[__i] = cpu_to_lelong(__val); \ + __b[__i >> 3] |= 1U << (__i & 0x7); \ +} while (0) + +#define nacl_csr_swap(__shmem, __csr, __val) \ +({ \ + void *__s = (__shmem); \ + unsigned int __i = SBI_NACL_SHMEM_CSR_INDEX(__csr); \ + unsigned long *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET; \ + u8 *__b = (__s) + SBI_NACL_SHMEM_DBITMAP_OFFSET; \ + unsigned long __r = lelong_to_cpu(__a[__i]); \ + __a[__i] = cpu_to_lelong(__val); \ + __b[__i >> 3] |= 1U << (__i & 0x7); \ + __r; \ +}) + +#define nacl_sync_csr(__csr) \ + sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_SYNC_CSR, \ + (__csr), 0, 0, 0, 0, 0) + +/* + * Each ncsr_xyz() macro defined below has it's own static-branch so every + * use of ncsr_xyz() macro emits a patchable direct jump. This means multiple + * back-to-back ncsr_xyz() macro usage will emit multiple patchable direct + * jumps which is sub-optimal. + * + * Based on the above, it is recommended to avoid multiple back-to-back + * ncsr_xyz() macro usage. + */ + +#define ncsr_read(__csr) \ +({ \ + unsigned long __r; \ + if (kvm_riscv_nacl_available()) \ + __r = nacl_csr_read(nacl_shmem(), __csr); \ + else \ + __r = csr_read(__csr); \ + __r; \ +}) + +#define ncsr_write(__csr, __val) \ +do { \ + if (kvm_riscv_nacl_sync_csr_available()) \ + nacl_csr_write(nacl_shmem(), __csr, __val); \ + else \ + csr_write(__csr, __val); \ +} while (0) + +#define ncsr_swap(__csr, __val) \ +({ \ + unsigned long __r; \ + if (kvm_riscv_nacl_sync_csr_available()) \ + __r = nacl_csr_swap(nacl_shmem(), __csr, __val); \ + else \ + __r = csr_swap(__csr, __val); \ + __r; \ +}) + +#define nsync_csr(__csr) \ +do { \ + if (kvm_riscv_nacl_sync_csr_available()) \ + nacl_sync_csr(__csr); \ +} while (0) + +#endif diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h index c9e03e9da3dc9c..1cc90465d75b18 100644 --- a/arch/riscv/include/asm/mmu.h +++ b/arch/riscv/include/asm/mmu.h @@ -25,9 +25,16 @@ typedef struct { #ifdef CONFIG_BINFMT_ELF_FDPIC unsigned long exec_fdpic_loadmap; unsigned long interp_fdpic_loadmap; +#endif + unsigned long flags; +#ifdef CONFIG_RISCV_ISA_SUPM + u8 pmlen; #endif } mm_context_t; +/* Lock the pointer masking mode because this mm is multithreaded */ +#define MM_CONTEXT_LOCK_PMLEN 0 + #define cntx2asid(cntx) ((cntx) & SATP_ASID_MASK) #define cntx2version(cntx) ((cntx) & ~SATP_ASID_MASK) diff --git a/arch/riscv/include/asm/mmu_context.h b/arch/riscv/include/asm/mmu_context.h index 7030837adc1a29..8c4bc49a3a0f5b 100644 --- a/arch/riscv/include/asm/mmu_context.h +++ b/arch/riscv/include/asm/mmu_context.h @@ -20,6 +20,9 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next, static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) { +#ifdef CONFIG_RISCV_ISA_SUPM + next->context.pmlen = 0; +#endif switch_mm(prev, next, NULL); } @@ -30,11 +33,21 @@ static inline int init_new_context(struct task_struct *tsk, #ifdef CONFIG_MMU atomic_long_set(&mm->context.id, 0); #endif + if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM)) + clear_bit(MM_CONTEXT_LOCK_PMLEN, &mm->context.flags); return 0; } DECLARE_STATIC_KEY_FALSE(use_asid_allocator); +#ifdef CONFIG_RISCV_ISA_SUPM +#define mm_untag_mask mm_untag_mask +static inline unsigned long mm_untag_mask(struct mm_struct *mm) +{ + return -1UL >> mm->context.pmlen; +} +#endif + #include #endif /* _ASM_RISCV_MMU_CONTEXT_H */ diff --git a/arch/riscv/include/asm/page.h b/arch/riscv/include/asm/page.h index 32d308a3355fd4..71aabc5c671389 100644 --- a/arch/riscv/include/asm/page.h +++ b/arch/riscv/include/asm/page.h @@ -12,9 +12,7 @@ #include #include -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE - 1)) +#include #define HPAGE_SHIFT PMD_SHIFT #define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) @@ -194,9 +192,6 @@ extern phys_addr_t __phys_addr_symbol(unsigned long x); #define virt_to_page(vaddr) (pfn_to_page(virt_to_pfn(vaddr))) #define page_to_virt(page) (pfn_to_virt(page_to_pfn(page))) -#define page_to_phys(page) (pfn_to_phys(page_to_pfn(page))) -#define phys_to_page(paddr) (pfn_to_page(phys_to_pfn(paddr))) - #define sym_to_pfn(x) __phys_to_pfn(__pa_symbol(x)) unsigned long kaslr_offset(void); diff --git a/arch/riscv/include/asm/patch.h b/arch/riscv/include/asm/patch.h deleted file mode 100644 index 7228e266b9a1ae..00000000000000 --- a/arch/riscv/include/asm/patch.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2020 SiFive - */ - -#ifndef _ASM_RISCV_PATCH_H -#define _ASM_RISCV_PATCH_H - -int patch_insn_write(void *addr, const void *insn, size_t len); -int patch_text_nosync(void *addr, const void *insns, size_t len); -int patch_text_set_nosync(void *addr, u8 c, size_t len); -int patch_text(void *addr, u32 *insns, size_t len); - -extern int riscv_patch_in_stop_machine; - -#endif /* _ASM_RISCV_PATCH_H */ diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h index 665bbc9b2f840a..bcc928fd3785c1 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h @@ -8,6 +8,7 @@ #ifndef _ASM_RISCV_PERF_EVENT_H #define _ASM_RISCV_PERF_EVENT_H +#ifdef CONFIG_PERF_EVENTS #include #define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs @@ -17,4 +18,6 @@ (regs)->sp = current_stack_pointer; \ (regs)->status = SR_PP; \ } +#endif + #endif /* _ASM_RISCV_PERF_EVENT_H */ diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index e79f15293492d5..d4e99eef90acf0 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -113,6 +113,7 @@ #include #include #include +#include #define __page_val_to_pfn(_val) (((_val) & _PAGE_PFN_MASK) >> _PAGE_PFN_SHIFT) @@ -284,7 +285,6 @@ static inline pte_t pud_pte(pud_t pud) } #ifdef CONFIG_RISCV_ISA_SVNAPOT -#include static __always_inline bool has_svnapot(void) { @@ -655,6 +655,17 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot) return __pgprot(prot); } +/* + * Both Svade and Svadu control the hardware behavior when the PTE A/D bits need to be set. By + * default the M-mode firmware enables the hardware updating scheme when only Svadu is present in + * DT. + */ +#define arch_has_hw_pte_young arch_has_hw_pte_young +static inline bool arch_has_hw_pte_young(void) +{ + return riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU); +} + /* * THP functions */ @@ -963,6 +974,25 @@ void misc_mem_init(void); extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) +/* + * Use set_p*_safe(), and elide TLB flushing, when confident that *no* + * TLB flush will be required as a result of the "set". For example, use + * in scenarios where it is known ahead of time that the routine is + * setting non-present entries, or re-setting an existing entry to the + * same value. Otherwise, use the typical "set" helpers and flush the + * TLB. + */ +#define set_p4d_safe(p4dp, p4d) \ +({ \ + WARN_ON_ONCE(p4d_present(*p4dp) && !p4d_same(*p4dp, p4d)); \ + set_p4d(p4dp, p4d); \ +}) + +#define set_pgd_safe(pgdp, pgd) \ +({ \ + WARN_ON_ONCE(pgd_present(*pgdp) && !pgd_same(*pgdp, pgd)); \ + set_pgd(pgdp, pgd); \ +}) #endif /* !__ASSEMBLY__ */ #endif /* _ASM_RISCV_PGTABLE_H */ diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index efa1b3519b2380..5f56eb9d114a95 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -102,6 +102,7 @@ struct thread_struct { unsigned long s[12]; /* s[0]: frame pointer */ struct __riscv_d_ext_state fstate; unsigned long bad_cause; + unsigned long envcfg; u32 riscv_v_flags; u32 vstate_ctrl; struct __riscv_v_ext_state vstate; @@ -177,6 +178,14 @@ extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); #define RISCV_SET_ICACHE_FLUSH_CTX(arg1, arg2) riscv_set_icache_flush_ctx(arg1, arg2) extern int riscv_set_icache_flush_ctx(unsigned long ctx, unsigned long per_thread); +#ifdef CONFIG_RISCV_ISA_SUPM +/* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */ +long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg); +long get_tagged_addr_ctrl(struct task_struct *task); +#define SET_TAGGED_ADDR_CTRL(arg) set_tagged_addr_ctrl(current, arg) +#define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl(current) +#endif + #endif /* __ASSEMBLY__ */ #endif /* _ASM_RISCV_PROCESSOR_H */ diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 98f631b051dba8..6c82318065cfd4 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -34,6 +34,7 @@ enum sbi_ext_id { SBI_EXT_PMU = 0x504D55, SBI_EXT_DBCN = 0x4442434E, SBI_EXT_STA = 0x535441, + SBI_EXT_NACL = 0x4E41434C, /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START = 0x08000000, @@ -281,6 +282,125 @@ struct sbi_sta_struct { #define SBI_SHMEM_DISABLE -1 +enum sbi_ext_nacl_fid { + SBI_EXT_NACL_PROBE_FEATURE = 0x0, + SBI_EXT_NACL_SET_SHMEM = 0x1, + SBI_EXT_NACL_SYNC_CSR = 0x2, + SBI_EXT_NACL_SYNC_HFENCE = 0x3, + SBI_EXT_NACL_SYNC_SRET = 0x4, +}; + +enum sbi_ext_nacl_feature { + SBI_NACL_FEAT_SYNC_CSR = 0x0, + SBI_NACL_FEAT_SYNC_HFENCE = 0x1, + SBI_NACL_FEAT_SYNC_SRET = 0x2, + SBI_NACL_FEAT_AUTOSWAP_CSR = 0x3, +}; + +#define SBI_NACL_SHMEM_ADDR_SHIFT 12 +#define SBI_NACL_SHMEM_SCRATCH_OFFSET 0x0000 +#define SBI_NACL_SHMEM_SCRATCH_SIZE 0x1000 +#define SBI_NACL_SHMEM_SRET_OFFSET 0x0000 +#define SBI_NACL_SHMEM_SRET_SIZE 0x0200 +#define SBI_NACL_SHMEM_AUTOSWAP_OFFSET (SBI_NACL_SHMEM_SRET_OFFSET + \ + SBI_NACL_SHMEM_SRET_SIZE) +#define SBI_NACL_SHMEM_AUTOSWAP_SIZE 0x0080 +#define SBI_NACL_SHMEM_UNUSED_OFFSET (SBI_NACL_SHMEM_AUTOSWAP_OFFSET + \ + SBI_NACL_SHMEM_AUTOSWAP_SIZE) +#define SBI_NACL_SHMEM_UNUSED_SIZE 0x0580 +#define SBI_NACL_SHMEM_HFENCE_OFFSET (SBI_NACL_SHMEM_UNUSED_OFFSET + \ + SBI_NACL_SHMEM_UNUSED_SIZE) +#define SBI_NACL_SHMEM_HFENCE_SIZE 0x0780 +#define SBI_NACL_SHMEM_DBITMAP_OFFSET (SBI_NACL_SHMEM_HFENCE_OFFSET + \ + SBI_NACL_SHMEM_HFENCE_SIZE) +#define SBI_NACL_SHMEM_DBITMAP_SIZE 0x0080 +#define SBI_NACL_SHMEM_CSR_OFFSET (SBI_NACL_SHMEM_DBITMAP_OFFSET + \ + SBI_NACL_SHMEM_DBITMAP_SIZE) +#define SBI_NACL_SHMEM_CSR_SIZE ((__riscv_xlen / 8) * 1024) +#define SBI_NACL_SHMEM_SIZE (SBI_NACL_SHMEM_CSR_OFFSET + \ + SBI_NACL_SHMEM_CSR_SIZE) + +#define SBI_NACL_SHMEM_CSR_INDEX(__csr_num) \ + ((((__csr_num) & 0xc00) >> 2) | ((__csr_num) & 0xff)) + +#define SBI_NACL_SHMEM_HFENCE_ENTRY_SZ ((__riscv_xlen / 8) * 4) +#define SBI_NACL_SHMEM_HFENCE_ENTRY_MAX \ + (SBI_NACL_SHMEM_HFENCE_SIZE / \ + SBI_NACL_SHMEM_HFENCE_ENTRY_SZ) +#define SBI_NACL_SHMEM_HFENCE_ENTRY(__num) \ + (SBI_NACL_SHMEM_HFENCE_OFFSET + \ + (__num) * SBI_NACL_SHMEM_HFENCE_ENTRY_SZ) +#define SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(__num) \ + SBI_NACL_SHMEM_HFENCE_ENTRY(__num) +#define SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(__num)\ + (SBI_NACL_SHMEM_HFENCE_ENTRY(__num) + (__riscv_xlen / 8)) +#define SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(__num)\ + (SBI_NACL_SHMEM_HFENCE_ENTRY(__num) + \ + ((__riscv_xlen / 8) * 3)) + +#define SBI_NACL_SHMEM_HFENCE_CONFIG_PEND_BITS 1 +#define SBI_NACL_SHMEM_HFENCE_CONFIG_PEND_SHIFT \ + (__riscv_xlen - SBI_NACL_SHMEM_HFENCE_CONFIG_PEND_BITS) +#define SBI_NACL_SHMEM_HFENCE_CONFIG_PEND_MASK \ + ((1UL << SBI_NACL_SHMEM_HFENCE_CONFIG_PEND_BITS) - 1) +#define SBI_NACL_SHMEM_HFENCE_CONFIG_PEND \ + (SBI_NACL_SHMEM_HFENCE_CONFIG_PEND_MASK << \ + SBI_NACL_SHMEM_HFENCE_CONFIG_PEND_SHIFT) + +#define SBI_NACL_SHMEM_HFENCE_CONFIG_RSVD1_BITS 3 +#define SBI_NACL_SHMEM_HFENCE_CONFIG_RSVD1_SHIFT \ + (SBI_NACL_SHMEM_HFENCE_CONFIG_PEND_SHIFT - \ + SBI_NACL_SHMEM_HFENCE_CONFIG_RSVD1_BITS) + +#define SBI_NACL_SHMEM_HFENCE_CONFIG_TYPE_BITS 4 +#define SBI_NACL_SHMEM_HFENCE_CONFIG_TYPE_SHIFT \ + (SBI_NACL_SHMEM_HFENCE_CONFIG_RSVD1_SHIFT - \ + SBI_NACL_SHMEM_HFENCE_CONFIG_TYPE_BITS) +#define SBI_NACL_SHMEM_HFENCE_CONFIG_TYPE_MASK \ + ((1UL << SBI_NACL_SHMEM_HFENCE_CONFIG_TYPE_BITS) - 1) + +#define SBI_NACL_SHMEM_HFENCE_TYPE_GVMA 0x0 +#define SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_ALL 0x1 +#define SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_VMID 0x2 +#define SBI_NACL_SHMEM_HFENCE_TYPE_GVMA_VMID_ALL 0x3 +#define SBI_NACL_SHMEM_HFENCE_TYPE_VVMA 0x4 +#define SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ALL 0x5 +#define SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ASID 0x6 +#define SBI_NACL_SHMEM_HFENCE_TYPE_VVMA_ASID_ALL 0x7 + +#define SBI_NACL_SHMEM_HFENCE_CONFIG_RSVD2_BITS 1 +#define SBI_NACL_SHMEM_HFENCE_CONFIG_RSVD2_SHIFT \ + (SBI_NACL_SHMEM_HFENCE_CONFIG_TYPE_SHIFT - \ + SBI_NACL_SHMEM_HFENCE_CONFIG_RSVD2_BITS) + +#define SBI_NACL_SHMEM_HFENCE_CONFIG_ORDER_BITS 7 +#define SBI_NACL_SHMEM_HFENCE_CONFIG_ORDER_SHIFT \ + (SBI_NACL_SHMEM_HFENCE_CONFIG_RSVD2_SHIFT - \ + SBI_NACL_SHMEM_HFENCE_CONFIG_ORDER_BITS) +#define SBI_NACL_SHMEM_HFENCE_CONFIG_ORDER_MASK \ + ((1UL << SBI_NACL_SHMEM_HFENCE_CONFIG_ORDER_BITS) - 1) +#define SBI_NACL_SHMEM_HFENCE_ORDER_BASE 12 + +#if __riscv_xlen == 32 +#define SBI_NACL_SHMEM_HFENCE_CONFIG_ASID_BITS 9 +#define SBI_NACL_SHMEM_HFENCE_CONFIG_VMID_BITS 7 +#else +#define SBI_NACL_SHMEM_HFENCE_CONFIG_ASID_BITS 16 +#define SBI_NACL_SHMEM_HFENCE_CONFIG_VMID_BITS 14 +#endif +#define SBI_NACL_SHMEM_HFENCE_CONFIG_VMID_SHIFT \ + SBI_NACL_SHMEM_HFENCE_CONFIG_ASID_BITS +#define SBI_NACL_SHMEM_HFENCE_CONFIG_ASID_MASK \ + ((1UL << SBI_NACL_SHMEM_HFENCE_CONFIG_ASID_BITS) - 1) +#define SBI_NACL_SHMEM_HFENCE_CONFIG_VMID_MASK \ + ((1UL << SBI_NACL_SHMEM_HFENCE_CONFIG_VMID_BITS) - 1) + +#define SBI_NACL_SHMEM_AUTOSWAP_FLAG_HSTATUS BIT(0) +#define SBI_NACL_SHMEM_AUTOSWAP_HSTATUS ((__riscv_xlen / 8) * 1) + +#define SBI_NACL_SHMEM_SRET_X(__i) ((__riscv_xlen / 8) * (__i)) +#define SBI_NACL_SHMEM_SRET_X_LAST 31 + /* SBI spec version fields */ #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 diff --git a/arch/riscv/include/asm/set_memory.h b/arch/riscv/include/asm/set_memory.h index ab92fc84e1fc9e..ea263d3683ef6f 100644 --- a/arch/riscv/include/asm/set_memory.h +++ b/arch/riscv/include/asm/set_memory.h @@ -42,6 +42,7 @@ static inline int set_kernel_memory(char *startp, char *endp, int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page); +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid); bool kernel_page_present(struct page *page); #endif /* __ASSEMBLY__ */ diff --git a/arch/riscv/include/asm/spinlock.h b/arch/riscv/include/asm/spinlock.h new file mode 100644 index 00000000000000..e5121b89aceaca --- /dev/null +++ b/arch/riscv/include/asm/spinlock.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASM_RISCV_SPINLOCK_H +#define __ASM_RISCV_SPINLOCK_H + +#ifdef CONFIG_RISCV_COMBO_SPINLOCKS +#define _Q_PENDING_LOOPS (1 << 9) + +#define __no_arch_spinlock_redefine +#include +#include +#include + +/* + * TODO: Use an alternative instead of a static key when we are able to parse + * the extensions string earlier in the boot process. + */ +DECLARE_STATIC_KEY_TRUE(qspinlock_key); + +#define SPINLOCK_BASE_DECLARE(op, type, type_lock) \ +static __always_inline type arch_spin_##op(type_lock lock) \ +{ \ + if (static_branch_unlikely(&qspinlock_key)) \ + return queued_spin_##op(lock); \ + return ticket_spin_##op(lock); \ +} + +SPINLOCK_BASE_DECLARE(lock, void, arch_spinlock_t *) +SPINLOCK_BASE_DECLARE(unlock, void, arch_spinlock_t *) +SPINLOCK_BASE_DECLARE(is_locked, int, arch_spinlock_t *) +SPINLOCK_BASE_DECLARE(is_contended, int, arch_spinlock_t *) +SPINLOCK_BASE_DECLARE(trylock, bool, arch_spinlock_t *) +SPINLOCK_BASE_DECLARE(value_unlocked, int, arch_spinlock_t) + +#elif defined(CONFIG_RISCV_QUEUED_SPINLOCKS) + +#include + +#else + +#include + +#endif + +#include + +#endif /* __ASM_RISCV_SPINLOCK_H */ diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 7594df37cc9ff3..94e33216b2d949 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -70,6 +70,24 @@ static __always_inline bool has_fpu(void) { return false; } #define __switch_to_fpu(__prev, __next) do { } while (0) #endif +static inline void envcfg_update_bits(struct task_struct *task, + unsigned long mask, unsigned long val) +{ + unsigned long envcfg; + + envcfg = (task->thread.envcfg & ~mask) | val; + task->thread.envcfg = envcfg; + if (task == current) + csr_write(CSR_ENVCFG, envcfg); +} + +static inline void __switch_to_envcfg(struct task_struct *next) +{ + asm volatile (ALTERNATIVE("nop", "csrw " __stringify(CSR_ENVCFG) ", %0", + 0, RISCV_ISA_EXT_XLINUXENVCFG, 1) + :: "r" (next->thread.envcfg) : "memory"); +} + extern struct task_struct *__switch_to(struct task_struct *, struct task_struct *); @@ -103,6 +121,7 @@ do { \ __switch_to_vector(__prev, __next); \ if (switch_to_should_flush_icache(__next)) \ local_flush_icache_all(); \ + __switch_to_envcfg(__next); \ ((last) = __switch_to(__prev, __next)); \ } while (0) diff --git a/arch/riscv/include/asm/text-patching.h b/arch/riscv/include/asm/text-patching.h new file mode 100644 index 00000000000000..7228e266b9a1ae --- /dev/null +++ b/arch/riscv/include/asm/text-patching.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020 SiFive + */ + +#ifndef _ASM_RISCV_PATCH_H +#define _ASM_RISCV_PATCH_H + +int patch_insn_write(void *addr, const void *insn, size_t len); +int patch_text_nosync(void *addr, const void *insns, size_t len); +int patch_text_set_nosync(void *addr, u8 c, size_t len); +int patch_text(void *addr, u32 *insns, size_t len); + +extern int riscv_patch_in_stop_machine; + +#endif /* _ASM_RISCV_PATCH_H */ diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index 9c10fb180f4389..f5916a70879a87 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -107,9 +107,10 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); * - pending work-to-be-done flags are in lowest half-word * - other flags in upper half-word(s) */ -#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_NEED_RESCHED 0 /* rescheduling necessary */ +#define TIF_NEED_RESCHED_LAZY 1 /* Lazy rescheduling needed */ +#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ +#define TIF_SIGPENDING 3 /* signal pending */ #define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */ #define TIF_MEMDIE 5 /* is terminating due to OOM killer */ #define TIF_NOTIFY_SIGNAL 9 /* signal notifications exist */ @@ -117,9 +118,10 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); #define TIF_32BIT 11 /* compat-mode 32bit process */ #define TIF_RISCV_V_DEFER_RESTORE 12 /* restore Vector before returing to user */ +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) -#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) #define _TIF_UPROBE (1 << TIF_UPROBE) #define _TIF_RISCV_V_DEFER_RESTORE (1 << TIF_RISCV_V_DEFER_RESTORE) diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index 72ec1d9bd3f312..fee56b0c805865 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -9,8 +9,41 @@ #define _ASM_RISCV_UACCESS_H #include +#include #include /* for TASK_SIZE */ +#ifdef CONFIG_RISCV_ISA_SUPM +static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigned long addr) +{ + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) { + u8 pmlen = mm->context.pmlen; + + /* Virtual addresses are sign-extended; physical addresses are zero-extended. */ + if (IS_ENABLED(CONFIG_MMU)) + return (long)(addr << pmlen) >> pmlen; + else + return (addr << pmlen) >> pmlen; + } + + return addr; +} + +#define untagged_addr(addr) ({ \ + unsigned long __addr = (__force unsigned long)(addr); \ + (__force __typeof__(addr))__untagged_addr_remote(current->mm, __addr); \ +}) + +#define untagged_addr_remote(mm, addr) ({ \ + unsigned long __addr = (__force unsigned long)(addr); \ + mmap_assert_locked(mm); \ + (__force __typeof__(addr))__untagged_addr_remote(mm, __addr); \ +}) + +#define access_ok(addr, size) likely(__access_ok(untagged_addr(addr), size)) +#else +#define untagged_addr(addr) (addr) +#endif + /* * User space memory access functions */ @@ -130,7 +163,7 @@ do { \ */ #define __get_user(x, ptr) \ ({ \ - const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \ long __gu_err = 0; \ \ __chk_user_ptr(__gu_ptr); \ @@ -246,7 +279,7 @@ do { \ */ #define __put_user(x, ptr) \ ({ \ - __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \ __typeof__(*__gu_ptr) __val = (x); \ long __pu_err = 0; \ \ @@ -293,13 +326,13 @@ unsigned long __must_check __asm_copy_from_user(void *to, static inline unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n) { - return __asm_copy_from_user(to, from, n); + return __asm_copy_from_user(to, untagged_addr(from), n); } static inline unsigned long raw_copy_to_user(void __user *to, const void *from, unsigned long n) { - return __asm_copy_to_user(to, from, n); + return __asm_copy_to_user(untagged_addr(to), from, n); } extern long strncpy_from_user(char *dest, const char __user *src, long count); @@ -314,7 +347,7 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n) { might_fault(); return access_ok(to, n) ? - __clear_user(to, n) : n; + __clear_user(untagged_addr(to), n) : n; } #define __get_kernel_nofault(dst, src, type, err_label) \ diff --git a/arch/riscv/include/asm/uprobes.h b/arch/riscv/include/asm/uprobes.h index 3fc7deda919025..5008f76cdc2753 100644 --- a/arch/riscv/include/asm/uprobes.h +++ b/arch/riscv/include/asm/uprobes.h @@ -4,7 +4,7 @@ #define _ASM_RISCV_UPROBES_H #include -#include +#include #include #define MAX_UINSN_BYTES 8 diff --git a/arch/riscv/include/asm/vdso/data.h b/arch/riscv/include/asm/vdso/data.h deleted file mode 100644 index dc2f76f58b7632..00000000000000 --- a/arch/riscv/include/asm/vdso/data.h +++ /dev/null @@ -1,17 +0,0 @@ -/* 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/time_data.h b/arch/riscv/include/asm/vdso/time_data.h new file mode 100644 index 00000000000000..dfa65228999bed --- /dev/null +++ b/arch/riscv/include/asm/vdso/time_data.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __RISCV_ASM_VDSO_TIME_DATA_H +#define __RISCV_ASM_VDSO_TIME_DATA_H + +#include +#include +#include + +struct arch_vdso_time_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_TIME_DATA_H */ diff --git a/arch/riscv/include/asm/vdso/vsyscall.h b/arch/riscv/include/asm/vdso/vsyscall.h index 82fd5d83bd602c..e8a9c4b53c0c9f 100644 --- a/arch/riscv/include/asm/vdso/vsyscall.h +++ b/arch/riscv/include/asm/vdso/vsyscall.h @@ -4,14 +4,10 @@ #ifndef __ASSEMBLY__ -#include #include extern struct vdso_data *vdso_data; -/* - * Update the vDSO data page to keep in sync with kernel timekeeping. - */ static __always_inline struct vdso_data *__riscv_get_k_vdso_data(void) { return vdso_data; diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h index be7d309cca8a78..c7c023afbacd7b 100644 --- a/arch/riscv/include/asm/vector.h +++ b/arch/riscv/include/asm/vector.h @@ -21,6 +21,7 @@ extern unsigned long riscv_v_vsize; int riscv_v_setup_vsize(void); +bool insn_is_vector(u32 insn_buf); bool riscv_v_first_use_handler(struct pt_regs *regs); void kernel_vector_begin(void); void kernel_vector_end(void); @@ -268,6 +269,7 @@ struct pt_regs; static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; } static __always_inline bool has_vector(void) { return false; } +static __always_inline bool insn_is_vector(u32 insn_buf) { return false; } static inline bool riscv_v_first_use_handler(struct pt_regs *regs) { return false; } static inline bool riscv_v_vstate_query(struct pt_regs *regs) { return false; } static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; } diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 1e153cda57db85..3af142b99f778b 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -72,6 +72,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZCF (1ULL << 46) #define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47) #define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48) +#define RISCV_HWPROBE_EXT_SUPM (1ULL << 49) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) @@ -88,6 +89,11 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2 #define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3 #define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4 +#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ /* Flags */ diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index e97db3296456e1..3482c9a73d1b64 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -175,6 +175,10 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_ZCF, KVM_RISCV_ISA_EXT_ZCMOP, KVM_RISCV_ISA_EXT_ZAWRS, + KVM_RISCV_ISA_EXT_SMNPM, + KVM_RISCV_ISA_EXT_SSNPM, + KVM_RISCV_ISA_EXT_SVADE, + KVM_RISCV_ISA_EXT_SVADU, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 69dc8aaab3fb3a..063d1faf5a53d5 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -75,7 +75,8 @@ obj-$(CONFIG_MMU) += vdso.o vdso/ obj-$(CONFIG_RISCV_MISALIGNED) += traps_misaligned.o obj-$(CONFIG_RISCV_MISALIGNED) += unaligned_access_speed.o -obj-$(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS) += copy-unaligned.o +obj-$(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS) += copy-unaligned.o +obj-$(CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS) += vec-copy-unaligned.o obj-$(CONFIG_FPU) += fpu.o obj-$(CONFIG_FPU) += kernel_mode_fpu.o diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c index 0128b161bfdab2..7eb3cb1215c621 100644 --- a/arch/riscv/kernel/alternative.c +++ b/arch/riscv/kernel/alternative.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include struct cpu_manufacturer_info_t { unsigned long vendor_id; diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index c2f3129a8e5cfb..e89455a6a0e50c 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -496,19 +496,19 @@ void asm_offsets(void) OFFSET(STACKFRAME_RA, stackframe, ra); #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS - DEFINE(FREGS_SIZE_ON_STACK, ALIGN(sizeof(struct ftrace_regs), STACK_ALIGN)); - DEFINE(FREGS_EPC, offsetof(struct ftrace_regs, epc)); - DEFINE(FREGS_RA, offsetof(struct ftrace_regs, ra)); - DEFINE(FREGS_SP, offsetof(struct ftrace_regs, sp)); - DEFINE(FREGS_S0, offsetof(struct ftrace_regs, s0)); - DEFINE(FREGS_T1, offsetof(struct ftrace_regs, t1)); - DEFINE(FREGS_A0, offsetof(struct ftrace_regs, a0)); - DEFINE(FREGS_A1, offsetof(struct ftrace_regs, a1)); - DEFINE(FREGS_A2, offsetof(struct ftrace_regs, a2)); - DEFINE(FREGS_A3, offsetof(struct ftrace_regs, a3)); - DEFINE(FREGS_A4, offsetof(struct ftrace_regs, a4)); - DEFINE(FREGS_A5, offsetof(struct ftrace_regs, a5)); - DEFINE(FREGS_A6, offsetof(struct ftrace_regs, a6)); - DEFINE(FREGS_A7, offsetof(struct ftrace_regs, a7)); + DEFINE(FREGS_SIZE_ON_STACK, ALIGN(sizeof(struct __arch_ftrace_regs), STACK_ALIGN)); + DEFINE(FREGS_EPC, offsetof(struct __arch_ftrace_regs, epc)); + DEFINE(FREGS_RA, offsetof(struct __arch_ftrace_regs, ra)); + DEFINE(FREGS_SP, offsetof(struct __arch_ftrace_regs, sp)); + DEFINE(FREGS_S0, offsetof(struct __arch_ftrace_regs, s0)); + DEFINE(FREGS_T1, offsetof(struct __arch_ftrace_regs, t1)); + DEFINE(FREGS_A0, offsetof(struct __arch_ftrace_regs, a0)); + DEFINE(FREGS_A1, offsetof(struct __arch_ftrace_regs, a1)); + DEFINE(FREGS_A2, offsetof(struct __arch_ftrace_regs, a2)); + DEFINE(FREGS_A3, offsetof(struct __arch_ftrace_regs, a3)); + DEFINE(FREGS_A4, offsetof(struct __arch_ftrace_regs, a4)); + DEFINE(FREGS_A5, offsetof(struct __arch_ftrace_regs, a5)); + DEFINE(FREGS_A6, offsetof(struct __arch_ftrace_regs, a6)); + DEFINE(FREGS_A7, offsetof(struct __arch_ftrace_regs, a7)); #endif } diff --git a/arch/riscv/kernel/copy-unaligned.h b/arch/riscv/kernel/copy-unaligned.h index e3d70d35b70819..85d4d11450cb61 100644 --- a/arch/riscv/kernel/copy-unaligned.h +++ b/arch/riscv/kernel/copy-unaligned.h @@ -10,4 +10,9 @@ void __riscv_copy_words_unaligned(void *dst, const void *src, size_t size); void __riscv_copy_bytes_unaligned(void *dst, const void *src, size_t size); +#ifdef CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS +void __riscv_copy_vec_words_unaligned(void *dst, const void *src, size_t size); +void __riscv_copy_vec_bytes_unaligned(void *dst, const void *src, size_t size); +#endif + #endif /* __RISCV_KERNEL_COPY_UNALIGNED_H */ diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 3a8eeaa9310c32..c0916ed318c20e 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -20,7 +20,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -28,6 +29,8 @@ #define NUM_ALPHA_EXTS ('z' - 'a' + 1) +static bool any_cpu_has_zicboz; + unsigned long elf_hwcap __read_mostly; /* Host ISA bitmap */ @@ -98,6 +101,7 @@ static int riscv_ext_zicboz_validate(const struct riscv_isa_ext_data *data, pr_err("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n"); return -EINVAL; } + any_cpu_has_zicboz = true; return 0; } @@ -132,6 +136,16 @@ static int riscv_ext_zcf_validate(const struct riscv_isa_ext_data *data, return -EPROBE_DEFER; } +static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + /* SVADE has already been detected, use SVADE only */ + if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SVADE)) + return -EOPNOTSUPP; + + return 0; +} + static const unsigned int riscv_zk_bundled_exts[] = { RISCV_ISA_EXT_ZBKB, RISCV_ISA_EXT_ZBKC, @@ -314,6 +328,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { riscv_ext_zicbom_validate), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate), + __RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE), __RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR), __RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND), __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR), @@ -322,6 +337,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), __RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM), __RISCV_ISA_EXT_DATA(zimop, RISCV_ISA_EXT_ZIMOP), + __RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA), __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS), __RISCV_ISA_EXT_DATA(zawrs, RISCV_ISA_EXT_ZAWRS), __RISCV_ISA_EXT_DATA(zfa, RISCV_ISA_EXT_ZFA), @@ -374,10 +390,15 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_BUNDLE(zvksg, riscv_zvksg_bundled_exts), __RISCV_ISA_EXT_DATA(zvkt, RISCV_ISA_EXT_ZVKT), __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA), + __RISCV_ISA_EXT_DATA(smmpm, RISCV_ISA_EXT_SMMPM), + __RISCV_ISA_EXT_SUPERSET(smnpm, RISCV_ISA_EXT_SMNPM, riscv_xlinuxenvcfg_exts), __RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN), __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA), __RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), + __RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts), __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), + __RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE), + __RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate), __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), @@ -917,10 +938,12 @@ unsigned long riscv_get_elf_hwcap(void) return hwcap; } -void riscv_user_isa_enable(void) +void __init riscv_user_isa_enable(void) { - if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_ZICBOZ)) - csr_set(CSR_ENVCFG, ENVCFG_CBZE); + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICBOZ)) + current->thread.envcfg |= ENVCFG_CBZE; + else if (any_cpu_has_zicboz) + pr_warn("Zicboz disabled as it is unavailable on some harts\n"); } #ifdef CONFIG_RISCV_ALTERNATIVE diff --git a/arch/riscv/kernel/fpu.S b/arch/riscv/kernel/fpu.S index 327cf527dd7e14..f74f6b60e347f7 100644 --- a/arch/riscv/kernel/fpu.S +++ b/arch/riscv/kernel/fpu.S @@ -170,7 +170,7 @@ SYM_FUNC_END(__fstate_restore) __access_func(f31) -#ifdef CONFIG_RISCV_MISALIGNED +#ifdef CONFIG_RISCV_SCALAR_MISALIGNED /* * Disable compressed instructions set to keep a constant offset between FP @@ -224,4 +224,4 @@ SYM_FUNC_START(get_f64_reg) fp_access_epilogue SYM_FUNC_END(get_f64_reg) -#endif /* CONFIG_RISCV_MISALIGNED */ +#endif /* CONFIG_RISCV_SCALAR_MISALIGNED */ diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 4b95c574fd0457..8cb9b211611d91 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #ifdef CONFIG_DYNAMIC_FTRACE void ftrace_arch_code_modify_prepare(void) __acquires(&text_mutex) @@ -214,7 +214,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { - prepare_ftrace_return(&fregs->ra, ip, fregs->s0); + prepare_ftrace_return(&arch_ftrace_regs(fregs)->ra, ip, arch_ftrace_regs(fregs)->s0); } #else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ extern void ftrace_graph_call(void); diff --git a/arch/riscv/kernel/jump_label.c b/arch/riscv/kernel/jump_label.c index 11ad789c60c698..654ed159c830b3 100644 --- a/arch/riscv/kernel/jump_label.c +++ b/arch/riscv/kernel/jump_label.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #define RISCV_INSN_NOP 0x00000013U #define RISCV_INSN_JAL 0x0000006fU @@ -36,9 +36,15 @@ bool arch_jump_label_transform_queue(struct jump_entry *entry, insn = RISCV_INSN_NOP; } - mutex_lock(&text_mutex); - patch_insn_write(addr, &insn, sizeof(insn)); - mutex_unlock(&text_mutex); + if (early_boot_irqs_disabled) { + riscv_patch_in_stop_machine = 1; + patch_insn_write(addr, &insn, sizeof(insn)); + riscv_patch_in_stop_machine = 0; + } else { + mutex_lock(&text_mutex); + patch_insn_write(addr, &insn, sizeof(insn)); + mutex_unlock(&text_mutex); + } return true; } diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c index 34ef522f07a8c2..db13c9ddf9e3d4 100644 --- a/arch/riscv/kernel/patch.c +++ b/arch/riscv/kernel/patch.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include struct patch_insn { diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c index c7468af77c663a..b465bc9eb870ec 100644 --- a/arch/riscv/kernel/perf_callchain.c +++ b/arch/riscv/kernel/perf_callchain.c @@ -28,11 +28,21 @@ static bool fill_callchain(void *entry, unsigned long pc) void perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) { + if (perf_guest_state()) { + /* TODO: We don't support guest os callchain now */ + return; + } + arch_stack_walk_user(fill_callchain, entry, regs); } void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs) { + if (perf_guest_state()) { + /* TODO: We don't support guest os callchain now */ + return; + } + walk_stackframe(NULL, regs, fill_callchain, entry); } diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c index 474a6521365783..380a0e8cecc0b2 100644 --- a/arch/riscv/kernel/probes/kprobes.c +++ b/arch/riscv/kernel/probes/kprobes.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "decode-insn.h" diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index e3142d8a6e284d..58b6482c2bf662 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -7,6 +7,7 @@ * Copyright (C) 2017 SiFive */ +#include #include #include #include @@ -180,6 +181,10 @@ void flush_thread(void) memset(¤t->thread.vstate, 0, sizeof(struct __riscv_v_ext_state)); clear_tsk_thread_flag(current, TIF_RISCV_V_DEFER_RESTORE); #endif +#ifdef CONFIG_RISCV_ISA_SUPM + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) + envcfg_update_bits(current, ENVCFG_PMM, ENVCFG_PMM_PMLEN_0); +#endif } void arch_release_task_struct(struct task_struct *tsk) @@ -208,6 +213,10 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) unsigned long tls = args->tls; struct pt_regs *childregs = task_pt_regs(p); + /* Ensure all threads in this mm have the same pointer masking mode. */ + if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM) && p->mm && (clone_flags & CLONE_VM)) + set_bit(MM_CONTEXT_LOCK_PMLEN, &p->mm->context.flags); + memset(&p->thread.s, 0, sizeof(p->thread.s)); /* p->thread holds context to be restored by __switch_to() */ @@ -242,3 +251,148 @@ void __init arch_task_cache_init(void) { riscv_v_setup_ctx_cache(); } + +#ifdef CONFIG_RISCV_ISA_SUPM +enum { + PMLEN_0 = 0, + PMLEN_7 = 7, + PMLEN_16 = 16, +}; + +static bool have_user_pmlen_7; +static bool have_user_pmlen_16; + +/* + * Control the relaxed ABI allowing tagged user addresses into the kernel. + */ +static unsigned int tagged_addr_disabled; + +long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg) +{ + unsigned long valid_mask = PR_PMLEN_MASK | PR_TAGGED_ADDR_ENABLE; + struct thread_info *ti = task_thread_info(task); + struct mm_struct *mm = task->mm; + unsigned long pmm; + u8 pmlen; + + if (is_compat_thread(ti)) + return -EINVAL; + + if (arg & ~valid_mask) + return -EINVAL; + + /* + * Prefer the smallest PMLEN that satisfies the user's request, + * in case choosing a larger PMLEN has a performance impact. + */ + pmlen = FIELD_GET(PR_PMLEN_MASK, arg); + if (pmlen == PMLEN_0) { + pmm = ENVCFG_PMM_PMLEN_0; + } else if (pmlen <= PMLEN_7 && have_user_pmlen_7) { + pmlen = PMLEN_7; + pmm = ENVCFG_PMM_PMLEN_7; + } else if (pmlen <= PMLEN_16 && have_user_pmlen_16) { + pmlen = PMLEN_16; + pmm = ENVCFG_PMM_PMLEN_16; + } else { + return -EINVAL; + } + + /* + * Do not allow the enabling of the tagged address ABI if globally + * disabled via sysctl abi.tagged_addr_disabled, if pointer masking + * is disabled for userspace. + */ + if (arg & PR_TAGGED_ADDR_ENABLE && (tagged_addr_disabled || !pmlen)) + return -EINVAL; + + if (!(arg & PR_TAGGED_ADDR_ENABLE)) + pmlen = PMLEN_0; + + if (mmap_write_lock_killable(mm)) + return -EINTR; + + if (test_bit(MM_CONTEXT_LOCK_PMLEN, &mm->context.flags) && mm->context.pmlen != pmlen) { + mmap_write_unlock(mm); + return -EBUSY; + } + + envcfg_update_bits(task, ENVCFG_PMM, pmm); + mm->context.pmlen = pmlen; + + mmap_write_unlock(mm); + + return 0; +} + +long get_tagged_addr_ctrl(struct task_struct *task) +{ + struct thread_info *ti = task_thread_info(task); + long ret = 0; + + if (is_compat_thread(ti)) + return -EINVAL; + + /* + * The mm context's pmlen is set only when the tagged address ABI is + * enabled, so the effective PMLEN must be extracted from envcfg.PMM. + */ + switch (task->thread.envcfg & ENVCFG_PMM) { + case ENVCFG_PMM_PMLEN_7: + ret = FIELD_PREP(PR_PMLEN_MASK, PMLEN_7); + break; + case ENVCFG_PMM_PMLEN_16: + ret = FIELD_PREP(PR_PMLEN_MASK, PMLEN_16); + break; + } + + if (task->mm->context.pmlen) + ret |= PR_TAGGED_ADDR_ENABLE; + + return ret; +} + +static bool try_to_set_pmm(unsigned long value) +{ + csr_set(CSR_ENVCFG, value); + return (csr_read_clear(CSR_ENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value; +} + +/* + * Global sysctl to disable the tagged user addresses support. This control + * only prevents the tagged address ABI enabling via prctl() and does not + * disable it for tasks that already opted in to the relaxed ABI. + */ + +static struct ctl_table tagged_addr_sysctl_table[] = { + { + .procname = "tagged_addr_disabled", + .mode = 0644, + .data = &tagged_addr_disabled, + .maxlen = sizeof(int), + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, +}; + +static int __init tagged_addr_init(void) +{ + if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) + return 0; + + /* + * envcfg.PMM is a WARL field. Detect which values are supported. + * Assume the supported PMLEN values are the same on all harts. + */ + csr_clear(CSR_ENVCFG, ENVCFG_PMM); + have_user_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7); + have_user_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16); + + if (!register_sysctl("abi", tagged_addr_sysctl_table)) + return -EINVAL; + + return 0; +} +core_initcall(tagged_addr_init); +#endif /* CONFIG_RISCV_ISA_SUPM */ diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index 92731ff8c79ad0..ea67e9fb7a5836 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -28,6 +28,9 @@ enum riscv_regset { #ifdef CONFIG_RISCV_ISA_V REGSET_V, #endif +#ifdef CONFIG_RISCV_ISA_SUPM + REGSET_TAGGED_ADDR_CTRL, +#endif }; static int riscv_gpr_get(struct task_struct *target, @@ -152,6 +155,35 @@ static int riscv_vr_set(struct task_struct *target, } #endif +#ifdef CONFIG_RISCV_ISA_SUPM +static int tagged_addr_ctrl_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + long ctrl = get_tagged_addr_ctrl(target); + + if (IS_ERR_VALUE(ctrl)) + return ctrl; + + return membuf_write(&to, &ctrl, sizeof(ctrl)); +} + +static int tagged_addr_ctrl_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + long ctrl; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, 0, -1); + if (ret) + return ret; + + return set_tagged_addr_ctrl(target, ctrl); +} +#endif + static const struct user_regset riscv_user_regset[] = { [REGSET_X] = { .core_note_type = NT_PRSTATUS, @@ -182,6 +214,16 @@ static const struct user_regset riscv_user_regset[] = { .set = riscv_vr_set, }, #endif +#ifdef CONFIG_RISCV_ISA_SUPM + [REGSET_TAGGED_ADDR_CTRL] = { + .core_note_type = NT_RISCV_TAGGED_ADDR_CTRL, + .n = 1, + .size = sizeof(long), + .align = sizeof(long), + .regset_get = tagged_addr_ctrl_get, + .set = tagged_addr_ctrl_set, + }, +#endif }; static const struct user_regset_view riscv_user_native_view = { diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index a2cde65b69e950..45010e71df86ce 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -227,7 +227,7 @@ static void __init init_resources(void) static void __init parse_dtb(void) { /* Early scan of device tree from init memory */ - if (early_init_dt_scan(dtb_early_va)) { + if (early_init_dt_scan(dtb_early_va, dtb_early_pa)) { const char *name = of_flat_dt_get_machine_name(); if (name) { @@ -244,6 +244,42 @@ static void __init parse_dtb(void) #endif } +#if defined(CONFIG_RISCV_COMBO_SPINLOCKS) +DEFINE_STATIC_KEY_TRUE(qspinlock_key); +EXPORT_SYMBOL(qspinlock_key); +#endif + +static void __init riscv_spinlock_init(void) +{ + char *using_ext = NULL; + + if (IS_ENABLED(CONFIG_RISCV_TICKET_SPINLOCKS)) { + pr_info("Ticket spinlock: enabled\n"); + return; + } + + if (IS_ENABLED(CONFIG_RISCV_ISA_ZABHA) && + IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) && + riscv_isa_extension_available(NULL, ZABHA) && + riscv_isa_extension_available(NULL, ZACAS)) { + using_ext = "using Zabha"; + } else if (riscv_isa_extension_available(NULL, ZICCRSE)) { + using_ext = "using Ziccrse"; + } +#if defined(CONFIG_RISCV_COMBO_SPINLOCKS) + else { + static_branch_disable(&qspinlock_key); + pr_info("Ticket spinlock: enabled\n"); + return; + } +#endif + + if (!using_ext) + pr_err("Queued spinlock without Zabha or Ziccrse"); + else + pr_info("Queued spinlock %s: enabled\n", using_ext); +} + extern void __init init_rt_signal_env(void); void __init setup_arch(char **cmdline_p) @@ -297,6 +333,7 @@ void __init setup_arch(char **cmdline_p) riscv_set_dma_cache_alignment(); riscv_user_isa_enable(); + riscv_spinlock_init(); } bool arch_cpu_is_hotpluggable(int cpu) diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 0f8f1c95ac38c9..e36d20205bd7d3 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -233,8 +233,6 @@ asmlinkage __visible void smp_callin(void) numa_add_cpu(curr_cpuid); set_cpu_online(curr_cpuid, true); - riscv_user_isa_enable(); - /* * Remote cache and TLB flushes are ignored while the CPU is offline, * so flush them both right now just in case. diff --git a/arch/riscv/kernel/suspend.c b/arch/riscv/kernel/suspend.c index c8cec0cc5833c4..9a8a0dc035b260 100644 --- a/arch/riscv/kernel/suspend.c +++ b/arch/riscv/kernel/suspend.c @@ -14,7 +14,7 @@ void suspend_save_csrs(struct suspend_context *context) { - if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_XLINUXENVCFG)) + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_XLINUXENVCFG)) context->envcfg = csr_read(CSR_ENVCFG); context->tvec = csr_read(CSR_TVEC); context->ie = csr_read(CSR_IE); @@ -37,7 +37,7 @@ void suspend_save_csrs(struct suspend_context *context) void suspend_restore_csrs(struct suspend_context *context) { csr_write(CSR_SCRATCH, 0); - if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_XLINUXENVCFG)) + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_XLINUXENVCFG)) csr_write(CSR_ENVCFG, context->envcfg); csr_write(CSR_TVEC, context->tvec); csr_write(CSR_IE, context->ie); diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index cea0ca2bf2a25e..cb93adfffc486e 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -150,6 +150,9 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, EXT_KEY(ZFH); EXT_KEY(ZFHMIN); } + + if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM)) + EXT_KEY(SUPM); #undef EXT_KEY } @@ -201,6 +204,43 @@ static u64 hwprobe_misaligned(const struct cpumask *cpus) } #endif +#ifdef CONFIG_RISCV_VECTOR_MISALIGNED +static u64 hwprobe_vec_misaligned(const struct cpumask *cpus) +{ + int cpu; + u64 perf = -1ULL; + + /* Return if supported or not even if speed wasn't probed */ + for_each_cpu(cpu, cpus) { + int this_perf = per_cpu(vector_misaligned_access, cpu); + + if (perf == -1ULL) + perf = this_perf; + + if (perf != this_perf) { + perf = RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN; + break; + } + } + + if (perf == -1ULL) + return RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN; + + return perf; +} +#else +static u64 hwprobe_vec_misaligned(const struct cpumask *cpus) +{ + if (IS_ENABLED(CONFIG_RISCV_EFFICIENT_VECTOR_UNALIGNED_ACCESS)) + return RISCV_HWPROBE_MISALIGNED_VECTOR_FAST; + + if (IS_ENABLED(CONFIG_RISCV_SLOW_VECTOR_UNALIGNED_ACCESS)) + return RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW; + + return RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN; +} +#endif + static void hwprobe_one_pair(struct riscv_hwprobe *pair, const struct cpumask *cpus) { @@ -229,6 +269,10 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair, pair->value = hwprobe_misaligned(cpus); break; + case RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF: + pair->value = hwprobe_vec_misaligned(cpus); + break; + case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE: pair->value = 0; if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ)) @@ -402,7 +446,7 @@ static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs, 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; + struct arch_vdso_time_data *avd = &vd->arch_data; u64 id_bitsmash = 0; struct riscv_hwprobe pair; int key; diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 1b9867136b6100..7cc108aed74e8b 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -16,6 +16,7 @@ #include #include #include +#include #define INSN_MATCH_LB 0x3 #define INSN_MASK_LB 0x707f @@ -320,12 +321,37 @@ union reg_data { u64 data_u64; }; -static bool unaligned_ctl __read_mostly; - /* sysctl hooks */ int unaligned_enabled __read_mostly = 1; /* Enabled by default */ -int handle_misaligned_load(struct pt_regs *regs) +#ifdef CONFIG_RISCV_VECTOR_MISALIGNED +static int handle_vector_misaligned_load(struct pt_regs *regs) +{ + unsigned long epc = regs->epc; + unsigned long insn; + + if (get_insn(regs, epc, &insn)) + return -1; + + /* Only return 0 when in check_vector_unaligned_access_emulated */ + if (*this_cpu_ptr(&vector_misaligned_access) == RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN) { + *this_cpu_ptr(&vector_misaligned_access) = RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED; + regs->epc = epc + INSN_LEN(insn); + return 0; + } + + /* If vector instruction we don't emulate it yet */ + regs->epc = epc; + return -1; +} +#else +static int handle_vector_misaligned_load(struct pt_regs *regs) +{ + return -1; +} +#endif + +static int handle_scalar_misaligned_load(struct pt_regs *regs) { union reg_data val; unsigned long epc = regs->epc; @@ -433,7 +459,7 @@ int handle_misaligned_load(struct pt_regs *regs) return 0; } -int handle_misaligned_store(struct pt_regs *regs) +static int handle_scalar_misaligned_store(struct pt_regs *regs) { union reg_data val; unsigned long epc = regs->epc; @@ -524,11 +550,96 @@ int handle_misaligned_store(struct pt_regs *regs) return 0; } -static bool check_unaligned_access_emulated(int cpu) +int handle_misaligned_load(struct pt_regs *regs) +{ + unsigned long epc = regs->epc; + unsigned long insn; + + if (IS_ENABLED(CONFIG_RISCV_VECTOR_MISALIGNED)) { + if (get_insn(regs, epc, &insn)) + return -1; + + if (insn_is_vector(insn)) + return handle_vector_misaligned_load(regs); + } + + if (IS_ENABLED(CONFIG_RISCV_SCALAR_MISALIGNED)) + return handle_scalar_misaligned_load(regs); + + return -1; +} + +int handle_misaligned_store(struct pt_regs *regs) { + if (IS_ENABLED(CONFIG_RISCV_SCALAR_MISALIGNED)) + return handle_scalar_misaligned_store(regs); + + return -1; +} + +#ifdef CONFIG_RISCV_VECTOR_MISALIGNED +void check_vector_unaligned_access_emulated(struct work_struct *work __always_unused) +{ + long *mas_ptr = this_cpu_ptr(&vector_misaligned_access); + unsigned long tmp_var; + + *mas_ptr = RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN; + + kernel_vector_begin(); + /* + * In pre-13.0.0 versions of GCC, vector registers cannot appear in + * the clobber list. This inline asm clobbers v0, but since we do not + * currently build the kernel with V enabled, the v0 clobber arg is not + * needed (as the compiler will not emit vector code itself). If the kernel + * is changed to build with V enabled, the clobber arg will need to be + * added here. + */ + __asm__ __volatile__ ( + ".balign 4\n\t" + ".option push\n\t" + ".option arch, +zve32x\n\t" + " vsetivli zero, 1, e16, m1, ta, ma\n\t" // Vectors of 16b + " vle16.v v0, (%[ptr])\n\t" // Load bytes + ".option pop\n\t" + : : [ptr] "r" ((u8 *)&tmp_var + 1)); + kernel_vector_end(); +} + +bool check_vector_unaligned_access_emulated_all_cpus(void) +{ + int cpu; + + if (!has_vector()) { + for_each_online_cpu(cpu) + per_cpu(vector_misaligned_access, cpu) = RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED; + return false; + } + + schedule_on_each_cpu(check_vector_unaligned_access_emulated); + + for_each_online_cpu(cpu) + if (per_cpu(vector_misaligned_access, cpu) + == RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN) + return false; + + return true; +} +#else +bool check_vector_unaligned_access_emulated_all_cpus(void) +{ + return false; +} +#endif + +#ifdef CONFIG_RISCV_SCALAR_MISALIGNED + +static bool unaligned_ctl __read_mostly; + +void check_unaligned_access_emulated(struct work_struct *work __always_unused) +{ + int cpu = smp_processor_id(); long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu); unsigned long tmp_var, tmp_val; - bool misaligned_emu_detected; *mas_ptr = RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN; @@ -536,19 +647,16 @@ static bool check_unaligned_access_emulated(int cpu) " "REG_L" %[tmp], 1(%[ptr])\n" : [tmp] "=r" (tmp_val) : [ptr] "r" (&tmp_var) : "memory"); - misaligned_emu_detected = (*mas_ptr == RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED); /* * If unaligned_ctl is already set, this means that we detected that all * CPUS uses emulated misaligned access at boot time. If that changed * when hotplugging the new cpu, this is something we don't handle. */ - if (unlikely(unaligned_ctl && !misaligned_emu_detected)) { + if (unlikely(unaligned_ctl && (*mas_ptr != RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED))) { pr_crit("CPU misaligned accesses non homogeneous (expected all emulated)\n"); while (true) cpu_relax(); } - - return misaligned_emu_detected; } bool check_unaligned_access_emulated_all_cpus(void) @@ -560,8 +668,11 @@ bool check_unaligned_access_emulated_all_cpus(void) * accesses emulated since tasks requesting such control can run on any * CPU. */ + schedule_on_each_cpu(check_unaligned_access_emulated); + for_each_online_cpu(cpu) - if (!check_unaligned_access_emulated(cpu)) + if (per_cpu(misaligned_access_speed, cpu) + != RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED) return false; unaligned_ctl = true; @@ -572,3 +683,9 @@ bool unaligned_ctl_available(void) { return unaligned_ctl; } +#else +bool check_unaligned_access_emulated_all_cpus(void) +{ + return false; +} +#endif diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c index 160628a2116de4..91f189cf16113c 100644 --- a/arch/riscv/kernel/unaligned_access_speed.c +++ b/arch/riscv/kernel/unaligned_access_speed.c @@ -6,11 +6,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "copy-unaligned.h" @@ -19,7 +21,8 @@ #define MISALIGNED_BUFFER_ORDER get_order(MISALIGNED_BUFFER_SIZE) #define MISALIGNED_COPY_SIZE ((MISALIGNED_BUFFER_SIZE / 2) - 0x80) -DEFINE_PER_CPU(long, misaligned_access_speed); +DEFINE_PER_CPU(long, misaligned_access_speed) = RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN; +DEFINE_PER_CPU(long, vector_misaligned_access) = RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED; #ifdef CONFIG_RISCV_PROBE_UNALIGNED_ACCESS static cpumask_t fast_misaligned_access; @@ -191,6 +194,7 @@ static int riscv_online_cpu(unsigned int cpu) if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) goto exit; + check_unaligned_access_emulated(NULL); buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); if (!buf) { pr_warn("Allocation failure, not measuring misaligned performance\n"); @@ -259,23 +263,159 @@ static int check_unaligned_access_speed_all_cpus(void) kfree(bufs); return 0; } +#else /* CONFIG_RISCV_PROBE_UNALIGNED_ACCESS */ +static int check_unaligned_access_speed_all_cpus(void) +{ + return 0; +} +#endif -static int check_unaligned_access_all_cpus(void) +#ifdef CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS +static void check_vector_unaligned_access(struct work_struct *work __always_unused) { - bool all_cpus_emulated = check_unaligned_access_emulated_all_cpus(); + int cpu = smp_processor_id(); + u64 start_cycles, end_cycles; + u64 word_cycles; + u64 byte_cycles; + int ratio; + unsigned long start_jiffies, now; + struct page *page; + void *dst; + void *src; + long speed = RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW; - if (!all_cpus_emulated) - return check_unaligned_access_speed_all_cpus(); + if (per_cpu(vector_misaligned_access, cpu) != RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN) + return; + + page = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); + if (!page) { + pr_warn("Allocation failure, not measuring vector misaligned performance\n"); + return; + } + + /* Make an unaligned destination buffer. */ + dst = (void *)((unsigned long)page_address(page) | 0x1); + /* Unalign src as well, but differently (off by 1 + 2 = 3). */ + src = dst + (MISALIGNED_BUFFER_SIZE / 2); + src += 2; + word_cycles = -1ULL; + + /* Do a warmup. */ + kernel_vector_begin(); + __riscv_copy_vec_words_unaligned(dst, src, MISALIGNED_COPY_SIZE); + start_jiffies = jiffies; + while ((now = jiffies) == start_jiffies) + cpu_relax(); + + /* + * For a fixed amount of time, repeatedly try the function, and take + * the best time in cycles as the measurement. + */ + while (time_before(jiffies, now + (1 << MISALIGNED_ACCESS_JIFFIES_LG2))) { + start_cycles = get_cycles64(); + /* Ensure the CSR read can't reorder WRT to the copy. */ + mb(); + __riscv_copy_vec_words_unaligned(dst, src, MISALIGNED_COPY_SIZE); + /* Ensure the copy ends before the end time is snapped. */ + mb(); + end_cycles = get_cycles64(); + if ((end_cycles - start_cycles) < word_cycles) + word_cycles = end_cycles - start_cycles; + } + + byte_cycles = -1ULL; + __riscv_copy_vec_bytes_unaligned(dst, src, MISALIGNED_COPY_SIZE); + start_jiffies = jiffies; + while ((now = jiffies) == start_jiffies) + cpu_relax(); + + while (time_before(jiffies, now + (1 << MISALIGNED_ACCESS_JIFFIES_LG2))) { + start_cycles = get_cycles64(); + /* Ensure the CSR read can't reorder WRT to the copy. */ + mb(); + __riscv_copy_vec_bytes_unaligned(dst, src, MISALIGNED_COPY_SIZE); + /* Ensure the copy ends before the end time is snapped. */ + mb(); + end_cycles = get_cycles64(); + if ((end_cycles - start_cycles) < byte_cycles) + byte_cycles = end_cycles - start_cycles; + } + + kernel_vector_end(); + + /* Don't divide by zero. */ + if (!word_cycles || !byte_cycles) { + pr_warn("cpu%d: rdtime lacks granularity needed to measure unaligned vector access speed\n", + cpu); + + return; + } + + if (word_cycles < byte_cycles) + speed = RISCV_HWPROBE_MISALIGNED_VECTOR_FAST; + + ratio = div_u64((byte_cycles * 100), word_cycles); + pr_info("cpu%d: Ratio of vector byte access time to vector unaligned word access is %d.%02d, unaligned accesses are %s\n", + cpu, + ratio / 100, + ratio % 100, + (speed == RISCV_HWPROBE_MISALIGNED_VECTOR_FAST) ? "fast" : "slow"); + + per_cpu(vector_misaligned_access, cpu) = speed; +} + +static int riscv_online_cpu_vec(unsigned int cpu) +{ + if (!has_vector()) + return 0; + + if (per_cpu(vector_misaligned_access, cpu) != RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED) + return 0; + + check_vector_unaligned_access_emulated(NULL); + check_vector_unaligned_access(NULL); return 0; } -#else /* CONFIG_RISCV_PROBE_UNALIGNED_ACCESS */ -static int check_unaligned_access_all_cpus(void) + +/* Measure unaligned access speed on all CPUs present at boot in parallel. */ +static int vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused) { - check_unaligned_access_emulated_all_cpus(); + schedule_on_each_cpu(check_vector_unaligned_access); + + /* + * Setup hotplug callbacks for any new CPUs that come online or go + * offline. + */ + cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "riscv:online", + riscv_online_cpu_vec, NULL); return 0; } +#else /* CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS */ +static int vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused) +{ + return 0; +} #endif +static int check_unaligned_access_all_cpus(void) +{ + bool all_cpus_emulated, all_cpus_vec_unsupported; + + all_cpus_emulated = check_unaligned_access_emulated_all_cpus(); + all_cpus_vec_unsupported = check_vector_unaligned_access_emulated_all_cpus(); + + if (!all_cpus_vec_unsupported && + IS_ENABLED(CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS)) { + kthread_run(vec_check_unaligned_access_speed_all_cpus, + NULL, "vec_check_unaligned_access_speed_all_cpus"); + } + + if (!all_cpus_emulated) + return check_unaligned_access_speed_all_cpus(); + + return 0; +} + arch_initcall(check_unaligned_access_all_cpus); diff --git a/arch/riscv/kernel/vdso.c b/arch/riscv/kernel/vdso.c index 98315b98256df4..3ca3ae4277e187 100644 --- a/arch/riscv/kernel/vdso.c +++ b/arch/riscv/kernel/vdso.c @@ -23,11 +23,6 @@ enum vvar_pages { VVAR_NR_PAGES, }; -enum rv_vdso_map { - RV_VDSO_MAP_VVAR, - RV_VDSO_MAP_VDSO, -}; - #define VVAR_SIZE (VVAR_NR_PAGES << PAGE_SHIFT) static union vdso_data_store vdso_data_store __page_aligned_data; @@ -38,8 +33,6 @@ struct __vdso_info { const char *vdso_code_start; const char *vdso_code_end; unsigned long vdso_pages; - /* Data Mapping */ - struct vm_special_mapping *dm; /* Code Mapping */ struct vm_special_mapping *cm; }; @@ -92,6 +85,8 @@ struct vdso_data *arch_get_vdso_data(void *vvar_page) return (struct vdso_data *)(vvar_page); } +static const struct vm_special_mapping rv_vvar_map; + /* * The vvar mapping contains data for a specific time namespace, so when a task * changes namespace we must unmap its vvar data for the old namespace. @@ -108,12 +103,8 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns) mmap_read_lock(mm); for_each_vma(vmi, vma) { - if (vma_is_special_mapping(vma, vdso_info.dm)) - zap_vma_pages(vma); -#ifdef CONFIG_COMPAT - if (vma_is_special_mapping(vma, compat_vdso_info.dm)) + if (vma_is_special_mapping(vma, &rv_vvar_map)) zap_vma_pages(vma); -#endif } mmap_read_unlock(mm); @@ -155,43 +146,34 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, return vmf_insert_pfn(vma, vmf->address, pfn); } -static struct vm_special_mapping rv_vdso_maps[] __ro_after_init = { - [RV_VDSO_MAP_VVAR] = { - .name = "[vvar]", - .fault = vvar_fault, - }, - [RV_VDSO_MAP_VDSO] = { - .name = "[vdso]", - .mremap = vdso_mremap, - }, +static const struct vm_special_mapping rv_vvar_map = { + .name = "[vvar]", + .fault = vvar_fault, +}; + +static struct vm_special_mapping rv_vdso_map __ro_after_init = { + .name = "[vdso]", + .mremap = vdso_mremap, }; static struct __vdso_info vdso_info __ro_after_init = { .name = "vdso", .vdso_code_start = vdso_start, .vdso_code_end = vdso_end, - .dm = &rv_vdso_maps[RV_VDSO_MAP_VVAR], - .cm = &rv_vdso_maps[RV_VDSO_MAP_VDSO], + .cm = &rv_vdso_map, }; #ifdef CONFIG_COMPAT -static struct vm_special_mapping rv_compat_vdso_maps[] __ro_after_init = { - [RV_VDSO_MAP_VVAR] = { - .name = "[vvar]", - .fault = vvar_fault, - }, - [RV_VDSO_MAP_VDSO] = { - .name = "[vdso]", - .mremap = vdso_mremap, - }, +static struct vm_special_mapping rv_compat_vdso_map __ro_after_init = { + .name = "[vdso]", + .mremap = vdso_mremap, }; static struct __vdso_info compat_vdso_info __ro_after_init = { .name = "compat_vdso", .vdso_code_start = compat_vdso_start, .vdso_code_end = compat_vdso_end, - .dm = &rv_compat_vdso_maps[RV_VDSO_MAP_VVAR], - .cm = &rv_compat_vdso_maps[RV_VDSO_MAP_VDSO], + .cm = &rv_compat_vdso_map, }; #endif @@ -227,7 +209,7 @@ static int __setup_additional_pages(struct mm_struct *mm, } ret = _install_special_mapping(mm, vdso_base, VVAR_SIZE, - (VM_READ | VM_MAYREAD | VM_PFNMAP), vdso_info->dm); + (VM_READ | VM_MAYREAD | VM_PFNMAP), &rv_vvar_map); if (IS_ERR(ret)) goto up_fail; diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index 3f1c4b2d0b0642..9a1b555e87331f 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile @@ -45,7 +45,7 @@ $(obj)/vdso.o: $(obj)/vdso.so # link rule for the .so file, .lds has to be first $(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE - $(call if_changed,vdsold) + $(call if_changed,vdsold_and_check) LDFLAGS_vdso.so.dbg = -shared -soname=linux-vdso.so.1 \ --build-id=sha1 --hash-style=both --eh-frame-hdr @@ -65,7 +65,8 @@ include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE # actual build commands # The DSO images are built using a special linker script # Make sure only to export the intended __vdso_xxx symbol offsets. -quiet_cmd_vdsold = VDSOLD $@ - cmd_vdsold = $(LD) $(ld_flags) -T $(filter-out FORCE,$^) -o $@.tmp && \ +quiet_cmd_vdsold_and_check = VDSOLD $@ + cmd_vdsold_and_check = $(LD) $(ld_flags) -T $(filter-out FORCE,$^) -o $@.tmp && \ $(OBJCOPY) $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ && \ - rm $@.tmp + rm $@.tmp && \ + $(cmd_vdso_check) diff --git a/arch/riscv/kernel/vdso/hwprobe.c b/arch/riscv/kernel/vdso/hwprobe.c index 1e926e4b5881b6..a158c029344f60 100644 --- a/arch/riscv/kernel/vdso/hwprobe.c +++ b/arch/riscv/kernel/vdso/hwprobe.c @@ -17,7 +17,7 @@ static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count, unsigned int flags) { const struct vdso_data *vd = __arch_get_vdso_data(); - const struct arch_vdso_data *avd = &vd->arch_data; + const struct arch_vdso_time_data *avd = &vd->arch_data; bool all_cpus = !cpusetsize && !cpus; struct riscv_hwprobe *p = pairs; struct riscv_hwprobe *end = pairs + pair_count; @@ -52,7 +52,7 @@ static int riscv_vdso_get_cpus(struct riscv_hwprobe *pairs, size_t pair_count, unsigned int flags) { const struct vdso_data *vd = __arch_get_vdso_data(); - const struct arch_vdso_data *avd = &vd->arch_data; + const struct arch_vdso_time_data *avd = &vd->arch_data; struct riscv_hwprobe *p = pairs; struct riscv_hwprobe *end = pairs + pair_count; unsigned char *c = (unsigned char *)cpus; diff --git a/arch/riscv/kernel/vec-copy-unaligned.S b/arch/riscv/kernel/vec-copy-unaligned.S new file mode 100644 index 00000000000000..d16f19f1b3b65f --- /dev/null +++ b/arch/riscv/kernel/vec-copy-unaligned.S @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2024 Rivos Inc. */ + +#include +#include +#include + + .text + +#define WORD_EEW 32 + +#define WORD_SEW CONCATENATE(e, WORD_EEW) +#define VEC_L CONCATENATE(vle, WORD_EEW).v +#define VEC_S CONCATENATE(vle, WORD_EEW).v + +/* void __riscv_copy_vec_words_unaligned(void *, const void *, size_t) */ +/* Performs a memcpy without aligning buffers, using word loads and stores. */ +/* Note: The size is truncated to a multiple of WORD_EEW */ +SYM_FUNC_START(__riscv_copy_vec_words_unaligned) + andi a4, a2, ~(WORD_EEW-1) + beqz a4, 2f + add a3, a1, a4 + .option push + .option arch, +zve32x +1: + vsetivli t0, 8, WORD_SEW, m8, ta, ma + VEC_L v0, (a1) + VEC_S v0, (a0) + addi a0, a0, WORD_EEW + addi a1, a1, WORD_EEW + bltu a1, a3, 1b + +2: + .option pop + ret +SYM_FUNC_END(__riscv_copy_vec_words_unaligned) + +/* void __riscv_copy_vec_bytes_unaligned(void *, const void *, size_t) */ +/* Performs a memcpy without aligning buffers, using only byte accesses. */ +/* Note: The size is truncated to a multiple of 8 */ +SYM_FUNC_START(__riscv_copy_vec_bytes_unaligned) + andi a4, a2, ~(8-1) + beqz a4, 2f + add a3, a1, a4 + .option push + .option arch, +zve32x +1: + vsetivli t0, 8, e8, m8, ta, ma + vle8.v v0, (a1) + vse8.v v0, (a0) + addi a0, a0, 8 + addi a1, a1, 8 + bltu a1, a3, 1b + +2: + .option pop + ret +SYM_FUNC_END(__riscv_copy_vec_bytes_unaligned) diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c index 682b3feee45114..821818886fab06 100644 --- a/arch/riscv/kernel/vector.c +++ b/arch/riscv/kernel/vector.c @@ -66,7 +66,7 @@ void __init riscv_v_setup_ctx_cache(void) #endif } -static bool insn_is_vector(u32 insn_buf) +bool insn_is_vector(u32 insn_buf) { u32 opcode = insn_buf & __INSN_OPCODE_MASK; u32 width, csr; diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig index 26d1727f0550d3..0c3cbb0915ffa0 100644 --- a/arch/riscv/kvm/Kconfig +++ b/arch/riscv/kvm/Kconfig @@ -32,6 +32,7 @@ config KVM select KVM_XFER_TO_GUEST_WORK select KVM_GENERIC_MMU_NOTIFIER select SCHED_INFO + select GUEST_PERF_EVENTS if PERF_EVENTS help Support hosting virtualized guest machines. diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index c2cacfbc06a06c..0fb1840c3e0ad4 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -9,27 +9,30 @@ include $(srctree)/virt/kvm/Makefile.kvm obj-$(CONFIG_KVM) += kvm.o +# Ordered alphabetically +kvm-y += aia.o +kvm-y += aia_aplic.o +kvm-y += aia_device.o +kvm-y += aia_imsic.o kvm-y += main.o -kvm-y += vm.o -kvm-y += vmid.o -kvm-y += tlb.o kvm-y += mmu.o +kvm-y += nacl.o +kvm-y += tlb.o kvm-y += vcpu.o kvm-y += vcpu_exit.o kvm-y += vcpu_fp.o -kvm-y += vcpu_vector.o kvm-y += vcpu_insn.o kvm-y += vcpu_onereg.o -kvm-y += vcpu_switch.o +kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o kvm-y += vcpu_sbi.o -kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o kvm-y += vcpu_sbi_base.o -kvm-y += vcpu_sbi_replace.o kvm-y += vcpu_sbi_hsm.o +kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_sbi_pmu.o +kvm-y += vcpu_sbi_replace.o kvm-y += vcpu_sbi_sta.o +kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o +kvm-y += vcpu_switch.o kvm-y += vcpu_timer.o -kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o vcpu_sbi_pmu.o -kvm-y += aia.o -kvm-y += aia_device.o -kvm-y += aia_aplic.o -kvm-y += aia_imsic.o +kvm-y += vcpu_vector.o +kvm-y += vm.o +kvm-y += vmid.o diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c index 2967d305c44278..19afd1f2353776 100644 --- a/arch/riscv/kvm/aia.c +++ b/arch/riscv/kvm/aia.c @@ -16,6 +16,7 @@ #include #include #include +#include struct aia_hgei_control { raw_spinlock_t lock; @@ -51,7 +52,7 @@ static int aia_find_hgei(struct kvm_vcpu *owner) return hgei; } -static void aia_set_hvictl(bool ext_irq_pending) +static inline unsigned long aia_hvictl_value(bool ext_irq_pending) { unsigned long hvictl; @@ -62,7 +63,7 @@ static void aia_set_hvictl(bool ext_irq_pending) hvictl = (IRQ_S_EXT << HVICTL_IID_SHIFT) & HVICTL_IID; hvictl |= ext_irq_pending; - csr_write(CSR_HVICTL, hvictl); + return hvictl; } #ifdef CONFIG_32BIT @@ -88,7 +89,7 @@ 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); + csr->vsieh = ncsr_read(CSR_VSIEH); } #endif @@ -115,7 +116,7 @@ bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) hgei = aia_find_hgei(vcpu); if (hgei > 0) - return !!(csr_read(CSR_HGEIP) & BIT(hgei)); + return !!(ncsr_read(CSR_HGEIP) & BIT(hgei)); return false; } @@ -128,45 +129,73 @@ void kvm_riscv_vcpu_aia_update_hvip(struct kvm_vcpu *vcpu) return; #ifdef CONFIG_32BIT - csr_write(CSR_HVIPH, vcpu->arch.aia_context.guest_csr.hviph); + ncsr_write(CSR_HVIPH, vcpu->arch.aia_context.guest_csr.hviph); #endif - aia_set_hvictl(!!(csr->hvip & BIT(IRQ_VS_EXT))); + ncsr_write(CSR_HVICTL, aia_hvictl_value(!!(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; + void *nsh; if (!kvm_riscv_aia_available()) return; - csr_write(CSR_VSISELECT, csr->vsiselect); - csr_write(CSR_HVIPRIO1, csr->hviprio1); - csr_write(CSR_HVIPRIO2, csr->hviprio2); + if (kvm_riscv_nacl_sync_csr_available()) { + nsh = nacl_shmem(); + nacl_csr_write(nsh, CSR_VSISELECT, csr->vsiselect); + nacl_csr_write(nsh, CSR_HVIPRIO1, csr->hviprio1); + nacl_csr_write(nsh, CSR_HVIPRIO2, csr->hviprio2); +#ifdef CONFIG_32BIT + nacl_csr_write(nsh, CSR_VSIEH, csr->vsieh); + nacl_csr_write(nsh, CSR_HVIPH, csr->hviph); + nacl_csr_write(nsh, CSR_HVIPRIO1H, csr->hviprio1h); + nacl_csr_write(nsh, CSR_HVIPRIO2H, csr->hviprio2h); +#endif + } else { + 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); + 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; + void *nsh; if (!kvm_riscv_aia_available()) return; - csr->vsiselect = csr_read(CSR_VSISELECT); - csr->hviprio1 = csr_read(CSR_HVIPRIO1); - csr->hviprio2 = csr_read(CSR_HVIPRIO2); + if (kvm_riscv_nacl_available()) { + nsh = nacl_shmem(); + csr->vsiselect = nacl_csr_read(nsh, CSR_VSISELECT); + csr->hviprio1 = nacl_csr_read(nsh, CSR_HVIPRIO1); + csr->hviprio2 = nacl_csr_read(nsh, 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); + csr->vsieh = nacl_csr_read(nsh, CSR_VSIEH); + csr->hviph = nacl_csr_read(nsh, CSR_HVIPH); + csr->hviprio1h = nacl_csr_read(nsh, CSR_HVIPRIO1H); + csr->hviprio2h = nacl_csr_read(nsh, CSR_HVIPRIO2H); #endif + } else { + 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, @@ -250,20 +279,20 @@ static u8 aia_get_iprio8(struct kvm_vcpu *vcpu, unsigned int irq) switch (bitpos / BITS_PER_LONG) { case 0: - hviprio = csr_read(CSR_HVIPRIO1); + hviprio = ncsr_read(CSR_HVIPRIO1); break; case 1: #ifndef CONFIG_32BIT - hviprio = csr_read(CSR_HVIPRIO2); + hviprio = ncsr_read(CSR_HVIPRIO2); break; #else - hviprio = csr_read(CSR_HVIPRIO1H); + hviprio = ncsr_read(CSR_HVIPRIO1H); break; case 2: - hviprio = csr_read(CSR_HVIPRIO2); + hviprio = ncsr_read(CSR_HVIPRIO2); break; case 3: - hviprio = csr_read(CSR_HVIPRIO2H); + hviprio = ncsr_read(CSR_HVIPRIO2H); break; #endif default: @@ -283,20 +312,20 @@ static void aia_set_iprio8(struct kvm_vcpu *vcpu, unsigned int irq, u8 prio) switch (bitpos / BITS_PER_LONG) { case 0: - hviprio = csr_read(CSR_HVIPRIO1); + hviprio = ncsr_read(CSR_HVIPRIO1); break; case 1: #ifndef CONFIG_32BIT - hviprio = csr_read(CSR_HVIPRIO2); + hviprio = ncsr_read(CSR_HVIPRIO2); break; #else - hviprio = csr_read(CSR_HVIPRIO1H); + hviprio = ncsr_read(CSR_HVIPRIO1H); break; case 2: - hviprio = csr_read(CSR_HVIPRIO2); + hviprio = ncsr_read(CSR_HVIPRIO2); break; case 3: - hviprio = csr_read(CSR_HVIPRIO2H); + hviprio = ncsr_read(CSR_HVIPRIO2H); break; #endif default: @@ -308,20 +337,20 @@ static void aia_set_iprio8(struct kvm_vcpu *vcpu, unsigned int irq, u8 prio) switch (bitpos / BITS_PER_LONG) { case 0: - csr_write(CSR_HVIPRIO1, hviprio); + ncsr_write(CSR_HVIPRIO1, hviprio); break; case 1: #ifndef CONFIG_32BIT - csr_write(CSR_HVIPRIO2, hviprio); + ncsr_write(CSR_HVIPRIO2, hviprio); break; #else - csr_write(CSR_HVIPRIO1H, hviprio); + ncsr_write(CSR_HVIPRIO1H, hviprio); break; case 2: - csr_write(CSR_HVIPRIO2, hviprio); + ncsr_write(CSR_HVIPRIO2, hviprio); break; case 3: - csr_write(CSR_HVIPRIO2H, hviprio); + ncsr_write(CSR_HVIPRIO2H, hviprio); break; #endif default: @@ -377,7 +406,7 @@ int kvm_riscv_vcpu_aia_rmw_ireg(struct kvm_vcpu *vcpu, unsigned int csr_num, return KVM_INSN_ILLEGAL_TRAP; /* First try to emulate in kernel space */ - isel = csr_read(CSR_VSISELECT) & ISELECT_MASK; + isel = ncsr_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 && @@ -499,6 +528,10 @@ static int aia_hgei_init(void) hgctrl->free_bitmap = 0; } + /* Skip SGEI interrupt setup for zero guest external interrupts */ + if (!kvm_riscv_aia_nr_hgei) + goto skip_sgei_interrupt; + /* Find INTC irq domain */ domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY); @@ -522,11 +555,16 @@ static int aia_hgei_init(void) return rc; } +skip_sgei_interrupt: return 0; } static void aia_hgei_exit(void) { + /* Do nothing for zero guest external interrupts */ + if (!kvm_riscv_aia_nr_hgei) + return; + /* Free per-CPU SGEI interrupt */ free_percpu_irq(hgei_parent_irq, &aia_hgei); } @@ -536,7 +574,7 @@ void kvm_riscv_aia_enable(void) if (!kvm_riscv_aia_available()) return; - aia_set_hvictl(false); + csr_write(CSR_HVICTL, aia_hvictl_value(false)); csr_write(CSR_HVIPRIO1, 0x0); csr_write(CSR_HVIPRIO2, 0x0); #ifdef CONFIG_32BIT @@ -552,7 +590,7 @@ void kvm_riscv_aia_enable(void) csr_set(CSR_HIE, BIT(IRQ_S_GEXT)); /* Enable IRQ filtering for overflow interrupt only if sscofpmf is present */ if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_SSCOFPMF)) - csr_write(CSR_HVIEN, BIT(IRQ_PMU_OVF)); + csr_set(CSR_HVIEN, BIT(IRQ_PMU_OVF)); } void kvm_riscv_aia_disable(void) @@ -572,7 +610,7 @@ void kvm_riscv_aia_disable(void) csr_clear(CSR_HIE, BIT(IRQ_S_GEXT)); disable_percpu_irq(hgei_parent_irq); - aia_set_hvictl(false); + csr_write(CSR_HVICTL, aia_hvictl_value(false)); raw_spin_lock_irqsave(&hgctrl->lock, flags); diff --git a/arch/riscv/kvm/aia_aplic.c b/arch/riscv/kvm/aia_aplic.c index da6ff1bade0df5..f59d1c0c8c43a7 100644 --- a/arch/riscv/kvm/aia_aplic.c +++ b/arch/riscv/kvm/aia_aplic.c @@ -143,7 +143,7 @@ static void aplic_write_pending(struct aplic *aplic, u32 irq, bool pending) if (sm == APLIC_SOURCECFG_SM_LEVEL_HIGH || sm == APLIC_SOURCECFG_SM_LEVEL_LOW) { if (!pending) - goto skip_write_pending; + goto noskip_write_pending; if ((irqd->state & APLIC_IRQ_STATE_INPUT) && sm == APLIC_SOURCECFG_SM_LEVEL_LOW) goto skip_write_pending; @@ -152,6 +152,7 @@ static void aplic_write_pending(struct aplic *aplic, u32 irq, bool pending) goto skip_write_pending; } +noskip_write_pending: if (pending) irqd->state |= APLIC_IRQ_STATE_PENDING; else diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index f3427f6de60807..1fa8be5ee5097f 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include long kvm_arch_dev_ioctl(struct file *filp, @@ -22,6 +22,12 @@ long kvm_arch_dev_ioctl(struct file *filp, int kvm_arch_enable_virtualization_cpu(void) { + int rc; + + rc = kvm_riscv_nacl_enable(); + if (rc) + return rc; + csr_write(CSR_HEDELEG, KVM_HEDELEG_DEFAULT); csr_write(CSR_HIDELEG, KVM_HIDELEG_DEFAULT); @@ -49,11 +55,21 @@ void kvm_arch_disable_virtualization_cpu(void) csr_write(CSR_HVIP, 0); csr_write(CSR_HEDELEG, 0); csr_write(CSR_HIDELEG, 0); + + kvm_riscv_nacl_disable(); +} + +static void kvm_riscv_teardown(void) +{ + kvm_riscv_aia_exit(); + kvm_riscv_nacl_exit(); + kvm_unregister_perf_callbacks(); } static int __init riscv_kvm_init(void) { int rc; + char slist[64]; const char *str; if (!riscv_isa_extension_available(NULL, h)) { @@ -71,16 +87,53 @@ static int __init riscv_kvm_init(void) return -ENODEV; } + rc = kvm_riscv_nacl_init(); + if (rc && rc != -ENODEV) + return rc; + kvm_riscv_gstage_mode_detect(); kvm_riscv_gstage_vmid_detect(); rc = kvm_riscv_aia_init(); - if (rc && rc != -ENODEV) + if (rc && rc != -ENODEV) { + kvm_riscv_nacl_exit(); return rc; + } kvm_info("hypervisor extension available\n"); + if (kvm_riscv_nacl_available()) { + rc = 0; + slist[0] = '\0'; + if (kvm_riscv_nacl_sync_csr_available()) { + if (rc) + strcat(slist, ", "); + strcat(slist, "sync_csr"); + rc++; + } + if (kvm_riscv_nacl_sync_hfence_available()) { + if (rc) + strcat(slist, ", "); + strcat(slist, "sync_hfence"); + rc++; + } + if (kvm_riscv_nacl_sync_sret_available()) { + if (rc) + strcat(slist, ", "); + strcat(slist, "sync_sret"); + rc++; + } + if (kvm_riscv_nacl_autoswap_csr_available()) { + if (rc) + strcat(slist, ", "); + strcat(slist, "autoswap_csr"); + rc++; + } + kvm_info("using SBI nested acceleration with %s\n", + (rc) ? slist : "no features"); + } + switch (kvm_riscv_gstage_mode()) { case HGATP_MODE_SV32X4: str = "Sv32x4"; @@ -105,9 +158,11 @@ static int __init riscv_kvm_init(void) kvm_info("AIA available with %d guest external interrupts\n", kvm_riscv_aia_nr_hgei); + kvm_register_perf_callbacks(NULL); + rc = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (rc) { - kvm_riscv_aia_exit(); + kvm_riscv_teardown(); return rc; } @@ -117,7 +172,7 @@ module_init(riscv_kvm_init); static void __exit riscv_kvm_exit(void) { - kvm_riscv_aia_exit(); + kvm_riscv_teardown(); kvm_exit(); } diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index b63650f9b966ac..1087ea74567b4c 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -601,6 +601,7 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, bool logging = (memslot->dirty_bitmap && !(memslot->flags & KVM_MEM_READONLY)) ? true : false; unsigned long vma_pagesize, mmu_seq; + struct page *page; /* We need minimum second+third level pages */ ret = kvm_mmu_topup_memory_cache(pcache, gstage_pgd_levels); @@ -631,7 +632,7 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, /* * 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 + * vma_lookup() or __kvm_faultin_pfn() become stale prior to acquiring * kvm->mmu_lock. * * Rely on mmap_read_unlock() for an implicit smp_rmb(), which pairs @@ -647,7 +648,7 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, return -EFAULT; } - hfn = gfn_to_pfn_prot(kvm, gfn, is_write, &writable); + hfn = kvm_faultin_pfn(vcpu, gfn, is_write, &writable, &page); if (hfn == KVM_PFN_ERR_HWPOISON) { send_sig_mceerr(BUS_MCEERR_AR, (void __user *)hva, vma_pageshift, current); @@ -669,7 +670,6 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, goto out_unlock; if (writable) { - kvm_set_pfn_dirty(hfn); mark_page_dirty(kvm, gfn); ret = gstage_map_page(kvm, pcache, gpa, hfn << PAGE_SHIFT, vma_pagesize, false, true); @@ -682,9 +682,8 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, kvm_err("Failed to map in G-stage\n"); out_unlock: + kvm_release_faultin_page(kvm, page, ret && ret != -EEXIST, writable); spin_unlock(&kvm->mmu_lock); - kvm_set_pfn_accessed(hfn); - kvm_release_pfn_clean(hfn); return ret; } @@ -732,7 +731,7 @@ void kvm_riscv_gstage_update_hgatp(struct kvm_vcpu *vcpu) hgatp |= (READ_ONCE(k->vmid.vmid) << HGATP_VMID_SHIFT) & HGATP_VMID; hgatp |= (k->pgd_phys >> PAGE_SHIFT) & HGATP_PPN; - csr_write(CSR_HGATP, hgatp); + ncsr_write(CSR_HGATP, hgatp); if (!kvm_riscv_gstage_vmid_bits()) kvm_riscv_local_hfence_gvma_all(); diff --git a/arch/riscv/kvm/nacl.c b/arch/riscv/kvm/nacl.c new file mode 100644 index 00000000000000..08a95ad9ada2c1 --- /dev/null +++ b/arch/riscv/kvm/nacl.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Ventana Micro Systems Inc. + */ + +#include +#include +#include + +DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_available); +DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_csr_available); +DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_hfence_available); +DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_sret_available); +DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_autoswap_csr_available); +DEFINE_PER_CPU(struct kvm_riscv_nacl, kvm_riscv_nacl); + +void __kvm_riscv_nacl_hfence(void *shmem, + unsigned long control, + unsigned long page_num, + unsigned long page_count) +{ + int i, ent = -1, try_count = 5; + unsigned long *entp; + +again: + for (i = 0; i < SBI_NACL_SHMEM_HFENCE_ENTRY_MAX; i++) { + entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i); + if (lelong_to_cpu(*entp) & SBI_NACL_SHMEM_HFENCE_CONFIG_PEND) + continue; + + ent = i; + break; + } + + if (ent < 0) { + if (try_count) { + nacl_sync_hfence(-1UL); + goto again; + } else { + pr_warn("KVM: No free entry in NACL shared memory\n"); + return; + } + } + + entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i); + *entp = cpu_to_lelong(control); + entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i); + *entp = cpu_to_lelong(page_num); + entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i); + *entp = cpu_to_lelong(page_count); +} + +int kvm_riscv_nacl_enable(void) +{ + int rc; + struct sbiret ret; + struct kvm_riscv_nacl *nacl; + + if (!kvm_riscv_nacl_available()) + return 0; + nacl = this_cpu_ptr(&kvm_riscv_nacl); + + ret = sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_SET_SHMEM, + nacl->shmem_phys, 0, 0, 0, 0, 0); + rc = sbi_err_map_linux_errno(ret.error); + if (rc) + return rc; + + return 0; +} + +void kvm_riscv_nacl_disable(void) +{ + if (!kvm_riscv_nacl_available()) + return; + + sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_SET_SHMEM, + SBI_SHMEM_DISABLE, SBI_SHMEM_DISABLE, 0, 0, 0, 0); +} + +void kvm_riscv_nacl_exit(void) +{ + int cpu; + struct kvm_riscv_nacl *nacl; + + if (!kvm_riscv_nacl_available()) + return; + + /* Allocate per-CPU shared memory */ + for_each_possible_cpu(cpu) { + nacl = per_cpu_ptr(&kvm_riscv_nacl, cpu); + if (!nacl->shmem) + continue; + + free_pages((unsigned long)nacl->shmem, + get_order(SBI_NACL_SHMEM_SIZE)); + nacl->shmem = NULL; + nacl->shmem_phys = 0; + } +} + +static long nacl_probe_feature(long feature_id) +{ + struct sbiret ret; + + if (!kvm_riscv_nacl_available()) + return 0; + + ret = sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_PROBE_FEATURE, + feature_id, 0, 0, 0, 0, 0); + return ret.value; +} + +int kvm_riscv_nacl_init(void) +{ + int cpu; + struct page *shmem_page; + struct kvm_riscv_nacl *nacl; + + if (sbi_spec_version < sbi_mk_version(1, 0) || + sbi_probe_extension(SBI_EXT_NACL) <= 0) + return -ENODEV; + + /* Enable NACL support */ + static_branch_enable(&kvm_riscv_nacl_available); + + /* Probe NACL features */ + if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_CSR)) + static_branch_enable(&kvm_riscv_nacl_sync_csr_available); + if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_HFENCE)) + static_branch_enable(&kvm_riscv_nacl_sync_hfence_available); + if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_SRET)) + static_branch_enable(&kvm_riscv_nacl_sync_sret_available); + if (nacl_probe_feature(SBI_NACL_FEAT_AUTOSWAP_CSR)) + static_branch_enable(&kvm_riscv_nacl_autoswap_csr_available); + + /* Allocate per-CPU shared memory */ + for_each_possible_cpu(cpu) { + nacl = per_cpu_ptr(&kvm_riscv_nacl, cpu); + + shmem_page = alloc_pages(GFP_KERNEL | __GFP_ZERO, + get_order(SBI_NACL_SHMEM_SIZE)); + if (!shmem_page) { + kvm_riscv_nacl_exit(); + return -ENOMEM; + } + nacl->shmem = page_to_virt(shmem_page); + nacl->shmem_phys = page_to_phys(shmem_page); + } + + return 0; +} diff --git a/arch/riscv/kvm/tlb.c b/arch/riscv/kvm/tlb.c index 23c0e82b5103cd..2f91ea5f849325 100644 --- a/arch/riscv/kvm/tlb.c +++ b/arch/riscv/kvm/tlb.c @@ -14,6 +14,7 @@ #include #include #include +#include #define has_svinval() riscv_has_extension_unlikely(RISCV_ISA_EXT_SVINVAL) @@ -186,18 +187,24 @@ void kvm_riscv_fence_i_process(struct kvm_vcpu *vcpu) void kvm_riscv_hfence_gvma_vmid_all_process(struct kvm_vcpu *vcpu) { - struct kvm_vmid *vmid; + struct kvm_vmid *v = &vcpu->kvm->arch.vmid; + unsigned long vmid = READ_ONCE(v->vmid); - vmid = &vcpu->kvm->arch.vmid; - kvm_riscv_local_hfence_gvma_vmid_all(READ_ONCE(vmid->vmid)); + if (kvm_riscv_nacl_available()) + nacl_hfence_gvma_vmid_all(nacl_shmem(), vmid); + else + kvm_riscv_local_hfence_gvma_vmid_all(vmid); } void kvm_riscv_hfence_vvma_all_process(struct kvm_vcpu *vcpu) { - struct kvm_vmid *vmid; + struct kvm_vmid *v = &vcpu->kvm->arch.vmid; + unsigned long vmid = READ_ONCE(v->vmid); - vmid = &vcpu->kvm->arch.vmid; - kvm_riscv_local_hfence_vvma_all(READ_ONCE(vmid->vmid)); + if (kvm_riscv_nacl_available()) + nacl_hfence_vvma_all(nacl_shmem(), vmid); + else + kvm_riscv_local_hfence_vvma_all(vmid); } static bool vcpu_hfence_dequeue(struct kvm_vcpu *vcpu, @@ -251,6 +258,7 @@ static bool vcpu_hfence_enqueue(struct kvm_vcpu *vcpu, void kvm_riscv_hfence_process(struct kvm_vcpu *vcpu) { + unsigned long vmid; struct kvm_riscv_hfence d = { 0 }; struct kvm_vmid *v = &vcpu->kvm->arch.vmid; @@ -259,26 +267,41 @@ void kvm_riscv_hfence_process(struct kvm_vcpu *vcpu) case KVM_RISCV_HFENCE_UNKNOWN: break; case KVM_RISCV_HFENCE_GVMA_VMID_GPA: - kvm_riscv_local_hfence_gvma_vmid_gpa( - READ_ONCE(v->vmid), - d.addr, d.size, d.order); + vmid = READ_ONCE(v->vmid); + if (kvm_riscv_nacl_available()) + nacl_hfence_gvma_vmid(nacl_shmem(), vmid, + d.addr, d.size, d.order); + else + kvm_riscv_local_hfence_gvma_vmid_gpa(vmid, d.addr, + d.size, d.order); break; case KVM_RISCV_HFENCE_VVMA_ASID_GVA: kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD); - kvm_riscv_local_hfence_vvma_asid_gva( - READ_ONCE(v->vmid), d.asid, - d.addr, d.size, d.order); + vmid = READ_ONCE(v->vmid); + if (kvm_riscv_nacl_available()) + nacl_hfence_vvma_asid(nacl_shmem(), vmid, d.asid, + d.addr, d.size, d.order); + else + kvm_riscv_local_hfence_vvma_asid_gva(vmid, d.asid, d.addr, + d.size, d.order); break; case KVM_RISCV_HFENCE_VVMA_ASID_ALL: kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_HFENCE_VVMA_ASID_RCVD); - kvm_riscv_local_hfence_vvma_asid_all( - READ_ONCE(v->vmid), d.asid); + vmid = READ_ONCE(v->vmid); + if (kvm_riscv_nacl_available()) + nacl_hfence_vvma_asid_all(nacl_shmem(), vmid, d.asid); + else + kvm_riscv_local_hfence_vvma_asid_all(vmid, d.asid); break; case KVM_RISCV_HFENCE_VVMA_GVA: kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_HFENCE_VVMA_RCVD); - kvm_riscv_local_hfence_vvma_gva( - READ_ONCE(v->vmid), - d.addr, d.size, d.order); + vmid = READ_ONCE(v->vmid); + if (kvm_riscv_nacl_available()) + nacl_hfence_vvma(nacl_shmem(), vmid, + d.addr, d.size, d.order); + else + kvm_riscv_local_hfence_vvma_gva(vmid, d.addr, + d.size, d.order); break; default: break; diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 8d7d381737ee54..e048dcc6e65e73 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include #define CREATE_TRACE_POINTS @@ -226,6 +226,13 @@ bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) return (vcpu->arch.guest_context.sstatus & SR_SPP) ? true : false; } +#ifdef CONFIG_GUEST_PERF_EVENTS +unsigned long kvm_arch_vcpu_get_ip(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.guest_context.sepc; +} +#endif + vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) { return VM_FAULT_SIGBUS; @@ -361,10 +368,10 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; /* Read current HVIP and VSIE CSRs */ - csr->vsie = csr_read(CSR_VSIE); + csr->vsie = ncsr_read(CSR_VSIE); /* Sync-up HVIP.VSSIP bit changes does by Guest */ - hvip = csr_read(CSR_HVIP); + hvip = ncsr_read(CSR_HVIP); if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) { if (hvip & (1UL << IRQ_VS_SOFT)) { if (!test_and_set_bit(IRQ_VS_SOFT, @@ -544,6 +551,10 @@ static void kvm_riscv_vcpu_setup_config(struct kvm_vcpu *vcpu) if (riscv_isa_extension_available(isa, ZICBOZ)) cfg->henvcfg |= ENVCFG_CBZE; + if (riscv_isa_extension_available(isa, SVADU) && + !riscv_isa_extension_available(isa, SVADE)) + cfg->henvcfg |= ENVCFG_ADUE; + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) { cfg->hstateen0 |= SMSTATEEN0_HSENVCFG; if (riscv_isa_extension_available(isa, SSAIA)) @@ -561,26 +572,49 @@ static void kvm_riscv_vcpu_setup_config(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { + void *nsh; struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; - csr_write(CSR_VSSTATUS, csr->vsstatus); - csr_write(CSR_VSIE, csr->vsie); - csr_write(CSR_VSTVEC, csr->vstvec); - csr_write(CSR_VSSCRATCH, csr->vsscratch); - csr_write(CSR_VSEPC, csr->vsepc); - csr_write(CSR_VSCAUSE, csr->vscause); - csr_write(CSR_VSTVAL, csr->vstval); - csr_write(CSR_HEDELEG, cfg->hedeleg); - csr_write(CSR_HVIP, csr->hvip); - csr_write(CSR_VSATP, csr->vsatp); - csr_write(CSR_HENVCFG, cfg->henvcfg); - if (IS_ENABLED(CONFIG_32BIT)) - csr_write(CSR_HENVCFGH, cfg->henvcfg >> 32); - if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) { - csr_write(CSR_HSTATEEN0, cfg->hstateen0); + if (kvm_riscv_nacl_sync_csr_available()) { + nsh = nacl_shmem(); + nacl_csr_write(nsh, CSR_VSSTATUS, csr->vsstatus); + nacl_csr_write(nsh, CSR_VSIE, csr->vsie); + nacl_csr_write(nsh, CSR_VSTVEC, csr->vstvec); + nacl_csr_write(nsh, CSR_VSSCRATCH, csr->vsscratch); + nacl_csr_write(nsh, CSR_VSEPC, csr->vsepc); + nacl_csr_write(nsh, CSR_VSCAUSE, csr->vscause); + nacl_csr_write(nsh, CSR_VSTVAL, csr->vstval); + nacl_csr_write(nsh, CSR_HEDELEG, cfg->hedeleg); + nacl_csr_write(nsh, CSR_HVIP, csr->hvip); + nacl_csr_write(nsh, CSR_VSATP, csr->vsatp); + nacl_csr_write(nsh, CSR_HENVCFG, cfg->henvcfg); + if (IS_ENABLED(CONFIG_32BIT)) + nacl_csr_write(nsh, CSR_HENVCFGH, cfg->henvcfg >> 32); + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) { + nacl_csr_write(nsh, CSR_HSTATEEN0, cfg->hstateen0); + if (IS_ENABLED(CONFIG_32BIT)) + nacl_csr_write(nsh, CSR_HSTATEEN0H, cfg->hstateen0 >> 32); + } + } else { + csr_write(CSR_VSSTATUS, csr->vsstatus); + csr_write(CSR_VSIE, csr->vsie); + csr_write(CSR_VSTVEC, csr->vstvec); + csr_write(CSR_VSSCRATCH, csr->vsscratch); + csr_write(CSR_VSEPC, csr->vsepc); + csr_write(CSR_VSCAUSE, csr->vscause); + csr_write(CSR_VSTVAL, csr->vstval); + csr_write(CSR_HEDELEG, cfg->hedeleg); + csr_write(CSR_HVIP, csr->hvip); + csr_write(CSR_VSATP, csr->vsatp); + csr_write(CSR_HENVCFG, cfg->henvcfg); if (IS_ENABLED(CONFIG_32BIT)) - csr_write(CSR_HSTATEEN0H, cfg->hstateen0 >> 32); + csr_write(CSR_HENVCFGH, cfg->henvcfg >> 32); + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) { + csr_write(CSR_HSTATEEN0, cfg->hstateen0); + if (IS_ENABLED(CONFIG_32BIT)) + csr_write(CSR_HSTATEEN0H, cfg->hstateen0 >> 32); + } } kvm_riscv_gstage_update_hgatp(vcpu); @@ -603,6 +637,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) { + void *nsh; struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; vcpu->cpu = -1; @@ -618,15 +653,28 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) vcpu->arch.isa); kvm_riscv_vcpu_host_vector_restore(&vcpu->arch.host_context); - csr->vsstatus = csr_read(CSR_VSSTATUS); - csr->vsie = csr_read(CSR_VSIE); - csr->vstvec = csr_read(CSR_VSTVEC); - csr->vsscratch = csr_read(CSR_VSSCRATCH); - csr->vsepc = csr_read(CSR_VSEPC); - csr->vscause = csr_read(CSR_VSCAUSE); - csr->vstval = csr_read(CSR_VSTVAL); - csr->hvip = csr_read(CSR_HVIP); - csr->vsatp = csr_read(CSR_VSATP); + if (kvm_riscv_nacl_available()) { + nsh = nacl_shmem(); + csr->vsstatus = nacl_csr_read(nsh, CSR_VSSTATUS); + csr->vsie = nacl_csr_read(nsh, CSR_VSIE); + csr->vstvec = nacl_csr_read(nsh, CSR_VSTVEC); + csr->vsscratch = nacl_csr_read(nsh, CSR_VSSCRATCH); + csr->vsepc = nacl_csr_read(nsh, CSR_VSEPC); + csr->vscause = nacl_csr_read(nsh, CSR_VSCAUSE); + csr->vstval = nacl_csr_read(nsh, CSR_VSTVAL); + csr->hvip = nacl_csr_read(nsh, CSR_HVIP); + csr->vsatp = nacl_csr_read(nsh, CSR_VSATP); + } else { + csr->vsstatus = csr_read(CSR_VSSTATUS); + csr->vsie = csr_read(CSR_VSIE); + csr->vstvec = csr_read(CSR_VSTVEC); + csr->vsscratch = csr_read(CSR_VSSCRATCH); + csr->vsepc = csr_read(CSR_VSEPC); + csr->vscause = csr_read(CSR_VSCAUSE); + csr->vstval = csr_read(CSR_VSTVAL); + csr->hvip = csr_read(CSR_HVIP); + csr->vsatp = csr_read(CSR_VSATP); + } } static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu) @@ -681,7 +729,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); + ncsr_write(CSR_HVIP, csr->hvip); kvm_riscv_vcpu_aia_update_hvip(vcpu); } @@ -691,6 +739,7 @@ static __always_inline void kvm_riscv_vcpu_swap_in_guest_state(struct kvm_vcpu * struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; + vcpu->arch.host_scounteren = csr_swap(CSR_SCOUNTEREN, csr->scounteren); vcpu->arch.host_senvcfg = csr_swap(CSR_SENVCFG, csr->senvcfg); if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN) && (cfg->hstateen0 & SMSTATEEN0_SSTATEEN0)) @@ -704,6 +753,7 @@ static __always_inline void kvm_riscv_vcpu_swap_in_host_state(struct kvm_vcpu *v struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; struct kvm_vcpu_config *cfg = &vcpu->arch.cfg; + csr->scounteren = csr_swap(CSR_SCOUNTEREN, vcpu->arch.host_scounteren); csr->senvcfg = csr_swap(CSR_SENVCFG, vcpu->arch.host_senvcfg); if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN) && (cfg->hstateen0 & SMSTATEEN0_SSTATEEN0)) @@ -718,11 +768,81 @@ static __always_inline void kvm_riscv_vcpu_swap_in_host_state(struct kvm_vcpu *v * This must be noinstr as instrumentation may make use of RCU, and this is not * safe during the EQS. */ -static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu) +static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu, + struct kvm_cpu_trap *trap) { + void *nsh; + struct kvm_cpu_context *gcntx = &vcpu->arch.guest_context; + struct kvm_cpu_context *hcntx = &vcpu->arch.host_context; + + /* + * We save trap CSRs (such as SEPC, SCAUSE, STVAL, HTVAL, and + * HTINST) here because we do local_irq_enable() after this + * function in kvm_arch_vcpu_ioctl_run() which can result in + * an interrupt immediately after local_irq_enable() and can + * potentially change trap CSRs. + */ + kvm_riscv_vcpu_swap_in_guest_state(vcpu); guest_state_enter_irqoff(); - __kvm_riscv_switch_to(&vcpu->arch); + + if (kvm_riscv_nacl_sync_sret_available()) { + nsh = nacl_shmem(); + + if (kvm_riscv_nacl_autoswap_csr_available()) { + hcntx->hstatus = + nacl_csr_read(nsh, CSR_HSTATUS); + nacl_scratch_write_long(nsh, + SBI_NACL_SHMEM_AUTOSWAP_OFFSET + + SBI_NACL_SHMEM_AUTOSWAP_HSTATUS, + gcntx->hstatus); + nacl_scratch_write_long(nsh, + SBI_NACL_SHMEM_AUTOSWAP_OFFSET, + SBI_NACL_SHMEM_AUTOSWAP_FLAG_HSTATUS); + } else if (kvm_riscv_nacl_sync_csr_available()) { + hcntx->hstatus = nacl_csr_swap(nsh, + CSR_HSTATUS, gcntx->hstatus); + } else { + hcntx->hstatus = csr_swap(CSR_HSTATUS, gcntx->hstatus); + } + + nacl_scratch_write_longs(nsh, + SBI_NACL_SHMEM_SRET_OFFSET + + SBI_NACL_SHMEM_SRET_X(1), + &gcntx->ra, + SBI_NACL_SHMEM_SRET_X_LAST); + + __kvm_riscv_nacl_switch_to(&vcpu->arch, SBI_EXT_NACL, + SBI_EXT_NACL_SYNC_SRET); + + if (kvm_riscv_nacl_autoswap_csr_available()) { + nacl_scratch_write_long(nsh, + SBI_NACL_SHMEM_AUTOSWAP_OFFSET, + 0); + gcntx->hstatus = nacl_scratch_read_long(nsh, + SBI_NACL_SHMEM_AUTOSWAP_OFFSET + + SBI_NACL_SHMEM_AUTOSWAP_HSTATUS); + } else { + gcntx->hstatus = csr_swap(CSR_HSTATUS, hcntx->hstatus); + } + + trap->htval = nacl_csr_read(nsh, CSR_HTVAL); + trap->htinst = nacl_csr_read(nsh, CSR_HTINST); + } else { + hcntx->hstatus = csr_swap(CSR_HSTATUS, gcntx->hstatus); + + __kvm_riscv_switch_to(&vcpu->arch); + + gcntx->hstatus = csr_swap(CSR_HSTATUS, hcntx->hstatus); + + trap->htval = csr_read(CSR_HTVAL); + trap->htinst = csr_read(CSR_HTINST); + } + + trap->sepc = gcntx->sepc; + trap->scause = csr_read(CSR_SCAUSE); + trap->stval = csr_read(CSR_STVAL); + vcpu->arch.last_exit_cpu = vcpu->cpu; guest_state_exit_irqoff(); kvm_riscv_vcpu_swap_in_host_state(vcpu); @@ -839,22 +959,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) guest_timing_enter_irqoff(); - kvm_riscv_vcpu_enter_exit(vcpu); + kvm_riscv_vcpu_enter_exit(vcpu, &trap); vcpu->mode = OUTSIDE_GUEST_MODE; vcpu->stat.exits++; - /* - * Save SCAUSE, STVAL, HTVAL, and HTINST because we might - * get an interrupt between __kvm_riscv_switch_to() and - * local_irq_enable() which can potentially change CSRs. - */ - trap.sepc = vcpu->arch.guest_context.sepc; - trap.scause = csr_read(CSR_SCAUSE); - trap.stval = csr_read(CSR_STVAL); - trap.htval = csr_read(CSR_HTVAL); - trap.htinst = csr_read(CSR_HTINST); - /* Syncup interrupts state with HW */ kvm_riscv_vcpu_sync_interrupts(vcpu); diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index b319c4c13c54ce..753f66c8b70a72 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #define KVM_RISCV_BASE_ISA_MASK GENMASK(25, 0) @@ -34,10 +35,14 @@ static const unsigned long kvm_isa_ext_arr[] = { [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m, [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v, /* Multi letter extensions (alphabetically sorted) */ + [KVM_RISCV_ISA_EXT_SMNPM] = RISCV_ISA_EXT_SSNPM, KVM_ISA_EXT_ARR(SMSTATEEN), KVM_ISA_EXT_ARR(SSAIA), KVM_ISA_EXT_ARR(SSCOFPMF), + KVM_ISA_EXT_ARR(SSNPM), KVM_ISA_EXT_ARR(SSTC), + KVM_ISA_EXT_ARR(SVADE), + KVM_ISA_EXT_ARR(SVADU), KVM_ISA_EXT_ARR(SVINVAL), KVM_ISA_EXT_ARR(SVNAPOT), KVM_ISA_EXT_ARR(SVPBMT), @@ -110,6 +115,12 @@ static bool kvm_riscv_vcpu_isa_enable_allowed(unsigned long ext) case KVM_RISCV_ISA_EXT_SSCOFPMF: /* Sscofpmf depends on interrupt filtering defined in ssaia */ return __riscv_isa_extension_available(NULL, RISCV_ISA_EXT_SSAIA); + case KVM_RISCV_ISA_EXT_SVADU: + /* + * The henvcfg.ADUE is read-only zero if menvcfg.ADUE is zero. + * Guest OS can use Svadu only when host OS enable Svadu. + */ + return arch_has_hw_pte_young(); case KVM_RISCV_ISA_EXT_V: return riscv_v_vstate_ctrl_user_allowed(); default: @@ -127,8 +138,10 @@ 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_SMNPM: /* There is not architectural config bit to disable sscofpmf completely */ case KVM_RISCV_ISA_EXT_SSCOFPMF: + case KVM_RISCV_ISA_EXT_SSNPM: case KVM_RISCV_ISA_EXT_SSTC: case KVM_RISCV_ISA_EXT_SVINVAL: case KVM_RISCV_ISA_EXT_SVNAPOT: @@ -181,6 +194,12 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) /* Extensions which can be disabled using Smstateen */ case KVM_RISCV_ISA_EXT_SSAIA: return riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN); + case KVM_RISCV_ISA_EXT_SVADE: + /* + * The henvcfg.ADUE is read-only zero if menvcfg.ADUE is zero. + * Svade is not allowed to disable when the platform use Svade. + */ + return arch_has_hw_pte_young(); default: break; } diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index 7de128be8db9bc..6e704ed86a83a9 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -486,19 +486,22 @@ void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu) struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; const struct kvm_riscv_sbi_extension_entry *entry; const struct kvm_vcpu_sbi_extension *ext; - int i; + int idx, i; for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { entry = &sbi_ext[i]; ext = entry->ext_ptr; + idx = entry->ext_idx; + + if (idx < 0 || idx >= ARRAY_SIZE(scontext->ext_status)) + continue; if (ext->probe && !ext->probe(vcpu)) { - scontext->ext_status[entry->ext_idx] = - KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE; + scontext->ext_status[idx] = KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE; continue; } - scontext->ext_status[entry->ext_idx] = ext->default_disabled ? + scontext->ext_status[idx] = ext->default_disabled ? KVM_RISCV_SBI_EXT_STATUS_DISABLED : KVM_RISCV_SBI_EXT_STATUS_ENABLED; } diff --git a/arch/riscv/kvm/vcpu_switch.S b/arch/riscv/kvm/vcpu_switch.S index 0c26189aa01cf5..47686bcb21e0a5 100644 --- a/arch/riscv/kvm/vcpu_switch.S +++ b/arch/riscv/kvm/vcpu_switch.S @@ -11,11 +11,7 @@ #include #include - .text - .altmacro - .option norelax - -SYM_FUNC_START(__kvm_riscv_switch_to) +.macro SAVE_HOST_GPRS /* Save Host GPRs (except A0 and T0-T6) */ REG_S ra, (KVM_ARCH_HOST_RA)(a0) REG_S sp, (KVM_ARCH_HOST_SP)(a0) @@ -40,39 +36,33 @@ SYM_FUNC_START(__kvm_riscv_switch_to) REG_S s9, (KVM_ARCH_HOST_S9)(a0) REG_S s10, (KVM_ARCH_HOST_S10)(a0) REG_S s11, (KVM_ARCH_HOST_S11)(a0) +.endm +.macro SAVE_HOST_AND_RESTORE_GUEST_CSRS __resume_addr /* Load Guest CSR values */ REG_L t0, (KVM_ARCH_GUEST_SSTATUS)(a0) - REG_L t1, (KVM_ARCH_GUEST_HSTATUS)(a0) - REG_L t2, (KVM_ARCH_GUEST_SCOUNTEREN)(a0) - la t4, .Lkvm_switch_return - REG_L t5, (KVM_ARCH_GUEST_SEPC)(a0) + la t1, \__resume_addr + REG_L t2, (KVM_ARCH_GUEST_SEPC)(a0) /* Save Host and Restore Guest SSTATUS */ csrrw t0, CSR_SSTATUS, t0 - /* Save Host and Restore Guest HSTATUS */ - csrrw t1, CSR_HSTATUS, t1 - - /* Save Host and Restore Guest SCOUNTEREN */ - csrrw t2, CSR_SCOUNTEREN, t2 - /* Save Host STVEC and change it to return path */ - csrrw t4, CSR_STVEC, t4 + csrrw t1, CSR_STVEC, t1 + + /* Restore Guest SEPC */ + csrw CSR_SEPC, t2 /* Save Host SSCRATCH and change it to struct kvm_vcpu_arch pointer */ csrrw t3, CSR_SSCRATCH, a0 - /* Restore Guest SEPC */ - csrw CSR_SEPC, t5 - /* Store Host CSR values */ REG_S t0, (KVM_ARCH_HOST_SSTATUS)(a0) - REG_S t1, (KVM_ARCH_HOST_HSTATUS)(a0) - REG_S t2, (KVM_ARCH_HOST_SCOUNTEREN)(a0) + REG_S t1, (KVM_ARCH_HOST_STVEC)(a0) REG_S t3, (KVM_ARCH_HOST_SSCRATCH)(a0) - REG_S t4, (KVM_ARCH_HOST_STVEC)(a0) +.endm +.macro RESTORE_GUEST_GPRS /* Restore Guest GPRs (except A0) */ REG_L ra, (KVM_ARCH_GUEST_RA)(a0) REG_L sp, (KVM_ARCH_GUEST_SP)(a0) @@ -107,13 +97,9 @@ SYM_FUNC_START(__kvm_riscv_switch_to) /* Restore Guest A0 */ REG_L a0, (KVM_ARCH_GUEST_A0)(a0) +.endm - /* Resume Guest */ - sret - - /* Back to Host */ - .align 2 -.Lkvm_switch_return: +.macro SAVE_GUEST_GPRS /* Swap Guest A0 with SSCRATCH */ csrrw a0, CSR_SSCRATCH, a0 @@ -148,39 +134,33 @@ SYM_FUNC_START(__kvm_riscv_switch_to) REG_S t4, (KVM_ARCH_GUEST_T4)(a0) REG_S t5, (KVM_ARCH_GUEST_T5)(a0) REG_S t6, (KVM_ARCH_GUEST_T6)(a0) +.endm +.macro SAVE_GUEST_AND_RESTORE_HOST_CSRS /* Load Host CSR values */ - REG_L t1, (KVM_ARCH_HOST_STVEC)(a0) - REG_L t2, (KVM_ARCH_HOST_SSCRATCH)(a0) - REG_L t3, (KVM_ARCH_HOST_SCOUNTEREN)(a0) - REG_L t4, (KVM_ARCH_HOST_HSTATUS)(a0) - REG_L t5, (KVM_ARCH_HOST_SSTATUS)(a0) - - /* Save Guest SEPC */ - csrr t0, CSR_SEPC + REG_L t0, (KVM_ARCH_HOST_STVEC)(a0) + REG_L t1, (KVM_ARCH_HOST_SSCRATCH)(a0) + REG_L t2, (KVM_ARCH_HOST_SSTATUS)(a0) /* Save Guest A0 and Restore Host SSCRATCH */ - csrrw t2, CSR_SSCRATCH, t2 + csrrw t1, CSR_SSCRATCH, t1 - /* Restore Host STVEC */ - csrw CSR_STVEC, t1 - - /* Save Guest and Restore Host SCOUNTEREN */ - csrrw t3, CSR_SCOUNTEREN, t3 + /* Save Guest SEPC */ + csrr t3, CSR_SEPC - /* Save Guest and Restore Host HSTATUS */ - csrrw t4, CSR_HSTATUS, t4 + /* Restore Host STVEC */ + csrw CSR_STVEC, t0 /* Save Guest and Restore Host SSTATUS */ - csrrw t5, CSR_SSTATUS, t5 + csrrw t2, CSR_SSTATUS, t2 /* Store Guest CSR values */ - REG_S t0, (KVM_ARCH_GUEST_SEPC)(a0) - REG_S t2, (KVM_ARCH_GUEST_A0)(a0) - REG_S t3, (KVM_ARCH_GUEST_SCOUNTEREN)(a0) - REG_S t4, (KVM_ARCH_GUEST_HSTATUS)(a0) - REG_S t5, (KVM_ARCH_GUEST_SSTATUS)(a0) + REG_S t1, (KVM_ARCH_GUEST_A0)(a0) + REG_S t2, (KVM_ARCH_GUEST_SSTATUS)(a0) + REG_S t3, (KVM_ARCH_GUEST_SEPC)(a0) +.endm +.macro RESTORE_HOST_GPRS /* Restore Host GPRs (except A0 and T0-T6) */ REG_L ra, (KVM_ARCH_HOST_RA)(a0) REG_L sp, (KVM_ARCH_HOST_SP)(a0) @@ -205,11 +185,68 @@ SYM_FUNC_START(__kvm_riscv_switch_to) REG_L s9, (KVM_ARCH_HOST_S9)(a0) REG_L s10, (KVM_ARCH_HOST_S10)(a0) REG_L s11, (KVM_ARCH_HOST_S11)(a0) +.endm + + .text + .altmacro + .option norelax + + /* + * Parameters: + * A0 <= Pointer to struct kvm_vcpu_arch + */ +SYM_FUNC_START(__kvm_riscv_switch_to) + SAVE_HOST_GPRS + + SAVE_HOST_AND_RESTORE_GUEST_CSRS .Lkvm_switch_return + + RESTORE_GUEST_GPRS + + /* Resume Guest using SRET */ + sret + + /* Back to Host */ + .align 2 +.Lkvm_switch_return: + SAVE_GUEST_GPRS + + SAVE_GUEST_AND_RESTORE_HOST_CSRS + + RESTORE_HOST_GPRS /* Return to C code */ ret SYM_FUNC_END(__kvm_riscv_switch_to) + /* + * Parameters: + * A0 <= Pointer to struct kvm_vcpu_arch + * A1 <= SBI extension ID + * A2 <= SBI function ID + */ +SYM_FUNC_START(__kvm_riscv_nacl_switch_to) + SAVE_HOST_GPRS + + SAVE_HOST_AND_RESTORE_GUEST_CSRS .Lkvm_nacl_switch_return + + /* Resume Guest using SBI nested acceleration */ + add a6, a2, zero + add a7, a1, zero + ecall + + /* Back to Host */ + .align 2 +.Lkvm_nacl_switch_return: + SAVE_GUEST_GPRS + + SAVE_GUEST_AND_RESTORE_HOST_CSRS + + RESTORE_HOST_GPRS + + /* Return to C code */ + ret +SYM_FUNC_END(__kvm_riscv_nacl_switch_to) + SYM_CODE_START(__kvm_riscv_unpriv_trap) /* * We assume that faulting unpriv load/store instruction is diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c index 75486b25ac45aa..96e7a4e463f7f7 100644 --- a/arch/riscv/kvm/vcpu_timer.c +++ b/arch/riscv/kvm/vcpu_timer.c @@ -11,8 +11,8 @@ #include #include #include -#include #include +#include #include static u64 kvm_riscv_current_cycles(struct kvm_guest_timer *gt) @@ -72,12 +72,12 @@ static int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t) static int kvm_riscv_vcpu_update_vstimecmp(struct kvm_vcpu *vcpu, u64 ncycles) { #if defined(CONFIG_32BIT) - csr_write(CSR_VSTIMECMP, ncycles & 0xFFFFFFFF); - csr_write(CSR_VSTIMECMPH, ncycles >> 32); + ncsr_write(CSR_VSTIMECMP, ncycles & 0xFFFFFFFF); + ncsr_write(CSR_VSTIMECMPH, ncycles >> 32); #else - csr_write(CSR_VSTIMECMP, ncycles); + ncsr_write(CSR_VSTIMECMP, ncycles); #endif - return 0; + return 0; } static int kvm_riscv_vcpu_update_hrtimer(struct kvm_vcpu *vcpu, u64 ncycles) @@ -289,10 +289,10 @@ static void kvm_riscv_vcpu_update_timedelta(struct kvm_vcpu *vcpu) struct kvm_guest_timer *gt = &vcpu->kvm->arch.timer; #if defined(CONFIG_32BIT) - csr_write(CSR_HTIMEDELTA, (u32)(gt->time_delta)); - csr_write(CSR_HTIMEDELTAH, (u32)(gt->time_delta >> 32)); + ncsr_write(CSR_HTIMEDELTA, (u32)(gt->time_delta)); + ncsr_write(CSR_HTIMEDELTAH, (u32)(gt->time_delta >> 32)); #else - csr_write(CSR_HTIMEDELTA, gt->time_delta); + ncsr_write(CSR_HTIMEDELTA, gt->time_delta); #endif } @@ -306,10 +306,10 @@ void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu) return; #if defined(CONFIG_32BIT) - csr_write(CSR_VSTIMECMP, (u32)t->next_cycles); - csr_write(CSR_VSTIMECMPH, (u32)(t->next_cycles >> 32)); + ncsr_write(CSR_VSTIMECMP, (u32)t->next_cycles); + ncsr_write(CSR_VSTIMECMPH, (u32)(t->next_cycles >> 32)); #else - csr_write(CSR_VSTIMECMP, t->next_cycles); + ncsr_write(CSR_VSTIMECMP, t->next_cycles); #endif /* timer should be enabled for the remaining operations */ @@ -327,10 +327,10 @@ void kvm_riscv_vcpu_timer_sync(struct kvm_vcpu *vcpu) return; #if defined(CONFIG_32BIT) - t->next_cycles = csr_read(CSR_VSTIMECMP); - t->next_cycles |= (u64)csr_read(CSR_VSTIMECMPH) << 32; + t->next_cycles = ncsr_read(CSR_VSTIMECMP); + t->next_cycles |= (u64)ncsr_read(CSR_VSTIMECMPH) << 32; #else - t->next_cycles = csr_read(CSR_VSTIMECMP); + t->next_cycles = ncsr_read(CSR_VSTIMECMP); #endif } diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 0e8c20adcd98df..fc53ce748c8049 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -1566,7 +1566,7 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd) pmd_clear(pmd); } -static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) +static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud, bool is_vmemmap) { struct page *page = pud_page(*pud); struct ptdesc *ptdesc = page_ptdesc(page); @@ -1579,7 +1579,8 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) return; } - pagetable_pmd_dtor(ptdesc); + if (!is_vmemmap) + pagetable_pmd_dtor(ptdesc); if (PageReserved(page)) free_reserved_page(page); else @@ -1703,7 +1704,7 @@ static void __meminit remove_pud_mapping(pud_t *pud_base, unsigned long addr, un remove_pmd_mapping(pmd_base, addr, next, is_vmemmap, altmap); if (pgtable_l4_enabled) - free_pmd_table(pmd_base, pudp); + free_pmd_table(pmd_base, pudp, is_vmemmap); } } diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c index 271d01a5ba4da1..d815448758a19c 100644 --- a/arch/riscv/mm/pageattr.c +++ b/arch/riscv/mm/pageattr.c @@ -386,6 +386,21 @@ int set_direct_map_default_noflush(struct page *page) PAGE_KERNEL, __pgprot(_PAGE_EXEC)); } +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid) +{ + pgprot_t set, clear; + + if (valid) { + set = PAGE_KERNEL; + clear = __pgprot(_PAGE_EXEC); + } else { + set = __pgprot(0); + clear = __pgprot(_PAGE_PRESENT); + } + + return __set_memory((unsigned long)page_address(page), nr, set, clear); +} + #ifdef CONFIG_DEBUG_PAGEALLOC static int debug_pagealloc_set_page(pte_t *pte, unsigned long addr, void *data) { diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 4cc631fa703913..ca60db75199d1b 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include "bpf_jit.h" diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c index 6de753c667f42a..f8cd2f70a7fb4b 100644 --- a/arch/riscv/net/bpf_jit_core.c +++ b/arch/riscv/net/bpf_jit_core.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include "bpf_jit.h" diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index cc1f9cffe2a5f4..0077969170e8b4 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -52,6 +52,13 @@ config KASAN_SHADOW_OFFSET depends on KASAN default 0x1C000000000000 +config GCC_ASM_FLAG_OUTPUT_BROKEN + def_bool CC_IS_GCC && GCC_VERSION < 140200 + help + GCC versions before 14.2.0 may die with an internal + compiler error in some configurations if flag output + operands are used within inline assemblies. + config S390 def_bool y # @@ -80,6 +87,7 @@ config S390 select ARCH_HAS_MEMBARRIER_SYNC_CORE select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS + select ARCH_HAS_PREEMPT_LAZY select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SCALED_CPUTIME select ARCH_HAS_SET_DIRECT_MAP @@ -88,7 +96,7 @@ config S390 select ARCH_HAS_STRICT_MODULE_RWX select ARCH_HAS_SYSCALL_WRAPPER select ARCH_HAS_UBSAN - select ARCH_HAS_VDSO_DATA + select ARCH_HAS_VDSO_TIME_DATA select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_INLINE_READ_LOCK select ARCH_INLINE_READ_LOCK_BH @@ -211,6 +219,7 @@ config S390 select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select HAVE_PREEMPT_DYNAMIC_KEY select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE select HAVE_RETHOOK @@ -224,6 +233,7 @@ config S390 select HAVE_VIRT_CPU_ACCOUNTING_IDLE select IOMMU_HELPER if PCI select IOMMU_SUPPORT if PCI + select LOCK_MM_AND_FIND_VMA select MMU_GATHER_MERGE_VMAS select MMU_GATHER_NO_GATHER select MMU_GATHER_RCU_TABLE_FREE diff --git a/arch/s390/boot/physmem_info.c b/arch/s390/boot/physmem_info.c index 1d131a81cb8be9..7617aa2d2f7e97 100644 --- a/arch/s390/boot/physmem_info.c +++ b/arch/s390/boot/physmem_info.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "decompressor.h" #include "boot.h" @@ -59,13 +60,13 @@ static int __diag260(unsigned long rx1, unsigned long rx2) { unsigned long reg1, reg2, ry; union register_pair rx; + int cc, exception; psw_t old; - int rc; rx.even = rx1; rx.odd = rx2; ry = 0x10; /* storage configuration */ - rc = -1; /* fail */ + exception = 1; asm volatile( " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" " epsw %[reg1],%[reg2]\n" @@ -74,20 +75,22 @@ static int __diag260(unsigned long rx1, unsigned long rx2) " larl %[reg1],1f\n" " stg %[reg1],8(%[psw_pgm])\n" " diag %[rx],%[ry],0x260\n" - " ipm %[rc]\n" - " srl %[rc],28\n" + " lhi %[exc],0\n" "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" - : [reg1] "=&d" (reg1), + CC_IPM(cc) + : CC_OUT(cc, cc), + [exc] "+d" (exception), + [reg1] "=&d" (reg1), [reg2] "=&a" (reg2), - [rc] "+&d" (rc), [ry] "+&d" (ry), "+Q" (get_lowcore()->program_new_psw), "=Q" (old) : [rx] "d" (rx.pair), [psw_old] "a" (&old), [psw_pgm] "a" (&get_lowcore()->program_new_psw) - : "cc", "memory"); - return rc == 0 ? ry : -1; + : CC_CLOBBER_LIST("memory")); + cc = exception ? -1 : CC_TRANSFORM(cc); + return cc == 0 ? ry : -1; } static int diag260(void) @@ -109,12 +112,49 @@ static int diag260(void) return 0; } +#define DIAG500_SC_STOR_LIMIT 4 + +static int diag500_storage_limit(unsigned long *max_physmem_end) +{ + unsigned long storage_limit; + unsigned long reg1, reg2; + 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" + " lghi 1,%[subcode]\n" + " lghi 2,0\n" + " diag 2,4,0x500\n" + "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" + " lgr %[slimit],2\n" + : [reg1] "=&d" (reg1), + [reg2] "=&a" (reg2), + [slimit] "=d" (storage_limit), + "=Q" (get_lowcore()->program_new_psw), + "=Q" (old) + : [psw_old] "a" (&old), + [psw_pgm] "a" (&get_lowcore()->program_new_psw), + [subcode] "i" (DIAG500_SC_STOR_LIMIT) + : "memory", "1", "2"); + if (!storage_limit) + return -EINVAL; + /* Convert inclusive end to exclusive end */ + *max_physmem_end = storage_limit + 1; + return 0; +} + static int tprot(unsigned long addr) { unsigned long reg1, reg2; - int rc = -EFAULT; + int cc, exception; psw_t old; + exception = 1; asm volatile( " mvc 0(16,%[psw_old]),0(%[psw_pgm])\n" " epsw %[reg1],%[reg2]\n" @@ -123,19 +163,21 @@ static int tprot(unsigned long addr) " larl %[reg1],1f\n" " stg %[reg1],8(%[psw_pgm])\n" " tprot 0(%[addr]),0\n" - " ipm %[rc]\n" - " srl %[rc],28\n" + " lhi %[exc],0\n" "1: mvc 0(16,%[psw_pgm]),0(%[psw_old])\n" - : [reg1] "=&d" (reg1), + CC_IPM(cc) + : CC_OUT(cc, cc), + [exc] "+d" (exception), + [reg1] "=&d" (reg1), [reg2] "=&a" (reg2), - [rc] "+&d" (rc), "=Q" (get_lowcore()->program_new_psw.addr), "=Q" (old) : [psw_old] "a" (&old), [psw_pgm] "a" (&get_lowcore()->program_new_psw), [addr] "a" (addr) - : "cc", "memory"); - return rc; + : CC_CLOBBER_LIST("memory")); + cc = exception ? -EFAULT : CC_TRANSFORM(cc); + return cc; } static unsigned long search_mem_end(void) @@ -157,7 +199,9 @@ unsigned long detect_max_physmem_end(void) { unsigned long max_physmem_end = 0; - if (!sclp_early_get_memsize(&max_physmem_end)) { + if (!diag500_storage_limit(&max_physmem_end)) { + physmem_info.info_source = MEM_DETECT_DIAG500_STOR_LIMIT; + } else if (!sclp_early_get_memsize(&max_physmem_end)) { physmem_info.info_source = MEM_DETECT_SCLP_READ_INFO; } else { max_physmem_end = search_mem_end(); @@ -170,6 +214,13 @@ 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 (physmem_info.info_source == MEM_DETECT_DIAG500_STOR_LIMIT) { + unsigned long online_end; + + if (!sclp_early_get_memsize(&online_end)) { + physmem_info.info_source = MEM_DETECT_SCLP_READ_INFO; + add_physmem_online_range(0, online_end); + } } else if (!diag260()) { physmem_info.info_source = MEM_DETECT_DIAG260; } else if (max_physmem_end) { diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index c8f149ad77e584..6087d38c723512 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -182,12 +182,15 @@ static void kaslr_adjust_got(unsigned long offset) * Merge information from several sources into a single ident_map_size value. * "ident_map_size" represents the upper limit of physical memory we may ever * reach. It might not be all online memory, but also include standby (offline) - * memory. "ident_map_size" could be lower then actual standby or even online + * memory or memory areas reserved for other means (e.g., memory devices such as + * virtio-mem). + * + * "ident_map_size" could be lower then actual standby/reserved or even online * memory present, due to limiting factors. We should never go above this limit. * It is the size of our identity mapping. * * Consider the following factors: - * 1. max_physmem_end - end of physical memory online or standby. + * 1. max_physmem_end - end of physical memory online, standby or reserved. * 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. @@ -231,6 +234,8 @@ static unsigned long get_vmem_size(unsigned long identity_size, vsize = round_up(SZ_2G + max_mappable, rte_size) + round_up(vmemmap_size, rte_size) + FIXMAP_SIZE + MODULES_LEN + KASLR_LEN; + if (IS_ENABLED(CONFIG_KMSAN)) + vsize += MODULES_LEN * 2; return size_add(vsize, vmalloc_size); } @@ -480,7 +485,7 @@ void startup_kernel(void) * __vmlinux_relocs_64_end as the lower range address. However, * .amode31 section is written to by the decompressed kernel - at * that time the contents of .vmlinux.relocs is not needed anymore. - * Conversly, .vmlinux.relocs is read only by the decompressor, even + * Conversely, .vmlinux.relocs is read only by the decompressor, even * before the kernel started. Therefore, in case the two sections * overlap there is no risk of corrupting any data. */ diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c index 318e6ba95bfd27..4568e8f81dac1d 100644 --- a/arch/s390/boot/uv.c +++ b/arch/s390/boot/uv.c @@ -22,8 +22,8 @@ void uv_query_info(void) if (!test_facility(158)) return; - /* rc==0x100 means that there is additional data we do not process */ - if (uv_call(0, (uint64_t)&uvcb) && uvcb.header.rc != 0x100) + /* Ignore that there might be more data we do not process */ + if (uv_call(0, (uint64_t)&uvcb) && uvcb.header.rc != UVC_RC_MORE_DATA) return; if (IS_ENABLED(CONFIG_KVM)) { @@ -46,7 +46,8 @@ void uv_query_info(void) uv_info.supp_add_secret_req_ver = uvcb.supp_add_secret_req_ver; uv_info.supp_add_secret_pcf = uvcb.supp_add_secret_pcf; uv_info.supp_secret_types = uvcb.supp_secret_types; - uv_info.max_secrets = uvcb.max_secrets; + uv_info.max_assoc_secrets = uvcb.max_assoc_secrets; + uv_info.max_retr_secrets = uvcb.max_retr_secrets; } if (test_bit_inv(BIT_UVC_CMD_SET_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list) && diff --git a/arch/s390/boot/vmem.c b/arch/s390/boot/vmem.c index 145035f84a0e3e..3fa28db2fe59f4 100644 --- a/arch/s390/boot/vmem.c +++ b/arch/s390/boot/vmem.c @@ -306,7 +306,7 @@ static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long e pages++; } } - if (mode == POPULATE_DIRECT) + if (mode == POPULATE_IDENTITY) update_page_count(PG_DIRECT_MAP_4K, pages); } @@ -339,7 +339,7 @@ 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) + if (mode == POPULATE_IDENTITY) update_page_count(PG_DIRECT_MAP_1M, pages); } @@ -372,7 +372,7 @@ 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) + if (mode == POPULATE_IDENTITY) update_page_count(PG_DIRECT_MAP_2G, pages); } diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index fb0e9a1d9be254..d8d227ab82de0e 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -625,6 +625,7 @@ CONFIG_VFIO_PCI=m CONFIG_MLX5_VFIO_PCI=m CONFIG_VIRTIO_PCI=m CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_MEM=m CONFIG_VIRTIO_INPUT=y CONFIG_VHOST_NET=m CONFIG_VHOST_VSOCK=m @@ -810,6 +811,7 @@ CONFIG_PKEY=m CONFIG_PKEY_CCA=m CONFIG_PKEY_EP11=m CONFIG_PKEY_PCKMO=m +CONFIG_PKEY_UV=m CONFIG_CRYPTO_PAES_S390=m CONFIG_CRYPTO_DEV_VIRTIO=m CONFIG_SYSTEM_BLACKLIST_KEYRING=y diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index 88be0a734b60f6..6c2f2bb4fbf8f6 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -615,6 +615,7 @@ CONFIG_VFIO_PCI=m CONFIG_MLX5_VFIO_PCI=m CONFIG_VIRTIO_PCI=m CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_MEM=m CONFIG_VIRTIO_INPUT=y CONFIG_VHOST_NET=m CONFIG_VHOST_VSOCK=m @@ -797,6 +798,7 @@ CONFIG_PKEY=m CONFIG_PKEY_CCA=m CONFIG_PKEY_EP11=m CONFIG_PKEY_PCKMO=m +CONFIG_PKEY_UV=m CONFIG_CRYPTO_PAES_S390=m CONFIG_CRYPTO_DEV_VIRTIO=m CONFIG_SYSTEM_BLACKLIST_KEYRING=y diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 8cc02d6e0d0fec..9c46b1b630b1ad 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -1168,4 +1168,4 @@ MODULE_ALIAS_CRYPTO("aes-all"); MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c index ef4491ccbbf84a..511093713a6fc8 100644 --- a/arch/s390/crypto/paes_s390.c +++ b/arch/s390/crypto/paes_s390.c @@ -34,14 +34,22 @@ * is called. As paes can handle different kinds of key blobs * and padding is also possible, the limits need to be generous. */ -#define PAES_MIN_KEYSIZE 16 -#define PAES_MAX_KEYSIZE MAXEP11AESKEYBLOBSIZE +#define PAES_MIN_KEYSIZE 16 +#define PAES_MAX_KEYSIZE MAXEP11AESKEYBLOBSIZE +#define PAES_256_PROTKEY_SIZE (32 + 32) /* key + verification pattern */ +#define PXTS_256_PROTKEY_SIZE (32 + 32 + 32) /* k1 + k2 + verification pattern */ static u8 *ctrblk; static DEFINE_MUTEX(ctrblk_lock); static cpacf_mask_t km_functions, kmc_functions, kmctr_functions; +struct paes_protkey { + u32 type; + u32 len; + u8 protkey[PXTS_256_PROTKEY_SIZE]; +}; + struct key_blob { /* * Small keys will be stored in the keybuf. Larger keys are @@ -55,31 +63,43 @@ struct key_blob { unsigned int keylen; }; -static inline int _key_to_kb(struct key_blob *kb, - const u8 *key, - unsigned int keylen) +/* + * make_clrkey_token() - wrap the raw key ck with pkey clearkey token + * information. + * @returns the size of the clearkey token + */ +static inline u32 make_clrkey_token(const u8 *ck, size_t cklen, u8 *dest) { - struct clearkey_header { + struct clrkey_token { u8 type; u8 res0[3]; u8 version; u8 res1[3]; u32 keytype; u32 len; - } __packed * h; + u8 key[]; + } __packed *token = (struct clrkey_token *)dest; + + token->type = 0x00; + token->version = 0x02; + token->keytype = (cklen - 8) >> 3; + token->len = cklen; + memcpy(token->key, ck, cklen); + + return sizeof(*token) + cklen; +} +static inline int _key_to_kb(struct key_blob *kb, + const u8 *key, + unsigned int keylen) +{ switch (keylen) { case 16: case 24: case 32: /* clear key value, prepare pkey clear key token in keybuf */ memset(kb->keybuf, 0, sizeof(kb->keybuf)); - h = (struct clearkey_header *) kb->keybuf; - h->version = 0x02; /* TOKVER_CLEAR_KEY */ - h->keytype = (keylen - 8) >> 3; - h->len = keylen; - memcpy(kb->keybuf + sizeof(*h), key, keylen); - kb->keylen = sizeof(*h) + keylen; + kb->keylen = make_clrkey_token(key, keylen, kb->keybuf); kb->key = kb->keybuf; break; default: @@ -99,6 +119,40 @@ static inline int _key_to_kb(struct key_blob *kb, return 0; } +static inline int _xts_key_to_kb(struct key_blob *kb, + const u8 *key, + unsigned int keylen) +{ + size_t cklen = keylen / 2; + + memset(kb->keybuf, 0, sizeof(kb->keybuf)); + + switch (keylen) { + case 32: + case 64: + /* clear key value, prepare pkey clear key tokens in keybuf */ + kb->key = kb->keybuf; + kb->keylen = make_clrkey_token(key, cklen, kb->key); + kb->keylen += make_clrkey_token(key + cklen, cklen, + kb->key + kb->keylen); + break; + default: + /* other key material, let pkey handle this */ + if (keylen <= sizeof(kb->keybuf)) { + kb->key = kb->keybuf; + } else { + kb->key = kmalloc(keylen, GFP_KERNEL); + if (!kb->key) + return -ENOMEM; + } + memcpy(kb->key, key, keylen); + kb->keylen = keylen; + break; + } + + return 0; +} + static inline void _free_kb_keybuf(struct key_blob *kb) { if (kb->key && kb->key != kb->keybuf @@ -106,52 +160,53 @@ static inline void _free_kb_keybuf(struct key_blob *kb) kfree_sensitive(kb->key); kb->key = NULL; } + memzero_explicit(kb->keybuf, sizeof(kb->keybuf)); } struct s390_paes_ctx { struct key_blob kb; - struct pkey_protkey pk; + struct paes_protkey pk; spinlock_t pk_lock; unsigned long fc; }; struct s390_pxts_ctx { - struct key_blob kb[2]; - struct pkey_protkey pk[2]; + struct key_blob kb; + struct paes_protkey pk[2]; spinlock_t pk_lock; unsigned long fc; }; -static inline int __paes_keyblob2pkey(struct key_blob *kb, - struct pkey_protkey *pk) +static inline int __paes_keyblob2pkey(const u8 *key, unsigned int keylen, + struct paes_protkey *pk) { - int i, ret = -EIO; + int i, rc = -EIO; /* try three times in case of busy card */ - for (i = 0; ret && i < 3; i++) { - if (ret == -EBUSY && in_task()) { + for (i = 0; rc && i < 3; i++) { + if (rc == -EBUSY && in_task()) { if (msleep_interruptible(1000)) return -EINTR; } - ret = pkey_key2protkey(kb->key, kb->keylen, - pk->protkey, &pk->len, &pk->type); + rc = pkey_key2protkey(key, keylen, pk->protkey, &pk->len, + &pk->type); } - return ret; + return rc; } static inline int __paes_convert_key(struct s390_paes_ctx *ctx) { - int ret; - struct pkey_protkey pkey; + struct paes_protkey pk; + int rc; - pkey.len = sizeof(pkey.protkey); - ret = __paes_keyblob2pkey(&ctx->kb, &pkey); - if (ret) - return ret; + pk.len = sizeof(pk.protkey); + rc = __paes_keyblob2pkey(ctx->kb.key, ctx->kb.keylen, &pk); + if (rc) + return rc; spin_lock_bh(&ctx->pk_lock); - memcpy(&ctx->pk, &pkey, sizeof(pkey)); + memcpy(&ctx->pk, &pk, sizeof(pk)); spin_unlock_bh(&ctx->pk_lock); return 0; @@ -176,8 +231,8 @@ static void ecb_paes_exit(struct crypto_skcipher *tfm) static inline int __ecb_paes_set_key(struct s390_paes_ctx *ctx) { - int rc; unsigned long fc; + int rc; rc = __paes_convert_key(ctx); if (rc) @@ -197,8 +252,8 @@ static inline int __ecb_paes_set_key(struct s390_paes_ctx *ctx) static int ecb_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, unsigned int key_len) { - int rc; struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); + int rc; _free_kb_keybuf(&ctx->kb); rc = _key_to_kb(&ctx->kb, in_key, key_len); @@ -212,19 +267,19 @@ static int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes, n, k; - int ret; struct { - u8 key[MAXPROTKEYSIZE]; + u8 key[PAES_256_PROTKEY_SIZE]; } param; + struct skcipher_walk walk; + unsigned int nbytes, n, k; + int rc; - ret = skcipher_walk_virt(&walk, req, false); - if (ret) - return ret; + rc = skcipher_walk_virt(&walk, req, false); + if (rc) + return rc; spin_lock_bh(&ctx->pk_lock); - memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); + memcpy(param.key, ctx->pk.protkey, PAES_256_PROTKEY_SIZE); spin_unlock_bh(&ctx->pk_lock); while ((nbytes = walk.nbytes) != 0) { @@ -233,16 +288,16 @@ static int ecb_paes_crypt(struct skcipher_request *req, unsigned long modifier) k = cpacf_km(ctx->fc | modifier, ¶m, walk.dst.virt.addr, walk.src.virt.addr, n); if (k) - ret = skcipher_walk_done(&walk, nbytes - k); + rc = skcipher_walk_done(&walk, nbytes - k); if (k < n) { if (__paes_convert_key(ctx)) return skcipher_walk_done(&walk, -EIO); spin_lock_bh(&ctx->pk_lock); - memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); + memcpy(param.key, ctx->pk.protkey, PAES_256_PROTKEY_SIZE); spin_unlock_bh(&ctx->pk_lock); } } - return ret; + return rc; } static int ecb_paes_encrypt(struct skcipher_request *req) @@ -291,8 +346,8 @@ static void cbc_paes_exit(struct crypto_skcipher *tfm) static inline int __cbc_paes_set_key(struct s390_paes_ctx *ctx) { - int rc; unsigned long fc; + int rc; rc = __paes_convert_key(ctx); if (rc) @@ -312,8 +367,8 @@ static inline int __cbc_paes_set_key(struct s390_paes_ctx *ctx) static int cbc_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, unsigned int key_len) { - int rc; struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); + int rc; _free_kb_keybuf(&ctx->kb); rc = _key_to_kb(&ctx->kb, in_key, key_len); @@ -327,21 +382,21 @@ static int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes, n, k; - int ret; struct { u8 iv[AES_BLOCK_SIZE]; - u8 key[MAXPROTKEYSIZE]; + u8 key[PAES_256_PROTKEY_SIZE]; } param; + struct skcipher_walk walk; + unsigned int nbytes, n, k; + int rc; - ret = skcipher_walk_virt(&walk, req, false); - if (ret) - return ret; + rc = skcipher_walk_virt(&walk, req, false); + if (rc) + return rc; memcpy(param.iv, walk.iv, AES_BLOCK_SIZE); spin_lock_bh(&ctx->pk_lock); - memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); + memcpy(param.key, ctx->pk.protkey, PAES_256_PROTKEY_SIZE); spin_unlock_bh(&ctx->pk_lock); while ((nbytes = walk.nbytes) != 0) { @@ -351,17 +406,17 @@ static int cbc_paes_crypt(struct skcipher_request *req, unsigned long modifier) walk.dst.virt.addr, walk.src.virt.addr, n); if (k) { memcpy(walk.iv, param.iv, AES_BLOCK_SIZE); - ret = skcipher_walk_done(&walk, nbytes - k); + rc = skcipher_walk_done(&walk, nbytes - k); } if (k < n) { if (__paes_convert_key(ctx)) return skcipher_walk_done(&walk, -EIO); spin_lock_bh(&ctx->pk_lock); - memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); + memcpy(param.key, ctx->pk.protkey, PAES_256_PROTKEY_SIZE); spin_unlock_bh(&ctx->pk_lock); } } - return ret; + return rc; } static int cbc_paes_encrypt(struct skcipher_request *req) @@ -396,8 +451,7 @@ static int xts_paes_init(struct crypto_skcipher *tfm) { struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); - ctx->kb[0].key = NULL; - ctx->kb[1].key = NULL; + ctx->kb.key = NULL; spin_lock_init(&ctx->pk_lock); return 0; @@ -407,24 +461,51 @@ static void xts_paes_exit(struct crypto_skcipher *tfm) { struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); - _free_kb_keybuf(&ctx->kb[0]); - _free_kb_keybuf(&ctx->kb[1]); + _free_kb_keybuf(&ctx->kb); } static inline int __xts_paes_convert_key(struct s390_pxts_ctx *ctx) { - struct pkey_protkey pkey0, pkey1; + struct paes_protkey pk0, pk1; + size_t split_keylen; + int rc; - pkey0.len = sizeof(pkey0.protkey); - pkey1.len = sizeof(pkey1.protkey); + pk0.len = sizeof(pk0.protkey); + pk1.len = sizeof(pk1.protkey); - if (__paes_keyblob2pkey(&ctx->kb[0], &pkey0) || - __paes_keyblob2pkey(&ctx->kb[1], &pkey1)) + rc = __paes_keyblob2pkey(ctx->kb.key, ctx->kb.keylen, &pk0); + if (rc) + return rc; + + switch (pk0.type) { + case PKEY_KEYTYPE_AES_128: + case PKEY_KEYTYPE_AES_256: + /* second keytoken required */ + if (ctx->kb.keylen % 2) + return -EINVAL; + split_keylen = ctx->kb.keylen / 2; + + rc = __paes_keyblob2pkey(ctx->kb.key + split_keylen, + split_keylen, &pk1); + if (rc) + return rc; + + if (pk0.type != pk1.type) + return -EINVAL; + break; + case PKEY_KEYTYPE_AES_XTS_128: + case PKEY_KEYTYPE_AES_XTS_256: + /* single key */ + pk1.type = 0; + break; + default: + /* unsupported protected keytype */ return -EINVAL; + } spin_lock_bh(&ctx->pk_lock); - memcpy(&ctx->pk[0], &pkey0, sizeof(pkey0)); - memcpy(&ctx->pk[1], &pkey1, sizeof(pkey1)); + ctx->pk[0] = pk0; + ctx->pk[1] = pk1; spin_unlock_bh(&ctx->pk_lock); return 0; @@ -433,17 +514,30 @@ static inline int __xts_paes_convert_key(struct s390_pxts_ctx *ctx) static inline int __xts_paes_set_key(struct s390_pxts_ctx *ctx) { unsigned long fc; + int rc; - if (__xts_paes_convert_key(ctx)) - return -EINVAL; - - if (ctx->pk[0].type != ctx->pk[1].type) - return -EINVAL; + rc = __xts_paes_convert_key(ctx); + if (rc) + return rc; /* Pick the correct function code based on the protected key type */ - fc = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? CPACF_KM_PXTS_128 : - (ctx->pk[0].type == PKEY_KEYTYPE_AES_256) ? - CPACF_KM_PXTS_256 : 0; + switch (ctx->pk[0].type) { + case PKEY_KEYTYPE_AES_128: + fc = CPACF_KM_PXTS_128; + break; + case PKEY_KEYTYPE_AES_256: + fc = CPACF_KM_PXTS_256; + break; + case PKEY_KEYTYPE_AES_XTS_128: + fc = CPACF_KM_PXTS_128_FULL; + break; + case PKEY_KEYTYPE_AES_XTS_256: + fc = CPACF_KM_PXTS_256_FULL; + break; + default: + fc = 0; + break; + } /* Check if the function code is available */ ctx->fc = (fc && cpacf_test_func(&km_functions, fc)) ? fc : 0; @@ -452,24 +546,19 @@ static inline int __xts_paes_set_key(struct s390_pxts_ctx *ctx) } static int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, - unsigned int xts_key_len) + unsigned int in_keylen) { - int rc; struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); u8 ckey[2 * AES_MAX_KEY_SIZE]; - unsigned int ckey_len, key_len; + unsigned int ckey_len; + int rc; - if (xts_key_len % 2) + if ((in_keylen == 32 || in_keylen == 64) && + xts_verify_key(tfm, in_key, in_keylen)) return -EINVAL; - key_len = xts_key_len / 2; - - _free_kb_keybuf(&ctx->kb[0]); - _free_kb_keybuf(&ctx->kb[1]); - rc = _key_to_kb(&ctx->kb[0], in_key, key_len); - if (rc) - return rc; - rc = _key_to_kb(&ctx->kb[1], in_key + key_len, key_len); + _free_kb_keybuf(&ctx->kb); + rc = _xts_key_to_kb(&ctx->kb, in_key, in_keylen); if (rc) return rc; @@ -477,6 +566,13 @@ static int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, if (rc) return rc; + /* + * It is not possible on a single protected key (e.g. full AES-XTS) to + * check, if k1 and k2 are the same. + */ + if (ctx->pk[0].type == PKEY_KEYTYPE_AES_XTS_128 || + ctx->pk[0].type == PKEY_KEYTYPE_AES_XTS_256) + return 0; /* * xts_verify_key verifies the key length is not odd and makes * sure that the two keys are not the same. This can be done @@ -489,28 +585,82 @@ static int xts_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, return xts_verify_key(tfm, ckey, 2*ckey_len); } -static int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier) +static int paes_xts_crypt_full(struct skcipher_request *req, + unsigned long modifier) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); + unsigned int keylen, offset, nbytes, n, k; + struct { + u8 key[64]; + u8 tweak[16]; + u8 nap[16]; + u8 wkvp[32]; + } fxts_param = { + .nap = {0}, + }; struct skcipher_walk walk; + int rc; + + rc = skcipher_walk_virt(&walk, req, false); + if (rc) + return rc; + + keylen = (ctx->pk[0].type == PKEY_KEYTYPE_AES_XTS_128) ? 32 : 64; + offset = (ctx->pk[0].type == PKEY_KEYTYPE_AES_XTS_128) ? 32 : 0; + + spin_lock_bh(&ctx->pk_lock); + memcpy(fxts_param.key + offset, ctx->pk[0].protkey, keylen); + memcpy(fxts_param.wkvp, ctx->pk[0].protkey + keylen, + sizeof(fxts_param.wkvp)); + spin_unlock_bh(&ctx->pk_lock); + memcpy(fxts_param.tweak, walk.iv, sizeof(fxts_param.tweak)); + fxts_param.nap[0] = 0x01; /* initial alpha power (1, little-endian) */ + + while ((nbytes = walk.nbytes) != 0) { + /* only use complete blocks */ + n = nbytes & ~(AES_BLOCK_SIZE - 1); + k = cpacf_km(ctx->fc | modifier, fxts_param.key + offset, + walk.dst.virt.addr, walk.src.virt.addr, n); + if (k) + rc = skcipher_walk_done(&walk, nbytes - k); + if (k < n) { + if (__xts_paes_convert_key(ctx)) + return skcipher_walk_done(&walk, -EIO); + spin_lock_bh(&ctx->pk_lock); + memcpy(fxts_param.key + offset, ctx->pk[0].protkey, + keylen); + memcpy(fxts_param.wkvp, ctx->pk[0].protkey + keylen, + sizeof(fxts_param.wkvp)); + spin_unlock_bh(&ctx->pk_lock); + } + } + + return rc; +} + +static int paes_xts_crypt(struct skcipher_request *req, unsigned long modifier) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); unsigned int keylen, offset, nbytes, n, k; - int ret; struct { - u8 key[MAXPROTKEYSIZE]; /* key + verification pattern */ + u8 key[PAES_256_PROTKEY_SIZE]; u8 tweak[16]; u8 block[16]; u8 bit[16]; u8 xts[16]; } pcc_param; struct { - u8 key[MAXPROTKEYSIZE]; /* key + verification pattern */ + u8 key[PAES_256_PROTKEY_SIZE]; u8 init[16]; } xts_param; + struct skcipher_walk walk; + int rc; - ret = skcipher_walk_virt(&walk, req, false); - if (ret) - return ret; + rc = skcipher_walk_virt(&walk, req, false); + if (rc) + return rc; keylen = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 48 : 64; offset = (ctx->pk[0].type == PKEY_KEYTYPE_AES_128) ? 16 : 0; @@ -530,7 +680,7 @@ static int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier) k = cpacf_km(ctx->fc | modifier, xts_param.key + offset, walk.dst.virt.addr, walk.src.virt.addr, n); if (k) - ret = skcipher_walk_done(&walk, nbytes - k); + rc = skcipher_walk_done(&walk, nbytes - k); if (k < n) { if (__xts_paes_convert_key(ctx)) return skcipher_walk_done(&walk, -EIO); @@ -541,7 +691,24 @@ static int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier) } } - return ret; + return rc; +} + +static inline int xts_paes_crypt(struct skcipher_request *req, unsigned long modifier) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct s390_pxts_ctx *ctx = crypto_skcipher_ctx(tfm); + + switch (ctx->fc) { + case CPACF_KM_PXTS_128: + case CPACF_KM_PXTS_256: + return paes_xts_crypt(req, modifier); + case CPACF_KM_PXTS_128_FULL: + case CPACF_KM_PXTS_256_FULL: + return paes_xts_crypt_full(req, modifier); + default: + return -EINVAL; + } } static int xts_paes_encrypt(struct skcipher_request *req) @@ -591,8 +758,8 @@ static void ctr_paes_exit(struct crypto_skcipher *tfm) static inline int __ctr_paes_set_key(struct s390_paes_ctx *ctx) { - int rc; unsigned long fc; + int rc; rc = __paes_convert_key(ctx); if (rc) @@ -613,8 +780,8 @@ static inline int __ctr_paes_set_key(struct s390_paes_ctx *ctx) static int ctr_paes_set_key(struct crypto_skcipher *tfm, const u8 *in_key, unsigned int key_len) { - int rc; struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); + int rc; _free_kb_keybuf(&ctx->kb); rc = _key_to_kb(&ctx->kb, in_key, key_len); @@ -644,19 +811,19 @@ static int ctr_paes_crypt(struct skcipher_request *req) struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct s390_paes_ctx *ctx = crypto_skcipher_ctx(tfm); u8 buf[AES_BLOCK_SIZE], *ctrptr; - struct skcipher_walk walk; - unsigned int nbytes, n, k; - int ret, locked; struct { - u8 key[MAXPROTKEYSIZE]; + u8 key[PAES_256_PROTKEY_SIZE]; } param; + struct skcipher_walk walk; + unsigned int nbytes, n, k; + int rc, locked; - ret = skcipher_walk_virt(&walk, req, false); - if (ret) - return ret; + rc = skcipher_walk_virt(&walk, req, false); + if (rc) + return rc; spin_lock_bh(&ctx->pk_lock); - memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); + memcpy(param.key, ctx->pk.protkey, PAES_256_PROTKEY_SIZE); spin_unlock_bh(&ctx->pk_lock); locked = mutex_trylock(&ctrblk_lock); @@ -673,7 +840,7 @@ static int ctr_paes_crypt(struct skcipher_request *req) memcpy(walk.iv, ctrptr + k - AES_BLOCK_SIZE, AES_BLOCK_SIZE); crypto_inc(walk.iv, AES_BLOCK_SIZE); - ret = skcipher_walk_done(&walk, nbytes - k); + rc = skcipher_walk_done(&walk, nbytes - k); } if (k < n) { if (__paes_convert_key(ctx)) { @@ -682,7 +849,7 @@ static int ctr_paes_crypt(struct skcipher_request *req) return skcipher_walk_done(&walk, -EIO); } spin_lock_bh(&ctx->pk_lock); - memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); + memcpy(param.key, ctx->pk.protkey, PAES_256_PROTKEY_SIZE); spin_unlock_bh(&ctx->pk_lock); } } @@ -702,15 +869,15 @@ static int ctr_paes_crypt(struct skcipher_request *req) if (__paes_convert_key(ctx)) return skcipher_walk_done(&walk, -EIO); spin_lock_bh(&ctx->pk_lock); - memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); + memcpy(param.key, ctx->pk.protkey, PAES_256_PROTKEY_SIZE); spin_unlock_bh(&ctx->pk_lock); } memcpy(walk.dst.virt.addr, buf, nbytes); crypto_inc(walk.iv, AES_BLOCK_SIZE); - ret = skcipher_walk_done(&walk, nbytes); + rc = skcipher_walk_done(&walk, nbytes); } - return ret; + return rc; } static struct skcipher_alg ctr_paes_alg = { @@ -750,7 +917,7 @@ static void paes_s390_fini(void) static int __init paes_s390_init(void) { - int ret; + int rc; /* Query available functions for KM, KMC and KMCTR */ cpacf_query(CPACF_KM, &km_functions); @@ -760,23 +927,23 @@ static int __init paes_s390_init(void) if (cpacf_test_func(&km_functions, CPACF_KM_PAES_128) || cpacf_test_func(&km_functions, CPACF_KM_PAES_192) || cpacf_test_func(&km_functions, CPACF_KM_PAES_256)) { - ret = crypto_register_skcipher(&ecb_paes_alg); - if (ret) + rc = crypto_register_skcipher(&ecb_paes_alg); + if (rc) goto out_err; } if (cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) || cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) || cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256)) { - ret = crypto_register_skcipher(&cbc_paes_alg); - if (ret) + rc = crypto_register_skcipher(&cbc_paes_alg); + if (rc) goto out_err; } if (cpacf_test_func(&km_functions, CPACF_KM_PXTS_128) || cpacf_test_func(&km_functions, CPACF_KM_PXTS_256)) { - ret = crypto_register_skcipher(&xts_paes_alg); - if (ret) + rc = crypto_register_skcipher(&xts_paes_alg); + if (rc) goto out_err; } @@ -785,18 +952,18 @@ static int __init paes_s390_init(void) cpacf_test_func(&kmctr_functions, CPACF_KMCTR_PAES_256)) { ctrblk = (u8 *) __get_free_page(GFP_KERNEL); if (!ctrblk) { - ret = -ENOMEM; + rc = -ENOMEM; goto out_err; } - ret = crypto_register_skcipher(&ctr_paes_alg); - if (ret) + rc = crypto_register_skcipher(&ctr_paes_alg); + if (rc) goto out_err; } return 0; out_err: paes_s390_fini(); - return ret; + return rc; } module_init(paes_s390_init); diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index a077087bc6ccfb..2becd77df741e5 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -679,7 +679,7 @@ static ssize_t prng_chunksize_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%u\n", prng_chunk_size); + return sysfs_emit(buf, "%u\n", prng_chunk_size); } static DEVICE_ATTR(chunksize, 0444, prng_chunksize_show, NULL); @@ -698,7 +698,7 @@ static ssize_t prng_counter_show(struct device *dev, counter = prng_data->prngws.byte_counter; mutex_unlock(&prng_data->mutex); - return scnprintf(buf, PAGE_SIZE, "%llu\n", counter); + return sysfs_emit(buf, "%llu\n", counter); } static DEVICE_ATTR(byte_counter, 0444, prng_counter_show, NULL); @@ -707,7 +707,7 @@ static ssize_t prng_errorflag_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d\n", prng_errorflag); + return sysfs_emit(buf, "%d\n", prng_errorflag); } static DEVICE_ATTR(errorflag, 0444, prng_errorflag_show, NULL); @@ -717,9 +717,9 @@ static ssize_t prng_mode_show(struct device *dev, char *buf) { if (prng_mode == PRNG_MODE_TDES) - return scnprintf(buf, PAGE_SIZE, "TDES\n"); + return sysfs_emit(buf, "TDES\n"); else - return scnprintf(buf, PAGE_SIZE, "SHA512\n"); + return sysfs_emit(buf, "SHA512\n"); } static DEVICE_ATTR(mode, 0444, prng_mode_show, NULL); @@ -742,7 +742,7 @@ static ssize_t prng_reseed_limit_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%u\n", prng_reseed_limit); + return sysfs_emit(buf, "%u\n", prng_reseed_limit); } static ssize_t prng_reseed_limit_store(struct device *dev, struct device_attribute *attr, @@ -773,7 +773,7 @@ static ssize_t prng_strength_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "256\n"); + return sysfs_emit(buf, "256\n"); } static DEVICE_ATTR(strength, 0444, prng_strength_show, NULL); diff --git a/arch/s390/include/asm/asm.h b/arch/s390/include/asm/asm.h new file mode 100644 index 00000000000000..ec011b94af2ab8 --- /dev/null +++ b/arch/s390/include/asm/asm.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_S390_ASM_H +#define _ASM_S390_ASM_H + +#include + +/* + * Helper macros to be used for flag output operand handling. + * Inline assemblies must use four of the five supplied macros: + * + * Use CC_IPM(sym) at the end of the inline assembly; this extracts the + * condition code and program mask with the ipm instruction and writes it to + * the variable with symbolic name [sym] if the compiler has no support for + * flag output operands. If the compiler has support for flag output operands + * this generates no code. + * + * Use CC_OUT(sym, var) at the output operand list of an inline assembly. This + * defines an output operand with symbolic name [sym] for the variable + * [var]. [var] must be an int variable and [sym] must be identical with [sym] + * used with CC_IPM(). + * + * Use either CC_CLOBBER or CC_CLOBBER_LIST() for the clobber list. Use + * CC_CLOBBER if the clobber list contains only "cc", otherwise use + * CC_CLOBBER_LIST() and add all clobbers as argument to the macro. + * + * Use CC_TRANSFORM() to convert the variable [var] which contains the + * extracted condition code. If the condition code is extracted with ipm, the + * [var] also contains the program mask. CC_TRANSFORM() moves the condition + * code to the two least significant bits and sets all other bits to zero. + */ +#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !(IS_ENABLED(CONFIG_GCC_ASM_FLAG_OUTPUT_BROKEN)) + +#define __HAVE_ASM_FLAG_OUTPUTS__ + +#define CC_IPM(sym) +#define CC_OUT(sym, var) "=@cc" (var) +#define CC_TRANSFORM(cc) ({ cc; }) +#define CC_CLOBBER +#define CC_CLOBBER_LIST(...) __VA_ARGS__ + +#else + +#define CC_IPM(sym) " ipm %[" __stringify(sym) "]\n" +#define CC_OUT(sym, var) [sym] "=d" (var) +#define CC_TRANSFORM(cc) ({ (cc) >> 28; }) +#define CC_CLOBBER "cc" +#define CC_CLOBBER_LIST(...) "cc", __VA_ARGS__ + +#endif + +#endif /* _ASM_S390_ASM_H */ diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index 0c4cad7d5a5b11..6723fca6401821 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -72,14 +72,24 @@ ATOMIC_OPS(xor) #define arch_atomic_fetch_or arch_atomic_fetch_or #define arch_atomic_fetch_xor arch_atomic_fetch_xor -#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), new)) +static __always_inline int arch_atomic_xchg(atomic_t *v, int new) +{ + return arch_xchg(&v->counter, new); +} +#define arch_atomic_xchg arch_atomic_xchg static __always_inline int arch_atomic_cmpxchg(atomic_t *v, int old, int new) { - return __atomic_cmpxchg(&v->counter, old, new); + return arch_cmpxchg(&v->counter, old, new); } #define arch_atomic_cmpxchg arch_atomic_cmpxchg +static __always_inline bool arch_atomic_try_cmpxchg(atomic_t *v, int *old, int new) +{ + return arch_try_cmpxchg(&v->counter, old, new); +} +#define arch_atomic_try_cmpxchg arch_atomic_try_cmpxchg + #define ATOMIC64_INIT(i) { (i) } static __always_inline s64 arch_atomic64_read(const atomic64_t *v) @@ -112,14 +122,24 @@ static __always_inline void arch_atomic64_add(s64 i, atomic64_t *v) } #define arch_atomic64_add arch_atomic64_add -#define arch_atomic64_xchg(v, new) (arch_xchg(&((v)->counter), new)) +static __always_inline s64 arch_atomic64_xchg(atomic64_t *v, s64 new) +{ + return arch_xchg(&v->counter, new); +} +#define arch_atomic64_xchg arch_atomic64_xchg static __always_inline s64 arch_atomic64_cmpxchg(atomic64_t *v, s64 old, s64 new) { - return __atomic64_cmpxchg((long *)&v->counter, old, new); + return arch_cmpxchg(&v->counter, old, new); } #define arch_atomic64_cmpxchg arch_atomic64_cmpxchg +static __always_inline bool arch_atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new) +{ + return arch_try_cmpxchg(&v->counter, old, new); +} +#define arch_atomic64_try_cmpxchg arch_atomic64_try_cmpxchg + #define ATOMIC64_OPS(op) \ static __always_inline void arch_atomic64_##op(s64 i, atomic64_t *v) \ { \ diff --git a/arch/s390/include/asm/atomic_ops.h b/arch/s390/include/asm/atomic_ops.h index 65380da9e75f3e..1d6b2056fad854 100644 --- a/arch/s390/include/asm/atomic_ops.h +++ b/arch/s390/include/asm/atomic_ops.h @@ -169,79 +169,4 @@ __ATOMIC64_OPS(__atomic64_xor, "xgr") #endif /* MARCH_HAS_Z196_FEATURES */ -static __always_inline int __atomic_cmpxchg(int *ptr, int old, int new) -{ - asm volatile( - " cs %[old],%[new],%[ptr]" - : [old] "+d" (old), [ptr] "+Q" (*ptr) - : [new] "d" (new) - : "cc", "memory"); - return old; -} - -static __always_inline long __atomic64_cmpxchg(long *ptr, long old, long new) -{ - asm volatile( - " csg %[old],%[new],%[ptr]" - : [old] "+d" (old), [ptr] "+QS" (*ptr) - : [new] "d" (new) - : "cc", "memory"); - return old; -} - -/* GCC versions before 14.2.0 may die with an ICE in some configurations. */ -#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !(IS_ENABLED(CONFIG_CC_IS_GCC) && (GCC_VERSION < 140200)) - -static __always_inline bool __atomic_cmpxchg_bool(int *ptr, int old, int new) -{ - int cc; - - asm volatile( - " cs %[old],%[new],%[ptr]" - : [old] "+d" (old), [ptr] "+Q" (*ptr), "=@cc" (cc) - : [new] "d" (new) - : "memory"); - return cc == 0; -} - -static __always_inline bool __atomic64_cmpxchg_bool(long *ptr, long old, long new) -{ - int cc; - - asm volatile( - " csg %[old],%[new],%[ptr]" - : [old] "+d" (old), [ptr] "+QS" (*ptr), "=@cc" (cc) - : [new] "d" (new) - : "memory"); - return cc == 0; -} - -#else /* __GCC_ASM_FLAG_OUTPUTS__ */ - -static __always_inline bool __atomic_cmpxchg_bool(int *ptr, int old, int new) -{ - int old_expected = old; - - asm volatile( - " cs %[old],%[new],%[ptr]" - : [old] "+d" (old), [ptr] "+Q" (*ptr) - : [new] "d" (new) - : "cc", "memory"); - return old == old_expected; -} - -static __always_inline bool __atomic64_cmpxchg_bool(long *ptr, long old, long new) -{ - long old_expected = old; - - asm volatile( - " csg %[old],%[new],%[ptr]" - : [old] "+d" (old), [ptr] "+QS" (*ptr) - : [new] "d" (new) - : "cc", "memory"); - return old == old_expected; -} - -#endif /* __GCC_ASM_FLAG_OUTPUTS__ */ - #endif /* __ARCH_S390_ATOMIC_OPS__ */ diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index aae0315374def2..a9e2006033b77f 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h @@ -11,185 +11,231 @@ #include #include #include +#include -void __xchg_called_with_bad_pointer(void); +void __cmpxchg_called_with_bad_pointer(void); + +static __always_inline u32 __cs_asm(u64 ptr, u32 old, u32 new) +{ + asm volatile( + " cs %[old],%[new],%[ptr]\n" + : [old] "+d" (old), [ptr] "+Q" (*(u32 *)ptr) + : [new] "d" (new) + : "memory", "cc"); + return old; +} + +static __always_inline u64 __csg_asm(u64 ptr, u64 old, u64 new) +{ + asm volatile( + " csg %[old],%[new],%[ptr]\n" + : [old] "+d" (old), [ptr] "+QS" (*(u64 *)ptr) + : [new] "d" (new) + : "memory", "cc"); + return old; +} -static __always_inline unsigned long -__arch_xchg(unsigned long x, unsigned long address, int size) +static inline u8 __arch_cmpxchg1(u64 ptr, u8 old, u8 new) { - unsigned long old; - int shift; + union { + u8 b[4]; + u32 w; + } old32, new32; + u32 prev; + int i; + + i = ptr & 3; + ptr &= ~0x3; + prev = READ_ONCE(*(u32 *)ptr); + do { + old32.w = prev; + if (old32.b[i] != old) + return old32.b[i]; + new32.w = old32.w; + new32.b[i] = new; + prev = __cs_asm(ptr, old32.w, new32.w); + } while (prev != old32.w); + return old; +} + +static inline u16 __arch_cmpxchg2(u64 ptr, u16 old, u16 new) +{ + union { + u16 b[2]; + u32 w; + } old32, new32; + u32 prev; + int i; + + i = (ptr & 3) >> 1; + ptr &= ~0x3; + prev = READ_ONCE(*(u32 *)ptr); + do { + old32.w = prev; + if (old32.b[i] != old) + return old32.b[i]; + new32.w = old32.w; + new32.b[i] = new; + prev = __cs_asm(ptr, old32.w, new32.w); + } while (prev != old32.w); + return old; +} +static __always_inline u64 __arch_cmpxchg(u64 ptr, u64 old, u64 new, int size) +{ switch (size) { - case 1: - shift = (3 ^ (address & 3)) << 3; - address ^= address & 3; - asm volatile( - " l %0,%1\n" - "0: lr 0,%0\n" - " nr 0,%3\n" - " or 0,%2\n" - " cs %0,0,%1\n" - " jl 0b\n" - : "=&d" (old), "+Q" (*(int *) address) - : "d" ((x & 0xff) << shift), "d" (~(0xff << shift)) - : "memory", "cc", "0"); - return old >> shift; - case 2: - shift = (2 ^ (address & 2)) << 3; - address ^= address & 2; - asm volatile( - " l %0,%1\n" - "0: lr 0,%0\n" - " nr 0,%3\n" - " or 0,%2\n" - " cs %0,0,%1\n" - " jl 0b\n" - : "=&d" (old), "+Q" (*(int *) address) - : "d" ((x & 0xffff) << shift), "d" (~(0xffff << shift)) - : "memory", "cc", "0"); - return old >> shift; - case 4: - asm volatile( - " l %0,%1\n" - "0: cs %0,%2,%1\n" - " jl 0b\n" - : "=&d" (old), "+Q" (*(int *) address) - : "d" (x) - : "memory", "cc"); - return old; - case 8: - asm volatile( - " lg %0,%1\n" - "0: csg %0,%2,%1\n" - " jl 0b\n" - : "=&d" (old), "+QS" (*(long *) address) - : "d" (x) - : "memory", "cc"); - return old; + case 1: return __arch_cmpxchg1(ptr, old & 0xff, new & 0xff); + case 2: return __arch_cmpxchg2(ptr, old & 0xffff, new & 0xffff); + case 4: return __cs_asm(ptr, old & 0xffffffff, new & 0xffffffff); + case 8: return __csg_asm(ptr, old, new); + default: __cmpxchg_called_with_bad_pointer(); } - __xchg_called_with_bad_pointer(); - return x; + return old; } -#define arch_xchg(ptr, x) \ +#define arch_cmpxchg(ptr, o, n) \ ({ \ - __typeof__(*(ptr)) __ret; \ + (__typeof__(*(ptr)))__arch_cmpxchg((unsigned long)(ptr), \ + (unsigned long)(o), \ + (unsigned long)(n), \ + sizeof(*(ptr))); \ +}) + +#define arch_cmpxchg64 arch_cmpxchg +#define arch_cmpxchg_local arch_cmpxchg +#define arch_cmpxchg64_local arch_cmpxchg + +#ifdef __HAVE_ASM_FLAG_OUTPUTS__ + +#define arch_try_cmpxchg(ptr, oldp, new) \ +({ \ + __typeof__(ptr) __oldp = (__typeof__(ptr))(oldp); \ + __typeof__(*(ptr)) __old = *__oldp; \ + __typeof__(*(ptr)) __new = (new); \ + __typeof__(*(ptr)) __prev; \ + int __cc; \ \ - __ret = (__typeof__(*(ptr))) \ - __arch_xchg((unsigned long)(x), (unsigned long)(ptr), \ - sizeof(*(ptr))); \ - __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: \ + case 2: { \ + __prev = arch_cmpxchg((ptr), (__old), (__new)); \ + __cc = (__prev != __old); \ + if (unlikely(__cc)) \ + *__oldp = __prev; \ + break; \ + } \ + case 4: { \ + asm volatile( \ + " cs %[__old],%[__new],%[__ptr]\n" \ + : [__old] "+d" (*__oldp), \ + [__ptr] "+Q" (*(ptr)), \ + "=@cc" (__cc) \ + : [__new] "d" (__new) \ + : "memory"); \ + break; \ + } \ + case 8: { \ + asm volatile( \ + " csg %[__old],%[__new],%[__ptr]\n" \ + : [__old] "+d" (*__oldp), \ + [__ptr] "+QS" (*(ptr)), \ + "=@cc" (__cc) \ + : [__new] "d" (__new) \ + : "memory"); \ + break; \ + } \ + default: \ + __cmpxchg_called_with_bad_pointer(); \ + } \ + likely(__cc == 0); \ }) -void __cmpxchg_called_with_bad_pointer(void); +#else /* __HAVE_ASM_FLAG_OUTPUTS__ */ -static __always_inline unsigned long __cmpxchg(unsigned long address, - unsigned long old, - unsigned long new, int size) +#define arch_try_cmpxchg(ptr, oldp, new) \ +({ \ + __typeof__((ptr)) __oldp = (__typeof__(ptr))(oldp); \ + __typeof__(*(ptr)) __old = *__oldp; \ + __typeof__(*(ptr)) __new = (new); \ + __typeof__(*(ptr)) __prev; \ + \ + __prev = arch_cmpxchg((ptr), (__old), (__new)); \ + if (unlikely(__prev != __old)) \ + *__oldp = __prev; \ + likely(__prev == __old); \ +}) + +#endif /* __HAVE_ASM_FLAG_OUTPUTS__ */ + +#define arch_try_cmpxchg64 arch_try_cmpxchg +#define arch_try_cmpxchg_local arch_try_cmpxchg +#define arch_try_cmpxchg64_local arch_try_cmpxchg + +void __xchg_called_with_bad_pointer(void); + +static inline u8 __arch_xchg1(u64 ptr, u8 x) +{ + int shift = (3 ^ (ptr & 3)) << 3; + u32 mask, old, new; + + ptr &= ~0x3; + mask = ~(0xff << shift); + old = READ_ONCE(*(u32 *)ptr); + do { + new = old & mask; + new |= x << shift; + } while (!arch_try_cmpxchg((u32 *)ptr, &old, new)); + return old >> shift; +} + +static inline u16 __arch_xchg2(u64 ptr, u16 x) +{ + int shift = (2 ^ (ptr & 2)) << 3; + u32 mask, old, new; + + ptr &= ~0x3; + mask = ~(0xffff << shift); + old = READ_ONCE(*(u32 *)ptr); + do { + new = old & mask; + new |= x << shift; + } while (!arch_try_cmpxchg((u32 *)ptr, &old, new)); + return old >> shift; +} + +static __always_inline u64 __arch_xchg(u64 ptr, u64 x, int size) { switch (size) { - case 1: { - unsigned int prev, shift, mask; - - shift = (3 ^ (address & 3)) << 3; - address ^= address & 3; - old = (old & 0xff) << shift; - new = (new & 0xff) << shift; - mask = ~(0xff << shift); - asm volatile( - " l %[prev],%[address]\n" - " nr %[prev],%[mask]\n" - " xilf %[mask],0xffffffff\n" - " or %[new],%[prev]\n" - " or %[prev],%[tmp]\n" - "0: lr %[tmp],%[prev]\n" - " cs %[prev],%[new],%[address]\n" - " jnl 1f\n" - " xr %[tmp],%[prev]\n" - " xr %[new],%[tmp]\n" - " nr %[tmp],%[mask]\n" - " jz 0b\n" - "1:" - : [prev] "=&d" (prev), - [address] "+Q" (*(int *)address), - [tmp] "+&d" (old), - [new] "+&d" (new), - [mask] "+&d" (mask) - :: "memory", "cc"); - return prev >> shift; - } - case 2: { - unsigned int prev, shift, mask; - - shift = (2 ^ (address & 2)) << 3; - address ^= address & 2; - old = (old & 0xffff) << shift; - new = (new & 0xffff) << shift; - mask = ~(0xffff << shift); - asm volatile( - " l %[prev],%[address]\n" - " nr %[prev],%[mask]\n" - " xilf %[mask],0xffffffff\n" - " or %[new],%[prev]\n" - " or %[prev],%[tmp]\n" - "0: lr %[tmp],%[prev]\n" - " cs %[prev],%[new],%[address]\n" - " jnl 1f\n" - " xr %[tmp],%[prev]\n" - " xr %[new],%[tmp]\n" - " nr %[tmp],%[mask]\n" - " jz 0b\n" - "1:" - : [prev] "=&d" (prev), - [address] "+Q" (*(int *)address), - [tmp] "+&d" (old), - [new] "+&d" (new), - [mask] "+&d" (mask) - :: "memory", "cc"); - return prev >> shift; - } + case 1: + return __arch_xchg1(ptr, x & 0xff); + case 2: + return __arch_xchg2(ptr, x & 0xffff); case 4: { - unsigned int prev = old; - - asm volatile( - " cs %[prev],%[new],%[address]\n" - : [prev] "+&d" (prev), - [address] "+Q" (*(int *)address) - : [new] "d" (new) - : "memory", "cc"); - return prev; + u32 old = READ_ONCE(*(u32 *)ptr); + + do { + } while (!arch_try_cmpxchg((u32 *)ptr, &old, x & 0xffffffff)); + return old; } case 8: { - unsigned long prev = old; - - asm volatile( - " csg %[prev],%[new],%[address]\n" - : [prev] "+&d" (prev), - [address] "+QS" (*(long *)address) - : [new] "d" (new) - : "memory", "cc"); - return prev; + u64 old = READ_ONCE(*(u64 *)ptr); + + do { + } while (!arch_try_cmpxchg((u64 *)ptr, &old, x)); + return old; } } - __cmpxchg_called_with_bad_pointer(); - return old; + __xchg_called_with_bad_pointer(); + return x; } -#define arch_cmpxchg(ptr, o, n) \ +#define arch_xchg(ptr, x) \ ({ \ - __typeof__(*(ptr)) __ret; \ - \ - __ret = (__typeof__(*(ptr))) \ - __cmpxchg((unsigned long)(ptr), (unsigned long)(o), \ - (unsigned long)(n), sizeof(*(ptr))); \ - __ret; \ + (__typeof__(*(ptr)))__arch_xchg((unsigned long)(ptr), \ + (unsigned long)(x), \ + sizeof(*(ptr))); \ }) -#define arch_cmpxchg64 arch_cmpxchg -#define arch_cmpxchg_local arch_cmpxchg -#define arch_cmpxchg64_local arch_cmpxchg - #define system_has_cmpxchg128() 1 static __always_inline u128 arch_cmpxchg128(volatile u128 *ptr, u128 old, u128 new) @@ -203,5 +249,25 @@ static __always_inline u128 arch_cmpxchg128(volatile u128 *ptr, u128 old, u128 n } #define arch_cmpxchg128 arch_cmpxchg128 +#define arch_cmpxchg128_local arch_cmpxchg128 + +#ifdef __HAVE_ASM_FLAG_OUTPUTS__ + +static __always_inline bool arch_try_cmpxchg128(volatile u128 *ptr, u128 *oldp, u128 new) +{ + int cc; + + asm volatile( + " cdsg %[old],%[new],%[ptr]\n" + : [old] "+d" (*oldp), [ptr] "+QS" (*ptr), "=@cc" (cc) + : [new] "d" (new) + : "memory"); + return likely(cc == 0); +} + +#define arch_try_cmpxchg128 arch_try_cmpxchg128 +#define arch_try_cmpxchg128_local arch_try_cmpxchg128 + +#endif /* __HAVE_ASM_FLAG_OUTPUTS__ */ #endif /* __ASM_CMPXCHG_H */ diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h index 1d3a4b0c650fc1..59ab1192e2d5b4 100644 --- a/arch/s390/include/asm/cpacf.h +++ b/arch/s390/include/asm/cpacf.h @@ -56,6 +56,8 @@ #define CPACF_KM_PXTS_256 0x3c #define CPACF_KM_XTS_128_FULL 0x52 #define CPACF_KM_XTS_256_FULL 0x54 +#define CPACF_KM_PXTS_128_FULL 0x5a +#define CPACF_KM_PXTS_256_FULL 0x5c /* * Function codes for the KMC (CIPHER MESSAGE WITH CHAINING) diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index 9e4bbc3e53f80e..e1a279e0d6a616 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -13,6 +13,7 @@ #include #include #include +#include asm(".include \"asm/cpu_mf-insn.h\"\n"); @@ -185,11 +186,12 @@ static inline int lcctl(u64 ctl) int cc; asm volatile ( - " lcctl %1\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) : "Q" (ctl) : "cc"); - return cc; + " lcctl %[ctl]\n" + CC_IPM(cc) + : CC_OUT(cc, cc) + : [ctl] "Q" (ctl) + : CC_CLOBBER); + return CC_TRANSFORM(cc); } /* Extract CPU counter */ @@ -199,12 +201,13 @@ static inline int __ecctr(u64 ctr, u64 *content) int cc; asm volatile ( - " ecctr %0,%2\n" - " ipm %1\n" - " srl %1,28\n" - : "=d" (_content), "=d" (cc) : "d" (ctr) : "cc"); + " ecctr %[_content],%[ctr]\n" + CC_IPM(cc) + : CC_OUT(cc, cc), [_content] "=d" (_content) + : [ctr] "d" (ctr) + : CC_CLOBBER); *content = _content; - return cc; + return CC_TRANSFORM(cc); } /* Extract CPU counter */ @@ -234,18 +237,17 @@ static __always_inline int stcctm(enum stcctm_ctr_set set, u64 range, u64 *dest) int cc; asm volatile ( - " STCCTM %2,%3,%1\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) - : "Q" (*dest), "d" (range), "i" (set) - : "cc", "memory"); + " STCCTM %[range],%[set],%[dest]\n" + CC_IPM(cc) + : CC_OUT(cc, cc) + : [dest] "Q" (*dest), [range] "d" (range), [set] "i" (set) + : CC_CLOBBER_LIST("memory")); /* * If cc == 2, less than RANGE counters are stored, but it's not easy * to tell how many. Always unpoison the whole range for simplicity. */ kmsan_unpoison_memory(dest, range * sizeof(u64)); - return cc; + return CC_TRANSFORM(cc); } /* Query sampling information */ @@ -265,19 +267,20 @@ static inline int qsi(struct hws_qsi_info_block *info) /* Load sampling controls */ static inline int lsctl(struct hws_lsctl_request_block *req) { - int cc; + int cc, exception; - cc = 1; + exception = 1; asm volatile( - "0: lsctl 0(%1)\n" - "1: ipm %0\n" - " srl %0,28\n" + "0: lsctl %[req]\n" + "1: lhi %[exc],0\n" "2:\n" + CC_IPM(cc) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b) - : "+d" (cc), "+a" (req) - : "m" (*req) - : "cc", "memory"); - - return cc ? -EINVAL : 0; + : CC_OUT(cc, cc), [exc] "+d" (exception) + : [req] "Q" (*req) + : CC_CLOBBER); + if (exception || CC_TRANSFORM(cc)) + return -EINVAL; + return 0; } #endif /* _ASM_S390_CPU_MF_H */ diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h index ccd4e148b5ed47..a7f7bdc9e19cae 100644 --- a/arch/s390/include/asm/debug.h +++ b/arch/s390/include/asm/debug.h @@ -66,14 +66,15 @@ typedef int (debug_header_proc_t) (debug_info_t *id, struct debug_view *view, int area, debug_entry_t *entry, - char *out_buf); + char *out_buf, size_t out_buf_size); typedef int (debug_format_proc_t) (debug_info_t *id, struct debug_view *view, char *out_buf, + size_t out_buf_size, const char *in_buf); typedef int (debug_prolog_proc_t) (debug_info_t *id, struct debug_view *view, - char *out_buf); + char *out_buf, size_t out_buf_size); typedef int (debug_input_proc_t) (debug_info_t *id, struct debug_view *view, struct file *file, @@ -81,7 +82,8 @@ typedef int (debug_input_proc_t) (debug_info_t *id, size_t in_buf_size, loff_t *offset); int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view, - int area, debug_entry_t *entry, char *out_buf); + int area, debug_entry_t *entry, + char *out_buf, size_t out_buf_size); struct debug_view { char name[DEBUG_MAX_NAME_LEN]; diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index 715bcf8fb69a51..5f5b1aa6c23312 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h @@ -88,7 +88,7 @@ static __always_inline bool test_facility(unsigned long nr) return __test_facility(nr, &stfle_fac_list); } -static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size) +static inline unsigned long __stfle_asm(u64 *fac_list, int size) { unsigned long reg0 = size - 1; @@ -96,7 +96,7 @@ static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size) " lgr 0,%[reg0]\n" " .insn s,0xb2b00000,%[list]\n" /* stfle */ " lgr %[reg0],0\n" - : [reg0] "+&d" (reg0), [list] "+Q" (*stfle_fac_list) + : [reg0] "+&d" (reg0), [list] "+Q" (*fac_list) : : "memory", "cc", "0"); return reg0; @@ -104,10 +104,10 @@ static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size) /** * stfle - Store facility list extended - * @stfle_fac_list: array where facility list can be stored + * @fac_list: array where facility list can be stored * @size: size of passed in array in double words */ -static inline void __stfle(u64 *stfle_fac_list, int size) +static inline void __stfle(u64 *fac_list, int size) { unsigned long nr; u32 stfl_fac_list; @@ -116,20 +116,20 @@ static inline void __stfle(u64 *stfle_fac_list, int size) " stfl 0(0)\n" : "=m" (get_lowcore()->stfl_fac_list)); stfl_fac_list = get_lowcore()->stfl_fac_list; - memcpy(stfle_fac_list, &stfl_fac_list, 4); + memcpy(fac_list, &stfl_fac_list, 4); nr = 4; /* bytes stored by stfl */ if (stfl_fac_list & 0x01000000) { /* More facility bits available with stfle */ - nr = __stfle_asm(stfle_fac_list, size); + nr = __stfle_asm(fac_list, size); nr = min_t(unsigned long, (nr + 1) * 8, size * 8); } - memset((char *) stfle_fac_list + nr, 0, size * 8 - nr); + memset((char *)fac_list + nr, 0, size * 8 - nr); } -static inline void stfle(u64 *stfle_fac_list, int size) +static inline void stfle(u64 *fac_list, int size) { preempt_disable(); - __stfle(stfle_fac_list, size); + __stfle(fac_list, size); preempt_enable(); } diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index 406746666eb782..fc97d75dc752c8 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h @@ -51,13 +51,11 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) return addr; } -struct ftrace_regs { - struct pt_regs regs; -}; +#include static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs) { - struct pt_regs *regs = &fregs->regs; + struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; if (test_pt_regs_flag(regs, PIF_FTRACE_FULL_REGS)) return regs; @@ -81,32 +79,13 @@ static __always_inline unsigned long fgraph_ret_regs_frame_pointer(struct fgraph } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -static __always_inline unsigned long -ftrace_regs_get_instruction_pointer(const struct ftrace_regs *fregs) -{ - return fregs->regs.psw.addr; -} - static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) { - fregs->regs.psw.addr = ip; + arch_ftrace_regs(fregs)->regs.psw.addr = 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) - #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS /* * When an ftrace registered caller is tracing a function that is @@ -117,7 +96,7 @@ ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, */ static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr) { - struct pt_regs *regs = &fregs->regs; + struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; regs->orig_gpr2 = addr; } #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h index 9725586f42597c..13f51a6a5bb1bf 100644 --- a/arch/s390/include/asm/gmap.h +++ b/arch/s390/include/asm/gmap.h @@ -17,8 +17,8 @@ #define GMAP_NOTIFY_MPROT 0x1 /* Status bits only for huge segment entries */ -#define _SEGMENT_ENTRY_GMAP_IN 0x8000 /* invalidation notify bit */ -#define _SEGMENT_ENTRY_GMAP_UC 0x4000 /* dirty (migration) */ +#define _SEGMENT_ENTRY_GMAP_IN 0x0800 /* invalidation notify bit */ +#define _SEGMENT_ENTRY_GMAP_UC 0x0002 /* dirty (migration) */ /** * struct gmap_struct - guest address space @@ -107,9 +107,6 @@ void gmap_remove(struct gmap *gmap); struct gmap *gmap_get(struct gmap *gmap); void gmap_put(struct gmap *gmap); -void gmap_enable(struct gmap *gmap); -void gmap_disable(struct gmap *gmap); -struct gmap *gmap_get_enabled(void); int gmap_map_segment(struct gmap *gmap, unsigned long from, unsigned long to, unsigned long len); int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h index cf1b5d6fb1a629..a40664b236e912 100644 --- a/arch/s390/include/asm/hugetlb.h +++ b/arch/s390/include/asm/hugetlb.h @@ -10,41 +10,30 @@ #define _ASM_S390_HUGETLB_H #include +#include +#include #include -#define hugetlb_free_pgd_range free_pgd_range #define hugepages_supported() (MACHINE_HAS_EDAT1) +#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, unsigned long sz); void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte); -pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep); -pte_t huge_ptep_get_and_clear(struct mm_struct *mm, +#define __HAVE_ARCH_HUGE_PTEP_GET +extern pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep); +#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR +extern pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep); -/* - * If the arch doesn't supply something else, assume that hugepage - * size aligned regions are ok without further preparation. - */ -static inline int prepare_hugepage_range(struct file *file, - unsigned long addr, unsigned long len) -{ - struct hstate *h = hstate_file(file); - - if (len & ~huge_page_mask(h)) - return -EINVAL; - if (addr & ~huge_page_mask(h)) - return -EINVAL; - return 0; -} - static inline void arch_clear_hugetlb_flags(struct folio *folio) { clear_bit(PG_arch_1, &folio->flags); } #define arch_clear_hugetlb_flags arch_clear_hugetlb_flags +#define __HAVE_ARCH_HUGE_PTE_CLEAR static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep, unsigned long sz) { @@ -54,12 +43,14 @@ static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr, set_pte(ptep, __pte(_SEGMENT_ENTRY_EMPTY)); } +#define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { return huge_ptep_get_and_clear(vma->vm_mm, address, ptep); } +#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep, pte_t pte, int dirty) @@ -72,6 +63,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, return changed; } +#define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { @@ -79,69 +71,36 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, __set_huge_pte_at(mm, addr, ptep, pte_wrprotect(pte)); } -static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot) -{ - return mk_pte(page, pgprot); -} - +#define __HAVE_ARCH_HUGE_PTE_NONE static inline int huge_pte_none(pte_t pte) { return pte_none(pte); } +#define __HAVE_ARCH_HUGE_PTE_NONE_MOSTLY static inline int huge_pte_none_mostly(pte_t pte) { - return huge_pte_none(pte); -} - -static inline int huge_pte_write(pte_t pte) -{ - return pte_write(pte); -} - -static inline int huge_pte_dirty(pte_t pte) -{ - return pte_dirty(pte); -} - -static inline pte_t huge_pte_mkwrite(pte_t pte) -{ - return pte_mkwrite_novma(pte); -} - -static inline pte_t huge_pte_mkdirty(pte_t pte) -{ - return pte_mkdirty(pte); -} - -static inline pte_t huge_pte_wrprotect(pte_t pte) -{ - return pte_wrprotect(pte); -} - -static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot) -{ - return pte_modify(pte, newprot); + return huge_pte_none(pte) || is_pte_marker(pte); } +#define __HAVE_ARCH_HUGE_PTE_MKUFFD_WP static inline pte_t huge_pte_mkuffd_wp(pte_t pte) { return pte; } +#define __HAVE_ARCH_HUGE_PTE_CLEAR_UFFD_WP static inline pte_t huge_pte_clear_uffd_wp(pte_t pte) { return pte; } +#define __HAVE_ARCH_HUGE_PTE_UFFD_WP static inline int huge_pte_uffd_wp(pte_t pte) { return 0; } -static inline bool gigantic_page_runtime_supported(void) -{ - return true; -} +#include #endif /* _ASM_S390_HUGETLB_H */ diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h index 1bd08eb56d5fc7..9084b750350dbb 100644 --- a/arch/s390/include/asm/kexec.h +++ b/arch/s390/include/asm/kexec.h @@ -94,6 +94,9 @@ void arch_kexec_protect_crashkres(void); void arch_kexec_unprotect_crashkres(void); #define arch_kexec_unprotect_crashkres arch_kexec_unprotect_crashkres + +bool is_kdump_kernel(void); +#define is_kdump_kernel is_kdump_kernel #endif #ifdef CONFIG_KEXEC_FILE diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 8e77afbed58ec2..97c7c812754345 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -94,11 +94,16 @@ union ipte_control { }; }; +/* + * Utility is defined as two bytes but having it four bytes wide + * generates more efficient code. Since the following bytes are + * reserved this makes no functional difference. + */ union sca_utility { - __u16 val; + __u32 val; struct { - __u16 mtcr : 1; - __u16 reserved : 15; + __u32 mtcr : 1; + __u32 : 31; }; }; @@ -107,7 +112,7 @@ struct bsca_block { __u64 reserved[5]; __u64 mcn; union sca_utility utility; - __u8 reserved2[6]; + __u8 reserved2[4]; struct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS]; }; @@ -115,7 +120,7 @@ struct esca_block { union ipte_control ipte_control; __u64 reserved1[6]; union sca_utility utility; - __u8 reserved2[6]; + __u8 reserved2[4]; __u64 mcn[4]; __u64 reserved3[20]; struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS]; @@ -356,6 +361,7 @@ struct kvm_s390_sie_block { #define ECD_MEF 0x08000000 #define ECD_ETOKENF 0x02000000 #define ECD_ECC 0x00200000 +#define ECD_HMAC 0x00004000 __u32 ecd; /* 0x01c8 */ __u8 reserved1cc[18]; /* 0x01cc */ __u64 pp; /* 0x01de */ @@ -527,6 +533,9 @@ struct kvm_vcpu_stat { #define PGM_REGION_FIRST_TRANS 0x39 #define PGM_REGION_SECOND_TRANS 0x3a #define PGM_REGION_THIRD_TRANS 0x3b +#define PGM_SECURE_STORAGE_ACCESS 0x3d +#define PGM_NON_SECURE_STORAGE_ACCESS 0x3e +#define PGM_SECURE_STORAGE_VIOLATION 0x3f #define PGM_MONITOR 0x40 #define PGM_PER 0x80 #define PGM_CRYPTO_OPERATION 0x119 @@ -747,8 +756,6 @@ struct kvm_vcpu_arch { struct hrtimer ckc_timer; struct kvm_s390_pgm_info pgm; struct gmap *gmap; - /* backup location for the currently enabled gmap when scheduled out */ - struct gmap *enabled_gmap; struct kvm_guestdbg_info_arch guestdbg; unsigned long pfault_token; unsigned long pfault_select; diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 48c64716d1f2fd..42a092fa102972 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -165,8 +165,7 @@ struct lowcore { __u64 percpu_offset; /* 0x03b8 */ __u8 pad_0x03c0[0x03c8-0x03c0]; /* 0x03c0 */ __u64 machine_flags; /* 0x03c8 */ - __u64 gmap; /* 0x03d0 */ - __u8 pad_0x03d8[0x0400-0x03d8]; /* 0x03d8 */ + __u8 pad_0x03d0[0x0400-0x03d0]; /* 0x03d0 */ __u32 return_lpswe; /* 0x0400 */ __u32 return_mcck_lpswe; /* 0x0404 */ diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 73e1e03317b433..4f43cdd9835b69 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -10,15 +10,10 @@ #include #include +#include -#define _PAGE_SHIFT CONFIG_PAGE_SHIFT -#define _PAGE_SIZE (_AC(1, UL) << _PAGE_SHIFT) -#define _PAGE_MASK (~(_PAGE_SIZE - 1)) +#include -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT _PAGE_SHIFT -#define PAGE_SIZE _PAGE_SIZE -#define PAGE_MASK _PAGE_MASK #define PAGE_DEFAULT_ACC _AC(0, UL) /* storage-protection override */ #define PAGE_SPO_ACC 9 @@ -74,7 +69,7 @@ static inline void copy_page(void *to, void *from) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #define vma_alloc_zeroed_movable_folio(vma, vaddr) \ - vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false) + vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr) /* * These are used to make use of C type-checking.. @@ -148,11 +143,12 @@ static inline int page_reset_referenced(unsigned long addr) int cc; asm volatile( - " rrbe 0,%1\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) : "a" (addr) : "cc"); - return cc; + " rrbe 0,%[addr]\n" + CC_IPM(cc) + : CC_OUT(cc, cc) + : [addr] "a" (addr) + : CC_CLOBBER); + return CC_TRANSFORM(cc); } /* Bits int the storage key */ @@ -245,9 +241,7 @@ static inline unsigned long __phys_addr(unsigned long x, bool is_31bit) #define phys_to_pfn(phys) ((phys) >> PAGE_SHIFT) #define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) -#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys)) #define phys_to_folio(phys) page_folio(phys_to_page(phys)) -#define page_to_phys(page) pfn_to_phys(page_to_pfn(page)) #define folio_to_phys(page) pfn_to_phys(folio_pfn(folio)) static inline void *pfn_to_virt(unsigned long pfn) diff --git a/arch/s390/include/asm/pai.h b/arch/s390/include/asm/pai.h index 25f2077ba3c979..ebeabd0aaa516a 100644 --- a/arch/s390/include/asm/pai.h +++ b/arch/s390/include/asm/pai.h @@ -11,6 +11,7 @@ #include #include #include +#include struct qpaci_info_block { u64 header; @@ -33,12 +34,11 @@ static inline int qpaci(struct qpaci_info_block *info) " lgr 0,%[size]\n" " .insn s,0xb28f0000,%[info]\n" " lgr %[size],0\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=d" (cc), [info] "=Q" (*info), [size] "+&d" (size) + CC_IPM(cc) + : CC_OUT(cc, cc), [info] "=Q" (*info), [size] "+&d" (size) : - : "0", "cc", "memory"); - return cc ? (size + 1) * sizeof(u64) : 0; + : CC_CLOBBER_LIST("0", "memory")); + return CC_TRANSFORM(cc) ? (size + 1) * sizeof(u64) : 0; } #define PAI_CRYPTO_BASE 0x1000 /* First event number */ diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 9d920ced604754..474e1f8d1d3c2f 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -96,7 +96,6 @@ struct zpci_bar_struct { u8 size; /* order 2 exponent */ }; -struct s390_domain; struct kvm_zdev; #define ZPCI_FUNCTIONS_PER_BUS 256 @@ -107,9 +106,10 @@ struct zpci_bus { struct list_head resources; struct list_head bus_next; struct resource bus_resource; - int pchid; + int topo; /* TID if topo_is_tid, PCHID otherwise */ int domain_nr; - bool multifunction; + u8 multifunction : 1; + u8 topo_is_tid : 1; enum pci_bus_speed max_bus_speed; }; @@ -130,9 +130,12 @@ struct zpci_dev { u16 vfn; /* virtual function number */ u16 pchid; /* physical channel ID */ u16 maxstbl; /* Maximum store block size */ + u16 rid; /* RID as supplied by firmware */ + u16 tid; /* Topology for which RID is valid */ u8 pfgid; /* function group ID */ u8 pft; /* pci function type */ u8 port; + u8 fidparm; u8 dtsm; /* Supported DT mask */ u8 rid_available : 1; u8 has_hp_slot : 1; @@ -140,7 +143,8 @@ struct zpci_dev { u8 is_physfn : 1; u8 util_str_avail : 1; u8 irqs_registered : 1; - u8 reserved : 2; + u8 tid_avail : 1; + u8 reserved : 1; unsigned int devfn; /* DEVFN part of the RID*/ u8 pfip[CLP_PFIP_NR_SEGMENTS]; /* pci function internal path */ @@ -181,9 +185,10 @@ struct zpci_dev { struct dentry *debugfs_dev; /* IOMMU and passthrough */ - struct s390_domain *s390_domain; /* s390 IOMMU domain data */ + struct iommu_domain *s390_domain; /* attached IOMMU domain */ struct kvm_zdev *kzdev; struct mutex kzdev_lock; + spinlock_t dom_lock; /* protect s390_domain change */ }; static inline bool zdev_enabled(struct zpci_dev *zdev) @@ -210,12 +215,14 @@ extern struct airq_iv *zpci_aif_sbv; ----------------------------------------------------------------------------- */ /* Base stuff */ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state); +int zpci_add_device(struct zpci_dev *zdev); int zpci_enable_device(struct zpci_dev *); int zpci_disable_device(struct zpci_dev *); int zpci_scan_configured_device(struct zpci_dev *zdev, u32 fh); int zpci_deconfigure_device(struct zpci_dev *zdev); void zpci_device_reserved(struct zpci_dev *zdev); bool zpci_is_device_configured(struct zpci_dev *zdev); +int zpci_scan_devices(void); int zpci_hot_reset_device(struct zpci_dev *zdev); int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64, u8 *); @@ -225,7 +232,7 @@ void zpci_update_fh(struct zpci_dev *zdev, u32 fh); /* CLP */ int clp_setup_writeback_mio(void); -int clp_scan_pci_devices(void); +int clp_scan_pci_devices(struct list_head *scan_list); int clp_query_pci_fn(struct zpci_dev *zdev); int clp_enable_fh(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as); int clp_disable_fh(struct zpci_dev *zdev, u32 *fh); diff --git a/arch/s390/include/asm/pci_clp.h b/arch/s390/include/asm/pci_clp.h index f0c677ddd27060..3fff2f7095c8c9 100644 --- a/arch/s390/include/asm/pci_clp.h +++ b/arch/s390/include/asm/pci_clp.h @@ -110,7 +110,8 @@ struct clp_req_query_pci { struct clp_rsp_query_pci { struct clp_rsp_hdr hdr; u16 vfn; /* virtual fn number */ - u16 : 3; + u16 : 2; + u16 tid_avail : 1; u16 rid_avail : 1; u16 is_physfn : 1; u16 reserved1 : 1; @@ -122,16 +123,18 @@ struct clp_rsp_query_pci { u16 pchid; __le32 bar[PCI_STD_NUM_BARS]; u8 pfip[CLP_PFIP_NR_SEGMENTS]; /* pci function internal path */ - u16 : 12; - u16 port : 4; + u8 fidparm; + u8 reserved3 : 4; + u8 port : 4; u8 fmb_len; u8 pft; /* pci function type */ u64 sdma; /* start dma as */ u64 edma; /* end dma as */ #define ZPCI_RID_MASK_DEVFN 0x00ff u16 rid; /* BUS/DEVFN PCI address */ - u16 reserved0; - u32 reserved[10]; + u32 reserved0; + u16 tid; + u32 reserved[9]; u32 uid; /* user defined id */ u8 util_str[CLP_UTIL_STR_LEN]; /* utility string */ u32 reserved2[16]; diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h index 2686bee800e3d5..43a5ea4ee20f44 100644 --- a/arch/s390/include/asm/pci_io.h +++ b/arch/s390/include/asm/pci_io.h @@ -143,7 +143,7 @@ static inline int zpci_get_max_io_size(u64 src, u64 dst, int len, int max) static inline int zpci_memcpy_fromio(void *dst, const volatile void __iomem *src, - unsigned long n) + size_t n) { int size, rc = 0; @@ -162,7 +162,7 @@ static inline int zpci_memcpy_fromio(void *dst, } static inline int zpci_memcpy_toio(volatile void __iomem *dst, - const void *src, unsigned long n) + const void *src, size_t n) { int size, rc = 0; @@ -187,7 +187,7 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst, } static inline int zpci_memset_io(volatile void __iomem *dst, - unsigned char val, size_t count) + int val, size_t count) { u8 *src = kmalloc(count, GFP_KERNEL); int rc; diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h index 29ee289108c562..e53894cedf0881 100644 --- a/arch/s390/include/asm/perf_event.h +++ b/arch/s390/include/asm/perf_event.h @@ -37,9 +37,9 @@ extern ssize_t cpumf_events_sysfs_show(struct device *dev, /* Perf callbacks */ struct pt_regs; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #define perf_arch_bpf_user_pt_regs(regs) ®s->user_regs /* Perf pt_regs extension for sample-data-entry indicators */ diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 0ffbaf7419558b..48268095b0a353 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -277,7 +277,8 @@ static inline int is_module_addr(void *addr) #define _REGION1_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R1 | _REGION_ENTRY_INVALID) #define _REGION2_ENTRY (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_LENGTH) #define _REGION2_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R2 | _REGION_ENTRY_INVALID) -#define _REGION3_ENTRY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH) +#define _REGION3_ENTRY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH | \ + _REGION3_ENTRY_PRESENT) #define _REGION3_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INVALID) #define _REGION3_ENTRY_HARDWARE_BITS 0xfffffffffffff6ffUL @@ -285,18 +286,27 @@ static inline int is_module_addr(void *addr) #define _REGION3_ENTRY_ORIGIN_LARGE ~0x7fffffffUL /* large page address */ #define _REGION3_ENTRY_DIRTY 0x2000 /* SW region dirty bit */ #define _REGION3_ENTRY_YOUNG 0x1000 /* SW region young bit */ +#define _REGION3_ENTRY_COMM 0x0010 /* Common-Region, marks swap entry */ #define _REGION3_ENTRY_LARGE 0x0400 /* RTTE-format control, large page */ -#define _REGION3_ENTRY_WRITE 0x0002 /* SW region write bit */ -#define _REGION3_ENTRY_READ 0x0001 /* SW region read bit */ +#define _REGION3_ENTRY_WRITE 0x8000 /* SW region write bit */ +#define _REGION3_ENTRY_READ 0x4000 /* SW region read bit */ #ifdef CONFIG_MEM_SOFT_DIRTY -#define _REGION3_ENTRY_SOFT_DIRTY 0x4000 /* SW region soft dirty bit */ +#define _REGION3_ENTRY_SOFT_DIRTY 0x0002 /* SW region soft dirty bit */ #else #define _REGION3_ENTRY_SOFT_DIRTY 0x0000 /* SW region soft dirty bit */ #endif #define _REGION_ENTRY_BITS 0xfffffffffffff22fUL +/* + * SW region present bit. For non-leaf region-third-table entries, bits 62-63 + * indicate the TABLE LENGTH and both must be set to 1. But such entries + * would always be considered as present, so it is safe to use bit 63 as + * PRESENT bit for PUD. + */ +#define _REGION3_ENTRY_PRESENT 0x0001 + /* Bits in the segment table entry */ #define _SEGMENT_ENTRY_BITS 0xfffffffffffffe3fUL #define _SEGMENT_ENTRY_HARDWARE_BITS 0xfffffffffffffe3cUL @@ -308,21 +318,29 @@ static inline int is_module_addr(void *addr) #define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */ #define _SEGMENT_ENTRY_TYPE_MASK 0x0c /* segment table type mask */ -#define _SEGMENT_ENTRY (0) +#define _SEGMENT_ENTRY (_SEGMENT_ENTRY_PRESENT) #define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INVALID) #define _SEGMENT_ENTRY_DIRTY 0x2000 /* SW segment dirty bit */ #define _SEGMENT_ENTRY_YOUNG 0x1000 /* SW segment young bit */ + +#define _SEGMENT_ENTRY_COMM 0x0010 /* Common-Segment, marks swap entry */ #define _SEGMENT_ENTRY_LARGE 0x0400 /* STE-format control, large page */ -#define _SEGMENT_ENTRY_WRITE 0x0002 /* SW segment write bit */ -#define _SEGMENT_ENTRY_READ 0x0001 /* SW segment read bit */ +#define _SEGMENT_ENTRY_WRITE 0x8000 /* SW segment write bit */ +#define _SEGMENT_ENTRY_READ 0x4000 /* SW segment read bit */ #ifdef CONFIG_MEM_SOFT_DIRTY -#define _SEGMENT_ENTRY_SOFT_DIRTY 0x4000 /* SW segment soft dirty bit */ +#define _SEGMENT_ENTRY_SOFT_DIRTY 0x0002 /* SW segment soft dirty bit */ #else #define _SEGMENT_ENTRY_SOFT_DIRTY 0x0000 /* SW segment soft dirty bit */ #endif +#define _SEGMENT_ENTRY_PRESENT 0x0001 /* SW segment present bit */ + +/* Common bits in region and segment table entries, for swap entries */ +#define _RST_ENTRY_COMM 0x0010 /* Common-Region/Segment, marks swap entry */ +#define _RST_ENTRY_INVALID 0x0020 /* invalid region/segment table entry */ + #define _CRST_ENTRIES 2048 /* number of region/segment table entries */ #define _PAGE_ENTRIES 256 /* number of page table entries */ @@ -338,7 +356,7 @@ static inline int is_module_addr(void *addr) #define _REGION2_INDEX (0x7ffUL << _REGION2_SHIFT) #define _REGION3_INDEX (0x7ffUL << _REGION3_SHIFT) #define _SEGMENT_INDEX (0x7ffUL << _SEGMENT_SHIFT) -#define _PAGE_INDEX (0xffUL << _PAGE_SHIFT) +#define _PAGE_INDEX (0xffUL << PAGE_SHIFT) #define _REGION1_SIZE (1UL << _REGION1_SHIFT) #define _REGION2_SIZE (1UL << _REGION2_SHIFT) @@ -454,17 +472,22 @@ static inline int is_module_addr(void *addr) /* * Segment entry (large page) protection definitions. */ -#define SEGMENT_NONE __pgprot(_SEGMENT_ENTRY_INVALID | \ +#define SEGMENT_NONE __pgprot(_SEGMENT_ENTRY_PRESENT | \ + _SEGMENT_ENTRY_INVALID | \ _SEGMENT_ENTRY_PROTECT) -#define SEGMENT_RO __pgprot(_SEGMENT_ENTRY_PROTECT | \ +#define SEGMENT_RO __pgprot(_SEGMENT_ENTRY_PRESENT | \ + _SEGMENT_ENTRY_PROTECT | \ _SEGMENT_ENTRY_READ | \ _SEGMENT_ENTRY_NOEXEC) -#define SEGMENT_RX __pgprot(_SEGMENT_ENTRY_PROTECT | \ +#define SEGMENT_RX __pgprot(_SEGMENT_ENTRY_PRESENT | \ + _SEGMENT_ENTRY_PROTECT | \ _SEGMENT_ENTRY_READ) -#define SEGMENT_RW __pgprot(_SEGMENT_ENTRY_READ | \ +#define SEGMENT_RW __pgprot(_SEGMENT_ENTRY_PRESENT | \ + _SEGMENT_ENTRY_READ | \ _SEGMENT_ENTRY_WRITE | \ _SEGMENT_ENTRY_NOEXEC) -#define SEGMENT_RWX __pgprot(_SEGMENT_ENTRY_READ | \ +#define SEGMENT_RWX __pgprot(_SEGMENT_ENTRY_PRESENT | \ + _SEGMENT_ENTRY_READ | \ _SEGMENT_ENTRY_WRITE) #define SEGMENT_KERNEL __pgprot(_SEGMENT_ENTRY | \ _SEGMENT_ENTRY_LARGE | \ @@ -491,6 +514,7 @@ static inline int is_module_addr(void *addr) */ #define REGION3_KERNEL __pgprot(_REGION_ENTRY_TYPE_R3 | \ + _REGION3_ENTRY_PRESENT | \ _REGION3_ENTRY_LARGE | \ _REGION3_ENTRY_READ | \ _REGION3_ENTRY_WRITE | \ @@ -498,12 +522,14 @@ static inline int is_module_addr(void *addr) _REGION3_ENTRY_DIRTY | \ _REGION_ENTRY_NOEXEC) #define REGION3_KERNEL_RO __pgprot(_REGION_ENTRY_TYPE_R3 | \ + _REGION3_ENTRY_PRESENT | \ _REGION3_ENTRY_LARGE | \ _REGION3_ENTRY_READ | \ _REGION3_ENTRY_YOUNG | \ _REGION_ENTRY_PROTECT | \ _REGION_ENTRY_NOEXEC) #define REGION3_KERNEL_EXEC __pgprot(_REGION_ENTRY_TYPE_R3 | \ + _REGION3_ENTRY_PRESENT | \ _REGION3_ENTRY_LARGE | \ _REGION3_ENTRY_READ | \ _REGION3_ENTRY_WRITE | \ @@ -746,7 +772,7 @@ static inline int pud_present(pud_t pud) { if (pud_folded(pud)) return 1; - return (pud_val(pud) & _REGION_ENTRY_ORIGIN) != 0UL; + return (pud_val(pud) & _REGION3_ENTRY_PRESENT) != 0; } static inline int pud_none(pud_t pud) @@ -761,13 +787,18 @@ static inline bool pud_leaf(pud_t pud) { if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) != _REGION_ENTRY_TYPE_R3) return 0; - return !!(pud_val(pud) & _REGION3_ENTRY_LARGE); + return (pud_present(pud) && (pud_val(pud) & _REGION3_ENTRY_LARGE) != 0); +} + +static inline int pmd_present(pmd_t pmd) +{ + return (pmd_val(pmd) & _SEGMENT_ENTRY_PRESENT) != 0; } #define pmd_leaf pmd_leaf static inline bool pmd_leaf(pmd_t pmd) { - return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0; + return (pmd_present(pmd) && (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0); } static inline int pmd_bad(pmd_t pmd) @@ -799,11 +830,6 @@ static inline int p4d_bad(p4d_t p4d) return (p4d_val(p4d) & ~_REGION_ENTRY_BITS) != 0; } -static inline int pmd_present(pmd_t pmd) -{ - return pmd_val(pmd) != _SEGMENT_ENTRY_EMPTY; -} - static inline int pmd_none(pmd_t pmd) { return pmd_val(pmd) == _SEGMENT_ENTRY_EMPTY; @@ -1851,7 +1877,7 @@ static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, static inline int pmd_trans_huge(pmd_t pmd) { - return pmd_val(pmd) & _SEGMENT_ENTRY_LARGE; + return pmd_leaf(pmd); } #define has_transparent_hugepage has_transparent_hugepage @@ -1911,6 +1937,53 @@ static inline swp_entry_t __swp_entry(unsigned long type, unsigned long offset) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) +/* + * 64 bit swap entry format for REGION3 and SEGMENT table entries (RSTE) + * Bits 59 and 63 are used to indicate the swap entry. Bit 58 marks the rste + * as invalid. + * A swap entry is indicated by bit pattern (rste & 0x011) == 0x010 + * | offset |Xtype |11TT|S0| + * |0000000000111111111122222222223333333333444444444455|555555|5566|66| + * |0123456789012345678901234567890123456789012345678901|234567|8901|23| + * + * Bits 0-51 store the offset. + * Bits 53-57 store the type. + * Bit 62 (S) is used for softdirty tracking. + * Bits 60-61 (TT) indicate the table type: 0x01 for REGION3 and 0x00 for SEGMENT. + * Bit 52 (X) is unused. + */ + +#define __SWP_OFFSET_MASK_RSTE ((1UL << 52) - 1) +#define __SWP_OFFSET_SHIFT_RSTE 12 +#define __SWP_TYPE_MASK_RSTE ((1UL << 5) - 1) +#define __SWP_TYPE_SHIFT_RSTE 6 + +/* + * TT bits set to 0x00 == SEGMENT. For REGION3 entries, caller must add R3 + * bits 0x01. See also __set_huge_pte_at(). + */ +static inline unsigned long mk_swap_rste(unsigned long type, unsigned long offset) +{ + unsigned long rste; + + rste = _RST_ENTRY_INVALID | _RST_ENTRY_COMM; + rste |= (offset & __SWP_OFFSET_MASK_RSTE) << __SWP_OFFSET_SHIFT_RSTE; + rste |= (type & __SWP_TYPE_MASK_RSTE) << __SWP_TYPE_SHIFT_RSTE; + return rste; +} + +static inline unsigned long __swp_type_rste(swp_entry_t entry) +{ + return (entry.val >> __SWP_TYPE_SHIFT_RSTE) & __SWP_TYPE_MASK_RSTE; +} + +static inline unsigned long __swp_offset_rste(swp_entry_t entry) +{ + return (entry.val >> __SWP_OFFSET_SHIFT_RSTE) & __SWP_OFFSET_MASK_RSTE; +} + +#define __rste_to_swp_entry(rste) ((swp_entry_t) { rste }) + extern int vmem_add_mapping(unsigned long start, unsigned long size); extern void vmem_remove_mapping(unsigned long start, unsigned long size); extern int __vmem_map_4k_page(unsigned long addr, unsigned long phys, pgprot_t prot, bool alloc); diff --git a/arch/s390/include/asm/physmem_info.h b/arch/s390/include/asm/physmem_info.h index f45cfc8bc233ff..51b68a43e19577 100644 --- a/arch/s390/include/asm/physmem_info.h +++ b/arch/s390/include/asm/physmem_info.h @@ -9,6 +9,7 @@ enum physmem_info_source { MEM_DETECT_NONE = 0, MEM_DETECT_SCLP_STOR_INFO, MEM_DETECT_DIAG260, + MEM_DETECT_DIAG500_STOR_LIMIT, MEM_DETECT_SCLP_READ_INFO, MEM_DETECT_BIN_SEARCH }; @@ -107,6 +108,8 @@ static inline const char *get_physmem_info_source(void) return "sclp storage info"; case MEM_DETECT_DIAG260: return "diag260"; + case MEM_DETECT_DIAG500_STOR_LIMIT: + return "diag500 storage limit"; case MEM_DETECT_SCLP_READ_INFO: return "sclp read info"; case MEM_DETECT_BIN_SEARCH: diff --git a/arch/s390/include/asm/preempt.h b/arch/s390/include/asm/preempt.h index deca3f221836ed..2c29bdf1212722 100644 --- a/arch/s390/include/asm/preempt.h +++ b/arch/s390/include/asm/preempt.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #ifdef MARCH_HAS_Z196_FEATURES @@ -22,12 +23,10 @@ static __always_inline void preempt_count_set(int pc) { int old, new; + old = READ_ONCE(get_lowcore()->preempt_count); do { - old = READ_ONCE(get_lowcore()->preempt_count); - new = (old & PREEMPT_NEED_RESCHED) | - (pc & ~PREEMPT_NEED_RESCHED); - } while (__atomic_cmpxchg(&get_lowcore()->preempt_count, - old, new) != old); + new = (old & PREEMPT_NEED_RESCHED) | (pc & ~PREEMPT_NEED_RESCHED); + } while (!arch_try_cmpxchg(&get_lowcore()->preempt_count, &old, new)); } static __always_inline void set_preempt_need_resched(void) @@ -131,10 +130,24 @@ static __always_inline bool should_resched(int preempt_offset) #define init_idle_preempt_count(p, cpu) do { } while (0) #ifdef CONFIG_PREEMPTION -extern void preempt_schedule(void); -#define __preempt_schedule() preempt_schedule() -extern void preempt_schedule_notrace(void); -#define __preempt_schedule_notrace() preempt_schedule_notrace() + +void preempt_schedule(void); +void preempt_schedule_notrace(void); + +#ifdef CONFIG_PREEMPT_DYNAMIC + +void dynamic_preempt_schedule(void); +void dynamic_preempt_schedule_notrace(void); +#define __preempt_schedule() dynamic_preempt_schedule() +#define __preempt_schedule_notrace() dynamic_preempt_schedule_notrace() + +#else /* CONFIG_PREEMPT_DYNAMIC */ + +#define __preempt_schedule() preempt_schedule() +#define __preempt_schedule_notrace() preempt_schedule_notrace() + +#endif /* CONFIG_PREEMPT_DYNAMIC */ + #endif /* CONFIG_PREEMPTION */ #endif /* __ASM_PREEMPT_H */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 9a5236acc0a860..8761fd01a9f09f 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -39,6 +39,7 @@ #include #include #include +#include struct pcpu { unsigned long ec_mask; /* bit mask for ec_xxx functions */ @@ -187,10 +188,8 @@ struct thread_struct { unsigned long hardirq_timer; /* task cputime in hardirq context */ unsigned long softirq_timer; /* task cputime in softirq context */ const sys_call_ptr_t *sys_call_table; /* system call table address */ - unsigned long gmap_addr; /* address of last gmap fault. */ - unsigned int gmap_write_flag; /* gmap fault write indication */ + union teid gmap_teid; /* address and flags of last gmap fault */ unsigned int gmap_int_code; /* int code of last gmap fault */ - unsigned int gmap_pfault; /* signal of a pending guest pfault */ int ufpu_flags; /* user fpu flags */ int kfpu_flags; /* kernel fpu flags */ diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 2ad9324f633876..788bc4467445c9 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -14,11 +14,13 @@ #define PIF_SYSCALL 0 /* inside a system call */ #define PIF_EXECVE_PGSTE_RESTART 1 /* restart execve for PGSTE binaries */ #define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */ +#define PIF_GUEST_FAULT 3 /* indicates program check in sie64a */ #define PIF_FTRACE_FULL_REGS 4 /* all register contents valid (ftrace) */ #define _PIF_SYSCALL BIT(PIF_SYSCALL) #define _PIF_EXECVE_PGSTE_RESTART BIT(PIF_EXECVE_PGSTE_RESTART) #define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET) +#define _PIF_GUEST_FAULT BIT(PIF_GUEST_FAULT) #define _PIF_FTRACE_FULL_REGS BIT(PIF_FTRACE_FULL_REGS) #define PSW32_MASK_PER _AC(0x40000000, UL) diff --git a/arch/s390/include/asm/set_memory.h b/arch/s390/include/asm/set_memory.h index 06fbabe2f66c98..94092f4ae76499 100644 --- a/arch/s390/include/asm/set_memory.h +++ b/arch/s390/include/asm/set_memory.h @@ -62,5 +62,7 @@ __SET_MEMORY_FUNC(set_memory_4k, SET_MEMORY_4K) int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page); +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid); +bool kernel_page_present(struct page *page); #endif diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h index edee63da08e727..472943b770662d 100644 --- a/arch/s390/include/asm/sigp.h +++ b/arch/s390/include/asm/sigp.h @@ -38,6 +38,8 @@ #ifndef __ASSEMBLY__ +#include + static inline int ____pcpu_sigp(u16 addr, u8 order, unsigned long parm, u32 *status) { @@ -46,13 +48,12 @@ static inline int ____pcpu_sigp(u16 addr, u8 order, unsigned long parm, asm volatile( " sigp %[r1],%[addr],0(%[order])\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (cc), [r1] "+&d" (r1.pair) + CC_IPM(cc) + : CC_OUT(cc, cc), [r1] "+d" (r1.pair) : [addr] "d" (addr), [order] "a" (order) - : "cc"); + : CC_CLOBBER); *status = r1.even; - return cc; + return CC_TRANSFORM(cc); } static inline int __pcpu_sigp(u16 addr, u8 order, unsigned long parm, diff --git a/arch/s390/include/asm/sparsemem.h b/arch/s390/include/asm/sparsemem.h index c549893602eabe..668dfc5de53874 100644 --- a/arch/s390/include/asm/sparsemem.h +++ b/arch/s390/include/asm/sparsemem.h @@ -2,7 +2,23 @@ #ifndef _ASM_S390_SPARSEMEM_H #define _ASM_S390_SPARSEMEM_H -#define SECTION_SIZE_BITS 28 +#define SECTION_SIZE_BITS 27 #define MAX_PHYSMEM_BITS CONFIG_MAX_PHYSMEM_BITS +#ifdef CONFIG_NUMA + +static inline int memory_add_physaddr_to_nid(u64 addr) +{ + return 0; +} +#define memory_add_physaddr_to_nid memory_add_physaddr_to_nid + +static inline int phys_to_target_node(u64 start) +{ + return 0; +} +#define phys_to_target_node phys_to_target_node + +#endif /* CONFIG_NUMA */ + #endif /* _ASM_S390_SPARSEMEM_H */ diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index 77d5e804af93e5..f87dd0a84855da 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -57,8 +57,10 @@ static inline int arch_spin_is_locked(arch_spinlock_t *lp) static inline int arch_spin_trylock_once(arch_spinlock_t *lp) { + int old = 0; + barrier(); - return likely(__atomic_cmpxchg_bool(&lp->lock, 0, SPINLOCK_LOCKVAL)); + return likely(arch_try_cmpxchg(&lp->lock, &old, SPINLOCK_LOCKVAL)); } static inline void arch_spin_lock(arch_spinlock_t *lp) @@ -80,9 +82,10 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp) kcsan_release(); asm_inline volatile( ALTERNATIVE("nop", ".insn rre,0xb2fa0000,7,0", ALT_FACILITY(49)) /* NIAI 7 */ - " sth %1,%0\n" - : "=R" (((unsigned short *) &lp->lock)[1]) - : "d" (0) : "cc", "memory"); + " mvhhi %[lock],0\n" + : [lock] "=Q" (((unsigned short *)&lp->lock)[1]) + : + : "memory"); } /* @@ -118,7 +121,9 @@ static inline void arch_read_unlock(arch_rwlock_t *rw) static inline void arch_write_lock(arch_rwlock_t *rw) { - if (!__atomic_cmpxchg_bool(&rw->cnts, 0, 0x30000)) + int old = 0; + + if (!arch_try_cmpxchg(&rw->cnts, &old, 0x30000)) arch_write_lock_wait(rw); } @@ -133,8 +138,7 @@ static inline int arch_read_trylock(arch_rwlock_t *rw) int old; old = READ_ONCE(rw->cnts); - return (!(old & 0xffff0000) && - __atomic_cmpxchg_bool(&rw->cnts, old, old + 1)); + return (!(old & 0xffff0000) && arch_try_cmpxchg(&rw->cnts, &old, old + 1)); } static inline int arch_write_trylock(arch_rwlock_t *rw) @@ -142,7 +146,7 @@ static inline int arch_write_trylock(arch_rwlock_t *rw) int old; old = READ_ONCE(rw->cnts); - return !old && __atomic_cmpxchg_bool(&rw->cnts, 0, 0x30000); + return !old && arch_try_cmpxchg(&rw->cnts, &old, 0x30000); } #endif /* __ASM_SPINLOCK_H */ diff --git a/arch/s390/include/asm/spinlock_types.h b/arch/s390/include/asm/spinlock_types.h index b69695e399574e..3653ff57d6d9a7 100644 --- a/arch/s390/include/asm/spinlock_types.h +++ b/arch/s390/include/asm/spinlock_types.h @@ -3,7 +3,7 @@ #define __ASM_SPINLOCK_TYPES_H #ifndef __LINUX_SPINLOCK_TYPES_RAW_H -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif typedef struct { diff --git a/arch/s390/include/asm/stp.h b/arch/s390/include/asm/stp.h index 4d74d7e33340b1..827cb208de86ea 100644 --- a/arch/s390/include/asm/stp.h +++ b/arch/s390/include/asm/stp.h @@ -94,5 +94,6 @@ struct stp_stzi { int stp_sync_check(void); int stp_island_check(void); void stp_queue_work(void); +bool stp_enabled(void); #endif /* __S390_STP_H */ diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index 00ac01874a129f..c33f7144d1b978 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -61,44 +61,45 @@ void arch_setup_new_exec(void); /* * thread information flags bit numbers */ -/* _TIF_WORK bits */ #define TIF_NOTIFY_RESUME 0 /* callback before returning to user */ #define TIF_SIGPENDING 1 /* signal pending */ #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ -#define TIF_UPROBE 3 /* breakpointed or single-stepping */ -#define TIF_GUARDED_STORAGE 4 /* load guarded storage control block */ +#define TIF_NEED_RESCHED_LAZY 3 /* lazy rescheduling needed */ +#define TIF_UPROBE 4 /* breakpointed or single-stepping */ #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_GUARDED_STORAGE 8 /* load guarded storage control block */ #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 */ - #define TIF_31BIT 16 /* 32bit process */ #define TIF_MEMDIE 17 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */ #define TIF_SINGLE_STEP 19 /* This task is single stepped */ #define TIF_BLOCK_STEP 20 /* This task is block stepped */ #define TIF_UPROBE_SINGLESTEP 21 /* This task is uprobe single stepped */ - -/* _TIF_TRACE bits */ #define TIF_SYSCALL_TRACE 24 /* syscall trace active */ #define TIF_SYSCALL_AUDIT 25 /* syscall auditing active */ #define TIF_SECCOMP 26 /* secure computing */ #define TIF_SYSCALL_TRACEPOINT 27 /* syscall tracepoint instrumentation */ #define _TIF_NOTIFY_RESUME BIT(TIF_NOTIFY_RESUME) -#define _TIF_NOTIFY_SIGNAL BIT(TIF_NOTIFY_SIGNAL) #define _TIF_SIGPENDING BIT(TIF_SIGPENDING) #define _TIF_NEED_RESCHED BIT(TIF_NEED_RESCHED) +#define _TIF_NEED_RESCHED_LAZY BIT(TIF_NEED_RESCHED_LAZY) #define _TIF_UPROBE BIT(TIF_UPROBE) -#define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE) #define _TIF_PATCH_PENDING BIT(TIF_PATCH_PENDING) +#define _TIF_PGSTE BIT(TIF_PGSTE) +#define _TIF_NOTIFY_SIGNAL BIT(TIF_NOTIFY_SIGNAL) +#define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE) #define _TIF_ISOLATE_BP_GUEST BIT(TIF_ISOLATE_BP_GUEST) #define _TIF_PER_TRAP BIT(TIF_PER_TRAP) - #define _TIF_31BIT BIT(TIF_31BIT) +#define _TIF_MEMDIE BIT(TIF_MEMDIE) +#define _TIF_RESTORE_SIGMASK BIT(TIF_RESTORE_SIGMASK) #define _TIF_SINGLE_STEP BIT(TIF_SINGLE_STEP) - +#define _TIF_BLOCK_STEP BIT(TIF_BLOCK_STEP) +#define _TIF_UPROBE_SINGLESTEP BIT(TIF_UPROBE_SINGLESTEP) #define _TIF_SYSCALL_TRACE BIT(TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT BIT(TIF_SYSCALL_AUDIT) #define _TIF_SECCOMP BIT(TIF_SECCOMP) diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index 640901f2fbc3cc..a9460bd6555b8b 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -13,6 +13,7 @@ #include #include #include +#include /* The value of the TOD clock for 1.1.1970. */ #define TOD_UNIX_EPOCH 0x7d91048bca000000ULL @@ -44,11 +45,12 @@ static inline int set_tod_clock(__u64 time) int cc; asm volatile( - " sck %1\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) : "Q" (time) : "cc"); - return cc; + " sck %[time]\n" + CC_IPM(cc) + : CC_OUT(cc, cc) + : [time] "Q" (time) + : CC_CLOBBER); + return CC_TRANSFORM(cc); } static inline int store_tod_clock_ext_cc(union tod_clock *clk) @@ -56,11 +58,12 @@ static inline int store_tod_clock_ext_cc(union tod_clock *clk) int cc; asm volatile( - " stcke %1\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc), "=Q" (*clk) : : "cc"); - return cc; + " stcke %[clk]\n" + CC_IPM(cc) + : CC_OUT(cc, cc), [clk] "=Q" (*clk) + : + : CC_CLOBBER); + return CC_TRANSFORM(cc); } static __always_inline void store_tod_clock_ext(union tod_clock *tod) @@ -93,6 +96,7 @@ extern unsigned char ptff_function_mask[16]; #define PTFF_QAF 0x00 /* query available functions */ #define PTFF_QTO 0x01 /* query tod offset */ #define PTFF_QSI 0x02 /* query steering information */ +#define PTFF_QPT 0x03 /* query physical clock */ #define PTFF_QUI 0x04 /* query UTC information */ #define PTFF_ATO 0x40 /* adjust tod offset */ #define PTFF_STO 0x41 /* set tod offset */ @@ -149,12 +153,11 @@ struct ptff_qui { " lgr 0,%[reg0]\n" \ " lgr 1,%[reg1]\n" \ " ptff\n" \ - " ipm %[rc]\n" \ - " srl %[rc],28\n" \ - : [rc] "=&d" (rc), "+m" (*(struct addrtype *)reg1) \ + CC_IPM(rc) \ + : CC_OUT(rc, rc), "+m" (*(struct addrtype *)reg1) \ : [reg0] "d" (reg0), [reg1] "d" (reg1) \ - : "cc", "0", "1"); \ - rc; \ + : CC_CLOBBER_LIST("0", "1")); \ + CC_TRANSFORM(rc); \ }) static inline unsigned long local_tick_disable(void) @@ -250,6 +253,11 @@ static __always_inline unsigned long tod_to_ns(unsigned long todval) return ((todval >> 9) * 125) + (((todval & 0x1ff) * 125) >> 9); } +static __always_inline u128 eitod_to_ns(u128 todval) +{ + return (todval * 125) >> 9; +} + /** * tod_after - compare two 64 bit TOD values * @a: first 64 bit TOD timestamp diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index a6e2cd89b60946..9dfd46dd03c64c 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h @@ -46,11 +46,6 @@ static inline void __tlb_flush_mm(struct mm_struct *mm) { unsigned long gmap_asce; - /* - * If the machine has IDTE we prefer to do a per mm flush - * on all cpus instead of doing a local flush if the mm - * only ran on the local cpu. - */ preempt_disable(); atomic_inc(&mm->context.flush_count); /* Reset TLB flush mask */ diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 153d93468b77c0..dc332609f2c3f9 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -2,7 +2,7 @@ /* * Ultravisor Interfaces * - * Copyright IBM Corp. 2019, 2022 + * Copyright IBM Corp. 2019, 2024 * * Author(s): * Vasily Gorbik @@ -17,6 +17,7 @@ #include #include #include +#include #define UVC_CC_OK 0 #define UVC_CC_ERROR 1 @@ -28,9 +29,11 @@ #define UVC_RC_INV_STATE 0x0003 #define UVC_RC_INV_LEN 0x0005 #define UVC_RC_NO_RESUME 0x0007 +#define UVC_RC_MORE_DATA 0x0100 #define UVC_RC_NEED_DESTROY 0x8000 #define UVC_CMD_QUI 0x0001 +#define UVC_CMD_QUERY_KEYS 0x0002 #define UVC_CMD_INIT_UV 0x000f #define UVC_CMD_CREATE_SEC_CONF 0x0100 #define UVC_CMD_DESTROY_SEC_CONF 0x0101 @@ -61,6 +64,7 @@ #define UVC_CMD_ADD_SECRET 0x1031 #define UVC_CMD_LIST_SECRETS 0x1033 #define UVC_CMD_LOCK_SECRETS 0x1034 +#define UVC_CMD_RETR_SECRET 0x1035 /* Bits in installed uv calls */ enum uv_cmds_inst { @@ -94,6 +98,8 @@ enum uv_cmds_inst { BIT_UVC_CMD_ADD_SECRET = 29, BIT_UVC_CMD_LIST_SECRETS = 30, BIT_UVC_CMD_LOCK_SECRETS = 31, + BIT_UVC_CMD_RETR_SECRET = 33, + BIT_UVC_CMD_QUERY_KEYS = 34, }; enum uv_feat_ind { @@ -140,11 +146,27 @@ struct uv_cb_qui { u64 reservedf0; /* 0x00f0 */ u64 supp_add_secret_req_ver; /* 0x00f8 */ u64 supp_add_secret_pcf; /* 0x0100 */ - u64 supp_secret_types; /* 0x0180 */ - u16 max_secrets; /* 0x0110 */ - u8 reserved112[0x120 - 0x112]; /* 0x0112 */ + u64 supp_secret_types; /* 0x0108 */ + u16 max_assoc_secrets; /* 0x0110 */ + u16 max_retr_secrets; /* 0x0112 */ + u8 reserved114[0x120 - 0x114]; /* 0x0114 */ } __packed __aligned(8); +struct uv_key_hash { + u64 dword[4]; +} __packed __aligned(8); + +#define UVC_QUERY_KEYS_IDX_HK 0 +#define UVC_QUERY_KEYS_IDX_BACK_HK 1 + +/* Query Ultravisor Keys */ +struct uv_cb_query_keys { + struct uv_cb_header header; /* 0x0000 */ + u64 reserved08[3]; /* 0x0008 */ + struct uv_key_hash key_hashes[15]; /* 0x0020 */ +} __packed __aligned(8); +static_assert(sizeof(struct uv_cb_query_keys) == 0x200); + /* Initialize Ultravisor */ struct uv_cb_init { struct uv_cb_header header; @@ -317,7 +339,6 @@ struct uv_cb_dump_complete { * A common UV call struct for pv guests that contains a single address * Examples: * Add Secret - * List Secrets */ struct uv_cb_guest_addr { struct uv_cb_header header; @@ -326,18 +347,102 @@ struct uv_cb_guest_addr { u64 reserved28[4]; } __packed __aligned(8); +#define UVC_RC_RETR_SECR_BUF_SMALL 0x0109 +#define UVC_RC_RETR_SECR_STORE_EMPTY 0x010f +#define UVC_RC_RETR_SECR_INV_IDX 0x0110 +#define UVC_RC_RETR_SECR_INV_SECRET 0x0111 + +struct uv_cb_retr_secr { + struct uv_cb_header header; + u64 reserved08[2]; + u16 secret_idx; + u16 reserved1a; + u32 buf_size; + u64 buf_addr; + u64 reserved28[4]; +} __packed __aligned(8); + +struct uv_cb_list_secrets { + struct uv_cb_header header; + u64 reserved08[2]; + u8 reserved18[6]; + u16 start_idx; + u64 list_addr; + u64 reserved28[4]; +} __packed __aligned(8); + +enum uv_secret_types { + UV_SECRET_INVAL = 0x0, + UV_SECRET_NULL = 0x1, + UV_SECRET_ASSOCIATION = 0x2, + UV_SECRET_PLAIN = 0x3, + UV_SECRET_AES_128 = 0x4, + UV_SECRET_AES_192 = 0x5, + UV_SECRET_AES_256 = 0x6, + UV_SECRET_AES_XTS_128 = 0x7, + UV_SECRET_AES_XTS_256 = 0x8, + UV_SECRET_HMAC_SHA_256 = 0x9, + UV_SECRET_HMAC_SHA_512 = 0xa, + /* 0x0b - 0x10 reserved */ + UV_SECRET_ECDSA_P256 = 0x11, + UV_SECRET_ECDSA_P384 = 0x12, + UV_SECRET_ECDSA_P521 = 0x13, + UV_SECRET_ECDSA_ED25519 = 0x14, + UV_SECRET_ECDSA_ED448 = 0x15, +}; + +/** + * uv_secret_list_item_hdr - UV secret metadata. + * @index: Index of the secret in the secret list. + * @type: Type of the secret. See `enum uv_secret_types`. + * @length: Length of the stored secret. + */ +struct uv_secret_list_item_hdr { + u16 index; + u16 type; + u32 length; +} __packed __aligned(8); + +#define UV_SECRET_ID_LEN 32 +/** + * uv_secret_list_item - UV secret entry. + * @hdr: The metadata of this secret. + * @id: The ID of this secret, not the secret itself. + */ +struct uv_secret_list_item { + struct uv_secret_list_item_hdr hdr; + u64 reserverd08; + u8 id[UV_SECRET_ID_LEN]; +} __packed __aligned(8); + +/** + * uv_secret_list - UV secret-metadata list. + * @num_secr_stored: Number of secrets stored in this list. + * @total_num_secrets: Number of secrets stored in the UV for this guest. + * @next_secret_idx: positive number if there are more secrets available or zero. + * @secrets: Up to 85 UV-secret metadata entries. + */ +struct uv_secret_list { + u16 num_secr_stored; + u16 total_num_secrets; + u16 next_secret_idx; + u16 reserved_06; + u64 reserved_08; + struct uv_secret_list_item secrets[85]; +} __packed __aligned(8); +static_assert(sizeof(struct uv_secret_list) == PAGE_SIZE); + static inline int __uv_call(unsigned long r1, unsigned long r2) { int cc; asm volatile( - " .insn rrf,0xB9A40000,%[r1],%[r2],0,0\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=d" (cc) + " .insn rrf,0xb9a40000,%[r1],%[r2],0,0\n" + CC_IPM(cc) + : CC_OUT(cc, cc) : [r1] "a" (r1), [r2] "a" (r2) - : "memory", "cc"); - return cc; + : CC_CLOBBER_LIST("memory")); + return CC_TRANSFORM(cc); } static inline int uv_call(unsigned long r1, unsigned long r2) @@ -382,6 +487,48 @@ static inline int uv_cmd_nodata(u64 handle, u16 cmd, u16 *rc, u16 *rrc) return cc ? -EINVAL : 0; } +/** + * uv_list_secrets() - Do a List Secrets UVC. + * + * @buf: Buffer to write list into; size of one page. + * @start_idx: The smallest index that should be included in the list. + * For the fist invocation use 0. + * @rc: Pointer to store the return code or NULL. + * @rrc: Pointer to store the return reason code or NULL. + * + * This function calls the List Secrets UVC. The result is written into `buf`, + * that needs to be at least one page of writable memory. + * `buf` consists of: + * * %struct uv_secret_list_hdr + * * %struct uv_secret_list_item (multiple) + * + * For `start_idx` use _0_ for the first call. If there are more secrets available + * but could not fit into the page then `rc` is `UVC_RC_MORE_DATA`. + * In this case use `uv_secret_list_hdr.next_secret_idx` for `start_idx`. + * + * Context: might sleep. + * + * Return: The UVC condition code. + */ +static inline int uv_list_secrets(struct uv_secret_list *buf, u16 start_idx, + u16 *rc, u16 *rrc) +{ + struct uv_cb_list_secrets uvcb = { + .header.len = sizeof(uvcb), + .header.cmd = UVC_CMD_LIST_SECRETS, + .start_idx = start_idx, + .list_addr = (u64)buf, + }; + int cc = uv_call_sched(0, (u64)&uvcb); + + if (rc) + *rc = uvcb.header.rc; + if (rrc) + *rrc = uvcb.header.rrc; + + return cc; +} + struct uv_info { unsigned long inst_calls_list[4]; unsigned long uv_base_stor_len; @@ -402,7 +549,8 @@ struct uv_info { unsigned long supp_add_secret_req_ver; unsigned long supp_add_secret_pcf; unsigned long supp_secret_types; - unsigned short max_secrets; + unsigned short max_assoc_secrets; + unsigned short max_retr_secrets; }; extern struct uv_info uv_info; @@ -468,6 +616,10 @@ static inline int uv_remove_shared(unsigned long addr) return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS); } +int uv_get_secret_metadata(const u8 secret_id[UV_SECRET_ID_LEN], + struct uv_secret_list_item_hdr *secret); +int uv_retrieve_secret(u16 secret_idx, u8 *buf, size_t buf_size); + extern int prot_virt_host; static inline int is_prot_virt_host(void) diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h index 91061f0279be45..92c73e4d97a93a 100644 --- a/arch/s390/include/asm/vdso.h +++ b/arch/s390/include/asm/vdso.h @@ -12,9 +12,6 @@ int vdso_getcpu_init(void); #endif /* __ASSEMBLY__ */ -/* Default link address for the vDSO */ -#define VDSO_LBASE 0 - #define __VVAR_PAGES 2 #define VDSO_VERSION_STRING LINUX_2.6.29 diff --git a/arch/s390/include/asm/vdso/data.h b/arch/s390/include/asm/vdso/data.h deleted file mode 100644 index 0e2b40ef69b049..00000000000000 --- a/arch/s390/include/asm/vdso/data.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __S390_ASM_VDSO_DATA_H -#define __S390_ASM_VDSO_DATA_H - -#include - -struct arch_vdso_data { - __s64 tod_steering_delta; - __u64 tod_steering_end; -}; - -#endif /* __S390_ASM_VDSO_DATA_H */ diff --git a/arch/s390/include/asm/vdso/time_data.h b/arch/s390/include/asm/vdso/time_data.h new file mode 100644 index 00000000000000..8a08752422e609 --- /dev/null +++ b/arch/s390/include/asm/vdso/time_data.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __S390_ASM_VDSO_TIME_DATA_H +#define __S390_ASM_VDSO_TIME_DATA_H + +#include + +struct arch_vdso_time_data { + __s64 tod_steering_delta; + __u64 tod_steering_end; +}; + +#endif /* __S390_ASM_VDSO_TIME_DATA_H */ diff --git a/arch/s390/include/asm/vdso/vsyscall.h b/arch/s390/include/asm/vdso/vsyscall.h index 3c5d5e47814e16..3eb576ecd3bd99 100644 --- a/arch/s390/include/asm/vdso/vsyscall.h +++ b/arch/s390/include/asm/vdso/vsyscall.h @@ -7,7 +7,6 @@ #ifndef __ASSEMBLY__ #include -#include #include #include @@ -17,10 +16,6 @@ enum vvar_pages { VVAR_NR_PAGES }; -/* - * Update the vDSO data page to keep in sync with kernel timekeeping. - */ - static __always_inline struct vdso_data *__s390_get_k_vdso_data(void) { return vdso_data; diff --git a/arch/s390/include/uapi/asm/dasd.h b/arch/s390/include/uapi/asm/dasd.h index b11d9880045845..7c364b33c84dce 100644 --- a/arch/s390/include/uapi/asm/dasd.h +++ b/arch/s390/include/uapi/asm/dasd.h @@ -294,7 +294,7 @@ struct dasd_snid_ioctl_data { /******************************************************************************** * SECTION: Definition of IOCTLs * - * Here ist how the ioctl-nr should be used: + * Here is how the ioctl-nr should be used: * 0 - 31 DASD driver itself * 32 - 239 still open * 240 - 255 reserved for EMC diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 05eaf6db3ad4cb..60345dd2cba2d6 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -469,7 +469,8 @@ struct kvm_s390_vm_cpu_subfunc { __u8 kdsa[16]; /* with MSA9 */ __u8 sortl[32]; /* with STFLE.150 */ __u8 dfltcc[32]; /* with STFLE.151 */ - __u8 reserved[1728]; + __u8 pfcr[16]; /* with STFLE.201 */ + __u8 reserved[1712]; }; #define KVM_S390_VM_CPU_PROCESSOR_UV_FEAT_GUEST 6 diff --git a/arch/s390/include/uapi/asm/pkey.h b/arch/s390/include/uapi/asm/pkey.h index 60431d00e6bd7b..ca42e941675d4c 100644 --- a/arch/s390/include/uapi/asm/pkey.h +++ b/arch/s390/include/uapi/asm/pkey.h @@ -48,21 +48,22 @@ /* the newer ioctls use a pkey_key_type enum for type information */ enum pkey_key_type { - PKEY_TYPE_CCA_DATA = (__u32) 1, - PKEY_TYPE_CCA_CIPHER = (__u32) 2, - PKEY_TYPE_EP11 = (__u32) 3, - PKEY_TYPE_CCA_ECC = (__u32) 0x1f, - PKEY_TYPE_EP11_AES = (__u32) 6, - PKEY_TYPE_EP11_ECC = (__u32) 7, - PKEY_TYPE_PROTKEY = (__u32) 8, + PKEY_TYPE_CCA_DATA = (__u32)1, + PKEY_TYPE_CCA_CIPHER = (__u32)2, + PKEY_TYPE_EP11 = (__u32)3, + PKEY_TYPE_CCA_ECC = (__u32)0x1f, + PKEY_TYPE_EP11_AES = (__u32)6, + PKEY_TYPE_EP11_ECC = (__u32)7, + PKEY_TYPE_PROTKEY = (__u32)8, + PKEY_TYPE_UVSECRET = (__u32)9, }; /* the newer ioctls use a pkey_key_size enum for key size information */ enum pkey_key_size { - PKEY_SIZE_AES_128 = (__u32) 128, - PKEY_SIZE_AES_192 = (__u32) 192, - PKEY_SIZE_AES_256 = (__u32) 256, - PKEY_SIZE_UNKNOWN = (__u32) 0xFFFFFFFF, + PKEY_SIZE_AES_128 = (__u32)128, + PKEY_SIZE_AES_192 = (__u32)192, + PKEY_SIZE_AES_256 = (__u32)256, + PKEY_SIZE_UNKNOWN = (__u32)0xFFFFFFFF, }; /* some of the newer ioctls use these flags */ @@ -125,6 +126,7 @@ struct pkey_genseck { __u32 keytype; /* in: key type to generate */ struct pkey_seckey seckey; /* out: the secure key blob */ }; + #define PKEY_GENSECK _IOWR(PKEY_IOCTL_MAGIC, 0x01, struct pkey_genseck) /* @@ -137,6 +139,7 @@ struct pkey_clr2seck { struct pkey_clrkey clrkey; /* in: the clear key value */ struct pkey_seckey seckey; /* out: the secure key blob */ }; + #define PKEY_CLR2SECK _IOWR(PKEY_IOCTL_MAGIC, 0x02, struct pkey_clr2seck) /* @@ -148,6 +151,7 @@ struct pkey_sec2protk { struct pkey_seckey seckey; /* in: the secure key blob */ struct pkey_protkey protkey; /* out: the protected key */ }; + #define PKEY_SEC2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x03, struct pkey_sec2protk) /* @@ -158,6 +162,7 @@ struct pkey_clr2protk { struct pkey_clrkey clrkey; /* in: the clear key value */ struct pkey_protkey protkey; /* out: the protected key */ }; + #define PKEY_CLR2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x04, struct pkey_clr2protk) /* @@ -169,6 +174,7 @@ struct pkey_findcard { __u16 cardnr; /* out: card number */ __u16 domain; /* out: domain number */ }; + #define PKEY_FINDCARD _IOWR(PKEY_IOCTL_MAGIC, 0x05, struct pkey_findcard) /* @@ -178,6 +184,7 @@ struct pkey_skey2pkey { struct pkey_seckey seckey; /* in: the secure key blob */ struct pkey_protkey protkey; /* out: the protected key */ }; + #define PKEY_SKEY2PKEY _IOWR(PKEY_IOCTL_MAGIC, 0x06, struct pkey_skey2pkey) /* @@ -195,6 +202,7 @@ struct pkey_verifykey { __u16 keysize; /* out: key size in bits */ __u32 attributes; /* out: attribute bits */ }; + #define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey) #define PKEY_VERIFY_ATTR_AES 0x00000001 /* key is an AES key */ #define PKEY_VERIFY_ATTR_OLD_MKVP 0x00000100 /* key has old MKVP value */ @@ -226,6 +234,7 @@ struct pkey_kblob2pkey { __u32 keylen; /* in: the key blob length */ struct pkey_protkey protkey; /* out: the protected key */ }; + #define PKEY_KBLOB2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x0A, struct pkey_kblob2pkey) /* @@ -258,6 +267,7 @@ struct pkey_genseck2 { __u32 keylen; /* in: available key blob buffer size */ /* out: actual key blob size */ }; + #define PKEY_GENSECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x11, struct pkey_genseck2) /* @@ -292,6 +302,7 @@ struct pkey_clr2seck2 { __u32 keylen; /* in: available key blob buffer size */ /* out: actual key blob size */ }; + #define PKEY_CLR2SECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x12, struct pkey_clr2seck2) /* @@ -329,6 +340,7 @@ struct pkey_verifykey2 { enum pkey_key_size size; /* out: the key size */ __u32 flags; /* out: additional key info flags */ }; + #define PKEY_VERIFYKEY2 _IOWR(PKEY_IOCTL_MAGIC, 0x17, struct pkey_verifykey2) /* @@ -351,6 +363,7 @@ struct pkey_kblob2pkey2 { __u32 apqn_entries; /* in: # of apqn target list entries */ struct pkey_protkey protkey; /* out: the protected key */ }; + #define PKEY_KBLOB2PROTK2 _IOWR(PKEY_IOCTL_MAGIC, 0x1A, struct pkey_kblob2pkey2) /* @@ -387,6 +400,7 @@ struct pkey_apqns4key { __u32 apqn_entries; /* in: max # of apqn entries in the list */ /* out: # apqns stored into the list */ }; + #define PKEY_APQNS4K _IOWR(PKEY_IOCTL_MAGIC, 0x1B, struct pkey_apqns4key) /* @@ -426,6 +440,7 @@ struct pkey_apqns4keytype { __u32 apqn_entries; /* in: max # of apqn entries in the list */ /* out: # apqns stored into the list */ }; + #define PKEY_APQNS4KT _IOWR(PKEY_IOCTL_MAGIC, 0x1C, struct pkey_apqns4keytype) /* @@ -452,6 +467,7 @@ struct pkey_kblob2pkey3 { __u32 pkeylen; /* in/out: size of pkey buffer/actual len of pkey */ __u8 __user *pkey; /* in: pkey blob buffer space ptr */ }; + #define PKEY_KBLOB2PROTK3 _IOWR(PKEY_IOCTL_MAGIC, 0x1D, struct pkey_kblob2pkey3) #endif /* _UAPI_PKEY_H */ diff --git a/arch/s390/include/uapi/asm/uvdevice.h b/arch/s390/include/uapi/asm/uvdevice.h index b9c2f14a6af31a..4947f26ad9fb8d 100644 --- a/arch/s390/include/uapi/asm/uvdevice.h +++ b/arch/s390/include/uapi/asm/uvdevice.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* - * Copyright IBM Corp. 2022 + * Copyright IBM Corp. 2022, 2024 * Author(s): Steffen Eiden */ #ifndef __S390_ASM_UVDEVICE_H @@ -52,7 +52,7 @@ struct uvio_uvdev_info { __u64 supp_uvio_cmds; /* * If bit `n` is set, the Ultravisor(UV) supports the UV-call - * corresponding to the IOCTL with nr `n` in the calling contextx (host + * corresponding to the IOCTL with nr `n` in the calling context (host * or guest). The value is only valid if the corresponding bit in * @supp_uvio_cmds is set as well. */ @@ -71,6 +71,7 @@ struct uvio_uvdev_info { #define UVIO_ATT_ADDITIONAL_MAX_LEN 0x8000 #define UVIO_ADD_SECRET_MAX_LEN 0x100000 #define UVIO_LIST_SECRETS_LEN 0x1000 +#define UVIO_RETR_SECRET_MAX_LEN 0x2000 #define UVIO_DEVICE_NAME "uv" #define UVIO_TYPE_UVC 'u' @@ -81,22 +82,25 @@ enum UVIO_IOCTL_NR { UVIO_IOCTL_ADD_SECRET_NR, UVIO_IOCTL_LIST_SECRETS_NR, UVIO_IOCTL_LOCK_SECRETS_NR, + UVIO_IOCTL_RETR_SECRET_NR, /* must be the last entry */ UVIO_IOCTL_NUM_IOCTLS }; -#define UVIO_IOCTL(nr) _IOWR(UVIO_TYPE_UVC, nr, struct uvio_ioctl_cb) -#define UVIO_IOCTL_UVDEV_INFO UVIO_IOCTL(UVIO_IOCTL_UVDEV_INFO_NR) -#define UVIO_IOCTL_ATT UVIO_IOCTL(UVIO_IOCTL_ATT_NR) -#define UVIO_IOCTL_ADD_SECRET UVIO_IOCTL(UVIO_IOCTL_ADD_SECRET_NR) -#define UVIO_IOCTL_LIST_SECRETS UVIO_IOCTL(UVIO_IOCTL_LIST_SECRETS_NR) -#define UVIO_IOCTL_LOCK_SECRETS UVIO_IOCTL(UVIO_IOCTL_LOCK_SECRETS_NR) +#define UVIO_IOCTL(nr) _IOWR(UVIO_TYPE_UVC, nr, struct uvio_ioctl_cb) +#define UVIO_IOCTL_UVDEV_INFO UVIO_IOCTL(UVIO_IOCTL_UVDEV_INFO_NR) +#define UVIO_IOCTL_ATT UVIO_IOCTL(UVIO_IOCTL_ATT_NR) +#define UVIO_IOCTL_ADD_SECRET UVIO_IOCTL(UVIO_IOCTL_ADD_SECRET_NR) +#define UVIO_IOCTL_LIST_SECRETS UVIO_IOCTL(UVIO_IOCTL_LIST_SECRETS_NR) +#define UVIO_IOCTL_LOCK_SECRETS UVIO_IOCTL(UVIO_IOCTL_LOCK_SECRETS_NR) +#define UVIO_IOCTL_RETR_SECRET UVIO_IOCTL(UVIO_IOCTL_RETR_SECRET_NR) -#define UVIO_SUPP_CALL(nr) (1ULL << (nr)) -#define UVIO_SUPP_UDEV_INFO UVIO_SUPP_CALL(UVIO_IOCTL_UDEV_INFO_NR) -#define UVIO_SUPP_ATT UVIO_SUPP_CALL(UVIO_IOCTL_ATT_NR) -#define UVIO_SUPP_ADD_SECRET UVIO_SUPP_CALL(UVIO_IOCTL_ADD_SECRET_NR) -#define UVIO_SUPP_LIST_SECRETS UVIO_SUPP_CALL(UVIO_IOCTL_LIST_SECRETS_NR) -#define UVIO_SUPP_LOCK_SECRETS UVIO_SUPP_CALL(UVIO_IOCTL_LOCK_SECRETS_NR) +#define UVIO_SUPP_CALL(nr) (1ULL << (nr)) +#define UVIO_SUPP_UDEV_INFO UVIO_SUPP_CALL(UVIO_IOCTL_UDEV_INFO_NR) +#define UVIO_SUPP_ATT UVIO_SUPP_CALL(UVIO_IOCTL_ATT_NR) +#define UVIO_SUPP_ADD_SECRET UVIO_SUPP_CALL(UVIO_IOCTL_ADD_SECRET_NR) +#define UVIO_SUPP_LIST_SECRETS UVIO_SUPP_CALL(UVIO_IOCTL_LIST_SECRETS_NR) +#define UVIO_SUPP_LOCK_SECRETS UVIO_SUPP_CALL(UVIO_IOCTL_LOCK_SECRETS_NR) +#define UVIO_SUPP_RETR_SECRET UVIO_SUPP_CALL(UVIO_IOCTL_RETR_SECRET_NR) #endif /* __S390_ASM_UVDEVICE_H */ diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 5529248d84fb87..862a9140528e91 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -13,7 +13,6 @@ #include #include #include -#include #include int main(void) @@ -138,7 +137,6 @@ int main(void) OFFSET(__LC_USER_ASCE, lowcore, user_asce); OFFSET(__LC_LPP, lowcore, lpp); OFFSET(__LC_CURRENT_PID, lowcore, current_pid); - OFFSET(__LC_GMAP, lowcore, gmap); OFFSET(__LC_LAST_BREAK, lowcore, last_break); /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */ OFFSET(__LC_DUMP_REIPL, lowcore, ipib); @@ -161,7 +159,6 @@ int main(void) OFFSET(__LC_PGM_TDB, lowcore, pgm_tdb); BLANK(); /* gmap/sie offsets */ - OFFSET(__GMAP_ASCE, gmap, asce); OFFSET(__SIE_PROG0C, kvm_s390_sie_block, prog0c); OFFSET(__SIE_PROG20, kvm_s390_sie_block, prog20); /* kexec_sha_region */ @@ -184,8 +181,8 @@ int main(void) OFFSET(__FGRAPH_RET_FP, fgraph_ret_regs, fp); DEFINE(__FGRAPH_RET_SIZE, sizeof(struct fgraph_ret_regs)); #endif - OFFSET(__FTRACE_REGS_PT_REGS, ftrace_regs, regs); - DEFINE(__FTRACE_REGS_SIZE, sizeof(struct ftrace_regs)); + OFFSET(__FTRACE_REGS_PT_REGS, __arch_ftrace_regs, regs); + DEFINE(__FTRACE_REGS_SIZE, sizeof(struct __arch_ftrace_regs)); OFFSET(__PCPU_FLAGS, pcpu, flags); return 0; diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index b210a29d3ee961..2f4174b961def0 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -20,6 +20,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(cpcmd_lock); static char cpcmd_buf[241]; @@ -45,12 +46,11 @@ static int diag8_response(int cmdlen, char *response, int *rlen) ry.odd = *rlen; asm volatile( " diag %[rx],%[ry],0x8\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (cc), [ry] "+&d" (ry.pair) + CC_IPM(cc) + : CC_OUT(cc, cc), [ry] "+d" (ry.pair) : [rx] "d" (rx.pair) - : "cc"); - if (cc) + : CC_CLOBBER); + if (CC_TRANSFORM(cc)) *rlen += ry.odd; else *rlen = ry.odd; diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index edae1341619600..cd0c93a8fb8bb5 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -237,6 +237,17 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, prot); } +/* + * Return true only when in a kdump or stand-alone kdump environment. + * Note that /proc/vmcore might also be available in "standard zfcp/nvme dump" + * environments, where this function returns false; see dump_available(). + */ +bool is_kdump_kernel(void) +{ + return oldmem_data.start; +} +EXPORT_SYMBOL_GPL(is_kdump_kernel); + static const char *nt_name(Elf64_Word type) { const char *name = "LINUX"; diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index e62bea9ab21e6a..de19fd8a6a9545 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -38,13 +38,13 @@ typedef struct file_private_info { loff_t offset; /* offset of last read in file */ - int act_area; /* number of last formated area */ + int act_area; /* number of last formatted area */ int act_page; /* act page in given area */ - int act_entry; /* last formated entry (offset */ + int act_entry; /* last formatted entry (offset */ /* relative to beginning of last */ - /* formated page) */ + /* formatted page) */ size_t act_entry_offset; /* up to this offset we copied */ - /* in last read the last formated */ + /* in last read the last formatted */ /* entry to userland */ char temp_buf[2048]; /* buffer for output */ debug_info_t *debug_info_org; /* original debug information */ @@ -63,7 +63,7 @@ typedef struct { long args[]; } debug_sprintf_entry_t; -/* internal function prototyes */ +/* internal function prototypes */ static int debug_init(void); static ssize_t debug_output(struct file *file, char __user *user_buf, @@ -77,12 +77,14 @@ static debug_info_t *debug_info_create(const char *name, int pages_per_area, static void debug_info_get(debug_info_t *); static void debug_info_put(debug_info_t *); static int debug_prolog_level_fn(debug_info_t *id, - struct debug_view *view, char *out_buf); + struct debug_view *view, char *out_buf, + size_t out_buf_size); static int debug_input_level_fn(debug_info_t *id, struct debug_view *view, struct file *file, const char __user *user_buf, size_t user_buf_size, loff_t *offset); static int debug_prolog_pages_fn(debug_info_t *id, - struct debug_view *view, char *out_buf); + struct debug_view *view, char *out_buf, + size_t out_buf_size); static int debug_input_pages_fn(debug_info_t *id, struct debug_view *view, struct file *file, const char __user *user_buf, size_t user_buf_size, loff_t *offset); @@ -90,9 +92,11 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view, struct file *file, const char __user *user_buf, size_t user_buf_size, loff_t *offset); static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view, - char *out_buf, const char *in_buf); + char *out_buf, size_t out_buf_size, + const char *in_buf); static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view, - char *out_buf, const char *inbuf); + char *out_buf, size_t out_buf_size, + const char *inbuf); static void debug_areas_swap(debug_info_t *a, debug_info_t *b); static void debug_events_append(debug_info_t *dest, debug_info_t *src); @@ -380,7 +384,7 @@ static void debug_info_put(debug_info_t *db_info) /* * debug_format_entry: - * - format one debug entry and return size of formated data + * - format one debug entry and return size of formatted data */ static int debug_format_entry(file_private_info_t *p_info) { @@ -391,8 +395,10 @@ static int debug_format_entry(file_private_info_t *p_info) if (p_info->act_entry == DEBUG_PROLOG_ENTRY) { /* print prolog */ - if (view->prolog_proc) - len += view->prolog_proc(id_snap, view, p_info->temp_buf); + if (view->prolog_proc) { + len += view->prolog_proc(id_snap, view, p_info->temp_buf, + sizeof(p_info->temp_buf)); + } goto out; } if (!id_snap->areas) /* this is true, if we have a prolog only view */ @@ -402,12 +408,16 @@ static int debug_format_entry(file_private_info_t *p_info) if (act_entry->clock == 0LL) goto out; /* empty entry */ - if (view->header_proc) + if (view->header_proc) { len += view->header_proc(id_snap, view, p_info->act_area, - act_entry, p_info->temp_buf + len); - if (view->format_proc) + act_entry, p_info->temp_buf + len, + sizeof(p_info->temp_buf) - len); + } + if (view->format_proc) { len += view->format_proc(id_snap, view, p_info->temp_buf + len, + sizeof(p_info->temp_buf) - len, DEBUG_DATA(act_entry)); + } out: return len; } @@ -449,7 +459,7 @@ static inline int debug_next_entry(file_private_info_t *p_info) /* * debug_output: * - called for user read() - * - copies formated debug entries to the user buffer + * - copies formatted debug entries to the user buffer */ static ssize_t debug_output(struct file *file, /* file descriptor */ char __user *user_buf, /* user buffer */ @@ -523,7 +533,7 @@ static ssize_t debug_input(struct file *file, const char __user *user_buf, /* * debug_open: * - called for user open() - * - copies formated output to private_data area of the file + * - copies formatted output to private_data area of the file * handle */ static int debug_open(struct inode *inode, struct file *file) @@ -1292,9 +1302,9 @@ static inline int debug_get_uint(char *buf) */ static int debug_prolog_pages_fn(debug_info_t *id, struct debug_view *view, - char *out_buf) + char *out_buf, size_t out_buf_size) { - return sprintf(out_buf, "%i\n", id->pages_per_area); + return scnprintf(out_buf, out_buf_size, "%i\n", id->pages_per_area); } /* @@ -1341,14 +1351,14 @@ static int debug_input_pages_fn(debug_info_t *id, struct debug_view *view, * prints out actual debug level */ static int debug_prolog_level_fn(debug_info_t *id, struct debug_view *view, - char *out_buf) + char *out_buf, size_t out_buf_size) { int rc = 0; if (id->level == DEBUG_OFF_LEVEL) - rc = sprintf(out_buf, "-\n"); + rc = scnprintf(out_buf, out_buf_size, "-\n"); else - rc = sprintf(out_buf, "%i\n", id->level); + rc = scnprintf(out_buf, out_buf_size, "%i\n", id->level); return rc; } @@ -1465,22 +1475,24 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view, * prints debug data in hex/ascii format */ static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view, - char *out_buf, const char *in_buf) + char *out_buf, size_t out_buf_size, const char *in_buf) { int i, rc = 0; - for (i = 0; i < id->buf_size; i++) - rc += sprintf(out_buf + rc, "%02x ", ((unsigned char *) in_buf)[i]); - rc += sprintf(out_buf + rc, "| "); + for (i = 0; i < id->buf_size; i++) { + rc += scnprintf(out_buf + rc, out_buf_size - rc, + "%02x ", ((unsigned char *)in_buf)[i]); + } + rc += scnprintf(out_buf + rc, out_buf_size - rc, "| "); for (i = 0; i < id->buf_size; i++) { unsigned char c = in_buf[i]; if (isascii(c) && isprint(c)) - rc += sprintf(out_buf + rc, "%c", c); + rc += scnprintf(out_buf + rc, out_buf_size - rc, "%c", c); else - rc += sprintf(out_buf + rc, "."); + rc += scnprintf(out_buf + rc, out_buf_size - rc, "."); } - rc += sprintf(out_buf + rc, "\n"); + rc += scnprintf(out_buf + rc, out_buf_size - rc, "\n"); return rc; } @@ -1488,7 +1500,8 @@ static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view, * prints header for debug entry */ int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view, - int area, debug_entry_t *entry, char *out_buf) + int area, debug_entry_t *entry, char *out_buf, + size_t out_buf_size) { unsigned long sec, usec; unsigned long caller; @@ -1505,22 +1518,22 @@ int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view, else except_str = "-"; caller = (unsigned long) entry->caller; - rc += sprintf(out_buf, "%02i %011ld:%06lu %1u %1s %04u %px ", - area, sec, usec, level, except_str, - entry->cpu, (void *)caller); + rc += scnprintf(out_buf, out_buf_size, "%02i %011ld:%06lu %1u %1s %04u %px ", + area, sec, usec, level, except_str, + entry->cpu, (void *)caller); return rc; } EXPORT_SYMBOL(debug_dflt_header_fn); /* - * prints debug data sprintf-formated: + * prints debug data sprintf-formatted: * debug_sprinf_event/exception calls must be used together with this view */ #define DEBUG_SPRINTF_MAX_ARGS 10 static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view, - char *out_buf, const char *inbuf) + char *out_buf, size_t out_buf_size, const char *inbuf) { debug_sprintf_entry_t *curr_event = (debug_sprintf_entry_t *)inbuf; int num_longs, num_used_args = 0, i, rc = 0; @@ -1533,8 +1546,9 @@ static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view, goto out; /* bufsize of entry too small */ if (num_longs == 1) { /* no args, we use only the string */ - strcpy(out_buf, curr_event->string); - rc = strlen(curr_event->string); + rc = strscpy(out_buf, curr_event->string, out_buf_size); + if (rc == -E2BIG) + rc = out_buf_size; goto out; } @@ -1546,12 +1560,13 @@ static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view, for (i = 0; i < num_used_args; i++) index[i] = i; - rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]], - curr_event->args[index[1]], curr_event->args[index[2]], - curr_event->args[index[3]], curr_event->args[index[4]], - curr_event->args[index[5]], curr_event->args[index[6]], - curr_event->args[index[7]], curr_event->args[index[8]], - curr_event->args[index[9]]); + rc = scnprintf(out_buf, out_buf_size, + curr_event->string, curr_event->args[index[0]], + curr_event->args[index[1]], curr_event->args[index[2]], + curr_event->args[index[3]], curr_event->args[index[4]], + curr_event->args[index[5]], curr_event->args[index[6]], + curr_event->args[index[7]], curr_event->args[index[8]], + curr_event->args[index[9]]); out: return rc; } diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c index 007e1795670e8a..cdd6e31344fa6b 100644 --- a/arch/s390/kernel/diag.c +++ b/arch/s390/kernel/diag.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "entry.h" struct diag_stat { @@ -307,16 +308,15 @@ EXPORT_SYMBOL(diag26c); int diag49c(unsigned long subcode) { - int rc; + int cc; diag_stat_inc(DIAG_STAT_X49C); asm volatile( " diag %[subcode],0,0x49c\n" - " ipm %[rc]\n" - " srl %[rc],28\n" - : [rc] "=d" (rc) + CC_IPM(cc) + : CC_OUT(cc, cc) : [subcode] "d" (subcode) - : "cc"); - return rc; + : CC_CLOBBER); + return CC_TRANSFORM(cc); } EXPORT_SYMBOL(diag49c); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index d6d5317f768e82..960c08700cf690 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -222,17 +222,6 @@ SYM_FUNC_START(__sie64a) lctlg %c1,%c1,__LC_KERNEL_ASCE(%r14) # load primary asce lg %r14,__LC_CURRENT(%r14) mvi __TI_sie(%r14),0 -# some program checks are suppressing. C code (e.g. do_protection_exception) -# will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There -# are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable. -# Other instructions between __sie64a and .Lsie_done should not cause program -# interrupts. So lets use 3 nops as a landing pad for all possible rewinds. -.Lrewind_pad6: - nopr 7 -.Lrewind_pad4: - nopr 7 -.Lrewind_pad2: - nopr 7 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 @@ -244,15 +233,6 @@ SYM_INNER_LABEL(sie_exit, SYM_L_GLOBAL) lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers lg %r2,__SF_SIE_REASON(%r15) # return exit reason code BR_EX %r14 -.Lsie_fault: - lghi %r14,-EFAULT - stg %r14,__SF_SIE_REASON(%r15) # set exit reason code - j sie_exit - - EX_TABLE(.Lrewind_pad6,.Lsie_fault) - EX_TABLE(.Lrewind_pad4,.Lsie_fault) - EX_TABLE(.Lrewind_pad2,.Lsie_fault) - EX_TABLE(sie_exit,.Lsie_fault) SYM_FUNC_END(__sie64a) EXPORT_SYMBOL(__sie64a) EXPORT_SYMBOL(sie_exit) @@ -327,13 +307,21 @@ SYM_CODE_START(pgm_check_handler) GET_LC %r13 stpt __LC_SYS_ENTER_TIMER(%r13) BPOFF - lgr %r10,%r15 lmg %r8,%r9,__LC_PGM_OLD_PSW(%r13) + xgr %r10,%r10 tmhh %r8,0x0001 # coming from user space? jno .Lpgm_skip_asce lctlg %c1,%c1,__LC_KERNEL_ASCE(%r13) j 3f # -> fault in user space .Lpgm_skip_asce: +#if IS_ENABLED(CONFIG_KVM) + lg %r11,__LC_CURRENT(%r13) + tm __TI_sie(%r11),0xff + jz 1f + BPENTER __SF_SIE_FLAGS(%r15),_TIF_ISOLATE_BP_GUEST + SIEEXIT __SF_SIE_CONTROL(%r15),%r13 + lghi %r10,_PIF_GUEST_FAULT +#endif 1: tmhh %r8,0x4000 # PER bit set in old PSW ? jnz 2f # -> enabled, can't be a double fault tm __LC_PGM_ILC+3(%r13),0x80 # check for per exception @@ -344,21 +332,12 @@ SYM_CODE_START(pgm_check_handler) CHECK_VMAP_STACK __LC_SAVE_AREA,%r13,4f 3: lg %r15,__LC_KERNEL_STACK(%r13) 4: la %r11,STACK_FRAME_OVERHEAD(%r15) - xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) + stg %r10,__PT_FLAGS(%r11) xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) stmg %r0,%r7,__PT_R0(%r11) mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13) mvc __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK(%r13) - stctg %c1,%c1,__PT_CR1(%r11) -#if IS_ENABLED(CONFIG_KVM) - ltg %r12,__LC_GMAP(%r13) - jz 5f - clc __GMAP_ASCE(8,%r12), __PT_CR1(%r11) - jne 5f - BPENTER __SF_SIE_FLAGS(%r10),_TIF_ISOLATE_BP_GUEST - SIEEXIT __SF_SIE_CONTROL(%r10),%r13 -#endif -5: stmg %r8,%r9,__PT_PSW(%r11) + stmg %r8,%r9,__PT_PSW(%r11) # clear user controlled registers to prevent speculative use xgr %r0,%r0 xgr %r1,%r1 @@ -367,6 +346,7 @@ SYM_CODE_START(pgm_check_handler) xgr %r5,%r5 xgr %r6,%r6 xgr %r7,%r7 + xgr %r12,%r12 lgr %r2,%r11 brasl %r14,__do_pgm_check tmhh %r8,0x0001 # returning to user space? @@ -450,9 +430,13 @@ SYM_CODE_START(\name) SYM_CODE_END(\name) .endm + .section .irqentry.text, "ax" + INT_HANDLER ext_int_handler,__LC_EXT_OLD_PSW,do_ext_irq INT_HANDLER io_int_handler,__LC_IO_OLD_PSW,do_io_irq + .section .kprobes.text, "ax" + /* * Machine check handler routines */ diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 0b6e62d1d8b87e..51439a71e392c6 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -318,7 +318,7 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, if (bit < 0) return; - kmsan_unpoison_memory(fregs, sizeof(*fregs)); + kmsan_unpoison_memory(fregs, ftrace_regs_size()); regs = ftrace_get_regs(fregs); p = get_kprobe((kprobe_opcode_t *)ip); if (!regs || unlikely(!p) || kprobe_disabled(p)) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index f17bb7bf939242..7d12a1305fc99f 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -209,7 +209,7 @@ static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \ struct kobj_attribute *attr, \ char *page) \ { \ - return scnprintf(page, PAGE_SIZE, _format, ##args); \ + return sysfs_emit(page, _format, ##args); \ } #define IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk) \ @@ -270,7 +270,7 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \ if (len >= sizeof(_value)) \ return -E2BIG; \ len = strscpy(_value, buf, sizeof(_value)); \ - if (len < 0) \ + if ((ssize_t)len < 0) \ return len; \ strim(_value); \ return len; \ @@ -372,7 +372,7 @@ EXPORT_SYMBOL_GPL(ipl_info); static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%s\n", ipl_type_str(ipl_info.type)); + return sysfs_emit(page, "%s\n", ipl_type_str(ipl_info.type)); } static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); @@ -380,7 +380,7 @@ static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); static ssize_t ipl_secure_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%i\n", !!ipl_secure_flag); + return sysfs_emit(page, "%i\n", !!ipl_secure_flag); } static struct kobj_attribute sys_ipl_secure_attr = @@ -389,7 +389,7 @@ static struct kobj_attribute sys_ipl_secure_attr = static ssize_t ipl_has_secure_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%i\n", !!sclp.has_sipl); + return sysfs_emit(page, "%i\n", !!sclp.has_sipl); } static struct kobj_attribute sys_ipl_has_secure_attr = @@ -402,7 +402,7 @@ static ssize_t ipl_vm_parm_show(struct kobject *kobj, if (ipl_block_valid && (ipl_block.pb0_hdr.pbt == IPL_PBT_CCW)) ipl_block_get_ascii_vmparm(parm, sizeof(parm), &ipl_block); - return sprintf(page, "%s\n", parm); + return sysfs_emit(page, "%s\n", parm); } static struct kobj_attribute sys_ipl_vm_parm_attr = @@ -413,18 +413,18 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj, { switch (ipl_info.type) { case IPL_TYPE_CCW: - return sprintf(page, "0.%x.%04x\n", ipl_block.ccw.ssid, - ipl_block.ccw.devno); + return sysfs_emit(page, "0.%x.%04x\n", ipl_block.ccw.ssid, + ipl_block.ccw.devno); case IPL_TYPE_ECKD: case IPL_TYPE_ECKD_DUMP: - return sprintf(page, "0.%x.%04x\n", ipl_block.eckd.ssid, - ipl_block.eckd.devno); + return sysfs_emit(page, "0.%x.%04x\n", ipl_block.eckd.ssid, + ipl_block.eckd.devno); case IPL_TYPE_FCP: case IPL_TYPE_FCP_DUMP: - return sprintf(page, "0.0.%04x\n", ipl_block.fcp.devno); + return sysfs_emit(page, "0.0.%04x\n", ipl_block.fcp.devno); case IPL_TYPE_NVME: case IPL_TYPE_NVME_DUMP: - return sprintf(page, "%08ux\n", ipl_block.nvme.fid); + return sysfs_emit(page, "%08ux\n", ipl_block.nvme.fid); default: return 0; } @@ -503,12 +503,12 @@ static ssize_t eckd_##_name##_br_chr_show(struct kobject *kobj, \ if (!ipb->br_chr.cyl && \ !ipb->br_chr.head && \ !ipb->br_chr.record) \ - return sprintf(buf, "auto\n"); \ + return sysfs_emit(buf, "auto\n"); \ \ - return sprintf(buf, "0x%x,0x%x,0x%x\n", \ - ipb->br_chr.cyl, \ - ipb->br_chr.head, \ - ipb->br_chr.record); \ + return sysfs_emit(buf, "0x%x,0x%x,0x%x\n", \ + ipb->br_chr.cyl, \ + ipb->br_chr.head, \ + ipb->br_chr.record); \ } #define IPL_ATTR_BR_CHR_STORE_FN(_name, _ipb) \ @@ -573,11 +573,11 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj, char loadparm[LOADPARM_LEN + 1] = {}; if (!sclp_ipl_info.is_valid) - return sprintf(page, "#unknown#\n"); + return sysfs_emit(page, "#unknown#\n"); memcpy(loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN); EBCASC(loadparm, LOADPARM_LEN); strim(loadparm); - return sprintf(page, "%s\n", loadparm); + return sysfs_emit(page, "%s\n", loadparm); } static struct kobj_attribute sys_ipl_ccw_loadparm_attr = @@ -731,7 +731,7 @@ static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb, char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; ipl_block_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb); - return sprintf(page, "%s\n", vmparm); + return sysfs_emit(page, "%s\n", vmparm); } static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb, @@ -839,7 +839,7 @@ static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb, char buf[LOADPARM_LEN + 1]; reipl_get_ascii_loadparm(buf, ipb); - return sprintf(page, "%s\n", buf); + return sysfs_emit(page, "%s\n", buf); } static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, @@ -895,7 +895,7 @@ DEFINE_GENERIC_LOADPARM(eckd); static ssize_t reipl_fcp_clear_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%u\n", reipl_fcp_clear); + return sysfs_emit(page, "%u\n", reipl_fcp_clear); } static ssize_t reipl_fcp_clear_store(struct kobject *kobj, @@ -963,7 +963,7 @@ static struct attribute_group reipl_nvme_attr_group = { static ssize_t reipl_nvme_clear_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%u\n", reipl_nvme_clear); + return sysfs_emit(page, "%u\n", reipl_nvme_clear); } static ssize_t reipl_nvme_clear_store(struct kobject *kobj, @@ -984,7 +984,7 @@ DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ccw); static ssize_t reipl_ccw_clear_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%u\n", reipl_ccw_clear); + return sysfs_emit(page, "%u\n", reipl_ccw_clear); } static ssize_t reipl_ccw_clear_store(struct kobject *kobj, @@ -1056,7 +1056,7 @@ static struct attribute_group reipl_eckd_attr_group = { static ssize_t reipl_eckd_clear_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%u\n", reipl_eckd_clear); + return sysfs_emit(page, "%u\n", reipl_eckd_clear); } static ssize_t reipl_eckd_clear_store(struct kobject *kobj, @@ -1086,7 +1086,7 @@ static ssize_t reipl_nss_name_show(struct kobject *kobj, char nss_name[NSS_NAME_SIZE + 1] = {}; reipl_get_ascii_nss_name(nss_name, reipl_block_nss); - return sprintf(page, "%s\n", nss_name); + return sysfs_emit(page, "%s\n", nss_name); } static ssize_t reipl_nss_name_store(struct kobject *kobj, @@ -1171,7 +1171,7 @@ static int reipl_set_type(enum ipl_type type) static ssize_t reipl_type_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%s\n", ipl_type_str(reipl_type)); + return sysfs_emit(page, "%s\n", ipl_type_str(reipl_type)); } static ssize_t reipl_type_store(struct kobject *kobj, @@ -1692,7 +1692,7 @@ static int dump_set_type(enum dump_type type) static ssize_t dump_type_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%s\n", dump_type_str(dump_type)); + return sysfs_emit(page, "%s\n", dump_type_str(dump_type)); } static ssize_t dump_type_store(struct kobject *kobj, @@ -1717,6 +1717,24 @@ static ssize_t dump_type_store(struct kobject *kobj, static struct kobj_attribute dump_type_attr = __ATTR(dump_type, 0644, dump_type_show, dump_type_store); +static ssize_t dump_area_size_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return sysfs_emit(page, "%lu\n", sclp.hsa_size); +} + +static struct kobj_attribute dump_area_size_attr = __ATTR_RO(dump_area_size); + +static struct attribute *dump_attrs[] = { + &dump_type_attr.attr, + &dump_area_size_attr.attr, + NULL, +}; + +static struct attribute_group dump_attr_group = { + .attrs = dump_attrs, +}; + static struct kset *dump_kset; static void diag308_dump(void *dump_block) @@ -1853,7 +1871,7 @@ static int __init dump_init(void) dump_kset = kset_create_and_add("dump", NULL, firmware_kobj); if (!dump_kset) return -ENOMEM; - rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr); + rc = sysfs_create_group(&dump_kset->kobj, &dump_attr_group); if (rc) { kset_unregister(dump_kset); return rc; @@ -2034,7 +2052,7 @@ static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR, static ssize_t on_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%s\n", on_reboot_trigger.action->name); + return sysfs_emit(page, "%s\n", on_reboot_trigger.action->name); } static ssize_t on_reboot_store(struct kobject *kobj, @@ -2060,7 +2078,7 @@ static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action}; static ssize_t on_panic_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%s\n", on_panic_trigger.action->name); + return sysfs_emit(page, "%s\n", on_panic_trigger.action->name); } static ssize_t on_panic_store(struct kobject *kobj, @@ -2086,7 +2104,7 @@ static struct shutdown_trigger on_restart_trigger = {ON_RESTART_STR, static ssize_t on_restart_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%s\n", on_restart_trigger.action->name); + return sysfs_emit(page, "%s\n", on_restart_trigger.action->name); } static ssize_t on_restart_store(struct kobject *kobj, @@ -2122,7 +2140,7 @@ static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action}; static ssize_t on_halt_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%s\n", on_halt_trigger.action->name); + return sysfs_emit(page, "%s\n", on_halt_trigger.action->name); } static ssize_t on_halt_store(struct kobject *kobj, @@ -2148,7 +2166,7 @@ static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action}; static ssize_t on_poff_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - return sprintf(page, "%s\n", on_poff_trigger.action->name); + return sysfs_emit(page, "%s\n", on_poff_trigger.action->name); } static ssize_t on_poff_store(struct kobject *kobj, diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 2639a3d12736a8..ef7be599e1f78c 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "entry.h" DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat); @@ -129,9 +130,13 @@ static int irq_pending(struct pt_regs *regs) { int cc; - asm volatile("tpi 0\n" - "ipm %0" : "=d" (cc) : : "cc"); - return cc >> 28; + asm volatile( + " tpi 0\n" + CC_IPM(cc) + : CC_OUT(cc, cc) + : + : CC_CLOBBER); + return CC_TRANSFORM(cc); } void noinstr do_io_irq(struct pt_regs *regs) @@ -253,7 +258,7 @@ int show_interrupts(struct seq_file *p, void *v) seq_putc(p, '\n'); goto out; } - if (index < nr_irqs) { + if (index < irq_get_nr_irqs()) { show_msi_interrupt(p, index); goto out; } diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 6295faf0987d86..8b80ea57125f3c 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -489,6 +489,12 @@ int __init arch_init_kprobes(void) return 0; } +int __init arch_populate_kprobe_blacklist(void) +{ + return kprobe_add_area_blacklist((unsigned long)__irqentry_text_start, + (unsigned long)__irqentry_text_end); +} + int arch_trampoline_kprobe(struct kprobe *p) { return 0; diff --git a/arch/s390/kernel/nospec-sysfs.c b/arch/s390/kernel/nospec-sysfs.c index a951888186370d..5970dd3ee7c5ad 100644 --- a/arch/s390/kernel/nospec-sysfs.c +++ b/arch/s390/kernel/nospec-sysfs.c @@ -7,17 +7,17 @@ ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "Mitigation: __user pointer sanitization\n"); + return sysfs_emit(buf, "Mitigation: __user pointer sanitization\n"); } ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) { if (test_facility(156)) - return sprintf(buf, "Mitigation: etokens\n"); + return sysfs_emit(buf, "Mitigation: etokens\n"); if (nospec_uses_trampoline()) - return sprintf(buf, "Mitigation: execute trampolines\n"); + return sysfs_emit(buf, "Mitigation: execute trampolines\n"); if (nobp_enabled()) - return sprintf(buf, "Mitigation: limited branch prediction\n"); - return sprintf(buf, "Vulnerable\n"); + return sysfs_emit(buf, "Mitigation: limited branch prediction\n"); + return sysfs_emit(buf, "Vulnerable\n"); } diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c index b695f980bbde03..29080d6d5d8d2f 100644 --- a/arch/s390/kernel/os_info.c +++ b/arch/s390/kernel/os_info.c @@ -180,7 +180,7 @@ static void os_info_old_init(void) } /* - * Return pointer to os infor entry and its size + * Return pointer to os info entry and its size */ void *os_info_old_entry(int nr, unsigned long *size) { diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index e2e0aa463fbd1e..b0bc68da6a116f 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -835,7 +835,7 @@ static int __hw_perf_event_init(struct perf_event *event, unsigned int type) return validate_ctr_version(hwc->config, set); } -/* Events CPU_CYLCES and INSTRUCTIONS can be submitted with two different +/* Events CPU_CYCLES and INSTRUCTIONS can be submitted with two different * attribute::type values: * - PERF_TYPE_HARDWARE: * - pmu->type: @@ -879,8 +879,8 @@ static int hw_perf_event_reset(struct perf_event *event) u64 prev, new; int err; + prev = local64_read(&event->hw.prev_count); do { - prev = local64_read(&event->hw.prev_count); err = ecctr(event->hw.config, &new); if (err) { if (err != 3) @@ -892,7 +892,7 @@ static int hw_perf_event_reset(struct perf_event *event) */ new = 0; } - } while (local64_cmpxchg(&event->hw.prev_count, prev, new) != prev); + } while (!local64_try_cmpxchg(&event->hw.prev_count, &prev, new)); return err; } @@ -902,12 +902,12 @@ static void hw_perf_event_update(struct perf_event *event) u64 prev, new, delta; int err; + prev = local64_read(&event->hw.prev_count); do { - prev = local64_read(&event->hw.prev_count); err = ecctr(event->hw.config, &new); if (err) return; - } while (local64_cmpxchg(&event->hw.prev_count, prev, new) != prev); + } while (!local64_try_cmpxchg(&event->hw.prev_count, &prev, new)); delta = (prev <= new) ? new - prev : (-1ULL - prev) + new + 1; /* overflow */ @@ -1054,7 +1054,7 @@ static void cpumf_pmu_del(struct perf_event *event, int flags) * * When a new perf event has been added but not yet started, this can * clear enable control and resets all counters in a set. Therefore, - * cpumf_pmu_start() always has to reenable a counter set. + * cpumf_pmu_start() always has to re-enable a counter set. */ for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) if (!atomic_read(&cpuhw->ctr_set[i])) @@ -1863,7 +1863,7 @@ static const struct attribute_group *cfdiag_attr_groups[] = { /* Performance monitoring unit for event CF_DIAG. Since this event * is also started and stopped via the perf_event_open() system call, use * the same event enable/disable call back functions. They do not - * have a pointer to the perf_event strcture as first parameter. + * have a pointer to the perf_event structure as first parameter. * * The functions XXX_add, XXX_del, XXX_start and XXX_stop are also common. * Reuse them and distinguish the event (always first parameter) via diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index 5b765e3ccf0cad..1e99514fb7ae3d 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -180,39 +180,27 @@ static int sf_buffer_available(struct cpu_hw_sf *cpuhw) */ static void free_sampling_buffer(struct sf_buffer *sfb) { - unsigned long *sdbt, *curr; - - if (!sfb->sdbt) - return; + unsigned long *sdbt, *curr, *head; sdbt = sfb->sdbt; - curr = sdbt; - + if (!sdbt) + return; + sfb->sdbt = NULL; /* Free the SDBT after all SDBs are processed... */ - while (1) { - if (!*curr || !sdbt) - break; - - /* Process table-link entries */ + head = sdbt; + curr = sdbt; + do { if (is_link_entry(curr)) { + /* Process table-link entries */ curr = get_next_sdbt(curr); - if (sdbt) - free_page((unsigned long)sdbt); - - /* If the origin is reached, sampling buffer is freed */ - if (curr == sfb->sdbt) - break; - else - sdbt = curr; + free_page((unsigned long)sdbt); + sdbt = curr; } else { /* Process SDB pointer */ - if (*curr) { - free_page((unsigned long)phys_to_virt(*curr)); - curr++; - } + free_page((unsigned long)phys_to_virt(*curr)); + curr++; } - } - + } while (curr != head); memset(sfb, 0, sizeof(*sfb)); } @@ -404,7 +392,7 @@ static void sfb_init_allocs(unsigned long num, struct hw_perf_event *hwc) static void deallocate_buffers(struct cpu_hw_sf *cpuhw) { - if (cpuhw->sfb.sdbt) + if (sf_buffer_available(cpuhw)) free_sampling_buffer(&cpuhw->sfb); } @@ -559,16 +547,15 @@ static void setup_pmc_cpu(void *flags) { struct cpu_hw_sf *cpuhw = this_cpu_ptr(&cpu_hw_sf); + sf_disable(); switch (*((int *)flags)) { case PMC_INIT: memset(cpuhw, 0, sizeof(*cpuhw)); qsi(&cpuhw->qsi); cpuhw->flags |= PMU_F_RESERVED; - sf_disable(); break; case PMC_RELEASE: cpuhw->flags &= ~PMU_F_RESERVED; - sf_disable(); deallocate_buffers(cpuhw); break; } @@ -759,7 +746,6 @@ static int __hw_perf_event_init(struct perf_event *event) reserve_pmc_hardware(); refcount_set(&num_events, 1); } - mutex_unlock(&pmc_reserve_mutex); event->destroy = hw_perf_event_destroy; /* Access per-CPU sampling information (query sampling info) */ @@ -818,7 +804,7 @@ static int __hw_perf_event_init(struct perf_event *event) /* Use AUX buffer. No need to allocate it by ourself */ if (attr->config == PERF_EVENT_CPUM_SF_DIAG) - return 0; + goto out; /* Allocate the per-CPU sampling buffer using the CPU information * from the event. If the event is not pinned to a particular @@ -848,6 +834,7 @@ static int __hw_perf_event_init(struct perf_event *event) if (is_default_overflow_handler(event)) event->overflow_handler = cpumsf_output_event_pid; out: + mutex_unlock(&pmc_reserve_mutex); return err; } @@ -910,10 +897,14 @@ static void cpumsf_pmu_enable(struct pmu *pmu) struct hw_perf_event *hwc; int err; - if (cpuhw->flags & PMU_F_ENABLED) - return; - - if (cpuhw->flags & PMU_F_ERR_MASK) + /* + * Event must be + * - added/started on this CPU (PMU_F_IN_USE set) + * - and CPU must be available (PMU_F_RESERVED set) + * - and not already enabled (PMU_F_ENABLED not set) + * - and not in error condition (PMU_F_ERR_MASK not set) + */ + if (cpuhw->flags != (PMU_F_IN_USE | PMU_F_RESERVED)) return; /* Check whether to extent the sampling buffer. @@ -927,33 +918,27 @@ static void cpumsf_pmu_enable(struct pmu *pmu) * facility, but it can be fully re-enabled using sampling controls that * have been saved in cpumsf_pmu_disable(). */ - if (cpuhw->event) { - hwc = &cpuhw->event->hw; - if (!(SAMPL_DIAG_MODE(hwc))) { - /* - * Account number of overflow-designated - * buffer extents - */ - sfb_account_overflows(cpuhw, hwc); - extend_sampling_buffer(&cpuhw->sfb, hwc); - } - /* Rate may be adjusted with ioctl() */ - cpuhw->lsctl.interval = SAMPL_RATE(hwc); + hwc = &cpuhw->event->hw; + if (!(SAMPL_DIAG_MODE(hwc))) { + /* + * Account number of overflow-designated buffer extents + */ + sfb_account_overflows(cpuhw, hwc); + extend_sampling_buffer(&cpuhw->sfb, hwc); } + /* Rate may be adjusted with ioctl() */ + cpuhw->lsctl.interval = SAMPL_RATE(hwc); /* (Re)enable the PMU and sampling facility */ - cpuhw->flags |= PMU_F_ENABLED; - barrier(); - err = lsctl(&cpuhw->lsctl); if (err) { - cpuhw->flags &= ~PMU_F_ENABLED; pr_err("Loading sampling controls failed: op 1 err %i\n", err); return; } /* Load current program parameter */ lpp(&get_lowcore()->lpp); + cpuhw->flags |= PMU_F_ENABLED; } static void cpumsf_pmu_disable(struct pmu *pmu) @@ -1191,8 +1176,8 @@ static void hw_collect_samples(struct perf_event *event, unsigned long *sdbt, static void hw_perf_event_update(struct perf_event *event, int flush_all) { unsigned long long event_overflow, sampl_overflow, num_sdb; - union hws_trailer_header old, prev, new; struct hw_perf_event *hwc = &event->hw; + union hws_trailer_header prev, new; struct hws_trailer_entry *te; unsigned long *sdbt, sdb; int done; @@ -1236,13 +1221,11 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all) /* Reset trailer (using compare-double-and-swap) */ prev.val = READ_ONCE_ALIGNED_128(te->header.val); do { - old.val = prev.val; new.val = prev.val; new.f = 0; new.a = 1; new.overflow = 0; - prev.val = cmpxchg128(&te->header.val, old.val, new.val); - } while (prev.val != old.val); + } while (!try_cmpxchg128(&te->header.val, &prev.val, new.val)); /* Advance to next sample-data-block */ sdbt++; @@ -1408,16 +1391,15 @@ static int aux_output_begin(struct perf_output_handle *handle, static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index, unsigned long long *overflow) { - union hws_trailer_header old, prev, new; + union hws_trailer_header prev, new; struct hws_trailer_entry *te; te = aux_sdb_trailer(aux, alert_index); prev.val = READ_ONCE_ALIGNED_128(te->header.val); do { - old.val = prev.val; new.val = prev.val; - *overflow = old.overflow; - if (old.f) { + *overflow = prev.overflow; + if (prev.f) { /* * SDB is already set by hardware. * Abort and try to set somewhere @@ -1427,8 +1409,7 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index, } new.a = 1; new.overflow = 0; - prev.val = cmpxchg128(&te->header.val, old.val, new.val); - } while (prev.val != old.val); + } while (!try_cmpxchg128(&te->header.val, &prev.val, new.val)); return true; } @@ -1457,7 +1438,7 @@ static bool aux_set_alert(struct aux_buffer *aux, unsigned long alert_index, static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range, unsigned long long *overflow) { - union hws_trailer_header old, prev, new; + union hws_trailer_header prev, new; unsigned long i, range_scan, idx; unsigned long long orig_overflow; struct hws_trailer_entry *te; @@ -1489,17 +1470,15 @@ static bool aux_reset_buffer(struct aux_buffer *aux, unsigned long range, te = aux_sdb_trailer(aux, idx); prev.val = READ_ONCE_ALIGNED_128(te->header.val); do { - old.val = prev.val; new.val = prev.val; - orig_overflow = old.overflow; + orig_overflow = prev.overflow; new.f = 0; new.overflow = 0; if (idx == aux->alert_mark) new.a = 1; else new.a = 0; - prev.val = cmpxchg128(&te->header.val, old.val, new.val); - } while (prev.val != old.val); + } while (!try_cmpxchg128(&te->header.val, &prev.val, new.val)); *overflow += orig_overflow; } @@ -1780,7 +1759,9 @@ static void cpumsf_pmu_stop(struct perf_event *event, int flags) event->hw.state |= PERF_HES_STOPPED; if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) { - hw_perf_event_update(event, 1); + /* CPU hotplug off removes SDBs. No samples to extract. */ + if (cpuhw->flags & PMU_F_RESERVED) + hw_perf_event_update(event, 1); event->hw.state |= PERF_HES_UPTODATE; } perf_pmu_enable(event->pmu); @@ -1795,7 +1776,7 @@ static int cpumsf_pmu_add(struct perf_event *event, int flags) if (cpuhw->flags & PMU_F_IN_USE) return -EAGAIN; - if (!SAMPL_DIAG_MODE(&event->hw) && !cpuhw->sfb.sdbt) + if (!SAMPL_DIAG_MODE(&event->hw) && !sf_buffer_available(cpuhw)) return -EINVAL; perf_pmu_disable(event->pmu); @@ -1957,13 +1938,12 @@ static void cpumf_measurement_alert(struct ext_code ext_code, /* Program alert request */ if (alert & CPU_MF_INT_SF_PRA) { - if (cpuhw->flags & PMU_F_IN_USE) + if (cpuhw->flags & PMU_F_IN_USE) { if (SAMPL_DIAG_MODE(&cpuhw->event->hw)) hw_collect_aux(cpuhw); else hw_perf_event_update(cpuhw->event, 0); - else - WARN_ON_ONCE(!(cpuhw->flags & PMU_F_IN_USE)); + } } /* Report measurement alerts only for non-PRA codes */ @@ -1984,7 +1964,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, /* Invalid sampling buffer entry */ if (alert & (CPU_MF_INT_SF_IAE|CPU_MF_INT_SF_ISE)) { - pr_err("A sampling buffer entry is incorrect (alert=0x%x)\n", + pr_err("A sampling buffer entry is incorrect (alert=%#x)\n", alert); cpuhw->flags |= PMU_F_ERR_IBE; sf_disable(); diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c index 5fff629b1a8980..2b9611c4718ed2 100644 --- a/arch/s390/kernel/perf_event.c +++ b/arch/s390/kernel/perf_event.c @@ -57,7 +57,7 @@ static unsigned long instruction_pointer_guest(struct pt_regs *regs) return sie_block(regs)->gpsw.addr; } -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { return is_in_guest(regs) ? instruction_pointer_guest(regs) : instruction_pointer(regs); @@ -84,7 +84,7 @@ static unsigned long perf_misc_flags_sf(struct pt_regs *regs) return flags; } -unsigned long perf_misc_flags(struct pt_regs *regs) +unsigned long perf_arch_misc_flags(struct pt_regs *regs) { /* Check if the cpum_sf PMU has created the pt_regs structure. * In this case, perf misc flags can be easily extracted. Otherwise, @@ -228,5 +228,5 @@ ssize_t cpumf_events_sysfs_show(struct device *dev, struct perf_pmu_events_attr *pmu_attr; pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); - return sprintf(page, "event=0x%04llx\n", pmu_attr->id); + return sysfs_emit(page, "event=0x%04llx\n", pmu_attr->id); } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 4df56fdb248807..822d8e6f871716 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -574,7 +574,7 @@ int smp_store_status(int cpu) /* * Collect CPU state of the previous, crashed system. - * There are four cases: + * There are three cases: * 1) standard zfcp/nvme dump * condition: OLDMEM_BASE == NULL && is_ipl_type_dump() == true * The state for all CPUs except the boot CPU needs to be collected @@ -587,16 +587,16 @@ int smp_store_status(int cpu) * with sigp stop-and-store-status. The firmware or the boot-loader * stored the registers of the boot CPU in the absolute lowcore in the * memory of the old system. - * 3) kdump and the old kernel did not store the CPU state, - * or stand-alone kdump for DASD - * condition: OLDMEM_BASE != NULL && !is_kdump_kernel() + * 3) kdump or stand-alone kdump for DASD + * condition: OLDMEM_BASE != NULL && is_ipl_type_dump() == false * The state for all CPUs except the boot CPU needs to be collected * with sigp stop-and-store-status. The kexec code or the boot-loader * stored the registers of the boot CPU in the memory of the old system. - * 4) kdump and the old kernel stored the CPU state - * condition: OLDMEM_BASE != NULL && is_kdump_kernel() - * This case does not exist for s390 anymore, setup_arch explicitly - * deactivates the elfcorehdr= kernel parameter + * + * Note that the legacy kdump mode where the old kernel stored the CPU states + * does no longer exist: setup_arch() explicitly deactivates the elfcorehdr= + * kernel parameter. The is_kdump_kernel() implementation on s390 is independent + * of the elfcorehdr= parameter. */ static bool dump_available(void) { @@ -1011,7 +1011,7 @@ static ssize_t cpu_configure_show(struct device *dev, ssize_t count; mutex_lock(&smp_cpu_state_mutex); - count = sprintf(buf, "%d\n", per_cpu(pcpu_devices, dev->id).state); + count = sysfs_emit(buf, "%d\n", per_cpu(pcpu_devices, dev->id).state); mutex_unlock(&smp_cpu_state_mutex); return count; } @@ -1083,7 +1083,7 @@ static DEVICE_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); static ssize_t show_cpu_address(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", per_cpu(pcpu_devices, dev->id).address); + return sysfs_emit(buf, "%d\n", per_cpu(pcpu_devices, dev->id).address); } static DEVICE_ATTR(address, 0444, show_cpu_address, NULL); diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 9f59837d159e0c..40edfde25f5b97 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -151,7 +151,7 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo break; } if (!store_ip(consume_entry, cookie, entry, perf, ip)) - return; + break; first = false; } pagefault_enable(); diff --git a/arch/s390/kernel/sthyi.c b/arch/s390/kernel/sthyi.c index 1cf2ad04f8e911..d40f0b983e74c7 100644 --- a/arch/s390/kernel/sthyi.c +++ b/arch/s390/kernel/sthyi.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "entry.h" #define DED_WEIGHT 0xffff @@ -425,13 +426,12 @@ static int sthyi(u64 vaddr, u64 *rc) asm volatile( ".insn rre,0xB2560000,%[r1],%[r2]\n" - "ipm %[cc]\n" - "srl %[cc],28\n" - : [cc] "=&d" (cc), [r2] "+&d" (r2.pair) + CC_IPM(cc) + : CC_OUT(cc, cc), [r2] "+&d" (r2.pair) : [r1] "d" (r1.pair) - : "memory", "cc"); + : CC_CLOBBER_LIST("memory")); *rc = r2.odd; - return cc; + return CC_TRANSFORM(cc); } static int fill_dst(void *dst, u64 *rc) diff --git a/arch/s390/kernel/syscalls/Makefile b/arch/s390/kernel/syscalls/Makefile index 1bb78b9468e8a9..c5d958a09ff438 100644 --- a/arch/s390/kernel/syscalls/Makefile +++ b/arch/s390/kernel/syscalls/Makefile @@ -12,7 +12,7 @@ kapi-hdrs-y := $(kapi)/unistd_nr.h uapi-hdrs-y := $(uapi)/unistd_32.h uapi-hdrs-y += $(uapi)/unistd_64.h -targets += $(addprefix ../../../,$(gen-y) $(kapi-hdrs-y) $(uapi-hdrs-y)) +targets += $(addprefix ../../../../,$(gen-y) $(kapi-hdrs-y) $(uapi-hdrs-y)) PHONY += kapi uapi @@ -23,23 +23,26 @@ uapi: $(uapi-hdrs-y) # Create output directory if not already present $(shell mkdir -p $(uapi) $(kapi)) -filechk_syshdr = $(CONFIG_SHELL) '$(systbl)' -H -a $(syshdr_abi_$(basetarget)) -f "$2" < $< +quiet_cmd_syshdr = SYSHDR $@ + cmd_syshdr = $(CONFIG_SHELL) '$(systbl)' -H -a $(syshdr_abi_$(basetarget)) -f "$@" < $< > $@ -filechk_sysnr = $(CONFIG_SHELL) '$(systbl)' -N -a $(sysnr_abi_$(basetarget)) < $< +quiet_cmd_sysnr = SYSNR $@ + cmd_sysnr = $(CONFIG_SHELL) '$(systbl)' -N -a $(sysnr_abi_$(basetarget)) < $< > $@ -filechk_syscalls = $(CONFIG_SHELL) '$(systbl)' -S < $< +quiet_cmd_syscalls = SYSTBL $@ + cmd_syscalls = $(CONFIG_SHELL) '$(systbl)' -S < $< > $@ syshdr_abi_unistd_32 := common,32 -$(uapi)/unistd_32.h: $(syscall) FORCE - $(call filechk,syshdr,$@) +$(uapi)/unistd_32.h: $(syscall) $(systbl) FORCE + $(call if_changed,syshdr) syshdr_abi_unistd_64 := common,64 -$(uapi)/unistd_64.h: $(syscall) FORCE - $(call filechk,syshdr,$@) +$(uapi)/unistd_64.h: $(syscall) $(systbl) FORCE + $(call if_changed,syshdr) -$(kapi)/syscall_table.h: $(syscall) FORCE - $(call filechk,syscalls) +$(kapi)/syscall_table.h: $(syscall) $(systbl) FORCE + $(call if_changed,syscalls) sysnr_abi_unistd_nr := common,32,64 -$(kapi)/unistd_nr.h: $(syscall) FORCE - $(call filechk,sysnr) +$(kapi)/unistd_nr.h: $(syscall) $(systbl) FORCE + $(call if_changed,sysnr) diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl index 01071182763e96..e9115b4d8b635b 100644 --- a/arch/s390/kernel/syscalls/syscall.tbl +++ b/arch/s390/kernel/syscalls/syscall.tbl @@ -465,3 +465,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal sys_mseal +463 common setxattrat sys_setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat sys_removexattrat diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index b713effe057967..34a65c141ea076 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -255,6 +254,7 @@ static struct clocksource clocksource_tod = { .shift = 24, .flags = CLOCK_SOURCE_IS_CONTINUOUS, .vdso_clock_mode = VDSO_CLOCKMODE_TOD, + .id = CSID_S390_TOD, }; struct clocksource * __init clocksource_default_clock(void) @@ -468,6 +468,12 @@ static void __init stp_reset(void) } } +bool stp_enabled(void) +{ + return test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags) && stp_online; +} +EXPORT_SYMBOL(stp_enabled); + static void stp_timeout(struct timer_list *unused) { queue_work(time_sync_wq, &stp_work); @@ -729,8 +735,8 @@ static ssize_t ctn_id_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid()) - ret = sprintf(buf, "%016lx\n", - *(unsigned long *) stp_info.ctnid); + ret = sysfs_emit(buf, "%016lx\n", + *(unsigned long *)stp_info.ctnid); mutex_unlock(&stp_mutex); return ret; } @@ -745,7 +751,7 @@ static ssize_t ctn_type_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid()) - ret = sprintf(buf, "%i\n", stp_info.ctn); + ret = sysfs_emit(buf, "%i\n", stp_info.ctn); mutex_unlock(&stp_mutex); return ret; } @@ -760,7 +766,7 @@ static ssize_t dst_offset_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid() && (stp_info.vbits & 0x2000)) - ret = sprintf(buf, "%i\n", (int)(s16) stp_info.dsto); + ret = sysfs_emit(buf, "%i\n", (int)(s16)stp_info.dsto); mutex_unlock(&stp_mutex); return ret; } @@ -775,7 +781,7 @@ static ssize_t leap_seconds_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid() && (stp_info.vbits & 0x8000)) - ret = sprintf(buf, "%i\n", (int)(s16) stp_info.leaps); + ret = sysfs_emit(buf, "%i\n", (int)(s16)stp_info.leaps); mutex_unlock(&stp_mutex); return ret; } @@ -801,11 +807,11 @@ static ssize_t leap_seconds_scheduled_show(struct device *dev, return ret; if (!stzi.lsoib.p) - return sprintf(buf, "0,0\n"); + return sysfs_emit(buf, "0,0\n"); - return sprintf(buf, "%lu,%d\n", - tod_to_ns(stzi.lsoib.nlsout - TOD_UNIX_EPOCH) / NSEC_PER_SEC, - stzi.lsoib.nlso - stzi.lsoib.also); + return sysfs_emit(buf, "%lu,%d\n", + tod_to_ns(stzi.lsoib.nlsout - TOD_UNIX_EPOCH) / NSEC_PER_SEC, + stzi.lsoib.nlso - stzi.lsoib.also); } static DEVICE_ATTR_RO(leap_seconds_scheduled); @@ -818,7 +824,7 @@ static ssize_t stratum_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid()) - ret = sprintf(buf, "%i\n", (int)(s16) stp_info.stratum); + ret = sysfs_emit(buf, "%i\n", (int)(s16)stp_info.stratum); mutex_unlock(&stp_mutex); return ret; } @@ -833,7 +839,7 @@ static ssize_t time_offset_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid() && (stp_info.vbits & 0x0800)) - ret = sprintf(buf, "%i\n", (int) stp_info.tto); + ret = sysfs_emit(buf, "%i\n", (int)stp_info.tto); mutex_unlock(&stp_mutex); return ret; } @@ -848,7 +854,7 @@ static ssize_t time_zone_offset_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid() && (stp_info.vbits & 0x4000)) - ret = sprintf(buf, "%i\n", (int)(s16) stp_info.tzo); + ret = sysfs_emit(buf, "%i\n", (int)(s16)stp_info.tzo); mutex_unlock(&stp_mutex); return ret; } @@ -863,7 +869,7 @@ static ssize_t timing_mode_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid()) - ret = sprintf(buf, "%i\n", stp_info.tmd); + ret = sysfs_emit(buf, "%i\n", stp_info.tmd); mutex_unlock(&stp_mutex); return ret; } @@ -878,7 +884,7 @@ static ssize_t timing_state_show(struct device *dev, mutex_lock(&stp_mutex); if (stpinfo_valid()) - ret = sprintf(buf, "%i\n", stp_info.tst); + ret = sysfs_emit(buf, "%i\n", stp_info.tst); mutex_unlock(&stp_mutex); return ret; } @@ -889,7 +895,7 @@ static ssize_t online_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%i\n", stp_online); + return sysfs_emit(buf, "%i\n", stp_online); } static ssize_t online_store(struct device *dev, diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 813e5da9a9737e..4f9c301a705b63 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -26,6 +26,7 @@ #include #include #include +#include #define PTF_HORIZONTAL (0UL) #define PTF_VERTICAL (1UL) @@ -224,15 +225,15 @@ static void topology_update_polarization_simple(void) static int ptf(unsigned long fc) { - int rc; + int cc; asm volatile( - " .insn rre,0xb9a20000,%1,%1\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (rc) - : "d" (fc) : "cc"); - return rc; + " .insn rre,0xb9a20000,%[fc],%[fc]\n" + CC_IPM(cc) + : CC_OUT(cc, cc) + : [fc] "d" (fc) + : CC_CLOBBER); + return CC_TRANSFORM(cc); } int topology_set_cpu_management(int fc) @@ -412,7 +413,7 @@ static ssize_t dispatching_show(struct device *dev, ssize_t count; mutex_lock(&smp_cpu_state_mutex); - count = sprintf(buf, "%d\n", cpu_management); + count = sysfs_emit(buf, "%d\n", cpu_management); mutex_unlock(&smp_cpu_state_mutex); return count; } @@ -443,19 +444,19 @@ static ssize_t cpu_polarization_show(struct device *dev, mutex_lock(&smp_cpu_state_mutex); switch (smp_cpu_get_polarization(cpu)) { case POLARIZATION_HRZ: - count = sprintf(buf, "horizontal\n"); + count = sysfs_emit(buf, "horizontal\n"); break; case POLARIZATION_VL: - count = sprintf(buf, "vertical:low\n"); + count = sysfs_emit(buf, "vertical:low\n"); break; case POLARIZATION_VM: - count = sprintf(buf, "vertical:medium\n"); + count = sysfs_emit(buf, "vertical:medium\n"); break; case POLARIZATION_VH: - count = sprintf(buf, "vertical:high\n"); + count = sysfs_emit(buf, "vertical:high\n"); break; default: - count = sprintf(buf, "unknown\n"); + count = sysfs_emit(buf, "unknown\n"); break; } mutex_unlock(&smp_cpu_state_mutex); @@ -479,7 +480,7 @@ static ssize_t cpu_dedicated_show(struct device *dev, ssize_t count; mutex_lock(&smp_cpu_state_mutex); - count = sprintf(buf, "%d\n", topology_cpu_dedicated(cpu)); + count = sysfs_emit(buf, "%d\n", topology_cpu_dedicated(cpu)); mutex_unlock(&smp_cpu_state_mutex); return count; } diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 160b2acba8db2b..24fee11b030d8b 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "entry.h" static inline void __user *get_trap_ip(struct pt_regs *regs) @@ -317,9 +318,24 @@ void noinstr __do_pgm_check(struct pt_regs *regs) struct lowcore *lc = get_lowcore(); irqentry_state_t state; unsigned int trapnr; + union teid teid; + teid.val = lc->trans_exc_code; regs->int_code = lc->pgm_int_code; - regs->int_parm_long = lc->trans_exc_code; + regs->int_parm_long = teid.val; + + /* + * In case of a guest fault, short-circuit the fault handler and return. + * This way the sie64a() function will return 0; fault address and + * other relevant bits are saved in current->thread.gmap_teid, and + * the fault number in current->thread.gmap_int_code. KVM will be + * able to use this information to handle the fault. + */ + if (test_pt_regs_flag(regs, PIF_GUEST_FAULT)) { + current->thread.gmap_teid.val = regs->int_parm_long; + current->thread.gmap_int_code = regs->int_code & 0xffff; + return; + } state = irqentry_enter(regs); @@ -408,8 +424,8 @@ static void (*pgm_check_table[128])(struct pt_regs *regs) = { [0x3b] = do_dat_exception, [0x3c] = default_trap_handler, [0x3d] = do_secure_storage_access, - [0x3e] = do_non_secure_storage_access, - [0x3f] = do_secure_storage_violation, + [0x3e] = default_trap_handler, + [0x3f] = default_trap_handler, [0x40] = monitor_event_exception, [0x41 ... 0x7f] = default_trap_handler, }; @@ -420,5 +436,3 @@ static void (*pgm_check_table[128])(struct pt_regs *regs) = { __stringify(default_trap_handler)) COND_TRAP(do_secure_storage_access); -COND_TRAP(do_non_secure_storage_access); -COND_TRAP(do_secure_storage_violation); diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 9646f773208a11..6f9654a191ad94 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -2,7 +2,7 @@ /* * Common Ultravisor functions and initialization * - * Copyright IBM Corp. 2019, 2020 + * Copyright IBM Corp. 2019, 2024 */ #define KMSG_COMPONENT "prot_virt" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt @@ -696,12 +696,32 @@ static struct kobj_attribute uv_query_supp_secret_types_attr = static ssize_t uv_query_max_secrets(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sysfs_emit(buf, "%d\n", uv_info.max_secrets); + return sysfs_emit(buf, "%d\n", + uv_info.max_assoc_secrets + uv_info.max_retr_secrets); } static struct kobj_attribute uv_query_max_secrets_attr = __ATTR(max_secrets, 0444, uv_query_max_secrets, NULL); +static ssize_t uv_query_max_retr_secrets(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%d\n", uv_info.max_retr_secrets); +} + +static struct kobj_attribute uv_query_max_retr_secrets_attr = + __ATTR(max_retr_secrets, 0444, uv_query_max_retr_secrets, NULL); + +static ssize_t uv_query_max_assoc_secrets(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%d\n", uv_info.max_assoc_secrets); +} + +static struct kobj_attribute uv_query_max_assoc_secrets_attr = + __ATTR(max_assoc_secrets, 0444, uv_query_max_assoc_secrets, NULL); + static struct attribute *uv_query_attrs[] = { &uv_query_facilities_attr.attr, &uv_query_feature_indications_attr.attr, @@ -719,13 +739,81 @@ static struct attribute *uv_query_attrs[] = { &uv_query_supp_add_secret_pcf_attr.attr, &uv_query_supp_secret_types_attr.attr, &uv_query_max_secrets_attr.attr, + &uv_query_max_assoc_secrets_attr.attr, + &uv_query_max_retr_secrets_attr.attr, NULL, }; +static inline struct uv_cb_query_keys uv_query_keys(void) +{ + struct uv_cb_query_keys uvcb = { + .header.cmd = UVC_CMD_QUERY_KEYS, + .header.len = sizeof(uvcb) + }; + + uv_call(0, (uint64_t)&uvcb); + return uvcb; +} + +static inline ssize_t emit_hash(struct uv_key_hash *hash, char *buf, int at) +{ + return sysfs_emit_at(buf, at, "%016llx%016llx%016llx%016llx\n", + hash->dword[0], hash->dword[1], hash->dword[2], hash->dword[3]); +} + +static ssize_t uv_keys_host_key(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct uv_cb_query_keys uvcb = uv_query_keys(); + + return emit_hash(&uvcb.key_hashes[UVC_QUERY_KEYS_IDX_HK], buf, 0); +} + +static struct kobj_attribute uv_keys_host_key_attr = + __ATTR(host_key, 0444, uv_keys_host_key, NULL); + +static ssize_t uv_keys_backup_host_key(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct uv_cb_query_keys uvcb = uv_query_keys(); + + return emit_hash(&uvcb.key_hashes[UVC_QUERY_KEYS_IDX_BACK_HK], buf, 0); +} + +static struct kobj_attribute uv_keys_backup_host_key_attr = + __ATTR(backup_host_key, 0444, uv_keys_backup_host_key, NULL); + +static ssize_t uv_keys_all(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct uv_cb_query_keys uvcb = uv_query_keys(); + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(uvcb.key_hashes); i++) + len += emit_hash(uvcb.key_hashes + i, buf, len); + + return len; +} + +static struct kobj_attribute uv_keys_all_attr = + __ATTR(all, 0444, uv_keys_all, NULL); + static struct attribute_group uv_query_attr_group = { .attrs = uv_query_attrs, }; +static struct attribute *uv_keys_attrs[] = { + &uv_keys_host_key_attr.attr, + &uv_keys_backup_host_key_attr.attr, + &uv_keys_all_attr.attr, + NULL, +}; + +static struct attribute_group uv_keys_attr_group = { + .attrs = uv_keys_attrs, +}; + static ssize_t uv_is_prot_virt_guest(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -751,9 +839,27 @@ static const struct attribute *uv_prot_virt_attrs[] = { }; static struct kset *uv_query_kset; +static struct kset *uv_keys_kset; static struct kobject *uv_kobj; -static int __init uv_info_init(void) +static int __init uv_sysfs_dir_init(const struct attribute_group *grp, + struct kset **uv_dir_kset, const char *name) +{ + struct kset *kset; + int rc; + + kset = kset_create_and_add(name, NULL, uv_kobj); + if (!kset) + return -ENOMEM; + *uv_dir_kset = kset; + + rc = sysfs_create_group(&kset->kobj, grp); + if (rc) + kset_unregister(kset); + return rc; +} + +static int __init uv_sysfs_init(void) { int rc = -ENOMEM; @@ -768,17 +874,16 @@ static int __init uv_info_init(void) if (rc) goto out_kobj; - uv_query_kset = kset_create_and_add("query", NULL, uv_kobj); - if (!uv_query_kset) { - rc = -ENOMEM; + rc = uv_sysfs_dir_init(&uv_query_attr_group, &uv_query_kset, "query"); + if (rc) goto out_ind_files; - } - rc = sysfs_create_group(&uv_query_kset->kobj, &uv_query_attr_group); - if (!rc) - return 0; + /* Get installed key hashes if available, ignore any errors */ + if (test_bit_inv(BIT_UVC_CMD_QUERY_KEYS, uv_info.inst_calls_list)) + uv_sysfs_dir_init(&uv_keys_attr_group, &uv_keys_kset, "keys"); + + return 0; - kset_unregister(uv_query_kset); out_ind_files: sysfs_remove_files(uv_kobj, uv_prot_virt_attrs); out_kobj: @@ -786,4 +891,131 @@ static int __init uv_info_init(void) kobject_put(uv_kobj); return rc; } -device_initcall(uv_info_init); +device_initcall(uv_sysfs_init); + +/* + * Find the secret with the secret_id in the provided list. + * + * Context: might sleep. + */ +static int find_secret_in_page(const u8 secret_id[UV_SECRET_ID_LEN], + const struct uv_secret_list *list, + struct uv_secret_list_item_hdr *secret) +{ + u16 i; + + for (i = 0; i < list->total_num_secrets; i++) { + if (memcmp(secret_id, list->secrets[i].id, UV_SECRET_ID_LEN) == 0) { + *secret = list->secrets[i].hdr; + return 0; + } + } + return -ENOENT; +} + +/* + * Do the actual search for `uv_get_secret_metadata`. + * + * Context: might sleep. + */ +static int find_secret(const u8 secret_id[UV_SECRET_ID_LEN], + struct uv_secret_list *list, + struct uv_secret_list_item_hdr *secret) +{ + u16 start_idx = 0; + u16 list_rc; + int ret; + + do { + uv_list_secrets(list, start_idx, &list_rc, NULL); + if (list_rc != UVC_RC_EXECUTED && list_rc != UVC_RC_MORE_DATA) { + if (list_rc == UVC_RC_INV_CMD) + return -ENODEV; + else + return -EIO; + } + ret = find_secret_in_page(secret_id, list, secret); + if (ret == 0) + return ret; + start_idx = list->next_secret_idx; + } while (list_rc == UVC_RC_MORE_DATA && start_idx < list->next_secret_idx); + + return -ENOENT; +} + +/** + * uv_get_secret_metadata() - get secret metadata for a given secret id. + * @secret_id: search pattern. + * @secret: output data, containing the secret's metadata. + * + * Search for a secret with the given secret_id in the Ultravisor secret store. + * + * Context: might sleep. + * + * Return: + * * %0: - Found entry; secret->idx and secret->type are valid. + * * %ENOENT - No entry found. + * * %ENODEV: - Not supported: UV not available or command not available. + * * %EIO: - Other unexpected UV error. + */ +int uv_get_secret_metadata(const u8 secret_id[UV_SECRET_ID_LEN], + struct uv_secret_list_item_hdr *secret) +{ + struct uv_secret_list *buf; + int rc; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + rc = find_secret(secret_id, buf, secret); + kfree(buf); + return rc; +} +EXPORT_SYMBOL_GPL(uv_get_secret_metadata); + +/** + * uv_retrieve_secret() - get the secret value for the secret index. + * @secret_idx: Secret index for which the secret should be retrieved. + * @buf: Buffer to store retrieved secret. + * @buf_size: Size of the buffer. The correct buffer size is reported as part of + * the result from `uv_get_secret_metadata`. + * + * Calls the Retrieve Secret UVC and translates the UV return code into an errno. + * + * Context: might sleep. + * + * Return: + * * %0 - Entry found; buffer contains a valid secret. + * * %ENOENT: - No entry found or secret at the index is non-retrievable. + * * %ENODEV: - Not supported: UV not available or command not available. + * * %EINVAL: - Buffer too small for content. + * * %EIO: - Other unexpected UV error. + */ +int uv_retrieve_secret(u16 secret_idx, u8 *buf, size_t buf_size) +{ + struct uv_cb_retr_secr uvcb = { + .header.len = sizeof(uvcb), + .header.cmd = UVC_CMD_RETR_SECRET, + .secret_idx = secret_idx, + .buf_addr = (u64)buf, + .buf_size = buf_size, + }; + + uv_call_sched(0, (u64)&uvcb); + + switch (uvcb.header.rc) { + case UVC_RC_EXECUTED: + return 0; + case UVC_RC_INV_CMD: + return -ENODEV; + case UVC_RC_RETR_SECR_STORE_EMPTY: + case UVC_RC_RETR_SECR_INV_SECRET: + case UVC_RC_RETR_SECR_INV_IDX: + return -ENOENT; + case UVC_RC_RETR_SECR_BUF_SMALL: + return -EINVAL; + default: + return -EIO; + } +} +EXPORT_SYMBOL_GPL(uv_retrieve_secret); diff --git a/arch/s390/kernel/vdso32/vdso32.lds.S b/arch/s390/kernel/vdso32/vdso32.lds.S index 65b9513a5a0ee2..c916c4f73f766e 100644 --- a/arch/s390/kernel/vdso32/vdso32.lds.S +++ b/arch/s390/kernel/vdso32/vdso32.lds.S @@ -16,7 +16,7 @@ SECTIONS #ifdef CONFIG_TIME_NS PROVIDE(_timens_data = _vdso_data + PAGE_SIZE); #endif - . = VDSO_LBASE + SIZEOF_HEADERS; + . = SIZEOF_HEADERS; .hash : { *(.hash) } :text .gnu.hash : { *(.gnu.hash) } diff --git a/arch/s390/kernel/vdso64/vdso64.lds.S b/arch/s390/kernel/vdso64/vdso64.lds.S index 753040a4b5ab27..ec42b7d9cb5309 100644 --- a/arch/s390/kernel/vdso64/vdso64.lds.S +++ b/arch/s390/kernel/vdso64/vdso64.lds.S @@ -18,7 +18,7 @@ SECTIONS #ifdef CONFIG_TIME_NS PROVIDE(_timens_data = _vdso_data + PAGE_SIZE); #endif - . = VDSO_LBASE + SIZEOF_HEADERS; + . = SIZEOF_HEADERS; .hash : { *(.hash) } :text .gnu.hash : { *(.gnu.hash) } diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c index a688351f4ab521..9816b0060fbe54 100644 --- a/arch/s390/kvm/gaccess.c +++ b/arch/s390/kvm/gaccess.c @@ -129,8 +129,8 @@ static void ipte_lock_simple(struct kvm *kvm) retry: read_lock(&kvm->arch.sca_lock); ic = kvm_s390_get_ipte_control(kvm); + old = READ_ONCE(*ic); do { - old = READ_ONCE(*ic); if (old.k) { read_unlock(&kvm->arch.sca_lock); cond_resched(); @@ -138,7 +138,7 @@ static void ipte_lock_simple(struct kvm *kvm) } new = old; new.k = 1; - } while (cmpxchg(&ic->val, old.val, new.val) != old.val); + } while (!try_cmpxchg(&ic->val, &old.val, new.val)); read_unlock(&kvm->arch.sca_lock); out: mutex_unlock(&kvm->arch.ipte_mutex); @@ -154,11 +154,11 @@ static void ipte_unlock_simple(struct kvm *kvm) goto out; read_lock(&kvm->arch.sca_lock); ic = kvm_s390_get_ipte_control(kvm); + old = READ_ONCE(*ic); do { - old = READ_ONCE(*ic); new = old; new.k = 0; - } while (cmpxchg(&ic->val, old.val, new.val) != old.val); + } while (!try_cmpxchg(&ic->val, &old.val, new.val)); read_unlock(&kvm->arch.sca_lock); wake_up(&kvm->arch.ipte_wq); out: @@ -172,8 +172,8 @@ static void ipte_lock_siif(struct kvm *kvm) retry: read_lock(&kvm->arch.sca_lock); ic = kvm_s390_get_ipte_control(kvm); + old = READ_ONCE(*ic); do { - old = READ_ONCE(*ic); if (old.kg) { read_unlock(&kvm->arch.sca_lock); cond_resched(); @@ -182,7 +182,7 @@ static void ipte_lock_siif(struct kvm *kvm) new = old; new.k = 1; new.kh++; - } while (cmpxchg(&ic->val, old.val, new.val) != old.val); + } while (!try_cmpxchg(&ic->val, &old.val, new.val)); read_unlock(&kvm->arch.sca_lock); } @@ -192,13 +192,13 @@ static void ipte_unlock_siif(struct kvm *kvm) read_lock(&kvm->arch.sca_lock); ic = kvm_s390_get_ipte_control(kvm); + old = READ_ONCE(*ic); do { - old = READ_ONCE(*ic); new = old; new.kh--; if (!new.kh) new.k = 0; - } while (cmpxchg(&ic->val, old.val, new.val) != old.val); + } while (!try_cmpxchg(&ic->val, &old.val, new.val)); read_unlock(&kvm->arch.sca_lock); if (!new.kh) wake_up(&kvm->arch.ipte_wq); diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index b16352083ff987..5bbaadf75dc64c 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -367,7 +367,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu) reg2, &srcaddr, GACC_FETCH, 0); if (rc) return kvm_s390_inject_prog_cond(vcpu, rc); - rc = kvm_arch_fault_in_page(vcpu, srcaddr, 0); + rc = gmap_fault(vcpu->arch.gmap, srcaddr, 0); if (rc != 0) return rc; @@ -376,7 +376,7 @@ static int handle_mvpg_pei(struct kvm_vcpu *vcpu) reg1, &dstaddr, GACC_STORE, 0); if (rc) return kvm_s390_inject_prog_cond(vcpu, rc); - rc = kvm_arch_fault_in_page(vcpu, dstaddr, 1); + rc = gmap_fault(vcpu->arch.gmap, dstaddr, FAULT_FLAG_WRITE); if (rc != 0) return rc; diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 4f0e7f61edf788..ea8dce299954a3 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -118,8 +118,6 @@ static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id) static void sca_clear_ext_call(struct kvm_vcpu *vcpu) { - int rc, expect; - if (!kvm_s390_use_sca_entries()) return; kvm_s390_clear_cpuflags(vcpu, CPUSTAT_ECALL_PEND); @@ -128,23 +126,16 @@ static void sca_clear_ext_call(struct kvm_vcpu *vcpu) struct esca_block *sca = vcpu->kvm->arch.sca; union esca_sigp_ctrl *sigp_ctrl = &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); - union esca_sigp_ctrl old; - old = READ_ONCE(*sigp_ctrl); - expect = old.value; - rc = cmpxchg(&sigp_ctrl->value, old.value, 0); + WRITE_ONCE(sigp_ctrl->value, 0); } else { struct bsca_block *sca = vcpu->kvm->arch.sca; union bsca_sigp_ctrl *sigp_ctrl = &(sca->cpu[vcpu->vcpu_id].sigp_ctrl); - union bsca_sigp_ctrl old; - old = READ_ONCE(*sigp_ctrl); - expect = old.value; - rc = cmpxchg(&sigp_ctrl->value, old.value, 0); + WRITE_ONCE(sigp_ctrl->value, 0); } read_unlock(&vcpu->kvm->arch.sca_lock); - WARN_ON(rc != expect); /* cannot clear? */ } int psw_extint_disabled(struct kvm_vcpu *vcpu) @@ -247,12 +238,12 @@ static inline int gisa_set_iam(struct kvm_s390_gisa *gisa, u8 iam) { u64 word, _word; + word = READ_ONCE(gisa->u64.word[0]); do { - word = READ_ONCE(gisa->u64.word[0]); if ((u64)gisa != word >> 32) return -EBUSY; _word = (word & ~0xffUL) | iam; - } while (cmpxchg(&gisa->u64.word[0], word, _word) != word); + } while (!try_cmpxchg(&gisa->u64.word[0], &word, _word)); return 0; } @@ -270,10 +261,10 @@ static inline void gisa_clear_ipm(struct kvm_s390_gisa *gisa) { u64 word, _word; + word = READ_ONCE(gisa->u64.word[0]); do { - word = READ_ONCE(gisa->u64.word[0]); _word = word & ~(0xffUL << 24); - } while (cmpxchg(&gisa->u64.word[0], word, _word) != word); + } while (!try_cmpxchg(&gisa->u64.word[0], &word, _word)); } /** @@ -291,14 +282,14 @@ static inline u8 gisa_get_ipm_or_restore_iam(struct kvm_s390_gisa_interrupt *gi) u8 pending_mask, alert_mask; u64 word, _word; + word = READ_ONCE(gi->origin->u64.word[0]); do { - word = READ_ONCE(gi->origin->u64.word[0]); alert_mask = READ_ONCE(gi->alert.mask); pending_mask = (u8)(word >> 24) & alert_mask; if (pending_mask) return pending_mask; _word = (word & ~0xffUL) | alert_mask; - } while (cmpxchg(&gi->origin->u64.word[0], word, _word) != word); + } while (!try_cmpxchg(&gi->origin->u64.word[0], &word, _word)); return 0; } diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index bb7134faaebff3..d8080c27d45bda 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -340,12 +341,21 @@ static inline int plo_test_bit(unsigned char nr) " lgr 0,%[function]\n" /* Parameter registers are ignored for "test bit" */ " plo 0,0,0,0(0)\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) + CC_IPM(cc) + : CC_OUT(cc, cc) : [function] "d" (function) + : CC_CLOBBER_LIST("0")); + return CC_TRANSFORM(cc) == 0; +} + +static __always_inline void pfcr_query(u8 (*query)[16]) +{ + asm volatile( + " lghi 0,0\n" + " .insn rsy,0xeb0000000016,0,0,%[query]\n" + : [query] "=QS" (*query) + : : "cc", "0"); - return cc == 0; } static __always_inline void __sortl_query(u8 (*query)[32]) @@ -429,6 +439,9 @@ static void __init kvm_s390_cpu_feat_init(void) if (test_facility(151)) /* DFLTCC */ __dfltcc_query(&kvm_s390_available_subfunc.dfltcc); + if (test_facility(201)) /* PFCR */ + pfcr_query(&kvm_s390_available_subfunc.pfcr); + if (MACHINE_HAS_ESOP) allow_cpu_feat(KVM_S390_VM_CPU_FEAT_ESOP); /* @@ -799,6 +812,14 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) set_kvm_facility(kvm->arch.model.fac_mask, 192); set_kvm_facility(kvm->arch.model.fac_list, 192); } + if (test_facility(198)) { + set_kvm_facility(kvm->arch.model.fac_mask, 198); + set_kvm_facility(kvm->arch.model.fac_list, 198); + } + if (test_facility(199)) { + set_kvm_facility(kvm->arch.model.fac_mask, 199); + set_kvm_facility(kvm->arch.model.fac_list, 199); + } r = 0; } else r = -EINVAL; @@ -1543,6 +1564,9 @@ static int kvm_s390_set_processor_subfunc(struct kvm *kvm, ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[1], ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[2], ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[3]); + VM_EVENT(kvm, 3, "GET: guest PFCR subfunc 0x%16.16lx.%16.16lx", + ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[0], + ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[1]); return 0; } @@ -1757,6 +1781,9 @@ static int kvm_s390_get_processor_subfunc(struct kvm *kvm, ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[1], ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[2], ((unsigned long *) &kvm->arch.model.subfuncs.dfltcc)[3]); + VM_EVENT(kvm, 3, "GET: guest PFCR subfunc 0x%16.16lx.%16.16lx", + ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[0], + ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[1]); return 0; } @@ -1825,6 +1852,9 @@ static int kvm_s390_get_machine_subfunc(struct kvm *kvm, ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[1], ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[2], ((unsigned long *) &kvm_s390_available_subfunc.dfltcc)[3]); + VM_EVENT(kvm, 3, "GET: host PFCR subfunc 0x%16.16lx.%16.16lx", + ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[0], + ((unsigned long *) &kvm_s390_available_subfunc.pfcr)[1]); return 0; } @@ -1907,11 +1937,11 @@ static void kvm_s390_update_topology_change_report(struct kvm *kvm, bool val) read_lock(&kvm->arch.sca_lock); sca = kvm->arch.sca; + old = READ_ONCE(sca->utility); do { - old = READ_ONCE(sca->utility); new = old; new.mtcr = val; - } while (cmpxchg(&sca->utility.val, old.val, new.val) != old.val); + } while (!try_cmpxchg(&sca->utility.val, &old.val, new.val)); read_unlock(&kvm->arch.sca_lock); } @@ -3719,7 +3749,6 @@ __u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { - gmap_enable(vcpu->arch.enabled_gmap); kvm_s390_set_cpuflags(vcpu, CPUSTAT_RUNNING); if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu)) __start_cpu_timer_accounting(vcpu); @@ -3732,8 +3761,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) if (vcpu->arch.cputm_enabled && !is_vcpu_idle(vcpu)) __stop_cpu_timer_accounting(vcpu); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_RUNNING); - vcpu->arch.enabled_gmap = gmap_get_enabled(); - gmap_disable(vcpu->arch.enabled_gmap); } @@ -3751,8 +3778,6 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) } if (test_kvm_facility(vcpu->kvm, 74) || vcpu->kvm->arch.user_instr0) vcpu->arch.sie_block->ictl |= ICTL_OPEREXC; - /* make vcpu_load load the right gmap on the first trigger */ - vcpu->arch.enabled_gmap = vcpu->arch.gmap; } static bool kvm_has_pckmo_subfunc(struct kvm *kvm, unsigned long nr) @@ -3774,6 +3799,13 @@ static bool kvm_has_pckmo_ecc(struct kvm *kvm) } +static bool kvm_has_pckmo_hmac(struct kvm *kvm) +{ + /* At least one HMAC subfunction must be present */ + return kvm_has_pckmo_subfunc(kvm, 118) || + kvm_has_pckmo_subfunc(kvm, 122); +} + static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu) { /* @@ -3786,7 +3818,7 @@ static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu) vcpu->arch.sie_block->crycbd = vcpu->kvm->arch.crypto.crycbd; vcpu->arch.sie_block->ecb3 &= ~(ECB3_AES | ECB3_DEA); vcpu->arch.sie_block->eca &= ~ECA_APIE; - vcpu->arch.sie_block->ecd &= ~ECD_ECC; + vcpu->arch.sie_block->ecd &= ~(ECD_ECC | ECD_HMAC); if (vcpu->kvm->arch.crypto.apie) vcpu->arch.sie_block->eca |= ECA_APIE; @@ -3794,9 +3826,11 @@ static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu) /* Set up protected key support */ if (vcpu->kvm->arch.crypto.aes_kw) { vcpu->arch.sie_block->ecb3 |= ECB3_AES; - /* ecc is also wrapped with AES key */ + /* ecc/hmac is also wrapped with AES key */ if (kvm_has_pckmo_ecc(vcpu->kvm)) vcpu->arch.sie_block->ecd |= ECD_ECC; + if (kvm_has_pckmo_hmac(vcpu->kvm)) + vcpu->arch.sie_block->ecd |= ECD_HMAC; } if (vcpu->kvm->arch.crypto.dea_kw) @@ -4579,22 +4613,6 @@ int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clo return 1; } -/** - * kvm_arch_fault_in_page - fault-in guest page if necessary - * @vcpu: The corresponding virtual cpu - * @gpa: Guest physical address - * @writable: Whether the page should be writable or not - * - * Make sure that a guest page has been faulted-in on the host. - * - * Return: Zero on success, negative error code otherwise. - */ -long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable) -{ - return gmap_fault(vcpu->arch.gmap, gpa, - writable ? FAULT_FLAG_WRITE : 0); -} - static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token, unsigned long token) { @@ -4662,12 +4680,11 @@ static bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu) if (!vcpu->arch.gmap->pfault_enabled) return false; - hva = gfn_to_hva(vcpu->kvm, gpa_to_gfn(current->thread.gmap_addr)); - hva += current->thread.gmap_addr & ~PAGE_MASK; + hva = gfn_to_hva(vcpu->kvm, current->thread.gmap_teid.addr); if (read_guest_real(vcpu, vcpu->arch.pfault_token, &arch.pfault_token, 8)) return false; - return kvm_setup_async_pf(vcpu, current->thread.gmap_addr, hva, &arch); + return kvm_setup_async_pf(vcpu, current->thread.gmap_teid.addr * PAGE_SIZE, hva, &arch); } static int vcpu_pre_run(struct kvm_vcpu *vcpu) @@ -4705,6 +4722,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu) clear_bit(vcpu->vcpu_idx, vcpu->kvm->arch.gisa_int.kicked_mask); vcpu->arch.sie_block->icptcode = 0; + current->thread.gmap_int_code = 0; cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags); VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags); trace_kvm_s390_sie_enter(vcpu, cpuflags); @@ -4712,7 +4730,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu) return 0; } -static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu) +static int vcpu_post_run_addressing_exception(struct kvm_vcpu *vcpu) { struct kvm_s390_pgm_info pgm_info = { .code = PGM_ADDRESSING, @@ -4748,10 +4766,106 @@ static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu) return kvm_s390_inject_prog_irq(vcpu, &pgm_info); } +static int vcpu_post_run_handle_fault(struct kvm_vcpu *vcpu) +{ + unsigned int flags = 0; + unsigned long gaddr; + int rc = 0; + + gaddr = current->thread.gmap_teid.addr * PAGE_SIZE; + if (kvm_s390_cur_gmap_fault_is_write()) + flags = FAULT_FLAG_WRITE; + + switch (current->thread.gmap_int_code & PGM_INT_CODE_MASK) { + case 0: + vcpu->stat.exit_null++; + break; + case PGM_NON_SECURE_STORAGE_ACCESS: + KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm, + "Unexpected program interrupt 0x%x, TEID 0x%016lx", + current->thread.gmap_int_code, current->thread.gmap_teid.val); + /* + * This is normal operation; a page belonging to a protected + * guest has not been imported yet. Try to import the page into + * the protected guest. + */ + if (gmap_convert_to_secure(vcpu->arch.gmap, gaddr) == -EINVAL) + send_sig(SIGSEGV, current, 0); + break; + case PGM_SECURE_STORAGE_ACCESS: + case PGM_SECURE_STORAGE_VIOLATION: + KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm, + "Unexpected program interrupt 0x%x, TEID 0x%016lx", + current->thread.gmap_int_code, current->thread.gmap_teid.val); + /* + * This can happen after a reboot with asynchronous teardown; + * the new guest (normal or protected) will run on top of the + * previous protected guest. The old pages need to be destroyed + * so the new guest can use them. + */ + if (gmap_destroy_page(vcpu->arch.gmap, gaddr)) { + /* + * Either KVM messed up the secure guest mapping or the + * same page is mapped into multiple secure guests. + * + * This exception is only triggered when a guest 2 is + * running and can therefore never occur in kernel + * context. + */ + pr_warn_ratelimited("Secure storage violation (%x) in task: %s, pid %d\n", + current->thread.gmap_int_code, current->comm, + current->pid); + send_sig(SIGSEGV, current, 0); + } + break; + case PGM_PROTECTION: + case PGM_SEGMENT_TRANSLATION: + case PGM_PAGE_TRANSLATION: + case PGM_ASCE_TYPE: + case PGM_REGION_FIRST_TRANS: + case PGM_REGION_SECOND_TRANS: + case PGM_REGION_THIRD_TRANS: + KVM_BUG(current->thread.gmap_teid.as != PSW_BITS_AS_PRIMARY, vcpu->kvm, + "Unexpected program interrupt 0x%x, TEID 0x%016lx", + current->thread.gmap_int_code, current->thread.gmap_teid.val); + if (vcpu->arch.gmap->pfault_enabled) { + rc = gmap_fault(vcpu->arch.gmap, gaddr, flags | FAULT_FLAG_RETRY_NOWAIT); + if (rc == -EFAULT) + return vcpu_post_run_addressing_exception(vcpu); + if (rc == -EAGAIN) { + trace_kvm_s390_major_guest_pfault(vcpu); + if (kvm_arch_setup_async_pf(vcpu)) + return 0; + vcpu->stat.pfault_sync++; + } else { + return rc; + } + } + rc = gmap_fault(vcpu->arch.gmap, gaddr, flags); + if (rc == -EFAULT) { + if (kvm_is_ucontrol(vcpu->kvm)) { + vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL; + vcpu->run->s390_ucontrol.trans_exc_code = gaddr; + vcpu->run->s390_ucontrol.pgm_code = 0x10; + return -EREMOTE; + } + return vcpu_post_run_addressing_exception(vcpu); + } + break; + default: + KVM_BUG(1, vcpu->kvm, "Unexpected program interrupt 0x%x, TEID 0x%016lx", + current->thread.gmap_int_code, current->thread.gmap_teid.val); + send_sig(SIGSEGV, current, 0); + break; + } + return rc; +} + static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) { struct mcck_volatile_info *mcck_info; struct sie_page *sie_page; + int rc; VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", vcpu->arch.sie_block->icptcode); @@ -4773,7 +4887,7 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) } if (vcpu->arch.sie_block->icptcode > 0) { - int rc = kvm_handle_sie_intercept(vcpu); + rc = kvm_handle_sie_intercept(vcpu); if (rc != -EOPNOTSUPP) return rc; @@ -4782,24 +4896,9 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) vcpu->run->s390_sieic.ipa = vcpu->arch.sie_block->ipa; vcpu->run->s390_sieic.ipb = vcpu->arch.sie_block->ipb; return -EREMOTE; - } else if (exit_reason != -EFAULT) { - vcpu->stat.exit_null++; - return 0; - } else if (kvm_is_ucontrol(vcpu->kvm)) { - vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL; - vcpu->run->s390_ucontrol.trans_exc_code = - current->thread.gmap_addr; - vcpu->run->s390_ucontrol.pgm_code = 0x10; - return -EREMOTE; - } else if (current->thread.gmap_pfault) { - trace_kvm_s390_major_guest_pfault(vcpu); - current->thread.gmap_pfault = 0; - if (kvm_arch_setup_async_pf(vcpu)) - return 0; - vcpu->stat.pfault_sync++; - return kvm_arch_fault_in_page(vcpu, current->thread.gmap_addr, 1); } - return vcpu_post_run_fault_in_sie(vcpu); + + return vcpu_post_run_handle_fault(vcpu); } #define PSW_INT_MASK (PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_MCHECK) @@ -4835,7 +4934,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) } exit_reason = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs, - gmap_get_enabled()->asce); + vcpu->arch.gmap->asce); if (kvm_s390_pv_cpu_is_protected(vcpu)) { memcpy(vcpu->run->s.regs.gprs, sie_page->pv_grregs, diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index e680c6bf0c9d94..597d7a71deebe0 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -394,7 +394,6 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu); /* implemented in kvm-s390.c */ int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod); -long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable); int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr); int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr); int kvm_s390_vcpu_start(struct kvm_vcpu *vcpu); @@ -529,6 +528,13 @@ static inline int kvm_s390_use_sca_entries(void) void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu, struct mcck_volatile_info *mcck_info); +static inline bool kvm_s390_cur_gmap_fault_is_write(void) +{ + if (current->thread.gmap_int_code == PGM_PROTECTION) + return true; + return test_facility(75) && (current->thread.gmap_teid.fsi == TEID_FSI_STORE); +} + /** * kvm_s390_vcpu_crypto_reset_all * diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c index ffa7739c7a284d..9b9e7fdd538078 100644 --- a/arch/s390/kvm/pci.c +++ b/arch/s390/kvm/pci.c @@ -103,7 +103,7 @@ static int zpci_reset_aipb(u8 nisc) /* * AEN registration can only happen once per system boot. If * an aipb already exists then AEN was already registered and - * we can re-use the aipb contents. This can only happen if + * we can reuse the aipb contents. This can only happen if * the KVM module was removed and re-inserted. However, we must * ensure that the same forwarding ISC is used as this is assigned * during KVM module load. @@ -208,13 +208,12 @@ static inline int account_mem(unsigned long nr_pages) page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; + cur_pages = atomic_long_read(&user->locked_vm); do { - cur_pages = atomic_long_read(&user->locked_vm); new_pages = cur_pages + nr_pages; if (new_pages > page_limit) return -ENOMEM; - } while (atomic_long_cmpxchg(&user->locked_vm, cur_pages, - new_pages) != cur_pages); + } while (!atomic_long_try_cmpxchg(&user->locked_vm, &cur_pages, new_pages)); atomic64_add(nr_pages, ¤t->mm->pinned_vm); diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 89cafea4c41f26..150b9387860ad2 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -335,7 +335,8 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) /* we may only allow it if enabled for guest 2 */ ecb3_flags = scb_o->ecb3 & vcpu->arch.sie_block->ecb3 & (ECB3_AES | ECB3_DEA); - ecd_flags = scb_o->ecd & vcpu->arch.sie_block->ecd & ECD_ECC; + ecd_flags = scb_o->ecd & vcpu->arch.sie_block->ecd & + (ECD_ECC | ECD_HMAC); if (!ecb3_flags && !ecd_flags) goto end; @@ -661,7 +662,7 @@ static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa) struct page *page; page = gfn_to_page(kvm, gpa_to_gfn(gpa)); - if (is_error_page(page)) + if (!page) return -EINVAL; *hpa = (hpa_t)page_to_phys(page) + (gpa & ~PAGE_MASK); return 0; @@ -670,7 +671,7 @@ static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa) /* Unpins a page previously pinned via pin_guest_page, marking it as dirty. */ static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa) { - kvm_release_pfn_dirty(hpa >> PAGE_SHIFT); + kvm_release_page_dirty(pfn_to_page(hpa >> PAGE_SHIFT)); /* mark the page always as dirty for migration */ mark_page_dirty(kvm, gpa_to_gfn(gpa)); } @@ -922,19 +923,19 @@ static int handle_fault(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { int rc; - if (current->thread.gmap_int_code == PGM_PROTECTION) + if ((current->thread.gmap_int_code & PGM_INT_CODE_MASK) == PGM_PROTECTION) /* we can directly forward all protection exceptions */ return inject_fault(vcpu, PGM_PROTECTION, - current->thread.gmap_addr, 1); + current->thread.gmap_teid.addr * PAGE_SIZE, 1); rc = kvm_s390_shadow_fault(vcpu, vsie_page->gmap, - current->thread.gmap_addr, NULL); + current->thread.gmap_teid.addr * PAGE_SIZE, NULL); if (rc > 0) { rc = inject_fault(vcpu, rc, - current->thread.gmap_addr, - current->thread.gmap_write_flag); + current->thread.gmap_teid.addr * PAGE_SIZE, + kvm_s390_cur_gmap_fault_is_write()); if (rc >= 0) - vsie_page->fault_addr = current->thread.gmap_addr; + vsie_page->fault_addr = current->thread.gmap_teid.addr * PAGE_SIZE; } return rc; } @@ -1148,9 +1149,10 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) * also kick the vSIE. */ vcpu->arch.sie_block->prog0c |= PROG_IN_SIE; + current->thread.gmap_int_code = 0; barrier(); if (!kvm_s390_vcpu_sie_inhibited(vcpu)) - rc = sie64a(scb_s, vcpu->run->s.regs.gprs, gmap_get_enabled()->asce); + rc = sie64a(scb_s, vcpu->run->s.regs.gprs, vsie_page->gmap->asce); barrier(); vcpu->arch.sie_block->prog0c &= ~PROG_IN_SIE; @@ -1172,7 +1174,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) if (rc > 0) rc = 0; /* we could still have an icpt */ - else if (rc == -EFAULT) + else if (current->thread.gmap_int_code) return handle_fault(vcpu, vsie_page); switch (scb_s->icptcode) { @@ -1295,10 +1297,8 @@ static int vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) if (!rc) rc = map_prefix(vcpu, vsie_page); if (!rc) { - gmap_enable(vsie_page->gmap); update_intervention_requests(vsie_page); rc = do_vsie_run(vcpu, vsie_page); - gmap_enable(vcpu->arch.gmap); } atomic_andnot(PROG_BLOCK_SIE, &scb_s->prog20); diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index 9f86ad8fa8b4dc..a81a01c449272e 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -15,6 +15,7 @@ #include #include #include +#include int spin_retry = -1; @@ -76,24 +77,43 @@ static inline int arch_load_niai4(int *lock) asm_inline volatile( ALTERNATIVE("nop", ".insn rre,0xb2fa0000,4,0", ALT_FACILITY(49)) /* NIAI 4 */ - " l %0,%1\n" - : "=d" (owner) : "Q" (*lock) : "memory"); + " l %[owner],%[lock]\n" + : [owner] "=d" (owner) : [lock] "R" (*lock) : "memory"); return owner; } -static inline int arch_cmpxchg_niai8(int *lock, int old, int new) +#ifdef __HAVE_ASM_FLAG_OUTPUTS__ + +static inline int arch_try_cmpxchg_niai8(int *lock, int old, int new) +{ + int cc; + + asm_inline volatile( + ALTERNATIVE("nop", ".insn rre,0xb2fa0000,8,0", ALT_FACILITY(49)) /* NIAI 8 */ + " cs %[old],%[new],%[lock]\n" + : [old] "+d" (old), [lock] "+Q" (*lock), "=@cc" (cc) + : [new] "d" (new) + : "memory"); + return cc == 0; +} + +#else /* __HAVE_ASM_FLAG_OUTPUTS__ */ + +static inline int arch_try_cmpxchg_niai8(int *lock, int old, int new) { int expected = old; asm_inline volatile( ALTERNATIVE("nop", ".insn rre,0xb2fa0000,8,0", ALT_FACILITY(49)) /* NIAI 8 */ - " cs %0,%3,%1\n" - : "=d" (old), "=Q" (*lock) - : "0" (old), "d" (new), "Q" (*lock) + " cs %[old],%[new],%[lock]\n" + : [old] "+d" (old), [lock] "+Q" (*lock) + : [new] "d" (new) : "cc", "memory"); return expected == old; } +#endif /* __HAVE_ASM_FLAG_OUTPUTS__ */ + static inline struct spin_wait *arch_spin_decode_tail(int lock) { int ix, cpu; @@ -127,8 +147,8 @@ static inline void arch_spin_lock_queued(arch_spinlock_t *lp) node_id = node->node_id; /* Enqueue the node for this CPU in the spinlock wait queue */ + old = READ_ONCE(lp->lock); while (1) { - old = READ_ONCE(lp->lock); if ((old & _Q_LOCK_CPU_MASK) == 0 && (old & _Q_LOCK_STEAL_MASK) != _Q_LOCK_STEAL_MASK) { /* @@ -139,7 +159,7 @@ static inline void arch_spin_lock_queued(arch_spinlock_t *lp) * waiter will get the lock. */ new = (old ? (old + _Q_LOCK_STEAL_ADD) : 0) | lockval; - if (__atomic_cmpxchg_bool(&lp->lock, old, new)) + if (arch_try_cmpxchg(&lp->lock, &old, new)) /* Got the lock */ goto out; /* lock passing in progress */ @@ -147,7 +167,7 @@ static inline void arch_spin_lock_queued(arch_spinlock_t *lp) } /* Make the node of this CPU the new tail. */ new = node_id | (old & _Q_LOCK_MASK); - if (__atomic_cmpxchg_bool(&lp->lock, old, new)) + if (arch_try_cmpxchg(&lp->lock, &old, new)) break; } /* Set the 'next' pointer of the tail node in the queue */ @@ -184,7 +204,7 @@ static inline void arch_spin_lock_queued(arch_spinlock_t *lp) if (!owner) { tail_id = old & _Q_TAIL_MASK; new = ((tail_id != node_id) ? tail_id : 0) | lockval; - if (__atomic_cmpxchg_bool(&lp->lock, old, new)) + if (arch_try_cmpxchg(&lp->lock, &old, new)) /* Got the lock */ break; continue; @@ -226,7 +246,7 @@ static inline void arch_spin_lock_classic(arch_spinlock_t *lp) /* Try to get the lock if it is free. */ if (!owner) { new = (old & _Q_TAIL_MASK) | lockval; - if (arch_cmpxchg_niai8(&lp->lock, old, new)) { + if (arch_try_cmpxchg_niai8(&lp->lock, old, new)) { /* Got the lock */ return; } @@ -258,7 +278,7 @@ int arch_spin_trylock_retry(arch_spinlock_t *lp) owner = READ_ONCE(lp->lock); /* Try to get the lock if it is free. */ if (!owner) { - if (__atomic_cmpxchg_bool(&lp->lock, 0, cpu)) + if (arch_try_cmpxchg(&lp->lock, &owner, cpu)) return 1; } } @@ -300,7 +320,7 @@ void arch_write_lock_wait(arch_rwlock_t *rw) while (1) { old = READ_ONCE(rw->cnts); if ((old & 0x1ffff) == 0 && - __atomic_cmpxchg_bool(&rw->cnts, old, old | 0x10000)) + arch_try_cmpxchg(&rw->cnts, &old, old | 0x10000)) /* Got the lock */ break; barrier(); diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c index 7d87418182397a..373fa1f019376d 100644 --- a/arch/s390/lib/string.c +++ b/arch/s390/lib/string.c @@ -15,6 +15,7 @@ #include #include #include +#include /* * Helper functions to find the end of a string @@ -238,12 +239,11 @@ static inline int clcle(const char *s1, unsigned long l1, asm volatile( "0: clcle %[r1],%[r3],0\n" " jo 0b\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (cc), [r1] "+&d" (r1.pair), [r3] "+&d" (r3.pair) + CC_IPM(cc) + : CC_OUT(cc, cc), [r1] "+d" (r1.pair), [r3] "+d" (r3.pair) : - : "cc", "memory"); - return cc; + : CC_CLOBBER_LIST("memory")); + return CC_TRANSFORM(cc); } /** diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c index 8b7f981e6f3477..6e42100875e75b 100644 --- a/arch/s390/lib/test_unwind.c +++ b/arch/s390/lib/test_unwind.c @@ -270,9 +270,9 @@ static void notrace __used test_unwind_ftrace_handler(unsigned long ip, struct ftrace_ops *fops, struct ftrace_regs *fregs) { - struct unwindme *u = (struct unwindme *)fregs->regs.gprs[2]; + struct unwindme *u = (struct unwindme *)arch_ftrace_regs(fregs)->regs.gprs[2]; - u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? &fregs->regs : NULL, + u->ret = test_unwind(NULL, (u->flags & UWM_REGS) ? &arch_ftrace_regs(fregs)->regs : NULL, (u->flags & UWM_SP) ? u->sp : 0); } diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 282fefe107a246..4692136c0af137 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -28,6 +28,7 @@ #include #include #include +#include #define DCSS_PURGESEG 0x08 #define DCSS_LOADSHRX 0x20 @@ -134,20 +135,21 @@ dcss_diag(int *func, void *parameter, unsigned long *ret1, unsigned long *ret2) { unsigned long rx, ry; - int rc; + int cc; rx = virt_to_phys(parameter); ry = (unsigned long) *func; diag_stat_inc(DIAG_STAT_X064); asm volatile( - " diag %0,%1,0x64\n" - " ipm %2\n" - " srl %2,28\n" - : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); + " diag %[rx],%[ry],0x64\n" + CC_IPM(cc) + : CC_OUT(cc, cc), [rx] "+d" (rx), [ry] "+d" (ry) + : + : CC_CLOBBER); *ret1 = rx; *ret2 = ry; - return rc; + return CC_TRANSFORM(cc); } static inline int diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index ad8b0d6b77ea16..9b681f74dccc1f 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -46,12 +46,6 @@ #include #include "../kernel/entry.h" -enum fault_type { - KERNEL_FAULT, - USER_FAULT, - GMAP_FAULT, -}; - static DEFINE_STATIC_KEY_FALSE(have_store_indication); static int __init fault_init(void) @@ -65,28 +59,15 @@ early_initcall(fault_init); /* * Find out which address space caused the exception. */ -static enum fault_type get_fault_type(struct pt_regs *regs) +static bool is_kernel_fault(struct pt_regs *regs) { union teid teid = { .val = regs->int_parm_long }; - struct gmap *gmap; - if (likely(teid.as == PSW_BITS_AS_PRIMARY)) { - if (user_mode(regs)) - return USER_FAULT; - if (!IS_ENABLED(CONFIG_PGSTE)) - return KERNEL_FAULT; - gmap = (struct gmap *)get_lowcore()->gmap; - if (gmap && gmap->asce == regs->cr1) - return GMAP_FAULT; - return KERNEL_FAULT; - } + if (user_mode(regs)) + return false; if (teid.as == PSW_BITS_AS_SECONDARY) - return USER_FAULT; - /* Access register mode, not used in the kernel */ - if (teid.as == PSW_BITS_AS_ACCREG) - return USER_FAULT; - /* Home space -> access via kernel ASCE */ - return KERNEL_FAULT; + return false; + return true; } static unsigned long get_fault_address(struct pt_regs *regs) @@ -147,7 +128,7 @@ static void dump_pagetable(unsigned long asce, unsigned long address) goto out; table = __va(entry & _SEGMENT_ENTRY_ORIGIN); } - table += (address & _PAGE_INDEX) >> _PAGE_SHIFT; + table += (address & _PAGE_INDEX) >> PAGE_SHIFT; if (get_kernel_nofault(entry, table)) goto bad; pr_cont("P:%016lx ", entry); @@ -181,21 +162,12 @@ static void dump_fault_info(struct pt_regs *regs) break; } pr_cont("mode while using "); - switch (get_fault_type(regs)) { - case USER_FAULT: - asce = get_lowcore()->user_asce.val; - pr_cont("user "); - break; - case GMAP_FAULT: - asce = ((struct gmap *)get_lowcore()->gmap)->asce; - pr_cont("gmap "); - break; - case KERNEL_FAULT: + if (is_kernel_fault(regs)) { asce = get_lowcore()->kernel_asce.val; pr_cont("kernel "); - break; - default: - unreachable(); + } else { + asce = get_lowcore()->user_asce.val; + pr_cont("user "); } pr_cont("ASCE.\n"); dump_pagetable(asce, get_fault_address(regs)); @@ -230,7 +202,6 @@ static void do_sigsegv(struct pt_regs *regs, int si_code) static void handle_fault_error_nolock(struct pt_regs *regs, int si_code) { - enum fault_type fault_type; unsigned long address; bool is_write; @@ -241,17 +212,15 @@ static void handle_fault_error_nolock(struct pt_regs *regs, int si_code) } if (fixup_exception(regs)) return; - fault_type = get_fault_type(regs); - if (fault_type == KERNEL_FAULT) { + if (is_kernel_fault(regs)) { address = get_fault_address(regs); is_write = fault_is_write(regs); if (kfence_handle_page_fault(address, is_write, regs)) return; - } - if (fault_type == KERNEL_FAULT) pr_alert("Unable to handle kernel pointer dereference in virtual kernel address space\n"); - else + } else { pr_alert("Unable to handle kernel paging request in virtual user address space\n"); + } dump_fault_info(regs); die(regs, "Oops"); } @@ -285,9 +254,7 @@ static void do_exception(struct pt_regs *regs, int access) struct vm_area_struct *vma; unsigned long address; struct mm_struct *mm; - enum fault_type type; unsigned int flags; - struct gmap *gmap; vm_fault_t fault; bool is_write; @@ -301,16 +268,8 @@ static void do_exception(struct pt_regs *regs, int access) mm = current->mm; address = get_fault_address(regs); is_write = fault_is_write(regs); - type = get_fault_type(regs); - switch (type) { - case KERNEL_FAULT: + if (is_kernel_fault(regs) || faulthandler_disabled() || !mm) return handle_fault_error_nolock(regs, 0); - case USER_FAULT: - case GMAP_FAULT: - if (faulthandler_disabled() || !mm) - return handle_fault_error_nolock(regs, 0); - break; - } perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); flags = FAULT_FLAG_DEFAULT; if (user_mode(regs)) @@ -334,14 +293,11 @@ static void do_exception(struct pt_regs *regs, int access) vma_end_read(vma); if (!(fault & VM_FAULT_RETRY)) { count_vm_vma_lock_event(VMA_LOCK_SUCCESS); - if (unlikely(fault & VM_FAULT_ERROR)) - goto error; - return; + goto done; } count_vm_vma_lock_event(VMA_LOCK_RETRY); if (fault & VM_FAULT_MAJOR) flags |= FAULT_FLAG_TRIED; - /* Quick path to respond to signals */ if (fault_signal_pending(fault, regs)) { if (!user_mode(regs)) @@ -349,81 +305,29 @@ static void do_exception(struct pt_regs *regs, int access) return; } lock_mmap: - mmap_read_lock(mm); - gmap = NULL; - if (IS_ENABLED(CONFIG_PGSTE) && type == GMAP_FAULT) { - gmap = (struct gmap *)get_lowcore()->gmap; - current->thread.gmap_addr = address; - current->thread.gmap_write_flag = !!(flags & FAULT_FLAG_WRITE); - current->thread.gmap_int_code = regs->int_code & 0xffff; - address = __gmap_translate(gmap, address); - if (address == -EFAULT) - return handle_fault_error(regs, SEGV_MAPERR); - if (gmap->pfault_enabled) - flags |= FAULT_FLAG_RETRY_NOWAIT; - } retry: - vma = find_vma(mm, address); + vma = lock_mm_and_find_vma(mm, address, regs); if (!vma) - return handle_fault_error(regs, SEGV_MAPERR); - if (unlikely(vma->vm_start > address)) { - if (!(vma->vm_flags & VM_GROWSDOWN)) - return handle_fault_error(regs, SEGV_MAPERR); - vma = expand_stack(mm, address); - if (!vma) - return handle_fault_error_nolock(regs, SEGV_MAPERR); - } + return handle_fault_error_nolock(regs, SEGV_MAPERR); if (unlikely(!(vma->vm_flags & access))) return handle_fault_error(regs, SEGV_ACCERR); fault = handle_mm_fault(vma, address, flags, regs); if (fault_signal_pending(fault, regs)) { - if (flags & FAULT_FLAG_RETRY_NOWAIT) - mmap_read_unlock(mm); if (!user_mode(regs)) handle_fault_error_nolock(regs, 0); return; } /* The fault is fully completed (including releasing mmap lock) */ - if (fault & VM_FAULT_COMPLETED) { - if (gmap) { - mmap_read_lock(mm); - goto gmap; - } + if (fault & VM_FAULT_COMPLETED) return; - } - if (unlikely(fault & VM_FAULT_ERROR)) { - mmap_read_unlock(mm); - goto error; - } if (fault & VM_FAULT_RETRY) { - if (IS_ENABLED(CONFIG_PGSTE) && gmap && (flags & FAULT_FLAG_RETRY_NOWAIT)) { - /* - * FAULT_FLAG_RETRY_NOWAIT has been set, - * mmap_lock has not been released - */ - current->thread.gmap_pfault = 1; - return handle_fault_error(regs, 0); - } - flags &= ~FAULT_FLAG_RETRY_NOWAIT; flags |= FAULT_FLAG_TRIED; - mmap_read_lock(mm); goto retry; } -gmap: - if (IS_ENABLED(CONFIG_PGSTE) && gmap) { - address = __gmap_link(gmap, current->thread.gmap_addr, - address); - if (address == -EFAULT) - return handle_fault_error(regs, SEGV_MAPERR); - if (address == -ENOMEM) { - fault = VM_FAULT_OOM; - mmap_read_unlock(mm); - goto error; - } - } mmap_read_unlock(mm); - return; -error: +done: + if (!(fault & VM_FAULT_ERROR)) + return; if (fault & VM_FAULT_OOM) { if (!user_mode(regs)) handle_fault_error_nolock(regs, 0); @@ -434,7 +338,8 @@ static void do_exception(struct pt_regs *regs, int access) handle_fault_error_nolock(regs, 0); else do_sigsegv(regs, SEGV_MAPERR); - } else if (fault & (VM_FAULT_SIGBUS | VM_FAULT_HWPOISON)) { + } else if (fault & (VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | + VM_FAULT_HWPOISON_LARGE)) { if (!user_mode(regs)) handle_fault_error_nolock(regs, 0); else @@ -496,7 +401,6 @@ void do_secure_storage_access(struct pt_regs *regs) struct folio_walk fw; struct mm_struct *mm; struct folio *folio; - struct gmap *gmap; int rc; /* @@ -521,17 +425,15 @@ void do_secure_storage_access(struct pt_regs *regs) */ panic("Unexpected PGM 0x3d with TEID bit 61=0"); } - switch (get_fault_type(regs)) { - case GMAP_FAULT: - mm = current->mm; - gmap = (struct gmap *)get_lowcore()->gmap; - mmap_read_lock(mm); - addr = __gmap_translate(gmap, addr); - mmap_read_unlock(mm); - if (IS_ERR_VALUE(addr)) - return handle_fault_error_nolock(regs, SEGV_MAPERR); - fallthrough; - case USER_FAULT: + if (is_kernel_fault(regs)) { + folio = phys_to_folio(addr); + if (unlikely(!folio_try_get(folio))) + return; + rc = arch_make_folio_accessible(folio); + folio_put(folio); + if (rc) + BUG(); + } else { mm = current->mm; mmap_read_lock(mm); vma = find_vma(mm, addr); @@ -540,7 +442,7 @@ void do_secure_storage_access(struct pt_regs *regs) folio = folio_walk_start(&fw, vma, addr, 0); if (!folio) { mmap_read_unlock(mm); - break; + return; } /* arch_make_folio_accessible() needs a raised refcount. */ folio_get(folio); @@ -550,56 +452,8 @@ void do_secure_storage_access(struct pt_regs *regs) if (rc) send_sig(SIGSEGV, current, 0); mmap_read_unlock(mm); - break; - case KERNEL_FAULT: - folio = phys_to_folio(addr); - if (unlikely(!folio_try_get(folio))) - break; - rc = arch_make_folio_accessible(folio); - folio_put(folio); - if (rc) - BUG(); - break; - default: - unreachable(); } } NOKPROBE_SYMBOL(do_secure_storage_access); -void do_non_secure_storage_access(struct pt_regs *regs) -{ - struct gmap *gmap = (struct gmap *)get_lowcore()->gmap; - unsigned long gaddr = get_fault_address(regs); - - if (WARN_ON_ONCE(get_fault_type(regs) != GMAP_FAULT)) - return handle_fault_error_nolock(regs, SEGV_MAPERR); - if (gmap_convert_to_secure(gmap, gaddr) == -EINVAL) - send_sig(SIGSEGV, current, 0); -} -NOKPROBE_SYMBOL(do_non_secure_storage_access); - -void do_secure_storage_violation(struct pt_regs *regs) -{ - struct gmap *gmap = (struct gmap *)get_lowcore()->gmap; - unsigned long gaddr = get_fault_address(regs); - - /* - * If the VM has been rebooted, its address space might still contain - * secure pages from the previous boot. - * Clear the page so it can be reused. - */ - if (!gmap_destroy_page(gmap, gaddr)) - return; - /* - * Either KVM messed up the secure guest mapping or the same - * page is mapped into multiple secure guests. - * - * This exception is only triggered when a guest 2 is running - * and can therefore never occur in kernel context. - */ - pr_warn_ratelimited("Secure storage violation in task: %s, pid %d\n", - current->comm, current->pid); - send_sig(SIGSEGV, current, 0); -} - #endif /* CONFIG_PGSTE */ diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index eb0b51a36be013..16b8a36c56de11 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -281,37 +281,6 @@ void gmap_remove(struct gmap *gmap) } EXPORT_SYMBOL_GPL(gmap_remove); -/** - * gmap_enable - switch primary space to the guest address space - * @gmap: pointer to the guest address space structure - */ -void gmap_enable(struct gmap *gmap) -{ - get_lowcore()->gmap = (unsigned long)gmap; -} -EXPORT_SYMBOL_GPL(gmap_enable); - -/** - * gmap_disable - switch back to the standard primary address space - * @gmap: pointer to the guest address space structure - */ -void gmap_disable(struct gmap *gmap) -{ - get_lowcore()->gmap = 0UL; -} -EXPORT_SYMBOL_GPL(gmap_disable); - -/** - * gmap_get_enabled - get a pointer to the currently enabled gmap - * - * Returns a pointer to the currently enabled gmap. 0 if none is enabled. - */ -struct gmap *gmap_get_enabled(void) -{ - return (struct gmap *)get_lowcore()->gmap; -} -EXPORT_SYMBOL_GPL(gmap_get_enabled); - /* * gmap_alloc_table is assumed to be called with mmap_lock held */ @@ -618,7 +587,8 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) if (pmd_leaf(*pmd)) { *table = (pmd_val(*pmd) & _SEGMENT_ENTRY_HARDWARE_BITS_LARGE) - | _SEGMENT_ENTRY_GMAP_UC; + | _SEGMENT_ENTRY_GMAP_UC + | _SEGMENT_ENTRY; } else *table = pmd_val(*pmd) & _SEGMENT_ENTRY_HARDWARE_BITS; @@ -637,44 +607,124 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) } /** - * gmap_fault - resolve a fault on a guest address + * fixup_user_fault_nowait - manually resolve a user page fault without waiting + * @mm: mm_struct of target mm + * @address: user address + * @fault_flags:flags to pass down to handle_mm_fault() + * @unlocked: did we unlock the mmap_lock while retrying + * + * This function behaves similarly to fixup_user_fault(), but it guarantees + * that the fault will be resolved without waiting. The function might drop + * and re-acquire the mm lock, in which case @unlocked will be set to true. + * + * The guarantee is that the fault is handled without waiting, but the + * function itself might sleep, due to the lock. + * + * Context: Needs to be called with mm->mmap_lock held in read mode, and will + * return with the lock held in read mode; @unlocked will indicate whether + * the lock has been dropped and re-acquired. This is the same behaviour as + * fixup_user_fault(). + * + * Return: 0 on success, -EAGAIN if the fault cannot be resolved without + * waiting, -EFAULT if the fault cannot be resolved, -ENOMEM if out of + * memory. + */ +static int fixup_user_fault_nowait(struct mm_struct *mm, unsigned long address, + unsigned int fault_flags, bool *unlocked) +{ + struct vm_area_struct *vma; + unsigned int test_flags; + vm_fault_t fault; + int rc; + + fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT; + test_flags = fault_flags & FAULT_FLAG_WRITE ? VM_WRITE : VM_READ; + + vma = find_vma(mm, address); + if (unlikely(!vma || address < vma->vm_start)) + return -EFAULT; + if (unlikely(!(vma->vm_flags & test_flags))) + return -EFAULT; + + fault = handle_mm_fault(vma, address, fault_flags, NULL); + /* the mm lock has been dropped, take it again */ + if (fault & VM_FAULT_COMPLETED) { + *unlocked = true; + mmap_read_lock(mm); + return 0; + } + /* the mm lock has not been dropped */ + if (fault & VM_FAULT_ERROR) { + rc = vm_fault_to_errno(fault, 0); + BUG_ON(!rc); + return rc; + } + /* the mm lock has not been dropped because of FAULT_FLAG_RETRY_NOWAIT */ + if (fault & VM_FAULT_RETRY) + return -EAGAIN; + /* nothing needed to be done and the mm lock has not been dropped */ + return 0; +} + +/** + * __gmap_fault - resolve a fault on a guest address * @gmap: pointer to guest mapping meta data structure * @gaddr: guest address * @fault_flags: flags to pass down to handle_mm_fault() * - * Returns 0 on success, -ENOMEM for out of memory conditions, and -EFAULT - * if the vm address is already mapped to a different guest segment. + * Context: Needs to be called with mm->mmap_lock held in read mode. Might + * drop and re-acquire the lock. Will always return with the lock held. */ -int gmap_fault(struct gmap *gmap, unsigned long gaddr, - unsigned int fault_flags) +static int __gmap_fault(struct gmap *gmap, unsigned long gaddr, unsigned int fault_flags) { unsigned long vmaddr; - int rc; bool unlocked; - - mmap_read_lock(gmap->mm); + int rc = 0; retry: unlocked = false; + vmaddr = __gmap_translate(gmap, gaddr); - if (IS_ERR_VALUE(vmaddr)) { - rc = vmaddr; - goto out_up; - } - if (fixup_user_fault(gmap->mm, vmaddr, fault_flags, - &unlocked)) { - rc = -EFAULT; - goto out_up; - } + if (IS_ERR_VALUE(vmaddr)) + return vmaddr; + + if (fault_flags & FAULT_FLAG_RETRY_NOWAIT) + rc = fixup_user_fault_nowait(gmap->mm, vmaddr, fault_flags, &unlocked); + else + rc = fixup_user_fault(gmap->mm, vmaddr, fault_flags, &unlocked); + if (rc) + return rc; /* * In the case that fixup_user_fault unlocked the mmap_lock during - * faultin redo __gmap_translate to not race with a map/unmap_segment. + * fault-in, redo __gmap_translate() to avoid racing with a + * map/unmap_segment. + * In particular, __gmap_translate(), fixup_user_fault{,_nowait}(), + * and __gmap_link() must all be called atomically in one go; if the + * lock had been dropped in between, a retry is needed. */ if (unlocked) goto retry; - rc = __gmap_link(gmap, gaddr, vmaddr); -out_up: + return __gmap_link(gmap, gaddr, vmaddr); +} + +/** + * gmap_fault - resolve a fault on a guest address + * @gmap: pointer to guest mapping meta data structure + * @gaddr: guest address + * @fault_flags: flags to pass down to handle_mm_fault() + * + * Returns 0 on success, -ENOMEM for out of memory conditions, -EFAULT if the + * vm address is already mapped to a different guest segment, and -EAGAIN if + * FAULT_FLAG_RETRY_NOWAIT was specified and the fault could not be processed + * immediately. + */ +int gmap_fault(struct gmap *gmap, unsigned long gaddr, unsigned int fault_flags) +{ + int rc; + + mmap_read_lock(gmap->mm); + rc = __gmap_fault(gmap, gaddr, fault_flags); mmap_read_unlock(gmap->mm); return rc; } @@ -851,7 +901,7 @@ static inline unsigned long *gmap_table_walk(struct gmap *gmap, if (*table & _REGION_ENTRY_INVALID) return NULL; table = __va(*table & _SEGMENT_ENTRY_ORIGIN); - table += (gaddr & _PAGE_INDEX) >> _PAGE_SHIFT; + table += (gaddr & _PAGE_INDEX) >> PAGE_SHIFT; } return table; } @@ -1317,7 +1367,7 @@ static void gmap_unshadow_page(struct gmap *sg, unsigned long raddr) table = gmap_table_walk(sg, raddr, 0); /* get page table pointer */ if (!table || *table & _PAGE_INVALID) return; - gmap_call_notifier(sg, raddr, raddr + _PAGE_SIZE - 1); + gmap_call_notifier(sg, raddr, raddr + PAGE_SIZE - 1); ptep_unshadow_pte(sg->mm, raddr, (pte_t *) table); } @@ -1335,7 +1385,7 @@ static void __gmap_unshadow_pgt(struct gmap *sg, unsigned long raddr, int i; BUG_ON(!gmap_is_shadow(sg)); - for (i = 0; i < _PAGE_ENTRIES; i++, raddr += _PAGE_SIZE) + for (i = 0; i < _PAGE_ENTRIES; i++, raddr += PAGE_SIZE) pgt[i] = _PAGE_INVALID; } @@ -2347,7 +2397,8 @@ static void gmap_pmdp_clear(struct mm_struct *mm, unsigned long vmaddr, gaddr = __gmap_segment_gaddr((unsigned long *)pmdp); pmdp_notify_gmap(gmap, pmdp, gaddr); WARN_ON(pmd_val(*pmdp) & ~(_SEGMENT_ENTRY_HARDWARE_BITS_LARGE | - _SEGMENT_ENTRY_GMAP_UC)); + _SEGMENT_ENTRY_GMAP_UC | + _SEGMENT_ENTRY)); if (purge) __pmdp_csp(pmdp); set_pmd(pmdp, __pmd(_SEGMENT_ENTRY_EMPTY)); @@ -2401,7 +2452,8 @@ void gmap_pmdp_idte_local(struct mm_struct *mm, unsigned long vmaddr) gaddr = __gmap_segment_gaddr(entry); pmdp_notify_gmap(gmap, pmdp, gaddr); WARN_ON(*entry & ~(_SEGMENT_ENTRY_HARDWARE_BITS_LARGE | - _SEGMENT_ENTRY_GMAP_UC)); + _SEGMENT_ENTRY_GMAP_UC | + _SEGMENT_ENTRY)); if (MACHINE_HAS_TLB_GUEST) __pmdp_idte(gaddr, pmdp, IDTE_GUEST_ASCE, gmap->asce, IDTE_LOCAL); @@ -2436,7 +2488,8 @@ void gmap_pmdp_idte_global(struct mm_struct *mm, unsigned long vmaddr) gaddr = __gmap_segment_gaddr(entry); pmdp_notify_gmap(gmap, pmdp, gaddr); WARN_ON(*entry & ~(_SEGMENT_ENTRY_HARDWARE_BITS_LARGE | - _SEGMENT_ENTRY_GMAP_UC)); + _SEGMENT_ENTRY_GMAP_UC | + _SEGMENT_ENTRY)); if (MACHINE_HAS_TLB_GUEST) __pmdp_idte(gaddr, pmdp, IDTE_GUEST_ASCE, gmap->asce, IDTE_GLOBAL); diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index ded0eff58a192a..d9ce199953de9e 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c @@ -24,6 +24,7 @@ static inline unsigned long __pte_to_rste(pte_t pte) { + swp_entry_t arch_entry; unsigned long rste; /* @@ -48,6 +49,7 @@ static inline unsigned long __pte_to_rste(pte_t pte) */ if (pte_present(pte)) { rste = pte_val(pte) & PAGE_MASK; + rste |= _SEGMENT_ENTRY_PRESENT; rste |= move_set_bit(pte_val(pte), _PAGE_READ, _SEGMENT_ENTRY_READ); rste |= move_set_bit(pte_val(pte), _PAGE_WRITE, @@ -66,6 +68,10 @@ static inline unsigned long __pte_to_rste(pte_t pte) #endif rste |= move_set_bit(pte_val(pte), _PAGE_NOEXEC, _SEGMENT_ENTRY_NOEXEC); + } else if (!pte_none(pte)) { + /* swap pte */ + arch_entry = __pte_to_swp_entry(pte); + rste = mk_swap_rste(__swp_type(arch_entry), __swp_offset(arch_entry)); } else rste = _SEGMENT_ENTRY_EMPTY; return rste; @@ -73,13 +79,18 @@ static inline unsigned long __pte_to_rste(pte_t pte) static inline pte_t __rste_to_pte(unsigned long rste) { + swp_entry_t arch_entry; unsigned long pteval; - int present; + int present, none; + pte_t pte; - if ((rste & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) + if ((rste & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) { present = pud_present(__pud(rste)); - else + none = pud_none(__pud(rste)); + } else { present = pmd_present(__pmd(rste)); + none = pmd_none(__pmd(rste)); + } /* * Convert encoding pmd / pud bits pte bits @@ -114,6 +125,11 @@ static inline pte_t __rste_to_pte(unsigned long rste) pteval |= move_set_bit(rste, _SEGMENT_ENTRY_SOFT_DIRTY, _PAGE_SOFT_DIRTY); #endif pteval |= move_set_bit(rste, _SEGMENT_ENTRY_NOEXEC, _PAGE_NOEXEC); + } else if (!none) { + /* swap rste */ + arch_entry = __rste_to_swp_entry(rste); + pte = mk_swap_pte(__swp_type_rste(arch_entry), __swp_offset_rste(arch_entry)); + pteval = pte_val(pte); } else pteval = _PAGE_INVALID; return __pte(pteval); @@ -148,8 +164,6 @@ void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr, unsigned long rste; rste = __pte_to_rste(pte); - if (!MACHINE_HAS_NX) - rste &= ~_SEGMENT_ENTRY_NOEXEC; /* Set correct table type for 2G hugepages */ if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) { @@ -223,11 +237,10 @@ pte_t *huge_pte_offset(struct mm_struct *mm, p4dp = p4d_offset(pgdp, addr); if (p4d_present(*p4dp)) { pudp = pud_offset(p4dp, addr); - if (pud_present(*pudp)) { - if (pud_leaf(*pudp)) - return (pte_t *) pudp; + if (sz == PUD_SIZE) + return (pte_t *)pudp; + if (pud_present(*pudp)) pmdp = pmd_offset(pudp, addr); - } } } return (pte_t *) pmdp; @@ -242,88 +255,3 @@ bool __init arch_hugetlb_valid_size(unsigned long size) else return false; } - -static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct vm_unmapped_area_info info = {}; - - info.length = len; - info.low_limit = current->mm->mmap_base; - info.high_limit = TASK_SIZE; - info.align_mask = PAGE_MASK & ~huge_page_mask(h); - return vm_unmapped_area(&info); -} - -static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, - unsigned long addr0, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct vm_unmapped_area_info info = {}; - unsigned long addr; - - info.flags = VM_UNMAPPED_AREA_TOPDOWN; - info.length = len; - info.low_limit = PAGE_SIZE; - info.high_limit = current->mm->mmap_base; - info.align_mask = PAGE_MASK & ~huge_page_mask(h); - addr = vm_unmapped_area(&info); - - /* - * 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. - */ - if (addr & ~PAGE_MASK) { - VM_BUG_ON(addr != -ENOMEM); - info.flags = 0; - info.low_limit = TASK_UNMAPPED_BASE; - info.high_limit = TASK_SIZE; - addr = vm_unmapped_area(&info); - } - - return addr; -} - -unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - - if (len & ~huge_page_mask(h)) - return -EINVAL; - if (len > TASK_SIZE - mmap_min_addr) - return -ENOMEM; - - if (flags & MAP_FIXED) { - if (prepare_hugepage_range(file, addr, len)) - return -EINVAL; - goto check_asce_limit; - } - - if (addr) { - addr = ALIGN(addr, huge_page_size(h)); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && addr >= mmap_min_addr && - (!vma || addr + len <= vm_start_gap(vma))) - goto check_asce_limit; - } - - if (!test_bit(MMF_TOPDOWN, &mm->flags)) - addr = hugetlb_get_unmapped_area_bottomup(file, addr, len, - pgoff, flags); - else - addr = hugetlb_get_unmapped_area_topdown(file, addr, len, - pgoff, flags); - if (offset_in_page(addr)) - return addr; - -check_asce_limit: - return check_asce_limit(mm, addr, len); -} diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index 96efa061ce01ba..33f3504be90b59 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -17,6 +17,7 @@ #include #include #include +#include #include static unsigned long stack_maxrandom_size(void) @@ -73,6 +74,8 @@ static inline unsigned long mmap_base(unsigned long rnd, static int get_align_mask(struct file *filp, unsigned long flags) { + if (filp && is_file_hugepages(filp)) + return huge_page_mask_align(filp); if (!(current->flags & PF_RANDOMIZE)) return 0; if (filp || (flags & MAP_SHARED)) @@ -106,7 +109,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, info.low_limit = mm->mmap_base; info.high_limit = TASK_SIZE; info.align_mask = get_align_mask(filp, flags); - info.align_offset = pgoff << PAGE_SHIFT; + if (!(filp && is_file_hugepages(filp))) + info.align_offset = pgoff << PAGE_SHIFT; addr = vm_unmapped_area(&info); if (offset_in_page(addr)) return addr; @@ -144,7 +148,8 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned long ad info.low_limit = PAGE_SIZE; info.high_limit = mm->mmap_base; info.align_mask = get_align_mask(filp, flags); - info.align_offset = pgoff << PAGE_SHIFT; + if (!(filp && is_file_hugepages(filp))) + info.align_offset = pgoff << PAGE_SHIFT; addr = vm_unmapped_area(&info); /* diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index 5f805ad42d4c3f..8f56a21a077f77 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c @@ -12,6 +12,7 @@ #include #include #include +#include #include static inline unsigned long sske_frame(unsigned long addr, unsigned char skey) @@ -406,6 +407,33 @@ int set_direct_map_default_noflush(struct page *page) return __set_memory((unsigned long)page_to_virt(page), 1, SET_MEMORY_DEF); } +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid) +{ + unsigned long flags; + + if (valid) + flags = SET_MEMORY_DEF; + else + flags = SET_MEMORY_INV; + + return __set_memory((unsigned long)page_to_virt(page), nr, flags); +} + +bool kernel_page_present(struct page *page) +{ + unsigned long addr; + unsigned int cc; + + addr = (unsigned long)page_address(page); + asm volatile( + " lra %[addr],0(%[addr])\n" + CC_IPM(cc) + : CC_OUT(cc, cc), [addr] "+a" (addr) + : + : CC_CLOBBER); + return CC_TRANSFORM(cc) == 0; +} + #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KFENCE) static void ipte_range(pte_t *pte, unsigned long address, int nr) diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index f691e0fb66a250..58696a0c4e4ac7 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -278,7 +278,7 @@ static inline unsigned long base_##NAME##_addr_end(unsigned long addr, \ return (next - 1) < (end - 1) ? next : end; \ } -BASE_ADDR_END_FUNC(page, _PAGE_SIZE) +BASE_ADDR_END_FUNC(page, PAGE_SIZE) BASE_ADDR_END_FUNC(segment, _SEGMENT_SIZE) BASE_ADDR_END_FUNC(region3, _REGION3_SIZE) BASE_ADDR_END_FUNC(region2, _REGION2_SIZE) @@ -302,7 +302,7 @@ static int base_page_walk(unsigned long *origin, unsigned long addr, if (!alloc) return 0; pte = origin; - pte += (addr & _PAGE_INDEX) >> _PAGE_SHIFT; + pte += (addr & _PAGE_INDEX) >> PAGE_SHIFT; do { next = base_page_addr_end(addr, end); *pte = base_lra(addr); diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 2c944bafb0309c..cea5dba80468cc 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -525,7 +525,7 @@ static inline void pudp_idte_global(struct mm_struct *mm, else /* * Invalid bit position is the same for pmd and pud, so we can - * re-use _pmd_csp() here + * reuse _pmd_csp() here */ __pmdp_csp((pmd_t *) pudp); } diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index bd9624c20b8020..88f72745fa59e1 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -160,6 +161,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_SET_MEASURE); struct zpci_iommu_ctrs *ctrs; struct zpci_fib fib = {0}; + unsigned long flags; u8 cc, status; if (zdev->fmb || sizeof(*zdev->fmb) < zdev->fmb_length) @@ -171,6 +173,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) WARN_ON((u64) zdev->fmb & 0xf); /* reset software counters */ + spin_lock_irqsave(&zdev->dom_lock, flags); ctrs = zpci_get_iommu_ctrs(zdev); if (ctrs) { atomic64_set(&ctrs->mapped_pages, 0); @@ -179,6 +182,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) atomic64_set(&ctrs->sync_map_rpcits, 0); atomic64_set(&ctrs->sync_rpcits, 0); } + spin_unlock_irqrestore(&zdev->dom_lock, flags); fib.fmb_addr = virt_to_phys(zdev->fmb); @@ -775,8 +779,9 @@ int zpci_hot_reset_device(struct zpci_dev *zdev) * @fh: Current Function Handle of the device to be created * @state: Initial state after creation either Standby or Configured * - * Creates a new zpci device and adds it to its, possibly newly created, zbus - * as well as zpci_list. + * Allocates a new struct zpci_dev and queries the platform for its details. + * If successful the device can subsequently be added to the zPCI subsystem + * using zpci_add_device(). * * Returns: the zdev on success or an error pointer otherwise */ @@ -785,7 +790,6 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state) struct zpci_dev *zdev; int rc; - zpci_dbg(1, "add fid:%x, fh:%x, c:%d\n", fid, fh, state); zdev = kzalloc(sizeof(*zdev), GFP_KERNEL); if (!zdev) return ERR_PTR(-ENOMEM); @@ -800,11 +804,34 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state) goto error; zdev->state = state; - kref_init(&zdev->kref); mutex_init(&zdev->state_lock); mutex_init(&zdev->fmb_lock); mutex_init(&zdev->kzdev_lock); + return zdev; + +error: + zpci_dbg(0, "crt fid:%x, rc:%d\n", fid, rc); + kfree(zdev); + return ERR_PTR(rc); +} + +/** + * zpci_add_device() - Add a previously created zPCI device to the zPCI subsystem + * @zdev: The zPCI device to be added + * + * A struct zpci_dev is added to the zPCI subsystem and to a virtual PCI bus creating + * a new one as necessary. A hotplug slot is created and events start to be handled. + * If successful from this point on zpci_zdev_get() and zpci_zdev_put() must be used. + * If adding the struct zpci_dev fails the device was not added and should be freed. + * + * Return: 0 on success, or an error code otherwise + */ +int zpci_add_device(struct zpci_dev *zdev) +{ + int rc; + + zpci_dbg(1, "add fid:%x, fh:%x, c:%d\n", zdev->fid, zdev->fh, zdev->state); rc = zpci_init_iommu(zdev); if (rc) goto error; @@ -813,18 +840,17 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state) if (rc) goto error_destroy_iommu; + kref_init(&zdev->kref); spin_lock(&zpci_list_lock); list_add_tail(&zdev->entry, &zpci_list); spin_unlock(&zpci_list_lock); - - return zdev; + return 0; error_destroy_iommu: zpci_destroy_iommu(zdev); error: - zpci_dbg(0, "add fid:%x, rc:%d\n", fid, rc); - kfree(zdev); - return ERR_PTR(rc); + zpci_dbg(0, "add fid:%x, rc:%d\n", zdev->fid, rc); + return rc; } bool zpci_is_device_configured(struct zpci_dev *zdev) @@ -914,10 +940,8 @@ void zpci_device_reserved(struct zpci_dev *zdev) void zpci_release_device(struct kref *kref) { struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref); - int ret; - if (zdev->has_hp_slot) - zpci_exit_slot(zdev); + WARN_ON(zdev->state != ZPCI_FN_STATE_RESERVED); if (zdev->zbus->bus) zpci_bus_remove_device(zdev, false); @@ -925,28 +949,14 @@ void zpci_release_device(struct kref *kref) if (zdev_enabled(zdev)) zpci_disable_device(zdev); - switch (zdev->state) { - case ZPCI_FN_STATE_CONFIGURED: - ret = sclp_pci_deconfigure(zdev->fid); - zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret); - fallthrough; - case ZPCI_FN_STATE_STANDBY: - if (zdev->has_hp_slot) - zpci_exit_slot(zdev); - spin_lock(&zpci_list_lock); - list_del(&zdev->entry); - spin_unlock(&zpci_list_lock); - zpci_dbg(3, "rsv fid:%x\n", zdev->fid); - fallthrough; - case ZPCI_FN_STATE_RESERVED: - if (zdev->has_resources) - zpci_cleanup_bus_resources(zdev); - zpci_bus_device_unregister(zdev); - zpci_destroy_iommu(zdev); - fallthrough; - default: - break; - } + if (zdev->has_hp_slot) + zpci_exit_slot(zdev); + + if (zdev->has_resources) + zpci_cleanup_bus_resources(zdev); + + zpci_bus_device_unregister(zdev); + zpci_destroy_iommu(zdev); zpci_dbg(3, "rem fid:%x\n", zdev->fid); kfree_rcu(zdev, rcu); } @@ -1082,6 +1092,50 @@ bool zpci_is_enabled(void) return s390_pci_initialized; } +static int zpci_cmp_rid(void *priv, const struct list_head *a, + const struct list_head *b) +{ + struct zpci_dev *za = container_of(a, struct zpci_dev, entry); + struct zpci_dev *zb = container_of(b, struct zpci_dev, entry); + + /* + * PCI functions without RID available maintain original order + * between themselves but sort before those with RID. + */ + if (za->rid == zb->rid) + return za->rid_available > zb->rid_available; + /* + * PCI functions with RID sort by RID ascending. + */ + return za->rid > zb->rid; +} + +static void zpci_add_devices(struct list_head *scan_list) +{ + struct zpci_dev *zdev, *tmp; + + list_sort(NULL, scan_list, &zpci_cmp_rid); + list_for_each_entry_safe(zdev, tmp, scan_list, entry) { + list_del_init(&zdev->entry); + if (zpci_add_device(zdev)) + kfree(zdev); + } +} + +int zpci_scan_devices(void) +{ + LIST_HEAD(scan_list); + int rc; + + rc = clp_scan_pci_devices(&scan_list); + if (rc) + return rc; + + zpci_add_devices(&scan_list); + zpci_bus_scan_busses(); + return 0; +} + static int __init pci_base_init(void) { int rc; @@ -1111,10 +1165,9 @@ static int __init pci_base_init(void) if (rc) goto out_irq; - rc = clp_scan_pci_devices(); + rc = zpci_scan_devices(); if (rc) goto out_find; - zpci_bus_scan_busses(); s390_pci_initialized = 1; return 0; diff --git a/arch/s390/pci/pci_bus.c b/arch/s390/pci/pci_bus.c index daa5d7450c7d38..d5ace00d10f042 100644 --- a/arch/s390/pci/pci_bus.c +++ b/arch/s390/pci/pci_bus.c @@ -53,7 +53,7 @@ static int zpci_bus_prepare_device(struct zpci_dev *zdev) zpci_setup_bus_resources(zdev); for (i = 0; i < PCI_STD_NUM_BARS; i++) { if (zdev->bars[i].res) - pci_bus_add_resource(zdev->zbus->bus, zdev->bars[i].res, 0); + pci_bus_add_resource(zdev->zbus->bus, zdev->bars[i].res); } } @@ -168,9 +168,16 @@ void zpci_bus_scan_busses(void) mutex_unlock(&zbus_list_lock); } +static bool zpci_bus_is_multifunction_root(struct zpci_dev *zdev) +{ + return !s390_pci_no_rid && zdev->rid_available && + zpci_is_device_configured(zdev) && + !zdev->vfn; +} + /* zpci_bus_create_pci_bus - Create the PCI bus associated with this zbus * @zbus: the zbus holding the zdevices - * @fr: PCI root function that will determine the bus's domain, and bus speeed + * @fr: PCI root function that will determine the bus's domain, and bus speed * @ops: the pci operations * * The PCI function @fr determines the domain (its UID), multifunction property @@ -188,7 +195,7 @@ static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, s return domain; zbus->domain_nr = domain; - zbus->multifunction = fr->rid_available; + zbus->multifunction = zpci_bus_is_multifunction_root(fr); zbus->max_bus_speed = fr->max_bus_speed; /* @@ -232,13 +239,15 @@ static void zpci_bus_put(struct zpci_bus *zbus) kref_put(&zbus->kref, zpci_bus_release); } -static struct zpci_bus *zpci_bus_get(int pchid) +static struct zpci_bus *zpci_bus_get(int topo, bool topo_is_tid) { struct zpci_bus *zbus; mutex_lock(&zbus_list_lock); list_for_each_entry(zbus, &zbus_list, bus_next) { - if (pchid == zbus->pchid) { + if (!zbus->multifunction) + continue; + if (topo_is_tid == zbus->topo_is_tid && topo == zbus->topo) { kref_get(&zbus->kref); goto out_unlock; } @@ -249,7 +258,7 @@ static struct zpci_bus *zpci_bus_get(int pchid) return zbus; } -static struct zpci_bus *zpci_bus_alloc(int pchid) +static struct zpci_bus *zpci_bus_alloc(int topo, bool topo_is_tid) { struct zpci_bus *zbus; @@ -257,7 +266,8 @@ static struct zpci_bus *zpci_bus_alloc(int pchid) if (!zbus) return NULL; - zbus->pchid = pchid; + zbus->topo = topo; + zbus->topo_is_tid = topo_is_tid; INIT_LIST_HEAD(&zbus->bus_next); mutex_lock(&zbus_list_lock); list_add_tail(&zbus->bus_next, &zbus_list); @@ -292,19 +302,22 @@ static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev) { int rc = -EINVAL; + if (zbus->multifunction) { + if (!zdev->rid_available) { + WARN_ONCE(1, "rid_available not set for multifunction\n"); + return rc; + } + zdev->devfn = zdev->rid & ZPCI_RID_MASK_DEVFN; + } + if (zbus->function[zdev->devfn]) { pr_err("devfn %04x is already assigned\n", zdev->devfn); return rc; } - zdev->zbus = zbus; zbus->function[zdev->devfn] = zdev; zpci_nb_devices++; - if (zbus->multifunction && !zdev->rid_available) { - WARN_ONCE(1, "rid_available not set for multifunction\n"); - goto error; - } rc = zpci_init_slot(zdev); if (rc) goto error; @@ -321,8 +334,9 @@ static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev) int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops) { + bool topo_is_tid = zdev->tid_avail; struct zpci_bus *zbus = NULL; - int rc = -EBADF; + int topo, rc = -EBADF; if (zpci_nb_devices == ZPCI_NR_DEVICES) { pr_warn("Adding PCI function %08x failed because the configured limit of %d is reached\n", @@ -330,14 +344,10 @@ int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops) return -ENOSPC; } - if (zdev->devfn >= ZPCI_FUNCTIONS_PER_BUS) - return -EINVAL; - - if (!s390_pci_no_rid && zdev->rid_available) - zbus = zpci_bus_get(zdev->pchid); - + topo = topo_is_tid ? zdev->tid : zdev->pchid; + zbus = zpci_bus_get(topo, topo_is_tid); if (!zbus) { - zbus = zpci_bus_alloc(zdev->pchid); + zbus = zpci_bus_alloc(topo, topo_is_tid); if (!zbus) return -ENOMEM; } diff --git a/arch/s390/pci/pci_bus.h b/arch/s390/pci/pci_bus.h index af9f0ac79a1b1b..e86a9419d233f7 100644 --- a/arch/s390/pci/pci_bus.h +++ b/arch/s390/pci/pci_bus.h @@ -6,6 +6,10 @@ * Pierre Morel * */ +#ifndef __S390_PCI_BUS_H +#define __S390_PCI_BUS_H + +#include int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops); void zpci_bus_device_unregister(struct zpci_dev *zdev); @@ -40,3 +44,4 @@ static inline struct zpci_dev *zdev_from_bus(struct pci_bus *bus, return (devfn >= ZPCI_FUNCTIONS_PER_BUS) ? NULL : zbus->function[devfn]; } +#endif /* __S390_PCI_BUS_H */ diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 6f55a59a087115..14bf7e8d06b7a7 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -52,18 +53,20 @@ static inline void zpci_err_clp(unsigned int rsp, int rc) static inline int clp_get_ilp(unsigned long *ilp) { unsigned long mask; - int cc = 3; + int cc, exception; + exception = 1; asm volatile ( " .insn rrf,0xb9a00000,%[mask],%[cmd],8,0\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [mask] "=d" (mask) : [cmd] "a" (1) - : "cc"); + : CC_OUT(cc, cc), [mask] "=d" (mask), [exc] "+d" (exception) + : [cmd] "a" (1) + : CC_CLOBBER); *ilp = mask; - return cc; + return exception ? 3 : CC_TRANSFORM(cc); } /* @@ -72,19 +75,20 @@ static inline int clp_get_ilp(unsigned long *ilp) static __always_inline int clp_req(void *data, unsigned int lps) { struct { u8 _[CLP_BLK_SIZE]; } *req = data; + int cc, exception; u64 ignored; - int cc = 3; + exception = 1; asm volatile ( " .insn rrf,0xb9a00000,%[ign],%[req],0,%[lps]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [ign] "=d" (ignored), "+m" (*req) + : CC_OUT(cc, cc), [ign] "=d" (ignored), "+m" (*req), [exc] "+d" (exception) : [req] "a" (req), [lps] "i" (lps) - : "cc"); - return cc; + : CC_CLOBBER); + return exception ? 3 : CC_TRANSFORM(cc); } static void *clp_alloc_block(gfp_t gfp_mask) @@ -162,12 +166,16 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev, zdev->pft = response->pft; zdev->vfn = response->vfn; zdev->port = response->port; + zdev->fidparm = response->fidparm; zdev->uid = response->uid; zdev->fmb_length = sizeof(u32) * response->fmb_len; - zdev->rid_available = response->rid_avail; zdev->is_physfn = response->is_physfn; - if (!s390_pci_no_rid && zdev->rid_available) - zdev->devfn = response->rid & ZPCI_RID_MASK_DEVFN; + zdev->rid_available = response->rid_avail; + if (zdev->rid_available) + zdev->rid = response->rid; + zdev->tid_avail = response->tid_avail; + if (zdev->tid_avail) + zdev->tid = response->tid; memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip)); if (response->util_str_avail) { @@ -407,6 +415,7 @@ static int clp_find_pci(struct clp_req_rsp_list_pci *rrb, u32 fid, static void __clp_add(struct clp_fh_list_entry *entry, void *data) { + struct list_head *scan_list = data; struct zpci_dev *zdev; if (!entry->vendor_id) @@ -417,10 +426,11 @@ static void __clp_add(struct clp_fh_list_entry *entry, void *data) zpci_zdev_put(zdev); return; } - zpci_create_device(entry->fid, entry->fh, entry->config_state); + zdev = zpci_create_device(entry->fid, entry->fh, entry->config_state); + list_add_tail(&zdev->entry, scan_list); } -int clp_scan_pci_devices(void) +int clp_scan_pci_devices(struct list_head *scan_list) { struct clp_req_rsp_list_pci *rrb; int rc; @@ -429,7 +439,7 @@ int clp_scan_pci_devices(void) if (!rrb) return -ENOMEM; - rc = clp_list_pci(rrb, NULL, __clp_add); + rc = clp_list_pci(rrb, scan_list, __clp_add); clp_free_block(rrb); return rc; diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c index 2cb5043a997d53..38014206c16b96 100644 --- a/arch/s390/pci/pci_debug.c +++ b/arch/s390/pci/pci_debug.c @@ -71,17 +71,23 @@ static void pci_fmb_show(struct seq_file *m, char *name[], int length, static void pci_sw_counter_show(struct seq_file *m) { - struct zpci_iommu_ctrs *ctrs = zpci_get_iommu_ctrs(m->private); + struct zpci_dev *zdev = m->private; + struct zpci_iommu_ctrs *ctrs; atomic64_t *counter; + unsigned long flags; int i; + spin_lock_irqsave(&zdev->dom_lock, flags); + ctrs = zpci_get_iommu_ctrs(m->private); if (!ctrs) - return; + goto unlock; counter = &ctrs->mapped_pages; for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++) seq_printf(m, "%26s:\t%llu\n", pci_sw_names[i], atomic64_read(counter)); +unlock: + spin_unlock_irqrestore(&zdev->dom_lock, flags); } static int pci_perf_show(struct seq_file *m, void *v) diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index d4f19d33914cbc..7f7b732b3f3efa 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -340,6 +340,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED); if (IS_ERR(zdev)) break; + if (zpci_add_device(zdev)) { + kfree(zdev); + break; + } } else { /* the configuration request may be stale */ if (zdev->state != ZPCI_FN_STATE_STANDBY) @@ -349,10 +353,17 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) zpci_scan_configured_device(zdev, ccdf->fh); break; case 0x0302: /* Reserved -> Standby */ - if (!zdev) - zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY); - else + if (!zdev) { + zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY); + if (IS_ERR(zdev)) + break; + if (zpci_add_device(zdev)) { + kfree(zdev); + break; + } + } else { zpci_update_fh(zdev, ccdf->fh); + } break; case 0x0303: /* Deconfiguration requested */ if (zdev) { @@ -381,7 +392,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) break; case 0x0306: /* 0x308 or 0x302 for multiple devices */ zpci_remove_reserved_devices(); - clp_scan_pci_devices(); + zpci_scan_devices(); break; case 0x0308: /* Standby -> Reserved */ if (!zdev) diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c index 56480be4824478..f5a75ea7629aff 100644 --- a/arch/s390/pci/pci_insn.c +++ b/arch/s390/pci/pci_insn.c @@ -15,6 +15,7 @@ #include #include #include +#include #define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */ @@ -57,16 +58,16 @@ static inline void zpci_err_insn_addr(int lvl, u8 insn, u8 cc, u8 status, /* Modify PCI Function Controls */ static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status) { - u8 cc; + int cc; asm volatile ( " .insn rxy,0xe300000000d0,%[req],%[fib]\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib) - : : "cc"); + CC_IPM(cc) + : CC_OUT(cc, cc), [req] "+d" (req), [fib] "+Q" (*fib) + : + : CC_CLOBBER); *status = req >> 24 & 0xff; - return cc; + return CC_TRANSFORM(cc); } u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status) @@ -98,17 +99,16 @@ EXPORT_SYMBOL_GPL(zpci_mod_fc); static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status) { union register_pair addr_range = {.even = addr, .odd = range}; - u8 cc; + int cc; asm volatile ( " .insn rre,0xb9d30000,%[fn],%[addr_range]\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=d" (cc), [fn] "+d" (fn) + CC_IPM(cc) + : CC_OUT(cc, cc), [fn] "+d" (fn) : [addr_range] "d" (addr_range.pair) - : "cc"); + : CC_CLOBBER); *status = fn >> 24 & 0xff; - return cc; + return CC_TRANSFORM(cc); } int zpci_refresh_trans(u64 fn, u64 addr, u64 range) @@ -156,20 +156,23 @@ EXPORT_SYMBOL_GPL(zpci_set_irq_ctrl); static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status) { union register_pair req_off = {.even = req, .odd = offset}; - int cc = -ENXIO; + int cc, exception; u64 __data; + exception = 1; asm volatile ( " .insn rre,0xb9d20000,%[data],%[req_off]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [data] "=d" (__data), - [req_off] "+&d" (req_off.pair) :: "cc"); + : CC_OUT(cc, cc), [data] "=d" (__data), + [req_off] "+d" (req_off.pair), [exc] "+d" (exception) + : + : CC_CLOBBER); *status = req_off.even >> 24 & 0xff; *data = __data; - return cc; + return exception ? -ENXIO : CC_TRANSFORM(cc); } static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status) @@ -222,20 +225,23 @@ static inline int zpci_load_fh(u64 *data, const volatile void __iomem *addr, static inline int __pcilg_mio(u64 *data, u64 ioaddr, u64 len, u8 *status) { union register_pair ioaddr_len = {.even = ioaddr, .odd = len}; - int cc = -ENXIO; + int cc, exception; u64 __data; + exception = 1; asm volatile ( " .insn rre,0xb9d60000,%[data],%[ioaddr_len]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [data] "=d" (__data), - [ioaddr_len] "+&d" (ioaddr_len.pair) :: "cc"); + : CC_OUT(cc, cc), [data] "=d" (__data), + [ioaddr_len] "+d" (ioaddr_len.pair), [exc] "+d" (exception) + : + : CC_CLOBBER); *status = ioaddr_len.odd >> 24 & 0xff; *data = __data; - return cc; + return exception ? -ENXIO : CC_TRANSFORM(cc); } int zpci_load(u64 *data, const volatile void __iomem *addr, unsigned long len) @@ -258,19 +264,20 @@ EXPORT_SYMBOL_GPL(zpci_load); static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status) { union register_pair req_off = {.even = req, .odd = offset}; - int cc = -ENXIO; + int cc, exception; + exception = 1; asm volatile ( " .insn rre,0xb9d00000,%[data],%[req_off]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [req_off] "+&d" (req_off.pair) + : CC_OUT(cc, cc), [req_off] "+d" (req_off.pair), [exc] "+d" (exception) : [data] "d" (data) - : "cc"); + : CC_CLOBBER); *status = req_off.even >> 24 & 0xff; - return cc; + return exception ? -ENXIO : CC_TRANSFORM(cc); } int __zpci_store(u64 data, u64 req, u64 offset) @@ -311,19 +318,20 @@ static inline int zpci_store_fh(const volatile void __iomem *addr, u64 data, static inline int __pcistg_mio(u64 data, u64 ioaddr, u64 len, u8 *status) { union register_pair ioaddr_len = {.even = ioaddr, .odd = len}; - int cc = -ENXIO; + int cc, exception; + exception = 1; asm volatile ( " .insn rre,0xb9d40000,%[data],%[ioaddr_len]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [ioaddr_len] "+&d" (ioaddr_len.pair) + : CC_OUT(cc, cc), [ioaddr_len] "+d" (ioaddr_len.pair), [exc] "+d" (exception) : [data] "d" (data) - : "cc", "memory"); + : CC_CLOBBER_LIST("memory")); *status = ioaddr_len.odd >> 24 & 0xff; - return cc; + return exception ? -ENXIO : CC_TRANSFORM(cc); } int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len) @@ -345,19 +353,20 @@ EXPORT_SYMBOL_GPL(zpci_store); /* PCI Store Block */ static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status) { - int cc = -ENXIO; + int cc, exception; + exception = 1; asm volatile ( " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [req] "+d" (req) + : CC_OUT(cc, cc), [req] "+d" (req), [exc] "+d" (exception) : [offset] "d" (offset), [data] "Q" (*data) - : "cc"); + : CC_CLOBBER); *status = req >> 24 & 0xff; - return cc; + return exception ? -ENXIO : CC_TRANSFORM(cc); } int __zpci_store_block(const u64 *data, u64 req, u64 offset) @@ -398,19 +407,20 @@ static inline int zpci_write_block_fh(volatile void __iomem *dst, static inline int __pcistb_mio(const u64 *data, u64 ioaddr, u64 len, u8 *status) { - int cc = -ENXIO; + int cc, exception; + exception = 1; asm volatile ( " .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[data]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+d" (cc), [len] "+d" (len) + : CC_OUT(cc, cc), [len] "+d" (len), [exc] "+d" (exception) : [ioaddr] "d" (ioaddr), [data] "Q" (*data) - : "cc"); + : CC_CLOBBER); *status = len >> 24 & 0xff; - return cc; + return exception ? -ENXIO : CC_TRANSFORM(cc); } int zpci_write_block(volatile void __iomem *dst, diff --git a/arch/s390/pci/pci_iov.h b/arch/s390/pci/pci_iov.h index b2c828003bad0a..e3fa4e77fc867a 100644 --- a/arch/s390/pci/pci_iov.h +++ b/arch/s390/pci/pci_iov.h @@ -10,6 +10,8 @@ #ifndef __S390_PCI_IOV_H #define __S390_PCI_IOV_H +#include + #ifdef CONFIG_PCI_IOV void zpci_iov_remove_virtfn(struct pci_dev *pdev, int vfn); diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c index de5c0b389a3ec8..46f99dc164ade4 100644 --- a/arch/s390/pci/pci_mmio.c +++ b/arch/s390/pci/pci_mmio.c @@ -14,6 +14,7 @@ #include #include #include +#include static inline void zpci_err_mmio(u8 cc, u8 status, u64 offset) { @@ -30,20 +31,21 @@ static inline int __pcistb_mio_inuser( void __iomem *ioaddr, const void __user *src, u64 len, u8 *status) { - int cc = -ENXIO; + int cc, exception; + exception = 1; asm volatile ( - " sacf 256\n" - "0: .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[src]\n" - "1: ipm %[cc]\n" - " srl %[cc],28\n" - "2: sacf 768\n" + " sacf 256\n" + "0: .insn rsy,0xeb00000000d4,%[len],%[ioaddr],%[src]\n" + "1: lhi %[exc],0\n" + "2: sacf 768\n" + CC_IPM(cc) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b) - : [cc] "+d" (cc), [len] "+d" (len) + : CC_OUT(cc, cc), [len] "+d" (len), [exc] "+d" (exception) : [ioaddr] "a" (ioaddr), [src] "Q" (*((u8 __force *)src)) - : "cc", "memory"); + : CC_CLOBBER_LIST("memory")); *status = len >> 24 & 0xff; - return cc; + return exception ? -ENXIO : CC_TRANSFORM(cc); } static inline int __pcistg_mio_inuser( @@ -51,7 +53,7 @@ static inline int __pcistg_mio_inuser( u64 ulen, u8 *status) { union register_pair ioaddr_len = {.even = (u64 __force)ioaddr, .odd = ulen}; - int cc = -ENXIO; + int cc, exception; u64 val = 0; u64 cnt = ulen; u8 tmp; @@ -61,25 +63,27 @@ static inline int __pcistg_mio_inuser( * a register, then store it to PCI at @ioaddr while in secondary * address space. pcistg then uses the user mappings. */ + exception = 1; asm volatile ( - " sacf 256\n" - "0: llgc %[tmp],0(%[src])\n" + " sacf 256\n" + "0: llgc %[tmp],0(%[src])\n" "4: sllg %[val],%[val],8\n" - " aghi %[src],1\n" - " ogr %[val],%[tmp]\n" - " brctg %[cnt],0b\n" - "1: .insn rre,0xb9d40000,%[val],%[ioaddr_len]\n" - "2: ipm %[cc]\n" - " srl %[cc],28\n" - "3: sacf 768\n" + " aghi %[src],1\n" + " ogr %[val],%[tmp]\n" + " brctg %[cnt],0b\n" + "1: .insn rre,0xb9d40000,%[val],%[ioaddr_len]\n" + "2: lhi %[exc],0\n" + "3: sacf 768\n" + CC_IPM(cc) EX_TABLE(0b, 3b) EX_TABLE(4b, 3b) EX_TABLE(1b, 3b) EX_TABLE(2b, 3b) + : [src] "+a" (src), [cnt] "+d" (cnt), + [val] "+d" (val), [tmp] "=d" (tmp), [exc] "+d" (exception), + CC_OUT(cc, cc), [ioaddr_len] "+&d" (ioaddr_len.pair) : - [src] "+a" (src), [cnt] "+d" (cnt), - [val] "+d" (val), [tmp] "=d" (tmp), - [cc] "+d" (cc), [ioaddr_len] "+&d" (ioaddr_len.pair) - :: "cc", "memory"); + : CC_CLOBBER_LIST("memory")); *status = ioaddr_len.odd >> 24 & 0xff; + cc = exception ? -ENXIO : CC_TRANSFORM(cc); /* did we read everything from user memory? */ if (!cc && cnt != 0) cc = -EFAULT; @@ -198,7 +202,7 @@ static inline int __pcilg_mio_inuser( union register_pair ioaddr_len = {.even = (u64 __force)ioaddr, .odd = ulen}; u64 cnt = ulen; int shift = ulen * 8; - int cc = -ENXIO; + int cc, exception; u64 val, tmp; /* @@ -206,27 +210,33 @@ static inline int __pcilg_mio_inuser( * user space) into a register using pcilg then store these bytes at * user address @dst */ + exception = 1; asm volatile ( - " sacf 256\n" - "0: .insn rre,0xb9d60000,%[val],%[ioaddr_len]\n" - "1: ipm %[cc]\n" - " srl %[cc],28\n" - " ltr %[cc],%[cc]\n" - " jne 4f\n" - "2: ahi %[shift],-8\n" - " srlg %[tmp],%[val],0(%[shift])\n" - "3: stc %[tmp],0(%[dst])\n" + " sacf 256\n" + "0: .insn rre,0xb9d60000,%[val],%[ioaddr_len]\n" + "1: lhi %[exc],0\n" + " jne 4f\n" + "2: ahi %[shift],-8\n" + " srlg %[tmp],%[val],0(%[shift])\n" + "3: stc %[tmp],0(%[dst])\n" "5: aghi %[dst],1\n" - " brctg %[cnt],2b\n" - "4: sacf 768\n" + " brctg %[cnt],2b\n" + /* + * Use xr to clear exc and set condition code to zero + * to ensure flag output is correct for this branch. + */ + " xr %[exc],%[exc]\n" + "4: sacf 768\n" + CC_IPM(cc) EX_TABLE(0b, 4b) EX_TABLE(1b, 4b) EX_TABLE(3b, 4b) EX_TABLE(5b, 4b) + : [ioaddr_len] "+&d" (ioaddr_len.pair), [exc] "+d" (exception), + CC_OUT(cc, cc), [val] "=d" (val), + [dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp), + [shift] "+d" (shift) : - [ioaddr_len] "+&d" (ioaddr_len.pair), - [cc] "+d" (cc), [val] "=d" (val), - [dst] "+a" (dst), [cnt] "+d" (cnt), [tmp] "=d" (tmp), - [shift] "+d" (shift) - :: "cc", "memory"); + : CC_CLOBBER_LIST("memory")); + cc = exception ? -ENXIO : CC_TRANSFORM(cc); /* did we write everything to the user space buffer? */ if (!cc && cnt != 0) cc = -EFAULT; diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c index 1f81f6ff7b954b..5f46ad58dcd1c3 100644 --- a/arch/s390/pci/pci_sysfs.c +++ b/arch/s390/pci/pci_sysfs.c @@ -23,7 +23,7 @@ static ssize_t name##_show(struct device *dev, \ { \ struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); \ \ - return sprintf(buf, fmt, zdev->member); \ + return sysfs_emit(buf, fmt, zdev->member); \ } \ static DEVICE_ATTR_RO(name) @@ -34,6 +34,7 @@ zpci_attr(pfgid, "0x%02x\n", pfgid); zpci_attr(vfn, "0x%04x\n", vfn); zpci_attr(pft, "0x%02x\n", pft); zpci_attr(port, "%d\n", port); +zpci_attr(fidparm, "0x%02x\n", fidparm); zpci_attr(uid, "0x%x\n", uid); zpci_attr(segment0, "0x%02x\n", pfip[0]); zpci_attr(segment1, "0x%02x\n", pfip[1]); @@ -45,7 +46,7 @@ static ssize_t mio_enabled_show(struct device *dev, { struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); - return sprintf(buf, zpci_use_mio(zdev) ? "1\n" : "0\n"); + return sysfs_emit(buf, zpci_use_mio(zdev) ? "1\n" : "0\n"); } static DEVICE_ATTR_RO(mio_enabled); @@ -215,6 +216,7 @@ static struct attribute *zpci_dev_attrs[] = { &dev_attr_pfgid.attr, &dev_attr_pft.attr, &dev_attr_port.attr, + &dev_attr_fidparm.attr, &dev_attr_vfn.attr, &dev_attr_uid.attr, &dev_attr_recover.attr, diff --git a/arch/s390/purgatory/head.S b/arch/s390/purgatory/head.S index 0f93f2e72eba08..db3ab240262174 100644 --- a/arch/s390/purgatory/head.S +++ b/arch/s390/purgatory/head.S @@ -156,7 +156,7 @@ SYM_CODE_START(purgatory_start) agr %r10,%r9 /* Buffer location (in crash memory) and size. As the purgatory is - * behind the point of no return it can re-use the stack as buffer. + * behind the point of no return it can reuse the stack as buffer. */ larl %r11,purgatory_end larl %r12,stack diff --git a/arch/s390/tools/gen_facilities.c b/arch/s390/tools/gen_facilities.c index 68580cbea4e629..855f818deb98ef 100644 --- a/arch/s390/tools/gen_facilities.c +++ b/arch/s390/tools/gen_facilities.c @@ -109,10 +109,12 @@ static struct facility_def facility_defs[] = { 15, /* AP Facilities Test */ 156, /* etoken facility */ 165, /* nnpa facility */ + 170, /* ineffective-nonconstrained-transaction facility */ 193, /* bear enhancement facility */ 194, /* rdp enhancement facility */ 196, /* processor activity instrumentation facility */ 197, /* processor activity instrumentation extension 1 */ + 201, /* concurrent-functions facility */ -1 /* END */ } }, diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig index 0311380160f42b..d871623955c59b 100644 --- a/arch/sh/configs/landisk_defconfig +++ b/arch/sh/configs/landisk_defconfig @@ -95,7 +95,6 @@ CONFIG_USB_SISUSBVGA=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_REISERFS_FS=y CONFIG_ISO9660_FS=m CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig index c1032559ecd4a5..99bc0e889287ab 100644 --- a/arch/sh/configs/titan_defconfig +++ b/arch/sh/configs/titan_defconfig @@ -220,7 +220,6 @@ CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set # CONFIG_EXT3_FS_XATTR is not set -CONFIG_REISERFS_FS=m CONFIG_XFS_FS=m CONFIG_FUSE_FS=m CONFIG_ISO9660_FS=m diff --git a/arch/sh/drivers/push-switch.c b/arch/sh/drivers/push-switch.c index 1dea43381b5ae6..2b51ad9d5586a4 100644 --- a/arch/sh/drivers/push-switch.c +++ b/arch/sh/drivers/push-switch.c @@ -110,7 +110,7 @@ static void switch_drv_remove(struct platform_device *pdev) static struct platform_driver switch_driver = { .probe = switch_drv_probe, - .remove_new = switch_drv_remove, + .remove = switch_drv_remove, .driver = { .name = DRV_NAME, }, diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild index fc44d9c88b4191..4d3f10ed827581 100644 --- a/arch/sh/include/asm/Kbuild +++ b/arch/sh/include/asm/Kbuild @@ -3,3 +3,4 @@ generated-y += syscall_table.h generic-y += kvm_para.h generic-y += mcs_spinlock.h generic-y += parport.h +generic-y += text-patching.h diff --git a/arch/sh/include/asm/hugetlb.h b/arch/sh/include/asm/hugetlb.h index 75028bd568ba5e..4a92e6e4d627e9 100644 --- a/arch/sh/include/asm/hugetlb.h +++ b/arch/sh/include/asm/hugetlb.h @@ -5,21 +5,6 @@ #include #include -/* - * If the arch doesn't supply something else, assume that hugepage - * size aligned regions are ok without further preparation. - */ -#define __HAVE_ARCH_PREPARE_HUGEPAGE_RANGE -static inline int prepare_hugepage_range(struct file *file, - unsigned long addr, unsigned long len) -{ - if (len & ~HPAGE_MASK) - return -EINVAL; - if (addr & ~HPAGE_MASK) - return -EINVAL; - return 0; -} - #define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h index f780b467e75d7c..3990cbd9aa0442 100644 --- a/arch/sh/include/asm/page.h +++ b/arch/sh/include/asm/page.h @@ -8,10 +8,8 @@ #include -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include + #define PTE_MASK PAGE_MASK #if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) @@ -147,7 +145,6 @@ typedef struct page *pgtable_t; #endif #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) /* * PFN = physical frame number (ie PFN 0 == physical address 0) diff --git a/arch/sh/include/asm/spinlock_types.h b/arch/sh/include/asm/spinlock_types.h index 907bda4b1619a9..7cb50e68448f4d 100644 --- a/arch/sh/include/asm/spinlock_types.h +++ b/arch/sh/include/asm/spinlock_types.h @@ -3,7 +3,7 @@ #define __ASM_SH_SPINLOCK_TYPES_H #ifndef __LINUX_SPINLOCK_TYPES_RAW_H -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif typedef struct { diff --git a/arch/sh/include/asm/vga.h b/arch/sh/include/asm/vga.h deleted file mode 100644 index 089fbdc6c0b1d0..00000000000000 --- a/arch/sh/include/asm/vga.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_SH_VGA_H -#define __ASM_SH_VGA_H - -/* Stupid drivers. */ - -#endif /* __ASM_SH_VGA_H */ diff --git a/arch/sh/kernel/cpu/proc.c b/arch/sh/kernel/cpu/proc.c index a306bcd6b34130..5f6d0e827baeb0 100644 --- a/arch/sh/kernel/cpu/proc.c +++ b/arch/sh/kernel/cpu/proc.c @@ -132,7 +132,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) static void *c_start(struct seq_file *m, loff_t *pos) { - return *pos < NR_CPUS ? cpu_data + *pos : NULL; + return *pos < nr_cpu_ids ? cpu_data + *pos : NULL; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) { diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 620e5cf8ae1e74..f2b6f16a46b85d 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -255,7 +255,7 @@ void __ref sh_fdt_init(phys_addr_t dt_phys) dt_virt = phys_to_virt(dt_phys); #endif - if (!dt_virt || !early_init_dt_scan(dt_virt)) { + if (!dt_virt || !early_init_dt_scan(dt_virt, __pa(dt_virt))) { pr_crit("Error: invalid device tree blob" " at physical address %p\n", (void *)dt_phys); diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl index c55fd7696d40fc..c8cad33bf250ea 100644 --- a/arch/sh/kernel/syscalls/syscall.tbl +++ b/arch/sh/kernel/syscalls/syscall.tbl @@ -466,3 +466,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 757451c3ea1df6..0400078076e588 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -29,7 +29,7 @@ UTS_MACHINE := sparc # versions of gcc. Some gcc versions won't pass -Av8 to binutils when you # give -mcpu=v8. This silently worked with older bintutils versions but # does not any more. -KBUILD_CFLAGS += -m32 -mcpu=v8 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 +KBUILD_CFLAGS += -m32 -mcpu=v8 -pipe -mno-fpu $(call cc-option,-fcall-used-g5) $(call cc-option,-fcall-used-g7) KBUILD_CFLAGS += -Wa,-Av8 KBUILD_AFLAGS += -m32 -Wa,-Av8 @@ -45,7 +45,7 @@ export BITS := 64 UTS_MACHINE := sparc64 KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow -KBUILD_CFLAGS += -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare +KBUILD_CFLAGS += -ffixed-g4 -ffixed-g5 $(call cc-option,-fcall-used-g7) -Wno-sign-compare KBUILD_CFLAGS += -Wa,--undeclared-regs KBUILD_CFLAGS += $(call cc-option,-mtune=ultrasparc3) KBUILD_AFLAGS += -m64 -mcpu=ultrasparc -Wa,--undeclared-regs diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild index 43b0ae4c2c2112..17ee8a273aa6b4 100644 --- a/arch/sparc/include/asm/Kbuild +++ b/arch/sparc/include/asm/Kbuild @@ -4,3 +4,4 @@ generated-y += syscall_table_64.h generic-y += agp.h generic-y += kvm_para.h generic-y += mcs_spinlock.h +generic-y += text-patching.h diff --git a/arch/sparc/include/asm/hvtramp.h b/arch/sparc/include/asm/hvtramp.h index 688ea43af0f5d9..ce2453ea4f2be2 100644 --- a/arch/sparc/include/asm/hvtramp.h +++ b/arch/sparc/include/asm/hvtramp.h @@ -17,7 +17,7 @@ struct hvtramp_descr { __u64 fault_info_va; __u64 fault_info_pa; __u64 thread_reg; - struct hvtramp_mapping maps[1]; + struct hvtramp_mapping maps[]; }; void hv_cpu_startup(unsigned long hvdescr_pa); diff --git a/arch/sparc/include/asm/page.h b/arch/sparc/include/asm/page.h index 5e44cdf2a8f2bd..1a00cc0a1893eb 100644 --- a/arch/sparc/include/asm/page.h +++ b/arch/sparc/include/asm/page.h @@ -2,8 +2,6 @@ #ifndef ___ASM_SPARC_PAGE_H #define ___ASM_SPARC_PAGE_H -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) - #if defined(__sparc__) && defined(__arch64__) #include #else diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h index 9977c77374cd41..9954254ea5698e 100644 --- a/arch/sparc/include/asm/page_32.h +++ b/arch/sparc/include/asm/page_32.h @@ -11,9 +11,7 @@ #include -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #ifndef __ASSEMBLY__ diff --git a/arch/sparc/include/asm/page_64.h b/arch/sparc/include/asm/page_64.h index e9bd24821c93db..2a68ff5b6eabdf 100644 --- a/arch/sparc/include/asm/page_64.h +++ b/arch/sparc/include/asm/page_64.h @@ -4,9 +4,7 @@ #include -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include /* Flushing for D-cache alias handling is only needed if * the page size is smaller than 16K. diff --git a/arch/sparc/include/asm/parport_64.h b/arch/sparc/include/asm/parport_64.h index 4f530a270760d3..3068809ef9ad0c 100644 --- a/arch/sparc/include/asm/parport_64.h +++ b/arch/sparc/include/asm/parport_64.h @@ -243,7 +243,7 @@ static struct platform_driver ecpp_driver = { .of_match_table = ecpp_match, }, .probe = ecpp_probe, - .remove_new = ecpp_remove, + .remove = ecpp_remove, }; static int parport_pc_find_nonpci_ports(int autoirq, int autodma) diff --git a/arch/sparc/include/asm/vga.h b/arch/sparc/include/asm/vga.h deleted file mode 100644 index 2952d667d93634..00000000000000 --- a/arch/sparc/include/asm/vga.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Access to VGA videoram - * - * (c) 1998 Martin Mares - */ - -#ifndef _LINUX_ASM_VGA_H_ -#define _LINUX_ASM_VGA_H_ - -#include -#include -#include - -#define VT_BUF_HAVE_RW -#define VT_BUF_HAVE_MEMSETW -#define VT_BUF_HAVE_MEMCPYW -#define VT_BUF_HAVE_MEMMOVEW - -#undef scr_writew -#undef scr_readw - -static inline void scr_writew(u16 val, u16 *addr) -{ - BUG_ON((long) addr >= 0); - - *addr = val; -} - -static inline u16 scr_readw(const u16 *addr) -{ - BUG_ON((long) addr >= 0); - - return *addr; -} - -static inline void scr_memsetw(u16 *p, u16 v, unsigned int n) -{ - BUG_ON((long) p >= 0); - - memset16(p, cpu_to_le16(v), n / 2); -} - -static inline void scr_memcpyw(u16 *d, u16 *s, unsigned int n) -{ - BUG_ON((long) d >= 0); - - memcpy(d, s, n); -} - -static inline void scr_memmovew(u16 *d, u16 *s, unsigned int n) -{ - BUG_ON((long) d >= 0); - - memmove(d, s, n); -} - -#define VGA_MAP_MEM(x,s) (x) - -#endif diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h index 57084ed2f3c4ec..113cd9f353e35f 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -139,6 +139,8 @@ #define SCM_DEVMEM_DMABUF SO_DEVMEM_DMABUF #define SO_DEVMEM_DONTNEED 0x0059 +#define SCM_TS_OPT_ID 0x005a + #if !defined(__KERNEL__) diff --git a/arch/sparc/kernel/chmc.c b/arch/sparc/kernel/chmc.c index e020740620011b..d4c74d6b2e1b83 100644 --- a/arch/sparc/kernel/chmc.c +++ b/arch/sparc/kernel/chmc.c @@ -814,7 +814,7 @@ static struct platform_driver us3mc_driver = { .of_match_table = us3mc_match, }, .probe = us3mc_probe, - .remove_new = us3mc_remove, + .remove = us3mc_remove, }; static inline bool us3mc_platform(void) diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index e40c395db2026c..5cbd6ed5ef6fab 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -297,9 +297,7 @@ static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg, unsigned long hv_err; int i; - hdesc = kzalloc(sizeof(*hdesc) + - (sizeof(struct hvtramp_mapping) * - num_kernel_image_mappings - 1), + hdesc = kzalloc(struct_size(hdesc, maps, num_kernel_image_mappings), GFP_KERNEL); if (!hdesc) { printk(KERN_ERR "ldom_startcpu_cpuid: Cannot allocate " diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 80822f922e7671..fb31bc0c5b4882 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -42,12 +43,16 @@ SYSCALL_DEFINE0(getpagesize) unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, vm_flags_t vm_flags) { struct vm_unmapped_area_info info = {}; + bool file_hugepage = false; + + if (filp && is_file_hugepages(filp)) + file_hugepage = true; if (flags & MAP_FIXED) { /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if (!file_hugepage && (flags & MAP_SHARED) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -62,9 +67,13 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi info.length = len; info.low_limit = addr; info.high_limit = TASK_SIZE; - info.align_mask = (flags & MAP_SHARED) ? - (PAGE_MASK & (SHMLBA - 1)) : 0; - info.align_offset = pgoff << PAGE_SHIFT; + if (!file_hugepage) { + info.align_mask = (flags & MAP_SHARED) ? + (PAGE_MASK & (SHMLBA - 1)) : 0; + info.align_offset = pgoff << PAGE_SHIFT; + } else { + info.align_mask = huge_page_mask_align(filp); + } return vm_unmapped_area(&info); } diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index acade309dc2fbd..c5a284df7b417e 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,16 @@ static inline unsigned long COLOR_ALIGN(unsigned long addr, return base + off; } +static unsigned long get_align_mask(struct file *filp, unsigned long flags) +{ + if (filp && is_file_hugepages(filp)) + return huge_page_mask_align(filp); + if (filp || (flags & MAP_SHARED)) + return PAGE_MASK & (SHMLBA - 1); + + return 0; +} + unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, vm_flags_t vm_flags) { struct mm_struct *mm = current->mm; @@ -94,12 +105,16 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi unsigned long task_size = TASK_SIZE; int do_color_align; struct vm_unmapped_area_info info = {}; + bool file_hugepage = false; + + if (filp && is_file_hugepages(filp)) + file_hugepage = true; if (flags & MAP_FIXED) { /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if (!file_hugepage && (flags & MAP_SHARED) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -111,7 +126,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi return -ENOMEM; do_color_align = 0; - if (filp || (flags & MAP_SHARED)) + if ((filp || (flags & MAP_SHARED)) && !file_hugepage) do_color_align = 1; if (addr) { @@ -129,8 +144,9 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi info.length = len; info.low_limit = TASK_UNMAPPED_BASE; info.high_limit = min(task_size, VA_EXCLUDE_START); - info.align_mask = do_color_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; - info.align_offset = pgoff << PAGE_SHIFT; + info.align_mask = get_align_mask(filp, flags); + if (!file_hugepage) + info.align_offset = pgoff << PAGE_SHIFT; addr = vm_unmapped_area(&info); if ((addr & ~PAGE_MASK) && task_size > VA_EXCLUDE_END) { @@ -154,15 +170,19 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, unsigned long addr = addr0; int do_color_align; struct vm_unmapped_area_info info = {}; + bool file_hugepage = false; /* This should only ever run for 32-bit processes. */ BUG_ON(!test_thread_flag(TIF_32BIT)); + if (filp && is_file_hugepages(filp)) + file_hugepage = true; + if (flags & MAP_FIXED) { /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if (!file_hugepage && (flags & MAP_SHARED) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -172,7 +192,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, return -ENOMEM; do_color_align = 0; - if (filp || (flags & MAP_SHARED)) + if ((filp || (flags & MAP_SHARED)) && !file_hugepage) do_color_align = 1; /* requesting a specific address */ @@ -192,8 +212,9 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.length = len; info.low_limit = PAGE_SIZE; info.high_limit = mm->mmap_base; - info.align_mask = do_color_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; - info.align_offset = pgoff << PAGE_SHIFT; + info.align_mask = get_align_mask(filp, flags); + if (!file_hugepage) + info.align_offset = pgoff << PAGE_SHIFT; addr = vm_unmapped_area(&info); /* diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl index cfdfb3707c167c..727f99d333b304 100644 --- a/arch/sparc/kernel/syscalls/syscall.tbl +++ b/arch/sparc/kernel/syscalls/syscall.tbl @@ -508,3 +508,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index 08bbdc4585969c..578fd0d49f3066 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c @@ -255,6 +255,7 @@ static void mostek_write_byte(struct device *dev, u32 ofs, u8 val) static struct m48t59_plat_data m48t59_data = { .read_byte = mostek_read_byte, .write_byte = mostek_write_byte, + .yy_offset = 68, }; /* resource is set at runtime */ diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 60f1c8cc5363e6..b32f27f929d1ab 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -544,6 +544,7 @@ static void mostek_write_byte(struct device *dev, u32 ofs, u8 val) static struct m48t59_plat_data m48t59_data = { .read_byte = mostek_read_byte, .write_byte = mostek_write_byte, + .yy_offset = 68, }; static struct platform_device m48t59_rtc = { diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index d317a843f7ea9b..f1b86eb3034043 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S @@ -48,6 +48,11 @@ SECTIONS { _text = .; HEAD_TEXT + ALIGN_FUNCTION(); +#ifdef CONFIG_SPARC64 + /* Match text section symbols in head_64.S first */ + *head_64.o(.text) +#endif TEXT_TEXT SCHED_TEXT LOCK_TEXT diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c index cc91ca7a1e182c..eee601a0d2cfb0 100644 --- a/arch/sparc/mm/hugetlbpage.c +++ b/arch/sparc/mm/hugetlbpage.c @@ -19,114 +19,6 @@ #include #include -/* Slightly simplified from the non-hugepage variant because by - * definition we don't have to worry about any page coloring stuff - */ - -static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *filp, - unsigned long addr, - unsigned long len, - unsigned long pgoff, - unsigned long flags) -{ - struct hstate *h = hstate_file(filp); - unsigned long task_size = TASK_SIZE; - struct vm_unmapped_area_info info = {}; - - if (test_thread_flag(TIF_32BIT)) - task_size = STACK_TOP32; - - info.length = len; - info.low_limit = TASK_UNMAPPED_BASE; - info.high_limit = min(task_size, VA_EXCLUDE_START); - info.align_mask = PAGE_MASK & ~huge_page_mask(h); - addr = vm_unmapped_area(&info); - - if ((addr & ~PAGE_MASK) && task_size > VA_EXCLUDE_END) { - VM_BUG_ON(addr != -ENOMEM); - info.low_limit = VA_EXCLUDE_END; - info.high_limit = task_size; - addr = vm_unmapped_area(&info); - } - - return addr; -} - -static unsigned long -hugetlb_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - const unsigned long len, - const unsigned long pgoff, - const unsigned long flags) -{ - struct hstate *h = hstate_file(filp); - struct mm_struct *mm = current->mm; - unsigned long addr = addr0; - struct vm_unmapped_area_info info = {}; - - /* This should only ever run for 32-bit processes. */ - BUG_ON(!test_thread_flag(TIF_32BIT)); - - info.flags = VM_UNMAPPED_AREA_TOPDOWN; - info.length = len; - info.low_limit = PAGE_SIZE; - info.high_limit = mm->mmap_base; - info.align_mask = PAGE_MASK & ~huge_page_mask(h); - addr = vm_unmapped_area(&info); - - /* - * 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. - */ - if (addr & ~PAGE_MASK) { - VM_BUG_ON(addr != -ENOMEM); - info.flags = 0; - info.low_limit = TASK_UNMAPPED_BASE; - info.high_limit = STACK_TOP32; - addr = vm_unmapped_area(&info); - } - - return addr; -} - -unsigned long -hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - unsigned long task_size = TASK_SIZE; - - if (test_thread_flag(TIF_32BIT)) - task_size = STACK_TOP32; - - if (len & ~huge_page_mask(h)) - return -EINVAL; - if (len > task_size) - return -ENOMEM; - - if (flags & MAP_FIXED) { - if (prepare_hugepage_range(file, addr, len)) - return -EINVAL; - return addr; - } - - if (addr) { - addr = ALIGN(addr, huge_page_size(h)); - vma = find_vma(mm, addr); - if (task_size - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - if (!test_bit(MMF_TOPDOWN, &mm->flags)) - return hugetlb_get_unmapped_area_bottomup(file, addr, len, - pgoff, flags); - else - return hugetlb_get_unmapped_area_topdown(file, addr, len, - pgoff, flags); -} static pte_t sun4u_hugepage_shift_to_tte(pte_t entry, unsigned int shift) { diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile index 243dbfc4609d80..50ec2978cda539 100644 --- a/arch/sparc/vdso/Makefile +++ b/arch/sparc/vdso/Makefile @@ -46,7 +46,7 @@ CFL := $(PROFILING) -mcmodel=medlow -fPIC -O2 -fasynchronous-unwind-tables -m64 -fno-omit-frame-pointer -foptimize-sibling-calls \ -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO -SPARC_REG_CFLAGS = -ffixed-g4 -ffixed-g5 -fcall-used-g5 -fcall-used-g7 +SPARC_REG_CFLAGS = -ffixed-g4 -ffixed-g5 $(call cc-option,-fcall-used-g5) $(call cc-option,-fcall-used-g7) $(vobjs): KBUILD_CFLAGS := $(filter-out $(RANDSTRUCT_CFLAGS) $(GCC_PLUGINS_CFLAGS) $(SPARC_REG_CFLAGS),$(KBUILD_CFLAGS)) $(CFL) diff --git a/arch/sparc/vdso/vclock_gettime.c b/arch/sparc/vdso/vclock_gettime.c index e794edde675548..79607804ea1b0f 100644 --- a/arch/sparc/vdso/vclock_gettime.c +++ b/arch/sparc/vdso/vclock_gettime.c @@ -86,6 +86,11 @@ notrace static long vdso_fallback_gettimeofday(struct __kernel_old_timeval *tv, } #ifdef CONFIG_SPARC64 +notrace static __always_inline u64 __shr64(u64 val, int amt) +{ + return val >> amt; +} + notrace static __always_inline u64 vread_tick(void) { u64 ret; @@ -102,6 +107,21 @@ notrace static __always_inline u64 vread_tick_stick(void) return ret; } #else +notrace static __always_inline u64 __shr64(u64 val, int amt) +{ + u64 ret; + + __asm__ __volatile__("sllx %H1, 32, %%g1\n\t" + "srl %L1, 0, %L1\n\t" + "or %%g1, %L1, %%g1\n\t" + "srlx %%g1, %2, %L0\n\t" + "srlx %L0, 32, %H0" + : "=r" (ret) + : "r" (val), "r" (amt) + : "g1"); + return ret; +} + notrace static __always_inline u64 vread_tick(void) { register unsigned long long ret asm("o4"); @@ -154,7 +174,7 @@ notrace static __always_inline int do_realtime(struct vvar_data *vvar, ts->tv_sec = vvar->wall_time_sec; ns = vvar->wall_time_snsec; ns += vgetsns(vvar); - ns >>= vvar->clock.shift; + ns = __shr64(ns, vvar->clock.shift); } while (unlikely(vvar_read_retry(vvar, seq))); ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); @@ -174,7 +194,7 @@ notrace static __always_inline int do_realtime_stick(struct vvar_data *vvar, ts->tv_sec = vvar->wall_time_sec; ns = vvar->wall_time_snsec; ns += vgetsns_stick(vvar); - ns >>= vvar->clock.shift; + ns = __shr64(ns, vvar->clock.shift); } while (unlikely(vvar_read_retry(vvar, seq))); ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); @@ -194,7 +214,7 @@ notrace static __always_inline int do_monotonic(struct vvar_data *vvar, ts->tv_sec = vvar->monotonic_time_sec; ns = vvar->monotonic_time_snsec; ns += vgetsns(vvar); - ns >>= vvar->clock.shift; + ns = __shr64(ns, vvar->clock.shift); } while (unlikely(vvar_read_retry(vvar, seq))); ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); @@ -214,7 +234,7 @@ notrace static __always_inline int do_monotonic_stick(struct vvar_data *vvar, ts->tv_sec = vvar->monotonic_time_sec; ns = vvar->monotonic_time_snsec; ns += vgetsns_stick(vvar); - ns >>= vvar->clock.shift; + ns = __shr64(ns, vvar->clock.shift); } while (unlikely(vvar_read_retry(vvar, seq))); ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); diff --git a/arch/um/Kconfig b/arch/um/Kconfig index c89575d05021f1..18051b1cfce0a2 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -5,6 +5,7 @@ menu "UML-specific options" config UML bool default y + select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_HAS_CPU_FINALIZE_INIT select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL @@ -32,6 +33,8 @@ config UML select HAVE_ARCH_VMAP_STACK select HAVE_RUST select ARCH_HAS_UBSAN + select HAVE_ARCH_TRACEHOOK + select THREAD_INFO_IN_TASK config MMU bool @@ -94,7 +97,7 @@ config MAY_HAVE_RUNTIME_DEPS config STATIC_LINK bool "Force a static link" - depends on CC_CAN_LINK_STATIC_NO_RUNTIME_DEPS || !MAY_HAVE_RUNTIME_DEPS + depends on !MAY_HAVE_RUNTIME_DEPS help This option gives you the ability to force a static link of UML. Normally, UML is linked as a shared binary. This is inconvenient for @@ -209,8 +212,8 @@ config MMAPPER config PGTABLE_LEVELS int - default 3 if 3_LEVEL_PGTABLES - default 2 + default 4 if 64BIT + default 2 if !64BIT config UML_TIME_TRAVEL_SUPPORT bool @@ -227,6 +230,21 @@ config UML_TIME_TRAVEL_SUPPORT It is safe to say Y, but you probably don't need this. +config UML_MAX_USERSPACE_ITERATIONS + int + prompt "Maximum number of unscheduled userspace iterations" + default 10000 + depends on UML_TIME_TRAVEL_SUPPORT + help + In UML inf-cpu and ext time-travel mode userspace can run without being + interrupted. This will eventually overwhelm the kernel and create OOM + situations (mainly RCU not running). This setting specifies the number + of kernel/userspace switches (minor/major page fault, signal or syscall) + for the same userspace thread before the sched_clock is advanced by a + jiffie to trigger scheduling. + + Setting it to zero disables the feature. + config KASAN_SHADOW_OFFSET hex depends on KASAN diff --git a/arch/um/Makefile b/arch/um/Makefile index 00b63bac5effb5..1d36a613aad83d 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -61,7 +61,8 @@ KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \ $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ -Dlongjmp=kernel_longjmp -Dsetjmp=kernel_setjmp \ -Din6addr_loopback=kernel_in6addr_loopback \ - -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr + -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr \ + -D__close_range=kernel__close_range KBUILD_RUSTFLAGS += -Crelocation-model=pie @@ -70,7 +71,9 @@ KBUILD_AFLAGS += $(ARCH_INCLUDE) USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \ $(ARCH_INCLUDE) $(MODE_INCLUDE) $(filter -I%,$(CFLAGS)) \ -D_FILE_OFFSET_BITS=64 -idirafter $(srctree)/include \ - -idirafter $(objtree)/include -D__KERNEL__ -D__UM_HOST__ + -idirafter $(objtree)/include -D__KERNEL__ -D__UM_HOST__ \ + -include $(srctree)/include/linux/compiler-version.h \ + -include $(srctree)/include/linux/kconfig.h #This will adjust *FLAGS accordingly to the platform. include $(srctree)/$(ARCH_DIR)/Makefile-os-Linux diff --git a/arch/um/Makefile-skas b/arch/um/Makefile-skas index 67323b02899990..1a27e65bcb9c15 100644 --- a/arch/um/Makefile-skas +++ b/arch/um/Makefile-skas @@ -3,15 +3,15 @@ # Licensed under the GPL # -GPROF_OPT += -pg +export UM_GPROF_OPT += -pg ifdef CONFIG_CC_IS_CLANG -GCOV_OPT += -fprofile-instr-generate -fcoverage-mapping +export UM_GCOV_OPT += -fprofile-instr-generate -fcoverage-mapping else -GCOV_OPT += -fprofile-arcs -ftest-coverage +export UM_GCOV_OPT += -fprofile-arcs -ftest-coverage endif -CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT) -CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT) -LINK-$(CONFIG_GCOV) += $(GCOV_OPT) -LINK-$(CONFIG_GPROF) += $(GPROF_OPT) +CFLAGS-$(CONFIG_GCOV) += $(UM_GCOV_OPT) +CFLAGS-$(CONFIG_GPROF) += $(UM_GPROF_OPT) +LINK-$(CONFIG_GCOV) += $(UM_GCOV_OPT) +LINK-$(CONFIG_GPROF) += $(UM_GPROF_OPT) diff --git a/arch/um/configs/i386_defconfig b/arch/um/configs/i386_defconfig index e543cbac879259..1ffa088739f4fe 100644 --- a/arch/um/configs/i386_defconfig +++ b/arch/um/configs/i386_defconfig @@ -1,4 +1,3 @@ -CONFIG_3_LEVEL_PGTABLES=y # CONFIG_COMPACTION is not set CONFIG_BINFMT_MISC=m CONFIG_HOSTFS=y @@ -61,7 +60,6 @@ CONFIG_UML_NET_DAEMON=y CONFIG_UML_NET_MCAST=y CONFIG_UML_NET_SLIRP=y CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=y CONFIG_QUOTA=y CONFIG_AUTOFS_FS=m CONFIG_ISO9660_FS=m diff --git a/arch/um/configs/x86_64_defconfig b/arch/um/configs/x86_64_defconfig index 939cb12318cae5..03b10d3f68163c 100644 --- a/arch/um/configs/x86_64_defconfig +++ b/arch/um/configs/x86_64_defconfig @@ -59,7 +59,6 @@ CONFIG_UML_NET_DAEMON=y CONFIG_UML_NET_MCAST=y CONFIG_UML_NET_SLIRP=y CONFIG_EXT4_FS=y -CONFIG_REISERFS_FS=y CONFIG_QUOTA=y CONFIG_AUTOFS_FS=m CONFIG_ISO9660_FS=m diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index a66e556012c484..35f9beeb19b3fe 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -161,6 +161,8 @@ static __noreturn int winch_thread(void *arg) int count; char c = 1; + os_set_pdeathsig(); + pty_fd = data->pty_fd; pipe_fd = data->pipe_fd; count = write(pipe_fd, &c, sizeof(c)); diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index 9d228878cea2ed..0ac149de1ac013 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -48,6 +48,7 @@ MODULE_PARM_DESC(mixer, MIXER_HELP); #ifndef MODULE static int set_dsp(char *name, int *add) { + *add = 0; dsp = name; return 0; } @@ -56,6 +57,7 @@ __uml_setup("dsp=", set_dsp, "dsp=\n" DSP_HELP); static int set_mixer(char *name, int *add) { + *add = 0; mixer = name; return 0; } diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 77c4afb8ab9071..75d04fb4994a06 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -336,7 +336,7 @@ static struct platform_driver uml_net_driver = { static void net_device_release(struct device *dev) { - struct uml_net *device = dev_get_drvdata(dev); + struct uml_net *device = container_of(dev, struct uml_net, pdev.dev); struct net_device *netdev = device->dev; struct uml_net_private *lp = netdev_priv(netdev); diff --git a/arch/um/drivers/rtc_kern.c b/arch/um/drivers/rtc_kern.c index 3a1582219c4b85..134a58f93c859d 100644 --- a/arch/um/drivers/rtc_kern.c +++ b/arch/um/drivers/rtc_kern.c @@ -176,7 +176,7 @@ static void uml_rtc_remove(struct platform_device *pdev) static struct platform_driver uml_rtc_driver = { .probe = uml_rtc_probe, - .remove_new = uml_rtc_remove, + .remove = uml_rtc_remove, .driver = { .name = "uml-rtc", }, diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 7f28ec1929dc0b..66c1a8835e3627 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -779,7 +779,7 @@ static int ubd_open_dev(struct ubd *ubd_dev) static void ubd_device_release(struct device *dev) { - struct ubd *ubd_dev = dev_get_drvdata(dev); + struct ubd *ubd_dev = container_of(dev, struct ubd, pdev.dev); blk_mq_free_tag_set(&ubd_dev->tag_set); *ubd_dev = ((struct ubd) DEFAULT_UBD); @@ -898,6 +898,8 @@ static int ubd_add(int n, char **error_out) if (err) goto out_cleanup_disk; + ubd_dev->disk = disk; + return 0; out_cleanup_disk: @@ -1499,6 +1501,7 @@ int io_thread(void *arg) { int n, count, written, res; + os_set_pdeathsig(); os_fix_helper_signals(); while(1){ diff --git a/arch/um/drivers/vector_kern.c b/arch/um/drivers/vector_kern.c index c992da83268dd8..64c09db392c16a 100644 --- a/arch/um/drivers/vector_kern.c +++ b/arch/um/drivers/vector_kern.c @@ -815,7 +815,8 @@ static struct platform_driver uml_net_driver = { static void vector_device_release(struct device *dev) { - struct vector_device *device = dev_get_drvdata(dev); + struct vector_device *device = + container_of(dev, struct vector_device, pdev.dev); struct net_device *netdev = device->dev; list_del(&device->list); diff --git a/arch/um/drivers/vhost_user.h b/arch/um/drivers/vhost_user.h index 6f147cd3c9f76a..fcfa3b7e021bae 100644 --- a/arch/um/drivers/vhost_user.h +++ b/arch/um/drivers/vhost_user.h @@ -10,6 +10,7 @@ /* Feature bits */ #define VHOST_USER_F_PROTOCOL_FEATURES 30 /* Protocol feature bits */ +#define VHOST_USER_PROTOCOL_F_MQ 0 #define VHOST_USER_PROTOCOL_F_REPLY_ACK 3 #define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5 #define VHOST_USER_PROTOCOL_F_CONFIG 9 @@ -23,7 +24,8 @@ /* Supported transport features */ #define VHOST_USER_SUPPORTED_F BIT_ULL(VHOST_USER_F_PROTOCOL_FEATURES) /* Supported protocol features */ -#define VHOST_USER_SUPPORTED_PROTOCOL_F (BIT_ULL(VHOST_USER_PROTOCOL_F_REPLY_ACK) | \ +#define VHOST_USER_SUPPORTED_PROTOCOL_F (BIT_ULL(VHOST_USER_PROTOCOL_F_MQ) | \ + BIT_ULL(VHOST_USER_PROTOCOL_F_REPLY_ACK) | \ BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ) | \ BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG) | \ BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS)) diff --git a/arch/um/drivers/virtio_uml.c b/arch/um/drivers/virtio_uml.c index 2b6e701776b6b8..65df43fa9be58d 100644 --- a/arch/um/drivers/virtio_uml.c +++ b/arch/um/drivers/virtio_uml.c @@ -56,6 +56,7 @@ struct virtio_uml_device { int sock, req_fd, irq; u64 features; u64 protocol_features; + u64 max_vqs; u8 status; u8 registered:1; u8 suspended:1; @@ -72,8 +73,6 @@ struct virtio_uml_vq_info { bool suspended; }; -extern unsigned long long physmem_size, highmem; - #define vu_err(vu_dev, ...) dev_err(&(vu_dev)->pdev->dev, ##__VA_ARGS__) /* Vhost-user protocol */ @@ -343,6 +342,17 @@ static int vhost_user_set_protocol_features(struct virtio_uml_device *vu_dev, protocol_features); } +static int vhost_user_get_queue_num(struct virtio_uml_device *vu_dev, + u64 *queue_num) +{ + int rc = vhost_user_send_no_payload(vu_dev, true, + VHOST_USER_GET_QUEUE_NUM); + + if (rc) + return rc; + return vhost_user_recv_u64(vu_dev, queue_num); +} + static void vhost_user_reply(struct virtio_uml_device *vu_dev, struct vhost_user_msg *msg, int response) { @@ -516,6 +526,15 @@ static int vhost_user_init(struct virtio_uml_device *vu_dev) return rc; } + if (vu_dev->protocol_features & + BIT_ULL(VHOST_USER_PROTOCOL_F_MQ)) { + rc = vhost_user_get_queue_num(vu_dev, &vu_dev->max_vqs); + if (rc) + return rc; + } else { + vu_dev->max_vqs = U64_MAX; + } + return 0; } @@ -625,7 +644,7 @@ static int vhost_user_set_mem_table(struct virtio_uml_device *vu_dev) { struct vhost_user_msg msg = { .header.request = VHOST_USER_SET_MEM_TABLE, - .header.size = sizeof(msg.payload.mem_regions), + .header.size = offsetof(typeof(msg.payload.mem_regions), regions[1]), .payload.mem_regions.num = 1, }; unsigned long reserved = uml_reserved - uml_physmem; @@ -673,13 +692,6 @@ static int vhost_user_set_mem_table(struct virtio_uml_device *vu_dev) if (rc < 0) return rc; - if (highmem) { - msg.payload.mem_regions.num++; - rc = vhost_user_init_mem_region(__pa(end_iomem), highmem, - &fds[1], &msg.payload.mem_regions.regions[1]); - if (rc < 0) - return rc; - } return vhost_user_send(vu_dev, false, &msg, fds, msg.payload.mem_regions.num); @@ -897,7 +909,7 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev, { struct virtio_uml_vq_info *info = vq->priv; int call_fds[2]; - int rc; + int rc, irq; /* no call FD needed/desired in this case */ if (vu_dev->protocol_features & @@ -914,19 +926,23 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev, return rc; info->call_fd = call_fds[0]; - rc = um_request_irq(vu_dev->irq, info->call_fd, IRQ_READ, - vu_interrupt, IRQF_SHARED, info->name, vq); - if (rc < 0) + irq = um_request_irq(vu_dev->irq, info->call_fd, IRQ_READ, + vu_interrupt, IRQF_SHARED, info->name, vq); + if (irq < 0) { + rc = irq; goto close_both; + } rc = vhost_user_set_vring_call(vu_dev, vq->index, call_fds[1]); if (rc) goto release_irq; + vu_dev->irq = irq; + goto out; release_irq: - um_free_irq(vu_dev->irq, vq); + um_free_irq(irq, vq); close_both: os_close_file(call_fds[0]); out: @@ -1023,7 +1039,9 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vq; /* not supported for now */ - if (WARN_ON(nvqs > 64)) + if (WARN(nvqs > 64 || nvqs > vu_dev->max_vqs, + "%d VQs requested, only up to 64 or %lld supported\n", + nvqs, vu_dev->max_vqs)) return -EINVAL; rc = vhost_user_set_mem_table(vu_dev); @@ -1210,6 +1228,7 @@ static int virtio_uml_probe(struct platform_device *pdev) vu_dev->vdev.id.vendor = VIRTIO_DEV_ANY_ID; vu_dev->pdev = pdev; vu_dev->req_fd = -1; + vu_dev->irq = UM_IRQ_ALLOC; time_travel_propagate_time(); @@ -1446,7 +1465,7 @@ static int virtio_uml_resume(struct platform_device *pdev) static struct platform_driver virtio_uml_driver = { .probe = virtio_uml_probe, - .remove_new = virtio_uml_remove, + .remove = virtio_uml_remove, .driver = { .name = "virtio-uml", .of_match_table = virtio_uml_match, diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index 18f902da8e9976..428f2c5158c2ac 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 generic-y += bug.h generic-y += compat.h -generic-y += current.h generic-y += device.h generic-y += dma-mapping.h generic-y += emergency-restart.h diff --git a/arch/um/include/asm/current.h b/arch/um/include/asm/current.h new file mode 100644 index 00000000000000..de64e032d66c1a --- /dev/null +++ b/arch/um/include/asm/current.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_CURRENT_H +#define __ASM_CURRENT_H + +#include +#include + +#ifndef __ASSEMBLY__ + +struct task_struct; +extern struct task_struct *cpu_tasks[NR_CPUS]; + +static __always_inline struct task_struct *get_current(void) +{ + return cpu_tasks[0]; +} + + +#define current get_current() + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_CURRENT_H */ diff --git a/arch/um/include/asm/page.h b/arch/um/include/asm/page.h index 9ef9a8aedfa661..3d516f3ca9c745 100644 --- a/arch/um/include/asm/page.h +++ b/arch/um/include/asm/page.h @@ -9,10 +9,7 @@ #include -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #ifndef __ASSEMBLY__ @@ -32,51 +29,35 @@ struct page; #define clear_user_page(page, vaddr, pg) clear_page(page) #define copy_user_page(to, from, vaddr, pg) copy_page(to, from) -#if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64BIT) - typedef struct { unsigned long pte; } pte_t; -typedef struct { unsigned long pmd; } pmd_t; typedef struct { unsigned long pgd; } pgd_t; -#define pte_val(p) ((p).pte) -#define pte_get_bits(p, bits) ((p).pte & (bits)) -#define pte_set_bits(p, bits) ((p).pte |= (bits)) -#define pte_clear_bits(p, bits) ((p).pte &= ~(bits)) -#define pte_copy(to, from) ({ (to).pte = (from).pte; }) -#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE)) -#define pte_set_val(p, phys, prot) \ - ({ (p).pte = (phys) | pgprot_val(prot); }) +#if CONFIG_PGTABLE_LEVELS > 2 +typedef struct { unsigned long pmd; } pmd_t; #define pmd_val(x) ((x).pmd) #define __pmd(x) ((pmd_t) { (x) } ) -typedef unsigned long long phys_t; +#if CONFIG_PGTABLE_LEVELS > 3 -#else - -typedef struct { unsigned long pte; } pte_t; -typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pud; } pud_t; +#define pud_val(x) ((x).pud) +#define __pud(x) ((pud_t) { (x) } ) -#ifdef CONFIG_3_LEVEL_PGTABLES -typedef struct { unsigned long pmd; } pmd_t; -#define pmd_val(x) ((x).pmd) -#define __pmd(x) ((pmd_t) { (x) } ) -#endif +#endif /* CONFIG_PGTABLE_LEVELS > 3 */ +#endif /* CONFIG_PGTABLE_LEVELS > 2 */ #define pte_val(x) ((x).pte) - #define pte_get_bits(p, bits) ((p).pte & (bits)) #define pte_set_bits(p, bits) ((p).pte |= (bits)) #define pte_clear_bits(p, bits) ((p).pte &= ~(bits)) #define pte_copy(to, from) ((to).pte = (from).pte) -#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE)) +#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEEDSYNC)) #define pte_set_val(p, phys, prot) (p).pte = (phys | pgprot_val(prot)) typedef unsigned long phys_t; -#endif - typedef struct { unsigned long pgprot; } pgprot_t; typedef struct page *pgtable_t; diff --git a/arch/um/include/asm/pgalloc.h b/arch/um/include/asm/pgalloc.h index de5e31c64793d7..04fb4e6969a46d 100644 --- a/arch/um/include/asm/pgalloc.h +++ b/arch/um/include/asm/pgalloc.h @@ -31,7 +31,7 @@ do { \ tlb_remove_page_ptdesc((tlb), (page_ptdesc(pte))); \ } while (0) -#ifdef CONFIG_3_LEVEL_PGTABLES +#if CONFIG_PGTABLE_LEVELS > 2 #define __pmd_free_tlb(tlb, pmd, address) \ do { \ @@ -39,6 +39,15 @@ do { \ tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(pmd)); \ } while (0) +#if CONFIG_PGTABLE_LEVELS > 3 + +#define __pud_free_tlb(tlb, pud, address) \ +do { \ + pagetable_pud_dtor(virt_to_ptdesc(pud)); \ + tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(pud)); \ +} while (0) + +#endif #endif #endif diff --git a/arch/um/include/asm/pgtable-2level.h b/arch/um/include/asm/pgtable-2level.h index 8256ecc5b91986..ab0c8dd8656486 100644 --- a/arch/um/include/asm/pgtable-2level.h +++ b/arch/um/include/asm/pgtable-2level.h @@ -31,7 +31,7 @@ printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), \ pgd_val(e)) -static inline int pgd_newpage(pgd_t pgd) { return 0; } +static inline int pgd_needsync(pgd_t pgd) { return 0; } static inline void pgd_mkuptodate(pgd_t pgd) { } #define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) diff --git a/arch/um/include/asm/pgtable-3level.h b/arch/um/include/asm/pgtable-3level.h deleted file mode 100644 index 8a5032ec231fd9..00000000000000 --- a/arch/um/include/asm/pgtable-3level.h +++ /dev/null @@ -1,100 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright 2003 PathScale Inc - * Derived from include/asm-i386/pgtable.h - */ - -#ifndef __UM_PGTABLE_3LEVEL_H -#define __UM_PGTABLE_3LEVEL_H - -#include - -/* PGDIR_SHIFT determines what a third-level page table entry can map */ - -#ifdef CONFIG_64BIT -#define PGDIR_SHIFT 30 -#else -#define PGDIR_SHIFT 31 -#endif -#define PGDIR_SIZE (1UL << PGDIR_SHIFT) -#define PGDIR_MASK (~(PGDIR_SIZE-1)) - -/* PMD_SHIFT determines the size of the area a second-level page table can - * map - */ - -#define PMD_SHIFT 21 -#define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1)) - -/* - * entries per page directory level - */ - -#define PTRS_PER_PTE 512 -#ifdef CONFIG_64BIT -#define PTRS_PER_PMD 512 -#define PTRS_PER_PGD 512 -#else -#define PTRS_PER_PMD 1024 -#define PTRS_PER_PGD 1024 -#endif - -#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) - -#define pte_ERROR(e) \ - printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), \ - pte_val(e)) -#define pmd_ERROR(e) \ - printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ - pmd_val(e)) -#define pgd_ERROR(e) \ - printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ - pgd_val(e)) - -#define pud_none(x) (!(pud_val(x) & ~_PAGE_NEWPAGE)) -#define pud_bad(x) ((pud_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) -#define pud_present(x) (pud_val(x) & _PAGE_PRESENT) -#define pud_populate(mm, pud, pmd) \ - set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd))) - -#define set_pud(pudptr, pudval) (*(pudptr) = (pudval)) - -static inline int pgd_newpage(pgd_t pgd) -{ - return(pgd_val(pgd) & _PAGE_NEWPAGE); -} - -static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEWPAGE; } - -#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) - -static inline void pud_clear (pud_t *pud) -{ - set_pud(pud, __pud(_PAGE_NEWPAGE)); -} - -#define pud_page(pud) phys_to_page(pud_val(pud) & PAGE_MASK) -#define pud_pgtable(pud) ((pmd_t *) __va(pud_val(pud) & PAGE_MASK)) - -static inline unsigned long pte_pfn(pte_t pte) -{ - return phys_to_pfn(pte_val(pte)); -} - -static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) -{ - pte_t pte; - phys_t phys = pfn_to_phys(page_nr); - - pte_set_val(pte, phys, pgprot); - return pte; -} - -static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) -{ - return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); -} - -#endif - diff --git a/arch/um/include/asm/pgtable-4level.h b/arch/um/include/asm/pgtable-4level.h new file mode 100644 index 00000000000000..0d279caee93ccd --- /dev/null +++ b/arch/um/include/asm/pgtable-4level.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2003 PathScale Inc + * Derived from include/asm-i386/pgtable.h + */ + +#ifndef __UM_PGTABLE_4LEVEL_H +#define __UM_PGTABLE_4LEVEL_H + +#include + +/* PGDIR_SHIFT determines what a fourth-level page table entry can map */ + +#define PGDIR_SHIFT 39 +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) + +/* PUD_SHIFT determines the size of the area a third-level page table can + * map + */ + +#define PUD_SHIFT 30 +#define PUD_SIZE (1UL << PUD_SHIFT) +#define PUD_MASK (~(PUD_SIZE-1)) + +/* PMD_SHIFT determines the size of the area a second-level page table can + * map + */ + +#define PMD_SHIFT 21 +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* + * entries per page directory level + */ + +#define PTRS_PER_PTE 512 +#define PTRS_PER_PMD 512 +#define PTRS_PER_PUD 512 +#define PTRS_PER_PGD 512 + +#define USER_PTRS_PER_PGD ((TASK_SIZE + (PGDIR_SIZE - 1)) / PGDIR_SIZE) + +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pte_val(e)) +#define pmd_ERROR(e) \ + printk("%s:%d: bad pmd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pmd_val(e)) +#define pud_ERROR(e) \ + printk("%s:%d: bad pud %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pud_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %p(%016lx).\n", __FILE__, __LINE__, &(e), \ + pgd_val(e)) + +#define pud_none(x) (!(pud_val(x) & ~_PAGE_NEEDSYNC)) +#define pud_bad(x) ((pud_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define pud_present(x) (pud_val(x) & _PAGE_PRESENT) +#define pud_populate(mm, pud, pmd) \ + set_pud(pud, __pud(_PAGE_TABLE + __pa(pmd))) + +#define set_pud(pudptr, pudval) (*(pudptr) = (pudval)) + +#define p4d_none(x) (!(p4d_val(x) & ~_PAGE_NEEDSYNC)) +#define p4d_bad(x) ((p4d_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) +#define p4d_present(x) (p4d_val(x) & _PAGE_PRESENT) +#define p4d_populate(mm, p4d, pud) \ + set_p4d(p4d, __p4d(_PAGE_TABLE + __pa(pud))) + +#define set_p4d(p4dptr, p4dval) (*(p4dptr) = (p4dval)) + + +static inline int pgd_needsync(pgd_t pgd) +{ + return pgd_val(pgd) & _PAGE_NEEDSYNC; +} + +static inline void pgd_mkuptodate(pgd_t pgd) { pgd_val(pgd) &= ~_PAGE_NEEDSYNC; } + +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval)) + +static inline void pud_clear (pud_t *pud) +{ + set_pud(pud, __pud(_PAGE_NEEDSYNC)); +} + +static inline void p4d_clear (p4d_t *p4d) +{ + set_p4d(p4d, __p4d(_PAGE_NEEDSYNC)); +} + +#define pud_page(pud) phys_to_page(pud_val(pud) & PAGE_MASK) +#define pud_pgtable(pud) ((pmd_t *) __va(pud_val(pud) & PAGE_MASK)) + +#define p4d_page(p4d) phys_to_page(p4d_val(p4d) & PAGE_MASK) +#define p4d_pgtable(p4d) ((pud_t *) __va(p4d_val(p4d) & PAGE_MASK)) + +static inline unsigned long pte_pfn(pte_t pte) +{ + return phys_to_pfn(pte_val(pte)); +} + +static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) +{ + pte_t pte; + phys_t phys = pfn_to_phys(page_nr); + + pte_set_val(pte, phys, pgprot); + return pte; +} + +static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) +{ + return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)); +} + +#endif diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index 83373c9963e7c9..0bd60afcc37d53 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h @@ -11,8 +11,7 @@ #include #define _PAGE_PRESENT 0x001 -#define _PAGE_NEWPAGE 0x002 -#define _PAGE_NEWPROT 0x004 +#define _PAGE_NEEDSYNC 0x002 #define _PAGE_RW 0x020 #define _PAGE_USER 0x040 #define _PAGE_ACCESSED 0x080 @@ -24,10 +23,12 @@ /* We borrow bit 10 to store the exclusive marker in swap PTEs. */ #define _PAGE_SWP_EXCLUSIVE 0x400 -#ifdef CONFIG_3_LEVEL_PGTABLES -#include -#else +#if CONFIG_PGTABLE_LEVELS == 4 +#include +#elif CONFIG_PGTABLE_LEVELS == 2 #include +#else +#error "Unsupported number of page table levels" #endif extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; @@ -78,22 +79,22 @@ extern unsigned long end_iomem; */ #define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) -#define pte_clear(mm,addr,xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEWPAGE)) +#define pte_clear(mm, addr, xp) pte_set_val(*(xp), (phys_t) 0, __pgprot(_PAGE_NEEDSYNC)) -#define pmd_none(x) (!((unsigned long)pmd_val(x) & ~_PAGE_NEWPAGE)) +#define pmd_none(x) (!((unsigned long)pmd_val(x) & ~_PAGE_NEEDSYNC)) #define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) -#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0) +#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEEDSYNC; } while (0) -#define pmd_newpage(x) (pmd_val(x) & _PAGE_NEWPAGE) -#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE) +#define pmd_needsync(x) (pmd_val(x) & _PAGE_NEEDSYNC) +#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEEDSYNC) -#define pud_newpage(x) (pud_val(x) & _PAGE_NEWPAGE) -#define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEWPAGE) +#define pud_needsync(x) (pud_val(x) & _PAGE_NEEDSYNC) +#define pud_mkuptodate(x) (pud_val(x) &= ~_PAGE_NEEDSYNC) -#define p4d_newpage(x) (p4d_val(x) & _PAGE_NEWPAGE) -#define p4d_mkuptodate(x) (p4d_val(x) &= ~_PAGE_NEWPAGE) +#define p4d_needsync(x) (p4d_val(x) & _PAGE_NEEDSYNC) +#define p4d_mkuptodate(x) (p4d_val(x) &= ~_PAGE_NEEDSYNC) #define pmd_pfn(pmd) (pmd_val(pmd) >> PAGE_SHIFT) #define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK) @@ -144,14 +145,9 @@ static inline int pte_young(pte_t pte) return pte_get_bits(pte, _PAGE_ACCESSED); } -static inline int pte_newpage(pte_t pte) +static inline int pte_needsync(pte_t pte) { - return pte_get_bits(pte, _PAGE_NEWPAGE); -} - -static inline int pte_newprot(pte_t pte) -{ - return(pte_present(pte) && (pte_get_bits(pte, _PAGE_NEWPROT))); + return pte_get_bits(pte, _PAGE_NEEDSYNC); } /* @@ -160,12 +156,6 @@ static inline int pte_newprot(pte_t pte) * ================================= */ -static inline pte_t pte_mknewprot(pte_t pte) -{ - pte_set_bits(pte, _PAGE_NEWPROT); - return(pte); -} - static inline pte_t pte_mkclean(pte_t pte) { pte_clear_bits(pte, _PAGE_DIRTY); @@ -180,19 +170,14 @@ static inline pte_t pte_mkold(pte_t pte) static inline pte_t pte_wrprotect(pte_t pte) { - if (likely(pte_get_bits(pte, _PAGE_RW))) - pte_clear_bits(pte, _PAGE_RW); - else - return pte; - return(pte_mknewprot(pte)); + pte_clear_bits(pte, _PAGE_RW); + return pte; } static inline pte_t pte_mkread(pte_t pte) { - if (unlikely(pte_get_bits(pte, _PAGE_USER))) - return pte; pte_set_bits(pte, _PAGE_USER); - return(pte_mknewprot(pte)); + return pte; } static inline pte_t pte_mkdirty(pte_t pte) @@ -209,23 +194,19 @@ static inline pte_t pte_mkyoung(pte_t pte) static inline pte_t pte_mkwrite_novma(pte_t pte) { - if (unlikely(pte_get_bits(pte, _PAGE_RW))) - return pte; pte_set_bits(pte, _PAGE_RW); - return(pte_mknewprot(pte)); + return pte; } static inline pte_t pte_mkuptodate(pte_t pte) { - pte_clear_bits(pte, _PAGE_NEWPAGE); - if(pte_present(pte)) - pte_clear_bits(pte, _PAGE_NEWPROT); - return(pte); + pte_clear_bits(pte, _PAGE_NEEDSYNC); + return pte; } -static inline pte_t pte_mknewpage(pte_t pte) +static inline pte_t pte_mkneedsync(pte_t pte) { - pte_set_bits(pte, _PAGE_NEWPAGE); + pte_set_bits(pte, _PAGE_NEEDSYNC); return(pte); } @@ -233,13 +214,11 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval) { pte_copy(*pteptr, pteval); - /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so - * fix_range knows to unmap it. _PAGE_NEWPROT is specific to - * mapped pages. + /* If it's a swap entry, it needs to be marked _PAGE_NEEDSYNC so + * update_pte_range knows to unmap it. */ - *pteptr = pte_mknewpage(*pteptr); - if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr); + *pteptr = pte_mkneedsync(*pteptr); } #define PFN_PTE_SHIFT PAGE_SHIFT @@ -279,7 +258,7 @@ static inline void set_ptes(struct mm_struct *mm, unsigned long addr, #define __HAVE_ARCH_PTE_SAME static inline int pte_same(pte_t pte_a, pte_t pte_b) { - return !((pte_val(pte_a) ^ pte_val(pte_b)) & ~_PAGE_NEWPAGE); + return !((pte_val(pte_a) ^ pte_val(pte_b)) & ~_PAGE_NEEDSYNC); } /* @@ -287,17 +266,13 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b) * and a page entry and page directory to the page they refer to. */ -#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys)) #define __virt_to_page(virt) phys_to_page(__pa(virt)) -#define page_to_phys(page) pfn_to_phys(page_to_pfn(page)) #define virt_to_page(addr) __virt_to_page((const unsigned long) addr) #define mk_pte(page, pgprot) \ ({ pte_t pte; \ \ pte_set_val(pte, page_to_phys(page), (pgprot)); \ - if (pte_present(pte)) \ - pte_mknewprot(pte_mknewpage(pte)); \ pte;}) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) @@ -331,7 +306,7 @@ extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); * <--------------- offset ----------------> E < type -> 0 0 0 1 0 * * E is the exclusive marker that is not stored in swap entries. - * _PAGE_NEWPAGE (bit 1) is always set to 1 in set_pte(). + * _PAGE_NEEDSYNC (bit 1) is always set to 1 in set_pte(). */ #define __swp_type(x) (((x).val >> 5) & 0x1f) #define __swp_offset(x) ((x).val >> 11) diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index bce4595798dae5..5d6356eafffee0 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h @@ -20,10 +20,7 @@ struct task_struct; struct mm_struct; struct thread_struct { - struct pt_regs regs; struct pt_regs *segv_regs; - void *fault_addr; - jmp_buf *fault_catcher; struct task_struct *prev_sched; struct arch_thread arch; jmp_buf switch_buf; @@ -33,12 +30,14 @@ struct thread_struct { void *arg; } thread; } request; + + /* Contains variable sized FP registers */ + struct pt_regs regs; }; #define INIT_THREAD \ { \ .regs = EMPTY_REGS, \ - .fault_addr = NULL, \ .prev_sched = NULL, \ .arch = INIT_ARCH_THREAD, \ .request = { } \ diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h index c7b4b49826a2aa..f9ad06fcc991a2 100644 --- a/arch/um/include/asm/thread_info.h +++ b/arch/um/include/asm/thread_info.h @@ -17,35 +17,17 @@ #include struct thread_info { - struct task_struct *task; /* main task structure */ unsigned long flags; /* low level flags */ __u32 cpu; /* current CPU */ int preempt_count; /* 0 => preemptable, <0 => BUG */ - struct thread_info *real_thread; /* Points to non-IRQ stack */ - unsigned long aux_fp_regs[FP_SIZE]; /* auxiliary fp_regs to save/restore - them out-of-band */ }; #define INIT_THREAD_INFO(tsk) \ { \ - .task = &tsk, \ .flags = 0, \ .cpu = 0, \ .preempt_count = INIT_PREEMPT_COUNT, \ - .real_thread = NULL, \ -} - -/* how to get the thread information struct from C */ -static inline struct thread_info *current_thread_info(void) -{ - struct thread_info *ti; - unsigned long mask = THREAD_SIZE - 1; - void *p; - - asm volatile ("" : "=r" (p) : "0" (&ti)); - ti = (struct thread_info *) (((unsigned long)p) & ~mask); - return ti; } #endif diff --git a/arch/um/include/asm/tlbflush.h b/arch/um/include/asm/tlbflush.h index db997976b6eada..13a3009942be6b 100644 --- a/arch/um/include/asm/tlbflush.h +++ b/arch/um/include/asm/tlbflush.h @@ -9,8 +9,8 @@ #include /* - * In UML, we need to sync the TLB over by using mmap/munmap/mprotect syscalls - * from the process handling the MM (which can be the kernel itself). + * In UML, we need to sync the TLB over by using mmap/munmap syscalls from + * the process handling the MM (which can be the kernel itself). * * To track updates, we can hook into set_ptes and flush_tlb_*. With set_ptes * we catch all PTE transitions where memory that was unusable becomes usable. diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h index 06292fca5a4da5..ea65f151bf4847 100644 --- a/arch/um/include/shared/as-layout.h +++ b/arch/um/include/shared/as-layout.h @@ -30,25 +30,23 @@ #include -struct cpu_task { - void *task; -}; +struct task_struct; +extern struct task_struct *cpu_tasks[]; -extern struct cpu_task cpu_tasks[]; +extern unsigned long long physmem_size; extern unsigned long high_physmem; extern unsigned long uml_physmem; extern unsigned long uml_reserved; extern unsigned long end_vm; extern unsigned long start_vm; -extern unsigned long long highmem; extern unsigned long brk_start; extern unsigned long host_task_size; extern unsigned long stub_start; -extern int linux_main(int argc, char **argv); +extern int linux_main(int argc, char **argv, char **envp); extern void uml_finishsetup(void); struct siginfo; diff --git a/arch/um/include/shared/common-offsets.h b/arch/um/include/shared/common-offsets.h index 579ed946a3a9a1..73f3a4792ed8ba 100644 --- a/arch/um/include/shared/common-offsets.h +++ b/arch/um/include/shared/common-offsets.h @@ -6,7 +6,6 @@ DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE); DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE); DEFINE(UM_KERN_PAGE_MASK, PAGE_MASK); DEFINE(UM_KERN_PAGE_SHIFT, PAGE_SHIFT); -DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); DEFINE(UM_GFP_KERNEL, GFP_KERNEL); DEFINE(UM_GFP_ATOMIC, GFP_ATOMIC); @@ -15,17 +14,3 @@ DEFINE(UM_THREAD_SIZE, THREAD_SIZE); DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC); DEFINE(UM_NSEC_PER_USEC, NSEC_PER_USEC); - -#ifdef CONFIG_PRINTK -DEFINE(UML_CONFIG_PRINTK, CONFIG_PRINTK); -#endif -#ifdef CONFIG_UML_X86 -DEFINE(UML_CONFIG_UML_X86, CONFIG_UML_X86); -#endif -#ifdef CONFIG_64BIT -DEFINE(UML_CONFIG_64BIT, CONFIG_64BIT); -#endif -#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT -DEFINE(UML_CONFIG_UML_TIME_TRAVEL_SUPPORT, CONFIG_UML_TIME_TRAVEL_SUPPORT); -#endif - diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h index d8ffd2db168e00..f21dc851753812 100644 --- a/arch/um/include/shared/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -60,7 +60,6 @@ extern unsigned long from_irq_stack(int nested); extern int singlestepping(void); extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); -extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs); extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); extern void fatal_sigsegv(void) __attribute__ ((noreturn)); diff --git a/arch/um/include/shared/mem_user.h b/arch/um/include/shared/mem_user.h index 11a723a58545e7..adfa08062f88e7 100644 --- a/arch/um/include/shared/mem_user.h +++ b/arch/um/include/shared/mem_user.h @@ -47,10 +47,9 @@ extern int iomem_size; #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1)) extern unsigned long find_iomem(char *driver, unsigned long *len_out); -extern void mem_total_pages(unsigned long physmem, unsigned long iomem, - unsigned long highmem); +extern void mem_total_pages(unsigned long physmem, unsigned long iomem); extern void setup_physmem(unsigned long start, unsigned long usable, - unsigned long len, unsigned long long highmem); + unsigned long len); extern void map_memory(unsigned long virt, unsigned long phys, unsigned long len, int r, int w, int x); diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 9a039d6f1f7483..5babad8c5f75ed 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -145,7 +145,6 @@ extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); extern int os_get_ifname(int fd, char *namebuf); extern int os_set_slip(int fd); extern int os_mode_fd(int fd, int mode); -extern int os_fsync_file(int fd); extern int os_seek_file(int fd, unsigned long long offset); extern int os_open_file(const char *file, struct openflags flags, int mode); @@ -199,15 +198,11 @@ extern int create_mem_file(unsigned long long len); extern void report_enomem(void); /* process.c */ -extern unsigned long os_process_pc(int pid); -extern int os_process_parent(int pid); extern void os_alarm_process(int pid); -extern void os_stop_process(int pid); extern void os_kill_process(int pid, int reap_child); extern void os_kill_ptraced_process(int pid, int reap_child); extern int os_getpid(void); -extern int os_getpgrp(void); extern void init_new_thread_signals(void); @@ -220,6 +215,8 @@ extern int os_drop_memory(void *addr, int length); extern int can_drop_memory(void); extern int os_mincore(void *addr, unsigned long len); +void os_set_pdeathsig(void); + /* execvp.c */ extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); /* helper.c */ @@ -244,7 +241,6 @@ extern void block_signals(void); extern void unblock_signals(void); extern int um_set_signals(int enable); extern int um_set_signals_trace(int enable); -extern int os_is_signal_stack(void); extern void deliver_alarm(void); extern void register_pm_wake_signal(void); extern void block_signals_hard(void); @@ -283,13 +279,11 @@ int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot, int phys_fd, unsigned long long offset); int unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len); -int protect(struct mm_id *mm_idp, unsigned long addr, - unsigned long len, unsigned int prot); /* skas/process.c */ extern int is_skas_winch(int pid, int fd, void *data); extern int start_userspace(unsigned long stub_stack); -extern void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs); +extern void userspace(struct uml_pt_regs *regs); extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)); extern void switch_threads(jmp_buf *me, jmp_buf *you); extern int start_idle_thread(void *stack, jmp_buf *switch_buf); @@ -329,9 +323,6 @@ extern int __ignore_sigio_fd(int fd); /* tty.c */ extern int get_pty(void); -/* sys-$ARCH/task_size.c */ -extern unsigned long os_get_top_address(void); - long syscall(long number, ...); /* irqflags tracing */ diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h index a0450326521cd5..7d81b2339a48ea 100644 --- a/arch/um/include/shared/registers.h +++ b/arch/um/include/shared/registers.h @@ -8,12 +8,6 @@ #include -extern int save_i387_registers(int pid, unsigned long *fp_regs); -extern int restore_i387_registers(int pid, unsigned long *fp_regs); -extern int save_fp_registers(int pid, unsigned long *fp_regs); -extern int restore_fp_registers(int pid, unsigned long *fp_regs); -extern int save_fpx_registers(int pid, unsigned long *fp_regs); -extern int restore_fpx_registers(int pid, unsigned long *fp_regs); extern int init_pid_registers(int pid); extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs); extern int get_fp_registers(int pid, unsigned long *regs); diff --git a/arch/um/include/shared/skas/stub-data.h b/arch/um/include/shared/skas/stub-data.h index 2b6b44759dfaf1..81a4cace032c95 100644 --- a/arch/um/include/shared/skas/stub-data.h +++ b/arch/um/include/shared/skas/stub-data.h @@ -12,6 +12,17 @@ #include #include +struct stub_init_data { + unsigned long stub_start; + + int stub_code_fd; + unsigned long stub_code_offset; + int stub_data_fd; + unsigned long stub_data_offset; + + unsigned long segv_handler; +}; + #define STUB_NEXT_SYSCALL(s) \ ((struct stub_syscall *) (((unsigned long) s) + (s)->cmd_len)) @@ -19,7 +30,6 @@ enum stub_syscall_type { STUB_SYSCALL_UNSET = 0, STUB_SYSCALL_MMAP, STUB_SYSCALL_MUNMAP, - STUB_SYSCALL_MPROTECT, }; struct stub_syscall { diff --git a/arch/um/include/shared/timetravel.h b/arch/um/include/shared/timetravel.h index c8db2f213dbace..7c2b277b7eb095 100644 --- a/arch/um/include/shared/timetravel.h +++ b/arch/um/include/shared/timetravel.h @@ -12,14 +12,13 @@ enum time_travel_mode { TT_MODE_EXTERNAL, }; -#if defined(UML_CONFIG_UML_TIME_TRAVEL_SUPPORT) || \ - defined(CONFIG_UML_TIME_TRAVEL_SUPPORT) +#if IS_ENABLED(CONFIG_UML_TIME_TRAVEL_SUPPORT) extern enum time_travel_mode time_travel_mode; extern int time_travel_should_print_bc_msg; #else #define time_travel_mode TT_MODE_OFF #define time_travel_should_print_bc_msg 0 -#endif /* (UML_)CONFIG_UML_TIME_TRAVEL_SUPPORT */ +#endif /* CONFIG_UML_TIME_TRAVEL_SUPPORT */ void _time_travel_print_bc_msg(void); static inline void time_travel_print_bc_msg(void) diff --git a/arch/um/include/shared/user.h b/arch/um/include/shared/user.h index bbab79c0c074ac..139eb78a476748 100644 --- a/arch/um/include/shared/user.h +++ b/arch/um/include/shared/user.h @@ -38,7 +38,7 @@ extern void panic(const char *fmt, ...) #define UM_KERN_DEBUG KERN_DEBUG #define UM_KERN_CONT KERN_CONT -#ifdef UML_CONFIG_PRINTK +#if IS_ENABLED(CONFIG_PRINTK) #define printk(...) _printk(__VA_ARGS__) extern int _printk(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); diff --git a/arch/um/kernel/dtb.c b/arch/um/kernel/dtb.c index 4954188a6a0908..15c342426489d9 100644 --- a/arch/um/kernel/dtb.c +++ b/arch/um/kernel/dtb.c @@ -17,7 +17,7 @@ void uml_dtb_init(void) area = uml_load_file(dtb, &size); if (area) { - if (!early_init_dt_scan(area)) { + if (!early_init_dt_scan(area, __pa(area))) { pr_err("invalid DTB %s\n", dtb); memblock_free(area, size); return; @@ -31,6 +31,7 @@ void uml_dtb_init(void) static int __init uml_dtb_setup(char *line, int *add) { + *add = 0; dtb = line; return 0; } diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index 3385d653ebd0d0..a36b7918a011ac 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -116,8 +116,6 @@ SECTIONS .fini_array : { *(.fini_array) } .data : { INIT_TASK_DATA(KERNEL_STACK_SIZE) - . = ALIGN(KERNEL_STACK_SIZE); - *(.data..init_irqstack) DATA_DATA *(.data.* .gnu.linkonce.d.*) SORT(CONSTRUCTORS) @@ -178,3 +176,6 @@ SECTIONS DISCARDS } + +ASSERT(__syscall_stub_end - __syscall_stub_start <= PAGE_SIZE, + "STUB code must not be larger than one page"); diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c index 47b8cb1a115618..99dba827461c8a 100644 --- a/arch/um/kernel/initrd.c +++ b/arch/um/kernel/initrd.c @@ -34,6 +34,7 @@ int __init read_initrd(void) static int __init uml_initrd_setup(char *line, int *add) { + *add = 0; initrd = line; return 0; } diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 534e91797f8927..338450741aac5b 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -674,115 +674,3 @@ void __init init_IRQ(void) /* Initialize EPOLL Loop */ os_setup_epoll(); } - -/* - * IRQ stack entry and exit: - * - * Unlike i386, UML doesn't receive IRQs on the normal kernel stack - * and switch over to the IRQ stack after some preparation. We use - * sigaltstack to receive signals on a separate stack from the start. - * These two functions make sure the rest of the kernel won't be too - * upset by being on a different stack. The IRQ stack has a - * thread_info structure at the bottom so that current et al continue - * to work. - * - * to_irq_stack copies the current task's thread_info to the IRQ stack - * thread_info and sets the tasks's stack to point to the IRQ stack. - * - * from_irq_stack copies the thread_info struct back (flags may have - * been modified) and resets the task's stack pointer. - * - * Tricky bits - - * - * What happens when two signals race each other? UML doesn't block - * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal - * could arrive while a previous one is still setting up the - * thread_info. - * - * There are three cases - - * The first interrupt on the stack - sets up the thread_info and - * handles the interrupt - * A nested interrupt interrupting the copying of the thread_info - - * can't handle the interrupt, as the stack is in an unknown state - * A nested interrupt not interrupting the copying of the - * thread_info - doesn't do any setup, just handles the interrupt - * - * The first job is to figure out whether we interrupted stack setup. - * This is done by xchging the signal mask with thread_info->pending. - * If the value that comes back is zero, then there is no setup in - * progress, and the interrupt can be handled. If the value is - * non-zero, then there is stack setup in progress. In order to have - * the interrupt handled, we leave our signal in the mask, and it will - * be handled by the upper handler after it has set up the stack. - * - * Next is to figure out whether we are the outer handler or a nested - * one. As part of setting up the stack, thread_info->real_thread is - * set to non-NULL (and is reset to NULL on exit). This is the - * nesting indicator. If it is non-NULL, then the stack is already - * set up and the handler can run. - */ - -static unsigned long pending_mask; - -unsigned long to_irq_stack(unsigned long *mask_out) -{ - struct thread_info *ti; - unsigned long mask, old; - int nested; - - mask = xchg(&pending_mask, *mask_out); - if (mask != 0) { - /* - * If any interrupts come in at this point, we want to - * make sure that their bits aren't lost by our - * putting our bit in. So, this loop accumulates bits - * until xchg returns the same value that we put in. - * When that happens, there were no new interrupts, - * and pending_mask contains a bit for each interrupt - * that came in. - */ - old = *mask_out; - do { - old |= mask; - mask = xchg(&pending_mask, old); - } while (mask != old); - return 1; - } - - ti = current_thread_info(); - nested = (ti->real_thread != NULL); - if (!nested) { - struct task_struct *task; - struct thread_info *tti; - - task = cpu_tasks[ti->cpu].task; - tti = task_thread_info(task); - - *ti = *tti; - ti->real_thread = tti; - task->stack = ti; - } - - mask = xchg(&pending_mask, 0); - *mask_out |= mask | nested; - return 0; -} - -unsigned long from_irq_stack(int nested) -{ - struct thread_info *ti, *to; - unsigned long mask; - - ti = current_thread_info(); - - pending_mask = 1; - - to = ti->real_thread; - current->stack = to; - ti->real_thread = NULL; - *to = *ti; - - mask = xchg(&pending_mask, 0); - return mask & ~1; -} - diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index a5b4fe2ad93153..53248ed04771d1 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -51,8 +50,6 @@ EXPORT_SYMBOL(empty_zero_page); pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* Initialized at boot time, and readonly after that */ -unsigned long long highmem; -EXPORT_SYMBOL(highmem); int kmalloc_ok = 0; /* Used during early boot */ @@ -98,7 +95,7 @@ static void __init one_page_table_init(pmd_t *pmd) static void __init one_md_table_init(pud_t *pud) { -#ifdef CONFIG_3_LEVEL_PGTABLES +#if CONFIG_PGTABLE_LEVELS > 2 pmd_t *pmd_table = (pmd_t *) memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); if (!pmd_table) panic("%s: Failed to allocate %lu bytes align=%lx\n", @@ -109,6 +106,19 @@ static void __init one_md_table_init(pud_t *pud) #endif } +static void __init one_ud_table_init(p4d_t *p4d) +{ +#if CONFIG_PGTABLE_LEVELS > 3 + pud_t *pud_table = (pud_t *) memblock_alloc_low(PAGE_SIZE, PAGE_SIZE); + if (!pud_table) + panic("%s: Failed to allocate %lu bytes align=%lx\n", + __func__, PAGE_SIZE, PAGE_SIZE); + + set_p4d(p4d, __p4d(_KERNPG_TABLE + (unsigned long) __pa(pud_table))); + BUG_ON(pud_table != pud_offset(p4d, 0)); +#endif +} + static void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { @@ -126,6 +136,8 @@ static void __init fixrange_init(unsigned long start, unsigned long end, for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) { p4d = p4d_offset(pgd, vaddr); + if (p4d_none(*p4d)) + one_ud_table_init(p4d); pud = pud_offset(p4d, vaddr); if (pud_none(*pud)) one_md_table_init(pud); diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index fb2adfb499452b..a74f17b033c417 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -22,19 +22,14 @@ static int physmem_fd = -1; unsigned long high_physmem; EXPORT_SYMBOL(high_physmem); -extern unsigned long long physmem_size; - -void __init mem_total_pages(unsigned long physmem, unsigned long iomem, - unsigned long highmem) +void __init mem_total_pages(unsigned long physmem, unsigned long iomem) { - unsigned long phys_pages, highmem_pages; - unsigned long iomem_pages, total_pages; + unsigned long phys_pages, iomem_pages, total_pages; - phys_pages = physmem >> PAGE_SHIFT; - iomem_pages = iomem >> PAGE_SHIFT; - highmem_pages = highmem >> PAGE_SHIFT; + phys_pages = physmem >> PAGE_SHIFT; + iomem_pages = iomem >> PAGE_SHIFT; - total_pages = phys_pages + iomem_pages + highmem_pages; + total_pages = phys_pages + iomem_pages; max_mapnr = total_pages; } @@ -64,13 +59,12 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, * @reserve_end: end address of the physical kernel memory. * @len: Length of total physical memory that should be mapped/made * available, in bytes. - * @highmem: Number of highmem bytes that should be mapped/made available. * - * Creates an unlinked temporary file of size (len + highmem) and memory maps + * Creates an unlinked temporary file of size (len) and memory maps * it on the last executable image address (uml_reserved). * * The offset is needed as the length of the total physical memory - * (len + highmem) includes the size of the memory used be the executable image, + * (len) includes the size of the memory used be the executable image, * but the mapped-to address is the last address of the executable image * (uml_reserved == end address of executable image). * @@ -78,24 +72,24 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, * of all user space processes/kernel tasks. */ void __init setup_physmem(unsigned long start, unsigned long reserve_end, - unsigned long len, unsigned long long highmem) + unsigned long len) { unsigned long reserve = reserve_end - start; - long map_size = len - reserve; + unsigned long map_size = len - reserve; int err; - if(map_size <= 0) { + if (len <= reserve) { os_warn("Too few physical memory! Needed=%lu, given=%lu\n", reserve, len); exit(1); } - physmem_fd = create_mem_file(len + highmem); + physmem_fd = create_mem_file(len); err = os_map_memory((void *) reserve_end, physmem_fd, reserve, map_size, 1, 1, 1); if (err < 0) { - os_warn("setup_physmem - mapping %ld bytes of memory at 0x%p " + os_warn("setup_physmem - mapping %lu bytes of memory at 0x%p " "failed - errno = %d\n", map_size, (void *) reserve_end, err); exit(1); @@ -107,9 +101,8 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end, */ os_seek_file(physmem_fd, __pa(__syscall_stub_start)); os_write_file(physmem_fd, __syscall_stub_start, PAGE_SIZE); - os_fsync_file(physmem_fd); - memblock_add(__pa(start), len + highmem); + memblock_add(__pa(start), len); memblock_reserve(__pa(start), reserve); min_low_pfn = PFN_UP(__pa(reserve_end)); @@ -137,10 +130,6 @@ int phys_mapping(unsigned long phys, unsigned long long *offset_out) region = region->next; } } - else if (phys < __pa(end_iomem) + highmem) { - fd = physmem_fd; - *offset_out = phys - iomem_size; - } return fd; } @@ -149,6 +138,8 @@ EXPORT_SYMBOL(phys_mapping); static int __init uml_mem_setup(char *line, int *add) { char *retptr; + + *add = 0; physmem_size = memparse(line,&retptr); return 0; } diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index be2856af6d4c31..30bdc0a87dc854 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -43,7 +43,8 @@ * cares about its entry, so it's OK if another processor is modifying its * entry. */ -struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { NULL } }; +struct task_struct *cpu_tasks[NR_CPUS]; +EXPORT_SYMBOL(cpu_tasks); void free_stack(unsigned long stack, int order) { @@ -64,7 +65,7 @@ unsigned long alloc_stack(int order, int atomic) static inline void set_current(struct task_struct *task) { - cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task) { task }); + cpu_tasks[task_thread_info(task)->cpu] = task; } struct task_struct *__switch_to(struct task_struct *from, struct task_struct *to) @@ -116,7 +117,7 @@ void new_thread_handler(void) * callback returns only if the kernel thread execs a process */ fn(arg); - userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs); + userspace(¤t->thread.regs.regs); } /* Called magically, see new_thread_handler above */ @@ -133,7 +134,7 @@ static void fork_handler(void) current->thread.prev_sched = NULL; - userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs); + userspace(¤t->thread.regs.regs); } int copy_thread(struct task_struct * p, const struct kernel_clone_args *args) @@ -187,6 +188,13 @@ void initial_thread_cb(void (*proc)(void *), void *arg) kmalloc_ok = save_kmalloc_ok; } +int arch_dup_task_struct(struct task_struct *dst, + struct task_struct *src) +{ + memcpy(dst, src, arch_task_struct_size); + return 0; +} + void um_idle_sleep(void) { if (time_travel_mode != TT_MODE_OFF) @@ -287,11 +295,3 @@ unsigned long __get_wchan(struct task_struct *p) return 0; } - -int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu) -{ - int cpu = current_thread_info()->cpu; - - return save_i387_registers(userspace_pid[cpu], (unsigned long *) fpu); -} - diff --git a/arch/um/kernel/skas/.gitignore b/arch/um/kernel/skas/.gitignore new file mode 100644 index 00000000000000..c3409ced0f38c3 --- /dev/null +++ b/arch/um/kernel/skas/.gitignore @@ -0,0 +1,2 @@ +stub_exe +stub_exe.dbg diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile index 6f86d53e3d6932..3384be42691f89 100644 --- a/arch/um/kernel/skas/Makefile +++ b/arch/um/kernel/skas/Makefile @@ -3,14 +3,48 @@ # Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) # -obj-y := stub.o mmu.o process.o syscall.o uaccess.o +obj-y := stub.o mmu.o process.o syscall.o uaccess.o \ + stub_exe_embed.o + +# Stub executable + +stub_exe_objs-y := stub_exe.o + +stub_exe_objs := $(foreach F,$(stub_exe_objs-y),$(obj)/$F) + +# Object file containing the ELF executable +$(obj)/stub_exe_embed.o: $(src)/stub_exe_embed.S $(obj)/stub_exe + +$(obj)/stub_exe.dbg: $(stub_exe_objs) FORCE + $(call if_changed,stub_exe) + +$(obj)/stub_exe: OBJCOPYFLAGS := -S +$(obj)/stub_exe: $(obj)/stub_exe.dbg FORCE + $(call if_changed,objcopy) + +quiet_cmd_stub_exe = STUB_EXE $@ + cmd_stub_exe = $(CC) -nostdlib -o $@ \ + $(filter-out $(UM_GPROF_OPT) $(UM_GCOV_OPT),$(KBUILD_CFLAGS)) $(STUB_EXE_LDFLAGS) \ + $(filter %.o,$^) + +STUB_EXE_LDFLAGS = -Wl,-n -static + +targets += stub_exe.dbg stub_exe $(stub_exe_objs-y) + +# end # stub.o is in the stub, so it can't be built with profiling # GCC hardened also auto-enables -fpic, but we need %ebx so it can't work -> # disable it CFLAGS_stub.o := $(CFLAGS_NO_HARDENING) -UNPROFILE_OBJS := stub.o +CFLAGS_stub_exe.o := $(CFLAGS_NO_HARDENING) + +# Clang will call memset() from __builtin_alloca() when stack variable +# initialization is enabled, which is used in stub_exe.c. +CFLAGS_stub_exe.o += $(call cc-option, -ftrivial-auto-var-init=uninitialized) + +UNPROFILE_OBJS := stub.o stub_exe.o KCOV_INSTRUMENT := n include $(srctree)/arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 886ed5e656743d..0eb5a1d3ba7013 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -40,35 +40,13 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) goto out_free; } - /* - * Ensure the new MM is clean and nothing unwanted is mapped. - * - * TODO: We should clear the memory up to STUB_START to ensure there is - * nothing mapped there, i.e. we (currently) have: - * - * |- user memory -|- unused -|- stub -|- unused -| - * ^ TASK_SIZE ^ STUB_START - * - * Meaning we have two unused areas where we may still have valid - * mappings from our internal clone(). That isn't really a problem as - * userspace is not going to access them, but it is definitely not - * correct. - * - * However, we are "lucky" and if rseq is configured, then on 32 bit - * it will fall into the first empty range while on 64 bit it is going - * to use an anonymous mapping in the second range. As such, things - * continue to work for now as long as we don't start unmapping these - * areas. - * - * Change this to STUB_START once we have a clean userspace. - */ - unmap(new_id, 0, TASK_SIZE); + /* Ensure the new MM is clean and nothing unwanted is mapped */ + unmap(new_id, 0, STUB_START); return 0; out_free: - if (new_id->stack != 0) - free_pages(new_id->stack, ilog2(STUB_DATA_PAGES)); + free_pages(new_id->stack, ilog2(STUB_DATA_PAGES)); out: return ret; } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 68657988c8d1ae..05dcdc057af948 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -22,15 +22,13 @@ static int __init start_kernel_proc(void *unused) { block_signals_trace(); - cpu_tasks[0].task = current; - start_kernel(); return 0; } extern int userspace_pid[]; -extern char cpu0_irqstack[]; +static char cpu0_irqstack[THREAD_SIZE] __aligned(THREAD_SIZE); int __init start_uml(void) { diff --git a/arch/um/kernel/skas/stub.c b/arch/um/kernel/skas/stub.c index 5d52ffa682dc48..796fc266d3bb00 100644 --- a/arch/um/kernel/skas/stub.c +++ b/arch/um/kernel/skas/stub.c @@ -35,16 +35,6 @@ static __always_inline int syscall_handler(struct stub_data *d) return -1; } break; - case STUB_SYSCALL_MPROTECT: - res = stub_syscall3(__NR_mprotect, - sc->mem.addr, sc->mem.length, - sc->mem.prot); - if (res) { - d->err = res; - d->syscall_data_len = i; - return -1; - } - break; default: d->err = -95; /* EOPNOTSUPP */ d->syscall_data_len = i; diff --git a/arch/um/kernel/skas/stub_exe.c b/arch/um/kernel/skas/stub_exe.c new file mode 100644 index 00000000000000..23c99b285e82e7 --- /dev/null +++ b/arch/um/kernel/skas/stub_exe.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include + +void _start(void); + +noinline static void real_init(void) +{ + struct stub_init_data init_data; + unsigned long res; + struct { + void *ss_sp; + int ss_flags; + size_t ss_size; + } stack = { + .ss_size = STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, + }; + struct { + void *sa_handler_; + unsigned long sa_flags; + void *sa_restorer; + unsigned long long sa_mask; + } sa = { + /* Need to set SA_RESTORER (but the handler never returns) */ + .sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO | 0x04000000, + /* no need to mask any signals */ + .sa_mask = 0, + }; + + /* set a nice name */ + stub_syscall2(__NR_prctl, PR_SET_NAME, (unsigned long)"uml-userspace"); + + /* Make sure this process dies if the kernel dies */ + stub_syscall2(__NR_prctl, PR_SET_PDEATHSIG, SIGKILL); + + /* read information from STDIN and close it */ + res = stub_syscall3(__NR_read, 0, + (unsigned long)&init_data, sizeof(init_data)); + if (res != sizeof(init_data)) + stub_syscall1(__NR_exit, 10); + + stub_syscall1(__NR_close, 0); + + /* map stub code + data */ + res = stub_syscall6(STUB_MMAP_NR, + init_data.stub_start, UM_KERN_PAGE_SIZE, + PROT_READ | PROT_EXEC, MAP_FIXED | MAP_SHARED, + init_data.stub_code_fd, init_data.stub_code_offset); + if (res != init_data.stub_start) + stub_syscall1(__NR_exit, 11); + + res = stub_syscall6(STUB_MMAP_NR, + init_data.stub_start + UM_KERN_PAGE_SIZE, + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, + init_data.stub_data_fd, init_data.stub_data_offset); + if (res != init_data.stub_start + UM_KERN_PAGE_SIZE) + stub_syscall1(__NR_exit, 12); + + /* setup signal stack inside stub data */ + stack.ss_sp = (void *)init_data.stub_start + UM_KERN_PAGE_SIZE; + stub_syscall2(__NR_sigaltstack, (unsigned long)&stack, 0); + + /* register SIGSEGV handler */ + sa.sa_handler_ = (void *) init_data.segv_handler; + res = stub_syscall4(__NR_rt_sigaction, SIGSEGV, (unsigned long)&sa, 0, + sizeof(sa.sa_mask)); + if (res != 0) + stub_syscall1(__NR_exit, 13); + + stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0); + + stub_syscall2(__NR_kill, stub_syscall0(__NR_getpid), SIGSTOP); + + stub_syscall1(__NR_exit, 14); + + __builtin_unreachable(); +} + +__attribute__((naked)) void _start(void) +{ + /* + * Since the stack after exec() starts at the top-most address, + * but that's exactly where we also want to map the stub data + * and code, this must: + * - push the stack by 1 code and STUB_DATA_PAGES data pages + * - call real_init() + * This way, real_init() can use the stack normally, while the + * original stack further down (higher address) will become + * inaccessible after the mmap() calls above. + */ + stub_start(real_init); +} diff --git a/arch/um/kernel/skas/stub_exe_embed.S b/arch/um/kernel/skas/stub_exe_embed.S new file mode 100644 index 00000000000000..6d8914fbe8f125 --- /dev/null +++ b/arch/um/kernel/skas/stub_exe_embed.S @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include + +__INITDATA + +SYM_DATA_START(stub_exe_start) + .incbin "arch/um/kernel/skas/stub_exe" +SYM_DATA_END_LABEL(stub_exe_start, SYM_L_GLOBAL, stub_exe_end) + +__FINIT diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 4bb8622dc51226..13ee5666668dd4 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -32,12 +32,6 @@ void show_stack(struct task_struct *task, unsigned long *stack, struct pt_regs *segv_regs = current->thread.segv_regs; int i; - if (!segv_regs && os_is_signal_stack()) { - pr_err("Received SIGSEGV in SIGSEGV handler," - " aborting stack trace!\n"); - return; - } - if (!stack) stack = get_stack_pointer(task, segv_regs); @@ -52,5 +46,5 @@ void show_stack(struct task_struct *task, unsigned long *stack, } printk("%sCall Trace:\n", loglvl); - dump_trace(current, &stackops, (void *)loglvl); + dump_trace(task ?: current, &stackops, (void *)loglvl); } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 29b27b90581fbb..1394568c02106f 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -25,6 +25,8 @@ #include #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT +#include + enum time_travel_mode time_travel_mode; EXPORT_SYMBOL_GPL(time_travel_mode); @@ -47,6 +49,15 @@ static u16 time_travel_shm_id; static struct um_timetravel_schedshm *time_travel_shm; static union um_timetravel_schedshm_client *time_travel_shm_client; +unsigned long tt_extra_sched_jiffies; + +notrace unsigned long long sched_clock(void) +{ + return (unsigned long long)(jiffies - INITIAL_JIFFIES + + tt_extra_sched_jiffies) + * (NSEC_PER_SEC / HZ); +} + static void time_travel_set_time(unsigned long long ns) { if (unlikely(ns < time_travel_time)) @@ -443,6 +454,11 @@ static void time_travel_periodic_timer(struct time_travel_event *e) { time_travel_add_event(&time_travel_timer_event, time_travel_time + time_travel_timer_interval); + + /* clock tick; decrease extra jiffies by keeping sched_clock constant */ + if (tt_extra_sched_jiffies > 0) + tt_extra_sched_jiffies -= 1; + deliver_alarm(); } @@ -594,6 +610,10 @@ EXPORT_SYMBOL_GPL(time_travel_add_irq_event); static void time_travel_oneshot_timer(struct time_travel_event *e) { + /* clock tick; decrease extra jiffies by keeping sched_clock constant */ + if (tt_extra_sched_jiffies > 0) + tt_extra_sched_jiffies -= 1; + deliver_alarm(); } diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 548af31d4111bb..cf7e0d4407f2cd 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -23,9 +23,6 @@ struct vm_ops { int phys_fd, unsigned long long offset); int (*unmap)(struct mm_id *mm_idp, unsigned long virt, unsigned long len); - int (*mprotect)(struct mm_id *mm_idp, - unsigned long virt, unsigned long len, - unsigned int prot); }; static int kern_map(struct mm_id *mm_idp, @@ -44,15 +41,6 @@ static int kern_unmap(struct mm_id *mm_idp, return os_unmap_memory((void *)virt, len); } -static int kern_mprotect(struct mm_id *mm_idp, - unsigned long virt, unsigned long len, - unsigned int prot) -{ - return os_protect_memory((void *)virt, len, - prot & UM_PROT_READ, prot & UM_PROT_WRITE, - 1); -} - void report_enomem(void) { printk(KERN_ERR "UML ran out of memory on the host side! " @@ -65,33 +53,37 @@ static inline int update_pte_range(pmd_t *pmd, unsigned long addr, struct vm_ops *ops) { pte_t *pte; - int r, w, x, prot, ret = 0; + int ret = 0; pte = pte_offset_kernel(pmd, addr); do { - r = pte_read(*pte); - w = pte_write(*pte); - x = pte_exec(*pte); - if (!pte_young(*pte)) { - r = 0; - w = 0; - } else if (!pte_dirty(*pte)) - w = 0; - - prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | - (x ? UM_PROT_EXEC : 0)); - if (pte_newpage(*pte)) { - if (pte_present(*pte)) { - __u64 offset; - unsigned long phys = pte_val(*pte) & PAGE_MASK; - int fd = phys_mapping(phys, &offset); - - ret = ops->mmap(ops->mm_idp, addr, PAGE_SIZE, - prot, fd, offset); - } else - ret = ops->unmap(ops->mm_idp, addr, PAGE_SIZE); - } else if (pte_newprot(*pte)) - ret = ops->mprotect(ops->mm_idp, addr, PAGE_SIZE, prot); + if (!pte_needsync(*pte)) + continue; + + if (pte_present(*pte)) { + __u64 offset; + unsigned long phys = pte_val(*pte) & PAGE_MASK; + int fd = phys_mapping(phys, &offset); + int r, w, x, prot; + + r = pte_read(*pte); + w = pte_write(*pte); + x = pte_exec(*pte); + if (!pte_young(*pte)) { + r = 0; + w = 0; + } else if (!pte_dirty(*pte)) + w = 0; + + prot = (r ? UM_PROT_READ : 0) | + (w ? UM_PROT_WRITE : 0) | + (x ? UM_PROT_EXEC : 0); + + ret = ops->mmap(ops->mm_idp, addr, PAGE_SIZE, + prot, fd, offset); + } else + ret = ops->unmap(ops->mm_idp, addr, PAGE_SIZE); + *pte = pte_mkuptodate(*pte); } while (pte++, addr += PAGE_SIZE, ((addr < end) && !ret)); return ret; @@ -109,7 +101,7 @@ static inline int update_pmd_range(pud_t *pud, unsigned long addr, do { next = pmd_addr_end(addr, end); if (!pmd_present(*pmd)) { - if (pmd_newpage(*pmd)) { + if (pmd_needsync(*pmd)) { ret = ops->unmap(ops->mm_idp, addr, next - addr); pmd_mkuptodate(*pmd); @@ -132,7 +124,7 @@ static inline int update_pud_range(p4d_t *p4d, unsigned long addr, do { next = pud_addr_end(addr, end); if (!pud_present(*pud)) { - if (pud_newpage(*pud)) { + if (pud_needsync(*pud)) { ret = ops->unmap(ops->mm_idp, addr, next - addr); pud_mkuptodate(*pud); @@ -155,7 +147,7 @@ static inline int update_p4d_range(pgd_t *pgd, unsigned long addr, do { next = p4d_addr_end(addr, end); if (!p4d_present(*p4d)) { - if (p4d_newpage(*p4d)) { + if (p4d_needsync(*p4d)) { ret = ops->unmap(ops->mm_idp, addr, next - addr); p4d_mkuptodate(*p4d); @@ -180,18 +172,16 @@ int um_tlb_sync(struct mm_struct *mm) if (mm == &init_mm) { ops.mmap = kern_map; ops.unmap = kern_unmap; - ops.mprotect = kern_mprotect; } else { ops.mmap = map; ops.unmap = unmap; - ops.mprotect = protect; } pgd = pgd_offset(mm, addr); do { next = pgd_addr_end(addr, mm->context.sync_tlb_range_to); if (!pgd_present(*pgd)) { - if (pgd_newpage(*pgd)) { + if (pgd_needsync(*pgd)) { ret = ops.unmap(ops.mm_idp, addr, next - addr); pgd_mkuptodate(*pgd); diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 97c8df9c44017c..cdaee3e9427341 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -201,7 +201,6 @@ void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, struct uml_pt_regs *regs) { - jmp_buf *catcher; int si_code; int err; int is_write = FAULT_WRITE(fi); @@ -246,15 +245,8 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, address = 0; } - catcher = current->thread.fault_catcher; if (!err) goto out; - else if (catcher != NULL) { - current->thread.fault_addr = (void *) address; - UML_LONGJMP(catcher, 1); - } - else if (current->thread.fault_addr != NULL) - panic("fault_addr set but no fault catcher"); else if (!is_user && arch_fixup(ip, regs)) goto out; @@ -310,14 +302,6 @@ void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs) } } -void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs) -{ - if (current->thread.fault_catcher != NULL) - UML_LONGJMP(current->thread.fault_catcher, 1); - else - relay_signal(sig, si, regs); -} - void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) { do_IRQ(WINCH_IRQ, regs); diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 8e594cda6d778d..8037a967225d82 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -65,9 +65,6 @@ struct cpuinfo_um boot_cpu_data = { EXPORT_SYMBOL(boot_cpu_data); -union thread_union cpu0_irqstack - __section(".data..init_irqstack") = - { .thread_info = INIT_THREAD_INFO(init_task) }; /* Changed in setup_arch, which is called in early boot */ static char host_info[(__NEW_UTS_LEN + 1) * 5]; @@ -131,7 +128,7 @@ static int have_root __initdata; static int have_console __initdata; /* Set in uml_mem_setup and modified in linux_main */ -long long physmem_size = 64 * 1024 * 1024; +unsigned long long physmem_size = 64 * 1024 * 1024; EXPORT_SYMBOL(physmem_size); static const char *usage_string = @@ -167,19 +164,6 @@ __uml_setup("root=", uml_root_setup, " root=/dev/ubd5\n\n" ); -static int __init no_skas_debug_setup(char *line, int *add) -{ - os_warn("'debug' is not necessary to gdb UML in skas mode - run\n"); - os_warn("'gdb linux'\n"); - - return 0; -} - -__uml_setup("debug", no_skas_debug_setup, -"debug\n" -" this flag is not needed to run gdb on UML in skas mode\n\n" -); - static int __init uml_console_setup(char *line, int *add) { have_console = 1; @@ -257,6 +241,8 @@ static struct notifier_block panic_exit_notifier = { void uml_finishsetup(void) { + cpu_tasks[0] = &init_task; + atomic_notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); @@ -302,7 +288,24 @@ static void parse_cache_line(char *line) } } -int __init linux_main(int argc, char **argv) +static unsigned long get_top_address(char **envp) +{ + unsigned long top_addr = (unsigned long) &top_addr; + int i; + + /* The earliest variable should be after the program name in ELF */ + for (i = 0; envp[i]; i++) { + if ((unsigned long) envp[i] > top_addr) + top_addr = (unsigned long) envp[i]; + } + + top_addr &= ~(UM_KERN_PAGE_SIZE - 1); + top_addr += UM_KERN_PAGE_SIZE; + + return top_addr; +} + +int __init linux_main(int argc, char **argv, char **envp) { unsigned long avail, diff; unsigned long virtmem_size, max_physmem; @@ -324,20 +327,23 @@ int __init linux_main(int argc, char **argv) if (have_console == 0) add_arg(DEFAULT_COMMAND_LINE_CONSOLE); - host_task_size = os_get_top_address(); - /* 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); + host_task_size = get_top_address(envp); + /* reserve a few pages for the stubs */ + stub_start = host_task_size - STUB_DATA_PAGES * PAGE_SIZE; /* another page for the code portion */ stub_start -= PAGE_SIZE; host_task_size = stub_start; + /* Limit TASK_SIZE to what is addressable by the page table */ + task_size = host_task_size; + if (task_size > (unsigned long long) PTRS_PER_PGD * PGDIR_SIZE) + task_size = PTRS_PER_PGD * PGDIR_SIZE; + /* * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps * out */ - task_size = host_task_size & PGDIR_MASK; + task_size = task_size & PGDIR_MASK; /* OS sanity checks that need to happen before the kernel runs */ os_early_checks(); @@ -366,18 +372,15 @@ int __init linux_main(int argc, char **argv) setup_machinename(init_utsname()->machine); - highmem = 0; + physmem_size = (physmem_size + PAGE_SIZE - 1) & PAGE_MASK; iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; + max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC; - /* - * Zones have to begin on a 1 << MAX_PAGE_ORDER page boundary, - * so this makes sure that's true for highmem - */ - max_physmem &= ~((1 << (PAGE_SHIFT + MAX_PAGE_ORDER)) - 1); if (physmem_size + iomem_size > max_physmem) { - highmem = physmem_size + iomem_size - max_physmem; - physmem_size -= highmem; + physmem_size = max_physmem - iomem_size; + os_info("Physical memory size shrunk to %llu bytes\n", + physmem_size); } high_physmem = uml_physmem + physmem_size; @@ -398,6 +401,8 @@ int __init linux_main(int argc, char **argv) os_info("Kernel virtual memory size shrunk to %lu bytes\n", virtmem_size); + arch_task_struct_size = sizeof(struct task_struct) + host_fp_size; + os_flush_stdout(); return start_uml(); @@ -412,9 +417,9 @@ void __init setup_arch(char **cmdline_p) { u8 rng_seed[32]; - stack_protections((unsigned long) &init_thread_info); - setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); - mem_total_pages(physmem_size, iomem_size, highmem); + stack_protections((unsigned long) init_task.stack); + setup_physmem(uml_physmem, uml_reserved, physmem_size); + mem_total_pages(physmem_size, iomem_size); uml_dtb_init(); read_initrd(); @@ -435,24 +440,25 @@ void __init arch_cpu_finalize_init(void) os_check_bugs(); } -void apply_seal_endbr(s32 *start, s32 *end) +void apply_seal_endbr(s32 *start, s32 *end, struct module *mod) { } -void apply_retpolines(s32 *start, s32 *end) +void apply_retpolines(s32 *start, s32 *end, struct module *mod) { } -void apply_returns(s32 *start, s32 *end) +void apply_returns(s32 *start, s32 *end, struct module *mod) { } void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, - s32 *start_cfi, s32 *end_cfi) + s32 *start_cfi, s32 *end_cfi, struct module *mod) { } -void apply_alternatives(struct alt_instr *start, struct alt_instr *end) +void apply_alternatives(struct alt_instr *start, struct alt_instr *end, + struct module *mod) { } @@ -468,6 +474,11 @@ void *text_poke(void *addr, const void *opcode, size_t len) return memcpy(addr, opcode, len); } +void *text_poke_copy(void *addr, const void *opcode, size_t len) +{ + return text_poke(addr, opcode, len); +} + void text_poke_sync(void) { } diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index 5c92d58a78e89c..a409d4b66114f7 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -77,8 +77,6 @@ SECTIONS .data : { INIT_TASK_DATA(KERNEL_STACK_SIZE) - . = ALIGN(KERNEL_STACK_SIZE); - *(.data..init_irqstack) DATA_DATA *(.gnu.linkonce.d*) CONSTRUCTORS diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 544e0b344c754a..049dfa5bc9c69a 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -12,6 +12,8 @@ obj-y = execvp.o file.o helper.o irq.o main.o mem.o process.o \ CFLAGS_signal.o += -Wframe-larger-than=4096 +CFLAGS_main.o += -Wno-frame-larger-than + obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o USER_OBJS := $(user-objs-y) elf_aux.o execvp.o file.o helper.o irq.o \ diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index f1d03cf3957fe8..a0d01c68ce3ee8 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -255,12 +255,6 @@ void os_close_file(int fd) { close(fd); } -int os_fsync_file(int fd) -{ - if (fsync(fd) < 0) - return -errno; - return 0; -} int os_seek_file(int fd, unsigned long long offset) { diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index f98ff79cdbf798..0afcdeb8995b75 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,21 @@ int __init main(int argc, char **argv, char **envp) char **new_argv; int ret, i, err; + /* Disable randomization and re-exec if it was changed successfully */ + ret = personality(PER_LINUX | ADDR_NO_RANDOMIZE); + if (ret >= 0 && (ret & (PER_LINUX | ADDR_NO_RANDOMIZE)) != + (PER_LINUX | ADDR_NO_RANDOMIZE)) { + char buf[4096] = {}; + ssize_t ret; + + ret = readlink("/proc/self/exe", buf, sizeof(buf)); + if (ret < 0 || ret >= sizeof(buf)) { + perror("readlink failure"); + exit(1); + } + execve(buf, argv, envp); + } + set_stklim(); setup_env_path(); @@ -140,7 +156,7 @@ int __init main(int argc, char **argv, char **envp) #endif change_sig(SIGPIPE, 0); - ret = linux_main(argc, argv); + ret = linux_main(argc, argv, envp); /* * Disable SIGPROF - I have no idea why libc doesn't do this or turn @@ -182,6 +198,7 @@ int __init main(int argc, char **argv, char **envp) } extern void *__real_malloc(int); +extern void __real_free(void *); /* workaround for -Wmissing-prototypes warnings */ void *__wrap_malloc(int size); @@ -219,10 +236,6 @@ void *__wrap_calloc(int n, int size) return ptr; } -extern void __real_free(void *); - -extern unsigned long high_physmem; - void __wrap_free(void *ptr) { unsigned long addr = (unsigned long) ptr; diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index cf44d386f23ce3..72f302f4d197f8 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -39,10 +39,22 @@ void kasan_map_memory(void *start, size_t len) strerror(errno)); exit(1); } + + if (madvise(start, len, MADV_DONTDUMP)) { + os_info("Couldn't set MAD_DONTDUMP on shadow memory: %s\n.", + strerror(errno)); + exit(1); + } + + if (madvise(start, len, MADV_DONTFORK)) { + os_info("Couldn't set MADV_DONTFORK on shadow memory: %s\n.", + strerror(errno)); + exit(1); + } } /* Set by make_tempfile() during early boot. */ -static char *tempdir = NULL; +char *tempdir = NULL; /* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */ static int __init check_tmpfs(const char *dir) diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index e52dd37ddadccc..9f086f9394202d 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -12,94 +12,18 @@ #include #include #include +#include #include #include #include #include #include -#define ARBITRARY_ADDR -1 -#define FAILURE_PID -1 - -#define STAT_PATH_LEN sizeof("/proc/#######/stat\0") -#define COMM_SCANF "%*[^)])" - -unsigned long os_process_pc(int pid) -{ - char proc_stat[STAT_PATH_LEN], buf[256]; - unsigned long pc = ARBITRARY_ADDR; - int fd, err; - - sprintf(proc_stat, "/proc/%d/stat", pid); - fd = open(proc_stat, O_RDONLY, 0); - if (fd < 0) { - printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', " - "errno = %d\n", proc_stat, errno); - goto out; - } - CATCH_EINTR(err = read(fd, buf, sizeof(buf))); - if (err < 0) { - printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', " - "err = %d\n", proc_stat, errno); - goto out_close; - } - os_close_file(fd); - pc = ARBITRARY_ADDR; - if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %lu", &pc) != 1) - printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n", - buf); - out_close: - close(fd); - out: - return pc; -} - -int os_process_parent(int pid) -{ - char stat[STAT_PATH_LEN]; - char data[256]; - int parent = FAILURE_PID, n, fd; - - if (pid == -1) - return parent; - - snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); - fd = open(stat, O_RDONLY, 0); - if (fd < 0) { - printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat, - errno); - return parent; - } - - CATCH_EINTR(n = read(fd, data, sizeof(data))); - close(fd); - - if (n < 0) { - printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat, - errno); - return parent; - } - - parent = FAILURE_PID; - n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent); - if (n != 1) - printk(UM_KERN_ERR "Failed to scan '%s'\n", data); - - return parent; -} - void os_alarm_process(int pid) { kill(pid, SIGALRM); } -void os_stop_process(int pid) -{ - kill(pid, SIGSTOP); -} - void os_kill_process(int pid, int reap_child) { kill(pid, SIGKILL); @@ -130,11 +54,6 @@ int os_getpid(void) return syscall(__NR_getpid); } -int os_getpgrp(void) -{ - return getpgrp(); -} - int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, int r, int w, int x) { @@ -285,3 +204,8 @@ void init_new_thread_signals(void) set_handler(SIGIO); signal(SIGWINCH, SIG_IGN); } + +void os_set_pdeathsig(void) +{ + prctl(PR_SET_PDEATHSIG, SIGKILL); +} diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c index bd80b921add06c..d7ca148807b282 100644 --- a/arch/um/os-Linux/registers.c +++ b/arch/um/os-Linux/registers.c @@ -10,11 +10,12 @@ #include #include #include +#include /* This is set once at boot time and not changed thereafter */ static unsigned long exec_regs[MAX_REG_NR]; -static unsigned long exec_fp_regs[FP_SIZE]; +static unsigned long *exec_fp_regs; int init_pid_registers(int pid) { @@ -24,7 +25,11 @@ int init_pid_registers(int pid) if (err < 0) return -errno; - arch_init_registers(pid); + err = arch_init_registers(pid); + if (err < 0) + return err; + + exec_fp_regs = malloc(host_fp_size); get_fp_registers(pid, exec_fp_regs); return 0; } @@ -34,5 +39,5 @@ void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) memcpy(regs, exec_regs, sizeof(exec_regs)); if (fp_regs) - memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs)); + memcpy(fp_regs, exec_fp_regs, host_fp_size); } diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 9e71794839e877..9aac8def4d6359 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -55,6 +55,7 @@ static int write_sigio_thread(void *unused) int i, n, respond_fd; char c; + os_set_pdeathsig(); os_fix_helper_signals(); fds = ¤t_poll; while (1) { diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index b11ed66c8bb0ea..9ea7269ffb7782 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -26,7 +26,7 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { [SIGFPE] = relay_signal, [SIGILL] = relay_signal, [SIGWINCH] = winch, - [SIGBUS] = bus_handler, + [SIGBUS] = relay_signal, [SIGSEGV] = segv_handler, [SIGIO] = sigio_handler, }; @@ -65,7 +65,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) #define SIGALRM_MASK (1 << SIGALRM_BIT) int signals_enabled; -#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT +#if IS_ENABLED(CONFIG_UML_TIME_TRAVEL_SUPPORT) static int signals_blocked, signals_blocked_pending; #endif static unsigned int signals_pending; @@ -75,7 +75,7 @@ static void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) { int enabled = signals_enabled; -#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT +#if IS_ENABLED(CONFIG_UML_TIME_TRAVEL_SUPPORT) if ((signals_blocked || __atomic_load_n(&signals_blocked_pending, __ATOMIC_SEQ_CST)) && (sig == SIGIO)) { @@ -190,43 +190,8 @@ static void hard_handler(int sig, siginfo_t *si, void *p) { ucontext_t *uc = p; mcontext_t *mc = &uc->uc_mcontext; - unsigned long pending = 1UL << sig; - do { - int nested, bail; - - /* - * pending comes back with one bit set for each - * interrupt that arrived while setting up the stack, - * plus a bit for this interrupt, plus the zero bit is - * set if this is a nested interrupt. - * If bail is true, then we interrupted another - * handler setting up the stack. In this case, we - * have to return, and the upper handler will deal - * with this interrupt. - */ - bail = to_irq_stack(&pending); - if (bail) - return; - - nested = pending & 1; - pending &= ~1; - - while ((sig = ffs(pending)) != 0){ - sig--; - pending &= ~(1 << sig); - (*handlers[sig])(sig, (struct siginfo *)si, mc); - } - - /* - * Again, pending comes back with a mask of signals - * that arrived while tearing down the stack. If this - * is non-zero, we just go back, set up the stack - * again, and handle the new interrupts. - */ - if (!nested) - pending = from_irq_stack(nested); - } while (pending); + (*handlers[sig])(sig, (struct siginfo *)si, mc); } void set_handler(int sig) @@ -297,7 +262,7 @@ void unblock_signals(void) return; signals_enabled = 1; -#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT +#if IS_ENABLED(CONFIG_UML_TIME_TRAVEL_SUPPORT) deliver_time_travel_irqs(); #endif @@ -389,7 +354,7 @@ int um_set_signals_trace(int enable) return ret; } -#ifdef UML_CONFIG_UML_TIME_TRAVEL_SUPPORT +#if IS_ENABLED(CONFIG_UML_TIME_TRAVEL_SUPPORT) void mark_sigio_pending(void) { /* @@ -487,11 +452,3 @@ void unblock_signals_hard(void) unblocking = false; } #endif - -int os_is_signal_stack(void) -{ - stack_t ss; - sigaltstack(NULL, &ss); - - return ss.ss_flags & SS_ONSTACK; -} diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c index 9a13ac23c60644..d7f1814b0e5abc 100644 --- a/arch/um/os-Linux/skas/mem.c +++ b/arch/um/os-Linux/skas/mem.c @@ -217,24 +217,3 @@ int unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len) return 0; } - -int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len, - unsigned int prot) -{ - struct stub_syscall *sc; - - /* Compress with previous syscall if that is possible */ - sc = syscall_stub_get_previous(mm_idp, STUB_SYSCALL_MPROTECT, addr); - if (sc && sc->mem.prot == prot) { - sc->mem.length += len; - return 0; - } - - sc = syscall_stub_alloc(mm_idp); - sc->syscall = STUB_SYSCALL_MPROTECT; - sc->mem.addr = addr; - sc->mem.length = len; - sc->mem.prot = prot; - - return 0; -} diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index b6f656bcffb178..f683cfc9e51a54 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -10,8 +10,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -141,16 +144,10 @@ void wait_stub_done(int pid) extern unsigned long current_stub_stack(void); -static void get_skas_faultinfo(int pid, struct faultinfo *fi, unsigned long *aux_fp_regs) +static void get_skas_faultinfo(int pid, struct faultinfo *fi) { int err; - err = get_fp_registers(pid, aux_fp_regs); - if (err < 0) { - printk(UM_KERN_ERR "save_fp_registers returned %d\n", - err); - fatal_sigsegv(); - } err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); if (err) { printk(UM_KERN_ERR "Failed to continue stub, pid = %d, " @@ -164,18 +161,11 @@ static void get_skas_faultinfo(int pid, struct faultinfo *fi, unsigned long *aux * the stub stack page. We just have to copy it. */ memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); - - err = put_fp_registers(pid, aux_fp_regs); - if (err < 0) { - printk(UM_KERN_ERR "put_fp_registers returned %d\n", - err); - fatal_sigsegv(); - } } -static void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp_regs) +static void handle_segv(int pid, struct uml_pt_regs *regs) { - get_skas_faultinfo(pid, ®s->faultinfo, aux_fp_regs); + get_skas_faultinfo(pid, ®s->faultinfo); segv(regs->faultinfo, 0, 1, NULL); } @@ -189,69 +179,131 @@ static void handle_trap(int pid, struct uml_pt_regs *regs) extern char __syscall_stub_start[]; -/** - * userspace_tramp() - userspace trampoline - * @stack: pointer to the new userspace stack page - * - * The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed. - * This function will run on a temporary stack page. - * It ptrace()'es itself, then - * Two pages are mapped into the userspace address space: - * - STUB_CODE (with EXEC), which contains the skas stub code - * - STUB_DATA (with R/W), which contains a data page that is used to transfer certain data between the UML userspace process and the UML kernel. - * Also for the userspace process a SIGSEGV handler is installed to catch pagefaults in the userspace process. - * And last the process stops itself to give control to the UML kernel for this userspace process. - * - * Return: Always zero, otherwise the current userspace process is ended with non null exit() call - */ +static int stub_exe_fd; + static int userspace_tramp(void *stack) { - struct sigaction sa; - void *addr; - int fd; + char *const argv[] = { "uml-userspace", NULL }; + int pipe_fds[2]; unsigned long long offset; - unsigned long segv_handler = STUB_CODE + - (unsigned long) stub_segv_handler - - (unsigned long) __syscall_stub_start; - - ptrace(PTRACE_TRACEME, 0, 0, 0); - - signal(SIGTERM, SIG_DFL); - signal(SIGWINCH, SIG_IGN); - - fd = phys_mapping(uml_to_phys(__syscall_stub_start), &offset); - addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, - PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); - if (addr == MAP_FAILED) { - os_info("mapping mmap stub at 0x%lx failed, errno = %d\n", - STUB_CODE, errno); - exit(1); + struct stub_init_data init_data = { + .stub_start = STUB_START, + .segv_handler = STUB_CODE + + (unsigned long) stub_segv_handler - + (unsigned long) __syscall_stub_start, + }; + struct iomem_region *iomem; + int ret; + + init_data.stub_code_fd = phys_mapping(uml_to_phys(__syscall_stub_start), + &offset); + init_data.stub_code_offset = MMAP_OFFSET(offset); + + init_data.stub_data_fd = phys_mapping(uml_to_phys(stack), &offset); + init_data.stub_data_offset = MMAP_OFFSET(offset); + + /* Set CLOEXEC on all FDs and then unset on all memory related FDs */ + close_range(0, ~0U, CLOSE_RANGE_CLOEXEC); + + fcntl(init_data.stub_data_fd, F_SETFD, 0); + for (iomem = iomem_regions; iomem; iomem = iomem->next) + fcntl(iomem->fd, F_SETFD, 0); + + /* Create a pipe for init_data (no CLOEXEC) and dup2 to STDIN */ + if (pipe(pipe_fds)) + exit(2); + + if (dup2(pipe_fds[0], 0) < 0) + exit(3); + close(pipe_fds[0]); + + /* Write init_data and close write side */ + ret = write(pipe_fds[1], &init_data, sizeof(init_data)); + close(pipe_fds[1]); + + if (ret != sizeof(init_data)) + exit(4); + + execveat(stub_exe_fd, "", argv, NULL, AT_EMPTY_PATH); + + exit(5); +} + +extern char stub_exe_start[]; +extern char stub_exe_end[]; + +extern char *tempdir; + +#define STUB_EXE_NAME_TEMPLATE "/uml-userspace-XXXXXX" + +#ifndef MFD_EXEC +#define MFD_EXEC 0x0010U +#endif + +static int __init init_stub_exe_fd(void) +{ + size_t written = 0; + char *tmpfile = NULL; + + stub_exe_fd = memfd_create("uml-userspace", + MFD_EXEC | MFD_CLOEXEC | MFD_ALLOW_SEALING); + + if (stub_exe_fd < 0) { + printk(UM_KERN_INFO "Could not create executable memfd, using temporary file!"); + + tmpfile = malloc(strlen(tempdir) + + strlen(STUB_EXE_NAME_TEMPLATE) + 1); + if (tmpfile == NULL) + panic("Failed to allocate memory for stub binary name"); + + strcpy(tmpfile, tempdir); + strcat(tmpfile, STUB_EXE_NAME_TEMPLATE); + + stub_exe_fd = mkstemp(tmpfile); + if (stub_exe_fd < 0) + panic("Could not create temporary file for stub binary: %d", + -errno); } - fd = phys_mapping(uml_to_phys(stack), &offset); - addr = mmap((void *) STUB_DATA, - STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_SHARED, fd, offset); - if (addr == MAP_FAILED) { - os_info("mapping segfault stack at 0x%lx failed, errno = %d\n", - STUB_DATA, errno); - exit(1); + while (written < stub_exe_end - stub_exe_start) { + ssize_t res = write(stub_exe_fd, stub_exe_start + written, + stub_exe_end - stub_exe_start - written); + if (res < 0) { + if (errno == EINTR) + continue; + + if (tmpfile) + unlink(tmpfile); + panic("Failed write stub binary: %d", -errno); + } + + written += res; } - 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 *) segv_handler; - sa.sa_restorer = NULL; - if (sigaction(SIGSEGV, &sa, NULL) < 0) { - os_info("%s - setting SIGSEGV handler failed - errno = %d\n", - __func__, errno); - exit(1); + if (!tmpfile) { + fcntl(stub_exe_fd, F_ADD_SEALS, + F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL); + } else { + if (fchmod(stub_exe_fd, 00500) < 0) { + unlink(tmpfile); + panic("Could not make stub binary executable: %d", + -errno); + } + + close(stub_exe_fd); + stub_exe_fd = open(tmpfile, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); + if (stub_exe_fd < 0) { + unlink(tmpfile); + panic("Could not reopen stub binary: %d", -errno); + } + + unlink(tmpfile); + free(tmpfile); } - kill(os_getpid(), SIGSTOP); return 0; } +__initcall(init_stub_exe_fd); int userspace_pid[NR_CPUS]; @@ -270,7 +322,7 @@ int start_userspace(unsigned long stub_stack) { void *stack; unsigned long sp; - int pid, status, n, flags, err; + int pid, status, n, err; /* setup a temporary stack page */ stack = mmap(NULL, UM_KERN_PAGE_SIZE, @@ -286,10 +338,10 @@ int start_userspace(unsigned long stub_stack) /* set stack pointer to the end of the stack page, so it can grow downwards */ sp = (unsigned long)stack + UM_KERN_PAGE_SIZE; - flags = CLONE_FILES | SIGCHLD; - /* clone into new userspace process */ - pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); + pid = clone(userspace_tramp, (void *) sp, + CLONE_VFORK | CLONE_VM | SIGCHLD, + (void *)stub_stack); if (pid < 0) { err = -errno; printk(UM_KERN_ERR "%s : clone failed, errno = %d\n", @@ -336,7 +388,10 @@ int start_userspace(unsigned long stub_stack) return err; } -void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) +int unscheduled_userspace_iterations; +extern unsigned long tt_extra_sched_jiffies; + +void userspace(struct uml_pt_regs *regs) { int err, status, op, pid = userspace_pid[0]; siginfo_t si; @@ -345,6 +400,29 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) interrupt_end(); while (1) { + /* + * When we are in time-travel mode, userspace can theoretically + * do a *lot* of work without being scheduled. The problem with + * this is that it will prevent kernel bookkeeping (primarily + * the RCU) from running and this can for example cause OOM + * situations. + * + * This code accounts a jiffie against the scheduling clock + * after the defined userspace iterations in the same thread. + * By doing so the situation is effectively prevented. + */ + if (time_travel_mode == TT_MODE_INFCPU || + time_travel_mode == TT_MODE_EXTERNAL) { +#ifdef CONFIG_UML_MAX_USERSPACE_ITERATIONS + if (CONFIG_UML_MAX_USERSPACE_ITERATIONS && + unscheduled_userspace_iterations++ > + CONFIG_UML_MAX_USERSPACE_ITERATIONS) { + tt_extra_sched_jiffies += 1; + unscheduled_userspace_iterations = 0; + } +#endif + } + time_travel_print_bc_msg(); current_mm_sync(); @@ -435,11 +513,11 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) case SIGSEGV: if (PTRACE_FULL_FAULTINFO) { get_skas_faultinfo(pid, - ®s->faultinfo, aux_fp_regs); + ®s->faultinfo); (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si, regs); } - else handle_segv(pid, regs, aux_fp_regs); + else handle_segv(pid, regs); break; case SIGTRAP + 0x80: handle_trap(pid, regs); @@ -487,6 +565,8 @@ void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) void switch_threads(jmp_buf *me, jmp_buf *you) { + unscheduled_userspace_iterations = 0; + if (UML_SETJMP(me) == 0) UML_LONGJMP(you, 1); } @@ -570,6 +650,7 @@ static bool noreboot; static int __init noreboot_cmd_param(char *str, int *add) { + *add = 0; noreboot = true; return 0; } diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index e09d65b05d1cab..eb523ab1e2189b 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -358,6 +358,8 @@ char *get_umid(void) static int __init set_uml_dir(char *name, int *add) { + *add = 0; + if (*name == '\0') { os_warn("uml_dir can't be an empty string\n"); return 0; diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index 1dca4ffbd572f7..4193e04d7e4a7f 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -52,8 +52,8 @@ void setup_machinename(char *machine_out) struct utsname host; uname(&host); -#ifdef UML_CONFIG_UML_X86 -# ifndef UML_CONFIG_64BIT +#if IS_ENABLED(CONFIG_UML_X86) +# if !IS_ENABLED(CONFIG_64BIT) if (!strcmp(host.machine, "x86_64")) { strcpy(machine_out, "i686"); return; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7b9a7e8f39acc8..9d7bd0ae48c426 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -83,6 +83,7 @@ config X86 select ARCH_HAS_DMA_OPS if GART_IOMMU || XEN select ARCH_HAS_EARLY_DEBUG if KGDB select ARCH_HAS_ELF_RANDOMIZE + select ARCH_HAS_EXECMEM_ROX if X86_64 select ARCH_HAS_FAST_MULTIPLIER select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL @@ -93,6 +94,7 @@ config X86 select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PMEM_API if X86_64 + select ARCH_HAS_PREEMPT_LAZY select ARCH_HAS_PTE_DEVMAP if X86_64 select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_HW_PTE_YOUNG @@ -126,6 +128,8 @@ config X86 select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_LTO_CLANG_THIN select ARCH_SUPPORTS_RT + select ARCH_SUPPORTS_AUTOFDO_CLANG + select ARCH_SUPPORTS_PROPELLER_CLANG if X86_64 select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF if X86_CMPXCHG64 select ARCH_USE_MEMTEST @@ -145,7 +149,6 @@ config X86 select ARCH_HAS_PARANOID_L1D_FLUSH select BUILDTIME_TABLE_SORT select CLKEVT_I8253 - select CLOCKSOURCE_VALIDATE_LAST_CYCLE select CLOCKSOURCE_WATCHDOG # Word-size accesses may read uninitialized data past the trailing \0 # in strings and cause false KMSAN reports. @@ -1954,6 +1957,7 @@ config X86_USER_SHADOW_STACK depends on AS_WRUSS depends on X86_64 select ARCH_USES_HIGH_VMA_FLAGS + select ARCH_HAS_USER_SHADOW_STACK select X86_CET help Shadow stack protection is a hardware feature that detects function @@ -2427,6 +2431,14 @@ config CFI_AUTO_DEFAULT source "kernel/livepatch/Kconfig" +config X86_BUS_LOCK_DETECT + bool "Split Lock Detect and Bus Lock Detect support" + depends on CPU_SUP_INTEL || CPU_SUP_AMD + default y + help + Enable Split Lock Detect and Bus Lock Detect functionalities. + See for more information. + endmenu config CC_HAS_NAMED_AS @@ -2555,15 +2567,14 @@ config MITIGATION_CALL_DEPTH_TRACKING default y help Compile the kernel with call depth tracking to mitigate the Intel - SKL Return-Speculation-Buffer (RSB) underflow issue. The - mitigation is off by default and needs to be enabled on the - kernel command line via the retbleed=stuff option. For - non-affected systems the overhead of this option is marginal as - the call depth tracking is using run-time generated call thunks - in a compiler generated padding area and call patching. This - increases text size by ~5%. For non affected systems this space - is unused. On affected SKL systems this results in a significant - performance gain over the IBRS mitigation. + SKL Return-Stack-Buffer (RSB) underflow issue. The mitigation is off + by default and needs to be enabled on the kernel command line via the + retbleed=stuff option. For non-affected systems the overhead of this + option is marginal as the call depth tracking is using run-time + generated call thunks in a compiler generated padding area and call + patching. This increases text size by ~5%. For non affected systems + this space is unused. On affected SKL systems this results in a + significant performance gain over the IBRS mitigation. config CALL_THUNKS_DEBUG bool "Enable call thunks and call depth tracking debugging" diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h index 148ba5c5106e1e..0f24f7ebec9baa 100644 --- a/arch/x86/boot/boot.h +++ b/arch/x86/boot/boot.h @@ -305,7 +305,6 @@ void initregs(struct biosregs *regs); int strcmp(const char *str1, const char *str2); int strncmp(const char *cs, const char *ct, size_t count); size_t strnlen(const char *s, size_t maxlen); -unsigned int atou(const char *s); unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base); size_t strlen(const char *s); char *strchr(const char *s, int c); diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 04a35b2c26e9be..0d37420cad0259 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -385,6 +385,19 @@ static void parse_mem_encrypt(struct setup_header *hdr) hdr->xloadflags |= XLF_MEM_ENCRYPTION; } +static void early_sev_detect(void) +{ + /* + * Accessing video memory causes guest termination because + * the boot stage2 #VC handler of SEV-ES/SNP guests does not + * support MMIO handling and kexec -c adds screen_info to the + * boot parameters passed to the kexec kernel, which causes + * console output to be dumped to both video and serial. + */ + if (sev_status & MSR_AMD64_SEV_ES_ENABLED) + lines = cols = 0; +} + /* * The compressed kernel image (ZO), has been moved so that its position * is against the end of the buffer used to hold the uncompressed kernel @@ -440,6 +453,8 @@ asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output) */ early_tdx_detect(); + early_sev_detect(); + console_init(); /* diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index c23f3b9c84fe9c..84f7a883ce1e82 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c @@ -88,14 +88,6 @@ size_t strnlen(const char *s, size_t maxlen) return (es - s); } -unsigned int atou(const char *s) -{ - unsigned int i = 0; - while (isdigit(*s)) - i = i * 10 + (*s++ - '0'); - return i; -} - /* Works only for digits and letters, but small and fast */ #define TOLOWER(x) ((x) | 0x20) diff --git a/arch/x86/boot/string.h b/arch/x86/boot/string.h index e5d2c6b8c2f1dc..a5b05ebc037de5 100644 --- a/arch/x86/boot/string.h +++ b/arch/x86/boot/string.h @@ -24,7 +24,6 @@ extern size_t strlen(const char *s); extern char *strstr(const char *s1, const char *s2); extern char *strchr(const char *s, int c); extern size_t strnlen(const char *s, size_t maxlen); -extern unsigned int atou(const char *s); extern unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base); long simple_strtol(const char *cp, char **endp, unsigned int base); diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c index de1df0cb45dab2..c5b0148b8c0a19 100644 --- a/arch/x86/coco/sev/core.c +++ b/arch/x86/coco/sev/core.c @@ -92,6 +92,9 @@ static struct ghcb *boot_ghcb __section(".data"); /* Bitmap of SEV features supported by the hypervisor */ static u64 sev_hv_features __ro_after_init; +/* Secrets page physical address from the CC blob */ +static u64 secrets_pa __ro_after_init; + /* #VC handler runtime per-CPU data */ struct sev_es_runtime_data { struct ghcb ghcb_page; @@ -141,33 +144,6 @@ static DEFINE_PER_CPU(struct sev_es_save_area *, sev_vmsa); static DEFINE_PER_CPU(struct svsm_ca *, svsm_caa); static DEFINE_PER_CPU(u64, svsm_caa_pa); -struct sev_config { - __u64 debug : 1, - - /* - * Indicates when the per-CPU GHCB has been created and registered - * and thus can be used by the BSP instead of the early boot GHCB. - * - * For APs, the per-CPU GHCB is created before they are started - * and registered upon startup, so this flag can be used globally - * for the BSP and APs. - */ - ghcbs_initialized : 1, - - /* - * Indicates when the per-CPU SVSM CA is to be used instead of the - * boot SVSM CA. - * - * For APs, the per-CPU SVSM CA is created as part of the AP - * bringup, so this flag can be used globally for the BSP and APs. - */ - use_cas : 1, - - __reserved : 61; -}; - -static struct sev_config sev_cfg __read_mostly; - static __always_inline bool on_vc_stack(struct pt_regs *regs) { unsigned long sp = regs->sp; @@ -722,45 +698,13 @@ void noinstr __sev_es_nmi_complete(void) __sev_put_ghcb(&state); } -static u64 __init get_secrets_page(void) -{ - u64 pa_data = boot_params.cc_blob_address; - struct cc_blob_sev_info info; - void *map; - - /* - * The CC blob contains the address of the secrets page, check if the - * blob is present. - */ - if (!pa_data) - return 0; - - map = early_memremap(pa_data, sizeof(info)); - if (!map) { - pr_err("Unable to locate SNP secrets page: failed to map the Confidential Computing blob.\n"); - return 0; - } - memcpy(&info, map, sizeof(info)); - early_memunmap(map, sizeof(info)); - - /* smoke-test the secrets page passed */ - if (!info.secrets_phys || info.secrets_len != PAGE_SIZE) - return 0; - - return info.secrets_phys; -} - static u64 __init get_snp_jump_table_addr(void) { struct snp_secrets_page *secrets; void __iomem *mem; - u64 pa, addr; + u64 addr; - pa = get_secrets_page(); - if (!pa) - return 0; - - mem = ioremap_encrypted(pa, PAGE_SIZE); + mem = ioremap_encrypted(secrets_pa, PAGE_SIZE); if (!mem) { pr_err("Unable to locate AP jump table address: failed to map the SNP secrets page.\n"); return 0; @@ -1010,6 +954,137 @@ void snp_accept_memory(phys_addr_t start, phys_addr_t end) set_pages_state(vaddr, npages, SNP_PAGE_STATE_PRIVATE); } +static void set_pte_enc(pte_t *kpte, int level, void *va) +{ + struct pte_enc_desc d = { + .kpte = kpte, + .pte_level = level, + .va = va, + .encrypt = true + }; + + prepare_pte_enc(&d); + set_pte_enc_mask(kpte, d.pfn, d.new_pgprot); +} + +static void unshare_all_memory(void) +{ + unsigned long addr, end, size, ghcb; + struct sev_es_runtime_data *data; + unsigned int npages, level; + bool skipped_addr; + pte_t *pte; + int cpu; + + /* Unshare the direct mapping. */ + addr = PAGE_OFFSET; + end = PAGE_OFFSET + get_max_mapped(); + + while (addr < end) { + pte = lookup_address(addr, &level); + size = page_level_size(level); + npages = size / PAGE_SIZE; + skipped_addr = false; + + if (!pte || !pte_decrypted(*pte) || pte_none(*pte)) { + addr += size; + continue; + } + + /* + * Ensure that all the per-CPU GHCBs are made private at the + * end of the unsharing loop so that the switch to the slower + * MSR protocol happens last. + */ + for_each_possible_cpu(cpu) { + data = per_cpu(runtime_data, cpu); + ghcb = (unsigned long)&data->ghcb_page; + + if (addr <= ghcb && ghcb <= addr + size) { + skipped_addr = true; + break; + } + } + + if (!skipped_addr) { + set_pte_enc(pte, level, (void *)addr); + snp_set_memory_private(addr, npages); + } + addr += size; + } + + /* Unshare all bss decrypted memory. */ + addr = (unsigned long)__start_bss_decrypted; + end = (unsigned long)__start_bss_decrypted_unused; + npages = (end - addr) >> PAGE_SHIFT; + + for (; addr < end; addr += PAGE_SIZE) { + pte = lookup_address(addr, &level); + if (!pte || !pte_decrypted(*pte) || pte_none(*pte)) + continue; + + set_pte_enc(pte, level, (void *)addr); + } + addr = (unsigned long)__start_bss_decrypted; + snp_set_memory_private(addr, npages); + + __flush_tlb_all(); +} + +/* Stop new private<->shared conversions */ +void snp_kexec_begin(void) +{ + if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP)) + return; + + if (!IS_ENABLED(CONFIG_KEXEC_CORE)) + return; + + /* + * Crash kernel ends up here with interrupts disabled: can't wait for + * conversions to finish. + * + * If race happened, just report and proceed. + */ + if (!set_memory_enc_stop_conversion()) + pr_warn("Failed to stop shared<->private conversions\n"); +} + +void snp_kexec_finish(void) +{ + struct sev_es_runtime_data *data; + unsigned int level, cpu; + unsigned long size; + struct ghcb *ghcb; + pte_t *pte; + + if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP)) + return; + + if (!IS_ENABLED(CONFIG_KEXEC_CORE)) + return; + + unshare_all_memory(); + + /* + * Switch to using the MSR protocol to change per-CPU GHCBs to + * private. All the per-CPU GHCBs have been switched back to private, + * so can't do any more GHCB calls to the hypervisor beyond this point + * until the kexec'ed kernel starts running. + */ + boot_ghcb = NULL; + sev_cfg.ghcbs_initialized = false; + + for_each_possible_cpu(cpu) { + data = per_cpu(runtime_data, cpu); + ghcb = &data->ghcb_page; + pte = lookup_address((unsigned long)ghcb, &level); + size = page_level_size(level); + set_pte_enc(pte, level, (void *)ghcb); + snp_set_memory_private((unsigned long)ghcb, (size / PAGE_SIZE)); + } +} + static int snp_set_vmsa(void *va, void *caa, int apic_id, bool make_vmsa) { int ret; @@ -1331,35 +1406,39 @@ int __init sev_es_efi_map_ghcbs(pgd_t *pgd) return 0; } +/* Writes to the SVSM CAA MSR are ignored */ +static enum es_result __vc_handle_msr_caa(struct pt_regs *regs, bool write) +{ + if (write) + return ES_OK; + + regs->ax = lower_32_bits(this_cpu_read(svsm_caa_pa)); + regs->dx = upper_32_bits(this_cpu_read(svsm_caa_pa)); + + return ES_OK; +} + static enum es_result vc_handle_msr(struct ghcb *ghcb, struct es_em_ctxt *ctxt) { struct pt_regs *regs = ctxt->regs; enum es_result ret; - u64 exit_info_1; + bool write; /* Is it a WRMSR? */ - exit_info_1 = (ctxt->insn.opcode.bytes[1] == 0x30) ? 1 : 0; + write = ctxt->insn.opcode.bytes[1] == 0x30; - if (regs->cx == MSR_SVSM_CAA) { - /* Writes to the SVSM CAA msr are ignored */ - if (exit_info_1) - return ES_OK; - - regs->ax = lower_32_bits(this_cpu_read(svsm_caa_pa)); - regs->dx = upper_32_bits(this_cpu_read(svsm_caa_pa)); - - return ES_OK; - } + if (regs->cx == MSR_SVSM_CAA) + return __vc_handle_msr_caa(regs, write); ghcb_set_rcx(ghcb, regs->cx); - if (exit_info_1) { + if (write) { ghcb_set_rax(ghcb, regs->ax); ghcb_set_rdx(ghcb, regs->dx); } - ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MSR, exit_info_1, 0); + ret = sev_es_ghcb_hv_call(ghcb, ctxt, SVM_EXIT_MSR, write, 0); - if ((ret == ES_OK) && (!exit_info_1)) { + if ((ret == ES_OK) && !write) { regs->ax = ghcb->save.rax; regs->dx = ghcb->save.rdx; } @@ -2300,6 +2379,11 @@ bool __head snp_init(struct boot_params *bp) if (!cc_info) return false; + if (cc_info->secrets_phys && cc_info->secrets_len == PAGE_SIZE) + secrets_pa = cc_info->secrets_phys; + else + return false; + setup_cpuid_table(cc_info); svsm_setup(cc_info); @@ -2374,23 +2458,6 @@ static int __init report_snp_info(void) } arch_initcall(report_snp_info); -static int __init init_sev_config(char *str) -{ - char *s; - - while ((s = strsep(&str, ","))) { - if (!strcmp(s, "debug")) { - sev_cfg.debug = true; - continue; - } - - pr_info("SEV command-line option '%s' was not recognized\n", s); - } - - return 1; -} -__setup("sev=", init_sev_config); - static void update_attest_input(struct svsm_call *call, struct svsm_attest_call *input) { /* If (new) lengths have been returned, propagate them up */ @@ -2441,7 +2508,8 @@ int snp_issue_svsm_attest_req(u64 call_id, struct svsm_call *call, } EXPORT_SYMBOL_GPL(snp_issue_svsm_attest_req); -int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio) +int snp_issue_guest_request(struct snp_guest_req *req, struct snp_req_data *input, + struct snp_guest_request_ioctl *rio) { struct ghcb_state state; struct es_em_ctxt ctxt; @@ -2465,12 +2533,12 @@ int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct sn vc_ghcb_invalidate(ghcb); - if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST) { + if (req->exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST) { ghcb_set_rax(ghcb, input->data_gpa); ghcb_set_rbx(ghcb, input->data_npages); } - ret = sev_es_ghcb_hv_call(ghcb, &ctxt, exit_code, input->req_gpa, input->resp_gpa); + ret = sev_es_ghcb_hv_call(ghcb, &ctxt, req->exit_code, input->req_gpa, input->resp_gpa); if (ret) goto e_put; @@ -2485,7 +2553,7 @@ int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct sn case SNP_GUEST_VMM_ERR(SNP_GUEST_VMM_ERR_INVALID_LEN): /* Number of expected pages are returned in RBX */ - if (exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST) { + if (req->exit_code == SVM_VMGEXIT_EXT_GUEST_REQUEST) { input->data_npages = ghcb_get_rbx(ghcb); ret = -ENOSPC; break; @@ -2513,16 +2581,11 @@ static struct platform_device sev_guest_device = { static int __init snp_init_platform_device(void) { struct sev_guest_platform_data data; - u64 gpa; if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP)) return -ENODEV; - gpa = get_secrets_page(); - if (!gpa) - return -ENODEV; - - data.secrets_gpa = gpa; + data.secrets_gpa = secrets_pa; if (platform_device_add_data(&sev_guest_device, &data, sizeof(data))) return -ENODEV; diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index 327c45c5013fea..0d9b090b48808b 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -78,6 +78,32 @@ static inline void tdcall(u64 fn, struct tdx_module_args *args) panic("TDCALL %lld failed (Buggy TDX module!)\n", fn); } +/* Read TD-scoped metadata */ +static inline u64 tdg_vm_rd(u64 field, u64 *value) +{ + struct tdx_module_args args = { + .rdx = field, + }; + u64 ret; + + ret = __tdcall_ret(TDG_VM_RD, &args); + *value = args.r8; + + return ret; +} + +/* Write TD-scoped metadata */ +static inline u64 tdg_vm_wr(u64 field, u64 value, u64 mask) +{ + struct tdx_module_args args = { + .rdx = field, + .r8 = value, + .r9 = mask, + }; + + return __tdcall(TDG_VM_WR, &args); +} + /** * tdx_mcall_get_report0() - Wrapper to get TDREPORT0 (a.k.a. TDREPORT * subtype 0) using TDG.MR.REPORT TDCALL. @@ -168,7 +194,87 @@ static void __noreturn tdx_panic(const char *msg) __tdx_hypercall(&args); } -static void tdx_parse_tdinfo(u64 *cc_mask) +/* + * The kernel cannot handle #VEs when accessing normal kernel memory. Ensure + * that no #VE will be delivered for accesses to TD-private memory. + * + * TDX 1.0 does not allow the guest to disable SEPT #VE on its own. The VMM + * controls if the guest will receive such #VE with TD attribute + * ATTR_SEPT_VE_DISABLE. + * + * Newer TDX modules allow the guest to control if it wants to receive SEPT + * violation #VEs. + * + * Check if the feature is available and disable SEPT #VE if possible. + * + * If the TD is allowed to disable/enable SEPT #VEs, the ATTR_SEPT_VE_DISABLE + * attribute is no longer reliable. It reflects the initial state of the + * control for the TD, but it will not be updated if someone (e.g. bootloader) + * changes it before the kernel starts. Kernel must check TDCS_TD_CTLS bit to + * determine if SEPT #VEs are enabled or disabled. + */ +static void disable_sept_ve(u64 td_attr) +{ + const char *msg = "TD misconfiguration: SEPT #VE has to be disabled"; + bool debug = td_attr & ATTR_DEBUG; + u64 config, controls; + + /* Is this TD allowed to disable SEPT #VE */ + tdg_vm_rd(TDCS_CONFIG_FLAGS, &config); + if (!(config & TDCS_CONFIG_FLEXIBLE_PENDING_VE)) { + /* No SEPT #VE controls for the guest: check the attribute */ + if (td_attr & ATTR_SEPT_VE_DISABLE) + return; + + /* Relax SEPT_VE_DISABLE check for debug TD for backtraces */ + if (debug) + pr_warn("%s\n", msg); + else + tdx_panic(msg); + return; + } + + /* Check if SEPT #VE has been disabled before us */ + tdg_vm_rd(TDCS_TD_CTLS, &controls); + if (controls & TD_CTLS_PENDING_VE_DISABLE) + return; + + /* Keep #VEs enabled for splats in debugging environments */ + if (debug) + return; + + /* Disable SEPT #VEs */ + tdg_vm_wr(TDCS_TD_CTLS, TD_CTLS_PENDING_VE_DISABLE, + TD_CTLS_PENDING_VE_DISABLE); +} + +/* + * TDX 1.0 generates a #VE when accessing topology-related CPUID leafs (0xB and + * 0x1F) and the X2APIC_APICID MSR. The kernel returns all zeros on CPUID #VEs. + * In practice, this means that the kernel can only boot with a plain topology. + * Any complications will cause problems. + * + * The ENUM_TOPOLOGY feature allows the VMM to provide topology information. + * Enabling the feature eliminates topology-related #VEs: the TDX module + * virtualizes accesses to the CPUID leafs and the MSR. + * + * Enable ENUM_TOPOLOGY if it is available. + */ +static void enable_cpu_topology_enumeration(void) +{ + u64 configured; + + /* Has the VMM provided a valid topology configuration? */ + tdg_vm_rd(TDCS_TOPOLOGY_ENUM_CONFIGURED, &configured); + if (!configured) { + pr_err("VMM did not configure X2APIC_IDs properly\n"); + return; + } + + tdg_vm_wr(TDCS_TD_CTLS, TD_CTLS_ENUM_TOPOLOGY, TD_CTLS_ENUM_TOPOLOGY); +} + +static void tdx_setup(u64 *cc_mask) { struct tdx_module_args args = {}; unsigned int gpa_width; @@ -193,21 +299,13 @@ static void tdx_parse_tdinfo(u64 *cc_mask) gpa_width = args.rcx & GENMASK(5, 0); *cc_mask = BIT_ULL(gpa_width - 1); - /* - * The kernel can not handle #VE's when accessing normal kernel - * memory. Ensure that no #VE will be delivered for accesses to - * TD-private memory. Only VMM-shared memory (MMIO) will #VE. - */ td_attr = args.rdx; - if (!(td_attr & ATTR_SEPT_VE_DISABLE)) { - const char *msg = "TD misconfiguration: SEPT_VE_DISABLE attribute must be set."; - /* Relax SEPT_VE_DISABLE check for debug TD. */ - if (td_attr & ATTR_DEBUG) - pr_warn("%s\n", msg); - else - tdx_panic(msg); - } + /* Kernel does not use NOTIFY_ENABLES and does not need random #VEs */ + tdg_vm_wr(TDCS_NOTIFY_ENABLES, 0, -1ULL); + + disable_sept_ve(td_attr); + enable_cpu_topology_enumeration(); } /* @@ -929,10 +1027,6 @@ static void tdx_kexec_finish(void) void __init tdx_early_init(void) { - struct tdx_module_args args = { - .rdx = TDCS_NOTIFY_ENABLES, - .r9 = -1ULL, - }; u64 cc_mask; u32 eax, sig[3]; @@ -947,11 +1041,11 @@ void __init tdx_early_init(void) setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE); cc_vendor = CC_VENDOR_INTEL; - tdx_parse_tdinfo(&cc_mask); - cc_set_mask(cc_mask); - /* Kernel does not use NOTIFY_ENABLES and does not need random #VEs */ - tdcall(TDG_VM_WR, &args); + /* Configure the TD */ + tdx_setup(&cc_mask); + + cc_set_mask(cc_mask); /* * All bits above GPA width are reserved and kernel treats shared bit diff --git a/arch/x86/crypto/Kconfig b/arch/x86/crypto/Kconfig index 7b1bebed879df3..3d2e38ba524033 100644 --- a/arch/x86/crypto/Kconfig +++ b/arch/x86/crypto/Kconfig @@ -363,7 +363,7 @@ config CRYPTO_CHACHA20_X86_64 - AVX-512VL (Advanced Vector Extensions-512VL) config CRYPTO_AEGIS128_AESNI_SSE2 - tristate "AEAD ciphers: AEGIS-128 (AES-NI/SSE2)" + tristate "AEAD ciphers: AEGIS-128 (AES-NI/SSE4.1)" depends on X86 && 64BIT select CRYPTO_AEAD select CRYPTO_SIMD @@ -372,7 +372,7 @@ config CRYPTO_AEGIS128_AESNI_SSE2 Architecture: x86_64 using: - AES-NI (AES New Instructions) - - SSE2 (Streaming SIMD Extensions 2) + - SSE4.1 (Streaming SIMD Extensions 4.1) config CRYPTO_NHPOLY1305_SSE2 tristate "Hash functions: NHPoly1305 (SSE2)" diff --git a/arch/x86/crypto/aegis128-aesni-asm.S b/arch/x86/crypto/aegis128-aesni-asm.S index ad7f4c89162568..7294dc0ee7baaa 100644 --- a/arch/x86/crypto/aegis128-aesni-asm.S +++ b/arch/x86/crypto/aegis128-aesni-asm.S @@ -1,14 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * AES-NI + SSE2 implementation of AEGIS-128 + * AES-NI + SSE4.1 implementation of AEGIS-128 * * Copyright (c) 2017-2018 Ondrej Mosnacek * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. + * Copyright 2024 Google LLC */ #include -#include -#include #define STATE0 %xmm0 #define STATE1 %xmm1 @@ -20,11 +19,6 @@ #define T0 %xmm6 #define T1 %xmm7 -#define STATEP %rdi -#define LEN %rsi -#define SRC %rdx -#define DST %rcx - .section .rodata.cst16.aegis128_const, "aM", @progbits, 32 .align 16 .Laegis128_const_0: @@ -34,11 +28,11 @@ .byte 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1 .byte 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd -.section .rodata.cst16.aegis128_counter, "aM", @progbits, 16 -.align 16 -.Laegis128_counter: - .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 - .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +.section .rodata.cst32.zeropad_mask, "aM", @progbits, 32 +.align 32 +.Lzeropad_mask: + .octa 0xffffffffffffffffffffffffffffffff + .octa 0 .text @@ -61,140 +55,102 @@ .endm /* - * __load_partial: internal ABI - * input: - * LEN - bytes - * SRC - src - * output: - * MSG - message block - * changed: - * T0 - * %r8 - * %r9 + * Load 1 <= LEN (%ecx) <= 15 bytes from the pointer SRC into the xmm register + * MSG and zeroize any remaining bytes. Clobbers %rax, %rcx, and %r8. */ -SYM_FUNC_START_LOCAL(__load_partial) - xor %r9d, %r9d - pxor MSG, MSG - - mov LEN, %r8 - and $0x1, %r8 - jz .Lld_partial_1 - - mov LEN, %r8 - and $0x1E, %r8 - add SRC, %r8 - mov (%r8), %r9b - -.Lld_partial_1: - mov LEN, %r8 - and $0x2, %r8 - jz .Lld_partial_2 - - mov LEN, %r8 - and $0x1C, %r8 - add SRC, %r8 - shl $0x10, %r9 - mov (%r8), %r9w - -.Lld_partial_2: - mov LEN, %r8 - and $0x4, %r8 - jz .Lld_partial_4 - - mov LEN, %r8 - and $0x18, %r8 - add SRC, %r8 - shl $32, %r9 - mov (%r8), %r8d - xor %r8, %r9 - -.Lld_partial_4: - movq %r9, MSG - - mov LEN, %r8 - and $0x8, %r8 - jz .Lld_partial_8 - - mov LEN, %r8 - and $0x10, %r8 - add SRC, %r8 - pslldq $8, MSG - movq (%r8), T0 - pxor T0, MSG - -.Lld_partial_8: - RET -SYM_FUNC_END(__load_partial) +.macro load_partial + sub $8, %ecx /* LEN - 8 */ + jle .Lle8\@ + + /* Load 9 <= LEN <= 15 bytes: */ + movq (SRC), MSG /* Load first 8 bytes */ + mov (SRC, %rcx), %rax /* Load last 8 bytes */ + neg %ecx + shl $3, %ecx + shr %cl, %rax /* Discard overlapping bytes */ + pinsrq $1, %rax, MSG + jmp .Ldone\@ + +.Lle8\@: + add $4, %ecx /* LEN - 4 */ + jl .Llt4\@ + + /* Load 4 <= LEN <= 8 bytes: */ + mov (SRC), %eax /* Load first 4 bytes */ + mov (SRC, %rcx), %r8d /* Load last 4 bytes */ + jmp .Lcombine\@ + +.Llt4\@: + /* Load 1 <= LEN <= 3 bytes: */ + add $2, %ecx /* LEN - 2 */ + movzbl (SRC), %eax /* Load first byte */ + jl .Lmovq\@ + movzwl (SRC, %rcx), %r8d /* Load last 2 bytes */ +.Lcombine\@: + shl $3, %ecx + shl %cl, %r8 + or %r8, %rax /* Combine the two parts */ +.Lmovq\@: + movq %rax, MSG +.Ldone\@: +.endm /* - * __store_partial: internal ABI - * input: - * LEN - bytes - * DST - dst - * output: - * T0 - message block - * changed: - * %r8 - * %r9 - * %r10 + * Store 1 <= LEN (%ecx) <= 15 bytes from the xmm register \msg to the pointer + * DST. Clobbers %rax, %rcx, and %r8. */ -SYM_FUNC_START_LOCAL(__store_partial) - mov LEN, %r8 - mov DST, %r9 - - movq T0, %r10 - - cmp $8, %r8 - jl .Lst_partial_8 - - mov %r10, (%r9) - psrldq $8, T0 - movq T0, %r10 - - sub $8, %r8 - add $8, %r9 - -.Lst_partial_8: - cmp $4, %r8 - jl .Lst_partial_4 - - mov %r10d, (%r9) - shr $32, %r10 - - sub $4, %r8 - add $4, %r9 - -.Lst_partial_4: - cmp $2, %r8 - jl .Lst_partial_2 - - mov %r10w, (%r9) - shr $0x10, %r10 - - sub $2, %r8 - add $2, %r9 - -.Lst_partial_2: - cmp $1, %r8 - jl .Lst_partial_1 - - mov %r10b, (%r9) - -.Lst_partial_1: - RET -SYM_FUNC_END(__store_partial) +.macro store_partial msg + sub $8, %ecx /* LEN - 8 */ + jl .Llt8\@ + + /* Store 8 <= LEN <= 15 bytes: */ + pextrq $1, \msg, %rax + mov %ecx, %r8d + shl $3, %ecx + ror %cl, %rax + mov %rax, (DST, %r8) /* Store last LEN - 8 bytes */ + movq \msg, (DST) /* Store first 8 bytes */ + jmp .Ldone\@ + +.Llt8\@: + add $4, %ecx /* LEN - 4 */ + jl .Llt4\@ + + /* Store 4 <= LEN <= 7 bytes: */ + pextrd $1, \msg, %eax + mov %ecx, %r8d + shl $3, %ecx + ror %cl, %eax + mov %eax, (DST, %r8) /* Store last LEN - 4 bytes */ + movd \msg, (DST) /* Store first 4 bytes */ + jmp .Ldone\@ + +.Llt4\@: + /* Store 1 <= LEN <= 3 bytes: */ + pextrb $0, \msg, 0(DST) + cmp $-2, %ecx /* LEN - 4 == -2, i.e. LEN == 2? */ + jl .Ldone\@ + pextrb $1, \msg, 1(DST) + je .Ldone\@ + pextrb $2, \msg, 2(DST) +.Ldone\@: +.endm /* - * void crypto_aegis128_aesni_init(void *state, const void *key, const void *iv); + * void aegis128_aesni_init(struct aegis_state *state, + * const struct aegis_block *key, + * const u8 iv[AEGIS128_NONCE_SIZE]); */ -SYM_FUNC_START(crypto_aegis128_aesni_init) - FRAME_BEGIN +SYM_FUNC_START(aegis128_aesni_init) + .set STATEP, %rdi + .set KEYP, %rsi + .set IVP, %rdx /* load IV: */ - movdqu (%rdx), T1 + movdqu (IVP), T1 /* load key: */ - movdqa (%rsi), KEY + movdqa (KEYP), KEY pxor KEY, T1 movdqa T1, STATE0 movdqa KEY, STATE3 @@ -224,20 +180,22 @@ SYM_FUNC_START(crypto_aegis128_aesni_init) movdqu STATE2, 0x20(STATEP) movdqu STATE3, 0x30(STATEP) movdqu STATE4, 0x40(STATEP) - - FRAME_END RET -SYM_FUNC_END(crypto_aegis128_aesni_init) +SYM_FUNC_END(aegis128_aesni_init) /* - * void crypto_aegis128_aesni_ad(void *state, unsigned int length, - * const void *data); + * void aegis128_aesni_ad(struct aegis_state *state, const u8 *data, + * unsigned int len); + * + * len must be a multiple of 16. */ -SYM_FUNC_START(crypto_aegis128_aesni_ad) - FRAME_BEGIN +SYM_FUNC_START(aegis128_aesni_ad) + .set STATEP, %rdi + .set SRC, %rsi + .set LEN, %edx - cmp $0x10, LEN - jb .Lad_out + test LEN, LEN + jz .Lad_out /* load the state: */ movdqu 0x00(STATEP), STATE0 @@ -246,89 +204,40 @@ SYM_FUNC_START(crypto_aegis128_aesni_ad) movdqu 0x30(STATEP), STATE3 movdqu 0x40(STATEP), STATE4 - mov SRC, %r8 - and $0xF, %r8 - jnz .Lad_u_loop - -.align 8 -.Lad_a_loop: - movdqa 0x00(SRC), MSG - aegis128_update - pxor MSG, STATE4 - sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_1 - - movdqa 0x10(SRC), MSG - aegis128_update - pxor MSG, STATE3 - sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_2 - - movdqa 0x20(SRC), MSG - aegis128_update - pxor MSG, STATE2 - sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_3 - - movdqa 0x30(SRC), MSG - aegis128_update - pxor MSG, STATE1 - sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_4 - - movdqa 0x40(SRC), MSG - aegis128_update - pxor MSG, STATE0 - sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_0 - - add $0x50, SRC - jmp .Lad_a_loop - .align 8 -.Lad_u_loop: +.Lad_loop: movdqu 0x00(SRC), MSG aegis128_update pxor MSG, STATE4 sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_1 + jz .Lad_out_1 movdqu 0x10(SRC), MSG aegis128_update pxor MSG, STATE3 sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_2 + jz .Lad_out_2 movdqu 0x20(SRC), MSG aegis128_update pxor MSG, STATE2 sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_3 + jz .Lad_out_3 movdqu 0x30(SRC), MSG aegis128_update pxor MSG, STATE1 sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_4 + jz .Lad_out_4 movdqu 0x40(SRC), MSG aegis128_update pxor MSG, STATE0 sub $0x10, LEN - cmp $0x10, LEN - jl .Lad_out_0 + jz .Lad_out_0 add $0x50, SRC - jmp .Lad_u_loop + jmp .Lad_loop /* store the state: */ .Lad_out_0: @@ -337,7 +246,6 @@ SYM_FUNC_START(crypto_aegis128_aesni_ad) movdqu STATE2, 0x20(STATEP) movdqu STATE3, 0x30(STATEP) movdqu STATE4, 0x40(STATEP) - FRAME_END RET .Lad_out_1: @@ -346,7 +254,6 @@ SYM_FUNC_START(crypto_aegis128_aesni_ad) movdqu STATE1, 0x20(STATEP) movdqu STATE2, 0x30(STATEP) movdqu STATE3, 0x40(STATEP) - FRAME_END RET .Lad_out_2: @@ -355,7 +262,6 @@ SYM_FUNC_START(crypto_aegis128_aesni_ad) movdqu STATE0, 0x20(STATEP) movdqu STATE1, 0x30(STATEP) movdqu STATE2, 0x40(STATEP) - FRAME_END RET .Lad_out_3: @@ -364,7 +270,6 @@ SYM_FUNC_START(crypto_aegis128_aesni_ad) movdqu STATE4, 0x20(STATEP) movdqu STATE0, 0x30(STATEP) movdqu STATE1, 0x40(STATEP) - FRAME_END RET .Lad_out_4: @@ -373,41 +278,38 @@ SYM_FUNC_START(crypto_aegis128_aesni_ad) movdqu STATE3, 0x20(STATEP) movdqu STATE4, 0x30(STATEP) movdqu STATE0, 0x40(STATEP) - FRAME_END - RET - .Lad_out: - FRAME_END RET -SYM_FUNC_END(crypto_aegis128_aesni_ad) +SYM_FUNC_END(aegis128_aesni_ad) -.macro encrypt_block a s0 s1 s2 s3 s4 i - movdq\a (\i * 0x10)(SRC), MSG +.macro encrypt_block s0 s1 s2 s3 s4 i + movdqu (\i * 0x10)(SRC), MSG movdqa MSG, T0 pxor \s1, T0 pxor \s4, T0 movdqa \s2, T1 pand \s3, T1 pxor T1, T0 - movdq\a T0, (\i * 0x10)(DST) + movdqu T0, (\i * 0x10)(DST) aegis128_update pxor MSG, \s4 sub $0x10, LEN - cmp $0x10, LEN - jl .Lenc_out_\i + jz .Lenc_out_\i .endm /* - * void crypto_aegis128_aesni_enc(void *state, unsigned int length, - * const void *src, void *dst); + * void aegis128_aesni_enc(struct aegis_state *state, const u8 *src, u8 *dst, + * unsigned int len); + * + * len must be nonzero and a multiple of 16. */ -SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc) - FRAME_BEGIN - - cmp $0x10, LEN - jb .Lenc_out +SYM_FUNC_START(aegis128_aesni_enc) + .set STATEP, %rdi + .set SRC, %rsi + .set DST, %rdx + .set LEN, %ecx /* load the state: */ movdqu 0x00(STATEP), STATE0 @@ -416,34 +318,17 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc) movdqu 0x30(STATEP), STATE3 movdqu 0x40(STATEP), STATE4 - mov SRC, %r8 - or DST, %r8 - and $0xF, %r8 - jnz .Lenc_u_loop - .align 8 -.Lenc_a_loop: - encrypt_block a STATE0 STATE1 STATE2 STATE3 STATE4 0 - encrypt_block a STATE4 STATE0 STATE1 STATE2 STATE3 1 - encrypt_block a STATE3 STATE4 STATE0 STATE1 STATE2 2 - encrypt_block a STATE2 STATE3 STATE4 STATE0 STATE1 3 - encrypt_block a STATE1 STATE2 STATE3 STATE4 STATE0 4 +.Lenc_loop: + encrypt_block STATE0 STATE1 STATE2 STATE3 STATE4 0 + encrypt_block STATE4 STATE0 STATE1 STATE2 STATE3 1 + encrypt_block STATE3 STATE4 STATE0 STATE1 STATE2 2 + encrypt_block STATE2 STATE3 STATE4 STATE0 STATE1 3 + encrypt_block STATE1 STATE2 STATE3 STATE4 STATE0 4 add $0x50, SRC add $0x50, DST - jmp .Lenc_a_loop - -.align 8 -.Lenc_u_loop: - encrypt_block u STATE0 STATE1 STATE2 STATE3 STATE4 0 - encrypt_block u STATE4 STATE0 STATE1 STATE2 STATE3 1 - encrypt_block u STATE3 STATE4 STATE0 STATE1 STATE2 2 - encrypt_block u STATE2 STATE3 STATE4 STATE0 STATE1 3 - encrypt_block u STATE1 STATE2 STATE3 STATE4 STATE0 4 - - add $0x50, SRC - add $0x50, DST - jmp .Lenc_u_loop + jmp .Lenc_loop /* store the state: */ .Lenc_out_0: @@ -452,7 +337,6 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc) movdqu STATE1, 0x20(STATEP) movdqu STATE2, 0x30(STATEP) movdqu STATE3, 0x40(STATEP) - FRAME_END RET .Lenc_out_1: @@ -461,7 +345,6 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc) movdqu STATE0, 0x20(STATEP) movdqu STATE1, 0x30(STATEP) movdqu STATE2, 0x40(STATEP) - FRAME_END RET .Lenc_out_2: @@ -470,7 +353,6 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc) movdqu STATE4, 0x20(STATEP) movdqu STATE0, 0x30(STATEP) movdqu STATE1, 0x40(STATEP) - FRAME_END RET .Lenc_out_3: @@ -479,7 +361,6 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc) movdqu STATE3, 0x20(STATEP) movdqu STATE4, 0x30(STATEP) movdqu STATE0, 0x40(STATEP) - FRAME_END RET .Lenc_out_4: @@ -488,20 +369,19 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc) movdqu STATE2, 0x20(STATEP) movdqu STATE3, 0x30(STATEP) movdqu STATE4, 0x40(STATEP) - FRAME_END - RET - .Lenc_out: - FRAME_END RET -SYM_FUNC_END(crypto_aegis128_aesni_enc) +SYM_FUNC_END(aegis128_aesni_enc) /* - * void crypto_aegis128_aesni_enc_tail(void *state, unsigned int length, - * const void *src, void *dst); + * void aegis128_aesni_enc_tail(struct aegis_state *state, const u8 *src, + * u8 *dst, unsigned int len); */ -SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc_tail) - FRAME_BEGIN +SYM_FUNC_START(aegis128_aesni_enc_tail) + .set STATEP, %rdi + .set SRC, %rsi + .set DST, %rdx + .set LEN, %ecx /* {load,store}_partial rely on this being %ecx */ /* load the state: */ movdqu 0x00(STATEP), STATE0 @@ -511,7 +391,8 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc_tail) movdqu 0x40(STATEP), STATE4 /* encrypt message: */ - call __load_partial + mov LEN, %r9d + load_partial movdqa MSG, T0 pxor STATE1, T0 @@ -520,7 +401,8 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc_tail) pand STATE3, T1 pxor T1, T0 - call __store_partial + mov %r9d, LEN + store_partial T0 aegis128_update pxor MSG, STATE4 @@ -531,37 +413,36 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_enc_tail) movdqu STATE1, 0x20(STATEP) movdqu STATE2, 0x30(STATEP) movdqu STATE3, 0x40(STATEP) - - FRAME_END RET -SYM_FUNC_END(crypto_aegis128_aesni_enc_tail) +SYM_FUNC_END(aegis128_aesni_enc_tail) -.macro decrypt_block a s0 s1 s2 s3 s4 i - movdq\a (\i * 0x10)(SRC), MSG +.macro decrypt_block s0 s1 s2 s3 s4 i + movdqu (\i * 0x10)(SRC), MSG pxor \s1, MSG pxor \s4, MSG movdqa \s2, T1 pand \s3, T1 pxor T1, MSG - movdq\a MSG, (\i * 0x10)(DST) + movdqu MSG, (\i * 0x10)(DST) aegis128_update pxor MSG, \s4 sub $0x10, LEN - cmp $0x10, LEN - jl .Ldec_out_\i + jz .Ldec_out_\i .endm /* - * void crypto_aegis128_aesni_dec(void *state, unsigned int length, - * const void *src, void *dst); + * void aegis128_aesni_dec(struct aegis_state *state, const u8 *src, u8 *dst, + * unsigned int len); + * + * len must be nonzero and a multiple of 16. */ -SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec) - FRAME_BEGIN - - cmp $0x10, LEN - jb .Ldec_out +SYM_FUNC_START(aegis128_aesni_dec) + .set STATEP, %rdi + .set SRC, %rsi + .set DST, %rdx + .set LEN, %ecx /* load the state: */ movdqu 0x00(STATEP), STATE0 @@ -570,34 +451,17 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec) movdqu 0x30(STATEP), STATE3 movdqu 0x40(STATEP), STATE4 - mov SRC, %r8 - or DST, %r8 - and $0xF, %r8 - jnz .Ldec_u_loop - .align 8 -.Ldec_a_loop: - decrypt_block a STATE0 STATE1 STATE2 STATE3 STATE4 0 - decrypt_block a STATE4 STATE0 STATE1 STATE2 STATE3 1 - decrypt_block a STATE3 STATE4 STATE0 STATE1 STATE2 2 - decrypt_block a STATE2 STATE3 STATE4 STATE0 STATE1 3 - decrypt_block a STATE1 STATE2 STATE3 STATE4 STATE0 4 +.Ldec_loop: + decrypt_block STATE0 STATE1 STATE2 STATE3 STATE4 0 + decrypt_block STATE4 STATE0 STATE1 STATE2 STATE3 1 + decrypt_block STATE3 STATE4 STATE0 STATE1 STATE2 2 + decrypt_block STATE2 STATE3 STATE4 STATE0 STATE1 3 + decrypt_block STATE1 STATE2 STATE3 STATE4 STATE0 4 add $0x50, SRC add $0x50, DST - jmp .Ldec_a_loop - -.align 8 -.Ldec_u_loop: - decrypt_block u STATE0 STATE1 STATE2 STATE3 STATE4 0 - decrypt_block u STATE4 STATE0 STATE1 STATE2 STATE3 1 - decrypt_block u STATE3 STATE4 STATE0 STATE1 STATE2 2 - decrypt_block u STATE2 STATE3 STATE4 STATE0 STATE1 3 - decrypt_block u STATE1 STATE2 STATE3 STATE4 STATE0 4 - - add $0x50, SRC - add $0x50, DST - jmp .Ldec_u_loop + jmp .Ldec_loop /* store the state: */ .Ldec_out_0: @@ -606,7 +470,6 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec) movdqu STATE1, 0x20(STATEP) movdqu STATE2, 0x30(STATEP) movdqu STATE3, 0x40(STATEP) - FRAME_END RET .Ldec_out_1: @@ -615,7 +478,6 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec) movdqu STATE0, 0x20(STATEP) movdqu STATE1, 0x30(STATEP) movdqu STATE2, 0x40(STATEP) - FRAME_END RET .Ldec_out_2: @@ -624,7 +486,6 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec) movdqu STATE4, 0x20(STATEP) movdqu STATE0, 0x30(STATEP) movdqu STATE1, 0x40(STATEP) - FRAME_END RET .Ldec_out_3: @@ -633,7 +494,6 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec) movdqu STATE3, 0x20(STATEP) movdqu STATE4, 0x30(STATEP) movdqu STATE0, 0x40(STATEP) - FRAME_END RET .Ldec_out_4: @@ -642,20 +502,19 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec) movdqu STATE2, 0x20(STATEP) movdqu STATE3, 0x30(STATEP) movdqu STATE4, 0x40(STATEP) - FRAME_END - RET - .Ldec_out: - FRAME_END RET -SYM_FUNC_END(crypto_aegis128_aesni_dec) +SYM_FUNC_END(aegis128_aesni_dec) /* - * void crypto_aegis128_aesni_dec_tail(void *state, unsigned int length, - * const void *src, void *dst); + * void aegis128_aesni_dec_tail(struct aegis_state *state, const u8 *src, + * u8 *dst, unsigned int len); */ -SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec_tail) - FRAME_BEGIN +SYM_FUNC_START(aegis128_aesni_dec_tail) + .set STATEP, %rdi + .set SRC, %rsi + .set DST, %rdx + .set LEN, %ecx /* {load,store}_partial rely on this being %ecx */ /* load the state: */ movdqu 0x00(STATEP), STATE0 @@ -665,7 +524,8 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec_tail) movdqu 0x40(STATEP), STATE4 /* decrypt message: */ - call __load_partial + mov LEN, %r9d + load_partial pxor STATE1, MSG pxor STATE4, MSG @@ -673,17 +533,13 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec_tail) pand STATE3, T1 pxor T1, MSG - movdqa MSG, T0 - call __store_partial + mov %r9d, LEN + store_partial MSG /* mask with byte count: */ - movq LEN, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - punpcklbw T0, T0 - movdqa .Laegis128_counter(%rip), T1 - pcmpgtb T1, T0 + lea .Lzeropad_mask+16(%rip), %rax + sub %r9, %rax + movdqu (%rax), T0 pand T0, MSG aegis128_update @@ -695,17 +551,19 @@ SYM_TYPED_FUNC_START(crypto_aegis128_aesni_dec_tail) movdqu STATE1, 0x20(STATEP) movdqu STATE2, 0x30(STATEP) movdqu STATE3, 0x40(STATEP) - - FRAME_END RET -SYM_FUNC_END(crypto_aegis128_aesni_dec_tail) +SYM_FUNC_END(aegis128_aesni_dec_tail) /* - * void crypto_aegis128_aesni_final(void *state, void *tag_xor, - * u64 assoclen, u64 cryptlen); + * void aegis128_aesni_final(struct aegis_state *state, + * struct aegis_block *tag_xor, + * unsigned int assoclen, unsigned int cryptlen); */ -SYM_FUNC_START(crypto_aegis128_aesni_final) - FRAME_BEGIN +SYM_FUNC_START(aegis128_aesni_final) + .set STATEP, %rdi + .set TAG_XOR, %rsi + .set ASSOCLEN, %edx + .set CRYPTLEN, %ecx /* load the state: */ movdqu 0x00(STATEP), STATE0 @@ -715,10 +573,8 @@ SYM_FUNC_START(crypto_aegis128_aesni_final) movdqu 0x40(STATEP), STATE4 /* prepare length block: */ - movq %rdx, MSG - movq %rcx, T0 - pslldq $8, T0 - pxor T0, MSG + movd ASSOCLEN, MSG + pinsrd $2, CRYPTLEN, MSG psllq $3, MSG /* multiply by 8 (to get bit count) */ pxor STATE3, MSG @@ -733,7 +589,7 @@ SYM_FUNC_START(crypto_aegis128_aesni_final) aegis128_update; pxor MSG, STATE3 /* xor tag: */ - movdqu (%rsi), MSG + movdqu (TAG_XOR), MSG pxor STATE0, MSG pxor STATE1, MSG @@ -741,8 +597,6 @@ SYM_FUNC_START(crypto_aegis128_aesni_final) pxor STATE3, MSG pxor STATE4, MSG - movdqu MSG, (%rsi) - - FRAME_END + movdqu MSG, (TAG_XOR) RET -SYM_FUNC_END(crypto_aegis128_aesni_final) +SYM_FUNC_END(aegis128_aesni_final) diff --git a/arch/x86/crypto/aegis128-aesni-glue.c b/arch/x86/crypto/aegis128-aesni-glue.c index 4623189000d894..c19d8e3d96a35d 100644 --- a/arch/x86/crypto/aegis128-aesni-glue.c +++ b/arch/x86/crypto/aegis128-aesni-glue.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * The AEGIS-128 Authenticated-Encryption Algorithm - * Glue for AES-NI + SSE2 implementation + * Glue for AES-NI + SSE4.1 implementation * * Copyright (c) 2017-2018 Ondrej Mosnacek * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. @@ -23,27 +23,6 @@ #define AEGIS128_MIN_AUTH_SIZE 8 #define AEGIS128_MAX_AUTH_SIZE 16 -asmlinkage void crypto_aegis128_aesni_init(void *state, void *key, void *iv); - -asmlinkage void crypto_aegis128_aesni_ad( - void *state, unsigned int length, const void *data); - -asmlinkage void crypto_aegis128_aesni_enc( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis128_aesni_dec( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis128_aesni_enc_tail( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis128_aesni_dec_tail( - void *state, unsigned int length, const void *src, void *dst); - -asmlinkage void crypto_aegis128_aesni_final( - void *state, void *tag_xor, unsigned int cryptlen, - unsigned int assoclen); - struct aegis_block { u8 bytes[AEGIS128_BLOCK_SIZE] __aligned(AEGIS128_BLOCK_ALIGN); }; @@ -56,15 +35,31 @@ struct aegis_ctx { struct aegis_block key; }; -struct aegis_crypt_ops { - int (*skcipher_walk_init)(struct skcipher_walk *walk, - struct aead_request *req, bool atomic); +asmlinkage void aegis128_aesni_init(struct aegis_state *state, + const struct aegis_block *key, + const u8 iv[AEGIS128_NONCE_SIZE]); - void (*crypt_blocks)(void *state, unsigned int length, const void *src, - void *dst); - void (*crypt_tail)(void *state, unsigned int length, const void *src, - void *dst); -}; +asmlinkage void aegis128_aesni_ad(struct aegis_state *state, const u8 *data, + unsigned int len); + +asmlinkage void aegis128_aesni_enc(struct aegis_state *state, const u8 *src, + u8 *dst, unsigned int len); + +asmlinkage void aegis128_aesni_dec(struct aegis_state *state, const u8 *src, + u8 *dst, unsigned int len); + +asmlinkage void aegis128_aesni_enc_tail(struct aegis_state *state, + const u8 *src, u8 *dst, + unsigned int len); + +asmlinkage void aegis128_aesni_dec_tail(struct aegis_state *state, + const u8 *src, u8 *dst, + unsigned int len); + +asmlinkage void aegis128_aesni_final(struct aegis_state *state, + struct aegis_block *tag_xor, + unsigned int assoclen, + unsigned int cryptlen); static void crypto_aegis128_aesni_process_ad( struct aegis_state *state, struct scatterlist *sg_src, @@ -85,16 +80,15 @@ static void crypto_aegis128_aesni_process_ad( if (pos > 0) { unsigned int fill = AEGIS128_BLOCK_SIZE - pos; memcpy(buf.bytes + pos, src, fill); - crypto_aegis128_aesni_ad(state, - AEGIS128_BLOCK_SIZE, - buf.bytes); + aegis128_aesni_ad(state, buf.bytes, + AEGIS128_BLOCK_SIZE); pos = 0; left -= fill; src += fill; } - crypto_aegis128_aesni_ad(state, left, src); - + aegis128_aesni_ad(state, src, + left & ~(AEGIS128_BLOCK_SIZE - 1)); src += left & ~(AEGIS128_BLOCK_SIZE - 1); left &= AEGIS128_BLOCK_SIZE - 1; } @@ -110,24 +104,37 @@ static void crypto_aegis128_aesni_process_ad( if (pos > 0) { memset(buf.bytes + pos, 0, AEGIS128_BLOCK_SIZE - pos); - crypto_aegis128_aesni_ad(state, AEGIS128_BLOCK_SIZE, buf.bytes); + aegis128_aesni_ad(state, buf.bytes, AEGIS128_BLOCK_SIZE); } } -static void crypto_aegis128_aesni_process_crypt( - struct aegis_state *state, struct skcipher_walk *walk, - const struct aegis_crypt_ops *ops) +static __always_inline void +crypto_aegis128_aesni_process_crypt(struct aegis_state *state, + struct skcipher_walk *walk, bool enc) { while (walk->nbytes >= AEGIS128_BLOCK_SIZE) { - ops->crypt_blocks(state, - round_down(walk->nbytes, AEGIS128_BLOCK_SIZE), - walk->src.virt.addr, walk->dst.virt.addr); + if (enc) + aegis128_aesni_enc(state, walk->src.virt.addr, + walk->dst.virt.addr, + round_down(walk->nbytes, + AEGIS128_BLOCK_SIZE)); + else + aegis128_aesni_dec(state, walk->src.virt.addr, + walk->dst.virt.addr, + round_down(walk->nbytes, + AEGIS128_BLOCK_SIZE)); skcipher_walk_done(walk, walk->nbytes % AEGIS128_BLOCK_SIZE); } if (walk->nbytes) { - ops->crypt_tail(state, walk->nbytes, walk->src.virt.addr, - walk->dst.virt.addr); + if (enc) + aegis128_aesni_enc_tail(state, walk->src.virt.addr, + walk->dst.virt.addr, + walk->nbytes); + else + aegis128_aesni_dec_tail(state, walk->src.virt.addr, + walk->dst.virt.addr, + walk->nbytes); skcipher_walk_done(walk, 0); } } @@ -162,42 +169,39 @@ static int crypto_aegis128_aesni_setauthsize(struct crypto_aead *tfm, return 0; } -static void crypto_aegis128_aesni_crypt(struct aead_request *req, - struct aegis_block *tag_xor, - unsigned int cryptlen, - const struct aegis_crypt_ops *ops) +static __always_inline void +crypto_aegis128_aesni_crypt(struct aead_request *req, + struct aegis_block *tag_xor, + unsigned int cryptlen, bool enc) { struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct aegis_ctx *ctx = crypto_aegis128_aesni_ctx(tfm); struct skcipher_walk walk; struct aegis_state state; - ops->skcipher_walk_init(&walk, req, true); + if (enc) + skcipher_walk_aead_encrypt(&walk, req, true); + else + skcipher_walk_aead_decrypt(&walk, req, true); kernel_fpu_begin(); - crypto_aegis128_aesni_init(&state, ctx->key.bytes, req->iv); + aegis128_aesni_init(&state, &ctx->key, req->iv); crypto_aegis128_aesni_process_ad(&state, req->src, req->assoclen); - crypto_aegis128_aesni_process_crypt(&state, &walk, ops); - crypto_aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen); + crypto_aegis128_aesni_process_crypt(&state, &walk, enc); + aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen); kernel_fpu_end(); } static int crypto_aegis128_aesni_encrypt(struct aead_request *req) { - static const struct aegis_crypt_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_encrypt, - .crypt_blocks = crypto_aegis128_aesni_enc, - .crypt_tail = crypto_aegis128_aesni_enc_tail, - }; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct aegis_block tag = {}; unsigned int authsize = crypto_aead_authsize(tfm); unsigned int cryptlen = req->cryptlen; - crypto_aegis128_aesni_crypt(req, &tag, cryptlen, &OPS); + crypto_aegis128_aesni_crypt(req, &tag, cryptlen, true); scatterwalk_map_and_copy(tag.bytes, req->dst, req->assoclen + cryptlen, authsize, 1); @@ -208,12 +212,6 @@ static int crypto_aegis128_aesni_decrypt(struct aead_request *req) { static const struct aegis_block zeros = {}; - static const struct aegis_crypt_ops OPS = { - .skcipher_walk_init = skcipher_walk_aead_decrypt, - .crypt_blocks = crypto_aegis128_aesni_dec, - .crypt_tail = crypto_aegis128_aesni_dec_tail, - }; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); struct aegis_block tag; unsigned int authsize = crypto_aead_authsize(tfm); @@ -222,27 +220,16 @@ static int crypto_aegis128_aesni_decrypt(struct aead_request *req) scatterwalk_map_and_copy(tag.bytes, req->src, req->assoclen + cryptlen, authsize, 0); - crypto_aegis128_aesni_crypt(req, &tag, cryptlen, &OPS); + crypto_aegis128_aesni_crypt(req, &tag, cryptlen, false); return crypto_memneq(tag.bytes, zeros.bytes, authsize) ? -EBADMSG : 0; } -static int crypto_aegis128_aesni_init_tfm(struct crypto_aead *aead) -{ - return 0; -} - -static void crypto_aegis128_aesni_exit_tfm(struct crypto_aead *aead) -{ -} - static struct aead_alg crypto_aegis128_aesni_alg = { .setkey = crypto_aegis128_aesni_setkey, .setauthsize = crypto_aegis128_aesni_setauthsize, .encrypt = crypto_aegis128_aesni_encrypt, .decrypt = crypto_aegis128_aesni_decrypt, - .init = crypto_aegis128_aesni_init_tfm, - .exit = crypto_aegis128_aesni_exit_tfm, .ivsize = AEGIS128_NONCE_SIZE, .maxauthsize = AEGIS128_MAX_AUTH_SIZE, @@ -267,7 +254,7 @@ static struct simd_aead_alg *simd_alg; static int __init crypto_aegis128_aesni_module_init(void) { - if (!boot_cpu_has(X86_FEATURE_XMM2) || + if (!boot_cpu_has(X86_FEATURE_XMM4_1) || !boot_cpu_has(X86_FEATURE_AES) || !cpu_has_xfeatures(XFEATURE_MASK_SSE, NULL)) return -ENODEV; @@ -286,6 +273,6 @@ module_exit(crypto_aegis128_aesni_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ondrej Mosnacek "); -MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm -- AESNI+SSE2 implementation"); +MODULE_DESCRIPTION("AEGIS-128 AEAD algorithm -- AESNI+SSE4.1 implementation"); MODULE_ALIAS_CRYPTO("aegis128"); MODULE_ALIAS_CRYPTO("aegis128-aesni"); diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index b0dd8355549979..fbf43482e1f5ec 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -1747,7 +1747,7 @@ static void __exit aesni_exit(void) unregister_avx_algs(); } -late_initcall(aesni_init); +module_init(aesni_init); module_exit(aesni_exit); MODULE_DESCRIPTION("AES cipher and modes, optimized with AES-NI or VAES instructions"); diff --git a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S index b4e460a87f18dd..fb95a614249d0c 100644 --- a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S +++ b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S @@ -487,79 +487,3 @@ SYM_FUNC_START(cast5_cbc_dec_16way) FRAME_END RET; SYM_FUNC_END(cast5_cbc_dec_16way) - -SYM_FUNC_START(cast5_ctr_16way) - /* input: - * %rdi: ctx - * %rsi: dst - * %rdx: src - * %rcx: iv (big endian, 64bit) - */ - FRAME_BEGIN - pushq %r12; - pushq %r15; - - movq %rdi, CTX; - movq %rsi, %r11; - movq %rdx, %r12; - - vpcmpeqd RTMP, RTMP, RTMP; - vpsrldq $8, RTMP, RTMP; /* low: -1, high: 0 */ - - vpcmpeqd RKR, RKR, RKR; - vpaddq RKR, RKR, RKR; /* low: -2, high: -2 */ - vmovdqa .Lbswap_iv_mask(%rip), R1ST; - vmovdqa .Lbswap128_mask(%rip), RKM; - - /* load IV and byteswap */ - vmovq (%rcx), RX; - vpshufb R1ST, RX, RX; - - /* construct IVs */ - vpsubq RTMP, RX, RX; /* le: IV1, IV0 */ - vpshufb RKM, RX, RL1; /* be: IV0, IV1 */ - vpsubq RKR, RX, RX; - vpshufb RKM, RX, RR1; /* be: IV2, IV3 */ - vpsubq RKR, RX, RX; - vpshufb RKM, RX, RL2; /* be: IV4, IV5 */ - vpsubq RKR, RX, RX; - vpshufb RKM, RX, RR2; /* be: IV6, IV7 */ - vpsubq RKR, RX, RX; - vpshufb RKM, RX, RL3; /* be: IV8, IV9 */ - vpsubq RKR, RX, RX; - vpshufb RKM, RX, RR3; /* be: IV10, IV11 */ - vpsubq RKR, RX, RX; - vpshufb RKM, RX, RL4; /* be: IV12, IV13 */ - vpsubq RKR, RX, RX; - vpshufb RKM, RX, RR4; /* be: IV14, IV15 */ - - /* store last IV */ - vpsubq RTMP, RX, RX; /* le: IV16, IV14 */ - vpshufb R1ST, RX, RX; /* be: IV16, IV16 */ - vmovq RX, (%rcx); - - call __cast5_enc_blk16; - - /* dst = src ^ iv */ - vpxor (0*16)(%r12), RR1, RR1; - vpxor (1*16)(%r12), RL1, RL1; - vpxor (2*16)(%r12), RR2, RR2; - vpxor (3*16)(%r12), RL2, RL2; - vpxor (4*16)(%r12), RR3, RR3; - vpxor (5*16)(%r12), RL3, RL3; - vpxor (6*16)(%r12), RR4, RR4; - vpxor (7*16)(%r12), RL4, RL4; - vmovdqu RR1, (0*16)(%r11); - vmovdqu RL1, (1*16)(%r11); - vmovdqu RR2, (2*16)(%r11); - vmovdqu RL2, (3*16)(%r11); - vmovdqu RR3, (4*16)(%r11); - vmovdqu RL3, (5*16)(%r11); - vmovdqu RR4, (6*16)(%r11); - vmovdqu RL4, (7*16)(%r11); - - popq %r15; - popq %r12; - FRAME_END - RET; -SYM_FUNC_END(cast5_ctr_16way) diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c index feccb5254c7e5e..52c5d47ef5a14e 100644 --- a/arch/x86/crypto/crc32c-intel_glue.c +++ b/arch/x86/crypto/crc32c-intel_glue.c @@ -41,7 +41,7 @@ */ #define CRC32C_PCL_BREAKEVEN 512 -asmlinkage unsigned int crc_pcl(const u8 *buffer, int len, +asmlinkage unsigned int crc_pcl(const u8 *buffer, unsigned int len, unsigned int crc_init); #endif /* CONFIG_X86_64 */ diff --git a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S index bbcff1fb78cb2b..752812bc4991df 100644 --- a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S +++ b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S @@ -7,6 +7,7 @@ * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-paper.pdf * * Copyright (C) 2012 Intel Corporation. + * Copyright 2024 Google LLC * * Authors: * Wajdi Feghali @@ -44,185 +45,129 @@ */ #include -#include ## ISCSI CRC 32 Implementation with crc32 and pclmulqdq Instruction -.macro LABEL prefix n -.L\prefix\n\(): -.endm - -.macro JMPTBL_ENTRY i -.quad .Lcrc_\i -.endm - -.macro JNC_LESS_THAN j - jnc .Lless_than_\j -.endm - -# Define threshold where buffers are considered "small" and routed to more -# efficient "by-1" code. This "by-1" code only handles up to 255 bytes, so -# SMALL_SIZE can be no larger than 255. - +# Define threshold below which buffers are considered "small" and routed to +# regular CRC code that does not interleave the CRC instructions. #define SMALL_SIZE 200 -.if (SMALL_SIZE > 255) -.error "SMALL_ SIZE must be < 256" -.endif - -# unsigned int crc_pcl(u8 *buffer, int len, unsigned int crc_init); +# unsigned int crc_pcl(const u8 *buffer, unsigned int len, unsigned int crc_init); .text SYM_FUNC_START(crc_pcl) -#define bufp rdi -#define bufp_dw %edi -#define bufp_w %di -#define bufp_b %dil -#define bufptmp %rcx -#define block_0 %rcx -#define block_1 %rdx -#define block_2 %r11 -#define len %rsi -#define len_dw %esi -#define len_w %si -#define len_b %sil -#define crc_init_arg %rdx -#define tmp %rbx -#define crc_init %r8 -#define crc_init_dw %r8d -#define crc1 %r9 -#define crc2 %r10 - - pushq %rbx - pushq %rdi - pushq %rsi - - ## Move crc_init for Linux to a different - mov crc_init_arg, crc_init +#define bufp %rdi +#define bufp_d %edi +#define len %esi +#define crc_init %edx +#define crc_init_q %rdx +#define n_misaligned %ecx /* overlaps chunk_bytes! */ +#define n_misaligned_q %rcx +#define chunk_bytes %ecx /* overlaps n_misaligned! */ +#define chunk_bytes_q %rcx +#define crc1 %r8 +#define crc2 %r9 + + cmp $SMALL_SIZE, len + jb .Lsmall ################################################################ ## 1) ALIGN: ################################################################ - - mov %bufp, bufptmp # rdi = *buf - neg %bufp - and $7, %bufp # calculate the unalignment amount of + mov bufp_d, n_misaligned + neg n_misaligned + and $7, n_misaligned # calculate the misalignment amount of # the address - je .Lproc_block # Skip if aligned - - ## If len is less than 8 and we're unaligned, we need to jump - ## to special code to avoid reading beyond the end of the buffer - cmp $8, len - jae .Ldo_align - # less_than_8 expects length in upper 3 bits of len_dw - # less_than_8_post_shl1 expects length = carryflag * 8 + len_dw[31:30] - shl $32-3+1, len_dw - jmp .Lless_than_8_post_shl1 + je .Laligned # Skip if aligned + # Process 1 <= n_misaligned <= 7 bytes individually in order to align + # the remaining data to an 8-byte boundary. .Ldo_align: - #### Calculate CRC of unaligned bytes of the buffer (if any) - movq (bufptmp), tmp # load a quadward from the buffer - add %bufp, bufptmp # align buffer pointer for quadword - # processing - sub %bufp, len # update buffer length + movq (bufp), %rax + add n_misaligned_q, bufp + sub n_misaligned, len .Lalign_loop: - crc32b %bl, crc_init_dw # compute crc32 of 1-byte - shr $8, tmp # get next byte - dec %bufp + crc32b %al, crc_init # compute crc32 of 1-byte + shr $8, %rax # get next byte + dec n_misaligned jne .Lalign_loop - -.Lproc_block: +.Laligned: ################################################################ - ## 2) PROCESS BLOCKS: + ## 2) PROCESS BLOCK: ################################################################ - ## compute num of bytes to be processed - movq len, tmp # save num bytes in tmp - - cmpq $128*24, len + cmp $128*24, len jae .Lfull_block -.Lcontinue_block: - cmpq $SMALL_SIZE, len - jb .Lsmall - - ## len < 128*24 - movq $2731, %rax # 2731 = ceil(2^16 / 24) - mul len_dw - shrq $16, %rax - - ## eax contains floor(bytes / 24) = num 24-byte chunks to do - - ## process rax 24-byte chunks (128 >= rax >= 0) - - ## compute end address of each block - ## block 0 (base addr + RAX * 8) - ## block 1 (base addr + RAX * 16) - ## block 2 (base addr + RAX * 24) - lea (bufptmp, %rax, 8), block_0 - lea (block_0, %rax, 8), block_1 - lea (block_1, %rax, 8), block_2 +.Lpartial_block: + # Compute floor(len / 24) to get num qwords to process from each lane. + imul $2731, len, %eax # 2731 = ceil(2^16 / 24) + shr $16, %eax + jmp .Lcrc_3lanes - xor crc1, crc1 - xor crc2, crc2 - - ## branch into array - leaq jump_table(%rip), %bufp - mov (%bufp,%rax,8), %bufp - JMP_NOSPEC bufp - - ################################################################ - ## 2a) PROCESS FULL BLOCKS: - ################################################################ .Lfull_block: - movl $128,%eax - lea 128*8*2(block_0), block_1 - lea 128*8*3(block_0), block_2 - add $128*8*1, block_0 - - xor crc1,crc1 - xor crc2,crc2 - - # Fall through into top of crc array (crc_128) + # Processing 128 qwords from each lane. + mov $128, %eax ################################################################ - ## 3) CRC Array: + ## 3) CRC each of three lanes: ################################################################ - i=128 -.rept 128-1 -.altmacro -LABEL crc_ %i -.noaltmacro - ENDBR - crc32q -i*8(block_0), crc_init - crc32q -i*8(block_1), crc1 - crc32q -i*8(block_2), crc2 - i=(i-1) -.endr - -.altmacro -LABEL crc_ %i -.noaltmacro - ENDBR - crc32q -i*8(block_0), crc_init - crc32q -i*8(block_1), crc1 -# SKIP crc32 -i*8(block_2), crc2 ; Don't do this one yet - - mov block_2, block_0 +.Lcrc_3lanes: + xor crc1,crc1 + xor crc2,crc2 + mov %eax, chunk_bytes + shl $3, chunk_bytes # num bytes to process from each lane + sub $5, %eax # 4 for 4x_loop, 1 for special last iter + jl .Lcrc_3lanes_4x_done + + # Unroll the loop by a factor of 4 to reduce the overhead of the loop + # bookkeeping instructions, which can compete with crc32q for the ALUs. +.Lcrc_3lanes_4x_loop: + crc32q (bufp), crc_init_q + crc32q (bufp,chunk_bytes_q), crc1 + crc32q (bufp,chunk_bytes_q,2), crc2 + crc32q 8(bufp), crc_init_q + crc32q 8(bufp,chunk_bytes_q), crc1 + crc32q 8(bufp,chunk_bytes_q,2), crc2 + crc32q 16(bufp), crc_init_q + crc32q 16(bufp,chunk_bytes_q), crc1 + crc32q 16(bufp,chunk_bytes_q,2), crc2 + crc32q 24(bufp), crc_init_q + crc32q 24(bufp,chunk_bytes_q), crc1 + crc32q 24(bufp,chunk_bytes_q,2), crc2 + add $32, bufp + sub $4, %eax + jge .Lcrc_3lanes_4x_loop + +.Lcrc_3lanes_4x_done: + add $4, %eax + jz .Lcrc_3lanes_last_qword + +.Lcrc_3lanes_1x_loop: + crc32q (bufp), crc_init_q + crc32q (bufp,chunk_bytes_q), crc1 + crc32q (bufp,chunk_bytes_q,2), crc2 + add $8, bufp + dec %eax + jnz .Lcrc_3lanes_1x_loop + +.Lcrc_3lanes_last_qword: + crc32q (bufp), crc_init_q + crc32q (bufp,chunk_bytes_q), crc1 +# SKIP crc32q (bufp,chunk_bytes_q,2), crc2 ; Don't do this one yet ################################################################ ## 4) Combine three results: ################################################################ - lea (K_table-8)(%rip), %bufp # first entry is for idx 1 - shlq $3, %rax # rax *= 8 - pmovzxdq (%bufp,%rax), %xmm0 # 2 consts: K1:K2 - leal (%eax,%eax,2), %eax # rax *= 3 (total *24) - subq %rax, tmp # tmp -= rax*24 + lea (K_table-8)(%rip), %rax # first entry is for idx 1 + pmovzxdq (%rax,chunk_bytes_q), %xmm0 # 2 consts: K1:K2 + lea (chunk_bytes,chunk_bytes,2), %eax # chunk_bytes * 3 + sub %eax, len # len -= chunk_bytes * 3 - movq crc_init, %xmm1 # CRC for block 1 + movq crc_init_q, %xmm1 # CRC for block 1 pclmulqdq $0x00, %xmm0, %xmm1 # Multiply by K2 movq crc1, %xmm2 # CRC for block 2 @@ -230,103 +175,54 @@ LABEL crc_ %i pxor %xmm2,%xmm1 movq %xmm1, %rax - xor -i*8(block_2), %rax - mov crc2, crc_init - crc32 %rax, crc_init + xor (bufp,chunk_bytes_q,2), %rax + mov crc2, crc_init_q + crc32 %rax, crc_init_q + lea 8(bufp,chunk_bytes_q,2), bufp ################################################################ - ## 5) Check for end: + ## 5) If more blocks remain, goto (2): ################################################################ -LABEL crc_ 0 - ENDBR - mov tmp, len - cmp $128*24, tmp - jae .Lfull_block - cmp $24, tmp - jae .Lcontinue_block - -.Lless_than_24: - shl $32-4, len_dw # less_than_16 expects length - # in upper 4 bits of len_dw - jnc .Lless_than_16 - crc32q (bufptmp), crc_init - crc32q 8(bufptmp), crc_init - jz .Ldo_return - add $16, bufptmp - # len is less than 8 if we got here - # less_than_8 expects length in upper 3 bits of len_dw - # less_than_8_post_shl1 expects length = carryflag * 8 + len_dw[31:30] - shl $2, len_dw - jmp .Lless_than_8_post_shl1 + cmp $128*24, len + jae .Lfull_block + cmp $SMALL_SIZE, len + jae .Lpartial_block ####################################################################### - ## 6) LESS THAN 256-bytes REMAIN AT THIS POINT (8-bits of len are full) + ## 6) Process any remainder without interleaving: ####################################################################### .Lsmall: - shl $32-8, len_dw # Prepare len_dw for less_than_256 - j=256 -.rept 5 # j = {256, 128, 64, 32, 16} -.altmacro -LABEL less_than_ %j # less_than_j: Length should be in - # upper lg(j) bits of len_dw - j=(j/2) - shl $1, len_dw # Get next MSB - JNC_LESS_THAN %j -.noaltmacro - i=0 -.rept (j/8) - crc32q i(bufptmp), crc_init # Compute crc32 of 8-byte data - i=i+8 -.endr - jz .Ldo_return # Return if remaining length is zero - add $j, bufptmp # Advance buf -.endr - -.Lless_than_8: # Length should be stored in - # upper 3 bits of len_dw - shl $1, len_dw -.Lless_than_8_post_shl1: - jnc .Lless_than_4 - crc32l (bufptmp), crc_init_dw # CRC of 4 bytes - jz .Ldo_return # return if remaining data is zero - add $4, bufptmp -.Lless_than_4: # Length should be stored in - # upper 2 bits of len_dw - shl $1, len_dw - jnc .Lless_than_2 - crc32w (bufptmp), crc_init_dw # CRC of 2 bytes - jz .Ldo_return # return if remaining data is zero - add $2, bufptmp -.Lless_than_2: # Length should be stored in the MSB - # of len_dw - shl $1, len_dw - jnc .Lless_than_1 - crc32b (bufptmp), crc_init_dw # CRC of 1 byte -.Lless_than_1: # Length should be zero -.Ldo_return: - movq crc_init, %rax - popq %rsi - popq %rdi - popq %rbx + test len, len + jz .Ldone + mov len, %eax + shr $3, %eax + jz .Ldo_dword +.Ldo_qwords: + crc32q (bufp), crc_init_q + add $8, bufp + dec %eax + jnz .Ldo_qwords +.Ldo_dword: + test $4, len + jz .Ldo_word + crc32l (bufp), crc_init + add $4, bufp +.Ldo_word: + test $2, len + jz .Ldo_byte + crc32w (bufp), crc_init + add $2, bufp +.Ldo_byte: + test $1, len + jz .Ldone + crc32b (bufp), crc_init +.Ldone: + mov crc_init, %eax RET SYM_FUNC_END(crc_pcl) .section .rodata, "a", @progbits - ################################################################ - ## jump table Table is 129 entries x 2 bytes each - ################################################################ -.align 4 -jump_table: - i=0 -.rept 129 -.altmacro -JMPTBL_ENTRY %i -.noaltmacro - i=i+1 -.endr - - ################################################################ ## PCLMULQDQ tables ## Table is 128 entries x 2 words (8 bytes) each diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 534c74b14fab51..4d0fb2fba7e208 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -468,3 +468,7 @@ 460 i386 lsm_set_self_attr sys_lsm_set_self_attr 461 i386 lsm_list_modules sys_lsm_list_modules 462 i386 mseal sys_mseal +463 i386 setxattrat sys_setxattrat +464 i386 getxattrat sys_getxattrat +465 i386 listxattrat sys_listxattrat +466 i386 removexattrat sys_removexattrat diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 7093ee21c0d1c0..5eb708bff1c791 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -386,6 +386,10 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat # # Due to a historical design error, certain syscalls are numbered differently diff --git a/arch/x86/entry/vdso/vdso-layout.lds.S b/arch/x86/entry/vdso/vdso-layout.lds.S index bafa73f09e9285..872947c1004c35 100644 --- a/arch/x86/entry/vdso/vdso-layout.lds.S +++ b/arch/x86/entry/vdso/vdso-layout.lds.S @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include +#include /* * Linker script for vDSO. This is an ELF shared object prelinked to @@ -16,23 +17,16 @@ SECTIONS * segment. */ - vvar_start = . - 4 * PAGE_SIZE; + vvar_start = . - __VVAR_PAGES * PAGE_SIZE; vvar_page = vvar_start; - /* Place all vvars at the offsets in asm/vvar.h. */ -#define EMIT_VVAR(name, offset) vvar_ ## name = vvar_page + offset; -#include -#undef EMIT_VVAR + vdso_rng_data = vvar_page + __VDSO_RND_DATA_OFFSET; - pvclock_page = vvar_start + PAGE_SIZE; - hvclock_page = vvar_start + 2 * PAGE_SIZE; - timens_page = vvar_start + 3 * PAGE_SIZE; + timens_page = vvar_start + PAGE_SIZE; -#undef _ASM_X86_VVAR_H - /* Place all vvars in timens too at the offsets in asm/vvar.h. */ -#define EMIT_VVAR(name, offset) timens_ ## name = timens_page + offset; -#include -#undef EMIT_VVAR + vclock_pages = vvar_start + VDSO_NR_VCLOCK_PAGES * PAGE_SIZE; + pvclock_page = vclock_pages + VDSO_PAGE_PVCLOCK_OFFSET * PAGE_SIZE; + hvclock_page = vclock_pages + VDSO_PAGE_HVCLOCK_OFFSET * PAGE_SIZE; . = SIZEOF_HEADERS; diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index b8fed8b8b9ccdb..39e6efc1a9cab7 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -20,26 +20,20 @@ #include #include #include -#include #include #include #include #include +#include #include -#undef _ASM_X86_VVAR_H -#define EMIT_VVAR(name, offset) \ - const size_t name ## _offset = offset; -#include - struct vdso_data *arch_get_vdso_data(void *vvar_page) { - return (struct vdso_data *)(vvar_page + _vdso_data_offset); + return (struct vdso_data *)vvar_page; } -#undef EMIT_VVAR -DEFINE_VVAR(struct vdso_data, _vdso_data); -DEFINE_VVAR_SINGLE(struct vdso_rng_data, _vdso_rng_data); +static union vdso_data_store vdso_data_store __page_aligned_data; +struct vdso_data *vdso_data = vdso_data_store.data; unsigned int vclocks_used __read_mostly; @@ -54,7 +48,8 @@ int __init init_vdso_image(const struct vdso_image *image) apply_alternatives((struct alt_instr *)(image->data + image->alt), (struct alt_instr *)(image->data + image->alt + - image->alt_len)); + image->alt_len), + NULL); return 0; } @@ -154,7 +149,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, if (sym_offset == image->sym_vvar_page) { struct page *timens_page = find_timens_vvar_page(vma); - pfn = __pa_symbol(&__vvar_page) >> PAGE_SHIFT; + pfn = __pa_symbol(vdso_data) >> PAGE_SHIFT; /* * If a task belongs to a time namespace then a namespace @@ -182,32 +177,52 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, } return vmf_insert_pfn(vma, vmf->address, pfn); - } else if (sym_offset == image->sym_pvclock_page) { - struct pvclock_vsyscall_time_info *pvti = - pvclock_get_pvti_cpu0_va(); - if (pvti && vclock_was_used(VDSO_CLOCKMODE_PVCLOCK)) { - return vmf_insert_pfn_prot(vma, vmf->address, - __pa(pvti) >> PAGE_SHIFT, - pgprot_decrypted(vma->vm_page_prot)); - } - } else if (sym_offset == image->sym_hvclock_page) { - pfn = hv_get_tsc_pfn(); - if (pfn && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK)) - return vmf_insert_pfn(vma, vmf->address, pfn); } else if (sym_offset == image->sym_timens_page) { struct page *timens_page = find_timens_vvar_page(vma); if (!timens_page) return VM_FAULT_SIGBUS; - pfn = __pa_symbol(&__vvar_page) >> PAGE_SHIFT; + pfn = __pa_symbol(vdso_data) >> PAGE_SHIFT; return vmf_insert_pfn(vma, vmf->address, pfn); } return VM_FAULT_SIGBUS; } +static vm_fault_t vvar_vclock_fault(const struct vm_special_mapping *sm, + struct vm_area_struct *vma, struct vm_fault *vmf) +{ + switch (vmf->pgoff) { +#ifdef CONFIG_PARAVIRT_CLOCK + case VDSO_PAGE_PVCLOCK_OFFSET: + { + struct pvclock_vsyscall_time_info *pvti = + pvclock_get_pvti_cpu0_va(); + + if (pvti && vclock_was_used(VDSO_CLOCKMODE_PVCLOCK)) + return vmf_insert_pfn_prot(vma, vmf->address, + __pa(pvti) >> PAGE_SHIFT, + pgprot_decrypted(vma->vm_page_prot)); + break; + } +#endif /* CONFIG_PARAVIRT_CLOCK */ +#ifdef CONFIG_HYPERV_TIMER + case VDSO_PAGE_HVCLOCK_OFFSET: + { + unsigned long pfn = hv_get_tsc_pfn(); + + if (pfn && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK)) + return vmf_insert_pfn(vma, vmf->address, pfn); + break; + } +#endif /* CONFIG_HYPERV_TIMER */ + } + + return VM_FAULT_SIGBUS; +} + static const struct vm_special_mapping vdso_mapping = { .name = "[vdso]", .fault = vdso_fault, @@ -217,6 +232,10 @@ static const struct vm_special_mapping vvar_mapping = { .name = "[vvar]", .fault = vvar_fault, }; +static const struct vm_special_mapping vvar_vclock_mapping = { + .name = "[vvar_vclock]", + .fault = vvar_vclock_fault, +}; /* * Add vdso and vvar mappings to current process. @@ -259,7 +278,7 @@ static int map_vdso(const struct vdso_image *image, unsigned long addr) vma = _install_special_mapping(mm, addr, - -image->sym_vvar_start, + (__VVAR_PAGES - VDSO_NR_VCLOCK_PAGES) * PAGE_SIZE, VM_READ|VM_MAYREAD|VM_IO|VM_DONTDUMP| VM_PFNMAP, &vvar_mapping); @@ -267,11 +286,26 @@ static int map_vdso(const struct vdso_image *image, unsigned long addr) if (IS_ERR(vma)) { ret = PTR_ERR(vma); do_munmap(mm, text_start, image->size, NULL); - } else { - current->mm->context.vdso = (void __user *)text_start; - current->mm->context.vdso_image = image; + goto up_fail; } + vma = _install_special_mapping(mm, + addr + (__VVAR_PAGES - VDSO_NR_VCLOCK_PAGES) * PAGE_SIZE, + VDSO_NR_VCLOCK_PAGES * PAGE_SIZE, + VM_READ|VM_MAYREAD|VM_IO|VM_DONTDUMP| + VM_PFNMAP, + &vvar_vclock_mapping); + + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + do_munmap(mm, text_start, image->size, NULL); + do_munmap(mm, addr, image->size, NULL); + goto up_fail; + } + + current->mm->context.vdso = (void __user *)text_start; + current->mm->context.vdso_image = image; + up_fail: mmap_write_unlock(mm); return ret; @@ -293,7 +327,8 @@ int map_vdso_once(const struct vdso_image *image, unsigned long addr) */ for_each_vma(vmi, vma) { if (vma_is_special_mapping(vma, &vdso_mapping) || - vma_is_special_mapping(vma, &vvar_mapping)) { + vma_is_special_mapping(vma, &vvar_mapping) || + vma_is_special_mapping(vma, &vvar_vclock_mapping)) { mmap_write_unlock(mm); return -EEXIST; } diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index 920e3a640caddd..b4a1a2576510e0 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -943,11 +943,12 @@ static int amd_pmu_v2_snapshot_branch_stack(struct perf_branch_entry *entries, u static int amd_pmu_v2_handle_irq(struct pt_regs *regs) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + static atomic64_t status_warned = ATOMIC64_INIT(0); + u64 reserved, status, mask, new_bits, prev_bits; struct perf_sample_data data; struct hw_perf_event *hwc; struct perf_event *event; int handled = 0, idx; - u64 reserved, status, mask; bool pmu_enabled; /* @@ -1012,7 +1013,12 @@ static int amd_pmu_v2_handle_irq(struct pt_regs *regs) * the corresponding PMCs are expected to be inactive according to the * active_mask */ - WARN_ON(status > 0); + if (status > 0) { + prev_bits = atomic64_fetch_or(status, &status_warned); + // A new bit was set for the very first time. + new_bits = status & ~prev_bits; + WARN(new_bits, "New overflows for inactive PMCs: %llx\n", new_bits); + } /* Clear overflow and freeze bits */ amd_pmu_ack_global_status(~status); diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c index 0bfde2ea5cb8ce..49c26ce2b11522 100644 --- a/arch/x86/events/amd/uncore.c +++ b/arch/x86/events/amd/uncore.c @@ -916,7 +916,8 @@ int amd_uncore_umc_ctx_init(struct amd_uncore *uncore, unsigned int cpu) u8 group_num_pmcs[UNCORE_GROUP_MAX] = { 0 }; union amd_uncore_info info; struct amd_uncore_pmu *pmu; - int index = 0, gid, i; + int gid, i; + u16 index = 0; if (pmu_version < 2) return 0; @@ -948,7 +949,7 @@ int amd_uncore_umc_ctx_init(struct amd_uncore *uncore, unsigned int cpu) for_each_set_bit(gid, gmask, UNCORE_GROUP_MAX) { for (i = 0; i < group_num_pmus[gid]; i++) { pmu = &uncore->pmus[index]; - snprintf(pmu->name, sizeof(pmu->name), "amd_umc_%d", index); + snprintf(pmu->name, sizeof(pmu->name), "amd_umc_%hu", index); pmu->num_counters = group_num_pmcs[gid] / group_num_pmus[gid]; pmu->msr_base = MSR_F19H_UMC_PERF_CTL + i * pmu->num_counters * 2; pmu->rdpmc_base = -1; diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 65ab6460aed4d7..c75c482d4c52f7 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -3003,35 +3003,57 @@ static unsigned long code_segment_base(struct pt_regs *regs) return 0; } -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { - if (perf_guest_state()) - return perf_guest_get_ip(); - return regs->ip + code_segment_base(regs); } -unsigned long perf_misc_flags(struct pt_regs *regs) +static unsigned long common_misc_flags(struct pt_regs *regs) { - unsigned int guest_state = perf_guest_state(); - int misc = 0; + if (regs->flags & PERF_EFLAGS_EXACT) + return PERF_RECORD_MISC_EXACT_IP; - if (guest_state) { - if (guest_state & PERF_GUEST_USER) - misc |= PERF_RECORD_MISC_GUEST_USER; - else - misc |= PERF_RECORD_MISC_GUEST_KERNEL; - } else { - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - } + return 0; +} - if (regs->flags & PERF_EFLAGS_EXACT) - misc |= PERF_RECORD_MISC_EXACT_IP; +static unsigned long guest_misc_flags(struct pt_regs *regs) +{ + unsigned long guest_state = perf_guest_state(); + + if (!(guest_state & PERF_GUEST_ACTIVE)) + return 0; + + if (guest_state & PERF_GUEST_USER) + return PERF_RECORD_MISC_GUEST_USER; + else + return PERF_RECORD_MISC_GUEST_KERNEL; + +} + +static unsigned long host_misc_flags(struct pt_regs *regs) +{ + if (user_mode(regs)) + return PERF_RECORD_MISC_USER; + else + return PERF_RECORD_MISC_KERNEL; +} + +unsigned long perf_arch_guest_misc_flags(struct pt_regs *regs) +{ + unsigned long flags = common_misc_flags(regs); + + flags |= guest_misc_flags(regs); + + return flags; +} + +unsigned long perf_arch_misc_flags(struct pt_regs *regs) +{ + unsigned long flags = common_misc_flags(regs); + + flags |= host_misc_flags(regs); - return misc; + return flags; } void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index d879478db3f572..2e1e268460500a 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3962,8 +3962,8 @@ static int intel_pmu_hw_config(struct perf_event *event) if (!(event->attr.freq || (event->attr.wakeup_events && !event->attr.watermark))) { event->hw.flags |= PERF_X86_EVENT_AUTO_RELOAD; - if (!(event->attr.sample_type & - ~intel_pmu_large_pebs_flags(event))) { + if (!(event->attr.sample_type & ~intel_pmu_large_pebs_flags(event)) && + !has_aux_action(event)) { event->hw.flags |= PERF_X86_EVENT_LARGE_PEBS; event->attach_state |= PERF_ATTACH_SCHED_CB; } @@ -4599,6 +4599,28 @@ static inline bool erratum_hsw11(struct perf_event *event) X86_CONFIG(.event=0xc0, .umask=0x01); } +static struct event_constraint * +arl_h_get_event_constraints(struct cpu_hw_events *cpuc, int idx, + struct perf_event *event) +{ + struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu); + + if (pmu->pmu_type == hybrid_tiny) + return cmt_get_event_constraints(cpuc, idx, event); + + return mtl_get_event_constraints(cpuc, idx, event); +} + +static int arl_h_hw_config(struct perf_event *event) +{ + struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu); + + if (pmu->pmu_type == hybrid_tiny) + return intel_pmu_hw_config(event); + + return adl_hw_config(event); +} + /* * The HSW11 requires a period larger than 100 which is the same as the BDM11. * A minimum period of 128 is enforced as well for the INST_RETIRED.ALL. @@ -4924,17 +4946,26 @@ static struct x86_hybrid_pmu *find_hybrid_pmu_for_cpu(void) /* * This essentially just maps between the 'hybrid_cpu_type' - * and 'hybrid_pmu_type' enums: + * and 'hybrid_pmu_type' enums except for ARL-H processor + * which needs to compare atom uarch native id since ARL-H + * contains two different atom uarchs. */ for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) { enum hybrid_pmu_type pmu_type = x86_pmu.hybrid_pmu[i].pmu_type; + u32 native_id; - if (cpu_type == HYBRID_INTEL_CORE && - pmu_type == hybrid_big) - return &x86_pmu.hybrid_pmu[i]; - if (cpu_type == HYBRID_INTEL_ATOM && - pmu_type == hybrid_small) + if (cpu_type == HYBRID_INTEL_CORE && pmu_type == hybrid_big) return &x86_pmu.hybrid_pmu[i]; + if (cpu_type == HYBRID_INTEL_ATOM) { + if (x86_pmu.num_hybrid_pmus == 2 && pmu_type == hybrid_small) + return &x86_pmu.hybrid_pmu[i]; + + native_id = get_this_hybrid_cpu_native_id(); + if (native_id == skt_native_id && pmu_type == hybrid_small) + return &x86_pmu.hybrid_pmu[i]; + if (native_id == cmt_native_id && pmu_type == hybrid_tiny) + return &x86_pmu.hybrid_pmu[i]; + } } return NULL; @@ -5965,6 +5996,37 @@ static struct attribute *lnl_hybrid_events_attrs[] = { NULL }; +/* The event string must be in PMU IDX order. */ +EVENT_ATTR_STR_HYBRID(topdown-retiring, + td_retiring_arl_h, + "event=0xc2,umask=0x02;event=0x00,umask=0x80;event=0xc2,umask=0x0", + hybrid_big_small_tiny); +EVENT_ATTR_STR_HYBRID(topdown-bad-spec, + td_bad_spec_arl_h, + "event=0x73,umask=0x0;event=0x00,umask=0x81;event=0x73,umask=0x0", + hybrid_big_small_tiny); +EVENT_ATTR_STR_HYBRID(topdown-fe-bound, + td_fe_bound_arl_h, + "event=0x9c,umask=0x01;event=0x00,umask=0x82;event=0x71,umask=0x0", + hybrid_big_small_tiny); +EVENT_ATTR_STR_HYBRID(topdown-be-bound, + td_be_bound_arl_h, + "event=0xa4,umask=0x02;event=0x00,umask=0x83;event=0x74,umask=0x0", + hybrid_big_small_tiny); + +static struct attribute *arl_h_hybrid_events_attrs[] = { + EVENT_PTR(slots_adl), + EVENT_PTR(td_retiring_arl_h), + EVENT_PTR(td_bad_spec_arl_h), + EVENT_PTR(td_fe_bound_arl_h), + EVENT_PTR(td_be_bound_arl_h), + EVENT_PTR(td_heavy_ops_adl), + EVENT_PTR(td_br_mis_adl), + EVENT_PTR(td_fetch_lat_adl), + EVENT_PTR(td_mem_bound_adl), + NULL, +}; + /* Must be in IDX order */ EVENT_ATTR_STR_HYBRID(mem-loads, mem_ld_adl, "event=0xd0,umask=0x5,ldlat=3;event=0xcd,umask=0x1,ldlat=3", hybrid_big_small); EVENT_ATTR_STR_HYBRID(mem-stores, mem_st_adl, "event=0xd0,umask=0x6;event=0xcd,umask=0x2", hybrid_big_small); @@ -5983,6 +6045,21 @@ static struct attribute *mtl_hybrid_mem_attrs[] = { NULL }; +EVENT_ATTR_STR_HYBRID(mem-loads, + mem_ld_arl_h, + "event=0xd0,umask=0x5,ldlat=3;event=0xcd,umask=0x1,ldlat=3;event=0xd0,umask=0x5,ldlat=3", + hybrid_big_small_tiny); +EVENT_ATTR_STR_HYBRID(mem-stores, + mem_st_arl_h, + "event=0xd0,umask=0x6;event=0xcd,umask=0x2;event=0xd0,umask=0x6", + hybrid_big_small_tiny); + +static struct attribute *arl_h_hybrid_mem_attrs[] = { + EVENT_PTR(mem_ld_arl_h), + EVENT_PTR(mem_st_arl_h), + NULL, +}; + EVENT_ATTR_STR_HYBRID(tx-start, tx_start_adl, "event=0xc9,umask=0x1", hybrid_big); EVENT_ATTR_STR_HYBRID(tx-commit, tx_commit_adl, "event=0xc9,umask=0x2", hybrid_big); EVENT_ATTR_STR_HYBRID(tx-abort, tx_abort_adl, "event=0xc9,umask=0x4", hybrid_big); @@ -6006,8 +6083,8 @@ static struct attribute *adl_hybrid_tsx_attrs[] = { FORMAT_ATTR_HYBRID(in_tx, hybrid_big); FORMAT_ATTR_HYBRID(in_tx_cp, hybrid_big); -FORMAT_ATTR_HYBRID(offcore_rsp, hybrid_big_small); -FORMAT_ATTR_HYBRID(ldlat, hybrid_big_small); +FORMAT_ATTR_HYBRID(offcore_rsp, hybrid_big_small_tiny); +FORMAT_ATTR_HYBRID(ldlat, hybrid_big_small_tiny); FORMAT_ATTR_HYBRID(frontend, hybrid_big); #define ADL_HYBRID_RTM_FORMAT_ATTR \ @@ -6030,7 +6107,7 @@ static struct attribute *adl_hybrid_extra_attr[] = { NULL }; -FORMAT_ATTR_HYBRID(snoop_rsp, hybrid_small); +FORMAT_ATTR_HYBRID(snoop_rsp, hybrid_small_tiny); static struct attribute *mtl_hybrid_extra_attr_rtm[] = { ADL_HYBRID_RTM_FORMAT_ATTR, @@ -6238,8 +6315,9 @@ static inline int intel_pmu_v6_addr_offset(int index, bool eventsel) } static const struct { enum hybrid_pmu_type id; char *name; } intel_hybrid_pmu_type_map[] __initconst = { - { hybrid_small, "cpu_atom" }, - { hybrid_big, "cpu_core" }, + { hybrid_small, "cpu_atom" }, + { hybrid_big, "cpu_core" }, + { hybrid_tiny, "cpu_lowpower" }, }; static __always_inline int intel_pmu_init_hybrid(enum hybrid_pmu_type pmus) @@ -6272,7 +6350,7 @@ static __always_inline int intel_pmu_init_hybrid(enum hybrid_pmu_type pmus) 0, x86_pmu_num_counters(&pmu->pmu), 0, 0); pmu->intel_cap.capabilities = x86_pmu.intel_cap.capabilities; - if (pmu->pmu_type & hybrid_small) { + if (pmu->pmu_type & hybrid_small_tiny) { pmu->intel_cap.perf_metrics = 0; pmu->intel_cap.pebs_output_pt_available = 1; pmu->mid_ack = true; @@ -7057,6 +7135,7 @@ __init int intel_pmu_init(void) case INTEL_METEORLAKE: case INTEL_METEORLAKE_L: + case INTEL_ARROWLAKE_U: intel_pmu_init_hybrid(hybrid_big_small); x86_pmu.pebs_latency_data = cmt_latency_data; @@ -7111,6 +7190,37 @@ __init int intel_pmu_init(void) name = "lunarlake_hybrid"; break; + case INTEL_ARROWLAKE_H: + intel_pmu_init_hybrid(hybrid_big_small_tiny); + + x86_pmu.pebs_latency_data = arl_h_latency_data; + x86_pmu.get_event_constraints = arl_h_get_event_constraints; + x86_pmu.hw_config = arl_h_hw_config; + + td_attr = arl_h_hybrid_events_attrs; + mem_attr = arl_h_hybrid_mem_attrs; + tsx_attr = adl_hybrid_tsx_attrs; + extra_attr = boot_cpu_has(X86_FEATURE_RTM) ? + mtl_hybrid_extra_attr_rtm : mtl_hybrid_extra_attr; + + /* Initialize big core specific PerfMon capabilities. */ + pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX]; + intel_pmu_init_lnc(&pmu->pmu); + + /* Initialize Atom core specific PerfMon capabilities. */ + pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX]; + intel_pmu_init_skt(&pmu->pmu); + + /* Initialize Lower Power Atom specific PerfMon capabilities. */ + pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_TINY_IDX]; + intel_pmu_init_grt(&pmu->pmu); + pmu->extra_regs = intel_cmt_extra_regs; + + intel_pmu_pebs_data_source_arl_h(); + pr_cont("ArrowLake-H Hybrid events, "); + name = "arrowlake_h_hybrid"; + break; + default: switch (x86_pmu.version) { case 1: diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index fa5ea65de0d0fa..1a4b326ca2ce1d 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -177,6 +177,17 @@ void __init intel_pmu_pebs_data_source_mtl(void) __intel_pmu_pebs_data_source_cmt(data_source); } +void __init intel_pmu_pebs_data_source_arl_h(void) +{ + u64 *data_source; + + intel_pmu_pebs_data_source_lnl(); + + data_source = x86_pmu.hybrid_pmu[X86_HYBRID_PMU_TINY_IDX].pebs_data_source; + memcpy(data_source, pebs_data_source, sizeof(pebs_data_source)); + __intel_pmu_pebs_data_source_cmt(data_source); +} + void __init intel_pmu_pebs_data_source_cmt(void) { __intel_pmu_pebs_data_source_cmt(pebs_data_source); @@ -388,6 +399,16 @@ u64 lnl_latency_data(struct perf_event *event, u64 status) return lnc_latency_data(event, status); } +u64 arl_h_latency_data(struct perf_event *event, u64 status) +{ + struct x86_hybrid_pmu *pmu = hybrid_pmu(event->pmu); + + if (pmu->pmu_type == hybrid_tiny) + return cmt_latency_data(event, status); + + return lnl_latency_data(event, status); +} + static u64 load_latency_data(struct perf_event *event, u64 status) { union intel_x86_pebs_dse dse; @@ -1468,7 +1489,7 @@ void intel_pmu_pebs_enable(struct perf_event *event) * hence we need to drain when changing said * size. */ - intel_pmu_drain_large_pebs(cpuc); + intel_pmu_drain_pebs_buffer(); adaptive_pebs_record_size_update(); wrmsrl(MSR_PEBS_DATA_CFG, pebs_data_cfg); cpuc->active_pebs_data_cfg = pebs_data_cfg; diff --git a/arch/x86/events/intel/pt.c b/arch/x86/events/intel/pt.c index fd4670a6694e77..4b0373bc8ab447 100644 --- a/arch/x86/events/intel/pt.c +++ b/arch/x86/events/intel/pt.c @@ -418,6 +418,9 @@ static void pt_config_start(struct perf_event *event) struct pt *pt = this_cpu_ptr(&pt_ctx); u64 ctl = event->hw.aux_config; + if (READ_ONCE(event->hw.aux_paused)) + return; + ctl |= RTIT_CTL_TRACEEN; if (READ_ONCE(pt->vmx_on)) perf_aux_output_flag(&pt->handle, PERF_AUX_FLAG_PARTIAL); @@ -534,7 +537,24 @@ static void pt_config(struct perf_event *event) reg |= (event->attr.config & PT_CONFIG_MASK); event->hw.aux_config = reg; + + /* + * Allow resume before starting so as not to overwrite a value set by a + * PMI. + */ + barrier(); + WRITE_ONCE(pt->resume_allowed, 1); + /* Configuration is complete, it is now OK to handle an NMI */ + barrier(); + WRITE_ONCE(pt->handle_nmi, 1); + barrier(); pt_config_start(event); + barrier(); + /* + * Allow pause after starting so its pt_config_stop() doesn't race with + * pt_config_start(). + */ + WRITE_ONCE(pt->pause_allowed, 1); } static void pt_config_stop(struct perf_event *event) @@ -828,11 +848,13 @@ static void pt_buffer_advance(struct pt_buffer *buf) buf->cur_idx++; if (buf->cur_idx == buf->cur->last) { - if (buf->cur == buf->last) + if (buf->cur == buf->last) { buf->cur = buf->first; - else + buf->wrapped = true; + } else { buf->cur = list_entry(buf->cur->list.next, struct topa, list); + } buf->cur_idx = 0; } } @@ -846,8 +868,11 @@ static void pt_buffer_advance(struct pt_buffer *buf) static void pt_update_head(struct pt *pt) { struct pt_buffer *buf = perf_get_aux(&pt->handle); + bool wrapped = buf->wrapped; u64 topa_idx, base, old; + buf->wrapped = false; + if (buf->single) { local_set(&buf->data_size, buf->output_off); return; @@ -865,7 +890,7 @@ static void pt_update_head(struct pt *pt) } else { old = (local64_xchg(&buf->head, base) & ((buf->nr_pages << PAGE_SHIFT) - 1)); - if (base < old) + if (base < old || (base == old && wrapped)) base += buf->nr_pages << PAGE_SHIFT; local_add(base - old, &buf->data_size); @@ -1511,6 +1536,7 @@ void intel_pt_interrupt(void) buf = perf_aux_output_begin(&pt->handle, event); if (!buf) { event->hw.state = PERF_HES_STOPPED; + WRITE_ONCE(pt->resume_allowed, 0); return; } @@ -1519,6 +1545,7 @@ void intel_pt_interrupt(void) ret = pt_buffer_reset_markers(buf, &pt->handle); if (ret) { perf_aux_output_end(&pt->handle, 0); + WRITE_ONCE(pt->resume_allowed, 0); return; } @@ -1573,6 +1600,26 @@ static void pt_event_start(struct perf_event *event, int mode) struct pt *pt = this_cpu_ptr(&pt_ctx); struct pt_buffer *buf; + if (mode & PERF_EF_RESUME) { + if (READ_ONCE(pt->resume_allowed)) { + u64 status; + + /* + * Only if the trace is not active and the error and + * stopped bits are clear, is it safe to start, but a + * PMI might have just cleared these, so resume_allowed + * must be checked again also. + */ + rdmsrl(MSR_IA32_RTIT_STATUS, status); + if (!(status & (RTIT_STATUS_TRIGGEREN | + RTIT_STATUS_ERROR | + RTIT_STATUS_STOPPED)) && + READ_ONCE(pt->resume_allowed)) + pt_config_start(event); + } + return; + } + buf = perf_aux_output_begin(&pt->handle, event); if (!buf) goto fail_stop; @@ -1583,7 +1630,6 @@ static void pt_event_start(struct perf_event *event, int mode) goto fail_end_stop; } - WRITE_ONCE(pt->handle_nmi, 1); hwc->state = 0; pt_config_buffer(buf); @@ -1601,6 +1647,12 @@ static void pt_event_stop(struct perf_event *event, int mode) { struct pt *pt = this_cpu_ptr(&pt_ctx); + if (mode & PERF_EF_PAUSE) { + if (READ_ONCE(pt->pause_allowed)) + pt_config_stop(event); + return; + } + /* * Protect against the PMI racing with disabling wrmsr, * see comment in intel_pt_interrupt(). @@ -1608,6 +1660,15 @@ static void pt_event_stop(struct perf_event *event, int mode) WRITE_ONCE(pt->handle_nmi, 0); barrier(); + /* + * Prevent a resume from attempting to restart tracing, or a pause + * during a subsequent start. Do this after clearing handle_nmi so that + * pt_event_snapshot_aux() will not re-allow them. + */ + WRITE_ONCE(pt->pause_allowed, 0); + WRITE_ONCE(pt->resume_allowed, 0); + barrier(); + pt_config_stop(event); if (event->hw.state == PERF_HES_STOPPED) @@ -1657,6 +1718,10 @@ static long pt_event_snapshot_aux(struct perf_event *event, if (WARN_ON_ONCE(!buf->snapshot)) return 0; + /* Prevent pause/resume from attempting to start/stop tracing */ + WRITE_ONCE(pt->pause_allowed, 0); + WRITE_ONCE(pt->resume_allowed, 0); + barrier(); /* * There is no PT interrupt in this mode, so stop the trace and it will * remain stopped while the buffer is copied. @@ -1676,8 +1741,13 @@ static long pt_event_snapshot_aux(struct perf_event *event, * Here, handle_nmi tells us if the tracing was on. * If the tracing was on, restart it. */ - if (READ_ONCE(pt->handle_nmi)) + if (READ_ONCE(pt->handle_nmi)) { + WRITE_ONCE(pt->resume_allowed, 1); + barrier(); pt_config_start(event); + barrier(); + WRITE_ONCE(pt->pause_allowed, 1); + } return ret; } @@ -1793,7 +1863,9 @@ static __init int pt_init(void) if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries)) pt_pmu.pmu.capabilities = PERF_PMU_CAP_AUX_NO_SG; - pt_pmu.pmu.capabilities |= PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE; + pt_pmu.pmu.capabilities |= PERF_PMU_CAP_EXCLUSIVE | + PERF_PMU_CAP_ITRACE | + PERF_PMU_CAP_AUX_PAUSE; pt_pmu.pmu.attr_groups = pt_attr_groups; pt_pmu.pmu.task_ctx_nr = perf_sw_context; pt_pmu.pmu.event_init = pt_event_init; diff --git a/arch/x86/events/intel/pt.h b/arch/x86/events/intel/pt.h index f5e46c04c145d0..7ee94fc6d7cb5d 100644 --- a/arch/x86/events/intel/pt.h +++ b/arch/x86/events/intel/pt.h @@ -65,6 +65,7 @@ struct pt_pmu { * @head: logical write offset inside the buffer * @snapshot: if this is for a snapshot/overwrite counter * @single: use Single Range Output instead of ToPA + * @wrapped: buffer advance wrapped back to the first topa table * @stop_pos: STOP topa entry index * @intr_pos: INT topa entry index * @stop_te: STOP topa entry pointer @@ -82,6 +83,7 @@ struct pt_buffer { local64_t head; bool snapshot; bool single; + bool wrapped; long stop_pos, intr_pos; struct topa_entry *stop_te, *intr_te; void **data_pages; @@ -117,6 +119,8 @@ struct pt_filters { * @filters: last configured filters * @handle_nmi: do handle PT PMI on this cpu, there's an active event * @vmx_on: 1 if VMX is ON on this cpu + * @pause_allowed: PERF_EF_PAUSE is allowed to stop tracing + * @resume_allowed: PERF_EF_RESUME is allowed to start tracing * @output_base: cached RTIT_OUTPUT_BASE MSR value * @output_mask: cached RTIT_OUTPUT_MASK MSR value */ @@ -125,6 +129,8 @@ struct pt { struct pt_filters filters; int handle_nmi; int vmx_on; + int pause_allowed; + int resume_allowed; u64 output_base; u64 output_mask; }; diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index ac1182141bf67f..82c6f45ce97552 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -668,24 +668,38 @@ enum { #define PERF_PEBS_DATA_SOURCE_GRT_MAX 0x10 #define PERF_PEBS_DATA_SOURCE_GRT_MASK (PERF_PEBS_DATA_SOURCE_GRT_MAX - 1) +/* + * CPUID.1AH.EAX[31:0] uniquely identifies the microarchitecture + * of the core. Bits 31-24 indicates its core type (Core or Atom) + * and Bits [23:0] indicates the native model ID of the core. + * Core type and native model ID are defined in below enumerations. + */ enum hybrid_cpu_type { HYBRID_INTEL_NONE, HYBRID_INTEL_ATOM = 0x20, HYBRID_INTEL_CORE = 0x40, }; +#define X86_HYBRID_PMU_ATOM_IDX 0 +#define X86_HYBRID_PMU_CORE_IDX 1 +#define X86_HYBRID_PMU_TINY_IDX 2 + enum hybrid_pmu_type { not_hybrid, - hybrid_small = BIT(0), - hybrid_big = BIT(1), - - hybrid_big_small = hybrid_big | hybrid_small, /* only used for matching */ + hybrid_small = BIT(X86_HYBRID_PMU_ATOM_IDX), + hybrid_big = BIT(X86_HYBRID_PMU_CORE_IDX), + hybrid_tiny = BIT(X86_HYBRID_PMU_TINY_IDX), + + /* The belows are only used for matching */ + hybrid_big_small = hybrid_big | hybrid_small, + hybrid_small_tiny = hybrid_small | hybrid_tiny, + hybrid_big_small_tiny = hybrid_big | hybrid_small_tiny, }; -#define X86_HYBRID_PMU_ATOM_IDX 0 -#define X86_HYBRID_PMU_CORE_IDX 1 - -#define X86_HYBRID_NUM_PMUS 2 +enum atom_native_id { + cmt_native_id = 0x2, /* Crestmont */ + skt_native_id = 0x3, /* Skymont */ +}; struct x86_hybrid_pmu { struct pmu pmu; @@ -1578,6 +1592,8 @@ u64 cmt_latency_data(struct perf_event *event, u64 status); u64 lnl_latency_data(struct perf_event *event, u64 status); +u64 arl_h_latency_data(struct perf_event *event, u64 status); + extern struct event_constraint intel_core2_pebs_event_constraints[]; extern struct event_constraint intel_atom_pebs_event_constraints[]; @@ -1697,6 +1713,8 @@ void intel_pmu_pebs_data_source_grt(void); void intel_pmu_pebs_data_source_mtl(void); +void intel_pmu_pebs_data_source_arl_h(void); + void intel_pmu_pebs_data_source_cmt(void); void intel_pmu_pebs_data_source_lnl(void); diff --git a/arch/x86/events/rapl.c b/arch/x86/events/rapl.c index a481a939862e54..a8defc813c3696 100644 --- a/arch/x86/events/rapl.c +++ b/arch/x86/events/rapl.c @@ -148,7 +148,6 @@ struct rapl_model { /* 1/2^hw_unit Joule */ static int rapl_hw_unit[NR_RAPL_DOMAINS] __read_mostly; static struct rapl_pmus *rapl_pmus; -static cpumask_t rapl_cpu_mask; static unsigned int rapl_cntr_mask; static u64 rapl_timer_ms; static struct perf_msr *rapl_msrs; @@ -369,8 +368,6 @@ static int rapl_pmu_event_init(struct perf_event *event) if (event->cpu < 0) return -EINVAL; - event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG; - if (!cfg || cfg >= NR_RAPL_DOMAINS + 1) return -EINVAL; @@ -389,7 +386,6 @@ static int rapl_pmu_event_init(struct perf_event *event) pmu = cpu_to_rapl_pmu(event->cpu); if (!pmu) return -EINVAL; - event->cpu = pmu->cpu; event->pmu_private = pmu; event->hw.event_base = rapl_msrs[bit].msr; event->hw.config = cfg; @@ -403,23 +399,6 @@ static void rapl_pmu_event_read(struct perf_event *event) rapl_event_update(event); } -static ssize_t rapl_get_attr_cpumask(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return cpumap_print_to_pagebuf(true, buf, &rapl_cpu_mask); -} - -static DEVICE_ATTR(cpumask, S_IRUGO, rapl_get_attr_cpumask, NULL); - -static struct attribute *rapl_pmu_attrs[] = { - &dev_attr_cpumask.attr, - NULL, -}; - -static struct attribute_group rapl_pmu_attr_group = { - .attrs = rapl_pmu_attrs, -}; - RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01"); RAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02"); RAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03"); @@ -467,7 +446,6 @@ static struct attribute_group rapl_pmu_format_group = { }; static const struct attribute_group *rapl_attr_groups[] = { - &rapl_pmu_attr_group, &rapl_pmu_format_group, &rapl_pmu_events_group, NULL, @@ -570,65 +548,6 @@ static struct perf_msr amd_rapl_msrs[] = { [PERF_RAPL_PSYS] = { 0, &rapl_events_psys_group, NULL, false, 0 }, }; -static int rapl_cpu_offline(unsigned int cpu) -{ - struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu); - int target; - - /* Check if exiting cpu is used for collecting rapl events */ - if (!cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask)) - return 0; - - pmu->cpu = -1; - /* Find a new cpu to collect rapl events */ - target = cpumask_any_but(get_rapl_pmu_cpumask(cpu), cpu); - - /* Migrate rapl events to the new target */ - if (target < nr_cpu_ids) { - cpumask_set_cpu(target, &rapl_cpu_mask); - pmu->cpu = target; - perf_pmu_migrate_context(pmu->pmu, cpu, target); - } - return 0; -} - -static int rapl_cpu_online(unsigned int cpu) -{ - s32 rapl_pmu_idx = get_rapl_pmu_idx(cpu); - if (rapl_pmu_idx < 0) { - pr_err("topology_logical_(package/die)_id() returned a negative value"); - return -EINVAL; - } - struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu); - int target; - - if (!pmu) { - pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu)); - if (!pmu) - return -ENOMEM; - - raw_spin_lock_init(&pmu->lock); - INIT_LIST_HEAD(&pmu->active_list); - pmu->pmu = &rapl_pmus->pmu; - pmu->timer_interval = ms_to_ktime(rapl_timer_ms); - rapl_hrtimer_init(pmu); - - rapl_pmus->pmus[rapl_pmu_idx] = pmu; - } - - /* - * Check if there is an online cpu in the package which collects rapl - * events already. - */ - target = cpumask_any_and(&rapl_cpu_mask, get_rapl_pmu_cpumask(cpu)); - if (target < nr_cpu_ids) - return 0; - - cpumask_set_cpu(cpu, &rapl_cpu_mask); - pmu->cpu = cpu; - return 0; -} - static int rapl_check_hw_unit(struct rapl_model *rm) { u64 msr_rapl_power_unit_bits; @@ -707,12 +626,41 @@ static const struct attribute_group *rapl_attr_update[] = { NULL, }; +static int __init init_rapl_pmu(void) +{ + struct rapl_pmu *pmu; + int idx; + + for (idx = 0; idx < rapl_pmus->nr_rapl_pmu; idx++) { + pmu = kzalloc(sizeof(*pmu), GFP_KERNEL); + if (!pmu) + goto free; + + raw_spin_lock_init(&pmu->lock); + INIT_LIST_HEAD(&pmu->active_list); + pmu->pmu = &rapl_pmus->pmu; + pmu->timer_interval = ms_to_ktime(rapl_timer_ms); + rapl_hrtimer_init(pmu); + + rapl_pmus->pmus[idx] = pmu; + } + + return 0; +free: + for (; idx > 0; idx--) + kfree(rapl_pmus->pmus[idx - 1]); + return -ENOMEM; +} + static int __init init_rapl_pmus(void) { int nr_rapl_pmu = topology_max_packages(); + int rapl_pmu_scope = PERF_PMU_SCOPE_PKG; - if (!rapl_pmu_is_pkg_scope()) + if (!rapl_pmu_is_pkg_scope()) { nr_rapl_pmu *= topology_max_dies_per_package(); + rapl_pmu_scope = PERF_PMU_SCOPE_DIE; + } rapl_pmus = kzalloc(struct_size(rapl_pmus, pmus, nr_rapl_pmu), GFP_KERNEL); if (!rapl_pmus) @@ -728,9 +676,11 @@ static int __init init_rapl_pmus(void) rapl_pmus->pmu.start = rapl_pmu_event_start; rapl_pmus->pmu.stop = rapl_pmu_event_stop; rapl_pmus->pmu.read = rapl_pmu_event_read; + rapl_pmus->pmu.scope = rapl_pmu_scope; rapl_pmus->pmu.module = THIS_MODULE; rapl_pmus->pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE; - return 0; + + return init_rapl_pmu(); } static struct rapl_model model_snb = { @@ -876,24 +826,13 @@ static int __init rapl_pmu_init(void) if (ret) return ret; - /* - * Install callbacks. Core will call them for each online cpu. - */ - ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE, - "perf/x86/rapl:online", - rapl_cpu_online, rapl_cpu_offline); - if (ret) - goto out; - ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1); if (ret) - goto out1; + goto out; rapl_advertise(); return 0; -out1: - cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE); out: pr_warn("Initialization failed (%d), disabled\n", ret); cleanup_rapl_pmus(); @@ -903,7 +842,6 @@ module_init(rapl_pmu_init); static void __exit intel_rapl_exit(void) { - cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE); perf_pmu_unregister(&rapl_pmus->pmu); cleanup_rapl_pmus(); } diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index ca9ae606aab9ac..dc03a647776d93 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -96,16 +96,16 @@ extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; * instructions were patched in already: */ extern int alternatives_patched; +struct module; extern void alternative_instructions(void); -extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); -extern void apply_retpolines(s32 *start, s32 *end); -extern void apply_returns(s32 *start, s32 *end); -extern void apply_seal_endbr(s32 *start, s32 *end); +extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end, + struct module *mod); +extern void apply_retpolines(s32 *start, s32 *end, struct module *mod); +extern void apply_returns(s32 *start, s32 *end, struct module *mod); +extern void apply_seal_endbr(s32 *start, s32 *end, struct module *mod); extern void apply_fineibt(s32 *start_retpoline, s32 *end_retpoine, - s32 *start_cfi, s32 *end_cfi); - -struct module; + s32 *start_cfi, s32 *end_cfi, struct module *mod); struct callthunk_sites { s32 *call_start, *call_end; diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h index 1f650b4dde509b..6c6e9b9f98a456 100644 --- a/arch/x86/include/asm/atomic64_32.h +++ b/arch/x86/include/asm/atomic64_32.h @@ -51,7 +51,8 @@ static __always_inline s64 arch_atomic64_read_nonatomic(const atomic64_t *v) #ifdef CONFIG_X86_CMPXCHG64 #define __alternative_atomic64(f, g, out, in...) \ asm volatile("call %c[func]" \ - : out : [func] "i" (atomic64_##g##_cx8), ## in) + : ALT_OUTPUT_SP(out) \ + : [func] "i" (atomic64_##g##_cx8), ## in) #define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8) #else diff --git a/arch/x86/include/asm/cmpxchg_32.h b/arch/x86/include/asm/cmpxchg_32.h index 62cef2113ca749..fd1282a783ddbf 100644 --- a/arch/x86/include/asm/cmpxchg_32.h +++ b/arch/x86/include/asm/cmpxchg_32.h @@ -94,7 +94,7 @@ static __always_inline bool __try_cmpxchg64_local(volatile u64 *ptr, u64 *oldp, asm volatile(ALTERNATIVE(_lock_loc \ "call cmpxchg8b_emu", \ _lock "cmpxchg8b %a[ptr]", X86_FEATURE_CX8) \ - : "+a" (o.low), "+d" (o.high) \ + : ALT_OUTPUT_SP("+a" (o.low), "+d" (o.high)) \ : "b" (n.low), "c" (n.high), [ptr] "S" (_ptr) \ : "memory"); \ \ @@ -123,8 +123,8 @@ static __always_inline u64 arch_cmpxchg64_local(volatile u64 *ptr, u64 old, u64 "call cmpxchg8b_emu", \ _lock "cmpxchg8b %a[ptr]", X86_FEATURE_CX8) \ CC_SET(e) \ - : CC_OUT(e) (ret), \ - "+a" (o.low), "+d" (o.high) \ + : ALT_OUTPUT_SP(CC_OUT(e) (ret), \ + "+a" (o.low), "+d" (o.high)) \ : "b" (n.low), "c" (n.high), [ptr] "S" (_ptr) \ : "memory"); \ \ diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index aa30fd8cad7f52..98eced5084ca74 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -26,12 +26,13 @@ int mwait_usable(const struct cpuinfo_x86 *); unsigned int x86_family(unsigned int sig); unsigned int x86_model(unsigned int sig); unsigned int x86_stepping(unsigned int sig); -#ifdef CONFIG_CPU_SUP_INTEL +#ifdef CONFIG_X86_BUS_LOCK_DETECT extern void __init sld_setup(struct cpuinfo_x86 *c); extern bool handle_user_split_lock(struct pt_regs *regs, long error_code); extern bool handle_guest_split_lock(unsigned long ip); extern void handle_bus_lock(struct pt_regs *regs); -u8 get_this_hybrid_cpu_type(void); +void split_lock_init(void); +void bus_lock_init(void); #else static inline void __init sld_setup(struct cpuinfo_x86 *c) {} static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code) @@ -45,11 +46,23 @@ static inline bool handle_guest_split_lock(unsigned long ip) } static inline void handle_bus_lock(struct pt_regs *regs) {} +static inline void split_lock_init(void) {} +static inline void bus_lock_init(void) {} +#endif +#ifdef CONFIG_CPU_SUP_INTEL +u8 get_this_hybrid_cpu_type(void); +u32 get_this_hybrid_cpu_native_id(void); +#else static inline u8 get_this_hybrid_cpu_type(void) { return 0; } + +static inline u32 get_this_hybrid_cpu_native_id(void) +{ + return 0; +} #endif #ifdef CONFIG_IA32_FEAT_CTL void init_ia32_feat_ctl(struct cpuinfo_x86 *c); diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 913fd3a7bac650..645aa360628da7 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -317,6 +317,9 @@ #define X86_FEATURE_ZEN1 (11*32+31) /* CPU based on Zen1 microarchitecture */ /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ +#define X86_FEATURE_SHA512 (12*32+ 0) /* SHA512 instructions */ +#define X86_FEATURE_SM3 (12*32+ 1) /* SM3 instructions */ +#define X86_FEATURE_SM4 (12*32+ 2) /* SM4 instructions */ #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* "avx_vnni" AVX VNNI instructions */ #define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* "avx512_bf16" AVX512 BFLOAT16 instructions */ #define X86_FEATURE_CMPCCXADD (12*32+ 7) /* CMPccXADD instructions */ @@ -449,6 +452,7 @@ #define X86_FEATURE_SME_COHERENT (19*32+10) /* AMD hardware-enforced cache coherency */ #define X86_FEATURE_DEBUG_SWAP (19*32+14) /* "debug_swap" AMD SEV-ES full debug state swap support */ #define X86_FEATURE_SVSM (19*32+28) /* "svsm" SVSM present */ +#define X86_FEATURE_HV_INUSE_WR_ALLOWED (19*32+30) /* Allow Write to in-use hypervisor-owned pages */ /* AMD-defined Extended Feature 2 EAX, CPUID level 0x80000021 (EAX), word 20 */ #define X86_FEATURE_NO_NESTED_DATA_BP (20*32+ 0) /* No Nested Data Breakpoints */ @@ -473,7 +477,9 @@ #define X86_FEATURE_BHI_CTRL (21*32+ 2) /* BHI_DIS_S HW control available */ #define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */ #define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */ -#define X86_FEATURE_FAST_CPPC (21*32 + 5) /* AMD Fast CPPC */ +#define X86_FEATURE_AMD_FAST_CPPC (21*32 + 5) /* Fast CPPC */ +#define X86_FEATURE_AMD_HETEROGENEOUS_CORES (21*32 + 6) /* Heterogeneous Core Topology */ +#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32 + 7) /* Workload Classification */ /* * BUG word(s) diff --git a/arch/x86/include/asm/cpuid.h b/arch/x86/include/asm/cpuid.h index ca4243318aadc4..239b9ba5c398a2 100644 --- a/arch/x86/include/asm/cpuid.h +++ b/arch/x86/include/asm/cpuid.h @@ -6,6 +6,8 @@ #ifndef _ASM_X86_CPUID_H #define _ASM_X86_CPUID_H +#include + #include struct cpuid_regs { @@ -20,11 +22,11 @@ enum cpuid_regs_idx { }; #ifdef CONFIG_X86_32 -extern int have_cpuid_p(void); +bool have_cpuid_p(void); #else -static inline int have_cpuid_p(void) +static inline bool have_cpuid_p(void) { - return 1; + return true; } #endif static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index b4d719de2c8459..6e8cf0fa48fc60 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h @@ -35,37 +35,21 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) } #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS -struct ftrace_regs { - struct pt_regs regs; -}; + +#include static __always_inline struct pt_regs * arch_ftrace_get_regs(struct ftrace_regs *fregs) { /* Only when FL_SAVE_REGS is set, cs will be non zero */ - if (!fregs->regs.cs) + if (!arch_ftrace_regs(fregs)->regs.cs) return NULL; - return &fregs->regs; + return &arch_ftrace_regs(fregs)->regs; } #define ftrace_regs_set_instruction_pointer(fregs, _ip) \ - do { (fregs)->regs.ip = (_ip); } while (0) - -#define ftrace_regs_get_instruction_pointer(fregs) \ - ((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) + do { arch_ftrace_regs(fregs)->regs.ip = (_ip); } while (0) + struct ftrace_ops; #define ftrace_graph_func ftrace_graph_func @@ -90,7 +74,7 @@ __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) regs->orig_ax = addr; } #define arch_ftrace_set_direct_caller(fregs, addr) \ - __arch_ftrace_set_direct_caller(&(fregs)->regs, addr) + __arch_ftrace_set_direct_caller(&arch_ftrace_regs(fregs)->regs, addr) #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ #ifdef CONFIG_DYNAMIC_FTRACE diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h index 99d345b686fa22..6e2458088800ac 100644 --- a/arch/x86/include/asm/futex.h +++ b/arch/x86/include/asm/futex.h @@ -48,7 +48,9 @@ do { \ static __always_inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) { - if (!user_access_begin(uaddr, sizeof(u32))) + if (can_do_masked_user_access()) + uaddr = masked_user_access_begin(uaddr); + else if (!user_access_begin(uaddr, sizeof(u32))) return -EFAULT; switch (op) { @@ -84,7 +86,9 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, { int ret = 0; - if (!user_access_begin(uaddr, sizeof(u32))) + if (can_do_masked_user_access()) + uaddr = masked_user_access_begin(uaddr); + else if (!user_access_begin(uaddr, sizeof(u32))) return -EFAULT; asm volatile("\n" "1:\t" LOCK_PREFIX "cmpxchgl %3, %2\n" diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h index 1a42f829667a37..6d7b04ffc5fd0e 100644 --- a/arch/x86/include/asm/intel-family.h +++ b/arch/x86/include/asm/intel-family.h @@ -177,10 +177,15 @@ #define INTEL_XEON_PHI_KNM IFM(6, 0x85) /* Knights Mill */ /* Family 5 */ -#define INTEL_FAM5_QUARK_X1000 0x09 /* Quark X1000 SoC */ #define INTEL_QUARK_X1000 IFM(5, 0x09) /* Quark X1000 SoC */ /* Family 19 */ #define INTEL_PANTHERCOVE_X IFM(19, 0x01) /* Diamond Rapids */ +/* CPU core types */ +enum intel_cpu_type { + INTEL_CPU_TYPE_ATOM = 0x20, + INTEL_CPU_TYPE_CORE = 0x40, +}; + #endif /* _ASM_X86_INTEL_FAMILY_H */ diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index 1d60427379c939..ed580c7f9d0aaf 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -151,11 +151,6 @@ static inline void *phys_to_virt(phys_addr_t address) } #define phys_to_virt phys_to_virt -/* - * Change "struct page" to physical address. - */ -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) - /* * ISA I/O bus memory addresses are 1:1 with the physical address. * However, we truncate the address to unsigned int to avoid undesirable diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h index cbbef32517f004..3f1c1d6c0da12d 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -12,35 +12,28 @@ #include #include -#define JUMP_TABLE_ENTRY \ +#define JUMP_TABLE_ENTRY(key, label) \ ".pushsection __jump_table, \"aw\" \n\t" \ _ASM_ALIGN "\n\t" \ ".long 1b - . \n\t" \ - ".long %l[l_yes] - . \n\t" \ - _ASM_PTR "%c0 + %c1 - .\n\t" \ + ".long " label " - . \n\t" \ + _ASM_PTR " " key " - . \n\t" \ ".popsection \n\t" +/* This macro is also expanded on the Rust side. */ #ifdef CONFIG_HAVE_JUMP_LABEL_HACK - -static __always_inline bool arch_static_branch(struct static_key *key, bool branch) -{ - asm goto("1:" - "jmp %l[l_yes] # objtool NOPs this \n\t" - JUMP_TABLE_ENTRY - : : "i" (key), "i" (2 | branch) : : l_yes); - - return false; -l_yes: - return true; -} - +#define ARCH_STATIC_BRANCH_ASM(key, label) \ + "1: jmp " label " # objtool NOPs this \n\t" \ + JUMP_TABLE_ENTRY(key " + 2", label) #else /* !CONFIG_HAVE_JUMP_LABEL_HACK */ +#define ARCH_STATIC_BRANCH_ASM(key, label) \ + "1: .byte " __stringify(BYTES_NOP5) "\n\t" \ + JUMP_TABLE_ENTRY(key, label) +#endif /* CONFIG_HAVE_JUMP_LABEL_HACK */ static __always_inline bool arch_static_branch(struct static_key * const key, const bool branch) { - asm goto("1:" - ".byte " __stringify(BYTES_NOP5) "\n\t" - JUMP_TABLE_ENTRY + asm goto(ARCH_STATIC_BRANCH_ASM("%c0 + %c1", "%l[l_yes]") : : "i" (key), "i" (branch) : : l_yes); return false; @@ -48,13 +41,11 @@ static __always_inline bool arch_static_branch(struct static_key * const key, co return true; } -#endif /* CONFIG_HAVE_JUMP_LABEL_HACK */ - static __always_inline bool arch_static_branch_jump(struct static_key * const key, const bool branch) { asm goto("1:" "jmp %l[l_yes]\n\t" - JUMP_TABLE_ENTRY + JUMP_TABLE_ENTRY("%c0 + %c1", "%l[l_yes]") : : "i" (key), "i" (branch) : : l_yes); return false; diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 861d080ed4c6ab..5aff7222e40fac 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -34,6 +34,7 @@ KVM_X86_OP(set_msr) KVM_X86_OP(get_segment_base) KVM_X86_OP(get_segment) KVM_X86_OP(get_cpl) +KVM_X86_OP(get_cpl_no_cache) KVM_X86_OP(set_segment) KVM_X86_OP(get_cs_db_l_bits) KVM_X86_OP(is_valid_cr0) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 6d9f763a7bb9d5..e159e44a6a1b61 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -1306,7 +1307,6 @@ struct kvm_arch { bool pre_fault_allowed; struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; struct list_head active_mmu_pages; - struct list_head zapped_obsolete_pages; /* * A list of kvm_mmu_page structs that, if zapped, could possibly be * replaced by an NX huge page. A shadow page is on this list if its @@ -1443,7 +1443,8 @@ struct kvm_arch { bool sgx_provisioning_allowed; struct kvm_x86_pmu_event_filter __rcu *pmu_event_filter; - struct task_struct *nx_huge_page_recovery_thread; + struct vhost_task *nx_huge_page_recovery_thread; + u64 nx_huge_page_last; #ifdef CONFIG_X86_64 /* The number of TDP MMU pages across all roots. */ @@ -1656,6 +1657,7 @@ struct kvm_x86_ops { void (*get_segment)(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); int (*get_cpl)(struct kvm_vcpu *vcpu); + int (*get_cpl_no_cache)(struct kvm_vcpu *vcpu); void (*set_segment)(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); @@ -1955,8 +1957,8 @@ void kvm_mmu_try_split_huge_pages(struct kvm *kvm, const struct kvm_memory_slot *memslot, u64 start, u64 end, int target_level); -void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm, - const struct kvm_memory_slot *memslot); +void kvm_mmu_recover_huge_pages(struct kvm *kvm, + const struct kvm_memory_slot *memslot); void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm, const struct kvm_memory_slot *memslot); void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen); @@ -2359,7 +2361,8 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages); KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT | \ KVM_X86_QUIRK_FIX_HYPERCALL_INSN | \ KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS | \ - KVM_X86_QUIRK_SLOT_ZAP_ALL) + KVM_X86_QUIRK_SLOT_ZAP_ALL | \ + KVM_X86_QUIRK_STUFF_FEATURE_MSRS) /* * KVM previously used a u32 field in kvm_run to indicate the hypercall was diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 3b9970117a0fa7..4543cf2eb5e8ff 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -61,6 +61,7 @@ * - TCC bit is present in MCx_STATUS. */ #define MCI_CONFIG_MCAX 0x1 +#define MCI_CONFIG_FRUTEXT BIT_ULL(9) #define MCI_IPID_MCATYPE 0xFFFF0000 #define MCI_IPID_HWID 0xFFF @@ -122,6 +123,9 @@ #define MSR_AMD64_SMCA_MC0_DESTAT 0xc0002008 #define MSR_AMD64_SMCA_MC0_DEADDR 0xc0002009 #define MSR_AMD64_SMCA_MC0_MISC1 0xc000200a +/* Registers MISC2 to MISC4 are at offsets B to D. */ +#define MSR_AMD64_SMCA_MC0_SYND1 0xc000200e +#define MSR_AMD64_SMCA_MC0_SYND2 0xc000200f #define MSR_AMD64_SMCA_MCx_CTL(x) (MSR_AMD64_SMCA_MC0_CTL + 0x10*(x)) #define MSR_AMD64_SMCA_MCx_STATUS(x) (MSR_AMD64_SMCA_MC0_STATUS + 0x10*(x)) #define MSR_AMD64_SMCA_MCx_ADDR(x) (MSR_AMD64_SMCA_MC0_ADDR + 0x10*(x)) @@ -132,6 +136,8 @@ #define MSR_AMD64_SMCA_MCx_DESTAT(x) (MSR_AMD64_SMCA_MC0_DESTAT + 0x10*(x)) #define MSR_AMD64_SMCA_MCx_DEADDR(x) (MSR_AMD64_SMCA_MC0_DEADDR + 0x10*(x)) #define MSR_AMD64_SMCA_MCx_MISCy(x, y) ((MSR_AMD64_SMCA_MC0_MISC1 + y) + (0x10*(x))) +#define MSR_AMD64_SMCA_MCx_SYND1(x) (MSR_AMD64_SMCA_MC0_SYND1 + 0x10*(x)) +#define MSR_AMD64_SMCA_MCx_SYND2(x) (MSR_AMD64_SMCA_MC0_SYND2 + 0x10*(x)) #define XEC(x, mask) (((x) >> 16) & mask) @@ -187,6 +193,32 @@ enum mce_notifier_prios { MCE_PRIO_HIGHEST = MCE_PRIO_CEC }; +/** + * struct mce_hw_err - Hardware Error Record. + * @m: Machine Check record. + * @vendor: Vendor-specific error information. + * + * Vendor-specific fields should not be added to struct mce. Instead, vendors + * should export their vendor-specific data through their structure in the + * vendor union below. + * + * AMD's vendor data is parsed by error decoding tools for supplemental error + * information. Thus, current offsets of existing fields must be maintained. + * Only add new fields at the end of AMD's vendor structure. + */ +struct mce_hw_err { + struct mce m; + + union vendor_info { + struct { + u64 synd1; /* MCA_SYND1 MSR */ + u64 synd2; /* MCA_SYND2 MSR */ + } amd; + } vendor; +}; + +#define to_mce_hw_err(mce) container_of(mce, struct mce_hw_err, m) + struct notifier_block; extern void mce_register_decode_chain(struct notifier_block *nb); extern void mce_unregister_decode_chain(struct notifier_block *nb); @@ -221,8 +253,8 @@ static inline int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, u64 lapic_id) { return -EINVAL; } #endif -void mce_prep_record(struct mce *m); -void mce_log(struct mce *m); +void mce_prep_record(struct mce_hw_err *err); +void mce_log(struct mce_hw_err *err); DECLARE_PER_CPU(struct device *, mce_device); /* Maximum number of MCA banks per CPU. */ diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h index 1b93ff80b43bcc..c9fe207916f487 100644 --- a/arch/x86/include/asm/page.h +++ b/arch/x86/include/asm/page.h @@ -35,7 +35,7 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr, } #define vma_alloc_zeroed_movable_folio(vma, vaddr) \ - vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr, false) + vma_alloc_folio(GFP_HIGHUSER_MOVABLE | __GFP_ZERO, 0, vma, vaddr) #ifndef __pa #define __pa(x) __phys_addr((unsigned long)(x)) diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h index f3d257c452254d..d63576608ce765 100644 --- a/arch/x86/include/asm/page_64.h +++ b/arch/x86/include/asm/page_64.h @@ -17,7 +17,7 @@ extern unsigned long phys_base; extern unsigned long page_offset_base; extern unsigned long vmalloc_base; extern unsigned long vmemmap_base; -extern unsigned long physmem_end; +extern unsigned long direct_map_physmem_end; static __always_inline unsigned long __phys_addr_nodebug(unsigned long x) { diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h index 52f1b4ff0cc16c..974688973cf6e0 100644 --- a/arch/x86/include/asm/page_types.h +++ b/arch/x86/include/asm/page_types.h @@ -6,10 +6,7 @@ #include #include -/* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index c55a79d5feaeb6..e525cd85f999fd 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -234,9 +234,10 @@ do { \ */ #define percpu_add_op(size, qual, var, val) \ do { \ - const int pao_ID__ = (__builtin_constant_p(val) && \ - ((val) == 1 || (val) == -1)) ? \ - (int)(val) : 0; \ + const int pao_ID__ = \ + (__builtin_constant_p(val) && \ + ((val) == 1 || \ + (val) == (typeof(val))-1)) ? (int)(val) : 0; \ \ if (0) { \ typeof(var) pao_tmp__; \ diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 91b73571412f16..d95f902acc5211 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -536,15 +536,17 @@ struct x86_perf_regs { u64 *xmm_regs; }; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +extern unsigned long perf_arch_guest_misc_flags(struct pt_regs *regs); +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) +#define perf_arch_guest_misc_flags(regs) perf_arch_guest_misc_flags(regs) #include /* - * We abuse bit 3 from flags to pass exact information, see perf_misc_flags - * and the comment with PERF_EFLAGS_EXACT. + * We abuse bit 3 from flags to pass exact information, see + * perf_arch_misc_flags() and the comment with PERF_EFLAGS_EXACT. */ #define perf_arch_fetch_caller_regs(regs, __ip) { \ (regs)->ip = (__ip); \ diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 4c2d080d26b4fb..593f10aabd45a6 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -1775,6 +1775,43 @@ bool arch_is_platform_page(u64 paddr); #define arch_is_platform_page arch_is_platform_page #endif +/* + * Use set_p*_safe(), and elide TLB flushing, when confident that *no* + * TLB flush will be required as a result of the "set". For example, use + * in scenarios where it is known ahead of time that the routine is + * setting non-present entries, or re-setting an existing entry to the + * same value. Otherwise, use the typical "set" helpers and flush the + * TLB. + */ +#define set_pte_safe(ptep, pte) \ +({ \ + WARN_ON_ONCE(pte_present(*ptep) && !pte_same(*ptep, pte)); \ + set_pte(ptep, pte); \ +}) + +#define set_pmd_safe(pmdp, pmd) \ +({ \ + WARN_ON_ONCE(pmd_present(*pmdp) && !pmd_same(*pmdp, pmd)); \ + set_pmd(pmdp, pmd); \ +}) + +#define set_pud_safe(pudp, pud) \ +({ \ + WARN_ON_ONCE(pud_present(*pudp) && !pud_same(*pudp, pud)); \ + set_pud(pudp, pud); \ +}) + +#define set_p4d_safe(p4dp, p4d) \ +({ \ + WARN_ON_ONCE(p4d_present(*p4dp) && !p4d_same(*p4dp, p4d)); \ + set_p4d(p4dp, p4d); \ +}) + +#define set_pgd_safe(pgdp, pgd) \ +({ \ + WARN_ON_ONCE(pgd_present(*pgdp) && !pgd_same(*pgdp, pgd)); \ + set_pgd(pgdp, pgd); \ +}) #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_PGTABLE_H */ diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h index a98e53491a4e6e..ec68f8369bdca4 100644 --- a/arch/x86/include/asm/pgtable_64_types.h +++ b/arch/x86/include/asm/pgtable_64_types.h @@ -141,7 +141,7 @@ extern unsigned int ptrs_per_p4d; #endif /* CONFIG_DYNAMIC_MEMORY_LAYOUT */ #ifdef CONFIG_RANDOMIZE_MEMORY -# define PHYSMEM_END physmem_end +# define DIRECT_MAP_PHYSMEM_END direct_map_physmem_end #endif /* diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 6f82e75b61494e..4b804531b03c3c 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -36,10 +36,12 @@ #define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4 #ifdef CONFIG_X86_64 -#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW5 /* Saved Dirty bit */ +#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW5 /* Saved Dirty bit (leaf) */ +#define _PAGE_BIT_NOPTISHADOW _PAGE_BIT_SOFTW5 /* No PTI shadow (root PGD) */ #else /* Shared with _PAGE_BIT_UFFD_WP which is not supported on 32 bit */ -#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW2 /* Saved Dirty bit */ +#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW2 /* Saved Dirty bit (leaf) */ +#define _PAGE_BIT_NOPTISHADOW _PAGE_BIT_SOFTW2 /* No PTI shadow (root PGD) */ #endif /* If _PAGE_BIT_PRESENT is clear, we use these: */ @@ -139,6 +141,8 @@ #define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE) +#define _PAGE_NOPTISHADOW (_AT(pteval_t, 1) << _PAGE_BIT_NOPTISHADOW) + /* * Set of bits not changed in pte_modify. The pte's * protection key is treated like _PAGE_RW, for diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 4a686f0e5dbf6d..20e6009381ed6f 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -105,6 +105,24 @@ struct cpuinfo_topology { // Cache level topology IDs u32 llc_id; u32 l2c_id; + + // Hardware defined CPU-type + union { + u32 cpu_type; + struct { + // CPUID.1A.EAX[23-0] + u32 intel_native_model_id :24; + // CPUID.1A.EAX[31-24] + u32 intel_type :8; + }; + struct { + // CPUID 0x80000026.EBX + u32 amd_num_processors :16, + amd_power_eff_ranking :8, + amd_native_model_id :4, + amd_type :4; + }; + }; }; struct cpuinfo_x86 { @@ -212,6 +230,8 @@ static inline unsigned long long l1tf_pfn_limit(void) return BIT_ULL(boot_cpu_data.x86_cache_bits - 1 - PAGE_SHIFT); } +void init_cpu_devs(void); +void get_cpu_vendor(struct cpuinfo_x86 *c); extern void early_cpu_init(void); extern void identify_secondary_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); diff --git a/arch/x86/include/asm/set_memory.h b/arch/x86/include/asm/set_memory.h index 4b2abce2e3e7d6..cc62ef70ccc0ac 100644 --- a/arch/x86/include/asm/set_memory.h +++ b/arch/x86/include/asm/set_memory.h @@ -89,6 +89,7 @@ int set_pages_rw(struct page *page, int numpages); int set_direct_map_invalid_noflush(struct page *page); int set_direct_map_default_noflush(struct page *page); +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid); bool kernel_page_present(struct page *page); extern int kernel_set_to_readonly; diff --git a/arch/x86/include/asm/sev-common.h b/arch/x86/include/asm/sev-common.h index 98726c2b04f852..50f5666938c097 100644 --- a/arch/x86/include/asm/sev-common.h +++ b/arch/x86/include/asm/sev-common.h @@ -220,4 +220,31 @@ struct snp_psc_desc { #define GHCB_ERR_INVALID_INPUT 5 #define GHCB_ERR_INVALID_EVENT 6 +struct sev_config { + __u64 debug : 1, + + /* + * Indicates when the per-CPU GHCB has been created and registered + * and thus can be used by the BSP instead of the early boot GHCB. + * + * For APs, the per-CPU GHCB is created before they are started + * and registered upon startup, so this flag can be used globally + * for the BSP and APs. + */ + ghcbs_initialized : 1, + + /* + * Indicates when the per-CPU SVSM CA is to be used instead of the + * boot SVSM CA. + * + * For APs, the per-CPU SVSM CA is created as part of the AP + * bringup, so this flag can be used globally for the BSP and APs. + */ + use_cas : 1, + + __reserved : 61; +}; + +extern struct sev_config sev_cfg; + #endif diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h index ee34ab00a8d6d9..91f08af3107853 100644 --- a/arch/x86/include/asm/sev.h +++ b/arch/x86/include/asm/sev.h @@ -120,6 +120,9 @@ struct snp_req_data { }; #define MAX_AUTHTAG_LEN 32 +#define AUTHTAG_LEN 16 +#define AAD_LEN 48 +#define MSG_HDR_VER 1 /* See SNP spec SNP_GUEST_REQUEST section for the structure */ enum msg_type { @@ -171,6 +174,19 @@ struct sev_guest_platform_data { u64 secrets_gpa; }; +struct snp_guest_req { + void *req_buf; + size_t req_sz; + + void *resp_buf; + size_t resp_sz; + + u64 exit_code; + unsigned int vmpck_id; + u8 msg_version; + u8 msg_type; +}; + /* * The secrets page contains 96-bytes of reserved field that can be used by * the guest OS. The guest OS uses the area to save the message sequence @@ -218,6 +234,27 @@ struct snp_secrets_page { u8 rsvd4[3744]; } __packed; +struct snp_msg_desc { + /* request and response are in unencrypted memory */ + struct snp_guest_msg *request, *response; + + /* + * Avoid information leakage by double-buffering shared messages + * in fields that are in regular encrypted memory. + */ + struct snp_guest_msg secret_request, secret_response; + + struct snp_secrets_page *secrets; + struct snp_req_data input; + + void *certs_data; + + struct aesgcm_ctx *ctx; + + u32 *os_area_msg_seqno; + u8 *vmpck; +}; + /* * The SVSM Calling Area (CA) related structures. */ @@ -285,6 +322,22 @@ struct svsm_attest_call { u8 rsvd[4]; }; +/* PTE descriptor used for the prepare_pte_enc() operations. */ +struct pte_enc_desc { + pte_t *kpte; + int pte_level; + bool encrypt; + /* pfn of the kpte above */ + unsigned long pfn; + /* physical address of @pfn */ + unsigned long pa; + /* virtual address of @pfn */ + void *va; + /* memory covered by the pte */ + unsigned long size; + pgprot_t new_pgprot; +}; + /* * SVSM protocol structure */ @@ -392,13 +445,18 @@ void snp_set_wakeup_secondary_cpu(void); bool snp_init(struct boot_params *bp); void __noreturn snp_abort(void); void snp_dmi_setup(void); -int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio); +int snp_issue_guest_request(struct snp_guest_req *req, struct snp_req_data *input, + struct snp_guest_request_ioctl *rio); int snp_issue_svsm_attest_req(u64 call_id, struct svsm_call *call, struct svsm_attest_call *input); void snp_accept_memory(phys_addr_t start, phys_addr_t end); u64 snp_get_unsupported_features(u64 status); u64 sev_get_status(void); void sev_show_status(void); void snp_update_svsm_ca(void); +int prepare_pte_enc(struct pte_enc_desc *d); +void set_pte_enc_mask(pte_t *kpte, unsigned long pfn, pgprot_t new_prot); +void snp_kexec_finish(void); +void snp_kexec_begin(void); #else /* !CONFIG_AMD_MEM_ENCRYPT */ @@ -422,7 +480,8 @@ static inline void snp_set_wakeup_secondary_cpu(void) { } static inline bool snp_init(struct boot_params *bp) { return false; } static inline void snp_abort(void) { } static inline void snp_dmi_setup(void) { } -static inline int snp_issue_guest_request(u64 exit_code, struct snp_req_data *input, struct snp_guest_request_ioctl *rio) +static inline int snp_issue_guest_request(struct snp_guest_req *req, struct snp_req_data *input, + struct snp_guest_request_ioctl *rio) { return -ENOTTY; } @@ -435,6 +494,10 @@ static inline u64 snp_get_unsupported_features(u64 status) { return 0; } static inline u64 sev_get_status(void) { return 0; } static inline void sev_show_status(void) { } static inline void snp_update_svsm_ca(void) { } +static inline int prepare_pte_enc(struct pte_enc_desc *d) { return 0; } +static inline void set_pte_enc_mask(pte_t *kpte, unsigned long pfn, pgprot_t new_prot) { } +static inline void snp_kexec_finish(void) { } +static inline void snp_kexec_begin(void) { } #endif /* CONFIG_AMD_MEM_ENCRYPT */ diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h index fdfd41511b0211..89f7fcade8ae9c 100644 --- a/arch/x86/include/asm/shared/tdx.h +++ b/arch/x86/include/asm/shared/tdx.h @@ -16,10 +16,21 @@ #define TDG_VP_VEINFO_GET 3 #define TDG_MR_REPORT 4 #define TDG_MEM_PAGE_ACCEPT 6 +#define TDG_VM_RD 7 #define TDG_VM_WR 8 -/* TDCS fields. To be used by TDG.VM.WR and TDG.VM.RD module calls */ +/* TDX TD-Scope Metadata. To be used by TDG.VM.WR and TDG.VM.RD */ +#define TDCS_CONFIG_FLAGS 0x1110000300000016 +#define TDCS_TD_CTLS 0x1110000300000017 #define TDCS_NOTIFY_ENABLES 0x9100000000000010 +#define TDCS_TOPOLOGY_ENUM_CONFIGURED 0x9100000000000019 + +/* TDCS_CONFIG_FLAGS bits */ +#define TDCS_CONFIG_FLEXIBLE_PENDING_VE BIT_ULL(1) + +/* TDCS_TD_CTLS bits */ +#define TD_CTLS_PENDING_VE_DISABLE BIT_ULL(0) +#define TD_CTLS_ENUM_TOPOLOGY BIT_ULL(1) /* TDX hypercall Leaf IDs */ #define TDVMCALL_MAP_GPA 0x10001 diff --git a/arch/x86/include/asm/static_call.h b/arch/x86/include/asm/static_call.h index 125c407e2abe6d..41502bd2afd646 100644 --- a/arch/x86/include/asm/static_call.h +++ b/arch/x86/include/asm/static_call.h @@ -65,4 +65,19 @@ extern bool __static_call_fixup(void *tramp, u8 op, void *dest); +extern void __static_call_update_early(void *tramp, void *func); + +#define static_call_update_early(name, _func) \ +({ \ + typeof(&STATIC_CALL_TRAMP(name)) __F = (_func); \ + if (static_call_initialized) { \ + __static_call_update(&STATIC_CALL_KEY(name), \ + STATIC_CALL_TRAMP_ADDR(name), __F);\ + } else { \ + WRITE_ONCE(STATIC_CALL_KEY(name).func, _func); \ + __static_call_update_early(STATIC_CALL_TRAMP_ADDR(name),\ + __F); \ + } \ +}) + #endif /* _ASM_STATIC_CALL_H */ diff --git a/arch/x86/include/asm/sync_core.h b/arch/x86/include/asm/sync_core.h index ab7382f92aff27..96bda43538ee70 100644 --- a/arch/x86/include/asm/sync_core.h +++ b/arch/x86/include/asm/sync_core.h @@ -8,7 +8,7 @@ #include #ifdef CONFIG_X86_32 -static inline void iret_to_self(void) +static __always_inline void iret_to_self(void) { asm volatile ( "pushfl\n\t" @@ -19,7 +19,7 @@ static inline void iret_to_self(void) : ASM_CALL_CONSTRAINT : : "memory"); } #else -static inline void iret_to_self(void) +static __always_inline void iret_to_self(void) { unsigned int tmp; @@ -55,7 +55,7 @@ static inline void iret_to_self(void) * Like all of Linux's memory ordering operations, this is a * compiler barrier as well. */ -static inline void sync_core(void) +static __always_inline void sync_core(void) { /* * The SERIALIZE instruction is the most straightforward way to diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h index 6259f1937fe77e..ab9e143ec9fea1 100644 --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -35,6 +35,7 @@ extern void *text_poke(void *addr, const void *opcode, size_t len); extern void text_poke_sync(void); extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len); extern void *text_poke_copy(void *addr, const void *opcode, size_t len); +#define text_poke_copy text_poke_copy extern void *text_poke_copy_locked(void *addr, const void *opcode, size_t len, bool core_ok); extern void *text_poke_set(void *addr, int c, size_t len); extern int poke_int3_handler(struct pt_regs *regs); diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 12da7dfd5ef13b..a55c214f3ba64d 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -87,8 +87,9 @@ struct thread_info { #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_SINGLESTEP 4 /* reenable singlestep on user return*/ -#define TIF_SSBD 5 /* Speculative store bypass disable */ +#define TIF_NEED_RESCHED_LAZY 4 /* Lazy rescheduling needed */ +#define TIF_SINGLESTEP 5 /* reenable singlestep on user return*/ +#define TIF_SSBD 6 /* Speculative store bypass disable */ #define TIF_SPEC_IB 9 /* Indirect branch speculation mitigation */ #define TIF_SPEC_L1D_FLUSH 10 /* Flush L1D on mm switches (processes) */ #define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */ @@ -110,6 +111,7 @@ struct thread_info { #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_NEED_RESCHED_LAZY (1 << TIF_NEED_RESCHED_LAZY) #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) #define _TIF_SSBD (1 << TIF_SSBD) #define _TIF_SPEC_IB (1 << TIF_SPEC_IB) diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h index 7365dd4acffb65..23baf8c9b34ca7 100644 --- a/arch/x86/include/asm/timer.h +++ b/arch/x86/include/asm/timer.h @@ -6,8 +6,6 @@ #include #include -#define TICK_SIZE (tick_nsec / 1000) - unsigned long long native_sched_clock(void); extern void recalibrate_cpu_khz(void); diff --git a/arch/x86/include/asm/tlb.h b/arch/x86/include/asm/tlb.h index 580636cdc257b7..4d3c9d00d6b6b2 100644 --- a/arch/x86/include/asm/tlb.h +++ b/arch/x86/include/asm/tlb.h @@ -34,4 +34,8 @@ static inline void __tlb_remove_table(void *table) free_page_and_swap_cache(table); } +static inline void invlpg(unsigned long addr) +{ + asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); +} #endif /* _ASM_X86_TLB_H */ diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 92f3664dd933b1..fd41103ad342c4 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -114,6 +114,12 @@ enum x86_topology_domains { TOPO_MAX_DOMAIN, }; +enum x86_topology_cpu_type { + TOPO_CPU_TYPE_PERFORMANCE, + TOPO_CPU_TYPE_EFFICIENCY, + TOPO_CPU_TYPE_UNKNOWN, +}; + struct x86_topology_system { unsigned int dom_shifts[TOPO_MAX_DOMAIN]; unsigned int dom_size[TOPO_MAX_DOMAIN]; @@ -149,6 +155,9 @@ extern unsigned int __max_threads_per_core; extern unsigned int __num_threads_per_package; extern unsigned int __num_cores_per_package; +const char *get_topology_cpu_type_name(struct cpuinfo_x86 *c); +enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c); + static inline unsigned int topology_max_packages(void) { return __max_logical_packages; diff --git a/arch/x86/include/asm/vdso/getrandom.h b/arch/x86/include/asm/vdso/getrandom.h index ff5334ad32a0f5..2bf9c0e970c3e7 100644 --- a/arch/x86/include/asm/vdso/getrandom.h +++ b/arch/x86/include/asm/vdso/getrandom.h @@ -8,7 +8,6 @@ #ifndef __ASSEMBLY__ #include -#include /** * getrandom_syscall - Invoke the getrandom() syscall. @@ -28,13 +27,14 @@ static __always_inline ssize_t getrandom_syscall(void *buffer, size_t len, unsig return ret; } -#define __vdso_rng_data (VVAR(_vdso_rng_data)) +extern struct vdso_rng_data vdso_rng_data + __attribute__((visibility("hidden"))); static __always_inline const struct vdso_rng_data *__arch_get_vdso_rng_data(void) { - if (IS_ENABLED(CONFIG_TIME_NS) && __vdso_data->clock_mode == VDSO_CLOCKMODE_TIMENS) - return (void *)&__vdso_rng_data + ((void *)&__timens_vdso_data - (void *)&__vdso_data); - return &__vdso_rng_data; + if (IS_ENABLED(CONFIG_TIME_NS) && __arch_get_vdso_data()->clock_mode == VDSO_CLOCKMODE_TIMENS) + return (void *)&vdso_rng_data + ((void *)&timens_page - (void *)__arch_get_vdso_data()); + return &vdso_rng_data; } #endif /* !__ASSEMBLY__ */ diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h index b2d2df026f6e70..375a34b0f36579 100644 --- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -14,14 +14,16 @@ #include #include -#include #include #include #include #include -#define __vdso_data (VVAR(_vdso_data)) -#define __timens_vdso_data (TIMENS(_vdso_data)) +extern struct vdso_data vvar_page + __attribute__((visibility("hidden"))); + +extern struct vdso_data timens_page + __attribute__((visibility("hidden"))); #define VDSO_HAS_TIME 1 @@ -61,7 +63,7 @@ extern struct ms_hyperv_tsc_page hvclock_page static __always_inline const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd) { - return __timens_vdso_data; + return &timens_page; } #endif @@ -275,7 +277,7 @@ static inline u64 __arch_get_hw_counter(s32 clock_mode, static __always_inline const struct vdso_data *__arch_get_vdso_data(void) { - return __vdso_data; + return &vvar_page; } static inline bool arch_vdso_clocksource_ok(const struct vdso_data *vd) diff --git a/arch/x86/include/asm/vdso/vsyscall.h b/arch/x86/include/asm/vdso/vsyscall.h index 67fedf1698b5e2..37b4a70559a822 100644 --- a/arch/x86/include/asm/vdso/vsyscall.h +++ b/arch/x86/include/asm/vdso/vsyscall.h @@ -2,12 +2,19 @@ #ifndef __ASM_VDSO_VSYSCALL_H #define __ASM_VDSO_VSYSCALL_H +#define __VDSO_RND_DATA_OFFSET 640 +#define __VVAR_PAGES 4 + +#define VDSO_NR_VCLOCK_PAGES 2 +#define VDSO_PAGE_PVCLOCK_OFFSET 0 +#define VDSO_PAGE_HVCLOCK_OFFSET 1 + #ifndef __ASSEMBLY__ -#include #include #include -#include + +extern struct vdso_data *vdso_data; /* * Update the vDSO data page to keep in sync with kernel timekeeping. @@ -15,14 +22,14 @@ static __always_inline struct vdso_data *__x86_get_k_vdso_data(void) { - return _vdso_data; + return vdso_data; } #define __arch_get_k_vdso_data __x86_get_k_vdso_data static __always_inline struct vdso_rng_data *__x86_get_k_vdso_rng_data(void) { - return &_vdso_rng_data; + return (void *)vdso_data + __VDSO_RND_DATA_OFFSET; } #define __arch_get_k_vdso_rng_data __x86_get_k_vdso_rng_data diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h deleted file mode 100644 index 9d9af37f7cab9e..00000000000000 --- a/arch/x86/include/asm/vvar.h +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vvar.h: Shared vDSO/kernel variable declarations - * Copyright (c) 2011 Andy Lutomirski - * - * A handful of variables are accessible (read-only) from userspace - * code in the vsyscall page and the vdso. They are declared here. - * Some other file must define them with DEFINE_VVAR. - * - * In normal kernel code, they are used like any other variable. - * In user code, they are accessed through the VVAR macro. - * - * These variables live in a page of kernel data that has an extra RO - * mapping for userspace. Each variable needs a unique offset within - * that page; specify that offset with the DECLARE_VVAR macro. (If - * you mess up, the linker will catch it.) - */ - -#ifndef _ASM_X86_VVAR_H -#define _ASM_X86_VVAR_H - -#ifdef EMIT_VVAR -/* - * EMIT_VVAR() is used by the kernel linker script to put vvars in the - * right place. Also, it's used by kernel code to import offsets values. - */ -#define DECLARE_VVAR(offset, type, name) \ - EMIT_VVAR(name, offset) -#define DECLARE_VVAR_SINGLE(offset, type, name) \ - EMIT_VVAR(name, offset) - -#else - -extern char __vvar_page; - -#define DECLARE_VVAR(offset, type, name) \ - extern type vvar_ ## name[CS_BASES] \ - __attribute__((visibility("hidden"))); \ - extern type timens_ ## name[CS_BASES] \ - __attribute__((visibility("hidden"))); \ - -#define DECLARE_VVAR_SINGLE(offset, type, name) \ - extern type vvar_ ## name \ - __attribute__((visibility("hidden"))); \ - -#define VVAR(name) (vvar_ ## name) -#define TIMENS(name) (timens_ ## name) - -#define DEFINE_VVAR(type, name) \ - type name[CS_BASES] \ - __attribute__((section(".vvar_" #name), aligned(16))) __visible - -#define DEFINE_VVAR_SINGLE(type, name) \ - type name \ - __attribute__((section(".vvar_" #name), aligned(16))) __visible - -#endif - -/* DECLARE_VVAR(offset, type, name) */ - -DECLARE_VVAR(128, struct vdso_data, _vdso_data) - -#if !defined(_SINGLE_DATA) -#define _SINGLE_DATA -DECLARE_VVAR_SINGLE(640, struct vdso_rng_data, _vdso_rng_data) -#endif - -#undef DECLARE_VVAR -#undef DECLARE_VVAR_SINGLE - -#endif diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h index a2dd24947eb85a..97771b9d33af30 100644 --- a/arch/x86/include/asm/xen/hypercall.h +++ b/arch/x86/include/asm/xen/hypercall.h @@ -39,9 +39,11 @@ #include #include #include +#include #include +#include #include #include #include @@ -86,11 +88,20 @@ struct xen_dm_op_buf; * there aren't more than 5 arguments...) */ -extern struct { char _entry[32]; } hypercall_page[]; +void xen_hypercall_func(void); +DECLARE_STATIC_CALL(xen_hypercall, xen_hypercall_func); -#define __HYPERCALL "call hypercall_page+%c[offset]" -#define __HYPERCALL_ENTRY(x) \ - [offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0])) +#ifdef MODULE +#define __ADDRESSABLE_xen_hypercall +#else +#define __ADDRESSABLE_xen_hypercall __ADDRESSABLE_ASM_STR(__SCK__xen_hypercall) +#endif + +#define __HYPERCALL \ + __ADDRESSABLE_xen_hypercall \ + "call __SCT__xen_hypercall" + +#define __HYPERCALL_ENTRY(x) "a" (x) #ifdef CONFIG_X86_32 #define __HYPERCALL_RETREG "eax" @@ -148,7 +159,7 @@ extern struct { char _entry[32]; } hypercall_page[]; __HYPERCALL_0ARG(); \ asm volatile (__HYPERCALL \ : __HYPERCALL_0PARAM \ - : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ : __HYPERCALL_CLOBBER0); \ (type)__res; \ }) @@ -159,7 +170,7 @@ extern struct { char _entry[32]; } hypercall_page[]; __HYPERCALL_1ARG(a1); \ asm volatile (__HYPERCALL \ : __HYPERCALL_1PARAM \ - : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ : __HYPERCALL_CLOBBER1); \ (type)__res; \ }) @@ -170,7 +181,7 @@ extern struct { char _entry[32]; } hypercall_page[]; __HYPERCALL_2ARG(a1, a2); \ asm volatile (__HYPERCALL \ : __HYPERCALL_2PARAM \ - : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ : __HYPERCALL_CLOBBER2); \ (type)__res; \ }) @@ -181,7 +192,7 @@ extern struct { char _entry[32]; } hypercall_page[]; __HYPERCALL_3ARG(a1, a2, a3); \ asm volatile (__HYPERCALL \ : __HYPERCALL_3PARAM \ - : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ : __HYPERCALL_CLOBBER3); \ (type)__res; \ }) @@ -192,7 +203,7 @@ extern struct { char _entry[32]; } hypercall_page[]; __HYPERCALL_4ARG(a1, a2, a3, a4); \ asm volatile (__HYPERCALL \ : __HYPERCALL_4PARAM \ - : __HYPERCALL_ENTRY(name) \ + : __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \ : __HYPERCALL_CLOBBER4); \ (type)__res; \ }) @@ -206,12 +217,9 @@ xen_single_call(unsigned int call, __HYPERCALL_DECLS; __HYPERCALL_5ARG(a1, a2, a3, a4, a5); - if (call >= PAGE_SIZE / sizeof(hypercall_page[0])) - return -EINVAL; - - asm volatile(CALL_NOSPEC + asm volatile(__HYPERCALL : __HYPERCALL_5PARAM - : [thunk_target] "a" (&hypercall_page[call]) + : __HYPERCALL_ENTRY(call) : __HYPERCALL_CLOBBER5); return (long)__res; diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h index e5d182c7373c8e..4a7cace0620429 100644 --- a/arch/x86/include/uapi/asm/amd_hsmp.h +++ b/arch/x86/include/uapi/asm/amd_hsmp.h @@ -88,7 +88,8 @@ struct hsmp_msg_desc { * * Not supported messages would return -ENOMSG. */ -static const struct hsmp_msg_desc hsmp_msg_desc_table[] = { +static const struct hsmp_msg_desc hsmp_msg_desc_table[] + __attribute__((unused)) = { /* RESERVED */ {0, 0, HSMP_RSVD}, diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index a8debbf2f70280..88585c1de416fa 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -440,6 +440,7 @@ struct kvm_sync_regs { #define KVM_X86_QUIRK_FIX_HYPERCALL_INSN (1 << 5) #define KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS (1 << 6) #define KVM_X86_QUIRK_SLOT_ZAP_ALL (1 << 7) +#define KVM_X86_QUIRK_STUFF_FEATURE_MSRS (1 << 8) #define KVM_STATE_NESTED_FORMAT_VMX 0 #define KVM_STATE_NESTED_FORMAT_SVM 1 diff --git a/arch/x86/include/uapi/asm/mce.h b/arch/x86/include/uapi/asm/mce.h index db9adc081c5af3..cb6b48a7c22b41 100644 --- a/arch/x86/include/uapi/asm/mce.h +++ b/arch/x86/include/uapi/asm/mce.h @@ -8,7 +8,8 @@ /* * Fields are zero when not available. Also, this struct is shared with * userspace mcelog and thus must keep existing fields at current offsets. - * Only add new fields to the end of the structure + * Only add new, shared fields to the end of the structure. + * Do not add vendor-specific fields. */ struct mce { __u64 status; /* Bank's MCi_STATUS MSR */ diff --git a/arch/x86/include/uapi/asm/mman.h b/arch/x86/include/uapi/asm/mman.h index 46cdc941f9586a..ac1e6277212b90 100644 --- a/arch/x86/include/uapi/asm/mman.h +++ b/arch/x86/include/uapi/asm/mman.h @@ -5,9 +5,6 @@ #define MAP_32BIT 0x40 /* only give out 32bit addresses */ #define MAP_ABOVE4G 0x80 /* only map above 4GB */ -/* Flags for map_shadow_stack(2) */ -#define SHADOW_STACK_SET_TOKEN (1ULL << 0) /* Set up a restore token in the shadow stack */ - #include #endif /* _ASM_X86_MMAN_H */ diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 4efecac49863ec..3a44a9dc3fb7ae 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1171,7 +1171,8 @@ static int __init acpi_parse_madt_ioapic_entries(void) } count = acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, - acpi_parse_int_src_ovr, nr_irqs); + acpi_parse_int_src_ovr, + irq_get_nr_irqs()); if (count < 0) { pr_err("Error parsing interrupt source overrides entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -1191,7 +1192,8 @@ static int __init acpi_parse_madt_ioapic_entries(void) mp_config_acpi_legacy_irqs(); count = acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, - acpi_parse_nmi_src, nr_irqs); + acpi_parse_nmi_src, + irq_get_nr_irqs()); if (count < 0) { pr_err("Error parsing NMI SRC entry\n"); /* TBD: Cleanup to allow fallback to MPS */ diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c index aab9d0570841a8..d745dd586303cc 100644 --- a/arch/x86/kernel/acpi/cppc.c +++ b/arch/x86/kernel/acpi/cppc.c @@ -239,8 +239,10 @@ EXPORT_SYMBOL_GPL(amd_detect_prefcore); */ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator) { + enum x86_topology_cpu_type core_type = get_topology_cpu_type(&cpu_data(cpu)); bool prefcore; int ret; + u32 tmp; ret = amd_detect_prefcore(&prefcore); if (ret) @@ -266,6 +268,27 @@ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator) break; } } + + /* detect if running on heterogeneous design */ + if (cpu_feature_enabled(X86_FEATURE_AMD_HETEROGENEOUS_CORES)) { + switch (core_type) { + case TOPO_CPU_TYPE_UNKNOWN: + pr_warn("Undefined core type found for cpu %d\n", cpu); + break; + case TOPO_CPU_TYPE_PERFORMANCE: + /* use the max scale for performance cores */ + *numerator = CPPC_HIGHEST_PERF_PERFORMANCE; + return 0; + case TOPO_CPU_TYPE_EFFICIENCY: + /* use the highest perf value for efficiency cores */ + ret = amd_get_highest_perf(cpu, &tmp); + if (ret) + return ret; + *numerator = tmp; + return 0; + } + } + *numerator = CPPC_HIGHEST_PERF_PREFCORE; return 0; diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 94ff83f3d3fe92..b200a193beeb35 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S @@ -87,6 +87,7 @@ SYM_FUNC_START(do_suspend_lowlevel) .align 4 .Lresume_point: + ANNOTATE_NOENDBR /* We don't restore %rax, it must be 0 anyway */ movq $saved_context, %rax movq saved_context_cr4(%rax), %rbx diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index d17518ca19b8b8..243843e44e89d8 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -392,8 +392,10 @@ EXPORT_SYMBOL(BUG_func); * Rewrite the "call BUG_func" replacement to point to the target of the * indirect pv_ops call "call *disp(%ip)". */ -static int alt_replace_call(u8 *instr, u8 *insn_buff, struct alt_instr *a) +static int alt_replace_call(u8 *instr, u8 *insn_buff, struct alt_instr *a, + struct module *mod) { + u8 *wr_instr = module_writable_address(mod, instr); void *target, *bug = &BUG_func; s32 disp; @@ -403,14 +405,14 @@ static int alt_replace_call(u8 *instr, u8 *insn_buff, struct alt_instr *a) } if (a->instrlen != 6 || - instr[0] != CALL_RIP_REL_OPCODE || - instr[1] != CALL_RIP_REL_MODRM) { + wr_instr[0] != CALL_RIP_REL_OPCODE || + wr_instr[1] != CALL_RIP_REL_MODRM) { pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n"); BUG(); } /* Skip CALL_RIP_REL_OPCODE and CALL_RIP_REL_MODRM */ - disp = *(s32 *)(instr + 2); + disp = *(s32 *)(wr_instr + 2); #ifdef CONFIG_X86_64 /* ff 15 00 00 00 00 call *0x0(%rip) */ /* target address is stored at "next instruction + disp". */ @@ -448,7 +450,8 @@ static inline u8 * instr_va(struct alt_instr *i) * to refetch changed I$ lines. */ void __init_or_module noinline apply_alternatives(struct alt_instr *start, - struct alt_instr *end) + struct alt_instr *end, + struct module *mod) { u8 insn_buff[MAX_PATCH_LEN]; u8 *instr, *replacement; @@ -477,6 +480,7 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, */ for (a = start; a < end; a++) { int insn_buff_sz = 0; + u8 *wr_instr, *wr_replacement; /* * In case of nested ALTERNATIVE()s the outer alternative might @@ -490,7 +494,11 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, } instr = instr_va(a); + wr_instr = module_writable_address(mod, instr); + replacement = (u8 *)&a->repl_offset + a->repl_offset; + wr_replacement = module_writable_address(mod, replacement); + BUG_ON(a->instrlen > sizeof(insn_buff)); BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32); @@ -501,9 +509,9 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, * patch if feature is *NOT* present. */ if (!boot_cpu_has(a->cpuid) == !(a->flags & ALT_FLAG_NOT)) { - memcpy(insn_buff, instr, a->instrlen); + memcpy(insn_buff, wr_instr, a->instrlen); optimize_nops(instr, insn_buff, a->instrlen); - text_poke_early(instr, insn_buff, a->instrlen); + text_poke_early(wr_instr, insn_buff, a->instrlen); continue; } @@ -513,11 +521,12 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, instr, instr, a->instrlen, replacement, a->replacementlen, a->flags); - memcpy(insn_buff, replacement, a->replacementlen); + memcpy(insn_buff, wr_replacement, a->replacementlen); insn_buff_sz = a->replacementlen; if (a->flags & ALT_FLAG_DIRECT_CALL) { - insn_buff_sz = alt_replace_call(instr, insn_buff, a); + insn_buff_sz = alt_replace_call(instr, insn_buff, a, + mod); if (insn_buff_sz < 0) continue; } @@ -527,11 +536,11 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, apply_relocation(insn_buff, instr, a->instrlen, replacement, a->replacementlen); - DUMP_BYTES(ALT, instr, a->instrlen, "%px: old_insn: ", instr); + DUMP_BYTES(ALT, wr_instr, a->instrlen, "%px: old_insn: ", instr); DUMP_BYTES(ALT, replacement, a->replacementlen, "%px: rpl_insn: ", replacement); DUMP_BYTES(ALT, insn_buff, insn_buff_sz, "%px: final_insn: ", instr); - text_poke_early(instr, insn_buff, insn_buff_sz); + text_poke_early(wr_instr, insn_buff, insn_buff_sz); } kasan_enable_current(); @@ -722,18 +731,20 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes) /* * Generated by 'objtool --retpoline'. */ -void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) +void __init_or_module noinline apply_retpolines(s32 *start, s32 *end, + struct module *mod) { s32 *s; for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr = module_writable_address(mod, addr); struct insn insn; int len, ret; u8 bytes[16]; u8 op1, op2; - ret = insn_decode_kernel(&insn, addr); + ret = insn_decode_kernel(&insn, wr_addr); if (WARN_ON_ONCE(ret < 0)) continue; @@ -761,9 +772,9 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) len = patch_retpoline(addr, &insn, bytes); if (len == insn.length) { optimize_nops(addr, bytes, len); - DUMP_BYTES(RETPOLINE, ((u8*)addr), len, "%px: orig: ", addr); + DUMP_BYTES(RETPOLINE, ((u8*)wr_addr), len, "%px: orig: ", addr); DUMP_BYTES(RETPOLINE, ((u8*)bytes), len, "%px: repl: ", addr); - text_poke_early(addr, bytes, len); + text_poke_early(wr_addr, bytes, len); } } } @@ -799,7 +810,8 @@ static int patch_return(void *addr, struct insn *insn, u8 *bytes) return i; } -void __init_or_module noinline apply_returns(s32 *start, s32 *end) +void __init_or_module noinline apply_returns(s32 *start, s32 *end, + struct module *mod) { s32 *s; @@ -808,12 +820,13 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end) for (s = start; s < end; s++) { void *dest = NULL, *addr = (void *)s + *s; + void *wr_addr = module_writable_address(mod, addr); struct insn insn; int len, ret; u8 bytes[16]; u8 op; - ret = insn_decode_kernel(&insn, addr); + ret = insn_decode_kernel(&insn, wr_addr); if (WARN_ON_ONCE(ret < 0)) continue; @@ -833,32 +846,35 @@ void __init_or_module noinline apply_returns(s32 *start, s32 *end) len = patch_return(addr, &insn, bytes); if (len == insn.length) { - DUMP_BYTES(RET, ((u8*)addr), len, "%px: orig: ", addr); + DUMP_BYTES(RET, ((u8*)wr_addr), len, "%px: orig: ", addr); DUMP_BYTES(RET, ((u8*)bytes), len, "%px: repl: ", addr); - text_poke_early(addr, bytes, len); + text_poke_early(wr_addr, bytes, len); } } } #else -void __init_or_module noinline apply_returns(s32 *start, s32 *end) { } +void __init_or_module noinline apply_returns(s32 *start, s32 *end, + struct module *mod) { } #endif /* CONFIG_MITIGATION_RETHUNK */ #else /* !CONFIG_MITIGATION_RETPOLINE || !CONFIG_OBJTOOL */ -void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { } -void __init_or_module noinline apply_returns(s32 *start, s32 *end) { } +void __init_or_module noinline apply_retpolines(s32 *start, s32 *end, + struct module *mod) { } +void __init_or_module noinline apply_returns(s32 *start, s32 *end, + struct module *mod) { } #endif /* CONFIG_MITIGATION_RETPOLINE && CONFIG_OBJTOOL */ #ifdef CONFIG_X86_KERNEL_IBT -static void poison_cfi(void *addr); +static void poison_cfi(void *addr, void *wr_addr); -static void __init_or_module poison_endbr(void *addr, bool warn) +static void __init_or_module poison_endbr(void *addr, void *wr_addr, bool warn) { u32 endbr, poison = gen_endbr_poison(); - if (WARN_ON_ONCE(get_kernel_nofault(endbr, addr))) + if (WARN_ON_ONCE(get_kernel_nofault(endbr, wr_addr))) return; if (!is_endbr(endbr)) { @@ -873,7 +889,7 @@ static void __init_or_module poison_endbr(void *addr, bool warn) */ DUMP_BYTES(ENDBR, ((u8*)addr), 4, "%px: orig: ", addr); DUMP_BYTES(ENDBR, ((u8*)&poison), 4, "%px: repl: ", addr); - text_poke_early(addr, &poison, 4); + text_poke_early(wr_addr, &poison, 4); } /* @@ -882,22 +898,23 @@ static void __init_or_module poison_endbr(void *addr, bool warn) * Seal the functions for indirect calls by clobbering the ENDBR instructions * and the kCFI hash value. */ -void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end) +void __init_or_module noinline apply_seal_endbr(s32 *start, s32 *end, struct module *mod) { s32 *s; for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr = module_writable_address(mod, addr); - poison_endbr(addr, true); + poison_endbr(addr, wr_addr, true); if (IS_ENABLED(CONFIG_FINEIBT)) - poison_cfi(addr - 16); + poison_cfi(addr - 16, wr_addr - 16); } } #else -void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { } +void __init_or_module apply_seal_endbr(s32 *start, s32 *end, struct module *mod) { } #endif /* CONFIG_X86_KERNEL_IBT */ @@ -1119,7 +1136,7 @@ static u32 decode_caller_hash(void *addr) } /* .retpoline_sites */ -static int cfi_disable_callers(s32 *start, s32 *end) +static int cfi_disable_callers(s32 *start, s32 *end, struct module *mod) { /* * Disable kCFI by patching in a JMP.d8, this leaves the hash immediate @@ -1131,20 +1148,23 @@ static int cfi_disable_callers(s32 *start, s32 *end) for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr; u32 hash; addr -= fineibt_caller_size; - hash = decode_caller_hash(addr); + wr_addr = module_writable_address(mod, addr); + hash = decode_caller_hash(wr_addr); + if (!hash) /* nocfi callers */ continue; - text_poke_early(addr, jmp, 2); + text_poke_early(wr_addr, jmp, 2); } return 0; } -static int cfi_enable_callers(s32 *start, s32 *end) +static int cfi_enable_callers(s32 *start, s32 *end, struct module *mod) { /* * Re-enable kCFI, undo what cfi_disable_callers() did. @@ -1154,106 +1174,115 @@ static int cfi_enable_callers(s32 *start, s32 *end) for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr; u32 hash; addr -= fineibt_caller_size; - hash = decode_caller_hash(addr); + wr_addr = module_writable_address(mod, addr); + hash = decode_caller_hash(wr_addr); if (!hash) /* nocfi callers */ continue; - text_poke_early(addr, mov, 2); + text_poke_early(wr_addr, mov, 2); } return 0; } /* .cfi_sites */ -static int cfi_rand_preamble(s32 *start, s32 *end) +static int cfi_rand_preamble(s32 *start, s32 *end, struct module *mod) { s32 *s; for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr = module_writable_address(mod, addr); u32 hash; - hash = decode_preamble_hash(addr); + hash = decode_preamble_hash(wr_addr); if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n", addr, addr, 5, addr)) return -EINVAL; hash = cfi_rehash(hash); - text_poke_early(addr + 1, &hash, 4); + text_poke_early(wr_addr + 1, &hash, 4); } return 0; } -static int cfi_rewrite_preamble(s32 *start, s32 *end) +static int cfi_rewrite_preamble(s32 *start, s32 *end, struct module *mod) { s32 *s; for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr = module_writable_address(mod, addr); u32 hash; - hash = decode_preamble_hash(addr); + hash = decode_preamble_hash(wr_addr); if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n", addr, addr, 5, addr)) return -EINVAL; - text_poke_early(addr, fineibt_preamble_start, fineibt_preamble_size); - WARN_ON(*(u32 *)(addr + fineibt_preamble_hash) != 0x12345678); - text_poke_early(addr + fineibt_preamble_hash, &hash, 4); + text_poke_early(wr_addr, fineibt_preamble_start, fineibt_preamble_size); + WARN_ON(*(u32 *)(wr_addr + fineibt_preamble_hash) != 0x12345678); + text_poke_early(wr_addr + fineibt_preamble_hash, &hash, 4); } return 0; } -static void cfi_rewrite_endbr(s32 *start, s32 *end) +static void cfi_rewrite_endbr(s32 *start, s32 *end, struct module *mod) { s32 *s; for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr = module_writable_address(mod, addr); - poison_endbr(addr+16, false); + poison_endbr(addr + 16, wr_addr + 16, false); } } /* .retpoline_sites */ -static int cfi_rand_callers(s32 *start, s32 *end) +static int cfi_rand_callers(s32 *start, s32 *end, struct module *mod) { s32 *s; for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr; u32 hash; addr -= fineibt_caller_size; - hash = decode_caller_hash(addr); + wr_addr = module_writable_address(mod, addr); + hash = decode_caller_hash(wr_addr); if (hash) { hash = -cfi_rehash(hash); - text_poke_early(addr + 2, &hash, 4); + text_poke_early(wr_addr + 2, &hash, 4); } } return 0; } -static int cfi_rewrite_callers(s32 *start, s32 *end) +static int cfi_rewrite_callers(s32 *start, s32 *end, struct module *mod) { s32 *s; for (s = start; s < end; s++) { void *addr = (void *)s + *s; + void *wr_addr; u32 hash; addr -= fineibt_caller_size; - hash = decode_caller_hash(addr); + wr_addr = module_writable_address(mod, addr); + hash = decode_caller_hash(wr_addr); if (hash) { - text_poke_early(addr, fineibt_caller_start, fineibt_caller_size); - WARN_ON(*(u32 *)(addr + fineibt_caller_hash) != 0x12345678); - text_poke_early(addr + fineibt_caller_hash, &hash, 4); + text_poke_early(wr_addr, fineibt_caller_start, fineibt_caller_size); + WARN_ON(*(u32 *)(wr_addr + fineibt_caller_hash) != 0x12345678); + text_poke_early(wr_addr + fineibt_caller_hash, &hash, 4); } /* rely on apply_retpolines() */ } @@ -1262,8 +1291,9 @@ static int cfi_rewrite_callers(s32 *start, s32 *end) } static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, - s32 *start_cfi, s32 *end_cfi, bool builtin) + s32 *start_cfi, s32 *end_cfi, struct module *mod) { + bool builtin = mod ? false : true; int ret; if (WARN_ONCE(fineibt_preamble_size != 16, @@ -1281,7 +1311,7 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, * rewrite them. This disables all CFI. If this succeeds but any of the * later stages fails, we're without CFI. */ - ret = cfi_disable_callers(start_retpoline, end_retpoline); + ret = cfi_disable_callers(start_retpoline, end_retpoline, mod); if (ret) goto err; @@ -1292,11 +1322,11 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, cfi_bpf_subprog_hash = cfi_rehash(cfi_bpf_subprog_hash); } - ret = cfi_rand_preamble(start_cfi, end_cfi); + ret = cfi_rand_preamble(start_cfi, end_cfi, mod); if (ret) goto err; - ret = cfi_rand_callers(start_retpoline, end_retpoline); + ret = cfi_rand_callers(start_retpoline, end_retpoline, mod); if (ret) goto err; } @@ -1308,7 +1338,7 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, return; case CFI_KCFI: - ret = cfi_enable_callers(start_retpoline, end_retpoline); + ret = cfi_enable_callers(start_retpoline, end_retpoline, mod); if (ret) goto err; @@ -1318,17 +1348,17 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, case CFI_FINEIBT: /* place the FineIBT preamble at func()-16 */ - ret = cfi_rewrite_preamble(start_cfi, end_cfi); + ret = cfi_rewrite_preamble(start_cfi, end_cfi, mod); if (ret) goto err; /* rewrite the callers to target func()-16 */ - ret = cfi_rewrite_callers(start_retpoline, end_retpoline); + ret = cfi_rewrite_callers(start_retpoline, end_retpoline, mod); if (ret) goto err; /* now that nobody targets func()+0, remove ENDBR there */ - cfi_rewrite_endbr(start_cfi, end_cfi); + cfi_rewrite_endbr(start_cfi, end_cfi, mod); if (builtin) pr_info("Using FineIBT CFI\n"); @@ -1347,7 +1377,7 @@ static inline void poison_hash(void *addr) *(u32 *)addr = 0; } -static void poison_cfi(void *addr) +static void poison_cfi(void *addr, void *wr_addr) { switch (cfi_mode) { case CFI_FINEIBT: @@ -1359,8 +1389,8 @@ static void poison_cfi(void *addr) * ud2 * 1: nop */ - poison_endbr(addr, false); - poison_hash(addr + fineibt_preamble_hash); + poison_endbr(addr, wr_addr, false); + poison_hash(wr_addr + fineibt_preamble_hash); break; case CFI_KCFI: @@ -1369,7 +1399,7 @@ static void poison_cfi(void *addr) * movl $0, %eax * .skip 11, 0x90 */ - poison_hash(addr + 1); + poison_hash(wr_addr + 1); break; default: @@ -1380,22 +1410,21 @@ static void poison_cfi(void *addr) #else static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, - s32 *start_cfi, s32 *end_cfi, bool builtin) + s32 *start_cfi, s32 *end_cfi, struct module *mod) { } #ifdef CONFIG_X86_KERNEL_IBT -static void poison_cfi(void *addr) { } +static void poison_cfi(void *addr, void *wr_addr) { } #endif #endif void apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, - s32 *start_cfi, s32 *end_cfi) + s32 *start_cfi, s32 *end_cfi, struct module *mod) { return __apply_fineibt(start_retpoline, end_retpoline, - start_cfi, end_cfi, - /* .builtin = */ false); + start_cfi, end_cfi, mod); } #ifdef CONFIG_SMP @@ -1692,16 +1721,16 @@ void __init alternative_instructions(void) paravirt_set_cap(); __apply_fineibt(__retpoline_sites, __retpoline_sites_end, - __cfi_sites, __cfi_sites_end, true); + __cfi_sites, __cfi_sites_end, NULL); /* * Rewrite the retpolines, must be done before alternatives since * those can rewrite the retpoline thunks. */ - apply_retpolines(__retpoline_sites, __retpoline_sites_end); - apply_returns(__return_sites, __return_sites_end); + apply_retpolines(__retpoline_sites, __retpoline_sites_end, NULL); + apply_returns(__return_sites, __return_sites_end, NULL); - apply_alternatives(__alt_instructions, __alt_instructions_end); + apply_alternatives(__alt_instructions, __alt_instructions_end, NULL); /* * Now all calls are established. Apply the call thunks if @@ -1712,7 +1741,7 @@ void __init alternative_instructions(void) /* * Seal all functions that do not have their address taken. */ - apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end); + apply_seal_endbr(__ibt_endbr_seal, __ibt_endbr_seal_end, NULL); #ifdef CONFIG_SMP /* Patch to UP if other cpus not imminent. */ diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 557318145038ec..736f62812f5c2b 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -712,8 +712,8 @@ int __init arch_probe_nr_irqs(void) { int nr; - if (nr_irqs > (NR_VECTORS * nr_cpu_ids)) - nr_irqs = NR_VECTORS * nr_cpu_ids; + if (irq_get_nr_irqs() > NR_VECTORS * nr_cpu_ids) + irq_set_nr_irqs(NR_VECTORS * nr_cpu_ids); nr = (gsi_top + nr_legacy_irqs()) + 8 * nr_cpu_ids; #if defined(CONFIG_PCI_MSI) @@ -725,8 +725,8 @@ int __init arch_probe_nr_irqs(void) else nr += gsi_top * 16; #endif - if (nr < nr_irqs) - nr_irqs = nr; + if (nr < irq_get_nr_irqs()) + irq_set_nr_irqs(nr); /* * We don't know if PIC is present at this point so we need to do diff --git a/arch/x86/kernel/callthunks.c b/arch/x86/kernel/callthunks.c index 4656474567533b..f17d166078823c 100644 --- a/arch/x86/kernel/callthunks.c +++ b/arch/x86/kernel/callthunks.c @@ -142,11 +142,6 @@ static bool skip_addr(void *dest) if (dest >= (void *)relocate_kernel && dest < (void*)relocate_kernel + KEXEC_CONTROL_CODE_MAX_SIZE) return true; -#endif -#ifdef CONFIG_XEN - if (dest >= (void *)hypercall_page && - dest < (void*)hypercall_page + PAGE_SIZE) - return true; #endif return false; } diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 5857a0f5d51404..4efdf5c2efc8a5 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -59,6 +59,8 @@ obj-$(CONFIG_ACRN_GUEST) += acrn.o obj-$(CONFIG_DEBUG_FS) += debugfs.o +obj-$(CONFIG_X86_BUS_LOCK_DETECT) += bus_lock.o + quiet_cmd_mkcapflags = MKCAP $@ cmd_mkcapflags = $(CONFIG_SHELL) $(src)/mkcapflags.sh $@ $^ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 823f44f7bc9465..79d2e17f6582e9 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -798,6 +798,7 @@ static void init_amd_bd(struct cpuinfo_x86 *c) static const struct x86_cpu_desc erratum_1386_microcode[] = { AMD_CPU_DESC(0x17, 0x1, 0x2, 0x0800126e), AMD_CPU_DESC(0x17, 0x31, 0x0, 0x08301052), + {}, }; static void fix_erratum_1386(struct cpuinfo_x86 *c) @@ -1064,7 +1065,7 @@ static void init_amd(struct cpuinfo_x86 *c) */ if (spectre_v2_in_eibrs_mode(spectre_v2_enabled) && cpu_has(c, X86_FEATURE_AUTOIBRS)) - WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS)); + WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS) < 0); /* AMD CPUs don't need fencing after x2APIC/TSC_DEADLINE MSR writes. */ clear_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); diff --git a/arch/x86/kernel/cpu/bus_lock.c b/arch/x86/kernel/cpu/bus_lock.c new file mode 100644 index 00000000000000..704e9241b96404 --- /dev/null +++ b/arch/x86/kernel/cpu/bus_lock.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define pr_fmt(fmt) "x86/split lock detection: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +enum split_lock_detect_state { + sld_off = 0, + sld_warn, + sld_fatal, + sld_ratelimit, +}; + +/* + * Default to sld_off because most systems do not support split lock detection. + * sld_state_setup() will switch this to sld_warn on systems that support + * split lock/bus lock detect, unless there is a command line override. + */ +static enum split_lock_detect_state sld_state __ro_after_init = sld_off; +static u64 msr_test_ctrl_cache __ro_after_init; + +/* + * With a name like MSR_TEST_CTL it should go without saying, but don't touch + * MSR_TEST_CTL unless the CPU is one of the whitelisted models. Writing it + * on CPUs that do not support SLD can cause fireworks, even when writing '0'. + */ +static bool cpu_model_supports_sld __ro_after_init; + +static const struct { + const char *option; + enum split_lock_detect_state state; +} sld_options[] __initconst = { + { "off", sld_off }, + { "warn", sld_warn }, + { "fatal", sld_fatal }, + { "ratelimit:", sld_ratelimit }, +}; + +static struct ratelimit_state bld_ratelimit; + +static unsigned int sysctl_sld_mitigate = 1; +static DEFINE_SEMAPHORE(buslock_sem, 1); + +#ifdef CONFIG_PROC_SYSCTL +static struct ctl_table sld_sysctls[] = { + { + .procname = "split_lock_mitigate", + .data = &sysctl_sld_mitigate, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, +}; + +static int __init sld_mitigate_sysctl_init(void) +{ + register_sysctl_init("kernel", sld_sysctls); + return 0; +} + +late_initcall(sld_mitigate_sysctl_init); +#endif + +static inline bool match_option(const char *arg, int arglen, const char *opt) +{ + int len = strlen(opt), ratelimit; + + if (strncmp(arg, opt, len)) + return false; + + /* + * Min ratelimit is 1 bus lock/sec. + * Max ratelimit is 1000 bus locks/sec. + */ + if (sscanf(arg, "ratelimit:%d", &ratelimit) == 1 && + ratelimit > 0 && ratelimit <= 1000) { + ratelimit_state_init(&bld_ratelimit, HZ, ratelimit); + ratelimit_set_flags(&bld_ratelimit, RATELIMIT_MSG_ON_RELEASE); + return true; + } + + return len == arglen; +} + +static bool split_lock_verify_msr(bool on) +{ + u64 ctrl, tmp; + + if (rdmsrl_safe(MSR_TEST_CTRL, &ctrl)) + return false; + if (on) + ctrl |= MSR_TEST_CTRL_SPLIT_LOCK_DETECT; + else + ctrl &= ~MSR_TEST_CTRL_SPLIT_LOCK_DETECT; + if (wrmsrl_safe(MSR_TEST_CTRL, ctrl)) + return false; + rdmsrl(MSR_TEST_CTRL, tmp); + return ctrl == tmp; +} + +static void __init sld_state_setup(void) +{ + enum split_lock_detect_state state = sld_warn; + char arg[20]; + int i, ret; + + if (!boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) && + !boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) + return; + + ret = cmdline_find_option(boot_command_line, "split_lock_detect", + arg, sizeof(arg)); + if (ret >= 0) { + for (i = 0; i < ARRAY_SIZE(sld_options); i++) { + if (match_option(arg, ret, sld_options[i].option)) { + state = sld_options[i].state; + break; + } + } + } + sld_state = state; +} + +static void __init __split_lock_setup(void) +{ + if (!split_lock_verify_msr(false)) { + pr_info("MSR access failed: Disabled\n"); + return; + } + + rdmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache); + + if (!split_lock_verify_msr(true)) { + pr_info("MSR access failed: Disabled\n"); + return; + } + + /* Restore the MSR to its cached value. */ + wrmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache); + + setup_force_cpu_cap(X86_FEATURE_SPLIT_LOCK_DETECT); +} + +/* + * MSR_TEST_CTRL is per core, but we treat it like a per CPU MSR. Locking + * is not implemented as one thread could undo the setting of the other + * thread immediately after dropping the lock anyway. + */ +static void sld_update_msr(bool on) +{ + u64 test_ctrl_val = msr_test_ctrl_cache; + + if (on) + test_ctrl_val |= MSR_TEST_CTRL_SPLIT_LOCK_DETECT; + + wrmsrl(MSR_TEST_CTRL, test_ctrl_val); +} + +void split_lock_init(void) +{ + /* + * #DB for bus lock handles ratelimit and #AC for split lock is + * disabled. + */ + if (sld_state == sld_ratelimit) { + split_lock_verify_msr(false); + return; + } + + if (cpu_model_supports_sld) + split_lock_verify_msr(sld_state != sld_off); +} + +static void __split_lock_reenable_unlock(struct work_struct *work) +{ + sld_update_msr(true); + up(&buslock_sem); +} + +static DECLARE_DELAYED_WORK(sl_reenable_unlock, __split_lock_reenable_unlock); + +static void __split_lock_reenable(struct work_struct *work) +{ + sld_update_msr(true); +} +static DECLARE_DELAYED_WORK(sl_reenable, __split_lock_reenable); + +/* + * If a CPU goes offline with pending delayed work to re-enable split lock + * detection then the delayed work will be executed on some other CPU. That + * handles releasing the buslock_sem, but because it executes on a + * different CPU probably won't re-enable split lock detection. This is a + * problem on HT systems since the sibling CPU on the same core may then be + * left running with split lock detection disabled. + * + * Unconditionally re-enable detection here. + */ +static int splitlock_cpu_offline(unsigned int cpu) +{ + sld_update_msr(true); + + return 0; +} + +static void split_lock_warn(unsigned long ip) +{ + struct delayed_work *work; + int cpu; + + if (!current->reported_split_lock) + pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n", + current->comm, current->pid, ip); + current->reported_split_lock = 1; + + if (sysctl_sld_mitigate) { + /* + * misery factor #1: + * sleep 10ms before trying to execute split lock. + */ + if (msleep_interruptible(10) > 0) + return; + /* + * Misery factor #2: + * only allow one buslocked disabled core at a time. + */ + if (down_interruptible(&buslock_sem) == -EINTR) + return; + work = &sl_reenable_unlock; + } else { + work = &sl_reenable; + } + + cpu = get_cpu(); + schedule_delayed_work_on(cpu, work, 2); + + /* Disable split lock detection on this CPU to make progress */ + sld_update_msr(false); + put_cpu(); +} + +bool handle_guest_split_lock(unsigned long ip) +{ + if (sld_state == sld_warn) { + split_lock_warn(ip); + return true; + } + + pr_warn_once("#AC: %s/%d %s split_lock trap at address: 0x%lx\n", + current->comm, current->pid, + sld_state == sld_fatal ? "fatal" : "bogus", ip); + + current->thread.error_code = 0; + current->thread.trap_nr = X86_TRAP_AC; + force_sig_fault(SIGBUS, BUS_ADRALN, NULL); + return false; +} +EXPORT_SYMBOL_GPL(handle_guest_split_lock); + +void bus_lock_init(void) +{ + u64 val; + + if (!boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) + return; + + rdmsrl(MSR_IA32_DEBUGCTLMSR, val); + + if ((boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) && + (sld_state == sld_warn || sld_state == sld_fatal)) || + sld_state == sld_off) { + /* + * Warn and fatal are handled by #AC for split lock if #AC for + * split lock is supported. + */ + val &= ~DEBUGCTLMSR_BUS_LOCK_DETECT; + } else { + val |= DEBUGCTLMSR_BUS_LOCK_DETECT; + } + + wrmsrl(MSR_IA32_DEBUGCTLMSR, val); +} + +bool handle_user_split_lock(struct pt_regs *regs, long error_code) +{ + if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal) + return false; + split_lock_warn(regs->ip); + return true; +} + +void handle_bus_lock(struct pt_regs *regs) +{ + switch (sld_state) { + case sld_off: + break; + case sld_ratelimit: + /* Enforce no more than bld_ratelimit bus locks/sec. */ + while (!__ratelimit(&bld_ratelimit)) + msleep(20); + /* Warn on the bus lock. */ + fallthrough; + case sld_warn: + pr_warn_ratelimited("#DB: %s/%d took a bus_lock trap at address: 0x%lx\n", + current->comm, current->pid, regs->ip); + break; + case sld_fatal: + force_sig_fault(SIGBUS, BUS_ADRALN, NULL); + break; + } +} + +/* + * CPU models that are known to have the per-core split-lock detection + * feature even though they do not enumerate IA32_CORE_CAPABILITIES. + */ +static const struct x86_cpu_id split_lock_cpu_ids[] __initconst = { + X86_MATCH_VFM(INTEL_ICELAKE_X, 0), + X86_MATCH_VFM(INTEL_ICELAKE_L, 0), + X86_MATCH_VFM(INTEL_ICELAKE_D, 0), + {} +}; + +static void __init split_lock_setup(struct cpuinfo_x86 *c) +{ + const struct x86_cpu_id *m; + u64 ia32_core_caps; + + if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) + return; + + /* Check for CPUs that have support but do not enumerate it: */ + m = x86_match_cpu(split_lock_cpu_ids); + if (m) + goto supported; + + if (!cpu_has(c, X86_FEATURE_CORE_CAPABILITIES)) + return; + + /* + * Not all bits in MSR_IA32_CORE_CAPS are architectural, but + * MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT is. All CPUs that set + * it have split lock detection. + */ + rdmsrl(MSR_IA32_CORE_CAPS, ia32_core_caps); + if (ia32_core_caps & MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT) + goto supported; + + /* CPU is not in the model list and does not have the MSR bit: */ + return; + +supported: + cpu_model_supports_sld = true; + __split_lock_setup(); +} + +static void sld_state_show(void) +{ + if (!boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT) && + !boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) + return; + + switch (sld_state) { + case sld_off: + pr_info("disabled\n"); + break; + case sld_warn: + if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) { + pr_info("#AC: crashing the kernel on kernel split_locks and warning on user-space split_locks\n"); + if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "x86/splitlock", NULL, splitlock_cpu_offline) < 0) + pr_warn("No splitlock CPU offline handler\n"); + } else if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) { + pr_info("#DB: warning on user-space bus_locks\n"); + } + break; + case sld_fatal: + if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) { + pr_info("#AC: crashing the kernel on kernel split_locks and sending SIGBUS on user-space split_locks\n"); + } else if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) { + pr_info("#DB: sending SIGBUS on user-space bus_locks%s\n", + boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) ? + " from non-WB" : ""); + } + break; + case sld_ratelimit: + if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) + pr_info("#DB: setting system wide bus lock rate limit to %u/sec\n", bld_ratelimit.burst); + break; + } +} + +void __init sld_setup(struct cpuinfo_x86 *c) +{ + split_lock_setup(c); + sld_state_setup(); + sld_state_show(); +} diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c index 392d09c936d60c..e6fa03ed9172c0 100644 --- a/arch/x86/kernel/cpu/cacheinfo.c +++ b/arch/x86/kernel/cpu/cacheinfo.c @@ -178,8 +178,6 @@ struct _cpuid4_info_regs { struct amd_northbridge *nb; }; -static unsigned short num_cache_leaves; - /* AMD doesn't have CPUID4. Emulate it here to report the same information to the user. This makes some assumptions about the machine: L2 not shared, no SMT etc. that is currently true on AMD CPUs. @@ -717,20 +715,23 @@ void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c) void init_amd_cacheinfo(struct cpuinfo_x86 *c) { + struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index); if (boot_cpu_has(X86_FEATURE_TOPOEXT)) { - num_cache_leaves = find_num_cache_leaves(c); + ci->num_leaves = find_num_cache_leaves(c); } else if (c->extended_cpuid_level >= 0x80000006) { if (cpuid_edx(0x80000006) & 0xf000) - num_cache_leaves = 4; + ci->num_leaves = 4; else - num_cache_leaves = 3; + ci->num_leaves = 3; } } void init_hygon_cacheinfo(struct cpuinfo_x86 *c) { - num_cache_leaves = find_num_cache_leaves(c); + struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index); + + ci->num_leaves = find_num_cache_leaves(c); } void init_intel_cacheinfo(struct cpuinfo_x86 *c) @@ -740,21 +741,21 @@ void init_intel_cacheinfo(struct cpuinfo_x86 *c) unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */ unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */ unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb; + struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index); if (c->cpuid_level > 3) { - static int is_initialized; - - if (is_initialized == 0) { - /* Init num_cache_leaves from boot CPU */ - num_cache_leaves = find_num_cache_leaves(c); - is_initialized++; - } + /* + * There should be at least one leaf. A non-zero value means + * that the number of leaves has been initialized. + */ + if (!ci->num_leaves) + ci->num_leaves = find_num_cache_leaves(c); /* * Whenever possible use cpuid(4), deterministic cache * parameters cpuid leaf to find the cache details */ - for (i = 0; i < num_cache_leaves; i++) { + for (i = 0; i < ci->num_leaves; i++) { struct _cpuid4_info_regs this_leaf = {}; int retval; @@ -790,14 +791,14 @@ void init_intel_cacheinfo(struct cpuinfo_x86 *c) * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for * trace cache */ - if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) { + if ((!ci->num_leaves || c->x86 == 15) && c->cpuid_level > 1) { /* supports eax=2 call */ int j, n; unsigned int regs[4]; unsigned char *dp = (unsigned char *)regs; int only_trace = 0; - if (num_cache_leaves != 0 && c->x86 == 15) + if (ci->num_leaves && c->x86 == 15) only_trace = 1; /* Number of times to iterate */ @@ -991,14 +992,12 @@ static void ci_leaf_init(struct cacheinfo *this_leaf, int init_cache_level(unsigned int cpu) { - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu); - if (!num_cache_leaves) + /* There should be at least one leaf. */ + if (!ci->num_leaves) return -ENOENT; - if (!this_cpu_ci) - return -EINVAL; - this_cpu_ci->num_levels = 3; - this_cpu_ci->num_leaves = num_cache_leaves; + return 0; } diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index f43bb974fc66d7..3e9037690814b3 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -169,7 +169,7 @@ static void ppin_init(struct cpuinfo_x86 *c) } clear_ppin: - clear_cpu_cap(c, info->feature); + setup_clear_cpu_cap(info->feature); } static void default_init(struct cpuinfo_x86 *c) @@ -276,21 +276,13 @@ static int __init x86_noinvpcid_setup(char *s) } early_param("noinvpcid", x86_noinvpcid_setup); -#ifdef CONFIG_X86_32 -static int cachesize_override = -1; -static int disable_x86_serial_nr = 1; - -static int __init cachesize_setup(char *str) -{ - get_option(&str, &cachesize_override); - return 1; -} -__setup("cachesize=", cachesize_setup); - /* Standard macro to see if a specific flag is changeable */ -static inline int flag_is_changeable_p(u32 flag) +static inline bool flag_is_changeable_p(unsigned long flag) { - u32 f1, f2; + unsigned long f1, f2; + + if (!IS_ENABLED(CONFIG_X86_32)) + return true; /* * Cyrix and IDT cpus allow disabling of CPUID @@ -313,11 +305,22 @@ static inline int flag_is_changeable_p(u32 flag) : "=&r" (f1), "=&r" (f2) : "ir" (flag)); - return ((f1^f2) & flag) != 0; + return (f1 ^ f2) & flag; } +#ifdef CONFIG_X86_32 +static int cachesize_override = -1; +static int disable_x86_serial_nr = 1; + +static int __init cachesize_setup(char *str) +{ + get_option(&str, &cachesize_override); + return 1; +} +__setup("cachesize=", cachesize_setup); + /* Probe for the CPUID instruction */ -int have_cpuid_p(void) +bool have_cpuid_p(void) { return flag_is_changeable_p(X86_EFLAGS_ID); } @@ -349,10 +352,6 @@ static int __init x86_serial_nr_setup(char *s) } __setup("serialnumber", x86_serial_nr_setup); #else -static inline int flag_is_changeable_p(u32 flag) -{ - return 1; -} static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c) { } @@ -868,7 +867,7 @@ static void cpu_detect_tlb(struct cpuinfo_x86 *c) tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]); } -static void get_cpu_vendor(struct cpuinfo_x86 *c) +void get_cpu_vendor(struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; int i; @@ -1088,7 +1087,6 @@ void get_cpu_address_sizes(struct cpuinfo_x86 *c) static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) { -#ifdef CONFIG_X86_32 int i; /* @@ -1109,7 +1107,6 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) break; } } -#endif } #define NO_SPECULATION BIT(0) @@ -1652,15 +1649,11 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) detect_nopl(); } -void __init early_cpu_init(void) +void __init init_cpu_devs(void) { const struct cpu_dev *const *cdev; int count = 0; -#ifdef CONFIG_PROCESSOR_SELECT - pr_info("KERNEL supported cpus:\n"); -#endif - for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) { const struct cpu_dev *cpudev = *cdev; @@ -1668,20 +1661,30 @@ void __init early_cpu_init(void) break; cpu_devs[count] = cpudev; count++; + } +} +void __init early_cpu_init(void) +{ #ifdef CONFIG_PROCESSOR_SELECT - { - unsigned int j; - - for (j = 0; j < 2; j++) { - if (!cpudev->c_ident[j]) - continue; - pr_info(" %s %s\n", cpudev->c_vendor, - cpudev->c_ident[j]); - } - } + unsigned int i, j; + + pr_info("KERNEL supported cpus:\n"); #endif + + init_cpu_devs(); + +#ifdef CONFIG_PROCESSOR_SELECT + for (i = 0; i < X86_VENDOR_NUM && cpu_devs[i]; i++) { + for (j = 0; j < 2; j++) { + if (!cpu_devs[i]->c_ident[j]) + continue; + pr_info(" %s %s\n", cpu_devs[i]->c_vendor, + cpu_devs[i]->c_ident[j]); + } } +#endif + early_identify_cpu(&boot_cpu_data); } @@ -1841,6 +1844,8 @@ static void identify_cpu(struct cpuinfo_x86 *c) if (this_cpu->c_init) this_cpu->c_init(c); + bus_lock_init(); + /* Disable the PN if appropriate */ squash_the_stupid_serial_number(c); @@ -1906,9 +1911,7 @@ static void identify_cpu(struct cpuinfo_x86 *c) /* Init Machine Check Exception if available. */ mcheck_cpu_init(c); -#ifdef CONFIG_NUMA numa_add_cpu(smp_processor_id()); -#endif } /* @@ -2392,12 +2395,12 @@ void __init arch_cpu_finalize_init(void) alternative_instructions(); if (IS_ENABLED(CONFIG_X86_64)) { - unsigned long USER_PTR_MAX = TASK_SIZE_MAX-1; + unsigned long USER_PTR_MAX = TASK_SIZE_MAX; /* * Enable this when LAM is gated on LASS support if (cpu_feature_enabled(X86_FEATURE_LAM)) - USER_PTR_MAX = (1ul << 63) - PAGE_SIZE - 1; + USER_PTR_MAX = (1ul << 63) - PAGE_SIZE; */ runtime_const_init(ptr, USER_PTR_MAX); diff --git a/arch/x86/kernel/cpu/debugfs.c b/arch/x86/kernel/cpu/debugfs.c index 3baf3e43583472..10719aba627680 100644 --- a/arch/x86/kernel/cpu/debugfs.c +++ b/arch/x86/kernel/cpu/debugfs.c @@ -22,6 +22,7 @@ static int cpu_debug_show(struct seq_file *m, void *p) seq_printf(m, "die_id: %u\n", c->topo.die_id); seq_printf(m, "cu_id: %u\n", c->topo.cu_id); seq_printf(m, "core_id: %u\n", c->topo.core_id); + seq_printf(m, "cpu_type: %s\n", get_topology_cpu_type_name(c)); seq_printf(m, "logical_pkg_id: %u\n", c->topo.logical_pkg_id); seq_printf(m, "logical_die_id: %u\n", c->topo.logical_die_id); seq_printf(m, "llc_id: %u\n", c->topo.llc_id); diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index e7656cbef68d54..8ded9f859a3a96 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -7,13 +7,9 @@ #include #include #include -#include #include #include #include -#include -#include -#include #include #include @@ -24,8 +20,6 @@ #include #include #include -#include -#include #include #include #include @@ -41,28 +35,6 @@ #include #endif -enum split_lock_detect_state { - sld_off = 0, - sld_warn, - sld_fatal, - sld_ratelimit, -}; - -/* - * Default to sld_off because most systems do not support split lock detection. - * sld_state_setup() will switch this to sld_warn on systems that support - * split lock/bus lock detect, unless there is a command line override. - */ -static enum split_lock_detect_state sld_state __ro_after_init = sld_off; -static u64 msr_test_ctrl_cache __ro_after_init; - -/* - * With a name like MSR_TEST_CTL it should go without saying, but don't touch - * MSR_TEST_CTL unless the CPU is one of the whitelisted models. Writing it - * on CPUs that do not support SLD can cause fireworks, even when writing '0'. - */ -static bool cpu_model_supports_sld __ro_after_init; - /* * Processors which have self-snooping capability can handle conflicting * memory type across CPUs by snooping its own cache. However, there exists @@ -549,9 +521,6 @@ static void init_intel_misc_features(struct cpuinfo_x86 *c) wrmsrl(MSR_MISC_FEATURES_ENABLES, msr); } -static void split_lock_init(void); -static void bus_lock_init(void); - static void init_intel(struct cpuinfo_x86 *c) { early_init_intel(c); @@ -586,7 +555,9 @@ static void init_intel(struct cpuinfo_x86 *c) c->x86_vfm == INTEL_WESTMERE_EX)) set_cpu_bug(c, X86_BUG_CLFLUSH_MONITOR); - if (boot_cpu_has(X86_FEATURE_MWAIT) && c->x86_vfm == INTEL_ATOM_GOLDMONT) + if (boot_cpu_has(X86_FEATURE_MWAIT) && + (c->x86_vfm == INTEL_ATOM_GOLDMONT || + c->x86_vfm == INTEL_LUNARLAKE_M)) set_cpu_bug(c, X86_BUG_MONITOR); #ifdef CONFIG_X86_64 @@ -643,7 +614,6 @@ static void init_intel(struct cpuinfo_x86 *c) init_intel_misc_features(c); split_lock_init(); - bus_lock_init(); intel_init_thermal(c); } @@ -909,381 +879,6 @@ static const struct cpu_dev intel_cpu_dev = { cpu_dev_register(intel_cpu_dev); -#undef pr_fmt -#define pr_fmt(fmt) "x86/split lock detection: " fmt - -static const struct { - const char *option; - enum split_lock_detect_state state; -} sld_options[] __initconst = { - { "off", sld_off }, - { "warn", sld_warn }, - { "fatal", sld_fatal }, - { "ratelimit:", sld_ratelimit }, -}; - -static struct ratelimit_state bld_ratelimit; - -static unsigned int sysctl_sld_mitigate = 1; -static DEFINE_SEMAPHORE(buslock_sem, 1); - -#ifdef CONFIG_PROC_SYSCTL -static struct ctl_table sld_sysctls[] = { - { - .procname = "split_lock_mitigate", - .data = &sysctl_sld_mitigate, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_douintvec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, -}; - -static int __init sld_mitigate_sysctl_init(void) -{ - register_sysctl_init("kernel", sld_sysctls); - return 0; -} - -late_initcall(sld_mitigate_sysctl_init); -#endif - -static inline bool match_option(const char *arg, int arglen, const char *opt) -{ - int len = strlen(opt), ratelimit; - - if (strncmp(arg, opt, len)) - return false; - - /* - * Min ratelimit is 1 bus lock/sec. - * Max ratelimit is 1000 bus locks/sec. - */ - if (sscanf(arg, "ratelimit:%d", &ratelimit) == 1 && - ratelimit > 0 && ratelimit <= 1000) { - ratelimit_state_init(&bld_ratelimit, HZ, ratelimit); - ratelimit_set_flags(&bld_ratelimit, RATELIMIT_MSG_ON_RELEASE); - return true; - } - - return len == arglen; -} - -static bool split_lock_verify_msr(bool on) -{ - u64 ctrl, tmp; - - if (rdmsrl_safe(MSR_TEST_CTRL, &ctrl)) - return false; - if (on) - ctrl |= MSR_TEST_CTRL_SPLIT_LOCK_DETECT; - else - ctrl &= ~MSR_TEST_CTRL_SPLIT_LOCK_DETECT; - if (wrmsrl_safe(MSR_TEST_CTRL, ctrl)) - return false; - rdmsrl(MSR_TEST_CTRL, tmp); - return ctrl == tmp; -} - -static void __init sld_state_setup(void) -{ - enum split_lock_detect_state state = sld_warn; - char arg[20]; - int i, ret; - - if (!boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) && - !boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) - return; - - ret = cmdline_find_option(boot_command_line, "split_lock_detect", - arg, sizeof(arg)); - if (ret >= 0) { - for (i = 0; i < ARRAY_SIZE(sld_options); i++) { - if (match_option(arg, ret, sld_options[i].option)) { - state = sld_options[i].state; - break; - } - } - } - sld_state = state; -} - -static void __init __split_lock_setup(void) -{ - if (!split_lock_verify_msr(false)) { - pr_info("MSR access failed: Disabled\n"); - return; - } - - rdmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache); - - if (!split_lock_verify_msr(true)) { - pr_info("MSR access failed: Disabled\n"); - return; - } - - /* Restore the MSR to its cached value. */ - wrmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache); - - setup_force_cpu_cap(X86_FEATURE_SPLIT_LOCK_DETECT); -} - -/* - * MSR_TEST_CTRL is per core, but we treat it like a per CPU MSR. Locking - * is not implemented as one thread could undo the setting of the other - * thread immediately after dropping the lock anyway. - */ -static void sld_update_msr(bool on) -{ - u64 test_ctrl_val = msr_test_ctrl_cache; - - if (on) - test_ctrl_val |= MSR_TEST_CTRL_SPLIT_LOCK_DETECT; - - wrmsrl(MSR_TEST_CTRL, test_ctrl_val); -} - -static void split_lock_init(void) -{ - /* - * #DB for bus lock handles ratelimit and #AC for split lock is - * disabled. - */ - if (sld_state == sld_ratelimit) { - split_lock_verify_msr(false); - return; - } - - if (cpu_model_supports_sld) - split_lock_verify_msr(sld_state != sld_off); -} - -static void __split_lock_reenable_unlock(struct work_struct *work) -{ - sld_update_msr(true); - up(&buslock_sem); -} - -static DECLARE_DELAYED_WORK(sl_reenable_unlock, __split_lock_reenable_unlock); - -static void __split_lock_reenable(struct work_struct *work) -{ - sld_update_msr(true); -} -static DECLARE_DELAYED_WORK(sl_reenable, __split_lock_reenable); - -/* - * If a CPU goes offline with pending delayed work to re-enable split lock - * detection then the delayed work will be executed on some other CPU. That - * handles releasing the buslock_sem, but because it executes on a - * different CPU probably won't re-enable split lock detection. This is a - * problem on HT systems since the sibling CPU on the same core may then be - * left running with split lock detection disabled. - * - * Unconditionally re-enable detection here. - */ -static int splitlock_cpu_offline(unsigned int cpu) -{ - sld_update_msr(true); - - return 0; -} - -static void split_lock_warn(unsigned long ip) -{ - struct delayed_work *work; - int cpu; - - if (!current->reported_split_lock) - pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n", - current->comm, current->pid, ip); - current->reported_split_lock = 1; - - if (sysctl_sld_mitigate) { - /* - * misery factor #1: - * sleep 10ms before trying to execute split lock. - */ - if (msleep_interruptible(10) > 0) - return; - /* - * Misery factor #2: - * only allow one buslocked disabled core at a time. - */ - if (down_interruptible(&buslock_sem) == -EINTR) - return; - work = &sl_reenable_unlock; - } else { - work = &sl_reenable; - } - - cpu = get_cpu(); - schedule_delayed_work_on(cpu, work, 2); - - /* Disable split lock detection on this CPU to make progress */ - sld_update_msr(false); - put_cpu(); -} - -bool handle_guest_split_lock(unsigned long ip) -{ - if (sld_state == sld_warn) { - split_lock_warn(ip); - return true; - } - - pr_warn_once("#AC: %s/%d %s split_lock trap at address: 0x%lx\n", - current->comm, current->pid, - sld_state == sld_fatal ? "fatal" : "bogus", ip); - - current->thread.error_code = 0; - current->thread.trap_nr = X86_TRAP_AC; - force_sig_fault(SIGBUS, BUS_ADRALN, NULL); - return false; -} -EXPORT_SYMBOL_GPL(handle_guest_split_lock); - -static void bus_lock_init(void) -{ - u64 val; - - if (!boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) - return; - - rdmsrl(MSR_IA32_DEBUGCTLMSR, val); - - if ((boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) && - (sld_state == sld_warn || sld_state == sld_fatal)) || - sld_state == sld_off) { - /* - * Warn and fatal are handled by #AC for split lock if #AC for - * split lock is supported. - */ - val &= ~DEBUGCTLMSR_BUS_LOCK_DETECT; - } else { - val |= DEBUGCTLMSR_BUS_LOCK_DETECT; - } - - wrmsrl(MSR_IA32_DEBUGCTLMSR, val); -} - -bool handle_user_split_lock(struct pt_regs *regs, long error_code) -{ - if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal) - return false; - split_lock_warn(regs->ip); - return true; -} - -void handle_bus_lock(struct pt_regs *regs) -{ - switch (sld_state) { - case sld_off: - break; - case sld_ratelimit: - /* Enforce no more than bld_ratelimit bus locks/sec. */ - while (!__ratelimit(&bld_ratelimit)) - msleep(20); - /* Warn on the bus lock. */ - fallthrough; - case sld_warn: - pr_warn_ratelimited("#DB: %s/%d took a bus_lock trap at address: 0x%lx\n", - current->comm, current->pid, regs->ip); - break; - case sld_fatal: - force_sig_fault(SIGBUS, BUS_ADRALN, NULL); - break; - } -} - -/* - * CPU models that are known to have the per-core split-lock detection - * feature even though they do not enumerate IA32_CORE_CAPABILITIES. - */ -static const struct x86_cpu_id split_lock_cpu_ids[] __initconst = { - X86_MATCH_VFM(INTEL_ICELAKE_X, 0), - X86_MATCH_VFM(INTEL_ICELAKE_L, 0), - X86_MATCH_VFM(INTEL_ICELAKE_D, 0), - {} -}; - -static void __init split_lock_setup(struct cpuinfo_x86 *c) -{ - const struct x86_cpu_id *m; - u64 ia32_core_caps; - - if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) - return; - - /* Check for CPUs that have support but do not enumerate it: */ - m = x86_match_cpu(split_lock_cpu_ids); - if (m) - goto supported; - - if (!cpu_has(c, X86_FEATURE_CORE_CAPABILITIES)) - return; - - /* - * Not all bits in MSR_IA32_CORE_CAPS are architectural, but - * MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT is. All CPUs that set - * it have split lock detection. - */ - rdmsrl(MSR_IA32_CORE_CAPS, ia32_core_caps); - if (ia32_core_caps & MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT) - goto supported; - - /* CPU is not in the model list and does not have the MSR bit: */ - return; - -supported: - cpu_model_supports_sld = true; - __split_lock_setup(); -} - -static void sld_state_show(void) -{ - if (!boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT) && - !boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) - return; - - switch (sld_state) { - case sld_off: - pr_info("disabled\n"); - break; - case sld_warn: - if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) { - pr_info("#AC: crashing the kernel on kernel split_locks and warning on user-space split_locks\n"); - if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, - "x86/splitlock", NULL, splitlock_cpu_offline) < 0) - pr_warn("No splitlock CPU offline handler\n"); - } else if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) { - pr_info("#DB: warning on user-space bus_locks\n"); - } - break; - case sld_fatal: - if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) { - pr_info("#AC: crashing the kernel on kernel split_locks and sending SIGBUS on user-space split_locks\n"); - } else if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) { - pr_info("#DB: sending SIGBUS on user-space bus_locks%s\n", - boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) ? - " from non-WB" : ""); - } - break; - case sld_ratelimit: - if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) - pr_info("#DB: setting system wide bus lock rate limit to %u/sec\n", bld_ratelimit.burst); - break; - } -} - -void __init sld_setup(struct cpuinfo_x86 *c) -{ - split_lock_setup(c); - sld_state_setup(); - sld_state_show(); -} - #define X86_HYBRID_CPU_TYPE_ID_SHIFT 24 /** @@ -1299,3 +894,18 @@ u8 get_this_hybrid_cpu_type(void) return cpuid_eax(0x0000001a) >> X86_HYBRID_CPU_TYPE_ID_SHIFT; } + +/** + * get_this_hybrid_cpu_native_id() - Get the native id of this hybrid CPU + * + * Returns the uarch native ID [23:0] of a CPU in a hybrid processor. + * If the processor is not hybrid, returns 0. + */ +u32 get_this_hybrid_cpu_native_id(void) +{ + if (!cpu_feature_enabled(X86_FEATURE_HYBRID_CPU)) + return 0; + + return cpuid_eax(0x0000001a) & + (BIT_ULL(X86_HYBRID_CPU_TYPE_ID_SHIFT) - 1); +} diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index 14bf8c232e457f..6ca80fff1fea94 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -778,29 +778,33 @@ bool amd_mce_usable_address(struct mce *m) static void __log_error(unsigned int bank, u64 status, u64 addr, u64 misc) { - struct mce m; + struct mce_hw_err err; + struct mce *m = &err.m; - mce_prep_record(&m); + mce_prep_record(&err); - m.status = status; - m.misc = misc; - m.bank = bank; - m.tsc = rdtsc(); + m->status = status; + m->misc = misc; + m->bank = bank; + m->tsc = rdtsc(); - if (m.status & MCI_STATUS_ADDRV) { - m.addr = addr; + if (m->status & MCI_STATUS_ADDRV) { + m->addr = addr; - smca_extract_err_addr(&m); + smca_extract_err_addr(m); } if (mce_flags.smca) { - rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), m.ipid); + rdmsrl(MSR_AMD64_SMCA_MCx_IPID(bank), m->ipid); - if (m.status & MCI_STATUS_SYNDV) - rdmsrl(MSR_AMD64_SMCA_MCx_SYND(bank), m.synd); + if (m->status & MCI_STATUS_SYNDV) { + rdmsrl(MSR_AMD64_SMCA_MCx_SYND(bank), m->synd); + rdmsrl(MSR_AMD64_SMCA_MCx_SYND1(bank), err.vendor.amd.synd1); + rdmsrl(MSR_AMD64_SMCA_MCx_SYND2(bank), err.vendor.amd.synd2); + } } - mce_log(&m); + mce_log(&err); } DEFINE_IDTENTRY_SYSVEC(sysvec_deferred_error) diff --git a/arch/x86/kernel/cpu/mce/apei.c b/arch/x86/kernel/cpu/mce/apei.c index 3885fe05f01ecc..0a89947e47bc86 100644 --- a/arch/x86/kernel/cpu/mce/apei.c +++ b/arch/x86/kernel/cpu/mce/apei.c @@ -28,7 +28,8 @@ void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err) { - struct mce m; + struct mce_hw_err err; + struct mce *m; int lsb; if (!(mem_err->validation_bits & CPER_MEM_VALID_PA)) @@ -44,31 +45,33 @@ void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err) else lsb = PAGE_SHIFT; - mce_prep_record(&m); - m.bank = -1; + mce_prep_record(&err); + m = &err.m; + m->bank = -1; /* Fake a memory read error with unknown channel */ - m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | MCI_STATUS_MISCV | 0x9f; - m.misc = (MCI_MISC_ADDR_PHYS << 6) | lsb; + m->status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | MCI_STATUS_MISCV | 0x9f; + m->misc = (MCI_MISC_ADDR_PHYS << 6) | lsb; if (severity >= GHES_SEV_RECOVERABLE) - m.status |= MCI_STATUS_UC; + m->status |= MCI_STATUS_UC; if (severity >= GHES_SEV_PANIC) { - m.status |= MCI_STATUS_PCC; - m.tsc = rdtsc(); + m->status |= MCI_STATUS_PCC; + m->tsc = rdtsc(); } - m.addr = mem_err->physical_addr; - mce_log(&m); + m->addr = mem_err->physical_addr; + mce_log(&err); } EXPORT_SYMBOL_GPL(apei_mce_report_mem_error); int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, u64 lapic_id) { const u64 *i_mce = ((const u64 *) (ctx_info + 1)); + unsigned int cpu, num_regs; bool apicid_found = false; - unsigned int cpu; - struct mce m; + struct mce_hw_err err; + struct mce *m; if (!boot_cpu_has(X86_FEATURE_SMCA)) return -EINVAL; @@ -86,16 +89,12 @@ int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, u64 lapic_id) return -EINVAL; /* - * The register array size must be large enough to include all the - * SMCA registers which need to be extracted. - * * The number of registers in the register array is determined by * Register Array Size/8 as defined in UEFI spec v2.8, sec N.2.4.2.2. - * The register layout is fixed and currently the raw data in the - * register array includes 6 SMCA registers which the kernel can - * extract. + * Sanity-check registers array size. */ - if (ctx_info->reg_arr_size < 48) + num_regs = ctx_info->reg_arr_size >> 3; + if (!num_regs) return -EINVAL; for_each_possible_cpu(cpu) { @@ -108,18 +107,68 @@ int apei_smca_report_x86_error(struct cper_ia_proc_ctx *ctx_info, u64 lapic_id) if (!apicid_found) return -EINVAL; - mce_prep_record_common(&m); - mce_prep_record_per_cpu(cpu, &m); + m = &err.m; + memset(&err, 0, sizeof(struct mce_hw_err)); + mce_prep_record_common(m); + mce_prep_record_per_cpu(cpu, m); + + m->bank = (ctx_info->msr_addr >> 4) & 0xFF; - m.bank = (ctx_info->msr_addr >> 4) & 0xFF; - m.status = *i_mce; - m.addr = *(i_mce + 1); - m.misc = *(i_mce + 2); - /* Skipping MCA_CONFIG */ - m.ipid = *(i_mce + 4); - m.synd = *(i_mce + 5); + /* + * The SMCA register layout is fixed and includes 16 registers. + * The end of the array may be variable, but the beginning is known. + * Cap the number of registers to expected max (15). + */ + if (num_regs > 15) + num_regs = 15; + + switch (num_regs) { + /* MCA_SYND2 */ + case 15: + err.vendor.amd.synd2 = *(i_mce + 14); + fallthrough; + /* MCA_SYND1 */ + case 14: + err.vendor.amd.synd1 = *(i_mce + 13); + fallthrough; + /* MCA_MISC4 */ + case 13: + /* MCA_MISC3 */ + case 12: + /* MCA_MISC2 */ + case 11: + /* MCA_MISC1 */ + case 10: + /* MCA_DEADDR */ + case 9: + /* MCA_DESTAT */ + case 8: + /* reserved */ + case 7: + /* MCA_SYND */ + case 6: + m->synd = *(i_mce + 5); + fallthrough; + /* MCA_IPID */ + case 5: + m->ipid = *(i_mce + 4); + fallthrough; + /* MCA_CONFIG */ + case 4: + /* MCA_MISC0 */ + case 3: + m->misc = *(i_mce + 2); + fallthrough; + /* MCA_ADDR */ + case 2: + m->addr = *(i_mce + 1); + fallthrough; + /* MCA_STATUS */ + case 1: + m->status = *i_mce; + } - mce_log(&m); + mce_log(&err); return 0; } diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c index 2a938f429c4d50..7fb5556a0b53d0 100644 --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -88,7 +88,7 @@ struct mca_config mca_cfg __read_mostly = { .monarch_timeout = -1 }; -static DEFINE_PER_CPU(struct mce, mces_seen); +static DEFINE_PER_CPU(struct mce_hw_err, hw_errs_seen); static unsigned long mce_need_notify; /* @@ -119,8 +119,6 @@ BLOCKING_NOTIFIER_HEAD(x86_mce_decoder_chain); void mce_prep_record_common(struct mce *m) { - memset(m, 0, sizeof(struct mce)); - m->cpuid = cpuid_eax(1); m->cpuvendor = boot_cpu_data.x86_vendor; m->mcgcap = __rdmsr(MSR_IA32_MCG_CAP); @@ -138,9 +136,12 @@ void mce_prep_record_per_cpu(unsigned int cpu, struct mce *m) m->socketid = topology_physical_package_id(cpu); } -/* Do initial initialization of a struct mce */ -void mce_prep_record(struct mce *m) +/* Do initial initialization of struct mce_hw_err */ +void mce_prep_record(struct mce_hw_err *err) { + struct mce *m = &err->m; + + memset(err, 0, sizeof(struct mce_hw_err)); mce_prep_record_common(m); mce_prep_record_per_cpu(smp_processor_id(), m); } @@ -148,9 +149,9 @@ void mce_prep_record(struct mce *m) DEFINE_PER_CPU(struct mce, injectm); EXPORT_PER_CPU_SYMBOL_GPL(injectm); -void mce_log(struct mce *m) +void mce_log(struct mce_hw_err *err) { - if (!mce_gen_pool_add(m)) + if (!mce_gen_pool_add(err)) irq_work_queue(&mce_irq_work); } EXPORT_SYMBOL_GPL(mce_log); @@ -171,8 +172,10 @@ void mce_unregister_decode_chain(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(mce_unregister_decode_chain); -static void __print_mce(struct mce *m) +static void __print_mce(struct mce_hw_err *err) { + struct mce *m = &err->m; + pr_emerg(HW_ERR "CPU %d: Machine Check%s: %Lx Bank %d: %016Lx\n", m->extcpu, (m->mcgstatus & MCG_STATUS_MCIP ? " Exception" : ""), @@ -199,6 +202,10 @@ static void __print_mce(struct mce *m) if (mce_flags.smca) { if (m->synd) pr_cont("SYND %llx ", m->synd); + if (err->vendor.amd.synd1) + pr_cont("SYND1 %llx ", err->vendor.amd.synd1); + if (err->vendor.amd.synd2) + pr_cont("SYND2 %llx ", err->vendor.amd.synd2); if (m->ipid) pr_cont("IPID %llx ", m->ipid); } @@ -214,9 +221,11 @@ static void __print_mce(struct mce *m) m->microcode); } -static void print_mce(struct mce *m) +static void print_mce(struct mce_hw_err *err) { - __print_mce(m); + struct mce *m = &err->m; + + __print_mce(err); if (m->cpuvendor != X86_VENDOR_AMD && m->cpuvendor != X86_VENDOR_HYGON) pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n"); @@ -251,7 +260,7 @@ static const char *mce_dump_aux_info(struct mce *m) return NULL; } -static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) +static noinstr void mce_panic(const char *msg, struct mce_hw_err *final, char *exp) { struct llist_node *pending; struct mce_evt_llist *l; @@ -282,20 +291,22 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) pending = mce_gen_pool_prepare_records(); /* First print corrected ones that are still unlogged */ llist_for_each_entry(l, pending, llnode) { - struct mce *m = &l->mce; + struct mce_hw_err *err = &l->err; + struct mce *m = &err->m; if (!(m->status & MCI_STATUS_UC)) { - print_mce(m); + print_mce(err); if (!apei_err) apei_err = apei_write_mce(m); } } /* Now print uncorrected but with the final one last */ llist_for_each_entry(l, pending, llnode) { - struct mce *m = &l->mce; + struct mce_hw_err *err = &l->err; + struct mce *m = &err->m; if (!(m->status & MCI_STATUS_UC)) continue; - if (!final || mce_cmp(m, final)) { - print_mce(m); + if (!final || mce_cmp(m, &final->m)) { + print_mce(err); if (!apei_err) apei_err = apei_write_mce(m); } @@ -303,12 +314,12 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) if (final) { print_mce(final); if (!apei_err) - apei_err = apei_write_mce(final); + apei_err = apei_write_mce(&final->m); } if (exp) pr_emerg(HW_ERR "Machine check: %s\n", exp); - memmsg = mce_dump_aux_info(final); + memmsg = mce_dump_aux_info(&final->m); if (memmsg) pr_emerg(HW_ERR "Machine check: %s\n", memmsg); @@ -323,9 +334,9 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) * panic. */ if (kexec_crash_loaded()) { - if (final && (final->status & MCI_STATUS_ADDRV)) { + if (final && (final->m.status & MCI_STATUS_ADDRV)) { struct page *p; - p = pfn_to_online_page(final->addr >> PAGE_SHIFT); + p = pfn_to_online_page(final->m.addr >> PAGE_SHIFT); if (p) SetPageHWPoison(p); } @@ -445,16 +456,18 @@ static noinstr void mce_wrmsrl(u32 msr, u64 v) * check into our "mce" struct so that we can use it later to assess * the severity of the problem as we read per-bank specific details. */ -static noinstr void mce_gather_info(struct mce *m, struct pt_regs *regs) +static noinstr void mce_gather_info(struct mce_hw_err *err, struct pt_regs *regs) { + struct mce *m; /* * Enable instrumentation around mce_prep_record() which calls external * facilities. */ instrumentation_begin(); - mce_prep_record(m); + mce_prep_record(err); instrumentation_end(); + m = &err->m; m->mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); if (regs) { /* @@ -574,13 +587,13 @@ EXPORT_SYMBOL_GPL(mce_is_correctable); static int mce_early_notifier(struct notifier_block *nb, unsigned long val, void *data) { - struct mce *m = (struct mce *)data; + struct mce_hw_err *err = to_mce_hw_err(data); - if (!m) + if (!err) return NOTIFY_DONE; /* Emit the trace record: */ - trace_mce_record(m); + trace_mce_record(err); set_bit(0, &mce_need_notify); @@ -624,13 +637,13 @@ static struct notifier_block mce_uc_nb = { static int mce_default_notifier(struct notifier_block *nb, unsigned long val, void *data) { - struct mce *m = (struct mce *)data; + struct mce_hw_err *err = to_mce_hw_err(data); - if (!m) + if (!err) return NOTIFY_DONE; - if (mca_cfg.print_all || !m->kflags) - __print_mce(m); + if (mca_cfg.print_all || !(err->m.kflags)) + __print_mce(err); return NOTIFY_DONE; } @@ -644,8 +657,10 @@ static struct notifier_block mce_default_nb = { /* * Read ADDR and MISC registers. */ -static noinstr void mce_read_aux(struct mce *m, int i) +static noinstr void mce_read_aux(struct mce_hw_err *err, int i) { + struct mce *m = &err->m; + if (m->status & MCI_STATUS_MISCV) m->misc = mce_rdmsrl(mca_msr_reg(i, MCA_MISC)); @@ -667,8 +682,11 @@ static noinstr void mce_read_aux(struct mce *m, int i) if (mce_flags.smca) { m->ipid = mce_rdmsrl(MSR_AMD64_SMCA_MCx_IPID(i)); - if (m->status & MCI_STATUS_SYNDV) + if (m->status & MCI_STATUS_SYNDV) { m->synd = mce_rdmsrl(MSR_AMD64_SMCA_MCx_SYND(i)); + err->vendor.amd.synd1 = mce_rdmsrl(MSR_AMD64_SMCA_MCx_SYND1(i)); + err->vendor.amd.synd2 = mce_rdmsrl(MSR_AMD64_SMCA_MCx_SYND2(i)); + } } } @@ -692,26 +710,28 @@ DEFINE_PER_CPU(unsigned, mce_poll_count); void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) { struct mce_bank *mce_banks = this_cpu_ptr(mce_banks_array); - struct mce m; + struct mce_hw_err err; + struct mce *m; int i; this_cpu_inc(mce_poll_count); - mce_gather_info(&m, NULL); + mce_gather_info(&err, NULL); + m = &err.m; if (flags & MCP_TIMESTAMP) - m.tsc = rdtsc(); + m->tsc = rdtsc(); for (i = 0; i < this_cpu_read(mce_num_banks); i++) { if (!mce_banks[i].ctl || !test_bit(i, *b)) continue; - m.misc = 0; - m.addr = 0; - m.bank = i; + m->misc = 0; + m->addr = 0; + m->bank = i; barrier(); - m.status = mce_rdmsrl(mca_msr_reg(i, MCA_STATUS)); + m->status = mce_rdmsrl(mca_msr_reg(i, MCA_STATUS)); /* * Update storm tracking here, before checking for the @@ -721,17 +741,17 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) * storm status. */ if (!mca_cfg.cmci_disabled) - mce_track_storm(&m); + mce_track_storm(m); /* If this entry is not valid, ignore it */ - if (!(m.status & MCI_STATUS_VAL)) + if (!(m->status & MCI_STATUS_VAL)) continue; /* * If we are logging everything (at CPU online) or this * is a corrected error, then we must log it. */ - if ((flags & MCP_UC) || !(m.status & MCI_STATUS_UC)) + if ((flags & MCP_UC) || !(m->status & MCI_STATUS_UC)) goto log_it; /* @@ -741,20 +761,20 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) * everything else. */ if (!mca_cfg.ser) { - if (m.status & MCI_STATUS_UC) + if (m->status & MCI_STATUS_UC) continue; goto log_it; } /* Log "not enabled" (speculative) errors */ - if (!(m.status & MCI_STATUS_EN)) + if (!(m->status & MCI_STATUS_EN)) goto log_it; /* * Log UCNA (SDM: 15.6.3 "UCR Error Classification") * UC == 1 && PCC == 0 && S == 0 */ - if (!(m.status & MCI_STATUS_PCC) && !(m.status & MCI_STATUS_S)) + if (!(m->status & MCI_STATUS_PCC) && !(m->status & MCI_STATUS_S)) goto log_it; /* @@ -768,20 +788,20 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) if (flags & MCP_DONTLOG) goto clear_it; - mce_read_aux(&m, i); - m.severity = mce_severity(&m, NULL, NULL, false); + mce_read_aux(&err, i); + m->severity = mce_severity(m, NULL, NULL, false); /* * Don't get the IP here because it's unlikely to * have anything to do with the actual error location. */ - if (mca_cfg.dont_log_ce && !mce_usable_address(&m)) + if (mca_cfg.dont_log_ce && !mce_usable_address(m)) goto clear_it; if (flags & MCP_QUEUE_LOG) - mce_gen_pool_add(&m); + mce_gen_pool_add(&err); else - mce_log(&m); + mce_log(&err); clear_it: /* @@ -905,9 +925,10 @@ static __always_inline void quirk_zen_ifu(int bank, struct mce *m, struct pt_reg * Do a quick check if any of the events requires a panic. * This decides if we keep the events around or clear them. */ -static __always_inline int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp, +static __always_inline int mce_no_way_out(struct mce_hw_err *err, char **msg, unsigned long *validp, struct pt_regs *regs) { + struct mce *m = &err->m; char *tmp = *msg; int i; @@ -925,7 +946,7 @@ static __always_inline int mce_no_way_out(struct mce *m, char **msg, unsigned lo m->bank = i; if (mce_severity(m, regs, &tmp, true) >= MCE_PANIC_SEVERITY) { - mce_read_aux(m, i); + mce_read_aux(err, i); *msg = tmp; return 1; } @@ -1016,10 +1037,11 @@ static noinstr int mce_timed_out(u64 *t, const char *msg) */ static void mce_reign(void) { - int cpu; + struct mce_hw_err *err = NULL; struct mce *m = NULL; int global_worst = 0; char *msg = NULL; + int cpu; /* * This CPU is the Monarch and the other CPUs have run @@ -1027,11 +1049,13 @@ static void mce_reign(void) * Grade the severity of the errors of all the CPUs. */ for_each_possible_cpu(cpu) { - struct mce *mtmp = &per_cpu(mces_seen, cpu); + struct mce_hw_err *etmp = &per_cpu(hw_errs_seen, cpu); + struct mce *mtmp = &etmp->m; if (mtmp->severity > global_worst) { global_worst = mtmp->severity; - m = &per_cpu(mces_seen, cpu); + err = &per_cpu(hw_errs_seen, cpu); + m = &err->m; } } @@ -1043,7 +1067,7 @@ static void mce_reign(void) if (m && global_worst >= MCE_PANIC_SEVERITY) { /* call mce_severity() to get "msg" for panic */ mce_severity(m, NULL, &msg, true); - mce_panic("Fatal machine check", m, msg); + mce_panic("Fatal machine check", err, msg); } /* @@ -1060,11 +1084,11 @@ static void mce_reign(void) mce_panic("Fatal machine check from unknown source", NULL, NULL); /* - * Now clear all the mces_seen so that they don't reappear on + * Now clear all the hw_errs_seen so that they don't reappear on * the next mce. */ for_each_possible_cpu(cpu) - memset(&per_cpu(mces_seen, cpu), 0, sizeof(struct mce)); + memset(&per_cpu(hw_errs_seen, cpu), 0, sizeof(struct mce_hw_err)); } static atomic_t global_nwo; @@ -1268,13 +1292,14 @@ static noinstr bool mce_check_crashing_cpu(void) } static __always_inline int -__mc_scan_banks(struct mce *m, struct pt_regs *regs, struct mce *final, - unsigned long *toclear, unsigned long *valid_banks, int no_way_out, - int *worst) +__mc_scan_banks(struct mce_hw_err *err, struct pt_regs *regs, + struct mce_hw_err *final, unsigned long *toclear, + unsigned long *valid_banks, int no_way_out, int *worst) { struct mce_bank *mce_banks = this_cpu_ptr(mce_banks_array); struct mca_config *cfg = &mca_cfg; int severity, i, taint = 0; + struct mce *m = &err->m; for (i = 0; i < this_cpu_read(mce_num_banks); i++) { arch___clear_bit(i, toclear); @@ -1319,7 +1344,7 @@ __mc_scan_banks(struct mce *m, struct pt_regs *regs, struct mce *final, if (severity == MCE_NO_SEVERITY) continue; - mce_read_aux(m, i); + mce_read_aux(err, i); /* assuming valid severity level != 0 */ m->severity = severity; @@ -1329,17 +1354,17 @@ __mc_scan_banks(struct mce *m, struct pt_regs *regs, struct mce *final, * done in #MC context, where instrumentation is disabled. */ instrumentation_begin(); - mce_log(m); + mce_log(err); instrumentation_end(); if (severity > *worst) { - *final = *m; + *final = *err; *worst = severity; } } /* mce_clear_state will clear *final, save locally for use later */ - *m = *final; + *err = *final; return taint; } @@ -1399,9 +1424,10 @@ static void kill_me_never(struct callback_head *cb) set_mce_nospec(pfn); } -static void queue_task_work(struct mce *m, char *msg, void (*func)(struct callback_head *)) +static void queue_task_work(struct mce_hw_err *err, char *msg, void (*func)(struct callback_head *)) { int count = ++current->mce_count; + struct mce *m = &err->m; /* First call, save all the details */ if (count == 1) { @@ -1414,11 +1440,12 @@ static void queue_task_work(struct mce *m, char *msg, void (*func)(struct callba /* Ten is likely overkill. Don't expect more than two faults before task_work() */ if (count > 10) - mce_panic("Too many consecutive machine checks while accessing user data", m, msg); + mce_panic("Too many consecutive machine checks while accessing user data", + err, msg); /* Second or later call, make sure page address matches the one from first call */ if (count > 1 && (current->mce_addr >> PAGE_SHIFT) != (m->addr >> PAGE_SHIFT)) - mce_panic("Consecutive machine checks to different user pages", m, msg); + mce_panic("Consecutive machine checks to different user pages", err, msg); /* Do not call task_work_add() more than once */ if (count > 1) @@ -1467,8 +1494,10 @@ noinstr void do_machine_check(struct pt_regs *regs) int worst = 0, order, no_way_out, kill_current_task, lmce, taint = 0; DECLARE_BITMAP(valid_banks, MAX_NR_BANKS) = { 0 }; DECLARE_BITMAP(toclear, MAX_NR_BANKS) = { 0 }; - struct mce m, *final; + struct mce_hw_err *final; + struct mce_hw_err err; char *msg = NULL; + struct mce *m; if (unlikely(mce_flags.p5)) return pentium_machine_check(regs); @@ -1506,13 +1535,14 @@ noinstr void do_machine_check(struct pt_regs *regs) this_cpu_inc(mce_exception_count); - mce_gather_info(&m, regs); - m.tsc = rdtsc(); + mce_gather_info(&err, regs); + m = &err.m; + m->tsc = rdtsc(); - final = this_cpu_ptr(&mces_seen); - *final = m; + final = this_cpu_ptr(&hw_errs_seen); + *final = err; - no_way_out = mce_no_way_out(&m, &msg, valid_banks, regs); + no_way_out = mce_no_way_out(&err, &msg, valid_banks, regs); barrier(); @@ -1521,15 +1551,15 @@ noinstr void do_machine_check(struct pt_regs *regs) * Assume the worst for now, but if we find the * severity is MCE_AR_SEVERITY we have other options. */ - if (!(m.mcgstatus & MCG_STATUS_RIPV)) + if (!(m->mcgstatus & MCG_STATUS_RIPV)) kill_current_task = 1; /* * Check if this MCE is signaled to only this logical processor, * on Intel, Zhaoxin only. */ - if (m.cpuvendor == X86_VENDOR_INTEL || - m.cpuvendor == X86_VENDOR_ZHAOXIN) - lmce = m.mcgstatus & MCG_STATUS_LMCES; + if (m->cpuvendor == X86_VENDOR_INTEL || + m->cpuvendor == X86_VENDOR_ZHAOXIN) + lmce = m->mcgstatus & MCG_STATUS_LMCES; /* * Local machine check may already know that we have to panic. @@ -1540,12 +1570,12 @@ noinstr void do_machine_check(struct pt_regs *regs) */ if (lmce) { if (no_way_out) - mce_panic("Fatal local machine check", &m, msg); + mce_panic("Fatal local machine check", &err, msg); } else { order = mce_start(&no_way_out); } - taint = __mc_scan_banks(&m, regs, final, toclear, valid_banks, no_way_out, &worst); + taint = __mc_scan_banks(&err, regs, final, toclear, valid_banks, no_way_out, &worst); if (!no_way_out) mce_clear_state(toclear); @@ -1560,7 +1590,7 @@ noinstr void do_machine_check(struct pt_regs *regs) no_way_out = worst >= MCE_PANIC_SEVERITY; if (no_way_out) - mce_panic("Fatal machine check on current CPU", &m, msg); + mce_panic("Fatal machine check on current CPU", &err, msg); } } else { /* @@ -1572,8 +1602,8 @@ noinstr void do_machine_check(struct pt_regs *regs) * make sure we have the right "msg". */ if (worst >= MCE_PANIC_SEVERITY) { - mce_severity(&m, regs, &msg, true); - mce_panic("Local fatal machine check!", &m, msg); + mce_severity(m, regs, &msg, true); + mce_panic("Local fatal machine check!", &err, msg); } } @@ -1591,16 +1621,16 @@ noinstr void do_machine_check(struct pt_regs *regs) goto out; /* Fault was in user mode and we need to take some action */ - if ((m.cs & 3) == 3) { + if ((m->cs & 3) == 3) { /* If this triggers there is no way to recover. Die hard. */ BUG_ON(!on_thread_stack() || !user_mode(regs)); - if (!mce_usable_address(&m)) - queue_task_work(&m, msg, kill_me_now); + if (!mce_usable_address(m)) + queue_task_work(&err, msg, kill_me_now); else - queue_task_work(&m, msg, kill_me_maybe); + queue_task_work(&err, msg, kill_me_maybe); - } else if (m.mcgstatus & MCG_STATUS_SEAM_NR) { + } else if (m->mcgstatus & MCG_STATUS_SEAM_NR) { /* * Saved RIP on stack makes it look like the machine check * was taken in the kernel on the instruction following @@ -1612,8 +1642,8 @@ noinstr void do_machine_check(struct pt_regs *regs) * not occur there. Mark the page as poisoned so it won't * be added to free list when the guest is terminated. */ - if (mce_usable_address(&m)) { - struct page *p = pfn_to_online_page(m.addr >> PAGE_SHIFT); + if (mce_usable_address(m)) { + struct page *p = pfn_to_online_page(m->addr >> PAGE_SHIFT); if (p) SetPageHWPoison(p); @@ -1628,13 +1658,13 @@ noinstr void do_machine_check(struct pt_regs *regs) * corresponding exception handler which would do that is the * proper one. */ - if (m.kflags & MCE_IN_KERNEL_RECOV) { + if (m->kflags & MCE_IN_KERNEL_RECOV) { if (!fixup_exception(regs, X86_TRAP_MC, 0, 0)) - mce_panic("Failed kernel mode recovery", &m, msg); + mce_panic("Failed kernel mode recovery", &err, msg); } - if (m.kflags & MCE_IN_KERNEL_COPYIN) - queue_task_work(&m, msg, kill_me_never); + if (m->kflags & MCE_IN_KERNEL_COPYIN) + queue_task_work(&err, msg, kill_me_never); } out: diff --git a/arch/x86/kernel/cpu/mce/dev-mcelog.c b/arch/x86/kernel/cpu/mce/dev-mcelog.c index af44fd5dbd7c39..8d023239ce18e9 100644 --- a/arch/x86/kernel/cpu/mce/dev-mcelog.c +++ b/arch/x86/kernel/cpu/mce/dev-mcelog.c @@ -264,15 +264,8 @@ static long mce_chrdev_ioctl(struct file *f, unsigned int cmd, return put_user(sizeof(struct mce), p); case MCE_GET_LOG_LEN: return put_user(mcelog->len, p); - case MCE_GETCLEAR_FLAGS: { - unsigned flags; - - do { - flags = mcelog->flags; - } while (cmpxchg(&mcelog->flags, flags, 0) != flags); - - return put_user(flags, p); - } + case MCE_GETCLEAR_FLAGS: + return put_user(xchg(&mcelog->flags, 0), p); default: return -ENOTTY; } diff --git a/arch/x86/kernel/cpu/mce/genpool.c b/arch/x86/kernel/cpu/mce/genpool.c index 4284749ec80373..d0be6dda0c14b4 100644 --- a/arch/x86/kernel/cpu/mce/genpool.c +++ b/arch/x86/kernel/cpu/mce/genpool.c @@ -31,15 +31,15 @@ static LLIST_HEAD(mce_event_llist); */ static bool is_duplicate_mce_record(struct mce_evt_llist *t, struct mce_evt_llist *l) { + struct mce_hw_err *err1, *err2; struct mce_evt_llist *node; - struct mce *m1, *m2; - m1 = &t->mce; + err1 = &t->err; llist_for_each_entry(node, &l->llnode, llnode) { - m2 = &node->mce; + err2 = &node->err; - if (!mce_cmp(m1, m2)) + if (!mce_cmp(&err1->m, &err2->m)) return true; } return false; @@ -73,8 +73,8 @@ struct llist_node *mce_gen_pool_prepare_records(void) void mce_gen_pool_process(struct work_struct *__unused) { - struct llist_node *head; struct mce_evt_llist *node, *tmp; + struct llist_node *head; struct mce *mce; head = llist_del_all(&mce_event_llist); @@ -83,7 +83,7 @@ void mce_gen_pool_process(struct work_struct *__unused) head = llist_reverse_order(head); llist_for_each_entry_safe(node, tmp, head, llnode) { - mce = &node->mce; + mce = &node->err.m; blocking_notifier_call_chain(&x86_mce_decoder_chain, 0, mce); gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node)); } @@ -94,11 +94,11 @@ bool mce_gen_pool_empty(void) return llist_empty(&mce_event_llist); } -int mce_gen_pool_add(struct mce *mce) +int mce_gen_pool_add(struct mce_hw_err *err) { struct mce_evt_llist *node; - if (filter_mce(mce)) + if (filter_mce(&err->m)) return -EINVAL; if (!mce_evt_pool) @@ -110,7 +110,7 @@ int mce_gen_pool_add(struct mce *mce) return -ENOMEM; } - memcpy(&node->mce, mce, sizeof(*mce)); + memcpy(&node->err, err, sizeof(*err)); llist_add(&node->llnode, &mce_event_llist); return 0; diff --git a/arch/x86/kernel/cpu/mce/inject.c b/arch/x86/kernel/cpu/mce/inject.c index 49ed3428785d84..313fe682db3396 100644 --- a/arch/x86/kernel/cpu/mce/inject.c +++ b/arch/x86/kernel/cpu/mce/inject.c @@ -502,8 +502,9 @@ static void prepare_msrs(void *info) static void do_inject(void) { - u64 mcg_status = 0; unsigned int cpu = i_mce.extcpu; + struct mce_hw_err err; + u64 mcg_status = 0; u8 b = i_mce.bank; i_mce.tsc = rdtsc_ordered(); @@ -517,7 +518,8 @@ static void do_inject(void) i_mce.status |= MCI_STATUS_SYNDV; if (inj_type == SW_INJ) { - mce_log(&i_mce); + err.m = i_mce; + mce_log(&err); return; } diff --git a/arch/x86/kernel/cpu/mce/intel.c b/arch/x86/kernel/cpu/mce/intel.c index f6103e6bf69a8b..b3cd2c61b11d22 100644 --- a/arch/x86/kernel/cpu/mce/intel.c +++ b/arch/x86/kernel/cpu/mce/intel.c @@ -94,7 +94,7 @@ static int cmci_supported(int *banks) if (!boot_cpu_has(X86_FEATURE_APIC) || lapic_get_maxlvt() < 6) return 0; rdmsrl(MSR_IA32_MCG_CAP, cap); - *banks = min_t(unsigned, MAX_NR_BANKS, cap & 0xff); + *banks = min_t(unsigned, MAX_NR_BANKS, cap & MCG_BANKCNT_MASK); return !!(cap & MCG_CMCI_P); } diff --git a/arch/x86/kernel/cpu/mce/internal.h b/arch/x86/kernel/cpu/mce/internal.h index 43c7f3b71df59c..84f810598231e2 100644 --- a/arch/x86/kernel/cpu/mce/internal.h +++ b/arch/x86/kernel/cpu/mce/internal.h @@ -26,12 +26,12 @@ extern struct blocking_notifier_head x86_mce_decoder_chain; struct mce_evt_llist { struct llist_node llnode; - struct mce mce; + struct mce_hw_err err; }; void mce_gen_pool_process(struct work_struct *__unused); bool mce_gen_pool_empty(void); -int mce_gen_pool_add(struct mce *mce); +int mce_gen_pool_add(struct mce_hw_err *err); int mce_gen_pool_init(void); struct llist_node *mce_gen_pool_prepare_records(void); diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 31a73715d75531..fb5d0c67fbab17 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "internal.h" @@ -483,11 +484,25 @@ static void scan_containers(u8 *ucode, size_t size, struct cont_desc *desc) } } -static int __apply_microcode_amd(struct microcode_amd *mc) +static int __apply_microcode_amd(struct microcode_amd *mc, unsigned int psize) { + unsigned long p_addr = (unsigned long)&mc->hdr.data_code; u32 rev, dummy; - native_wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc->hdr.data_code); + native_wrmsrl(MSR_AMD64_PATCH_LOADER, p_addr); + + if (x86_family(bsp_cpuid_1_eax) == 0x17) { + unsigned long p_addr_end = p_addr + psize - 1; + + invlpg(p_addr); + + /* + * Flush next page too if patch image is crossing a page + * boundary. + */ + if (p_addr >> PAGE_SHIFT != p_addr_end >> PAGE_SHIFT) + invlpg(p_addr_end); + } /* verify patch application was successful */ native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); @@ -529,7 +544,7 @@ static bool early_apply_microcode(u32 old_rev, void *ucode, size_t size) if (old_rev > mc->hdr.patch_id) return ret; - return !__apply_microcode_amd(mc); + return !__apply_microcode_amd(mc, desc.psize); } static bool get_builtin_microcode(struct cpio_data *cp) @@ -745,7 +760,7 @@ void reload_ucode_amd(unsigned int cpu) rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); if (rev < mc->hdr.patch_id) { - if (!__apply_microcode_amd(mc)) + if (!__apply_microcode_amd(mc, p->size)) pr_info_once("reload revision: 0x%08x\n", mc->hdr.patch_id); } } @@ -798,7 +813,7 @@ static enum ucode_state apply_microcode_amd(int cpu) goto out; } - if (__apply_microcode_amd(mc_amd)) { + if (__apply_microcode_amd(mc_amd, p->size)) { pr_err("CPU%d: update failed for patch_level=0x%08x\n", cpu, mc_amd->hdr.patch_id); return UCODE_ERROR; diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 815fa67356a2dd..f3d534807d914a 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -319,12 +319,6 @@ static enum ucode_state __apply_microcode(struct ucode_cpu_info *uci, return UCODE_OK; } - /* - * Writeback and invalidate caches before updating microcode to avoid - * internal issues depending on what the microcode is updating. - */ - native_wbinvd(); - /* write microcode via MSR 0x79 */ native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); @@ -574,14 +568,14 @@ static bool is_blacklisted(unsigned int cpu) /* * Late loading on model 79 with microcode revision less than 0x0b000021 * and LLC size per core bigger than 2.5MB may result in a system hang. - * This behavior is documented in item BDF90, #334165 (Intel Xeon + * This behavior is documented in item BDX90, #334165 (Intel Xeon * Processor E7-8800/4800 v4 Product Family). */ if (c->x86_vfm == INTEL_BROADWELL_X && c->x86_stepping == 0x01 && llc_size_per_core > 2621440 && c->microcode < 0x0b000021) { - pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); + pr_err_once("Erratum BDX90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); return true; } diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index d18078834dedac..dc12fe5ef3caa9 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -223,6 +223,63 @@ static void hv_machine_crash_shutdown(struct pt_regs *regs) hyperv_cleanup(); } #endif /* CONFIG_CRASH_DUMP */ + +static u64 hv_ref_counter_at_suspend; +static void (*old_save_sched_clock_state)(void); +static void (*old_restore_sched_clock_state)(void); + +/* + * Hyper-V clock counter resets during hibernation. Save and restore clock + * offset during suspend/resume, while also considering the time passed + * before suspend. This is to make sure that sched_clock using hv tsc page + * based clocksource, proceeds from where it left off during suspend and + * it shows correct time for the timestamps of kernel messages after resume. + */ +static void save_hv_clock_tsc_state(void) +{ + hv_ref_counter_at_suspend = hv_read_reference_counter(); +} + +static void restore_hv_clock_tsc_state(void) +{ + /* + * Adjust the offsets used by hv tsc clocksource to + * account for the time spent before hibernation. + * adjusted value = reference counter (time) at suspend + * - reference counter (time) now. + */ + hv_adj_sched_clock_offset(hv_ref_counter_at_suspend - hv_read_reference_counter()); +} + +/* + * Functions to override save_sched_clock_state and restore_sched_clock_state + * functions of x86_platform. The Hyper-V clock counter is reset during + * suspend-resume and the offset used to measure time needs to be + * corrected, post resume. + */ +static void hv_save_sched_clock_state(void) +{ + old_save_sched_clock_state(); + save_hv_clock_tsc_state(); +} + +static void hv_restore_sched_clock_state(void) +{ + restore_hv_clock_tsc_state(); + old_restore_sched_clock_state(); +} + +static void __init x86_setup_ops_for_tsc_pg_clock(void) +{ + if (!(ms_hyperv.features & HV_MSR_REFERENCE_TSC_AVAILABLE)) + return; + + old_save_sched_clock_state = x86_platform.save_sched_clock_state; + x86_platform.save_sched_clock_state = hv_save_sched_clock_state; + + old_restore_sched_clock_state = x86_platform.restore_sched_clock_state; + x86_platform.restore_sched_clock_state = hv_restore_sched_clock_state; +} #endif /* CONFIG_HYPERV */ static uint32_t __init ms_hyperv_platform(void) @@ -579,6 +636,7 @@ static void __init ms_hyperv_init_platform(void) /* Register Hyper-V specific clocksource */ hv_init_clocksource(); + x86_setup_ops_for_tsc_pg_clock(); hv_vtl_init_platform(); #endif /* diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c index e65fae63660e3f..41ed01f46bd92d 100644 --- a/arch/x86/kernel/cpu/proc.c +++ b/arch/x86/kernel/cpu/proc.c @@ -41,11 +41,11 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c) "fpu_exception\t: %s\n" "cpuid level\t: %d\n" "wp\t\t: yes\n", - boot_cpu_has_bug(X86_BUG_FDIV) ? "yes" : "no", - boot_cpu_has_bug(X86_BUG_F00F) ? "yes" : "no", - boot_cpu_has_bug(X86_BUG_COMA) ? "yes" : "no", - boot_cpu_has(X86_FEATURE_FPU) ? "yes" : "no", - boot_cpu_has(X86_FEATURE_FPU) ? "yes" : "no", + str_yes_no(boot_cpu_has_bug(X86_BUG_FDIV)), + str_yes_no(boot_cpu_has_bug(X86_BUG_F00F)), + str_yes_no(boot_cpu_has_bug(X86_BUG_COMA)), + str_yes_no(boot_cpu_has(X86_FEATURE_FPU)), + str_yes_no(boot_cpu_has(X86_FEATURE_FPU)), c->cpuid_level); } #else diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 851b561850e0c2..5fcb3d635d9158 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -1158,11 +1158,12 @@ static __init int snc_get_config(void) ret = cpus_per_l3 / cpus_per_node; - /* sanity check: Only valid results are 1, 2, 3, 4 */ + /* sanity check: Only valid results are 1, 2, 3, 4, 6 */ switch (ret) { case 1: break; case 2 ... 4: + case 6: pr_info("Sub-NUMA Cluster mode detected with %d nodes per L3 cache\n", ret); rdt_resources_all[RDT_RESOURCE_L3].r_resctrl.mon_scope = RESCTRL_L3_NODE; break; diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index d7163b764c6268..d906a1cd849178 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -1596,7 +1596,7 @@ static void mondata_config_read(struct rdt_mon_domain *d, struct mon_config_info static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid) { - struct mon_config_info mon_info = {0}; + struct mon_config_info mon_info; struct rdt_mon_domain *dom; bool sep = false; diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index c84c30188fdf24..16f3ca30626ab2 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -24,34 +24,36 @@ struct cpuid_bit { * levels are different and there is a separate entry for each. */ static const struct cpuid_bit cpuid_bits[] = { - { X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 }, - { X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 }, - { X86_FEATURE_INTEL_PPIN, CPUID_EBX, 0, 0x00000007, 1 }, - { X86_FEATURE_RRSBA_CTRL, CPUID_EDX, 2, 0x00000007, 2 }, - { X86_FEATURE_BHI_CTRL, CPUID_EDX, 4, 0x00000007, 2 }, - { X86_FEATURE_CQM_LLC, CPUID_EDX, 1, 0x0000000f, 0 }, - { X86_FEATURE_CQM_OCCUP_LLC, CPUID_EDX, 0, 0x0000000f, 1 }, - { X86_FEATURE_CQM_MBM_TOTAL, CPUID_EDX, 1, 0x0000000f, 1 }, - { X86_FEATURE_CQM_MBM_LOCAL, CPUID_EDX, 2, 0x0000000f, 1 }, - { X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 }, - { X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 }, - { X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 }, - { X86_FEATURE_CDP_L2, CPUID_ECX, 2, 0x00000010, 2 }, - { X86_FEATURE_MBA, CPUID_EBX, 3, 0x00000010, 0 }, - { X86_FEATURE_PER_THREAD_MBA, CPUID_ECX, 0, 0x00000010, 3 }, - { X86_FEATURE_SGX1, CPUID_EAX, 0, 0x00000012, 0 }, - { X86_FEATURE_SGX2, CPUID_EAX, 1, 0x00000012, 0 }, - { X86_FEATURE_SGX_EDECCSSA, CPUID_EAX, 11, 0x00000012, 0 }, - { X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 }, - { X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 }, - { X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 }, - { X86_FEATURE_FAST_CPPC, CPUID_EDX, 15, 0x80000007, 0 }, - { X86_FEATURE_MBA, CPUID_EBX, 6, 0x80000008, 0 }, - { X86_FEATURE_SMBA, CPUID_EBX, 2, 0x80000020, 0 }, - { X86_FEATURE_BMEC, CPUID_EBX, 3, 0x80000020, 0 }, - { X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 }, - { X86_FEATURE_AMD_LBR_V2, CPUID_EAX, 1, 0x80000022, 0 }, + { X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 }, + { X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 }, + { X86_FEATURE_INTEL_PPIN, CPUID_EBX, 0, 0x00000007, 1 }, + { X86_FEATURE_RRSBA_CTRL, CPUID_EDX, 2, 0x00000007, 2 }, + { X86_FEATURE_BHI_CTRL, CPUID_EDX, 4, 0x00000007, 2 }, + { X86_FEATURE_CQM_LLC, CPUID_EDX, 1, 0x0000000f, 0 }, + { X86_FEATURE_CQM_OCCUP_LLC, CPUID_EDX, 0, 0x0000000f, 1 }, + { X86_FEATURE_CQM_MBM_TOTAL, CPUID_EDX, 1, 0x0000000f, 1 }, + { X86_FEATURE_CQM_MBM_LOCAL, CPUID_EDX, 2, 0x0000000f, 1 }, + { X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 }, + { X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 }, + { X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 }, + { X86_FEATURE_CDP_L2, CPUID_ECX, 2, 0x00000010, 2 }, + { X86_FEATURE_MBA, CPUID_EBX, 3, 0x00000010, 0 }, + { X86_FEATURE_PER_THREAD_MBA, CPUID_ECX, 0, 0x00000010, 3 }, + { X86_FEATURE_SGX1, CPUID_EAX, 0, 0x00000012, 0 }, + { X86_FEATURE_SGX2, CPUID_EAX, 1, 0x00000012, 0 }, + { X86_FEATURE_SGX_EDECCSSA, CPUID_EAX, 11, 0x00000012, 0 }, + { X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 }, + { X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 }, + { X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 }, + { X86_FEATURE_AMD_FAST_CPPC, CPUID_EDX, 15, 0x80000007, 0 }, + { X86_FEATURE_MBA, CPUID_EBX, 6, 0x80000008, 0 }, + { X86_FEATURE_SMBA, CPUID_EBX, 2, 0x80000020, 0 }, + { X86_FEATURE_BMEC, CPUID_EBX, 3, 0x80000020, 0 }, + { X86_FEATURE_AMD_WORKLOAD_CLASS, CPUID_EAX, 22, 0x80000021, 0 }, + { X86_FEATURE_PERFMON_V2, CPUID_EAX, 0, 0x80000022, 0 }, + { X86_FEATURE_AMD_LBR_V2, CPUID_EAX, 1, 0x80000022, 0 }, { X86_FEATURE_AMD_LBR_PMC_FREEZE, CPUID_EAX, 2, 0x80000022, 0 }, + { X86_FEATURE_AMD_HETEROGENEOUS_CORES, CPUID_EAX, 30, 0x80000026, 0 }, { 0, 0, 0, 0, 0 } }; diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c index 9ace84486499b8..8ce352fc72ac3d 100644 --- a/arch/x86/kernel/cpu/sgx/main.c +++ b/arch/x86/kernel/cpu/sgx/main.c @@ -630,7 +630,7 @@ static bool __init sgx_setup_epc_section(u64 phys_addr, u64 size, if (!section->virt_addr) return false; - section->pages = vmalloc(nr_pages * sizeof(struct sgx_epc_page)); + section->pages = vmalloc_array(nr_pages, sizeof(struct sgx_epc_page)); if (!section->pages) { memunmap(section->virt_addr); return false; @@ -901,19 +901,15 @@ static struct miscdevice sgx_dev_provision = { int sgx_set_attribute(unsigned long *allowed_attributes, unsigned int attribute_fd) { - struct fd f = fdget(attribute_fd); + CLASS(fd, f)(attribute_fd); - if (!fd_file(f)) + if (fd_empty(f)) return -EINVAL; - if (fd_file(f)->f_op != &sgx_provision_fops) { - fdput(f); + if (fd_file(f)->f_op != &sgx_provision_fops) return -EINVAL; - } *allowed_attributes |= SGX_ATTR_PROVISIONKEY; - - fdput(f); return 0; } EXPORT_SYMBOL_GPL(sgx_set_attribute); diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c index 621a151ccf7d0a..b2e313ea17bf6f 100644 --- a/arch/x86/kernel/cpu/topology.c +++ b/arch/x86/kernel/cpu/topology.c @@ -428,8 +428,8 @@ void __init topology_apply_cmdline_limits_early(void) { unsigned int possible = nr_cpu_ids; - /* 'maxcpus=0' 'nosmp' 'nolapic' 'disableapic' 'noapic' */ - if (!setup_max_cpus || ioapic_is_disabled || apic_is_disabled) + /* 'maxcpus=0' 'nosmp' 'nolapic' 'disableapic' */ + if (!setup_max_cpus || apic_is_disabled) possible = 1; /* 'possible_cpus=N' */ @@ -443,7 +443,7 @@ void __init topology_apply_cmdline_limits_early(void) static __init bool restrict_to_up(void) { - if (!smp_found_config || ioapic_is_disabled) + if (!smp_found_config) return true; /* * XEN PV is special as it does not advertise the local APIC diff --git a/arch/x86/kernel/cpu/topology_amd.c b/arch/x86/kernel/cpu/topology_amd.c index 7d476fa697ca53..03b3c9c3a45e2e 100644 --- a/arch/x86/kernel/cpu/topology_amd.c +++ b/arch/x86/kernel/cpu/topology_amd.c @@ -182,6 +182,9 @@ static void parse_topology_amd(struct topo_scan *tscan) if (cpu_feature_enabled(X86_FEATURE_TOPOEXT)) has_topoext = cpu_parse_topology_ext(tscan); + if (cpu_feature_enabled(X86_FEATURE_AMD_HETEROGENEOUS_CORES)) + tscan->c->topo.cpu_type = cpuid_ebx(0x80000026); + if (!has_topoext && !parse_8000_0008(tscan)) return; diff --git a/arch/x86/kernel/cpu/topology_common.c b/arch/x86/kernel/cpu/topology_common.c index 9a6069e7133c9c..8277c64f88dbfd 100644 --- a/arch/x86/kernel/cpu/topology_common.c +++ b/arch/x86/kernel/cpu/topology_common.c @@ -3,6 +3,7 @@ #include +#include #include #include #include @@ -27,6 +28,36 @@ void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom, } } +enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c) +{ + if (c->x86_vendor == X86_VENDOR_INTEL) { + switch (c->topo.intel_type) { + case INTEL_CPU_TYPE_ATOM: return TOPO_CPU_TYPE_EFFICIENCY; + case INTEL_CPU_TYPE_CORE: return TOPO_CPU_TYPE_PERFORMANCE; + } + } + if (c->x86_vendor == X86_VENDOR_AMD) { + switch (c->topo.amd_type) { + case 0: return TOPO_CPU_TYPE_PERFORMANCE; + case 1: return TOPO_CPU_TYPE_EFFICIENCY; + } + } + + return TOPO_CPU_TYPE_UNKNOWN; +} + +const char *get_topology_cpu_type_name(struct cpuinfo_x86 *c) +{ + switch (get_topology_cpu_type(c)) { + case TOPO_CPU_TYPE_PERFORMANCE: + return "performance"; + case TOPO_CPU_TYPE_EFFICIENCY: + return "efficiency"; + default: + return "unknown"; + } +} + static unsigned int __maybe_unused parse_num_cores_legacy(struct cpuinfo_x86 *c) { struct { @@ -87,6 +118,7 @@ static void parse_topology(struct topo_scan *tscan, bool early) .cu_id = 0xff, .llc_id = BAD_APICID, .l2c_id = BAD_APICID, + .cpu_type = TOPO_CPU_TYPE_UNKNOWN, }; struct cpuinfo_x86 *c = tscan->c; struct { @@ -132,6 +164,8 @@ static void parse_topology(struct topo_scan *tscan, bool early) case X86_VENDOR_INTEL: if (!IS_ENABLED(CONFIG_CPU_SUP_INTEL) || !cpu_parse_topology_ext(tscan)) parse_legacy(tscan); + if (c->cpuid_level >= 0x1a) + c->topo.cpu_type = cpuid_eax(0x1a); break; case X86_VENDOR_HYGON: if (IS_ENABLED(CONFIG_CPU_SUP_HYGON)) diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 64280879c68c02..59d23cdf4ed0fa 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -305,7 +305,7 @@ void __init x86_flattree_get_config(void) map_len = size; } - early_init_dt_verify(dt); + early_init_dt_verify(dt, __pa(dt)); } unflatten_and_copy_device_tree(); diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index 29d1f9104e9494..6b6f32f40cbeb4 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 1065ab995305cd..8f62e0666dea51 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -63,16 +63,6 @@ static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf, return true; } -/* - * Update the value of PKRU register that was already pushed onto the signal frame. - */ -static inline int update_pkru_in_sigframe(struct xregs_state __user *buf, u32 pkru) -{ - if (unlikely(!cpu_feature_enabled(X86_FEATURE_OSPKE))) - return 0; - return __put_user(pkru, (unsigned int __user *)get_xsave_addr_user(buf, XFEATURE_PKRU)); -} - /* * Signal frame handlers. */ @@ -168,14 +158,8 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame, static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf, u32 pkru) { - int err = 0; - - if (use_xsave()) { - err = xsave_to_user_sigframe(buf); - if (!err) - err = update_pkru_in_sigframe(buf, pkru); - return err; - } + if (use_xsave()) + return xsave_to_user_sigframe(buf, pkru); if (use_fxsr()) return fxsave_to_user_sigframe((struct fxregs_state __user *) buf); diff --git a/arch/x86/kernel/fpu/xstate.h b/arch/x86/kernel/fpu/xstate.h index 0b86a5002c846d..aa16f1a1bbcf17 100644 --- a/arch/x86/kernel/fpu/xstate.h +++ b/arch/x86/kernel/fpu/xstate.h @@ -69,6 +69,28 @@ static inline u64 xfeatures_mask_independent(void) return fpu_kernel_cfg.independent_features; } +/* + * Update the value of PKRU register that was already pushed onto the signal frame. + */ +static inline int update_pkru_in_sigframe(struct xregs_state __user *buf, u64 mask, u32 pkru) +{ + u64 xstate_bv; + int err; + + if (unlikely(!cpu_feature_enabled(X86_FEATURE_OSPKE))) + return 0; + + /* Mark PKRU as in-use so that it is restored correctly. */ + xstate_bv = (mask & xfeatures_in_use()) | XFEATURE_MASK_PKRU; + + err = __put_user(xstate_bv, &buf->header.xfeatures); + if (err) + return err; + + /* Update PKRU value in the userspace xsave buffer. */ + return __put_user(pkru, (unsigned int __user *)get_xsave_addr_user(buf, XFEATURE_PKRU)); +} + /* XSAVE/XRSTOR wrapper functions */ #ifdef CONFIG_X86_64 @@ -256,7 +278,7 @@ static inline u64 xfeatures_need_sigframe_write(void) * The caller has to zero buf::header before calling this because XSAVE* * does not touch the reserved fields in the header. */ -static inline int xsave_to_user_sigframe(struct xregs_state __user *buf) +static inline int xsave_to_user_sigframe(struct xregs_state __user *buf, u32 pkru) { /* * Include the features which are not xsaved/rstored by the kernel @@ -281,6 +303,9 @@ static inline int xsave_to_user_sigframe(struct xregs_state __user *buf) XSTATE_OP(XSAVE, buf, lmask, hmask, err); clac(); + if (!err) + err = update_pkru_in_sigframe(buf, mask, pkru); + return err; } diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 8da0e66ca22dec..4dd0ad6c94d661 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -118,10 +118,13 @@ ftrace_modify_code_direct(unsigned long ip, const char *old_code, return ret; /* replace the text with the new text */ - if (ftrace_poke_late) + if (ftrace_poke_late) { text_poke_queue((void *)ip, new_code, MCOUNT_INSN_SIZE, NULL); - else - text_poke_early((void *)ip, new_code, MCOUNT_INSN_SIZE); + } else { + mutex_lock(&text_mutex); + text_poke((void *)ip, new_code, MCOUNT_INSN_SIZE); + mutex_unlock(&text_mutex); + } return 0; } @@ -318,7 +321,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) unsigned const char op_ref[] = { 0x48, 0x8b, 0x15 }; unsigned const char retq[] = { RET_INSN_OPCODE, INT3_INSN_OPCODE }; union ftrace_op_code_union op_ptr; - int ret; + void *ret; if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) { start_offset = (unsigned long)ftrace_regs_caller; @@ -349,15 +352,15 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) npages = DIV_ROUND_UP(*tramp_size, PAGE_SIZE); /* Copy ftrace_caller onto the trampoline memory */ - ret = copy_from_kernel_nofault(trampoline, (void *)start_offset, size); - if (WARN_ON(ret < 0)) + ret = text_poke_copy(trampoline, (void *)start_offset, size); + if (WARN_ON(!ret)) goto fail; ip = trampoline + size; if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) __text_gen_insn(ip, JMP32_INSN_OPCODE, ip, x86_return_thunk, JMP32_INSN_SIZE); else - memcpy(ip, retq, sizeof(retq)); + text_poke_copy(ip, retq, sizeof(retq)); /* No need to test direct calls on created trampolines */ if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) { @@ -365,8 +368,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) ip = trampoline + (jmp_offset - start_offset); if (WARN_ON(*(char *)ip != 0x75)) goto fail; - ret = copy_from_kernel_nofault(ip, x86_nops[2], 2); - if (ret < 0) + if (!text_poke_copy(ip, x86_nops[2], 2)) goto fail; } @@ -379,7 +381,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) */ ptr = (unsigned long *)(trampoline + size + RET_SIZE); - *ptr = (unsigned long)ops; + text_poke_copy(ptr, &ops, sizeof(unsigned long)); op_offset -= start_offset; memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE); @@ -395,7 +397,7 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) op_ptr.offset = offset; /* put in the new offset to the ftrace_ops */ - memcpy(trampoline + op_offset, &op_ptr, OP_REF_SIZE); + text_poke_copy(trampoline + op_offset, &op_ptr, OP_REF_SIZE); /* put in the call to the function */ mutex_lock(&text_mutex); @@ -405,9 +407,9 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) * the depth accounting before the call already. */ dest = ftrace_ops_get_func(ops); - memcpy(trampoline + call_offset, - text_gen_insn(CALL_INSN_OPCODE, trampoline + call_offset, dest), - CALL_INSN_SIZE); + text_poke_copy_locked(trampoline + call_offset, + text_gen_insn(CALL_INSN_OPCODE, trampoline + call_offset, dest), + CALL_INSN_SIZE, false); mutex_unlock(&text_mutex); /* ALLOC_TRAMP flags lets us know we created it */ @@ -647,7 +649,7 @@ void prepare_ftrace_return(unsigned long ip, unsigned long *parent, void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct ftrace_regs *fregs) { - struct pt_regs *regs = &fregs->regs; + struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs; unsigned long *stack = (unsigned long *)kernel_stack_pointer(regs); prepare_ftrace_return(ip, (unsigned long *)stack, 0); diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 16752b8dfa8992..56163e2124cf3a 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -77,6 +77,7 @@ SYM_CODE_START_NOALIGN(startup_64) lretq .Lon_kernel_cs: + ANNOTATE_NOENDBR UNWIND_HINT_END_OF_STACK #ifdef CONFIG_AMD_MEM_ENCRYPT diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c index 15af7e98e161a4..2be55ec3f392c1 100644 --- a/arch/x86/kernel/kprobes/ftrace.c +++ b/arch/x86/kernel/kprobes/ftrace.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "common.h" @@ -36,23 +37,25 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, if (kprobe_running()) { kprobes_inc_nmissed_count(p); } else { - unsigned long orig_ip = regs->ip; + unsigned long orig_ip = instruction_pointer(regs); + /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */ - regs->ip = ip + sizeof(kprobe_opcode_t); + instruction_pointer_set(regs, ip + INT3_INSN_SIZE); __this_cpu_write(current_kprobe, p); kcb->kprobe_status = KPROBE_HIT_ACTIVE; if (!p->pre_handler || !p->pre_handler(p, regs)) { - /* - * Emulate singlestep (and also recover regs->ip) - * as if there is a 5byte nop - */ - regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE; if (unlikely(p->post_handler)) { + /* + * Emulate singlestep (and also recover regs->ip) + * as if there is a 5byte nop + */ + instruction_pointer_set(regs, ip + MCOUNT_INSN_SIZE); kcb->kprobe_status = KPROBE_HIT_SSDONE; p->post_handler(p, regs, 0); } - regs->ip = orig_ip; + /* Recover IP address */ + instruction_pointer_set(regs, orig_ip); } /* * If pre_handler returns !0, it changes regs->ip. We have to diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 837450b6e882f7..8984abd91c001f 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -146,18 +146,21 @@ static int __write_relocate_add(Elf64_Shdr *sechdrs, } if (apply) { - if (memcmp(loc, &zero, size)) { + void *wr_loc = module_writable_address(me, loc); + + if (memcmp(wr_loc, &zero, size)) { pr_err("x86/modules: Invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n", (int)ELF64_R_TYPE(rel[i].r_info), loc, val); return -ENOEXEC; } - write(loc, &val, size); + write(wr_loc, &val, size); } else { if (memcmp(loc, &val, size)) { pr_warn("x86/modules: Invalid relocation target, existing value does not match expected value for type %d, loc %p, val %Lx\n", (int)ELF64_R_TYPE(rel[i].r_info), loc, val); return -ENOEXEC; } + /* FIXME: needs care for ROX module allocations */ write(loc, &zero, size); } } @@ -224,7 +227,7 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { - const Elf_Shdr *s, *alt = NULL, *locks = NULL, + const Elf_Shdr *s, *alt = NULL, *orc = NULL, *orc_ip = NULL, *retpolines = NULL, *returns = NULL, *ibt_endbr = NULL, *calls = NULL, *cfi = NULL; @@ -233,8 +236,6 @@ int module_finalize(const Elf_Ehdr *hdr, for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { if (!strcmp(".altinstructions", secstrings + s->sh_name)) alt = s; - if (!strcmp(".smp_locks", secstrings + s->sh_name)) - locks = s; if (!strcmp(".orc_unwind", secstrings + s->sh_name)) orc = s; if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name)) @@ -265,20 +266,20 @@ int module_finalize(const Elf_Ehdr *hdr, csize = cfi->sh_size; } - apply_fineibt(rseg, rseg + rsize, cseg, cseg + csize); + apply_fineibt(rseg, rseg + rsize, cseg, cseg + csize, me); } if (retpolines) { void *rseg = (void *)retpolines->sh_addr; - apply_retpolines(rseg, rseg + retpolines->sh_size); + apply_retpolines(rseg, rseg + retpolines->sh_size, me); } if (returns) { void *rseg = (void *)returns->sh_addr; - apply_returns(rseg, rseg + returns->sh_size); + apply_returns(rseg, rseg + returns->sh_size, me); } if (alt) { /* patch .altinstructions */ void *aseg = (void *)alt->sh_addr; - apply_alternatives(aseg, aseg + alt->sh_size); + apply_alternatives(aseg, aseg + alt->sh_size, me); } if (calls || alt) { struct callthunk_sites cs = {}; @@ -297,8 +298,28 @@ int module_finalize(const Elf_Ehdr *hdr, } if (ibt_endbr) { void *iseg = (void *)ibt_endbr->sh_addr; - apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size); + apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size, me); } + + if (orc && orc_ip) + unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size, + (void *)orc->sh_addr, orc->sh_size); + + return 0; +} + +int module_post_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + const Elf_Shdr *s, *locks = NULL; + char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { + if (!strcmp(".smp_locks", secstrings + s->sh_name)) + locks = s; + } + if (locks) { void *lseg = (void *)locks->sh_addr; void *text = me->mem[MOD_TEXT].base; @@ -308,10 +329,6 @@ int module_finalize(const Elf_Ehdr *hdr, text, text_end); } - if (orc && orc_ip) - unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size, - (void *)orc->sh_addr, orc->sh_size); - return 0; } diff --git a/arch/x86/kernel/relocate_kernel_64.S b/arch/x86/kernel/relocate_kernel_64.S index e9e88c342f752e..540443d699e3c2 100644 --- a/arch/x86/kernel/relocate_kernel_64.S +++ b/arch/x86/kernel/relocate_kernel_64.S @@ -13,6 +13,7 @@ #include #include #include +#include /* * Must be relocatable PIC code callable as a C function, in particular @@ -242,6 +243,13 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped) movq CR0(%r8), %r8 movq %rax, %cr3 movq %r8, %cr0 + +#ifdef CONFIG_KEXEC_JUMP + /* Saved in save_processor_state. */ + movq $saved_context, %rax + lgdt saved_context_gdt_desc(%rax) +#endif + movq %rbp, %rax popf diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 766f092dab80b3..b5a8f0891135b1 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -497,8 +497,9 @@ static int x86_cluster_flags(void) static int x86_die_flags(void) { - if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU)) - return x86_sched_itmt_flags(); + if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU) || + cpu_feature_enabled(X86_FEATURE_AMD_HETEROGENEOUS_CORES)) + return x86_sched_itmt_flags(); return 0; } diff --git a/arch/x86/kernel/static_call.c b/arch/x86/kernel/static_call.c index 4eefaac64c6cba..9eed0c144dad51 100644 --- a/arch/x86/kernel/static_call.c +++ b/arch/x86/kernel/static_call.c @@ -172,6 +172,15 @@ void arch_static_call_transform(void *site, void *tramp, void *func, bool tail) } EXPORT_SYMBOL_GPL(arch_static_call_transform); +noinstr void __static_call_update_early(void *tramp, void *func) +{ + BUG_ON(system_state != SYSTEM_BOOTING); + BUG_ON(!early_boot_irqs_disabled); + BUG_ON(static_call_initialized); + __text_gen_insn(tramp, JMP32_INSN_OPCODE, tramp, func, JMP32_INSN_SIZE); + sync_core(); +} + #ifdef CONFIG_MITIGATION_RETHUNK /* * This is called by apply_returns() to fix up static call trampolines, diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 87f8c9a71c4964..776ae6fa7f2d67 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,8 +26,10 @@ /* * Align a virtual address to avoid aliasing in the I$ on AMD F15h. */ -static unsigned long get_align_mask(void) +static unsigned long get_align_mask(struct file *filp) { + if (filp && is_file_hugepages(filp)) + return huge_page_mask_align(filp); /* handle 32- and 64-bit case with a single conditional */ if (va_align.flags < 0 || !(va_align.flags & (2 - mmap_is_ia32()))) return 0; @@ -49,7 +52,7 @@ static unsigned long get_align_mask(void) */ static unsigned long get_align_bits(void) { - return va_align.bits & get_align_mask(); + return va_align.bits & get_align_mask(NULL); } static int __init control_va_addr_alignment(char *str) @@ -148,12 +151,15 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, info.length = len; info.low_limit = begin; info.high_limit = end; - info.align_offset = pgoff << PAGE_SHIFT; - info.start_gap = stack_guard_placement(vm_flags); + if (!(filp && is_file_hugepages(filp))) { + info.align_offset = pgoff << PAGE_SHIFT; + info.start_gap = stack_guard_placement(vm_flags); + } if (filp) { - info.align_mask = get_align_mask(); + info.align_mask = get_align_mask(filp); info.align_offset += get_align_bits(); } + return vm_unmapped_area(&info); } @@ -199,7 +205,10 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr0, info.low_limit = PAGE_SIZE; info.high_limit = get_mmap_base(0); - info.start_gap = stack_guard_placement(vm_flags); + if (!(filp && is_file_hugepages(filp))) { + info.start_gap = stack_guard_placement(vm_flags); + info.align_offset = pgoff << PAGE_SHIFT; + } /* * If hint address is above DEFAULT_MAP_WINDOW, look for unmapped area @@ -211,9 +220,8 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr0, if (addr > DEFAULT_MAP_WINDOW && !in_32bit_syscall()) info.high_limit += TASK_SIZE_MAX - DEFAULT_MAP_WINDOW; - info.align_offset = pgoff << PAGE_SHIFT; if (filp) { - info.align_mask = get_align_mask(); + info.align_mask = get_align_mask(filp); info.align_offset += get_align_bits(); } addr = vm_unmapped_area(&info); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index dfe6847fd99e5e..67aeaba4ba9c86 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -174,10 +174,11 @@ static void __set_cyc2ns_scale(unsigned long khz, int cpu, unsigned long long ts c2n = per_cpu_ptr(&cyc2ns, cpu); - raw_write_seqcount_latch(&c2n->seq); + write_seqcount_latch_begin(&c2n->seq); c2n->data[0] = data; - raw_write_seqcount_latch(&c2n->seq); + write_seqcount_latch(&c2n->seq); c2n->data[1] = data; + write_seqcount_latch_end(&c2n->seq); } static void set_cyc2ns_scale(unsigned long khz, int cpu, unsigned long long tsc_now) diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index d00c28aaa5be45..d4705a348a8045 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -723,7 +723,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, state->sp = task->thread.sp + sizeof(*frame); state->bp = READ_ONCE_NOCHECK(frame->bp); state->ip = READ_ONCE_NOCHECK(frame->ret_addr); - state->signal = (void *)state->ip == ret_from_fork; + state->signal = (void *)state->ip == ret_from_fork_asm; } if (get_stack_info((unsigned long *)state->sp, state->task, diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index feb8102a9ca78c..6a17396c8174e9 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -193,29 +193,6 @@ SECTIONS ORC_UNWIND_TABLE - . = ALIGN(PAGE_SIZE); - __vvar_page = .; - - .vvar : AT(ADDR(.vvar) - LOAD_OFFSET) { - /* work around gold bug 13023 */ - __vvar_beginning_hack = .; - - /* Place all vvars at the offsets in asm/vvar.h. */ -#define EMIT_VVAR(name, offset) \ - . = __vvar_beginning_hack + offset; \ - *(.vvar_ ## name) -#include -#undef EMIT_VVAR - - /* - * Pad the rest of the page with zeros. Otherwise the loader - * can leave garbage here. - */ - . = __vvar_beginning_hack + PAGE_SIZE; - } :data - - . = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE); - /* Init code and data - will be freed after init */ . = ALIGN(PAGE_SIZE); .init.begin : AT(ADDR(.init.begin) - LOAD_OFFSET) { @@ -443,6 +420,10 @@ SECTIONS STABS_DEBUG DWARF_DEBUG +#ifdef CONFIG_PROPELLER_CLANG + .llvm_bb_addr_map : { *(.llvm_bb_addr_map) } +#endif + ELF_DETAILS DISCARDS @@ -531,3 +512,18 @@ INIT_PER_CPU(irq_stack_backing_store); #endif #endif /* CONFIG_X86_64 */ + +/* + * The symbols below are referenced using relative relocations in the + * respective ELF notes. This produces build time constants that the + * linker will never mark as relocatable. (Using just ABSOLUTE() is not + * sufficient for that). + */ +#ifdef CONFIG_XEN_PV +xen_elfnote_entry_value = + ABSOLUTE(xen_elfnote_entry) + ABSOLUTE(startup_xen); +#endif +#ifdef CONFIG_PVH +xen_elfnote_phys32_entry_value = + ABSOLUTE(xen_elfnote_phys32_entry) + ABSOLUTE(pvh_start_xen - LOAD_OFFSET); +#endif diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index f09f13c01c6bbd..ea2c4f21c1ca9b 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -18,10 +18,10 @@ menuconfig VIRTUALIZATION if VIRTUALIZATION config KVM_X86 - def_tristate KVM if KVM_INTEL || KVM_AMD - depends on X86_LOCAL_APIC + def_tristate KVM if (KVM_INTEL != n || KVM_AMD != n) select KVM_COMMON select KVM_GENERIC_MMU_NOTIFIER + select KVM_ELIDE_TLB_FLUSH_IF_YOUNG select HAVE_KVM_IRQCHIP select HAVE_KVM_PFNCACHE select HAVE_KVM_DIRTY_RING_TSO @@ -29,6 +29,7 @@ config KVM_X86 select HAVE_KVM_IRQ_BYPASS select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_READONLY_MEM + select VHOST_TASK select KVM_ASYNC_PF select USER_RETURN_NOTIFIER select KVM_MMIO @@ -49,6 +50,7 @@ config KVM_X86 config KVM tristate "Kernel-based Virtual Machine (KVM) support" + depends on X86_LOCAL_APIC help Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 41786b834b1635..ae0b438a2c991c 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -36,6 +36,26 @@ u32 kvm_cpu_caps[NR_KVM_CPU_CAPS] __read_mostly; EXPORT_SYMBOL_GPL(kvm_cpu_caps); +struct cpuid_xstate_sizes { + u32 eax; + u32 ebx; + u32 ecx; +}; + +static struct cpuid_xstate_sizes xstate_sizes[XFEATURE_MAX] __ro_after_init; + +void __init kvm_init_xstate_sizes(void) +{ + u32 ign; + int i; + + for (i = XFEATURE_YMM; i < ARRAY_SIZE(xstate_sizes); i++) { + struct cpuid_xstate_sizes *xs = &xstate_sizes[i]; + + cpuid_count(0xD, i, &xs->eax, &xs->ebx, &xs->ecx, &ign); + } +} + u32 xstate_required_size(u64 xstate_bv, bool compacted) { int feature_bit = 0; @@ -44,14 +64,15 @@ u32 xstate_required_size(u64 xstate_bv, bool compacted) xstate_bv &= XFEATURE_MASK_EXTEND; while (xstate_bv) { if (xstate_bv & 0x1) { - u32 eax, ebx, ecx, edx, offset; - cpuid_count(0xD, feature_bit, &eax, &ebx, &ecx, &edx); + struct cpuid_xstate_sizes *xs = &xstate_sizes[feature_bit]; + u32 offset; + /* ECX[1]: 64B alignment in compacted form */ if (compacted) - offset = (ecx & 0x2) ? ALIGN(ret, 64) : ret; + offset = (xs->ecx & 0x2) ? ALIGN(ret, 64) : ret; else - offset = ebx; - ret = max(ret, offset + eax); + offset = xs->ebx; + ret = max(ret, offset + xs->eax); } xstate_bv >>= 1; @@ -690,7 +711,9 @@ void kvm_set_cpu_caps(void) kvm_cpu_cap_set(X86_FEATURE_TSC_ADJUST); kvm_cpu_cap_set(X86_FEATURE_ARCH_CAPABILITIES); - if (boot_cpu_has(X86_FEATURE_IBPB) && boot_cpu_has(X86_FEATURE_IBRS)) + if (boot_cpu_has(X86_FEATURE_AMD_IBPB_RET) && + boot_cpu_has(X86_FEATURE_AMD_IBPB) && + boot_cpu_has(X86_FEATURE_AMD_IBRS)) kvm_cpu_cap_set(X86_FEATURE_SPEC_CTRL); if (boot_cpu_has(X86_FEATURE_STIBP)) kvm_cpu_cap_set(X86_FEATURE_INTEL_STIBP); @@ -698,14 +721,14 @@ void kvm_set_cpu_caps(void) kvm_cpu_cap_set(X86_FEATURE_SPEC_CTRL_SSBD); kvm_cpu_cap_mask(CPUID_7_1_EAX, - F(AVX_VNNI) | F(AVX512_BF16) | F(CMPCCXADD) | - F(FZRM) | F(FSRS) | F(FSRC) | - F(AMX_FP16) | F(AVX_IFMA) | F(LAM) + F(SHA512) | F(SM3) | F(SM4) | F(AVX_VNNI) | F(AVX512_BF16) | + F(CMPCCXADD) | F(FZRM) | F(FSRS) | F(FSRC) | F(AMX_FP16) | + F(AVX_IFMA) | F(LAM) ); kvm_cpu_cap_init_kvm_defined(CPUID_7_1_EDX, - F(AVX_VNNI_INT8) | F(AVX_NE_CONVERT) | F(PREFETCHITI) | - F(AMX_COMPLEX) | F(AVX10) + F(AVX_VNNI_INT8) | F(AVX_NE_CONVERT) | F(AMX_COMPLEX) | + F(AVX_VNNI_INT16) | F(PREFETCHITI) | F(AVX10) ); kvm_cpu_cap_init_kvm_defined(CPUID_7_2_EDX, @@ -755,7 +778,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) | - F(AMD_PSFD) + F(AMD_PSFD) | F(AMD_IBPB_RET) ); /* @@ -763,8 +786,12 @@ void kvm_set_cpu_caps(void) * arch/x86/kernel/cpu/bugs.c is kind enough to * record that in cpufeatures so use them. */ - if (boot_cpu_has(X86_FEATURE_IBPB)) + if (boot_cpu_has(X86_FEATURE_IBPB)) { kvm_cpu_cap_set(X86_FEATURE_AMD_IBPB); + if (boot_cpu_has(X86_FEATURE_SPEC_CTRL) && + !boot_cpu_has_bug(X86_BUG_EIBRS_PBRSB)) + kvm_cpu_cap_set(X86_FEATURE_AMD_IBPB_RET); + } if (boot_cpu_has(X86_FEATURE_IBRS)) kvm_cpu_cap_set(X86_FEATURE_AMD_IBRS); if (boot_cpu_has(X86_FEATURE_STIBP)) diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 41697cca354e6b..f16a7b2c2adcf4 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -2,7 +2,6 @@ #ifndef ARCH_X86_KVM_CPUID_H #define ARCH_X86_KVM_CPUID_H -#include "x86.h" #include "reverse_cpuid.h" #include #include @@ -32,6 +31,7 @@ int kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu, bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, bool exact_only); +void __init kvm_init_xstate_sizes(void); u32 xstate_required_size(u64 xstate_bv, bool compacted); int cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index e72aed25d72126..60986f67c35a88 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -651,9 +651,10 @@ static inline u8 ctxt_virt_addr_bits(struct x86_emulate_ctxt *ctxt) } static inline bool emul_is_noncanonical_address(u64 la, - struct x86_emulate_ctxt *ctxt) + struct x86_emulate_ctxt *ctxt, + unsigned int flags) { - return !__is_canonical_address(la, ctxt_virt_addr_bits(ctxt)); + return !ctxt->ops->is_canonical_addr(ctxt, la, flags); } /* @@ -1733,7 +1734,8 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (ret != X86EMUL_CONTINUE) return ret; if (emul_is_noncanonical_address(get_desc_base(&seg_desc) | - ((u64)base3 << 32), ctxt)) + ((u64)base3 << 32), ctxt, + X86EMUL_F_DT_LOAD)) return emulate_gp(ctxt, err_code); } @@ -2516,8 +2518,8 @@ static int em_sysexit(struct x86_emulate_ctxt *ctxt) ss_sel = cs_sel + 8; cs.d = 0; cs.l = 1; - if (emul_is_noncanonical_address(rcx, ctxt) || - emul_is_noncanonical_address(rdx, ctxt)) + if (emul_is_noncanonical_address(rcx, ctxt, 0) || + emul_is_noncanonical_address(rdx, ctxt, 0)) return emulate_gp(ctxt, 0); break; } @@ -3494,7 +3496,8 @@ static int em_lgdt_lidt(struct x86_emulate_ctxt *ctxt, bool lgdt) if (rc != X86EMUL_CONTINUE) return rc; if (ctxt->mode == X86EMUL_MODE_PROT64 && - emul_is_noncanonical_address(desc_ptr.address, ctxt)) + emul_is_noncanonical_address(desc_ptr.address, ctxt, + X86EMUL_F_DT_LOAD)) return emulate_gp(ctxt, 0); if (lgdt) ctxt->ops->set_gdt(ctxt, &desc_ptr); diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h index b1eb46e26b2e69..36a8786db29162 100644 --- a/arch/x86/kvm/kvm_cache_regs.h +++ b/arch/x86/kvm/kvm_cache_regs.h @@ -43,6 +43,18 @@ BUILD_KVM_GPR_ACCESSORS(r14, R14) BUILD_KVM_GPR_ACCESSORS(r15, R15) #endif +/* + * Using the register cache from interrupt context is generally not allowed, as + * caching a register and marking it available/dirty can't be done atomically, + * i.e. accesses from interrupt context may clobber state or read stale data if + * the vCPU task is in the process of updating the cache. The exception is if + * KVM is handling a PMI IRQ/NMI VM-Exit, as that bound code sequence doesn't + * touch the cache, it runs after the cache is reset (post VM-Exit), and PMIs + * need to access several registers that are cacheable. + */ +#define kvm_assert_register_caching_allowed(vcpu) \ + lockdep_assert_once(in_task() || kvm_arch_pmi_in_guest(vcpu)) + /* * avail dirty * 0 0 register in VMCS/VMCB @@ -53,24 +65,28 @@ BUILD_KVM_GPR_ACCESSORS(r15, R15) static inline bool kvm_register_is_available(struct kvm_vcpu *vcpu, enum kvm_reg reg) { + kvm_assert_register_caching_allowed(vcpu); return test_bit(reg, (unsigned long *)&vcpu->arch.regs_avail); } static inline bool kvm_register_is_dirty(struct kvm_vcpu *vcpu, enum kvm_reg reg) { + kvm_assert_register_caching_allowed(vcpu); return test_bit(reg, (unsigned long *)&vcpu->arch.regs_dirty); } static inline void kvm_register_mark_available(struct kvm_vcpu *vcpu, enum kvm_reg reg) { + kvm_assert_register_caching_allowed(vcpu); __set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail); } static inline void kvm_register_mark_dirty(struct kvm_vcpu *vcpu, enum kvm_reg reg) { + kvm_assert_register_caching_allowed(vcpu); __set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail); __set_bit(reg, (unsigned long *)&vcpu->arch.regs_dirty); } @@ -84,6 +100,7 @@ static inline void kvm_register_mark_dirty(struct kvm_vcpu *vcpu, static __always_inline bool kvm_register_test_and_mark_available(struct kvm_vcpu *vcpu, enum kvm_reg reg) { + kvm_assert_register_caching_allowed(vcpu); return arch___test_and_set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail); } diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index 55a18e2f2dcd99..10495fffb8905c 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -94,6 +94,8 @@ struct x86_instruction_info { #define X86EMUL_F_FETCH BIT(1) #define X86EMUL_F_IMPLICIT BIT(2) #define X86EMUL_F_INVLPG BIT(3) +#define X86EMUL_F_MSR BIT(4) +#define X86EMUL_F_DT_LOAD BIT(5) struct x86_emulate_ops { void (*vm_bugged)(struct x86_emulate_ctxt *ctxt); @@ -235,6 +237,9 @@ struct x86_emulate_ops { gva_t (*get_untagged_addr)(struct x86_emulate_ctxt *ctxt, gva_t addr, unsigned int flags); + + bool (*is_canonical_addr)(struct x86_emulate_ctxt *ctxt, gva_t addr, + unsigned int flags); }; /* Type, address-of, and value of an instruction's operand. */ diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 95c6beb8ce2799..3c83951c619ead 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -382,7 +382,7 @@ enum { DIRTY }; -void kvm_recalculate_apic_map(struct kvm *kvm) +static void kvm_recalculate_apic_map(struct kvm *kvm) { struct kvm_apic_map *new, *old = NULL; struct kvm_vcpu *vcpu; @@ -2577,7 +2577,7 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) return (tpr & 0xf0) >> 4; } -void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) +static void __kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value) { u64 old_value = vcpu->arch.apic_base; struct kvm_lapic *apic = vcpu->arch.apic; @@ -2625,6 +2625,31 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) } } +int kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value, bool host_initiated) +{ + enum lapic_mode old_mode = kvm_get_apic_mode(vcpu); + enum lapic_mode new_mode = kvm_apic_mode(value); + + if (vcpu->arch.apic_base == value) + return 0; + + u64 reserved_bits = kvm_vcpu_reserved_gpa_bits_raw(vcpu) | 0x2ff | + (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC) ? 0 : X2APIC_ENABLE); + + if ((value & reserved_bits) != 0 || new_mode == LAPIC_MODE_INVALID) + return 1; + if (!host_initiated) { + if (old_mode == LAPIC_MODE_X2APIC && new_mode == LAPIC_MODE_XAPIC) + return 1; + if (old_mode == LAPIC_MODE_DISABLED && new_mode == LAPIC_MODE_X2APIC) + return 1; + } + + __kvm_apic_set_base(vcpu, value); + kvm_recalculate_apic_map(vcpu->kvm); + return 0; +} + void kvm_apic_update_apicv(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; @@ -2654,7 +2679,6 @@ void kvm_apic_update_apicv(struct kvm_vcpu *vcpu) int kvm_alloc_apic_access_page(struct kvm *kvm) { - struct page *page; void __user *hva; int ret = 0; @@ -2670,17 +2694,6 @@ int kvm_alloc_apic_access_page(struct kvm *kvm) goto out; } - page = gfn_to_page(kvm, APIC_DEFAULT_PHYS_BASE >> PAGE_SHIFT); - if (is_error_page(page)) { - ret = -EFAULT; - goto out; - } - - /* - * Do not pin the page in memory, so that memory hot-unplug - * is able to migrate it. - */ - put_page(page); kvm->arch.apic_access_memslot_enabled = true; out: mutex_unlock(&kvm->slots_lock); @@ -2735,7 +2748,14 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) msr_val = APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE; if (kvm_vcpu_is_reset_bsp(vcpu)) msr_val |= MSR_IA32_APICBASE_BSP; - kvm_lapic_set_base(vcpu, msr_val); + + /* + * Use the inner helper to avoid an extra recalcuation of the + * optimized APIC map if some other task has dirtied the map. + * The recalculation needed for this vCPU will be done after + * all APIC state has been initialized (see below). + */ + __kvm_apic_set_base(vcpu, msr_val); } if (!apic) @@ -3076,7 +3096,6 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) kvm_x86_call(apicv_pre_state_restore)(vcpu); - kvm_lapic_set_base(vcpu, vcpu->arch.apic_base); /* set SPIV separately to get count of SW disabled APICs right */ apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV))); diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 1b8ef9856422a4..24add38beaf0ba 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -95,8 +95,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event); u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu); -void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); -void kvm_recalculate_apic_map(struct kvm *kvm); void kvm_apic_set_version(struct kvm_vcpu *vcpu); void kvm_apic_after_set_mcg_cap(struct kvm_vcpu *vcpu); bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, @@ -117,11 +115,9 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, struct kvm_lapic_irq *irq, int *r, struct dest_map *dest_map); void kvm_apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high); -u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); -int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info); +int kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value, bool host_initiated); int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s); int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s); -enum lapic_mode kvm_get_apic_mode(struct kvm_vcpu *vcpu); int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu); @@ -271,6 +267,11 @@ static inline enum lapic_mode kvm_apic_mode(u64 apic_base) return apic_base & (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE); } +static inline enum lapic_mode kvm_get_apic_mode(struct kvm_vcpu *vcpu) +{ + return kvm_apic_mode(vcpu->arch.apic_base); +} + static inline u8 kvm_xapic_id(struct kvm_lapic *apic) { return kvm_lapic_get_reg(apic, APIC_ID) >> 24; diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 9dc5dd43ae7f21..e9322358678b67 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -4,6 +4,7 @@ #include #include "kvm_cache_regs.h" +#include "x86.h" #include "cpuid.h" extern bool __read_mostly enable_mmio_caching; diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 8e853a5fc867b7..2401606db2604b 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -179,7 +179,6 @@ struct kvm_shadow_walk_iterator { static struct kmem_cache *pte_list_desc_cache; struct kmem_cache *mmu_page_header_cache; -static struct percpu_counter kvm_total_used_mmu_pages; static void mmu_spte_set(u64 *sptep, u64 spte); @@ -485,11 +484,12 @@ static void mmu_spte_set(u64 *sptep, u64 new_spte) __set_spte(sptep, new_spte); } -/* - * Update the SPTE (excluding the PFN), but do not track changes in its - * accessed/dirty status. +/* Rules for using mmu_spte_update: + * Update the state bits, it means the mapped pfn is not changed. + * + * Returns true if the TLB needs to be flushed */ -static u64 mmu_spte_update_no_track(u64 *sptep, u64 new_spte) +static bool mmu_spte_update(u64 *sptep, u64 new_spte) { u64 old_spte = *sptep; @@ -498,7 +498,7 @@ static u64 mmu_spte_update_no_track(u64 *sptep, u64 new_spte) if (!is_shadow_present_pte(old_spte)) { mmu_spte_set(sptep, new_spte); - return old_spte; + return false; } if (!spte_has_volatile_bits(old_spte)) @@ -506,53 +506,10 @@ static u64 mmu_spte_update_no_track(u64 *sptep, u64 new_spte) else old_spte = __update_clear_spte_slow(sptep, new_spte); - WARN_ON_ONCE(spte_to_pfn(old_spte) != spte_to_pfn(new_spte)); - - return old_spte; -} - -/* Rules for using mmu_spte_update: - * Update the state bits, it means the mapped pfn is not changed. - * - * Whenever an MMU-writable SPTE is overwritten with a read-only SPTE, remote - * TLBs must be flushed. Otherwise rmap_write_protect will find a read-only - * spte, even though the writable spte might be cached on a CPU's TLB. - * - * Returns true if the TLB needs to be flushed - */ -static bool mmu_spte_update(u64 *sptep, u64 new_spte) -{ - bool flush = false; - u64 old_spte = mmu_spte_update_no_track(sptep, new_spte); - - if (!is_shadow_present_pte(old_spte)) - return false; - - /* - * For the spte updated out of mmu-lock is safe, since - * we always atomically update it, see the comments in - * spte_has_volatile_bits(). - */ - if (is_mmu_writable_spte(old_spte) && - !is_writable_pte(new_spte)) - flush = true; + WARN_ON_ONCE(!is_shadow_present_pte(old_spte) || + spte_to_pfn(old_spte) != spte_to_pfn(new_spte)); - /* - * Flush TLB when accessed/dirty states are changed in the page tables, - * to guarantee consistency between TLB and page tables. - */ - - if (is_accessed_spte(old_spte) && !is_accessed_spte(new_spte)) { - flush = true; - kvm_set_pfn_accessed(spte_to_pfn(old_spte)); - } - - if (is_dirty_spte(old_spte) && !is_dirty_spte(new_spte)) { - flush = true; - kvm_set_pfn_dirty(spte_to_pfn(old_spte)); - } - - return flush; + return leaf_spte_change_needs_tlb_flush(old_spte, new_spte); } /* @@ -563,10 +520,8 @@ static bool mmu_spte_update(u64 *sptep, u64 new_spte) */ static u64 mmu_spte_clear_track_bits(struct kvm *kvm, u64 *sptep) { - kvm_pfn_t pfn; u64 old_spte = *sptep; int level = sptep_to_sp(sptep)->role.level; - struct page *page; if (!is_shadow_present_pte(old_spte) || !spte_has_volatile_bits(old_spte)) @@ -578,24 +533,6 @@ static u64 mmu_spte_clear_track_bits(struct kvm *kvm, u64 *sptep) return old_spte; kvm_update_page_stats(kvm, level, -1); - - pfn = spte_to_pfn(old_spte); - - /* - * KVM doesn't hold a reference to any pages mapped into the guest, and - * instead uses the mmu_notifier to ensure that KVM unmaps any pages - * before they are reclaimed. Sanity check that, if the pfn is backed - * by a refcounted page, the refcount is elevated. - */ - page = kvm_pfn_to_refcounted_page(pfn); - WARN_ON_ONCE(page && !page_count(page)); - - if (is_accessed_spte(old_spte)) - kvm_set_pfn_accessed(pfn); - - if (is_dirty_spte(old_spte)) - kvm_set_pfn_dirty(pfn); - return old_spte; } @@ -1250,16 +1187,6 @@ static bool spte_clear_dirty(u64 *sptep) return mmu_spte_update(sptep, spte); } -static bool spte_wrprot_for_clear_dirty(u64 *sptep) -{ - bool was_writable = test_and_clear_bit(PT_WRITABLE_SHIFT, - (unsigned long *)sptep); - if (was_writable && !spte_ad_enabled(*sptep)) - kvm_set_pfn_dirty(spte_to_pfn(*sptep)); - - return was_writable; -} - /* * Gets the GFN ready for another round of dirty logging by clearing the * - D bit on ad-enabled SPTEs, and @@ -1275,7 +1202,8 @@ static bool __rmap_clear_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head, for_each_rmap_spte(rmap_head, &iter, sptep) if (spte_ad_need_write_protect(*sptep)) - flush |= spte_wrprot_for_clear_dirty(sptep); + flush |= test_and_clear_bit(PT_WRITABLE_SHIFT, + (unsigned long *)sptep); else flush |= spte_clear_dirty(sptep); @@ -1640,15 +1568,12 @@ static bool kvm_rmap_age_gfn_range(struct kvm *kvm, (unsigned long *)sptep); } else { /* - * Capture the dirty status of the page, so that - * it doesn't get lost when the SPTE is marked - * for access tracking. + * WARN if mmu_spte_update() signals the need + * for a TLB flush, as Access tracking a SPTE + * should never trigger an _immediate_ flush. */ - if (is_writable_pte(spte)) - kvm_set_pfn_dirty(spte_to_pfn(spte)); - spte = mark_spte_for_access_track(spte); - mmu_spte_update_no_track(sptep, spte); + WARN_ON_ONCE(mmu_spte_update(sptep, spte)); } young = true; } @@ -1696,27 +1621,15 @@ static void kvm_mmu_check_sptes_at_free(struct kvm_mmu_page *sp) #endif } -/* - * This value is the sum of all of the kvm instances's - * kvm->arch.n_used_mmu_pages values. We need a global, - * aggregate version in order to make the slab shrinker - * faster - */ -static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, long nr) -{ - kvm->arch.n_used_mmu_pages += nr; - percpu_counter_add(&kvm_total_used_mmu_pages, nr); -} - static void kvm_account_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp) { - kvm_mod_used_mmu_pages(kvm, +1); + kvm->arch.n_used_mmu_pages++; kvm_account_pgtable_pages((void *)sp->spt, +1); } static void kvm_unaccount_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp) { - kvm_mod_used_mmu_pages(kvm, -1); + kvm->arch.n_used_mmu_pages--; kvm_account_pgtable_pages((void *)sp->spt, -1); } @@ -2802,7 +2715,7 @@ static void kvm_unsync_page(struct kvm *kvm, struct kvm_mmu_page *sp) * be write-protected. */ int mmu_try_to_unsync_pages(struct kvm *kvm, const struct kvm_memory_slot *slot, - gfn_t gfn, bool can_unsync, bool prefetch) + gfn_t gfn, bool synchronizing, bool prefetch) { struct kvm_mmu_page *sp; bool locked = false; @@ -2817,12 +2730,12 @@ int mmu_try_to_unsync_pages(struct kvm *kvm, const struct kvm_memory_slot *slot, /* * The page is not write-tracked, mark existing shadow pages unsync - * unless KVM is synchronizing an unsync SP (can_unsync = false). In - * that case, KVM must complete emulation of the guest TLB flush before - * allowing shadow pages to become unsync (writable by the guest). + * unless KVM is synchronizing an unsync SP. In that case, KVM must + * complete emulation of the guest TLB flush before allowing shadow + * pages to become unsync (writable by the guest). */ for_each_gfn_valid_sp_with_gptes(kvm, sp, gfn) { - if (!can_unsync) + if (synchronizing) return -EPERM; if (sp->unsync) @@ -2926,6 +2839,9 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, } if (is_shadow_present_pte(*sptep)) { + if (prefetch) + return RET_PF_SPURIOUS; + /* * If we overwrite a PTE page pointer with a 2MB PMD, unlink * the parent of the now unreachable PTE. @@ -2945,7 +2861,7 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, } wrprot = make_spte(vcpu, sp, slot, pte_access, gfn, pfn, *sptep, prefetch, - true, host_writable, &spte); + false, host_writable, &spte); if (*sptep == spte) { ret = RET_PF_SPURIOUS; @@ -2971,32 +2887,51 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, return ret; } -static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *sp, - u64 *start, u64 *end) +static bool kvm_mmu_prefetch_sptes(struct kvm_vcpu *vcpu, gfn_t gfn, u64 *sptep, + int nr_pages, unsigned int access) { struct page *pages[PTE_PREFETCH_NUM]; struct kvm_memory_slot *slot; - unsigned int access = sp->role.access; - int i, ret; - gfn_t gfn; + int i; + + if (WARN_ON_ONCE(nr_pages > PTE_PREFETCH_NUM)) + return false; - gfn = kvm_mmu_page_get_gfn(sp, spte_index(start)); slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, access & ACC_WRITE_MASK); if (!slot) - return -1; + return false; - ret = gfn_to_page_many_atomic(slot, gfn, pages, end - start); - if (ret <= 0) - return -1; + nr_pages = kvm_prefetch_pages(slot, gfn, pages, nr_pages); + if (nr_pages <= 0) + return false; - for (i = 0; i < ret; i++, gfn++, start++) { - mmu_set_spte(vcpu, slot, start, access, gfn, + for (i = 0; i < nr_pages; i++, gfn++, sptep++) { + mmu_set_spte(vcpu, slot, sptep, access, gfn, page_to_pfn(pages[i]), NULL); - put_page(pages[i]); + + /* + * KVM always prefetches writable pages from the primary MMU, + * and KVM can make its SPTE writable in the fast page handler, + * without notifying the primary MMU. Mark pages/folios dirty + * now to ensure file data is written back if it ends up being + * written by the guest. Because KVM's prefetching GUPs + * writable PTEs, the probability of unnecessary writeback is + * extremely low. + */ + kvm_release_page_dirty(pages[i]); } - return 0; + return true; +} + +static bool direct_pte_prefetch_many(struct kvm_vcpu *vcpu, + struct kvm_mmu_page *sp, + u64 *start, u64 *end) +{ + gfn_t gfn = kvm_mmu_page_get_gfn(sp, spte_index(start)); + unsigned int access = sp->role.access; + + return kvm_mmu_prefetch_sptes(vcpu, gfn, start, end - start, access); } static void __direct_pte_prefetch(struct kvm_vcpu *vcpu, @@ -3014,8 +2949,9 @@ static void __direct_pte_prefetch(struct kvm_vcpu *vcpu, if (is_shadow_present_pte(*spte) || spte == sptep) { if (!start) continue; - if (direct_pte_prefetch_many(vcpu, sp, start, spte) < 0) + if (!direct_pte_prefetch_many(vcpu, sp, start, spte)) return; + start = NULL; } else if (!start) start = spte; @@ -3165,13 +3101,12 @@ static int __kvm_mmu_max_mapping_level(struct kvm *kvm, } int kvm_mmu_max_mapping_level(struct kvm *kvm, - const struct kvm_memory_slot *slot, gfn_t gfn, - int max_level) + const struct kvm_memory_slot *slot, gfn_t gfn) { bool is_private = kvm_slot_can_be_private(slot) && kvm_mem_is_private(kvm, gfn); - return __kvm_mmu_max_mapping_level(kvm, slot, gfn, max_level, is_private); + return __kvm_mmu_max_mapping_level(kvm, slot, gfn, PG_LEVEL_NUM, is_private); } void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) @@ -3322,7 +3257,6 @@ static int kvm_handle_noslot_fault(struct kvm_vcpu *vcpu, fault->slot = NULL; fault->pfn = KVM_PFN_NOSLOT; fault->map_writable = false; - fault->hva = KVM_HVA_ERR_BAD; /* * If MMIO caching is disabled, emulate immediately without @@ -3392,7 +3326,7 @@ static bool page_fault_can_be_fast(struct kvm *kvm, struct kvm_page_fault *fault * by setting the Writable bit, which can be done out of mmu_lock. */ if (!fault->present) - return !kvm_ad_enabled(); + return !kvm_ad_enabled; /* * Note, instruction fetches and writes are mutually exclusive, ignore @@ -3419,7 +3353,7 @@ static bool fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, * harm. This also avoids the TLB flush needed after setting dirty bit * so non-PML cases won't be impacted. * - * Compare with set_spte where instead shadow_dirty_mask is set. + * Compare with make_spte() where instead shadow_dirty_mask is set. */ if (!try_cmpxchg64(sptep, &old_spte, new_spte)) return false; @@ -3430,18 +3364,6 @@ static bool fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, return true; } -static bool is_access_allowed(struct kvm_page_fault *fault, u64 spte) -{ - if (fault->exec) - return is_executable_pte(spte); - - if (fault->write) - return is_writable_pte(spte); - - /* Fault was on Read access */ - return spte & PT_PRESENT_MASK; -} - /* * Returns the last level spte pointer of the shadow page walk for the given * gpa, and sets *spte to the spte value. This spte may be non-preset. If no @@ -3527,8 +3449,9 @@ static int fast_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) * uses A/D bits for non-nested MMUs. Thus, if A/D bits are * enabled, the SPTE can't be an access-tracked SPTE. */ - if (unlikely(!kvm_ad_enabled()) && is_access_track_spte(spte)) - new_spte = restore_acc_track_spte(new_spte); + if (unlikely(!kvm_ad_enabled) && is_access_track_spte(spte)) + new_spte = restore_acc_track_spte(new_spte) | + shadow_accessed_mask; /* * To keep things simple, only SPTEs that are MMU-writable can @@ -4376,8 +4299,15 @@ static u8 kvm_max_private_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, return max_level; } -static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, - struct kvm_page_fault *fault) +static void kvm_mmu_finish_page_fault(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault, int r) +{ + kvm_release_faultin_page(vcpu->kvm, fault->refcounted_page, + r == RET_PF_RETRY, fault->map_writable); +} + +static int kvm_mmu_faultin_pfn_private(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault) { int max_order, r; @@ -4387,7 +4317,7 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, } r = kvm_gmem_get_pfn(vcpu->kvm, fault->slot, fault->gfn, &fault->pfn, - &max_order); + &fault->refcounted_page, &max_order); if (r) { kvm_mmu_prepare_memory_fault_exit(vcpu, fault); return r; @@ -4400,19 +4330,26 @@ static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, return RET_PF_CONTINUE; } -static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) +static int __kvm_mmu_faultin_pfn(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault) { - bool async; + unsigned int foll = fault->write ? FOLL_WRITE : 0; if (fault->is_private) - return kvm_faultin_pfn_private(vcpu, fault); + return kvm_mmu_faultin_pfn_private(vcpu, fault); + + foll |= FOLL_NOWAIT; + fault->pfn = __kvm_faultin_pfn(fault->slot, fault->gfn, foll, + &fault->map_writable, &fault->refcounted_page); - async = false; - fault->pfn = __gfn_to_pfn_memslot(fault->slot, fault->gfn, false, false, - &async, fault->write, - &fault->map_writable, &fault->hva); - if (!async) - return RET_PF_CONTINUE; /* *pfn has correct page already */ + /* + * If resolving the page failed because I/O is needed to fault-in the + * page, then either set up an asynchronous #PF to do the I/O, or if + * doing an async #PF isn't possible, retry with I/O allowed. All + * other failures are terminal, i.e. retrying won't help. + */ + if (fault->pfn != KVM_PFN_ERR_NEEDS_IO) + return RET_PF_CONTINUE; if (!fault->prefetch && kvm_can_do_async_pf(vcpu)) { trace_kvm_try_async_get_page(fault->addr, fault->gfn); @@ -4430,14 +4367,16 @@ static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault * to wait for IO. Note, gup always bails if it is unable to quickly * get a page and a fatal signal, i.e. SIGKILL, is pending. */ - fault->pfn = __gfn_to_pfn_memslot(fault->slot, fault->gfn, false, true, - NULL, fault->write, - &fault->map_writable, &fault->hva); + foll |= FOLL_INTERRUPTIBLE; + foll &= ~FOLL_NOWAIT; + fault->pfn = __kvm_faultin_pfn(fault->slot, fault->gfn, foll, + &fault->map_writable, &fault->refcounted_page); + return RET_PF_CONTINUE; } -static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, - unsigned int access) +static int kvm_mmu_faultin_pfn(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault, unsigned int access) { struct kvm_memory_slot *slot = fault->slot; int ret; @@ -4520,7 +4459,7 @@ static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, if (mmu_invalidate_retry_gfn_unsafe(vcpu->kvm, fault->mmu_seq, fault->gfn)) return RET_PF_RETRY; - ret = __kvm_faultin_pfn(vcpu, fault); + ret = __kvm_mmu_faultin_pfn(vcpu, fault); if (ret != RET_PF_CONTINUE) return ret; @@ -4538,7 +4477,7 @@ static int kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, * mmu_lock is acquired. */ if (mmu_invalidate_retry_gfn_unsafe(vcpu->kvm, fault->mmu_seq, fault->gfn)) { - kvm_release_pfn_clean(fault->pfn); + kvm_mmu_finish_page_fault(vcpu, fault, RET_PF_RETRY); return RET_PF_RETRY; } @@ -4597,7 +4536,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault if (r) return r; - r = kvm_faultin_pfn(vcpu, fault, ACC_ALL); + r = kvm_mmu_faultin_pfn(vcpu, fault, ACC_ALL); if (r != RET_PF_CONTINUE) return r; @@ -4614,8 +4553,8 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault r = direct_map(vcpu, fault); out_unlock: + kvm_mmu_finish_page_fault(vcpu, fault, r); write_unlock(&vcpu->kvm->mmu_lock); - kvm_release_pfn_clean(fault->pfn); return r; } @@ -4688,7 +4627,7 @@ static int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu, if (r) return r; - r = kvm_faultin_pfn(vcpu, fault, ACC_ALL); + r = kvm_mmu_faultin_pfn(vcpu, fault, ACC_ALL); if (r != RET_PF_CONTINUE) return r; @@ -4701,8 +4640,8 @@ static int kvm_tdp_mmu_page_fault(struct kvm_vcpu *vcpu, r = kvm_tdp_mmu_map(vcpu, fault); out_unlock: + kvm_mmu_finish_page_fault(vcpu, fault, r); read_unlock(&vcpu->kvm->mmu_lock); - kvm_release_pfn_clean(fault->pfn); return r; } #endif @@ -5488,7 +5427,7 @@ kvm_calc_tdp_mmu_root_page_role(struct kvm_vcpu *vcpu, role.efer_nx = true; role.smm = cpu_role.base.smm; role.guest_mode = cpu_role.base.guest_mode; - role.ad_disabled = !kvm_ad_enabled(); + role.ad_disabled = !kvm_ad_enabled; role.level = kvm_mmu_get_tdp_level(vcpu); role.direct = true; role.has_4_byte_gpte = false; @@ -6228,7 +6167,7 @@ void kvm_mmu_invalidate_addr(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, /* 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(addr, vcpu)) + if (is_noncanonical_invlpg_address(addr, vcpu)) return; kvm_x86_call(flush_tlb_gva)(vcpu, addr); @@ -6416,8 +6355,11 @@ static void kvm_zap_obsolete_pages(struct kvm *kvm) { struct kvm_mmu_page *sp, *node; int nr_zapped, batch = 0; + LIST_HEAD(invalid_list); bool unstable; + lockdep_assert_held(&kvm->slots_lock); + restart: list_for_each_entry_safe_reverse(sp, node, &kvm->arch.active_mmu_pages, link) { @@ -6449,7 +6391,7 @@ static void kvm_zap_obsolete_pages(struct kvm *kvm) } unstable = __kvm_mmu_prepare_zap_page(kvm, sp, - &kvm->arch.zapped_obsolete_pages, &nr_zapped); + &invalid_list, &nr_zapped); batch += nr_zapped; if (unstable) @@ -6465,7 +6407,7 @@ static void kvm_zap_obsolete_pages(struct kvm *kvm) * kvm_mmu_load()), and the reload in the caller ensure no vCPUs are * running with an obsolete MMU. */ - kvm_mmu_commit_zap_page(kvm, &kvm->arch.zapped_obsolete_pages); + kvm_mmu_commit_zap_page(kvm, &invalid_list); } /* @@ -6528,16 +6470,10 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm) kvm_tdp_mmu_zap_invalidated_roots(kvm); } -static bool kvm_has_zapped_obsolete_pages(struct kvm *kvm) -{ - return unlikely(!list_empty_careful(&kvm->arch.zapped_obsolete_pages)); -} - void kvm_mmu_init_vm(struct kvm *kvm) { kvm->arch.shadow_mmio_value = shadow_mmio_value; INIT_LIST_HEAD(&kvm->arch.active_mmu_pages); - INIT_LIST_HEAD(&kvm->arch.zapped_obsolete_pages); INIT_LIST_HEAD(&kvm->arch.possible_nx_huge_pages); spin_lock_init(&kvm->arch.mmu_unsync_pages_lock); @@ -6771,7 +6707,7 @@ static void shadow_mmu_split_huge_page(struct kvm *kvm, continue; } - spte = make_huge_page_split_spte(kvm, huge_spte, sp->role, index); + spte = make_small_spte(kvm, huge_spte, sp->role, index); mmu_spte_set(sptep, spte); __rmap_add(kvm, cache, slot, sptep, gfn, sp->role.access); } @@ -6954,8 +6890,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm, * mapping if the indirect sp has level = 1. */ if (sp->role.direct && - sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn, - PG_LEVEL_NUM)) { + sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn)) { kvm_zap_one_rmap_spte(kvm, rmap_head, sptep); if (kvm_available_flush_remote_tlbs_range()) @@ -6983,8 +6918,8 @@ static void kvm_rmap_zap_collapsible_sptes(struct kvm *kvm, kvm_flush_remote_tlbs_memslot(kvm, slot); } -void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm, - const struct kvm_memory_slot *slot) +void kvm_mmu_recover_huge_pages(struct kvm *kvm, + const struct kvm_memory_slot *slot) { if (kvm_memslots_have_rmaps(kvm)) { write_lock(&kvm->mmu_lock); @@ -6994,7 +6929,7 @@ void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm, if (tdp_mmu_enabled) { read_lock(&kvm->mmu_lock); - kvm_tdp_mmu_zap_collapsible_sptes(kvm, slot); + kvm_tdp_mmu_recover_huge_pages(kvm, slot); read_unlock(&kvm->mmu_lock); } } @@ -7149,72 +7084,6 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen) } } -static unsigned long mmu_shrink_scan(struct shrinker *shrink, - struct shrink_control *sc) -{ - struct kvm *kvm; - int nr_to_scan = sc->nr_to_scan; - unsigned long freed = 0; - - mutex_lock(&kvm_lock); - - list_for_each_entry(kvm, &vm_list, vm_list) { - int idx; - - /* - * Never scan more than sc->nr_to_scan VM instances. - * Will not hit this condition practically since we do not try - * to shrink more than one VM and it is very unlikely to see - * !n_used_mmu_pages so many times. - */ - if (!nr_to_scan--) - break; - /* - * n_used_mmu_pages is accessed without holding kvm->mmu_lock - * here. We may skip a VM instance errorneosly, but we do not - * want to shrink a VM that only started to populate its MMU - * anyway. - */ - if (!kvm->arch.n_used_mmu_pages && - !kvm_has_zapped_obsolete_pages(kvm)) - continue; - - idx = srcu_read_lock(&kvm->srcu); - write_lock(&kvm->mmu_lock); - - if (kvm_has_zapped_obsolete_pages(kvm)) { - kvm_mmu_commit_zap_page(kvm, - &kvm->arch.zapped_obsolete_pages); - goto unlock; - } - - freed = kvm_mmu_zap_oldest_mmu_pages(kvm, sc->nr_to_scan); - -unlock: - write_unlock(&kvm->mmu_lock); - srcu_read_unlock(&kvm->srcu, idx); - - /* - * unfair on small ones - * per-vm shrinkers cry out - * sadness comes quickly - */ - list_move_tail(&kvm->vm_list, &vm_list); - break; - } - - mutex_unlock(&kvm_lock); - return freed; -} - -static unsigned long mmu_shrink_count(struct shrinker *shrink, - struct shrink_control *sc) -{ - return percpu_counter_read_positive(&kvm_total_used_mmu_pages); -} - -static struct shrinker *mmu_shrinker; - static void mmu_destroy_caches(void) { kmem_cache_destroy(pte_list_desc_cache); @@ -7281,7 +7150,7 @@ static int set_nx_huge_pages(const char *val, const struct kernel_param *kp) kvm_mmu_zap_all_fast(kvm); mutex_unlock(&kvm->slots_lock); - wake_up_process(kvm->arch.nx_huge_page_recovery_thread); + vhost_task_wake(kvm->arch.nx_huge_page_recovery_thread); } mutex_unlock(&kvm_lock); } @@ -7341,23 +7210,8 @@ int kvm_mmu_vendor_module_init(void) if (!mmu_page_header_cache) goto out; - if (percpu_counter_init(&kvm_total_used_mmu_pages, 0, GFP_KERNEL)) - goto out; - - mmu_shrinker = shrinker_alloc(0, "x86-mmu"); - if (!mmu_shrinker) - goto out_shrinker; - - mmu_shrinker->count_objects = mmu_shrink_count; - mmu_shrinker->scan_objects = mmu_shrink_scan; - mmu_shrinker->seeks = DEFAULT_SEEKS * 10; - - shrinker_register(mmu_shrinker); - return 0; -out_shrinker: - percpu_counter_destroy(&kvm_total_used_mmu_pages); out: mmu_destroy_caches(); return ret; @@ -7374,8 +7228,6 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu) void kvm_mmu_vendor_module_exit(void) { mmu_destroy_caches(); - percpu_counter_destroy(&kvm_total_used_mmu_pages); - shrinker_free(mmu_shrinker); } /* @@ -7427,7 +7279,7 @@ static int set_nx_huge_pages_recovery_param(const char *val, const struct kernel mutex_lock(&kvm_lock); list_for_each_entry(kvm, &vm_list, vm_list) - wake_up_process(kvm->arch.nx_huge_page_recovery_thread); + vhost_task_wake(kvm->arch.nx_huge_page_recovery_thread); mutex_unlock(&kvm_lock); } @@ -7530,62 +7382,56 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm) srcu_read_unlock(&kvm->srcu, rcu_idx); } -static long get_nx_huge_page_recovery_timeout(u64 start_time) +static void kvm_nx_huge_page_recovery_worker_kill(void *data) { - bool enabled; - uint period; - - enabled = calc_nx_huge_pages_recovery_period(&period); - - return enabled ? start_time + msecs_to_jiffies(period) - get_jiffies_64() - : MAX_SCHEDULE_TIMEOUT; } -static int kvm_nx_huge_page_recovery_worker(struct kvm *kvm, uintptr_t data) +static bool kvm_nx_huge_page_recovery_worker(void *data) { - u64 start_time; + struct kvm *kvm = data; + bool enabled; + uint period; long remaining_time; - while (true) { - start_time = get_jiffies_64(); - remaining_time = get_nx_huge_page_recovery_timeout(start_time); - - set_current_state(TASK_INTERRUPTIBLE); - while (!kthread_should_stop() && remaining_time > 0) { - schedule_timeout(remaining_time); - remaining_time = get_nx_huge_page_recovery_timeout(start_time); - set_current_state(TASK_INTERRUPTIBLE); - } - - set_current_state(TASK_RUNNING); - - if (kthread_should_stop()) - return 0; + enabled = calc_nx_huge_pages_recovery_period(&period); + if (!enabled) + return false; - kvm_recover_nx_huge_pages(kvm); + remaining_time = kvm->arch.nx_huge_page_last + msecs_to_jiffies(period) + - get_jiffies_64(); + if (remaining_time > 0) { + schedule_timeout(remaining_time); + /* check for signals and come back */ + return true; } + + __set_current_state(TASK_RUNNING); + kvm_recover_nx_huge_pages(kvm); + kvm->arch.nx_huge_page_last = get_jiffies_64(); + return true; } int kvm_mmu_post_init_vm(struct kvm *kvm) { - int err; - if (nx_hugepage_mitigation_hard_disabled) return 0; - err = kvm_vm_create_worker_thread(kvm, kvm_nx_huge_page_recovery_worker, 0, - "kvm-nx-lpage-recovery", - &kvm->arch.nx_huge_page_recovery_thread); - if (!err) - kthread_unpark(kvm->arch.nx_huge_page_recovery_thread); + kvm->arch.nx_huge_page_last = get_jiffies_64(); + kvm->arch.nx_huge_page_recovery_thread = vhost_task_create( + kvm_nx_huge_page_recovery_worker, kvm_nx_huge_page_recovery_worker_kill, + kvm, "kvm-nx-lpage-recovery"); - return err; + if (!kvm->arch.nx_huge_page_recovery_thread) + return -ENOMEM; + + vhost_task_start(kvm->arch.nx_huge_page_recovery_thread); + return 0; } void kvm_mmu_pre_destroy_vm(struct kvm *kvm) { if (kvm->arch.nx_huge_page_recovery_thread) - kthread_stop(kvm->arch.nx_huge_page_recovery_thread); + vhost_task_stop(kvm->arch.nx_huge_page_recovery_thread); } #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index c98827840e07ab..b00abbe3f6cfa8 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -164,7 +164,7 @@ static inline gfn_t gfn_round_for_level(gfn_t gfn, int level) } int mmu_try_to_unsync_pages(struct kvm *kvm, const struct kvm_memory_slot *slot, - gfn_t gfn, bool can_unsync, bool prefetch); + gfn_t gfn, bool synchronizing, bool prefetch); void kvm_mmu_gfn_disallow_lpage(const struct kvm_memory_slot *slot, gfn_t gfn); void kvm_mmu_gfn_allow_lpage(const struct kvm_memory_slot *slot, gfn_t gfn); @@ -235,10 +235,10 @@ struct kvm_page_fault { /* The memslot containing gfn. May be NULL. */ struct kvm_memory_slot *slot; - /* Outputs of kvm_faultin_pfn. */ + /* Outputs of kvm_mmu_faultin_pfn(). */ unsigned long mmu_seq; kvm_pfn_t pfn; - hva_t hva; + struct page *refcounted_page; bool map_writable; /* @@ -313,7 +313,6 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, .is_private = err & PFERR_PRIVATE_ACCESS, .pfn = KVM_PFN_ERR_FAULT, - .hva = KVM_HVA_ERR_BAD, }; int r; @@ -347,8 +346,7 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, } int kvm_mmu_max_mapping_level(struct kvm *kvm, - const struct kvm_memory_slot *slot, gfn_t gfn, - int max_level); + const struct kvm_memory_slot *slot, gfn_t gfn); void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault); void disallowed_hugepage_adjust(struct kvm_page_fault *fault, u64 spte, int cur_level); diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index ae7d39ff2d07f0..f4711674c47bd0 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -533,10 +533,8 @@ static bool FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, u64 *spte, pt_element_t gpte) { - struct kvm_memory_slot *slot; unsigned pte_access; gfn_t gfn; - kvm_pfn_t pfn; if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte)) return false; @@ -545,17 +543,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, pte_access & ACC_WRITE_MASK); - if (!slot) - return false; - - pfn = gfn_to_pfn_memslot_atomic(slot, gfn); - if (is_error_pfn(pfn)) - return false; - - mmu_set_spte(vcpu, slot, spte, pte_access, gfn, pfn, NULL); - kvm_release_pfn_clean(pfn); - return true; + return kvm_mmu_prefetch_sptes(vcpu, gfn, spte, 1, pte_access); } static bool FNAME(gpte_changed)(struct kvm_vcpu *vcpu, @@ -813,7 +801,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault if (r) return r; - r = kvm_faultin_pfn(vcpu, fault, walker.pte_access); + r = kvm_mmu_faultin_pfn(vcpu, fault, walker.pte_access); if (r != RET_PF_CONTINUE) return r; @@ -848,8 +836,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault r = FNAME(fetch)(vcpu, fault, &walker); out_unlock: + kvm_mmu_finish_page_fault(vcpu, fault, r); write_unlock(&vcpu->kvm->mmu_lock); - kvm_release_pfn_clean(fault->pfn); return r; } @@ -892,9 +880,9 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, /* * Using the information in sp->shadowed_translation (kvm_mmu_page_get_gfn()) is - * safe because: - * - The spte has a reference to the struct page, so the pfn for a given gfn - * can't change unless all sptes pointing to it are nuked first. + * safe because SPTEs are protected by mmu_notifiers and memslot generations, so + * the pfn for a given gfn can't change unless all SPTEs pointing to the gfn are + * nuked first. * * Returns * < 0: failed to sync spte @@ -963,9 +951,14 @@ static int FNAME(sync_spte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, int 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, + spte_to_pfn(spte), spte, true, true, host_writable, &spte); + /* + * There is no need to mark the pfn dirty, as the new protections must + * be a subset of the old protections, i.e. synchronizing a SPTE cannot + * change the SPTE from read-only to writable. + */ return mmu_spte_update(sptep, spte); } diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index 8f7eb3ad88fcb9..22551e2f1d009d 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -24,6 +24,8 @@ static bool __ro_after_init allow_mmio_caching; module_param_named(mmio_caching, enable_mmio_caching, bool, 0444); EXPORT_SYMBOL_GPL(enable_mmio_caching); +bool __read_mostly kvm_ad_enabled; + u64 __read_mostly shadow_host_writable_mask; u64 __read_mostly shadow_mmu_writable_mask; u64 __read_mostly shadow_nx_mask; @@ -133,12 +135,6 @@ static bool kvm_is_mmio_pfn(kvm_pfn_t pfn) */ bool spte_has_volatile_bits(u64 spte) { - /* - * Always atomically update spte if it can be updated - * out of mmu-lock, it can ensure dirty bit is not lost, - * also, it can help us to get a stable is_writable_pte() - * to ensure tlb flush is not missed. - */ if (!is_writable_pte(spte) && is_mmu_writable_spte(spte)) return true; @@ -157,7 +153,7 @@ bool spte_has_volatile_bits(u64 spte) bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, const struct kvm_memory_slot *slot, unsigned int pte_access, gfn_t gfn, kvm_pfn_t pfn, - u64 old_spte, bool prefetch, bool can_unsync, + u64 old_spte, bool prefetch, bool synchronizing, bool host_writable, u64 *new_spte) { int level = sp->role.level; @@ -178,8 +174,8 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, spte |= SPTE_TDP_AD_WRPROT_ONLY; spte |= shadow_present_mask; - if (!prefetch) - spte |= spte_shadow_accessed_mask(spte); + if (!prefetch || synchronizing) + spte |= shadow_accessed_mask; /* * For simplicity, enforce the NX huge page mitigation even if not @@ -223,41 +219,39 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, spte |= (u64)pfn << PAGE_SHIFT; if (pte_access & ACC_WRITE_MASK) { - spte |= PT_WRITABLE_MASK | shadow_mmu_writable_mask; - - /* - * Optimization: for pte sync, if spte was writable the hash - * lookup is unnecessary (and expensive). Write protection - * is responsibility of kvm_mmu_get_page / kvm_mmu_sync_roots. - * Same reasoning can be applied to dirty page accounting. - */ - if (is_writable_pte(old_spte)) - goto out; - /* * Unsync shadow pages that are reachable by the new, writable * SPTE. Write-protect the SPTE if the page can't be unsync'd, * e.g. it's write-tracked (upper-level SPs) or has one or more * shadow pages and unsync'ing pages is not allowed. + * + * When overwriting an existing leaf SPTE, and the old SPTE was + * writable, skip trying to unsync shadow pages as any relevant + * shadow pages must already be unsync, i.e. the hash lookup is + * unnecessary (and expensive). Note, this relies on KVM not + * changing PFNs without first zapping the old SPTE, which is + * guaranteed by both the shadow MMU and the TDP MMU. */ - if (mmu_try_to_unsync_pages(vcpu->kvm, slot, gfn, can_unsync, prefetch)) { + if ((!is_last_spte(old_spte, level) || !is_writable_pte(old_spte)) && + mmu_try_to_unsync_pages(vcpu->kvm, slot, gfn, synchronizing, prefetch)) wrprot = true; - pte_access &= ~ACC_WRITE_MASK; - spte &= ~(PT_WRITABLE_MASK | shadow_mmu_writable_mask); - } + else + spte |= PT_WRITABLE_MASK | shadow_mmu_writable_mask | + shadow_dirty_mask; } - if (pte_access & ACC_WRITE_MASK) - spte |= spte_shadow_dirty_mask(spte); - -out: - if (prefetch) + if (prefetch && !synchronizing) spte = mark_spte_for_access_track(spte); WARN_ONCE(is_rsvd_spte(&vcpu->arch.mmu->shadow_zero_check, spte, level), "spte = 0x%llx, level = %d, rsvd bits = 0x%llx", spte, level, get_rsvd_bits(&vcpu->arch.mmu->shadow_zero_check, spte, level)); + /* + * Mark the memslot dirty *after* modifying it for access tracking. + * Unlike folios, memslots can be safely marked dirty out of mmu_lock, + * i.e. in the fast page fault handler. + */ if ((spte & PT_WRITABLE_MASK) && kvm_slot_dirty_track_enabled(slot)) { /* Enforced by kvm_mmu_hugepage_adjust. */ WARN_ON_ONCE(level > PG_LEVEL_4K); @@ -268,15 +262,15 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, return wrprot; } -static u64 make_spte_executable(u64 spte) +static u64 modify_spte_protections(u64 spte, u64 set, u64 clear) { bool is_access_track = is_access_track_spte(spte); if (is_access_track) spte = restore_acc_track_spte(spte); - spte &= ~shadow_nx_mask; - spte |= shadow_x_mask; + KVM_MMU_WARN_ON(set & clear); + spte = (spte | set) & ~clear; if (is_access_track) spte = mark_spte_for_access_track(spte); @@ -284,6 +278,16 @@ static u64 make_spte_executable(u64 spte) return spte; } +static u64 make_spte_executable(u64 spte) +{ + return modify_spte_protections(spte, shadow_x_mask, shadow_nx_mask); +} + +static u64 make_spte_nonexecutable(u64 spte) +{ + return modify_spte_protections(spte, shadow_nx_mask, shadow_x_mask); +} + /* * Construct an SPTE that maps a sub-page of the given huge page SPTE where * `index` identifies which sub-page. @@ -291,8 +295,8 @@ static u64 make_spte_executable(u64 spte) * This is used during huge page splitting to build the SPTEs that make up the * new page table. */ -u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, - union kvm_mmu_page_role role, int index) +u64 make_small_spte(struct kvm *kvm, u64 huge_spte, + union kvm_mmu_page_role role, int index) { u64 child_spte = huge_spte; @@ -320,6 +324,26 @@ u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, return child_spte; } +u64 make_huge_spte(struct kvm *kvm, u64 small_spte, int level) +{ + u64 huge_spte; + + KVM_BUG_ON(!is_shadow_present_pte(small_spte) || level == PG_LEVEL_4K, kvm); + + huge_spte = small_spte | PT_PAGE_SIZE_MASK; + + /* + * huge_spte already has the address of the sub-page being collapsed + * from small_spte, so just clear the lower address bits to create the + * huge page address. + */ + huge_spte &= KVM_HPAGE_MASK(level) | ~PAGE_MASK; + + if (is_nx_huge_page_enabled(kvm)) + huge_spte = make_spte_nonexecutable(huge_spte); + + return huge_spte; +} u64 make_nonleaf_spte(u64 *child_pt, bool ad_disabled) { @@ -352,7 +376,7 @@ u64 mark_spte_for_access_track(u64 spte) spte |= (spte & SHADOW_ACC_TRACK_SAVED_BITS_MASK) << SHADOW_ACC_TRACK_SAVED_BITS_SHIFT; - spte &= ~shadow_acc_track_mask; + spte &= ~(shadow_acc_track_mask | shadow_accessed_mask); return spte; } @@ -422,9 +446,11 @@ EXPORT_SYMBOL_GPL(kvm_mmu_set_me_spte_mask); void kvm_mmu_set_ept_masks(bool has_ad_bits, bool has_exec_only) { + kvm_ad_enabled = has_ad_bits; + shadow_user_mask = VMX_EPT_READABLE_MASK; - shadow_accessed_mask = has_ad_bits ? VMX_EPT_ACCESS_BIT : 0ull; - shadow_dirty_mask = has_ad_bits ? VMX_EPT_DIRTY_BIT : 0ull; + shadow_accessed_mask = VMX_EPT_ACCESS_BIT; + shadow_dirty_mask = VMX_EPT_DIRTY_BIT; shadow_nx_mask = 0ull; shadow_x_mask = VMX_EPT_EXECUTABLE_MASK; /* VMX_EPT_SUPPRESS_VE_BIT is needed for W or X violation. */ @@ -455,6 +481,8 @@ void kvm_mmu_reset_all_pte_masks(void) u8 low_phys_bits; u64 mask; + kvm_ad_enabled = true; + /* * If the CPU has 46 or less physical address bits, then set an * appropriate mask to guard against L1TF attacks. Otherwise, it is diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index 2cb816ea24307a..af10bc0380a320 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -167,6 +167,15 @@ static_assert(!(SHADOW_NONPRESENT_VALUE & SPTE_MMU_PRESENT_MASK)); #define SHADOW_NONPRESENT_VALUE 0ULL #endif + +/* + * True if A/D bits are supported in hardware and are enabled by KVM. When + * enabled, KVM uses A/D bits for all non-nested MMUs. Because L1 can disable + * A/D bits in EPTP12, SP and SPTE variants are needed to handle the scenario + * where KVM is using A/D bits for L1, but not L2. + */ +extern bool __read_mostly kvm_ad_enabled; + extern u64 __read_mostly shadow_host_writable_mask; extern u64 __read_mostly shadow_mmu_writable_mask; extern u64 __read_mostly shadow_nx_mask; @@ -285,17 +294,6 @@ static inline bool is_ept_ve_possible(u64 spte) (spte & VMX_EPT_RWX_MASK) != VMX_EPT_MISCONFIG_WX_VALUE; } -/* - * Returns true if A/D bits are supported in hardware and are enabled by KVM. - * When enabled, KVM uses A/D bits for all non-nested MMUs. Because L1 can - * disable A/D bits in EPTP12, SP and SPTE variants are needed to handle the - * scenario where KVM is using A/D bits for L1, but not L2. - */ -static inline bool kvm_ad_enabled(void) -{ - return !!shadow_accessed_mask; -} - static inline bool sp_ad_disabled(struct kvm_mmu_page *sp) { return sp->role.ad_disabled; @@ -318,18 +316,6 @@ static inline bool spte_ad_need_write_protect(u64 spte) return (spte & SPTE_TDP_AD_MASK) != SPTE_TDP_AD_ENABLED; } -static inline u64 spte_shadow_accessed_mask(u64 spte) -{ - KVM_MMU_WARN_ON(!is_shadow_present_pte(spte)); - return spte_ad_enabled(spte) ? shadow_accessed_mask : 0; -} - -static inline u64 spte_shadow_dirty_mask(u64 spte) -{ - KVM_MMU_WARN_ON(!is_shadow_present_pte(spte)); - return spte_ad_enabled(spte) ? shadow_dirty_mask : 0; -} - static inline bool is_access_track_spte(u64 spte) { return !spte_ad_enabled(spte) && (spte & shadow_acc_track_mask) == 0; @@ -357,17 +343,7 @@ static inline kvm_pfn_t spte_to_pfn(u64 pte) static inline bool is_accessed_spte(u64 spte) { - u64 accessed_mask = spte_shadow_accessed_mask(spte); - - return accessed_mask ? spte & accessed_mask - : !is_access_track_spte(spte); -} - -static inline bool is_dirty_spte(u64 spte) -{ - u64 dirty_mask = spte_shadow_dirty_mask(spte); - - return dirty_mask ? spte & dirty_mask : spte & PT_WRITABLE_MASK; + return spte & shadow_accessed_mask; } static inline u64 get_rsvd_bits(struct rsvd_bits_validate *rsvd_check, u64 pte, @@ -485,6 +461,50 @@ static inline bool is_mmu_writable_spte(u64 spte) return spte & shadow_mmu_writable_mask; } +/* + * Returns true if the access indicated by @fault is allowed by the existing + * SPTE protections. Note, the caller is responsible for checking that the + * SPTE is a shadow-present, leaf SPTE (either before or after). + */ +static inline bool is_access_allowed(struct kvm_page_fault *fault, u64 spte) +{ + if (fault->exec) + return is_executable_pte(spte); + + if (fault->write) + return is_writable_pte(spte); + + /* Fault was on Read access */ + return spte & PT_PRESENT_MASK; +} + +/* + * If the MMU-writable flag is cleared, i.e. the SPTE is write-protected for + * write-tracking, remote TLBs must be flushed, even if the SPTE was read-only, + * as KVM allows stale Writable TLB entries to exist. When dirty logging, KVM + * flushes TLBs based on whether or not dirty bitmap/ring entries were reaped, + * not whether or not SPTEs were modified, i.e. only the write-tracking case + * needs to flush at the time the SPTEs is modified, before dropping mmu_lock. + * + * Don't flush if the Accessed bit is cleared, as access tracking tolerates + * false negatives, e.g. KVM x86 omits TLB flushes even when aging SPTEs for a + * mmu_notifier.clear_flush_young() event. + * + * Lastly, don't flush if the Dirty bit is cleared, as KVM unconditionally + * flushes when enabling dirty logging (see kvm_mmu_slot_apply_flags()), and + * when clearing dirty logs, KVM flushes based on whether or not dirty entries + * were reaped from the bitmap/ring, not whether or not dirty SPTEs were found. + * + * Note, this logic only applies to shadow-present leaf SPTEs. The caller is + * responsible for checking that the old SPTE is shadow-present, and is also + * responsible for determining whether or not a TLB flush is required when + * modifying a shadow-present non-leaf SPTE. + */ +static inline bool leaf_spte_change_needs_tlb_flush(u64 old_spte, u64 new_spte) +{ + return is_mmu_writable_spte(old_spte) && !is_mmu_writable_spte(new_spte); +} + static inline u64 get_mmio_spte_generation(u64 spte) { u64 gen; @@ -499,10 +519,11 @@ bool spte_has_volatile_bits(u64 spte); bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, const struct kvm_memory_slot *slot, unsigned int pte_access, gfn_t gfn, kvm_pfn_t pfn, - u64 old_spte, bool prefetch, bool can_unsync, + u64 old_spte, bool prefetch, bool synchronizing, bool host_writable, u64 *new_spte); -u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, - union kvm_mmu_page_role role, int index); +u64 make_small_spte(struct kvm *kvm, u64 huge_spte, + union kvm_mmu_page_role role, int index); +u64 make_huge_spte(struct kvm *kvm, u64 small_spte, int level); u64 make_nonleaf_spte(u64 *child_pt, bool ad_disabled); u64 make_mmio_spte(struct kvm_vcpu *vcpu, u64 gfn, unsigned int access); u64 mark_spte_for_access_track(u64 spte); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 3b996c1fdaabc0..2f15e0e33903ab 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -511,10 +511,6 @@ static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn, if (is_leaf != was_leaf) kvm_update_page_stats(kvm, level, is_leaf ? 1 : -1); - if (was_leaf && is_dirty_spte(old_spte) && - (!is_present || !is_dirty_spte(new_spte) || pfn_changed)) - kvm_set_pfn_dirty(spte_to_pfn(old_spte)); - /* * Recursively handle child PTs if the change removed a subtree from * the paging structure. Note the WARN on the PFN changing without the @@ -524,10 +520,6 @@ 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); - - 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)); } static inline int __must_check __tdp_mmu_set_spte_atomic(struct tdp_iter *iter, @@ -591,48 +583,6 @@ static inline int __must_check tdp_mmu_set_spte_atomic(struct kvm *kvm, return 0; } -static inline int __must_check tdp_mmu_zap_spte_atomic(struct kvm *kvm, - struct tdp_iter *iter) -{ - int ret; - - lockdep_assert_held_read(&kvm->mmu_lock); - - /* - * Freeze the SPTE by setting it to a special, non-present value. This - * will stop other threads from immediately installing a present entry - * in its place before the TLBs are flushed. - * - * Delay processing of the zapped SPTE until after TLBs are flushed and - * the FROZEN_SPTE is replaced (see below). - */ - ret = __tdp_mmu_set_spte_atomic(iter, FROZEN_SPTE); - if (ret) - return ret; - - kvm_flush_remote_tlbs_gfn(kvm, iter->gfn, iter->level); - - /* - * No other thread can overwrite the frozen SPTE as they must either - * wait on the MMU lock or use tdp_mmu_set_spte_atomic() which will not - * overwrite the special frozen SPTE value. Use the raw write helper to - * avoid an unnecessary check on volatile bits. - */ - __kvm_tdp_mmu_write_spte(iter->sptep, SHADOW_NONPRESENT_VALUE); - - /* - * Process the zapped SPTE after flushing TLBs, and after replacing - * FROZEN_SPTE with 0. This minimizes the amount of time vCPUs are - * blocked by the FROZEN_SPTE and reduces contention on the child - * SPTEs. - */ - handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte, - SHADOW_NONPRESENT_VALUE, iter->level, true); - - return 0; -} - - /* * tdp_mmu_set_spte - Set a TDP MMU SPTE and handle the associated bookkeeping * @kvm: KVM instance @@ -688,6 +638,16 @@ static inline void tdp_mmu_iter_set_spte(struct kvm *kvm, struct tdp_iter *iter, #define tdp_mmu_for_each_pte(_iter, _mmu, _start, _end) \ for_each_tdp_pte(_iter, root_to_sp(_mmu->root.hpa), _start, _end) +static inline bool __must_check tdp_mmu_iter_need_resched(struct kvm *kvm, + struct tdp_iter *iter) +{ + if (!need_resched() && !rwlock_needbreak(&kvm->mmu_lock)) + return false; + + /* Ensure forward progress has been made before yielding. */ + return iter->next_last_level_gfn != iter->yielded_gfn; +} + /* * Yield if the MMU lock is contended or this thread needs to return control * to the scheduler. @@ -706,31 +666,27 @@ static inline bool __must_check tdp_mmu_iter_cond_resched(struct kvm *kvm, struct tdp_iter *iter, bool flush, bool shared) { - WARN_ON_ONCE(iter->yielded); + KVM_MMU_WARN_ON(iter->yielded); - /* Ensure forward progress has been made before yielding. */ - if (iter->next_last_level_gfn == iter->yielded_gfn) + if (!tdp_mmu_iter_need_resched(kvm, iter)) return false; - if (need_resched() || rwlock_needbreak(&kvm->mmu_lock)) { - if (flush) - kvm_flush_remote_tlbs(kvm); - - rcu_read_unlock(); + if (flush) + kvm_flush_remote_tlbs(kvm); - if (shared) - cond_resched_rwlock_read(&kvm->mmu_lock); - else - cond_resched_rwlock_write(&kvm->mmu_lock); + rcu_read_unlock(); - rcu_read_lock(); + if (shared) + cond_resched_rwlock_read(&kvm->mmu_lock); + else + cond_resched_rwlock_write(&kvm->mmu_lock); - WARN_ON_ONCE(iter->gfn > iter->next_last_level_gfn); + rcu_read_lock(); - iter->yielded = true; - } + WARN_ON_ONCE(iter->gfn > iter->next_last_level_gfn); - return iter->yielded; + iter->yielded = true; + return true; } static inline gfn_t tdp_mmu_max_gfn_exclusive(void) @@ -1026,19 +982,28 @@ static int tdp_mmu_map_handle_target_level(struct kvm_vcpu *vcpu, if (WARN_ON_ONCE(sp->role.level != fault->goal_level)) return RET_PF_RETRY; + if (fault->prefetch && is_shadow_present_pte(iter->old_spte)) + return RET_PF_SPURIOUS; + + if (is_shadow_present_pte(iter->old_spte) && + is_access_allowed(fault, iter->old_spte) && + is_last_spte(iter->old_spte, iter->level)) + return RET_PF_SPURIOUS; + if (unlikely(!fault->slot)) new_spte = make_mmio_spte(vcpu, iter->gfn, ACC_ALL); else wrprot = make_spte(vcpu, sp, fault->slot, ACC_ALL, iter->gfn, - fault->pfn, iter->old_spte, fault->prefetch, true, - fault->map_writable, &new_spte); + fault->pfn, iter->old_spte, fault->prefetch, + false, fault->map_writable, &new_spte); if (new_spte == iter->old_spte) ret = RET_PF_SPURIOUS; else if (tdp_mmu_set_spte_atomic(vcpu->kvm, iter, new_spte)) return RET_PF_RETRY; else if (is_shadow_present_pte(iter->old_spte) && - !is_last_spte(iter->old_spte, iter->level)) + (!is_last_spte(iter->old_spte, iter->level) || + WARN_ON_ONCE(leaf_spte_change_needs_tlb_flush(iter->old_spte, new_spte)))) kvm_flush_remote_tlbs_gfn(vcpu->kvm, iter->gfn, iter->level); /* @@ -1078,7 +1043,7 @@ static int tdp_mmu_map_handle_target_level(struct kvm_vcpu *vcpu, static int tdp_mmu_link_sp(struct kvm *kvm, struct tdp_iter *iter, struct kvm_mmu_page *sp, bool shared) { - u64 spte = make_nonleaf_spte(sp->spt, !kvm_ad_enabled()); + u64 spte = make_nonleaf_spte(sp->spt, !kvm_ad_enabled); int ret = 0; if (shared) { @@ -1195,33 +1160,6 @@ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range, return flush; } -typedef bool (*tdp_handler_t)(struct kvm *kvm, struct tdp_iter *iter, - struct kvm_gfn_range *range); - -static __always_inline bool kvm_tdp_mmu_handle_gfn(struct kvm *kvm, - struct kvm_gfn_range *range, - tdp_handler_t handler) -{ - struct kvm_mmu_page *root; - struct tdp_iter iter; - bool ret = false; - - /* - * Don't support rescheduling, none of the MMU notifiers that funnel - * into this helper allow blocking; it'd be dead, wasteful code. - */ - for_each_tdp_mmu_root(kvm, root, range->slot->as_id) { - rcu_read_lock(); - - tdp_root_for_each_leaf_pte(iter, root, range->start, range->end) - ret |= handler(kvm, &iter, range); - - rcu_read_unlock(); - } - - return ret; -} - /* * Mark the SPTEs range of GFNs [start, end) unaccessed and return non-zero * if any of the GFNs in the range have been accessed. @@ -1230,15 +1168,10 @@ static __always_inline bool kvm_tdp_mmu_handle_gfn(struct kvm *kvm, * 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) +static void kvm_tdp_mmu_age_spte(struct tdp_iter *iter) { 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; - if (spte_ad_enabled(iter->old_spte)) { iter->old_spte = tdp_mmu_clear_spte_bits(iter->sptep, iter->old_spte, @@ -1246,13 +1179,6 @@ static bool age_gfn_range(struct kvm *kvm, struct tdp_iter *iter, 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(iter->old_spte)) - kvm_set_pfn_dirty(spte_to_pfn(iter->old_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, @@ -1261,23 +1187,48 @@ static bool age_gfn_range(struct kvm *kvm, struct tdp_iter *iter, trace_kvm_tdp_mmu_spte_changed(iter->as_id, iter->gfn, iter->level, iter->old_spte, new_spte); - return true; } -bool kvm_tdp_mmu_age_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range) +static bool __kvm_tdp_mmu_age_gfn_range(struct kvm *kvm, + struct kvm_gfn_range *range, + bool test_only) { - return kvm_tdp_mmu_handle_gfn(kvm, range, age_gfn_range); + struct kvm_mmu_page *root; + struct tdp_iter iter; + bool ret = false; + + /* + * Don't support rescheduling, none of the MMU notifiers that funnel + * into this helper allow blocking; it'd be dead, wasteful code. Note, + * this helper must NOT be used to unmap GFNs, as it processes only + * valid roots! + */ + for_each_valid_tdp_mmu_root(kvm, root, range->slot->as_id) { + guard(rcu)(); + + tdp_root_for_each_leaf_pte(iter, root, range->start, range->end) { + if (!is_accessed_spte(iter.old_spte)) + continue; + + if (test_only) + return true; + + ret = true; + kvm_tdp_mmu_age_spte(&iter); + } + } + + return ret; } -static bool test_age_gfn(struct kvm *kvm, struct tdp_iter *iter, - struct kvm_gfn_range *range) +bool kvm_tdp_mmu_age_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range) { - return is_accessed_spte(iter->old_spte); + return __kvm_tdp_mmu_age_gfn_range(kvm, range, false); } bool kvm_tdp_mmu_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) { - return kvm_tdp_mmu_handle_gfn(kvm, range, test_age_gfn); + return __kvm_tdp_mmu_age_gfn_range(kvm, range, true); } /* @@ -1368,7 +1319,7 @@ static int tdp_mmu_split_huge_page(struct kvm *kvm, struct tdp_iter *iter, * not been linked in yet and thus is not reachable from any other CPU. */ for (i = 0; i < SPTE_ENT_PER_PAGE; i++) - sp->spt[i] = make_huge_page_split_spte(kvm, huge_spte, sp->role, i); + sp->spt[i] = make_small_spte(kvm, huge_spte, sp->role, i); /* * Replace the huge spte with a pointer to the populated lower level @@ -1501,16 +1452,15 @@ static bool tdp_mmu_need_write_protect(struct kvm_mmu_page *sp) * from level, so it is valid to key off any shadow page to determine if * write protection is needed for an entire tree. */ - return kvm_mmu_page_ad_need_write_protect(sp) || !kvm_ad_enabled(); + return kvm_mmu_page_ad_need_write_protect(sp) || !kvm_ad_enabled; } -static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, - gfn_t start, gfn_t end) +static void clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, + gfn_t start, gfn_t end) { const u64 dbit = tdp_mmu_need_write_protect(root) ? PT_WRITABLE_MASK : shadow_dirty_mask; struct tdp_iter iter; - bool spte_set = false; rcu_read_lock(); @@ -1531,31 +1481,24 @@ static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, if (tdp_mmu_set_spte_atomic(kvm, &iter, iter.old_spte & ~dbit)) goto retry; - - spte_set = true; } rcu_read_unlock(); - return spte_set; } /* * Clear the dirty status (D-bit or W-bit) of all the SPTEs mapping GFNs in the - * memslot. Returns true if an SPTE has been changed and the TLBs need to be - * flushed. + * memslot. */ -bool kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, +void kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, const struct kvm_memory_slot *slot) { struct kvm_mmu_page *root; - bool spte_set = false; lockdep_assert_held_read(&kvm->mmu_lock); for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id) - spte_set |= clear_dirty_gfn_range(kvm, root, slot->base_gfn, - slot->base_gfn + slot->npages); - - return spte_set; + clear_dirty_gfn_range(kvm, root, slot->base_gfn, + slot->base_gfn + slot->npages); } static void clear_dirty_pt_masked(struct kvm *kvm, struct kvm_mmu_page *root, @@ -1593,7 +1536,6 @@ static void clear_dirty_pt_masked(struct kvm *kvm, struct kvm_mmu_page *root, 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(); @@ -1615,21 +1557,55 @@ void kvm_tdp_mmu_clear_dirty_pt_masked(struct kvm *kvm, clear_dirty_pt_masked(kvm, root, gfn, mask, wrprot); } -static void zap_collapsible_spte_range(struct kvm *kvm, - struct kvm_mmu_page *root, - const struct kvm_memory_slot *slot) +static int tdp_mmu_make_huge_spte(struct kvm *kvm, + struct tdp_iter *parent, + u64 *huge_spte) +{ + struct kvm_mmu_page *root = spte_to_child_sp(parent->old_spte); + gfn_t start = parent->gfn; + gfn_t end = start + KVM_PAGES_PER_HPAGE(parent->level); + struct tdp_iter iter; + + tdp_root_for_each_leaf_pte(iter, root, start, end) { + /* + * Use the parent iterator when checking for forward progress so + * that KVM doesn't get stuck continuously trying to yield (i.e. + * returning -EAGAIN here and then failing the forward progress + * check in the caller ad nauseam). + */ + if (tdp_mmu_iter_need_resched(kvm, parent)) + return -EAGAIN; + + *huge_spte = make_huge_spte(kvm, iter.old_spte, parent->level); + return 0; + } + + return -ENOENT; +} + +static void recover_huge_pages_range(struct kvm *kvm, + struct kvm_mmu_page *root, + const struct kvm_memory_slot *slot) { gfn_t start = slot->base_gfn; gfn_t end = start + slot->npages; struct tdp_iter iter; int max_mapping_level; + bool flush = false; + u64 huge_spte; + int r; + + if (WARN_ON_ONCE(kvm_slot_dirty_track_enabled(slot))) + return; rcu_read_lock(); for_each_tdp_pte_min_level(iter, root, PG_LEVEL_2M, start, end) { retry: - if (tdp_mmu_iter_cond_resched(kvm, &iter, false, true)) + if (tdp_mmu_iter_cond_resched(kvm, &iter, flush, true)) { + flush = false; continue; + } if (iter.level > KVM_MAX_HUGEPAGE_LEVEL || !is_shadow_present_pte(iter.old_spte)) @@ -1653,31 +1629,40 @@ static void zap_collapsible_spte_range(struct kvm *kvm, if (iter.gfn < start || iter.gfn >= end) continue; - max_mapping_level = kvm_mmu_max_mapping_level(kvm, slot, - iter.gfn, PG_LEVEL_NUM); + max_mapping_level = kvm_mmu_max_mapping_level(kvm, slot, iter.gfn); if (max_mapping_level < iter.level) continue; - /* Note, a successful atomic zap also does a remote TLB flush. */ - if (tdp_mmu_zap_spte_atomic(kvm, &iter)) + r = tdp_mmu_make_huge_spte(kvm, &iter, &huge_spte); + if (r == -EAGAIN) + goto retry; + else if (r) + continue; + + if (tdp_mmu_set_spte_atomic(kvm, &iter, huge_spte)) goto retry; + + flush = true; } + if (flush) + kvm_flush_remote_tlbs_memslot(kvm, slot); + rcu_read_unlock(); } /* - * Zap non-leaf SPTEs (and free their associated page tables) which could - * be replaced by huge pages, for GFNs within the slot. + * Recover huge page mappings within the slot by replacing non-leaf SPTEs with + * huge SPTEs where possible. */ -void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm, - const struct kvm_memory_slot *slot) +void kvm_tdp_mmu_recover_huge_pages(struct kvm *kvm, + const struct kvm_memory_slot *slot) { struct kvm_mmu_page *root; lockdep_assert_held_read(&kvm->mmu_lock); for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id) - zap_collapsible_spte_range(kvm, root, slot); + recover_huge_pages_range(kvm, root, slot); } /* diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h index 1b74e058a81c95..f03ca0dd13d9df 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.h +++ b/arch/x86/kvm/mmu/tdp_mmu.h @@ -34,14 +34,14 @@ bool kvm_tdp_mmu_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range); bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm, const struct kvm_memory_slot *slot, int min_level); -bool kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, +void kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, const struct kvm_memory_slot *slot); void kvm_tdp_mmu_clear_dirty_pt_masked(struct kvm *kvm, struct kvm_memory_slot *slot, gfn_t gfn, unsigned long mask, bool wrprot); -void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm, - const struct kvm_memory_slot *slot); +void kvm_tdp_mmu_recover_huge_pages(struct kvm *kvm, + const struct kvm_memory_slot *slot); bool kvm_tdp_mmu_write_protect_gfn(struct kvm *kvm, struct kvm_memory_slot *slot, gfn_t gfn, diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c index 05490b9d8a434f..6f74e2b27c1ed5 100644 --- a/arch/x86/kvm/mtrr.c +++ b/arch/x86/kvm/mtrr.c @@ -19,6 +19,7 @@ #include #include "cpuid.h" +#include "x86.h" static u64 *find_mtrr(struct kvm_vcpu *vcpu, unsigned int msr) { diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h index 0d17d6b7063964..e46220ece83c60 100644 --- a/arch/x86/kvm/reverse_cpuid.h +++ b/arch/x86/kvm/reverse_cpuid.h @@ -46,6 +46,7 @@ enum kvm_only_cpuid_leafs { #define X86_FEATURE_AVX_VNNI_INT8 KVM_X86_FEATURE(CPUID_7_1_EDX, 4) #define X86_FEATURE_AVX_NE_CONVERT KVM_X86_FEATURE(CPUID_7_1_EDX, 5) #define X86_FEATURE_AMX_COMPLEX KVM_X86_FEATURE(CPUID_7_1_EDX, 8) +#define X86_FEATURE_AVX_VNNI_INT16 KVM_X86_FEATURE(CPUID_7_1_EDX, 10) #define X86_FEATURE_PREFETCHITI KVM_X86_FEATURE(CPUID_7_1_EDX, 14) #define X86_FEATURE_AVX10 KVM_X86_FEATURE(CPUID_7_1_EDX, 19) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 4b74ea91f4e6bb..65fd245a9953ce 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -1199,6 +1199,12 @@ bool avic_hardware_setup(void) return false; } + if (cc_platform_has(CC_ATTR_HOST_SEV_SNP) && + !boot_cpu_has(X86_FEATURE_HV_INUSE_WR_ALLOWED)) { + pr_warn("AVIC disabled: missing HvInUseWrAllowed on SNP-enabled system\n"); + return false; + } + if (boot_cpu_has(X86_FEATURE_AVIC)) { pr_info("AVIC enabled\n"); } else if (force_avic) { diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index cf84103ce38b97..b708bdf7eaffd2 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -926,7 +926,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu) nested_svm_vmexit(svm); out: - kvm_vcpu_unmap(vcpu, &map, true); + kvm_vcpu_unmap(vcpu, &map); return ret; } @@ -1130,7 +1130,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm) vmcb12->control.exit_int_info_err, KVM_ISA_SVM); - kvm_vcpu_unmap(vcpu, &map, true); + kvm_vcpu_unmap(vcpu, &map); nested_svm_transition_tlb_flush(vcpu); diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index fb854cf20ac3be..943bd074a5d372 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -533,17 +533,12 @@ static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error) static int __sev_issue_cmd(int fd, int id, void *data, int *error) { - struct fd f; - int ret; + CLASS(fd, f)(fd); - f = fdget(fd); - if (!fd_file(f)) + if (fd_empty(f)) return -EBADF; - ret = sev_issue_cmd_external_user(fd_file(f), id, data, error); - - fdput(f); - return ret; + return sev_issue_cmd_external_user(fd_file(f), id, data, error); } static int sev_issue_cmd(struct kvm *kvm, int id, void *data, int *error) @@ -2076,23 +2071,21 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd) { struct kvm_sev_info *dst_sev = &to_kvm_svm(kvm)->sev_info; struct kvm_sev_info *src_sev, *cg_cleanup_sev; - struct fd f = fdget(source_fd); + CLASS(fd, f)(source_fd); struct kvm *source_kvm; bool charged = false; int ret; - if (!fd_file(f)) + if (fd_empty(f)) return -EBADF; - if (!file_is_kvm(fd_file(f))) { - ret = -EBADF; - goto out_fput; - } + if (!file_is_kvm(fd_file(f))) + return -EBADF; source_kvm = fd_file(f)->private_data; ret = sev_lock_two_vms(kvm, source_kvm); if (ret) - goto out_fput; + return ret; if (kvm->arch.vm_type != source_kvm->arch.vm_type || sev_guest(kvm) || !sev_guest(source_kvm)) { @@ -2139,8 +2132,6 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd) cg_cleanup_sev->misc_cg = NULL; out_unlock: sev_unlock_two_vms(kvm, source_kvm); -out_fput: - fdput(f); return ret; } @@ -2801,23 +2792,21 @@ int sev_mem_enc_unregister_region(struct kvm *kvm, int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd) { - struct fd f = fdget(source_fd); + CLASS(fd, f)(source_fd); struct kvm *source_kvm; struct kvm_sev_info *source_sev, *mirror_sev; int ret; - if (!fd_file(f)) + if (fd_empty(f)) return -EBADF; - if (!file_is_kvm(fd_file(f))) { - ret = -EBADF; - goto e_source_fput; - } + if (!file_is_kvm(fd_file(f))) + return -EBADF; source_kvm = fd_file(f)->private_data; ret = sev_lock_two_vms(kvm, source_kvm); if (ret) - goto e_source_fput; + return ret; /* * Mirrors of mirrors should work, but let's not get silly. Also @@ -2860,8 +2849,6 @@ int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd) e_unlock: sev_unlock_two_vms(kvm, source_kvm); -e_source_fput: - fdput(f); return ret; } @@ -3471,7 +3458,7 @@ void sev_es_unmap_ghcb(struct vcpu_svm *svm) sev_es_sync_to_ghcb(svm); - kvm_vcpu_unmap(&svm->vcpu, &svm->sev_es.ghcb_map, true); + kvm_vcpu_unmap(&svm->vcpu, &svm->sev_es.ghcb_map); svm->sev_es.ghcb = NULL; } @@ -3852,6 +3839,7 @@ static int __sev_snp_update_protected_guest_state(struct kvm_vcpu *vcpu) if (VALID_PAGE(svm->sev_es.snp_vmsa_gpa)) { gfn_t gfn = gpa_to_gfn(svm->sev_es.snp_vmsa_gpa); struct kvm_memory_slot *slot; + struct page *page; kvm_pfn_t pfn; slot = gfn_to_memslot(vcpu->kvm, gfn); @@ -3862,7 +3850,7 @@ static int __sev_snp_update_protected_guest_state(struct kvm_vcpu *vcpu) * The new VMSA will be private memory guest memory, so * retrieve the PFN from the gmem backend. */ - if (kvm_gmem_get_pfn(vcpu->kvm, slot, gfn, &pfn, NULL)) + if (kvm_gmem_get_pfn(vcpu->kvm, slot, gfn, &pfn, &page, NULL)) return -EINVAL; /* @@ -3891,7 +3879,7 @@ static int __sev_snp_update_protected_guest_state(struct kvm_vcpu *vcpu) * changes then care should be taken to ensure * svm->sev_es.vmsa is pinned through some other means. */ - kvm_release_pfn_clean(pfn); + kvm_release_page_clean(page); } /* @@ -4691,6 +4679,7 @@ void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) struct kvm_memory_slot *slot; struct kvm *kvm = vcpu->kvm; int order, rmp_level, ret; + struct page *page; bool assigned; kvm_pfn_t pfn; gfn_t gfn; @@ -4717,7 +4706,7 @@ void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) return; } - ret = kvm_gmem_get_pfn(kvm, slot, gfn, &pfn, &order); + ret = kvm_gmem_get_pfn(kvm, slot, gfn, &pfn, &page, &order); if (ret) { pr_warn_ratelimited("SEV: Unexpected RMP fault, no backing page for private GPA 0x%llx\n", gpa); @@ -4775,7 +4764,7 @@ void sev_handle_rmp_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u64 error_code) out: trace_kvm_rmp_fault(vcpu, gpa, pfn, error_code, rmp_level, ret); out_no_trace: - put_page(pfn_to_page(pfn)); + kvm_release_page_unused(page); } static bool is_pfn_range_shared(kvm_pfn_t start, kvm_pfn_t end) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 9df3e1e5ae81a1..21dacd31277922 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1390,7 +1390,9 @@ static void __svm_vcpu_reset(struct kvm_vcpu *vcpu) svm_vcpu_init_msrpm(vcpu, svm->msrpm); svm_init_osvw(vcpu); - vcpu->arch.microcode_version = 0x01000065; + + if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_STUFF_FEATURE_MSRS)) + vcpu->arch.microcode_version = 0x01000065; svm->tsc_ratio_msr = kvm_caps.default_tsc_scaling_ratio; svm->nmi_masked = false; @@ -2299,7 +2301,7 @@ static int vmload_vmsave_interception(struct kvm_vcpu *vcpu, bool vmload) svm_copy_vmloadsave_state(vmcb12, svm->vmcb); } - kvm_vcpu_unmap(vcpu, &map, true); + kvm_vcpu_unmap(vcpu, &map); return ret; } @@ -3199,15 +3201,6 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) if (data & ~supported_de_cfg) return 1; - /* - * Don't let the guest change the host-programmed value. The - * MSR is very model specific, i.e. contains multiple bits that - * are completely unknown to KVM, and the one bit known to KVM - * is simply a reflection of hardware capabilities. - */ - if (!msr->host_initiated && data != svm->msr_decfg) - return 1; - svm->msr_decfg = data; break; } @@ -4714,7 +4707,7 @@ static int svm_enter_smm(struct kvm_vcpu *vcpu, union kvm_smram *smram) svm_copy_vmrun_state(map_save.hva + 0x400, &svm->vmcb01.ptr->save); - kvm_vcpu_unmap(vcpu, &map_save, true); + kvm_vcpu_unmap(vcpu, &map_save); return 0; } @@ -4774,9 +4767,9 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram) svm->nested.nested_run_pending = 1; unmap_save: - kvm_vcpu_unmap(vcpu, &map_save, true); + kvm_vcpu_unmap(vcpu, &map_save); unmap_map: - kvm_vcpu_unmap(vcpu, &map, true); + kvm_vcpu_unmap(vcpu, &map); return ret; } @@ -5031,6 +5024,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .get_segment = svm_get_segment, .set_segment = svm_set_segment, .get_cpl = svm_get_cpl, + .get_cpl_no_cache = svm_get_cpl, .get_cs_db_l_bits = svm_get_cs_db_l_bits, .is_valid_cr0 = svm_is_valid_cr0, .set_cr0 = svm_set_cr0, diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c index fab6a1ad98dc18..fa41d036acd49e 100644 --- a/arch/x86/kvm/vmx/hyperv.c +++ b/arch/x86/kvm/vmx/hyperv.c @@ -4,6 +4,7 @@ #include #include +#include "x86.h" #include "../cpuid.h" #include "hyperv.h" #include "nested.h" diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index 7668e2fb8043ef..92d35cc6cd15d8 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -50,6 +50,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = { .get_segment = vmx_get_segment, .set_segment = vmx_set_segment, .get_cpl = vmx_get_cpl, + .get_cpl_no_cache = vmx_get_cpl_no_cache, .get_cs_db_l_bits = vmx_get_cs_db_l_bits, .is_valid_cr0 = vmx_is_valid_cr0, .set_cr0 = vmx_set_cr0, diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 931a7361c30f2d..aa78b6f38dfefd 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -7,6 +7,7 @@ #include #include +#include "x86.h" #include "cpuid.h" #include "hyperv.h" #include "mmu.h" @@ -16,7 +17,6 @@ #include "sgx.h" #include "trace.h" #include "vmx.h" -#include "x86.h" #include "smm.h" static bool __read_mostly enable_shadow_vmcs = 1; @@ -231,11 +231,8 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu) struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu); - if (nested_vmx_is_evmptr12_valid(vmx)) { - kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true); - vmx->nested.hv_evmcs = NULL; - } - + kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map); + vmx->nested.hv_evmcs = NULL; vmx->nested.hv_evmcs_vmptr = EVMPTR_INVALID; if (hv_vcpu) { @@ -317,6 +314,16 @@ static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs) vcpu->arch.regs_dirty = 0; } +static void nested_put_vmcs12_pages(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + kvm_vcpu_unmap(vcpu, &vmx->nested.apic_access_page_map); + kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map); + kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map); + vmx->nested.pi_desc = NULL; +} + /* * Free whatever needs to be freed from vmx->nested when L1 goes down, or * just stops using VMX. @@ -349,15 +356,8 @@ static void free_nested(struct kvm_vcpu *vcpu) vmx->nested.cached_vmcs12 = NULL; kfree(vmx->nested.cached_shadow_vmcs12); vmx->nested.cached_shadow_vmcs12 = NULL; - /* - * Unpin physical memory we referred to in the vmcs02. The APIC access - * page's backing page (yeah, confusing) shouldn't actually be accessed, - * and if it is written, the contents are irrelevant. - */ - kvm_vcpu_unmap(vcpu, &vmx->nested.apic_access_page_map, false); - kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true); - kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true); - vmx->nested.pi_desc = NULL; + + nested_put_vmcs12_pages(vcpu); kvm_mmu_free_roots(vcpu->kvm, &vcpu->arch.guest_mmu, KVM_MMU_ROOTS_ALL); @@ -624,7 +624,7 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu, int msr; unsigned long *msr_bitmap_l1; unsigned long *msr_bitmap_l0 = vmx->nested.vmcs02.msr_bitmap; - struct kvm_host_map *map = &vmx->nested.msr_bitmap_map; + struct kvm_host_map map; /* Nothing to do if the MSR bitmap is not in use. */ if (!cpu_has_vmx_msr_bitmap() || @@ -647,10 +647,10 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu, return true; } - if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->msr_bitmap), map)) + if (kvm_vcpu_map_readonly(vcpu, gpa_to_gfn(vmcs12->msr_bitmap), &map)) return false; - msr_bitmap_l1 = (unsigned long *)map->hva; + msr_bitmap_l1 = (unsigned long *)map.hva; /* * To keep the control flow simple, pay eight 8-byte writes (sixteen @@ -714,7 +714,7 @@ 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_FLUSH_CMD, MSR_TYPE_W); - kvm_vcpu_unmap(vcpu, &vmx->nested.msr_bitmap_map, false); + kvm_vcpu_unmap(vcpu, &map); vmx->nested.force_msr_bitmap_recalc = false; @@ -3010,6 +3010,17 @@ static int nested_vmx_check_address_space_size(struct kvm_vcpu *vcpu, return 0; } +static bool is_l1_noncanonical_address_on_vmexit(u64 la, struct vmcs12 *vmcs12) +{ + /* + * Check that the given linear address is canonical after a VM exit + * from L2, based on HOST_CR4.LA57 value that will be loaded for L1. + */ + u8 l1_address_bits_on_exit = (vmcs12->host_cr4 & X86_CR4_LA57) ? 57 : 48; + + return !__is_canonical_address(la, l1_address_bits_on_exit); +} + static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { @@ -3020,8 +3031,8 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, CC(!kvm_vcpu_is_legal_cr3(vcpu, vmcs12->host_cr3))) return -EINVAL; - if (CC(is_noncanonical_address(vmcs12->host_ia32_sysenter_esp, vcpu)) || - CC(is_noncanonical_address(vmcs12->host_ia32_sysenter_eip, vcpu))) + if (CC(is_noncanonical_msr_address(vmcs12->host_ia32_sysenter_esp, vcpu)) || + CC(is_noncanonical_msr_address(vmcs12->host_ia32_sysenter_eip, vcpu))) return -EINVAL; if ((vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PAT) && @@ -3055,12 +3066,12 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, CC(vmcs12->host_ss_selector == 0 && !ia32e)) return -EINVAL; - if (CC(is_noncanonical_address(vmcs12->host_fs_base, vcpu)) || - CC(is_noncanonical_address(vmcs12->host_gs_base, vcpu)) || - CC(is_noncanonical_address(vmcs12->host_gdtr_base, vcpu)) || - CC(is_noncanonical_address(vmcs12->host_idtr_base, vcpu)) || - CC(is_noncanonical_address(vmcs12->host_tr_base, vcpu)) || - CC(is_noncanonical_address(vmcs12->host_rip, vcpu))) + if (CC(is_noncanonical_base_address(vmcs12->host_fs_base, vcpu)) || + CC(is_noncanonical_base_address(vmcs12->host_gs_base, vcpu)) || + CC(is_noncanonical_base_address(vmcs12->host_gdtr_base, vcpu)) || + CC(is_noncanonical_base_address(vmcs12->host_idtr_base, vcpu)) || + CC(is_noncanonical_base_address(vmcs12->host_tr_base, vcpu)) || + CC(is_l1_noncanonical_address_on_vmexit(vmcs12->host_rip, vmcs12))) return -EINVAL; /* @@ -3178,7 +3189,7 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu, } if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS) && - (CC(is_noncanonical_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu)) || + (CC(is_noncanonical_msr_address(vmcs12->guest_bndcfgs & PAGE_MASK, vcpu)) || CC((vmcs12->guest_bndcfgs & MSR_IA32_BNDCFGS_RSVD)))) return -EINVAL; @@ -5027,11 +5038,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, vmx_update_cpu_dirty_logging(vcpu); } - /* Unpin physical memory we referred to in vmcs02 */ - kvm_vcpu_unmap(vcpu, &vmx->nested.apic_access_page_map, false); - kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true); - kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true); - vmx->nested.pi_desc = NULL; + nested_put_vmcs12_pages(vcpu); if (vmx->nested.reload_vmcs01_apic_access_page) { vmx->nested.reload_vmcs01_apic_access_page = false; @@ -5167,7 +5174,7 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification, * non-canonical form. This is the only check on the memory * destination for long mode! */ - exn = is_noncanonical_address(*ret, vcpu); + exn = is_noncanonical_address(*ret, vcpu, 0); } else { /* * When not in long mode, the virtual/linear address is @@ -5978,7 +5985,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) * invalidation. */ if (!operand.vpid || - is_noncanonical_address(operand.gla, vcpu)) + is_noncanonical_invlpg_address(operand.gla, vcpu)) return nested_vmx_fail(vcpu, VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID); vpid_sync_vcpu_addr(vpid02, operand.gla); diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 83382a4d1d66fd..9c9d4a3361664e 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -365,7 +365,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) } break; case MSR_IA32_DS_AREA: - if (is_noncanonical_address(data, vcpu)) + if (is_noncanonical_msr_address(data, vcpu)) return 1; pmu->ds_area = data; diff --git a/arch/x86/kvm/vmx/posted_intr.h b/arch/x86/kvm/vmx/posted_intr.h index 1715d2ab07be5d..ad9116a99bccb2 100644 --- a/arch/x86/kvm/vmx/posted_intr.h +++ b/arch/x86/kvm/vmx/posted_intr.h @@ -2,7 +2,7 @@ #ifndef __KVM_X86_VMX_POSTED_INTR_H #define __KVM_X86_VMX_POSTED_INTR_H -#include +#include #include void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu); diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c index a3c3d2a51f47d1..b352a3ba7354a2 100644 --- a/arch/x86/kvm/vmx/sgx.c +++ b/arch/x86/kvm/vmx/sgx.c @@ -4,12 +4,11 @@ #include -#include "cpuid.h" +#include "x86.h" #include "kvm_cache_regs.h" #include "nested.h" #include "sgx.h" #include "vmx.h" -#include "x86.h" bool __read_mostly enable_sgx = 1; module_param_named(sgx, enable_sgx, bool, 0444); @@ -38,7 +37,7 @@ static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset, fault = true; } else if (likely(is_64_bit_mode(vcpu))) { *gva = vmx_get_untagged_addr(vcpu, *gva, 0); - fault = is_noncanonical_address(*gva, vcpu); + fault = is_noncanonical_address(*gva, vcpu, 0); } else { *gva &= 0xffffffff; fault = (s.unusable) || diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index d28618e9277ede..893366e5373224 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -483,10 +483,9 @@ noinline void invvpid_error(unsigned long ext, u16 vpid, gva_t gva) ext, vpid, gva); } -noinline void invept_error(unsigned long ext, u64 eptp, gpa_t gpa) +noinline void invept_error(unsigned long ext, u64 eptp) { - vmx_insn_failed("invept failed: ext=0x%lx eptp=%llx gpa=0x%llx\n", - ext, eptp, gpa); + vmx_insn_failed("invept failed: ext=0x%lx eptp=%llx\n", ext, eptp); } static DEFINE_PER_CPU(struct vmcs *, vmxarea); @@ -2285,7 +2284,7 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) (!msr_info->host_initiated && !guest_cpuid_has(vcpu, X86_FEATURE_MPX))) return 1; - if (is_noncanonical_address(data & PAGE_MASK, vcpu) || + if (is_noncanonical_msr_address(data & PAGE_MASK, vcpu) || (data & MSR_IA32_BNDCFGS_RSVD)) return 1; @@ -2450,7 +2449,7 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) index = msr_info->index - MSR_IA32_RTIT_ADDR0_A; if (index >= 2 * vmx->pt_desc.num_address_ranges) return 1; - if (is_noncanonical_address(data, vcpu)) + if (is_noncanonical_msr_address(data, vcpu)) return 1; if (index % 2) vmx->pt_desc.guest.addr_b[index / 2] = data; @@ -2458,8 +2457,6 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vmx->pt_desc.guest.addr_a[index / 2] = data; break; case MSR_IA32_PERF_CAPABILITIES: - if (data && !vcpu_to_pmu(vcpu)->version) - return 1; if (data & PMU_CAP_LBR_FMT) { if ((data & PMU_CAP_LBR_FMT) != (kvm_caps.supported_perf_cap & PMU_CAP_LBR_FMT)) @@ -2551,28 +2548,6 @@ static bool cpu_has_sgx(void) return cpuid_eax(0) >= 0x12 && (cpuid_eax(0x12) & BIT(0)); } -/* - * Some cpus support VM_{ENTRY,EXIT}_IA32_PERF_GLOBAL_CTRL but they - * can't be used due to errata where VM Exit may incorrectly clear - * IA32_PERF_GLOBAL_CTRL[34:32]. Work around the errata by using the - * MSR load mechanism to switch IA32_PERF_GLOBAL_CTRL. - */ -static bool cpu_has_perf_global_ctrl_bug(void) -{ - switch (boot_cpu_data.x86_vfm) { - case INTEL_NEHALEM_EP: /* AAK155 */ - case INTEL_NEHALEM: /* AAP115 */ - case INTEL_WESTMERE: /* AAT100 */ - case INTEL_WESTMERE_EP: /* BC86,AAY89,BD102 */ - case INTEL_NEHALEM_EX: /* BA97 */ - return true; - default: - break; - } - - return false; -} - static int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, u32 msr, u32 *result) { u32 vmx_msr_low, vmx_msr_high; @@ -2732,6 +2707,27 @@ static int setup_vmcs_config(struct vmcs_config *vmcs_conf, _vmexit_control &= ~x_ctrl; } + /* + * Some cpus support VM_{ENTRY,EXIT}_IA32_PERF_GLOBAL_CTRL but they + * can't be used due to an errata where VM Exit may incorrectly clear + * IA32_PERF_GLOBAL_CTRL[34:32]. Workaround the errata by using the + * MSR load mechanism to switch IA32_PERF_GLOBAL_CTRL. + */ + switch (boot_cpu_data.x86_vfm) { + case INTEL_NEHALEM_EP: /* AAK155 */ + case INTEL_NEHALEM: /* AAP115 */ + case INTEL_WESTMERE: /* AAT100 */ + case INTEL_WESTMERE_EP: /* BC86,AAY89,BD102 */ + case INTEL_NEHALEM_EX: /* BA97 */ + _vmentry_control &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; + _vmexit_control &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; + pr_warn_once("VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL " + "does not work properly. Using workaround\n"); + break; + default: + break; + } + rdmsrl(MSR_IA32_VMX_BASIC, basic_msr); /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ @@ -3570,16 +3566,29 @@ u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg) return vmx_read_guest_seg_base(to_vmx(vcpu), seg); } -int vmx_get_cpl(struct kvm_vcpu *vcpu) +static int __vmx_get_cpl(struct kvm_vcpu *vcpu, bool no_cache) { struct vcpu_vmx *vmx = to_vmx(vcpu); + int ar; if (unlikely(vmx->rmode.vm86_active)) return 0; - else { - int ar = vmx_read_guest_seg_ar(vmx, VCPU_SREG_SS); - return VMX_AR_DPL(ar); - } + + if (no_cache) + ar = vmcs_read32(GUEST_SS_AR_BYTES); + else + ar = vmx_read_guest_seg_ar(vmx, VCPU_SREG_SS); + return VMX_AR_DPL(ar); +} + +int vmx_get_cpl(struct kvm_vcpu *vcpu) +{ + return __vmx_get_cpl(vcpu, false); +} + +int vmx_get_cpl_no_cache(struct kvm_vcpu *vcpu) +{ + return __vmx_get_cpl(vcpu, true); } static u32 vmx_segment_access_rights(struct kvm_segment *var) @@ -4422,9 +4431,6 @@ static u32 vmx_vmentry_ctrl(void) VM_ENTRY_LOAD_IA32_EFER | VM_ENTRY_IA32E_MODE); - if (cpu_has_perf_global_ctrl_bug()) - vmentry_ctrl &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; - return vmentry_ctrl; } @@ -4442,10 +4448,6 @@ static u32 vmx_vmexit_ctrl(void) if (vmx_pt_mode_is_system()) vmexit_ctrl &= ~(VM_EXIT_PT_CONCEAL_PIP | VM_EXIT_CLEAR_IA32_RTIT_CTL); - - if (cpu_has_perf_global_ctrl_bug()) - vmexit_ctrl &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; - /* Loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically */ return vmexit_ctrl & ~(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | VM_EXIT_LOAD_IA32_EFER); @@ -4561,7 +4563,8 @@ vmx_adjust_secondary_exec_control(struct vcpu_vmx *vmx, u32 *exec_control, * Update the nested MSR settings so that a nested VMM can/can't set * controls for features that are/aren't exposed to the guest. */ - if (nested) { + if (nested && + kvm_check_has_quirk(vmx->vcpu.kvm, KVM_X86_QUIRK_STUFF_FEATURE_MSRS)) { /* * All features that can be added or removed to VMX MSRs must * be supported in the first place for nested virtualization. @@ -4851,7 +4854,8 @@ static void __vmx_vcpu_reset(struct kvm_vcpu *vcpu) init_vmcs(vmx); - if (nested) + if (nested && + kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_STUFF_FEATURE_MSRS)) memcpy(&vmx->nested.msrs, &vmcs_config.nested, sizeof(vmx->nested.msrs)); vcpu_setup_sgx_lepubkeyhash(vcpu); @@ -4864,7 +4868,8 @@ static void __vmx_vcpu_reset(struct kvm_vcpu *vcpu) vmx->nested.hv_evmcs_vmptr = EVMPTR_INVALID; #endif - vcpu->arch.microcode_version = 0x100000000ULL; + if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_STUFF_FEATURE_MSRS)) + vcpu->arch.microcode_version = 0x100000000ULL; vmx->msr_ia32_feature_control_valid_bits = FEAT_CTL_LOCKED; /* @@ -6792,8 +6797,10 @@ void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu) struct kvm *kvm = vcpu->kvm; struct kvm_memslots *slots = kvm_memslots(kvm); struct kvm_memory_slot *slot; + struct page *refcounted_page; unsigned long mmu_seq; kvm_pfn_t pfn; + bool writable; /* Defer reload until vmcs01 is the current VMCS. */ if (is_guest_mode(vcpu)) { @@ -6829,30 +6836,30 @@ void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu) * controls the APIC-access page memslot, and only deletes the memslot * if APICv is permanently inhibited, i.e. the memslot won't reappear. */ - pfn = gfn_to_pfn_memslot(slot, gfn); + pfn = __kvm_faultin_pfn(slot, gfn, FOLL_WRITE, &writable, &refcounted_page); if (is_error_noslot_pfn(pfn)) return; read_lock(&vcpu->kvm->mmu_lock); - if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn)) { + if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn)) kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu); - read_unlock(&vcpu->kvm->mmu_lock); - goto out; - } + else + vmcs_write64(APIC_ACCESS_ADDR, pfn_to_hpa(pfn)); - vmcs_write64(APIC_ACCESS_ADDR, pfn_to_hpa(pfn)); - read_unlock(&vcpu->kvm->mmu_lock); + /* + * Do not pin the APIC access page in memory so that it can be freely + * migrated, the MMU notifier will call us again if it is migrated or + * swapped out. KVM backs the memslot with anonymous memory, the pfn + * should always point at a refcounted page (if the pfn is valid). + */ + if (!WARN_ON_ONCE(!refcounted_page)) + kvm_release_page_clean(refcounted_page); /* * No need for a manual TLB flush at this point, KVM has already done a * flush if there were SPTEs pointing at the previous page. */ -out: - /* - * Do not pin apic access page in memory, the MMU notifier - * will call us again if it is migrated or swapped out. - */ - kvm_release_pfn_clean(pfn); + read_unlock(&vcpu->kvm->mmu_lock); } void vmx_hwapic_isr_update(int max_isr) @@ -8400,10 +8407,6 @@ __init int vmx_hardware_setup(void) if (setup_vmcs_config(&vmcs_config, &vmx_capability) < 0) return -EIO; - if (cpu_has_perf_global_ctrl_bug()) - pr_warn_once("VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL " - "does not work properly. Using workaround\n"); - if (boot_cpu_has(X86_FEATURE_NX)) kvm_enable_efer_bits(EFER_NX); diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 2325f773a20be0..43f573f6ca46a3 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -200,8 +200,6 @@ struct nested_vmx { struct kvm_host_map virtual_apic_map; struct kvm_host_map pi_desc_map; - struct kvm_host_map msr_bitmap_map; - struct pi_desc *pi_desc; bool pi_pending; u16 posted_intr_nv; @@ -385,6 +383,7 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu); void vmx_set_host_fs_gs(struct vmcs_host_state *host, u16 fs_sel, u16 gs_sel, unsigned long fs_base, unsigned long gs_base); int vmx_get_cpl(struct kvm_vcpu *vcpu); +int vmx_get_cpl_no_cache(struct kvm_vcpu *vcpu); bool vmx_emulation_required(struct kvm_vcpu *vcpu); unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu); void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags); diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h index 93e020dc88f654..633c87e2fd92ee 100644 --- a/arch/x86/kvm/vmx/vmx_ops.h +++ b/arch/x86/kvm/vmx/vmx_ops.h @@ -15,7 +15,7 @@ void vmwrite_error(unsigned long field, unsigned long value); void vmclear_error(struct vmcs *vmcs, u64 phys_addr); void vmptrld_error(struct vmcs *vmcs, u64 phys_addr); void invvpid_error(unsigned long ext, u16 vpid, gva_t gva); -void invept_error(unsigned long ext, u64 eptp, gpa_t gpa); +void invept_error(unsigned long ext, u64 eptp); #ifndef CONFIG_CC_HAS_ASM_GOTO_OUTPUT /* @@ -312,13 +312,13 @@ static inline void __invvpid(unsigned long ext, u16 vpid, gva_t gva) vmx_asm2(invvpid, "r"(ext), "m"(operand), ext, vpid, gva); } -static inline void __invept(unsigned long ext, u64 eptp, gpa_t gpa) +static inline void __invept(unsigned long ext, u64 eptp) { struct { - u64 eptp, gpa; - } operand = {eptp, gpa}; - - vmx_asm2(invept, "r"(ext), "m"(operand), ext, eptp, gpa); + u64 eptp; + u64 reserved_0; + } operand = { eptp, 0 }; + vmx_asm2(invept, "r"(ext), "m"(operand), ext, eptp); } static inline void vpid_sync_vcpu_single(int vpid) @@ -355,13 +355,13 @@ static inline void vpid_sync_vcpu_addr(int vpid, gva_t addr) static inline void ept_sync_global(void) { - __invept(VMX_EPT_EXTENT_GLOBAL, 0, 0); + __invept(VMX_EPT_EXTENT_GLOBAL, 0); } static inline void ept_sync_context(u64 eptp) { if (cpu_has_vmx_invept_context()) - __invept(VMX_EPT_EXTENT_CONTEXT, eptp, 0); + __invept(VMX_EPT_EXTENT_CONTEXT, eptp); else ept_sync_global(); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 83fe0a78146fc1..c79a8cc57ba42d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -451,6 +451,7 @@ static const u32 msr_based_features_all_except_vmx[] = { MSR_IA32_UCODE_REV, MSR_IA32_ARCH_CAPABILITIES, MSR_IA32_PERF_CAPABILITIES, + MSR_PLATFORM_INFO, }; static u32 msr_based_features[ARRAY_SIZE(msr_based_features_all_except_vmx) + @@ -667,38 +668,6 @@ static void drop_user_return_notifiers(void) kvm_on_user_return(&msrs->urn); } -u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) -{ - return vcpu->arch.apic_base; -} - -enum lapic_mode kvm_get_apic_mode(struct kvm_vcpu *vcpu) -{ - return kvm_apic_mode(kvm_get_apic_base(vcpu)); -} -EXPORT_SYMBOL_GPL(kvm_get_apic_mode); - -int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info) -{ - enum lapic_mode old_mode = kvm_get_apic_mode(vcpu); - enum lapic_mode new_mode = kvm_apic_mode(msr_info->data); - u64 reserved_bits = kvm_vcpu_reserved_gpa_bits_raw(vcpu) | 0x2ff | - (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC) ? 0 : X2APIC_ENABLE); - - if ((msr_info->data & reserved_bits) != 0 || new_mode == LAPIC_MODE_INVALID) - return 1; - if (!msr_info->host_initiated) { - if (old_mode == LAPIC_MODE_X2APIC && new_mode == LAPIC_MODE_XAPIC) - return 1; - if (old_mode == LAPIC_MODE_DISABLED && new_mode == LAPIC_MODE_X2APIC) - return 1; - } - - kvm_lapic_set_base(vcpu, msr_info->data); - kvm_recalculate_apic_map(vcpu->kvm); - return 0; -} - /* * Handle a fault on a hardware virtualization (VMX or SVM) instruction. * @@ -1706,6 +1675,9 @@ static int kvm_get_feature_msr(struct kvm_vcpu *vcpu, u32 index, u64 *data, case MSR_IA32_PERF_CAPABILITIES: *data = kvm_caps.supported_perf_cap; break; + case MSR_PLATFORM_INFO: + *data = MSR_PLATFORM_INFO_CPUID_FAULT; + break; case MSR_IA32_UCODE_REV: rdmsrl_safe(index, data); break; @@ -1854,7 +1826,7 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data, case MSR_KERNEL_GS_BASE: case MSR_CSTAR: case MSR_LSTAR: - if (is_noncanonical_address(data, vcpu)) + if (is_noncanonical_msr_address(data, vcpu)) return 1; break; case MSR_IA32_SYSENTER_EIP: @@ -1871,7 +1843,7 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data, * value, and that something deterministic happens if the guest * invokes 64-bit SYSENTER. */ - data = __canonical_address(data, vcpu_virt_addr_bits(vcpu)); + data = __canonical_address(data, max_host_virt_addr_bits()); break; case MSR_TSC_AUX: if (!kvm_is_supported_user_return_msr(MSR_TSC_AUX)) @@ -2144,8 +2116,9 @@ EXPORT_SYMBOL_GPL(kvm_emulate_monitor); static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu) { xfer_to_guest_mode_prepare(); - return vcpu->mode == EXITING_GUEST_MODE || kvm_request_pending(vcpu) || - xfer_to_guest_mode_work_pending(); + + return READ_ONCE(vcpu->mode) == EXITING_GUEST_MODE || + kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending(); } /* @@ -3793,13 +3766,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.microcode_version = data; break; case MSR_IA32_ARCH_CAPABILITIES: - if (!msr_info->host_initiated) - return 1; + if (!msr_info->host_initiated || + !guest_cpuid_has(vcpu, X86_FEATURE_ARCH_CAPABILITIES)) + return KVM_MSR_RET_UNSUPPORTED; vcpu->arch.arch_capabilities = data; break; case MSR_IA32_PERF_CAPABILITIES: - if (!msr_info->host_initiated) - return 1; + if (!msr_info->host_initiated || + !guest_cpuid_has(vcpu, X86_FEATURE_PDCM)) + return KVM_MSR_RET_UNSUPPORTED; + if (data & ~kvm_caps.supported_perf_cap) return 1; @@ -3890,7 +3866,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_MTRRdefType: return kvm_mtrr_set_msr(vcpu, msr, data); case MSR_IA32_APICBASE: - return kvm_set_apic_base(vcpu, msr_info); + return kvm_apic_set_base(vcpu, data, msr_info->host_initiated); case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff: return kvm_x2apic_msr_write(vcpu, msr, data); case MSR_IA32_TSC_DEADLINE: @@ -4111,9 +4087,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.osvw.status = data; break; case MSR_PLATFORM_INFO: - if (!msr_info->host_initiated || - (!(data & MSR_PLATFORM_INFO_CPUID_FAULT) && - cpuid_fault_enabled(vcpu))) + if (!msr_info->host_initiated) return 1; vcpu->arch.msr_platform_info = data; break; @@ -4252,15 +4226,13 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = vcpu->arch.microcode_version; break; case MSR_IA32_ARCH_CAPABILITIES: - if (!msr_info->host_initiated && - !guest_cpuid_has(vcpu, X86_FEATURE_ARCH_CAPABILITIES)) - return 1; + if (!guest_cpuid_has(vcpu, X86_FEATURE_ARCH_CAPABILITIES)) + return KVM_MSR_RET_UNSUPPORTED; msr_info->data = vcpu->arch.arch_capabilities; break; case MSR_IA32_PERF_CAPABILITIES: - if (!msr_info->host_initiated && - !guest_cpuid_has(vcpu, X86_FEATURE_PDCM)) - return 1; + if (!guest_cpuid_has(vcpu, X86_FEATURE_PDCM)) + return KVM_MSR_RET_UNSUPPORTED; msr_info->data = vcpu->arch.perf_capabilities; break; case MSR_IA32_POWER_CTL: @@ -4314,7 +4286,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = 1 << 24; break; case MSR_IA32_APICBASE: - msr_info->data = kvm_get_apic_base(vcpu); + msr_info->data = vcpu->arch.apic_base; break; case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff: return kvm_x2apic_msr_read(vcpu, msr_info->index, &msr_info->data); @@ -5094,7 +5066,13 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) int idx; if (vcpu->preempted) { - vcpu->arch.preempted_in_kernel = kvm_arch_vcpu_in_kernel(vcpu); + /* + * Assume protected guests are in-kernel. Inefficient yielding + * due to false positives is preferable to never yielding due + * to false negatives. + */ + vcpu->arch.preempted_in_kernel = vcpu->arch.guest_state_protected || + !kvm_x86_call(get_cpl_no_cache)(vcpu); /* * Take the srcu lock as memslots will be accessed to check the gfn @@ -8612,6 +8590,12 @@ static gva_t emulator_get_untagged_addr(struct x86_emulate_ctxt *ctxt, addr, flags); } +static bool emulator_is_canonical_addr(struct x86_emulate_ctxt *ctxt, + gva_t addr, unsigned int flags) +{ + return !is_noncanonical_address(addr, emul_to_vcpu(ctxt), flags); +} + static const struct x86_emulate_ops emulate_ops = { .vm_bugged = emulator_vm_bugged, .read_gpr = emulator_read_gpr, @@ -8658,6 +8642,7 @@ static const struct x86_emulate_ops emulate_ops = { .triple_fault = emulator_triple_fault, .set_xcr = emulator_set_xcr, .get_untagged_addr = emulator_get_untagged_addr, + .is_canonical_addr = emulator_is_canonical_addr, }; static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) @@ -9991,7 +9976,7 @@ static int complete_hypercall_exit(struct kvm_vcpu *vcpu) { u64 ret = vcpu->run->hypercall.ret; - if (!is_64_bit_mode(vcpu)) + if (!is_64_bit_hypercall(vcpu)) ret = (u32)ret; kvm_rax_write(vcpu, ret); ++vcpu->stat.hypercalls; @@ -10159,7 +10144,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu) kvm_run->if_flag = kvm_x86_call(get_if_flag)(vcpu); kvm_run->cr8 = kvm_get_cr8(vcpu); - kvm_run->apic_base = kvm_get_apic_base(vcpu); + kvm_run->apic_base = vcpu->arch.apic_base; kvm_run->ready_for_interrupt_injection = pic_in_kernel(vcpu->kvm) || @@ -10576,8 +10561,8 @@ static void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu) * deleted if any vCPU has xAPIC virtualization and x2APIC enabled, but * and hardware doesn't support x2APIC virtualization. E.g. some AMD * CPUs support AVIC but not x2APIC. KVM still allows enabling AVIC in - * this case so that KVM can the AVIC doorbell to inject interrupts to - * running vCPUs, but KVM must not create SPTEs for the APIC base as + * this case so that KVM can use the AVIC doorbell to inject interrupts + * to running vCPUs, but KVM must not create SPTEs for the APIC base as * the vCPU would incorrectly be able to access the vAPIC page via MMIO * despite being in x2APIC mode. For simplicity, inhibiting the APIC * access page is sticky. @@ -10606,11 +10591,11 @@ void __kvm_set_or_clear_apicv_inhibit(struct kvm *kvm, if (!!old != !!new) { /* * Kick all vCPUs before setting apicv_inhibit_reasons to avoid - * false positives in the sanity check WARN in svm_vcpu_run(). + * false positives in the sanity check WARN in vcpu_enter_guest(). * This task will wait for all vCPUs to ack the kick IRQ before * updating apicv_inhibit_reasons, and all other vCPUs will * block on acquiring apicv_update_lock so that vCPUs can't - * redo svm_vcpu_run() without seeing the new inhibit state. + * redo vcpu_enter_guest() without seeing the new inhibit state. * * Note, holding apicv_update_lock and taking it in the read * side (handling the request) also prevents other vCPUs from @@ -11711,7 +11696,7 @@ static void __get_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) sregs->cr4 = kvm_read_cr4(vcpu); sregs->cr8 = kvm_get_cr8(vcpu); sregs->efer = vcpu->arch.efer; - sregs->apic_base = kvm_get_apic_base(vcpu); + sregs->apic_base = vcpu->arch.apic_base; } static void __get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) @@ -11888,16 +11873,13 @@ static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) static int __set_sregs_common(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs, int *mmu_reset_needed, bool update_pdptrs) { - struct msr_data apic_base_msr; int idx; struct desc_ptr dt; if (!kvm_is_valid_sregs(vcpu, sregs)) return -EINVAL; - apic_base_msr.data = sregs->apic_base; - apic_base_msr.host_initiated = true; - if (kvm_set_apic_base(vcpu, &apic_base_msr)) + if (kvm_apic_set_base(vcpu, sregs->apic_base, true)) return -EINVAL; if (vcpu->arch.guest_state_protected) @@ -12299,7 +12281,11 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) kvm_async_pf_hash_reset(vcpu); - vcpu->arch.perf_capabilities = kvm_caps.supported_perf_cap; + if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_STUFF_FEATURE_MSRS)) { + vcpu->arch.arch_capabilities = kvm_get_arch_capabilities(); + vcpu->arch.msr_platform_info = MSR_PLATFORM_INFO_CPUID_FAULT; + vcpu->arch.perf_capabilities = kvm_caps.supported_perf_cap; + } kvm_pmu_init(vcpu); vcpu->arch.pending_external_vector = -1; @@ -12313,8 +12299,6 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) if (r) goto free_guest_fpu; - vcpu->arch.arch_capabilities = kvm_get_arch_capabilities(); - vcpu->arch.msr_platform_info = MSR_PLATFORM_INFO_CPUID_FAULT; kvm_xen_init_vcpu(vcpu); vcpu_load(vcpu); kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz); @@ -12740,6 +12724,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm_hv_init_vm(kvm); kvm_xen_init_vm(kvm); + if (ignore_msrs && !report_ignored_msrs) { + pr_warn_once("Running KVM with ignore_msrs=1 and report_ignored_msrs=0 is not a\n" + "a supported configuration. Lying to the guest about the existence of MSRs\n" + "may cause the guest operating system to hang or produce errors. If a guest\n" + "does not run without ignore_msrs=1, please report it to kvm@vger.kernel.org.\n"); + } + return 0; out_uninit_mmu: @@ -13104,19 +13095,15 @@ static void kvm_mmu_slot_apply_flags(struct kvm *kvm, if (!log_dirty_pages) { /* - * Dirty logging tracks sptes in 4k granularity, meaning that - * large sptes have to be split. If live migration succeeds, - * the guest in the source machine will be destroyed and large - * sptes will be created in the destination. However, if the - * guest continues to run in the source machine (for example if - * live migration fails), small sptes will remain around and - * cause bad performance. + * Recover huge page mappings in the slot now that dirty logging + * is disabled, i.e. now that KVM does not have to track guest + * writes at 4KiB granularity. * - * Scan sptes if dirty logging has been stopped, dropping those - * which can be collapsed into a single large-page spte. Later - * page faults will create the large-page sptes. + * Dirty logging might be disabled by userspace if an ongoing VM + * live migration is cancelled and the VM must continue running + * on the source. */ - kvm_mmu_zap_collapsible_sptes(kvm, new); + kvm_mmu_recover_huge_pages(kvm, new); } else { /* * Initially-all-set does not require write protecting any page, @@ -13207,6 +13194,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) { + WARN_ON_ONCE(!kvm_arch_pmi_in_guest(vcpu)); + if (vcpu->arch.guest_state_protected) return true; @@ -13215,6 +13204,11 @@ bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) unsigned long kvm_arch_vcpu_get_ip(struct kvm_vcpu *vcpu) { + WARN_ON_ONCE(!kvm_arch_pmi_in_guest(vcpu)); + + if (vcpu->arch.guest_state_protected) + return 0; + return kvm_rip_read(vcpu); } @@ -13730,7 +13724,7 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva) * invalidation. */ if ((!pcid_enabled && (operand.pcid != 0)) || - is_noncanonical_address(operand.gla, vcpu)) { + is_noncanonical_invlpg_address(operand.gla, vcpu)) { kvm_inject_gp(vcpu, 0); return 1; } @@ -14010,6 +14004,8 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_rmp_fault); static int __init kvm_x86_init(void) { + kvm_init_xstate_sizes(); + kvm_mmu_x86_module_init(); mitigate_smt_rsb &= boot_cpu_has_bug(X86_BUG_SMT_RSB) && cpu_smt_possible(); return 0; diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index a84c48ef527853..ec623d23d13d2e 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -8,6 +8,7 @@ #include #include "kvm_cache_regs.h" #include "kvm_emulate.h" +#include "cpuid.h" struct kvm_caps { /* control of guest tsc rate supported? */ @@ -233,9 +234,52 @@ static inline u8 vcpu_virt_addr_bits(struct kvm_vcpu *vcpu) return kvm_is_cr4_bit_set(vcpu, X86_CR4_LA57) ? 57 : 48; } -static inline bool is_noncanonical_address(u64 la, struct kvm_vcpu *vcpu) +static inline u8 max_host_virt_addr_bits(void) { - return !__is_canonical_address(la, vcpu_virt_addr_bits(vcpu)); + return kvm_cpu_cap_has(X86_FEATURE_LA57) ? 57 : 48; +} + +/* + * x86 MSRs which contain linear addresses, x86 hidden segment bases, and + * IDT/GDT bases have static canonicality checks, the size of which depends + * only on the CPU's support for 5-level paging, rather than on the state of + * CR4.LA57. This applies to both WRMSR and to other instructions that set + * their values, e.g. SGDT. + * + * KVM passes through most of these MSRS and also doesn't intercept the + * instructions that set the hidden segment bases. + * + * Because of this, to be consistent with hardware, even if the guest doesn't + * have LA57 enabled in its CPUID, perform canonicality checks based on *host* + * support for 5 level paging. + * + * Finally, instructions which are related to MMU invalidation of a given + * linear address, also have a similar static canonical check on address. + * This allows for example to invalidate 5-level addresses of a guest from a + * host which uses 4-level paging. + */ +static inline bool is_noncanonical_address(u64 la, struct kvm_vcpu *vcpu, + unsigned int flags) +{ + if (flags & (X86EMUL_F_INVLPG | X86EMUL_F_MSR | X86EMUL_F_DT_LOAD)) + return !__is_canonical_address(la, max_host_virt_addr_bits()); + else + return !__is_canonical_address(la, vcpu_virt_addr_bits(vcpu)); +} + +static inline bool is_noncanonical_msr_address(u64 la, struct kvm_vcpu *vcpu) +{ + return is_noncanonical_address(la, vcpu, X86EMUL_F_MSR); +} + +static inline bool is_noncanonical_base_address(u64 la, struct kvm_vcpu *vcpu) +{ + return is_noncanonical_address(la, vcpu, X86EMUL_F_DT_LOAD); +} + +static inline bool is_noncanonical_invlpg_address(u64 la, struct kvm_vcpu *vcpu) +{ + return is_noncanonical_address(la, vcpu, X86EMUL_F_INVLPG); } static inline void vcpu_cache_mmio_info(struct kvm_vcpu *vcpu, diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 622fe24da91064..a909b817b9c0da 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -263,13 +263,6 @@ static void kvm_xen_stop_timer(struct kvm_vcpu *vcpu) atomic_set(&vcpu->arch.xen.timer_pending, 0); } -static void kvm_xen_init_timer(struct kvm_vcpu *vcpu) -{ - hrtimer_init(&vcpu->arch.xen.timer, CLOCK_MONOTONIC, - HRTIMER_MODE_ABS_HARD); - vcpu->arch.xen.timer.function = xen_timer_callback; -} - static void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, bool atomic) { struct kvm_vcpu_xen *vx = &v->arch.xen; @@ -1070,9 +1063,6 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) break; } - if (!vcpu->arch.xen.timer.function) - kvm_xen_init_timer(vcpu); - /* Stop the timer (if it's running) before changing the vector */ kvm_xen_stop_timer(vcpu); vcpu->arch.xen.timer_virq = data->u.timer.port; @@ -2235,6 +2225,8 @@ void kvm_xen_init_vcpu(struct kvm_vcpu *vcpu) vcpu->arch.xen.poll_evtchn = 0; timer_setup(&vcpu->arch.xen.poll_timer, cancel_evtchn_poll, 0); + hrtimer_init(&vcpu->arch.xen.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); + vcpu->arch.xen.timer.function = xen_timer_callback; kvm_gpc_init(&vcpu->arch.xen.runstate_cache, vcpu->kvm); kvm_gpc_init(&vcpu->arch.xen.runstate2_cache, vcpu->kvm); diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c index 807a5859a3c4b3..58f7f2bd535d59 100644 --- a/arch/x86/mm/hugetlbpage.c +++ b/arch/x86/mm/hugetlbpage.c @@ -19,107 +19,6 @@ #include #include -#ifdef CONFIG_HUGETLB_PAGE -static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct vm_unmapped_area_info info = {}; - - info.length = len; - info.low_limit = get_mmap_base(1); - - /* - * If hint address is above DEFAULT_MAP_WINDOW, look for unmapped area - * in the full address space. - */ - info.high_limit = in_32bit_syscall() ? - task_size_32bit() : task_size_64bit(addr > DEFAULT_MAP_WINDOW); - - info.align_mask = PAGE_MASK & ~huge_page_mask(h); - return vm_unmapped_area(&info); -} - -static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct vm_unmapped_area_info info = {}; - - info.flags = VM_UNMAPPED_AREA_TOPDOWN; - info.length = len; - info.low_limit = PAGE_SIZE; - info.high_limit = get_mmap_base(0); - - /* - * If hint address is above DEFAULT_MAP_WINDOW, look for unmapped area - * in the full address space. - */ - if (addr > DEFAULT_MAP_WINDOW && !in_32bit_syscall()) - info.high_limit += TASK_SIZE_MAX - DEFAULT_MAP_WINDOW; - - info.align_mask = PAGE_MASK & ~huge_page_mask(h); - addr = vm_unmapped_area(&info); - - /* - * 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. - */ - if (addr & ~PAGE_MASK) { - VM_BUG_ON(addr != -ENOMEM); - info.flags = 0; - info.low_limit = TASK_UNMAPPED_BASE; - info.high_limit = TASK_SIZE_LOW; - addr = vm_unmapped_area(&info); - } - - return addr; -} - -unsigned long -hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - - if (len & ~huge_page_mask(h)) - return -EINVAL; - - if (len > TASK_SIZE) - return -ENOMEM; - - /* No address checking. See comment at mmap_address_hint_valid() */ - if (flags & MAP_FIXED) { - if (prepare_hugepage_range(file, addr, len)) - return -EINVAL; - return addr; - } - - if (addr) { - addr &= huge_page_mask(h); - if (!mmap_address_hint_valid(addr, len)) - goto get_unmapped_area; - - vma = find_vma(mm, addr); - if (!vma || addr + len <= vm_start_gap(vma)) - return addr; - } - -get_unmapped_area: - if (!test_bit(MMF_TOPDOWN, &mm->flags)) - return hugetlb_get_unmapped_area_bottomup(file, addr, len, - pgoff, flags); - else - return hugetlb_get_unmapped_area_topdown(file, addr, len, - pgoff, flags); -} -#endif /* CONFIG_HUGETLB_PAGE */ #ifdef CONFIG_X86_64 bool __init arch_hugetlb_valid_size(unsigned long size) diff --git a/arch/x86/mm/ident_map.c b/arch/x86/mm/ident_map.c index 437e96fb497734..5ab7bd2f1983c1 100644 --- a/arch/x86/mm/ident_map.c +++ b/arch/x86/mm/ident_map.c @@ -174,7 +174,7 @@ static int ident_p4d_init(struct x86_mapping_info *info, p4d_t *p4d_page, if (result) return result; - set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag)); + set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag | _PAGE_NOPTISHADOW)); } return 0; @@ -218,14 +218,14 @@ int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page, if (result) return result; if (pgtable_l5_enabled()) { - set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag)); + set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag | _PAGE_NOPTISHADOW)); } else { /* * With p4d folded, pgd is equal to p4d. * The pgd entry has to point to the pud page table in this case. */ pud_t *pud = pud_offset(p4d, 0); - set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag)); + set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag | _PAGE_NOPTISHADOW)); } } diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index eb503f53c3195c..c6d29f283001ae 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -263,28 +263,33 @@ static void __init probe_page_size_mask(void) } /* - * INVLPG may not properly flush Global entries - * on these CPUs when PCIDs are enabled. + * INVLPG may not properly flush Global entries on + * these CPUs. New microcode fixes the issue. */ static const struct x86_cpu_id invlpg_miss_ids[] = { - X86_MATCH_VFM(INTEL_ALDERLAKE, 0), - X86_MATCH_VFM(INTEL_ALDERLAKE_L, 0), - X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, 0), - X86_MATCH_VFM(INTEL_RAPTORLAKE, 0), - X86_MATCH_VFM(INTEL_RAPTORLAKE_P, 0), - X86_MATCH_VFM(INTEL_RAPTORLAKE_S, 0), + X86_MATCH_VFM(INTEL_ALDERLAKE, 0x2e), + X86_MATCH_VFM(INTEL_ALDERLAKE_L, 0x42c), + X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, 0x11), + X86_MATCH_VFM(INTEL_RAPTORLAKE, 0x118), + X86_MATCH_VFM(INTEL_RAPTORLAKE_P, 0x4117), + X86_MATCH_VFM(INTEL_RAPTORLAKE_S, 0x2e), {} }; static void setup_pcid(void) { + const struct x86_cpu_id *invlpg_miss_match; + if (!IS_ENABLED(CONFIG_X86_64)) return; if (!boot_cpu_has(X86_FEATURE_PCID)) return; - if (x86_match_cpu(invlpg_miss_ids)) { + invlpg_miss_match = x86_match_cpu(invlpg_miss_ids); + + if (invlpg_miss_match && + boot_cpu_data.microcode < invlpg_miss_match->driver_data) { pr_info("Incomplete global flushes, disabling PCID"); setup_clear_cpu_cap(X86_FEATURE_PCID); return; @@ -1053,18 +1058,53 @@ unsigned long arch_max_swapfile_size(void) #ifdef CONFIG_EXECMEM static struct execmem_info execmem_info __ro_after_init; +#ifdef CONFIG_ARCH_HAS_EXECMEM_ROX +void execmem_fill_trapping_insns(void *ptr, size_t size, bool writeable) +{ + /* fill memory with INT3 instructions */ + if (writeable) + memset(ptr, INT3_INSN_OPCODE, size); + else + text_poke_set(ptr, INT3_INSN_OPCODE, size); +} +#endif + struct execmem_info __init *execmem_arch_setup(void) { unsigned long start, offset = 0; + enum execmem_range_flags flags; + pgprot_t pgprot; if (kaslr_enabled()) offset = get_random_u32_inclusive(1, 1024) * PAGE_SIZE; start = MODULES_VADDR + offset; + if (IS_ENABLED(CONFIG_ARCH_HAS_EXECMEM_ROX)) { + pgprot = PAGE_KERNEL_ROX; + flags = EXECMEM_KASAN_SHADOW | EXECMEM_ROX_CACHE; + } else { + pgprot = PAGE_KERNEL; + flags = EXECMEM_KASAN_SHADOW; + } + execmem_info = (struct execmem_info){ .ranges = { - [EXECMEM_DEFAULT] = { + [EXECMEM_MODULE_TEXT] = { + .flags = flags, + .start = start, + .end = MODULES_END, + .pgprot = pgprot, + .alignment = MODULE_ALIGN, + }, + [EXECMEM_KPROBES ... EXECMEM_BPF] = { + .flags = EXECMEM_KASAN_SHADOW, + .start = start, + .end = MODULES_END, + .pgprot = PAGE_KERNEL, + .alignment = MODULE_ALIGN, + }, + [EXECMEM_MODULE_DATA] = { .flags = EXECMEM_KASAN_SHADOW, .start = start, .end = MODULES_END, diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index ff253648706fa9..01ea7c6df3036b 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -961,7 +961,7 @@ int add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages, unsigned long end = ((start_pfn + nr_pages) << PAGE_SHIFT) - 1; int ret; - if (WARN_ON_ONCE(end > PHYSMEM_END)) + if (WARN_ON_ONCE(end > DIRECT_MAP_PHYSMEM_END)) return -ERANGE; ret = __add_pages(nid, start_pfn, nr_pages, params); @@ -985,22 +985,32 @@ int arch_add_memory(int nid, u64 start, u64 size, return add_pages(nid, start_pfn, nr_pages, params); } -static void __meminit free_pagetable(struct page *page, int order) +static void free_reserved_pages(struct page *page, unsigned long nr_pages) { - unsigned long magic; - unsigned int nr_pages = 1 << order; + while (nr_pages--) + free_reserved_page(page++); +} +static void __meminit free_pagetable(struct page *page, int order) +{ /* bootmem page has reserved flag */ if (PageReserved(page)) { - magic = page->index; - if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) { + unsigned long nr_pages = 1 << order; +#ifdef CONFIG_HAVE_BOOTMEM_INFO_NODE + enum bootmem_type type = bootmem_type(page); + + if (type == SECTION_INFO || type == MIX_SECTION_INFO) { while (nr_pages--) put_page_bootmem(page++); - } else - while (nr_pages--) - free_reserved_page(page++); - } else + } else { + free_reserved_pages(page, nr_pages); + } +#else + free_reserved_pages(page, nr_pages); +#endif + } else { free_pages((unsigned long)page_address(page), order); + } } static void __meminit free_hugepage_table(struct page *page, diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index 230f1dee4f0954..11a93542d1983a 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -52,7 +52,7 @@ static __initdata struct kaslr_memory_region { } kaslr_regions[] = { { .base = &page_offset_base, - .end = &physmem_end, + .end = &direct_map_physmem_end, }, { .base = &vmalloc_base, @@ -62,8 +62,12 @@ static __initdata struct kaslr_memory_region { }, }; -/* The end of the possible address space for physical memory */ -unsigned long physmem_end __ro_after_init; +/* + * The end of the physical address space that can be mapped directly by the + * kernel. This starts out at (1< __START_KERNEL_map); /* Preset the end of the possible address space for physical memory */ - physmem_end = ((1ULL << MAX_PHYSMEM_BITS) - 1); + direct_map_physmem_end = ((1ULL << MAX_PHYSMEM_BITS) - 1); if (!kaslr_memory_enabled()) return; @@ -145,7 +149,7 @@ void __init kernel_randomize_memory(void) vaddr += get_padding(&kaslr_regions[i]); /* * KASLR trims the maximum possible size of the - * direct-map. Update the physmem_end boundary. + * direct-map. Update the direct_map_physmem_end boundary. * No rounding required as the region starts * PUD aligned and size is in units of TB. */ diff --git a/arch/x86/mm/mem_encrypt_amd.c b/arch/x86/mm/mem_encrypt_amd.c index 86a476a426c26d..774f9677458f27 100644 --- a/arch/x86/mm/mem_encrypt_amd.c +++ b/arch/x86/mm/mem_encrypt_amd.c @@ -311,59 +311,82 @@ static int amd_enc_status_change_finish(unsigned long vaddr, int npages, bool en return 0; } -static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc) +int prepare_pte_enc(struct pte_enc_desc *d) { - pgprot_t old_prot, new_prot; - unsigned long pfn, pa, size; - pte_t new_pte; + pgprot_t old_prot; - pfn = pg_level_to_pfn(level, kpte, &old_prot); - if (!pfn) - return; + d->pfn = pg_level_to_pfn(d->pte_level, d->kpte, &old_prot); + if (!d->pfn) + return 1; - new_prot = old_prot; - if (enc) - pgprot_val(new_prot) |= _PAGE_ENC; + d->new_pgprot = old_prot; + if (d->encrypt) + pgprot_val(d->new_pgprot) |= _PAGE_ENC; else - pgprot_val(new_prot) &= ~_PAGE_ENC; + pgprot_val(d->new_pgprot) &= ~_PAGE_ENC; /* If prot is same then do nothing. */ - if (pgprot_val(old_prot) == pgprot_val(new_prot)) - return; + if (pgprot_val(old_prot) == pgprot_val(d->new_pgprot)) + return 1; - pa = pfn << PAGE_SHIFT; - size = page_level_size(level); + d->pa = d->pfn << PAGE_SHIFT; + d->size = page_level_size(d->pte_level); /* - * We are going to perform in-place en-/decryption and change the - * physical page attribute from C=1 to C=0 or vice versa. Flush the - * caches to ensure that data gets accessed with the correct C-bit. + * In-place en-/decryption and physical page attribute change + * from C=1 to C=0 or vice versa will be performed. Flush the + * caches to ensure that data gets accessed with the correct + * C-bit. */ - clflush_cache_range(__va(pa), size); + if (d->va) + clflush_cache_range(d->va, d->size); + else + clflush_cache_range(__va(d->pa), d->size); + + return 0; +} + +void set_pte_enc_mask(pte_t *kpte, unsigned long pfn, pgprot_t new_prot) +{ + pte_t new_pte; + + /* Change the page encryption mask. */ + new_pte = pfn_pte(pfn, new_prot); + set_pte_atomic(kpte, new_pte); +} + +static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc) +{ + struct pte_enc_desc d = { + .kpte = kpte, + .pte_level = level, + .encrypt = enc + }; + + if (prepare_pte_enc(&d)) + return; /* Encrypt/decrypt the contents in-place */ if (enc) { - sme_early_encrypt(pa, size); + sme_early_encrypt(d.pa, d.size); } else { - sme_early_decrypt(pa, size); + sme_early_decrypt(d.pa, d.size); /* * ON SNP, the page state in the RMP table must happen * before the page table updates. */ - early_snp_set_memory_shared((unsigned long)__va(pa), pa, 1); + early_snp_set_memory_shared((unsigned long)__va(d.pa), d.pa, 1); } - /* Change the page encryption mask. */ - new_pte = pfn_pte(pfn, new_prot); - set_pte_atomic(kpte, new_pte); + set_pte_enc_mask(kpte, d.pfn, d.new_pgprot); /* * If page is set encrypted in the page table, then update the RMP table to * add this page as private. */ if (enc) - early_snp_set_memory_private((unsigned long)__va(pa), pa, 1); + early_snp_set_memory_private((unsigned long)__va(d.pa), d.pa, 1); } static int __init early_set_memory_enc_dec(unsigned long vaddr, @@ -467,6 +490,8 @@ void __init sme_early_init(void) x86_platform.guest.enc_status_change_finish = amd_enc_status_change_finish; x86_platform.guest.enc_tlb_flush_required = amd_enc_tlb_flush_required; x86_platform.guest.enc_cache_flush_required = amd_enc_cache_flush_required; + x86_platform.guest.enc_kexec_begin = snp_kexec_begin; + x86_platform.guest.enc_kexec_finish = snp_kexec_finish; /* * AMD-SEV-ES intercepts the RDMSR to read the X2APIC ID in the diff --git a/arch/x86/mm/mem_encrypt_identity.c b/arch/x86/mm/mem_encrypt_identity.c index ac33b2263a434d..e6c7686f443a06 100644 --- a/arch/x86/mm/mem_encrypt_identity.c +++ b/arch/x86/mm/mem_encrypt_identity.c @@ -495,10 +495,10 @@ void __head sme_enable(struct boot_params *bp) unsigned int eax, ebx, ecx, edx; unsigned long feature_mask; unsigned long me_mask; - bool snp; + bool snp_en; u64 msr; - snp = snp_init(bp); + snp_en = snp_init(bp); /* Check for the SME/SEV support leaf */ eax = 0x80000000; @@ -531,8 +531,11 @@ void __head sme_enable(struct boot_params *bp) RIP_REL_REF(sev_status) = msr = __rdmsr(MSR_AMD64_SEV); feature_mask = (msr & MSR_AMD64_SEV_ENABLED) ? AMD_SEV_BIT : AMD_SME_BIT; - /* The SEV-SNP CC blob should never be present unless SEV-SNP is enabled. */ - if (snp && !(msr & MSR_AMD64_SEV_SNP_ENABLED)) + /* + * Any discrepancies between the presence of a CC blob and SNP + * enablement abort the guest. + */ + if (snp_en ^ !!(msr & MSR_AMD64_SEV_SNP_ENABLED)) snp_abort(); /* Check if memory encryption is enabled */ diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index a2cabb1c81e1ae..b8a6ffffb4519c 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -163,11 +163,6 @@ unsigned long get_mmap_base(int is_legacy) return is_legacy ? mm->mmap_legacy_base : mm->mmap_base; } -const char *arch_vma_name(struct vm_area_struct *vma) -{ - return NULL; -} - /** * mmap_address_hint_valid - Validate the address hint of mmap * @addr: Address hint diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 44f7b2ea6a073f..95bc50a8541c6a 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -354,7 +354,7 @@ bool cpu_cache_has_invalidate_memregion(void) { return !cpu_feature_enabled(X86_FEATURE_HYPERVISOR); } -EXPORT_SYMBOL_NS_GPL(cpu_cache_has_invalidate_memregion, DEVMEM); +EXPORT_SYMBOL_NS_GPL(cpu_cache_has_invalidate_memregion, "DEVMEM"); int cpu_cache_invalidate_memregion(int res_desc) { @@ -363,7 +363,7 @@ int cpu_cache_invalidate_memregion(int res_desc) wbinvd_on_all_cpus(); return 0; } -EXPORT_SYMBOL_NS_GPL(cpu_cache_invalidate_memregion, DEVMEM); +EXPORT_SYMBOL_NS_GPL(cpu_cache_invalidate_memregion, "DEVMEM"); #endif static void __cpa_flush_all(void *arg) @@ -2444,6 +2444,14 @@ int set_direct_map_default_noflush(struct page *page) return __set_pages_p(page, 1); } +int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid) +{ + if (valid) + return __set_pages_p(page, nr); + + return __set_pages_np(page, nr); +} + #ifdef CONFIG_DEBUG_PAGEALLOC void __kernel_map_pages(struct page *page, int numpages, int enable) { diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index 851ec8f1363a8b..5f0d579932c688 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c @@ -132,7 +132,7 @@ pgd_t __pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd) * Top-level entries added to init_mm's usermode pgd after boot * will not be automatically propagated to other mms. */ - if (!pgdp_maps_userspace(pgdp)) + if (!pgdp_maps_userspace(pgdp) || (pgd.pgd & _PAGE_NOPTISHADOW)) return pgd; /* diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 86593d1b787d8a..a2becb85bea796 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "mm_internal.h" @@ -568,7 +569,7 @@ void switch_mm_irqs_off(struct mm_struct *unused, struct mm_struct *next, * mm_cpumask. The TLB shootdown code can figure out from * cpu_tlbstate_shared.is_lazy whether or not to send an IPI. */ - if (WARN_ON_ONCE(prev != &init_mm && + if (IS_ENABLED(CONFIG_DEBUG_VM) && WARN_ON_ONCE(prev != &init_mm && !cpumask_test_cpu(cpu, mm_cpumask(next)))) cpumask_set_cpu(cpu, mm_cpumask(next)); @@ -1140,7 +1141,7 @@ STATIC_NOPV void native_flush_tlb_one_user(unsigned long addr) bool cpu_pcide; /* Flush 'addr' from the kernel PCID: */ - asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); + invlpg(addr); /* If PTI is off there is no user PCID and nothing to flush. */ if (!static_cpu_has(X86_FEATURE_PTI)) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 06b080b61aa578..a43fc5af973d27 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -325,6 +325,22 @@ struct jit_context { /* Number of bytes that will be skipped on tailcall */ #define X86_TAIL_CALL_OFFSET (12 + ENDBR_INSN_SIZE) +static void push_r9(u8 **pprog) +{ + u8 *prog = *pprog; + + EMIT2(0x41, 0x51); /* push r9 */ + *pprog = prog; +} + +static void pop_r9(u8 **pprog) +{ + u8 *prog = *pprog; + + EMIT2(0x41, 0x59); /* pop r9 */ + *pprog = prog; +} + static void push_r12(u8 **pprog) { u8 *prog = *pprog; @@ -1404,6 +1420,24 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op) *pprog = prog; } +static void emit_priv_frame_ptr(u8 **pprog, void __percpu *priv_frame_ptr) +{ + u8 *prog = *pprog; + + /* movabs r9, priv_frame_ptr */ + emit_mov_imm64(&prog, X86_REG_R9, (__force long) priv_frame_ptr >> 32, + (u32) (__force long) priv_frame_ptr); + +#ifdef CONFIG_SMP + /* add , gs:[] */ + EMIT2(0x65, 0x4c); + EMIT3(0x03, 0x0c, 0x25); + EMIT((u32)(unsigned long)&this_cpu_off, 4); +#endif + + *pprog = prog; +} + #define INSN_SZ_DIFF (((addrs[i] - addrs[i - 1]) - (prog - temp))) #define __LOAD_TCC_PTR(off) \ @@ -1412,6 +1446,10 @@ static void emit_shiftx(u8 **pprog, u32 dst_reg, u8 src_reg, bool is64, u8 op) #define LOAD_TAIL_CALL_CNT_PTR(stack) \ __LOAD_TCC_PTR(BPF_TAIL_CALL_CNT_PTR_STACK_OFF(stack)) +/* Memory size/value to protect private stack overflow/underflow */ +#define PRIV_STACK_GUARD_SZ 8 +#define PRIV_STACK_GUARD_VAL 0xEB9F12345678eb9fULL + static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image, int oldproglen, struct jit_context *ctx, bool jmp_padding) { @@ -1421,18 +1459,28 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image int insn_cnt = bpf_prog->len; bool seen_exit = false; u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY]; + void __percpu *priv_frame_ptr = NULL; u64 arena_vm_start, user_vm_start; + void __percpu *priv_stack_ptr; int i, excnt = 0; int ilen, proglen = 0; u8 *prog = temp; + u32 stack_depth; int err; + stack_depth = bpf_prog->aux->stack_depth; + priv_stack_ptr = bpf_prog->aux->priv_stack_ptr; + if (priv_stack_ptr) { + priv_frame_ptr = priv_stack_ptr + PRIV_STACK_GUARD_SZ + round_up(stack_depth, 8); + stack_depth = 0; + } + arena_vm_start = bpf_arena_get_kern_vm_start(bpf_prog->aux->arena); user_vm_start = bpf_arena_get_user_vm_start(bpf_prog->aux->arena); detect_reg_usage(insn, insn_cnt, callee_regs_used); - emit_prologue(&prog, bpf_prog->aux->stack_depth, + emit_prologue(&prog, stack_depth, bpf_prog_was_classic(bpf_prog), tail_call_reachable, bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb); /* Exception callback will clobber callee regs for its own use, and @@ -1454,6 +1502,9 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image emit_mov_imm64(&prog, X86_REG_R12, arena_vm_start >> 32, (u32) arena_vm_start); + if (priv_frame_ptr) + emit_priv_frame_ptr(&prog, priv_frame_ptr); + ilen = prog - temp; if (rw_image) memcpy(rw_image + proglen, temp, ilen); @@ -1473,6 +1524,14 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image u8 *func; int nops; + if (priv_frame_ptr) { + if (src_reg == BPF_REG_FP) + src_reg = X86_REG_R9; + + if (dst_reg == BPF_REG_FP) + dst_reg = X86_REG_R9; + } + switch (insn->code) { /* ALU */ case BPF_ALU | BPF_ADD | BPF_X: @@ -2127,15 +2186,21 @@ st: if (is_imm8(insn->off)) u8 *ip = image + addrs[i - 1]; func = (u8 *) __bpf_call_base + imm32; - if (tail_call_reachable) { - LOAD_TAIL_CALL_CNT_PTR(bpf_prog->aux->stack_depth); + if (src_reg == BPF_PSEUDO_CALL && tail_call_reachable) { + LOAD_TAIL_CALL_CNT_PTR(stack_depth); ip += 7; } if (!imm32) return -EINVAL; + if (priv_frame_ptr) { + push_r9(&prog); + ip += 2; + } ip += x86_call_depth_emit_accounting(&prog, func, ip); if (emit_call(&prog, func, ip)) return -EINVAL; + if (priv_frame_ptr) + pop_r9(&prog); break; } @@ -2145,13 +2210,13 @@ st: if (is_imm8(insn->off)) &bpf_prog->aux->poke_tab[imm32 - 1], &prog, image + addrs[i - 1], callee_regs_used, - bpf_prog->aux->stack_depth, + stack_depth, ctx); else emit_bpf_tail_call_indirect(bpf_prog, &prog, callee_regs_used, - bpf_prog->aux->stack_depth, + stack_depth, image + addrs[i - 1], ctx); break; @@ -3303,6 +3368,42 @@ int arch_prepare_bpf_dispatcher(void *image, void *buf, s64 *funcs, int num_func return emit_bpf_dispatcher(&prog, 0, num_funcs - 1, funcs, image, buf); } +static const char *bpf_get_prog_name(struct bpf_prog *prog) +{ + if (prog->aux->ksym.prog) + return prog->aux->ksym.name; + return prog->aux->name; +} + +static void priv_stack_init_guard(void __percpu *priv_stack_ptr, int alloc_size) +{ + int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3; + u64 *stack_ptr; + + for_each_possible_cpu(cpu) { + stack_ptr = per_cpu_ptr(priv_stack_ptr, cpu); + stack_ptr[0] = PRIV_STACK_GUARD_VAL; + stack_ptr[underflow_idx] = PRIV_STACK_GUARD_VAL; + } +} + +static void priv_stack_check_guard(void __percpu *priv_stack_ptr, int alloc_size, + struct bpf_prog *prog) +{ + int cpu, underflow_idx = (alloc_size - PRIV_STACK_GUARD_SZ) >> 3; + u64 *stack_ptr; + + for_each_possible_cpu(cpu) { + stack_ptr = per_cpu_ptr(priv_stack_ptr, cpu); + if (stack_ptr[0] != PRIV_STACK_GUARD_VAL || + stack_ptr[underflow_idx] != PRIV_STACK_GUARD_VAL) { + pr_err("BPF private stack overflow/underflow detected for prog %sx\n", + bpf_get_prog_name(prog)); + break; + } + } +} + struct x64_jit_data { struct bpf_binary_header *rw_header; struct bpf_binary_header *header; @@ -3320,7 +3421,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) struct bpf_binary_header *rw_header = NULL; struct bpf_binary_header *header = NULL; struct bpf_prog *tmp, *orig_prog = prog; + void __percpu *priv_stack_ptr = NULL; struct x64_jit_data *jit_data; + int priv_stack_alloc_sz; int proglen, oldproglen = 0; struct jit_context ctx = {}; bool tmp_blinded = false; @@ -3356,6 +3459,23 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) } prog->aux->jit_data = jit_data; } + priv_stack_ptr = prog->aux->priv_stack_ptr; + if (!priv_stack_ptr && prog->aux->jits_use_priv_stack) { + /* Allocate actual private stack size with verifier-calculated + * stack size plus two memory guards to protect overflow and + * underflow. + */ + priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 8) + + 2 * PRIV_STACK_GUARD_SZ; + priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 8, GFP_KERNEL); + if (!priv_stack_ptr) { + prog = orig_prog; + goto out_priv_stack; + } + + priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz); + prog->aux->priv_stack_ptr = priv_stack_ptr; + } addrs = jit_data->addrs; if (addrs) { ctx = jit_data->ctx; @@ -3491,6 +3611,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) bpf_prog_fill_jited_linfo(prog, addrs + 1); out_addrs: kvfree(addrs); + if (!image && priv_stack_ptr) { + free_percpu(priv_stack_ptr); + prog->aux->priv_stack_ptr = NULL; + } +out_priv_stack: kfree(jit_data); prog->aux->jit_data = NULL; } @@ -3529,6 +3654,8 @@ void bpf_jit_free(struct bpf_prog *prog) if (prog->jited) { struct x64_jit_data *jit_data = prog->aux->jit_data; struct bpf_binary_header *hdr; + void __percpu *priv_stack_ptr; + int priv_stack_alloc_sz; /* * If we fail the final pass of JIT (from jit_subprogs), @@ -3544,6 +3671,13 @@ void bpf_jit_free(struct bpf_prog *prog) prog->bpf_func = (void *)prog->bpf_func - cfi_get_offset(); hdr = bpf_jit_binary_pack_hdr(prog); bpf_jit_binary_pack_free(hdr, NULL); + priv_stack_ptr = prog->aux->priv_stack_ptr; + if (priv_stack_ptr) { + priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 8) + + 2 * PRIV_STACK_GUARD_SZ; + priv_stack_check_guard(priv_stack_ptr, priv_stack_alloc_sz, prog); + free_percpu(prog->aux->priv_stack_ptr); + } WARN_ON_ONCE(!bpf_prog_kallsyms_verify_off(prog)); } @@ -3559,6 +3693,11 @@ bool bpf_jit_supports_exceptions(void) return IS_ENABLED(CONFIG_UNWINDER_ORC); } +bool bpf_jit_supports_private_stack(void) +{ + return true; +} + void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie) { #if defined(CONFIG_UNWINDER_ORC) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 55c4b07ec1f631..0c316bae1726ee 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -250,6 +250,125 @@ void __init pci_acpi_crs_quirks(void) pr_info("Please notify linux-pci@vger.kernel.org so future kernels can do this automatically\n"); } +/* + * Check if pdev is part of a PCIe switch that is directly below the + * specified bridge. + */ +static bool pcie_switch_directly_under(struct pci_dev *bridge, + struct pci_dev *pdev) +{ + struct pci_dev *parent = pci_upstream_bridge(pdev); + + /* If the device doesn't have a parent, it's not under anything */ + if (!parent) + return false; + + /* + * If the device has a PCIe type, check if it is below the + * corresponding PCIe switch components (if applicable). Then check + * if its upstream port is directly beneath the specified bridge. + */ + switch (pci_pcie_type(pdev)) { + case PCI_EXP_TYPE_UPSTREAM: + return parent == bridge; + + case PCI_EXP_TYPE_DOWNSTREAM: + if (pci_pcie_type(parent) != PCI_EXP_TYPE_UPSTREAM) + return false; + parent = pci_upstream_bridge(parent); + return parent == bridge; + + case PCI_EXP_TYPE_ENDPOINT: + if (pci_pcie_type(parent) != PCI_EXP_TYPE_DOWNSTREAM) + return false; + parent = pci_upstream_bridge(parent); + if (!parent || pci_pcie_type(parent) != PCI_EXP_TYPE_UPSTREAM) + return false; + parent = pci_upstream_bridge(parent); + return parent == bridge; + } + + return false; +} + +static bool pcie_has_usb4_host_interface(struct pci_dev *pdev) +{ + struct fwnode_handle *fwnode; + + /* + * For USB4, the tunneled PCIe Root or Downstream Ports are marked + * with the "usb4-host-interface" ACPI property, so we look for + * that first. This should cover most cases. + */ + fwnode = fwnode_find_reference(dev_fwnode(&pdev->dev), + "usb4-host-interface", 0); + if (!IS_ERR(fwnode)) { + fwnode_handle_put(fwnode); + return true; + } + + /* + * Any integrated Thunderbolt 3/4 PCIe Root Ports from Intel + * before Alder Lake do not have the "usb4-host-interface" + * property so we use their PCI IDs instead. All these are + * tunneled. This list is not expected to grow. + */ + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { + switch (pdev->device) { + /* Ice Lake Thunderbolt 3 PCIe Root Ports */ + case 0x8a1d: + case 0x8a1f: + case 0x8a21: + case 0x8a23: + /* Tiger Lake-LP Thunderbolt 4 PCIe Root Ports */ + case 0x9a23: + case 0x9a25: + case 0x9a27: + case 0x9a29: + /* Tiger Lake-H Thunderbolt 4 PCIe Root Ports */ + case 0x9a2b: + case 0x9a2d: + case 0x9a2f: + case 0x9a31: + return true; + } + } + + return false; +} + +bool arch_pci_dev_is_removable(struct pci_dev *pdev) +{ + struct pci_dev *parent, *root; + + /* pdev without a parent or Root Port is never tunneled */ + parent = pci_upstream_bridge(pdev); + if (!parent) + return false; + root = pcie_find_root_port(pdev); + if (!root) + return false; + + /* Internal PCIe devices are not tunneled */ + if (!root->external_facing) + return false; + + /* Anything directly behind a "usb4-host-interface" is tunneled */ + if (pcie_has_usb4_host_interface(parent)) + return true; + + /* + * Check if this is a discrete Thunderbolt/USB4 controller that is + * directly behind the non-USB4 PCIe Root Port marked as + * "ExternalFacingPort". Those are not behind a PCIe tunnel. + */ + if (pcie_switch_directly_under(root, pdev)) + return false; + + /* PCIe devices after the discrete chip are tunneled */ + return true; +} + #ifdef CONFIG_PCI_MMCONFIG static int check_segment(u16 seg, struct device *dev, char *estr) { diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 98a9bb92d75c88..0681ecfe34300e 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -757,7 +757,7 @@ static void pci_amd_enable_64bit_bar(struct pci_dev *dev) dev_info(&dev->dev, "adding root bus resource %pR (tainting kernel)\n", res); add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); - pci_bus_add_resource(dev->bus, res, 0); + pci_bus_add_resource(dev->bus, res); } base = ((res->start >> 8) & AMD_141b_MMIO_BASE_MMIOBASE_MASK) | diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 88a96816de9a9b..a7ff189421c3d8 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -54,14 +54,12 @@ #include static unsigned long efi_systab_phys __initdata; -static unsigned long prop_phys = EFI_INVALID_TABLE_ADDR; static unsigned long uga_phys = EFI_INVALID_TABLE_ADDR; static unsigned long efi_runtime, efi_nr_tables; unsigned long efi_fw_vendor, efi_config_table; static const efi_config_table_type_t arch_tables[] __initconst = { - {EFI_PROPERTIES_TABLE_GUID, &prop_phys, "PROP" }, {UGA_IO_PROTOCOL_GUID, &uga_phys, "UGA" }, #ifdef CONFIG_X86_UV {UV_SYSTEM_TABLE_GUID, &uv_systab_phys, "UVsystab" }, @@ -82,7 +80,6 @@ static const unsigned long * const efi_tables[] = { &efi_runtime, &efi_config_table, &efi.esrt, - &prop_phys, &efi_mem_attr_table, #ifdef CONFIG_EFI_RCI2_TABLE &rci2_table_phys, @@ -502,22 +499,6 @@ void __init efi_init(void) return; } - /* Parse the EFI Properties table if it exists */ - if (prop_phys != EFI_INVALID_TABLE_ADDR) { - efi_properties_table_t *tbl; - - tbl = early_memremap_ro(prop_phys, sizeof(*tbl)); - if (tbl == NULL) { - pr_err("Could not map Properties table!\n"); - } else { - if (tbl->memory_protection_attribute & - EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA) - set_bit(EFI_NX_PE_DATA, &efi.flags); - - early_memunmap(tbl, sizeof(*tbl)); - } - } - set_bit(EFI_RUNTIME_SERVICES, &efi.flags); efi_clean_memmap(); @@ -784,6 +765,7 @@ static void __init kexec_enter_virtual_mode(void) efi_sync_low_kernel_mappings(); efi_native_runtime_setup(); + efi_runtime_update_mappings(); #endif } diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 91d31ac422d6cd..ac57259a432b8c 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -412,51 +412,9 @@ static int __init efi_update_mem_attr(struct mm_struct *mm, efi_memory_desc_t *m void __init efi_runtime_update_mappings(void) { - efi_memory_desc_t *md; - - /* - * Use the EFI Memory Attribute Table for mapping permissions if it - * exists, since it is intended to supersede EFI_PROPERTIES_TABLE. - */ if (efi_enabled(EFI_MEM_ATTR)) { efi_disable_ibt_for_runtime = false; efi_memattr_apply_permissions(NULL, efi_update_mem_attr); - return; - } - - /* - * EFI_MEMORY_ATTRIBUTES_TABLE is intended to replace - * EFI_PROPERTIES_TABLE. So, use EFI_PROPERTIES_TABLE to update - * permissions only if EFI_MEMORY_ATTRIBUTES_TABLE is not - * published by the firmware. Even if we find a buggy implementation of - * EFI_MEMORY_ATTRIBUTES_TABLE, don't fall back to - * EFI_PROPERTIES_TABLE, because of the same reason. - */ - - if (!efi_enabled(EFI_NX_PE_DATA)) - return; - - for_each_efi_memory_desc(md) { - unsigned long pf = 0; - - if (!(md->attribute & EFI_MEMORY_RUNTIME)) - continue; - - if (!(md->attribute & EFI_MEMORY_WB)) - pf |= _PAGE_PCD; - - if ((md->attribute & EFI_MEMORY_XP) || - (md->type == EFI_RUNTIME_SERVICES_DATA)) - pf |= _PAGE_NX; - - if (!(md->attribute & EFI_MEMORY_RO) && - (md->type != EFI_RUNTIME_SERVICES_CODE)) - pf |= _PAGE_RW; - - if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) - pf |= _PAGE_ENC; - - efi_update_mappings(md, pf); } } diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index f0cc00032751d0..846bf49f2508da 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -656,8 +656,7 @@ static int qrk_capsule_setup_info(struct capsule_info *cap_info, void **pkbuff, } static const struct x86_cpu_id efi_capsule_quirk_ids[] = { - X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, - &qrk_capsule_setup_info), + X86_MATCH_VFM(INTEL_QUARK_X1000, &qrk_capsule_setup_info), { } }; diff --git a/arch/x86/platform/intel-mid/pwr.c b/arch/x86/platform/intel-mid/pwr.c index 27288d8d3f719b..cd7e0c71addef6 100644 --- a/arch/x86/platform/intel-mid/pwr.c +++ b/arch/x86/platform/intel-mid/pwr.c @@ -358,18 +358,18 @@ static int mid_pwr_probe(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } - ret = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); - if (ret) { - dev_err(&pdev->dev, "I/O memory remapping failed\n"); - return ret; - } - pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); if (!pwr) return -ENOMEM; + pwr->regs = pcim_iomap_region(pdev, 0, "intel_mid_pwr"); + ret = PTR_ERR_OR_ZERO(pwr->regs); + if (ret) { + dev_err(&pdev->dev, "Could not request / ioremap I/O-Mem: %d\n", ret); + return ret; + } + pwr->dev = dev; - pwr->regs = pcim_iomap_table(pdev)[0]; pwr->irq = pdev->irq; mutex_init(&pwr->lock); diff --git a/arch/x86/platform/intel-quark/imr.c b/arch/x86/platform/intel-quark/imr.c index d3d456925b2a93..ee25b032c0b3ab 100644 --- a/arch/x86/platform/intel-quark/imr.c +++ b/arch/x86/platform/intel-quark/imr.c @@ -569,7 +569,7 @@ static void __init imr_fixup_memmap(struct imr_device *idev) } static const struct x86_cpu_id imr_ids[] __initconst = { - X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL), + X86_MATCH_VFM(INTEL_QUARK_X1000, NULL), {} }; diff --git a/arch/x86/platform/intel-quark/imr_selftest.c b/arch/x86/platform/intel-quark/imr_selftest.c index 84ba715f44d128..657925b0f428dc 100644 --- a/arch/x86/platform/intel-quark/imr_selftest.c +++ b/arch/x86/platform/intel-quark/imr_selftest.c @@ -105,7 +105,7 @@ static void __init imr_self_test(void) } static const struct x86_cpu_id imr_ids[] __initconst = { - X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL), + X86_MATCH_VFM(INTEL_QUARK_X1000, NULL), {} }; diff --git a/arch/x86/platform/iris/iris.c b/arch/x86/platform/iris/iris.c index c5f3bbdbdcfef6..5591a2d9cfe8a2 100644 --- a/arch/x86/platform/iris/iris.c +++ b/arch/x86/platform/iris/iris.c @@ -73,7 +73,7 @@ static struct platform_driver iris_driver = { .name = "iris", }, .probe = iris_probe, - .remove_new = iris_remove, + .remove = iris_remove, }; static struct resource iris_resources[] = { diff --git a/arch/x86/platform/olpc/olpc-xo1-pm.c b/arch/x86/platform/olpc/olpc-xo1-pm.c index 6a9c42de74e74f..424eeae127591a 100644 --- a/arch/x86/platform/olpc/olpc-xo1-pm.c +++ b/arch/x86/platform/olpc/olpc-xo1-pm.c @@ -159,7 +159,7 @@ static struct platform_driver cs5535_pms_driver = { .name = "cs5535-pms", }, .probe = xo1_pm_probe, - .remove_new = xo1_pm_remove, + .remove = xo1_pm_remove, }; static struct platform_driver cs5535_acpi_driver = { @@ -167,7 +167,7 @@ static struct platform_driver cs5535_acpi_driver = { .name = "olpc-xo1-pm-acpi", }, .probe = xo1_pm_probe, - .remove_new = xo1_pm_remove, + .remove = xo1_pm_remove, }; static int __init xo1_pm_init(void) diff --git a/arch/x86/platform/olpc/olpc-xo1-sci.c b/arch/x86/platform/olpc/olpc-xo1-sci.c index 46d42ff6e18ab5..ccb23c73cbe8b2 100644 --- a/arch/x86/platform/olpc/olpc-xo1-sci.c +++ b/arch/x86/platform/olpc/olpc-xo1-sci.c @@ -616,7 +616,7 @@ static struct platform_driver xo1_sci_driver = { .dev_groups = lid_groups, }, .probe = xo1_sci_probe, - .remove_new = xo1_sci_remove, + .remove = xo1_sci_remove, .suspend = xo1_sci_suspend, .resume = xo1_sci_resume, }; diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S index 64fca49cd88ff9..4733a5f467b812 100644 --- a/arch/x86/platform/pvh/head.S +++ b/arch/x86/platform/pvh/head.S @@ -6,7 +6,9 @@ .code32 .text +#ifdef CONFIG_X86_32 #define _pa(x) ((x) - __START_KERNEL_map) +#endif #define rva(x) ((x) - pvh_start_xen) #include @@ -52,7 +54,7 @@ #define PVH_CS_SEL (PVH_GDT_ENTRY_CS * 8) #define PVH_DS_SEL (PVH_GDT_ENTRY_DS * 8) -SYM_CODE_START_LOCAL(pvh_start_xen) +SYM_CODE_START(pvh_start_xen) UNWIND_HINT_END_OF_STACK cld @@ -72,8 +74,7 @@ SYM_CODE_START_LOCAL(pvh_start_xen) movl $0, %esp leal rva(gdt)(%ebp), %eax - leal rva(gdt_start)(%ebp), %ecx - movl %ecx, 2(%eax) + addl %eax, 2(%eax) lgdt (%eax) mov $PVH_DS_SEL,%eax @@ -103,10 +104,23 @@ SYM_CODE_START_LOCAL(pvh_start_xen) btsl $_EFER_LME, %eax wrmsr + /* + * Reuse the non-relocatable symbol emitted for the ELF note to + * subtract the build time physical address of pvh_start_xen() from + * its actual runtime address, without relying on absolute 32-bit ELF + * relocations, as these are not supported by the linker when running + * in -pie mode, and should be avoided in .head.text in general. + */ mov %ebp, %ebx - subl $_pa(pvh_start_xen), %ebx /* offset */ + subl rva(xen_elfnote_phys32_entry)(%ebp), %ebx jz .Lpagetable_done + /* + * Store the resulting load offset in phys_base. __pa() needs + * phys_base set to calculate the hypercall page in xen_pvh_init(). + */ + movl %ebx, rva(phys_base)(%ebp) + /* Fixup page-tables for relocation. */ leal rva(pvh_init_top_pgt)(%ebp), %edi movl $PTRS_PER_PGD, %ecx @@ -165,20 +179,12 @@ SYM_CODE_START_LOCAL(pvh_start_xen) xor %edx, %edx wrmsr - /* - * Calculate load offset and store in phys_base. __pa() needs - * phys_base set to calculate the hypercall page in xen_pvh_init(). - */ - movq %rbp, %rbx - subq $_pa(pvh_start_xen), %rbx - movq %rbx, phys_base(%rip) - call xen_prepare_pvh - /* - * Clear phys_base. __startup_64 will *add* to its value, - * so reset to 0. - */ - xor %rbx, %rbx - movq %rbx, phys_base(%rip) + /* Call xen_prepare_pvh() via the kernel virtual mapping */ + leaq xen_prepare_pvh(%rip), %rax + subq phys_base(%rip), %rax + addq $__START_KERNEL_map, %rax + ANNOTATE_RETPOLINE_SAFE + call *%rax /* startup_64 expects boot_params in %rsi. */ lea pvh_bootparams(%rip), %rsi @@ -217,8 +223,8 @@ SYM_CODE_END(pvh_start_xen) .section ".init.data","aw" .balign 8 SYM_DATA_START_LOCAL(gdt) - .word gdt_end - gdt_start - .long _pa(gdt_start) /* x86-64 will overwrite if relocated. */ + .word gdt_end - gdt_start - 1 + .long gdt_start - gdt .word 0 SYM_DATA_END(gdt) SYM_DATA_START_LOCAL(gdt_start) @@ -300,5 +306,5 @@ SYM_DATA_END(pvh_level2_kernel_pgt) .long KERNEL_IMAGE_SIZE - 1) #endif - ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, - _ASM_PTR (pvh_start_xen - __START_KERNEL_map)) + ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .global xen_elfnote_phys32_entry; + xen_elfnote_phys32_entry: _ASM_PTR xen_elfnote_phys32_entry_value - .) diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index c101bed6194000..27441e5863b23b 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -56,6 +56,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { [S_ABS] = "^(xen_irq_disable_direct_reloc$|" "xen_save_fl_direct_reloc$|" + "xen_elfnote_.+_offset$|" "VDSO|" "__kcfi_typeid_|" "__crc_)", @@ -89,7 +90,6 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { "init_per_cpu__.*|" "__end_rodata_hpage_align|" #endif - "__vvar_page|" "_end)$" }; diff --git a/arch/x86/um/Kconfig b/arch/x86/um/Kconfig index 186f13268401bd..986045d5e63854 100644 --- a/arch/x86/um/Kconfig +++ b/arch/x86/um/Kconfig @@ -10,6 +10,7 @@ config UML_X86 def_bool y select ARCH_BINFMT_ELF_EXTRA_PHDRS if X86_32 select DCACHE_WORD_ACCESS + select HAVE_EFFICIENT_UNALIGNED_ACCESS config 64BIT bool "64-bit kernel" if "$(SUBARCH)" = "x86" @@ -28,17 +29,6 @@ config X86_64 def_bool 64BIT select MODULES_USE_ELF_RELA -config 3_LEVEL_PGTABLES - bool "Three-level pagetables" if !64BIT - default 64BIT - help - Three-level pagetables will let UML have more than 4G of physical - memory. All the memory that can't be mapped directly will be treated - as high memory. - - However, this it experimental on 32-bit architectures, so if unsure say - N (on x86-64 it's automatically enabled, instead, as it's safe there). - config ARCH_HAS_SC_SIGNALS def_bool !64BIT diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile index 36e67fc97c22fd..b42c31cd2390cb 100644 --- a/arch/x86/um/Makefile +++ b/arch/x86/um/Makefile @@ -10,7 +10,7 @@ else endif obj-y = bugs_$(BITS).o delay.o fault.o \ - ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ + ptrace.o ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ stub_segv.o \ sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ mem_$(BITS).o subarch.o os-Linux/ diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h index 6052200fe92568..62ed5d68a9788f 100644 --- a/arch/x86/um/asm/elf.h +++ b/arch/x86/um/asm/elf.h @@ -8,6 +8,8 @@ #include #include +#define CORE_DUMP_USE_REGSET + #ifdef CONFIG_X86_32 #define R_386_NONE 0 diff --git a/arch/x86/um/asm/ptrace.h b/arch/x86/um/asm/ptrace.h index 2fef3da5553377..2641d28d115ca6 100644 --- a/arch/x86/um/asm/ptrace.h +++ b/arch/x86/um/asm/ptrace.h @@ -2,6 +2,16 @@ #ifndef __UM_X86_PTRACE_H #define __UM_X86_PTRACE_H +/* This is here because signal.c needs the REGSET_FP_LEGACY definition */ +enum { + REGSET_GENERAL, +#ifdef CONFIG_X86_32 + REGSET_FP_LEGACY, +#endif + REGSET_FP, + REGSET_XSTATE, +}; + #include #ifndef CONFIG_X86_32 #define __FRAME_OFFSETS /* Needed to get the R* macros */ diff --git a/arch/x86/um/os-Linux/Makefile b/arch/x86/um/os-Linux/Makefile index 5249bbc30dcdb1..77a308aaa5ec9a 100644 --- a/arch/x86/um/os-Linux/Makefile +++ b/arch/x86/um/os-Linux/Makefile @@ -3,7 +3,7 @@ # Licensed under the GPL # -obj-y = registers.o task_size.o mcontext.o +obj-y = registers.o mcontext.o obj-$(CONFIG_X86_32) += tls.o diff --git a/arch/x86/um/os-Linux/registers.c b/arch/x86/um/os-Linux/registers.c index f3638dd09cecec..76eaeb93928cce 100644 --- a/arch/x86/um/os-Linux/registers.c +++ b/arch/x86/um/os-Linux/registers.c @@ -16,133 +16,58 @@ #include #include #include +#include -static int have_xstate_support; +unsigned long host_fp_size; -int save_i387_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} - -int save_fp_registers(int pid, unsigned long *fp_regs) +int get_fp_registers(int pid, unsigned long *regs) { -#ifdef PTRACE_GETREGSET - struct iovec iov; + struct iovec iov = { + .iov_base = regs, + .iov_len = host_fp_size, + }; - if (have_xstate_support) { - iov.iov_base = fp_regs; - iov.iov_len = FP_SIZE * sizeof(unsigned long); - if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) - return -errno; - return 0; - } else -#endif - return save_i387_registers(pid, fp_regs); -} - -int restore_i387_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) + if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) < 0) return -errno; return 0; } -int restore_fp_registers(int pid, unsigned long *fp_regs) -{ -#ifdef PTRACE_SETREGSET - struct iovec iov; - if (have_xstate_support) { - iov.iov_base = fp_regs; - iov.iov_len = FP_SIZE * sizeof(unsigned long); - if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) - return -errno; - return 0; - } else -#endif - return restore_i387_registers(pid, fp_regs); -} - -#ifdef __i386__ -int have_fpx_regs = 1; -int save_fpx_registers(int pid, unsigned long *fp_regs) +int put_fp_registers(int pid, unsigned long *regs) { - if (ptrace(PTRACE_GETFPXREGS, pid, 0, fp_regs) < 0) - return -errno; - return 0; -} + struct iovec iov = { + .iov_base = regs, + .iov_len = host_fp_size, + }; -int restore_fpx_registers(int pid, unsigned long *fp_regs) -{ - if (ptrace(PTRACE_SETFPXREGS, pid, 0, fp_regs) < 0) + if (ptrace(PTRACE_SETREGSET, pid, NT_X86_XSTATE, &iov) < 0) return -errno; return 0; } -int get_fp_registers(int pid, unsigned long *regs) -{ - if (have_fpx_regs) - return save_fpx_registers(pid, regs); - else - return save_fp_registers(pid, regs); -} - -int put_fp_registers(int pid, unsigned long *regs) -{ - if (have_fpx_regs) - return restore_fpx_registers(pid, regs); - else - return restore_fp_registers(pid, regs); -} - -void arch_init_registers(int pid) -{ - struct user_fpxregs_struct fpx_regs; - int err; - - err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); - if (!err) - return; - - if (errno != EIO) - panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", - errno); - - have_fpx_regs = 0; -} -#else - -int get_fp_registers(int pid, unsigned long *regs) +int arch_init_registers(int pid) { - return save_fp_registers(pid, regs); + struct iovec iov = { + /* Just use plenty of space, it does not cost us anything */ + .iov_len = 2 * 1024 * 1024, + }; + int ret; + + iov.iov_base = mmap(NULL, iov.iov_len, PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (iov.iov_base == MAP_FAILED) + return -ENOMEM; + + /* GDB has x86_xsave_length, which uses x86_cpuid_count */ + ret = ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov); + if (ret) + ret = -errno; + munmap(iov.iov_base, 2 * 1024 * 1024); + + host_fp_size = iov.iov_len; + + return ret; } -int put_fp_registers(int pid, unsigned long *regs) -{ - return restore_fp_registers(pid, regs); -} - -void arch_init_registers(int pid) -{ -#ifdef PTRACE_GETREGSET - void * fp_regs; - struct iovec iov; - - fp_regs = malloc(FP_SIZE * sizeof(unsigned long)); - if(fp_regs == NULL) - return; - - iov.iov_base = fp_regs; - iov.iov_len = FP_SIZE * sizeof(unsigned long); - if (ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov) == 0) - have_xstate_support = 1; - - free(fp_regs); -#endif -} -#endif - unsigned long get_thread_reg(int reg, jmp_buf *buf) { switch (reg) { diff --git a/arch/x86/um/os-Linux/task_size.c b/arch/x86/um/os-Linux/task_size.c deleted file mode 100644 index 1dc9adc20b1ca0..00000000000000 --- a/arch/x86/um/os-Linux/task_size.c +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include - -#ifdef __i386__ - -static jmp_buf buf; - -static void segfault(int sig) -{ - longjmp(buf, 1); -} - -static int page_ok(unsigned long page) -{ - unsigned long *address = (unsigned long *) (page << UM_KERN_PAGE_SHIFT); - unsigned long n = ~0UL; - void *mapped = NULL; - int ok = 0; - - /* - * First see if the page is readable. If it is, it may still - * be a VDSO, so we go on to see if it's writable. If not - * then try mapping memory there. If that fails, then we're - * still in the kernel area. As a sanity check, we'll fail if - * the mmap succeeds, but gives us an address different from - * what we wanted. - */ - if (setjmp(buf) == 0) - n = *address; - else { - mapped = mmap(address, UM_KERN_PAGE_SIZE, - PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (mapped == MAP_FAILED) - return 0; - if (mapped != address) - goto out; - } - - /* - * Now, is it writeable? If so, then we're in user address - * space. If not, then try mprotecting it and try the write - * again. - */ - if (setjmp(buf) == 0) { - *address = n; - ok = 1; - goto out; - } else if (mprotect(address, UM_KERN_PAGE_SIZE, - PROT_READ | PROT_WRITE) != 0) - goto out; - - if (setjmp(buf) == 0) { - *address = n; - ok = 1; - } - - out: - if (mapped != NULL) - munmap(mapped, UM_KERN_PAGE_SIZE); - return ok; -} - -unsigned long os_get_top_address(void) -{ - struct sigaction sa, old; - unsigned long bottom = 0; - /* - * A 32-bit UML on a 64-bit host gets confused about the VDSO at - * 0xffffe000. It is mapped, is readable, can be reprotected writeable - * and written. However, exec discovers later that it can't be - * unmapped. So, just set the highest address to be checked to just - * below it. This might waste some address space on 4G/4G 32-bit - * hosts, but shouldn't hurt otherwise. - */ - unsigned long top = 0xffffd000 >> UM_KERN_PAGE_SHIFT; - unsigned long test, original; - - printf("Locating the bottom of the address space ... "); - fflush(stdout); - - /* - * We're going to be longjmping out of the signal handler, so - * SA_DEFER needs to be set. - */ - sa.sa_handler = segfault; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_NODEFER; - if (sigaction(SIGSEGV, &sa, &old)) { - perror("os_get_top_address"); - exit(1); - } - - /* Manually scan the address space, bottom-up, until we find - * the first valid page (or run out of them). - */ - for (bottom = 0; bottom < top; bottom++) { - if (page_ok(bottom)) - break; - } - - /* If we've got this far, we ran out of pages. */ - if (bottom == top) { - fprintf(stderr, "Unable to determine bottom of address " - "space.\n"); - exit(1); - } - - printf("0x%lx\n", bottom << UM_KERN_PAGE_SHIFT); - printf("Locating the top of the address space ... "); - fflush(stdout); - - original = bottom; - - /* This could happen with a 4G/4G split */ - if (page_ok(top)) - goto out; - - do { - test = bottom + (top - bottom) / 2; - if (page_ok(test)) - bottom = test; - else - top = test; - } while (top - bottom > 1); - -out: - /* Restore the old SIGSEGV handling */ - if (sigaction(SIGSEGV, &old, NULL)) { - perror("os_get_top_address"); - exit(1); - } - top <<= UM_KERN_PAGE_SHIFT; - printf("0x%lx\n", top); - - return top; -} - -#else - -unsigned long os_get_top_address(void) -{ - /* The old value of CONFIG_TOP_ADDR */ - return 0x7fc0002000; -} - -#endif diff --git a/arch/x86/um/ptrace.c b/arch/x86/um/ptrace.c new file mode 100644 index 00000000000000..57c504fd5626e5 --- /dev/null +++ b/arch/x86/um/ptrace.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include + +#ifdef CONFIG_X86_32 +/* + * FPU tag word conversions. + */ + +static inline unsigned short twd_i387_to_fxsr(unsigned short twd) +{ + unsigned int tmp; /* to avoid 16 bit prefixes in the code */ + + /* Transform each pair of bits into 01 (valid) or 00 (empty) */ + tmp = ~twd; + tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ + /* and move the valid bits to the lower byte. */ + tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ + tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ + tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ + return tmp; +} + +static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) +{ + struct _fpxreg *st = NULL; + unsigned long twd = (unsigned long) fxsave->twd; + unsigned long tag; + unsigned long ret = 0xffff0000; + int i; + +#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) + + for (i = 0; i < 8; i++) { + if (twd & 0x1) { + st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); + + switch (st->exponent & 0x7fff) { + case 0x7fff: + tag = 2; /* Special */ + break; + case 0x0000: + if (!st->significand[0] && + !st->significand[1] && + !st->significand[2] && + !st->significand[3]) { + tag = 1; /* Zero */ + } else { + tag = 2; /* Special */ + } + break; + default: + if (st->significand[3] & 0x8000) + tag = 0; /* Valid */ + else + tag = 2; /* Special */ + break; + } + } else { + tag = 3; /* Empty */ + } + ret |= (tag << (2 * i)); + twd = twd >> 1; + } + return ret; +} + +/* Get/set the old 32bit i387 registers (pre-FPX) */ +static int fpregs_legacy_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + struct user_fxsr_struct *fxsave = (void *)target->thread.regs.regs.fp; + int i; + + membuf_store(&to, (unsigned long)fxsave->cwd | 0xffff0000ul); + membuf_store(&to, (unsigned long)fxsave->swd | 0xffff0000ul); + membuf_store(&to, twd_fxsr_to_i387(fxsave)); + membuf_store(&to, fxsave->fip); + membuf_store(&to, fxsave->fcs | ((unsigned long)fxsave->fop << 16)); + membuf_store(&to, fxsave->foo); + membuf_store(&to, fxsave->fos); + + for (i = 0; i < 8; i++) + membuf_write(&to, (void *)fxsave->st_space + i * 16, 10); + + return 0; +} + +static int fpregs_legacy_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct user_fxsr_struct *fxsave = (void *)target->thread.regs.regs.fp; + const struct user_i387_struct *from; + struct user_i387_struct buf; + int i; + + if (ubuf) { + if (copy_from_user(&buf, ubuf, sizeof(buf))) + return -EFAULT; + from = &buf; + } else { + from = kbuf; + } + + fxsave->cwd = (unsigned short)(from->cwd & 0xffff); + fxsave->swd = (unsigned short)(from->swd & 0xffff); + fxsave->twd = twd_i387_to_fxsr((unsigned short)(from->twd & 0xffff)); + fxsave->fip = from->fip; + fxsave->fop = (unsigned short)((from->fcs & 0xffff0000ul) >> 16); + fxsave->fcs = (from->fcs & 0xffff); + fxsave->foo = from->foo; + fxsave->fos = from->fos; + + for (i = 0; i < 8; i++) { + memcpy((void *)fxsave->st_space + i * 16, + (void *)from->st_space + i * 10, 10); + } + + return 0; +} +#endif + +static int genregs_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + int reg; + + for (reg = 0; to.left; reg++) + membuf_store(&to, getreg(target, reg * sizeof(unsigned long))); + return 0; +} + +static int genregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret = 0; + + if (kbuf) { + const unsigned long *k = kbuf; + + while (count >= sizeof(*k) && !ret) { + ret = putreg(target, pos, *k++); + count -= sizeof(*k); + pos += sizeof(*k); + } + } else { + const unsigned long __user *u = ubuf; + + while (count >= sizeof(*u) && !ret) { + unsigned long word; + + ret = __get_user(word, u++); + if (ret) + break; + ret = putreg(target, pos, word); + count -= sizeof(*u); + pos += sizeof(*u); + } + } + return ret; +} + +static int generic_fpregs_active(struct task_struct *target, const struct user_regset *regset) +{ + return regset->n; +} + +static int generic_fpregs_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + void *fpregs = task_pt_regs(target)->regs.fp; + + membuf_write(&to, fpregs, regset->size * regset->n); + return 0; +} + +static int generic_fpregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + void *fpregs = task_pt_regs(target)->regs.fp; + + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, + fpregs, 0, regset->size * regset->n); +} + +static struct user_regset uml_regsets[] __ro_after_init = { + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = sizeof(struct user_regs_struct) / sizeof(long), + .size = sizeof(long), + .align = sizeof(long), + .regset_get = genregs_get, + .set = genregs_set + }, +#ifdef CONFIG_X86_32 + /* Old FP registers, they are needed in signal frames */ + [REGSET_FP_LEGACY] = { + .core_note_type = NT_PRFPREG, + .n = sizeof(struct user_i387_ia32_struct) / sizeof(long), + .size = sizeof(long), + .align = sizeof(long), + .active = generic_fpregs_active, + .regset_get = fpregs_legacy_get, + .set = fpregs_legacy_set, + }, +#endif + [REGSET_FP] = { +#ifdef CONFIG_X86_32 + .core_note_type = NT_PRXFPREG, + .n = sizeof(struct user32_fxsr_struct) / sizeof(long), +#else + .core_note_type = NT_PRFPREG, + .n = sizeof(struct user_i387_struct) / sizeof(long), +#endif + .size = sizeof(long), + .align = sizeof(long), + .active = generic_fpregs_active, + .regset_get = generic_fpregs_get, + .set = generic_fpregs_set, + }, + [REGSET_XSTATE] = { + .core_note_type = NT_X86_XSTATE, + .size = sizeof(long), + .align = sizeof(long), + .active = generic_fpregs_active, + .regset_get = generic_fpregs_get, + .set = generic_fpregs_set, + }, + /* TODO: Add TLS regset for 32bit */ +}; + +static const struct user_regset_view user_uml_view = { +#ifdef CONFIG_X86_32 + .name = "i386", .e_machine = EM_386, +#else + .name = "x86_64", .e_machine = EM_X86_64, +#endif + .regsets = uml_regsets, .n = ARRAY_SIZE(uml_regsets) +}; + +const struct user_regset_view * +task_user_regset_view(struct task_struct *tsk) +{ + return &user_uml_view; +} + +static int __init init_regset_xstate_info(void) +{ + uml_regsets[REGSET_XSTATE].n = + host_fp_size / uml_regsets[REGSET_XSTATE].size; + + return 0; +} +arch_initcall(init_regset_xstate_info); diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index b0a71c6cdc6e6c..3af3cb821524bf 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -168,65 +169,6 @@ int peek_user(struct task_struct *child, long addr, long data) return put_user(tmp, (unsigned long __user *) data); } -static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) -{ - int err, n, cpu = task_cpu(child); - struct user_i387_struct fpregs; - - err = save_i387_registers(userspace_pid[cpu], - (unsigned long *) &fpregs); - if (err) - return err; - - n = copy_to_user(buf, &fpregs, sizeof(fpregs)); - if(n > 0) - return -EFAULT; - - return n; -} - -static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) -{ - int n, cpu = task_cpu(child); - struct user_i387_struct fpregs; - - n = copy_from_user(&fpregs, buf, sizeof(fpregs)); - if (n > 0) - return -EFAULT; - - return restore_i387_registers(userspace_pid[cpu], - (unsigned long *) &fpregs); -} - -static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) -{ - int err, n, cpu = task_cpu(child); - struct user_fxsr_struct fpregs; - - err = save_fpx_registers(userspace_pid[cpu], (unsigned long *) &fpregs); - if (err) - return err; - - n = copy_to_user(buf, &fpregs, sizeof(fpregs)); - if(n > 0) - return -EFAULT; - - return n; -} - -static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) -{ - int n, cpu = task_cpu(child); - struct user_fxsr_struct fpregs; - - n = copy_from_user(&fpregs, buf, sizeof(fpregs)); - if (n > 0) - return -EFAULT; - - return restore_fpx_registers(userspace_pid[cpu], - (unsigned long *) &fpregs); -} - long subarch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { @@ -234,17 +176,25 @@ long subarch_ptrace(struct task_struct *child, long request, void __user *datap = (void __user *) data; switch (request) { case PTRACE_GETFPREGS: /* Get the child FPU state. */ - ret = get_fpregs(datap, child); - break; + return copy_regset_to_user(child, task_user_regset_view(child), + REGSET_FP_LEGACY, + 0, sizeof(struct user_i387_struct), + datap); case PTRACE_SETFPREGS: /* Set the child FPU state. */ - ret = set_fpregs(datap, child); - break; + return copy_regset_from_user(child, task_user_regset_view(child), + REGSET_FP_LEGACY, + 0, sizeof(struct user_i387_struct), + datap); case PTRACE_GETFPXREGS: /* Get the child FPU state. */ - ret = get_fpxregs(datap, child); - break; + return copy_regset_to_user(child, task_user_regset_view(child), + REGSET_FP, + 0, sizeof(struct user_fxsr_struct), + datap); case PTRACE_SETFPXREGS: /* Set the child FPU state. */ - ret = set_fpxregs(datap, child); - break; + return copy_regset_from_user(child, task_user_regset_view(child), + REGSET_FP, + 0, sizeof(struct user_fxsr_struct), + datap); default: ret = -EIO; } diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index aa68d83d3f441b..e0d4120a45c8bc 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -8,6 +8,7 @@ #include #include #include +#include #define __FRAME_OFFSETS #include #include @@ -188,36 +189,6 @@ int peek_user(struct task_struct *child, long addr, long data) return put_user(tmp, (unsigned long *) data); } -static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) -{ - int err, n, cpu = ((struct thread_info *) child->stack)->cpu; - struct user_i387_struct fpregs; - - err = save_i387_registers(userspace_pid[cpu], - (unsigned long *) &fpregs); - if (err) - return err; - - n = copy_to_user(buf, &fpregs, sizeof(fpregs)); - if (n > 0) - return -EFAULT; - - return n; -} - -static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) -{ - int n, cpu = ((struct thread_info *) child->stack)->cpu; - struct user_i387_struct fpregs; - - n = copy_from_user(&fpregs, buf, sizeof(fpregs)); - if (n > 0) - return -EFAULT; - - return restore_i387_registers(userspace_pid[cpu], - (unsigned long *) &fpregs); -} - long subarch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { @@ -226,11 +197,15 @@ long subarch_ptrace(struct task_struct *child, long request, switch (request) { case PTRACE_GETFPREGS: /* Get the child FPU state. */ - ret = get_fpregs(datap, child); - break; + return copy_regset_to_user(child, task_user_regset_view(child), + REGSET_FP, + 0, sizeof(struct user_i387_struct), + datap); case PTRACE_SETFPREGS: /* Set the child FPU state. */ - ret = set_fpregs(datap, child); - break; + return copy_regset_from_user(child, task_user_regset_view(child), + REGSET_FP, + 0, sizeof(struct user_i387_struct), + datap); case PTRACE_ARCH_PRCTL: /* XXX Calls ptrace on the host - needs some SMP thinking */ ret = arch_prctl(child, data, (void __user *) addr); diff --git a/arch/x86/um/shared/sysdep/ptrace.h b/arch/x86/um/shared/sysdep/ptrace.h index 6ca4ecabc55b55..2dd4ca6713f8bf 100644 --- a/arch/x86/um/shared/sysdep/ptrace.h +++ b/arch/x86/um/shared/sysdep/ptrace.h @@ -56,12 +56,16 @@ struct syscall_args { UPT_SYSCALL_ARG5(r), \ UPT_SYSCALL_ARG6(r) } } ) +extern unsigned long host_fp_size; + struct uml_pt_regs { unsigned long gp[MAX_REG_NR]; - unsigned long fp[MAX_FP_NR]; struct faultinfo faultinfo; long syscall; int is_user; + + /* Dynamically sized FP registers (holds an XSTATE) */ + unsigned long fp[]; }; #define EMPTY_UML_PT_REGS { } @@ -72,4 +76,6 @@ struct uml_pt_regs { extern int user_context(unsigned long sp); +extern int arch_init_registers(int pid); + #endif /* __SYSDEP_X86_PTRACE_H */ diff --git a/arch/x86/um/shared/sysdep/ptrace_32.h b/arch/x86/um/shared/sysdep/ptrace_32.h index 0c4989842fbe6c..2392470cac4dbe 100644 --- a/arch/x86/um/shared/sysdep/ptrace_32.h +++ b/arch/x86/um/shared/sysdep/ptrace_32.h @@ -6,8 +6,6 @@ #ifndef __SYSDEP_I386_PTRACE_H #define __SYSDEP_I386_PTRACE_H -#define MAX_FP_NR HOST_FPX_SIZE - #define UPT_SYSCALL_ARG1(r) UPT_BX(r) #define UPT_SYSCALL_ARG2(r) UPT_CX(r) #define UPT_SYSCALL_ARG3(r) UPT_DX(r) @@ -15,6 +13,4 @@ #define UPT_SYSCALL_ARG5(r) UPT_DI(r) #define UPT_SYSCALL_ARG6(r) UPT_BP(r) -extern void arch_init_registers(int pid); - #endif diff --git a/arch/x86/um/shared/sysdep/ptrace_64.h b/arch/x86/um/shared/sysdep/ptrace_64.h index 0dc223aa1c2db5..e73573ac871fc9 100644 --- a/arch/x86/um/shared/sysdep/ptrace_64.h +++ b/arch/x86/um/shared/sysdep/ptrace_64.h @@ -8,8 +8,6 @@ #ifndef __SYSDEP_X86_64_PTRACE_H #define __SYSDEP_X86_64_PTRACE_H -#define MAX_FP_NR HOST_FP_SIZE - #define REGS_R8(r) ((r)[HOST_R8]) #define REGS_R9(r) ((r)[HOST_R9]) #define REGS_R10(r) ((r)[HOST_R10]) @@ -57,6 +55,4 @@ #define UPT_SYSCALL_ARG5(r) UPT_R8(r) #define UPT_SYSCALL_ARG6(r) UPT_R9(r) -extern void arch_init_registers(int pid); - #endif diff --git a/arch/x86/um/shared/sysdep/ptrace_user.h b/arch/x86/um/shared/sysdep/ptrace_user.h index 1d1a824fa65282..98da2312053861 100644 --- a/arch/x86/um/shared/sysdep/ptrace_user.h +++ b/arch/x86/um/shared/sysdep/ptrace_user.h @@ -11,12 +11,6 @@ #define REGS_IP_INDEX HOST_IP #define REGS_SP_INDEX HOST_SP -#ifdef __i386__ -#define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE) -#else -#define FP_SIZE HOST_FP_SIZE -#endif - /* * glibc before 2.27 does not include PTRACE_SYSEMU_SINGLESTEP in its enum, * ensure we have a definition by (re-)defining it here. diff --git a/arch/x86/um/shared/sysdep/stub_32.h b/arch/x86/um/shared/sysdep/stub_32.h index 0b44a86dd346e4..390988132c0a7a 100644 --- a/arch/x86/um/shared/sysdep/stub_32.h +++ b/arch/x86/um/shared/sysdep/stub_32.h @@ -112,11 +112,23 @@ static __always_inline void *get_stub_data(void) unsigned long ret; asm volatile ( - "movl %%esp,%0 ;" - "andl %1,%0" + "call _here_%=;" + "_here_%=:" + "popl %0;" + "andl %1, %0 ;" + "addl %2, %0 ;" : "=a" (ret) - : "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1))); + : "g" (~(UM_KERN_PAGE_SIZE - 1)), + "g" (UM_KERN_PAGE_SIZE)); return (void *)ret; } + +#define stub_start(fn) \ + asm volatile ( \ + "subl %0,%%esp ;" \ + "movl %1, %%eax ; " \ + "call *%%eax ;" \ + :: "i" ((1 + STUB_DATA_PAGES) * UM_KERN_PAGE_SIZE), \ + "i" (&fn)) #endif diff --git a/arch/x86/um/shared/sysdep/stub_64.h b/arch/x86/um/shared/sysdep/stub_64.h index 67f44284f1aa41..294affbec74293 100644 --- a/arch/x86/um/shared/sysdep/stub_64.h +++ b/arch/x86/um/shared/sysdep/stub_64.h @@ -28,6 +28,17 @@ static __always_inline long stub_syscall0(long syscall) return ret; } +static __always_inline long stub_syscall1(long syscall, long arg1) +{ + long ret; + + __asm__ volatile (__syscall + : "=a" (ret) + : "0" (syscall), "D" (arg1) : __syscall_clobber ); + + return ret; +} + static __always_inline long stub_syscall2(long syscall, long arg1, long arg2) { long ret; @@ -106,11 +117,21 @@ static __always_inline void *get_stub_data(void) unsigned long ret; asm volatile ( - "movq %%rsp,%0 ;" - "andq %1,%0" + "lea 0(%%rip), %0;" + "andq %1, %0 ;" + "addq %2, %0 ;" : "=a" (ret) - : "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1))); + : "g" (~(UM_KERN_PAGE_SIZE - 1)), + "g" (UM_KERN_PAGE_SIZE)); return (void *)ret; } + +#define stub_start(fn) \ + asm volatile ( \ + "subq %0,%%rsp ;" \ + "movq %1,%%rax ;" \ + "call *%%rax ;" \ + :: "i" ((1 + STUB_DATA_PAGES) * UM_KERN_PAGE_SIZE), \ + "i" (&fn)) #endif diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index 2cc8c230902287..75087e85b6fdb7 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -16,145 +16,24 @@ #include #include -#ifdef CONFIG_X86_32 - -/* - * FPU tag word conversions. - */ - -static inline unsigned short twd_i387_to_fxsr(unsigned short twd) -{ - unsigned int tmp; /* to avoid 16 bit prefixes in the code */ - - /* Transform each pair of bits into 01 (valid) or 00 (empty) */ - tmp = ~twd; - tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ - /* and move the valid bits to the lower byte. */ - tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ - tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ - tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ - return tmp; -} - -static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) -{ - struct _fpxreg *st = NULL; - unsigned long twd = (unsigned long) fxsave->twd; - unsigned long tag; - unsigned long ret = 0xffff0000; - int i; - -#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) - - for (i = 0; i < 8; i++) { - if (twd & 0x1) { - st = (struct _fpxreg *) FPREG_ADDR(fxsave, i); - - switch (st->exponent & 0x7fff) { - case 0x7fff: - tag = 2; /* Special */ - break; - case 0x0000: - if ( !st->significand[0] && - !st->significand[1] && - !st->significand[2] && - !st->significand[3] ) { - tag = 1; /* Zero */ - } else { - tag = 2; /* Special */ - } - break; - default: - if (st->significand[3] & 0x8000) { - tag = 0; /* Valid */ - } else { - tag = 2; /* Special */ - } - break; - } - } else { - tag = 3; /* Empty */ - } - ret |= (tag << (2 * i)); - twd = twd >> 1; - } - return ret; -} - -static int convert_fxsr_to_user(struct _fpstate __user *buf, - struct user_fxsr_struct *fxsave) -{ - unsigned long env[7]; - struct _fpreg __user *to; - struct _fpxreg *from; - int i; - - env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul; - env[1] = (unsigned long)fxsave->swd | 0xffff0000ul; - env[2] = twd_fxsr_to_i387(fxsave); - env[3] = fxsave->fip; - env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); - env[5] = fxsave->foo; - env[6] = fxsave->fos; - - if (__copy_to_user(buf, env, 7 * sizeof(unsigned long))) - return 1; - - to = &buf->_st[0]; - from = (struct _fpxreg *) &fxsave->st_space[0]; - for (i = 0; i < 8; i++, to++, from++) { - unsigned long __user *t = (unsigned long __user *)to; - unsigned long *f = (unsigned long *)from; - - if (__put_user(*f, t) || - __put_user(*(f + 1), t + 1) || - __put_user(from->exponent, &to->exponent)) - return 1; - } - return 0; -} - -static int convert_fxsr_from_user(struct user_fxsr_struct *fxsave, - struct _fpstate __user *buf) -{ - unsigned long env[7]; - struct _fpxreg *to; - struct _fpreg __user *from; - int i; - - if (copy_from_user( env, buf, 7 * sizeof(long))) - return 1; - - fxsave->cwd = (unsigned short)(env[0] & 0xffff); - fxsave->swd = (unsigned short)(env[1] & 0xffff); - fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); - fxsave->fip = env[3]; - fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16); - fxsave->fcs = (env[4] & 0xffff); - fxsave->foo = env[5]; - fxsave->fos = env[6]; - - to = (struct _fpxreg *) &fxsave->st_space[0]; - from = &buf->_st[0]; - for (i = 0; i < 8; i++, to++, from++) { - unsigned long *t = (unsigned long *)to; - unsigned long __user *f = (unsigned long __user *)from; - - if (__get_user(*t, f) || - __get_user(*(t + 1), f + 1) || - __get_user(to->exponent, &from->exponent)) - return 1; - } - return 0; -} - -extern int have_fpx_regs; +#include +#include +#ifdef CONFIG_X86_32 +struct _xstate_64 { + struct _fpstate_64 fpstate; + struct _header xstate_hdr; + struct _ymmh_state ymmh; + /* New processor state extensions go here: */ +}; +#else +#define _xstate_64 _xstate #endif static int copy_sc_from_user(struct pt_regs *regs, struct sigcontext __user *from) { + struct _xstate_64 __user *from_fp64; struct sigcontext sc; int err; @@ -203,35 +82,27 @@ static int copy_sc_from_user(struct pt_regs *regs, #undef GETREG #ifdef CONFIG_X86_32 - if (have_fpx_regs) { - struct user_fxsr_struct fpx; - int pid = userspace_pid[current_thread_info()->cpu]; + from_fp64 = ((void __user *)sc.fpstate) + + offsetof(struct _fpstate_32, _fxsr_env); +#else + from_fp64 = (void __user *)sc.fpstate; +#endif - err = copy_from_user(&fpx, - &((struct _fpstate __user *)sc.fpstate)->_fxsr_env[0], - sizeof(struct user_fxsr_struct)); - if (err) - return 1; + err = copy_from_user(regs->regs.fp, from_fp64, host_fp_size); + if (err) + return 1; - err = convert_fxsr_from_user(&fpx, (void *)sc.fpstate); - if (err) - return 1; - - err = restore_fpx_registers(pid, (unsigned long *) &fpx); - if (err < 0) { - printk(KERN_ERR "copy_sc_from_user - " - "restore_fpx_registers failed, errno = %d\n", - -err); - return 1; - } - } else +#ifdef CONFIG_X86_32 + /* Data is duplicated and this copy is the important one */ + err = copy_regset_from_user(current, + task_user_regset_view(current), + REGSET_FP_LEGACY, 0, + sizeof(struct user_i387_struct), + (void __user *)sc.fpstate); + if (err < 0) + return err; #endif - { - err = copy_from_user(regs->regs.fp, (void *)sc.fpstate, - sizeof(struct _xstate)); - if (err) - return 1; - } + return 0; } @@ -239,6 +110,7 @@ static int copy_sc_to_user(struct sigcontext __user *to, struct _xstate __user *to_fp, struct pt_regs *regs, unsigned long mask) { + struct _xstate_64 __user *to_fp64; struct sigcontext sc; struct faultinfo * fi = ¤t->thread.arch.faultinfo; int err; @@ -290,35 +162,46 @@ static int copy_sc_to_user(struct sigcontext __user *to, return 1; #ifdef CONFIG_X86_32 - if (have_fpx_regs) { - int pid = userspace_pid[current_thread_info()->cpu]; - struct user_fxsr_struct fpx; - - err = save_fpx_registers(pid, (unsigned long *) &fpx); - if (err < 0){ - printk(KERN_ERR "copy_sc_to_user - save_fpx_registers " - "failed, errno = %d\n", err); - return 1; - } - - err = convert_fxsr_to_user(&to_fp->fpstate, &fpx); - if (err) - return 1; + err = copy_regset_to_user(current, + task_user_regset_view(current), + REGSET_FP_LEGACY, 0, + sizeof(struct _fpstate_32), to_fp); + if (err < 0) + return err; - err |= __put_user(fpx.swd, &to_fp->fpstate.status); - err |= __put_user(X86_FXSR_MAGIC, &to_fp->fpstate.magic); - if (err) - return 1; + __put_user(X86_FXSR_MAGIC, &to_fp->fpstate.magic); + + BUILD_BUG_ON(offsetof(struct _xstate, xstate_hdr) != + offsetof(struct _xstate_64, xstate_hdr) + + offsetof(struct _fpstate_32, _fxsr_env)); + to_fp64 = (void __user *)to_fp + + offsetof(struct _fpstate_32, _fxsr_env); +#else + to_fp64 = to_fp; +#endif /* CONFIG_X86_32 */ + + if (copy_to_user(to_fp64, regs->regs.fp, host_fp_size)) + return 1; - if (copy_to_user(&to_fp->fpstate._fxsr_env[0], &fpx, - sizeof(struct user_fxsr_struct))) - return 1; - } else + /* + * Put magic/size values for userspace. We do not bother to verify them + * later on, however, userspace needs them should it try to read the + * XSTATE data. And ptrace does not fill in these parts. + */ + BUILD_BUG_ON(sizeof(int) != FP_XSTATE_MAGIC2_SIZE); +#ifdef CONFIG_X86_32 + __put_user(offsetof(struct _fpstate_32, _fxsr_env) + + host_fp_size + FP_XSTATE_MAGIC2_SIZE, + &to_fp64->fpstate.sw_reserved.extended_size); +#else + __put_user(host_fp_size + FP_XSTATE_MAGIC2_SIZE, + &to_fp64->fpstate.sw_reserved.extended_size); #endif - { - if (copy_to_user(to_fp, regs->regs.fp, sizeof(struct _xstate))) - return 1; - } + __put_user(host_fp_size, &to_fp64->fpstate.sw_reserved.xstate_size); + + __put_user(FP_XSTATE_MAGIC1, &to_fp64->fpstate.sw_reserved.magic1); + __put_user(FP_XSTATE_MAGIC2, + (int __user *)((void __user *)to_fp64 + host_fp_size)); return 0; } @@ -336,34 +219,15 @@ static int copy_ucontext_to_user(struct ucontext __user *uc, return err; } -struct sigframe -{ - char __user *pretcode; - int sig; - struct sigcontext sc; - struct _xstate fpstate; - unsigned long extramask[_NSIG_WORDS-1]; - char retcode[8]; -}; - -struct rt_sigframe -{ - char __user *pretcode; - int sig; - struct siginfo __user *pinfo; - void __user *puc; - struct siginfo info; - struct ucontext uc; - struct _xstate fpstate; - char retcode[8]; -}; - int setup_signal_stack_sc(unsigned long stack_top, struct ksignal *ksig, struct pt_regs *regs, sigset_t *mask) { + size_t math_size = offsetof(struct _fpstate_32, _fxsr_env) + + host_fp_size + FP_XSTATE_MAGIC2_SIZE; struct sigframe __user *frame; void __user *restorer; int err = 0, sig = ksig->sig; + unsigned long fp_to; /* This is the same calculation as i386 - ((sp + 4) & 15) == 0 */ stack_top = ((stack_top + 4) & -16UL) - 4; @@ -371,13 +235,21 @@ int setup_signal_stack_sc(unsigned long stack_top, struct ksignal *ksig, if (!access_ok(frame, sizeof(*frame))) return 1; + /* Add required space for math frame */ + frame = (struct sigframe __user *)((unsigned long)frame - math_size); + restorer = frame->retcode; if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = ksig->ka.sa.sa_restorer; - err |= __put_user(restorer, &frame->pretcode); + err |= __put_user(restorer, (void __user * __user *)&frame->pretcode); err |= __put_user(sig, &frame->sig); - err |= copy_sc_to_user(&frame->sc, &frame->fpstate, regs, mask->sig[0]); + + fp_to = (unsigned long)frame + sizeof(*frame); + + err |= copy_sc_to_user(&frame->sc, + (struct _xstate __user *)fp_to, + regs, mask->sig[0]); if (_NSIG_WORDS > 1) err |= __copy_to_user(&frame->extramask, &mask->sig[1], sizeof(frame->extramask)); @@ -407,26 +279,35 @@ int setup_signal_stack_sc(unsigned long stack_top, struct ksignal *ksig, int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, struct pt_regs *regs, sigset_t *mask) { + size_t math_size = offsetof(struct _fpstate_32, _fxsr_env) + + host_fp_size + FP_XSTATE_MAGIC2_SIZE; struct rt_sigframe __user *frame; void __user *restorer; int err = 0, sig = ksig->sig; + unsigned long fp_to; stack_top &= -8UL; frame = (struct rt_sigframe __user *) stack_top - 1; if (!access_ok(frame, sizeof(*frame))) return 1; + /* Add required space for math frame */ + frame = (struct rt_sigframe __user *)((unsigned long)frame - math_size); + restorer = frame->retcode; if (ksig->ka.sa.sa_flags & SA_RESTORER) restorer = ksig->ka.sa.sa_restorer; - err |= __put_user(restorer, &frame->pretcode); + err |= __put_user(restorer, (void __user * __user *)&frame->pretcode); err |= __put_user(sig, &frame->sig); - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); + err |= __put_user(&frame->info, (void __user * __user *)&frame->pinfo); + err |= __put_user(&frame->uc, (void __user * __user *)&frame->puc); err |= copy_siginfo_to_user(&frame->info, &ksig->info); - err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, - PT_REGS_SP(regs)); + + fp_to = (unsigned long)frame + sizeof(*frame); + + err |= copy_ucontext_to_user(&frame->uc, (struct _xstate __user *)fp_to, + mask, PT_REGS_SP(regs)); /* * This is movl $,%eax ; int $0x80 @@ -478,27 +359,24 @@ SYSCALL_DEFINE0(sigreturn) #else -struct rt_sigframe -{ - char __user *pretcode; - struct ucontext uc; - struct siginfo info; - struct _xstate fpstate; -}; - int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, struct pt_regs *regs, sigset_t *set) { + unsigned long math_size = host_fp_size + FP_XSTATE_MAGIC2_SIZE; struct rt_sigframe __user *frame; int err = 0, sig = ksig->sig; unsigned long fp_to; frame = (struct rt_sigframe __user *) round_down(stack_top - sizeof(struct rt_sigframe), 16); + + /* Add required space for math frame */ + frame = (struct rt_sigframe __user *)((unsigned long)frame - math_size); + /* Subtract 128 for a red zone and 8 for proper alignment */ frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8); - if (!access_ok(frame, sizeof(*frame))) + if (!access_ok(frame, sizeof(*frame) + math_size)) goto out; if (ksig->ka.sa.sa_flags & SA_SIGINFO) { @@ -509,12 +387,14 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(NULL, &frame->uc.uc_link); err |= __save_altstack(&frame->uc.uc_stack, PT_REGS_SP(regs)); - err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs, - set->sig[0]); - fp_to = (unsigned long)&frame->fpstate; + fp_to = (unsigned long)frame + sizeof(*frame); + + err |= copy_sc_to_user(&frame->uc.uc_mcontext, + (struct _xstate __user *)fp_to, + regs, set->sig[0]); err |= __put_user(fp_to, &frame->uc.uc_mcontext.fpstate); if (sizeof(*set) == 16) { @@ -531,7 +411,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, */ /* x86-64 should always use SA_RESTORER. */ if (ksig->ka.sa.sa_flags & SA_RESTORER) - err |= __put_user((void *)ksig->ka.sa.sa_restorer, + err |= __put_user((void __user *)ksig->ka.sa.sa_restorer, &frame->pretcode); else /* could use a vstub here */ diff --git a/arch/x86/um/user-offsets.c b/arch/x86/um/user-offsets.c index 1c77d994619985..d6e1cd9956bf99 100644 --- a/arch/x86/um/user-offsets.c +++ b/arch/x86/um/user-offsets.c @@ -20,9 +20,6 @@ void foo(void); void foo(void) { #ifdef __i386__ - DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_fpregs_struct)); - DEFINE_LONGS(HOST_FPX_SIZE, sizeof(struct user_fpxregs_struct)); - DEFINE(HOST_IP, EIP); DEFINE(HOST_SP, UESP); DEFINE(HOST_EFLAGS, EFL); @@ -41,11 +38,6 @@ void foo(void) DEFINE(HOST_GS, GS); DEFINE(HOST_ORIG_AX, ORIG_EAX); #else -#ifdef FP_XSTATE_MAGIC1 - DEFINE_LONGS(HOST_FP_SIZE, 2696); -#else - DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long)); -#endif DEFINE_LONGS(HOST_BX, RBX); DEFINE_LONGS(HOST_CX, RCX); DEFINE_LONGS(HOST_DI, RDI); diff --git a/arch/x86/um/vdso/Makefile b/arch/x86/um/vdso/Makefile index 6a77ea6434ffde..7478d11dacb713 100644 --- a/arch/x86/um/vdso/Makefile +++ b/arch/x86/um/vdso/Makefile @@ -56,7 +56,6 @@ CFLAGS_REMOVE_um_vdso.o = -pg -fprofile-arcs -ftest-coverage quiet_cmd_vdso = VDSO $@ cmd_vdso = $(CC) -nostdlib -o $@ \ $(CC_FLAGS_LTO) $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ - -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \ - sh $(src)/checkundef.sh '$(NM)' '$@' + -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) -VDSO_LDFLAGS = -fPIC -shared -Wl,--hash-style=sysv -z noexecstack +VDSO_LDFLAGS = -fPIC -shared -Wl,--hash-style=sysv -z noexecstack -Wl,--no-undefined diff --git a/arch/x86/um/vdso/checkundef.sh b/arch/x86/um/vdso/checkundef.sh deleted file mode 100644 index 8e3ea6bb956fc8..00000000000000 --- a/arch/x86/um/vdso/checkundef.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -nm="$1" -file="$2" -$nm "$file" | grep '^ *U' > /dev/null 2>&1 -if [ $? -eq 1 ]; then - exit 0 -else - echo "$file: undefined symbols found" >&2 - exit 1 -fi diff --git a/arch/x86/virt/svm/Makefile b/arch/x86/virt/svm/Makefile index ef2a31bdcc7044..eca6d71355facd 100644 --- a/arch/x86/virt/svm/Makefile +++ b/arch/x86/virt/svm/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_KVM_AMD_SEV) += sev.o +obj-$(CONFIG_CPU_SUP_AMD) += cmdline.o diff --git a/arch/x86/virt/svm/cmdline.c b/arch/x86/virt/svm/cmdline.c new file mode 100644 index 00000000000000..affa2759fa20ae --- /dev/null +++ b/arch/x86/virt/svm/cmdline.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AMD SVM-SEV command line parsing support + * + * Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. + * + * Author: Michael Roth + */ + +#include +#include +#include +#include + +#include + +struct sev_config sev_cfg __read_mostly; + +static int __init init_sev_config(char *str) +{ + char *s; + + while ((s = strsep(&str, ","))) { + if (!strcmp(s, "debug")) { + sev_cfg.debug = true; + continue; + } + + if (!strcmp(s, "nosnp")) { + if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) { + setup_clear_cpu_cap(X86_FEATURE_SEV_SNP); + cc_platform_clear(CC_ATTR_HOST_SEV_SNP); + continue; + } else { + goto warn; + } + } + +warn: + pr_info("SEV command-line option '%s' was not recognized\n", s); + } + + return 1; +} +__setup("sev=", init_sev_config); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 84e5adbd0925cb..43dcd8c7badc08 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -21,7 +22,8 @@ #include "xen-ops.h" -EXPORT_SYMBOL_GPL(hypercall_page); +DEFINE_STATIC_CALL(xen_hypercall, xen_hypercall_hvm); +EXPORT_STATIC_CALL_TRAMP(xen_hypercall); /* * Pointer to the xen_vcpu_info structure or @@ -68,6 +70,67 @@ EXPORT_SYMBOL(xen_start_flags); */ struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info; +static __ref void xen_get_vendor(void) +{ + init_cpu_devs(); + cpu_detect(&boot_cpu_data); + get_cpu_vendor(&boot_cpu_data); +} + +void xen_hypercall_setfunc(void) +{ + if (static_call_query(xen_hypercall) != xen_hypercall_hvm) + return; + + if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD || + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) + static_call_update(xen_hypercall, xen_hypercall_amd); + else + static_call_update(xen_hypercall, xen_hypercall_intel); +} + +/* + * Evaluate processor vendor in order to select the correct hypercall + * function for HVM/PVH guests. + * Might be called very early in boot before vendor has been set by + * early_cpu_init(). + */ +noinstr void *__xen_hypercall_setfunc(void) +{ + void (*func)(void); + + /* + * Xen is supported only on CPUs with CPUID, so testing for + * X86_FEATURE_CPUID is a test for early_cpu_init() having been + * run. + * + * Note that __xen_hypercall_setfunc() is noinstr only due to a nasty + * dependency chain: it is being called via the xen_hypercall static + * call when running as a PVH or HVM guest. Hypercalls need to be + * noinstr due to PV guests using hypercalls in noinstr code. So we + * can safely tag the function body as "instrumentation ok", since + * the PV guest requirement is not of interest here (xen_get_vendor() + * calls noinstr functions, and static_call_update_early() might do + * so, too). + */ + instrumentation_begin(); + + if (!boot_cpu_has(X86_FEATURE_CPUID)) + xen_get_vendor(); + + if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD || + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)) + func = xen_hypercall_amd; + else + func = xen_hypercall_intel; + + static_call_update_early(xen_hypercall, func); + + instrumentation_end(); + + return func; +} + static int xen_cpu_up_online(unsigned int cpu) { xen_init_lock_cpu(cpu); diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c index 24d2957a4726d8..fe57ff85d004ba 100644 --- a/arch/x86/xen/enlighten_hvm.c +++ b/arch/x86/xen/enlighten_hvm.c @@ -106,15 +106,8 @@ static void __init init_hvm_pv_info(void) /* PVH set up hypercall page in xen_prepare_pvh(). */ if (xen_pvh_domain()) pv_info.name = "Xen PVH"; - else { - u64 pfn; - uint32_t msr; - + else pv_info.name = "Xen HVM"; - msr = cpuid_ebx(base + 2); - pfn = __pa(hypercall_page); - wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); - } xen_setup_features(); @@ -300,6 +293,10 @@ static uint32_t __init xen_platform_hvm(void) if (xen_pv_domain()) return 0; + /* Set correct hypercall function. */ + if (xen_domain) + xen_hypercall_setfunc(); + if (xen_pvh_domain() && nopv) { /* Guest booting via the Xen-PVH boot entry goes here */ pr_info("\"nopv\" parameter is ignored in PVH guest\n"); diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index d6818c6cafda16..a8eb7e0c473cf6 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -1341,6 +1341,9 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si) xen_domain_type = XEN_PV_DOMAIN; xen_start_flags = xen_start_info->flags; + /* Interrupts are guaranteed to be off initially. */ + early_boot_irqs_disabled = true; + static_call_update_early(xen_hypercall, xen_hypercall_pv); xen_setup_features(); @@ -1431,7 +1434,6 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si) WARN_ON(xen_cpuhp_setup(xen_cpu_up_prepare_pv, xen_cpu_dead_pv)); local_irq_disable(); - early_boot_irqs_disabled = true; xen_raw_console_write("mapping kernel into physical memory\n"); xen_setup_kernel_pagetable((pgd_t *)xen_start_info->pt_base, diff --git a/arch/x86/xen/enlighten_pvh.c b/arch/x86/xen/enlighten_pvh.c index bf68c329fc013e..0e3d930bcb89e8 100644 --- a/arch/x86/xen/enlighten_pvh.c +++ b/arch/x86/xen/enlighten_pvh.c @@ -129,17 +129,10 @@ static void __init pvh_arch_setup(void) void __init xen_pvh_init(struct boot_params *boot_params) { - u32 msr; - u64 pfn; - xen_pvh = 1; xen_domain_type = XEN_HVM_DOMAIN; xen_start_flags = pvh_start_info.flags; - msr = cpuid_ebx(xen_cpuid_base() + 2); - pfn = __pa(hypercall_page); - wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32)); - x86_init.oem.arch_setup = pvh_arch_setup; x86_init.oem.banner = xen_banner; diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S index 83189cf5cdce93..b518f36d1ca2e7 100644 --- a/arch/x86/xen/xen-asm.S +++ b/arch/x86/xen/xen-asm.S @@ -20,9 +20,32 @@ #include #include +#include #include <../entry/calling.h> .pushsection .noinstr.text, "ax" +/* + * PV hypercall interface to the hypervisor. + * + * Called via inline asm(), so better preserve %rcx and %r11. + * + * Input: + * %eax: hypercall number + * %rdi, %rsi, %rdx, %r10, %r8: args 1..5 for the hypercall + * Output: %rax + */ +SYM_FUNC_START(xen_hypercall_pv) + ANNOTATE_NOENDBR + push %rcx + push %r11 + UNWIND_HINT_SAVE + syscall + UNWIND_HINT_RESTORE + pop %r11 + pop %rcx + RET +SYM_FUNC_END(xen_hypercall_pv) + /* * Disabling events is simply a matter of making the event mask * non-zero. @@ -176,7 +199,6 @@ SYM_CODE_START(xen_early_idt_handler_array) SYM_CODE_END(xen_early_idt_handler_array) __FINIT -hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 /* * Xen64 iret frame: * @@ -186,17 +208,28 @@ hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 * cs * rip <-- standard iret frame * - * flags + * flags <-- xen_iret must push from here on * - * rcx } - * r11 }<-- pushed by hypercall page - * rsp->rax } + * rcx + * r11 + * rsp->rax */ +.macro xen_hypercall_iret + pushq $0 /* Flags */ + push %rcx + push %r11 + push %rax + mov $__HYPERVISOR_iret, %eax + syscall /* Do the IRET. */ +#ifdef CONFIG_MITIGATION_SLS + int3 +#endif +.endm + SYM_CODE_START(xen_iret) UNWIND_HINT_UNDEFINED ANNOTATE_NOENDBR - pushq $0 - jmp hypercall_iret + xen_hypercall_iret SYM_CODE_END(xen_iret) /* @@ -301,8 +334,7 @@ SYM_CODE_START(xen_entry_SYSENTER_compat) ENDBR lea 16(%rsp), %rsp /* strip %rcx, %r11 */ mov $-ENOSYS, %rax - pushq $0 - jmp hypercall_iret + xen_hypercall_iret SYM_CODE_END(xen_entry_SYSENTER_compat) SYM_CODE_END(xen_entry_SYSCALL_compat) diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S index 758bcd47b72d32..9252652afe5964 100644 --- a/arch/x86/xen/xen-head.S +++ b/arch/x86/xen/xen-head.S @@ -6,9 +6,11 @@ #include #include +#include #include #include +#include #include #include #include @@ -20,28 +22,6 @@ #include #include -.pushsection .noinstr.text, "ax" - .balign PAGE_SIZE -SYM_CODE_START(hypercall_page) - .rept (PAGE_SIZE / 32) - UNWIND_HINT_FUNC - ANNOTATE_NOENDBR - ANNOTATE_UNRET_SAFE - ret - /* - * Xen will write the hypercall page, and sort out ENDBR. - */ - .skip 31, 0xcc - .endr - -#define HYPERCALL(n) \ - .equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \ - .type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32 -#include -#undef HYPERCALL -SYM_CODE_END(hypercall_page) -.popsection - #ifdef CONFIG_XEN_PV __INIT SYM_CODE_START(startup_xen) @@ -87,6 +67,87 @@ SYM_CODE_END(xen_cpu_bringup_again) #endif #endif + .pushsection .noinstr.text, "ax" +/* + * Xen hypercall interface to the hypervisor. + * + * Input: + * %eax: hypercall number + * 32-bit: + * %ebx, %ecx, %edx, %esi, %edi: args 1..5 for the hypercall + * 64-bit: + * %rdi, %rsi, %rdx, %r10, %r8: args 1..5 for the hypercall + * Output: %[er]ax + */ +SYM_FUNC_START(xen_hypercall_hvm) + ENDBR + FRAME_BEGIN + /* Save all relevant registers (caller save and arguments). */ +#ifdef CONFIG_X86_32 + push %eax + push %ebx + push %ecx + push %edx + push %esi + push %edi +#else + push %rax + push %rcx + push %rdx + push %rdi + push %rsi + push %r11 + push %r10 + push %r9 + push %r8 +#ifdef CONFIG_FRAME_POINTER + pushq $0 /* Dummy push for stack alignment. */ +#endif +#endif + /* Set the vendor specific function. */ + call __xen_hypercall_setfunc + /* Set ZF = 1 if AMD, Restore saved registers. */ +#ifdef CONFIG_X86_32 + lea xen_hypercall_amd, %ebx + cmp %eax, %ebx + pop %edi + pop %esi + pop %edx + pop %ecx + pop %ebx + pop %eax +#else + lea xen_hypercall_amd(%rip), %rbx + cmp %rax, %rbx +#ifdef CONFIG_FRAME_POINTER + pop %rax /* Dummy pop. */ +#endif + pop %r8 + pop %r9 + pop %r10 + pop %r11 + pop %rsi + pop %rdi + pop %rdx + pop %rcx + pop %rax +#endif + /* Use correct hypercall function. */ + jz xen_hypercall_amd + jmp xen_hypercall_intel +SYM_FUNC_END(xen_hypercall_hvm) + +SYM_FUNC_START(xen_hypercall_amd) + vmmcall + RET +SYM_FUNC_END(xen_hypercall_amd) + +SYM_FUNC_START(xen_hypercall_intel) + vmcall + RET +SYM_FUNC_END(xen_hypercall_intel) + .popsection + ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux") ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6") ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0") @@ -94,7 +155,8 @@ SYM_CODE_END(xen_cpu_bringup_again) ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, _ASM_PTR __START_KERNEL_map) /* Map the p2m table to a 512GB-aligned user address. */ ELFNOTE(Xen, XEN_ELFNOTE_INIT_P2M, .quad (PUD_SIZE * PTRS_PER_PUD)) - ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, _ASM_PTR startup_xen) + ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .globl xen_elfnote_entry; + xen_elfnote_entry: _ASM_PTR xen_elfnote_entry_value - .) ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .ascii "!writable_page_tables") ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "yes") ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID, @@ -115,7 +177,6 @@ SYM_CODE_END(xen_cpu_bringup_again) #else # define FEATURES_DOM0 0 #endif - ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, _ASM_PTR hypercall_page) ELFNOTE(Xen, XEN_ELFNOTE_SUPPORTED_FEATURES, .long FEATURES_PV | FEATURES_PVH | FEATURES_DOM0) ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic") diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h index e1b782e823e6b4..63c13a2ccf556a 100644 --- a/arch/x86/xen/xen-ops.h +++ b/arch/x86/xen/xen-ops.h @@ -326,4 +326,13 @@ static inline void xen_smp_intr_free_pv(unsigned int cpu) {} static inline void xen_smp_count_cpus(void) { } #endif /* CONFIG_SMP */ +#ifdef CONFIG_XEN_PV +void xen_hypercall_pv(void); +#endif +void xen_hypercall_hvm(void); +void xen_hypercall_amd(void); +void xen_hypercall_intel(void); +void xen_hypercall_setfunc(void); +void *__xen_hypercall_setfunc(void); + #endif /* XEN_OPS_H */ diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild index fa07c686cbcc21..cc5dba738389c3 100644 --- a/arch/xtensa/include/asm/Kbuild +++ b/arch/xtensa/include/asm/Kbuild @@ -8,3 +8,4 @@ generic-y += parport.h generic-y += qrwlock.h generic-y += qspinlock.h generic-y += user.h +generic-y += text-patching.h diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h index 4db56ef052d223..644413792bf359 100644 --- a/arch/xtensa/include/asm/page.h +++ b/arch/xtensa/include/asm/page.h @@ -18,13 +18,7 @@ #include #include -/* - * PAGE_SHIFT determines the page size - */ - -#define PAGE_SHIFT CONFIG_PAGE_SHIFT -#define PAGE_SIZE (__XTENSA_UL_CONST(1) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE-1)) +#include #ifdef CONFIG_MMU #define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR @@ -109,26 +103,8 @@ typedef struct page *pgtable_t; #define __pgd(x) ((pgd_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } ) -/* - * Pure 2^n version of get_order - * Use 'nsau' instructions if supported by the processor or the generic version. - */ - -#if XCHAL_HAVE_NSA - -static inline __attribute_const__ int get_order(unsigned long size) -{ - int lz; - asm ("nsau %0, %1" : "=r" (lz) : "r" ((size - 1) >> PAGE_SHIFT)); - return 32 - lz; -} - -#else - # include -#endif - struct page; struct vm_area_struct; extern void clear_page(void *page); @@ -195,7 +171,6 @@ static inline unsigned long ___pa(unsigned long va) #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) #define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) -#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #endif /* __ASSEMBLY__ */ diff --git a/arch/xtensa/include/asm/spinlock_types.h b/arch/xtensa/include/asm/spinlock_types.h index 797aed7df3dd81..6baaeac6248b82 100644 --- a/arch/xtensa/include/asm/spinlock_types.h +++ b/arch/xtensa/include/asm/spinlock_types.h @@ -3,7 +3,7 @@ #define __ASM_SPINLOCK_TYPES_H #if !defined(__LINUX_SPINLOCK_TYPES_RAW_H) && !defined(__ASM_SPINLOCK_H) -# error "please don't include this file directly" +# error "Please do not include this file directly." #endif #include diff --git a/arch/xtensa/include/uapi/asm/mman.h b/arch/xtensa/include/uapi/asm/mman.h index 1ff0c858544fa8..99d4ccee7f6e8a 100644 --- a/arch/xtensa/include/uapi/asm/mman.h +++ b/arch/xtensa/include/uapi/asm/mman.h @@ -113,6 +113,9 @@ #define MADV_COLLAPSE 25 /* Synchronous hugepage collapse */ +#define MADV_GUARD_INSTALL 102 /* fatal signal on access to range */ +#define MADV_GUARD_REMOVE 103 /* unguard range */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index bdec4a773af098..e51f2060e83089 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -216,7 +216,7 @@ static int __init xtensa_dt_io_area(unsigned long node, const char *uname, void __init early_init_devtree(void *params) { - early_init_dt_scan(params); + early_init_dt_scan(params, __pa(params)); of_scan_flat_dt(xtensa_dt_io_area, NULL); if (!command_line[0]) diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl index 67083fc1b2f563..37effc1b134eea 100644 --- a/arch/xtensa/kernel/syscalls/syscall.tbl +++ b/arch/xtensa/kernel/syscalls/syscall.tbl @@ -433,3 +433,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/block/bdev.c b/block/bdev.c index 738e3c8457e7f4..9d73a8fbf7f997 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -155,8 +155,7 @@ int set_blocksize(struct file *file, int size) struct inode *inode = file->f_mapping->host; struct block_device *bdev = I_BDEV(inode); - /* Size must be a power of two, and between 512 and PAGE_SIZE */ - if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size)) + if (blk_validate_block_size(size)) return -EINVAL; /* Size cannot be smaller than the size supported by the device */ diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index e831aedb464329..9fb9f353315025 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -736,6 +736,7 @@ static void bfq_sync_bfqq_move(struct bfq_data *bfqd, */ bfq_put_cooperator(sync_bfqq); bic_set_bfqq(bic, NULL, true, act_idx); + bfq_release_process_ref(bfqd, sync_bfqq); } } diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 0747d9d0e48c8a..95dd7b79593565 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -582,23 +582,31 @@ static struct request *bfq_choose_req(struct bfq_data *bfqd, #define BFQ_LIMIT_INLINE_DEPTH 16 #ifdef CONFIG_BFQ_GROUP_IOSCHED -static bool bfqq_request_over_limit(struct bfq_queue *bfqq, int limit) +static bool bfqq_request_over_limit(struct bfq_data *bfqd, + struct bfq_io_cq *bic, blk_opf_t opf, + unsigned int act_idx, int limit) { - struct bfq_data *bfqd = bfqq->bfqd; - struct bfq_entity *entity = &bfqq->entity; struct bfq_entity *inline_entities[BFQ_LIMIT_INLINE_DEPTH]; struct bfq_entity **entities = inline_entities; - int depth, level, alloc_depth = BFQ_LIMIT_INLINE_DEPTH; - int class_idx = bfqq->ioprio_class - 1; + int alloc_depth = BFQ_LIMIT_INLINE_DEPTH; struct bfq_sched_data *sched_data; + struct bfq_entity *entity; + struct bfq_queue *bfqq; unsigned long wsum; bool ret = false; - - if (!entity->on_st_or_in_serv) - return false; + int depth; + int level; retry: spin_lock_irq(&bfqd->lock); + bfqq = bic_to_bfqq(bic, op_is_sync(opf), act_idx); + if (!bfqq) + goto out; + + entity = &bfqq->entity; + if (!entity->on_st_or_in_serv) + goto out; + /* +1 for bfqq entity, root cgroup not included */ depth = bfqg_to_blkg(bfqq_group(bfqq))->blkcg->css.cgroup->level + 1; if (depth > alloc_depth) { @@ -643,7 +651,7 @@ static bool bfqq_request_over_limit(struct bfq_queue *bfqq, int limit) * class. */ wsum = 0; - for (i = 0; i <= class_idx; i++) { + for (i = 0; i <= bfqq->ioprio_class - 1; i++) { wsum = wsum * IOPRIO_BE_NR + sched_data->service_tree[i].wsum; } @@ -666,7 +674,9 @@ static bool bfqq_request_over_limit(struct bfq_queue *bfqq, int limit) return ret; } #else -static bool bfqq_request_over_limit(struct bfq_queue *bfqq, int limit) +static bool bfqq_request_over_limit(struct bfq_data *bfqd, + struct bfq_io_cq *bic, blk_opf_t opf, + unsigned int act_idx, int limit) { return false; } @@ -704,8 +714,9 @@ static void bfq_limit_depth(blk_opf_t opf, struct blk_mq_alloc_data *data) } for (act_idx = 0; bic && act_idx < bfqd->num_actuators; act_idx++) { - struct bfq_queue *bfqq = - bic_to_bfqq(bic, op_is_sync(opf), act_idx); + /* Fast path to check if bfqq is already allocated. */ + if (!bic_to_bfqq(bic, op_is_sync(opf), act_idx)) + continue; /* * Does queue (or any parent entity) exceed number of @@ -713,7 +724,7 @@ static void bfq_limit_depth(blk_opf_t opf, struct blk_mq_alloc_data *data) * limit depth so that it cannot consume more * available requests and thus starve other entities. */ - if (bfqq && bfqq_request_over_limit(bfqq, limit)) { + if (bfqq_request_over_limit(bfqd, bic, opf, act_idx, limit)) { depth = 1; break; } @@ -5434,8 +5445,6 @@ void bfq_put_cooperator(struct bfq_queue *bfqq) bfq_put_queue(__bfqq); __bfqq = next; } - - bfq_release_process_ref(bfqq->bfqd, bfqq); } static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq) @@ -5448,6 +5457,8 @@ static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq) bfq_log_bfqq(bfqd, bfqq, "exit_bfqq: %p, %d", bfqq, bfqq->ref); bfq_put_cooperator(bfqq); + + bfq_release_process_ref(bfqd, bfqq); } static void bfq_exit_icq_bfqq(struct bfq_io_cq *bic, bool is_sync, @@ -6734,6 +6745,8 @@ bfq_split_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq) bic_set_bfqq(bic, NULL, true, bfqq->actuator_idx); bfq_put_cooperator(bfqq); + + bfq_release_process_ref(bfqq->bfqd, bfqq); return NULL; } diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 88e3ad73c38549..2a4bd661169207 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -199,7 +199,7 @@ EXPORT_SYMBOL(bio_integrity_add_page); static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, int nr_vecs, unsigned int len, - unsigned int direction, u32 seed) + unsigned int direction) { bool write = direction == ITER_SOURCE; struct bio_integrity_payload *bip; @@ -247,7 +247,6 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, } bip->bip_flags |= BIP_COPY_USER; - bip->bip_iter.bi_sector = seed; bip->bip_vcnt = nr_vecs; return 0; free_bip: @@ -258,7 +257,7 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, } static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec, - int nr_vecs, unsigned int len, u32 seed) + int nr_vecs, unsigned int len) { struct bio_integrity_payload *bip; @@ -267,7 +266,6 @@ static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec, return PTR_ERR(bip); memcpy(bip->bip_vec, bvec, nr_vecs * sizeof(*bvec)); - bip->bip_iter.bi_sector = seed; bip->bip_iter.bi_size = len; bip->bip_vcnt = nr_vecs; return 0; @@ -303,8 +301,7 @@ static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages, return nr_bvecs; } -int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes, - u32 seed) +int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes) { struct request_queue *q = bdev_get_queue(bio->bi_bdev); unsigned int align = blk_lim_dma_alignment_and_pad(&q->limits); @@ -350,9 +347,9 @@ int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes, if (copy) ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes, - direction, seed); + direction); else - ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes, seed); + ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes); if (ret) goto release_pages; if (bvec != stack_vec) diff --git a/block/bio.c b/block/bio.c index ac4d77c889322d..d5bdc31d88d327 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1064,39 +1064,6 @@ int bio_add_pc_page(struct request_queue *q, struct bio *bio, } EXPORT_SYMBOL(bio_add_pc_page); -/** - * bio_add_zone_append_page - attempt to add page to zone-append bio - * @bio: destination bio - * @page: page to add - * @len: vec entry length - * @offset: vec entry offset - * - * Attempt to add a page to the bio_vec maplist of a bio that will be submitted - * for a zone-append request. This can fail for a number of reasons, such as the - * bio being full or the target block device is not a zoned block device or - * other limitations of the target block device. The target block device must - * allow bio's up to PAGE_SIZE, so it is always possible to add a single page - * to an empty bio. - * - * Returns: number of bytes added to the bio, or 0 in case of a failure. - */ -int bio_add_zone_append_page(struct bio *bio, struct page *page, - unsigned int len, unsigned int offset) -{ - struct request_queue *q = bdev_get_queue(bio->bi_bdev); - bool same_page = false; - - if (WARN_ON_ONCE(bio_op(bio) != REQ_OP_ZONE_APPEND)) - return 0; - - if (WARN_ON_ONCE(!bdev_is_zoned(bio->bi_bdev))) - return 0; - - return bio_add_hw_page(q, bio, page, len, offset, - queue_max_zone_append_sectors(q), &same_page); -} -EXPORT_SYMBOL_GPL(bio_add_zone_append_page); - /** * __bio_add_page - add page(s) to a bio in a new segment * @bio: destination bio @@ -1204,23 +1171,14 @@ void __bio_release_pages(struct bio *bio, bool mark_dirty) } EXPORT_SYMBOL_GPL(__bio_release_pages); -void bio_iov_bvec_set(struct bio *bio, struct iov_iter *iter) +void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter) { - size_t size = iov_iter_count(iter); - WARN_ON_ONCE(bio->bi_max_vecs); - if (bio_op(bio) == REQ_OP_ZONE_APPEND) { - struct request_queue *q = bdev_get_queue(bio->bi_bdev); - size_t max_sectors = queue_max_zone_append_sectors(q); - - size = min(size, max_sectors << SECTOR_SHIFT); - } - bio->bi_vcnt = iter->nr_segs; bio->bi_io_vec = (struct bio_vec *)iter->bvec; bio->bi_iter.bi_bvec_done = iter->iov_offset; - bio->bi_iter.bi_size = size; + bio->bi_iter.bi_size = iov_iter_count(iter); bio_set_flag(bio, BIO_CLONED); } @@ -1245,20 +1203,6 @@ static int bio_iov_add_folio(struct bio *bio, struct folio *folio, size_t len, return 0; } -static int bio_iov_add_zone_append_folio(struct bio *bio, struct folio *folio, - size_t len, size_t offset) -{ - struct request_queue *q = bdev_get_queue(bio->bi_bdev); - bool same_page = false; - - if (bio_add_hw_folio(q, bio, folio, len, offset, - queue_max_zone_append_sectors(q), &same_page) != len) - return -EINVAL; - if (same_page && bio_flagged(bio, BIO_PAGE_PINNED)) - unpin_user_folio(folio, 1); - return 0; -} - static unsigned int get_contig_folio_len(unsigned int *num_pages, struct page **pages, unsigned int i, struct folio *folio, size_t left, @@ -1365,14 +1309,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) len = get_contig_folio_len(&num_pages, pages, i, folio, left, offset); - if (bio_op(bio) == REQ_OP_ZONE_APPEND) { - ret = bio_iov_add_zone_append_folio(bio, folio, len, - folio_offset); - if (ret) - break; - } else - bio_iov_add_folio(bio, folio, len, folio_offset); - + bio_iov_add_folio(bio, folio, len, folio_offset); offset = 0; } @@ -1728,16 +1665,22 @@ struct bio *bio_split(struct bio *bio, int sectors, { struct bio *split; - BUG_ON(sectors <= 0); - BUG_ON(sectors >= bio_sectors(bio)); + if (WARN_ON_ONCE(sectors <= 0)) + return ERR_PTR(-EINVAL); + if (WARN_ON_ONCE(sectors >= bio_sectors(bio))) + return ERR_PTR(-EINVAL); /* Zone append commands cannot be split */ if (WARN_ON_ONCE(bio_op(bio) == REQ_OP_ZONE_APPEND)) - return NULL; + return ERR_PTR(-EINVAL); + + /* atomic writes cannot be split */ + if (bio->bi_opf & REQ_ATOMIC) + return ERR_PTR(-EINVAL); split = bio_alloc_clone(bio->bi_bdev, bio, gfp, bs); if (!split) - return NULL; + return ERR_PTR(-ENOMEM); split->bi_iter.bi_size = sectors << 9; diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index e68c725cf8d975..45a395862fbc88 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1324,10 +1324,14 @@ void blkcg_unpin_online(struct cgroup_subsys_state *blkcg_css) struct blkcg *blkcg = css_to_blkcg(blkcg_css); do { + struct blkcg *parent; + if (!refcount_dec_and_test(&blkcg->online_pin)) break; + + parent = blkcg_parent(blkcg); blkcg_destroy_blkgs(blkcg); - blkcg = blkcg_parent(blkcg); + blkcg = parent; } while (blkcg); } diff --git a/block/blk-core.c b/block/blk-core.c index bc5e8c5eaac9ff..666efe8fa20206 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -261,6 +261,8 @@ static void blk_free_queue(struct request_queue *q) blk_mq_release(q); ida_free(&blk_queue_ida, q->id); + lockdep_unregister_key(&q->io_lock_cls_key); + lockdep_unregister_key(&q->q_lock_cls_key); call_rcu(&q->rcu_head, blk_free_queue_rcu); } @@ -278,18 +280,20 @@ void blk_put_queue(struct request_queue *q) } EXPORT_SYMBOL(blk_put_queue); -void blk_queue_start_drain(struct request_queue *q) +bool blk_queue_start_drain(struct request_queue *q) { /* * When queue DYING flag is set, we need to block new req * entering queue, so we call blk_freeze_queue_start() to * prevent I/O from crossing blk_queue_enter(). */ - blk_freeze_queue_start(q); + bool freeze = __blk_freeze_queue_start(q, current); if (queue_is_mq(q)) blk_mq_wake_waiters(q); /* Make blk_queue_enter() reexamine the DYING flag. */ wake_up_all(&q->mq_freeze_wq); + + return freeze; } /** @@ -321,6 +325,8 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags) return -ENODEV; } + rwsem_acquire_read(&q->q_lockdep_map, 0, 0, _RET_IP_); + rwsem_release(&q->q_lockdep_map, _RET_IP_); return 0; } @@ -352,6 +358,8 @@ int __bio_queue_enter(struct request_queue *q, struct bio *bio) goto dead; } + rwsem_acquire_read(&q->io_lockdep_map, 0, 0, _RET_IP_); + rwsem_release(&q->io_lockdep_map, _RET_IP_); return 0; dead: bio_io_error(bio); @@ -441,6 +449,12 @@ struct request_queue *blk_alloc_queue(struct queue_limits *lim, int node_id) PERCPU_REF_INIT_ATOMIC, GFP_KERNEL); if (error) goto fail_stats; + lockdep_register_key(&q->io_lock_cls_key); + lockdep_register_key(&q->q_lock_cls_key); + lockdep_init_map(&q->io_lockdep_map, "&q->q_usage_counter(io)", + &q->io_lock_cls_key, 0); + lockdep_init_map(&q->q_lockdep_map, "&q->q_usage_counter(queue)", + &q->q_lock_cls_key, 0); q->nr_requests = BLKDEV_DEFAULT_RQ; @@ -593,7 +607,7 @@ static inline blk_status_t blk_check_zone_append(struct request_queue *q, return BLK_STS_IOERR; /* Make sure the BIO is small enough and will not get split */ - if (nr_sectors > queue_max_zone_append_sectors(q)) + if (nr_sectors > q->limits.max_zone_append_sectors) return BLK_STS_IOERR; bio->bi_opf |= REQ_NOMERGE; @@ -1106,8 +1120,8 @@ void blk_start_plug_nr_ios(struct blk_plug *plug, unsigned short nr_ios) return; plug->cur_ktime = 0; - plug->mq_list = NULL; - plug->cached_rq = NULL; + rq_list_init(&plug->mq_list); + rq_list_init(&plug->cached_rqs); plug->nr_ios = min_t(unsigned short, nr_ios, BLK_MAX_REQUEST_COUNT); plug->rq_count = 0; plug->multiple_queues = false; @@ -1203,7 +1217,7 @@ void __blk_flush_plug(struct blk_plug *plug, bool from_schedule) * queue for cached requests, we don't want a blocked task holding * up a queue freeze/quiesce event. */ - if (unlikely(!rq_list_empty(plug->cached_rq))) + if (unlikely(!rq_list_empty(&plug->cached_rqs))) blk_mq_free_plug_rqs(plug); plug->cur_ktime = 0; diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c index b1e7415f8439c4..29a205482617c8 100644 --- a/block/blk-crypto-fallback.c +++ b/block/blk-crypto-fallback.c @@ -226,7 +226,7 @@ static bool blk_crypto_fallback_split_bio_if_needed(struct bio **bio_ptr) split_bio = bio_split(bio, num_sectors, GFP_NOIO, &crypto_bio_split); - if (!split_bio) { + if (IS_ERR(split_bio)) { bio->bi_status = BLK_STS_RESOURCE; return false; } diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 83b696ba0cac31..b180cac61a9ddb 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -113,9 +113,9 @@ int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist) EXPORT_SYMBOL(blk_rq_map_integrity_sg); int blk_rq_integrity_map_user(struct request *rq, void __user *ubuf, - ssize_t bytes, u32 seed) + ssize_t bytes) { - int ret = bio_integrity_map_user(rq->bio, ubuf, bytes, seed); + int ret = bio_integrity_map_user(rq->bio, ubuf, bytes); if (ret) return ret; diff --git a/block/blk-ioc.c b/block/blk-ioc.c index 25dd4db11121bf..ce82770c72abad 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c @@ -32,13 +32,6 @@ static void get_io_context(struct io_context *ioc) atomic_long_inc(&ioc->refcount); } -static void icq_free_icq_rcu(struct rcu_head *head) -{ - struct io_cq *icq = container_of(head, struct io_cq, __rcu_head); - - kmem_cache_free(icq->__rcu_icq_cache, icq); -} - /* * Exit an icq. Called with ioc locked for blk-mq, and with both ioc * and queue locked for legacy. @@ -102,7 +95,7 @@ static void ioc_destroy_icq(struct io_cq *icq) */ icq->__rcu_icq_cache = et->icq_cache; icq->flags |= ICQ_DESTROYED; - call_rcu(&icq->__rcu_head, icq_free_icq_rcu); + kfree_rcu(icq, __rcu_head); } /* diff --git a/block/blk-iocost.c b/block/blk-iocost.c index 384aa15e8260bd..a5894ec9696e7e 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -1098,7 +1098,14 @@ static void __propagate_weights(struct ioc_gq *iocg, u32 active, u32 inuse, inuse = DIV64_U64_ROUND_UP(active * iocg->child_inuse_sum, iocg->child_active_sum); } else { - inuse = clamp_t(u32, inuse, 1, active); + /* + * It may be tempting to turn this into a clamp expression with + * a lower limit of 1 but active may be 0, which cannot be used + * as an upper limit in that situation. This expression allows + * active to clamp inuse unless it is 0, in which case inuse + * becomes 1. + */ + inuse = min(inuse, active) ?: 1; } iocg->last_inuse = iocg->inuse; diff --git a/block/blk-map.c b/block/blk-map.c index b5fd1d8574615e..894009b2d881be 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -574,7 +574,7 @@ static int blk_rq_map_user_bvec(struct request *rq, const struct iov_iter *iter) bio = blk_rq_map_bio_alloc(rq, 0, GFP_KERNEL); if (!bio) return -ENOMEM; - bio_iov_bvec_set(bio, (struct iov_iter *)iter); + bio_iov_bvec_set(bio, iter); /* check that the data layout matches the hardware restrictions */ ret = bio_split_rw_at(bio, lim, &nsegs, max_bytes); diff --git a/block/blk-merge.c b/block/blk-merge.c index ad763ec313b6ad..e01383c6e534b0 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -107,17 +107,18 @@ static unsigned int bio_allowed_max_sectors(const struct queue_limits *lim) static struct bio *bio_submit_split(struct bio *bio, int split_sectors) { - if (unlikely(split_sectors < 0)) { - bio->bi_status = errno_to_blk_status(split_sectors); - bio_endio(bio); - return NULL; - } + if (unlikely(split_sectors < 0)) + goto error; if (split_sectors) { struct bio *split; split = bio_split(bio, split_sectors, GFP_NOIO, &bio->bi_bdev->bd_disk->bio_split); + if (IS_ERR(split)) { + split_sectors = PTR_ERR(split); + goto error; + } split->bi_opf |= REQ_NOMERGE; blkcg_bio_issue_init(split); bio_chain(split, bio); @@ -128,6 +129,10 @@ static struct bio *bio_submit_split(struct bio *bio, int split_sectors) } return bio; +error: + bio->bi_status = errno_to_blk_status(split_sectors); + bio_endio(bio); + return NULL; } struct bio *bio_split_discard(struct bio *bio, const struct queue_limits *lim, @@ -166,17 +171,6 @@ struct bio *bio_split_discard(struct bio *bio, const struct queue_limits *lim, return bio_submit_split(bio, split_sectors); } -struct bio *bio_split_write_zeroes(struct bio *bio, - const struct queue_limits *lim, unsigned *nsegs) -{ - *nsegs = 0; - if (!lim->max_write_zeroes_sectors) - return bio; - if (bio_sectors(bio) <= lim->max_write_zeroes_sectors) - return bio; - return bio_submit_split(bio, lim->max_write_zeroes_sectors); -} - static inline unsigned int blk_boundary_sectors(const struct queue_limits *lim, bool is_atomic) { @@ -211,7 +205,9 @@ static inline unsigned get_max_io_size(struct bio *bio, * We ignore lim->max_sectors for atomic writes because it may less * than the actual bio size, which we cannot tolerate. */ - if (is_atomic) + if (bio_op(bio) == REQ_OP_WRITE_ZEROES) + max_sectors = lim->max_write_zeroes_sectors; + else if (is_atomic) max_sectors = lim->atomic_write_max_sectors; else max_sectors = lim->max_sectors; @@ -296,6 +292,14 @@ static bool bvec_split_segs(const struct queue_limits *lim, return len > 0 || bv->bv_len > max_len; } +static unsigned int bio_split_alignment(struct bio *bio, + const struct queue_limits *lim) +{ + if (op_is_write(bio_op(bio)) && lim->zone_write_granularity) + return lim->zone_write_granularity; + return lim->logical_block_size; +} + /** * bio_split_rw_at - check if and where to split a read/write bio * @bio: [in] bio to be split @@ -358,7 +362,7 @@ int bio_split_rw_at(struct bio *bio, const struct queue_limits *lim, * split size so that each bio is properly block size aligned, even if * we do not use the full hardware limits. */ - bytes = ALIGN_DOWN(bytes, lim->logical_block_size); + bytes = ALIGN_DOWN(bytes, bio_split_alignment(bio, lim)); /* * Bio splitting may cause subtle trouble such as hang when doing sync @@ -388,16 +392,35 @@ struct bio *bio_split_rw(struct bio *bio, const struct queue_limits *lim, struct bio *bio_split_zone_append(struct bio *bio, const struct queue_limits *lim, unsigned *nr_segs) { - unsigned int max_sectors = queue_limits_max_zone_append_sectors(lim); int split_sectors; split_sectors = bio_split_rw_at(bio, lim, nr_segs, - max_sectors << SECTOR_SHIFT); + lim->max_zone_append_sectors << SECTOR_SHIFT); if (WARN_ON_ONCE(split_sectors > 0)) split_sectors = -EINVAL; return bio_submit_split(bio, split_sectors); } +struct bio *bio_split_write_zeroes(struct bio *bio, + const struct queue_limits *lim, unsigned *nsegs) +{ + unsigned int max_sectors = get_max_io_size(bio, lim); + + *nsegs = 0; + + /* + * An unset limit should normally not happen, as bio submission is keyed + * off having a non-zero limit. But SCSI can clear the limit in the + * I/O completion handler, and we can race and see this. Splitting to a + * zero limit obviously doesn't make sense, so band-aid it here. + */ + if (!max_sectors) + return bio; + if (bio_sectors(bio) <= max_sectors) + return bio; + return bio_submit_split(bio, max_sectors); +} + /** * bio_split_to_limits - split a bio to fit the queue limits * @bio: bio to be split @@ -411,10 +434,9 @@ struct bio *bio_split_zone_append(struct bio *bio, */ struct bio *bio_split_to_limits(struct bio *bio) { - const struct queue_limits *lim = &bdev_get_queue(bio->bi_bdev)->limits; unsigned int nr_segs; - return __bio_split_to_limits(bio, lim, &nr_segs); + return __bio_split_to_limits(bio, bdev_limits(bio->bi_bdev), &nr_segs); } EXPORT_SYMBOL(bio_split_to_limits); @@ -797,7 +819,7 @@ static inline void blk_update_mixed_merge(struct request *req, static void blk_account_io_merge_request(struct request *req) { - if (blk_do_io_stat(req)) { + if (req->rq_flags & RQF_IO_STAT) { part_stat_lock(); part_stat_inc(req->part, merges[op_stat_group(req_op(req))]); part_stat_local_dec(req->part, @@ -842,16 +864,10 @@ static struct request *attempt_merge(struct request_queue *q, if (req_op(req) != req_op(next)) return NULL; - if (rq_data_dir(req) != rq_data_dir(next)) + if (req->bio->bi_write_hint != next->bio->bi_write_hint) return NULL; - - /* Don't merge requests with different write hints. */ - if (req->write_hint != next->write_hint) + if (req->bio->bi_ioprio != next->bio->bi_ioprio) return NULL; - - if (req->ioprio != next->ioprio) - return NULL; - if (!blk_atomic_write_mergeable_rqs(req, next)) return NULL; @@ -963,29 +979,16 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) if (req_op(rq) != bio_op(bio)) return false; - /* different data direction or already started, don't merge */ - if (bio_data_dir(bio) != rq_data_dir(rq)) - return false; - - /* don't merge across cgroup boundaries */ if (!blk_cgroup_mergeable(rq, bio)) return false; - - /* only merge integrity protected bio into ditto rq */ if (blk_integrity_merge_bio(rq->q, rq, bio) == false) return false; - - /* Only merge if the crypt contexts are compatible */ if (!bio_crypt_rq_ctx_compatible(rq, bio)) return false; - - /* Don't merge requests with different write hints. */ - if (rq->write_hint != bio->bi_write_hint) + if (rq->bio->bi_write_hint != bio->bi_write_hint) return false; - - if (rq->ioprio != bio_prio(bio)) + if (rq->bio->bi_ioprio != bio->bi_ioprio) return false; - if (blk_atomic_write_mergeable_rq_bio(rq, bio) == false) return false; @@ -1005,12 +1008,11 @@ enum elv_merge blk_try_merge(struct request *rq, struct bio *bio) static void blk_account_io_merge_bio(struct request *req) { - if (!blk_do_io_stat(req)) - return; - - part_stat_lock(); - part_stat_inc(req->part, merges[op_stat_group(req_op(req))]); - part_stat_unlock(); + if (req->rq_flags & RQF_IO_STAT) { + part_stat_lock(); + part_stat_inc(req->part, merges[op_stat_group(req_op(req))]); + part_stat_unlock(); + } } enum bio_merge_status bio_attempt_back_merge(struct request *req, @@ -1156,7 +1158,7 @@ bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio, struct blk_plug *plug = current->plug; struct request *rq; - if (!plug || rq_list_empty(plug->mq_list)) + if (!plug || rq_list_empty(&plug->mq_list)) return false; rq_list_for_each(&plug->mq_list, rq) { diff --git a/block/blk-mq.c b/block/blk-mq.c index cf626e061dd774..8ac19d4ae3c0ae 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -43,6 +43,7 @@ static DEFINE_PER_CPU(struct llist_head, blk_cpu_done); static DEFINE_PER_CPU(call_single_data_t, blk_cpu_csd); +static DEFINE_MUTEX(blk_mq_cpuhp_lock); static void blk_mq_insert_request(struct request *rq, blk_insert_t flags); static void blk_mq_request_bypass_insert(struct request *rq, @@ -92,7 +93,7 @@ static bool blk_mq_check_inflight(struct request *rq, void *priv) { struct mq_inflight *mi = priv; - if (rq->part && blk_do_io_stat(rq) && + if (rq->rq_flags & RQF_IO_STAT && (!bdev_is_partition(mi->part) || rq->part == mi->part) && blk_mq_rq_state(rq) == MQ_RQ_IN_FLIGHT) mi->inflight[rq_data_dir(rq)]++; @@ -120,9 +121,59 @@ void blk_mq_in_flight_rw(struct request_queue *q, struct block_device *part, inflight[1] = mi.inflight[1]; } -void blk_freeze_queue_start(struct request_queue *q) +#ifdef CONFIG_LOCKDEP +static bool blk_freeze_set_owner(struct request_queue *q, + struct task_struct *owner) +{ + if (!owner) + return false; + + if (!q->mq_freeze_depth) { + q->mq_freeze_owner = owner; + q->mq_freeze_owner_depth = 1; + return true; + } + + if (owner == q->mq_freeze_owner) + q->mq_freeze_owner_depth += 1; + return false; +} + +/* verify the last unfreeze in owner context */ +static bool blk_unfreeze_check_owner(struct request_queue *q) +{ + if (!q->mq_freeze_owner) + return false; + if (q->mq_freeze_owner != current) + return false; + if (--q->mq_freeze_owner_depth == 0) { + q->mq_freeze_owner = NULL; + return true; + } + return false; +} + +#else + +static bool blk_freeze_set_owner(struct request_queue *q, + struct task_struct *owner) +{ + return false; +} + +static bool blk_unfreeze_check_owner(struct request_queue *q) +{ + return false; +} +#endif + +bool __blk_freeze_queue_start(struct request_queue *q, + struct task_struct *owner) { + bool freeze; + mutex_lock(&q->mq_freeze_lock); + freeze = blk_freeze_set_owner(q, owner); if (++q->mq_freeze_depth == 1) { percpu_ref_kill(&q->q_usage_counter); mutex_unlock(&q->mq_freeze_lock); @@ -131,6 +182,14 @@ void blk_freeze_queue_start(struct request_queue *q) } else { mutex_unlock(&q->mq_freeze_lock); } + + return freeze; +} + +void blk_freeze_queue_start(struct request_queue *q) +{ + if (__blk_freeze_queue_start(q, current)) + blk_freeze_acquire_lock(q, false, false); } EXPORT_SYMBOL_GPL(blk_freeze_queue_start); @@ -149,35 +208,17 @@ int blk_mq_freeze_queue_wait_timeout(struct request_queue *q, } EXPORT_SYMBOL_GPL(blk_mq_freeze_queue_wait_timeout); -/* - * Guarantee no request is in use, so we can change any data structure of - * the queue afterward. - */ -void blk_freeze_queue(struct request_queue *q) +void blk_mq_freeze_queue(struct request_queue *q) { - /* - * In the !blk_mq case we are only calling this to kill the - * q_usage_counter, otherwise this increases the freeze depth - * and waits for it to return to zero. For this reason there is - * no blk_unfreeze_queue(), and blk_freeze_queue() is not - * exported to drivers as the only user for unfreeze is blk_mq. - */ blk_freeze_queue_start(q); blk_mq_freeze_queue_wait(q); } - -void blk_mq_freeze_queue(struct request_queue *q) -{ - /* - * ...just an alias to keep freeze and unfreeze actions balanced - * in the blk_mq_* namespace - */ - blk_freeze_queue(q); -} EXPORT_SYMBOL_GPL(blk_mq_freeze_queue); -void __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic) +bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic) { + bool unfreeze; + mutex_lock(&q->mq_freeze_lock); if (force_atomic) q->q_usage_counter.data->force_atomic = true; @@ -187,15 +228,39 @@ void __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic) percpu_ref_resurrect(&q->q_usage_counter); wake_up_all(&q->mq_freeze_wq); } + unfreeze = blk_unfreeze_check_owner(q); mutex_unlock(&q->mq_freeze_lock); + + return unfreeze; } void blk_mq_unfreeze_queue(struct request_queue *q) { - __blk_mq_unfreeze_queue(q, false); + if (__blk_mq_unfreeze_queue(q, false)) + blk_unfreeze_release_lock(q, false, false); } EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue); +/* + * non_owner variant of blk_freeze_queue_start + * + * Unlike blk_freeze_queue_start, the queue doesn't need to be unfrozen + * by the same task. This is fragile and should not be used if at all + * possible. + */ +void blk_freeze_queue_start_non_owner(struct request_queue *q) +{ + __blk_freeze_queue_start(q, NULL); +} +EXPORT_SYMBOL_GPL(blk_freeze_queue_start_non_owner); + +/* non_owner variant of blk_mq_unfreeze_queue */ +void blk_mq_unfreeze_queue_non_owner(struct request_queue *q) +{ + __blk_mq_unfreeze_queue(q, false); +} +EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue_non_owner); + /* * FIXME: replace the scsi_internal_device_*block_nowait() calls in the * mpt3sas driver such that this function can be removed. @@ -283,8 +348,9 @@ void blk_mq_quiesce_tagset(struct blk_mq_tag_set *set) if (!blk_queue_skip_tagset_quiesce(q)) blk_mq_quiesce_queue_nowait(q); } - blk_mq_wait_quiesce_done(set); mutex_unlock(&set->tag_list_lock); + + blk_mq_wait_quiesce_done(set); } EXPORT_SYMBOL_GPL(blk_mq_quiesce_tagset); @@ -323,7 +389,6 @@ void blk_rq_init(struct request_queue *q, struct request *rq) rq->tag = BLK_MQ_NO_TAG; rq->internal_tag = BLK_MQ_NO_TAG; rq->start_time_ns = blk_time_get_ns(); - rq->part = NULL; blk_crypto_rq_set_defaults(rq); } EXPORT_SYMBOL(blk_rq_init); @@ -331,14 +396,9 @@ EXPORT_SYMBOL(blk_rq_init); /* Set start and alloc time when the allocated request is actually used */ static inline void blk_mq_rq_time_init(struct request *rq, u64 alloc_time_ns) { - if (blk_mq_need_time_stamp(rq)) - rq->start_time_ns = blk_time_get_ns(); - else - rq->start_time_ns = 0; - #ifdef CONFIG_BLK_RQ_ALLOC_TIME if (blk_queue_rq_alloc_time(rq->q)) - rq->alloc_time_ns = alloc_time_ns ?: rq->start_time_ns; + rq->alloc_time_ns = alloc_time_ns; else rq->alloc_time_ns = 0; #endif @@ -359,8 +419,6 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data, if (data->flags & BLK_MQ_REQ_PM) data->rq_flags |= RQF_PM; - if (blk_queue_io_stat(q)) - data->rq_flags |= RQF_IO_STAT; rq->rq_flags = data->rq_flags; if (data->rq_flags & RQF_SCHED_TAGS) { @@ -420,7 +478,7 @@ __blk_mq_alloc_requests_batch(struct blk_mq_alloc_data *data) prefetch(tags->static_rqs[tag]); tag_mask &= ~(1UL << i); rq = blk_mq_rq_ctx_init(data, tags, tag); - rq_list_add(data->cached_rq, rq); + rq_list_add_head(data->cached_rqs, rq); nr++; } if (!(data->rq_flags & RQF_SCHED_TAGS)) @@ -429,7 +487,7 @@ __blk_mq_alloc_requests_batch(struct blk_mq_alloc_data *data) percpu_ref_get_many(&data->q->q_usage_counter, nr - 1); data->nr_tags -= nr; - return rq_list_pop(data->cached_rq); + return rq_list_pop(data->cached_rqs); } static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data) @@ -526,7 +584,7 @@ static struct request *blk_mq_rq_cache_fill(struct request_queue *q, .flags = flags, .cmd_flags = opf, .nr_tags = plug->nr_ios, - .cached_rq = &plug->cached_rq, + .cached_rqs = &plug->cached_rqs, }; struct request *rq; @@ -551,14 +609,14 @@ static struct request *blk_mq_alloc_cached_request(struct request_queue *q, if (!plug) return NULL; - if (rq_list_empty(plug->cached_rq)) { + if (rq_list_empty(&plug->cached_rqs)) { if (plug->nr_ios == 1) return NULL; rq = blk_mq_rq_cache_fill(q, plug, opf, flags); if (!rq) return NULL; } else { - rq = rq_list_peek(&plug->cached_rq); + rq = rq_list_peek(&plug->cached_rqs); if (!rq || rq->q != q) return NULL; @@ -567,8 +625,8 @@ static struct request *blk_mq_alloc_cached_request(struct request_queue *q, if (op_is_flush(rq->cmd_flags) != op_is_flush(opf)) return NULL; - plug->cached_rq = rq_list_next(rq); - blk_mq_rq_time_init(rq, 0); + rq_list_pop(&plug->cached_rqs); + blk_mq_rq_time_init(rq, blk_time_get_ns()); } rq->cmd_flags = opf; @@ -744,7 +802,7 @@ void blk_mq_free_plug_rqs(struct blk_plug *plug) { struct request *rq; - while ((rq = rq_list_pop(&plug->cached_rq)) != NULL) + while ((rq = rq_list_pop(&plug->cached_rqs)) != NULL) blk_mq_free_request(rq); } @@ -764,7 +822,7 @@ EXPORT_SYMBOL(blk_dump_rq_flags); static void blk_account_io_completion(struct request *req, unsigned int bytes) { - if (req->part && blk_do_io_stat(req)) { + if (req->rq_flags & RQF_IO_STAT) { const int sgrp = op_stat_group(req_op(req)); part_stat_lock(); @@ -784,7 +842,7 @@ static void blk_print_req_error(struct request *req, blk_status_t status) blk_op_str(req_op(req)), (__force u32)(req->cmd_flags & ~REQ_OP_MASK), req->nr_phys_segments, - IOPRIO_PRIO_CLASS(req->ioprio)); + IOPRIO_PRIO_CLASS(req_get_ioprio(req))); } /* @@ -982,8 +1040,7 @@ static inline void blk_account_io_done(struct request *req, u64 now) * normal IO on queueing nor completion. Accounting the * containing request is enough. */ - if (blk_do_io_stat(req) && req->part && - !(req->rq_flags & RQF_FLUSH_SEQ)) { + if ((req->rq_flags & (RQF_IO_STAT|RQF_FLUSH_SEQ)) == RQF_IO_STAT) { const int sgrp = op_stat_group(req_op(req)); part_stat_lock(); @@ -996,28 +1053,63 @@ static inline void blk_account_io_done(struct request *req, u64 now) } } +static inline bool blk_rq_passthrough_stats(struct request *req) +{ + struct bio *bio = req->bio; + + if (!blk_queue_passthrough_stat(req->q)) + return false; + + /* Requests without a bio do not transfer data. */ + if (!bio) + return false; + + /* + * Stats are accumulated in the bdev, so must have one attached to a + * bio to track stats. Most drivers do not set the bdev for passthrough + * requests, but nvme is one that will set it. + */ + if (!bio->bi_bdev) + return false; + + /* + * We don't know what a passthrough command does, but we know the + * payload size and data direction. Ensuring the size is aligned to the + * block size filters out most commands with payloads that don't + * represent sector access. + */ + if (blk_rq_bytes(req) & (bdev_logical_block_size(bio->bi_bdev) - 1)) + return false; + return true; +} + static inline void blk_account_io_start(struct request *req) { trace_block_io_start(req); - if (blk_do_io_stat(req)) { - /* - * All non-passthrough requests are created from a bio with one - * exception: when a flush command that is part of a flush sequence - * generated by the state machine in blk-flush.c is cloned onto the - * lower device by dm-multipath we can get here without a bio. - */ - if (req->bio) - req->part = req->bio->bi_bdev; - else - req->part = req->q->disk->part0; + if (!blk_queue_io_stat(req->q)) + return; + if (blk_rq_is_passthrough(req) && !blk_rq_passthrough_stats(req)) + return; - part_stat_lock(); - update_io_ticks(req->part, jiffies, false); - part_stat_local_inc(req->part, - in_flight[op_is_write(req_op(req))]); - part_stat_unlock(); - } + req->rq_flags |= RQF_IO_STAT; + req->start_time_ns = blk_time_get_ns(); + + /* + * All non-passthrough requests are created from a bio with one + * exception: when a flush command that is part of a flush sequence + * generated by the state machine in blk-flush.c is cloned onto the + * lower device by dm-multipath we can get here without a bio. + */ + if (req->bio) + req->part = req->bio->bi_bdev; + else + req->part = req->q->disk->part0; + + part_stat_lock(); + update_io_ticks(req->part, jiffies, false); + part_stat_local_inc(req->part, in_flight[op_is_write(req_op(req))]); + part_stat_unlock(); } static inline void __blk_mq_end_request_acct(struct request *rq, u64 now) @@ -1300,8 +1392,7 @@ static void blk_add_rq_to_plug(struct blk_plug *plug, struct request *rq) */ if (!plug->has_elevator && (rq->rq_flags & RQF_SCHED_TAGS)) plug->has_elevator = true; - rq->rq_next = NULL; - rq_list_add(&plug->mq_list, rq); + rq_list_add_tail(&plug->mq_list, rq); plug->rq_count++; } @@ -1453,19 +1544,17 @@ static void blk_mq_requeue_work(struct work_struct *work) while (!list_empty(&rq_list)) { rq = list_entry(rq_list.next, struct request, queuelist); + list_del_init(&rq->queuelist); /* - * If RQF_DONTPREP ist set, the request has been started by the + * If RQF_DONTPREP is set, the request has been started by the * driver already and might have driver-specific data allocated * already. Insert it into the hctx dispatch list to avoid * block layer merges for the request. */ - if (rq->rq_flags & RQF_DONTPREP) { - list_del_init(&rq->queuelist); + if (rq->rq_flags & RQF_DONTPREP) blk_mq_request_bypass_insert(rq, 0); - } else { - list_del_init(&rq->queuelist); + else blk_mq_insert_request(rq, BLK_MQ_INSERT_AT_HEAD); - } } while (!list_empty(&flush_list)) { @@ -1698,7 +1787,6 @@ void blk_mq_flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list) sbitmap_for_each_set(&hctx->ctx_map, flush_busy_ctx, &data); } -EXPORT_SYMBOL_GPL(blk_mq_flush_busy_ctxs); struct dispatch_rq_data { struct blk_mq_hw_ctx *hctx; @@ -2200,6 +2288,24 @@ void blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs) } EXPORT_SYMBOL(blk_mq_delay_run_hw_queue); +static inline bool blk_mq_hw_queue_need_run(struct blk_mq_hw_ctx *hctx) +{ + bool need_run; + + /* + * When queue is quiesced, we may be switching io scheduler, or + * updating nr_hw_queues, or other things, and we can't run queue + * any more, even blk_mq_hctx_has_pending() can't be called safely. + * + * And queue will be rerun in blk_mq_unquiesce_queue() if it is + * quiesced. + */ + __blk_mq_run_dispatch_ops(hctx->queue, false, + need_run = !blk_queue_quiesced(hctx->queue) && + blk_mq_hctx_has_pending(hctx)); + return need_run; +} + /** * blk_mq_run_hw_queue - Start to run a hardware queue. * @hctx: Pointer to the hardware queue to run. @@ -2220,20 +2326,23 @@ void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async) might_sleep_if(!async && hctx->flags & BLK_MQ_F_BLOCKING); - /* - * When queue is quiesced, we may be switching io scheduler, or - * updating nr_hw_queues, or other things, and we can't run queue - * any more, even __blk_mq_hctx_has_pending() can't be called safely. - * - * And queue will be rerun in blk_mq_unquiesce_queue() if it is - * quiesced. - */ - __blk_mq_run_dispatch_ops(hctx->queue, false, - need_run = !blk_queue_quiesced(hctx->queue) && - blk_mq_hctx_has_pending(hctx)); + need_run = blk_mq_hw_queue_need_run(hctx); + if (!need_run) { + unsigned long flags; - if (!need_run) - return; + /* + * Synchronize with blk_mq_unquiesce_queue(), because we check + * if hw queue is quiesced locklessly above, we need the use + * ->queue_lock to make sure we see the up-to-date status to + * not miss rerunning the hw queue. + */ + spin_lock_irqsave(&hctx->queue->queue_lock, flags); + need_run = blk_mq_hw_queue_need_run(hctx); + spin_unlock_irqrestore(&hctx->queue->queue_lock, flags); + + if (!need_run) + return; + } if (async || !cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask)) { blk_mq_delay_run_hw_queue(hctx, 0); @@ -2390,6 +2499,12 @@ void blk_mq_start_stopped_hw_queue(struct blk_mq_hw_ctx *hctx, bool async) return; clear_bit(BLK_MQ_S_STOPPED, &hctx->state); + /* + * Pairs with the smp_mb() in blk_mq_hctx_stopped() to order the + * clearing of BLK_MQ_S_STOPPED above and the checking of dispatch + * list in the subsequent routine. + */ + smp_mb__after_atomic(); blk_mq_run_hw_queue(hctx, async); } EXPORT_SYMBOL_GPL(blk_mq_start_stopped_hw_queue); @@ -2542,7 +2657,6 @@ static void blk_mq_bio_to_request(struct request *rq, struct bio *bio, rq->cmd_flags |= REQ_FAILFAST_MASK; rq->__sector = bio->bi_iter.bi_sector; - rq->write_hint = bio->bi_write_hint; blk_rq_bio_prep(rq, bio, nr_segs); if (bio_integrity(bio)) rq->nr_integrity_segments = blk_rq_count_integrity_sg(rq->q, @@ -2620,6 +2734,7 @@ static void blk_mq_try_issue_directly(struct blk_mq_hw_ctx *hctx, if (blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(rq->q)) { blk_mq_insert_request(rq, 0); + blk_mq_run_hw_queue(hctx, false); return; } @@ -2650,6 +2765,7 @@ static blk_status_t blk_mq_request_issue_directly(struct request *rq, bool last) if (blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(rq->q)) { blk_mq_insert_request(rq, 0); + blk_mq_run_hw_queue(hctx, false); return BLK_STS_OK; } @@ -2666,7 +2782,7 @@ static void blk_mq_plug_issue_direct(struct blk_plug *plug) blk_status_t ret = BLK_STS_OK; while ((rq = rq_list_pop(&plug->mq_list))) { - bool last = rq_list_empty(plug->mq_list); + bool last = rq_list_empty(&plug->mq_list); if (hctx != rq->mq_hctx) { if (hctx) { @@ -2709,8 +2825,7 @@ static void blk_mq_dispatch_plug_list(struct blk_plug *plug, bool from_sched) { struct blk_mq_hw_ctx *this_hctx = NULL; struct blk_mq_ctx *this_ctx = NULL; - struct request *requeue_list = NULL; - struct request **requeue_lastp = &requeue_list; + struct rq_list requeue_list = {}; unsigned int depth = 0; bool is_passthrough = false; LIST_HEAD(list); @@ -2724,12 +2839,12 @@ static void blk_mq_dispatch_plug_list(struct blk_plug *plug, bool from_sched) is_passthrough = blk_rq_is_passthrough(rq); } else if (this_hctx != rq->mq_hctx || this_ctx != rq->mq_ctx || is_passthrough != blk_rq_is_passthrough(rq)) { - rq_list_add_tail(&requeue_lastp, rq); + rq_list_add_tail(&requeue_list, rq); continue; } - list_add(&rq->queuelist, &list); + list_add_tail(&rq->queuelist, &list); depth++; - } while (!rq_list_empty(plug->mq_list)); + } while (!rq_list_empty(&plug->mq_list)); plug->mq_list = requeue_list; trace_block_unplug(this_hctx->queue, depth, !from_sched); @@ -2784,19 +2899,19 @@ void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule) if (q->mq_ops->queue_rqs) { blk_mq_run_dispatch_ops(q, __blk_mq_flush_plug_list(q, plug)); - if (rq_list_empty(plug->mq_list)) + if (rq_list_empty(&plug->mq_list)) return; } blk_mq_run_dispatch_ops(q, blk_mq_plug_issue_direct(plug)); - if (rq_list_empty(plug->mq_list)) + if (rq_list_empty(&plug->mq_list)) return; } do { blk_mq_dispatch_plug_list(plug, from_schedule); - } while (!rq_list_empty(plug->mq_list)); + } while (!rq_list_empty(&plug->mq_list)); } static void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx, @@ -2861,7 +2976,7 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q, if (plug) { data.nr_tags = plug->nr_ios; plug->nr_ios = 1; - data.cached_rq = &plug->cached_rq; + data.cached_rqs = &plug->cached_rqs; } rq = __blk_mq_alloc_requests(&data); @@ -2884,7 +2999,7 @@ static struct request *blk_mq_peek_cached_request(struct blk_plug *plug, if (!plug) return NULL; - rq = rq_list_peek(&plug->cached_rq); + rq = rq_list_peek(&plug->cached_rqs); if (!rq || rq->q != q) return NULL; if (type != rq->mq_hctx->type && @@ -2898,17 +3013,17 @@ static struct request *blk_mq_peek_cached_request(struct blk_plug *plug, static void blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug, struct bio *bio) { - WARN_ON_ONCE(rq_list_peek(&plug->cached_rq) != rq); + if (rq_list_pop(&plug->cached_rqs) != rq) + WARN_ON_ONCE(1); /* * If any qos ->throttle() end up blocking, we will have flushed the * plug and hence killed the cached_rq list as well. Pop this entry * before we throttle. */ - plug->cached_rq = rq_list_next(rq); rq_qos_throttle(rq->q, bio); - blk_mq_rq_time_init(rq, 0); + blk_mq_rq_time_init(rq, blk_time_get_ns()); rq->cmd_flags = bio->bi_opf; INIT_LIST_HEAD(&rq->queuelist); } @@ -3156,19 +3271,21 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src, int (*bio_ctr)(struct bio *, struct bio *, void *), void *data) { - struct bio *bio, *bio_src; + struct bio *bio_src; if (!bs) bs = &fs_bio_set; __rq_for_each_bio(bio_src, rq_src) { - bio = bio_alloc_clone(rq->q->disk->part0, bio_src, gfp_mask, - bs); + struct bio *bio = bio_alloc_clone(rq->q->disk->part0, bio_src, + gfp_mask, bs); if (!bio) goto free_and_out; - if (bio_ctr && bio_ctr(bio, bio_src, data)) + if (bio_ctr && bio_ctr(bio, bio_src, data)) { + bio_put(bio); goto free_and_out; + } if (rq->bio) { rq->biotail->bi_next = bio; @@ -3176,7 +3293,6 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src, } else { rq->bio = rq->biotail = bio; } - bio = NULL; } /* Copy attributes of the original request to the clone request. */ @@ -3187,8 +3303,6 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src, rq->special_vec = rq_src->special_vec; } rq->nr_phys_segments = rq_src->nr_phys_segments; - rq->ioprio = rq_src->ioprio; - rq->write_hint = rq_src->write_hint; if (rq->bio && blk_crypto_rq_bio_prep(rq, rq->bio, gfp_mask) < 0) goto free_and_out; @@ -3196,8 +3310,6 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src, return 0; free_and_out: - if (bio) - bio_put(bio); blk_rq_unprep_clone(rq); return -ENOMEM; @@ -3626,13 +3738,91 @@ static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node) return 0; } -static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx) +static void __blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx) { - if (!(hctx->flags & BLK_MQ_F_STACKING)) + lockdep_assert_held(&blk_mq_cpuhp_lock); + + if (!(hctx->flags & BLK_MQ_F_STACKING) && + !hlist_unhashed(&hctx->cpuhp_online)) { cpuhp_state_remove_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE, &hctx->cpuhp_online); - cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD, - &hctx->cpuhp_dead); + INIT_HLIST_NODE(&hctx->cpuhp_online); + } + + if (!hlist_unhashed(&hctx->cpuhp_dead)) { + cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD, + &hctx->cpuhp_dead); + INIT_HLIST_NODE(&hctx->cpuhp_dead); + } +} + +static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx) +{ + mutex_lock(&blk_mq_cpuhp_lock); + __blk_mq_remove_cpuhp(hctx); + mutex_unlock(&blk_mq_cpuhp_lock); +} + +static void __blk_mq_add_cpuhp(struct blk_mq_hw_ctx *hctx) +{ + lockdep_assert_held(&blk_mq_cpuhp_lock); + + if (!(hctx->flags & BLK_MQ_F_STACKING) && + hlist_unhashed(&hctx->cpuhp_online)) + cpuhp_state_add_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE, + &hctx->cpuhp_online); + + if (hlist_unhashed(&hctx->cpuhp_dead)) + cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, + &hctx->cpuhp_dead); +} + +static void __blk_mq_remove_cpuhp_list(struct list_head *head) +{ + struct blk_mq_hw_ctx *hctx; + + lockdep_assert_held(&blk_mq_cpuhp_lock); + + list_for_each_entry(hctx, head, hctx_list) + __blk_mq_remove_cpuhp(hctx); +} + +/* + * Unregister cpuhp callbacks from exited hw queues + * + * Safe to call if this `request_queue` is live + */ +static void blk_mq_remove_hw_queues_cpuhp(struct request_queue *q) +{ + LIST_HEAD(hctx_list); + + spin_lock(&q->unused_hctx_lock); + list_splice_init(&q->unused_hctx_list, &hctx_list); + spin_unlock(&q->unused_hctx_lock); + + mutex_lock(&blk_mq_cpuhp_lock); + __blk_mq_remove_cpuhp_list(&hctx_list); + mutex_unlock(&blk_mq_cpuhp_lock); + + spin_lock(&q->unused_hctx_lock); + list_splice(&hctx_list, &q->unused_hctx_list); + spin_unlock(&q->unused_hctx_lock); +} + +/* + * Register cpuhp callbacks from all hw queues + * + * Safe to call if this `request_queue` is live + */ +static void blk_mq_add_hw_queues_cpuhp(struct request_queue *q) +{ + struct blk_mq_hw_ctx *hctx; + unsigned long i; + + mutex_lock(&blk_mq_cpuhp_lock); + queue_for_each_hw_ctx(q, hctx, i) + __blk_mq_add_cpuhp(hctx); + mutex_unlock(&blk_mq_cpuhp_lock); } /* @@ -3683,8 +3873,6 @@ static void blk_mq_exit_hctx(struct request_queue *q, if (set->ops->exit_hctx) set->ops->exit_hctx(hctx, hctx_idx); - blk_mq_remove_cpuhp(hctx); - xa_erase(&q->hctx_table, hctx_idx); spin_lock(&q->unused_hctx_lock); @@ -3701,6 +3889,7 @@ static void blk_mq_exit_hw_queues(struct request_queue *q, queue_for_each_hw_ctx(q, hctx, i) { if (i == nr_queue) break; + blk_mq_remove_cpuhp(hctx); blk_mq_exit_hctx(q, set, hctx, i); } } @@ -3711,16 +3900,11 @@ static int blk_mq_init_hctx(struct request_queue *q, { hctx->queue_num = hctx_idx; - if (!(hctx->flags & BLK_MQ_F_STACKING)) - cpuhp_state_add_instance_nocalls(CPUHP_AP_BLK_MQ_ONLINE, - &hctx->cpuhp_online); - cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, &hctx->cpuhp_dead); - hctx->tags = set->tags[hctx_idx]; if (set->ops->init_hctx && set->ops->init_hctx(hctx, set->driver_data, hctx_idx)) - goto unregister_cpu_notifier; + goto fail; if (blk_mq_init_request(set, hctx->fq->flush_rq, hctx_idx, hctx->numa_node)) @@ -3737,8 +3921,7 @@ static int blk_mq_init_hctx(struct request_queue *q, exit_hctx: if (set->ops->exit_hctx) set->ops->exit_hctx(hctx, hctx_idx); - unregister_cpu_notifier: - blk_mq_remove_cpuhp(hctx); + fail: return -1; } @@ -3764,6 +3947,8 @@ blk_mq_alloc_hctx(struct request_queue *q, struct blk_mq_tag_set *set, INIT_DELAYED_WORK(&hctx->run_work, blk_mq_run_work_fn); spin_lock_init(&hctx->lock); INIT_LIST_HEAD(&hctx->dispatch); + INIT_HLIST_NODE(&hctx->cpuhp_dead); + INIT_HLIST_NODE(&hctx->cpuhp_online); hctx->queue = q; hctx->flags = set->flags & ~BLK_MQ_F_TAG_QUEUE_SHARED; @@ -4227,6 +4412,15 @@ struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q, } EXPORT_SYMBOL(blk_mq_alloc_disk_for_queue); +/* + * Only hctx removed from cpuhp list can be reused + */ +static bool blk_mq_hctx_is_reusable(struct blk_mq_hw_ctx *hctx) +{ + return hlist_unhashed(&hctx->cpuhp_online) && + hlist_unhashed(&hctx->cpuhp_dead); +} + static struct blk_mq_hw_ctx *blk_mq_alloc_and_init_hctx( struct blk_mq_tag_set *set, struct request_queue *q, int hctx_idx, int node) @@ -4236,7 +4430,7 @@ static struct blk_mq_hw_ctx *blk_mq_alloc_and_init_hctx( /* reuse dead hctx first */ spin_lock(&q->unused_hctx_lock); list_for_each_entry(tmp, &q->unused_hctx_list, hctx_list) { - if (tmp->numa_node == node) { + if (tmp->numa_node == node && blk_mq_hctx_is_reusable(tmp)) { hctx = tmp; break; } @@ -4302,6 +4496,12 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, xa_for_each_start(&q->hctx_table, j, hctx, j) blk_mq_exit_hctx(q, set, hctx, j); mutex_unlock(&q->sysfs_lock); + + /* unregister cpuhp callbacks for exited hctxs */ + blk_mq_remove_hw_queues_cpuhp(q); + + /* register cpuhp for new initialized hctxs */ + blk_mq_add_hw_queues_cpuhp(q); } int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, diff --git a/block/blk-mq.h b/block/blk-mq.h index 3bd43b10032f83..89a20fffa4b1ce 100644 --- a/block/blk-mq.h +++ b/block/blk-mq.h @@ -155,7 +155,7 @@ struct blk_mq_alloc_data { /* allocate multiple requests/tags in one go */ unsigned int nr_tags; - struct request **cached_rq; + struct rq_list *cached_rqs; /* input & output parameter */ struct blk_mq_ctx *ctx; @@ -230,6 +230,19 @@ static inline struct blk_mq_tags *blk_mq_tags_from_data(struct blk_mq_alloc_data static inline bool blk_mq_hctx_stopped(struct blk_mq_hw_ctx *hctx) { + /* Fast path: hardware queue is not stopped most of the time. */ + if (likely(!test_bit(BLK_MQ_S_STOPPED, &hctx->state))) + return false; + + /* + * This barrier is used to order adding of dispatch list before and + * the test of BLK_MQ_S_STOPPED below. Pairs with the memory barrier + * in blk_mq_start_stopped_hw_queue() so that dispatch code could + * either see BLK_MQ_S_STOPPED is cleared or dispatch list is not + * empty to avoid missing dispatching requests. + */ + smp_mb(); + return test_bit(BLK_MQ_S_STOPPED, &hctx->state); } diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c index 058f92c4f9d57b..eb9618cd68adfb 100644 --- a/block/blk-rq-qos.c +++ b/block/blk-rq-qos.c @@ -218,7 +218,6 @@ static int rq_qos_wake_function(struct wait_queue_entry *curr, return -1; data->got_token = true; - smp_wmb(); wake_up_process(data->task); list_del_init_careful(&curr->entry); return 1; @@ -274,10 +273,9 @@ void rq_qos_wait(struct rq_wait *rqw, void *private_data, * which means we now have two. Put our local token * and wake anyone else potentially waiting for one. */ - smp_rmb(); if (data.got_token) cleanup_cb(rqw, private_data); - break; + return; } io_schedule(); has_sleeper = true; diff --git a/block/blk-settings.c b/block/blk-settings.c index a446654ddee5ef..8f09e33f41f68a 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -50,7 +50,7 @@ void blk_set_stacking_limits(struct queue_limits *lim) lim->max_sectors = UINT_MAX; lim->max_dev_sectors = UINT_MAX; lim->max_write_zeroes_sectors = UINT_MAX; - lim->max_zone_append_sectors = UINT_MAX; + lim->max_hw_zone_append_sectors = UINT_MAX; lim->max_user_discard_sectors = UINT_MAX; } EXPORT_SYMBOL(blk_set_stacking_limits); @@ -91,17 +91,16 @@ static int blk_validate_zoned_limits(struct queue_limits *lim) if (lim->zone_write_granularity < lim->logical_block_size) lim->zone_write_granularity = lim->logical_block_size; - if (lim->max_zone_append_sectors) { - /* - * The Zone Append size is limited by the maximum I/O size - * and the zone size given that it can't span zones. - */ - lim->max_zone_append_sectors = - min3(lim->max_hw_sectors, - lim->max_zone_append_sectors, - lim->chunk_sectors); - } - + /* + * The Zone Append size is limited by the maximum I/O size and the zone + * size given that it can't span zones. + * + * If no max_hw_zone_append_sectors limit is provided, the block layer + * will emulated it, else we're also bound by the hardware limit. + */ + lim->max_zone_append_sectors = + min_not_zero(lim->max_hw_zone_append_sectors, + min(lim->chunk_sectors, lim->max_hw_sectors)); return 0; } @@ -179,9 +178,26 @@ static void blk_validate_atomic_write_limits(struct queue_limits *lim) if (!lim->atomic_write_hw_max) goto unsupported; + if (WARN_ON_ONCE(!is_power_of_2(lim->atomic_write_hw_unit_min))) + goto unsupported; + + if (WARN_ON_ONCE(!is_power_of_2(lim->atomic_write_hw_unit_max))) + goto unsupported; + + if (WARN_ON_ONCE(lim->atomic_write_hw_unit_min > + lim->atomic_write_hw_unit_max)) + goto unsupported; + + if (WARN_ON_ONCE(lim->atomic_write_hw_unit_max > + lim->atomic_write_hw_max)) + goto unsupported; + boundary_sectors = lim->atomic_write_hw_boundary >> SECTOR_SHIFT; if (boundary_sectors) { + if (WARN_ON_ONCE(lim->atomic_write_hw_max > + lim->atomic_write_hw_boundary)) + goto unsupported; /* * A feature of boundary support is that it disallows bios to * be merged which would result in a merged request which @@ -223,7 +239,7 @@ static void blk_validate_atomic_write_limits(struct queue_limits *lim) * Check that the limits in lim are valid, initialize defaults for unset * values, and cap values based on others where needed. */ -static int blk_validate_limits(struct queue_limits *lim) +int blk_validate_limits(struct queue_limits *lim) { unsigned int max_hw_sectors; unsigned int logical_block_sectors; @@ -249,6 +265,13 @@ static int blk_validate_limits(struct queue_limits *lim) if (lim->io_min < lim->physical_block_size) lim->io_min = lim->physical_block_size; + /* + * The optimal I/O size may not be aligned to physical block size + * (because it may be limited by dma engines which have no clue about + * block size of the disks attached to them), so we round it down here. + */ + lim->io_opt = round_down(lim->io_opt, lim->physical_block_size); + /* * max_hw_sectors has a somewhat weird default for historical reason, * but driver really should set their own instead of relying on this @@ -366,6 +389,7 @@ static int blk_validate_limits(struct queue_limits *lim) return err; return blk_validate_zoned_limits(lim); } +EXPORT_SYMBOL_GPL(blk_validate_limits); /* * Set the default limits for a newly allocated queue. @lim contains the @@ -458,8 +482,6 @@ static unsigned int queue_limit_discard_alignment( /* Why are these in bytes, not sectors? */ alignment = lim->discard_alignment >> SECTOR_SHIFT; granularity = lim->discard_granularity >> SECTOR_SHIFT; - if (!granularity) - return 0; /* Offset of the partition start in 'granularity' sectors */ offset = sector_div(sector, granularity); @@ -479,6 +501,119 @@ static unsigned int blk_round_down_sectors(unsigned int sectors, unsigned int lb return sectors; } +/* Check if second and later bottom devices are compliant */ +static bool blk_stack_atomic_writes_tail(struct queue_limits *t, + struct queue_limits *b) +{ + /* We're not going to support different boundary sizes.. yet */ + if (t->atomic_write_hw_boundary != b->atomic_write_hw_boundary) + return false; + + /* Can't support this */ + if (t->atomic_write_hw_unit_min > b->atomic_write_hw_unit_max) + return false; + + /* Or this */ + if (t->atomic_write_hw_unit_max < b->atomic_write_hw_unit_min) + return false; + + t->atomic_write_hw_max = min(t->atomic_write_hw_max, + b->atomic_write_hw_max); + t->atomic_write_hw_unit_min = max(t->atomic_write_hw_unit_min, + b->atomic_write_hw_unit_min); + t->atomic_write_hw_unit_max = min(t->atomic_write_hw_unit_max, + b->atomic_write_hw_unit_max); + return true; +} + +/* Check for valid boundary of first bottom device */ +static bool blk_stack_atomic_writes_boundary_head(struct queue_limits *t, + struct queue_limits *b) +{ + /* + * Ensure atomic write boundary is aligned with chunk sectors. Stacked + * devices store chunk sectors in t->io_min. + */ + if (b->atomic_write_hw_boundary > t->io_min && + b->atomic_write_hw_boundary % t->io_min) + return false; + if (t->io_min > b->atomic_write_hw_boundary && + t->io_min % b->atomic_write_hw_boundary) + return false; + + t->atomic_write_hw_boundary = b->atomic_write_hw_boundary; + return true; +} + + +/* Check stacking of first bottom device */ +static bool blk_stack_atomic_writes_head(struct queue_limits *t, + struct queue_limits *b) +{ + if (b->atomic_write_hw_boundary && + !blk_stack_atomic_writes_boundary_head(t, b)) + return false; + + if (t->io_min <= SECTOR_SIZE) { + /* No chunk sectors, so use bottom device values directly */ + t->atomic_write_hw_unit_max = b->atomic_write_hw_unit_max; + t->atomic_write_hw_unit_min = b->atomic_write_hw_unit_min; + t->atomic_write_hw_max = b->atomic_write_hw_max; + return true; + } + + /* + * Find values for limits which work for chunk size. + * b->atomic_write_hw_unit_{min, max} may not be aligned with chunk + * size (t->io_min), as chunk size is not restricted to a power-of-2. + * So we need to find highest power-of-2 which works for the chunk + * size. + * As an example scenario, we could have b->unit_max = 16K and + * t->io_min = 24K. For this case, reduce t->unit_max to a value + * aligned with both limits, i.e. 8K in this example. + */ + t->atomic_write_hw_unit_max = b->atomic_write_hw_unit_max; + while (t->io_min % t->atomic_write_hw_unit_max) + t->atomic_write_hw_unit_max /= 2; + + t->atomic_write_hw_unit_min = min(b->atomic_write_hw_unit_min, + t->atomic_write_hw_unit_max); + t->atomic_write_hw_max = min(b->atomic_write_hw_max, t->io_min); + + return true; +} + +static void blk_stack_atomic_writes_limits(struct queue_limits *t, + struct queue_limits *b) +{ + if (!(t->features & BLK_FEAT_ATOMIC_WRITES_STACKED)) + goto unsupported; + + if (!b->atomic_write_unit_min) + goto unsupported; + + /* + * If atomic_write_hw_max is set, we have already stacked 1x bottom + * device, so check for compliance. + */ + if (t->atomic_write_hw_max) { + if (!blk_stack_atomic_writes_tail(t, b)) + goto unsupported; + return; + } + + if (!blk_stack_atomic_writes_head(t, b)) + goto unsupported; + return; + +unsupported: + t->atomic_write_hw_max = 0; + t->atomic_write_hw_unit_max = 0; + t->atomic_write_hw_unit_min = 0; + t->atomic_write_hw_boundary = 0; + t->features &= ~BLK_FEAT_ATOMIC_WRITES_STACKED; +} + /** * blk_stack_limits - adjust queue_limits for stacked devices * @t: the stacking driver limits (top device) @@ -508,10 +643,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->features |= (b->features & BLK_FEAT_INHERIT_MASK); /* - * BLK_FEAT_NOWAIT and BLK_FEAT_POLL need to be supported both by the - * stacking driver and all underlying devices. The stacking driver sets - * the flags before stacking the limits, and this will clear the flags - * if any of the underlying devices does not support it. + * Some feaures need to be supported both by the stacking driver and all + * underlying devices. The stacking driver sets these flags before + * stacking the limits, and this will clear the flags if any of the + * underlying devices does not support it. */ if (!(b->features & BLK_FEAT_NOWAIT)) t->features &= ~BLK_FEAT_NOWAIT; @@ -527,8 +662,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors); t->max_write_zeroes_sectors = min(t->max_write_zeroes_sectors, b->max_write_zeroes_sectors); - t->max_zone_append_sectors = min(queue_limits_max_zone_append_sectors(t), - queue_limits_max_zone_append_sectors(b)); + t->max_hw_zone_append_sectors = min(t->max_hw_zone_append_sectors, + b->max_hw_zone_append_sectors); t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask); @@ -639,6 +774,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->zone_write_granularity = 0; t->max_zone_append_sectors = 0; } + blk_stack_atomic_writes_limits(t, b); + return ret; } EXPORT_SYMBOL(blk_stack_limits); @@ -661,7 +798,7 @@ EXPORT_SYMBOL(blk_stack_limits); void queue_limits_stack_bdev(struct queue_limits *t, struct block_device *bdev, sector_t offset, const char *pfx) { - if (blk_stack_limits(t, &bdev_get_queue(bdev)->limits, + if (blk_stack_limits(t, bdev_limits(bdev), get_start_sect(bdev) + offset)) pr_notice("%s: Warning: Device %pg is misaligned\n", pfx, bdev); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index e85941bec857b6..767598e719ab0e 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -23,14 +23,14 @@ struct queue_sysfs_entry { struct attribute attr; ssize_t (*show)(struct gendisk *disk, char *page); - int (*load_module)(struct gendisk *disk, const char *page, size_t count); ssize_t (*store)(struct gendisk *disk, const char *page, size_t count); + void (*load_module)(struct gendisk *disk, const char *page, size_t count); }; static ssize_t queue_var_show(unsigned long var, char *page) { - return sprintf(page, "%lu\n", var); + return sysfs_emit(page, "%lu\n", var); } static ssize_t @@ -121,7 +121,7 @@ QUEUE_SYSFS_LIMIT_SHOW(atomic_write_unit_max) #define QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(_field) \ static ssize_t queue_##_field##_show(struct gendisk *disk, char *page) \ { \ - return sprintf(page, "%llu\n", \ + return sysfs_emit(page, "%llu\n", \ (unsigned long long)disk->queue->limits._field << \ SECTOR_SHIFT); \ } @@ -131,6 +131,7 @@ QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_hw_discard_sectors) QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_write_zeroes_sectors) QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(atomic_write_max_sectors) QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(atomic_write_boundary_sectors) +QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES(max_zone_append_sectors) #define QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_KB(_field) \ static ssize_t queue_##_field##_show(struct gendisk *disk, char *page) \ @@ -144,7 +145,7 @@ QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_KB(max_hw_sectors) #define QUEUE_SYSFS_SHOW_CONST(_name, _val) \ static ssize_t queue_##_name##_show(struct gendisk *disk, char *page) \ { \ - return sprintf(page, "%d\n", _val); \ + return sysfs_emit(page, "%d\n", _val); \ } /* deprecated fields */ @@ -178,18 +179,6 @@ static ssize_t queue_max_discard_sectors_store(struct gendisk *disk, return ret; } -/* - * For zone append queue_max_zone_append_sectors does not just return the - * underlying queue limits, but actually contains a calculation. Because of - * that we can't simply use QUEUE_SYSFS_LIMIT_SHOW_SECTORS_TO_BYTES here. - */ -static ssize_t queue_zone_append_max_show(struct gendisk *disk, char *page) -{ - return sprintf(page, "%llu\n", - (u64)queue_max_zone_append_sectors(disk->queue) << - SECTOR_SHIFT); -} - static ssize_t queue_max_sectors_store(struct gendisk *disk, const char *page, size_t count) { @@ -235,7 +224,7 @@ static ssize_t queue_feature_store(struct gendisk *disk, const char *page, #define QUEUE_SYSFS_FEATURE(_name, _feature) \ static ssize_t queue_##_name##_show(struct gendisk *disk, char *page) \ { \ - return sprintf(page, "%u\n", \ + return sysfs_emit(page, "%u\n", \ !!(disk->queue->limits.features & _feature)); \ } \ static ssize_t queue_##_name##_store(struct gendisk *disk, \ @@ -252,7 +241,7 @@ QUEUE_SYSFS_FEATURE(stable_writes, BLK_FEAT_STABLE_WRITES); #define QUEUE_SYSFS_FEATURE_SHOW(_name, _feature) \ static ssize_t queue_##_name##_show(struct gendisk *disk, char *page) \ { \ - return sprintf(page, "%u\n", \ + return sysfs_emit(page, "%u\n", \ !!(disk->queue->limits.features & _feature)); \ } @@ -263,8 +252,8 @@ QUEUE_SYSFS_FEATURE_SHOW(dax, BLK_FEAT_DAX); static ssize_t queue_zoned_show(struct gendisk *disk, char *page) { if (blk_queue_is_zoned(disk->queue)) - return sprintf(page, "host-managed\n"); - return sprintf(page, "none\n"); + return sysfs_emit(page, "host-managed\n"); + return sysfs_emit(page, "none\n"); } static ssize_t queue_nr_zones_show(struct gendisk *disk, char *page) @@ -272,6 +261,34 @@ static ssize_t queue_nr_zones_show(struct gendisk *disk, char *page) return queue_var_show(disk_nr_zones(disk), page); } +static ssize_t queue_iostats_passthrough_show(struct gendisk *disk, char *page) +{ + return queue_var_show(!!blk_queue_passthrough_stat(disk->queue), page); +} + +static ssize_t queue_iostats_passthrough_store(struct gendisk *disk, + const char *page, size_t count) +{ + struct queue_limits lim; + unsigned long ios; + ssize_t ret; + + ret = queue_var_store(&ios, page, count); + if (ret < 0) + return ret; + + lim = queue_limits_start_update(disk->queue); + if (ios) + lim.flags |= BLK_FLAG_IOSTATS_PASSTHROUGH; + else + lim.flags &= ~BLK_FLAG_IOSTATS_PASSTHROUGH; + + ret = queue_limits_commit_update(disk->queue, &lim); + if (ret) + return ret; + + return count; +} static ssize_t queue_nomerges_show(struct gendisk *disk, char *page) { return queue_var_show((blk_queue_nomerges(disk->queue) << 1) | @@ -349,7 +366,7 @@ static ssize_t queue_poll_store(struct gendisk *disk, const char *page, static ssize_t queue_io_timeout_show(struct gendisk *disk, char *page) { - return sprintf(page, "%u\n", jiffies_to_msecs(disk->queue->rq_timeout)); + return sysfs_emit(page, "%u\n", jiffies_to_msecs(disk->queue->rq_timeout)); } static ssize_t queue_io_timeout_store(struct gendisk *disk, const char *page, @@ -370,8 +387,8 @@ static ssize_t queue_io_timeout_store(struct gendisk *disk, const char *page, static ssize_t queue_wc_show(struct gendisk *disk, char *page) { if (blk_queue_write_cache(disk->queue)) - return sprintf(page, "write back\n"); - return sprintf(page, "write through\n"); + return sysfs_emit(page, "write back\n"); + return sysfs_emit(page, "write through\n"); } static ssize_t queue_wc_store(struct gendisk *disk, const char *page, @@ -451,7 +468,7 @@ QUEUE_RO_ENTRY(queue_atomic_write_unit_min, "atomic_write_unit_min_bytes"); QUEUE_RO_ENTRY(queue_write_same_max, "write_same_max_bytes"); QUEUE_RO_ENTRY(queue_max_write_zeroes_sectors, "write_zeroes_max_bytes"); -QUEUE_RO_ENTRY(queue_zone_append_max, "zone_append_max_bytes"); +QUEUE_RO_ENTRY(queue_max_zone_append_sectors, "zone_append_max_bytes"); QUEUE_RO_ENTRY(queue_zone_write_granularity, "zone_write_granularity"); QUEUE_RO_ENTRY(queue_zoned, "zoned"); @@ -460,6 +477,7 @@ QUEUE_RO_ENTRY(queue_max_open_zones, "max_open_zones"); QUEUE_RO_ENTRY(queue_max_active_zones, "max_active_zones"); QUEUE_RW_ENTRY(queue_nomerges, "nomerges"); +QUEUE_RW_ENTRY(queue_iostats_passthrough, "iostats_passthrough"); QUEUE_RW_ENTRY(queue_rq_affinity, "rq_affinity"); QUEUE_RW_ENTRY(queue_poll, "io_poll"); QUEUE_RW_ENTRY(queue_poll_delay, "io_poll_delay"); @@ -501,9 +519,9 @@ static ssize_t queue_wb_lat_show(struct gendisk *disk, char *page) return -EINVAL; if (wbt_disabled(disk->queue)) - return sprintf(page, "0\n"); + return sysfs_emit(page, "0\n"); - return sprintf(page, "%llu\n", + return sysfs_emit(page, "%llu\n", div_u64(wbt_get_min_lat(disk->queue), 1000)); } @@ -578,7 +596,7 @@ static struct attribute *queue_attrs[] = { &queue_atomic_write_unit_max_entry.attr, &queue_write_same_max_entry.attr, &queue_max_write_zeroes_sectors_entry.attr, - &queue_zone_append_max_entry.attr, + &queue_max_zone_append_sectors_entry.attr, &queue_zone_write_granularity_entry.attr, &queue_rotational_entry.attr, &queue_zoned_entry.attr, @@ -586,6 +604,7 @@ static struct attribute *queue_attrs[] = { &queue_max_open_zones_entry.attr, &queue_max_active_zones_entry.attr, &queue_nomerges_entry.attr, + &queue_iostats_passthrough_entry.attr, &queue_iostats_entry.attr, &queue_stable_writes_entry.attr, &queue_add_random_entry.attr, @@ -684,11 +703,8 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr, * queue to ensure that the module file can be read when the request * queue is the one for the device storing the module file. */ - if (entry->load_module) { - res = entry->load_module(disk, page, length); - if (res) - return res; - } + if (entry->load_module) + entry->load_module(disk, page, length); blk_mq_freeze_queue(q); mutex_lock(&q->sysfs_lock); @@ -794,10 +810,8 @@ int blk_register_queue(struct gendisk *disk) * faster to shut down and is made fully functional here as * request_queues for non-existent devices never get registered. */ - if (!blk_queue_init_done(q)) { - blk_queue_flag_set(QUEUE_FLAG_INIT_DONE, q); - percpu_ref_switch_to_percpu(&q->q_usage_counter); - } + blk_queue_flag_set(QUEUE_FLAG_INIT_DONE, q); + percpu_ref_switch_to_percpu(&q->q_usage_counter); return ret; diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 2c4192e12efab6..82dbaefcfa3bf5 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -1485,13 +1485,13 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of, goto out_finish; ret = -EINVAL; - if (!strcmp(tok, "rbps") && val > 1) + if (!strcmp(tok, "rbps")) v[0] = val; - else if (!strcmp(tok, "wbps") && val > 1) + else if (!strcmp(tok, "wbps")) v[1] = val; - else if (!strcmp(tok, "riops") && val > 1) + else if (!strcmp(tok, "riops")) v[2] = min_t(u64, val, UINT_MAX); - else if (!strcmp(tok, "wiops") && val > 1) + else if (!strcmp(tok, "wiops")) v[3] = min_t(u64, val, UINT_MAX); else goto out_finish; @@ -1526,6 +1526,42 @@ static void throtl_shutdown_wq(struct request_queue *q) cancel_work_sync(&td->dispatch_work); } +static void tg_flush_bios(struct throtl_grp *tg) +{ + struct throtl_service_queue *sq = &tg->service_queue; + + if (tg->flags & THROTL_TG_CANCELING) + return; + /* + * Set the flag to make sure throtl_pending_timer_fn() won't + * stop until all throttled bios are dispatched. + */ + tg->flags |= THROTL_TG_CANCELING; + + /* + * Do not dispatch cgroup without THROTL_TG_PENDING or cgroup + * will be inserted to service queue without THROTL_TG_PENDING + * set in tg_update_disptime below. Then IO dispatched from + * child in tg_dispatch_one_bio will trigger double insertion + * and corrupt the tree. + */ + if (!(tg->flags & THROTL_TG_PENDING)) + return; + + /* + * Update disptime after setting the above flag to make sure + * throtl_select_dispatch() won't exit without dispatching. + */ + tg_update_disptime(tg); + + throtl_schedule_pending_timer(sq, jiffies + 1); +} + +static void throtl_pd_offline(struct blkg_policy_data *pd) +{ + tg_flush_bios(pd_to_tg(pd)); +} + struct blkcg_policy blkcg_policy_throtl = { .dfl_cftypes = throtl_files, .legacy_cftypes = throtl_legacy_files, @@ -1533,6 +1569,7 @@ struct blkcg_policy blkcg_policy_throtl = { .pd_alloc_fn = throtl_pd_alloc, .pd_init_fn = throtl_pd_init, .pd_online_fn = throtl_pd_online, + .pd_offline_fn = throtl_pd_offline, .pd_free_fn = throtl_pd_free, }; @@ -1553,32 +1590,15 @@ void blk_throtl_cancel_bios(struct gendisk *disk) */ rcu_read_lock(); blkg_for_each_descendant_post(blkg, pos_css, q->root_blkg) { - struct throtl_grp *tg = blkg_to_tg(blkg); - struct throtl_service_queue *sq = &tg->service_queue; - - /* - * Set the flag to make sure throtl_pending_timer_fn() won't - * stop until all throttled bios are dispatched. - */ - tg->flags |= THROTL_TG_CANCELING; - /* - * Do not dispatch cgroup without THROTL_TG_PENDING or cgroup - * will be inserted to service queue without THROTL_TG_PENDING - * set in tg_update_disptime below. Then IO dispatched from - * child in tg_dispatch_one_bio will trigger double insertion - * and corrupt the tree. + * disk_release will call pd_offline_fn to cancel bios. + * However, disk_release can't be called if someone get + * the refcount of device and issued bios which are + * inflight after del_gendisk. + * Cancel bios here to ensure no bios are inflight after + * del_gendisk. */ - if (!(tg->flags & THROTL_TG_PENDING)) - continue; - - /* - * Update disptime after setting the above flag to make sure - * throtl_select_dispatch() won't exit without dispatching. - */ - tg_update_disptime(tg); - - throtl_schedule_pending_timer(sq, jiffies + 1); + tg_flush_bios(blkg_to_tg(blkg)); } rcu_read_unlock(); spin_unlock_irq(&q->queue_lock); diff --git a/block/blk-zoned.c b/block/blk-zoned.c index af19296fa50df1..84da1eadff642d 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include "blk.h" @@ -41,7 +41,6 @@ static const char *const zone_cond_name[] = { /* * Per-zone write plug. * @node: hlist_node structure for managing the plug using a hash table. - * @link: To list the plug in the zone write plug error list of the disk. * @ref: Zone write plug reference counter. A zone write plug reference is * always at least 1 when the plug is hashed in the disk plug hash table. * The reference is incremented whenever a new BIO needing plugging is @@ -63,8 +62,7 @@ static const char *const zone_cond_name[] = { */ struct blk_zone_wplug { struct hlist_node node; - struct list_head link; - atomic_t ref; + refcount_t ref; spinlock_t lock; unsigned int flags; unsigned int zone_no; @@ -80,8 +78,8 @@ struct blk_zone_wplug { * - BLK_ZONE_WPLUG_PLUGGED: Indicates that the zone write plug is plugged, * that is, that write BIOs are being throttled due to a write BIO already * being executed or the zone write plug bio list is not empty. - * - BLK_ZONE_WPLUG_ERROR: Indicates that a write error happened which will be - * recovered with a report zone to update the zone write pointer offset. + * - BLK_ZONE_WPLUG_NEED_WP_UPDATE: Indicates that we lost track of a zone + * write pointer offset and need to update it. * - BLK_ZONE_WPLUG_UNHASHED: Indicates that the zone write plug was removed * from the disk hash table and that the initial reference to the zone * write plug set when the plug was first added to the hash table has been @@ -91,11 +89,9 @@ struct blk_zone_wplug { * freed once all remaining references from BIOs or functions are dropped. */ #define BLK_ZONE_WPLUG_PLUGGED (1U << 0) -#define BLK_ZONE_WPLUG_ERROR (1U << 1) +#define BLK_ZONE_WPLUG_NEED_WP_UPDATE (1U << 1) #define BLK_ZONE_WPLUG_UNHASHED (1U << 2) -#define BLK_ZONE_WPLUG_BUSY (BLK_ZONE_WPLUG_PLUGGED | BLK_ZONE_WPLUG_ERROR) - /** * blk_zone_cond_str - Return string XXX in BLK_ZONE_COND_XXX. * @zone_cond: BLK_ZONE_COND_XXX. @@ -115,6 +111,30 @@ const char *blk_zone_cond_str(enum blk_zone_cond zone_cond) } EXPORT_SYMBOL_GPL(blk_zone_cond_str); +struct disk_report_zones_cb_args { + struct gendisk *disk; + report_zones_cb user_cb; + void *user_data; +}; + +static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk, + struct blk_zone *zone); + +static int disk_report_zones_cb(struct blk_zone *zone, unsigned int idx, + void *data) +{ + struct disk_report_zones_cb_args *args = data; + struct gendisk *disk = args->disk; + + if (disk->zone_wplugs_hash) + disk_zone_wplug_sync_wp_offset(disk, zone); + + if (!args->user_cb) + return 0; + + return args->user_cb(zone, idx, args->user_data); +} + /** * blkdev_report_zones - Get zones information * @bdev: Target block device @@ -139,6 +159,11 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector, { struct gendisk *disk = bdev->bd_disk; sector_t capacity = get_capacity(disk); + struct disk_report_zones_cb_args args = { + .disk = disk, + .user_cb = cb, + .user_data = data, + }; if (!bdev_is_zoned(bdev) || WARN_ON_ONCE(!disk->fops->report_zones)) return -EOPNOTSUPP; @@ -146,7 +171,8 @@ int blkdev_report_zones(struct block_device *bdev, sector_t sector, if (!nr_zones || sector >= capacity) return 0; - return disk->fops->report_zones(disk, sector, nr_zones, cb, data); + return disk->fops->report_zones(disk, sector, nr_zones, + disk_report_zones_cb, &args); } EXPORT_SYMBOL_GPL(blkdev_report_zones); @@ -348,13 +374,6 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode, return ret; } -static inline bool disk_zone_is_conv(struct gendisk *disk, sector_t sector) -{ - if (!disk->conv_zones_bitmap) - return false; - return test_bit(disk_zone_no(disk, sector), disk->conv_zones_bitmap); -} - static bool disk_zone_is_last(struct gendisk *disk, struct blk_zone *zone) { return zone->start + zone->len >= get_capacity(disk); @@ -411,7 +430,7 @@ static struct blk_zone_wplug *disk_get_zone_wplug(struct gendisk *disk, hlist_for_each_entry_rcu(zwplug, &disk->zone_wplugs_hash[idx], node) { if (zwplug->zone_no == zno && - atomic_inc_not_zero(&zwplug->ref)) { + refcount_inc_not_zero(&zwplug->ref)) { rcu_read_unlock(); return zwplug; } @@ -432,9 +451,9 @@ static void disk_free_zone_wplug_rcu(struct rcu_head *rcu_head) static inline void disk_put_zone_wplug(struct blk_zone_wplug *zwplug) { - if (atomic_dec_and_test(&zwplug->ref)) { + if (refcount_dec_and_test(&zwplug->ref)) { WARN_ON_ONCE(!bio_list_empty(&zwplug->bio_list)); - WARN_ON_ONCE(!list_empty(&zwplug->link)); + WARN_ON_ONCE(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED); WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_UNHASHED)); call_rcu(&zwplug->rcu_head, disk_free_zone_wplug_rcu); @@ -448,8 +467,8 @@ static inline bool disk_should_remove_zone_wplug(struct gendisk *disk, if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED) return false; - /* If the zone write plug is still busy, it cannot be removed. */ - if (zwplug->flags & BLK_ZONE_WPLUG_BUSY) + /* If the zone write plug is still plugged, it cannot be removed. */ + if (zwplug->flags & BLK_ZONE_WPLUG_PLUGGED) return false; /* @@ -463,7 +482,7 @@ static inline bool disk_should_remove_zone_wplug(struct gendisk *disk, * taken when the plug was allocated and another reference taken by the * caller context). */ - if (atomic_read(&zwplug->ref) > 2) + if (refcount_read(&zwplug->ref) > 2) return false; /* We can remove zone write plugs for zones that are empty or full. */ @@ -532,12 +551,11 @@ static struct blk_zone_wplug *disk_get_and_lock_zone_wplug(struct gendisk *disk, return NULL; INIT_HLIST_NODE(&zwplug->node); - INIT_LIST_HEAD(&zwplug->link); - atomic_set(&zwplug->ref, 2); + refcount_set(&zwplug->ref, 2); spin_lock_init(&zwplug->lock); zwplug->flags = 0; zwplug->zone_no = zno; - zwplug->wp_offset = sector & (disk->queue->limits.chunk_sectors - 1); + zwplug->wp_offset = bdev_offset_from_zone_start(disk->part0, sector); bio_list_init(&zwplug->bio_list); INIT_WORK(&zwplug->bio_work, blk_zone_wplug_bio_work); zwplug->disk = disk; @@ -581,124 +599,81 @@ static void disk_zone_wplug_abort(struct blk_zone_wplug *zwplug) } /* - * Abort (fail) all plugged BIOs of a zone write plug that are not aligned - * with the assumed write pointer location of the zone when the BIO will - * be unplugged. + * Set a zone write plug write pointer offset to the specified value. + * This aborts all plugged BIOs, which is fine as this function is called for + * a zone reset operation, a zone finish operation or if the zone needs a wp + * update from a report zone after a write error. */ -static void disk_zone_wplug_abort_unaligned(struct gendisk *disk, - struct blk_zone_wplug *zwplug) -{ - unsigned int wp_offset = zwplug->wp_offset; - struct bio_list bl = BIO_EMPTY_LIST; - struct bio *bio; - - while ((bio = bio_list_pop(&zwplug->bio_list))) { - if (disk_zone_is_full(disk, zwplug->zone_no, wp_offset) || - (bio_op(bio) != REQ_OP_ZONE_APPEND && - bio_offset_from_zone_start(bio) != wp_offset)) { - blk_zone_wplug_bio_io_error(zwplug, bio); - continue; - } - - wp_offset += bio_sectors(bio); - bio_list_add(&bl, bio); - } - - bio_list_merge(&zwplug->bio_list, &bl); -} - -static inline void disk_zone_wplug_set_error(struct gendisk *disk, - struct blk_zone_wplug *zwplug) +static void disk_zone_wplug_set_wp_offset(struct gendisk *disk, + struct blk_zone_wplug *zwplug, + unsigned int wp_offset) { - unsigned long flags; + lockdep_assert_held(&zwplug->lock); - if (zwplug->flags & BLK_ZONE_WPLUG_ERROR) - return; + /* Update the zone write pointer and abort all plugged BIOs. */ + zwplug->flags &= ~BLK_ZONE_WPLUG_NEED_WP_UPDATE; + zwplug->wp_offset = wp_offset; + disk_zone_wplug_abort(zwplug); /* - * At this point, we already have a reference on the zone write plug. - * However, since we are going to add the plug to the disk zone write - * plugs work list, increase its reference count. This reference will - * be dropped in disk_zone_wplugs_work() once the error state is - * handled, or in disk_zone_wplug_clear_error() if the zone is reset or - * finished. + * The zone write plug now has no BIO plugged: remove it from the + * hash table so that it cannot be seen. The plug will be freed + * when the last reference is dropped. */ - zwplug->flags |= BLK_ZONE_WPLUG_ERROR; - atomic_inc(&zwplug->ref); - - spin_lock_irqsave(&disk->zone_wplugs_lock, flags); - list_add_tail(&zwplug->link, &disk->zone_wplugs_err_list); - spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); + if (disk_should_remove_zone_wplug(disk, zwplug)) + disk_remove_zone_wplug(disk, zwplug); } -static inline void disk_zone_wplug_clear_error(struct gendisk *disk, - struct blk_zone_wplug *zwplug) +static unsigned int blk_zone_wp_offset(struct blk_zone *zone) { - unsigned long flags; - - if (!(zwplug->flags & BLK_ZONE_WPLUG_ERROR)) - return; - - /* - * We are racing with the error handling work which drops the reference - * on the zone write plug after handling the error state. So remove the - * plug from the error list and drop its reference count only if the - * error handling has not yet started, that is, if the zone write plug - * is still listed. - */ - spin_lock_irqsave(&disk->zone_wplugs_lock, flags); - if (!list_empty(&zwplug->link)) { - list_del_init(&zwplug->link); - zwplug->flags &= ~BLK_ZONE_WPLUG_ERROR; - disk_put_zone_wplug(zwplug); + switch (zone->cond) { + case BLK_ZONE_COND_IMP_OPEN: + case BLK_ZONE_COND_EXP_OPEN: + case BLK_ZONE_COND_CLOSED: + return zone->wp - zone->start; + case BLK_ZONE_COND_FULL: + return zone->len; + case BLK_ZONE_COND_EMPTY: + return 0; + case BLK_ZONE_COND_NOT_WP: + case BLK_ZONE_COND_OFFLINE: + case BLK_ZONE_COND_READONLY: + default: + /* + * Conventional, offline and read-only zones do not have a valid + * write pointer. + */ + return UINT_MAX; } - spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); } -/* - * Set a zone write plug write pointer offset to either 0 (zone reset case) - * or to the zone size (zone finish case). This aborts all plugged BIOs, which - * is fine to do as doing a zone reset or zone finish while writes are in-flight - * is a mistake from the user which will most likely cause all plugged BIOs to - * fail anyway. - */ -static void disk_zone_wplug_set_wp_offset(struct gendisk *disk, - struct blk_zone_wplug *zwplug, - unsigned int wp_offset) +static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk, + struct blk_zone *zone) { + struct blk_zone_wplug *zwplug; unsigned long flags; - spin_lock_irqsave(&zwplug->lock, flags); - - /* - * Make sure that a BIO completion or another zone reset or finish - * operation has not already removed the plug from the hash table. - */ - if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED) { - spin_unlock_irqrestore(&zwplug->lock, flags); + zwplug = disk_get_zone_wplug(disk, zone->start); + if (!zwplug) return; - } - /* Update the zone write pointer and abort all plugged BIOs. */ - zwplug->wp_offset = wp_offset; - disk_zone_wplug_abort(zwplug); + spin_lock_irqsave(&zwplug->lock, flags); + if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE) + disk_zone_wplug_set_wp_offset(disk, zwplug, + blk_zone_wp_offset(zone)); + spin_unlock_irqrestore(&zwplug->lock, flags); - /* - * Updating the write pointer offset puts back the zone - * in a good state. So clear the error flag and decrement the - * error count if we were in error state. - */ - disk_zone_wplug_clear_error(disk, zwplug); + disk_put_zone_wplug(zwplug); +} - /* - * The zone write plug now has no BIO plugged: remove it from the - * hash table so that it cannot be seen. The plug will be freed - * when the last reference is dropped. - */ - if (disk_should_remove_zone_wplug(disk, zwplug)) - disk_remove_zone_wplug(disk, zwplug); +static int disk_zone_sync_wp_offset(struct gendisk *disk, sector_t sector) +{ + struct disk_report_zones_cb_args args = { + .disk = disk, + }; - spin_unlock_irqrestore(&zwplug->lock, flags); + return disk->fops->report_zones(disk, sector, 1, + disk_report_zones_cb, &args); } static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, @@ -707,13 +682,23 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, struct gendisk *disk = bio->bi_bdev->bd_disk; sector_t sector = bio->bi_iter.bi_sector; struct blk_zone_wplug *zwplug; + unsigned long flags; /* Conventional zones cannot be reset nor finished. */ - if (disk_zone_is_conv(disk, sector)) { + if (!bdev_zone_is_seq(bio->bi_bdev, sector)) { bio_io_error(bio); return true; } + /* + * No-wait reset or finish BIOs do not make much sense as the callers + * issue these as blocking operations in most cases. To avoid issues + * the BIO execution potentially failing with BLK_STS_AGAIN, warn about + * REQ_NOWAIT being set and ignore that flag. + */ + if (WARN_ON_ONCE(bio->bi_opf & REQ_NOWAIT)) + bio->bi_opf &= ~REQ_NOWAIT; + /* * If we have a zone write plug, set its write pointer offset to 0 * (reset case) or to the zone size (finish case). This will abort all @@ -723,7 +708,9 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio, */ zwplug = disk_get_zone_wplug(disk, sector); if (zwplug) { + spin_lock_irqsave(&zwplug->lock, flags); disk_zone_wplug_set_wp_offset(disk, zwplug, wp_offset); + spin_unlock_irqrestore(&zwplug->lock, flags); disk_put_zone_wplug(zwplug); } @@ -734,6 +721,7 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio) { struct gendisk *disk = bio->bi_bdev->bd_disk; struct blk_zone_wplug *zwplug; + unsigned long flags; sector_t sector; /* @@ -745,7 +733,9 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio) sector += disk->queue->limits.chunk_sectors) { zwplug = disk_get_zone_wplug(disk, sector); if (zwplug) { + spin_lock_irqsave(&zwplug->lock, flags); disk_zone_wplug_set_wp_offset(disk, zwplug, 0); + spin_unlock_irqrestore(&zwplug->lock, flags); disk_put_zone_wplug(zwplug); } } @@ -753,9 +743,25 @@ static bool blk_zone_wplug_handle_reset_all(struct bio *bio) return false; } -static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug, - struct bio *bio, unsigned int nr_segs) +static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk, + struct blk_zone_wplug *zwplug) +{ + /* + * Take a reference on the zone write plug and schedule the submission + * of the next plugged BIO. blk_zone_wplug_bio_work() will release the + * reference we take here. + */ + WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)); + refcount_inc(&zwplug->ref); + queue_work(disk->zone_wplugs_wq, &zwplug->bio_work); +} + +static inline void disk_zone_wplug_add_bio(struct gendisk *disk, + struct blk_zone_wplug *zwplug, + struct bio *bio, unsigned int nr_segs) { + bool schedule_bio_work = false; + /* * Grab an extra reference on the BIO request queue usage counter. * This reference will be reused to submit a request for the BIO for @@ -771,6 +777,16 @@ static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug, */ bio_clear_polled(bio); + /* + * REQ_NOWAIT BIOs are always handled using the zone write plug BIO + * work, which can block. So clear the REQ_NOWAIT flag and schedule the + * work if this is the first BIO we are plugging. + */ + if (bio->bi_opf & REQ_NOWAIT) { + schedule_bio_work = !(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED); + bio->bi_opf &= ~REQ_NOWAIT; + } + /* * Reuse the poll cookie field to store the number of segments when * split to the hardware limits. @@ -784,6 +800,11 @@ static inline void blk_zone_wplug_add_bio(struct blk_zone_wplug *zwplug, * at the tail of the list to preserve the sequential write order. */ bio_list_add(&zwplug->bio_list, bio); + + zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; + + if (schedule_bio_work) + disk_zone_wplug_schedule_bio_work(disk, zwplug); } /* @@ -896,13 +917,23 @@ static bool blk_zone_wplug_prepare_bio(struct blk_zone_wplug *zwplug, { struct gendisk *disk = bio->bi_bdev->bd_disk; + /* + * If we lost track of the zone write pointer due to a write error, + * the user must either execute a report zones, reset the zone or finish + * the to recover a reliable write pointer position. Fail BIOs if the + * user did not do that as we cannot handle emulated zone append + * otherwise. + */ + if (zwplug->flags & BLK_ZONE_WPLUG_NEED_WP_UPDATE) + return false; + /* * Check that the user is not attempting to write to a full zone. * We know such BIO will fail, and that would potentially overflow our * write pointer offset beyond the end of the zone. */ if (disk_zone_wplug_is_full(disk, zwplug)) - goto err; + return false; if (bio_op(bio) == REQ_OP_ZONE_APPEND) { /* @@ -921,24 +952,18 @@ static bool blk_zone_wplug_prepare_bio(struct blk_zone_wplug *zwplug, bio_set_flag(bio, BIO_EMULATES_ZONE_APPEND); } else { /* - * Check for non-sequential writes early because we avoid a - * whole lot of error handling trouble if we don't send it off - * to the driver. + * Check for non-sequential writes early as we know that BIOs + * with a start sector not unaligned to the zone write pointer + * will fail. */ if (bio_offset_from_zone_start(bio) != zwplug->wp_offset) - goto err; + return false; } /* Advance the zone write pointer offset. */ zwplug->wp_offset += bio_sectors(bio); return true; - -err: - /* We detected an invalid write BIO: schedule error recovery. */ - disk_zone_wplug_set_error(disk, zwplug); - kblockd_schedule_work(&disk->zone_wplugs_work); - return false; } static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) @@ -963,7 +988,7 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) } /* Conventional zones do not need write plugging. */ - if (disk_zone_is_conv(disk, sector)) { + if (!bdev_zone_is_seq(bio->bi_bdev, sector)) { /* Zone append to conventional zones is not allowed. */ if (bio_op(bio) == REQ_OP_ZONE_APPEND) { bio_io_error(bio); @@ -977,7 +1002,10 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) zwplug = disk_get_and_lock_zone_wplug(disk, sector, gfp_mask, &flags); if (!zwplug) { - bio_io_error(bio); + if (bio->bi_opf & REQ_NOWAIT) + bio_wouldblock_error(bio); + else + bio_io_error(bio); return true; } @@ -985,18 +1013,20 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) bio_set_flag(bio, BIO_ZONE_WRITE_PLUGGING); /* - * If the zone is already plugged or has a pending error, add the BIO - * to the plug BIO list. Otherwise, plug and let the BIO execute. + * If the zone is already plugged, add the BIO to the plug BIO list. + * Do the same for REQ_NOWAIT BIOs to ensure that we will not see a + * BLK_STS_AGAIN failure if we let the BIO execute. + * Otherwise, plug and let the BIO execute. */ - if (zwplug->flags & BLK_ZONE_WPLUG_BUSY) + if ((zwplug->flags & BLK_ZONE_WPLUG_PLUGGED) || + (bio->bi_opf & REQ_NOWAIT)) goto plug; - /* - * If an error is detected when preparing the BIO, add it to the BIO - * list so that error recovery can deal with it. - */ - if (!blk_zone_wplug_prepare_bio(zwplug, bio)) - goto plug; + if (!blk_zone_wplug_prepare_bio(zwplug, bio)) { + spin_unlock_irqrestore(&zwplug->lock, flags); + bio_io_error(bio); + return true; + } zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; @@ -1005,8 +1035,7 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) return false; plug: - zwplug->flags |= BLK_ZONE_WPLUG_PLUGGED; - blk_zone_wplug_add_bio(zwplug, bio, nr_segs); + disk_zone_wplug_add_bio(disk, zwplug, bio, nr_segs); spin_unlock_irqrestore(&zwplug->lock, flags); @@ -1090,19 +1119,6 @@ bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs) } EXPORT_SYMBOL_GPL(blk_zone_plug_bio); -static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk, - struct blk_zone_wplug *zwplug) -{ - /* - * Take a reference on the zone write plug and schedule the submission - * of the next plugged BIO. blk_zone_wplug_bio_work() will release the - * reference we take here. - */ - WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)); - atomic_inc(&zwplug->ref); - queue_work(disk->zone_wplugs_wq, &zwplug->bio_work); -} - static void disk_zone_wplug_unplug_bio(struct gendisk *disk, struct blk_zone_wplug *zwplug) { @@ -1110,16 +1126,6 @@ static void disk_zone_wplug_unplug_bio(struct gendisk *disk, spin_lock_irqsave(&zwplug->lock, flags); - /* - * If we had an error, schedule error recovery. The recovery work - * will restart submission of plugged BIOs. - */ - if (zwplug->flags & BLK_ZONE_WPLUG_ERROR) { - spin_unlock_irqrestore(&zwplug->lock, flags); - kblockd_schedule_work(&disk->zone_wplugs_work); - return; - } - /* Schedule submission of the next plugged BIO if we have one. */ if (!bio_list_empty(&zwplug->bio_list)) { disk_zone_wplug_schedule_bio_work(disk, zwplug); @@ -1162,12 +1168,13 @@ void blk_zone_write_plug_bio_endio(struct bio *bio) } /* - * If the BIO failed, mark the plug as having an error to trigger - * recovery. + * If the BIO failed, abort all plugged BIOs and mark the plug as + * needing a write pointer update. */ if (bio->bi_status != BLK_STS_OK) { spin_lock_irqsave(&zwplug->lock, flags); - disk_zone_wplug_set_error(disk, zwplug); + disk_zone_wplug_abort(zwplug); + zwplug->flags |= BLK_ZONE_WPLUG_NEED_WP_UPDATE; spin_unlock_irqrestore(&zwplug->lock, flags); } @@ -1223,6 +1230,7 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) */ spin_lock_irqsave(&zwplug->lock, flags); +again: bio = bio_list_pop(&zwplug->bio_list); if (!bio) { zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; @@ -1231,10 +1239,8 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) } if (!blk_zone_wplug_prepare_bio(zwplug, bio)) { - /* Error recovery will decide what to do with the BIO. */ - bio_list_add_head(&zwplug->bio_list, bio); - spin_unlock_irqrestore(&zwplug->lock, flags); - goto put_zwplug; + blk_zone_wplug_bio_io_error(zwplug, bio); + goto again; } spin_unlock_irqrestore(&zwplug->lock, flags); @@ -1256,120 +1262,6 @@ static void blk_zone_wplug_bio_work(struct work_struct *work) disk_put_zone_wplug(zwplug); } -static unsigned int blk_zone_wp_offset(struct blk_zone *zone) -{ - switch (zone->cond) { - case BLK_ZONE_COND_IMP_OPEN: - case BLK_ZONE_COND_EXP_OPEN: - case BLK_ZONE_COND_CLOSED: - return zone->wp - zone->start; - case BLK_ZONE_COND_FULL: - return zone->len; - case BLK_ZONE_COND_EMPTY: - return 0; - case BLK_ZONE_COND_NOT_WP: - case BLK_ZONE_COND_OFFLINE: - case BLK_ZONE_COND_READONLY: - default: - /* - * Conventional, offline and read-only zones do not have a valid - * write pointer. - */ - return UINT_MAX; - } -} - -static int blk_zone_wplug_report_zone_cb(struct blk_zone *zone, - unsigned int idx, void *data) -{ - struct blk_zone *zonep = data; - - *zonep = *zone; - return 0; -} - -static void disk_zone_wplug_handle_error(struct gendisk *disk, - struct blk_zone_wplug *zwplug) -{ - sector_t zone_start_sector = - bdev_zone_sectors(disk->part0) * zwplug->zone_no; - unsigned int noio_flag; - struct blk_zone zone; - unsigned long flags; - int ret; - - /* Get the current zone information from the device. */ - noio_flag = memalloc_noio_save(); - ret = disk->fops->report_zones(disk, zone_start_sector, 1, - blk_zone_wplug_report_zone_cb, &zone); - memalloc_noio_restore(noio_flag); - - spin_lock_irqsave(&zwplug->lock, flags); - - /* - * A zone reset or finish may have cleared the error already. In such - * case, do nothing as the report zones may have seen the "old" write - * pointer value before the reset/finish operation completed. - */ - if (!(zwplug->flags & BLK_ZONE_WPLUG_ERROR)) - goto unlock; - - zwplug->flags &= ~BLK_ZONE_WPLUG_ERROR; - - if (ret != 1) { - /* - * We failed to get the zone information, meaning that something - * is likely really wrong with the device. Abort all remaining - * plugged BIOs as otherwise we could endup waiting forever on - * plugged BIOs to complete if there is a queue freeze on-going. - */ - disk_zone_wplug_abort(zwplug); - goto unplug; - } - - /* Update the zone write pointer offset. */ - zwplug->wp_offset = blk_zone_wp_offset(&zone); - disk_zone_wplug_abort_unaligned(disk, zwplug); - - /* Restart BIO submission if we still have any BIO left. */ - if (!bio_list_empty(&zwplug->bio_list)) { - disk_zone_wplug_schedule_bio_work(disk, zwplug); - goto unlock; - } - -unplug: - zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED; - if (disk_should_remove_zone_wplug(disk, zwplug)) - disk_remove_zone_wplug(disk, zwplug); - -unlock: - spin_unlock_irqrestore(&zwplug->lock, flags); -} - -static void disk_zone_wplugs_work(struct work_struct *work) -{ - struct gendisk *disk = - container_of(work, struct gendisk, zone_wplugs_work); - struct blk_zone_wplug *zwplug; - unsigned long flags; - - spin_lock_irqsave(&disk->zone_wplugs_lock, flags); - - while (!list_empty(&disk->zone_wplugs_err_list)) { - zwplug = list_first_entry(&disk->zone_wplugs_err_list, - struct blk_zone_wplug, link); - list_del_init(&zwplug->link); - spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); - - disk_zone_wplug_handle_error(disk, zwplug); - disk_put_zone_wplug(zwplug); - - spin_lock_irqsave(&disk->zone_wplugs_lock, flags); - } - - spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); -} - static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) { return 1U << disk->zone_wplugs_hash_bits; @@ -1378,8 +1270,6 @@ static inline unsigned int disk_zone_wplugs_hash_size(struct gendisk *disk) void disk_init_zone_resources(struct gendisk *disk) { spin_lock_init(&disk->zone_wplugs_lock); - INIT_LIST_HEAD(&disk->zone_wplugs_err_list); - INIT_WORK(&disk->zone_wplugs_work, disk_zone_wplugs_work); } /* @@ -1444,7 +1334,7 @@ static void disk_destroy_zone_wplugs_hash_table(struct gendisk *disk) while (!hlist_empty(&disk->zone_wplugs_hash[i])) { zwplug = hlist_entry(disk->zone_wplugs_hash[i].first, struct blk_zone_wplug, node); - atomic_inc(&zwplug->ref); + refcount_inc(&zwplug->ref); disk_remove_zone_wplug(disk, zwplug); disk_put_zone_wplug(zwplug); } @@ -1455,13 +1345,29 @@ static void disk_destroy_zone_wplugs_hash_table(struct gendisk *disk) disk->zone_wplugs_hash_bits = 0; } +static unsigned int disk_set_conv_zones_bitmap(struct gendisk *disk, + unsigned long *bitmap) +{ + unsigned int nr_conv_zones = 0; + unsigned long flags; + + spin_lock_irqsave(&disk->zone_wplugs_lock, flags); + if (bitmap) + nr_conv_zones = bitmap_weight(bitmap, disk->nr_zones); + bitmap = rcu_replace_pointer(disk->conv_zones_bitmap, bitmap, + lockdep_is_held(&disk->zone_wplugs_lock)); + spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags); + + kfree_rcu_mightsleep(bitmap); + + return nr_conv_zones; +} + void disk_free_zone_resources(struct gendisk *disk) { if (!disk->zone_wplugs_pool) return; - cancel_work_sync(&disk->zone_wplugs_work); - if (disk->zone_wplugs_wq) { destroy_workqueue(disk->zone_wplugs_wq); disk->zone_wplugs_wq = NULL; @@ -1478,8 +1384,7 @@ void disk_free_zone_resources(struct gendisk *disk) mempool_destroy(disk->zone_wplugs_pool); disk->zone_wplugs_pool = NULL; - bitmap_free(disk->conv_zones_bitmap); - disk->conv_zones_bitmap = NULL; + disk_set_conv_zones_bitmap(disk, NULL); disk->zone_capacity = 0; disk->last_zone_capacity = 0; disk->nr_zones = 0; @@ -1538,17 +1443,16 @@ static int disk_update_zone_resources(struct gendisk *disk, struct blk_revalidate_zone_args *args) { struct request_queue *q = disk->queue; - unsigned int nr_seq_zones, nr_conv_zones = 0; + unsigned int nr_seq_zones, nr_conv_zones; unsigned int pool_size; struct queue_limits lim; + int ret; disk->nr_zones = args->nr_zones; disk->zone_capacity = args->zone_capacity; disk->last_zone_capacity = args->last_zone_capacity; - swap(disk->conv_zones_bitmap, args->conv_zones_bitmap); - if (disk->conv_zones_bitmap) - nr_conv_zones = bitmap_weight(disk->conv_zones_bitmap, - disk->nr_zones); + nr_conv_zones = + disk_set_conv_zones_bitmap(disk, args->conv_zones_bitmap); if (nr_conv_zones >= disk->nr_zones) { pr_warn("%s: Invalid number of conventional zones %u / %u\n", disk->disk_name, nr_conv_zones, disk->nr_zones); @@ -1593,7 +1497,11 @@ static int disk_update_zone_resources(struct gendisk *disk, } commit: - return queue_limits_commit_update(q, &lim); + blk_mq_freeze_queue(q); + ret = queue_limits_commit_update(q, &lim); + blk_mq_unfreeze_queue(q); + + return ret; } static int blk_revalidate_conv_zone(struct blk_zone *zone, unsigned int idx, @@ -1656,6 +1564,8 @@ static int blk_revalidate_seq_zone(struct blk_zone *zone, unsigned int idx, if (!disk->zone_wplugs_hash) return 0; + disk_zone_wplug_sync_wp_offset(disk, zone); + wp_offset = blk_zone_wp_offset(zone); if (!wp_offset || wp_offset >= zone->capacity) return 0; @@ -1774,12 +1684,6 @@ int blk_revalidate_disk_zones(struct gendisk *disk) return -ENODEV; } - if (!queue_max_zone_append_sectors(q)) { - pr_warn("%s: Invalid 0 maximum zone append limit\n", - disk->disk_name); - return -ENODEV; - } - /* * Ensure that all memory allocations in this context are done as if * GFP_NOIO was specified. @@ -1792,6 +1696,7 @@ int blk_revalidate_disk_zones(struct gendisk *disk) memalloc_noio_restore(noio_flag); return ret; } + ret = disk->fops->report_zones(disk, 0, UINT_MAX, blk_revalidate_zone_cb, &args); if (!ret) { @@ -1814,21 +1719,62 @@ int blk_revalidate_disk_zones(struct gendisk *disk) * Set the new disk zone parameters only once the queue is frozen and * all I/Os are completed. */ - blk_mq_freeze_queue(q); if (ret > 0) ret = disk_update_zone_resources(disk, &args); else pr_warn("%s: failed to revalidate zones\n", disk->disk_name); - if (ret) + if (ret) { + blk_mq_freeze_queue(q); disk_free_zone_resources(disk); - blk_mq_unfreeze_queue(q); - - kfree(args.conv_zones_bitmap); + blk_mq_unfreeze_queue(q); + } return ret; } EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones); +/** + * blk_zone_issue_zeroout - zero-fill a block range in a zone + * @bdev: blockdev to write + * @sector: start sector + * @nr_sects: number of sectors to write + * @gfp_mask: memory allocation flags (for bio_alloc) + * + * Description: + * Zero-fill a block range in a zone (@sector must be equal to the zone write + * pointer), handling potential errors due to the (initially unknown) lack of + * hardware offload (See blkdev_issue_zeroout()). + */ +int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector, + sector_t nr_sects, gfp_t gfp_mask) +{ + int ret; + + if (WARN_ON_ONCE(!bdev_is_zoned(bdev))) + return -EIO; + + ret = blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask, + BLKDEV_ZERO_NOFALLBACK); + if (ret != -EOPNOTSUPP) + return ret; + + /* + * The failed call to blkdev_issue_zeroout() advanced the zone write + * pointer. Undo this using a report zone to update the zone write + * pointer to the correct current value. + */ + ret = disk_zone_sync_wp_offset(bdev->bd_disk, sector); + if (ret != 1) + return ret < 0 ? ret : -EIO; + + /* + * Retry without BLKDEV_ZERO_NOFALLBACK to force the fallback to a + * regular write with zero-pages. + */ + return blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask, 0); +} +EXPORT_SYMBOL_GPL(blk_zone_issue_zeroout); + #ifdef CONFIG_BLK_DEBUG_FS int queue_zone_wplugs_show(void *data, struct seq_file *m) @@ -1851,7 +1797,7 @@ int queue_zone_wplugs_show(void *data, struct seq_file *m) spin_lock_irqsave(&zwplug->lock, flags); zwp_zone_no = zwplug->zone_no; zwp_flags = zwplug->flags; - zwp_ref = atomic_read(&zwplug->ref); + zwp_ref = refcount_read(&zwplug->ref); zwp_wp_offset = zwplug->wp_offset; zwp_bio_list_size = bio_list_size(&zwplug->bio_list); spin_unlock_irqrestore(&zwplug->lock, flags); diff --git a/block/blk.h b/block/blk.h index c718e4291db062..2c26abf505b877 100644 --- a/block/blk.h +++ b/block/blk.h @@ -4,6 +4,7 @@ #include #include +#include #include /* for max_pfn/max_low_pfn */ #include #include @@ -34,9 +35,10 @@ struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size, gfp_t flags); void blk_free_flush_queue(struct blk_flush_queue *q); -void blk_freeze_queue(struct request_queue *q); -void __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic); -void blk_queue_start_drain(struct request_queue *q); +bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic); +bool blk_queue_start_drain(struct request_queue *q); +bool __blk_freeze_queue_start(struct request_queue *q, + struct task_struct *owner); int __bio_queue_enter(struct request_queue *q, struct bio *bio); void submit_bio_noacct_nocheck(struct bio *bio); void bio_await_chain(struct bio *bio); @@ -69,8 +71,11 @@ static inline int bio_queue_enter(struct bio *bio) { struct request_queue *q = bdev_get_queue(bio->bi_bdev); - if (blk_try_enter_queue(q, false)) + if (blk_try_enter_queue(q, false)) { + rwsem_acquire_read(&q->io_lockdep_map, 0, 0, _RET_IP_); + rwsem_release(&q->io_lockdep_map, _RET_IP_); return 0; + } return __bio_queue_enter(q, bio); } @@ -405,17 +410,6 @@ void blk_apply_bdi_limits(struct backing_dev_info *bdi, struct queue_limits *lim); int blk_dev_init(void); -/* - * Contribute to IO statistics IFF: - * - * a) it's attached to a gendisk, and - * b) the queue had IO stats enabled when this request was started - */ -static inline bool blk_do_io_stat(struct request *rq) -{ - return (rq->rq_flags & RQF_IO_STAT) && !blk_rq_is_passthrough(rq); -} - void update_io_ticks(struct block_device *part, unsigned long now, bool end); unsigned int part_in_flight(struct block_device *part); @@ -463,11 +457,6 @@ static inline bool bio_zone_write_plugging(struct bio *bio) { return bio_flagged(bio, BIO_ZONE_WRITE_PLUGGING); } -static inline bool bio_is_zone_append(struct bio *bio) -{ - return bio_op(bio) == REQ_OP_ZONE_APPEND || - bio_flagged(bio, BIO_EMULATES_ZONE_APPEND); -} void blk_zone_write_plug_bio_merged(struct bio *bio); void blk_zone_write_plug_init_request(struct request *rq); static inline void blk_zone_update_request_bio(struct request *rq, @@ -516,10 +505,6 @@ static inline bool bio_zone_write_plugging(struct bio *bio) { return false; } -static inline bool bio_is_zone_append(struct bio *bio) -{ - return false; -} static inline void blk_zone_write_plug_bio_merged(struct bio *bio) { } @@ -558,6 +543,7 @@ void blk_free_ext_minor(unsigned int minor); #define ADDPART_FLAG_NONE 0 #define ADDPART_FLAG_RAID 1 #define ADDPART_FLAG_WHOLEDISK 2 +#define ADDPART_FLAG_READONLY 4 int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, sector_t length); int bdev_del_partition(struct gendisk *disk, int partno); @@ -734,4 +720,22 @@ void blk_integrity_verify(struct bio *bio); void blk_integrity_prepare(struct request *rq); void blk_integrity_complete(struct request *rq, unsigned int nr_bytes); +static inline void blk_freeze_acquire_lock(struct request_queue *q, bool + disk_dead, bool queue_dying) +{ + if (!disk_dead) + rwsem_acquire(&q->io_lockdep_map, 0, 1, _RET_IP_); + if (!queue_dying) + rwsem_acquire(&q->q_lockdep_map, 0, 1, _RET_IP_); +} + +static inline void blk_unfreeze_release_lock(struct request_queue *q, bool + disk_dead, bool queue_dying) +{ + if (!queue_dying) + rwsem_release(&q->q_lockdep_map, _RET_IP_); + if (!disk_dead) + rwsem_release(&q->io_lockdep_map, _RET_IP_); +} + #endif /* BLK_INTERNAL_H */ diff --git a/block/elevator.c b/block/elevator.c index 9430cde13d1a41..7c3ba80e5ff4a3 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -598,13 +598,19 @@ void elevator_init_mq(struct request_queue *q) * drain any dispatch activities originated from passthrough * requests, then no need to quiesce queue which may add long boot * latency, especially when lots of disks are involved. + * + * Disk isn't added yet, so verifying queue lock only manually. */ - blk_mq_freeze_queue(q); + blk_freeze_queue_start_non_owner(q); + blk_freeze_acquire_lock(q, true, false); + blk_mq_freeze_queue_wait(q); + blk_mq_cancel_work_sync(q); err = blk_mq_init_sched(q, e); - blk_mq_unfreeze_queue(q); + blk_unfreeze_release_lock(q, true, false); + blk_mq_unfreeze_queue_non_owner(q); if (err) { pr_warn("\"%s\" elevator initialization failed, " @@ -704,15 +710,15 @@ static int elevator_change(struct request_queue *q, const char *elevator_name) return ret; } -int elv_iosched_load_module(struct gendisk *disk, const char *buf, - size_t count) +void elv_iosched_load_module(struct gendisk *disk, const char *buf, + size_t count) { char elevator_name[ELV_NAME_MAX]; struct elevator_type *found; const char *name; if (!elv_support_iosched(disk->queue)) - return -EOPNOTSUPP; + return; strscpy(elevator_name, buf, sizeof(elevator_name)); name = strstrip(elevator_name); @@ -723,8 +729,6 @@ int elv_iosched_load_module(struct gendisk *disk, const char *buf, if (!found) request_module("%s-iosched", name); - - return 0; } ssize_t elv_iosched_store(struct gendisk *disk, const char *buf, diff --git a/block/elevator.h b/block/elevator.h index 2a78544bf20180..dbf357ef4fab93 100644 --- a/block/elevator.h +++ b/block/elevator.h @@ -148,8 +148,8 @@ extern void elv_unregister(struct elevator_type *); * io scheduler sysfs switching */ ssize_t elv_iosched_show(struct gendisk *disk, char *page); -int elv_iosched_load_module(struct gendisk *disk, const char *page, - size_t count); +void elv_iosched_load_module(struct gendisk *disk, const char *page, + size_t count); ssize_t elv_iosched_store(struct gendisk *disk, const char *page, size_t count); extern bool elv_bio_merge_ok(struct request *, struct bio *); diff --git a/block/fops.c b/block/fops.c index e696ae53bf1e08..13a67940d0408d 100644 --- a/block/fops.c +++ b/block/fops.c @@ -35,13 +35,10 @@ static blk_opf_t dio_bio_write_op(struct kiocb *iocb) return opf; } -static bool blkdev_dio_invalid(struct block_device *bdev, loff_t pos, - struct iov_iter *iter, bool is_atomic) +static bool blkdev_dio_invalid(struct block_device *bdev, struct kiocb *iocb, + struct iov_iter *iter) { - if (is_atomic && !generic_atomic_write_valid(iter, pos)) - return true; - - return pos & (bdev_logical_block_size(bdev) - 1) || + return iocb->ki_pos & (bdev_logical_block_size(bdev) - 1) || !bdev_iter_is_aligned(bdev, iter); } @@ -368,13 +365,12 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb, static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter) { struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host); - bool is_atomic = iocb->ki_flags & IOCB_ATOMIC; unsigned int nr_pages; if (!iov_iter_count(iter)) return 0; - if (blkdev_dio_invalid(bdev, iocb->ki_pos, iter, is_atomic)) + if (blkdev_dio_invalid(bdev, iocb, iter)) return -EINVAL; nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1); @@ -383,7 +379,7 @@ static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter) return __blkdev_direct_IO_simple(iocb, iter, bdev, nr_pages); return __blkdev_direct_IO_async(iocb, iter, bdev, nr_pages); - } else if (is_atomic) { + } else if (iocb->ki_flags & IOCB_ATOMIC) { return -EINVAL; } return __blkdev_direct_IO(iocb, iter, bdev, bio_max_segs(nr_pages)); @@ -625,7 +621,7 @@ static int blkdev_open(struct inode *inode, struct file *filp) if (!bdev) return -ENXIO; - if (bdev_can_atomic_write(bdev) && filp->f_flags & O_DIRECT) + if (bdev_can_atomic_write(bdev)) filp->f_mode |= FMODE_CAN_ATOMIC_WRITE; ret = bdev_open(bdev, mode, filp->private_data, NULL, filp); @@ -681,6 +677,7 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) struct file *file = iocb->ki_filp; struct inode *bd_inode = bdev_file_inode(file); struct block_device *bdev = I_BDEV(bd_inode); + bool atomic = iocb->ki_flags & IOCB_ATOMIC; loff_t size = bdev_nr_bytes(bdev); size_t shorted = 0; ssize_t ret; @@ -700,8 +697,16 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) if ((iocb->ki_flags & (IOCB_NOWAIT | IOCB_DIRECT)) == IOCB_NOWAIT) return -EOPNOTSUPP; + if (atomic) { + ret = generic_atomic_write_valid(iocb, from); + if (ret) + return ret; + } + size -= iocb->ki_pos; if (iov_iter_count(from) > size) { + if (atomic) + return -EINVAL; shorted = iov_iter_count(from) - size; iov_iter_truncate(from, size); } diff --git a/block/genhd.c b/block/genhd.c index 1c05dd4c6980b5..79230c109fca03 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -383,16 +383,18 @@ int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode) } /** - * device_add_disk - add disk information to kernel list + * add_disk_fwnode - add disk information to kernel list with fwnode * @parent: parent device for the disk * @disk: per-device partitioning information * @groups: Additional per-device sysfs groups + * @fwnode: attached disk fwnode * * This function registers the partitioning information in @disk - * with the kernel. + * with the kernel. Also attach a fwnode to the disk device. */ -int __must_check device_add_disk(struct device *parent, struct gendisk *disk, - const struct attribute_group **groups) +int __must_check add_disk_fwnode(struct device *parent, struct gendisk *disk, + const struct attribute_group **groups, + struct fwnode_handle *fwnode) { struct device *ddev = disk_to_dev(disk); @@ -452,6 +454,8 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, ddev->parent = parent; ddev->groups = groups; dev_set_name(ddev, "%s", disk->disk_name); + if (fwnode) + device_set_node(ddev, fwnode); if (!(disk->flags & GENHD_FL_HIDDEN)) ddev->devt = MKDEV(disk->major, disk->first_minor); ret = device_add(ddev); @@ -553,6 +557,22 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, elevator_exit(disk->queue); return ret; } +EXPORT_SYMBOL_GPL(add_disk_fwnode); + +/** + * device_add_disk - add disk information to kernel list + * @parent: parent device for the disk + * @disk: per-device partitioning information + * @groups: Additional per-device sysfs groups + * + * This function registers the partitioning information in @disk + * with the kernel. + */ +int __must_check device_add_disk(struct device *parent, struct gendisk *disk, + const struct attribute_group **groups) +{ + return add_disk_fwnode(parent, disk, groups, NULL); +} EXPORT_SYMBOL(device_add_disk); static void blk_report_disk_dead(struct gendisk *disk, bool surprise) @@ -581,13 +601,13 @@ static void blk_report_disk_dead(struct gendisk *disk, bool surprise) rcu_read_unlock(); } -static void __blk_mark_disk_dead(struct gendisk *disk) +static bool __blk_mark_disk_dead(struct gendisk *disk) { /* * Fail any new I/O. */ if (test_and_set_bit(GD_DEAD, &disk->state)) - return; + return false; if (test_bit(GD_OWNS_QUEUE, &disk->state)) blk_queue_flag_set(QUEUE_FLAG_DYING, disk->queue); @@ -600,7 +620,7 @@ static void __blk_mark_disk_dead(struct gendisk *disk) /* * Prevent new I/O from crossing bio_queue_enter(). */ - blk_queue_start_drain(disk->queue); + return blk_queue_start_drain(disk->queue); } /** @@ -641,6 +661,7 @@ void del_gendisk(struct gendisk *disk) struct request_queue *q = disk->queue; struct block_device *part; unsigned long idx; + bool start_drain, queue_dying; might_sleep(); @@ -668,7 +689,10 @@ void del_gendisk(struct gendisk *disk) * Drop all partitions now that the disk is marked dead. */ mutex_lock(&disk->open_mutex); - __blk_mark_disk_dead(disk); + start_drain = __blk_mark_disk_dead(disk); + queue_dying = blk_queue_dying(q); + if (start_drain) + blk_freeze_acquire_lock(q, true, queue_dying); xa_for_each_start(&disk->part_tbl, idx, part, 1) drop_partition(part); mutex_unlock(&disk->open_mutex); @@ -718,13 +742,13 @@ void del_gendisk(struct gendisk *disk) * If the disk does not own the queue, allow using passthrough requests * again. Else leave the queue frozen to fail all I/O. */ - if (!test_bit(GD_OWNS_QUEUE, &disk->state)) { - blk_queue_flag_clear(QUEUE_FLAG_INIT_DONE, q); + if (!test_bit(GD_OWNS_QUEUE, &disk->state)) __blk_mq_unfreeze_queue(q, true); - } else { - if (queue_is_mq(q)) - blk_mq_exit_queue(q); - } + else if (queue_is_mq(q)) + blk_mq_exit_queue(q); + + if (start_drain) + blk_unfreeze_release_lock(q, true, queue_dying); } EXPORT_SYMBOL(del_gendisk); @@ -756,7 +780,7 @@ static ssize_t disk_badblocks_show(struct device *dev, struct gendisk *disk = dev_to_disk(dev); if (!disk->bb) - return sprintf(page, "\n"); + return sysfs_emit(page, "\n"); return badblocks_show(disk->bb, page, 0); } @@ -904,7 +928,7 @@ static ssize_t disk_range_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%d\n", disk->minors); + return sysfs_emit(buf, "%d\n", disk->minors); } static ssize_t disk_ext_range_show(struct device *dev, @@ -912,7 +936,7 @@ static ssize_t disk_ext_range_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%d\n", + return sysfs_emit(buf, "%d\n", (disk->flags & GENHD_FL_NO_PART) ? 1 : DISK_MAX_PARTS); } @@ -921,7 +945,7 @@ static ssize_t disk_removable_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%d\n", + return sysfs_emit(buf, "%d\n", (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); } @@ -930,7 +954,7 @@ static ssize_t disk_hidden_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%d\n", + return sysfs_emit(buf, "%d\n", (disk->flags & GENHD_FL_HIDDEN ? 1 : 0)); } @@ -939,13 +963,13 @@ static ssize_t disk_ro_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%d\n", get_disk_ro(disk) ? 1 : 0); + return sysfs_emit(buf, "%d\n", get_disk_ro(disk) ? 1 : 0); } ssize_t part_size_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%llu\n", bdev_nr_sectors(dev_to_bdev(dev))); + return sysfs_emit(buf, "%llu\n", bdev_nr_sectors(dev_to_bdev(dev))); } ssize_t part_stat_show(struct device *dev, @@ -962,7 +986,7 @@ ssize_t part_stat_show(struct device *dev, part_stat_unlock(); } part_stat_read_all(bdev, &stat); - return sprintf(buf, + return sysfs_emit(buf, "%8lu %8lu %8llu %8u " "%8lu %8lu %8llu %8u " "%8u %8u %8u " @@ -1004,14 +1028,14 @@ ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr, else part_in_flight_rw(bdev, inflight); - return sprintf(buf, "%8u %8u\n", inflight[0], inflight[1]); + return sysfs_emit(buf, "%8u %8u\n", inflight[0], inflight[1]); } static ssize_t disk_capability_show(struct device *dev, struct device_attribute *attr, char *buf) { dev_warn_once(dev, "the capability attribute has been deprecated.\n"); - return sprintf(buf, "0\n"); + return sysfs_emit(buf, "0\n"); } static ssize_t disk_alignment_offset_show(struct device *dev, @@ -1020,7 +1044,7 @@ static ssize_t disk_alignment_offset_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%d\n", bdev_alignment_offset(disk->part0)); + return sysfs_emit(buf, "%d\n", bdev_alignment_offset(disk->part0)); } static ssize_t disk_discard_alignment_show(struct device *dev, @@ -1029,7 +1053,7 @@ static ssize_t disk_discard_alignment_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%d\n", bdev_alignment_offset(disk->part0)); + return sysfs_emit(buf, "%d\n", bdev_alignment_offset(disk->part0)); } static ssize_t diskseq_show(struct device *dev, @@ -1037,13 +1061,13 @@ static ssize_t diskseq_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%llu\n", disk->diskseq); + return sysfs_emit(buf, "%llu\n", disk->diskseq); } static ssize_t partscan_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", disk_has_partscan(dev_to_disk(dev))); + return sysfs_emit(buf, "%u\n", disk_has_partscan(dev_to_disk(dev))); } static DEVICE_ATTR(range, 0444, disk_range_show, NULL); @@ -1065,7 +1089,7 @@ static DEVICE_ATTR(partscan, 0444, partscan_show, NULL); ssize_t part_fail_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", + return sysfs_emit(buf, "%d\n", bdev_test_flag(dev_to_bdev(dev), BD_MAKE_IT_FAIL)); } @@ -1264,40 +1288,35 @@ static int diskstats_show(struct seq_file *seqf, void *v) part_stat_unlock(); } part_stat_read_all(hd, &stat); - seq_printf(seqf, "%4d %7d %pg " - "%lu %lu %lu %u " - "%lu %lu %lu %u " - "%u %u %u " - "%lu %lu %lu %u " - "%lu %u" - "\n", - MAJOR(hd->bd_dev), MINOR(hd->bd_dev), hd, - stat.ios[STAT_READ], - stat.merges[STAT_READ], - stat.sectors[STAT_READ], - (unsigned int)div_u64(stat.nsecs[STAT_READ], - NSEC_PER_MSEC), - stat.ios[STAT_WRITE], - stat.merges[STAT_WRITE], - stat.sectors[STAT_WRITE], - (unsigned int)div_u64(stat.nsecs[STAT_WRITE], - NSEC_PER_MSEC), - inflight, - jiffies_to_msecs(stat.io_ticks), - (unsigned int)div_u64(stat.nsecs[STAT_READ] + - stat.nsecs[STAT_WRITE] + - stat.nsecs[STAT_DISCARD] + - stat.nsecs[STAT_FLUSH], - NSEC_PER_MSEC), - stat.ios[STAT_DISCARD], - stat.merges[STAT_DISCARD], - stat.sectors[STAT_DISCARD], - (unsigned int)div_u64(stat.nsecs[STAT_DISCARD], - NSEC_PER_MSEC), - stat.ios[STAT_FLUSH], - (unsigned int)div_u64(stat.nsecs[STAT_FLUSH], - NSEC_PER_MSEC) - ); + seq_put_decimal_ull_width(seqf, "", MAJOR(hd->bd_dev), 4); + seq_put_decimal_ull_width(seqf, " ", MINOR(hd->bd_dev), 7); + seq_printf(seqf, " %pg", hd); + seq_put_decimal_ull(seqf, " ", stat.ios[STAT_READ]); + seq_put_decimal_ull(seqf, " ", stat.merges[STAT_READ]); + seq_put_decimal_ull(seqf, " ", stat.sectors[STAT_READ]); + seq_put_decimal_ull(seqf, " ", (unsigned int)div_u64(stat.nsecs[STAT_READ], + NSEC_PER_MSEC)); + seq_put_decimal_ull(seqf, " ", stat.ios[STAT_WRITE]); + seq_put_decimal_ull(seqf, " ", stat.merges[STAT_WRITE]); + seq_put_decimal_ull(seqf, " ", stat.sectors[STAT_WRITE]); + seq_put_decimal_ull(seqf, " ", (unsigned int)div_u64(stat.nsecs[STAT_WRITE], + NSEC_PER_MSEC)); + seq_put_decimal_ull(seqf, " ", inflight); + seq_put_decimal_ull(seqf, " ", jiffies_to_msecs(stat.io_ticks)); + seq_put_decimal_ull(seqf, " ", (unsigned int)div_u64(stat.nsecs[STAT_READ] + + stat.nsecs[STAT_WRITE] + + stat.nsecs[STAT_DISCARD] + + stat.nsecs[STAT_FLUSH], + NSEC_PER_MSEC)); + seq_put_decimal_ull(seqf, " ", stat.ios[STAT_DISCARD]); + seq_put_decimal_ull(seqf, " ", stat.merges[STAT_DISCARD]); + seq_put_decimal_ull(seqf, " ", stat.sectors[STAT_DISCARD]); + seq_put_decimal_ull(seqf, " ", (unsigned int)div_u64(stat.nsecs[STAT_DISCARD], + NSEC_PER_MSEC)); + seq_put_decimal_ull(seqf, " ", stat.ios[STAT_FLUSH]); + seq_put_decimal_ull(seqf, " ", (unsigned int)div_u64(stat.nsecs[STAT_FLUSH], + NSEC_PER_MSEC)); + seq_putc(seqf, '\n'); } rcu_read_unlock(); diff --git a/block/mq-deadline.c b/block/mq-deadline.c index acdc28756d9d77..5528347b5fcfca 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -685,10 +685,9 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq, prio = ioprio_class_to_prio[ioprio_class]; per_prio = &dd->per_prio[prio]; - if (!rq->elv.priv[0]) { + if (!rq->elv.priv[0]) per_prio->stats.inserted++; - rq->elv.priv[0] = (void *)(uintptr_t)1; - } + rq->elv.priv[0] = per_prio; if (blk_mq_sched_try_insert_merge(q, rq, free)) return; @@ -699,8 +698,6 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq, list_add(&rq->queuelist, &per_prio->dispatch); rq->fifo_time = jiffies; } else { - struct list_head *insert_before; - deadline_add_rq_rb(per_prio, rq); if (rq_mergeable(rq)) { @@ -713,8 +710,7 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq, * set expire time and add to fifo list */ rq->fifo_time = jiffies + dd->fifo_expire[data_dir]; - insert_before = &per_prio->fifo_list[data_dir]; - list_add_tail(&rq->queuelist, insert_before); + list_add_tail(&rq->queuelist, &per_prio->fifo_list[data_dir]); } } @@ -753,18 +749,14 @@ static void dd_prepare_request(struct request *rq) */ static void dd_finish_request(struct request *rq) { - struct request_queue *q = rq->q; - struct deadline_data *dd = q->elevator->elevator_data; - const u8 ioprio_class = dd_rq_ioclass(rq); - const enum dd_prio prio = ioprio_class_to_prio[ioprio_class]; - struct dd_per_prio *per_prio = &dd->per_prio[prio]; + struct dd_per_prio *per_prio = rq->elv.priv[0]; /* * The block layer core may call dd_finish_request() without having * called dd_insert_requests(). Skip requests that bypassed I/O * scheduling. See also blk_mq_request_bypass_insert(). */ - if (rq->elv.priv[0]) + if (per_prio) atomic_inc(&per_prio->stats.completed); } diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig index 7aff4eb81c60f4..ce17e41451afe3 100644 --- a/block/partitions/Kconfig +++ b/block/partitions/Kconfig @@ -270,4 +270,13 @@ config CMDLINE_PARTITION Say Y here if you want to read the partition table from bootargs. The format for the command line is just like mtdparts. +config OF_PARTITION + bool "Device Tree partition support" if PARTITION_ADVANCED + depends on OF + help + Say Y here if you want to enable support for partition table + defined in Device Tree. (mainly for eMMC) + The format for the device tree node is just like MTD fixed-partition + schema. + endmenu diff --git a/block/partitions/Makefile b/block/partitions/Makefile index a7f05cdb02a844..25d424922c6e72 100644 --- a/block/partitions/Makefile +++ b/block/partitions/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o obj-$(CONFIG_MAC_PARTITION) += mac.o obj-$(CONFIG_LDM_PARTITION) += ldm.o obj-$(CONFIG_MSDOS_PARTITION) += msdos.o +obj-$(CONFIG_OF_PARTITION) += of.o obj-$(CONFIG_OSF_PARTITION) += osf.o obj-$(CONFIG_SGI_PARTITION) += sgi.o obj-$(CONFIG_SUN_PARTITION) += sun.o diff --git a/block/partitions/check.h b/block/partitions/check.h index 8d70a880c3720a..e5c1c61eb3532a 100644 --- a/block/partitions/check.h +++ b/block/partitions/check.h @@ -62,6 +62,7 @@ int karma_partition(struct parsed_partitions *state); int ldm_partition(struct parsed_partitions *state); int mac_partition(struct parsed_partitions *state); int msdos_partition(struct parsed_partitions *state); +int of_partition(struct parsed_partitions *state); int osf_partition(struct parsed_partitions *state); int sgi_partition(struct parsed_partitions *state); int sun_partition(struct parsed_partitions *state); diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c index 152c85df92b20e..da3e719d8e51e2 100644 --- a/block/partitions/cmdline.c +++ b/block/partitions/cmdline.c @@ -237,6 +237,9 @@ static int add_part(int slot, struct cmdline_subpart *subpart, put_partition(state, slot, subpart->from >> 9, subpart->size >> 9); + if (subpart->flags & PF_RDONLY) + state->parts[slot].flags |= ADDPART_FLAG_READONLY; + info = &state->parts[slot].info; strscpy(info->volname, subpart->name, sizeof(info->volname)); diff --git a/block/partitions/core.c b/block/partitions/core.c index 5bd7a603092ea9..815ed33caa1b86 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -43,6 +43,9 @@ static int (*const check_part[])(struct parsed_partitions *) = { #ifdef CONFIG_CMDLINE_PARTITION cmdline_partition, #endif +#ifdef CONFIG_OF_PARTITION + of_partition, /* cmdline have priority to OF */ +#endif #ifdef CONFIG_EFI_PARTITION efi_partition, /* this must come before msdos */ #endif @@ -253,6 +256,8 @@ static int part_uevent(const struct device *dev, struct kobj_uevent_env *env) add_uevent_var(env, "PARTN=%u", bdev_partno(part)); if (part->bd_meta_info && part->bd_meta_info->volname[0]) add_uevent_var(env, "PARTNAME=%s", part->bd_meta_info->volname); + if (part->bd_meta_info && part->bd_meta_info->uuid[0]) + add_uevent_var(env, "PARTUUID=%s", part->bd_meta_info->uuid); return 0; } @@ -373,6 +378,9 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, goto out_del; } + if (flags & ADDPART_FLAG_READONLY) + bdev_set_flag(bdev, BD_READ_ONLY); + /* everything is up and running, commence */ err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL); if (err) diff --git a/block/partitions/of.c b/block/partitions/of.c new file mode 100644 index 00000000000000..4e760fdffb3fe7 --- /dev/null +++ b/block/partitions/of.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include "check.h" + +static int validate_of_partition(struct device_node *np, int slot) +{ + u64 offset, size; + int len; + + const __be32 *reg = of_get_property(np, "reg", &len); + int a_cells = of_n_addr_cells(np); + int s_cells = of_n_size_cells(np); + + /* Make sure reg len match the expected addr and size cells */ + if (len / sizeof(*reg) != a_cells + s_cells) + return -EINVAL; + + /* Validate offset conversion from bytes to sectors */ + offset = of_read_number(reg, a_cells); + if (offset % SECTOR_SIZE) + return -EINVAL; + + /* Validate size conversion from bytes to sectors */ + size = of_read_number(reg + a_cells, s_cells); + if (!size || size % SECTOR_SIZE) + return -EINVAL; + + return 0; +} + +static void add_of_partition(struct parsed_partitions *state, int slot, + struct device_node *np) +{ + struct partition_meta_info *info; + char tmp[sizeof(info->volname) + 4]; + const char *partname; + int len; + + const __be32 *reg = of_get_property(np, "reg", &len); + int a_cells = of_n_addr_cells(np); + int s_cells = of_n_size_cells(np); + + /* Convert bytes to sector size */ + u64 offset = of_read_number(reg, a_cells) / SECTOR_SIZE; + u64 size = of_read_number(reg + a_cells, s_cells) / SECTOR_SIZE; + + put_partition(state, slot, offset, size); + + if (of_property_read_bool(np, "read-only")) + state->parts[slot].flags |= ADDPART_FLAG_READONLY; + + /* + * Follow MTD label logic, search for label property, + * fallback to node name if not found. + */ + info = &state->parts[slot].info; + partname = of_get_property(np, "label", &len); + if (!partname) + partname = of_get_property(np, "name", &len); + strscpy(info->volname, partname, sizeof(info->volname)); + + snprintf(tmp, sizeof(tmp), "(%s)", info->volname); + strlcat(state->pp_buf, tmp, PAGE_SIZE); +} + +int of_partition(struct parsed_partitions *state) +{ + struct device *ddev = disk_to_dev(state->disk); + struct device_node *np; + int slot; + + struct device_node *partitions_np = of_node_get(ddev->of_node); + + if (!partitions_np || + !of_device_is_compatible(partitions_np, "fixed-partitions")) + return 0; + + slot = 1; + /* Validate parition offset and size */ + for_each_child_of_node(partitions_np, np) { + if (validate_of_partition(np, slot)) { + of_node_put(np); + of_node_put(partitions_np); + + return -1; + } + + slot++; + } + + slot = 1; + for_each_child_of_node(partitions_np, np) { + if (slot >= state->limit) { + of_node_put(np); + break; + } + + add_of_partition(state, slot, np); + + slot++; + } + + strlcat(state->pp_buf, "\n", PAGE_SIZE); + + return 1; +} diff --git a/block/sed-opal.c b/block/sed-opal.c index 598fd3e7fcc8e2..5a28f23f7f22c8 100644 --- a/block/sed-opal.c +++ b/block/sed-opal.c @@ -3037,6 +3037,29 @@ static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw) return ret; } +static int opal_set_new_sid_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw) +{ + int ret; + struct opal_key *newkey = &opal_pw->new_user_pw.opal_key; + struct opal_key *oldkey = &opal_pw->session.opal_key; + + const struct opal_step pw_steps[] = { + { start_SIDASP_opal_session, oldkey }, + { set_sid_cpin_pin, newkey }, + { end_opal_session, } + }; + + if (!dev) + return -ENODEV; + + mutex_lock(&dev->dev_lock); + setup_opal_dev(dev); + ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps)); + mutex_unlock(&dev->dev_lock); + + return ret; +} + static int opal_activate_user(struct opal_dev *dev, struct opal_session_info *opal_session) { @@ -3286,6 +3309,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg) case IOC_OPAL_DISCOVERY: ret = opal_get_discv(dev, p); break; + case IOC_OPAL_SET_SID_PW: + ret = opal_set_new_sid_pw(dev, p); + break; default: break; diff --git a/crypto/Kconfig b/crypto/Kconfig index a779cab668c24c..6b0bfbccac08b8 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -250,6 +250,7 @@ config CRYPTO_RSA tristate "RSA (Rivest-Shamir-Adleman)" select CRYPTO_AKCIPHER select CRYPTO_MANAGER + select CRYPTO_SIG select MPILIB select ASN1 help @@ -290,19 +291,19 @@ config CRYPTO_ECDH config CRYPTO_ECDSA tristate "ECDSA (Elliptic Curve Digital Signature Algorithm)" select CRYPTO_ECC - select CRYPTO_AKCIPHER + select CRYPTO_SIG select ASN1 help ECDSA (Elliptic Curve Digital Signature Algorithm) (FIPS 186, ISO/IEC 14888-3) - using curves P-192, P-256, and P-384 + using curves P-192, P-256, P-384 and P-521 Only signature verification is implemented. config CRYPTO_ECRDSA tristate "EC-RDSA (Elliptic Curve Russian Digital Signature Algorithm)" select CRYPTO_ECC - select CRYPTO_AKCIPHER + select CRYPTO_SIG select CRYPTO_STREEBOG select OID_REGISTRY select ASN1 diff --git a/crypto/Makefile b/crypto/Makefile index 4c99e5d376f687..77abca715445d0 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -48,11 +48,14 @@ rsa_generic-y += rsaprivkey.asn1.o rsa_generic-y += rsa.o rsa_generic-y += rsa_helper.o rsa_generic-y += rsa-pkcs1pad.o +rsa_generic-y += rsassa-pkcs1.o obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o $(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h -$(obj)/ecdsa.o: $(obj)/ecdsasignature.asn1.h +$(obj)/ecdsa-x962.o: $(obj)/ecdsasignature.asn1.h ecdsa_generic-y += ecdsa.o +ecdsa_generic-y += ecdsa-x962.o +ecdsa_generic-y += ecdsa-p1363.o ecdsa_generic-y += ecdsasignature.asn1.o obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o @@ -152,6 +155,8 @@ obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o +CFLAGS_crc32c_generic.o += -DARCH=$(ARCH) +CFLAGS_crc32_generic.o += -DARCH=$(ARCH) obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o obj-$(CONFIG_CRYPTO_CRC64_ROCKSOFT) += crc64_rocksoft_generic.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o diff --git a/crypto/adiantum.c b/crypto/adiantum.c index 60f3883b736aa8..c3ef583598b4f4 100644 --- a/crypto/adiantum.c +++ b/crypto/adiantum.c @@ -646,4 +646,4 @@ MODULE_DESCRIPTION("Adiantum length-preserving encryption mode"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Eric Biggers "); MODULE_ALIAS_CRYPTO("adiantum"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/akcipher.c b/crypto/akcipher.c index e0ff5f4dda6d62..72c82d9aa07789 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -20,6 +20,19 @@ #define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e +struct crypto_akcipher_sync_data { + struct crypto_akcipher *tfm; + const void *src; + void *dst; + unsigned int slen; + unsigned int dlen; + + struct akcipher_request *req; + struct crypto_wait cwait; + struct scatterlist sg; + u8 *buf; +}; + static int __maybe_unused crypto_akcipher_report( struct sk_buff *skb, struct crypto_alg *alg) { @@ -126,10 +139,6 @@ int crypto_register_akcipher(struct akcipher_alg *alg) { struct crypto_alg *base = &alg->base; - if (!alg->sign) - alg->sign = akcipher_default_op; - if (!alg->verify) - alg->verify = akcipher_default_op; if (!alg->encrypt) alg->encrypt = akcipher_default_op; if (!alg->decrypt) @@ -158,7 +167,7 @@ int akcipher_register_instance(struct crypto_template *tmpl, } EXPORT_SYMBOL_GPL(akcipher_register_instance); -int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) +static int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) { unsigned int reqsize = crypto_akcipher_reqsize(data->tfm); struct akcipher_request *req; @@ -167,10 +176,7 @@ int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) unsigned int len; u8 *buf; - if (data->dst) - mlen = max(data->slen, data->dlen); - else - mlen = data->slen + data->dlen; + mlen = max(data->slen, data->dlen); len = sizeof(*req) + reqsize + mlen; if (len < mlen) @@ -189,8 +195,7 @@ int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) sg = &data->sg; sg_init_one(sg, buf, mlen); - akcipher_request_set_crypt(req, sg, data->dst ? sg : NULL, - data->slen, data->dlen); + akcipher_request_set_crypt(req, sg, sg, data->slen, data->dlen); crypto_init_wait(&data->cwait); akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, @@ -198,18 +203,16 @@ int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) return 0; } -EXPORT_SYMBOL_GPL(crypto_akcipher_sync_prep); -int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, int err) +static int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, + int err) { err = crypto_wait_req(err, &data->cwait); - if (data->dst) - memcpy(data->dst, data->buf, data->dlen); + memcpy(data->dst, data->buf, data->dlen); data->dlen = data->req->dst_len; kfree_sensitive(data->req); return err; } -EXPORT_SYMBOL_GPL(crypto_akcipher_sync_post); int crypto_akcipher_sync_encrypt(struct crypto_akcipher *tfm, const void *src, unsigned int slen, @@ -248,34 +251,5 @@ int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm, } EXPORT_SYMBOL_GPL(crypto_akcipher_sync_decrypt); -static void crypto_exit_akcipher_ops_sig(struct crypto_tfm *tfm) -{ - struct crypto_akcipher **ctx = crypto_tfm_ctx(tfm); - - crypto_free_akcipher(*ctx); -} - -int crypto_init_akcipher_ops_sig(struct crypto_tfm *tfm) -{ - struct crypto_akcipher **ctx = crypto_tfm_ctx(tfm); - struct crypto_alg *calg = tfm->__crt_alg; - struct crypto_akcipher *akcipher; - - if (!crypto_mod_get(calg)) - return -EAGAIN; - - akcipher = crypto_create_tfm(calg, &crypto_akcipher_type); - if (IS_ERR(akcipher)) { - crypto_mod_put(calg); - return PTR_ERR(akcipher); - } - - *ctx = akcipher; - tfm->exit = crypto_exit_akcipher_ops_sig; - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_init_akcipher_ops_sig); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic public key cipher type"); diff --git a/crypto/algapi.c b/crypto/algapi.c index 004d27e41315ff..16f7c7a9d8ab66 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include @@ -23,11 +22,6 @@ static LIST_HEAD(crypto_template_list); -#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS -DEFINE_PER_CPU(bool, crypto_simd_disabled_for_test); -EXPORT_PER_CPU_SYMBOL_GPL(crypto_simd_disabled_for_test); -#endif - static inline void crypto_check_module_sig(struct module *mod) { if (fips_enabled && mod && !module_sig_ok(mod)) diff --git a/crypto/ansi_cprng.c b/crypto/ansi_cprng.c index 3f512efaba3aa1..64f57c4c4b0621 100644 --- a/crypto/ansi_cprng.c +++ b/crypto/ansi_cprng.c @@ -471,4 +471,4 @@ subsys_initcall(prng_mod_init); module_exit(prng_mod_fini); MODULE_ALIAS_CRYPTO("stdrng"); MODULE_ALIAS_CRYPTO("ansi_cprng"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 422940a6706a7f..bbd07a9022e609 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -83,13 +83,19 @@ software_key_determine_akcipher(const struct public_key *pkey, if (strcmp(encoding, "pkcs1") == 0) { *sig = op == kernel_pkey_sign || op == kernel_pkey_verify; - if (!hash_algo) { + if (!*sig) { + /* + * For encrypt/decrypt, hash_algo is not used + * but allowed to be set for historic reasons. + */ n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", pkey->pkey_algo); } else { + if (!hash_algo) + hash_algo = "none"; n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, - "pkcs1pad(%s,%s)", + "pkcs1(%s,%s)", pkey->pkey_algo, hash_algo); } return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; @@ -104,7 +110,8 @@ software_key_determine_akcipher(const struct public_key *pkey, return -EINVAL; *sig = false; } else if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { - if (strcmp(encoding, "x962") != 0) + if (strcmp(encoding, "x962") != 0 && + strcmp(encoding, "p1363") != 0) return -EINVAL; /* * ECDSA signatures are taken over a raw hash, so they don't @@ -124,6 +131,9 @@ software_key_determine_akcipher(const struct public_key *pkey, strcmp(hash_algo, "sha3-384") != 0 && strcmp(hash_algo, "sha3-512") != 0) return -EINVAL; + n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", + encoding, pkey->pkey_algo); + return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; } else if (strcmp(pkey->pkey_algo, "ecrdsa") == 0) { if (strcmp(encoding, "raw") != 0) return -EINVAL; @@ -192,7 +202,9 @@ static int software_key_query(const struct kernel_pkey_params *params, if (ret < 0) goto error_free_tfm; - len = crypto_sig_maxsize(sig); + len = crypto_sig_keysize(sig); + info->max_sig_size = crypto_sig_maxsize(sig); + info->max_data_size = crypto_sig_digestsize(sig); info->supported_ops = KEYCTL_SUPPORTS_VERIFY; if (pkey->key_is_private) @@ -218,6 +230,8 @@ static int software_key_query(const struct kernel_pkey_params *params, goto error_free_tfm; len = crypto_akcipher_maxsize(tfm); + info->max_sig_size = len; + info->max_data_size = len; info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT; if (pkey->key_is_private) @@ -225,40 +239,6 @@ static int software_key_query(const struct kernel_pkey_params *params, } info->key_size = len * 8; - - if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { - int slen = len; - /* - * ECDSA key sizes are much smaller than RSA, and thus could - * operate on (hashed) inputs that are larger than key size. - * For example SHA384-hashed input used with secp256r1 - * based keys. Set max_data_size to be at least as large as - * the largest supported hash size (SHA512) - */ - info->max_data_size = 64; - - /* - * Verify takes ECDSA-Sig (described in RFC 5480) as input, - * which is actually 2 'key_size'-bit integers encoded in - * ASN.1. Account for the ASN.1 encoding overhead here. - * - * NIST P192/256/384 may prepend a '0' to a coordinate to - * indicate a positive integer. NIST P521 never needs it. - */ - if (strcmp(pkey->pkey_algo, "ecdsa-nist-p521") != 0) - slen += 1; - /* Length of encoding the x & y coordinates */ - slen = 2 * (slen + 2); - /* - * If coordinate encoding takes at least 128 bytes then an - * additional byte for length encoding is needed. - */ - info->max_sig_size = 1 + (slen >= 128) + 1 + slen; - } else { - info->max_data_size = len; - info->max_sig_size = len; - } - info->max_enc_size = len; info->max_dec_size = len; @@ -323,7 +303,7 @@ static int software_key_eds_op(struct kernel_pkey_params *params, if (ret) goto error_free_tfm; - ksz = crypto_sig_maxsize(sig); + ksz = crypto_sig_keysize(sig); } else { tfm = crypto_alloc_akcipher(alg_name, 0, 0); if (IS_ERR(tfm)) { diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c index 2deff81f8af50b..041d04b5c95355 100644 --- a/crypto/asymmetric_keys/signature.c +++ b/crypto/asymmetric_keys/signature.c @@ -64,69 +64,6 @@ int query_asymmetric_key(const struct kernel_pkey_params *params, } EXPORT_SYMBOL_GPL(query_asymmetric_key); -/** - * encrypt_blob - Encrypt data using an asymmetric key - * @params: Various parameters - * @data: Data blob to be encrypted, length params->data_len - * @enc: Encrypted data buffer, length params->enc_len - * - * Encrypt the specified data blob using the private key specified by - * params->key. The encrypted data is wrapped in an encoding if - * params->encoding is specified (eg. "pkcs1"). - * - * Returns the length of the data placed in the encrypted data buffer or an - * error. - */ -int encrypt_blob(struct kernel_pkey_params *params, - const void *data, void *enc) -{ - params->op = kernel_pkey_encrypt; - return asymmetric_key_eds_op(params, data, enc); -} -EXPORT_SYMBOL_GPL(encrypt_blob); - -/** - * decrypt_blob - Decrypt data using an asymmetric key - * @params: Various parameters - * @enc: Encrypted data to be decrypted, length params->enc_len - * @data: Decrypted data buffer, length params->data_len - * - * Decrypt the specified data blob using the private key specified by - * params->key. The decrypted data is wrapped in an encoding if - * params->encoding is specified (eg. "pkcs1"). - * - * Returns the length of the data placed in the decrypted data buffer or an - * error. - */ -int decrypt_blob(struct kernel_pkey_params *params, - const void *enc, void *data) -{ - params->op = kernel_pkey_decrypt; - return asymmetric_key_eds_op(params, enc, data); -} -EXPORT_SYMBOL_GPL(decrypt_blob); - -/** - * create_signature - Sign some data using an asymmetric key - * @params: Various parameters - * @data: Data blob to be signed, length params->data_len - * @enc: Signature buffer, length params->enc_len - * - * Sign the specified data blob using the private key specified by params->key. - * The signature is wrapped in an encoding if params->encoding is specified - * (eg. "pkcs1"). If the encoding needs to know the digest type, this can be - * passed through params->hash_algo (eg. "sha1"). - * - * Returns the length of the data placed in the signature buffer or an error. - */ -int create_signature(struct kernel_pkey_params *params, - const void *data, void *enc) -{ - params->op = kernel_pkey_sign; - return asymmetric_key_eds_op(params, data, enc); -} -EXPORT_SYMBOL_GPL(create_signature); - /** * verify_signature - Initiate the use of an asymmetric key to verify a signature * @key: The asymmetric key to verify against diff --git a/crypto/ccm.c b/crypto/ccm.c index 36f0acec32e196..06476b53b49163 100644 --- a/crypto/ccm.c +++ b/crypto/ccm.c @@ -949,4 +949,4 @@ MODULE_ALIAS_CRYPTO("ccm_base"); MODULE_ALIAS_CRYPTO("rfc4309"); MODULE_ALIAS_CRYPTO("ccm"); MODULE_ALIAS_CRYPTO("cbcmac"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/cipher.c b/crypto/cipher.c index 40cae908788eca..1fe62bf79656bb 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -53,7 +53,7 @@ int crypto_cipher_setkey(struct crypto_cipher *tfm, return cia->cia_setkey(crypto_cipher_tfm(tfm), key, keylen); } -EXPORT_SYMBOL_NS_GPL(crypto_cipher_setkey, CRYPTO_INTERNAL); +EXPORT_SYMBOL_NS_GPL(crypto_cipher_setkey, "CRYPTO_INTERNAL"); static inline void cipher_crypt_one(struct crypto_cipher *tfm, u8 *dst, const u8 *src, bool enc) @@ -81,14 +81,14 @@ void crypto_cipher_encrypt_one(struct crypto_cipher *tfm, { cipher_crypt_one(tfm, dst, src, true); } -EXPORT_SYMBOL_NS_GPL(crypto_cipher_encrypt_one, CRYPTO_INTERNAL); +EXPORT_SYMBOL_NS_GPL(crypto_cipher_encrypt_one, "CRYPTO_INTERNAL"); void crypto_cipher_decrypt_one(struct crypto_cipher *tfm, u8 *dst, const u8 *src) { cipher_crypt_one(tfm, dst, src, false); } -EXPORT_SYMBOL_NS_GPL(crypto_cipher_decrypt_one, CRYPTO_INTERNAL); +EXPORT_SYMBOL_NS_GPL(crypto_cipher_decrypt_one, "CRYPTO_INTERNAL"); struct crypto_cipher *crypto_clone_cipher(struct crypto_cipher *cipher) { diff --git a/crypto/cmac.c b/crypto/cmac.c index c7aa3665b076e4..c66a0f4d880806 100644 --- a/crypto/cmac.c +++ b/crypto/cmac.c @@ -313,4 +313,4 @@ module_exit(crypto_cmac_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CMAC keyed hash algorithm"); MODULE_ALIAS_CRYPTO("cmac"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/crc32_generic.c b/crypto/crc32_generic.c index d1251663ed6683..6a55d206fab317 100644 --- a/crypto/crc32_generic.c +++ b/crypto/crc32_generic.c @@ -59,6 +59,15 @@ static int crc32_update(struct shash_desc *desc, const u8 *data, { u32 *crcp = shash_desc_ctx(desc); + *crcp = crc32_le_base(*crcp, data, len); + return 0; +} + +static int crc32_update_arch(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + u32 *crcp = shash_desc_ctx(desc); + *crcp = crc32_le(*crcp, data, len); return 0; } @@ -66,6 +75,13 @@ static int crc32_update(struct shash_desc *desc, const u8 *data, /* No final XOR 0xFFFFFFFF, like crc32_le */ static int __crc32_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out) +{ + put_unaligned_le32(crc32_le_base(*crcp, data, len), out); + return 0; +} + +static int __crc32_finup_arch(u32 *crcp, const u8 *data, unsigned int len, + u8 *out) { put_unaligned_le32(crc32_le(*crcp, data, len), out); return 0; @@ -77,6 +93,12 @@ static int crc32_finup(struct shash_desc *desc, const u8 *data, return __crc32_finup(shash_desc_ctx(desc), data, len, out); } +static int crc32_finup_arch(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + return __crc32_finup_arch(shash_desc_ctx(desc), data, len, out); +} + static int crc32_final(struct shash_desc *desc, u8 *out) { u32 *crcp = shash_desc_ctx(desc); @@ -88,38 +110,62 @@ static int crc32_final(struct shash_desc *desc, u8 *out) static int crc32_digest(struct shash_desc *desc, const u8 *data, unsigned int len, u8 *out) { - return __crc32_finup(crypto_shash_ctx(desc->tfm), data, len, - out); + return __crc32_finup(crypto_shash_ctx(desc->tfm), data, len, out); } -static struct shash_alg alg = { - .setkey = crc32_setkey, - .init = crc32_init, - .update = crc32_update, - .final = crc32_final, - .finup = crc32_finup, - .digest = crc32_digest, - .descsize = sizeof(u32), - .digestsize = CHKSUM_DIGEST_SIZE, - .base = { - .cra_name = "crc32", - .cra_driver_name = "crc32-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, - .cra_blocksize = CHKSUM_BLOCK_SIZE, - .cra_ctxsize = sizeof(u32), - .cra_module = THIS_MODULE, - .cra_init = crc32_cra_init, - } -}; + +static int crc32_digest_arch(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + return __crc32_finup_arch(crypto_shash_ctx(desc->tfm), data, len, out); +} + +static struct shash_alg algs[] = {{ + .setkey = crc32_setkey, + .init = crc32_init, + .update = crc32_update, + .final = crc32_final, + .finup = crc32_finup, + .digest = crc32_digest, + .descsize = sizeof(u32), + .digestsize = CHKSUM_DIGEST_SIZE, + + .base.cra_name = "crc32", + .base.cra_driver_name = "crc32-generic", + .base.cra_priority = 100, + .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .base.cra_blocksize = CHKSUM_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(u32), + .base.cra_module = THIS_MODULE, + .base.cra_init = crc32_cra_init, +}, { + .setkey = crc32_setkey, + .init = crc32_init, + .update = crc32_update_arch, + .final = crc32_final, + .finup = crc32_finup_arch, + .digest = crc32_digest_arch, + .descsize = sizeof(u32), + .digestsize = CHKSUM_DIGEST_SIZE, + + .base.cra_name = "crc32", + .base.cra_driver_name = "crc32-" __stringify(ARCH), + .base.cra_priority = 150, + .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .base.cra_blocksize = CHKSUM_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(u32), + .base.cra_module = THIS_MODULE, + .base.cra_init = crc32_cra_init, +}}; static int __init crc32_mod_init(void) { - return crypto_register_shash(&alg); + /* register the arch flavor only if it differs from the generic one */ + return crypto_register_shashes(algs, 1 + (&crc32_le != &crc32_le_base)); } static void __exit crc32_mod_fini(void) { - crypto_unregister_shash(&alg); + crypto_unregister_shashes(algs, 1 + (&crc32_le != &crc32_le_base)); } subsys_initcall(crc32_mod_init); diff --git a/crypto/crc32c_generic.c b/crypto/crc32c_generic.c index a8c90b3f4c6c55..7c2357c30fdf7e 100644 --- a/crypto/crc32c_generic.c +++ b/crypto/crc32c_generic.c @@ -85,6 +85,15 @@ static int chksum_update(struct shash_desc *desc, const u8 *data, { struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + ctx->crc = __crc32c_le_base(ctx->crc, data, length); + return 0; +} + +static int chksum_update_arch(struct shash_desc *desc, const u8 *data, + unsigned int length) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + ctx->crc = __crc32c_le(ctx->crc, data, length); return 0; } @@ -98,6 +107,13 @@ static int chksum_final(struct shash_desc *desc, u8 *out) } static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out) +{ + put_unaligned_le32(~__crc32c_le_base(*crcp, data, len), out); + return 0; +} + +static int __chksum_finup_arch(u32 *crcp, const u8 *data, unsigned int len, + u8 *out) { put_unaligned_le32(~__crc32c_le(*crcp, data, len), out); return 0; @@ -111,6 +127,14 @@ static int chksum_finup(struct shash_desc *desc, const u8 *data, return __chksum_finup(&ctx->crc, data, len, out); } +static int chksum_finup_arch(struct shash_desc *desc, const u8 *data, + unsigned int len, u8 *out) +{ + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); + + return __chksum_finup_arch(&ctx->crc, data, len, out); +} + static int chksum_digest(struct shash_desc *desc, const u8 *data, unsigned int length, u8 *out) { @@ -119,6 +143,14 @@ static int chksum_digest(struct shash_desc *desc, const u8 *data, return __chksum_finup(&mctx->key, data, length, out); } +static int chksum_digest_arch(struct shash_desc *desc, const u8 *data, + unsigned int length, u8 *out) +{ + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); + + return __chksum_finup_arch(&mctx->key, data, length, out); +} + static int crc32c_cra_init(struct crypto_tfm *tfm) { struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); @@ -127,35 +159,53 @@ static int crc32c_cra_init(struct crypto_tfm *tfm) return 0; } -static struct shash_alg 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 = "crc32c", - .cra_driver_name = "crc32c-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, - .cra_blocksize = CHKSUM_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct chksum_ctx), - .cra_module = THIS_MODULE, - .cra_init = crc32c_cra_init, - } -}; +static struct shash_alg algs[] = {{ + .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 = "crc32c", + .base.cra_driver_name = "crc32c-generic", + .base.cra_priority = 100, + .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .base.cra_blocksize = CHKSUM_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct chksum_ctx), + .base.cra_module = THIS_MODULE, + .base.cra_init = crc32c_cra_init, +}, { + .digestsize = CHKSUM_DIGEST_SIZE, + .setkey = chksum_setkey, + .init = chksum_init, + .update = chksum_update_arch, + .final = chksum_final, + .finup = chksum_finup_arch, + .digest = chksum_digest_arch, + .descsize = sizeof(struct chksum_desc_ctx), + + .base.cra_name = "crc32c", + .base.cra_driver_name = "crc32c-" __stringify(ARCH), + .base.cra_priority = 150, + .base.cra_flags = CRYPTO_ALG_OPTIONAL_KEY, + .base.cra_blocksize = CHKSUM_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct chksum_ctx), + .base.cra_module = THIS_MODULE, + .base.cra_init = crc32c_cra_init, +}}; static int __init crc32c_mod_init(void) { - return crypto_register_shash(&alg); + /* register the arch flavor only if it differs from the generic one */ + return crypto_register_shashes(algs, 1 + (&__crc32c_le != &__crc32c_le_base)); } static void __exit crc32c_mod_fini(void) { - crypto_unregister_shash(&alg); + crypto_unregister_shashes(algs, 1 + (&__crc32c_le != &__crc32c_le_base)); } subsys_initcall(crc32c_mod_init); diff --git a/crypto/ctr.c b/crypto/ctr.c index 1420496062d57d..73c0d6e53b2fd0 100644 --- a/crypto/ctr.c +++ b/crypto/ctr.c @@ -357,4 +357,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CTR block cipher mode of operation"); MODULE_ALIAS_CRYPTO("rfc3686"); MODULE_ALIAS_CRYPTO("ctr"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/drbg.c b/crypto/drbg.c index 3addce90930c3e..f28dfc2511a2b9 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -101,6 +101,7 @@ #include #include #include +#include /*************************************************************** * Backend cipher definitions available to DRBG @@ -1412,7 +1413,7 @@ static int drbg_generate(struct drbg_state *drbg, if (drbg->pr || drbg->seeded == DRBG_SEED_STATE_UNSEEDED) { pr_devel("DRBG: reseeding before generation (prediction " "resistance: %s, state %s)\n", - drbg->pr ? "true" : "false", + str_true_false(drbg->pr), (drbg->seeded == DRBG_SEED_STATE_FULL ? "seeded" : "unseeded")); /* 9.3.1 steps 7.1 through 7.3 */ @@ -1562,7 +1563,7 @@ static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, bool reseed = true; pr_devel("DRBG: Initializing DRBG core %d with prediction resistance " - "%s\n", coreref, pr ? "enabled" : "disabled"); + "%s\n", coreref, str_enabled_disabled(pr)); mutex_lock(&drbg->drbg_mutex); /* 9.1 step 1 is implicit with the selected DRBG type */ @@ -2150,4 +2151,4 @@ MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG) " CRYPTO_DRBG_HMAC_STRING CRYPTO_DRBG_CTR_STRING); MODULE_ALIAS_CRYPTO("stdrng"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/ecb.c b/crypto/ecb.c index e3a67789050ee2..95d7e972865a86 100644 --- a/crypto/ecb.c +++ b/crypto/ecb.c @@ -225,4 +225,4 @@ module_exit(crypto_ecb_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ECB block cipher mode of operation"); MODULE_ALIAS_CRYPTO("ecb"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/ecdsa-p1363.c b/crypto/ecdsa-p1363.c new file mode 100644 index 00000000000000..eaae7214d69bca --- /dev/null +++ b/crypto/ecdsa-p1363.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ECDSA P1363 signature encoding + * + * Copyright (c) 2024 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include + +struct ecdsa_p1363_ctx { + struct crypto_sig *child; +}; + +static int ecdsa_p1363_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + unsigned int keylen = crypto_sig_keysize(ctx->child); + unsigned int ndigits = DIV_ROUND_UP(keylen, sizeof(u64)); + struct ecdsa_raw_sig sig; + + if (slen != 2 * keylen) + return -EINVAL; + + ecc_digits_from_bytes(src, keylen, sig.r, ndigits); + ecc_digits_from_bytes(src + keylen, keylen, sig.s, ndigits); + + return crypto_sig_verify(ctx->child, &sig, sizeof(sig), digest, dlen); +} + +static unsigned int ecdsa_p1363_key_size(struct crypto_sig *tfm) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_keysize(ctx->child); +} + +static unsigned int ecdsa_p1363_max_size(struct crypto_sig *tfm) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + return 2 * crypto_sig_keysize(ctx->child); +} + +static unsigned int ecdsa_p1363_digest_size(struct crypto_sig *tfm) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_digestsize(ctx->child); +} + +static int ecdsa_p1363_set_pub_key(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_set_pubkey(ctx->child, key, keylen); +} + +static int ecdsa_p1363_init_tfm(struct crypto_sig *tfm) +{ + struct sig_instance *inst = sig_alg_instance(tfm); + struct crypto_sig_spawn *spawn = sig_instance_ctx(inst); + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + struct crypto_sig *child_tfm; + + child_tfm = crypto_spawn_sig(spawn); + if (IS_ERR(child_tfm)) + return PTR_ERR(child_tfm); + + ctx->child = child_tfm; + + return 0; +} + +static void ecdsa_p1363_exit_tfm(struct crypto_sig *tfm) +{ + struct ecdsa_p1363_ctx *ctx = crypto_sig_ctx(tfm); + + crypto_free_sig(ctx->child); +} + +static void ecdsa_p1363_free(struct sig_instance *inst) +{ + struct crypto_sig_spawn *spawn = sig_instance_ctx(inst); + + crypto_drop_sig(spawn); + kfree(inst); +} + +static int ecdsa_p1363_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct crypto_sig_spawn *spawn; + struct sig_instance *inst; + struct sig_alg *ecdsa_alg; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask); + if (err) + return err; + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + spawn = sig_instance_ctx(inst); + + err = crypto_grab_sig(spawn, sig_crypto_instance(inst), + crypto_attr_alg_name(tb[1]), 0, mask); + if (err) + goto err_free_inst; + + ecdsa_alg = crypto_spawn_sig_alg(spawn); + + err = -EINVAL; + if (strncmp(ecdsa_alg->base.cra_name, "ecdsa", 5) != 0) + goto err_free_inst; + + err = crypto_inst_setname(sig_crypto_instance(inst), tmpl->name, + &ecdsa_alg->base); + if (err) + goto err_free_inst; + + inst->alg.base.cra_priority = ecdsa_alg->base.cra_priority; + inst->alg.base.cra_ctxsize = sizeof(struct ecdsa_p1363_ctx); + + inst->alg.init = ecdsa_p1363_init_tfm; + inst->alg.exit = ecdsa_p1363_exit_tfm; + + inst->alg.verify = ecdsa_p1363_verify; + inst->alg.key_size = ecdsa_p1363_key_size; + inst->alg.max_size = ecdsa_p1363_max_size; + inst->alg.digest_size = ecdsa_p1363_digest_size; + inst->alg.set_pub_key = ecdsa_p1363_set_pub_key; + + inst->free = ecdsa_p1363_free; + + err = sig_register_instance(tmpl, inst); + if (err) { +err_free_inst: + ecdsa_p1363_free(inst); + } + return err; +} + +struct crypto_template ecdsa_p1363_tmpl = { + .name = "p1363", + .create = ecdsa_p1363_create, + .module = THIS_MODULE, +}; + +MODULE_ALIAS_CRYPTO("p1363"); diff --git a/crypto/ecdsa-x962.c b/crypto/ecdsa-x962.c new file mode 100644 index 00000000000000..6a77c13e192b1a --- /dev/null +++ b/crypto/ecdsa-x962.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * ECDSA X9.62 signature encoding + * + * Copyright (c) 2021 IBM Corporation + * Copyright (c) 2024 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ecdsasignature.asn1.h" + +struct ecdsa_x962_ctx { + struct crypto_sig *child; +}; + +struct ecdsa_x962_signature_ctx { + struct ecdsa_raw_sig sig; + unsigned int ndigits; +}; + +/* Get the r and s components of a signature from the X.509 certificate. */ +static int ecdsa_get_signature_rs(u64 *dest, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen, + unsigned int ndigits) +{ + size_t bufsize = ndigits * sizeof(u64); + const char *d = value; + + if (!value || !vlen || vlen > bufsize + 1) + return -EINVAL; + + /* + * vlen may be 1 byte larger than bufsize due to a leading zero byte + * (necessary if the most significant bit of the integer is set). + */ + if (vlen > bufsize) { + /* skip over leading zeros that make 'value' a positive int */ + if (*d == 0) { + vlen -= 1; + d++; + } else { + return -EINVAL; + } + } + + ecc_digits_from_bytes(d, vlen, dest, ndigits); + + return 0; +} + +int ecdsa_get_signature_r(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_x962_signature_ctx *sig_ctx = context; + + return ecdsa_get_signature_rs(sig_ctx->sig.r, hdrlen, tag, value, vlen, + sig_ctx->ndigits); +} + +int ecdsa_get_signature_s(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct ecdsa_x962_signature_ctx *sig_ctx = context; + + return ecdsa_get_signature_rs(sig_ctx->sig.s, hdrlen, tag, value, vlen, + sig_ctx->ndigits); +} + +static int ecdsa_x962_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + struct ecdsa_x962_signature_ctx sig_ctx; + int err; + + sig_ctx.ndigits = DIV_ROUND_UP(crypto_sig_keysize(ctx->child), + sizeof(u64)); + + err = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx, src, slen); + if (err < 0) + return err; + + return crypto_sig_verify(ctx->child, &sig_ctx.sig, sizeof(sig_ctx.sig), + digest, dlen); +} + +static unsigned int ecdsa_x962_key_size(struct crypto_sig *tfm) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_keysize(ctx->child); +} + +static unsigned int ecdsa_x962_max_size(struct crypto_sig *tfm) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + struct sig_alg *alg = crypto_sig_alg(ctx->child); + int slen = crypto_sig_keysize(ctx->child); + + /* + * Verify takes ECDSA-Sig-Value (described in RFC 5480) as input, + * which is actually 2 'key_size'-bit integers encoded in ASN.1. + * Account for the ASN.1 encoding overhead here. + * + * NIST P192/256/384 may prepend a '0' to a coordinate to indicate + * a positive integer. NIST P521 never needs it. + */ + if (strcmp(alg->base.cra_name, "ecdsa-nist-p521") != 0) + slen += 1; + + /* Length of encoding the x & y coordinates */ + slen = 2 * (slen + 2); + + /* + * If coordinate encoding takes at least 128 bytes then an + * additional byte for length encoding is needed. + */ + return 1 + (slen >= 128) + 1 + slen; +} + +static unsigned int ecdsa_x962_digest_size(struct crypto_sig *tfm) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_digestsize(ctx->child); +} + +static int ecdsa_x962_set_pub_key(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + + return crypto_sig_set_pubkey(ctx->child, key, keylen); +} + +static int ecdsa_x962_init_tfm(struct crypto_sig *tfm) +{ + struct sig_instance *inst = sig_alg_instance(tfm); + struct crypto_sig_spawn *spawn = sig_instance_ctx(inst); + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + struct crypto_sig *child_tfm; + + child_tfm = crypto_spawn_sig(spawn); + if (IS_ERR(child_tfm)) + return PTR_ERR(child_tfm); + + ctx->child = child_tfm; + + return 0; +} + +static void ecdsa_x962_exit_tfm(struct crypto_sig *tfm) +{ + struct ecdsa_x962_ctx *ctx = crypto_sig_ctx(tfm); + + crypto_free_sig(ctx->child); +} + +static void ecdsa_x962_free(struct sig_instance *inst) +{ + struct crypto_sig_spawn *spawn = sig_instance_ctx(inst); + + crypto_drop_sig(spawn); + kfree(inst); +} + +static int ecdsa_x962_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct crypto_sig_spawn *spawn; + struct sig_instance *inst; + struct sig_alg *ecdsa_alg; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask); + if (err) + return err; + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + spawn = sig_instance_ctx(inst); + + err = crypto_grab_sig(spawn, sig_crypto_instance(inst), + crypto_attr_alg_name(tb[1]), 0, mask); + if (err) + goto err_free_inst; + + ecdsa_alg = crypto_spawn_sig_alg(spawn); + + err = -EINVAL; + if (strncmp(ecdsa_alg->base.cra_name, "ecdsa", 5) != 0) + goto err_free_inst; + + err = crypto_inst_setname(sig_crypto_instance(inst), tmpl->name, + &ecdsa_alg->base); + if (err) + goto err_free_inst; + + inst->alg.base.cra_priority = ecdsa_alg->base.cra_priority; + inst->alg.base.cra_ctxsize = sizeof(struct ecdsa_x962_ctx); + + inst->alg.init = ecdsa_x962_init_tfm; + inst->alg.exit = ecdsa_x962_exit_tfm; + + inst->alg.verify = ecdsa_x962_verify; + inst->alg.key_size = ecdsa_x962_key_size; + inst->alg.max_size = ecdsa_x962_max_size; + inst->alg.digest_size = ecdsa_x962_digest_size; + inst->alg.set_pub_key = ecdsa_x962_set_pub_key; + + inst->free = ecdsa_x962_free; + + err = sig_register_instance(tmpl, inst); + if (err) { +err_free_inst: + ecdsa_x962_free(inst); + } + return err; +} + +struct crypto_template ecdsa_x962_tmpl = { + .name = "x962", + .create = ecdsa_x962_create, + .module = THIS_MODULE, +}; + +MODULE_ALIAS_CRYPTO("x962"); diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c index d5a10959ec281c..117526d15ddebf 100644 --- a/crypto/ecdsa.c +++ b/crypto/ecdsa.c @@ -4,14 +4,11 @@ */ #include -#include #include -#include +#include #include -#include -#include - -#include "ecdsasignature.asn1.h" +#include +#include struct ecc_ctx { unsigned int curve_id; @@ -23,66 +20,6 @@ struct ecc_ctx { struct ecc_point pub_key; }; -struct ecdsa_signature_ctx { - const struct ecc_curve *curve; - u64 r[ECC_MAX_DIGITS]; - u64 s[ECC_MAX_DIGITS]; -}; - -/* - * Get the r and s components of a signature from the X509 certificate. - */ -static int ecdsa_get_signature_rs(u64 *dest, size_t hdrlen, unsigned char tag, - const void *value, size_t vlen, unsigned int ndigits) -{ - size_t bufsize = ndigits * sizeof(u64); - ssize_t diff = vlen - bufsize; - const char *d = value; - - if (!value || !vlen) - return -EINVAL; - - /* diff = 0: 'value' has exacly the right size - * diff > 0: 'value' has too many bytes; one leading zero is allowed that - * makes the value a positive integer; error on more - * diff < 0: 'value' is missing leading zeros - */ - if (diff > 0) { - /* skip over leading zeros that make 'value' a positive int */ - if (*d == 0) { - vlen -= 1; - diff--; - d++; - } - if (diff) - return -EINVAL; - } - if (-diff >= bufsize) - return -EINVAL; - - ecc_digits_from_bytes(d, vlen, dest, ndigits); - - return 0; -} - -int ecdsa_get_signature_r(void *context, size_t hdrlen, unsigned char tag, - const void *value, size_t vlen) -{ - struct ecdsa_signature_ctx *sig = context; - - return ecdsa_get_signature_rs(sig->r, hdrlen, tag, value, vlen, - sig->curve->g.ndigits); -} - -int ecdsa_get_signature_s(void *context, size_t hdrlen, unsigned char tag, - const void *value, size_t vlen) -{ - struct ecdsa_signature_ctx *sig = context; - - return ecdsa_get_signature_rs(sig->s, hdrlen, tag, value, vlen, - sig->curve->g.ndigits); -} - static int _ecdsa_verify(struct ecc_ctx *ctx, const u64 *hash, const u64 *r, const u64 *s) { const struct ecc_curve *curve = ctx->curve; @@ -126,46 +63,27 @@ static int _ecdsa_verify(struct ecc_ctx *ctx, const u64 *hash, const u64 *r, con /* * Verify an ECDSA signature. */ -static int ecdsa_verify(struct akcipher_request *req) +static int ecdsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) { - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); size_t bufsize = ctx->curve->g.ndigits * sizeof(u64); - struct ecdsa_signature_ctx sig_ctx = { - .curve = ctx->curve, - }; + const struct ecdsa_raw_sig *sig = src; u64 hash[ECC_MAX_DIGITS]; - unsigned char *buffer; - int ret; if (unlikely(!ctx->pub_key_set)) return -EINVAL; - buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - sg_pcopy_to_buffer(req->src, - sg_nents_for_len(req->src, req->src_len + req->dst_len), - buffer, req->src_len + req->dst_len, 0); - - ret = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx, - buffer, req->src_len); - if (ret < 0) - goto error; - - if (bufsize > req->dst_len) - bufsize = req->dst_len; - - ecc_digits_from_bytes(buffer + req->src_len, bufsize, - hash, ctx->curve->g.ndigits); + if (slen != sizeof(*sig)) + return -EINVAL; - ret = _ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s); + if (bufsize > dlen) + bufsize = dlen; -error: - kfree(buffer); + ecc_digits_from_bytes(digest, bufsize, hash, ctx->curve->g.ndigits); - return ret; + return _ecdsa_verify(ctx, hash, sig->r, sig->s); } static int ecdsa_ecc_ctx_init(struct ecc_ctx *ctx, unsigned int curve_id) @@ -201,9 +119,10 @@ static int ecdsa_ecc_ctx_reset(struct ecc_ctx *ctx) * Set the public ECC key as defined by RFC5480 section 2.2 "Subject Public * Key". Only the uncompressed format is supported. */ -static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) +static int ecdsa_set_pub_key(struct crypto_sig *tfm, const void *key, + unsigned int keylen) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); unsigned int digitlen, ndigits; const unsigned char *d = key; int ret; @@ -237,31 +156,43 @@ static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsig return ret; } -static void ecdsa_exit_tfm(struct crypto_akcipher *tfm) +static void ecdsa_exit_tfm(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); ecdsa_ecc_ctx_deinit(ctx); } -static unsigned int ecdsa_max_size(struct crypto_akcipher *tfm) +static unsigned int ecdsa_key_size(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return DIV_ROUND_UP(ctx->curve->nbits, 8); } -static int ecdsa_nist_p521_init_tfm(struct crypto_akcipher *tfm) +static unsigned int ecdsa_digest_size(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + /* + * ECDSA key sizes are much smaller than RSA, and thus could + * operate on (hashed) inputs that are larger than the key size. + * E.g. SHA384-hashed input used with secp256r1 based keys. + * Return the largest supported hash size (SHA512). + */ + return SHA512_DIGEST_SIZE; +} + +static int ecdsa_nist_p521_init_tfm(struct crypto_sig *tfm) +{ + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P521); } -static struct akcipher_alg ecdsa_nist_p521 = { +static struct sig_alg ecdsa_nist_p521 = { .verify = ecdsa_verify, .set_pub_key = ecdsa_set_pub_key, - .max_size = ecdsa_max_size, + .key_size = ecdsa_key_size, + .digest_size = ecdsa_digest_size, .init = ecdsa_nist_p521_init_tfm, .exit = ecdsa_exit_tfm, .base = { @@ -273,17 +204,18 @@ static struct akcipher_alg ecdsa_nist_p521 = { }, }; -static int ecdsa_nist_p384_init_tfm(struct crypto_akcipher *tfm) +static int ecdsa_nist_p384_init_tfm(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P384); } -static struct akcipher_alg ecdsa_nist_p384 = { +static struct sig_alg ecdsa_nist_p384 = { .verify = ecdsa_verify, .set_pub_key = ecdsa_set_pub_key, - .max_size = ecdsa_max_size, + .key_size = ecdsa_key_size, + .digest_size = ecdsa_digest_size, .init = ecdsa_nist_p384_init_tfm, .exit = ecdsa_exit_tfm, .base = { @@ -295,17 +227,18 @@ static struct akcipher_alg ecdsa_nist_p384 = { }, }; -static int ecdsa_nist_p256_init_tfm(struct crypto_akcipher *tfm) +static int ecdsa_nist_p256_init_tfm(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P256); } -static struct akcipher_alg ecdsa_nist_p256 = { +static struct sig_alg ecdsa_nist_p256 = { .verify = ecdsa_verify, .set_pub_key = ecdsa_set_pub_key, - .max_size = ecdsa_max_size, + .key_size = ecdsa_key_size, + .digest_size = ecdsa_digest_size, .init = ecdsa_nist_p256_init_tfm, .exit = ecdsa_exit_tfm, .base = { @@ -317,17 +250,18 @@ static struct akcipher_alg ecdsa_nist_p256 = { }, }; -static int ecdsa_nist_p192_init_tfm(struct crypto_akcipher *tfm) +static int ecdsa_nist_p192_init_tfm(struct crypto_sig *tfm) { - struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecc_ctx *ctx = crypto_sig_ctx(tfm); return ecdsa_ecc_ctx_init(ctx, ECC_CURVE_NIST_P192); } -static struct akcipher_alg ecdsa_nist_p192 = { +static struct sig_alg ecdsa_nist_p192 = { .verify = ecdsa_verify, .set_pub_key = ecdsa_set_pub_key, - .max_size = ecdsa_max_size, + .key_size = ecdsa_key_size, + .digest_size = ecdsa_digest_size, .init = ecdsa_nist_p192_init_tfm, .exit = ecdsa_exit_tfm, .base = { @@ -345,42 +279,59 @@ static int __init ecdsa_init(void) int ret; /* NIST p192 may not be available in FIPS mode */ - ret = crypto_register_akcipher(&ecdsa_nist_p192); + ret = crypto_register_sig(&ecdsa_nist_p192); ecdsa_nist_p192_registered = ret == 0; - ret = crypto_register_akcipher(&ecdsa_nist_p256); + ret = crypto_register_sig(&ecdsa_nist_p256); if (ret) goto nist_p256_error; - ret = crypto_register_akcipher(&ecdsa_nist_p384); + ret = crypto_register_sig(&ecdsa_nist_p384); if (ret) goto nist_p384_error; - ret = crypto_register_akcipher(&ecdsa_nist_p521); + ret = crypto_register_sig(&ecdsa_nist_p521); if (ret) goto nist_p521_error; + ret = crypto_register_template(&ecdsa_x962_tmpl); + if (ret) + goto x962_tmpl_error; + + ret = crypto_register_template(&ecdsa_p1363_tmpl); + if (ret) + goto p1363_tmpl_error; + return 0; +p1363_tmpl_error: + crypto_unregister_template(&ecdsa_x962_tmpl); + +x962_tmpl_error: + crypto_unregister_sig(&ecdsa_nist_p521); + nist_p521_error: - crypto_unregister_akcipher(&ecdsa_nist_p384); + crypto_unregister_sig(&ecdsa_nist_p384); nist_p384_error: - crypto_unregister_akcipher(&ecdsa_nist_p256); + crypto_unregister_sig(&ecdsa_nist_p256); nist_p256_error: if (ecdsa_nist_p192_registered) - crypto_unregister_akcipher(&ecdsa_nist_p192); + crypto_unregister_sig(&ecdsa_nist_p192); return ret; } static void __exit ecdsa_exit(void) { + crypto_unregister_template(&ecdsa_x962_tmpl); + crypto_unregister_template(&ecdsa_p1363_tmpl); + if (ecdsa_nist_p192_registered) - crypto_unregister_akcipher(&ecdsa_nist_p192); - crypto_unregister_akcipher(&ecdsa_nist_p256); - crypto_unregister_akcipher(&ecdsa_nist_p384); - crypto_unregister_akcipher(&ecdsa_nist_p521); + crypto_unregister_sig(&ecdsa_nist_p192); + crypto_unregister_sig(&ecdsa_nist_p256); + crypto_unregister_sig(&ecdsa_nist_p384); + crypto_unregister_sig(&ecdsa_nist_p521); } subsys_initcall(ecdsa_init); diff --git a/crypto/ecrdsa.c b/crypto/ecrdsa.c index 3811f3805b5d88..b3dd8a3ddeb796 100644 --- a/crypto/ecrdsa.c +++ b/crypto/ecrdsa.c @@ -18,12 +18,11 @@ #include #include +#include #include -#include #include -#include +#include #include -#include #include "ecrdsa_params.asn1.h" #include "ecrdsa_pub_key.asn1.h" #include "ecrdsa_defs.h" @@ -68,13 +67,12 @@ static const struct ecc_curve *get_curve_by_oid(enum OID oid) } } -static int ecrdsa_verify(struct akcipher_request *req) +static int ecrdsa_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) { - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm); - unsigned char sig[ECRDSA_MAX_SIG_SIZE]; - unsigned char digest[STREEBOG512_DIGEST_SIZE]; - unsigned int ndigits = req->dst_len / sizeof(u64); + struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm); + unsigned int ndigits = dlen / sizeof(u64); u64 r[ECRDSA_MAX_DIGITS]; /* witness (r) */ u64 _r[ECRDSA_MAX_DIGITS]; /* -r */ u64 s[ECRDSA_MAX_DIGITS]; /* second part of sig (s) */ @@ -91,25 +89,19 @@ static int ecrdsa_verify(struct akcipher_request *req) */ if (!ctx->curve || !ctx->digest || - !req->src || + !src || + !digest || !ctx->pub_key.x || - req->dst_len != ctx->digest_len || - req->dst_len != ctx->curve->g.ndigits * sizeof(u64) || + dlen != ctx->digest_len || + dlen != ctx->curve->g.ndigits * sizeof(u64) || ctx->pub_key.ndigits != ctx->curve->g.ndigits || - req->dst_len * 2 != req->src_len || - WARN_ON(req->src_len > sizeof(sig)) || - WARN_ON(req->dst_len > sizeof(digest))) + dlen * 2 != slen || + WARN_ON(slen > ECRDSA_MAX_SIG_SIZE) || + WARN_ON(dlen > STREEBOG512_DIGEST_SIZE)) return -EBADMSG; - sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len), - sig, req->src_len); - sg_pcopy_to_buffer(req->src, - sg_nents_for_len(req->src, - req->src_len + req->dst_len), - digest, req->dst_len, req->src_len); - - vli_from_be64(s, sig, ndigits); - vli_from_be64(r, sig + ndigits * sizeof(u64), ndigits); + vli_from_be64(s, src, ndigits); + vli_from_be64(r, src + ndigits * sizeof(u64), ndigits); /* Step 1: verify that 0 < r < q, 0 < s < q */ if (vli_is_zero(r, ndigits) || @@ -188,10 +180,10 @@ static u8 *ecrdsa_unpack_u32(u32 *dst, void *src) } /* Parse BER encoded subjectPublicKey. */ -static int ecrdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, +static int ecrdsa_set_pub_key(struct crypto_sig *tfm, const void *key, unsigned int keylen) { - struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm); unsigned int ndigits; u32 algo, paramlen; u8 *params; @@ -249,9 +241,9 @@ static int ecrdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, return 0; } -static unsigned int ecrdsa_max_size(struct crypto_akcipher *tfm) +static unsigned int ecrdsa_key_size(struct crypto_sig *tfm) { - struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm); /* * Verify doesn't need any output, so it's just informational @@ -260,13 +252,21 @@ static unsigned int ecrdsa_max_size(struct crypto_akcipher *tfm) return ctx->pub_key.ndigits * sizeof(u64); } -static void ecrdsa_exit_tfm(struct crypto_akcipher *tfm) +static unsigned int ecrdsa_max_size(struct crypto_sig *tfm) +{ + struct ecrdsa_ctx *ctx = crypto_sig_ctx(tfm); + + return 2 * ctx->pub_key.ndigits * sizeof(u64); +} + +static void ecrdsa_exit_tfm(struct crypto_sig *tfm) { } -static struct akcipher_alg ecrdsa_alg = { +static struct sig_alg ecrdsa_alg = { .verify = ecrdsa_verify, .set_pub_key = ecrdsa_set_pub_key, + .key_size = ecrdsa_key_size, .max_size = ecrdsa_max_size, .exit = ecrdsa_exit_tfm, .base = { @@ -280,12 +280,12 @@ static struct akcipher_alg ecrdsa_alg = { static int __init ecrdsa_mod_init(void) { - return crypto_register_akcipher(&ecrdsa_alg); + return crypto_register_sig(&ecrdsa_alg); } static void __exit ecrdsa_mod_fini(void) { - crypto_unregister_akcipher(&ecrdsa_alg); + crypto_unregister_sig(&ecrdsa_alg); } module_init(ecrdsa_mod_init); diff --git a/crypto/essiv.c b/crypto/essiv.c index e63fc6442e3201..1c00c3324058c2 100644 --- a/crypto/essiv.c +++ b/crypto/essiv.c @@ -649,4 +649,4 @@ module_exit(essiv_module_exit); MODULE_DESCRIPTION("ESSIV skcipher/aead wrapper for block encryption"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS_CRYPTO("essiv"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/hctr2.c b/crypto/hctr2.c index 87e7547ad18623..cbcd673be481f9 100644 --- a/crypto/hctr2.c +++ b/crypto/hctr2.c @@ -576,4 +576,4 @@ module_exit(hctr2_module_exit); MODULE_DESCRIPTION("HCTR2 length-preserving encryption mode"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS_CRYPTO("hctr2"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/internal.h b/crypto/internal.h index 711a6a5bfa2b56..46b661be0f90fe 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -22,8 +22,6 @@ #include #include -struct akcipher_request; -struct crypto_akcipher; struct crypto_instance; struct crypto_template; @@ -35,19 +33,6 @@ struct crypto_larval { bool test_started; }; -struct crypto_akcipher_sync_data { - struct crypto_akcipher *tfm; - const void *src; - void *dst; - unsigned int slen; - unsigned int dlen; - - struct akcipher_request *req; - struct crypto_wait cwait; - struct scatterlist sg; - u8 *buf; -}; - enum { CRYPTOA_UNSPEC, CRYPTOA_ALG, @@ -129,10 +114,6 @@ void *crypto_create_tfm_node(struct crypto_alg *alg, void *crypto_clone_tfm(const struct crypto_type *frontend, struct crypto_tfm *otfm); -int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data); -int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, int err); -int crypto_init_akcipher_ops_sig(struct crypto_tfm *tfm); - static inline void *crypto_create_tfm(struct crypto_alg *alg, const struct crypto_type *frontend) { diff --git a/crypto/jitterentropy-testing.c b/crypto/jitterentropy-testing.c index 5cb6a77b8e3b2a..21c9d7c3269a22 100644 --- a/crypto/jitterentropy-testing.c +++ b/crypto/jitterentropy-testing.c @@ -15,7 +15,7 @@ #define JENT_TEST_RINGBUFFER_MASK (JENT_TEST_RINGBUFFER_SIZE - 1) struct jent_testing { - u32 jent_testing_rb[JENT_TEST_RINGBUFFER_SIZE]; + u64 jent_testing_rb[JENT_TEST_RINGBUFFER_SIZE]; u32 rb_reader; atomic_t rb_writer; atomic_t jent_testing_enabled; @@ -72,7 +72,7 @@ static void jent_testing_fini(struct jent_testing *data, u32 boot) pr_warn("Disabling data collection\n"); } -static bool jent_testing_store(struct jent_testing *data, u32 value, +static bool jent_testing_store(struct jent_testing *data, u64 value, u32 *boot) { unsigned long flags; @@ -156,20 +156,20 @@ static int jent_testing_reader(struct jent_testing *data, u32 *boot, } /* We copy out word-wise */ - if (outbuflen < sizeof(u32)) { + if (outbuflen < sizeof(u64)) { spin_unlock_irqrestore(&data->lock, flags); goto out; } memcpy(outbuf, &data->jent_testing_rb[data->rb_reader], - sizeof(u32)); + sizeof(u64)); data->rb_reader++; spin_unlock_irqrestore(&data->lock, flags); - outbuf += sizeof(u32); - outbuflen -= sizeof(u32); - collected_data += sizeof(u32); + outbuf += sizeof(u64); + outbuflen -= sizeof(u64); + collected_data += sizeof(u64); } out: @@ -189,16 +189,17 @@ static int jent_testing_extract_user(struct file *file, char __user *buf, /* * The intention of this interface is for collecting at least - * 1000 samples due to the SP800-90B requirements. So, we make no - * effort in avoiding allocating more memory that actually needed - * by the user. Hence, we allocate sufficient memory to always hold - * that amount of data. + * 1000 samples due to the SP800-90B requirements. However, due to + * memory and performance constraints, it is not desirable to allocate + * 8000 bytes of memory. Instead, we allocate space for only 125 + * samples, which will allow the user to collect all 1000 samples using + * 8 calls to this interface. */ - tmp = kmalloc(JENT_TEST_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL); + tmp = kmalloc(125 * sizeof(u64) + sizeof(u64), GFP_KERNEL); if (!tmp) return -ENOMEM; - tmp_aligned = PTR_ALIGN(tmp, sizeof(u32)); + tmp_aligned = PTR_ALIGN(tmp, sizeof(u64)); while (nbytes) { int i; @@ -212,7 +213,7 @@ static int jent_testing_extract_user(struct file *file, char __user *buf, schedule(); } - i = min_t(int, nbytes, JENT_TEST_RINGBUFFER_SIZE); + i = min_t(int, nbytes, 125 * sizeof(u64)); i = reader(tmp_aligned, i); if (i <= 0) { if (i < 0) @@ -251,7 +252,7 @@ static struct jent_testing jent_raw_hires = { .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(jent_raw_hires.read_wait) }; -int jent_raw_hires_entropy_store(__u32 value) +int jent_raw_hires_entropy_store(__u64 value) { return jent_testing_store(&jent_raw_hires, value, &boot_raw_hires_test); } diff --git a/crypto/jitterentropy.h b/crypto/jitterentropy.h index aa4728675ae245..4c5dbf2a8d8f95 100644 --- a/crypto/jitterentropy.h +++ b/crypto/jitterentropy.h @@ -22,11 +22,11 @@ extern struct rand_data *jent_entropy_collector_alloc(unsigned int osr, extern void jent_entropy_collector_free(struct rand_data *entropy_collector); #ifdef CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE -int jent_raw_hires_entropy_store(__u32 value); +int jent_raw_hires_entropy_store(__u64 value); void jent_testing_init(void); void jent_testing_exit(void); #else /* CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE */ -static inline int jent_raw_hires_entropy_store(__u32 value) { return 0; } +static inline int jent_raw_hires_entropy_store(__u64 value) { return 0; } static inline void jent_testing_init(void) { } static inline void jent_testing_exit(void) { } #endif /* CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE */ diff --git a/crypto/keywrap.c b/crypto/keywrap.c index 054d9a216fc9f3..385ffdfd5a9b4a 100644 --- a/crypto/keywrap.c +++ b/crypto/keywrap.c @@ -317,4 +317,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Stephan Mueller "); MODULE_DESCRIPTION("Key Wrapping (RFC3394 / NIST SP800-38F)"); MODULE_ALIAS_CRYPTO("kw"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/pcbc.c b/crypto/pcbc.c index ab469ba50c13d2..cbfb3ac14b3a80 100644 --- a/crypto/pcbc.c +++ b/crypto/pcbc.c @@ -192,4 +192,4 @@ module_exit(crypto_pcbc_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("PCBC block cipher mode of operation"); MODULE_ALIAS_CRYPTO("pcbc"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index d0d954fe9d54f3..7fc79e7dce44a9 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -117,8 +117,10 @@ static int pcrypt_aead_encrypt(struct aead_request *req) err = padata_do_parallel(ictx->psenc, padata, &ctx->cb_cpu); if (!err) return -EINPROGRESS; - if (err == -EBUSY) - return -EAGAIN; + if (err == -EBUSY) { + /* try non-parallel mode */ + return crypto_aead_encrypt(creq); + } return err; } @@ -166,8 +168,10 @@ static int pcrypt_aead_decrypt(struct aead_request *req) err = padata_do_parallel(ictx->psdec, padata, &ctx->cb_cpu); if (!err) return -EINPROGRESS; - if (err == -EBUSY) - return -EAGAIN; + if (err == -EBUSY) { + /* try non-parallel mode */ + return crypto_aead_decrypt(creq); + } return err; } diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c index cd501195f34a1a..50bdb18e7b4837 100644 --- a/crypto/rsa-pkcs1pad.c +++ b/crypto/rsa-pkcs1pad.c @@ -16,101 +16,6 @@ #include #include -/* - * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. - */ -static const u8 rsa_digest_info_md5[] = { - 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* OID */ - 0x05, 0x00, 0x04, 0x10 -}; - -static const u8 rsa_digest_info_sha1[] = { - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, - 0x2b, 0x0e, 0x03, 0x02, 0x1a, - 0x05, 0x00, 0x04, 0x14 -}; - -static const u8 rsa_digest_info_rmd160[] = { - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, - 0x2b, 0x24, 0x03, 0x02, 0x01, - 0x05, 0x00, 0x04, 0x14 -}; - -static const u8 rsa_digest_info_sha224[] = { - 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, - 0x05, 0x00, 0x04, 0x1c -}; - -static const u8 rsa_digest_info_sha256[] = { - 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, - 0x05, 0x00, 0x04, 0x20 -}; - -static const u8 rsa_digest_info_sha384[] = { - 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, - 0x05, 0x00, 0x04, 0x30 -}; - -static const u8 rsa_digest_info_sha512[] = { - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, - 0x05, 0x00, 0x04, 0x40 -}; - -static const u8 rsa_digest_info_sha3_256[] = { - 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, - 0x05, 0x00, 0x04, 0x20 -}; - -static const u8 rsa_digest_info_sha3_384[] = { - 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, - 0x05, 0x00, 0x04, 0x30 -}; - -static const u8 rsa_digest_info_sha3_512[] = { - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A, - 0x05, 0x00, 0x04, 0x40 -}; - -static const struct rsa_asn1_template { - const char *name; - const u8 *data; - size_t size; -} rsa_asn1_templates[] = { -#define _(X) { #X, rsa_digest_info_##X, sizeof(rsa_digest_info_##X) } - _(md5), - _(sha1), - _(rmd160), - _(sha256), - _(sha384), - _(sha512), - _(sha224), -#undef _ -#define _(X) { "sha3-" #X, rsa_digest_info_sha3_##X, sizeof(rsa_digest_info_sha3_##X) } - _(256), - _(384), - _(512), -#undef _ - { NULL } -}; - -static const struct rsa_asn1_template *rsa_lookup_asn1(const char *name) -{ - const struct rsa_asn1_template *p; - - for (p = rsa_asn1_templates; p->name; p++) - if (strcmp(name, p->name) == 0) - return p; - return NULL; -} - struct pkcs1pad_ctx { struct crypto_akcipher *child; unsigned int key_size; @@ -118,7 +23,6 @@ struct pkcs1pad_ctx { struct pkcs1pad_inst_ctx { struct crypto_akcipher_spawn spawn; - const struct rsa_asn1_template *digest_info; }; struct pkcs1pad_request { @@ -131,42 +35,16 @@ static int pkcs1pad_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); - int err; - - ctx->key_size = 0; - - err = crypto_akcipher_set_pub_key(ctx->child, key, keylen); - if (err) - return err; - - /* Find out new modulus size from rsa implementation */ - err = crypto_akcipher_maxsize(ctx->child); - if (err > PAGE_SIZE) - return -ENOTSUPP; - ctx->key_size = err; - return 0; + return rsa_set_key(ctx->child, &ctx->key_size, RSA_PUB, key, keylen); } static int pkcs1pad_set_priv_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); - int err; - - ctx->key_size = 0; - - err = crypto_akcipher_set_priv_key(ctx->child, key, keylen); - if (err) - return err; - /* Find out new modulus size from rsa implementation */ - err = crypto_akcipher_maxsize(ctx->child); - if (err > PAGE_SIZE) - return -ENOTSUPP; - - ctx->key_size = err; - return 0; + return rsa_set_key(ctx->child, &ctx->key_size, RSA_PRIV, key, keylen); } static unsigned int pkcs1pad_get_max_size(struct crypto_akcipher *tfm) @@ -174,9 +52,9 @@ static unsigned int pkcs1pad_get_max_size(struct crypto_akcipher *tfm) struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); /* - * The maximum destination buffer size for the encrypt/sign operations + * The maximum destination buffer size for the encrypt operation * will be the same as for RSA, even though it's smaller for - * decrypt/verify. + * decrypt. */ return ctx->key_size; @@ -194,7 +72,7 @@ static void pkcs1pad_sg_set_buf(struct scatterlist *sg, void *buf, size_t len, sg_chain(sg, nsegs, next); } -static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err) +static int pkcs1pad_encrypt_complete(struct akcipher_request *req, int err) { struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); @@ -233,14 +111,14 @@ static int pkcs1pad_encrypt_sign_complete(struct akcipher_request *req, int err) return err; } -static void pkcs1pad_encrypt_sign_complete_cb(void *data, int err) +static void pkcs1pad_encrypt_complete_cb(void *data, int err) { struct akcipher_request *req = data; if (err == -EINPROGRESS) goto out; - err = pkcs1pad_encrypt_sign_complete(req, err); + err = pkcs1pad_encrypt_complete(req, err); out: akcipher_request_complete(req, err); @@ -281,7 +159,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req) akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, - pkcs1pad_encrypt_sign_complete_cb, req); + pkcs1pad_encrypt_complete_cb, req); /* Reuse output buffer */ akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg, @@ -289,7 +167,7 @@ static int pkcs1pad_encrypt(struct akcipher_request *req) err = crypto_akcipher_encrypt(&req_ctx->child_req); if (err != -EINPROGRESS && err != -EBUSY) - return pkcs1pad_encrypt_sign_complete(req, err); + return pkcs1pad_encrypt_complete(req, err); return err; } @@ -394,195 +272,6 @@ static int pkcs1pad_decrypt(struct akcipher_request *req) return err; } -static int pkcs1pad_sign(struct akcipher_request *req) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); - struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); - struct akcipher_instance *inst = akcipher_alg_instance(tfm); - struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst); - const struct rsa_asn1_template *digest_info = ictx->digest_info; - int err; - unsigned int ps_end, digest_info_size = 0; - - if (!ctx->key_size) - return -EINVAL; - - if (digest_info) - digest_info_size = digest_info->size; - - if (req->src_len + digest_info_size > ctx->key_size - 11) - return -EOVERFLOW; - - if (req->dst_len < ctx->key_size) { - req->dst_len = ctx->key_size; - return -EOVERFLOW; - } - - req_ctx->in_buf = kmalloc(ctx->key_size - 1 - req->src_len, - GFP_KERNEL); - if (!req_ctx->in_buf) - return -ENOMEM; - - ps_end = ctx->key_size - digest_info_size - req->src_len - 2; - req_ctx->in_buf[0] = 0x01; - memset(req_ctx->in_buf + 1, 0xff, ps_end - 1); - req_ctx->in_buf[ps_end] = 0x00; - - if (digest_info) - memcpy(req_ctx->in_buf + ps_end + 1, digest_info->data, - digest_info->size); - - pkcs1pad_sg_set_buf(req_ctx->in_sg, req_ctx->in_buf, - ctx->key_size - 1 - req->src_len, req->src); - - akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); - akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, - pkcs1pad_encrypt_sign_complete_cb, req); - - /* Reuse output buffer */ - akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg, - req->dst, ctx->key_size - 1, req->dst_len); - - err = crypto_akcipher_decrypt(&req_ctx->child_req); - if (err != -EINPROGRESS && err != -EBUSY) - return pkcs1pad_encrypt_sign_complete(req, err); - - return err; -} - -static int pkcs1pad_verify_complete(struct akcipher_request *req, int err) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); - struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); - struct akcipher_instance *inst = akcipher_alg_instance(tfm); - struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst); - const struct rsa_asn1_template *digest_info = ictx->digest_info; - const unsigned int sig_size = req->src_len; - const unsigned int digest_size = req->dst_len; - unsigned int dst_len; - unsigned int pos; - u8 *out_buf; - - if (err) - goto done; - - err = -EINVAL; - dst_len = req_ctx->child_req.dst_len; - if (dst_len < ctx->key_size - 1) - goto done; - - out_buf = req_ctx->out_buf; - if (dst_len == ctx->key_size) { - if (out_buf[0] != 0x00) - /* Decrypted value had no leading 0 byte */ - goto done; - - dst_len--; - out_buf++; - } - - err = -EBADMSG; - if (out_buf[0] != 0x01) - goto done; - - for (pos = 1; pos < dst_len; pos++) - if (out_buf[pos] != 0xff) - break; - - if (pos < 9 || pos == dst_len || out_buf[pos] != 0x00) - goto done; - pos++; - - if (digest_info) { - if (digest_info->size > dst_len - pos) - goto done; - if (crypto_memneq(out_buf + pos, digest_info->data, - digest_info->size)) - goto done; - - pos += digest_info->size; - } - - err = 0; - - if (digest_size != dst_len - pos) { - err = -EKEYREJECTED; - req->dst_len = dst_len - pos; - goto done; - } - /* Extract appended digest. */ - sg_pcopy_to_buffer(req->src, - sg_nents_for_len(req->src, sig_size + digest_size), - req_ctx->out_buf + ctx->key_size, - digest_size, sig_size); - /* Do the actual verification step. */ - if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos, - digest_size) != 0) - err = -EKEYREJECTED; -done: - kfree_sensitive(req_ctx->out_buf); - - return err; -} - -static void pkcs1pad_verify_complete_cb(void *data, int err) -{ - struct akcipher_request *req = data; - - if (err == -EINPROGRESS) - goto out; - - err = pkcs1pad_verify_complete(req, err); - -out: - akcipher_request_complete(req, err); -} - -/* - * The verify operation is here for completeness similar to the verification - * defined in RFC2313 section 10.2 except that block type 0 is not accepted, - * as in RFC2437. RFC2437 section 9.2 doesn't define any operation to - * retrieve the DigestInfo from a signature, instead the user is expected - * to call the sign operation to generate the expected signature and compare - * signatures instead of the message-digests. - */ -static int pkcs1pad_verify(struct akcipher_request *req) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm); - struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); - const unsigned int sig_size = req->src_len; - const unsigned int digest_size = req->dst_len; - int err; - - if (WARN_ON(req->dst) || WARN_ON(!digest_size) || - !ctx->key_size || sig_size != ctx->key_size) - return -EINVAL; - - req_ctx->out_buf = kmalloc(ctx->key_size + digest_size, GFP_KERNEL); - if (!req_ctx->out_buf) - return -ENOMEM; - - pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf, - ctx->key_size, NULL); - - akcipher_request_set_tfm(&req_ctx->child_req, ctx->child); - akcipher_request_set_callback(&req_ctx->child_req, req->base.flags, - pkcs1pad_verify_complete_cb, req); - - /* Reuse input buffer, output to a new buffer */ - akcipher_request_set_crypt(&req_ctx->child_req, req->src, - req_ctx->out_sg, sig_size, ctx->key_size); - - err = crypto_akcipher_encrypt(&req_ctx->child_req); - if (err != -EINPROGRESS && err != -EBUSY) - return pkcs1pad_verify_complete(req, err); - - return err; -} - static int pkcs1pad_init_tfm(struct crypto_akcipher *tfm) { struct akcipher_instance *inst = akcipher_alg_instance(tfm); @@ -624,7 +313,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) struct akcipher_instance *inst; struct pkcs1pad_inst_ctx *ctx; struct akcipher_alg *rsa_alg; - const char *hash_name; int err; err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AKCIPHER, &mask); @@ -650,36 +338,15 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) } err = -ENAMETOOLONG; - hash_name = crypto_attr_alg_name(tb[2]); - if (IS_ERR(hash_name)) { - if (snprintf(inst->alg.base.cra_name, - CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", - rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME) - goto err_free_inst; - - if (snprintf(inst->alg.base.cra_driver_name, - CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", - rsa_alg->base.cra_driver_name) >= - CRYPTO_MAX_ALG_NAME) - goto err_free_inst; - } else { - ctx->digest_info = rsa_lookup_asn1(hash_name); - if (!ctx->digest_info) { - err = -EINVAL; - goto err_free_inst; - } - - if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, - "pkcs1pad(%s,%s)", rsa_alg->base.cra_name, - hash_name) >= CRYPTO_MAX_ALG_NAME) - goto err_free_inst; - - if (snprintf(inst->alg.base.cra_driver_name, - CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)", - rsa_alg->base.cra_driver_name, - hash_name) >= CRYPTO_MAX_ALG_NAME) - goto err_free_inst; - } + if (snprintf(inst->alg.base.cra_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", + rsa_alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + if (snprintf(inst->alg.base.cra_driver_name, + CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", + rsa_alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; inst->alg.base.cra_priority = rsa_alg->base.cra_priority; inst->alg.base.cra_ctxsize = sizeof(struct pkcs1pad_ctx); @@ -689,8 +356,6 @@ static int pkcs1pad_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.encrypt = pkcs1pad_encrypt; inst->alg.decrypt = pkcs1pad_decrypt; - inst->alg.sign = pkcs1pad_sign; - inst->alg.verify = pkcs1pad_verify; inst->alg.set_pub_key = pkcs1pad_set_pub_key; inst->alg.set_priv_key = pkcs1pad_set_priv_key; inst->alg.max_size = pkcs1pad_get_max_size; diff --git a/crypto/rsa.c b/crypto/rsa.c index 78b28d14ced397..b7d21529c55229 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -407,16 +407,25 @@ static int __init rsa_init(void) return err; err = crypto_register_template(&rsa_pkcs1pad_tmpl); - if (err) { - crypto_unregister_akcipher(&rsa); - return err; - } + if (err) + goto err_unregister_rsa; + + err = crypto_register_template(&rsassa_pkcs1_tmpl); + if (err) + goto err_unregister_rsa_pkcs1pad; return 0; + +err_unregister_rsa_pkcs1pad: + crypto_unregister_template(&rsa_pkcs1pad_tmpl); +err_unregister_rsa: + crypto_unregister_akcipher(&rsa); + return err; } static void __exit rsa_exit(void) { + crypto_unregister_template(&rsassa_pkcs1_tmpl); crypto_unregister_template(&rsa_pkcs1pad_tmpl); crypto_unregister_akcipher(&rsa); } diff --git a/crypto/rsassa-pkcs1.c b/crypto/rsassa-pkcs1.c new file mode 100644 index 00000000000000..f68ffd338f483f --- /dev/null +++ b/crypto/rsassa-pkcs1.c @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * RSA Signature Scheme with Appendix - PKCS #1 v1.5 (RFC 8017 sec 8.2) + * + * https://www.rfc-editor.org/rfc/rfc8017#section-8.2 + * + * Copyright (c) 2015 - 2024 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Full Hash Prefix for EMSA-PKCS1-v1_5 encoding method (RFC 9580 table 24) + * + * RSA keys are usually much larger than the hash of the message to be signed. + * The hash is therefore prepended by the Full Hash Prefix and a 0xff padding. + * The Full Hash Prefix is an ASN.1 SEQUENCE containing the hash algorithm OID. + * + * https://www.rfc-editor.org/rfc/rfc9580#table-24 + */ + +static const u8 hash_prefix_none[] = { }; + +static const u8 hash_prefix_md5[] = { + 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, /* SEQUENCE (SEQUENCE (OID */ + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* , */ + 0x05, 0x00, 0x04, 0x10 /* NULL), OCTET STRING ) */ +}; + +static const u8 hash_prefix_sha1[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1a, + 0x05, 0x00, 0x04, 0x14 +}; + +static const u8 hash_prefix_rmd160[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2b, 0x24, 0x03, 0x02, 0x01, + 0x05, 0x00, 0x04, 0x14 +}; + +static const u8 hash_prefix_sha224[] = { + 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, + 0x05, 0x00, 0x04, 0x1c +}; + +static const u8 hash_prefix_sha256[] = { + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + 0x05, 0x00, 0x04, 0x20 +}; + +static const u8 hash_prefix_sha384[] = { + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, + 0x05, 0x00, 0x04, 0x30 +}; + +static const u8 hash_prefix_sha512[] = { + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, + 0x05, 0x00, 0x04, 0x40 +}; + +static const u8 hash_prefix_sha3_256[] = { + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, + 0x05, 0x00, 0x04, 0x20 +}; + +static const u8 hash_prefix_sha3_384[] = { + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, + 0x05, 0x00, 0x04, 0x30 +}; + +static const u8 hash_prefix_sha3_512[] = { + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a, + 0x05, 0x00, 0x04, 0x40 +}; + +static const struct hash_prefix { + const char *name; + const u8 *data; + size_t size; +} hash_prefixes[] = { +#define _(X) { #X, hash_prefix_##X, sizeof(hash_prefix_##X) } + _(none), + _(md5), + _(sha1), + _(rmd160), + _(sha256), + _(sha384), + _(sha512), + _(sha224), +#undef _ +#define _(X) { "sha3-" #X, hash_prefix_sha3_##X, sizeof(hash_prefix_sha3_##X) } + _(256), + _(384), + _(512), +#undef _ + { NULL } +}; + +static const struct hash_prefix *rsassa_pkcs1_find_hash_prefix(const char *name) +{ + const struct hash_prefix *p; + + for (p = hash_prefixes; p->name; p++) + if (strcmp(name, p->name) == 0) + return p; + return NULL; +} + +static bool rsassa_pkcs1_invalid_hash_len(unsigned int len, + const struct hash_prefix *p) +{ + /* + * Legacy protocols such as TLS 1.1 or earlier and IKE version 1 + * do not prepend a Full Hash Prefix to the hash. In that case, + * the size of the Full Hash Prefix is zero. + */ + if (p->data == hash_prefix_none) + return false; + + /* + * The final byte of the Full Hash Prefix encodes the hash length. + * + * This needs to be revisited should hash algorithms with more than + * 1016 bits (127 bytes * 8) ever be added. The length would then + * be encoded into more than one byte by ASN.1. + */ + static_assert(HASH_MAX_DIGESTSIZE <= 127); + + return len != p->data[p->size - 1]; +} + +struct rsassa_pkcs1_ctx { + struct crypto_akcipher *child; + unsigned int key_size; +}; + +struct rsassa_pkcs1_inst_ctx { + struct crypto_akcipher_spawn spawn; + const struct hash_prefix *hash_prefix; +}; + +static int rsassa_pkcs1_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct sig_instance *inst = sig_alg_instance(tfm); + struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst); + const struct hash_prefix *hash_prefix = ictx->hash_prefix; + struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); + unsigned int pad_len; + unsigned int ps_end; + unsigned int len; + u8 *in_buf; + int err; + + if (!ctx->key_size) + return -EINVAL; + + if (dlen < ctx->key_size) + return -EOVERFLOW; + + if (rsassa_pkcs1_invalid_hash_len(slen, hash_prefix)) + return -EINVAL; + + if (slen + hash_prefix->size > ctx->key_size - 11) + return -EOVERFLOW; + + pad_len = ctx->key_size - slen - hash_prefix->size - 1; + + /* RFC 8017 sec 8.2.1 step 1 - EMSA-PKCS1-v1_5 encoding generation */ + in_buf = dst; + memmove(in_buf + pad_len + hash_prefix->size, src, slen); + memcpy(in_buf + pad_len, hash_prefix->data, hash_prefix->size); + + ps_end = pad_len - 1; + in_buf[0] = 0x01; + memset(in_buf + 1, 0xff, ps_end - 1); + in_buf[ps_end] = 0x00; + + + /* RFC 8017 sec 8.2.1 step 2 - RSA signature */ + err = crypto_akcipher_sync_decrypt(ctx->child, in_buf, + ctx->key_size - 1, in_buf, + ctx->key_size); + if (err < 0) + return err; + + len = err; + pad_len = ctx->key_size - len; + + /* Four billion to one */ + if (unlikely(pad_len)) { + memmove(dst + pad_len, dst, len); + memset(dst, 0, pad_len); + } + + return 0; +} + +static int rsassa_pkcs1_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct sig_instance *inst = sig_alg_instance(tfm); + struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst); + const struct hash_prefix *hash_prefix = ictx->hash_prefix; + struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); + unsigned int child_reqsize = crypto_akcipher_reqsize(ctx->child); + struct akcipher_request *child_req __free(kfree_sensitive) = NULL; + struct crypto_wait cwait; + struct scatterlist sg; + unsigned int dst_len; + unsigned int pos; + u8 *out_buf; + int err; + + /* RFC 8017 sec 8.2.2 step 1 - length checking */ + if (!ctx->key_size || + slen != ctx->key_size || + rsassa_pkcs1_invalid_hash_len(dlen, hash_prefix)) + return -EINVAL; + + /* RFC 8017 sec 8.2.2 step 2 - RSA verification */ + child_req = kmalloc(sizeof(*child_req) + child_reqsize + ctx->key_size, + GFP_KERNEL); + if (!child_req) + return -ENOMEM; + + out_buf = (u8 *)(child_req + 1) + child_reqsize; + memcpy(out_buf, src, slen); + + crypto_init_wait(&cwait); + sg_init_one(&sg, out_buf, slen); + akcipher_request_set_tfm(child_req, ctx->child); + akcipher_request_set_crypt(child_req, &sg, &sg, slen, slen); + akcipher_request_set_callback(child_req, CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &cwait); + + err = crypto_akcipher_encrypt(child_req); + err = crypto_wait_req(err, &cwait); + if (err) + return err; + + /* RFC 8017 sec 8.2.2 step 3 - EMSA-PKCS1-v1_5 encoding verification */ + dst_len = child_req->dst_len; + if (dst_len < ctx->key_size - 1) + return -EINVAL; + + if (dst_len == ctx->key_size) { + if (out_buf[0] != 0x00) + /* Encrypted value had no leading 0 byte */ + return -EINVAL; + + dst_len--; + out_buf++; + } + + if (out_buf[0] != 0x01) + return -EBADMSG; + + for (pos = 1; pos < dst_len; pos++) + if (out_buf[pos] != 0xff) + break; + + if (pos < 9 || pos == dst_len || out_buf[pos] != 0x00) + return -EBADMSG; + pos++; + + if (hash_prefix->size > dst_len - pos) + return -EBADMSG; + if (crypto_memneq(out_buf + pos, hash_prefix->data, hash_prefix->size)) + return -EBADMSG; + pos += hash_prefix->size; + + /* RFC 8017 sec 8.2.2 step 4 - comparison of digest with out_buf */ + if (dlen != dst_len - pos) + return -EKEYREJECTED; + if (memcmp(digest, out_buf + pos, dlen) != 0) + return -EKEYREJECTED; + + return 0; +} + +static unsigned int rsassa_pkcs1_key_size(struct crypto_sig *tfm) +{ + struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); + + return ctx->key_size; +} + +static int rsassa_pkcs1_set_pub_key(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); + + return rsa_set_key(ctx->child, &ctx->key_size, RSA_PUB, key, keylen); +} + +static int rsassa_pkcs1_set_priv_key(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); + + return rsa_set_key(ctx->child, &ctx->key_size, RSA_PRIV, key, keylen); +} + +static int rsassa_pkcs1_init_tfm(struct crypto_sig *tfm) +{ + struct sig_instance *inst = sig_alg_instance(tfm); + struct rsassa_pkcs1_inst_ctx *ictx = sig_instance_ctx(inst); + struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); + struct crypto_akcipher *child_tfm; + + child_tfm = crypto_spawn_akcipher(&ictx->spawn); + if (IS_ERR(child_tfm)) + return PTR_ERR(child_tfm); + + ctx->child = child_tfm; + + return 0; +} + +static void rsassa_pkcs1_exit_tfm(struct crypto_sig *tfm) +{ + struct rsassa_pkcs1_ctx *ctx = crypto_sig_ctx(tfm); + + crypto_free_akcipher(ctx->child); +} + +static void rsassa_pkcs1_free(struct sig_instance *inst) +{ + struct rsassa_pkcs1_inst_ctx *ctx = sig_instance_ctx(inst); + struct crypto_akcipher_spawn *spawn = &ctx->spawn; + + crypto_drop_akcipher(spawn); + kfree(inst); +} + +static int rsassa_pkcs1_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct rsassa_pkcs1_inst_ctx *ctx; + struct akcipher_alg *rsa_alg; + struct sig_instance *inst; + const char *hash_name; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SIG, &mask); + if (err) + return err; + + inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + ctx = sig_instance_ctx(inst); + + err = crypto_grab_akcipher(&ctx->spawn, sig_crypto_instance(inst), + crypto_attr_alg_name(tb[1]), 0, mask); + if (err) + goto err_free_inst; + + rsa_alg = crypto_spawn_akcipher_alg(&ctx->spawn); + + if (strcmp(rsa_alg->base.cra_name, "rsa") != 0) { + err = -EINVAL; + goto err_free_inst; + } + + hash_name = crypto_attr_alg_name(tb[2]); + if (IS_ERR(hash_name)) { + err = PTR_ERR(hash_name); + goto err_free_inst; + } + + ctx->hash_prefix = rsassa_pkcs1_find_hash_prefix(hash_name); + if (!ctx->hash_prefix) { + err = -EINVAL; + goto err_free_inst; + } + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, + "pkcs1(%s,%s)", rsa_alg->base.cra_name, + hash_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "pkcs1(%s,%s)", rsa_alg->base.cra_driver_name, + hash_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + inst->alg.base.cra_priority = rsa_alg->base.cra_priority; + inst->alg.base.cra_ctxsize = sizeof(struct rsassa_pkcs1_ctx); + + inst->alg.init = rsassa_pkcs1_init_tfm; + inst->alg.exit = rsassa_pkcs1_exit_tfm; + + inst->alg.sign = rsassa_pkcs1_sign; + inst->alg.verify = rsassa_pkcs1_verify; + inst->alg.key_size = rsassa_pkcs1_key_size; + inst->alg.set_pub_key = rsassa_pkcs1_set_pub_key; + inst->alg.set_priv_key = rsassa_pkcs1_set_priv_key; + + inst->free = rsassa_pkcs1_free; + + err = sig_register_instance(tmpl, inst); + if (err) { +err_free_inst: + rsassa_pkcs1_free(inst); + } + return err; +} + +struct crypto_template rsassa_pkcs1_tmpl = { + .name = "pkcs1", + .create = rsassa_pkcs1_create, + .module = THIS_MODULE, +}; + +MODULE_ALIAS_CRYPTO("pkcs1"); diff --git a/crypto/sig.c b/crypto/sig.c index 7645bedf3a1fd4..5e1f1f739da2ec 100644 --- a/crypto/sig.c +++ b/crypto/sig.c @@ -5,12 +5,10 @@ * Copyright (c) 2023 Herbert Xu */ -#include #include #include #include #include -#include #include #include #include @@ -19,16 +17,35 @@ #define CRYPTO_ALG_TYPE_SIG_MASK 0x0000000e -static const struct crypto_type crypto_sig_type; +static void crypto_sig_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_sig *sig = __crypto_sig_tfm(tfm); + struct sig_alg *alg = crypto_sig_alg(sig); + + alg->exit(sig); +} static int crypto_sig_init_tfm(struct crypto_tfm *tfm) { - if (tfm->__crt_alg->cra_type != &crypto_sig_type) - return crypto_init_akcipher_ops_sig(tfm); + struct crypto_sig *sig = __crypto_sig_tfm(tfm); + struct sig_alg *alg = crypto_sig_alg(sig); + + if (alg->exit) + sig->base.exit = crypto_sig_exit_tfm; + + if (alg->init) + return alg->init(sig); return 0; } +static void crypto_sig_free_instance(struct crypto_instance *inst) +{ + struct sig_instance *sig = sig_instance(inst); + + sig->free(sig); +} + static void __maybe_unused crypto_sig_show(struct seq_file *m, struct crypto_alg *alg) { @@ -38,16 +55,17 @@ static void __maybe_unused crypto_sig_show(struct seq_file *m, static int __maybe_unused crypto_sig_report(struct sk_buff *skb, struct crypto_alg *alg) { - struct crypto_report_akcipher rsig = {}; + struct crypto_report_sig rsig = {}; strscpy(rsig.type, "sig", sizeof(rsig.type)); - return nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER, sizeof(rsig), &rsig); + return nla_put(skb, CRYPTOCFGA_REPORT_SIG, sizeof(rsig), &rsig); } static const struct crypto_type crypto_sig_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_sig_init_tfm, + .free = crypto_sig_free_instance, #ifdef CONFIG_PROC_FS .show = crypto_sig_show, #endif @@ -66,74 +84,95 @@ struct crypto_sig *crypto_alloc_sig(const char *alg_name, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(crypto_alloc_sig); -int crypto_sig_maxsize(struct crypto_sig *tfm) +static int sig_default_sign(struct crypto_sig *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + return -ENOSYS; +} + +static int sig_default_verify(struct crypto_sig *tfm, + const void *src, unsigned int slen, + const void *dst, unsigned int dlen) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); + return -ENOSYS; +} - return crypto_akcipher_maxsize(*ctx); +static int sig_default_set_key(struct crypto_sig *tfm, + const void *key, unsigned int keylen) +{ + return -ENOSYS; } -EXPORT_SYMBOL_GPL(crypto_sig_maxsize); -int crypto_sig_sign(struct crypto_sig *tfm, - const void *src, unsigned int slen, - void *dst, unsigned int dlen) +static int sig_prepare_alg(struct sig_alg *alg) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); - struct crypto_akcipher_sync_data data = { - .tfm = *ctx, - .src = src, - .dst = dst, - .slen = slen, - .dlen = dlen, - }; - - return crypto_akcipher_sync_prep(&data) ?: - crypto_akcipher_sync_post(&data, - crypto_akcipher_sign(data.req)); + struct crypto_alg *base = &alg->base; + + if (!alg->sign) + alg->sign = sig_default_sign; + if (!alg->verify) + alg->verify = sig_default_verify; + if (!alg->set_priv_key) + alg->set_priv_key = sig_default_set_key; + if (!alg->set_pub_key) + return -EINVAL; + if (!alg->key_size) + return -EINVAL; + if (!alg->max_size) + alg->max_size = alg->key_size; + if (!alg->digest_size) + alg->digest_size = alg->key_size; + + base->cra_type = &crypto_sig_type; + base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + base->cra_flags |= CRYPTO_ALG_TYPE_SIG; + + return 0; } -EXPORT_SYMBOL_GPL(crypto_sig_sign); -int crypto_sig_verify(struct crypto_sig *tfm, - const void *src, unsigned int slen, - const void *digest, unsigned int dlen) +int crypto_register_sig(struct sig_alg *alg) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); - struct crypto_akcipher_sync_data data = { - .tfm = *ctx, - .src = src, - .slen = slen, - .dlen = dlen, - }; + struct crypto_alg *base = &alg->base; int err; - err = crypto_akcipher_sync_prep(&data); + err = sig_prepare_alg(alg); if (err) return err; - memcpy(data.buf + slen, digest, dlen); + return crypto_register_alg(base); +} +EXPORT_SYMBOL_GPL(crypto_register_sig); - return crypto_akcipher_sync_post(&data, - crypto_akcipher_verify(data.req)); +void crypto_unregister_sig(struct sig_alg *alg) +{ + crypto_unregister_alg(&alg->base); } -EXPORT_SYMBOL_GPL(crypto_sig_verify); +EXPORT_SYMBOL_GPL(crypto_unregister_sig); -int crypto_sig_set_pubkey(struct crypto_sig *tfm, - const void *key, unsigned int keylen) +int sig_register_instance(struct crypto_template *tmpl, + struct sig_instance *inst) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); + int err; + + if (WARN_ON(!inst->free)) + return -EINVAL; + + err = sig_prepare_alg(&inst->alg); + if (err) + return err; - return crypto_akcipher_set_pub_key(*ctx, key, keylen); + return crypto_register_instance(tmpl, sig_crypto_instance(inst)); } -EXPORT_SYMBOL_GPL(crypto_sig_set_pubkey); +EXPORT_SYMBOL_GPL(sig_register_instance); -int crypto_sig_set_privkey(struct crypto_sig *tfm, - const void *key, unsigned int keylen) +int crypto_grab_sig(struct crypto_sig_spawn *spawn, + struct crypto_instance *inst, + const char *name, u32 type, u32 mask) { - struct crypto_akcipher **ctx = crypto_sig_ctx(tfm); - - return crypto_akcipher_set_priv_key(*ctx, key, keylen); + spawn->base.frontend = &crypto_sig_type; + return crypto_grab_spawn(&spawn->base, inst, name, type, mask); } -EXPORT_SYMBOL_GPL(crypto_sig_set_privkey); +EXPORT_SYMBOL_GPL(crypto_grab_sig); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Public Key Signature Algorithms"); diff --git a/crypto/skcipher.c b/crypto/skcipher.c index ceed7f33a67ba5..f74e4d0d87a22d 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -1085,4 +1085,4 @@ EXPORT_SYMBOL_GPL(skcipher_alloc_instance_simple); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Symmetric key cipher type"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 2f5f6b52b2d454..1f5f48ab18c741 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -33,12 +33,13 @@ #include #include #include +#include #include #include #include "internal.h" -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); static bool notests; module_param(notests, bool, 0644); @@ -131,6 +132,11 @@ struct akcipher_test_suite { unsigned int count; }; +struct sig_test_suite { + const struct sig_testvec *vecs; + unsigned int count; +}; + struct kpp_test_suite { const struct kpp_testvec *vecs; unsigned int count; @@ -151,6 +157,7 @@ struct alg_test_desc { struct cprng_test_suite cprng; struct drbg_test_suite drbg; struct akcipher_test_suite akcipher; + struct sig_test_suite sig; struct kpp_test_suite kpp; } suite; }; @@ -4123,11 +4130,9 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, struct crypto_wait wait; unsigned int out_len_max, out_len = 0; int err = -ENOMEM; - struct scatterlist src, dst, src_tab[3]; - const char *m, *c; - unsigned int m_size, c_size; - const char *op; - u8 *key, *ptr; + struct scatterlist src, dst, src_tab[2]; + const char *c; + unsigned int c_size; if (testmgr_alloc_buf(xbuf)) return err; @@ -4138,92 +4143,53 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, crypto_init_wait(&wait); - key = kmalloc(vecs->key_len + sizeof(u32) * 2 + vecs->param_len, - GFP_KERNEL); - if (!key) - goto free_req; - memcpy(key, vecs->key, vecs->key_len); - ptr = key + vecs->key_len; - ptr = test_pack_u32(ptr, vecs->algo); - ptr = test_pack_u32(ptr, vecs->param_len); - memcpy(ptr, vecs->params, vecs->param_len); - if (vecs->public_key_vec) - err = crypto_akcipher_set_pub_key(tfm, key, vecs->key_len); + err = crypto_akcipher_set_pub_key(tfm, vecs->key, + vecs->key_len); else - err = crypto_akcipher_set_priv_key(tfm, key, vecs->key_len); + err = crypto_akcipher_set_priv_key(tfm, vecs->key, + vecs->key_len); if (err) - goto free_key; + goto free_req; - /* - * First run test which do not require a private key, such as - * encrypt or verify. - */ + /* First run encrypt test which does not require a private key */ err = -ENOMEM; out_len_max = crypto_akcipher_maxsize(tfm); outbuf_enc = kzalloc(out_len_max, GFP_KERNEL); if (!outbuf_enc) - goto free_key; - - if (!vecs->siggen_sigver_test) { - m = vecs->m; - m_size = vecs->m_size; - c = vecs->c; - c_size = vecs->c_size; - op = "encrypt"; - } else { - /* Swap args so we could keep plaintext (digest) - * in vecs->m, and cooked signature in vecs->c. - */ - m = vecs->c; /* signature */ - m_size = vecs->c_size; - c = vecs->m; /* digest */ - c_size = vecs->m_size; - op = "verify"; - } + goto free_req; + + c = vecs->c; + c_size = vecs->c_size; err = -E2BIG; - if (WARN_ON(m_size > PAGE_SIZE)) + if (WARN_ON(vecs->m_size > PAGE_SIZE)) goto free_all; - memcpy(xbuf[0], m, m_size); + memcpy(xbuf[0], vecs->m, vecs->m_size); - sg_init_table(src_tab, 3); + sg_init_table(src_tab, 2); sg_set_buf(&src_tab[0], xbuf[0], 8); - sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8); - if (vecs->siggen_sigver_test) { - if (WARN_ON(c_size > PAGE_SIZE)) - goto free_all; - memcpy(xbuf[1], c, c_size); - sg_set_buf(&src_tab[2], xbuf[1], c_size); - akcipher_request_set_crypt(req, src_tab, NULL, m_size, c_size); - } else { - sg_init_one(&dst, outbuf_enc, out_len_max); - akcipher_request_set_crypt(req, src_tab, &dst, m_size, - out_len_max); - } + sg_set_buf(&src_tab[1], xbuf[0] + 8, vecs->m_size - 8); + sg_init_one(&dst, outbuf_enc, out_len_max); + akcipher_request_set_crypt(req, src_tab, &dst, vecs->m_size, + out_len_max); akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, &wait); - err = crypto_wait_req(vecs->siggen_sigver_test ? - /* Run asymmetric signature verification */ - crypto_akcipher_verify(req) : - /* Run asymmetric encrypt */ - crypto_akcipher_encrypt(req), &wait); + err = crypto_wait_req(crypto_akcipher_encrypt(req), &wait); if (err) { - pr_err("alg: akcipher: %s test failed. err %d\n", op, err); + pr_err("alg: akcipher: encrypt test failed. err %d\n", err); goto free_all; } - if (!vecs->siggen_sigver_test && c) { + if (c) { if (req->dst_len != c_size) { - pr_err("alg: akcipher: %s test failed. Invalid output len\n", - op); + pr_err("alg: akcipher: encrypt test failed. Invalid output len\n"); err = -EINVAL; goto free_all; } /* verify that encrypted message is equal to expected */ if (memcmp(c, outbuf_enc, c_size) != 0) { - pr_err("alg: akcipher: %s test failed. Invalid output\n", - op); + pr_err("alg: akcipher: encrypt test failed. Invalid output\n"); hexdump(outbuf_enc, c_size); err = -EINVAL; goto free_all; @@ -4231,7 +4197,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, } /* - * Don't invoke (decrypt or sign) test which require a private key + * Don't invoke decrypt test which requires a private key * for vectors with only a public key. */ if (vecs->public_key_vec) { @@ -4244,13 +4210,12 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, goto free_all; } - if (!vecs->siggen_sigver_test && !c) { + if (!c) { c = outbuf_enc; c_size = req->dst_len; } err = -E2BIG; - op = vecs->siggen_sigver_test ? "sign" : "decrypt"; if (WARN_ON(c_size > PAGE_SIZE)) goto free_all; memcpy(xbuf[0], c, c_size); @@ -4260,34 +4225,29 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, crypto_init_wait(&wait); akcipher_request_set_crypt(req, &src, &dst, c_size, out_len_max); - err = crypto_wait_req(vecs->siggen_sigver_test ? - /* Run asymmetric signature generation */ - crypto_akcipher_sign(req) : - /* Run asymmetric decrypt */ - crypto_akcipher_decrypt(req), &wait); + err = crypto_wait_req(crypto_akcipher_decrypt(req), &wait); if (err) { - pr_err("alg: akcipher: %s test failed. err %d\n", op, err); + pr_err("alg: akcipher: decrypt test failed. err %d\n", err); goto free_all; } out_len = req->dst_len; - if (out_len < m_size) { - pr_err("alg: akcipher: %s test failed. Invalid output len %u\n", - op, out_len); + if (out_len < vecs->m_size) { + pr_err("alg: akcipher: decrypt test failed. Invalid output len %u\n", + out_len); err = -EINVAL; goto free_all; } /* verify that decrypted message is equal to the original msg */ - if (memchr_inv(outbuf_dec, 0, out_len - m_size) || - memcmp(m, outbuf_dec + out_len - m_size, m_size)) { - pr_err("alg: akcipher: %s test failed. Invalid output\n", op); + if (memchr_inv(outbuf_dec, 0, out_len - vecs->m_size) || + memcmp(vecs->m, outbuf_dec + out_len - vecs->m_size, + vecs->m_size)) { + pr_err("alg: akcipher: decrypt test failed. Invalid output\n"); hexdump(outbuf_dec, out_len); err = -EINVAL; } free_all: kfree(outbuf_dec); kfree(outbuf_enc); -free_key: - kfree(key); free_req: akcipher_request_free(req); free_xbuf: @@ -4337,6 +4297,113 @@ static int alg_test_akcipher(const struct alg_test_desc *desc, return err; } +static int test_sig_one(struct crypto_sig *tfm, const struct sig_testvec *vecs) +{ + u8 *ptr, *key __free(kfree); + int err, sig_size; + + key = kmalloc(vecs->key_len + 2 * sizeof(u32) + vecs->param_len, + GFP_KERNEL); + if (!key) + return -ENOMEM; + + /* ecrdsa expects additional parameters appended to the key */ + memcpy(key, vecs->key, vecs->key_len); + ptr = key + vecs->key_len; + ptr = test_pack_u32(ptr, vecs->algo); + ptr = test_pack_u32(ptr, vecs->param_len); + memcpy(ptr, vecs->params, vecs->param_len); + + if (vecs->public_key_vec) + err = crypto_sig_set_pubkey(tfm, key, vecs->key_len); + else + err = crypto_sig_set_privkey(tfm, key, vecs->key_len); + if (err) + return err; + + /* + * Run asymmetric signature verification first + * (which does not require a private key) + */ + err = crypto_sig_verify(tfm, vecs->c, vecs->c_size, + vecs->m, vecs->m_size); + if (err) { + pr_err("alg: sig: verify test failed: err %d\n", err); + return err; + } + + /* + * Don't invoke sign test (which requires a private key) + * for vectors with only a public key. + */ + if (vecs->public_key_vec) + return 0; + + sig_size = crypto_sig_keysize(tfm); + if (sig_size < vecs->c_size) { + pr_err("alg: sig: invalid maxsize %u\n", sig_size); + return -EINVAL; + } + + u8 *sig __free(kfree) = kzalloc(sig_size, GFP_KERNEL); + if (!sig) + return -ENOMEM; + + /* Run asymmetric signature generation */ + err = crypto_sig_sign(tfm, vecs->m, vecs->m_size, sig, sig_size); + if (err) { + pr_err("alg: sig: sign test failed: err %d\n", err); + return err; + } + + /* Verify that generated signature equals cooked signature */ + if (memcmp(sig, vecs->c, vecs->c_size) || + memchr_inv(sig + vecs->c_size, 0, sig_size - vecs->c_size)) { + pr_err("alg: sig: sign test failed: invalid output\n"); + hexdump(sig, sig_size); + return -EINVAL; + } + + return 0; +} + +static int test_sig(struct crypto_sig *tfm, const char *alg, + const struct sig_testvec *vecs, unsigned int tcount) +{ + const char *algo = crypto_tfm_alg_driver_name(crypto_sig_tfm(tfm)); + int ret, i; + + for (i = 0; i < tcount; i++) { + ret = test_sig_one(tfm, vecs++); + if (ret) { + pr_err("alg: sig: test %d failed for %s: err %d\n", + i + 1, algo, ret); + return ret; + } + } + return 0; +} + +static int alg_test_sig(const struct alg_test_desc *desc, const char *driver, + u32 type, u32 mask) +{ + struct crypto_sig *tfm; + int err = 0; + + tfm = crypto_alloc_sig(driver, type, mask); + if (IS_ERR(tfm)) { + pr_err("alg: sig: Failed to load tfm for %s: %ld\n", + driver, PTR_ERR(tfm)); + return PTR_ERR(tfm); + } + if (desc->suite.sig.vecs) + err = test_sig(tfm, desc->alg, desc->suite.sig.vecs, + desc->suite.sig.count); + + crypto_free_sig(tfm); + return err; +} + static int alg_test_null(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask) { @@ -5126,36 +5193,36 @@ static const struct alg_test_desc alg_test_descs[] = { } }, { .alg = "ecdsa-nist-p192", - .test = alg_test_akcipher, + .test = alg_test_sig, .suite = { - .akcipher = __VECS(ecdsa_nist_p192_tv_template) + .sig = __VECS(ecdsa_nist_p192_tv_template) } }, { .alg = "ecdsa-nist-p256", - .test = alg_test_akcipher, + .test = alg_test_sig, .fips_allowed = 1, .suite = { - .akcipher = __VECS(ecdsa_nist_p256_tv_template) + .sig = __VECS(ecdsa_nist_p256_tv_template) } }, { .alg = "ecdsa-nist-p384", - .test = alg_test_akcipher, + .test = alg_test_sig, .fips_allowed = 1, .suite = { - .akcipher = __VECS(ecdsa_nist_p384_tv_template) + .sig = __VECS(ecdsa_nist_p384_tv_template) } }, { .alg = "ecdsa-nist-p521", - .test = alg_test_akcipher, + .test = alg_test_sig, .fips_allowed = 1, .suite = { - .akcipher = __VECS(ecdsa_nist_p521_tv_template) + .sig = __VECS(ecdsa_nist_p521_tv_template) } }, { .alg = "ecrdsa", - .test = alg_test_akcipher, + .test = alg_test_sig, .suite = { - .akcipher = __VECS(ecrdsa_tv_template) + .sig = __VECS(ecrdsa_tv_template) } }, { .alg = "essiv(authenc(hmac(sha256),cbc(aes)),sha256)", @@ -5447,6 +5514,24 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(nhpoly1305_tv_template) } + }, { + .alg = "p1363(ecdsa-nist-p192)", + .test = alg_test_null, + }, { + .alg = "p1363(ecdsa-nist-p256)", + .test = alg_test_sig, + .fips_allowed = 1, + .suite = { + .sig = __VECS(p1363_ecdsa_nist_p256_tv_template) + } + }, { + .alg = "p1363(ecdsa-nist-p384)", + .test = alg_test_null, + .fips_allowed = 1, + }, { + .alg = "p1363(ecdsa-nist-p521)", + .test = alg_test_null, + .fips_allowed = 1, }, { .alg = "pcbc(fcrypt)", .test = alg_test_skcipher, @@ -5454,34 +5539,44 @@ static const struct alg_test_desc alg_test_descs[] = { .cipher = __VECS(fcrypt_pcbc_tv_template) } }, { - .alg = "pkcs1pad(rsa,sha224)", + .alg = "pkcs1(rsa,none)", + .test = alg_test_sig, + .suite = { + .sig = __VECS(pkcs1_rsa_none_tv_template) + } + }, { + .alg = "pkcs1(rsa,sha224)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha256)", - .test = alg_test_akcipher, + .alg = "pkcs1(rsa,sha256)", + .test = alg_test_sig, .fips_allowed = 1, .suite = { - .akcipher = __VECS(pkcs1pad_rsa_tv_template) + .sig = __VECS(pkcs1_rsa_tv_template) } }, { - .alg = "pkcs1pad(rsa,sha3-256)", + .alg = "pkcs1(rsa,sha3-256)", + .test = alg_test_null, + .fips_allowed = 1, + }, { + .alg = "pkcs1(rsa,sha3-384)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha3-384)", + .alg = "pkcs1(rsa,sha3-512)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha3-512)", + .alg = "pkcs1(rsa,sha384)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha384)", + .alg = "pkcs1(rsa,sha512)", .test = alg_test_null, .fips_allowed = 1, }, { - .alg = "pkcs1pad(rsa,sha512)", + .alg = "pkcs1pad(rsa)", .test = alg_test_null, .fips_allowed = 1, }, { @@ -5678,6 +5773,33 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(wp512_tv_template) } + }, { + .alg = "x962(ecdsa-nist-p192)", + .test = alg_test_sig, + .suite = { + .sig = __VECS(x962_ecdsa_nist_p192_tv_template) + } + }, { + .alg = "x962(ecdsa-nist-p256)", + .test = alg_test_sig, + .fips_allowed = 1, + .suite = { + .sig = __VECS(x962_ecdsa_nist_p256_tv_template) + } + }, { + .alg = "x962(ecdsa-nist-p384)", + .test = alg_test_sig, + .fips_allowed = 1, + .suite = { + .sig = __VECS(x962_ecdsa_nist_p384_tv_template) + } + }, { + .alg = "x962(ecdsa-nist-p521)", + .test = alg_test_sig, + .fips_allowed = 1, + .suite = { + .sig = __VECS(x962_ecdsa_nist_p521_tv_template) + } }, { .alg = "xcbc(aes)", .test = alg_test_hash, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 9b38501a17b2a0..430d33d9ac1359 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -21,6 +21,7 @@ #define _CRYPTO_TESTMGR_H #include +#include #define MAX_IVLEN 32 @@ -149,6 +150,16 @@ struct drbg_testvec { }; struct akcipher_testvec { + const unsigned char *key; + const unsigned char *m; + const unsigned char *c; + unsigned int key_len; + unsigned int m_size; + unsigned int c_size; + bool public_key_vec; +}; + +struct sig_testvec { const unsigned char *key; const unsigned char *params; const unsigned char *m; @@ -158,7 +169,6 @@ struct akcipher_testvec { unsigned int m_size; unsigned int c_size; bool public_key_vec; - bool siggen_sigver_test; enum OID algo; }; @@ -647,26 +657,713 @@ static const struct akcipher_testvec rsa_tv_template[] = { } }; +#ifdef CONFIG_CPU_BIG_ENDIAN +#define be64_to_cpua(b1, b2, b3, b4, b5, b6, b7, b8) \ + 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8 +#else +#define be64_to_cpua(b1, b2, b3, b4, b5, b6, b7, b8) \ + 0x##b8, 0x##b7, 0x##b6, 0x##b5, 0x##b4, 0x##b3, 0x##b2, 0x##b1 +#endif + /* * ECDSA test vectors. */ -static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { +static const struct sig_testvec ecdsa_nist_p192_tv_template[] = { { - .key = + .key = /* secp192r1(sha1) */ + "\x04\xf7\x46\xf8\x2f\x15\xf6\x22\x8e\xd7\x57\x4f\xcc\xe7\xbb\xc1" + "\xd4\x09\x73\xcf\xea\xd0\x15\x07\x3d\xa5\x8a\x8a\x95\x43\xe4\x68" + "\xea\xc6\x25\xc1\xc1\x01\x25\x4c\x7e\xc3\x3c\xa6\x04\x0a\xe7\x08" + "\x98", + .key_len = 49, + .m = + "\xcd\xb9\xd2\x1c\xb7\x6f\xcd\x44\xb3\xfd\x63\xea\xa3\x66\x7f\xae" + "\x63\x85\xe7\x82", + .m_size = 20, + .c = (const unsigned char[]){ + be64_to_cpua(ad, 59, ad, 88, 27, d6, 92, 6b), + be64_to_cpua(a0, 27, 91, c6, f6, 7f, c3, 09), + be64_to_cpua(ba, e5, 93, 83, 6e, b6, 3b, 63), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(86, 80, 6f, a5, 79, 77, da, d0), + be64_to_cpua(ef, 95, 52, 7b, a0, 0f, e4, 18), + be64_to_cpua(10, 68, 01, 9d, ba, ce, 83, 08), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp192r1(sha224) */ + "\x04\xb6\x4b\xb1\xd1\xac\xba\x24\x8f\x65\xb2\x60\x00\x90\xbf\xbd" + "\x78\x05\x73\xe9\x79\x1d\x6f\x7c\x0b\xd2\xc3\x93\xa7\x28\xe1\x75" + "\xf7\xd5\x95\x1d\x28\x10\xc0\x75\x50\x5c\x1a\x4f\x3f\x8f\xa5\xee" + "\xa3", + .key_len = 49, + .m = + "\x8d\xd6\xb8\x3e\xe5\xff\x23\xf6\x25\xa2\x43\x42\x74\x45\xa7\x40" + "\x3a\xff\x2f\xe1\xd3\xf6\x9f\xe8\x33\xcb\x12\x11", + .m_size = 28, + .c = (const unsigned char[]){ + be64_to_cpua(83, 7b, 12, e6, b6, 5b, cb, d4), + be64_to_cpua(14, f8, 11, 2b, 55, dc, ae, 37), + be64_to_cpua(5a, 8b, 82, 69, 7e, 8a, 0a, 09), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(a3, e3, 5c, 99, db, 92, 5b, 36), + be64_to_cpua(eb, c3, 92, 0f, 1e, 72, ee, c4), + be64_to_cpua(6a, 14, 4f, 53, 75, c8, 02, 48), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp192r1(sha256) */ + "\x04\xe2\x51\x24\x9b\xf7\xb6\x32\x82\x39\x66\x3d\x5b\xec\x3b\xae" + "\x0c\xd5\xf2\x67\xd1\xc7\xe1\x02\xe4\xbf\x90\x62\xb8\x55\x75\x56" + "\x69\x20\x5e\xcb\x4e\xca\x33\xd6\xcb\x62\x6b\x94\xa9\xa2\xe9\x58" + "\x91", + .key_len = 49, + .m = + "\x35\xec\xa1\xa0\x9e\x14\xde\x33\x03\xb6\xf6\xbd\x0c\x2f\xb2\xfd" + "\x1f\x27\x82\xa5\xd7\x70\x3f\xef\xa0\x82\x69\x8e\x73\x31\x8e\xd7", + .m_size = 32, + .c = (const unsigned char[]){ + be64_to_cpua(01, 48, fb, 5f, 72, 2a, d4, 8f), + be64_to_cpua(6b, 1a, 58, 56, f1, 8f, f7, fd), + be64_to_cpua(3f, 72, 3f, 1f, 42, d2, 3f, 1d), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(7d, 3a, 97, d9, cd, 1a, 6a, 49), + be64_to_cpua(32, dd, 41, 74, 6a, 51, c7, d9), + be64_to_cpua(b3, 69, 43, fd, 48, 19, 86, cf), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp192r1(sha384) */ + "\x04\x5a\x13\xfe\x68\x86\x4d\xf4\x17\xc7\xa4\xe5\x8c\x65\x57\xb7" + "\x03\x73\x26\x57\xfb\xe5\x58\x40\xd8\xfd\x49\x05\xab\xf1\x66\x1f" + "\xe2\x9d\x93\x9e\xc2\x22\x5a\x8b\x4f\xf3\x77\x22\x59\x7e\xa6\x4e" + "\x8b", + .key_len = 49, + .m = + "\x9d\x2e\x1a\x8f\xed\x6c\x4b\x61\xae\xac\xd5\x19\x79\xce\x67\xf9" + "\xa0\x34\xeb\xb0\x81\xf9\xd9\xdc\x6e\xb3\x5c\xa8\x69\xfc\x8a\x61" + "\x39\x81\xfb\xfd\x5c\x30\x6b\xa8\xee\xed\x89\xaf\xa3\x05\xe4\x78", + .m_size = 48, + .c = (const unsigned char[]){ + be64_to_cpua(dd, 15, bb, d6, 8c, a7, 03, 78), + be64_to_cpua(cf, 7f, 34, b4, b4, e5, c5, 00), + be64_to_cpua(f0, a3, 38, ce, 2b, f8, 9d, 1a), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(93, 12, 3b, 3b, 28, fb, 6d, e1), + be64_to_cpua(d1, 01, 77, 44, 5d, 53, a4, 7c), + be64_to_cpua(64, bc, 5a, 1f, 82, 96, 61, d7), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp192r1(sha512) */ + "\x04\xd5\xf2\x6e\xc3\x94\x5c\x52\xbc\xdf\x86\x6c\x14\xd1\xca\xea" + "\xcc\x72\x3a\x8a\xf6\x7a\x3a\x56\x36\x3b\xca\xc6\x94\x0e\x17\x1d" + "\x9e\xa0\x58\x28\xf9\x4b\xe6\xd1\xa5\x44\x91\x35\x0d\xe7\xf5\x11" + "\x57", + .key_len = 49, + .m = + "\xd5\x4b\xe9\x36\xda\xd8\x6e\xc0\x50\x03\xbe\x00\x43\xff\xf0\x23" + "\xac\xa2\x42\xe7\x37\x77\x79\x52\x8f\x3e\xc0\x16\xc1\xfc\x8c\x67" + "\x16\xbc\x8a\x5d\x3b\xd3\x13\xbb\xb6\xc0\x26\x1b\xeb\x33\xcc\x70" + "\x4a\xf2\x11\x37\xe8\x1b\xba\x55\xac\x69\xe1\x74\x62\x7c\x6e\xb5", + .m_size = 64, + .c = (const unsigned char[]){ + be64_to_cpua(2b, 11, 2d, 1c, b6, 06, c9, 6c), + be64_to_cpua(dd, 3f, 07, 87, 12, a0, d4, ac), + be64_to_cpua(88, 5b, 8f, 59, 43, bf, cf, c6), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(28, 6a, df, 97, fd, 82, 76, 24), + be64_to_cpua(a9, 14, 2a, 5e, f5, e5, fb, 72), + be64_to_cpua(73, b4, 22, 9a, 98, 73, 3c, 83), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, +}; + +static const struct sig_testvec ecdsa_nist_p256_tv_template[] = { + { + .key = /* secp256r1(sha1) */ + "\x04\xb9\x7b\xbb\xd7\x17\x64\xd2\x7e\xfc\x81\x5d\x87\x06\x83\x41" + "\x22\xd6\x9a\xaa\x87\x17\xec\x4f\x63\x55\x2f\x94\xba\xdd\x83\xe9" + "\x34\x4b\xf3\xe9\x91\x13\x50\xb6\xcb\xca\x62\x08\xe7\x3b\x09\xdc" + "\xc3\x63\x4b\x2d\xb9\x73\x53\xe4\x45\xe6\x7c\xad\xe7\x6b\xb0\xe8" + "\xaf", + .key_len = 65, + .m = + "\xc2\x2b\x5f\x91\x78\x34\x26\x09\x42\x8d\x6f\x51\xb2\xc5\xaf\x4c" + "\x0b\xde\x6a\x42", + .m_size = 20, + .c = (const unsigned char[]){ + be64_to_cpua(ee, ca, 6a, 52, 0e, 48, 4d, cc), + be64_to_cpua(f7, d4, ad, 8d, 94, 5a, 69, 89), + be64_to_cpua(cf, d4, e7, b7, f0, 82, 56, 41), + be64_to_cpua(f9, 25, ce, 9f, 3a, a6, 35, 81), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(fb, 9d, 8b, de, d4, 8d, 6f, ad), + be64_to_cpua(f1, 03, 03, f3, 3b, e2, 73, f7), + be64_to_cpua(8a, fa, 54, 93, 29, a7, 70, 86), + be64_to_cpua(d7, e4, ef, 52, 66, d3, 5b, 9d), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp256r1(sha224) */ + "\x04\x8b\x6d\xc0\x33\x8e\x2d\x8b\x67\xf5\xeb\xc4\x7f\xa0\xf5\xd9" + "\x7b\x03\xa5\x78\x9a\xb5\xea\x14\xe4\x23\xd0\xaf\xd7\x0e\x2e\xa0" + "\xc9\x8b\xdb\x95\xf8\xb3\xaf\xac\x00\x2c\x2c\x1f\x7a\xfd\x95\x88" + "\x43\x13\xbf\xf3\x1c\x05\x1a\x14\x18\x09\x3f\xd6\x28\x3e\xc5\xa0" + "\xd4", + .key_len = 65, + .m = + "\x1a\x15\xbc\xa3\xe4\xed\x3a\xb8\x23\x67\xc6\xc4\x34\xf8\x6c\x41" + "\x04\x0b\xda\xc5\x77\xfa\x1c\x2d\xe6\x2c\x3b\xe0", + .m_size = 28, + .c = (const unsigned char[]){ + be64_to_cpua(7d, 25, d8, 25, f5, 81, d2, 1e), + be64_to_cpua(34, 62, 79, cb, 6a, 91, 67, 2e), + be64_to_cpua(ae, ce, 77, 59, 1a, db, 59, d5), + be64_to_cpua(20, 43, fa, c0, 9f, 9d, 7b, e7), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(ce, d5, 2e, 8b, de, 5a, 04, 0e), + be64_to_cpua(bf, 50, 05, 58, 39, 0e, 26, 92), + be64_to_cpua(76, 20, 4a, 77, 22, ec, c8, 66), + be64_to_cpua(5f, f8, 74, f8, 57, d0, 5e, 54), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp256r1(sha256) */ + "\x04\xf1\xea\xc4\x53\xf3\xb9\x0e\x9f\x7e\xad\xe3\xea\xd7\x0e\x0f" + "\xd6\x98\x9a\xca\x92\x4d\x0a\x80\xdb\x2d\x45\xc7\xec\x4b\x97\x00" + "\x2f\xe9\x42\x6c\x29\xdc\x55\x0e\x0b\x53\x12\x9b\x2b\xad\x2c\xe9" + "\x80\xe6\xc5\x43\xc2\x1d\x5e\xbb\x65\x21\x50\xb6\x37\xb0\x03\x8e" + "\xb8", + .key_len = 65, + .m = + "\x8f\x43\x43\x46\x64\x8f\x6b\x96\xdf\x89\xdd\xa9\x01\xc5\x17\x6b" + "\x10\xa6\xd8\x39\x61\xdd\x3c\x1a\xc8\x8b\x59\xb2\xdc\x32\x7a\xa4", + .m_size = 32, + .c = (const unsigned char[]){ + be64_to_cpua(91, dc, 02, 67, dc, 0c, d0, 82), + be64_to_cpua(ac, 44, c3, e8, 24, 11, 2d, a4), + be64_to_cpua(09, dc, 29, 63, a8, 1a, ad, fc), + be64_to_cpua(08, 31, fa, 74, 0d, 1d, 21, 5d), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(4f, 2a, 65, 35, 23, e3, 1d, fa), + be64_to_cpua(0a, 6e, 1b, c4, af, e1, 83, c3), + be64_to_cpua(f9, a9, 81, ac, 4a, 50, d0, 91), + be64_to_cpua(bd, ff, ce, ee, 42, c3, 97, ff), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp256r1(sha384) */ + "\x04\xc5\xc6\xea\x60\xc9\xce\xad\x02\x8d\xf5\x3e\x24\xe3\x52\x1d" + "\x28\x47\x3b\xc3\x6b\xa4\x99\x35\x99\x11\x88\x88\xc8\xf4\xee\x7e" + "\x8c\x33\x8f\x41\x03\x24\x46\x2b\x1a\x82\xf9\x9f\xe1\x97\x1b\x00" + "\xda\x3b\x24\x41\xf7\x66\x33\x58\x3d\x3a\x81\xad\xcf\x16\xe9\xe2" + "\x7c", + .key_len = 65, + .m = + "\x3e\x78\x70\xfb\xcd\x66\xba\x91\xa1\x79\xff\x1e\x1c\x6b\x78\xe6" + "\xc0\x81\x3a\x65\x97\x14\x84\x36\x14\x1a\x9a\xb7\xc5\xab\x84\x94" + "\x5e\xbb\x1b\x34\x71\xcb\x41\xe1\xf6\xfc\x92\x7b\x34\xbb\x86\xbb", + .m_size = 48, + .c = (const unsigned char[]){ + be64_to_cpua(f2, e4, 6c, c7, 94, b1, d5, fe), + be64_to_cpua(08, b2, 6b, 24, 94, 48, 46, 5e), + be64_to_cpua(d0, 2e, 95, 54, d1, 95, 64, 93), + be64_to_cpua(8e, f3, 6f, dc, f8, 69, a6, 2e), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(c0, 60, 11, 92, dc, 17, 89, 12), + be64_to_cpua(69, f4, 3b, 4f, 47, cf, 9b, 16), + be64_to_cpua(19, fb, 5f, 92, f4, c9, 23, 37), + be64_to_cpua(eb, a7, 80, 26, dc, f9, 3a, 44), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp256r1(sha512) */ + "\x04\xd7\x27\x46\x49\xf6\x26\x85\x12\x40\x76\x8e\xe2\xe6\x2a\x7a" + "\x83\xb1\x4e\x7a\xeb\x3b\x5c\x67\x4a\xb5\xa4\x92\x8c\x69\xff\x38" + "\xee\xd9\x4e\x13\x29\x59\xad\xde\x6b\xbb\x45\x31\xee\xfd\xd1\x1b" + "\x64\xd3\xb5\xfc\xaf\x9b\x4b\x88\x3b\x0e\xb7\xd6\xdf\xf1\xd5\x92" + "\xbf", + .key_len = 65, + .m = + "\x57\xb7\x9e\xe9\x05\x0a\x8c\x1b\xc9\x13\xe5\x4a\x24\xc7\xe2\xe9" + "\x43\xc3\xd1\x76\x62\xf4\x98\x1a\x9c\x13\xb0\x20\x1b\xe5\x39\xca" + "\x4f\xd9\x85\x34\x95\xa2\x31\xbc\xbb\xde\xdd\x76\xbb\x61\xe3\xcf" + "\x9d\xc0\x49\x7a\xf3\x7a\xc4\x7d\xa8\x04\x4b\x8d\xb4\x4d\x5b\xd6", + .m_size = 64, + .c = (const unsigned char[]){ + be64_to_cpua(76, f6, 04, 99, 09, 37, 4d, fa), + be64_to_cpua(ed, 8c, 73, 30, 6c, 22, b3, 97), + be64_to_cpua(40, ea, 44, 81, 00, 4e, 29, 08), + be64_to_cpua(b8, 6d, 87, 81, 43, df, fb, 9f), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(76, 31, 79, 4a, e9, 81, 6a, ee), + be64_to_cpua(5c, ad, c3, 78, 1c, c2, c1, 19), + be64_to_cpua(f8, 00, dd, ab, d4, c0, 2b, e6), + be64_to_cpua(1e, b9, 75, 31, f6, 04, a5, 4d), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, +}; + +static const struct sig_testvec ecdsa_nist_p384_tv_template[] = { + { + .key = /* secp384r1(sha1) */ + "\x04\x89\x25\xf3\x97\x88\xcb\xb0\x78\xc5\x72\x9a\x14\x6e\x7a\xb1" + "\x5a\xa5\x24\xf1\x95\x06\x9e\x28\xfb\xc4\xb9\xbe\x5a\x0d\xd9\x9f" + "\xf3\xd1\x4d\x2d\x07\x99\xbd\xda\xa7\x66\xec\xbb\xea\xba\x79\x42" + "\xc9\x34\x89\x6a\xe7\x0b\xc3\xf2\xfe\x32\x30\xbe\xba\xf9\xdf\x7e" + "\x4b\x6a\x07\x8e\x26\x66\x3f\x1d\xec\xa2\x57\x91\x51\xdd\x17\x0e" + "\x0b\x25\xd6\x80\x5c\x3b\xe6\x1a\x98\x48\x91\x45\x7a\x73\xb0\xc3" + "\xf1", + .key_len = 97, + .m = + "\x12\x55\x28\xf0\x77\xd5\xb6\x21\x71\x32\x48\xcd\x28\xa8\x25\x22" + "\x3a\x69\xc1\x93", + .m_size = 20, + .c = (const unsigned char[]){ + be64_to_cpua(ec, 7c, 7e, d0, 87, d7, d7, 6e), + be64_to_cpua(78, f1, 4c, 26, e6, 5b, 86, cf), + be64_to_cpua(3a, c6, f1, 32, 3c, ce, 70, 2b), + be64_to_cpua(8d, 26, 8e, ae, 63, 3f, bc, 20), + be64_to_cpua(57, 55, 07, 20, 43, 30, de, a0), + be64_to_cpua(f5, 0f, 24, 4c, 07, 93, 6f, 21), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(79, 12, 2a, b7, c5, 15, 92, c5), + be64_to_cpua(4a, a1, 59, f1, 1c, a4, 58, 26), + be64_to_cpua(74, a0, 0f, bf, af, c3, 36, 76), + be64_to_cpua(df, 28, 8c, 1b, fa, f9, 95, 88), + be64_to_cpua(5f, 63, b1, be, 5e, 4c, 0e, a1), + be64_to_cpua(cd, bb, 7e, 81, 5d, 8f, 63, c0), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp384r1(sha224) */ + "\x04\x69\x6c\xcf\x62\xee\xd0\x0d\xe5\xb5\x2f\x70\x54\xcf\x26\xa0" + "\xd9\x98\x8d\x92\x2a\xab\x9b\x11\xcb\x48\x18\xa1\xa9\x0d\xd5\x18" + "\x3e\xe8\x29\x6e\xf6\xe4\xb5\x8e\xc7\x4a\xc2\x5f\x37\x13\x99\x05" + "\xb6\xa4\x9d\xf9\xfb\x79\x41\xe7\xd7\x96\x9f\x73\x3b\x39\x43\xdc" + "\xda\xf4\x06\xb9\xa5\x29\x01\x9d\x3b\xe1\xd8\x68\x77\x2a\xf4\x50" + "\x6b\x93\x99\x6c\x66\x4c\x42\x3f\x65\x60\x6c\x1c\x0b\x93\x9b\x9d" + "\xe0", + .key_len = 97, + .m = + "\x12\x80\xb6\xeb\x25\xe2\x3d\xf0\x21\x32\x96\x17\x3a\x38\x39\xfd" + "\x1f\x05\x34\x7b\xb8\xf9\x71\x66\x03\x4f\xd5\xe5", + .m_size = 28, + .c = (const unsigned char[]){ + be64_to_cpua(3f, dd, 15, 1b, 68, 2b, 9d, 8b), + be64_to_cpua(c9, 9c, 11, b8, 10, 01, c5, 41), + be64_to_cpua(c5, da, b4, e3, 93, 07, e0, 99), + be64_to_cpua(97, f1, c8, 72, 26, cf, 5a, 5e), + be64_to_cpua(ec, cb, e4, 89, 47, b2, f7, bc), + be64_to_cpua(8a, 51, 84, ce, 13, 1e, d2, dc), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(88, 2b, 82, 26, 5e, 1c, da, fb), + be64_to_cpua(9f, 19, d0, 42, 8b, 93, c2, 11), + be64_to_cpua(4d, d0, c6, 6e, b0, e9, fc, 14), + be64_to_cpua(df, d8, 68, a2, 64, 42, 65, f3), + be64_to_cpua(4b, 00, 08, 31, 6c, f5, d5, f6), + be64_to_cpua(8b, 03, 2c, fc, 1f, d1, a9, a4), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp384r1(sha256) */ + "\x04\xee\xd6\xda\x3e\x94\x90\x00\x27\xed\xf8\x64\x55\xd6\x51\x9a" + "\x1f\x52\x00\x63\x78\xf1\xa9\xfd\x75\x4c\x9e\xb2\x20\x1a\x91\x5a" + "\xba\x7a\xa3\xe5\x6c\xb6\x25\x68\x4b\xe8\x13\xa6\x54\x87\x2c\x0e" + "\xd0\x83\x95\xbc\xbf\xc5\x28\x4f\x77\x1c\x46\xa6\xf0\xbc\xd4\xa4" + "\x8d\xc2\x8f\xb3\x32\x37\x40\xd6\xca\xf8\xae\x07\x34\x52\x39\x52" + "\x17\xc3\x34\x29\xd6\x40\xea\x5c\xb9\x3f\xfb\x32\x2e\x12\x33\xbc" + "\xab", + .key_len = 97, + .m = + "\xaa\xe7\xfd\x03\x26\xcb\x94\x71\xe4\xce\x0f\xc5\xff\xa6\x29\xa3" + "\xe1\xcc\x4c\x35\x4e\xde\xca\x80\xab\x26\x0c\x25\xe6\x68\x11\xc2", + .m_size = 32, + .c = (const unsigned char[]){ + be64_to_cpua(c8, 8d, 2c, 79, 3a, 8e, 32, c4), + be64_to_cpua(b6, c6, fc, 70, 2e, 66, 3c, 77), + be64_to_cpua(af, 06, 3f, 84, 04, e2, f9, 67), + be64_to_cpua(cc, 47, 53, 87, bc, bd, 83, 3f), + be64_to_cpua(8e, 3f, 7e, ce, 0a, 9b, aa, 59), + be64_to_cpua(08, 09, 12, 9d, 6e, 96, 64, a6), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(10, 0e, f4, 1f, 39, ca, 4d, 43), + be64_to_cpua(4f, 8d, de, 1e, 93, 8d, 95, bb), + be64_to_cpua(15, 68, c0, 75, 3e, 23, 5e, 36), + be64_to_cpua(dd, ce, bc, b2, 97, f4, 9c, f3), + be64_to_cpua(26, a2, b0, 89, 42, 0a, da, d9), + be64_to_cpua(40, 34, b8, 90, a9, 80, ab, 47), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp384r1(sha384) */ + "\x04\x3a\x2f\x62\xe7\x1a\xcf\x24\xd0\x0b\x7c\xe0\xed\x46\x0a\x4f" + "\x74\x16\x43\xe9\x1a\x25\x7c\x55\xff\xf0\x29\x68\x66\x20\x91\xf9" + "\xdb\x2b\xf6\xb3\x6c\x54\x01\xca\xc7\x6a\x5c\x0d\xeb\x68\xd9\x3c" + "\xf1\x01\x74\x1f\xf9\x6c\xe5\x5b\x60\xe9\x7f\x5d\xb3\x12\x80\x2a" + "\xd8\x67\x92\xc9\x0e\x4c\x4c\x6b\xa1\xb2\xa8\x1e\xac\x1c\x97\xd9" + "\x21\x67\xe5\x1b\x5a\x52\x31\x68\xd6\xee\xf0\x19\xb0\x55\xed\x89" + "\x9e", + .key_len = 97, + .m = + "\x8d\xf2\xc0\xe9\xa8\xf3\x8e\x44\xc4\x8c\x1a\xa0\xb8\xd7\x17\xdf" + "\xf2\x37\x1b\xc6\xe3\xf5\x62\xcc\x68\xf5\xd5\x0b\xbf\x73\x2b\xb1" + "\xb0\x4c\x04\x00\x31\xab\xfe\xc8\xd6\x09\xc8\xf2\xea\xd3\x28\xff", + .m_size = 48, + .c = (const unsigned char[]){ + be64_to_cpua(a2, a4, c8, f2, ea, 9d, 11, 1f), + be64_to_cpua(3b, 1f, 07, 8f, 15, 02, fe, 1d), + be64_to_cpua(29, e6, fb, ca, 8c, d6, b6, b4), + be64_to_cpua(2d, 7a, 91, 5f, 49, 2d, 22, 08), + be64_to_cpua(ee, 2e, 62, 35, 46, fa, 00, d8), + be64_to_cpua(9b, 28, 68, c0, a1, ea, 8c, 50), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(ab, 8d, 4e, de, e6, 6d, 9b, 66), + be64_to_cpua(96, 17, 04, c9, 05, 77, f1, 8e), + be64_to_cpua(44, 92, 8c, 86, 99, 65, b3, 97), + be64_to_cpua(71, cd, 8f, 18, 99, f0, 0f, 13), + be64_to_cpua(bf, e3, 75, 24, 49, ac, fb, c8), + be64_to_cpua(fc, 50, f6, 43, bd, 50, 82, 0e), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, { + .key = /* secp384r1(sha512) */ + "\x04\xb4\xe7\xc1\xeb\x64\x25\x22\x46\xc3\x86\x61\x80\xbe\x1e\x46" + "\xcb\xf6\x05\xc2\xee\x73\x83\xbc\xea\x30\x61\x4d\x40\x05\x41\xf4" + "\x8c\xe3\x0e\x5c\xf0\x50\xf2\x07\x19\xe8\x4f\x25\xbe\xee\x0c\x95" + "\x54\x36\x86\xec\xc2\x20\x75\xf3\x89\xb5\x11\xa1\xb7\xf5\xaf\xbe" + "\x81\xe4\xc3\x39\x06\xbd\xe4\xfe\x68\x1c\x6d\x99\x2b\x1b\x63\xfa" + "\xdf\x42\x5c\xc2\x5a\xc7\x0c\xf4\x15\xf7\x1b\xa3\x2e\xd7\x00\xac" + "\xa3", + .key_len = 97, + .m = + "\xe8\xb7\x52\x7d\x1a\x44\x20\x05\x53\x6b\x3a\x68\xf2\xe7\x6c\xa1" + "\xae\x9d\x84\xbb\xba\x52\x43\x3e\x2c\x42\x78\x49\xbf\x78\xb2\x71" + "\xeb\xe1\xe0\xe8\x42\x7b\x11\xad\x2b\x99\x05\x1d\x36\xe6\xac\xfc" + "\x55\x73\xf0\x15\x63\x39\xb8\x6a\x6a\xc5\x91\x5b\xca\x6a\xa8\x0e", + .m_size = 64, + .c = (const unsigned char[]){ + be64_to_cpua(3e, b3, c7, a8, b3, 17, 77, d1), + be64_to_cpua(dc, 2b, 43, 0e, 6a, b3, 53, 6f), + be64_to_cpua(4c, fc, 6f, 80, e3, af, b3, d9), + be64_to_cpua(9a, 02, de, 93, e8, 83, e4, 84), + be64_to_cpua(4d, c6, ef, da, 02, e7, 0f, 52), + be64_to_cpua(00, 1d, 20, 94, 77, fe, 31, fa), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(4e, 45, cf, 3c, 93, ff, 50, 5d), + be64_to_cpua(34, e4, 8b, 80, a5, b6, da, 2c), + be64_to_cpua(c4, 6a, 03, 5f, 8d, 7a, f9, fb), + be64_to_cpua(ec, 63, e3, 0c, ec, 50, dc, cc), + be64_to_cpua(de, 3a, 3d, 16, af, b4, 52, 6a), + be64_to_cpua(63, f6, f0, 3d, 5f, 5f, 99, 3f), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 00) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, +}; + +static const struct sig_testvec ecdsa_nist_p521_tv_template[] = { + { + .key = /* secp521r1(sha224) */ + "\x04\x01\x4f\x43\x18\xb6\xa9\xc9\x5d\x68\xd3\xa9\x42\xf8\x98\xc0" + "\xd2\xd1\xa9\x50\x3b\xe8\xc4\x40\xe6\x11\x78\x88\x4b\xbd\x76\xa7" + "\x9a\xe0\xdd\x31\xa4\x67\x78\x45\x33\x9e\x8c\xd1\xc7\x44\xac\x61" + "\x68\xc8\x04\xe7\x5c\x79\xb1\xf1\x41\x0c\x71\xc0\x53\xa8\xbc\xfb" + "\xf5\xca\xd4\x01\x40\xfd\xa3\x45\xda\x08\xe0\xb4\xcb\x28\x3b\x0a" + "\x02\x35\x5f\x02\x9f\x3f\xcd\xef\x08\x22\x40\x97\x74\x65\xb7\x76" + "\x85\xc7\xc0\x5c\xfb\x81\xe1\xa5\xde\x0c\x4e\x8b\x12\x31\xb6\x47" + "\xed\x37\x0f\x99\x3f\x26\xba\xa3\x8e\xff\x79\x34\x7c\x3a\xfe\x1f" + "\x3b\x83\x82\x2f\x14", + .key_len = 133, + .m = + "\xa2\x3a\x6a\x8c\x7b\x3c\xf2\x51\xf8\xbe\x5f\x4f\x3b\x15\x05\xc4" + "\xb5\xbc\x19\xe7\x21\x85\xe9\x23\x06\x33\x62\xfb", + .m_size = 28, + .c = (const unsigned char[]){ + be64_to_cpua(46, 6b, c7, af, 7a, b9, 19, 0a), + be64_to_cpua(6c, a6, 9b, 89, 8b, 1e, fd, 09), + be64_to_cpua(98, 85, 29, 88, ff, 0b, 94, 94), + be64_to_cpua(18, c6, 37, 8a, cb, a7, d8, 7d), + be64_to_cpua(f8, 3f, 59, 0f, 74, f0, 3f, d8), + be64_to_cpua(e2, ef, 07, 92, ee, 60, 94, 06), + be64_to_cpua(35, f6, dc, 6d, 02, 7b, 22, ac), + be64_to_cpua(d6, 43, e7, ff, 42, b2, ba, 74), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 01), + be64_to_cpua(50, b1, a5, 98, 92, 2a, a5, 52), + be64_to_cpua(1c, ad, 22, da, 82, 00, 35, a3), + be64_to_cpua(0e, 64, cc, c4, e8, 43, d9, 0e), + be64_to_cpua(30, 90, 0f, 1c, 8f, 78, d3, 9f), + be64_to_cpua(26, 0b, 5f, 49, 32, 6b, 91, 99), + be64_to_cpua(0f, f8, 65, 97, 6b, 09, 4d, 22), + be64_to_cpua(5e, f9, 88, f3, d2, 32, 90, 57), + be64_to_cpua(26, 0d, 55, cd, 23, 1e, 7d, a0), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 3a) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, + { + .key = /* secp521r1(sha256) */ + "\x04\x01\x05\x3a\x6b\x3b\x5a\x0f\xa7\xb9\xb7\x32\x53\x4e\xe2\xae" + "\x0a\x52\xc5\xda\xdd\x5a\x79\x1c\x30\x2d\x33\x07\x79\xd5\x70\x14" + "\x61\x0c\xec\x26\x4d\xd8\x35\x57\x04\x1d\x88\x33\x4d\xce\x05\x36" + "\xa5\xaf\x56\x84\xfa\x0b\x9e\xff\x7b\x30\x4b\x92\x1d\x06\xf8\x81" + "\x24\x1e\x51\x00\x09\x21\x51\xf7\x46\x0a\x77\xdb\xb5\x0c\xe7\x9c" + "\xff\x27\x3c\x02\x71\xd7\x85\x36\xf1\xaa\x11\x59\xd8\xb8\xdc\x09" + "\xdc\x6d\x5a\x6f\x63\x07\x6c\xe1\xe5\x4d\x6e\x0f\x6e\xfb\x7c\x05" + "\x8a\xe9\x53\xa8\xcf\xce\x43\x0e\x82\x20\x86\xbc\x88\x9c\xb7\xe3" + "\xe6\x77\x1e\x1f\x8a", + .key_len = 133, + .m = + "\xcc\x97\x73\x0c\x73\xa2\x53\x2b\xfa\xd7\x83\x1d\x0c\x72\x1b\x39" + "\x80\x71\x8d\xdd\xc5\x9b\xff\x55\x32\x98\x25\xa2\x58\x2e\xb7\x73", + .m_size = 32, + .c = (const unsigned char[]){ + be64_to_cpua(de, 7e, d7, 59, 10, e9, d9, d5), + be64_to_cpua(38, 1f, 46, 0b, 04, 64, 34, 79), + be64_to_cpua(ae, ce, 54, 76, 9a, c2, 8f, b8), + be64_to_cpua(95, 35, 6f, 02, 0e, af, e1, 4c), + be64_to_cpua(56, 3c, f6, f0, d8, e1, b7, 5d), + be64_to_cpua(50, 9f, 7d, 1f, ca, 8b, a8, 2d), + be64_to_cpua(06, 0f, fd, 83, fc, 0e, d9, ce), + be64_to_cpua(a5, 5f, 57, 52, 27, 78, 3a, b5), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, cd), + be64_to_cpua(55, 38, b6, f6, 34, 65, c7, bd), + be64_to_cpua(1c, 57, 56, 8f, 12, b7, 1d, 91), + be64_to_cpua(03, 42, 02, 5f, 50, f0, a2, 0d), + be64_to_cpua(fa, 10, dd, 9b, fb, 36, 1a, 31), + be64_to_cpua(e0, 87, 2c, 44, 4b, 5a, ee, af), + be64_to_cpua(a9, 79, 24, b9, 37, 35, dd, a0), + be64_to_cpua(6b, 35, ae, 65, b5, 99, 12, 0a), + be64_to_cpua(50, 85, 38, f9, 15, 83, 18, 04), + be64_to_cpua(00, 00, 00, 00, 00, 00, 01, cf) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, + { + .key = /* secp521r1(sha384) */ + "\x04\x00\x2e\xd6\x21\x04\x75\xc3\xdc\x7d\xff\x0e\xf3\x70\x25\x2b" + "\xad\x72\xfc\x5a\x91\xf1\xd5\x9c\x64\xf3\x1f\x47\x11\x10\x62\x33" + "\xfd\x2e\xe8\x32\xca\x9e\x6f\x0a\x4c\x5b\x35\x9a\x46\xc5\xe7\xd4" + "\x38\xda\xb2\xf0\xf4\x87\xf3\x86\xf4\xea\x70\xad\x1e\xd4\x78\x8c" + "\x36\x18\x17\x00\xa2\xa0\x34\x1b\x2e\x6a\xdf\x06\xd6\x99\x2d\x47" + "\x50\x92\x1a\x8a\x72\x9c\x23\x44\xfa\xa7\xa9\xed\xa6\xef\x26\x14" + "\xb3\x9d\xfe\x5e\xa3\x8c\xd8\x29\xf8\xdf\xad\xa6\xab\xfc\xdd\x46" + "\x22\x6e\xd7\x35\xc7\x23\xb7\x13\xae\xb6\x34\xff\xd7\x80\xe5\x39" + "\xb3\x3b\x5b\x1b\x94", + .key_len = 133, + .m = + "\x36\x98\xd6\x82\xfa\xad\xed\x3c\xb9\x40\xb6\x4d\x9e\xb7\x04\x26" + "\xad\x72\x34\x44\xd2\x81\xb4\x9b\xbe\x01\x04\x7a\xd8\x50\xf8\x59" + "\xba\xad\x23\x85\x6b\x59\xbe\xfb\xf6\x86\xd4\x67\xa8\x43\x28\x76", + .m_size = 48, + .c = (const unsigned char[]){ + be64_to_cpua(b8, 6a, dd, fb, e6, 63, 4e, 28), + be64_to_cpua(84, 59, fd, 1a, c4, 40, dd, 43), + be64_to_cpua(32, 76, 06, d0, f9, c0, e4, e6), + be64_to_cpua(e4, df, 9b, 7d, 9e, 47, ca, 33), + be64_to_cpua(7e, 42, 71, 86, 57, 2d, f1, 7d), + be64_to_cpua(f2, 4b, 64, 98, f7, ec, da, c7), + be64_to_cpua(ec, 51, dc, e8, 35, 5e, ae, 16), + be64_to_cpua(96, 76, 3c, 27, ea, aa, 9c, 26), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, 93), + be64_to_cpua(c6, 4f, ab, 2b, 62, c1, 42, b1), + be64_to_cpua(e5, 5a, 94, 56, cf, 8f, b4, 22), + be64_to_cpua(6a, c3, f3, 7a, d1, fa, e7, a7), + be64_to_cpua(df, c4, c0, db, 54, db, 8a, 0d), + be64_to_cpua(da, a7, cd, 26, 28, 76, 3b, 52), + be64_to_cpua(e4, 3c, bc, 93, 65, 57, 1c, 30), + be64_to_cpua(55, ce, 37, 97, c9, 05, 51, e5), + be64_to_cpua(c3, 6a, 87, 6e, b5, 13, 1f, 20), + be64_to_cpua(00, 00, 00, 00, 00, 00, 00, ff) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, + { + .key = /* secp521r1(sha512) */ + "\x04\x00\xc7\x65\xee\x0b\x86\x7d\x8f\x02\xf1\x74\x5b\xb0\x4c\x3f" + "\xa6\x35\x60\x9f\x55\x23\x11\xcc\xdf\xb8\x42\x99\xee\x6c\x96\x6a" + "\x27\xa2\x56\xb2\x2b\x03\xad\x0f\xe7\x97\xde\x09\x5d\xb4\xc5\x5f" + "\xbd\x87\x37\xbf\x5a\x16\x35\x56\x08\xfd\x6f\x06\x1a\x1c\x84\xee" + "\xc3\x64\xb3\x00\x9e\xbd\x6e\x60\x76\xee\x69\xfd\x3a\xb8\xcd\x7e" + "\x91\x68\x53\x57\x44\x13\x2e\x77\x09\x2a\xbe\x48\xbd\x91\xd8\xf6" + "\x21\x16\x53\x99\xd5\xf0\x40\xad\xa6\xf8\x58\x26\xb6\x9a\xf8\x77" + "\xfe\x3a\x05\x1a\xdb\xa9\x0f\xc0\x6c\x76\x30\x8c\xd8\xde\x44\xae" + "\xd0\x17\xdf\x49\x6a", + .key_len = 133, + .m = + "\x5c\xa6\xbc\x79\xb8\xa0\x1e\x11\x83\xf7\xe9\x05\xdf\xba\xf7\x69" + "\x97\x22\x32\xe4\x94\x7c\x65\xbd\x74\xc6\x9a\x8b\xbd\x0d\xdc\xed" + "\xf5\x9c\xeb\xe1\xc5\x68\x40\xf2\xc7\x04\xde\x9e\x0d\x76\xc5\xa3" + "\xf9\x3c\x6c\x98\x08\x31\xbd\x39\xe8\x42\x7f\x80\x39\x6f\xfe\x68", + .m_size = 64, + .c = (const unsigned char[]){ + be64_to_cpua(28, b5, 04, b0, b6, 33, 1c, 7e), + be64_to_cpua(80, a6, 13, fc, b6, 90, f7, bb), + be64_to_cpua(27, 93, e8, 6c, 49, 7d, 28, fc), + be64_to_cpua(1f, 12, 3e, b7, 7e, 51, ff, 7f), + be64_to_cpua(fb, 62, 1e, 42, 03, 6c, 74, 8a), + be64_to_cpua(63, 0e, 02, cc, 94, a9, 05, b9), + be64_to_cpua(aa, 86, ec, a8, 05, 03, 52, 56), + be64_to_cpua(71, 86, 96, ac, 21, 33, 7e, 4e), + be64_to_cpua(00, 00, 00, 00, 00, 00, 01, 5c), + be64_to_cpua(46, 1e, 77, 44, 78, e0, d1, 04), + be64_to_cpua(72, 74, 13, 63, 39, a6, e5, 25), + be64_to_cpua(00, 55, bb, 6a, b4, 73, 00, d2), + be64_to_cpua(71, d0, e9, ca, a7, c0, cb, aa), + be64_to_cpua(7a, 76, 37, 51, 47, 49, 98, 12), + be64_to_cpua(88, 05, 3e, 43, 39, 01, bd, b7), + be64_to_cpua(95, 35, 89, 4f, 41, 5f, 9e, 19), + be64_to_cpua(43, 52, 1d, e3, c6, bd, 5a, 40), + be64_to_cpua(00, 00, 00, 00, 00, 00, 01, 70) }, + .c_size = ECC_MAX_BYTES * 2, + .public_key_vec = true, + }, +}; + +/* + * ECDSA X9.62 test vectors. + * + * Identical to ECDSA test vectors, except signature in "c" is X9.62 encoded. + */ +static const struct sig_testvec x962_ecdsa_nist_p192_tv_template[] = { + { + .key = /* secp192r1(sha1) */ "\x04\xf7\x46\xf8\x2f\x15\xf6\x22\x8e\xd7\x57\x4f\xcc\xe7\xbb\xc1" "\xd4\x09\x73\xcf\xea\xd0\x15\x07\x3d\xa5\x8a\x8a\x95\x43\xe4\x68" "\xea\xc6\x25\xc1\xc1\x01\x25\x4c\x7e\xc3\x3c\xa6\x04\x0a\xe7\x08" "\x98", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\xcd\xb9\xd2\x1c\xb7\x6f\xcd\x44\xb3\xfd\x63\xea\xa3\x66\x7f\xae" "\x63\x85\xe7\x82", .m_size = 20, - .algo = OID_id_ecdsa_with_sha1, .c = "\x30\x35\x02\x19\x00\xba\xe5\x93\x83\x6e\xb6\x3b\x63\xa0\x27\x91" "\xc6\xf6\x7f\xc3\x09\xad\x59\xad\x88\x27\xd6\x92\x6b\x02\x18\x10" @@ -674,23 +1371,17 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x80\x6f\xa5\x79\x77\xda\xd0", .c_size = 55, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp192r1(sha224) */ "\x04\xb6\x4b\xb1\xd1\xac\xba\x24\x8f\x65\xb2\x60\x00\x90\xbf\xbd" "\x78\x05\x73\xe9\x79\x1d\x6f\x7c\x0b\xd2\xc3\x93\xa7\x28\xe1\x75" "\xf7\xd5\x95\x1d\x28\x10\xc0\x75\x50\x5c\x1a\x4f\x3f\x8f\xa5\xee" "\xa3", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\x8d\xd6\xb8\x3e\xe5\xff\x23\xf6\x25\xa2\x43\x42\x74\x45\xa7\x40" "\x3a\xff\x2f\xe1\xd3\xf6\x9f\xe8\x33\xcb\x12\x11", .m_size = 28, - .algo = OID_id_ecdsa_with_sha224, .c = "\x30\x34\x02\x18\x5a\x8b\x82\x69\x7e\x8a\x0a\x09\x14\xf8\x11\x2b" "\x55\xdc\xae\x37\x83\x7b\x12\xe6\xb6\x5b\xcb\xd4\x02\x18\x6a\x14" @@ -698,23 +1389,17 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x5c\x99\xdb\x92\x5b\x36", .c_size = 54, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp192r1(sha256) */ "\x04\xe2\x51\x24\x9b\xf7\xb6\x32\x82\x39\x66\x3d\x5b\xec\x3b\xae" "\x0c\xd5\xf2\x67\xd1\xc7\xe1\x02\xe4\xbf\x90\x62\xb8\x55\x75\x56" "\x69\x20\x5e\xcb\x4e\xca\x33\xd6\xcb\x62\x6b\x94\xa9\xa2\xe9\x58" "\x91", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\x35\xec\xa1\xa0\x9e\x14\xde\x33\x03\xb6\xf6\xbd\x0c\x2f\xb2\xfd" "\x1f\x27\x82\xa5\xd7\x70\x3f\xef\xa0\x82\x69\x8e\x73\x31\x8e\xd7", .m_size = 32, - .algo = OID_id_ecdsa_with_sha256, .c = "\x30\x35\x02\x18\x3f\x72\x3f\x1f\x42\xd2\x3f\x1d\x6b\x1a\x58\x56" "\xf1\x8f\xf7\xfd\x01\x48\xfb\x5f\x72\x2a\xd4\x8f\x02\x19\x00\xb3" @@ -722,24 +1407,18 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x3a\x97\xd9\xcd\x1a\x6a\x49", .c_size = 55, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp192r1(sha384) */ "\x04\x5a\x13\xfe\x68\x86\x4d\xf4\x17\xc7\xa4\xe5\x8c\x65\x57\xb7" "\x03\x73\x26\x57\xfb\xe5\x58\x40\xd8\xfd\x49\x05\xab\xf1\x66\x1f" "\xe2\x9d\x93\x9e\xc2\x22\x5a\x8b\x4f\xf3\x77\x22\x59\x7e\xa6\x4e" "\x8b", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\x9d\x2e\x1a\x8f\xed\x6c\x4b\x61\xae\xac\xd5\x19\x79\xce\x67\xf9" "\xa0\x34\xeb\xb0\x81\xf9\xd9\xdc\x6e\xb3\x5c\xa8\x69\xfc\x8a\x61" "\x39\x81\xfb\xfd\x5c\x30\x6b\xa8\xee\xed\x89\xaf\xa3\x05\xe4\x78", .m_size = 48, - .algo = OID_id_ecdsa_with_sha384, .c = "\x30\x35\x02\x19\x00\xf0\xa3\x38\xce\x2b\xf8\x9d\x1a\xcf\x7f\x34" "\xb4\xb4\xe5\xc5\x00\xdd\x15\xbb\xd6\x8c\xa7\x03\x78\x02\x18\x64" @@ -747,25 +1426,19 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x12\x3b\x3b\x28\xfb\x6d\xe1", .c_size = 55, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp192r1(sha512) */ "\x04\xd5\xf2\x6e\xc3\x94\x5c\x52\xbc\xdf\x86\x6c\x14\xd1\xca\xea" "\xcc\x72\x3a\x8a\xf6\x7a\x3a\x56\x36\x3b\xca\xc6\x94\x0e\x17\x1d" "\x9e\xa0\x58\x28\xf9\x4b\xe6\xd1\xa5\x44\x91\x35\x0d\xe7\xf5\x11" "\x57", .key_len = 49, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x01", - .param_len = 21, .m = "\xd5\x4b\xe9\x36\xda\xd8\x6e\xc0\x50\x03\xbe\x00\x43\xff\xf0\x23" "\xac\xa2\x42\xe7\x37\x77\x79\x52\x8f\x3e\xc0\x16\xc1\xfc\x8c\x67" "\x16\xbc\x8a\x5d\x3b\xd3\x13\xbb\xb6\xc0\x26\x1b\xeb\x33\xcc\x70" "\x4a\xf2\x11\x37\xe8\x1b\xba\x55\xac\x69\xe1\x74\x62\x7c\x6e\xb5", .m_size = 64, - .algo = OID_id_ecdsa_with_sha512, .c = "\x30\x35\x02\x19\x00\x88\x5b\x8f\x59\x43\xbf\xcf\xc6\xdd\x3f\x07" "\x87\x12\xa0\xd4\xac\x2b\x11\x2d\x1c\xb6\x06\xc9\x6c\x02\x18\x73" @@ -773,28 +1446,22 @@ static const struct akcipher_testvec ecdsa_nist_p192_tv_template[] = { "\x6a\xdf\x97\xfd\x82\x76\x24", .c_size = 55, .public_key_vec = true, - .siggen_sigver_test = true, }, }; -static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { +static const struct sig_testvec x962_ecdsa_nist_p256_tv_template[] = { { - .key = + .key = /* secp256r1(sha1) */ "\x04\xb9\x7b\xbb\xd7\x17\x64\xd2\x7e\xfc\x81\x5d\x87\x06\x83\x41" "\x22\xd6\x9a\xaa\x87\x17\xec\x4f\x63\x55\x2f\x94\xba\xdd\x83\xe9" "\x34\x4b\xf3\xe9\x91\x13\x50\xb6\xcb\xca\x62\x08\xe7\x3b\x09\xdc" "\xc3\x63\x4b\x2d\xb9\x73\x53\xe4\x45\xe6\x7c\xad\xe7\x6b\xb0\xe8" "\xaf", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\xc2\x2b\x5f\x91\x78\x34\x26\x09\x42\x8d\x6f\x51\xb2\xc5\xaf\x4c" "\x0b\xde\x6a\x42", .m_size = 20, - .algo = OID_id_ecdsa_with_sha1, .c = "\x30\x46\x02\x21\x00\xf9\x25\xce\x9f\x3a\xa6\x35\x81\xcf\xd4\xe7" "\xb7\xf0\x82\x56\x41\xf7\xd4\xad\x8d\x94\x5a\x69\x89\xee\xca\x6a" @@ -803,24 +1470,18 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\xfb\x9d\x8b\xde\xd4\x8d\x6f\xad", .c_size = 72, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp256r1(sha224) */ "\x04\x8b\x6d\xc0\x33\x8e\x2d\x8b\x67\xf5\xeb\xc4\x7f\xa0\xf5\xd9" "\x7b\x03\xa5\x78\x9a\xb5\xea\x14\xe4\x23\xd0\xaf\xd7\x0e\x2e\xa0" "\xc9\x8b\xdb\x95\xf8\xb3\xaf\xac\x00\x2c\x2c\x1f\x7a\xfd\x95\x88" "\x43\x13\xbf\xf3\x1c\x05\x1a\x14\x18\x09\x3f\xd6\x28\x3e\xc5\xa0" "\xd4", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\x1a\x15\xbc\xa3\xe4\xed\x3a\xb8\x23\x67\xc6\xc4\x34\xf8\x6c\x41" "\x04\x0b\xda\xc5\x77\xfa\x1c\x2d\xe6\x2c\x3b\xe0", .m_size = 28, - .algo = OID_id_ecdsa_with_sha224, .c = "\x30\x44\x02\x20\x20\x43\xfa\xc0\x9f\x9d\x7b\xe7\xae\xce\x77\x59" "\x1a\xdb\x59\xd5\x34\x62\x79\xcb\x6a\x91\x67\x2e\x7d\x25\xd8\x25" @@ -829,24 +1490,18 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\x2e\x8b\xde\x5a\x04\x0e", .c_size = 70, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp256r1(sha256) */ "\x04\xf1\xea\xc4\x53\xf3\xb9\x0e\x9f\x7e\xad\xe3\xea\xd7\x0e\x0f" "\xd6\x98\x9a\xca\x92\x4d\x0a\x80\xdb\x2d\x45\xc7\xec\x4b\x97\x00" "\x2f\xe9\x42\x6c\x29\xdc\x55\x0e\x0b\x53\x12\x9b\x2b\xad\x2c\xe9" "\x80\xe6\xc5\x43\xc2\x1d\x5e\xbb\x65\x21\x50\xb6\x37\xb0\x03\x8e" "\xb8", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\x8f\x43\x43\x46\x64\x8f\x6b\x96\xdf\x89\xdd\xa9\x01\xc5\x17\x6b" "\x10\xa6\xd8\x39\x61\xdd\x3c\x1a\xc8\x8b\x59\xb2\xdc\x32\x7a\xa4", .m_size = 32, - .algo = OID_id_ecdsa_with_sha256, .c = "\x30\x45\x02\x20\x08\x31\xfa\x74\x0d\x1d\x21\x5d\x09\xdc\x29\x63" "\xa8\x1a\xad\xfc\xac\x44\xc3\xe8\x24\x11\x2d\xa4\x91\xdc\x02\x67" @@ -855,25 +1510,19 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\x2a\x65\x35\x23\xe3\x1d\xfa", .c_size = 71, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp256r1(sha384) */ "\x04\xc5\xc6\xea\x60\xc9\xce\xad\x02\x8d\xf5\x3e\x24\xe3\x52\x1d" "\x28\x47\x3b\xc3\x6b\xa4\x99\x35\x99\x11\x88\x88\xc8\xf4\xee\x7e" "\x8c\x33\x8f\x41\x03\x24\x46\x2b\x1a\x82\xf9\x9f\xe1\x97\x1b\x00" "\xda\x3b\x24\x41\xf7\x66\x33\x58\x3d\x3a\x81\xad\xcf\x16\xe9\xe2" "\x7c", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\x3e\x78\x70\xfb\xcd\x66\xba\x91\xa1\x79\xff\x1e\x1c\x6b\x78\xe6" "\xc0\x81\x3a\x65\x97\x14\x84\x36\x14\x1a\x9a\xb7\xc5\xab\x84\x94" "\x5e\xbb\x1b\x34\x71\xcb\x41\xe1\xf6\xfc\x92\x7b\x34\xbb\x86\xbb", .m_size = 48, - .algo = OID_id_ecdsa_with_sha384, .c = "\x30\x46\x02\x21\x00\x8e\xf3\x6f\xdc\xf8\x69\xa6\x2e\xd0\x2e\x95" "\x54\xd1\x95\x64\x93\x08\xb2\x6b\x24\x94\x48\x46\x5e\xf2\xe4\x6c" @@ -882,26 +1531,20 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\xc0\x60\x11\x92\xdc\x17\x89\x12", .c_size = 72, .public_key_vec = true, - .siggen_sigver_test = true, }, { - .key = + .key = /* secp256r1(sha512) */ "\x04\xd7\x27\x46\x49\xf6\x26\x85\x12\x40\x76\x8e\xe2\xe6\x2a\x7a" "\x83\xb1\x4e\x7a\xeb\x3b\x5c\x67\x4a\xb5\xa4\x92\x8c\x69\xff\x38" "\xee\xd9\x4e\x13\x29\x59\xad\xde\x6b\xbb\x45\x31\xee\xfd\xd1\x1b" "\x64\xd3\xb5\xfc\xaf\x9b\x4b\x88\x3b\x0e\xb7\xd6\xdf\xf1\xd5\x92" "\xbf", .key_len = 65, - .params = - "\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48" - "\xce\x3d\x03\x01\x07", - .param_len = 21, .m = "\x57\xb7\x9e\xe9\x05\x0a\x8c\x1b\xc9\x13\xe5\x4a\x24\xc7\xe2\xe9" "\x43\xc3\xd1\x76\x62\xf4\x98\x1a\x9c\x13\xb0\x20\x1b\xe5\x39\xca" "\x4f\xd9\x85\x34\x95\xa2\x31\xbc\xbb\xde\xdd\x76\xbb\x61\xe3\xcf" "\x9d\xc0\x49\x7a\xf3\x7a\xc4\x7d\xa8\x04\x4b\x8d\xb4\x4d\x5b\xd6", .m_size = 64, - .algo = OID_id_ecdsa_with_sha512, .c = "\x30\x45\x02\x21\x00\xb8\x6d\x87\x81\x43\xdf\xfb\x9f\x40\xea\x44" "\x81\x00\x4e\x29\x08\xed\x8c\x73\x30\x6c\x22\xb3\x97\x76\xf6\x04" @@ -910,11 +1553,10 @@ static const struct akcipher_testvec ecdsa_nist_p256_tv_template[] = { "\x31\x79\x4a\xe9\x81\x6a\xee", .c_size = 71, .public_key_vec = true, - .siggen_sigver_test = true, }, }; -static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { +static const struct sig_testvec x962_ecdsa_nist_p384_tv_template[] = { { .key = /* secp384r1(sha1) */ "\x04\x89\x25\xf3\x97\x88\xcb\xb0\x78\xc5\x72\x9a\x14\x6e\x7a\xb1" @@ -925,15 +1567,10 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x0b\x25\xd6\x80\x5c\x3b\xe6\x1a\x98\x48\x91\x45\x7a\x73\xb0\xc3" "\xf1", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\x12\x55\x28\xf0\x77\xd5\xb6\x21\x71\x32\x48\xcd\x28\xa8\x25\x22" "\x3a\x69\xc1\x93", .m_size = 20, - .algo = OID_id_ecdsa_with_sha1, .c = "\x30\x66\x02\x31\x00\xf5\x0f\x24\x4c\x07\x93\x6f\x21\x57\x55\x07" "\x20\x43\x30\xde\xa0\x8d\x26\x8e\xae\x63\x3f\xbc\x20\x3a\xc6\xf1" @@ -944,7 +1581,6 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x79\x12\x2a\xb7\xc5\x15\x92\xc5", .c_size = 104, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp384r1(sha224) */ "\x04\x69\x6c\xcf\x62\xee\xd0\x0d\xe5\xb5\x2f\x70\x54\xcf\x26\xa0" @@ -955,15 +1591,10 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x6b\x93\x99\x6c\x66\x4c\x42\x3f\x65\x60\x6c\x1c\x0b\x93\x9b\x9d" "\xe0", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\x12\x80\xb6\xeb\x25\xe2\x3d\xf0\x21\x32\x96\x17\x3a\x38\x39\xfd" "\x1f\x05\x34\x7b\xb8\xf9\x71\x66\x03\x4f\xd5\xe5", .m_size = 28, - .algo = OID_id_ecdsa_with_sha224, .c = "\x30\x66\x02\x31\x00\x8a\x51\x84\xce\x13\x1e\xd2\xdc\xec\xcb\xe4" "\x89\x47\xb2\xf7\xbc\x97\xf1\xc8\x72\x26\xcf\x5a\x5e\xc5\xda\xb4" @@ -974,7 +1605,6 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x88\x2b\x82\x26\x5e\x1c\xda\xfb", .c_size = 104, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp384r1(sha256) */ "\x04\xee\xd6\xda\x3e\x94\x90\x00\x27\xed\xf8\x64\x55\xd6\x51\x9a" @@ -985,15 +1615,10 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x17\xc3\x34\x29\xd6\x40\xea\x5c\xb9\x3f\xfb\x32\x2e\x12\x33\xbc" "\xab", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\xaa\xe7\xfd\x03\x26\xcb\x94\x71\xe4\xce\x0f\xc5\xff\xa6\x29\xa3" "\xe1\xcc\x4c\x35\x4e\xde\xca\x80\xab\x26\x0c\x25\xe6\x68\x11\xc2", .m_size = 32, - .algo = OID_id_ecdsa_with_sha256, .c = "\x30\x64\x02\x30\x08\x09\x12\x9d\x6e\x96\x64\xa6\x8e\x3f\x7e\xce" "\x0a\x9b\xaa\x59\xcc\x47\x53\x87\xbc\xbd\x83\x3f\xaf\x06\x3f\x84" @@ -1004,7 +1629,6 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\xf4\x1f\x39\xca\x4d\x43", .c_size = 102, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp384r1(sha384) */ "\x04\x3a\x2f\x62\xe7\x1a\xcf\x24\xd0\x0b\x7c\xe0\xed\x46\x0a\x4f" @@ -1015,16 +1639,11 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x21\x67\xe5\x1b\x5a\x52\x31\x68\xd6\xee\xf0\x19\xb0\x55\xed\x89" "\x9e", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\x8d\xf2\xc0\xe9\xa8\xf3\x8e\x44\xc4\x8c\x1a\xa0\xb8\xd7\x17\xdf" "\xf2\x37\x1b\xc6\xe3\xf5\x62\xcc\x68\xf5\xd5\x0b\xbf\x73\x2b\xb1" "\xb0\x4c\x04\x00\x31\xab\xfe\xc8\xd6\x09\xc8\xf2\xea\xd3\x28\xff", .m_size = 48, - .algo = OID_id_ecdsa_with_sha384, .c = "\x30\x66\x02\x31\x00\x9b\x28\x68\xc0\xa1\xea\x8c\x50\xee\x2e\x62" "\x35\x46\xfa\x00\xd8\x2d\x7a\x91\x5f\x49\x2d\x22\x08\x29\xe6\xfb" @@ -1035,7 +1654,6 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\xab\x8d\x4e\xde\xe6\x6d\x9b\x66", .c_size = 104, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp384r1(sha512) */ "\x04\xb4\xe7\xc1\xeb\x64\x25\x22\x46\xc3\x86\x61\x80\xbe\x1e\x46" @@ -1046,17 +1664,12 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\xdf\x42\x5c\xc2\x5a\xc7\x0c\xf4\x15\xf7\x1b\xa3\x2e\xd7\x00\xac" "\xa3", .key_len = 97, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x22", - .param_len = 18, .m = "\xe8\xb7\x52\x7d\x1a\x44\x20\x05\x53\x6b\x3a\x68\xf2\xe7\x6c\xa1" "\xae\x9d\x84\xbb\xba\x52\x43\x3e\x2c\x42\x78\x49\xbf\x78\xb2\x71" "\xeb\xe1\xe0\xe8\x42\x7b\x11\xad\x2b\x99\x05\x1d\x36\xe6\xac\xfc" "\x55\x73\xf0\x15\x63\x39\xb8\x6a\x6a\xc5\x91\x5b\xca\x6a\xa8\x0e", .m_size = 64, - .algo = OID_id_ecdsa_with_sha512, .c = "\x30\x63\x02\x2f\x1d\x20\x94\x77\xfe\x31\xfa\x4d\xc6\xef\xda\x02" "\xe7\x0f\x52\x9a\x02\xde\x93\xe8\x83\xe4\x84\x4c\xfc\x6f\x80\xe3" @@ -1067,11 +1680,10 @@ static const struct akcipher_testvec ecdsa_nist_p384_tv_template[] = { "\x3c\x93\xff\x50\x5d", .c_size = 101, .public_key_vec = true, - .siggen_sigver_test = true, }, }; -static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { +static const struct sig_testvec x962_ecdsa_nist_p521_tv_template[] = { { .key = /* secp521r1(sha224) */ "\x04\x01\x4f\x43\x18\xb6\xa9\xc9\x5d\x68\xd3\xa9\x42\xf8\x98\xc0" @@ -1084,15 +1696,10 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xed\x37\x0f\x99\x3f\x26\xba\xa3\x8e\xff\x79\x34\x7c\x3a\xfe\x1f" "\x3b\x83\x82\x2f\x14", .key_len = 133, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x23", - .param_len = 18, .m = "\xa2\x3a\x6a\x8c\x7b\x3c\xf2\x51\xf8\xbe\x5f\x4f\x3b\x15\x05\xc4" "\xb5\xbc\x19\xe7\x21\x85\xe9\x23\x06\x33\x62\xfb", .m_size = 28, - .algo = OID_id_ecdsa_with_sha224, .c = "\x30\x81\x86\x02\x41\x01\xd6\x43\xe7\xff\x42\xb2\xba\x74\x35\xf6" "\xdc\x6d\x02\x7b\x22\xac\xe2\xef\x07\x92\xee\x60\x94\x06\xf8\x3f" @@ -1105,7 +1712,6 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xa3\x50\xb1\xa5\x98\x92\x2a\xa5\x52", .c_size = 137, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp521r1(sha256) */ @@ -1119,15 +1725,10 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\x8a\xe9\x53\xa8\xcf\xce\x43\x0e\x82\x20\x86\xbc\x88\x9c\xb7\xe3" "\xe6\x77\x1e\x1f\x8a", .key_len = 133, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x23", - .param_len = 18, .m = "\xcc\x97\x73\x0c\x73\xa2\x53\x2b\xfa\xd7\x83\x1d\x0c\x72\x1b\x39" "\x80\x71\x8d\xdd\xc5\x9b\xff\x55\x32\x98\x25\xa2\x58\x2e\xb7\x73", .m_size = 32, - .algo = OID_id_ecdsa_with_sha256, .c = "\x30\x81\x88\x02\x42\x00\xcd\xa5\x5f\x57\x52\x27\x78\x3a\xb5\x06" "\x0f\xfd\x83\xfc\x0e\xd9\xce\x50\x9f\x7d\x1f\xca\x8b\xa8\x2d\x56" @@ -1140,7 +1741,6 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xb7\x1d\x91\x55\x38\xb6\xf6\x34\x65\xc7\xbd", .c_size = 139, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp521r1(sha384) */ @@ -1154,16 +1754,11 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\x22\x6e\xd7\x35\xc7\x23\xb7\x13\xae\xb6\x34\xff\xd7\x80\xe5\x39" "\xb3\x3b\x5b\x1b\x94", .key_len = 133, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x23", - .param_len = 18, .m = "\x36\x98\xd6\x82\xfa\xad\xed\x3c\xb9\x40\xb6\x4d\x9e\xb7\x04\x26" "\xad\x72\x34\x44\xd2\x81\xb4\x9b\xbe\x01\x04\x7a\xd8\x50\xf8\x59" "\xba\xad\x23\x85\x6b\x59\xbe\xfb\xf6\x86\xd4\x67\xa8\x43\x28\x76", .m_size = 48, - .algo = OID_id_ecdsa_with_sha384, .c = "\x30\x81\x88\x02\x42\x00\x93\x96\x76\x3c\x27\xea\xaa\x9c\x26\xec" "\x51\xdc\xe8\x35\x5e\xae\x16\xf2\x4b\x64\x98\xf7\xec\xda\xc7\x7e" @@ -1176,7 +1771,6 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\x8f\xb4\x22\xc6\x4f\xab\x2b\x62\xc1\x42\xb1", .c_size = 139, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = /* secp521r1(sha512) */ @@ -1190,17 +1784,12 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xfe\x3a\x05\x1a\xdb\xa9\x0f\xc0\x6c\x76\x30\x8c\xd8\xde\x44\xae" "\xd0\x17\xdf\x49\x6a", .key_len = 133, - .params = - "\x30\x10\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x05\x2b\x81\x04" - "\x00\x23", - .param_len = 18, .m = "\x5c\xa6\xbc\x79\xb8\xa0\x1e\x11\x83\xf7\xe9\x05\xdf\xba\xf7\x69" "\x97\x22\x32\xe4\x94\x7c\x65\xbd\x74\xc6\x9a\x8b\xbd\x0d\xdc\xed" "\xf5\x9c\xeb\xe1\xc5\x68\x40\xf2\xc7\x04\xde\x9e\x0d\x76\xc5\xa3" "\xf9\x3c\x6c\x98\x08\x31\xbd\x39\xe8\x42\x7f\x80\x39\x6f\xfe\x68", .m_size = 64, - .algo = OID_id_ecdsa_with_sha512, .c = "\x30\x81\x88\x02\x42\x01\x5c\x71\x86\x96\xac\x21\x33\x7e\x4e\xaa" "\x86\xec\xa8\x05\x03\x52\x56\x63\x0e\x02\xcc\x94\xa9\x05\xb9\xfb" @@ -1213,14 +1802,41 @@ static const struct akcipher_testvec ecdsa_nist_p521_tv_template[] = { "\xa6\xe5\x25\x46\x1e\x77\x44\x78\xe0\xd1\x04", .c_size = 139, .public_key_vec = true, - .siggen_sigver_test = true, + }, +}; + +/* + * ECDSA P1363 test vectors. + * + * Identical to ECDSA test vectors, except signature in "c" is P1363 encoded. + */ +static const struct sig_testvec p1363_ecdsa_nist_p256_tv_template[] = { + { + .key = /* secp256r1(sha256) */ + "\x04\xf1\xea\xc4\x53\xf3\xb9\x0e\x9f\x7e\xad\xe3\xea\xd7\x0e\x0f" + "\xd6\x98\x9a\xca\x92\x4d\x0a\x80\xdb\x2d\x45\xc7\xec\x4b\x97\x00" + "\x2f\xe9\x42\x6c\x29\xdc\x55\x0e\x0b\x53\x12\x9b\x2b\xad\x2c\xe9" + "\x80\xe6\xc5\x43\xc2\x1d\x5e\xbb\x65\x21\x50\xb6\x37\xb0\x03\x8e" + "\xb8", + .key_len = 65, + .m = + "\x8f\x43\x43\x46\x64\x8f\x6b\x96\xdf\x89\xdd\xa9\x01\xc5\x17\x6b" + "\x10\xa6\xd8\x39\x61\xdd\x3c\x1a\xc8\x8b\x59\xb2\xdc\x32\x7a\xa4", + .m_size = 32, + .c = + "\x08\x31\xfa\x74\x0d\x1d\x21\x5d\x09\xdc\x29\x63\xa8\x1a\xad\xfc" + "\xac\x44\xc3\xe8\x24\x11\x2d\xa4\x91\xdc\x02\x67\xdc\x0c\xd0\x82" + "\xbd\xff\xce\xee\x42\xc3\x97\xff\xf9\xa9\x81\xac\x4a\x50\xd0\x91" + "\x0a\x6e\x1b\xc4\xaf\xe1\x83\xc3\x4f\x2a\x65\x35\x23\xe3\x1d\xfa", + .c_size = 64, + .public_key_vec = true, }, }; /* * EC-RDSA test vectors are generated by gost-engine. */ -static const struct akcipher_testvec ecrdsa_tv_template[] = { +static const struct sig_testvec ecrdsa_tv_template[] = { { .key = "\x04\x40\xd5\xa7\x77\xf9\x26\x2f\x8c\xbd\xcc\xe3\x1f\x01\x94\x05" @@ -1245,7 +1861,6 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\x79\xd2\x76\x64\xa3\xbd\x66\x10\x79\x05\x5a\x06\x42\xec\xb9\xc9", .m_size = 32, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = @@ -1271,7 +1886,6 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\x11\x23\x4a\x70\x43\x52\x7a\x68\x11\x65\x45\x37\xbb\x25\xb7\x40", .m_size = 32, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = @@ -1297,7 +1911,6 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\x9f\x16\xc6\x1c\xb1\x3f\x84\x41\x69\xec\x34\xfd\xf1\xf9\xa3\x39", .m_size = 32, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = @@ -1332,7 +1945,6 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\xa8\xf6\x80\x01\xb9\x27\xac\xd8\x45\x96\x66\xa1\xee\x48\x08\x3f", .m_size = 64, .public_key_vec = true, - .siggen_sigver_test = true, }, { .key = @@ -1367,14 +1979,68 @@ static const struct akcipher_testvec ecrdsa_tv_template[] = { "\x6d\xf4\xd2\x45\xc2\x83\xa0\x42\x95\x05\x9d\x89\x8e\x0a\xca\xcc", .m_size = 64, .public_key_vec = true, - .siggen_sigver_test = true, + }, +}; + +/* + * PKCS#1 RSA test vectors for hash algorithm "none" + * (i.e. the hash in "m" is not prepended by a Full Hash Prefix) + * + * Obtained from: + * https://vcsjones.dev/sometimes-valid-rsa-dotnet/ + * https://gist.github.com/vcsjones/ab4c2327b53ed018eada76b75ef4fd99 + */ +static const struct sig_testvec pkcs1_rsa_none_tv_template[] = { + { + .key = + "\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xa2\x63\x0b\x39\x44\xb8\xbb" + "\x23\xa7\x44\x49\xbb\x0e\xff\xa1\xf0\x61\x0a\x53\x93\xb0\x98\xdb" + "\xad\x2c\x0f\x4a\xc5\x6e\xff\x86\x3c\x53\x55\x0f\x15\xce\x04\x3f" + "\x2b\xfd\xa9\x96\x96\xd9\xbe\x61\x79\x0b\x5b\xc9\x4c\x86\x76\xe5" + "\xe0\x43\x4b\x22\x95\xee\xc2\x2b\x43\xc1\x9f\xd8\x68\xb4\x8e\x40" + "\x4f\xee\x85\x38\xb9\x11\xc5\x23\xf2\x64\x58\xf0\x15\x32\x6f\x4e" + "\x57\xa1\xae\x88\xa4\x02\xd7\x2a\x1e\xcd\x4b\xe1\xdd\x63\xd5\x17" + "\x89\x32\x5b\xb0\x5e\x99\x5a\xa8\x9d\x28\x50\x0e\x17\xee\x96\xdb" + "\x61\x3b\x45\x51\x1d\xcf\x12\x56\x0b\x92\x47\xfc\xab\xae\xf6\x66" + "\x3d\x47\xac\x70\x72\xe7\x92\xe7\x5f\xcd\x10\xb9\xc4\x83\x64\x94" + "\x19\xbd\x25\x80\xe1\xe8\xd2\x22\xa5\xd0\xba\x02\x7a\xa1\x77\x93" + "\x5b\x65\xc3\xee\x17\x74\xbc\x41\x86\x2a\xdc\x08\x4c\x8c\x92\x8c" + "\x91\x2d\x9e\x77\x44\x1f\x68\xd6\xa8\x74\x77\xdb\x0e\x5b\x32\x8b" + "\x56\x8b\x33\xbd\xd9\x63\xc8\x49\x9d\x3a\xc5\xc5\xea\x33\x0b\xd2" + "\xf1\xa3\x1b\xf4\x8b\xbe\xd9\xb3\x57\x8b\x3b\xde\x04\xa7\x7a\x22" + "\xb2\x24\xae\x2e\xc7\x70\xc5\xbe\x4e\x83\x26\x08\xfb\x0b\xbd\xa9" + "\x4f\x99\x08\xe1\x10\x28\x72\xaa\xcd\x02\x03\x01\x00\x01", + .key_len = 270, + .m = + "\x68\xb4\xf9\x26\x34\x31\x25\xdd\x26\x50\x13\x68\xc1\x99\x26\x71" + "\x19\xa2\xde\x81", + .m_size = 20, + .c = + "\x6a\xdb\x39\xe5\x63\xb3\x25\xde\x58\xca\xc3\xf1\x36\x9c\x0b\x36" + "\xb7\xd6\x69\xf9\xba\xa6\x68\x14\x8c\x24\x52\xd3\x25\xa5\xf3\xad" + "\xc9\x47\x44\xde\x06\xd8\x0f\x56\xca\x2d\xfb\x0f\xe9\x99\xe2\x9d" + "\x8a\xe8\x7f\xfb\x9a\x99\x96\xf1\x2c\x4a\xe4\xc0\xae\x4d\x29\x47" + "\x38\x96\x51\x2f\x6d\x8e\xb8\x88\xbd\x1a\x0a\x70\xbc\x23\x38\x67" + "\x62\x22\x01\x23\x71\xe5\xbb\x95\xea\x6b\x8d\x31\x62\xbf\xf0\xc4" + "\xb9\x46\xd6\x67\xfc\x4c\xe6\x1f\xd6\x5d\xf7\xa9\xad\x3a\xf1\xbf" + "\xa2\xf9\x66\xde\xb6\x8e\xec\x8f\x81\x8d\x1e\x3a\x12\x27\x6a\xfc" + "\xae\x92\x9f\xc3\x87\xc3\xba\x8d\x04\xb8\x8f\x0f\x61\x68\x9a\x96" + "\x2c\x80\x2c\x32\x40\xde\x9d\xb9\x9b\xe2\xe4\x45\x2e\x91\x47\x5c" + "\x47\xa4\x9d\x02\x57\x59\xf7\x75\x5d\x5f\x32\x82\x75\x5d\xe5\x78" + "\xc9\x19\x61\x46\x06\x9d\xa5\x1d\xd6\x32\x48\x9a\xdb\x09\x29\x81" + "\x14\x2e\xf0\x27\xe9\x37\x13\x74\xec\xa5\xcd\x67\x6b\x19\xf6\x88" + "\xf0\xc2\x8b\xa8\x7f\x2f\x76\x5a\x3e\x0c\x47\x5d\xe8\x82\x50\x27" + "\x40\xce\x27\x41\x45\xa0\xcf\xaa\x2f\xd3\xad\x3c\xbf\x73\xff\x93" + "\xe3\x78\x49\xd9\xa9\x78\x22\x81\x9a\xe5\xe2\x94\xe9\x40\xab\xf1", + .c_size = 256, + .public_key_vec = true, }, }; /* * PKCS#1 RSA test vectors. Obtained from CAVS testing. */ -static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = { +static const struct sig_testvec pkcs1_rsa_tv_template[] = { { .key = "\x30\x82\x04\xa5\x02\x01\x00\x02\x82\x01\x01\x00\xd7\x1e\x77\x82" @@ -1486,7 +2152,6 @@ static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = { "\xda\x62\x8d\xe1\x2a\x71\x91\x43\x40\x61\x3c\x5a\xbe\x86\xfc\x5b" "\xe6\xf9\xa9\x16\x31\x1f\xaf\x25\x6d\xc2\x4a\x23\x6e\x63\x02\xa2", .c_size = 256, - .siggen_sigver_test = true, } }; diff --git a/crypto/vmac.c b/crypto/vmac.c index bd9d70eac22e00..2ea384645ecf7d 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c @@ -693,4 +693,4 @@ module_exit(vmac_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VMAC hash algorithm"); MODULE_ALIAS_CRYPTO("vmac64"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/xcbc.c b/crypto/xcbc.c index a9e8ee9c1949cb..fc785667b134d9 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -261,4 +261,4 @@ module_exit(crypto_xcbc_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("XCBC keyed hash algorithm"); MODULE_ALIAS_CRYPTO("xcbc"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/xctr.c b/crypto/xctr.c index 5c00147e8ec40b..6ed9c85ededa09 100644 --- a/crypto/xctr.c +++ b/crypto/xctr.c @@ -188,4 +188,4 @@ module_exit(crypto_xctr_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("XCTR block cipher mode of operation"); MODULE_ALIAS_CRYPTO("xctr"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/crypto/xts.c b/crypto/xts.c index 672e1a3f0b0c93..821060ede2cf00 100644 --- a/crypto/xts.c +++ b/crypto/xts.c @@ -472,5 +472,5 @@ module_exit(xts_module_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("XTS block cipher mode"); MODULE_ALIAS_CRYPTO("xts"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); MODULE_SOFTDEP("pre: ecb"); diff --git a/drivers/accel/habanalabs/common/memory.c b/drivers/accel/habanalabs/common/memory.c index 3348ad12c23751..601fdbe701790b 100644 --- a/drivers/accel/habanalabs/common/memory.c +++ b/drivers/accel/habanalabs/common/memory.c @@ -14,7 +14,7 @@ #include #include -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); #define HL_MMU_DEBUG 0 diff --git a/drivers/accel/ivpu/Kconfig b/drivers/accel/ivpu/Kconfig index 682c532452863e..9e055b5ce03d22 100644 --- a/drivers/accel/ivpu/Kconfig +++ b/drivers/accel/ivpu/Kconfig @@ -8,6 +8,7 @@ config DRM_ACCEL_IVPU select FW_LOADER select DRM_GEM_SHMEM_HELPER select GENERIC_ALLOCATOR + select WANT_DEV_COREDUMP help Choose this option if you have a system with an 14th generation Intel CPU (Meteor Lake) or newer. Intel NPU (formerly called Intel VPU) @@ -15,3 +16,12 @@ config DRM_ACCEL_IVPU and Deep Learning applications. If "M" is selected, the module will be called intel_vpu. + +config DRM_ACCEL_IVPU_DEBUG + bool "Intel NPU debug mode" + depends on DRM_ACCEL_IVPU + help + Choose this option to enable additional + debug features for the Intel NPU driver: + - Always print debug messages regardless of dyndbg config, + - Enable unsafe module params. diff --git a/drivers/accel/ivpu/Makefile b/drivers/accel/ivpu/Makefile index ebd682a42eb124..1029e0bab0615f 100644 --- a/drivers/accel/ivpu/Makefile +++ b/drivers/accel/ivpu/Makefile @@ -16,8 +16,14 @@ intel_vpu-y := \ ivpu_mmu_context.o \ ivpu_ms.o \ ivpu_pm.o \ - ivpu_sysfs.o + ivpu_sysfs.o \ + ivpu_trace_points.o intel_vpu-$(CONFIG_DEBUG_FS) += ivpu_debugfs.o +intel_vpu-$(CONFIG_DEV_COREDUMP) += ivpu_coredump.o obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o + +subdir-ccflags-$(CONFIG_DRM_ACCEL_IVPU_DEBUG) += -DDEBUG + +CFLAGS_ivpu_trace_points.o = -I$(src) diff --git a/drivers/accel/ivpu/ivpu_coredump.c b/drivers/accel/ivpu/ivpu_coredump.c new file mode 100644 index 00000000000000..16ad0c30818ccf --- /dev/null +++ b/drivers/accel/ivpu/ivpu_coredump.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-2024 Intel Corporation + */ + +#include +#include + +#include "ivpu_coredump.h" +#include "ivpu_fw.h" +#include "ivpu_gem.h" +#include "vpu_boot_api.h" + +#define CRASH_DUMP_HEADER "Intel NPU crash dump" +#define CRASH_DUMP_HEADERS_SIZE SZ_4K + +void ivpu_dev_coredump(struct ivpu_device *vdev) +{ + struct drm_print_iterator pi = {}; + struct drm_printer p; + size_t coredump_size; + char *coredump; + + coredump_size = CRASH_DUMP_HEADERS_SIZE + FW_VERSION_HEADER_SIZE + + ivpu_bo_size(vdev->fw->mem_log_crit) + ivpu_bo_size(vdev->fw->mem_log_verb); + coredump = vmalloc(coredump_size); + if (!coredump) + return; + + pi.data = coredump; + pi.remain = coredump_size; + p = drm_coredump_printer(&pi); + + drm_printf(&p, "%s\n", CRASH_DUMP_HEADER); + drm_printf(&p, "FW version: %s\n", vdev->fw->version); + ivpu_fw_log_print(vdev, false, &p); + + dev_coredumpv(vdev->drm.dev, coredump, pi.offset, GFP_KERNEL); +} diff --git a/drivers/accel/ivpu/ivpu_coredump.h b/drivers/accel/ivpu/ivpu_coredump.h new file mode 100644 index 00000000000000..8efb09d0244115 --- /dev/null +++ b/drivers/accel/ivpu/ivpu_coredump.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020-2024 Intel Corporation + */ + +#ifndef __IVPU_COREDUMP_H__ +#define __IVPU_COREDUMP_H__ + +#include + +#include "ivpu_drv.h" +#include "ivpu_fw_log.h" + +#ifdef CONFIG_DEV_COREDUMP +void ivpu_dev_coredump(struct ivpu_device *vdev); +#else +static inline void ivpu_dev_coredump(struct ivpu_device *vdev) +{ + struct drm_printer p = drm_info_printer(vdev->drm.dev); + + ivpu_fw_log_print(vdev, false, &p); +} +#endif + +#endif /* __IVPU_COREDUMP_H__ */ diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 8d50981594d153..8180b95ed69dc7 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -45,6 +45,14 @@ static int fw_name_show(struct seq_file *s, void *v) return 0; } +static int fw_version_show(struct seq_file *s, void *v) +{ + struct ivpu_device *vdev = seq_to_ivpu(s); + + seq_printf(s, "%s\n", vdev->fw->version); + return 0; +} + static int fw_trace_capability_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = seq_to_ivpu(s); @@ -119,6 +127,7 @@ static int firewall_irq_counter_show(struct seq_file *s, void *v) static const struct drm_debugfs_info vdev_debugfs_list[] = { {"bo_list", bo_list_show, 0}, {"fw_name", fw_name_show, 0}, + {"fw_version", fw_version_show, 0}, {"fw_trace_capability", fw_trace_capability_show, 0}, {"fw_trace_config", fw_trace_config_show, 0}, {"last_bootmode", last_bootmode_show, 0}, @@ -127,32 +136,23 @@ static const struct drm_debugfs_info vdev_debugfs_list[] = { {"firewall_irq_counter", firewall_irq_counter_show, 0}, }; -static ssize_t -dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) +static int dvfs_mode_get(void *data, u64 *dvfs_mode) { - struct ivpu_device *vdev = file->private_data; - struct ivpu_fw_info *fw = vdev->fw; - u32 dvfs_mode; - int ret; - - ret = kstrtou32_from_user(user_buf, size, 0, &dvfs_mode); - if (ret < 0) - return ret; + struct ivpu_device *vdev = (struct ivpu_device *)data; - fw->dvfs_mode = dvfs_mode; + *dvfs_mode = vdev->fw->dvfs_mode; + return 0; +} - ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); - if (ret) - return ret; +static int dvfs_mode_set(void *data, u64 dvfs_mode) +{ + struct ivpu_device *vdev = (struct ivpu_device *)data; - return size; + vdev->fw->dvfs_mode = (u32)dvfs_mode; + return pci_try_reset_function(to_pci_dev(vdev->drm.dev)); } -static const struct file_operations dvfs_mode_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .write = dvfs_mode_fops_write, -}; +DEFINE_DEBUGFS_ATTRIBUTE(dvfs_mode_fops, dvfs_mode_get, dvfs_mode_set, "%llu\n"); static ssize_t fw_dyndbg_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) @@ -201,7 +201,7 @@ fw_log_fops_write(struct file *file, const char __user *user_buf, size_t size, l if (!size) return -EINVAL; - ivpu_fw_log_clear(vdev); + ivpu_fw_log_mark_read(vdev); return size; } @@ -346,49 +346,23 @@ static const struct file_operations ivpu_force_recovery_fops = { .write = ivpu_force_recovery_fn, }; -static ssize_t -ivpu_reset_engine_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) +static int ivpu_reset_engine_fn(void *data, u64 val) { - struct ivpu_device *vdev = file->private_data; - - if (!size) - return -EINVAL; + struct ivpu_device *vdev = (struct ivpu_device *)data; - if (ivpu_jsm_reset_engine(vdev, DRM_IVPU_ENGINE_COMPUTE)) - return -ENODEV; - if (ivpu_jsm_reset_engine(vdev, DRM_IVPU_ENGINE_COPY)) - return -ENODEV; - - return size; + return ivpu_jsm_reset_engine(vdev, (u32)val); } -static const struct file_operations ivpu_reset_engine_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .write = ivpu_reset_engine_fn, -}; +DEFINE_DEBUGFS_ATTRIBUTE(ivpu_reset_engine_fops, NULL, ivpu_reset_engine_fn, "0x%02llx\n"); -static ssize_t -ivpu_resume_engine_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) +static int ivpu_resume_engine_fn(void *data, u64 val) { - struct ivpu_device *vdev = file->private_data; - - if (!size) - return -EINVAL; + struct ivpu_device *vdev = (struct ivpu_device *)data; - if (ivpu_jsm_hws_resume_engine(vdev, DRM_IVPU_ENGINE_COMPUTE)) - return -ENODEV; - if (ivpu_jsm_hws_resume_engine(vdev, DRM_IVPU_ENGINE_COPY)) - return -ENODEV; - - return size; + return ivpu_jsm_hws_resume_engine(vdev, (u32)val); } -static const struct file_operations ivpu_resume_engine_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .write = ivpu_resume_engine_fn, -}; +DEFINE_DEBUGFS_ATTRIBUTE(ivpu_resume_engine_fops, NULL, ivpu_resume_engine_fn, "0x%02llx\n"); static int dct_active_get(void *data, u64 *active_percent) { @@ -432,7 +406,7 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, &ivpu_force_recovery_fops); - debugfs_create_file("dvfs_mode", 0200, debugfs_root, vdev, + debugfs_create_file("dvfs_mode", 0644, debugfs_root, vdev, &dvfs_mode_fops); debugfs_create_file("fw_dyndbg", 0200, debugfs_root, vdev, diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index c91400ecf92651..ca2bf47ce2484a 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -14,7 +15,7 @@ #include #include -#include "vpu_boot_api.h" +#include "ivpu_coredump.h" #include "ivpu_debugfs.h" #include "ivpu_drv.h" #include "ivpu_fw.h" @@ -29,10 +30,10 @@ #include "ivpu_ms.h" #include "ivpu_pm.h" #include "ivpu_sysfs.h" +#include "vpu_boot_api.h" #ifndef DRIVER_VERSION_STR -#define DRIVER_VERSION_STR __stringify(DRM_IVPU_DRIVER_MAJOR) "." \ - __stringify(DRM_IVPU_DRIVER_MINOR) "." +#define DRIVER_VERSION_STR "1.0.0 " UTS_RELEASE #endif static struct lock_class_key submitted_jobs_xa_lock_class_key; @@ -42,8 +43,10 @@ module_param_named(dbg_mask, ivpu_dbg_mask, int, 0644); MODULE_PARM_DESC(dbg_mask, "Driver debug mask. See IVPU_DBG_* macros."); int ivpu_test_mode; +#if IS_ENABLED(CONFIG_DRM_ACCEL_IVPU_DEBUG) module_param_named_unsafe(test_mode, ivpu_test_mode, int, 0644); MODULE_PARM_DESC(test_mode, "Test mode mask. See IVPU_TEST_MODE_* macros."); +#endif u8 ivpu_pll_min_ratio; module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); @@ -53,9 +56,9 @@ u8 ivpu_pll_max_ratio = U8_MAX; module_param_named(pll_max_ratio, ivpu_pll_max_ratio, byte, 0644); MODULE_PARM_DESC(pll_max_ratio, "Maximum PLL ratio used to set NPU frequency"); -int ivpu_sched_mode; +int ivpu_sched_mode = IVPU_SCHED_MODE_AUTO; module_param_named(sched_mode, ivpu_sched_mode, int, 0444); -MODULE_PARM_DESC(sched_mode, "Scheduler mode: 0 - Default scheduler, 1 - Force HW scheduler"); +MODULE_PARM_DESC(sched_mode, "Scheduler mode: -1 - Use default scheduler, 0 - Use OS scheduler, 1 - Use HW scheduler"); bool ivpu_disable_mmu_cont_pages; module_param_named(disable_mmu_cont_pages, ivpu_disable_mmu_cont_pages, bool, 0444); @@ -85,7 +88,7 @@ static void file_priv_unbind(struct ivpu_device *vdev, struct ivpu_file_priv *fi ivpu_cmdq_release_all_locked(file_priv); ivpu_bo_unbind_all_bos_from_context(vdev, &file_priv->ctx); - ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); + ivpu_mmu_context_fini(vdev, &file_priv->ctx); file_priv->bound = false; drm_WARN_ON(&vdev->drm, !xa_erase_irq(&vdev->context_xa, file_priv->ctx.id)); } @@ -103,6 +106,8 @@ static void file_priv_release(struct kref *ref) pm_runtime_get_sync(vdev->drm.dev); mutex_lock(&vdev->context_list_lock); file_priv_unbind(vdev, file_priv); + drm_WARN_ON(&vdev->drm, !xa_empty(&file_priv->cmdq_xa)); + xa_destroy(&file_priv->cmdq_xa); mutex_unlock(&vdev->context_list_lock); pm_runtime_put_autosuspend(vdev->drm.dev); @@ -116,8 +121,6 @@ void ivpu_file_priv_put(struct ivpu_file_priv **link) struct ivpu_file_priv *file_priv = *link; struct ivpu_device *vdev = file_priv->vdev; - drm_WARN_ON(&vdev->drm, !file_priv); - ivpu_dbg(vdev, KREF, "file_priv put: ctx %u refcount %u\n", file_priv->ctx.id, kref_read(&file_priv->ref)); @@ -255,9 +258,14 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file) goto err_unlock; } - ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id); - if (ret) - goto err_xa_erase; + ivpu_mmu_context_init(vdev, &file_priv->ctx, ctx_id); + + file_priv->job_limit.min = FIELD_PREP(IVPU_JOB_ID_CONTEXT_MASK, (file_priv->ctx.id - 1)); + file_priv->job_limit.max = file_priv->job_limit.min | IVPU_JOB_ID_JOB_MASK; + + xa_init_flags(&file_priv->cmdq_xa, XA_FLAGS_ALLOC1); + file_priv->cmdq_limit.min = IVPU_CMDQ_MIN_ID; + file_priv->cmdq_limit.max = IVPU_CMDQ_MAX_ID; mutex_unlock(&vdev->context_list_lock); drm_dev_exit(idx); @@ -269,8 +277,6 @@ static int ivpu_open(struct drm_device *dev, struct drm_file *file) return 0; -err_xa_erase: - xa_erase_irq(&vdev->context_xa, ctx_id); err_unlock: mutex_unlock(&vdev->context_list_lock); mutex_destroy(&file_priv->ms_lock); @@ -346,7 +352,7 @@ static int ivpu_hw_sched_init(struct ivpu_device *vdev) { int ret = 0; - if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW) { + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { ret = ivpu_jsm_hws_setup_priority_bands(vdev); if (ret) { ivpu_err(vdev, "Failed to enable hw scheduler: %d", ret); @@ -380,10 +386,7 @@ int ivpu_boot(struct ivpu_device *vdev) ret = ivpu_wait_for_ready(vdev); if (ret) { ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret); - ivpu_hw_diagnose_failure(vdev); - ivpu_mmu_evtq_dump(vdev); - ivpu_fw_log_dump(vdev); - return ret; + goto err_diagnose_failure; } ivpu_hw_irq_clear(vdev); @@ -394,12 +397,20 @@ int ivpu_boot(struct ivpu_device *vdev) if (ivpu_fw_is_cold_boot(vdev)) { ret = ivpu_pm_dct_init(vdev); if (ret) - return ret; + goto err_diagnose_failure; - return ivpu_hw_sched_init(vdev); + ret = ivpu_hw_sched_init(vdev); + if (ret) + goto err_diagnose_failure; } return 0; + +err_diagnose_failure: + ivpu_hw_diagnose_failure(vdev); + ivpu_mmu_evtq_dump(vdev); + ivpu_dev_coredump(vdev); + return ret; } void ivpu_prepare_for_reset(struct ivpu_device *vdev) @@ -446,9 +457,16 @@ static const struct drm_driver driver = { .name = DRIVER_NAME, .desc = DRIVER_DESC, + +#ifdef DRIVER_DATE .date = DRIVER_DATE, - .major = DRM_IVPU_DRIVER_MAJOR, - .minor = DRM_IVPU_DRIVER_MINOR, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +#else + .date = UTS_RELEASE, + .major = 1, +#endif }; static void ivpu_context_abort_invalid(struct ivpu_device *vdev) @@ -606,6 +624,9 @@ static int ivpu_dev_init(struct ivpu_device *vdev) lockdep_set_class(&vdev->submitted_jobs_xa.xa_lock, &submitted_jobs_xa_lock_class_key); INIT_LIST_HEAD(&vdev->bo_list); + vdev->db_limit.min = IVPU_MIN_DB; + vdev->db_limit.max = IVPU_MAX_DB; + ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock); if (ret) goto err_xa_destroy; @@ -632,9 +653,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev) if (ret) goto err_shutdown; - ret = ivpu_mmu_global_context_init(vdev); - if (ret) - goto err_shutdown; + ivpu_mmu_global_context_init(vdev); ret = ivpu_mmu_init(vdev); if (ret) @@ -722,6 +741,7 @@ static struct pci_device_id ivpu_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PTL_P) }, { } }; MODULE_DEVICE_TABLE(pci, ivpu_pci_ids); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 63f13b697eed71..3fdff3f6cffd85 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -21,11 +21,11 @@ #define DRIVER_NAME "intel_vpu" #define DRIVER_DESC "Driver for Intel NPU (Neural Processing Unit)" -#define DRIVER_DATE "20230117" -#define PCI_DEVICE_ID_MTL 0x7d1d -#define PCI_DEVICE_ID_ARL 0xad1d -#define PCI_DEVICE_ID_LNL 0x643e +#define PCI_DEVICE_ID_MTL 0x7d1d +#define PCI_DEVICE_ID_ARL 0xad1d +#define PCI_DEVICE_ID_LNL 0x643e +#define PCI_DEVICE_ID_PTL_P 0xb03e #define IVPU_HW_IP_37XX 37 #define IVPU_HW_IP_40XX 40 @@ -46,17 +46,22 @@ #define IVPU_MIN_DB 1 #define IVPU_MAX_DB 255 -#define IVPU_NUM_ENGINES 2 +#define IVPU_JOB_ID_JOB_MASK GENMASK(7, 0) +#define IVPU_JOB_ID_CONTEXT_MASK GENMASK(31, 8) + #define IVPU_NUM_PRIORITIES 4 -#define IVPU_NUM_CMDQS_PER_CTX (IVPU_NUM_ENGINES * IVPU_NUM_PRIORITIES) +#define IVPU_NUM_CMDQS_PER_CTX (IVPU_NUM_PRIORITIES) -#define IVPU_CMDQ_INDEX(engine, priority) ((engine) * IVPU_NUM_PRIORITIES + (priority)) +#define IVPU_CMDQ_MIN_ID 1 +#define IVPU_CMDQ_MAX_ID 255 #define IVPU_PLATFORM_SILICON 0 #define IVPU_PLATFORM_SIMICS 2 #define IVPU_PLATFORM_FPGA 3 #define IVPU_PLATFORM_INVALID 8 +#define IVPU_SCHED_MODE_AUTO -1 + #define IVPU_DBG_REG BIT(0) #define IVPU_DBG_IRQ BIT(1) #define IVPU_DBG_MMU BIT(2) @@ -134,6 +139,8 @@ struct ivpu_device { struct xa_limit context_xa_limit; struct xarray db_xa; + struct xa_limit db_limit; + u32 db_next; struct mutex bo_list_lock; /* Protects bo_list */ struct list_head bo_list; @@ -152,6 +159,7 @@ struct ivpu_device { int tdr; int autosuspend; int d0i3_entry_msg; + int state_dump_msg; } timeout; }; @@ -163,11 +171,15 @@ struct ivpu_file_priv { struct kref ref; struct ivpu_device *vdev; struct mutex lock; /* Protects cmdq */ - struct ivpu_cmdq *cmdq[IVPU_NUM_CMDQS_PER_CTX]; + struct xarray cmdq_xa; struct ivpu_mmu_context ctx; struct mutex ms_lock; /* Protects ms_instance_list, ms_info_bo */ struct list_head ms_instance_list; struct ivpu_bo *ms_info_bo; + struct xa_limit job_limit; + u32 job_id_next; + struct xa_limit cmdq_limit; + u32 cmdq_id_next; bool has_mmu_faults; bool bound; bool aborted; @@ -185,9 +197,9 @@ extern bool ivpu_force_snoop; #define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) #define IVPU_TEST_MODE_D0I3_MSG_DISABLE BIT(4) #define IVPU_TEST_MODE_D0I3_MSG_ENABLE BIT(5) -#define IVPU_TEST_MODE_PREEMPTION_DISABLE BIT(6) -#define IVPU_TEST_MODE_HWS_EXTRA_EVENTS BIT(7) +#define IVPU_TEST_MODE_MIP_DISABLE BIT(6) #define IVPU_TEST_MODE_DISABLE_TIMEOUTS BIT(8) +#define IVPU_TEST_MODE_TURBO BIT(9) extern int ivpu_test_mode; struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv); @@ -215,6 +227,8 @@ static inline int ivpu_hw_ip_gen(struct ivpu_device *vdev) return IVPU_HW_IP_37XX; case PCI_DEVICE_ID_LNL: return IVPU_HW_IP_40XX; + case PCI_DEVICE_ID_PTL_P: + return IVPU_HW_IP_50XX; default: dump_stack(); ivpu_err(vdev, "Unknown NPU IP generation\n"); @@ -229,6 +243,7 @@ static inline int ivpu_hw_btrs_gen(struct ivpu_device *vdev) case PCI_DEVICE_ID_ARL: return IVPU_HW_BTRS_MTL; case PCI_DEVICE_ID_LNL: + case PCI_DEVICE_ID_PTL_P: return IVPU_HW_BTRS_LNL; default: dump_stack(); diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index ede6165e09d90d..6037ec0b309689 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -25,7 +25,6 @@ #define FW_SHAVE_NN_MAX_SIZE SZ_2M #define FW_RUNTIME_MIN_ADDR (FW_GLOBAL_MEM_START) #define FW_RUNTIME_MAX_ADDR (FW_GLOBAL_MEM_END - FW_SHARED_MEM_SIZE) -#define FW_VERSION_HEADER_SIZE SZ_4K #define FW_FILE_IMAGE_OFFSET (VPU_FW_HEADER_SIZE + FW_VERSION_HEADER_SIZE) #define WATCHDOG_MSS_REDIRECT 32 @@ -47,8 +46,10 @@ #define IVPU_FOCUS_PRESENT_TIMER_MS 1000 static char *ivpu_firmware; +#if IS_ENABLED(CONFIG_DRM_ACCEL_IVPU_DEBUG) module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644); MODULE_PARM_DESC(firmware, "NPU firmware binary in /lib/firmware/.."); +#endif static struct { int gen; @@ -58,11 +59,14 @@ static struct { { IVPU_HW_IP_37XX, "intel/vpu/vpu_37xx_v0.0.bin" }, { IVPU_HW_IP_40XX, "vpu_40xx.bin" }, { IVPU_HW_IP_40XX, "intel/vpu/vpu_40xx_v0.0.bin" }, + { IVPU_HW_IP_50XX, "vpu_50xx.bin" }, + { IVPU_HW_IP_50XX, "intel/vpu/vpu_50xx_v0.0.bin" }, }; /* Production fw_names from the table above */ MODULE_FIRMWARE("intel/vpu/vpu_37xx_v0.0.bin"); MODULE_FIRMWARE("intel/vpu/vpu_40xx_v0.0.bin"); +MODULE_FIRMWARE("intel/vpu/vpu_50xx_v0.0.bin"); static int ivpu_fw_request(struct ivpu_device *vdev) { @@ -135,6 +139,15 @@ static bool is_within_range(u64 addr, size_t size, u64 range_start, size_t range return true; } +static u32 +ivpu_fw_sched_mode_select(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr) +{ + if (ivpu_sched_mode != IVPU_SCHED_MODE_AUTO) + return ivpu_sched_mode; + + return VPU_SCHEDULING_MODE_OS; +} + static int ivpu_fw_parse(struct ivpu_device *vdev) { struct ivpu_fw_info *fw = vdev->fw; @@ -191,8 +204,10 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) ivpu_dbg(vdev, FW_BOOT, "Header version: 0x%x, format 0x%x\n", fw_hdr->header_version, fw_hdr->image_format); - ivpu_info(vdev, "Firmware: %s, version: %s", fw->name, - (const char *)fw_hdr + VPU_FW_HEADER_SIZE); + if (!scnprintf(fw->version, sizeof(fw->version), "%s", fw->file->data + VPU_FW_HEADER_SIZE)) + ivpu_warn(vdev, "Missing firmware version\n"); + + ivpu_info(vdev, "Firmware: %s, version: %s\n", fw->name, fw->version); if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3)) return -EINVAL; @@ -208,14 +223,16 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->cold_boot_entry_point = fw_hdr->entry_point; fw->entry_point = fw->cold_boot_entry_point; - fw->trace_level = min_t(u32, ivpu_log_level, IVPU_FW_LOG_FATAL); + fw->trace_level = min_t(u32, ivpu_fw_log_level, IVPU_FW_LOG_FATAL); fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING; fw->trace_hw_component_mask = -1; fw->dvfs_mode = 0; + fw->sched_mode = ivpu_fw_sched_mode_select(vdev, fw_hdr); fw->primary_preempt_buf_size = fw_hdr->preemption_buffer_1_size; fw->secondary_preempt_buf_size = fw_hdr->preemption_buffer_2_size; + ivpu_info(vdev, "Scheduler mode: %s\n", fw->sched_mode ? "HW" : "OS"); if (fw_hdr->ro_section_start_address && !is_within_range(fw_hdr->ro_section_start_address, fw_hdr->ro_section_size, @@ -311,7 +328,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) goto err_free_fw_mem; } - if (ivpu_log_level <= IVPU_FW_LOG_INFO) + if (ivpu_fw_log_level <= IVPU_FW_LOG_INFO) log_verb_size = IVPU_FW_VERBOSE_BUFFER_LARGE_SIZE; else log_verb_size = IVPU_FW_VERBOSE_BUFFER_SMALL_SIZE; @@ -567,8 +584,10 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->ipc_payload_area_start = ipc_mem_rx->vpu_addr + ivpu_bo_size(ipc_mem_rx) / 2; boot_params->ipc_payload_area_size = ivpu_bo_size(ipc_mem_rx) / 2; - boot_params->global_aliased_pio_base = vdev->hw->ranges.user.start; - boot_params->global_aliased_pio_size = ivpu_hw_range_size(&vdev->hw->ranges.user); + if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { + boot_params->global_aliased_pio_base = vdev->hw->ranges.user.start; + boot_params->global_aliased_pio_size = ivpu_hw_range_size(&vdev->hw->ranges.user); + } /* Allow configuration for L2C_PAGE_TABLE with boot param value */ boot_params->autoconfig = 1; @@ -604,8 +623,8 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_base = ivpu_hw_telemetry_offset_get(vdev); boot_params->punit_telemetry_sram_size = ivpu_hw_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_telemetry_enable_get(vdev); - boot_params->vpu_scheduling_mode = vdev->hw->sched_mode; - if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW) + boot_params->vpu_scheduling_mode = vdev->fw->sched_mode; + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) boot_params->vpu_focus_present_timer_ms = IVPU_FOCUS_PRESENT_TIMER_MS; boot_params->dvfs_mode = vdev->fw->dvfs_mode; if (!IVPU_WA(disable_d0i3_msg)) diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h index 40d9d17be3f528..1d0b2bd9d65cf0 100644 --- a/drivers/accel/ivpu/ivpu_fw.h +++ b/drivers/accel/ivpu/ivpu_fw.h @@ -1,11 +1,16 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (C) 2020-2023 Intel Corporation + * Copyright (C) 2020-2024 Intel Corporation */ #ifndef __IVPU_FW_H__ #define __IVPU_FW_H__ +#include "vpu_jsm_api.h" + +#define FW_VERSION_HEADER_SIZE SZ_4K +#define FW_VERSION_STR_SIZE SZ_256 + struct ivpu_device; struct ivpu_bo; struct vpu_boot_params; @@ -13,6 +18,7 @@ struct vpu_boot_params; struct ivpu_fw_info { const struct firmware *file; const char *name; + char version[FW_VERSION_STR_SIZE]; struct ivpu_bo *mem; struct ivpu_bo *mem_shave_nn; struct ivpu_bo *mem_log_crit; @@ -32,6 +38,7 @@ struct ivpu_fw_info { u32 secondary_preempt_buf_size; u64 read_only_addr; u32 read_only_size; + u32 sched_mode; }; int ivpu_fw_init(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_fw_log.c b/drivers/accel/ivpu/ivpu_fw_log.c index ef0adb5e0fbeb3..337c906b021072 100644 --- a/drivers/accel/ivpu/ivpu_fw_log.c +++ b/drivers/accel/ivpu/ivpu_fw_log.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2020-2023 Intel Corporation + * Copyright (C) 2020-2024 Intel Corporation */ #include @@ -15,19 +15,19 @@ #include "ivpu_fw_log.h" #include "ivpu_gem.h" -#define IVPU_FW_LOG_LINE_LENGTH 256 +#define IVPU_FW_LOG_LINE_LENGTH 256 -unsigned int ivpu_log_level = IVPU_FW_LOG_ERROR; -module_param(ivpu_log_level, uint, 0444); -MODULE_PARM_DESC(ivpu_log_level, - "NPU firmware default trace level: debug=" __stringify(IVPU_FW_LOG_DEBUG) +unsigned int ivpu_fw_log_level = IVPU_FW_LOG_ERROR; +module_param_named(fw_log_level, ivpu_fw_log_level, uint, 0444); +MODULE_PARM_DESC(fw_log_level, + "NPU firmware default log level: debug=" __stringify(IVPU_FW_LOG_DEBUG) " info=" __stringify(IVPU_FW_LOG_INFO) " warn=" __stringify(IVPU_FW_LOG_WARN) " error=" __stringify(IVPU_FW_LOG_ERROR) " fatal=" __stringify(IVPU_FW_LOG_FATAL)); -static int fw_log_ptr(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset, - struct vpu_tracing_buffer_header **log_header) +static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset, + struct vpu_tracing_buffer_header **out_log) { struct vpu_tracing_buffer_header *log; @@ -48,7 +48,7 @@ static int fw_log_ptr(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset, return -EINVAL; } - *log_header = log; + *out_log = log; *offset += log->size; ivpu_dbg(vdev, FW_BOOT, @@ -59,7 +59,7 @@ static int fw_log_ptr(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset, return 0; } -static void buffer_print(char *buffer, u32 size, struct drm_printer *p) +static void fw_log_print_lines(char *buffer, u32 size, struct drm_printer *p) { char line[IVPU_FW_LOG_LINE_LENGTH]; u32 index = 0; @@ -87,56 +87,89 @@ static void buffer_print(char *buffer, u32 size, struct drm_printer *p) } line[index] = 0; if (index != 0) - drm_printf(p, "%s\n", line); + drm_printf(p, "%s", line); } -static void fw_log_print_buffer(struct ivpu_device *vdev, struct vpu_tracing_buffer_header *log, - const char *prefix, bool only_new_msgs, struct drm_printer *p) +static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const char *prefix, + bool only_new_msgs, struct drm_printer *p) { - char *log_buffer = (void *)log + log->header_size; - u32 log_size = log->size - log->header_size; - u32 log_start = log->read_index; - u32 log_end = log->write_index; - - if (!(log->write_index || log->wrap_count) || - (log->write_index == log->read_index && only_new_msgs)) { - drm_printf(p, "==== %s \"%s\" log empty ====\n", prefix, log->name); - return; + char *log_data = (void *)log + log->header_size; + u32 data_size = log->size - log->header_size; + u32 log_start = only_new_msgs ? READ_ONCE(log->read_index) : 0; + u32 log_end = READ_ONCE(log->write_index); + + if (log->wrap_count == log->read_wrap_count) { + if (log_end <= log_start) { + drm_printf(p, "==== %s \"%s\" log empty ====\n", prefix, log->name); + return; + } + } else if (log->wrap_count == log->read_wrap_count + 1) { + if (log_end > log_start) + log_start = log_end; + } else { + log_start = log_end; } drm_printf(p, "==== %s \"%s\" log start ====\n", prefix, log->name); - if (log->write_index > log->read_index) { - buffer_print(log_buffer + log_start, log_end - log_start, p); + if (log_end > log_start) { + fw_log_print_lines(log_data + log_start, log_end - log_start, p); } else { - buffer_print(log_buffer + log_end, log_size - log_end, p); - buffer_print(log_buffer, log_end, p); + fw_log_print_lines(log_data + log_start, data_size - log_start, p); + fw_log_print_lines(log_data, log_end, p); } - drm_printf(p, "\x1b[0m"); + drm_printf(p, "\n\x1b[0m"); /* add new line and clear formatting */ drm_printf(p, "==== %s \"%s\" log end ====\n", prefix, log->name); } -void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_printer *p) +static void +fw_log_print_all_in_bo(struct ivpu_device *vdev, const char *name, + struct ivpu_bo *bo, bool only_new_msgs, struct drm_printer *p) { - struct vpu_tracing_buffer_header *log_header; + struct vpu_tracing_buffer_header *log; u32 next = 0; - while (fw_log_ptr(vdev, vdev->fw->mem_log_crit, &next, &log_header) == 0) - fw_log_print_buffer(vdev, log_header, "NPU critical", only_new_msgs, p); + while (fw_log_from_bo(vdev, bo, &next, &log) == 0) + fw_log_print_buffer(log, name, only_new_msgs, p); +} + +void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_printer *p) +{ + fw_log_print_all_in_bo(vdev, "NPU critical", vdev->fw->mem_log_crit, only_new_msgs, p); + fw_log_print_all_in_bo(vdev, "NPU verbose", vdev->fw->mem_log_verb, only_new_msgs, p); +} + +void ivpu_fw_log_mark_read(struct ivpu_device *vdev) +{ + struct vpu_tracing_buffer_header *log; + u32 next; + + next = 0; + while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) { + log->read_index = READ_ONCE(log->write_index); + log->read_wrap_count = READ_ONCE(log->wrap_count); + } next = 0; - while (fw_log_ptr(vdev, vdev->fw->mem_log_verb, &next, &log_header) == 0) - fw_log_print_buffer(vdev, log_header, "NPU verbose", only_new_msgs, p); + while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) { + log->read_index = READ_ONCE(log->write_index); + log->read_wrap_count = READ_ONCE(log->wrap_count); + } } -void ivpu_fw_log_clear(struct ivpu_device *vdev) +void ivpu_fw_log_reset(struct ivpu_device *vdev) { - struct vpu_tracing_buffer_header *log_header; - u32 next = 0; + struct vpu_tracing_buffer_header *log; + u32 next; - while (fw_log_ptr(vdev, vdev->fw->mem_log_crit, &next, &log_header) == 0) - log_header->read_index = log_header->write_index; + next = 0; + while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) { + log->read_index = 0; + log->read_wrap_count = 0; + } next = 0; - while (fw_log_ptr(vdev, vdev->fw->mem_log_verb, &next, &log_header) == 0) - log_header->read_index = log_header->write_index; + while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) { + log->read_index = 0; + log->read_wrap_count = 0; + } } diff --git a/drivers/accel/ivpu/ivpu_fw_log.h b/drivers/accel/ivpu/ivpu_fw_log.h index 0b2573f6f31519..8bb528a73cb7e5 100644 --- a/drivers/accel/ivpu/ivpu_fw_log.h +++ b/drivers/accel/ivpu/ivpu_fw_log.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (C) 2020-2023 Intel Corporation + * Copyright (C) 2020-2024 Intel Corporation */ #ifndef __IVPU_FW_LOG_H__ @@ -8,8 +8,6 @@ #include -#include - #include "ivpu_drv.h" #define IVPU_FW_LOG_DEFAULT 0 @@ -19,20 +17,15 @@ #define IVPU_FW_LOG_ERROR 4 #define IVPU_FW_LOG_FATAL 5 -extern unsigned int ivpu_log_level; - #define IVPU_FW_VERBOSE_BUFFER_SMALL_SIZE SZ_1M #define IVPU_FW_VERBOSE_BUFFER_LARGE_SIZE SZ_8M #define IVPU_FW_CRITICAL_BUFFER_SIZE SZ_512K -void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_printer *p); -void ivpu_fw_log_clear(struct ivpu_device *vdev); +extern unsigned int ivpu_fw_log_level; -static inline void ivpu_fw_log_dump(struct ivpu_device *vdev) -{ - struct drm_printer p = drm_info_printer(vdev->drm.dev); +void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_printer *p); +void ivpu_fw_log_mark_read(struct ivpu_device *vdev); +void ivpu_fw_log_reset(struct ivpu_device *vdev); - ivpu_fw_log_print(vdev, false, &p); -} #endif /* __IVPU_FW_LOG_H__ */ diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 1b409dbd332d80..16178054e62962 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -384,6 +384,9 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file timeout = drm_timeout_abs_to_jiffies(args->timeout_ns); + /* Add 1 jiffy to ensure the wait function never times out before intended timeout_ns */ + timeout += 1; + obj = drm_gem_object_lookup(file, args->handle); if (!obj) return -EINVAL; @@ -406,7 +409,7 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) mutex_lock(&bo->lock); drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u", - bo, bo->ctx->id, bo->vpu_addr, bo->base.base.size, + bo, bo->ctx ? bo->ctx->id : 0, bo->vpu_addr, bo->base.base.size, bo->flags, kref_read(&bo->base.base.refcount)); if (bo->base.pages) diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c index e69c0613513f11..4e1054f3466e80 100644 --- a/drivers/accel/ivpu/ivpu_hw.c +++ b/drivers/accel/ivpu/ivpu_hw.c @@ -89,12 +89,14 @@ static void timeouts_init(struct ivpu_device *vdev) vdev->timeout.tdr = 2000000; vdev->timeout.autosuspend = -1; vdev->timeout.d0i3_entry_msg = 500; + vdev->timeout.state_dump_msg = 10; } else if (ivpu_is_simics(vdev)) { vdev->timeout.boot = 50; vdev->timeout.jsm = 500; vdev->timeout.tdr = 10000; - vdev->timeout.autosuspend = -1; + vdev->timeout.autosuspend = 100; vdev->timeout.d0i3_entry_msg = 100; + vdev->timeout.state_dump_msg = 10; } else { vdev->timeout.boot = 1000; vdev->timeout.jsm = 500; @@ -104,6 +106,7 @@ static void timeouts_init(struct ivpu_device *vdev) else vdev->timeout.autosuspend = 100; vdev->timeout.d0i3_entry_msg = 5; + vdev->timeout.state_dump_msg = 10; } } @@ -111,14 +114,14 @@ static void memory_ranges_init(struct ivpu_device *vdev) { if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { ivpu_hw_range_init(&vdev->hw->ranges.global, 0x80000000, SZ_512M); - ivpu_hw_range_init(&vdev->hw->ranges.user, 0xc0000000, 255 * SZ_1M); + ivpu_hw_range_init(&vdev->hw->ranges.user, 0x88000000, 511 * SZ_1M); ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x180000000, SZ_2G); - ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); + ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_128G); } else { ivpu_hw_range_init(&vdev->hw->ranges.global, 0x80000000, SZ_512M); - ivpu_hw_range_init(&vdev->hw->ranges.user, 0x80000000, SZ_256M); - ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x80000000 + SZ_256M, SZ_2G - SZ_256M); - ivpu_hw_range_init(&vdev->hw->ranges.dma, 0x200000000, SZ_8G); + ivpu_hw_range_init(&vdev->hw->ranges.shave, 0x80000000, SZ_2G); + ivpu_hw_range_init(&vdev->hw->ranges.user, 0x100000000, SZ_256G); + vdev->hw->ranges.dma = vdev->hw->ranges.user; } } diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index a96a05b2acda9a..fc4dbfc980c819 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -46,7 +46,6 @@ struct ivpu_hw_info { u32 profiling_freq; } pll; u32 tile_fuse; - u32 sched_mode; u32 sku; u16 config; int dma_bits; diff --git a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h index d0b795b344c7f7..fc0ee8d637f968 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h @@ -115,6 +115,8 @@ #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY 0x00030068u #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST_DLY_MASK GENMASK(7, 0) +#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST1_DLY_MASK GENMASK(15, 8) +#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY_POST2_DLY_MASK GENMASK(23, 16) #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu #define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0) diff --git a/drivers/accel/ivpu/ivpu_hw_btrs.c b/drivers/accel/ivpu/ivpu_hw_btrs.c index 745e5248803daf..3212c99f36823a 100644 --- a/drivers/accel/ivpu/ivpu_hw_btrs.c +++ b/drivers/accel/ivpu/ivpu_hw_btrs.c @@ -141,16 +141,10 @@ static int read_tile_config_fuse(struct ivpu_device *vdev, u32 *tile_fuse_config } config = REG_GET_FLD(VPU_HW_BTRS_LNL_TILE_FUSE, CONFIG, fuse); - if (!tile_disable_check(config)) { - ivpu_err(vdev, "Fuse: Invalid tile disable config (0x%x)\n", config); - return -EIO; - } + if (!tile_disable_check(config)) + ivpu_warn(vdev, "More than 1 tile disabled, tile fuse config mask: 0x%x\n", config); - if (config) - ivpu_dbg(vdev, MISC, "Fuse: %d tiles enabled. Tile number %d disabled\n", - BTRS_LNL_TILE_MAX_NUM - 1, ffs(config) - 1); - else - ivpu_dbg(vdev, MISC, "Fuse: All %d tiles enabled\n", BTRS_LNL_TILE_MAX_NUM); + ivpu_dbg(vdev, MISC, "Tile disable config mask: 0x%x\n", config); *tile_fuse_config = config; return 0; @@ -163,7 +157,6 @@ static int info_init_mtl(struct ivpu_device *vdev) hw->tile_fuse = BTRS_MTL_TILE_FUSE_ENABLE_BOTH; hw->sku = BTRS_MTL_TILE_SKU_BOTH; hw->config = BTRS_MTL_WP_CONFIG_2_TILE_4_3_RATIO; - hw->sched_mode = ivpu_sched_mode; return 0; } @@ -178,7 +171,6 @@ static int info_init_lnl(struct ivpu_device *vdev) if (ret) return ret; - hw->sched_mode = ivpu_sched_mode; hw->tile_fuse = tile_fuse_config; hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT; @@ -315,10 +307,6 @@ static void prepare_wp_request(struct ivpu_device *vdev, struct wp_request *wp, wp->cdyn = enable ? PLL_CDYN_DEFAULT : 0; wp->epp = enable ? PLL_EPP_DEFAULT : 0; } - - /* Simics cannot start without at least one tile */ - if (enable && ivpu_is_simics(vdev)) - wp->cfg = 1; } static int wait_for_pll_lock(struct ivpu_device *vdev, bool enable) @@ -465,9 +453,6 @@ int ivpu_hw_btrs_wait_for_clock_res_own_ack(struct ivpu_device *vdev) if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) return 0; - if (ivpu_is_simics(vdev)) - return 0; - return REGB_POLL_FLD(VPU_HW_BTRS_LNL_VPU_STATUS, CLOCK_RESOURCE_OWN_ACK, 1, TIMEOUT_US); } diff --git a/drivers/accel/ivpu/ivpu_hw_ip.c b/drivers/accel/ivpu/ivpu_hw_ip.c index 60b33fc59d96e3..029dd065614b2b 100644 --- a/drivers/accel/ivpu/ivpu_hw_ip.c +++ b/drivers/accel/ivpu/ivpu_hw_ip.c @@ -8,15 +8,12 @@ #include "ivpu_hw.h" #include "ivpu_hw_37xx_reg.h" #include "ivpu_hw_40xx_reg.h" +#include "ivpu_hw_btrs.h" #include "ivpu_hw_ip.h" #include "ivpu_hw_reg_io.h" #include "ivpu_mmu.h" #include "ivpu_pm.h" -#define PWR_ISLAND_EN_POST_DLY_FREQ_DEFAULT 0 -#define PWR_ISLAND_EN_POST_DLY_FREQ_HIGH 18 -#define PWR_ISLAND_STATUS_DLY_FREQ_DEFAULT 3 -#define PWR_ISLAND_STATUS_DLY_FREQ_HIGH 46 #define PWR_ISLAND_STATUS_TIMEOUT_US (5 * USEC_PER_MSEC) #define TIM_SAFE_ENABLE 0xf1d0dead @@ -268,20 +265,15 @@ void ivpu_hw_ip_idle_gen_disable(struct ivpu_device *vdev) idle_gen_drive_40xx(vdev, false); } -static void pwr_island_delay_set_50xx(struct ivpu_device *vdev) +static void +pwr_island_delay_set_50xx(struct ivpu_device *vdev, u32 post, u32 post1, u32 post2, u32 status) { - u32 val, post, status; - - if (vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_DEFAULT) { - post = PWR_ISLAND_EN_POST_DLY_FREQ_DEFAULT; - status = PWR_ISLAND_STATUS_DLY_FREQ_DEFAULT; - } else { - post = PWR_ISLAND_EN_POST_DLY_FREQ_HIGH; - status = PWR_ISLAND_STATUS_DLY_FREQ_HIGH; - } + u32 val; val = REGV_RD32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY); val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST_DLY, post, val); + val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST1_DLY, post1, val); + val = REG_SET_FLD_NUM(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, POST2_DLY, post2, val); REGV_WR32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_EN_POST_DLY, val); val = REGV_RD32(VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY); @@ -311,9 +303,6 @@ static void pwr_island_trickle_drive_40xx(struct ivpu_device *vdev, bool enable) val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, CSS_CPU, val); REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_TRICKLE_EN0, val); - - if (enable) - ndelay(500); } static void pwr_island_drive_37xx(struct ivpu_device *vdev, bool enable) @@ -326,9 +315,6 @@ static void pwr_island_drive_37xx(struct ivpu_device *vdev, bool enable) val = REG_CLR_FLD(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, CSS_CPU, val); REGV_WR32(VPU_40XX_HOST_SS_AON_PWR_ISLAND_EN0, val); - - if (!enable) - ndelay(500); } static void pwr_island_drive_40xx(struct ivpu_device *vdev, bool enable) @@ -347,9 +333,11 @@ static void pwr_island_enable(struct ivpu_device *vdev) { if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_37XX) { pwr_island_trickle_drive_37xx(vdev, true); + ndelay(500); pwr_island_drive_37xx(vdev, true); } else { pwr_island_trickle_drive_40xx(vdev, true); + ndelay(500); pwr_island_drive_40xx(vdev, true); } } @@ -686,13 +674,36 @@ static void dpu_active_drive_37xx(struct ivpu_device *vdev, bool enable) REGV_WR32(VPU_37XX_HOST_SS_AON_DPU_ACTIVE, val); } +static void pwr_island_delay_set(struct ivpu_device *vdev) +{ + bool high = vdev->hw->pll.profiling_freq == PLL_PROFILING_FREQ_HIGH; + u32 post, post1, post2, status; + + if (ivpu_hw_ip_gen(vdev) < IVPU_HW_IP_50XX) + return; + + switch (ivpu_device_id(vdev)) { + case PCI_DEVICE_ID_PTL_P: + post = high ? 18 : 0; + post1 = 0; + post2 = 0; + status = high ? 46 : 3; + break; + + default: + dump_stack(); + ivpu_err(vdev, "Unknown device ID\n"); + return; + } + + pwr_island_delay_set_50xx(vdev, post, post1, post2, status); +} + int ivpu_hw_ip_pwr_domain_enable(struct ivpu_device *vdev) { int ret; - if (ivpu_hw_ip_gen(vdev) == IVPU_HW_IP_50XX) - pwr_island_delay_set_50xx(vdev); - + pwr_island_delay_set(vdev); pwr_island_enable(vdev); ret = wait_for_pwr_island_status(vdev, 0x1); diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 78b32a8232419e..01ebf88fe6ef0a 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -15,6 +15,7 @@ #include "ivpu_ipc.h" #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" +#include "ivpu_trace.h" #define IPC_MAX_RX_MSG 128 @@ -227,6 +228,7 @@ int ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, stru goto unlock; ivpu_ipc_tx(vdev, cons->tx_vpu_addr); + trace_jsm("[tx]", req); unlock: mutex_unlock(&ipc->lock); @@ -278,12 +280,13 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, u32 size = min_t(int, rx_msg->ipc_hdr->data_size, sizeof(*jsm_msg)); if (rx_msg->jsm_msg->result != VPU_JSM_STATUS_SUCCESS) { - ivpu_dbg(vdev, IPC, "IPC resp result error: %d\n", rx_msg->jsm_msg->result); + ivpu_err(vdev, "IPC resp result error: %d\n", rx_msg->jsm_msg->result); ret = -EBADMSG; } if (jsm_msg) memcpy(jsm_msg, rx_msg->jsm_msg, size); + trace_jsm("[rx]", rx_msg->jsm_msg); } ivpu_ipc_rx_msg_del(vdev, rx_msg); @@ -291,15 +294,16 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, return ret; } -static int +int ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req, enum vpu_ipc_msg_type expected_resp_type, - struct vpu_jsm_msg *resp, u32 channel, - unsigned long timeout_ms) + struct vpu_jsm_msg *resp, u32 channel, unsigned long timeout_ms) { struct ivpu_ipc_consumer cons; int ret; + drm_WARN_ON(&vdev->drm, pm_runtime_status_suspended(vdev->drm.dev)); + ivpu_ipc_consumer_add(vdev, &cons, channel, NULL); ret = ivpu_ipc_send(vdev, &cons, req); @@ -325,19 +329,21 @@ ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req return ret; } -int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, - u32 channel, unsigned long timeout_ms) +int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms) { struct vpu_jsm_msg hb_req = { .type = VPU_JSM_MSG_QUERY_ENGINE_HB }; struct vpu_jsm_msg hb_resp; int ret, hb_ret; - drm_WARN_ON(&vdev->drm, pm_runtime_status_suspended(vdev->drm.dev)); + ret = ivpu_rpm_get(vdev); + if (ret < 0) + return ret; ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp, resp, channel, timeout_ms); if (ret != -ETIMEDOUT) - return ret; + goto rpm_put; hb_ret = ivpu_ipc_send_receive_internal(vdev, &hb_req, VPU_JSM_MSG_QUERY_ENGINE_HB_DONE, &hb_resp, VPU_IPC_CHAN_ASYNC_CMD, @@ -345,21 +351,33 @@ int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *r if (hb_ret == -ETIMEDOUT) ivpu_pm_trigger_recovery(vdev, "IPC timeout"); +rpm_put: + ivpu_rpm_put(vdev); return ret; } -int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, - u32 channel, unsigned long timeout_ms) +int ivpu_ipc_send_and_wait(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + u32 channel, unsigned long timeout_ms) { + struct ivpu_ipc_consumer cons; int ret; ret = ivpu_rpm_get(vdev); if (ret < 0) return ret; - ret = ivpu_ipc_send_receive_active(vdev, req, expected_resp, resp, channel, timeout_ms); + ivpu_ipc_consumer_add(vdev, &cons, channel, NULL); + ret = ivpu_ipc_send(vdev, &cons, req); + if (ret) { + ivpu_warn_ratelimited(vdev, "IPC send failed: %d\n", ret); + goto consumer_del; + } + + msleep(timeout_ms); + +consumer_del: + ivpu_ipc_consumer_del(vdev, &cons); ivpu_rpm_put(vdev); return ret; } @@ -518,7 +536,6 @@ void ivpu_ipc_fini(struct ivpu_device *vdev) { struct ivpu_ipc_info *ipc = vdev->ipc; - drm_WARN_ON(&vdev->drm, ipc->on); drm_WARN_ON(&vdev->drm, !list_empty(&ipc->cons_list)); drm_WARN_ON(&vdev->drm, !list_empty(&ipc->cb_msg_list)); drm_WARN_ON(&vdev->drm, atomic_read(&ipc->rx_msg_count) > 0); diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 4fe38141045ea3..b4dfb504679bac 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -101,12 +101,13 @@ int ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *jsm_msg, unsigned long timeout_ms); - -int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, - enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, - u32 channel, unsigned long timeout_ms); +int ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp_type, + struct vpu_jsm_msg *resp, u32 channel, unsigned long timeout_ms); int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, u32 channel, unsigned long timeout_ms); +int ivpu_ipc_send_and_wait(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + u32 channel, unsigned long timeout_ms); #endif /* __IVPU_IPC_H__ */ diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c index be2e2bf0f43f02..7149312f16e193 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -18,11 +18,10 @@ #include "ivpu_job.h" #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" +#include "ivpu_trace.h" #include "vpu_boot_api.h" #define CMD_BUF_IDX 0 -#define JOB_ID_JOB_MASK GENMASK(7, 0) -#define JOB_ID_CONTEXT_MASK GENMASK(31, 8) #define JOB_MAX_BUFFER_COUNT 65535 static void ivpu_cmdq_ring_db(struct ivpu_device *vdev, struct ivpu_cmdq *cmdq) @@ -35,24 +34,20 @@ static int ivpu_preemption_buffers_create(struct ivpu_device *vdev, { u64 primary_size = ALIGN(vdev->fw->primary_preempt_buf_size, PAGE_SIZE); u64 secondary_size = ALIGN(vdev->fw->secondary_preempt_buf_size, PAGE_SIZE); - struct ivpu_addr_range range; - if (vdev->hw->sched_mode != VPU_SCHEDULING_MODE_HW) + if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW || + ivpu_test_mode & IVPU_TEST_MODE_MIP_DISABLE) return 0; - range.start = vdev->hw->ranges.user.end - (primary_size * IVPU_NUM_CMDQS_PER_CTX); - range.end = vdev->hw->ranges.user.end; - cmdq->primary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &range, primary_size, - DRM_IVPU_BO_WC); + cmdq->primary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &vdev->hw->ranges.user, + primary_size, DRM_IVPU_BO_WC); if (!cmdq->primary_preempt_buf) { ivpu_err(vdev, "Failed to create primary preemption buffer\n"); return -ENOMEM; } - range.start = vdev->hw->ranges.shave.end - (secondary_size * IVPU_NUM_CMDQS_PER_CTX); - range.end = vdev->hw->ranges.shave.end; - cmdq->secondary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &range, secondary_size, - DRM_IVPU_BO_WC); + cmdq->secondary_preempt_buf = ivpu_bo_create(vdev, &file_priv->ctx, &vdev->hw->ranges.dma, + secondary_size, DRM_IVPU_BO_WC); if (!cmdq->secondary_preempt_buf) { ivpu_err(vdev, "Failed to create secondary preemption buffer\n"); goto err_free_primary; @@ -62,24 +57,24 @@ static int ivpu_preemption_buffers_create(struct ivpu_device *vdev, err_free_primary: ivpu_bo_free(cmdq->primary_preempt_buf); + cmdq->primary_preempt_buf = NULL; return -ENOMEM; } static void ivpu_preemption_buffers_free(struct ivpu_device *vdev, struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq) { - if (vdev->hw->sched_mode != VPU_SCHEDULING_MODE_HW) + if (vdev->fw->sched_mode != VPU_SCHEDULING_MODE_HW) return; - drm_WARN_ON(&vdev->drm, !cmdq->primary_preempt_buf); - drm_WARN_ON(&vdev->drm, !cmdq->secondary_preempt_buf); - ivpu_bo_free(cmdq->primary_preempt_buf); - ivpu_bo_free(cmdq->secondary_preempt_buf); + if (cmdq->primary_preempt_buf) + ivpu_bo_free(cmdq->primary_preempt_buf); + if (cmdq->secondary_preempt_buf) + ivpu_bo_free(cmdq->secondary_preempt_buf); } static struct ivpu_cmdq *ivpu_cmdq_alloc(struct ivpu_file_priv *file_priv) { - struct xa_limit db_xa_limit = {.max = IVPU_MAX_DB, .min = IVPU_MIN_DB}; struct ivpu_device *vdev = file_priv->vdev; struct ivpu_cmdq *cmdq; int ret; @@ -88,25 +83,33 @@ static struct ivpu_cmdq *ivpu_cmdq_alloc(struct ivpu_file_priv *file_priv) if (!cmdq) return NULL; - ret = xa_alloc(&vdev->db_xa, &cmdq->db_id, NULL, db_xa_limit, GFP_KERNEL); - if (ret) { + ret = xa_alloc_cyclic(&vdev->db_xa, &cmdq->db_id, NULL, vdev->db_limit, &vdev->db_next, + GFP_KERNEL); + if (ret < 0) { ivpu_err(vdev, "Failed to allocate doorbell id: %d\n", ret); goto err_free_cmdq; } + ret = xa_alloc_cyclic(&file_priv->cmdq_xa, &cmdq->id, cmdq, file_priv->cmdq_limit, + &file_priv->cmdq_id_next, GFP_KERNEL); + if (ret < 0) { + ivpu_err(vdev, "Failed to allocate command queue id: %d\n", ret); + goto err_erase_db_xa; + } + cmdq->mem = ivpu_bo_create_global(vdev, SZ_4K, DRM_IVPU_BO_WC | DRM_IVPU_BO_MAPPABLE); if (!cmdq->mem) - goto err_erase_xa; + goto err_erase_cmdq_xa; ret = ivpu_preemption_buffers_create(vdev, file_priv, cmdq); if (ret) - goto err_free_cmdq_mem; + ivpu_warn(vdev, "Failed to allocate preemption buffers, preemption limited\n"); return cmdq; -err_free_cmdq_mem: - ivpu_bo_free(cmdq->mem); -err_erase_xa: +err_erase_cmdq_xa: + xa_erase(&file_priv->cmdq_xa, cmdq->id); +err_erase_db_xa: xa_erase(&vdev->db_xa, cmdq->db_id); err_free_cmdq: kfree(cmdq); @@ -130,13 +133,13 @@ static int ivpu_hws_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq struct ivpu_device *vdev = file_priv->vdev; int ret; - ret = ivpu_jsm_hws_create_cmdq(vdev, file_priv->ctx.id, file_priv->ctx.id, cmdq->db_id, + ret = ivpu_jsm_hws_create_cmdq(vdev, file_priv->ctx.id, file_priv->ctx.id, cmdq->id, task_pid_nr(current), engine, cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); if (ret) return ret; - ret = ivpu_jsm_hws_set_context_sched_properties(vdev, file_priv->ctx.id, cmdq->db_id, + ret = ivpu_jsm_hws_set_context_sched_properties(vdev, file_priv->ctx.id, cmdq->id, priority); if (ret) return ret; @@ -149,21 +152,22 @@ static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq * struct ivpu_device *vdev = file_priv->vdev; int ret; - if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW) - ret = ivpu_jsm_hws_register_db(vdev, file_priv->ctx.id, cmdq->db_id, cmdq->db_id, + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) + ret = ivpu_jsm_hws_register_db(vdev, file_priv->ctx.id, cmdq->id, cmdq->db_id, cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); else ret = ivpu_jsm_register_db(vdev, file_priv->ctx.id, cmdq->db_id, cmdq->mem->vpu_addr, ivpu_bo_size(cmdq->mem)); if (!ret) - ivpu_dbg(vdev, JOB, "DB %d registered to ctx %d\n", cmdq->db_id, file_priv->ctx.id); + ivpu_dbg(vdev, JOB, "DB %d registered to cmdq %d ctx %d\n", + cmdq->db_id, cmdq->id, file_priv->ctx.id); return ret; } static int -ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u16 engine, u8 priority) +ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u8 priority) { struct ivpu_device *vdev = file_priv->vdev; struct vpu_job_queue_header *jobq_header; @@ -179,13 +183,18 @@ ivpu_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq, u16 eng cmdq->jobq = (struct vpu_job_queue *)ivpu_bo_vaddr(cmdq->mem); jobq_header = &cmdq->jobq->header; - jobq_header->engine_idx = engine; + jobq_header->engine_idx = VPU_ENGINE_COMPUTE; jobq_header->head = 0; jobq_header->tail = 0; + if (ivpu_test_mode & IVPU_TEST_MODE_TURBO) { + ivpu_dbg(vdev, JOB, "Turbo mode enabled"); + jobq_header->flags = VPU_JOB_QUEUE_FLAGS_TURBO_MODE; + } + wmb(); /* Flush WC buffer for jobq->header */ - if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW) { - ret = ivpu_hws_cmdq_init(file_priv, cmdq, engine, priority); + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { + ret = ivpu_hws_cmdq_init(file_priv, cmdq, VPU_ENGINE_COMPUTE, priority); if (ret) return ret; } @@ -211,10 +220,10 @@ static int ivpu_cmdq_fini(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cm cmdq->db_registered = false; - if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW) { - ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->db_id); + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { + ret = ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->id); if (!ret) - ivpu_dbg(vdev, JOB, "Command queue %d destroyed\n", cmdq->db_id); + ivpu_dbg(vdev, JOB, "Command queue %d destroyed\n", cmdq->id); } ret = ivpu_jsm_unregister_db(vdev, cmdq->db_id); @@ -224,55 +233,46 @@ static int ivpu_cmdq_fini(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cm return 0; } -static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u16 engine, - u8 priority) +static struct ivpu_cmdq *ivpu_cmdq_acquire(struct ivpu_file_priv *file_priv, u8 priority) { - int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority); - struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx]; + struct ivpu_cmdq *cmdq; + unsigned long cmdq_id; int ret; lockdep_assert_held(&file_priv->lock); + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) + if (cmdq->priority == priority) + break; + if (!cmdq) { cmdq = ivpu_cmdq_alloc(file_priv); if (!cmdq) return NULL; - file_priv->cmdq[cmdq_idx] = cmdq; + cmdq->priority = priority; } - ret = ivpu_cmdq_init(file_priv, cmdq, engine, priority); + ret = ivpu_cmdq_init(file_priv, cmdq, priority); if (ret) return NULL; return cmdq; } -static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engine, u8 priority) +void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) { - int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority); - struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx]; + struct ivpu_cmdq *cmdq; + unsigned long cmdq_id; lockdep_assert_held(&file_priv->lock); - if (cmdq) { - file_priv->cmdq[cmdq_idx] = NULL; + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) { + xa_erase(&file_priv->cmdq_xa, cmdq_id); ivpu_cmdq_fini(file_priv, cmdq); ivpu_cmdq_free(file_priv, cmdq); } } -void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) -{ - u16 engine; - u8 priority; - - lockdep_assert_held(&file_priv->lock); - - for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) - for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) - ivpu_cmdq_release_locked(file_priv, engine, priority); -} - /* * Mark the doorbell as unregistered * This function needs to be called when the VPU hardware is restarted @@ -281,20 +281,13 @@ void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) */ static void ivpu_cmdq_reset(struct ivpu_file_priv *file_priv) { - u16 engine; - u8 priority; + struct ivpu_cmdq *cmdq; + unsigned long cmdq_id; mutex_lock(&file_priv->lock); - for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) { - for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) { - int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority); - struct ivpu_cmdq *cmdq = file_priv->cmdq[cmdq_idx]; - - if (cmdq) - cmdq->db_registered = false; - } - } + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) + cmdq->db_registered = false; mutex_unlock(&file_priv->lock); } @@ -314,17 +307,11 @@ void ivpu_cmdq_reset_all_contexts(struct ivpu_device *vdev) static void ivpu_cmdq_fini_all(struct ivpu_file_priv *file_priv) { - u16 engine; - u8 priority; - - for (engine = 0; engine < IVPU_NUM_ENGINES; engine++) { - for (priority = 0; priority < IVPU_NUM_PRIORITIES; priority++) { - int cmdq_idx = IVPU_CMDQ_INDEX(engine, priority); + struct ivpu_cmdq *cmdq; + unsigned long cmdq_id; - if (file_priv->cmdq[cmdq_idx]) - ivpu_cmdq_fini(file_priv, file_priv->cmdq[cmdq_idx]); - } - } + xa_for_each(&file_priv->cmdq_xa, cmdq_id, cmdq) + ivpu_cmdq_fini(file_priv, cmdq); } void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv) @@ -335,7 +322,7 @@ void ivpu_context_abort_locked(struct ivpu_file_priv *file_priv) ivpu_cmdq_fini_all(file_priv); - if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_OS) + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_OS) ivpu_jsm_context_release(vdev, file_priv->ctx.id); } @@ -349,24 +336,29 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) /* Check if there is space left in job queue */ if (next_entry == header->head) { - ivpu_dbg(vdev, JOB, "Job queue full: ctx %d engine %d db %d head %d tail %d\n", - job->file_priv->ctx.id, job->engine_idx, cmdq->db_id, header->head, tail); + ivpu_dbg(vdev, JOB, "Job queue full: ctx %d cmdq %d db %d head %d tail %d\n", + job->file_priv->ctx.id, cmdq->id, cmdq->db_id, header->head, tail); return -EBUSY; } - entry = &cmdq->jobq->job[tail]; + entry = &cmdq->jobq->slot[tail].job; entry->batch_buf_addr = job->cmd_buf_vpu_addr; entry->job_id = job->job_id; entry->flags = 0; if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION)) entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; - if (vdev->hw->sched_mode == VPU_SCHEDULING_MODE_HW && - (unlikely(!(ivpu_test_mode & IVPU_TEST_MODE_PREEMPTION_DISABLE)))) { - entry->primary_preempt_buf_addr = cmdq->primary_preempt_buf->vpu_addr; - entry->primary_preempt_buf_size = ivpu_bo_size(cmdq->primary_preempt_buf); - entry->secondary_preempt_buf_addr = cmdq->secondary_preempt_buf->vpu_addr; - entry->secondary_preempt_buf_size = ivpu_bo_size(cmdq->secondary_preempt_buf); + if (vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW) { + if (cmdq->primary_preempt_buf) { + entry->primary_preempt_buf_addr = cmdq->primary_preempt_buf->vpu_addr; + entry->primary_preempt_buf_size = ivpu_bo_size(cmdq->primary_preempt_buf); + } + + if (cmdq->secondary_preempt_buf) { + entry->secondary_preempt_buf_addr = cmdq->secondary_preempt_buf->vpu_addr; + entry->secondary_preempt_buf_size = + ivpu_bo_size(cmdq->secondary_preempt_buf); + } } wmb(); /* Ensure that tail is updated after filling entry */ @@ -457,6 +449,7 @@ ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) job->file_priv = ivpu_file_priv_get(file_priv); + trace_job("create", job); ivpu_dbg(vdev, JOB, "Job created: ctx %2d engine %d", file_priv->ctx.id, job->engine_idx); return job; @@ -496,6 +489,7 @@ static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32 job->bos[CMD_BUF_IDX]->job_status = job_status; dma_fence_signal(job->done_fence); + trace_job("done", job); ivpu_dbg(vdev, JOB, "Job complete: id %3u ctx %2d engine %d status 0x%x\n", job->job_id, job->file_priv->ctx.id, job->engine_idx, job_status); @@ -519,7 +513,6 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 priority) { struct ivpu_file_priv *file_priv = job->file_priv; struct ivpu_device *vdev = job->vdev; - struct xa_limit job_id_range; struct ivpu_cmdq *cmdq; bool is_first_job; int ret; @@ -530,7 +523,7 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 priority) mutex_lock(&file_priv->lock); - cmdq = ivpu_cmdq_acquire(job->file_priv, job->engine_idx, priority); + cmdq = ivpu_cmdq_acquire(file_priv, priority); if (!cmdq) { ivpu_warn_ratelimited(vdev, "Failed to get job queue, ctx %d engine %d prio %d\n", file_priv->ctx.id, job->engine_idx, priority); @@ -538,13 +531,11 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 priority) goto err_unlock_file_priv; } - job_id_range.min = FIELD_PREP(JOB_ID_CONTEXT_MASK, (file_priv->ctx.id - 1)); - job_id_range.max = job_id_range.min | JOB_ID_JOB_MASK; - xa_lock(&vdev->submitted_jobs_xa); is_first_job = xa_empty(&vdev->submitted_jobs_xa); - ret = __xa_alloc(&vdev->submitted_jobs_xa, &job->job_id, job, job_id_range, GFP_KERNEL); - if (ret) { + ret = __xa_alloc_cyclic(&vdev->submitted_jobs_xa, &job->job_id, job, file_priv->job_limit, + &file_priv->job_id_next, GFP_KERNEL); + if (ret < 0) { ivpu_dbg(vdev, JOB, "Too many active jobs in ctx %d\n", file_priv->ctx.id); ret = -EBUSY; @@ -566,6 +557,7 @@ static int ivpu_job_submit(struct ivpu_job *job, u8 priority) vdev->busy_start_ts = ktime_get(); } + trace_job("submit", job); ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d prio %d addr 0x%llx next %d\n", job->job_id, file_priv->ctx.id, job->engine_idx, priority, job->cmd_buf_vpu_addr, cmdq->jobq->header.tail); @@ -673,7 +665,7 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) int idx, ret; u8 priority; - if (params->engine > DRM_IVPU_ENGINE_COPY) + if (params->engine != DRM_IVPU_ENGINE_COMPUTE) return -EINVAL; if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h index 6accb94028c7a2..8b19e3f8b4cfb3 100644 --- a/drivers/accel/ivpu/ivpu_job.h +++ b/drivers/accel/ivpu/ivpu_job.h @@ -28,8 +28,10 @@ struct ivpu_cmdq { struct ivpu_bo *secondary_preempt_buf; struct ivpu_bo *mem; u32 entry_count; + u32 id; u32 db_id; bool db_registered; + u8 priority; }; /** diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 46ef16c3c06910..30a40be7693019 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -48,9 +48,10 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE); IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP); IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP_RSP); - IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT); + IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT_DEPRECATED); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL); IVPU_CASE_TO_STR(VPU_JSM_MSG_JOB_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_NATIVE_FENCE_SIGNALLED); IVPU_CASE_TO_STR(VPU_JSM_MSG_ENGINE_RESET_DONE); IVPU_CASE_TO_STR(VPU_JSM_MSG_ENGINE_PREEMPT_DONE); IVPU_CASE_TO_STR(VPU_JSM_MSG_REGISTER_DB_DONE); @@ -131,7 +132,7 @@ int ivpu_jsm_get_heartbeat(struct ivpu_device *vdev, u32 engine, u64 *heartbeat) struct vpu_jsm_msg resp; int ret; - if (engine > VPU_ENGINE_COPY) + if (engine != VPU_ENGINE_COMPUTE) return -EINVAL; req.payload.query_engine_hb.engine_idx = engine; @@ -154,7 +155,7 @@ int ivpu_jsm_reset_engine(struct ivpu_device *vdev, u32 engine) struct vpu_jsm_msg resp; int ret; - if (engine > VPU_ENGINE_COPY) + if (engine != VPU_ENGINE_COMPUTE) return -EINVAL; req.payload.engine_reset.engine_idx = engine; @@ -173,7 +174,7 @@ int ivpu_jsm_preempt_engine(struct ivpu_device *vdev, u32 engine, u32 preempt_id struct vpu_jsm_msg resp; int ret; - if (engine > VPU_ENGINE_COPY) + if (engine != VPU_ENGINE_COMPUTE) return -EINVAL; req.payload.engine_preempt.engine_idx = engine; @@ -196,7 +197,7 @@ int ivpu_jsm_dyndbg_control(struct ivpu_device *vdev, char *command, size_t size strscpy(req.payload.dyndbg_control.dyndbg_cmd, command, VPU_DYNDBG_CMD_MAX_LEN); ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_DYNDBG_CONTROL_RSP, &resp, - VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); + VPU_IPC_CHAN_GEN_CMD, vdev->timeout.jsm); if (ret) ivpu_warn_ratelimited(vdev, "Failed to send command \"%s\": ret %d\n", command, ret); @@ -270,9 +271,8 @@ int ivpu_jsm_pwr_d0i3_enter(struct ivpu_device *vdev) req.payload.pwr_d0i3_enter.send_response = 1; - ret = ivpu_ipc_send_receive_active(vdev, &req, VPU_JSM_MSG_PWR_D0I3_ENTER_DONE, - &resp, VPU_IPC_CHAN_GEN_CMD, - vdev->timeout.d0i3_entry_msg); + ret = ivpu_ipc_send_receive_internal(vdev, &req, VPU_JSM_MSG_PWR_D0I3_ENTER_DONE, &resp, + VPU_IPC_CHAN_GEN_CMD, vdev->timeout.d0i3_entry_msg); if (ret) return ret; @@ -346,7 +346,7 @@ int ivpu_jsm_hws_resume_engine(struct ivpu_device *vdev, u32 engine) struct vpu_jsm_msg resp; int ret; - if (engine >= VPU_ENGINE_NB) + if (engine != VPU_ENGINE_COMPUTE) return -EINVAL; req.payload.hws_resume_engine.engine_idx = engine; @@ -394,8 +394,6 @@ int ivpu_jsm_hws_set_scheduling_log(struct ivpu_device *vdev, u32 engine_idx, u3 req.payload.hws_set_scheduling_log.host_ssid = host_ssid; req.payload.hws_set_scheduling_log.vpu_log_buffer_va = vpu_log_buffer_va; req.payload.hws_set_scheduling_log.notify_index = 0; - req.payload.hws_set_scheduling_log.enable_extra_events = - ivpu_test_mode & IVPU_TEST_MODE_HWS_EXTRA_EVENTS; ret = ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP, &resp, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); @@ -430,8 +428,8 @@ int ivpu_jsm_hws_setup_priority_bands(struct ivpu_device *vdev) req.payload.hws_priority_band_setup.normal_band_percentage = 10; - ret = ivpu_ipc_send_receive_active(vdev, &req, VPU_JSM_MSG_SET_PRIORITY_BAND_SETUP_RSP, - &resp, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); + ret = ivpu_ipc_send_receive_internal(vdev, &req, VPU_JSM_MSG_SET_PRIORITY_BAND_SETUP_RSP, + &resp, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); if (ret) ivpu_warn_ratelimited(vdev, "Failed to set priority bands: %d\n", ret); @@ -544,9 +542,8 @@ int ivpu_jsm_dct_enable(struct ivpu_device *vdev, u32 active_us, u32 inactive_us req.payload.pwr_dct_control.dct_active_us = active_us; req.payload.pwr_dct_control.dct_inactive_us = inactive_us; - return ivpu_ipc_send_receive_active(vdev, &req, VPU_JSM_MSG_DCT_ENABLE_DONE, - &resp, VPU_IPC_CHAN_ASYNC_CMD, - vdev->timeout.jsm); + return ivpu_ipc_send_receive_internal(vdev, &req, VPU_JSM_MSG_DCT_ENABLE_DONE, &resp, + VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); } int ivpu_jsm_dct_disable(struct ivpu_device *vdev) @@ -554,7 +551,14 @@ int ivpu_jsm_dct_disable(struct ivpu_device *vdev) struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_DCT_DISABLE }; struct vpu_jsm_msg resp; - return ivpu_ipc_send_receive_active(vdev, &req, VPU_JSM_MSG_DCT_DISABLE_DONE, - &resp, VPU_IPC_CHAN_ASYNC_CMD, - vdev->timeout.jsm); + return ivpu_ipc_send_receive_internal(vdev, &req, VPU_JSM_MSG_DCT_DISABLE_DONE, &resp, + VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); +} + +int ivpu_jsm_state_dump(struct ivpu_device *vdev) +{ + struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_STATE_DUMP }; + + return ivpu_ipc_send_and_wait(vdev, &req, VPU_IPC_CHAN_ASYNC_CMD, + vdev->timeout.state_dump_msg); } diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.h b/drivers/accel/ivpu/ivpu_jsm_msg.h index e4e42c0ff6e656..9e84d3526a1463 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.h +++ b/drivers/accel/ivpu/ivpu_jsm_msg.h @@ -43,4 +43,6 @@ int ivpu_jsm_metric_streamer_info(struct ivpu_device *vdev, u64 metric_group_mas u64 buffer_size, u32 *sample_size, u64 *info_size); int ivpu_jsm_dct_enable(struct ivpu_device *vdev, u32 active_us, u32 inactive_us); int ivpu_jsm_dct_disable(struct ivpu_device *vdev); +int ivpu_jsm_state_dump(struct ivpu_device *vdev); + #endif diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index c078e214b22129..26ef52fbb93e53 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -696,7 +696,7 @@ int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid) return ret; } -static int ivpu_mmu_cd_add(struct ivpu_device *vdev, u32 ssid, u64 cd_dma) +static int ivpu_mmu_cdtab_entry_set(struct ivpu_device *vdev, u32 ssid, u64 cd_dma, bool valid) { struct ivpu_mmu_info *mmu = vdev->mmu; struct ivpu_mmu_cdtab *cdtab = &mmu->cdtab; @@ -708,30 +708,29 @@ static int ivpu_mmu_cd_add(struct ivpu_device *vdev, u32 ssid, u64 cd_dma) return -EINVAL; entry = cdtab->base + (ssid * IVPU_MMU_CDTAB_ENT_SIZE); - - if (cd_dma != 0) { - cd[0] = FIELD_PREP(IVPU_MMU_CD_0_TCR_T0SZ, IVPU_MMU_T0SZ_48BIT) | - FIELD_PREP(IVPU_MMU_CD_0_TCR_TG0, 0) | - FIELD_PREP(IVPU_MMU_CD_0_TCR_IRGN0, 0) | - FIELD_PREP(IVPU_MMU_CD_0_TCR_ORGN0, 0) | - FIELD_PREP(IVPU_MMU_CD_0_TCR_SH0, 0) | - FIELD_PREP(IVPU_MMU_CD_0_TCR_IPS, IVPU_MMU_IPS_48BIT) | - FIELD_PREP(IVPU_MMU_CD_0_ASID, ssid) | - IVPU_MMU_CD_0_TCR_EPD1 | - IVPU_MMU_CD_0_AA64 | - IVPU_MMU_CD_0_R | - IVPU_MMU_CD_0_ASET | - IVPU_MMU_CD_0_V; - cd[1] = cd_dma & IVPU_MMU_CD_1_TTB0_MASK; - cd[2] = 0; - cd[3] = 0x0000000000007444; - - /* For global context generate memory fault on VPU */ - if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) - cd[0] |= IVPU_MMU_CD_0_A; - } else { - memset(cd, 0, sizeof(cd)); - } + drm_WARN_ON(&vdev->drm, (entry[0] & IVPU_MMU_CD_0_V) == valid); + + cd[0] = FIELD_PREP(IVPU_MMU_CD_0_TCR_T0SZ, IVPU_MMU_T0SZ_48BIT) | + FIELD_PREP(IVPU_MMU_CD_0_TCR_TG0, 0) | + FIELD_PREP(IVPU_MMU_CD_0_TCR_IRGN0, 0) | + FIELD_PREP(IVPU_MMU_CD_0_TCR_ORGN0, 0) | + FIELD_PREP(IVPU_MMU_CD_0_TCR_SH0, 0) | + FIELD_PREP(IVPU_MMU_CD_0_TCR_IPS, IVPU_MMU_IPS_48BIT) | + FIELD_PREP(IVPU_MMU_CD_0_ASID, ssid) | + IVPU_MMU_CD_0_TCR_EPD1 | + IVPU_MMU_CD_0_AA64 | + IVPU_MMU_CD_0_R | + IVPU_MMU_CD_0_ASET; + cd[1] = cd_dma & IVPU_MMU_CD_1_TTB0_MASK; + cd[2] = 0; + cd[3] = 0x0000000000007444; + + /* For global context generate memory fault on VPU */ + if (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) + cd[0] |= IVPU_MMU_CD_0_A; + + if (valid) + cd[0] |= IVPU_MMU_CD_0_V; WRITE_ONCE(entry[1], cd[1]); WRITE_ONCE(entry[2], cd[2]); @@ -741,8 +740,8 @@ static int ivpu_mmu_cd_add(struct ivpu_device *vdev, u32 ssid, u64 cd_dma) if (!ivpu_is_force_snoop_enabled(vdev)) clflush_cache_range(entry, IVPU_MMU_CDTAB_ENT_SIZE); - ivpu_dbg(vdev, MMU, "CDTAB %s entry (SSID=%u, dma=%pad): 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", - cd_dma ? "write" : "clear", ssid, &cd_dma, cd[0], cd[1], cd[2], cd[3]); + ivpu_dbg(vdev, MMU, "CDTAB set %s entry (SSID=%u, dma=%pad): 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", + valid ? "valid" : "invalid", ssid, &cd_dma, cd[0], cd[1], cd[2], cd[3]); mutex_lock(&mmu->lock); if (!mmu->on) @@ -750,38 +749,18 @@ static int ivpu_mmu_cd_add(struct ivpu_device *vdev, u32 ssid, u64 cd_dma) ret = ivpu_mmu_cmdq_write_cfgi_all(vdev); if (ret) - goto unlock; + goto err_invalidate; ret = ivpu_mmu_cmdq_sync(vdev); + if (ret) + goto err_invalidate; unlock: mutex_unlock(&mmu->lock); - return ret; -} - -static int ivpu_mmu_cd_add_gbl(struct ivpu_device *vdev) -{ - int ret; - - ret = ivpu_mmu_cd_add(vdev, 0, vdev->gctx.pgtable.pgd_dma); - if (ret) - ivpu_err(vdev, "Failed to add global CD entry: %d\n", ret); - - return ret; -} - -static int ivpu_mmu_cd_add_user(struct ivpu_device *vdev, u32 ssid, dma_addr_t cd_dma) -{ - int ret; - - if (ssid == 0) { - ivpu_err(vdev, "Invalid SSID: %u\n", ssid); - return -EINVAL; - } - - ret = ivpu_mmu_cd_add(vdev, ssid, cd_dma); - if (ret) - ivpu_err(vdev, "Failed to add CD entry SSID=%u: %d\n", ssid, ret); + return 0; +err_invalidate: + WRITE_ONCE(entry[0], 0); + mutex_unlock(&mmu->lock); return ret; } @@ -808,12 +787,6 @@ int ivpu_mmu_init(struct ivpu_device *vdev) return ret; } - ret = ivpu_mmu_cd_add_gbl(vdev); - if (ret) { - ivpu_err(vdev, "Failed to initialize strtab: %d\n", ret); - return ret; - } - ret = ivpu_mmu_enable(vdev); if (ret) { ivpu_err(vdev, "Failed to resume MMU: %d\n", ret); @@ -966,12 +939,12 @@ void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev) REGV_WR32(IVPU_MMU_REG_GERRORN, gerror_val); } -int ivpu_mmu_set_pgtable(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable) +int ivpu_mmu_cd_set(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable) { - return ivpu_mmu_cd_add_user(vdev, ssid, pgtable->pgd_dma); + return ivpu_mmu_cdtab_entry_set(vdev, ssid, pgtable->pgd_dma, true); } -void ivpu_mmu_clear_pgtable(struct ivpu_device *vdev, int ssid) +void ivpu_mmu_cd_clear(struct ivpu_device *vdev, int ssid) { - ivpu_mmu_cd_add_user(vdev, ssid, 0); /* 0 will clear CD entry */ + ivpu_mmu_cdtab_entry_set(vdev, ssid, 0, false); } diff --git a/drivers/accel/ivpu/ivpu_mmu.h b/drivers/accel/ivpu/ivpu_mmu.h index 6fa35c24071062..7afea9cd8731d5 100644 --- a/drivers/accel/ivpu/ivpu_mmu.h +++ b/drivers/accel/ivpu/ivpu_mmu.h @@ -40,8 +40,8 @@ struct ivpu_mmu_info { int ivpu_mmu_init(struct ivpu_device *vdev); void ivpu_mmu_disable(struct ivpu_device *vdev); int ivpu_mmu_enable(struct ivpu_device *vdev); -int ivpu_mmu_set_pgtable(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable); -void ivpu_mmu_clear_pgtable(struct ivpu_device *vdev, int ssid); +int ivpu_mmu_cd_set(struct ivpu_device *vdev, int ssid, struct ivpu_mmu_pgtable *pgtable); +void ivpu_mmu_cd_clear(struct ivpu_device *vdev, int ssid); int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid); void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_mmu_context.c b/drivers/accel/ivpu/ivpu_mmu_context.c index bbe652a7019d03..0af614dfb6f925 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -90,19 +90,6 @@ static void ivpu_pgtable_free_page(struct ivpu_device *vdev, u64 *cpu_addr, dma_ } } -static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) -{ - dma_addr_t pgd_dma; - - pgtable->pgd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pgd_dma); - if (!pgtable->pgd_dma_ptr) - return -ENOMEM; - - pgtable->pgd_dma = pgd_dma; - - return 0; -} - static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) { int pgd_idx, pud_idx, pmd_idx; @@ -140,6 +127,27 @@ static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgt } ivpu_pgtable_free_page(vdev, pgtable->pgd_dma_ptr, pgtable->pgd_dma); + pgtable->pgd_dma_ptr = NULL; + pgtable->pgd_dma = 0; +} + +static u64* +ivpu_mmu_ensure_pgd(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) +{ + u64 *pgd_dma_ptr = pgtable->pgd_dma_ptr; + dma_addr_t pgd_dma; + + if (pgd_dma_ptr) + return pgd_dma_ptr; + + pgd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pgd_dma); + if (!pgd_dma_ptr) + return NULL; + + pgtable->pgd_dma_ptr = pgd_dma_ptr; + pgtable->pgd_dma = pgd_dma; + + return pgd_dma_ptr; } static u64* @@ -237,6 +245,12 @@ ivpu_mmu_context_map_page(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx int pmd_idx = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr); int pte_idx = FIELD_GET(IVPU_MMU_PTE_INDEX_MASK, vpu_addr); + drm_WARN_ON(&vdev->drm, ctx->id == IVPU_RESERVED_CONTEXT_MMU_SSID); + + /* Allocate PGD - first level page table if needed */ + if (!ivpu_mmu_ensure_pgd(vdev, &ctx->pgtable)) + return -ENOMEM; + /* Allocate PUD - second level page table if needed */ if (!ivpu_mmu_ensure_pud(vdev, &ctx->pgtable, pgd_idx)) return -ENOMEM; @@ -418,6 +432,7 @@ int ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 vpu_addr, struct sg_table *sgt, bool llc_coherent) { + size_t start_vpu_addr = vpu_addr; struct scatterlist *sg; int ret; u64 prot; @@ -448,20 +463,36 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, ret = ivpu_mmu_context_map_pages(vdev, ctx, vpu_addr, dma_addr, size, prot); if (ret) { ivpu_err(vdev, "Failed to map context pages\n"); - mutex_unlock(&ctx->lock); - return ret; + goto err_unmap_pages; } vpu_addr += size; } + if (!ctx->is_cd_valid) { + ret = ivpu_mmu_cd_set(vdev, ctx->id, &ctx->pgtable); + if (ret) { + ivpu_err(vdev, "Failed to set context descriptor for context %u: %d\n", + ctx->id, ret); + goto err_unmap_pages; + } + ctx->is_cd_valid = true; + } + /* Ensure page table modifications are flushed from wc buffers to memory */ wmb(); - mutex_unlock(&ctx->lock); - ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); - if (ret) + if (ret) { ivpu_err(vdev, "Failed to invalidate TLB for ctx %u: %d\n", ctx->id, ret); + goto err_unmap_pages; + } + + mutex_unlock(&ctx->lock); + return 0; + +err_unmap_pages: + ivpu_mmu_context_unmap_pages(ctx, start_vpu_addr, vpu_addr - start_vpu_addr); + mutex_unlock(&ctx->lock); return ret; } @@ -530,65 +561,79 @@ ivpu_mmu_context_remove_node(struct ivpu_mmu_context *ctx, struct drm_mm_node *n mutex_unlock(&ctx->lock); } -static int -ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 context_id) +void ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 context_id) { u64 start, end; - int ret; mutex_init(&ctx->lock); - ret = ivpu_mmu_pgtable_init(vdev, &ctx->pgtable); - if (ret) { - ivpu_err(vdev, "Failed to initialize pgtable for ctx %u: %d\n", context_id, ret); - return ret; - } - if (!context_id) { start = vdev->hw->ranges.global.start; end = vdev->hw->ranges.shave.end; } else { - start = vdev->hw->ranges.user.start; - end = vdev->hw->ranges.dma.end; + start = min_t(u64, vdev->hw->ranges.user.start, vdev->hw->ranges.shave.start); + end = max_t(u64, vdev->hw->ranges.user.end, vdev->hw->ranges.dma.end); } drm_mm_init(&ctx->mm, start, end - start); ctx->id = context_id; - - return 0; } -static void ivpu_mmu_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) +void ivpu_mmu_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) { - if (drm_WARN_ON(&vdev->drm, !ctx->pgtable.pgd_dma_ptr)) - return; + if (ctx->is_cd_valid) { + ivpu_mmu_cd_clear(vdev, ctx->id); + ctx->is_cd_valid = false; + } mutex_destroy(&ctx->lock); ivpu_mmu_pgtables_free(vdev, &ctx->pgtable); drm_mm_takedown(&ctx->mm); - - ctx->pgtable.pgd_dma_ptr = NULL; - ctx->pgtable.pgd_dma = 0; } -int ivpu_mmu_global_context_init(struct ivpu_device *vdev) +void ivpu_mmu_global_context_init(struct ivpu_device *vdev) { - return ivpu_mmu_context_init(vdev, &vdev->gctx, IVPU_GLOBAL_CONTEXT_MMU_SSID); + ivpu_mmu_context_init(vdev, &vdev->gctx, IVPU_GLOBAL_CONTEXT_MMU_SSID); } void ivpu_mmu_global_context_fini(struct ivpu_device *vdev) { - return ivpu_mmu_context_fini(vdev, &vdev->gctx); + ivpu_mmu_context_fini(vdev, &vdev->gctx); } int ivpu_mmu_reserved_context_init(struct ivpu_device *vdev) { - return ivpu_mmu_user_context_init(vdev, &vdev->rctx, IVPU_RESERVED_CONTEXT_MMU_SSID); + int ret; + + ivpu_mmu_context_init(vdev, &vdev->rctx, IVPU_RESERVED_CONTEXT_MMU_SSID); + + mutex_lock(&vdev->rctx.lock); + + if (!ivpu_mmu_ensure_pgd(vdev, &vdev->rctx.pgtable)) { + ivpu_err(vdev, "Failed to allocate root page table for reserved context\n"); + ret = -ENOMEM; + goto err_ctx_fini; + } + + ret = ivpu_mmu_cd_set(vdev, vdev->rctx.id, &vdev->rctx.pgtable); + if (ret) { + ivpu_err(vdev, "Failed to set context descriptor for reserved context\n"); + goto err_ctx_fini; + } + + mutex_unlock(&vdev->rctx.lock); + return ret; + +err_ctx_fini: + mutex_unlock(&vdev->rctx.lock); + ivpu_mmu_context_fini(vdev, &vdev->rctx); + return ret; } void ivpu_mmu_reserved_context_fini(struct ivpu_device *vdev) { - return ivpu_mmu_user_context_fini(vdev, &vdev->rctx); + ivpu_mmu_cd_clear(vdev, vdev->rctx.id); + ivpu_mmu_context_fini(vdev, &vdev->rctx); } void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid) @@ -603,36 +648,3 @@ void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid) xa_unlock(&vdev->context_xa); } - -int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 ctx_id) -{ - int ret; - - drm_WARN_ON(&vdev->drm, !ctx_id); - - ret = ivpu_mmu_context_init(vdev, ctx, ctx_id); - if (ret) { - ivpu_err(vdev, "Failed to initialize context %u: %d\n", ctx_id, ret); - return ret; - } - - ret = ivpu_mmu_set_pgtable(vdev, ctx_id, &ctx->pgtable); - if (ret) { - ivpu_err(vdev, "Failed to set page table for context %u: %d\n", ctx_id, ret); - goto err_context_fini; - } - - return 0; - -err_context_fini: - ivpu_mmu_context_fini(vdev, ctx); - return ret; -} - -void ivpu_mmu_user_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) -{ - drm_WARN_ON(&vdev->drm, !ctx->id); - - ivpu_mmu_clear_pgtable(vdev, ctx->id); - ivpu_mmu_context_fini(vdev, ctx); -} diff --git a/drivers/accel/ivpu/ivpu_mmu_context.h b/drivers/accel/ivpu/ivpu_mmu_context.h index 7f9aaf3d10c2f7..8042fc0670622b 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.h +++ b/drivers/accel/ivpu/ivpu_mmu_context.h @@ -23,19 +23,20 @@ struct ivpu_mmu_pgtable { }; struct ivpu_mmu_context { - struct mutex lock; /* Protects: mm, pgtable */ + struct mutex lock; /* Protects: mm, pgtable, is_cd_valid */ struct drm_mm mm; struct ivpu_mmu_pgtable pgtable; + bool is_cd_valid; u32 id; }; -int ivpu_mmu_global_context_init(struct ivpu_device *vdev); +void ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 context_id); +void ivpu_mmu_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); +void ivpu_mmu_global_context_init(struct ivpu_device *vdev); void ivpu_mmu_global_context_fini(struct ivpu_device *vdev); int ivpu_mmu_reserved_context_init(struct ivpu_device *vdev); void ivpu_mmu_reserved_context_fini(struct ivpu_device *vdev); -int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u32 ctx_id); -void ivpu_mmu_user_context_fini(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); void ivpu_mmu_user_context_mark_invalid(struct ivpu_device *vdev, u32 ssid); int ivpu_mmu_context_insert_node(struct ivpu_mmu_context *ctx, const struct ivpu_addr_range *range, diff --git a/drivers/accel/ivpu/ivpu_ms.c b/drivers/accel/ivpu/ivpu_ms.c index 2f9d37f5c208a9..ffe7b10f8a767b 100644 --- a/drivers/accel/ivpu/ivpu_ms.c +++ b/drivers/accel/ivpu/ivpu_ms.c @@ -11,7 +11,7 @@ #include "ivpu_ms.h" #include "ivpu_pm.h" -#define MS_INFO_BUFFER_SIZE SZ_16K +#define MS_INFO_BUFFER_SIZE SZ_64K #define MS_NUM_BUFFERS 2 #define MS_READ_PERIOD_MULTIPLIER 2 #define MS_MIN_SAMPLE_PERIOD_NS 1000000 diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index 59d3170f5e3541..949f4233946c63 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -9,21 +9,25 @@ #include #include -#include "vpu_boot_api.h" +#include "ivpu_coredump.h" #include "ivpu_drv.h" -#include "ivpu_hw.h" #include "ivpu_fw.h" #include "ivpu_fw_log.h" +#include "ivpu_hw.h" #include "ivpu_ipc.h" #include "ivpu_job.h" #include "ivpu_jsm_msg.h" #include "ivpu_mmu.h" #include "ivpu_ms.h" #include "ivpu_pm.h" +#include "ivpu_trace.h" +#include "vpu_boot_api.h" static bool ivpu_disable_recovery; +#if IS_ENABLED(CONFIG_DRM_ACCEL_IVPU_DEBUG) module_param_named_unsafe(disable_recovery, ivpu_disable_recovery, bool, 0644); MODULE_PARM_DESC(disable_recovery, "Disables recovery when NPU hang is detected"); +#endif static unsigned long ivpu_tdr_timeout_ms; module_param_named(tdr_timeout_ms, ivpu_tdr_timeout_ms, ulong, 0644); @@ -37,6 +41,7 @@ static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev) ivpu_cmdq_reset_all_contexts(vdev); ivpu_ipc_reset(vdev); + ivpu_fw_log_reset(vdev); ivpu_fw_load(vdev); fw->entry_point = fw->cold_boot_entry_point; } @@ -123,7 +128,8 @@ static void ivpu_pm_recovery_work(struct work_struct *work) if (ret) ivpu_err(vdev, "Failed to resume NPU: %d\n", ret); - ivpu_fw_log_dump(vdev); + ivpu_jsm_state_dump(vdev); + ivpu_dev_coredump(vdev); atomic_inc(&vdev->pm->reset_counter); atomic_set(&vdev->pm->reset_pending, 1); @@ -195,6 +201,7 @@ int ivpu_pm_suspend_cb(struct device *dev) struct ivpu_device *vdev = to_ivpu_device(drm); unsigned long timeout; + trace_pm("suspend"); ivpu_dbg(vdev, PM, "Suspend..\n"); timeout = jiffies + msecs_to_jiffies(vdev->timeout.tdr); @@ -212,6 +219,7 @@ int ivpu_pm_suspend_cb(struct device *dev) ivpu_pm_prepare_warm_boot(vdev); ivpu_dbg(vdev, PM, "Suspend done.\n"); + trace_pm("suspend done"); return 0; } @@ -222,6 +230,7 @@ int ivpu_pm_resume_cb(struct device *dev) struct ivpu_device *vdev = to_ivpu_device(drm); int ret; + trace_pm("resume"); ivpu_dbg(vdev, PM, "Resume..\n"); ret = ivpu_resume(vdev); @@ -229,6 +238,7 @@ int ivpu_pm_resume_cb(struct device *dev) ivpu_err(vdev, "Failed to resume: %d\n", ret); ivpu_dbg(vdev, PM, "Resume done.\n"); + trace_pm("resume done"); return ret; } @@ -243,6 +253,7 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa)); drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work)); + trace_pm("runtime suspend"); ivpu_dbg(vdev, PM, "Runtime suspend..\n"); ivpu_mmu_disable(vdev); @@ -262,13 +273,14 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) if (!is_idle || ret_d0i3) { ivpu_err(vdev, "Forcing cold boot due to previous errors\n"); atomic_inc(&vdev->pm->reset_counter); - ivpu_fw_log_dump(vdev); + ivpu_dev_coredump(vdev); ivpu_pm_prepare_cold_boot(vdev); } else { ivpu_pm_prepare_warm_boot(vdev); } ivpu_dbg(vdev, PM, "Runtime suspend done.\n"); + trace_pm("runtime suspend done"); return 0; } @@ -279,6 +291,7 @@ int ivpu_pm_runtime_resume_cb(struct device *dev) struct ivpu_device *vdev = to_ivpu_device(drm); int ret; + trace_pm("runtime resume"); ivpu_dbg(vdev, PM, "Runtime resume..\n"); ret = ivpu_resume(vdev); @@ -286,6 +299,7 @@ int ivpu_pm_runtime_resume_cb(struct device *dev) ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret); ivpu_dbg(vdev, PM, "Runtime resume done.\n"); + trace_pm("runtime resume done"); return ret; } @@ -364,6 +378,7 @@ void ivpu_pm_init(struct ivpu_device *vdev) pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, delay); + pm_runtime_set_active(dev); ivpu_dbg(vdev, PM, "Autosuspend delay = %d\n", delay); } @@ -378,7 +393,6 @@ void ivpu_pm_enable(struct ivpu_device *vdev) { struct device *dev = vdev->drm.dev; - pm_runtime_set_active(dev); pm_runtime_allow(dev); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -411,7 +425,7 @@ int ivpu_pm_dct_enable(struct ivpu_device *vdev, u8 active_percent) ret = ivpu_jsm_dct_enable(vdev, active_us, inactive_us); if (ret) { - ivpu_err_ratelimited(vdev, "Filed to enable DCT: %d\n", ret); + ivpu_err_ratelimited(vdev, "Failed to enable DCT: %d\n", ret); return ret; } @@ -428,7 +442,7 @@ int ivpu_pm_dct_disable(struct ivpu_device *vdev) ret = ivpu_jsm_dct_disable(vdev); if (ret) { - ivpu_err_ratelimited(vdev, "Filed to disable DCT: %d\n", ret); + ivpu_err_ratelimited(vdev, "Failed to disable DCT: %d\n", ret); return ret; } diff --git a/drivers/accel/ivpu/ivpu_sysfs.c b/drivers/accel/ivpu/ivpu_sysfs.c index 913669f1786e86..616477fc17fa07 100644 --- a/drivers/accel/ivpu/ivpu_sysfs.c +++ b/drivers/accel/ivpu/ivpu_sysfs.c @@ -6,6 +6,8 @@ #include #include +#include "ivpu_drv.h" +#include "ivpu_fw.h" #include "ivpu_hw.h" #include "ivpu_sysfs.h" @@ -39,8 +41,30 @@ npu_busy_time_us_show(struct device *dev, struct device_attribute *attr, char *b static DEVICE_ATTR_RO(npu_busy_time_us); +/** + * DOC: sched_mode + * + * The sched_mode is used to report current NPU scheduling mode. + * + * It returns following strings: + * - "HW" - Hardware Scheduler mode + * - "OS" - Operating System Scheduler mode + * + */ +static ssize_t +sched_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_device *drm = dev_get_drvdata(dev); + struct ivpu_device *vdev = to_ivpu_device(drm); + + return sysfs_emit(buf, "%s\n", vdev->fw->sched_mode ? "HW" : "OS"); +} + +static DEVICE_ATTR_RO(sched_mode); + static struct attribute *ivpu_dev_attrs[] = { &dev_attr_npu_busy_time_us.attr, + &dev_attr_sched_mode.attr, NULL, }; diff --git a/drivers/accel/ivpu/ivpu_trace.h b/drivers/accel/ivpu/ivpu_trace.h new file mode 100644 index 00000000000000..eb792038e7010c --- /dev/null +++ b/drivers/accel/ivpu/ivpu_trace.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2020-2024 Intel Corporation + */ + +#if !defined(__IVPU_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) +#define __IVPU_TRACE_H__ + +#include +#include "ivpu_drv.h" +#include "ivpu_job.h" +#include "vpu_jsm_api.h" +#include "ivpu_jsm_msg.h" +#include "ivpu_ipc.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM vpu +#define TRACE_INCLUDE_FILE ivpu_trace + +TRACE_EVENT(pm, + TP_PROTO(const char *event), + TP_ARGS(event), + TP_STRUCT__entry(__field(const char *, event)), + TP_fast_assign(__entry->event = event;), + TP_printk("%s", __entry->event) +); + +TRACE_EVENT(job, + TP_PROTO(const char *event, struct ivpu_job *job), + TP_ARGS(event, job), + TP_STRUCT__entry(__field(const char *, event) + __field(u32, ctx_id) + __field(u32, engine_id) + __field(u32, job_id) + ), + TP_fast_assign(__entry->event = event; + __entry->ctx_id = job->file_priv->ctx.id; + __entry->engine_id = job->engine_idx; + __entry->job_id = job->job_id;), + TP_printk("%s context:%d engine:%d job:%d", + __entry->event, + __entry->ctx_id, + __entry->engine_id, + __entry->job_id) +); + +TRACE_EVENT(jsm, + TP_PROTO(const char *event, struct vpu_jsm_msg *msg), + TP_ARGS(event, msg), + TP_STRUCT__entry(__field(const char *, event) + __field(const char *, type) + __field(enum vpu_ipc_msg_status, status) + __field(u32, request_id) + __field(u32, result) + ), + TP_fast_assign(__entry->event = event; + __entry->type = ivpu_jsm_msg_type_to_str(msg->type); + __entry->status = msg->status; + __entry->request_id = msg->request_id; + __entry->result = msg->result;), + TP_printk("%s type:%s, status:%#x, id:%#x, result:%#x", + __entry->event, + __entry->type, + __entry->status, + __entry->request_id, + __entry->result) +); + +#endif /* __IVPU_TRACE_H__ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include diff --git a/drivers/accel/ivpu/ivpu_trace_points.c b/drivers/accel/ivpu/ivpu_trace_points.c new file mode 100644 index 00000000000000..f8fb99de0de32a --- /dev/null +++ b/drivers/accel/ivpu/ivpu_trace_points.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2020-2024 Intel Corporation + */ + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "ivpu_trace.h" +#endif diff --git a/drivers/accel/ivpu/vpu_boot_api.h b/drivers/accel/ivpu/vpu_boot_api.h index 82954b91b7481c..908e68ea1c39c2 100644 --- a/drivers/accel/ivpu/vpu_boot_api.h +++ b/drivers/accel/ivpu/vpu_boot_api.h @@ -1,14 +1,13 @@ /* SPDX-License-Identifier: MIT */ /* - * Copyright (c) 2020-2023, Intel Corporation. + * Copyright (c) 2020-2024, Intel Corporation. */ #ifndef VPU_BOOT_API_H #define VPU_BOOT_API_H /* - * =========== FW API version information beginning ================ - * The bellow values will be used to construct the version info this way: + * The below values will be used to construct the version info this way: * fw_bin_header->api_version[VPU_BOOT_API_VER_ID] = (VPU_BOOT_API_VER_MAJOR << 16) | * VPU_BOOT_API_VER_MINOR; * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes @@ -27,19 +26,18 @@ * Minor version changes when API backward compatibility is preserved. * Resets to 0 if Major version is incremented. */ -#define VPU_BOOT_API_VER_MINOR 24 +#define VPU_BOOT_API_VER_MINOR 26 /* * API header changed (field names, documentation, formatting) but API itself has not been changed */ -#define VPU_BOOT_API_VER_PATCH 0 +#define VPU_BOOT_API_VER_PATCH 3 /* * Index in the API version table * Must be unique for each API */ #define VPU_BOOT_API_VER_INDEX 0 -/* ------------ FW API version information end ---------------------*/ #pragma pack(push, 4) @@ -164,8 +162,6 @@ enum vpu_trace_destination { /* VPU 30xx HW component IDs are sequential, so define first and last IDs. */ #define VPU_TRACE_PROC_BIT_30XX_FIRST VPU_TRACE_PROC_BIT_LRT #define VPU_TRACE_PROC_BIT_30XX_LAST VPU_TRACE_PROC_BIT_SHV_15 -#define VPU_TRACE_PROC_BIT_KMB_FIRST VPU_TRACE_PROC_BIT_30XX_FIRST -#define VPU_TRACE_PROC_BIT_KMB_LAST VPU_TRACE_PROC_BIT_30XX_LAST struct vpu_boot_l2_cache_config { u8 use; @@ -199,6 +195,17 @@ struct vpu_warm_boot_section { */ #define POWER_PROFILE_SURVIVABILITY 0x1 +/** + * Enum for dvfs_mode boot param. + */ +enum vpu_governor { + VPU_GOV_DEFAULT = 0, /* Default Governor for the system */ + VPU_GOV_MAX_PERFORMANCE = 1, /* Maximum performance governor */ + VPU_GOV_ON_DEMAND = 2, /* On Demand frequency control governor */ + VPU_GOV_POWER_SAVE = 3, /* Power save governor */ + VPU_GOV_ON_DEMAND_PRIORITY_AWARE = 4 /* On Demand priority based governor */ +}; + struct vpu_boot_params { u32 magic; u32 vpu_id; @@ -301,7 +308,14 @@ struct vpu_boot_params { u32 temp_sensor_period_ms; /** PLL ratio for efficient clock frequency */ u32 pn_freq_pll_ratio; - /** DVFS Mode: Default: 0, Max Performance: 1, On Demand: 2, Power Save: 3 */ + /** + * DVFS Mode: + * 0 - Default, DVFS mode selected by the firmware + * 1 - Max Performance + * 2 - On Demand + * 3 - Power Save + * 4 - On Demand Priority Aware + */ u32 dvfs_mode; /** * Depending on DVFS Mode: @@ -332,8 +346,8 @@ struct vpu_boot_params { u64 d0i3_entry_vpu_ts; /* * The system time of the host operating system in microseconds. - * E.g the number of microseconds since 1st of January 1970, or whatever date the - * host operating system uses to maintain system time. + * E.g the number of microseconds since 1st of January 1970, or whatever + * date the host operating system uses to maintain system time. * This value will be used to track system time on the VPU. * The KMD is required to update this value on every VPU reset. */ @@ -382,10 +396,7 @@ struct vpu_boot_params { u32 pad6[734]; }; -/* - * Magic numbers set between host and vpu to detect corruptio of tracing init - */ - +/* Magic numbers set between host and vpu to detect corruption of tracing init */ #define VPU_TRACING_BUFFER_CANARY (0xCAFECAFE) /* Tracing buffer message format definitions */ @@ -405,7 +416,9 @@ struct vpu_tracing_buffer_header { u32 host_canary_start; /* offset from start of buffer for trace entries */ u32 read_index; - u32 pad_to_cache_line_size_0[14]; + /* keeps track of wrapping on the reader side */ + u32 read_wrap_count; + u32 pad_to_cache_line_size_0[13]; /* End of first cache line */ /** diff --git a/drivers/accel/ivpu/vpu_jsm_api.h b/drivers/accel/ivpu/vpu_jsm_api.h index 33f462b1a25d88..7215c144158cbd 100644 --- a/drivers/accel/ivpu/vpu_jsm_api.h +++ b/drivers/accel/ivpu/vpu_jsm_api.h @@ -22,7 +22,7 @@ /* * Minor version changes when API backward compatibility is preserved. */ -#define VPU_JSM_API_VER_MINOR 16 +#define VPU_JSM_API_VER_MINOR 25 /* * API header changed (field names, documentation, formatting) but API itself has not been changed @@ -36,7 +36,7 @@ /* * Number of Priority Bands for Hardware Scheduling - * Bands: RealTime, Focus, Normal, Idle + * Bands: Idle(0), Normal(1), Focus(2), RealTime(3) */ #define VPU_HWS_NUM_PRIORITY_BANDS 4 @@ -74,6 +74,7 @@ #define VPU_JSM_STATUS_MVNCI_INTERNAL_ERROR 0xCU /* Job status returned when the job was preempted mid-inference */ #define VPU_JSM_STATUS_PREEMPTED_MID_INFERENCE 0xDU +#define VPU_JSM_STATUS_MVNCI_CONTEXT_VIOLATION_HW 0xEU /* * Host <-> VPU IPC channels. @@ -86,18 +87,58 @@ /* * Job flags bit masks. */ -#define VPU_JOB_FLAGS_NULL_SUBMISSION_MASK 0x00000001 -#define VPU_JOB_FLAGS_PRIVATE_DATA_MASK 0xFF000000 +enum { + /* + * Null submission mask. + * When set, batch buffer's commands are not processed but returned as + * successful immediately, except fences and timestamps. + * When cleared, batch buffer's commands are processed normally. + * Used for testing and profiling purposes. + */ + VPU_JOB_FLAGS_NULL_SUBMISSION_MASK = (1 << 0U), + /* + * Inline command mask. + * When set, the object in job queue is an inline command (see struct vpu_inline_cmd below). + * When cleared, the object in job queue is a job (see struct vpu_job_queue_entry below). + */ + VPU_JOB_FLAGS_INLINE_CMD_MASK = (1 << 1U), + /* + * VPU private data mask. + * Reserved for the VPU to store private data about the job (or inline command) + * while being processed. + */ + VPU_JOB_FLAGS_PRIVATE_DATA_MASK = 0xFFFF0000U +}; /* - * Sizes of the reserved areas in jobs, in bytes. + * Job queue flags bit masks. */ -#define VPU_JOB_RESERVED_BYTES 8 +enum { + /* + * No job done notification mask. + * When set, indicates that no job done notification should be sent for any + * job from this queue. When cleared, indicates that job done notification + * should be sent for every job completed from this queue. + */ + VPU_JOB_QUEUE_FLAGS_NO_JOB_DONE_MASK = (1 << 0U), + /* + * Native fence usage mask. + * When set, indicates that job queue uses native fences (as inline commands + * in job queue). Such queues may also use legacy fences (as commands in batch buffers). + * When cleared, indicates the job queue only uses legacy fences. + * NOTE: For queues using native fences, VPU expects that all jobs in the queue + * are immediately followed by an inline command object. This object is expected + * to be a fence signal command in most cases, but can also be a NOP in case the host + * does not need per-job fence signalling. Other inline commands objects can be + * inserted between "job and inline command" pairs. + */ + VPU_JOB_QUEUE_FLAGS_USE_NATIVE_FENCE_MASK = (1 << 1U), -/* - * Sizes of the reserved areas in job queues, in bytes. - */ -#define VPU_JOB_QUEUE_RESERVED_BYTES 52 + /* + * Enable turbo mode for testing NPU performance; not recommended for regular usage. + */ + VPU_JOB_QUEUE_FLAGS_TURBO_MODE = (1 << 2U) +}; /* * Max length (including trailing NULL char) of trace entity name (e.g., the @@ -140,24 +181,113 @@ */ #define VPU_HWS_INVALID_CMDQ_HANDLE 0ULL +/* + * Inline commands types. + */ +/* + * NOP. + * VPU does nothing other than consuming the inline command object. + */ +#define VPU_INLINE_CMD_TYPE_NOP 0x0 +/* + * Fence wait. + * VPU waits for the fence current value to reach monitored value. + * Fence wait operations are executed upon job dispatching. While waiting for + * the fence to be satisfied, VPU blocks fetching of the next objects in the queue. + * Jobs present in the queue prior to the fence wait object may be processed + * concurrently. + */ +#define VPU_INLINE_CMD_TYPE_FENCE_WAIT 0x1 +/* + * Fence signal. + * VPU sets the fence current value to the provided value. If new current value + * is equal to or higher than monitored value, VPU sends fence signalled notification + * to the host. Fence signal operations are executed upon completion of all the jobs + * present in the queue prior to them, and in-order relative to each other in the queue. + * But jobs in-between them may be processed concurrently and may complete out-of-order. + */ +#define VPU_INLINE_CMD_TYPE_FENCE_SIGNAL 0x2 + +/* + * Job scheduling priority bands for both hardware scheduling and OS scheduling. + */ +enum vpu_job_scheduling_priority_band { + VPU_JOB_SCHEDULING_PRIORITY_BAND_IDLE = 0, + VPU_JOB_SCHEDULING_PRIORITY_BAND_NORMAL = 1, + VPU_JOB_SCHEDULING_PRIORITY_BAND_FOCUS = 2, + VPU_JOB_SCHEDULING_PRIORITY_BAND_REALTIME = 3, + VPU_JOB_SCHEDULING_PRIORITY_BAND_COUNT = 4, +}; + /* * Job format. + * Jobs defines the actual workloads to be executed by a given engine. */ struct vpu_job_queue_entry { - u64 batch_buf_addr; /**< Address of VPU commands batch buffer */ - u32 job_id; /**< Job ID */ - u32 flags; /**< Flags bit field, see VPU_JOB_FLAGS_* above */ - u64 root_page_table_addr; /**< Address of root page table to use for this job */ - u64 root_page_table_update_counter; /**< Page tables update events counter */ - u64 primary_preempt_buf_addr; + /**< Address of VPU commands batch buffer */ + u64 batch_buf_addr; + /**< Job ID */ + u32 job_id; + /**< Flags bit field, see VPU_JOB_FLAGS_* above */ + u32 flags; + /** + * Doorbell ring timestamp taken by KMD from SoC's global system clock, in + * microseconds. NPU can convert this value to its own fixed clock's timebase, + * to match other profiling timestamps. + */ + u64 doorbell_timestamp; + /**< Extra id for job tracking, used only in the firmware perf traces */ + u64 host_tracking_id; /**< Address of the primary preemption buffer to use for this job */ - u32 primary_preempt_buf_size; + u64 primary_preempt_buf_addr; /**< Size of the primary preemption buffer to use for this job */ - u32 secondary_preempt_buf_size; + u32 primary_preempt_buf_size; /**< Size of secondary preemption buffer to use for this job */ - u64 secondary_preempt_buf_addr; + u32 secondary_preempt_buf_size; /**< Address of secondary preemption buffer to use for this job */ - u8 reserved_0[VPU_JOB_RESERVED_BYTES]; + u64 secondary_preempt_buf_addr; + u64 reserved_0; +}; + +/* + * Inline command format. + * Inline commands are the commands executed at scheduler level (typically, + * synchronization directives). Inline command and job objects must be of + * the same size and have flags field at same offset. + */ +struct vpu_inline_cmd { + u64 reserved_0; + /* Inline command type, see VPU_INLINE_CMD_TYPE_* defines. */ + u32 type; + /* Flags bit field, see VPU_JOB_FLAGS_* above. */ + u32 flags; + /* Inline command payload. Depends on inline command type. */ + union { + /* Fence (wait and signal) commands' payload. */ + struct { + /* Fence object handle. */ + u64 fence_handle; + /* User VA of the current fence value. */ + u64 current_value_va; + /* User VA of the monitored fence value (read-only). */ + u64 monitored_value_va; + /* Value to wait for or write in fence location. */ + u64 value; + /* User VA of the log buffer in which to add log entry on completion. */ + u64 log_buffer_va; + } fence; + /* Other commands do not have a payload. */ + /* Payload definition for future inline commands can be inserted here. */ + u64 reserved_1[6]; + } payload; +}; + +/* + * Job queue slots can be populated either with job objects or inline command objects. + */ +union vpu_jobq_slot { + struct vpu_job_queue_entry job; + struct vpu_inline_cmd inline_cmd; }; /* @@ -167,7 +297,21 @@ struct vpu_job_queue_header { u32 engine_idx; u32 head; u32 tail; - u8 reserved_0[VPU_JOB_QUEUE_RESERVED_BYTES]; + u32 flags; + /* Set to 1 to indicate priority_band field is valid */ + u32 priority_band_valid; + /* + * Priority for the work of this job queue, valid only if the HWS is NOT used + * and the `priority_band_valid` is set to 1. It is applied only during + * the VPU_JSM_MSG_REGISTER_DB message processing. + * The device firmware might use the `priority_band` to optimize the power + * management logic, but it will not affect the order of jobs. + * Available priority bands: @see enum vpu_job_scheduling_priority_band + */ + u32 priority_band; + /* Inside realtime band assigns a further priority, limited to 0..31 range */ + u32 realtime_priority_level; + u32 reserved_0[9]; }; /* @@ -175,7 +319,7 @@ struct vpu_job_queue_header { */ struct vpu_job_queue { struct vpu_job_queue_header header; - struct vpu_job_queue_entry job[]; + union vpu_jobq_slot slot[]; }; /** @@ -197,9 +341,7 @@ enum vpu_trace_entity_type { struct vpu_hws_log_buffer_header { /* Written by VPU after adding a log entry. Initialised by host to 0. */ u32 first_free_entry_index; - /* Incremented by VPU every time the VPU overwrites the 0th entry; - * initialised by host to 0. - */ + /* Incremented by VPU every time the VPU writes the 0th entry; initialised by host to 0. */ u32 wraparound_count; /* * This is the number of buffers that can be stored in the log buffer provided by the host. @@ -230,14 +372,80 @@ struct vpu_hws_log_buffer_entry { u64 operation_data[2]; }; +/* Native fence log buffer types. */ +enum vpu_hws_native_fence_log_type { + VPU_HWS_NATIVE_FENCE_LOG_TYPE_WAITS = 1, + VPU_HWS_NATIVE_FENCE_LOG_TYPE_SIGNALS = 2 +}; + +/* HWS native fence log buffer header. */ +struct vpu_hws_native_fence_log_header { + union { + struct { + /* Index of the first free entry in buffer. */ + u32 first_free_entry_idx; + /* Incremented each time NPU wraps around the buffer to write next entry. */ + u32 wraparound_count; + }; + /* Field allowing atomic update of both fields above. */ + u64 atomic_wraparound_and_entry_idx; + }; + /* Log buffer type, see enum vpu_hws_native_fence_log_type. */ + u64 type; + /* Allocated number of entries in the log buffer. */ + u64 entry_nb; + u64 reserved[2]; +}; + +/* Native fence log operation types. */ +enum vpu_hws_native_fence_log_op { + VPU_HWS_NATIVE_FENCE_LOG_OP_SIGNAL_EXECUTED = 0, + VPU_HWS_NATIVE_FENCE_LOG_OP_WAIT_UNBLOCKED = 1 +}; + +/* HWS native fence log entry. */ +struct vpu_hws_native_fence_log_entry { + /* Newly signaled/unblocked fence value. */ + u64 fence_value; + /* Native fence object handle to which this operation belongs. */ + u64 fence_handle; + /* Operation type, see enum vpu_hws_native_fence_log_op. */ + u64 op_type; + u64 reserved_0; + /* + * VPU_HWS_NATIVE_FENCE_LOG_OP_WAIT_UNBLOCKED only: Timestamp at which fence + * wait was started (in NPU SysTime). + */ + u64 fence_wait_start_ts; + u64 reserved_1; + /* Timestamp at which fence operation was completed (in NPU SysTime). */ + u64 fence_end_ts; +}; + +/* Native fence log buffer. */ +struct vpu_hws_native_fence_log_buffer { + struct vpu_hws_native_fence_log_header header; + struct vpu_hws_native_fence_log_entry entry[]; +}; + /* * Host <-> VPU IPC messages types. */ enum vpu_ipc_msg_type { VPU_JSM_MSG_UNKNOWN = 0xFFFFFFFF, + /* IPC Host -> Device, Async commands */ VPU_JSM_MSG_ASYNC_CMD = 0x1100, VPU_JSM_MSG_ENGINE_RESET = VPU_JSM_MSG_ASYNC_CMD, + /** + * Preempt engine. The NPU stops (preempts) all the jobs currently + * executing on the target engine making the engine become idle and ready to + * execute new jobs. + * NOTE: The NPU does not remove unstarted jobs (if any) from job queues of + * the target engine, but it stops processing them (until the queue doorbell + * is rung again); the host is responsible to reset the job queue, either + * after preemption or when resubmitting jobs to the queue. + */ VPU_JSM_MSG_ENGINE_PREEMPT = 0x1101, VPU_JSM_MSG_REGISTER_DB = 0x1102, VPU_JSM_MSG_UNREGISTER_DB = 0x1103, @@ -323,9 +531,10 @@ enum vpu_ipc_msg_type { * NOTE: Please introduce new ASYNC commands before this one. * */ VPU_JSM_MSG_STATE_DUMP = 0x11FF, + /* IPC Host -> Device, General commands */ VPU_JSM_MSG_GENERAL_CMD = 0x1200, - VPU_JSM_MSG_BLOB_DEINIT = VPU_JSM_MSG_GENERAL_CMD, + VPU_JSM_MSG_BLOB_DEINIT_DEPRECATED = VPU_JSM_MSG_GENERAL_CMD, /** * Control dyndbg behavior by executing a dyndbg command; equivalent to * Linux command: `echo '' > /dynamic_debug/control`. @@ -335,8 +544,12 @@ enum vpu_ipc_msg_type { * Perform the save procedure for the D0i3 entry */ VPU_JSM_MSG_PWR_D0I3_ENTER = 0x1202, + /* IPC Device -> Host, Job completion */ VPU_JSM_MSG_JOB_DONE = 0x2100, + /* IPC Device -> Host, Fence signalled */ + VPU_JSM_MSG_NATIVE_FENCE_SIGNALLED = 0x2101, + /* IPC Device -> Host, Async command completion */ VPU_JSM_MSG_ASYNC_CMD_DONE = 0x2200, VPU_JSM_MSG_ENGINE_RESET_DONE = VPU_JSM_MSG_ASYNC_CMD_DONE, @@ -422,6 +635,7 @@ enum vpu_ipc_msg_type { * NOTE: Please introduce new ASYNC responses before this one. * */ VPU_JSM_MSG_STATE_DUMP_RSP = 0x22FF, + /* IPC Device -> Host, General command completion */ VPU_JSM_MSG_GENERAL_CMD_DONE = 0x2300, VPU_JSM_MSG_BLOB_DEINIT_DONE = VPU_JSM_MSG_GENERAL_CMD_DONE, @@ -600,11 +814,6 @@ struct vpu_jsm_metric_streamer_update { u64 next_buffer_size; }; -struct vpu_ipc_msg_payload_blob_deinit { - /* 64-bit unique ID for the blob to be de-initialized. */ - u64 blob_id; -}; - struct vpu_ipc_msg_payload_job_done { /* Engine to which the job was submitted. */ u32 engine_idx; @@ -622,6 +831,21 @@ struct vpu_ipc_msg_payload_job_done { u64 cmdq_id; }; +/* + * Notification message upon native fence signalling. + * @see VPU_JSM_MSG_NATIVE_FENCE_SIGNALLED + */ +struct vpu_ipc_msg_payload_native_fence_signalled { + /* Engine ID. */ + u32 engine_idx; + /* Host SSID. */ + u32 host_ssid; + /* CMDQ ID */ + u64 cmdq_id; + /* Fence object handle. */ + u64 fence_handle; +}; + struct vpu_jsm_engine_reset_context { /* Host SSID */ u32 host_ssid; @@ -700,11 +924,6 @@ struct vpu_ipc_msg_payload_get_power_level_count_done { u8 power_limit[16]; }; -struct vpu_ipc_msg_payload_blob_deinit_done { - /* 64-bit unique ID for the blob de-initialized. */ - u64 blob_id; -}; - /* HWS priority band setup request / response */ struct vpu_ipc_msg_payload_hws_priority_band_setup { /* @@ -794,7 +1013,10 @@ struct vpu_ipc_msg_payload_hws_set_context_sched_properties { u32 reserved_0; /* Command queue id */ u64 cmdq_id; - /* Priority band to assign to work of this context */ + /* + * Priority band to assign to work of this context. + * Available priority bands: @see enum vpu_job_scheduling_priority_band + */ u32 priority_band; /* Inside realtime band assigns a further priority */ u32 realtime_priority_level; @@ -869,9 +1091,7 @@ struct vpu_ipc_msg_payload_hws_set_scheduling_log { */ u64 notify_index; /* - * Enable extra events to be output to log for debug of scheduling algorithm. - * Interpreted by VPU as a boolean to enable or disable, expected values are - * 0 and 1. + * Field is now deprecated, will be removed when KMD is updated to support removal */ u32 enable_extra_events; /* Zero Padding */ @@ -1243,10 +1463,10 @@ union vpu_ipc_msg_payload { struct vpu_jsm_metric_streamer_start metric_streamer_start; struct vpu_jsm_metric_streamer_stop metric_streamer_stop; struct vpu_jsm_metric_streamer_update metric_streamer_update; - struct vpu_ipc_msg_payload_blob_deinit blob_deinit; struct vpu_ipc_msg_payload_ssid_release ssid_release; struct vpu_jsm_hws_register_db hws_register_db; struct vpu_ipc_msg_payload_job_done job_done; + struct vpu_ipc_msg_payload_native_fence_signalled native_fence_signalled; struct vpu_ipc_msg_payload_engine_reset_done engine_reset_done; struct vpu_ipc_msg_payload_engine_preempt_done engine_preempt_done; struct vpu_ipc_msg_payload_register_db_done register_db_done; @@ -1254,7 +1474,6 @@ union vpu_ipc_msg_payload { struct vpu_ipc_msg_payload_query_engine_hb_done query_engine_hb_done; struct vpu_ipc_msg_payload_get_power_level_count_done get_power_level_count_done; struct vpu_jsm_metric_streamer_done metric_streamer_done; - struct vpu_ipc_msg_payload_blob_deinit_done blob_deinit_done; struct vpu_ipc_msg_payload_trace_config trace_config; struct vpu_ipc_msg_payload_trace_capability_rsp trace_capability; struct vpu_ipc_msg_payload_trace_get_name trace_get_name; diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index ada9b1eb0787e3..8ab82e78dd9448 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -405,6 +405,38 @@ static const struct mhi_channel_config aic100_channels[] = { .auto_queue = false, .wake_capable = false, }, + { + .name = "IPCR", + .num = 24, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "IPCR", + .num = 25, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = true, + .wake_capable = false, + }, }; static struct mhi_event_config aic100_events[] = { diff --git a/drivers/accel/qaic/qaic_debugfs.c b/drivers/accel/qaic/qaic_debugfs.c index 20b653d99e524a..ba0cf2f94732cc 100644 --- a/drivers/accel/qaic/qaic_debugfs.c +++ b/drivers/accel/qaic/qaic_debugfs.c @@ -64,20 +64,9 @@ static int bootlog_show(struct seq_file *s, void *unused) return 0; } -static int bootlog_fops_open(struct inode *inode, struct file *file) -{ - return single_open(file, bootlog_show, inode->i_private); -} - -static const struct file_operations bootlog_fops = { - .owner = THIS_MODULE, - .open = bootlog_fops_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(bootlog); -static int read_dbc_fifo_size(struct seq_file *s, void *unused) +static int fifo_size_show(struct seq_file *s, void *unused) { struct dma_bridge_chan *dbc = s->private; @@ -85,20 +74,9 @@ static int read_dbc_fifo_size(struct seq_file *s, void *unused) return 0; } -static int fifo_size_open(struct inode *inode, struct file *file) -{ - return single_open(file, read_dbc_fifo_size, inode->i_private); -} - -static const struct file_operations fifo_size_fops = { - .owner = THIS_MODULE, - .open = fifo_size_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(fifo_size); -static int read_dbc_queued(struct seq_file *s, void *unused) +static int queued_show(struct seq_file *s, void *unused) { struct dma_bridge_chan *dbc = s->private; u32 tail = 0, head = 0; @@ -115,18 +93,7 @@ static int read_dbc_queued(struct seq_file *s, void *unused) return 0; } -static int queued_open(struct inode *inode, struct file *file) -{ - return single_open(file, read_dbc_queued, inode->i_private); -} - -static const struct file_operations queued_fops = { - .owner = THIS_MODULE, - .open = queued_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(queued); void qaic_debugfs_init(struct qaic_drm_device *qddev) { diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index bf10156c334e71..4ddf89308ff5a4 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -32,8 +32,9 @@ #include "qaic_timesync.h" #include "sahara.h" -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); +#define PCI_DEV_AIC080 0xa080 #define PCI_DEV_AIC100 0xa100 #define QAIC_NAME "qaic" #define QAIC_DESC "Qualcomm Cloud AI Accelerators" @@ -53,12 +54,12 @@ static void qaicm_wq_release(struct drm_device *dev, void *res) destroy_workqueue(wq); } -static struct workqueue_struct *qaicm_wq_init(struct drm_device *dev, const char *fmt) +static struct workqueue_struct *qaicm_wq_init(struct drm_device *dev, const char *name) { struct workqueue_struct *wq; int ret; - wq = alloc_workqueue(fmt, WQ_UNBOUND, 0); + wq = alloc_workqueue("%s", WQ_UNBOUND, 0, name); if (!wq) return ERR_PTR(-ENOMEM); ret = drmm_add_action_or_reset(dev, qaicm_wq_release, wq); @@ -365,7 +366,7 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de return NULL; qdev->dev_state = QAIC_OFFLINE; - if (id->device == PCI_DEV_AIC100) { + if (id->device == PCI_DEV_AIC080 || id->device == PCI_DEV_AIC100) { qdev->num_dbc = 16; qdev->dbc = devm_kcalloc(dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); if (!qdev->dbc) @@ -607,6 +608,7 @@ static struct mhi_driver qaic_mhi_driver = { }; static const struct pci_device_id qaic_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, PCI_DEV_AIC080), }, { PCI_DEVICE(PCI_VENDOR_ID_QCOM, PCI_DEV_AIC100), }, { } }; diff --git a/drivers/accel/qaic/sahara.c b/drivers/accel/qaic/sahara.c index bf94bbab6be5a1..6d772143d61256 100644 --- a/drivers/accel/qaic/sahara.c +++ b/drivers/accel/qaic/sahara.c @@ -2,6 +2,7 @@ /* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include #include #include #include @@ -9,6 +10,7 @@ #include #include #include +#include #include #include "sahara.h" @@ -36,12 +38,14 @@ #define SAHARA_PACKET_MAX_SIZE 0xffffU /* MHI_MAX_MTU */ #define SAHARA_TRANSFER_MAX_SIZE 0x80000 +#define SAHARA_READ_MAX_SIZE 0xfff0U /* Avoid unaligned requests */ #define SAHARA_NUM_TX_BUF DIV_ROUND_UP(SAHARA_TRANSFER_MAX_SIZE,\ SAHARA_PACKET_MAX_SIZE) #define SAHARA_IMAGE_ID_NONE U32_MAX #define SAHARA_VERSION 2 #define SAHARA_SUCCESS 0 +#define SAHARA_TABLE_ENTRY_STR_LEN 20 #define SAHARA_MODE_IMAGE_TX_PENDING 0x0 #define SAHARA_MODE_IMAGE_TX_COMPLETE 0x1 @@ -53,6 +57,8 @@ #define SAHARA_END_OF_IMAGE_LENGTH 0x10 #define SAHARA_DONE_LENGTH 0x8 #define SAHARA_RESET_LENGTH 0x8 +#define SAHARA_MEM_DEBUG64_LENGTH 0x18 +#define SAHARA_MEM_READ64_LENGTH 0x18 struct sahara_packet { __le32 cmd; @@ -80,18 +86,95 @@ struct sahara_packet { __le32 image; __le32 status; } end_of_image; + struct { + __le64 table_address; + __le64 table_length; + } memory_debug64; + struct { + __le64 memory_address; + __le64 memory_length; + } memory_read64; }; }; +struct sahara_debug_table_entry64 { + __le64 type; + __le64 address; + __le64 length; + char description[SAHARA_TABLE_ENTRY_STR_LEN]; + char filename[SAHARA_TABLE_ENTRY_STR_LEN]; +}; + +struct sahara_dump_table_entry { + u64 type; + u64 address; + u64 length; + char description[SAHARA_TABLE_ENTRY_STR_LEN]; + char filename[SAHARA_TABLE_ENTRY_STR_LEN]; +}; + +#define SAHARA_DUMP_V1_MAGIC 0x1234567890abcdef +#define SAHARA_DUMP_V1_VER 1 +struct sahara_memory_dump_meta_v1 { + u64 magic; + u64 version; + u64 dump_size; + u64 table_size; +}; + +/* + * Layout of crashdump provided to user via devcoredump + * +------------------------------------------+ + * | Crashdump Meta structure | + * | type: struct sahara_memory_dump_meta_v1 | + * +------------------------------------------+ + * | Crashdump Table | + * | type: array of struct | + * | sahara_dump_table_entry | + * | | + * | | + * +------------------------------------------+ + * | Crashdump | + * | | + * | | + * | | + * | | + * | | + * +------------------------------------------+ + * + * First is the metadata header. Userspace can use the magic number to verify + * the content type, and then check the version for the rest of the format. + * New versions should keep the magic number location/value, and version + * location, but increment the version value. + * + * For v1, the metadata lists the size of the entire dump (header + table + + * dump) and the size of the table. Then the dump image table, which describes + * the contents of the dump. Finally all the images are listed in order, with + * no deadspace in between. Userspace can use the sizes listed in the image + * table to reconstruct the individual images. + */ + struct sahara_context { struct sahara_packet *tx[SAHARA_NUM_TX_BUF]; struct sahara_packet *rx; - struct work_struct work; + struct work_struct fw_work; + struct work_struct dump_work; struct mhi_device *mhi_dev; const char **image_table; u32 table_size; u32 active_image_id; const struct firmware *firmware; + u64 dump_table_address; + u64 dump_table_length; + size_t rx_size; + size_t rx_size_requested; + void *mem_dump; + size_t mem_dump_sz; + struct sahara_dump_table_entry *dump_image; + u64 dump_image_offset; + void *mem_dump_freespace; + u64 dump_images_left; + bool is_mem_dump_mode; }; static const char *aic100_image_table[] = { @@ -153,6 +236,8 @@ static void sahara_send_reset(struct sahara_context *context) { int ret; + context->is_mem_dump_mode = false; + context->tx[0]->cmd = cpu_to_le32(SAHARA_RESET_CMD); context->tx[0]->length = cpu_to_le32(SAHARA_RESET_LENGTH); @@ -186,7 +271,8 @@ static void sahara_hello(struct sahara_context *context) } if (le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_IMAGE_TX_PENDING && - le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_IMAGE_TX_COMPLETE) { + le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_IMAGE_TX_COMPLETE && + le32_to_cpu(context->rx->hello.mode) != SAHARA_MODE_MEMORY_DEBUG) { dev_err(&context->mhi_dev->dev, "Unsupported hello packet - mode %d\n", le32_to_cpu(context->rx->hello.mode)); return; @@ -320,9 +406,70 @@ static void sahara_end_of_image(struct sahara_context *context) dev_dbg(&context->mhi_dev->dev, "Unable to send done response %d\n", ret); } +static void sahara_memory_debug64(struct sahara_context *context) +{ + int ret; + + dev_dbg(&context->mhi_dev->dev, + "MEMORY DEBUG64 cmd received. length:%d table_address:%#llx table_length:%#llx\n", + le32_to_cpu(context->rx->length), + le64_to_cpu(context->rx->memory_debug64.table_address), + le64_to_cpu(context->rx->memory_debug64.table_length)); + + if (le32_to_cpu(context->rx->length) != SAHARA_MEM_DEBUG64_LENGTH) { + dev_err(&context->mhi_dev->dev, "Malformed memory debug64 packet - length %d\n", + le32_to_cpu(context->rx->length)); + return; + } + + context->dump_table_address = le64_to_cpu(context->rx->memory_debug64.table_address); + context->dump_table_length = le64_to_cpu(context->rx->memory_debug64.table_length); + + if (context->dump_table_length % sizeof(struct sahara_debug_table_entry64) != 0 || + !context->dump_table_length) { + dev_err(&context->mhi_dev->dev, "Malformed memory debug64 packet - table length %lld\n", + context->dump_table_length); + return; + } + + /* + * From this point, the protocol flips. We make memory_read requests to + * the device, and the device responds with the raw data. If the device + * has an error, it will send an End of Image command. First we need to + * request the memory dump table so that we know where all the pieces + * of the dump are that we can consume. + */ + + context->is_mem_dump_mode = true; + + /* + * Assume that the table is smaller than our MTU so that we can read it + * in one shot. The spec does not put an upper limit on the table, but + * no known device will exceed this. + */ + if (context->dump_table_length > SAHARA_PACKET_MAX_SIZE) { + dev_err(&context->mhi_dev->dev, "Memory dump table length %lld exceeds supported size. Discarding dump\n", + context->dump_table_length); + sahara_send_reset(context); + return; + } + + context->tx[0]->cmd = cpu_to_le32(SAHARA_MEM_READ64_CMD); + context->tx[0]->length = cpu_to_le32(SAHARA_MEM_READ64_LENGTH); + context->tx[0]->memory_read64.memory_address = cpu_to_le64(context->dump_table_address); + context->tx[0]->memory_read64.memory_length = cpu_to_le64(context->dump_table_length); + + context->rx_size_requested = context->dump_table_length; + + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], + SAHARA_MEM_READ64_LENGTH, MHI_EOT); + if (ret) + dev_err(&context->mhi_dev->dev, "Unable to send read for dump table %d\n", ret); +} + static void sahara_processing(struct work_struct *work) { - struct sahara_context *context = container_of(work, struct sahara_context, work); + struct sahara_context *context = container_of(work, struct sahara_context, fw_work); int ret; switch (le32_to_cpu(context->rx->cmd)) { @@ -338,6 +485,12 @@ static void sahara_processing(struct work_struct *work) case SAHARA_DONE_RESP_CMD: /* Intentional do nothing as we don't need to exit an app */ break; + case SAHARA_RESET_RESP_CMD: + /* Intentional do nothing as we don't need to exit an app */ + break; + case SAHARA_MEM_DEBUG64_CMD: + sahara_memory_debug64(context); + break; default: dev_err(&context->mhi_dev->dev, "Unknown command %d\n", le32_to_cpu(context->rx->cmd)); @@ -350,6 +503,217 @@ static void sahara_processing(struct work_struct *work) dev_err(&context->mhi_dev->dev, "Unable to requeue rx buf %d\n", ret); } +static void sahara_parse_dump_table(struct sahara_context *context) +{ + struct sahara_dump_table_entry *image_out_table; + struct sahara_debug_table_entry64 *dev_table; + struct sahara_memory_dump_meta_v1 *dump_meta; + u64 table_nents; + u64 dump_length; + int ret; + u64 i; + + table_nents = context->dump_table_length / sizeof(*dev_table); + context->dump_images_left = table_nents; + dump_length = 0; + + dev_table = (struct sahara_debug_table_entry64 *)(context->rx); + for (i = 0; i < table_nents; ++i) { + /* Do not trust the device, ensure the strings are terminated */ + dev_table[i].description[SAHARA_TABLE_ENTRY_STR_LEN - 1] = 0; + dev_table[i].filename[SAHARA_TABLE_ENTRY_STR_LEN - 1] = 0; + + dump_length = size_add(dump_length, le64_to_cpu(dev_table[i].length)); + if (dump_length == SIZE_MAX) { + /* Discard the dump */ + sahara_send_reset(context); + return; + } + + dev_dbg(&context->mhi_dev->dev, + "Memory dump table entry %lld type: %lld address: %#llx length: %#llx description: \"%s\" filename \"%s\"\n", + i, + le64_to_cpu(dev_table[i].type), + le64_to_cpu(dev_table[i].address), + le64_to_cpu(dev_table[i].length), + dev_table[i].description, + dev_table[i].filename); + } + + dump_length = size_add(dump_length, sizeof(*dump_meta)); + if (dump_length == SIZE_MAX) { + /* Discard the dump */ + sahara_send_reset(context); + return; + } + dump_length = size_add(dump_length, size_mul(sizeof(*image_out_table), table_nents)); + if (dump_length == SIZE_MAX) { + /* Discard the dump */ + sahara_send_reset(context); + return; + } + + context->mem_dump_sz = dump_length; + context->mem_dump = vzalloc(dump_length); + if (!context->mem_dump) { + /* Discard the dump */ + sahara_send_reset(context); + return; + } + + /* Populate the dump metadata and table for userspace */ + dump_meta = context->mem_dump; + dump_meta->magic = SAHARA_DUMP_V1_MAGIC; + dump_meta->version = SAHARA_DUMP_V1_VER; + dump_meta->dump_size = dump_length; + dump_meta->table_size = context->dump_table_length; + + image_out_table = context->mem_dump + sizeof(*dump_meta); + for (i = 0; i < table_nents; ++i) { + image_out_table[i].type = le64_to_cpu(dev_table[i].type); + image_out_table[i].address = le64_to_cpu(dev_table[i].address); + image_out_table[i].length = le64_to_cpu(dev_table[i].length); + strscpy(image_out_table[i].description, dev_table[i].description, + SAHARA_TABLE_ENTRY_STR_LEN); + strscpy(image_out_table[i].filename, + dev_table[i].filename, + SAHARA_TABLE_ENTRY_STR_LEN); + } + + context->mem_dump_freespace = &image_out_table[i]; + + /* Done parsing the table, switch to image dump mode */ + context->dump_table_length = 0; + + /* Request the first chunk of the first image */ + context->dump_image = &image_out_table[0]; + dump_length = min(context->dump_image->length, SAHARA_READ_MAX_SIZE); + /* Avoid requesting EOI sized data so that we can identify errors */ + if (dump_length == SAHARA_END_OF_IMAGE_LENGTH) + dump_length = SAHARA_END_OF_IMAGE_LENGTH / 2; + + context->dump_image_offset = dump_length; + + context->tx[0]->cmd = cpu_to_le32(SAHARA_MEM_READ64_CMD); + context->tx[0]->length = cpu_to_le32(SAHARA_MEM_READ64_LENGTH); + context->tx[0]->memory_read64.memory_address = cpu_to_le64(context->dump_image->address); + context->tx[0]->memory_read64.memory_length = cpu_to_le64(dump_length); + + context->rx_size_requested = dump_length; + + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], + SAHARA_MEM_READ64_LENGTH, MHI_EOT); + if (ret) + dev_err(&context->mhi_dev->dev, "Unable to send read for dump content %d\n", ret); +} + +static void sahara_parse_dump_image(struct sahara_context *context) +{ + u64 dump_length; + int ret; + + memcpy(context->mem_dump_freespace, context->rx, context->rx_size); + context->mem_dump_freespace += context->rx_size; + + if (context->dump_image_offset >= context->dump_image->length) { + /* Need to move to next image */ + context->dump_image++; + context->dump_images_left--; + context->dump_image_offset = 0; + + if (!context->dump_images_left) { + /* Dump done */ + dev_coredumpv(context->mhi_dev->mhi_cntrl->cntrl_dev, + context->mem_dump, + context->mem_dump_sz, + GFP_KERNEL); + context->mem_dump = NULL; + sahara_send_reset(context); + return; + } + } + + /* Get next image chunk */ + dump_length = context->dump_image->length - context->dump_image_offset; + dump_length = min(dump_length, SAHARA_READ_MAX_SIZE); + /* Avoid requesting EOI sized data so that we can identify errors */ + if (dump_length == SAHARA_END_OF_IMAGE_LENGTH) + dump_length = SAHARA_END_OF_IMAGE_LENGTH / 2; + + context->tx[0]->cmd = cpu_to_le32(SAHARA_MEM_READ64_CMD); + context->tx[0]->length = cpu_to_le32(SAHARA_MEM_READ64_LENGTH); + context->tx[0]->memory_read64.memory_address = + cpu_to_le64(context->dump_image->address + context->dump_image_offset); + context->tx[0]->memory_read64.memory_length = cpu_to_le64(dump_length); + + context->dump_image_offset += dump_length; + context->rx_size_requested = dump_length; + + ret = mhi_queue_buf(context->mhi_dev, DMA_TO_DEVICE, context->tx[0], + SAHARA_MEM_READ64_LENGTH, MHI_EOT); + if (ret) + dev_err(&context->mhi_dev->dev, + "Unable to send read for dump content %d\n", ret); +} + +static void sahara_dump_processing(struct work_struct *work) +{ + struct sahara_context *context = container_of(work, struct sahara_context, dump_work); + int ret; + + /* + * We should get the expected raw data, but if the device has an error + * it is supposed to send EOI with an error code. + */ + if (context->rx_size != context->rx_size_requested && + context->rx_size != SAHARA_END_OF_IMAGE_LENGTH) { + dev_err(&context->mhi_dev->dev, + "Unexpected response to read_data. Expected size: %#zx got: %#zx\n", + context->rx_size_requested, + context->rx_size); + goto error; + } + + if (context->rx_size == SAHARA_END_OF_IMAGE_LENGTH && + le32_to_cpu(context->rx->cmd) == SAHARA_END_OF_IMAGE_CMD) { + dev_err(&context->mhi_dev->dev, + "Unexpected EOI response to read_data. Status: %d\n", + le32_to_cpu(context->rx->end_of_image.status)); + goto error; + } + + if (context->rx_size == SAHARA_END_OF_IMAGE_LENGTH && + le32_to_cpu(context->rx->cmd) != SAHARA_END_OF_IMAGE_CMD) { + dev_err(&context->mhi_dev->dev, + "Invalid EOI response to read_data. CMD: %d\n", + le32_to_cpu(context->rx->cmd)); + goto error; + } + + /* + * Need to know if we received the dump table, or part of a dump image. + * Since we get raw data, we cannot tell from the data itself. Instead, + * we use the stored dump_table_length, which we zero after we read and + * process the entire table. + */ + if (context->dump_table_length) + sahara_parse_dump_table(context); + else + sahara_parse_dump_image(context); + + ret = mhi_queue_buf(context->mhi_dev, DMA_FROM_DEVICE, context->rx, + SAHARA_PACKET_MAX_SIZE, MHI_EOT); + if (ret) + dev_err(&context->mhi_dev->dev, "Unable to requeue rx buf %d\n", ret); + + return; + +error: + vfree(context->mem_dump); + context->mem_dump = NULL; + sahara_send_reset(context); +} + static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) { struct sahara_context *context; @@ -382,7 +746,8 @@ static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_ } context->mhi_dev = mhi_dev; - INIT_WORK(&context->work, sahara_processing); + INIT_WORK(&context->fw_work, sahara_processing); + INIT_WORK(&context->dump_work, sahara_dump_processing); context->image_table = aic100_image_table; context->table_size = ARRAY_SIZE(aic100_image_table); context->active_image_id = SAHARA_IMAGE_ID_NONE; @@ -405,7 +770,10 @@ static void sahara_mhi_remove(struct mhi_device *mhi_dev) { struct sahara_context *context = dev_get_drvdata(&mhi_dev->dev); - cancel_work_sync(&context->work); + cancel_work_sync(&context->fw_work); + cancel_work_sync(&context->dump_work); + if (context->mem_dump) + vfree(context->mem_dump); sahara_release_image(context); mhi_unprepare_from_transfer(mhi_dev); } @@ -418,8 +786,14 @@ static void sahara_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result { struct sahara_context *context = dev_get_drvdata(&mhi_dev->dev); - if (!mhi_result->transaction_status) - schedule_work(&context->work); + if (!mhi_result->transaction_status) { + context->rx_size = mhi_result->bytes_xferd; + if (context->is_mem_dump_mode) + schedule_work(&context->dump_work); + else + schedule_work(&context->fw_work); + } + } static const struct mhi_device_id sahara_mhi_match_table[] = { diff --git a/drivers/accessibility/speakup/Makefile b/drivers/accessibility/speakup/Makefile index 6f6a83565c0ded..14ba1cca87f47e 100644 --- a/drivers/accessibility/speakup/Makefile +++ b/drivers/accessibility/speakup/Makefile @@ -40,9 +40,7 @@ hostprogs += makemapdata makemapdata-objs := makemapdata.o quiet_cmd_mkmap = MKMAP $@ - cmd_mkmap = TOPDIR=$(srctree) \ - SPKDIR=$(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD),$(srctree)/drivers/accessibility/speakup) \ - $(obj)/makemapdata > $@ + cmd_mkmap = TOPDIR=$(srctree) SPKDIR=$(src) $(obj)/makemapdata > $@ $(obj)/mapdata.h: $(obj)/makemapdata $(call cmd,mkmap) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index d67f63d93b2abd..d81b55f5068c40 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -132,8 +132,17 @@ config ACPI_REV_OVERRIDE_POSSIBLE makes it possible to force the kernel to return "5" as the supported ACPI revision via the "acpi_rev_override" command line switch. +config ACPI_EC + bool "Embedded Controller" + depends on HAS_IOPORT + default X86 || LOONGARCH + help + This driver handles communication with the microcontroller + on many x86/LoongArch laptops and other machines. + config ACPI_EC_DEBUGFS tristate "EC read/write access through /sys/kernel/debug/ec" + depends on ACPI_EC help Say N to disable Embedded Controller /sys/kernel/debug interface @@ -433,7 +442,7 @@ config ACPI_HOTPLUG_IOAPIC config ACPI_SBS tristate "Smart Battery System" - depends on X86 + depends on X86 && ACPI_EC select POWER_SUPPLY help This driver supports the Smart Battery System, another diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 61ca4afe83dcdb..40208a0f5dfb57 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -41,7 +41,7 @@ acpi-y += resource.o acpi-y += acpi_processor.o acpi-y += processor_core.o acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o -acpi-y += ec.o +acpi-$(CONFIG_ACPI_EC) += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-$(CONFIG_PCI) += pci_root.o pci_link.o pci_irq.o obj-$(CONFIG_ACPI_MCFG) += pci_mcfg.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 7c5b040a83e8d6..1f69be8f51a29b 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -290,7 +290,7 @@ static void acpi_ac_remove(struct platform_device *pdev) static struct platform_driver acpi_ac_driver = { .probe = acpi_ac_probe, - .remove_new = acpi_ac_remove, + .remove = acpi_ac_remove, .driver = { .name = "ac", .acpi_match_table = ac_device_ids, diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 800f978684481e..49539f7528c647 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -86,7 +86,7 @@ static int fch_misc_setup(struct apd_private_data *pdata) if (!clk_data->name) return -ENOMEM; - strcpy(clk_data->name, obj->string.pointer); + strscpy(clk_data->name, obj->string.pointer, obj->string.length); } else { /* Set default name to mclk if entry missing in firmware */ clk_data->name = "mclk"; diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 42b7220d4cfda7..4ec20fd5698529 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -462,7 +462,7 @@ MODULE_DEVICE_TABLE(acpi, pad_device_ids); static struct platform_driver acpi_pad_driver = { .probe = acpi_pad_probe, - .remove_new = acpi_pad_remove, + .remove = acpi_pad_remove, .driver = { .dev_groups = acpi_pad_groups, .name = "processor_aggregator", diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c index b831cb8e53dc31..825c2a8acea436 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -684,7 +684,7 @@ static struct platform_driver acpi_tad_driver = { .acpi_match_table = acpi_tad_ids, }, .probe = acpi_tad_probe, - .remove_new = acpi_tad_remove, + .remove = acpi_tad_remove, }; MODULE_DEVICE_TABLE(acpi, acpi_tad_ids); diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 95f78383bbdba1..bff2d099f4691e 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -232,8 +232,6 @@ acpi_remove_address_space_handler(acpi_handle device, /* Now we can delete the handler object */ - acpi_os_release_mutex(handler_obj->address_space. - context_mutex); acpi_ut_remove_reference(handler_obj); goto unlock_and_exit; } diff --git a/drivers/acpi/apei/einj-core.c b/drivers/acpi/apei/einj-core.c index 5c22720f43ccb9..04731a5b01faab 100644 --- a/drivers/acpi/apei/einj-core.c +++ b/drivers/acpi/apei/einj-core.c @@ -880,7 +880,7 @@ static struct platform_device *einj_dev; * triggering a section mismatch warning. */ static struct platform_driver einj_driver __refdata = { - .remove_new = __exit_p(einj_remove), + .remove = __exit_p(einj_remove), .driver = { .name = "acpi-einj", }, diff --git a/drivers/acpi/apei/einj-cxl.c b/drivers/acpi/apei/einj-cxl.c index a4e709937236f6..78da9ae543a2b1 100644 --- a/drivers/acpi/apei/einj-cxl.c +++ b/drivers/acpi/apei/einj-cxl.c @@ -45,7 +45,7 @@ int einj_cxl_available_error_type_show(struct seq_file *m, void *v) return 0; } -EXPORT_SYMBOL_NS_GPL(einj_cxl_available_error_type_show, CXL); +EXPORT_SYMBOL_NS_GPL(einj_cxl_available_error_type_show, "CXL"); static int cxl_dport_get_sbdf(struct pci_dev *dport_dev, u64 *sbdf) { @@ -83,7 +83,7 @@ int einj_cxl_inject_rch_error(u64 rcrb, u64 type) return einj_cxl_rch_error_inject(type, 0x2, rcrb, GENMASK_ULL(63, 0), 0, 0); } -EXPORT_SYMBOL_NS_GPL(einj_cxl_inject_rch_error, CXL); +EXPORT_SYMBOL_NS_GPL(einj_cxl_inject_rch_error, "CXL"); int einj_cxl_inject_error(struct pci_dev *dport, u64 type) { @@ -104,10 +104,10 @@ int einj_cxl_inject_error(struct pci_dev *dport, u64 type) return einj_error_inject(type, 0x4, 0, 0, 0, param4); } -EXPORT_SYMBOL_NS_GPL(einj_cxl_inject_error, CXL); +EXPORT_SYMBOL_NS_GPL(einj_cxl_inject_error, "CXL"); bool einj_cxl_is_initialized(void) { return einj_initialized; } -EXPORT_SYMBOL_NS_GPL(einj_cxl_is_initialized, CXL); +EXPORT_SYMBOL_NS_GPL(einj_cxl_is_initialized, "CXL"); diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index ada93cfde9ba1c..07789f0b59bcda 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -726,7 +726,7 @@ int cxl_cper_register_work(struct work_struct *work) cxl_cper_work = work; return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL"); int cxl_cper_unregister_work(struct work_struct *work) { @@ -737,13 +737,13 @@ int cxl_cper_unregister_work(struct work_struct *work) cxl_cper_work = NULL; return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_work, "CXL"); int cxl_cper_kfifo_get(struct cxl_cper_work_data *wd) { return kfifo_get(&cxl_cper_fifo, wd); } -EXPORT_SYMBOL_NS_GPL(cxl_cper_kfifo_get, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_cper_kfifo_get, "CXL"); static bool ghes_do_proc(struct ghes *ghes, const struct acpi_hest_generic_status *estatus) @@ -1605,7 +1605,7 @@ static struct platform_driver ghes_platform_driver = { .name = "GHES", }, .probe = ghes_probe, - .remove_new = ghes_remove, + .remove = ghes_remove, }; void __init acpi_ghes_init(void) diff --git a/drivers/acpi/arm64/agdi.c b/drivers/acpi/arm64/agdi.c index f5f21dd0d277e9..e0df3daa4abf0f 100644 --- a/drivers/acpi/arm64/agdi.c +++ b/drivers/acpi/arm64/agdi.c @@ -88,7 +88,7 @@ static struct platform_driver agdi_driver = { .name = "agdi", }, .probe = agdi_probe, - .remove_new = agdi_remove, + .remove = agdi_remove, }; void __init acpi_agdi_init(void) diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c index c0e77c1c8e09d6..3561553eff8b5e 100644 --- a/drivers/acpi/arm64/gtdt.c +++ b/drivers/acpi/arm64/gtdt.c @@ -36,19 +36,25 @@ struct acpi_gtdt_descriptor { static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata; -static inline __init void *next_platform_timer(void *platform_timer) +static __init bool platform_timer_valid(void *platform_timer) { struct acpi_gtdt_header *gh = platform_timer; - platform_timer += gh->length; - if (platform_timer < acpi_gtdt_desc.gtdt_end) - return platform_timer; + return (platform_timer >= (void *)(acpi_gtdt_desc.gtdt + 1) && + platform_timer < acpi_gtdt_desc.gtdt_end && + gh->length != 0 && + platform_timer + gh->length <= acpi_gtdt_desc.gtdt_end); +} + +static __init void *next_platform_timer(void *platform_timer) +{ + struct acpi_gtdt_header *gh = platform_timer; - return NULL; + return platform_timer + gh->length; } #define for_each_platform_timer(_g) \ - for (_g = acpi_gtdt_desc.platform_timer; _g; \ + for (_g = acpi_gtdt_desc.platform_timer; platform_timer_valid(_g);\ _g = next_platform_timer(_g)) static inline bool is_timer_block(void *platform_timer) @@ -157,6 +163,7 @@ int __init acpi_gtdt_init(struct acpi_table_header *table, { void *platform_timer; struct acpi_table_gtdt *gtdt; + int cnt = 0; gtdt = container_of(table, struct acpi_table_gtdt, header); acpi_gtdt_desc.gtdt = gtdt; @@ -176,12 +183,16 @@ int __init acpi_gtdt_init(struct acpi_table_header *table, return 0; } - platform_timer = (void *)gtdt + gtdt->platform_timer_offset; - if (platform_timer < (void *)table + sizeof(struct acpi_table_gtdt)) { + acpi_gtdt_desc.platform_timer = (void *)gtdt + gtdt->platform_timer_offset; + for_each_platform_timer(platform_timer) + cnt++; + + if (cnt != gtdt->platform_timer_count) { + acpi_gtdt_desc.platform_timer = NULL; pr_err(FW_BUG "invalid timer data.\n"); return -EINVAL; } - acpi_gtdt_desc.platform_timer = platform_timer; + if (platform_timer_count) *platform_timer_count = gtdt->platform_timer_count; @@ -283,7 +294,7 @@ static int __init gtdt_parse_timer_block(struct acpi_gtdt_timer_block *block, if (frame->virt_irq > 0) acpi_unregister_gsi(gtdt_frame->virtual_timer_interrupt); frame->virt_irq = 0; - } while (i-- >= 0 && gtdt_frame--); + } while (i-- > 0 && gtdt_frame--); return -EINVAL; } @@ -352,7 +363,7 @@ static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd, } irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags); - res[2] = (struct resource)DEFINE_RES_IRQ(irq); + res[2] = DEFINE_RES_IRQ(irq); if (irq <= 0) { pr_warn("failed to map the Watchdog interrupt.\n"); nr_res--; diff --git a/drivers/acpi/arm64/init.c b/drivers/acpi/arm64/init.c index d0c8aed90fd16f..7a47d8095a7dd5 100644 --- a/drivers/acpi/arm64/init.c +++ b/drivers/acpi/arm64/init.c @@ -2,7 +2,7 @@ #include #include "init.h" -void __init acpi_arm_init(void) +void __init acpi_arch_init(void) { if (IS_ENABLED(CONFIG_ACPI_AGDI)) acpi_agdi_init(); diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 4c745a26226b27..98759d6199d3ac 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -1218,6 +1218,17 @@ static bool iort_pci_rc_supports_ats(struct acpi_iort_node *node) return pci_rc->ats_attribute & ACPI_IORT_ATS_SUPPORTED; } +static bool iort_pci_rc_supports_canwbs(struct acpi_iort_node *node) +{ + struct acpi_iort_memory_access *memory_access; + struct acpi_iort_root_complex *pci_rc; + + pci_rc = (struct acpi_iort_root_complex *)node->node_data; + memory_access = + (struct acpi_iort_memory_access *)&pci_rc->memory_properties; + return memory_access->memory_flags & ACPI_IORT_MF_CANWBS; +} + static int iort_iommu_xlate(struct device *dev, struct acpi_iort_node *node, u32 streamid) { @@ -1335,6 +1346,8 @@ int iort_iommu_configure_id(struct device *dev, const u32 *id_in) fwspec = dev_iommu_fwspec_get(dev); if (fwspec && iort_pci_rc_supports_ats(node)) fwspec->flags |= IOMMU_FWSPEC_PCI_RC_ATS; + if (fwspec && iort_pci_rc_supports_canwbs(node)) + fwspec->flags |= IOMMU_FWSPEC_PCI_RC_CANWBS; } else { node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, iort_match_node_callback, dev); @@ -1703,6 +1716,8 @@ static struct acpi_platform_list pmcg_plat_info[] __initdata = { /* HiSilicon Hip09 Platform */ {"HISI ", "HIP09 ", 0, ACPI_SIG_IORT, greater_than_or_equal, "Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP09}, + {"HISI ", "HIP09A ", 0, ACPI_SIG_IORT, greater_than_or_equal, + "Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP09}, /* HiSilicon Hip10/11 Platform uses the same SMMU IP with Hip09 */ {"HISI ", "HIP10 ", 0, ACPI_SIG_IORT, greater_than_or_equal, "Erratum #162001900", IORT_SMMU_V3_PMCG_HISI_HIP09}, diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 65fa3444367a13..3d5342f8d7b3ae 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -853,6 +853,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) struct power_supply_config psy_cfg = { .drv_data = battery, .attr_grp = acpi_battery_groups, + .no_wakeup_source = true, }; bool full_cap_broken = false; @@ -888,7 +889,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) battery->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; battery->bat_desc.get_property = acpi_battery_get_property; - battery->bat = power_supply_register_no_ws(&battery->device->dev, + battery->bat = power_supply_register(&battery->device->dev, &battery->bat_desc, &psy_cfg); if (IS_ERR(battery->bat)) { @@ -1218,15 +1219,21 @@ static int acpi_battery_add(struct acpi_device *device) if (device->dep_unmet) return -EPROBE_DEFER; - battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); + battery = devm_kzalloc(&device->dev, sizeof(*battery), GFP_KERNEL); if (!battery) return -ENOMEM; battery->device = device; strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS); device->driver_data = battery; - mutex_init(&battery->lock); - mutex_init(&battery->sysfs_lock); + result = devm_mutex_init(&device->dev, &battery->lock); + if (result) + return result; + + result = devm_mutex_init(&device->dev, &battery->sysfs_lock); + if (result) + return result; + if (acpi_has_method(battery->device->handle, "_BIX")) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); @@ -1238,7 +1245,9 @@ static int acpi_battery_add(struct acpi_device *device) device->status.battery_present ? "present" : "absent"); battery->pm_nb.notifier_call = battery_notify; - register_pm_notifier(&battery->pm_nb); + result = register_pm_notifier(&battery->pm_nb); + if (result) + goto fail; device_init_wakeup(&device->dev, 1); @@ -1254,9 +1263,6 @@ static int acpi_battery_add(struct acpi_device *device) unregister_pm_notifier(&battery->pm_nb); fail: sysfs_remove_battery(battery); - mutex_destroy(&battery->lock); - mutex_destroy(&battery->sysfs_lock); - kfree(battery); return result; } @@ -1276,13 +1282,8 @@ static void acpi_battery_remove(struct acpi_device *device) device_init_wakeup(&device->dev, 0); unregister_pm_notifier(&battery->pm_nb); sysfs_remove_battery(battery); - - mutex_destroy(&battery->lock); - mutex_destroy(&battery->sysfs_lock); - kfree(battery); } -#ifdef CONFIG_PM_SLEEP /* this is needed to learn about changes made in suspended state */ static int acpi_battery_resume(struct device *dev) { @@ -1299,11 +1300,8 @@ static int acpi_battery_resume(struct device *dev) acpi_battery_update(battery, true); return 0; } -#else -#define acpi_battery_resume NULL -#endif -static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume); static struct acpi_driver acpi_battery_driver = { .name = "battery", @@ -1313,7 +1311,7 @@ static struct acpi_driver acpi_battery_driver = { .add = acpi_battery_add, .remove = acpi_battery_remove, }, - .drv.pm = &acpi_battery_pm, + .drv.pm = pm_sleep_ptr(&acpi_battery_pm), .drv.probe_type = PROBE_PREFER_ASYNCHRONOUS, }; diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 16917dc3ad604c..058910af82bca6 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1434,6 +1434,8 @@ static int __init acpi_bus_init(void) struct kobject *acpi_kobj; EXPORT_SYMBOL_GPL(acpi_kobj); +void __weak __init acpi_arch_init(void) { } + static int __init acpi_init(void) { int result; @@ -1461,8 +1463,7 @@ static int __init acpi_init(void) acpi_viot_early_init(); acpi_hest_init(); acpi_ghes_init(); - acpi_arm_init(); - acpi_riscv_init(); + acpi_arch_init(); acpi_scan_init(); acpi_ec_init(); acpi_debugfs_init(); diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 5c0cc7aae8726b..f193e713825ac2 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1011,7 +1011,8 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val) *val = 0; size = GET_BIT_WIDTH(reg); - if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + if (IS_ENABLED(CONFIG_HAS_IOPORT) && + reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { u32 val_u32; acpi_status status; @@ -1085,7 +1086,8 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) size = GET_BIT_WIDTH(reg); - if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + if (IS_ENABLED(CONFIG_HAS_IOPORT) && + reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { acpi_status status; status = acpi_os_write_port((acpi_io_address)reg->address, @@ -1140,7 +1142,6 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) return -EFAULT; } val = MASK_VAL_WRITE(reg, prev_val, val); - val |= prev_val; } switch (size) { diff --git a/drivers/acpi/dptf/dptf_pch_fivr.c b/drivers/acpi/dptf/dptf_pch_fivr.c index d202730fafd8d6..624fce67ce4359 100644 --- a/drivers/acpi/dptf/dptf_pch_fivr.c +++ b/drivers/acpi/dptf/dptf_pch_fivr.c @@ -158,7 +158,7 @@ MODULE_DEVICE_TABLE(acpi, pch_fivr_device_ids); static struct platform_driver pch_fivr_driver = { .probe = pch_fivr_add, - .remove_new = pch_fivr_remove, + .remove = pch_fivr_remove, .driver = { .name = "dptf_pch_fivr", .acpi_match_table = pch_fivr_device_ids, diff --git a/drivers/acpi/dptf/dptf_power.c b/drivers/acpi/dptf/dptf_power.c index 8023b3e2331561..3d3edd81b1729b 100644 --- a/drivers/acpi/dptf/dptf_power.c +++ b/drivers/acpi/dptf/dptf_power.c @@ -242,7 +242,7 @@ MODULE_DEVICE_TABLE(acpi, int3407_device_ids); static struct platform_driver dptf_power_driver = { .probe = dptf_power_add, - .remove_new = dptf_power_remove, + .remove = dptf_power_remove, .driver = { .name = "dptf_power", .acpi_match_table = int3407_device_ids, diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 25399f6dde7e27..8db09d81918fbb 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1677,8 +1677,8 @@ static int acpi_ec_add(struct acpi_device *device) struct acpi_ec *ec; int ret; - strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_EC_CLASS); + strscpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_EC_CLASS); if (boot_ec && (boot_ec->handle == device->handle || !strcmp(acpi_device_hid(device), ACPI_ECDT_HID))) { diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index d199a19bb29280..96a9aaaaf9f705 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -28,8 +28,8 @@ int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data) { struct acpi_bus_event event; - strcpy(event.device_class, dev->pnp.device_class); - strcpy(event.bus_id, dev->pnp.bus_id); + strscpy(event.device_class, dev->pnp.device_class); + strscpy(event.bus_id, dev->pnp.bus_id); event.type = type; event.data = data; return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event) diff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c index 11778c93254bfc..5c35cbc7f6ff12 100644 --- a/drivers/acpi/evged.c +++ b/drivers/acpi/evged.c @@ -185,7 +185,7 @@ static const struct acpi_device_id ged_acpi_ids[] = { static struct platform_driver ged_driver = { .probe = ged_probe, - .remove_new = ged_remove, + .remove = ged_remove, .shutdown = ged_shutdown, .driver = { .name = MODULE_NAME, diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c index 7cea4495f19bbe..3ea9cfcff46e79 100644 --- a/drivers/acpi/fan_core.c +++ b/drivers/acpi/fan_core.c @@ -448,7 +448,7 @@ static const struct dev_pm_ops acpi_fan_pm = { static struct platform_driver acpi_fan_driver = { .probe = acpi_fan_probe, - .remove_new = acpi_fan_remove, + .remove = acpi_fan_remove, .driver = { .name = "acpi-fan", .acpi_match_table = fan_device_ids, diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ced7dff9a5dbfe..00910ccd7eda81 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -215,6 +215,8 @@ extern struct acpi_ec *first_ec; /* External interfaces use first EC only, so remember */ typedef int (*acpi_ec_query_func) (void *data); +#ifdef CONFIG_ACPI_EC + void acpi_ec_init(void); void acpi_ec_ecdt_probe(void); void acpi_ec_dsdt_probe(void); @@ -231,6 +233,29 @@ void acpi_ec_flush_work(void); bool acpi_ec_dispatch_gpe(void); #endif +#else + +static inline void acpi_ec_init(void) {} +static inline void acpi_ec_ecdt_probe(void) {} +static inline void acpi_ec_dsdt_probe(void) {} +static inline void acpi_ec_block_transactions(void) {} +static inline void acpi_ec_unblock_transactions(void) {} +static inline int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, + acpi_handle handle, acpi_ec_query_func func, + void *data) +{ + return -ENXIO; +} +static inline void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) {} +static inline void acpi_ec_register_opregions(struct acpi_device *adev) {} + +static inline void acpi_ec_flush_work(void) {} +static inline bool acpi_ec_dispatch_gpe(void) +{ + return false; +} + +#endif /*-------------------------------------------------------------------------- Suspend/Resume diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 5429ec9ef06f06..a5d47819b3a4e2 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -454,8 +454,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, if (cmd_rc) *cmd_rc = -EINVAL; - if (cmd == ND_CMD_CALL) + if (cmd == ND_CMD_CALL) { + if (!buf || buf_len < sizeof(*call_pkg)) + return -EINVAL; + call_pkg = buf; + } + func = cmd_to_func(nfit_mem, cmd, call_pkg, &family); if (func < 0) return func; diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index 1a902a02390f6d..80a3481c04701d 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -151,7 +151,7 @@ int acpi_get_genport_coordinates(u32 uid, return 0; } -EXPORT_SYMBOL_NS_GPL(acpi_get_genport_coordinates, CXL); +EXPORT_SYMBOL_NS_GPL(acpi_get_genport_coordinates, "CXL"); static __init void alloc_memory_initiator(unsigned int cpu_pxm) { diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 70af3fbbebe54c..fed446aace4259 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -642,6 +642,15 @@ acpi_status acpi_os_read_port(acpi_io_address port, u32 *value, u32 width) { u32 dummy; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) { + /* + * set all-1 result as if reading from non-existing + * I/O port + */ + *value = GENMASK(width, 0); + return AE_NOT_IMPLEMENTED; + } + if (value) *value = 0; else @@ -665,6 +674,9 @@ EXPORT_SYMBOL(acpi_os_read_port); acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return AE_NOT_IMPLEMENTED; + if (width <= 8) { outb(value, port); } else if (width <= 16) { diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index b727db968f3349..08e10b6226dc60 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -714,8 +714,8 @@ static int acpi_pci_link_add(struct acpi_device *device, return -ENOMEM; link->device = device; - strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); + strscpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); device->driver_data = link; mutex_lock(&acpi_link_lock); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d0bfb370680198..d0b6a024daaeca 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -689,8 +689,8 @@ static int acpi_pci_root_add(struct acpi_device *device, root->device = device; root->segment = segment & 0xFFFF; - strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); + strscpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS); device->driver_data = root; if (hotadd && dmar_device_add(handle)) { diff --git a/drivers/acpi/pfr_telemetry.c b/drivers/acpi/pfr_telemetry.c index 998264a7333d6e..32bdf8cbe8f237 100644 --- a/drivers/acpi/pfr_telemetry.c +++ b/drivers/acpi/pfr_telemetry.c @@ -272,9 +272,6 @@ static long pfrt_log_ioctl(struct file *file, unsigned int cmd, unsigned long ar case PFRT_LOG_IOC_GET_INFO: info.log_level = get_pfrt_log_level(pfrt_log_dev); - if (ret < 0) - return ret; - info.log_type = pfrt_log_dev->info.log_type; info.log_revid = pfrt_log_dev->info.log_revid; if (copy_to_user(p, &info, sizeof(info))) @@ -425,7 +422,7 @@ static struct platform_driver acpi_pfrt_log_driver = { .acpi_match_table = acpi_pfrt_log_ids, }, .probe = acpi_pfrt_log_probe, - .remove_new = acpi_pfrt_log_remove, + .remove = acpi_pfrt_log_remove, }; module_platform_driver(acpi_pfrt_log_driver); diff --git a/drivers/acpi/pfr_update.c b/drivers/acpi/pfr_update.c index 8b2910995fc1a9..031d1ba81b866d 100644 --- a/drivers/acpi/pfr_update.c +++ b/drivers/acpi/pfr_update.c @@ -565,7 +565,7 @@ static struct platform_driver acpi_pfru_driver = { .acpi_match_table = acpi_pfru_ids, }, .probe = acpi_pfru_probe, - .remove_new = acpi_pfru_remove, + .remove = acpi_pfru_remove, }; module_platform_driver(acpi_pfru_driver); diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index c2c70139c4f1d9..25174c24d3d757 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -950,8 +950,8 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) mutex_init(&resource->resource_lock); INIT_LIST_HEAD(&resource->list_node); INIT_LIST_HEAD(&resource->dependents); - strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_POWER_CLASS); + strscpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_POWER_CLASS); device->power.state = ACPI_STATE_UNKNOWN; device->flags.match_driver = true; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 831fa4a1215985..698897b29de244 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -578,7 +578,7 @@ static void __cpuidle acpi_idle_do_entry(struct acpi_processor_cx *cx) * @dev: the target CPU * @index: the index of suggested state */ -static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) +static void acpi_idle_play_dead(struct cpuidle_device *dev, int index) { struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu); @@ -591,11 +591,8 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index) else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) { io_idle(cx->address); } else - return -ENODEV; + return; } - - /* Never reached */ - return 0; } static __always_inline bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) @@ -803,12 +800,12 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) state->enter = acpi_idle_enter; state->flags = 0; - if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2 || - cx->type == ACPI_STATE_C3) { - state->enter_dead = acpi_idle_play_dead; - if (cx->type != ACPI_STATE_C3) - drv->safe_state_index = count; - } + + state->enter_dead = acpi_idle_play_dead; + + if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2) + drv->safe_state_index = count; + /* * Halt-induced C1 is not good for ->enter_s2idle, because it * re-enables interrupts on exit. Moreover, C1 is generally not diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 4265814c74f81a..53996f1a2d80e9 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -24,8 +24,6 @@ #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" -static DEFINE_MUTEX(performance_mutex); - /* * _PPC support is implemented as a CPUfreq policy notifier: * This means each time a CPUfreq driver registered also with @@ -209,6 +207,10 @@ void acpi_processor_ppc_exit(struct cpufreq_policy *policy) } } +#ifdef CONFIG_X86 + +static DEFINE_MUTEX(performance_mutex); + static int acpi_processor_get_performance_control(struct acpi_processor *pr) { int result = 0; @@ -267,7 +269,6 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr) return result; } -#ifdef CONFIG_X86 /* * Some AMDs have 50MHz frequency multiples, but only provide 100MHz rounding * in their ACPI data. Calculate the real values and fix up the _PSS data. @@ -298,9 +299,6 @@ static void amd_fixup_frequency(struct acpi_processor_px *px, int i) px->core_frequency = (100 * (fid + 8)) >> did; } } -#else -static void amd_fixup_frequency(struct acpi_processor_px *px, int i) {}; -#endif static int acpi_processor_get_performance_states(struct acpi_processor *pr) { @@ -440,13 +438,11 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr) * the BIOS is older than the CPU and does not know its frequencies */ update_bios: -#ifdef CONFIG_X86 if (acpi_has_method(pr->handle, "_PPC")) { if(boot_cpu_has(X86_FEATURE_EST)) pr_warn(FW_BUG "BIOS needs update for CPU " "frequency support\n"); } -#endif return result; } EXPORT_SYMBOL_GPL(acpi_processor_get_performance_info); @@ -788,3 +784,4 @@ void acpi_processor_unregister_performance(unsigned int cpu) mutex_unlock(&performance_mutex); } EXPORT_SYMBOL(acpi_processor_unregister_performance); +#endif diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 7fe842dae1ec05..821867de43bea3 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -250,6 +250,9 @@ static bool acpi_decode_space(struct resource_win *win, switch (addr->resource_type) { case ACPI_MEMORY_RANGE: acpi_dev_memresource_flags(res, len, wp); + + if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) + res->flags |= IORESOURCE_PREFETCH; break; case ACPI_IO_RANGE: acpi_dev_ioresource_flags(res, len, iodec, @@ -265,9 +268,6 @@ static bool acpi_decode_space(struct resource_win *win, if (addr->producer_consumer == ACPI_PRODUCER) res->flags |= IORESOURCE_WINDOW; - if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY) - res->flags |= IORESOURCE_PREFETCH; - return !(res->flags & IORESOURCE_DISABLED); } diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c index 5ef97905a72759..673e4d5dd75271 100644 --- a/drivers/acpi/riscv/init.c +++ b/drivers/acpi/riscv/init.c @@ -7,7 +7,7 @@ #include #include "init.h" -void __init acpi_riscv_init(void) +void __init acpi_arch_init(void) { riscv_acpi_init_gsi_mapping(); } diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 7a0914055fca01..a3f95a3fffde20 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -644,8 +644,8 @@ static int acpi_sbs_add(struct acpi_device *device) sbs->hc = acpi_driver_data(acpi_dev_parent(device)); sbs->device = device; - strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_SBS_CLASS); + strscpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_SBS_CLASS); device->driver_data = sbs; result = acpi_charger_add(sbs); diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index 16f2daaa2c454b..1a2bf520be2306 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -14,6 +14,7 @@ #include #include #include "sbshc.h" +#include "internal.h" #define ACPI_SMB_HC_CLASS "smbus_host_ctl" #define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC" @@ -236,12 +237,6 @@ static int smbus_alarm(void *context) return 0; } -typedef int (*acpi_ec_query_func) (void *data); - -extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, - acpi_handle handle, acpi_ec_query_func func, - void *data); - static int acpi_smbus_hc_add(struct acpi_device *device) { int status; @@ -257,8 +252,8 @@ static int acpi_smbus_hc_add(struct acpi_device *device) return -EIO; } - strcpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_SMB_HC_CLASS); + strscpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_SMB_HC_CLASS); hc = kzalloc(sizeof(struct acpi_smb_hc), GFP_KERNEL); if (!hc) @@ -278,8 +273,6 @@ static int acpi_smbus_hc_add(struct acpi_device *device) return 0; } -extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit); - static void acpi_smbus_hc_remove(struct acpi_device *device) { struct acpi_smb_hc *hc; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7ecc401fb97f9e..74dcccdc6482b8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1179,19 +1179,19 @@ static void acpi_device_get_busid(struct acpi_device *device) * TBD: Shouldn't this value be unique (within the ACPI namespace)? */ if (!acpi_dev_parent(device)) { - strcpy(device->pnp.bus_id, "ACPI"); + strscpy(device->pnp.bus_id, "ACPI"); return; } switch (device->device_type) { case ACPI_BUS_TYPE_POWER_BUTTON: - strcpy(device->pnp.bus_id, "PWRF"); + strscpy(device->pnp.bus_id, "PWRF"); break; case ACPI_BUS_TYPE_SLEEP_BUTTON: - strcpy(device->pnp.bus_id, "SLPF"); + strscpy(device->pnp.bus_id, "SLPF"); break; case ACPI_BUS_TYPE_ECDT_EC: - strcpy(device->pnp.bus_id, "ECDT"); + strscpy(device->pnp.bus_id, "ECDT"); break; default: acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer); @@ -1202,7 +1202,7 @@ static void acpi_device_get_busid(struct acpi_device *device) else break; } - strcpy(device->pnp.bus_id, bus_id); + strscpy(device->pnp.bus_id, bus_id); break; } } @@ -1453,8 +1453,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp, acpi_object_is_system_bus(handle)) { /* \_SB, \_TZ, LNXSYBUS */ acpi_add_id(pnp, ACPI_BUS_HID); - strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME); - strcpy(pnp->device_class, ACPI_BUS_CLASS); + strscpy(pnp->device_name, ACPI_BUS_DEVICE_NAME); + strscpy(pnp->device_class, ACPI_BUS_CLASS); } break; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 78db38c7076e45..95982c098d5bd5 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -796,9 +796,9 @@ static int acpi_thermal_add(struct acpi_device *device) return -ENOMEM; tz->device = device; - strcpy(tz->name, device->pnp.bus_id); - strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); + strscpy(tz->name, device->pnp.bus_id); + strscpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_THERMAL_CLASS); device->driver_data = tz; acpi_thermal_aml_dependency_fix(tz); @@ -1082,7 +1082,7 @@ static void __exit acpi_thermal_exit(void) module_init(acpi_thermal_init); module_exit(acpi_thermal_exit); -MODULE_IMPORT_NS(ACPI_THERMAL); +MODULE_IMPORT_NS("ACPI_THERMAL"); MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION("ACPI Thermal Zone Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/acpi/thermal_lib.c b/drivers/acpi/thermal_lib.c index 6214d6ebe1fa31..f81591927e8658 100644 --- a/drivers/acpi/thermal_lib.c +++ b/drivers/acpi/thermal_lib.c @@ -53,25 +53,25 @@ int acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp) return acpi_trip_temp(adev, obj_name, ret_temp); } -EXPORT_SYMBOL_NS_GPL(acpi_active_trip_temp, ACPI_THERMAL); +EXPORT_SYMBOL_NS_GPL(acpi_active_trip_temp, "ACPI_THERMAL"); int acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp) { return acpi_trip_temp(adev, "_PSV", ret_temp); } -EXPORT_SYMBOL_NS_GPL(acpi_passive_trip_temp, ACPI_THERMAL); +EXPORT_SYMBOL_NS_GPL(acpi_passive_trip_temp, "ACPI_THERMAL"); int acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp) { return acpi_trip_temp(adev, "_HOT", ret_temp); } -EXPORT_SYMBOL_NS_GPL(acpi_hot_trip_temp, ACPI_THERMAL); +EXPORT_SYMBOL_NS_GPL(acpi_hot_trip_temp, "ACPI_THERMAL"); int acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp) { return acpi_trip_temp(adev, "_CRT", ret_temp); } -EXPORT_SYMBOL_NS_GPL(acpi_critical_trip_temp, ACPI_THERMAL); +EXPORT_SYMBOL_NS_GPL(acpi_critical_trip_temp, "ACPI_THERMAL"); static int thermal_temp(int error, int temp_decik, int *ret_temp) { diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 015bd8e66c1cf8..d507d5e084354b 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -549,6 +549,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "iMac12,2"), }, }, + { + .callback = video_detect_force_native, + /* Apple MacBook Air 7,2 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir7,2"), + }, + }, { .callback = video_detect_force_native, /* Apple MacBook Air 9,1 */ @@ -565,6 +573,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,2"), }, }, + { + .callback = video_detect_force_native, + /* Apple MacBook Pro 11,2 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro11,2"), + }, + }, { /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */ .callback = video_detect_force_native, diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c index 6af546b21574f9..cb45ef5240dab6 100644 --- a/drivers/acpi/x86/utils.c +++ b/drivers/acpi/x86/utils.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -295,6 +296,7 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = { /* * 2. Devices which also have the skip i2c/serdev quirks and which * need the x86-android-tablets module to properly work. + * Sorted alphabetically. */ #if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS) { @@ -308,6 +310,19 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = { ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS), }, { + /* Acer Iconia One 8 A1-840 (non FHD version) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Above strings are too generic also match BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "04/01/2014"), + }, + .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | + ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY | + ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS), + }, + { + /* Asus ME176C tablet */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), @@ -318,23 +333,24 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = { ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS), }, { - /* Lenovo Yoga Book X90F/L */ + /* Asus TF103C transformer 2-in-1 */ .matches = { - 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"), + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), }, .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | - ACPI_QUIRK_UART1_SKIP | ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY | ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS), }, { + /* Lenovo Yoga Book X90F/L */ .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), + 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"), }, .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | + ACPI_QUIRK_UART1_SKIP | ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY | ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS), }, @@ -391,6 +407,19 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = { .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY), }, + { + /* Vexia Edu Atla 10 tablet 9V version */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), + }, + .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS | + ACPI_QUIRK_UART1_SKIP | + ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY | + ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS), + }, { /* Whitelabel (sold as various brands) TM800A550L */ .matches = { @@ -411,6 +440,7 @@ static const struct acpi_device_id i2c_acpi_known_good_ids[] = { { "10EC5640", 0 }, /* RealTek ALC5640 audio codec */ { "10EC5651", 0 }, /* RealTek ALC5651 audio codec */ { "INT33F4", 0 }, /* X-Powers AXP288 PMIC */ + { "INT33F5", 0 }, /* TI Dollar Cove PMIC */ { "INT33FD", 0 }, /* Intel Crystal Cove PMIC */ { "INT34D3", 0 }, /* Intel Whiskey Cove PMIC */ { "NPCE69A", 0 }, /* Asus Transformer keyboard dock */ @@ -439,18 +469,35 @@ static int acpi_dmi_skip_serdev_enumeration(struct device *controller_parent, bo struct acpi_device *adev = ACPI_COMPANION(controller_parent); const struct dmi_system_id *dmi_id; long quirks = 0; - u64 uid; - int ret; + u64 uid = 0; - ret = acpi_dev_uid_to_integer(adev, &uid); - if (ret) + dmi_id = dmi_first_match(acpi_quirk_skip_dmi_ids); + if (!dmi_id) return 0; - dmi_id = dmi_first_match(acpi_quirk_skip_dmi_ids); - if (dmi_id) - quirks = (unsigned long)dmi_id->driver_data; + quirks = (unsigned long)dmi_id->driver_data; + + /* uid is left at 0 on errors and 0 is not a valid UART UID */ + acpi_dev_uid_to_integer(adev, &uid); + + /* For PCI UARTs without an UID */ + if (!uid && dev_is_pci(controller_parent)) { + struct pci_dev *pdev = to_pci_dev(controller_parent); + + /* + * Devfn values for PCI UARTs on Bay Trail SoCs, which are + * the only devices where this fallback is necessary. + */ + if (pdev->devfn == PCI_DEVFN(0x1e, 3)) + uid = 1; + else if (pdev->devfn == PCI_DEVFN(0x1e, 4)) + uid = 2; + } + + if (!uid) + return 0; - if (!dev_is_platform(controller_parent)) { + if (!dev_is_platform(controller_parent) && !dev_is_pci(controller_parent)) { /* PNP enumerated UARTs */ if ((quirks & ACPI_QUIRK_PNP_UART1_SKIP) && uid == 1) *skip = true; @@ -505,7 +552,7 @@ int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *s * Set skip to true so that the tty core creates a serdev ctrl device. * The backlight driver will manually create the serdev client device. */ - if (acpi_dev_hid_match(adev, "DELL0501")) { + if (adev && acpi_dev_hid_match(adev, "DELL0501")) { *skip = true; /* * Create a platform dev for dell-uart-backlight to bind to. diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 0230c43377c1da..8ef259b4d0378a 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -449,6 +449,12 @@ const struct bus_type amba_bustype = { }; EXPORT_SYMBOL_GPL(amba_bustype); +bool dev_is_amba(const struct device *dev) +{ + return dev->bus == &amba_bustype; +} +EXPORT_SYMBOL_GPL(dev_is_amba); + static int __init amba_init(void) { return bus_register(&amba_bustype); diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 978740537a1aac..ef353ca13c356a 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1225,6 +1225,12 @@ static void binder_cleanup_ref_olocked(struct binder_ref *ref) binder_dequeue_work(ref->proc, &ref->death->work); binder_stats_deleted(BINDER_STAT_DEATH); } + + if (ref->freeze) { + binder_dequeue_work(ref->proc, &ref->freeze->work); + binder_stats_deleted(BINDER_STAT_FREEZE); + } + binder_stats_deleted(BINDER_STAT_REF); } @@ -3850,7 +3856,6 @@ binder_request_freeze_notification(struct binder_proc *proc, { struct binder_ref_freeze *freeze; struct binder_ref *ref; - bool is_frozen; freeze = kzalloc(sizeof(*freeze), GFP_KERNEL); if (!freeze) @@ -3866,32 +3871,31 @@ binder_request_freeze_notification(struct binder_proc *proc, } binder_node_lock(ref->node); - - if (ref->freeze || !ref->node->proc) { - binder_user_error("%d:%d invalid BC_REQUEST_FREEZE_NOTIFICATION %s\n", - proc->pid, thread->pid, - ref->freeze ? "already set" : "dead node"); + if (ref->freeze) { + binder_user_error("%d:%d BC_REQUEST_FREEZE_NOTIFICATION already set\n", + proc->pid, thread->pid); binder_node_unlock(ref->node); binder_proc_unlock(proc); kfree(freeze); return -EINVAL; } - binder_inner_proc_lock(ref->node->proc); - is_frozen = ref->node->proc->is_frozen; - binder_inner_proc_unlock(ref->node->proc); binder_stats_created(BINDER_STAT_FREEZE); INIT_LIST_HEAD(&freeze->work.entry); freeze->cookie = handle_cookie->cookie; freeze->work.type = BINDER_WORK_FROZEN_BINDER; - freeze->is_frozen = is_frozen; - ref->freeze = freeze; - binder_inner_proc_lock(proc); - binder_enqueue_work_ilocked(&ref->freeze->work, &proc->todo); - binder_wakeup_proc_ilocked(proc); - binder_inner_proc_unlock(proc); + if (ref->node->proc) { + binder_inner_proc_lock(ref->node->proc); + freeze->is_frozen = ref->node->proc->is_frozen; + binder_inner_proc_unlock(ref->node->proc); + + binder_inner_proc_lock(proc); + binder_enqueue_work_ilocked(&freeze->work, &proc->todo); + binder_wakeup_proc_ilocked(proc); + binder_inner_proc_unlock(proc); + } binder_node_unlock(ref->node); binder_proc_unlock(proc); @@ -5151,6 +5155,16 @@ static void binder_release_work(struct binder_proc *proc, } break; case BINDER_WORK_NODE: break; + case BINDER_WORK_CLEAR_FREEZE_NOTIFICATION: { + struct binder_ref_freeze *freeze; + + freeze = container_of(w, struct binder_ref_freeze, work); + binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, + "undelivered freeze notification, %016llx\n", + (u64)freeze->cookie); + kfree(freeze); + binder_stats_deleted(BINDER_STAT_FREEZE); + } break; default: pr_err("unexpected work type, %d, not freed\n", wtype); @@ -5552,6 +5566,7 @@ static bool binder_txns_pending_ilocked(struct binder_proc *proc) static void binder_add_freeze_work(struct binder_proc *proc, bool is_frozen) { + struct binder_node *prev = NULL; struct rb_node *n; struct binder_ref *ref; @@ -5560,7 +5575,10 @@ static void binder_add_freeze_work(struct binder_proc *proc, bool is_frozen) struct binder_node *node; node = rb_entry(n, struct binder_node, rb_node); + binder_inc_node_tmpref_ilocked(node); binder_inner_proc_unlock(proc); + if (prev) + binder_put_node(prev); binder_node_lock(node); hlist_for_each_entry(ref, &node->refs, node_entry) { /* @@ -5586,10 +5604,15 @@ static void binder_add_freeze_work(struct binder_proc *proc, bool is_frozen) } binder_inner_proc_unlock(ref->proc); } + prev = node; binder_node_unlock(node); binder_inner_proc_lock(proc); + if (proc->is_dead) + break; } binder_inner_proc_unlock(proc); + if (prev) + binder_put_node(prev); } static int binder_ioctl_freeze(struct binder_freeze_info *info, @@ -6260,6 +6283,7 @@ static void binder_deferred_release(struct binder_proc *proc) binder_release_work(proc, &proc->todo); binder_release_work(proc, &proc->delivered_death); + binder_release_work(proc, &proc->delivered_freeze); binder_debug(BINDER_DEBUG_OPEN_CLOSE, "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n", @@ -6393,6 +6417,12 @@ static void print_binder_work_ilocked(struct seq_file *m, case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: seq_printf(m, "%shas cleared death notification\n", prefix); break; + case BINDER_WORK_FROZEN_BINDER: + seq_printf(m, "%shas frozen binder\n", prefix); + break; + case BINDER_WORK_CLEAR_FREEZE_NOTIFICATION: + seq_printf(m, "%shas cleared freeze notification\n", prefix); + break; default: seq_printf(m, "%sunknown work: type %d\n", prefix, w->type); break; @@ -6539,6 +6569,10 @@ static void print_binder_proc(struct seq_file *m, seq_puts(m, " has delivered dead binder\n"); break; } + list_for_each_entry(w, &proc->delivered_freeze, entry) { + seq_puts(m, " has delivered freeze binder\n"); + break; + } binder_inner_proc_unlock(proc); if (!print_all && m->count == header_pos) m->count = start_pos; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index b3acbc4174fb1f..a738e774586586 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -1047,7 +1047,7 @@ void binder_alloc_vma_close(struct binder_alloc *alloc) /** * binder_alloc_free_page() - shrinker callback to free pages * @item: item to free - * @lock: lock protecting the item + * @lru: list_lru instance of the item * @cb_arg: callback argument * * Called from list_lru_walk() in binder_shrink_scan() to free @@ -1055,9 +1055,8 @@ void binder_alloc_vma_close(struct binder_alloc *alloc) */ enum lru_status binder_alloc_free_page(struct list_head *item, struct list_lru_one *lru, - spinlock_t *lock, void *cb_arg) - __must_hold(lock) + __must_hold(&lru->lock) { struct binder_lru_page *page = container_of(item, typeof(*page), lru); struct binder_alloc *alloc = page->alloc; @@ -1092,7 +1091,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item, list_lru_isolate(lru, item); spin_unlock(&alloc->lock); - spin_unlock(lock); + spin_unlock(&lru->lock); if (vma) { trace_binder_unmap_user_start(alloc, index); @@ -1106,7 +1105,6 @@ enum lru_status binder_alloc_free_page(struct list_head *item, mmput_async(mm); __free_page(page_to_free); - spin_lock(lock); return LRU_REMOVED_RETRY; err_invalid_vma: diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 70387234477e0c..c02c8ebcb466bc 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -118,7 +118,7 @@ static inline void binder_selftest_alloc(struct binder_alloc *alloc) {} #endif enum lru_status binder_alloc_free_page(struct list_head *item, struct list_lru_one *lru, - spinlock_t *lock, void *cb_arg); + void *cb_arg); struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, size_t data_size, size_t offsets_size, diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c index 547f5634170574..3999305b535603 100644 --- a/drivers/ata/acard-ahci.c +++ b/drivers/ata/acard-ahci.c @@ -370,7 +370,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id /* AHCI controllers often implement SFF compatible interface. * Grab all PCI BARs just in case. */ - rc = pcim_iomap_regions_request_all(pdev, 1 << AHCI_PCI_BAR, DRV_NAME); + rc = pcim_request_all_regions(pdev, DRV_NAME); if (rc == -EBUSY) pcim_pin_device(pdev); if (rc) @@ -386,7 +386,9 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) pci_enable_msi(pdev); - hpriv->mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR]; + hpriv->mmio = pcim_iomap(pdev, AHCI_PCI_BAR, 0); + if (!hpriv->mmio) + return -ENOMEM; /* save initial config */ ahci_save_initial_config(&pdev->dev, hpriv); diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 45f63b09828a1a..8d27c567be1c15 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1676,7 +1676,7 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, /* * If number of MSIs is less than number of ports then Sharing Last * Message mode could be enforced. In this case assume that advantage - * of multipe MSIs is negated and use single MSI mode instead. + * of multiple MSIs is negated and use single MSI mode instead. */ if (n_ports > 1) { nvec = pci_alloc_irq_vectors(pdev, n_ports, INT_MAX, @@ -1869,7 +1869,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* AHCI controllers often implement SFF compatible interface. * Grab all PCI BARs just in case. */ - rc = pcim_iomap_regions_request_all(pdev, 1 << ahci_pci_bar, DRV_NAME); + rc = pcim_request_all_regions(pdev, DRV_NAME); if (rc == -EBUSY) pcim_pin_device(pdev); if (rc) @@ -1893,7 +1893,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (ahci_sb600_enable_64bit(pdev)) hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY; - hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; + hpriv->mmio = pcim_iomap(pdev, ahci_pci_bar, 0); + if (!hpriv->mmio) + return -ENOMEM; /* detect remapped nvme devices */ ahci_remap_check(pdev, ahci_pci_bar, hpriv); diff --git a/drivers/ata/ahci_brcm.c b/drivers/ata/ahci_brcm.c index 2f16524c252629..ef569eae4ce462 100644 --- a/drivers/ata/ahci_brcm.c +++ b/drivers/ata/ahci_brcm.c @@ -571,7 +571,7 @@ static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume); static struct platform_driver brcm_ahci_driver = { .probe = brcm_ahci_probe, - .remove_new = brcm_ahci_remove, + .remove = brcm_ahci_remove, .shutdown = brcm_ahci_shutdown, .driver = { .name = DRV_NAME, diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c index 11a2c199a7c246..1ec35778903ddc 100644 --- a/drivers/ata/ahci_ceva.c +++ b/drivers/ata/ahci_ceva.c @@ -402,7 +402,7 @@ MODULE_DEVICE_TABLE(of, ceva_ahci_of_match); static struct platform_driver ceva_ahci_driver = { .probe = ceva_ahci_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = ceva_ahci_of_match, diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c index 55a6627d5450e7..ca0924dc5bd26b 100644 --- a/drivers/ata/ahci_da850.c +++ b/drivers/ata/ahci_da850.c @@ -238,7 +238,7 @@ MODULE_DEVICE_TABLE(of, ahci_da850_of_match); static struct platform_driver ahci_da850_driver = { .probe = ahci_da850_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = ahci_da850_of_match, diff --git a/drivers/ata/ahci_dm816.c b/drivers/ata/ahci_dm816.c index 4cb70064fb9944..b08547b877a1f7 100644 --- a/drivers/ata/ahci_dm816.c +++ b/drivers/ata/ahci_dm816.c @@ -182,7 +182,7 @@ MODULE_DEVICE_TABLE(of, ahci_dm816_of_match); static struct platform_driver ahci_dm816_driver = { .probe = ahci_dm816_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = AHCI_DM816_DRV_NAME, .of_match_table = ahci_dm816_of_match, diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c index ed263de3fd7067..aec6d793f51a9c 100644 --- a/drivers/ata/ahci_dwc.c +++ b/drivers/ata/ahci_dwc.c @@ -478,7 +478,7 @@ MODULE_DEVICE_TABLE(of, ahci_dwc_of_match); static struct platform_driver ahci_dwc_driver = { .probe = ahci_dwc_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .shutdown = ahci_platform_shutdown, .driver = { .name = DRV_NAME, diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 6f955e9105e883..f01f08048f97aa 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -511,7 +511,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) { /* - * set PHY Paremeters, two steps to configure the GPR13, + * set PHY Parameters, two steps to configure the GPR13, * one write for rest of parameters, mask of first write * is 0x07ffffff, and the other one write for setting * the mpll_clk_en. @@ -1027,7 +1027,7 @@ static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume); static struct platform_driver imx_ahci_driver = { .probe = imx_ahci_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = imx_ahci_of_match, diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c index adc851cd55789c..7295b9066ae213 100644 --- a/drivers/ata/ahci_mtk.c +++ b/drivers/ata/ahci_mtk.c @@ -174,7 +174,7 @@ MODULE_DEVICE_TABLE(of, ahci_of_match); static struct platform_driver mtk_ahci_driver = { .probe = mtk_ahci_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = ahci_of_match, diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index f3187351e8a6c2..8744dae41612fc 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -245,7 +245,7 @@ MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match); static struct platform_driver ahci_mvebu_driver = { .probe = ahci_mvebu_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .suspend = ahci_mvebu_suspend, .resume = ahci_mvebu_resume, .driver = { diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 81fc63f6b00816..c18054333f7c96 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -96,7 +96,7 @@ MODULE_DEVICE_TABLE(acpi, ahci_acpi_match); static struct platform_driver ahci_driver = { .probe = ahci_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .shutdown = ahci_platform_shutdown, .driver = { .name = DRV_NAME, diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index b1a4e57578e203..30e39885b64edf 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -357,7 +357,7 @@ static SIMPLE_DEV_PM_OPS(ahci_qoriq_pm_ops, ahci_platform_suspend, static struct platform_driver ahci_qoriq_driver = { .probe = ahci_qoriq_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = ahci_qoriq_of_match, diff --git a/drivers/ata/ahci_seattle.c b/drivers/ata/ahci_seattle.c index 59f97aa7ac75c2..3f16c167840222 100644 --- a/drivers/ata/ahci_seattle.c +++ b/drivers/ata/ahci_seattle.c @@ -185,7 +185,7 @@ MODULE_DEVICE_TABLE(acpi, ahci_acpi_match); static struct platform_driver ahci_seattle_driver = { .probe = ahci_seattle_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .acpi_match_table = ahci_acpi_match, diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index 79a8b0aa37bf37..6b9b4a1dfa15bb 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -238,7 +238,7 @@ static struct platform_driver st_ahci_driver = { .of_match_table = st_ahci_match, }, .probe = st_ahci_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, }; module_platform_driver(st_ahci_driver); diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index 58b2683954ddf7..5d4584570ae013 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -292,7 +292,7 @@ MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match); static struct platform_driver ahci_sunxi_driver = { .probe = ahci_sunxi_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = ahci_sunxi_of_match, diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c index 8703c2a4658bb9..44584eed637442 100644 --- a/drivers/ata/ahci_tegra.c +++ b/drivers/ata/ahci_tegra.c @@ -608,7 +608,7 @@ static int tegra_ahci_probe(struct platform_device *pdev) static struct platform_driver tegra_ahci_driver = { .probe = tegra_ahci_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = tegra_ahci_of_match, diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 81a1d838c0fc5e..dfbd8c53abcbd4 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -534,7 +534,7 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class, /** * xgene_ahci_handle_broken_edge_irq - Handle the broken irq. - * @host: Host that recieved the irq + * @host: Host that received the irq * @irq_masked: HOST_IRQ_STAT value * * For hardware with broken edge trigger latch @@ -859,7 +859,7 @@ static int xgene_ahci_probe(struct platform_device *pdev) static struct platform_driver xgene_ahci_driver = { .probe = xgene_ahci_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, .of_match_table = xgene_ahci_of_match, diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index d36e71f475abdc..b7f0bf79552134 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -86,7 +86,7 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev) * @dev: ATA device ACPI event occurred (can be NULL) * @event: ACPI event which occurred * - * All ACPI bay / device realted events end up in this function. If + * All ACPI bay / device related events end up in this function. If * the event is port-wide @dev is NULL. If the event is specific to a * device, @dev points to it. * @@ -832,7 +832,7 @@ void ata_acpi_on_resume(struct ata_port *ap) dev->flags |= ATA_DFLAG_ACPI_PENDING; } } else { - /* SATA _GTF needs to be evaulated after _SDD and + /* SATA _GTF needs to be evaluated after _SDD and * there's no reason to evaluate IDE _GTF early * without _STM. Clear cache and schedule _GTF. */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f915e3df57a9a0..2ce5befd2242be 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1334,17 +1334,8 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc) */ static void scsi_6_lba_len(const u8 *cdb, u64 *plba, u32 *plen) { - u64 lba = 0; - u32 len; - - lba |= ((u64)(cdb[1] & 0x1f)) << 16; - lba |= ((u64)cdb[2]) << 8; - lba |= ((u64)cdb[3]); - - len = cdb[4]; - - *plba = lba; - *plen = len; + *plba = get_unaligned_be24(&cdb[1]) & 0x1fffff; + *plen = cdb[4]; } /** @@ -1781,15 +1772,10 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, return SCSI_MLQUEUE_HOST_BUSY; } -struct ata_scsi_args { - struct ata_device *dev; - u16 *id; - struct scsi_cmnd *cmd; -}; - /** * ata_scsi_rbuf_fill - wrapper for SCSI command simulators - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @actor: Callback hook for desired SCSI command simulator * * Takes care of the hard work of simulating a SCSI command... @@ -1802,30 +1788,32 @@ struct ata_scsi_args { * LOCKING: * spin_lock_irqsave(host lock) */ -static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, - unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf)) +static void ata_scsi_rbuf_fill(struct ata_device *dev, struct scsi_cmnd *cmd, + unsigned int (*actor)(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf)) { - unsigned int rc; - struct scsi_cmnd *cmd = args->cmd; unsigned long flags; + unsigned int len; spin_lock_irqsave(&ata_scsi_rbuf_lock, flags); memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); - rc = actor(args, ata_scsi_rbuf); - if (rc == 0) + len = actor(dev, cmd, ata_scsi_rbuf); + if (len) { sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + cmd->result = SAM_STAT_GOOD; + if (scsi_bufflen(cmd) > len) + scsi_set_resid(cmd, scsi_bufflen(cmd) - len); + } spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); - - if (rc == 0) - cmd->result = SAM_STAT_GOOD; } /** - * ata_scsiop_inq_std - Simulate INQUIRY command - * @args: device IDENTIFY data / SCSI command of interest. + * ata_scsiop_inq_std - Simulate standard INQUIRY command + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns standard device identification data associated @@ -1834,7 +1822,8 @@ static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_std(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { static const u8 versions[] = { 0x00, @@ -1875,40 +1864,45 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) * Set the SCSI Removable Media Bit (RMB) if the ATA removable media * device bit (obsolete since ATA-8 ACS) is set. */ - if (ata_id_removable(args->id)) + if (ata_id_removable(dev->id)) hdr[1] |= (1 << 7); - if (args->dev->class == ATA_DEV_ZAC) { + if (dev->class == ATA_DEV_ZAC) { hdr[0] = TYPE_ZBC; hdr[2] = 0x7; /* claim SPC-5 version compatibility */ } - if (args->dev->flags & ATA_DFLAG_CDL) + if (dev->flags & ATA_DFLAG_CDL) hdr[2] = 0xd; /* claim SPC-6 version compatibility */ memcpy(rbuf, hdr, sizeof(hdr)); memcpy(&rbuf[8], "ATA ", 8); - ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); + ata_id_string(dev->id, &rbuf[16], ATA_ID_PROD, 16); /* From SAT, use last 2 words from fw rev unless they are spaces */ - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV + 2, 4); + ata_id_string(dev->id, &rbuf[32], ATA_ID_FW_REV + 2, 4); if (strncmp(&rbuf[32], " ", 4) == 0) - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); + ata_id_string(dev->id, &rbuf[32], ATA_ID_FW_REV, 4); if (rbuf[32] == 0 || rbuf[32] == ' ') memcpy(&rbuf[32], "n/a ", 4); - if (ata_id_zoned_cap(args->id) || args->dev->class == ATA_DEV_ZAC) + if (ata_id_zoned_cap(dev->id) || dev->class == ATA_DEV_ZAC) memcpy(rbuf + 58, versions_zbc, sizeof(versions_zbc)); else memcpy(rbuf + 58, versions, sizeof(versions)); - return 0; + /* + * Include all 8 possible version descriptors, even if not all of + * them are popoulated. + */ + return 96; } /** * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns list of inquiry VPD pages available. @@ -1916,7 +1910,8 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_00(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { int i, num_pages = 0; static const u8 pages[] = { @@ -1933,18 +1928,20 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) for (i = 0; i < sizeof(pages); i++) { if (pages[i] == 0xb6 && - !(args->dev->flags & ATA_DFLAG_ZAC)) + !(dev->flags & ATA_DFLAG_ZAC)) continue; rbuf[num_pages + 4] = pages[i]; num_pages++; } rbuf[3] = num_pages; /* number of supported VPD pages */ - return 0; + + return get_unaligned_be16(&rbuf[2]) + 4; } /** * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns ATA device serial number. @@ -1952,7 +1949,8 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_80(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { static const u8 hdr[] = { 0, @@ -1962,14 +1960,16 @@ static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) }; memcpy(rbuf, hdr, sizeof(hdr)); - ata_id_string(args->id, (unsigned char *) &rbuf[4], + ata_id_string(dev->id, (unsigned char *) &rbuf[4], ATA_ID_SERNO, ATA_ID_SERNO_LEN); - return 0; + + return get_unaligned_be16(&rbuf[2]) + 4; } /** * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields two logical unit device identification designators: @@ -1980,7 +1980,8 @@ static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_83(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { const int sat_model_serial_desc_len = 68; int num; @@ -1992,7 +1993,7 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) rbuf[num + 0] = 2; rbuf[num + 3] = ATA_ID_SERNO_LEN; num += 4; - ata_id_string(args->id, (unsigned char *) rbuf + num, + ata_id_string(dev->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, ATA_ID_SERNO_LEN); num += ATA_ID_SERNO_LEN; @@ -2004,31 +2005,33 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) num += 4; memcpy(rbuf + num, "ATA ", 8); num += 8; - ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_PROD, + ata_id_string(dev->id, (unsigned char *) rbuf + num, ATA_ID_PROD, ATA_ID_PROD_LEN); num += ATA_ID_PROD_LEN; - ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, + ata_id_string(dev->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, ATA_ID_SERNO_LEN); num += ATA_ID_SERNO_LEN; - if (ata_id_has_wwn(args->id)) { + if (ata_id_has_wwn(dev->id)) { /* SAT defined lu world wide name */ /* piv=0, assoc=lu, code_set=binary, designator=NAA */ rbuf[num + 0] = 1; rbuf[num + 1] = 3; rbuf[num + 3] = ATA_ID_WWN_LEN; num += 4; - ata_id_string(args->id, (unsigned char *) rbuf + num, + ata_id_string(dev->id, (unsigned char *) rbuf + num, ATA_ID_WWN, ATA_ID_WWN_LEN); num += ATA_ID_WWN_LEN; } rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */ - return 0; + + return get_unaligned_be16(&rbuf[2]) + 4; } /** * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields SAT-specified ATA VPD page. @@ -2036,7 +2039,8 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_inq_89(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { rbuf[1] = 0x89; /* our page code */ rbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ @@ -2057,13 +2061,25 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) rbuf[56] = ATA_CMD_ID_ATA; - memcpy(&rbuf[60], &args->id[0], 512); - return 0; + memcpy(&rbuf[60], &dev->id[0], 512); + + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b0 - Simulate INQUIRY VPD page B0, Block Limits + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B0h (Block Limits). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b0(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_device *dev = args->dev; u16 min_io_sectors; rbuf[1] = 0xb0; @@ -2076,7 +2092,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) * logical than physical sector size we need to figure out what the * latter is. */ - min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id); + min_io_sectors = 1 << ata_id_log2_per_physical_sector(dev->id); put_unaligned_be16(min_io_sectors, &rbuf[6]); /* @@ -2088,7 +2104,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) * that we support some form of unmap - in thise case via WRITE SAME * with the unmap bit set. */ - if (ata_id_has_trim(args->id)) { + if (ata_id_has_trim(dev->id)) { u64 max_blocks = 65535 * ATA_MAX_TRIM_RNUM; if (dev->quirks & ATA_QUIRK_MAX_TRIM_128M) @@ -2098,14 +2114,27 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf) put_unaligned_be32(1, &rbuf[28]); } - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b1 - Simulate INQUIRY VPD page B1, Block Device + * Characteristics + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B1h (Block Device Characteristics). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b1(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - int form_factor = ata_id_form_factor(args->id); - int media_rotation_rate = ata_id_rotation_rate(args->id); - u8 zoned = ata_id_zoned_cap(args->id); + int form_factor = ata_id_form_factor(dev->id); + int media_rotation_rate = ata_id_rotation_rate(dev->id); + u8 zoned = ata_id_zoned_cap(dev->id); rbuf[1] = 0xb1; rbuf[3] = 0x3c; @@ -2115,21 +2144,52 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf) if (zoned) rbuf[8] = (zoned << 4); - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b2 - Simulate INQUIRY VPD page B2, Logical Block + * Provisioning + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B2h (Logical Block Provisioning). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b2(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { /* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */ rbuf[1] = 0xb2; rbuf[3] = 0x4; rbuf[5] = 1 << 6; /* TPWS */ - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b6 - Simulate INQUIRY VPD page B6, Zoned Block Device + * Characteristics + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B2h (Zoned Block Device Characteristics). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b6(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { + if (!(dev->flags & ATA_DFLAG_ZAC)) { + ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); + return 0; + } + /* * zbc-r05 SCSI Zoned Block device characteristics VPD page */ @@ -2139,21 +2199,39 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf) /* * URSWRZ bit is only meaningful for host-managed ZAC drives */ - if (args->dev->zac_zoned_cap & 1) + if (dev->zac_zoned_cap & 1) rbuf[4] |= 1; - put_unaligned_be32(args->dev->zac_zones_optimal_open, &rbuf[8]); - put_unaligned_be32(args->dev->zac_zones_optimal_nonseq, &rbuf[12]); - put_unaligned_be32(args->dev->zac_zones_max_open, &rbuf[16]); + put_unaligned_be32(dev->zac_zones_optimal_open, &rbuf[8]); + put_unaligned_be32(dev->zac_zones_optimal_nonseq, &rbuf[12]); + put_unaligned_be32(dev->zac_zones_max_open, &rbuf[16]); - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; } -static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf) +/** + * ata_scsiop_inq_b9 - Simulate INQUIRY VPD page B9, Concurrent Positioning + * Ranges + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Return data for the VPD page B9h (Concurrent Positioning Ranges). + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inq_b9(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_cpr_log *cpr_log = args->dev->cpr_log; + struct ata_cpr_log *cpr_log = dev->cpr_log; u8 *desc = &rbuf[64]; int i; + if (!cpr_log) { + ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); + return 0; + } + /* SCSI Concurrent Positioning Ranges VPD page: SBC-5 rev 1 or later */ rbuf[1] = 0xb9; put_unaligned_be16(64 + (int)cpr_log->nr_cpr * 32 - 4, &rbuf[2]); @@ -2165,7 +2243,58 @@ static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf) put_unaligned_be64(cpr_log->cpr[i].num_lbas, &desc[16]); } - return 0; + return get_unaligned_be16(&rbuf[2]) + 4; +} + +/** + * ata_scsiop_inquiry - Simulate INQUIRY command + * @dev: Target device. + * @cmd: SCSI command of interest. + * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. + * + * Returns data associated with an INQUIRY command output. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ +static unsigned int ata_scsiop_inquiry(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) +{ + const u8 *scsicmd = cmd->cmnd; + + /* is CmdDt set? */ + if (scsicmd[1] & 2) { + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; + } + + /* Is EVPD clear? */ + if ((scsicmd[1] & 1) == 0) + return ata_scsiop_inq_std(dev, cmd, rbuf); + + switch (scsicmd[2]) { + case 0x00: + return ata_scsiop_inq_00(dev, cmd, rbuf); + case 0x80: + return ata_scsiop_inq_80(dev, cmd, rbuf); + case 0x83: + return ata_scsiop_inq_83(dev, cmd, rbuf); + case 0x89: + return ata_scsiop_inq_89(dev, cmd, rbuf); + case 0xb0: + return ata_scsiop_inq_b0(dev, cmd, rbuf); + case 0xb1: + return ata_scsiop_inq_b1(dev, cmd, rbuf); + case 0xb2: + return ata_scsiop_inq_b2(dev, cmd, rbuf); + case 0xb6: + return ata_scsiop_inq_b6(dev, cmd, rbuf); + case 0xb9: + return ata_scsiop_inq_b9(dev, cmd, rbuf); + default: + ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); + return 0; + } } /** @@ -2388,7 +2517,8 @@ static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable) /** * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate MODE SENSE commands. Assume this is invoked for direct @@ -2398,10 +2528,10 @@ static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_mode_sense(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_device *dev = args->dev; - u8 *scsicmd = args->cmd->cmnd, *p = rbuf; + u8 *scsicmd = cmd->cmnd, *p = rbuf; static const u8 sat_blk_desc[] = { 0, 0, 0, 0, /* number of blocks: sat unspecified */ 0, @@ -2466,17 +2596,17 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) break; case CACHE_MPAGE: - p += ata_msense_caching(args->id, p, page_control == 1); + p += ata_msense_caching(dev->id, p, page_control == 1); break; case CONTROL_MPAGE: - p += ata_msense_control(args->dev, p, spg, page_control == 1); + p += ata_msense_control(dev, p, spg, page_control == 1); break; case ALL_MPAGES: p += ata_msense_rw_recovery(p, page_control == 1); - p += ata_msense_caching(args->id, p, page_control == 1); - p += ata_msense_control(args->dev, p, spg, page_control == 1); + p += ata_msense_caching(dev->id, p, page_control == 1); + p += ata_msense_control(dev, p, spg, page_control == 1); break; default: /* invalid page code */ @@ -2494,29 +2624,33 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) rbuf[3] = sizeof(sat_blk_desc); memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc)); } - } else { - put_unaligned_be16(p - rbuf - 2, &rbuf[0]); - rbuf[3] |= dpofua; - if (ebd) { - rbuf[7] = sizeof(sat_blk_desc); - memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc)); - } + + return rbuf[0] + 1; } - return 0; + + put_unaligned_be16(p - rbuf - 2, &rbuf[0]); + rbuf[3] |= dpofua; + if (ebd) { + rbuf[7] = sizeof(sat_blk_desc); + memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc)); + } + + return get_unaligned_be16(&rbuf[0]) + 2; invalid_fld: - ata_scsi_set_invalid_field(dev, args->cmd, fp, bp); - return 1; + ata_scsi_set_invalid_field(dev, cmd, fp, bp); + return 0; saving_not_supp: - ata_scsi_set_sense(dev, args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); + ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x39, 0x0); /* "Saving parameters not supported" */ - return 1; + return 0; } /** * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate READ CAPACITY commands. @@ -2524,9 +2658,10 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * None. */ -static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_read_cap(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_device *dev = args->dev; + u8 *scsicmd = cmd->cmnd; u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */ u32 sector_size; /* physical sector size in bytes */ u8 log2_per_phys; @@ -2536,7 +2671,7 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) log2_per_phys = ata_id_log2_per_physical_sector(dev->id); lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys); - if (args->cmd->cmnd[0] == READ_CAPACITY) { + if (scsicmd[0] == READ_CAPACITY) { if (last_lba >= 0xffffffffULL) last_lba = 0xffffffff; @@ -2551,48 +2686,59 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[5] = sector_size >> (8 * 2); rbuf[6] = sector_size >> (8 * 1); rbuf[7] = sector_size; - } else { - /* sector count, 64-bit */ - rbuf[0] = last_lba >> (8 * 7); - rbuf[1] = last_lba >> (8 * 6); - rbuf[2] = last_lba >> (8 * 5); - rbuf[3] = last_lba >> (8 * 4); - rbuf[4] = last_lba >> (8 * 3); - rbuf[5] = last_lba >> (8 * 2); - rbuf[6] = last_lba >> (8 * 1); - rbuf[7] = last_lba; - /* sector size */ - rbuf[ 8] = sector_size >> (8 * 3); - rbuf[ 9] = sector_size >> (8 * 2); - rbuf[10] = sector_size >> (8 * 1); - rbuf[11] = sector_size; - - rbuf[12] = 0; - rbuf[13] = log2_per_phys; - rbuf[14] = (lowest_aligned >> 8) & 0x3f; - rbuf[15] = lowest_aligned; - - if (ata_id_has_trim(args->id) && - !(dev->quirks & ATA_QUIRK_NOTRIM)) { - rbuf[14] |= 0x80; /* LBPME */ - - if (ata_id_has_zero_after_trim(args->id) && - dev->quirks & ATA_QUIRK_ZERO_AFTER_TRIM) { - ata_dev_info(dev, "Enabling discard_zeroes_data\n"); - rbuf[14] |= 0x40; /* LBPRZ */ - } + return 8; + } + + /* + * READ CAPACITY 16 command is defined as a service action + * (SERVICE_ACTION_IN_16 command). + */ + if (scsicmd[0] != SERVICE_ACTION_IN_16 || + (scsicmd[1] & 0x1f) != SAI_READ_CAPACITY_16) { + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; + } + + /* sector count, 64-bit */ + rbuf[0] = last_lba >> (8 * 7); + rbuf[1] = last_lba >> (8 * 6); + rbuf[2] = last_lba >> (8 * 5); + rbuf[3] = last_lba >> (8 * 4); + rbuf[4] = last_lba >> (8 * 3); + rbuf[5] = last_lba >> (8 * 2); + rbuf[6] = last_lba >> (8 * 1); + rbuf[7] = last_lba; + + /* sector size */ + rbuf[ 8] = sector_size >> (8 * 3); + rbuf[ 9] = sector_size >> (8 * 2); + rbuf[10] = sector_size >> (8 * 1); + rbuf[11] = sector_size; + + if (ata_id_zoned_cap(dev->id) || dev->class == ATA_DEV_ZAC) + rbuf[12] = (1 << 4); /* RC_BASIS */ + rbuf[13] = log2_per_phys; + rbuf[14] = (lowest_aligned >> 8) & 0x3f; + rbuf[15] = lowest_aligned; + + if (ata_id_has_trim(dev->id) && !(dev->quirks & ATA_QUIRK_NOTRIM)) { + rbuf[14] |= 0x80; /* LBPME */ + + if (ata_id_has_zero_after_trim(dev->id) && + dev->quirks & ATA_QUIRK_ZERO_AFTER_TRIM) { + ata_dev_info(dev, "Enabling discard_zeroes_data\n"); + rbuf[14] |= 0x40; /* LBPRZ */ } - if (ata_id_zoned_cap(args->id) || - args->dev->class == ATA_DEV_ZAC) - rbuf[12] = (1 << 4); /* RC_BASIS */ } - return 0; + + return 16; } /** * ata_scsiop_report_luns - Simulate REPORT LUNS command - * @args: device IDENTIFY data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate REPORT LUNS command. @@ -2600,11 +2746,12 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_report_luns(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */ - return 0; + return 16; } /* @@ -3312,7 +3459,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) /** * ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN - * @args: device MAINTENANCE_IN data / SCSI command of interest. + * @dev: Target device. + * @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields a subset to satisfy scsi_report_opcode() @@ -3320,17 +3468,21 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc) * LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) +static unsigned int ata_scsiop_maint_in(struct ata_device *dev, + struct scsi_cmnd *cmd, u8 *rbuf) { - struct ata_device *dev = args->dev; - u8 *cdb = args->cmd->cmnd; + u8 *cdb = cmd->cmnd; u8 supported = 0, cdlp = 0, rwcdlp = 0; - unsigned int err = 0; + + if ((cdb[1] & 0x1f) != MI_REPORT_SUPPORTED_OPERATION_CODES) { + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; + } if (cdb[2] != 1 && cdb[2] != 3) { ata_dev_warn(dev, "invalid command format %d\n", cdb[2]); - err = 2; - goto out; + ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + return 0; } switch (cdb[3]) { @@ -3398,11 +3550,12 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) default: break; } -out: + /* One command format */ rbuf[0] = rwcdlp; rbuf[1] = cdlp | supported; - return err; + + return 4; } /** @@ -4262,78 +4415,26 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) { - struct ata_scsi_args args; const u8 *scsicmd = cmd->cmnd; u8 tmp8; - args.dev = dev; - args.id = dev->id; - args.cmd = cmd; - switch(scsicmd[0]) { case INQUIRY: - if (scsicmd[1] & 2) /* is CmdDt set? */ - ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); - else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); - else switch (scsicmd[2]) { - case 0x00: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00); - break; - case 0x80: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80); - break; - case 0x83: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); - break; - case 0x89: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89); - break; - case 0xb0: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b0); - break; - case 0xb1: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1); - break; - case 0xb2: - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2); - break; - case 0xb6: - if (dev->flags & ATA_DFLAG_ZAC) - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b6); - else - ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); - break; - case 0xb9: - if (dev->cpr_log) - ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b9); - else - ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); - break; - default: - ata_scsi_set_invalid_field(dev, cmd, 2, 0xff); - break; - } + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_inquiry); break; case MODE_SENSE: case MODE_SENSE_10: - ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense); + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_mode_sense); break; case READ_CAPACITY: - ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); - break; - case SERVICE_ACTION_IN_16: - if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) - ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); - else - ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_read_cap); break; case REPORT_LUNS: - ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_report_luns); break; case REQUEST_SENSE: @@ -4361,10 +4462,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) break; case MAINTENANCE_IN: - if ((scsicmd[1] & 0x1f) == MI_REPORT_SUPPORTED_OPERATION_CODES) - ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in); - else - ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); + ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_maint_in); break; /* all other commands */ diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index d0c6924d25b67f..514d549286b56e 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -964,7 +964,7 @@ MODULE_DEVICE_TABLE(of, arasan_cf_id_table); static struct platform_driver arasan_cf_driver = { .probe = arasan_cf_probe, - .remove_new = arasan_cf_remove, + .remove = arasan_cf_remove, .driver = { .name = DRIVER_NAME, .pm = &arasan_cf_pm_ops, diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index f3f5b2b0ecc9f1..e8cda988feb503 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -1015,7 +1015,7 @@ static struct platform_driver ep93xx_pata_platform_driver = { .of_match_table = ep93xx_pata_of_ids, }, .probe = ep93xx_pata_probe, - .remove_new = ep93xx_pata_remove, + .remove = ep93xx_pata_remove, }; module_platform_driver(ep93xx_pata_platform_driver); diff --git a/drivers/ata/pata_falcon.c b/drivers/ata/pata_falcon.c index 18ceefd176df0f..334c4eea41ec0a 100644 --- a/drivers/ata/pata_falcon.c +++ b/drivers/ata/pata_falcon.c @@ -225,8 +225,8 @@ static void pata_falcon_remove_one(struct platform_device *pdev) static struct platform_driver pata_falcon_driver = { .probe = pata_falcon_init_one, - .remove_new = pata_falcon_remove_one, - .driver = { + .remove = pata_falcon_remove_one, + .driver = { .name = "atari-falcon-ide", }, }; diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c index 73a9a5109238b3..c3a8384c3e04d4 100644 --- a/drivers/ata/pata_ftide010.c +++ b/drivers/ata/pata_ftide010.c @@ -557,7 +557,7 @@ static struct platform_driver pata_ftide010_driver = { .of_match_table = pata_ftide010_of_match, }, .probe = pata_ftide010_probe, - .remove_new = pata_ftide010_remove, + .remove = pata_ftide010_remove, }; module_platform_driver(pata_ftide010_driver); diff --git a/drivers/ata/pata_gayle.c b/drivers/ata/pata_gayle.c index 94df60ac230782..8602c388994863 100644 --- a/drivers/ata/pata_gayle.c +++ b/drivers/ata/pata_gayle.c @@ -202,9 +202,9 @@ static void pata_gayle_remove_one(struct platform_device *pdev) static struct platform_driver pata_gayle_driver = { .probe = pata_gayle_init_one, - .remove_new = pata_gayle_remove_one, - .driver = { - .name = "amiga-gayle-ide", + .remove = pata_gayle_remove_one, + .driver = { + .name = "amiga-gayle-ide", }, }; diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index d0aa8fc929b450..b37682b0578f48 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -249,7 +249,7 @@ MODULE_DEVICE_TABLE(of, imx_pata_dt_ids); static struct platform_driver pata_imx_driver = { .probe = pata_imx_probe, - .remove_new = pata_imx_remove, + .remove = pata_imx_remove, .driver = { .name = DRV_NAME, .of_match_table = imx_pata_dt_ids, diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index b7ac56103c8a3f..9cbe2132ce59b9 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -81,7 +81,7 @@ static void it8213_set_piomode (struct ata_port *ap, struct ata_device *adev) int control = 0; /* - * See Intel Document 298600-004 for the timing programing rules + * See Intel Document 298600-004 for the timing programming rules * for PIIX/ICH. The 8213 is a clone so very similar */ diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 8a9ee828478f01..80f6a91acf6f50 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -298,7 +298,7 @@ static struct platform_driver ixp4xx_pata_platform_driver = { .of_match_table = ixp4xx_pata_of_match, }, .probe = ixp4xx_pata_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, }; module_platform_driver(ixp4xx_pata_platform_driver); diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 3f92586779156a..210a63283f62be 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -854,7 +854,7 @@ static const struct of_device_id mpc52xx_ata_of_match[] = { static struct platform_driver mpc52xx_ata_of_platform_driver = { .probe = mpc52xx_ata_probe, - .remove_new = mpc52xx_ata_remove, + .remove = mpc52xx_ata_remove, #ifdef CONFIG_PM_SLEEP .suspend = mpc52xx_ata_suspend, .resume = mpc52xx_ata_resume, diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c index 0bb9607e734863..dce24806a05297 100644 --- a/drivers/ata/pata_octeon_cf.c +++ b/drivers/ata/pata_octeon_cf.c @@ -183,7 +183,7 @@ static void octeon_cf_set_piomode(struct ata_port *ap, struct ata_device *dev) reg_tim.s.ale = 0; /* Not used */ reg_tim.s.page = 0; - /* Time after IORDY to coninue to assert the data */ + /* Time after IORDY to continue to assert the data */ reg_tim.s.wait = 0; /* Time to wait to complete the cycle. */ reg_tim.s.pause = pause; diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index 4956f0f5b93fad..178b28eff170a9 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -89,7 +89,7 @@ static struct platform_driver pata_of_platform_driver = { .of_match_table = pata_of_platform_match, }, .probe = pata_of_platform_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, }; module_platform_driver(pata_of_platform_driver); diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index dca82d92b004f3..3d01b7000e41cb 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -70,7 +70,7 @@ static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev) int control = 0; /* - * See Intel Document 298600-004 for the timing programing rules + * See Intel Document 298600-004 for the timing programming rules * for PIIX/ICH. Note that the early PIIX does not have the slave * timing port at 0x44. */ diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 232c3dad7ee88a..87479bc893b252 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -223,7 +223,7 @@ static int pata_platform_probe(struct platform_device *pdev) static struct platform_driver pata_platform_driver = { .probe = pata_platform_probe, - .remove_new = ata_platform_remove_one, + .remove = ata_platform_remove_one, .driver = { .name = DRV_NAME, }, diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c index 538bd3423d859d..434f380114af09 100644 --- a/drivers/ata/pata_pxa.c +++ b/drivers/ata/pata_pxa.c @@ -306,7 +306,7 @@ static void pxa_ata_remove(struct platform_device *pdev) static struct platform_driver pxa_ata_driver = { .probe = pxa_ata_probe, - .remove_new = pxa_ata_remove, + .remove = pxa_ata_remove, .driver = { .name = DRV_NAME, }, diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 84b00109709379..40ef8072c1592a 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -45,7 +45,7 @@ static void radisys_set_piomode (struct ata_port *ap, struct ata_device *adev) int control = 0; /* - * See Intel Document 298600-004 for the timing programing rules + * See Intel Document 298600-004 for the timing programming rules * for PIIX/ICH. Note that the early PIIX does not have the slave * timing port at 0x44. The Radisys is a relative of the PIIX * but not the same so be careful. diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 0fa253ad7c93e6..fd81e75c940237 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -164,7 +164,7 @@ static void rb532_pata_driver_remove(struct platform_device *pdev) static struct platform_driver rb532_pata_platform_driver = { .probe = rb532_pata_driver_probe, - .remove_new = rb532_pata_driver_remove, + .remove = rb532_pata_driver_remove, .driver = { .name = DRV_NAME, }, diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c index 52f5168e4db542..6e1dd0d9c03529 100644 --- a/drivers/ata/sata_dwc_460ex.c +++ b/drivers/ata/sata_dwc_460ex.c @@ -1240,7 +1240,7 @@ static struct platform_driver sata_dwc_driver = { .of_match_table = sata_dwc_match, }, .probe = sata_dwc_probe, - .remove_new = sata_dwc_remove, + .remove = sata_dwc_remove, }; module_platform_driver(sata_dwc_driver); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 01aa05f4c3f5cd..87e91a937a44a1 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1589,7 +1589,7 @@ static struct platform_driver fsl_sata_driver = { .of_match_table = fsl_sata_match, }, .probe = sata_fsl_probe, - .remove_new = sata_fsl_remove, + .remove = sata_fsl_remove, #ifdef CONFIG_PM_SLEEP .suspend = sata_fsl_suspend, .resume = sata_fsl_resume, diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c index f574e3c3f5b48f..d040799bf9cb71 100644 --- a/drivers/ata/sata_gemini.c +++ b/drivers/ata/sata_gemini.c @@ -425,7 +425,7 @@ static struct platform_driver gemini_sata_driver = { .of_match_table = gemini_sata_of_match, }, .probe = gemini_sata_probe, - .remove_new = gemini_sata_remove, + .remove = gemini_sata_remove, }; module_platform_driver(gemini_sata_driver); diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 63ef7bb073ce03..c8c817c51230a7 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -348,6 +348,7 @@ static int highbank_initialize_phys(struct device *dev, void __iomem *addr) phy_nodes[phy] = phy_data.np; cphy_base[phy] = of_iomap(phy_nodes[phy], 0); if (cphy_base[phy] == NULL) { + of_node_put(phy_data.np); return 0; } phy_count += 1; @@ -614,12 +615,12 @@ static SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops, ahci_highbank_suspend, ahci_highbank_resume); static struct platform_driver ahci_highbank_driver = { - .remove_new = ata_platform_remove_one, - .driver = { - .name = "highbank-ahci", - .of_match_table = ahci_of_match, - .pm = &ahci_highbank_pm_ops, - }, + .remove = ata_platform_remove_one, + .driver = { + .name = "highbank-ahci", + .of_match_table = ahci_of_match, + .pm = &ahci_highbank_pm_ops, + }, .probe = ahci_highbank_probe, }; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 05c905827dc5c6..b8f363370e1aa4 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4255,7 +4255,7 @@ MODULE_DEVICE_TABLE(of, mv_sata_dt_ids); static struct platform_driver mv_platform_driver = { .probe = mv_platform_probe, - .remove_new = mv_platform_remove, + .remove = mv_platform_remove, .suspend = mv_platform_suspend, .resume = mv_platform_resume, .driver = { diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index c1469d07688019..22820a02d74080 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -1009,7 +1009,7 @@ static const struct dev_pm_ops sata_rcar_pm_ops = { static struct platform_driver sata_rcar_driver = { .probe = sata_rcar_probe, - .remove_new = sata_rcar_remove, + .remove = sata_rcar_remove, .driver = { .name = DRV_NAME, .of_match_table = sata_rcar_match, diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index cb00f8244e4110..4fea1149e00371 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2569,7 +2569,7 @@ static struct platform_driver fore200e_sba_driver = { .of_match_table = fore200e_sba_match, }, .probe = fore200e_sba_probe, - .remove_new = fore200e_sba_remove, + .remove = fore200e_sba_remove, }; #endif diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 21545ffba0658f..8934e6ad5772b4 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -489,7 +489,7 @@ config IMG_ASCII_LCD config HT16K33 tristate "Holtek Ht16K33 LED controller with keyscan" - depends on FB && I2C && INPUT + depends on FB && I2C && INPUT && BACKLIGHT_CLASS_DEVICE select FB_SYSMEM_HELPERS select INPUT_MATRIXKMAP select FB_BACKLIGHT diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c index 6526aa51fb1d75..e1a94ae3eb0c36 100644 --- a/drivers/auxdisplay/cfag12864b.c +++ b/drivers/auxdisplay/cfag12864b.c @@ -37,11 +37,6 @@ module_param(cfag12864b_rate, uint, 0444); MODULE_PARM_DESC(cfag12864b_rate, "Refresh rate (hertz)"); -unsigned int cfag12864b_getrate(void) -{ - return cfag12864b_rate; -} - /* * cfag12864b Commands * @@ -249,11 +244,6 @@ void cfag12864b_disable(void) mutex_unlock(&cfag12864b_mutex); } -unsigned char cfag12864b_isenabled(void) -{ - return cfag12864b_updating; -} - static void cfag12864b_update(struct work_struct *work) { unsigned char c; @@ -293,10 +283,8 @@ static void cfag12864b_update(struct work_struct *work) */ EXPORT_SYMBOL_GPL(cfag12864b_buffer); -EXPORT_SYMBOL_GPL(cfag12864b_getrate); EXPORT_SYMBOL_GPL(cfag12864b_enable); EXPORT_SYMBOL_GPL(cfag12864b_disable); -EXPORT_SYMBOL_GPL(cfag12864b_isenabled); /* * Is the module inited? diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c index 2b74dabe7e1757..24baf6b2c58764 100644 --- a/drivers/auxdisplay/cfag12864bfb.c +++ b/drivers/auxdisplay/cfag12864bfb.c @@ -108,7 +108,7 @@ static void cfag12864bfb_remove(struct platform_device *device) static struct platform_driver cfag12864bfb_driver = { .probe = cfag12864bfb_probe, - .remove_new = cfag12864bfb_remove, + .remove = cfag12864bfb_remove, .driver = { .name = CFAG12864BFB_NAME, }, diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c index 025dc6855cb253..0526f0d90a793e 100644 --- a/drivers/auxdisplay/hd44780.c +++ b/drivers/auxdisplay/hd44780.c @@ -339,7 +339,7 @@ MODULE_DEVICE_TABLE(of, hd44780_of_match); static struct platform_driver hd44780_driver = { .probe = hd44780_probe, - .remove_new = hd44780_remove, + .remove = hd44780_remove, .driver = { .name = "hd44780", .of_match_table = hd44780_of_match, diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index a816f9e1025595..0b8ba754b3430a 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -657,7 +657,6 @@ static int ht16k33_seg_probe(struct device *dev, struct ht16k33_priv *priv, static int ht16k33_probe(struct i2c_client *client) { struct device *dev = &client->dev; - const struct of_device_id *id; struct ht16k33_priv *priv; uint32_t dft_brightness; int err; @@ -672,9 +671,8 @@ static int ht16k33_probe(struct i2c_client *client) return -ENOMEM; priv->client = client; - id = i2c_of_match_device(dev->driver->of_match_table, client); - if (id) - priv->type = (uintptr_t)id->data; + priv->type = (uintptr_t)i2c_get_match_data(client); + i2c_set_clientdata(client, priv); err = ht16k33_initialize(priv); @@ -747,7 +745,9 @@ static void ht16k33_remove(struct i2c_client *client) } static const struct i2c_device_id ht16k33_i2c_match[] = { - { "ht16k33", 0 }, + { "3108", DISP_QUAD_7SEG }, + { "3130", DISP_QUAD_14SEG }, + { "ht16k33", DISP_MATRIX }, { } }; MODULE_DEVICE_TABLE(i2c, ht16k33_i2c_match); @@ -780,5 +780,5 @@ module_i2c_driver(ht16k33_driver); MODULE_DESCRIPTION("Holtek HT16K33 driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(LINEDISP); +MODULE_IMPORT_NS("LINEDISP"); MODULE_AUTHOR("Robin van der Gracht "); diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c index 9ba132dc6143ad..a802678a6f7448 100644 --- a/drivers/auxdisplay/img-ascii-lcd.c +++ b/drivers/auxdisplay/img-ascii-lcd.c @@ -291,11 +291,11 @@ static struct platform_driver img_ascii_lcd_driver = { .of_match_table = img_ascii_lcd_matches, }, .probe = img_ascii_lcd_probe, - .remove_new = img_ascii_lcd_remove, + .remove = img_ascii_lcd_remove, }; module_platform_driver(img_ascii_lcd_driver); MODULE_DESCRIPTION("Imagination Technologies ASCII LCD Display"); MODULE_AUTHOR("Paul Burton "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(LINEDISP); +MODULE_IMPORT_NS("LINEDISP"); diff --git a/drivers/auxdisplay/lcd2s.c b/drivers/auxdisplay/lcd2s.c index 6422be0dfe20e6..a28daa4ffbf752 100644 --- a/drivers/auxdisplay/lcd2s.c +++ b/drivers/auxdisplay/lcd2s.c @@ -349,7 +349,7 @@ static void lcd2s_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id lcd2s_i2c_id[] = { - { "lcd2s", 0 }, + { "lcd2s" }, { } }; MODULE_DEVICE_TABLE(i2c, lcd2s_i2c_id); diff --git a/drivers/auxdisplay/line-display.c b/drivers/auxdisplay/line-display.c index 731ffdfafc4ed9..fcec77f100ce94 100644 --- a/drivers/auxdisplay/line-display.c +++ b/drivers/auxdisplay/line-display.c @@ -381,7 +381,7 @@ int linedisp_register(struct linedisp *linedisp, struct device *parent, put_device(&linedisp->dev); return err; } -EXPORT_SYMBOL_NS_GPL(linedisp_register, LINEDISP); +EXPORT_SYMBOL_NS_GPL(linedisp_register, "LINEDISP"); /** * linedisp_unregister - unregister a character line display @@ -394,7 +394,7 @@ void linedisp_unregister(struct linedisp *linedisp) del_timer_sync(&linedisp->timer); put_device(&linedisp->dev); } -EXPORT_SYMBOL_NS_GPL(linedisp_unregister, LINEDISP); +EXPORT_SYMBOL_NS_GPL(linedisp_unregister, "LINEDISP"); MODULE_DESCRIPTION("Character line display core support"); MODULE_LICENSE("GPL"); diff --git a/drivers/auxdisplay/max6959.c b/drivers/auxdisplay/max6959.c index 5519c014bd2950..962488197b9e97 100644 --- a/drivers/auxdisplay/max6959.c +++ b/drivers/auxdisplay/max6959.c @@ -191,4 +191,4 @@ module_i2c_driver(max6959_i2c_driver); MODULE_DESCRIPTION("MAX6958/6959 7-segment LED controller"); MODULE_AUTHOR("Andy Shevchenko "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(LINEDISP); +MODULE_IMPORT_NS("LINEDISP"); diff --git a/drivers/auxdisplay/seg-led-gpio.c b/drivers/auxdisplay/seg-led-gpio.c index 183ab3011cbb19..f10c25e6bf126c 100644 --- a/drivers/auxdisplay/seg-led-gpio.c +++ b/drivers/auxdisplay/seg-led-gpio.c @@ -97,7 +97,7 @@ MODULE_DEVICE_TABLE(of, seg_led_of_match); static struct platform_driver seg_led_driver = { .probe = seg_led_probe, - .remove_new = seg_led_remove, + .remove = seg_led_remove, .driver = { .name = "seg-led-gpio", .of_match_table = seg_led_of_match, @@ -108,4 +108,4 @@ module_platform_driver(seg_led_driver); MODULE_AUTHOR("Chris Packham "); MODULE_DESCRIPTION("7 segment LED driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(LINEDISP); +MODULE_IMPORT_NS("LINEDISP"); diff --git a/drivers/base/arch_numa.c b/drivers/base/arch_numa.c index e1870167642658..c99f2ab105e5b7 100644 --- a/drivers/base/arch_numa.c +++ b/drivers/base/arch_numa.c @@ -208,6 +208,10 @@ static int __init numa_register_nodes(void) { int nid; + /* Check the validity of the memblock/node mapping */ + if (!memblock_validate_numa_coverage(0)) + return -EINVAL; + /* Finally register nodes. */ for_each_node_mask(nid, numa_nodes_parsed) { unsigned long start_pfn, end_pfn; diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c index 7823888af4f684..afa4df4c5a3f37 100644 --- a/drivers/base/auxiliary.c +++ b/drivers/base/auxiliary.c @@ -92,7 +92,7 @@ * Auxiliary devices are created and registered by a subsystem-level core * device that needs to break up its functionality into smaller fragments. One * way to extend the scope of an auxiliary_device is to encapsulate it within a - * domain- pecific structure defined by the parent device. This structure + * domain-specific structure defined by the parent device. This structure * contains the auxiliary_device and any associated shared data/callbacks * needed to establish the connection with the parent. * @@ -335,35 +335,6 @@ int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname) } EXPORT_SYMBOL_GPL(__auxiliary_device_add); -/** - * auxiliary_find_device - auxiliary device iterator for locating a particular device. - * @start: Device to begin with - * @data: Data to pass to match function - * @match: Callback function to check device - * - * This function returns a reference to a device that is 'found' - * for later use, as determined by the @match callback. - * - * The reference returned should be released with put_device(). - * - * The callback should return 0 if the device doesn't match and non-zero - * if it does. If the callback returns non-zero, this function will - * return to the caller and not iterate over any more devices. - */ -struct auxiliary_device *auxiliary_find_device(struct device *start, - const void *data, - device_match_t match) -{ - struct device *dev; - - dev = bus_find_device(&auxiliary_bus_type, start, data, match); - if (!dev) - return NULL; - - return to_auxiliary_dev(dev); -} -EXPORT_SYMBOL_GPL(auxiliary_find_device); - /** * __auxiliary_driver_register - register a driver for auxiliary bus devices * @auxdrv: auxiliary_driver structure diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 7a7609298e18bd..cf0d455209d7fc 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -58,7 +58,7 @@ bool last_level_cache_is_valid(unsigned int cpu) { struct cacheinfo *llc; - if (!cache_leaves(cpu)) + if (!cache_leaves(cpu) || !per_cpu_cacheinfo(cpu)) return false; llc = per_cpu_cacheinfo_idx(cpu, cache_leaves(cpu) - 1); @@ -254,11 +254,11 @@ static int of_count_cache_leaves(struct device_node *np) { unsigned int leaves = 0; - if (of_property_read_bool(np, "cache-size")) + if (of_property_present(np, "cache-size")) ++leaves; - if (of_property_read_bool(np, "i-cache-size")) + if (of_property_present(np, "i-cache-size")) ++leaves; - if (of_property_read_bool(np, "d-cache-size")) + if (of_property_present(np, "d-cache-size")) ++leaves; if (!leaves) { @@ -367,9 +367,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); for_each_online_cpu(i) { - struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i); - - if (i == cpu || !sib_cpu_ci->info_list) + if (i == cpu || !per_cpu_cacheinfo(i)) 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); @@ -409,10 +407,7 @@ static void cache_shared_cpu_map_remove(unsigned int cpu) for (index = 0; index < cache_leaves(cpu); index++) { this_leaf = per_cpu_cacheinfo_idx(cpu, index); for_each_cpu(sibling, &this_leaf->shared_cpu_map) { - struct cpu_cacheinfo *sib_cpu_ci = - get_cpu_cacheinfo(sibling); - - if (sibling == cpu || !sib_cpu_ci->info_list) + if (sibling == cpu || !per_cpu_cacheinfo(sibling)) continue;/* skip if itself or no cacheinfo */ for (sib_index = 0; sib_index < cache_leaves(sibling); sib_index++) { @@ -463,11 +458,9 @@ int __weak populate_cache_leaves(unsigned int cpu) return -ENOENT; } -static inline -int allocate_cache_info(int cpu) +static inline int allocate_cache_info(int cpu) { - per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu), - sizeof(struct cacheinfo), GFP_ATOMIC); + per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu), sizeof(struct cacheinfo), GFP_ATOMIC); if (!per_cpu_cacheinfo(cpu)) { cache_leaves(cpu) = 0; return -ENOMEM; @@ -539,7 +532,11 @@ static inline int init_level_allocate_ci(unsigned int cpu) */ ci_cacheinfo(cpu)->early_ci_levels = false; - if (cache_leaves(cpu) <= early_leaves) + /* + * Some architectures (e.g., x86) do not use early initialization. + * Allocate memory now in such case. + */ + if (cache_leaves(cpu) <= early_leaves && per_cpu_cacheinfo(cpu)) return 0; kfree(per_cpu_cacheinfo(cpu)); diff --git a/drivers/base/class.c b/drivers/base/class.c index cb5359235c7020..582b5a02a5c410 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -405,7 +405,7 @@ int class_for_each_device(const struct class *class, const struct device *start, if (!class) return -EINVAL; if (!sp) { - WARN(1, "%s called for class '%s' before it was initialized", + WARN(1, "%s called for class '%s' before it was registered", __func__, class->name); return -EINVAL; } @@ -453,7 +453,7 @@ struct device *class_find_device(const struct class *class, const struct device if (!class) return NULL; if (!sp) { - WARN(1, "%s called for class '%s' before it was initialized", + WARN(1, "%s called for class '%s' before it was registered", __func__, class->name); return NULL; } diff --git a/drivers/base/core.c b/drivers/base/core.c index 048ff98dbdfd84..94865c9d8adcf5 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -552,7 +552,7 @@ void device_link_wait_removal(void) } EXPORT_SYMBOL_GPL(device_link_wait_removal); -static struct class devlink_class = { +static const struct class devlink_class = { .name = "devlink", .dev_groups = devlink_groups, .dev_release = devlink_dev_release, @@ -1971,7 +1971,7 @@ static struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwn /** * __fw_devlink_relax_cycles - Relax and mark dependency cycles. - * @con: Potential consumer device. + * @con_handle: Potential consumer device fwnode. * @sup_handle: Potential supplier's fwnode. * * Needs to be called with fwnode_lock and device link lock held. @@ -1989,10 +1989,10 @@ static struct device *fwnode_get_next_parent_dev(const struct fwnode_handle *fwn * * Return true if one or more cycles were found. Otherwise, return false. */ -static bool __fw_devlink_relax_cycles(struct device *con, +static bool __fw_devlink_relax_cycles(struct fwnode_handle *con_handle, struct fwnode_handle *sup_handle) { - struct device *sup_dev = NULL, *par_dev = NULL; + struct device *sup_dev = NULL, *par_dev = NULL, *con_dev = NULL; struct fwnode_link *link; struct device_link *dev_link; bool ret = false; @@ -2009,22 +2009,22 @@ static bool __fw_devlink_relax_cycles(struct device *con, sup_handle->flags |= FWNODE_FLAG_VISITED; - sup_dev = get_dev_from_fwnode(sup_handle); - /* Termination condition. */ - if (sup_dev == con) { + if (sup_handle == con_handle) { pr_debug("----- cycle: start -----\n"); ret = true; goto out; } + sup_dev = get_dev_from_fwnode(sup_handle); + con_dev = get_dev_from_fwnode(con_handle); /* * If sup_dev is bound to a driver and @con hasn't started binding to a * driver, sup_dev can't be a consumer of @con. So, no need to check * further. */ if (sup_dev && sup_dev->links.status == DL_DEV_DRIVER_BOUND && - con->links.status == DL_DEV_NO_DRIVER) { + con_dev && con_dev->links.status == DL_DEV_NO_DRIVER) { ret = false; goto out; } @@ -2033,7 +2033,7 @@ static bool __fw_devlink_relax_cycles(struct device *con, if (link->flags & FWLINK_FLAG_IGNORE) continue; - if (__fw_devlink_relax_cycles(con, link->supplier)) { + if (__fw_devlink_relax_cycles(con_handle, link->supplier)) { __fwnode_link_cycle(link); ret = true; } @@ -2048,7 +2048,7 @@ static bool __fw_devlink_relax_cycles(struct device *con, else par_dev = fwnode_get_next_parent_dev(sup_handle); - if (par_dev && __fw_devlink_relax_cycles(con, par_dev->fwnode)) { + if (par_dev && __fw_devlink_relax_cycles(con_handle, par_dev->fwnode)) { pr_debug("%pfwf: cycle: child of %pfwf\n", sup_handle, par_dev->fwnode); ret = true; @@ -2066,7 +2066,7 @@ static bool __fw_devlink_relax_cycles(struct device *con, !(dev_link->flags & DL_FLAG_CYCLE)) continue; - if (__fw_devlink_relax_cycles(con, + if (__fw_devlink_relax_cycles(con_handle, dev_link->supplier->fwnode)) { pr_debug("%pfwf: cycle: depends on %pfwf\n", sup_handle, dev_link->supplier->fwnode); @@ -2114,11 +2114,6 @@ static int fw_devlink_create_devlink(struct device *con, if (link->flags & FWLINK_FLAG_IGNORE) return 0; - if (con->fwnode == link->consumer) - flags = fw_devlink_get_flags(link->flags); - else - flags = FW_DEVLINK_FLAGS_PERMISSIVE; - /* * In some cases, a device P might also be a supplier to its child node * C. However, this would defer the probe of C until the probe of P @@ -2139,25 +2134,23 @@ static int fw_devlink_create_devlink(struct device *con, return -EINVAL; /* - * SYNC_STATE_ONLY device links don't block probing and supports cycles. - * So, one might expect that cycle detection isn't necessary for them. - * However, if the device link was marked as SYNC_STATE_ONLY because - * it's part of a cycle, then we still need to do cycle detection. This - * is because the consumer and supplier might be part of multiple cycles - * and we need to detect all those cycles. + * Don't try to optimize by not calling the cycle detection logic under + * certain conditions. There's always some corner case that won't get + * detected. */ - if (!device_link_flag_is_sync_state_only(flags) || - flags & DL_FLAG_CYCLE) { - device_links_write_lock(); - if (__fw_devlink_relax_cycles(con, sup_handle)) { - __fwnode_link_cycle(link); - flags = fw_devlink_get_flags(link->flags); - pr_debug("----- cycle: end -----\n"); - dev_info(con, "Fixed dependency cycle(s) with %pfwf\n", - sup_handle); - } - device_links_write_unlock(); + device_links_write_lock(); + if (__fw_devlink_relax_cycles(link->consumer, sup_handle)) { + __fwnode_link_cycle(link); + pr_debug("----- cycle: end -----\n"); + pr_info("%pfwf: Fixed dependency cycle(s) with %pfwf\n", + link->consumer, sup_handle); } + device_links_write_unlock(); + + if (con->fwnode == link->consumer) + flags = fw_devlink_get_flags(link->flags); + else + flags = FW_DEVLINK_FLAGS_PERMISSIVE; if (sup_handle->flags & FWNODE_FLAG_NOT_DEVICE) sup_dev = fwnode_get_next_parent_dev(sup_handle); @@ -2180,8 +2173,8 @@ static int fw_devlink_create_devlink(struct device *con, } if (con != sup_dev && !device_link_add(con, sup_dev, flags)) { - dev_err(con, "Failed to create device link (0x%x) with %s\n", - flags, dev_name(sup_dev)); + dev_err(con, "Failed to create device link (0x%x) with supplier %s for %pfwf\n", + flags, dev_name(sup_dev), link->consumer); ret = -EINVAL; } @@ -5012,6 +5005,49 @@ define_dev_printk_level(_dev_info, KERN_INFO); #endif +static void __dev_probe_failed(const struct device *dev, int err, bool fatal, + const char *fmt, va_list vargsp) +{ + struct va_format vaf; + va_list vargs; + + /* + * On x86_64 and possibly on other architectures, va_list is actually a + * size-1 array containing a structure. As a result, function parameter + * vargsp decays from T[1] to T*, and &vargsp has type T** rather than + * T(*)[1], which is expected by its assignment to vaf.va below. + * + * One standard way to solve this mess is by creating a copy in a local + * variable of type va_list and then using a pointer to that local copy + * instead, which is the approach employed here. + */ + va_copy(vargs, vargsp); + + vaf.fmt = fmt; + vaf.va = &vargs; + + switch (err) { + case -EPROBE_DEFER: + device_set_deferred_probe_reason(dev, &vaf); + dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf); + break; + + case -ENOMEM: + /* Don't print anything on -ENOMEM, there's already enough output */ + break; + + default: + /* Log fatal final failures as errors, otherwise produce warnings */ + if (fatal) + dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf); + else + dev_warn(dev, "error %pe: %pV", ERR_PTR(err), &vaf); + break; + } + + va_end(vargs); +} + /** * dev_err_probe - probe error check and log helper * @dev: the pointer to the struct device @@ -5024,7 +5060,7 @@ define_dev_printk_level(_dev_info, KERN_INFO); * -EPROBE_DEFER and propagate error upwards. * In case of -EPROBE_DEFER it sets also defer probe reason, which can be * checked later by reading devices_deferred debugfs attribute. - * It replaces code sequence:: + * It replaces the following code sequence:: * * if (err != -EPROBE_DEFER) * dev_err(dev, ...); @@ -5036,47 +5072,77 @@ define_dev_printk_level(_dev_info, KERN_INFO); * * return dev_err_probe(dev, err, ...); * - * Using this helper in your probe function is totally fine even if @err is - * known to never be -EPROBE_DEFER. + * Using this helper in your probe function is totally fine even if @err + * is known to never be -EPROBE_DEFER. * The benefit compared to a normal dev_err() is the standardized format - * of the error code, it being emitted symbolically (i.e. you get "EAGAIN" - * instead of "-35") and the fact that the error code is returned which allows - * more compact error paths. + * of the error code, which is emitted symbolically (i.e. you get "EAGAIN" + * instead of "-35"), and having the error code returned allows more + * compact error paths. * * Returns @err. */ int dev_err_probe(const struct device *dev, int err, const char *fmt, ...) { - struct va_format vaf; - va_list args; + va_list vargs; - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; + va_start(vargs, fmt); - switch (err) { - case -EPROBE_DEFER: - device_set_deferred_probe_reason(dev, &vaf); - dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf); - break; + /* Use dev_err() for logging when err doesn't equal -EPROBE_DEFER */ + __dev_probe_failed(dev, err, true, fmt, vargs); - case -ENOMEM: - /* - * We don't print anything on -ENOMEM, there is already enough - * output. - */ - break; + va_end(vargs); - default: - dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf); - break; - } + return err; +} +EXPORT_SYMBOL_GPL(dev_err_probe); - va_end(args); +/** + * dev_warn_probe - probe error check and log helper + * @dev: the pointer to the struct device + * @err: error value to test + * @fmt: printf-style format string + * @...: arguments as specified in the format string + * + * This helper implements common pattern present in probe functions for error + * checking: print debug or warning message depending if the error value is + * -EPROBE_DEFER and propagate error upwards. + * In case of -EPROBE_DEFER it sets also defer probe reason, which can be + * checked later by reading devices_deferred debugfs attribute. + * It replaces the following code sequence:: + * + * if (err != -EPROBE_DEFER) + * dev_warn(dev, ...); + * else + * dev_dbg(dev, ...); + * return err; + * + * with:: + * + * return dev_warn_probe(dev, err, ...); + * + * Using this helper in your probe function is totally fine even if @err + * is known to never be -EPROBE_DEFER. + * The benefit compared to a normal dev_warn() is the standardized format + * of the error code, which is emitted symbolically (i.e. you get "EAGAIN" + * instead of "-35"), and having the error code returned allows more + * compact error paths. + * + * Returns @err. + */ +int dev_warn_probe(const struct device *dev, int err, const char *fmt, ...) +{ + va_list vargs; + + va_start(vargs, fmt); + + /* Use dev_warn() for logging when err doesn't equal -EPROBE_DEFER */ + __dev_probe_failed(dev, err, false, fmt, vargs); + + va_end(vargs); return err; } -EXPORT_SYMBOL_GPL(dev_err_probe); +EXPORT_SYMBOL_GPL(dev_warn_probe); static inline bool fwnode_is_primary(struct fwnode_handle *fwnode) { diff --git a/drivers/base/firmware_loader/builtin/main.c b/drivers/base/firmware_loader/builtin/main.c index a065c315089736..d36befebb1b937 100644 --- a/drivers/base/firmware_loader/builtin/main.c +++ b/drivers/base/firmware_loader/builtin/main.c @@ -61,7 +61,7 @@ bool firmware_request_builtin(struct firmware *fw, const char *name) return false; } -EXPORT_SYMBOL_NS_GPL(firmware_request_builtin, TEST_FIRMWARE); +EXPORT_SYMBOL_NS_GPL(firmware_request_builtin, "TEST_FIRMWARE"); /** * firmware_request_builtin_buf() - load builtin firmware into optional buffer diff --git a/drivers/base/firmware_loader/fallback_table.c b/drivers/base/firmware_loader/fallback_table.c index 8432ab2c3b3ccd..ddb70e29eb4233 100644 --- a/drivers/base/firmware_loader/fallback_table.c +++ b/drivers/base/firmware_loader/fallback_table.c @@ -22,7 +22,7 @@ struct firmware_fallback_config fw_fallback_config = { .loading_timeout = 60, .old_timeout = 60, }; -EXPORT_SYMBOL_NS_GPL(fw_fallback_config, FIRMWARE_LOADER_PRIVATE); +EXPORT_SYMBOL_NS_GPL(fw_fallback_config, "FIRMWARE_LOADER_PRIVATE"); #ifdef CONFIG_SYSCTL static struct ctl_table firmware_config_table[] = { @@ -56,13 +56,13 @@ int register_firmware_config_sysctl(void) return -ENOMEM; return 0; } -EXPORT_SYMBOL_NS_GPL(register_firmware_config_sysctl, FIRMWARE_LOADER_PRIVATE); +EXPORT_SYMBOL_NS_GPL(register_firmware_config_sysctl, "FIRMWARE_LOADER_PRIVATE"); void unregister_firmware_config_sysctl(void) { unregister_sysctl_table(firmware_config_sysct_table_header); firmware_config_sysct_table_header = NULL; } -EXPORT_SYMBOL_NS_GPL(unregister_firmware_config_sysctl, FIRMWARE_LOADER_PRIVATE); +EXPORT_SYMBOL_NS_GPL(unregister_firmware_config_sysctl, "FIRMWARE_LOADER_PRIVATE"); #endif /* CONFIG_SYSCTL */ diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 324a9a3c087aa2..cb0912ea3e627e 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -829,19 +829,18 @@ static void fw_log_firmware_info(const struct firmware *fw, const char *name, st shash->tfm = alg; if (crypto_shash_digest(shash, fw->data, fw->size, sha256buf) < 0) - goto out_shash; + goto out_free; 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); + crypto_free_shash(alg); } #else static void fw_log_firmware_info(const struct firmware *fw, const char *name, @@ -1075,8 +1074,8 @@ EXPORT_SYMBOL_GPL(firmware_request_platform); /** * firmware_request_cache() - cache firmware for suspend so resume can use it - * @name: name of firmware file * @device: device for which firmware should be cached for + * @name: name of firmware file * * There are some devices with an optimization that enables the device to not * require loading firmware on system reboot. This optimization may still diff --git a/drivers/base/firmware_loader/sysfs.h b/drivers/base/firmware_loader/sysfs.h index 2060add8ef81b7..1cabea544a40bc 100644 --- a/drivers/base/firmware_loader/sysfs.h +++ b/drivers/base/firmware_loader/sysfs.h @@ -6,7 +6,7 @@ #include "firmware.h" -MODULE_IMPORT_NS(FIRMWARE_LOADER_PRIVATE); +MODULE_IMPORT_NS("FIRMWARE_LOADER_PRIVATE"); extern struct firmware_fallback_config fw_fallback_config; extern struct device_attribute dev_attr_loading; diff --git a/drivers/base/node.c b/drivers/base/node.c index eb72580288e627..0ea653fa34330e 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -27,7 +27,7 @@ static const struct bus_type node_subsys = { }; static inline ssize_t cpumap_read(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, + const struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj); @@ -45,10 +45,10 @@ static inline ssize_t cpumap_read(struct file *file, struct kobject *kobj, return n; } -static BIN_ATTR_RO(cpumap, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(cpumap, CPUMAP_FILE_MAX_BYTES); static inline ssize_t cpulist_read(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, + const struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj); @@ -66,7 +66,7 @@ static inline ssize_t cpulist_read(struct file *file, struct kobject *kobj, return n; } -static BIN_ATTR_RO(cpulist, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(cpulist, CPULIST_FILE_MAX_BYTES); /** * struct node_access_nodes - Access class device to hold user visible @@ -578,7 +578,7 @@ static struct attribute *node_dev_attrs[] = { NULL }; -static struct bin_attribute *node_dev_bin_attrs[] = { +static const struct bin_attribute *node_dev_bin_attrs[] = { &bin_attr_cpumap, &bin_attr_cpulist, NULL @@ -586,7 +586,7 @@ static struct bin_attribute *node_dev_bin_attrs[] = { static const struct attribute_group node_dev_group = { .attrs = node_dev_attrs, - .bin_attrs = node_dev_bin_attrs + .bin_attrs_new = node_dev_bin_attrs, }; static const struct attribute_group *node_dev_groups[] = { diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index cca2fd0a1aed64..781968a128ff75 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "power.h" @@ -222,13 +223,15 @@ int dev_pm_domain_attach_list(struct device *dev, if (!pds) return -ENOMEM; - size = sizeof(*pds->pd_devs) + sizeof(*pds->pd_links); + size = sizeof(*pds->pd_devs) + sizeof(*pds->pd_links) + + sizeof(*pds->opp_tokens); pds->pd_devs = kcalloc(num_pds, size, GFP_KERNEL); if (!pds->pd_devs) { ret = -ENOMEM; goto free_pds; } pds->pd_links = (void *)(pds->pd_devs + num_pds); + pds->opp_tokens = (void *)(pds->pd_links + num_pds); if (link_flags && pd_flags & PD_FLAG_DEV_LINK_ON) link_flags |= DL_FLAG_RPM_ACTIVE; @@ -244,6 +247,19 @@ int dev_pm_domain_attach_list(struct device *dev, goto err_attach; } + if (pd_flags & PD_FLAG_REQUIRED_OPP) { + struct dev_pm_opp_config config = { + .required_dev = pd_dev, + .required_dev_index = i, + }; + + ret = dev_pm_opp_set_config(dev, &config); + if (ret < 0) + goto err_link; + + pds->opp_tokens[i] = ret; + } + if (link_flags) { struct device_link *link; @@ -264,9 +280,11 @@ int dev_pm_domain_attach_list(struct device *dev, return num_pds; err_link: + dev_pm_opp_clear_config(pds->opp_tokens[i]); dev_pm_domain_detach(pd_dev, true); err_attach: while (--i >= 0) { + dev_pm_opp_clear_config(pds->opp_tokens[i]); if (pds->pd_links[i]) device_link_del(pds->pd_links[i]); dev_pm_domain_detach(pds->pd_devs[i], true); @@ -361,6 +379,7 @@ void dev_pm_domain_detach_list(struct dev_pm_domain_list *list) return; for (i = 0; i < list->num_pds; i++) { + dev_pm_opp_clear_config(list->opp_tokens[i]); if (list->pd_links[i]) device_link_del(list->pd_links[i]); dev_pm_domain_detach(list->pd_devs[i], true); diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index bd77f6734f14cd..ff393cba764969 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -137,6 +137,7 @@ s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type) return ret; } +EXPORT_SYMBOL_GPL(dev_pm_qos_read_value); /** * apply_constraint - Add/modify/remove device PM QoS request. diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index a1474fb67db9b2..f8163b559bf992 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -509,14 +509,6 @@ static ssize_t wakeup_last_time_ms_show(struct device *dev, return sysfs_emit(buf, "%lld\n", msec); } -static inline int dpm_sysfs_wakeup_change_owner(struct device *dev, kuid_t kuid, - kgid_t kgid) -{ - if (dev->power.wakeup && dev->power.wakeup->dev) - return device_change_owner(dev->power.wakeup->dev, kuid, kgid); - return 0; -} - static DEVICE_ATTR_RO(wakeup_last_time_ms); #ifdef CONFIG_PM_AUTOSLEEP @@ -541,6 +533,15 @@ static ssize_t wakeup_prevent_sleep_time_ms_show(struct device *dev, static DEVICE_ATTR_RO(wakeup_prevent_sleep_time_ms); #endif /* CONFIG_PM_AUTOSLEEP */ + +static inline int dpm_sysfs_wakeup_change_owner(struct device *dev, kuid_t kuid, + kgid_t kgid) +{ + if (dev->power.wakeup && dev->power.wakeup->dev) + return device_change_owner(dev->power.wakeup->dev, kuid, kgid); + return 0; +} + #else /* CONFIG_PM_SLEEP */ static inline int dpm_sysfs_wakeup_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 83acccdc100897..bdb450436cbc53 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -59,6 +59,7 @@ struct regmap { unsigned long raw_spinlock_flags; }; }; + struct lock_class_key *lock_key; regmap_lock lock; regmap_unlock unlock; void *lock_arg; /* This is passed to lock/unlock functions */ diff --git a/drivers/base/regmap/regcache-maple.c b/drivers/base/regmap/regcache-maple.c index 8d27d3653ea3e7..23da7b31d71534 100644 --- a/drivers/base/regmap/regcache-maple.c +++ b/drivers/base/regmap/regcache-maple.c @@ -355,6 +355,9 @@ static int regcache_maple_init(struct regmap *map) mt_init(mt); + if (!mt_external_lock(mt) && map->lock_key) + lockdep_set_class_and_subclass(&mt->ma_lock, map->lock_key, 1); + if (!map->num_reg_defaults) return 0; diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index a750e48a26b87c..0bcd81389a29f8 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -364,14 +364,11 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) memset32(data->status_buf, GENMASK(31, 0), chip->num_regs); } else if (chip->num_main_regs) { unsigned int max_main_bits; - unsigned long size; - - size = chip->num_regs * sizeof(unsigned int); max_main_bits = (chip->num_main_status_bits) ? chip->num_main_status_bits : chip->num_regs; /* Clear the status buf as we don't read all status regs */ - memset(data->status_buf, 0, size); + memset32(data->status_buf, 0, chip->num_regs); /* We could support bulk read for main status registers * but I don't expect to see devices with really many main @@ -514,12 +511,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) return IRQ_NONE; } +static struct lock_class_key regmap_irq_lock_class; +static struct lock_class_key regmap_irq_request_class; + static int regmap_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct regmap_irq_chip_data *data = h->host_data; irq_set_chip_data(virq, data); + irq_set_lockdep_class(virq, ®map_irq_lock_class, ®map_irq_request_class); irq_set_chip(virq, &data->irq_chip); irq_set_nested_thread(virq, 1); irq_set_parent(virq, data->irq); diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index 4bf3f1e59ed760..64ea340950b6a3 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -126,7 +126,7 @@ static const struct regmap_test_param real_cache_types_list[] = { { .cache = REGCACHE_RBTREE, .from_reg = 0x2003 }, { .cache = REGCACHE_RBTREE, .from_reg = 0x2004 }, { .cache = REGCACHE_MAPLE, .from_reg = 0 }, - { .cache = REGCACHE_RBTREE, .from_reg = 0, .fast_io = true }, + { .cache = REGCACHE_MAPLE, .from_reg = 0, .fast_io = true }, { .cache = REGCACHE_MAPLE, .from_reg = 0x2001 }, { .cache = REGCACHE_MAPLE, .from_reg = 0x2002 }, { .cache = REGCACHE_MAPLE, .from_reg = 0x2003 }, @@ -1499,6 +1499,48 @@ static void cache_present(struct kunit *test) KUNIT_ASSERT_TRUE(test, regcache_reg_cached(map, param->from_reg + i)); } +static void cache_write_zero(struct kunit *test) +{ + const struct regmap_test_param *param = test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int val; + int i; + + config = test_regmap_config; + + map = gen_regmap(test, &config, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + for (i = 0; i < BLOCK_TEST_SIZE; i++) + data->read[param->from_reg + i] = false; + + /* No defaults so no registers cached. */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_ASSERT_FALSE(test, regcache_reg_cached(map, param->from_reg + i)); + + /* We didn't trigger any reads */ + for (i = 0; i < BLOCK_TEST_SIZE; i++) + KUNIT_ASSERT_FALSE(test, data->read[param->from_reg + i]); + + /* Write a zero value */ + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 1, 0)); + + /* Read that zero value back */ + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 1, &val)); + KUNIT_EXPECT_EQ(test, 0, val); + + /* From the cache? */ + KUNIT_ASSERT_TRUE(test, regcache_reg_cached(map, 1)); + + /* Try to throw it away */ + KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, 1, 1)); + KUNIT_ASSERT_FALSE(test, regcache_reg_cached(map, 1)); +} + /* Check that caching the window register works with sync */ static void cache_range_window_reg(struct kunit *test) { @@ -2012,6 +2054,7 @@ static struct kunit_case regmap_test_cases[] = { KUNIT_CASE_PARAM(cache_drop_all_and_sync_no_defaults, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_drop_all_and_sync_has_defaults, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_present, sparse_cache_types_gen_params), + KUNIT_CASE_PARAM(cache_write_zero, sparse_cache_types_gen_params), KUNIT_CASE_PARAM(cache_range_window_reg, real_cache_types_only_gen_params), KUNIT_CASE_PARAM(raw_read_defaults_single, raw_test_types_gen_params), diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 4ded93687c1f0a..5962ea1230a17e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -598,6 +598,17 @@ int regmap_attach_dev(struct device *dev, struct regmap *map, } EXPORT_SYMBOL_GPL(regmap_attach_dev); +static int dev_get_regmap_match(struct device *dev, void *res, void *data); + +static int regmap_detach_dev(struct device *dev, struct regmap *map) +{ + if (!dev) + return 0; + + return devres_release(dev, dev_get_regmap_release, + dev_get_regmap_match, (void *)map->name); +} + static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus, const struct regmap_config *config) { @@ -745,6 +756,7 @@ struct regmap *__regmap_init(struct device *dev, lock_key, lock_name); } map->lock_arg = map; + map->lock_key = lock_key; } /* @@ -1051,13 +1063,13 @@ struct regmap *__regmap_init(struct device *dev, /* Sanity check */ if (range_cfg->range_max < range_cfg->range_min) { - dev_err(map->dev, "Invalid range %d: %d < %d\n", i, + dev_err(map->dev, "Invalid range %d: %u < %u\n", i, range_cfg->range_max, range_cfg->range_min); goto err_range; } if (range_cfg->range_max > map->max_register) { - dev_err(map->dev, "Invalid range %d: %d > %d\n", i, + dev_err(map->dev, "Invalid range %d: %u > %u\n", i, range_cfg->range_max, map->max_register); goto err_range; } @@ -1444,6 +1456,7 @@ void regmap_exit(struct regmap *map) { struct regmap_async *async; + regmap_detach_dev(map->dev, map); regcache_exit(map); regmap_debugfs_exit(map); diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 89f98be5c5b991..cf160dd2c27bd7 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -23,7 +23,7 @@ static ssize_t name##_show(struct device *dev, \ #define define_siblings_read_func(name, mask) \ static ssize_t name##_read(struct file *file, struct kobject *kobj, \ - struct bin_attribute *attr, char *buf, \ + const struct bin_attribute *attr, char *buf, \ loff_t off, size_t count) \ { \ struct device *dev = kobj_to_dev(kobj); \ @@ -33,7 +33,7 @@ static ssize_t name##_read(struct file *file, struct kobject *kobj, \ } \ \ static ssize_t name##_list_read(struct file *file, struct kobject *kobj, \ - struct bin_attribute *attr, char *buf, \ + const struct bin_attribute *attr, char *buf, \ loff_t off, size_t count) \ { \ struct device *dev = kobj_to_dev(kobj); \ @@ -62,50 +62,50 @@ define_id_show_func(ppin, "0x%llx"); static DEVICE_ATTR_ADMIN_RO(ppin); define_siblings_read_func(thread_siblings, sibling_cpumask); -static BIN_ATTR_RO(thread_siblings, CPUMAP_FILE_MAX_BYTES); -static BIN_ATTR_RO(thread_siblings_list, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(thread_siblings, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(thread_siblings_list, CPULIST_FILE_MAX_BYTES); define_siblings_read_func(core_cpus, sibling_cpumask); -static BIN_ATTR_RO(core_cpus, CPUMAP_FILE_MAX_BYTES); -static BIN_ATTR_RO(core_cpus_list, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(core_cpus, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(core_cpus_list, CPULIST_FILE_MAX_BYTES); define_siblings_read_func(core_siblings, core_cpumask); -static BIN_ATTR_RO(core_siblings, CPUMAP_FILE_MAX_BYTES); -static BIN_ATTR_RO(core_siblings_list, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(core_siblings, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(core_siblings_list, CPULIST_FILE_MAX_BYTES); #ifdef TOPOLOGY_CLUSTER_SYSFS define_siblings_read_func(cluster_cpus, cluster_cpumask); -static BIN_ATTR_RO(cluster_cpus, CPUMAP_FILE_MAX_BYTES); -static BIN_ATTR_RO(cluster_cpus_list, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(cluster_cpus, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(cluster_cpus_list, CPULIST_FILE_MAX_BYTES); #endif #ifdef TOPOLOGY_DIE_SYSFS define_siblings_read_func(die_cpus, die_cpumask); -static BIN_ATTR_RO(die_cpus, CPUMAP_FILE_MAX_BYTES); -static BIN_ATTR_RO(die_cpus_list, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(die_cpus, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(die_cpus_list, CPULIST_FILE_MAX_BYTES); #endif define_siblings_read_func(package_cpus, core_cpumask); -static BIN_ATTR_RO(package_cpus, CPUMAP_FILE_MAX_BYTES); -static BIN_ATTR_RO(package_cpus_list, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(package_cpus, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(package_cpus_list, CPULIST_FILE_MAX_BYTES); #ifdef TOPOLOGY_BOOK_SYSFS define_id_show_func(book_id, "%d"); static DEVICE_ATTR_RO(book_id); define_siblings_read_func(book_siblings, book_cpumask); -static BIN_ATTR_RO(book_siblings, CPUMAP_FILE_MAX_BYTES); -static BIN_ATTR_RO(book_siblings_list, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(book_siblings, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(book_siblings_list, CPULIST_FILE_MAX_BYTES); #endif #ifdef TOPOLOGY_DRAWER_SYSFS define_id_show_func(drawer_id, "%d"); static DEVICE_ATTR_RO(drawer_id); define_siblings_read_func(drawer_siblings, drawer_cpumask); -static BIN_ATTR_RO(drawer_siblings, CPUMAP_FILE_MAX_BYTES); -static BIN_ATTR_RO(drawer_siblings_list, CPULIST_FILE_MAX_BYTES); +static const BIN_ATTR_RO(drawer_siblings, CPUMAP_FILE_MAX_BYTES); +static const BIN_ATTR_RO(drawer_siblings_list, CPULIST_FILE_MAX_BYTES); #endif -static struct bin_attribute *bin_attrs[] = { +static const struct bin_attribute *const bin_attrs[] = { &bin_attr_core_cpus, &bin_attr_core_cpus_list, &bin_attr_thread_siblings, @@ -163,7 +163,7 @@ static umode_t topology_is_visible(struct kobject *kobj, static const struct attribute_group topology_attr_group = { .attrs = default_attrs, - .bin_attrs = bin_attrs, + .bin_attrs_new = bin_attrs, .is_visible = topology_is_visible, .name = "topology" }; diff --git a/drivers/base/trace.h b/drivers/base/trace.h index e52b6eae060dde..3b83b13a57ff1e 100644 --- a/drivers/base/trace.h +++ b/drivers/base/trace.h @@ -24,18 +24,18 @@ DECLARE_EVENT_CLASS(devres, __field(struct device *, dev) __field(const char *, op) __field(void *, node) - __field(const char *, name) + __string(name, name) __field(size_t, size) ), TP_fast_assign( __assign_str(devname); __entry->op = op; __entry->node = node; - __entry->name = name; + __assign_str(name); __entry->size = size; ), TP_printk("%s %3s %p %s (%zu bytes)", __get_str(devname), - __entry->op, __entry->node, __entry->name, __entry->size) + __entry->op, __entry->node, __get_str(name), __entry->size) ); DEFINE_EVENT(devres, devres_log, diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c index 8ae0b918e74038..20b1816c570b23 100644 --- a/drivers/bcma/host_soc.c +++ b/drivers/bcma/host_soc.c @@ -261,7 +261,7 @@ static struct platform_driver bcma_host_soc_driver = { .of_match_table = bcma_host_soc_of_match, }, .probe = bcma_host_soc_probe, - .remove_new = bcma_host_soc_remove, + .remove = bcma_host_soc_remove, }; int __init bcma_host_soc_register_driver(void) diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index ed209f4f279839..a97f2c40c640dd 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -130,7 +130,7 @@ config BLK_DEV_UBD_SYNC kernel command line option. Alternatively, you can say Y here to turn on synchronous operation by default for all block devices. - If you're running a journalling file system (like reiserfs, for + If you're running a journalling file system (like xfs, for example) in your virtual machine, you will want to say Y here. If you care for the safety of the data in your virtual machine, Y is a wise choice too. In all other cases (for example, if you're just diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 2fd1ed1017481b..292f127cae0abe 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -231,8 +231,10 @@ static void brd_do_discard(struct brd_device *brd, sector_t sector, u32 size) xa_lock(&brd->brd_pages); while (size >= PAGE_SIZE && aligned_sector < rd_size * 2) { page = __xa_erase(&brd->brd_pages, aligned_sector >> PAGE_SECTORS_SHIFT); - if (page) + if (page) { __free_page(page); + brd->brd_nr_pages--; + } aligned_sector += PAGE_SECTORS; size -= PAGE_SIZE; } @@ -316,8 +318,40 @@ __setup("ramdisk_size=", ramdisk_size); * (should share code eventually). */ static LIST_HEAD(brd_devices); +static DEFINE_MUTEX(brd_devices_mutex); static struct dentry *brd_debugfs_dir; +static struct brd_device *brd_find_or_alloc_device(int i) +{ + struct brd_device *brd; + + mutex_lock(&brd_devices_mutex); + list_for_each_entry(brd, &brd_devices, brd_list) { + if (brd->brd_number == i) { + mutex_unlock(&brd_devices_mutex); + return ERR_PTR(-EEXIST); + } + } + + brd = kzalloc(sizeof(*brd), GFP_KERNEL); + if (!brd) { + mutex_unlock(&brd_devices_mutex); + return ERR_PTR(-ENOMEM); + } + brd->brd_number = i; + list_add_tail(&brd->brd_list, &brd_devices); + mutex_unlock(&brd_devices_mutex); + return brd; +} + +static void brd_free_device(struct brd_device *brd) +{ + mutex_lock(&brd_devices_mutex); + list_del(&brd->brd_list); + mutex_unlock(&brd_devices_mutex); + kfree(brd); +} + static int brd_alloc(int i) { struct brd_device *brd; @@ -340,14 +374,9 @@ static int brd_alloc(int i) BLK_FEAT_NOWAIT, }; - list_for_each_entry(brd, &brd_devices, brd_list) - if (brd->brd_number == i) - return -EEXIST; - brd = kzalloc(sizeof(*brd), GFP_KERNEL); - if (!brd) - return -ENOMEM; - brd->brd_number = i; - list_add_tail(&brd->brd_list, &brd_devices); + brd = brd_find_or_alloc_device(i); + if (IS_ERR(brd)) + return PTR_ERR(brd); xa_init(&brd->brd_pages); @@ -378,8 +407,7 @@ static int brd_alloc(int i) out_cleanup_disk: put_disk(disk); out_free_dev: - list_del(&brd->brd_list); - kfree(brd); + brd_free_device(brd); return err; } @@ -398,8 +426,7 @@ static void brd_cleanup(void) del_gendisk(brd->brd_disk); put_disk(brd->brd_disk); brd_free_pages(brd); - list_del(&brd->brd_list); - kfree(brd); + brd_free_device(brd); } } @@ -426,16 +453,6 @@ static int __init brd_init(void) { int err, i; - brd_check_and_reset_par(); - - brd_debugfs_dir = debugfs_create_dir("ramdisk_pages", NULL); - - for (i = 0; i < rd_nr; i++) { - err = brd_alloc(i); - if (err) - goto out_free; - } - /* * brd module now has a feature to instantiate underlying device * structure on-demand, provided that there is an access dev node. @@ -451,11 +468,18 @@ static int __init brd_init(void) * dynamically. */ + brd_check_and_reset_par(); + + brd_debugfs_dir = debugfs_create_dir("ramdisk_pages", NULL); + if (__register_blkdev(RAMDISK_MAJOR, "ramdisk", brd_probe)) { err = -EIO; goto out_free; } + for (i = 0; i < rd_nr; i++) + brd_alloc(i); + pr_info("brd: module loaded\n"); return 0; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 78a7bb28defe4c..8f6761c27c68b2 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -173,7 +173,7 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file) static bool lo_bdev_can_use_dio(struct loop_device *lo, struct block_device *backing_bdev) { - unsigned short sb_bsize = bdev_logical_block_size(backing_bdev); + unsigned int sb_bsize = bdev_logical_block_size(backing_bdev); if (queue_logical_block_size(lo->lo_queue) < sb_bsize) return false; @@ -770,12 +770,11 @@ static void loop_sysfs_exit(struct loop_device *lo) &loop_attribute_group); } -static void loop_config_discard(struct loop_device *lo, - struct queue_limits *lim) +static void loop_get_discard_config(struct loop_device *lo, + u32 *granularity, u32 *max_discard_sectors) { struct file *file = lo->lo_backing_file; struct inode *inode = file->f_mapping->host; - u32 granularity = 0, max_discard_sectors = 0; struct kstatfs sbuf; /* @@ -786,27 +785,19 @@ static void loop_config_discard(struct loop_device *lo, * file-backed loop devices: discarded regions read back as zero. */ if (S_ISBLK(inode->i_mode)) { - struct request_queue *backingq = bdev_get_queue(I_BDEV(inode)); + struct block_device *bdev = I_BDEV(inode); - max_discard_sectors = backingq->limits.max_write_zeroes_sectors; - granularity = bdev_discard_granularity(I_BDEV(inode)) ?: - queue_physical_block_size(backingq); + *max_discard_sectors = bdev_write_zeroes_sectors(bdev); + *granularity = bdev_discard_granularity(bdev); /* * We use punch hole to reclaim the free space used by the * image a.k.a. discard. */ } else if (file->f_op->fallocate && !vfs_statfs(&file->f_path, &sbuf)) { - max_discard_sectors = UINT_MAX >> 9; - granularity = sbuf.f_bsize; + *max_discard_sectors = UINT_MAX >> 9; + *granularity = sbuf.f_bsize; } - - lim->max_hw_discard_sectors = max_discard_sectors; - lim->max_write_zeroes_sectors = max_discard_sectors; - if (max_discard_sectors) - lim->discard_granularity = granularity; - else - lim->discard_granularity = 0; } struct loop_worker { @@ -977,7 +968,7 @@ loop_set_status_from_info(struct loop_device *lo, return 0; } -static unsigned short loop_default_blocksize(struct loop_device *lo, +static unsigned int loop_default_blocksize(struct loop_device *lo, struct block_device *backing_bdev) { /* In case of direct I/O, match underlying block size */ @@ -986,12 +977,13 @@ static unsigned short loop_default_blocksize(struct loop_device *lo, return SECTOR_SIZE; } -static int loop_reconfigure_limits(struct loop_device *lo, unsigned short bsize) +static int loop_reconfigure_limits(struct loop_device *lo, unsigned int bsize) { struct file *file = lo->lo_backing_file; struct inode *inode = file->f_mapping->host; struct block_device *backing_bdev = NULL; struct queue_limits lim; + u32 granularity = 0, max_discard_sectors = 0; if (S_ISBLK(inode->i_mode)) backing_bdev = I_BDEV(inode); @@ -1001,6 +993,8 @@ static int loop_reconfigure_limits(struct loop_device *lo, unsigned short bsize) if (!bsize) bsize = loop_default_blocksize(lo, backing_bdev); + loop_get_discard_config(lo, &granularity, &max_discard_sectors); + lim = queue_limits_start_update(lo->lo_queue); lim.logical_block_size = bsize; lim.physical_block_size = bsize; @@ -1010,7 +1004,12 @@ static int loop_reconfigure_limits(struct loop_device *lo, unsigned short bsize) lim.features |= BLK_FEAT_WRITE_CACHE; if (backing_bdev && !bdev_nonrot(backing_bdev)) lim.features |= BLK_FEAT_ROTATIONAL; - loop_config_discard(lo, &lim); + lim.max_hw_discard_sectors = max_discard_sectors; + lim.max_write_zeroes_sectors = max_discard_sectors; + if (max_discard_sectors) + lim.discard_granularity = granularity; + else + lim.discard_granularity = 0; return queue_limits_commit_update(lo->lo_queue, &lim); } diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 223faa9d5ffdae..43701b7b10a7be 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -2701,7 +2701,12 @@ static int mtip_hw_init(struct driver_data *dd) int rv; unsigned long timeout, timetaken; - dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; + dd->mmio = pcim_iomap_region(dd->pdev, MTIP_ABAR, MTIP_DRV_NAME); + if (IS_ERR(dd->mmio)) { + dev_err(&dd->pdev->dev, "Unable to request / ioremap PCI region\n"); + return PTR_ERR(dd->mmio); + } + mtip_detect_product(dd); if (dd->product_type == MTIP_PRODUCT_UNKNOWN) { @@ -3710,13 +3715,6 @@ static int mtip_pci_probe(struct pci_dev *pdev, goto iomap_err; } - /* Map BAR5 to memory. */ - rv = pcim_iomap_regions(pdev, 1 << MTIP_ABAR, MTIP_DRV_NAME); - if (rv < 0) { - dev_err(&pdev->dev, "Unable to map regions\n"); - goto iomap_err; - } - rv = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rv) { dev_warn(&pdev->dev, "64-bit DMA enable failed\n"); diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c index 2f0431e42c494d..3c3d8d200abba5 100644 --- a/drivers/block/null_blk/main.c +++ b/drivers/block/null_blk/main.c @@ -1638,10 +1638,9 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx, return BLK_STS_OK; } -static void null_queue_rqs(struct request **rqlist) +static void null_queue_rqs(struct rq_list *rqlist) { - struct request *requeue_list = NULL; - struct request **requeue_lastp = &requeue_list; + struct rq_list requeue_list = {}; struct blk_mq_queue_data bd = { }; blk_status_t ret; @@ -1651,8 +1650,8 @@ static void null_queue_rqs(struct request **rqlist) bd.rq = rq; ret = null_queue_rq(rq->mq_hctx, &bd); if (ret != BLK_STS_OK) - rq_list_add_tail(&requeue_lastp, rq); - } while (!rq_list_empty(*rqlist)); + rq_list_add_tail(&requeue_list, rq); + } while (!rq_list_empty(rqlist)); *rqlist = requeue_list; } diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c index 9bc768b2ca56b7..0d5f9bf952292e 100644 --- a/drivers/block/null_blk/zoned.c +++ b/drivers/block/null_blk/zoned.c @@ -166,7 +166,7 @@ int null_init_zoned_dev(struct nullb_device *dev, lim->features |= BLK_FEAT_ZONED; lim->chunk_sectors = dev->zone_size_sects; - lim->max_zone_append_sectors = dev->zone_append_max_sectors; + lim->max_hw_zone_append_sectors = dev->zone_append_max_sectors; lim->max_open_zones = dev->zone_max_open; lim->max_active_zones = dev->zone_max_active; return 0; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 9c8b19a22c2a80..ac421dbeeb11f0 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -7284,6 +7284,7 @@ static ssize_t do_rbd_remove(const char *buf, size_t count) */ blk_mq_freeze_queue(rbd_dev->disk->queue); blk_mark_disk_dead(rbd_dev->disk); + blk_mq_unfreeze_queue(rbd_dev->disk->queue); } del_gendisk(rbd_dev->disk); diff --git a/drivers/block/rnull.rs b/drivers/block/rnull.rs index b0227cf9ddd387..9cca05dcf772c8 100644 --- a/drivers/block/rnull.rs +++ b/drivers/block/rnull.rs @@ -28,11 +28,12 @@ type: NullBlkModule, name: "rnull_mod", author: "Andreas Hindborg", + description: "Rust implementation of the C null block driver", license: "GPL v2", } struct NullBlkModule { - _disk: Pin>>>, + _disk: Pin>>>, } impl kernel::Module for NullBlkModule { @@ -47,7 +48,7 @@ fn init(_module: &'static ThisModule) -> Result { .rotational(false) .build(format_args!("rnullb{}", 0), tagset)?; - let disk = Box::pin_init(new_mutex!(disk, "nullb:disk"), flags::GFP_KERNEL)?; + let disk = KBox::pin_init(new_mutex!(disk, "nullb:disk"), flags::GFP_KERNEL)?; Ok(Self { _disk: disk }) } diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 126f151c4f2cf0..be4ac58afe4191 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -944,7 +944,7 @@ static void swim_remove(struct platform_device *dev) static struct platform_driver swim_driver = { .probe = swim_probe, - .remove_new = swim_remove, + .remove = swim_remove, .driver = { .name = CARDNAME, }, diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 6ba2c1dd1d878a..d4aed12dd436be 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -60,7 +60,12 @@ | UBLK_F_UNPRIVILEGED_DEV \ | UBLK_F_CMD_IOCTL_ENCODE \ | UBLK_F_USER_COPY \ - | UBLK_F_ZONED) + | UBLK_F_ZONED \ + | UBLK_F_USER_RECOVERY_FAIL_IO) + +#define UBLK_F_ALL_RECOVERY_FLAGS (UBLK_F_USER_RECOVERY \ + | UBLK_F_USER_RECOVERY_REISSUE \ + | UBLK_F_USER_RECOVERY_FAIL_IO) /* All UBLK_PARAM_TYPE_* should be included here */ #define UBLK_PARAM_TYPE_ALL \ @@ -143,6 +148,7 @@ struct ublk_queue { bool force_abort; bool timeout; bool canceling; + bool fail_io; /* copy of dev->state == UBLK_S_DEV_FAIL_IO */ unsigned short nr_io_ready; /* how many ios setup */ spinlock_t cancel_lock; struct ublk_device *dev; @@ -179,8 +185,7 @@ struct ublk_device { unsigned int nr_queues_ready; unsigned int nr_privileged_daemon; - struct work_struct quiesce_work; - struct work_struct stop_work; + struct work_struct nosrv_work; }; /* header of ublk_params */ @@ -664,30 +669,69 @@ static inline char *ublk_queue_cmd_buf(struct ublk_device *ub, int q_id) return ublk_get_queue(ub, q_id)->io_cmd_buf; } +static inline int __ublk_queue_cmd_buf_size(int depth) +{ + return round_up(depth * sizeof(struct ublksrv_io_desc), PAGE_SIZE); +} + static inline int ublk_queue_cmd_buf_size(struct ublk_device *ub, int q_id) { struct ublk_queue *ubq = ublk_get_queue(ub, q_id); - return round_up(ubq->q_depth * sizeof(struct ublksrv_io_desc), - PAGE_SIZE); + return __ublk_queue_cmd_buf_size(ubq->q_depth); +} + +static int ublk_max_cmd_buf_size(void) +{ + return __ublk_queue_cmd_buf_size(UBLK_MAX_QUEUE_DEPTH); +} + +/* + * Should I/O outstanding to the ublk server when it exits be reissued? + * If not, outstanding I/O will get errors. + */ +static inline bool ublk_nosrv_should_reissue_outstanding(struct ublk_device *ub) +{ + return (ub->dev_info.flags & UBLK_F_USER_RECOVERY) && + (ub->dev_info.flags & UBLK_F_USER_RECOVERY_REISSUE); +} + +/* + * Should I/O issued while there is no ublk server queue? If not, I/O + * issued while there is no ublk server will get errors. + */ +static inline bool ublk_nosrv_dev_should_queue_io(struct ublk_device *ub) +{ + return (ub->dev_info.flags & UBLK_F_USER_RECOVERY) && + !(ub->dev_info.flags & UBLK_F_USER_RECOVERY_FAIL_IO); } -static inline bool ublk_queue_can_use_recovery_reissue( - struct ublk_queue *ubq) +/* + * Same as ublk_nosrv_dev_should_queue_io, but uses a queue-local copy + * of the device flags for smaller cache footprint - better for fast + * paths. + */ +static inline bool ublk_nosrv_should_queue_io(struct ublk_queue *ubq) { return (ubq->flags & UBLK_F_USER_RECOVERY) && - (ubq->flags & UBLK_F_USER_RECOVERY_REISSUE); + !(ubq->flags & UBLK_F_USER_RECOVERY_FAIL_IO); } -static inline bool ublk_queue_can_use_recovery( - struct ublk_queue *ubq) +/* + * Should ublk devices be stopped (i.e. no recovery possible) when the + * ublk server exits? If not, devices can be used again by a future + * incarnation of a ublk server via the start_recovery/end_recovery + * commands. + */ +static inline bool ublk_nosrv_should_stop_dev(struct ublk_device *ub) { - return ubq->flags & UBLK_F_USER_RECOVERY; + return !(ub->dev_info.flags & UBLK_F_USER_RECOVERY); } -static inline bool ublk_can_use_recovery(struct ublk_device *ub) +static inline bool ublk_dev_in_recoverable_state(struct ublk_device *ub) { - return ub->dev_info.flags & UBLK_F_USER_RECOVERY; + return ub->dev_info.state == UBLK_S_DEV_QUIESCED || + ub->dev_info.state == UBLK_S_DEV_FAIL_IO; } static void ublk_free_disk(struct gendisk *disk) @@ -1063,7 +1107,7 @@ static void __ublk_fail_req(struct ublk_queue *ubq, struct ublk_io *io, { WARN_ON_ONCE(io->flags & UBLK_IO_FLAG_ACTIVE); - if (ublk_queue_can_use_recovery_reissue(ubq)) + if (ublk_nosrv_should_reissue_outstanding(ubq->dev)) blk_mq_requeue_request(req, false); else ublk_put_req_ref(ubq, req); @@ -1091,7 +1135,7 @@ static inline void __ublk_abort_rq(struct ublk_queue *ubq, struct request *rq) { /* We cannot process this rq so just requeue it. */ - if (ublk_queue_can_use_recovery(ubq)) + if (ublk_nosrv_dev_should_queue_io(ubq->dev)) blk_mq_requeue_request(rq, false); else blk_mq_end_request(rq, BLK_STS_IOERR); @@ -1236,10 +1280,7 @@ static enum blk_eh_timer_return ublk_timeout(struct request *rq) struct ublk_device *ub = ubq->dev; if (ublk_abort_requests(ub, ubq)) { - if (ublk_can_use_recovery(ub)) - schedule_work(&ub->quiesce_work); - else - schedule_work(&ub->stop_work); + schedule_work(&ub->nosrv_work); } return BLK_EH_DONE; } @@ -1254,6 +1295,10 @@ static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq = bd->rq; blk_status_t res; + if (unlikely(ubq->fail_io)) { + return BLK_STS_TARGET; + } + /* fill iod to slot in io cmd buffer */ res = ublk_setup_iod(ubq, rq); if (unlikely(res != BLK_STS_OK)) @@ -1268,7 +1313,7 @@ static blk_status_t ublk_queue_rq(struct blk_mq_hw_ctx *hctx, * Note: force_abort is guaranteed to be seen because it is set * before request queue is unqiuesced. */ - if (ublk_queue_can_use_recovery(ubq) && unlikely(ubq->force_abort)) + if (ublk_nosrv_should_queue_io(ubq) && unlikely(ubq->force_abort)) return BLK_STS_IOERR; if (unlikely(ubq->canceling)) { @@ -1322,7 +1367,7 @@ static int ublk_ch_mmap(struct file *filp, struct vm_area_struct *vma) { struct ublk_device *ub = filp->private_data; size_t sz = vma->vm_end - vma->vm_start; - unsigned max_sz = UBLK_MAX_QUEUE_DEPTH * sizeof(struct ublksrv_io_desc); + unsigned max_sz = ublk_max_cmd_buf_size(); unsigned long pfn, end, phys_off = vma->vm_pgoff << PAGE_SHIFT; int q_id, ret = 0; @@ -1489,10 +1534,7 @@ static void ublk_uring_cmd_cancel_fn(struct io_uring_cmd *cmd, ublk_cancel_cmd(ubq, io, issue_flags); if (need_schedule) { - if (ublk_can_use_recovery(ub)) - schedule_work(&ub->quiesce_work); - else - schedule_work(&ub->stop_work); + schedule_work(&ub->nosrv_work); } } @@ -1555,20 +1597,6 @@ static void __ublk_quiesce_dev(struct ublk_device *ub) ub->dev_info.state = UBLK_S_DEV_QUIESCED; } -static void ublk_quiesce_work_fn(struct work_struct *work) -{ - struct ublk_device *ub = - container_of(work, struct ublk_device, quiesce_work); - - mutex_lock(&ub->mutex); - if (ub->dev_info.state != UBLK_S_DEV_LIVE) - goto unlock; - __ublk_quiesce_dev(ub); - unlock: - mutex_unlock(&ub->mutex); - ublk_cancel_dev(ub); -} - static void ublk_unquiesce_dev(struct ublk_device *ub) { int i; @@ -1597,7 +1625,7 @@ static void ublk_stop_dev(struct ublk_device *ub) mutex_lock(&ub->mutex); if (ub->dev_info.state == UBLK_S_DEV_DEAD) goto unlock; - if (ublk_can_use_recovery(ub)) { + if (ublk_nosrv_dev_should_queue_io(ub)) { if (ub->dev_info.state == UBLK_S_DEV_LIVE) __ublk_quiesce_dev(ub); ublk_unquiesce_dev(ub); @@ -1617,6 +1645,37 @@ static void ublk_stop_dev(struct ublk_device *ub) ublk_cancel_dev(ub); } +static void ublk_nosrv_work(struct work_struct *work) +{ + struct ublk_device *ub = + container_of(work, struct ublk_device, nosrv_work); + int i; + + if (ublk_nosrv_should_stop_dev(ub)) { + ublk_stop_dev(ub); + return; + } + + mutex_lock(&ub->mutex); + if (ub->dev_info.state != UBLK_S_DEV_LIVE) + goto unlock; + + if (ublk_nosrv_dev_should_queue_io(ub)) { + __ublk_quiesce_dev(ub); + } else { + blk_mq_quiesce_queue(ub->ub_disk->queue); + ub->dev_info.state = UBLK_S_DEV_FAIL_IO; + for (i = 0; i < ub->dev_info.nr_hw_queues; i++) { + ublk_get_queue(ub, i)->fail_io = true; + } + blk_mq_unquiesce_queue(ub->ub_disk->queue); + } + + unlock: + mutex_unlock(&ub->mutex); + ublk_cancel_dev(ub); +} + /* device can only be started after all IOs are ready */ static void ublk_mark_io_ready(struct ublk_device *ub, struct ublk_queue *ubq) { @@ -2130,14 +2189,6 @@ static int ublk_add_chdev(struct ublk_device *ub) return ret; } -static void ublk_stop_work_fn(struct work_struct *work) -{ - struct ublk_device *ub = - container_of(work, struct ublk_device, stop_work); - - ublk_stop_dev(ub); -} - /* align max io buffer size with PAGE_SIZE */ static void ublk_align_max_io_size(struct ublk_device *ub) { @@ -2162,8 +2213,7 @@ static int ublk_add_tag_set(struct ublk_device *ub) static void ublk_remove(struct ublk_device *ub) { ublk_stop_dev(ub); - cancel_work_sync(&ub->stop_work); - cancel_work_sync(&ub->quiesce_work); + cancel_work_sync(&ub->nosrv_work); cdev_device_del(&ub->cdev, &ub->cdev_dev); ublk_put_device(ub); ublks_added--; @@ -2229,7 +2279,7 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd) lim.features |= BLK_FEAT_ZONED; lim.max_active_zones = p->max_active_zones; lim.max_open_zones = p->max_open_zones; - lim.max_zone_append_sectors = p->max_zone_append_sectors; + lim.max_hw_zone_append_sectors = p->max_zone_append_sectors; } if (ub->params.basic.attrs & UBLK_ATTR_VOLATILE_CACHE) { @@ -2372,6 +2422,19 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd) else if (!(info.flags & UBLK_F_UNPRIVILEGED_DEV)) return -EPERM; + /* forbid nonsense combinations of recovery flags */ + switch (info.flags & UBLK_F_ALL_RECOVERY_FLAGS) { + case 0: + case UBLK_F_USER_RECOVERY: + case (UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE): + case (UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_FAIL_IO): + break; + default: + pr_warn("%s: invalid recovery flags %llx\n", __func__, + info.flags & UBLK_F_ALL_RECOVERY_FLAGS); + return -EINVAL; + } + /* * unprivileged device can't be trusted, but RECOVERY and * RECOVERY_REISSUE still may hang error handling, so can't @@ -2424,8 +2487,7 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd) goto out_unlock; mutex_init(&ub->mutex); spin_lock_init(&ub->lock); - INIT_WORK(&ub->quiesce_work, ublk_quiesce_work_fn); - INIT_WORK(&ub->stop_work, ublk_stop_work_fn); + INIT_WORK(&ub->nosrv_work, ublk_nosrv_work); ret = ublk_alloc_dev_number(ub, header->dev_id); if (ret < 0) @@ -2560,9 +2622,7 @@ static inline void ublk_ctrl_cmd_dump(struct io_uring_cmd *cmd) static int ublk_ctrl_stop_dev(struct ublk_device *ub) { ublk_stop_dev(ub); - cancel_work_sync(&ub->stop_work); - cancel_work_sync(&ub->quiesce_work); - + cancel_work_sync(&ub->nosrv_work); return 0; } @@ -2699,7 +2759,7 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub, int i; mutex_lock(&ub->mutex); - if (!ublk_can_use_recovery(ub)) + if (ublk_nosrv_should_stop_dev(ub)) goto out_unlock; if (!ub->nr_queues_ready) goto out_unlock; @@ -2710,14 +2770,18 @@ static int ublk_ctrl_start_recovery(struct ublk_device *ub, * and related io_uring ctx is freed so file struct of /dev/ublkcX is * released. * + * and one of the following holds + * * (2) UBLK_S_DEV_QUIESCED is set, which means the quiesce_work: * (a)has quiesced request queue * (b)has requeued every inflight rqs whose io_flags is ACTIVE * (c)has requeued/aborted every inflight rqs whose io_flags is NOT ACTIVE * (d)has completed/camceled all ioucmds owned by ther dying process + * + * (3) UBLK_S_DEV_FAIL_IO is set, which means the queue is not + * quiesced, but all I/O is being immediately errored */ - if (test_bit(UB_STATE_OPEN, &ub->state) || - ub->dev_info.state != UBLK_S_DEV_QUIESCED) { + if (test_bit(UB_STATE_OPEN, &ub->state) || !ublk_dev_in_recoverable_state(ub)) { ret = -EBUSY; goto out_unlock; } @@ -2741,6 +2805,7 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub, const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe); int ublksrv_pid = (int)header->data[0]; int ret = -EINVAL; + int i; pr_devel("%s: Waiting for new ubq_daemons(nr: %d) are ready, dev id %d...\n", __func__, ub->dev_info.nr_hw_queues, header->dev_id); @@ -2752,21 +2817,32 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub, __func__, ub->dev_info.nr_hw_queues, header->dev_id); mutex_lock(&ub->mutex); - if (!ublk_can_use_recovery(ub)) + if (ublk_nosrv_should_stop_dev(ub)) goto out_unlock; - if (ub->dev_info.state != UBLK_S_DEV_QUIESCED) { + if (!ublk_dev_in_recoverable_state(ub)) { ret = -EBUSY; goto out_unlock; } ub->dev_info.ublksrv_pid = ublksrv_pid; pr_devel("%s: new ublksrv_pid %d, dev id %d\n", __func__, ublksrv_pid, header->dev_id); - blk_mq_unquiesce_queue(ub->ub_disk->queue); - pr_devel("%s: queue unquiesced, dev id %d.\n", - __func__, header->dev_id); - blk_mq_kick_requeue_list(ub->ub_disk->queue); - ub->dev_info.state = UBLK_S_DEV_LIVE; + + if (ublk_nosrv_dev_should_queue_io(ub)) { + ub->dev_info.state = UBLK_S_DEV_LIVE; + blk_mq_unquiesce_queue(ub->ub_disk->queue); + pr_devel("%s: queue unquiesced, dev id %d.\n", + __func__, header->dev_id); + blk_mq_kick_requeue_list(ub->ub_disk->queue); + } else { + blk_mq_quiesce_queue(ub->ub_disk->queue); + ub->dev_info.state = UBLK_S_DEV_LIVE; + for (i = 0; i < ub->dev_info.nr_hw_queues; i++) { + ublk_get_queue(ub, i)->fail_io = false; + } + blk_mq_unquiesce_queue(ub->ub_disk->queue); + } + ret = 0; out_unlock: mutex_unlock(&ub->mutex); @@ -2965,7 +3041,7 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd, ret = ublk_ctrl_end_recovery(ub, cmd); break; default: - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; break; } diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 194417abc1053c..3efe378f138662 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -471,18 +471,18 @@ static bool virtblk_prep_rq_batch(struct request *req) return virtblk_prep_rq(req->mq_hctx, vblk, req, vbr) == BLK_STS_OK; } -static bool virtblk_add_req_batch(struct virtio_blk_vq *vq, - struct request **rqlist) +static void virtblk_add_req_batch(struct virtio_blk_vq *vq, + struct rq_list *rqlist) { + struct request *req; unsigned long flags; - int err; bool kick; spin_lock_irqsave(&vq->lock, flags); - while (!rq_list_empty(*rqlist)) { - struct request *req = rq_list_pop(rqlist); + while ((req = rq_list_pop(rqlist))) { struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); + int err; err = virtblk_add_req(vq->vq, vbr); if (err) { @@ -495,37 +495,32 @@ static bool virtblk_add_req_batch(struct virtio_blk_vq *vq, kick = virtqueue_kick_prepare(vq->vq); spin_unlock_irqrestore(&vq->lock, flags); - return kick; + if (kick) + virtqueue_notify(vq->vq); } -static void virtio_queue_rqs(struct request **rqlist) +static void virtio_queue_rqs(struct rq_list *rqlist) { - struct request *req, *next, *prev = NULL; - struct request *requeue_list = NULL; - - rq_list_for_each_safe(rqlist, req, next) { - struct virtio_blk_vq *vq = get_virtio_blk_vq(req->mq_hctx); - bool kick; - - if (!virtblk_prep_rq_batch(req)) { - rq_list_move(rqlist, &requeue_list, req, prev); - req = prev; - if (!req) - continue; - } + struct rq_list submit_list = { }; + struct rq_list requeue_list = { }; + struct virtio_blk_vq *vq = NULL; + struct request *req; + + while ((req = rq_list_pop(rqlist))) { + struct virtio_blk_vq *this_vq = get_virtio_blk_vq(req->mq_hctx); - if (!next || req->mq_hctx != next->mq_hctx) { - req->rq_next = NULL; - kick = virtblk_add_req_batch(vq, rqlist); - if (kick) - virtqueue_notify(vq->vq); + if (vq && vq != this_vq) + virtblk_add_req_batch(vq, &submit_list); + vq = this_vq; - *rqlist = next; - prev = NULL; - } else - prev = req; + if (virtblk_prep_rq_batch(req)) + rq_list_add_tail(&submit_list, req); + else + rq_list_add_tail(&requeue_list, req); } + if (vq) + virtblk_add_req_batch(vq, &submit_list); *rqlist = requeue_list; } @@ -784,7 +779,7 @@ static int virtblk_read_zoned_limits(struct virtio_blk *vblk, wg, v); return -ENODEV; } - lim->max_zone_append_sectors = v; + lim->max_hw_zone_append_sectors = v; dev_dbg(&vdev->dev, "max append sectors = %u\n", v); return 0; @@ -1591,9 +1586,12 @@ static void virtblk_remove(struct virtio_device *vdev) static int virtblk_freeze(struct virtio_device *vdev) { struct virtio_blk *vblk = vdev->priv; + struct request_queue *q = vblk->disk->queue; /* Ensure no requests in virtqueues before deleting vqs. */ - blk_mq_freeze_queue(vblk->disk->queue); + blk_mq_freeze_queue(q); + blk_mq_quiesce_queue_nowait(q); + blk_mq_unfreeze_queue(q); /* Ensure we don't receive any more interrupts */ virtio_reset_device(vdev); @@ -1617,8 +1615,8 @@ static int virtblk_restore(struct virtio_device *vdev) return ret; virtio_device_ready(vdev); + blk_mq_unquiesce_queue(vblk->disk->queue); - blk_mq_unfreeze_queue(vblk->disk->queue); return 0; } #endif diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig index 6aea609b795c2f..402b7b17586328 100644 --- a/drivers/block/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -94,6 +94,7 @@ endchoice config ZRAM_DEF_COMP string + depends on ZRAM default "lzo-rle" if ZRAM_DEF_COMP_LZORLE default "lzo" if ZRAM_DEF_COMP_LZO default "lz4" if ZRAM_DEF_COMP_LZ4 diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index ad9c9bc3ccfc5b..45df5eeabc5e3d 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -178,11 +178,105 @@ static inline u32 zram_get_priority(struct zram *zram, u32 index) static void zram_accessed(struct zram *zram, u32 index) { zram_clear_flag(zram, index, ZRAM_IDLE); + zram_clear_flag(zram, index, ZRAM_PP_SLOT); #ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME zram->table[index].ac_time = ktime_get_boottime(); #endif } +#if defined CONFIG_ZRAM_WRITEBACK || defined CONFIG_ZRAM_MULTI_COMP +struct zram_pp_slot { + unsigned long index; + struct list_head entry; +}; + +/* + * A post-processing bucket is, essentially, a size class, this defines + * the range (in bytes) of pp-slots sizes in particular bucket. + */ +#define PP_BUCKET_SIZE_RANGE 64 +#define NUM_PP_BUCKETS ((PAGE_SIZE / PP_BUCKET_SIZE_RANGE) + 1) + +struct zram_pp_ctl { + struct list_head pp_buckets[NUM_PP_BUCKETS]; +}; + +static struct zram_pp_ctl *init_pp_ctl(void) +{ + struct zram_pp_ctl *ctl; + u32 idx; + + ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); + if (!ctl) + return NULL; + + for (idx = 0; idx < NUM_PP_BUCKETS; idx++) + INIT_LIST_HEAD(&ctl->pp_buckets[idx]); + return ctl; +} + +static void release_pp_slot(struct zram *zram, struct zram_pp_slot *pps) +{ + list_del_init(&pps->entry); + + zram_slot_lock(zram, pps->index); + zram_clear_flag(zram, pps->index, ZRAM_PP_SLOT); + zram_slot_unlock(zram, pps->index); + + kfree(pps); +} + +static void release_pp_ctl(struct zram *zram, struct zram_pp_ctl *ctl) +{ + u32 idx; + + if (!ctl) + return; + + for (idx = 0; idx < NUM_PP_BUCKETS; idx++) { + while (!list_empty(&ctl->pp_buckets[idx])) { + struct zram_pp_slot *pps; + + pps = list_first_entry(&ctl->pp_buckets[idx], + struct zram_pp_slot, + entry); + release_pp_slot(zram, pps); + } + } + + kfree(ctl); +} + +static void place_pp_slot(struct zram *zram, struct zram_pp_ctl *ctl, + struct zram_pp_slot *pps) +{ + u32 idx; + + idx = zram_get_obj_size(zram, pps->index) / PP_BUCKET_SIZE_RANGE; + list_add(&pps->entry, &ctl->pp_buckets[idx]); + + zram_set_flag(zram, pps->index, ZRAM_PP_SLOT); +} + +static struct zram_pp_slot *select_pp_slot(struct zram_pp_ctl *ctl) +{ + struct zram_pp_slot *pps = NULL; + s32 idx = NUM_PP_BUCKETS - 1; + + /* The higher the bucket id the more optimal slot post-processing is */ + while (idx >= 0) { + pps = list_first_entry_or_null(&ctl->pp_buckets[idx], + struct zram_pp_slot, + entry); + if (pps) + break; + + idx--; + } + return pps; +} +#endif + static inline void update_used_max(struct zram *zram, const unsigned long pages) { @@ -296,19 +390,28 @@ static void mark_idle(struct zram *zram, ktime_t cutoff) for (index = 0; index < nr_pages; index++) { /* - * Do not mark ZRAM_UNDER_WB slot as ZRAM_IDLE to close race. - * See the comment in writeback_store. + * Do not mark ZRAM_SAME slots as ZRAM_IDLE, because no + * post-processing (recompress, writeback) happens to the + * ZRAM_SAME slot. + * + * And ZRAM_WB slots simply cannot be ZRAM_IDLE. */ zram_slot_lock(zram, index); - if (zram_allocated(zram, index) && - !zram_test_flag(zram, index, ZRAM_UNDER_WB)) { + if (!zram_allocated(zram, index) || + zram_test_flag(zram, index, ZRAM_WB) || + zram_test_flag(zram, index, ZRAM_SAME)) { + zram_slot_unlock(zram, index); + continue; + } + #ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME - is_idle = !cutoff || ktime_after(cutoff, - zram->table[index].ac_time); + is_idle = !cutoff || + ktime_after(cutoff, zram->table[index].ac_time); #endif - if (is_idle) - zram_set_flag(zram, index, ZRAM_IDLE); - } + if (is_idle) + zram_set_flag(zram, index, ZRAM_IDLE); + else + zram_clear_flag(zram, index, ZRAM_IDLE); zram_slot_unlock(zram, index); } } @@ -511,6 +614,12 @@ static ssize_t backing_dev_store(struct device *dev, } nr_pages = i_size_read(inode) >> PAGE_SHIFT; + /* Refuse to use zero sized device (also prevents self reference) */ + if (!nr_pages) { + err = -EINVAL; + goto out; + } + bitmap_sz = BITS_TO_LONGS(nr_pages) * sizeof(long); bitmap = kvzalloc(bitmap_sz, GFP_KERNEL); if (!bitmap) { @@ -587,11 +696,57 @@ static void read_from_bdev_async(struct zram *zram, struct page *page, #define IDLE_WRITEBACK (1<<1) #define INCOMPRESSIBLE_WRITEBACK (1<<2) +static int scan_slots_for_writeback(struct zram *zram, u32 mode, + unsigned long nr_pages, + unsigned long index, + struct zram_pp_ctl *ctl) +{ + struct zram_pp_slot *pps = NULL; + + for (; nr_pages != 0; index++, nr_pages--) { + if (!pps) + pps = kmalloc(sizeof(*pps), GFP_KERNEL); + if (!pps) + return -ENOMEM; + + INIT_LIST_HEAD(&pps->entry); + + zram_slot_lock(zram, index); + if (!zram_allocated(zram, index)) + goto next; + + if (zram_test_flag(zram, index, ZRAM_WB) || + zram_test_flag(zram, index, ZRAM_SAME)) + goto next; + + if (mode & IDLE_WRITEBACK && + !zram_test_flag(zram, index, ZRAM_IDLE)) + goto next; + if (mode & HUGE_WRITEBACK && + !zram_test_flag(zram, index, ZRAM_HUGE)) + goto next; + if (mode & INCOMPRESSIBLE_WRITEBACK && + !zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE)) + goto next; + + pps->index = index; + place_pp_slot(zram, ctl, pps); + pps = NULL; +next: + zram_slot_unlock(zram, index); + } + + kfree(pps); + return 0; +} + static ssize_t writeback_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { struct zram *zram = dev_to_zram(dev); unsigned long nr_pages = zram->disksize >> PAGE_SHIFT; + struct zram_pp_ctl *ctl = NULL; + struct zram_pp_slot *pps; unsigned long index = 0; struct bio bio; struct bio_vec bio_vec; @@ -626,6 +781,12 @@ static ssize_t writeback_store(struct device *dev, goto release_init_lock; } + /* Do not permit concurrent post-processing actions. */ + if (atomic_xchg(&zram->pp_in_progress, 1)) { + up_read(&zram->init_lock); + return -EAGAIN; + } + if (!zram->backing_dev) { ret = -ENODEV; goto release_init_lock; @@ -637,7 +798,15 @@ static ssize_t writeback_store(struct device *dev, goto release_init_lock; } - for (; nr_pages != 0; index++, nr_pages--) { + ctl = init_pp_ctl(); + if (!ctl) { + ret = -ENOMEM; + goto release_init_lock; + } + + scan_slots_for_writeback(zram, mode, nr_pages, index, ctl); + + while ((pps = select_pp_slot(ctl))) { spin_lock(&zram->wb_limit_lock); if (zram->wb_limit_enable && !zram->bd_wb_limit) { spin_unlock(&zram->wb_limit_lock); @@ -654,38 +823,20 @@ static ssize_t writeback_store(struct device *dev, } } + index = pps->index; zram_slot_lock(zram, index); - if (!zram_allocated(zram, index)) - goto next; - - if (zram_test_flag(zram, index, ZRAM_WB) || - zram_test_flag(zram, index, ZRAM_SAME) || - zram_test_flag(zram, index, ZRAM_UNDER_WB)) - goto next; - - if (mode & IDLE_WRITEBACK && - !zram_test_flag(zram, index, ZRAM_IDLE)) - goto next; - if (mode & HUGE_WRITEBACK && - !zram_test_flag(zram, index, ZRAM_HUGE)) - goto next; - if (mode & INCOMPRESSIBLE_WRITEBACK && - !zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE)) - goto next; - /* - * Clearing ZRAM_UNDER_WB is duty of caller. - * IOW, zram_free_page never clear it. + * scan_slots() sets ZRAM_PP_SLOT and relases slot lock, so + * slots can change in the meantime. If slots are accessed or + * freed they lose ZRAM_PP_SLOT flag and hence we don't + * post-process them. */ - zram_set_flag(zram, index, ZRAM_UNDER_WB); - /* Need for hugepage writeback racing */ - zram_set_flag(zram, index, ZRAM_IDLE); + if (!zram_test_flag(zram, index, ZRAM_PP_SLOT)) + goto next; zram_slot_unlock(zram, index); + 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); - zram_slot_unlock(zram, index); + release_pp_slot(zram, pps); continue; } @@ -700,10 +851,7 @@ static ssize_t writeback_store(struct device *dev, */ err = submit_bio_wait(&bio); if (err) { - zram_slot_lock(zram, index); - zram_clear_flag(zram, index, ZRAM_UNDER_WB); - zram_clear_flag(zram, index, ZRAM_IDLE); - zram_slot_unlock(zram, index); + release_pp_slot(zram, pps); /* * BIO errors are not fatal, we continue and simply * attempt to writeback the remaining objects (pages). @@ -717,25 +865,19 @@ static ssize_t writeback_store(struct device *dev, } atomic64_inc(&zram->stats.bd_writes); + zram_slot_lock(zram, index); /* - * We released zram_slot_lock so need to check if the slot was - * changed. If there is freeing for the slot, we can catch it - * easily by zram_allocated. - * A subtle case is the slot is freed/reallocated/marked as - * ZRAM_IDLE again. To close the race, idle_store doesn't - * mark ZRAM_IDLE once it found the slot was ZRAM_UNDER_WB. - * Thus, we could close the race by checking ZRAM_IDLE bit. + * Same as above, we release slot lock during writeback so + * slot can change under us: slot_free() or slot_free() and + * reallocation (zram_write_page()). In both cases slot loses + * ZRAM_PP_SLOT flag. No concurrent post-processing can set + * ZRAM_PP_SLOT on such slots until current post-processing + * finishes. */ - zram_slot_lock(zram, index); - if (!zram_allocated(zram, index) || - !zram_test_flag(zram, index, ZRAM_IDLE)) { - zram_clear_flag(zram, index, ZRAM_UNDER_WB); - zram_clear_flag(zram, index, ZRAM_IDLE); + if (!zram_test_flag(zram, index, ZRAM_PP_SLOT)) goto next; - } zram_free_page(zram, index); - zram_clear_flag(zram, index, ZRAM_UNDER_WB); zram_set_flag(zram, index, ZRAM_WB); zram_set_element(zram, index, blk_idx); blk_idx = 0; @@ -746,12 +888,15 @@ static ssize_t writeback_store(struct device *dev, spin_unlock(&zram->wb_limit_lock); next: zram_slot_unlock(zram, index); + release_pp_slot(zram, pps); } if (blk_idx) free_block_bdev(zram, blk_idx); __free_page(page); release_init_lock: + release_pp_ctl(zram, ctl); + atomic_set(&zram->pp_in_progress, 0); up_read(&zram->init_lock); return ret; @@ -1299,12 +1444,16 @@ static void zram_meta_free(struct zram *zram, u64 disksize) size_t num_pages = disksize >> PAGE_SHIFT; size_t index; + if (!zram->table) + return; + /* Free all pages that are still in this zram device */ for (index = 0; index < num_pages; index++) zram_free_page(zram, index); zs_destroy_pool(zram->mem_pool); vfree(zram->table); + zram->table = NULL; } static bool zram_meta_alloc(struct zram *zram, u64 disksize) @@ -1342,19 +1491,17 @@ static void zram_free_page(struct zram *zram, size_t index) #ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME zram->table[index].ac_time = 0; #endif - if (zram_test_flag(zram, index, ZRAM_IDLE)) - zram_clear_flag(zram, index, ZRAM_IDLE); + + zram_clear_flag(zram, index, ZRAM_IDLE); + zram_clear_flag(zram, index, ZRAM_INCOMPRESSIBLE); + zram_clear_flag(zram, index, ZRAM_PP_SLOT); + zram_set_priority(zram, index, 0); if (zram_test_flag(zram, index, ZRAM_HUGE)) { zram_clear_flag(zram, index, ZRAM_HUGE); atomic64_dec(&zram->stats.huge_pages); } - if (zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE)) - zram_clear_flag(zram, index, ZRAM_INCOMPRESSIBLE); - - zram_set_priority(zram, index, 0); - if (zram_test_flag(zram, index, ZRAM_WB)) { zram_clear_flag(zram, index, ZRAM_WB); free_block_bdev(zram, zram_get_element(zram, index)); @@ -1378,13 +1525,11 @@ static void zram_free_page(struct zram *zram, size_t index) zs_free(zram->mem_pool, handle); atomic64_sub(zram_get_obj_size(zram, index), - &zram->stats.compr_data_size); + &zram->stats.compr_data_size); out: atomic64_dec(&zram->stats.pages_stored); zram_set_handle(zram, index, 0); zram_set_obj_size(zram, index, 0); - WARN_ON_ONCE(zram->table[index].flags & - ~(1UL << ZRAM_UNDER_WB)); } /* @@ -1648,6 +1793,52 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, } #ifdef CONFIG_ZRAM_MULTI_COMP +#define RECOMPRESS_IDLE (1 << 0) +#define RECOMPRESS_HUGE (1 << 1) + +static int scan_slots_for_recompress(struct zram *zram, u32 mode, + struct zram_pp_ctl *ctl) +{ + unsigned long nr_pages = zram->disksize >> PAGE_SHIFT; + struct zram_pp_slot *pps = NULL; + unsigned long index; + + for (index = 0; index < nr_pages; index++) { + if (!pps) + pps = kmalloc(sizeof(*pps), GFP_KERNEL); + if (!pps) + return -ENOMEM; + + INIT_LIST_HEAD(&pps->entry); + + zram_slot_lock(zram, index); + if (!zram_allocated(zram, index)) + goto next; + + if (mode & RECOMPRESS_IDLE && + !zram_test_flag(zram, index, ZRAM_IDLE)) + goto next; + + if (mode & RECOMPRESS_HUGE && + !zram_test_flag(zram, index, ZRAM_HUGE)) + goto next; + + if (zram_test_flag(zram, index, ZRAM_WB) || + zram_test_flag(zram, index, ZRAM_SAME) || + zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE)) + goto next; + + pps->index = index; + place_pp_slot(zram, ctl, pps); + pps = NULL; +next: + zram_slot_unlock(zram, index); + } + + kfree(pps); + return 0; +} + /* * This function will decompress (unless it's ZRAM_HUGE) the page and then * attempt to compress it using provided compression algorithm priority @@ -1655,7 +1846,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, * * Corresponding ZRAM slot should be locked. */ -static int zram_recompress(struct zram *zram, u32 index, struct page *page, +static int recompress_slot(struct zram *zram, u32 index, struct page *page, u64 *num_recomp_pages, u32 threshold, u32 prio, u32 prio_max) { @@ -1685,6 +1876,13 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page, if (ret) return ret; + /* + * We touched this entry so mark it as non-IDLE. This makes sure that + * we don't preserve IDLE flag and don't incorrectly pick this entry + * for different post-processing type (e.g. writeback). + */ + zram_clear_flag(zram, index, ZRAM_IDLE); + class_index_old = zs_lookup_class_index(zram->mem_pool, comp_len_old); /* * Iterate the secondary comp algorithms list (in order of priority) @@ -1798,20 +1996,17 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page, return 0; } -#define RECOMPRESS_IDLE (1 << 0) -#define RECOMPRESS_HUGE (1 << 1) - static ssize_t recompress_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { u32 prio = ZRAM_SECONDARY_COMP, prio_max = ZRAM_MAX_COMPS; struct zram *zram = dev_to_zram(dev); - unsigned long nr_pages = zram->disksize >> PAGE_SHIFT; char *args, *param, *val, *algo = NULL; u64 num_recomp_pages = ULLONG_MAX; + struct zram_pp_ctl *ctl = NULL; + struct zram_pp_slot *pps; u32 mode = 0, threshold = 0; - unsigned long index; struct page *page; ssize_t ret; @@ -1881,6 +2076,12 @@ static ssize_t recompress_store(struct device *dev, goto release_init_lock; } + /* Do not permit concurrent post-processing actions. */ + if (atomic_xchg(&zram->pp_in_progress, 1)) { + up_read(&zram->init_lock); + return -EAGAIN; + } + if (algo) { bool found = false; @@ -1907,36 +2108,32 @@ static ssize_t recompress_store(struct device *dev, goto release_init_lock; } + ctl = init_pp_ctl(); + if (!ctl) { + ret = -ENOMEM; + goto release_init_lock; + } + + scan_slots_for_recompress(zram, mode, ctl); + ret = len; - for (index = 0; index < nr_pages; index++) { + while ((pps = select_pp_slot(ctl))) { int err = 0; if (!num_recomp_pages) break; - zram_slot_lock(zram, index); - - if (!zram_allocated(zram, index)) - goto next; - - if (mode & RECOMPRESS_IDLE && - !zram_test_flag(zram, index, ZRAM_IDLE)) - goto next; - - if (mode & RECOMPRESS_HUGE && - !zram_test_flag(zram, index, ZRAM_HUGE)) + zram_slot_lock(zram, pps->index); + if (!zram_test_flag(zram, pps->index, ZRAM_PP_SLOT)) goto next; - if (zram_test_flag(zram, index, ZRAM_WB) || - zram_test_flag(zram, index, ZRAM_UNDER_WB) || - zram_test_flag(zram, index, ZRAM_SAME) || - zram_test_flag(zram, index, ZRAM_INCOMPRESSIBLE)) - goto next; - - err = zram_recompress(zram, index, page, &num_recomp_pages, - threshold, prio, prio_max); + err = recompress_slot(zram, pps->index, page, + &num_recomp_pages, threshold, + prio, prio_max); next: - zram_slot_unlock(zram, index); + zram_slot_unlock(zram, pps->index); + release_pp_slot(zram, pps); + if (err) { ret = err; break; @@ -1948,6 +2145,8 @@ static ssize_t recompress_store(struct device *dev, __free_page(page); release_init_lock: + release_pp_ctl(zram, ctl); + atomic_set(&zram->pp_in_progress, 0); up_read(&zram->init_lock); return ret; } @@ -2105,7 +2304,7 @@ static void zram_destroy_comps(struct zram *zram) { u32 prio; - for (prio = 0; prio < ZRAM_MAX_COMPS; prio++) { + for (prio = ZRAM_PRIMARY_COMP; prio < ZRAM_MAX_COMPS; prio++) { struct zcomp *comp = zram->comps[prio]; zram->comps[prio] = NULL; @@ -2131,11 +2330,6 @@ static void zram_reset_device(struct zram *zram) zram->limit_pages = 0; - if (!init_done(zram)) { - up_write(&zram->init_lock); - return; - } - set_capacity_and_notify(zram->disk, 0); part_stat_set_all(zram->disk->part0, 0); @@ -2144,6 +2338,7 @@ static void zram_reset_device(struct zram *zram) zram->disksize = 0; zram_destroy_comps(zram); memset(&zram->stats, 0, sizeof(zram->stats)); + atomic_set(&zram->pp_in_progress, 0); reset_bdev(zram); comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, default_compressor); @@ -2176,7 +2371,7 @@ static ssize_t disksize_store(struct device *dev, goto out_unlock; } - for (prio = 0; prio < ZRAM_MAX_COMPS; prio++) { + for (prio = ZRAM_PRIMARY_COMP; prio < ZRAM_MAX_COMPS; prio++) { if (!zram->comp_algs[prio]) continue; @@ -2381,6 +2576,9 @@ static int zram_add(void) zram->disk->fops = &zram_devops; zram->disk->private_data = zram; snprintf(zram->disk->disk_name, 16, "zram%d", device_id); + atomic_set(&zram->pp_in_progress, 0); + zram_comp_params_reset(zram); + comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, default_compressor); /* Actual capacity set using sysfs (/sys/block/zram/disksize */ set_capacity(zram->disk, 0); @@ -2388,9 +2586,6 @@ static int zram_add(void) if (ret) goto out_cleanup_disk; - zram_comp_params_reset(zram); - comp_algorithm_set(zram, ZRAM_PRIMARY_COMP, default_compressor); - zram_debugfs_register(zram); pr_info("Added device: %s\n", zram->disk->disk_name); return device_id; diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index cfc8c059db6369..134be414e2106b 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -47,7 +47,7 @@ enum zram_pageflags { ZRAM_SAME = ZRAM_FLAG_SHIFT, /* Page consists the same element */ ZRAM_WB, /* page is stored on backing_device */ - ZRAM_UNDER_WB, /* page is under writeback */ + ZRAM_PP_SLOT, /* Selected for post-processing */ ZRAM_HUGE, /* Incompressible page */ ZRAM_IDLE, /* not accessed page since last idle marking */ ZRAM_INCOMPRESSIBLE, /* none of the algorithms could compress it */ @@ -139,5 +139,6 @@ struct zram { #ifdef CONFIG_ZRAM_MEMORY_TRACKING struct dentry *debugfs_dir; #endif + atomic_t pp_in_progress; }; #endif diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 18767b54df352e..4ab32abf0f4864 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -336,7 +336,7 @@ config BT_HCIBFUSB config BT_HCIDTL1 tristate "HCI DTL1 (PC Card) driver" - depends on PCMCIA + depends on PCMCIA && HAS_IOPORT help Bluetooth HCI DTL1 (PC Card) driver. This driver provides support for Bluetooth PCMCIA devices with @@ -349,7 +349,7 @@ config BT_HCIDTL1 config BT_HCIBT3C tristate "HCI BT3C (PC Card) driver" - depends on PCMCIA + depends on PCMCIA && HAS_IOPORT select FW_LOADER help Bluetooth HCI BT3C (PC Card) driver. @@ -363,7 +363,7 @@ config BT_HCIBT3C config BT_HCIBLUECARD tristate "HCI BlueCard (PC Card) driver" - depends on PCMCIA + depends on PCMCIA && HAS_IOPORT help Bluetooth HCI BlueCard (PC Card) driver. This driver provides support for Bluetooth PCMCIA devices with diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index eef00467905eb3..a1153ada74d206 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -541,11 +541,10 @@ static const struct bcm_subver_table bcm_usb_subver_table[] = { static const char *btbcm_get_board_name(struct device *dev) { #ifdef CONFIG_OF - struct device_node *root; + struct device_node *root __free(device_node) = of_find_node_by_path("/"); char *board_type; const char *tmp; - root = of_find_node_by_path("/"); if (!root) return NULL; @@ -555,7 +554,6 @@ static const char *btbcm_get_board_name(struct device *dev) /* get rid of any '/' in the compatible string */ board_type = devm_kstrdup(dev, tmp, GFP_KERNEL); strreplace(board_type, '/', '-'); - of_node_put(root); return board_type; #else diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 30a32ebbcc681b..d496cf2c34111f 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -1040,7 +1040,7 @@ static int btintel_download_firmware_payload(struct hci_dev *hdev, * as needed. * * Send set of commands with 4 byte alignment from the - * firmware data buffer as a single Data fragement. + * firmware data buffer as a single Data fragment. */ if (!(frag_len % 4)) { err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); @@ -1252,6 +1252,12 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev) struct intel_reset params; struct sk_buff *skb; + /* PCIe transport uses shared hardware reset mechanism for recovery + * which gets triggered in pcie *setup* function on error. + */ + if (hdev->bus == HCI_PCI) + return; + /* Send Intel Reset command. This will result in * re-enumeration of BT controller. * @@ -1267,6 +1273,7 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev) * boot_param: Boot address * */ + params.reset_type = 0x01; params.patch_enable = 0x01; params.ddc_reload = 0x01; @@ -1841,6 +1848,37 @@ static int btintel_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec) return 0; } +static int btintel_boot_wait_d0(struct hci_dev *hdev, ktime_t calltime, + int msec) +{ + ktime_t delta, rettime; + unsigned long long duration; + int err; + + bt_dev_info(hdev, "Waiting for device transition to d0"); + + err = btintel_wait_on_flag_timeout(hdev, INTEL_WAIT_FOR_D0, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(msec)); + if (err == -EINTR) { + bt_dev_err(hdev, "Device d0 move interrupted"); + return -EINTR; + } + + if (err) { + bt_dev_err(hdev, "Device d0 move timeout"); + return -ETIMEDOUT; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long)ktime_to_ns(delta) >> 10; + + bt_dev_info(hdev, "Device moved to D0 in %llu usecs", duration); + + return 0; +} + static int btintel_boot(struct hci_dev *hdev, u32 boot_addr) { ktime_t calltime; @@ -1849,6 +1887,7 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr) calltime = ktime_get(); btintel_set_flag(hdev, INTEL_BOOTING); + btintel_set_flag(hdev, INTEL_WAIT_FOR_D0); err = btintel_send_intel_reset(hdev, boot_addr); if (err) { @@ -1861,13 +1900,28 @@ static int btintel_boot(struct hci_dev *hdev, u32 boot_addr) * is done by the operational firmware sending bootup notification. * * Booting into operational firmware should not take longer than - * 1 second. However if that happens, then just fail the setup + * 5 second. However if that happens, then just fail the setup * since something went wrong. */ - err = btintel_boot_wait(hdev, calltime, 1000); - if (err == -ETIMEDOUT) + err = btintel_boot_wait(hdev, calltime, 5000); + if (err == -ETIMEDOUT) { btintel_reset_to_bootloader(hdev); + goto exit_error; + } + if (hdev->bus == HCI_PCI) { + /* In case of PCIe, after receiving bootup event, driver performs + * D0 entry by writing 0 to sleep control register (check + * btintel_pcie_recv_event()) + * Firmware acks with alive interrupt indicating host is full ready to + * perform BT operation. Lets wait here till INTEL_WAIT_FOR_D0 + * bit is cleared. + */ + calltime = ktime_get(); + err = btintel_boot_wait_d0(hdev, calltime, 2000); + } + +exit_error: return err; } @@ -2693,20 +2747,32 @@ static int btintel_set_dsbr(struct hci_dev *hdev, struct intel_version_tlv *ver) struct btintel_dsbr_cmd cmd; struct sk_buff *skb; + u32 dsbr, cnvi; u8 status; - u32 dsbr; - bool apply_dsbr; int err; - /* DSBR command needs to be sent for BlazarI + B0 step product after - * downloading IML image. + cnvi = ver->cnvi_top & 0xfff; + /* DSBR command needs to be sent for, + * 1. BlazarI or BlazarIW + B0 step product in IML image. + * 2. Gale Peak2 or BlazarU in OP image. */ - apply_dsbr = (ver->img_type == BTINTEL_IMG_IML && - ((ver->cnvi_top & 0xfff) == BTINTEL_CNVI_BLAZARI) && - INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01); - if (!apply_dsbr) + switch (cnvi) { + case BTINTEL_CNVI_BLAZARI: + case BTINTEL_CNVI_BLAZARIW: + if (ver->img_type == BTINTEL_IMG_IML && + INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01) + break; + return 0; + case BTINTEL_CNVI_GAP: + case BTINTEL_CNVI_BLAZARU: + if (ver->img_type == BTINTEL_IMG_OP && + hdev->bus == HCI_USB) + break; return 0; + default: + return 0; + } dsbr = 0; err = btintel_uefi_get_dsbr(&dsbr); @@ -2749,6 +2815,13 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev, */ boot_param = 0x00000000; + /* In case of PCIe, this function might get called multiple times with + * same hdev instance if there is any error on firmware download. + * Need to clear stale bits of previous firmware download attempt. + */ + for (int i = 0; i < __INTEL_NUM_FLAGS; i++) + btintel_clear_flag(hdev, i); + btintel_set_flag(hdev, INTEL_BOOTLOADER); err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param); @@ -2835,7 +2908,7 @@ void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant) case 0x12: /* ThP */ case 0x13: /* HrP */ case 0x14: /* CcP */ - /* All Intel new genration controllers support the Microsoft vendor + /* All Intel new generation controllers support the Microsoft vendor * extension are using 0xFC1E for VsMsftOpCode. */ case 0x17: @@ -3273,7 +3346,7 @@ int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name) } EXPORT_SYMBOL_GPL(btintel_configure_setup); -static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) +int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) { struct intel_tlv *tlv = (void *)&skb->data[5]; @@ -3301,6 +3374,7 @@ static int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) recv_frame: return hci_recv_frame(hdev, skb); } +EXPORT_SYMBOL_GPL(btintel_diagnostics); int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) { @@ -3320,7 +3394,8 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) * indicating that the bootup completed. */ btintel_bootup(hdev, ptr, len); - break; + kfree_skb(skb); + return 0; case 0x06: /* When the firmware loading completes the * device sends out a vendor specific event @@ -3328,7 +3403,8 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) * loading. */ btintel_secure_send_result(hdev, ptr, len); - break; + kfree_skb(skb); + return 0; } } diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index aa70e4c2741653..fa43eb13782181 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -53,6 +53,9 @@ struct intel_tlv { } __packed; #define BTINTEL_CNVI_BLAZARI 0x900 +#define BTINTEL_CNVI_BLAZARIW 0x901 +#define BTINTEL_CNVI_GAP 0x910 +#define BTINTEL_CNVI_BLAZARU 0x930 #define BTINTEL_IMG_BOOTLOADER 0x01 /* Bootloader image */ #define BTINTEL_IMG_IML 0x02 /* Intermediate image */ @@ -178,6 +181,7 @@ enum { INTEL_ROM_LEGACY, INTEL_ROM_LEGACY_NO_WBS_SUPPORT, INTEL_ACPI_RESET_ACTIVE, + INTEL_WAIT_FOR_D0, __INTEL_NUM_FLAGS, }; @@ -249,6 +253,7 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev, int btintel_shutdown_combined(struct hci_dev *hdev); void btintel_hw_error(struct hci_dev *hdev, u8 code); void btintel_print_fseq_info(struct hci_dev *hdev); +int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb); #else static inline int btintel_check_bdaddr(struct hci_dev *hdev) @@ -382,4 +387,9 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) static inline void btintel_print_fseq_info(struct hci_dev *hdev) { } + +static inline int btintel_diagnostics(struct hci_dev *hdev, struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} #endif diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 5252125b003f58..2b79952f3628de 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -48,6 +48,17 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table); #define BTINTEL_PCIE_HCI_EVT_PKT 0x00000004 #define BTINTEL_PCIE_HCI_ISO_PKT 0x00000005 +/* Alive interrupt context */ +enum { + BTINTEL_PCIE_ROM, + BTINTEL_PCIE_FW_DL, + BTINTEL_PCIE_HCI_RESET, + BTINTEL_PCIE_INTEL_HCI_RESET1, + BTINTEL_PCIE_INTEL_HCI_RESET2, + BTINTEL_PCIE_D0, + BTINTEL_PCIE_D3 +}; + static inline void ipc_print_ia_ring(struct hci_dev *hdev, struct ia *ia, u16 queue_num) { @@ -64,24 +75,6 @@ static inline void ipc_print_urbd1(struct hci_dev *hdev, struct urbd1 *urbd1, index, urbd1->frbd_tag, urbd1->status, urbd1->fixed); } -static int btintel_pcie_poll_bit(struct btintel_pcie_data *data, u32 offset, - u32 bits, u32 mask, int timeout_us) -{ - int t = 0; - u32 reg; - - do { - reg = btintel_pcie_rd_reg32(data, offset); - - if ((reg & mask) == (bits & mask)) - return t; - udelay(POLL_INTERVAL_US); - t += POLL_INTERVAL_US; - } while (t < timeout_us); - - return -ETIMEDOUT; -} - static struct btintel_pcie_data *btintel_pcie_get_data(struct msix_entry *entry) { u8 queue = entry->entry; @@ -237,10 +230,47 @@ static void btintel_pcie_reset_ia(struct btintel_pcie_data *data) memset(data->ia.cr_tia, 0, sizeof(u16) * BTINTEL_PCIE_NUM_QUEUES); } -static void btintel_pcie_reset_bt(struct btintel_pcie_data *data) +static int btintel_pcie_reset_bt(struct btintel_pcie_data *data) { - btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, - BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET); + u32 reg; + int retry = 3; + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + + reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA | + BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT | + BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT); + reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON; + + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); + + do { + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + if (reg & BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_STS) + break; + usleep_range(10000, 12000); + + } while (--retry > 0); + usleep_range(10000, 12000); + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + + reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA | + BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT | + BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT); + reg |= BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET; + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); + usleep_range(10000, 12000); + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + bt_dev_dbg(data->hdev, "csr register after reset: 0x%8.8x", reg); + + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_BOOT_STAGE_REG); + + /* If shared hardware reset is success then boot stage register shall be + * set to 0 + */ + return reg == 0 ? 0 : -ENODEV; } /* This function enables BT function by setting BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT bit in @@ -252,6 +282,7 @@ static void btintel_pcie_reset_bt(struct btintel_pcie_data *data) static int btintel_pcie_enable_bt(struct btintel_pcie_data *data) { int err; + u32 reg; data->gp0_received = false; @@ -267,22 +298,17 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data) data->boot_stage_cache = 0x0; /* Set MAC_INIT bit to start primary bootloader */ - btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); + reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT | + BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON | + BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET); + reg |= (BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA | + BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT); - btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, - BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT); - - /* Wait until MAC_ACCESS is granted */ - err = btintel_pcie_poll_bit(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, - BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS, - BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS, - BTINTEL_DEFAULT_MAC_ACCESS_TIMEOUT_US); - if (err < 0) - return -ENODEV; + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, reg); /* MAC is ready. Enable BT FUNC */ btintel_pcie_set_reg_bits(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG, - BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_ENA | BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT); btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG); @@ -290,8 +316,9 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data) /* wait for interrupt from the device after booting up to primary * bootloader. */ + data->alive_intr_ctxt = BTINTEL_PCIE_ROM; err = wait_event_timeout(data->gp0_wait_q, data->gp0_received, - msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT)); + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); if (!err) return -ETIME; @@ -302,12 +329,77 @@ static int btintel_pcie_enable_bt(struct btintel_pcie_data *data) return 0; } +/* BIT(0) - ROM, BIT(1) - IML and BIT(3) - OP + * Sometimes during firmware image switching from ROM to IML or IML to OP image, + * the previous image bit is not cleared by firmware when alive interrupt is + * received. Driver needs to take care of these sticky bits when deciding the + * current image running on controller. + * Ex: 0x10 and 0x11 - both represents that controller is running IML + */ +static inline bool btintel_pcie_in_rom(struct btintel_pcie_data *data) +{ + return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ROM && + !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) && + !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW); +} + +static inline bool btintel_pcie_in_op(struct btintel_pcie_data *data) +{ + return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW; +} + +static inline bool btintel_pcie_in_iml(struct btintel_pcie_data *data) +{ + return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML && + !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW); +} + +static inline bool btintel_pcie_in_d3(struct btintel_pcie_data *data) +{ + return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY; +} + +static inline bool btintel_pcie_in_d0(struct btintel_pcie_data *data) +{ + return !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY); +} + +static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data, + u32 dxstate) +{ + bt_dev_dbg(data->hdev, "writing sleep_ctl_reg: 0x%8.8x", dxstate); + btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG, dxstate); +} + +static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt) +{ + switch (alive_intr_ctxt) { + case BTINTEL_PCIE_ROM: + return "rom"; + case BTINTEL_PCIE_FW_DL: + return "fw_dl"; + case BTINTEL_PCIE_D0: + return "d0"; + case BTINTEL_PCIE_D3: + return "d3"; + case BTINTEL_PCIE_HCI_RESET: + return "hci_reset"; + case BTINTEL_PCIE_INTEL_HCI_RESET1: + return "intel_reset1"; + case BTINTEL_PCIE_INTEL_HCI_RESET2: + return "intel_reset2"; + default: + return "unknown"; + } +} + /* This function handles the MSI-X interrupt for gp0 cause (bit 0 in * BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES) which is sent for boot stage and image response. */ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data) { - u32 reg; + bool submit_rx, signal_waitq; + u32 reg, old_ctxt; /* This interrupt is for three different causes and it is not easy to * know what causes the interrupt. So, it compares each register value @@ -317,20 +409,87 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data) if (reg != data->boot_stage_cache) data->boot_stage_cache = reg; + bt_dev_dbg(data->hdev, "Alive context: %s old_boot_stage: 0x%8.8x new_boot_stage: 0x%8.8x", + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt), + data->boot_stage_cache, reg); reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IMG_RESPONSE_REG); if (reg != data->img_resp_cache) data->img_resp_cache = reg; data->gp0_received = true; - /* If the boot stage is OP or IML, reset IA and start RX again */ - if (data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_OPFW || - data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_IML) { + old_ctxt = data->alive_intr_ctxt; + submit_rx = false; + signal_waitq = false; + + switch (data->alive_intr_ctxt) { + case BTINTEL_PCIE_ROM: + data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL; + signal_waitq = true; + break; + case BTINTEL_PCIE_FW_DL: + /* Error case is already handled. Ideally control shall not + * reach here + */ + break; + case BTINTEL_PCIE_INTEL_HCI_RESET1: + if (btintel_pcie_in_op(data)) { + submit_rx = true; + break; + } + + if (btintel_pcie_in_iml(data)) { + submit_rx = true; + data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL; + break; + } + break; + case BTINTEL_PCIE_INTEL_HCI_RESET2: + if (btintel_test_and_clear_flag(data->hdev, INTEL_WAIT_FOR_D0)) { + btintel_wake_up_flag(data->hdev, INTEL_WAIT_FOR_D0); + data->alive_intr_ctxt = BTINTEL_PCIE_D0; + } + break; + case BTINTEL_PCIE_D0: + if (btintel_pcie_in_d3(data)) { + data->alive_intr_ctxt = BTINTEL_PCIE_D3; + signal_waitq = true; + break; + } + break; + case BTINTEL_PCIE_D3: + if (btintel_pcie_in_d0(data)) { + data->alive_intr_ctxt = BTINTEL_PCIE_D0; + submit_rx = true; + signal_waitq = true; + break; + } + break; + case BTINTEL_PCIE_HCI_RESET: + data->alive_intr_ctxt = BTINTEL_PCIE_D0; + submit_rx = true; + signal_waitq = true; + break; + default: + bt_dev_err(data->hdev, "Unknown state: 0x%2.2x", + data->alive_intr_ctxt); + break; + } + + if (submit_rx) { btintel_pcie_reset_ia(data); btintel_pcie_start_rx(data); } - wake_up(&data->gp0_wait_q); + if (signal_waitq) { + bt_dev_dbg(data->hdev, "wake up gp0 wait_q"); + wake_up(&data->gp0_wait_q); + } + + if (old_ctxt != data->alive_intr_ctxt) + bt_dev_dbg(data->hdev, "alive context changed: %s -> %s", + btintel_pcie_alivectxt_state2str(old_ctxt), + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); } /* This function handles the MSX-X interrupt for rx queue 0 which is for TX @@ -364,6 +523,83 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data) } } +static int btintel_pcie_recv_event(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_event_hdr *hdr = (void *)skb->data; + const char diagnostics_hdr[] = { 0x87, 0x80, 0x03 }; + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + + if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff && + hdr->plen > 0) { + const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1; + unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1; + + if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) { + switch (skb->data[2]) { + case 0x02: + /* When switching to the operational firmware + * the device sends a vendor specific event + * indicating that the bootup completed. + */ + btintel_bootup(hdev, ptr, len); + + /* If bootup event is from operational image, + * driver needs to write sleep control register to + * move into D0 state + */ + if (btintel_pcie_in_op(data)) { + btintel_pcie_wr_sleep_cntrl(data, BTINTEL_PCIE_STATE_D0); + data->alive_intr_ctxt = BTINTEL_PCIE_INTEL_HCI_RESET2; + kfree_skb(skb); + return 0; + } + + if (btintel_pcie_in_iml(data)) { + /* In case of IML, there is no concept + * of D0 transition. Just mimic as if + * IML moved to D0 by clearing INTEL_WAIT_FOR_D0 + * bit and waking up the task waiting on + * INTEL_WAIT_FOR_D0. This is required + * as intel_boot() is common function for + * both IML and OP image loading. + */ + if (btintel_test_and_clear_flag(data->hdev, + INTEL_WAIT_FOR_D0)) + btintel_wake_up_flag(data->hdev, + INTEL_WAIT_FOR_D0); + } + kfree_skb(skb); + return 0; + case 0x06: + /* When the firmware loading completes the + * device sends out a vendor specific event + * indicating the result of the firmware + * loading. + */ + btintel_secure_send_result(hdev, ptr, len); + kfree_skb(skb); + return 0; + } + } + + /* Handle all diagnostics events separately. May still call + * hci_recv_frame. + */ + if (len >= sizeof(diagnostics_hdr) && + memcmp(&skb->data[2], diagnostics_hdr, + sizeof(diagnostics_hdr)) == 0) { + return btintel_diagnostics(hdev, skb); + } + + /* This is a debug event that comes from IML and OP image when it + * starts execution. There is no need pass this event to stack. + */ + if (skb->data[2] == 0x97) + return 0; + } + + return hci_recv_frame(hdev, skb); +} /* Process the received rx data * It check the frame header to identify the data type and create skb * and calling HCI API @@ -465,7 +701,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data, hdev->stat.byte_rx += plen; if (pcie_pkt_type == BTINTEL_PCIE_HCI_EVT_PKT) - ret = btintel_recv_event(hdev, new_skb); + ret = btintel_pcie_recv_event(hdev, new_skb); else ret = hci_recv_frame(hdev, new_skb); @@ -516,10 +752,8 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status buf += sizeof(*rfh_hdr); skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - ret = -ENOMEM; + if (!skb) goto resubmit; - } skb_put_data(skb, buf, len); skb_queue_tail(&data->rx_skb_q, skb); @@ -734,13 +968,9 @@ static int btintel_pcie_config_pcie(struct pci_dev *pdev, return err; } - err = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME); - if (err) - return err; - - data->base_addr = pcim_iomap_table(pdev)[0]; - if (!data->base_addr) - return -ENODEV; + data->base_addr = pcim_iomap_region(pdev, 0, KBUILD_MODNAME); + if (IS_ERR(data->base_addr)) + return PTR_ERR(data->base_addr); err = btintel_pcie_setup_irq(data); if (err) @@ -1053,8 +1283,11 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, struct sk_buff *skb) { struct btintel_pcie_data *data = hci_get_drvdata(hdev); + struct hci_command_hdr *cmd; + __u16 opcode = ~0; int ret; u32 type; + u32 old_ctxt; /* Due to the fw limitation, the type header of the packet should be * 4 bytes unlike 1 byte for UART. In UART, the firmware can read @@ -1073,6 +1306,8 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, switch (hci_skb_pkt_type(skb)) { case HCI_COMMAND_PKT: type = BTINTEL_PCIE_HCI_CMD_PKT; + cmd = (void *)skb->data; + opcode = le16_to_cpu(cmd->opcode); if (btintel_test_flag(hdev, INTEL_BOOTLOADER)) { struct hci_command_hdr *cmd = (void *)skb->data; __u16 opcode = le16_to_cpu(cmd->opcode); @@ -1111,6 +1346,30 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, bt_dev_err(hdev, "Failed to send frame (%d)", ret); goto exit_error; } + + if (type == BTINTEL_PCIE_HCI_CMD_PKT && + (opcode == HCI_OP_RESET || opcode == 0xfc01)) { + old_ctxt = data->alive_intr_ctxt; + data->alive_intr_ctxt = + (opcode == 0xfc01 ? BTINTEL_PCIE_INTEL_HCI_RESET1 : + BTINTEL_PCIE_HCI_RESET); + bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s -> %s", + opcode, btintel_pcie_alivectxt_state2str(old_ctxt), + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); + if (opcode == HCI_OP_RESET) { + data->gp0_received = false; + ret = wait_event_timeout(data->gp0_wait_q, + data->gp0_received, + msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS)); + if (!ret) { + hdev->stat.err_tx++; + bt_dev_err(hdev, "No alive interrupt received for %s", + btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt)); + ret = -ETIME; + goto exit_error; + } + } + } hdev->stat.byte_tx += skb->len; kfree_skb(skb); @@ -1128,7 +1387,7 @@ static void btintel_pcie_release_hdev(struct btintel_pcie_data *data) data->hdev = NULL; } -static int btintel_pcie_setup(struct hci_dev *hdev) +static int btintel_pcie_setup_internal(struct hci_dev *hdev) { const u8 param[1] = { 0xFF }; struct intel_version_tlv ver_tlv; @@ -1219,6 +1478,32 @@ static int btintel_pcie_setup(struct hci_dev *hdev) return err; } +static int btintel_pcie_setup(struct hci_dev *hdev) +{ + int err, fw_dl_retry = 0; + struct btintel_pcie_data *data = hci_get_drvdata(hdev); + + while ((err = btintel_pcie_setup_internal(hdev)) && fw_dl_retry++ < 1) { + bt_dev_err(hdev, "Firmware download retry count: %d", + fw_dl_retry); + err = btintel_pcie_reset_bt(data); + if (err) { + bt_dev_err(hdev, "Failed to do shr reset: %d", err); + break; + } + usleep_range(10000, 12000); + btintel_pcie_reset_ia(data); + btintel_pcie_config_msix(data); + err = btintel_pcie_enable_bt(data); + if (err) { + bt_dev_err(hdev, "Failed to enable hardware: %d", err); + break; + } + btintel_pcie_start_rx(data); + } + return err; +} + static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data) { int err; diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h index baaff70420f575..f9aada0543c489 100644 --- a/drivers/bluetooth/btintel_pcie.h +++ b/drivers/bluetooth/btintel_pcie.h @@ -12,6 +12,7 @@ #define BTINTEL_PCIE_CSR_HW_REV_REG (BTINTEL_PCIE_CSR_BASE + 0x028) #define BTINTEL_PCIE_CSR_RF_ID_REG (BTINTEL_PCIE_CSR_BASE + 0x09C) #define BTINTEL_PCIE_CSR_BOOT_STAGE_REG (BTINTEL_PCIE_CSR_BASE + 0x108) +#define BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG (BTINTEL_PCIE_CSR_BASE + 0x114) #define BTINTEL_PCIE_CSR_CI_ADDR_LSB_REG (BTINTEL_PCIE_CSR_BASE + 0x118) #define BTINTEL_PCIE_CSR_CI_ADDR_MSB_REG (BTINTEL_PCIE_CSR_BASE + 0x11C) #define BTINTEL_PCIE_CSR_IMG_RESPONSE_REG (BTINTEL_PCIE_CSR_BASE + 0x12C) @@ -22,6 +23,8 @@ #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT (BIT(6)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT (BIT(7)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS (BIT(20)) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_STS (BIT(28)) +#define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON (BIT(29)) #define BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET (BIT(31)) /* Value for BTINTEL_PCIE_CSR_BOOT_STAGE register */ @@ -32,6 +35,7 @@ #define BTINTEL_PCIE_CSR_BOOT_STAGE_IML_LOCKDOWN (BIT(11)) #define BTINTEL_PCIE_CSR_BOOT_STAGE_MAC_ACCESS_ON (BIT(16)) #define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE (BIT(23)) +#define BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY (BIT(24)) /* Registers for MSI-X */ #define BTINTEL_PCIE_CSR_MSIX_BASE (0x2000) @@ -55,6 +59,16 @@ enum msix_hw_int_causes { BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0 = BIT(0), /* cause 32 */ }; +/* PCIe device states + * Host-Device interface is active + * Host-Device interface is inactive(as reflected by IPC_SLEEP_CONTROL_CSR_AD) + * Host-Device interface is inactive(as reflected by IPC_SLEEP_CONTROL_CSR_AD) + */ +enum { + BTINTEL_PCIE_STATE_D0 = 0, + BTINTEL_PCIE_STATE_D3_HOT = 2, + BTINTEL_PCIE_STATE_D3_COLD = 3, +}; #define BTINTEL_PCIE_MSIX_NON_AUTO_CLEAR_CAUSE BIT(7) /* Minimum and Maximum number of MSI-X Vector @@ -67,7 +81,7 @@ enum msix_hw_int_causes { #define BTINTEL_DEFAULT_MAC_ACCESS_TIMEOUT_US 200000 /* Default interrupt timeout in msec */ -#define BTINTEL_DEFAULT_INTR_TIMEOUT 3000 +#define BTINTEL_DEFAULT_INTR_TIMEOUT_MS 3000 /* The number of descriptors in TX/RX queues */ #define BTINTEL_DESCS_COUNT 16 @@ -343,6 +357,7 @@ struct rxq { * @ia: Index Array struct * @txq: TX Queue struct * @rxq: RX Queue struct + * @alive_intr_ctxt: Alive interrupt context */ struct btintel_pcie_data { struct pci_dev *pdev; @@ -389,6 +404,7 @@ struct btintel_pcie_data { struct ia ia; struct txq txq; struct rxq rxq; + u32 alive_intr_ctxt; }; static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data, diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 9bbf205021634f..7fd9d5ddce02c2 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -324,7 +324,7 @@ int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname, wmt_params.data = NULL; wmt_params.status = NULL; - /* Activate funciton the firmware providing to */ + /* Activate function the firmware providing to */ err = wmt_cmd_sync(hdev, &wmt_params); if (err < 0) { bt_dev_err(hdev, "Failed to send wmt rst (%d)", err); @@ -395,6 +395,7 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) { struct btmtk_data *data = hci_get_priv(hdev); int err; + bool complete = false; if (!IS_ENABLED(CONFIG_DEV_COREDUMP)) { kfree_skb(skb); @@ -416,19 +417,22 @@ int btmtk_process_coredump(struct hci_dev *hdev, struct sk_buff *skb) fallthrough; case HCI_DEVCOREDUMP_ACTIVE: default: + /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ + if (data->cd_info.cnt >= MTK_COREDUMP_NUM && + skb->len > MTK_COREDUMP_END_LEN) + if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN], + MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) + complete = true; + err = hci_devcd_append(hdev, skb); if (err < 0) break; data->cd_info.cnt++; - /* Mediatek coredump data would be more than MTK_COREDUMP_NUM */ - if (data->cd_info.cnt > MTK_COREDUMP_NUM && - skb->len > MTK_COREDUMP_END_LEN) - if (!memcmp((char *)&skb->data[skb->len - MTK_COREDUMP_END_LEN], - MTK_COREDUMP_END, MTK_COREDUMP_END_LEN - 1)) { - bt_dev_info(hdev, "Mediatek coredump end"); - hci_devcd_complete(hdev); - } + if (complete) { + bt_dev_info(hdev, "Mediatek coredump end"); + hci_devcd_complete(hdev); + } break; } @@ -1215,7 +1219,6 @@ static int btmtk_usb_isointf_init(struct hci_dev *hdev) struct sk_buff *skb; int err; - init_usb_anchor(&btmtk_data->isopkt_anchor); spin_lock_init(&btmtk_data->isorxlock); __set_mtk_intr_interface(hdev); diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 11d33cd7b08fc0..a1dfcfe43d3aad 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -681,7 +681,7 @@ static int btmtksdio_open(struct hci_dev *hdev) if (err < 0) goto err_release_irq; - /* Explitly set write-1-clear method */ + /* Explicitly set write-1-clear method */ val = sdio_readl(bdev->func, MTK_REG_CHCR, &err); if (err < 0) goto err_release_irq; @@ -1328,6 +1328,8 @@ static int btmtksdio_probe(struct sdio_func *func, { struct btmtksdio_dev *bdev; struct hci_dev *hdev; + struct device_node *old_node; + bool restore_node; int err; bdev = devm_kzalloc(&func->dev, sizeof(*bdev), GFP_KERNEL); @@ -1396,7 +1398,7 @@ static int btmtksdio_probe(struct sdio_func *func, if (pm_runtime_enabled(bdev->dev)) pm_runtime_disable(bdev->dev); - /* As explaination in drivers/mmc/core/sdio_bus.c tells us: + /* As explanation in drivers/mmc/core/sdio_bus.c tells us: * Unbound SDIO functions are always suspended. * During probe, the function is set active and the usage count * is incremented. If the driver supports runtime PM, @@ -1411,13 +1413,24 @@ static int btmtksdio_probe(struct sdio_func *func, if (err) bt_dev_err(hdev, "failed to initialize device wakeup"); - bdev->dev->of_node = of_find_compatible_node(NULL, NULL, - "mediatek,mt7921s-bluetooth"); + restore_node = false; + if (!of_device_is_compatible(bdev->dev->of_node, "mediatek,mt7921s-bluetooth")) { + restore_node = true; + old_node = bdev->dev->of_node; + bdev->dev->of_node = of_find_compatible_node(NULL, NULL, + "mediatek,mt7921s-bluetooth"); + } + bdev->reset = devm_gpiod_get_optional(bdev->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(bdev->reset)) err = PTR_ERR(bdev->reset); + if (restore_node) { + of_node_put(bdev->dev->of_node); + bdev->dev->of_node = old_node; + } + return err; } diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 64e4d835af5211..c97e260fcb0c30 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -327,7 +327,7 @@ mtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count, if (count <= 0) return NULL; - /* Tranlate to how much the size of data H4 can handle so far */ + /* Translate to how much the size of data H4 can handle so far */ *sz_h4 = min_t(int, count, bdev->stp_dlen); /* Update the remaining size of STP packet */ diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index 5ea0d23e88c02b..569f5b7d6e46f2 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -34,16 +35,17 @@ /* NXP HW err codes */ #define BTNXPUART_IR_HW_ERR 0xb0 -#define FIRMWARE_W8987 "uart8987_bt_v0.bin" +#define FIRMWARE_W8987 "uart8987_bt.bin" #define FIRMWARE_W8987_OLD "uartuart8987_bt.bin" #define FIRMWARE_W8997 "uart8997_bt_v4.bin" #define FIRMWARE_W8997_OLD "uartuart8997_bt_v4.bin" #define FIRMWARE_W9098 "uart9098_bt_v1.bin" #define FIRMWARE_W9098_OLD "uartuart9098_bt_v1.bin" -#define FIRMWARE_IW416 "uartiw416_bt_v0.bin" +#define FIRMWARE_IW416 "uartiw416_bt.bin" +#define FIRMWARE_IW416_OLD "uartiw416_bt_v0.bin" #define FIRMWARE_IW612 "uartspi_n61x_v1.bin.se" -#define FIRMWARE_IW615 "uartspi_iw610_v0.bin" -#define FIRMWARE_SECURE_IW615 "uartspi_iw610_v0.bin.se" +#define FIRMWARE_IW610 "uartspi_iw610.bin" +#define FIRMWARE_SECURE_IW610 "uartspi_iw610.bin.se" #define FIRMWARE_IW624 "uartiw624_bt.bin" #define FIRMWARE_SECURE_IW624 "uartiw624_bt.bin.se" #define FIRMWARE_AW693 "uartaw693_bt.bin" @@ -59,8 +61,8 @@ #define CHIP_ID_IW624c 0x8001 #define CHIP_ID_AW693a0 0x8200 #define CHIP_ID_AW693a1 0x8201 -#define CHIP_ID_IW615a0 0x8800 -#define CHIP_ID_IW615a1 0x8801 +#define CHIP_ID_IW610a0 0x8800 +#define CHIP_ID_IW610a1 0x8801 #define FW_SECURE_MASK 0xc0 #define FW_OPEN 0x00 @@ -81,6 +83,7 @@ #define WAKEUP_METHOD_BREAK 1 #define WAKEUP_METHOD_EXT_BREAK 2 #define WAKEUP_METHOD_RTS 3 +#define WAKEUP_METHOD_GPIO 4 #define WAKEUP_METHOD_INVALID 0xff /* power save mode status */ @@ -134,6 +137,7 @@ struct ps_data { bool driver_sent_cmd; u16 h2c_ps_interval; u16 c2h_ps_interval; + struct gpio_desc *h2c_ps_gpio; struct hci_dev *hdev; struct work_struct work; struct timer_list ps_timer; @@ -364,7 +368,7 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct ps_data *psdata = &nxpdev->psdata; - int status; + int status = 0; if (psdata->ps_state == ps_state || !test_bit(BTNXPUART_SERDEV_OPEN, &nxpdev->tx_state)) @@ -372,6 +376,14 @@ static void ps_control(struct hci_dev *hdev, u8 ps_state) mutex_lock(&psdata->ps_lock); switch (psdata->cur_h2c_wakeupmode) { + case WAKEUP_METHOD_GPIO: + if (ps_state == PS_STATE_AWAKE) + gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 0); + else + gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 1); + bt_dev_dbg(hdev, "Set h2c_ps_gpio: %s", + str_high_low(ps_state == PS_STATE_SLEEP)); + break; case WAKEUP_METHOD_DTR: if (ps_state == PS_STATE_AWAKE) status = serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0); @@ -421,15 +433,29 @@ static void ps_timeout_func(struct timer_list *t) } } -static void ps_setup(struct hci_dev *hdev) +static int ps_setup(struct hci_dev *hdev) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); + struct serdev_device *serdev = nxpdev->serdev; struct ps_data *psdata = &nxpdev->psdata; + psdata->h2c_ps_gpio = devm_gpiod_get_optional(&serdev->dev, "device-wakeup", + GPIOD_OUT_LOW); + if (IS_ERR(psdata->h2c_ps_gpio)) { + bt_dev_err(hdev, "Error fetching device-wakeup-gpios: %ld", + PTR_ERR(psdata->h2c_ps_gpio)); + return PTR_ERR(psdata->h2c_ps_gpio); + } + + if (!psdata->h2c_ps_gpio) + psdata->h2c_wakeup_gpio = 0xff; + psdata->hdev = hdev; INIT_WORK(&psdata->work, ps_work_func); mutex_init(&psdata->ps_lock); timer_setup(&psdata->ps_timer, ps_timeout_func, 0); + + return 0; } static bool ps_wakeup(struct btnxpuart_dev *nxpdev) @@ -515,6 +541,9 @@ static int send_wakeup_method_cmd(struct hci_dev *hdev, void *data) pcmd.c2h_wakeupmode = psdata->c2h_wakeupmode; pcmd.c2h_wakeup_gpio = psdata->c2h_wakeup_gpio; switch (psdata->h2c_wakeupmode) { + case WAKEUP_METHOD_GPIO: + pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_GPIO; + break; case WAKEUP_METHOD_DTR: pcmd.h2c_wakeupmode = BT_CTRL_WAKEUP_METHOD_DSR; break; @@ -549,6 +578,7 @@ static void ps_init(struct hci_dev *hdev) { struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev); struct ps_data *psdata = &nxpdev->psdata; + u8 default_h2c_wakeup_mode = DEFAULT_H2C_WAKEUP_MODE; serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_RTS); usleep_range(5000, 10000); @@ -560,8 +590,17 @@ static void ps_init(struct hci_dev *hdev) psdata->c2h_wakeup_gpio = 0xff; psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID; + if (psdata->h2c_ps_gpio) + default_h2c_wakeup_mode = WAKEUP_METHOD_GPIO; + psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS; - switch (DEFAULT_H2C_WAKEUP_MODE) { + + switch (default_h2c_wakeup_mode) { + case WAKEUP_METHOD_GPIO: + psdata->h2c_wakeupmode = WAKEUP_METHOD_GPIO; + gpiod_set_value_cansleep(psdata->h2c_ps_gpio, 0); + usleep_range(5000, 10000); + break; case WAKEUP_METHOD_DTR: psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR; serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR); @@ -946,12 +985,12 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid, else bt_dev_err(hdev, "Illegal loader version %02x", loader_ver); break; - case CHIP_ID_IW615a0: - case CHIP_ID_IW615a1: + case CHIP_ID_IW610a0: + case CHIP_ID_IW610a1: if ((loader_ver & FW_SECURE_MASK) == FW_OPEN) - fw_name = FIRMWARE_IW615; + fw_name = FIRMWARE_IW610; else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL) - fw_name = FIRMWARE_SECURE_IW615; + fw_name = FIRMWARE_SECURE_IW610; else bt_dev_err(hdev, "Illegal loader version %02x", loader_ver); break; @@ -971,6 +1010,9 @@ static char *nxp_get_old_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid, case CHIP_ID_W9098: fw_name_old = FIRMWARE_W9098_OLD; break; + case CHIP_ID_IW416: + fw_name_old = FIRMWARE_IW416_OLD; + break; } return fw_name_old; } @@ -1275,6 +1317,9 @@ static int nxp_enqueue(struct hci_dev *hdev, struct sk_buff *skb) psdata->c2h_wakeup_gpio = wakeup_parm.c2h_wakeup_gpio; psdata->h2c_wakeup_gpio = wakeup_parm.h2c_wakeup_gpio; switch (wakeup_parm.h2c_wakeupmode) { + case BT_CTRL_WAKEUP_METHOD_GPIO: + psdata->h2c_wakeupmode = WAKEUP_METHOD_GPIO; + break; case BT_CTRL_WAKEUP_METHOD_DSR: psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR; break; @@ -1505,13 +1550,17 @@ static int nxp_serdev_probe(struct serdev_device *serdev) if (hci_register_dev(hdev) < 0) { dev_err(&serdev->dev, "Can't register HCI device\n"); - hci_free_dev(hdev); - return -ENODEV; + goto probe_fail; } - ps_setup(hdev); + if (ps_setup(hdev)) + goto probe_fail; return 0; + +probe_fail: + hci_free_dev(hdev); + return -ENODEV; } static void nxp_serdev_remove(struct serdev_device *serdev) diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c index 88dbb2f3fabf98..c0eb71d6ffd3bd 100644 --- a/drivers/bluetooth/btqcomsmd.c +++ b/drivers/bluetooth/btqcomsmd.c @@ -216,7 +216,7 @@ MODULE_DEVICE_TABLE(of, btqcomsmd_of_match); static struct platform_driver btqcomsmd_driver = { .probe = btqcomsmd_probe, - .remove_new = btqcomsmd_remove, + .remove = btqcomsmd_remove, .driver = { .name = "btqcomsmd", .of_match_table = btqcomsmd_of_match, diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 0bcb44cf7b31d7..83025f457ca044 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -1371,7 +1371,7 @@ int btrtl_shutdown_realtek(struct hci_dev *hdev) /* According to the vendor driver, BT must be reset on close to avoid * firmware crash. */ - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_CMD_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); bt_dev_err(hdev, "HCI reset during shutdown failed"); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e9534fbc92e32f..279fe6c115fac5 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -371,6 +371,12 @@ static const struct usb_device_id quirks_table[] = { /* QCA WCN785x chipset */ { USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe0fc), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe0f3), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3623), .driver_info = BTUSB_QCA_WCN6855 | + BTUSB_WIDEBAND_SPEECH }, /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, @@ -524,6 +530,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe123), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, @@ -563,6 +571,16 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x043e, 0x3109), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + /* Additional MediaTek MT7920 Bluetooth devices */ + { USB_DEVICE(0x0489, 0xe134), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3620), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3621), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3622), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + /* Additional MediaTek MT7921 Bluetooth devices */ { USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, @@ -630,12 +648,24 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, /* Additional MediaTek MT7925 Bluetooth devices */ + { USB_DEVICE(0x0489, 0xe111), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe113), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe118), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0489, 0xe11e), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe124), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe139), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe14f), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe150), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x0489, 0xe151), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3602), .driver_info = BTUSB_MEDIATEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3603), .driver_info = BTUSB_MEDIATEK | @@ -846,6 +876,7 @@ struct btusb_data { int (*suspend)(struct hci_dev *hdev); int (*resume)(struct hci_dev *hdev); + int (*disconnect)(struct hci_dev *hdev); int oob_wake_irq; /* irq for out-of-band wake-on-bt */ unsigned cmd_timeout_cnt; @@ -1061,7 +1092,7 @@ static inline void btusb_free_frags(struct btusb_data *data) static int btusb_recv_event(struct btusb_data *data, struct sk_buff *skb) { if (data->intr_interval) { - /* Trigger dequeue immediatelly if an event is received */ + /* Trigger dequeue immediately if an event is received */ schedule_delayed_work(&data->rx_work, 0); } @@ -2616,13 +2647,14 @@ static void btusb_mtk_claim_iso_intf(struct btusb_data *data) } set_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags); + init_usb_anchor(&btmtk_data->isopkt_anchor); } -static void btusb_mtk_release_iso_intf(struct btusb_data *data) +static void btusb_mtk_release_iso_intf(struct hci_dev *hdev) { - struct btmtk_data *btmtk_data = hci_get_priv(data->hdev); + struct btmtk_data *btmtk_data = hci_get_priv(hdev); - if (btmtk_data->isopkt_intf) { + if (test_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags)) { usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor); clear_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags); @@ -2636,6 +2668,16 @@ static void btusb_mtk_release_iso_intf(struct btusb_data *data) clear_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags); } +static int btusb_mtk_disconnect(struct hci_dev *hdev) +{ + /* This function describes the specific additional steps taken by MediaTek + * when Bluetooth usb driver's resume function is called. + */ + btusb_mtk_release_iso_intf(hdev); + + return 0; +} + static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -2652,8 +2694,8 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) if (err < 0) return err; - if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags)) - btusb_mtk_release_iso_intf(data); + /* Release MediaTek ISO data interface */ + btusb_mtk_release_iso_intf(hdev); btusb_stop_traffic(data); usb_kill_anchored_urbs(&data->tx_anchor); @@ -2698,22 +2740,24 @@ static int btusb_mtk_setup(struct hci_dev *hdev) btmtk_data->reset_sync = btusb_mtk_reset; /* Claim ISO data interface and endpoint */ - btmtk_data->isopkt_intf = usb_ifnum_to_if(data->udev, MTK_ISO_IFNUM); - if (btmtk_data->isopkt_intf) + if (!test_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags)) { + btmtk_data->isopkt_intf = usb_ifnum_to_if(data->udev, MTK_ISO_IFNUM); btusb_mtk_claim_iso_intf(data); + } return btmtk_usb_setup(hdev); } static int btusb_mtk_shutdown(struct hci_dev *hdev) { - struct btusb_data *data = hci_get_drvdata(hdev); - struct btmtk_data *btmtk_data = hci_get_priv(hdev); + int ret; - if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags)) - btusb_mtk_release_iso_intf(data); + ret = btmtk_usb_shutdown(hdev); - return btmtk_usb_shutdown(hdev); + /* Release MediaTek iso interface after shutdown */ + btusb_mtk_release_iso_intf(hdev); + + return ret; } #ifdef CONFIG_PM @@ -3825,6 +3869,7 @@ static int btusb_probe(struct usb_interface *intf, data->recv_acl = btmtk_usb_recv_acl; data->suspend = btmtk_usb_suspend; data->resume = btmtk_usb_resume; + data->disconnect = btusb_mtk_disconnect; } if (id->driver_info & BTUSB_SWAVE) { @@ -3896,6 +3941,8 @@ static int btusb_probe(struct usb_interface *intf, set_bit(HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT, &hdev->quirks); set_bit(HCI_QUIRK_BROKEN_EXT_SCAN, &hdev->quirks); set_bit(HCI_QUIRK_BROKEN_READ_ENC_KEY_SIZE, &hdev->quirks); + set_bit(HCI_QUIRK_BROKEN_EXT_CREATE_CONN, &hdev->quirks); + set_bit(HCI_QUIRK_BROKEN_WRITE_AUTH_PAYLOAD_TIMEOUT, &hdev->quirks); } if (!reset) @@ -4013,6 +4060,9 @@ static void btusb_disconnect(struct usb_interface *intf) if (data->diag) usb_set_intfdata(data->diag, NULL); + if (data->disconnect) + data->disconnect(hdev); + hci_unregister_dev(hdev); if (intf == data->intf) { diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 89d4c2224546fb..9684eb16059bb0 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -1068,17 +1068,17 @@ static struct clk *bcm_get_txco(struct device *dev) struct clk *clk; /* New explicit name */ - clk = devm_clk_get(dev, "txco"); - if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER) + clk = devm_clk_get_optional(dev, "txco"); + if (clk) return clk; /* Deprecated name */ - clk = devm_clk_get(dev, "extclk"); - if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER) + clk = devm_clk_get_optional(dev, "extclk"); + if (clk) return clk; /* Original code used no name at all */ - return devm_clk_get(dev, NULL); + return devm_clk_get_optional(dev, NULL); } static int bcm_get_resources(struct bcm_device *dev) @@ -1093,21 +1093,12 @@ static int bcm_get_resources(struct bcm_device *dev) return 0; dev->txco_clk = bcm_get_txco(dev->dev); - - /* Handle deferred probing */ - if (dev->txco_clk == ERR_PTR(-EPROBE_DEFER)) - return PTR_ERR(dev->txco_clk); - - /* Ignore all other errors as before */ if (IS_ERR(dev->txco_clk)) - dev->txco_clk = NULL; - - dev->lpo_clk = devm_clk_get(dev->dev, "lpo"); - if (dev->lpo_clk == ERR_PTR(-EPROBE_DEFER)) - return PTR_ERR(dev->lpo_clk); + return PTR_ERR(dev->txco_clk); + dev->lpo_clk = devm_clk_get_optional(dev->dev, "lpo"); if (IS_ERR(dev->lpo_clk)) - dev->lpo_clk = NULL; + return PTR_ERR(dev->lpo_clk); /* Check if we accidentally fetched the lpo clock twice */ if (dev->lpo_clk && clk_is_match(dev->lpo_clk, dev->txco_clk)) { @@ -1507,7 +1498,7 @@ static const struct dev_pm_ops bcm_pm_ops = { static struct platform_driver bcm_driver = { .probe = bcm_probe, - .remove_new = bcm_remove, + .remove = bcm_remove, .driver = { .name = "hci_bcm", .acpi_match_table = ACPI_PTR(bcm_acpi_match), diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 999ccd5bb4f248..811f33701f8477 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -1206,7 +1206,7 @@ static void intel_remove(struct platform_device *pdev) static struct platform_driver intel_driver = { .probe = intel_probe, - .remove_new = intel_remove, + .remove = intel_remove, .driver = { .name = "hci_intel", .acpi_match_table = ACPI_PTR(intel_acpi_match), diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 395d66e32a2ea9..d2d6ba8d2f8b1c 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -594,7 +594,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) * Called by tty low level driver when receive data is * available. * - * Arguments: tty pointer to tty isntance data + * Arguments: tty pointer to tty instance data * data pointer to received data * flags pointer to flags for data * count count of received data in bytes diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 4a0b5c3160c2b6..e19e9bd4955564 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -305,7 +305,7 @@ static void ll_device_woke_up(struct hci_uart *hu) hci_uart_tx_wakeup(hu); } -/* Enqueue frame for transmittion (padding, crc, etc) */ +/* Enqueue frame for transmission (padding, crc, etc) */ /* may be called from two simultaneous tasklets */ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb) { diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c index 49bbe4975be4bc..9fc10a16fd962d 100644 --- a/drivers/bluetooth/hci_nokia.c +++ b/drivers/bluetooth/hci_nokia.c @@ -501,7 +501,7 @@ static int nokia_close(struct hci_uart *hu) return 0; } -/* Enqueue frame for transmittion (padding, crc, etc) */ +/* Enqueue frame for transmission (padding, crc, etc) */ static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb) { struct nokia_bt_dev *btdev = hu->priv; diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 37fddf6055bebb..37129e6cb0eb13 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -873,7 +873,7 @@ static void device_woke_up(struct hci_uart *hu) hci_uart_tx_wakeup(hu); } -/* Enqueue frame for transmittion (padding, crc, etc) may be called from +/* Enqueue frame for transmission (padding, crc, etc) may be called from * two simultaneous tasklets. */ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb) @@ -1059,7 +1059,7 @@ static void qca_controller_memdump(struct work_struct *work) if (!seq_no) { /* This is the first frame of memdump packet from - * the controller, Disable IBS to recevie dump + * the controller, Disable IBS to receive dump * with out any interruption, ideally time required for * the controller to send the dump is 8 seconds. let us * start timer to handle this asynchronous activity. @@ -2294,13 +2294,6 @@ static int qca_init_regulators(struct qca_power *qca, return 0; } -static void qca_clk_disable_unprepare(void *data) -{ - struct clk *clk = data; - - clk_disable_unprepare(clk); -} - static int qca_serdev_probe(struct serdev_device *serdev) { struct qca_serdev *qcadev; @@ -2358,7 +2351,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) * Backward compatibility with old DT sources. If the * node doesn't have the 'enable-gpios' property then * let's use the power sequencer. Otherwise, let's - * drive everything outselves. + * drive everything ourselves. */ qcadev->bt_power->pwrseq = devm_pwrseq_get(&serdev->dev, "bluetooth"); @@ -2433,25 +2426,12 @@ static int qca_serdev_probe(struct serdev_device *serdev) if (!qcadev->bt_en) power_ctrl_enabled = false; - qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL); + qcadev->susclk = devm_clk_get_optional_enabled_with_rate( + &serdev->dev, NULL, SUSCLK_RATE_32KHZ); if (IS_ERR(qcadev->susclk)) { dev_warn(&serdev->dev, "failed to acquire clk\n"); return PTR_ERR(qcadev->susclk); } - err = clk_set_rate(qcadev->susclk, SUSCLK_RATE_32KHZ); - if (err) - return err; - - err = clk_prepare_enable(qcadev->susclk); - if (err) - return err; - - err = devm_add_action_or_reset(&serdev->dev, - qca_clk_disable_unprepare, - qcadev->susclk); - if (err) - return err; - } err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto); @@ -2530,7 +2510,7 @@ static void qca_serdev_shutdown(struct device *dev) hci_dev_test_flag(hdev, HCI_SETUP)) return; - /* The serdev must be in open state when conrol logic arrives + /* The serdev must be in open state when control logic arrives * here, so also fix the use-after-free issue caused by that * the serdev is flushed or wrote after it is closed. */ diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 930d8a3ba722b3..2916d13336499c 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1210,7 +1210,7 @@ static struct platform_driver fsl_mc_bus_driver = { .acpi_match_table = fsl_mc_bus_acpi_match_table, }, .probe = fsl_mc_bus_probe, - .remove_new = fsl_mc_bus_remove, + .remove = fsl_mc_bus_remove, .shutdown = fsl_mc_bus_remove, }; diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index 09340adbacc2cc..53dd1573e3238a 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c @@ -689,6 +689,6 @@ static struct platform_driver hisi_lpc_driver = { .acpi_match_table = hisi_lpc_acpi_match, }, .probe = hisi_lpc_probe, - .remove_new = hisi_lpc_remove, + .remove = hisi_lpc_remove, }; builtin_platform_driver(hisi_lpc_driver); diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index dedd29ca8db355..e8c92972f9df92 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -82,9 +82,9 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) * other cores to shutdown while we're collecting RDDM buffer. After * returning from this function, we expect the device to reset. * - * Normaly, we read/write pm_state only after grabbing the + * Normally, we read/write pm_state only after grabbing the * pm_lock, since we're in a panic, skipping it. Also there is no - * gurantee that this state change would take effect since + * guarantee that this state change would take effect since * we're setting it w/o grabbing pm_lock */ mhi_cntrl->pm_state = MHI_PM_LD_ERR_FATAL_DETECT; diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h index d057e877932e3a..3134f111be3533 100644 --- a/drivers/bus/mhi/host/internal.h +++ b/drivers/bus/mhi/host/internal.h @@ -255,7 +255,7 @@ struct mhi_chan { /* * Important: When consuming, increment tre_ring first and when * releasing, decrement buf_ring first. If tre_ring has space, buf_ring - * is guranteed to have space so we do not need to check both rings. + * is guaranteed to have space so we do not need to check both rings. */ struct mhi_ring buf_ring; struct mhi_ring tre_ring; diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 9938bb034c1cbc..07645ce2119a71 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -917,12 +917,12 @@ static int mhi_pci_claim(struct mhi_controller *mhi_cntrl, return err; } - err = pcim_iomap_regions(pdev, 1 << bar_num, pci_name(pdev)); - if (err) { + mhi_cntrl->regs = pcim_iomap_region(pdev, 1 << bar_num, pci_name(pdev)); + if (IS_ERR(mhi_cntrl->regs)) { + err = PTR_ERR(mhi_cntrl->regs); dev_err(&pdev->dev, "failed to map pci region: %d\n", err); return err; } - mhi_cntrl->regs = pcim_iomap_table(pdev)[bar_num]; mhi_cntrl->reg_len = pci_resource_len(pdev, bar_num); err = dma_set_mask_and_coherent(&pdev->dev, dma_mask); diff --git a/drivers/bus/mhi/host/trace.h b/drivers/bus/mhi/host/trace.h index 95613c8ebe0691..3e0c41777429eb 100644 --- a/drivers/bus/mhi/host/trace.h +++ b/drivers/bus/mhi/host/trace.h @@ -9,6 +9,7 @@ #if !defined(_TRACE_EVENT_MHI_HOST_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_EVENT_MHI_HOST_H +#include #include #include #include "../common.h" @@ -97,18 +98,18 @@ TRACE_EVENT(mhi_gen_tre, __string(name, mhi_cntrl->mhi_dev->name) __field(int, ch_num) __field(void *, wp) - __field(__le64, tre_ptr) - __field(__le32, dword0) - __field(__le32, dword1) + __field(uint64_t, tre_ptr) + __field(uint32_t, dword0) + __field(uint32_t, dword1) ), TP_fast_assign( __assign_str(name); __entry->ch_num = mhi_chan->chan; __entry->wp = mhi_tre; - __entry->tre_ptr = mhi_tre->ptr; - __entry->dword0 = mhi_tre->dword[0]; - __entry->dword1 = mhi_tre->dword[1]; + __entry->tre_ptr = le64_to_cpu(mhi_tre->ptr); + __entry->dword0 = le32_to_cpu(mhi_tre->dword[0]); + __entry->dword1 = le32_to_cpu(mhi_tre->dword[1]); ), TP_printk("%s: Chan: %d TRE: 0x%p TRE buf: 0x%llx DWORD0: 0x%08x DWORD1: 0x%08x\n", @@ -176,19 +177,19 @@ DECLARE_EVENT_CLASS(mhi_process_event_ring, TP_STRUCT__entry( __string(name, mhi_cntrl->mhi_dev->name) - __field(__le32, dword0) - __field(__le32, dword1) + __field(uint32_t, dword0) + __field(uint32_t, dword1) __field(int, state) - __field(__le64, ptr) + __field(uint64_t, ptr) __field(void *, rp) ), TP_fast_assign( __assign_str(name); __entry->rp = rp; - __entry->ptr = rp->ptr; - __entry->dword0 = rp->dword[0]; - __entry->dword1 = rp->dword[1]; + __entry->ptr = le64_to_cpu(rp->ptr); + __entry->dword0 = le32_to_cpu(rp->dword[0]); + __entry->dword1 = le32_to_cpu(rp->dword[1]); __entry->state = MHI_TRE_GET_EV_STATE(rp); ), diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c index 7d7479ba0a7599..e4dfda7b3b1027 100644 --- a/drivers/bus/omap-ocp2scp.c +++ b/drivers/bus/omap-ocp2scp.c @@ -101,7 +101,7 @@ MODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table); static struct platform_driver omap_ocp2scp_driver = { .probe = omap_ocp2scp_probe, - .remove_new = omap_ocp2scp_remove, + .remove = omap_ocp2scp_remove, .driver = { .name = "omap-ocp2scp", .of_match_table = of_match_ptr(omap_ocp2scp_id_table), diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c index ee6d29925e4df7..7f0a8f8b3f4ce7 100644 --- a/drivers/bus/omap_l3_smx.c +++ b/drivers/bus/omap_l3_smx.c @@ -273,7 +273,7 @@ static void omap3_l3_remove(struct platform_device *pdev) static struct platform_driver omap3_l3_driver = { .probe = omap3_l3_probe, - .remove_new = omap3_l3_remove, + .remove = omap3_l3_remove, .driver = { .name = "omap_l3_smx", .of_match_table = of_match_ptr(omap3_l3_match), diff --git a/drivers/bus/qcom-ssc-block-bus.c b/drivers/bus/qcom-ssc-block-bus.c index 5931974a21fa3a..85d781a32df4b2 100644 --- a/drivers/bus/qcom-ssc-block-bus.c +++ b/drivers/bus/qcom-ssc-block-bus.c @@ -373,7 +373,7 @@ MODULE_DEVICE_TABLE(of, qcom_ssc_block_bus_of_match); static struct platform_driver qcom_ssc_block_bus_driver = { .probe = qcom_ssc_block_bus_probe, - .remove_new = qcom_ssc_block_bus_remove, + .remove = qcom_ssc_block_bus_remove, .driver = { .name = "qcom-ssc-block-bus", .of_match_table = qcom_ssc_block_bus_of_match, diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c index 50870c82788992..5dea31769f9a8b 100644 --- a/drivers/bus/simple-pm-bus.c +++ b/drivers/bus/simple-pm-bus.c @@ -128,7 +128,7 @@ MODULE_DEVICE_TABLE(of, simple_pm_bus_of_match); static struct platform_driver simple_pm_bus_driver = { .probe = simple_pm_bus_probe, - .remove_new = simple_pm_bus_remove, + .remove = simple_pm_bus_remove, .driver = { .name = "simple-pm-bus", .of_match_table = simple_pm_bus_of_match, diff --git a/drivers/bus/sun50i-de2.c b/drivers/bus/sun50i-de2.c index 3339311ce06834..dfe588179acab9 100644 --- a/drivers/bus/sun50i-de2.c +++ b/drivers/bus/sun50i-de2.c @@ -36,7 +36,7 @@ static const struct of_device_id sun50i_de2_bus_of_match[] = { static struct platform_driver sun50i_de2_bus_driver = { .probe = sun50i_de2_bus_probe, - .remove_new = sun50i_de2_bus_remove, + .remove = sun50i_de2_bus_remove, .driver = { .name = "sun50i-de2-bus", .of_match_table = sun50i_de2_bus_of_match, diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index a89d7892563767..7a33c3b31d1e94 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -832,7 +832,7 @@ MODULE_DEVICE_TABLE(of, sunxi_rsb_of_match_table); static struct platform_driver sunxi_rsb_driver = { .probe = sunxi_rsb_probe, - .remove_new = sunxi_rsb_remove, + .remove = sunxi_rsb_remove, .driver = { .name = RSB_CTRL_NAME, .of_match_table = sunxi_rsb_of_match_table, diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c index de80008bff92de..90e3b0a108161e 100644 --- a/drivers/bus/tegra-aconnect.c +++ b/drivers/bus/tegra-aconnect.c @@ -104,7 +104,7 @@ MODULE_DEVICE_TABLE(of, tegra_aconnect_of_match); static struct platform_driver tegra_aconnect_driver = { .probe = tegra_aconnect_probe, - .remove_new = tegra_aconnect_remove, + .remove = tegra_aconnect_remove, .driver = { .name = "tegra-aconnect", .of_match_table = tegra_aconnect_of_match, diff --git a/drivers/bus/tegra-gmi.c b/drivers/bus/tegra-gmi.c index f5d6414df9f238..9c09141961d87e 100644 --- a/drivers/bus/tegra-gmi.c +++ b/drivers/bus/tegra-gmi.c @@ -303,7 +303,7 @@ MODULE_DEVICE_TABLE(of, tegra_gmi_id_table); static struct platform_driver tegra_gmi_driver = { .probe = tegra_gmi_probe, - .remove_new = tegra_gmi_remove, + .remove = tegra_gmi_remove, .driver = { .name = "tegra-gmi", .of_match_table = tegra_gmi_id_table, diff --git a/drivers/bus/ti-pwmss.c b/drivers/bus/ti-pwmss.c index 4969c556e7521b..1f2cab91e43899 100644 --- a/drivers/bus/ti-pwmss.c +++ b/drivers/bus/ti-pwmss.c @@ -44,7 +44,7 @@ static struct platform_driver pwmss_driver = { .of_match_table = pwmss_of_match, }, .probe = pwmss_probe, - .remove_new = pwmss_remove, + .remove = pwmss_remove, }; module_platform_driver(pwmss_driver); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 270a94a06e05ce..f67b927ae4caa8 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -3345,7 +3345,7 @@ MODULE_DEVICE_TABLE(of, sysc_match); static struct platform_driver sysc_driver = { .probe = sysc_probe, - .remove_new = sysc_remove, + .remove = sysc_remove, .driver = { .name = "ti-sysc", .of_match_table = sysc_match, diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c index b8af44c5cdbd0d..2328c48b9b1260 100644 --- a/drivers/bus/ts-nbus.c +++ b/drivers/bus/ts-nbus.c @@ -336,7 +336,7 @@ MODULE_DEVICE_TABLE(of, ts_nbus_of_match); static struct platform_driver ts_nbus_driver = { .probe = ts_nbus_probe, - .remove_new = ts_nbus_remove, + .remove = ts_nbus_remove, .driver = { .name = "ts_nbus", .of_match_table = ts_nbus_of_match, diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 71cfe7a85913c4..64b097e830d464 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -847,7 +847,7 @@ static void remove_gdrom(struct platform_device *devptr) static struct platform_driver gdrom_driver = { .probe = probe_gdrom, - .remove_new = remove_gdrom, + .remove = remove_gdrom, .driver = { .name = GDROM_DEV_NAME, }, diff --git a/drivers/cdx/Makefile b/drivers/cdx/Makefile index 749a3295c2bdc1..3ca7068a305256 100644 --- a/drivers/cdx/Makefile +++ b/drivers/cdx/Makefile @@ -5,7 +5,7 @@ # Copyright (C) 2022-2023, Advanced Micro Devices, Inc. # -ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CDX_BUS +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"CDX_BUS"' obj-$(CONFIG_CDX_BUS) += cdx.o controller/ diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 07371cb653d356..76eac3653b1c64 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -707,7 +707,7 @@ static const struct vm_operations_struct cdx_phys_vm_ops = { * Return: true on success, false otherwise. */ static int cdx_mmap_resource(struct file *fp, struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma) { struct cdx_device *cdx_dev = to_cdx_device(kobj_to_dev(kobj)); @@ -868,7 +868,7 @@ int cdx_device_add(struct cdx_dev_params *dev_params) return ret; } -EXPORT_SYMBOL_NS_GPL(cdx_device_add, CDX_BUS_CONTROLLER); +EXPORT_SYMBOL_NS_GPL(cdx_device_add, "CDX_BUS_CONTROLLER"); struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num) { @@ -915,7 +915,7 @@ struct device *cdx_bus_add(struct cdx_controller *cdx, u8 bus_num) return NULL; } -EXPORT_SYMBOL_NS_GPL(cdx_bus_add, CDX_BUS_CONTROLLER); +EXPORT_SYMBOL_NS_GPL(cdx_bus_add, "CDX_BUS_CONTROLLER"); int cdx_register_controller(struct cdx_controller *cdx) { @@ -940,7 +940,7 @@ int cdx_register_controller(struct cdx_controller *cdx) return 0; } -EXPORT_SYMBOL_NS_GPL(cdx_register_controller, CDX_BUS_CONTROLLER); +EXPORT_SYMBOL_NS_GPL(cdx_register_controller, "CDX_BUS_CONTROLLER"); void cdx_unregister_controller(struct cdx_controller *cdx) { @@ -955,7 +955,7 @@ void cdx_unregister_controller(struct cdx_controller *cdx) mutex_unlock(&cdx_controller_lock); } -EXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, CDX_BUS_CONTROLLER); +EXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, "CDX_BUS_CONTROLLER"); static int __init cdx_bus_init(void) { diff --git a/drivers/cdx/cdx_msi.c b/drivers/cdx/cdx_msi.c index e55f1716cfcb20..06d7239782327b 100644 --- a/drivers/cdx/cdx_msi.c +++ b/drivers/cdx/cdx_msi.c @@ -189,4 +189,4 @@ struct irq_domain *cdx_msi_domain_init(struct device *dev) return cdx_msi_domain; } -EXPORT_SYMBOL_NS_GPL(cdx_msi_domain_init, CDX_BUS_CONTROLLER); +EXPORT_SYMBOL_NS_GPL(cdx_msi_domain_init, "CDX_BUS_CONTROLLER"); diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index 201f9a6fbde702..d623f9c7517a86 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -250,7 +250,7 @@ static struct platform_driver cdx_pdriver = { .of_match_table = cdx_match_table, }, .probe = xlnx_cdx_probe, - .remove_new = xlnx_cdx_remove, + .remove = xlnx_cdx_remove, }; static int __init cdx_controller_init(void) @@ -275,4 +275,4 @@ module_exit(cdx_controller_exit); MODULE_AUTHOR("AMD Inc."); MODULE_DESCRIPTION("CDX controller for AMD devices"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CDX_BUS_CONTROLLER); +MODULE_IMPORT_NS("CDX_BUS_CONTROLLER"); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 7c8dd0abcfdf72..8fb33c90482f79 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -238,6 +238,7 @@ config APPLICOM config SONYPI tristate "Sony Vaio Programmable I/O Control Device support" depends on X86_32 && PCI && INPUT + depends on ACPI_EC || !ACPI help This driver enables access to the Sony Programmable I/O Control Device which can be found in many (all ?) Sony Vaio laptops. diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index e904e476e49ad8..48fe96ab464901 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -162,6 +162,7 @@ static irqreturn_t hpet_interrupt(int irq, void *data) static void hpet_timer_set_irq(struct hpet_dev *devp) { + const unsigned int nr_irqs = irq_get_nr_irqs(); unsigned long v; int irq, gsi; struct hpet_timer __iomem *timer; diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index b51d9e243f3512..17854f052386ef 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -50,7 +50,7 @@ config HW_RANDOM_INTEL config HW_RANDOM_AMD tristate "AMD HW Random Number Generator support" - depends on (X86 || PPC_MAPLE || COMPILE_TEST) + depends on (X86 || COMPILE_TEST) depends on PCI && HAS_IOPORT_MAP default HW_RANDOM help @@ -62,6 +62,19 @@ config HW_RANDOM_AMD If unsure, say Y. +config HW_RANDOM_AIROHA + tristate "Airoha True HW Random Number Generator support" + depends on ARCH_AIROHA || COMPILE_TEST + default HW_RANDOM + help + This driver provides kernel-side support for the True Random Number + Generator hardware found on Airoha SoC. + + To compile this driver as a module, choose M here: the + module will be called airoha-rng. + + If unsure, say Y. + config HW_RANDOM_ATMEL tristate "Atmel Random Number Generator support" depends on (ARCH_AT91 || COMPILE_TEST) @@ -99,9 +112,22 @@ config HW_RANDOM_BCM2835 If unsure, say Y. +config HW_RANDOM_BCM74110 + tristate "Broadcom BCM74110 Random Number Generator support" + depends on ARCH_BRCMSTB || COMPILE_TEST + default HW_RANDOM + help + This driver provides kernel-side support for the Random Number + Generator hardware found on the Broadcom BCM74110 SoCs. + + To compile this driver as a module, choose M here: the + module will be called bcm74110-rng + + If unsure, say Y. + config HW_RANDOM_IPROC_RNG200 tristate "Broadcom iProc/STB RNG200 support" - depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST + depends on ARCH_BCM_IPROC || ARCH_BCM2835 || ARCH_BCMBCA || ARCH_BRCMSTB || COMPILE_TEST default HW_RANDOM help This driver provides kernel-side support for the RNG200 diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 01f012eab44008..b9132b3f5d2103 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -8,6 +8,7 @@ rng-core-y := core.o obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o +obj-$(CONFIG_HW_RANDOM_AIROHA) += airoha-trng.o obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o obj-$(CONFIG_HW_RANDOM_BA431) += ba431-rng.o obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o @@ -31,6 +32,7 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o obj-$(CONFIG_HW_RANDOM_HISTB) += histb-rng.o obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o +obj-$(CONFIG_HW_RANDOM_BCM74110) += bcm74110-rng.o obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o diff --git a/drivers/char/hw_random/airoha-trng.c b/drivers/char/hw_random/airoha-trng.c new file mode 100644 index 00000000000000..1dbfa9505c214f --- /dev/null +++ b/drivers/char/hw_random/airoha-trng.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2024 Christian Marangi */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRNG_IP_RDY 0x800 +#define CNT_TRANS GENMASK(15, 8) +#define SAMPLE_RDY BIT(0) +#define TRNG_NS_SEK_AND_DAT_EN 0x804 +#define RNG_EN BIT(31) /* referenced as ring_en */ +#define RAW_DATA_EN BIT(16) +#define TRNG_HEALTH_TEST_SW_RST 0x808 +#define SW_RST BIT(0) /* Active High */ +#define TRNG_INTR_EN 0x818 +#define INTR_MASK BIT(16) +#define CONTINUOUS_HEALTH_INITR_EN BIT(2) +#define SW_STARTUP_INITR_EN BIT(1) +#define RST_STARTUP_INITR_EN BIT(0) +/* Notice that Health Test are done only out of Reset and with RNG_EN */ +#define TRNG_HEALTH_TEST_STATUS 0x824 +#define CONTINUOUS_HEALTH_AP_TEST_FAIL BIT(23) +#define CONTINUOUS_HEALTH_RC_TEST_FAIL BIT(22) +#define SW_STARTUP_TEST_DONE BIT(21) +#define SW_STARTUP_AP_TEST_FAIL BIT(20) +#define SW_STARTUP_RC_TEST_FAIL BIT(19) +#define RST_STARTUP_TEST_DONE BIT(18) +#define RST_STARTUP_AP_TEST_FAIL BIT(17) +#define RST_STARTUP_RC_TEST_FAIL BIT(16) +#define RAW_DATA_VALID BIT(7) + +#define TRNG_RAW_DATA_OUT 0x828 + +#define TRNG_CNT_TRANS_VALID 0x80 +#define BUSY_LOOP_SLEEP 10 +#define BUSY_LOOP_TIMEOUT (BUSY_LOOP_SLEEP * 10000) + +struct airoha_trng { + void __iomem *base; + struct hwrng rng; + struct device *dev; + + struct completion rng_op_done; +}; + +static int airoha_trng_irq_mask(struct airoha_trng *trng) +{ + u32 val; + + val = readl(trng->base + TRNG_INTR_EN); + val |= INTR_MASK; + writel(val, trng->base + TRNG_INTR_EN); + + return 0; +} + +static int airoha_trng_irq_unmask(struct airoha_trng *trng) +{ + u32 val; + + val = readl(trng->base + TRNG_INTR_EN); + val &= ~INTR_MASK; + writel(val, trng->base + TRNG_INTR_EN); + + return 0; +} + +static int airoha_trng_init(struct hwrng *rng) +{ + struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); + int ret; + u32 val; + + val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); + val |= RNG_EN; + writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); + + /* Set out of SW Reset */ + airoha_trng_irq_unmask(trng); + writel(0, trng->base + TRNG_HEALTH_TEST_SW_RST); + + ret = wait_for_completion_timeout(&trng->rng_op_done, BUSY_LOOP_TIMEOUT); + if (ret <= 0) { + dev_err(trng->dev, "Timeout waiting for Health Check\n"); + airoha_trng_irq_mask(trng); + return -ENODEV; + } + + /* Check if Health Test Failed */ + val = readl(trng->base + TRNG_HEALTH_TEST_STATUS); + if (val & (RST_STARTUP_AP_TEST_FAIL | RST_STARTUP_RC_TEST_FAIL)) { + dev_err(trng->dev, "Health Check fail: %s test fail\n", + val & RST_STARTUP_AP_TEST_FAIL ? "AP" : "RC"); + return -ENODEV; + } + + /* Check if IP is ready */ + ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val, + val & SAMPLE_RDY, 10, 1000); + if (ret < 0) { + dev_err(trng->dev, "Timeout waiting for IP ready"); + return -ENODEV; + } + + /* CNT_TRANS must be 0x80 for IP to be considered ready */ + ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val, + FIELD_GET(CNT_TRANS, val) == TRNG_CNT_TRANS_VALID, + 10, 1000); + if (ret < 0) { + dev_err(trng->dev, "Timeout waiting for IP ready"); + return -ENODEV; + } + + return 0; +} + +static void airoha_trng_cleanup(struct hwrng *rng) +{ + struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); + u32 val; + + val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); + val &= ~RNG_EN; + writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); + + /* Put it in SW Reset */ + writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST); +} + +static int airoha_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait) +{ + struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); + u32 *data = buf; + u32 status; + int ret; + + ret = readl_poll_timeout(trng->base + TRNG_HEALTH_TEST_STATUS, status, + status & RAW_DATA_VALID, 10, 1000); + if (ret < 0) { + dev_err(trng->dev, "Timeout waiting for TRNG RAW Data valid\n"); + return ret; + } + + *data = readl(trng->base + TRNG_RAW_DATA_OUT); + + return 4; +} + +static irqreturn_t airoha_trng_irq(int irq, void *priv) +{ + struct airoha_trng *trng = (struct airoha_trng *)priv; + + airoha_trng_irq_mask(trng); + /* Just complete the task, we will read the value later */ + complete(&trng->rng_op_done); + + return IRQ_HANDLED; +} + +static int airoha_trng_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct airoha_trng *trng; + int irq, ret; + u32 val; + + trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL); + if (!trng) + return -ENOMEM; + + trng->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(trng->base)) + return PTR_ERR(trng->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + airoha_trng_irq_mask(trng); + ret = devm_request_irq(&pdev->dev, irq, airoha_trng_irq, 0, + pdev->name, (void *)trng); + if (ret) { + dev_err(dev, "Can't get interrupt working.\n"); + return ret; + } + + init_completion(&trng->rng_op_done); + + /* Enable interrupt for SW reset Health Check */ + val = readl(trng->base + TRNG_INTR_EN); + val |= RST_STARTUP_INITR_EN; + writel(val, trng->base + TRNG_INTR_EN); + + /* Set output to raw data */ + val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); + val |= RAW_DATA_EN; + writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); + + /* Put it in SW Reset */ + writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST); + + trng->dev = dev; + trng->rng.name = pdev->name; + trng->rng.init = airoha_trng_init; + trng->rng.cleanup = airoha_trng_cleanup; + trng->rng.read = airoha_trng_read; + + ret = devm_hwrng_register(dev, &trng->rng); + if (ret) { + dev_err(dev, "failed to register rng device: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id airoha_trng_of_match[] = { + { .compatible = "airoha,en7581-trng", }, + {}, +}; +MODULE_DEVICE_TABLE(of, airoha_trng_of_match); + +static struct platform_driver airoha_trng_driver = { + .driver = { + .name = "airoha-trng", + .of_match_table = airoha_trng_of_match, + }, + .probe = airoha_trng_probe, +}; + +module_platform_driver(airoha_trng_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Marangi "); +MODULE_DESCRIPTION("Airoha True Random Number Generator driver"); diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index e9157255f8513c..143406bc69393f 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -216,7 +216,7 @@ MODULE_DEVICE_TABLE(of, atmel_trng_dt_ids); static struct platform_driver atmel_trng_driver = { .probe = atmel_trng_probe, - .remove_new = atmel_trng_remove, + .remove = atmel_trng_remove, .driver = { .name = "atmel-trng", .pm = pm_ptr(&atmel_trng_pm_ops), diff --git a/drivers/char/hw_random/bcm74110-rng.c b/drivers/char/hw_random/bcm74110-rng.c new file mode 100644 index 00000000000000..5c64148e91f1e3 --- /dev/null +++ b/drivers/char/hw_random/bcm74110-rng.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Broadcom + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +#define HOST_REV_ID 0x00 +#define HOST_FIFO_DEPTH 0x04 +#define HOST_FIFO_COUNT 0x08 +#define HOST_FIFO_THRESHOLD 0x0c +#define HOST_FIFO_DATA 0x10 + +#define HOST_FIFO_COUNT_MASK 0xffff + +/* Delay range in microseconds */ +#define FIFO_DELAY_MIN_US 3 +#define FIFO_DELAY_MAX_US 7 +#define FIFO_DELAY_MAX_COUNT 10 + +struct bcm74110_priv { + void __iomem *base; +}; + +static inline int bcm74110_rng_fifo_count(void __iomem *mem) +{ + return readl_relaxed(mem) & HOST_FIFO_COUNT_MASK; +} + +static int bcm74110_rng_read(struct hwrng *rng, void *buf, size_t max, + bool wait) +{ + struct bcm74110_priv *priv = (struct bcm74110_priv *)rng->priv; + void __iomem *fc_addr = priv->base + HOST_FIFO_COUNT; + void __iomem *fd_addr = priv->base + HOST_FIFO_DATA; + unsigned underrun_count = 0; + u32 max_words = max / sizeof(u32); + u32 num_words; + unsigned i; + + /* + * We need to check how many words are available in the RNG FIFO. If + * there aren't any, we need to wait for some to become available. + */ + while ((num_words = bcm74110_rng_fifo_count(fc_addr)) == 0) { + if (!wait) + return 0; + /* + * As a precaution, limit how long we wait. If the FIFO doesn't + * refill within the allotted time, return 0 (=no data) to the + * caller. + */ + if (likely(underrun_count < FIFO_DELAY_MAX_COUNT)) + usleep_range(FIFO_DELAY_MIN_US, FIFO_DELAY_MAX_US); + else + return 0; + underrun_count++; + } + if (num_words > max_words) + num_words = max_words; + + /* Bail early if we run out of random numbers unexpectedly */ + for (i = 0; i < num_words && bcm74110_rng_fifo_count(fc_addr) > 0; i++) + ((u32 *)buf)[i] = readl_relaxed(fd_addr); + + return i * sizeof(u32); +} + +static struct hwrng bcm74110_hwrng = { + .read = bcm74110_rng_read, +}; + +static int bcm74110_rng_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct bcm74110_priv *priv; + int rc; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + bcm74110_hwrng.name = pdev->name; + bcm74110_hwrng.priv = (unsigned long)priv; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + rc = devm_hwrng_register(dev, &bcm74110_hwrng); + if (rc) + dev_err(dev, "hwrng registration failed (%d)\n", rc); + else + dev_info(dev, "hwrng registered\n"); + + return rc; +} + +static const struct of_device_id bcm74110_rng_match[] = { + { .compatible = "brcm,bcm74110-rng", }, + {}, +}; +MODULE_DEVICE_TABLE(of, bcm74110_rng_match); + +static struct platform_driver bcm74110_rng_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = bcm74110_rng_match, + }, + .probe = bcm74110_rng_probe, +}; +module_platform_driver(bcm74110_rng_driver); + +MODULE_AUTHOR("Markus Mayer "); +MODULE_DESCRIPTION("BCM 74110 Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/char/hw_random/cctrng.c b/drivers/char/hw_random/cctrng.c index 4c50efc464835b..4db198849695d2 100644 --- a/drivers/char/hw_random/cctrng.c +++ b/drivers/char/hw_random/cctrng.c @@ -653,7 +653,7 @@ static struct platform_driver cctrng_driver = { .pm = &cctrng_pm, }, .probe = cctrng_probe, - .remove_new = cctrng_remove, + .remove = cctrng_remove, }; module_platform_driver(cctrng_driver); diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 57c51efa56131e..018316f546215a 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -181,8 +181,15 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, int present; BUG_ON(!mutex_is_locked(&reading_mutex)); - if (rng->read) - return rng->read(rng, (void *)buffer, size, wait); + if (rng->read) { + int err; + + err = rng->read(rng, buffer, size, wait); + if (WARN_ON_ONCE(err > 0 && err > size)) + err = size; + + return err; + } if (rng->data_present) present = rng->data_present(rng, wait); diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c index 9f039fddaee3ea..02e207c09e8112 100644 --- a/drivers/char/hw_random/exynos-trng.c +++ b/drivers/char/hw_random/exynos-trng.c @@ -335,7 +335,7 @@ static struct platform_driver exynos_trng_driver = { .of_match_table = exynos_trng_dt_match, }, .probe = exynos_trng_probe, - .remove_new = exynos_trng_remove, + .remove = exynos_trng_remove, }; module_platform_driver(exynos_trng_driver); diff --git a/drivers/char/hw_random/histb-rng.c b/drivers/char/hw_random/histb-rng.c index f652e1135e4b24..1b91e88cc4c061 100644 --- a/drivers/char/hw_random/histb-rng.c +++ b/drivers/char/hw_random/histb-rng.c @@ -89,7 +89,7 @@ depth_show(struct device *dev, struct device_attribute *attr, char *buf) struct histb_rng_priv *priv = dev_get_drvdata(dev); void __iomem *base = priv->base; - return sprintf(buf, "%d\n", histb_rng_get_depth(base)); + return sprintf(buf, "%u\n", histb_rng_get_depth(base)); } static ssize_t diff --git a/drivers/char/hw_random/ingenic-rng.c b/drivers/char/hw_random/ingenic-rng.c index 2f9b6483c4a12a..bbfd662d25a67c 100644 --- a/drivers/char/hw_random/ingenic-rng.c +++ b/drivers/char/hw_random/ingenic-rng.c @@ -132,7 +132,7 @@ MODULE_DEVICE_TABLE(of, ingenic_rng_of_match); static struct platform_driver ingenic_rng_driver = { .probe = ingenic_rng_probe, - .remove_new = ingenic_rng_remove, + .remove = ingenic_rng_remove, .driver = { .name = "ingenic-rng", .of_match_table = ingenic_rng_of_match, diff --git a/drivers/char/hw_random/ks-sa-rng.c b/drivers/char/hw_random/ks-sa-rng.c index 36c34252b4f631..d8fd8a3544828a 100644 --- a/drivers/char/hw_random/ks-sa-rng.c +++ b/drivers/char/hw_random/ks-sa-rng.c @@ -261,7 +261,7 @@ static struct platform_driver ks_sa_rng_driver = { .of_match_table = ks_sa_rng_dt_match, }, .probe = ks_sa_rng_probe, - .remove_new = ks_sa_rng_remove, + .remove = ks_sa_rng_remove, }; module_platform_driver(ks_sa_rng_driver); diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c index f01eb95bee314b..e3fcb8bcc29bbf 100644 --- a/drivers/char/hw_random/mxc-rnga.c +++ b/drivers/char/hw_random/mxc-rnga.c @@ -188,7 +188,7 @@ static struct platform_driver mxc_rnga_driver = { .of_match_table = mxc_rnga_of_match, }, .probe = mxc_rnga_probe, - .remove_new = mxc_rnga_remove, + .remove = mxc_rnga_remove, }; module_platform_driver(mxc_rnga_driver); diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 1b49e3a86d57b7..ea6d5599242f67 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -858,7 +858,7 @@ static struct platform_driver n2rng_driver = { .of_match_table = n2rng_match, }, .probe = n2rng_probe, - .remove_new = n2rng_remove, + .remove = n2rng_remove, }; module_platform_driver(n2rng_driver); diff --git a/drivers/char/hw_random/npcm-rng.c b/drivers/char/hw_random/npcm-rng.c index bce8c4829a1f83..9ff00f096f3816 100644 --- a/drivers/char/hw_random/npcm-rng.c +++ b/drivers/char/hw_random/npcm-rng.c @@ -176,7 +176,7 @@ static struct platform_driver npcm_rng_driver = { .of_match_table = of_match_ptr(rng_dt_id), }, .probe = npcm_rng_probe, - .remove_new = npcm_rng_remove, + .remove = npcm_rng_remove, }; module_platform_driver(npcm_rng_driver); diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 4914a8720e5820..5e8b50f15db754 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -558,7 +558,7 @@ static struct platform_driver omap_rng_driver = { .of_match_table = of_match_ptr(omap_rng_of_match), }, .probe = omap_rng_probe, - .remove_new = omap_rng_remove, + .remove = omap_rng_remove, }; module_platform_driver(omap_rng_driver); diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c index 9d041a67c295a5..98edbe796bc523 100644 --- a/drivers/char/hw_random/stm32-rng.c +++ b/drivers/char/hw_random/stm32-rng.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -49,6 +50,7 @@ struct stm32_rng_data { uint max_clock_rate; + uint nb_clock; u32 cr; u32 nscr; u32 htcr; @@ -72,7 +74,7 @@ struct stm32_rng_private { struct hwrng rng; struct device *dev; void __iomem *base; - struct clk *clk; + struct clk_bulk_data *clk_bulk; struct reset_control *rst; struct stm32_rng_config pm_conf; const struct stm32_rng_data *data; @@ -266,7 +268,7 @@ static uint stm32_rng_clock_freq_restrain(struct hwrng *rng) unsigned long clock_rate = 0; uint clock_div = 0; - clock_rate = clk_get_rate(priv->clk); + clock_rate = clk_get_rate(priv->clk_bulk[0].clk); /* * Get the exponent to apply on the CLKDIV field in RNG_CR register @@ -276,7 +278,7 @@ static uint stm32_rng_clock_freq_restrain(struct hwrng *rng) while ((clock_rate >> clock_div) > priv->data->max_clock_rate) clock_div++; - pr_debug("RNG clk rate : %lu\n", clk_get_rate(priv->clk) >> clock_div); + pr_debug("RNG clk rate : %lu\n", clk_get_rate(priv->clk_bulk[0].clk) >> clock_div); return clock_div; } @@ -288,7 +290,7 @@ static int stm32_rng_init(struct hwrng *rng) int err; u32 reg; - err = clk_prepare_enable(priv->clk); + err = clk_bulk_prepare_enable(priv->data->nb_clock, priv->clk_bulk); if (err) return err; @@ -328,7 +330,7 @@ static int stm32_rng_init(struct hwrng *rng) (!(reg & RNG_CR_CONDRST)), 10, 50000); if (err) { - clk_disable_unprepare(priv->clk); + clk_bulk_disable_unprepare(priv->data->nb_clock, priv->clk_bulk); dev_err(priv->dev, "%s: timeout %x!\n", __func__, reg); return -EINVAL; } @@ -356,12 +358,13 @@ static int stm32_rng_init(struct hwrng *rng) reg & RNG_SR_DRDY, 10, 100000); if (err || (reg & ~RNG_SR_DRDY)) { - clk_disable_unprepare(priv->clk); + clk_bulk_disable_unprepare(priv->data->nb_clock, priv->clk_bulk); dev_err(priv->dev, "%s: timeout:%x SR: %x!\n", __func__, err, reg); + return -EINVAL; } - clk_disable_unprepare(priv->clk); + clk_bulk_disable_unprepare(priv->data->nb_clock, priv->clk_bulk); return 0; } @@ -379,7 +382,8 @@ static int __maybe_unused stm32_rng_runtime_suspend(struct device *dev) reg = readl_relaxed(priv->base + RNG_CR); reg &= ~RNG_CR_RNGEN; writel_relaxed(reg, priv->base + RNG_CR); - clk_disable_unprepare(priv->clk); + + clk_bulk_disable_unprepare(priv->data->nb_clock, priv->clk_bulk); return 0; } @@ -389,7 +393,7 @@ static int __maybe_unused stm32_rng_suspend(struct device *dev) struct stm32_rng_private *priv = dev_get_drvdata(dev); int err; - err = clk_prepare_enable(priv->clk); + err = clk_bulk_prepare_enable(priv->data->nb_clock, priv->clk_bulk); if (err) return err; @@ -403,7 +407,7 @@ static int __maybe_unused stm32_rng_suspend(struct device *dev) writel_relaxed(priv->pm_conf.cr, priv->base + RNG_CR); - clk_disable_unprepare(priv->clk); + clk_bulk_disable_unprepare(priv->data->nb_clock, priv->clk_bulk); return 0; } @@ -414,7 +418,7 @@ static int __maybe_unused stm32_rng_runtime_resume(struct device *dev) int err; u32 reg; - err = clk_prepare_enable(priv->clk); + err = clk_bulk_prepare_enable(priv->data->nb_clock, priv->clk_bulk); if (err) return err; @@ -434,7 +438,7 @@ static int __maybe_unused stm32_rng_resume(struct device *dev) int err; u32 reg; - err = clk_prepare_enable(priv->clk); + err = clk_bulk_prepare_enable(priv->data->nb_clock, priv->clk_bulk); if (err) return err; @@ -462,7 +466,7 @@ static int __maybe_unused stm32_rng_resume(struct device *dev) reg & ~RNG_CR_CONDRST, 10, 100000); if (err) { - clk_disable_unprepare(priv->clk); + clk_bulk_disable_unprepare(priv->data->nb_clock, priv->clk_bulk); dev_err(priv->dev, "%s: timeout:%x CR: %x!\n", __func__, err, reg); return -EINVAL; } @@ -472,7 +476,7 @@ static int __maybe_unused stm32_rng_resume(struct device *dev) writel_relaxed(reg, priv->base + RNG_CR); } - clk_disable_unprepare(priv->clk); + clk_bulk_disable_unprepare(priv->data->nb_clock, priv->clk_bulk); return 0; } @@ -484,9 +488,19 @@ static const struct dev_pm_ops __maybe_unused stm32_rng_pm_ops = { stm32_rng_resume) }; +static const struct stm32_rng_data stm32mp25_rng_data = { + .has_cond_reset = true, + .max_clock_rate = 48000000, + .nb_clock = 2, + .cr = 0x00F00D00, + .nscr = 0x2B5BB, + .htcr = 0x969D, +}; + static const struct stm32_rng_data stm32mp13_rng_data = { .has_cond_reset = true, .max_clock_rate = 48000000, + .nb_clock = 1, .cr = 0x00F00D00, .nscr = 0x2B5BB, .htcr = 0x969D, @@ -494,10 +508,15 @@ static const struct stm32_rng_data stm32mp13_rng_data = { static const struct stm32_rng_data stm32_rng_data = { .has_cond_reset = false, - .max_clock_rate = 3000000, + .max_clock_rate = 48000000, + .nb_clock = 1, }; static const struct of_device_id stm32_rng_match[] = { + { + .compatible = "st,stm32mp25-rng", + .data = &stm32mp25_rng_data, + }, { .compatible = "st,stm32mp13-rng", .data = &stm32mp13_rng_data, @@ -516,6 +535,7 @@ static int stm32_rng_probe(struct platform_device *ofdev) struct device_node *np = ofdev->dev.of_node; struct stm32_rng_private *priv; struct resource *res; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -525,10 +545,6 @@ static int stm32_rng_probe(struct platform_device *ofdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - priv->clk = devm_clk_get(&ofdev->dev, NULL); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - priv->rst = devm_reset_control_get(&ofdev->dev, NULL); if (!IS_ERR(priv->rst)) { reset_control_assert(priv->rst); @@ -551,6 +567,28 @@ static int stm32_rng_probe(struct platform_device *ofdev) priv->rng.read = stm32_rng_read; priv->rng.quality = 900; + if (!priv->data->nb_clock || priv->data->nb_clock > 2) + return -EINVAL; + + ret = devm_clk_bulk_get_all(dev, &priv->clk_bulk); + if (ret != priv->data->nb_clock) + return dev_err_probe(dev, -EINVAL, "Failed to get clocks: %d\n", ret); + + if (priv->data->nb_clock == 2) { + const char *id = priv->clk_bulk[1].id; + struct clk *clk = priv->clk_bulk[1].clk; + + if (!priv->clk_bulk[0].id || !priv->clk_bulk[1].id) + return dev_err_probe(dev, -EINVAL, "Missing clock name\n"); + + if (strcmp(priv->clk_bulk[0].id, "core")) { + priv->clk_bulk[1].id = priv->clk_bulk[0].id; + priv->clk_bulk[1].clk = priv->clk_bulk[0].clk; + priv->clk_bulk[0].id = id; + priv->clk_bulk[0].clk = clk; + } + } + pm_runtime_set_autosuspend_delay(dev, 100); pm_runtime_use_autosuspend(dev); pm_runtime_enable(dev); @@ -565,7 +603,7 @@ static struct platform_driver stm32_rng_driver = { .of_match_table = stm32_rng_match, }, .probe = stm32_rng_probe, - .remove_new = stm32_rng_remove, + .remove = stm32_rng_remove, }; module_platform_driver(stm32_rng_driver); diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index 65b8260339f5be..7174bfccc7b32f 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -193,7 +193,7 @@ static struct platform_driver timeriomem_rng_driver = { .of_match_table = timeriomem_rng_match, }, .probe = timeriomem_rng_probe, - .remove_new = timeriomem_rng_remove, + .remove = timeriomem_rng_remove, }; module_platform_driver(timeriomem_rng_driver); diff --git a/drivers/char/hw_random/xgene-rng.c b/drivers/char/hw_random/xgene-rng.c index 642d13519464c0..39acaa503fec1b 100644 --- a/drivers/char/hw_random/xgene-rng.c +++ b/drivers/char/hw_random/xgene-rng.c @@ -375,7 +375,7 @@ MODULE_DEVICE_TABLE(of, xgene_rng_of_match); static struct platform_driver xgene_rng_driver = { .probe = xgene_rng_probe, - .remove_new = xgene_rng_remove, + .remove = xgene_rng_remove, .driver = { .name = "xgene-rng", .of_match_table = xgene_rng_of_match, diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c index b8b9c07d3b5de9..009e32033b174d 100644 --- a/drivers/char/ipmi/bt-bmc.c +++ b/drivers/char/ipmi/bt-bmc.c @@ -481,7 +481,7 @@ static struct platform_driver bt_bmc_driver = { .of_match_table = bt_bmc_match, }, .probe = bt_bmc_probe, - .remove_new = bt_bmc_remove, + .remove = bt_bmc_remove, }; module_platform_driver(bt_bmc_driver); diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index c59a86eb58c7ba..4a2efafcd1f855 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -302,7 +302,7 @@ static struct platform_driver powernv_ipmi_driver = { .of_match_table = ipmi_powernv_match, }, .probe = ipmi_powernv_probe, - .remove_new = ipmi_powernv_remove, + .remove = ipmi_powernv_remove, }; diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index 96ba85648120d4..550cabd43ae616 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -445,7 +445,7 @@ struct platform_driver ipmi_platform_driver = { .acpi_match_table = ACPI_PTR(acpi_ipmi_match), }, .probe = ipmi_probe, - .remove_new = ipmi_remove, + .remove = ipmi_remove, .id_table = si_plat_ids }; diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index d04b391048fbaa..506d9988721efb 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -2114,7 +2114,7 @@ static struct platform_driver ipmi_driver = { .name = DEVICE_NAME, }, .probe = ssif_platform_probe, - .remove_new = ssif_platform_remove, + .remove = ssif_platform_remove, .id_table = ssif_plat_ids }; diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c index 227bf06c7ca492..c03bc1ec593ad9 100644 --- a/drivers/char/ipmi/kcs_bmc_aspeed.c +++ b/drivers/char/ipmi/kcs_bmc_aspeed.c @@ -672,7 +672,7 @@ static struct platform_driver ast_kcs_bmc_driver = { .of_match_table = ast_kcs_bmc_match, }, .probe = aspeed_kcs_probe, - .remove_new = aspeed_kcs_remove, + .remove = aspeed_kcs_remove, }; module_platform_driver(ast_kcs_bmc_driver); diff --git a/drivers/char/ipmi/kcs_bmc_npcm7xx.c b/drivers/char/ipmi/kcs_bmc_npcm7xx.c index 07710198233a2f..4808a61bf273d3 100644 --- a/drivers/char/ipmi/kcs_bmc_npcm7xx.c +++ b/drivers/char/ipmi/kcs_bmc_npcm7xx.c @@ -241,7 +241,7 @@ static struct platform_driver npcm_kcs_bmc_driver = { .of_match_table = npcm_kcs_bmc_match, }, .probe = npcm7xx_kcs_probe, - .remove_new = npcm7xx_kcs_remove, + .remove = npcm7xx_kcs_remove, }; module_platform_driver(npcm_kcs_bmc_driver); diff --git a/drivers/char/powernv-op-panel.c b/drivers/char/powernv-op-panel.c index f2cff1a6fed520..53467b0a6187f5 100644 --- a/drivers/char/powernv-op-panel.c +++ b/drivers/char/powernv-op-panel.c @@ -213,7 +213,7 @@ static struct platform_driver oppanel_driver = { .of_match_table = oppanel_match, }, .probe = oppanel_probe, - .remove_new = oppanel_remove, + .remove = oppanel_remove, }; module_platform_driver(oppanel_driver); diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 0f8185e541ed47..f887569fd3d0f0 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1467,7 +1467,7 @@ static struct platform_driver sonypi_driver = { .pm = SONYPI_PM, }, .probe = sonypi_probe, - .remove_new = sonypi_remove, + .remove = sonypi_remove, .shutdown = sonypi_shutdown, }; diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index cf0be8a7939de4..0fc9a510e05977 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -162,7 +162,7 @@ config TCG_NSC config TCG_ATMEL tristate "Atmel TPM Interface" - depends on PPC64 || HAS_IOPORT_MAP + depends on HAS_IOPORT_MAP depends on HAS_IOPORT help If you have a TPM security chip from Atmel say Yes and it diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c index b0f13c8ea79c7a..b70165b588eccd 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -1390,5 +1390,4 @@ int tpm2_sessions_init(struct tpm_chip *chip) return rc; } -EXPORT_SYMBOL(tpm2_sessions_init); #endif /* CONFIG_TCG_TPM2_HMAC */ diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 9fb2defa9dc421..54a0360a3c95ea 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -15,7 +15,66 @@ */ #include "tpm.h" -#include "tpm_atmel.h" + +struct tpm_atmel_priv { + int region_size; + int have_region; + unsigned long base; + void __iomem *iobase; +}; + +#define atmel_getb(chip, offset) inb(atmel_get_priv(chip)->base + (offset)) +#define atmel_putb(val, chip, offset) \ + outb(val, atmel_get_priv(chip)->base + (offset)) +#define atmel_request_region request_region +#define atmel_release_region release_region +/* Atmel definitions */ +enum tpm_atmel_addr { + TPM_ATMEL_BASE_ADDR_LO = 0x08, + TPM_ATMEL_BASE_ADDR_HI = 0x09 +}; + +static inline int tpm_read_index(int base, int index) +{ + outb(index, base); + return inb(base + 1) & 0xFF; +} + +/* Verify this is a 1.1 Atmel TPM */ +static int atmel_verify_tpm11(void) +{ + /* verify that it is an Atmel part */ + if (tpm_read_index(TPM_ADDR, 4) != 'A' || + tpm_read_index(TPM_ADDR, 5) != 'T' || + tpm_read_index(TPM_ADDR, 6) != 'M' || + tpm_read_index(TPM_ADDR, 7) != 'L') + return 1; + + /* query chip for its version number */ + if (tpm_read_index(TPM_ADDR, 0x00) != 1 || + tpm_read_index(TPM_ADDR, 0x01) != 1) + return 1; + + /* This is an atmel supported part */ + return 0; +} + +/* Determine where to talk to device */ +static void __iomem *atmel_get_base_addr(unsigned long *base, int *region_size) +{ + int lo, hi; + + if (atmel_verify_tpm11() != 0) + return NULL; + + lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); + hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); + + *base = (hi << 8) | lo; + *region_size = 2; + + return ioport_map(*base, *region_size); +} /* write status bits */ enum tpm_atmel_write_status { @@ -142,7 +201,6 @@ static void atml_plat_remove(void) tpm_chip_unregister(chip); if (priv->have_region) atmel_release_region(priv->base, priv->region_size); - atmel_put_base_addr(priv->iobase); platform_device_unregister(pdev); } @@ -211,7 +269,6 @@ static int __init init_atmel(void) err_unreg_dev: platform_device_unregister(pdev); err_rel_reg: - atmel_put_base_addr(iobase); if (have_region) atmel_release_region(base, region_size); diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h deleted file mode 100644 index 7ac3f69dcf0f5f..00000000000000 --- a/drivers/char/tpm/tpm_atmel.h +++ /dev/null @@ -1,140 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (C) 2005 IBM Corporation - * - * Authors: - * Kylene Hall - * - * Maintained by: - * - * Device driver for TCG/TCPA TPM (trusted platform module). - * Specifications at www.trustedcomputinggroup.org - * - * These difference are required on power because the device must be - * discovered through the device tree and iomap must be used to get - * around the need for holes in the io_page_mask. This does not happen - * automatically because the tpm is not a normal pci device and lives - * under the root node. - */ - -struct tpm_atmel_priv { - int region_size; - int have_region; - unsigned long base; - void __iomem *iobase; -}; - -#ifdef CONFIG_PPC64 - -#include - -#define atmel_getb(priv, offset) readb(priv->iobase + offset) -#define atmel_putb(val, priv, offset) writeb(val, priv->iobase + offset) -#define atmel_request_region request_mem_region -#define atmel_release_region release_mem_region - -static inline void atmel_put_base_addr(void __iomem *iobase) -{ - iounmap(iobase); -} - -static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) -{ - struct device_node *dn; - unsigned long address, size; - const unsigned int *reg; - int reglen; - int naddrc; - int nsizec; - - dn = of_find_node_by_name(NULL, "tpm"); - - if (!dn) - return NULL; - - if (!of_device_is_compatible(dn, "AT97SC3201")) { - of_node_put(dn); - return NULL; - } - - reg = of_get_property(dn, "reg", ®len); - naddrc = of_n_addr_cells(dn); - nsizec = of_n_size_cells(dn); - - of_node_put(dn); - - - if (naddrc == 2) - address = ((unsigned long) reg[0] << 32) | reg[1]; - else - address = reg[0]; - - if (nsizec == 2) - size = - ((unsigned long) reg[naddrc] << 32) | reg[naddrc + 1]; - else - size = reg[naddrc]; - - *base = address; - *region_size = size; - return ioremap(*base, *region_size); -} -#else -#define atmel_getb(chip, offset) inb(atmel_get_priv(chip)->base + offset) -#define atmel_putb(val, chip, offset) \ - outb(val, atmel_get_priv(chip)->base + offset) -#define atmel_request_region request_region -#define atmel_release_region release_region -/* Atmel definitions */ -enum tpm_atmel_addr { - TPM_ATMEL_BASE_ADDR_LO = 0x08, - TPM_ATMEL_BASE_ADDR_HI = 0x09 -}; - -static inline int tpm_read_index(int base, int index) -{ - outb(index, base); - return inb(base+1) & 0xFF; -} - -/* Verify this is a 1.1 Atmel TPM */ -static int atmel_verify_tpm11(void) -{ - - /* verify that it is an Atmel part */ - if (tpm_read_index(TPM_ADDR, 4) != 'A' || - tpm_read_index(TPM_ADDR, 5) != 'T' || - tpm_read_index(TPM_ADDR, 6) != 'M' || - tpm_read_index(TPM_ADDR, 7) != 'L') - return 1; - - /* query chip for its version number */ - if (tpm_read_index(TPM_ADDR, 0x00) != 1 || - tpm_read_index(TPM_ADDR, 0x01) != 1) - return 1; - - /* This is an atmel supported part */ - return 0; -} - -static inline void atmel_put_base_addr(void __iomem *iobase) -{ -} - -/* Determine where to talk to device */ -static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) -{ - int lo, hi; - - if (atmel_verify_tpm11() != 0) - return NULL; - - lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); - hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); - - *base = (hi << 8) | lo; - *region_size = 2; - - return ioport_map(*base, *region_size); -} -#endif diff --git a/drivers/char/tpm/tpm_ftpm_tee.c b/drivers/char/tpm/tpm_ftpm_tee.c index 2ea4882251cf7f..139556b21cc649 100644 --- a/drivers/char/tpm/tpm_ftpm_tee.c +++ b/drivers/char/tpm/tpm_ftpm_tee.c @@ -366,7 +366,7 @@ static struct platform_driver ftpm_tee_plat_driver = { }, .shutdown = ftpm_plat_tee_shutdown, .probe = ftpm_plat_tee_probe, - .remove_new = ftpm_plat_tee_remove, + .remove = ftpm_plat_tee_remove, }; /* UUID of the fTPM TA */ diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 1e5b107d1f3bdb..76d048f63d55b5 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -450,6 +450,7 @@ static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status) } static const struct tpm_class_ops tpm_ibmvtpm = { + .flags = TPM_OPS_AUTO_STARTUP, .recv = tpm_ibmvtpm_recv, .send = tpm_ibmvtpm_send, .cancel = tpm_ibmvtpm_cancel, @@ -690,20 +691,6 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, if (!strcmp(id->compat, "IBM,vtpm20")) chip->flags |= TPM_CHIP_FLAG_TPM2; - rc = tpm_get_timeouts(chip); - if (rc) - goto init_irq_cleanup; - - if (chip->flags & TPM_CHIP_FLAG_TPM2) { - rc = tpm2_get_cc_attrs_tbl(chip); - if (rc) - goto init_irq_cleanup; - - rc = tpm2_sessions_init(chip); - if (rc) - goto init_irq_cleanup; - } - return tpm_chip_register(chip); init_irq_cleanup: do { diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 2f7326d297adb9..9aa230a6361662 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -356,7 +356,7 @@ MODULE_DEVICE_TABLE(of, tis_of_platform_match); static struct platform_driver tis_drv = { .probe = tpm_tis_plat_probe, - .remove_new = tpm_tis_plat_remove, + .remove = tpm_tis_plat_remove, .driver = { .name = "tpm_tis", .pm = &tpm_tis_pm, diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index adf22992138e5c..3b55a7b05c46a9 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -30,11 +31,13 @@ #define TPM_CR50_MAX_BUFSIZE 64 #define TPM_CR50_TIMEOUT_SHORT_MS 2 /* Short timeout during transactions */ #define TPM_CR50_TIMEOUT_NOIRQ_MS 20 /* Timeout for TPM ready without IRQ */ -#define TPM_CR50_I2C_DID_VID 0x00281ae0L /* Device and vendor ID reg value */ -#define TPM_TI50_I2C_DID_VID 0x504a6666L /* Device and vendor ID reg value */ +#define TPM_CR50_I2C_DID_VID 0x00281ae0L /* Device and vendor ID for Cr50 H1 */ +#define TPM_TI50_DT_I2C_DID_VID 0x504a6666L /* Device and vendor ID for Ti50 DT */ +#define TPM_TI50_OT_I2C_DID_VID 0x50666666L /* Device and vendor ID for TI50 OT */ #define TPM_CR50_I2C_MAX_RETRIES 3 /* Max retries due to I2C errors */ #define TPM_CR50_I2C_RETRY_DELAY_LO 55 /* Min usecs between retries on I2C */ #define TPM_CR50_I2C_RETRY_DELAY_HI 65 /* Max usecs between retries on I2C */ +#define TPM_CR50_I2C_DEFAULT_LOC 0 #define TPM_I2C_ACCESS(l) (0x0000 | ((l) << 4)) #define TPM_I2C_STS(l) (0x0001 | ((l) << 4)) @@ -199,8 +202,6 @@ static int tpm_cr50_i2c_read(struct tpm_chip *chip, u8 addr, u8 *buffer, size_t }; int rc; - i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); - /* Prepare for completion interrupt */ tpm_cr50_i2c_enable_tpm_irq(chip); @@ -219,7 +220,6 @@ static int tpm_cr50_i2c_read(struct tpm_chip *chip, u8 addr, u8 *buffer, size_t out: tpm_cr50_i2c_disable_tpm_irq(chip); - i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); if (rc < 0) return rc; @@ -261,8 +261,6 @@ static int tpm_cr50_i2c_write(struct tpm_chip *chip, u8 addr, u8 *buffer, priv->buf[0] = addr; memcpy(priv->buf + 1, buffer, len); - i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); - /* Prepare for completion interrupt */ tpm_cr50_i2c_enable_tpm_irq(chip); @@ -276,7 +274,6 @@ static int tpm_cr50_i2c_write(struct tpm_chip *chip, u8 addr, u8 *buffer, out: tpm_cr50_i2c_disable_tpm_irq(chip); - i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); if (rc < 0) return rc; @@ -285,25 +282,26 @@ static int tpm_cr50_i2c_write(struct tpm_chip *chip, u8 addr, u8 *buffer, } /** - * tpm_cr50_check_locality() - Verify TPM locality 0 is active. + * tpm_cr50_check_locality() - Verify if required TPM locality is active. * @chip: A TPM chip. + * @loc: Locality to be verified * * Return: - * - 0: Success. + * - loc: Success. * - -errno: A POSIX error code. */ -static int tpm_cr50_check_locality(struct tpm_chip *chip) +static int tpm_cr50_check_locality(struct tpm_chip *chip, int loc) { u8 mask = TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY; u8 buf; int rc; - rc = tpm_cr50_i2c_read(chip, TPM_I2C_ACCESS(0), &buf, sizeof(buf)); + rc = tpm_cr50_i2c_read(chip, TPM_I2C_ACCESS(loc), &buf, sizeof(buf)); if (rc < 0) return rc; if ((buf & mask) == mask) - return 0; + return loc; return -EIO; } @@ -311,53 +309,72 @@ static int tpm_cr50_check_locality(struct tpm_chip *chip) /** * tpm_cr50_release_locality() - Release TPM locality. * @chip: A TPM chip. - * @force: Flag to force release if set. + * @loc: Locality to be released + * + * Return: + * - 0: Success. + * - -errno: A POSIX error code. */ -static void tpm_cr50_release_locality(struct tpm_chip *chip, bool force) +static int tpm_cr50_release_locality(struct tpm_chip *chip, int loc) { + struct i2c_client *client = to_i2c_client(chip->dev.parent); u8 mask = TPM_ACCESS_VALID | TPM_ACCESS_REQUEST_PENDING; - u8 addr = TPM_I2C_ACCESS(0); + u8 addr = TPM_I2C_ACCESS(loc); u8 buf; + int rc; - if (tpm_cr50_i2c_read(chip, addr, &buf, sizeof(buf)) < 0) - return; + rc = tpm_cr50_i2c_read(chip, addr, &buf, sizeof(buf)); + if (rc < 0) + goto unlock_out; - if (force || (buf & mask) == mask) { + if ((buf & mask) == mask) { buf = TPM_ACCESS_ACTIVE_LOCALITY; - tpm_cr50_i2c_write(chip, addr, &buf, sizeof(buf)); + rc = tpm_cr50_i2c_write(chip, addr, &buf, sizeof(buf)); } + +unlock_out: + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); + return rc; } /** - * tpm_cr50_request_locality() - Request TPM locality 0. + * tpm_cr50_request_locality() - Request TPM locality. * @chip: A TPM chip. + * @loc: Locality to be requested. * * Return: - * - 0: Success. + * - loc: Success. * - -errno: A POSIX error code. */ -static int tpm_cr50_request_locality(struct tpm_chip *chip) +static int tpm_cr50_request_locality(struct tpm_chip *chip, int loc) { + struct i2c_client *client = to_i2c_client(chip->dev.parent); u8 buf = TPM_ACCESS_REQUEST_USE; unsigned long stop; int rc; - if (!tpm_cr50_check_locality(chip)) - return 0; + i2c_lock_bus(client->adapter, I2C_LOCK_SEGMENT); - rc = tpm_cr50_i2c_write(chip, TPM_I2C_ACCESS(0), &buf, sizeof(buf)); + if (tpm_cr50_check_locality(chip, loc) == loc) + return loc; + + rc = tpm_cr50_i2c_write(chip, TPM_I2C_ACCESS(loc), &buf, sizeof(buf)); if (rc < 0) - return rc; + goto unlock_out; stop = jiffies + chip->timeout_a; do { - if (!tpm_cr50_check_locality(chip)) - return 0; + if (tpm_cr50_check_locality(chip, loc) == loc) + return loc; msleep(TPM_CR50_TIMEOUT_SHORT_MS); } while (time_before(jiffies, stop)); - return -ETIMEDOUT; + rc = -ETIMEDOUT; + +unlock_out: + i2c_unlock_bus(client->adapter, I2C_LOCK_SEGMENT); + return rc; } /** @@ -373,7 +390,7 @@ static u8 tpm_cr50_i2c_tis_status(struct tpm_chip *chip) { u8 buf[4]; - if (tpm_cr50_i2c_read(chip, TPM_I2C_STS(0), buf, sizeof(buf)) < 0) + if (tpm_cr50_i2c_read(chip, TPM_I2C_STS(chip->locality), buf, sizeof(buf)) < 0) return 0; return buf[0]; @@ -389,7 +406,7 @@ static void tpm_cr50_i2c_tis_set_ready(struct tpm_chip *chip) { u8 buf[4] = { TPM_STS_COMMAND_READY }; - tpm_cr50_i2c_write(chip, TPM_I2C_STS(0), buf, sizeof(buf)); + tpm_cr50_i2c_write(chip, TPM_I2C_STS(chip->locality), buf, sizeof(buf)); msleep(TPM_CR50_TIMEOUT_SHORT_MS); } @@ -419,7 +436,7 @@ static int tpm_cr50_i2c_get_burst_and_status(struct tpm_chip *chip, u8 mask, stop = jiffies + chip->timeout_b; do { - if (tpm_cr50_i2c_read(chip, TPM_I2C_STS(0), buf, sizeof(buf)) < 0) { + if (tpm_cr50_i2c_read(chip, TPM_I2C_STS(chip->locality), buf, sizeof(buf)) < 0) { msleep(TPM_CR50_TIMEOUT_SHORT_MS); continue; } @@ -453,7 +470,7 @@ static int tpm_cr50_i2c_tis_recv(struct tpm_chip *chip, u8 *buf, size_t buf_len) u8 mask = TPM_STS_VALID | TPM_STS_DATA_AVAIL; size_t burstcnt, cur, len, expected; - u8 addr = TPM_I2C_DATA_FIFO(0); + u8 addr = TPM_I2C_DATA_FIFO(chip->locality); u32 status; int rc; @@ -515,7 +532,6 @@ static int tpm_cr50_i2c_tis_recv(struct tpm_chip *chip, u8 *buf, size_t buf_len) goto out_err; } - tpm_cr50_release_locality(chip, false); return cur; out_err: @@ -523,7 +539,6 @@ static int tpm_cr50_i2c_tis_recv(struct tpm_chip *chip, u8 *buf, size_t buf_len) if (tpm_cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY) tpm_cr50_i2c_tis_set_ready(chip); - tpm_cr50_release_locality(chip, false); return rc; } @@ -545,10 +560,6 @@ static int tpm_cr50_i2c_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) u32 status; int rc; - rc = tpm_cr50_request_locality(chip); - if (rc < 0) - return rc; - /* Wait until TPM is ready for a command */ stop = jiffies + chip->timeout_b; while (!(tpm_cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY)) { @@ -577,7 +588,8 @@ static int tpm_cr50_i2c_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) * that is inserted by tpm_cr50_i2c_write() */ limit = min_t(size_t, burstcnt - 1, len); - rc = tpm_cr50_i2c_write(chip, TPM_I2C_DATA_FIFO(0), &buf[sent], limit); + rc = tpm_cr50_i2c_write(chip, TPM_I2C_DATA_FIFO(chip->locality), + &buf[sent], limit); if (rc < 0) { dev_err(&chip->dev, "Write failed\n"); goto out_err; @@ -598,7 +610,7 @@ static int tpm_cr50_i2c_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) } /* Start the TPM command */ - rc = tpm_cr50_i2c_write(chip, TPM_I2C_STS(0), tpm_go, + rc = tpm_cr50_i2c_write(chip, TPM_I2C_STS(chip->locality), tpm_go, sizeof(tpm_go)); if (rc < 0) { dev_err(&chip->dev, "Start command failed\n"); @@ -611,7 +623,6 @@ static int tpm_cr50_i2c_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) if (tpm_cr50_i2c_tis_status(chip) & TPM_STS_COMMAND_READY) tpm_cr50_i2c_tis_set_ready(chip); - tpm_cr50_release_locality(chip, false); return rc; } @@ -650,6 +661,8 @@ static const struct tpm_class_ops cr50_i2c = { .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_canceled = &tpm_cr50_i2c_req_canceled, + .request_locality = &tpm_cr50_request_locality, + .relinquish_locality = &tpm_cr50_release_locality, }; #ifdef CONFIG_ACPI @@ -668,6 +681,27 @@ static const struct of_device_id of_cr50_i2c_match[] = { MODULE_DEVICE_TABLE(of, of_cr50_i2c_match); #endif +/** + * tpm_cr50_vid_to_name() - Maps VID to name. + * @vendor: Vendor identifier to map to name + * + * Return: + * A valid string for the vendor or empty string + */ +static const char *tpm_cr50_vid_to_name(u32 vendor) +{ + switch (vendor) { + case TPM_CR50_I2C_DID_VID: + return "cr50"; + case TPM_TI50_DT_I2C_DID_VID: + return "ti50 DT"; + case TPM_TI50_OT_I2C_DID_VID: + return "ti50 OT"; + default: + return "unknown"; + } +} + /** * tpm_cr50_i2c_probe() - Driver probe function. * @client: I2C client information. @@ -684,6 +718,7 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client) u32 vendor; u8 buf[4]; int rc; + int loc; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -726,29 +761,37 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client) TPM_CR50_TIMEOUT_NOIRQ_MS); } - rc = tpm_cr50_request_locality(chip); - if (rc < 0) { + loc = tpm_cr50_request_locality(chip, TPM_CR50_I2C_DEFAULT_LOC); + if (loc < 0) { dev_err(dev, "Could not request locality\n"); - return rc; + return loc; } /* Read four bytes from DID_VID register */ - rc = tpm_cr50_i2c_read(chip, TPM_I2C_DID_VID(0), buf, sizeof(buf)); + rc = tpm_cr50_i2c_read(chip, TPM_I2C_DID_VID(loc), buf, sizeof(buf)); if (rc < 0) { dev_err(dev, "Could not read vendor id\n"); - tpm_cr50_release_locality(chip, true); + if (tpm_cr50_release_locality(chip, loc)) + dev_err(dev, "Could not release locality\n"); + return rc; + } + + rc = tpm_cr50_release_locality(chip, loc); + if (rc) { + dev_err(dev, "Could not release locality\n"); return rc; } vendor = le32_to_cpup((__le32 *)buf); - if (vendor != TPM_CR50_I2C_DID_VID && vendor != TPM_TI50_I2C_DID_VID) { + if (vendor != TPM_CR50_I2C_DID_VID && + vendor != TPM_TI50_DT_I2C_DID_VID && + vendor != TPM_TI50_OT_I2C_DID_VID) { dev_err(dev, "Vendor ID did not match! ID was %08x\n", vendor); - tpm_cr50_release_locality(chip, true); return -ENODEV; } dev_info(dev, "%s TPM 2.0 (i2c 0x%02x irq %d id 0x%x)\n", - vendor == TPM_TI50_I2C_DID_VID ? "ti50" : "cr50", + tpm_cr50_vid_to_name(vendor), client->addr, client->irq, vendor >> 16); return tpm_chip_register(chip); } @@ -772,7 +815,6 @@ static void tpm_cr50_i2c_remove(struct i2c_client *client) } tpm_chip_unregister(chip); - tpm_cr50_release_locality(chip, true); } static SIMPLE_DEV_PM_OPS(cr50_i2c_pm, tpm_pm_suspend, tpm_pm_resume); diff --git a/drivers/char/tpm/tpm_tis_synquacer.c b/drivers/char/tpm/tpm_tis_synquacer.c index 0621ebec530b47..4927714d277a12 100644 --- a/drivers/char/tpm/tpm_tis_synquacer.c +++ b/drivers/char/tpm/tpm_tis_synquacer.c @@ -152,7 +152,7 @@ MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl); static struct platform_driver tis_synquacer_drv = { .probe = tpm_tis_synquacer_probe, - .remove_new = tpm_tis_synquacer_remove, + .remove = tpm_tis_synquacer_remove, .driver = { .name = "tpm_tis_synquacer", .pm = &tpm_tis_synquacer_pm, diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 4f6c3cb8aa4138..34a345dc5e724d 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -738,7 +738,7 @@ MODULE_DEVICE_TABLE(of, hwicap_of_match); static struct platform_driver hwicap_platform_driver = { .probe = hwicap_drv_probe, - .remove_new = hwicap_drv_remove, + .remove = hwicap_drv_remove, .driver = { .name = DRIVER_NAME, .of_match_table = hwicap_of_match, diff --git a/drivers/char/xillybus/xillybus_of.c b/drivers/char/xillybus/xillybus_of.c index 8802e2a6fd20b7..1a1e64133315bc 100644 --- a/drivers/char/xillybus/xillybus_of.c +++ b/drivers/char/xillybus/xillybus_of.c @@ -74,7 +74,7 @@ static void xilly_drv_remove(struct platform_device *op) static struct platform_driver xillybus_platform_driver = { .probe = xilly_drv_probe, - .remove_new = xilly_drv_remove, + .remove = xilly_drv_remove, .driver = { .name = xillyname, .of_match_table = xillybus_of_match, diff --git a/drivers/clk/.kunitconfig b/drivers/clk/.kunitconfig index 54ece920705525..08e26137f3d9c9 100644 --- a/drivers/clk/.kunitconfig +++ b/drivers/clk/.kunitconfig @@ -1,5 +1,6 @@ CONFIG_KUNIT=y CONFIG_OF=y +CONFIG_OF_OVERLAY=y CONFIG_COMMON_CLK=y CONFIG_CLK_KUNIT_TEST=y CONFIG_CLK_FIXED_RATE_KUNIT_TEST=y diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 299bc678ed1b9f..713573b6c86c79 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -226,6 +226,17 @@ config COMMON_CLK_EP93XX help This driver supports the SoC clocks on the Cirrus Logic ep93xx. +config COMMON_CLK_EYEQ + bool "Clock driver for the Mobileye EyeQ platform" + depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST + select AUXILIARY_BUS + default MACH_EYEQ5 || MACH_EYEQ6H + help + This driver provides clocks found on Mobileye EyeQ5, EyeQ6L and Eye6H + SoCs. Controllers live in shared register regions called OLB. Driver + provides read-only PLLs, derived from the main crystal clock (which + must be constant). It also exposes some divider clocks. + config COMMON_CLK_FSL_FLEXSPI tristate "Clock driver for FlexSPI on Layerscape SoCs" depends on ARCH_LAYERSCAPE || COMPILE_TEST @@ -259,7 +270,7 @@ config COMMON_CLK_LAN966X tristate "Generic Clock Controller driver for LAN966X SoC" depends on HAS_IOMEM depends on OF - depends on SOC_LAN966 || COMPILE_TEST + depends on SOC_LAN966 || ARCH_LAN969X || COMPILE_TEST help This driver provides support for Generic Clock Controller(GCK) on LAN966X SoC. GCK generates and supplies clock to various peripherals @@ -291,7 +302,7 @@ config CLK_TWL help Enable support for controlling the clock resources on TWL family PMICs. These devices have some 32K clock outputs which can be - controlled by software. For now, only the TWL6032 clocks are + controlled by software. For now, the TWL6032 and TWL6030 clocks are supported. config CLK_TWL6040 @@ -342,6 +353,14 @@ config COMMON_CLK_LOCHNAGAR This driver supports the clocking features of the Cirrus Logic Lochnagar audio development board. +config COMMON_CLK_NPCM8XX + tristate "Clock driver for the NPCM8XX SoC Family" + depends on ARCH_NPCM || COMPILE_TEST + help + This driver supports the clocks on the Nuvoton BMC NPCM8XX SoC Family, + all the clocks are initialized by the bootloader, so this driver + allows only reading of current settings directly from the hardware. + config COMMON_CLK_LOONGSON2 bool "Clock driver for Loongson-2 SoC" depends on LOONGARCH || COMPILE_TEST @@ -517,7 +536,6 @@ config CLK_KUNIT_TEST tristate "Basic Clock Framework Kunit Tests" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS - select OF_OVERLAY if OF select DTC help Kunit tests for the common clock framework. @@ -526,7 +544,6 @@ config CLK_FIXED_RATE_KUNIT_TEST tristate "Basic fixed rate clk type KUnit test" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS - select OF_OVERLAY if OF select DTC help KUnit tests for the basic fixed rate clk type. diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index fb8878a5d7d93d..bf4bd45adc3a0e 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -4,6 +4,20 @@ obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o obj-$(CONFIG_CLK_KUNIT_TEST) += clk-test.o clk-test-y := clk_test.o \ + kunit_clk_assigned_rates_u64_one.dtbo.o \ + kunit_clk_assigned_rates_u64_one_consumer.dtbo.o \ + kunit_clk_assigned_rates_u64_multiple.dtbo.o \ + kunit_clk_assigned_rates_u64_multiple_consumer.dtbo.o \ + kunit_clk_assigned_rates_multiple.dtbo.o \ + kunit_clk_assigned_rates_multiple_consumer.dtbo.o \ + kunit_clk_assigned_rates_null.dtbo.o \ + kunit_clk_assigned_rates_null_consumer.dtbo.o \ + kunit_clk_assigned_rates_one.dtbo.o \ + kunit_clk_assigned_rates_one_consumer.dtbo.o \ + kunit_clk_assigned_rates_without.dtbo.o \ + kunit_clk_assigned_rates_without_consumer.dtbo.o \ + kunit_clk_assigned_rates_zero.dtbo.o \ + kunit_clk_assigned_rates_zero_consumer.dtbo.o \ kunit_clk_parent_data_test.dtbo.o obj-$(CONFIG_COMMON_CLK) += clk-divider.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o @@ -42,6 +56,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o +obj-$(CONFIG_COMMON_CLK_EYEQ) += clk-eyeq.o obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o @@ -62,6 +77,7 @@ obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o +obj-$(CONFIG_COMMON_CLK_NPCM8XX) += clk-npcm8xx.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o diff --git a/drivers/clk/clk-apple-nco.c b/drivers/clk/clk-apple-nco.c index 39472a51530a34..457a48d4894128 100644 --- a/drivers/clk/clk-apple-nco.c +++ b/drivers/clk/clk-apple-nco.c @@ -297,6 +297,9 @@ static int applnco_probe(struct platform_device *pdev) memset(&init, 0, sizeof(init)); init.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-%d", np->name, i); + if (!init.name) + return -ENOMEM; + init.ops = &applnco_ops; init.parent_data = &pdata; init.num_parents = 1; diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index bf4d8ddc93aea1..934e53a96dddac 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -512,6 +513,7 @@ static int axi_clkgen_probe(struct platform_device *pdev) struct clk_init_data init; const char *parent_names[2]; const char *clk_name; + struct clk *axi_clk; unsigned int i; int ret; @@ -528,8 +530,24 @@ static int axi_clkgen_probe(struct platform_device *pdev) return PTR_ERR(axi_clkgen->base); init.num_parents = of_clk_get_parent_count(pdev->dev.of_node); - if (init.num_parents < 1 || init.num_parents > 2) - return -EINVAL; + + axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk"); + if (!IS_ERR(axi_clk)) { + if (init.num_parents < 2 || init.num_parents > 3) + return -EINVAL; + + init.num_parents -= 1; + } else { + /* + * Legacy... So that old DTs which do not have clock-names still + * work. In this case we don't explicitly enable the AXI bus + * clock. + */ + if (PTR_ERR(axi_clk) != -ENOENT) + return PTR_ERR(axi_clk); + if (init.num_parents < 1 || init.num_parents > 2) + return -EINVAL; + } for (i = 0; i < init.num_parents; i++) { parent_names[i] = of_clk_get_parent_name(pdev->dev.of_node, i); diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index dd3d42d9ad8670..d0705bb03a2aae 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -678,7 +678,7 @@ MODULE_DEVICE_TABLE(of, cdce706_dt_match); #endif static const struct i2c_device_id cdce706_id[] = { - { "cdce706", 0 }, + { "cdce706" }, { } }; MODULE_DEVICE_TABLE(i2c, cdce706_id); diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index e48be7a6c0e2b0..c51818c1af9826 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -601,7 +601,7 @@ static int cdce925_regulator_enable(struct device *dev, const char *name) /* The CDCE925 uses a funky way to read/write registers. Bulk mode is * just weird, so just use the single byte mode exclusively. */ -static struct regmap_bus regmap_cdce925_bus = { +static const struct regmap_bus regmap_cdce925_bus = { .write = cdce925_regmap_i2c_write, .read = cdce925_regmap_i2c_read, }; diff --git a/drivers/clk/clk-devres.c b/drivers/clk/clk-devres.c index 82ae1f26e63457..5368d92d9b3993 100644 --- a/drivers/clk/clk-devres.c +++ b/drivers/clk/clk-devres.c @@ -218,8 +218,8 @@ static void devm_clk_bulk_release_all_enable(struct device *dev, void *res) clk_bulk_put_all(devres->num_clks, devres->clks); } -int __must_check devm_clk_bulk_get_all_enable(struct device *dev, - struct clk_bulk_data **clks) +int __must_check devm_clk_bulk_get_all_enabled(struct device *dev, + struct clk_bulk_data **clks) { struct clk_bulk_devres *devres; int ret; @@ -244,11 +244,12 @@ int __must_check devm_clk_bulk_get_all_enable(struct device *dev, } else { clk_bulk_put_all(devres->num_clks, devres->clks); devres_free(devres); + return ret; } - return ret; + return devres->num_clks; } -EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable); +EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enabled); static int devm_clk_match(struct device *dev, void *res, void *data) { diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index a2c2b5203b0a95..c1f426b8a5043c 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -72,6 +72,8 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width, return clk_div_mask(width); if (flags & CLK_DIVIDER_POWER_OF_TWO) return 1 << clk_div_mask(width); + if (flags & CLK_DIVIDER_EVEN_INTEGERS) + return 2 * (clk_div_mask(width) + 1); if (table) return _get_table_maxdiv(table, width); return clk_div_mask(width) + 1; @@ -97,6 +99,8 @@ static unsigned int _get_div(const struct clk_div_table *table, return 1 << val; if (flags & CLK_DIVIDER_MAX_AT_ZERO) return val ? val : clk_div_mask(width) + 1; + if (flags & CLK_DIVIDER_EVEN_INTEGERS) + return 2 * (val + 1); if (table) return _get_table_div(table, val); return val + 1; @@ -122,6 +126,8 @@ static unsigned int _get_val(const struct clk_div_table *table, return __ffs(div); if (flags & CLK_DIVIDER_MAX_AT_ZERO) return (div == clk_div_mask(width) + 1) ? 0 : div; + if (flags & CLK_DIVIDER_EVEN_INTEGERS) + return (div >> 1) - 1; if (table) return _get_table_val(table, div); return div - 1; @@ -538,7 +544,8 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev, struct device_node *np, const char *name, const char *parent_name, const struct clk_hw *parent_hw, const struct clk_parent_data *parent_data, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + void __iomem *reg, u8 shift, u8 width, + unsigned long clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { struct clk_divider *div; @@ -610,8 +617,8 @@ EXPORT_SYMBOL_GPL(__clk_hw_register_divider); struct clk *clk_register_divider_table(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table, - spinlock_t *lock) + unsigned long clk_divider_flags, + const struct clk_div_table *table, spinlock_t *lock) { struct clk_hw *hw; @@ -664,7 +671,8 @@ struct clk_hw *__devm_clk_hw_register_divider(struct device *dev, struct device_node *np, const char *name, const char *parent_name, const struct clk_hw *parent_hw, const struct clk_parent_data *parent_data, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + void __iomem *reg, u8 shift, u8 width, + unsigned long clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { struct clk_hw **ptr, *hw; diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c index 22fbea61c3dcc0..495c0d607c7d5b 100644 --- a/drivers/clk/clk-en7523.c +++ b/drivers/clk/clk-en7523.c @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -31,19 +33,14 @@ #define REG_RESET_CONTROL_PCIE1 BIT(27) #define REG_RESET_CONTROL_PCIE2 BIT(26) /* EN7581 */ -#define REG_PCIE0_MEM 0x00 -#define REG_PCIE0_MEM_MASK 0x04 -#define REG_PCIE1_MEM 0x08 -#define REG_PCIE1_MEM_MASK 0x0c -#define REG_PCIE2_MEM 0x10 -#define REG_PCIE2_MEM_MASK 0x14 #define REG_NP_SCU_PCIC 0x88 #define REG_NP_SCU_SSTR 0x9c #define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13) #define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11) +#define REG_CRYPTO_CLKSRC2 0x20c -#define REG_RST_CTRL2 0x00 -#define REG_RST_CTRL1 0x04 +#define REG_RST_CTRL2 0x830 +#define REG_RST_CTRL1 0x834 struct en_clk_desc { int id; @@ -79,12 +76,8 @@ struct en_rst_data { struct en_clk_soc_data { const struct clk_ops pcie_ops; - struct { - const u16 *bank_ofs; - const u16 *idx_map; - u16 idx_map_nr; - } reset; - int (*hw_init)(struct platform_device *pdev, void __iomem *np_base); + int (*hw_init)(struct platform_device *pdev, + struct clk_hw_onecell_data *clk_data); }; static const u32 gsw_base[] = { 400000000, 500000000 }; @@ -92,6 +85,11 @@ static const u32 emi_base[] = { 333000000, 400000000 }; static const u32 bus_base[] = { 500000000, 540000000 }; static const u32 slic_base[] = { 100000000, 3125000 }; static const u32 npu_base[] = { 333000000, 400000000, 500000000 }; +/* EN7581 */ +static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 }; +static const u32 bus7581_base[] = { 600000000, 540000000 }; +static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 }; +static const u32 crypto_base[] = { 540000000, 480000000 }; static const struct en_clk_desc en7523_base_clks[] = { { @@ -189,6 +187,102 @@ static const struct en_clk_desc en7523_base_clks[] = { } }; +static const struct en_clk_desc en7581_base_clks[] = { + { + .id = EN7523_CLK_GSW, + .name = "gsw", + + .base_reg = REG_GSW_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, + .base_values = gsw_base, + .n_base_values = ARRAY_SIZE(gsw_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + .div_offset = 1, + }, { + .id = EN7523_CLK_EMI, + .name = "emi", + + .base_reg = REG_EMI_CLK_DIV_SEL, + .base_bits = 2, + .base_shift = 8, + .base_values = emi7581_base, + .n_base_values = ARRAY_SIZE(emi7581_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + .div_offset = 1, + }, { + .id = EN7523_CLK_BUS, + .name = "bus", + + .base_reg = REG_BUS_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, + .base_values = bus7581_base, + .n_base_values = ARRAY_SIZE(bus7581_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + .div_offset = 1, + }, { + .id = EN7523_CLK_SLIC, + .name = "slic", + + .base_reg = REG_SPI_CLK_FREQ_SEL, + .base_bits = 1, + .base_shift = 0, + .base_values = slic_base, + .n_base_values = ARRAY_SIZE(slic_base), + + .div_reg = REG_SPI_CLK_DIV_SEL, + .div_bits = 5, + .div_shift = 24, + .div_val0 = 20, + .div_step = 2, + }, { + .id = EN7523_CLK_SPI, + .name = "spi", + + .base_reg = REG_SPI_CLK_DIV_SEL, + + .base_value = 400000000, + + .div_bits = 5, + .div_shift = 8, + .div_val0 = 40, + .div_step = 2, + }, { + .id = EN7523_CLK_NPU, + .name = "npu", + + .base_reg = REG_NPU_CLK_DIV_SEL, + .base_bits = 2, + .base_shift = 8, + .base_values = npu7581_base, + .n_base_values = ARRAY_SIZE(npu7581_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + .div_offset = 1, + }, { + .id = EN7523_CLK_CRYPTO, + .name = "crypto", + + .base_reg = REG_CRYPTO_CLKSRC2, + .base_bits = 1, + .base_shift = 0, + .base_values = crypto_base, + .n_base_values = ARRAY_SIZE(crypto_base), + } +}; + static const u16 en7581_rst_ofs[] = { REG_RST_CTRL2, REG_RST_CTRL1, @@ -252,15 +346,11 @@ static const u16 en7581_rst_map[] = { [EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31, }; -static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i) +static u32 en7523_get_base_rate(const struct en_clk_desc *desc, u32 val) { - const struct en_clk_desc *desc = &en7523_base_clks[i]; - u32 val; - if (!desc->base_bits) return desc->base_value; - val = readl(base + desc->base_reg); val >>= desc->base_shift; val &= (1 << desc->base_bits) - 1; @@ -270,16 +360,11 @@ static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i) return desc->base_values[val]; } -static u32 en7523_get_div(void __iomem *base, int i) +static u32 en7523_get_div(const struct en_clk_desc *desc, u32 val) { - const struct en_clk_desc *desc = &en7523_base_clks[i]; - u32 reg, val; - if (!desc->div_bits) return 1; - reg = desc->div_reg ? desc->div_reg : desc->base_reg; - val = readl(base + reg); val >>= desc->div_shift; val &= (1 << desc->div_bits) - 1; @@ -412,44 +497,83 @@ static void en7581_pci_disable(struct clk_hw *hw) usleep_range(1000, 2000); } -static int en7581_clk_hw_init(struct platform_device *pdev, - void __iomem *np_base) +static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data, + void __iomem *base, void __iomem *np_base) { - void __iomem *pb_base; - u32 val; + struct clk_hw *hw; + u32 rate; + int i; - pb_base = devm_platform_ioremap_resource(pdev, 3); - if (IS_ERR(pb_base)) - return PTR_ERR(pb_base); + clk_data->num = EN7523_NUM_CLOCKS; - val = readl(np_base + REG_NP_SCU_SSTR); - val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK); - writel(val, np_base + REG_NP_SCU_SSTR); - val = readl(np_base + REG_NP_SCU_PCIC); - writel(val | 3, np_base + REG_NP_SCU_PCIC); + for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) { + const struct en_clk_desc *desc = &en7523_base_clks[i]; + u32 reg = desc->div_reg ? desc->div_reg : desc->base_reg; + u32 val = readl(base + desc->base_reg); + + rate = en7523_get_base_rate(desc, val); + val = readl(base + reg); + rate /= en7523_get_div(desc, val); + + hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate); + if (IS_ERR(hw)) { + pr_err("Failed to register clk %s: %ld\n", + desc->name, PTR_ERR(hw)); + continue; + } + + clk_data->hws[desc->id] = hw; + } + + hw = en7523_register_pcie_clk(dev, np_base); + clk_data->hws[EN7523_CLK_PCIE] = hw; +} + +static int en7523_clk_hw_init(struct platform_device *pdev, + struct clk_hw_onecell_data *clk_data) +{ + void __iomem *base, *np_base; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); - writel(0x20000000, pb_base + REG_PCIE0_MEM); - writel(0xfc000000, pb_base + REG_PCIE0_MEM_MASK); - writel(0x24000000, pb_base + REG_PCIE1_MEM); - writel(0xfc000000, pb_base + REG_PCIE1_MEM_MASK); - writel(0x28000000, pb_base + REG_PCIE2_MEM); - writel(0xfc000000, pb_base + REG_PCIE2_MEM_MASK); + np_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(np_base)) + return PTR_ERR(np_base); + + en7523_register_clocks(&pdev->dev, clk_data, base, np_base); return 0; } -static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data, - void __iomem *base, void __iomem *np_base) +static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data, + struct regmap *map, void __iomem *base) { struct clk_hw *hw; u32 rate; int i; - for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) { - const struct en_clk_desc *desc = &en7523_base_clks[i]; + for (i = 0; i < ARRAY_SIZE(en7581_base_clks); i++) { + const struct en_clk_desc *desc = &en7581_base_clks[i]; + u32 val, reg = desc->div_reg ? desc->div_reg : desc->base_reg; + int err; - rate = en7523_get_base_rate(base, i); - rate /= en7523_get_div(base, i); + err = regmap_read(map, desc->base_reg, &val); + if (err) { + pr_err("Failed reading fixed clk rate %s: %d\n", + desc->name, err); + continue; + } + rate = en7523_get_base_rate(desc, val); + + err = regmap_read(map, reg, &val); + if (err) { + pr_err("Failed reading fixed clk div %s: %d\n", + desc->name, err); + continue; + } + rate /= en7523_get_div(desc, val); hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate); if (IS_ERR(hw)) { @@ -461,7 +585,7 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat clk_data->hws[desc->id] = hw; } - hw = en7523_register_pcie_clk(dev, np_base); + hw = en7523_register_pcie_clk(dev, base); clk_data->hws[EN7523_CLK_PCIE] = hw; clk_data->num = EN7523_NUM_CLOCKS; @@ -516,38 +640,27 @@ static int en7523_reset_xlate(struct reset_controller_dev *rcdev, return rst_data->idx_map[reset_spec->args[0]]; } -static const struct reset_control_ops en7523_reset_ops = { +static const struct reset_control_ops en7581_reset_ops = { .assert = en7523_reset_assert, .deassert = en7523_reset_deassert, .status = en7523_reset_status, }; -static int en7523_reset_register(struct platform_device *pdev, - const struct en_clk_soc_data *soc_data) +static int en7581_reset_register(struct device *dev, void __iomem *base) { - struct device *dev = &pdev->dev; struct en_rst_data *rst_data; - void __iomem *base; - - /* no reset lines available */ - if (!soc_data->reset.idx_map_nr) - return 0; - - base = devm_platform_ioremap_resource(pdev, 2); - if (IS_ERR(base)) - return PTR_ERR(base); rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL); if (!rst_data) return -ENOMEM; - rst_data->bank_ofs = soc_data->reset.bank_ofs; - rst_data->idx_map = soc_data->reset.idx_map; + rst_data->bank_ofs = en7581_rst_ofs; + rst_data->idx_map = en7581_rst_map; rst_data->base = base; - rst_data->rcdev.nr_resets = soc_data->reset.idx_map_nr; + rst_data->rcdev.nr_resets = ARRAY_SIZE(en7581_rst_map); rst_data->rcdev.of_xlate = en7523_reset_xlate; - rst_data->rcdev.ops = &en7523_reset_ops; + rst_data->rcdev.ops = &en7581_reset_ops; rst_data->rcdev.of_node = dev->of_node; rst_data->rcdev.of_reset_n_cells = 1; rst_data->rcdev.owner = THIS_MODULE; @@ -556,28 +669,38 @@ static int en7523_reset_register(struct platform_device *pdev, return devm_reset_controller_register(dev, &rst_data->rcdev); } -static int en7523_clk_probe(struct platform_device *pdev) +static int en7581_clk_hw_init(struct platform_device *pdev, + struct clk_hw_onecell_data *clk_data) { - struct device_node *node = pdev->dev.of_node; - const struct en_clk_soc_data *soc_data; - struct clk_hw_onecell_data *clk_data; - void __iomem *base, *np_base; - int r; + struct regmap *map; + void __iomem *base; + u32 val; + + map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu"); + if (IS_ERR(map)) + return PTR_ERR(map); base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); - np_base = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(np_base)) - return PTR_ERR(np_base); + en7581_register_clocks(&pdev->dev, clk_data, map, base); - soc_data = device_get_match_data(&pdev->dev); - if (soc_data->hw_init) { - r = soc_data->hw_init(pdev, np_base); - if (r) - return r; - } + val = readl(base + REG_NP_SCU_SSTR); + val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK); + writel(val, base + REG_NP_SCU_SSTR); + val = readl(base + REG_NP_SCU_PCIC); + writel(val | 3, base + REG_NP_SCU_PCIC); + + return en7581_reset_register(&pdev->dev, base); +} + +static int en7523_clk_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + const struct en_clk_soc_data *soc_data; + struct clk_hw_onecell_data *clk_data; + int r; clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, EN7523_NUM_CLOCKS), @@ -585,21 +708,12 @@ static int en7523_clk_probe(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - en7523_register_clocks(&pdev->dev, clk_data, base, np_base); - - r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + soc_data = device_get_match_data(&pdev->dev); + r = soc_data->hw_init(pdev, clk_data); if (r) - return dev_err_probe(&pdev->dev, r, "Could not register clock provider: %s\n", - pdev->name); - - r = en7523_reset_register(pdev, soc_data); - if (r) { - of_clk_del_provider(node); - return dev_err_probe(&pdev->dev, r, "Could not register reset controller: %s\n", - pdev->name); - } + return r; - return 0; + return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); } static const struct en_clk_soc_data en7523_data = { @@ -608,6 +722,7 @@ static const struct en_clk_soc_data en7523_data = { .prepare = en7523_pci_prepare, .unprepare = en7523_pci_unprepare, }, + .hw_init = en7523_clk_hw_init, }; static const struct en_clk_soc_data en7581_data = { @@ -616,11 +731,6 @@ static const struct en_clk_soc_data en7581_data = { .enable = en7581_pci_enable, .disable = en7581_pci_disable, }, - .reset = { - .bank_ofs = en7581_rst_ofs, - .idx_map = en7581_rst_map, - .idx_map_nr = ARRAY_SIZE(en7581_rst_map), - }, .hw_init = en7581_clk_hw_init, }; diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c new file mode 100644 index 00000000000000..640c25788487f8 --- /dev/null +++ b/drivers/clk/clk-eyeq.c @@ -0,0 +1,859 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PLL clock driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms. + * + * This controller handles: + * - Read-only PLLs, all derived from the same main crystal clock. + * - It also exposes divider clocks, those are children to PLLs. + * - Fixed factor clocks, children to PLLs. + * + * Parent clock is expected to be constant. This driver's registers live in a + * shared region called OLB. Some PLLs and fixed-factors are initialised early + * by of_clk_init(); if so, two clk providers are registered. + * + * We use eqc_ as prefix, as-in "EyeQ Clock", but way shorter. + * + * Copyright (C) 2024 Mobileye Vision Technologies Ltd. + */ + +/* + * Set pr_fmt() for printing from eqc_early_init(). + * It is called at of_clk_init() stage (read: really early). + */ +#define pr_fmt(fmt) "clk-eyeq: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* In frac mode, it enables fractional noise canceling DAC. Else, no function. */ +#define PCSR0_DAC_EN BIT(0) +/* Fractional or integer mode */ +#define PCSR0_DSM_EN BIT(1) +#define PCSR0_PLL_EN BIT(2) +/* All clocks output held at 0 */ +#define PCSR0_FOUTPOSTDIV_EN BIT(3) +#define PCSR0_POST_DIV1 GENMASK(6, 4) +#define PCSR0_POST_DIV2 GENMASK(9, 7) +#define PCSR0_REF_DIV GENMASK(15, 10) +#define PCSR0_INTIN GENMASK(27, 16) +#define PCSR0_BYPASS BIT(28) +/* Bits 30..29 are reserved */ +#define PCSR0_PLL_LOCKED BIT(31) + +#define PCSR1_RESET BIT(0) +#define PCSR1_SSGC_DIV GENMASK(4, 1) +/* Spread amplitude (% = 0.1 * SPREAD[4:0]) */ +#define PCSR1_SPREAD GENMASK(9, 5) +#define PCSR1_DIS_SSCG BIT(10) +/* Down-spread or center-spread */ +#define PCSR1_DOWN_SPREAD BIT(11) +#define PCSR1_FRAC_IN GENMASK(31, 12) + +struct eqc_pll { + unsigned int index; + const char *name; + unsigned int reg64; +}; + +/* + * Divider clock. Divider is 2*(v+1), with v the register value. + * Min divider is 2, max is 2*(2^width). + */ +struct eqc_div { + unsigned int index; + const char *name; + unsigned int parent; + unsigned int reg; + u8 shift; + u8 width; +}; + +struct eqc_fixed_factor { + unsigned int index; + const char *name; + unsigned int mult; + unsigned int div; + unsigned int parent; +}; + +struct eqc_match_data { + unsigned int pll_count; + const struct eqc_pll *plls; + + unsigned int div_count; + const struct eqc_div *divs; + + unsigned int fixed_factor_count; + const struct eqc_fixed_factor *fixed_factors; + + const char *reset_auxdev_name; + const char *pinctrl_auxdev_name; + + unsigned int early_clk_count; +}; + +struct eqc_early_match_data { + unsigned int early_pll_count; + const struct eqc_pll *early_plls; + + unsigned int early_fixed_factor_count; + const struct eqc_fixed_factor *early_fixed_factors; + + /* + * We want our of_xlate callback to EPROBE_DEFER instead of dev_err() + * and EINVAL. For that, we must know the total clock count. + */ + unsigned int late_clk_count; +}; + +/* + * Both factors (mult and div) must fit in 32 bits. When an operation overflows, + * this function throws away low bits so that factors still fit in 32 bits. + * + * Precision loss depends on amplitude of mult and div. Worst theorical + * loss is: (UINT_MAX+1) / UINT_MAX - 1 = 2.3e-10. + * This is 1Hz every 4.3GHz. + */ +static void eqc_pll_downshift_factors(unsigned long *mult, unsigned long *div) +{ + unsigned long biggest; + unsigned int shift; + + /* This function can be removed if mult/div switch to unsigned long. */ + static_assert(sizeof_field(struct clk_fixed_factor, mult) == sizeof(unsigned int)); + static_assert(sizeof_field(struct clk_fixed_factor, div) == sizeof(unsigned int)); + + /* No overflow, nothing to be done. */ + if (*mult <= UINT_MAX && *div <= UINT_MAX) + return; + + /* + * Compute the shift required to bring the biggest factor into unsigned + * int range. That is, shift its highest set bit to the unsigned int + * most significant bit. + */ + biggest = max(*mult, *div); + shift = __fls(biggest) - (BITS_PER_BYTE * sizeof(unsigned int)) + 1; + + *mult >>= shift; + *div >>= shift; +} + +static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult, + unsigned long *div, unsigned long *acc) +{ + u32 spread; + + if (r0 & PCSR0_BYPASS) { + *mult = 1; + *div = 1; + *acc = 0; + return 0; + } + + if (!(r0 & PCSR0_PLL_LOCKED)) + return -EINVAL; + + *mult = FIELD_GET(PCSR0_INTIN, r0); + *div = FIELD_GET(PCSR0_REF_DIV, r0); + if (r0 & PCSR0_FOUTPOSTDIV_EN) + *div *= FIELD_GET(PCSR0_POST_DIV1, r0) * FIELD_GET(PCSR0_POST_DIV2, r0); + + /* Fractional mode, in 2^20 (0x100000) parts. */ + if (r0 & PCSR0_DSM_EN) { + *div *= (1ULL << 20); + *mult = *mult * (1ULL << 20) + FIELD_GET(PCSR1_FRAC_IN, r1); + } + + if (!*mult || !*div) + return -EINVAL; + + if (r1 & (PCSR1_RESET | PCSR1_DIS_SSCG)) { + *acc = 0; + return 0; + } + + /* + * Spread spectrum. + * + * Spread is 1/1000 parts of frequency, accuracy is half of + * that. To get accuracy, convert to ppb (parts per billion). + * + * acc = spread * 1e6 / 2 + * with acc in parts per billion and, + * spread in parts per thousand. + */ + spread = FIELD_GET(PCSR1_SPREAD, r1); + *acc = spread * 500000; + + if (r1 & PCSR1_DOWN_SPREAD) { + /* + * Downspreading: the central frequency is half a + * spread lower. + */ + *mult *= 2000 - spread; + *div *= 2000; + + /* + * Previous operation might overflow 32 bits. If it + * does, throw away the least amount of low bits. + */ + eqc_pll_downshift_factors(mult, div); + } + + return 0; +} + +static void eqc_probe_init_plls(struct device *dev, const struct eqc_match_data *data, + void __iomem *base, struct clk_hw_onecell_data *cells) +{ + unsigned long mult, div, acc; + const struct eqc_pll *pll; + struct clk_hw *hw; + unsigned int i; + u32 r0, r1; + u64 val; + int ret; + + for (i = 0; i < data->pll_count; i++) { + pll = &data->plls[i]; + + val = readq(base + pll->reg64); + r0 = val; + r1 = val >> 32; + + ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc); + if (ret) { + dev_warn(dev, "failed parsing state of %s\n", pll->name); + cells->hws[pll->index] = ERR_PTR(ret); + continue; + } + + hw = clk_hw_register_fixed_factor_with_accuracy_fwname(dev, + dev->of_node, pll->name, "ref", 0, mult, div, acc); + cells->hws[pll->index] = hw; + if (IS_ERR(hw)) + dev_warn(dev, "failed registering %s: %pe\n", pll->name, hw); + } +} + +static void eqc_probe_init_divs(struct device *dev, const struct eqc_match_data *data, + void __iomem *base, struct clk_hw_onecell_data *cells) +{ + struct clk_parent_data parent_data = { }; + const struct eqc_div *div; + struct clk_hw *parent; + void __iomem *reg; + struct clk_hw *hw; + unsigned int i; + + for (i = 0; i < data->div_count; i++) { + div = &data->divs[i]; + reg = base + div->reg; + parent = cells->hws[div->parent]; + + if (IS_ERR(parent)) { + /* Parent is in early clk provider. */ + parent_data.index = div->parent; + parent_data.hw = NULL; + } else { + /* Avoid clock lookup when we already have the hw reference. */ + parent_data.index = 0; + parent_data.hw = parent; + } + + hw = clk_hw_register_divider_table_parent_data(dev, div->name, + &parent_data, 0, reg, div->shift, div->width, + CLK_DIVIDER_EVEN_INTEGERS, NULL, NULL); + cells->hws[div->index] = hw; + if (IS_ERR(hw)) + dev_warn(dev, "failed registering %s: %pe\n", + div->name, hw); + } +} + +static void eqc_probe_init_fixed_factors(struct device *dev, + const struct eqc_match_data *data, + struct clk_hw_onecell_data *cells) +{ + const struct eqc_fixed_factor *ff; + struct clk_hw *hw, *parent_hw; + unsigned int i; + + for (i = 0; i < data->fixed_factor_count; i++) { + ff = &data->fixed_factors[i]; + parent_hw = cells->hws[ff->parent]; + + if (IS_ERR(parent_hw)) { + /* Parent is in early clk provider. */ + hw = clk_hw_register_fixed_factor_index(dev, ff->name, + ff->parent, 0, ff->mult, ff->div); + } else { + /* Avoid clock lookup when we already have the hw reference. */ + hw = clk_hw_register_fixed_factor_parent_hw(dev, ff->name, + parent_hw, 0, ff->mult, ff->div); + } + + cells->hws[ff->index] = hw; + if (IS_ERR(hw)) + dev_warn(dev, "failed registering %s: %pe\n", + ff->name, hw); + } +} + +static void eqc_auxdev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + + kfree(adev); +} + +static int eqc_auxdev_create(struct device *dev, void __iomem *base, + const char *name, u32 id) +{ + struct auxiliary_device *adev; + int ret; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + adev->name = name; + adev->dev.parent = dev; + adev->dev.platform_data = (void __force *)base; + adev->dev.release = eqc_auxdev_release; + adev->id = id; + + ret = auxiliary_device_init(adev); + if (ret) + return ret; + + ret = auxiliary_device_add(adev); + if (ret) + auxiliary_device_uninit(adev); + + return ret; +} + +static int eqc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct eqc_match_data *data; + struct clk_hw_onecell_data *cells; + unsigned int i, clk_count; + struct resource *res; + void __iomem *base; + int ret; + + data = device_get_match_data(dev); + if (!data) + return 0; /* No clocks nor auxdevs, we are done. */ + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + base = ioremap(res->start, resource_size(res)); + if (!base) + return -ENOMEM; + + /* Init optional reset auxiliary device. */ + if (data->reset_auxdev_name) { + ret = eqc_auxdev_create(dev, base, data->reset_auxdev_name, 0); + if (ret) + dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n", + KBUILD_MODNAME, data->reset_auxdev_name, ret); + } + + /* Init optional pinctrl auxiliary device. */ + if (data->pinctrl_auxdev_name) { + ret = eqc_auxdev_create(dev, base, data->pinctrl_auxdev_name, 0); + if (ret) + dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n", + KBUILD_MODNAME, data->pinctrl_auxdev_name, ret); + } + + if (data->pll_count + data->div_count + data->fixed_factor_count == 0) + return 0; /* Zero clocks, we are done. */ + + clk_count = data->pll_count + data->div_count + + data->fixed_factor_count + data->early_clk_count; + cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL); + if (!cells) + return -ENOMEM; + + cells->num = clk_count; + + /* Early PLLs are marked as errors: the early provider will get queried. */ + for (i = 0; i < clk_count; i++) + cells->hws[i] = ERR_PTR(-EINVAL); + + eqc_probe_init_plls(dev, data, base, cells); + + eqc_probe_init_divs(dev, data, base, cells); + + eqc_probe_init_fixed_factors(dev, data, cells); + + return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells); +} + +/* Required early for GIC timer (pll-cpu) and UARTs (pll-per). */ +static const struct eqc_pll eqc_eyeq5_early_plls[] = { + { .index = EQ5C_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C }, + { .index = EQ5C_PLL_PER, .name = "pll-per", .reg64 = 0x05C }, +}; + +static const struct eqc_pll eqc_eyeq5_plls[] = { + { .index = EQ5C_PLL_VMP, .name = "pll-vmp", .reg64 = 0x034 }, + { .index = EQ5C_PLL_PMA, .name = "pll-pma", .reg64 = 0x03C }, + { .index = EQ5C_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 }, + { .index = EQ5C_PLL_DDR0, .name = "pll-ddr0", .reg64 = 0x04C }, + { .index = EQ5C_PLL_PCI, .name = "pll-pci", .reg64 = 0x054 }, + { .index = EQ5C_PLL_PMAC, .name = "pll-pmac", .reg64 = 0x064 }, + { .index = EQ5C_PLL_MPC, .name = "pll-mpc", .reg64 = 0x06C }, + { .index = EQ5C_PLL_DDR1, .name = "pll-ddr1", .reg64 = 0x074 }, +}; + +enum { + /* + * EQ5C_PLL_CPU children. + * EQ5C_PER_OCC_PCI is the last clock exposed in dt-bindings. + */ + EQ5C_CPU_OCC = EQ5C_PER_OCC_PCI + 1, + EQ5C_CPU_SI_CSS0, + EQ5C_CPU_CPC, + EQ5C_CPU_CM, + EQ5C_CPU_MEM, + EQ5C_CPU_OCC_ISRAM, + EQ5C_CPU_ISRAM, + EQ5C_CPU_OCC_DBU, + EQ5C_CPU_SI_DBU_TP, + + /* + * EQ5C_PLL_VDI children. + */ + EQ5C_VDI_OCC_VDI, + EQ5C_VDI_VDI, + EQ5C_VDI_OCC_CAN_SER, + EQ5C_VDI_CAN_SER, + EQ5C_VDI_I2C_SER, + + /* + * EQ5C_PLL_PER children. + */ + EQ5C_PER_PERIPH, + EQ5C_PER_CAN, + EQ5C_PER_TIMER, + EQ5C_PER_CCF, + EQ5C_PER_OCC_MJPEG, + EQ5C_PER_HSM, + EQ5C_PER_MJPEG, + EQ5C_PER_FCMU_A, +}; + +static const struct eqc_fixed_factor eqc_eyeq5_early_fixed_factors[] = { + /* EQ5C_PLL_CPU children */ + { EQ5C_CPU_OCC, "occ-cpu", 1, 1, EQ5C_PLL_CPU }, + { EQ5C_CPU_SI_CSS0, "si-css0", 1, 1, EQ5C_CPU_OCC }, + { EQ5C_CPU_CORE0, "core0", 1, 1, EQ5C_CPU_SI_CSS0 }, + { EQ5C_CPU_CORE1, "core1", 1, 1, EQ5C_CPU_SI_CSS0 }, + { EQ5C_CPU_CORE2, "core2", 1, 1, EQ5C_CPU_SI_CSS0 }, + { EQ5C_CPU_CORE3, "core3", 1, 1, EQ5C_CPU_SI_CSS0 }, + + /* EQ5C_PLL_PER children */ + { EQ5C_PER_OCC, "occ-periph", 1, 16, EQ5C_PLL_PER }, + { EQ5C_PER_UART, "uart", 1, 1, EQ5C_PER_OCC }, +}; + +static const struct eqc_fixed_factor eqc_eyeq5_fixed_factors[] = { + /* EQ5C_PLL_CPU children */ + { EQ5C_CPU_CPC, "cpc", 1, 1, EQ5C_CPU_SI_CSS0 }, + { EQ5C_CPU_CM, "cm", 1, 1, EQ5C_CPU_SI_CSS0 }, + { EQ5C_CPU_MEM, "mem", 1, 1, EQ5C_CPU_SI_CSS0 }, + { EQ5C_CPU_OCC_ISRAM, "occ-isram", 1, 2, EQ5C_PLL_CPU }, + { EQ5C_CPU_ISRAM, "isram", 1, 1, EQ5C_CPU_OCC_ISRAM }, + { EQ5C_CPU_OCC_DBU, "occ-dbu", 1, 10, EQ5C_PLL_CPU }, + { EQ5C_CPU_SI_DBU_TP, "si-dbu-tp", 1, 1, EQ5C_CPU_OCC_DBU }, + + /* EQ5C_PLL_VDI children */ + { EQ5C_VDI_OCC_VDI, "occ-vdi", 1, 2, EQ5C_PLL_VDI }, + { EQ5C_VDI_VDI, "vdi", 1, 1, EQ5C_VDI_OCC_VDI }, + { EQ5C_VDI_OCC_CAN_SER, "occ-can-ser", 1, 16, EQ5C_PLL_VDI }, + { EQ5C_VDI_CAN_SER, "can-ser", 1, 1, EQ5C_VDI_OCC_CAN_SER }, + { EQ5C_VDI_I2C_SER, "i2c-ser", 1, 20, EQ5C_PLL_VDI }, + + /* EQ5C_PLL_PER children */ + { EQ5C_PER_PERIPH, "periph", 1, 1, EQ5C_PER_OCC }, + { EQ5C_PER_CAN, "can", 1, 1, EQ5C_PER_OCC }, + { EQ5C_PER_SPI, "spi", 1, 1, EQ5C_PER_OCC }, + { EQ5C_PER_I2C, "i2c", 1, 1, EQ5C_PER_OCC }, + { EQ5C_PER_TIMER, "timer", 1, 1, EQ5C_PER_OCC }, + { EQ5C_PER_GPIO, "gpio", 1, 1, EQ5C_PER_OCC }, + { EQ5C_PER_EMMC, "emmc-sys", 1, 10, EQ5C_PLL_PER }, + { EQ5C_PER_CCF, "ccf-ctrl", 1, 4, EQ5C_PLL_PER }, + { EQ5C_PER_OCC_MJPEG, "occ-mjpeg", 1, 2, EQ5C_PLL_PER }, + { EQ5C_PER_HSM, "hsm", 1, 1, EQ5C_PER_OCC_MJPEG }, + { EQ5C_PER_MJPEG, "mjpeg", 1, 1, EQ5C_PER_OCC_MJPEG }, + { EQ5C_PER_FCMU_A, "fcmu-a", 1, 20, EQ5C_PLL_PER }, + { EQ5C_PER_OCC_PCI, "occ-pci-sys", 1, 8, EQ5C_PLL_PER }, +}; + +static const struct eqc_div eqc_eyeq5_divs[] = { + { + .index = EQ5C_DIV_OSPI, + .name = "div-ospi", + .parent = EQ5C_PLL_PER, + .reg = 0x11C, + .shift = 0, + .width = 4, + }, +}; + +static const struct eqc_early_match_data eqc_eyeq5_early_match_data __initconst = { + .early_pll_count = ARRAY_SIZE(eqc_eyeq5_early_plls), + .early_plls = eqc_eyeq5_early_plls, + + .early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq5_early_fixed_factors), + .early_fixed_factors = eqc_eyeq5_early_fixed_factors, + + .late_clk_count = ARRAY_SIZE(eqc_eyeq5_plls) + ARRAY_SIZE(eqc_eyeq5_divs) + + ARRAY_SIZE(eqc_eyeq5_fixed_factors), +}; + +static const struct eqc_match_data eqc_eyeq5_match_data = { + .pll_count = ARRAY_SIZE(eqc_eyeq5_plls), + .plls = eqc_eyeq5_plls, + + .div_count = ARRAY_SIZE(eqc_eyeq5_divs), + .divs = eqc_eyeq5_divs, + + .fixed_factor_count = ARRAY_SIZE(eqc_eyeq5_fixed_factors), + .fixed_factors = eqc_eyeq5_fixed_factors, + + .reset_auxdev_name = "reset", + .pinctrl_auxdev_name = "pinctrl", + + .early_clk_count = ARRAY_SIZE(eqc_eyeq5_early_plls) + + ARRAY_SIZE(eqc_eyeq5_early_fixed_factors), +}; + +static const struct eqc_pll eqc_eyeq6l_plls[] = { + { .index = EQ6LC_PLL_DDR, .name = "pll-ddr", .reg64 = 0x02C }, + { .index = EQ6LC_PLL_CPU, .name = "pll-cpu", .reg64 = 0x034 }, /* also acc */ + { .index = EQ6LC_PLL_PER, .name = "pll-per", .reg64 = 0x03C }, + { .index = EQ6LC_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 }, +}; + +static const struct eqc_match_data eqc_eyeq6l_match_data = { + .pll_count = ARRAY_SIZE(eqc_eyeq6l_plls), + .plls = eqc_eyeq6l_plls, + + .reset_auxdev_name = "reset", +}; + +static const struct eqc_match_data eqc_eyeq6h_west_match_data = { + .reset_auxdev_name = "reset_west", +}; + +static const struct eqc_pll eqc_eyeq6h_east_plls[] = { + { .index = 0, .name = "pll-east", .reg64 = 0x074 }, +}; + +static const struct eqc_match_data eqc_eyeq6h_east_match_data = { + .pll_count = ARRAY_SIZE(eqc_eyeq6h_east_plls), + .plls = eqc_eyeq6h_east_plls, + + .reset_auxdev_name = "reset_east", +}; + +static const struct eqc_pll eqc_eyeq6h_south_plls[] = { + { .index = EQ6HC_SOUTH_PLL_VDI, .name = "pll-vdi", .reg64 = 0x000 }, + { .index = EQ6HC_SOUTH_PLL_PCIE, .name = "pll-pcie", .reg64 = 0x008 }, + { .index = EQ6HC_SOUTH_PLL_PER, .name = "pll-per", .reg64 = 0x010 }, + { .index = EQ6HC_SOUTH_PLL_ISP, .name = "pll-isp", .reg64 = 0x018 }, +}; + +static const struct eqc_div eqc_eyeq6h_south_divs[] = { + { + .index = EQ6HC_SOUTH_DIV_EMMC, + .name = "div-emmc", + .parent = EQ6HC_SOUTH_PLL_PER, + .reg = 0x070, + .shift = 4, + .width = 4, + }, + { + .index = EQ6HC_SOUTH_DIV_OSPI_REF, + .name = "div-ospi-ref", + .parent = EQ6HC_SOUTH_PLL_PER, + .reg = 0x090, + .shift = 4, + .width = 4, + }, + { + .index = EQ6HC_SOUTH_DIV_OSPI_SYS, + .name = "div-ospi-sys", + .parent = EQ6HC_SOUTH_PLL_PER, + .reg = 0x090, + .shift = 8, + .width = 1, + }, + { + .index = EQ6HC_SOUTH_DIV_TSU, + .name = "div-tsu", + .parent = EQ6HC_SOUTH_PLL_PCIE, + .reg = 0x098, + .shift = 4, + .width = 8, + }, +}; + +static const struct eqc_match_data eqc_eyeq6h_south_match_data = { + .pll_count = ARRAY_SIZE(eqc_eyeq6h_south_plls), + .plls = eqc_eyeq6h_south_plls, + + .div_count = ARRAY_SIZE(eqc_eyeq6h_south_divs), + .divs = eqc_eyeq6h_south_divs, +}; + +static const struct eqc_pll eqc_eyeq6h_ddr0_plls[] = { + { .index = 0, .name = "pll-ddr0", .reg64 = 0x074 }, +}; + +static const struct eqc_match_data eqc_eyeq6h_ddr0_match_data = { + .pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr0_plls), + .plls = eqc_eyeq6h_ddr0_plls, +}; + +static const struct eqc_pll eqc_eyeq6h_ddr1_plls[] = { + { .index = 0, .name = "pll-ddr1", .reg64 = 0x074 }, +}; + +static const struct eqc_match_data eqc_eyeq6h_ddr1_match_data = { + .pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr1_plls), + .plls = eqc_eyeq6h_ddr1_plls, +}; + +static const struct eqc_pll eqc_eyeq6h_acc_plls[] = { + { .index = EQ6HC_ACC_PLL_XNN, .name = "pll-xnn", .reg64 = 0x040 }, + { .index = EQ6HC_ACC_PLL_VMP, .name = "pll-vmp", .reg64 = 0x050 }, + { .index = EQ6HC_ACC_PLL_PMA, .name = "pll-pma", .reg64 = 0x05C }, + { .index = EQ6HC_ACC_PLL_MPC, .name = "pll-mpc", .reg64 = 0x068 }, + { .index = EQ6HC_ACC_PLL_NOC, .name = "pll-noc", .reg64 = 0x070 }, +}; + +static const struct eqc_match_data eqc_eyeq6h_acc_match_data = { + .pll_count = ARRAY_SIZE(eqc_eyeq6h_acc_plls), + .plls = eqc_eyeq6h_acc_plls, + + .reset_auxdev_name = "reset_acc", +}; + +static const struct of_device_id eqc_match_table[] = { + { .compatible = "mobileye,eyeq5-olb", .data = &eqc_eyeq5_match_data }, + { .compatible = "mobileye,eyeq6l-olb", .data = &eqc_eyeq6l_match_data }, + { .compatible = "mobileye,eyeq6h-west-olb", .data = &eqc_eyeq6h_west_match_data }, + { .compatible = "mobileye,eyeq6h-east-olb", .data = &eqc_eyeq6h_east_match_data }, + { .compatible = "mobileye,eyeq6h-south-olb", .data = &eqc_eyeq6h_south_match_data }, + { .compatible = "mobileye,eyeq6h-ddr0-olb", .data = &eqc_eyeq6h_ddr0_match_data }, + { .compatible = "mobileye,eyeq6h-ddr1-olb", .data = &eqc_eyeq6h_ddr1_match_data }, + { .compatible = "mobileye,eyeq6h-acc-olb", .data = &eqc_eyeq6h_acc_match_data }, + {} +}; + +static struct platform_driver eqc_driver = { + .probe = eqc_probe, + .driver = { + .name = "clk-eyeq", + .of_match_table = eqc_match_table, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(eqc_driver); + +/* Required early for GIC timer. */ +static const struct eqc_pll eqc_eyeq6h_central_early_plls[] = { + { .index = EQ6HC_CENTRAL_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C }, +}; + +static const struct eqc_fixed_factor eqc_eyeq6h_central_early_fixed_factors[] = { + { EQ6HC_CENTRAL_CPU_OCC, "occ-cpu", 1, 1, EQ6HC_CENTRAL_PLL_CPU }, +}; + +static const struct eqc_early_match_data eqc_eyeq6h_central_early_match_data __initconst = { + .early_pll_count = ARRAY_SIZE(eqc_eyeq6h_central_early_plls), + .early_plls = eqc_eyeq6h_central_early_plls, + + .early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6h_central_early_fixed_factors), + .early_fixed_factors = eqc_eyeq6h_central_early_fixed_factors, +}; + +/* Required early for UART. */ +static const struct eqc_pll eqc_eyeq6h_west_early_plls[] = { + { .index = EQ6HC_WEST_PLL_PER, .name = "pll-west", .reg64 = 0x074 }, +}; + +static const struct eqc_fixed_factor eqc_eyeq6h_west_early_fixed_factors[] = { + { EQ6HC_WEST_PER_OCC, "west-per-occ", 1, 10, EQ6HC_WEST_PLL_PER }, + { EQ6HC_WEST_PER_UART, "west-per-uart", 1, 1, EQ6HC_WEST_PER_OCC }, +}; + +static const struct eqc_early_match_data eqc_eyeq6h_west_early_match_data __initconst = { + .early_pll_count = ARRAY_SIZE(eqc_eyeq6h_west_early_plls), + .early_plls = eqc_eyeq6h_west_early_plls, + + .early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6h_west_early_fixed_factors), + .early_fixed_factors = eqc_eyeq6h_west_early_fixed_factors, +}; + +static void __init eqc_early_init(struct device_node *np, + const struct eqc_early_match_data *early_data) +{ + struct clk_hw_onecell_data *cells; + unsigned int i, clk_count; + void __iomem *base; + int ret; + + clk_count = early_data->early_pll_count + early_data->early_fixed_factor_count + + early_data->late_clk_count; + cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL); + if (!cells) { + ret = -ENOMEM; + goto err; + } + + cells->num = clk_count; + + /* + * Mark all clocks as deferred; some are registered here, the rest at + * platform device probe. + * + * Once the platform device is probed, its provider will take priority + * when looking up clocks. + */ + for (i = 0; i < clk_count; i++) + cells->hws[i] = ERR_PTR(-EPROBE_DEFER); + + /* Offsets (reg64) of early PLLs are relative to OLB block. */ + base = of_iomap(np, 0); + if (!base) { + ret = -ENODEV; + goto err; + } + + for (i = 0; i < early_data->early_pll_count; i++) { + const struct eqc_pll *pll = &early_data->early_plls[i]; + unsigned long mult, div, acc; + struct clk_hw *hw; + u32 r0, r1; + u64 val; + + val = readq(base + pll->reg64); + r0 = val; + r1 = val >> 32; + + ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc); + if (ret) { + pr_err("failed parsing state of %s\n", pll->name); + goto err; + } + + hw = clk_hw_register_fixed_factor_with_accuracy_fwname(NULL, + np, pll->name, "ref", 0, mult, div, acc); + cells->hws[pll->index] = hw; + if (IS_ERR(hw)) { + pr_err("failed registering %s: %pe\n", pll->name, hw); + ret = PTR_ERR(hw); + goto err; + } + } + + for (i = 0; i < early_data->early_fixed_factor_count; i++) { + const struct eqc_fixed_factor *ff = &early_data->early_fixed_factors[i]; + struct clk_hw *parent_hw = cells->hws[ff->parent]; + struct clk_hw *hw; + + hw = clk_hw_register_fixed_factor_parent_hw(NULL, ff->name, + parent_hw, 0, ff->mult, ff->div); + cells->hws[ff->index] = hw; + if (IS_ERR(hw)) { + pr_err("failed registering %s: %pe\n", ff->name, hw); + ret = PTR_ERR(hw); + goto err; + } + } + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells); + if (ret) { + pr_err("failed registering clk provider: %d\n", ret); + goto err; + } + + return; + +err: + /* + * We are doomed. The system will not be able to boot. + * + * Let's still try to be good citizens by freeing resources and print + * a last error message that might help debugging. + */ + + pr_err("failed clk init: %d\n", ret); + + if (cells) { + of_clk_del_provider(np); + + for (i = 0; i < early_data->early_pll_count; i++) { + const struct eqc_pll *pll = &early_data->early_plls[i]; + struct clk_hw *hw = cells->hws[pll->index]; + + if (!IS_ERR_OR_NULL(hw)) + clk_hw_unregister_fixed_factor(hw); + } + + kfree(cells); + } +} + +static void __init eqc_eyeq5_early_init(struct device_node *np) +{ + eqc_early_init(np, &eqc_eyeq5_early_match_data); +} +CLK_OF_DECLARE_DRIVER(eqc_eyeq5, "mobileye,eyeq5-olb", eqc_eyeq5_early_init); + +static void __init eqc_eyeq6h_central_early_init(struct device_node *np) +{ + eqc_early_init(np, &eqc_eyeq6h_central_early_match_data); +} +CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_central, "mobileye,eyeq6h-central-olb", + eqc_eyeq6h_central_early_init); + +static void __init eqc_eyeq6h_west_early_init(struct device_node *np) +{ + eqc_early_init(np, &eqc_eyeq6h_west_early_match_data); +} +CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_west, "mobileye,eyeq6h-west-olb", + eqc_eyeq6h_west_early_init); diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 8fba63fc70c554..e62ae8794d445f 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -241,6 +241,17 @@ struct clk_hw *clk_hw_register_fixed_factor_with_accuracy_fwname(struct device * } EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_with_accuracy_fwname); +struct clk_hw *clk_hw_register_fixed_factor_index(struct device *dev, + const char *name, unsigned int index, unsigned long flags, + unsigned int mult, unsigned int div) +{ + const struct clk_parent_data pdata = { .index = index }; + + return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, &pdata, + flags, mult, div, 0, 0, false); +} +EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_index); + struct clk *clk_register_fixed_factor(struct device *dev, const char *name, const char *parent_name, unsigned long flags, unsigned int mult, unsigned int div) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 5b114043771ddb..9099c57e27156c 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -17,13 +17,15 @@ #include #include #include +#include /** * DOC: basic gpio gated clock which can be enabled and disabled * with gpio output * Traits of this clock: - * prepare - clk_(un)prepare only ensures parent is (un)prepared - * enable - clk_enable and clk_disable are functional & control gpio + * prepare - clk_(un)prepare are functional and control a gpio that can sleep + * enable - clk_enable and clk_disable are functional & control + * non-sleeping gpio * rate - inherits rate from parent. No clk_set_rate support * parent - fixed parent. No clk_set_parent support */ @@ -199,7 +201,6 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) struct gpio_desc *gpiod; struct clk_hw *hw; bool is_mux; - int ret; is_mux = of_device_is_compatible(node, "gpio-mux-clock"); @@ -211,17 +212,9 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) gpio_name = is_mux ? "select" : "enable"; gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW); - if (IS_ERR(gpiod)) { - ret = PTR_ERR(gpiod); - if (ret == -EPROBE_DEFER) - pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n", - node, __func__); - else - pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n", - node, __func__, - gpio_name); - return ret; - } + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), + "Can't get '%s' named GPIO property\n", gpio_name); if (is_mux) hw = clk_hw_register_gpio_mux(dev, gpiod); @@ -247,3 +240,187 @@ static struct platform_driver gpio_clk_driver = { }, }; builtin_platform_driver(gpio_clk_driver); + +/** + * DOC: gated fixed clock, controlled with a gpio output and a regulator + * Traits of this clock: + * prepare - clk_prepare and clk_unprepare are function & control regulator + * optionally a gpio that can sleep + * enable - clk_enable and clk_disable are functional & control gpio + * rate - rate is fixed and set on clock registration + * parent - fixed clock is a root clock and has no parent + */ + +/** + * struct clk_gated_fixed - Gateable fixed rate clock + * @clk_gpio: instance of clk_gpio for gate-gpio + * @supply: supply regulator + * @rate: fixed rate + */ +struct clk_gated_fixed { + struct clk_gpio clk_gpio; + struct regulator *supply; + unsigned long rate; +}; + +#define to_clk_gated_fixed(_clk_gpio) container_of(_clk_gpio, struct clk_gated_fixed, clk_gpio) + +static unsigned long clk_gated_fixed_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return to_clk_gated_fixed(to_clk_gpio(hw))->rate; +} + +static int clk_gated_fixed_prepare(struct clk_hw *hw) +{ + struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); + + if (!clk->supply) + return 0; + + return regulator_enable(clk->supply); +} + +static void clk_gated_fixed_unprepare(struct clk_hw *hw) +{ + struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); + + if (!clk->supply) + return; + + regulator_disable(clk->supply); +} + +static int clk_gated_fixed_is_prepared(struct clk_hw *hw) +{ + struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw)); + + if (!clk->supply) + return true; + + return regulator_is_enabled(clk->supply); +} + +/* + * Fixed gated clock with non-sleeping gpio. + * + * Prepare operation turns on the supply regulator + * and the enable operation switches the enable-gpio. + */ +static const struct clk_ops clk_gated_fixed_ops = { + .prepare = clk_gated_fixed_prepare, + .unprepare = clk_gated_fixed_unprepare, + .is_prepared = clk_gated_fixed_is_prepared, + .enable = clk_gpio_gate_enable, + .disable = clk_gpio_gate_disable, + .is_enabled = clk_gpio_gate_is_enabled, + .recalc_rate = clk_gated_fixed_recalc_rate, +}; + +static int clk_sleeping_gated_fixed_prepare(struct clk_hw *hw) +{ + int ret; + + ret = clk_gated_fixed_prepare(hw); + if (ret) + return ret; + + ret = clk_sleeping_gpio_gate_prepare(hw); + if (ret) + clk_gated_fixed_unprepare(hw); + + return ret; +} + +static void clk_sleeping_gated_fixed_unprepare(struct clk_hw *hw) +{ + clk_gated_fixed_unprepare(hw); + clk_sleeping_gpio_gate_unprepare(hw); +} + +/* + * Fixed gated clock with non-sleeping gpio. + * + * Enabling the supply regulator and switching the enable-gpio happens + * both in the prepare step. + * is_prepared only needs to check the gpio state, as toggling the + * gpio is the last step when preparing. + */ +static const struct clk_ops clk_sleeping_gated_fixed_ops = { + .prepare = clk_sleeping_gated_fixed_prepare, + .unprepare = clk_sleeping_gated_fixed_unprepare, + .is_prepared = clk_sleeping_gpio_gate_is_prepared, + .recalc_rate = clk_gated_fixed_recalc_rate, +}; + +static int clk_gated_fixed_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct clk_gated_fixed *clk; + const struct clk_ops *ops; + const char *clk_name; + u32 rate; + int ret; + + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return -ENOMEM; + + ret = device_property_read_u32(dev, "clock-frequency", &rate); + if (ret) + return dev_err_probe(dev, ret, "Failed to get clock-frequency\n"); + clk->rate = rate; + + ret = device_property_read_string(dev, "clock-output-names", &clk_name); + if (ret) + clk_name = fwnode_get_name(dev->fwnode); + + clk->supply = devm_regulator_get_optional(dev, "vdd"); + if (IS_ERR(clk->supply)) { + if (PTR_ERR(clk->supply) != -ENODEV) + return dev_err_probe(dev, PTR_ERR(clk->supply), + "Failed to get regulator\n"); + clk->supply = NULL; + } + + clk->clk_gpio.gpiod = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(clk->clk_gpio.gpiod)) + return dev_err_probe(dev, PTR_ERR(clk->clk_gpio.gpiod), + "Failed to get gpio\n"); + + if (gpiod_cansleep(clk->clk_gpio.gpiod)) + ops = &clk_sleeping_gated_fixed_ops; + else + ops = &clk_gated_fixed_ops; + + clk->clk_gpio.hw.init = CLK_HW_INIT_NO_PARENT(clk_name, ops, 0); + + /* register the clock */ + ret = devm_clk_hw_register(dev, &clk->clk_gpio.hw); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register clock\n"); + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + &clk->clk_gpio.hw); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register clock provider\n"); + + return 0; +} + +static const struct of_device_id gated_fixed_clk_match_table[] = { + { .compatible = "gated-fixed-clock" }, + { /* sentinel */ } +}; + +static struct platform_driver gated_fixed_clk_driver = { + .probe = clk_gated_fixed_probe, + .driver = { + .name = "gated-fixed-clk", + .of_match_table = gated_fixed_clk_match_table, + }, +}; +builtin_platform_driver(gated_fixed_clk_driver); diff --git a/drivers/clk/clk-lan966x.c b/drivers/clk/clk-lan966x.c index 870fd7df50c1f0..16e0405fe28bf0 100644 --- a/drivers/clk/clk-lan966x.c +++ b/drivers/clk/clk-lan966x.c @@ -24,13 +24,20 @@ #define DIV_MAX 255 -static const char *clk_names[N_CLOCKS] = { +static const char * const lan966x_clk_names[] = { "qspi0", "qspi1", "qspi2", "sdmmc0", "pi", "mcan0", "mcan1", "flexcom0", "flexcom1", "flexcom2", "flexcom3", "flexcom4", "timer1", "usb_refclk", }; +static const char * const lan969x_clk_names[] = { + "qspi0", "qspi2", "sdmmc0", "sdmmc1", + "mcan0", "mcan1", "flexcom0", + "flexcom1", "flexcom2", "flexcom3", + "timer1", "usb_refclk", +}; + struct lan966x_gck { struct clk_hw hw; void __iomem *reg; @@ -53,7 +60,7 @@ struct clk_gate_soc_desc { int bit_idx; }; -static const struct clk_gate_soc_desc clk_gate_desc[] = { +static const struct clk_gate_soc_desc lan966x_clk_gate_desc[] = { { "uhphs", 11 }, { "udphs", 10 }, { "mcramc", 9 }, @@ -61,6 +68,37 @@ static const struct clk_gate_soc_desc clk_gate_desc[] = { { } }; +static const struct clk_gate_soc_desc lan969x_clk_gate_desc[] = { + { "usb_drd", 10 }, + { "mcramc", 9 }, + { "hmatrix", 8 }, + { } +}; + +struct lan966x_match_data { + char *name; + const char * const *clk_name; + const struct clk_gate_soc_desc *clk_gate_desc; + u8 num_generic_clks; + u8 num_total_clks; +}; + +static struct lan966x_match_data lan966x_desc = { + .name = "lan966x", + .clk_name = lan966x_clk_names, + .clk_gate_desc = lan966x_clk_gate_desc, + .num_total_clks = 18, + .num_generic_clks = 14, +}; + +static struct lan966x_match_data lan969x_desc = { + .name = "lan969x", + .clk_name = lan969x_clk_names, + .clk_gate_desc = lan969x_clk_gate_desc, + .num_total_clks = 15, + .num_generic_clks = 12, +}; + static DEFINE_SPINLOCK(clk_gate_lock); static void __iomem *base; @@ -186,24 +224,26 @@ static struct clk_hw *lan966x_gck_clk_register(struct device *dev, int i) }; static int lan966x_gate_clk_register(struct device *dev, + const struct lan966x_match_data *data, struct clk_hw_onecell_data *hw_data, void __iomem *gate_base) { - int i; + for (int i = data->num_generic_clks; i < data->num_total_clks; ++i) { + int idx = i - data->num_generic_clks; + const struct clk_gate_soc_desc *desc; - for (i = GCK_GATE_UHPHS; i < N_CLOCKS; ++i) { - int idx = i - GCK_GATE_UHPHS; + desc = &data->clk_gate_desc[idx]; hw_data->hws[i] = - devm_clk_hw_register_gate(dev, clk_gate_desc[idx].name, - "lan966x", 0, gate_base, - clk_gate_desc[idx].bit_idx, + devm_clk_hw_register_gate(dev, desc->name, + data->name, 0, gate_base, + desc->bit_idx, 0, &clk_gate_lock); if (IS_ERR(hw_data->hws[i])) return dev_err_probe(dev, PTR_ERR(hw_data->hws[i]), "failed to register %s clock\n", - clk_gate_desc[idx].name); + desc->name); } return 0; @@ -211,13 +251,18 @@ static int lan966x_gate_clk_register(struct device *dev, static int lan966x_clk_probe(struct platform_device *pdev) { + const struct lan966x_match_data *data; struct clk_hw_onecell_data *hw_data; struct device *dev = &pdev->dev; void __iomem *gate_base; struct resource *res; int i, ret; - hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, N_CLOCKS), + data = device_get_match_data(dev); + if (!data) + return -EINVAL; + + hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, data->num_total_clks), GFP_KERNEL); if (!hw_data) return -ENOMEM; @@ -228,10 +273,10 @@ static int lan966x_clk_probe(struct platform_device *pdev) init.ops = &lan966x_gck_ops; - hw_data->num = GCK_GATE_UHPHS; + hw_data->num = data->num_generic_clks; - for (i = 0; i < GCK_GATE_UHPHS; i++) { - init.name = clk_names[i]; + for (i = 0; i < data->num_generic_clks; i++) { + init.name = data->clk_name[i]; hw_data->hws[i] = lan966x_gck_clk_register(dev, i); if (IS_ERR(hw_data->hws[i])) { dev_err(dev, "failed to register %s clock\n", @@ -246,9 +291,9 @@ static int lan966x_clk_probe(struct platform_device *pdev) if (IS_ERR(gate_base)) return PTR_ERR(gate_base); - hw_data->num = N_CLOCKS; + hw_data->num = data->num_total_clks; - ret = lan966x_gate_clk_register(dev, hw_data, gate_base); + ret = lan966x_gate_clk_register(dev, data, hw_data, gate_base); if (ret) return ret; } @@ -257,7 +302,8 @@ static int lan966x_clk_probe(struct platform_device *pdev) } static const struct of_device_id lan966x_clk_dt_ids[] = { - { .compatible = "microchip,lan966x-gck", }, + { .compatible = "microchip,lan966x-gck", .data = &lan966x_desc }, + { .compatible = "microchip,lan9691-gck", .data = &lan969x_desc }, { } }; MODULE_DEVICE_TABLE(of, lan966x_clk_dt_ids); diff --git a/drivers/clk/clk-loongson2.c b/drivers/clk/clk-loongson2.c index 820bb1e9e3b79a..7082b4309c6f15 100644 --- a/drivers/clk/clk-loongson2.c +++ b/drivers/clk/clk-loongson2.c @@ -29,8 +29,10 @@ enum loongson2_clk_type { struct loongson2_clk_provider { void __iomem *base; struct device *dev; - struct clk_hw_onecell_data clk_data; spinlock_t clk_lock; /* protect access to DIV registers */ + + /* Must be last --ends in a flexible-array member. */ + struct clk_hw_onecell_data clk_data; }; struct loongson2_clk_data { @@ -304,7 +306,7 @@ static int loongson2_clk_probe(struct platform_device *pdev) return PTR_ERR(clp->base); spin_lock_init(&clp->clk_lock); - clp->clk_data.num = clks_num + 1; + clp->clk_data.num = clks_num; clp->dev = dev; for (i = 0; i < clks_num; i++) { diff --git a/drivers/clk/clk-npcm8xx.c b/drivers/clk/clk-npcm8xx.c new file mode 100644 index 00000000000000..2138c011411d28 --- /dev/null +++ b/drivers/clk/clk-npcm8xx.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Nuvoton NPCM8xx Clock Generator + * All the clocks are initialized by the bootloader, so this driver allows only + * reading of current settings directly from the hardware. + * + * Copyright (C) 2020 Nuvoton Technologies + * Author: Tomer Maimon + */ + +#define pr_fmt(fmt) "npcm8xx_clk: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* npcm8xx clock registers*/ +#define NPCM8XX_CLKSEL 0x04 +#define NPCM8XX_CLKDIV1 0x08 +#define NPCM8XX_CLKDIV2 0x2C +#define NPCM8XX_CLKDIV3 0x58 +#define NPCM8XX_CLKDIV4 0x7C +#define NPCM8XX_PLLCON0 0x0C +#define NPCM8XX_PLLCON1 0x10 +#define NPCM8XX_PLLCON2 0x54 +#define NPCM8XX_PLLCONG 0x60 +#define NPCM8XX_THRTL_CNT 0xC0 + +#define PLLCON_LOKI BIT(31) +#define PLLCON_LOKS BIT(30) +#define PLLCON_FBDV GENMASK(27, 16) +#define PLLCON_OTDV2 GENMASK(15, 13) +#define PLLCON_PWDEN BIT(12) +#define PLLCON_OTDV1 GENMASK(10, 8) +#define PLLCON_INDV GENMASK(5, 0) + +static void __iomem *clk_base; + +struct npcm8xx_clk_pll { + void __iomem *pllcon; + unsigned int id; + const char *name; + unsigned long flags; + struct clk_hw hw; +}; + +#define to_npcm8xx_clk_pll(_hw) container_of(_hw, struct npcm8xx_clk_pll, hw) + +struct npcm8xx_clk_pll_data { + const char *name; + struct clk_parent_data parent; + unsigned int reg; + unsigned long flags; + struct clk_hw hw; +}; + +struct npcm8xx_clk_div_data { + u32 reg; + u8 shift; + u8 width; + const char *name; + const struct clk_hw *parent_hw; + unsigned long clk_divider_flags; + unsigned long flags; + int onecell_idx; + struct clk_hw hw; +}; + +struct npcm8xx_clk_mux_data { + u8 shift; + u32 mask; + const u32 *table; + const char *name; + const struct clk_parent_data *parent_data; + u8 num_parents; + unsigned long flags; + struct clk_hw hw; +}; + +static struct clk_hw hw_pll1_div2, hw_pll2_div2, hw_gfx_div2, hw_pre_clk; +static struct npcm8xx_clk_pll_data npcm8xx_pll_clks[] = { + { "pll0", { .index = 0 }, NPCM8XX_PLLCON0, 0 }, + { "pll1", { .index = 0 }, NPCM8XX_PLLCON1, 0 }, + { "pll2", { .index = 0 }, NPCM8XX_PLLCON2, 0 }, + { "pll_gfx", { .index = 0 }, NPCM8XX_PLLCONG, 0 }, +}; + +static const u32 cpuck_mux_table[] = { 0, 1, 2, 7 }; +static const struct clk_parent_data cpuck_mux_parents[] = { + { .hw = &npcm8xx_pll_clks[0].hw }, + { .hw = &npcm8xx_pll_clks[1].hw }, + { .index = 0 }, + { .hw = &npcm8xx_pll_clks[2].hw } +}; + +static const u32 pixcksel_mux_table[] = { 0, 2 }; +static const struct clk_parent_data pixcksel_mux_parents[] = { + { .hw = &npcm8xx_pll_clks[3].hw }, + { .index = 0 } +}; + +static const u32 default_mux_table[] = { 0, 1, 2, 3 }; +static const struct clk_parent_data default_mux_parents[] = { + { .hw = &npcm8xx_pll_clks[0].hw }, + { .hw = &npcm8xx_pll_clks[1].hw }, + { .index = 0 }, + { .hw = &hw_pll2_div2 } +}; + +static const u32 sucksel_mux_table[] = { 2, 3 }; +static const struct clk_parent_data sucksel_mux_parents[] = { + { .index = 0 }, + { .hw = &hw_pll2_div2 } +}; + +static const u32 mccksel_mux_table[] = { 0, 2 }; +static const struct clk_parent_data mccksel_mux_parents[] = { + { .hw = &hw_pll1_div2 }, + { .index = 0 } +}; + +static const u32 clkoutsel_mux_table[] = { 0, 1, 2, 3, 4 }; +static const struct clk_parent_data clkoutsel_mux_parents[] = { + { .hw = &npcm8xx_pll_clks[0].hw }, + { .hw = &npcm8xx_pll_clks[1].hw }, + { .index = 0 }, + { .hw = &hw_gfx_div2 }, + { .hw = &hw_pll2_div2 } +}; + +static const u32 gfxmsel_mux_table[] = { 2, 3 }; +static const struct clk_parent_data gfxmsel_mux_parents[] = { + { .index = 0 }, + { .hw = &npcm8xx_pll_clks[2].hw } +}; + +static const u32 dvcssel_mux_table[] = { 2, 3 }; +static const struct clk_parent_data dvcssel_mux_parents[] = { + { .index = 0 }, + { .hw = &npcm8xx_pll_clks[2].hw } +}; + +static const u32 default3_mux_table[] = { 0, 1, 2 }; +static const struct clk_parent_data default3_mux_parents[] = { + { .hw = &npcm8xx_pll_clks[0].hw }, + { .hw = &npcm8xx_pll_clks[1].hw }, + { .index = 0 } +}; + +static struct npcm8xx_clk_mux_data npcm8xx_muxes[] = { + { 0, 3, cpuck_mux_table, "cpu_mux", cpuck_mux_parents, + ARRAY_SIZE(cpuck_mux_parents), CLK_IS_CRITICAL }, + { 4, 2, pixcksel_mux_table, "gfx_pixel_mux", pixcksel_mux_parents, + ARRAY_SIZE(pixcksel_mux_parents), 0 }, + { 6, 2, default_mux_table, "sd_mux", default_mux_parents, + ARRAY_SIZE(default_mux_parents), 0 }, + { 8, 2, default_mux_table, "uart_mux", default_mux_parents, + ARRAY_SIZE(default_mux_parents), 0 }, + { 10, 2, sucksel_mux_table, "serial_usb_mux", sucksel_mux_parents, + ARRAY_SIZE(sucksel_mux_parents), 0 }, + { 12, 2, mccksel_mux_table, "mc_mux", mccksel_mux_parents, + ARRAY_SIZE(mccksel_mux_parents), 0 }, + { 14, 2, default_mux_table, "adc_mux", default_mux_parents, + ARRAY_SIZE(default_mux_parents), 0 }, + { 16, 2, default_mux_table, "gfx_mux", default_mux_parents, + ARRAY_SIZE(default_mux_parents), 0 }, + { 18, 3, clkoutsel_mux_table, "clkout_mux", clkoutsel_mux_parents, + ARRAY_SIZE(clkoutsel_mux_parents), 0 }, + { 21, 2, gfxmsel_mux_table, "gfxm_mux", gfxmsel_mux_parents, + ARRAY_SIZE(gfxmsel_mux_parents), 0 }, + { 23, 2, dvcssel_mux_table, "dvc_mux", dvcssel_mux_parents, + ARRAY_SIZE(dvcssel_mux_parents), 0 }, + { 25, 2, default3_mux_table, "rg_mux", default3_mux_parents, + ARRAY_SIZE(default3_mux_parents), 0 }, + { 27, 2, default3_mux_table, "rcp_mux", default3_mux_parents, + ARRAY_SIZE(default3_mux_parents), 0 }, +}; + +/* configurable pre dividers: */ +static struct npcm8xx_clk_div_data npcm8xx_pre_divs[] = { + { NPCM8XX_CLKDIV1, 21, 5, "pre_adc", &npcm8xx_muxes[6].hw, CLK_DIVIDER_READ_ONLY, 0, -1 }, + { NPCM8XX_CLKDIV1, 26, 2, "ahb", &hw_pre_clk, CLK_DIVIDER_READ_ONLY, CLK_IS_CRITICAL, NPCM8XX_CLK_AHB }, +}; + +/* configurable dividers: */ +static struct npcm8xx_clk_div_data npcm8xx_divs[] = { + { NPCM8XX_CLKDIV1, 28, 3, "adc", &npcm8xx_pre_divs[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_ADC }, + { NPCM8XX_CLKDIV1, 16, 5, "uart", &npcm8xx_muxes[3].hw, 0, 0, NPCM8XX_CLK_UART }, + { NPCM8XX_CLKDIV1, 11, 5, "mmc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_MMC }, + { NPCM8XX_CLKDIV1, 6, 5, "spi3", &npcm8xx_pre_divs[1].hw, 0, 0, NPCM8XX_CLK_SPI3 }, + { NPCM8XX_CLKDIV1, 2, 4, "pci", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_PCI }, + + { NPCM8XX_CLKDIV2, 30, 2, "apb4", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB4 }, + { NPCM8XX_CLKDIV2, 28, 2, "apb3", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB3 }, + { NPCM8XX_CLKDIV2, 26, 2, "apb2", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB2 }, + { NPCM8XX_CLKDIV2, 24, 2, "apb1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB1 }, + { NPCM8XX_CLKDIV2, 22, 2, "apb5", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB5 }, + { NPCM8XX_CLKDIV2, 16, 5, "clkout", &npcm8xx_muxes[8].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_CLKOUT }, + { NPCM8XX_CLKDIV2, 13, 3, "gfx", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_GFX }, + { NPCM8XX_CLKDIV2, 8, 5, "usb_bridge", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU }, + { NPCM8XX_CLKDIV2, 4, 4, "usb_host", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU48 }, + { NPCM8XX_CLKDIV2, 0, 4, "sdhc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SDHC }, + + { NPCM8XX_CLKDIV3, 16, 8, "spi1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI1 }, + { NPCM8XX_CLKDIV3, 11, 5, "uart2", &npcm8xx_muxes[3].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_UART2 }, + { NPCM8XX_CLKDIV3, 6, 5, "spi0", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI0 }, + { NPCM8XX_CLKDIV3, 1, 5, "spix", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPIX }, + + { NPCM8XX_CLKDIV4, 28, 4, "rg", &npcm8xx_muxes[11].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RG }, + { NPCM8XX_CLKDIV4, 12, 4, "rcp", &npcm8xx_muxes[12].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RCP }, + + { NPCM8XX_THRTL_CNT, 0, 2, "th", &npcm8xx_muxes[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_TH }, +}; + +static unsigned long npcm8xx_clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct npcm8xx_clk_pll *pll = to_npcm8xx_clk_pll(hw); + unsigned long fbdv, indv, otdv1, otdv2; + unsigned int val; + u64 ret; + + if (parent_rate == 0) { + pr_debug("%s: parent rate is zero\n", __func__); + return 0; + } + + val = readl_relaxed(pll->pllcon); + + indv = FIELD_GET(PLLCON_INDV, val); + fbdv = FIELD_GET(PLLCON_FBDV, val); + otdv1 = FIELD_GET(PLLCON_OTDV1, val); + otdv2 = FIELD_GET(PLLCON_OTDV2, val); + + ret = (u64)parent_rate * fbdv; + do_div(ret, indv * otdv1 * otdv2); + + return ret; +} + +static const struct clk_ops npcm8xx_clk_pll_ops = { + .recalc_rate = npcm8xx_clk_pll_recalc_rate, +}; + +static struct clk_hw * +npcm8xx_clk_register_pll(struct device *dev, void __iomem *pllcon, + const char *name, const struct clk_parent_data *parent, + unsigned long flags) +{ + struct npcm8xx_clk_pll *pll; + struct clk_init_data init = {}; + int ret; + + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &npcm8xx_clk_pll_ops; + init.parent_data = parent; + init.num_parents = 1; + init.flags = flags; + + pll->pllcon = pllcon; + pll->hw.init = &init; + + ret = devm_clk_hw_register(dev, &pll->hw); + if (ret) + return ERR_PTR(ret); + + return &pll->hw; +} + +static DEFINE_SPINLOCK(npcm8xx_clk_lock); + +static int npcm8xx_clk_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct npcm_clock_adev *rdev = to_npcm_clock_adev(adev); + struct clk_hw_onecell_data *npcm8xx_clk_data; + struct device *dev = &adev->dev; + struct clk_hw *hw; + unsigned int i; + + npcm8xx_clk_data = devm_kzalloc(dev, struct_size(npcm8xx_clk_data, hws, + NPCM8XX_NUM_CLOCKS), + GFP_KERNEL); + if (!npcm8xx_clk_data) + return -ENOMEM; + + clk_base = rdev->base; + + npcm8xx_clk_data->num = NPCM8XX_NUM_CLOCKS; + + for (i = 0; i < NPCM8XX_NUM_CLOCKS; i++) + npcm8xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); + + /* Register plls */ + for (i = 0; i < ARRAY_SIZE(npcm8xx_pll_clks); i++) { + struct npcm8xx_clk_pll_data *pll_clk = &npcm8xx_pll_clks[i]; + + hw = npcm8xx_clk_register_pll(dev, clk_base + pll_clk->reg, + pll_clk->name, &pll_clk->parent, + pll_clk->flags); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll\n"); + pll_clk->hw = *hw; + } + + /* Register fixed dividers */ + hw = devm_clk_hw_register_fixed_factor(dev, "pll1_div2", "pll1", 0, 1, 2); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register fixed div\n"); + hw_pll1_div2 = *hw; + + hw = devm_clk_hw_register_fixed_factor(dev, "pll2_div2", "pll2", 0, 1, 2); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll2 div2\n"); + hw_pll2_div2 = *hw; + + hw = devm_clk_hw_register_fixed_factor(dev, "pll_gfx_div2", "pll_gfx", 0, 1, 2); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register gfx div2\n"); + hw_gfx_div2 = *hw; + + /* Register muxes */ + for (i = 0; i < ARRAY_SIZE(npcm8xx_muxes); i++) { + struct npcm8xx_clk_mux_data *mux_data = &npcm8xx_muxes[i]; + + hw = devm_clk_hw_register_mux_parent_data_table(dev, + mux_data->name, + mux_data->parent_data, + mux_data->num_parents, + mux_data->flags, + clk_base + NPCM8XX_CLKSEL, + mux_data->shift, + mux_data->mask, + 0, + mux_data->table, + &npcm8xx_clk_lock); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register mux\n"); + mux_data->hw = *hw; + } + + hw = devm_clk_hw_register_fixed_factor(dev, "pre_clk", "cpu_mux", 0, 1, 2); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre clk div2\n"); + hw_pre_clk = *hw; + + hw = devm_clk_hw_register_fixed_factor(dev, "axi", "th", 0, 1, 2); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register axi div2\n"); + npcm8xx_clk_data->hws[NPCM8XX_CLK_AXI] = hw; + + hw = devm_clk_hw_register_fixed_factor(dev, "atb", "axi", 0, 1, 2); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register atb div2\n"); + npcm8xx_clk_data->hws[NPCM8XX_CLK_ATB] = hw; + + /* Register pre dividers */ + for (i = 0; i < ARRAY_SIZE(npcm8xx_pre_divs); i++) { + struct npcm8xx_clk_div_data *div_data = &npcm8xx_pre_divs[i]; + + hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name, + div_data->parent_hw, + div_data->flags, + clk_base + div_data->reg, + div_data->shift, + div_data->width, + div_data->clk_divider_flags, + &npcm8xx_clk_lock); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre div\n"); + div_data->hw = *hw; + + if (div_data->onecell_idx >= 0) + npcm8xx_clk_data->hws[div_data->onecell_idx] = hw; + } + + /* Register dividers */ + for (i = 0; i < ARRAY_SIZE(npcm8xx_divs); i++) { + struct npcm8xx_clk_div_data *div_data = &npcm8xx_divs[i]; + + hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name, + div_data->parent_hw, + div_data->flags, + clk_base + div_data->reg, + div_data->shift, + div_data->width, + div_data->clk_divider_flags, + &npcm8xx_clk_lock); + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Can't register div\n"); + + if (div_data->onecell_idx >= 0) + npcm8xx_clk_data->hws[div_data->onecell_idx] = hw; + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + npcm8xx_clk_data); +} + +static const struct auxiliary_device_id npcm8xx_clock_ids[] = { + { + .name = "reset_npcm.clk-npcm8xx", + }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, npcm8xx_clock_ids); + +static struct auxiliary_driver npcm8xx_clock_driver = { + .probe = npcm8xx_clk_probe, + .id_table = npcm8xx_clock_ids, +}; +module_auxiliary_driver(npcm8xx_clock_driver); + +MODULE_DESCRIPTION("Clock driver for Nuvoton NPCM8XX BMC SoC"); +MODULE_AUTHOR("Tomer Maimon "); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 4dcde305944c45..a560edeb4b55a5 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -1065,11 +1066,8 @@ static void __init _clockgen_init(struct device_node *np, bool legacy); static void __init legacy_init_clockgen(struct device_node *np) { if (!clockgen.node) { - struct device_node *parent_np; - - parent_np = of_get_parent(np); + struct device_node *parent_np __free(device_node) = of_get_parent(np); _clockgen_init(parent_np, true); - of_node_put(parent_np); } } diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index 6ee148e5469dc1..1127c35ce57d70 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -371,7 +371,7 @@ static int si514_probe(struct i2c_client *client) } static const struct i2c_device_id si514_id[] = { - { "si514", 0 }, + { "si514" }, { } }; MODULE_DEVICE_TABLE(i2c, si514_id); diff --git a/drivers/clk/clk-twl.c b/drivers/clk/clk-twl.c index eab9d3c8ed8aee..20bc3bf8fd62d3 100644 --- a/drivers/clk/clk-twl.c +++ b/drivers/clk/clk-twl.c @@ -11,13 +11,29 @@ #include #include -#define VREG_STATE 2 +#define VREG_STATE 2 +#define VREG_GRP 0 #define TWL6030_CFG_STATE_OFF 0x00 #define TWL6030_CFG_STATE_ON 0x01 #define TWL6030_CFG_STATE_MASK 0x03 +#define TWL6030_CFG_STATE_GRP_SHIFT 5 +#define TWL6030_CFG_STATE_APP_SHIFT 2 +#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT) +#define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ + TWL6030_CFG_STATE_APP_SHIFT) +#define P1_GRP BIT(0) /* processor power group */ +#define P2_GRP BIT(1) +#define P3_GRP BIT(2) +#define ALL_GRP (P1_GRP | P2_GRP | P3_GRP) + +enum twl_type { + TWL_TYPE_6030, + TWL_TYPE_6032, +}; struct twl_clock_info { struct device *dev; + enum twl_type type; u8 base; struct clk_hw hw; }; @@ -56,14 +72,21 @@ static unsigned long twl_clks_recalc_rate(struct clk_hw *hw, static int twl6032_clks_prepare(struct clk_hw *hw) { struct twl_clock_info *cinfo = to_twl_clks_info(hw); - int ret; - ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE, - TWL6030_CFG_STATE_ON); - if (ret < 0) - dev_err(cinfo->dev, "clk prepare failed\n"); + if (cinfo->type == TWL_TYPE_6030) { + int grp; + + grp = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_GRP); + if (grp < 0) + return grp; - return ret; + return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE, + grp << TWL6030_CFG_STATE_GRP_SHIFT | + TWL6030_CFG_STATE_ON); + } + + return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE, + TWL6030_CFG_STATE_ON); } static void twl6032_clks_unprepare(struct clk_hw *hw) @@ -71,32 +94,21 @@ static void twl6032_clks_unprepare(struct clk_hw *hw) struct twl_clock_info *cinfo = to_twl_clks_info(hw); int ret; - ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE, - TWL6030_CFG_STATE_OFF); + if (cinfo->type == TWL_TYPE_6030) + ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE, + ALL_GRP << TWL6030_CFG_STATE_GRP_SHIFT | + TWL6030_CFG_STATE_OFF); + else + ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE, + TWL6030_CFG_STATE_OFF); + if (ret < 0) dev_err(cinfo->dev, "clk unprepare failed\n"); } -static int twl6032_clks_is_prepared(struct clk_hw *hw) -{ - struct twl_clock_info *cinfo = to_twl_clks_info(hw); - int val; - - val = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE); - if (val < 0) { - dev_err(cinfo->dev, "clk read failed\n"); - return val; - } - - val &= TWL6030_CFG_STATE_MASK; - - return val == TWL6030_CFG_STATE_ON; -} - static const struct clk_ops twl6032_clks_ops = { .prepare = twl6032_clks_prepare, .unprepare = twl6032_clks_unprepare, - .is_prepared = twl6032_clks_is_prepared, .recalc_rate = twl_clks_recalc_rate, }; @@ -155,6 +167,7 @@ static int twl_clks_probe(struct platform_device *pdev) for (i = 0; i < count; i++) { cinfo[i].base = hw_data[i].base; cinfo[i].dev = &pdev->dev; + cinfo[i].type = platform_get_device_id(pdev)->driver_data; cinfo[i].hw.init = &hw_data[i].init; ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw); if (ret) { @@ -176,7 +189,11 @@ static int twl_clks_probe(struct platform_device *pdev) static const struct platform_device_id twl_clks_id[] = { { + .name = "twl6030-clk", + .driver_data = TWL_TYPE_6030, + }, { .name = "twl6032-clk", + .driver_data = TWL_TYPE_6032, }, { /* sentinel */ } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d02451f951cf05..9b45fa005030f5 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -608,12 +608,6 @@ bool clk_hw_is_prepared(const struct clk_hw *hw) } EXPORT_SYMBOL_GPL(clk_hw_is_prepared); -bool clk_hw_rate_is_protected(const struct clk_hw *hw) -{ - return clk_core_rate_is_protected(hw->core); -} -EXPORT_SYMBOL_GPL(clk_hw_rate_is_protected); - bool clk_hw_is_enabled(const struct clk_hw *hw) { return clk_core_is_enabled(hw->core); diff --git a/drivers/clk/clk_kunit_helpers.c b/drivers/clk/clk_kunit_helpers.c index 52fd25594c9607..68a28e70bb61cd 100644 --- a/drivers/clk/clk_kunit_helpers.c +++ b/drivers/clk/clk_kunit_helpers.c @@ -203,5 +203,35 @@ int of_clk_hw_register_kunit(struct kunit *test, struct device_node *node, struc } EXPORT_SYMBOL_GPL(of_clk_hw_register_kunit); +KUNIT_DEFINE_ACTION_WRAPPER(of_clk_del_provider_wrapper, + of_clk_del_provider, struct device_node *); + +/** + * of_clk_add_hw_provider_kunit() - Test managed of_clk_add_hw_provider() + * @test: The test context + * @np: Device node pointer associated with clock provider + * @get: Callback for decoding clk_hw + * @data: Context pointer for @get callback. + * + * Just like of_clk_add_hw_provider(), except the clk_hw provider is managed by + * the test case and is automatically unregistered after the test case + * concludes. + * + * Return: 0 on success or a negative errno value on failure. + */ +int of_clk_add_hw_provider_kunit(struct kunit *test, struct device_node *np, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, void *data), + void *data) +{ + int ret; + + ret = of_clk_add_hw_provider(np, get, data); + if (ret) + return ret; + + return kunit_add_action_or_reset(test, of_clk_del_provider_wrapper, np); +} +EXPORT_SYMBOL_GPL(of_clk_add_hw_provider_kunit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("KUnit helpers for clk providers and consumers"); diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index aa3ddcfc00eba0..f08feeaa3750bc 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include @@ -15,6 +16,7 @@ #include #include +#include "kunit_clk_assigned_rates.h" #include "clk_parent_data_test.h" static const struct clk_ops empty_clk_ops = { }; @@ -3075,7 +3077,326 @@ static struct kunit_suite clk_register_clk_parent_data_device_suite = { .test_cases = clk_register_clk_parent_data_device_test_cases, }; +struct clk_assigned_rates_context { + struct clk_dummy_context clk0; + struct clk_dummy_context clk1; +}; + +/* + * struct clk_assigned_rates_test_param - Test parameters for clk_assigned_rates test + * @desc: Test description + * @overlay_begin: Pointer to start of DT overlay to apply for test + * @overlay_end: Pointer to end of DT overlay to apply for test + * @rate0: Initial rate of first clk + * @rate1: Initial rate of second clk + * @consumer_test: true if a consumer is being tested + */ +struct clk_assigned_rates_test_param { + const char *desc; + u8 *overlay_begin; + u8 *overlay_end; + unsigned long rate0; + unsigned long rate1; + bool consumer_test; +}; + +#define TEST_PARAM_OVERLAY(overlay_name) \ + .overlay_begin = of_overlay_begin(overlay_name), \ + .overlay_end = of_overlay_end(overlay_name) + +static void +clk_assigned_rates_register_clk(struct kunit *test, + struct clk_dummy_context *ctx, + struct device_node *np, const char *name, + unsigned long rate) +{ + struct clk_init_data init = { }; + + init.name = name; + init.ops = &clk_dummy_rate_ops; + ctx->hw.init = &init; + ctx->rate = rate; + + KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, np, &ctx->hw)); + KUNIT_ASSERT_EQ(test, ctx->rate, rate); +} + +/* + * Does most of the work of the test: + * + * 1. Apply the overlay to test + * 2. Register the clk or clks to test + * 3. Register the clk provider + * 4. Apply clk defaults to the consumer device if this is a consumer test + * + * The tests will set different test_param values to test different scenarios + * and validate that in their test functions. + */ +static int clk_assigned_rates_test_init(struct kunit *test) +{ + struct device_node *np, *consumer; + struct clk_hw_onecell_data *data; + struct clk_assigned_rates_context *ctx; + u32 clk_cells; + const struct clk_assigned_rates_test_param *test_param; + + test_param = test->param_value; + + KUNIT_ASSERT_EQ(test, 0, __of_overlay_apply_kunit(test, + test_param->overlay_begin, + test_param->overlay_end)); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL)); + test->priv = ctx; + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, + np = of_find_compatible_node(NULL, NULL, "test,clk-assigned-rates")); + of_node_put_kunit(test, np); + + KUNIT_ASSERT_EQ(test, 0, of_property_read_u32(np, "#clock-cells", &clk_cells)); + /* Only support #clock-cells = <0> or <1> */ + KUNIT_ASSERT_LT(test, clk_cells, 2); + + clk_assigned_rates_register_clk(test, &ctx->clk0, np, + "test_assigned_rate0", test_param->rate0); + if (clk_cells == 0) { + KUNIT_ASSERT_EQ(test, 0, + of_clk_add_hw_provider_kunit(test, np, of_clk_hw_simple_get, + &ctx->clk0.hw)); + } else if (clk_cells == 1) { + clk_assigned_rates_register_clk(test, &ctx->clk1, np, + "test_assigned_rate1", test_param->rate1); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, + data = kunit_kzalloc(test, struct_size(data, hws, 2), GFP_KERNEL)); + data->num = 2; + data->hws[0] = &ctx->clk0.hw; + data->hws[1] = &ctx->clk1.hw; + + KUNIT_ASSERT_EQ(test, 0, + of_clk_add_hw_provider_kunit(test, np, of_clk_hw_onecell_get, data)); + } + + /* Consumers are optional */ + if (test_param->consumer_test) { + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, + consumer = of_find_compatible_node(NULL, NULL, "test,clk-consumer")); + of_node_put_kunit(test, consumer); + + KUNIT_ASSERT_EQ(test, 0, of_clk_set_defaults(consumer, false)); + } + + return 0; +} + +static void clk_assigned_rates_assigns_one(struct kunit *test) +{ + struct clk_assigned_rates_context *ctx = test->priv; + + KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE); +} + +static void clk_assigned_rates_assigns_multiple(struct kunit *test) +{ + struct clk_assigned_rates_context *ctx = test->priv; + + KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE); + KUNIT_EXPECT_EQ(test, ctx->clk1.rate, ASSIGNED_RATES_1_RATE); +} + +static void clk_assigned_rates_skips(struct kunit *test) +{ + struct clk_assigned_rates_context *ctx = test->priv; + const struct clk_assigned_rates_test_param *test_param = test->param_value; + + KUNIT_EXPECT_NE(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE); + KUNIT_EXPECT_EQ(test, ctx->clk0.rate, test_param->rate0); +} + +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one_consumer); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one_consumer); + +/* Test cases that assign one rate */ +static const struct clk_assigned_rates_test_param clk_assigned_rates_assigns_one_test_params[] = { + { + /* + * Test that a single cell assigned-clock-rates property + * assigns the rate when the property is in the provider. + */ + .desc = "provider assigns", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_one), + }, + { + /* + * Test that a single cell assigned-clock-rates property + * assigns the rate when the property is in the consumer. + */ + .desc = "consumer assigns", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_one_consumer), + .consumer_test = true, + }, + { + /* + * Test that a single cell assigned-clock-rates-u64 property + * assigns the rate when the property is in the provider. + */ + .desc = "provider assigns u64", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_one), + }, + { + /* + * Test that a single cell assigned-clock-rates-u64 property + * assigns the rate when the property is in the consumer. + */ + .desc = "consumer assigns u64", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_one_consumer), + .consumer_test = true, + }, +}; +KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_assigns_one, + clk_assigned_rates_assigns_one_test_params, desc) + +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_multiple); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_multiple_consumer); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_multiple); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_multiple_consumer); + +/* Test cases that assign multiple rates */ +static const struct clk_assigned_rates_test_param clk_assigned_rates_assigns_multiple_test_params[] = { + { + /* + * Test that a multiple cell assigned-clock-rates property + * assigns the rates when the property is in the provider. + */ + .desc = "provider assigns", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_multiple), + }, + { + /* + * Test that a multiple cell assigned-clock-rates property + * assigns the rates when the property is in the consumer. + */ + .desc = "consumer assigns", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_multiple_consumer), + .consumer_test = true, + }, + { + /* + * Test that a single cell assigned-clock-rates-u64 property + * assigns the rate when the property is in the provider. + */ + .desc = "provider assigns u64", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_multiple), + }, + { + /* + * Test that a multiple cell assigned-clock-rates-u64 property + * assigns the rates when the property is in the consumer. + */ + .desc = "consumer assigns u64", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_multiple_consumer), + .consumer_test = true, + }, +}; +KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_assigns_multiple, + clk_assigned_rates_assigns_multiple_test_params, + desc) + +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_without); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_without_consumer); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_zero); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_zero_consumer); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_null); +OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_null_consumer); + +/* Test cases that skip changing the rate due to malformed DT */ +static const struct clk_assigned_rates_test_param clk_assigned_rates_skips_test_params[] = { + { + /* + * Test that an assigned-clock-rates property without an assigned-clocks + * property fails when the property is in the provider. + */ + .desc = "provider missing assigned-clocks", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_without), + .rate0 = 3000, + }, + { + /* + * Test that an assigned-clock-rates property without an assigned-clocks + * property fails when the property is in the consumer. + */ + .desc = "consumer missing assigned-clocks", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_without_consumer), + .rate0 = 3000, + .consumer_test = true, + }, + { + /* + * Test that an assigned-clock-rates property of zero doesn't + * set a rate when the property is in the provider. + */ + .desc = "provider assigned-clock-rates of zero", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_zero), + .rate0 = 3000, + }, + { + /* + * Test that an assigned-clock-rates property of zero doesn't + * set a rate when the property is in the consumer. + */ + .desc = "consumer assigned-clock-rates of zero", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_zero_consumer), + .rate0 = 3000, + .consumer_test = true, + }, + { + /* + * Test that an assigned-clocks property with a null phandle + * doesn't set a rate when the property is in the provider. + */ + .desc = "provider assigned-clocks null phandle", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_null), + .rate0 = 3000, + }, + { + /* + * Test that an assigned-clocks property with a null phandle + * doesn't set a rate when the property is in the consumer. + */ + .desc = "provider assigned-clocks null phandle", + TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_null_consumer), + .rate0 = 3000, + .consumer_test = true, + }, +}; +KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_skips, + clk_assigned_rates_skips_test_params, + desc) + +static struct kunit_case clk_assigned_rates_test_cases[] = { + KUNIT_CASE_PARAM(clk_assigned_rates_assigns_one, + clk_assigned_rates_assigns_one_gen_params), + KUNIT_CASE_PARAM(clk_assigned_rates_assigns_multiple, + clk_assigned_rates_assigns_multiple_gen_params), + KUNIT_CASE_PARAM(clk_assigned_rates_skips, + clk_assigned_rates_skips_gen_params), + {} +}; + +/* + * Test suite for assigned-clock-rates{-u64} DT property. + */ +static struct kunit_suite clk_assigned_rates_suite = { + .name = "clk_assigned_rates", + .test_cases = clk_assigned_rates_test_cases, + .init = clk_assigned_rates_test_init, +}; + kunit_test_suites( + &clk_assigned_rates_suite, &clk_leaf_mux_set_rate_parent_test_suite, &clk_test_suite, &clk_multiple_parents_mux_test_suite, diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 591e0364ee5c11..85771afd4698ae 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -254,9 +254,11 @@ 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); + readl(pll->base + PLL_DIV); 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); + readl(pll->base + PLL_NUMERATOR); } /* Wait for 5us according to fracn mode pll doc */ @@ -265,6 +267,7 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate, /* Enable Powerup */ tmp |= POWERUP_MASK; writel_relaxed(tmp, pll->base + PLL_CTRL); + readl(pll->base + PLL_CTRL); /* Wait Lock */ ret = clk_fracn_gppll_wait_lock(pll); @@ -302,14 +305,15 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw) val |= POWERUP_MASK; writel_relaxed(val, pll->base + PLL_CTRL); - - val |= CLKMUX_EN; - writel_relaxed(val, pll->base + PLL_CTRL); + readl(pll->base + PLL_CTRL); ret = clk_fracn_gppll_wait_lock(pll); if (ret) return ret; + val |= CLKMUX_EN; + writel_relaxed(val, pll->base + PLL_CTRL); + val &= ~CLKMUX_BYPASS; writel_relaxed(val, pll->base + PLL_CTRL); diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 6c351050b82ae0..c169fe53a35f83 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -294,9 +294,9 @@ static int clk_imx_acm_attach_pm_domains(struct device *dev, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); - if (IS_ERR(dev_pm->pd_dev_link[i])) { + if (!dev_pm->pd_dev_link[i]) { dev_pm_domain_detach(dev_pm->pd_dev[i], false); - ret = PTR_ERR(dev_pm->pd_dev_link[i]); + ret = -EINVAL; goto detach_pm; } } diff --git a/drivers/clk/imx/clk-imx93.c b/drivers/clk/imx/clk-imx93.c index c6a9bc8ecc1fc7..58a516dd385bf5 100644 --- a/drivers/clk/imx/clk-imx93.c +++ b/drivers/clk/imx/clk-imx93.c @@ -15,6 +15,11 @@ #include "clk.h" +#define IMX93_CLK_END 207 + +#define PLAT_IMX93 BIT(0) +#define PLAT_IMX91 BIT(1) + enum clk_sel { LOW_SPEED_IO_SEL, NON_IO_SEL, @@ -53,6 +58,7 @@ static const struct imx93_clk_root { u32 off; enum clk_sel sel; unsigned long flags; + unsigned long plat; } root_array[] = { /* a55/m33/bus critical clk for system run */ { IMX93_CLK_A55_PERIPH, "a55_periph_root", 0x0000, FAST_SEL, CLK_IS_CRITICAL }, @@ -63,7 +69,7 @@ static const struct imx93_clk_root { { IMX93_CLK_BUS_AON, "bus_aon_root", 0x0300, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL }, { IMX93_CLK_WAKEUP_AXI, "wakeup_axi_root", 0x0380, FAST_SEL, CLK_IS_CRITICAL }, { IMX93_CLK_SWO_TRACE, "swo_trace_root", 0x0400, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, }, + { IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_FLEXIO1, "flexio1_root", 0x0500, LOW_SPEED_IO_SEL, }, { IMX93_CLK_FLEXIO2, "flexio2_root", 0x0580, LOW_SPEED_IO_SEL, }, { IMX93_CLK_LPTMR1, "lptmr1_root", 0x0700, LOW_SPEED_IO_SEL, }, @@ -120,15 +126,15 @@ static const struct imx93_clk_root { { 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_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_MEDIA_AXI, "media_axi_root", 0x2280, FAST_SEL, }, { IMX93_CLK_MEDIA_APB, "media_apb_root", 0x2300, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, }, + { IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_MEDIA_DISP_PIX, "media_disp_pix_root", 0x2400, VIDEO_SEL, }, { IMX93_CLK_CAM_PIX, "cam_pix_root", 0x2480, VIDEO_SEL, }, - { IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, }, - { IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, }, + { IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_ADC, "adc_root", 0x2700, LOW_SPEED_IO_SEL, }, { IMX93_CLK_PDM, "pdm_root", 0x2780, AUDIO_SEL, }, { IMX93_CLK_TSTMR1, "tstmr1_root", 0x2800, LOW_SPEED_IO_SEL, }, @@ -137,13 +143,16 @@ static const struct imx93_clk_root { { IMX93_CLK_MQS2, "mqs2_root", 0x2980, AUDIO_SEL, }, { IMX93_CLK_AUDIO_XCVR, "audio_xcvr_root", 0x2a00, NON_IO_SEL, }, { IMX93_CLK_SPDIF, "spdif_root", 0x2a80, AUDIO_SEL, }, - { IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, }, - { IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, }, - { IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, }, - { IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, }, + { IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX91_CLK_ENET1_QOS_TSN, "enet1_qos_tsn_root", 0x2b00, NON_IO_SEL, 0, PLAT_IMX91, }, + { IMX91_CLK_ENET_TIMER, "enet_timer_root", 0x2b80, LOW_SPEED_IO_SEL, 0, PLAT_IMX91, }, + { IMX91_CLK_ENET2_REGULAR, "enet2_regular_root", 0x2c80, NON_IO_SEL, 0, PLAT_IMX91, }, + { IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, + { IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, }, { IMX93_CLK_USB_PHY_BURUNIN, "usb_phy_root", 0x2e80, LOW_SPEED_IO_SEL, }, { IMX93_CLK_PAL_CAME_SCAN, "pal_came_scan_root", 0x2f00, MISC_SEL, } }; @@ -155,6 +164,7 @@ static const struct imx93_clk_ccgr { u32 off; unsigned long flags; u32 *shared_count; + unsigned long plat; } ccgr_array[] = { { IMX93_CLK_A55_GATE, "a55_alt", "a55_alt_root", 0x8000, }, /* M33 critical clk for system run */ @@ -244,8 +254,10 @@ static const struct imx93_clk_ccgr { { IMX93_CLK_AUD_XCVR_GATE, "aud_xcvr", "audio_xcvr_root", 0x9b80, }, { IMX93_CLK_SPDIF_GATE, "spdif", "spdif_root", 0x9c00, }, { IMX93_CLK_HSIO_32K_GATE, "hsio_32k", "osc_32k", 0x9dc0, }, - { IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, }, - { IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, }, + { IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, 0, NULL, PLAT_IMX93, }, + { IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, 0, NULL, PLAT_IMX93, }, + { IMX91_CLK_ENET2_REGULAR_GATE, "enet2_regular", "wakeup_axi_root", 0x9e00, 0, NULL, PLAT_IMX91, }, + { IMX91_CLK_ENET1_QOS_TSN_GATE, "enet1_qos_tsn", "wakeup_axi_root", 0x9e40, 0, NULL, PLAT_IMX91, }, /* Critical because clk accessed during CPU idle */ { IMX93_CLK_SYS_CNT_GATE, "sys_cnt", "osc_24m", 0x9e80, CLK_IS_CRITICAL}, { IMX93_CLK_TSTMR1_GATE, "tstmr1", "bus_aon_root", 0x9ec0, }, @@ -265,6 +277,7 @@ static int imx93_clocks_probe(struct platform_device *pdev) const struct imx93_clk_ccgr *ccgr; void __iomem *base, *anatop_base; int i, ret; + const unsigned long plat = (unsigned long)device_get_match_data(&pdev->dev); clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, IMX93_CLK_END), GFP_KERNEL); @@ -314,17 +327,20 @@ static int imx93_clocks_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(root_array); i++) { root = &root_array[i]; - clks[root->clk] = imx93_clk_composite_flags(root->name, - parent_names[root->sel], - 4, base + root->off, 3, - root->flags); + if (!root->plat || root->plat & plat) + clks[root->clk] = imx93_clk_composite_flags(root->name, + parent_names[root->sel], + 4, base + root->off, 3, + root->flags); } for (i = 0; i < ARRAY_SIZE(ccgr_array); i++) { ccgr = &ccgr_array[i]; - clks[ccgr->clk] = imx93_clk_gate(NULL, ccgr->name, ccgr->parent_name, - ccgr->flags, base + ccgr->off, 0, 1, 1, 3, - ccgr->shared_count); + if (!ccgr->plat || ccgr->plat & plat) + clks[ccgr->clk] = imx93_clk_gate(NULL, + ccgr->name, ccgr->parent_name, + ccgr->flags, base + ccgr->off, 0, 1, 1, 3, + ccgr->shared_count); } clks[IMX93_CLK_A55_SEL] = imx_clk_hw_mux2("a55_sel", base + 0x4820, 0, 1, a55_core_sels, @@ -354,7 +370,8 @@ static int imx93_clocks_probe(struct platform_device *pdev) } static const struct of_device_id imx93_clk_of_match[] = { - { .compatible = "fsl,imx93-ccm" }, + { .compatible = "fsl,imx93-ccm", .data = (void *)PLAT_IMX93 }, + { .compatible = "fsl,imx91-ccm", .data = (void *)PLAT_IMX91 }, { /* Sentinel */ }, }; MODULE_DEVICE_TABLE(of, imx93_clk_of_match); diff --git a/drivers/clk/imx/clk-imx95-blk-ctl.c b/drivers/clk/imx/clk-imx95-blk-ctl.c index 19a62da74be450..25974947ad0c18 100644 --- a/drivers/clk/imx/clk-imx95-blk-ctl.c +++ b/drivers/clk/imx/clk-imx95-blk-ctl.c @@ -277,6 +277,25 @@ static const struct imx95_blk_ctl_dev_data netcmix_dev_data = { .clk_reg_offset = 0, }; +static const struct imx95_blk_ctl_clk_dev_data hsio_blk_ctl_clk_dev_data[] = { + [0] = { + .name = "hsio_blk_ctl_clk", + .parent_names = (const char *[]){ "hsio_pll", }, + .num_parents = 1, + .reg = 0, + .bit_idx = 6, + .bit_width = 1, + .type = CLK_GATE, + .flags = CLK_SET_RATE_PARENT, + } +}; + +static const struct imx95_blk_ctl_dev_data hsio_blk_ctl_dev_data = { + .num_clks = 1, + .clk_dev_data = hsio_blk_ctl_clk_dev_data, + .clk_reg_offset = 0, +}; + static int imx95_bc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -447,6 +466,7 @@ static const struct of_device_id imx95_bc_of_match[] = { { .compatible = "nxp,imx95-display-master-csr", }, { .compatible = "nxp,imx95-lvds-csr", .data = &lvds_csr_dev_data }, { .compatible = "nxp,imx95-display-csr", .data = &dispmix_csr_dev_data }, + { .compatible = "nxp,imx95-hsio-blk-ctl", .data = &hsio_blk_ctl_dev_data }, { .compatible = "nxp,imx95-vpu-csr", .data = &vpublk_dev_data }, { .compatible = "nxp,imx95-netcmix-blk-ctrl", .data = &netcmix_dev_data}, { /* Sentinel */ }, diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index dd5abd09f3e206..6376557a3c3d03 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -6,10 +6,12 @@ #include #include +#include #include #include #include #include +#include #include "clk-scu.h" @@ -41,6 +43,29 @@ struct clk_lpcg_scu { #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw) +/* e10858 -LPCG clock gating register synchronization errata */ +static void lpcg_e10858_writel(unsigned long rate, void __iomem *reg, u32 val) +{ + writel(val, reg); + + if (rate >= 24 * HZ_PER_MHZ || rate == 0) { + /* + * The time taken to access the LPCG registers from the AP core + * through the interconnect is longer than the minimum delay + * of 4 clock cycles required by the errata. + * Adding a readl will provide sufficient delay to prevent + * back-to-back writes. + */ + readl(reg); + } else { + /* + * For clocks running below 24MHz, wait a minimum of + * 4 clock cycles. + */ + ndelay(4 * (DIV_ROUND_UP(1000 * HZ_PER_MHZ, rate))); + } +} + static int clk_lpcg_scu_enable(struct clk_hw *hw) { struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw); @@ -57,7 +82,8 @@ static int clk_lpcg_scu_enable(struct clk_hw *hw) val |= CLK_GATE_SCU_LPCG_HW_SEL; reg |= val << clk->bit_idx; - writel(reg, clk->reg); + + lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg); spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); @@ -74,7 +100,7 @@ static void clk_lpcg_scu_disable(struct clk_hw *hw) reg = readl_relaxed(clk->reg); reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx); - writel(reg, clk->reg); + lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg); spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags); } @@ -135,6 +161,9 @@ static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev) { struct clk_lpcg_scu *clk = dev_get_drvdata(dev); + if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg"))) + return 0; + clk->state = readl_relaxed(clk->reg); dev_dbg(dev, "save lpcg state 0x%x\n", clk->state); @@ -145,13 +174,11 @@ static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) { struct clk_lpcg_scu *clk = dev_get_drvdata(dev); - /* - * FIXME: Sometimes writes don't work unless the CPU issues - * them twice - */ + if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg"))) + return 0; writel(clk->state, clk->reg); - writel(clk->state, clk->reg); + lpcg_e10858_writel(0, clk->reg, clk->state); dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state); return 0; diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index b1dd0c08e091b6..b27186aaf2a156 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -596,7 +596,7 @@ static int __maybe_unused imx_clk_scu_suspend(struct device *dev) clk->rate = clk_scu_recalc_rate(&clk->hw, 0); else clk->rate = clk_hw_get_rate(&clk->hw); - clk->is_enabled = clk_hw_is_enabled(&clk->hw); + clk->is_enabled = clk_hw_is_prepared(&clk->hw); if (clk->parent) dev_dbg(dev, "save parent %s idx %u\n", clk_hw_get_name(clk->parent), diff --git a/drivers/clk/kunit_clk_assigned_rates.h b/drivers/clk/kunit_clk_assigned_rates.h new file mode 100644 index 00000000000000..df2d84dcaa9351 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _KUNIT_CLK_ASSIGNED_RATES_H +#define _KUNIT_CLK_ASSIGNED_RATES_H + +#define ASSIGNED_RATES_0_RATE 1600000 +#define ASSIGNED_RATES_1_RATE 9700000 + +#endif diff --git a/drivers/clk/kunit_clk_assigned_rates_multiple.dtso b/drivers/clk/kunit_clk_assigned_rates_multiple.dtso new file mode 100644 index 00000000000000..e600736e70f504 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_multiple.dtso @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <1>; + assigned-clocks = <&clk 0>, + <&clk 1>; + assigned-clock-rates = , + ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso new file mode 100644 index 00000000000000..260aba458daf2b --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <1>; + }; + + kunit-clock-consumer { + compatible = "test,clk-consumer"; + assigned-clocks = <&clk 0>, + <&clk 1>; + assigned-clock-rates = , + ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_null.dtso b/drivers/clk/kunit_clk_assigned_rates_null.dtso new file mode 100644 index 00000000000000..0b27b38a91305c --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_null.dtso @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + assigned-clocks = <0>; + assigned-clock-rates = ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_null_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_null_consumer.dtso new file mode 100644 index 00000000000000..99fb332ae83d86 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_null_consumer.dtso @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + }; + + kunit-clock-consumer { + compatible = "test,clk-consumer"; + assigned-clocks = <0>; + assigned-clock-rates = ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_one.dtso b/drivers/clk/kunit_clk_assigned_rates_one.dtso new file mode 100644 index 00000000000000..dd95ec9b1cf977 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_one.dtso @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + assigned-clocks = <&clk>; + assigned-clock-rates = ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso new file mode 100644 index 00000000000000..a41dca806318b0 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + }; + + kunit-clock-consumer { + compatible = "test,clk-consumer"; + assigned-clocks = <&clk>; + assigned-clock-rates = ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso new file mode 100644 index 00000000000000..389b4e2eb7f74f --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <1>; + assigned-clocks = <&clk 0>, + <&clk 1>; + assigned-clock-rates-u64 = /bits/ 64 , + /bits/ 64 ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso new file mode 100644 index 00000000000000..3e117fd59b7da1 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_u64_multiple_consumer.dtso @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <1>; + }; + + kunit-clock-consumer { + compatible = "test,clk-consumer"; + assigned-clocks = <&clk 0>, + <&clk 1>; + assigned-clock-rates-u64 = /bits/ 64 , + /bits/ 64 ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso new file mode 100644 index 00000000000000..87041264e8f544 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_u64_one.dtso @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + assigned-clocks = <&clk>; + assigned-clock-rates-u64 = /bits/ 64 ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso new file mode 100644 index 00000000000000..3259c003aec0be --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + }; + + kunit-clock-consumer { + compatible = "test,clk-consumer"; + assigned-clocks = <&clk>; + assigned-clock-rates-u64 = /bits/ 64 ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_without.dtso b/drivers/clk/kunit_clk_assigned_rates_without.dtso new file mode 100644 index 00000000000000..22d333495cf2b3 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_without.dtso @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + assigned-clock-rates = ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_without_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_without_consumer.dtso new file mode 100644 index 00000000000000..75ac09140f8349 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_without_consumer.dtso @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "kunit_clk_assigned_rates.h" + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + }; + + kunit-clock-consumer { + compatible = "test,clk-consumer"; + assigned-clock-rates = ; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_zero.dtso b/drivers/clk/kunit_clk_assigned_rates_zero.dtso new file mode 100644 index 00000000000000..08e042c2eafe19 --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_zero.dtso @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + assigned-clocks = <&clk>; + assigned-clock-rates = <0>; + }; +}; diff --git a/drivers/clk/kunit_clk_assigned_rates_zero_consumer.dtso b/drivers/clk/kunit_clk_assigned_rates_zero_consumer.dtso new file mode 100644 index 00000000000000..1d964672e8553a --- /dev/null +++ b/drivers/clk/kunit_clk_assigned_rates_zero_consumer.dtso @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +&{/} { + clk: kunit-clock { + compatible = "test,clk-assigned-rates"; + #clock-cells = <0>; + }; + + kunit-clock-consumer { + compatible = "test,clk-consumer"; + assigned-clocks = <&clk>; + assigned-clock-rates = <0>; + }; +}; diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 70a005e7e1b180..5f8e6d68fa148d 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -124,6 +124,43 @@ config COMMON_CLK_MT2712_VENCSYS help This driver supports MediaTek MT2712 vencsys clocks. +config COMMON_CLK_MT6735 + tristate "Main clock drivers for MediaTek MT6735" + depends on ARCH_MEDIATEK || COMPILE_TEST + select COMMON_CLK_MEDIATEK + help + This enables drivers for clocks and resets provided + by apmixedsys, topckgen, infracfg and pericfg on the + MediaTek MT6735 SoC. + +config COMMON_CLK_MT6735_IMGSYS + tristate "Clock driver for MediaTek MT6735 imgsys" + depends on COMMON_CLK_MT6735 + help + This enables a driver for clocks provided by imgsys + on the MediaTek MT6735 SoC. + +config COMMON_CLK_MT6735_MFGCFG + tristate "Clock driver for MediaTek MT6735 mfgcfg" + depends on COMMON_CLK_MT6735 + help + This enables a driver for clocks and resets provided + by mfgcfg on the MediaTek MT6735 SoC. + +config COMMON_CLK_MT6735_VDECSYS + tristate "Clock driver for MediaTek MT6735 vdecsys" + depends on COMMON_CLK_MT6735 + help + This enables a driver for clocks and resets provided + by vdecsys on the MediaTek MT6735 SoC. + +config COMMON_CLK_MT6735_VENCSYS + tristate "Clock driver for MediaTek MT6735 vencsys" + depends on COMMON_CLK_MT6735 + help + This enables a driver for clocks provided by vencsys + on the MediaTek MT6735 SoC. + config COMMON_CLK_MT6765 bool "Clock driver for MediaTek MT6765" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST @@ -887,13 +924,6 @@ config COMMON_CLK_MT8195_APUSYS 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 @@ -908,14 +938,6 @@ config COMMON_CLK_MT8195_MFGCFG 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 diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index eeccfa039896f3..6efec95406bd5c 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -2,6 +2,11 @@ obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o clk-mux.o obj-$(CONFIG_COMMON_CLK_MEDIATEK_FHCTL) += clk-fhctl.o clk-pllfh.o +obj-$(CONFIG_COMMON_CLK_MT6735) += clk-mt6735-apmixedsys.o clk-mt6735-infracfg.o clk-mt6735-pericfg.o clk-mt6735-topckgen.o +obj-$(CONFIG_COMMON_CLK_MT6735_IMGSYS) += clk-mt6735-imgsys.o +obj-$(CONFIG_COMMON_CLK_MT6735_MFGCFG) += clk-mt6735-mfgcfg.o +obj-$(CONFIG_COMMON_CLK_MT6735_VDECSYS) += clk-mt6735-vdecsys.o +obj-$(CONFIG_COMMON_CLK_MT6735_VENCSYS) += clk-mt6735-vencsys.o obj-$(CONFIG_COMMON_CLK_MT6765) += clk-mt6765.o obj-$(CONFIG_COMMON_CLK_MT6765_AUDIOSYS) += clk-mt6765-audio.o obj-$(CONFIG_COMMON_CLK_MT6765_CAMSYS) += clk-mt6765-cam.o diff --git a/drivers/clk/mediatek/clk-mt6735-apmixedsys.c b/drivers/clk/mediatek/clk-mt6735-apmixedsys.c new file mode 100644 index 00000000000000..e0949911e8f7da --- /dev/null +++ b/drivers/clk/mediatek/clk-mt6735-apmixedsys.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Yassine Oudjana + */ + +#include +#include + +#include "clk-mtk.h" +#include "clk-pll.h" + +#include + +#define AP_PLL_CON_5 0x014 +#define ARMPLL_CON0 0x200 +#define ARMPLL_CON1 0x204 +#define ARMPLL_PWR_CON0 0x20c +#define MAINPLL_CON0 0x210 +#define MAINPLL_CON1 0x214 +#define MAINPLL_PWR_CON0 0x21c +#define UNIVPLL_CON0 0x220 +#define UNIVPLL_CON1 0x224 +#define UNIVPLL_PWR_CON0 0x22c +#define MMPLL_CON0 0x230 +#define MMPLL_CON1 0x234 +#define MMPLL_PWR_CON0 0x23c +#define MSDCPLL_CON0 0x240 +#define MSDCPLL_CON1 0x244 +#define MSDCPLL_PWR_CON0 0x24c +#define VENCPLL_CON0 0x250 +#define VENCPLL_CON1 0x254 +#define VENCPLL_PWR_CON0 0x25c +#define TVDPLL_CON0 0x260 +#define TVDPLL_CON1 0x264 +#define TVDPLL_PWR_CON0 0x26c +#define APLL1_CON0 0x270 +#define APLL1_CON1 0x274 +#define APLL1_CON2 0x278 +#define APLL1_PWR_CON0 0x280 +#define APLL2_CON0 0x284 +#define APLL2_CON1 0x288 +#define APLL2_CON2 0x28c +#define APLL2_PWR_CON0 0x294 + +#define CON0_RST_BAR BIT(24) + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _rst_bar_mask, \ + _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcwbits, _flags) { \ + .id = _id, \ + .name = _name, \ + .parent_name = "clk26m", \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .rst_bar_mask = _rst_bar_mask, \ + .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_chg_reg = _pcw_reg, \ + .pcwbits = _pcwbits, \ + .flags = _flags, \ + } + +static const struct mtk_pll_data apmixedsys_plls[] = { + PLL(CLK_APMIXED_ARMPLL, "armpll", ARMPLL_CON0, ARMPLL_PWR_CON0, 0x00000001, 0, ARMPLL_CON1, 24, 0, 0, 0, ARMPLL_CON1, 21, PLL_AO), + PLL(CLK_APMIXED_MAINPLL, "mainpll", MAINPLL_CON0, MAINPLL_PWR_CON0, 0xf0000101, CON0_RST_BAR, MAINPLL_CON1, 24, 0, 0, 0, MAINPLL_CON1, 21, HAVE_RST_BAR), + PLL(CLK_APMIXED_UNIVPLL, "univpll", UNIVPLL_CON0, UNIVPLL_PWR_CON0, 0xfc000001, CON0_RST_BAR, UNIVPLL_CON1, 24, 0, 0, 0, UNIVPLL_CON1, 21, HAVE_RST_BAR), + PLL(CLK_APMIXED_MMPLL, "mmpll", MMPLL_CON0, MMPLL_PWR_CON0, 0x00000001, 0, MMPLL_CON1, 24, 0, 0, 0, MMPLL_CON1, 21, 0), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", MSDCPLL_CON0, MSDCPLL_PWR_CON0, 0x00000001, 0, MSDCPLL_CON1, 24, 0, 0, 0, MSDCPLL_CON1, 21, 0), + PLL(CLK_APMIXED_VENCPLL, "vencpll", VENCPLL_CON0, VENCPLL_PWR_CON0, 0x00000001, CON0_RST_BAR, VENCPLL_CON1, 24, 0, 0, 0, VENCPLL_CON1, 21, HAVE_RST_BAR), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", TVDPLL_CON0, TVDPLL_PWR_CON0, 0x00000001, 0, TVDPLL_CON1, 24, 0, 0, 0, TVDPLL_CON1, 21, 0), + PLL(CLK_APMIXED_APLL1, "apll1", APLL1_CON0, APLL1_PWR_CON0, 0x00000001, 0, APLL1_CON0, 4, APLL1_CON2, AP_PLL_CON_5, 0, APLL1_CON1, 31, 0), + PLL(CLK_APMIXED_APLL2, "apll2", APLL2_CON0, APLL2_PWR_CON0, 0x00000001, 0, APLL2_CON0, 4, APLL2_CON2, AP_PLL_CON_5, 1, APLL2_CON1, 31, 0) +}; + +static int clk_mt6735_apmixed_probe(struct platform_device *pdev) +{ + void __iomem *base; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct clk_hw_onecell_data *clk_data; + int ret; + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_devm_alloc_clk_data(&pdev->dev, ARRAY_SIZE(apmixedsys_plls)); + if (!clk_data) + return -ENOMEM; + platform_set_drvdata(pdev, clk_data); + + ret = mtk_clk_register_plls(pdev->dev.of_node, apmixedsys_plls, + ARRAY_SIZE(apmixedsys_plls), clk_data); + if (ret) { + dev_err(&pdev->dev, "Failed to register PLLs: %d\n", ret); + return ret; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get, + clk_data); + if (ret) + dev_err(&pdev->dev, + "Failed to register clock provider: %d\n", ret); + + return ret; +} + +static void clk_mt6735_apmixed_remove(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev); + + mtk_clk_unregister_plls(apmixedsys_plls, ARRAY_SIZE(apmixedsys_plls), clk_data); +} + +static const struct of_device_id of_match_mt6735_apmixedsys[] = { + { .compatible = "mediatek,mt6735-apmixedsys" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_mt6735_apmixedsys); + +static struct platform_driver clk_mt6735_apmixedsys = { + .probe = clk_mt6735_apmixed_probe, + .remove = clk_mt6735_apmixed_remove, + .driver = { + .name = "clk-mt6735-apmixedsys", + .of_match_table = of_match_mt6735_apmixedsys, + }, +}; +module_platform_driver(clk_mt6735_apmixedsys); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("MediaTek MT6735 apmixedsys clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6735-imgsys.c b/drivers/clk/mediatek/clk-mt6735-imgsys.c new file mode 100644 index 00000000000000..c564f8f7243242 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt6735-imgsys.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Yassine Oudjana + */ + +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +#include + +#define IMG_CG_CON 0x00 +#define IMG_CG_SET 0x04 +#define IMG_CG_CLR 0x08 + +static struct mtk_gate_regs imgsys_cg_regs = { + .set_ofs = IMG_CG_SET, + .clr_ofs = IMG_CG_CLR, + .sta_ofs = IMG_CG_CON, +}; + +static const struct mtk_gate imgsys_gates[] = { + GATE_MTK(CLK_IMG_SMI_LARB2, "smi_larb2", "mm_sel", &imgsys_cg_regs, 0, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_IMG_CAM_SMI, "cam_smi", "mm_sel", &imgsys_cg_regs, 5, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_IMG_CAM_CAM, "cam_cam", "mm_sel", &imgsys_cg_regs, 6, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_IMG_SEN_TG, "sen_tg", "mm_sel", &imgsys_cg_regs, 7, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_IMG_SEN_CAM, "sen_cam", "mm_sel", &imgsys_cg_regs, 8, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_IMG_CAM_SV, "cam_sv", "mm_sel", &imgsys_cg_regs, 9, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_IMG_SUFOD, "sufod", "mm_sel", &imgsys_cg_regs, 10, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_IMG_FD, "fd", "mm_sel", &imgsys_cg_regs, 11, &mtk_clk_gate_ops_setclr), +}; + +static const struct mtk_clk_desc imgsys_clks = { + .clks = imgsys_gates, + .num_clks = ARRAY_SIZE(imgsys_gates), +}; + +static const struct of_device_id of_match_mt6735_imgsys[] = { + { .compatible = "mediatek,mt6735-imgsys", .data = &imgsys_clks }, + { /* sentinel */ } +}; + +static struct platform_driver clk_mt6735_imgsys = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt6735-imgsys", + .of_match_table = of_match_mt6735_imgsys, + }, +}; +module_platform_driver(clk_mt6735_imgsys); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("MediaTek MT6735 imgsys clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6735-infracfg.c b/drivers/clk/mediatek/clk-mt6735-infracfg.c new file mode 100644 index 00000000000000..c1171f903cfae5 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt6735-infracfg.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Yassine Oudjana + */ + +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +#include +#include + +#define INFRA_RST0 0x30 +#define INFRA_GLOBALCON_PDN0 0x40 +#define INFRA_PDN1 0x44 +#define INFRA_PDN_STA 0x48 + +#define RST_NR_PER_BANK 32 + +static struct mtk_gate_regs infra_cg_regs = { + .set_ofs = INFRA_GLOBALCON_PDN0, + .clr_ofs = INFRA_PDN1, + .sta_ofs = INFRA_PDN_STA, +}; + +static const struct mtk_gate infracfg_gates[] = { + GATE_MTK(CLK_INFRA_DBG, "dbg", "axi_sel", &infra_cg_regs, 0, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_GCE, "gce", "axi_sel", &infra_cg_regs, 1, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_TRBG, "trbg", "axi_sel", &infra_cg_regs, 2, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_CPUM, "cpum", "axi_sel", &infra_cg_regs, 3, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_DEVAPC, "devapc", "axi_sel", &infra_cg_regs, 4, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_AUDIO, "audio", "aud_intbus_sel", &infra_cg_regs, 5, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_GCPU, "gcpu", "axi_sel", &infra_cg_regs, 6, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_L2C_SRAM, "l2csram", "axi_sel", &infra_cg_regs, 7, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_M4U, "m4u", "axi_sel", &infra_cg_regs, 8, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_CLDMA, "cldma", "axi_sel", &infra_cg_regs, 12, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_CONNMCU_BUS, "connmcu_bus", "axi_sel", &infra_cg_regs, 15, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_KP, "kp", "axi_sel", &infra_cg_regs, 16, &mtk_clk_gate_ops_setclr), + GATE_MTK_FLAGS(CLK_INFRA_APXGPT, "apxgpt", "axi_sel", &infra_cg_regs, 18, &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL), + GATE_MTK(CLK_INFRA_SEJ, "sej", "axi_sel", &infra_cg_regs, 19, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_CCIF0_AP, "ccif0ap", "axi_sel", &infra_cg_regs, 20, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_CCIF1_AP, "ccif1ap", "axi_sel", &infra_cg_regs, 21, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_PMIC_SPI, "pmicspi", "pmicspi_sel", &infra_cg_regs, 22, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_INFRA_PMIC_WRAP, "pmicwrap", "axi_sel", &infra_cg_regs, 23, &mtk_clk_gate_ops_setclr) +}; + +static u16 infracfg_rst_bank_ofs[] = { INFRA_RST0 }; + +static u16 infracfg_rst_idx_map[] = { + [MT6735_INFRA_RST0_EMI_REG] = 0 * RST_NR_PER_BANK + 0, + [MT6735_INFRA_RST0_DRAMC0_AO] = 0 * RST_NR_PER_BANK + 1, + [MT6735_INFRA_RST0_AP_CIRQ_EINT] = 0 * RST_NR_PER_BANK + 3, + [MT6735_INFRA_RST0_APXGPT] = 0 * RST_NR_PER_BANK + 4, + [MT6735_INFRA_RST0_SCPSYS] = 0 * RST_NR_PER_BANK + 5, + [MT6735_INFRA_RST0_KP] = 0 * RST_NR_PER_BANK + 6, + [MT6735_INFRA_RST0_PMIC_WRAP] = 0 * RST_NR_PER_BANK + 7, + [MT6735_INFRA_RST0_CLDMA_AO_TOP] = 0 * RST_NR_PER_BANK + 8, + [MT6735_INFRA_RST0_USBSIF_TOP] = 0 * RST_NR_PER_BANK + 9, + [MT6735_INFRA_RST0_EMI] = 0 * RST_NR_PER_BANK + 16, + [MT6735_INFRA_RST0_CCIF] = 0 * RST_NR_PER_BANK + 17, + [MT6735_INFRA_RST0_DRAMC0] = 0 * RST_NR_PER_BANK + 18, + [MT6735_INFRA_RST0_EMI_AO_REG] = 0 * RST_NR_PER_BANK + 19, + [MT6735_INFRA_RST0_CCIF_AO] = 0 * RST_NR_PER_BANK + 20, + [MT6735_INFRA_RST0_TRNG] = 0 * RST_NR_PER_BANK + 21, + [MT6735_INFRA_RST0_SYS_CIRQ] = 0 * RST_NR_PER_BANK + 22, + [MT6735_INFRA_RST0_GCE] = 0 * RST_NR_PER_BANK + 23, + [MT6735_INFRA_RST0_M4U] = 0 * RST_NR_PER_BANK + 24, + [MT6735_INFRA_RST0_CCIF1] = 0 * RST_NR_PER_BANK + 25, + [MT6735_INFRA_RST0_CLDMA_TOP_PD] = 0 * RST_NR_PER_BANK + 26 +}; + +static const struct mtk_clk_rst_desc infracfg_resets = { + .version = MTK_RST_SIMPLE, + .rst_bank_ofs = infracfg_rst_bank_ofs, + .rst_bank_nr = ARRAY_SIZE(infracfg_rst_bank_ofs), + .rst_idx_map = infracfg_rst_idx_map, + .rst_idx_map_nr = ARRAY_SIZE(infracfg_rst_idx_map) +}; + +static const struct mtk_clk_desc infracfg_clks = { + .clks = infracfg_gates, + .num_clks = ARRAY_SIZE(infracfg_gates), + + .rst_desc = &infracfg_resets +}; + +static const struct of_device_id of_match_mt6735_infracfg[] = { + { .compatible = "mediatek,mt6735-infracfg", .data = &infracfg_clks }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_mt6735_infracfg); + +static struct platform_driver clk_mt6735_infracfg = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt6735-infracfg", + .of_match_table = of_match_mt6735_infracfg, + }, +}; +module_platform_driver(clk_mt6735_infracfg); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("MediaTek MT6735 infracfg clock and reset driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6735-mfgcfg.c b/drivers/clk/mediatek/clk-mt6735-mfgcfg.c new file mode 100644 index 00000000000000..1f5aedddf209df --- /dev/null +++ b/drivers/clk/mediatek/clk-mt6735-mfgcfg.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Yassine Oudjana + */ + +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +#include + +#define MFG_CG_CON 0x00 +#define MFG_CG_SET 0x04 +#define MFG_CG_CLR 0x08 +#define MFG_RESET 0x0c + +static struct mtk_gate_regs mfgcfg_cg_regs = { + .set_ofs = MFG_CG_SET, + .clr_ofs = MFG_CG_CLR, + .sta_ofs = MFG_CG_CON, +}; + +static const struct mtk_gate mfgcfg_gates[] = { + GATE_MTK(CLK_MFG_BG3D, "bg3d", "mfg_sel", &mfgcfg_cg_regs, 0, &mtk_clk_gate_ops_setclr), +}; + +static u16 mfgcfg_rst_ofs[] = { MFG_RESET }; + +static const struct mtk_clk_rst_desc mfgcfg_resets = { + .version = MTK_RST_SIMPLE, + .rst_bank_ofs = mfgcfg_rst_ofs, + .rst_bank_nr = ARRAY_SIZE(mfgcfg_rst_ofs) +}; + +static const struct mtk_clk_desc mfgcfg_clks = { + .clks = mfgcfg_gates, + .num_clks = ARRAY_SIZE(mfgcfg_gates), + + .rst_desc = &mfgcfg_resets +}; + +static const struct of_device_id of_match_mt6735_mfgcfg[] = { + { .compatible = "mediatek,mt6735-mfgcfg", .data = &mfgcfg_clks }, + { /* sentinel */ } +}; + +static struct platform_driver clk_mt6735_mfgcfg = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt6735-mfgcfg", + .of_match_table = of_match_mt6735_mfgcfg, + }, +}; +module_platform_driver(clk_mt6735_mfgcfg); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("Mediatek MT6735 mfgcfg clock and reset driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6735-pericfg.c b/drivers/clk/mediatek/clk-mt6735-pericfg.c new file mode 100644 index 00000000000000..cbdf6d25c1b252 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt6735-pericfg.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Yassine Oudjana + */ + +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +#include +#include + +#define PERI_GLOBALCON_RST0 0x00 +#define PERI_GLOBALCON_RST1 0x04 +#define PERI_GLOBALCON_PDN0_SET 0x08 +#define PERI_GLOBALCON_PDN0_CLR 0x10 +#define PERI_GLOBALCON_PDN0_STA 0x18 + +#define RST_NR_PER_BANK 32 + +static struct mtk_gate_regs peri_cg_regs = { + .set_ofs = PERI_GLOBALCON_PDN0_SET, + .clr_ofs = PERI_GLOBALCON_PDN0_CLR, + .sta_ofs = PERI_GLOBALCON_PDN0_STA, +}; + +static const struct mtk_gate pericfg_gates[] = { + GATE_MTK(CLK_PERI_DISP_PWM, "disp_pwm", "disppwm_sel", &peri_cg_regs, 0, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_THERM, "therm", "axi_sel", &peri_cg_regs, 1, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_PWM1, "pwm1", "axi_sel", &peri_cg_regs, 2, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_PWM2, "pwm2", "axi_sel", &peri_cg_regs, 3, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_PWM3, "pwm3", "axi_sel", &peri_cg_regs, 4, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_PWM4, "pwm4", "axi_sel", &peri_cg_regs, 5, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_PWM5, "pwm5", "axi_sel", &peri_cg_regs, 6, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_PWM6, "pwm6", "axi_sel", &peri_cg_regs, 7, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_PWM7, "pwm7", "axi_sel", &peri_cg_regs, 8, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_PWM, "pwm", "axi_sel", &peri_cg_regs, 9, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_USB0, "usb0", "usb20_sel", &peri_cg_regs, 10, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_IRDA, "irda", "irda_sel", &peri_cg_regs, 11, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_APDMA, "apdma", "axi_sel", &peri_cg_regs, 12, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_MSDC30_0, "msdc30_0", "msdc30_0_sel", &peri_cg_regs, 13, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_MSDC30_1, "msdc30_1", "msdc30_1_sel", &peri_cg_regs, 14, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_MSDC30_2, "msdc30_2", "msdc30_2_sel", &peri_cg_regs, 15, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_MSDC30_3, "msdc30_3", "msdc30_3_sel", &peri_cg_regs, 16, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_UART0, "uart0", "uart_sel", &peri_cg_regs, 17, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_UART1, "uart1", "uart_sel", &peri_cg_regs, 18, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_UART2, "uart2", "uart_sel", &peri_cg_regs, 19, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_UART3, "uart3", "uart_sel", &peri_cg_regs, 20, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_UART4, "uart4", "uart_sel", &peri_cg_regs, 21, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_BTIF, "btif", "axi_sel", &peri_cg_regs, 22, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_I2C0, "i2c0", "axi_sel", &peri_cg_regs, 23, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_I2C1, "i2c1", "axi_sel", &peri_cg_regs, 24, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_I2C2, "i2c2", "axi_sel", &peri_cg_regs, 25, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_I2C3, "i2c3", "axi_sel", &peri_cg_regs, 26, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_AUXADC, "auxadc", "axi_sel", &peri_cg_regs, 27, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_SPI0, "spi0", "spi_sel", &peri_cg_regs, 28, &mtk_clk_gate_ops_setclr), + GATE_MTK(CLK_PERI_IRTX, "irtx", "irtx_sel", &peri_cg_regs, 29, &mtk_clk_gate_ops_setclr) +}; + +static u16 pericfg_rst_bank_ofs[] = { PERI_GLOBALCON_RST0, PERI_GLOBALCON_RST1 }; + +static u16 pericfg_rst_idx_map[] = { + [MT6735_PERI_RST0_UART0] = 0 * RST_NR_PER_BANK + 0, + [MT6735_PERI_RST0_UART1] = 0 * RST_NR_PER_BANK + 1, + [MT6735_PERI_RST0_UART2] = 0 * RST_NR_PER_BANK + 2, + [MT6735_PERI_RST0_UART3] = 0 * RST_NR_PER_BANK + 3, + [MT6735_PERI_RST0_UART4] = 0 * RST_NR_PER_BANK + 4, + [MT6735_PERI_RST0_BTIF] = 0 * RST_NR_PER_BANK + 6, + [MT6735_PERI_RST0_DISP_PWM_PERI] = 0 * RST_NR_PER_BANK + 7, + [MT6735_PERI_RST0_PWM] = 0 * RST_NR_PER_BANK + 8, + [MT6735_PERI_RST0_AUXADC] = 0 * RST_NR_PER_BANK + 10, + [MT6735_PERI_RST0_DMA] = 0 * RST_NR_PER_BANK + 11, + [MT6735_PERI_RST0_IRDA] = 0 * RST_NR_PER_BANK + 12, + [MT6735_PERI_RST0_IRTX] = 0 * RST_NR_PER_BANK + 13, + [MT6735_PERI_RST0_THERM] = 0 * RST_NR_PER_BANK + 16, + [MT6735_PERI_RST0_MSDC2] = 0 * RST_NR_PER_BANK + 17, + [MT6735_PERI_RST0_MSDC3] = 0 * RST_NR_PER_BANK + 18, + [MT6735_PERI_RST0_MSDC0] = 0 * RST_NR_PER_BANK + 19, + [MT6735_PERI_RST0_MSDC1] = 0 * RST_NR_PER_BANK + 20, + [MT6735_PERI_RST0_I2C0] = 0 * RST_NR_PER_BANK + 22, + [MT6735_PERI_RST0_I2C1] = 0 * RST_NR_PER_BANK + 23, + [MT6735_PERI_RST0_I2C2] = 0 * RST_NR_PER_BANK + 24, + [MT6735_PERI_RST0_I2C3] = 0 * RST_NR_PER_BANK + 25, + [MT6735_PERI_RST0_USB] = 0 * RST_NR_PER_BANK + 28, + + [MT6735_PERI_RST1_SPI0] = 1 * RST_NR_PER_BANK + 1, +}; + +static const struct mtk_clk_rst_desc pericfg_resets = { + .version = MTK_RST_SIMPLE, + .rst_bank_ofs = pericfg_rst_bank_ofs, + .rst_bank_nr = ARRAY_SIZE(pericfg_rst_bank_ofs), + .rst_idx_map = pericfg_rst_idx_map, + .rst_idx_map_nr = ARRAY_SIZE(pericfg_rst_idx_map) +}; + +static const struct mtk_clk_desc pericfg_clks = { + .clks = pericfg_gates, + .num_clks = ARRAY_SIZE(pericfg_gates), + + .rst_desc = &pericfg_resets +}; + +static const struct of_device_id of_match_mt6735_pericfg[] = { + { .compatible = "mediatek,mt6735-pericfg", .data = &pericfg_clks }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_mt6735_pericfg); + +static struct platform_driver clk_mt6735_pericfg = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt6735-pericfg", + .of_match_table = of_match_mt6735_pericfg, + }, +}; +module_platform_driver(clk_mt6735_pericfg); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("MediaTek MT6735 pericfg clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6735-topckgen.c b/drivers/clk/mediatek/clk-mt6735-topckgen.c new file mode 100644 index 00000000000000..2589ebfe227160 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt6735-topckgen.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Yassine Oudjana + */ + +#include +#include + +#include "clk-mtk.h" +#include "clk-mux.h" + +#include + +#define CLK_CFG_0 0x40 +#define CLK_CFG_0_SET 0x44 +#define CLK_CFG_0_CLR 0x48 +#define CLK_CFG_1 0x50 +#define CLK_CFG_1_SET 0x54 +#define CLK_CFG_1_CLR 0x58 +#define CLK_CFG_2 0x60 +#define CLK_CFG_2_SET 0x64 +#define CLK_CFG_2_CLR 0x68 +#define CLK_CFG_3 0x70 +#define CLK_CFG_3_SET 0x74 +#define CLK_CFG_3_CLR 0x78 +#define CLK_CFG_4 0x80 +#define CLK_CFG_4_SET 0x84 +#define CLK_CFG_4_CLR 0x88 +#define CLK_CFG_5 0x90 +#define CLK_CFG_5_SET 0x94 +#define CLK_CFG_5_CLR 0x98 +#define CLK_CFG_6 0xa0 +#define CLK_CFG_6_SET 0xa4 +#define CLK_CFG_6_CLR 0xa8 +#define CLK_CFG_7 0xb0 +#define CLK_CFG_7_SET 0xb4 +#define CLK_CFG_7_CLR 0xb8 + +static DEFINE_SPINLOCK(mt6735_topckgen_lock); + +/* Some clocks with unknown details are modeled as fixed clocks */ +static const struct mtk_fixed_clk topckgen_fixed_clks[] = { + /* + * This clock is available as a parent option for multiple + * muxes and seems like an alternative name for clk26m at first, + * but it appears alongside it in several muxes which should + * mean it is a separate clock. + */ + FIXED_CLK(CLK_TOP_AD_SYS_26M_CK, "ad_sys_26m_ck", "clk26m", 26 * MHZ), + /* + * This clock is the parent of DMPLL divisors. It might be MEMPLL + * or its parent, as DMPLL appears to be an alternative name for + * MEMPLL. + */ + FIXED_CLK(CLK_TOP_CLKPH_MCK_O, "clkph_mck_o", NULL, 0), + /* + * DMPLL clock (dmpll_ck), controlled by DDRPHY. + */ + FIXED_CLK(CLK_TOP_DMPLL, "dmpll", "clkph_mck_o", 0), + /* + * MIPI DPI clock. Parent option for dpi0_sel. Unknown parent. + */ + FIXED_CLK(CLK_TOP_DPI_CK, "dpi_ck", NULL, 0), + /* + * This clock is a child of WHPLL which is controlled by + * the modem. + */ + FIXED_CLK(CLK_TOP_WHPLL_AUDIO_CK, "whpll_audio_ck", NULL, 0) +}; + +static const struct mtk_fixed_factor topckgen_factors[] = { + FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2), + FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3), + FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5), + FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "mainpll", 1, 2), + FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "mainpll", 1, 4), + FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "mainpll", 1, 8), + FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "mainpll", 1, 16), + FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "mainpll", 1, 2), + FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "mainpll", 1, 4), + FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "mainpll", 1, 2), + FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "mainpll", 1, 4), + FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "mainpll", 1, 2), + FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "mainpll", 1, 4), + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5), + FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26), + FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll", 1, 4), + FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll", 1, 8), + FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll", 1, 4), + FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll", 1, 8), + FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll", 1, 4), + FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2), + FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4), + FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8), + FACTOR(CLK_TOP_MSDCPLL_D16, "msdcpll_d16", "msdcpll", 1, 16), + FACTOR(CLK_TOP_VENCPLL_D3, "vencpll_d3", "vencpll", 1, 3), + FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2), + FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4), + FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "clkph_mck_o", 1, 2), + FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "clkph_mck_o", 1, 4), + FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "clkph_mck_o", 1, 8), + FACTOR(CLK_TOP_AD_SYS_26M_D2, "ad_sys_26m_d2", "clk26m", 1, 2) +}; + +static const char * const axi_sel_parents[] = { + "clk26m", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "univpll2_d2", + "dmpll", + "dmpll_d2" +}; + +static const char * const mem_sel_parents[] = { + "clk26m", + "dmpll" +}; + +static const char * const ddrphycfg_parents[] = { + "clk26m", + "syspll1_d8" +}; + +static const char * const mm_sel_parents[] = { + "clk26m", + "vencpll", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "univpll2_d2", + "dmpll" +}; + +static const char * const pwm_sel_parents[] = { + "clk26m", + "univpll2_d4", + "univpll3_d2", + "univpll1_d4" +}; + +static const char * const vdec_sel_parents[] = { + "clk26m", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "syspll_d2", + "syspll2_d2", + "msdcpll_d2" +}; + +static const char * const mfg_sel_parents[] = { + "clk26m", + "mmpll", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "syspll_d3", + "syspll1_d2", + "syspll_d5", + "univpll_d3", + "univpll1_d2" +}; + +static const char * const camtg_sel_parents[] = { + "clk26m", + "univpll_d26", + "univpll2_d2", + "syspll3_d2", + "syspll3_d4", + "msdcpll_d4" +}; + +static const char * const uart_sel_parents[] = { + "clk26m", + "univpll2_d8" +}; + +static const char * const spi_sel_parents[] = { + "clk26m", + "syspll3_d2", + "msdcpll_d8", + "syspll2_d4", + "syspll4_d2", + "univpll2_d4", + "univpll1_d8" +}; + +static const char * const usb20_sel_parents[] = { + "clk26m", + "univpll1_d8", + "univpll3_d4" +}; + +static const char * const msdc50_0_sel_parents[] = { + "clk26m", + "syspll1_d2", + "syspll2_d2", + "syspll4_d2", + "univpll_d5", + "univpll1_d4" +}; + +static const char * const msdc30_0_sel_parents[] = { + "clk26m", + "msdcpll", + "msdcpll_d2", + "msdcpll_d4", + "syspll2_d2", + "syspll1_d4", + "univpll1_d4", + "univpll_d3", + "univpll_d26", + "syspll2_d4", + "univpll_d2" +}; + +static const char * const msdc30_1_2_sel_parents[] = { + "clk26m", + "univpll2_d2", + "msdcpll_d4", + "syspll2_d2", + "syspll1_d4", + "univpll1_d4", + "univpll_d26", + "syspll2_d4" +}; + +static const char * const msdc30_3_sel_parents[] = { + "clk26m", + "univpll2_d2", + "msdcpll_d4", + "syspll2_d2", + "syspll1_d4", + "univpll1_d4", + "univpll_d26", + "msdcpll_d16", + "syspll2_d4" +}; + +static const char * const audio_sel_parents[] = { + "clk26m", + "syspll3_d4", + "syspll4_d4", + "syspll1_d16" +}; + +static const char * const aud_intbus_sel_parents[] = { + "clk26m", + "syspll1_d4", + "syspll4_d2", + "dmpll_d4" +}; + +static const char * const pmicspi_sel_parents[] = { + "clk26m", + "syspll1_d8", + "syspll3_d4", + "syspll1_d16", + "univpll3_d4", + "univpll_d26", + "dmpll_d4", + "dmpll_d8" +}; + +static const char * const scp_sel_parents[] = { + "clk26m", + "syspll1_d8", + "dmpll_d2", + "dmpll_d4" +}; + +static const char * const atb_sel_parents[] = { + "clk26m", + "syspll1_d2", + "syspll_d5", + "dmpll" +}; + +static const char * const dpi0_sel_parents[] = { + "clk26m", + "tvdpll", + "tvdpll_d2", + "tvdpll_d4", + "dpi_ck" +}; + +static const char * const scam_sel_parents[] = { + "clk26m", + "syspll3_d2", + "univpll2_d4", + "vencpll_d3" +}; + +static const char * const mfg13m_sel_parents[] = { + "clk26m", + "ad_sys_26m_d2" +}; + +static const char * const aud_1_2_sel_parents[] = { + "clk26m", + "apll1" +}; + +static const char * const irda_sel_parents[] = { + "clk26m", + "univpll2_d4" +}; + +static const char * const irtx_sel_parents[] = { + "clk26m", + "ad_sys_26m_ck" +}; + +static const char * const disppwm_sel_parents[] = { + "clk26m", + "univpll2_d4", + "syspll4_d2_d8", + "ad_sys_26m_ck" +}; + +static const struct mtk_mux topckgen_muxes[] = { + MUX_CLR_SET_UPD(CLK_TOP_AXI_SEL, "axi_sel", axi_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 0, 3, 0, 0), + MUX_CLR_SET_UPD(CLK_TOP_MEM_SEL, "mem_sel", mem_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 8, 1, 0, 0), + MUX_CLR_SET_UPD(CLK_TOP_DDRPHY_SEL, "ddrphycfg_sel", ddrphycfg_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 16, 1, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MM_SEL, "mm_sel", mm_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 24, 3, 31, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 0, 2, 7, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 8, 3, 15, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG_SEL, "mfg_sel", mfg_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 16, 4, 23, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 24, 3, 31, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 0, 1, 7, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 8, 3, 15, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB20_SEL, "usb20_sel", usb20_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 16, 2, 23, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 24, 3, 31, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_0_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 0, 4, 7, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_2_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 8, 3, 15, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_1_2_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 16, 3, 23, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 24, 4, 31, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDIO_SEL, "audio_sel", audio_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 0, 2, 7, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 8, 2, 15, 0, 0), + MUX_CLR_SET_UPD(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 16, 3, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SCP_SEL, "scp_sel", scp_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 24, 2, 31, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ATB_SEL, "atb_sel", atb_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 0, 2, 7, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 8, 3, 15, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SCAM_SEL, "scam_sel", scam_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 16, 2, 23, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG13M_SEL, "mfg13m_sel", mfg13m_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 24, 1, 31, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD1_SEL, "aud_1_sel", aud_1_2_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 0, 1, 7, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD2_SEL, "aud_2_sel", aud_1_2_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 8, 1, 15, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_IRDA_SEL, "irda_sel", irda_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 16, 1, 23, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_IRTX_SEL, "irtx_sel", irtx_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 24, 1, 31, 0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DISPPWM_SEL, "disppwm_sel", disppwm_sel_parents, CLK_CFG_7, CLK_CFG_7_SET, CLK_CFG_7_CLR, 0, 2, 7, 0, 0), +}; + +static const struct mtk_clk_desc topckgen_desc = { + .fixed_clks = topckgen_fixed_clks, + .num_fixed_clks = ARRAY_SIZE(topckgen_fixed_clks), + .factor_clks = topckgen_factors, + .num_factor_clks = ARRAY_SIZE(topckgen_factors), + .mux_clks = topckgen_muxes, + .num_mux_clks = ARRAY_SIZE(topckgen_muxes), + .clk_lock = &mt6735_topckgen_lock, +}; + +static const struct of_device_id of_match_mt6735_topckgen[] = { + { .compatible = "mediatek,mt6735-topckgen", .data = &topckgen_desc}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_mt6735_topckgen); + +static struct platform_driver clk_mt6735_topckgen = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt6735-topckgen", + .of_match_table = of_match_mt6735_topckgen, + }, +}; +module_platform_driver(clk_mt6735_topckgen); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("MediaTek MT6735 topckgen clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6735-vdecsys.c b/drivers/clk/mediatek/clk-mt6735-vdecsys.c new file mode 100644 index 00000000000000..8817085fc1db4f --- /dev/null +++ b/drivers/clk/mediatek/clk-mt6735-vdecsys.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Yassine Oudjana + */ + +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +#include +#include + +#define VDEC_CKEN_SET 0x00 +#define VDEC_CKEN_CLR 0x04 +#define SMI_LARB1_CKEN_SET 0x08 +#define SMI_LARB1_CKEN_CLR 0x0c +#define VDEC_RESETB_CON 0x10 +#define SMI_LARB1_RESETB_CON 0x14 + +#define RST_NR_PER_BANK 32 + +static struct mtk_gate_regs vdec_cg_regs = { + .set_ofs = VDEC_CKEN_SET, + .clr_ofs = VDEC_CKEN_CLR, + .sta_ofs = VDEC_CKEN_SET, +}; + +static struct mtk_gate_regs smi_larb1_cg_regs = { + .set_ofs = SMI_LARB1_CKEN_SET, + .clr_ofs = SMI_LARB1_CKEN_CLR, + .sta_ofs = SMI_LARB1_CKEN_SET, +}; + +static const struct mtk_gate vdecsys_gates[] = { + GATE_MTK(CLK_VDEC_VDEC, "vdec", "vdec_sel", &vdec_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv), + GATE_MTK(CLK_VDEC_SMI_LARB1, "smi_larb1", "vdec_sel", &smi_larb1_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv), +}; + +static u16 vdecsys_rst_bank_ofs[] = { VDEC_RESETB_CON, SMI_LARB1_RESETB_CON }; + +static u16 vdecsys_rst_idx_map[] = { + [MT6735_VDEC_RST0_VDEC] = 0 * RST_NR_PER_BANK + 0, + [MT6735_VDEC_RST1_SMI_LARB1] = 1 * RST_NR_PER_BANK + 0, +}; + +static const struct mtk_clk_rst_desc vdecsys_resets = { + .version = MTK_RST_SIMPLE, + .rst_bank_ofs = vdecsys_rst_bank_ofs, + .rst_bank_nr = ARRAY_SIZE(vdecsys_rst_bank_ofs), + .rst_idx_map = vdecsys_rst_idx_map, + .rst_idx_map_nr = ARRAY_SIZE(vdecsys_rst_idx_map) +}; + +static const struct mtk_clk_desc vdecsys_clks = { + .clks = vdecsys_gates, + .num_clks = ARRAY_SIZE(vdecsys_gates), + .rst_desc = &vdecsys_resets +}; + +static const struct of_device_id of_match_mt6735_vdecsys[] = { + { .compatible = "mediatek,mt6735-vdecsys", .data = &vdecsys_clks }, + { /* sentinel */ } +}; + +static struct platform_driver clk_mt6735_vdecsys = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt6735-vdecsys", + .of_match_table = of_match_mt6735_vdecsys, + }, +}; +module_platform_driver(clk_mt6735_vdecsys); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("MediaTek MT6735 vdecsys clock and reset driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt6735-vencsys.c b/drivers/clk/mediatek/clk-mt6735-vencsys.c new file mode 100644 index 00000000000000..8dec7f98492ac5 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt6735-vencsys.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Yassine Oudjana + */ + +#include +#include + +#include "clk-gate.h" +#include "clk-mtk.h" + +#include + +#define VENC_CG_CON 0x00 +#define VENC_CG_SET 0x04 +#define VENC_CG_CLR 0x08 + +static struct mtk_gate_regs venc_cg_regs = { + .set_ofs = VENC_CG_SET, + .clr_ofs = VENC_CG_CLR, + .sta_ofs = VENC_CG_CON, +}; + +static const struct mtk_gate vencsys_gates[] = { + GATE_MTK(CLK_VENC_SMI_LARB3, "smi_larb3", "mm_sel", &venc_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv), + GATE_MTK(CLK_VENC_VENC, "venc", "mm_sel", &venc_cg_regs, 4, &mtk_clk_gate_ops_setclr_inv), + GATE_MTK(CLK_VENC_JPGENC, "jpgenc", "mm_sel", &venc_cg_regs, 8, &mtk_clk_gate_ops_setclr_inv), + GATE_MTK(CLK_VENC_JPGDEC, "jpgdec", "mm_sel", &venc_cg_regs, 12, &mtk_clk_gate_ops_setclr_inv), +}; + +static const struct mtk_clk_desc vencsys_clks = { + .clks = vencsys_gates, + .num_clks = ARRAY_SIZE(vencsys_gates), +}; + +static const struct of_device_id of_match_mt6735_vencsys[] = { + { .compatible = "mediatek,mt6735-vencsys", .data = &vencsys_clks }, + { /* sentinel */ } +}; + +static struct platform_driver clk_mt6735_vencsys = { + .probe = mtk_clk_simple_probe, + .remove = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt6735-vencsys", + .of_match_table = of_match_mt6735_vencsys, + }, +}; +module_platform_driver(clk_mt6735_vencsys); + +MODULE_AUTHOR("Yassine Oudjana "); +MODULE_DESCRIPTION("Mediatek MT6735 vencsys clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-topckgen.c b/drivers/clk/mediatek/clk-mt8188-topckgen.c index c4baf4076ed64a..6b07abe9a8f5f2 100644 --- a/drivers/clk/mediatek/clk-mt8188-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8188-topckgen.c @@ -342,11 +342,14 @@ static const char * const dsp7_parents[] = { "univpll_d3" }; +/* + * MFG can be also parented to "univpll_d6" and "univpll_d7": + * these have been removed from the parents list to let us + * achieve GPU DVFS without any special clock handlers. + */ static const char * const mfg_core_tmp_parents[] = { "clk26m", - "mainpll_d5_d2", - "univpll_d6", - "univpll_d7" + "mainpll_d5_d2" }; static const char * const camtg_parents[] = { diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 78f648c9c97dc6..be2e3a5f83363b 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -106,6 +106,7 @@ config COMMON_CLK_AXG_AUDIO select COMMON_CLK_MESON_SCLK_DIV select COMMON_CLK_MESON_CLKC_UTILS select REGMAP_MMIO + select RESET_CONTROLLER help Support for the audio clock controller on AmLogic A113D devices, aka axg, Say Y if you want audio subsystem to work. diff --git a/drivers/clk/meson/a1-peripherals.c b/drivers/clk/meson/a1-peripherals.c index 7aa6abb2eb1f2b..36489e0f948a54 100644 --- a/drivers/clk/meson/a1-peripherals.c +++ b/drivers/clk/meson/a1-peripherals.c @@ -2246,4 +2246,4 @@ MODULE_DESCRIPTION("Amlogic A1 Peripherals Clock Controller driver"); MODULE_AUTHOR("Jian Hu "); MODULE_AUTHOR("Dmitry Rokosov "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c index 8e5a42d1afbbcd..8d7c7b4493c406 100644 --- a/drivers/clk/meson/a1-pll.c +++ b/drivers/clk/meson/a1-pll.c @@ -360,4 +360,4 @@ MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver"); MODULE_AUTHOR("Jian Hu "); MODULE_AUTHOR("Dmitry Rokosov "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index 1dabc81535a6f7..f44091ffb57d93 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -342,4 +342,4 @@ module_platform_driver(axg_aoclkc_driver); MODULE_DESCRIPTION("Amlogic AXG Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index beda8634938999..9df627b142f897 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -1912,4 +1912,4 @@ module_platform_driver(axg_audio_driver); MODULE_DESCRIPTION("Amlogic AXG/G12A/SM1 Audio Clock driver"); MODULE_AUTHOR("Jerome Brunet "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 757c7a28c53de6..448eece246ca75 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -23,8 +23,6 @@ #include -static DEFINE_SPINLOCK(meson_clk_lock); - static struct clk_regmap axg_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { @@ -506,7 +504,6 @@ static struct clk_regmap axg_mpll0_div = { .shift = 0, .width = 1, }, - .lock = &meson_clk_lock, .flags = CLK_MESON_MPLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ @@ -557,7 +554,6 @@ static struct clk_regmap axg_mpll1_div = { .shift = 1, .width = 1, }, - .lock = &meson_clk_lock, .flags = CLK_MESON_MPLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ @@ -613,7 +609,6 @@ static struct clk_regmap axg_mpll2_div = { .shift = 2, .width = 1, }, - .lock = &meson_clk_lock, .flags = CLK_MESON_MPLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ @@ -664,7 +659,6 @@ static struct clk_regmap axg_mpll3_div = { .shift = 3, .width = 1, }, - .lock = &meson_clk_lock, .flags = CLK_MESON_MPLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ @@ -2187,4 +2181,4 @@ module_platform_driver(axg_driver); MODULE_DESCRIPTION("Amlogic AXG Main Clock Controller driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/c3-peripherals.c b/drivers/clk/meson/c3-peripherals.c index 7dcbf4ebee078a..2075668ed3062e 100644 --- a/drivers/clk/meson/c3-peripherals.c +++ b/drivers/clk/meson/c3-peripherals.c @@ -2364,4 +2364,4 @@ module_platform_driver(c3_peripherals_driver); MODULE_DESCRIPTION("Amlogic C3 Peripherals Clock Controller driver"); MODULE_AUTHOR("Chuan Liu "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/c3-pll.c b/drivers/clk/meson/c3-pll.c index 32bd2ed9d30441..ed4bc495862e1a 100644 --- a/drivers/clk/meson/c3-pll.c +++ b/drivers/clk/meson/c3-pll.c @@ -361,6 +361,7 @@ static struct clk_regmap hifi_pll_dco = { .range = &c3_gp0_pll_mult_range, .init_regs = c3_hifi_init_regs, .init_count = ARRAY_SIZE(c3_hifi_init_regs), + .frac_max = 100000, }, .hw.init = &(struct clk_init_data) { .name = "hifi_pll_dco", @@ -745,4 +746,4 @@ module_platform_driver(c3_pll_driver); MODULE_DESCRIPTION("Amlogic C3 PLL Clock Controller driver"); MODULE_AUTHOR("Chuan Liu "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-cpu-dyndiv.c b/drivers/clk/meson/clk-cpu-dyndiv.c index 6c1f58826e24a2..cb043b52b65d8a 100644 --- a/drivers/clk/meson/clk-cpu-dyndiv.c +++ b/drivers/clk/meson/clk-cpu-dyndiv.c @@ -65,9 +65,9 @@ const struct clk_ops meson_clk_cpu_dyndiv_ops = { .determine_rate = meson_clk_cpu_dyndiv_determine_rate, .set_rate = meson_clk_cpu_dyndiv_set_rate, }; -EXPORT_SYMBOL_NS_GPL(meson_clk_cpu_dyndiv_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_cpu_dyndiv_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic CPU Dynamic Clock divider"); MODULE_AUTHOR("Neil Armstrong "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-dualdiv.c b/drivers/clk/meson/clk-dualdiv.c index 913bf25d3771bd..c896cf29b318ca 100644 --- a/drivers/clk/meson/clk-dualdiv.c +++ b/drivers/clk/meson/clk-dualdiv.c @@ -130,15 +130,15 @@ const struct clk_ops meson_clk_dualdiv_ops = { .determine_rate = meson_clk_dualdiv_determine_rate, .set_rate = meson_clk_dualdiv_set_rate, }; -EXPORT_SYMBOL_NS_GPL(meson_clk_dualdiv_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_dualdiv_ops, "CLK_MESON"); const struct clk_ops meson_clk_dualdiv_ro_ops = { .recalc_rate = meson_clk_dualdiv_recalc_rate, }; -EXPORT_SYMBOL_NS_GPL(meson_clk_dualdiv_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_dualdiv_ro_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic dual divider driver"); MODULE_AUTHOR("Neil Armstrong "); MODULE_AUTHOR("Jerome Brunet "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index f639d56f0fd3f3..ee91e32b4050bf 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -112,26 +112,15 @@ static int mpll_set_rate(struct clk_hw *hw, struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); unsigned int sdm, n2; - unsigned long flags = 0; params_from_rate(rate, parent_rate, &sdm, &n2, mpll->flags); - if (mpll->lock) - spin_lock_irqsave(mpll->lock, flags); - else - __acquire(mpll->lock); - /* Set the fractional part */ meson_parm_write(clk->map, &mpll->sdm, sdm); /* Set the integer divider part */ meson_parm_write(clk->map, &mpll->n2, n2); - if (mpll->lock) - spin_unlock_irqrestore(mpll->lock, flags); - else - __release(mpll->lock); - return 0; } @@ -165,7 +154,7 @@ const struct clk_ops meson_clk_mpll_ro_ops = { .recalc_rate = mpll_recalc_rate, .determine_rate = mpll_determine_rate, }; -EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ro_ops, "CLK_MESON"); const struct clk_ops meson_clk_mpll_ops = { .recalc_rate = mpll_recalc_rate, @@ -173,9 +162,9 @@ const struct clk_ops meson_clk_mpll_ops = { .set_rate = mpll_set_rate, .init = mpll_init, }; -EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic MPLL driver"); MODULE_AUTHOR("Michael Turquette "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h index a991d568c43ae0..4ffd3aeef79952 100644 --- a/drivers/clk/meson/clk-mpll.h +++ b/drivers/clk/meson/clk-mpll.h @@ -20,7 +20,6 @@ struct meson_clk_mpll_data { struct parm misc; const struct reg_sequence *init_regs; unsigned int init_count; - spinlock_t *lock; u8 flags; }; diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c index c1526fbfb6c4cc..7012111206107a 100644 --- a/drivers/clk/meson/clk-phase.c +++ b/drivers/clk/meson/clk-phase.c @@ -61,7 +61,7 @@ const struct clk_ops meson_clk_phase_ops = { .get_phase = meson_clk_phase_get_phase, .set_phase = meson_clk_phase_set_phase, }; -EXPORT_SYMBOL_NS_GPL(meson_clk_phase_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_phase_ops, "CLK_MESON"); /* * This is a special clock for the audio controller. @@ -123,7 +123,7 @@ const struct clk_ops meson_clk_triphase_ops = { .get_phase = meson_clk_triphase_get_phase, .set_phase = meson_clk_triphase_set_phase, }; -EXPORT_SYMBOL_NS_GPL(meson_clk_triphase_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_triphase_ops, "CLK_MESON"); /* * This is a special clock for the audio controller. @@ -178,9 +178,9 @@ const struct clk_ops meson_sclk_ws_inv_ops = { .get_phase = meson_sclk_ws_inv_get_phase, .set_phase = meson_sclk_ws_inv_set_phase, }; -EXPORT_SYMBOL_NS_GPL(meson_sclk_ws_inv_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_sclk_ws_inv_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic phase driver"); MODULE_AUTHOR("Jerome Brunet "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index bc570a2ff3a3f8..e8e53855b00a81 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -57,12 +57,13 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate, struct meson_clk_pll_data *pll) { u64 rate = (u64)parent_rate * m; + unsigned int frac_max = pll->frac_max ? pll->frac_max : + (1 << pll->frac.width); if (frac && MESON_PARM_APPLICABLE(&pll->frac)) { u64 frac_rate = (u64)parent_rate * frac; - rate += DIV_ROUND_UP_ULL(frac_rate, - (1 << pll->frac.width)); + rate += DIV_ROUND_UP_ULL(frac_rate, frac_max); } return DIV_ROUND_UP_ULL(rate, n); @@ -100,7 +101,8 @@ static unsigned int __pll_params_with_frac(unsigned long rate, unsigned int n, struct meson_clk_pll_data *pll) { - unsigned int frac_max = (1 << pll->frac.width); + unsigned int frac_max = pll->frac_max ? pll->frac_max : + (1 << pll->frac.width); u64 val = (u64)rate * n; /* Bail out if we are already over the requested rate */ @@ -472,7 +474,7 @@ const struct clk_ops meson_clk_pcie_pll_ops = { .enable = meson_clk_pcie_pll_enable, .disable = meson_clk_pll_disable }; -EXPORT_SYMBOL_NS_GPL(meson_clk_pcie_pll_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_pcie_pll_ops, "CLK_MESON"); const struct clk_ops meson_clk_pll_ops = { .init = meson_clk_pll_init, @@ -483,16 +485,16 @@ const struct clk_ops meson_clk_pll_ops = { .enable = meson_clk_pll_enable, .disable = meson_clk_pll_disable }; -EXPORT_SYMBOL_NS_GPL(meson_clk_pll_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_pll_ops, "CLK_MESON"); const struct clk_ops meson_clk_pll_ro_ops = { .recalc_rate = meson_clk_pll_recalc_rate, .is_enabled = meson_clk_pll_is_enabled, }; -EXPORT_SYMBOL_NS_GPL(meson_clk_pll_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_pll_ro_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic PLL driver"); MODULE_AUTHOR("Carlo Caione "); MODULE_AUTHOR("Jerome Brunet "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h index 7b6b87274073d0..949157fb7bf55a 100644 --- a/drivers/clk/meson/clk-pll.h +++ b/drivers/clk/meson/clk-pll.h @@ -43,6 +43,7 @@ struct meson_clk_pll_data { unsigned int init_count; const struct pll_params_table *table; const struct pll_mult_range *range; + unsigned int frac_max; u8 flags; }; diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c index 07f7e441b9161c..f3e504f6757152 100644 --- a/drivers/clk/meson/clk-regmap.c +++ b/drivers/clk/meson/clk-regmap.c @@ -49,12 +49,12 @@ const struct clk_ops clk_regmap_gate_ops = { .disable = clk_regmap_gate_disable, .is_enabled = clk_regmap_gate_is_enabled, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ops, "CLK_MESON"); const struct clk_ops clk_regmap_gate_ro_ops = { .is_enabled = clk_regmap_gate_is_enabled, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ro_ops, "CLK_MESON"); static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, unsigned long prate) @@ -125,13 +125,13 @@ const struct clk_ops clk_regmap_divider_ops = { .determine_rate = clk_regmap_div_determine_rate, .set_rate = clk_regmap_div_set_rate, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ops, "CLK_MESON"); const struct clk_ops clk_regmap_divider_ro_ops = { .recalc_rate = clk_regmap_div_recalc_rate, .determine_rate = clk_regmap_div_determine_rate, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ro_ops, "CLK_MESON"); static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) { @@ -174,14 +174,14 @@ const struct clk_ops clk_regmap_mux_ops = { .set_parent = clk_regmap_mux_set_parent, .determine_rate = clk_regmap_mux_determine_rate, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ops, "CLK_MESON"); const struct clk_ops clk_regmap_mux_ro_ops = { .get_parent = clk_regmap_mux_get_parent, }; -EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ro_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic regmap backed clock driver"); MODULE_AUTHOR("Jerome Brunet "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c index f0a18d8c9fc231..71c758ffa4934d 100644 --- a/drivers/clk/meson/g12a-aoclk.c +++ b/drivers/clk/meson/g12a-aoclk.c @@ -477,4 +477,4 @@ module_platform_driver(g12a_aoclkc_driver); MODULE_DESCRIPTION("Amlogic G12A Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 02dda57105b10e..cfffd434e998ef 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -28,8 +28,6 @@ #include -static DEFINE_SPINLOCK(meson_clk_lock); - static struct clk_regmap g12a_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ .en = { @@ -2225,7 +2223,6 @@ static struct clk_regmap g12a_mpll0_div = { .shift = 29, .width = 1, }, - .lock = &meson_clk_lock, .init_regs = g12a_mpll0_init_regs, .init_count = ARRAY_SIZE(g12a_mpll0_init_regs), }, @@ -2279,7 +2276,6 @@ static struct clk_regmap g12a_mpll1_div = { .shift = 29, .width = 1, }, - .lock = &meson_clk_lock, .init_regs = g12a_mpll1_init_regs, .init_count = ARRAY_SIZE(g12a_mpll1_init_regs), }, @@ -2333,7 +2329,6 @@ static struct clk_regmap g12a_mpll2_div = { .shift = 29, .width = 1, }, - .lock = &meson_clk_lock, .init_regs = g12a_mpll2_init_regs, .init_count = ARRAY_SIZE(g12a_mpll2_init_regs), }, @@ -2387,7 +2382,6 @@ static struct clk_regmap g12a_mpll3_div = { .shift = 29, .width = 1, }, - .lock = &meson_clk_lock, .init_regs = g12a_mpll3_init_regs, .init_count = ARRAY_SIZE(g12a_mpll3_init_regs), }, @@ -5616,4 +5610,4 @@ module_platform_driver(g12a_driver); MODULE_DESCRIPTION("Amlogic G12/SM1 Main Clock Controller driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 83b034157b3534..43940232f71802 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -303,4 +303,4 @@ module_platform_driver(gxbb_aoclkc_driver); MODULE_DESCRIPTION("Amlogic GXBB Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index f071faad1ebb70..8575b848538598 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -19,8 +19,6 @@ #include -static DEFINE_SPINLOCK(meson_clk_lock); - static const struct pll_params_table gxbb_gp0_pll_params_table[] = { PLL_PARAMS(32, 1), PLL_PARAMS(33, 1), @@ -731,7 +729,6 @@ static struct clk_regmap gxbb_mpll0_div = { .shift = 16, .width = 9, }, - .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ .name = "mpll0_div", @@ -760,7 +757,6 @@ static struct clk_regmap gxl_mpll0_div = { .shift = 16, .width = 9, }, - .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ .name = "mpll0_div", @@ -812,7 +808,6 @@ static struct clk_regmap gxbb_mpll1_div = { .shift = 16, .width = 9, }, - .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ .name = "mpll1_div", @@ -855,7 +850,6 @@ static struct clk_regmap gxbb_mpll2_div = { .shift = 16, .width = 9, }, - .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ .name = "mpll2_div", @@ -3571,4 +3565,4 @@ module_platform_driver(gxbb_driver); MODULE_DESCRIPTION("Amlogic GXBB Main Clock Controller driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index 053940ee8940d7..995be51987f482 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -88,8 +88,8 @@ int meson_aoclkc_probe(struct platform_device *pdev) return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); } -EXPORT_SYMBOL_NS_GPL(meson_aoclkc_probe, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_aoclkc_probe, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic Always-ON Clock Controller helpers"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-clkc-utils.c b/drivers/clk/meson/meson-clkc-utils.c index a8cd2c21fab77f..6937d1482719bd 100644 --- a/drivers/clk/meson/meson-clkc-utils.c +++ b/drivers/clk/meson/meson-clkc-utils.c @@ -20,8 +20,8 @@ struct clk_hw *meson_clk_hw_get(struct of_phandle_args *clkspec, void *clk_hw_da return data->hws[idx]; } -EXPORT_SYMBOL_NS_GPL(meson_clk_hw_get, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_clk_hw_get, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic Clock Controller Utilities"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c index 66f79e384fe511..3053ee7425eb5c 100644 --- a/drivers/clk/meson/meson-eeclk.c +++ b/drivers/clk/meson/meson-eeclk.c @@ -57,8 +57,8 @@ int meson_eeclkc_probe(struct platform_device *pdev) return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); } -EXPORT_SYMBOL_NS_GPL(meson_eeclkc_probe, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_eeclkc_probe, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic Main Clock Controller Helpers"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index b7417ac262d33e..e4b474c5f86ce3 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -25,8 +25,6 @@ #include #include -static DEFINE_SPINLOCK(meson_clk_lock); - struct meson8b_clk_reset { struct reset_controller_dev reset; struct regmap *regmap; @@ -492,7 +490,6 @@ static struct clk_regmap meson8b_mpll0_div = { .shift = 25, .width = 1, }, - .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ .name = "mpll0_div", @@ -537,7 +534,6 @@ static struct clk_regmap meson8b_mpll1_div = { .shift = 16, .width = 9, }, - .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ .name = "mpll1_div", @@ -582,7 +578,6 @@ static struct clk_regmap meson8b_mpll2_div = { .shift = 16, .width = 9, }, - .lock = &meson_clk_lock, }, .hw.init = &(struct clk_init_data){ .name = "mpll2_div", @@ -3702,7 +3697,6 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, container_of(rcdev, struct meson8b_clk_reset, reset); const struct meson8b_clk_reset_line *reset; unsigned int value = 0; - unsigned long flags; if (id >= ARRAY_SIZE(meson8b_clk_reset_bits)) return -EINVAL; @@ -3712,13 +3706,9 @@ static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev, if (assert != reset->active_low) value = BIT(reset->bit_idx); - spin_lock_irqsave(&meson_clk_lock, flags); - regmap_update_bits(meson8b_clk_reset->regmap, reset->reg, BIT(reset->bit_idx), value); - spin_unlock_irqrestore(&meson_clk_lock, flags); - return 0; } diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index c930cf0614a0f4..8a403737778749 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -3814,4 +3814,4 @@ module_platform_driver(s4_driver); MODULE_DESCRIPTION("Amlogic S4 Peripherals Clock Controller driver"); MODULE_AUTHOR("Yu Tu "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/s4-pll.c b/drivers/clk/meson/s4-pll.c index b0258933fb9d25..f9cc05a506e395 100644 --- a/drivers/clk/meson/s4-pll.c +++ b/drivers/clk/meson/s4-pll.c @@ -17,8 +17,6 @@ #include "meson-clkc-utils.h" #include -static DEFINE_SPINLOCK(meson_clk_lock); - /* * These clock are a fixed value (fixed_pll is 2GHz) that is initialized by ROMcode. * The chip was changed fixed pll for security reasons. Fixed PLL registers are not writable @@ -329,7 +327,6 @@ static struct clk_regmap s4_gp0_pll = { * Internal hifi pll emulation configuration parameters */ static const struct reg_sequence s4_hifi_init_regs[] = { - { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00010e56 }, { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 }, { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 }, { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 }, @@ -354,6 +351,11 @@ static struct clk_regmap s4_hifi_pll_dco = { .shift = 10, .width = 5, }, + .frac = { + .reg_off = ANACTRL_HIFIPLL_CTRL1, + .shift = 0, + .width = 17, + }, .l = { .reg_off = ANACTRL_HIFIPLL_CTRL0, .shift = 31, @@ -367,6 +369,7 @@ static struct clk_regmap s4_hifi_pll_dco = { .range = &s4_gp0_pll_mult_range, .init_regs = s4_hifi_init_regs, .init_count = ARRAY_SIZE(s4_hifi_init_regs), + .frac_max = 100000, .flags = CLK_MESON_PLL_ROUND_CLOSEST, }, .hw.init = &(struct clk_init_data){ @@ -542,7 +545,6 @@ static struct clk_regmap s4_mpll0_div = { .shift = 29, .width = 1, }, - .lock = &meson_clk_lock, .init_regs = s4_mpll0_init_regs, .init_count = ARRAY_SIZE(s4_mpll0_init_regs), }, @@ -596,7 +598,6 @@ static struct clk_regmap s4_mpll1_div = { .shift = 29, .width = 1, }, - .lock = &meson_clk_lock, .init_regs = s4_mpll1_init_regs, .init_count = ARRAY_SIZE(s4_mpll1_init_regs), }, @@ -650,7 +651,6 @@ static struct clk_regmap s4_mpll2_div = { .shift = 29, .width = 1, }, - .lock = &meson_clk_lock, .init_regs = s4_mpll2_init_regs, .init_count = ARRAY_SIZE(s4_mpll2_init_regs), }, @@ -704,7 +704,6 @@ static struct clk_regmap s4_mpll3_div = { .shift = 29, .width = 1, }, - .lock = &meson_clk_lock, .init_regs = s4_mpll3_init_regs, .init_count = ARRAY_SIZE(s4_mpll3_init_regs), }, @@ -873,4 +872,4 @@ module_platform_driver(s4_driver); MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver"); MODULE_AUTHOR("Yu Tu "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c index ae03b048182f3b..9c4945234f2682 100644 --- a/drivers/clk/meson/sclk-div.c +++ b/drivers/clk/meson/sclk-div.c @@ -247,9 +247,9 @@ const struct clk_ops meson_sclk_div_ops = { .set_duty_cycle = sclk_div_set_duty_cycle, .init = sclk_div_init, }; -EXPORT_SYMBOL_NS_GPL(meson_sclk_div_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_sclk_div_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic Sample divider driver"); MODULE_AUTHOR("Jerome Brunet "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/vclk.c b/drivers/clk/meson/vclk.c index 36f637d2d01b5d..6a167ebdc8d74b 100644 --- a/drivers/clk/meson/vclk.c +++ b/drivers/clk/meson/vclk.c @@ -49,7 +49,7 @@ const struct clk_ops meson_vclk_gate_ops = { .disable = meson_vclk_gate_disable, .is_enabled = meson_vclk_gate_is_enabled, }; -EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops, "CLK_MESON"); /* The VCLK Divider has supplementary reset & enable bits */ @@ -134,9 +134,9 @@ const struct clk_ops meson_vclk_div_ops = { .disable = meson_vclk_div_disable, .is_enabled = meson_vclk_div_is_enabled, }; -EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic vclk clock driver"); MODULE_AUTHOR("Neil Armstrong "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c index 486cf68fc97a02..965ed7281f57ed 100644 --- a/drivers/clk/meson/vid-pll-div.c +++ b/drivers/clk/meson/vid-pll-div.c @@ -92,9 +92,9 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw, const struct clk_ops meson_vid_pll_div_ro_ops = { .recalc_rate = meson_vid_pll_div_recalc_rate, }; -EXPORT_SYMBOL_NS_GPL(meson_vid_pll_div_ro_ops, CLK_MESON); +EXPORT_SYMBOL_NS_GPL(meson_vid_pll_div_ro_ops, "CLK_MESON"); MODULE_DESCRIPTION("Amlogic video pll divider driver"); MODULE_AUTHOR("Neil Armstrong "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CLK_MESON); +MODULE_IMPORT_NS("CLK_MESON"); diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c index 28ec0da88cb389..c22632a7439c5d 100644 --- a/drivers/clk/microchip/clk-mpfs.c +++ b/drivers/clk/microchip/clk-mpfs.c @@ -443,4 +443,4 @@ MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver"); MODULE_AUTHOR("Padmarao Begari "); MODULE_AUTHOR("Daire McNamara "); MODULE_AUTHOR("Conor Dooley "); -MODULE_IMPORT_NS(MCHP_CLK_MPFS); +MODULE_IMPORT_NS("MCHP_CLK_MPFS"); diff --git a/drivers/clk/mmp/Makefile b/drivers/clk/mmp/Makefile index 441bf83080a12b..062cd87fa8ddcc 100644 --- a/drivers/clk/mmp/Makefile +++ b/drivers/clk/mmp/Makefile @@ -11,4 +11,4 @@ obj-$(CONFIG_MACH_MMP_DT) += clk-of-pxa168.o clk-of-pxa910.o obj-$(CONFIG_COMMON_CLK_MMP2) += clk-of-mmp2.o clk-pll.o pwr-island.o obj-$(CONFIG_COMMON_CLK_MMP2_AUDIO) += clk-audio.o -obj-y += clk-of-pxa1928.o +obj-$(CONFIG_ARCH_MMP) += clk-of-pxa1928.o clk-pxa1908-apbc.o clk-pxa1908-apbcp.o clk-pxa1908-apmu.o clk-pxa1908-mpmu.o diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c index 1b90867b60c4b5..6556f6ada2e830 100644 --- a/drivers/clk/mmp/clk-frac.c +++ b/drivers/clk/mmp/clk-frac.c @@ -26,14 +26,15 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long drate, { struct mmp_clk_factor *factor = to_clk_factor(hw); u64 rate = 0, prev_rate; + struct u32_fract *d; int i; for (i = 0; i < factor->ftbl_cnt; i++) { - prev_rate = rate; - rate = *prate; - rate *= factor->ftbl[i].den; - do_div(rate, factor->ftbl[i].num * factor->masks->factor); + d = &factor->ftbl[i]; + prev_rate = rate; + rate = (u64)(*prate) * d->denominator; + do_div(rate, d->numerator * factor->masks->factor); if (rate > drate) break; } @@ -52,23 +53,22 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, { struct mmp_clk_factor *factor = to_clk_factor(hw); struct mmp_clk_factor_masks *masks = factor->masks; - unsigned int val, num, den; + struct u32_fract d; + unsigned int val; u64 rate; val = readl_relaxed(factor->base); /* calculate numerator */ - num = (val >> masks->num_shift) & masks->num_mask; + d.numerator = (val >> masks->num_shift) & masks->num_mask; /* calculate denominator */ - den = (val >> masks->den_shift) & masks->den_mask; - - if (!den) + d.denominator = (val >> masks->den_shift) & masks->den_mask; + if (!d.denominator) return 0; - rate = parent_rate; - rate *= den; - do_div(rate, num * factor->masks->factor); + rate = (u64)parent_rate * d.denominator; + do_div(rate, d.numerator * factor->masks->factor); return rate; } @@ -82,18 +82,18 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, int i; unsigned long val; unsigned long flags = 0; + struct u32_fract *d; u64 rate = 0; for (i = 0; i < factor->ftbl_cnt; i++) { - rate = prate; - rate *= factor->ftbl[i].den; - do_div(rate, factor->ftbl[i].num * factor->masks->factor); + d = &factor->ftbl[i]; + rate = (u64)prate * d->denominator; + do_div(rate, d->numerator * factor->masks->factor); if (rate > drate) break; } - if (i > 0) - i--; + d = i ? &factor->ftbl[i - 1] : &factor->ftbl[0]; if (factor->lock) spin_lock_irqsave(factor->lock, flags); @@ -101,10 +101,10 @@ static int clk_factor_set_rate(struct clk_hw *hw, unsigned long drate, val = readl_relaxed(factor->base); val &= ~(masks->num_mask << masks->num_shift); - val |= (factor->ftbl[i].num & masks->num_mask) << masks->num_shift; + val |= (d->numerator & masks->num_mask) << masks->num_shift; val &= ~(masks->den_mask << masks->den_shift); - val |= (factor->ftbl[i].den & masks->den_mask) << masks->den_shift; + val |= (d->denominator & masks->den_mask) << masks->den_shift; writel_relaxed(val, factor->base); @@ -118,7 +118,8 @@ static int clk_factor_init(struct clk_hw *hw) { struct mmp_clk_factor *factor = to_clk_factor(hw); struct mmp_clk_factor_masks *masks = factor->masks; - u32 val, num, den; + struct u32_fract d; + u32 val; int i; unsigned long flags = 0; @@ -128,23 +129,22 @@ static int clk_factor_init(struct clk_hw *hw) val = readl(factor->base); /* calculate numerator */ - num = (val >> masks->num_shift) & masks->num_mask; + d.numerator = (val >> masks->num_shift) & masks->num_mask; /* calculate denominator */ - den = (val >> masks->den_shift) & masks->den_mask; + d.denominator = (val >> masks->den_shift) & masks->den_mask; for (i = 0; i < factor->ftbl_cnt; i++) - if (den == factor->ftbl[i].den && num == factor->ftbl[i].num) + if (d.denominator == factor->ftbl[i].denominator && + d.numerator == factor->ftbl[i].numerator) break; if (i >= factor->ftbl_cnt) { val &= ~(masks->num_mask << masks->num_shift); - val |= (factor->ftbl[0].num & masks->num_mask) << - masks->num_shift; + val |= (factor->ftbl[0].numerator & masks->num_mask) << masks->num_shift; val &= ~(masks->den_mask << masks->den_shift); - val |= (factor->ftbl[0].den & masks->den_mask) << - masks->den_shift; + val |= (factor->ftbl[0].denominator & masks->den_mask) << masks->den_shift; } if (!(val & masks->enable_mask) || i >= factor->ftbl_cnt) { @@ -168,8 +168,7 @@ static const struct clk_ops clk_factor_ops = { struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, unsigned long flags, void __iomem *base, struct mmp_clk_factor_masks *masks, - struct mmp_clk_factor_tbl *ftbl, - unsigned int ftbl_cnt, spinlock_t *lock) + struct u32_fract *ftbl, unsigned int ftbl_cnt, spinlock_t *lock) { struct mmp_clk_factor *factor; struct clk_init_data init; diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index eaad36ee323d14..a4f15cee630ee6 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -143,9 +143,9 @@ static struct mmp_clk_factor_masks uart_factor_masks = { .den_shift = 0, }; -static struct mmp_clk_factor_tbl uart_factor_tbl[] = { - {.num = 8125, .den = 1536}, /*14.745MHZ */ - {.num = 3521, .den = 689}, /*19.23MHZ */ +static struct u32_fract uart_factor_tbl[] = { + { .numerator = 8125, .denominator = 1536 }, /* 14.745MHZ */ + { .numerator = 3521, .denominator = 689 }, /* 19.23MHZ */ }; static struct mmp_clk_factor_masks i2s_factor_masks = { @@ -157,16 +157,16 @@ static struct mmp_clk_factor_masks i2s_factor_masks = { .enable_mask = 0xd0000000, }; -static struct mmp_clk_factor_tbl i2s_factor_tbl[] = { - {.num = 24868, .den = 511}, /* 2.0480 MHz */ - {.num = 28003, .den = 793}, /* 2.8224 MHz */ - {.num = 24941, .den = 1025}, /* 4.0960 MHz */ - {.num = 28003, .den = 1586}, /* 5.6448 MHz */ - {.num = 31158, .den = 2561}, /* 8.1920 MHz */ - {.num = 16288, .den = 1845}, /* 11.2896 MHz */ - {.num = 20772, .den = 2561}, /* 12.2880 MHz */ - {.num = 8144, .den = 1845}, /* 22.5792 MHz */ - {.num = 10386, .den = 2561}, /* 24.5760 MHz */ +static struct u32_fract i2s_factor_tbl[] = { + { .numerator = 24868, .denominator = 511 }, /* 2.0480 MHz */ + { .numerator = 28003, .denominator = 793 }, /* 2.8224 MHz */ + { .numerator = 24941, .denominator = 1025 }, /* 4.0960 MHz */ + { .numerator = 28003, .denominator = 1586 }, /* 5.6448 MHz */ + { .numerator = 31158, .denominator = 2561 }, /* 8.1920 MHz */ + { .numerator = 16288, .denominator = 1845 }, /* 11.2896 MHz */ + { .numerator = 20772, .denominator = 2561 }, /* 12.2880 MHz */ + { .numerator = 8144, .denominator = 1845 }, /* 22.5792 MHz */ + { .numerator = 10386, .denominator = 2561 }, /* 24.5760 MHz */ }; static DEFINE_SPINLOCK(acgr_lock); diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c index c5a7ba1deaa3a1..5f250427e60d25 100644 --- a/drivers/clk/mmp/clk-of-pxa168.c +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -106,8 +106,8 @@ static struct mmp_clk_factor_masks uart_factor_masks = { .den_shift = 0, }; -static struct mmp_clk_factor_tbl uart_factor_tbl[] = { - {.num = 8125, .den = 1536}, /*14.745MHZ */ +static struct u32_fract uart_factor_tbl[] = { + { .numerator = 8125, .denominator = 1536 }, /* 14.745MHZ */ }; static void pxa168_pll_init(struct pxa168_clk_unit *pxa_unit) diff --git a/drivers/clk/mmp/clk-of-pxa1928.c b/drivers/clk/mmp/clk-of-pxa1928.c index 9def4b5f10e910..ebb6e278eda33c 100644 --- a/drivers/clk/mmp/clk-of-pxa1928.c +++ b/drivers/clk/mmp/clk-of-pxa1928.c @@ -61,9 +61,9 @@ static struct mmp_clk_factor_masks uart_factor_masks = { .den_shift = 0, }; -static struct mmp_clk_factor_tbl uart_factor_tbl[] = { - {.num = 832, .den = 234}, /*58.5MHZ */ - {.num = 1, .den = 1}, /*26MHZ */ +static struct u32_fract uart_factor_tbl[] = { + { .numerator = 832, .denominator = 234 }, /* 58.5MHZ */ + { .numerator = 1, .denominator = 1 }, /* 26MHZ */ }; static void pxa1928_pll_init(struct pxa1928_clk_unit *pxa_unit) diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c index 7a38c424782e61..fe65e7bdb411fe 100644 --- a/drivers/clk/mmp/clk-of-pxa910.c +++ b/drivers/clk/mmp/clk-of-pxa910.c @@ -86,8 +86,8 @@ static struct mmp_clk_factor_masks uart_factor_masks = { .den_shift = 0, }; -static struct mmp_clk_factor_tbl uart_factor_tbl[] = { - {.num = 8125, .den = 1536}, /*14.745MHZ */ +static struct u32_fract uart_factor_tbl[] = { + { .numerator = 8125, .denominator = 1536 }, /* 14.745MHZ */ }; static void pxa910_pll_init(struct pxa910_clk_unit *pxa_unit) diff --git a/drivers/clk/mmp/clk-pxa1908-apbc.c b/drivers/clk/mmp/clk-pxa1908-apbc.c new file mode 100644 index 00000000000000..b93d0846619856 --- /dev/null +++ b/drivers/clk/mmp/clk-pxa1908-apbc.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define APBC_UART0 0x0 +#define APBC_UART1 0x4 +#define APBC_GPIO 0x8 +#define APBC_PWM0 0xc +#define APBC_PWM1 0x10 +#define APBC_PWM2 0x14 +#define APBC_PWM3 0x18 +#define APBC_SSP0 0x1c +#define APBC_SSP1 0x20 +#define APBC_IPC_RST 0x24 +#define APBC_RTC 0x28 +#define APBC_TWSI0 0x2c +#define APBC_KPC 0x30 +#define APBC_SWJTAG 0x40 +#define APBC_SSP2 0x4c +#define APBC_TWSI1 0x60 +#define APBC_THERMAL 0x6c +#define APBC_TWSI3 0x70 + +#define APBC_NR_CLKS 19 + +struct pxa1908_clk_unit { + struct mmp_clk_unit unit; + void __iomem *base; +}; + +static DEFINE_SPINLOCK(pwm0_lock); +static DEFINE_SPINLOCK(pwm2_lock); + +static DEFINE_SPINLOCK(uart0_lock); +static DEFINE_SPINLOCK(uart1_lock); + +static const char * const uart_parent_names[] = {"pll1_117", "uart_pll"}; +static const char * const ssp_parent_names[] = {"pll1_d16", "pll1_d48", "pll1_d24", "pll1_d12"}; + +static struct mmp_param_gate_clk apbc_gate_clks[] = { + {PXA1908_CLK_TWSI0, "twsi0_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x7, 3, 0, 0, NULL}, + {PXA1908_CLK_TWSI1, "twsi1_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x7, 3, 0, 0, NULL}, + {PXA1908_CLK_TWSI3, "twsi3_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI3, 0x7, 3, 0, 0, NULL}, + {PXA1908_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x7, 3, 0, 0, NULL}, + {PXA1908_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x7, 3, 0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA1908_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x87, 0x83, 0, MMP_CLK_GATE_NEED_DELAY, NULL}, + {PXA1908_CLK_PWM0, "pwm0_clk", "pwm01_apb_share", CLK_SET_RATE_PARENT, APBC_PWM0, 0x2, 2, 0, 0, &pwm0_lock}, + {PXA1908_CLK_PWM1, "pwm1_clk", "pwm01_apb_share", CLK_SET_RATE_PARENT, APBC_PWM1, 0x6, 2, 0, 0, NULL}, + {PXA1908_CLK_PWM2, "pwm2_clk", "pwm23_apb_share", CLK_SET_RATE_PARENT, APBC_PWM2, 0x2, 2, 0, 0, NULL}, + {PXA1908_CLK_PWM3, "pwm3_clk", "pwm23_apb_share", CLK_SET_RATE_PARENT, APBC_PWM3, 0x6, 2, 0, 0, NULL}, + {PXA1908_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x7, 3, 0, 0, &uart0_lock}, + {PXA1908_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x7, 3, 0, 0, &uart1_lock}, + {PXA1908_CLK_THERMAL, "thermal_clk", NULL, 0, APBC_THERMAL, 0x7, 3, 0, 0, NULL}, + {PXA1908_CLK_IPC_RST, "ipc_clk", NULL, 0, APBC_IPC_RST, 0x7, 3, 0, 0, NULL}, + {PXA1908_CLK_SSP0, "ssp0_clk", "ssp0_mux", 0, APBC_SSP0, 0x7, 3, 0, 0, NULL}, + {PXA1908_CLK_SSP2, "ssp2_clk", "ssp2_mux", 0, APBC_SSP2, 0x7, 3, 0, 0, NULL}, +}; + +static struct mmp_param_mux_clk apbc_mux_clks[] = { + {0, "uart0_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART0, 4, 3, 0, &uart0_lock}, + {0, "uart1_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBC_UART1, 4, 3, 0, &uart1_lock}, + {0, "ssp0_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), 0, APBC_SSP0, 4, 3, 0, NULL}, + {0, "ssp2_mux", ssp_parent_names, ARRAY_SIZE(ssp_parent_names), 0, APBC_SSP2, 4, 3, 0, NULL}, +}; + +static void pxa1908_apb_periph_clk_init(struct pxa1908_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + struct clk *clk; + + mmp_clk_register_gate(NULL, "pwm01_apb_share", "pll1_d48", + CLK_SET_RATE_PARENT, + pxa_unit->base + APBC_PWM0, + 0x5, 1, 0, 0, &pwm0_lock); + mmp_clk_register_gate(NULL, "pwm23_apb_share", "pll1_d48", + CLK_SET_RATE_PARENT, + pxa_unit->base + APBC_PWM2, + 0x5, 1, 0, 0, &pwm2_lock); + clk = mmp_clk_register_apbc("swjtag", NULL, + pxa_unit->base + APBC_SWJTAG, 10, 0, NULL); + mmp_clk_add(unit, PXA1908_CLK_SWJTAG, clk); + mmp_register_mux_clks(unit, apbc_mux_clks, pxa_unit->base, + ARRAY_SIZE(apbc_mux_clks)); + mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->base, + ARRAY_SIZE(apbc_gate_clks)); +} + +static int pxa1908_apbc_probe(struct platform_device *pdev) +{ + struct pxa1908_clk_unit *pxa_unit; + + pxa_unit = devm_kzalloc(&pdev->dev, sizeof(*pxa_unit), GFP_KERNEL); + if (IS_ERR(pxa_unit)) + return PTR_ERR(pxa_unit); + + pxa_unit->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pxa_unit->base)) + return PTR_ERR(pxa_unit->base); + + mmp_clk_init(pdev->dev.of_node, &pxa_unit->unit, APBC_NR_CLKS); + + pxa1908_apb_periph_clk_init(pxa_unit); + + return 0; +} + +static const struct of_device_id pxa1908_apbc_match_table[] = { + { .compatible = "marvell,pxa1908-apbc" }, + { } +}; +MODULE_DEVICE_TABLE(of, pxa1908_apbc_match_table); + +static struct platform_driver pxa1908_apbc_driver = { + .probe = pxa1908_apbc_probe, + .driver = { + .name = "pxa1908-apbc", + .of_match_table = pxa1908_apbc_match_table + } +}; +module_platform_driver(pxa1908_apbc_driver); + +MODULE_AUTHOR("Duje Mihanović "); +MODULE_DESCRIPTION("Marvell PXA1908 APBC Clock Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mmp/clk-pxa1908-apbcp.c b/drivers/clk/mmp/clk-pxa1908-apbcp.c new file mode 100644 index 00000000000000..08f3845cbb1bec --- /dev/null +++ b/drivers/clk/mmp/clk-pxa1908-apbcp.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define APBCP_UART2 0x1c +#define APBCP_TWSI2 0x28 +#define APBCP_AICER 0x38 + +#define APBCP_NR_CLKS 4 + +struct pxa1908_clk_unit { + struct mmp_clk_unit unit; + void __iomem *base; +}; + +static DEFINE_SPINLOCK(uart2_lock); + +static const char * const uart_parent_names[] = {"pll1_117", "uart_pll"}; + +static struct mmp_param_gate_clk apbcp_gate_clks[] = { + {PXA1908_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBCP_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock}, + {PXA1908_CLK_TWSI2, "twsi2_clk", "pll1_32", CLK_SET_RATE_PARENT, APBCP_TWSI2, 0x7, 0x3, 0x0, 0, NULL}, + {PXA1908_CLK_AICER, "ripc_clk", NULL, 0, APBCP_AICER, 0x7, 0x2, 0x0, 0, NULL}, +}; + +static struct mmp_param_mux_clk apbcp_mux_clks[] = { + {0, "uart2_mux", uart_parent_names, ARRAY_SIZE(uart_parent_names), CLK_SET_RATE_PARENT, APBCP_UART2, 4, 3, 0, &uart2_lock}, +}; + +static void pxa1908_apb_p_periph_clk_init(struct pxa1908_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_mux_clks(unit, apbcp_mux_clks, pxa_unit->base, + ARRAY_SIZE(apbcp_mux_clks)); + mmp_register_gate_clks(unit, apbcp_gate_clks, pxa_unit->base, + ARRAY_SIZE(apbcp_gate_clks)); +} + +static int pxa1908_apbcp_probe(struct platform_device *pdev) +{ + struct pxa1908_clk_unit *pxa_unit; + + pxa_unit = devm_kzalloc(&pdev->dev, sizeof(*pxa_unit), GFP_KERNEL); + if (IS_ERR(pxa_unit)) + return PTR_ERR(pxa_unit); + + pxa_unit->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pxa_unit->base)) + return PTR_ERR(pxa_unit->base); + + mmp_clk_init(pdev->dev.of_node, &pxa_unit->unit, APBCP_NR_CLKS); + + pxa1908_apb_p_periph_clk_init(pxa_unit); + + return 0; +} + +static const struct of_device_id pxa1908_apbcp_match_table[] = { + { .compatible = "marvell,pxa1908-apbcp" }, + { } +}; +MODULE_DEVICE_TABLE(of, pxa1908_apbcp_match_table); + +static struct platform_driver pxa1908_apbcp_driver = { + .probe = pxa1908_apbcp_probe, + .driver = { + .name = "pxa1908-apbcp", + .of_match_table = pxa1908_apbcp_match_table + } +}; +module_platform_driver(pxa1908_apbcp_driver); + +MODULE_AUTHOR("Duje Mihanović "); +MODULE_DESCRIPTION("Marvell PXA1908 APBCP Clock Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mmp/clk-pxa1908-apmu.c b/drivers/clk/mmp/clk-pxa1908-apmu.c new file mode 100644 index 00000000000000..8cfb1258202f6f --- /dev/null +++ b/drivers/clk/mmp/clk-pxa1908-apmu.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define APMU_CLK_GATE_CTRL 0x40 +#define APMU_CCIC1 0x24 +#define APMU_ISP 0x38 +#define APMU_DSI1 0x44 +#define APMU_DISP1 0x4c +#define APMU_CCIC0 0x50 +#define APMU_SDH0 0x54 +#define APMU_SDH1 0x58 +#define APMU_USB 0x5c +#define APMU_NF 0x60 +#define APMU_VPU 0xa4 +#define APMU_GC 0xcc +#define APMU_SDH2 0xe0 +#define APMU_GC2D 0xf4 +#define APMU_TRACE 0x108 +#define APMU_DVC_DFC_DEBUG 0x140 + +#define APMU_NR_CLKS 17 + +struct pxa1908_clk_unit { + struct mmp_clk_unit unit; + void __iomem *base; +}; + +static DEFINE_SPINLOCK(pll1_lock); +static struct mmp_param_general_gate_clk pll1_gate_clks[] = { + {PXA1908_CLK_PLL1_D2_GATE, "pll1_d2_gate", "pll1_d2", 0, APMU_CLK_GATE_CTRL, 29, 0, &pll1_lock}, + {PXA1908_CLK_PLL1_416_GATE, "pll1_416_gate", "pll1_416", 0, APMU_CLK_GATE_CTRL, 27, 0, &pll1_lock}, + {PXA1908_CLK_PLL1_624_GATE, "pll1_624_gate", "pll1_624", 0, APMU_CLK_GATE_CTRL, 26, 0, &pll1_lock}, + {PXA1908_CLK_PLL1_832_GATE, "pll1_832_gate", "pll1_832", 0, APMU_CLK_GATE_CTRL, 30, 0, &pll1_lock}, + {PXA1908_CLK_PLL1_1248_GATE, "pll1_1248_gate", "pll1_1248", 0, APMU_CLK_GATE_CTRL, 28, 0, &pll1_lock}, +}; + +static DEFINE_SPINLOCK(sdh0_lock); +static DEFINE_SPINLOCK(sdh1_lock); +static DEFINE_SPINLOCK(sdh2_lock); + +static const char * const sdh_parent_names[] = {"pll1_416", "pll1_624"}; + +static struct mmp_clk_mix_config sdh_mix_config = { + .reg_info = DEFINE_MIX_REG_INFO(3, 8, 2, 6, 11), +}; + +static struct mmp_param_gate_clk apmu_gate_clks[] = { + {PXA1908_CLK_USB, "usb_clk", NULL, 0, APMU_USB, 0x9, 0x9, 0x1, 0, NULL}, + {PXA1908_CLK_SDH0, "sdh0_clk", "sdh0_mix_clk", CLK_SET_RATE_PARENT | CLK_SET_RATE_UNGATE, APMU_SDH0, 0x12, 0x12, 0x0, 0, &sdh0_lock}, + {PXA1908_CLK_SDH1, "sdh1_clk", "sdh1_mix_clk", CLK_SET_RATE_PARENT | CLK_SET_RATE_UNGATE, APMU_SDH1, 0x12, 0x12, 0x0, 0, &sdh1_lock}, + {PXA1908_CLK_SDH2, "sdh2_clk", "sdh2_mix_clk", CLK_SET_RATE_PARENT | CLK_SET_RATE_UNGATE, APMU_SDH2, 0x12, 0x12, 0x0, 0, &sdh2_lock} +}; + +static void pxa1908_axi_periph_clk_init(struct pxa1908_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_general_gate_clks(unit, pll1_gate_clks, + pxa_unit->base, ARRAY_SIZE(pll1_gate_clks)); + + sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->base + APMU_SDH0; + mmp_clk_register_mix(NULL, "sdh0_mix_clk", sdh_parent_names, + ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, + &sdh_mix_config, &sdh0_lock); + sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->base + APMU_SDH1; + mmp_clk_register_mix(NULL, "sdh1_mix_clk", sdh_parent_names, + ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, + &sdh_mix_config, &sdh1_lock); + sdh_mix_config.reg_info.reg_clk_ctrl = pxa_unit->base + APMU_SDH2; + mmp_clk_register_mix(NULL, "sdh2_mix_clk", sdh_parent_names, + ARRAY_SIZE(sdh_parent_names), CLK_SET_RATE_PARENT, + &sdh_mix_config, &sdh2_lock); + + mmp_register_gate_clks(unit, apmu_gate_clks, pxa_unit->base, + ARRAY_SIZE(apmu_gate_clks)); +} + +static int pxa1908_apmu_probe(struct platform_device *pdev) +{ + struct pxa1908_clk_unit *pxa_unit; + + pxa_unit = devm_kzalloc(&pdev->dev, sizeof(*pxa_unit), GFP_KERNEL); + if (IS_ERR(pxa_unit)) + return PTR_ERR(pxa_unit); + + pxa_unit->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pxa_unit->base)) + return PTR_ERR(pxa_unit->base); + + mmp_clk_init(pdev->dev.of_node, &pxa_unit->unit, APMU_NR_CLKS); + + pxa1908_axi_periph_clk_init(pxa_unit); + + return 0; +} + +static const struct of_device_id pxa1908_apmu_match_table[] = { + { .compatible = "marvell,pxa1908-apmu" }, + { } +}; +MODULE_DEVICE_TABLE(of, pxa1908_apmu_match_table); + +static struct platform_driver pxa1908_apmu_driver = { + .probe = pxa1908_apmu_probe, + .driver = { + .name = "pxa1908-apmu", + .of_match_table = pxa1908_apmu_match_table + } +}; +module_platform_driver(pxa1908_apmu_driver); + +MODULE_AUTHOR("Duje Mihanović "); +MODULE_DESCRIPTION("Marvell PXA1908 APMU Clock Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mmp/clk-pxa1908-mpmu.c b/drivers/clk/mmp/clk-pxa1908-mpmu.c new file mode 100644 index 00000000000000..e3337bacaadd5a --- /dev/null +++ b/drivers/clk/mmp/clk-pxa1908-mpmu.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +#define MPMU_UART_PLL 0x14 + +#define MPMU_NR_CLKS 39 + +struct pxa1908_clk_unit { + struct mmp_clk_unit unit; + void __iomem *base; +}; + +static struct mmp_param_fixed_rate_clk fixed_rate_clks[] = { + {PXA1908_CLK_CLK32, "clk32", NULL, 0, 32768}, + {PXA1908_CLK_VCTCXO, "vctcxo", NULL, 0, 26 * HZ_PER_MHZ}, + {PXA1908_CLK_PLL1_624, "pll1_624", NULL, 0, 624 * HZ_PER_MHZ}, + {PXA1908_CLK_PLL1_416, "pll1_416", NULL, 0, 416 * HZ_PER_MHZ}, + {PXA1908_CLK_PLL1_499, "pll1_499", NULL, 0, 499 * HZ_PER_MHZ}, + {PXA1908_CLK_PLL1_832, "pll1_832", NULL, 0, 832 * HZ_PER_MHZ}, + {PXA1908_CLK_PLL1_1248, "pll1_1248", NULL, 0, 1248 * HZ_PER_MHZ}, +}; + +static struct mmp_param_fixed_factor_clk fixed_factor_clks[] = { + {PXA1908_CLK_PLL1_D2, "pll1_d2", "pll1_624", 1, 2, 0}, + {PXA1908_CLK_PLL1_D4, "pll1_d4", "pll1_d2", 1, 2, 0}, + {PXA1908_CLK_PLL1_D6, "pll1_d6", "pll1_d2", 1, 3, 0}, + {PXA1908_CLK_PLL1_D8, "pll1_d8", "pll1_d4", 1, 2, 0}, + {PXA1908_CLK_PLL1_D12, "pll1_d12", "pll1_d6", 1, 2, 0}, + {PXA1908_CLK_PLL1_D13, "pll1_d13", "pll1_624", 1, 13, 0}, + {PXA1908_CLK_PLL1_D16, "pll1_d16", "pll1_d8", 1, 2, 0}, + {PXA1908_CLK_PLL1_D24, "pll1_d24", "pll1_d12", 1, 2, 0}, + {PXA1908_CLK_PLL1_D48, "pll1_d48", "pll1_d24", 1, 2, 0}, + {PXA1908_CLK_PLL1_D96, "pll1_d96", "pll1_d48", 1, 2, 0}, + {PXA1908_CLK_PLL1_32, "pll1_32", "pll1_d13", 2, 3, 0}, + {PXA1908_CLK_PLL1_208, "pll1_208", "pll1_d2", 2, 3, 0}, + {PXA1908_CLK_PLL1_117, "pll1_117", "pll1_624", 3, 16, 0}, +}; + +static struct u32_fract uart_factor_tbl[] = { + {.numerator = 8125, .denominator = 1536}, /* 14.745MHz */ +}; + +static struct mmp_clk_factor_masks uart_factor_masks = { + .factor = 2, + .num_mask = GENMASK(12, 0), + .den_mask = GENMASK(12, 0), + .num_shift = 16, + .den_shift = 0, +}; + +static void pxa1908_pll_init(struct pxa1908_clk_unit *pxa_unit) +{ + struct mmp_clk_unit *unit = &pxa_unit->unit; + + mmp_register_fixed_rate_clks(unit, fixed_rate_clks, + ARRAY_SIZE(fixed_rate_clks)); + + mmp_register_fixed_factor_clks(unit, fixed_factor_clks, + ARRAY_SIZE(fixed_factor_clks)); + + mmp_clk_register_factor("uart_pll", "pll1_d4", + CLK_SET_RATE_PARENT, + pxa_unit->base + MPMU_UART_PLL, + &uart_factor_masks, uart_factor_tbl, + ARRAY_SIZE(uart_factor_tbl), NULL); +} + +static int pxa1908_mpmu_probe(struct platform_device *pdev) +{ + struct pxa1908_clk_unit *pxa_unit; + + pxa_unit = devm_kzalloc(&pdev->dev, sizeof(*pxa_unit), GFP_KERNEL); + if (IS_ERR(pxa_unit)) + return PTR_ERR(pxa_unit); + + pxa_unit->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pxa_unit->base)) + return PTR_ERR(pxa_unit->base); + + mmp_clk_init(pdev->dev.of_node, &pxa_unit->unit, MPMU_NR_CLKS); + + pxa1908_pll_init(pxa_unit); + + return 0; +} + +static const struct of_device_id pxa1908_mpmu_match_table[] = { + { .compatible = "marvell,pxa1908-mpmu" }, + { } +}; +MODULE_DEVICE_TABLE(of, pxa1908_mpmu_match_table); + +static struct platform_driver pxa1908_mpmu_driver = { + .probe = pxa1908_mpmu_probe, + .driver = { + .name = "pxa1908-mpmu", + .of_match_table = pxa1908_mpmu_match_table + } +}; +module_platform_driver(pxa1908_mpmu_driver); + +MODULE_AUTHOR("Duje Mihanović "); +MODULE_DESCRIPTION("Marvell PXA1908 MPMU Clock Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mmp/clk.h b/drivers/clk/mmp/clk.h index 55ac053797819e..c83cec169ddc5e 100644 --- a/drivers/clk/mmp/clk.h +++ b/drivers/clk/mmp/clk.h @@ -3,6 +3,7 @@ #define __MACH_MMP_CLK_H #include +#include #include #include @@ -20,16 +21,11 @@ struct mmp_clk_factor_masks { unsigned int enable_mask; }; -struct mmp_clk_factor_tbl { - unsigned int num; - unsigned int den; -}; - struct mmp_clk_factor { struct clk_hw hw; void __iomem *base; struct mmp_clk_factor_masks *masks; - struct mmp_clk_factor_tbl *ftbl; + struct u32_fract *ftbl; unsigned int ftbl_cnt; spinlock_t *lock; }; @@ -37,7 +33,7 @@ struct mmp_clk_factor { extern struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, unsigned long flags, void __iomem *base, struct mmp_clk_factor_masks *masks, - struct mmp_clk_factor_tbl *ftbl, unsigned int ftbl_cnt, + struct u32_fract *ftbl, unsigned int ftbl_cnt, spinlock_t *lock); /* Clock type "mix" */ diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index a3e2a09e2105b2..ef89d686cbc4e0 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -213,6 +213,14 @@ config IPQ_GCC_5332 Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, SD/eMMC, etc. +config IPQ_GCC_5424 + tristate "IPQ5424 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + help + Support for the global clock controller on ipq5424 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 @@ -467,6 +475,26 @@ config QCS_GCC_404 Say Y if you want to use multimedia devices or peripheral devices such as UART, SPI, I2C, USB, SD/eMMC, PCIe etc. +config SA_CAMCC_8775P + tristate "SA8775P Camera Clock Controller" + depends on ARM64 || COMPILE_TEST + select SA_GCC_8775P + help + Support for the camera clock controller on Qualcomm Technologies, Inc + SA8775P devices. + Say Y if you want to support camera devices and functionality such as + capturing pictures. + +config QCS_GCC_8300 + tristate "QCS8300 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on Qualcomm Technologies, Inc + QCS8300 devices. + Say Y if you want to use peripheral devices such as UART, + SPI, I2C, USB, SD/UFS, PCIe etc. + config SC_CAMCC_7180 tristate "SC7180 Camera Clock Controller" depends on ARM64 || COMPILE_TEST @@ -497,6 +525,16 @@ config SC_CAMCC_8280XP Say Y if you want to support camera devices and functionality such as capturing pictures. +config SA_DISPCC_8775P + tristate "SA8775P Display Clock Controller" + depends on ARM64 || COMPILE_TEST + select SA_GCC_8775P + help + Support for the two display clock controllers on Qualcomm + Technologies, Inc. SA8775P devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config SC_DISPCC_7180 tristate "SC7180 Display Clock Controller" depends on ARM64 || COMPILE_TEST @@ -545,6 +583,24 @@ config SA_GPUCC_8775P Say Y if you want to support graphics controller devices and functionality such as 3D graphics. +config SAR_GCC_2130P + tristate "SAR2130P Global Clock Controller" + select QCOM_GDSC + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on SAR2130P devices. + Say Y if you want to use peripheral devices such as UART, SPI, + I2C, USB, SDCC, etc. + +config SAR_GPUCC_2130P + tristate "SAR2130P Graphics clock controller" + select QCOM_GDSC + select SAR_GCC_2130P + help + Support for the graphics clock controller on SAR2130P 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 @@ -857,7 +913,7 @@ config SM_CAMCC_8450 depends on ARM64 || COMPILE_TEST select SM_GCC_8450 help - Support for the camera clock controller on SM8450 devices. + Support for the camera clock controller on SM8450 or SM8475 devices. Say Y if you want to support camera devices and camera functionality. config SM_CAMCC_8550 @@ -952,17 +1008,17 @@ config SM_DISPCC_8450 depends on SM_GCC_8450 help Support for the display clock controller on Qualcomm Technologies, Inc - SM8450 devices. + SM8450 or SM8475 devices. Say Y if you want to support display devices and functionality such as splash screen. config SM_DISPCC_8550 tristate "SM8550 Display Clock Controller" depends on ARM64 || COMPILE_TEST - depends on SM_GCC_8550 || SM_GCC_8650 + depends on SM_GCC_8550 || SM_GCC_8650 || SAR_GCC_2130P help Support for the display clock controller on Qualcomm Technologies, Inc - SM8550 or SM8650 devices. + SAR2130P, SM8550 or SM8650 devices. Say Y if you want to support display devices and functionality such as splash screen. @@ -987,6 +1043,7 @@ config SM_GCC_6115 config SM_GCC_6125 tristate "SM6125 Global Clock Controller" depends on ARM64 || COMPILE_TEST + select QCOM_GDSC help Support for the global clock controller on SM6125 devices. Say Y if you want to use peripheral devices such as UART, @@ -1050,7 +1107,8 @@ config SM_GCC_8450 depends on ARM64 || COMPILE_TEST select QCOM_GDSC help - Support for the global clock controller on SM8450 devices. + Support for the global clock controller on SM8450 or SM8475 + devices. Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD/UFS, PCIe etc. @@ -1149,7 +1207,8 @@ config SM_GPUCC_8450 depends on ARM64 || COMPILE_TEST select SM_GCC_8450 help - Support for the graphics clock controller on SM8450 devices. + Support for the graphics clock controller on SM8450 or SM8475 + devices. Say Y if you want to support graphics controller devices and functionality such as 3D graphics. @@ -1187,6 +1246,17 @@ config SM_TCSRCC_8650 Support for the TCSR clock controller on SM8650 devices. Say Y if you want to use peripheral devices such as SD/UFS. +config SA_VIDEOCC_8775P + tristate "SA8775P Video Clock Controller" + depends on ARM64 || COMPILE_TEST + select SA_GCC_8775P + select QCOM_GDSC + help + Support for the video clock controller on Qualcomm Technologies, Inc. + SA8775P devices. + Say Y if you want to support video devices and functionality such as + video encode/decode. + config SM_VIDEOCC_7150 tristate "SM7150 Video Clock Controller" depends on ARM64 || COMPILE_TEST @@ -1230,11 +1300,11 @@ config SM_VIDEOCC_8350 config SM_VIDEOCC_8550 tristate "SM8550 Video Clock Controller" depends on ARM64 || COMPILE_TEST - select SM_GCC_8550 + depends on SM_GCC_8550 || SM_GCC_8650 select QCOM_GDSC help Support for the video clock controller on Qualcomm Technologies, Inc. - SM8550 devices. + SM8550 or SM8650 devices. Say Y if you want to support video devices and functionality such as video encode/decode. @@ -1283,7 +1353,7 @@ config SM_VIDEOCC_8450 select QCOM_GDSC help Support for the video clock controller on Qualcomm Technologies, Inc. - SM8450 devices. + SM8450 or SM8475 devices. Say Y if you want to support video devices and functionality such as video encode/decode. endif diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 2b378667a63ff6..b09dbdc210eb1c 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o obj-$(CONFIG_IPQ_GCC_5018) += gcc-ipq5018.o obj-$(CONFIG_IPQ_GCC_5332) += gcc-ipq5332.o +obj-$(CONFIG_IPQ_GCC_5424) += gcc-ipq5424.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 @@ -70,6 +71,7 @@ obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_QCM_GCC_2290) += gcc-qcm2290.o obj-$(CONFIG_QCM_DISPCC_2290) += dispcc-qcm2290.o obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o +obj-$(CONFIG_QCS_GCC_8300) += gcc-qcs8300.o obj-$(CONFIG_QCS_Q6SSTOP_404) += q6sstop-qcs404.o obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o obj-$(CONFIG_QDU_ECPRICC_1000) += ecpricc-qdu1000.o @@ -80,8 +82,13 @@ obj-$(CONFIG_SC_CAMCC_8280XP) += camcc-sc8280xp.o 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_CAMCC_8775P) += camcc-sa8775p.o +obj-$(CONFIG_SA_DISPCC_8775P) += dispcc0-sa8775p.o dispcc1-sa8775p.o obj-$(CONFIG_SA_GCC_8775P) += gcc-sa8775p.o obj-$(CONFIG_SA_GPUCC_8775P) += gpucc-sa8775p.o +obj-$(CONFIG_SA_VIDEOCC_8775P) += videocc-sa8775p.o +obj-$(CONFIG_SAR_GCC_2130P) += gcc-sar2130p.o +obj-$(CONFIG_SAR_GPUCC_2130P) += gpucc-sar2130p.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 diff --git a/drivers/clk/qcom/camcc-sa8775p.c b/drivers/clk/qcom/camcc-sa8775p.c new file mode 100644 index 00000000000000..c04801a5af3508 --- /dev/null +++ b/drivers/clk/qcom/camcc-sa8775p.c @@ -0,0 +1,1868 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#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 "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_IFACE, + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, +}; + +enum { + P_BI_TCXO, + P_BI_TCXO_AO, + P_CAM_CC_PLL0_OUT_EVEN, + P_CAM_CC_PLL0_OUT_MAIN, + P_CAM_CC_PLL0_OUT_ODD, + P_CAM_CC_PLL2_OUT_EVEN, + P_CAM_CC_PLL2_OUT_MAIN, + P_CAM_CC_PLL3_OUT_EVEN, + P_CAM_CC_PLL4_OUT_EVEN, + P_CAM_CC_PLL5_OUT_EVEN, + P_SLEEP_CLK, +}; + +static const struct pll_vco lucid_evo_vco[] = { + { 249600000, 2020000000, 0 }, +}; + +static const struct pll_vco rivian_evo_vco[] = { + { 864000000, 1056000000, 0 }, +}; + +static const struct alpha_pll_config cam_cc_pll0_config = { + .l = 0x3e, + .alpha = 0x8000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00008400, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll cam_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 = "cam_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_evo_ops, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll0_out_odd[] = { + { 0x2, 3 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = { + .offset = 0x0, + .post_div_shift = 14, + .post_div_table = post_div_table_cam_cc_pll0_out_odd, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_odd), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll0_out_odd", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_evo_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll2_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x90008820, + .config_ctl_hi_val = 0x00890263, + .config_ctl_hi1_val = 0x00000247, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00400000, +}; + +static struct clk_alpha_pll cam_cc_pll2 = { + .offset = 0x1000, + .vco_table = rivian_evo_vco, + .num_vco = ARRAY_SIZE(rivian_evo_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_RIVIAN_EVO], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll2", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_rivian_evo_ops, + }, + }, +}; + +static const struct alpha_pll_config cam_cc_pll3_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll cam_cc_pll3 = { + .offset = 0x2000, + .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 = "cam_cc_pll3", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll3_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = { + .offset = 0x2000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll3_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll3_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll3_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll3.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_evo_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll4_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll cam_cc_pll4 = { + .offset = 0x3000, + .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 = "cam_cc_pll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll4_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll4_out_even = { + .offset = 0x3000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll4_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll4_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll4_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll4.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_evo_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll5_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll cam_cc_pll5 = { + .offset = 0x4000, + .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 = "cam_cc_pll5", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll5_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll5_out_even = { + .offset = 0x4000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll5_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll5_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll5_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll5.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_evo_ops, + }, +}; + +static const struct parent_map cam_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL0_OUT_MAIN, 1 }, + { P_CAM_CC_PLL0_OUT_EVEN, 2 }, + { P_CAM_CC_PLL0_OUT_ODD, 3 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll0.clkr.hw }, + { .hw = &cam_cc_pll0_out_even.clkr.hw }, + { .hw = &cam_cc_pll0_out_odd.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL2_OUT_EVEN, 3 }, + { P_CAM_CC_PLL2_OUT_MAIN, 5 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll2.clkr.hw }, + { .hw = &cam_cc_pll2.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL4_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll4_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL5_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll5_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL3_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll3_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_5[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_5[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map cam_cc_parent_map_6_ao[] = { + { P_BI_TCXO_AO, 0 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_6_ao[] = { + { .index = DT_BI_TCXO_AO }, +}; + +static const struct freq_tbl ftbl_cam_cc_camnoc_axi_clk_src[] = { + F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_camnoc_axi_clk_src = { + .cmd_rcgr = 0x13170, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_camnoc_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_camnoc_axi_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cci_0_clk_src[] = { + F(37500000, P_CAM_CC_PLL0_OUT_MAIN, 16, 1, 2), + { } +}; + +static struct clk_rcg2 cam_cc_cci_0_clk_src = { + .cmd_rcgr = 0x130a0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_0_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_cci_1_clk_src = { + .cmd_rcgr = 0x130bc, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_1_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_cci_2_clk_src = { + .cmd_rcgr = 0x130d8, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_2_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_cci_3_clk_src = { + .cmd_rcgr = 0x130f4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_3_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = { + F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cphy_rx_clk_src = { + .cmd_rcgr = 0x11034, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cphy_rx_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = { + .cmd_rcgr = 0x15074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi0phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = { + .cmd_rcgr = 0x15098, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi1phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = { + .cmd_rcgr = 0x150b8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi2phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = { + .cmd_rcgr = 0x150d8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi3phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csid_clk_src = { + .cmd_rcgr = 0x13150, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csid_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = { + F(300000000, P_CAM_CC_PLL0_OUT_MAIN, 4, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_fast_ahb_clk_src = { + .cmd_rcgr = 0x13120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_fast_ahb_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = { + F(480000000, P_CAM_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_icp_clk_src = { + .cmd_rcgr = 0x1307c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_icp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_icp_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = { + F(480000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_clk_src = { + .cmd_rcgr = 0x11004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_2, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_0_clk_src", + .parent_data = cam_cc_parent_data_2, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_1_clk_src[] = { + F(480000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_1_clk_src = { + .cmd_rcgr = 0x12004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_3, + .freq_tbl = ftbl_cam_cc_ife_1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_1_clk_src", + .parent_data = cam_cc_parent_data_3, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_lite_clk_src[] = { + F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(480000000, P_CAM_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_lite_clk_src = { + .cmd_rcgr = 0x13000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_lite_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = { + .cmd_rcgr = 0x13020, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_csid_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ipe_clk_src[] = { + F(480000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ipe_clk_src = { + .cmd_rcgr = 0x10004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_4, + .freq_tbl = ftbl_cam_cc_ipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_clk_src", + .parent_data = cam_cc_parent_data_4, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = { + F(19200000, P_CAM_CC_PLL2_OUT_MAIN, 1, 1, 50), + F(24000000, P_CAM_CC_PLL2_OUT_MAIN, 10, 1, 4), + F(64000000, P_CAM_CC_PLL2_OUT_MAIN, 15, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_mclk0_clk_src = { + .cmd_rcgr = 0x15004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk0_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk1_clk_src = { + .cmd_rcgr = 0x15020, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk1_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk2_clk_src = { + .cmd_rcgr = 0x1503c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk2_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk3_clk_src = { + .cmd_rcgr = 0x15058, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk3_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_sleep_clk_src = { + .cmd_rcgr = 0x131f0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_5, + .freq_tbl = ftbl_cam_cc_sleep_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sleep_clk_src", + .parent_data = cam_cc_parent_data_5, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = { + F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_slow_ahb_clk_src = { + .cmd_rcgr = 0x13138, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_slow_ahb_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_xo_clk_src[] = { + F(19200000, P_BI_TCXO_AO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_xo_clk_src = { + .cmd_rcgr = 0x131d4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_6_ao, + .freq_tbl = ftbl_cam_cc_xo_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_xo_clk_src", + .parent_data = cam_cc_parent_data_6_ao, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_6_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_branch cam_cc_camnoc_axi_clk = { + .halt_reg = 0x13188, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13188, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_camnoc_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_camnoc_dcd_xo_clk = { + .halt_reg = 0x13190, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13190, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_camnoc_dcd_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_qdss_debug_xo_clk = { + .halt_reg = 0x131b8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x131b8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_qdss_debug_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_0_clk = { + .halt_reg = 0x130b8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x130b8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cci_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_1_clk = { + .halt_reg = 0x130d4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x130d4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cci_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_2_clk = { + .halt_reg = 0x130f0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x130f0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cci_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_3_clk = { + .halt_reg = 0x1310c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1310c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cci_3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_core_ahb_clk = { + .halt_reg = 0x131d0, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x131d0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_core_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ahb_clk = { + .halt_reg = 0x13110, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13110, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_fast_ahb_clk = { + .halt_reg = 0x13118, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13118, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ife_0_clk = { + .halt_reg = 0x11024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ife_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ife_1_clk = { + .halt_reg = 0x12024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ife_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ife_lite_clk = { + .halt_reg = 0x1301c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1301c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ife_lite_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_lite_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ipe_clk = { + .halt_reg = 0x10024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_sfe_lite_0_clk = { + .halt_reg = 0x13050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_sfe_lite_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_sfe_lite_1_clk = { + .halt_reg = 0x13068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_sfe_lite_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi0phytimer_clk = { + .halt_reg = 0x1508c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1508c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi0phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi0phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi1phytimer_clk = { + .halt_reg = 0x150b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x150b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi1phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi1phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi2phytimer_clk = { + .halt_reg = 0x150d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x150d0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi2phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi2phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi3phytimer_clk = { + .halt_reg = 0x150f0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x150f0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi3phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi3phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csid_clk = { + .halt_reg = 0x13168, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13168, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csid_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csid_csiphy_rx_clk = { + .halt_reg = 0x15094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csid_csiphy_rx_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy0_clk = { + .halt_reg = 0x15090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy1_clk = { + .halt_reg = 0x150b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x150b4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy2_clk = { + .halt_reg = 0x150d4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x150d4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy2_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy3_clk = { + .halt_reg = 0x150f4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x150f4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy3_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_ahb_clk = { + .halt_reg = 0x1309c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1309c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_icp_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_clk = { + .halt_reg = 0x13094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_icp_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_icp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_clk = { + .halt_reg = 0x1101c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1101c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_fast_ahb_clk = { + .halt_reg = 0x11030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_0_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_clk = { + .halt_reg = 0x1201c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1201c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_fast_ahb_clk = { + .halt_reg = 0x12030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_1_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_ahb_clk = { + .halt_reg = 0x13044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_clk = { + .halt_reg = 0x13018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_lite_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = { + .halt_reg = 0x13040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_csid_clk = { + .halt_reg = 0x13038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_csid_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_lite_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_ahb_clk = { + .halt_reg = 0x10030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_clk = { + .halt_reg = 0x1001c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1001c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_fast_ahb_clk = { + .halt_reg = 0x10034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk0_clk = { + .halt_reg = 0x1501c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1501c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk1_clk = { + .halt_reg = 0x15038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk2_clk = { + .halt_reg = 0x15054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk2_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk3_clk = { + .halt_reg = 0x15070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk3_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sfe_lite_0_clk = { + .halt_reg = 0x1304c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1304c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_lite_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sfe_lite_0_fast_ahb_clk = { + .halt_reg = 0x1305c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1305c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_lite_0_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sfe_lite_1_clk = { + .halt_reg = 0x13064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_lite_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sfe_lite_1_fast_ahb_clk = { + .halt_reg = 0x13074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_lite_1_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sm_obs_clk = { + .halt_reg = 0x1510c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x1510c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sm_obs_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc cam_cc_titan_top_gdsc = { + .gdscr = 0x131bc, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_titan_top_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *cam_cc_sa8775p_clocks[] = { + [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr, + [CAM_CC_CAMNOC_AXI_CLK_SRC] = &cam_cc_camnoc_axi_clk_src.clkr, + [CAM_CC_CAMNOC_DCD_XO_CLK] = &cam_cc_camnoc_dcd_xo_clk.clkr, + [CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr, + [CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr, + [CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr, + [CAM_CC_CCI_1_CLK_SRC] = &cam_cc_cci_1_clk_src.clkr, + [CAM_CC_CCI_2_CLK] = &cam_cc_cci_2_clk.clkr, + [CAM_CC_CCI_2_CLK_SRC] = &cam_cc_cci_2_clk_src.clkr, + [CAM_CC_CCI_3_CLK] = &cam_cc_cci_3_clk.clkr, + [CAM_CC_CCI_3_CLK_SRC] = &cam_cc_cci_3_clk_src.clkr, + [CAM_CC_CORE_AHB_CLK] = &cam_cc_core_ahb_clk.clkr, + [CAM_CC_CPAS_AHB_CLK] = &cam_cc_cpas_ahb_clk.clkr, + [CAM_CC_CPAS_FAST_AHB_CLK] = &cam_cc_cpas_fast_ahb_clk.clkr, + [CAM_CC_CPAS_IFE_0_CLK] = &cam_cc_cpas_ife_0_clk.clkr, + [CAM_CC_CPAS_IFE_1_CLK] = &cam_cc_cpas_ife_1_clk.clkr, + [CAM_CC_CPAS_IFE_LITE_CLK] = &cam_cc_cpas_ife_lite_clk.clkr, + [CAM_CC_CPAS_IPE_CLK] = &cam_cc_cpas_ipe_clk.clkr, + [CAM_CC_CPAS_SFE_LITE_0_CLK] = &cam_cc_cpas_sfe_lite_0_clk.clkr, + [CAM_CC_CPAS_SFE_LITE_1_CLK] = &cam_cc_cpas_sfe_lite_1_clk.clkr, + [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr, + [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr, + [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr, + [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr, + [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr, + [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr, + [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr, + [CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr, + [CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr, + [CAM_CC_CSID_CLK] = &cam_cc_csid_clk.clkr, + [CAM_CC_CSID_CLK_SRC] = &cam_cc_csid_clk_src.clkr, + [CAM_CC_CSID_CSIPHY_RX_CLK] = &cam_cc_csid_csiphy_rx_clk.clkr, + [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr, + [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr, + [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr, + [CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr, + [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr, + [CAM_CC_ICP_AHB_CLK] = &cam_cc_icp_ahb_clk.clkr, + [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr, + [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr, + [CAM_CC_IFE_0_CLK] = &cam_cc_ife_0_clk.clkr, + [CAM_CC_IFE_0_CLK_SRC] = &cam_cc_ife_0_clk_src.clkr, + [CAM_CC_IFE_0_FAST_AHB_CLK] = &cam_cc_ife_0_fast_ahb_clk.clkr, + [CAM_CC_IFE_1_CLK] = &cam_cc_ife_1_clk.clkr, + [CAM_CC_IFE_1_CLK_SRC] = &cam_cc_ife_1_clk_src.clkr, + [CAM_CC_IFE_1_FAST_AHB_CLK] = &cam_cc_ife_1_fast_ahb_clk.clkr, + [CAM_CC_IFE_LITE_AHB_CLK] = &cam_cc_ife_lite_ahb_clk.clkr, + [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr, + [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr, + [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr, + [CAM_CC_IPE_AHB_CLK] = &cam_cc_ipe_ahb_clk.clkr, + [CAM_CC_IPE_CLK] = &cam_cc_ipe_clk.clkr, + [CAM_CC_IPE_CLK_SRC] = &cam_cc_ipe_clk_src.clkr, + [CAM_CC_IPE_FAST_AHB_CLK] = &cam_cc_ipe_fast_ahb_clk.clkr, + [CAM_CC_MCLK0_CLK] = &cam_cc_mclk0_clk.clkr, + [CAM_CC_MCLK0_CLK_SRC] = &cam_cc_mclk0_clk_src.clkr, + [CAM_CC_MCLK1_CLK] = &cam_cc_mclk1_clk.clkr, + [CAM_CC_MCLK1_CLK_SRC] = &cam_cc_mclk1_clk_src.clkr, + [CAM_CC_MCLK2_CLK] = &cam_cc_mclk2_clk.clkr, + [CAM_CC_MCLK2_CLK_SRC] = &cam_cc_mclk2_clk_src.clkr, + [CAM_CC_MCLK3_CLK] = &cam_cc_mclk3_clk.clkr, + [CAM_CC_MCLK3_CLK_SRC] = &cam_cc_mclk3_clk_src.clkr, + [CAM_CC_PLL0] = &cam_cc_pll0.clkr, + [CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.clkr, + [CAM_CC_PLL0_OUT_ODD] = &cam_cc_pll0_out_odd.clkr, + [CAM_CC_PLL2] = &cam_cc_pll2.clkr, + [CAM_CC_PLL3] = &cam_cc_pll3.clkr, + [CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr, + [CAM_CC_PLL4] = &cam_cc_pll4.clkr, + [CAM_CC_PLL4_OUT_EVEN] = &cam_cc_pll4_out_even.clkr, + [CAM_CC_PLL5] = &cam_cc_pll5.clkr, + [CAM_CC_PLL5_OUT_EVEN] = &cam_cc_pll5_out_even.clkr, + [CAM_CC_SFE_LITE_0_CLK] = &cam_cc_sfe_lite_0_clk.clkr, + [CAM_CC_SFE_LITE_0_FAST_AHB_CLK] = &cam_cc_sfe_lite_0_fast_ahb_clk.clkr, + [CAM_CC_SFE_LITE_1_CLK] = &cam_cc_sfe_lite_1_clk.clkr, + [CAM_CC_SFE_LITE_1_FAST_AHB_CLK] = &cam_cc_sfe_lite_1_fast_ahb_clk.clkr, + [CAM_CC_SLEEP_CLK_SRC] = &cam_cc_sleep_clk_src.clkr, + [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr, + [CAM_CC_SM_OBS_CLK] = &cam_cc_sm_obs_clk.clkr, + [CAM_CC_XO_CLK_SRC] = &cam_cc_xo_clk_src.clkr, + [CAM_CC_QDSS_DEBUG_XO_CLK] = &cam_cc_qdss_debug_xo_clk.clkr, +}; + +static struct gdsc *cam_cc_sa8775p_gdscs[] = { + [CAM_CC_TITAN_TOP_GDSC] = &cam_cc_titan_top_gdsc, +}; + +static const struct qcom_reset_map cam_cc_sa8775p_resets[] = { + [CAM_CC_ICP_BCR] = { 0x13078 }, + [CAM_CC_IFE_0_BCR] = { 0x11000 }, + [CAM_CC_IFE_1_BCR] = { 0x12000 }, + [CAM_CC_IPE_0_BCR] = { 0x10000 }, + [CAM_CC_SFE_LITE_0_BCR] = { 0x13048 }, + [CAM_CC_SFE_LITE_1_BCR] = { 0x13060 }, +}; + +static const struct regmap_config cam_cc_sa8775p_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x16218, + .fast_io = true, +}; + +static struct qcom_cc_desc cam_cc_sa8775p_desc = { + .config = &cam_cc_sa8775p_regmap_config, + .clks = cam_cc_sa8775p_clocks, + .num_clks = ARRAY_SIZE(cam_cc_sa8775p_clocks), + .resets = cam_cc_sa8775p_resets, + .num_resets = ARRAY_SIZE(cam_cc_sa8775p_resets), + .gdscs = cam_cc_sa8775p_gdscs, + .num_gdscs = ARRAY_SIZE(cam_cc_sa8775p_gdscs), +}; + +static const struct of_device_id cam_cc_sa8775p_match_table[] = { + { .compatible = "qcom,sa8775p-camcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, cam_cc_sa8775p_match_table); + +static int cam_cc_sa8775p_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + regmap = qcom_cc_map(pdev, &cam_cc_sa8775p_desc); + if (IS_ERR(regmap)) { + pm_runtime_put(&pdev->dev); + return PTR_ERR(regmap); + } + + clk_lucid_evo_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config); + clk_rivian_evo_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config); + clk_lucid_evo_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config); + clk_lucid_evo_pll_configure(&cam_cc_pll4, regmap, &cam_cc_pll4_config); + clk_lucid_evo_pll_configure(&cam_cc_pll5, regmap, &cam_cc_pll5_config); + + /* Keep some clocks always enabled */ + qcom_branch_set_clk_en(regmap, 0x13194); /* CAM_CC_CAMNOC_XO_CLK */ + qcom_branch_set_clk_en(regmap, 0x131ec); /* CAM_CC_GDSC_CLK */ + qcom_branch_set_clk_en(regmap, 0x13208); /* CAM_CC_SLEEP_CLK */ + + ret = qcom_cc_really_probe(&pdev->dev, &cam_cc_sa8775p_desc, regmap); + + pm_runtime_put(&pdev->dev); + + return ret; +} + +static struct platform_driver cam_cc_sa8775p_driver = { + .probe = cam_cc_sa8775p_probe, + .driver = { + .name = "camcc-sa8775p", + .of_match_table = cam_cc_sa8775p_match_table, + }, +}; + +module_platform_driver(cam_cc_sa8775p_driver); + +MODULE_DESCRIPTION("QTI CAMCC SA8775P Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/camcc-sm8450.c b/drivers/clk/qcom/camcc-sm8450.c index 26b78eed15efdb..08982737e4901c 100644 --- a/drivers/clk/qcom/camcc-sm8450.c +++ b/drivers/clk/qcom/camcc-sm8450.c @@ -54,6 +54,10 @@ static const struct pll_vco rivian_evo_vco[] = { { 864000000, 1056000000, 0 }, }; +static const struct pll_vco rivian_ole_vco[] = { + { 864000000, 1075000000, 0 }, +}; + static const struct clk_parent_data pll_parent_data_tcxo = { .index = DT_BI_TCXO }; static const struct alpha_pll_config cam_cc_pll0_config = { @@ -66,6 +70,20 @@ static const struct alpha_pll_config cam_cc_pll0_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_cam_cc_pll0_config = { + .l = 0x3e, + .alpha = 0x8000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00008400, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll cam_cc_pll0 = { .offset = 0x0, .vco_table = lucid_evo_vco, @@ -86,6 +104,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll0_out_even[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll0_out_even_init = { + .name = "cam_cc_pll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = { .offset = 0x0, .post_div_shift = 10, @@ -109,6 +137,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll0_out_odd[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll0_out_odd_init = { + .name = "cam_cc_pll0_out_odd", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = { .offset = 0x0, .post_div_shift = 14, @@ -137,6 +175,20 @@ static const struct alpha_pll_config cam_cc_pll1_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_cam_cc_pll1_config = { + .l = 0x25, + .alpha = 0xeaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll cam_cc_pll1 = { .offset = 0x1000, .vco_table = lucid_evo_vco, @@ -157,6 +209,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll1_out_even[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll1_out_even_init = { + .name = "cam_cc_pll1_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll1.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = { .offset = 0x1000, .post_div_shift = 10, @@ -183,6 +245,16 @@ static const struct alpha_pll_config cam_cc_pll2_config = { .config_ctl_hi1_val = 0x00000217, }; +static const struct alpha_pll_config sm8475_cam_cc_pll2_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x10000030, + .config_ctl_hi_val = 0x80890263, + .config_ctl_hi1_val = 0x00000217, + .user_ctl_val = 0x00000001, + .user_ctl_hi_val = 0x00000000, +}; + static struct clk_alpha_pll cam_cc_pll2 = { .offset = 0x2000, .vco_table = rivian_evo_vco, @@ -208,6 +280,20 @@ static const struct alpha_pll_config cam_cc_pll3_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_cam_cc_pll3_config = { + .l = 0x2d, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll cam_cc_pll3 = { .offset = 0x3000, .vco_table = lucid_evo_vco, @@ -228,6 +314,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll3_out_even[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll3_out_even_init = { + .name = "cam_cc_pll3_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll3.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = { .offset = 0x3000, .post_div_shift = 10, @@ -256,6 +352,20 @@ static const struct alpha_pll_config cam_cc_pll4_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_cam_cc_pll4_config = { + .l = 0x2d, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll cam_cc_pll4 = { .offset = 0x4000, .vco_table = lucid_evo_vco, @@ -276,6 +386,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll4_out_even[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll4_out_even_init = { + .name = "cam_cc_pll4_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll4.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll4_out_even = { .offset = 0x4000, .post_div_shift = 10, @@ -304,6 +424,20 @@ static const struct alpha_pll_config cam_cc_pll5_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_cam_cc_pll5_config = { + .l = 0x2d, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll cam_cc_pll5 = { .offset = 0x5000, .vco_table = lucid_evo_vco, @@ -324,6 +458,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll5_out_even[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll5_out_even_init = { + .name = "cam_cc_pll5_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll5.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll5_out_even = { .offset = 0x5000, .post_div_shift = 10, @@ -352,6 +496,20 @@ static const struct alpha_pll_config cam_cc_pll6_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_cam_cc_pll6_config = { + .l = 0x2d, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll cam_cc_pll6 = { .offset = 0x6000, .vco_table = lucid_evo_vco, @@ -372,6 +530,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll6_out_even[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll6_out_even_init = { + .name = "cam_cc_pll6_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll6.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll6_out_even = { .offset = 0x6000, .post_div_shift = 10, @@ -400,6 +568,20 @@ static const struct alpha_pll_config cam_cc_pll7_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_cam_cc_pll7_config = { + .l = 0x2d, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll cam_cc_pll7 = { .offset = 0x7000, .vco_table = lucid_evo_vco, @@ -420,6 +602,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll7_out_even[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll7_out_even_init = { + .name = "cam_cc_pll7_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll7.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll7_out_even = { .offset = 0x7000, .post_div_shift = 10, @@ -448,6 +640,20 @@ static const struct alpha_pll_config cam_cc_pll8_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_cam_cc_pll8_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll cam_cc_pll8 = { .offset = 0x8000, .vco_table = lucid_evo_vco, @@ -468,6 +674,16 @@ static const struct clk_div_table post_div_table_cam_cc_pll8_out_even[] = { { } }; +static struct clk_init_data sm8475_cam_cc_pll8_out_even_init = { + .name = "cam_cc_pll8_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll8.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static struct clk_alpha_pll_postdiv cam_cc_pll8_out_even = { .offset = 0x8000, .post_div_shift = 10, @@ -2817,6 +3033,7 @@ static const struct qcom_cc_desc cam_cc_sm8450_desc = { static const struct of_device_id cam_cc_sm8450_match_table[] = { { .compatible = "qcom,sm8450-camcc" }, + { .compatible = "qcom,sm8475-camcc" }, { } }; MODULE_DEVICE_TABLE(of, cam_cc_sm8450_match_table); @@ -2829,15 +3046,72 @@ static int cam_cc_sm8450_probe(struct platform_device *pdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); - clk_lucid_evo_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config); - clk_lucid_evo_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config); - clk_rivian_evo_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config); - clk_lucid_evo_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config); - clk_lucid_evo_pll_configure(&cam_cc_pll4, regmap, &cam_cc_pll4_config); - clk_lucid_evo_pll_configure(&cam_cc_pll5, regmap, &cam_cc_pll5_config); - clk_lucid_evo_pll_configure(&cam_cc_pll6, regmap, &cam_cc_pll6_config); - clk_lucid_evo_pll_configure(&cam_cc_pll7, regmap, &cam_cc_pll7_config); - clk_lucid_evo_pll_configure(&cam_cc_pll8, regmap, &cam_cc_pll8_config); + if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8475-camcc")) { + /* Update CAMCC PLL0 */ + cam_cc_pll0.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll0_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll0_out_even.clkr.hw.init = &sm8475_cam_cc_pll0_out_even_init; + cam_cc_pll0_out_odd.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll0_out_odd.clkr.hw.init = &sm8475_cam_cc_pll0_out_odd_init; + + /* Update CAMCC PLL1 */ + cam_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll1_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll1_out_even.clkr.hw.init = &sm8475_cam_cc_pll1_out_even_init; + + /* Update CAMCC PLL2 */ + cam_cc_pll2.vco_table = rivian_ole_vco; + + /* Update CAMCC PLL3 */ + cam_cc_pll3.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll3_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll3_out_even.clkr.hw.init = &sm8475_cam_cc_pll3_out_even_init; + + /* Update CAMCC PLL4 */ + cam_cc_pll4.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll4_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll4_out_even.clkr.hw.init = &sm8475_cam_cc_pll4_out_even_init; + + /* Update CAMCC PLL5 */ + cam_cc_pll5.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll5_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll5_out_even.clkr.hw.init = &sm8475_cam_cc_pll5_out_even_init; + + /* Update CAMCC PLL6 */ + cam_cc_pll6.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll6_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll6_out_even.clkr.hw.init = &sm8475_cam_cc_pll6_out_even_init; + + /* Update CAMCC PLL7 */ + cam_cc_pll7.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll7_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll7_out_even.clkr.hw.init = &sm8475_cam_cc_pll7_out_even_init; + + /* Update CAMCC PLL8 */ + cam_cc_pll8.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll8_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + cam_cc_pll8_out_even.clkr.hw.init = &sm8475_cam_cc_pll8_out_even_init; + + clk_lucid_ole_pll_configure(&cam_cc_pll0, regmap, &sm8475_cam_cc_pll0_config); + clk_lucid_ole_pll_configure(&cam_cc_pll1, regmap, &sm8475_cam_cc_pll1_config); + clk_rivian_evo_pll_configure(&cam_cc_pll2, regmap, &sm8475_cam_cc_pll2_config); + clk_lucid_ole_pll_configure(&cam_cc_pll3, regmap, &sm8475_cam_cc_pll3_config); + clk_lucid_ole_pll_configure(&cam_cc_pll4, regmap, &sm8475_cam_cc_pll4_config); + clk_lucid_ole_pll_configure(&cam_cc_pll5, regmap, &sm8475_cam_cc_pll5_config); + clk_lucid_ole_pll_configure(&cam_cc_pll6, regmap, &sm8475_cam_cc_pll6_config); + clk_lucid_ole_pll_configure(&cam_cc_pll7, regmap, &sm8475_cam_cc_pll7_config); + clk_lucid_ole_pll_configure(&cam_cc_pll8, regmap, &sm8475_cam_cc_pll8_config); + } else { + clk_lucid_evo_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config); + clk_lucid_evo_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config); + clk_rivian_evo_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config); + clk_lucid_evo_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config); + clk_lucid_evo_pll_configure(&cam_cc_pll4, regmap, &cam_cc_pll4_config); + clk_lucid_evo_pll_configure(&cam_cc_pll5, regmap, &cam_cc_pll5_config); + clk_lucid_evo_pll_configure(&cam_cc_pll6, regmap, &cam_cc_pll6_config); + clk_lucid_evo_pll_configure(&cam_cc_pll7, regmap, &cam_cc_pll7_config); + clk_lucid_evo_pll_configure(&cam_cc_pll8, regmap, &cam_cc_pll8_config); + } return qcom_cc_really_probe(&pdev->dev, &cam_cc_sm8450_desc, regmap); } @@ -2852,5 +3126,5 @@ static struct platform_driver cam_cc_sm8450_driver = { module_platform_driver(cam_cc_sm8450_driver); -MODULE_DESCRIPTION("QCOM CAMCC SM8450 Driver"); +MODULE_DESCRIPTION("QCOM CAMCC SM8450 / SM8475 Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index be9bee6ab65f6e..b8351f8c0b8401 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -267,6 +267,17 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_OPMODE] = 0x30, [PLL_OFF_STATUS] = 0x3c, }, + [CLK_ALPHA_PLL_TYPE_NSS_HUAYRA] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_ALPHA_VAL] = 0x08, + [PLL_OFF_TEST_CTL] = 0x0c, + [PLL_OFF_TEST_CTL_U] = 0x10, + [PLL_OFF_USER_CTL] = 0x14, + [PLL_OFF_CONFIG_CTL] = 0x18, + [PLL_OFF_CONFIG_CTL_U] = 0x1c, + [PLL_OFF_STATUS] = 0x20, + }, + }; EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); @@ -1903,9 +1914,8 @@ static int alpha_pll_lucid_5lpe_enable(struct clk_hw *hw) } /* Check if PLL is already enabled, return if enabled */ - ret = trion_pll_is_enabled(pll, pll->clkr.regmap); - if (ret < 0) - return ret; + if (trion_pll_is_enabled(pll, pll->clkr.regmap)) + return 0; ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); if (ret) @@ -2318,13 +2328,8 @@ static int alpha_pll_lucid_evo_enable(struct clk_hw *hw) } /* Check if PLL is already enabled */ - ret = trion_pll_is_enabled(pll, regmap); - if (ret < 0) { - return ret; - } else if (ret) { - pr_warn("%s PLL is already enabled\n", clk_hw_get_name(&pll->clkr.hw)); + if (trion_pll_is_enabled(pll, regmap)) return 0; - } ret = regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); if (ret) diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index 55eca04b23a1fc..c6d1b8429f951a 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -32,6 +32,7 @@ enum { CLK_ALPHA_PLL_TYPE_BRAMMO_EVO, CLK_ALPHA_PLL_TYPE_STROMER, CLK_ALPHA_PLL_TYPE_STROMER_PLUS, + CLK_ALPHA_PLL_TYPE_NSS_HUAYRA, CLK_ALPHA_PLL_TYPE_MAX, }; diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 8e0f3372dc7a83..80f1f4fcd52a68 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -198,6 +198,7 @@ extern const struct clk_ops clk_byte2_ops; extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_rcg2_shared_ops; +extern const struct clk_ops clk_rcg2_shared_floor_ops; extern const struct clk_ops clk_rcg2_shared_no_init_park_ops; extern const struct clk_ops clk_dp_ops; diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index bf26c5448f0067..bf6406f5279a4c 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1186,15 +1186,23 @@ clk_rcg2_shared_force_enable_clear(struct clk_hw *hw, const struct freq_tbl *f) return clk_rcg2_clear_force_enable(hw); } -static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static int __clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, + enum freq_policy policy) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f; - f = qcom_find_freq(rcg->freq_tbl, rate); - if (!f) + switch (policy) { + case FLOOR: + f = qcom_find_freq_floor(rcg->freq_tbl, rate); + break; + case CEIL: + f = qcom_find_freq(rcg->freq_tbl, rate); + break; + default: return -EINVAL; + } /* * In case clock is disabled, update the M, N and D registers, cache @@ -1207,10 +1215,28 @@ static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate, return clk_rcg2_shared_force_enable_clear(hw, f); } +static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, CEIL); +} + static int clk_rcg2_shared_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate, u8 index) { - return clk_rcg2_shared_set_rate(hw, rate, parent_rate); + return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, CEIL); +} + +static int clk_rcg2_shared_set_floor_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, FLOOR); +} + +static int clk_rcg2_shared_set_floor_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, FLOOR); } static int clk_rcg2_shared_enable(struct clk_hw *hw) @@ -1348,6 +1374,18 @@ const struct clk_ops clk_rcg2_shared_ops = { }; EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); +const struct clk_ops clk_rcg2_shared_floor_ops = { + .enable = clk_rcg2_shared_enable, + .disable = clk_rcg2_shared_disable, + .get_parent = clk_rcg2_shared_get_parent, + .set_parent = clk_rcg2_shared_set_parent, + .recalc_rate = clk_rcg2_shared_recalc_rate, + .determine_rate = clk_rcg2_determine_floor_rate, + .set_rate = clk_rcg2_shared_set_floor_rate, + .set_rate_and_parent = clk_rcg2_shared_set_floor_rate_and_parent, +}; +EXPORT_SYMBOL_GPL(clk_rcg2_shared_floor_ops); + static int clk_rcg2_shared_no_init_park(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 4acde937114af3..eefc322ce36798 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -389,6 +389,18 @@ DEFINE_CLK_RPMH_BCM(ipa, "IP0"); DEFINE_CLK_RPMH_BCM(pka, "PKA0"); DEFINE_CLK_RPMH_BCM(qpic_clk, "QP0"); +static struct clk_hw *sar2130p_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div1.hw, + [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div1_ao.hw, + [RPMH_RF_CLK1] = &clk_rpmh_rf_clk1_a.hw, + [RPMH_RF_CLK1_A] = &clk_rpmh_rf_clk1_a_ao.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_sar2130p = { + .clks = sar2130p_rpmh_clocks, + .num_clks = ARRAY_SIZE(sar2130p_rpmh_clocks), +}; + static struct clk_hw *sdm845_rpmh_clocks[] = { [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw, [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw, @@ -880,6 +892,7 @@ static int clk_rpmh_probe(struct platform_device *pdev) static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,qdu1000-rpmh-clk", .data = &clk_rpmh_qdu1000}, { .compatible = "qcom,sa8775p-rpmh-clk", .data = &clk_rpmh_sa8775p}, + { .compatible = "qcom,sar2130p-rpmh-clk", .data = &clk_rpmh_sar2130p}, { .compatible = "qcom,sc7180-rpmh-clk", .data = &clk_rpmh_sc7180}, { .compatible = "qcom,sc8180x-rpmh-clk", .data = &clk_rpmh_sc8180x}, { .compatible = "qcom,sc8280xp-rpmh-clk", .data = &clk_rpmh_sc8280xp}, diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 7e57f8fe8ea6bc..7ace5d7f5836aa 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -35,7 +35,7 @@ struct qcom_cc_desc { size_t num_gdscs; struct clk_hw **clk_hws; size_t num_clk_hws; - struct qcom_icc_hws_data *icc_hws; + const struct qcom_icc_hws_data *icc_hws; size_t num_icc_hws; unsigned int icc_first_node_id; }; diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c index d1d3f60789ee0b..a1f183e6c636ea 100644 --- a/drivers/clk/qcom/dispcc-sm8450.c +++ b/drivers/clk/qcom/dispcc-sm8450.c @@ -85,6 +85,29 @@ static const struct alpha_pll_config disp_cc_pll0_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_disp_cc_pll0_config = { + .l = 0xd, + .alpha = 0x6492, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_init_data sm8475_disp_cc_pll0_init = { + .name = "disp_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_reset_lucid_ole_ops, +}; + static struct clk_alpha_pll disp_cc_pll0 = { .offset = 0x0, .vco_table = lucid_evo_vco, @@ -112,6 +135,29 @@ static const struct alpha_pll_config disp_cc_pll1_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_disp_cc_pll1_config = { + .l = 0x1f, + .alpha = 0x4000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_init_data sm8475_disp_cc_pll1_init = { + .name = "disp_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_reset_lucid_ole_ops, +}; + static struct clk_alpha_pll disp_cc_pll1 = { .offset = 0x1000, .vco_table = lucid_evo_vco, @@ -1746,6 +1792,7 @@ static struct qcom_cc_desc disp_cc_sm8450_desc = { static const struct of_device_id disp_cc_sm8450_match_table[] = { { .compatible = "qcom,sm8450-dispcc" }, + { .compatible = "qcom,sm8475-dispcc" }, { } }; MODULE_DEVICE_TABLE(of, disp_cc_sm8450_match_table); @@ -1769,8 +1816,21 @@ static int disp_cc_sm8450_probe(struct platform_device *pdev) goto err_put_rpm; } - clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); - clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); + if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8475-dispcc")) { + /* Update DISPCC PLL0 */ + disp_cc_pll0.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + disp_cc_pll0.clkr.hw.init = &sm8475_disp_cc_pll0_init; + + /* Update DISPCC PLL1 */ + disp_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + disp_cc_pll1.clkr.hw.init = &sm8475_disp_cc_pll1_init; + + clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &sm8475_disp_cc_pll0_config); + clk_lucid_ole_pll_configure(&disp_cc_pll1, regmap, &sm8475_disp_cc_pll1_config); + } else { + clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); + clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); + } /* Enable clock gating for MDP clocks */ regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10); @@ -1802,5 +1862,5 @@ static struct platform_driver disp_cc_sm8450_driver = { module_platform_driver(disp_cc_sm8450_driver); -MODULE_DESCRIPTION("QTI DISPCC SM8450 Driver"); +MODULE_DESCRIPTION("QTI DISPCC SM8450 / SM8475 Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/dispcc-sm8550.c b/drivers/clk/qcom/dispcc-sm8550.c index 7f9021ca0ecb0e..e41d4104d77021 100644 --- a/drivers/clk/qcom/dispcc-sm8550.c +++ b/drivers/clk/qcom/dispcc-sm8550.c @@ -75,7 +75,7 @@ static struct pll_vco lucid_ole_vco[] = { { 249600000, 2000000000, 0 }, }; -static const struct alpha_pll_config disp_cc_pll0_config = { +static struct alpha_pll_config disp_cc_pll0_config = { .l = 0xd, .alpha = 0x6492, .config_ctl_val = 0x20485699, @@ -106,7 +106,7 @@ static struct clk_alpha_pll disp_cc_pll0 = { }, }; -static const struct alpha_pll_config disp_cc_pll1_config = { +static struct alpha_pll_config disp_cc_pll1_config = { .l = 0x1f, .alpha = 0x4000, .config_ctl_val = 0x20485699, @@ -594,6 +594,13 @@ static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { { } }; +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sar2130p[] = { + F(200000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(325000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(514000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + { } +}; + static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sm8650[] = { F(19200000, P_BI_TCXO, 1, 0, 0), F(85714286, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), @@ -1750,6 +1757,7 @@ static struct qcom_cc_desc disp_cc_sm8550_desc = { }; static const struct of_device_id disp_cc_sm8550_match_table[] = { + { .compatible = "qcom,sar2130p-dispcc" }, { .compatible = "qcom,sm8550-dispcc" }, { .compatible = "qcom,sm8650-dispcc" }, { } @@ -1780,6 +1788,12 @@ static int disp_cc_sm8550_probe(struct platform_device *pdev) disp_cc_mdss_mdp_clk_src.freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src_sm8650; disp_cc_mdss_dptx1_usb_router_link_intf_clk.clkr.hw.init->parent_hws[0] = &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw; + } else if (of_device_is_compatible(pdev->dev.of_node, "qcom,sar2130p-dispcc")) { + disp_cc_pll0_config.l = 0x1f; + disp_cc_pll0_config.alpha = 0x4000; + disp_cc_pll0_config.user_ctl_val = 0x1; + disp_cc_pll1_config.user_ctl_val = 0x1; + disp_cc_mdss_mdp_clk_src.freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src_sar2130p; } clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); diff --git a/drivers/clk/qcom/dispcc0-sa8775p.c b/drivers/clk/qcom/dispcc0-sa8775p.c new file mode 100644 index 00000000000000..6e399b5f138371 --- /dev/null +++ b/drivers/clk/qcom/dispcc0-sa8775p.c @@ -0,0 +1,1481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#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 "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_IFACE, + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, + DT_DP0_PHY_PLL_LINK_CLK, + DT_DP0_PHY_PLL_VCO_DIV_CLK, + DT_DP1_PHY_PLL_LINK_CLK, + DT_DP1_PHY_PLL_VCO_DIV_CLK, + DT_DSI0_PHY_PLL_OUT_BYTECLK, + DT_DSI0_PHY_PLL_OUT_DSICLK, + DT_DSI1_PHY_PLL_OUT_BYTECLK, + DT_DSI1_PHY_PLL_OUT_DSICLK, +}; + +enum { + P_BI_TCXO, + P_DP0_PHY_PLL_LINK_CLK, + P_DP0_PHY_PLL_VCO_DIV_CLK, + P_DP1_PHY_PLL_LINK_CLK, + P_DP1_PHY_PLL_VCO_DIV_CLK, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_MDSS_0_DISP_CC_PLL0_OUT_MAIN, + P_MDSS_0_DISP_CC_PLL1_OUT_EVEN, + P_MDSS_0_DISP_CC_PLL1_OUT_MAIN, + P_SLEEP_CLK, +}; + +static const struct pll_vco lucid_evo_vco[] = { + { 249600000, 2020000000, 0 }, +}; + +static const struct alpha_pll_config mdss_0_disp_cc_pll0_config = { + .l = 0x3a, + .alpha = 0x9800, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll mdss_0_disp_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 = "mdss_0_disp_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct alpha_pll_config mdss_0_disp_cc_pll1_config = { + .l = 0x1f, + .alpha = 0x4000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll mdss_0_disp_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 = "mdss_0_disp_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map disp_cc_0_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DP0_PHY_PLL_LINK_CLK, 1 }, + { P_DP0_PHY_PLL_VCO_DIV_CLK, 2 }, + { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP0_PHY_PLL_LINK_CLK }, + { .index = DT_DP0_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK }, +}; + +static const struct parent_map disp_cc_0_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 3 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK }, + { .index = DT_DSI1_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK }, +}; + +static const struct parent_map disp_cc_0_parent_map_2[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_2[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_2_ao[] = { + { .index = DT_BI_TCXO_AO }, +}; + +static const struct parent_map disp_cc_0_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DP0_PHY_PLL_LINK_CLK, 1 }, + { P_DP1_PHY_PLL_LINK_CLK, 2 }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP0_PHY_PLL_LINK_CLK }, + { .index = DT_DP1_PHY_PLL_LINK_CLK }, +}; + +static const struct parent_map disp_cc_0_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK }, + { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK }, +}; + +static const struct parent_map disp_cc_0_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_MDSS_0_DISP_CC_PLL1_OUT_MAIN, 4 }, + { P_MDSS_0_DISP_CC_PLL1_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &mdss_0_disp_cc_pll1.clkr.hw }, + { .hw = &mdss_0_disp_cc_pll1.clkr.hw }, +}; + +static const struct parent_map disp_cc_0_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_MDSS_0_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_MDSS_0_DISP_CC_PLL1_OUT_MAIN, 4 }, + { P_MDSS_0_DISP_CC_PLL1_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &mdss_0_disp_cc_pll0.clkr.hw }, + { .hw = &mdss_0_disp_cc_pll1.clkr.hw }, + { .hw = &mdss_0_disp_cc_pll1.clkr.hw }, +}; + +static const struct parent_map disp_cc_0_parent_map_7[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data disp_cc_0_parent_data_7[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct freq_tbl ftbl_mdss_0_disp_cc_mdss_ahb_clk_src[] = { + F(37500000, P_MDSS_0_DISP_CC_PLL1_OUT_MAIN, 16, 0, 0), + F(75000000, P_MDSS_0_DISP_CC_PLL1_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_ahb_clk_src = { + .cmd_rcgr = 0x824c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_5, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_ahb_clk_src", + .parent_data = disp_cc_0_parent_data_5, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_mdss_0_disp_cc_mdss_byte0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x80ec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_1, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_byte0_clk_src", + .parent_data = disp_cc_0_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_byte1_clk_src = { + .cmd_rcgr = 0x8108, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_1, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_byte1_clk_src", + .parent_data = disp_cc_0_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx0_aux_clk_src = { + .cmd_rcgr = 0x81b8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_2, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_aux_clk_src", + .parent_data = disp_cc_0_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx0_crypto_clk_src = { + .cmd_rcgr = 0x8170, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_3, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_crypto_clk_src", + .parent_data = disp_cc_0_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx0_link_clk_src = { + .cmd_rcgr = 0x8154, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_3, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_link_clk_src", + .parent_data = disp_cc_0_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx0_pixel0_clk_src = { + .cmd_rcgr = 0x8188, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_0, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_pixel0_clk_src", + .parent_data = disp_cc_0_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx0_pixel1_clk_src = { + .cmd_rcgr = 0x81a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_0, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_pixel1_clk_src", + .parent_data = disp_cc_0_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx0_pixel2_clk_src = { + .cmd_rcgr = 0x826c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_0, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_pixel2_clk_src", + .parent_data = disp_cc_0_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx0_pixel3_clk_src = { + .cmd_rcgr = 0x8284, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_0, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_pixel3_clk_src", + .parent_data = disp_cc_0_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx1_aux_clk_src = { + .cmd_rcgr = 0x8234, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_2, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_aux_clk_src", + .parent_data = disp_cc_0_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx1_crypto_clk_src = { + .cmd_rcgr = 0x821c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_3, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_crypto_clk_src", + .parent_data = disp_cc_0_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx1_link_clk_src = { + .cmd_rcgr = 0x8200, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_3, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_link_clk_src", + .parent_data = disp_cc_0_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx1_pixel0_clk_src = { + .cmd_rcgr = 0x81d0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_0, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_pixel0_clk_src", + .parent_data = disp_cc_0_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_dptx1_pixel1_clk_src = { + .cmd_rcgr = 0x81e8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_0, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_pixel1_clk_src", + .parent_data = disp_cc_0_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_esc0_clk_src = { + .cmd_rcgr = 0x8124, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_4, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_esc0_clk_src", + .parent_data = disp_cc_0_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_esc1_clk_src = { + .cmd_rcgr = 0x813c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_4, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_esc1_clk_src", + .parent_data = disp_cc_0_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_mdss_0_disp_cc_mdss_mdp_clk_src[] = { + F(375000000, P_MDSS_0_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(500000000, P_MDSS_0_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(575000000, P_MDSS_0_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(650000000, P_MDSS_0_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_mdp_clk_src = { + .cmd_rcgr = 0x80bc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_6, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_mdp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_mdp_clk_src", + .parent_data = disp_cc_0_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_pclk0_clk_src = { + .cmd_rcgr = 0x808c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_1, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_0_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_pclk1_clk_src = { + .cmd_rcgr = 0x80a4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_1, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_0_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_mdss_vsync_clk_src = { + .cmd_rcgr = 0x80d4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_2, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_vsync_clk_src", + .parent_data = disp_cc_0_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_mdss_0_disp_cc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 mdss_0_disp_cc_sleep_clk_src = { + .cmd_rcgr = 0xc058, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_7, + .freq_tbl = ftbl_mdss_0_disp_cc_sleep_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_sleep_clk_src", + .parent_data = disp_cc_0_parent_data_7, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_0_disp_cc_xo_clk_src = { + .cmd_rcgr = 0xc03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_0_parent_map_2, + .freq_tbl = ftbl_mdss_0_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_xo_clk_src", + .parent_data = disp_cc_0_parent_data_2_ao, + .num_parents = ARRAY_SIZE(disp_cc_0_parent_data_2_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div mdss_0_disp_cc_mdss_byte0_div_clk_src = { + .reg = 0x8104, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_byte0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, +}; + +static struct clk_regmap_div mdss_0_disp_cc_mdss_byte1_div_clk_src = { + .reg = 0x8120, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_byte1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, +}; + +static struct clk_regmap_div mdss_0_disp_cc_mdss_dptx0_link_div_clk_src = { + .reg = 0x816c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div mdss_0_disp_cc_mdss_dptx1_link_div_clk_src = { + .reg = 0x8218, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_ahb1_clk = { + .halt_reg = 0x8088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_ahb1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_ahb_clk = { + .halt_reg = 0x8084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_byte0_clk = { + .halt_reg = 0x8034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_byte0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_byte0_intf_clk = { + .halt_reg = 0x8038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_byte0_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_byte0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_byte1_clk = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_byte1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_byte1_intf_clk = { + .halt_reg = 0x8040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_byte1_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_byte1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_aux_clk = { + .halt_reg = 0x805c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x805c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_crypto_clk = { + .halt_reg = 0x8058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_crypto_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_crypto_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_link_clk = { + .halt_reg = 0x804c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x804c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_link_intf_clk = { + .halt_reg = 0x8050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_pixel0_clk = { + .halt_reg = 0x8060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_pixel1_clk = { + .halt_reg = 0x8064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_pixel2_clk = { + .halt_reg = 0x8264, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8264, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_pixel2_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_pixel2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_pixel3_clk = { + .halt_reg = 0x8268, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8268, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_pixel3_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_pixel3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx0_usb_router_link_intf_clk = { + .halt_reg = 0x8054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx0_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx1_aux_clk = { + .halt_reg = 0x8080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx1_crypto_clk = { + .halt_reg = 0x807c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x807c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_crypto_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx1_crypto_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx1_link_clk = { + .halt_reg = 0x8070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx1_link_intf_clk = { + .halt_reg = 0x8074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx1_pixel0_clk = { + .halt_reg = 0x8068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx1_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx1_pixel1_clk = { + .halt_reg = 0x806c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x806c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx1_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_dptx1_usb_router_link_intf_clk = { + .halt_reg = 0x8078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_dptx1_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_esc0_clk = { + .halt_reg = 0x8044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_esc0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_esc0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_esc1_clk = { + .halt_reg = 0x8048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_esc1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_esc1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_mdp1_clk = { + .halt_reg = 0x8014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_mdp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_mdp_clk = { + .halt_reg = 0x800c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x800c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_mdp_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_mdp_lut1_clk = { + .halt_reg = 0x8024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_mdp_lut1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_mdp_lut_clk = { + .halt_reg = 0x801c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x801c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_mdp_lut_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_non_gdsc_ahb_clk = { + .halt_reg = 0xa004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xa004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_non_gdsc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_pclk0_clk = { + .halt_reg = 0x8004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_pclk0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_pclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_pclk1_clk = { + .halt_reg = 0x8008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_pclk1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_pclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_pll_lock_monitor_clk = { + .halt_reg = 0xe000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_pll_lock_monitor_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_rscc_ahb_clk = { + .halt_reg = 0xa00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_rscc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_rscc_vsync_clk = { + .halt_reg = 0xa008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_rscc_vsync_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_vsync1_clk = { + .halt_reg = 0x8030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_vsync1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_mdss_vsync_clk = { + .halt_reg = 0x802c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x802c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_mdss_vsync_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_0_disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_0_disp_cc_sm_obs_clk = { + .halt_reg = 0x11014, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x11014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_0_disp_cc_sm_obs_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc mdss_0_disp_cc_mdss_core_gdsc = { + .gdscr = 0x9000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "mdss_0_disp_cc_mdss_core_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL, +}; + +static struct gdsc mdss_0_disp_cc_mdss_core_int2_gdsc = { + .gdscr = 0xd000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "mdss_0_disp_cc_mdss_core_int2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL, +}; + +static struct clk_regmap *disp_cc_0_sa8775p_clocks[] = { + [MDSS_DISP_CC_MDSS_AHB1_CLK] = &mdss_0_disp_cc_mdss_ahb1_clk.clkr, + [MDSS_DISP_CC_MDSS_AHB_CLK] = &mdss_0_disp_cc_mdss_ahb_clk.clkr, + [MDSS_DISP_CC_MDSS_AHB_CLK_SRC] = &mdss_0_disp_cc_mdss_ahb_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE0_CLK] = &mdss_0_disp_cc_mdss_byte0_clk.clkr, + [MDSS_DISP_CC_MDSS_BYTE0_CLK_SRC] = &mdss_0_disp_cc_mdss_byte0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &mdss_0_disp_cc_mdss_byte0_div_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE0_INTF_CLK] = &mdss_0_disp_cc_mdss_byte0_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_BYTE1_CLK] = &mdss_0_disp_cc_mdss_byte1_clk.clkr, + [MDSS_DISP_CC_MDSS_BYTE1_CLK_SRC] = &mdss_0_disp_cc_mdss_byte1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &mdss_0_disp_cc_mdss_byte1_div_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE1_INTF_CLK] = &mdss_0_disp_cc_mdss_byte1_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK] = &mdss_0_disp_cc_mdss_dptx0_aux_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx0_aux_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_CRYPTO_CLK] = &mdss_0_disp_cc_mdss_dptx0_crypto_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_CRYPTO_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx0_crypto_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK] = &mdss_0_disp_cc_mdss_dptx0_link_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx0_link_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC] = + &mdss_0_disp_cc_mdss_dptx0_link_div_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_LINK_INTF_CLK] = &mdss_0_disp_cc_mdss_dptx0_link_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK] = &mdss_0_disp_cc_mdss_dptx0_pixel0_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx0_pixel0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK] = &mdss_0_disp_cc_mdss_dptx0_pixel1_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx0_pixel1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK] = &mdss_0_disp_cc_mdss_dptx0_pixel2_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx0_pixel2_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK] = &mdss_0_disp_cc_mdss_dptx0_pixel3_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx0_pixel3_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK] = + &mdss_0_disp_cc_mdss_dptx0_usb_router_link_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_AUX_CLK] = &mdss_0_disp_cc_mdss_dptx1_aux_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_AUX_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx1_aux_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_CRYPTO_CLK] = &mdss_0_disp_cc_mdss_dptx1_crypto_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_CRYPTO_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx1_crypto_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_LINK_CLK] = &mdss_0_disp_cc_mdss_dptx1_link_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_LINK_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx1_link_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC] = + &mdss_0_disp_cc_mdss_dptx1_link_div_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_LINK_INTF_CLK] = &mdss_0_disp_cc_mdss_dptx1_link_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_PIXEL0_CLK] = &mdss_0_disp_cc_mdss_dptx1_pixel0_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx1_pixel0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_PIXEL1_CLK] = &mdss_0_disp_cc_mdss_dptx1_pixel1_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC] = &mdss_0_disp_cc_mdss_dptx1_pixel1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK] = + &mdss_0_disp_cc_mdss_dptx1_usb_router_link_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_ESC0_CLK] = &mdss_0_disp_cc_mdss_esc0_clk.clkr, + [MDSS_DISP_CC_MDSS_ESC0_CLK_SRC] = &mdss_0_disp_cc_mdss_esc0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_ESC1_CLK] = &mdss_0_disp_cc_mdss_esc1_clk.clkr, + [MDSS_DISP_CC_MDSS_ESC1_CLK_SRC] = &mdss_0_disp_cc_mdss_esc1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_MDP1_CLK] = &mdss_0_disp_cc_mdss_mdp1_clk.clkr, + [MDSS_DISP_CC_MDSS_MDP_CLK] = &mdss_0_disp_cc_mdss_mdp_clk.clkr, + [MDSS_DISP_CC_MDSS_MDP_CLK_SRC] = &mdss_0_disp_cc_mdss_mdp_clk_src.clkr, + [MDSS_DISP_CC_MDSS_MDP_LUT1_CLK] = &mdss_0_disp_cc_mdss_mdp_lut1_clk.clkr, + [MDSS_DISP_CC_MDSS_MDP_LUT_CLK] = &mdss_0_disp_cc_mdss_mdp_lut_clk.clkr, + [MDSS_DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &mdss_0_disp_cc_mdss_non_gdsc_ahb_clk.clkr, + [MDSS_DISP_CC_MDSS_PCLK0_CLK] = &mdss_0_disp_cc_mdss_pclk0_clk.clkr, + [MDSS_DISP_CC_MDSS_PCLK0_CLK_SRC] = &mdss_0_disp_cc_mdss_pclk0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_PCLK1_CLK] = &mdss_0_disp_cc_mdss_pclk1_clk.clkr, + [MDSS_DISP_CC_MDSS_PCLK1_CLK_SRC] = &mdss_0_disp_cc_mdss_pclk1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_PLL_LOCK_MONITOR_CLK] = &mdss_0_disp_cc_mdss_pll_lock_monitor_clk.clkr, + [MDSS_DISP_CC_MDSS_RSCC_AHB_CLK] = &mdss_0_disp_cc_mdss_rscc_ahb_clk.clkr, + [MDSS_DISP_CC_MDSS_RSCC_VSYNC_CLK] = &mdss_0_disp_cc_mdss_rscc_vsync_clk.clkr, + [MDSS_DISP_CC_MDSS_VSYNC1_CLK] = &mdss_0_disp_cc_mdss_vsync1_clk.clkr, + [MDSS_DISP_CC_MDSS_VSYNC_CLK] = &mdss_0_disp_cc_mdss_vsync_clk.clkr, + [MDSS_DISP_CC_MDSS_VSYNC_CLK_SRC] = &mdss_0_disp_cc_mdss_vsync_clk_src.clkr, + [MDSS_DISP_CC_PLL0] = &mdss_0_disp_cc_pll0.clkr, + [MDSS_DISP_CC_PLL1] = &mdss_0_disp_cc_pll1.clkr, + [MDSS_DISP_CC_SLEEP_CLK_SRC] = &mdss_0_disp_cc_sleep_clk_src.clkr, + [MDSS_DISP_CC_SM_OBS_CLK] = &mdss_0_disp_cc_sm_obs_clk.clkr, + [MDSS_DISP_CC_XO_CLK_SRC] = &mdss_0_disp_cc_xo_clk_src.clkr, +}; + +static struct gdsc *disp_cc_0_sa8775p_gdscs[] = { + [MDSS_DISP_CC_MDSS_CORE_GDSC] = &mdss_0_disp_cc_mdss_core_gdsc, + [MDSS_DISP_CC_MDSS_CORE_INT2_GDSC] = &mdss_0_disp_cc_mdss_core_int2_gdsc, +}; + +static const struct qcom_reset_map disp_cc_0_sa8775p_resets[] = { + [MDSS_DISP_CC_MDSS_CORE_BCR] = { 0x8000 }, + [MDSS_DISP_CC_MDSS_RSCC_BCR] = { 0xa000 }, +}; + +static const struct regmap_config disp_cc_0_sa8775p_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x12414, + .fast_io = true, +}; + +static struct qcom_cc_desc disp_cc_0_sa8775p_desc = { + .config = &disp_cc_0_sa8775p_regmap_config, + .clks = disp_cc_0_sa8775p_clocks, + .num_clks = ARRAY_SIZE(disp_cc_0_sa8775p_clocks), + .resets = disp_cc_0_sa8775p_resets, + .num_resets = ARRAY_SIZE(disp_cc_0_sa8775p_resets), + .gdscs = disp_cc_0_sa8775p_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_0_sa8775p_gdscs), +}; + +static const struct of_device_id disp_cc_0_sa8775p_match_table[] = { + { .compatible = "qcom,sa8775p-dispcc0" }, + { } +}; +MODULE_DEVICE_TABLE(of, disp_cc_0_sa8775p_match_table); + +static int disp_cc_0_sa8775p_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + regmap = qcom_cc_map(pdev, &disp_cc_0_sa8775p_desc); + if (IS_ERR(regmap)) { + pm_runtime_put(&pdev->dev); + return PTR_ERR(regmap); + } + + clk_lucid_evo_pll_configure(&mdss_0_disp_cc_pll0, regmap, &mdss_0_disp_cc_pll0_config); + clk_lucid_evo_pll_configure(&mdss_0_disp_cc_pll1, regmap, &mdss_0_disp_cc_pll1_config); + + /* Keep some clocks always enabled */ + qcom_branch_set_clk_en(regmap, 0xc070); /* MDSS_0_DISP_CC_SLEEP_CLK */ + qcom_branch_set_clk_en(regmap, 0xc054); /* MDSS_0_DISP_CC_XO_CLK */ + + ret = qcom_cc_really_probe(&pdev->dev, &disp_cc_0_sa8775p_desc, regmap); + + pm_runtime_put(&pdev->dev); + + return ret; +} + +static struct platform_driver disp_cc_0_sa8775p_driver = { + .probe = disp_cc_0_sa8775p_probe, + .driver = { + .name = "dispcc0-sa8775p", + .of_match_table = disp_cc_0_sa8775p_match_table, + }, +}; + +module_platform_driver(disp_cc_0_sa8775p_driver); + +MODULE_DESCRIPTION("QTI DISPCC0 SA8775P Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/dispcc1-sa8775p.c b/drivers/clk/qcom/dispcc1-sa8775p.c new file mode 100644 index 00000000000000..30ccea59415a4e --- /dev/null +++ b/drivers/clk/qcom/dispcc1-sa8775p.c @@ -0,0 +1,1481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#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 "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_IFACE, + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, + DT_DP0_PHY_PLL_LINK_CLK, + DT_DP0_PHY_PLL_VCO_DIV_CLK, + DT_DP1_PHY_PLL_LINK_CLK, + DT_DP1_PHY_PLL_VCO_DIV_CLK, + DT_DSI0_PHY_PLL_OUT_BYTECLK, + DT_DSI0_PHY_PLL_OUT_DSICLK, + DT_DSI1_PHY_PLL_OUT_BYTECLK, + DT_DSI1_PHY_PLL_OUT_DSICLK, +}; + +enum { + P_BI_TCXO, + P_DP0_PHY_PLL_LINK_CLK, + P_DP0_PHY_PLL_VCO_DIV_CLK, + P_DP1_PHY_PLL_LINK_CLK, + P_DP1_PHY_PLL_VCO_DIV_CLK, + P_DSI0_PHY_PLL_OUT_BYTECLK, + P_DSI0_PHY_PLL_OUT_DSICLK, + P_DSI1_PHY_PLL_OUT_BYTECLK, + P_DSI1_PHY_PLL_OUT_DSICLK, + P_MDSS_1_DISP_CC_PLL0_OUT_MAIN, + P_MDSS_1_DISP_CC_PLL1_OUT_EVEN, + P_MDSS_1_DISP_CC_PLL1_OUT_MAIN, + P_SLEEP_CLK, +}; + +static const struct pll_vco lucid_evo_vco[] = { + { 249600000, 2020000000, 0 }, +}; + +static const struct alpha_pll_config mdss_1_disp_cc_pll0_config = { + .l = 0x3a, + .alpha = 0x9800, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll mdss_1_disp_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 = "mdss_1_disp_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct alpha_pll_config mdss_1_disp_cc_pll1_config = { + .l = 0x1f, + .alpha = 0x4000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll mdss_1_disp_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 = "mdss_1_disp_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map disp_cc_1_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_DP0_PHY_PLL_LINK_CLK, 1 }, + { P_DP0_PHY_PLL_VCO_DIV_CLK, 2 }, + { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP0_PHY_PLL_LINK_CLK }, + { .index = DT_DP0_PHY_PLL_VCO_DIV_CLK }, + { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK }, +}; + +static const struct parent_map disp_cc_1_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_DSICLK, 1 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_DSICLK, 3 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK }, + { .index = DT_DSI1_PHY_PLL_OUT_DSICLK }, + { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK }, +}; + +static const struct parent_map disp_cc_1_parent_map_2[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_2[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_2_ao[] = { + { .index = DT_BI_TCXO_AO }, +}; + +static const struct parent_map disp_cc_1_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_DP0_PHY_PLL_LINK_CLK, 1 }, + { P_DP1_PHY_PLL_LINK_CLK, 2 }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DP0_PHY_PLL_LINK_CLK }, + { .index = DT_DP1_PHY_PLL_LINK_CLK }, +}; + +static const struct parent_map disp_cc_1_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 }, + { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK }, + { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK }, +}; + +static const struct parent_map disp_cc_1_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_MDSS_1_DISP_CC_PLL1_OUT_MAIN, 4 }, + { P_MDSS_1_DISP_CC_PLL1_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &mdss_1_disp_cc_pll1.clkr.hw }, + { .hw = &mdss_1_disp_cc_pll1.clkr.hw }, +}; + +static const struct parent_map disp_cc_1_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_MDSS_1_DISP_CC_PLL0_OUT_MAIN, 1 }, + { P_MDSS_1_DISP_CC_PLL1_OUT_MAIN, 4 }, + { P_MDSS_1_DISP_CC_PLL1_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &mdss_1_disp_cc_pll0.clkr.hw }, + { .hw = &mdss_1_disp_cc_pll1.clkr.hw }, + { .hw = &mdss_1_disp_cc_pll1.clkr.hw }, +}; + +static const struct parent_map disp_cc_1_parent_map_7[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data disp_cc_1_parent_data_7_ao[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct freq_tbl ftbl_mdss_1_disp_cc_mdss_ahb_clk_src[] = { + F(37500000, P_MDSS_1_DISP_CC_PLL1_OUT_MAIN, 16, 0, 0), + F(75000000, P_MDSS_1_DISP_CC_PLL1_OUT_MAIN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_ahb_clk_src = { + .cmd_rcgr = 0x824c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_5, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_ahb_clk_src", + .parent_data = disp_cc_1_parent_data_5, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_mdss_1_disp_cc_mdss_byte0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_byte0_clk_src = { + .cmd_rcgr = 0x80ec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_1, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_byte0_clk_src", + .parent_data = disp_cc_1_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_byte1_clk_src = { + .cmd_rcgr = 0x8108, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_1, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_byte1_clk_src", + .parent_data = disp_cc_1_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx0_aux_clk_src = { + .cmd_rcgr = 0x81b8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_2, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_aux_clk_src", + .parent_data = disp_cc_1_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx0_crypto_clk_src = { + .cmd_rcgr = 0x8170, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_3, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_crypto_clk_src", + .parent_data = disp_cc_1_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx0_link_clk_src = { + .cmd_rcgr = 0x8154, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_3, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_link_clk_src", + .parent_data = disp_cc_1_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx0_pixel0_clk_src = { + .cmd_rcgr = 0x8188, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_0, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_pixel0_clk_src", + .parent_data = disp_cc_1_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx0_pixel1_clk_src = { + .cmd_rcgr = 0x81a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_0, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_pixel1_clk_src", + .parent_data = disp_cc_1_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx0_pixel2_clk_src = { + .cmd_rcgr = 0x826c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_0, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_pixel2_clk_src", + .parent_data = disp_cc_1_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx0_pixel3_clk_src = { + .cmd_rcgr = 0x8284, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_0, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_pixel3_clk_src", + .parent_data = disp_cc_1_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx1_aux_clk_src = { + .cmd_rcgr = 0x8234, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_2, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_aux_clk_src", + .parent_data = disp_cc_1_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx1_crypto_clk_src = { + .cmd_rcgr = 0x821c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_3, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_crypto_clk_src", + .parent_data = disp_cc_1_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx1_link_clk_src = { + .cmd_rcgr = 0x8200, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_3, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_link_clk_src", + .parent_data = disp_cc_1_parent_data_3, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx1_pixel0_clk_src = { + .cmd_rcgr = 0x81d0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_0, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_pixel0_clk_src", + .parent_data = disp_cc_1_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_dptx1_pixel1_clk_src = { + .cmd_rcgr = 0x81e8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_0, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_pixel1_clk_src", + .parent_data = disp_cc_1_parent_data_0, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_dp_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_esc0_clk_src = { + .cmd_rcgr = 0x8124, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_4, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_esc0_clk_src", + .parent_data = disp_cc_1_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_esc1_clk_src = { + .cmd_rcgr = 0x813c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_4, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_esc1_clk_src", + .parent_data = disp_cc_1_parent_data_4, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_mdss_1_disp_cc_mdss_mdp_clk_src[] = { + F(375000000, P_MDSS_1_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(500000000, P_MDSS_1_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(575000000, P_MDSS_1_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(650000000, P_MDSS_1_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_mdp_clk_src = { + .cmd_rcgr = 0x80bc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_6, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_mdp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_mdp_clk_src", + .parent_data = disp_cc_1_parent_data_6, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_pclk0_clk_src = { + .cmd_rcgr = 0x808c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_1, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_pclk0_clk_src", + .parent_data = disp_cc_1_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_pclk1_clk_src = { + .cmd_rcgr = 0x80a4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_1, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_pclk1_clk_src", + .parent_data = disp_cc_1_parent_data_1, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_pixel_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_mdss_vsync_clk_src = { + .cmd_rcgr = 0x80d4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_2, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_vsync_clk_src", + .parent_data = disp_cc_1_parent_data_2, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_mdss_1_disp_cc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 mdss_1_disp_cc_sleep_clk_src = { + .cmd_rcgr = 0xc058, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_7, + .freq_tbl = ftbl_mdss_1_disp_cc_sleep_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_sleep_clk_src", + .parent_data = disp_cc_1_parent_data_7_ao, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_7_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 mdss_1_disp_cc_xo_clk_src = { + .cmd_rcgr = 0xc03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_1_parent_map_2, + .freq_tbl = ftbl_mdss_1_disp_cc_mdss_byte0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_xo_clk_src", + .parent_data = disp_cc_1_parent_data_2_ao, + .num_parents = ARRAY_SIZE(disp_cc_1_parent_data_2_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div mdss_1_disp_cc_mdss_byte0_div_clk_src = { + .reg = 0x8104, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_byte0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, +}; + +static struct clk_regmap_div mdss_1_disp_cc_mdss_byte1_div_clk_src = { + .reg = 0x8120, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_byte1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, +}; + +static struct clk_regmap_div mdss_1_disp_cc_mdss_dptx0_link_div_clk_src = { + .reg = 0x816c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div mdss_1_disp_cc_mdss_dptx1_link_div_clk_src = { + .reg = 0x8218, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_link_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_ahb1_clk = { + .halt_reg = 0x8088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_ahb1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_ahb_clk = { + .halt_reg = 0x8084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_byte0_clk = { + .halt_reg = 0x8034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_byte0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_byte0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_byte0_intf_clk = { + .halt_reg = 0x8038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_byte0_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_byte0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_byte1_clk = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_byte1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_byte1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_byte1_intf_clk = { + .halt_reg = 0x8040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_byte1_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_byte1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_aux_clk = { + .halt_reg = 0x805c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x805c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_crypto_clk = { + .halt_reg = 0x8058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_crypto_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_crypto_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_link_clk = { + .halt_reg = 0x804c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x804c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_link_intf_clk = { + .halt_reg = 0x8050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_pixel0_clk = { + .halt_reg = 0x8060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_pixel1_clk = { + .halt_reg = 0x8064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_pixel2_clk = { + .halt_reg = 0x8264, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8264, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_pixel2_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_pixel2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_pixel3_clk = { + .halt_reg = 0x8268, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8268, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_pixel3_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_pixel3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx0_usb_router_link_intf_clk = { + .halt_reg = 0x8054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx0_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx1_aux_clk = { + .halt_reg = 0x8080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx1_crypto_clk = { + .halt_reg = 0x807c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x807c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_crypto_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx1_crypto_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx1_link_clk = { + .halt_reg = 0x8070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_link_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx1_link_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx1_link_intf_clk = { + .halt_reg = 0x8074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx1_pixel0_clk = { + .halt_reg = 0x8068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_pixel0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx1_pixel0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx1_pixel1_clk = { + .halt_reg = 0x806c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x806c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_pixel1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx1_pixel1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_dptx1_usb_router_link_intf_clk = { + .halt_reg = 0x8078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_dptx1_usb_router_link_intf_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_esc0_clk = { + .halt_reg = 0x8044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_esc0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_esc0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_esc1_clk = { + .halt_reg = 0x8048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_esc1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_esc1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_mdp1_clk = { + .halt_reg = 0x8014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_mdp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_mdp_clk = { + .halt_reg = 0x800c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x800c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_mdp_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_mdp_lut1_clk = { + .halt_reg = 0x8024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_mdp_lut1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_mdp_lut_clk = { + .halt_reg = 0x801c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x801c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_mdp_lut_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_mdp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_non_gdsc_ahb_clk = { + .halt_reg = 0xa004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xa004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_non_gdsc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_pclk0_clk = { + .halt_reg = 0x8004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_pclk0_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_pclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_pclk1_clk = { + .halt_reg = 0x8008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_pclk1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_pclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_pll_lock_monitor_clk = { + .halt_reg = 0xe000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_pll_lock_monitor_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_rscc_ahb_clk = { + .halt_reg = 0xa00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_rscc_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_rscc_vsync_clk = { + .halt_reg = 0xa008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_rscc_vsync_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_vsync1_clk = { + .halt_reg = 0x8030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_vsync1_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_mdss_vsync_clk = { + .halt_reg = 0x802c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x802c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_mdss_vsync_clk", + .parent_hws = (const struct clk_hw*[]) { + &mdss_1_disp_cc_mdss_vsync_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch mdss_1_disp_cc_sm_obs_clk = { + .halt_reg = 0x11014, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x11014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "mdss_1_disp_cc_sm_obs_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc mdss_1_disp_cc_mdss_core_gdsc = { + .gdscr = 0x9000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "mdss_1_disp_cc_mdss_core_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL, +}; + +static struct gdsc mdss_1_disp_cc_mdss_core_int2_gdsc = { + .gdscr = 0xd000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "mdss_1_disp_cc_mdss_core_int2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL, +}; + +static struct clk_regmap *disp_cc_1_sa8775p_clocks[] = { + [MDSS_DISP_CC_MDSS_AHB1_CLK] = &mdss_1_disp_cc_mdss_ahb1_clk.clkr, + [MDSS_DISP_CC_MDSS_AHB_CLK] = &mdss_1_disp_cc_mdss_ahb_clk.clkr, + [MDSS_DISP_CC_MDSS_AHB_CLK_SRC] = &mdss_1_disp_cc_mdss_ahb_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE0_CLK] = &mdss_1_disp_cc_mdss_byte0_clk.clkr, + [MDSS_DISP_CC_MDSS_BYTE0_CLK_SRC] = &mdss_1_disp_cc_mdss_byte0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &mdss_1_disp_cc_mdss_byte0_div_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE0_INTF_CLK] = &mdss_1_disp_cc_mdss_byte0_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_BYTE1_CLK] = &mdss_1_disp_cc_mdss_byte1_clk.clkr, + [MDSS_DISP_CC_MDSS_BYTE1_CLK_SRC] = &mdss_1_disp_cc_mdss_byte1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &mdss_1_disp_cc_mdss_byte1_div_clk_src.clkr, + [MDSS_DISP_CC_MDSS_BYTE1_INTF_CLK] = &mdss_1_disp_cc_mdss_byte1_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK] = &mdss_1_disp_cc_mdss_dptx0_aux_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_AUX_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx0_aux_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_CRYPTO_CLK] = &mdss_1_disp_cc_mdss_dptx0_crypto_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_CRYPTO_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx0_crypto_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK] = &mdss_1_disp_cc_mdss_dptx0_link_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_LINK_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx0_link_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC] = + &mdss_1_disp_cc_mdss_dptx0_link_div_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_LINK_INTF_CLK] = &mdss_1_disp_cc_mdss_dptx0_link_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK] = &mdss_1_disp_cc_mdss_dptx0_pixel0_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx0_pixel0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK] = &mdss_1_disp_cc_mdss_dptx0_pixel1_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx0_pixel1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK] = &mdss_1_disp_cc_mdss_dptx0_pixel2_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL2_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx0_pixel2_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK] = &mdss_1_disp_cc_mdss_dptx0_pixel3_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_PIXEL3_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx0_pixel3_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK] = + &mdss_1_disp_cc_mdss_dptx0_usb_router_link_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_AUX_CLK] = &mdss_1_disp_cc_mdss_dptx1_aux_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_AUX_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx1_aux_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_CRYPTO_CLK] = &mdss_1_disp_cc_mdss_dptx1_crypto_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_CRYPTO_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx1_crypto_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_LINK_CLK] = &mdss_1_disp_cc_mdss_dptx1_link_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_LINK_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx1_link_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC] = + &mdss_1_disp_cc_mdss_dptx1_link_div_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_LINK_INTF_CLK] = &mdss_1_disp_cc_mdss_dptx1_link_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_PIXEL0_CLK] = &mdss_1_disp_cc_mdss_dptx1_pixel0_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx1_pixel0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_PIXEL1_CLK] = &mdss_1_disp_cc_mdss_dptx1_pixel1_clk.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC] = &mdss_1_disp_cc_mdss_dptx1_pixel1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK] = + &mdss_1_disp_cc_mdss_dptx1_usb_router_link_intf_clk.clkr, + [MDSS_DISP_CC_MDSS_ESC0_CLK] = &mdss_1_disp_cc_mdss_esc0_clk.clkr, + [MDSS_DISP_CC_MDSS_ESC0_CLK_SRC] = &mdss_1_disp_cc_mdss_esc0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_ESC1_CLK] = &mdss_1_disp_cc_mdss_esc1_clk.clkr, + [MDSS_DISP_CC_MDSS_ESC1_CLK_SRC] = &mdss_1_disp_cc_mdss_esc1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_MDP1_CLK] = &mdss_1_disp_cc_mdss_mdp1_clk.clkr, + [MDSS_DISP_CC_MDSS_MDP_CLK] = &mdss_1_disp_cc_mdss_mdp_clk.clkr, + [MDSS_DISP_CC_MDSS_MDP_CLK_SRC] = &mdss_1_disp_cc_mdss_mdp_clk_src.clkr, + [MDSS_DISP_CC_MDSS_MDP_LUT1_CLK] = &mdss_1_disp_cc_mdss_mdp_lut1_clk.clkr, + [MDSS_DISP_CC_MDSS_MDP_LUT_CLK] = &mdss_1_disp_cc_mdss_mdp_lut_clk.clkr, + [MDSS_DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &mdss_1_disp_cc_mdss_non_gdsc_ahb_clk.clkr, + [MDSS_DISP_CC_MDSS_PCLK0_CLK] = &mdss_1_disp_cc_mdss_pclk0_clk.clkr, + [MDSS_DISP_CC_MDSS_PCLK0_CLK_SRC] = &mdss_1_disp_cc_mdss_pclk0_clk_src.clkr, + [MDSS_DISP_CC_MDSS_PCLK1_CLK] = &mdss_1_disp_cc_mdss_pclk1_clk.clkr, + [MDSS_DISP_CC_MDSS_PCLK1_CLK_SRC] = &mdss_1_disp_cc_mdss_pclk1_clk_src.clkr, + [MDSS_DISP_CC_MDSS_PLL_LOCK_MONITOR_CLK] = &mdss_1_disp_cc_mdss_pll_lock_monitor_clk.clkr, + [MDSS_DISP_CC_MDSS_RSCC_AHB_CLK] = &mdss_1_disp_cc_mdss_rscc_ahb_clk.clkr, + [MDSS_DISP_CC_MDSS_RSCC_VSYNC_CLK] = &mdss_1_disp_cc_mdss_rscc_vsync_clk.clkr, + [MDSS_DISP_CC_MDSS_VSYNC1_CLK] = &mdss_1_disp_cc_mdss_vsync1_clk.clkr, + [MDSS_DISP_CC_MDSS_VSYNC_CLK] = &mdss_1_disp_cc_mdss_vsync_clk.clkr, + [MDSS_DISP_CC_MDSS_VSYNC_CLK_SRC] = &mdss_1_disp_cc_mdss_vsync_clk_src.clkr, + [MDSS_DISP_CC_PLL0] = &mdss_1_disp_cc_pll0.clkr, + [MDSS_DISP_CC_PLL1] = &mdss_1_disp_cc_pll1.clkr, + [MDSS_DISP_CC_SLEEP_CLK_SRC] = &mdss_1_disp_cc_sleep_clk_src.clkr, + [MDSS_DISP_CC_SM_OBS_CLK] = &mdss_1_disp_cc_sm_obs_clk.clkr, + [MDSS_DISP_CC_XO_CLK_SRC] = &mdss_1_disp_cc_xo_clk_src.clkr, +}; + +static struct gdsc *disp_cc_1_sa8775p_gdscs[] = { + [MDSS_DISP_CC_MDSS_CORE_GDSC] = &mdss_1_disp_cc_mdss_core_gdsc, + [MDSS_DISP_CC_MDSS_CORE_INT2_GDSC] = &mdss_1_disp_cc_mdss_core_int2_gdsc, +}; + +static const struct qcom_reset_map disp_cc_1_sa8775p_resets[] = { + [MDSS_DISP_CC_MDSS_CORE_BCR] = { 0x8000 }, + [MDSS_DISP_CC_MDSS_RSCC_BCR] = { 0xa000 }, +}; + +static const struct regmap_config disp_cc_1_sa8775p_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x12414, + .fast_io = true, +}; + +static struct qcom_cc_desc disp_cc_1_sa8775p_desc = { + .config = &disp_cc_1_sa8775p_regmap_config, + .clks = disp_cc_1_sa8775p_clocks, + .num_clks = ARRAY_SIZE(disp_cc_1_sa8775p_clocks), + .resets = disp_cc_1_sa8775p_resets, + .num_resets = ARRAY_SIZE(disp_cc_1_sa8775p_resets), + .gdscs = disp_cc_1_sa8775p_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_1_sa8775p_gdscs), +}; + +static const struct of_device_id disp_cc_1_sa8775p_match_table[] = { + { .compatible = "qcom,sa8775p-dispcc1" }, + { } +}; +MODULE_DEVICE_TABLE(of, disp_cc_1_sa8775p_match_table); + +static int disp_cc_1_sa8775p_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + regmap = qcom_cc_map(pdev, &disp_cc_1_sa8775p_desc); + if (IS_ERR(regmap)) { + pm_runtime_put(&pdev->dev); + return PTR_ERR(regmap); + } + + clk_lucid_evo_pll_configure(&mdss_1_disp_cc_pll0, regmap, &mdss_1_disp_cc_pll0_config); + clk_lucid_evo_pll_configure(&mdss_1_disp_cc_pll1, regmap, &mdss_1_disp_cc_pll1_config); + + /* Keep some clocks always enabled */ + qcom_branch_set_clk_en(regmap, 0xc070); /* MDSS_1_DISP_CC_SLEEP_CLK */ + qcom_branch_set_clk_en(regmap, 0xc054); /* MDSS_1_DISP_CC_XO_CLK */ + + ret = qcom_cc_really_probe(&pdev->dev, &disp_cc_1_sa8775p_desc, regmap); + + pm_runtime_put(&pdev->dev); + + return ret; +} + +static struct platform_driver disp_cc_1_sa8775p_driver = { + .probe = disp_cc_1_sa8775p_probe, + .driver = { + .name = "dispcc1-sa8775p", + .of_match_table = disp_cc_1_sa8775p_match_table, + }, +}; + +module_platform_driver(disp_cc_1_sa8775p_driver); + +MODULE_DESCRIPTION("QTI DISPCC1 SA8775P Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-ipq5332.c b/drivers/clk/qcom/gcc-ipq5332.c index 9536b2b7d07c25..9246e97d785a1f 100644 --- a/drivers/clk/qcom/gcc-ipq5332.c +++ b/drivers/clk/qcom/gcc-ipq5332.c @@ -2185,150 +2185,6 @@ static struct clk_branch gcc_prng_ahb_clk = { }, }; -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, @@ -2756,24 +2612,6 @@ static struct clk_branch gcc_sys_noc_at_clk = { }, }; -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, @@ -2989,204 +2827,6 @@ static struct clk_branch gcc_usb0_sleep_clk = { }, }; -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, @@ -3362,15 +3002,7 @@ static struct clk_regmap *gcc_ipq5332_clocks[] = { [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, @@ -3400,7 +3032,6 @@ static struct clk_regmap *gcc_ipq5332_clocks[] = { [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, @@ -3421,17 +3052,6 @@ static struct clk_regmap *gcc_ipq5332_clocks[] = { [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, @@ -3622,7 +3242,7 @@ static const struct qcom_reset_map gcc_ipq5332_resets[] = { #define IPQ_APPS_ID 5332 /* some unique value */ -static struct qcom_icc_hws_data icc_ipq5332_hws[] = { +static const struct qcom_icc_hws_data icc_ipq5332_hws[] = { { MASTER_SNOC_PCIE3_1_M, SLAVE_SNOC_PCIE3_1_M, GCC_SNOC_PCIE3_1LANE_M_CLK }, { MASTER_ANOC_PCIE3_1_S, SLAVE_ANOC_PCIE3_1_S, GCC_SNOC_PCIE3_1LANE_S_CLK }, { MASTER_SNOC_PCIE3_2_M, SLAVE_SNOC_PCIE3_2_M, GCC_SNOC_PCIE3_2LANE_M_CLK }, diff --git a/drivers/clk/qcom/gcc-ipq5424.c b/drivers/clk/qcom/gcc-ipq5424.c new file mode 100644 index 00000000000000..88a7d5b2e751a4 --- /dev/null +++ b/drivers/clk/qcom/gcc-ipq5424.c @@ -0,0 +1,3291 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018,2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#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 "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "common.h" +#include "reset.h" + +enum { + DT_XO, + DT_SLEEP_CLK, + DT_PCIE30_PHY0_PIPE_CLK, + DT_PCIE30_PHY1_PIPE_CLK, + DT_PCIE30_PHY2_PIPE_CLK, + DT_PCIE30_PHY3_PIPE_CLK, + DT_USB_PCIE_WRAPPER_PIPE_CLK, +}; + +enum { + 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, + P_USB3PHY_0_PIPE, +}; + +static const struct clk_parent_data gcc_parent_data_xo = { .index = DT_XO }; + +static struct clk_alpha_pll gpll0 = { + .offset = 0x20000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO], + .clkr = { + .enable_reg = 0xb000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpll0", + .parent_data = &gcc_parent_data_xo, + .num_parents = 1, + .ops = &clk_alpha_pll_ops, + }, + }, +}; + +static struct clk_fixed_factor gpll0_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(const struct clk_init_data) { + .name = "gpll0_div2", + .parent_hws = (const struct clk_hw *[]) { + &gpll0.clkr.hw + }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_alpha_pll gpll2 = { + .offset = 0x21000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_NSS_HUAYRA], + .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_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gpll2_out_main[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpll2_out_main = { + .offset = 0x21000, + .post_div_table = post_div_table_gpll2_out_main, + .num_post_div = ARRAY_SIZE(post_div_table_gpll2_out_main), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_NSS_HUAYRA], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpll2_out_main", + .parent_hws = (const struct clk_hw*[]) { + &gpll2.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_ro_ops, + }, +}; + +static struct clk_alpha_pll gpll4 = { + .offset = 0x22000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT_EVO], + .clkr = { + .enable_reg = 0xb000, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gpll4", + .parent_data = &gcc_parent_data_xo, + .num_parents = 1, + .ops = &clk_alpha_pll_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 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_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_3[] = { + { .index = DT_XO }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_XO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_XO }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { 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_5[] = { + { .index = DT_XO }, + { .hw = &gpll4.clkr.hw }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_SLEEP_CLK, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { 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_7[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll0.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_MAIN, 2 }, + { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2_out_main.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct parent_map gcc_parent_map_9[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_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 = &gpll4.clkr.hw }, + { .hw = &gpll0_div2.hw }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_AUX, 2 }, + { P_SLEEP_CLK, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_10[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_11[] = { + { P_XO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL2_OUT_AUX, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_11[] = { + { .index = DT_XO }, + { .hw = &gpll0.clkr.hw }, + { .hw = &gpll2.clkr.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_nss_ts_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + { } +}; + +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 = &(const 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_rcg2 gcc_nss_ts_clk_src = { + .cmd_rcgr = 0x17088, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .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_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie0_axi_m_clk_src[] = { + F(240000000, P_GPLL4_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie0_axi_m_clk_src = { + .cmd_rcgr = 0x28018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie0_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_pcie0_axi_s_clk_src = { + .cmd_rcgr = 0x28020, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie0_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_pcie1_axi_m_clk_src = { + .cmd_rcgr = 0x29018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie1_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_pcie1_axi_s_clk_src = { + .cmd_rcgr = 0x29020, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie1_axi_s_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_pcie2_axi_m_clk_src[] = { + F(266666667, P_GPLL4_OUT_MAIN, 4.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie2_axi_m_clk_src = { + .cmd_rcgr = 0x2a018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie2_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_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_pcie2_axi_s_clk_src = { + .cmd_rcgr = 0x2a020, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_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_pcie3_axi_m_clk_src = { + .cmd_rcgr = 0x2b018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie2_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_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_pcie3_axi_s_clk_src = { + .cmd_rcgr = 0x2b020, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_axi_s_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_pcie_aux_clk_src[] = { + F(20000000, P_GPLL0_OUT_MAIN, 10, 1, 4), + { } +}; + +static struct clk_rcg2 gcc_pcie_aux_clk_src = { + .cmd_rcgr = 0x28004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .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_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_i2c0_clk_src[] = { + F(4800000, P_XO, 5, 0, 0), + F(9600000, P_XO, 2.5, 0, 0), + F(24000000, P_XO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + F(64000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qupv3_i2c0_clk_src = { + .cmd_rcgr = 0x2018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_i2c0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c0_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_i2c1_clk_src = { + .cmd_rcgr = 0x3018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_i2c0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c1_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_spi0_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_OUT_MAIN, 10, 1, 5), + F(24000000, P_XO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2), + F(32000000, P_GPLL0_OUT_MAIN, 10, 2, 5), + F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qupv3_spi0_clk_src = { + .cmd_rcgr = 0x4004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_spi0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_spi0_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_spi1_clk_src = { + .cmd_rcgr = 0x5004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_spi0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_spi1_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_uart0_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_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), + F(64000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qupv3_uart0_clk_src = { + .cmd_rcgr = 0x202c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_uart0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_uart0_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_uart1_clk_src = { + .cmd_rcgr = 0x302c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_uart0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_uart1_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_sdcc1_apps_clk_src[] = { + F(144000, P_XO, 16, 12, 125), + F(400000, P_XO, 12, 1, 5), + F(24000000, P_XO, 1, 0, 0), + F(48000000, P_GPLL2_OUT_MAIN, 12, 1, 2), + F(96000000, P_GPLL2_OUT_MAIN, 6, 1, 2), + 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_8, + .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_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = { + F(300000000, P_GPLL4_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x33018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_uniphy_sys_clk_src = { + .cmd_rcgr = 0x17090, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .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_10, + .freq_tbl = ftbl_gcc_nss_ts_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb0_aux_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_usb0_master_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + { } +}; + +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_usb0_master_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(24000000, P_XO, 1, 0, 0), + 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_5, + .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_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_usb1_mock_utmi_clk_src = { + .cmd_rcgr = 0x3c004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_usb0_mock_utmi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb1_mock_utmi_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_wcss_ahb_clk_src[] = { + F(24000000, P_XO, 1, 0, 0), + F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_wcss_ahb_clk_src = { + .cmd_rcgr = 0x25030, + .freq_tbl = ftbl_gcc_wcss_ahb_clk_src, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .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 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, + .freq_tbl = ftbl_gcc_qdss_at_clk_src, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_at_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_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, + .freq_tbl = ftbl_gcc_qdss_tsctr_clk_src, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_tsctr_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_fixed_factor gcc_qdss_tsctr_div2_clk_src = { + .mult = 1, + .div = 2, + .hw.init = &(const 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_dap_sync_clk_src = { + .mult = 1, + .div = 4, + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_dap_sync_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_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, + .freq_tbl = ftbl_gcc_system_noc_bfdcd_clk_src, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_system_noc_bfdcd_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_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 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 struct clk_rcg2 gcc_lpass_axim_clk_src = { + .cmd_rcgr = 0x2700c, + .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_axim_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_fixed_factor gcc_eud_at_div_clk_src = { + .mult = 1, + .div = 6, + .hw.init = &(const 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 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_6, + .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_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .ops = &clk_rcg2_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), + F(400000000, P_GPLL0_OUT_MAIN, 2, 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_11, + .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_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_qpic_clk_src = { + .cmd_rcgr = 0x32020, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_11, + .freq_tbl = ftbl_gcc_qpic_io_macro_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qpic_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie0_rchng_clk_src = { + .cmd_rcgr = 0x28028, + .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_pcie0_rchng_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_pcie1_rchng_clk_src = { + .cmd_rcgr = 0x29028, + .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_pcie1_rchng_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_pcie2_rchng_clk_src = { + .cmd_rcgr = 0x2a028, + .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_pcie2_rchng_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_pcie3_rchng_clk_src = { + .cmd_rcgr = 0x2b028, + .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_pcie3_rchng_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_i2c0_div_clk_src = { + .reg = 0x2020, + .shift = 0, + .width = 2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_i2c1_div_clk_src = { + .reg = 0x3020, + .shift = 0, + .width = 2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .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_regmap_div gcc_usb1_mock_utmi_div_clk_src = { + .reg = 0x3c018, + .shift = 0, + .width = 2, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb1_mock_utmi_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb1_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_apss_dbg_clk = { + .halt_reg = 0x2402c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2402c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_apss_dbg_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie0_1lane_s_clk = { + .halt_reg = 0x31088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie0_1lane_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie0_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie1_1lane_s_clk = { + .halt_reg = 0x3108c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3108c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie1_1lane_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie1_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie2_2lane_s_clk = { + .halt_reg = 0x31090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie2_2lane_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie2_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie3_2lane_s_clk = { + .halt_reg = 0x31094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x31094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie3_2lane_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_usb_clk = { + .halt_reg = 0x310a8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x310a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_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_mdio_ahb_clk = { + .halt_reg = 0x17040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17040, + .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_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_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_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_pcie0_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_pcie0_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_pcie0_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_pcie0_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_pcie0_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_pcie0_axi_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e07c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_anoc_pcie0_1lane_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie0_axi_m_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 = 0x28048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x28048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie0_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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_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_pcie0_axi_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie0_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie0_pipe_clk_src = { + .reg = 0x28064, + .clkr = { + .hw.init = &(const 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_branch gcc_pcie0_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_pcie0_pipe_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie0_pipe_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, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie1_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_pcie1_aux_clk = { + .halt_reg = 0x29074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie1_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_pcie1_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_pcie1_axi_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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 = 0x2e084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_anoc_pcie1_1lane_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie1_axi_m_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 = 0x29048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie1_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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_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_pcie1_axi_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie1_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie1_pipe_clk_src = { + .reg = 0x29064, + .clkr = { + .hw.init = &(const 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_branch gcc_pcie1_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_pcie1_pipe_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie1_pipe_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, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_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_pcie2_aux_clk = { + .halt_reg = 0x2a078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_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_pcie2_axi_m_clk = { + .halt_reg = 0x2a038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_axi_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_anoc_pcie2_2lane_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie2_axi_m_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 = 0x2a048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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_clk = { + .halt_reg = 0x2a040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2a040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_axi_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie2_axi_s_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie2_pipe_clk_src = { + .reg = 0x2a064, + .clkr = { + .hw.init = &(const 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_branch gcc_pcie2_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_pcie2_pipe_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie2_pipe_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, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_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_pcie3_aux_clk = { + .halt_reg = 0x2b07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b07c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_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_pcie3_axi_m_clk = { + .halt_reg = 0x2b038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_axi_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2e090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_anoc_pcie3_2lane_m_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie3_axi_m_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 = 0x2b048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_axi_s_bridge_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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_clk = { + .halt_reg = 0x2b040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_axi_s_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_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 gcc_pcie3_pipe_clk_src = { + .reg = 0x2b064, + .clkr = { + .hw.init = &(const 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 struct clk_branch gcc_pcie3_pipe_clk = { + .halt_reg = 0x2b068, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x2b068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_pipe_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie3_pipe_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_qupv3_ahb_mst_clk = { + .halt_reg = 0x1014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb004, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_ahb_mst_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_qupv3_ahb_slv_clk = { + .halt_reg = 0x102c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0xb004, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_ahb_slv_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_qupv3_i2c0_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_qupv3_i2c0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c1_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_qupv3_i2c1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_spi0_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_qupv3_spi0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_spi0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_spi1_clk = { + .halt_reg = 0x5020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_spi1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_spi1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_uart0_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_qupv3_uart0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_uart0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_uart1_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_qupv3_uart1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_uart1_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 = 0x3303c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3303c, + .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_sdcc1_ice_core_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_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_uniphy0_ahb_clk = { + .halt_reg = 0x1704c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1704c, + .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 = 0x17048, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x17048, + .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 = 0x1705c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1705c, + .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 = 0x17058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x17058, + .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_uniphy2_ahb_clk = { + .halt_reg = 0x1706c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1706c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_uniphy2_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_uniphy2_sys_clk = { + .halt_reg = 0x17068, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x17068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_uniphy2_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 = 0x2c04c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2c04c, + .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_master_clk = { + .halt_reg = 0x2c044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2c044, + .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 = 0x2c050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x2c050, + .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_usb1_mock_utmi_clk = { + .halt_reg = 0x3c024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x3c024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb1_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb1_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_usb1_phy_cfg_ahb_clk = { + .halt_reg = 0x3c01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x3c01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb1_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_usb1_master_clk = { + .halt_reg = 0x3c028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x3c028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb1_master_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_regmap_phy_mux gcc_usb0_pipe_clk_src = { + .reg = 0x2c074, + .clkr = { + .hw.init = &(const 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_branch gcc_usb0_pipe_clk = { + .halt_reg = 0x2c054, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x2c054, + .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_usb1_sleep_clk = { + .halt_reg = 0x3c020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x3c020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb1_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_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_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_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_cnoc_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_cnoc_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_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_axim_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_snoc_lpass_clk = { + .halt_reg = 0x31020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x31020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_snoc_lpass_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_lpass_axim_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_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 = 0x32028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x32028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qpic_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qpic_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_qdss_dap_clk = { + .halt_reg = 0x2d058, + .clkr = { + .enable_reg = 0x2d058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qdss_dap_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_qdss_dap_sync_clk_src.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qdss_at_clk = { + .halt_reg = 0x2d034, + .clkr = { + .enable_reg = 0x2d034, + .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_pcie0_rchng_clk = { + .halt_reg = 0x28028, + .clkr = { + .enable_reg = 0x28028, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie0_rchng_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie0_rchng_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie1_rchng_clk = { + .halt_reg = 0x29028, + .clkr = { + .enable_reg = 0x29028, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie1_rchng_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie1_rchng_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie2_rchng_clk = { + .halt_reg = 0x2a028, + .clkr = { + .enable_reg = 0x2a028, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_rchng_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie2_rchng_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie3_rchng_clk = { + .halt_reg = 0x2b028, + .clkr = { + .enable_reg = 0x2b028, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie3_rchng_clk", + .parent_hws = (const struct clk_hw *[]) { + &gcc_pcie3_rchng_clk_src.clkr.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gcc_ipq5424_clocks[] = { + [GCC_ADSS_PWM_CLK] = &gcc_adss_pwm_clk.clkr, + [GCC_ADSS_PWM_CLK_SRC] = &gcc_adss_pwm_clk_src.clkr, + [GCC_APSS_DBG_CLK] = &gcc_apss_dbg_clk.clkr, + [GCC_CNOC_PCIE0_1LANE_S_CLK] = &gcc_cnoc_pcie0_1lane_s_clk.clkr, + [GCC_CNOC_PCIE1_1LANE_S_CLK] = &gcc_cnoc_pcie1_1lane_s_clk.clkr, + [GCC_CNOC_PCIE2_2LANE_S_CLK] = &gcc_cnoc_pcie2_2lane_s_clk.clkr, + [GCC_CNOC_PCIE3_2LANE_S_CLK] = &gcc_cnoc_pcie3_2lane_s_clk.clkr, + [GCC_CNOC_USB_CLK] = &gcc_cnoc_usb_clk.clkr, + [GCC_MDIO_AHB_CLK] = &gcc_mdio_ahb_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_PCNOC_1_CLK] = &gcc_nssnoc_pcnoc_1_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_PCIE0_AHB_CLK] = &gcc_pcie0_ahb_clk.clkr, + [GCC_PCIE0_AUX_CLK] = &gcc_pcie0_aux_clk.clkr, + [GCC_PCIE0_AXI_M_CLK] = &gcc_pcie0_axi_m_clk.clkr, + [GCC_PCIE0_AXI_M_CLK_SRC] = &gcc_pcie0_axi_m_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, + [GCC_PCIE0_AXI_S_CLK_SRC] = &gcc_pcie0_axi_s_clk_src.clkr, + [GCC_PCIE0_PIPE_CLK] = &gcc_pcie0_pipe_clk.clkr, + [GCC_ANOC_PCIE0_1LANE_M_CLK] = &gcc_anoc_pcie0_1lane_m_clk.clkr, + [GCC_PCIE0_PIPE_CLK_SRC] = &gcc_pcie0_pipe_clk_src.clkr, + [GCC_PCIE0_RCHNG_CLK_SRC] = &gcc_pcie0_rchng_clk_src.clkr, + [GCC_PCIE0_RCHNG_CLK] = &gcc_pcie0_rchng_clk.clkr, + [GCC_PCIE1_AHB_CLK] = &gcc_pcie1_ahb_clk.clkr, + [GCC_PCIE1_AUX_CLK] = &gcc_pcie1_aux_clk.clkr, + [GCC_PCIE1_AXI_M_CLK] = &gcc_pcie1_axi_m_clk.clkr, + [GCC_PCIE1_AXI_M_CLK_SRC] = &gcc_pcie1_axi_m_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, + [GCC_PCIE1_AXI_S_CLK_SRC] = &gcc_pcie1_axi_s_clk_src.clkr, + [GCC_PCIE1_PIPE_CLK] = &gcc_pcie1_pipe_clk.clkr, + [GCC_ANOC_PCIE1_1LANE_M_CLK] = &gcc_anoc_pcie1_1lane_m_clk.clkr, + [GCC_PCIE1_PIPE_CLK_SRC] = &gcc_pcie1_pipe_clk_src.clkr, + [GCC_PCIE1_RCHNG_CLK_SRC] = &gcc_pcie1_rchng_clk_src.clkr, + [GCC_PCIE1_RCHNG_CLK] = &gcc_pcie1_rchng_clk.clkr, + [GCC_PCIE2_AHB_CLK] = &gcc_pcie2_ahb_clk.clkr, + [GCC_PCIE2_AUX_CLK] = &gcc_pcie2_aux_clk.clkr, + [GCC_PCIE2_AXI_M_CLK] = &gcc_pcie2_axi_m_clk.clkr, + [GCC_PCIE2_AXI_M_CLK_SRC] = &gcc_pcie2_axi_m_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, + [GCC_PCIE2_AXI_S_CLK_SRC] = &gcc_pcie2_axi_s_clk_src.clkr, + [GCC_PCIE2_PIPE_CLK] = &gcc_pcie2_pipe_clk.clkr, + [GCC_ANOC_PCIE2_2LANE_M_CLK] = &gcc_anoc_pcie2_2lane_m_clk.clkr, + [GCC_PCIE2_PIPE_CLK_SRC] = &gcc_pcie2_pipe_clk_src.clkr, + [GCC_PCIE2_RCHNG_CLK_SRC] = &gcc_pcie2_rchng_clk_src.clkr, + [GCC_PCIE2_RCHNG_CLK] = &gcc_pcie2_rchng_clk.clkr, + [GCC_PCIE3_AHB_CLK] = &gcc_pcie3_ahb_clk.clkr, + [GCC_PCIE3_AUX_CLK] = &gcc_pcie3_aux_clk.clkr, + [GCC_PCIE3_AXI_M_CLK] = &gcc_pcie3_axi_m_clk.clkr, + [GCC_PCIE3_AXI_M_CLK_SRC] = &gcc_pcie3_axi_m_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, + [GCC_PCIE3_AXI_S_CLK_SRC] = &gcc_pcie3_axi_s_clk_src.clkr, + [GCC_PCIE3_PIPE_CLK] = &gcc_pcie3_pipe_clk.clkr, + [GCC_ANOC_PCIE3_2LANE_M_CLK] = &gcc_anoc_pcie3_2lane_m_clk.clkr, + [GCC_PCIE3_PIPE_CLK_SRC] = &gcc_pcie3_pipe_clk_src.clkr, + [GCC_PCIE3_RCHNG_CLK_SRC] = &gcc_pcie3_rchng_clk_src.clkr, + [GCC_PCIE3_RCHNG_CLK] = &gcc_pcie3_rchng_clk.clkr, + [GCC_PCIE_AUX_CLK_SRC] = &gcc_pcie_aux_clk_src.clkr, + [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr, + [GCC_QUPV3_AHB_MST_CLK] = &gcc_qupv3_ahb_mst_clk.clkr, + [GCC_QUPV3_AHB_SLV_CLK] = &gcc_qupv3_ahb_slv_clk.clkr, + [GCC_QUPV3_I2C0_CLK] = &gcc_qupv3_i2c0_clk.clkr, + [GCC_QUPV3_I2C0_CLK_SRC] = &gcc_qupv3_i2c0_clk_src.clkr, + [GCC_QUPV3_I2C0_DIV_CLK_SRC] = &gcc_qupv3_i2c0_div_clk_src.clkr, + [GCC_QUPV3_I2C1_CLK] = &gcc_qupv3_i2c1_clk.clkr, + [GCC_QUPV3_I2C1_CLK_SRC] = &gcc_qupv3_i2c1_clk_src.clkr, + [GCC_QUPV3_I2C1_DIV_CLK_SRC] = &gcc_qupv3_i2c1_div_clk_src.clkr, + [GCC_QUPV3_SPI0_CLK] = &gcc_qupv3_spi0_clk.clkr, + [GCC_QUPV3_SPI0_CLK_SRC] = &gcc_qupv3_spi0_clk_src.clkr, + [GCC_QUPV3_SPI1_CLK] = &gcc_qupv3_spi1_clk.clkr, + [GCC_QUPV3_SPI1_CLK_SRC] = &gcc_qupv3_spi1_clk_src.clkr, + [GCC_QUPV3_UART0_CLK] = &gcc_qupv3_uart0_clk.clkr, + [GCC_QUPV3_UART0_CLK_SRC] = &gcc_qupv3_uart0_clk_src.clkr, + [GCC_QUPV3_UART1_CLK] = &gcc_qupv3_uart1_clk.clkr, + [GCC_QUPV3_UART1_CLK_SRC] = &gcc_qupv3_uart1_clk_src.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_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_UNIPHY2_AHB_CLK] = &gcc_uniphy2_ahb_clk.clkr, + [GCC_UNIPHY2_SYS_CLK] = &gcc_uniphy2_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_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_EUD_AT_CLK] = &gcc_usb0_eud_at_clk.clkr, + [GCC_USB0_PIPE_CLK_SRC] = &gcc_usb0_pipe_clk_src.clkr, + [GCC_USB1_MOCK_UTMI_CLK] = &gcc_usb1_mock_utmi_clk.clkr, + [GCC_USB1_MOCK_UTMI_CLK_SRC] = &gcc_usb1_mock_utmi_clk_src.clkr, + [GCC_USB1_MOCK_UTMI_DIV_CLK_SRC] = &gcc_usb1_mock_utmi_div_clk_src.clkr, + [GCC_USB0_PHY_CFG_AHB_CLK] = &gcc_usb0_phy_cfg_ahb_clk.clkr, + [GCC_USB1_PHY_CFG_AHB_CLK] = &gcc_usb1_phy_cfg_ahb_clk.clkr, + [GCC_USB0_PIPE_CLK] = &gcc_usb0_pipe_clk.clkr, + [GCC_USB0_SLEEP_CLK] = &gcc_usb0_sleep_clk.clkr, + [GCC_USB1_SLEEP_CLK] = &gcc_usb1_sleep_clk.clkr, + [GCC_USB1_MASTER_CLK] = &gcc_usb1_master_clk.clkr, + [GCC_WCSS_AHB_CLK_SRC] = &gcc_wcss_ahb_clk_src.clkr, + [GCC_CMN_12GPLL_AHB_CLK] = &gcc_cmn_12gpll_ahb_clk.clkr, + [GCC_CMN_12GPLL_SYS_CLK] = &gcc_cmn_12gpll_sys_clk.clkr, + [GCC_LPASS_SWAY_CLK] = &gcc_lpass_sway_clk.clkr, + [GCC_CNOC_LPASS_CFG_CLK] = &gcc_cnoc_lpass_cfg_clk.clkr, + [GCC_LPASS_CORE_AXIM_CLK] = &gcc_lpass_core_axim_clk.clkr, + [GCC_SNOC_LPASS_CLK] = &gcc_snoc_lpass_clk.clkr, + [GCC_QDSS_AT_CLK_SRC] = &gcc_qdss_at_clk_src.clkr, + [GCC_QDSS_TSCTR_CLK_SRC] = &gcc_qdss_tsctr_clk_src.clkr, + [GCC_SYSTEM_NOC_BFDCD_CLK_SRC] = &gcc_system_noc_bfdcd_clk_src.clkr, + [GCC_PCNOC_BFDCD_CLK_SRC] = &gcc_pcnoc_bfdcd_clk_src.clkr, + [GCC_LPASS_SWAY_CLK_SRC] = &gcc_lpass_sway_clk_src.clkr, + [GCC_LPASS_AXIM_CLK_SRC] = &gcc_lpass_axim_clk_src.clkr, + [GCC_SLEEP_CLK_SRC] = &gcc_sleep_clk_src.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_CLK] = &gcc_qpic_clk.clkr, + [GCC_QPIC_CLK_SRC] = &gcc_qpic_clk_src.clkr, + [GCC_QPIC_AHB_CLK] = &gcc_qpic_ahb_clk.clkr, + [GCC_XO_CLK_SRC] = &gcc_xo_clk_src.clkr, + [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr, + [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL2] = &gpll2.clkr, + [GPLL2_OUT_MAIN] = &gpll2_out_main.clkr, + [GPLL4] = &gpll4.clkr, +}; + +static const struct qcom_reset_map gcc_ipq5424_resets[] = { + [GCC_QUPV3_BCR] = { 0x01000, 0 }, + [GCC_QUPV3_I2C0_BCR] = { 0x02000, 0 }, + [GCC_QUPV3_UART0_BCR] = { 0x02020, 0 }, + [GCC_QUPV3_I2C1_BCR] = { 0x03000, 0 }, + [GCC_QUPV3_UART1_BCR] = { 0x03028, 0 }, + [GCC_QUPV3_SPI0_BCR] = { 0x04000, 0 }, + [GCC_QUPV3_SPI1_BCR] = { 0x05000, 0 }, + [GCC_IMEM_BCR] = { 0x0e000, 0 }, + [GCC_TME_BCR] = { 0x100000, 0 }, + [GCC_DDRSS_BCR] = { 0x11000, 0 }, + [GCC_PRNG_BCR] = { 0x13020, 0 }, + [GCC_BOOT_ROM_BCR] = { 0x13028, 0 }, + [GCC_NSS_BCR] = { 0x17000, 0 }, + [GCC_MDIO_BCR] = { 0x1703c, 0 }, + [GCC_UNIPHY0_BCR] = { 0x17044, 0 }, + [GCC_UNIPHY1_BCR] = { 0x17054, 0 }, + [GCC_UNIPHY2_BCR] = { 0x17064, 0 }, + [GCC_WCSS_BCR] = { 0x18004, 0 }, + [GCC_SEC_CTRL_BCR] = { 0x1a000, 0 }, + [GCC_TME_SEC_BUS_BCR] = { 0xa1030, 0 }, + [GCC_ADSS_BCR] = { 0x1c000, 0 }, + [GCC_LPASS_BCR] = { 0x27000, 0 }, + [GCC_PCIE0_BCR] = { 0x28000, 0 }, + [GCC_PCIE0_LINK_DOWN_BCR] = { 0x28054, 0 }, + [GCC_PCIE0PHY_PHY_BCR] = { 0x2805c, 0 }, + [GCC_PCIE0_PHY_BCR] = { 0x28060, 0 }, + [GCC_PCIE1_BCR] = { 0x29000, 0 }, + [GCC_PCIE1_LINK_DOWN_BCR] = { 0x29054, 0 }, + [GCC_PCIE1PHY_PHY_BCR] = { 0x2905c, 0 }, + [GCC_PCIE1_PHY_BCR] = { 0x29060, 0 }, + [GCC_PCIE2_BCR] = { 0x2a000, 0 }, + [GCC_PCIE2_LINK_DOWN_BCR] = { 0x2a054, 0 }, + [GCC_PCIE2PHY_PHY_BCR] = { 0x2a05c, 0 }, + [GCC_PCIE2_PHY_BCR] = { 0x2a060, 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_USB_BCR] = { 0x2c000, 0 }, + [GCC_QUSB2_0_PHY_BCR] = { 0x2c068, 0 }, + [GCC_USB0_PHY_BCR] = { 0x2c06c, 0 }, + [GCC_USB3PHY_0_PHY_BCR] = { 0x2c070, 0 }, + [GCC_QDSS_BCR] = { 0x2d000, 0 }, + [GCC_SNOC_BCR] = { 0x2e000, 0 }, + [GCC_ANOC_BCR] = { 0x2e074, 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_QPIC_BCR] = { 0x32000, 0 }, + [GCC_SDCC_BCR] = { 0x33000, 0 }, + [GCC_DCC_BCR] = { 0x35000, 0 }, + [GCC_SPDM_BCR] = { 0x36000, 0 }, + [GCC_MPM_BCR] = { 0x37000, 0 }, + [GCC_APC0_VOLTAGE_DROOP_DETECTOR_BCR] = { 0x38000, 0 }, + [GCC_RBCPR_BCR] = { 0x39000, 0 }, + [GCC_CMN_BLK_BCR] = { 0x3a000, 0 }, + [GCC_TCSR_BCR] = { 0x3d000, 0 }, + [GCC_TLMM_BCR] = { 0x3e000, 0 }, + [GCC_QUPV3_AHB_MST_ARES] = { 0x01014, 2 }, + [GCC_QUPV3_CORE_ARES] = { 0x01018, 2 }, + [GCC_QUPV3_2X_CORE_ARES] = { 0x01020, 2 }, + [GCC_QUPV3_SLEEP_ARES] = { 0x01028, 2 }, + [GCC_QUPV3_AHB_SLV_ARES] = { 0x0102c, 2 }, + [GCC_QUPV3_I2C0_ARES] = { 0x02024, 2 }, + [GCC_QUPV3_UART0_ARES] = { 0x02040, 2 }, + [GCC_QUPV3_I2C1_ARES] = { 0x03024, 2 }, + [GCC_QUPV3_UART1_ARES] = { 0x03040, 2 }, + [GCC_QUPV3_SPI0_ARES] = { 0x04020, 2 }, + [GCC_QUPV3_SPI1_ARES] = { 0x05020, 2 }, + [GCC_DEBUG_ARES] = { 0x06068, 2 }, + [GCC_GP1_ARES] = { 0x08018, 2 }, + [GCC_GP2_ARES] = { 0x09018, 2 }, + [GCC_GP3_ARES] = { 0x0a018, 2 }, + [GCC_IMEM_AXI_ARES] = { 0x0e004, 2 }, + [GCC_IMEM_CFG_AHB_ARES] = { 0x0e00c, 2 }, + [GCC_TME_ARES] = { 0x100b4, 2 }, + [GCC_TME_TS_ARES] = { 0x100c0, 2 }, + [GCC_TME_SLOW_ARES] = { 0x100d0, 2 }, + [GCC_TME_RTC_TOGGLE_ARES] = { 0x100d8, 2 }, + [GCC_TIC_ARES] = { 0x12004, 2 }, + [GCC_PRNG_AHB_ARES] = { 0x13024, 2 }, + [GCC_BOOT_ROM_AHB_ARES] = { 0x1302c, 2 }, + [GCC_NSSNOC_ATB_ARES] = { 0x17014, 2 }, + [GCC_NSS_TS_ARES] = { 0x17018, 2 }, + [GCC_NSSNOC_QOSGEN_REF_ARES] = { 0x1701c, 2 }, + [GCC_NSSNOC_TIMEOUT_REF_ARES] = { 0x17020, 2 }, + [GCC_NSSNOC_MEMNOC_ARES] = { 0x17024, 2 }, + [GCC_NSSNOC_SNOC_ARES] = { 0x17028, 2 }, + [GCC_NSSCFG_ARES] = { 0x1702c, 2 }, + [GCC_NSSNOC_NSSCC_ARES] = { 0x17030, 2 }, + [GCC_NSSCC_ARES] = { 0x17034, 2 }, + [GCC_MDIO_AHB_ARES] = { 0x17040, 2 }, + [GCC_UNIPHY0_SYS_ARES] = { 0x17048, 2 }, + [GCC_UNIPHY0_AHB_ARES] = { 0x1704c, 2 }, + [GCC_UNIPHY1_SYS_ARES] = { 0x17058, 2 }, + [GCC_UNIPHY1_AHB_ARES] = { 0x1705c, 2 }, + [GCC_UNIPHY2_SYS_ARES] = { 0x17068, 2 }, + [GCC_UNIPHY2_AHB_ARES] = { 0x1706c, 2 }, + [GCC_NSSNOC_XO_DCD_ARES] = { 0x17074, 2 }, + [GCC_NSSNOC_SNOC_1_ARES] = { 0x1707c, 2 }, + [GCC_NSSNOC_PCNOC_1_ARES] = { 0x17080, 2 }, + [GCC_NSSNOC_MEMNOC_1_ARES] = { 0x17084, 2 }, + [GCC_DDRSS_ATB_ARES] = { 0x19004, 2 }, + [GCC_DDRSS_AHB_ARES] = { 0x19008, 2 }, + [GCC_GEMNOC_AHB_ARES] = { 0x1900c, 2 }, + [GCC_GEMNOC_Q6_AXI_ARES] = { 0x19010, 2 }, + [GCC_GEMNOC_NSSNOC_ARES] = { 0x19014, 2 }, + [GCC_GEMNOC_SNOC_ARES] = { 0x19018, 2 }, + [GCC_GEMNOC_APSS_ARES] = { 0x1901c, 2 }, + [GCC_GEMNOC_QOSGEN_EXTREF_ARES] = { 0x19024, 2 }, + [GCC_GEMNOC_TS_ARES] = { 0x19028, 2 }, + [GCC_DDRSS_SMS_SLOW_ARES] = { 0x1902c, 2 }, + [GCC_GEMNOC_CNOC_ARES] = { 0x19038, 2 }, + [GCC_GEMNOC_XO_DBG_ARES] = { 0x19040, 2 }, + [GCC_GEMNOC_ANOC_ARES] = { 0x19048, 2 }, + [GCC_DDRSS_LLCC_ATB_ARES] = { 0x1904c, 2 }, + [GCC_LLCC_TPDM_CFG_ARES] = { 0x19050, 2 }, + [GCC_TME_BUS_ARES] = { 0x1a014, 2 }, + [GCC_SEC_CTRL_ACC_ARES] = { 0x1a018, 2 }, + [GCC_SEC_CTRL_ARES] = { 0x1a020, 2 }, + [GCC_SEC_CTRL_SENSE_ARES] = { 0x1a028, 2 }, + [GCC_SEC_CTRL_AHB_ARES] = { 0x1a038, 2 }, + [GCC_SEC_CTRL_BOOT_ROM_PATCH_ARES] = { 0x1a03c, 2 }, + [GCC_ADSS_PWM_ARES] = { 0x1c00c, 2 }, + [GCC_TME_ATB_ARES] = { 0x1e030, 2 }, + [GCC_TME_DBGAPB_ARES] = { 0x1e034, 2 }, + [GCC_TME_DEBUG_ARES] = { 0x1e038, 2 }, + [GCC_TME_AT_ARES] = { 0x1e03C, 2 }, + [GCC_TME_APB_ARES] = { 0x1e040, 2 }, + [GCC_TME_DMI_DBG_HS_ARES] = { 0x1e044, 2 }, + [GCC_APSS_AHB_ARES] = { 0x24014, 2 }, + [GCC_APSS_AXI_ARES] = { 0x24018, 2 }, + [GCC_CPUSS_TRIG_ARES] = { 0x2401c, 2 }, + [GCC_APSS_DBG_ARES] = { 0x2402c, 2 }, + [GCC_APSS_TS_ARES] = { 0x24030, 2 }, + [GCC_APSS_ATB_ARES] = { 0x24034, 2 }, + [GCC_Q6_AXIM_ARES] = { 0x2500c, 2 }, + [GCC_Q6_AXIS_ARES] = { 0x25010, 2 }, + [GCC_Q6_AHB_ARES] = { 0x25014, 2 }, + [GCC_Q6_AHB_S_ARES] = { 0x25018, 2 }, + [GCC_Q6SS_ATBM_ARES] = { 0x2501c, 2 }, + [GCC_Q6_TSCTR_1TO2_ARES] = { 0x25020, 2 }, + [GCC_Q6SS_PCLKDBG_ARES] = { 0x25024, 2 }, + [GCC_Q6SS_TRIG_ARES] = { 0x25028, 2 }, + [GCC_Q6SS_BOOT_CBCR_ARES] = { 0x2502c, 2 }, + [GCC_WCSS_DBG_IFC_APB_ARES] = { 0x25038, 2 }, + [GCC_WCSS_DBG_IFC_ATB_ARES] = { 0x2503c, 2 }, + [GCC_WCSS_DBG_IFC_NTS_ARES] = { 0x25040, 2 }, + [GCC_WCSS_DBG_IFC_DAPBUS_ARES] = { 0x25044, 2 }, + [GCC_WCSS_DBG_IFC_APB_BDG_ARES] = { 0x25048, 2 }, + [GCC_WCSS_DBG_IFC_NTS_BDG_ARES] = { 0x25050, 2 }, + [GCC_WCSS_DBG_IFC_DAPBUS_BDG_ARES] = { 0x25054, 2 }, + [GCC_WCSS_ECAHB_ARES] = { 0x25058, 2 }, + [GCC_WCSS_ACMT_ARES] = { 0x2505c, 2 }, + [GCC_WCSS_AHB_S_ARES] = { 0x25060, 2 }, + [GCC_WCSS_AXI_M_ARES] = { 0x25064, 2 }, + [GCC_PCNOC_WAPSS_ARES] = { 0x25080, 2 }, + [GCC_SNOC_WAPSS_ARES] = { 0x25090, 2 }, + [GCC_LPASS_SWAY_ARES] = { 0x27014, 2 }, + [GCC_LPASS_CORE_AXIM_ARES] = { 0x27018, 2 }, + [GCC_PCIE0_AHB_ARES] = { 0x28030, 2 }, + [GCC_PCIE0_AXI_M_ARES] = { 0x28038, 2 }, + [GCC_PCIE0_AXI_S_ARES] = { 0x28040, 2 }, + [GCC_PCIE0_AXI_S_BRIDGE_ARES] = { 0x28048, 2}, + [GCC_PCIE0_PIPE_ARES] = { 0x28068, 2}, + [GCC_PCIE0_AUX_ARES] = { 0x28070, 2 }, + [GCC_PCIE1_AHB_ARES] = { 0x29030, 2 }, + [GCC_PCIE1_AXI_M_ARES] = { 0x29038, 2 }, + [GCC_PCIE1_AXI_S_ARES] = { 0x29040, 2 }, + [GCC_PCIE1_AXI_S_BRIDGE_ARES] = { 0x29048, 2 }, + [GCC_PCIE1_PIPE_ARES] = { 0x29068, 2 }, + [GCC_PCIE1_AUX_ARES] = { 0x29074, 2 }, + [GCC_PCIE2_AHB_ARES] = { 0x2a030, 2 }, + [GCC_PCIE2_AXI_M_ARES] = { 0x2a038, 2 }, + [GCC_PCIE2_AXI_S_ARES] = { 0x2a040, 2 }, + [GCC_PCIE2_AXI_S_BRIDGE_ARES] = { 0x2a048, 2 }, + [GCC_PCIE2_PIPE_ARES] = { 0x2a068, 2 }, + [GCC_PCIE2_AUX_ARES] = { 0x2a078, 2 }, + [GCC_PCIE3_AHB_ARES] = { 0x2b030, 2 }, + [GCC_PCIE3_AXI_M_ARES] = { 0x2b038, 2 }, + [GCC_PCIE3_AXI_S_ARES] = { 0x2b040, 2 }, + [GCC_PCIE3_AXI_S_BRIDGE_ARES] = { 0x2b048, 2 }, + [GCC_PCIE3_PIPE_ARES] = { 0x2b068, 2 }, + [GCC_PCIE3_AUX_ARES] = { 0x2b07C, 2 }, + [GCC_USB0_MASTER_ARES] = { 0x2c044, 2 }, + [GCC_USB0_AUX_ARES] = { 0x2c04c, 2 }, + [GCC_USB0_MOCK_UTMI_ARES] = { 0x2c050, 2 }, + [GCC_USB0_PIPE_ARES] = { 0x2c054, 2 }, + [GCC_USB0_SLEEP_ARES] = { 0x2c058, 2 }, + [GCC_USB0_PHY_CFG_AHB_ARES] = { 0x2c05c, 2 }, + [GCC_QDSS_AT_ARES] = { 0x2d034, 2 }, + [GCC_QDSS_STM_ARES] = { 0x2d03C, 2 }, + [GCC_QDSS_TRACECLKIN_ARES] = { 0x2d040, 2 }, + [GCC_QDSS_TSCTR_DIV2_ARES] = { 0x2d044, 2 }, + [GCC_QDSS_TSCTR_DIV3_ARES] = { 0x2d048, 2 }, + [GCC_QDSS_TSCTR_DIV4_ARES] = { 0x2d04c, 2 }, + [GCC_QDSS_TSCTR_DIV8_ARES] = { 0x2d050, 2 }, + [GCC_QDSS_TSCTR_DIV16_ARES] = { 0x2d054, 2 }, + [GCC_QDSS_DAP_ARES] = { 0x2d058, 2 }, + [GCC_QDSS_APB2JTAG_ARES] = { 0x2d05c, 2 }, + [GCC_QDSS_ETR_USB_ARES] = { 0x2d060, 2 }, + [GCC_QDSS_DAP_AHB_ARES] = { 0x2d064, 2 }, + [GCC_QDSS_CFG_AHB_ARES] = { 0x2d068, 2 }, + [GCC_QDSS_EUD_AT_ARES] = { 0x2d06c, 2 }, + [GCC_QDSS_TS_ARES] = { 0x2d078, 2 }, + [GCC_QDSS_USB_ARES] = { 0x2d07c, 2 }, + [GCC_SYS_NOC_AXI_ARES] = { 0x2e01c, 2 }, + [GCC_SNOC_QOSGEN_EXTREF_ARES] = { 0x2e020, 2 }, + [GCC_CNOC_LPASS_CFG_ARES] = { 0x2e028, 2 }, + [GCC_SYS_NOC_AT_ARES] = { 0x2e038, 2 }, + [GCC_SNOC_PCNOC_AHB_ARES] = { 0x2e03c, 2 }, + [GCC_SNOC_TME_ARES] = { 0x2e05c, 2 }, + [GCC_SNOC_XO_DCD_ARES] = { 0x2e060, 2 }, + [GCC_SNOC_TS_ARES] = { 0x2e068, 2 }, + [GCC_ANOC0_AXI_ARES] = { 0x2e078, 2 }, + [GCC_ANOC_PCIE0_1LANE_M_ARES] = { 0x2e07c, 2 }, + [GCC_ANOC_PCIE2_2LANE_M_ARES] = { 0x2e080, 2 }, + [GCC_ANOC_PCIE1_1LANE_M_ARES] = { 0x2e084, 2 }, + [GCC_ANOC_PCIE3_2LANE_M_ARES] = { 0x2e090, 2 }, + [GCC_ANOC_PCNOC_AHB_ARES] = { 0x2e094, 2 }, + [GCC_ANOC_QOSGEN_EXTREF_ARES] = { 0x2e098, 2 }, + [GCC_ANOC_XO_DCD_ARES] = { 0x2e09C, 2 }, + [GCC_SNOC_XO_DBG_ARES] = { 0x2e0a0, 2 }, + [GCC_AGGRNOC_ATB_ARES] = { 0x2e0ac, 2 }, + [GCC_AGGRNOC_TS_ARES] = { 0x2e0b0, 2 }, + [GCC_USB0_EUD_AT_ARES] = { 0x30004, 2 }, + [GCC_PCNOC_TIC_ARES] = { 0x31014, 2 }, + [GCC_PCNOC_AHB_ARES] = { 0x31018, 2 }, + [GCC_PCNOC_XO_DBG_ARES] = { 0x3101c, 2 }, + [GCC_SNOC_LPASS_ARES] = { 0x31020, 2 }, + [GCC_PCNOC_AT_ARES] = { 0x31024, 2 }, + [GCC_PCNOC_XO_DCD_ARES] = { 0x31028, 2 }, + [GCC_PCNOC_TS_ARES] = { 0x3102c, 2 }, + [GCC_PCNOC_BUS_TIMEOUT0_AHB_ARES] = { 0x31034, 2 }, + [GCC_PCNOC_BUS_TIMEOUT1_AHB_ARES] = { 0x3103c, 2 }, + [GCC_PCNOC_BUS_TIMEOUT2_AHB_ARES] = { 0x31044, 2 }, + [GCC_PCNOC_BUS_TIMEOUT3_AHB_ARES] = { 0x3104c, 2 }, + [GCC_PCNOC_BUS_TIMEOUT4_AHB_ARES] = { 0x31054, 2 }, + [GCC_PCNOC_BUS_TIMEOUT5_AHB_ARES] = { 0x3105c, 2 }, + [GCC_PCNOC_BUS_TIMEOUT6_AHB_ARES] = { 0x31064, 2 }, + [GCC_PCNOC_BUS_TIMEOUT7_AHB_ARES] = { 0x3106c, 2 }, + [GCC_Q6_AXIM_RESET] = { 0x2506c, 0 }, + [GCC_Q6_AXIS_RESET] = { 0x2506c, 1 }, + [GCC_Q6_AHB_S_RESET] = { 0x2506c, 2 }, + [GCC_Q6_AHB_RESET] = { 0x2506c, 3 }, + [GCC_Q6SS_DBG_RESET] = { 0x2506c, 4 }, + [GCC_WCSS_ECAHB_RESET] = { 0x25070, 0 }, + [GCC_WCSS_DBG_BDG_RESET] = { 0x25070, 1 }, + [GCC_WCSS_DBG_RESET] = { 0x25070, 2 }, + [GCC_WCSS_AXI_M_RESET] = { 0x25070, 3 }, + [GCC_WCSS_AHB_S_RESET] = { 0x25070, 4 }, + [GCC_WCSS_ACMT_RESET] = { 0x25070, 5 }, + [GCC_WCSSAON_RESET] = { 0x25074, 0 }, + [GCC_PCIE0_PIPE_RESET] = { 0x28058, 0 }, + [GCC_PCIE0_CORE_STICKY_RESET] = { 0x28058, 1 }, + [GCC_PCIE0_AXI_S_STICKY_RESET] = { 0x28058, 2 }, + [GCC_PCIE0_AXI_S_RESET] = { 0x28058, 3 }, + [GCC_PCIE0_AXI_M_STICKY_RESET] = { 0x28058, 4 }, + [GCC_PCIE0_AXI_M_RESET] = { 0x28058, 5 }, + [GCC_PCIE0_AUX_RESET] = { 0x28058, 6 }, + [GCC_PCIE0_AHB_RESET] = { 0x28058, 7 }, + [GCC_PCIE1_PIPE_RESET] = { 0x29058, 0 }, + [GCC_PCIE1_CORE_STICKY_RESET] = { 0x29058, 1 }, + [GCC_PCIE1_AXI_S_STICKY_RESET] = { 0x29058, 2 }, + [GCC_PCIE1_AXI_S_RESET] = { 0x29058, 3 }, + [GCC_PCIE1_AXI_M_STICKY_RESET] = { 0x29058, 4 }, + [GCC_PCIE1_AXI_M_RESET] = { 0x29058, 5 }, + [GCC_PCIE1_AUX_RESET] = { 0x29058, 6 }, + [GCC_PCIE1_AHB_RESET] = { 0x29058, 7 }, + [GCC_PCIE2_PIPE_RESET] = { 0x2a058, 0 }, + [GCC_PCIE2_CORE_STICKY_RESET] = { 0x2a058, 1 }, + [GCC_PCIE2_AXI_S_STICKY_RESET] = { 0x2a058, 2 }, + [GCC_PCIE2_AXI_S_RESET] = { 0x2a058, 3 }, + [GCC_PCIE2_AXI_M_STICKY_RESET] = { 0x2a058, 4 }, + [GCC_PCIE2_AXI_M_RESET] = { 0x2a058, 5 }, + [GCC_PCIE2_AUX_RESET] = { 0x2a058, 6 }, + [GCC_PCIE2_AHB_RESET] = { 0x2a058, 7 }, + [GCC_PCIE3_PIPE_RESET] = { 0x2b058, 0 }, + [GCC_PCIE3_CORE_STICKY_RESET] = { 0x2b058, 1 }, + [GCC_PCIE3_AXI_S_STICKY_RESET] = { 0x2b058, 2 }, + [GCC_PCIE3_AXI_S_RESET] = { 0x2b058, 3 }, + [GCC_PCIE3_AXI_M_STICKY_RESET] = { 0x2b058, 4 }, + [GCC_PCIE3_AXI_M_RESET] = { 0x2b058, 5 }, + [GCC_PCIE3_AUX_RESET] = { 0x2b058, 6 }, + [GCC_PCIE3_AHB_RESET] = { 0x2b058, 7 }, + [GCC_NSS_PARTIAL_RESET] = { 0x17078, 0 }, + [GCC_UNIPHY0_XPCS_ARES] = { 0x17050, 2 }, + [GCC_UNIPHY1_XPCS_ARES] = { 0x17060, 2 }, + [GCC_UNIPHY2_XPCS_ARES] = { 0x17070, 2 }, + [GCC_USB1_BCR] = { 0x3C000, 0 }, + [GCC_QUSB2_1_PHY_BCR] = { 0x3C030, 0 }, +}; + +static const struct of_device_id gcc_ipq5424_match_table[] = { + { .compatible = "qcom,ipq5424-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_ipq5424_match_table); + +static const struct regmap_config gcc_ipq5424_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x3f024, + .fast_io = true, +}; + +static struct clk_hw *gcc_ipq5424_hws[] = { + &gpll0_div2.hw, + &gcc_xo_div4_clk_src.hw, + &gcc_qdss_tsctr_div2_clk_src.hw, + &gcc_qdss_dap_sync_clk_src.hw, + &gcc_eud_at_div_clk_src.hw, +}; + +static const struct qcom_cc_desc gcc_ipq5424_desc = { + .config = &gcc_ipq5424_regmap_config, + .clks = gcc_ipq5424_clocks, + .num_clks = ARRAY_SIZE(gcc_ipq5424_clocks), + .resets = gcc_ipq5424_resets, + .num_resets = ARRAY_SIZE(gcc_ipq5424_resets), + .clk_hws = gcc_ipq5424_hws, + .num_clk_hws = ARRAY_SIZE(gcc_ipq5424_hws), +}; + +static int gcc_ipq5424_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &gcc_ipq5424_desc); +} + +static struct platform_driver gcc_ipq5424_driver = { + .probe = gcc_ipq5424_probe, + .driver = { + .name = "qcom,gcc-ipq5424", + .of_match_table = gcc_ipq5424_match_table, + }, +}; + +static int __init gcc_ipq5424_init(void) +{ + return platform_driver_register(&gcc_ipq5424_driver); +} +core_initcall(gcc_ipq5424_init); + +static void __exit gcc_ipq5424_exit(void) +{ + platform_driver_unregister(&gcc_ipq5424_driver); +} +module_exit(gcc_ipq5424_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. GCC IPQ5424 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-ipq9574.c b/drivers/clk/qcom/gcc-ipq9574.c index 645109f75b46cd..6bb66a7e1fb65d 100644 --- a/drivers/clk/qcom/gcc-ipq9574.c +++ b/drivers/clk/qcom/gcc-ipq9574.c @@ -2645,24 +2645,6 @@ static struct clk_rcg2 system_noc_bfdcd_clk_src = { }, }; -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 = &(const 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 = { @@ -2733,91 +2715,6 @@ static struct clk_rcg2 wcss_ahb_clk_src = { }, }; -static struct clk_branch gcc_q6_ahb_clk = { - .halt_reg = 0x25014, - .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 *[]) { - &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 = &(const 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 = &(const 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 = &(const 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 = &(const 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), @@ -2838,23 +2735,6 @@ static struct clk_rcg2 wcss_axi_m_clk_src = { }, }; -static struct clk_branch gcc_anoc_wcss_axi_m_clk = { - .halt_reg = 0x2e0a8, - .clkr = { - .enable_reg = 0x2e0a8, - .enable_mask = BIT(0), - .hw.init = &(const 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), { } @@ -2873,40 +2753,6 @@ static struct clk_rcg2 qdss_at_clk_src = { }, }; -static struct clk_branch gcc_q6ss_atbm_clk = { - .halt_reg = 0x2501c, - .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 *[]) { - &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 = &(const 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 = { @@ -3143,40 +2989,6 @@ static struct clk_fixed_factor qdss_tsctr_div2_clk_src = { }, }; -static struct clk_branch gcc_q6_tsctr_1to2_clk = { - .halt_reg = 0x25020, - .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 *[]) { - &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 = &(const 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 = { @@ -3351,74 +3163,6 @@ static struct clk_branch gcc_qdss_tsctr_div16_clk = { }, }; -static struct clk_branch gcc_q6ss_pclkdbg_clk = { - .halt_reg = 0x25024, - .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 *[]) { - &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 = &(const 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 = &(const 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 = &(const 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 = { @@ -3540,58 +3284,6 @@ static struct clk_rcg2 q6_axi_clk_src = { }, }; -static struct clk_branch gcc_q6_axim_clk = { - .halt_reg = 0x2500c, - .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 *[]) { - &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 = &(const 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 = &(const 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), { } @@ -4141,16 +3833,8 @@ static struct clk_regmap *gcc_ipq9574_clks[] = { [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, @@ -4163,27 +3847,18 @@ static struct clk_regmap *gcc_ipq9574_clks[] = { [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, @@ -4207,7 +3882,6 @@ static struct clk_regmap *gcc_ipq9574_clks[] = { [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, @@ -4384,7 +4058,7 @@ static const struct qcom_reset_map gcc_ipq9574_resets[] = { #define IPQ_APPS_ID 9574 /* some unique value */ -static struct qcom_icc_hws_data icc_ipq9574_hws[] = { +static const struct qcom_icc_hws_data icc_ipq9574_hws[] = { { MASTER_ANOC_PCIE0, SLAVE_ANOC_PCIE0, GCC_ANOC_PCIE0_1LANE_M_CLK }, { MASTER_SNOC_PCIE0, SLAVE_SNOC_PCIE0, GCC_SNOC_PCIE0_1LANE_S_CLK }, { MASTER_ANOC_PCIE1, SLAVE_ANOC_PCIE1, GCC_ANOC_PCIE1_1LANE_M_CLK }, diff --git a/drivers/clk/qcom/gcc-qcs404.c b/drivers/clk/qcom/gcc-qcs404.c index c3cfd572e7c1e0..5ca003c9bfba89 100644 --- a/drivers/clk/qcom/gcc-qcs404.c +++ b/drivers/clk/qcom/gcc-qcs404.c @@ -131,6 +131,7 @@ static struct clk_alpha_pll gpll1_out_main = { /* 930MHz configuration */ static const struct alpha_pll_config gpll3_config = { .l = 48, + .alpha_hi = 0x70, .alpha = 0x0, .alpha_en_mask = BIT(24), .post_div_mask = 0xf << 8, diff --git a/drivers/clk/qcom/gcc-qcs8300.c b/drivers/clk/qcom/gcc-qcs8300.c new file mode 100644 index 00000000000000..80831c7dea3bcd --- /dev/null +++ b/drivers/clk/qcom/gcc-qcs8300.c @@ -0,0 +1,3640 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#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 "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_SLEEP_CLK, + DT_PCIE_0_PIPE_CLK, + DT_PCIE_1_PIPE_CLK, + DT_PCIE_PHY_AUX_CLK, + DT_RXC0_REF_CLK, + DT_UFS_PHY_RX_SYMBOL_0_CLK, + DT_UFS_PHY_RX_SYMBOL_1_CLK, + DT_UFS_PHY_TX_SYMBOL_0_CLK, + DT_USB3_PHY_WRAPPER_GCC_USB30_PRIM_PIPE_CLK, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL1_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL7_OUT_MAIN, + P_GCC_GPLL9_OUT_MAIN, + P_PCIE_0_PIPE_CLK, + P_PCIE_1_PIPE_CLK, + P_PCIE_PHY_AUX_CLK, + P_RXC0_REF_CLK, + P_SLEEP_CLK, + P_UFS_PHY_RX_SYMBOL_0_CLK, + P_UFS_PHY_RX_SYMBOL_1_CLK, + P_UFS_PHY_TX_SYMBOL_0_CLK, + P_USB3_PHY_WRAPPER_GCC_USB30_PRIM_PIPE_CLK, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x4b028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_evo_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll1 = { + .offset = 0x1000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x4b028, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x4b028, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll7 = { + .offset = 0x7000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x4b028, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x4b028, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL1_OUT_MAIN, 4 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll1.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll7.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_RXC0_REF_CLK, 3 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll7.clkr.hw }, + { .index = DT_RXC0_REF_CLK }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_PCIE_PHY_AUX_CLK, 1 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_PCIE_PHY_AUX_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_PCIE_PHY_AUX_CLK, 1 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_10[] = { + { .index = DT_PCIE_PHY_AUX_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_12[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL9_OUT_MAIN, 2 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_12[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll9.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_13[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, +}; + +static const struct clk_parent_data gcc_parent_data_13[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_14[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL4_OUT_MAIN, 3 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_14[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_15[] = { + { P_UFS_PHY_RX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_15[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_16[] = { + { P_UFS_PHY_RX_SYMBOL_1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_16[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_1_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_17[] = { + { P_UFS_PHY_TX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_17[] = { + { .index = DT_UFS_PHY_TX_SYMBOL_0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_18[] = { + { P_USB3_PHY_WRAPPER_GCC_USB30_PRIM_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_18[] = { + { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PRIM_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static struct clk_regmap_mux gcc_pcie_0_phy_aux_clk_src = { + .reg = 0xa9074, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_8, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_aux_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = { + .reg = 0xa906c, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE_0_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_pcie_1_phy_aux_clk_src = { + .reg = 0x77074, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_10, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_aux_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_1_pipe_clk_src = { + .reg = 0x7706c, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE_1_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_0_clk_src = { + .reg = 0x83060, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_15, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk_src", + .parent_data = gcc_parent_data_15, + .num_parents = ARRAY_SIZE(gcc_parent_data_15), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_1_clk_src = { + .reg = 0x830d0, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_16, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk_src", + .parent_data = gcc_parent_data_16, + .num_parents = ARRAY_SIZE(gcc_parent_data_16), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_tx_symbol_0_clk_src = { + .reg = 0x83050, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_17, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk_src", + .parent_data = gcc_parent_data_17, + .num_parents = ARRAY_SIZE(gcc_parent_data_17), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x1b068, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_18, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_18, + .num_parents = ARRAY_SIZE(gcc_parent_data_18), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_emac0_phy_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_emac0_phy_aux_clk_src = { + .cmd_rcgr = 0xb6028, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_emac0_phy_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_emac0_ptp_clk_src[] = { + F(125000000, P_GCC_GPLL7_OUT_MAIN, 8, 0, 0), + F(230400000, P_GCC_GPLL4_OUT_MAIN, 3.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_emac0_ptp_clk_src = { + .cmd_rcgr = 0xb6060, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_emac0_ptp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_emac0_ptp_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_emac0_rgmii_clk_src[] = { + F(5000000, P_GCC_GPLL0_OUT_EVEN, 10, 1, 6), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(125000000, P_GCC_GPLL7_OUT_MAIN, 8, 0, 0), + F(250000000, P_GCC_GPLL7_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_emac0_rgmii_clk_src = { + .cmd_rcgr = 0xb6048, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_emac0_rgmii_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_emac0_rgmii_clk_src", + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x70004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .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_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x71004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .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_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x62004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp4_clk_src = { + .cmd_rcgr = 0x1e004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp4_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp5_clk_src = { + .cmd_rcgr = 0x1f004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp5_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0xa9078, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0xa9054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .cmd_rcgr = 0x77078, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = { + .cmd_rcgr = 0x77054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x3f010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { + .cmd_rcgr = 0x23154, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { + .cmd_rcgr = 0x23288, + .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 const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { + .cmd_rcgr = 0x233bc, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { + .cmd_rcgr = 0x234f0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { + .cmd_rcgr = 0x23624, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { + .cmd_rcgr = 0x23758, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = { + .cmd_rcgr = 0x2388c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { + .cmd_rcgr = 0x239c0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x24154, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x24288, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { + .cmd_rcgr = 0x243bc, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x244f0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x24624, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x24758, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { + .cmd_rcgr = 0x2488c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { + .cmd_rcgr = 0x249c0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap3_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(403200000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap3_s0_clk_src_init = { + .name = "gcc_qupv3_wrap3_s0_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_s0_clk_src = { + .cmd_rcgr = 0xc4158, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_qupv3_wrap3_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_s0_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_GCC_GPLL0_OUT_EVEN, 5, 1, 3), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(192000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + F(384000000, P_GCC_GPLL9_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0x20014, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_12, + .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_12, + .num_parents = ARRAY_SIZE(gcc_parent_data_12), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = { + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x2002c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_13, + .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_data = gcc_parent_data_13, + .num_parents = ARRAY_SIZE(gcc_parent_data_13), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x8302c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(const 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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(201600000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403200000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x83074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_14, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = gcc_parent_data_14, + .num_parents = ARRAY_SIZE(gcc_parent_data_14), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x830a8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x8308c, + .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 = &(const 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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb20_master_clk_src[] = { + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb20_master_clk_src = { + .cmd_rcgr = 0x1c028, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb20_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb20_mock_utmi_clk_src = { + .cmd_rcgr = 0x1c040, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0x1b028, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .clkr.hw.init = &(const 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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x1b040, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src, + .clkr.hw.init = &(const 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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x1b06c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_emac0_phy_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div gcc_pcie_0_pipe_div_clk_src = { + .reg = 0xa9070, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_pcie_1_pipe_div_clk_src = { + .reg = 0x77070, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap3_s0_div_clk_src = { + .reg = 0xc4288, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb20_mock_utmi_postdiv_clk_src = { + .reg = 0x1c058, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = { + .reg = 0x1b058, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src", + .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_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_qupv3_axi_clk = { + .halt_reg = 0x8e200, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8e200, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_qupv3_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x830d4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x830d4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x830d4, + .enable_mask = BIT(0), + .hw.init = &(const 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_usb2_prim_axi_clk = { + .halt_reg = 0x1c05c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1c05c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x1c05c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb2_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0x1b084, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1b084, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x1b084, + .enable_mask = BIT(0), + .hw.init = &(const 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_ahb2phy0_clk = { + .halt_reg = 0x76004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x76004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x76004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ahb2phy0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ahb2phy2_clk = { + .halt_reg = 0x76008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x76008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x76008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ahb2phy2_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ahb2phy3_clk = { + .halt_reg = 0x7600c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7600c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7600c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ahb2phy3_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x44004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x44004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(10), + .hw.init = &(const 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 = 0x32010, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x32018, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_throttle_xo_clk = { + .halt_reg = 0x32024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x32024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_throttle_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb2_prim_axi_clk = { + .halt_reg = 0x1c060, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1c060, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x1c060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb2_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x1b088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1b088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x1b088, + .enable_mask = BIT(0), + .hw.init = &(const 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_ddrss_gpu_axi_clk = { + .halt_reg = 0x7d164, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7d164, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7d164, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_gpu_axi_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x33010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x33010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_edp_ref_clkref_en = { + .halt_reg = 0x97448, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x97448, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_edp_ref_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_emac0_axi_clk = { + .halt_reg = 0xb6018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb6018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb6018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_emac0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_emac0_phy_aux_clk = { + .halt_reg = 0xb6024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb6024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_emac0_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_emac0_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_emac0_ptp_clk = { + .halt_reg = 0xb6040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb6040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_emac0_ptp_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_emac0_ptp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_emac0_rgmii_clk = { + .halt_reg = 0xb6044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb6044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_emac0_rgmii_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_emac0_rgmii_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_emac0_slv_ahb_clk = { + .halt_reg = 0xb6020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb6020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb6020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_emac0_slv_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x70000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x70000, + .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 = 0x71000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x71000, + .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_gp3_clk = { + .halt_reg = 0x62000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(0), + .hw.init = &(const 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_gp4_clk = { + .halt_reg = 0x1e000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1e000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp5_clk = { + .halt_reg = 0x1f000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1f000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp5_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 = 0x4b000, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_memnoc_gfx_center_pipeline_clk = { + .halt_reg = 0x7d160, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7d160, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7d160, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_memnoc_gfx_center_pipeline_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_memnoc_gfx_clk = { + .halt_reg = 0x7d010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7d010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7d010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_memnoc_gfx_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { + .halt_reg = 0x7d01c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x7d01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_tcu_throttle_ahb_clk = { + .halt_reg = 0x7d008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7d008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7d008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_tcu_throttle_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_tcu_throttle_clk = { + .halt_reg = 0x7d014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7d014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7d014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_tcu_throttle_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0xa9038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b010, + .enable_mask = BIT(16), + .hw.init = &(const 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 = 0xa902c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa902c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b010, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0xa9024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b010, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_phy_aux_clk = { + .halt_reg = 0xa9030, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b010, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_phy_rchng_clk = { + .halt_reg = 0xa9050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b010, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0xa9040, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x4b010, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipediv2_clk = { + .halt_reg = 0xa9048, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x4b018, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0xa901c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b010, + .enable_mask = BIT(10), + .hw.init = &(const 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 = 0xa9018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b018, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_aux_clk = { + .halt_reg = 0x77038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { + .halt_reg = 0x7702c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7702c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_mstr_axi_clk = { + .halt_reg = 0x77024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_phy_aux_clk = { + .halt_reg = 0x77030, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_phy_rchng_clk = { + .halt_reg = 0x77050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_pipe_clk = { + .halt_reg = 0x77040, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_pipediv2_clk = { + .halt_reg = 0x77048, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x4b018, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_axi_clk = { + .halt_reg = 0x7701c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = { + .halt_reg = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_clkref_en = { + .halt_reg = 0x9746c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x9746c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_throttle_cfg_clk = { + .halt_reg = 0xb2034, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b020, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_throttle_cfg_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3f00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f00c, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x3f004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3f004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3f004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x3f008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3f008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = { + .halt_reg = 0x32008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_nrt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_rt_ahb_clk = { + .halt_reg = 0x3200c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3200c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3200c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_rt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_disp_ahb_clk = { + .halt_reg = 0x33008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x33008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_disp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_disp_rot_ahb_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x3300c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_disp_rot_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_ahb_clk = { + .halt_reg = 0x34008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x34008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x34008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = { + .halt_reg = 0x3400c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3400c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3400c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcpu_ahb_clk = { + .halt_reg = 0x34010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x34010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x34010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = { + .halt_reg = 0x23018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(9), + .hw.init = &(const 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 = 0x2300c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(8), + .hw.init = &(const 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 = 0x2314c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(10), + .hw.init = &(const 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 = 0x23280, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(11), + .hw.init = &(const 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 = 0x233b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(12), + .hw.init = &(const 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 = 0x234e8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(13), + .hw.init = &(const 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 = 0x2361c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(14), + .hw.init = &(const 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 = 0x23750, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(15), + .hw.init = &(const 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 = 0x23884, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(16), + .hw.init = &(const 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 = 0x239b8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(17), + .hw.init = &(const 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 = 0x24018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(18), + .hw.init = &(const 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 = 0x2400c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(19), + .hw.init = &(const 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 = 0x2414c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(22), + .hw.init = &(const 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 = 0x24280, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(23), + .hw.init = &(const 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 = 0x243b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(24), + .hw.init = &(const 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 = 0x244e8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(25), + .hw.init = &(const 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 = 0x2461c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(26), + .hw.init = &(const 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 = 0x24750, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(27), + .hw.init = &(const 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 = 0x24884, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b018, + .enable_mask = BIT(27), + .hw.init = &(const 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 = 0x249b8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b018, + .enable_mask = BIT(28), + .hw.init = &(const 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_wrap3_core_2x_clk = { + .halt_reg = 0xc4018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_core_clk = { + .halt_reg = 0xc400c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_qspi_clk = { + .halt_reg = 0xc4284, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_qspi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap3_s0_clk = { + .halt_reg = 0xc4150, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_s0_div_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 = 0x23004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(6), + .hw.init = &(const 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 = 0x23008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(7), + .hw.init = &(const 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 = 0x24004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x24004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(20), + .hw.init = &(const 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 = 0x24008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x24008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b008, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_3_m_ahb_clk = { + .halt_reg = 0xc4004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc4004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_3_s_ahb_clk = { + .halt_reg = 0xc4008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xc4008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4b000, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x2000c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2000c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x20004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x20004, + .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_sdcc1_ice_core_clk = { + .halt_reg = 0x20044, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x20044, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x20044, + .enable_mask = BIT(0), + .hw.init = &(const 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_sgmi_clkref_en = { + .halt_reg = 0x97034, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x97034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sgmi_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0x83020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x83020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x83020, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x83018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x83018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x83018, + .enable_mask = BIT(0), + .hw.init = &(const 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_ice_core_clk = { + .halt_reg = 0x8306c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8306c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x8306c, + .enable_mask = BIT(0), + .hw.init = &(const 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_phy_aux_clk = { + .halt_reg = 0x830a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x830a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x830a4, + .enable_mask = BIT(0), + .hw.init = &(const 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_rx_symbol_0_clk = { + .halt_reg = 0x83028, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x83028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { + .halt_reg = 0x830c0, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x830c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x83024, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x83024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_tx_symbol_0_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_clk = { + .halt_reg = 0x83064, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x83064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x83064, + .enable_mask = BIT(0), + .hw.init = &(const 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_usb20_master_clk = { + .halt_reg = 0x1c018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1c018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_mock_utmi_clk = { + .halt_reg = 0x1c024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1c024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb20_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb20_sleep_clk = { + .halt_reg = 0x1c020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1c020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb20_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0x1b018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1b018, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x1b024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1b024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_postdiv_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 = 0x1b020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1b020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0x1b05c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1b05c, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x1b060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1b060, + .enable_mask = BIT(0), + .hw.init = &(const 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_reg = 0x1b064, + .halt_check = BRANCH_HALT_DELAY, + .hwcg_reg = 0x1b064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x1b064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb_clkref_en = { + .halt_reg = 0x97468, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x97468, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0_clk = { + .halt_reg = 0x34014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x34014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x34014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0x3401c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3401c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3401c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gcc_emac0_gdsc = { + .gdscr = 0xb6004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_emac0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_pcie_0_gdsc = { + .gdscr = 0xa9004, + .collapse_ctrl = 0x4b104, + .collapse_mask = BIT(0), + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE | POLL_CFG_GDSCR, +}; + +static struct gdsc gcc_pcie_1_gdsc = { + .gdscr = 0x77004, + .collapse_ctrl = 0x4b104, + .collapse_mask = BIT(1), + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE | POLL_CFG_GDSCR, +}; + +static struct gdsc gcc_ufs_phy_gdsc = { + .gdscr = 0x83004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, +}; + +static struct gdsc gcc_usb20_prim_gdsc = { + .gdscr = 0x1c004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb20_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, +}; + +static struct gdsc gcc_usb30_prim_gdsc = { + .gdscr = 0x1b004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, +}; + +static struct clk_regmap *gcc_qcs8300_clocks[] = { + [GCC_AGGRE_NOC_QUPV3_AXI_CLK] = &gcc_aggre_noc_qupv3_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_USB2_PRIM_AXI_CLK] = &gcc_aggre_usb2_prim_axi_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_AHB2PHY0_CLK] = &gcc_ahb2phy0_clk.clkr, + [GCC_AHB2PHY2_CLK] = &gcc_ahb2phy2_clk.clkr, + [GCC_AHB2PHY3_CLK] = &gcc_ahb2phy3_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_CAMERA_THROTTLE_XO_CLK] = &gcc_camera_throttle_xo_clk.clkr, + [GCC_CFG_NOC_USB2_PRIM_AXI_CLK] = &gcc_cfg_noc_usb2_prim_axi_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_EDP_REF_CLKREF_EN] = &gcc_edp_ref_clkref_en.clkr, + [GCC_EMAC0_AXI_CLK] = &gcc_emac0_axi_clk.clkr, + [GCC_EMAC0_PHY_AUX_CLK] = &gcc_emac0_phy_aux_clk.clkr, + [GCC_EMAC0_PHY_AUX_CLK_SRC] = &gcc_emac0_phy_aux_clk_src.clkr, + [GCC_EMAC0_PTP_CLK] = &gcc_emac0_ptp_clk.clkr, + [GCC_EMAC0_PTP_CLK_SRC] = &gcc_emac0_ptp_clk_src.clkr, + [GCC_EMAC0_RGMII_CLK] = &gcc_emac0_rgmii_clk.clkr, + [GCC_EMAC0_RGMII_CLK_SRC] = &gcc_emac0_rgmii_clk_src.clkr, + [GCC_EMAC0_SLV_AHB_CLK] = &gcc_emac0_slv_ahb_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_GP4_CLK] = &gcc_gp4_clk.clkr, + [GCC_GP4_CLK_SRC] = &gcc_gp4_clk_src.clkr, + [GCC_GP5_CLK] = &gcc_gp5_clk.clkr, + [GCC_GP5_CLK_SRC] = &gcc_gp5_clk_src.clkr, + [GCC_GPLL0] = &gcc_gpll0.clkr, + [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr, + [GCC_GPLL1] = &gcc_gpll1.clkr, + [GCC_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL7] = &gcc_gpll7.clkr, + [GCC_GPLL9] = &gcc_gpll9.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_CENTER_PIPELINE_CLK] = &gcc_gpu_memnoc_gfx_center_pipeline_clk.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_TCU_THROTTLE_AHB_CLK] = &gcc_gpu_tcu_throttle_ahb_clk.clkr, + [GCC_GPU_TCU_THROTTLE_CLK] = &gcc_gpu_tcu_throttle_clk.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_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PHY_AUX_CLK] = &gcc_pcie_0_phy_aux_clk.clkr, + [GCC_PCIE_0_PHY_AUX_CLK_SRC] = &gcc_pcie_0_phy_aux_clk_src.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr, + [GCC_PCIE_0_PIPE_DIV_CLK_SRC] = &gcc_pcie_0_pipe_div_clk_src.clkr, + [GCC_PCIE_0_PIPEDIV2_CLK] = &gcc_pcie_0_pipediv2_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_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr, + [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr, + [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr, + [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr, + [GCC_PCIE_1_PHY_AUX_CLK] = &gcc_pcie_1_phy_aux_clk.clkr, + [GCC_PCIE_1_PHY_AUX_CLK_SRC] = &gcc_pcie_1_phy_aux_clk_src.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK] = &gcc_pcie_1_phy_rchng_clk.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr, + [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr, + [GCC_PCIE_1_PIPE_CLK_SRC] = &gcc_pcie_1_pipe_clk_src.clkr, + [GCC_PCIE_1_PIPE_DIV_CLK_SRC] = &gcc_pcie_1_pipe_div_clk_src.clkr, + [GCC_PCIE_1_PIPEDIV2_CLK] = &gcc_pcie_1_pipediv2_clk.clkr, + [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr, + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr, + [GCC_PCIE_CLKREF_EN] = &gcc_pcie_clkref_en.clkr, + [GCC_PCIE_THROTTLE_CFG_CLK] = &gcc_pcie_throttle_cfg_clk.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_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr, + [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr, + [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr, + [GCC_QMIP_DISP_ROT_AHB_CLK] = &gcc_qmip_disp_rot_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCPU_AHB_CLK] = &gcc_qmip_video_vcpu_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_WRAP3_CORE_2X_CLK] = &gcc_qupv3_wrap3_core_2x_clk.clkr, + [GCC_QUPV3_WRAP3_CORE_CLK] = &gcc_qupv3_wrap3_core_clk.clkr, + [GCC_QUPV3_WRAP3_QSPI_CLK] = &gcc_qupv3_wrap3_qspi_clk.clkr, + [GCC_QUPV3_WRAP3_S0_CLK] = &gcc_qupv3_wrap3_s0_clk.clkr, + [GCC_QUPV3_WRAP3_S0_CLK_SRC] = &gcc_qupv3_wrap3_s0_clk_src.clkr, + [GCC_QUPV3_WRAP3_S0_DIV_CLK_SRC] = &gcc_qupv3_wrap3_s0_div_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_QUPV3_WRAP_3_M_AHB_CLK] = &gcc_qupv3_wrap_3_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_3_S_AHB_CLK] = &gcc_qupv3_wrap_3_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_SGMI_CLKREF_EN] = &gcc_sgmi_clkref_en.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_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_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_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_tx_symbol_0_clk_src.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_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr, + [GCC_USB20_MASTER_CLK_SRC] = &gcc_usb20_master_clk_src.clkr, + [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr, + [GCC_USB20_MOCK_UTMI_CLK_SRC] = &gcc_usb20_mock_utmi_clk_src.clkr, + [GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb20_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_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_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_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_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr, + [GCC_USB_CLKREF_EN] = &gcc_usb_clkref_en.clkr, + [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, +}; + +static struct gdsc *gcc_qcs8300_gdscs[] = { + [GCC_EMAC0_GDSC] = &gcc_emac0_gdsc, + [GCC_PCIE_0_GDSC] = &gcc_pcie_0_gdsc, + [GCC_PCIE_1_GDSC] = &gcc_pcie_1_gdsc, + [GCC_UFS_PHY_GDSC] = &gcc_ufs_phy_gdsc, + [GCC_USB20_PRIM_GDSC] = &gcc_usb20_prim_gdsc, + [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc, +}; + +static const struct qcom_reset_map gcc_qcs8300_resets[] = { + [GCC_EMAC0_BCR] = { 0xb6000 }, + [GCC_PCIE_0_BCR] = { 0xa9000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0xbf000 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0xbf008 }, + [GCC_PCIE_0_PHY_BCR] = { 0xa9144 }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0xbf00c }, + [GCC_PCIE_1_BCR] = { 0x77000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0xae084 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0xae090 }, + [GCC_PCIE_1_PHY_BCR] = { 0xae08c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0xae094 }, + [GCC_SDCC1_BCR] = { 0x20000 }, + [GCC_UFS_PHY_BCR] = { 0x83000 }, + [GCC_USB20_PRIM_BCR] = { 0x1c000 }, + [GCC_USB2_PHY_PRIM_BCR] = { 0x5c01c }, + [GCC_USB2_PHY_SEC_BCR] = { 0x5c020 }, + [GCC_USB30_PRIM_BCR] = { 0x1b000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x5c008 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x5c000 }, + [GCC_USB3_PHY_TERT_BCR] = { 0x5c024 }, + [GCC_USB3_UNIPHY_MP0_BCR] = { 0x5c00c }, + [GCC_USB3_UNIPHY_MP1_BCR] = { 0x5c010 }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x5c004 }, + [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x5c014 }, + [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x5c018 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x76000 }, + [GCC_VIDEO_AXI0_CLK_ARES] = { 0x34014, 2 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { 0x3401c, 2 }, + [GCC_VIDEO_BCR] = { 0x34000 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + 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), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_s0_clk_src), +}; + +static const struct regmap_config gcc_qcs8300_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x472cffc, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_qcs8300_desc = { + .config = &gcc_qcs8300_regmap_config, + .clks = gcc_qcs8300_clocks, + .num_clks = ARRAY_SIZE(gcc_qcs8300_clocks), + .resets = gcc_qcs8300_resets, + .num_resets = ARRAY_SIZE(gcc_qcs8300_resets), + .gdscs = gcc_qcs8300_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_qcs8300_gdscs), +}; + +static const struct of_device_id gcc_qcs8300_match_table[] = { + { .compatible = "qcom,qcs8300-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_qcs8300_match_table); + +static int gcc_qcs8300_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_qcs8300_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) + return ret; + + /* Keep some clocks always enabled */ + qcom_branch_set_clk_en(regmap, 0x32004); /* GCC_CAMERA_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x32020); /* GCC_CAMERA_XO_CLK */ + qcom_branch_set_clk_en(regmap, 0x33004); /* GCC_DISP_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x33018); /* GCC_DISP_XO_CLK */ + qcom_branch_set_clk_en(regmap, 0x7d004); /* GCC_GPU_CFG_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x34004); /* GCC_VIDEO_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x34024); /* GCC_VIDEO_XO_CLK */ + + /* FORCE_MEM_CORE_ON for ufs phy ice core clocks */ + qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); + + return qcom_cc_really_probe(&pdev->dev, &gcc_qcs8300_desc, regmap); +} + +static struct platform_driver gcc_qcs8300_driver = { + .probe = gcc_qcs8300_probe, + .driver = { + .name = "gcc-qcs8300", + .of_match_table = gcc_qcs8300_match_table, + }, +}; + +static int __init gcc_qcs8300_init(void) +{ + return platform_driver_register(&gcc_qcs8300_driver); +} +subsys_initcall(gcc_qcs8300_init); + +static void __exit gcc_qcs8300_exit(void) +{ + platform_driver_unregister(&gcc_qcs8300_driver); +} +module_exit(gcc_qcs8300_exit); + +MODULE_DESCRIPTION("QTI GCC QCS8300 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-sar2130p.c b/drivers/clk/qcom/gcc-sar2130p.c new file mode 100644 index 00000000000000..475e2cda3618b9 --- /dev/null +++ b/drivers/clk/qcom/gcc-sar2130p.c @@ -0,0 +1,2366 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021-2023, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ + +#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 "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "gdsc.h" +#include "reset.h" + +/* Need to match the order of clocks in DT binding */ +enum { + DT_BI_TCXO, + DT_SLEEP_CLK, + + DT_PCIE_0_PIPE, + DT_PCIE_1_PIPE, + + DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL1_OUT_EVEN, + P_GCC_GPLL1_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL5_OUT_MAIN, + P_GCC_GPLL7_OUT_MAIN, + P_GCC_GPLL9_OUT_EVEN, + P_PCIE_0_PIPE_CLK, + P_PCIE_1_PIPE_CLK, + P_SLEEP_CLK, + P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll1 = { + .offset = 0x1000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll5 = { + .offset = 0x5000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll5", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll7 = { + .offset = 0x7000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll9_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll9_out_even = { + .offset = 0x9000, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll9_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll9_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll9.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_GCC_GPLL5_OUT_MAIN, 3 }, + { P_GCC_GPLL1_OUT_MAIN, 4 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .hw = &gcc_gpll5.clkr.hw }, + { .hw = &gcc_gpll1.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.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_6[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL9_OUT_EVEN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll9_out_even.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL1_OUT_EVEN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll1.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = { + .reg = 0x7b070, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE_0_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_1_pipe_clk_src = { + .reg = 0x9d06c, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE_1_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x4906c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_8, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_ddrss_spad_clk_src[] = { + F(300000000, P_GCC_GPLL0_OUT_EVEN, 1, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + F(426400000, P_GCC_GPLL1_OUT_MAIN, 2.5, 0, 0), + F(500000000, P_GCC_GPLL7_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ddrss_spad_clk_src = { + .cmd_rcgr = 0x70004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_ddrss_spad_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_spad_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x74004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .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_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x75004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .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_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x76004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const 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_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0x7b074, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const 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_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0x7b058, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .cmd_rcgr = 0x9d070, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = { + .cmd_rcgr = 0x9d054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x43010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(const 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_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { + .cmd_rcgr = 0x28018, + .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 const struct freq_tbl ftbl_gcc_qupv3_wrap0_s1_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { + .cmd_rcgr = 0x28150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { + .cmd_rcgr = 0x28288, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { + .cmd_rcgr = 0x283c0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { + .cmd_rcgr = 0x284f8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { + .cmd_rcgr = 0x28630, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s5_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x2e018, + .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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x2e150, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { + .cmd_rcgr = 0x2e288, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x2e3c0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x2e4f8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_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_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x2e630, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s5_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(20000000, P_GCC_GPLL0_OUT_EVEN, 5, 1, 3), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(192000000, P_GCC_GPLL9_OUT_EVEN, 2, 0, 0), + F(384000000, P_GCC_GPLL9_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0x26018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .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_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .ops = &clk_rcg2_shared_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x2603c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .ops = &clk_rcg2_shared_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0), + F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0x4902c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .clkr.hw.init = &(const 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_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x49044, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const 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_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x49070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const 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_shared_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = { + .reg = 0x4905c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src", + .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_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_1_axi_clk = { + .halt_reg = 0x7b094, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x7b094, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0x4908c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4908c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4908c, + .enable_mask = BIT(0), + .hw.init = &(const 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_boot_rom_ahb_clk = { + .halt_reg = 0x48004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x48004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = { + .halt_reg = 0x20034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x20034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x49088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x49088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x49088, + .enable_mask = BIT(0), + .hw.init = &(const 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_ddrss_gpu_axi_clk = { + .halt_reg = 0x81154, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x81154, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x81154, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_gpu_axi_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_pcie_sf_clk = { + .halt_reg = 0x9d098, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x9d098, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_pcie_sf_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_spad_clk = { + .halt_reg = 0x70000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x70000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x70000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_spad_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ddrss_spad_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x37008, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x37008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x37008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x74000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x74000, + .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 = 0x75000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x75000, + .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_gp3_clk = { + .halt_reg = 0x76000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x76000, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x62000, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_memnoc_gfx_clk = { + .halt_reg = 0x9b010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9b010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9b010, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x9b018, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x9b018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_iris_ss_hf_axi1_clk = { + .halt_reg = 0x42030, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x42030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_iris_ss_hf_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_iris_ss_spd_axi1_clk = { + .halt_reg = 0x70020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x70020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x70020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_iris_ss_spd_axi1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ddrss_spad_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x7b03c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(3), + .hw.init = &(const 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 = 0x7b038, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7b038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0x7b02c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x7b02c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_phy_rchng_clk = { + .halt_reg = 0x7b054, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x7b048, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0x7b020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7b020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x7b01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_aux_clk = { + .halt_reg = 0x9d038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { + .halt_reg = 0x9d034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9d034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_mstr_axi_clk = { + .halt_reg = 0x9d028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x9d028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_phy_rchng_clk = { + .halt_reg = 0x9d050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_pipe_clk = { + .halt_reg = 0x9d044, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_1_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_axi_clk = { + .halt_reg = 0x9d01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9d01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = { + .halt_reg = 0x9d018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x4300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4300c, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x43004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x43004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x43004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x43008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x43008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_gpu_ahb_clk = { + .halt_reg = 0x9b008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9b008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9b008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_gpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_ahb_clk = { + .halt_reg = 0x7b018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7b018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = { + .halt_reg = 0x42014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x42014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cv_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_ahb_clk = { + .halt_reg = 0x42008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x42008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_lsr_ahb_clk = { + .halt_reg = 0x4204c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4204c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4204c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_lsr_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = { + .halt_reg = 0x42010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x42010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_v_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = { + .halt_reg = 0x4200c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4200c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4200c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = { + .halt_reg = 0x33034, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(18), + .hw.init = &(const 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 = 0x33024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(19), + .hw.init = &(const 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 = 0x2800c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(22), + .hw.init = &(const 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 = 0x28144, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(23), + .hw.init = &(const 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 = 0x2827c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(24), + .hw.init = &(const 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 = 0x283b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(25), + .hw.init = &(const 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 = 0x284ec, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(26), + .hw.init = &(const 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 = 0x28624, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(27), + .hw.init = &(const 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_wrap1_core_2x_clk = { + .halt_reg = 0x3317c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(3), + .hw.init = &(const 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 = 0x3316c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x2e00c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(4), + .hw.init = &(const 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 = 0x2e144, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(5), + .hw.init = &(const 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 = 0x2e27c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(6), + .hw.init = &(const 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 = 0x2e3b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(7), + .hw.init = &(const 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 = 0x2e4ec, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(8), + .hw.init = &(const 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 = 0x2e624, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(9), + .hw.init = &(const 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_wrap_0_m_ahb_clk = { + .halt_reg = 0x28004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x28004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(20), + .hw.init = &(const 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 = 0x28008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x28008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(21), + .hw.init = &(const 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 = 0x2e004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2e004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(2), + .hw.init = &(const 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 = 0x2e008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2e008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(1), + .hw.init = &(const 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 = 0x26010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x26010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x26004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x26004, + .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_sdcc1_ice_core_clk = { + .halt_reg = 0x26030, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26030, + .enable_mask = BIT(0), + .hw.init = &(const 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_usb30_prim_master_clk = { + .halt_reg = 0x49018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49018, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x49028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_postdiv_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 = 0x49024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0x49060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49060, + .enable_mask = BIT(0), + .hw.init = &(const 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 = 0x49064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49064, + .enable_mask = BIT(0), + .hw.init = &(const 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_reg = 0x49068, + .halt_check = BRANCH_HALT_DELAY, + .hwcg_reg = 0x49068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x49068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0_clk = { + .halt_reg = 0x42018, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x42018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0x42024, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x42024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc hlos1_vote_mm_snoc_mmu_tbu_hf0_gdsc = { + .gdscr = 0x8d204, + .pd = { + .name = "hlos1_vote_mm_snoc_mmu_tbu_hf0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_mm_snoc_mmu_tbu_sf0_gdsc = { + .gdscr = 0x8d054, + .pd = { + .name = "hlos1_vote_mm_snoc_mmu_tbu_sf0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_turing_mmu_tbu0_gdsc = { + .gdscr = 0x8d05c, + .pd = { + .name = "hlos1_vote_turing_mmu_tbu0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc hlos1_vote_turing_mmu_tbu1_gdsc = { + .gdscr = 0x8d060, + .pd = { + .name = "hlos1_vote_turing_mmu_tbu1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc pcie_0_gdsc = { + .gdscr = 0x7b004, + .collapse_ctrl = 0x62200, + .collapse_mask = BIT(0), + .pd = { + .name = "pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE, +}; + +static struct gdsc pcie_0_phy_gdsc = { + .gdscr = 0x7c000, + .collapse_ctrl = 0x62200, + .collapse_mask = BIT(3), + .pd = { + .name = "pcie_0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE, +}; + +static struct gdsc pcie_1_gdsc = { + .gdscr = 0x9d004, + .collapse_ctrl = 0x62200, + .collapse_mask = BIT(1), + .pd = { + .name = "pcie_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE, +}; + +static struct gdsc pcie_1_phy_gdsc = { + .gdscr = 0x9e000, + .collapse_ctrl = 0x62200, + .collapse_mask = BIT(4), + .pd = { + .name = "pcie_1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE, +}; + +static struct gdsc usb30_prim_gdsc = { + .gdscr = 0x49004, + .pd = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = RETAIN_FF_ENABLE, +}; + +static struct gdsc usb3_phy_gdsc = { + .gdscr = 0x60018, + .pd = { + .name = "usb3_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *gcc_sar2130p_clocks[] = { + [GCC_AGGRE_NOC_PCIE_1_AXI_CLK] = &gcc_aggre_noc_pcie_1_axi_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DDRSS_PCIE_SF_CLK] = &gcc_ddrss_pcie_sf_clk.clkr, + [GCC_DDRSS_SPAD_CLK] = &gcc_ddrss_spad_clk.clkr, + [GCC_DDRSS_SPAD_CLK_SRC] = &gcc_ddrss_spad_clk_src.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_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_GPLL0] = &gcc_gpll0.clkr, + [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr, + [GCC_GPLL1] = &gcc_gpll1.clkr, + [GCC_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL5] = &gcc_gpll5.clkr, + [GCC_GPLL7] = &gcc_gpll7.clkr, + [GCC_GPLL9] = &gcc_gpll9.clkr, + [GCC_GPLL9_OUT_EVEN] = &gcc_gpll9_out_even.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_IRIS_SS_HF_AXI1_CLK] = &gcc_iris_ss_hf_axi1_clk.clkr, + [GCC_IRIS_SS_SPD_AXI1_CLK] = &gcc_iris_ss_spd_axi1_clk.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_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.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_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr, + [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr, + [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr, + [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK] = &gcc_pcie_1_phy_rchng_clk.clkr, + [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr, + [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr, + [GCC_PCIE_1_PIPE_CLK_SRC] = &gcc_pcie_1_pipe_clk_src.clkr, + [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr, + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.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_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr, + [GCC_QMIP_PCIE_AHB_CLK] = &gcc_qmip_pcie_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_LSR_AHB_CLK] = &gcc_qmip_video_lsr_ahb_clk.clkr, + [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_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_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_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_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_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_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_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr, + [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, +}; + +static const struct qcom_reset_map gcc_sar2130p_resets[] = { + [GCC_DISPLAY_BCR] = { 0x37000 }, + [GCC_GPU_BCR] = { 0x9b000 }, + [GCC_PCIE_0_BCR] = { 0x7b000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x7c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x7c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x7c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x7c028 }, + [GCC_PCIE_1_BCR] = { 0x9d000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x9e014 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x9e020 }, + [GCC_PCIE_1_PHY_BCR] = { 0x9e01c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x9e024 }, + [GCC_PCIE_PHY_BCR] = { 0x7f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x7f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x7f010 }, + [GCC_PDM_BCR] = { 0x43000 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x28000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x2e000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x22000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x22004 }, + [GCC_SDCC1_BCR] = { 0x26000 }, + [GCC_USB30_PRIM_BCR] = { 0x49000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x60008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x60014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x60000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x6000c }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x60004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x60010 }, + [GCC_VIDEO_AXI0_CLK_ARES] = { .reg = 0x42018, .bit = 2, .udelay = 1000 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { .reg = 0x42024, .bit = 2, .udelay = 1000 }, + [GCC_VIDEO_BCR] = { 0x42000 }, + [GCC_IRIS_SS_HF_AXI_CLK_ARES] = { .reg = 0x42030, .bit = 2 }, + [GCC_IRIS_SS_SPD_AXI_CLK_ARES] = { .reg = 0x70020, .bit = 2 }, + [GCC_DDRSS_SPAD_CLK_ARES] = { .reg = 0x70000, .bit = 2 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + 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_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), +}; + +static struct gdsc *gcc_sar2130p_gdscs[] = { + [HLOS1_VOTE_MM_SNOC_MMU_TBU_HF0_GDSC] = &hlos1_vote_mm_snoc_mmu_tbu_hf0_gdsc, + [HLOS1_VOTE_MM_SNOC_MMU_TBU_SF0_GDSC] = &hlos1_vote_mm_snoc_mmu_tbu_sf0_gdsc, + [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = &hlos1_vote_turing_mmu_tbu0_gdsc, + [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = &hlos1_vote_turing_mmu_tbu1_gdsc, + [PCIE_0_GDSC] = &pcie_0_gdsc, + [PCIE_0_PHY_GDSC] = &pcie_0_phy_gdsc, + [PCIE_1_GDSC] = &pcie_1_gdsc, + [PCIE_1_PHY_GDSC] = &pcie_1_phy_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB3_PHY_GDSC] = &usb3_phy_gdsc, +}; + +static const struct regmap_config gcc_sar2130p_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f1030, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sar2130p_desc = { + .config = &gcc_sar2130p_regmap_config, + .clks = gcc_sar2130p_clocks, + .num_clks = ARRAY_SIZE(gcc_sar2130p_clocks), + .resets = gcc_sar2130p_resets, + .num_resets = ARRAY_SIZE(gcc_sar2130p_resets), + .gdscs = gcc_sar2130p_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_sar2130p_gdscs), +}; + +static const struct of_device_id gcc_sar2130p_match_table[] = { + { .compatible = "qcom,sar2130p-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sar2130p_match_table); + +static int gcc_sar2130p_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_sar2130p_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) + return ret; + + /* Keep some clocks always-on */ + qcom_branch_set_clk_en(regmap, 0x37004); /* GCC_DISP_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x42004); /* GCC_VIDEO_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x42028); /* GCC_VIDEO_XO_CLK */ + qcom_branch_set_clk_en(regmap, 0x9b004); /* GCC_GPU_CFG_AHB_CLK */ + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x62204, 0x0); + + return qcom_cc_really_probe(&pdev->dev, &gcc_sar2130p_desc, regmap); +} + +static struct platform_driver gcc_sar2130p_driver = { + .probe = gcc_sar2130p_probe, + .driver = { + .name = "gcc-sar2130p", + .of_match_table = gcc_sar2130p_match_table, + }, +}; + +static int __init gcc_sar2130p_init(void) +{ + return platform_driver_register(&gcc_sar2130p_driver); +} +subsys_initcall(gcc_sar2130p_init); + +static void __exit gcc_sar2130p_exit(void) +{ + platform_driver_unregister(&gcc_sar2130p_driver); +} +module_exit(gcc_sar2130p_exit); + +MODULE_DESCRIPTION("QTI GCC SAR2130P Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-sm8450.c b/drivers/clk/qcom/gcc-sm8450.c index c445c271678a5f..65d7d52bce0343 100644 --- a/drivers/clk/qcom/gcc-sm8450.c +++ b/drivers/clk/qcom/gcc-sm8450.c @@ -26,6 +26,8 @@ enum { P_BI_TCXO, P_GCC_GPLL0_OUT_EVEN, P_GCC_GPLL0_OUT_MAIN, + P_SM8475_GCC_GPLL2_OUT_EVEN, + P_SM8475_GCC_GPLL3_OUT_EVEN, P_GCC_GPLL4_OUT_MAIN, P_GCC_GPLL9_OUT_MAIN, P_PCIE_1_PHY_AUX_CLK, @@ -36,6 +38,15 @@ enum { P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, }; +static struct clk_init_data sm8475_gcc_gpll0_init = { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, +}; + static struct clk_alpha_pll gcc_gpll0 = { .offset = 0x0, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], @@ -53,6 +64,15 @@ static struct clk_alpha_pll gcc_gpll0 = { }, }; +static struct clk_init_data sm8475_gcc_gpll0_out_even_init = { + .name = "gcc_gpll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, +}; + static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = { { 0x1, 2 }, { } @@ -75,6 +95,49 @@ static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = { }, }; +static struct clk_alpha_pll sm8475_gcc_gpll2 = { + .offset = 0x2000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpll2", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll sm8475_gcc_gpll3 = { + .offset = 0x3000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gpll3", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_init_data sm8475_gcc_gpll4_init = { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, +}; + static struct clk_alpha_pll gcc_gpll4 = { .offset = 0x4000, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], @@ -92,6 +155,15 @@ static struct clk_alpha_pll gcc_gpll4 = { }, }; +static struct clk_init_data sm8475_gcc_gpll9_init = { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, +}; + static struct clk_alpha_pll gcc_gpll9 = { .offset = 0x9000, .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], @@ -153,6 +225,22 @@ static const struct clk_parent_data gcc_parent_data_3[] = { { .fw_name = "bi_tcxo" }, }; +static const struct parent_map sm8475_gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_SM8475_GCC_GPLL2_OUT_EVEN, 2 }, + { P_SM8475_GCC_GPLL3_OUT_EVEN, 3 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data sm8475_gcc_parent_data_3[] = { + { .fw_name = "bi_tcxo" }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &sm8475_gcc_gpll2.clkr.hw }, + { .hw = &sm8475_gcc_gpll3.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + static const struct parent_map gcc_parent_map_5[] = { { P_PCIE_1_PHY_AUX_CLK, 0 }, { P_BI_TCXO, 2 }, @@ -915,6 +1003,16 @@ static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = { .clkr.hw.init = &gcc_qupv3_wrap2_s6_clk_src_init, }; +static const struct freq_tbl sm8475_ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(37000000, P_GCC_GPLL9_OUT_MAIN, 16, 0, 0), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(148000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { F(400000, P_BI_TCXO, 12, 1, 4), F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), @@ -963,6 +1061,25 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { }, }; +static const struct freq_tbl sm8475_ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + F(600000000, P_GCC_GPLL0_OUT_MAIN, 1, 0, 0), + F(806400000, P_SM8475_GCC_GPLL2_OUT_EVEN, 1, 0, 0), + F(850000000, P_SM8475_GCC_GPLL2_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_init_data sm8475_gcc_ufs_phy_axi_clk_src_init = { + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = sm8475_gcc_parent_data_3, + .num_parents = ARRAY_SIZE(sm8475_gcc_parent_map_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, +}; + static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), @@ -987,6 +1104,24 @@ static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { }, }; +static const struct freq_tbl sm8475_ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + F(600000000, P_GCC_GPLL0_OUT_MAIN, 1, 0, 0), + F(806400000, P_SM8475_GCC_GPLL2_OUT_EVEN, 1, 0, 0), + F(850000000, P_SM8475_GCC_GPLL2_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_init_data sm8475_gcc_ufs_phy_ice_core_clk_src_init = { + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = sm8475_gcc_parent_data_3, + .num_parents = ARRAY_SIZE(sm8475_gcc_parent_map_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, +}; + static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), @@ -1032,6 +1167,14 @@ static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { }, }; +static struct clk_init_data sm8475_gcc_ufs_phy_unipro_core_clk_src_init = { + .name = "gcc_ufs_phy_unipro_core_clk_src", + .parent_data = sm8475_gcc_parent_data_3, + .num_parents = ARRAY_SIZE(sm8475_gcc_parent_map_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, +}; + static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { .cmd_rcgr = 0x8708c, .mnd_width = 0, @@ -3166,6 +3309,8 @@ static struct clk_regmap *gcc_sm8450_clocks[] = { [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr, [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, + [SM8475_GCC_GPLL2] = NULL, + [SM8475_GCC_GPLL3] = NULL, }; static const struct qcom_reset_map gcc_sm8450_resets[] = { @@ -3259,6 +3404,7 @@ static const struct qcom_cc_desc gcc_sm8450_desc = { static const struct of_device_id gcc_sm8450_match_table[] = { { .compatible = "qcom,gcc-sm8450" }, + { .compatible = "qcom,sm8475-gcc" }, { } }; MODULE_DEVICE_TABLE(of, gcc_sm8450_match_table); @@ -3277,6 +3423,39 @@ static int gcc_sm8450_probe(struct platform_device *pdev) if (ret) return ret; + if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8475-gcc")) { + /* Update GCC PLL0 */ + gcc_gpll0.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + gcc_gpll0.clkr.hw.init = &sm8475_gcc_gpll0_init; + gcc_gpll0_out_even.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + gcc_gpll0_out_even.clkr.hw.init = &sm8475_gcc_gpll0_out_even_init; + + /* Update GCC PLL4 */ + gcc_gpll4.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + gcc_gpll4.clkr.hw.init = &sm8475_gcc_gpll4_init; + + /* Update GCC PLL9 */ + gcc_gpll9.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + gcc_gpll9.clkr.hw.init = &sm8475_gcc_gpll9_init; + + gcc_sdcc2_apps_clk_src.freq_tbl = sm8475_ftbl_gcc_sdcc2_apps_clk_src; + + gcc_ufs_phy_axi_clk_src.parent_map = sm8475_gcc_parent_map_3; + gcc_ufs_phy_axi_clk_src.freq_tbl = sm8475_ftbl_gcc_ufs_phy_axi_clk_src; + gcc_ufs_phy_axi_clk_src.clkr.hw.init = &sm8475_gcc_ufs_phy_axi_clk_src_init; + + gcc_ufs_phy_ice_core_clk_src.parent_map = sm8475_gcc_parent_map_3; + gcc_ufs_phy_ice_core_clk_src.freq_tbl = sm8475_ftbl_gcc_ufs_phy_ice_core_clk_src; + gcc_ufs_phy_ice_core_clk_src.clkr.hw.init = &sm8475_gcc_ufs_phy_ice_core_clk_src_init; + + gcc_ufs_phy_unipro_core_clk_src.parent_map = sm8475_gcc_parent_map_3; + gcc_ufs_phy_unipro_core_clk_src.freq_tbl = sm8475_ftbl_gcc_ufs_phy_ice_core_clk_src; + gcc_ufs_phy_unipro_core_clk_src.clkr.hw.init = &sm8475_gcc_ufs_phy_unipro_core_clk_src_init; + + gcc_sm8450_desc.clks[SM8475_GCC_GPLL2] = &sm8475_gcc_gpll2.clkr; + gcc_sm8450_desc.clks[SM8475_GCC_GPLL3] = &sm8475_gcc_gpll3.clkr; + } + /* FORCE_MEM_CORE_ON for ufs phy ice core clocks */ regmap_update_bits(regmap, gcc_ufs_phy_ice_core_clk.halt_reg, BIT(14), BIT(14)); @@ -3312,5 +3491,5 @@ static void __exit gcc_sm8450_exit(void) } module_exit(gcc_sm8450_exit); -MODULE_DESCRIPTION("QTI GCC SM8450 Driver"); +MODULE_DESCRIPTION("QTI GCC SM8450 / SM8475 Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/gpucc-sar2130p.c b/drivers/clk/qcom/gpucc-sar2130p.c new file mode 100644 index 00000000000000..dd72b2a48c42da --- /dev/null +++ b/drivers/clk/qcom/gpucc-sar2130p.c @@ -0,0 +1,502 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2024, Linaro Limited + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GPLL0_OUT_MAIN, + DT_GPLL0_OUT_MAIN_DIV, +}; + +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 pll_vco lucid_ole_vco[] = { + { 249600000, 2000000000, 0 }, +}; + +/* 470MHz Configuration */ +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x18, + .alpha = 0x7aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const 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_lucid_evo_ops, + }, + }, +}; + +/* 440MHz Configuration */ +static const struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x16, + .alpha = 0xeaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const 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_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_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +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_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +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_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +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_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(220000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0), + F(550000000, 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_shared_ops, + }, +}; + +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_ff_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_shared_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_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .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_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .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, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x913c, + .halt_check = BRANCH_HALT_VOTED, + .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, + .ops = &clk_branch2_aon_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", + .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", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x90bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90bc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_gx_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_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, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_cx_int_clk = { + .halt_reg = 0x9148, + .halt_check = BRANCH_HALT_VOTED, + .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_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_memnoc_gfx_clk = { + .halt_reg = 0x9150, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9150, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_memnoc_gfx_clk", + .ops = &clk_branch2_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", + .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", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cx_gdsc = { + .gdscr = 0x9108, + .gds_hw_ctrl = 0x953c, + .clk_dis_wait_val = 8, + .pd = { + .name = "gpu_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x905c, + .clamp_io_ctrl = 0x9504, + .resets = (unsigned int []){ GPUCC_GPU_CC_GX_BCR, + GPUCC_GPU_CC_ACD_BCR, + GPUCC_GPU_CC_GX_ACD_IROOT_BCR }, + .reset_count = 3, + .pd = { + .name = "gpu_gx_gdsc", + .power_on = gdsc_gx_do_nothing_enable, + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO | AON_RESET | SW_RESET, +}; + +static struct clk_regmap *gpu_cc_sar2130p_clocks[] = { + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_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_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.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_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.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_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, +}; + +static const struct qcom_reset_map gpu_cc_sar2130p_resets[] = { + [GPUCC_GPU_CC_ACD_BCR] = { 0x9358 }, + [GPUCC_GPU_CC_GX_ACD_IROOT_BCR] = { 0x958c }, + [GPUCC_GPU_CC_GX_BCR] = { 0x9058 }, +}; + +static struct gdsc *gpu_cc_sar2130p_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cx_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, +}; + +static const struct regmap_config gpu_cc_sar2130p_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xa000, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sar2130p_desc = { + .config = &gpu_cc_sar2130p_regmap_config, + .clks = gpu_cc_sar2130p_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sar2130p_clocks), + .resets = gpu_cc_sar2130p_resets, + .num_resets = ARRAY_SIZE(gpu_cc_sar2130p_resets), + .gdscs = gpu_cc_sar2130p_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_sar2130p_gdscs), +}; + +static const struct of_device_id gpu_cc_sar2130p_match_table[] = { + { .compatible = "qcom,sar2130p-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sar2130p_match_table); + +static int gpu_cc_sar2130p_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gpu_cc_sar2130p_desc); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Couldn't map GPU_CC\n"); + + clk_lucid_ole_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_lucid_ole_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + /* Keep some clocks always-on */ + qcom_branch_set_clk_en(regmap, 0x900c); /* GPU_CC_DEMET_CLK */ + + return qcom_cc_really_probe(dev, &gpu_cc_sar2130p_desc, regmap); +} + +static struct platform_driver gpu_cc_sar2130p_driver = { + .probe = gpu_cc_sar2130p_probe, + .driver = { + .name = "gpu_cc-sar2130p", + .of_match_table = gpu_cc_sar2130p_match_table, + }, +}; +module_platform_driver(gpu_cc_sar2130p_driver); + +MODULE_DESCRIPTION("QTI GPU_CC SAR2130P Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gpucc-sm8450.c b/drivers/clk/qcom/gpucc-sm8450.c index b3c5d6923cd202..059df72deaa17a 100644 --- a/drivers/clk/qcom/gpucc-sm8450.c +++ b/drivers/clk/qcom/gpucc-sm8450.c @@ -40,7 +40,7 @@ static const struct pll_vco lucid_evo_vco[] = { { 249600000, 2000000000, 0 }, }; -static struct alpha_pll_config gpu_cc_pll0_config = { +static const struct alpha_pll_config gpu_cc_pll0_config = { .l = 0x1d, .alpha = 0xb000, .config_ctl_val = 0x20485699, @@ -50,6 +50,20 @@ static struct alpha_pll_config gpu_cc_pll0_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_gpu_cc_pll0_config = { + .l = 0x1d, + .alpha = 0xb000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll gpu_cc_pll0 = { .offset = 0x0, .vco_table = lucid_evo_vco, @@ -67,7 +81,7 @@ static struct clk_alpha_pll gpu_cc_pll0 = { }, }; -static struct alpha_pll_config gpu_cc_pll1_config = { +static const struct alpha_pll_config gpu_cc_pll1_config = { .l = 0x34, .alpha = 0x1555, .config_ctl_val = 0x20485699, @@ -77,6 +91,20 @@ static struct alpha_pll_config gpu_cc_pll1_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_gpu_cc_pll1_config = { + .l = 0x34, + .alpha = 0x1555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll gpu_cc_pll1 = { .offset = 0x1000, .vco_table = lucid_evo_vco, @@ -736,6 +764,7 @@ static const struct qcom_cc_desc gpu_cc_sm8450_desc = { static const struct of_device_id gpu_cc_sm8450_match_table[] = { { .compatible = "qcom,sm8450-gpucc" }, + { .compatible = "qcom,sm8475-gpucc" }, { } }; MODULE_DEVICE_TABLE(of, gpu_cc_sm8450_match_table); @@ -748,8 +777,19 @@ static int gpu_cc_sm8450_probe(struct platform_device *pdev) 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); + if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8475-gpucc")) { + /* Update GPUCC PLL0 */ + gpu_cc_pll0.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + + /* Update GPUCC PLL1 */ + gpu_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + + clk_lucid_ole_pll_configure(&gpu_cc_pll0, regmap, &sm8475_gpu_cc_pll0_config); + clk_lucid_ole_pll_configure(&gpu_cc_pll1, regmap, &sm8475_gpu_cc_pll1_config); + } else { + 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->dev, &gpu_cc_sm8450_desc, regmap); } @@ -763,5 +803,5 @@ static struct platform_driver gpu_cc_sm8450_driver = { }; module_platform_driver(gpu_cc_sm8450_driver); -MODULE_DESCRIPTION("QTI GPU_CC SM8450 Driver"); +MODULE_DESCRIPTION("QTI GPU_CC SM8450 / SM8475 Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/tcsrcc-sm8550.c b/drivers/clk/qcom/tcsrcc-sm8550.c index e5e8f2e82b949d..41d73f92a000ab 100644 --- a/drivers/clk/qcom/tcsrcc-sm8550.c +++ b/drivers/clk/qcom/tcsrcc-sm8550.c @@ -129,6 +129,13 @@ static struct clk_branch tcsr_usb3_clkref_en = { }, }; +static struct clk_regmap *tcsr_cc_sar2130p_clocks[] = { + [TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr, + [TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr, + [TCSR_USB2_CLKREF_EN] = &tcsr_usb2_clkref_en.clkr, + [TCSR_USB3_CLKREF_EN] = &tcsr_usb3_clkref_en.clkr, +}; + static struct clk_regmap *tcsr_cc_sm8550_clocks[] = { [TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr, [TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr, @@ -146,6 +153,12 @@ static const struct regmap_config tcsr_cc_sm8550_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc tcsr_cc_sar2130p_desc = { + .config = &tcsr_cc_sm8550_regmap_config, + .clks = tcsr_cc_sar2130p_clocks, + .num_clks = ARRAY_SIZE(tcsr_cc_sar2130p_clocks), +}; + static const struct qcom_cc_desc tcsr_cc_sm8550_desc = { .config = &tcsr_cc_sm8550_regmap_config, .clks = tcsr_cc_sm8550_clocks, @@ -153,7 +166,8 @@ static const struct qcom_cc_desc tcsr_cc_sm8550_desc = { }; static const struct of_device_id tcsr_cc_sm8550_match_table[] = { - { .compatible = "qcom,sm8550-tcsr" }, + { .compatible = "qcom,sar2130p-tcsr", .data = &tcsr_cc_sar2130p_desc }, + { .compatible = "qcom,sm8550-tcsr", .data = &tcsr_cc_sm8550_desc }, { } }; MODULE_DEVICE_TABLE(of, tcsr_cc_sm8550_match_table); @@ -162,7 +176,7 @@ static int tcsr_cc_sm8550_probe(struct platform_device *pdev) { struct regmap *regmap; - regmap = qcom_cc_map(pdev, &tcsr_cc_sm8550_desc); + regmap = qcom_cc_map(pdev, of_device_get_match_data(&pdev->dev)); if (IS_ERR(regmap)) return PTR_ERR(regmap); diff --git a/drivers/clk/qcom/videocc-sa8775p.c b/drivers/clk/qcom/videocc-sa8775p.c new file mode 100644 index 00000000000000..bf5de411fd5d63 --- /dev/null +++ b/drivers/clk/qcom/videocc-sa8775p.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#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 "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_IFACE, + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, +}; + +enum { + P_BI_TCXO, + P_BI_TCXO_AO, + P_SLEEP_CLK, + P_VIDEO_PLL0_OUT_MAIN, + P_VIDEO_PLL1_OUT_MAIN, +}; + +static const struct pll_vco lucid_evo_vco[] = { + { 249600000, 2020000000, 0 }, +}; + +static const struct alpha_pll_config video_pll0_config = { + .l = 0x39, + .alpha = 0x3000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll video_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 = "video_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct alpha_pll_config video_pll1_config = { + .l = 0x39, + .alpha = 0x3000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00400805, +}; + +static struct clk_alpha_pll video_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 = "video_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map video_cc_parent_map_0_ao[] = { + { P_BI_TCXO_AO, 0 }, +}; + +static const struct clk_parent_data video_cc_parent_data_0_ao[] = { + { .index = DT_BI_TCXO_AO }, +}; + +static const struct parent_map video_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_VIDEO_PLL0_OUT_MAIN, 1 }, +}; + +static const struct clk_parent_data video_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &video_pll0.clkr.hw }, +}; + +static const struct parent_map video_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_VIDEO_PLL1_OUT_MAIN, 1 }, +}; + +static const struct clk_parent_data video_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &video_pll1.clkr.hw }, +}; + +static const struct parent_map video_cc_parent_map_3[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data video_cc_parent_data_3[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct freq_tbl ftbl_video_cc_ahb_clk_src[] = { + F(19200000, P_BI_TCXO_AO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 video_cc_ahb_clk_src = { + .cmd_rcgr = 0x8030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_0_ao, + .freq_tbl = ftbl_video_cc_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_ahb_clk_src", + .parent_data = video_cc_parent_data_0_ao, + .num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = { + F(1098000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(1332000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(1599000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(1680000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 video_cc_mvs0_clk_src = { + .cmd_rcgr = 0x8000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_1, + .freq_tbl = ftbl_video_cc_mvs0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs0_clk_src", + .parent_data = video_cc_parent_data_1, + .num_parents = ARRAY_SIZE(video_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = { + F(1098000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0), + F(1332000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0), + F(1600000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0), + F(1800000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 video_cc_mvs1_clk_src = { + .cmd_rcgr = 0x8018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_2, + .freq_tbl = ftbl_video_cc_mvs1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs1_clk_src", + .parent_data = video_cc_parent_data_2, + .num_parents = ARRAY_SIZE(video_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 video_cc_sleep_clk_src = { + .cmd_rcgr = 0x812c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_3, + .freq_tbl = ftbl_video_cc_sleep_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_sleep_clk_src", + .parent_data = video_cc_parent_data_3, + .num_parents = ARRAY_SIZE(video_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 video_cc_xo_clk_src = { + .cmd_rcgr = 0x8110, + .mnd_width = 0, + .hid_width = 5, + .parent_map = video_cc_parent_map_0_ao, + .freq_tbl = ftbl_video_cc_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_xo_clk_src", + .parent_data = video_cc_parent_data_0_ao, + .num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div video_cc_mvs0_div_clk_src = { + .reg = 0x80b8, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_mvs0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = { + .reg = 0x806c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs0c_div2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_mvs0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div video_cc_mvs1_div_clk_src = { + .reg = 0x80dc, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_mvs1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = { + .reg = 0x8094, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs1c_div2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_mvs1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div video_cc_sm_div_clk_src = { + .reg = 0x8108, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "video_cc_sm_div_clk_src", + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch video_cc_mvs0_clk = { + .halt_reg = 0x80b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x80b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x80b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs0_clk", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_mvs0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs0c_clk = { + .halt_reg = 0x8064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs0c_clk", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_mvs0c_div2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs1_clk = { + .halt_reg = 0x80d4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x80d4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x80d4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs1_clk", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_mvs1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_mvs1c_clk = { + .halt_reg = 0x808c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x808c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "video_cc_mvs1c_clk", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_mvs1c_div2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_pll_lock_monitor_clk = { + .halt_reg = 0x9000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "video_cc_pll_lock_monitor_clk", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch video_cc_sm_obs_clk = { + .halt_reg = 0x810c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x810c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "video_cc_sm_obs_clk", + .parent_hws = (const struct clk_hw*[]) { + &video_cc_sm_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc video_cc_mvs0c_gdsc = { + .gdscr = 0x804c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x6, + .pd = { + .name = "video_cc_mvs0c_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, +}; + +static struct gdsc video_cc_mvs0_gdsc = { + .gdscr = 0x809c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x6, + .pd = { + .name = "video_cc_mvs0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .parent = &video_cc_mvs0c_gdsc.pd, + .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR | HW_CTRL_TRIGGER, +}; + +static struct gdsc video_cc_mvs1c_gdsc = { + .gdscr = 0x8074, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x6, + .pd = { + .name = "video_cc_mvs1c_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR, +}; + +static struct gdsc video_cc_mvs1_gdsc = { + .gdscr = 0x80c0, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x6, + .pd = { + .name = "video_cc_mvs1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .parent = &video_cc_mvs1c_gdsc.pd, + .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR | HW_CTRL_TRIGGER, +}; + +static struct clk_regmap *video_cc_sa8775p_clocks[] = { + [VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr, + [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr, + [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr, + [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr, + [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr, + [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr, + [VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr, + [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr, + [VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr, + [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr, + [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr, + [VIDEO_CC_PLL_LOCK_MONITOR_CLK] = &video_cc_pll_lock_monitor_clk.clkr, + [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr, + [VIDEO_CC_SM_DIV_CLK_SRC] = &video_cc_sm_div_clk_src.clkr, + [VIDEO_CC_SM_OBS_CLK] = &video_cc_sm_obs_clk.clkr, + [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr, + [VIDEO_PLL0] = &video_pll0.clkr, + [VIDEO_PLL1] = &video_pll1.clkr, +}; + +static struct gdsc *video_cc_sa8775p_gdscs[] = { + [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc, + [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc, + [VIDEO_CC_MVS1_GDSC] = &video_cc_mvs1_gdsc, + [VIDEO_CC_MVS1C_GDSC] = &video_cc_mvs1c_gdsc, +}; + +static const struct qcom_reset_map video_cc_sa8775p_resets[] = { + [VIDEO_CC_INTERFACE_BCR] = { 0x80e8 }, + [VIDEO_CC_MVS0_BCR] = { 0x8098 }, + [VIDEO_CC_MVS0C_CLK_ARES] = { 0x8064, 2 }, + [VIDEO_CC_MVS0C_BCR] = { 0x8048 }, + [VIDEO_CC_MVS1_BCR] = { 0x80bc }, + [VIDEO_CC_MVS1C_CLK_ARES] = { 0x808c, 2 }, + [VIDEO_CC_MVS1C_BCR] = { 0x8070 }, +}; + +static const struct regmap_config video_cc_sa8775p_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xb000, + .fast_io = true, +}; + +static struct qcom_cc_desc video_cc_sa8775p_desc = { + .config = &video_cc_sa8775p_regmap_config, + .clks = video_cc_sa8775p_clocks, + .num_clks = ARRAY_SIZE(video_cc_sa8775p_clocks), + .resets = video_cc_sa8775p_resets, + .num_resets = ARRAY_SIZE(video_cc_sa8775p_resets), + .gdscs = video_cc_sa8775p_gdscs, + .num_gdscs = ARRAY_SIZE(video_cc_sa8775p_gdscs), +}; + +static const struct of_device_id video_cc_sa8775p_match_table[] = { + { .compatible = "qcom,sa8775p-videocc" }, + { } +}; +MODULE_DEVICE_TABLE(of, video_cc_sa8775p_match_table); + +static int video_cc_sa8775p_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + regmap = qcom_cc_map(pdev, &video_cc_sa8775p_desc); + if (IS_ERR(regmap)) { + pm_runtime_put(&pdev->dev); + return PTR_ERR(regmap); + } + + clk_lucid_evo_pll_configure(&video_pll0, regmap, &video_pll0_config); + clk_lucid_evo_pll_configure(&video_pll1, regmap, &video_pll1_config); + + /* Keep some clocks always enabled */ + qcom_branch_set_clk_en(regmap, 0x80ec); /* VIDEO_CC_AHB_CLK */ + qcom_branch_set_clk_en(regmap, 0x8144); /* VIDEO_CC_SLEEP_CLK */ + qcom_branch_set_clk_en(regmap, 0x8128); /* VIDEO_CC_XO_CLK */ + + ret = qcom_cc_really_probe(&pdev->dev, &video_cc_sa8775p_desc, regmap); + + pm_runtime_put(&pdev->dev); + + return ret; +} + +static struct platform_driver video_cc_sa8775p_driver = { + .probe = video_cc_sa8775p_probe, + .driver = { + .name = "videocc-sa8775p", + .of_match_table = video_cc_sa8775p_match_table, + }, +}; + +module_platform_driver(video_cc_sa8775p_driver); + +MODULE_DESCRIPTION("QTI VIDEOCC SA8775P Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/videocc-sm8450.c b/drivers/clk/qcom/videocc-sm8450.c index ed9163d642441b..f26c7eccb62e7e 100644 --- a/drivers/clk/qcom/videocc-sm8450.c +++ b/drivers/clk/qcom/videocc-sm8450.c @@ -46,6 +46,21 @@ static const struct alpha_pll_config video_cc_pll0_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_video_cc_pll0_config = { + /* .l includes CAL_L_VAL, L_VAL fields */ + .l = 0x1e, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll video_cc_pll0 = { .offset = 0x0, .vco_table = lucid_evo_vco, @@ -74,6 +89,21 @@ static const struct alpha_pll_config video_cc_pll1_config = { .user_ctl_hi_val = 0x00000805, }; +static const struct alpha_pll_config sm8475_video_cc_pll1_config = { + /* .l includes CAL_L_VAL, L_VAL fields */ + .l = 0x2b, + .alpha = 0xc000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + static struct clk_alpha_pll video_cc_pll1 = { .offset = 0x1000, .vco_table = lucid_evo_vco, @@ -397,6 +427,7 @@ static struct qcom_cc_desc video_cc_sm8450_desc = { static const struct of_device_id video_cc_sm8450_match_table[] = { { .compatible = "qcom,sm8450-videocc" }, + { .compatible = "qcom,sm8475-videocc" }, { } }; MODULE_DEVICE_TABLE(of, video_cc_sm8450_match_table); @@ -420,8 +451,19 @@ static int video_cc_sm8450_probe(struct platform_device *pdev) return PTR_ERR(regmap); } - clk_lucid_evo_pll_configure(&video_cc_pll0, regmap, &video_cc_pll0_config); - clk_lucid_evo_pll_configure(&video_cc_pll1, regmap, &video_cc_pll1_config); + if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8475-videocc")) { + /* Update VideoCC PLL0 */ + video_cc_pll0.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + + /* Update VideoCC PLL1 */ + video_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; + + clk_lucid_ole_pll_configure(&video_cc_pll0, regmap, &sm8475_video_cc_pll0_config); + clk_lucid_ole_pll_configure(&video_cc_pll1, regmap, &sm8475_video_cc_pll1_config); + } else { + clk_lucid_evo_pll_configure(&video_cc_pll0, regmap, &video_cc_pll0_config); + clk_lucid_evo_pll_configure(&video_cc_pll1, regmap, &video_cc_pll1_config); + } /* Keep some clocks always-on */ qcom_branch_set_clk_en(regmap, 0x80e4); /* VIDEO_CC_AHB_CLK */ @@ -445,5 +487,5 @@ static struct platform_driver video_cc_sm8450_driver = { module_platform_driver(video_cc_sm8450_driver); -MODULE_DESCRIPTION("QTI VIDEOCC SM8450 Driver"); +MODULE_DESCRIPTION("QTI VIDEOCC SM8450 / SM8475 Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/ralink/clk-mtmips.c b/drivers/clk/ralink/clk-mtmips.c index 50a443bf79ecd3..97b8ca0f91816f 100644 --- a/drivers/clk/ralink/clk-mtmips.c +++ b/drivers/clk/ralink/clk-mtmips.c @@ -207,6 +207,7 @@ static struct mtmips_clk mt7620_pherip_clks[] = { { CLK_PERIPH("10000b00.spi", "bus") }, { CLK_PERIPH("10000b40.spi", "bus") }, { CLK_PERIPH("10000c00.uartlite", "periph") }, + { CLK_PERIPH("10130000.mmc", "sdhc") }, { CLK_PERIPH("10180000.wmac", "xtal") } }; @@ -220,6 +221,7 @@ static struct mtmips_clk mt76x8_pherip_clks[] = { { CLK_PERIPH("10000c00.uart0", "periph") }, { CLK_PERIPH("10000d00.uart1", "periph") }, { CLK_PERIPH("10000e00.uart2", "periph") }, + { CLK_PERIPH("10130000.mmc", "sdhc") }, { CLK_PERIPH("10300000.wmac", "xtal") } }; @@ -263,16 +265,22 @@ static int mtmips_register_pherip_clocks(struct device_node *np, .rate = _rate \ } -static struct mtmips_clk_fixed rt305x_fixed_clocks[] = { - CLK_FIXED("xtal", NULL, 40000000) +static struct mtmips_clk_fixed rt3883_fixed_clocks[] = { + CLK_FIXED("xtal", NULL, 40000000), + CLK_FIXED("periph", "xtal", 40000000) }; static struct mtmips_clk_fixed rt3352_fixed_clocks[] = { CLK_FIXED("periph", "xtal", 40000000) }; +static struct mtmips_clk_fixed mt7620_fixed_clocks[] = { + CLK_FIXED("bbppll", "xtal", 480000000) +}; + static struct mtmips_clk_fixed mt76x8_fixed_clocks[] = { - CLK_FIXED("pcmi2s", "xtal", 480000000), + CLK_FIXED("bbppll", "xtal", 480000000), + CLK_FIXED("pcmi2s", "bbppll", 480000000), CLK_FIXED("periph", "xtal", 40000000) }; @@ -327,6 +335,15 @@ static struct mtmips_clk_factor rt305x_factor_clocks[] = { CLK_FACTOR("bus", "cpu", 1, 3) }; +static struct mtmips_clk_factor mt7620_factor_clocks[] = { + CLK_FACTOR("sdhc", "bbppll", 1, 10) +}; + +static struct mtmips_clk_factor mt76x8_factor_clocks[] = { + CLK_FACTOR("bus", "cpu", 1, 3), + CLK_FACTOR("sdhc", "bbppll", 1, 10) +}; + static int mtmips_register_factor_clocks(struct clk_hw_onecell_data *clk_data, struct mtmips_clk_priv *priv) { @@ -366,6 +383,12 @@ static inline struct mtmips_clk *to_mtmips_clk(struct clk_hw *hw) return container_of(hw, struct mtmips_clk, hw); } +static unsigned long rt2880_xtal_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 40000000; +} + static unsigned long rt5350_xtal_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -677,10 +700,12 @@ static unsigned long mt76x8_cpu_recalc_rate(struct clk_hw *hw, } static struct mtmips_clk rt2880_clks_base[] = { + { CLK_BASE("xtal", NULL, rt2880_xtal_recalc_rate) }, { CLK_BASE("cpu", "xtal", rt2880_cpu_recalc_rate) } }; static struct mtmips_clk rt305x_clks_base[] = { + { CLK_BASE("xtal", NULL, rt2880_xtal_recalc_rate) }, { CLK_BASE("cpu", "xtal", rt305x_cpu_recalc_rate) } }; @@ -690,6 +715,7 @@ static struct mtmips_clk rt3352_clks_base[] = { }; static struct mtmips_clk rt3883_clks_base[] = { + { CLK_BASE("xtal", NULL, rt2880_xtal_recalc_rate) }, { CLK_BASE("cpu", "xtal", rt3883_cpu_recalc_rate) }, { CLK_BASE("bus", "cpu", rt3883_bus_recalc_rate) } }; @@ -746,8 +772,8 @@ static int mtmips_register_clocks(struct device_node *np, static const struct mtmips_clk_data rt2880_clk_data = { .clk_base = rt2880_clks_base, .num_clk_base = ARRAY_SIZE(rt2880_clks_base), - .clk_fixed = rt305x_fixed_clocks, - .num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks), + .clk_fixed = NULL, + .num_clk_fixed = 0, .clk_factor = rt2880_factor_clocks, .num_clk_factor = ARRAY_SIZE(rt2880_factor_clocks), .clk_periph = rt2880_pherip_clks, @@ -757,8 +783,8 @@ static const struct mtmips_clk_data rt2880_clk_data = { static const struct mtmips_clk_data rt305x_clk_data = { .clk_base = rt305x_clks_base, .num_clk_base = ARRAY_SIZE(rt305x_clks_base), - .clk_fixed = rt305x_fixed_clocks, - .num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks), + .clk_fixed = NULL, + .num_clk_fixed = 0, .clk_factor = rt305x_factor_clocks, .num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks), .clk_periph = rt305x_pherip_clks, @@ -779,8 +805,8 @@ static const struct mtmips_clk_data rt3352_clk_data = { static const struct mtmips_clk_data rt3883_clk_data = { .clk_base = rt3883_clks_base, .num_clk_base = ARRAY_SIZE(rt3883_clks_base), - .clk_fixed = rt305x_fixed_clocks, - .num_clk_fixed = ARRAY_SIZE(rt305x_fixed_clocks), + .clk_fixed = rt3883_fixed_clocks, + .num_clk_fixed = ARRAY_SIZE(rt3883_fixed_clocks), .clk_factor = NULL, .num_clk_factor = 0, .clk_periph = rt5350_pherip_clks, @@ -801,10 +827,10 @@ static const struct mtmips_clk_data rt5350_clk_data = { static const struct mtmips_clk_data mt7620_clk_data = { .clk_base = mt7620_clks_base, .num_clk_base = ARRAY_SIZE(mt7620_clks_base), - .clk_fixed = NULL, - .num_clk_fixed = 0, - .clk_factor = NULL, - .num_clk_factor = 0, + .clk_fixed = mt7620_fixed_clocks, + .num_clk_fixed = ARRAY_SIZE(mt7620_fixed_clocks), + .clk_factor = mt7620_factor_clocks, + .num_clk_factor = ARRAY_SIZE(mt7620_factor_clocks), .clk_periph = mt7620_pherip_clks, .num_clk_periph = ARRAY_SIZE(mt7620_pherip_clks), }; @@ -814,8 +840,8 @@ static const struct mtmips_clk_data mt76x8_clk_data = { .num_clk_base = ARRAY_SIZE(mt76x8_clks_base), .clk_fixed = mt76x8_fixed_clocks, .num_clk_fixed = ARRAY_SIZE(mt76x8_fixed_clocks), - .clk_factor = rt305x_factor_clocks, - .num_clk_factor = ARRAY_SIZE(rt305x_factor_clocks), + .clk_factor = mt76x8_factor_clocks, + .num_clk_factor = ARRAY_SIZE(mt76x8_factor_clocks), .clk_periph = mt76x8_pherip_clks, .num_clk_periph = ARRAY_SIZE(mt76x8_pherip_clks), }; diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 76791a1c50ac73..ff01f5f0ed207a 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -237,6 +237,11 @@ config CLK_RZV2H bool "RZ/V2H(P) family clock support" if COMPILE_TEST select RESET_CONTROLLER +config CLK_RENESAS_VBATTB + tristate "Renesas VBATTB clock controller" + depends on ARCH_RZG2L || COMPILE_TEST + select RESET_CONTROLLER + # Generic config CLK_RENESAS_CPG_MSSR bool "CPG/MSSR clock support" if COMPILE_TEST diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 23d2e26051c84a..82efaa835ac70f 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_CLK_RZV2H) += rzv2h-cpg.o obj-$(CONFIG_CLK_RENESAS_CPG_MSSR) += renesas-cpg-mssr.o obj-$(CONFIG_CLK_RENESAS_CPG_MSTP) += clk-mstp.o obj-$(CONFIG_CLK_RENESAS_DIV6) += clk-div6.o +obj-$(CONFIG_CLK_RENESAS_VBATTB) += clk-vbattb.o diff --git a/drivers/clk/renesas/clk-r8a73a4.c b/drivers/clk/renesas/clk-r8a73a4.c index 4b1815147f7769..f331d8bc9dafb2 100644 --- a/drivers/clk/renesas/clk-r8a73a4.c +++ b/drivers/clk/renesas/clk-r8a73a4.c @@ -64,7 +64,6 @@ r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg, unsigned int mult = 1; unsigned int div = 1; - if (!strcmp(name, "main")) { u32 ckscr = readl(base + CPG_CKSCR); diff --git a/drivers/clk/renesas/clk-r8a7778.c b/drivers/clk/renesas/clk-r8a7778.c index 797556259370bb..6ea173f22251bc 100644 --- a/drivers/clk/renesas/clk-r8a7778.c +++ b/drivers/clk/renesas/clk-r8a7778.c @@ -67,7 +67,6 @@ r8a7778_cpg_register_clock(struct device_node *np, const char *name) return ERR_PTR(-EINVAL); } - static void __init r8a7778_cpg_clocks_init(struct device_node *np) { struct clk_onecell_data *data; diff --git a/drivers/clk/renesas/clk-vbattb.c b/drivers/clk/renesas/clk-vbattb.c new file mode 100644 index 00000000000000..ff9d1ead455c38 --- /dev/null +++ b/drivers/clk/renesas/clk-vbattb.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * VBATTB clock driver + * + * Copyright (C) 2024 Renesas Electronics Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VBATTB_BKSCCR 0x1c +#define VBATTB_BKSCCR_SOSEL 6 +#define VBATTB_SOSCCR2 0x24 +#define VBATTB_SOSCCR2_SOSTP2 0 +#define VBATTB_XOSCCR 0x30 +#define VBATTB_XOSCCR_OUTEN 16 +#define VBATTB_XOSCCR_XSEL GENMASK(1, 0) +#define VBATTB_XOSCCR_XSEL_4_PF 0x0 +#define VBATTB_XOSCCR_XSEL_7_PF 0x1 +#define VBATTB_XOSCCR_XSEL_9_PF 0x2 +#define VBATTB_XOSCCR_XSEL_12_5_PF 0x3 + +/** + * struct vbattb_clk - VBATTB clock data structure + * @base: base address + * @lock: lock + */ +struct vbattb_clk { + void __iomem *base; + spinlock_t lock; +}; + +static int vbattb_clk_validate_load_capacitance(u32 *reg_lc, u32 of_lc) +{ + switch (of_lc) { + case 4000: + *reg_lc = VBATTB_XOSCCR_XSEL_4_PF; + break; + case 7000: + *reg_lc = VBATTB_XOSCCR_XSEL_7_PF; + break; + case 9000: + *reg_lc = VBATTB_XOSCCR_XSEL_9_PF; + break; + case 12500: + *reg_lc = VBATTB_XOSCCR_XSEL_12_5_PF; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void vbattb_clk_action(void *data) +{ + struct device *dev = data; + struct reset_control *rstc = dev_get_drvdata(dev); + int ret; + + ret = reset_control_assert(rstc); + if (ret) + dev_err(dev, "Failed to de-assert reset!"); + + ret = pm_runtime_put_sync(dev); + if (ret < 0) + dev_err(dev, "Failed to runtime suspend!"); + + of_clk_del_provider(dev->of_node); +} + +static int vbattb_clk_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct clk_parent_data parent_data = {}; + struct clk_hw_onecell_data *clk_data; + const struct clk_hw *parent_hws[2]; + struct device *dev = &pdev->dev; + struct reset_control *rstc; + struct vbattb_clk *vbclk; + u32 of_lc, reg_lc; + struct clk_hw *hw; + /* 4 clocks are exported: VBATTB_XC, VBATTB_XBYP, VBATTB_MUX, VBATTB_VBATTCLK. */ + u8 num_clks = 4; + int ret; + + /* Default to 4pF as this is not needed if external clock device is connected. */ + of_lc = 4000; + of_property_read_u32(np, "quartz-load-femtofarads", &of_lc); + + ret = vbattb_clk_validate_load_capacitance(®_lc, of_lc); + if (ret) + return ret; + + vbclk = devm_kzalloc(dev, sizeof(*vbclk), GFP_KERNEL); + if (!vbclk) + return -ENOMEM; + + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, num_clks), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + clk_data->num = num_clks; + + vbclk->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(vbclk->base)) + return PTR_ERR(vbclk->base); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + rstc = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(rstc)) + return PTR_ERR(rstc); + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = reset_control_deassert(rstc); + if (ret) { + pm_runtime_put_sync(dev); + return ret; + } + + dev_set_drvdata(dev, rstc); + ret = devm_add_action_or_reset(dev, vbattb_clk_action, dev); + if (ret) + return ret; + + spin_lock_init(&vbclk->lock); + + parent_data.fw_name = "rtx"; + hw = devm_clk_hw_register_gate_parent_data(dev, "xc", &parent_data, 0, + vbclk->base + VBATTB_SOSCCR2, + VBATTB_SOSCCR2_SOSTP2, + CLK_GATE_SET_TO_DISABLE, &vbclk->lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + clk_data->hws[VBATTB_XC] = hw; + + hw = devm_clk_hw_register_fixed_factor_fwname(dev, np, "xbyp", "rtx", 0, 1, 1); + if (IS_ERR(hw)) + return PTR_ERR(hw); + clk_data->hws[VBATTB_XBYP] = hw; + + parent_hws[0] = clk_data->hws[VBATTB_XC]; + parent_hws[1] = clk_data->hws[VBATTB_XBYP]; + hw = devm_clk_hw_register_mux_parent_hws(dev, "mux", parent_hws, 2, 0, + vbclk->base + VBATTB_BKSCCR, + VBATTB_BKSCCR_SOSEL, + 1, 0, &vbclk->lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + clk_data->hws[VBATTB_MUX] = hw; + + /* Set load capacitance before registering the VBATTCLK clock. */ + scoped_guard(spinlock, &vbclk->lock) { + u32 val = readl_relaxed(vbclk->base + VBATTB_XOSCCR); + + val &= ~VBATTB_XOSCCR_XSEL; + val |= reg_lc; + writel_relaxed(val, vbclk->base + VBATTB_XOSCCR); + } + + /* This feeds the RTC counter clock and it needs to stay on. */ + hw = devm_clk_hw_register_gate_parent_hw(dev, "vbattclk", hw, CLK_IS_CRITICAL, + vbclk->base + VBATTB_XOSCCR, + VBATTB_XOSCCR_OUTEN, 0, + &vbclk->lock); + + if (IS_ERR(hw)) + return PTR_ERR(hw); + clk_data->hws[VBATTB_VBATTCLK] = hw; + + return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); +} + +static const struct of_device_id vbattb_clk_match[] = { + { .compatible = "renesas,r9a08g045-vbattb" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, vbattb_clk_match); + +static struct platform_driver vbattb_clk_driver = { + .driver = { + .name = "renesas-vbattb-clk", + .of_match_table = vbattb_clk_match, + }, + .probe = vbattb_clk_probe, +}; +module_platform_driver(vbattb_clk_driver); + +MODULE_DESCRIPTION("Renesas VBATTB Clock Driver"); +MODULE_AUTHOR("Claudiu Beznea "); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index 4c8e4c69c1bfaa..9c7e4094705c72 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -266,7 +266,6 @@ static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] __initconst = { { 2, 128, 1, 192, 1, 32, }, }; - static int __init r8a779a0_cpg_mssr_init(struct device *dev) { const struct rcar_gen4_cpg_pll_config *cpg_pll_config; diff --git a/drivers/clk/renesas/r8a779h0-cpg-mssr.c b/drivers/clk/renesas/r8a779h0-cpg-mssr.c index e20c048bfa9be1..9067e407cbc69f 100644 --- a/drivers/clk/renesas/r8a779h0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779h0-cpg-mssr.c @@ -37,7 +37,6 @@ enum clk_ids { CLK_PLL5, CLK_PLL6, CLK_PLL1_DIV2, - CLK_PLL2_DIV2, CLK_PLL3_DIV2, CLK_PLL4_DIV2, CLK_PLL4_DIV5, @@ -78,7 +77,6 @@ static const struct cpg_core_clk r8a779h0_core_clks[] __initconst = { DEF_GEN4_PLL_V8_25(".pll6", 6, CLK_PLL6, CLK_MAIN), DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), - DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 2, 1), DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 2, 1), DEF_FIXED(".pll4_div2", CLK_PLL4_DIV2, CLK_PLL4, 2, 1), DEF_FIXED(".pll4_div5", CLK_PLL4_DIV5, CLK_PLL4, 5, 1), @@ -101,10 +99,10 @@ static const struct cpg_core_clk r8a779h0_core_clks[] __initconst = { DEF_RATE(".oco", CLK_OCO, 32768), /* Core Clock Outputs */ - DEF_GEN4_Z("zc0", R8A779H0_CLK_ZC0, CLK_TYPE_GEN4_Z, CLK_PLL2_DIV2, 2, 0), - DEF_GEN4_Z("zc1", R8A779H0_CLK_ZC1, CLK_TYPE_GEN4_Z, CLK_PLL2_DIV2, 2, 8), - DEF_GEN4_Z("zc2", R8A779H0_CLK_ZC2, CLK_TYPE_GEN4_Z, CLK_PLL2_DIV2, 2, 32), - DEF_GEN4_Z("zc3", R8A779H0_CLK_ZC3, CLK_TYPE_GEN4_Z, CLK_PLL2_DIV2, 2, 40), + DEF_GEN4_Z("zc0", R8A779H0_CLK_ZC0, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 0), + DEF_GEN4_Z("zc1", R8A779H0_CLK_ZC1, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 8), + DEF_GEN4_Z("zc2", R8A779H0_CLK_ZC2, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 32), + DEF_GEN4_Z("zc3", R8A779H0_CLK_ZC3, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 40), DEF_FIXED("s0d2", R8A779H0_CLK_S0D2, CLK_S0, 2, 1), DEF_FIXED("s0d3", R8A779H0_CLK_S0D3, CLK_S0, 3, 1), DEF_FIXED("s0d4", R8A779H0_CLK_S0D4, CLK_S0, 4, 1), diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c index 1ce40fb51f13bd..b2ae8cdc4723e6 100644 --- a/drivers/clk/renesas/r9a08g045-cpg.c +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -266,61 +267,50 @@ static const struct rzg2l_cpg_pm_domain_init_data r9a08g045_pm_domains[] = { /* Keep always-on domain on the first position for proper domains registration. */ DEF_PD("always-on", R9A08G045_PD_ALWAYS_ON, DEF_REG_CONF(0, 0), - RZG2L_PD_F_ALWAYS_ON), + GENPD_FLAG_ALWAYS_ON | GENPD_FLAG_IRQ_SAFE), DEF_PD("gic", R9A08G045_PD_GIC, DEF_REG_CONF(CPG_BUS_ACPU_MSTOP, BIT(3)), - RZG2L_PD_F_ALWAYS_ON), + GENPD_FLAG_ALWAYS_ON), DEF_PD("ia55", R9A08G045_PD_IA55, DEF_REG_CONF(CPG_BUS_PERI_CPU_MSTOP, BIT(13)), - RZG2L_PD_F_ALWAYS_ON), + GENPD_FLAG_ALWAYS_ON), DEF_PD("dmac", R9A08G045_PD_DMAC, DEF_REG_CONF(CPG_BUS_REG1_MSTOP, GENMASK(3, 0)), - RZG2L_PD_F_ALWAYS_ON), + GENPD_FLAG_ALWAYS_ON), DEF_PD("wdt0", R9A08G045_PD_WDT0, DEF_REG_CONF(CPG_BUS_REG0_MSTOP, BIT(0)), - RZG2L_PD_F_NONE), + GENPD_FLAG_IRQ_SAFE), DEF_PD("sdhi0", R9A08G045_PD_SDHI0, - DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(0)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(0)), 0), DEF_PD("sdhi1", R9A08G045_PD_SDHI1, - DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(1)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(1)), 0), DEF_PD("sdhi2", R9A08G045_PD_SDHI2, - DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(11)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(11)), 0), DEF_PD("usb0", R9A08G045_PD_USB0, - DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, GENMASK(6, 5)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, GENMASK(6, 5)), 0), DEF_PD("usb1", R9A08G045_PD_USB1, - DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(7)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(7)), 0), DEF_PD("usb-phy", R9A08G045_PD_USB_PHY, - DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(4)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(4)), 0), DEF_PD("eth0", R9A08G045_PD_ETHER0, - DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(2)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(2)), 0), DEF_PD("eth1", R9A08G045_PD_ETHER1, - DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(3)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(3)), 0), DEF_PD("i2c0", R9A08G045_PD_I2C0, - DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(10)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(10)), 0), DEF_PD("i2c1", R9A08G045_PD_I2C1, - DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(11)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(11)), 0), DEF_PD("i2c2", R9A08G045_PD_I2C2, - DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(12)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(12)), 0), DEF_PD("i2c3", R9A08G045_PD_I2C3, - DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(13)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(13)), 0), DEF_PD("scif0", R9A08G045_PD_SCIF0, - DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(1)), - RZG2L_PD_F_NONE), + DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(1)), 0), DEF_PD("vbat", R9A08G045_PD_VBAT, DEF_REG_CONF(CPG_BUS_MCPU3_MSTOP, BIT(8)), - RZG2L_PD_F_ALWAYS_ON), + GENPD_FLAG_ALWAYS_ON), + DEF_PD("rtc", R9A08G045_PD_RTC, + DEF_REG_CONF(CPG_BUS_MCPU3_MSTOP, BIT(7)), 0), }; const struct rzg2l_cpg_info r9a08g045_cpg_info = { diff --git a/drivers/clk/renesas/r9a09g011-cpg.c b/drivers/clk/renesas/r9a09g011-cpg.c index dda9f29dff3337..22272279b104fa 100644 --- a/drivers/clk/renesas/r9a09g011-cpg.c +++ b/drivers/clk/renesas/r9a09g011-cpg.c @@ -98,7 +98,6 @@ static const struct clk_div_table dtable_divd[] = { {0, 0}, }; - static const struct clk_div_table dtable_divw[] = { {0, 6}, {1, 7}, diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c index 3ee32db5c0af79..7c4507fd34e6a3 100644 --- a/drivers/clk/renesas/r9a09g057-cpg.c +++ b/drivers/clk/renesas/r9a09g057-cpg.c @@ -41,6 +41,14 @@ enum clk_ids { MOD_CLK_BASE, }; +static const struct clk_div_table dtable_1_8[] = { + {0, 1}, + {1, 2}, + {2, 4}, + {3, 8}, + {0, 0}, +}; + static const struct clk_div_table dtable_2_64[] = { {0, 2}, {1, 4}, @@ -74,10 +82,19 @@ static const struct cpg_core_clk r9a09g057_core_clks[] __initconst = { /* Core Clocks */ DEF_FIXED("sys_0_pclk", R9A09G057_SYS_0_PCLK, CLK_QEXTAL, 1, 1), + DEF_DDIV("ca55_0_coreclk0", R9A09G057_CA55_0_CORE_CLK0, CLK_PLLCA55, + CDDIV1_DIVCTL0, dtable_1_8), + DEF_DDIV("ca55_0_coreclk1", R9A09G057_CA55_0_CORE_CLK1, CLK_PLLCA55, + CDDIV1_DIVCTL1, dtable_1_8), + DEF_DDIV("ca55_0_coreclk2", R9A09G057_CA55_0_CORE_CLK2, CLK_PLLCA55, + CDDIV1_DIVCTL2, dtable_1_8), + DEF_DDIV("ca55_0_coreclk3", R9A09G057_CA55_0_CORE_CLK3, CLK_PLLCA55, + CDDIV1_DIVCTL3, dtable_1_8), DEF_FIXED("iotop_0_shclk", R9A09G057_IOTOP_0_SHCLK, CLK_PLLCM33_DIV16, 1, 1), }; static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + DEF_MOD_CRITICAL("icu_0_pclk_i", CLK_PLLCM33_DIV16, 0, 5, 0, 5), DEF_MOD("gtm_0_pclk", CLK_PLLCM33_DIV16, 4, 3, 2, 3), DEF_MOD("gtm_1_pclk", CLK_PLLCM33_DIV16, 4, 4, 2, 4), DEF_MOD("gtm_2_pclk", CLK_PLLCLN_DIV16, 4, 5, 2, 5), @@ -119,6 +136,7 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { }; static const struct rzv2h_reset r9a09g057_resets[] __initconst = { + DEF_RST(3, 6, 1, 7), /* ICU_0_PRESETN_I */ DEF_RST(6, 13, 2, 30), /* GTM_0_PRESETZ */ DEF_RST(6, 14, 2, 31), /* GTM_1_PRESETZ */ DEF_RST(6, 15, 3, 0), /* GTM_2_PRESETZ */ diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c index 42b126ea3e1337..a45f8e7e9ab676 100644 --- a/drivers/clk/renesas/rcar-cpg-lib.c +++ b/drivers/clk/renesas/rcar-cpg-lib.c @@ -206,4 +206,3 @@ struct clk * __init cpg_rpcd2_clk_register(const char *name, return clk; } - diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 20b89eb6c35c1f..027100e84ee4c4 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -335,7 +335,6 @@ static u32 cpg_quirks __initdata; #define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */ - static const struct soc_device_attribute cpg_quirks_match[] __initconst = { { .soc_id = "r8a7796", .revision = "ES1.0", diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 1b421b8097965b..79e7a90c3b1bef 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -39,7 +39,6 @@ #define WARN_DEBUG(x) do { } while (0) #endif - /* * Module Standby and Software Reset register offets. * @@ -716,7 +715,6 @@ static inline int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv) } #endif /* !CONFIG_RESET_CONTROLLER */ - static const struct of_device_id cpg_mssr_match[] = { #ifdef CONFIG_CLK_R7S9210 { diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 88bf39e8c79c83..ddf722ca79eb0f 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -548,7 +548,7 @@ static unsigned long rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params, unsigned long rate) { - unsigned long foutpostdiv_rate; + unsigned long foutpostdiv_rate, foutvco_rate; params->pl5_intin = rate / MEGA; params->pl5_fracin = div_u64(((u64)rate % MEGA) << 24, MEGA); @@ -557,10 +557,11 @@ rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params, params->pl5_postdiv2 = 1; params->pl5_spread = 0x16; - foutpostdiv_rate = - EXTAL_FREQ_IN_MEGA_HZ * MEGA / params->pl5_refdiv * - ((((params->pl5_intin << 24) + params->pl5_fracin)) >> 24) / - (params->pl5_postdiv1 * params->pl5_postdiv2); + foutvco_rate = div_u64(mul_u32_u32(EXTAL_FREQ_IN_MEGA_HZ * MEGA, + (params->pl5_intin << 24) + params->pl5_fracin), + params->pl5_refdiv) >> 24; + foutpostdiv_rate = DIV_ROUND_CLOSEST_ULL(foutvco_rate, + params->pl5_postdiv1 * params->pl5_postdiv2); return foutpostdiv_rate; } @@ -1680,23 +1681,31 @@ static int rzg2l_cpg_power_off(struct generic_pm_domain *domain) return 0; } -static int __init rzg2l_cpg_pd_setup(struct rzg2l_cpg_pd *pd, bool always_on) +static int __init rzg2l_cpg_pd_setup(struct rzg2l_cpg_pd *pd) { + bool always_on = !!(pd->genpd.flags & GENPD_FLAG_ALWAYS_ON); struct dev_power_governor *governor; + int ret; + + if (always_on) + governor = &pm_domain_always_on_gov; + else + governor = &simple_qos_governor; pd->genpd.flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; pd->genpd.attach_dev = rzg2l_cpg_attach_dev; pd->genpd.detach_dev = rzg2l_cpg_detach_dev; - if (always_on) { - pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; - governor = &pm_domain_always_on_gov; - } else { - pd->genpd.power_on = rzg2l_cpg_power_on; - pd->genpd.power_off = rzg2l_cpg_power_off; - governor = &simple_qos_governor; - } + pd->genpd.power_on = rzg2l_cpg_power_on; + pd->genpd.power_off = rzg2l_cpg_power_off; + + ret = pm_genpd_init(&pd->genpd, governor, !always_on); + if (ret) + return ret; - return pm_genpd_init(&pd->genpd, governor, !always_on); + if (always_on) + ret = rzg2l_cpg_power_on(&pd->genpd); + + return ret; } static int __init rzg2l_cpg_add_clk_domain(struct rzg2l_cpg_priv *priv) @@ -1711,8 +1720,9 @@ static int __init rzg2l_cpg_add_clk_domain(struct rzg2l_cpg_priv *priv) return -ENOMEM; pd->genpd.name = np->name; + pd->genpd.flags = GENPD_FLAG_ALWAYS_ON; pd->priv = priv; - ret = rzg2l_cpg_pd_setup(pd, true); + ret = rzg2l_cpg_pd_setup(pd); if (ret) return ret; @@ -1777,7 +1787,6 @@ static int __init rzg2l_cpg_add_pm_domains(struct rzg2l_cpg_priv *priv) return ret; for (unsigned int i = 0; i < info->num_pm_domains; i++) { - bool always_on = !!(info->pm_domains[i].flags & RZG2L_PD_F_ALWAYS_ON); struct rzg2l_cpg_pd *pd; pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); @@ -1785,20 +1794,15 @@ static int __init rzg2l_cpg_add_pm_domains(struct rzg2l_cpg_priv *priv) return -ENOMEM; pd->genpd.name = info->pm_domains[i].name; + pd->genpd.flags = info->pm_domains[i].genpd_flags; pd->conf = info->pm_domains[i].conf; pd->id = info->pm_domains[i].id; pd->priv = priv; - ret = rzg2l_cpg_pd_setup(pd, always_on); + ret = rzg2l_cpg_pd_setup(pd); if (ret) return ret; - if (always_on) { - ret = rzg2l_cpg_power_on(&pd->genpd); - if (ret) - return ret; - } - domains->domains[i] = &pd->genpd; /* Parent should be on the very first entry of info->pm_domains[]. */ if (!i) { diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index ecfe7e7ea8a177..881a89b5a71001 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -270,14 +270,14 @@ struct rzg2l_cpg_pm_domain_conf { * struct rzg2l_cpg_pm_domain_init_data - PM domain init data * @name: PM domain name * @conf: PM domain configuration - * @flags: RZG2L PM domain flags (see RZG2L_PD_F_*) + * @genpd_flags: genpd flags (see GENPD_FLAG_*) * @id: PM domain ID (similar to the ones defined in * include/dt-bindings/clock/-cpg.h) */ struct rzg2l_cpg_pm_domain_init_data { const char * const name; struct rzg2l_cpg_pm_domain_conf conf; - u32 flags; + u32 genpd_flags; u16 id; }; @@ -288,13 +288,9 @@ struct rzg2l_cpg_pm_domain_init_data { .conf = { \ .mstop = (_mstop_conf), \ }, \ - .flags = (_flags), \ + .genpd_flags = (_flags), \ } -/* Power domain flags. */ -#define RZG2L_PD_F_ALWAYS_ON BIT(0) -#define RZG2L_PD_F_NONE (0) - /** * struct rzg2l_cpg_info - SoC-specific CPG Description * diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h index 1bd406c69015ba..819029c81904ec 100644 --- a/drivers/clk/renesas/rzv2h-cpg.h +++ b/drivers/clk/renesas/rzv2h-cpg.h @@ -32,8 +32,13 @@ struct ddiv { }) #define CPG_CDDIV0 (0x400) +#define CPG_CDDIV1 (0x404) #define CDDIV0_DIVCTL2 DDIV_PACK(CPG_CDDIV0, 8, 3, 2) +#define CDDIV1_DIVCTL0 DDIV_PACK(CPG_CDDIV1, 0, 2, 4) +#define CDDIV1_DIVCTL1 DDIV_PACK(CPG_CDDIV1, 4, 2, 5) +#define CDDIV1_DIVCTL2 DDIV_PACK(CPG_CDDIV1, 8, 2, 6) +#define CDDIV1_DIVCTL3 DDIV_PACK(CPG_CDDIV1, 12, 2, 7) /** * Definitions of CPG Core Clocks diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index f1ba48758c78c5..7a88331a658d50 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos-arm64.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7885.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos850.o +obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos8895.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynosautov9.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynosautov920.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-gs101.o diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index abd49edcf707aa..e11ac67819ef26 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -4,7 +4,7 @@ * Author: Padmavathi Venna * * Common Clock Framework support for Audio Subsystem Clock Controller. -*/ + */ #include #include diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index cd4fec323a4274..aec4d18c1f9ef9 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -260,7 +260,7 @@ static const struct samsung_mux_clock mux_clks[] __initconst = { /* SRC_TOP0 */ MUX(CLK_MOUT_EBI, "mout_ebi", mout_ebi_p, SRC_TOP0, 28, 1), - MUX(CLK_MOUT_ACLK_200, "mout_aclk_200", group_div_mpll_pre_p,SRC_TOP0, 24, 1), + MUX(CLK_MOUT_ACLK_200, "mout_aclk_200", group_div_mpll_pre_p, SRC_TOP0, 24, 1), MUX(CLK_MOUT_ACLK_160, "mout_aclk_160", group_div_mpll_pre_p, SRC_TOP0, 20, 1), MUX(CLK_MOUT_ACLK_100, "mout_aclk_100", group_div_mpll_pre_p, SRC_TOP0, 16, 1), MUX(CLK_MOUT_ACLK_266_1, "mout_aclk_266_1", mout_aclk_266_1_p, SRC_TOP0, 14, 1), diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 28945b6b0ee1c1..16be0c53903cf4 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -5,7 +5,7 @@ * Author: Thomas Abraham * * Common Clock Framework support for all Exynos4 SoCs. -*/ + */ #include #include diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c index a70c2b06a61a46..29c5644f059379 100644 --- a/drivers/clk/samsung/clk-exynos4412-isp.c +++ b/drivers/clk/samsung/clk-exynos4412-isp.c @@ -4,7 +4,7 @@ * Author: Marek Szyprowski * * Common Clock Framework support for Exynos4412 ISP module. -*/ + */ #include #include diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index e02e7c013f3d2a..47e9ac2275ee35 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -5,7 +5,7 @@ * Author: Thomas Abraham * * Common Clock Framework support for Exynos5250 SoC. -*/ + */ #include #include diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index 16da6ef5ca0c6d..fd0520d204dc7e 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -1458,7 +1458,7 @@ static const struct samsung_fixed_rate_clock fixed_rate_clks[] __initconst = { FRATE(PHYCLK_HDMI_LINK_O_TMDS_CLKHI, "phyclk_hdmi_link_o_tmds_clkhi", NULL, 0, 125000000), FRATE(PHYCLK_MIPI_DPHY_4L_M_TXBYTECLKHS, - "phyclk_mipi_dphy_4l_m_txbyte_clkhs" , NULL, + "phyclk_mipi_dphy_4l_m_txbyte_clkhs", NULL, 0, 187500000), FRATE(PHYCLK_DPTX_PHY_O_REF_CLK_24M, "phyclk_dptx_phy_o_ref_clk_24m", NULL, 0, 24000000), @@ -1629,7 +1629,7 @@ static const struct samsung_mux_clock top_mux_clks[] __initconst = { mout_isp1_media_400_p, MUX_SEL_TOP_ISP10, 4, 1), MUX(TOP_MOUT_ACLK_ISP1_400, "mout_aclk_isp1_400", mout_aclk_isp1_400_p, - MUX_SEL_TOP_ISP10, 8 , 1), + MUX_SEL_TOP_ISP10, 8, 1), MUX(TOP_MOUT_ISP1_MEDIA_266, "mout_isp1_media_266", mout_isp1_media_266_p, MUX_SEL_TOP_ISP10, 16, 1), diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index 2654077211e78d..99b1bb4539fd0f 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -4,7 +4,7 @@ * Author: Tarek Dakhran * * Common Clock Framework support for Exynos5410 SoC. -*/ + */ #include diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index c630135c686bba..333c52fda17f69 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -5,7 +5,7 @@ * Chander Kashyap * * Common Clock Framework support for Exynos5420 SoC. -*/ + */ #include #include @@ -295,8 +295,8 @@ static const struct samsung_clk_reg_dump exynos5420_set_clksrc[] = { /* list of all parent clocks */ PNAME(mout_mspll_cpu_p) = {"mout_sclk_cpll", "mout_sclk_dpll", "mout_sclk_mpll", "mout_sclk_spll"}; -PNAME(mout_cpu_p) = {"mout_apll" , "mout_mspll_cpu"}; -PNAME(mout_kfc_p) = {"mout_kpll" , "mout_mspll_kfc"}; +PNAME(mout_cpu_p) = {"mout_apll", "mout_mspll_cpu"}; +PNAME(mout_kfc_p) = {"mout_kpll", "mout_mspll_kfc"}; PNAME(mout_apll_p) = {"fin_pll", "fout_apll"}; PNAME(mout_bpll_p) = {"fin_pll", "fout_bpll"}; PNAME(mout_cpll_p) = {"fin_pll", "fout_cpll"}; diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index 4a5d2a914bd668..e6c938effa29bc 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2014 Samsung Electronics Co., Ltd. * Author: Naveen Krishna Ch -*/ + */ #include #include diff --git a/drivers/clk/samsung/clk-exynos8895.c b/drivers/clk/samsung/clk-exynos8895.c new file mode 100644 index 00000000000000..29ec0c4a863524 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos8895.c @@ -0,0 +1,2803 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Ivaylo Ivanov + * Author: Ivaylo Ivanov + * + * Common Clock Framework support for Exynos8895 SoC. + */ + +#include +#include +#include +#include + +#include + +#include "clk.h" +#include "clk-exynos-arm64.h" + +/* NOTE: Must be equal to the last clock ID increased by one */ +#define CLKS_NR_TOP (CLK_GOUT_CMU_VPU_BUS + 1) +#define CLKS_NR_FSYS0 (CLK_GOUT_FSYS0_XIU_P_FSYS0_ACLK + 1) +#define CLKS_NR_FSYS1 (CLK_GOUT_FSYS1_XIU_P_FSYS1_ACLK + 1) +#define CLKS_NR_PERIC0 (CLK_GOUT_PERIC0_USI03_I_SCLK_USI + 1) +#define CLKS_NR_PERIC1 (CLK_GOUT_PERIC1_XIU_P_PERIC1_ACLK + 1) +#define CLKS_NR_PERIS (CLK_GOUT_PERIS_XIU_P_PERIS_ACLK + 1) + +/* ---- CMU_TOP ------------------------------------------------------------- */ + +/* Register Offset definitions for CMU_TOP (0x15a80000) */ +#define PLL_LOCKTIME_PLL_SHARED0 0x0000 +#define PLL_LOCKTIME_PLL_SHARED1 0x0004 +#define PLL_LOCKTIME_PLL_SHARED2 0x0008 +#define PLL_LOCKTIME_PLL_SHARED3 0x000c +#define PLL_LOCKTIME_PLL_SHARED4 0x0010 +#define PLL_CON0_MUX_CP2AP_MIF_CLK_USER 0x0100 +#define PLL_CON2_MUX_CP2AP_MIF_CLK_USER 0x0108 +#define PLL_CON0_PLL_SHARED0 0x0120 +#define PLL_CON0_PLL_SHARED1 0x0140 +#define PLL_CON0_PLL_SHARED2 0x0160 +#define PLL_CON0_PLL_SHARED3 0x0180 +#define PLL_CON0_PLL_SHARED4 0x01a0 +#define CLK_CON_MUX_MUX_CLKCMU_ABOX_CPUABOX 0x1000 +#define CLK_CON_MUX_MUX_CLKCMU_APM_BUS 0x1004 +#define CLK_CON_MUX_MUX_CLKCMU_BUS1_BUS 0x1008 +#define CLK_CON_MUX_MUX_CLKCMU_BUSC_BUS 0x100c +#define CLK_CON_MUX_MUX_CLKCMU_BUSC_BUSPHSI2C 0x1010 +#define CLK_CON_MUX_MUX_CLKCMU_CAM_BUS 0x1014 +#define CLK_CON_MUX_MUX_CLKCMU_CAM_TPU0 0x1018 +#define CLK_CON_MUX_MUX_CLKCMU_CAM_TPU1 0x101c +#define CLK_CON_MUX_MUX_CLKCMU_CAM_VRA 0x1020 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK0 0x1024 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK1 0x1028 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK2 0x102c +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK3 0x1030 +#define CLK_CON_MUX_MUX_CLKCMU_CORE_BUS 0x1034 +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH 0x1038 +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH 0x103c +#define CLK_CON_MUX_MUX_CLKCMU_DBG_BUS 0x1040 +#define CLK_CON_MUX_MUX_CLKCMU_DCAM_BUS 0x1044 +#define CLK_CON_MUX_MUX_CLKCMU_DCAM_IMGD 0x1048 +#define CLK_CON_MUX_MUX_CLKCMU_DPU_BUS 0x104c +#define CLK_CON_MUX_MUX_CLKCMU_DROOPDETECTOR 0x1050 +#define CLK_CON_MUX_MUX_CLKCMU_DSP_BUS 0x1054 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS0_BUS 0x1058 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS0_DPGTC 0x105c +#define CLK_CON_MUX_MUX_CLKCMU_FSYS0_MMC_EMBD 0x1060 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS0_UFS_EMBD 0x1064 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS0_USBDRD30 0x1068 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS1_BUS 0x106c +#define CLK_CON_MUX_MUX_CLKCMU_FSYS1_MMC_CARD 0x1070 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS1_PCIE 0x1074 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS1_UFS_CARD 0x1078 +#define CLK_CON_MUX_MUX_CLKCMU_G2D_G2D 0x107c +#define CLK_CON_MUX_MUX_CLKCMU_G2D_JPEG 0x1080 +#define CLK_CON_MUX_MUX_CLKCMU_HPM 0x1084 +#define CLK_CON_MUX_MUX_CLKCMU_IMEM_BUS 0x1088 +#define CLK_CON_MUX_MUX_CLKCMU_ISPHQ_BUS 0x108c +#define CLK_CON_MUX_MUX_CLKCMU_ISPLP_BUS 0x1090 +#define CLK_CON_MUX_MUX_CLKCMU_IVA_BUS 0x1094 +#define CLK_CON_MUX_MUX_CLKCMU_MFC_BUS 0x1098 +#define CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH 0x109c +#define CLK_CON_MUX_MUX_CLKCMU_PERIC0_BUS 0x10a0 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC0_UART_DBG 0x10a4 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI00 0x10a8 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI01 0x10ac +#define CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI02 0x10b0 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI03 0x10b4 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_BUS 0x10b8 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPEEDY2 0x10bc +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPI_CAM0 0x10c0 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPI_CAM1 0x10c4 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_UART_BT 0x10c8 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI04 0x10cc +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI05 0x10d0 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI06 0x10d4 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI07 0x10d8 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI08 0x10dc +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI09 0x10e0 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI10 0x10e4 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI11 0x10e8 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI12 0x10ec +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI13 0x10f0 +#define CLK_CON_MUX_MUX_CLKCMU_PERIS_BUS 0x10f4 +#define CLK_CON_MUX_MUX_CLKCMU_SRDZ_BUS 0x10f8 +#define CLK_CON_MUX_MUX_CLKCMU_SRDZ_IMGD 0x10fc +#define CLK_CON_MUX_MUX_CLKCMU_VPU_BUS 0x1100 +#define CLK_CON_MUX_MUX_CLK_CMU_CMUREF 0x1104 +#define CLK_CON_MUX_MUX_CMU_CMUREF 0x1108 +#define CLK_CON_DIV_CLKCMU_ABOX_CPUABOX 0x1800 +#define CLK_CON_DIV_CLKCMU_APM_BUS 0x1804 +#define CLK_CON_DIV_CLKCMU_BUS1_BUS 0x1808 +#define CLK_CON_DIV_CLKCMU_BUSC_BUS 0x180c +#define CLK_CON_DIV_CLKCMU_BUSC_BUSPHSI2C 0x1810 +#define CLK_CON_DIV_CLKCMU_CAM_BUS 0x1814 +#define CLK_CON_DIV_CLKCMU_CAM_TPU0 0x1818 +#define CLK_CON_DIV_CLKCMU_CAM_TPU1 0x181c +#define CLK_CON_DIV_CLKCMU_CAM_VRA 0x1820 +#define CLK_CON_DIV_CLKCMU_CIS_CLK0 0x1824 +#define CLK_CON_DIV_CLKCMU_CIS_CLK1 0x1828 +#define CLK_CON_DIV_CLKCMU_CIS_CLK2 0x182c +#define CLK_CON_DIV_CLKCMU_CIS_CLK3 0x1830 +#define CLK_CON_DIV_CLKCMU_CORE_BUS 0x1834 +#define CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH 0x1838 +#define CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH 0x183c +#define CLK_CON_DIV_CLKCMU_DBG_BUS 0x1840 +#define CLK_CON_DIV_CLKCMU_DCAM_BUS 0x1844 +#define CLK_CON_DIV_CLKCMU_DCAM_IMGD 0x1848 +#define CLK_CON_DIV_CLKCMU_DPU_BUS 0x184c +#define CLK_CON_DIV_CLKCMU_DSP_BUS 0x1850 +#define CLK_CON_DIV_CLKCMU_FSYS0_BUS 0x1854 +#define CLK_CON_DIV_CLKCMU_FSYS0_DPGTC 0x1858 +#define CLK_CON_DIV_CLKCMU_FSYS0_MMC_EMBD 0x185c +#define CLK_CON_DIV_CLKCMU_FSYS0_UFS_EMBD 0x1860 +#define CLK_CON_DIV_CLKCMU_FSYS0_USBDRD30 0x1864 +#define CLK_CON_DIV_CLKCMU_FSYS1_BUS 0x1868 +#define CLK_CON_DIV_CLKCMU_FSYS1_MMC_CARD 0x186c +#define CLK_CON_DIV_CLKCMU_FSYS1_PCIE 0x1870 +#define CLK_CON_DIV_CLKCMU_FSYS1_UFS_CARD 0x1874 +#define CLK_CON_DIV_CLKCMU_G2D_G2D 0x1878 +#define CLK_CON_DIV_CLKCMU_G2D_JPEG 0x187c +#define CLK_CON_DIV_CLKCMU_G3D_SWITCH 0x1880 +#define CLK_CON_DIV_CLKCMU_HPM 0x1884 +#define CLK_CON_DIV_CLKCMU_IMEM_BUS 0x1888 +#define CLK_CON_DIV_CLKCMU_ISPHQ_BUS 0x188c +#define CLK_CON_DIV_CLKCMU_ISPLP_BUS 0x1890 +#define CLK_CON_DIV_CLKCMU_IVA_BUS 0x1894 +#define CLK_CON_DIV_CLKCMU_MFC_BUS 0x1898 +#define CLK_CON_DIV_CLKCMU_MODEM_SHARED0 0x189c +#define CLK_CON_DIV_CLKCMU_MODEM_SHARED1 0x18a0 +#define CLK_CON_DIV_CLKCMU_OTP 0x18a4 +#define CLK_CON_DIV_CLKCMU_PERIC0_BUS 0x18a8 +#define CLK_CON_DIV_CLKCMU_PERIC0_UART_DBG 0x18ac +#define CLK_CON_DIV_CLKCMU_PERIC0_USI00 0x18b0 +#define CLK_CON_DIV_CLKCMU_PERIC0_USI01 0x18b4 +#define CLK_CON_DIV_CLKCMU_PERIC0_USI02 0x18b8 +#define CLK_CON_DIV_CLKCMU_PERIC0_USI03 0x18bc +#define CLK_CON_DIV_CLKCMU_PERIC1_BUS 0x18c0 +#define CLK_CON_DIV_CLKCMU_PERIC1_SPEEDY2 0x18c4 +#define CLK_CON_DIV_CLKCMU_PERIC1_SPI_CAM0 0x18c8 +#define CLK_CON_DIV_CLKCMU_PERIC1_SPI_CAM1 0x18cc +#define CLK_CON_DIV_CLKCMU_PERIC1_UART_BT 0x18d0 +#define CLK_CON_DIV_CLKCMU_PERIC1_USI04 0x18d4 +#define CLK_CON_DIV_CLKCMU_PERIC1_USI05 0x18d8 +#define CLK_CON_DIV_CLKCMU_PERIC1_USI06 0x18dc +#define CLK_CON_DIV_CLKCMU_PERIC1_USI07 0x18e0 +#define CLK_CON_DIV_CLKCMU_PERIC1_USI08 0x18e4 +#define CLK_CON_DIV_CLKCMU_PERIC1_USI09 0x18e8 +#define CLK_CON_DIV_CLKCMU_PERIC1_USI10 0x18ec +#define CLK_CON_DIV_CLKCMU_PERIC1_USI11 0x18f0 +#define CLK_CON_DIV_CLKCMU_PERIC1_USI12 0x18f4 +#define CLK_CON_DIV_CLKCMU_PERIC1_USI13 0x18f8 +#define CLK_CON_DIV_CLKCMU_PERIS_BUS 0x18fc +#define CLK_CON_DIV_CLKCMU_SRDZ_BUS 0x1900 +#define CLK_CON_DIV_CLKCMU_SRDZ_IMGD 0x1904 +#define CLK_CON_DIV_CLKCMU_VPU_BUS 0x1908 +#define CLK_CON_DIV_DIV_CLK_CMU_CMUREF 0x190c +#define CLK_CON_DIV_DIV_CP2AP_MIF_CLK_DIV2 0x1910 +#define CLK_CON_DIV_DIV_PLL_SHARED0_DIV2 0x1914 +#define CLK_CON_DIV_DIV_PLL_SHARED0_DIV4 0x1918 +#define CLK_CON_DIV_DIV_PLL_SHARED1_DIV2 0x191c +#define CLK_CON_DIV_DIV_PLL_SHARED1_DIV4 0x1920 +#define CLK_CON_DIV_DIV_PLL_SHARED2_DIV2 0x1924 +#define CLK_CON_DIV_DIV_PLL_SHARED3_DIV2 0x1928 +#define CLK_CON_DIV_DIV_PLL_SHARED4_DIV2 0x192c +#define CLK_CON_GAT_CLKCMU_DROOPDETECTOR 0x2000 +#define CLK_CON_GAT_CLKCMU_MIF_SWITCH 0x2004 +#define CLK_CON_GAT_GATE_CLKCMU_ABOX_CPUABOX 0x2008 +#define CLK_CON_GAT_GATE_CLKCMU_APM_BUS 0x200c +#define CLK_CON_GAT_GATE_CLKCMU_BUS1_BUS 0x2010 +#define CLK_CON_GAT_GATE_CLKCMU_BUSC_BUS 0x2014 +#define CLK_CON_GAT_GATE_CLKCMU_BUSC_BUSPHSI2C 0x2018 +#define CLK_CON_GAT_GATE_CLKCMU_CAM_BUS 0x201c +#define CLK_CON_GAT_GATE_CLKCMU_CAM_TPU0 0x2020 +#define CLK_CON_GAT_GATE_CLKCMU_CAM_TPU1 0x2024 +#define CLK_CON_GAT_GATE_CLKCMU_CAM_VRA 0x2028 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK0 0x202c +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK1 0x2030 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK2 0x2034 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK3 0x2038 +#define CLK_CON_GAT_GATE_CLKCMU_CORE_BUS 0x203c +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH 0x2040 +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH 0x2044 +#define CLK_CON_GAT_GATE_CLKCMU_DBG_BUS 0x2048 +#define CLK_CON_GAT_GATE_CLKCMU_DCAM_BUS 0x204c +#define CLK_CON_GAT_GATE_CLKCMU_DCAM_IMGD 0x2050 +#define CLK_CON_GAT_GATE_CLKCMU_DPU_BUS 0x2054 +#define CLK_CON_GAT_GATE_CLKCMU_DSP_BUS 0x2058 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS0_BUS 0x205c +#define CLK_CON_GAT_GATE_CLKCMU_FSYS0_DPGTC 0x2060 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS0_MMC_EMBD 0x2064 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS0_UFS_EMBD 0x2068 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS0_USBDRD30 0x206c +#define CLK_CON_GAT_GATE_CLKCMU_FSYS1_BUS 0x2070 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS1_MMC_CARD 0x2074 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS1_PCIE 0x2078 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS1_UFS_CARD 0x207c +#define CLK_CON_GAT_GATE_CLKCMU_G2D_G2D 0x2080 +#define CLK_CON_GAT_GATE_CLKCMU_G2D_JPEG 0x2084 +#define CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH 0x2088 +#define CLK_CON_GAT_GATE_CLKCMU_HPM 0x208c +#define CLK_CON_GAT_GATE_CLKCMU_IMEM_BUS 0x2090 +#define CLK_CON_GAT_GATE_CLKCMU_ISPHQ_BUS 0x2094 +#define CLK_CON_GAT_GATE_CLKCMU_ISPLP_BUS 0x2098 +#define CLK_CON_GAT_GATE_CLKCMU_IVA_BUS 0x209c +#define CLK_CON_GAT_GATE_CLKCMU_MFC_BUS 0x20a0 +#define CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED0 0x20a4 +#define CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED1 0x20a8 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC0_BUS 0x20ac +#define CLK_CON_GAT_GATE_CLKCMU_PERIC0_UART_DBG 0x20b0 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI00 0x20b4 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI01 0x20b8 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI02 0x20bc +#define CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI03 0x20c0 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_BUS 0x20c4 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPEEDY2 0x20c8 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPI_CAM0 0x20cc +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPI_CAM1 0x20d0 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_UART_BT 0x20d4 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI04 0x20d8 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI05 0x20dc +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI06 0x20e0 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI07 0x20e4 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI08 0x20e8 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI09 0x20ec +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI10 0x20f0 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI11 0x20f4 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI12 0x20f8 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI13 0x20fc +#define CLK_CON_GAT_GATE_CLKCMU_PERIS_BUS 0x2100 +#define CLK_CON_GAT_GATE_CLKCMU_SRDZ_BUS 0x2104 +#define CLK_CON_GAT_GATE_CLKCMU_SRDZ_IMGD 0x2108 +#define CLK_CON_GAT_GATE_CLKCMU_VPU_BUS 0x210c + +static const unsigned long top_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_SHARED0, + PLL_LOCKTIME_PLL_SHARED1, + PLL_LOCKTIME_PLL_SHARED2, + PLL_LOCKTIME_PLL_SHARED3, + PLL_LOCKTIME_PLL_SHARED4, + PLL_CON0_MUX_CP2AP_MIF_CLK_USER, + PLL_CON2_MUX_CP2AP_MIF_CLK_USER, + PLL_CON0_PLL_SHARED0, + PLL_CON0_PLL_SHARED1, + PLL_CON0_PLL_SHARED2, + PLL_CON0_PLL_SHARED3, + PLL_CON0_PLL_SHARED4, + CLK_CON_MUX_MUX_CLKCMU_ABOX_CPUABOX, + CLK_CON_MUX_MUX_CLKCMU_APM_BUS, + CLK_CON_MUX_MUX_CLKCMU_BUS1_BUS, + CLK_CON_MUX_MUX_CLKCMU_BUSC_BUS, + CLK_CON_MUX_MUX_CLKCMU_BUSC_BUSPHSI2C, + CLK_CON_MUX_MUX_CLKCMU_CAM_BUS, + CLK_CON_MUX_MUX_CLKCMU_CAM_TPU0, + CLK_CON_MUX_MUX_CLKCMU_CAM_TPU1, + CLK_CON_MUX_MUX_CLKCMU_CAM_VRA, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK0, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK1, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK2, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK3, + CLK_CON_MUX_MUX_CLKCMU_CORE_BUS, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_DBG_BUS, + CLK_CON_MUX_MUX_CLKCMU_DCAM_BUS, + CLK_CON_MUX_MUX_CLKCMU_DCAM_IMGD, + CLK_CON_MUX_MUX_CLKCMU_DPU_BUS, + CLK_CON_MUX_MUX_CLKCMU_DROOPDETECTOR, + CLK_CON_MUX_MUX_CLKCMU_DSP_BUS, + CLK_CON_MUX_MUX_CLKCMU_FSYS0_BUS, + CLK_CON_MUX_MUX_CLKCMU_FSYS0_DPGTC, + CLK_CON_MUX_MUX_CLKCMU_FSYS0_MMC_EMBD, + CLK_CON_MUX_MUX_CLKCMU_FSYS0_UFS_EMBD, + CLK_CON_MUX_MUX_CLKCMU_FSYS0_USBDRD30, + CLK_CON_MUX_MUX_CLKCMU_FSYS1_BUS, + CLK_CON_MUX_MUX_CLKCMU_FSYS1_MMC_CARD, + CLK_CON_MUX_MUX_CLKCMU_FSYS1_PCIE, + CLK_CON_MUX_MUX_CLKCMU_FSYS1_UFS_CARD, + CLK_CON_MUX_MUX_CLKCMU_G2D_G2D, + CLK_CON_MUX_MUX_CLKCMU_G2D_JPEG, + CLK_CON_MUX_MUX_CLKCMU_HPM, + CLK_CON_MUX_MUX_CLKCMU_IMEM_BUS, + CLK_CON_MUX_MUX_CLKCMU_ISPHQ_BUS, + CLK_CON_MUX_MUX_CLKCMU_ISPLP_BUS, + CLK_CON_MUX_MUX_CLKCMU_IVA_BUS, + CLK_CON_MUX_MUX_CLKCMU_MFC_BUS, + CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_BUS, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_UART_DBG, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI00, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI01, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI02, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI03, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_BUS, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPEEDY2, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPI_CAM0, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPI_CAM1, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_UART_BT, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI04, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI05, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI06, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI07, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI08, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI09, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI10, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI11, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI12, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI13, + CLK_CON_MUX_MUX_CLKCMU_PERIS_BUS, + CLK_CON_MUX_MUX_CLKCMU_SRDZ_BUS, + CLK_CON_MUX_MUX_CLKCMU_SRDZ_IMGD, + CLK_CON_MUX_MUX_CLKCMU_VPU_BUS, + CLK_CON_MUX_MUX_CLK_CMU_CMUREF, + CLK_CON_MUX_MUX_CMU_CMUREF, + CLK_CON_DIV_CLKCMU_ABOX_CPUABOX, + CLK_CON_DIV_CLKCMU_APM_BUS, + CLK_CON_DIV_CLKCMU_BUS1_BUS, + CLK_CON_DIV_CLKCMU_BUSC_BUS, + CLK_CON_DIV_CLKCMU_BUSC_BUSPHSI2C, + CLK_CON_DIV_CLKCMU_CAM_BUS, + CLK_CON_DIV_CLKCMU_CAM_TPU0, + CLK_CON_DIV_CLKCMU_CAM_TPU1, + CLK_CON_DIV_CLKCMU_CAM_VRA, + CLK_CON_DIV_CLKCMU_CIS_CLK0, + CLK_CON_DIV_CLKCMU_CIS_CLK1, + CLK_CON_DIV_CLKCMU_CIS_CLK2, + CLK_CON_DIV_CLKCMU_CIS_CLK3, + CLK_CON_DIV_CLKCMU_CORE_BUS, + CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH, + CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH, + CLK_CON_DIV_CLKCMU_DBG_BUS, + CLK_CON_DIV_CLKCMU_DCAM_BUS, + CLK_CON_DIV_CLKCMU_DCAM_IMGD, + CLK_CON_DIV_CLKCMU_DPU_BUS, + CLK_CON_DIV_CLKCMU_DSP_BUS, + CLK_CON_DIV_CLKCMU_FSYS0_BUS, + CLK_CON_DIV_CLKCMU_FSYS0_DPGTC, + CLK_CON_DIV_CLKCMU_FSYS0_MMC_EMBD, + CLK_CON_DIV_CLKCMU_FSYS0_UFS_EMBD, + CLK_CON_DIV_CLKCMU_FSYS0_USBDRD30, + CLK_CON_DIV_CLKCMU_FSYS1_BUS, + CLK_CON_DIV_CLKCMU_FSYS1_MMC_CARD, + CLK_CON_DIV_CLKCMU_FSYS1_PCIE, + CLK_CON_DIV_CLKCMU_FSYS1_UFS_CARD, + CLK_CON_DIV_CLKCMU_G2D_G2D, + CLK_CON_DIV_CLKCMU_G2D_JPEG, + CLK_CON_DIV_CLKCMU_G3D_SWITCH, + CLK_CON_DIV_CLKCMU_HPM, + CLK_CON_DIV_CLKCMU_IMEM_BUS, + CLK_CON_DIV_CLKCMU_ISPHQ_BUS, + CLK_CON_DIV_CLKCMU_ISPLP_BUS, + CLK_CON_DIV_CLKCMU_IVA_BUS, + CLK_CON_DIV_CLKCMU_MFC_BUS, + CLK_CON_DIV_CLKCMU_MODEM_SHARED0, + CLK_CON_DIV_CLKCMU_MODEM_SHARED1, + CLK_CON_DIV_CLKCMU_OTP, + CLK_CON_DIV_CLKCMU_PERIC0_BUS, + CLK_CON_DIV_CLKCMU_PERIC0_UART_DBG, + CLK_CON_DIV_CLKCMU_PERIC0_USI00, + CLK_CON_DIV_CLKCMU_PERIC0_USI01, + CLK_CON_DIV_CLKCMU_PERIC0_USI02, + CLK_CON_DIV_CLKCMU_PERIC0_USI03, + CLK_CON_DIV_CLKCMU_PERIC1_BUS, + CLK_CON_DIV_CLKCMU_PERIC1_SPEEDY2, + CLK_CON_DIV_CLKCMU_PERIC1_SPI_CAM0, + CLK_CON_DIV_CLKCMU_PERIC1_SPI_CAM1, + CLK_CON_DIV_CLKCMU_PERIC1_UART_BT, + CLK_CON_DIV_CLKCMU_PERIC1_USI04, + CLK_CON_DIV_CLKCMU_PERIC1_USI05, + CLK_CON_DIV_CLKCMU_PERIC1_USI06, + CLK_CON_DIV_CLKCMU_PERIC1_USI07, + CLK_CON_DIV_CLKCMU_PERIC1_USI08, + CLK_CON_DIV_CLKCMU_PERIC1_USI09, + CLK_CON_DIV_CLKCMU_PERIC1_USI10, + CLK_CON_DIV_CLKCMU_PERIC1_USI11, + CLK_CON_DIV_CLKCMU_PERIC1_USI12, + CLK_CON_DIV_CLKCMU_PERIC1_USI13, + CLK_CON_DIV_CLKCMU_PERIS_BUS, + CLK_CON_DIV_CLKCMU_SRDZ_BUS, + CLK_CON_DIV_CLKCMU_SRDZ_IMGD, + CLK_CON_DIV_CLKCMU_VPU_BUS, + CLK_CON_DIV_DIV_CLK_CMU_CMUREF, + CLK_CON_DIV_DIV_CP2AP_MIF_CLK_DIV2, + CLK_CON_DIV_DIV_PLL_SHARED0_DIV2, + CLK_CON_DIV_DIV_PLL_SHARED0_DIV4, + CLK_CON_DIV_DIV_PLL_SHARED1_DIV2, + CLK_CON_DIV_DIV_PLL_SHARED1_DIV4, + CLK_CON_DIV_DIV_PLL_SHARED2_DIV2, + CLK_CON_DIV_DIV_PLL_SHARED3_DIV2, + CLK_CON_DIV_DIV_PLL_SHARED4_DIV2, + CLK_CON_GAT_CLKCMU_DROOPDETECTOR, + CLK_CON_GAT_CLKCMU_MIF_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_ABOX_CPUABOX, + CLK_CON_GAT_GATE_CLKCMU_APM_BUS, + CLK_CON_GAT_GATE_CLKCMU_BUS1_BUS, + CLK_CON_GAT_GATE_CLKCMU_BUSC_BUS, + CLK_CON_GAT_GATE_CLKCMU_BUSC_BUSPHSI2C, + CLK_CON_GAT_GATE_CLKCMU_CAM_BUS, + CLK_CON_GAT_GATE_CLKCMU_CAM_TPU0, + CLK_CON_GAT_GATE_CLKCMU_CAM_TPU1, + CLK_CON_GAT_GATE_CLKCMU_CAM_VRA, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK0, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK1, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK2, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK3, + CLK_CON_GAT_GATE_CLKCMU_CORE_BUS, + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_DBG_BUS, + CLK_CON_GAT_GATE_CLKCMU_DCAM_BUS, + CLK_CON_GAT_GATE_CLKCMU_DCAM_IMGD, + CLK_CON_GAT_GATE_CLKCMU_DPU_BUS, + CLK_CON_GAT_GATE_CLKCMU_DSP_BUS, + CLK_CON_GAT_GATE_CLKCMU_FSYS0_BUS, + CLK_CON_GAT_GATE_CLKCMU_FSYS0_DPGTC, + CLK_CON_GAT_GATE_CLKCMU_FSYS0_MMC_EMBD, + CLK_CON_GAT_GATE_CLKCMU_FSYS0_UFS_EMBD, + CLK_CON_GAT_GATE_CLKCMU_FSYS0_USBDRD30, + CLK_CON_GAT_GATE_CLKCMU_FSYS1_BUS, + CLK_CON_GAT_GATE_CLKCMU_FSYS1_MMC_CARD, + CLK_CON_GAT_GATE_CLKCMU_FSYS1_PCIE, + CLK_CON_GAT_GATE_CLKCMU_FSYS1_UFS_CARD, + CLK_CON_GAT_GATE_CLKCMU_G2D_G2D, + CLK_CON_GAT_GATE_CLKCMU_G2D_JPEG, + CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_HPM, + CLK_CON_GAT_GATE_CLKCMU_IMEM_BUS, + CLK_CON_GAT_GATE_CLKCMU_ISPHQ_BUS, + CLK_CON_GAT_GATE_CLKCMU_ISPLP_BUS, + CLK_CON_GAT_GATE_CLKCMU_IVA_BUS, + CLK_CON_GAT_GATE_CLKCMU_MFC_BUS, + CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED0, + CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED1, + CLK_CON_GAT_GATE_CLKCMU_PERIC0_BUS, + CLK_CON_GAT_GATE_CLKCMU_PERIC0_UART_DBG, + CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI00, + CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI01, + CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI02, + CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI03, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_BUS, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPEEDY2, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPI_CAM0, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPI_CAM1, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_UART_BT, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI04, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI05, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI06, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI07, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI08, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI09, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI10, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI11, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI12, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI13, + CLK_CON_GAT_GATE_CLKCMU_PERIS_BUS, + CLK_CON_GAT_GATE_CLKCMU_SRDZ_BUS, + CLK_CON_GAT_GATE_CLKCMU_SRDZ_IMGD, + CLK_CON_GAT_GATE_CLKCMU_VPU_BUS, +}; + +static const struct samsung_pll_rate_table pll_shared0_rate_table[] __initconst = { + PLL_35XX_RATE(26 * MHZ, 2132000000U, 328, 4, 0), +}; + +static const struct samsung_pll_rate_table pll_shared1_rate_table[] __initconst = { + PLL_35XX_RATE(26 * MHZ, 1865500000U, 287, 4, 0), +}; + +static const struct samsung_pll_rate_table pll_shared2_rate_table[] __initconst = { + PLL_35XX_RATE(26 * MHZ, 800000000U, 400, 13, 0), +}; + +static const struct samsung_pll_rate_table pll_shared3_rate_table[] __initconst = { + PLL_35XX_RATE(26 * MHZ, 630000000U, 315, 13, 0), +}; + +static const struct samsung_pll_rate_table pll_shared4_rate_table[] __initconst = { + PLL_35XX_RATE(26 * MHZ, 667333333U, 154, 6, 0), +}; + +static const struct samsung_pll_clock top_pll_clks[] __initconst = { + /* CMU_TOP_PURECLKCOMP */ + PLL(pll_1051x, CLK_FOUT_SHARED0_PLL, "fout_shared0_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED0, PLL_CON0_PLL_SHARED0, + pll_shared0_rate_table), + PLL(pll_1051x, CLK_FOUT_SHARED1_PLL, "fout_shared1_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED1, PLL_CON0_PLL_SHARED1, + pll_shared1_rate_table), + PLL(pll_1052x, CLK_FOUT_SHARED2_PLL, "fout_shared2_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED2, PLL_CON0_PLL_SHARED2, + pll_shared2_rate_table), + PLL(pll_1052x, CLK_FOUT_SHARED3_PLL, "fout_shared3_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED3, PLL_CON0_PLL_SHARED3, + pll_shared3_rate_table), + PLL(pll_1052x, CLK_FOUT_SHARED4_PLL, "fout_shared4_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED4, PLL_CON0_PLL_SHARED4, + pll_shared4_rate_table), +}; + +/* List of parent clocks for Muxes in CMU_TOP */ +PNAME(mout_pll_shared0_p) = { "oscclk", "fout_shared0_pll" }; +PNAME(mout_pll_shared1_p) = { "oscclk", "fout_shared1_pll" }; +PNAME(mout_pll_shared2_p) = { "oscclk", "fout_shared2_pll" }; +PNAME(mout_pll_shared3_p) = { "oscclk", "fout_shared3_pll" }; +PNAME(mout_pll_shared4_p) = { "oscclk", "fout_shared4_pll" }; +PNAME(mout_cp2ap_mif_clk_user_p) = { "oscclk" }; +PNAME(mout_cmu_abox_cpuabox_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", + "fout_shared4_pll" }; +PNAME(mout_cmu_apm_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_bus1_bus_p) = { "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_busc_bus_p) = { "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_cp2ap_mif_clk_div2", + "oscclk", "oscclk", "oscclk" }; +PNAME(mout_cmu_busc_busphsi2c_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_cp2ap_mif_clk_div2", + "oscclk" }; +PNAME(mout_cmu_cam_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_cam_tpu0_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_cam_tpu1_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_cam_vra_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_cis_clk0_p) = { "oscclk", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_cis_clk1_p) = { "oscclk", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_cis_clk2_p) = { "oscclk", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_cis_clk3_p) = { "oscclk", + "dout_cmu_shared2_div2" }; +PNAME(mout_core_bus_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", + "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_cp2ap_mif_clk_div2" }; +PNAME(mout_cmu_cpucl0_switch_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", + "fout_shared4_pll" }; +PNAME(mout_cmu_cpucl1_switch_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", + "fout_shared4_pll" }; +PNAME(mout_cmu_dbg_bus_p) = { "fout_shared2_pll", + "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4" }; +PNAME(mout_cmu_dcam_bus_p) = { "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_dcam_imgd_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_dpu_bus_p) = { "dout_cmu_shared0_div2", + "fout_shared3_pll", + "fout_shared4_pll", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "oscclk", "oscclk", "oscclk" }; +PNAME(mout_cmu_droopdetector_p) = { "oscclk", "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll" }; +PNAME(mout_cmu_dsp_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_fsys0_bus_p) = { "dout_cmu_shared1_div2", + "fout_shared2_pll", + "fout_shared4_pll", + "dout_cmu_shared0_div4" }; +PNAME(mout_fsys0_dpgtc_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_fsys0_mmc_embd_p) = { "oscclk", "fout_shared2_pll", + "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "oscclk", "oscclk", "oscclk" }; +PNAME(mout_fsys0_ufs_embd_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_fsys0_usbdrd30_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_fsys1_bus_p) = { "fout_shared2_pll", + "dout_cmu_shared0_div4" }; +PNAME(mout_cmu_fsys1_mmc_card_p) = { "oscclk", "fout_shared2_pll", + "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "oscclk", "oscclk", "oscclk" }; +PNAME(mout_cmu_fsys1_pcie_p) = { "oscclk", "fout_shared2_pll" }; +PNAME(mout_cmu_fsys1_ufs_card_p) = { "oscclk", + "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_g2d_g2d_p) = { "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_g2d_jpeg_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_hpm_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_imem_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_isphq_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_isplp_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_iva_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_mfc_bus_p) = { "fout_shared4_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_mif_switch_p) = { "fout_shared0_pll", + "fout_shared1_pll", + "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", + "mout_cp2ap_mif_clk_user", + "oscclk", "oscclk" }; +PNAME(mout_cmu_peric0_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_peric0_uart_dbg_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric0_usi00_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric0_usi01_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric0_usi02_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric0_usi03_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_peric1_speedy2_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "oscclk" }; +PNAME(mout_cmu_peric1_spi_cam0_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_spi_cam1_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_uart_bt_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi04_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi05_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi06_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi07_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi08_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi09_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi10_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi11_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi12_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peric1_usi13_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_peris_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_srdz_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_srdz_imgd_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; +PNAME(mout_cmu_vpu_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared4_div2" }; + +/* + * Register name to clock name mangling strategy used in this file + * + * Replace PLL_CON0_PLL with CLK_MOUT_PLL and mout_pll + * Replace CLK_CON_MUX_MUX_CLKCMU with CLK_MOUT_CMU and mout_cmu + * Replace CLK_CON_DIV_CLKCMU with CLK_DOUT_CMU and dout_cmu + * Replace CLK_CON_DIV_DIV_CLKCMU with CLK_DOUT_CMU and dout_cmu + * Replace CLK_CON_GAT_CLKCMU with CLK_GOUT_CMU and gout_cmu + * Replace CLK_CON_GAT_GATE_CLKCMU with CLK_GOUT_CMU and gout_cmu + * + * For gates remove _UID _BLK _IPCLKPORT and _RSTNSYNC + */ + +static const struct samsung_mux_clock top_mux_clks[] __initconst = { + MUX(CLK_MOUT_PLL_SHARED0, "mout_pll_shared0", mout_pll_shared0_p, + PLL_CON0_PLL_SHARED0, 4, 1), + MUX(CLK_MOUT_PLL_SHARED1, "mout_pll_shared1", mout_pll_shared1_p, + PLL_CON0_PLL_SHARED1, 4, 1), + MUX(CLK_MOUT_PLL_SHARED2, "mout_pll_shared2", mout_pll_shared2_p, + PLL_CON0_PLL_SHARED2, 4, 1), + MUX(CLK_MOUT_PLL_SHARED3, "mout_pll_shared3", mout_pll_shared3_p, + PLL_CON0_PLL_SHARED3, 4, 1), + MUX(CLK_MOUT_PLL_SHARED4, "mout_pll_shared4", mout_pll_shared4_p, + PLL_CON0_PLL_SHARED4, 4, 1), + MUX(CLK_MOUT_CP2AP_MIF_CLK_USER, "mout_cp2ap_mif_clk_user", + mout_cp2ap_mif_clk_user_p, PLL_CON0_MUX_CP2AP_MIF_CLK_USER, 4, 1), + MUX(CLK_MOUT_CMU_ABOX_CPUABOX, "mout_cmu_abox_cpuabox", + mout_cmu_abox_cpuabox_p, CLK_CON_MUX_MUX_CLKCMU_ABOX_CPUABOX, + 0, 2), + MUX(CLK_MOUT_CMU_APM_BUS, "mout_cmu_apm_bus", mout_cmu_apm_bus_p, + CLK_CON_MUX_MUX_CLKCMU_APM_BUS, 0, 1), + MUX(CLK_MOUT_CMU_BUS1_BUS, "mout_cmu_bus1_bus", mout_cmu_bus1_bus_p, + CLK_CON_MUX_MUX_CLKCMU_BUS1_BUS, 0, 2), + MUX(CLK_MOUT_CMU_BUSC_BUS, "mout_cmu_busc_bus", mout_cmu_busc_bus_p, + CLK_CON_MUX_MUX_CLKCMU_BUSC_BUS, 0, 3), + MUX(CLK_MOUT_CMU_BUSC_BUSPHSI2C, "mout_cmu_busc_busphsi2c", + mout_cmu_busc_busphsi2c_p, CLK_CON_MUX_MUX_CLKCMU_BUSC_BUSPHSI2C, + 0, 2), + MUX(CLK_MOUT_CMU_CAM_BUS, "mout_cmu_cam_bus", mout_cmu_cam_bus_p, + CLK_CON_MUX_MUX_CLKCMU_CAM_BUS, 0, 2), + MUX(CLK_MOUT_CMU_CAM_TPU0, "mout_cmu_cam_tpu0", mout_cmu_cam_tpu0_p, + CLK_CON_MUX_MUX_CLKCMU_CAM_TPU0, 0, 2), + MUX(CLK_MOUT_CMU_CAM_TPU1, "mout_cmu_cam_tpu1", mout_cmu_cam_tpu1_p, + CLK_CON_MUX_MUX_CLKCMU_CAM_TPU1, 0, 2), + MUX(CLK_MOUT_CMU_CAM_VRA, "mout_cmu_cam_vra", mout_cmu_cam_vra_p, + CLK_CON_MUX_MUX_CLKCMU_CAM_VRA, 0, 2), + MUX(CLK_MOUT_CMU_CIS_CLK0, "mout_cmu_cis_clk0", mout_cmu_cis_clk0_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK0, 0, 1), + MUX(CLK_MOUT_CMU_CIS_CLK1, "mout_cmu_cis_clk1", mout_cmu_cis_clk1_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK1, 0, 1), + MUX(CLK_MOUT_CMU_CIS_CLK2, "mout_cmu_cis_clk2", mout_cmu_cis_clk2_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK2, 0, 1), + MUX(CLK_MOUT_CMU_CIS_CLK3, "mout_cmu_cis_clk3", mout_cmu_cis_clk3_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK3, 0, 1), + MUX(CLK_MOUT_CMU_CORE_BUS, "mout_core_bus", mout_core_bus_p, + CLK_CON_MUX_MUX_CLKCMU_CORE_BUS, 0, 3), + MUX(CLK_MOUT_CMU_CPUCL0_SWITCH, "mout_cmu_cpucl0_switch", + mout_cmu_cpucl0_switch_p, CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH, + 0, 2), + MUX(CLK_MOUT_CMU_CPUCL1_SWITCH, "mout_cmu_cpucl1_switch", + mout_cmu_cpucl1_switch_p, CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH, + 0, 2), + MUX(CLK_MOUT_CMU_DBG_BUS, "mout_cmu_dbg_bus", mout_cmu_dbg_bus_p, + CLK_CON_MUX_MUX_CLKCMU_DBG_BUS, 0, 2), + MUX(CLK_MOUT_CMU_DCAM_BUS, "mout_cmu_dcam_bus", mout_cmu_dcam_bus_p, + CLK_CON_MUX_MUX_CLKCMU_DCAM_BUS, 0, 2), + MUX(CLK_MOUT_CMU_DCAM_IMGD, "mout_cmu_dcam_imgd", mout_cmu_dcam_imgd_p, + CLK_CON_MUX_MUX_CLKCMU_DCAM_IMGD, 0, 2), + MUX(CLK_MOUT_CMU_DPU_BUS, "mout_cmu_dpu_bus", mout_cmu_dpu_bus_p, + CLK_CON_MUX_MUX_CLKCMU_DPU_BUS, 0, 3), + MUX(CLK_MOUT_CMU_DROOPDETECTOR, "mout_cmu_droopdetector", + mout_cmu_droopdetector_p, CLK_CON_MUX_MUX_CLKCMU_DROOPDETECTOR, + 0, 2), + MUX(CLK_MOUT_CMU_DSP_BUS, "mout_cmu_dsp_bus", mout_cmu_dsp_bus_p, + CLK_CON_MUX_MUX_CLKCMU_DSP_BUS, 0, 2), + MUX(CLK_MOUT_CMU_FSYS0_BUS, "mout_fsys0_bus", mout_fsys0_bus_p, + CLK_CON_MUX_MUX_CLKCMU_FSYS0_BUS, 0, 2), + MUX(CLK_MOUT_CMU_FSYS0_DPGTC, "mout_fsys0_dpgtc", mout_fsys0_dpgtc_p, + CLK_CON_MUX_MUX_CLKCMU_FSYS0_DPGTC, 0, 2), + MUX(CLK_MOUT_CMU_FSYS0_MMC_EMBD, "mout_fsys0_mmc_embd", + mout_fsys0_mmc_embd_p, CLK_CON_MUX_MUX_CLKCMU_FSYS0_MMC_EMBD, + 0, 3), + MUX(CLK_MOUT_CMU_FSYS0_UFS_EMBD, "mout_fsys0_ufs_embd", + mout_fsys0_ufs_embd_p, CLK_CON_MUX_MUX_CLKCMU_FSYS0_UFS_EMBD, + 0, 2), + MUX(CLK_MOUT_CMU_FSYS0_USBDRD30, "mout_fsys0_usbdrd30", + mout_fsys0_usbdrd30_p, CLK_CON_MUX_MUX_CLKCMU_FSYS0_USBDRD30, + 0, 2), + MUX(CLK_MOUT_CMU_FSYS1_BUS, "mout_cmu_fsys1_bus", mout_cmu_fsys1_bus_p, + CLK_CON_MUX_MUX_CLKCMU_FSYS1_BUS, 0, 1), + MUX(CLK_MOUT_CMU_FSYS1_MMC_CARD, "mout_cmu_fsys1_mmc_card", + mout_cmu_fsys1_mmc_card_p, CLK_CON_MUX_MUX_CLKCMU_FSYS1_MMC_CARD, + 0, 3), + MUX(CLK_MOUT_CMU_FSYS1_PCIE, "mout_cmu_fsys1_pcie", + mout_cmu_fsys1_pcie_p, CLK_CON_MUX_MUX_CLKCMU_FSYS1_PCIE, 0, 1), + MUX(CLK_MOUT_CMU_FSYS1_UFS_CARD, "mout_cmu_fsys1_ufs_card", + mout_cmu_fsys1_ufs_card_p, CLK_CON_MUX_MUX_CLKCMU_FSYS1_UFS_CARD, + 0, 2), + MUX(CLK_MOUT_CMU_G2D_G2D, "mout_cmu_g2d_g2d", mout_cmu_g2d_g2d_p, + CLK_CON_MUX_MUX_CLKCMU_G2D_G2D, 0, 2), + MUX(CLK_MOUT_CMU_G2D_JPEG, "mout_cmu_g2d_jpeg", mout_cmu_g2d_jpeg_p, + CLK_CON_MUX_MUX_CLKCMU_G2D_JPEG, 0, 2), + MUX(CLK_MOUT_CMU_HPM, "mout_cmu_hpm", mout_cmu_hpm_p, + CLK_CON_MUX_MUX_CLKCMU_HPM, 0, 2), + MUX(CLK_MOUT_CMU_IMEM_BUS, "mout_cmu_imem_bus", mout_cmu_imem_bus_p, + CLK_CON_MUX_MUX_CLKCMU_IMEM_BUS, 0, 2), + MUX(CLK_MOUT_CMU_ISPHQ_BUS, "mout_cmu_isphq_bus", mout_cmu_isphq_bus_p, + CLK_CON_MUX_MUX_CLKCMU_ISPHQ_BUS, 0, 2), + MUX(CLK_MOUT_CMU_ISPLP_BUS, "mout_cmu_isplp_bus", mout_cmu_isplp_bus_p, + CLK_CON_MUX_MUX_CLKCMU_ISPLP_BUS, 0, 2), + MUX(CLK_MOUT_CMU_IVA_BUS, "mout_cmu_iva_bus", mout_cmu_iva_bus_p, + CLK_CON_MUX_MUX_CLKCMU_IVA_BUS, 0, 2), + MUX(CLK_MOUT_CMU_MFC_BUS, "mout_cmu_mfc_bus", mout_cmu_mfc_bus_p, + CLK_CON_MUX_MUX_CLKCMU_MFC_BUS, 0, 2), + MUX(CLK_MOUT_CMU_MIF_SWITCH, "mout_cmu_mif_switch", + mout_cmu_mif_switch_p, CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH, 0, 3), + MUX(CLK_MOUT_CMU_PERIC0_BUS, "mout_cmu_peric0_bus", + mout_cmu_peric0_bus_p, CLK_CON_MUX_MUX_CLKCMU_PERIC0_BUS, 0, 1), + MUX(CLK_MOUT_CMU_PERIC0_UART_DBG, "mout_cmu_peric0_uart_dbg", + mout_cmu_peric0_uart_dbg_p, CLK_CON_MUX_MUX_CLKCMU_PERIC0_UART_DBG, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC0_USI00, "mout_cmu_peric0_usi00", + mout_cmu_peric0_usi00_p, CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI00, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC0_USI01, "mout_cmu_peric0_usi01", + mout_cmu_peric0_usi01_p, CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI01, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC0_USI02, "mout_cmu_peric0_usi02", + mout_cmu_peric0_usi02_p, CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI02, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC0_USI03, "mout_cmu_peric0_usi03", + mout_cmu_peric0_usi03_p, CLK_CON_MUX_MUX_CLKCMU_PERIC0_USI03, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_BUS, "mout_cmu_peric1_bus", + mout_cmu_peric1_bus_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_BUS, 0, 1), + MUX(CLK_MOUT_CMU_PERIC1_SPEEDY2, "mout_cmu_peric1_speedy2", + mout_cmu_peric1_speedy2_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPEEDY2, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_SPI_CAM0, "mout_cmu_peric1_spi_cam0", + mout_cmu_peric1_spi_cam0_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPI_CAM0, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_SPI_CAM1, "mout_cmu_peric1_spi_cam1", + mout_cmu_peric1_spi_cam1_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_SPI_CAM1, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_UART_BT, "mout_cmu_peric1_uart_bt", + mout_cmu_peric1_uart_bt_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_UART_BT, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI04, "mout_cmu_peric1_usi04", + mout_cmu_peric1_usi04_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI04, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI05, "mout_cmu_peric1_usi05", + mout_cmu_peric1_usi05_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI05, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI06, "mout_cmu_peric1_usi06", + mout_cmu_peric1_usi06_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI06, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI07, "mout_cmu_peric1_usi07", + mout_cmu_peric1_usi07_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI07, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI08, "mout_cmu_peric1_usi08", + mout_cmu_peric1_usi08_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI08, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI09, "mout_cmu_peric1_usi09", + mout_cmu_peric1_usi09_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI09, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI10, "mout_cmu_peric1_usi10", + mout_cmu_peric1_usi10_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI10, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI11, "mout_cmu_peric1_usi11", + mout_cmu_peric1_usi11_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI11, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI12, "mout_cmu_peric1_usi12", + mout_cmu_peric1_usi12_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI12, + 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_USI13, "mout_cmu_peric1_usi13", + mout_cmu_peric1_usi13_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_USI13, + 0, 2), + MUX(CLK_MOUT_CMU_PERIS_BUS, "mout_cmu_peris_bus", mout_cmu_peris_bus_p, + CLK_CON_MUX_MUX_CLKCMU_PERIS_BUS, 0, 1), + MUX(CLK_MOUT_CMU_SRDZ_BUS, "mout_cmu_srdz_bus", mout_cmu_srdz_bus_p, + CLK_CON_MUX_MUX_CLKCMU_SRDZ_BUS, 0, 2), + MUX(CLK_MOUT_CMU_SRDZ_IMGD, "mout_cmu_srdz_imgd", mout_cmu_srdz_imgd_p, + CLK_CON_MUX_MUX_CLKCMU_SRDZ_IMGD, 0, 2), + MUX(CLK_MOUT_CMU_VPU_BUS, "mout_cmu_vpu_bus", mout_cmu_vpu_bus_p, + CLK_CON_MUX_MUX_CLKCMU_VPU_BUS, 0, 2), +}; + +static const struct samsung_div_clock top_div_clks[] __initconst = { + DIV(CLK_DOUT_CMU_ABOX_CPUABOX, "dout_cmu_cmu_abox_cpuabox", + "gout_cmu_abox_cpuabox", CLK_CON_DIV_CLKCMU_ABOX_CPUABOX, 0, 3), + DIV(CLK_DOUT_CMU_APM_BUS, "dout_cmu_apm_bus", "gout_cmu_apm_bus", + CLK_CON_DIV_CLKCMU_APM_BUS, 0, 3), + DIV(CLK_DOUT_CMU_BUS1_BUS, "dout_cmu_bus1_bus", "gout_cmu_bus1_bus", + CLK_CON_DIV_CLKCMU_BUS1_BUS, 0, 4), + DIV(CLK_DOUT_CMU_BUSC_BUS, "dout_cmu_busc_bus", + "gout_cmu_clkcmu_busc_bus", CLK_CON_DIV_CLKCMU_BUSC_BUS, 0, 4), + DIV(CLK_DOUT_CMU_BUSC_BUSPHSI2C, "dout_cmu_busc_busphsi2c", + "gout_cmu_busc_busphsi2c", CLK_CON_DIV_CLKCMU_BUSC_BUSPHSI2C, + 0, 4), + DIV(CLK_DOUT_CMU_CAM_BUS, "dout_cmu_cam_bus", "gout_cmu_cam_bus", + CLK_CON_DIV_CLKCMU_CAM_BUS, 0, 4), + DIV(CLK_DOUT_CMU_CAM_TPU0, "dout_cmu_cam_tpu0", "gout_cmu_cam_tpu0", + CLK_CON_DIV_CLKCMU_CAM_TPU0, 0, 4), + DIV(CLK_DOUT_CMU_CAM_TPU1, "dout_cmu_cam_tpu1", "gout_cmu_cam_tpu1", + CLK_CON_DIV_CLKCMU_CAM_TPU1, 0, 4), + DIV(CLK_DOUT_CMU_CAM_VRA, "dout_cmu_cam_vra", "gout_cmu_cam_vra", + CLK_CON_DIV_CLKCMU_CAM_VRA, 0, 4), + DIV(CLK_DOUT_CMU_CIS_CLK0, "dout_cmu_cis_clk0", "gout_cmu_cis_clk0", + CLK_CON_DIV_CLKCMU_CIS_CLK0, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK1, "dout_cmu_cis_clk1", "gout_cmu_cis_clk1", + CLK_CON_DIV_CLKCMU_CIS_CLK1, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK2, "dout_cmu_cis_clk2", "gout_cmu_cis_clk2", + CLK_CON_DIV_CLKCMU_CIS_CLK2, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK3, "dout_cmu_cis_clk3", "gout_cmu_cis_clk3", + CLK_CON_DIV_CLKCMU_CIS_CLK3, 0, 5), + DIV(CLK_DOUT_CMU_CORE_BUS, "dout_cmu_core_bus", "gout_cmu_core_bus", + CLK_CON_DIV_CLKCMU_CORE_BUS, 0, 4), + DIV(CLK_DOUT_CMU_CPUCL0_SWITCH, "dout_cmu_cpucl0_switch", + "gout_cmu_cpucl0_switch", CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH, 0, 3), + DIV(CLK_DOUT_CMU_CPUCL1_SWITCH, "dout_cmu_cpucl1_switch", + "gout_cmu_cpucl1_switch", CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH, 0, 3), + DIV(CLK_DOUT_CMU_DBG_BUS, "dout_cmu_dbg_bus", "gout_cmu_dbg_bus", + CLK_CON_DIV_CLKCMU_DBG_BUS, 0, 4), + DIV(CLK_DOUT_CMU_DCAM_BUS, "dout_cmu_dcam_bus", "gout_cmu_dcam_bus", + CLK_CON_DIV_CLKCMU_DCAM_BUS, 0, 4), + DIV(CLK_DOUT_CMU_DCAM_IMGD, "dout_cmu_dcam_imgd", "gout_cmu_dcam_imgd", + CLK_CON_DIV_CLKCMU_DCAM_IMGD, 0, 4), + DIV(CLK_DOUT_CMU_DPU_BUS, "dout_cmu_dpu_bus", "gout_cmu_dpu_bus", + CLK_CON_DIV_CLKCMU_DPU_BUS, 0, 4), + DIV(CLK_DOUT_CMU_DSP_BUS, "dout_cmu_dsp_bus", "gout_cmu_dsp_bus", + CLK_CON_DIV_CLKCMU_DSP_BUS, 0, 4), + DIV(CLK_DOUT_CMU_FSYS0_BUS, "dout_cmu_fsys0_bus", "gout_cmu_fsys0_bus", + CLK_CON_DIV_CLKCMU_FSYS0_BUS, 0, 4), + DIV(CLK_DOUT_CMU_FSYS0_DPGTC, "dout_cmu_fsys0_dpgtc", + "gout_cmu_fsys0_dpgtc", CLK_CON_DIV_CLKCMU_FSYS0_DPGTC, 0, 3), + DIV(CLK_DOUT_CMU_FSYS0_MMC_EMBD, "dout_cmu_fsys0_mmc_embd", + "gout_cmu_fsys0_mmc_embd", CLK_CON_DIV_CLKCMU_FSYS0_MMC_EMBD, + 0, 9), + DIV(CLK_DOUT_CMU_FSYS0_UFS_EMBD, "dout_cmu_fsys0_ufs_embd", + "gout_cmu_fsys0_ufs_embd", CLK_CON_DIV_CLKCMU_FSYS0_UFS_EMBD, + 0, 3), + DIV(CLK_DOUT_CMU_FSYS0_USBDRD30, "dout_cmu_fsys0_usbdrd30", + "gout_cmu_fsys0_usbdrd30", CLK_CON_DIV_CLKCMU_FSYS0_USBDRD30, + 0, 4), + DIV(CLK_DOUT_CMU_FSYS1_BUS, "dout_cmu_fsys1_bus", "gout_cmu_fsys1_bus", + CLK_CON_DIV_CLKCMU_FSYS1_BUS, 0, 4), + DIV(CLK_DOUT_CMU_FSYS1_MMC_CARD, "dout_cmu_fsys1_mmc_card", + "gout_cmu_fsys1_mmc_card", CLK_CON_DIV_CLKCMU_FSYS1_MMC_CARD, + 0, 9), + DIV(CLK_DOUT_CMU_FSYS1_UFS_CARD, "dout_cmu_fsys1_ufs_card", + "gout_cmu_fsys1_ufs_card", CLK_CON_DIV_CLKCMU_FSYS1_UFS_CARD, + 0, 4), + DIV(CLK_DOUT_CMU_G2D_G2D, "dout_cmu_g2d_g2d", "gout_cmu_g2d_g2d", + CLK_CON_DIV_CLKCMU_G2D_G2D, 0, 4), + DIV(CLK_DOUT_CMU_G2D_JPEG, "dout_cmu_g2d_jpeg", "gout_cmu_g2d_jpeg", + CLK_CON_DIV_CLKCMU_G2D_JPEG, 0, 4), + DIV(CLK_DOUT_CMU_G3D_SWITCH, "dout_cmu_g3d_switch", + "gout_cmu_g3d_switch", CLK_CON_DIV_CLKCMU_G3D_SWITCH, 0, 3), + DIV(CLK_DOUT_CMU_HPM, "dout_cmu_hpm", "gout_cmu_hpm", + CLK_CON_DIV_CLKCMU_HPM, 0, 2), + DIV(CLK_DOUT_CMU_IMEM_BUS, "dout_cmu_imem_bus", "gout_cmu_imem_bus", + CLK_CON_DIV_CLKCMU_IMEM_BUS, 0, 4), + DIV(CLK_DOUT_CMU_ISPHQ_BUS, "dout_cmu_isphq_bus", "gout_cmu_isphq_bus", + CLK_CON_DIV_CLKCMU_ISPHQ_BUS, 0, 4), + DIV(CLK_DOUT_CMU_ISPLP_BUS, "dout_cmu_isplp_bus", "gout_cmu_isplp_bus", + CLK_CON_DIV_CLKCMU_ISPLP_BUS, 0, 4), + DIV(CLK_DOUT_CMU_IVA_BUS, "dout_cmu_iva_bus", "gout_cmu_iva_bus", + CLK_CON_DIV_CLKCMU_IVA_BUS, 0, 4), + DIV(CLK_DOUT_CMU_MFC_BUS, "dout_cmu_mfc_bus", "gout_cmu_mfc_bus", + CLK_CON_DIV_CLKCMU_MFC_BUS, 0, 4), + DIV(CLK_DOUT_CMU_MODEM_SHARED0, "dout_cmu_modem_shared0", + "gout_cmu_modem_shared0", CLK_CON_DIV_CLKCMU_MODEM_SHARED0, 0, 3), + DIV(CLK_DOUT_CMU_MODEM_SHARED1, "dout_cmu_modem_shared1", + "gout_cmu_modem_shared1", CLK_CON_DIV_CLKCMU_MODEM_SHARED1, 0, 3), + DIV(CLK_DOUT_CMU_PERIC0_BUS, "dout_cmu_peric0_bus", + "gout_cmu_peric0_bus", CLK_CON_DIV_CLKCMU_PERIC0_BUS, 0, 4), + DIV(CLK_DOUT_CMU_PERIC0_UART_DBG, "dout_cmu_peric0_uart_dbg", + "gout_cmu_peric0_uart_dbg", CLK_CON_DIV_CLKCMU_PERIC0_UART_DBG, + 0, 4), + DIV(CLK_DOUT_CMU_PERIC0_USI00, "dout_cmu_peric0_usi00", + "gout_cmu_peric0_usi00", CLK_CON_DIV_CLKCMU_PERIC0_USI00, 0, 4), + DIV(CLK_DOUT_CMU_PERIC0_USI01, "dout_cmu_peric0_usi01", + "gout_cmu_peric0_usi01", CLK_CON_DIV_CLKCMU_PERIC0_USI01, 0, 4), + DIV(CLK_DOUT_CMU_PERIC0_USI02, "dout_cmu_peric0_usi02", + "gout_cmu_peric0_usi02", CLK_CON_DIV_CLKCMU_PERIC0_USI02, 0, 4), + DIV(CLK_DOUT_CMU_PERIC0_USI03, "dout_cmu_peric0_usi03", + "gout_cmu_peric0_usi03", CLK_CON_DIV_CLKCMU_PERIC0_USI03, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_BUS, "dout_cmu_peric1_bus", + "gout_cmu_peric1_bus", CLK_CON_DIV_CLKCMU_PERIC1_BUS, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_SPEEDY2, "dout_cmu_peric1_speedy2", + "gout_cmu_peric1_speedy2", CLK_CON_DIV_CLKCMU_PERIC1_SPEEDY2, + 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_SPI_CAM0, "dout_cmu_peric1_spi_cam0", + "gout_cmu_peric1_spi_cam0", CLK_CON_DIV_CLKCMU_PERIC1_SPI_CAM0, + 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_SPI_CAM1, "dout_cmu_peric1_spi_cam1", + "gout_cmu_peric1_spi_cam1", CLK_CON_DIV_CLKCMU_PERIC1_SPI_CAM1, + 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_UART_BT, "dout_cmu_peric1_uart_bt", + "gout_cmu_peric1_uart_bt", CLK_CON_DIV_CLKCMU_PERIC1_UART_BT, + 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI04, "dout_cmu_peric1_usi04", + "gout_cmu_peric1_usi04", CLK_CON_DIV_CLKCMU_PERIC1_USI04, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI05, "dout_cmu_peric1_usi05", + "gout_cmu_peric1_usi05", CLK_CON_DIV_CLKCMU_PERIC1_USI05, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI06, "dout_cmu_peric1_usi06", + "gout_cmu_peric1_usi06", CLK_CON_DIV_CLKCMU_PERIC1_USI06, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI07, "dout_cmu_peric1_usi07", + "gout_cmu_peric1_usi07", CLK_CON_DIV_CLKCMU_PERIC1_USI07, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI08, "dout_cmu_peric1_usi08", + "gout_cmu_peric1_usi08", CLK_CON_DIV_CLKCMU_PERIC1_USI08, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI09, "dout_cmu_peric1_usi09", + "gout_cmu_peric1_usi09", CLK_CON_DIV_CLKCMU_PERIC1_USI09, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI10, "dout_cmu_peric1_usi10", + "gout_cmu_peric1_usi10", CLK_CON_DIV_CLKCMU_PERIC1_USI10, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI11, "dout_cmu_peric1_usi11", + "gout_cmu_peric1_usi11", CLK_CON_DIV_CLKCMU_PERIC1_USI11, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI12, "dout_cmu_peric1_usi12", + "gout_cmu_peric1_usi12", CLK_CON_DIV_CLKCMU_PERIC1_USI12, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_USI13, "dout_cmu_peric1_usi13", + "gout_cmu_peric1_usi13", CLK_CON_DIV_CLKCMU_PERIC1_USI13, 0, 4), + DIV(CLK_DOUT_CMU_PERIS_BUS, "dout_cmu_peris_bus", "gout_cmu_peris_bus", + CLK_CON_DIV_CLKCMU_PERIS_BUS, 0, 4), + DIV(CLK_DOUT_CMU_SRDZ_BUS, "dout_cmu_srdz_bus", "gout_cmu_srdz_bus", + CLK_CON_DIV_CLKCMU_SRDZ_BUS, 0, 4), + DIV(CLK_DOUT_CMU_SRDZ_IMGD, "dout_cmu_srdz_imgd", "gout_cmu_srdz_imgd", + CLK_CON_DIV_CLKCMU_SRDZ_IMGD, 0, 4), + DIV(CLK_DOUT_CMU_VPU_BUS, "dout_cmu_vpu_bus", "gout_cmu_vpu_bus", + CLK_CON_DIV_CLKCMU_VPU_BUS, 0, 4), +}; + +static const struct samsung_fixed_factor_clock top_fixed_factor_clks[] __initconst = { + FFACTOR(CLK_DOUT_CMU_SHARED0_DIV2, "dout_cmu_shared0_div2", + "mout_pll_shared0", 1, 2, 0), + FFACTOR(CLK_DOUT_CMU_SHARED0_DIV4, "dout_cmu_shared0_div4", + "mout_pll_shared0", 1, 4, 0), + FFACTOR(CLK_DOUT_CMU_SHARED1_DIV2, "dout_cmu_shared1_div2", + "mout_pll_shared1", 1, 2, 0), + FFACTOR(CLK_DOUT_CMU_SHARED1_DIV4, "dout_cmu_shared1_div4", + "mout_pll_shared1", 1, 4, 0), + FFACTOR(CLK_DOUT_CMU_SHARED2_DIV2, "dout_cmu_shared2_div2", + "mout_pll_shared2", 1, 2, 0), + FFACTOR(CLK_DOUT_CMU_SHARED3_DIV2, "dout_cmu_shared3_div2", + "mout_pll_shared3", 1, 2, 0), + FFACTOR(CLK_DOUT_CMU_SHARED4_DIV2, "dout_cmu_shared4_div2", + "mout_pll_shared4", 1, 2, 0), + FFACTOR(CLK_DOUT_CMU_FSYS1_PCIE, "dout_cmu_fsys1_pcie", + "gout_cmu_fsys1_pcie", 1, 8, 0), + FFACTOR(CLK_DOUT_CMU_CP2AP_MIF_CLK_DIV2, "dout_cmu_cp2ap_mif_clk_div2", + "mout_cp2ap_mif_clk_user", 1, 2, 0), + FFACTOR(CLK_DOUT_CMU_CMU_OTP, "dout_cmu_cmu_otp", "oscclk", 1, 8, 0), +}; + +static const struct samsung_gate_clock top_gate_clks[] __initconst = { + GATE(CLK_GOUT_CMU_DROOPDETECTOR, "gout_droopdetector", + "mout_cmu_droopdetector", CLK_CON_GAT_CLKCMU_DROOPDETECTOR, + 21, 0, 0), + GATE(CLK_GOUT_CMU_MIF_SWITCH, "gout_cmu_mif_switch", + "mout_cmu_mif_switch", CLK_CON_GAT_CLKCMU_MIF_SWITCH, 21, 0, 0), + GATE(CLK_GOUT_CMU_ABOX_CPUABOX, "gout_cmu_abox_cpuabox", + "mout_cmu_abox_cpuabox", CLK_CON_GAT_GATE_CLKCMU_ABOX_CPUABOX, + 21, 0, 0), + GATE(CLK_GOUT_CMU_APM_BUS, "gout_cmu_apm_bus", "mout_cmu_apm_bus", + CLK_CON_GAT_GATE_CLKCMU_APM_BUS, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_BUS1_BUS, "gout_cmu_bus1_bus", "mout_cmu_bus1_bus", + CLK_CON_GAT_GATE_CLKCMU_BUS1_BUS, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_BUSC_BUS, "gout_cmu_busc_bus", "mout_cmu_busc_bus", + CLK_CON_GAT_GATE_CLKCMU_BUSC_BUS, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_BUSC_BUSPHSI2C, "gout_cmu_busc_busphsi2c", + "mout_cmu_busc_busphsi2c", CLK_CON_GAT_GATE_CLKCMU_BUSC_BUSPHSI2C, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_CAM_BUS, "gout_cmu_cam_bus", "mout_cmu_cam_bus", + CLK_CON_GAT_GATE_CLKCMU_CAM_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_CAM_TPU0, "gout_cmu_cam_tpu0", "mout_cmu_cam_tpu0", + CLK_CON_GAT_GATE_CLKCMU_CAM_TPU0, 21, 0, 0), + GATE(CLK_GOUT_CMU_CAM_TPU1, "gout_cmu_cam_tpu1", "mout_cmu_cam_tpu1", + CLK_CON_GAT_GATE_CLKCMU_CAM_TPU1, 21, 0, 0), + GATE(CLK_GOUT_CMU_CAM_VRA, "gout_cmu_cam_vra", "mout_cmu_cam_vra", + CLK_CON_GAT_GATE_CLKCMU_CAM_VRA, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK0, "gout_cmu_cis_clk0", "mout_cmu_cis_clk0", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK0, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK1, "gout_cmu_cis_clk1", "mout_cmu_cis_clk1", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK1, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK2, "gout_cmu_cis_clk2", "mout_cmu_cis_clk2", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK2, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK3, "gout_cmu_cis_clk3", "mout_cmu_cis_clk3", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK3, 21, 0, 0), + GATE(CLK_GOUT_CMU_CORE_BUS, "gout_cmu_core_bus", "mout_core_bus", + CLK_CON_GAT_GATE_CLKCMU_CORE_BUS, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_CPUCL0_SWITCH, "gout_cmu_cpucl0_switch", + "mout_cmu_cpucl0_switch", CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_CPUCL1_SWITCH, "gout_cmu_cpucl1_switch", + "mout_cmu_cpucl1_switch", CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_DBG_BUS, "gout_cmu_dbg_bus", "mout_cmu_dbg_bus", + CLK_CON_GAT_GATE_CLKCMU_DBG_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_DCAM_BUS, "gout_cmu_dcam_bus", "mout_cmu_dcam_bus", + CLK_CON_GAT_GATE_CLKCMU_DCAM_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_DCAM_IMGD, "gout_cmu_dcam_imgd", + "mout_cmu_dcam_imgd", CLK_CON_GAT_GATE_CLKCMU_DCAM_IMGD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_DPU_BUS, "gout_cmu_dpu_bus", "mout_cmu_dpu_bus", + CLK_CON_GAT_GATE_CLKCMU_DPU_BUS, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_DSP_BUS, "gout_cmu_dsp_bus", "mout_cmu_dsp_bus", + CLK_CON_GAT_GATE_CLKCMU_DSP_BUS, 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_CMU_FSYS0_BUS, "gout_cmu_fsys0_bus", "mout_fsys0_bus", + CLK_CON_GAT_GATE_CLKCMU_FSYS0_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS0_DPGTC, "gout_cmu_fsys0_dpgtc", + "mout_fsys0_dpgtc", CLK_CON_GAT_GATE_CLKCMU_FSYS0_DPGTC, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS0_MMC_EMBD, "gout_cmu_fsys0_mmc_embd", + "mout_fsys0_mmc_embd", CLK_CON_GAT_GATE_CLKCMU_FSYS0_MMC_EMBD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS0_UFS_EMBD, "gout_cmu_fsys0_ufs_embd", + "mout_fsys0_ufs_embd", CLK_CON_GAT_GATE_CLKCMU_FSYS0_UFS_EMBD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS0_USBDRD30, "gout_cmu_fsys0_usbdrd30", + "mout_fsys0_usbdrd30", CLK_CON_GAT_GATE_CLKCMU_FSYS0_USBDRD30, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS1_BUS, "gout_cmu_fsys1_bus", + "mout_cmu_fsys1_bus", CLK_CON_GAT_GATE_CLKCMU_FSYS1_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS1_MMC_CARD, "gout_cmu_fsys1_mmc_card", + "mout_cmu_fsys1_mmc_card", CLK_CON_GAT_GATE_CLKCMU_FSYS1_MMC_CARD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS1_PCIE, "gout_cmu_fsys1_pcie", + "mout_cmu_fsys1_pcie", CLK_CON_GAT_GATE_CLKCMU_FSYS1_PCIE, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS1_UFS_CARD, "gout_cmu_fsys1_ufs_card", + "mout_cmu_fsys1_ufs_card", CLK_CON_GAT_GATE_CLKCMU_FSYS1_UFS_CARD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_G2D_G2D, "gout_cmu_g2d_g2d", "mout_cmu_g2d_g2d", + CLK_CON_GAT_GATE_CLKCMU_G2D_G2D, 21, 0, 0), + GATE(CLK_GOUT_CMU_G2D_JPEG, "gout_cmu_g2d_jpeg", "mout_cmu_g2d_jpeg", + CLK_CON_GAT_GATE_CLKCMU_G2D_JPEG, 21, 0, 0), + GATE(CLK_GOUT_CMU_G3D_SWITCH, "gout_cmu_g3d_switch", + "fout_shared2_pll", CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH, 21, 0, 0), + GATE(CLK_GOUT_CMU_HPM, "gout_cmu_hpm", "mout_cmu_hpm", + CLK_CON_GAT_GATE_CLKCMU_HPM, 21, 0, 0), + GATE(CLK_GOUT_CMU_IMEM_BUS, "gout_cmu_imem_bus", "mout_cmu_imem_bus", + CLK_CON_GAT_GATE_CLKCMU_IMEM_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_ISPHQ_BUS, "gout_cmu_isphq_bus", + "mout_cmu_isphq_bus", CLK_CON_GAT_GATE_CLKCMU_ISPHQ_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_ISPLP_BUS, "gout_cmu_isplp_bus", + "mout_cmu_isplp_bus", CLK_CON_GAT_GATE_CLKCMU_ISPLP_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_IVA_BUS, "gout_cmu_iva_bus", "mout_cmu_iva_bus", + CLK_CON_GAT_GATE_CLKCMU_IVA_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_MFC_BUS, "gout_cmu_mfc_bus", "mout_cmu_mfc_bus", + CLK_CON_GAT_GATE_CLKCMU_MFC_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_MODEM_SHARED0, "gout_cmu_modem_shared0", + "dout_cmu_shared0_div2", CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED0, + 21, 0, 0), + GATE(CLK_GOUT_CMU_MODEM_SHARED1, "gout_cmu_modem_shared1", + "fout_shared2_pll", CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED1, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC0_BUS, "gout_cmu_peric0_bus", + "mout_cmu_peric0_bus", CLK_CON_GAT_GATE_CLKCMU_PERIC0_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC0_UART_DBG, "gout_cmu_peric0_uart_dbg", + "mout_cmu_peric0_uart_dbg", + CLK_CON_GAT_GATE_CLKCMU_PERIC0_UART_DBG, 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC0_USI00, "gout_cmu_peric0_usi00", + "mout_cmu_peric0_usi00", CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI00, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC0_USI01, "gout_cmu_peric0_usi01", + "mout_cmu_peric0_usi01", CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI01, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC0_USI02, "gout_cmu_peric0_usi02", + "mout_cmu_peric0_usi02", CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI02, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC0_USI03, "gout_cmu_peric0_usi03", + "mout_cmu_peric0_usi03", CLK_CON_GAT_GATE_CLKCMU_PERIC0_USI03, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_BUS, "gout_cmu_peric1_bus", + "mout_cmu_peric1_bus", CLK_CON_GAT_GATE_CLKCMU_PERIC1_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_SPEEDY2, "gout_cmu_peric1_speedy2", + "mout_cmu_peric1_speedy2", CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPEEDY2, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_SPI_CAM0, "gout_cmu_peric1_spi_cam0", + "mout_cmu_peric1_spi_cam0", + CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPI_CAM0, 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_SPI_CAM1, "gout_cmu_peric1_spi_cam1", + "mout_cmu_peric1_spi_cam1", + CLK_CON_GAT_GATE_CLKCMU_PERIC1_SPI_CAM1, 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_UART_BT, "gout_cmu_peric1_uart_bt", + "mout_cmu_peric1_uart_bt", CLK_CON_GAT_GATE_CLKCMU_PERIC1_UART_BT, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI04, "gout_cmu_peric1_usi04", + "mout_cmu_peric1_usi04", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI04, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI05, "gout_cmu_peric1_usi05", + "mout_cmu_peric1_usi05", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI05, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI06, "gout_cmu_peric1_usi06", + "mout_cmu_peric1_usi06", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI06, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI07, "gout_cmu_peric1_usi07", + "mout_cmu_peric1_usi07", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI07, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI08, "gout_cmu_peric1_usi08", + "mout_cmu_peric1_usi08", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI08, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI09, "gout_cmu_peric1_usi09", + "mout_cmu_peric1_usi09", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI09, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI10, "gout_cmu_peric1_usi10", + "mout_cmu_peric1_usi10", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI10, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI11, "gout_cmu_peric1_usi11", + "mout_cmu_peric1_usi11", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI11, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI12, "gout_cmu_peric1_usi12", + "mout_cmu_peric1_usi12", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI12, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_USI13, "gout_cmu_peric1_usi13", + "mout_cmu_peric1_usi13", CLK_CON_GAT_GATE_CLKCMU_PERIC1_USI13, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIS_BUS, "gout_cmu_peris_bus", + "mout_cmu_peris_bus", CLK_CON_GAT_GATE_CLKCMU_PERIS_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_SRDZ_BUS, "gout_cmu_srdz_bus", "mout_cmu_srdz_bus", + CLK_CON_GAT_GATE_CLKCMU_SRDZ_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_SRDZ_IMGD, "gout_cmu_srdz_imgd", + "mout_cmu_srdz_imgd", CLK_CON_GAT_GATE_CLKCMU_SRDZ_IMGD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_VPU_BUS, "gout_cmu_vpu_bus", "mout_cmu_vpu_bus", + CLK_CON_GAT_GATE_CLKCMU_VPU_BUS, 21, 0, 0), +}; + +static const struct samsung_cmu_info top_cmu_info __initconst = { + .pll_clks = top_pll_clks, + .nr_pll_clks = ARRAY_SIZE(top_pll_clks), + .mux_clks = top_mux_clks, + .nr_mux_clks = ARRAY_SIZE(top_mux_clks), + .div_clks = top_div_clks, + .nr_div_clks = ARRAY_SIZE(top_div_clks), + .fixed_factor_clks = top_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(top_fixed_factor_clks), + .gate_clks = top_gate_clks, + .nr_gate_clks = ARRAY_SIZE(top_gate_clks), + .nr_clk_ids = CLKS_NR_TOP, + .clk_regs = top_clk_regs, + .nr_clk_regs = ARRAY_SIZE(top_clk_regs), +}; + +static void __init exynos8895_cmu_top_init(struct device_node *np) +{ + exynos_arm64_register_cmu(NULL, np, &top_cmu_info); +} + +/* Register CMU_TOP early, as it's a dependency for other early domains */ +CLK_OF_DECLARE(exynos8895_cmu_top, "samsung,exynos8895-cmu-top", + exynos8895_cmu_top_init); + +/* ---- CMU_PERIS ----------------------------------------------------------- */ + +/* Register Offset definitions for CMU_PERIS (0x10010000) */ +#define PLL_CON0_MUX_CLKCMU_PERIS_BUS_USER 0x0100 +#define PLL_CON2_MUX_CLKCMU_PERIS_BUS_USER 0x0108 +#define CLK_CON_MUX_MUX_CLK_PERIS_GIC 0x1000 +#define CLK_CON_GAT_CLK_BLK_PERIS_UID_PERIS_CMU_PERIS_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_AD_AXI_P_PERIS_IPCLKPORT_ACLKM 0x2010 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_AD_AXI_P_PERIS_IPCLKPORT_ACLKS 0x2014 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_AXI2APB_PERISP0_IPCLKPORT_ACLK 0x2018 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_AXI2APB_PERISP1_IPCLKPORT_ACLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_BUSIF_TMU_IPCLKPORT_PCLK 0x2020 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_GIC_IPCLKPORT_CLK 0x2024 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_LHM_AXI_P_PERIS_IPCLKPORT_I_CLK 0x2028 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_MCT_IPCLKPORT_PCLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_OTP_CON_BIRA_IPCLKPORT_PCLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_OTP_CON_TOP_IPCLKPORT_PCLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_PMU_PERIS_IPCLKPORT_PCLK 0x2038 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_RSTNSYNC_CLK_PERIS_BUSP_IPCLKPORT_CLK 0x203c +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_RSTNSYNC_CLK_PERIS_GIC_IPCLKPORT_CLK 0x2040 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_SYSREG_PERIS_IPCLKPORT_PCLK 0x2044 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC00_IPCLKPORT_PCLK 0x2048 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC01_IPCLKPORT_PCLK 0x204c +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC02_IPCLKPORT_PCLK 0x2050 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC03_IPCLKPORT_PCLK 0x2054 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC04_IPCLKPORT_PCLK 0x2058 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC05_IPCLKPORT_PCLK 0x205c +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC06_IPCLKPORT_PCLK 0x2060 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC07_IPCLKPORT_PCLK 0x2064 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC08_IPCLKPORT_PCLK 0x2068 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC09_IPCLKPORT_PCLK 0x206c +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC10_IPCLKPORT_PCLK 0x2070 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC11_IPCLKPORT_PCLK 0x2074 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC12_IPCLKPORT_PCLK 0x2078 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC13_IPCLKPORT_PCLK 0x207c +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC14_IPCLKPORT_PCLK 0x2080 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC15_IPCLKPORT_PCLK 0x2084 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_WDT_CLUSTER0_IPCLKPORT_PCLK 0x2088 +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_WDT_CLUSTER1_IPCLKPORT_PCLK 0x208c +#define CLK_CON_GAT_GOUT_BLK_PERIS_UID_XIU_P_PERIS_IPCLKPORT_ACLK 0x2090 + +static const unsigned long peris_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_PERIS_BUS_USER, + PLL_CON2_MUX_CLKCMU_PERIS_BUS_USER, + CLK_CON_MUX_MUX_CLK_PERIS_GIC, + CLK_CON_GAT_CLK_BLK_PERIS_UID_PERIS_CMU_PERIS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_AD_AXI_P_PERIS_IPCLKPORT_ACLKM, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_AD_AXI_P_PERIS_IPCLKPORT_ACLKS, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_AXI2APB_PERISP0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_AXI2APB_PERISP1_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_BUSIF_TMU_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_GIC_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_LHM_AXI_P_PERIS_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_MCT_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_OTP_CON_BIRA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_OTP_CON_TOP_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_PMU_PERIS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_RSTNSYNC_CLK_PERIS_BUSP_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_RSTNSYNC_CLK_PERIS_GIC_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_SYSREG_PERIS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC00_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC01_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC02_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC03_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC04_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC05_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC06_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC07_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC08_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC09_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC10_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC11_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC12_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC13_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC14_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC15_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_WDT_CLUSTER0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_WDT_CLUSTER1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIS_UID_XIU_P_PERIS_IPCLKPORT_ACLK, +}; + +/* List of parent clocks for Muxes in CMU_PERIS */ +PNAME(mout_peris_bus_user_p) = { "oscclk", "dout_cmu_peris_bus" }; +PNAME(mout_peris_gic_p) = { "oscclk", "mout_peris_bus_user" }; + +static const struct samsung_mux_clock peris_mux_clks[] __initconst = { + MUX(CLK_MOUT_PERIS_BUS_USER, "mout_peris_bus_user", + mout_peris_bus_user_p, PLL_CON0_MUX_CLKCMU_PERIS_BUS_USER, 4, 1), + MUX(CLK_MOUT_PERIS_GIC, "mout_peris_gic", + mout_peris_gic_p, CLK_CON_MUX_MUX_CLK_PERIS_GIC, 0, 5), +}; + +static const struct samsung_gate_clock peris_gate_clks[] __initconst = { + GATE(CLK_GOUT_PERIS_CMU_PERIS_PCLK, "gout_peris_cmu_peris_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_CLK_BLK_PERIS_UID_PERIS_CMU_PERIS_IPCLKPORT_PCLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIS_AD_AXI_P_PERIS_ACLKM, + "gout_peris_ad_axi_p_peris_aclkm", "mout_peris_gic", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_AD_AXI_P_PERIS_IPCLKPORT_ACLKM, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIS_AD_AXI_P_PERIS_ACLKS, + "gout_peris_ad_axi_p_peris_aclks", "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_AD_AXI_P_PERIS_IPCLKPORT_ACLKS, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIS_AXI2APB_PERISP0_ACLK, + "gout_peris_axi2apb_perisp0_aclk", "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_AXI2APB_PERISP0_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIS_AXI2APB_PERISP1_ACLK, + "gout_peris_axi2apb_perisp1_aclk", "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_AXI2APB_PERISP1_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIS_BUSIF_TMU_PCLK, "gout_peris_busif_tmu_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_BUSIF_TMU_IPCLKPORT_PCLK, + 21, 0, 0), + /* GIC (interrupt controller) clock must be always running */ + GATE(CLK_GOUT_PERIS_GIC_CLK, "gout_peris_gic_clk", + "mout_peris_gic", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_GIC_IPCLKPORT_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIS_LHM_AXI_P_PERIS_I_CLK, + "gout_peris_lhm_axi_p_peris_i_clk", "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_LHM_AXI_P_PERIS_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIS_MCT_PCLK, "gout_peris_mct_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_MCT_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_OTP_CON_BIRA_PCLK, "gout_peris_otp_con_bira_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_OTP_CON_BIRA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIS_OTP_CON_TOP_PCLK, "gout_peris_otp_con_top_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_OTP_CON_TOP_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIS_PMU_PERIS_PCLK, "gout_peris_pmu_peris_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_PMU_PERIS_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIS_RSTNSYNC_CLK_PERIS_BUSP_CLK, + "gout_peris_rstnsync_clk_peris_busp_clk", "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_RSTNSYNC_CLK_PERIS_BUSP_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIS_RSTNSYNC_CLK_PERIS_GIC_CLK, + "gout_peris_rstnsync_clk_peris_gic_clk", "mout_peris_gic", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_RSTNSYNC_CLK_PERIS_GIC_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIS_SYSREG_PERIS_PCLK, "gout_peris_sysreg_peris_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_SYSREG_PERIS_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC00_PCLK, "gout_peris_tzpc00_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC00_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC01_PCLK, "gout_peris_tzpc01_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC01_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC02_PCLK, "gout_peris_tzpc02_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC02_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC03_PCLK, "gout_peris_tzpc03_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC03_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC04_PCLK, "gout_peris_tzpc04_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC04_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC05_PCLK, "gout_peris_tzpc05_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC05_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC06_PCLK, "gout_peris_tzpc06_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC06_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC07_PCLK, "gout_peris_tzpc07_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC07_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC08_PCLK, "gout_peris_tzpc08_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC08_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC09_PCLK, "gout_peris_tzpc09_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC09_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC10_PCLK, "gout_peris_tzpc10_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC10_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC11_PCLK, "gout_peris_tzpc11_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC11_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC12_PCLK, "gout_peris_tzpc12_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC12_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC13_PCLK, "gout_peris_tzpc13_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC13_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC14_PCLK, "gout_peris_tzpc14_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC14_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_TZPC15_PCLK, "gout_peris_tzpc15_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_TZPC15_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIS_WDT_CLUSTER0_PCLK, "gout_peris_wdt_cluster0_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_WDT_CLUSTER0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIS_WDT_CLUSTER1_PCLK, "gout_peris_wdt_cluster1_pclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_WDT_CLUSTER1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIS_XIU_P_PERIS_ACLK, "gout_peris_xiu_p_peris_aclk", + "mout_peris_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIS_UID_XIU_P_PERIS_IPCLKPORT_ACLK, + 21, CLK_IGNORE_UNUSED, 0), +}; + +static const struct samsung_cmu_info peris_cmu_info __initconst = { + .mux_clks = peris_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peris_mux_clks), + .gate_clks = peris_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peris_gate_clks), + .nr_clk_ids = CLKS_NR_PERIS, + .clk_regs = peris_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peris_clk_regs), + .clk_name = "bus", +}; + +static void __init exynos8895_cmu_peris_init(struct device_node *np) +{ + exynos_arm64_register_cmu(NULL, np, &peris_cmu_info); +} + +/* Register CMU_PERIS early, as it's needed for MCT timer */ +CLK_OF_DECLARE(exynos8895_cmu_peris, "samsung,exynos8895-cmu-peris", + exynos8895_cmu_peris_init); + +/* ---- CMU_FSYS0 ---------------------------------------------------------- */ + +/* Register Offset definitions for CMU_FSYS0 (0x11000000) */ +#define PLL_CON0_MUX_CLKCMU_FSYS0_BUS_USER 0x0100 +#define PLL_CON2_MUX_CLKCMU_FSYS0_BUS_USER 0x0108 +#define PLL_CON0_MUX_CLKCMU_FSYS0_DPGTC_USER 0x0120 +#define PLL_CON2_MUX_CLKCMU_FSYS0_DPGTC_USER 0x0128 +#define PLL_CON0_MUX_CLKCMU_FSYS0_MMC_EMBD_USER 0x0140 +#define PLL_CON2_MUX_CLKCMU_FSYS0_MMC_EMBD_USER 0x0148 +#define PLL_CON0_MUX_CLKCMU_FSYS0_UFS_EMBD_USER 0x0160 +#define PLL_CON2_MUX_CLKCMU_FSYS0_UFS_EMBD_USER 0x0168 +#define PLL_CON0_MUX_CLKCMU_FSYS0_USBDRD30_USER 0x0180 +#define PLL_CON2_MUX_CLKCMU_FSYS0_USBDRD30_USER 0x0188 +#define CLK_CON_GAT_CLK_BLK_FSYS0_UID_FSYS0_CMU_FSYS0_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AHBBR_FSYS0_IPCLKPORT_HCLK 0x2010 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2AHB_FSYS0_IPCLKPORT_ACLK 0x2014 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2AHB_USB_FSYS0_IPCLKPORT_ACLK 0x2018 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2APB_FSYS0_IPCLKPORT_ACLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BTM_FSYS0_IPCLKPORT_I_ACLK 0x2020 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BTM_FSYS0_IPCLKPORT_I_PCLK 0x2024 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_DP_LINK_IPCLKPORT_I_GTC_EXT_CLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_DP_LINK_IPCLKPORT_I_PCLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_ETR_MIU_IPCLKPORT_I_ACLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_ETR_MIU_IPCLKPORT_I_PCLK 0x2038 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_GPIO_FSYS0_IPCLKPORT_PCLK 0x203c +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_D_USBTV_IPCLKPORT_I_CLK 0x2040 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_G_ETR_IPCLKPORT_I_CLK 0x2044 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_P_FSYS0_IPCLKPORT_I_CLK 0x2048 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHS_ACEL_D_FSYS0_IPCLKPORT_I_CLK 0x204c +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_MMC_EMBD_IPCLKPORT_I_ACLK 0x2050 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_MMC_EMBD_IPCLKPORT_SDCLKIN 0x2054 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_PMU_FSYS0_IPCLKPORT_PCLK 0x2058 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BCM_FSYS0_IPCLKPORT_ACLK 0x205c +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BCM_FSYS0_IPCLKPORT_PCLK 0x2060 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_RSTNSYNC_CLK_FSYS0_BUS_IPCLKPORT_CLK 0x2064 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_SYSREG_FSYS0_IPCLKPORT_PCLK 0x2068 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_ACLK 0x206c +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_CLK_UNIPRO 0x2070 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_FMP_CLK 0x2074 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_ACLK 0x2078 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_REF_CLK 0x207c +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_SUSPEND_CLK 0x2080 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_AHB_CLK 0x2084 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_CORE_CLK 0x2088 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_XIU_CLK 0x208c +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_US_D_FSYS0_USB_IPCLKPORT_ACLK 0x2090 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_D_FSYS0_IPCLKPORT_ACLK 0x2094 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_D_FSYS0_USB_IPCLKPORT_ACLK 0x2098 +#define CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_P_FSYS0_IPCLKPORT_ACLK 0x209c + +static const unsigned long fsys0_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_FSYS0_BUS_USER, + PLL_CON2_MUX_CLKCMU_FSYS0_BUS_USER, + PLL_CON0_MUX_CLKCMU_FSYS0_DPGTC_USER, + PLL_CON2_MUX_CLKCMU_FSYS0_DPGTC_USER, + PLL_CON0_MUX_CLKCMU_FSYS0_MMC_EMBD_USER, + PLL_CON2_MUX_CLKCMU_FSYS0_MMC_EMBD_USER, + PLL_CON0_MUX_CLKCMU_FSYS0_UFS_EMBD_USER, + PLL_CON2_MUX_CLKCMU_FSYS0_UFS_EMBD_USER, + PLL_CON0_MUX_CLKCMU_FSYS0_USBDRD30_USER, + PLL_CON2_MUX_CLKCMU_FSYS0_USBDRD30_USER, + CLK_CON_GAT_CLK_BLK_FSYS0_UID_FSYS0_CMU_FSYS0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AHBBR_FSYS0_IPCLKPORT_HCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2AHB_FSYS0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2AHB_USB_FSYS0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2APB_FSYS0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BTM_FSYS0_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BTM_FSYS0_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_DP_LINK_IPCLKPORT_I_GTC_EXT_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_DP_LINK_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_ETR_MIU_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_ETR_MIU_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_GPIO_FSYS0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_D_USBTV_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_G_ETR_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_P_FSYS0_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHS_ACEL_D_FSYS0_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_MMC_EMBD_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_MMC_EMBD_IPCLKPORT_SDCLKIN, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_PMU_FSYS0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BCM_FSYS0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BCM_FSYS0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_RSTNSYNC_CLK_FSYS0_BUS_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_SYSREG_FSYS0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_CLK_UNIPRO, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_FMP_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_REF_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_SUSPEND_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_AHB_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_CORE_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_XIU_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_US_D_FSYS0_USB_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_D_FSYS0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_D_FSYS0_USB_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_P_FSYS0_IPCLKPORT_ACLK, +}; + +/* List of parent clocks for Muxes in CMU_FSYS0 */ +PNAME(mout_fsys0_bus_user_p) = { "oscclk", "dout_cmu_fsys0_bus" }; +PNAME(mout_fsys0_dpgtc_user_p) = { "oscclk", "dout_cmu_fsys0_dpgtc" }; +PNAME(mout_fsys0_mmc_embd_user_p) = { "oscclk", + "dout_cmu_fsys0_mmc_embd" }; +PNAME(mout_fsys0_ufs_embd_user_p) = { "oscclk", + "dout_cmu_fsys0_ufs_embd" }; +PNAME(mout_fsys0_usbdrd30_user_p) = { "oscclk", + "dout_cmu_fsys0_usbdrd30" }; + +static const struct samsung_mux_clock fsys0_mux_clks[] __initconst = { + MUX(CLK_MOUT_FSYS0_BUS_USER, "mout_fsys0_bus_user", + mout_fsys0_bus_user_p, PLL_CON0_MUX_CLKCMU_FSYS0_BUS_USER, 4, 1), + MUX(CLK_MOUT_FSYS0_DPGTC_USER, "mout_fsys0_dpgtc_user", + mout_fsys0_dpgtc_user_p, PLL_CON0_MUX_CLKCMU_FSYS0_DPGTC_USER, + 4, 1), + MUX_F(CLK_MOUT_FSYS0_MMC_EMBD_USER, "mout_fsys0_mmc_embd_user", + mout_fsys0_mmc_embd_user_p, PLL_CON0_MUX_CLKCMU_FSYS0_MMC_EMBD_USER, + 4, 1, CLK_SET_RATE_PARENT, 0), + MUX(CLK_MOUT_FSYS0_UFS_EMBD_USER, "mout_fsys0_ufs_embd_user", + mout_fsys0_ufs_embd_user_p, PLL_CON0_MUX_CLKCMU_FSYS0_UFS_EMBD_USER, + 4, 1), + MUX(CLK_MOUT_FSYS0_USBDRD30_USER, "mout_fsys0_usbdrd30_user", + mout_fsys0_usbdrd30_user_p, PLL_CON0_MUX_CLKCMU_FSYS0_USBDRD30_USER, + 4, 1), +}; + +static const struct samsung_gate_clock fsys0_gate_clks[] __initconst = { + /* Disabling this clock makes the system hang. Mark the clock as critical. */ + GATE(CLK_GOUT_FSYS0_FSYS0_CMU_FSYS0_PCLK, + "gout_fsys0_fsys0_cmu_fsys0_pclk", "mout_fsys0_bus_user", + CLK_CON_GAT_CLK_BLK_FSYS0_UID_FSYS0_CMU_FSYS0_IPCLKPORT_PCLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS0_AHBBR_FSYS0_HCLK, "gout_fsys0_ahbbr_fsys0_hclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AHBBR_FSYS0_IPCLKPORT_HCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_AXI2AHB_FSYS0_ACLK, + "gout_fsys0_axi2ahb_fsys0_aclk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2AHB_FSYS0_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS0_AXI2AHB_USB_FSYS0_ACLK, + "gout_fsys0_axi2ahb_usb_fsys0_aclk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2AHB_USB_FSYS0_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS0_AXI2APB_FSYS0_ACLK, + "gout_fsys0_axi2apb_fsys0_aclk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_AXI2APB_FSYS0_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS0_BTM_FSYS0_I_ACLK, "gout_fsys0_btm_fsys0_i_aclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BTM_FSYS0_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_BTM_FSYS0_I_PCLK, "gout_fsys0_btm_fsys0_i_pclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BTM_FSYS0_IPCLKPORT_I_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_DP_LINK_I_GTC_EXT_CLK, + "gout_fsys0_dp_link_i_gtc_ext_clk", "mout_fsys0_dpgtc_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_DP_LINK_IPCLKPORT_I_GTC_EXT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_DP_LINK_I_PCLK, "gout_fsys0_dp_link_i_pclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_DP_LINK_IPCLKPORT_I_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_ETR_MIU_I_ACLK, "gout_fsys0_etr_miu_i_aclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_ETR_MIU_IPCLKPORT_I_ACLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS0_ETR_MIU_I_PCLK, "gout_fsys0_etr_miu_i_pclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_ETR_MIU_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS0_GPIO_FSYS0_PCLK, "gout_fsys0_gpio_fsys0_pclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_GPIO_FSYS0_IPCLKPORT_PCLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_FSYS0_LHM_AXI_D_USBTV_I_CLK, + "gout_fsys0_lhm_axi_d_usbtv_i_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_D_USBTV_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_LHM_AXI_G_ETR_I_CLK, + "gout_fsys0_lhm_axi_g_etr_i_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_G_ETR_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_LHM_AXI_P_FSYS0_I_CLK, + "gout_fsys0_lhm_axi_p_fsys0_i_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHM_AXI_P_FSYS0_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS0_LHS_ACEL_D_FSYS0_I_CLK, + "gout_fsys0_lhs_acel_d_fsys0_i_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_LHS_ACEL_D_FSYS0_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS0_MMC_EMBD_I_ACLK, "gout_fsys0_mmc_embd_i_aclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_MMC_EMBD_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_MMC_EMBD_SDCLKIN, "gout_fsys0_mmc_embd_sdclkin", + "mout_fsys0_mmc_embd_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_MMC_EMBD_IPCLKPORT_SDCLKIN, + 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS0_PMU_FSYS0_PCLK, "gout_fsys0_pmu_fsys0_pclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_PMU_FSYS0_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS0_BCM_FSYS0_ACLK, "gout_fsys0_bcm_fsys0_aclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BCM_FSYS0_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS0_BCM_FSYS0_PCLK, "gout_fsys0_bcm_fsys0_pclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_BCM_FSYS0_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS0_RSTNSYNC_CLK_FSYS0_BUS_CLK, + "gout_fsys0_rstnsync_clk_fsys0_bus_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_RSTNSYNC_CLK_FSYS0_BUS_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_SYSREG_FSYS0_PCLK, "gout_fsys0_sysreg_fsys0_pclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_SYSREG_FSYS0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_UFS_EMBD_I_ACLK, "gout_fsys0_ufs_embd_i_aclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_UFS_EMBD_I_CLK_UNIPRO, + "gout_fsys0_ufs_embd_i_clk_unipro", "mout_fsys0_ufs_embd_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_CLK_UNIPRO, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS0_UFS_EMBD_I_FMP_CLK, + "gout_fsys0_ufs_embd_i_fmp_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_UFS_EMBD_IPCLKPORT_I_FMP_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_USBTV_I_USB30DRD_ACLK, + "gout_fsys0_usbtv_i_usb30drd_aclk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_USBTV_I_USB30DRD_REF_CLK, + "gout_fsys0_usbtv_i_usb30drd_ref_clk", "mout_fsys0_usbdrd30_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_REF_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_USBTV_I_USB30DRD_SUSPEND_CLK, + "gout_fsys0_usbtv_i_usb30drd_suspend_clk", + "mout_fsys0_usbdrd30_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USB30DRD_SUSPEND_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_USBTV_I_USBTVH_AHB_CLK, + "gout_fsys0_usbtv_i_usbtvh_ahb_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_AHB_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_USBTV_I_USBTVH_CORE_CLK, + "gout_fsys0_usbtv_i_usbtvh_core_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_CORE_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_USBTV_I_USBTVH_XIU_CLK, + "gout_fsys0_usbtv_i_usbtvh_xiu_clk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_USBTV_IPCLKPORT_I_USBTVH_XIU_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_US_D_FSYS0_USB_ACLK, + "gout_fsys0_us_d_fsys0_usb_aclk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_US_D_FSYS0_USB_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS0_XIU_D_FSYS0_ACLK, "gout_fsys0_xiu_d_fsys0_aclk", + "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_D_FSYS0_IPCLKPORT_ACLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_FSYS0_XIU_D_FSYS0_USB_ACLK, + "gout_fsys0_xiu_d_fsys0_usb_aclk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_D_FSYS0_USB_IPCLKPORT_ACLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_FSYS0_XIU_P_FSYS0_ACLK, + "gout_fsys0_xiu_p_fsys0_aclk", "mout_fsys0_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS0_UID_XIU_P_FSYS0_IPCLKPORT_ACLK, + 21, CLK_IGNORE_UNUSED, 0), +}; + +static const struct samsung_cmu_info fsys0_cmu_info __initconst = { + .mux_clks = fsys0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(fsys0_mux_clks), + .gate_clks = fsys0_gate_clks, + .nr_gate_clks = ARRAY_SIZE(fsys0_gate_clks), + .nr_clk_ids = CLKS_NR_FSYS0, + .clk_regs = fsys0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(fsys0_clk_regs), + .clk_name = "bus", +}; + +/* ---- CMU_FSYS1 ---------------------------------------------------------- */ + +/* Register Offset definitions for CMU_FSYS1 (0x11400000) */ +#define PLL_CON0_MUX_CLKCMU_FSYS1_BUS_USER 0x0100 +#define PLL_CON2_MUX_CLKCMU_FSYS1_BUS_USER 0x0108 +#define PLL_CON0_MUX_CLKCMU_FSYS1_MMC_CARD_USER 0x0120 +#define PLL_CON2_MUX_CLKCMU_FSYS1_MMC_CARD_USER 0x0128 +#define PLL_CON0_MUX_CLKCMU_FSYS1_PCIE_USER 0x0140 +#define PLL_CON2_MUX_CLKCMU_FSYS1_PCIE_USER 0x0148 +#define PLL_CON0_MUX_CLKCMU_FSYS1_UFS_CARD_USER 0x0160 +#define PLL_CON2_MUX_CLKCMU_FSYS1_UFS_CARD_USER 0x0168 +#define CLK_CON_GAT_CLK_BLK_FSYS1_UID_PCIE_IPCLKPORT_PHY_REF_CLK_IN 0x2000 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_ADM_AHB_SSS_IPCLKPORT_HCLKM 0x2004 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AHBBR_FSYS1_IPCLKPORT_HCLK 0x2008 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2AHB_FSYS1_IPCLKPORT_ACLK 0x200c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2APB_FSYS1P0_IPCLKPORT_ACLK 0x2010 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2APB_FSYS1P1_IPCLKPORT_ACLK 0x2014 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BTM_FSYS1_IPCLKPORT_I_ACLK 0x2018 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BTM_FSYS1_IPCLKPORT_I_PCLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_FSYS1_CMU_FSYS1_IPCLKPORT_PCLK 0x2024 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_GPIO_FSYS1_IPCLKPORT_PCLK 0x2028 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_LHM_AXI_P_FSYS1_IPCLKPORT_I_CLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_LHS_ACEL_D_FSYS1_IPCLKPORT_I_CLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_MMC_CARD_IPCLKPORT_I_ACLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_MMC_CARD_IPCLKPORT_SDCLKIN 0x2038 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_DBI_ACLK_0 0x203c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_DBI_ACLK_1 0x2040 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_IEEE1500_WRAPPER_FOR_PCIE_PHY_LC_X2_INST_0_I_SCL_APB_PCLK 0x2044 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_MSTR_ACLK_0 0x2048 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_MSTR_ACLK_1 0x204c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PCIE_SUB_CTRL_INST_0_I_DRIVER_APB_CLK 0x2050 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PCIE_SUB_CTRL_INST_1_I_DRIVER_APB_CLK 0x2054 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PIPE2_DIGITAL_X2_WRAP_INST_0_I_APB_PCLK_SCL 0x2058 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_SLV_ACLK_0 0x205c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_SLV_ACLK_1 0x2060 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PMU_FSYS1_IPCLKPORT_PCLK 0x2068 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BCM_FSYS1_IPCLKPORT_ACLK 0x206c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BCM_FSYS1_IPCLKPORT_PCLK 0x2070 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RSTNSYNC_CLK_FSYS1_BUS_IPCLKPORT_CLK 0x2074 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RTIC_IPCLKPORT_I_ACLK 0x207c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RTIC_IPCLKPORT_I_PCLK 0x2080 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SSS_IPCLKPORT_I_ACLK 0x2084 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SSS_IPCLKPORT_I_PCLK 0x2088 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SYSREG_FSYS1_IPCLKPORT_PCLK 0x2090 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_TOE_WIFI0_IPCLKPORT_I_CLK 0x2094 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_TOE_WIFI1_IPCLKPORT_I_CLK 0x2098 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_ACLK 0x209c +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_CLK_UNIPRO 0x20a0 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_FMP_CLK 0x20a4 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_XIU_D_FSYS1_IPCLKPORT_ACLK 0x20a8 +#define CLK_CON_GAT_GOUT_BLK_FSYS1_UID_XIU_P_FSYS1_IPCLKPORT_ACLK 0x20ac + +static const unsigned long fsys1_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_FSYS1_BUS_USER, + PLL_CON2_MUX_CLKCMU_FSYS1_BUS_USER, + PLL_CON0_MUX_CLKCMU_FSYS1_MMC_CARD_USER, + PLL_CON2_MUX_CLKCMU_FSYS1_MMC_CARD_USER, + PLL_CON0_MUX_CLKCMU_FSYS1_PCIE_USER, + PLL_CON2_MUX_CLKCMU_FSYS1_PCIE_USER, + PLL_CON0_MUX_CLKCMU_FSYS1_UFS_CARD_USER, + PLL_CON2_MUX_CLKCMU_FSYS1_UFS_CARD_USER, + CLK_CON_GAT_CLK_BLK_FSYS1_UID_PCIE_IPCLKPORT_PHY_REF_CLK_IN, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_ADM_AHB_SSS_IPCLKPORT_HCLKM, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AHBBR_FSYS1_IPCLKPORT_HCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2AHB_FSYS1_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2APB_FSYS1P0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2APB_FSYS1P1_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BTM_FSYS1_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BTM_FSYS1_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_FSYS1_CMU_FSYS1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_GPIO_FSYS1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_LHM_AXI_P_FSYS1_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_LHS_ACEL_D_FSYS1_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_MMC_CARD_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_MMC_CARD_IPCLKPORT_SDCLKIN, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_DBI_ACLK_0, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_DBI_ACLK_1, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_IEEE1500_WRAPPER_FOR_PCIE_PHY_LC_X2_INST_0_I_SCL_APB_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_MSTR_ACLK_0, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_MSTR_ACLK_1, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PCIE_SUB_CTRL_INST_0_I_DRIVER_APB_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PCIE_SUB_CTRL_INST_1_I_DRIVER_APB_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PIPE2_DIGITAL_X2_WRAP_INST_0_I_APB_PCLK_SCL, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_SLV_ACLK_0, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_SLV_ACLK_1, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PMU_FSYS1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BCM_FSYS1_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BCM_FSYS1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RSTNSYNC_CLK_FSYS1_BUS_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RTIC_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RTIC_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SSS_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SSS_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SYSREG_FSYS1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_TOE_WIFI0_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_TOE_WIFI1_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_CLK_UNIPRO, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_FMP_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_XIU_D_FSYS1_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_XIU_P_FSYS1_IPCLKPORT_ACLK, +}; + +/* List of parent clocks for Muxes in CMU_FSYS1 */ +PNAME(mout_fsys1_bus_user_p) = { "oscclk", "dout_cmu_fsys1_bus" }; +PNAME(mout_fsys1_mmc_card_user_p) = { "oscclk", + "dout_cmu_fsys1_mmc_card" }; +PNAME(mout_fsys1_pcie_user_p) = { "oscclk", "dout_cmu_fsys1_pcie" }; +PNAME(mout_fsys1_ufs_card_user_p) = { "oscclk", + "dout_cmu_fsys1_ufs_card" }; + +static const struct samsung_mux_clock fsys1_mux_clks[] __initconst = { + MUX(CLK_MOUT_FSYS1_BUS_USER, "mout_fsys1_bus_user", + mout_fsys1_bus_user_p, PLL_CON0_MUX_CLKCMU_FSYS1_BUS_USER, 4, 1), + MUX_F(CLK_MOUT_FSYS1_MMC_CARD_USER, "mout_fsys1_mmc_card_user", + mout_fsys1_mmc_card_user_p, + PLL_CON0_MUX_CLKCMU_FSYS1_MMC_CARD_USER, + 4, 1, CLK_SET_RATE_PARENT, 0), + MUX(CLK_MOUT_FSYS1_PCIE_USER, "mout_fsys1_pcie_user", + mout_fsys1_pcie_user_p, PLL_CON0_MUX_CLKCMU_FSYS1_PCIE_USER, 4, 1), + MUX(CLK_MOUT_FSYS1_UFS_CARD_USER, "mout_fsys1_ufs_card_user", + mout_fsys1_ufs_card_user_p, + PLL_CON0_MUX_CLKCMU_FSYS1_UFS_CARD_USER, 4, 1), +}; + +static const struct samsung_gate_clock fsys1_gate_clks[] __initconst = { + GATE(CLK_GOUT_FSYS1_PCIE_PHY_REF_CLK_IN, + "gout_clk_blk_fsys1_pcie_phy_ref_clk_in", "mout_fsys1_pcie_user", + CLK_CON_GAT_CLK_BLK_FSYS1_UID_PCIE_IPCLKPORT_PHY_REF_CLK_IN, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_ADM_AHB_SSS_HCLKM, "gout_fsys1_adm_ahb_sss_hclkm", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_ADM_AHB_SSS_IPCLKPORT_HCLKM, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_AHBBR_FSYS1_HCLK, "gout_fsys1_ahbbr_fsys1_hclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AHBBR_FSYS1_IPCLKPORT_HCLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS1_AXI2AHB_FSYS1_ACLK, + "gout_fsys1_axi2ahb_fsys1_aclk", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2AHB_FSYS1_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS1_AXI2APB_FSYS1P0_ACLK, + "gout_fsys1_axi2apb_fsys1p0_aclk", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2APB_FSYS1P0_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS1_AXI2APB_FSYS1P1_ACLK, + "gout_fsys1_axi2apb_fsys1p1_aclk", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_AXI2APB_FSYS1P1_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS1_BTM_FSYS1_I_ACLK, "gout_fsys1_btm_fsys1_i_aclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BTM_FSYS1_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_BTM_FSYS1_I_PCLK, "gout_fsys1_btm_fsys1_i_pclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BTM_FSYS1_IPCLKPORT_I_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_FSYS1_CMU_FSYS1_PCLK, + "gout_fsys1_fsys1_cmu_fsys1_pclk", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_FSYS1_CMU_FSYS1_IPCLKPORT_PCLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS1_GPIO_FSYS1_PCLK, "gout_fsys1_gpio_fsys1_pclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_GPIO_FSYS1_IPCLKPORT_PCLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_FSYS1_LHM_AXI_P_FSYS1_I_CLK, + "gout_fsys1_lhm_axi_p_fsys1_i_clk", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_LHM_AXI_P_FSYS1_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS1_LHS_ACEL_D_FSYS1_I_CLK, + "gout_fsys1_lhs_acel_d_fsys1_i_clk", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_LHS_ACEL_D_FSYS1_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_FSYS1_MMC_CARD_I_ACLK, "gout_fsys1_mmc_card_i_aclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_MMC_CARD_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_MMC_CARD_SDCLKIN, "gout_fsys1_mmc_card_sdclkin", + "mout_fsys1_mmc_card_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_MMC_CARD_IPCLKPORT_SDCLKIN, + 21, CLK_SET_RATE_PARENT, 0), + GATE(CLK_GOUT_FSYS1_PCIE_DBI_ACLK_0, "gout_fsys1_pcie_dbi_aclk_0", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_DBI_ACLK_0, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_DBI_ACLK_1, "gout_fsys1_pcie_dbi_aclk_1", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_DBI_ACLK_1, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_IEEE1500_WRAPPER_FOR_PCIE_PHY_LC_X2_INST_0_I_SCL_APB_PCLK, + "gout_fsys1_pcie_ieee1500_wrapper_for_pcie_phy_lc_x2_inst_0_i_scl_apb_pclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_IEEE1500_WRAPPER_FOR_PCIE_PHY_LC_X2_INST_0_I_SCL_APB_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_MSTR_ACLK_0, + "gout_fsys1_pcie_mstr_aclk_0", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_MSTR_ACLK_0, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_MSTR_ACLK_1, + "gout_fsys1_pcie_mstr_aclk_1", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_MSTR_ACLK_1, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_PCIE_SUB_CTRL_INST_0_I_DRIVER_APB_CLK, + "gout_fsys1_pcie_pcie_sub_ctrl_inst_0_i_driver_apb_clk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PCIE_SUB_CTRL_INST_0_I_DRIVER_APB_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_PCIE_SUB_CTRL_INST_1_I_DRIVER_APB_CLK, + "gout_fsys1_pcie_pcie_sub_ctrl_inst_1_i_driver_apb_clk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PCIE_SUB_CTRL_INST_1_I_DRIVER_APB_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_PIPE2_DIGITAL_X2_WRAP_INST_0_I_APB_PCLK_SCL, + "gout_fsys1_pcie_pipe2_digital_x2_wrap_inst_0_i_apb_pclk_scl", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_PIPE2_DIGITAL_X2_WRAP_INST_0_I_APB_PCLK_SCL, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_SLV_ACLK_0, "gout_fsys1_pcie_slv_aclk_0", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_SLV_ACLK_0, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PCIE_SLV_ACLK_1, "gout_fsys1_pcie_slv_aclk_1", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PCIE_IPCLKPORT_SLV_ACLK_1, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_PMU_FSYS1_PCLK, "gout_fsys1_pmu_fsys1_pclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_PMU_FSYS1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_BCM_FSYS1_ACLK, "gout_fsys1_bcm_fsys1_aclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BCM_FSYS1_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_BCM_FSYS1_PCLK, "gout_fsys1_bcm_fsys1_pclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_BCM_FSYS1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_RSTNSYNC_CLK_FSYS1_BUS_CLK, + "gout_fsys1_rstnsync_clk_fsys1_bus_clk", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RSTNSYNC_CLK_FSYS1_BUS_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_RTIC_I_ACLK, "gout_fsys1_rtic_i_aclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RTIC_IPCLKPORT_I_ACLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS1_RTIC_I_PCLK, "gout_fsys1_rtic_i_pclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_RTIC_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS1_SSS_I_ACLK, "gout_fsys1_sss_i_aclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SSS_IPCLKPORT_I_ACLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS1_SSS_I_PCLK, "gout_fsys1_sss_i_pclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SSS_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_FSYS1_SYSREG_FSYS1_PCLK, "gout_fsys1_sysreg_fsys1_pclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_SYSREG_FSYS1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_TOE_WIFI0_I_CLK, "gout_fsys1_toe_wifi0_i_clk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_TOE_WIFI0_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_TOE_WIFI1_I_CLK, "gout_fsys1_toe_wifi1_i_clk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_TOE_WIFI1_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_UFS_CARD_I_ACLK, "gout_fsys1_ufs_card_i_aclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_UFS_CARD_I_CLK_UNIPRO, + "gout_fsys1_ufs_card_i_clk_unipro", "mout_fsys1_ufs_card_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_CLK_UNIPRO, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_FSYS1_UFS_CARD_I_FMP_CLK, + "gout_fsys1_ufs_card_i_fmp_clk", "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_UFS_CARD_IPCLKPORT_I_FMP_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS1_XIU_D_FSYS1_ACLK, "gout_fsys1_xiu_d_fsys1_aclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_XIU_D_FSYS1_IPCLKPORT_ACLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_FSYS1_XIU_P_FSYS1_ACLK, "gout_fsys1_xiu_p_fsys1_aclk", + "mout_fsys1_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS1_UID_XIU_P_FSYS1_IPCLKPORT_ACLK, + 21, CLK_IGNORE_UNUSED, 0), +}; + +static const struct samsung_cmu_info fsys1_cmu_info __initconst = { + .mux_clks = fsys1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(fsys1_mux_clks), + .gate_clks = fsys1_gate_clks, + .nr_gate_clks = ARRAY_SIZE(fsys1_gate_clks), + .nr_clk_ids = CLKS_NR_FSYS1, + .clk_regs = fsys1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(fsys1_clk_regs), + .clk_name = "bus", +}; + +/* ---- CMU_PERIC0 ---------------------------------------------------------- */ + +/* Register Offset definitions for CMU_PERIC0 (0x10400000) */ +#define PLL_CON0_MUX_CLKCMU_PERIC0_BUS_USER 0x0100 +#define PLL_CON2_MUX_CLKCMU_PERIC0_BUS_USER 0x0108 +#define PLL_CON0_MUX_CLKCMU_PERIC0_UART_DBG_USER 0x0120 +#define PLL_CON2_MUX_CLKCMU_PERIC0_UART_DBG_USER 0x0128 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI00_USER 0x0140 +#define PLL_CON2_MUX_CLKCMU_PERIC0_USI00_USER 0x0148 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI01_USER 0x0160 +#define PLL_CON2_MUX_CLKCMU_PERIC0_USI01_USER 0x0168 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI02_USER 0x0180 +#define PLL_CON2_MUX_CLKCMU_PERIC0_USI02_USER 0x0188 +#define PLL_CON0_MUX_CLKCMU_PERIC0_USI03_USER 0x01a0 +#define PLL_CON2_MUX_CLKCMU_PERIC0_USI03_USER 0x01a8 +#define CLK_CON_GAT_CLK_BLK_PERIC0_UID_PERIC0_CMU_PERIC0_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_AXI2APB_PERIC0_IPCLKPORT_ACLK 0x2014 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_GPIO_PERIC0_IPCLKPORT_PCLK 0x2018 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_LHM_AXI_P_PERIC0_IPCLKPORT_I_CLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PMU_PERIC0_IPCLKPORT_PCLK 0x2020 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PWM_IPCLKPORT_I_PCLK_S0 0x2028 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_BUSP_IPCLKPORT_CLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SPEEDY2_TSP_IPCLKPORT_CLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SYSREG_PERIC0_IPCLKPORT_PCLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_UART_DBG_IPCLKPORT_EXT_UCLK 0x2038 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_UART_DBG_IPCLKPORT_PCLK 0x203c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI00_IPCLKPORT_I_PCLK 0x2040 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI00_IPCLKPORT_I_SCLK_USI 0x2044 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI01_IPCLKPORT_I_PCLK 0x2048 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI01_IPCLKPORT_I_SCLK_USI 0x204c +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI02_IPCLKPORT_I_PCLK 0x2050 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI02_IPCLKPORT_I_SCLK_USI 0x2054 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI03_IPCLKPORT_I_PCLK 0x2058 +#define CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI03_IPCLKPORT_I_SCLK_USI 0x205c + +static const unsigned long peric0_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_PERIC0_BUS_USER, + PLL_CON2_MUX_CLKCMU_PERIC0_BUS_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_UART_DBG_USER, + PLL_CON2_MUX_CLKCMU_PERIC0_UART_DBG_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI00_USER, + PLL_CON2_MUX_CLKCMU_PERIC0_USI00_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI01_USER, + PLL_CON2_MUX_CLKCMU_PERIC0_USI01_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI02_USER, + PLL_CON2_MUX_CLKCMU_PERIC0_USI02_USER, + PLL_CON0_MUX_CLKCMU_PERIC0_USI03_USER, + PLL_CON2_MUX_CLKCMU_PERIC0_USI03_USER, + CLK_CON_GAT_CLK_BLK_PERIC0_UID_PERIC0_CMU_PERIC0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_AXI2APB_PERIC0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_GPIO_PERIC0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_LHM_AXI_P_PERIC0_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PMU_PERIC0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PWM_IPCLKPORT_I_PCLK_S0, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_BUSP_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SPEEDY2_TSP_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SYSREG_PERIC0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_UART_DBG_IPCLKPORT_EXT_UCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_UART_DBG_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI00_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI00_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI01_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI01_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI02_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI02_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI03_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI03_IPCLKPORT_I_SCLK_USI, +}; + +/* List of parent clocks for Muxes in CMU_PERIC0 */ +PNAME(mout_peric0_bus_user_p) = { "oscclk", "dout_cmu_peric0_bus" }; +PNAME(mout_peric0_uart_dbg_user_p) = { "oscclk", + "dout_cmu_peric0_uart_dbg" }; +PNAME(mout_peric0_usi00_user_p) = { "oscclk", + "dout_cmu_peric0_usi00" }; +PNAME(mout_peric0_usi01_user_p) = { "oscclk", + "dout_cmu_peric0_usi01" }; +PNAME(mout_peric0_usi02_user_p) = { "oscclk", + "dout_cmu_peric0_usi02" }; +PNAME(mout_peric0_usi03_user_p) = { "oscclk", + "dout_cmu_peric0_usi03" }; + +static const struct samsung_mux_clock peric0_mux_clks[] __initconst = { + MUX(CLK_MOUT_PERIC0_BUS_USER, "mout_peric0_bus_user", + mout_peric0_bus_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_BUS_USER, 4, 1), + MUX(CLK_MOUT_PERIC0_UART_DBG_USER, "mout_peric0_uart_dbg_user", + mout_peric0_uart_dbg_user_p, + PLL_CON0_MUX_CLKCMU_PERIC0_UART_DBG_USER, 4, 1), + MUX(CLK_MOUT_PERIC0_USI00_USER, "mout_peric0_usi00_user", + mout_peric0_usi00_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI00_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI01_USER, "mout_peric0_usi01_user", + mout_peric0_usi01_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI01_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI02_USER, "mout_peric0_usi02_user", + mout_peric0_usi02_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI02_USER, + 4, 1), + MUX(CLK_MOUT_PERIC0_USI03_USER, "mout_peric0_usi03_user", + mout_peric0_usi03_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI03_USER, + 4, 1), +}; + +static const struct samsung_gate_clock peric0_gate_clks[] __initconst = { + GATE(CLK_GOUT_PERIC0_PERIC0_CMU_PERIC0_PCLK, + "gout_cperic0_peric0_cmu_peric0_pclk", "mout_peric0_bus_user", + CLK_CON_GAT_CLK_BLK_PERIC0_UID_PERIC0_CMU_PERIC0_IPCLKPORT_PCLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC0_AXI2APB_PERIC0_ACLK, + "gout_peric0_axi2apb_peric0_aclk", "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_AXI2APB_PERIC0_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC0_GPIO_PERIC0_PCLK, "gout_peric0_gpio_peric0_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_GPIO_PERIC0_IPCLKPORT_PCLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_PERIC0_LHM_AXI_P_PERIC0_I_CLK, + "gout_peric0_lhm_axi_p_peric0_i_clk", "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_LHM_AXI_P_PERIC0_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC0_PMU_PERIC0_PCLK, "gout_peric0_pmu_peric0_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PMU_PERIC0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_PWM_I_PCLK_S0, "gout_peric0_pwm_i_pclk_s0", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_PWM_IPCLKPORT_I_PCLK_S0, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_RSTNSYNC_CLK_PERIC0_BUSP_CLK, + "gout_peric0_rstnsync_clk_peric0_busp_clk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_RSTNSYNC_CLK_PERIC0_BUSP_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_SPEEDY2_TSP_CLK, "gout_peric0_speedy2_tsp_clk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SPEEDY2_TSP_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_SYSREG_PERIC0_PCLK, + "gout_peric0_sysreg_peric0_pclk", "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_SYSREG_PERIC0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_UART_DBG_EXT_UCLK, + "gout_peric0_uart_dbg_ext_uclk", "mout_peric0_uart_dbg_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_UART_DBG_IPCLKPORT_EXT_UCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_UART_DBG_PCLK, "gout_peric0_uart_dbg_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_UART_DBG_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI00_I_PCLK, "gout_peric0_usi00_i_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI00_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI00_I_SCLK_USI, "gout_peric0_usi00_i_sclk_usi", + "mout_peric0_usi00_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI00_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI01_I_PCLK, "gout_peric0_usi01_i_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI01_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI01_I_SCLK_USI, "gout_peric0_usi01_i_sclk_usi", + "mout_peric0_usi01_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI01_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI02_I_PCLK, "gout_peric0_usi02_i_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI02_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI02_I_SCLK_USI, "gout_peric0_usi02_i_sclk_usi", + "mout_peric0_usi02_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI02_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI03_I_PCLK, "gout_peric0_usi03_i_pclk", + "mout_peric0_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI03_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC0_USI03_I_SCLK_USI, "gout_peric0_usi03_i_sclk_usi", + "mout_peric0_usi03_user", + CLK_CON_GAT_GOUT_BLK_PERIC0_UID_USI03_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), +}; + +static const struct samsung_cmu_info peric0_cmu_info __initconst = { + .mux_clks = peric0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peric0_mux_clks), + .gate_clks = peric0_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peric0_gate_clks), + .nr_clk_ids = CLKS_NR_PERIC0, + .clk_regs = peric0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peric0_clk_regs), + .clk_name = "bus", +}; + +/* ---- CMU_PERIC1 ---------------------------------------------------------- */ + +/* Register Offset definitions for CMU_PERIC1 (0x10800000) */ +#define PLL_CON0_MUX_CLKCMU_PERIC1_BUS_USER 0x0100 +#define PLL_CON2_MUX_CLKCMU_PERIC1_BUS_USER 0x0108 +#define PLL_CON0_MUX_CLKCMU_PERIC1_SPEEDY2_USER 0x0120 +#define PLL_CON2_MUX_CLKCMU_PERIC1_SPEEDY2_USER 0x0128 +#define PLL_CON0_MUX_CLKCMU_PERIC1_SPI_CAM0_USER 0x0140 +#define PLL_CON2_MUX_CLKCMU_PERIC1_SPI_CAM0_USER 0x0148 +#define PLL_CON0_MUX_CLKCMU_PERIC1_SPI_CAM1_USER 0x0160 +#define PLL_CON2_MUX_CLKCMU_PERIC1_SPI_CAM1_USER 0x0168 +#define PLL_CON0_MUX_CLKCMU_PERIC1_UART_BT_USER 0x0180 +#define PLL_CON2_MUX_CLKCMU_PERIC1_UART_BT_USER 0x0188 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI04_USER 0x01a0 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI04_USER 0x01a8 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI05_USER 0x01c0 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI05_USER 0x01c8 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI06_USER 0x01e0 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI06_USER 0x01e8 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI07_USER 0x0200 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI07_USER 0x0208 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI08_USER 0x0220 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI08_USER 0x0228 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI09_USER 0x0240 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI09_USER 0x0248 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI10_USER 0x0260 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI10_USER 0x0268 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI11_USER 0x0280 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI11_USER 0x0288 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI12_USER 0x02a0 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI12_USER 0x02a8 +#define PLL_CON0_MUX_CLKCMU_PERIC1_USI13_USER 0x02c0 +#define PLL_CON2_MUX_CLKCMU_PERIC1_USI13_USER 0x02c8 +#define CLK_CON_GAT_CLK_BLK_PERIC1_UID_PERIC1_CMU_PERIC1_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_SPEEDY2_IPCLKPORT_CLK 0x200c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P0_IPCLKPORT_ACLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P1_IPCLKPORT_ACLK 0x2020 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P2_IPCLKPORT_ACLK 0x2024 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_GPIO_PERIC1_IPCLKPORT_PCLK 0x2028 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM0_IPCLKPORT_IPCLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM1_IPCLKPORT_IPCLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM2_IPCLKPORT_IPCLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM3_IPCLKPORT_IPCLK 0x2038 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_PERIC1_IPCLKPORT_I_CLK 0x203c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PMU_PERIC1_IPCLKPORT_PCLK 0x2040 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_BUSP_IPCLKPORT_CLK 0x2044 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI1_IPCLKPORT_CLK 0x2048 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI1_IPCLKPORT_SCLK 0x204c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI2_IPCLKPORT_CLK 0x2050 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI2_IPCLKPORT_SCLK 0x2054 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI_IPCLKPORT_CLK 0x2058 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI_IPCLKPORT_SCLK 0x205c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_TSP1_IPCLKPORT_CLK 0x2060 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_TSP2_IPCLKPORT_CLK 0x2064 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM0_IPCLKPORT_PCLK 0x2068 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM0_IPCLKPORT_SPI_EXT_CLK 0x206c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM1_IPCLKPORT_PCLK 0x2070 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM1_IPCLKPORT_SPI_EXT_CLK 0x2074 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SYSREG_PERIC1_IPCLKPORT_PCLK 0x2078 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_UART_BT_IPCLKPORT_EXT_UCLK 0x207c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_UART_BT_IPCLKPORT_PCLK 0x2080 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI04_IPCLKPORT_I_PCLK 0x2084 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI04_IPCLKPORT_I_SCLK_USI 0x2088 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI05_IPCLKPORT_I_PCLK 0x208c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI05_IPCLKPORT_I_SCLK_USI 0x2090 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI06_IPCLKPORT_I_PCLK 0x2094 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI06_IPCLKPORT_I_SCLK_USI 0x2098 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI07_IPCLKPORT_I_PCLK 0x209c +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI07_IPCLKPORT_I_SCLK_USI 0x20a0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI08_IPCLKPORT_I_PCLK 0x20a4 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI08_IPCLKPORT_I_SCLK_USI 0x20a8 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI09_IPCLKPORT_I_PCLK 0x20ac +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI09_IPCLKPORT_I_SCLK_USI 0x20b0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI10_IPCLKPORT_I_PCLK 0x20b4 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI10_IPCLKPORT_I_SCLK_USI 0x20b8 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI11_IPCLKPORT_I_PCLK 0x20bc +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI11_IPCLKPORT_I_SCLK_USI 0x20c0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI12_IPCLKPORT_I_PCLK 0x20c4 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI12_IPCLKPORT_I_SCLK_USI 0x20c8 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI13_IPCLKPORT_I_PCLK 0x20cc +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI13_IPCLKPORT_I_SCLK_USI 0x20d0 +#define CLK_CON_GAT_GOUT_BLK_PERIC1_UID_XIU_P_PERIC1_IPCLKPORT_ACLK 0x20d4 + +static const unsigned long peric1_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_PERIC1_BUS_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_BUS_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_SPEEDY2_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_SPEEDY2_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_SPI_CAM0_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_SPI_CAM0_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_SPI_CAM1_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_SPI_CAM1_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_UART_BT_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_UART_BT_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI04_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI04_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI05_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI05_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI06_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI06_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI07_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI07_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI08_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI08_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI09_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI09_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI10_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI10_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI11_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI11_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI12_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI12_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_USI13_USER, + PLL_CON2_MUX_CLKCMU_PERIC1_USI13_USER, + CLK_CON_GAT_CLK_BLK_PERIC1_UID_PERIC1_CMU_PERIC1_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_SPEEDY2_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P0_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P1_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P2_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_GPIO_PERIC1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM0_IPCLKPORT_IPCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM1_IPCLKPORT_IPCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM2_IPCLKPORT_IPCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM3_IPCLKPORT_IPCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_PERIC1_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PMU_PERIC1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_BUSP_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI1_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI1_IPCLKPORT_SCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI2_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI2_IPCLKPORT_SCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI_IPCLKPORT_SCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_TSP1_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_TSP2_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM0_IPCLKPORT_SPI_EXT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM1_IPCLKPORT_SPI_EXT_CLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SYSREG_PERIC1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_UART_BT_IPCLKPORT_EXT_UCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_UART_BT_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI04_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI04_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI05_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI05_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI06_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI06_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI07_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI07_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI08_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI08_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI09_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI09_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI10_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI10_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI11_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI11_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI12_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI12_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI13_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI13_IPCLKPORT_I_SCLK_USI, + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_XIU_P_PERIC1_IPCLKPORT_ACLK, +}; + +/* List of parent clocks for Muxes in CMU_PERIC1 */ +PNAME(mout_peric1_bus_user_p) = { "oscclk", "dout_cmu_peric1_bus" }; +PNAME(mout_peric1_speedy2_user_p) = { "oscclk", + "dout_cmu_peric1_speedy2" }; +PNAME(mout_peric1_spi_cam0_user_p) = { "oscclk", + "dout_cmu_peric1_spi_cam0" }; +PNAME(mout_peric1_spi_cam1_user_p) = { "oscclk", + "dout_cmu_peric1_spi_cam1" }; +PNAME(mout_peric1_uart_bt_user_p) = { "oscclk", + "dout_cmu_peric1_uart_bt" }; +PNAME(mout_peric1_usi04_user_p) = { "oscclk", + "dout_cmu_peric1_usi04" }; +PNAME(mout_peric1_usi05_user_p) = { "oscclk", + "dout_cmu_peric1_usi05" }; +PNAME(mout_peric1_usi06_user_p) = { "oscclk", + "dout_cmu_peric1_usi06" }; +PNAME(mout_peric1_usi07_user_p) = { "oscclk", + "dout_cmu_peric1_usi07" }; +PNAME(mout_peric1_usi08_user_p) = { "oscclk", + "dout_cmu_peric1_usi08" }; +PNAME(mout_peric1_usi09_user_p) = { "oscclk", + "dout_cmu_peric1_usi09" }; +PNAME(mout_peric1_usi10_user_p) = { "oscclk", + "dout_cmu_peric1_usi10" }; +PNAME(mout_peric1_usi11_user_p) = { "oscclk", + "dout_cmu_peric1_usi11" }; +PNAME(mout_peric1_usi12_user_p) = { "oscclk", + "dout_cmu_peric1_usi12" }; +PNAME(mout_peric1_usi13_user_p) = { "oscclk", + "dout_cmu_peric1_usi13" }; + +static const struct samsung_mux_clock peric1_mux_clks[] __initconst = { + MUX(CLK_MOUT_PERIC1_BUS_USER, "mout_peric1_bus_user", + mout_peric1_bus_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_BUS_USER, 4, 1), + MUX(CLK_MOUT_PERIC1_SPEEDY2_USER, "mout_peric1_speedy2_user", + mout_peric1_speedy2_user_p, + PLL_CON0_MUX_CLKCMU_PERIC1_SPEEDY2_USER, 4, 1), + MUX(CLK_MOUT_PERIC1_SPI_CAM0_USER, "mout_peric1_spi_cam0_user", + mout_peric1_spi_cam0_user_p, + PLL_CON0_MUX_CLKCMU_PERIC1_SPI_CAM0_USER, 4, 1), + MUX(CLK_MOUT_PERIC1_SPI_CAM1_USER, "mout_peric1_spi_cam1_user", + mout_peric1_spi_cam1_user_p, + PLL_CON0_MUX_CLKCMU_PERIC1_SPI_CAM1_USER, 4, 1), + MUX(CLK_MOUT_PERIC1_UART_BT_USER, "mout_peric1_uart_bt_user", + mout_peric1_uart_bt_user_p, + PLL_CON0_MUX_CLKCMU_PERIC1_UART_BT_USER, 4, 1), + MUX(CLK_MOUT_PERIC1_USI04_USER, "mout_peric1_usi04_user", + mout_peric1_usi04_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI04_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI05_USER, "mout_peric1_usi05_user", + mout_peric1_usi05_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI05_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI06_USER, "mout_peric1_usi06_user", + mout_peric1_usi06_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI06_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI07_USER, "mout_peric1_usi07_user", + mout_peric1_usi07_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI07_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI08_USER, "mout_peric1_usi08_user", + mout_peric1_usi08_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI08_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI09_USER, "mout_peric1_usi09_user", + mout_peric1_usi09_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI09_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI10_USER, "mout_peric1_usi10_user", + mout_peric1_usi10_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI10_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI11_USER, "mout_peric1_usi11_user", + mout_peric1_usi11_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI11_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI12_USER, "mout_peric1_usi12_user", + mout_peric1_usi12_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI12_USER, + 4, 1), + MUX(CLK_MOUT_PERIC1_USI13_USER, "mout_peric1_usi13_user", + mout_peric1_usi13_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI13_USER, + 4, 1), +}; + +static const struct samsung_gate_clock peric1_gate_clks[] __initconst = { + GATE(CLK_GOUT_PERIC1_PERIC1_CMU_PERIC1_PCLK, + "gout_peric1_peric1_cmu_peric1_pclk", "mout_peric1_bus_user", + CLK_CON_GAT_CLK_BLK_PERIC1_UID_PERIC1_CMU_PERIC1_IPCLKPORT_PCLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC1_RSTNSYNC_CLK_PERIC1_SPEEDY2_CLK, + "gout_peric1_rstnsync_clk_peric1_speedy2_clk", + "mout_peric1_speedy2_user", + CLK_CON_GAT_CLK_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_SPEEDY2_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_AXI2APB_PERIC1P0_ACLK, + "gout_peric1_axi2apb_peric1p0_aclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P0_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC1_AXI2APB_PERIC1P1_ACLK, + "gout_peric1_axi2apb_peric1p1_aclk", "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P1_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC1_AXI2APB_PERIC1P2_ACLK, + "gout_peric1_axi2apb_peric1p2_aclk", "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_AXI2APB_PERIC1P2_IPCLKPORT_ACLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC1_GPIO_PERIC1_PCLK, + "gout_peric1_gpio_peric1_pclk", "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_GPIO_PERIC1_IPCLKPORT_PCLK, + 21, CLK_IGNORE_UNUSED, 0), + GATE(CLK_GOUT_PERIC1_HSI2C_CAM0_IPCLK, "gout_peric1_hsi2c_cam0_ipclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM0_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_HSI2C_CAM1_IPCLK, + "gout_peric1_hsi2c_cam1_ipclk", "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM1_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_HSI2C_CAM2_IPCLK, + "gout_peric1_hsi2c_cam2_ipclk", "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM2_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_HSI2C_CAM3_IPCLK, "gout_peric1_hsi2c_cam3_ipclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_HSI2C_CAM3_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_LHM_AXI_P_PERIC1_I_CLK, + "gout_peric1_lhm_axi_p_peric1_i_clk", "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_LHM_AXI_P_PERIC1_IPCLKPORT_I_CLK, + 21, CLK_IS_CRITICAL, 0), + GATE(CLK_GOUT_PERIC1_PMU_PERIC1_PCLK, "gout_peric1_pmu_peric1_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_PMU_PERIC1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_RSTNSYNC_CLK_PERIC1_BUSP_CLK, + "gout_peric1_rstnsync_clk_peric1_busp_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_RSTNSYNC_CLK_PERIC1_BUSP_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPEEDY2_DDI1_CLK, "gout_peric1_speedy2_ddi1_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI1_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPEEDY2_DDI1_SCLK, + "gout_peric1_speedy2_ddi1_sclk", "mout_peric1_speedy2_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI1_IPCLKPORT_SCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPEEDY2_DDI2_CLK, "gout_peric1_speedy2_ddi2_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI2_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPEEDY2_DDI2_SCLK, + "gout_peric1_speedy2_ddi2_sclk", "mout_peric1_speedy2_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI2_IPCLKPORT_SCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPEEDY2_DDI_CLK, "gout_peric1_speedy2_ddi_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPEEDY2_DDI_SCLK, "gout_peric1_speedy2_ddi_sclk", + "mout_peric1_speedy2_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_DDI_IPCLKPORT_SCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPEEDY2_TSP1_CLK, "gout_peric1_speedy2_tsp1_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_TSP1_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPEEDY2_TSP2_CLK, "gout_peric1_speedy2_tsp2_clk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPEEDY2_TSP2_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPI_CAM0_PCLK, "gout_peric1_spi_cam0_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPI_CAM0_SPI_EXT_CLK, + "gout_peric1_spi_cam0_spi_ext_clk", "mout_peric1_spi_cam0_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM0_IPCLKPORT_SPI_EXT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPI_CAM1_PCLK, "gout_peric1_spi_cam1_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SPI_CAM1_SPI_EXT_CLK, + "gout_peric1_spi_cam1_spi_ext_clk", "mout_peric1_spi_cam1_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SPI_CAM1_IPCLKPORT_SPI_EXT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_SYSREG_PERIC1_PCLK, + "gout_peric1_sysreg_peric1_pclk", "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_SYSREG_PERIC1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_UART_BT_EXT_UCLK, "gout_peric1_uart_bt_ext_uclk", + "mout_peric1_uart_bt_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_UART_BT_IPCLKPORT_EXT_UCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_UART_BT_PCLK, "gout_peric1_uart_bt_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_UART_BT_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI04_I_PCLK, "gout_peric1_usi04_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI04_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI04_I_SCLK_USI, "gout_peric1_usi04_i_sclk_usi", + "mout_peric1_usi04_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI04_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI05_I_PCLK, "gout_peric1_usi05_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI05_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI05_I_SCLK_USI, "gout_peric1_usi05_i_sclk_usi", + "mout_peric1_usi05_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI05_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI06_I_PCLK, "gout_peric1_usi06_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI06_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI06_I_SCLK_USI, "gout_peric1_usi06_i_sclk_usi", + "mout_peric1_usi06_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI06_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI07_I_PCLK, "gout_peric1_usi07_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI07_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI07_I_SCLK_USI, "gout_peric1_usi07_i_sclk_usi", + "mout_peric1_usi07_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI07_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI08_I_PCLK, "gout_peric1_usi08_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI08_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI08_I_SCLK_USI, "gout_peric1_usi08_i_sclk_usi", + "mout_peric1_usi08_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI08_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI09_I_PCLK, "gout_peric1_usi09_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI09_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI09_I_SCLK_USI, "gout_peric1_usi09_i_sclk_usi", + "mout_peric1_usi09_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI09_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI10_I_PCLK, "gout_peric1_usi10_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI10_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI10_I_SCLK_USI, "gout_peric1_usi10_i_sclk_usi", + "mout_peric1_usi10_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI10_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI11_I_PCLK, "gout_peric1_usi11_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI11_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI11_I_SCLK_USI, "gout_peric1_usi11_i_sclk_usi", + "mout_peric1_usi11_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI11_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI12_I_PCLK, "gout_peric1_usi12_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI12_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI12_I_SCLK_USI, "gout_peric1_usi12_i_sclk_usi", + "mout_peric1_usi12_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI12_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI13_I_PCLK, "gout_peric1_usi13_i_pclk", + "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI13_IPCLKPORT_I_PCLK, 21, 0, 0), + GATE(CLK_GOUT_PERIC1_USI13_I_SCLK_USI, "gout_peric1_usi13_i_sclk_usi", + "mout_peric1_usi13_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_USI13_IPCLKPORT_I_SCLK_USI, + 21, 0, 0), + GATE(CLK_GOUT_PERIC1_XIU_P_PERIC1_ACLK, + "gout_peric1_xiu_p_peric1_aclk", "mout_peric1_bus_user", + CLK_CON_GAT_GOUT_BLK_PERIC1_UID_XIU_P_PERIC1_IPCLKPORT_ACLK, + 21, CLK_IGNORE_UNUSED, 0), +}; + +static const struct samsung_cmu_info peric1_cmu_info __initconst = { + .mux_clks = peric1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peric1_mux_clks), + .gate_clks = peric1_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peric1_gate_clks), + .nr_clk_ids = CLKS_NR_PERIC1, + .clk_regs = peric1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peric1_clk_regs), + .clk_name = "bus", +}; + +static int __init exynos8895_cmu_probe(struct platform_device *pdev) +{ + const struct samsung_cmu_info *info; + struct device *dev = &pdev->dev; + + info = of_device_get_match_data(dev); + exynos_arm64_register_cmu(dev, dev->of_node, info); + + return 0; +} + +static const struct of_device_id exynos8895_cmu_of_match[] = { + { + .compatible = "samsung,exynos8895-cmu-fsys0", + .data = &fsys0_cmu_info, + }, { + .compatible = "samsung,exynos8895-cmu-fsys1", + .data = &fsys1_cmu_info, + }, { + .compatible = "samsung,exynos8895-cmu-peric0", + .data = &peric0_cmu_info, + }, { + .compatible = "samsung,exynos8895-cmu-peric1", + .data = &peric1_cmu_info, + }, + { } +}; + +static struct platform_driver exynos8895_cmu_driver __refdata = { + .driver = { + .name = "exynos8895-cmu", + .of_match_table = exynos8895_cmu_of_match, + .suppress_bind_attrs = true, + }, + .probe = exynos8895_cmu_probe, +}; + +static int __init exynos8895_cmu_init(void) +{ + return platform_driver_register(&exynos8895_cmu_driver); +} +core_initcall(exynos8895_cmu_init); diff --git a/drivers/clk/samsung/clk-exynosautov920.c b/drivers/clk/samsung/clk-exynosautov920.c index f60f0a0c598de5..2a8bfd5d9abc8a 100644 --- a/drivers/clk/samsung/clk-exynosautov920.c +++ b/drivers/clk/samsung/clk-exynosautov920.c @@ -19,6 +19,10 @@ /* NOTE: Must be equal to the last clock ID increased by one */ #define CLKS_NR_TOP (DOUT_CLKCMU_TAA_NOC + 1) #define CLKS_NR_PERIC0 (CLK_DOUT_PERIC0_I3C + 1) +#define CLKS_NR_PERIC1 (CLK_DOUT_PERIC1_I3C + 1) +#define CLKS_NR_MISC (CLK_DOUT_MISC_OSC_DIV2 + 1) +#define CLKS_NR_HSI0 (CLK_DOUT_HSI0_PCIE_APB + 1) +#define CLKS_NR_HSI1 (CLK_MOUT_HSI1_USBDRD + 1) /* ---- CMU_TOP ------------------------------------------------------------ */ @@ -974,6 +978,8 @@ static const struct samsung_fixed_factor_clock top_fixed_factor_clks[] __initcon "mout_shared5_pll", 1, 3, 0), FFACTOR(DOUT_SHARED5_DIV4, "dout_shared5_div4", "mout_shared5_pll", 1, 4, 0), + FFACTOR(DOUT_TCXO_DIV2, "dout_tcxo_div2", + "oscclk", 1, 2, 0), }; static const struct samsung_cmu_info top_cmu_info __initconst = { @@ -1139,6 +1145,277 @@ static const struct samsung_cmu_info peric0_cmu_info __initconst = { .clk_name = "noc", }; +/* ---- CMU_PERIC1 --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_PERIC1 (0x10C00000) */ +#define PLL_CON0_MUX_CLKCMU_PERIC1_IP_USER 0x600 +#define PLL_CON0_MUX_CLKCMU_PERIC1_NOC_USER 0x610 +#define CLK_CON_MUX_MUX_CLK_PERIC1_I3C 0x1000 +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI09_USI 0x1004 +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI10_USI 0x1008 +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI11_USI 0x100c +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI12_USI 0x1010 +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI13_USI 0x1014 +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI14_USI 0x1018 +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI15_USI 0x101c +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI16_USI 0x1020 +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI17_USI 0x1024 +#define CLK_CON_MUX_MUX_CLK_PERIC1_USI_I2C 0x1028 +#define CLK_CON_DIV_DIV_CLK_PERIC1_I3C 0x1800 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI09_USI 0x1804 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI10_USI 0x1808 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI11_USI 0x180c +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI12_USI 0x1810 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI13_USI 0x1814 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI14_USI 0x1818 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI15_USI 0x181c +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI16_USI 0x1820 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI17_USI 0x1824 +#define CLK_CON_DIV_DIV_CLK_PERIC1_USI_I2C 0x1828 + +static const unsigned long peric1_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_PERIC1_IP_USER, + PLL_CON0_MUX_CLKCMU_PERIC1_NOC_USER, + CLK_CON_MUX_MUX_CLK_PERIC1_I3C, + CLK_CON_MUX_MUX_CLK_PERIC1_USI09_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI10_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI11_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI12_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI13_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI14_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI15_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI16_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI17_USI, + CLK_CON_MUX_MUX_CLK_PERIC1_USI_I2C, + CLK_CON_DIV_DIV_CLK_PERIC1_I3C, + CLK_CON_DIV_DIV_CLK_PERIC1_USI09_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI10_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI11_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI12_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI13_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI14_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI15_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI16_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI17_USI, + CLK_CON_DIV_DIV_CLK_PERIC1_USI_I2C, +}; + +/* List of parent clocks for Muxes in CMU_PERIC1 */ +PNAME(mout_peric1_ip_user_p) = { "oscclk", "dout_clkcmu_peric1_ip" }; +PNAME(mout_peric1_noc_user_p) = { "oscclk", "dout_clkcmu_peric1_noc" }; +PNAME(mout_peric1_usi_p) = { "oscclk", "mout_peric1_ip_user" }; + +static const struct samsung_mux_clock peric1_mux_clks[] __initconst = { + MUX(CLK_MOUT_PERIC1_IP_USER, "mout_peric1_ip_user", + mout_peric1_ip_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_IP_USER, 4, 1), + MUX(CLK_MOUT_PERIC1_NOC_USER, "mout_peric1_noc_user", + mout_peric1_noc_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_NOC_USER, 4, 1), + /* USI09 ~ USI17 */ + MUX(CLK_MOUT_PERIC1_USI09_USI, "mout_peric1_usi09_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI09_USI, 0, 1), + MUX(CLK_MOUT_PERIC1_USI10_USI, "mout_peric1_usi10_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI10_USI, 0, 1), + MUX(CLK_MOUT_PERIC1_USI11_USI, "mout_peric1_usi11_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI11_USI, 0, 1), + MUX(CLK_MOUT_PERIC1_USI12_USI, "mout_peric1_usi12_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI12_USI, 0, 1), + MUX(CLK_MOUT_PERIC1_USI13_USI, "mout_peric1_usi13_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI13_USI, 0, 1), + MUX(CLK_MOUT_PERIC1_USI14_USI, "mout_peric1_usi14_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI14_USI, 0, 1), + MUX(CLK_MOUT_PERIC1_USI15_USI, "mout_peric1_usi15_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI15_USI, 0, 1), + MUX(CLK_MOUT_PERIC1_USI16_USI, "mout_peric1_usi16_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI16_USI, 0, 1), + MUX(CLK_MOUT_PERIC1_USI17_USI, "mout_peric1_usi17_usi", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI17_USI, 0, 1), + /* USI_I2C */ + MUX(CLK_MOUT_PERIC1_USI_I2C, "mout_peric1_usi_i2c", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_USI_I2C, 0, 1), + /* USI_I3C */ + MUX(CLK_MOUT_PERIC1_I3C, "mout_peric1_i3c", + mout_peric1_usi_p, CLK_CON_MUX_MUX_CLK_PERIC1_I3C, 0, 1), +}; + +static const struct samsung_div_clock peric1_div_clks[] __initconst = { + /* USI09 ~ USI17 */ + DIV(CLK_DOUT_PERIC1_USI09_USI, "dout_peric1_usi09_usi", + "mout_peric1_usi09_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI09_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI10_USI, "dout_peric1_usi10_usi", + "mout_peric1_usi10_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI10_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI11_USI, "dout_peric1_usi11_usi", + "mout_peric1_usi11_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI11_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI12_USI, "dout_peric1_usi12_usi", + "mout_peric1_usi12_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI12_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI13_USI, "dout_peric1_usi13_usi", + "mout_peric1_usi13_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI13_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI14_USI, "dout_peric1_usi14_usi", + "mout_peric1_usi14_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI14_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI15_USI, "dout_peric1_usi15_usi", + "mout_peric1_usi15_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI15_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI16_USI, "dout_peric1_usi16_usi", + "mout_peric1_usi16_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI16_USI, + 0, 4), + DIV(CLK_DOUT_PERIC1_USI17_USI, "dout_peric1_usi17_usi", + "mout_peric1_usi17_usi", CLK_CON_DIV_DIV_CLK_PERIC1_USI17_USI, + 0, 4), + /* USI_I2C */ + DIV(CLK_DOUT_PERIC1_USI_I2C, "dout_peric1_usi_i2c", + "mout_peric1_usi_i2c", CLK_CON_DIV_DIV_CLK_PERIC1_USI_I2C, 0, 4), + /* USI_I3C */ + DIV(CLK_DOUT_PERIC1_I3C, "dout_peric1_i3c", + "mout_peric1_i3c", CLK_CON_DIV_DIV_CLK_PERIC1_I3C, 0, 4), +}; + +static const struct samsung_cmu_info peric1_cmu_info __initconst = { + .mux_clks = peric1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peric1_mux_clks), + .div_clks = peric1_div_clks, + .nr_div_clks = ARRAY_SIZE(peric1_div_clks), + .nr_clk_ids = CLKS_NR_PERIC1, + .clk_regs = peric1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peric1_clk_regs), + .clk_name = "noc", +}; + +/* ---- CMU_MISC --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_MISC (0x10020000) */ +#define PLL_CON0_MUX_CLKCMU_MISC_NOC_USER 0x600 +#define CLK_CON_MUX_MUX_CLK_MISC_GIC 0x1000 +#define CLK_CON_DIV_CLKCMU_OTP 0x1800 +#define CLK_CON_DIV_DIV_CLK_MISC_NOCP 0x1804 +#define CLK_CON_DIV_DIV_CLK_MISC_OSC_DIV2 0x1808 + +static const unsigned long misc_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_MISC_NOC_USER, + CLK_CON_MUX_MUX_CLK_MISC_GIC, + CLK_CON_DIV_CLKCMU_OTP, + CLK_CON_DIV_DIV_CLK_MISC_NOCP, + CLK_CON_DIV_DIV_CLK_MISC_OSC_DIV2, +}; + +/* List of parent clocks for Muxes in CMU_MISC */ +PNAME(mout_misc_noc_user_p) = { "oscclk", "dout_clkcmu_misc_noc" }; +PNAME(mout_misc_gic_p) = { "dout_misc_nocp", "oscclk" }; + +static const struct samsung_mux_clock misc_mux_clks[] __initconst = { + MUX(CLK_MOUT_MISC_NOC_USER, "mout_misc_noc_user", + mout_misc_noc_user_p, PLL_CON0_MUX_CLKCMU_MISC_NOC_USER, 4, 1), + MUX(CLK_MOUT_MISC_GIC, "mout_misc_gic", + mout_misc_gic_p, CLK_CON_MUX_MUX_CLK_MISC_GIC, 0, 1), +}; + +static const struct samsung_div_clock misc_div_clks[] __initconst = { + DIV(CLK_DOUT_MISC_NOCP, "dout_misc_nocp", + "mout_misc_noc_user", CLK_CON_DIV_DIV_CLK_MISC_NOCP, + 0, 3), +}; + +static const struct samsung_fixed_factor_clock misc_fixed_factor_clks[] __initconst = { + FFACTOR(CLK_DOUT_MISC_OTP, "dout_misc_otp", + "oscclk", 1, 10, 0), + FFACTOR(CLK_DOUT_MISC_OSC_DIV2, "dout_misc_osc_div2", + "oscclk", 1, 2, 0), +}; + +static const struct samsung_cmu_info misc_cmu_info __initconst = { + .mux_clks = misc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(misc_mux_clks), + .div_clks = misc_div_clks, + .nr_div_clks = ARRAY_SIZE(misc_div_clks), + .fixed_factor_clks = misc_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(misc_fixed_factor_clks), + .nr_clk_ids = CLKS_NR_MISC, + .clk_regs = misc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(misc_clk_regs), + .clk_name = "noc", +}; + +/* ---- CMU_HSI0 --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_HSI0 (0x16000000) */ +#define PLL_CON0_MUX_CLKCMU_HSI0_NOC_USER 0x600 +#define CLK_CON_DIV_DIV_CLK_HSI0_PCIE_APB 0x1800 + +static const unsigned long hsi0_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_HSI0_NOC_USER, + CLK_CON_DIV_DIV_CLK_HSI0_PCIE_APB, +}; + +/* List of parent clocks for Muxes in CMU_HSI0 */ +PNAME(mout_hsi0_noc_user_p) = { "oscclk", "dout_clkcmu_hsi0_noc" }; + +static const struct samsung_mux_clock hsi0_mux_clks[] __initconst = { + MUX(CLK_MOUT_HSI0_NOC_USER, "mout_hsi0_noc_user", + mout_hsi0_noc_user_p, PLL_CON0_MUX_CLKCMU_HSI0_NOC_USER, 4, 1), +}; + +static const struct samsung_div_clock hsi0_div_clks[] __initconst = { + DIV(CLK_DOUT_HSI0_PCIE_APB, "dout_hsi0_pcie_apb", + "mout_hsi0_noc_user", CLK_CON_DIV_DIV_CLK_HSI0_PCIE_APB, + 0, 4), +}; + +static const struct samsung_cmu_info hsi0_cmu_info __initconst = { + .mux_clks = hsi0_mux_clks, + .nr_mux_clks = ARRAY_SIZE(hsi0_mux_clks), + .div_clks = hsi0_div_clks, + .nr_div_clks = ARRAY_SIZE(hsi0_div_clks), + .nr_clk_ids = CLKS_NR_HSI0, + .clk_regs = hsi0_clk_regs, + .nr_clk_regs = ARRAY_SIZE(hsi0_clk_regs), + .clk_name = "noc", +}; + +/* ---- CMU_HSI1 --------------------------------------------------------- */ + +/* Register Offset definitions for CMU_HSI1 (0x16400000) */ +#define PLL_CON0_MUX_CLKCMU_HSI1_MMC_CARD_USER 0x600 +#define PLL_CON0_MUX_CLKCMU_HSI1_NOC_USER 0x610 +#define PLL_CON0_MUX_CLKCMU_HSI1_USBDRD_USER 0x620 +#define CLK_CON_MUX_MUX_CLK_HSI1_USBDRD 0x1000 + +static const unsigned long hsi1_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_HSI1_MMC_CARD_USER, + PLL_CON0_MUX_CLKCMU_HSI1_NOC_USER, + PLL_CON0_MUX_CLKCMU_HSI1_USBDRD_USER, + CLK_CON_MUX_MUX_CLK_HSI1_USBDRD, +}; + +/* List of parent clocks for Muxes in CMU_HSI1 */ +PNAME(mout_hsi1_mmc_card_user_p) = {"oscclk", "dout_clkcmu_hsi1_mmc_card"}; +PNAME(mout_hsi1_noc_user_p) = { "oscclk", "dout_clkcmu_hsi1_noc" }; +PNAME(mout_hsi1_usbdrd_user_p) = { "oscclk", "mout_clkcmu_hsi1_usbdrd" }; +PNAME(mout_hsi1_usbdrd_p) = { "dout_tcxo_div2", "mout_hsi1_usbdrd_user" }; + +static const struct samsung_mux_clock hsi1_mux_clks[] __initconst = { + MUX(CLK_MOUT_HSI1_MMC_CARD_USER, "mout_hsi1_mmc_card_user", + mout_hsi1_mmc_card_user_p, PLL_CON0_MUX_CLKCMU_HSI1_MMC_CARD_USER, 4, 1), + MUX(CLK_MOUT_HSI1_NOC_USER, "mout_hsi1_noc_user", + mout_hsi1_noc_user_p, PLL_CON0_MUX_CLKCMU_HSI1_NOC_USER, 4, 1), + MUX(CLK_MOUT_HSI1_USBDRD_USER, "mout_hsi1_usbdrd_user", + mout_hsi1_usbdrd_user_p, PLL_CON0_MUX_CLKCMU_HSI1_USBDRD_USER, 4, 1), + MUX(CLK_MOUT_HSI1_USBDRD, "mout_hsi1_usbdrd", + mout_hsi1_usbdrd_p, CLK_CON_MUX_MUX_CLK_HSI1_USBDRD, 4, 1), +}; + +static const struct samsung_cmu_info hsi1_cmu_info __initconst = { + .mux_clks = hsi1_mux_clks, + .nr_mux_clks = ARRAY_SIZE(hsi1_mux_clks), + .nr_clk_ids = CLKS_NR_HSI1, + .clk_regs = hsi1_clk_regs, + .nr_clk_regs = ARRAY_SIZE(hsi1_clk_regs), + .clk_name = "noc", +}; + static int __init exynosautov920_cmu_probe(struct platform_device *pdev) { const struct samsung_cmu_info *info; @@ -1154,6 +1431,18 @@ static const struct of_device_id exynosautov920_cmu_of_match[] = { { .compatible = "samsung,exynosautov920-cmu-peric0", .data = &peric0_cmu_info, + }, { + .compatible = "samsung,exynosautov920-cmu-peric1", + .data = &peric1_cmu_info, + }, { + .compatible = "samsung,exynosautov920-cmu-misc", + .data = &misc_cmu_info, + }, { + .compatible = "samsung,exynosautov920-cmu-hsi0", + .data = &hsi0_cmu_info, + }, { + .compatible = "samsung,exynosautov920-cmu-hsi1", + .data = &hsi1_cmu_info, }, { } }; diff --git a/drivers/clk/samsung/clk-fsd.c b/drivers/clk/samsung/clk-fsd.c index 6f984cfcd33cbf..9a6006c298c2a8 100644 --- a/drivers/clk/samsung/clk-fsd.c +++ b/drivers/clk/samsung/clk-fsd.c @@ -82,6 +82,15 @@ #define GAT_CMU_NS_BRDG_CMU_IPCLKPORT_CLK__PSOC_CMU__CLK_CMU 0x205c #define GAT_CMU_SYSREG_CMU_IPCLKPORT_PCLK 0x2060 +/* NOTE: Must be equal to the last clock ID increased by one */ +#define CLKS_NR_CMU (GAT_CMU_FSYS0_SHARED0DIV4 + 1) +#define CLKS_NR_PERIC (PERIC_DOUT_RGMII_CLK + 1) +#define CLKS_NR_FSYS0 (FSYS0_DOUT_FSYS0_PERIBUS_GRP + 1) +#define CLKS_NR_FSYS1 (PCIE_LINK1_IPCLKPORT_SLV_ACLK + 1) +#define CLKS_NR_IMEM (IMEM_TMU_GT_IPCLKPORT_I_CLK_TS + 1) +#define CLKS_NR_MFC (MFC_MFC_IPCLKPORT_ACLK + 1) +#define CLKS_NR_CAM_CSI (CAM_CSI2_3_IPCLKPORT_I_ACLK + 1) + static const unsigned long cmu_clk_regs[] __initconst = { PLL_LOCKTIME_PLL_SHARED0, PLL_LOCKTIME_PLL_SHARED1, @@ -300,7 +309,7 @@ static const struct samsung_cmu_info cmu_cmu_info __initconst = { .nr_div_clks = ARRAY_SIZE(cmu_div_clks), .gate_clks = cmu_gate_clks, .nr_gate_clks = ARRAY_SIZE(cmu_gate_clks), - .nr_clk_ids = CMU_NR_CLK, + .nr_clk_ids = CLKS_NR_CMU, .clk_regs = cmu_clk_regs, .nr_clk_regs = ARRAY_SIZE(cmu_clk_regs), }; @@ -665,7 +674,7 @@ static const struct samsung_cmu_info peric_cmu_info __initconst = { .nr_gate_clks = ARRAY_SIZE(peric_gate_clks), .fixed_clks = peric_fixed_clks, .nr_fixed_clks = ARRAY_SIZE(peric_fixed_clks), - .nr_clk_ids = PERIC_NR_CLK, + .nr_clk_ids = CLKS_NR_PERIC, .clk_regs = peric_clk_regs, .nr_clk_regs = ARRAY_SIZE(peric_clk_regs), .clk_name = "dout_cmu_pll_shared0_div4", @@ -964,7 +973,7 @@ static const struct samsung_cmu_info fsys0_cmu_info __initconst = { .nr_gate_clks = ARRAY_SIZE(fsys0_gate_clks), .fixed_clks = fsys0_fixed_clks, .nr_fixed_clks = ARRAY_SIZE(fsys0_fixed_clks), - .nr_clk_ids = FSYS0_NR_CLK, + .nr_clk_ids = CLKS_NR_FSYS0, .clk_regs = fsys0_clk_regs, .nr_clk_regs = ARRAY_SIZE(fsys0_clk_regs), .clk_name = "dout_cmu_fsys0_shared1div4", @@ -1136,7 +1145,7 @@ static const struct samsung_cmu_info fsys1_cmu_info __initconst = { .nr_gate_clks = ARRAY_SIZE(fsys1_gate_clks), .fixed_clks = fsys1_fixed_clks, .nr_fixed_clks = ARRAY_SIZE(fsys1_fixed_clks), - .nr_clk_ids = FSYS1_NR_CLK, + .nr_clk_ids = CLKS_NR_FSYS1, .clk_regs = fsys1_clk_regs, .nr_clk_regs = ARRAY_SIZE(fsys1_clk_regs), .clk_name = "dout_cmu_fsys1_shared0div4", @@ -1413,7 +1422,7 @@ static const struct samsung_cmu_info imem_cmu_info __initconst = { .nr_div_clks = ARRAY_SIZE(imem_div_clks), .gate_clks = imem_gate_clks, .nr_gate_clks = ARRAY_SIZE(imem_gate_clks), - .nr_clk_ids = IMEM_NR_CLK, + .nr_clk_ids = CLKS_NR_IMEM, .clk_regs = imem_clk_regs, .nr_clk_regs = ARRAY_SIZE(imem_clk_regs), }; @@ -1538,7 +1547,7 @@ static const struct samsung_cmu_info mfc_cmu_info __initconst = { .nr_div_clks = ARRAY_SIZE(mfc_div_clks), .gate_clks = mfc_gate_clks, .nr_gate_clks = ARRAY_SIZE(mfc_gate_clks), - .nr_clk_ids = MFC_NR_CLK, + .nr_clk_ids = CLKS_NR_MFC, .clk_regs = mfc_clk_regs, .nr_clk_regs = ARRAY_SIZE(mfc_clk_regs), }; @@ -1742,7 +1751,7 @@ static const struct samsung_cmu_info cam_csi_cmu_info __initconst = { .nr_div_clks = ARRAY_SIZE(cam_csi_div_clks), .gate_clks = cam_csi_gate_clks, .nr_gate_clks = ARRAY_SIZE(cam_csi_gate_clks), - .nr_clk_ids = CAM_CSI_NR_CLK, + .nr_clk_ids = CLKS_NR_CAM_CSI, .clk_regs = cam_csi_clk_regs, .nr_clk_regs = ARRAY_SIZE(cam_csi_clk_regs), }; diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c index 85098c61c15e6f..86b39edba12276 100644 --- a/drivers/clk/samsung/clk-gs101.c +++ b/drivers/clk/samsung/clk-gs101.c @@ -2775,11 +2775,11 @@ static const struct samsung_gate_clock hsi2_gate_clks[] __initconst = { GATE(CLK_GOUT_HSI2_QE_UFS_EMBD_HSI2_ACLK, "gout_hsi2_qe_ufs_embd_hsi2_aclk", "mout_hsi2_bus_user", CLK_CON_GAT_GOUT_BLK_HSI2_UID_QE_UFS_EMBD_HSI2_IPCLKPORT_ACLK, - 21, 0, 0), + 21, CLK_IS_CRITICAL, 0), GATE(CLK_GOUT_HSI2_QE_UFS_EMBD_HSI2_PCLK, "gout_hsi2_qe_ufs_embd_hsi2_pclk", "mout_hsi2_bus_user", CLK_CON_GAT_GOUT_BLK_HSI2_UID_QE_UFS_EMBD_HSI2_IPCLKPORT_PCLK, - 21, 0, 0), + 21, CLK_IS_CRITICAL, 0), GATE(CLK_GOUT_HSI2_CLK_HSI2_BUS_CLK, "gout_hsi2_clk_hsi2_bus_clk", "mout_hsi2_bus_user", CLK_CON_GAT_GOUT_BLK_HSI2_UID_RSTNSYNC_CLK_HSI2_BUS_IPCLKPORT_CLK, @@ -2806,7 +2806,7 @@ static const struct samsung_gate_clock hsi2_gate_clks[] __initconst = { GATE(CLK_GOUT_HSI2_SYSREG_HSI2_PCLK, "gout_hsi2_sysreg_hsi2_pclk", "mout_hsi2_bus_user", CLK_CON_GAT_GOUT_BLK_HSI2_UID_SYSREG_HSI2_IPCLKPORT_PCLK, - 21, 0, 0), + 21, CLK_IS_CRITICAL, 0), GATE(CLK_GOUT_HSI2_UASC_PCIE_GEN4A_DBI_1_ACLK, "gout_hsi2_uasc_pcie_gen4a_dbi_1_aclk", "mout_hsi2_bus_user", CLK_CON_GAT_GOUT_BLK_HSI2_UID_UASC_PCIE_GEN4A_DBI_1_IPCLKPORT_ACLK, @@ -2842,7 +2842,7 @@ static const struct samsung_gate_clock hsi2_gate_clks[] __initconst = { GATE(CLK_GOUT_HSI2_UFS_EMBD_I_ACLK, "gout_hsi2_ufs_embd_i_aclk", "mout_hsi2_bus_user", CLK_CON_GAT_GOUT_BLK_HSI2_UID_UFS_EMBD_IPCLKPORT_I_ACLK, - 21, 0, 0), + 21, CLK_IS_CRITICAL, 0), GATE(CLK_GOUT_HSI2_UFS_EMBD_I_CLK_UNIPRO, "gout_hsi2_ufs_embd_i_clk_unipro", "mout_hsi2_ufs_embd_user", CLK_CON_GAT_GOUT_BLK_HSI2_UID_UFS_EMBD_IPCLKPORT_I_CLK_UNIPRO, @@ -2850,7 +2850,7 @@ static const struct samsung_gate_clock hsi2_gate_clks[] __initconst = { GATE(CLK_GOUT_HSI2_UFS_EMBD_I_FMP_CLK, "gout_hsi2_ufs_embd_i_fmp_clk", "mout_hsi2_bus_user", CLK_CON_GAT_GOUT_BLK_HSI2_UID_UFS_EMBD_IPCLKPORT_I_FMP_CLK, - 21, 0, 0), + 21, CLK_IS_CRITICAL, 0), /* TODO: should have a driver for this */ GATE(CLK_GOUT_HSI2_XIU_D_HSI2_ACLK, "gout_hsi2_xiu_d_hsi2_aclk", "mout_hsi2_bus_user", diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index cca3e630922c14..be6b516949193f 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -1370,6 +1370,8 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, break; case pll_1417x: case pll_1418x: + case pll_1051x: + case pll_1052x: case pll_0818x: case pll_0822x: case pll_0516x: diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 3481941ba07a9d..858ab367eb6552 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -43,6 +43,8 @@ enum samsung_pll_type { pll_0517x, pll_0518x, pll_531x, + pll_1051x, + pll_1052x, }; #define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index d27a1f73f077e3..e2ec8fe32e3928 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -3,7 +3,7 @@ * Copyright (c) 2013 Tomasz Figa * * Common Clock Framework support for all S3C64xx SoCs. -*/ + */ #include #include diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c index b31c00ea331f37..d19a3d9fd45239 100644 --- a/drivers/clk/samsung/clk-s5pv210-audss.c +++ b/drivers/clk/samsung/clk-s5pv210-audss.c @@ -8,7 +8,7 @@ * Author: Padmavathi Venna * * Driver for Audio Subsystem Clock Controller of S5PV210-compatible SoCs. -*/ + */ #include #include diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index afa5760ed3a11b..283c523763e6b6 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -6,7 +6,7 @@ * * This file includes utility functions to register clocks to common * clock framework for Samsung platforms. -*/ + */ #include #include diff --git a/drivers/clk/sophgo/clk-sg2042-pll.c b/drivers/clk/sophgo/clk-sg2042-pll.c index ff9deeef509b8f..1537f4f05860ea 100644 --- a/drivers/clk/sophgo/clk-sg2042-pll.c +++ b/drivers/clk/sophgo/clk-sg2042-pll.c @@ -153,7 +153,7 @@ static unsigned long sg2042_pll_recalc_rate(unsigned int reg_value, sg2042_pll_ctrl_decode(reg_value, &ctrl_table); - numerator = parent_rate * ctrl_table.fbdiv; + numerator = (u64)parent_rate * ctrl_table.fbdiv; denominator = ctrl_table.refdiv * ctrl_table.postdiv1 * ctrl_table.postdiv2; do_div(numerator, denominator); return numerator; diff --git a/drivers/clk/starfive/clk-starfive-jh7110-pll.c b/drivers/clk/starfive/clk-starfive-jh7110-pll.c index 3598390e8fd089..56dc58a04f8a9f 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-pll.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-pll.c @@ -453,7 +453,7 @@ static struct clk_hw *jh7110_pll_get(struct of_phandle_args *clkspec, void *data return ERR_PTR(-EINVAL); } -static int jh7110_pll_probe(struct platform_device *pdev) +static int __init jh7110_pll_probe(struct platform_device *pdev) { struct jh7110_pll_priv *priv; unsigned int idx; diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c index de36e21d3eaf16..44b2ebdebdac49 100644 --- a/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c @@ -91,7 +91,7 @@ static struct clk_hw_onecell_data sun20i_d1_r_hw_clks = { }, }; -static struct ccu_reset_map sun20i_d1_r_ccu_resets[] = { +static const struct ccu_reset_map sun20i_d1_r_ccu_resets[] = { [RST_BUS_R_TIMER] = { 0x11c, BIT(16) }, [RST_BUS_R_TWD] = { 0x12c, BIT(16) }, [RST_BUS_R_PPU] = { 0x1ac, BIT(16) }, @@ -137,6 +137,6 @@ static struct platform_driver sun20i_d1_r_ccu_driver = { }; module_platform_driver(sun20i_d1_r_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner D1/R528/T113 PRCM CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c index 9b5cfac2ee70cb..bb66c906ebbb62 100644 --- a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c +++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c @@ -1232,7 +1232,7 @@ static struct clk_hw_onecell_data sun20i_d1_hw_clks = { }, }; -static struct ccu_reset_map sun20i_d1_ccu_resets[] = { +static const struct ccu_reset_map sun20i_d1_ccu_resets[] = { [RST_MBUS] = { 0x540, BIT(30) }, [RST_BUS_DE] = { 0x60c, BIT(16) }, [RST_BUS_DI] = { 0x62c, BIT(16) }, @@ -1371,7 +1371,7 @@ static int sun20i_d1_ccu_probe(struct platform_device *pdev) /* Enforce m1 = 0, m0 = 0 for PLL_AUDIO0 */ val = readl(reg + SUN20I_D1_PLL_AUDIO0_REG); - val &= ~BIT(1) | BIT(0); + val &= ~(BIT(1) | BIT(0)); writel(val, reg + SUN20I_D1_PLL_AUDIO0_REG); /* Force fanout-27M factor N to 0. */ @@ -1406,6 +1406,6 @@ static struct platform_driver sun20i_d1_ccu_driver = { }; module_platform_driver(sun20i_d1_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner D1/R528/T113 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c index d1a1683baff4ec..409feb085021fa 100644 --- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c +++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c @@ -1382,7 +1382,7 @@ static struct clk_hw_onecell_data sun7i_a20_hw_clks = { .num = CLK_NUMBER_SUN7I, }; -static struct ccu_reset_map sunxi_a10_a20_ccu_resets[] = { +static const struct ccu_reset_map sunxi_a10_a20_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_PHY2] = { 0x0cc, BIT(2) }, @@ -1493,6 +1493,6 @@ static struct platform_driver sun4i_a10_ccu_driver = { }; module_platform_driver(sun4i_a10_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A10/A20 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c index 2c791761a6467b..cb0f8d110c3204 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c @@ -166,7 +166,7 @@ static struct clk_hw_onecell_data sun50i_a100_r_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun50i_a100_r_ccu_resets[] = { +static const struct ccu_reset_map sun50i_a100_r_ccu_resets[] = { [RST_R_APB1_TIMER] = { 0x11c, BIT(16) }, [RST_R_APB1_BUS_PWM] = { 0x13c, BIT(16) }, [RST_R_APB1_PPU] = { 0x17c, BIT(16) }, @@ -214,6 +214,6 @@ static struct platform_driver sun50i_a100_r_ccu_driver = { }; module_platform_driver(sun50i_a100_r_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A100 PRCM CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c index bbaa82978716a9..7133377d41630f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c @@ -1061,7 +1061,7 @@ static struct clk_hw_onecell_data sun50i_a100_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun50i_a100_ccu_resets[] = { +static const struct ccu_reset_map sun50i_a100_ccu_resets[] = { [RST_MBUS] = { 0x540, BIT(30) }, [RST_BUS_DE] = { 0x60c, BIT(16) }, @@ -1276,6 +1276,6 @@ static struct platform_driver sun50i_a100_ccu_driver = { }; module_platform_driver(sun50i_a100_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A100 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index c255dba2c96db3..3a7d61c816672d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -858,7 +858,7 @@ static struct clk_hw_onecell_data sun50i_a64_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun50i_a64_ccu_resets[] = { +static const struct ccu_reset_map sun50i_a64_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_HSIC] = { 0x0cc, BIT(2) }, @@ -994,6 +994,6 @@ static struct platform_driver sun50i_a64_ccu_driver = { }; module_platform_driver(sun50i_a64_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A64 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c index c7281584111164..acb4e8b9b1bae9 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c @@ -179,7 +179,7 @@ static struct clk_hw_onecell_data sun50i_h616_r_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun50i_h6_r_ccu_resets[] = { +static const struct ccu_reset_map sun50i_h6_r_ccu_resets[] = { [RST_R_APB1_TIMER] = { 0x11c, BIT(16) }, [RST_R_APB1_TWD] = { 0x12c, BIT(16) }, [RST_R_APB1_PWM] = { 0x13c, BIT(16) }, @@ -190,7 +190,7 @@ static struct ccu_reset_map sun50i_h6_r_ccu_resets[] = { [RST_R_APB1_W1] = { 0x1ec, BIT(16) }, }; -static struct ccu_reset_map sun50i_h616_r_ccu_resets[] = { +static const struct ccu_reset_map sun50i_h616_r_ccu_resets[] = { [RST_R_APB1_TWD] = { 0x12c, BIT(16) }, [RST_R_APB2_I2C] = { 0x19c, BIT(16) }, [RST_R_APB2_RSB] = { 0x1bc, BIT(16) }, @@ -256,6 +256,6 @@ static struct platform_driver sun50i_h6_r_ccu_driver = { }; module_platform_driver(sun50i_h6_r_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner H6 and H616 PRCM CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index a20b621ad8f1d1..7fccda96d4449f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -1076,7 +1076,7 @@ static struct clk_hw_onecell_data sun50i_h6_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun50i_h6_ccu_resets[] = { +static const struct ccu_reset_map sun50i_h6_ccu_resets[] = { [RST_MBUS] = { 0x540, BIT(30) }, [RST_BUS_DE] = { 0x60c, BIT(16) }, @@ -1286,6 +1286,6 @@ static struct platform_driver sun50i_h6_ccu_driver = { }; module_platform_driver(sun50i_h6_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner H6 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c index 84e406ddf9d120..1086669b91da66 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c @@ -216,19 +216,29 @@ static struct ccu_nkmp pll_de_clk = { }; /* - * TODO: Determine SDM settings for the audio PLL. The manual suggests - * PLL_FACTOR_N=16, PLL_POST_DIV_P=2, OUTPUT_DIV=2, pattern=0xe000c49b - * for 24.576 MHz, and PLL_FACTOR_N=22, PLL_POST_DIV_P=3, OUTPUT_DIV=2, - * pattern=0xe001288c for 22.5792 MHz. - * This clashes with our fixed PLL_POST_DIV_P. + * Sigma-delta modulation settings table obtained from the vendor SDK driver. + * There are additional M0 and M1 divider bits not modelled here, so forced to + * fixed values in the probe routine. Sigma-delta modulation allows providing a + * fractional-N divider in the PLL, to help reaching those specific + * frequencies with less error. */ +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 90316800, .pattern = 0xc001288d, .m = 3, .n = 22 }, + { .rate = 98304000, .pattern = 0xc001eb85, .m = 5, .n = 40 }, +}; + #define SUN50I_H616_PLL_AUDIO_REG 0x078 static struct ccu_nm pll_audio_hs_clk = { .enable = BIT(31), .lock = BIT(28), .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), - .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .m = _SUNXI_CCU_DIV(16, 6), + .sdm = _SUNXI_CCU_SDM(pll_audio_sdm_table, + BIT(24), 0x178, BIT(31)), + .fixed_post_div = 2, .common = { + .features = CCU_FEATURE_FIXED_POSTDIV | + CCU_FEATURE_SIGMA_DELTA_MOD, .reg = 0x078, .hw.init = CLK_HW_INIT("pll-audio-hs", "osc24M", &ccu_nm_ops, @@ -685,18 +695,20 @@ static const struct clk_hw *clk_parent_pll_audio[] = { }; /* - * The divider of pll-audio is fixed to 24 for now, so 24576000 and 22579200 - * rates can be set exactly in conjunction with sigma-delta modulation. + * The PLL_AUDIO_4X clock defaults to 24.5714 MHz according to the manual, with + * a final divider of 1. The 2X and 1X clocks use 2 and 4 respectively. The 1x + * clock is set to either 24576000 or 22579200 for 48Khz and 44.1Khz (and + * multiples). */ static CLK_FIXED_FACTOR_HWS(pll_audio_1x_clk, "pll-audio-1x", clk_parent_pll_audio, - 96, 1, CLK_SET_RATE_PARENT); + 4, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", clk_parent_pll_audio, - 48, 1, CLK_SET_RATE_PARENT); + 2, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", clk_parent_pll_audio, - 24, 1, CLK_SET_RATE_PARENT); + 1, 1, CLK_SET_RATE_PARENT); static const struct clk_hw *pll_periph0_parents[] = { &pll_periph0_clk.common.hw @@ -990,7 +1002,7 @@ static struct clk_hw_onecell_data sun50i_h616_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun50i_h616_ccu_resets[] = { +static const struct ccu_reset_map sun50i_h616_ccu_resets[] = { [RST_MBUS] = { 0x540, BIT(30) }, [RST_BUS_DE] = { 0x60c, BIT(16) }, @@ -1136,12 +1148,14 @@ static int sun50i_h616_ccu_probe(struct platform_device *pdev) } /* - * Force the post-divider of pll-audio to 12 and the output divider - * of it to 2, so 24576000 and 22579200 rates can be set exactly. + * Set the output-divider for the pll-audio clocks (M0) to 2 and the + * input divider (M1) to 1 as recommended by the manual when using + * SDM. */ val = readl(reg + SUN50I_H616_PLL_AUDIO_REG); - val &= ~(GENMASK(21, 16) | BIT(0)); - writel(val | (11 << 16) | BIT(0), reg + SUN50I_H616_PLL_AUDIO_REG); + val &= ~BIT(1); + val |= BIT(0); + writel(val, reg + SUN50I_H616_PLL_AUDIO_REG); /* * First clock parent (osc32K) is unusable for CEC. But since there @@ -1171,6 +1185,6 @@ static struct platform_driver sun50i_h616_ccu_driver = { }; module_platform_driver(sun50i_h616_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner H616 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c index 1f4bc0e773a7ed..c9bf1fdb8a8a5f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun5i.c +++ b/drivers/clk/sunxi-ng/ccu-sun5i.c @@ -731,7 +731,7 @@ static struct clk_hw_onecell_data sun5i_a10s_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun5i_a10s_ccu_resets[] = { +static const struct ccu_reset_map sun5i_a10s_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index e8b8d2dd7f2cce..bab65cfe9501d7 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -1146,7 +1146,7 @@ static struct clk_hw_onecell_data sun6i_a31_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun6i_a31_ccu_resets[] = { +static const struct ccu_reset_map sun6i_a31_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_PHY2] = { 0x0cc, BIT(2) }, @@ -1283,6 +1283,6 @@ static struct platform_driver sun6i_a31_ccu_driver = { }; module_platform_driver(sun6i_a31_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A31/A31s CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c index 87e23d16ed0f37..0536e880b80fe1 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c @@ -356,7 +356,7 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg) const char *fw_name; /* ext-osc32k was the only input clock in the old binding. */ - fw_name = of_property_read_bool(dev->of_node, "clock-names") + fw_name = of_property_present(dev->of_node, "clock-names") ? "ext-osc32k" : NULL; ext_osc32k_clk = devm_clk_get_optional(dev, fw_name); if (IS_ERR(ext_osc32k_clk)) @@ -381,6 +381,6 @@ int sun6i_rtc_ccu_probe(struct device *dev, void __iomem *reg) return devm_sunxi_ccu_probe(dev, reg, &sun6i_rtc_ccu_desc); } -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner H616/R329 RTC CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index 6c2a08f722a84a..78cf3818ab09a5 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -668,7 +668,7 @@ static struct clk_hw_onecell_data sun8i_a23_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun8i_a23_ccu_resets[] = { +static const struct ccu_reset_map sun8i_a23_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_HSIC] = { 0x0cc, BIT(2) }, @@ -763,6 +763,6 @@ static struct platform_driver sun8i_a23_ccu_driver = { }; module_platform_driver(sun8i_a23_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A23 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c index 5e0bc08a9ce3c5..b039d419512ce8 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c @@ -712,7 +712,7 @@ static struct clk_hw_onecell_data sun8i_a33_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun8i_a33_ccu_resets[] = { +static const struct ccu_reset_map sun8i_a33_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_HSIC] = { 0x0cc, BIT(2) }, @@ -835,6 +835,6 @@ static struct platform_driver sun8i_a33_ccu_driver = { }; module_platform_driver(sun8i_a33_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A33 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index cb4c6b16c46771..60e918965a7208 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -797,7 +797,7 @@ static struct clk_hw_onecell_data sun8i_a83t_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun8i_a83t_ccu_resets[] = { +static const struct ccu_reset_map sun8i_a83t_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_HSIC] = { 0x0cc, BIT(2) }, @@ -923,6 +923,6 @@ static struct platform_driver sun8i_a83t_ccu_driver = { }; module_platform_driver(sun8i_a83t_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A83T CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 7683ea08d8e30a..f2aa71206bc207 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -146,7 +146,7 @@ static struct clk_hw_onecell_data sun50i_a64_de2_hw_clks = { .num = CLK_NUMBER_WITH_ROT, }; -static struct ccu_reset_map sun8i_a83t_de2_resets[] = { +static const struct ccu_reset_map sun8i_a83t_de2_resets[] = { [RST_MIXER0] = { 0x08, BIT(0) }, /* * Mixer1 reset line is shared with wb, so only RST_WB is @@ -156,7 +156,7 @@ static struct ccu_reset_map sun8i_a83t_de2_resets[] = { [RST_ROT] = { 0x08, BIT(3) }, }; -static struct ccu_reset_map sun8i_h3_de2_resets[] = { +static const struct ccu_reset_map sun8i_h3_de2_resets[] = { [RST_MIXER0] = { 0x08, BIT(0) }, /* * Mixer1 reset line is shared with wb, so only RST_WB is @@ -166,14 +166,14 @@ static struct ccu_reset_map sun8i_h3_de2_resets[] = { [RST_WB] = { 0x08, BIT(2) }, }; -static struct ccu_reset_map sun50i_a64_de2_resets[] = { +static const struct ccu_reset_map sun50i_a64_de2_resets[] = { [RST_MIXER0] = { 0x08, BIT(0) }, [RST_MIXER1] = { 0x08, BIT(1) }, [RST_WB] = { 0x08, BIT(2) }, [RST_ROT] = { 0x08, BIT(3) }, }; -static struct ccu_reset_map sun50i_h5_de2_resets[] = { +static const struct ccu_reset_map sun50i_h5_de2_resets[] = { [RST_MIXER0] = { 0x08, BIT(0) }, [RST_MIXER1] = { 0x08, BIT(1) }, [RST_WB] = { 0x08, BIT(2) }, @@ -348,6 +348,6 @@ static struct platform_driver sunxi_de2_clk_driver = { }; module_platform_driver(sunxi_de2_clk_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner SoCs DE2 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 13e57db2f8d555..740c4c97331c1a 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -876,7 +876,7 @@ static struct clk_hw_onecell_data sun50i_h5_hw_clks = { .num = CLK_NUMBER_H5, }; -static struct ccu_reset_map sun8i_h3_ccu_resets[] = { +static const struct ccu_reset_map sun8i_h3_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_PHY2] = { 0x0cc, BIT(2) }, @@ -939,7 +939,7 @@ static struct ccu_reset_map sun8i_h3_ccu_resets[] = { [RST_BUS_SCR0] = { 0x2d8, BIT(20) }, }; -static struct ccu_reset_map sun50i_h5_ccu_resets[] = { +static const struct ccu_reset_map sun50i_h5_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_PHY2] = { 0x0cc, BIT(2) }, @@ -1094,6 +1094,6 @@ static struct platform_driver sun8i_h3_ccu_driver = { }; module_platform_driver(sun8i_h3_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner H3 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c index da6569334d68b4..0e324344673b61 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c @@ -178,7 +178,7 @@ static struct clk_hw_onecell_data sun50i_a64_r_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun8i_a83t_r_ccu_resets[] = { +static const struct ccu_reset_map sun8i_a83t_r_ccu_resets[] = { [RST_APB0_IR] = { 0xb0, BIT(1) }, [RST_APB0_TIMER] = { 0xb0, BIT(2) }, [RST_APB0_RSB] = { 0xb0, BIT(3) }, @@ -186,14 +186,14 @@ static struct ccu_reset_map sun8i_a83t_r_ccu_resets[] = { [RST_APB0_I2C] = { 0xb0, BIT(6) }, }; -static struct ccu_reset_map sun8i_h3_r_ccu_resets[] = { +static const struct ccu_reset_map sun8i_h3_r_ccu_resets[] = { [RST_APB0_IR] = { 0xb0, BIT(1) }, [RST_APB0_TIMER] = { 0xb0, BIT(2) }, [RST_APB0_UART] = { 0xb0, BIT(4) }, [RST_APB0_I2C] = { 0xb0, BIT(6) }, }; -static struct ccu_reset_map sun50i_a64_r_ccu_resets[] = { +static const struct ccu_reset_map sun50i_a64_r_ccu_resets[] = { [RST_APB0_IR] = { 0xb0, BIT(1) }, [RST_APB0_TIMER] = { 0xb0, BIT(2) }, [RST_APB0_RSB] = { 0xb0, BIT(3) }, @@ -274,6 +274,6 @@ static struct platform_driver sun8i_r_ccu_driver = { }; module_platform_driver(sun8i_r_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for Allwinner SoCs' PRCM CCUs"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index 2f51ceab8016f8..8b729c9b3545c8 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -1162,7 +1162,7 @@ static struct clk_hw_onecell_data sun8i_r40_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun8i_r40_ccu_resets[] = { +static const struct ccu_reset_map sun8i_r40_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_USB_PHY1] = { 0x0cc, BIT(1) }, [RST_USB_PHY2] = { 0x0cc, BIT(2) }, @@ -1375,6 +1375,6 @@ static struct platform_driver sun8i_r40_ccu_driver = { }; module_platform_driver(sun8i_r40_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner R40 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c index d24c0d8dfee4cc..579a81bb46df39 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c @@ -644,7 +644,7 @@ static struct clk_hw_onecell_data sun8i_v3_hw_clks = { .num = CLK_I2S0 + 1, }; -static struct ccu_reset_map sun8i_v3s_ccu_resets[] = { +static const struct ccu_reset_map sun8i_v3s_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_MBUS] = { 0x0fc, BIT(31) }, @@ -679,7 +679,7 @@ static struct ccu_reset_map sun8i_v3s_ccu_resets[] = { [RST_BUS_UART2] = { 0x2d8, BIT(18) }, }; -static struct ccu_reset_map sun8i_v3_ccu_resets[] = { +static const struct ccu_reset_map sun8i_v3_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_MBUS] = { 0x0fc, BIT(31) }, @@ -780,6 +780,6 @@ static struct platform_driver sun8i_v3s_ccu_driver = { }; module_platform_driver(sun8i_v3s_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner V3s CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c index 0975ac58949f45..91e5dc448bc0ed 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c @@ -177,7 +177,7 @@ static struct clk_hw_onecell_data sun9i_a80_de_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun9i_a80_de_resets[] = { +static const struct ccu_reset_map sun9i_a80_de_resets[] = { [RST_FE0] = { 0x0c, BIT(0) }, [RST_FE1] = { 0x0c, BIT(1) }, [RST_FE2] = { 0x0c, BIT(2) }, @@ -266,6 +266,6 @@ static struct platform_driver sun9i_a80_de_clk_driver = { }; module_platform_driver(sun9i_a80_de_clk_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A80 Display Engine CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c index e5527c8cc64ff4..62063f525616da 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c @@ -68,7 +68,7 @@ static struct clk_hw_onecell_data sun9i_a80_usb_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun9i_a80_usb_resets[] = { +static const struct ccu_reset_map sun9i_a80_usb_resets[] = { [RST_USB0_HCI] = { 0x0, BIT(17) }, [RST_USB1_HCI] = { 0x0, BIT(18) }, [RST_USB2_HCI] = { 0x0, BIT(19) }, @@ -138,6 +138,6 @@ static struct platform_driver sun9i_a80_usb_clk_driver = { }; module_platform_driver(sun9i_a80_usb_clk_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A80 USB CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c index 756dd8fca6b0a4..3377519980051d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c @@ -1108,7 +1108,7 @@ static struct clk_hw_onecell_data sun9i_a80_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map sun9i_a80_ccu_resets[] = { +static const struct ccu_reset_map sun9i_a80_ccu_resets[] = { /* AHB0 reset controls */ [RST_BUS_FD] = { 0x5a0, BIT(0) }, [RST_BUS_VE] = { 0x5a0, BIT(1) }, @@ -1248,6 +1248,6 @@ static struct platform_driver sun9i_a80_ccu_driver = { }; module_platform_driver(sun9i_a80_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner A80 CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c index 52f1a04269f8c1..35935423145e80 100644 --- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c +++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c @@ -477,7 +477,7 @@ static struct clk_hw_onecell_data suniv_hw_clks = { .num = CLK_NUMBER, }; -static struct ccu_reset_map suniv_ccu_resets[] = { +static const struct ccu_reset_map suniv_ccu_resets[] = { [RST_USB_PHY0] = { 0x0cc, BIT(0) }, [RST_BUS_DMA] = { 0x2c0, BIT(6) }, @@ -577,6 +577,6 @@ static struct platform_driver suniv_f1c100s_ccu_driver = { }; module_platform_driver(suniv_f1c100s_ccu_driver); -MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_IMPORT_NS("SUNXI_CCU"); MODULE_DESCRIPTION("Support for the Allwinner newer F1C100s CCU"); MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index 4117b0bea26712..88ed89658d4579 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -37,7 +37,7 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000)); } -EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, "SUNXI_CCU"); bool ccu_is_better_rate(struct ccu_common *common, unsigned long target_rate, @@ -59,7 +59,7 @@ bool ccu_is_better_rate(struct ccu_common *common, return current_rate <= target_rate && current_rate > best_rate; } -EXPORT_SYMBOL_NS_GPL(ccu_is_better_rate, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_is_better_rate, "SUNXI_CCU"); /* * This clock notifier is called when the frequency of a PLL clock is @@ -107,7 +107,7 @@ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb) return clk_notifier_register(pll_nb->common->hw.clk, &pll_nb->clk_nb); } -EXPORT_SYMBOL_NS_GPL(ccu_pll_notifier_register, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_pll_notifier_register, "SUNXI_CCU"); static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev, struct device_node *node, void __iomem *reg, @@ -234,7 +234,7 @@ int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg, return 0; } -EXPORT_SYMBOL_NS_GPL(devm_sunxi_ccu_probe, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(devm_sunxi_ccu_probe, "SUNXI_CCU"); void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg, const struct sunxi_ccu_desc *desc) diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h index 329734f8cf42b4..dd330426a6e5f3 100644 --- a/drivers/clk/sunxi-ng/ccu_common.h +++ b/drivers/clk/sunxi-ng/ccu_common.h @@ -50,7 +50,7 @@ struct sunxi_ccu_desc { struct clk_hw_onecell_data *hw_clks; - struct ccu_reset_map *resets; + const struct ccu_reset_map *resets; unsigned long num_resets; }; diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c index cb10a3ea23f9f0..7f4691f09e01fc 100644 --- a/drivers/clk/sunxi-ng/ccu_div.c +++ b/drivers/clk/sunxi-ng/ccu_div.c @@ -141,4 +141,4 @@ const struct clk_ops ccu_div_ops = { .recalc_rate = ccu_div_recalc_rate, .set_rate = ccu_div_set_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_div_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_div_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_frac.c b/drivers/clk/sunxi-ng/ccu_frac.c index b31f3ad946d6ad..75323912608a3b 100644 --- a/drivers/clk/sunxi-ng/ccu_frac.c +++ b/drivers/clk/sunxi-ng/ccu_frac.c @@ -18,7 +18,7 @@ bool ccu_frac_helper_is_enabled(struct ccu_common *common, return !(readl(common->base + common->reg) & cf->enable); } -EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_is_enabled, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_is_enabled, "SUNXI_CCU"); void ccu_frac_helper_enable(struct ccu_common *common, struct ccu_frac_internal *cf) @@ -34,7 +34,7 @@ void ccu_frac_helper_enable(struct ccu_common *common, writel(reg & ~cf->enable, common->base + common->reg); spin_unlock_irqrestore(common->lock, flags); } -EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_enable, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_enable, "SUNXI_CCU"); void ccu_frac_helper_disable(struct ccu_common *common, struct ccu_frac_internal *cf) @@ -50,7 +50,7 @@ void ccu_frac_helper_disable(struct ccu_common *common, writel(reg | cf->enable, common->base + common->reg); spin_unlock_irqrestore(common->lock, flags); } -EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_disable, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_disable, "SUNXI_CCU"); bool ccu_frac_helper_has_rate(struct ccu_common *common, struct ccu_frac_internal *cf, @@ -61,7 +61,7 @@ bool ccu_frac_helper_has_rate(struct ccu_common *common, return (cf->rates[0] == rate) || (cf->rates[1] == rate); } -EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_has_rate, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_has_rate, "SUNXI_CCU"); unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, struct ccu_frac_internal *cf) @@ -83,7 +83,7 @@ unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, return (reg & cf->select) ? cf->rates[1] : cf->rates[0]; } -EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_read_rate, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_read_rate, "SUNXI_CCU"); int ccu_frac_helper_set_rate(struct ccu_common *common, struct ccu_frac_internal *cf, @@ -112,4 +112,4 @@ int ccu_frac_helper_set_rate(struct ccu_common *common, return 0; } -EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_set_rate, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_set_rate, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c index a2115a21807d17..ac52fd6bff6776 100644 --- a/drivers/clk/sunxi-ng/ccu_gate.c +++ b/drivers/clk/sunxi-ng/ccu_gate.c @@ -24,7 +24,7 @@ void ccu_gate_helper_disable(struct ccu_common *common, u32 gate) spin_unlock_irqrestore(common->lock, flags); } -EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, "SUNXI_CCU"); static void ccu_gate_disable(struct clk_hw *hw) { @@ -50,7 +50,7 @@ int ccu_gate_helper_enable(struct ccu_common *common, u32 gate) return 0; } -EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, "SUNXI_CCU"); static int ccu_gate_enable(struct clk_hw *hw) { @@ -66,7 +66,7 @@ int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate) return readl(common->base + common->reg) & gate; } -EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, "SUNXI_CCU"); static int ccu_gate_is_enabled(struct clk_hw *hw) { @@ -127,4 +127,4 @@ const struct clk_ops ccu_gate_ops = { .set_rate = ccu_gate_set_rate, .recalc_rate = ccu_gate_recalc_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_gate_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_gate_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c index cc94a694cb676c..2bb8987ddcc205 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.c +++ b/drivers/clk/sunxi-ng/ccu_mp.c @@ -246,7 +246,7 @@ const struct clk_ops ccu_mp_ops = { .recalc_rate = ccu_mp_recalc_rate, .set_rate = ccu_mp_set_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_mp_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mp_ops, "SUNXI_CCU"); /* * Support for MMC timing mode switching @@ -327,4 +327,4 @@ const struct clk_ops ccu_mp_mmc_ops = { .recalc_rate = ccu_mp_mmc_recalc_rate, .set_rate = ccu_mp_mmc_set_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_mp_mmc_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mp_mmc_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_mult.c b/drivers/clk/sunxi-ng/ccu_mult.c index 7bee217ef1116b..8d5720f3dec1d4 100644 --- a/drivers/clk/sunxi-ng/ccu_mult.c +++ b/drivers/clk/sunxi-ng/ccu_mult.c @@ -170,4 +170,4 @@ const struct clk_ops ccu_mult_ops = { .recalc_rate = ccu_mult_recalc_rate, .set_rate = ccu_mult_set_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_mult_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mult_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 5edc63b466516c..d7ffbdeee9e047 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -66,7 +66,7 @@ unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common, { return parent_rate / ccu_mux_get_prediv(common, cm, parent_index); } -EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_apply_prediv, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_apply_prediv, "SUNXI_CCU"); static unsigned long ccu_mux_helper_unapply_prediv(struct ccu_common *common, struct ccu_mux_internal *cm, @@ -155,7 +155,7 @@ int ccu_mux_helper_determine_rate(struct ccu_common *common, req->rate = best_rate; return 0; } -EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_determine_rate, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_determine_rate, "SUNXI_CCU"); u8 ccu_mux_helper_get_parent(struct ccu_common *common, struct ccu_mux_internal *cm) @@ -178,7 +178,7 @@ u8 ccu_mux_helper_get_parent(struct ccu_common *common, return parent; } -EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_get_parent, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_get_parent, "SUNXI_CCU"); int ccu_mux_helper_set_parent(struct ccu_common *common, struct ccu_mux_internal *cm, @@ -205,7 +205,7 @@ int ccu_mux_helper_set_parent(struct ccu_common *common, return 0; } -EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_set_parent, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_set_parent, "SUNXI_CCU"); static void ccu_mux_disable(struct clk_hw *hw) { @@ -273,7 +273,7 @@ const struct clk_ops ccu_mux_ops = { .determine_rate = ccu_mux_determine_rate, .recalc_rate = ccu_mux_recalc_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, "SUNXI_CCU"); /* * This clock notifier is called when the frequency of the of the parent @@ -308,4 +308,4 @@ int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb) return clk_notifier_register(clk, &mux_nb->clk_nb); } -EXPORT_SYMBOL_NS_GPL(ccu_mux_notifier_register, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_mux_notifier_register, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c index 8aa35d5804f303..555e99de2cc6ee 100644 --- a/drivers/clk/sunxi-ng/ccu_nk.c +++ b/drivers/clk/sunxi-ng/ccu_nk.c @@ -158,4 +158,4 @@ const struct clk_ops ccu_nk_ops = { .round_rate = ccu_nk_round_rate, .set_rate = ccu_nk_set_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_nk_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_nk_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index 1168d894d636bf..784eec9ac9979b 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -267,4 +267,4 @@ const struct clk_ops ccu_nkm_ops = { .recalc_rate = ccu_nkm_recalc_rate, .set_rate = ccu_nkm_set_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_nkm_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_nkm_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index 99359a06892d47..6e03b69d402848 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -230,4 +230,4 @@ const struct clk_ops ccu_nkmp_ops = { .round_rate = ccu_nkmp_round_rate, .set_rate = ccu_nkmp_set_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_nkmp_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_nkmp_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index ffac3deb89d662..a4e2243b8d6b4a 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -236,4 +236,4 @@ const struct clk_ops ccu_nm_ops = { .round_rate = ccu_nm_round_rate, .set_rate = ccu_nm_set_rate, }; -EXPORT_SYMBOL_NS_GPL(ccu_nm_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_nm_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_phase.c b/drivers/clk/sunxi-ng/ccu_phase.c index e4cae2afe9db9d..ca43cf448666bd 100644 --- a/drivers/clk/sunxi-ng/ccu_phase.c +++ b/drivers/clk/sunxi-ng/ccu_phase.c @@ -121,4 +121,4 @@ const struct clk_ops ccu_phase_ops = { .get_phase = ccu_phase_get_phase, .set_phase = ccu_phase_set_phase, }; -EXPORT_SYMBOL_NS_GPL(ccu_phase_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_phase_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_reset.c b/drivers/clk/sunxi-ng/ccu_reset.c index 6577aa18cb01e3..55bc7c7cda0fcf 100644 --- a/drivers/clk/sunxi-ng/ccu_reset.c +++ b/drivers/clk/sunxi-ng/ccu_reset.c @@ -75,4 +75,4 @@ const struct reset_control_ops ccu_reset_ops = { .reset = ccu_reset_reset, .status = ccu_reset_status, }; -EXPORT_SYMBOL_NS_GPL(ccu_reset_ops, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_reset_ops, "SUNXI_CCU"); diff --git a/drivers/clk/sunxi-ng/ccu_reset.h b/drivers/clk/sunxi-ng/ccu_reset.h index e9b973cae4af9a..941276a8ec2ee3 100644 --- a/drivers/clk/sunxi-ng/ccu_reset.h +++ b/drivers/clk/sunxi-ng/ccu_reset.h @@ -17,7 +17,7 @@ struct ccu_reset_map { struct ccu_reset { void __iomem *base; - struct ccu_reset_map *reset_map; + const struct ccu_reset_map *reset_map; spinlock_t *lock; struct reset_controller_dev rcdev; diff --git a/drivers/clk/sunxi-ng/ccu_sdm.c b/drivers/clk/sunxi-ng/ccu_sdm.c index 41937ed0766dbf..c564e5f9e61040 100644 --- a/drivers/clk/sunxi-ng/ccu_sdm.c +++ b/drivers/clk/sunxi-ng/ccu_sdm.c @@ -20,7 +20,7 @@ bool ccu_sdm_helper_is_enabled(struct ccu_common *common, return !!(readl(common->base + sdm->tuning_reg) & sdm->tuning_enable); } -EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_is_enabled, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_is_enabled, "SUNXI_CCU"); void ccu_sdm_helper_enable(struct ccu_common *common, struct ccu_sdm_internal *sdm, @@ -50,7 +50,7 @@ void ccu_sdm_helper_enable(struct ccu_common *common, writel(reg | sdm->enable, common->base + common->reg); spin_unlock_irqrestore(common->lock, flags); } -EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_enable, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_enable, "SUNXI_CCU"); void ccu_sdm_helper_disable(struct ccu_common *common, struct ccu_sdm_internal *sdm) @@ -71,7 +71,7 @@ void ccu_sdm_helper_disable(struct ccu_common *common, writel(reg & ~sdm->tuning_enable, common->base + sdm->tuning_reg); spin_unlock_irqrestore(common->lock, flags); } -EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_disable, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_disable, "SUNXI_CCU"); /* * Sigma delta modulation provides a way to do fractional-N frequency @@ -105,7 +105,7 @@ bool ccu_sdm_helper_has_rate(struct ccu_common *common, return false; } -EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_has_rate, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_has_rate, "SUNXI_CCU"); unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common, struct ccu_sdm_internal *sdm, @@ -136,7 +136,7 @@ unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common, /* We can't calculate the effective clock rate, so just fail. */ return 0; } -EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_read_rate, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_read_rate, "SUNXI_CCU"); int ccu_sdm_helper_get_factors(struct ccu_common *common, struct ccu_sdm_internal *sdm, @@ -158,4 +158,4 @@ int ccu_sdm_helper_get_factors(struct ccu_common *common, /* nothing found */ return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_get_factors, SUNXI_CCU); +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_get_factors, "SUNXI_CCU"); diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index 7bfba0afd77831..b2323cb8eddcce 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -174,7 +174,7 @@ static int tegra_bpmp_clk_determine_rate(struct clk_hw *hw, unsigned long rate; int err; - rate = min(max(rate_req->rate, rate_req->min_rate), rate_req->max_rate); + rate = clamp(rate_req->rate, rate_req->min_rate, rate_req->max_rate); memset(&request, 0, sizeof(request)); request.rate = min_t(u64, rate, S64_MAX); diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index 7a0269bdfbb385..b2233d3ff9a99d 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -121,26 +122,24 @@ enum clk_wzrd_int_clks { /** * struct clk_wzrd - Clock wizard private data structure * - * @clk_data: Clock data * @nb: Notifier block * @base: Memory base * @clk_in1: Handle to input clock 'clk_in1' * @axi_clk: Handle to input clock 's_axi_aclk' * @clks_internal: Internal clocks - * @clkout: Output clocks * @speed_grade: Speed grade of the device * @suspended: Flag indicating power state of the device + * @clk_data: Output clock data */ struct clk_wzrd { - struct clk_onecell_data clk_data; struct notifier_block nb; void __iomem *base; struct clk *clk_in1; struct clk *axi_clk; - struct clk *clks_internal[wzrd_clk_int_max]; - struct clk *clkout[WZRD_NUM_OUTPUTS]; + struct clk_hw *clks_internal[wzrd_clk_int_max]; unsigned int speed_grade; bool suspended; + struct clk_hw_onecell_data clk_data; }; /** @@ -765,7 +764,7 @@ static const struct clk_ops clk_wzrd_clk_divider_ops_f = { .recalc_rate = clk_wzrd_recalc_ratef, }; -static struct clk *clk_wzrd_register_divf(struct device *dev, +static struct clk_hw *clk_wzrd_register_divf(struct device *dev, const char *name, const char *parent_name, unsigned long flags, @@ -805,10 +804,10 @@ static struct clk *clk_wzrd_register_divf(struct device *dev, if (ret) return ERR_PTR(ret); - return hw->clk; + return hw; } -static struct clk *clk_wzrd_ver_register_divider(struct device *dev, +static struct clk_hw *clk_wzrd_ver_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, @@ -852,10 +851,10 @@ static struct clk *clk_wzrd_ver_register_divider(struct device *dev, if (ret) return ERR_PTR(ret); - return hw->clk; + return hw; } -static struct clk *clk_wzrd_register_divider(struct device *dev, +static struct clk_hw *clk_wzrd_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, @@ -898,7 +897,7 @@ static struct clk *clk_wzrd_register_divider(struct device *dev, if (ret) return ERR_PTR(ret); - return hw->clk; + return hw; } static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event, @@ -963,81 +962,30 @@ static const struct versal_clk_data versal_data = { .is_versal = true, }; -static int clk_wzrd_probe(struct platform_device *pdev) +static int clk_wzrd_register_output_clocks(struct device *dev, int nr_outputs) { const char *clkout_name, *clk_name, *clk_mul_name; + struct clk_wzrd *clk_wzrd = dev_get_drvdata(dev); u32 regl, regh, edge, regld, reghd, edged, div; - struct device_node *np = pdev->dev.of_node; const struct versal_clk_data *data; - struct clk_wzrd *clk_wzrd; unsigned long flags = 0; + bool is_versal = false; void __iomem *ctrl_reg; u32 reg, reg_f, mult; - bool is_versal = false; - unsigned long rate; - int nr_outputs; - int i, ret; - - clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL); - if (!clk_wzrd) - return -ENOMEM; - platform_set_drvdata(pdev, clk_wzrd); - - clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(clk_wzrd->base)) - return PTR_ERR(clk_wzrd->base); - - ret = of_property_read_u32(np, "xlnx,speed-grade", &clk_wzrd->speed_grade); - if (!ret) { - if (clk_wzrd->speed_grade < 1 || clk_wzrd->speed_grade > 3) { - dev_warn(&pdev->dev, "invalid speed grade '%d'\n", - clk_wzrd->speed_grade); - clk_wzrd->speed_grade = 0; - } - } - - clk_wzrd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1"); - if (IS_ERR(clk_wzrd->clk_in1)) - return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->clk_in1), - "clk_in1 not found\n"); - - clk_wzrd->axi_clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); - if (IS_ERR(clk_wzrd->axi_clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->axi_clk), - "s_axi_aclk not found\n"); - ret = clk_prepare_enable(clk_wzrd->axi_clk); - if (ret) { - dev_err(&pdev->dev, "enabling s_axi_aclk failed\n"); - return ret; - } - rate = clk_get_rate(clk_wzrd->axi_clk); - if (rate > WZRD_ACLK_MAX_FREQ) { - dev_err(&pdev->dev, "s_axi_aclk frequency (%lu) too high\n", - rate); - ret = -EINVAL; - goto err_disable_clk; - } + int i; - data = device_get_match_data(&pdev->dev); + data = device_get_match_data(dev); if (data) is_versal = data->is_versal; - 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 (!clkout_name) { - ret = -ENOMEM; - goto err_disable_clk; - } + clkout_name = devm_kasprintf(dev, GFP_KERNEL, "%s_out0", dev_name(dev)); + if (!clkout_name) + return -ENOMEM; if (is_versal) { if (nr_outputs == 1) { - clk_wzrd->clkout[0] = clk_wzrd_ver_register_divider - (&pdev->dev, clkout_name, + clk_wzrd->clk_data.hws[0] = clk_wzrd_ver_register_divider + (dev, clkout_name, __clk_get_name(clk_wzrd->clk_in1), 0, clk_wzrd->base, WZRD_CLK_CFG_REG(is_versal, 3), WZRD_CLKOUT_DIVIDE_SHIFT, @@ -1045,7 +993,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, DIV_ALL, &clkwzrd_lock); - goto out; + return 0; } /* register multiplier */ edge = !!(readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0)) & @@ -1069,8 +1017,8 @@ static int clk_wzrd_probe(struct platform_device *pdev) div = 64; } else { if (nr_outputs == 1) { - clk_wzrd->clkout[0] = clk_wzrd_register_divider - (&pdev->dev, clkout_name, + clk_wzrd->clk_data.hws[0] = clk_wzrd_register_divider + (dev, clkout_name, __clk_get_name(clk_wzrd->clk_in1), 0, clk_wzrd->base, WZRD_CLK_CFG_REG(is_versal, 3), WZRD_CLKOUT_DIVIDE_SHIFT, @@ -1078,7 +1026,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, DIV_ALL, &clkwzrd_lock); - goto out; + return 0; } reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0)); reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK; @@ -1089,26 +1037,21 @@ static int clk_wzrd_probe(struct platform_device *pdev) mult = (reg * 1000) + reg_f; div = 1000; } - clk_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_mul", dev_name(&pdev->dev)); - if (!clk_name) { - ret = -ENOMEM; - goto err_disable_clk; - } - clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor - (&pdev->dev, clk_name, + clk_name = devm_kasprintf(dev, GFP_KERNEL, "%s_mul", dev_name(dev)); + if (!clk_name) + return -ENOMEM; + clk_wzrd->clks_internal[wzrd_clk_mul] = devm_clk_hw_register_fixed_factor + (dev, clk_name, __clk_get_name(clk_wzrd->clk_in1), 0, mult, div); if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul])) { - dev_err(&pdev->dev, "unable to register fixed-factor clock\n"); - ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul]); - goto err_disable_clk; + dev_err(dev, "unable to register fixed-factor clock\n"); + return PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul]); } - 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; - } + clk_name = devm_kasprintf(dev, GFP_KERNEL, "%s_mul_div", dev_name(dev)); + if (!clk_name) + return -ENOMEM; if (is_versal) { edged = !!(readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 20)) & @@ -1121,36 +1064,31 @@ static int clk_wzrd_probe(struct platform_device *pdev) if (!div) div = 1; - clk_mul_name = __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]); + clk_mul_name = clk_hw_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]); clk_wzrd->clks_internal[wzrd_clk_mul_div] = - clk_register_fixed_factor(&pdev->dev, clk_name, - clk_mul_name, 0, 1, div); + devm_clk_hw_register_fixed_factor(dev, clk_name, clk_mul_name, 0, 1, div); } else { ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0); - clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider - (&pdev->dev, clk_name, - __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]), + clk_wzrd->clks_internal[wzrd_clk_mul_div] = devm_clk_hw_register_divider + (dev, clk_name, + clk_hw_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]), flags, ctrl_reg, 0, 8, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, &clkwzrd_lock); } if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div])) { - dev_err(&pdev->dev, "unable to register divider clock\n"); - ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]); - goto err_rm_int_clk; + dev_err(dev, "unable to register divider clock\n"); + return PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]); } /* register div per output */ for (i = nr_outputs - 1; i >= 0 ; 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; - } + clkout_name = devm_kasprintf(dev, GFP_KERNEL, "%s_out%d", dev_name(dev), i); + if (!clkout_name) + return -ENOMEM; if (is_versal) { - clk_wzrd->clkout[i] = clk_wzrd_ver_register_divider - (&pdev->dev, + clk_wzrd->clk_data.hws[i] = clk_wzrd_ver_register_divider + (dev, clkout_name, clk_name, 0, clk_wzrd->base, (WZRD_CLK_CFG_REG(is_versal, 3) + i * 8), @@ -1161,84 +1099,108 @@ static int clk_wzrd_probe(struct platform_device *pdev) DIV_O, &clkwzrd_lock); } else { if (!i) - clk_wzrd->clkout[i] = clk_wzrd_register_divf - (&pdev->dev, clkout_name, clk_name, flags, clk_wzrd->base, + clk_wzrd->clk_data.hws[i] = clk_wzrd_register_divf + (dev, clkout_name, clk_name, flags, clk_wzrd->base, (WZRD_CLK_CFG_REG(is_versal, 2) + i * 12), WZRD_CLKOUT_DIVIDE_SHIFT, WZRD_CLKOUT_DIVIDE_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, DIV_O, &clkwzrd_lock); else - clk_wzrd->clkout[i] = clk_wzrd_register_divider - (&pdev->dev, clkout_name, clk_name, 0, clk_wzrd->base, + clk_wzrd->clk_data.hws[i] = clk_wzrd_register_divider + (dev, clkout_name, clk_name, 0, clk_wzrd->base, (WZRD_CLK_CFG_REG(is_versal, 2) + i * 12), WZRD_CLKOUT_DIVIDE_SHIFT, WZRD_CLKOUT_DIVIDE_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, DIV_O, &clkwzrd_lock); } - if (IS_ERR(clk_wzrd->clkout[i])) { - int j; - - for (j = i + 1; j < nr_outputs; j++) - clk_unregister(clk_wzrd->clkout[j]); - dev_err(&pdev->dev, - "unable to register divider clock\n"); - ret = PTR_ERR(clk_wzrd->clkout[i]); - goto err_rm_int_clks; + if (IS_ERR(clk_wzrd->clk_data.hws[i])) { + dev_err(dev, "unable to register divider clock\n"); + return PTR_ERR(clk_wzrd->clk_data.hws[i]); } } -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); + return 0; +} - if (clk_wzrd->speed_grade) { - clk_wzrd->nb.notifier_call = clk_wzrd_clk_notifier; +static int clk_wzrd_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct clk_wzrd *clk_wzrd; + unsigned long rate; + int nr_outputs; + int ret; - ret = clk_notifier_register(clk_wzrd->clk_in1, - &clk_wzrd->nb); - if (ret) - dev_warn(&pdev->dev, - "unable to register clock notifier\n"); + ret = of_property_read_u32(np, "xlnx,nr-outputs", &nr_outputs); + if (ret || nr_outputs > WZRD_NUM_OUTPUTS) + return -EINVAL; - ret = clk_notifier_register(clk_wzrd->axi_clk, &clk_wzrd->nb); - if (ret) - dev_warn(&pdev->dev, - "unable to register clock notifier\n"); - } + clk_wzrd = devm_kzalloc(&pdev->dev, struct_size(clk_wzrd, clk_data.hws, nr_outputs), + GFP_KERNEL); + if (!clk_wzrd) + return -ENOMEM; + platform_set_drvdata(pdev, clk_wzrd); - return 0; + clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(clk_wzrd->base)) + return PTR_ERR(clk_wzrd->base); -err_rm_int_clks: - clk_unregister(clk_wzrd->clks_internal[1]); -err_rm_int_clk: - clk_unregister(clk_wzrd->clks_internal[0]); -err_disable_clk: - clk_disable_unprepare(clk_wzrd->axi_clk); + clk_wzrd->axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk"); + if (IS_ERR(clk_wzrd->axi_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->axi_clk), + "s_axi_aclk not found\n"); + rate = clk_get_rate(clk_wzrd->axi_clk); + if (rate > WZRD_ACLK_MAX_FREQ) { + dev_err(&pdev->dev, "s_axi_aclk frequency (%lu) too high\n", rate); + return -EINVAL; + } - return ret; -} + if (!of_property_present(np, "xlnx,static-config")) { + ret = of_property_read_u32(np, "xlnx,speed-grade", &clk_wzrd->speed_grade); + if (!ret) { + if (clk_wzrd->speed_grade < 1 || clk_wzrd->speed_grade > 3) { + dev_warn(&pdev->dev, "invalid speed grade '%d'\n", + clk_wzrd->speed_grade); + clk_wzrd->speed_grade = 0; + } + } -static void clk_wzrd_remove(struct platform_device *pdev) -{ - int i; - struct clk_wzrd *clk_wzrd = platform_get_drvdata(pdev); + clk_wzrd->clk_in1 = devm_clk_get(&pdev->dev, "clk_in1"); + if (IS_ERR(clk_wzrd->clk_in1)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk_wzrd->clk_in1), + "clk_in1 not found\n"); + + ret = clk_wzrd_register_output_clocks(&pdev->dev, nr_outputs); + if (ret) + return ret; + + clk_wzrd->clk_data.num = nr_outputs; + ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get, + &clk_wzrd->clk_data); + if (ret) { + dev_err(&pdev->dev, "unable to register clock provider\n"); + return ret; + } - of_clk_del_provider(pdev->dev.of_node); + if (clk_wzrd->speed_grade) { + clk_wzrd->nb.notifier_call = clk_wzrd_clk_notifier; - for (i = 0; i < WZRD_NUM_OUTPUTS; i++) - clk_unregister(clk_wzrd->clkout[i]); - for (i = 0; i < wzrd_clk_int_max; i++) - clk_unregister(clk_wzrd->clks_internal[i]); + ret = devm_clk_notifier_register(&pdev->dev, clk_wzrd->clk_in1, + &clk_wzrd->nb); + if (ret) + dev_warn(&pdev->dev, + "unable to register clock notifier\n"); - if (clk_wzrd->speed_grade) { - clk_notifier_unregister(clk_wzrd->axi_clk, &clk_wzrd->nb); - clk_notifier_unregister(clk_wzrd->clk_in1, &clk_wzrd->nb); + ret = devm_clk_notifier_register(&pdev->dev, clk_wzrd->axi_clk, + &clk_wzrd->nb); + if (ret) + dev_warn(&pdev->dev, + "unable to register clock notifier\n"); + } } - clk_disable_unprepare(clk_wzrd->axi_clk); + return 0; } static const struct of_device_id clk_wzrd_ids[] = { @@ -1257,7 +1219,6 @@ static struct platform_driver clk_wzrd_driver = { .pm = &clk_wzrd_dev_pm_ops, }, .probe = clk_wzrd_probe, - .remove = clk_wzrd_remove, }; module_platform_driver(clk_wzrd_driver); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 95dd4660b5b659..487c8525996724 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -400,7 +400,8 @@ config ARM_GT_INITIAL_PRESCALER_VAL This affects CPU_FREQ max delta from the initial frequency. config ARM_TIMER_SP804 - bool "Support for Dual Timer SP804 module" if COMPILE_TEST + bool "Support for Dual Timer SP804 module" + depends on ARM || ARM64 || COMPILE_TEST depends on GENERIC_SCHED_CLOCK && HAVE_CLK select CLKSRC_MMIO select TIMER_OF if OF @@ -753,4 +754,13 @@ config EP93XX_TIMER Enables support for the Cirrus Logic timer block EP93XX. +config RALINK_TIMER + bool "Ralink System Tick Counter" + depends on SOC_RT305X || SOC_MT7620 || COMPILE_TEST + select CLKSRC_MMIO + select TIMER_OF + help + Enables support for system tick counter present on + Ralink SoCs RT3352 and MT7620. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 22743785299eda..43ef16a4efa6a3 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -91,3 +91,4 @@ obj-$(CONFIG_GOLDFISH_TIMER) += timer-goldfish.o obj-$(CONFIG_GXP_TIMER) += timer-gxp.o obj-$(CONFIG_CLKSRC_LOONGSON1_PWM) += timer-loongson1-pwm.o obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o +obj-$(CONFIG_RALINK_TIMER) += timer-ralink.o diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 03733101e23174..808f259781fd2a 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -1179,8 +1179,6 @@ static void arch_timer_stop(struct clock_event_device *clk) disable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi]); if (arch_timer_has_nonsecure_ppi()) disable_percpu_irq(arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]); - - clk->set_state_shutdown(clk); } static int arch_timer_dying_cpu(unsigned int cpu) @@ -1430,7 +1428,7 @@ static int __init arch_timer_of_init(struct device_node *np) arch_timers_present |= ARCH_TIMER_TYPE_CP15; - has_names = of_property_read_bool(np, "interrupt-names"); + has_names = of_property_present(np, "interrupt-names"); for (i = ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++) { if (has_names) diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index a05cfaab5f843e..2d86bbc2764a04 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -195,7 +195,6 @@ static int gt_dying_cpu(unsigned int cpu) { struct clock_event_device *clk = this_cpu_ptr(gt_evt); - gt_clockevent_shutdown(clk); disable_percpu_irq(clk->irq); return 0; } diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index f5f24a95ee820f..3a55ae5fe225ac 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -68,25 +68,6 @@ static inline void apbt_writel_relaxed(struct dw_apb_timer *timer, u32 val, writel_relaxed(val, timer->base + offs); } -static void apbt_disable_int(struct dw_apb_timer *timer) -{ - u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL); - - ctrl |= APBTMR_CONTROL_INT; - apbt_writel(timer, ctrl, APBTMR_N_CONTROL); -} - -/** - * dw_apb_clockevent_pause() - stop the clock_event_device from running - * - * @dw_ced: The APB clock to stop generating events. - */ -void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced) -{ - disable_irq(dw_ced->timer.irq); - apbt_disable_int(&dw_ced->timer); -} - static void apbt_eoi(struct dw_apb_timer *timer) { apbt_readl_relaxed(timer, APBTMR_N_EOI); @@ -284,26 +265,6 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, return dw_ced; } -/** - * dw_apb_clockevent_resume() - resume a clock that has been paused. - * - * @dw_ced: The APB clock to resume. - */ -void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced) -{ - enable_irq(dw_ced->timer.irq); -} - -/** - * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ. - * - * @dw_ced: The APB clock to stop generating the events. - */ -void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced) -{ - free_irq(dw_ced->timer.irq, &dw_ced->ced); -} - /** * dw_apb_clockevent_register() - register the clock with the generic layer * diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index ef8cb1b71be4a8..e6a02e351d771b 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -496,7 +496,6 @@ static int exynos4_mct_dying_cpu(unsigned int cpu) per_cpu_ptr(&percpu_mct_tick, cpu); struct clock_event_device *evt = &mevt->evt; - evt->set_state_shutdown(evt); if (mct_int_type == MCT_INT_SPI) { if (evt->irq != -1) disable_irq_nosync(evt->irq); diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index 99177835cadec4..b39dee7b93af04 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -27,7 +27,8 @@ #include static struct clock_event_device __percpu *hv_clock_event; -static u64 hv_sched_clock_offset __ro_after_init; +/* Note: offset can hold negative values after hibernation. */ +static u64 hv_sched_clock_offset __read_mostly; /* * If false, we're using the old mechanism for stimer0 interrupts @@ -470,6 +471,17 @@ static void resume_hv_clock_tsc(struct clocksource *arg) hv_set_msr(HV_MSR_REFERENCE_TSC, tsc_msr.as_uint64); } +/* + * Called during resume from hibernation, from overridden + * x86_platform.restore_sched_clock_state routine. This is to adjust offsets + * used to calculate time for hv tsc page based sched_clock, to account for + * time spent before hibernation. + */ +void hv_adj_sched_clock_offset(u64 offset) +{ + hv_sched_clock_offset -= offset; +} + #ifdef HAVE_VDSO_CLOCKMODE_HVCLOCK static int hv_cs_enable(struct clocksource *cs) { diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 110347707ff980..7907b740497a5c 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -166,6 +166,37 @@ static u64 gic_hpt_read(struct clocksource *cs) return gic_read_count(); } +static u64 gic_hpt_read_multicluster(struct clocksource *cs) +{ + unsigned int hi, hi2, lo; + u64 count; + + mips_cm_lock_other(0, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL); + + if (mips_cm_is64) { + count = read_gic_redir_counter(); + goto out; + } + + hi = read_gic_redir_counter_32h(); + while (true) { + lo = read_gic_redir_counter_32l(); + + /* If hi didn't change then lo didn't wrap & we're done */ + hi2 = read_gic_redir_counter_32h(); + if (hi2 == hi) + break; + + /* Otherwise, repeat with the latest hi value */ + hi = hi2; + } + + count = (((u64)hi) << 32) + lo; +out: + mips_cm_unlock_other(); + return count; +} + static struct clocksource gic_clocksource = { .name = "GIC", .read = gic_hpt_read, @@ -203,6 +234,11 @@ static int __init __gic_clocksource_init(void) gic_clocksource.rating = 200; gic_clocksource.rating += clamp(gic_frequency / 10000000, 0, 99); + if (mips_cps_multicluster_cpus()) { + gic_clocksource.read = &gic_hpt_read_multicluster; + gic_clocksource.vdso_clock_mode = VDSO_CLOCKMODE_NONE; + } + ret = clocksource_register_hz(&gic_clocksource, gic_frequency); if (ret < 0) pr_warn("Unable to register clocksource\n"); @@ -261,7 +297,8 @@ static int __init gic_clocksource_of_init(struct device_node *node) * stable CPU frequency or on the platforms with CM3 and CPU frequency * change performed by the CPC core clocks divider. */ - if (mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ)) { + if ((mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ)) && + !mips_cps_multicluster_cpus()) { sched_clock_register(mips_cm_is64 ? gic_read_count_64 : gic_read_count_2x32, gic_count_width, gic_frequency); diff --git a/drivers/clocksource/timer-armada-370-xp.c b/drivers/clocksource/timer-armada-370-xp.c index 6ec565d6939ad4..54284c1c065148 100644 --- a/drivers/clocksource/timer-armada-370-xp.c +++ b/drivers/clocksource/timer-armada-370-xp.c @@ -201,7 +201,6 @@ static int armada_370_xp_timer_dying_cpu(unsigned int cpu) { struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu); - evt->set_state_shutdown(evt); disable_percpu_irq(evt->irq); return 0; } diff --git a/drivers/clocksource/timer-gxp.c b/drivers/clocksource/timer-gxp.c index 57aa2e2cce53a5..48a73c101eb85a 100644 --- a/drivers/clocksource/timer-gxp.c +++ b/drivers/clocksource/timer-gxp.c @@ -85,7 +85,7 @@ static int __init gxp_timer_init(struct device_node *node) clk = of_clk_get(node, 0); if (IS_ERR(clk)) { - ret = (int)PTR_ERR(clk); + ret = PTR_ERR(clk); pr_err("%pOFn clock not found: %d\n", node, ret); goto err_free; } diff --git a/drivers/clocksource/timer-qcom.c b/drivers/clocksource/timer-qcom.c index eac4c95c6127f2..ddb1debe6a6b76 100644 --- a/drivers/clocksource/timer-qcom.c +++ b/drivers/clocksource/timer-qcom.c @@ -130,7 +130,6 @@ static int msm_local_timer_dying_cpu(unsigned int cpu) { struct clock_event_device *evt = per_cpu_ptr(msm_evt, cpu); - evt->set_state_shutdown(evt); disable_percpu_irq(evt->irq); return 0; } diff --git a/drivers/clocksource/timer-ralink.c b/drivers/clocksource/timer-ralink.c new file mode 100644 index 00000000000000..6ecdb4228f7637 --- /dev/null +++ b/drivers/clocksource/timer-ralink.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Ralink System Tick Counter driver present on RT3352 and MT7620 SoCs. + * + * Copyright (C) 2013 by John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYSTICK_FREQ (50 * 1000) + +#define SYSTICK_CONFIG 0x00 +#define SYSTICK_COMPARE 0x04 +#define SYSTICK_COUNT 0x08 + +/* route systick irq to mips irq 7 instead of the r4k-timer */ +#define CFG_EXT_STK_EN 0x2 +/* enable the counter */ +#define CFG_CNT_EN 0x1 + +struct systick_device { + void __iomem *membase; + struct clock_event_device dev; + int irq_requested; + int freq_scale; +}; + +static int systick_set_oneshot(struct clock_event_device *evt); +static int systick_shutdown(struct clock_event_device *evt); + +static int systick_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + struct systick_device *sdev; + u32 count; + + sdev = container_of(evt, struct systick_device, dev); + count = ioread32(sdev->membase + SYSTICK_COUNT); + count = (count + delta) % SYSTICK_FREQ; + iowrite32(count, sdev->membase + SYSTICK_COMPARE); + + return 0; +} + +static void systick_event_handler(struct clock_event_device *dev) +{ + /* noting to do here */ +} + +static irqreturn_t systick_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *dev = (struct clock_event_device *)dev_id; + + dev->event_handler(dev); + + return IRQ_HANDLED; +} + +static struct systick_device systick = { + .dev = { + /* + * cevt-r4k uses 300, make sure systick + * gets used if available + */ + .rating = 310, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = systick_next_event, + .set_state_shutdown = systick_shutdown, + .set_state_oneshot = systick_set_oneshot, + .event_handler = systick_event_handler, + }, +}; + +static int systick_shutdown(struct clock_event_device *evt) +{ + struct systick_device *sdev; + + sdev = container_of(evt, struct systick_device, dev); + + if (sdev->irq_requested) + free_irq(systick.dev.irq, &systick.dev); + sdev->irq_requested = 0; + iowrite32(0, systick.membase + SYSTICK_CONFIG); + + return 0; +} + +static int systick_set_oneshot(struct clock_event_device *evt) +{ + const char *name = systick.dev.name; + struct systick_device *sdev; + int irq = systick.dev.irq; + + sdev = container_of(evt, struct systick_device, dev); + + if (!sdev->irq_requested) { + if (request_irq(irq, systick_interrupt, + IRQF_PERCPU | IRQF_TIMER, name, &systick.dev)) + pr_err("Failed to request irq %d (%s)\n", irq, name); + } + sdev->irq_requested = 1; + iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, + systick.membase + SYSTICK_CONFIG); + + return 0; +} + +static int __init ralink_systick_init(struct device_node *np) +{ + int ret; + + systick.membase = of_iomap(np, 0); + if (!systick.membase) + return -ENXIO; + + systick.dev.name = np->name; + clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60); + systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev); + systick.dev.max_delta_ticks = 0x7fff; + systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); + systick.dev.min_delta_ticks = 0x3; + systick.dev.irq = irq_of_parse_and_map(np, 0); + if (!systick.dev.irq) { + pr_err("%pOFn: request_irq failed", np); + return -EINVAL; + } + + ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, + SYSTICK_FREQ, 301, 16, + clocksource_mmio_readl_up); + if (ret) + return ret; + + clockevents_register_device(&systick.dev); + + pr_info("%pOFn: running - mult: %d, shift: %d\n", + np, systick.dev.mult, systick.dev.shift); + + return 0; +} + +TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 0d229a9058dad8..6b48a9006444dd 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -318,7 +318,7 @@ MODULE_DEVICE_TABLE(of, sun5i_timer_of_match); static struct platform_driver sun5i_timer_driver = { .probe = sun5i_timer_probe, - .remove_new = sun5i_timer_remove, + .remove = sun5i_timer_remove, .driver = { .name = "sun5i-timer", .of_match_table = sun5i_timer_of_match, diff --git a/drivers/clocksource/timer-tegra.c b/drivers/clocksource/timer-tegra.c index e9635c25eef4df..35b6ce9deffa6d 100644 --- a/drivers/clocksource/timer-tegra.c +++ b/drivers/clocksource/timer-tegra.c @@ -158,7 +158,6 @@ static int tegra_timer_stop(unsigned int cpu) { struct timer_of *to = per_cpu_ptr(&tegra_to, cpu); - to->clkevt.set_state_shutdown(&to->clkevt); disable_irq_nosync(to->clkevt.irq); return 0; diff --git a/drivers/clocksource/timer-tegra186.c b/drivers/clocksource/timer-tegra186.c index 304537dadf2c1c..5d4cf5237a113c 100644 --- a/drivers/clocksource/timer-tegra186.c +++ b/drivers/clocksource/timer-tegra186.c @@ -502,7 +502,7 @@ static struct platform_driver tegra186_wdt_driver = { .of_match_table = tegra186_timer_of_match, }, .probe = tegra186_timer_probe, - .remove_new = tegra186_timer_remove, + .remove = tegra186_timer_remove, }; module_platform_driver(tegra186_wdt_driver); diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c index c2dcd8d68e4587..985a6d08512b42 100644 --- a/drivers/clocksource/timer-ti-dm-systimer.c +++ b/drivers/clocksource/timer-ti-dm-systimer.c @@ -202,10 +202,10 @@ static bool __init dmtimer_is_preferred(struct device_node *np) /* Secure gptimer12 is always clocked with a fixed source */ if (!of_property_read_bool(np, "ti,timer-secure")) { - if (!of_property_read_bool(np, "assigned-clocks")) + if (!of_property_present(np, "assigned-clocks")) return false; - if (!of_property_read_bool(np, "assigned-clock-parents")) + if (!of_property_present(np, "assigned-clock-parents")) return false; } @@ -686,9 +686,9 @@ subsys_initcall(dmtimer_percpu_timer_startup); static int __init dmtimer_percpu_quirk_init(struct device_node *np, u32 pa) { - struct device_node *arm_timer; + struct device_node *arm_timer __free(device_node) = + of_find_compatible_node(NULL, NULL, "arm,armv7-timer"); - arm_timer = of_find_compatible_node(NULL, NULL, "arm,armv7-timer"); if (of_device_is_available(arm_timer)) { pr_warn_once("ARM architected timer wrap issue i940 detected\n"); return 0; diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index b7a34b1a975ec5..e9e32df6b56664 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -1104,8 +1104,12 @@ static int omap_dm_timer_probe(struct platform_device *pdev) return -ENOMEM; timer->irq = platform_get_irq(pdev, 0); - if (timer->irq < 0) - return timer->irq; + if (timer->irq < 0) { + if (of_property_read_bool(dev->of_node, "ti,timer-pwm")) + dev_info(dev, "Did not find timer interrupt, timer usable in PWM mode only\n"); + else + return timer->irq; + } timer->io_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(timer->io_base)) @@ -1291,7 +1295,7 @@ MODULE_DEVICE_TABLE(of, omap_timer_match); static struct platform_driver omap_dm_timer_driver = { .probe = omap_dm_timer_probe, - .remove_new = omap_dm_timer_remove, + .remove = omap_dm_timer_remove, .driver = { .name = "omap_timer", .of_match_table = omap_timer_match, diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c index 1b481731df964e..b9df9b19d4bd97 100644 --- a/drivers/comedi/comedi_fops.c +++ b/drivers/comedi/comedi_fops.c @@ -2407,6 +2407,18 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) start += PAGE_SIZE; } + +#ifdef CONFIG_MMU + /* + * Leaving behind a partial mapping of a buffer we're about to + * drop is unsafe, see remap_pfn_range_notrack(). + * We need to zap the range here ourselves instead of relying + * on the automatic zapping in remap_pfn_range() because we call + * remap_pfn_range() in a loop. + */ + if (retval) + zap_vma_ptes(vma, vma->vm_start, size); +#endif } if (retval == 0) { diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index 4a6868b8f58bce..ce81fc4e1ae763 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -1360,4 +1360,4 @@ module_isa_driver_with_irq(quad8_driver, num_quad8, num_irq); MODULE_AUTHOR("William Breathitt Gray "); MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c index 3ee75e1a78cd5e..23fdf0caf712a2 100644 --- a/drivers/counter/counter-chrdev.c +++ b/drivers/counter/counter-chrdev.c @@ -672,4 +672,4 @@ void counter_push_event(struct counter_device *const counter, const u8 event, if (copied) wake_up_poll(&counter->events_wait, EPOLLIN); } -EXPORT_SYMBOL_NS_GPL(counter_push_event, COUNTER); +EXPORT_SYMBOL_NS_GPL(counter_push_event, "COUNTER"); diff --git a/drivers/counter/counter-core.c b/drivers/counter/counter-core.c index 893b4f0726d2e6..50bd30ba3d0377 100644 --- a/drivers/counter/counter-core.c +++ b/drivers/counter/counter-core.c @@ -74,7 +74,7 @@ void *counter_priv(const struct counter_device *const counter) return &ch->privdata; } -EXPORT_SYMBOL_NS_GPL(counter_priv, COUNTER); +EXPORT_SYMBOL_NS_GPL(counter_priv, "COUNTER"); /** * counter_alloc - allocate a counter_device @@ -134,13 +134,13 @@ struct counter_device *counter_alloc(size_t sizeof_priv) return NULL; } -EXPORT_SYMBOL_NS_GPL(counter_alloc, COUNTER); +EXPORT_SYMBOL_NS_GPL(counter_alloc, "COUNTER"); void counter_put(struct counter_device *counter) { put_device(&counter->dev); } -EXPORT_SYMBOL_NS_GPL(counter_put, COUNTER); +EXPORT_SYMBOL_NS_GPL(counter_put, "COUNTER"); /** * counter_add - complete registration of a counter @@ -167,7 +167,7 @@ int counter_add(struct counter_device *counter) /* implies device_add(dev) */ return cdev_device_add(&counter->chrdev, dev); } -EXPORT_SYMBOL_NS_GPL(counter_add, COUNTER); +EXPORT_SYMBOL_NS_GPL(counter_add, "COUNTER"); /** * counter_unregister - unregister Counter from the system @@ -189,7 +189,7 @@ void counter_unregister(struct counter_device *const counter) mutex_unlock(&counter->ops_exist_lock); } -EXPORT_SYMBOL_NS_GPL(counter_unregister, COUNTER); +EXPORT_SYMBOL_NS_GPL(counter_unregister, "COUNTER"); static void devm_counter_release(void *counter) { @@ -224,7 +224,7 @@ struct counter_device *devm_counter_alloc(struct device *dev, size_t sizeof_priv return counter; } -EXPORT_SYMBOL_NS_GPL(devm_counter_alloc, COUNTER); +EXPORT_SYMBOL_NS_GPL(devm_counter_alloc, "COUNTER"); /** * devm_counter_add - complete registration of a counter @@ -245,7 +245,7 @@ int devm_counter_add(struct device *dev, return devm_add_action_or_reset(dev, devm_counter_release, counter); } -EXPORT_SYMBOL_NS_GPL(devm_counter_add, COUNTER); +EXPORT_SYMBOL_NS_GPL(devm_counter_add, "COUNTER"); #define COUNTER_DEV_MAX 256 diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c index 200876f3ec0486..c47741292ae111 100644 --- a/drivers/counter/ftm-quaddec.c +++ b/drivers/counter/ftm-quaddec.c @@ -311,6 +311,7 @@ static const struct of_device_id ftm_quaddec_match[] = { { .compatible = "fsl,ftm-quaddec" }, {}, }; +MODULE_DEVICE_TABLE(of, ftm_quaddec_match); static struct platform_driver ftm_quaddec_driver = { .driver = { @@ -326,4 +327,4 @@ MODULE_DESCRIPTION("Flex Timer Module Quadrature decoder"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kjeld Flarup "); MODULE_AUTHOR("Patrick Havelange "); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/i8254.c b/drivers/counter/i8254.c index 6d74e8ef92f009..95ad928725eca4 100644 --- a/drivers/counter/i8254.c +++ b/drivers/counter/i8254.c @@ -439,9 +439,9 @@ int devm_i8254_regmap_register(struct device *const dev, return 0; } -EXPORT_SYMBOL_NS_GPL(devm_i8254_regmap_register, I8254); +EXPORT_SYMBOL_NS_GPL(devm_i8254_regmap_register, "I8254"); MODULE_AUTHOR("William Breathitt Gray"); MODULE_DESCRIPTION("Intel 8254 Programmable Interval Timer"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/intel-qep.c b/drivers/counter/intel-qep.c index af5942e66f7d0c..c49c178056f451 100644 --- a/drivers/counter/intel-qep.c +++ b/drivers/counter/intel-qep.c @@ -408,13 +408,9 @@ static int intel_qep_probe(struct pci_dev *pci, const struct pci_device_id *id) pci_set_master(pci); - ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci)); - if (ret) - return ret; - - regs = pcim_iomap_table(pci)[0]; - if (!regs) - return -ENOMEM; + regs = pcim_iomap_region(pci, 0, pci_name(pci)); + if (IS_ERR(regs)) + return PTR_ERR(regs); qep->dev = dev; qep->regs = regs; @@ -523,4 +519,4 @@ MODULE_AUTHOR("Jarkko Nikula "); MODULE_AUTHOR("Raymond Tan "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Intel Quadrature Encoder Peripheral driver"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c index 229473855c5b38..949598d51575a1 100644 --- a/drivers/counter/interrupt-cnt.c +++ b/drivers/counter/interrupt-cnt.c @@ -253,4 +253,4 @@ MODULE_ALIAS("platform:interrupt-counter"); MODULE_AUTHOR("Oleksij Rempel "); MODULE_DESCRIPTION("Interrupt counter driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/microchip-tcb-capture.c b/drivers/counter/microchip-tcb-capture.c index b3e615cbd2caa6..2f096a5b973d18 100644 --- a/drivers/counter/microchip-tcb-capture.c +++ b/drivers/counter/microchip-tcb-capture.c @@ -403,4 +403,4 @@ module_platform_driver(mchp_tc_driver); MODULE_AUTHOR("Kamel Bouhara "); MODULE_DESCRIPTION("Microchip TCB Capture driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/rz-mtu3-cnt.c b/drivers/counter/rz-mtu3-cnt.c index ee821493b16649..e755d54dfece94 100644 --- a/drivers/counter/rz-mtu3-cnt.c +++ b/drivers/counter/rz-mtu3-cnt.c @@ -903,4 +903,4 @@ 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); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c index 8439755559b219..cf73f65baf606c 100644 --- a/drivers/counter/stm32-lptimer-cnt.c +++ b/drivers/counter/stm32-lptimer-cnt.c @@ -520,4 +520,4 @@ MODULE_AUTHOR("Fabrice Gasnier "); MODULE_ALIAS("platform:stm32-lptimer-counter"); MODULE_DESCRIPTION("STMicroelectronics STM32 LPTIM counter driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 186e73d6ccb455..e75b69476a00a8 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -214,11 +214,17 @@ static int stm32_count_enable_write(struct counter_device *counter, { struct stm32_timer_cnt *const priv = counter_priv(counter); u32 cr1; + int ret; if (enable) { regmap_read(priv->regmap, TIM_CR1, &cr1); - if (!(cr1 & TIM_CR1_CEN)) - clk_enable(priv->clk); + if (!(cr1 & TIM_CR1_CEN)) { + ret = clk_enable(priv->clk); + if (ret) { + dev_err(counter->parent, "Cannot enable clock %d\n", ret); + return ret; + } + } regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); @@ -694,6 +700,7 @@ static int stm32_timer_cnt_probe_encoder(struct device *dev, } ret = of_property_read_u32(tnode, "reg", &idx); + of_node_put(tnode); if (ret) { dev_err(dev, "Can't get index (%d)\n", ret); return ret; @@ -816,7 +823,11 @@ static int __maybe_unused stm32_timer_cnt_resume(struct device *dev) return ret; if (priv->enabled) { - clk_enable(priv->clk); + ret = clk_enable(priv->clk); + if (ret) { + dev_err(dev, "Cannot enable clock %d\n", ret); + return ret; + } /* Restore registers that may have been lost */ regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr); @@ -853,4 +864,4 @@ MODULE_AUTHOR("Benjamin Gaignard "); MODULE_ALIAS("platform:stm32-timer-counter"); MODULE_DESCRIPTION("STMicroelectronics STM32 TIMER counter driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/ti-ecap-capture.c b/drivers/counter/ti-ecap-capture.c index 675447315cafb8..3faaf7f60539ac 100644 --- a/drivers/counter/ti-ecap-capture.c +++ b/drivers/counter/ti-ecap-capture.c @@ -574,8 +574,13 @@ static int ecap_cnt_resume(struct device *dev) { struct counter_device *counter_dev = dev_get_drvdata(dev); struct ecap_cnt_dev *ecap_dev = counter_priv(counter_dev); + int ret; - clk_enable(ecap_dev->clk); + ret = clk_enable(ecap_dev->clk); + if (ret) { + dev_err(dev, "Cannot enable clock %d\n", ret); + return ret; + } ecap_cnt_capture_set_evmode(counter_dev, ecap_dev->pm_ctx.ev_mode); @@ -598,7 +603,7 @@ MODULE_DEVICE_TABLE(of, ecap_cnt_of_match); static struct platform_driver ecap_cnt_driver = { .probe = ecap_cnt_probe, - .remove_new = ecap_cnt_remove, + .remove = ecap_cnt_remove, .driver = { .name = "ecap-capture", .of_match_table = ecap_cnt_of_match, @@ -610,4 +615,4 @@ module_platform_driver(ecap_cnt_driver); MODULE_DESCRIPTION("ECAP Capture driver"); MODULE_AUTHOR("Julien Panis "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c index 313b91456f2652..bc586eff0daeb5 100644 --- a/drivers/counter/ti-eqep.c +++ b/drivers/counter/ti-eqep.c @@ -548,7 +548,7 @@ MODULE_DEVICE_TABLE(of, ti_eqep_of_match); static struct platform_driver ti_eqep_driver = { .probe = ti_eqep_probe, - .remove_new = ti_eqep_remove, + .remove = ti_eqep_remove, .driver = { .name = "ti-eqep-cnt", .of_match_table = ti_eqep_of_match, @@ -559,4 +559,4 @@ module_platform_driver(ti_eqep_driver); MODULE_AUTHOR("David Lechner "); MODULE_DESCRIPTION("TI eQEP counter driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(COUNTER); +MODULE_IMPORT_NS("COUNTER"); diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 2561b215432a82..92a83a9bb2e105 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -217,6 +217,20 @@ config CPUFREQ_DT If in doubt, say N. +config CPUFREQ_VIRT + tristate "Virtual cpufreq driver" + depends on GENERIC_ARCH_TOPOLOGY + help + This adds a virtualized cpufreq driver for guest kernels that + read/writes to a MMIO region for a virtualized cpufreq device to + communicate with the host. It sends performance requests to the host + which gets used as a hint to schedule vCPU threads and select CPU + frequency. If a VM does not support a virtualized FIE such as AMUs, + it updates the frequency scaling factor by polling host CPU frequency + to enable accurate Per-Entity Load Tracking for tasks running in the guest. + + If in doubt, say N. + config CPUFREQ_DT_PLATDEV tristate "Generic DT based cpufreq platdev driver" depends on OF diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc index 58151ca566958a..eb678fa5260aa6 100644 --- a/drivers/cpufreq/Kconfig.powerpc +++ b/drivers/cpufreq/Kconfig.powerpc @@ -17,13 +17,6 @@ config CPU_FREQ_CBE_PMI frequencies. Using PMI, the processor will not only be able to run at lower speed, but also at lower core voltage. -config CPU_FREQ_MAPLE - bool "Support for Maple 970FX Evaluation Board" - depends on PPC_MAPLE - help - This adds support for frequency switching on Maple 970FX - Evaluation Board and compatible boards (IBM JS2x blades). - config CPU_FREQ_PMAC bool "Support for Apple PowerBooks" depends on ADB_PMU && PPC32 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 0f184031dd123c..d35a28dd946307 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET) += cpufreq_governor_attr_set.o obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o +obj-$(CONFIG_CPUFREQ_VIRT) += virtual-cpufreq.o # Traces CFLAGS_amd-pstate-trace.o := -I$(src) @@ -92,7 +93,6 @@ obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o obj-$(CONFIG_CPU_FREQ_CBE) += ppc-cbe-cpufreq.o ppc-cbe-cpufreq-y += ppc_cbe_cpufreq_pervasive.o ppc_cbe_cpufreq.o obj-$(CONFIG_CPU_FREQ_CBE_PMI) += ppc_cbe_cpufreq_pmi.o -obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o obj-$(CONFIG_QORIQ_CPUFREQ) += qoriq-cpufreq.o obj-$(CONFIG_CPU_FREQ_PMAC) += pmac32-cpufreq.o obj-$(CONFIG_CPU_FREQ_PMAC64) += pmac64-cpufreq.o diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 0f04feb6cafaf1..c9ebacf5c88e24 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -73,20 +73,17 @@ static unsigned int acpi_pstate_strict; static bool boost_state(unsigned int cpu) { - u32 lo, hi; u64 msr; switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_INTEL: case X86_VENDOR_CENTAUR: case X86_VENDOR_ZHAOXIN: - rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi); - msr = lo | ((u64)hi << 32); + rdmsrl_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &msr); return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE); case X86_VENDOR_HYGON: case X86_VENDOR_AMD: - rdmsr_on_cpu(cpu, MSR_K7_HWCR, &lo, &hi); - msr = lo | ((u64)hi << 32); + rdmsrl_on_cpu(cpu, MSR_K7_HWCR, &msr); return !(msr & MSR_K7_HWCR_CPB_DIS); } return false; @@ -1028,7 +1025,7 @@ static struct platform_driver acpi_cpufreq_platdrv = { .driver = { .name = "acpi-cpufreq", }, - .remove_new = acpi_cpufreq_remove, + .remove = acpi_cpufreq_remove, }; static int __init acpi_cpufreq_init(void) diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c index f66701514d9063..a261d7300951e0 100644 --- a/drivers/cpufreq/amd-pstate-ut.c +++ b/drivers/cpufreq/amd-pstate-ut.c @@ -227,10 +227,10 @@ static void amd_pstate_ut_check_freq(u32 index) goto skip_test; } - if (cpudata->min_freq != policy->min) { + if (cpudata->lowest_nonlinear_freq != policy->min) { amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL; - pr_err("%s cpu%d cpudata_min_freq=%d policy_min=%d, they should be equal!\n", - __func__, cpu, cpudata->min_freq, policy->min); + pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n", + __func__, cpu, cpudata->lowest_nonlinear_freq, policy->min); goto skip_test; } diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index b63863f77c6778..66e5dfc711c0c5 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -233,7 +233,7 @@ static int amd_pstate_get_energy_pref_index(struct amd_cpudata *cpudata) return index; } -static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, +static void msr_update_perf(struct amd_cpudata *cpudata, u32 min_perf, u32 des_perf, u32 max_perf, bool fast_switch) { if (fast_switch) @@ -243,7 +243,7 @@ static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, READ_ONCE(cpudata->cppc_req_cached)); } -DEFINE_STATIC_CALL(amd_pstate_update_perf, pstate_update_perf); +DEFINE_STATIC_CALL(amd_pstate_update_perf, msr_update_perf); static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, u32 des_perf, @@ -306,11 +306,17 @@ static int amd_pstate_set_energy_pref_index(struct amd_cpudata *cpudata, return ret; } -static inline int pstate_enable(bool enable) +static inline int msr_cppc_enable(bool enable) { int ret, cpu; unsigned long logical_proc_id_mask = 0; + /* + * MSR_AMD_CPPC_ENABLE is write-once, once set it cannot be cleared. + */ + if (!enable) + return 0; + if (enable == cppc_enabled) return 0; @@ -332,7 +338,7 @@ static inline int pstate_enable(bool enable) return 0; } -static int cppc_enable(bool enable) +static int shmem_cppc_enable(bool enable) { int cpu, ret = 0; struct cppc_perf_ctrls perf_ctrls; @@ -359,24 +365,28 @@ static int cppc_enable(bool enable) return ret; } -DEFINE_STATIC_CALL(amd_pstate_enable, pstate_enable); +DEFINE_STATIC_CALL(amd_pstate_cppc_enable, msr_cppc_enable); -static inline int amd_pstate_enable(bool enable) +static inline int amd_pstate_cppc_enable(bool enable) { - return static_call(amd_pstate_enable)(enable); + return static_call(amd_pstate_cppc_enable)(enable); } -static int pstate_init_perf(struct amd_cpudata *cpudata) +static int msr_init_perf(struct amd_cpudata *cpudata) { - u64 cap1; + u64 cap1, numerator; int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1, &cap1); if (ret) return ret; - WRITE_ONCE(cpudata->highest_perf, AMD_CPPC_HIGHEST_PERF(cap1)); - WRITE_ONCE(cpudata->max_limit_perf, AMD_CPPC_HIGHEST_PERF(cap1)); + ret = amd_get_boost_ratio_numerator(cpudata->cpu, &numerator); + if (ret) + return ret; + + WRITE_ONCE(cpudata->highest_perf, numerator); + WRITE_ONCE(cpudata->max_limit_perf, numerator); WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1)); WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1)); WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1)); @@ -385,16 +395,21 @@ static int pstate_init_perf(struct amd_cpudata *cpudata) return 0; } -static int cppc_init_perf(struct amd_cpudata *cpudata) +static int shmem_init_perf(struct amd_cpudata *cpudata) { struct cppc_perf_caps cppc_perf; + u64 numerator; int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf); if (ret) return ret; - WRITE_ONCE(cpudata->highest_perf, cppc_perf.highest_perf); - WRITE_ONCE(cpudata->max_limit_perf, cppc_perf.highest_perf); + ret = amd_get_boost_ratio_numerator(cpudata->cpu, &numerator); + if (ret) + return ret; + + WRITE_ONCE(cpudata->highest_perf, numerator); + WRITE_ONCE(cpudata->max_limit_perf, numerator); WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf); WRITE_ONCE(cpudata->lowest_nonlinear_perf, cppc_perf.lowest_nonlinear_perf); @@ -420,14 +435,14 @@ static int cppc_init_perf(struct amd_cpudata *cpudata) return ret; } -DEFINE_STATIC_CALL(amd_pstate_init_perf, pstate_init_perf); +DEFINE_STATIC_CALL(amd_pstate_init_perf, msr_init_perf); static inline int amd_pstate_init_perf(struct amd_cpudata *cpudata) { return static_call(amd_pstate_init_perf)(cpudata); } -static void cppc_update_perf(struct amd_cpudata *cpudata, +static void shmem_update_perf(struct amd_cpudata *cpudata, u32 min_perf, u32 des_perf, u32 max_perf, bool fast_switch) { @@ -527,25 +542,41 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, cpufreq_cpu_put(policy); } -static int amd_pstate_verify(struct cpufreq_policy_data *policy) +static int amd_pstate_verify(struct cpufreq_policy_data *policy_data) { - cpufreq_verify_within_cpu_limits(policy); + /* + * Initialize lower frequency limit (i.e.policy->min) with + * lowest_nonlinear_frequency which is the most energy efficient + * frequency. Override the initial value set by cpufreq core and + * amd-pstate qos_requests. + */ + if (policy_data->min == FREQ_QOS_MIN_DEFAULT_VALUE) { + struct cpufreq_policy *policy = cpufreq_cpu_get(policy_data->cpu); + struct amd_cpudata *cpudata; + + if (!policy) + return -EINVAL; + + cpudata = policy->driver_data; + policy_data->min = cpudata->lowest_nonlinear_freq; + cpufreq_cpu_put(policy); + } + + cpufreq_verify_within_cpu_limits(policy_data); + pr_debug("policy_max =%d, policy_min=%d\n", policy_data->max, policy_data->min); return 0; } static int amd_pstate_update_min_max_limit(struct cpufreq_policy *policy) { - u32 max_limit_perf, min_limit_perf, lowest_perf, max_perf; + u32 max_limit_perf, min_limit_perf, lowest_perf, max_perf, max_freq; struct amd_cpudata *cpudata = policy->driver_data; - if (cpudata->boost_supported && !policy->boost_enabled) - max_perf = READ_ONCE(cpudata->nominal_perf); - else - max_perf = READ_ONCE(cpudata->highest_perf); - - max_limit_perf = div_u64(policy->max * max_perf, policy->cpuinfo.max_freq); - min_limit_perf = div_u64(policy->min * max_perf, policy->cpuinfo.max_freq); + max_perf = READ_ONCE(cpudata->highest_perf); + max_freq = READ_ONCE(cpudata->max_freq); + max_limit_perf = div_u64(policy->max * max_perf, max_freq); + min_limit_perf = div_u64(policy->min * max_perf, max_freq); lowest_perf = READ_ONCE(cpudata->lowest_perf); if (min_limit_perf < lowest_perf) @@ -665,34 +696,12 @@ static void amd_pstate_adjust_perf(unsigned int cpu, static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on) { struct amd_cpudata *cpudata = policy->driver_data; - struct cppc_perf_ctrls perf_ctrls; - u32 highest_perf, nominal_perf, nominal_freq, max_freq; + u32 nominal_freq, max_freq; int ret = 0; - highest_perf = READ_ONCE(cpudata->highest_perf); - nominal_perf = READ_ONCE(cpudata->nominal_perf); nominal_freq = READ_ONCE(cpudata->nominal_freq); max_freq = READ_ONCE(cpudata->max_freq); - if (boot_cpu_has(X86_FEATURE_CPPC)) { - u64 value = READ_ONCE(cpudata->cppc_req_cached); - - value &= ~GENMASK_ULL(7, 0); - value |= on ? highest_perf : nominal_perf; - WRITE_ONCE(cpudata->cppc_req_cached, value); - - wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value); - } else { - perf_ctrls.max_perf = on ? highest_perf : nominal_perf; - ret = cppc_set_perf(cpudata->cpu, &perf_ctrls); - if (ret) { - cpufreq_cpu_release(policy); - pr_debug("Failed to set max perf on CPU:%d. ret:%d\n", - cpudata->cpu, ret); - return ret; - } - } - if (on) policy->cpuinfo.max_freq = max_freq; else if (policy->cpuinfo.max_freq > nominal_freq * 1000) @@ -847,7 +856,7 @@ static u32 amd_pstate_get_transition_delay_us(unsigned int cpu) transition_delay_ns = cppc_get_transition_latency(cpu); if (transition_delay_ns == CPUFREQ_ETERNAL) { - if (cpu_feature_enabled(X86_FEATURE_FAST_CPPC)) + if (cpu_feature_enabled(X86_FEATURE_AMD_FAST_CPPC)) return AMD_PSTATE_FAST_CPPC_TRANSITION_DELAY; else return AMD_PSTATE_TRANSITION_DELAY; @@ -886,7 +895,6 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) { int ret; u32 min_freq, max_freq; - u64 numerator; u32 nominal_perf, nominal_freq; u32 lowest_nonlinear_perf, lowest_nonlinear_freq; u32 boost_ratio, lowest_nonlinear_ratio; @@ -908,10 +916,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) nominal_perf = READ_ONCE(cpudata->nominal_perf); - ret = amd_get_boost_ratio_numerator(cpudata->cpu, &numerator); - if (ret) - return ret; - boost_ratio = div_u64(numerator << SCHED_CAPACITY_SHIFT, nominal_perf); + boost_ratio = div_u64(cpudata->highest_perf << SCHED_CAPACITY_SHIFT, nominal_perf); max_freq = (nominal_freq * boost_ratio >> SCHED_CAPACITY_SHIFT) * 1000; lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); @@ -1001,7 +1006,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) policy->fast_switch_possible = true; ret = freq_qos_add_request(&policy->constraints, &cpudata->req[0], - FREQ_QOS_MIN, policy->cpuinfo.min_freq); + FREQ_QOS_MIN, FREQ_QOS_MIN_DEFAULT_VALUE); if (ret < 0) { dev_err(dev, "Failed to add min-freq constraint (%d)\n", ret); goto free_cpudata1; @@ -1045,7 +1050,7 @@ static int amd_pstate_cpu_resume(struct cpufreq_policy *policy) { int ret; - ret = amd_pstate_enable(true); + ret = amd_pstate_cppc_enable(true); if (ret) pr_err("failed to enable amd-pstate during resume, return %d\n", ret); @@ -1056,7 +1061,7 @@ static int amd_pstate_cpu_suspend(struct cpufreq_policy *policy) { int ret; - ret = amd_pstate_enable(false); + ret = amd_pstate_cppc_enable(false); if (ret) pr_err("failed to disable amd-pstate during suspend, return %d\n", ret); @@ -1189,25 +1194,41 @@ static ssize_t show_energy_performance_preference( static void amd_pstate_driver_cleanup(void) { - amd_pstate_enable(false); + amd_pstate_cppc_enable(false); cppc_state = AMD_PSTATE_DISABLE; current_pstate_driver = NULL; } +static int amd_pstate_set_driver(int mode_idx) +{ + if (mode_idx >= AMD_PSTATE_DISABLE && mode_idx < AMD_PSTATE_MAX) { + cppc_state = mode_idx; + if (cppc_state == AMD_PSTATE_DISABLE) + pr_info("driver is explicitly disabled\n"); + + if (cppc_state == AMD_PSTATE_ACTIVE) + current_pstate_driver = &amd_pstate_epp_driver; + + if (cppc_state == AMD_PSTATE_PASSIVE || cppc_state == AMD_PSTATE_GUIDED) + current_pstate_driver = &amd_pstate_driver; + + return 0; + } + + return -EINVAL; +} + static int amd_pstate_register_driver(int mode) { int ret; - if (mode == AMD_PSTATE_PASSIVE || mode == AMD_PSTATE_GUIDED) - current_pstate_driver = &amd_pstate_driver; - else if (mode == AMD_PSTATE_ACTIVE) - current_pstate_driver = &amd_pstate_epp_driver; - else - return -EINVAL; + ret = amd_pstate_set_driver(mode); + if (ret) + return ret; cppc_state = mode; - ret = amd_pstate_enable(true); + ret = amd_pstate_cppc_enable(true); if (ret) { pr_err("failed to enable cppc during amd-pstate driver registration, return %d\n", ret); @@ -1485,6 +1506,8 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) WRITE_ONCE(cpudata->cppc_cap1_cached, value); } + current_pstate_driver->adjust_perf = NULL; + return 0; free_cpudata1: @@ -1507,26 +1530,13 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy) static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy) { struct amd_cpudata *cpudata = policy->driver_data; - u32 max_perf, min_perf, min_limit_perf, max_limit_perf; + u32 max_perf, min_perf; u64 value; s16 epp; - if (cpudata->boost_supported && !policy->boost_enabled) - max_perf = READ_ONCE(cpudata->nominal_perf); - else - max_perf = READ_ONCE(cpudata->highest_perf); + max_perf = READ_ONCE(cpudata->highest_perf); min_perf = READ_ONCE(cpudata->lowest_perf); - max_limit_perf = div_u64(policy->max * max_perf, policy->cpuinfo.max_freq); - min_limit_perf = div_u64(policy->min * max_perf, policy->cpuinfo.max_freq); - - if (min_limit_perf < min_perf) - min_limit_perf = min_perf; - - if (max_limit_perf < min_limit_perf) - max_limit_perf = min_limit_perf; - - WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); - WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); + amd_pstate_update_min_max_limit(policy); max_perf = clamp_t(unsigned long, max_perf, cpudata->min_limit_perf, cpudata->max_limit_perf); @@ -1535,7 +1545,7 @@ static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy) value = READ_ONCE(cpudata->cppc_req_cached); if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) - min_perf = max_perf; + min_perf = min(cpudata->nominal_perf, max_perf); /* Initial min/max values for CPPC Performance Controls Register */ value &= ~AMD_CPPC_MIN_PERF(~0L); @@ -1563,12 +1573,6 @@ static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy) if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) epp = 0; - /* Set initial EPP value */ - if (cpu_feature_enabled(X86_FEATURE_CPPC)) { - value &= ~GENMASK_ULL(31, 24); - value |= (u64)epp << 24; - } - WRITE_ONCE(cpudata->cppc_req_cached, value); return amd_pstate_set_epp(cpudata, epp); } @@ -1605,7 +1609,7 @@ static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata) u64 value, max_perf; int ret; - ret = amd_pstate_enable(true); + ret = amd_pstate_cppc_enable(true); if (ret) pr_err("failed to enable amd pstate during resume, return %d\n", ret); @@ -1616,8 +1620,9 @@ static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata) wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value); } else { perf_ctrls.max_perf = max_perf; - perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(cpudata->epp_cached); cppc_set_perf(cpudata->cpu, &perf_ctrls); + perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(cpudata->epp_cached); + cppc_set_epp_perf(cpudata->cpu, &perf_ctrls, 1); } } @@ -1657,9 +1662,11 @@ static void amd_pstate_epp_offline(struct cpufreq_policy *policy) wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value); } else { perf_ctrls.desired_perf = 0; + perf_ctrls.min_perf = min_perf; perf_ctrls.max_perf = min_perf; - perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(HWP_EPP_BALANCE_POWERSAVE); cppc_set_perf(cpudata->cpu, &perf_ctrls); + perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(HWP_EPP_BALANCE_POWERSAVE); + cppc_set_epp_perf(cpudata->cpu, &perf_ctrls, 1); } mutex_unlock(&amd_pstate_limits_lock); } @@ -1679,13 +1686,6 @@ static int amd_pstate_epp_cpu_offline(struct cpufreq_policy *policy) return 0; } -static int amd_pstate_epp_verify_policy(struct cpufreq_policy_data *policy) -{ - cpufreq_verify_within_cpu_limits(policy); - pr_debug("policy_max =%d, policy_min=%d\n", policy->max, policy->min); - return 0; -} - static int amd_pstate_epp_suspend(struct cpufreq_policy *policy) { struct amd_cpudata *cpudata = policy->driver_data; @@ -1699,7 +1699,7 @@ static int amd_pstate_epp_suspend(struct cpufreq_policy *policy) cpudata->suspended = true; /* disable CPPC in lowlevel firmware */ - ret = amd_pstate_enable(false); + ret = amd_pstate_cppc_enable(false); if (ret) pr_err("failed to suspend, return %d\n", ret); @@ -1741,7 +1741,7 @@ static struct cpufreq_driver amd_pstate_driver = { static struct cpufreq_driver amd_pstate_epp_driver = { .flags = CPUFREQ_CONST_LOOPS, - .verify = amd_pstate_epp_verify_policy, + .verify = amd_pstate_verify, .setpolicy = amd_pstate_epp_set_policy, .init = amd_pstate_epp_cpu_init, .exit = amd_pstate_epp_cpu_exit, @@ -1755,26 +1755,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = { .attr = amd_pstate_epp_attr, }; -static int __init amd_pstate_set_driver(int mode_idx) -{ - if (mode_idx >= AMD_PSTATE_DISABLE && mode_idx < AMD_PSTATE_MAX) { - cppc_state = mode_idx; - if (cppc_state == AMD_PSTATE_DISABLE) - pr_info("driver is explicitly disabled\n"); - - if (cppc_state == AMD_PSTATE_ACTIVE) - current_pstate_driver = &amd_pstate_epp_driver; - - if (cppc_state == AMD_PSTATE_PASSIVE || cppc_state == AMD_PSTATE_GUIDED) - current_pstate_driver = &amd_pstate_driver; - - return 0; - } - - return -EINVAL; -} - -/** +/* * CPPC function is not supported for family ID 17H with model_ID ranging from 0x10 to 0x2F. * show the debug message that helps to check if the CPU has CPPC support for loading issue. */ @@ -1864,10 +1845,10 @@ static int __init amd_pstate_init(void) if (cppc_state == AMD_PSTATE_UNDEFINED) { /* Disable on the following configs by default: * 1. Undefined platforms - * 2. Server platforms + * 2. Server platforms with CPUs older than Family 0x1A. */ if (amd_pstate_acpi_pm_profile_undefined() || - amd_pstate_acpi_pm_profile_server()) { + (amd_pstate_acpi_pm_profile_server() && boot_cpu_data.x86 < 0x1A)) { pr_info("driver load is disabled, boot with specific mode to enable this\n"); return -ENODEV; } @@ -1875,31 +1856,19 @@ static int __init amd_pstate_init(void) cppc_state = CONFIG_X86_AMD_PSTATE_DEFAULT_MODE; } - switch (cppc_state) { - case AMD_PSTATE_DISABLE: + if (cppc_state == AMD_PSTATE_DISABLE) { pr_info("driver load is disabled, boot with specific mode to enable this\n"); return -ENODEV; - case AMD_PSTATE_PASSIVE: - case AMD_PSTATE_ACTIVE: - case AMD_PSTATE_GUIDED: - ret = amd_pstate_set_driver(cppc_state); - if (ret) - return ret; - break; - default: - return -EINVAL; } /* capability check */ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { pr_debug("AMD CPPC MSR based functionality is supported\n"); - if (cppc_state != AMD_PSTATE_ACTIVE) - current_pstate_driver->adjust_perf = amd_pstate_adjust_perf; } else { pr_debug("AMD CPPC shared memory based functionality is supported\n"); - static_call_update(amd_pstate_enable, cppc_enable); - static_call_update(amd_pstate_init_perf, cppc_init_perf); - static_call_update(amd_pstate_update_perf, cppc_update_perf); + static_call_update(amd_pstate_cppc_enable, shmem_cppc_enable); + static_call_update(amd_pstate_init_perf, shmem_init_perf); + static_call_update(amd_pstate_update_perf, shmem_update_perf); } if (amd_pstate_prefcore) { @@ -1908,17 +1877,10 @@ static int __init amd_pstate_init(void) return ret; } - /* enable amd pstate feature */ - ret = amd_pstate_enable(true); - if (ret) { - pr_err("failed to enable driver mode(%d)\n", cppc_state); - return ret; - } - - ret = cpufreq_register_driver(current_pstate_driver); + ret = amd_pstate_register_driver(cppc_state); if (ret) { pr_err("failed to register with return %d\n", ret); - goto disable_driver; + return ret; } dev_root = bus_get_dev_root(&cpu_subsys); @@ -1935,8 +1897,7 @@ static int __init amd_pstate_init(void) global_attr_free: cpufreq_unregister_driver(current_pstate_driver); -disable_driver: - amd_pstate_enable(false); + amd_pstate_cppc_enable(false); return ret; } device_initcall(amd_pstate_init); diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index ea8438550b4901..2fd0f6be6fa39b 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -474,8 +474,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv) rc = brcm_avs_get_pmap(priv, NULL); magic = readl(priv->base + AVS_MBOX_MAGIC); - return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) || - (rc != -EINVAL)); + return (magic == AVS_FIRMWARE_MAGIC) && (rc != -ENOTSUPP) && + (rc != -EINVAL); } static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) @@ -777,7 +777,7 @@ static struct platform_driver brcm_avs_cpufreq_platdrv = { .of_match_table = brcm_avs_cpufreq_match, }, .probe = brcm_avs_cpufreq_probe, - .remove_new = brcm_avs_cpufreq_remove, + .remove = brcm_avs_cpufreq_remove, }; module_platform_driver(brcm_avs_cpufreq_platdrv); diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 2b8708475ac776..bd8f75accfa01e 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -36,33 +36,15 @@ static LIST_HEAD(cpu_data_list); static bool boost_supported; -struct cppc_workaround_oem_info { - char oem_id[ACPI_OEM_ID_SIZE + 1]; - char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; - u32 oem_revision; -}; - -static struct cppc_workaround_oem_info wa_info[] = { - { - .oem_id = "HISI ", - .oem_table_id = "HIP07 ", - .oem_revision = 0, - }, { - .oem_id = "HISI ", - .oem_table_id = "HIP08 ", - .oem_revision = 0, - } -}; - static struct cpufreq_driver cppc_cpufreq_driver; +#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE static enum { FIE_UNSET = -1, FIE_ENABLED, FIE_DISABLED } fie_disabled = FIE_UNSET; -#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE module_param(fie_disabled, int, 0444); MODULE_PARM_DESC(fie_disabled, "Disable Frequency Invariance Engine (FIE)"); @@ -78,7 +60,6 @@ struct cppc_freq_invariance { static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv); static struct kthread_worker *kworker_fie; -static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu); static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data, struct cppc_perf_fb_ctrs *fb_ctrs_t0, struct cppc_perf_fb_ctrs *fb_ctrs_t1); @@ -118,6 +99,9 @@ static void cppc_scale_freq_workfn(struct kthread_work *work) perf = cppc_perf_from_fbctrs(cpu_data, &cppc_fi->prev_perf_fb_ctrs, &fb_ctrs); + if (!perf) + return; + cppc_fi->prev_perf_fb_ctrs = fb_ctrs; perf <<= SCHED_CAPACITY_SHIFT; @@ -420,6 +404,9 @@ static int cppc_get_cpu_power(struct device *cpu_dev, struct cppc_cpudata *cpu_data; policy = cpufreq_cpu_get_raw(cpu_dev->id); + if (!policy) + return -EINVAL; + cpu_data = policy->driver_data; perf_caps = &cpu_data->perf_caps; max_cap = arch_scale_cpu_capacity(cpu_dev->id); @@ -487,6 +474,9 @@ static int cppc_get_cpu_cost(struct device *cpu_dev, unsigned long KHz, int step; policy = cpufreq_cpu_get_raw(cpu_dev->id); + if (!policy) + return -EINVAL; + cpu_data = policy->driver_data; perf_caps = &cpu_data->perf_caps; max_cap = arch_scale_cpu_capacity(cpu_dev->id); @@ -724,13 +714,31 @@ static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data, delta_delivered = get_delta(fb_ctrs_t1->delivered, fb_ctrs_t0->delivered); - /* Check to avoid divide-by zero and invalid delivered_perf */ + /* + * Avoid divide-by zero and unchanged feedback counters. + * Leave it for callers to handle. + */ if (!delta_reference || !delta_delivered) - return cpu_data->perf_ctrls.desired_perf; + return 0; return (reference_perf * delta_delivered) / delta_reference; } +static int cppc_get_perf_ctrs_sample(int cpu, + struct cppc_perf_fb_ctrs *fb_ctrs_t0, + struct cppc_perf_fb_ctrs *fb_ctrs_t1) +{ + int ret; + + ret = cppc_get_perf_ctrs(cpu, fb_ctrs_t0); + if (ret) + return ret; + + udelay(2); /* 2usec delay between sampling */ + + return cppc_get_perf_ctrs(cpu, fb_ctrs_t1); +} + static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) { struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0}; @@ -746,18 +754,32 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) cpufreq_cpu_put(policy); - ret = cppc_get_perf_ctrs(cpu, &fb_ctrs_t0); - if (ret) - return 0; - - udelay(2); /* 2usec delay between sampling */ - - ret = cppc_get_perf_ctrs(cpu, &fb_ctrs_t1); - if (ret) - return 0; + ret = cppc_get_perf_ctrs_sample(cpu, &fb_ctrs_t0, &fb_ctrs_t1); + if (ret) { + if (ret == -EFAULT) + /* Any of the associated CPPC regs is 0. */ + goto out_invalid_counters; + else + return 0; + } delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0, &fb_ctrs_t1); + if (!delivered_perf) + goto out_invalid_counters; + + return cppc_perf_to_khz(&cpu_data->perf_caps, delivered_perf); + +out_invalid_counters: + /* + * Feedback counters could be unchanged or 0 when a cpu enters a + * low-power idle state, e.g. clock-gated or power-gated. + * Use desired perf for reflecting frequency. Get the latest register + * value first as some platforms may update the actual delivered perf + * there; if failed, resort to the cached desired perf. + */ + if (cppc_get_desired_perf(cpu, &delivered_perf)) + delivered_perf = cpu_data->perf_ctrls.desired_perf; return cppc_perf_to_khz(&cpu_data->perf_caps, delivered_perf); } @@ -812,57 +834,6 @@ static struct cpufreq_driver cppc_cpufreq_driver = { .name = "cppc_cpufreq", }; -/* - * HISI platform does not support delivered performance counter and - * reference performance counter. It can calculate the performance using the - * platform specific mechanism. We reuse the desired performance register to - * store the real performance calculated by the platform. - */ -static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu) -{ - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); - struct cppc_cpudata *cpu_data; - u64 desired_perf; - int ret; - - if (!policy) - return -ENODEV; - - cpu_data = policy->driver_data; - - cpufreq_cpu_put(policy); - - ret = cppc_get_desired_perf(cpu, &desired_perf); - if (ret < 0) - return -EIO; - - return cppc_perf_to_khz(&cpu_data->perf_caps, desired_perf); -} - -static void cppc_check_hisi_workaround(void) -{ - struct acpi_table_header *tbl; - acpi_status status = AE_OK; - int i; - - status = acpi_get_table(ACPI_SIG_PCCT, 0, &tbl); - if (ACPI_FAILURE(status) || !tbl) - return; - - for (i = 0; i < ARRAY_SIZE(wa_info); i++) { - if (!memcmp(wa_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) && - !memcmp(wa_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) && - wa_info[i].oem_revision == tbl->oem_revision) { - /* Overwrite the get() callback */ - cppc_cpufreq_driver.get = hisi_cppc_cpufreq_get_rate; - fie_disabled = FIE_DISABLED; - break; - } - } - - acpi_put_table(tbl); -} - static int __init cppc_cpufreq_init(void) { int ret; @@ -870,7 +841,6 @@ static int __init cppc_cpufreq_init(void) if (!acpi_cpc_valid()) return -ENODEV; - cppc_check_hisi_workaround(); cppc_freq_invariance_init(); populate_efficiency_class(); diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 18942bfe9c95f7..2a3e8bd317c9d2 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -103,6 +103,7 @@ static const struct of_device_id allowlist[] __initconst = { * platforms using "operating-points-v2" property. */ static const struct of_device_id blocklist[] __initconst = { + { .compatible = "allwinner,sun50i-a100" }, { .compatible = "allwinner,sun50i-h6", }, { .compatible = "allwinner,sun50i-h616", }, { .compatible = "allwinner,sun50i-h618", }, diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 983443396f8f22..3a7c3372bda751 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -345,7 +345,7 @@ static struct platform_driver dt_cpufreq_platdrv = { .name = "cpufreq-dt", }, .probe = dt_cpufreq_probe, - .remove_new = dt_cpufreq_remove, + .remove = dt_cpufreq_remove, }; module_platform_driver(dt_cpufreq_platdrv); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f98c9438760c97..1a4cae54a01bd7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1520,7 +1520,7 @@ static int cpufreq_online(unsigned int cpu) * frequency for longer duration. Hence, a BUG_ON(). */ BUG_ON(ret); - pr_info("%s: CPU%d: Running at unlisted initial frequency: %u KHz, changing to: %u KHz\n", + pr_info("%s: CPU%d: Running at unlisted initial frequency: %u kHz, changing to: %u kHz\n", __func__, policy->cpu, old_freq, policy->cur); } } diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c index 7d2754411d8c80..8736be3a06ce93 100644 --- a/drivers/cpufreq/davinci-cpufreq.c +++ b/drivers/cpufreq/davinci-cpufreq.c @@ -145,7 +145,7 @@ static struct platform_driver davinci_cpufreq_driver = { .driver = { .name = "cpufreq-davinci", }, - .remove_new = __exit_p(davinci_cpufreq_remove), + .remove = __exit_p(davinci_cpufreq_remove), }; int __init davinci_cpufreq_init(void) diff --git a/drivers/cpufreq/imx-cpufreq-dt.c b/drivers/cpufreq/imx-cpufreq-dt.c index 577bb9e2f112c2..1492c92ffc1a1e 100644 --- a/drivers/cpufreq/imx-cpufreq-dt.c +++ b/drivers/cpufreq/imx-cpufreq-dt.c @@ -183,7 +183,7 @@ static void imx_cpufreq_dt_remove(struct platform_device *pdev) static struct platform_driver imx_cpufreq_dt_driver = { .probe = imx_cpufreq_dt_probe, - .remove_new = imx_cpufreq_dt_remove, + .remove = imx_cpufreq_dt_remove, .driver = { .name = "imx-cpufreq-dt", }, diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index c20d3ecc5a81ea..f3c99f378ad699 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -522,7 +522,7 @@ static struct platform_driver imx6q_cpufreq_platdrv = { .name = "imx6q-cpufreq", }, .probe = imx6q_cpufreq_probe, - .remove_new = imx6q_cpufreq_remove, + .remove = imx6q_cpufreq_remove, }; module_platform_driver(imx6q_cpufreq_platdrv); diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 400337f3b572da..b8e2396a708ad6 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -3655,6 +3655,8 @@ static const struct x86_cpu_id intel_epp_default[] = { X86_MATCH_VFM(INTEL_ALDERLAKE_L, HWP_SET_DEF_BALANCE_PERF_EPP(102)), X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, HWP_SET_DEF_BALANCE_PERF_EPP(32)), X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, HWP_SET_DEF_BALANCE_PERF_EPP(32)), + X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, HWP_SET_DEF_BALANCE_PERF_EPP(32)), + X86_MATCH_VFM(INTEL_GRANITERAPIDS_D, HWP_SET_DEF_BALANCE_PERF_EPP(32)), X86_MATCH_VFM(INTEL_METEORLAKE_L, HWP_SET_EPP_VALUES(HWP_EPP_POWERSAVE, 179, 64, 16)), X86_MATCH_VFM(INTEL_ARROWLAKE, HWP_SET_EPP_VALUES(HWP_EPP_POWERSAVE, diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index fd20b986d1f2f8..312f2654d1d550 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c @@ -189,7 +189,7 @@ static void kirkwood_cpufreq_remove(struct platform_device *pdev) static struct platform_driver kirkwood_cpufreq_platform_driver = { .probe = kirkwood_cpufreq_probe, - .remove_new = kirkwood_cpufreq_remove, + .remove = kirkwood_cpufreq_remove, .driver = { .name = "kirkwood-cpufreq", }, diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index 6a8e97896d38ca..ed1a6dbad63894 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c @@ -148,7 +148,9 @@ static int __init cpufreq_init(void) ret = cpufreq_register_driver(&loongson2_cpufreq_driver); - if (!ret && !nowait) { + if (ret) { + platform_driver_unregister(&platform_driver); + } else if (!nowait) { saved_cpu_wait = cpu_wait; cpu_wait = loongson2_cpu_wait; } diff --git a/drivers/cpufreq/loongson3_cpufreq.c b/drivers/cpufreq/loongson3_cpufreq.c index 6b5e6798d9a283..bd34bf0fafa5a3 100644 --- a/drivers/cpufreq/loongson3_cpufreq.c +++ b/drivers/cpufreq/loongson3_cpufreq.c @@ -346,8 +346,11 @@ static int loongson3_cpufreq_probe(struct platform_device *pdev) { int i, ret; - for (i = 0; i < MAX_PACKAGES; i++) - devm_mutex_init(&pdev->dev, &cpufreq_mutex[i]); + for (i = 0; i < MAX_PACKAGES; i++) { + ret = devm_mutex_init(&pdev->dev, &cpufreq_mutex[i]); + if (ret) + return ret; + } ret = do_service_request(0, 0, CMD_GET_VERSION, 0, 0); if (ret <= 0) @@ -386,7 +389,7 @@ static struct platform_driver loongson3_platform_driver = { }, .id_table = cpufreq_id_table, .probe = loongson3_cpufreq_probe, - .remove_new = loongson3_cpufreq_remove, + .remove = loongson3_cpufreq_remove, }; module_platform_driver(loongson3_platform_driver); diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c deleted file mode 100644 index 690da85c4865a0..00000000000000 --- a/drivers/cpufreq/maple-cpufreq.c +++ /dev/null @@ -1,242 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2011 Dmitry Eremin-Solenikov - * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt - * and Markus Demleitner - * - * This driver adds basic cpufreq support for SMU & 970FX based G5 Macs, - * that is iMac G5 and latest single CPU desktop. - */ - -#undef DEBUG - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DBG(fmt...) pr_debug(fmt) - -/* see 970FX user manual */ - -#define SCOM_PCR 0x0aa001 /* PCR scom addr */ - -#define PCR_HILO_SELECT 0x80000000U /* 1 = PCR, 0 = PCRH */ -#define PCR_SPEED_FULL 0x00000000U /* 1:1 speed value */ -#define PCR_SPEED_HALF 0x00020000U /* 1:2 speed value */ -#define PCR_SPEED_QUARTER 0x00040000U /* 1:4 speed value */ -#define PCR_SPEED_MASK 0x000e0000U /* speed mask */ -#define PCR_SPEED_SHIFT 17 -#define PCR_FREQ_REQ_VALID 0x00010000U /* freq request valid */ -#define PCR_VOLT_REQ_VALID 0x00008000U /* volt request valid */ -#define PCR_TARGET_TIME_MASK 0x00006000U /* target time */ -#define PCR_STATLAT_MASK 0x00001f00U /* STATLAT value */ -#define PCR_SNOOPLAT_MASK 0x000000f0U /* SNOOPLAT value */ -#define PCR_SNOOPACC_MASK 0x0000000fU /* SNOOPACC value */ - -#define SCOM_PSR 0x408001 /* PSR scom addr */ -/* warning: PSR is a 64 bits register */ -#define PSR_CMD_RECEIVED 0x2000000000000000U /* command received */ -#define PSR_CMD_COMPLETED 0x1000000000000000U /* command completed */ -#define PSR_CUR_SPEED_MASK 0x0300000000000000U /* current speed */ -#define PSR_CUR_SPEED_SHIFT (56) - -/* - * The G5 only supports two frequencies (Quarter speed is not supported) - */ -#define CPUFREQ_HIGH 0 -#define CPUFREQ_LOW 1 - -static struct cpufreq_frequency_table maple_cpu_freqs[] = { - {0, CPUFREQ_HIGH, 0}, - {0, CPUFREQ_LOW, 0}, - {0, 0, CPUFREQ_TABLE_END}, -}; - -/* Power mode data is an array of the 32 bits PCR values to use for - * the various frequencies, retrieved from the device-tree - */ -static int maple_pmode_cur; - -static const u32 *maple_pmode_data; -static int maple_pmode_max; - -/* - * SCOM based frequency switching for 970FX rev3 - */ -static int maple_scom_switch_freq(int speed_mode) -{ - unsigned long flags; - int to; - - local_irq_save(flags); - - /* Clear PCR high */ - scom970_write(SCOM_PCR, 0); - /* Clear PCR low */ - scom970_write(SCOM_PCR, PCR_HILO_SELECT | 0); - /* Set PCR low */ - scom970_write(SCOM_PCR, PCR_HILO_SELECT | - maple_pmode_data[speed_mode]); - - /* Wait for completion */ - for (to = 0; to < 10; to++) { - unsigned long psr = scom970_read(SCOM_PSR); - - if ((psr & PSR_CMD_RECEIVED) == 0 && - (((psr >> PSR_CUR_SPEED_SHIFT) ^ - (maple_pmode_data[speed_mode] >> PCR_SPEED_SHIFT)) & 0x3) - == 0) - break; - if (psr & PSR_CMD_COMPLETED) - break; - udelay(100); - } - - local_irq_restore(flags); - - maple_pmode_cur = speed_mode; - ppc_proc_freq = maple_cpu_freqs[speed_mode].frequency * 1000ul; - - return 0; -} - -static int maple_scom_query_freq(void) -{ - unsigned long psr = scom970_read(SCOM_PSR); - int i; - - for (i = 0; i <= maple_pmode_max; i++) - if ((((psr >> PSR_CUR_SPEED_SHIFT) ^ - (maple_pmode_data[i] >> PCR_SPEED_SHIFT)) & 0x3) == 0) - break; - return i; -} - -/* - * Common interface to the cpufreq core - */ - -static int maple_cpufreq_target(struct cpufreq_policy *policy, - unsigned int index) -{ - return maple_scom_switch_freq(index); -} - -static unsigned int maple_cpufreq_get_speed(unsigned int cpu) -{ - return maple_cpu_freqs[maple_pmode_cur].frequency; -} - -static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy) -{ - cpufreq_generic_init(policy, maple_cpu_freqs, 12000); - return 0; -} - -static struct cpufreq_driver maple_cpufreq_driver = { - .name = "maple", - .flags = CPUFREQ_CONST_LOOPS, - .init = maple_cpufreq_cpu_init, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = maple_cpufreq_target, - .get = maple_cpufreq_get_speed, - .attr = cpufreq_generic_attr, -}; - -static int __init maple_cpufreq_init(void) -{ - struct device_node *cpunode; - unsigned int psize; - unsigned long max_freq; - const u32 *valp; - u32 pvr_hi; - int rc = -ENODEV; - - /* - * Behave here like powermac driver which checks machine compatibility - * to ease merging of two drivers in future. - */ - if (!of_machine_is_compatible("Momentum,Maple") && - !of_machine_is_compatible("Momentum,Apache")) - return 0; - - /* Get first CPU node */ - cpunode = of_cpu_device_node_get(0); - if (cpunode == NULL) { - pr_err("Can't find any CPU 0 node\n"); - goto bail_noprops; - } - - /* Check 970FX for now */ - /* we actually don't care on which CPU to access PVR */ - pvr_hi = PVR_VER(mfspr(SPRN_PVR)); - if (pvr_hi != 0x3c && pvr_hi != 0x44) { - pr_err("Unsupported CPU version (%x)\n", pvr_hi); - goto bail_noprops; - } - - /* Look for the powertune data in the device-tree */ - /* - * On Maple this property is provided by PIBS in dual-processor config, - * not provided by PIBS in CPU0 config and also not provided by SLOF, - * so YMMV - */ - maple_pmode_data = of_get_property(cpunode, "power-mode-data", &psize); - if (!maple_pmode_data) { - DBG("No power-mode-data !\n"); - goto bail_noprops; - } - maple_pmode_max = psize / sizeof(u32) - 1; - - /* - * From what I see, clock-frequency is always the maximal frequency. - * The current driver can not slew sysclk yet, so we really only deal - * with powertune steps for now. We also only implement full freq and - * half freq in this version. So far, I haven't yet seen a machine - * supporting anything else. - */ - valp = of_get_property(cpunode, "clock-frequency", NULL); - if (!valp) - goto bail_noprops; - max_freq = (*valp)/1000; - maple_cpu_freqs[0].frequency = max_freq; - maple_cpu_freqs[1].frequency = max_freq/2; - - /* Force apply current frequency to make sure everything is in - * sync (voltage is right for example). Firmware may leave us with - * a strange setting ... - */ - msleep(10); - maple_pmode_cur = -1; - maple_scom_switch_freq(maple_scom_query_freq()); - - pr_info("Registering Maple CPU frequency driver\n"); - pr_info("Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n", - maple_cpu_freqs[1].frequency/1000, - maple_cpu_freqs[0].frequency/1000, - maple_cpu_freqs[maple_pmode_cur].frequency/1000); - - rc = cpufreq_register_driver(&maple_cpufreq_driver); - -bail_noprops: - of_node_put(cpunode); - - return rc; -} - -module_init(maple_cpufreq_init); - - -MODULE_DESCRIPTION("cpufreq driver for Maple 970FX/970MP boards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/mediatek-cpufreq-hw.c b/drivers/cpufreq/mediatek-cpufreq-hw.c index 8925e096d5b9a0..9252ebd60373f1 100644 --- a/drivers/cpufreq/mediatek-cpufreq-hw.c +++ b/drivers/cpufreq/mediatek-cpufreq-hw.c @@ -62,7 +62,7 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, policy = cpufreq_cpu_get_raw(cpu_dev->id); if (!policy) - return 0; + return -EINVAL; data = policy->driver_data; @@ -344,7 +344,7 @@ MODULE_DEVICE_TABLE(of, mtk_cpufreq_hw_match); static struct platform_driver mtk_cpufreq_hw_driver = { .probe = mtk_cpufreq_hw_driver_probe, - .remove_new = mtk_cpufreq_hw_driver_remove, + .remove = mtk_cpufreq_hw_driver_remove, .driver = { .name = "mtk-cpufreq-hw", .of_match_table = mtk_cpufreq_hw_match, diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index de8be0a8932d88..106220c0fd1135 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -188,7 +188,7 @@ static struct platform_driver omap_cpufreq_platdrv = { .name = "omap-cpufreq", }, .probe = omap_cpufreq_probe, - .remove_new = omap_cpufreq_remove, + .remove = omap_cpufreq_remove, }; module_platform_driver(omap_cpufreq_platdrv); diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 771efbf51a48e3..ac2e90a65f0c4b 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -615,7 +615,7 @@ static struct platform_driver pcc_cpufreq_platdrv = { .driver = { .name = "pcc-cpufreq", }, - .remove_new = pcc_cpufreq_remove, + .remove = pcc_cpufreq_remove, }; static int __init pcc_cpufreq_init(void) diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index 900d6844c43d3f..98129565acb8e0 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -736,7 +736,7 @@ static void qcom_cpufreq_hw_driver_remove(struct platform_device *pdev) static struct platform_driver qcom_cpufreq_hw_driver = { .probe = qcom_cpufreq_hw_driver_probe, - .remove_new = qcom_cpufreq_hw_driver_remove, + .remove = qcom_cpufreq_hw_driver_remove, .driver = { .name = "qcom-cpufreq-hw", .of_match_table = qcom_cpufreq_hw_match, diff --git a/drivers/cpufreq/qcom-cpufreq-nvmem.c b/drivers/cpufreq/qcom-cpufreq-nvmem.c index 703308fb891a33..3a8ed723a23e52 100644 --- a/drivers/cpufreq/qcom-cpufreq-nvmem.c +++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c @@ -52,12 +52,13 @@ struct qcom_cpufreq_match_data { struct nvmem_cell *speedbin_nvmem, char **pvs_name, struct qcom_cpufreq_drv *drv); - const char **genpd_names; + const char **pd_names; + unsigned int num_pd_names; }; struct qcom_cpufreq_drv_cpu { int opp_token; - struct device **virt_devs; + struct dev_pm_domain_list *pd_list; }; struct qcom_cpufreq_drv { @@ -395,8 +396,6 @@ static int qcom_cpufreq_ipq8074_name_version(struct device *cpu_dev, return 0; } -static const char *generic_genpd_names[] = { "perf", NULL }; - static const struct qcom_cpufreq_match_data match_data_kryo = { .get_version = qcom_cpufreq_kryo_name_version, }; @@ -407,13 +406,13 @@ static const struct qcom_cpufreq_match_data match_data_krait = { static const struct qcom_cpufreq_match_data match_data_msm8909 = { .get_version = qcom_cpufreq_simple_get_version, - .genpd_names = generic_genpd_names, + .pd_names = (const char *[]) { "perf" }, + .num_pd_names = 1, }; -static const char *qcs404_genpd_names[] = { "cpr", NULL }; - static const struct qcom_cpufreq_match_data match_data_qcs404 = { - .genpd_names = qcs404_genpd_names, + .pd_names = (const char *[]) { "cpr" }, + .num_pd_names = 1, }; static const struct qcom_cpufreq_match_data match_data_ipq6018 = { @@ -428,28 +427,16 @@ static const struct qcom_cpufreq_match_data match_data_ipq8074 = { .get_version = qcom_cpufreq_ipq8074_name_version, }; -static void qcom_cpufreq_suspend_virt_devs(struct qcom_cpufreq_drv *drv, unsigned int cpu) -{ - const char * const *name = drv->data->genpd_names; - int i; - - if (!drv->cpus[cpu].virt_devs) - return; - - for (i = 0; *name; i++, name++) - device_set_awake_path(drv->cpus[cpu].virt_devs[i]); -} - -static void qcom_cpufreq_put_virt_devs(struct qcom_cpufreq_drv *drv, unsigned int cpu) +static void qcom_cpufreq_suspend_pd_devs(struct qcom_cpufreq_drv *drv, unsigned int cpu) { - const char * const *name = drv->data->genpd_names; + struct dev_pm_domain_list *pd_list = drv->cpus[cpu].pd_list; int i; - if (!drv->cpus[cpu].virt_devs) + if (!pd_list) return; - for (i = 0; *name; i++, name++) - pm_runtime_put(drv->cpus[cpu].virt_devs[i]); + for (i = 0; i < pd_list->num_pds; i++) + device_set_awake_path(pd_list->pd_devs[i]); } static int qcom_cpufreq_probe(struct platform_device *pdev) @@ -503,7 +490,6 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) } for_each_possible_cpu(cpu) { - struct device **virt_devs = NULL; struct dev_pm_opp_config config = { .supported_hw = NULL, }; @@ -522,12 +508,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) config.prop_name = pvs_name; } - if (drv->data->genpd_names) { - config.genpd_names = drv->data->genpd_names; - config.virt_devs = &virt_devs; - } - - if (config.supported_hw || config.genpd_names) { + if (config.supported_hw) { drv->cpus[cpu].opp_token = dev_pm_opp_set_config(cpu_dev, &config); if (drv->cpus[cpu].opp_token < 0) { ret = drv->cpus[cpu].opp_token; @@ -536,25 +517,18 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) } } - if (virt_devs) { - const char * const *name = config.genpd_names; - int i, j; - - for (i = 0; *name; i++, name++) { - ret = pm_runtime_resume_and_get(virt_devs[i]); - if (ret) { - dev_err(cpu_dev, "failed to resume %s: %d\n", - *name, ret); - - /* Rollback previous PM runtime calls */ - name = config.genpd_names; - for (j = 0; *name && j < i; j++, name++) - pm_runtime_put(virt_devs[j]); - - goto free_opp; - } - } - drv->cpus[cpu].virt_devs = virt_devs; + if (drv->data->pd_names) { + struct dev_pm_domain_attach_data attach_data = { + .pd_names = drv->data->pd_names, + .num_pd_names = drv->data->num_pd_names, + .pd_flags = PD_FLAG_DEV_LINK_ON | + PD_FLAG_REQUIRED_OPP, + }; + + ret = dev_pm_domain_attach_list(cpu_dev, &attach_data, + &drv->cpus[cpu].pd_list); + if (ret < 0) + goto free_opp; } } @@ -570,7 +544,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev) free_opp: for_each_possible_cpu(cpu) { - qcom_cpufreq_put_virt_devs(drv, cpu); + dev_pm_domain_detach_list(drv->cpus[cpu].pd_list); dev_pm_opp_clear_config(drv->cpus[cpu].opp_token); } return ret; @@ -584,7 +558,7 @@ static void qcom_cpufreq_remove(struct platform_device *pdev) platform_device_unregister(cpufreq_dt_pdev); for_each_possible_cpu(cpu) { - qcom_cpufreq_put_virt_devs(drv, cpu); + dev_pm_domain_detach_list(drv->cpus[cpu].pd_list); dev_pm_opp_clear_config(drv->cpus[cpu].opp_token); } } @@ -595,7 +569,7 @@ static int qcom_cpufreq_suspend(struct device *dev) unsigned int cpu; for_each_possible_cpu(cpu) - qcom_cpufreq_suspend_virt_devs(drv, cpu); + qcom_cpufreq_suspend_pd_devs(drv, cpu); return 0; } @@ -604,7 +578,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(qcom_cpufreq_pm_ops, qcom_cpufreq_suspend, NULL) static struct platform_driver qcom_cpufreq_driver = { .probe = qcom_cpufreq_probe, - .remove_new = qcom_cpufreq_remove, + .remove = qcom_cpufreq_remove, .driver = { .name = "qcom-cpufreq-nvmem", .pm = pm_sleep_ptr(&qcom_cpufreq_pm_ops), diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c index 3519bf34d3970a..a37ce051236cf4 100644 --- a/drivers/cpufreq/qoriq-cpufreq.c +++ b/drivers/cpufreq/qoriq-cpufreq.c @@ -296,7 +296,7 @@ static struct platform_driver qoriq_cpufreq_platform_driver = { .name = "qoriq-cpufreq", }, .probe = qoriq_cpufreq_probe, - .remove_new = qoriq_cpufreq_remove, + .remove = qoriq_cpufreq_remove, }; module_platform_driver(qoriq_cpufreq_platform_driver); diff --git a/drivers/cpufreq/raspberrypi-cpufreq.c b/drivers/cpufreq/raspberrypi-cpufreq.c index e0705cc9a57db4..5050932954e3fe 100644 --- a/drivers/cpufreq/raspberrypi-cpufreq.c +++ b/drivers/cpufreq/raspberrypi-cpufreq.c @@ -85,7 +85,7 @@ static struct platform_driver raspberrypi_cpufreq_driver = { .name = "raspberrypi-cpufreq", }, .probe = raspberrypi_cpufreq_probe, - .remove_new = raspberrypi_cpufreq_remove, + .remove = raspberrypi_cpufreq_remove, }; module_platform_driver(raspberrypi_cpufreq_driver); diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index 5892c73e129d2b..07d6f9a9b7c820 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -287,7 +287,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) ret = cpufreq_enable_boost_support(); if (ret) { dev_warn(cpu_dev, "failed to enable boost: %d\n", ret); - goto out_free_opp; + goto out_free_table; } else { scmi_cpufreq_hw_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs; scmi_cpufreq_driver.boost_enabled = true; @@ -296,6 +296,8 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) return 0; +out_free_table: + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); out_free_opp: dev_pm_opp_remove_all_dynamic(cpu_dev); diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index 8d73e6e8be2a58..cd89c1b9832c02 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -217,7 +217,7 @@ static struct platform_driver scpi_cpufreq_platdrv = { .name = "scpi-cpufreq", }, .probe = scpi_cpufreq_probe, - .remove_new = scpi_cpufreq_remove, + .remove = scpi_cpufreq_remove, }; module_platform_driver(scpi_cpufreq_platdrv); diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c index 293921acec9378..17d6a149f580dc 100644 --- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c +++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c @@ -22,6 +22,9 @@ #define NVMEM_MASK 0x7 #define NVMEM_SHIFT 5 +#define SUN50I_A100_NVMEM_MASK 0xf +#define SUN50I_A100_NVMEM_SHIFT 12 + static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev; struct sunxi_cpufreq_data { @@ -45,6 +48,23 @@ static u32 sun50i_h6_efuse_xlate(u32 speedbin) return 0; } +static u32 sun50i_a100_efuse_xlate(u32 speedbin) +{ + u32 efuse_value; + + efuse_value = (speedbin >> SUN50I_A100_NVMEM_SHIFT) & + SUN50I_A100_NVMEM_MASK; + + switch (efuse_value) { + case 0b100: + return 2; + case 0b010: + return 1; + default: + return 0; + } +} + static int get_soc_id_revision(void) { #ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY @@ -108,6 +128,10 @@ static struct sunxi_cpufreq_data sun50i_h6_cpufreq_data = { .efuse_xlate = sun50i_h6_efuse_xlate, }; +static struct sunxi_cpufreq_data sun50i_a100_cpufreq_data = { + .efuse_xlate = sun50i_a100_efuse_xlate, +}; + static struct sunxi_cpufreq_data sun50i_h616_cpufreq_data = { .efuse_xlate = sun50i_h616_efuse_xlate, }; @@ -116,6 +140,9 @@ static const struct of_device_id cpu_opp_match_list[] = { { .compatible = "allwinner,sun50i-h6-operating-points", .data = &sun50i_h6_cpufreq_data, }, + { .compatible = "allwinner,sun50i-a100-operating-points", + .data = &sun50i_a100_cpufreq_data, + }, { .compatible = "allwinner,sun50i-h616-operating-points", .data = &sun50i_h616_cpufreq_data, }, @@ -283,7 +310,7 @@ static void sun50i_cpufreq_nvmem_remove(struct platform_device *pdev) static struct platform_driver sun50i_cpufreq_driver = { .probe = sun50i_cpufreq_nvmem_probe, - .remove_new = sun50i_cpufreq_nvmem_remove, + .remove = sun50i_cpufreq_nvmem_remove, .driver = { .name = "sun50i-cpufreq-nvmem", }, @@ -291,6 +318,7 @@ static struct platform_driver sun50i_cpufreq_driver = { static const struct of_device_id sun50i_cpufreq_match_list[] = { { .compatible = "allwinner,sun50i-h6" }, + { .compatible = "allwinner,sun50i-a100" }, { .compatible = "allwinner,sun50i-h616" }, { .compatible = "allwinner,sun50i-h618" }, { .compatible = "allwinner,sun50i-h700" }, diff --git a/drivers/cpufreq/tegra186-cpufreq.c b/drivers/cpufreq/tegra186-cpufreq.c index 7b8fcfa55038bc..c7761eb99f3ccc 100644 --- a/drivers/cpufreq/tegra186-cpufreq.c +++ b/drivers/cpufreq/tegra186-cpufreq.c @@ -276,7 +276,7 @@ static struct platform_driver tegra186_cpufreq_platform_driver = { .of_match_table = tegra186_cpufreq_of_match, }, .probe = tegra186_cpufreq_probe, - .remove_new = tegra186_cpufreq_remove, + .remove = tegra186_cpufreq_remove, }; module_platform_driver(tegra186_cpufreq_platform_driver); diff --git a/drivers/cpufreq/tegra194-cpufreq.c b/drivers/cpufreq/tegra194-cpufreq.c index 07ea7ed61b687c..9055dd398e7f9d 100644 --- a/drivers/cpufreq/tegra194-cpufreq.c +++ b/drivers/cpufreq/tegra194-cpufreq.c @@ -818,7 +818,7 @@ static struct platform_driver tegra194_ccplex_driver = { .of_match_table = tegra194_cpufreq_of_match, }, .probe = tegra194_cpufreq_probe, - .remove_new = tegra194_cpufreq_remove, + .remove = tegra194_cpufreq_remove, }; module_platform_driver(tegra194_ccplex_driver); diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c index ba621ce1cdda69..5a5147277cd0ab 100644 --- a/drivers/cpufreq/ti-cpufreq.c +++ b/drivers/cpufreq/ti-cpufreq.c @@ -93,6 +93,8 @@ struct ti_cpufreq_soc_data { bool multi_regulator; /* Backward compatibility hack: Might have missing syscon */ #define TI_QUIRK_SYSCON_MAY_BE_MISSING 0x1 +/* Backward compatibility hack: new syscon size is 1 register wide */ +#define TI_QUIRK_SYSCON_IS_SINGLE_REG 0x2 u8 quirks; }; @@ -316,8 +318,8 @@ static struct ti_cpufreq_soc_data am625_soc_data = { .efuse_offset = 0x0018, .efuse_mask = 0x07c0, .efuse_shift = 0x6, - .rev_offset = 0x0014, .multi_regulator = false, + .quirks = TI_QUIRK_SYSCON_IS_SINGLE_REG, }; static struct ti_cpufreq_soc_data am62a7_soc_data = { @@ -325,7 +327,6 @@ static struct ti_cpufreq_soc_data am62a7_soc_data = { .efuse_offset = 0x0, .efuse_mask = 0x07c0, .efuse_shift = 0x6, - .rev_offset = 0x0014, .multi_regulator = false, }; @@ -334,7 +335,6 @@ static struct ti_cpufreq_soc_data am62p5_soc_data = { .efuse_offset = 0x0, .efuse_mask = 0x07c0, .efuse_shift = 0x6, - .rev_offset = 0x0014, .multi_regulator = false, }; @@ -354,6 +354,10 @@ static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data, ret = regmap_read(opp_data->syscon, opp_data->soc_data->efuse_offset, &efuse); + + if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_IS_SINGLE_REG && ret == -EIO) + ret = regmap_read(opp_data->syscon, 0x0, &efuse); + if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) { /* not a syscon register! */ void __iomem *regs = ioremap(OMAP3_SYSCON_BASE + diff --git a/drivers/cpufreq/vexpress-spc-cpufreq.c b/drivers/cpufreq/vexpress-spc-cpufreq.c index 3fadf536c42981..0f86cdb7ec8ab6 100644 --- a/drivers/cpufreq/vexpress-spc-cpufreq.c +++ b/drivers/cpufreq/vexpress-spc-cpufreq.c @@ -565,7 +565,7 @@ static struct platform_driver ve_spc_cpufreq_platdrv = { .name = "vexpress-spc-cpufreq", }, .probe = ve_spc_cpufreq_probe, - .remove_new = ve_spc_cpufreq_remove, + .remove = ve_spc_cpufreq_remove, }; module_platform_driver(ve_spc_cpufreq_platdrv); diff --git a/drivers/cpufreq/virtual-cpufreq.c b/drivers/cpufreq/virtual-cpufreq.c new file mode 100644 index 00000000000000..a050b3a6737f00 --- /dev/null +++ b/drivers/cpufreq/virtual-cpufreq.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * CPU0..CPUn + * +-------------+-------------------------------+--------+-------+ + * | Register | Description | Offset | Len | + * +-------------+-------------------------------+--------+-------+ + * | cur_perf | read this register to get | 0x0 | 0x4 | + * | | the current perf (integer val | | | + * | | representing perf relative to | | | + * | | max performance) | | | + * | | that vCPU is running at | | | + * +-------------+-------------------------------+--------+-------+ + * | set_perf | write to this register to set | 0x4 | 0x4 | + * | | perf value of the vCPU | | | + * +-------------+-------------------------------+--------+-------+ + * | perftbl_len | number of entries in perf | 0x8 | 0x4 | + * | | table. A single entry in the | | | + * | | perf table denotes no table | | | + * | | and the entry contains | | | + * | | the maximum perf value | | | + * | | that this vCPU supports. | | | + * | | The guest can request any | | | + * | | value between 1 and max perf | | | + * | | when perftbls are not used. | | | + * +---------------------------------------------+--------+-------+ + * | perftbl_sel | write to this register to | 0xc | 0x4 | + * | | select perf table entry to | | | + * | | read from | | | + * +---------------------------------------------+--------+-------+ + * | perftbl_rd | read this register to get | 0x10 | 0x4 | + * | | perf value of the selected | | | + * | | entry based on perftbl_sel | | | + * +---------------------------------------------+--------+-------+ + * | perf_domain | performance domain number | 0x14 | 0x4 | + * | | that this vCPU belongs to. | | | + * | | vCPUs sharing the same perf | | | + * | | domain number are part of the | | | + * | | same performance domain. | | | + * +-------------+-------------------------------+--------+-------+ + */ + +#define REG_CUR_PERF_STATE_OFFSET 0x0 +#define REG_SET_PERF_STATE_OFFSET 0x4 +#define REG_PERFTBL_LEN_OFFSET 0x8 +#define REG_PERFTBL_SEL_OFFSET 0xc +#define REG_PERFTBL_RD_OFFSET 0x10 +#define REG_PERF_DOMAIN_OFFSET 0x14 +#define PER_CPU_OFFSET 0x1000 + +#define PERFTBL_MAX_ENTRIES 64U + +static void __iomem *base; +static DEFINE_PER_CPU(u32, perftbl_num_entries); + +static void virt_scale_freq_tick(void) +{ + int cpu = smp_processor_id(); + u32 max_freq = (u32)cpufreq_get_hw_max_freq(cpu); + u64 cur_freq; + unsigned long scale; + + cur_freq = (u64)readl_relaxed(base + cpu * PER_CPU_OFFSET + + REG_CUR_PERF_STATE_OFFSET); + + cur_freq <<= SCHED_CAPACITY_SHIFT; + scale = (unsigned long)div_u64(cur_freq, max_freq); + scale = min(scale, SCHED_CAPACITY_SCALE); + + this_cpu_write(arch_freq_scale, scale); +} + +static struct scale_freq_data virt_sfd = { + .source = SCALE_FREQ_SOURCE_VIRT, + .set_freq_scale = virt_scale_freq_tick, +}; + +static unsigned int virt_cpufreq_set_perf(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + writel_relaxed(target_freq, + base + policy->cpu * PER_CPU_OFFSET + REG_SET_PERF_STATE_OFFSET); + return 0; +} + +static unsigned int virt_cpufreq_fast_switch(struct cpufreq_policy *policy, + unsigned int target_freq) +{ + virt_cpufreq_set_perf(policy, target_freq); + return target_freq; +} + +static u32 virt_cpufreq_get_perftbl_entry(int cpu, u32 idx) +{ + writel_relaxed(idx, base + cpu * PER_CPU_OFFSET + + REG_PERFTBL_SEL_OFFSET); + return readl_relaxed(base + cpu * PER_CPU_OFFSET + + REG_PERFTBL_RD_OFFSET); +} + +static int virt_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + int ret = 0; + + freqs.old = policy->cur; + freqs.new = target_freq; + + cpufreq_freq_transition_begin(policy, &freqs); + ret = virt_cpufreq_set_perf(policy, target_freq); + cpufreq_freq_transition_end(policy, &freqs, ret != 0); + + return ret; +} + +static int virt_cpufreq_get_sharing_cpus(struct cpufreq_policy *policy) +{ + u32 cur_perf_domain, perf_domain; + struct device *cpu_dev; + int cpu; + + cur_perf_domain = readl_relaxed(base + policy->cpu * + PER_CPU_OFFSET + REG_PERF_DOMAIN_OFFSET); + + for_each_possible_cpu(cpu) { + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) + continue; + + perf_domain = readl_relaxed(base + cpu * + PER_CPU_OFFSET + REG_PERF_DOMAIN_OFFSET); + + if (perf_domain == cur_perf_domain) + cpumask_set_cpu(cpu, policy->cpus); + } + + return 0; +} + +static int virt_cpufreq_get_freq_info(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *table; + u32 num_perftbl_entries, idx; + + num_perftbl_entries = per_cpu(perftbl_num_entries, policy->cpu); + + if (num_perftbl_entries == 1) { + policy->cpuinfo.min_freq = 1; + policy->cpuinfo.max_freq = virt_cpufreq_get_perftbl_entry(policy->cpu, 0); + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + + policy->cur = policy->max; + return 0; + } + + table = kcalloc(num_perftbl_entries + 1, sizeof(*table), GFP_KERNEL); + if (!table) + return -ENOMEM; + + for (idx = 0; idx < num_perftbl_entries; idx++) + table[idx].frequency = virt_cpufreq_get_perftbl_entry(policy->cpu, idx); + + table[idx].frequency = CPUFREQ_TABLE_END; + policy->freq_table = table; + + return 0; +} + +static int virt_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + struct device *cpu_dev; + int ret; + + cpu_dev = get_cpu_device(policy->cpu); + if (!cpu_dev) + return -ENODEV; + + ret = virt_cpufreq_get_freq_info(policy); + if (ret) { + dev_warn(cpu_dev, "failed to get cpufreq info\n"); + return ret; + } + + ret = virt_cpufreq_get_sharing_cpus(policy); + if (ret) { + dev_warn(cpu_dev, "failed to get sharing cpumask\n"); + return ret; + } + + /* + * To simplify and improve latency of handling frequency requests on + * the host side, this ensures that the vCPU thread triggering the MMIO + * abort is the same thread whose performance constraints (Ex. uclamp + * settings) need to be updated. This simplifies the VMM (Virtual + * Machine Manager) having to find the correct vCPU thread and/or + * facing permission issues when configuring other threads. + */ + policy->dvfs_possible_from_any_cpu = false; + policy->fast_switch_possible = true; + + /* + * Using the default SCALE_FREQ_SOURCE_CPUFREQ is insufficient since + * the actual physical CPU frequency may not match requested frequency + * from the vCPU thread due to frequency update latencies or other + * inputs to the physical CPU frequency selection. This additional FIE + * source allows for more accurate freq_scale updates and only takes + * effect if another FIE source such as AMUs have not been registered. + */ + topology_set_scale_freq_source(&virt_sfd, policy->cpus); + + return 0; +} + +static void virt_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_VIRT, policy->related_cpus); + kfree(policy->freq_table); +} + +static int virt_cpufreq_online(struct cpufreq_policy *policy) +{ + /* Nothing to restore. */ + return 0; +} + +static int virt_cpufreq_offline(struct cpufreq_policy *policy) +{ + /* Dummy offline() to avoid exit() being called and freeing resources. */ + return 0; +} + +static int virt_cpufreq_verify_policy(struct cpufreq_policy_data *policy) +{ + if (policy->freq_table) + return cpufreq_frequency_table_verify(policy, policy->freq_table); + + cpufreq_verify_within_cpu_limits(policy); + return 0; +} + +static struct cpufreq_driver cpufreq_virt_driver = { + .name = "virt-cpufreq", + .init = virt_cpufreq_cpu_init, + .exit = virt_cpufreq_cpu_exit, + .online = virt_cpufreq_online, + .offline = virt_cpufreq_offline, + .verify = virt_cpufreq_verify_policy, + .target = virt_cpufreq_target, + .fast_switch = virt_cpufreq_fast_switch, + .attr = cpufreq_generic_attr, +}; + +static int virt_cpufreq_driver_probe(struct platform_device *pdev) +{ + u32 num_perftbl_entries; + int ret, cpu; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + for_each_possible_cpu(cpu) { + num_perftbl_entries = readl_relaxed(base + cpu * PER_CPU_OFFSET + + REG_PERFTBL_LEN_OFFSET); + + if (!num_perftbl_entries || num_perftbl_entries > PERFTBL_MAX_ENTRIES) + return -ENODEV; + + per_cpu(perftbl_num_entries, cpu) = num_perftbl_entries; + } + + ret = cpufreq_register_driver(&cpufreq_virt_driver); + if (ret) { + dev_err(&pdev->dev, "Virtual CPUFreq driver failed to register: %d\n", ret); + return ret; + } + + dev_dbg(&pdev->dev, "Virtual CPUFreq driver initialized\n"); + return 0; +} + +static void virt_cpufreq_driver_remove(struct platform_device *pdev) +{ + cpufreq_unregister_driver(&cpufreq_virt_driver); +} + +static const struct of_device_id virt_cpufreq_match[] = { + { .compatible = "qemu,virtual-cpufreq", .data = NULL}, + {} +}; +MODULE_DEVICE_TABLE(of, virt_cpufreq_match); + +static struct platform_driver virt_cpufreq_driver = { + .probe = virt_cpufreq_driver_probe, + .remove = virt_cpufreq_driver_remove, + .driver = { + .name = "virt-cpufreq", + .of_match_table = virt_cpufreq_match, + }, +}; + +static int __init virt_cpufreq_init(void) +{ + return platform_driver_register(&virt_cpufreq_driver); +} +postcore_initcall(virt_cpufreq_init); + +static void __exit virt_cpufreq_exit(void) +{ + platform_driver_unregister(&virt_cpufreq_driver); +} +module_exit(virt_cpufreq_exit); + +MODULE_DESCRIPTION("Virtual cpufreq driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index 7cfb980a357d84..caba6f4bb1b793 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -139,7 +139,7 @@ static int __init arm_idle_init_cpu(int cpu) * * Initializes arm cpuidle driver for all CPUs, if any CPU fails * to register cpuidle driver then rollback to cancel all CPUs - * registeration. + * registration. */ static int __init arm_idle_init(void) { diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 602c4dfdd7e2ea..5235e6e8f360fb 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -66,7 +66,7 @@ static void kirkwood_cpuidle_remove(struct platform_device *pdev) static struct platform_driver kirkwood_cpuidle_driver = { .probe = kirkwood_cpuidle_probe, - .remove_new = kirkwood_cpuidle_remove, + .remove = kirkwood_cpuidle_remove, .driver = { .name = "kirkwood_cpuidle", }, diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c index 14db9b7d985d14..f68c65f1d023f2 100644 --- a/drivers/cpuidle/cpuidle-pseries.c +++ b/drivers/cpuidle/cpuidle-pseries.c @@ -22,6 +22,7 @@ #include #include #include +#include static struct cpuidle_driver pseries_idle_driver = { .name = "pseries_idle", diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c index 1fc9968eae1996..3ab240e0e12292 100644 --- a/drivers/cpuidle/cpuidle-qcom-spm.c +++ b/drivers/cpuidle/cpuidle-qcom-spm.c @@ -48,7 +48,7 @@ static int qcom_cpu_spc(struct spm_driver_data *drv) ret = cpu_suspend(0, qcom_pm_collapse); /* * ARM common code executes WFI without calling into our driver and - * if the SPM mode is not reset, then we may accidently power down the + * if the SPM mode is not reset, then we may accidentally power down the * cpu when we intended only to gate the cpu clock. * Ensure the state is set to standby before returning. */ diff --git a/drivers/cpuidle/cpuidle-riscv-sbi.c b/drivers/cpuidle/cpuidle-riscv-sbi.c index d228b4d18d5600..14462c092039ea 100644 --- a/drivers/cpuidle/cpuidle-riscv-sbi.c +++ b/drivers/cpuidle/cpuidle-riscv-sbi.c @@ -26,6 +26,7 @@ #include #include +#include "cpuidle.h" #include "dt_idle_states.h" #include "dt_idle_genpd.h" @@ -329,6 +330,9 @@ static int sbi_cpuidle_init_cpu(struct device *dev, int cpu) return ret; } + if (cpuidle_disabled()) + return 0; + ret = cpuidle_register(drv, NULL); if (ret) goto deinit; @@ -538,7 +542,10 @@ static int sbi_cpuidle_probe(struct platform_device *pdev) /* Setup CPU hotplut notifiers */ sbi_idle_init_cpuhp(); - pr_info("idle driver registered for all CPUs\n"); + if (cpuidle_disabled()) + pr_info("cpuidle is disabled\n"); + else + pr_info("idle driver registered for all CPUs\n"); return 0; @@ -582,4 +589,4 @@ static int __init sbi_cpuidle_init(void) return 0; } -device_initcall(sbi_cpuidle_init); +arch_initcall(sbi_cpuidle_init); diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 9e418aec17550e..0835da449db8b4 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -69,11 +69,15 @@ int cpuidle_play_dead(void) if (!drv) return -ENODEV; - /* Find lowest-power state that supports long-term idle */ - for (i = drv->state_count - 1; i >= 0; i--) + for (i = drv->state_count - 1; i >= 0; i--) { if (drv->states[i].enter_dead) - return drv->states[i].enter_dead(dev, i); + drv->states[i].enter_dead(dev, i); + } + /* + * If :enter_dead() is successful, it will never return, so reaching + * here means that all of them failed above or were not present. + */ return -ENODEV; } @@ -406,7 +410,7 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index) * Min polling interval of 10usec is a guess. It is assuming that * for most users, the time for a single ping-pong workload like * perf bench pipe would generally complete within 10usec but - * this is hardware dependant. Actual time can be estimated with + * this is hardware dependent. Actual time can be estimated with * * perf bench sched pipe -l 10000 * diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index cf5873cc45dc8c..9bbfa594c4425d 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -261,7 +261,7 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) * @drv: a pointer to a valid struct cpuidle_driver * * Register the driver under a lock to prevent concurrent attempts to - * [un]register the driver from occuring at the same time. + * [un]register the driver from occurring at the same time. * * Returns 0 on success, a negative error code (returned by * __cpuidle_register_driver()) otherwise. @@ -296,7 +296,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver); * @drv: a pointer to a valid struct cpuidle_driver * * Unregisters the cpuidle driver under a lock to prevent concurrent attempts - * to [un]register the driver from occuring at the same time. @drv has to + * to [un]register the driver from occurring at the same time. @drv has to * match the currently registered driver. */ void cpuidle_unregister_driver(struct cpuidle_driver *drv) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index f3c9d49f0f2a52..28363bfa3e4c9f 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -19,7 +19,7 @@ #include "gov.h" -#define BUCKETS 12 +#define BUCKETS 6 #define INTERVAL_SHIFT 3 #define INTERVALS (1UL << INTERVAL_SHIFT) #define RESOLUTION 1024 @@ -29,12 +29,11 @@ /* * Concepts and ideas behind the menu governor * - * For the menu governor, there are 3 decision factors for picking a C + * For the menu governor, there are 2 decision factors for picking a C * state: * 1) Energy break even point - * 2) Performance impact - * 3) Latency tolerance (from pmqos infrastructure) - * These three factors are treated independently. + * 2) Latency tolerance (from pmqos infrastructure) + * These two factors are treated independently. * * Energy break even point * ----------------------- @@ -75,30 +74,6 @@ * intervals and if the stand deviation of these 8 intervals is below a * threshold value, we use the average of these intervals as prediction. * - * Limiting Performance Impact - * --------------------------- - * C states, especially those with large exit latencies, can have a real - * noticeable impact on workloads, which is not acceptable for most sysadmins, - * and in addition, less performance has a power price of its own. - * - * As a general rule of thumb, menu assumes that the following heuristic - * holds: - * The busier the system, the less impact of C states is acceptable - * - * This rule-of-thumb is implemented using a performance-multiplier: - * If the exit latency times the performance multiplier is longer than - * the predicted duration, the C state is not considered a candidate - * for selection due to a too high performance impact. So the higher - * this multiplier is, the longer we need to be idle to pick a deep C - * state, and thus the less likely a busy CPU will hit such a deep - * C state. - * - * Currently there is only one value determining the factor: - * 10 points are added for each process that is waiting for IO on this CPU. - * (This value was experimentally determined.) - * Utilization is no longer a factor as it was shown that it never contributed - * significantly to the performance multiplier in the first place. - * */ struct menu_device { @@ -112,19 +87,10 @@ struct menu_device { int interval_ptr; }; -static inline int which_bucket(u64 duration_ns, unsigned int nr_iowaiters) +static inline int which_bucket(u64 duration_ns) { int bucket = 0; - /* - * We keep two groups of stats; one with no - * IO pending, one without. - * This allows us to calculate - * E(duration)|iowait - */ - if (nr_iowaiters) - bucket = BUCKETS/2; - if (duration_ns < 10ULL * NSEC_PER_USEC) return bucket; if (duration_ns < 100ULL * NSEC_PER_USEC) @@ -138,19 +104,6 @@ static inline int which_bucket(u64 duration_ns, unsigned int nr_iowaiters) return bucket + 5; } -/* - * Return a multiplier for the exit latency that is intended - * to take performance requirements into account. - * The more performance critical we estimate the system - * to be, the higher this multiplier, and thus the higher - * the barrier to go to an expensive C state. - */ -static inline int performance_multiplier(unsigned int nr_iowaiters) -{ - /* for IO wait tasks (per cpu!) we add 10x each */ - return 1 + 10 * nr_iowaiters; -} - static DEFINE_PER_CPU(struct menu_device, menu_devices); static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); @@ -258,8 +211,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, struct menu_device *data = this_cpu_ptr(&menu_devices); s64 latency_req = cpuidle_governor_latency_req(dev->cpu); u64 predicted_ns; - u64 interactivity_req; - unsigned int nr_iowaiters; ktime_t delta, delta_tick; int i, idx; @@ -268,8 +219,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, data->needs_update = 0; } - nr_iowaiters = nr_iowait_cpu(dev->cpu); - /* Find the shortest expected idle interval. */ predicted_ns = get_typical_interval(data) * NSEC_PER_USEC; if (predicted_ns > RESIDENCY_THRESHOLD_NS) { @@ -283,7 +232,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, } data->next_timer_ns = delta; - data->bucket = which_bucket(data->next_timer_ns, nr_iowaiters); + data->bucket = which_bucket(data->next_timer_ns); /* Round up the result for half microseconds. */ timer_us = div_u64((RESOLUTION * DECAY * NSEC_PER_USEC) / 2 + @@ -301,7 +250,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, */ data->next_timer_ns = KTIME_MAX; delta_tick = TICK_NSEC / 2; - data->bucket = which_bucket(KTIME_MAX, nr_iowaiters); + data->bucket = which_bucket(KTIME_MAX); } if (unlikely(drv->state_count <= 1 || latency_req == 0) || @@ -328,15 +277,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, */ if (predicted_ns < TICK_NSEC) predicted_ns = data->next_timer_ns; - } else { - /* - * Use the performance multiplier and the user-configurable - * latency_req to determine the maximum exit latency. - */ - interactivity_req = div64_u64(predicted_ns, - performance_multiplier(nr_iowaiters)); - if (latency_req > interactivity_req) - latency_req = interactivity_req; + } else if (latency_req > predicted_ns) { + latency_req = predicted_ns; } /* diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 08b1238bcd7b37..0a9cdd31cbd9f9 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -95,6 +95,9 @@ config PKEY loaded when a CEX crypto card is available. - A pkey EP11 kernel module (pkey-ep11.ko) which is automatically loaded when a CEX crypto card is available. + - A pkey UV kernel module (pkey-uv.ko) which is automatically + loaded when the Ultravisor feature is available within a + protected execution environment. Select this option if you want to enable the kernel and userspace API for protected key handling. @@ -152,6 +155,24 @@ config PKEY_PCKMO this option unless you are sure you never need to derive protected keys from clear key values directly via PCKMO. +config PKEY_UV + tristate "PKEY UV support handler" + depends on PKEY + depends on S390_UV_UAPI + help + This is the PKEY Ultravisor support handler for deriving protected + keys from secrets stored within the Ultravisor (UV). + + This module works together with the UV device and supports the + retrieval of protected keys from secrets stored within the + UV firmware layer. This service is only available within + a protected execution guest and thus this module will fail upon + modprobe if no protected execution environment is detected. + + Enable this option if you intend to run this kernel with an KVM + guest with protected execution and you want to use UV retrievable + secrets via PKEY API. + config CRYPTO_PAES_S390 tristate "PAES cipher algorithms" depends on S390 diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c index 890664bd5f0f13..58a76e2ba64e25 100644 --- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c +++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c @@ -542,7 +542,7 @@ MODULE_DEVICE_TABLE(of, a20ss_crypto_of_match_table); static struct platform_driver sun4i_ss_driver = { .probe = sun4i_ss_probe, - .remove_new = sun4i_ss_remove, + .remove = sun4i_ss_remove, .driver = { .name = "sun4i-ss", .pm = &sun4i_ss_pm_ops, diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c index e55e58e164db32..ec1ffda9ea32e0 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-core.c @@ -1129,7 +1129,7 @@ MODULE_DEVICE_TABLE(of, sun8i_ce_crypto_of_match_table); static struct platform_driver sun8i_ce_driver = { .probe = sun8i_ce_probe, - .remove_new = sun8i_ce_remove, + .remove = sun8i_ce_remove, .driver = { .name = "sun8i-ce", .pm = &sun8i_ce_pm_ops, diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c index 0dbc0220146c71..f45685707e0d3f 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-core.c @@ -929,7 +929,7 @@ MODULE_DEVICE_TABLE(of, sun8i_ss_crypto_of_match_table); static struct platform_driver sun8i_ss_driver = { .probe = sun8i_ss_probe, - .remove_new = sun8i_ss_remove, + .remove = sun8i_ss_remove, .driver = { .name = "sun8i-ss", .pm = &sun8i_ss_pm_ops, diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 6006703fb6d767..ec3ccfa60445fc 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -653,9 +653,6 @@ static void crypto4xx_stop_all(struct crypto4xx_core_device *core_dev) crypto4xx_destroy_pdr(core_dev->dev); crypto4xx_destroy_gdr(core_dev->dev); crypto4xx_destroy_sdr(core_dev->dev); - iounmap(core_dev->dev->ce_base); - kfree(core_dev->dev); - kfree(core_dev); } static u32 get_next_gd(u32 current) @@ -1333,17 +1330,12 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { static int crypto4xx_probe(struct platform_device *ofdev) { int rc; - struct resource res; struct device *dev = &ofdev->dev; struct crypto4xx_core_device *core_dev; struct device_node *np; u32 pvr; bool is_revb = true; - rc = of_address_to_resource(ofdev->dev.of_node, 0, &res); - if (rc) - return -ENODEV; - np = of_find_compatible_node(NULL, NULL, "amcc,ppc460ex-crypto"); if (np) { mtdcri(SDR0, PPC460EX_SDR0_SRST, @@ -1374,16 +1366,17 @@ static int crypto4xx_probe(struct platform_device *ofdev) of_node_put(np); - core_dev = kzalloc(sizeof(struct crypto4xx_core_device), GFP_KERNEL); + core_dev = devm_kzalloc( + &ofdev->dev, sizeof(struct crypto4xx_core_device), GFP_KERNEL); if (!core_dev) return -ENOMEM; dev_set_drvdata(dev, core_dev); core_dev->ofdev = ofdev; - core_dev->dev = kzalloc(sizeof(struct crypto4xx_device), GFP_KERNEL); - rc = -ENOMEM; + core_dev->dev = devm_kzalloc( + &ofdev->dev, sizeof(struct crypto4xx_device), GFP_KERNEL); if (!core_dev->dev) - goto err_alloc_dev; + return -ENOMEM; /* * Older version of 460EX/GT have a hardware bug. @@ -1402,7 +1395,9 @@ static int crypto4xx_probe(struct platform_device *ofdev) core_dev->dev->core_dev = core_dev; core_dev->dev->is_revb = is_revb; core_dev->device = dev; - mutex_init(&core_dev->rng_lock); + rc = devm_mutex_init(&ofdev->dev, &core_dev->rng_lock); + if (rc) + return rc; spin_lock_init(&core_dev->lock); INIT_LIST_HEAD(&core_dev->dev->alg_list); ratelimit_default_init(&core_dev->dev->aead_ratelimit); @@ -1421,21 +1416,21 @@ static int crypto4xx_probe(struct platform_device *ofdev) tasklet_init(&core_dev->tasklet, crypto4xx_bh_tasklet_cb, (unsigned long) dev); - core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0); - if (!core_dev->dev->ce_base) { - dev_err(dev, "failed to of_iomap\n"); - rc = -ENOMEM; - goto err_iomap; + core_dev->dev->ce_base = devm_platform_ioremap_resource(ofdev, 0); + if (IS_ERR(core_dev->dev->ce_base)) { + dev_err(&ofdev->dev, "failed to ioremap resource"); + rc = PTR_ERR(core_dev->dev->ce_base); + goto err_build_sdr; } /* Register for Crypto isr, Crypto Engine IRQ */ core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); - rc = request_irq(core_dev->irq, is_revb ? - crypto4xx_ce_interrupt_handler_revb : - crypto4xx_ce_interrupt_handler, 0, - KBUILD_MODNAME, dev); + rc = devm_request_irq(&ofdev->dev, core_dev->irq, + is_revb ? crypto4xx_ce_interrupt_handler_revb : + crypto4xx_ce_interrupt_handler, + 0, KBUILD_MODNAME, dev); if (rc) - goto err_request_irq; + goto err_iomap; /* need to setup pdr, rdr, gdr and sdr before this */ crypto4xx_hw_init(core_dev->dev); @@ -1444,26 +1439,17 @@ static int crypto4xx_probe(struct platform_device *ofdev) rc = crypto4xx_register_alg(core_dev->dev, crypto4xx_alg, ARRAY_SIZE(crypto4xx_alg)); if (rc) - goto err_start_dev; + goto err_iomap; ppc4xx_trng_probe(core_dev); return 0; -err_start_dev: - free_irq(core_dev->irq, dev); -err_request_irq: - irq_dispose_mapping(core_dev->irq); - iounmap(core_dev->dev->ce_base); err_iomap: tasklet_kill(&core_dev->tasklet); err_build_sdr: crypto4xx_destroy_sdr(core_dev->dev); crypto4xx_destroy_gdr(core_dev->dev); crypto4xx_destroy_pdr(core_dev->dev); - kfree(core_dev->dev); -err_alloc_dev: - kfree(core_dev); - return rc; } @@ -1474,13 +1460,9 @@ static void crypto4xx_remove(struct platform_device *ofdev) ppc4xx_trng_remove(core_dev); - free_irq(core_dev->irq, dev); - irq_dispose_mapping(core_dev->irq); - tasklet_kill(&core_dev->tasklet); /* Un-register with Linux CryptoAPI */ crypto4xx_unregister_alg(core_dev->dev); - mutex_destroy(&core_dev->rng_lock); /* Free all allocated memory */ crypto4xx_stop_all(core_dev); } @@ -1497,7 +1479,7 @@ static struct platform_driver crypto4xx_driver = { .of_match_table = crypto4xx_match, }, .probe = crypto4xx_probe, - .remove_new = crypto4xx_remove, + .remove = crypto4xx_remove, }; module_platform_driver(crypto4xx_driver); diff --git a/drivers/crypto/amlogic/amlogic-gxl-core.c b/drivers/crypto/amlogic/amlogic-gxl-core.c index f54ab0d0b1e852..1c18a5b8470e0d 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-core.c +++ b/drivers/crypto/amlogic/amlogic-gxl-core.c @@ -240,11 +240,9 @@ static int meson_crypto_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mc); mc->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(mc->base)) { - err = PTR_ERR(mc->base); - dev_err(&pdev->dev, "Cannot request MMIO err=%d\n", err); - return err; - } + if (IS_ERR(mc->base)) + return PTR_ERR(mc->base); + mc->busclk = devm_clk_get(&pdev->dev, "blkmv"); if (IS_ERR(mc->busclk)) { err = PTR_ERR(mc->busclk); @@ -322,7 +320,7 @@ MODULE_DEVICE_TABLE(of, meson_crypto_of_match_table); static struct platform_driver meson_crypto_driver = { .probe = meson_crypto_probe, - .remove_new = meson_crypto_remove, + .remove = meson_crypto_remove, .driver = { .name = "gxl-crypto", .of_match_table = meson_crypto_of_match_table, diff --git a/drivers/crypto/aspeed/aspeed-acry.c b/drivers/crypto/aspeed/aspeed-acry.c index b4613bd4ad9643..8d1c79aaca07d7 100644 --- a/drivers/crypto/aspeed/aspeed-acry.c +++ b/drivers/crypto/aspeed/aspeed-acry.c @@ -601,8 +601,6 @@ static struct aspeed_acry_alg aspeed_acry_akcipher_algs[] = { .akcipher.base = { .encrypt = aspeed_acry_rsa_enc, .decrypt = aspeed_acry_rsa_dec, - .sign = aspeed_acry_rsa_dec, - .verify = aspeed_acry_rsa_enc, .set_pub_key = aspeed_acry_rsa_set_pub_key, .set_priv_key = aspeed_acry_rsa_set_priv_key, .max_size = aspeed_acry_rsa_max_size, @@ -808,7 +806,7 @@ MODULE_DEVICE_TABLE(of, aspeed_acry_of_matches); static struct platform_driver aspeed_acry_driver = { .probe = aspeed_acry_probe, - .remove_new = aspeed_acry_remove, + .remove = aspeed_acry_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = aspeed_acry_of_matches, diff --git a/drivers/crypto/aspeed/aspeed-hace.c b/drivers/crypto/aspeed/aspeed-hace.c index 062f2a66dd2399..3fe644bfe0373e 100644 --- a/drivers/crypto/aspeed/aspeed-hace.c +++ b/drivers/crypto/aspeed/aspeed-hace.c @@ -266,7 +266,7 @@ MODULE_DEVICE_TABLE(of, aspeed_hace_of_matches); static struct platform_driver aspeed_hace_driver = { .probe = aspeed_hace_probe, - .remove_new = aspeed_hace_remove, + .remove = aspeed_hace_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = aspeed_hace_of_matches, diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 0dd90785db9a86..14bf86957d3182 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -2453,7 +2453,7 @@ static void atmel_aes_remove(struct platform_device *pdev) static struct platform_driver atmel_aes_driver = { .probe = atmel_aes_probe, - .remove_new = atmel_aes_remove, + .remove = atmel_aes_remove, .driver = { .name = "atmel_aes", .of_match_table = atmel_aes_dt_ids, diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c index 590ea984c6220a..0d48e64d28b113 100644 --- a/drivers/crypto/atmel-ecc.c +++ b/drivers/crypto/atmel-ecc.c @@ -379,7 +379,7 @@ MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids); #endif static const struct i2c_device_id atmel_ecc_id[] = { - { "atecc508a", 0 }, + { "atecc508a" }, { } }; MODULE_DEVICE_TABLE(i2c, atmel_ecc_id); diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 8cc57df257784a..67a17060856634 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -2691,7 +2691,7 @@ static void atmel_sha_remove(struct platform_device *pdev) static struct platform_driver atmel_sha_driver = { .probe = atmel_sha_probe, - .remove_new = atmel_sha_remove, + .remove = atmel_sha_remove, .driver = { .name = "atmel_sha", .of_match_table = atmel_sha_dt_ids, diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c index a02d496f4c410f..75bebec2c757bf 100644 --- a/drivers/crypto/atmel-sha204a.c +++ b/drivers/crypto/atmel-sha204a.c @@ -202,8 +202,8 @@ static const struct of_device_id atmel_sha204a_dt_ids[] __maybe_unused = { MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids); static const struct i2c_device_id atmel_sha204a_id[] = { - { "atsha204", 0 }, - { "atsha204a", 0 }, + { "atsha204" }, + { "atsha204a" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, atmel_sha204a_id); diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index dcc2380a5889f5..de9717e221e424 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -872,7 +872,7 @@ static void atmel_tdes_done_task(unsigned long data) if (!err) err = atmel_tdes_crypt_start(dd); if (!err) - return; /* DMA started. Not fininishing. */ + return; /* DMA started. Not finishing. */ } atmel_tdes_finish_req(dd, err); @@ -1074,7 +1074,7 @@ static void atmel_tdes_remove(struct platform_device *pdev) static struct platform_driver atmel_tdes_driver = { .probe = atmel_tdes_probe, - .remove_new = atmel_tdes_remove, + .remove = atmel_tdes_remove, .driver = { .name = "atmel_tdes", .of_match_table = atmel_tdes_dt_ids, diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index 75440ea6206e21..1c1f57baef0ea9 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -2975,7 +2975,7 @@ static void artpec6_crypto_remove(struct platform_device *pdev) static struct platform_driver artpec6_crypto_driver = { .probe = artpec6_crypto_probe, - .remove_new = artpec6_crypto_remove, + .remove = artpec6_crypto_remove, .driver = { .name = "artpec6-crypto", .of_match_table = artpec6_crypto_of_match, diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 1a3ecd44cbaf65..9e6798efbfb769 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -2415,6 +2415,7 @@ static int ahash_hmac_setkey(struct crypto_ahash *ahash, const u8 *key, static int ahash_hmac_init(struct ahash_request *req) { + int ret; struct iproc_reqctx_s *rctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); struct iproc_ctx_s *ctx = crypto_ahash_ctx(tfm); @@ -2424,7 +2425,9 @@ static int ahash_hmac_init(struct ahash_request *req) flow_log("ahash_hmac_init()\n"); /* init the context as a hash */ - ahash_init(req); + ret = ahash_init(req); + if (ret) + return ret; if (!spu_no_incr_hash(ctx)) { /* SPU-M can do incr hashing but needs sw for outer HMAC */ @@ -4704,7 +4707,7 @@ static struct platform_driver bcm_spu_pdriver = { .of_match_table = of_match_ptr(bcm_spu_dt_ids), }, .probe = bcm_spu_probe, - .remove_new = bcm_spu_remove, + .remove = bcm_spu_remove, }; module_platform_driver(bcm_spu_pdriver); diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index 887a5f2fb9279b..cb001aa1de6618 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -984,7 +984,7 @@ static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, return -ENOMEM; } -static void caam_rsa_set_priv_key_form(struct caam_rsa_ctx *ctx, +static int caam_rsa_set_priv_key_form(struct caam_rsa_ctx *ctx, struct rsa_key *raw_key) { struct caam_rsa_key *rsa_key = &ctx->key; @@ -994,7 +994,7 @@ static void caam_rsa_set_priv_key_form(struct caam_rsa_ctx *ctx, rsa_key->p = caam_read_raw_data(raw_key->p, &p_sz); if (!rsa_key->p) - return; + return -ENOMEM; rsa_key->p_sz = p_sz; rsa_key->q = caam_read_raw_data(raw_key->q, &q_sz); @@ -1029,7 +1029,7 @@ static void caam_rsa_set_priv_key_form(struct caam_rsa_ctx *ctx, rsa_key->priv_form = FORM3; - return; + return 0; free_dq: kfree_sensitive(rsa_key->dq); @@ -1043,6 +1043,7 @@ static void caam_rsa_set_priv_key_form(struct caam_rsa_ctx *ctx, kfree_sensitive(rsa_key->q); free_p: kfree_sensitive(rsa_key->p); + return -ENOMEM; } static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, @@ -1088,7 +1089,9 @@ static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, rsa_key->e_sz = raw_key.e_sz; rsa_key->n_sz = raw_key.n_sz; - caam_rsa_set_priv_key_form(ctx, &raw_key); + ret = caam_rsa_set_priv_key_form(ctx, &raw_key); + if (ret) + goto err; return 0; diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 26eba7de3fb0e4..9fcdb64084accd 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -819,7 +819,7 @@ static struct platform_driver caam_jr_driver = { .pm = pm_ptr(&caam_jr_pm_ops), }, .probe = caam_jr_probe, - .remove_new = caam_jr_remove, + .remove = caam_jr_remove, .shutdown = caam_jr_remove, }; diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c index f6111ee9ed342d..7701d00bcb3ac5 100644 --- a/drivers/crypto/caam/qi.c +++ b/drivers/crypto/caam/qi.c @@ -733,7 +733,7 @@ static void free_caam_qi_pcpu_netdev(const cpumask_t *cpus) int caam_qi_init(struct platform_device *caam_pdev) { int err, i; - struct device *ctrldev = &caam_pdev->dev, *qidev; + struct device *qidev = &caam_pdev->dev; struct caam_drv_private *ctrlpriv; const cpumask_t *cpus = qman_affine_cpus(); cpumask_var_t clean_mask; @@ -742,8 +742,7 @@ int caam_qi_init(struct platform_device *caam_pdev) if (!zalloc_cpumask_var(&clean_mask, GFP_KERNEL)) goto fail_cpumask; - ctrlpriv = dev_get_drvdata(ctrldev); - qidev = ctrldev; + ctrlpriv = dev_get_drvdata(qidev); /* Initialize the congestion detection */ err = init_cgr(qidev); @@ -794,7 +793,7 @@ int caam_qi_init(struct platform_device *caam_pdev) caam_debugfs_qi_init(ctrlpriv); - err = devm_add_action_or_reset(qidev, caam_qi_shutdown, ctrlpriv); + err = devm_add_action_or_reset(qidev, caam_qi_shutdown, qidev); if (err) goto fail2; diff --git a/drivers/crypto/cavium/cpt/cptpf_main.c b/drivers/crypto/cavium/cpt/cptpf_main.c index 6872ac3440010f..54de869e5374c2 100644 --- a/drivers/crypto/cavium/cpt/cptpf_main.c +++ b/drivers/crypto/cavium/cpt/cptpf_main.c @@ -44,7 +44,7 @@ static void cpt_disable_cores(struct cpt_device *cpt, u64 coremask, dev_err(dev, "Cores still busy %llx", coremask); grp = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXEC_BUSY(0)); - if (timeout--) + if (!timeout--) break; udelay(CSR_DELAY); @@ -302,6 +302,8 @@ static int cpt_ucode_load_fw(struct cpt_device *cpt, const u8 *fw, bool is_ae) ret = do_cpt_init(cpt, mcode); if (ret) { + dma_free_coherent(&cpt->pdev->dev, mcode->code_size, + mcode->code, mcode->phys_base); dev_err(dev, "do_cpt_init failed with ret: %d\n", ret); goto fw_release; } @@ -394,7 +396,7 @@ static void cpt_disable_all_cores(struct cpt_device *cpt) dev_err(dev, "Cores still busy"); grp = cpt_read_csr64(cpt->reg_base, CPTX_PF_EXEC_BUSY(0)); - if (timeout--) + if (!timeout--) break; udelay(CSR_DELAY); diff --git a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c index 153004bdfb5cde..fb59bb28245575 100644 --- a/drivers/crypto/cavium/cpt/cptvf_reqmanager.c +++ b/drivers/crypto/cavium/cpt/cptvf_reqmanager.c @@ -238,7 +238,7 @@ static int send_cpt_command(struct cpt_vf *cptvf, union cpt_inst_s *cmd, qinfo = &cptvf->cqinfo; queue = &qinfo->queue[qno]; - /* lock commad queue */ + /* lock command queue */ spin_lock(&queue->lock); ent = &queue->qhead->head[queue->idx * qinfo->cmd_size]; memcpy(ent, (void *)cmd, qinfo->cmd_size); @@ -510,7 +510,7 @@ int process_request(struct cpt_vf *cptvf, struct cpt_request_info *req) info->time_in = jiffies; info->req = req; - /* Create the CPT_INST_S type command for HW intrepretation */ + /* Create the CPT_INST_S type command for HW interpretation */ cptinst.s.doneint = true; cptinst.s.res_addr = (u64)info->comp_baddr; cptinst.s.tag = 0; diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c index a5cdc2b48bd6c3..068265207ddd8a 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_lib.c +++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c @@ -17,7 +17,7 @@ #define CRYPTO_CTX_SIZE 256 -/* packet inuput ring alignments */ +/* packet input ring alignments */ #define PKTIN_Q_ALIGN_BYTES 16 /* AQM Queue input alignments */ #define AQM_Q_ALIGN_BYTES 32 diff --git a/drivers/crypto/ccp/sp-platform.c b/drivers/crypto/ccp/sp-platform.c index ff6ceb4feee04e..3933cac1694d4e 100644 --- a/drivers/crypto/ccp/sp-platform.c +++ b/drivers/crypto/ccp/sp-platform.c @@ -210,7 +210,7 @@ static struct platform_driver sp_platform_driver = { .of_match_table = sp_of_match, }, .probe = sp_platform_probe, - .remove_new = sp_platform_remove, + .remove = sp_platform_remove, #ifdef CONFIG_PM .suspend = sp_platform_suspend, .resume = sp_platform_resume, diff --git a/drivers/crypto/ccree/cc_aead.c b/drivers/crypto/ccree/cc_aead.c index 5ef39d68238977..81533681f7fb59 100644 --- a/drivers/crypto/ccree/cc_aead.c +++ b/drivers/crypto/ccree/cc_aead.c @@ -2226,7 +2226,7 @@ static int cc_rfc4543_gcm_encrypt(struct aead_request *req) memset(areq_ctx, 0, sizeof(*areq_ctx)); - //plaintext is not encryped with rfc4543 + //plaintext is not encrypted with rfc4543 areq_ctx->plaintext_authenticate_only = true; /* No generated IV required */ @@ -2277,7 +2277,7 @@ static int cc_rfc4543_gcm_decrypt(struct aead_request *req) memset(areq_ctx, 0, sizeof(*areq_ctx)); - //plaintext is not decryped with rfc4543 + //plaintext is not decrypted with rfc4543 areq_ctx->plaintext_authenticate_only = true; /* No generated IV required */ diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index 3fb667a17bbb1d..d39c067672fd61 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -179,7 +179,7 @@ static int cc_cipher_init(struct crypto_tfm *tfm) } max_key_buf_size <<= 1; - /* Alloc fallabck tfm or essiv when key size != 256 bit */ + /* Alloc fallback tfm or essiv when key size != 256 bit */ ctx_p->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK | CRYPTO_ALG_ASYNC); diff --git a/drivers/crypto/ccree/cc_driver.c b/drivers/crypto/ccree/cc_driver.c index 9177b54bb0f58a..061e68a31c36cc 100644 --- a/drivers/crypto/ccree/cc_driver.c +++ b/drivers/crypto/ccree/cc_driver.c @@ -643,7 +643,7 @@ static struct platform_driver ccree_driver = { #endif }, .probe = ccree_probe, - .remove_new = ccree_remove, + .remove = ccree_remove, }; static int __init ccree_init(void) diff --git a/drivers/crypto/ccree/cc_hash.c b/drivers/crypto/ccree/cc_hash.c index f418162932fe39..d0612bec4d58d7 100644 --- a/drivers/crypto/ccree/cc_hash.c +++ b/drivers/crypto/ccree/cc_hash.c @@ -1577,7 +1577,7 @@ struct cc_hash_template { /* hash descriptors */ static struct cc_hash_template driver_hash[] = { - //Asynchronize hash template + //Asynchronous hash template { .name = "sha1", .driver_name = "sha1-ccree", diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 177428480c7d16..af37477ffd8ddb 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -1186,7 +1186,7 @@ static int chcr_handle_cipher_resp(struct skcipher_request *req, else bytes = rounddown(bytes, 16); } else { - /*CTR mode counter overfloa*/ + /*CTR mode counter overflow*/ bytes = req->cryptlen - reqctx->processed; } err = chcr_update_cipher_iv(req, fw6_pld, reqctx->iv); diff --git a/drivers/crypto/exynos-rng.c b/drivers/crypto/exynos-rng.c index 0dd8baf16cb457..2aaa98f9b44e23 100644 --- a/drivers/crypto/exynos-rng.c +++ b/drivers/crypto/exynos-rng.c @@ -389,7 +389,7 @@ static struct platform_driver exynos_rng_driver = { .of_match_table = exynos_rng_dt_match, }, .probe = exynos_rng_probe, - .remove_new = exynos_rng_remove, + .remove = exynos_rng_remove, }; module_platform_driver(exynos_rng_driver); diff --git a/drivers/crypto/gemini/sl3516-ce-core.c b/drivers/crypto/gemini/sl3516-ce-core.c index 1d1a889599bb43..f7e0e3fea15c32 100644 --- a/drivers/crypto/gemini/sl3516-ce-core.c +++ b/drivers/crypto/gemini/sl3516-ce-core.c @@ -528,7 +528,7 @@ MODULE_DEVICE_TABLE(of, sl3516_ce_crypto_of_match_table); static struct platform_driver sl3516_ce_driver = { .probe = sl3516_ce_probe, - .remove_new = sl3516_ce_remove, + .remove = sl3516_ce_remove, .driver = { .name = "sl3516-crypto", .pm = &sl3516_ce_pm_ops, diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index fa5a9f207bc90a..d933f26aeb3aaa 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -433,4 +433,4 @@ module_pci_driver(geode_aes_driver); MODULE_AUTHOR("Advanced Micro Devices, Inc."); MODULE_DESCRIPTION("Geode LX Hardware AES driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 1b9b7bccdeff08..45e130b901eb5e 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -192,7 +192,7 @@ static int qm_sqc_dump(struct hisi_qm *qm, char *s, char *name) down_read(&qm->qps_lock); if (qm->sqc) { - memcpy(&sqc, qm->sqc + qp_id * sizeof(struct qm_sqc), sizeof(struct qm_sqc)); + memcpy(&sqc, qm->sqc + qp_id, sizeof(struct qm_sqc)); sqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); sqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &sqc, sizeof(struct qm_sqc), "SOFT SQC"); @@ -229,7 +229,7 @@ static int qm_cqc_dump(struct hisi_qm *qm, char *s, char *name) down_read(&qm->qps_lock); if (qm->cqc) { - memcpy(&cqc, qm->cqc + qp_id * sizeof(struct qm_cqc), sizeof(struct qm_cqc)); + memcpy(&cqc, qm->cqc + qp_id, sizeof(struct qm_cqc)); cqc.base_h = cpu_to_le32(QM_XQC_ADDR_MASK); cqc.base_l = cpu_to_le32(QM_XQC_ADDR_MASK); dump_show(qm, &cqc, sizeof(struct qm_cqc), "SOFT CQC"); diff --git a/drivers/crypto/hisilicon/hpre/hpre.h b/drivers/crypto/hisilicon/hpre/hpre.h index 9f0b94c8e03dd0..0f3ddbadbcf991 100644 --- a/drivers/crypto/hisilicon/hpre/hpre.h +++ b/drivers/crypto/hisilicon/hpre/hpre.h @@ -100,6 +100,29 @@ struct hpre_sqe { __le32 rsvd1[_HPRE_SQE_ALIGN_EXT]; }; +enum hpre_cap_table_type { + QM_RAS_NFE_TYPE = 0x0, + QM_RAS_NFE_RESET, + QM_RAS_CE_TYPE, + HPRE_RAS_NFE_TYPE, + HPRE_RAS_NFE_RESET, + HPRE_RAS_CE_TYPE, + HPRE_CORE_INFO, + HPRE_CORE_EN, + HPRE_DRV_ALG_BITMAP, + HPRE_ALG_BITMAP, + HPRE_CORE1_BITMAP_CAP, + HPRE_CORE2_BITMAP_CAP, + HPRE_CORE3_BITMAP_CAP, + HPRE_CORE4_BITMAP_CAP, + HPRE_CORE5_BITMAP_CAP, + HPRE_CORE6_BITMAP_CAP, + HPRE_CORE7_BITMAP_CAP, + HPRE_CORE8_BITMAP_CAP, + HPRE_CORE9_BITMAP_CAP, + HPRE_CORE10_BITMAP_CAP, +}; + struct hisi_qp *hpre_create_qp(u8 type); int hpre_algs_register(struct hisi_qm *qm); void hpre_algs_unregister(struct hisi_qm *qm); diff --git a/drivers/crypto/hisilicon/hpre/hpre_crypto.c b/drivers/crypto/hisilicon/hpre/hpre_crypto.c index c167dbd6c7d623..2a29102612108f 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_crypto.c +++ b/drivers/crypto/hisilicon/hpre/hpre_crypto.c @@ -2006,8 +2006,6 @@ static void hpre_curve25519_exit_tfm(struct crypto_kpp *tfm) } static struct akcipher_alg rsa = { - .sign = hpre_rsa_dec, - .verify = hpre_rsa_enc, .encrypt = hpre_rsa_enc, .decrypt = hpre_rsa_dec, .set_pub_key = hpre_rsa_setpubkey, diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 6b536ad2ada52a..96fde9437b4b8f 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -13,6 +13,7 @@ #include #include "hpre.h" +#define CAP_FILE_PERMISSION 0444 #define HPRE_CTRL_CNT_CLR_CE_BIT BIT(0) #define HPRE_CTRL_CNT_CLR_CE 0x301000 #define HPRE_FSM_MAX_CNT 0x301008 @@ -203,7 +204,7 @@ static const struct hisi_qm_cap_info hpre_basic_info[] = { {HPRE_RESET_MASK_CAP, 0x3134, 0, GENMASK(31, 0), 0x0, 0x3FFFFE, 0xBFFC3E}, {HPRE_OOO_SHUTDOWN_MASK_CAP, 0x3134, 0, GENMASK(31, 0), 0x0, 0x22, 0xBFFC3E}, {HPRE_CE_MASK_CAP, 0x3138, 0, GENMASK(31, 0), 0x0, 0x1, 0x1}, - {HPRE_CLUSTER_NUM_CAP, 0x313c, 20, GENMASK(3, 0), 0x0, 0x4, 0x1}, + {HPRE_CLUSTER_NUM_CAP, 0x313c, 20, GENMASK(3, 0), 0x0, 0x4, 0x1}, {HPRE_CORE_TYPE_NUM_CAP, 0x313c, 16, GENMASK(3, 0), 0x0, 0x2, 0x2}, {HPRE_CORE_NUM_CAP, 0x313c, 8, GENMASK(7, 0), 0x0, 0x8, 0xA}, {HPRE_CLUSTER_CORE_NUM_CAP, 0x313c, 0, GENMASK(7, 0), 0x0, 0x2, 0xA}, @@ -222,18 +223,27 @@ static const struct hisi_qm_cap_info hpre_basic_info[] = { {HPRE_CORE10_ALG_BITMAP_CAP, 0x3170, 0, GENMASK(31, 0), 0x0, 0x10, 0x10} }; -enum hpre_pre_store_cap_idx { - HPRE_CLUSTER_NUM_CAP_IDX = 0x0, - HPRE_CORE_ENABLE_BITMAP_CAP_IDX, - HPRE_DRV_ALG_BITMAP_CAP_IDX, - HPRE_DEV_ALG_BITMAP_CAP_IDX, -}; - -static const u32 hpre_pre_store_caps[] = { - HPRE_CLUSTER_NUM_CAP, - HPRE_CORE_ENABLE_BITMAP_CAP, - HPRE_DRV_ALG_BITMAP_CAP, - HPRE_DEV_ALG_BITMAP_CAP, +static const struct hisi_qm_cap_query_info hpre_cap_query_info[] = { + {QM_RAS_NFE_TYPE, "QM_RAS_NFE_TYPE ", 0x3124, 0x0, 0x1C37, 0x7C37}, + {QM_RAS_NFE_RESET, "QM_RAS_NFE_RESET ", 0x3128, 0x0, 0xC77, 0x6C77}, + {QM_RAS_CE_TYPE, "QM_RAS_CE_TYPE ", 0x312C, 0x0, 0x8, 0x8}, + {HPRE_RAS_NFE_TYPE, "HPRE_RAS_NFE_TYPE ", 0x3130, 0x0, 0x3FFFFE, 0x1FFFC3E}, + {HPRE_RAS_NFE_RESET, "HPRE_RAS_NFE_RESET ", 0x3134, 0x0, 0x3FFFFE, 0xBFFC3E}, + {HPRE_RAS_CE_TYPE, "HPRE_RAS_CE_TYPE ", 0x3138, 0x0, 0x1, 0x1}, + {HPRE_CORE_INFO, "HPRE_CORE_INFO ", 0x313c, 0x0, 0x420802, 0x120A0A}, + {HPRE_CORE_EN, "HPRE_CORE_EN ", 0x3140, 0x0, 0xF, 0x3FF}, + {HPRE_DRV_ALG_BITMAP, "HPRE_DRV_ALG_BITMAP ", 0x3144, 0x0, 0x03, 0x27}, + {HPRE_ALG_BITMAP, "HPRE_ALG_BITMAP ", 0x3148, 0x0, 0x03, 0x7F}, + {HPRE_CORE1_BITMAP_CAP, "HPRE_CORE1_BITMAP_CAP ", 0x314c, 0x0, 0x7F, 0x7F}, + {HPRE_CORE2_BITMAP_CAP, "HPRE_CORE2_BITMAP_CAP ", 0x3150, 0x0, 0x7F, 0x7F}, + {HPRE_CORE3_BITMAP_CAP, "HPRE_CORE3_BITMAP_CAP ", 0x3154, 0x0, 0x7F, 0x7F}, + {HPRE_CORE4_BITMAP_CAP, "HPRE_CORE4_BITMAP_CAP ", 0x3158, 0x0, 0x7F, 0x7F}, + {HPRE_CORE5_BITMAP_CAP, "HPRE_CORE5_BITMAP_CAP ", 0x315c, 0x0, 0x7F, 0x7F}, + {HPRE_CORE6_BITMAP_CAP, "HPRE_CORE6_BITMAP_CAP ", 0x3160, 0x0, 0x7F, 0x7F}, + {HPRE_CORE7_BITMAP_CAP, "HPRE_CORE7_BITMAP_CAP ", 0x3164, 0x0, 0x7F, 0x7F}, + {HPRE_CORE8_BITMAP_CAP, "HPRE_CORE8_BITMAP_CAP ", 0x3168, 0x0, 0x7F, 0x7F}, + {HPRE_CORE9_BITMAP_CAP, "HPRE_CORE9_BITMAP_CAP ", 0x316c, 0x0, 0x10, 0x10}, + {HPRE_CORE10_BITMAP_CAP, "HPRE_CORE10_BITMAP_CAP ", 0x3170, 0x0, 0x10, 0x10}, }; static const struct hpre_hw_error hpre_hw_errors[] = { @@ -360,7 +370,7 @@ bool hpre_check_alg_support(struct hisi_qm *qm, u32 alg) { u32 cap_val; - cap_val = qm->cap_tables.dev_cap_table[HPRE_DRV_ALG_BITMAP_CAP_IDX].cap_val; + cap_val = qm->cap_tables.dev_cap_table[HPRE_DRV_ALG_BITMAP].cap_val; if (alg & cap_val) return true; @@ -415,7 +425,7 @@ static int pf_q_num_set(const char *val, const struct kernel_param *kp) { pf_q_num_flag = true; - return q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_HPRE_PF); + return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_HPRE_PF); } static const struct kernel_param_ops hpre_pf_q_num_ops = { @@ -503,14 +513,17 @@ static int hpre_cfg_by_dsm(struct hisi_qm *qm) static int hpre_set_cluster(struct hisi_qm *qm) { struct device *dev = &qm->pdev->dev; - unsigned long offset; u32 cluster_core_mask; + unsigned long offset; + u32 hpre_core_info; u8 clusters_num; u32 val = 0; int ret, i; - cluster_core_mask = qm->cap_tables.dev_cap_table[HPRE_CORE_ENABLE_BITMAP_CAP_IDX].cap_val; - clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + cluster_core_mask = qm->cap_tables.dev_cap_table[HPRE_CORE_EN].cap_val; + hpre_core_info = qm->cap_tables.dev_cap_table[HPRE_CORE_INFO].cap_val; + clusters_num = (hpre_core_info >> hpre_basic_info[HPRE_CLUSTER_NUM_CAP].shift) & + hpre_basic_info[HPRE_CLUSTER_NUM_CAP].mask; for (i = 0; i < clusters_num; i++) { offset = i * HPRE_CLSTR_ADDR_INTRVL; @@ -593,6 +606,9 @@ static void hpre_close_sva_prefetch(struct hisi_qm *qm) static void hpre_enable_clock_gate(struct hisi_qm *qm) { + unsigned long offset; + u8 clusters_num, i; + u32 hpre_core_info; u32 val; if (qm->ver < QM_HW_V3) @@ -606,17 +622,26 @@ static void hpre_enable_clock_gate(struct hisi_qm *qm) val |= HPRE_PEH_CFG_AUTO_GATE_EN; writel(val, qm->io_base + HPRE_PEH_CFG_AUTO_GATE); - val = readl(qm->io_base + HPRE_CLUSTER_DYN_CTL); - val |= HPRE_CLUSTER_DYN_CTL_EN; - writel(val, qm->io_base + HPRE_CLUSTER_DYN_CTL); - - val = readl_relaxed(qm->io_base + HPRE_CORE_SHB_CFG); - val |= HPRE_CORE_GATE_EN; - writel(val, qm->io_base + HPRE_CORE_SHB_CFG); + hpre_core_info = qm->cap_tables.dev_cap_table[HPRE_CORE_INFO].cap_val; + clusters_num = (hpre_core_info >> hpre_basic_info[HPRE_CLUSTER_NUM_CAP].shift) & + hpre_basic_info[HPRE_CLUSTER_NUM_CAP].mask; + for (i = 0; i < clusters_num; i++) { + offset = (unsigned long)i * HPRE_CLSTR_ADDR_INTRVL; + val = readl(qm->io_base + offset + HPRE_CLUSTER_DYN_CTL); + val |= HPRE_CLUSTER_DYN_CTL_EN; + writel(val, qm->io_base + offset + HPRE_CLUSTER_DYN_CTL); + + val = readl(qm->io_base + offset + HPRE_CORE_SHB_CFG); + val |= HPRE_CORE_GATE_EN; + writel(val, qm->io_base + offset + HPRE_CORE_SHB_CFG); + } } static void hpre_disable_clock_gate(struct hisi_qm *qm) { + unsigned long offset; + u8 clusters_num, i; + u32 hpre_core_info; u32 val; if (qm->ver < QM_HW_V3) @@ -630,13 +655,19 @@ static void hpre_disable_clock_gate(struct hisi_qm *qm) val &= ~HPRE_PEH_CFG_AUTO_GATE_EN; writel(val, qm->io_base + HPRE_PEH_CFG_AUTO_GATE); - val = readl(qm->io_base + HPRE_CLUSTER_DYN_CTL); - val &= ~HPRE_CLUSTER_DYN_CTL_EN; - writel(val, qm->io_base + HPRE_CLUSTER_DYN_CTL); - - val = readl_relaxed(qm->io_base + HPRE_CORE_SHB_CFG); - val &= ~HPRE_CORE_GATE_EN; - writel(val, qm->io_base + HPRE_CORE_SHB_CFG); + hpre_core_info = qm->cap_tables.dev_cap_table[HPRE_CORE_INFO].cap_val; + clusters_num = (hpre_core_info >> hpre_basic_info[HPRE_CLUSTER_NUM_CAP].shift) & + hpre_basic_info[HPRE_CLUSTER_NUM_CAP].mask; + for (i = 0; i < clusters_num; i++) { + offset = (unsigned long)i * HPRE_CLSTR_ADDR_INTRVL; + val = readl(qm->io_base + offset + HPRE_CLUSTER_DYN_CTL); + val &= ~HPRE_CLUSTER_DYN_CTL_EN; + writel(val, qm->io_base + offset + HPRE_CLUSTER_DYN_CTL); + + val = readl(qm->io_base + offset + HPRE_CORE_SHB_CFG); + val &= ~HPRE_CORE_GATE_EN; + writel(val, qm->io_base + offset + HPRE_CORE_SHB_CFG); + } } static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) @@ -699,11 +730,14 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) static void hpre_cnt_regs_clear(struct hisi_qm *qm) { unsigned long offset; + u32 hpre_core_info; u8 clusters_num; int i; /* clear clusterX/cluster_ctrl */ - clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + hpre_core_info = qm->cap_tables.dev_cap_table[HPRE_CORE_INFO].cap_val; + clusters_num = (hpre_core_info >> hpre_basic_info[HPRE_CLUSTER_NUM_CAP].shift) & + hpre_basic_info[HPRE_CLUSTER_NUM_CAP].mask; for (i = 0; i < clusters_num; i++) { offset = HPRE_CLSTR_BASE + i * HPRE_CLSTR_ADDR_INTRVL; writel(0x0, qm->io_base + offset + HPRE_CLUSTER_INQURY); @@ -995,10 +1029,13 @@ static int hpre_cluster_debugfs_init(struct hisi_qm *qm) char buf[HPRE_DBGFS_VAL_MAX_LEN]; struct debugfs_regset32 *regset; struct dentry *tmp_d; + u32 hpre_core_info; u8 clusters_num; int i, ret; - clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + hpre_core_info = qm->cap_tables.dev_cap_table[HPRE_CORE_INFO].cap_val; + clusters_num = (hpre_core_info >> hpre_basic_info[HPRE_CLUSTER_NUM_CAP].shift) & + hpre_basic_info[HPRE_CLUSTER_NUM_CAP].mask; for (i = 0; i < clusters_num; i++) { ret = snprintf(buf, HPRE_DBGFS_VAL_MAX_LEN, "cluster%d", i); if (ret >= HPRE_DBGFS_VAL_MAX_LEN) @@ -1041,6 +1078,26 @@ static int hpre_ctrl_debug_init(struct hisi_qm *qm) return hpre_cluster_debugfs_init(qm); } +static int hpre_cap_regs_show(struct seq_file *s, void *unused) +{ + struct hisi_qm *qm = s->private; + u32 i, size; + + size = qm->cap_tables.qm_cap_size; + for (i = 0; i < size; i++) + seq_printf(s, "%s= 0x%08x\n", qm->cap_tables.qm_cap_table[i].name, + qm->cap_tables.qm_cap_table[i].cap_val); + + size = qm->cap_tables.dev_cap_size; + for (i = 0; i < size; i++) + seq_printf(s, "%s= 0x%08x\n", qm->cap_tables.dev_cap_table[i].name, + qm->cap_tables.dev_cap_table[i].cap_val); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(hpre_cap_regs); + static void hpre_dfx_debug_init(struct hisi_qm *qm) { struct dfx_diff_registers *hpre_regs = qm->debug.acc_diff_regs; @@ -1059,6 +1116,9 @@ static void hpre_dfx_debug_init(struct hisi_qm *qm) if (qm->fun_type == QM_HW_PF && hpre_regs) debugfs_create_file("diff_regs", 0444, parent, qm, &hpre_diff_regs_fops); + + debugfs_create_file("cap_regs", CAP_FILE_PERMISSION, + qm->debug.debug_root, qm, &hpre_cap_regs_fops); } static int hpre_debugfs_init(struct hisi_qm *qm) @@ -1106,26 +1166,33 @@ static int hpre_pre_store_cap_reg(struct hisi_qm *qm) { struct hisi_qm_cap_record *hpre_cap; struct device *dev = &qm->pdev->dev; + u32 hpre_core_info; + u8 clusters_num; size_t i, size; - size = ARRAY_SIZE(hpre_pre_store_caps); + size = ARRAY_SIZE(hpre_cap_query_info); hpre_cap = devm_kzalloc(dev, sizeof(*hpre_cap) * size, GFP_KERNEL); if (!hpre_cap) return -ENOMEM; for (i = 0; i < size; i++) { - hpre_cap[i].type = hpre_pre_store_caps[i]; - hpre_cap[i].cap_val = hisi_qm_get_hw_info(qm, hpre_basic_info, - hpre_pre_store_caps[i], qm->cap_ver); + hpre_cap[i].type = hpre_cap_query_info[i].type; + hpre_cap[i].name = hpre_cap_query_info[i].name; + hpre_cap[i].cap_val = hisi_qm_get_cap_value(qm, hpre_cap_query_info, + i, qm->cap_ver); } - if (hpre_cap[HPRE_CLUSTER_NUM_CAP_IDX].cap_val > HPRE_CLUSTERS_NUM_MAX) { + hpre_core_info = hpre_cap[HPRE_CORE_INFO].cap_val; + clusters_num = (hpre_core_info >> hpre_basic_info[HPRE_CLUSTER_NUM_CAP].shift) & + hpre_basic_info[HPRE_CLUSTER_NUM_CAP].mask; + if (clusters_num > HPRE_CLUSTERS_NUM_MAX) { dev_err(dev, "Device cluster num %u is out of range for driver supports %d!\n", - hpre_cap[HPRE_CLUSTER_NUM_CAP_IDX].cap_val, HPRE_CLUSTERS_NUM_MAX); + clusters_num, HPRE_CLUSTERS_NUM_MAX); return -EINVAL; } qm->cap_tables.dev_cap_table = hpre_cap; + qm->cap_tables.dev_cap_size = size; return 0; } @@ -1172,7 +1239,7 @@ static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - alg_msk = qm->cap_tables.dev_cap_table[HPRE_DEV_ALG_BITMAP_CAP_IDX].cap_val; + alg_msk = qm->cap_tables.dev_cap_table[HPRE_ALG_BITMAP].cap_val; ret = hisi_qm_set_algs(qm, alg_msk, hpre_dev_algs, ARRAY_SIZE(hpre_dev_algs)); if (ret) { pci_err(pdev, "Failed to set hpre algs!\n"); @@ -1188,10 +1255,13 @@ static int hpre_show_last_regs_init(struct hisi_qm *qm) int com_dfx_regs_num = ARRAY_SIZE(hpre_com_dfx_regs); struct qm_debug *debug = &qm->debug; void __iomem *io_base; + u32 hpre_core_info; u8 clusters_num; int i, j, idx; - clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + hpre_core_info = qm->cap_tables.dev_cap_table[HPRE_CORE_INFO].cap_val; + clusters_num = (hpre_core_info >> hpre_basic_info[HPRE_CLUSTER_NUM_CAP].shift) & + hpre_basic_info[HPRE_CLUSTER_NUM_CAP].mask; debug->last_words = kcalloc(cluster_dfx_regs_num * clusters_num + com_dfx_regs_num, sizeof(unsigned int), GFP_KERNEL); if (!debug->last_words) @@ -1231,6 +1301,7 @@ static void hpre_show_last_dfx_regs(struct hisi_qm *qm) struct qm_debug *debug = &qm->debug; struct pci_dev *pdev = qm->pdev; void __iomem *io_base; + u32 hpre_core_info; u8 clusters_num; int i, j, idx; u32 val; @@ -1246,7 +1317,9 @@ static void hpre_show_last_dfx_regs(struct hisi_qm *qm) hpre_com_dfx_regs[i].name, debug->last_words[i], val); } - clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; + hpre_core_info = qm->cap_tables.dev_cap_table[HPRE_CORE_INFO].cap_val; + clusters_num = (hpre_core_info >> hpre_basic_info[HPRE_CLUSTER_NUM_CAP].shift) & + hpre_basic_info[HPRE_CLUSTER_NUM_CAP].mask; for (i = 0; i < clusters_num; i++) { io_base = qm->io_base + hpre_cluster_offsets[i]; for (j = 0; j < cluster_dfx_regs_num; j++) { @@ -1280,11 +1353,15 @@ static u32 hpre_get_hw_err_status(struct hisi_qm *qm) static void hpre_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) { - u32 nfe; - writel(err_sts, qm->io_base + HPRE_HAC_SOURCE_INT); - nfe = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); - writel(nfe, qm->io_base + HPRE_RAS_NFE_ENB); +} + +static void hpre_disable_error_report(struct hisi_qm *qm, u32 err_type) +{ + u32 nfe_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_NFE_MASK_CAP, qm->cap_ver); + writel(nfe_mask & (~err_type), qm->io_base + HPRE_RAS_NFE_ENB); } static void hpre_open_axi_master_ooo(struct hisi_qm *qm) @@ -1298,6 +1375,27 @@ static void hpre_open_axi_master_ooo(struct hisi_qm *qm) qm->io_base + HPRE_AM_OOO_SHUTDOWN_ENB); } +static enum acc_err_result hpre_get_err_result(struct hisi_qm *qm) +{ + u32 err_status; + + err_status = hpre_get_hw_err_status(qm); + if (err_status) { + if (err_status & qm->err_info.ecc_2bits_mask) + qm->err_status.is_dev_ecc_mbit = true; + hpre_log_hw_error(qm, err_status); + + if (err_status & qm->err_info.dev_reset_mask) { + /* Disable the same error reporting until device is recovered. */ + hpre_disable_error_report(qm, err_status); + return ACC_ERR_NEED_RESET; + } + hpre_clear_hw_err_status(qm, err_status); + } + + return ACC_ERR_RECOVERED; +} + static void hpre_err_info_init(struct hisi_qm *qm) { struct hisi_qm_err_info *err_info = &qm->err_info; @@ -1324,12 +1422,12 @@ static const struct hisi_qm_err_ini hpre_err_ini = { .hw_err_disable = hpre_hw_error_disable, .get_dev_hw_err_status = hpre_get_hw_err_status, .clear_dev_hw_err_status = hpre_clear_hw_err_status, - .log_dev_hw_err = hpre_log_hw_error, .open_axi_master_ooo = hpre_open_axi_master_ooo, .open_sva_prefetch = hpre_open_sva_prefetch, .close_sva_prefetch = hpre_close_sva_prefetch, .show_last_dfx_regs = hpre_show_last_dfx_regs, .err_info_init = hpre_err_info_init, + .get_err_result = hpre_get_err_result, }; static int hpre_pf_probe_init(struct hpre *hpre) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 07983af9e3e229..19c1b5d3c954cb 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -271,12 +271,6 @@ enum vft_type { SHAPER_VFT, }; -enum acc_err_result { - ACC_ERR_NONE, - ACC_ERR_NEED_RESET, - ACC_ERR_RECOVERED, -}; - enum qm_alg_type { ALG_TYPE_0, ALG_TYPE_1, @@ -307,11 +301,29 @@ enum qm_basic_type { QM_VF_IRQ_NUM_CAP, }; -enum qm_pre_store_cap_idx { - QM_EQ_IRQ_TYPE_CAP_IDX = 0x0, - QM_AEQ_IRQ_TYPE_CAP_IDX, - QM_ABN_IRQ_TYPE_CAP_IDX, - QM_PF2VF_IRQ_TYPE_CAP_IDX, +enum qm_cap_table_type { + QM_CAP_VF = 0x0, + QM_AEQE_NUM, + QM_SCQE_NUM, + QM_EQ_IRQ, + QM_AEQ_IRQ, + QM_ABNORMAL_IRQ, + QM_MB_IRQ, + MAX_IRQ_NUM, + EXT_BAR_INDEX, +}; + +static const struct hisi_qm_cap_query_info qm_cap_query_info[] = { + {QM_CAP_VF, "QM_CAP_VF ", 0x3100, 0x0, 0x0, 0x6F01}, + {QM_AEQE_NUM, "QM_AEQE_NUM ", 0x3104, 0x800, 0x4000800, 0x4000800}, + {QM_SCQE_NUM, "QM_SCQE_NUM ", + 0x3108, 0x4000400, 0x4000400, 0x4000400}, + {QM_EQ_IRQ, "QM_EQ_IRQ ", 0x310c, 0x10000, 0x10000, 0x10000}, + {QM_AEQ_IRQ, "QM_AEQ_IRQ ", 0x3110, 0x0, 0x10001, 0x10001}, + {QM_ABNORMAL_IRQ, "QM_ABNORMAL_IRQ ", 0x3114, 0x0, 0x10003, 0x10003}, + {QM_MB_IRQ, "QM_MB_IRQ ", 0x3118, 0x0, 0x0, 0x10002}, + {MAX_IRQ_NUM, "MAX_IRQ_NUM ", 0x311c, 0x10001, 0x40002, 0x40003}, + {EXT_BAR_INDEX, "EXT_BAR_INDEX ", 0x3120, 0x0, 0x0, 0x14}, }; static const struct hisi_qm_cap_info qm_cap_info_comm[] = { @@ -344,13 +356,6 @@ static const struct hisi_qm_cap_info qm_basic_info[] = { {QM_VF_IRQ_NUM_CAP, 0x311c, 0, GENMASK(15, 0), 0x1, 0x2, 0x3}, }; -static const u32 qm_pre_store_caps[] = { - QM_EQ_IRQ_TYPE_CAP, - QM_AEQ_IRQ_TYPE_CAP, - QM_ABN_IRQ_TYPE_CAP, - QM_PF2VF_IRQ_TYPE_CAP, -}; - struct qm_mailbox { __le16 w0; __le16 queue_num; @@ -451,6 +456,37 @@ static struct qm_typical_qos_table shaper_cbs_s[] = { static void qm_irqs_unregister(struct hisi_qm *qm); static int qm_reset_device(struct hisi_qm *qm); +int hisi_qm_q_num_set(const char *val, const struct kernel_param *kp, + unsigned int device) +{ + struct pci_dev *pdev; + u32 n, q_num; + int ret; + + if (!val) + return -EINVAL; + + pdev = pci_get_device(PCI_VENDOR_ID_HUAWEI, device, NULL); + if (!pdev) { + q_num = min_t(u32, QM_QNUM_V1, QM_QNUM_V2); + pr_info("No device found currently, suppose queue number is %u\n", + q_num); + } else { + if (pdev->revision == QM_HW_V1) + q_num = QM_QNUM_V1; + else + q_num = QM_QNUM_V2; + + pci_dev_put(pdev); + } + + ret = kstrtou32(val, 10, &n); + if (ret || n < QM_MIN_QNUM || n > q_num) + return -EINVAL; + + return param_set_int(val, kp); +} +EXPORT_SYMBOL_GPL(hisi_qm_q_num_set); static u32 qm_get_hw_error_status(struct hisi_qm *qm) { @@ -763,6 +799,27 @@ u32 hisi_qm_get_hw_info(struct hisi_qm *qm, } EXPORT_SYMBOL_GPL(hisi_qm_get_hw_info); +u32 hisi_qm_get_cap_value(struct hisi_qm *qm, + const struct hisi_qm_cap_query_info *info_table, + u32 index, bool is_read) +{ + u32 val; + + switch (qm->ver) { + case QM_HW_V1: + return info_table[index].v1_val; + case QM_HW_V2: + return info_table[index].v2_val; + default: + if (!is_read) + return info_table[index].v3_val; + + val = readl(qm->io_base + info_table[index].offset); + return val; + } +} +EXPORT_SYMBOL_GPL(hisi_qm_get_cap_value); + static void qm_get_xqc_depth(struct hisi_qm *qm, u16 *low_bits, u16 *high_bits, enum qm_basic_type type) { @@ -1425,22 +1482,25 @@ static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) static enum acc_err_result qm_hw_error_handle_v2(struct hisi_qm *qm) { - u32 error_status, tmp; - - /* read err sts */ - tmp = readl(qm->io_base + QM_ABNORMAL_INT_STATUS); - error_status = qm->error_mask & tmp; + u32 error_status; - if (error_status) { + error_status = qm_get_hw_error_status(qm); + if (error_status & qm->error_mask) { if (error_status & QM_ECC_MBIT) qm->err_status.is_qm_ecc_mbit = true; qm_log_hw_error(qm, error_status); - if (error_status & qm->err_info.qm_reset_mask) + if (error_status & qm->err_info.qm_reset_mask) { + /* Disable the same error reporting until device is recovered. */ + writel(qm->err_info.nfe & (~error_status), + qm->io_base + QM_RAS_NFE_ENABLE); return ACC_ERR_NEED_RESET; + } + /* Clear error source if not need reset. */ writel(error_status, qm->io_base + QM_ABNORMAL_INT_SOURCE); writel(qm->err_info.nfe, qm->io_base + QM_RAS_NFE_ENABLE); + writel(qm->err_info.ce, qm->io_base + QM_RAS_CE_ENABLE); } return ACC_ERR_RECOVERED; @@ -3861,30 +3921,12 @@ EXPORT_SYMBOL_GPL(hisi_qm_sriov_configure); static enum acc_err_result qm_dev_err_handle(struct hisi_qm *qm) { - u32 err_sts; - - if (!qm->err_ini->get_dev_hw_err_status) { - dev_err(&qm->pdev->dev, "Device doesn't support get hw error status!\n"); + if (!qm->err_ini->get_err_result) { + dev_err(&qm->pdev->dev, "Device doesn't support reset!\n"); return ACC_ERR_NONE; } - /* get device hardware error status */ - err_sts = qm->err_ini->get_dev_hw_err_status(qm); - if (err_sts) { - if (err_sts & qm->err_info.ecc_2bits_mask) - qm->err_status.is_dev_ecc_mbit = true; - - if (qm->err_ini->log_dev_hw_err) - qm->err_ini->log_dev_hw_err(qm, err_sts); - - if (err_sts & qm->err_info.dev_reset_mask) - return ACC_ERR_NEED_RESET; - - if (qm->err_ini->clear_dev_hw_err_status) - qm->err_ini->clear_dev_hw_err_status(qm, err_sts); - } - - return ACC_ERR_RECOVERED; + return qm->err_ini->get_err_result(qm); } static enum acc_err_result qm_process_dev_error(struct hisi_qm *qm) @@ -4866,7 +4908,7 @@ static void qm_unregister_abnormal_irq(struct hisi_qm *qm) if (qm->fun_type == QM_HW_VF) return; - val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; + val = qm->cap_tables.qm_cap_table[QM_ABNORMAL_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) return; @@ -4883,7 +4925,7 @@ static int qm_register_abnormal_irq(struct hisi_qm *qm) if (qm->fun_type == QM_HW_VF) return 0; - val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; + val = qm->cap_tables.qm_cap_table[QM_ABNORMAL_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) return 0; @@ -4900,7 +4942,7 @@ static void qm_unregister_mb_cmd_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; + val = qm->cap_tables.qm_cap_table[QM_MB_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4914,7 +4956,7 @@ static int qm_register_mb_cmd_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; + val = qm->cap_tables.qm_cap_table[QM_MB_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -4931,7 +4973,7 @@ static void qm_unregister_aeq_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; + val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4945,7 +4987,7 @@ static int qm_register_aeq_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; + val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -4963,7 +5005,7 @@ static void qm_unregister_eq_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; + val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4977,7 +5019,7 @@ static int qm_register_eq_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; + val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -5065,24 +5107,26 @@ static int qm_get_qp_num(struct hisi_qm *qm) return 0; } -static int qm_pre_store_irq_type_caps(struct hisi_qm *qm) +static int qm_pre_store_caps(struct hisi_qm *qm) { struct hisi_qm_cap_record *qm_cap; struct pci_dev *pdev = qm->pdev; size_t i, size; - size = ARRAY_SIZE(qm_pre_store_caps); + size = ARRAY_SIZE(qm_cap_query_info); qm_cap = devm_kzalloc(&pdev->dev, sizeof(*qm_cap) * size, GFP_KERNEL); if (!qm_cap) return -ENOMEM; for (i = 0; i < size; i++) { - qm_cap[i].type = qm_pre_store_caps[i]; - qm_cap[i].cap_val = hisi_qm_get_hw_info(qm, qm_basic_info, - qm_pre_store_caps[i], qm->cap_ver); + qm_cap[i].type = qm_cap_query_info[i].type; + qm_cap[i].name = qm_cap_query_info[i].name; + qm_cap[i].cap_val = hisi_qm_get_cap_value(qm, qm_cap_query_info, + i, qm->cap_ver); } qm->cap_tables.qm_cap_table = qm_cap; + qm->cap_tables.qm_cap_size = size; return 0; } @@ -5119,8 +5163,8 @@ static int qm_get_hw_caps(struct hisi_qm *qm) set_bit(cap_info[i].type, &qm->caps); } - /* Fetch and save the value of irq type related capability registers */ - return qm_pre_store_irq_type_caps(qm); + /* Fetch and save the value of qm capability registers */ + return qm_pre_store_caps(qm); } static int qm_get_pci_res(struct hisi_qm *qm) diff --git a/drivers/crypto/hisilicon/sec/sec_drv.c b/drivers/crypto/hisilicon/sec/sec_drv.c index 9bafcc5aa404f5..ef0cb733c92c8e 100644 --- a/drivers/crypto/hisilicon/sec/sec_drv.c +++ b/drivers/crypto/hisilicon/sec/sec_drv.c @@ -1304,7 +1304,7 @@ MODULE_DEVICE_TABLE(acpi, sec_acpi_match); static struct platform_driver sec_driver = { .probe = sec_probe, - .remove_new = sec_remove, + .remove = sec_remove, .driver = { .name = "hisi_sec_platform_driver", .of_match_table = sec_match, diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h index 410c83712e2851..356188bee6fbcb 100644 --- a/drivers/crypto/hisilicon/sec2/sec.h +++ b/drivers/crypto/hisilicon/sec2/sec.h @@ -220,11 +220,27 @@ enum sec_cap_type { SEC_CORE4_ALG_BITMAP_HIGH, }; -enum sec_cap_reg_record_idx { - SEC_DRV_ALG_BITMAP_LOW_IDX = 0x0, - SEC_DRV_ALG_BITMAP_HIGH_IDX, - SEC_DEV_ALG_BITMAP_LOW_IDX, - SEC_DEV_ALG_BITMAP_HIGH_IDX, +enum sec_cap_table_type { + QM_RAS_NFE_TYPE = 0x0, + QM_RAS_NFE_RESET, + QM_RAS_CE_TYPE, + SEC_RAS_NFE_TYPE, + SEC_RAS_NFE_RESET, + SEC_RAS_CE_TYPE, + SEC_CORE_INFO, + SEC_CORE_EN, + SEC_DRV_ALG_BITMAP_LOW_TB, + SEC_DRV_ALG_BITMAP_HIGH_TB, + SEC_ALG_BITMAP_LOW, + SEC_ALG_BITMAP_HIGH, + SEC_CORE1_BITMAP_LOW, + SEC_CORE1_BITMAP_HIGH, + SEC_CORE2_BITMAP_LOW, + SEC_CORE2_BITMAP_HIGH, + SEC_CORE3_BITMAP_LOW, + SEC_CORE3_BITMAP_HIGH, + SEC_CORE4_BITMAP_LOW, + SEC_CORE4_BITMAP_HIGH, }; void sec_destroy_qps(struct hisi_qp **qps, int qp_num); diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index 0558f98e221f63..ae9ebbb4103d41 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -2520,8 +2520,8 @@ int sec_register_to_crypto(struct hisi_qm *qm) u64 alg_mask; int ret = 0; - alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_IDX, - SEC_DRV_ALG_BITMAP_LOW_IDX); + alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_TB, + SEC_DRV_ALG_BITMAP_LOW_TB); mutex_lock(&sec_algs_lock); if (sec_available_devs) { @@ -2553,8 +2553,8 @@ void sec_unregister_from_crypto(struct hisi_qm *qm) { u64 alg_mask; - alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_IDX, - SEC_DRV_ALG_BITMAP_LOW_IDX); + alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_TB, + SEC_DRV_ALG_BITMAP_LOW_TB); mutex_lock(&sec_algs_lock); if (--sec_available_devs) diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index c35533d8930b21..8ec5333bb5aa32 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -14,9 +14,9 @@ #include #include #include - #include "sec.h" +#define CAP_FILE_PERMISSION 0444 #define SEC_VF_NUM 63 #define SEC_QUEUE_NUM_V1 4096 #define PCI_DEVICE_ID_HUAWEI_SEC_PF 0xa255 @@ -167,11 +167,34 @@ static const struct hisi_qm_cap_info sec_basic_info[] = { {SEC_CORE4_ALG_BITMAP_HIGH, 0x3170, 0, GENMASK(31, 0), 0x3FFF, 0x3FFF, 0x3FFF}, }; -static const u32 sec_pre_store_caps[] = { - SEC_DRV_ALG_BITMAP_LOW, - SEC_DRV_ALG_BITMAP_HIGH, - SEC_DEV_ALG_BITMAP_LOW, - SEC_DEV_ALG_BITMAP_HIGH, +static const struct hisi_qm_cap_query_info sec_cap_query_info[] = { + {QM_RAS_NFE_TYPE, "QM_RAS_NFE_TYPE ", 0x3124, 0x0, 0x1C77, 0x7C77}, + {QM_RAS_NFE_RESET, "QM_RAS_NFE_RESET ", 0x3128, 0x0, 0xC77, 0x6C77}, + {QM_RAS_CE_TYPE, "QM_RAS_CE_TYPE ", 0x312C, 0x0, 0x8, 0x8}, + {SEC_RAS_NFE_TYPE, "SEC_RAS_NFE_TYPE ", 0x3130, 0x0, 0x177, 0x60177}, + {SEC_RAS_NFE_RESET, "SEC_RAS_NFE_RESET ", 0x3134, 0x0, 0x177, 0x177}, + {SEC_RAS_CE_TYPE, "SEC_RAS_CE_TYPE ", 0x3138, 0x0, 0x88, 0xC088}, + {SEC_CORE_INFO, "SEC_CORE_INFO ", 0x313c, 0x110404, 0x110404, 0x110404}, + {SEC_CORE_EN, "SEC_CORE_EN ", 0x3140, 0x17F, 0x17F, 0xF}, + {SEC_DRV_ALG_BITMAP_LOW_TB, "SEC_DRV_ALG_BITMAP_LOW ", + 0x3144, 0x18050CB, 0x18050CB, 0x18670CF}, + {SEC_DRV_ALG_BITMAP_HIGH_TB, "SEC_DRV_ALG_BITMAP_HIGH ", + 0x3148, 0x395C, 0x395C, 0x395C}, + {SEC_ALG_BITMAP_LOW, "SEC_ALG_BITMAP_LOW ", + 0x314c, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {SEC_ALG_BITMAP_HIGH, "SEC_ALG_BITMAP_HIGH ", 0x3150, 0x3FFF, 0x3FFF, 0x3FFF}, + {SEC_CORE1_BITMAP_LOW, "SEC_CORE1_BITMAP_LOW ", + 0x3154, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {SEC_CORE1_BITMAP_HIGH, "SEC_CORE1_BITMAP_HIGH ", 0x3158, 0x3FFF, 0x3FFF, 0x3FFF}, + {SEC_CORE2_BITMAP_LOW, "SEC_CORE2_BITMAP_LOW ", + 0x315c, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {SEC_CORE2_BITMAP_HIGH, "SEC_CORE2_BITMAP_HIGH ", 0x3160, 0x3FFF, 0x3FFF, 0x3FFF}, + {SEC_CORE3_BITMAP_LOW, "SEC_CORE3_BITMAP_LOW ", + 0x3164, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {SEC_CORE3_BITMAP_HIGH, "SEC_CORE3_BITMAP_HIGH ", 0x3168, 0x3FFF, 0x3FFF, 0x3FFF}, + {SEC_CORE4_BITMAP_LOW, "SEC_CORE4_BITMAP_LOW ", + 0x316c, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, + {SEC_CORE4_BITMAP_HIGH, "SEC_CORE4_BITMAP_HIGH ", 0x3170, 0x3FFF, 0x3FFF, 0x3FFF}, }; static const struct qm_dev_alg sec_dev_algs[] = { { @@ -322,7 +345,7 @@ static int sec_pf_q_num_set(const char *val, const struct kernel_param *kp) { pf_q_num_flag = true; - return q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_SEC_PF); + return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_SEC_PF); } static const struct kernel_param_ops sec_pf_q_num_ops = { @@ -838,6 +861,26 @@ static int sec_regs_show(struct seq_file *s, void *unused) DEFINE_SHOW_ATTRIBUTE(sec_regs); +static int sec_cap_regs_show(struct seq_file *s, void *unused) +{ + struct hisi_qm *qm = s->private; + u32 i, size; + + size = qm->cap_tables.qm_cap_size; + for (i = 0; i < size; i++) + seq_printf(s, "%s= 0x%08x\n", qm->cap_tables.qm_cap_table[i].name, + qm->cap_tables.qm_cap_table[i].cap_val); + + size = qm->cap_tables.dev_cap_size; + for (i = 0; i < size; i++) + seq_printf(s, "%s= 0x%08x\n", qm->cap_tables.dev_cap_table[i].name, + qm->cap_tables.dev_cap_table[i].cap_val); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(sec_cap_regs); + static int sec_core_debug_init(struct hisi_qm *qm) { struct dfx_diff_registers *sec_regs = qm->debug.acc_diff_regs; @@ -872,6 +915,9 @@ static int sec_core_debug_init(struct hisi_qm *qm) tmp_d, data, &sec_atomic64_ops); } + debugfs_create_file("cap_regs", CAP_FILE_PERMISSION, + qm->debug.debug_root, qm, &sec_cap_regs_fops); + return 0; } @@ -1010,11 +1056,15 @@ static u32 sec_get_hw_err_status(struct hisi_qm *qm) static void sec_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) { - u32 nfe; - writel(err_sts, qm->io_base + SEC_CORE_INT_SOURCE); - nfe = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_NFE_MASK_CAP, qm->cap_ver); - writel(nfe, qm->io_base + SEC_RAS_NFE_REG); +} + +static void sec_disable_error_report(struct hisi_qm *qm, u32 err_type) +{ + u32 nfe_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, sec_basic_info, SEC_NFE_MASK_CAP, qm->cap_ver); + writel(nfe_mask & (~err_type), qm->io_base + SEC_RAS_NFE_REG); } static void sec_open_axi_master_ooo(struct hisi_qm *qm) @@ -1026,6 +1076,27 @@ static void sec_open_axi_master_ooo(struct hisi_qm *qm) writel(val | SEC_AXI_SHUTDOWN_ENABLE, qm->io_base + SEC_CONTROL_REG); } +static enum acc_err_result sec_get_err_result(struct hisi_qm *qm) +{ + u32 err_status; + + err_status = sec_get_hw_err_status(qm); + if (err_status) { + if (err_status & qm->err_info.ecc_2bits_mask) + qm->err_status.is_dev_ecc_mbit = true; + sec_log_hw_error(qm, err_status); + + if (err_status & qm->err_info.dev_reset_mask) { + /* Disable the same error reporting until device is recovered. */ + sec_disable_error_report(qm, err_status); + return ACC_ERR_NEED_RESET; + } + sec_clear_hw_err_status(qm, err_status); + } + + return ACC_ERR_RECOVERED; +} + static void sec_err_info_init(struct hisi_qm *qm) { struct hisi_qm_err_info *err_info = &qm->err_info; @@ -1052,12 +1123,12 @@ static const struct hisi_qm_err_ini sec_err_ini = { .hw_err_disable = sec_hw_error_disable, .get_dev_hw_err_status = sec_get_hw_err_status, .clear_dev_hw_err_status = sec_clear_hw_err_status, - .log_dev_hw_err = sec_log_hw_error, .open_axi_master_ooo = sec_open_axi_master_ooo, .open_sva_prefetch = sec_open_sva_prefetch, .close_sva_prefetch = sec_close_sva_prefetch, .show_last_dfx_regs = sec_show_last_dfx_regs, .err_info_init = sec_err_info_init, + .get_err_result = sec_get_err_result, }; static int sec_pf_probe_init(struct sec_dev *sec) @@ -1085,18 +1156,20 @@ static int sec_pre_store_cap_reg(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; size_t i, size; - size = ARRAY_SIZE(sec_pre_store_caps); + size = ARRAY_SIZE(sec_cap_query_info); sec_cap = devm_kzalloc(&pdev->dev, sizeof(*sec_cap) * size, GFP_KERNEL); if (!sec_cap) return -ENOMEM; for (i = 0; i < size; i++) { - sec_cap[i].type = sec_pre_store_caps[i]; - sec_cap[i].cap_val = hisi_qm_get_hw_info(qm, sec_basic_info, - sec_pre_store_caps[i], qm->cap_ver); + sec_cap[i].type = sec_cap_query_info[i].type; + sec_cap[i].name = sec_cap_query_info[i].name; + sec_cap[i].cap_val = hisi_qm_get_cap_value(qm, sec_cap_query_info, + i, qm->cap_ver); } qm->cap_tables.dev_cap_table = sec_cap; + qm->cap_tables.dev_cap_size = size; return 0; } @@ -1146,8 +1219,7 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) hisi_qm_uninit(qm); return ret; } - - alg_msk = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH_IDX, SEC_DEV_ALG_BITMAP_LOW_IDX); + alg_msk = sec_get_alg_bitmap(qm, SEC_ALG_BITMAP_HIGH, SEC_ALG_BITMAP_LOW); ret = hisi_qm_set_algs(qm, alg_msk, sec_dev_algs, ARRAY_SIZE(sec_dev_algs)); if (ret) { pci_err(qm->pdev, "Failed to set sec algs!\n"); diff --git a/drivers/crypto/hisilicon/trng/trng.c b/drivers/crypto/hisilicon/trng/trng.c index 66c551ecdee80f..ac74df4a947126 100644 --- a/drivers/crypto/hisilicon/trng/trng.c +++ b/drivers/crypto/hisilicon/trng/trng.c @@ -324,7 +324,7 @@ MODULE_DEVICE_TABLE(acpi, hisi_trng_acpi_match); static struct platform_driver hisi_trng_driver = { .probe = hisi_trng_probe, - .remove_new = hisi_trng_remove, + .remove = hisi_trng_remove, .driver = { .name = "hisi-trng-v2", .acpi_match_table = ACPI_PTR(hisi_trng_acpi_match), diff --git a/drivers/crypto/hisilicon/zip/zip.h b/drivers/crypto/hisilicon/zip/zip.h index f2e6da3240aeb3..2fecf346c3c985 100644 --- a/drivers/crypto/hisilicon/zip/zip.h +++ b/drivers/crypto/hisilicon/zip/zip.h @@ -81,6 +81,24 @@ struct hisi_zip_sqe { u32 rsvd1[4]; }; +enum zip_cap_table_type { + QM_RAS_NFE_TYPE, + QM_RAS_NFE_RESET, + QM_RAS_CE_TYPE, + ZIP_RAS_NFE_TYPE, + ZIP_RAS_NFE_RESET, + ZIP_RAS_CE_TYPE, + ZIP_CORE_INFO, + ZIP_CORE_EN, + ZIP_DRV_ALG_BITMAP_TB, + ZIP_ALG_BITMAP, + ZIP_CORE1_BITMAP, + ZIP_CORE2_BITMAP, + ZIP_CORE3_BITMAP, + ZIP_CORE4_BITMAP, + ZIP_CORE5_BITMAP, +}; + int zip_create_qps(struct hisi_qp **qps, int qp_num, int node); int hisi_zip_register_to_crypto(struct hisi_qm *qm); void hisi_zip_unregister_from_crypto(struct hisi_qm *qm); diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index d07e47b48be06a..9239b251c2d726 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -14,6 +14,7 @@ #include #include "zip.h" +#define CAP_FILE_PERMISSION 0444 #define PCI_DEVICE_ID_HUAWEI_ZIP_PF 0xa250 #define HZIP_QUEUE_NUM_V1 4096 @@ -250,24 +251,22 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = { {ZIP_CAP_MAX, 0x317c, 0, GENMASK(0, 0), 0x0, 0x0, 0x0} }; -enum zip_pre_store_cap_idx { - ZIP_CORE_NUM_CAP_IDX = 0x0, - ZIP_CLUSTER_COMP_NUM_CAP_IDX, - ZIP_CLUSTER_DECOMP_NUM_CAP_IDX, - ZIP_DECOMP_ENABLE_BITMAP_IDX, - ZIP_COMP_ENABLE_BITMAP_IDX, - ZIP_DRV_ALG_BITMAP_IDX, - ZIP_DEV_ALG_BITMAP_IDX, -}; - -static const u32 zip_pre_store_caps[] = { - ZIP_CORE_NUM_CAP, - ZIP_CLUSTER_COMP_NUM_CAP, - ZIP_CLUSTER_DECOMP_NUM_CAP, - ZIP_DECOMP_ENABLE_BITMAP, - ZIP_COMP_ENABLE_BITMAP, - ZIP_DRV_ALG_BITMAP, - ZIP_DEV_ALG_BITMAP, +static const struct hisi_qm_cap_query_info zip_cap_query_info[] = { + {QM_RAS_NFE_TYPE, "QM_RAS_NFE_TYPE ", 0x3124, 0x0, 0x1C57, 0x7C77}, + {QM_RAS_NFE_RESET, "QM_RAS_NFE_RESET ", 0x3128, 0x0, 0xC57, 0x6C77}, + {QM_RAS_CE_TYPE, "QM_RAS_CE_TYPE ", 0x312C, 0x0, 0x8, 0x8}, + {ZIP_RAS_NFE_TYPE, "ZIP_RAS_NFE_TYPE ", 0x3130, 0x0, 0x7FE, 0x1FFE}, + {ZIP_RAS_NFE_RESET, "ZIP_RAS_NFE_RESET ", 0x3134, 0x0, 0x7FE, 0x7FE}, + {ZIP_RAS_CE_TYPE, "ZIP_RAS_CE_TYPE ", 0x3138, 0x0, 0x1, 0x1}, + {ZIP_CORE_INFO, "ZIP_CORE_INFO ", 0x313C, 0x12080206, 0x12080206, 0x12050203}, + {ZIP_CORE_EN, "ZIP_CORE_EN ", 0x3140, 0xFC0003, 0xFC0003, 0x1C0003}, + {ZIP_DRV_ALG_BITMAP_TB, "ZIP_DRV_ALG_BITMAP ", 0x3144, 0x0, 0x0, 0x30}, + {ZIP_ALG_BITMAP, "ZIP_ALG_BITMAP ", 0x3148, 0xF, 0xF, 0x3F}, + {ZIP_CORE1_BITMAP, "ZIP_CORE1_BITMAP ", 0x314C, 0x5, 0x5, 0xD5}, + {ZIP_CORE2_BITMAP, "ZIP_CORE2_BITMAP ", 0x3150, 0x5, 0x5, 0xD5}, + {ZIP_CORE3_BITMAP, "ZIP_CORE3_BITMAP ", 0x3154, 0xA, 0xA, 0x2A}, + {ZIP_CORE4_BITMAP, "ZIP_CORE4_BITMAP ", 0x3158, 0xA, 0xA, 0x2A}, + {ZIP_CORE5_BITMAP, "ZIP_CORE5_BITMAP ", 0x315C, 0xA, 0xA, 0x2A}, }; static const struct debugfs_reg32 hzip_dfx_regs[] = { @@ -402,7 +401,7 @@ static int pf_q_num_set(const char *val, const struct kernel_param *kp) { pf_q_num_flag = true; - return q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_ZIP_PF); + return hisi_qm_q_num_set(val, kp, PCI_DEVICE_ID_HUAWEI_ZIP_PF); } static const struct kernel_param_ops pf_q_num_ops = { @@ -442,7 +441,7 @@ bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) { u32 cap_val; - cap_val = qm->cap_tables.dev_cap_table[ZIP_DRV_ALG_BITMAP_IDX].cap_val; + cap_val = qm->cap_tables.dev_cap_table[ZIP_DRV_ALG_BITMAP_TB].cap_val; if ((alg & cap_val) == alg) return true; @@ -530,6 +529,7 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) { void __iomem *base = qm->io_base; u32 dcomp_bm, comp_bm; + u32 zip_core_en; /* qm user domain */ writel(AXUSER_BASE, base + QM_ARUSER_M_CFG_1); @@ -567,8 +567,12 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) } /* let's open all compression/decompression cores */ - dcomp_bm = qm->cap_tables.dev_cap_table[ZIP_DECOMP_ENABLE_BITMAP_IDX].cap_val; - comp_bm = qm->cap_tables.dev_cap_table[ZIP_COMP_ENABLE_BITMAP_IDX].cap_val; + + zip_core_en = qm->cap_tables.dev_cap_table[ZIP_CORE_EN].cap_val; + dcomp_bm = (zip_core_en >> zip_basic_cap_info[ZIP_DECOMP_ENABLE_BITMAP].shift) & + zip_basic_cap_info[ZIP_DECOMP_ENABLE_BITMAP].mask; + comp_bm = (zip_core_en >> zip_basic_cap_info[ZIP_COMP_ENABLE_BITMAP].shift) & + zip_basic_cap_info[ZIP_COMP_ENABLE_BITMAP].mask; writel(HZIP_DECOMP_CHECK_ENABLE | dcomp_bm | comp_bm, base + HZIP_CLOCK_GATE_CTRL); /* enable sqc,cqc writeback */ @@ -788,7 +792,12 @@ DEFINE_SHOW_ATTRIBUTE(hisi_zip_regs); static void __iomem *get_zip_core_addr(struct hisi_qm *qm, int core_num) { - u32 zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; + u8 zip_comp_core_num; + u32 zip_core_info; + + zip_core_info = qm->cap_tables.dev_cap_table[ZIP_CORE_INFO].cap_val; + zip_comp_core_num = (zip_core_info >> zip_basic_cap_info[ZIP_CLUSTER_COMP_NUM_CAP].shift) & + zip_basic_cap_info[ZIP_CLUSTER_COMP_NUM_CAP].mask; if (core_num < zip_comp_core_num) return qm->io_base + HZIP_CORE_DFX_BASE + @@ -803,12 +812,16 @@ static int hisi_zip_core_debug_init(struct hisi_qm *qm) u32 zip_core_num, zip_comp_core_num; struct device *dev = &qm->pdev->dev; struct debugfs_regset32 *regset; + u32 zip_core_info; struct dentry *tmp_d; char buf[HZIP_BUF_SIZE]; int i; - zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; - zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; + zip_core_info = qm->cap_tables.dev_cap_table[ZIP_CORE_INFO].cap_val; + zip_core_num = (zip_core_info >> zip_basic_cap_info[ZIP_CORE_NUM_CAP].shift) & + zip_basic_cap_info[ZIP_CORE_NUM_CAP].mask; + zip_comp_core_num = (zip_core_info >> zip_basic_cap_info[ZIP_CLUSTER_COMP_NUM_CAP].shift) & + zip_basic_cap_info[ZIP_CLUSTER_COMP_NUM_CAP].mask; for (i = 0; i < zip_core_num; i++) { if (i < zip_comp_core_num) @@ -834,6 +847,26 @@ static int hisi_zip_core_debug_init(struct hisi_qm *qm) return 0; } +static int zip_cap_regs_show(struct seq_file *s, void *unused) +{ + struct hisi_qm *qm = s->private; + u32 i, size; + + size = qm->cap_tables.qm_cap_size; + for (i = 0; i < size; i++) + seq_printf(s, "%s= 0x%08x\n", qm->cap_tables.qm_cap_table[i].name, + qm->cap_tables.qm_cap_table[i].cap_val); + + size = qm->cap_tables.dev_cap_size; + for (i = 0; i < size; i++) + seq_printf(s, "%s= 0x%08x\n", qm->cap_tables.dev_cap_table[i].name, + qm->cap_tables.dev_cap_table[i].cap_val); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(zip_cap_regs); + static void hisi_zip_dfx_debug_init(struct hisi_qm *qm) { struct dfx_diff_registers *hzip_regs = qm->debug.acc_diff_regs; @@ -854,6 +887,9 @@ static void hisi_zip_dfx_debug_init(struct hisi_qm *qm) if (qm->fun_type == QM_HW_PF && hzip_regs) debugfs_create_file("diff_regs", 0444, tmp_dir, qm, &hzip_diff_regs_fops); + + debugfs_create_file("cap_regs", CAP_FILE_PERMISSION, + qm->debug.debug_root, qm, &zip_cap_regs_fops); } static int hisi_zip_ctrl_debug_init(struct hisi_qm *qm) @@ -912,9 +948,14 @@ static int hisi_zip_debugfs_init(struct hisi_qm *qm) /* hisi_zip_debug_regs_clear() - clear the zip debug regs */ static void hisi_zip_debug_regs_clear(struct hisi_qm *qm) { - u32 zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; + u32 zip_core_info; + u8 zip_core_num; int i, j; + zip_core_info = qm->cap_tables.dev_cap_table[ZIP_CORE_INFO].cap_val; + zip_core_num = (zip_core_info >> zip_basic_cap_info[ZIP_CORE_NUM_CAP].shift) & + zip_basic_cap_info[ZIP_CORE_NUM_CAP].mask; + /* enable register read_clear bit */ writel(HZIP_RD_CNT_CLR_CE_EN, qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE); for (i = 0; i < zip_core_num; i++) @@ -946,10 +987,13 @@ static int hisi_zip_show_last_regs_init(struct hisi_qm *qm) int com_dfx_regs_num = ARRAY_SIZE(hzip_com_dfx_regs); struct qm_debug *debug = &qm->debug; void __iomem *io_base; + u32 zip_core_info; u32 zip_core_num; int i, j, idx; - zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; + zip_core_info = qm->cap_tables.dev_cap_table[ZIP_CORE_INFO].cap_val; + zip_core_num = (zip_core_info >> zip_basic_cap_info[ZIP_CORE_NUM_CAP].shift) & + zip_basic_cap_info[ZIP_CORE_NUM_CAP].mask; debug->last_words = kcalloc(core_dfx_regs_num * zip_core_num + com_dfx_regs_num, sizeof(unsigned int), GFP_KERNEL); @@ -991,6 +1035,7 @@ static void hisi_zip_show_last_dfx_regs(struct hisi_qm *qm) u32 zip_core_num, zip_comp_core_num; struct qm_debug *debug = &qm->debug; char buf[HZIP_BUF_SIZE]; + u32 zip_core_info; void __iomem *base; int i, j, idx; u32 val; @@ -1005,8 +1050,11 @@ static void hisi_zip_show_last_dfx_regs(struct hisi_qm *qm) hzip_com_dfx_regs[i].name, debug->last_words[i], val); } - zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; - zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; + zip_core_info = qm->cap_tables.dev_cap_table[ZIP_CORE_INFO].cap_val; + zip_core_num = (zip_core_info >> zip_basic_cap_info[ZIP_CORE_NUM_CAP].shift) & + zip_basic_cap_info[ZIP_CORE_NUM_CAP].mask; + zip_comp_core_num = (zip_core_info >> zip_basic_cap_info[ZIP_CLUSTER_COMP_NUM_CAP].shift) & + zip_basic_cap_info[ZIP_CLUSTER_COMP_NUM_CAP].mask; for (i = 0; i < zip_core_num; i++) { if (i < zip_comp_core_num) @@ -1059,11 +1107,15 @@ static u32 hisi_zip_get_hw_err_status(struct hisi_qm *qm) static void hisi_zip_clear_hw_err_status(struct hisi_qm *qm, u32 err_sts) { - u32 nfe; - writel(err_sts, qm->io_base + HZIP_CORE_INT_SOURCE); - nfe = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); - writel(nfe, qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); +} + +static void hisi_zip_disable_error_report(struct hisi_qm *qm, u32 err_type) +{ + u32 nfe_mask; + + nfe_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_NFE_MASK_CAP, qm->cap_ver); + writel(nfe_mask & (~err_type), qm->io_base + HZIP_CORE_INT_RAS_NFE_ENB); } static void hisi_zip_open_axi_master_ooo(struct hisi_qm *qm) @@ -1093,6 +1145,27 @@ static void hisi_zip_close_axi_master_ooo(struct hisi_qm *qm) qm->io_base + HZIP_CORE_INT_SET); } +static enum acc_err_result hisi_zip_get_err_result(struct hisi_qm *qm) +{ + u32 err_status; + + err_status = hisi_zip_get_hw_err_status(qm); + if (err_status) { + if (err_status & qm->err_info.ecc_2bits_mask) + qm->err_status.is_dev_ecc_mbit = true; + hisi_zip_log_hw_error(qm, err_status); + + if (err_status & qm->err_info.dev_reset_mask) { + /* Disable the same error reporting until device is recovered. */ + hisi_zip_disable_error_report(qm, err_status); + return ACC_ERR_NEED_RESET; + } + hisi_zip_clear_hw_err_status(qm, err_status); + } + + return ACC_ERR_RECOVERED; +} + static void hisi_zip_err_info_init(struct hisi_qm *qm) { struct hisi_qm_err_info *err_info = &qm->err_info; @@ -1120,13 +1193,13 @@ static const struct hisi_qm_err_ini hisi_zip_err_ini = { .hw_err_disable = hisi_zip_hw_error_disable, .get_dev_hw_err_status = hisi_zip_get_hw_err_status, .clear_dev_hw_err_status = hisi_zip_clear_hw_err_status, - .log_dev_hw_err = hisi_zip_log_hw_error, .open_axi_master_ooo = hisi_zip_open_axi_master_ooo, .close_axi_master_ooo = hisi_zip_close_axi_master_ooo, .open_sva_prefetch = hisi_zip_open_sva_prefetch, .close_sva_prefetch = hisi_zip_close_sva_prefetch, .show_last_dfx_regs = hisi_zip_show_last_dfx_regs, .err_info_init = hisi_zip_err_info_init, + .get_err_result = hisi_zip_get_err_result, }; static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) @@ -1167,18 +1240,20 @@ static int zip_pre_store_cap_reg(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; size_t i, size; - size = ARRAY_SIZE(zip_pre_store_caps); + size = ARRAY_SIZE(zip_cap_query_info); zip_cap = devm_kzalloc(&pdev->dev, sizeof(*zip_cap) * size, GFP_KERNEL); if (!zip_cap) return -ENOMEM; for (i = 0; i < size; i++) { - zip_cap[i].type = zip_pre_store_caps[i]; - zip_cap[i].cap_val = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - zip_pre_store_caps[i], qm->cap_ver); + zip_cap[i].type = zip_cap_query_info[i].type; + zip_cap[i].name = zip_cap_query_info[i].name; + zip_cap[i].cap_val = hisi_qm_get_cap_value(qm, zip_cap_query_info, + i, qm->cap_ver); } qm->cap_tables.dev_cap_table = zip_cap; + qm->cap_tables.dev_cap_size = size; return 0; } @@ -1230,7 +1305,7 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - alg_msk = qm->cap_tables.dev_cap_table[ZIP_DEV_ALG_BITMAP_IDX].cap_val; + alg_msk = qm->cap_tables.dev_cap_table[ZIP_ALG_BITMAP].cap_val; ret = hisi_qm_set_algs(qm, alg_msk, zip_dev_algs, ARRAY_SIZE(zip_dev_algs)); if (ret) { pci_err(qm->pdev, "Failed to set zip algs!\n"); diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c index 7e93159c3b6b96..1dc2378aa88b4e 100644 --- a/drivers/crypto/img-hash.c +++ b/drivers/crypto/img-hash.c @@ -1084,7 +1084,7 @@ static const struct dev_pm_ops img_hash_pm_ops = { static struct platform_driver img_hash_driver = { .probe = img_hash_probe, - .remove_new = img_hash_remove, + .remove = img_hash_remove, .driver = { .name = "img-hash-accelerator", .pm = &img_hash_pm_ops, diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index f5c1912aa56436..9ca80d082c4fb7 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -1868,7 +1868,7 @@ MODULE_DEVICE_TABLE(of, safexcel_of_match_table); static struct platform_driver crypto_safexcel = { .probe = safexcel_probe, - .remove_new = safexcel_remove, + .remove = safexcel_remove, .driver = { .name = "crypto-safexcel", .of_match_table = safexcel_of_match_table, @@ -2031,7 +2031,7 @@ MODULE_AUTHOR("Ofer Heifetz "); MODULE_AUTHOR("Igal Liberman "); MODULE_DESCRIPTION("Support for SafeXcel cryptographic engines: EIP97 & EIP197"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); MODULE_FIRMWARE("ifpp.bin"); MODULE_FIRMWARE("ipue.bin"); diff --git a/drivers/crypto/inside-secure/safexcel_hash.c b/drivers/crypto/inside-secure/safexcel_hash.c index e17577b785c33a..f44c08f5f5ec4a 100644 --- a/drivers/crypto/inside-secure/safexcel_hash.c +++ b/drivers/crypto/inside-secure/safexcel_hash.c @@ -2093,7 +2093,7 @@ static int safexcel_xcbcmac_cra_init(struct crypto_tfm *tfm) safexcel_ahash_cra_init(tfm); ctx->aes = kmalloc(sizeof(*ctx->aes), GFP_KERNEL); - return PTR_ERR_OR_ZERO(ctx->aes); + return ctx->aes == NULL ? -ENOMEM : 0; } static void safexcel_xcbcmac_cra_exit(struct crypto_tfm *tfm) diff --git a/drivers/crypto/intel/iaa/Makefile b/drivers/crypto/intel/iaa/Makefile index b64b208d234408..55bda7770fac79 100644 --- a/drivers/crypto/intel/iaa/Makefile +++ b/drivers/crypto/intel/iaa/Makefile @@ -3,7 +3,7 @@ # Makefile for IAA crypto device drivers # -ccflags-y += -I $(srctree)/drivers/dma/idxd -DDEFAULT_SYMBOL_NAMESPACE=IDXD +ccflags-y += -I $(srctree)/drivers/dma/idxd -DDEFAULT_SYMBOL_NAMESPACE='"IDXD"' obj-$(CONFIG_CRYPTO_DEV_IAA_CRYPTO) := iaa_crypto.o diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c index 237f8700007021..9e557649e5d084 100644 --- a/drivers/crypto/intel/iaa/iaa_crypto_main.c +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c @@ -945,12 +945,22 @@ static inline int check_completion(struct device *dev, bool only_once) { char *op_str = compress ? "compress" : "decompress"; + int status_checks = 0; int ret = 0; while (!comp->status) { if (only_once) return -EAGAIN; cpu_relax(); + if (status_checks++ >= IAA_COMPLETION_TIMEOUT) { + /* Something is wrong with the hw, disable it. */ + dev_err(dev, "%s completion timed out - " + "assuming broken hw, iaa_crypto now DISABLED\n", + op_str); + iaa_crypto_enabled = false; + ret = -ETIMEDOUT; + goto out; + } } if (comp->status != IAX_COMP_SUCCESS) { @@ -2084,7 +2094,7 @@ static void __exit iaa_crypto_cleanup_module(void) pr_debug("cleaned up\n"); } -MODULE_IMPORT_NS(IDXD); +MODULE_IMPORT_NS("IDXD"); MODULE_LICENSE("GPL"); MODULE_ALIAS_IDXD_DEVICE(0); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c b/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c index f8a77bff88448d..449c6d3ab2db14 100644 --- a/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c +++ b/drivers/crypto/intel/ixp4xx/ixp4xx_crypto.c @@ -1588,7 +1588,7 @@ static const struct of_device_id ixp4xx_crypto_of_match[] = { static struct platform_driver ixp_crypto_driver = { .probe = ixp_crypto_probe, - .remove_new = ixp_crypto_remove, + .remove = ixp_crypto_remove, .driver = { .name = "ixp4xx_crypto", .of_match_table = ixp4xx_crypto_of_match, diff --git a/drivers/crypto/intel/keembay/keembay-ocs-aes-core.c b/drivers/crypto/intel/keembay/keembay-ocs-aes-core.c index 9b2d098e5eb2c4..8a8f6c81e010c2 100644 --- a/drivers/crypto/intel/keembay/keembay-ocs-aes-core.c +++ b/drivers/crypto/intel/keembay/keembay-ocs-aes-core.c @@ -1656,7 +1656,7 @@ static int kmb_ocs_aes_probe(struct platform_device *pdev) /* The OCS driver is a platform device. */ static struct platform_driver kmb_ocs_aes_driver = { .probe = kmb_ocs_aes_probe, - .remove_new = kmb_ocs_aes_remove, + .remove = kmb_ocs_aes_remove, .driver = { .name = DRV_NAME, .of_match_table = kmb_ocs_aes_of_match, diff --git a/drivers/crypto/intel/keembay/keembay-ocs-ecc.c b/drivers/crypto/intel/keembay/keembay-ocs-ecc.c index 5e24f2d8affc63..59308926399d0b 100644 --- a/drivers/crypto/intel/keembay/keembay-ocs-ecc.c +++ b/drivers/crypto/intel/keembay/keembay-ocs-ecc.c @@ -991,7 +991,7 @@ static const struct of_device_id kmb_ocs_ecc_of_match[] = { /* The OCS driver is a platform device. */ static struct platform_driver kmb_ocs_ecc_driver = { .probe = kmb_ocs_ecc_probe, - .remove_new = kmb_ocs_ecc_remove, + .remove = kmb_ocs_ecc_remove, .driver = { .name = DRV_NAME, .of_match_table = kmb_ocs_ecc_of_match, diff --git a/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c b/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c index e54c79890d44f5..95dc8979918d8b 100644 --- a/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c +++ b/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c @@ -1243,7 +1243,7 @@ static int kmb_ocs_hcu_probe(struct platform_device *pdev) /* The OCS driver is a platform device. */ static struct platform_driver kmb_ocs_hcu_driver = { .probe = kmb_ocs_hcu_probe, - .remove_new = kmb_ocs_hcu_remove, + .remove = kmb_ocs_hcu_remove, .driver = { .name = DRV_NAME, .of_match_table = kmb_ocs_hcu_of_match, diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c index 78f0ea49254dbb..9faef33e54bd32 100644 --- a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c @@ -375,7 +375,7 @@ static const char *uof_get_name(struct adf_accel_dev *accel_dev, u32 obj_num, else id = -EINVAL; - if (id < 0 || id > num_objs) + if (id < 0 || id >= num_objs) return NULL; return fw_objs[id]; diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c index f49818a13013a3..9589d60fb281da 100644 --- a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c @@ -129,16 +129,21 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Find and map all the device's BARS */ bar_mask = pci_select_bars(pdev, IORESOURCE_MEM) & ADF_GEN4_BAR_MASK; - ret = pcim_iomap_regions_request_all(pdev, bar_mask, pci_name(pdev)); + ret = pcim_request_all_regions(pdev, pci_name(pdev)); if (ret) { - dev_err(&pdev->dev, "Failed to map pci regions.\n"); + dev_err(&pdev->dev, "Failed to request PCI regions.\n"); goto out_err; } i = 0; for_each_set_bit(bar_nr, &bar_mask, PCI_STD_NUM_BARS) { bar = &accel_pci_dev->pci_bars[i++]; - bar->virt_addr = pcim_iomap_table(pdev)[bar_nr]; + bar->virt_addr = pcim_iomap(pdev, bar_nr, 0); + if (!bar->virt_addr) { + dev_err(&pdev->dev, "Failed to ioremap PCI region.\n"); + ret = -ENOMEM; + goto out_err; + } } pci_set_master(pdev); @@ -199,4 +204,4 @@ MODULE_FIRMWARE(ADF_420XX_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); MODULE_SOFTDEP("pre: crypto-intel_qat"); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c index 9fd7ec53b9f3d8..bbd92c017c28ed 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -334,7 +334,7 @@ static const char *uof_get_name(struct adf_accel_dev *accel_dev, u32 obj_num, else id = -EINVAL; - if (id < 0 || id > num_objs) + if (id < 0 || id >= num_objs) return NULL; return fw_objs[id]; diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c index 659905e4595034..d7de1cad133543 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c @@ -131,16 +131,21 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Find and map all the device's BARS */ bar_mask = pci_select_bars(pdev, IORESOURCE_MEM) & ADF_GEN4_BAR_MASK; - ret = pcim_iomap_regions_request_all(pdev, bar_mask, pci_name(pdev)); + ret = pcim_request_all_regions(pdev, pci_name(pdev)); if (ret) { - dev_err(&pdev->dev, "Failed to map pci regions.\n"); + dev_err(&pdev->dev, "Failed to request PCI regions.\n"); goto out_err; } i = 0; for_each_set_bit(bar_nr, &bar_mask, PCI_STD_NUM_BARS) { bar = &accel_pci_dev->pci_bars[i++]; - bar->virt_addr = pcim_iomap_table(pdev)[bar_nr]; + bar->virt_addr = pcim_iomap(pdev, bar_nr, 0); + if (!bar->virt_addr) { + dev_err(&pdev->dev, "Failed to ioremap PCI region.\n"); + ret = -ENOMEM; + goto out_err; + } } pci_set_master(pdev); @@ -203,4 +208,4 @@ MODULE_FIRMWARE(ADF_402XX_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); MODULE_SOFTDEP("pre: crypto-intel_qat"); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c index 4d18057745d444..caa53882fda655 100644 --- a/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c3xxx/adf_drv.c @@ -252,4 +252,4 @@ MODULE_FIRMWARE(ADF_C3XXX_FW); MODULE_FIRMWARE(ADF_C3XXX_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c index f0023cfb234cdd..c622793e94a875 100644 --- a/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c3xxxvf/adf_drv.c @@ -226,4 +226,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c index e6b5de55434ec1..b7398fee19edef 100644 --- a/drivers/crypto/intel/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c62x/adf_drv.c @@ -252,4 +252,4 @@ MODULE_FIRMWARE(ADF_C62X_FW); MODULE_FIRMWARE(ADF_C62X_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c index 2bd5b0ff00e369..4840d44bbd5b2e 100644 --- a/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_c62xvf/adf_drv.c @@ -226,4 +226,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_common/Makefile b/drivers/crypto/intel/qat/qat_common/Makefile index eac73cbfdd38e2..7acf9c576149ba 100644 --- a/drivers/crypto/intel/qat/qat_common/Makefile +++ b/drivers/crypto/intel/qat/qat_common/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_CRYPTO_DEV_QAT) += intel_qat.o -ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CRYPTO_QAT +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"CRYPTO_QAT"' intel_qat-objs := adf_cfg.o \ adf_isr.o \ adf_ctl_drv.o \ diff --git a/drivers/crypto/intel/qat/qat_common/adf_aer.c b/drivers/crypto/intel/qat/qat_common/adf_aer.c index ec7913ab00a2c7..4cb8bd83f57071 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_aer.c +++ b/drivers/crypto/intel/qat/qat_common/adf_aer.c @@ -281,8 +281,11 @@ int adf_init_aer(void) return -EFAULT; device_sriov_wq = alloc_workqueue("qat_device_sriov_wq", 0, 0); - if (!device_sriov_wq) + if (!device_sriov_wq) { + destroy_workqueue(device_reset_wq); + device_reset_wq = NULL; return -EFAULT; + } return 0; } diff --git a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h index f7ecabdf7805db..eaa6388a6678b0 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/intel/qat/qat_common/adf_common_drv.h @@ -69,7 +69,6 @@ void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev, struct adf_accel_dev *pf); struct list_head *adf_devmgr_get_head(void); struct adf_accel_dev *adf_devmgr_get_dev_by_id(u32 id); -struct adf_accel_dev *adf_devmgr_get_first(void); struct adf_accel_dev *adf_devmgr_pci_to_accel_dev(struct pci_dev *pci_dev); int adf_devmgr_verify_id(u32 id); void adf_devmgr_get_num_dev(u32 *num); 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 70fa0f6497a968..48c62a14a6a75b 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/intel/qat/qat_common/adf_ctl_drv.c @@ -475,4 +475,4 @@ MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_ALIAS_CRYPTO("intel_qat"); MODULE_VERSION(ADF_DRV_VERSION); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); +MODULE_IMPORT_NS("CRYPTO_INTERNAL"); diff --git a/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c b/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c index c42f5c25aabdfa..4c11ad1ebcf0f8 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c @@ -22,18 +22,13 @@ void adf_dbgfs_init(struct adf_accel_dev *accel_dev) { char name[ADF_DEVICE_NAME_LENGTH]; - void *ret; /* Create dev top level debugfs entry */ snprintf(name, sizeof(name), "%s%s_%s", ADF_DEVICE_NAME_PREFIX, accel_dev->hw_device->dev_class->name, pci_name(accel_dev->accel_pci_dev.pci_dev)); - ret = debugfs_create_dir(name, NULL); - if (IS_ERR_OR_NULL(ret)) - return; - - accel_dev->debugfs_dir = ret; + accel_dev->debugfs_dir = debugfs_create_dir(name, NULL); adf_cfg_dev_dbgfs_add(accel_dev); } @@ -59,9 +54,6 @@ EXPORT_SYMBOL_GPL(adf_dbgfs_exit); */ void adf_dbgfs_add(struct adf_accel_dev *accel_dev) { - if (!accel_dev->debugfs_dir) - return; - if (!accel_dev->is_vf) { adf_fw_counters_dbgfs_add(accel_dev); adf_heartbeat_dbgfs_add(accel_dev); @@ -77,9 +69,6 @@ void adf_dbgfs_add(struct adf_accel_dev *accel_dev) */ void adf_dbgfs_rm(struct adf_accel_dev *accel_dev) { - if (!accel_dev->debugfs_dir) - return; - if (!accel_dev->is_vf) { adf_tl_dbgfs_rm(accel_dev); adf_cnv_dbgfs_rm(accel_dev); diff --git a/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c b/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c index 96ddd1c419c4a0..34b9f7731c782e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c +++ b/drivers/crypto/intel/qat/qat_common/adf_dev_mgr.c @@ -276,16 +276,6 @@ void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev, } EXPORT_SYMBOL_GPL(adf_devmgr_rm_dev); -struct adf_accel_dev *adf_devmgr_get_first(void) -{ - struct adf_accel_dev *dev = NULL; - - if (!list_empty(&accel_table)) - dev = list_first_entry(&accel_table, struct adf_accel_dev, - list); - return dev; -} - /** * adf_devmgr_pci_to_accel_dev() - Get accel_dev associated with the pci_dev. * @pci_dev: Pointer to PCI device. diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_pm_debugfs.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_pm_debugfs.c index ee0b5079de3ec9..2e4095c4c12c94 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen4_pm_debugfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_pm_debugfs.c @@ -42,13 +42,13 @@ struct pm_status_row { const char *key; }; -static struct pm_status_row pm_fuse_rows[] = { +static const struct pm_status_row pm_fuse_rows[] = { PM_INFO_REGSET_ENTRY(fusectl0, ENABLE_PM), PM_INFO_REGSET_ENTRY(fusectl0, ENABLE_PM_IDLE), PM_INFO_REGSET_ENTRY(fusectl0, ENABLE_DEEP_PM_IDLE), }; -static struct pm_status_row pm_info_rows[] = { +static const struct pm_status_row pm_info_rows[] = { PM_INFO_REGSET_ENTRY(pm.status, CPM_PM_STATE), PM_INFO_REGSET_ENTRY(pm.status, PENDING_WP), PM_INFO_REGSET_ENTRY(pm.status, CURRENT_WP), @@ -59,7 +59,7 @@ static struct pm_status_row pm_info_rows[] = { PM_INFO_REGSET_ENTRY(pm.main, THR_VALUE), }; -static struct pm_status_row pm_ssm_rows[] = { +static const struct pm_status_row pm_ssm_rows[] = { PM_INFO_REGSET_ENTRY(ssm.pm_enable, SSM_PM_ENABLE), PM_INFO_REGSET_ENTRY32(ssm.active_constraint, ACTIVE_CONSTRAINT), PM_INFO_REGSET_ENTRY(ssm.pm_domain_status, DOMAIN_POWER_GATED), @@ -83,7 +83,7 @@ static struct pm_status_row pm_ssm_rows[] = { PM_INFO_REGSET_ENTRY(ssm.pm_managed_status, WCP_MANAGED_COUNT), }; -static struct pm_status_row pm_log_rows[] = { +static const struct pm_status_row pm_log_rows[] = { PM_INFO_REGSET_ENTRY32(event_counters.host_msg, HOST_MSG_EVENT_COUNT), PM_INFO_REGSET_ENTRY32(event_counters.sys_pm, SYS_PM_EVENT_COUNT), PM_INFO_REGSET_ENTRY32(event_counters.local_ssm, SSM_EVENT_COUNT), @@ -91,7 +91,7 @@ static struct pm_status_row pm_log_rows[] = { PM_INFO_REGSET_ENTRY32(event_counters.unknown, UNKNOWN_EVENT_COUNT), }; -static struct pm_status_row pm_event_rows[ICP_QAT_NUMBER_OF_PM_EVENTS] = { +static const struct pm_status_row pm_event_rows[ICP_QAT_NUMBER_OF_PM_EVENTS] = { PM_INFO_REGSET_ENTRY32(event_log[0], EVENT0), PM_INFO_REGSET_ENTRY32(event_log[1], EVENT1), PM_INFO_REGSET_ENTRY32(event_log[2], EVENT2), @@ -102,14 +102,14 @@ static struct pm_status_row pm_event_rows[ICP_QAT_NUMBER_OF_PM_EVENTS] = { PM_INFO_REGSET_ENTRY32(event_log[7], EVENT7), }; -static struct pm_status_row pm_csrs_rows[] = { +static const struct pm_status_row pm_csrs_rows[] = { PM_INFO_REGSET_ENTRY32(pm.fw_init, CPM_PM_FW_INIT), PM_INFO_REGSET_ENTRY32(pm.status, CPM_PM_STATUS), PM_INFO_REGSET_ENTRY32(pm.main, CPM_PM_MASTER_FW), PM_INFO_REGSET_ENTRY32(pm.pwrreq, CPM_PM_PWRREQ), }; -static int pm_scnprint_table(char *buff, struct pm_status_row *table, +static int pm_scnprint_table(char *buff, const struct pm_status_row *table, u32 *pm_info_regs, size_t buff_size, int table_len, bool lowercase) { @@ -131,7 +131,7 @@ static int pm_scnprint_table(char *buff, struct pm_status_row *table, return wr; } -static int pm_scnprint_table_upper_keys(char *buff, struct pm_status_row *table, +static int pm_scnprint_table_upper_keys(char *buff, const struct pm_status_row *table, u32 *pm_info_regs, size_t buff_size, int table_len) { @@ -139,7 +139,7 @@ static int pm_scnprint_table_upper_keys(char *buff, struct pm_status_row *table, table_len, false); } -static int pm_scnprint_table_lower_keys(char *buff, struct pm_status_row *table, +static int pm_scnprint_table_lower_keys(char *buff, const struct pm_status_row *table, u32 *pm_info_regs, size_t buff_size, int table_len) { diff --git a/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c b/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c index 65bd26b25abce9..f93d9cca70cee4 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c +++ b/drivers/crypto/intel/qat/qat_common/adf_hw_arbiter.c @@ -90,10 +90,6 @@ void adf_exit_arb(struct adf_accel_dev *accel_dev) hw_data->get_arb_info(&info); - /* Reset arbiter configuration */ - for (i = 0; i < ADF_ARB_NUM; i++) - WRITE_CSR_ARB_SARCONFIG(csr, arb_off, i, 0); - /* Unmap worker threads to service arbiters */ for (i = 0; i < hw_data->num_engines; i++) WRITE_CSR_ARB_WT2SAM(csr, arb_off, wt_off, i, 0); diff --git a/drivers/crypto/intel/qat/qat_common/qat_hal.c b/drivers/crypto/intel/qat/qat_common/qat_hal.c index 317cafa9d11f9e..ef8a9cf74f0c76 100644 --- a/drivers/crypto/intel/qat/qat_common/qat_hal.c +++ b/drivers/crypto/intel/qat/qat_common/qat_hal.c @@ -163,7 +163,7 @@ int qat_hal_set_ae_ctx_mode(struct icp_qat_fw_loader_handle *handle, return -EINVAL; } - /* Sets the accelaration engine context mode to either four or eight */ + /* Sets the acceleration engine context mode to either four or eight */ csr = qat_hal_rd_ae_csr(handle, ae, CTX_ENABLES); csr = IGNORE_W1C_MASK & csr; new_csr = (mode == 4) ? diff --git a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c index 2a50cce415151b..3137fc3b5cf651 100644 --- a/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_dh895xcc/adf_drv.c @@ -252,4 +252,4 @@ MODULE_FIRMWARE(ADF_DH895XCC_FW); MODULE_FIRMWARE(ADF_DH895XCC_MMP); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c index 7cb015b5512234..7cd528ee31e77c 100644 --- a/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_dh895xccvf/adf_drv.c @@ -226,4 +226,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel"); MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); MODULE_VERSION(ADF_DRV_VERSION); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/crypto/marvell/Kconfig b/drivers/crypto/marvell/Kconfig index 78217577aa5403..4c25a78ab3ed4d 100644 --- a/drivers/crypto/marvell/Kconfig +++ b/drivers/crypto/marvell/Kconfig @@ -7,7 +7,7 @@ config CRYPTO_DEV_MARVELL config CRYPTO_DEV_MARVELL_CESA tristate "Marvell's Cryptographic Engine driver" - depends on PLAT_ORION || ARCH_MVEBU + depends on PLAT_ORION || ARCH_MVEBU || COMPILE_TEST select CRYPTO_LIB_AES select CRYPTO_LIB_DES select CRYPTO_SKCIPHER diff --git a/drivers/crypto/marvell/cesa/cesa.c b/drivers/crypto/marvell/cesa/cesa.c index 5fd31ba715c22a..fa08f10e6f3f2c 100644 --- a/drivers/crypto/marvell/cesa/cesa.c +++ b/drivers/crypto/marvell/cesa/cesa.c @@ -375,7 +375,6 @@ static int mv_cesa_get_sram(struct platform_device *pdev, int idx) { struct mv_cesa_dev *cesa = platform_get_drvdata(pdev); struct mv_cesa_engine *engine = &cesa->engines[idx]; - const char *res_name = "sram"; struct resource *res; engine->pool = of_gen_pool_get(cesa->dev->of_node, @@ -391,19 +390,7 @@ static int mv_cesa_get_sram(struct platform_device *pdev, int idx) return -ENOMEM; } - if (cesa->caps->nengines > 1) { - if (!idx) - res_name = "sram0"; - else - res_name = "sram1"; - } - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - res_name); - if (!res || resource_size(res) < cesa->sram_size) - return -EINVAL; - - engine->sram = devm_ioremap_resource(cesa->dev, res); + engine->sram = devm_platform_get_and_ioremap_resource(pdev, idx, &res); if (IS_ERR(engine->sram)) return PTR_ERR(engine->sram); @@ -510,25 +497,21 @@ static int mv_cesa_probe(struct platform_device *pdev) * if the clock does not exist. */ snprintf(res_name, sizeof(res_name), "cesa%u", i); - engine->clk = devm_clk_get(dev, res_name); + engine->clk = devm_clk_get_optional_enabled(dev, res_name); if (IS_ERR(engine->clk)) { - engine->clk = devm_clk_get(dev, NULL); - if (IS_ERR(engine->clk)) - engine->clk = NULL; + engine->clk = devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(engine->clk)) { + ret = PTR_ERR(engine->clk); + goto err_cleanup; + } } snprintf(res_name, sizeof(res_name), "cesaz%u", i); - engine->zclk = devm_clk_get(dev, res_name); - if (IS_ERR(engine->zclk)) - engine->zclk = NULL; - - ret = clk_prepare_enable(engine->clk); - if (ret) - goto err_cleanup; - - ret = clk_prepare_enable(engine->zclk); - if (ret) + engine->zclk = devm_clk_get_optional_enabled(dev, res_name); + if (IS_ERR(engine->zclk)) { + ret = PTR_ERR(engine->zclk); goto err_cleanup; + } engine->regs = cesa->regs + CESA_ENGINE_OFF(i); @@ -570,13 +553,8 @@ static int mv_cesa_probe(struct platform_device *pdev) return 0; err_cleanup: - for (i = 0; i < caps->nengines; i++) { - clk_disable_unprepare(cesa->engines[i].zclk); - clk_disable_unprepare(cesa->engines[i].clk); + for (i = 0; i < caps->nengines; i++) mv_cesa_put_sram(pdev, i); - if (cesa->engines[i].irq > 0) - irq_set_affinity_hint(cesa->engines[i].irq, NULL); - } return ret; } @@ -588,12 +566,8 @@ static void mv_cesa_remove(struct platform_device *pdev) mv_cesa_remove_algs(cesa); - for (i = 0; i < cesa->caps->nengines; i++) { - clk_disable_unprepare(cesa->engines[i].zclk); - clk_disable_unprepare(cesa->engines[i].clk); + for (i = 0; i < cesa->caps->nengines; i++) mv_cesa_put_sram(pdev, i); - irq_set_affinity_hint(cesa->engines[i].irq, NULL); - } } static const struct platform_device_id mv_cesa_plat_id_table[] = { @@ -604,7 +578,7 @@ MODULE_DEVICE_TABLE(platform, mv_cesa_plat_id_table); static struct platform_driver marvell_cesa = { .probe = mv_cesa_probe, - .remove_new = mv_cesa_remove, + .remove = mv_cesa_remove, .id_table = mv_cesa_plat_id_table, .driver = { .name = "marvell-cesa", diff --git a/drivers/crypto/marvell/cesa/cipher.c b/drivers/crypto/marvell/cesa/cipher.c index 0f37dfd42d8509..cf62db50f95858 100644 --- a/drivers/crypto/marvell/cesa/cipher.c +++ b/drivers/crypto/marvell/cesa/cipher.c @@ -489,7 +489,7 @@ static int mv_cesa_des_op(struct skcipher_request *req, static int mv_cesa_ecb_des_encrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_CRYPTCM_ECB | @@ -500,7 +500,7 @@ static int mv_cesa_ecb_des_encrypt(struct skcipher_request *req) static int mv_cesa_ecb_des_decrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_CRYPTCM_ECB | @@ -543,7 +543,7 @@ static int mv_cesa_cbc_des_op(struct skcipher_request *req, static int mv_cesa_cbc_des_encrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_DIR_ENC); @@ -552,7 +552,7 @@ static int mv_cesa_cbc_des_encrypt(struct skcipher_request *req) static int mv_cesa_cbc_des_decrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_DIR_DEC); @@ -596,7 +596,7 @@ static int mv_cesa_des3_op(struct skcipher_request *req, static int mv_cesa_ecb_des3_ede_encrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_CRYPTCM_ECB | @@ -608,7 +608,7 @@ static int mv_cesa_ecb_des3_ede_encrypt(struct skcipher_request *req) static int mv_cesa_ecb_des3_ede_decrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_CRYPTCM_ECB | @@ -649,7 +649,7 @@ static int mv_cesa_cbc_des3_op(struct skcipher_request *req, static int mv_cesa_cbc_des3_ede_encrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_CRYPTCM_CBC | @@ -661,7 +661,7 @@ static int mv_cesa_cbc_des3_ede_encrypt(struct skcipher_request *req) static int mv_cesa_cbc_des3_ede_decrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_CRYPTCM_CBC | @@ -725,7 +725,7 @@ static int mv_cesa_aes_op(struct skcipher_request *req, static int mv_cesa_ecb_aes_encrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_CRYPTCM_ECB | @@ -736,7 +736,7 @@ static int mv_cesa_ecb_aes_encrypt(struct skcipher_request *req) static int mv_cesa_ecb_aes_decrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_CRYPTCM_ECB | @@ -778,7 +778,7 @@ static int mv_cesa_cbc_aes_op(struct skcipher_request *req, static int mv_cesa_cbc_aes_encrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_DIR_ENC); @@ -787,7 +787,7 @@ static int mv_cesa_cbc_aes_encrypt(struct skcipher_request *req) static int mv_cesa_cbc_aes_decrypt(struct skcipher_request *req) { - struct mv_cesa_op_ctx tmpl; + struct mv_cesa_op_ctx tmpl = { }; mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_DIR_DEC); diff --git a/drivers/crypto/marvell/octeontx2/cn10k_cpt.c b/drivers/crypto/marvell/octeontx2/cn10k_cpt.c index 6bfc59e6774780..5cae8fafa15189 100644 --- a/drivers/crypto/marvell/octeontx2/cn10k_cpt.c +++ b/drivers/crypto/marvell/octeontx2/cn10k_cpt.c @@ -73,7 +73,7 @@ int cn10k_cptpf_lmtst_init(struct otx2_cptpf_dev *cptpf) return 0; } -EXPORT_SYMBOL_NS_GPL(cn10k_cptpf_lmtst_init, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(cn10k_cptpf_lmtst_init, "CRYPTO_DEV_OCTEONTX2_CPT"); int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf) { @@ -94,7 +94,7 @@ int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf) return 0; } -EXPORT_SYMBOL_NS_GPL(cn10k_cptvf_lmtst_init, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(cn10k_cptvf_lmtst_init, "CRYPTO_DEV_OCTEONTX2_CPT"); void cn10k_cpt_hw_ctx_clear(struct pci_dev *pdev, struct cn10k_cpt_errata_ctx *er_ctx) @@ -110,7 +110,7 @@ void cn10k_cpt_hw_ctx_clear(struct pci_dev *pdev, DMA_BIDIRECTIONAL); kfree(er_ctx->hw_ctx); } -EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_clear, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_clear, "CRYPTO_DEV_OCTEONTX2_CPT"); void cn10k_cpt_hw_ctx_set(union cn10k_cpt_hw_ctx *hctx, u16 ctx_sz) { @@ -119,7 +119,7 @@ void cn10k_cpt_hw_ctx_set(union cn10k_cpt_hw_ctx *hctx, u16 ctx_sz) hctx->w0.ctx_sz = ctx_sz; hctx->w0.ctx_push_sz = 1; } -EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_set, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_set, "CRYPTO_DEV_OCTEONTX2_CPT"); int cn10k_cpt_hw_ctx_init(struct pci_dev *pdev, struct cn10k_cpt_errata_ctx *er_ctx) @@ -149,7 +149,7 @@ int cn10k_cpt_hw_ctx_init(struct pci_dev *pdev, return 0; } -EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_init, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_init, "CRYPTO_DEV_OCTEONTX2_CPT"); void cn10k_cpt_ctx_flush(struct pci_dev *pdev, u64 cptr, bool inval) { @@ -168,7 +168,7 @@ void cn10k_cpt_ctx_flush(struct pci_dev *pdev, u64 cptr, bool inval) otx2_cpt_read64(lfs->reg_base, lfs->blkaddr, lfs->lf[0].slot, OTX2_CPT_LF_CTX_ERR); } -EXPORT_SYMBOL_NS_GPL(cn10k_cpt_ctx_flush, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(cn10k_cpt_ctx_flush, "CRYPTO_DEV_OCTEONTX2_CPT"); void cptvf_hw_ops_get(struct otx2_cptvf_dev *cptvf) { @@ -177,4 +177,4 @@ void cptvf_hw_ops_get(struct otx2_cptvf_dev *cptvf) else cptvf->lfs.ops = &otx2_hw_ops; } -EXPORT_SYMBOL_NS_GPL(cptvf_hw_ops_get, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(cptvf_hw_ops_get, "CRYPTO_DEV_OCTEONTX2_CPT"); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c b/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c index 5be0103c1fb817..b8b7c8a3c0ca56 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c @@ -19,7 +19,7 @@ int otx2_cpt_send_mbox_msg(struct otx2_mbox *mbox, struct pci_dev *pdev) } return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_send_mbox_msg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_send_mbox_msg, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cpt_send_ready_msg(struct otx2_mbox *mbox, struct pci_dev *pdev) { @@ -37,13 +37,13 @@ int otx2_cpt_send_ready_msg(struct otx2_mbox *mbox, struct pci_dev *pdev) return otx2_cpt_send_mbox_msg(mbox, pdev); } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_send_ready_msg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_send_ready_msg, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cpt_send_af_reg_requests(struct otx2_mbox *mbox, struct pci_dev *pdev) { return otx2_cpt_send_mbox_msg(mbox, pdev); } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_send_af_reg_requests, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_send_af_reg_requests, "CRYPTO_DEV_OCTEONTX2_CPT"); static int otx2_cpt_add_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, u64 reg, @@ -95,7 +95,7 @@ int otx2_cpt_add_write_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, return 0; } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_add_write_af_reg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_add_write_af_reg, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cpt_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, u64 reg, u64 *val, int blkaddr) @@ -108,7 +108,7 @@ int otx2_cpt_read_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, return otx2_cpt_send_mbox_msg(mbox, pdev); } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_read_af_reg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_read_af_reg, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cpt_write_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, u64 reg, u64 val, int blkaddr) @@ -121,7 +121,7 @@ int otx2_cpt_write_af_reg(struct otx2_mbox *mbox, struct pci_dev *pdev, return otx2_cpt_send_mbox_msg(mbox, pdev); } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_write_af_reg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_write_af_reg, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cpt_attach_rscrs_msg(struct otx2_cptlfs_info *lfs) { @@ -180,7 +180,7 @@ int otx2_cpt_detach_rsrcs_msg(struct otx2_cptlfs_info *lfs) return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_detach_rsrcs_msg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_detach_rsrcs_msg, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cpt_msix_offset_msg(struct otx2_cptlfs_info *lfs) { @@ -213,7 +213,7 @@ int otx2_cpt_msix_offset_msg(struct otx2_cptlfs_info *lfs) } return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_msix_offset_msg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_msix_offset_msg, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cpt_sync_mbox_msg(struct otx2_mbox *mbox) { @@ -228,7 +228,7 @@ int otx2_cpt_sync_mbox_msg(struct otx2_mbox *mbox) return otx2_mbox_check_rsp_msgs(mbox, 0); } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_sync_mbox_msg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_sync_mbox_msg, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cpt_lf_reset_msg(struct otx2_cptlfs_info *lfs, int slot) { @@ -254,4 +254,4 @@ int otx2_cpt_lf_reset_msg(struct otx2_cptlfs_info *lfs, int slot) return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cpt_lf_reset_msg, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cpt_lf_reset_msg, "CRYPTO_DEV_OCTEONTX2_CPT"); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c index b52728e3c0d13e..b5d66afcc030b3 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c @@ -288,8 +288,7 @@ void otx2_cptlf_unregister_misc_interrupts(struct otx2_cptlfs_info *lfs) cptlf_set_misc_intrs(lfs, false); } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_unregister_misc_interrupts, - CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_unregister_misc_interrupts, "CRYPTO_DEV_OCTEONTX2_CPT"); void otx2_cptlf_unregister_done_interrupts(struct otx2_cptlfs_info *lfs) { @@ -308,8 +307,7 @@ void otx2_cptlf_unregister_done_interrupts(struct otx2_cptlfs_info *lfs) cptlf_set_done_intrs(lfs, false); } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_unregister_done_interrupts, - CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_unregister_done_interrupts, "CRYPTO_DEV_OCTEONTX2_CPT"); static int cptlf_do_register_interrrupts(struct otx2_cptlfs_info *lfs, int lf_num, int irq_offset, @@ -351,8 +349,7 @@ int otx2_cptlf_register_misc_interrupts(struct otx2_cptlfs_info *lfs) otx2_cptlf_unregister_misc_interrupts(lfs); return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_register_misc_interrupts, - CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_register_misc_interrupts, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cptlf_register_done_interrupts(struct otx2_cptlfs_info *lfs) { @@ -375,8 +372,7 @@ int otx2_cptlf_register_done_interrupts(struct otx2_cptlfs_info *lfs) otx2_cptlf_unregister_done_interrupts(lfs); return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_register_done_interrupts, - CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_register_done_interrupts, "CRYPTO_DEV_OCTEONTX2_CPT"); void otx2_cptlf_free_irqs_affinity(struct otx2_cptlfs_info *lfs) { @@ -390,7 +386,7 @@ void otx2_cptlf_free_irqs_affinity(struct otx2_cptlfs_info *lfs) free_cpumask_var(lfs->lf[slot].affinity_mask); } } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_free_irqs_affinity, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_free_irqs_affinity, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cptlf_set_irqs_affinity(struct otx2_cptlfs_info *lfs) { @@ -423,7 +419,7 @@ int otx2_cptlf_set_irqs_affinity(struct otx2_cptlfs_info *lfs) otx2_cptlf_free_irqs_affinity(lfs); return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_set_irqs_affinity, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_set_irqs_affinity, "CRYPTO_DEV_OCTEONTX2_CPT"); int otx2_cptlf_init(struct otx2_cptlfs_info *lfs, u8 eng_grp_mask, int pri, int lfs_num) @@ -486,7 +482,7 @@ int otx2_cptlf_init(struct otx2_cptlfs_info *lfs, u8 eng_grp_mask, int pri, lfs->lfs_num = 0; return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_init, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_init, "CRYPTO_DEV_OCTEONTX2_CPT"); void otx2_cptlf_shutdown(struct otx2_cptlfs_info *lfs) { @@ -498,7 +494,7 @@ void otx2_cptlf_shutdown(struct otx2_cptlfs_info *lfs) otx2_cpt_detach_rsrcs_msg(lfs); lfs->lfs_num = 0; } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_shutdown, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_shutdown, "CRYPTO_DEV_OCTEONTX2_CPT"); MODULE_AUTHOR("Marvell"); MODULE_DESCRIPTION("Marvell RVU CPT Common module"); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c index 400e36d9908f43..12971300296d97 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c @@ -739,18 +739,22 @@ static int otx2_cptpf_probe(struct pci_dev *pdev, dev_err(dev, "Unable to get usable DMA configuration\n"); goto clear_drvdata; } - /* Map PF's configuration registers */ - err = pcim_iomap_regions_request_all(pdev, 1 << PCI_PF_REG_BAR_NUM, - OTX2_CPT_DRV_NAME); + err = pcim_request_all_regions(pdev, OTX2_CPT_DRV_NAME); if (err) { - dev_err(dev, "Couldn't get PCI resources 0x%x\n", err); + dev_err(dev, "Couldn't request PCI resources 0x%x\n", err); goto clear_drvdata; } pci_set_master(pdev); pci_set_drvdata(pdev, cptpf); cptpf->pdev = pdev; - cptpf->reg_base = pcim_iomap_table(pdev)[PCI_PF_REG_BAR_NUM]; + /* Map PF's configuration registers */ + cptpf->reg_base = pcim_iomap(pdev, PCI_PF_REG_BAR_NUM, 0); + if (!cptpf->reg_base) { + err = -ENOMEM; + dev_err(dev, "Couldn't ioremap PCI resource 0x%x\n", err); + goto clear_drvdata; + } /* Check if AF driver is up, otherwise defer probe */ err = cpt_is_pf_usable(cptpf); @@ -864,7 +868,7 @@ static struct pci_driver otx2_cpt_pci_driver = { module_pci_driver(otx2_cpt_pci_driver); -MODULE_IMPORT_NS(CRYPTO_DEV_OCTEONTX2_CPT); +MODULE_IMPORT_NS("CRYPTO_DEV_OCTEONTX2_CPT"); MODULE_AUTHOR("Marvell"); MODULE_DESCRIPTION(OTX2_CPT_DRV_STRING); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c index 527d34cc258b45..d84eebdf2fa847 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c @@ -358,9 +358,8 @@ static int otx2_cptvf_probe(struct pci_dev *pdev, dev_err(dev, "Unable to get usable DMA configuration\n"); goto clear_drvdata; } - /* Map VF's configuration registers */ - ret = pcim_iomap_regions_request_all(pdev, 1 << PCI_PF_REG_BAR_NUM, - OTX2_CPTVF_DRV_NAME); + + ret = pcim_request_all_regions(pdev, OTX2_CPTVF_DRV_NAME); if (ret) { dev_err(dev, "Couldn't get PCI resources 0x%x\n", ret); goto clear_drvdata; @@ -369,7 +368,13 @@ static int otx2_cptvf_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, cptvf); cptvf->pdev = pdev; - cptvf->reg_base = pcim_iomap_table(pdev)[PCI_PF_REG_BAR_NUM]; + /* Map VF's configuration registers */ + cptvf->reg_base = pcim_iomap(pdev, PCI_PF_REG_BAR_NUM, 0); + if (!cptvf->reg_base) { + ret = -ENOMEM; + dev_err(dev, "Couldn't ioremap PCI resource 0x%x\n", ret); + goto clear_drvdata; + } otx2_cpt_set_hw_caps(pdev, &cptvf->cap_flag); @@ -448,7 +453,7 @@ static struct pci_driver otx2_cptvf_pci_driver = { module_pci_driver(otx2_cptvf_pci_driver); -MODULE_IMPORT_NS(CRYPTO_DEV_OCTEONTX2_CPT); +MODULE_IMPORT_NS("CRYPTO_DEV_OCTEONTX2_CPT"); MODULE_AUTHOR("Marvell"); MODULE_DESCRIPTION("Marvell RVU CPT Virtual Function Driver"); diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index c82775dbb557a7..d94a26c3541a08 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -225,21 +225,22 @@ static int mxs_dcp_start_dma(struct dcp_async_ctx *actx) static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, struct skcipher_request *req, int init) { - dma_addr_t key_phys = 0; - dma_addr_t src_phys, dst_phys; + dma_addr_t key_phys, src_phys, dst_phys; struct dcp *sdcp = global_sdcp; struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); bool key_referenced = actx->key_referenced; int ret; - if (!key_referenced) { + if (key_referenced) + key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key + AES_KEYSIZE_128, + AES_KEYSIZE_128, DMA_TO_DEVICE); + else key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key, 2 * AES_KEYSIZE_128, DMA_TO_DEVICE); - ret = dma_mapping_error(sdcp->dev, key_phys); - if (ret) - return ret; - } + ret = dma_mapping_error(sdcp->dev, key_phys); + if (ret) + return ret; src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf, DCP_BUF_SZ, DMA_TO_DEVICE); @@ -300,7 +301,10 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, err_dst: dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE); err_src: - if (!key_referenced) + if (key_referenced) + dma_unmap_single(sdcp->dev, key_phys, AES_KEYSIZE_128, + DMA_TO_DEVICE); + else dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128, DMA_TO_DEVICE); return ret; @@ -1243,7 +1247,7 @@ MODULE_DEVICE_TABLE(of, mxs_dcp_dt_ids); static struct platform_driver mxs_dcp_driver = { .probe = mxs_dcp_probe, - .remove_new = mxs_dcp_remove, + .remove = mxs_dcp_remove, .driver = { .name = "mxs-dcp", .of_match_table = mxs_dcp_dt_ids, diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index b11545cc5cb795..14c302d2db79b1 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -2119,7 +2119,7 @@ static struct platform_driver n2_crypto_driver = { .of_match_table = n2_crypto_match, }, .probe = n2_crypto_probe, - .remove_new = n2_crypto_remove, + .remove = n2_crypto_remove, }; static const struct of_device_id n2_mau_match[] = { @@ -2146,7 +2146,7 @@ static struct platform_driver n2_mau_driver = { .of_match_table = n2_mau_match, }, .probe = n2_mau_probe, - .remove_new = n2_mau_remove, + .remove = n2_mau_remove, }; static struct platform_driver * const drivers[] = { diff --git a/drivers/crypto/nx/nx-common-pseries.c b/drivers/crypto/nx/nx-common-pseries.c index 35f2d0d8507ed7..1660c5cf3641c2 100644 --- a/drivers/crypto/nx/nx-common-pseries.c +++ b/drivers/crypto/nx/nx-common-pseries.c @@ -133,7 +133,7 @@ struct nx842_devdata { }; static struct nx842_devdata __rcu *devdata; -static DEFINE_SPINLOCK(devdata_mutex); +static DEFINE_SPINLOCK(devdata_spinlock); #define NX842_COUNTER_INC(_x) \ static inline void nx842_inc_##_x( \ @@ -750,15 +750,15 @@ static int nx842_OF_upd(struct property *new_prop) if (!new_devdata) return -ENOMEM; - spin_lock_irqsave(&devdata_mutex, flags); + spin_lock_irqsave(&devdata_spinlock, flags); old_devdata = rcu_dereference_check(devdata, - lockdep_is_held(&devdata_mutex)); + lockdep_is_held(&devdata_spinlock)); if (old_devdata) of_node = old_devdata->dev->of_node; if (!old_devdata || !of_node) { pr_err("%s: device is not available\n", __func__); - spin_unlock_irqrestore(&devdata_mutex, flags); + spin_unlock_irqrestore(&devdata_spinlock, flags); kfree(new_devdata); return -ENODEV; } @@ -810,7 +810,7 @@ static int nx842_OF_upd(struct property *new_prop) old_devdata->max_sg_len); rcu_assign_pointer(devdata, new_devdata); - spin_unlock_irqrestore(&devdata_mutex, flags); + spin_unlock_irqrestore(&devdata_spinlock, flags); synchronize_rcu(); dev_set_drvdata(new_devdata->dev, new_devdata); kfree(old_devdata); @@ -821,13 +821,13 @@ static int nx842_OF_upd(struct property *new_prop) dev_info(old_devdata->dev, "%s: device disabled\n", __func__); nx842_OF_set_defaults(new_devdata); rcu_assign_pointer(devdata, new_devdata); - spin_unlock_irqrestore(&devdata_mutex, flags); + spin_unlock_irqrestore(&devdata_spinlock, flags); synchronize_rcu(); dev_set_drvdata(new_devdata->dev, new_devdata); kfree(old_devdata); } else { dev_err(old_devdata->dev, "%s: could not update driver from hardware\n", __func__); - spin_unlock_irqrestore(&devdata_mutex, flags); + spin_unlock_irqrestore(&devdata_spinlock, flags); } if (!ret) @@ -1045,9 +1045,9 @@ static int nx842_probe(struct vio_dev *viodev, return -ENOMEM; } - spin_lock_irqsave(&devdata_mutex, flags); + spin_lock_irqsave(&devdata_spinlock, flags); old_devdata = rcu_dereference_check(devdata, - lockdep_is_held(&devdata_mutex)); + lockdep_is_held(&devdata_spinlock)); if (old_devdata && old_devdata->vdev != NULL) { dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__); @@ -1062,7 +1062,7 @@ static int nx842_probe(struct vio_dev *viodev, nx842_OF_set_defaults(new_devdata); rcu_assign_pointer(devdata, new_devdata); - spin_unlock_irqrestore(&devdata_mutex, flags); + spin_unlock_irqrestore(&devdata_spinlock, flags); synchronize_rcu(); kfree(old_devdata); @@ -1101,7 +1101,7 @@ static int nx842_probe(struct vio_dev *viodev, return 0; error_unlock: - spin_unlock_irqrestore(&devdata_mutex, flags); + spin_unlock_irqrestore(&devdata_spinlock, flags); if (new_devdata) kfree(new_devdata->counters); kfree(new_devdata); @@ -1122,12 +1122,13 @@ static void nx842_remove(struct vio_dev *viodev) crypto_unregister_alg(&nx842_pseries_alg); - spin_lock_irqsave(&devdata_mutex, flags); - old_devdata = rcu_dereference_check(devdata, - lockdep_is_held(&devdata_mutex)); of_reconfig_notifier_unregister(&nx842_of_nb); + + spin_lock_irqsave(&devdata_spinlock, flags); + old_devdata = rcu_dereference_check(devdata, + lockdep_is_held(&devdata_spinlock)); RCU_INIT_POINTER(devdata, NULL); - spin_unlock_irqrestore(&devdata_mutex, flags); + spin_unlock_irqrestore(&devdata_spinlock, flags); synchronize_rcu(); dev_set_drvdata(&viodev->dev, NULL); if (old_devdata) @@ -1257,11 +1258,11 @@ static void __exit nx842_pseries_exit(void) crypto_unregister_alg(&nx842_pseries_alg); - spin_lock_irqsave(&devdata_mutex, flags); + spin_lock_irqsave(&devdata_spinlock, flags); old_devdata = rcu_dereference_check(devdata, - lockdep_is_held(&devdata_mutex)); + lockdep_is_held(&devdata_spinlock)); RCU_INIT_POINTER(devdata, NULL); - spin_unlock_irqrestore(&devdata_mutex, flags); + spin_unlock_irqrestore(&devdata_spinlock, flags); synchronize_rcu(); if (old_devdata && old_devdata->dev) dev_set_drvdata(old_devdata->dev, NULL); diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index bad1adacbc84c4..e27b8461674393 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -1305,7 +1305,7 @@ static SIMPLE_DEV_PM_OPS(omap_aes_pm_ops, omap_aes_suspend, omap_aes_resume); static struct platform_driver omap_aes_driver = { .probe = omap_aes_probe, - .remove_new = omap_aes_remove, + .remove = omap_aes_remove, .driver = { .name = "omap-aes", .pm = &omap_aes_pm_ops, diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index 209d3dc03a9bca..498cbd585ed1da 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -1115,7 +1115,7 @@ static SIMPLE_DEV_PM_OPS(omap_des_pm_ops, omap_des_suspend, omap_des_resume); static struct platform_driver omap_des_driver = { .probe = omap_des_probe, - .remove_new = omap_des_remove, + .remove = omap_des_remove, .driver = { .name = "omap-des", .pm = &omap_des_pm_ops, diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 5bcd9ab0f72ad5..7021481bf02715 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -2216,7 +2216,7 @@ static void omap_sham_remove(struct platform_device *pdev) static struct platform_driver omap_sham_driver = { .probe = omap_sham_probe, - .remove_new = omap_sham_remove, + .remove = omap_sham_remove, .driver = { .name = "omap-sham", .of_match_table = omap_sham_of_match, diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c index 28b5fd82382775..e228a31fe28dc0 100644 --- a/drivers/crypto/qce/core.c +++ b/drivers/crypto/qce/core.c @@ -299,7 +299,7 @@ MODULE_DEVICE_TABLE(of, qce_crypto_of_match); static struct platform_driver qce_crypto_driver = { .probe = qce_crypto_probe, - .remove_new = qce_crypto_remove, + .remove = qce_crypto_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = qce_crypto_of_match, diff --git a/drivers/crypto/qcom-rng.c b/drivers/crypto/qcom-rng.c index 09419e79e34c6b..0685ba122e8ac0 100644 --- a/drivers/crypto/qcom-rng.c +++ b/drivers/crypto/qcom-rng.c @@ -262,7 +262,7 @@ MODULE_DEVICE_TABLE(of, qcom_rng_of_match); static struct platform_driver qcom_rng_driver = { .probe = qcom_rng_probe, - .remove_new = qcom_rng_remove, + .remove = qcom_rng_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(qcom_rng_of_match), diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c index f74b3c81ba6df7..b77bdce8e7fcb4 100644 --- a/drivers/crypto/rockchip/rk3288_crypto.c +++ b/drivers/crypto/rockchip/rk3288_crypto.c @@ -433,7 +433,7 @@ static void rk_crypto_remove(struct platform_device *pdev) static struct platform_driver crypto_driver = { .probe = rk_crypto_probe, - .remove_new = rk_crypto_remove, + .remove = rk_crypto_remove, .driver = { .name = "rk3288-crypto", .pm = &rk_crypto_pm_ops, diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 8b6e3f5c94ded7..57ab237e899e38 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -2335,7 +2335,7 @@ static void s5p_aes_remove(struct platform_device *pdev) static struct platform_driver s5p_aes_crypto = { .probe = s5p_aes_probe, - .remove_new = s5p_aes_remove, + .remove = s5p_aes_remove, .driver = { .name = "s5p-secss", .of_match_table = s5p_sss_dt_match, diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c index 461eca40e8789f..091612b066f1e7 100644 --- a/drivers/crypto/sa2ul.c +++ b/drivers/crypto/sa2ul.c @@ -574,7 +574,7 @@ static int sa_format_cmdl_gen(struct sa_cmdl_cfg *cfg, u8 *cmdl, /* Clear the command label */ memzero_explicit(cmdl, (SA_MAX_CMDL_WORDS * sizeof(u32))); - /* Iniialize the command update structure */ + /* Initialize the command update structure */ memzero_explicit(upd_info, sizeof(*upd_info)); if (cfg->enc_eng_id && cfg->auth_eng_id) { @@ -2489,7 +2489,7 @@ static void sa_ul_remove(struct platform_device *pdev) static struct platform_driver sa_ul_driver = { .probe = sa_ul_probe, - .remove_new = sa_ul_remove, + .remove = sa_ul_remove, .driver = { .name = "saul-crypto", .of_match_table = of_match, diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 96d4af5d48a644..533080b0cddc96 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -1421,7 +1421,7 @@ static void sahara_remove(struct platform_device *pdev) static struct platform_driver sahara_driver = { .probe = sahara_probe, - .remove_new = sahara_remove, + .remove = sahara_remove, .driver = { .name = SAHARA_NAME, .of_match_table = sahara_dt_ids, diff --git a/drivers/crypto/starfive/jh7110-cryp.c b/drivers/crypto/starfive/jh7110-cryp.c index e4dfed7ee0b01d..42114e9364f0d0 100644 --- a/drivers/crypto/starfive/jh7110-cryp.c +++ b/drivers/crypto/starfive/jh7110-cryp.c @@ -151,7 +151,7 @@ static int starfive_cryp_probe(struct platform_device *pdev) ret = starfive_aes_register_algs(); if (ret) - goto err_algs_aes; + goto err_engine_start; ret = starfive_hash_register_algs(); if (ret) @@ -167,8 +167,6 @@ static int starfive_cryp_probe(struct platform_device *pdev) starfive_hash_unregister_algs(); err_algs_hash: starfive_aes_unregister_algs(); -err_algs_aes: - crypto_engine_stop(cryp->engine); err_engine_start: crypto_engine_exit(cryp->engine); err_engine: @@ -193,7 +191,6 @@ static void starfive_cryp_remove(struct platform_device *pdev) starfive_hash_unregister_algs(); starfive_rsa_unregister_algs(); - crypto_engine_stop(cryp->engine); crypto_engine_exit(cryp->engine); starfive_dma_cleanup(cryp); @@ -215,7 +212,7 @@ MODULE_DEVICE_TABLE(of, starfive_dt_ids); static struct platform_driver starfive_cryp_driver = { .probe = starfive_cryp_probe, - .remove_new = starfive_cryp_remove, + .remove = starfive_cryp_remove, .driver = { .name = DRIVER_NAME, .of_match_table = starfive_dt_ids, diff --git a/drivers/crypto/starfive/jh7110-rsa.c b/drivers/crypto/starfive/jh7110-rsa.c index a778c48460253f..d109c743f076d6 100644 --- a/drivers/crypto/starfive/jh7110-rsa.c +++ b/drivers/crypto/starfive/jh7110-rsa.c @@ -565,8 +565,6 @@ static void starfive_rsa_exit_tfm(struct crypto_akcipher *tfm) static struct akcipher_alg starfive_rsa = { .encrypt = starfive_rsa_enc, .decrypt = starfive_rsa_dec, - .sign = starfive_rsa_dec, - .verify = starfive_rsa_enc, .set_pub_key = starfive_rsa_set_pub_key, .set_priv_key = starfive_rsa_set_priv_key, .max_size = starfive_rsa_max_size, diff --git a/drivers/crypto/stm32/stm32-crc32.c b/drivers/crypto/stm32/stm32-crc32.c index e0faddbf8990cb..de4d0402f13391 100644 --- a/drivers/crypto/stm32/stm32-crc32.c +++ b/drivers/crypto/stm32/stm32-crc32.c @@ -465,7 +465,7 @@ MODULE_DEVICE_TABLE(of, stm32_dt_ids); static struct platform_driver stm32_crc_driver = { .probe = stm32_crc_probe, - .remove_new = stm32_crc_remove, + .remove = stm32_crc_remove, .driver = { .name = DRIVER_NAME, .pm = &stm32_crc_pm_ops, diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c index 937f6dab8955ee..14c6339c2e43ce 100644 --- a/drivers/crypto/stm32/stm32-cryp.c +++ b/drivers/crypto/stm32/stm32-cryp.c @@ -2771,7 +2771,7 @@ static const struct dev_pm_ops stm32_cryp_pm_ops = { static struct platform_driver stm32_cryp_driver = { .probe = stm32_cryp_probe, - .remove_new = stm32_cryp_remove, + .remove = stm32_cryp_remove, .driver = { .name = DRIVER_NAME, .pm = &stm32_cryp_pm_ops, diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c index 351827372ea6f9..768b27de473786 100644 --- a/drivers/crypto/stm32/stm32-hash.c +++ b/drivers/crypto/stm32/stm32-hash.c @@ -2532,7 +2532,7 @@ static const struct dev_pm_ops stm32_hash_pm_ops = { static struct platform_driver stm32_hash_driver = { .probe = stm32_hash_probe, - .remove_new = stm32_hash_remove, + .remove = stm32_hash_remove, .driver = { .name = "stm32-hash", .pm = &stm32_hash_pm_ops, diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 511ddcb0efd4b4..e8c0db687c57fd 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -3560,7 +3560,7 @@ static struct platform_driver talitos_driver = { .of_match_table = talitos_match, }, .probe = talitos_probe, - .remove_new = talitos_remove, + .remove = talitos_remove, }; module_platform_driver(talitos_driver); diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c index ae7a0f8435fc63..9d130592cc0acd 100644 --- a/drivers/crypto/tegra/tegra-se-aes.c +++ b/drivers/crypto/tegra/tegra-se-aes.c @@ -1180,8 +1180,6 @@ static int tegra_ccm_do_one_req(struct crypto_engine *engine, void *areq) goto out; } else { rctx->cryptlen = req->cryptlen - ctx->authsize; - if (ret) - goto out; /* CTR operation */ ret = tegra_ccm_do_ctr(ctx, rctx); diff --git a/drivers/crypto/tegra/tegra-se-main.c b/drivers/crypto/tegra/tegra-se-main.c index f94c0331b148cc..918c0b10614d43 100644 --- a/drivers/crypto/tegra/tegra-se-main.c +++ b/drivers/crypto/tegra/tegra-se-main.c @@ -312,7 +312,6 @@ static int tegra_se_probe(struct platform_device *pdev) ret = tegra_se_host1x_register(se); if (ret) { - crypto_engine_stop(se->engine); crypto_engine_exit(se->engine); return dev_err_probe(dev, ret, "failed to init host1x params\n"); } @@ -324,7 +323,6 @@ static void tegra_se_remove(struct platform_device *pdev) { struct tegra_se *se = platform_get_drvdata(pdev); - crypto_engine_stop(se->engine); crypto_engine_exit(se->engine); host1x_client_unregister(&se->client); } @@ -387,7 +385,7 @@ static struct platform_driver tegra_se_driver = { .of_match_table = tegra_se_of_match, }, .probe = tegra_se_probe, - .remove_new = tegra_se_remove, + .remove = tegra_se_remove, }; static int tegra_se_host1x_probe(struct host1x_device *dev) diff --git a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c index cb92b7fa99c6f8..48fee07b7e517b 100644 --- a/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c +++ b/drivers/crypto/virtio/virtio_crypto_akcipher_algs.c @@ -83,23 +83,16 @@ static void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request * case VIRTIO_CRYPTO_BADMSG: error = -EBADMSG; break; - - case VIRTIO_CRYPTO_KEY_REJECTED: - error = -EKEYREJECTED; - break; - default: error = -EIO; break; } akcipher_req = vc_akcipher_req->akcipher_req; - if (vc_akcipher_req->opcode != VIRTIO_CRYPTO_AKCIPHER_VERIFY) { - /* actuall length maybe less than dst buffer */ - akcipher_req->dst_len = len - sizeof(vc_req->status); - sg_copy_from_buffer(akcipher_req->dst, sg_nents(akcipher_req->dst), - vc_akcipher_req->dst_buf, akcipher_req->dst_len); - } + /* actual length maybe less than dst buffer */ + akcipher_req->dst_len = len - sizeof(vc_req->status); + sg_copy_from_buffer(akcipher_req->dst, sg_nents(akcipher_req->dst), + vc_akcipher_req->dst_buf, akcipher_req->dst_len); virtio_crypto_akcipher_finalize_req(vc_akcipher_req, akcipher_req, error); } @@ -230,36 +223,27 @@ static int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request int node = dev_to_node(&vcrypto->vdev->dev); unsigned long flags; int ret; - bool verify = vc_akcipher_req->opcode == VIRTIO_CRYPTO_AKCIPHER_VERIFY; - unsigned int src_len = verify ? req->src_len + req->dst_len : req->src_len; /* out header */ sg_init_one(&outhdr_sg, req_data, sizeof(*req_data)); sgs[num_out++] = &outhdr_sg; /* src data */ - src_buf = kcalloc_node(src_len, 1, GFP_KERNEL, node); + src_buf = kcalloc_node(req->src_len, 1, GFP_KERNEL, node); if (!src_buf) return -ENOMEM; - if (verify) { - /* for verify operation, both src and dst data work as OUT direction */ - sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len); - sg_init_one(&srcdata_sg, src_buf, src_len); - sgs[num_out++] = &srcdata_sg; - } else { - sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len); - sg_init_one(&srcdata_sg, src_buf, src_len); - sgs[num_out++] = &srcdata_sg; + sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, req->src_len); + sg_init_one(&srcdata_sg, src_buf, req->src_len); + sgs[num_out++] = &srcdata_sg; - /* dst data */ - dst_buf = kcalloc_node(req->dst_len, 1, GFP_KERNEL, node); - if (!dst_buf) - goto free_src; + /* dst data */ + dst_buf = kcalloc_node(req->dst_len, 1, GFP_KERNEL, node); + if (!dst_buf) + goto free_src; - sg_init_one(&dstdata_sg, dst_buf, req->dst_len); - sgs[num_out + num_in++] = &dstdata_sg; - } + sg_init_one(&dstdata_sg, dst_buf, req->dst_len); + sgs[num_out + num_in++] = &dstdata_sg; vc_akcipher_req->src_buf = src_buf; vc_akcipher_req->dst_buf = dst_buf; @@ -352,16 +336,6 @@ static int virtio_crypto_rsa_decrypt(struct akcipher_request *req) return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_DECRYPT); } -static int virtio_crypto_rsa_sign(struct akcipher_request *req) -{ - return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_SIGN); -} - -static int virtio_crypto_rsa_verify(struct akcipher_request *req) -{ - return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_VERIFY); -} - static int virtio_crypto_rsa_set_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen, @@ -524,16 +498,19 @@ static struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = { .algo.base = { .encrypt = virtio_crypto_rsa_encrypt, .decrypt = virtio_crypto_rsa_decrypt, - .sign = virtio_crypto_rsa_sign, - .verify = virtio_crypto_rsa_verify, + /* + * Must specify an arbitrary hash algorithm upon + * set_{pub,priv}_key (even though it's not used + * by encrypt/decrypt) because qemu checks for it. + */ .set_pub_key = virtio_crypto_p1pad_rsa_sha1_set_pub_key, .set_priv_key = virtio_crypto_p1pad_rsa_sha1_set_priv_key, .max_size = virtio_crypto_rsa_max_size, .init = virtio_crypto_rsa_init_tfm, .exit = virtio_crypto_rsa_exit_tfm, .base = { - .cra_name = "pkcs1pad(rsa,sha1)", - .cra_driver_name = "virtio-pkcs1-rsa-with-sha1", + .cra_name = "pkcs1pad(rsa)", + .cra_driver_name = "virtio-pkcs1-rsa", .cra_priority = 150, .cra_module = THIS_MODULE, .cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx), diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c index 7f0ec6887a399c..6e72d922941065 100644 --- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c +++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c @@ -438,7 +438,7 @@ MODULE_DEVICE_TABLE(of, zynqmp_aes_dt_ids); static struct platform_driver zynqmp_aes_driver = { .probe = zynqmp_aes_aead_probe, - .remove_new = zynqmp_aes_aead_remove, + .remove = zynqmp_aes_aead_remove, .driver = { .name = "zynqmp-aes", .of_match_table = zynqmp_aes_dt_ids, diff --git a/drivers/crypto/xilinx/zynqmp-sha.c b/drivers/crypto/xilinx/zynqmp-sha.c index 1bcec6f46c9c75..580649f9bff81f 100644 --- a/drivers/crypto/xilinx/zynqmp-sha.c +++ b/drivers/crypto/xilinx/zynqmp-sha.c @@ -248,7 +248,7 @@ static void zynqmp_sha_remove(struct platform_device *pdev) static struct platform_driver zynqmp_sha_driver = { .probe = zynqmp_sha_probe, - .remove_new = zynqmp_sha_remove, + .remove = zynqmp_sha_remove, .driver = { .name = "zynqmp-sha3-384", }, diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 432b7cfd12a8e1..cb14829bb9be4b 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -934,5 +934,5 @@ MODULE_SOFTDEP("pre: cxl_port"); module_exit(cxl_acpi_exit); MODULE_DESCRIPTION("CXL ACPI: Platform Support"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(CXL); -MODULE_IMPORT_NS(ACPI); +MODULE_IMPORT_NS("CXL"); +MODULE_IMPORT_NS("ACPI"); diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index e9cd7939c407ac..8153f8d83a164a 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -247,8 +247,8 @@ static void update_perf_entry(struct device *dev, struct dsmas_entry *dent, dpa_perf->dpa_range = dent->dpa_range; dpa_perf->qos_class = dent->qos_class; dev_dbg(dev, - "DSMAS: dpa: %#llx qos: %d read_bw: %d write_bw %d read_lat: %d write_lat: %d\n", - dent->dpa_range.start, dpa_perf->qos_class, + "DSMAS: dpa: %pra qos: %d read_bw: %d write_bw %d read_lat: %d write_lat: %d\n", + &dent->dpa_range, dpa_perf->qos_class, dent->coord[ACCESS_COORDINATE_CPU].read_bandwidth, dent->coord[ACCESS_COORDINATE_CPU].write_bandwidth, dent->coord[ACCESS_COORDINATE_CPU].read_latency, @@ -279,8 +279,8 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds, range_contains(&pmem_range, &dent->dpa_range)) update_perf_entry(dev, dent, &mds->pmem_perf); else - dev_dbg(dev, "no partition for dsmas dpa: %#llx\n", - dent->dpa_range.start); + dev_dbg(dev, "no partition for dsmas dpa: %pra\n", + &dent->dpa_range); } } @@ -416,7 +416,7 @@ void cxl_endpoint_parse_cdat(struct cxl_port *port) cxl_qos_class_verify(cxlmd); cxl_memdev_update_perf(cxlmd); } -EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, "CXL"); static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, const unsigned long end) @@ -513,7 +513,7 @@ void cxl_switch_parse_cdat(struct cxl_port *port) if (rc) dev_dbg(&port->dev, "Failed to parse SSLBIS: %d\n", rc); } -EXPORT_SYMBOL_NS_GPL(cxl_switch_parse_cdat, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_switch_parse_cdat, "CXL"); static void __cxl_coordinates_combine(struct access_coordinate *out, struct access_coordinate *c1, @@ -545,7 +545,7 @@ void cxl_coordinates_combine(struct access_coordinate *out, __cxl_coordinates_combine(&out[i], &c1[i], &c2[i]); } -MODULE_IMPORT_NS(CXL); +MODULE_IMPORT_NS("CXL"); static void cxl_bandwidth_add(struct access_coordinate *coord, struct access_coordinate *c1, diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 0c62b4069ba00a..800466f96a6851 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -89,6 +89,11 @@ resource_size_t __rcrb_to_component(struct device *dev, enum cxl_rcrb which); u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb); +#define PCI_RCRB_CAP_LIST_ID_MASK GENMASK(7, 0) +#define PCI_RCRB_CAP_HDR_ID_MASK GENMASK(7, 0) +#define PCI_RCRB_CAP_HDR_NEXT_MASK GENMASK(15, 8) +#define PCI_CAP_EXP_SIZEOF 0x3c + extern struct rw_semaphore cxl_dpa_rwsem; extern struct rw_semaphore cxl_region_rwsem; diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 223c273c0cd179..28edd582248685 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -73,7 +73,7 @@ int devm_cxl_add_passthrough_decoder(struct cxl_port *port) return add_hdm_decoder(port, &cxlsd->cxld, single_port_map); } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, "CXL"); static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm) { @@ -199,7 +199,7 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, return cxlhdm; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, "CXL"); static void __cxl_dpa_debug(struct seq_file *file, struct resource *r, int depth) { @@ -221,7 +221,7 @@ void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds) } up_read(&cxl_dpa_rwsem); } -EXPORT_SYMBOL_NS_GPL(cxl_dpa_debug, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_dpa_debug, "CXL"); /* * Must be called in a context that synchronizes against this decoder's @@ -358,7 +358,7 @@ int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled); } -EXPORT_SYMBOL_NS_GPL(devm_cxl_dpa_reserve, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_dpa_reserve, "CXL"); resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled) { @@ -424,7 +424,6 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); struct cxl_dev_state *cxlds = cxlmd->cxlds; struct device *dev = &cxled->cxld.dev; - int rc; switch (mode) { case CXL_DECODER_RAM: @@ -435,11 +434,9 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, return -EINVAL; } - down_write(&cxl_dpa_rwsem); - if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) { - rc = -EBUSY; - goto out; - } + guard(rwsem_write)(&cxl_dpa_rwsem); + if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) + return -EBUSY; /* * Only allow modes that are supported by the current partition @@ -447,21 +444,15 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, */ if (mode == CXL_DECODER_PMEM && !resource_size(&cxlds->pmem_res)) { dev_dbg(dev, "no available pmem capacity\n"); - rc = -ENXIO; - goto out; + return -ENXIO; } if (mode == CXL_DECODER_RAM && !resource_size(&cxlds->ram_res)) { dev_dbg(dev, "no available ram capacity\n"); - rc = -ENXIO; - goto out; + return -ENXIO; } cxled->mode = mode; - rc = 0; -out: - up_write(&cxl_dpa_rwsem); - - return rc; + return 0; } int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size) @@ -747,7 +738,7 @@ void cxl_port_commit_reap(struct cxl_decoder *cxld) device_for_each_child_reverse_from(&port->dev, &cxld->dev, NULL, commit_reap); } -EXPORT_SYMBOL_NS_GPL(cxl_port_commit_reap, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_port_commit_reap, "CXL"); static void cxl_decoder_reset(struct cxl_decoder *cxld) { @@ -1073,4 +1064,4 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, return 0; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, "CXL"); diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 5175138c4fb738..548564c770c02c 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -281,7 +281,7 @@ int cxl_internal_send_cmd(struct cxl_mailbox *cxl_mbox, return -EIO; return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_internal_send_cmd, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_internal_send_cmd, "CXL"); static bool cxl_mem_raw_command_allowed(u16 opcode) { @@ -854,7 +854,7 @@ int cxl_enumerate_cmds(struct cxl_memdev_state *mds) kvfree(gsl); return rc; } -EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, "CXL"); void cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_log_type type, @@ -894,7 +894,7 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, trace_cxl_dram(cxlmd, type, cxlr, hpa, &evt->dram); } } -EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, "CXL"); static void __cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_log_type type, @@ -1063,7 +1063,7 @@ void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status) if (status & CXLDEV_EVENT_STATUS_INFO) cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_INFO); } -EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_mem_get_event_records, "CXL"); /** * cxl_mem_get_partition_info - Get partition info @@ -1155,7 +1155,7 @@ int cxl_dev_state_identify(struct cxl_memdev_state *mds) return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, "CXL"); static int __cxl_mem_sanitize(struct cxl_memdev_state *mds, u16 cmd) { @@ -1306,7 +1306,7 @@ int cxl_mem_create_range_info(struct cxl_memdev_state *mds) mds->active_volatile_bytes, mds->active_persistent_bytes, "pmem"); } -EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, "CXL"); int cxl_set_timestamp(struct cxl_memdev_state *mds) { @@ -1333,7 +1333,7 @@ int cxl_set_timestamp(struct cxl_memdev_state *mds) return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_set_timestamp, CXL); +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) @@ -1384,7 +1384,7 @@ int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, mutex_unlock(&mds->poison.lock); return rc; } -EXPORT_SYMBOL_NS_GPL(cxl_mem_get_poison, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_mem_get_poison, "CXL"); static void free_poison_buf(void *buf) { @@ -1420,7 +1420,7 @@ int cxl_poison_state_init(struct cxl_memdev_state *mds) mutex_init(&mds->poison.lock); return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_poison_state_init, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_poison_state_init, "CXL"); int cxl_mailbox_init(struct cxl_mailbox *cxl_mbox, struct device *host) { @@ -1433,7 +1433,7 @@ int cxl_mailbox_init(struct cxl_mailbox *cxl_mbox, struct device *host) return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_mailbox_init, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_mailbox_init, "CXL"); struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev) { @@ -1455,7 +1455,7 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev) return mds; } -EXPORT_SYMBOL_NS_GPL(cxl_memdev_state_create, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_memdev_state_create, "CXL"); void __init cxl_mbox_init(void) { diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index 84fefb76dafabc..ae3dfcbe893897 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -250,7 +250,7 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd) return rc; } -EXPORT_SYMBOL_NS_GPL(cxl_trigger_poison_list, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_trigger_poison_list, "CXL"); static int cxl_validate_poison_dpa(struct cxl_memdev *cxlmd, u64 dpa) { @@ -329,7 +329,7 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) return rc; } -EXPORT_SYMBOL_NS_GPL(cxl_inject_poison, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_inject_poison, "CXL"); int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) { @@ -393,7 +393,7 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) return rc; } -EXPORT_SYMBOL_NS_GPL(cxl_clear_poison, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_clear_poison, "CXL"); static struct attribute *cxl_memdev_attributes[] = { &dev_attr_serial.attr, @@ -537,7 +537,7 @@ void cxl_memdev_update_perf(struct cxl_memdev *cxlmd) sysfs_update_group(&cxlmd->dev.kobj, &cxl_memdev_ram_attribute_group); sysfs_update_group(&cxlmd->dev.kobj, &cxl_memdev_pmem_attribute_group); } -EXPORT_SYMBOL_NS_GPL(cxl_memdev_update_perf, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_memdev_update_perf, "CXL"); static const struct device_type cxl_memdev_type = { .name = "cxl_memdev", @@ -550,7 +550,7 @@ bool is_cxl_memdev(const struct device *dev) { return dev->type == &cxl_memdev_type; } -EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, CXL); +EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, "CXL"); /** * set_exclusive_cxl_commands() - atomically disable user cxl commands @@ -569,7 +569,7 @@ void set_exclusive_cxl_commands(struct cxl_memdev_state *mds, CXL_MEM_COMMAND_ID_MAX); up_write(&cxl_memdev_rwsem); } -EXPORT_SYMBOL_NS_GPL(set_exclusive_cxl_commands, CXL); +EXPORT_SYMBOL_NS_GPL(set_exclusive_cxl_commands, "CXL"); /** * clear_exclusive_cxl_commands() - atomically enable user cxl commands @@ -584,7 +584,7 @@ void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds, CXL_MEM_COMMAND_ID_MAX); up_write(&cxl_memdev_rwsem); } -EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL); +EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, "CXL"); static void cxl_memdev_shutdown(struct device *dev) { @@ -1006,7 +1006,7 @@ int devm_cxl_setup_fw_upload(struct device *host, struct cxl_memdev_state *mds) return PTR_ERR(fwl); return devm_add_action_or_reset(host, cxl_remove_fw_upload, fwl); } -EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_fw_upload, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_fw_upload, "CXL"); static const struct file_operations cxl_memdev_fops = { .owner = THIS_MODULE, @@ -1060,7 +1060,7 @@ struct cxl_memdev *devm_cxl_add_memdev(struct device *host, put_device(dev); return ERR_PTR(rc); } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, "CXL"); static void sanitize_teardown_notifier(void *data) { @@ -1105,7 +1105,7 @@ int devm_cxl_sanitize_setup_notifier(struct device *host, return devm_add_action_or_reset(host, sanitize_teardown_notifier, mds); } -EXPORT_SYMBOL_NS_GPL(devm_cxl_sanitize_setup_notifier, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_sanitize_setup_notifier, "CXL"); __init int cxl_memdev_init(void) { diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 5b46bc46aaa951..9d58ab9d33c554 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -101,7 +101,7 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port) return ctx.error; return ctx.count; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_port_enumerate_dports, "CXL"); static int cxl_dvsec_mem_range_valid(struct cxl_dev_state *cxlds, int id) { @@ -209,7 +209,7 @@ int cxl_await_media_ready(struct cxl_dev_state *cxlds) return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_await_media_ready, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_await_media_ready, "CXL"); static int cxl_set_mem_enable(struct cxl_dev_state *cxlds, u16 val) { @@ -386,7 +386,7 @@ int cxl_dvsec_rr_decode(struct device *dev, struct cxl_port *port, return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_dvsec_rr_decode, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_dvsec_rr_decode, "CXL"); /** * cxl_hdm_decode_init() - Setup HDM decoding for the endpoint @@ -464,7 +464,7 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, */ return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, "CXL"); #define CXL_DOE_TABLE_ACCESS_REQ_CODE 0x000000ff #define CXL_DOE_TABLE_ACCESS_REQ_CODE_READ 0 @@ -648,7 +648,7 @@ void read_cdat_data(struct cxl_port *port) devm_kfree(dev, buf); dev_err(dev, "Failed to read/validate CDAT.\n"); } -EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL); +EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL"); static void __cxl_handle_cor_ras(struct cxl_dev_state *cxlds, void __iomem *ras_base) @@ -805,7 +805,7 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host) cxl_disable_rch_root_ints(dport); } } -EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL"); static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds, struct cxl_dport *dport) @@ -916,7 +916,7 @@ void cxl_cor_error_detected(struct pci_dev *pdev) cxl_handle_endpoint_cor_ras(cxlds); } } -EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL"); pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, pci_channel_state_t state) @@ -966,7 +966,7 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, } return PCI_ERS_RESULT_NEED_RESET; } -EXPORT_SYMBOL_NS_GPL(cxl_error_detected, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL"); static int cxl_flit_size(struct pci_dev *pdev) { @@ -1030,7 +1030,7 @@ bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port) return device_for_each_child(&port->dev, port, __cxl_endpoint_decoder_reset_detected); } -EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_reset_detected, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_reset_detected, "CXL"); int cxl_pci_get_bandwidth(struct pci_dev *pdev, struct access_coordinate *c) { diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c index c00f3a933164fa..b3378d3f6acb4c 100644 --- a/drivers/cxl/core/pmem.c +++ b/drivers/cxl/core/pmem.c @@ -49,13 +49,13 @@ struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev) return NULL; return container_of(dev, struct cxl_nvdimm_bridge, dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm_bridge, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm_bridge, "CXL"); bool is_cxl_nvdimm_bridge(struct device *dev) { return dev->type == &cxl_nvdimm_bridge_type; } -EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm_bridge, CXL); +EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm_bridge, "CXL"); static int match_nvdimm_bridge(struct device *dev, void *data) { @@ -82,7 +82,7 @@ struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_port *port) return to_cxl_nvdimm_bridge(dev); } -EXPORT_SYMBOL_NS_GPL(cxl_find_nvdimm_bridge, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_find_nvdimm_bridge, "CXL"); static struct lock_class_key cxl_nvdimm_bridge_key; @@ -164,7 +164,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, put_device(dev); return ERR_PTR(rc); } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm_bridge, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm_bridge, "CXL"); static void cxl_nvdimm_release(struct device *dev) { @@ -188,7 +188,7 @@ bool is_cxl_nvdimm(struct device *dev) { return dev->type == &cxl_nvdimm_type; } -EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm, CXL); +EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm, "CXL"); struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev) { @@ -197,7 +197,7 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev) return NULL; return container_of(dev, struct cxl_nvdimm, dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm, "CXL"); static struct lock_class_key cxl_nvdimm_key; @@ -293,4 +293,4 @@ int devm_cxl_add_nvdimm(struct cxl_port *parent_port, return rc; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm, "CXL"); diff --git a/drivers/cxl/core/pmu.c b/drivers/cxl/core/pmu.c index 5d8e06b0ba6e88..b3136d7664aba8 100644 --- a/drivers/cxl/core/pmu.c +++ b/drivers/cxl/core/pmu.c @@ -65,4 +65,4 @@ int devm_cxl_pmu_add(struct device *parent, struct cxl_pmu_regs *regs, put_device(&pmu->dev); return rc; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_pmu_add, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_pmu_add, "CXL"); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index af92c67bc9542d..78a5c2c259829c 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -437,7 +437,7 @@ struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev) return NULL; return container_of(dev, struct cxl_root_decoder, cxlsd.cxld.dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_root_decoder, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_root_decoder, "CXL"); static void cxl_root_decoder_release(struct device *dev) { @@ -471,19 +471,19 @@ bool is_endpoint_decoder(struct device *dev) { return dev->type == &cxl_decoder_endpoint_type; } -EXPORT_SYMBOL_NS_GPL(is_endpoint_decoder, CXL); +EXPORT_SYMBOL_NS_GPL(is_endpoint_decoder, "CXL"); bool is_root_decoder(struct device *dev) { return dev->type == &cxl_decoder_root_type; } -EXPORT_SYMBOL_NS_GPL(is_root_decoder, CXL); +EXPORT_SYMBOL_NS_GPL(is_root_decoder, "CXL"); bool is_switch_decoder(struct device *dev) { return is_root_decoder(dev) || dev->type == &cxl_decoder_switch_type; } -EXPORT_SYMBOL_NS_GPL(is_switch_decoder, CXL); +EXPORT_SYMBOL_NS_GPL(is_switch_decoder, "CXL"); struct cxl_decoder *to_cxl_decoder(struct device *dev) { @@ -493,7 +493,7 @@ struct cxl_decoder *to_cxl_decoder(struct device *dev) return NULL; return container_of(dev, struct cxl_decoder, dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_decoder, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_decoder, "CXL"); struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev) { @@ -502,7 +502,7 @@ struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev) return NULL; return container_of(dev, struct cxl_endpoint_decoder, cxld.dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_endpoint_decoder, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_endpoint_decoder, "CXL"); struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev) { @@ -511,7 +511,7 @@ struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev) return NULL; return container_of(dev, struct cxl_switch_decoder, cxld.dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_switch_decoder, "CXL"); static void cxl_ep_release(struct cxl_ep *ep) { @@ -585,7 +585,7 @@ bool is_cxl_port(const struct device *dev) { return dev->type == &cxl_port_type; } -EXPORT_SYMBOL_NS_GPL(is_cxl_port, CXL); +EXPORT_SYMBOL_NS_GPL(is_cxl_port, "CXL"); struct cxl_port *to_cxl_port(const struct device *dev) { @@ -594,7 +594,7 @@ struct cxl_port *to_cxl_port(const struct device *dev) return NULL; return container_of(dev, struct cxl_port, dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_port, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_port, "CXL"); static void unregister_port(void *_port) { @@ -942,7 +942,7 @@ struct cxl_port *devm_cxl_add_port(struct device *host, return port; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, "CXL"); struct cxl_root *devm_cxl_add_root(struct device *host, const struct cxl_root_ops *ops) @@ -958,7 +958,7 @@ struct cxl_root *devm_cxl_add_root(struct device *host, cxl_root->ops = ops; return cxl_root; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_root, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_root, "CXL"); struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port) { @@ -974,7 +974,7 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port) return xa_load(&cxl_root_buses, (unsigned long)port->uport_dev); } -EXPORT_SYMBOL_NS_GPL(cxl_port_to_pci_bus, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_port_to_pci_bus, "CXL"); static void unregister_pci_bus(void *uport_dev) { @@ -995,7 +995,7 @@ int devm_cxl_register_pci_bus(struct device *host, struct device *uport_dev, return rc; return devm_add_action_or_reset(host, unregister_pci_bus, uport_dev); } -EXPORT_SYMBOL_NS_GPL(devm_cxl_register_pci_bus, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_register_pci_bus, "CXL"); static bool dev_is_cxl_root_child(struct device *dev) { @@ -1027,7 +1027,7 @@ struct cxl_root *find_cxl_root(struct cxl_port *port) get_device(&iter->dev); return to_cxl_root(iter); } -EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL); +EXPORT_SYMBOL_NS_GPL(find_cxl_root, "CXL"); void put_cxl_root(struct cxl_root *cxl_root) { @@ -1036,7 +1036,7 @@ void put_cxl_root(struct cxl_root *cxl_root) put_device(&cxl_root->port.dev); } -EXPORT_SYMBOL_NS_GPL(put_cxl_root, CXL); +EXPORT_SYMBOL_NS_GPL(put_cxl_root, "CXL"); static struct cxl_dport *find_dport(struct cxl_port *port, int id) { @@ -1230,7 +1230,7 @@ struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port, return dport; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport, "CXL"); /** * devm_cxl_add_rch_dport - append RCH downstream port data to a cxl_port @@ -1264,7 +1264,7 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port, return dport; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_add_rch_dport, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_rch_dport, "CXL"); static int add_ep(struct cxl_ep *new) { @@ -1421,7 +1421,7 @@ int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint) cxlmd->depth = endpoint->depth; return devm_add_action_or_reset(dev, delete_endpoint, cxlmd); } -EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, "CXL"); /* * The natural end of life of a non-root 'cxl_port' is when its parent port goes @@ -1692,21 +1692,21 @@ int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd) return 0; } -EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, CXL); +EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, "CXL"); struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev, struct cxl_dport **dport) { return find_cxl_port(pdev->dev.parent, dport); } -EXPORT_SYMBOL_NS_GPL(cxl_pci_find_port, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_pci_find_port, "CXL"); struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, struct cxl_dport **dport) { return find_cxl_port(grandparent(&cxlmd->dev), dport); } -EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, "CXL"); static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, struct cxl_port *port, int *target_map) @@ -1840,7 +1840,7 @@ struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, cxlrd->qos_class = CXL_QOS_CLASS_INVALID; return cxlrd; } -EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, "CXL"); /** * cxl_switch_decoder_alloc - Allocate a switch level decoder @@ -1877,7 +1877,7 @@ struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, cxld->dev.type = &cxl_decoder_switch_type; return cxlsd; } -EXPORT_SYMBOL_NS_GPL(cxl_switch_decoder_alloc, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_switch_decoder_alloc, "CXL"); /** * cxl_endpoint_decoder_alloc - Allocate an endpoint decoder @@ -1909,7 +1909,7 @@ struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port) cxld->dev.type = &cxl_decoder_endpoint_type; return cxled; } -EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, "CXL"); /** * cxl_decoder_add_locked - Add a decoder with targets @@ -1965,7 +1965,7 @@ int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map) return device_add(dev); } -EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, "CXL"); /** * cxl_decoder_add - Add a decoder with targets @@ -1995,7 +1995,7 @@ int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) guard(device)(&port->dev); return cxl_decoder_add_locked(cxld, target_map); } -EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, "CXL"); static void cxld_unregister(void *dev) { @@ -2013,7 +2013,7 @@ int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld) { return devm_add_action_or_reset(host, cxld_unregister, &cxld->dev); } -EXPORT_SYMBOL_NS_GPL(cxl_decoder_autoremove, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_decoder_autoremove, "CXL"); /** * __cxl_driver_register - register a driver for the cxl bus @@ -2046,13 +2046,13 @@ int __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner, return driver_register(&cxl_drv->drv); } -EXPORT_SYMBOL_NS_GPL(__cxl_driver_register, CXL); +EXPORT_SYMBOL_NS_GPL(__cxl_driver_register, "CXL"); void cxl_driver_unregister(struct cxl_driver *cxl_drv) { driver_unregister(&cxl_drv->drv); } -EXPORT_SYMBOL_NS_GPL(cxl_driver_unregister, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_driver_unregister, "CXL"); static int cxl_bus_uevent(const struct device *dev, struct kobj_uevent_env *env) { @@ -2104,19 +2104,19 @@ void cxl_bus_rescan(void) queue_work(cxl_bus_wq, &rescan_work); } -EXPORT_SYMBOL_NS_GPL(cxl_bus_rescan, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_bus_rescan, "CXL"); void cxl_bus_drain(void) { drain_workqueue(cxl_bus_wq); } -EXPORT_SYMBOL_NS_GPL(cxl_bus_drain, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_bus_drain, "CXL"); bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd) { return queue_work(cxl_bus_wq, &cxlmd->detach_work); } -EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, CXL); +EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, "CXL"); static void add_latency(struct access_coordinate *c, long latency) { @@ -2242,7 +2242,7 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_endpoint_get_perf_coordinates, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_get_perf_coordinates, "CXL"); int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port, struct access_coordinate *c) @@ -2299,7 +2299,7 @@ struct bus_type cxl_bus_type = { .remove = cxl_bus_remove, .bus_groups = cxl_bus_attribute_groups, }; -EXPORT_SYMBOL_NS_GPL(cxl_bus_type, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_bus_type, "CXL"); static struct dentry *cxl_debugfs; @@ -2307,7 +2307,7 @@ struct dentry *cxl_debugfs_create_dir(const char *dir) { return debugfs_create_dir(dir, cxl_debugfs); } -EXPORT_SYMBOL_NS_GPL(cxl_debugfs_create_dir, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_debugfs_create_dir, "CXL"); static __init int cxl_core_init(void) { @@ -2363,4 +2363,4 @@ subsys_initcall(cxl_core_init); module_exit(cxl_core_exit); MODULE_DESCRIPTION("CXL: Core Compute Express Link support"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(CXL); +MODULE_IMPORT_NS("CXL"); diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index dff618c708dc68..b98b1ccffd1ca1 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1295,6 +1295,7 @@ static int cxl_port_setup_targets(struct cxl_port *port, struct cxl_region_params *p = &cxlr->params; struct cxl_decoder *cxld = cxl_rr->decoder; struct cxl_switch_decoder *cxlsd; + struct cxl_port *iter = port; u16 eig, peig; u8 eiw, peiw; @@ -1311,16 +1312,26 @@ static int cxl_port_setup_targets(struct cxl_port *port, cxlsd = to_cxl_switch_decoder(&cxld->dev); if (cxl_rr->nr_targets_set) { - int i, distance; + int i, distance = 1; + struct cxl_region_ref *cxl_rr_iter; /* - * Passthrough decoders impose no distance requirements between - * peers + * The "distance" between peer downstream ports represents which + * endpoint positions in the region interleave a given port can + * host. + * + * For example, at the root of a hierarchy the distance is + * always 1 as every index targets a different host-bridge. At + * each subsequent switch level those ports map every Nth region + * position where N is the width of the switch == distance. */ - if (cxl_rr->nr_targets == 1) - distance = 0; - else - distance = p->nr_targets / cxl_rr->nr_targets; + do { + cxl_rr_iter = cxl_rr_load(iter, cxlr); + distance *= cxl_rr_iter->nr_targets; + iter = to_cxl_port(iter->dev.parent); + } while (!is_cxl_root(iter)); + distance *= cxlrd->cxlsd.cxld.interleave_ways; + for (i = 0; i < cxl_rr->nr_targets_set; i++) if (ep->dport == cxlsd->target[i]) { rc = check_last_peer(cxled, ep, cxl_rr, @@ -2299,7 +2310,7 @@ bool is_cxl_region(struct device *dev) { return dev->type == &cxl_region_type; } -EXPORT_SYMBOL_NS_GPL(is_cxl_region, CXL); +EXPORT_SYMBOL_NS_GPL(is_cxl_region, "CXL"); static struct cxl_region *to_cxl_region(struct device *dev) { @@ -2537,9 +2548,8 @@ static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd, return devm_cxl_add_region(cxlrd, id, mode, CXL_DECODER_HOSTONLYMEM); } -static ssize_t create_pmem_region_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static ssize_t create_region_store(struct device *dev, const char *buf, + size_t len, enum cxl_decoder_mode mode) { struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); struct cxl_region *cxlr; @@ -2549,31 +2559,26 @@ static ssize_t create_pmem_region_store(struct device *dev, if (rc != 1) return -EINVAL; - cxlr = __create_region(cxlrd, CXL_DECODER_PMEM, id); + cxlr = __create_region(cxlrd, mode, id); if (IS_ERR(cxlr)) return PTR_ERR(cxlr); return len; } + +static ssize_t create_pmem_region_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return create_region_store(dev, buf, len, CXL_DECODER_PMEM); +} DEVICE_ATTR_RW(create_pmem_region); static ssize_t create_ram_region_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); - struct cxl_region *cxlr; - int rc, id; - - rc = sscanf(buf, "region%d\n", &id); - if (rc != 1) - return -EINVAL; - - cxlr = __create_region(cxlrd, CXL_DECODER_RAM, id); - if (IS_ERR(cxlr)) - return PTR_ERR(cxlr); - - return len; + return create_region_store(dev, buf, len, CXL_DECODER_RAM); } DEVICE_ATTR_RW(create_ram_region); @@ -2658,7 +2663,7 @@ bool is_cxl_pmem_region(struct device *dev) { return dev->type == &cxl_pmem_region_type; } -EXPORT_SYMBOL_NS_GPL(is_cxl_pmem_region, CXL); +EXPORT_SYMBOL_NS_GPL(is_cxl_pmem_region, "CXL"); struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev) { @@ -2667,7 +2672,7 @@ struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev) return NULL; return container_of(dev, struct cxl_pmem_region, dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_pmem_region, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_pmem_region, "CXL"); struct cxl_poison_context { struct cxl_port *port; @@ -3021,7 +3026,7 @@ struct cxl_dax_region *to_cxl_dax_region(struct device *dev) return NULL; return container_of(dev, struct cxl_dax_region, dev); } -EXPORT_SYMBOL_NS_GPL(to_cxl_dax_region, CXL); +EXPORT_SYMBOL_NS_GPL(to_cxl_dax_region, "CXL"); static struct lock_class_key cxl_dax_region_key; @@ -3365,7 +3370,7 @@ int cxl_add_to_region(struct cxl_port *root, struct cxl_endpoint_decoder *cxled) put_device(cxlrd_dev); return rc; } -EXPORT_SYMBOL_NS_GPL(cxl_add_to_region, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_add_to_region, "CXL"); static int is_system_ram(struct resource *res, void *arg) { @@ -3468,6 +3473,6 @@ void cxl_region_exit(void) cxl_driver_unregister(&cxl_region_driver); } -MODULE_IMPORT_NS(CXL); -MODULE_IMPORT_NS(DEVMEM); +MODULE_IMPORT_NS("CXL"); +MODULE_IMPORT_NS("DEVMEM"); MODULE_ALIAS_CXL(CXL_DEVICE_REGION); diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c index e1082e749c69e6..59cb35b40c7e55 100644 --- a/drivers/cxl/core/regs.c +++ b/drivers/cxl/core/regs.c @@ -52,7 +52,7 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base, cap_array = readl(base + CXL_CM_CAP_HDR_OFFSET); if (FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, cap_array) != CM_CAP_HDR_CAP_ID) { - dev_err(dev, + dev_dbg(dev, "Couldn't locate the CXL.cache and CXL.mem capability array header.\n"); return; } @@ -106,7 +106,7 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base, rmap->size = length; } } -EXPORT_SYMBOL_NS_GPL(cxl_probe_component_regs, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_probe_component_regs, "CXL"); /** * cxl_probe_device_regs() - Detect CXL Device register blocks @@ -174,7 +174,7 @@ void cxl_probe_device_regs(struct device *dev, void __iomem *base, rmap->size = length; } } -EXPORT_SYMBOL_NS_GPL(cxl_probe_device_regs, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_probe_device_regs, "CXL"); void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, resource_size_t length) @@ -232,7 +232,7 @@ int cxl_map_component_regs(const struct cxl_register_map *map, return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, "CXL"); int cxl_map_device_regs(const struct cxl_register_map *map, struct cxl_device_regs *regs) @@ -266,7 +266,7 @@ int cxl_map_device_regs(const struct cxl_register_map *map, return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, "CXL"); static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi, struct cxl_register_map *map) @@ -344,7 +344,7 @@ int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type, map->resource = CXL_RESOURCE_NONE; return -ENODEV; } -EXPORT_SYMBOL_NS_GPL(cxl_find_regblock_instance, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_find_regblock_instance, "CXL"); /** * cxl_find_regblock() - Locate register blocks by type @@ -362,7 +362,7 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, { return cxl_find_regblock_instance(pdev, type, map, 0); } -EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, "CXL"); /** * cxl_count_regblock() - Count instances of a given regblock type. @@ -385,7 +385,7 @@ int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type) count++; } } -EXPORT_SYMBOL_NS_GPL(cxl_count_regblock, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_count_regblock, "CXL"); int cxl_map_pmu_regs(struct cxl_register_map *map, struct cxl_pmu_regs *regs) { @@ -399,7 +399,7 @@ int cxl_map_pmu_regs(struct cxl_register_map *map, struct cxl_pmu_regs *regs) return 0; } -EXPORT_SYMBOL_NS_GPL(cxl_map_pmu_regs, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_map_pmu_regs, "CXL"); static int cxl_map_regblock(struct cxl_register_map *map) { @@ -468,7 +468,7 @@ int cxl_setup_regs(struct cxl_register_map *map) return rc; } -EXPORT_SYMBOL_NS_GPL(cxl_setup_regs, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_setup_regs, "CXL"); u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb) { @@ -506,6 +506,62 @@ u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb) return offset; } +static resource_size_t cxl_rcrb_to_linkcap(struct device *dev, struct cxl_dport *dport) +{ + resource_size_t rcrb = dport->rcrb.base; + void __iomem *addr; + u32 cap_hdr; + u16 offset; + + if (!request_mem_region(rcrb, SZ_4K, "CXL RCRB")) + return CXL_RESOURCE_NONE; + + addr = ioremap(rcrb, SZ_4K); + if (!addr) { + dev_err(dev, "Failed to map region %pr\n", addr); + release_mem_region(rcrb, SZ_4K); + return CXL_RESOURCE_NONE; + } + + offset = FIELD_GET(PCI_RCRB_CAP_LIST_ID_MASK, readw(addr + PCI_CAPABILITY_LIST)); + cap_hdr = readl(addr + offset); + while ((FIELD_GET(PCI_RCRB_CAP_HDR_ID_MASK, cap_hdr)) != PCI_CAP_ID_EXP) { + offset = FIELD_GET(PCI_RCRB_CAP_HDR_NEXT_MASK, cap_hdr); + if (offset == 0 || offset > SZ_4K) { + offset = 0; + break; + } + cap_hdr = readl(addr + offset); + } + + iounmap(addr); + release_mem_region(rcrb, SZ_4K); + if (!offset) + return CXL_RESOURCE_NONE; + + return offset; +} + +int cxl_dport_map_rcd_linkcap(struct pci_dev *pdev, struct cxl_dport *dport) +{ + void __iomem *dport_pcie_cap = NULL; + resource_size_t pos; + struct cxl_rcrb_info *ri; + + ri = &dport->rcrb; + pos = cxl_rcrb_to_linkcap(&pdev->dev, dport); + if (pos == CXL_RESOURCE_NONE) + return -ENXIO; + + dport_pcie_cap = devm_cxl_iomap_block(&pdev->dev, + ri->base + pos, + PCI_CAP_EXP_SIZEOF); + dport->regs.rcd_pcie_cap = dport_pcie_cap; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_dport_map_rcd_linkcap, "CXL"); + resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri, enum cxl_rcrb which) { @@ -577,4 +633,4 @@ resource_size_t cxl_rcd_component_reg_phys(struct device *dev, return CXL_RESOURCE_NONE; return __rcrb_to_component(dev, &dport->rcrb, CXL_RCRB_UPSTREAM); } -EXPORT_SYMBOL_NS_GPL(cxl_rcd_component_reg_phys, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_rcd_component_reg_phys, "CXL"); diff --git a/drivers/cxl/core/suspend.c b/drivers/cxl/core/suspend.c index a5984d96ea1d06..29aa5cc5e5652a 100644 --- a/drivers/cxl/core/suspend.c +++ b/drivers/cxl/core/suspend.c @@ -15,10 +15,10 @@ void cxl_mem_active_inc(void) { atomic_inc(&mem_active); } -EXPORT_SYMBOL_NS_GPL(cxl_mem_active_inc, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_mem_active_inc, "CXL"); void cxl_mem_active_dec(void) { atomic_dec(&mem_active); } -EXPORT_SYMBOL_NS_GPL(cxl_mem_active_dec, CXL); +EXPORT_SYMBOL_NS_GPL(cxl_mem_active_dec, "CXL"); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 5406e3ab3d4a45..f6015f24ad3818 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -235,6 +235,14 @@ struct cxl_regs { struct_group_tagged(cxl_rch_regs, rch_regs, void __iomem *dport_aer; ); + + /* + * RCD upstream port specific PCIe cap register + * @pcie_cap: CXL 3.0 8.2.1.2 RCD Upstream Port RCRB + */ + struct_group_tagged(cxl_rcd_regs, rcd_regs, + void __iomem *rcd_pcie_cap; + ); }; struct cxl_reg_map { @@ -304,6 +312,7 @@ int cxl_setup_regs(struct cxl_register_map *map); struct cxl_dport; resource_size_t cxl_rcd_component_reg_phys(struct device *dev, struct cxl_dport *dport); +int cxl_dport_map_rcd_linkcap(struct pci_dev *pdev, struct cxl_dport *dport); #define CXL_RESOURCE_NONE ((resource_size_t) -1) #define CXL_TARGET_STRLEN 20 diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index a9fd5cd5a0d2f9..2f03a4d5606ea7 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -252,7 +252,7 @@ module_cxl_driver(cxl_mem_driver); MODULE_DESCRIPTION("CXL: Memory Expansion"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(CXL); +MODULE_IMPORT_NS("CXL"); MODULE_ALIAS_CXL(CXL_DEVICE_MEMORY_EXPANDER); /* * create_endpoint() wants to validate port driver attach immediately after diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 188412d45e0d26..6d94ff4a4f1a62 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -475,9 +475,9 @@ static bool is_cxl_restricted(struct pci_dev *pdev) } static int cxl_rcrb_get_comp_regs(struct pci_dev *pdev, - struct cxl_register_map *map) + struct cxl_register_map *map, + struct cxl_dport *dport) { - struct cxl_dport *dport; resource_size_t component_reg_phys; *map = (struct cxl_register_map) { @@ -513,11 +513,24 @@ static int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, * is an RCH and try to extract the Component Registers from * an RCRB. */ - if (rc && type == CXL_REGLOC_RBI_COMPONENT && is_cxl_restricted(pdev)) - rc = cxl_rcrb_get_comp_regs(pdev, map); - - if (rc) + if (rc && type == CXL_REGLOC_RBI_COMPONENT && is_cxl_restricted(pdev)) { + struct cxl_dport *dport; + struct cxl_port *port __free(put_cxl_port) = + cxl_pci_find_port(pdev, &dport); + if (!port) + return -EPROBE_DEFER; + + rc = cxl_rcrb_get_comp_regs(pdev, map, dport); + if (rc) + return rc; + + rc = cxl_dport_map_rcd_linkcap(pdev, dport); + if (rc) + return rc; + + } else if (rc) { return rc; + } return cxl_setup_regs(map); } @@ -764,10 +777,6 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, return 0; } - rc = cxl_mem_alloc_event_buf(mds); - if (rc) - return rc; - rc = cxl_event_get_int_policy(mds, &policy); if (rc) return rc; @@ -781,6 +790,10 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, return -EBUSY; } + rc = cxl_mem_alloc_event_buf(mds); + if (rc) + return rc; + rc = cxl_event_irqsetup(mds); if (rc) return rc; @@ -807,6 +820,86 @@ static int cxl_pci_type3_init_mailbox(struct cxl_dev_state *cxlds) return 0; } +static ssize_t rcd_pcie_cap_emit(struct device *dev, u16 offset, char *buf, size_t width) +{ + struct cxl_dev_state *cxlds = dev_get_drvdata(dev); + struct cxl_memdev *cxlmd = cxlds->cxlmd; + struct device *root_dev; + struct cxl_dport *dport; + struct cxl_port *root __free(put_cxl_port) = + cxl_mem_find_port(cxlmd, &dport); + + if (!root) + return -ENXIO; + + root_dev = root->uport_dev; + if (!root_dev) + return -ENXIO; + + if (!dport->regs.rcd_pcie_cap) + return -ENXIO; + + guard(device)(root_dev); + if (!root_dev->driver) + return -ENXIO; + + switch (width) { + case 2: + return sysfs_emit(buf, "%#x\n", + readw(dport->regs.rcd_pcie_cap + offset)); + case 4: + return sysfs_emit(buf, "%#x\n", + readl(dport->regs.rcd_pcie_cap + offset)); + default: + return -EINVAL; + } +} + +static ssize_t rcd_link_cap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return rcd_pcie_cap_emit(dev, PCI_EXP_LNKCAP, buf, sizeof(u32)); +} +static DEVICE_ATTR_RO(rcd_link_cap); + +static ssize_t rcd_link_ctrl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return rcd_pcie_cap_emit(dev, PCI_EXP_LNKCTL, buf, sizeof(u16)); +} +static DEVICE_ATTR_RO(rcd_link_ctrl); + +static ssize_t rcd_link_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return rcd_pcie_cap_emit(dev, PCI_EXP_LNKSTA, buf, sizeof(u16)); +} +static DEVICE_ATTR_RO(rcd_link_status); + +static struct attribute *cxl_rcd_attrs[] = { + &dev_attr_rcd_link_cap.attr, + &dev_attr_rcd_link_ctrl.attr, + &dev_attr_rcd_link_status.attr, + NULL +}; + +static umode_t cxl_rcd_visible(struct kobject *kobj, struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct pci_dev *pdev = to_pci_dev(dev); + + if (is_cxl_restricted(pdev)) + return a->mode; + + return 0; +} + +static struct attribute_group cxl_rcd_group = { + .attrs = cxl_rcd_attrs, + .is_visible = cxl_rcd_visible, +}; +__ATTRIBUTE_GROUPS(cxl_rcd); + static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pci_host_bridge *host_bridge = pci_find_host_bridge(pdev->bus); @@ -942,8 +1035,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; - rc = cxl_pci_ras_unmask(pdev); - if (rc) + if (cxl_pci_ras_unmask(pdev)) dev_dbg(&pdev->dev, "No RAS reporting unmasked\n"); pci_save_state(pdev); @@ -1016,6 +1108,7 @@ static struct pci_driver cxl_pci_driver = { .id_table = cxl_mem_pci_tbl, .probe = cxl_pci_probe, .err_handler = &cxl_error_handlers, + .dev_groups = cxl_rcd_groups, .driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, @@ -1093,4 +1186,4 @@ module_init(cxl_pci_driver_init); module_exit(cxl_pci_driver_exit); MODULE_DESCRIPTION("CXL: PCI manageability"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(CXL); +MODULE_IMPORT_NS("CXL"); diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index d2d43a4fc05387..f9c95996e937ed 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -459,7 +459,7 @@ MODULE_DESCRIPTION("CXL PMEM: Persistent Memory Support"); MODULE_LICENSE("GPL v2"); module_init(cxl_pmem_init); module_exit(cxl_pmem_exit); -MODULE_IMPORT_NS(CXL); +MODULE_IMPORT_NS("CXL"); MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE); MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM); MODULE_ALIAS_CXL(CXL_DEVICE_PMEM_REGION); diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index 9dc394295e1fcd..4c83f6a22e584f 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -173,7 +173,7 @@ static ssize_t CDAT_read(struct file *filp, struct kobject *kobj, static BIN_ATTR_ADMIN_RO(CDAT, 0); static umode_t cxl_port_bin_attr_is_visible(struct kobject *kobj, - struct bin_attribute *attr, int i) + const struct bin_attribute *attr, int i) { struct device *dev = kobj_to_dev(kobj); struct cxl_port *port = to_cxl_port(dev); @@ -226,5 +226,5 @@ module_exit(cxl_port_exit); MODULE_DESCRIPTION("CXL: Port enumeration and services"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(CXL); +MODULE_IMPORT_NS("CXL"); MODULE_ALIAS_CXL(CXL_DEVICE_PORT); diff --git a/drivers/dax/cxl.c b/drivers/dax/cxl.c index 9b29e732b39a69..13cd94d32ff7a1 100644 --- a/drivers/dax/cxl.c +++ b/drivers/dax/cxl.c @@ -46,4 +46,4 @@ MODULE_ALIAS_CXL(CXL_DEVICE_DAX_REGION); MODULE_DESCRIPTION("CXL DAX: direct access to CXL regions"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Intel Corporation"); -MODULE_IMPORT_NS(CXL); +MODULE_IMPORT_NS("CXL"); diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index 446617b73aeab2..0867115aeef2e1 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -40,12 +40,30 @@ struct dax_region { struct device *youngest; }; +/** + * struct dax_mapping - device to display mapping range attributes + * @dev: device representing this range + * @range_id: index within dev_dax ranges array + * @id: ida of this mapping + */ struct dax_mapping { struct device dev; int range_id; int id; }; +/** + * struct dev_dax_range - tuple represenging a range of memory used by dev_dax + * @pgoff: page offset + * @range: resource-span + * @mapping: reference to the dax_mapping for this range + */ +struct dev_dax_range { + unsigned long pgoff; + struct range range; + struct dax_mapping *mapping; +}; + /** * struct dev_dax - instance data for a subdivision of a dax region, and * data while the device is activated in the driver. @@ -58,7 +76,7 @@ struct dax_mapping { * @dev - device core * @pgmap - pgmap for memmap setup / lifetime (driver owned) * @nr_range: size of @ranges - * @ranges: resource-span + pgoff tuples for the instance + * @ranges: range tuples of memory used */ struct dev_dax { struct dax_region *region; @@ -72,11 +90,7 @@ struct dev_dax { struct dev_pagemap *pgmap; bool memmap_on_memory; int nr_range; - struct dev_dax_range { - unsigned long pgoff; - struct range range; - struct dax_mapping *mapping; - } *ranges; + struct dev_dax_range *ranges; }; /* diff --git a/drivers/dax/pmem/Makefile b/drivers/dax/pmem/Makefile deleted file mode 100644 index 191c31f0d4f008..00000000000000 --- a/drivers/dax/pmem/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o -obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem_core.o - -dax_pmem-y := pmem.o -dax_pmem_core-y := core.o -dax_pmem_compat-y := compat.o diff --git a/drivers/dax/pmem/pmem.c b/drivers/dax/pmem/pmem.c deleted file mode 100644 index dfe91a2990fec4..00000000000000 --- a/drivers/dax/pmem/pmem.c +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright(c) 2016 - 2018 Intel Corporation. All rights reserved. */ -#include -#include -#include -#include -#include -#include "../bus.h" - - diff --git a/drivers/devfreq/event/exynos-nocp.c b/drivers/devfreq/event/exynos-nocp.c index 5edc522f715c3e..6a3efd782ad0df 100644 --- a/drivers/devfreq/event/exynos-nocp.c +++ b/drivers/devfreq/event/exynos-nocp.c @@ -284,7 +284,7 @@ static void exynos_nocp_remove(struct platform_device *pdev) static struct platform_driver exynos_nocp_driver = { .probe = exynos_nocp_probe, - .remove_new = exynos_nocp_remove, + .remove = exynos_nocp_remove, .driver = { .name = "exynos-nocp", .of_match_table = exynos_nocp_id_match, diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index 7002df20a49eef..88cd4dfe87e127 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -701,7 +701,7 @@ static void exynos_ppmu_remove(struct platform_device *pdev) static struct platform_driver exynos_ppmu_driver = { .probe = exynos_ppmu_probe, - .remove_new = exynos_ppmu_remove, + .remove = exynos_ppmu_remove, .driver = { .name = "exynos-ppmu", .of_match_table = exynos_ppmu_id_match, diff --git a/drivers/devfreq/mtk-cci-devfreq.c b/drivers/devfreq/mtk-cci-devfreq.c index 7ad5225b0381d2..22fe9e631f8aaf 100644 --- a/drivers/devfreq/mtk-cci-devfreq.c +++ b/drivers/devfreq/mtk-cci-devfreq.c @@ -430,7 +430,7 @@ MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines); static struct platform_driver mtk_ccifreq_platdrv = { .probe = mtk_ccifreq_probe, - .remove_new = mtk_ccifreq_remove, + .remove = mtk_ccifreq_remove, .driver = { .name = "mtk-ccifreq", .of_match_table = mtk_ccifreq_machines, diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c index d405cee92c2506..dbdce7636ca5b8 100644 --- a/drivers/devfreq/rk3399_dmc.c +++ b/drivers/devfreq/rk3399_dmc.c @@ -474,7 +474,7 @@ MODULE_DEVICE_TABLE(of, rk3399dmc_devfreq_of_match); static struct platform_driver rk3399_dmcfreq_driver = { .probe = rk3399_dmcfreq_probe, - .remove_new = rk3399_dmcfreq_remove, + .remove = rk3399_dmcfreq_remove, .driver = { .name = "rk3399-dmc-freq", .pm = &rk3399_dmcfreq_pm, diff --git a/drivers/devfreq/sun8i-a33-mbus.c b/drivers/devfreq/sun8i-a33-mbus.c index bcf654f4ff96b8..7c6ae91ede1f56 100644 --- a/drivers/devfreq/sun8i-a33-mbus.c +++ b/drivers/devfreq/sun8i-a33-mbus.c @@ -495,7 +495,7 @@ static SIMPLE_DEV_PM_OPS(sun8i_a33_mbus_pm_ops, static struct platform_driver sun8i_a33_mbus_driver = { .probe = sun8i_a33_mbus_probe, - .remove_new = sun8i_a33_mbus_remove, + .remove = sun8i_a33_mbus_remove, .driver = { .name = "sun8i-a33-mbus", .of_match_table = sun8i_a33_mbus_of_match, diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index b46eb8a552d7be..fee04fdb08220c 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -36,6 +36,7 @@ config UDMABUF depends on DMA_SHARED_BUFFER depends on MEMFD_CREATE || COMPILE_TEST depends on MMU + select VMAP_PFN help A driver to let userspace turn memfd regions into dma-bufs. Qemu can use this to create host dmabufs for guest framebuffers. diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 8892bc701a662d..5baa83b8551565 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -60,7 +60,7 @@ static void __dma_buf_debugfs_list_add(struct dma_buf *dmabuf) { } -static void __dma_buf_debugfs_list_del(struct file *file) +static void __dma_buf_debugfs_list_del(struct dma_buf *dmabuf) { } #endif @@ -176,8 +176,9 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence) dmabuf = file->private_data; /* only support discovering the end of the buffer, - but also allow SEEK_SET to maintain the idiomatic - SEEK_END(0), SEEK_CUR(0) pattern */ + * but also allow SEEK_SET to maintain the idiomatic + * SEEK_END(0), SEEK_CUR(0) pattern. + */ if (whence == SEEK_END) base = dmabuf->size; else if (whence == SEEK_SET) @@ -558,7 +559,7 @@ static struct file *dma_buf_getfile(size_t size, int flags) * Override ->i_ino with the unique and dmabuffs specific * value. */ - inode->i_ino = atomic64_add_return(1, &dmabuf_inode); + inode->i_ino = atomic64_inc_return(&dmabuf_inode); flags &= O_ACCMODE | O_NONBLOCK; file = alloc_file_pseudo(inode, dma_buf_mnt, "dmabuf", flags, &dma_buf_fops); @@ -702,7 +703,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) module_put(exp_info->owner); return ERR_PTR(ret); } -EXPORT_SYMBOL_NS_GPL(dma_buf_export, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_export, "DMA_BUF"); /** * dma_buf_fd - returns a file descriptor for the given struct dma_buf @@ -726,7 +727,7 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags) return fd; } -EXPORT_SYMBOL_NS_GPL(dma_buf_fd, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF"); /** * dma_buf_get - returns the struct dma_buf related to an fd @@ -752,7 +753,7 @@ struct dma_buf *dma_buf_get(int fd) return file->private_data; } -EXPORT_SYMBOL_NS_GPL(dma_buf_get, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_get, "DMA_BUF"); /** * dma_buf_put - decreases refcount of the buffer @@ -771,7 +772,7 @@ void dma_buf_put(struct dma_buf *dmabuf) fput(dmabuf->file); } -EXPORT_SYMBOL_NS_GPL(dma_buf_put, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_put, "DMA_BUF"); static void mangle_sg_table(struct sg_table *sg_table) { @@ -782,13 +783,14 @@ static void mangle_sg_table(struct sg_table *sg_table) /* To catch abuse of the underlying struct page by importers mix * up the bits, but take care to preserve the low SG_ bits to * not corrupt the sgt. The mixing is undone in __unmap_dma_buf - * before passing the sgt back to the exporter. */ + * before passing the sgt back to the exporter. + */ for_each_sgtable_sg(sg_table, sg, i) sg->page_link ^= ~0xffUL; #endif } -static struct sg_table * __map_dma_buf(struct dma_buf_attachment *attach, +static struct sg_table *__map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction direction) { struct sg_table *sg_table; @@ -976,7 +978,7 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev, dma_buf_detach(dmabuf, attach); return ERR_PTR(ret); } -EXPORT_SYMBOL_NS_GPL(dma_buf_dynamic_attach, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_dynamic_attach, "DMA_BUF"); /** * dma_buf_attach - Wrapper for dma_buf_dynamic_attach @@ -991,7 +993,7 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, { return dma_buf_dynamic_attach(dmabuf, dev, NULL, NULL); } -EXPORT_SYMBOL_NS_GPL(dma_buf_attach, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_attach, "DMA_BUF"); static void __unmap_dma_buf(struct dma_buf_attachment *attach, struct sg_table *sg_table, @@ -1035,7 +1037,7 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach) kfree(attach); } -EXPORT_SYMBOL_NS_GPL(dma_buf_detach, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_detach, "DMA_BUF"); /** * dma_buf_pin - Lock down the DMA-buf @@ -1065,7 +1067,7 @@ int dma_buf_pin(struct dma_buf_attachment *attach) return ret; } -EXPORT_SYMBOL_NS_GPL(dma_buf_pin, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_pin, "DMA_BUF"); /** * dma_buf_unpin - Unpin a DMA-buf @@ -1086,7 +1088,7 @@ void dma_buf_unpin(struct dma_buf_attachment *attach) if (dmabuf->ops->unpin) dmabuf->ops->unpin(attach); } -EXPORT_SYMBOL_NS_GPL(dma_buf_unpin, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_unpin, "DMA_BUF"); /** * dma_buf_map_attachment - Returns the scatterlist table of the attachment; @@ -1174,7 +1176,7 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, #endif /* CONFIG_DMA_API_DEBUG */ return sg_table; } -EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment, "DMA_BUF"); /** * dma_buf_map_attachment_unlocked - Returns the scatterlist table of the attachment; @@ -1202,7 +1204,7 @@ dma_buf_map_attachment_unlocked(struct dma_buf_attachment *attach, return sg_table; } -EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment_unlocked, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_map_attachment_unlocked, "DMA_BUF"); /** * dma_buf_unmap_attachment - unmaps and decreases usecount of the buffer;might @@ -1234,7 +1236,7 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, !IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY)) dma_buf_unpin(attach); } -EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment, "DMA_BUF"); /** * dma_buf_unmap_attachment_unlocked - unmaps and decreases usecount of the buffer;might @@ -1259,7 +1261,7 @@ void dma_buf_unmap_attachment_unlocked(struct dma_buf_attachment *attach, dma_buf_unmap_attachment(attach, sg_table, direction); dma_resv_unlock(attach->dmabuf->resv); } -EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment_unlocked, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_unmap_attachment_unlocked, "DMA_BUF"); /** * dma_buf_move_notify - notify attachments that DMA-buf is moving @@ -1279,7 +1281,7 @@ void dma_buf_move_notify(struct dma_buf *dmabuf) if (attach->importer_ops) attach->importer_ops->move_notify(attach); } -EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, "DMA_BUF"); /** * DOC: cpu access @@ -1296,10 +1298,12 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, DMA_BUF); * vmap interface is introduced. Note that on very old 32-bit architectures * vmalloc space might be limited and result in vmap calls failing. * - * Interfaces:: + * Interfaces: * - * void \*dma_buf_vmap(struct dma_buf \*dmabuf, struct iosys_map \*map) - * void dma_buf_vunmap(struct dma_buf \*dmabuf, struct iosys_map \*map) + * .. code-block:: c + * + * void *dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map) + * void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) * * The vmap call can fail if there is no vmap support in the exporter, or if * it runs out of vmalloc space. Note that the dma-buf layer keeps a reference @@ -1356,10 +1360,11 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_move_notify, DMA_BUF); * enough, since adding interfaces to intercept pagefaults and allow pte * shootdowns would increase the complexity quite a bit. * - * Interface:: + * Interface: + * + * .. code-block:: c * - * int dma_buf_mmap(struct dma_buf \*, struct vm_area_struct \*, - * unsigned long); + * int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, unsigned long); * * If the importing subsystem simply provides a special-purpose mmap call to * set up a mapping in userspace, calling do_mmap with &dma_buf.file will @@ -1424,7 +1429,7 @@ int dma_buf_begin_cpu_access(struct dma_buf *dmabuf, return ret; } -EXPORT_SYMBOL_NS_GPL(dma_buf_begin_cpu_access, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_begin_cpu_access, "DMA_BUF"); /** * dma_buf_end_cpu_access - Must be called after accessing a dma_buf from the @@ -1452,7 +1457,7 @@ int dma_buf_end_cpu_access(struct dma_buf *dmabuf, return ret; } -EXPORT_SYMBOL_NS_GPL(dma_buf_end_cpu_access, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_end_cpu_access, "DMA_BUF"); /** @@ -1494,7 +1499,7 @@ int dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma, return dmabuf->ops->mmap(dmabuf, vma); } -EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_mmap, "DMA_BUF"); /** * dma_buf_vmap - Create virtual mapping for the buffer object into kernel @@ -1547,7 +1552,7 @@ int dma_buf_vmap(struct dma_buf *dmabuf, struct iosys_map *map) return 0; } -EXPORT_SYMBOL_NS_GPL(dma_buf_vmap, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_vmap, "DMA_BUF"); /** * dma_buf_vmap_unlocked - Create virtual mapping for the buffer object into kernel @@ -1574,7 +1579,7 @@ int dma_buf_vmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map) return ret; } -EXPORT_SYMBOL_NS_GPL(dma_buf_vmap_unlocked, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_vmap_unlocked, "DMA_BUF"); /** * dma_buf_vunmap - Unmap a vmap obtained by dma_buf_vmap. @@ -1598,7 +1603,7 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, struct iosys_map *map) iosys_map_clear(&dmabuf->vmap_ptr); } } -EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap, "DMA_BUF"); /** * dma_buf_vunmap_unlocked - Unmap a vmap obtained by dma_buf_vmap. @@ -1614,7 +1619,7 @@ void dma_buf_vunmap_unlocked(struct dma_buf *dmabuf, struct iosys_map *map) dma_buf_vunmap(dmabuf, map); dma_resv_unlock(dmabuf->resv); } -EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, DMA_BUF); +EXPORT_SYMBOL_NS_GPL(dma_buf_vunmap_unlocked, "DMA_BUF"); #ifdef CONFIG_DEBUG_FS static int dma_buf_debug_show(struct seq_file *s, void *unused) @@ -1694,7 +1699,7 @@ static int dma_buf_init_debugfs(void) dma_buf_debugfs_dir = d; - d = debugfs_create_file("bufinfo", S_IRUGO, dma_buf_debugfs_dir, + d = debugfs_create_file("bufinfo", 0444, dma_buf_debugfs_dir, NULL, &dma_buf_debug_fops); if (IS_ERR(d)) { pr_debug("dma_buf: debugfs: failed to create node bufinfo\n"); diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index 8a08ffde31e758..6657d4b30af9dc 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c @@ -103,10 +103,36 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence) static bool dma_fence_array_signaled(struct dma_fence *fence) { struct dma_fence_array *array = to_dma_fence_array(fence); + int num_pending; + unsigned int i; - if (atomic_read(&array->num_pending) > 0) + /* + * We need to read num_pending before checking the enable_signal bit + * to avoid racing with the enable_signaling() implementation, which + * might decrement the counter, and cause a partial check. + * atomic_read_acquire() pairs with atomic_dec_and_test() in + * dma_fence_array_enable_signaling() + * + * The !--num_pending check is here to account for the any_signaled case + * if we race with enable_signaling(), that means the !num_pending check + * in the is_signalling_enabled branch might be outdated (num_pending + * might have been decremented), but that's fine. The user will get the + * right value when testing again later. + */ + num_pending = atomic_read_acquire(&array->num_pending); + if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &array->base.flags)) { + if (num_pending <= 0) + goto signal; return false; + } + + for (i = 0; i < array->num_fences; ++i) { + if (dma_fence_is_signaled(array->fences[i]) && !--num_pending) + goto signal; + } + return false; +signal: dma_fence_array_clear_pending_error(array); return true; } diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c index 628af51c81af3d..6345062731f153 100644 --- a/drivers/dma-buf/dma-fence-unwrap.c +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -12,6 +12,7 @@ #include #include #include +#include /* Internal helper to start new array iteration, don't use directly */ static struct dma_fence * @@ -59,6 +60,25 @@ struct dma_fence *dma_fence_unwrap_next(struct dma_fence_unwrap *cursor) } EXPORT_SYMBOL_GPL(dma_fence_unwrap_next); + +static int fence_cmp(const void *_a, const void *_b) +{ + struct dma_fence *a = *(struct dma_fence **)_a; + struct dma_fence *b = *(struct dma_fence **)_b; + + if (a->context < b->context) + return -1; + else if (a->context > b->context) + return 1; + + if (dma_fence_is_later(b, a)) + return 1; + else if (dma_fence_is_later(a, b)) + return -1; + + return 0; +} + /* Implementation for the dma_fence_merge() marco, don't use directly */ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, struct dma_fence **fences, @@ -67,8 +87,7 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, struct dma_fence_array *result; struct dma_fence *tmp, **array; ktime_t timestamp; - unsigned int i; - size_t count; + int i, j, count; count = 0; timestamp = ns_to_ktime(0); @@ -96,78 +115,55 @@ struct dma_fence *__dma_fence_unwrap_merge(unsigned int num_fences, if (!array) return NULL; - /* - * This trashes the input fence array and uses it as position for the - * following merge loop. This works because the dma_fence_merge() - * wrapper macro is creating this temporary array on the stack together - * with the iterators. - */ - for (i = 0; i < num_fences; ++i) - fences[i] = dma_fence_unwrap_first(fences[i], &iter[i]); - count = 0; - do { - unsigned int sel; - -restart: - tmp = NULL; - for (i = 0; i < num_fences; ++i) { - struct dma_fence *next; - - while (fences[i] && dma_fence_is_signaled(fences[i])) - fences[i] = dma_fence_unwrap_next(&iter[i]); - - next = fences[i]; - if (!next) - continue; - - /* - * We can't guarantee that inpute fences are ordered by - * context, but it is still quite likely when this - * function is used multiple times. So attempt to order - * the fences by context as we pass over them and merge - * fences with the same context. - */ - if (!tmp || tmp->context > next->context) { - tmp = next; - sel = i; - - } else if (tmp->context < next->context) { - continue; - - } else if (dma_fence_is_later(tmp, next)) { - fences[i] = dma_fence_unwrap_next(&iter[i]); - goto restart; + for (i = 0; i < num_fences; ++i) { + dma_fence_unwrap_for_each(tmp, &iter[i], fences[i]) { + if (!dma_fence_is_signaled(tmp)) { + array[count++] = dma_fence_get(tmp); } else { - fences[sel] = dma_fence_unwrap_next(&iter[sel]); - goto restart; + ktime_t t = dma_fence_timestamp(tmp); + + if (ktime_after(t, timestamp)) + timestamp = t; } } + } - if (tmp) { - array[count++] = dma_fence_get(tmp); - fences[sel] = dma_fence_unwrap_next(&iter[sel]); - } - } while (tmp); + if (count == 0 || count == 1) + goto return_fastpath; - if (count == 0) { - tmp = dma_fence_allocate_private_stub(ktime_get()); - goto return_tmp; - } + sort(array, count, sizeof(*array), fence_cmp, NULL); - if (count == 1) { - tmp = array[0]; - goto return_tmp; + /* + * Only keep the most recent fence for each context. + */ + j = 0; + for (i = 1; i < count; i++) { + if (array[i]->context == array[j]->context) + dma_fence_put(array[i]); + else + array[++j] = array[i]; } - - result = dma_fence_array_create(count, array, - dma_fence_context_alloc(1), - 1, false); - if (!result) { - tmp = NULL; - goto return_tmp; + count = ++j; + + if (count > 1) { + result = dma_fence_array_create(count, array, + dma_fence_context_alloc(1), + 1, false); + if (!result) { + for (i = 0; i < count; i++) + dma_fence_put(array[i]); + tmp = NULL; + goto return_tmp; + } + return &result->base; } - return &result->base; + +return_fastpath: + if (count == 0) + tmp = dma_fence_allocate_private_stub(timestamp); + else + tmp = array[0]; return_tmp: kfree(array); diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 0393a9bba3a8a9..f0cdd3e99d369c 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -309,8 +309,8 @@ bool dma_fence_begin_signalling(void) if (in_atomic()) return true; - /* ... and non-recursive readlock */ - lock_acquire(&dma_fence_lockdep_map, 0, 0, 1, 1, NULL, _RET_IP_); + /* ... and non-recursive successful read_trylock */ + lock_acquire(&dma_fence_lockdep_map, 0, 1, 1, 1, NULL, _RET_IP_); return false; } @@ -341,7 +341,7 @@ void __dma_fence_might_wait(void) lock_map_acquire(&dma_fence_lockdep_map); lock_map_release(&dma_fence_lockdep_map); if (tmp) - lock_acquire(&dma_fence_lockdep_map, 0, 0, 1, 1, NULL, _THIS_IP_); + lock_acquire(&dma_fence_lockdep_map, 0, 1, 1, 1, NULL, _THIS_IP_); } #endif @@ -412,7 +412,7 @@ int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp) unsigned long flags; int ret; - if (!fence) + if (WARN_ON(!fence)) return -EINVAL; spin_lock_irqsave(fence->lock, flags); @@ -464,7 +464,7 @@ int dma_fence_signal(struct dma_fence *fence) int ret; bool tmp; - if (!fence) + if (WARN_ON(!fence)) return -EINVAL; tmp = dma_fence_begin_signalling(); diff --git a/drivers/dma-buf/heaps/cma_heap.c b/drivers/dma-buf/heaps/cma_heap.c index 93be88b805fe78..9512d050563a9a 100644 --- a/drivers/dma-buf/heaps/cma_heap.c +++ b/drivers/dma-buf/heaps/cma_heap.c @@ -309,13 +309,13 @@ static struct dma_buf *cma_heap_allocate(struct dma_heap *heap, struct page *page = cma_pages; while (nr_clear_pages > 0) { - void *vaddr = kmap_atomic(page); + void *vaddr = kmap_local_page(page); memset(vaddr, 0, PAGE_SIZE); - kunmap_atomic(vaddr); + kunmap_local(vaddr); /* * Avoid wasting time zeroing memory if the process - * has been killed by by SIGKILL + * has been killed by SIGKILL. */ if (fatal_signal_pending(current)) goto free_cma; @@ -366,7 +366,7 @@ static const struct dma_heap_ops cma_heap_ops = { .allocate = cma_heap_allocate, }; -static int __add_cma_heap(struct cma *cma, void *data) +static int __init __add_cma_heap(struct cma *cma, void *data) { struct cma_heap *cma_heap; struct dma_heap_export_info exp_info; @@ -391,7 +391,7 @@ static int __add_cma_heap(struct cma *cma, void *data) return 0; } -static int add_default_cma_heap(void) +static int __init add_default_cma_heap(void) { struct cma *default_cma = dev_get_cma_area(NULL); int ret = 0; diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c index d78cdb9d01e5e4..26d5dc89ea1663 100644 --- a/drivers/dma-buf/heaps/system_heap.c +++ b/drivers/dma-buf/heaps/system_heap.c @@ -421,7 +421,7 @@ static const struct dma_heap_ops system_heap_ops = { .allocate = system_heap_allocate, }; -static int system_heap_create(void) +static int __init system_heap_create(void) { struct dma_heap_export_info exp_info; diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index c353029789cf1a..f5905d67dedbbb 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -173,11 +173,6 @@ static bool timeline_fence_signaled(struct dma_fence *fence) return !__dma_fence_is_later(fence->seqno, parent->value, fence->ops); } -static bool timeline_fence_enable_signaling(struct dma_fence *fence) -{ - return true; -} - static void timeline_fence_value_str(struct dma_fence *fence, char *str, int size) { @@ -211,7 +206,6 @@ static void timeline_fence_set_deadline(struct dma_fence *fence, ktime_t deadlin static const struct dma_fence_ops timeline_fence_ops = { .get_driver_name = timeline_fence_get_driver_name, .get_timeline_name = timeline_fence_get_timeline_name, - .enable_signaling = timeline_fence_enable_signaling, .signaled = timeline_fence_signaled, .release = timeline_fence_release, .fence_value_str = timeline_fence_value_str, diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 047c3cd2cefff6..cc7398cc17d67f 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -27,15 +27,21 @@ MODULE_PARM_DESC(size_limit_mb, "Max size of a dmabuf, in megabytes. Default is struct udmabuf { pgoff_t pagecount; struct folio **folios; + + /** + * Unlike folios, pinned_folios is only used for unpin. + * So, nr_pinned is not the same to pagecount, the pinned_folios + * only set each folio which already pinned when udmabuf_create. + * Note that, since a folio may be pinned multiple times, each folio + * can be added to pinned_folios multiple times, depending on how many + * times the folio has been pinned when create. + */ + pgoff_t nr_pinned; + struct folio **pinned_folios; + struct sg_table *sg; struct miscdevice *device; pgoff_t *offsets; - struct list_head unpin_list; -}; - -struct udmabuf_folio { - struct folio *folio; - struct list_head list; }; static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) @@ -43,7 +49,8 @@ static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) struct vm_area_struct *vma = vmf->vma; struct udmabuf *ubuf = vma->vm_private_data; pgoff_t pgoff = vmf->pgoff; - unsigned long pfn; + unsigned long addr, pfn; + vm_fault_t ret; if (pgoff >= ubuf->pagecount) return VM_FAULT_SIGBUS; @@ -51,7 +58,35 @@ static vm_fault_t udmabuf_vm_fault(struct vm_fault *vmf) pfn = folio_pfn(ubuf->folios[pgoff]); pfn += ubuf->offsets[pgoff] >> PAGE_SHIFT; - return vmf_insert_pfn(vma, vmf->address, pfn); + ret = vmf_insert_pfn(vma, vmf->address, pfn); + if (ret & VM_FAULT_ERROR) + return ret; + + /* pre fault */ + pgoff = vma->vm_pgoff; + addr = vma->vm_start; + + for (; addr < vma->vm_end; pgoff++, addr += PAGE_SIZE) { + if (addr == vmf->address) + continue; + + if (WARN_ON(pgoff >= ubuf->pagecount)) + break; + + pfn = folio_pfn(ubuf->folios[pgoff]); + pfn += ubuf->offsets[pgoff] >> PAGE_SHIFT; + + /** + * If the below vmf_insert_pfn() fails, we do not return an + * error here during this pre-fault step. However, an error + * will be returned if the failure occurs when the addr is + * truly accessed. + */ + if (vmf_insert_pfn(vma, addr, pfn) & VM_FAULT_ERROR) + break; + } + + return ret; } static const struct vm_operations_struct udmabuf_vm_ops = { @@ -74,21 +109,29 @@ static int mmap_udmabuf(struct dma_buf *buf, struct vm_area_struct *vma) static int vmap_udmabuf(struct dma_buf *buf, struct iosys_map *map) { struct udmabuf *ubuf = buf->priv; - struct page **pages; + unsigned long *pfns; void *vaddr; pgoff_t pg; dma_resv_assert_held(buf->resv); - pages = kmalloc_array(ubuf->pagecount, sizeof(*pages), GFP_KERNEL); - if (!pages) + /** + * HVO may free tail pages, so just use pfn to map each folio + * into vmalloc area. + */ + pfns = kvmalloc_array(ubuf->pagecount, sizeof(*pfns), GFP_KERNEL); + if (!pfns) return -ENOMEM; - for (pg = 0; pg < ubuf->pagecount; pg++) - pages[pg] = &ubuf->folios[pg]->page; + for (pg = 0; pg < ubuf->pagecount; pg++) { + unsigned long pfn = folio_pfn(ubuf->folios[pg]); + + pfn += ubuf->offsets[pg] >> PAGE_SHIFT; + pfns[pg] = pfn; + } - vaddr = vm_map_ram(pages, ubuf->pagecount, -1); - kfree(pages); + vaddr = vmap_pfn(pfns, ubuf->pagecount, PAGE_KERNEL); + kvfree(pfns); if (!vaddr) return -EINVAL; @@ -159,34 +202,42 @@ static void unmap_udmabuf(struct dma_buf_attachment *at, return put_sg_table(at->dev, sg, direction); } -static void unpin_all_folios(struct list_head *unpin_list) +static void unpin_all_folios(struct udmabuf *ubuf) { - struct udmabuf_folio *ubuf_folio; + pgoff_t i; - while (!list_empty(unpin_list)) { - ubuf_folio = list_first_entry(unpin_list, - struct udmabuf_folio, list); - unpin_folio(ubuf_folio->folio); + for (i = 0; i < ubuf->nr_pinned; ++i) + unpin_folio(ubuf->pinned_folios[i]); - list_del(&ubuf_folio->list); - kfree(ubuf_folio); - } + kvfree(ubuf->pinned_folios); } -static int add_to_unpin_list(struct list_head *unpin_list, - struct folio *folio) +static __always_inline int init_udmabuf(struct udmabuf *ubuf, pgoff_t pgcnt) { - struct udmabuf_folio *ubuf_folio; + ubuf->folios = kvmalloc_array(pgcnt, sizeof(*ubuf->folios), GFP_KERNEL); + if (!ubuf->folios) + return -ENOMEM; + + ubuf->offsets = kvcalloc(pgcnt, sizeof(*ubuf->offsets), GFP_KERNEL); + if (!ubuf->offsets) + return -ENOMEM; - ubuf_folio = kzalloc(sizeof(*ubuf_folio), GFP_KERNEL); - if (!ubuf_folio) + ubuf->pinned_folios = kvmalloc_array(pgcnt, + sizeof(*ubuf->pinned_folios), + GFP_KERNEL); + if (!ubuf->pinned_folios) return -ENOMEM; - ubuf_folio->folio = folio; - list_add_tail(&ubuf_folio->list, unpin_list); return 0; } +static __always_inline void deinit_udmabuf(struct udmabuf *ubuf) +{ + unpin_all_folios(ubuf); + kvfree(ubuf->offsets); + kvfree(ubuf->folios); +} + static void release_udmabuf(struct dma_buf *buf) { struct udmabuf *ubuf = buf->priv; @@ -195,9 +246,7 @@ static void release_udmabuf(struct dma_buf *buf) if (ubuf->sg) put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL); - unpin_all_folios(&ubuf->unpin_list); - kfree(ubuf->offsets); - kfree(ubuf->folios); + deinit_udmabuf(ubuf); kfree(ubuf); } @@ -248,15 +297,12 @@ static const struct dma_buf_ops udmabuf_ops = { }; #define SEALS_WANTED (F_SEAL_SHRINK) -#define SEALS_DENIED (F_SEAL_WRITE) +#define SEALS_DENIED (F_SEAL_WRITE|F_SEAL_FUTURE_WRITE) static int check_memfd_seals(struct file *memfd) { int seals; - if (!memfd) - return -EBADFD; - if (!shmem_file(memfd) && !is_file_hugepages(memfd)) return -EBADFD; @@ -271,12 +317,10 @@ static int check_memfd_seals(struct file *memfd) return 0; } -static int export_udmabuf(struct udmabuf *ubuf, - struct miscdevice *device, - u32 flags) +static struct dma_buf *export_udmabuf(struct udmabuf *ubuf, + struct miscdevice *device) { DEFINE_DMA_BUF_EXPORT_INFO(exp_info); - struct dma_buf *buf; ubuf->device = device; exp_info.ops = &udmabuf_ops; @@ -284,123 +328,151 @@ static int export_udmabuf(struct udmabuf *ubuf, exp_info.priv = ubuf; exp_info.flags = O_RDWR; - buf = dma_buf_export(&exp_info); - if (IS_ERR(buf)) - return PTR_ERR(buf); + return dma_buf_export(&exp_info); +} + +static long udmabuf_pin_folios(struct udmabuf *ubuf, struct file *memfd, + loff_t start, loff_t size, struct folio **folios) +{ + pgoff_t nr_pinned = ubuf->nr_pinned; + pgoff_t upgcnt = ubuf->pagecount; + u32 cur_folio, cur_pgcnt; + pgoff_t pgoff, pgcnt; + long nr_folios; + loff_t end; + + pgcnt = size >> PAGE_SHIFT; + end = start + (pgcnt << PAGE_SHIFT) - 1; + nr_folios = memfd_pin_folios(memfd, start, end, folios, pgcnt, &pgoff); + if (nr_folios <= 0) + return nr_folios ? nr_folios : -EINVAL; + + cur_pgcnt = 0; + for (cur_folio = 0; cur_folio < nr_folios; ++cur_folio) { + pgoff_t subpgoff = pgoff; + size_t fsize = folio_size(folios[cur_folio]); + + ubuf->pinned_folios[nr_pinned++] = folios[cur_folio]; - return dma_buf_fd(buf, flags); + for (; subpgoff < fsize; subpgoff += PAGE_SIZE) { + ubuf->folios[upgcnt] = folios[cur_folio]; + ubuf->offsets[upgcnt] = subpgoff; + ++upgcnt; + + if (++cur_pgcnt >= pgcnt) + goto end; + } + + /** + * In a given range, only the first subpage of the first folio + * has an offset, that is returned by memfd_pin_folios(). + * The first subpages of other folios (in the range) have an + * offset of 0. + */ + pgoff = 0; + } +end: + ubuf->pagecount = upgcnt; + ubuf->nr_pinned = nr_pinned; + return 0; } static long udmabuf_create(struct miscdevice *device, struct udmabuf_create_list *head, struct udmabuf_create_item *list) { - pgoff_t pgoff, pgcnt, pglimit, pgbuf = 0; - long nr_folios, ret = -EINVAL; - struct file *memfd = NULL; - struct folio **folios; + unsigned long max_nr_folios = 0; + struct folio **folios = NULL; + pgoff_t pgcnt = 0, pglimit; struct udmabuf *ubuf; - u32 i, j, k, flags; - loff_t end; + struct dma_buf *dmabuf; + long ret = -EINVAL; + u32 i, flags; ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL); if (!ubuf) return -ENOMEM; - INIT_LIST_HEAD(&ubuf->unpin_list); pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; for (i = 0; i < head->count; i++) { - if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) - goto err; - if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) - goto err; - ubuf->pagecount += list[i].size >> PAGE_SHIFT; - if (ubuf->pagecount > pglimit) - goto err; + pgoff_t subpgcnt; + + if (!PAGE_ALIGNED(list[i].offset)) + goto err_noinit; + if (!PAGE_ALIGNED(list[i].size)) + goto err_noinit; + + subpgcnt = list[i].size >> PAGE_SHIFT; + pgcnt += subpgcnt; + if (pgcnt > pglimit) + goto err_noinit; + + max_nr_folios = max_t(unsigned long, subpgcnt, max_nr_folios); } - if (!ubuf->pagecount) - goto err; + if (!pgcnt) + goto err_noinit; - ubuf->folios = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->folios), - GFP_KERNEL); - if (!ubuf->folios) { - ret = -ENOMEM; + ret = init_udmabuf(ubuf, pgcnt); + if (ret) goto err; - } - ubuf->offsets = kcalloc(ubuf->pagecount, sizeof(*ubuf->offsets), - GFP_KERNEL); - if (!ubuf->offsets) { + + folios = kvmalloc_array(max_nr_folios, sizeof(*folios), GFP_KERNEL); + if (!folios) { ret = -ENOMEM; goto err; } - pgbuf = 0; for (i = 0; i < head->count; i++) { - memfd = fget(list[i].memfd); - ret = check_memfd_seals(memfd); - if (ret < 0) - goto err; + struct file *memfd = fget(list[i].memfd); - pgcnt = list[i].size >> PAGE_SHIFT; - folios = kmalloc_array(pgcnt, sizeof(*folios), GFP_KERNEL); - if (!folios) { - ret = -ENOMEM; + if (!memfd) { + ret = -EBADFD; goto err; } - end = list[i].offset + (pgcnt << PAGE_SHIFT) - 1; - ret = memfd_pin_folios(memfd, list[i].offset, end, - folios, pgcnt, &pgoff); - if (ret <= 0) { - kfree(folios); - if (!ret) - ret = -EINVAL; - goto err; - } - - nr_folios = ret; - pgoff >>= PAGE_SHIFT; - for (j = 0, k = 0; j < pgcnt; j++) { - ubuf->folios[pgbuf] = folios[k]; - ubuf->offsets[pgbuf] = pgoff << PAGE_SHIFT; - - if (j == 0 || ubuf->folios[pgbuf-1] != folios[k]) { - ret = add_to_unpin_list(&ubuf->unpin_list, - folios[k]); - if (ret < 0) { - kfree(folios); - goto err; - } - } - - pgbuf++; - if (++pgoff == folio_nr_pages(folios[k])) { - pgoff = 0; - if (++k == nr_folios) - break; - } - } + /* + * Take the inode lock to protect against concurrent + * memfd_add_seals(), which takes this lock in write mode. + */ + inode_lock_shared(file_inode(memfd)); + ret = check_memfd_seals(memfd); + if (ret) + goto out_unlock; - kfree(folios); + ret = udmabuf_pin_folios(ubuf, memfd, list[i].offset, + list[i].size, folios); +out_unlock: + inode_unlock_shared(file_inode(memfd)); fput(memfd); - memfd = NULL; + if (ret) + goto err; } flags = head->flags & UDMABUF_FLAGS_CLOEXEC ? O_CLOEXEC : 0; - ret = export_udmabuf(ubuf, device, flags); - if (ret < 0) + dmabuf = export_udmabuf(ubuf, device); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); goto err; + } + /* + * Ownership of ubuf is held by the dmabuf from here. + * If the following dma_buf_fd() fails, dma_buf_put() cleans up both the + * dmabuf and the ubuf (through udmabuf_ops.release). + */ + ret = dma_buf_fd(dmabuf, flags); + if (ret < 0) + dma_buf_put(dmabuf); + + kvfree(folios); return ret; err: - if (memfd) - fput(memfd); - unpin_all_folios(&ubuf->unpin_list); - kfree(ubuf->offsets); - kfree(ubuf->folios); + deinit_udmabuf(ubuf); +err_noinit: kfree(ubuf); + kvfree(folios); return ret; } diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d9ec1e69e42831..e994d6e0779e02 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -378,6 +378,20 @@ config LOONGSON1_APB_DMA This selects support for the APB DMA controller in Loongson1 SoCs, which is required by Loongson1 NAND and audio support. +config LOONGSON2_APB_DMA + tristate "Loongson2 APB DMA support" + depends on LOONGARCH || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support for the Loongson2 APB DMA controller driver. The + DMA controller is having single DMA channel which can be + configured for different peripherals like audio, nand, sdio + etc which is in APB bus. + + This DMA controller transfers data from memory to peripheral fifo. + It does not support memory to memory data transfer. + config LPC18XX_DMAMUX bool "NXP LPC18xx/43xx DMA MUX for PL080" depends on ARCH_LPC18XX || COMPILE_TEST @@ -396,20 +410,6 @@ config LPC32XX_DMAMUX Support for PL080 multiplexed DMA request lines on LPC32XX platrofm. -config LS2X_APB_DMA - tristate "Loongson LS2X APB DMA support" - depends on LOONGARCH || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support for the Loongson LS2X APB DMA controller driver. The - DMA controller is having single DMA channel which can be - configured for different peripherals like audio, nand, sdio - etc which is in APB bus. - - This DMA controller transfers data from memory to peripheral fifo. - It does not support memory to memory data transfer. - config MCF_EDMA tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs" depends on M5441x || (COMPILE_TEST && FSL_EDMA=n) diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index ad6a03c052ec4a..5b2a52f4f2ee99 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -50,9 +50,9 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioat/ obj-y += idxd/ obj-$(CONFIG_K3_DMA) += k3dma.o obj-$(CONFIG_LOONGSON1_APB_DMA) += loongson1-apb-dma.o +obj-$(CONFIG_LOONGSON2_APB_DMA) += loongson2-apb-dma.o obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o obj-$(CONFIG_LPC32XX_DMAMUX) += lpc32xx-dmamux.o -obj-$(CONFIG_LS2X_APB_DMA) += ls2x-apb-dma.o obj-$(CONFIG_MILBEAUT_HDMAC) += milbeaut-hdmac.o obj-$(CONFIG_MILBEAUT_XDMAC) += milbeaut-xdmac.o obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c index a58a1600dd6590..2abbe11e797e9d 100644 --- a/drivers/dma/acpi-dma.c +++ b/drivers/dma/acpi-dma.c @@ -9,18 +9,21 @@ * Mika Westerberg */ +#include +#include #include #include #include -#include +#include +#include +#include #include #include #include -#include -#include -#include -#include #include +#include +#include +#include static LIST_HEAD(acpi_dma_list); static DEFINE_MUTEX(acpi_dma_lock); @@ -236,7 +239,7 @@ int acpi_dma_controller_free(struct device *dev) } EXPORT_SYMBOL_GPL(acpi_dma_controller_free); -static void devm_acpi_dma_release(struct device *dev, void *res) +static void devm_acpi_dma_free(void *dev) { acpi_dma_controller_free(dev); } @@ -259,37 +262,15 @@ int devm_acpi_dma_controller_register(struct device *dev, (struct acpi_dma_spec *, struct acpi_dma *), void *data) { - void *res; int ret; - res = devres_alloc(devm_acpi_dma_release, 0, GFP_KERNEL); - if (!res) - return -ENOMEM; - ret = acpi_dma_controller_register(dev, acpi_dma_xlate, data); - if (ret) { - devres_free(res); + if (ret) return ret; - } - devres_add(dev, res); - return 0; -} -EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register); -/** - * devm_acpi_dma_controller_free - resource managed acpi_dma_controller_free() - * @dev: device that is unregistering as DMA controller - * - * Unregister a DMA controller registered with - * devm_acpi_dma_controller_register(). Normally this function will not need to - * be called and the resource management code will ensure that the resource is - * freed. - */ -void devm_acpi_dma_controller_free(struct device *dev) -{ - WARN_ON(devres_release(dev, devm_acpi_dma_release, NULL, NULL)); + return devm_add_action_or_reset(dev, devm_acpi_dma_free, dev); } -EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free); +EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register); /** * acpi_dma_update_dma_spec - prepare dma specifier to pass to translation function diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c index e6a6566b309ee4..a203fdd84950ef 100644 --- a/drivers/dma/altera-msgdma.c +++ b/drivers/dma/altera-msgdma.c @@ -954,7 +954,7 @@ static struct platform_driver msgdma_driver = { .of_match_table = of_match_ptr(msgdma_match), }, .probe = msgdma_probe, - .remove_new = msgdma_remove, + .remove = msgdma_remove, }; module_platform_driver(msgdma_driver); diff --git a/drivers/dma/amd/qdma/qdma.c b/drivers/dma/amd/qdma/qdma.c index b0a1f3ad851b1e..6d9079458fe9cc 100644 --- a/drivers/dma/amd/qdma/qdma.c +++ b/drivers/dma/amd/qdma/qdma.c @@ -1133,7 +1133,7 @@ static struct platform_driver amd_qdma_driver = { .name = "amd-qdma", }, .probe = amd_qdma_probe, - .remove_new = amd_qdma_remove, + .remove = amd_qdma_remove, }; module_platform_driver(amd_qdma_driver); diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index 9588773dd2eb67..c499173d80b20f 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -950,7 +950,7 @@ static struct platform_driver apple_admac_driver = { .of_match_table = admac_of_match, }, .probe = admac_probe, - .remove_new = admac_remove, + .remove = admac_remove, }; module_platform_driver(apple_admac_driver); diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index baebddc740b0d4..2d147712cbc69b 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -2250,7 +2250,7 @@ static const struct dev_pm_ops __maybe_unused at_dma_dev_pm_ops = { }; static struct platform_driver at_dma_driver = { - .remove_new = at_dma_remove, + .remove = at_dma_remove, .shutdown = at_dma_shutdown, .id_table = atdma_devtypes, .driver = { diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 299396121e6dc5..9c7b402200040f 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -2476,7 +2476,7 @@ MODULE_DEVICE_TABLE(of, atmel_xdmac_dt_ids); static struct platform_driver at_xdmac_driver = { .probe = at_xdmac_probe, - .remove_new = at_xdmac_remove, + .remove = at_xdmac_remove, .driver = { .name = "at_xdmac", .of_match_table = of_match_ptr(atmel_xdmac_dt_ids), diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index cfa6e1167a1fd1..7f0e76439ce58e 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -1756,7 +1756,7 @@ MODULE_DEVICE_TABLE(of, sba_of_match); static struct platform_driver sba_driver = { .probe = sba_probe, - .remove_new = sba_remove, + .remove = sba_remove, .driver = { .name = "bcm-sba-raid", .of_match_table = sba_of_match, diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index e1b92b4d7b056e..7ba52dee40a967 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -1029,7 +1029,7 @@ static void bcm2835_dma_remove(struct platform_device *pdev) static struct platform_driver bcm2835_dma_driver = { .probe = bcm2835_dma_probe, - .remove_new = bcm2835_dma_remove, + .remove = bcm2835_dma_remove, .driver = { .name = "bcm2835-dma", .of_match_table = of_match_ptr(bcm2835_dma_of_match), diff --git a/drivers/dma/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c index 0bbaa7620bdd4b..6c4d655ffe77fa 100644 --- a/drivers/dma/bestcomm/bestcomm.c +++ b/drivers/dma/bestcomm/bestcomm.c @@ -486,7 +486,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match); static struct platform_driver mpc52xx_bcom_of_platform_driver = { .probe = mpc52xx_bcom_probe, - .remove_new = mpc52xx_bcom_remove, + .remove = mpc52xx_bcom_remove, .driver = { .name = DRIVER_NAME, .of_match_table = mpc52xx_bcom_of_match, diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index c9cfa341db5103..100057603fd4e1 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -1122,7 +1122,7 @@ MODULE_DEVICE_TABLE(of, jz4780_dma_dt_match); static struct platform_driver jz4780_dma_driver = { .probe = jz4780_dma_probe, - .remove_new = jz4780_dma_remove, + .remove = jz4780_dma_remove, .driver = { .name = "jz4780-dma", .of_match_table = jz4780_dma_dt_match, 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 fffafa86d964e0..b23536645ff7cc 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -1676,7 +1676,7 @@ MODULE_DEVICE_TABLE(of, dw_dma_of_id_table); static struct platform_driver dw_driver = { .probe = dw_probe, - .remove_new = dw_remove, + .remove = dw_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = dw_dma_of_id_table, diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 47c58ad468cbca..2606cf9cd42994 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -191,7 +191,7 @@ static const struct dev_pm_ops dw_dev_pm_ops = { static struct platform_driver dw_driver = { .probe = dw_probe, - .remove_new = dw_remove, + .remove = dw_remove, .shutdown = dw_shutdown, .driver = { .name = DRV_NAME, diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index 6b98a23e333248..e424bb5c40e79c 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -929,8 +929,7 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan) /* Sanity check the channel parameters */ if (!edmac->edma->m2m) { - if (edmac->dma_cfg.port < EP93XX_DMA_I2S1 || - edmac->dma_cfg.port > EP93XX_DMA_IRDA) + if (edmac->dma_cfg.port > EP93XX_DMA_IRDA) return -EINVAL; if (edmac->dma_cfg.dir != ep93xx_dma_chan_direction(chan)) return -EINVAL; diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index f9f1eda792546e..60de1003193aa3 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -740,7 +740,7 @@ static struct platform_driver fsl_edma_driver = { .pm = &fsl_edma_pm_ops, }, .probe = fsl_edma_probe, - .remove_new = fsl_edma_remove, + .remove = fsl_edma_remove, }; static int __init fsl_edma_init(void) diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index 5005e138fc239b..823f5c6bc2e1a5 100644 --- a/drivers/dma/fsl-qdma.c +++ b/drivers/dma/fsl-qdma.c @@ -1288,7 +1288,7 @@ static struct platform_driver fsl_qdma_driver = { .of_match_table = fsl_qdma_dt_ids, }, .probe = fsl_qdma_probe, - .remove_new = fsl_qdma_remove, + .remove = fsl_qdma_remove, }; module_platform_driver(fsl_qdma_driver); diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c index 014ff523d5ec90..6aa97e258a557c 100644 --- a/drivers/dma/fsl_raid.c +++ b/drivers/dma/fsl_raid.c @@ -886,7 +886,7 @@ static struct platform_driver fsl_re_driver = { .of_match_table = fsl_re_ids, }, .probe = fsl_re_probe, - .remove_new = fsl_re_remove, + .remove = fsl_re_remove, }; module_platform_driver(fsl_re_driver); diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 18a6c4bf6275c4..b5e7d18b976694 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -1404,7 +1404,7 @@ static struct platform_driver fsldma_of_driver = { #endif }, .probe = fsldma_of_probe, - .remove_new = fsldma_of_remove, + .remove = fsldma_of_remove, }; /*----------------------------------------------------------------------------*/ diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c index 3c648308a54a38..d147353d47ab70 100644 --- a/drivers/dma/idma64.c +++ b/drivers/dma/idma64.c @@ -693,7 +693,7 @@ static const struct dev_pm_ops idma64_dev_pm_ops = { static struct platform_driver idma64_platform_driver = { .probe = idma64_platform_probe, - .remove_new = idma64_platform_remove, + .remove = idma64_platform_remove, .driver = { .name = LPSS_IDMA64_DRIVER_NAME, .pm = &idma64_dev_pm_ops, diff --git a/drivers/dma/idxd/Makefile b/drivers/dma/idxd/Makefile index 2b4a0d406e1e71..9ff9d7b87b649d 100644 --- a/drivers/dma/idxd/Makefile +++ b/drivers/dma/idxd/Makefile @@ -1,4 +1,4 @@ -ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=IDXD +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"IDXD"' obj-$(CONFIG_INTEL_IDXD_BUS) += idxd_bus.o idxd_bus-y := bus.o diff --git a/drivers/dma/idxd/compat.c b/drivers/dma/idxd/compat.c index a4adb0c179959f..eff9943f1a42e2 100644 --- a/drivers/dma/idxd/compat.c +++ b/drivers/dma/idxd/compat.c @@ -103,4 +103,4 @@ struct idxd_device_driver dsa_drv = { }; module_idxd_driver(dsa_drv); -MODULE_IMPORT_NS(IDXD); +MODULE_IMPORT_NS("IDXD"); diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index c41ef195eeb9f2..5cf419fe6b4645 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -161,7 +161,7 @@ int idxd_wq_alloc_resources(struct idxd_wq *wq) free_hw_descs(wq); return rc; } -EXPORT_SYMBOL_NS_GPL(idxd_wq_alloc_resources, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_wq_alloc_resources, "IDXD"); void idxd_wq_free_resources(struct idxd_wq *wq) { @@ -175,7 +175,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq) dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr); sbitmap_queue_free(&wq->sbq); } -EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, "IDXD"); int idxd_wq_enable(struct idxd_wq *wq) { @@ -407,7 +407,7 @@ int idxd_wq_init_percpu_ref(struct idxd_wq *wq) reinit_completion(&wq->wq_resurrect); return 0; } -EXPORT_SYMBOL_NS_GPL(idxd_wq_init_percpu_ref, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_wq_init_percpu_ref, "IDXD"); void __idxd_wq_quiesce(struct idxd_wq *wq) { @@ -417,7 +417,7 @@ void __idxd_wq_quiesce(struct idxd_wq *wq) complete_all(&wq->wq_resurrect); wait_for_completion(&wq->wq_dead); } -EXPORT_SYMBOL_NS_GPL(__idxd_wq_quiesce, IDXD); +EXPORT_SYMBOL_NS_GPL(__idxd_wq_quiesce, "IDXD"); void idxd_wq_quiesce(struct idxd_wq *wq) { @@ -425,7 +425,7 @@ void idxd_wq_quiesce(struct idxd_wq *wq) __idxd_wq_quiesce(wq); mutex_unlock(&wq->wq_lock); } -EXPORT_SYMBOL_NS_GPL(idxd_wq_quiesce, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_wq_quiesce, "IDXD"); /* Device control bits */ static inline bool idxd_is_enabled(struct idxd_device *idxd) @@ -1494,7 +1494,7 @@ int idxd_drv_enable_wq(struct idxd_wq *wq) err: return rc; } -EXPORT_SYMBOL_NS_GPL(idxd_drv_enable_wq, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_drv_enable_wq, "IDXD"); void idxd_drv_disable_wq(struct idxd_wq *wq) { @@ -1516,7 +1516,7 @@ void idxd_drv_disable_wq(struct idxd_wq *wq) wq->type = IDXD_WQT_NONE; wq->client_count = 0; } -EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, "IDXD"); int idxd_device_drv_probe(struct idxd_dev *idxd_dev) { diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 234c1c658ec792..140f8d772bee13 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -25,7 +25,7 @@ MODULE_VERSION(IDXD_DRIVER_VERSION); MODULE_DESCRIPTION("Intel Data Streaming Accelerator and In-Memory Analytics Accelerator common driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); -MODULE_IMPORT_NS(IDXD); +MODULE_IMPORT_NS("IDXD"); static bool sva = true; module_param(sva, bool, 0644); diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h index e16dbf9ab324c5..c426511f21048e 100644 --- a/drivers/dma/idxd/registers.h +++ b/drivers/dma/idxd/registers.h @@ -6,6 +6,10 @@ #include /* PCI Config */ +#define PCI_DEVICE_ID_INTEL_DSA_GNRD 0x11fb +#define PCI_DEVICE_ID_INTEL_DSA_DMR 0x1212 +#define PCI_DEVICE_ID_INTEL_IAA_DMR 0x1216 + #define DEVICE_VERSION_1 0x100 #define DEVICE_VERSION_2 0x200 diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index 94eca25ae9b909..6db1c5fcedc580 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -61,7 +61,7 @@ struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype) return __get_desc(wq, idx, cpu); } -EXPORT_SYMBOL_NS_GPL(idxd_alloc_desc, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_alloc_desc, "IDXD"); void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc) { @@ -70,7 +70,7 @@ void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc) desc->cpu = -1; sbitmap_queue_clear(&wq->sbq, desc->id, cpu); } -EXPORT_SYMBOL_NS_GPL(idxd_free_desc, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_free_desc, "IDXD"); static struct idxd_desc *list_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie, struct idxd_desc *desc) @@ -219,4 +219,4 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) percpu_ref_put(&wq->wq_active); return 0; } -EXPORT_SYMBOL_NS_GPL(idxd_submit_desc, IDXD); +EXPORT_SYMBOL_NS_GPL(idxd_submit_desc, "IDXD"); diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c index 0532dd2640dce3..4127c1bdcca7c8 100644 --- a/drivers/dma/img-mdc-dma.c +++ b/drivers/dma/img-mdc-dma.c @@ -1076,7 +1076,7 @@ static struct platform_driver mdc_dma_driver = { .of_match_table = of_match_ptr(mdc_dma_of_match), }, .probe = mdc_dma_probe, - .remove_new = mdc_dma_remove, + .remove = mdc_dma_remove, }; module_platform_driver(mdc_dma_driver); diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index e913f0db99dadf..a651e0995ce8de 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -1233,7 +1233,7 @@ static struct platform_driver imxdma_driver = { .name = "imx-dma", .of_match_table = imx_dma_of_dev_id, }, - .remove_new = imxdma_remove, + .remove = imxdma_remove, }; static int __init imxdma_module_init(void) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 72299a08af441b..3449006cd14b56 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -2440,7 +2440,7 @@ static struct platform_driver sdma_driver = { .name = "imx-sdma", .of_match_table = sdma_dt_ids, }, - .remove_new = sdma_remove, + .remove = sdma_remove, .probe = sdma_probe, }; diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 5de8c21d41e7d3..acc2983e28e0dd 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -1028,7 +1028,7 @@ static struct platform_driver k3_pdma_driver = { .of_match_table = k3_pdma_dt_ids, }, .probe = k3_dma_probe, - .remove_new = k3_dma_remove, + .remove = k3_dma_remove, }; module_platform_driver(k3_pdma_driver); diff --git a/drivers/dma/loongson2-apb-dma.c b/drivers/dma/loongson2-apb-dma.c new file mode 100644 index 00000000000000..367ed34ce4da5b --- /dev/null +++ b/drivers/dma/loongson2-apb-dma.c @@ -0,0 +1,705 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for the Loongson-2 APB DMA Controller + * + * Copyright (C) 2017-2023 Loongson Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmaengine.h" +#include "virt-dma.h" + +/* Global Configuration Register */ +#define LDMA_ORDER_ERG 0x0 + +/* Bitfield definitions */ + +/* Bitfields in Global Configuration Register */ +#define LDMA_64BIT_EN BIT(0) /* 1: 64 bit support */ +#define LDMA_UNCOHERENT_EN BIT(1) /* 0: cache, 1: uncache */ +#define LDMA_ASK_VALID BIT(2) +#define LDMA_START BIT(3) /* DMA start operation */ +#define LDMA_STOP BIT(4) /* DMA stop operation */ +#define LDMA_CONFIG_MASK GENMASK(4, 0) /* DMA controller config bits mask */ + +/* Bitfields in ndesc_addr field of HW descriptor */ +#define LDMA_DESC_EN BIT(0) /*1: The next descriptor is valid */ +#define LDMA_DESC_ADDR_LOW GENMASK(31, 1) + +/* Bitfields in cmd field of HW descriptor */ +#define LDMA_INT BIT(1) /* Enable DMA interrupts */ +#define LDMA_DATA_DIRECTION BIT(12) /* 1: write to device, 0: read from device */ + +#define LDMA_SLAVE_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) + +#define LDMA_MAX_TRANS_LEN U32_MAX + +/*-- descriptors -----------------------------------------------------*/ + +/* + * struct ls2x_dma_hw_desc - DMA HW descriptor + * @ndesc_addr: the next descriptor low address. + * @mem_addr: memory low address. + * @apb_addr: device buffer address. + * @len: length of a piece of carried content, in words. + * @step_len: length between two moved memory data blocks. + * @step_times: number of blocks to be carried in a single DMA operation. + * @cmd: descriptor command or state. + * @stats: DMA status. + * @high_ndesc_addr: the next descriptor high address. + * @high_mem_addr: memory high address. + * @reserved: reserved + */ +struct ls2x_dma_hw_desc { + u32 ndesc_addr; + u32 mem_addr; + u32 apb_addr; + u32 len; + u32 step_len; + u32 step_times; + u32 cmd; + u32 stats; + u32 high_ndesc_addr; + u32 high_mem_addr; + u32 reserved[2]; +} __packed; + +/* + * struct ls2x_dma_sg - ls2x dma scatter gather entry + * @hw: the pointer to DMA HW descriptor. + * @llp: physical address of the DMA HW descriptor. + * @phys: destination or source address(mem). + * @len: number of Bytes to read. + */ +struct ls2x_dma_sg { + struct ls2x_dma_hw_desc *hw; + dma_addr_t llp; + dma_addr_t phys; + u32 len; +}; + +/* + * struct ls2x_dma_desc - software descriptor + * @vdesc: pointer to the virtual dma descriptor. + * @cyclic: flag to dma cyclic + * @burst_size: burst size of transaction, in words. + * @desc_num: number of sg entries. + * @direction: transfer direction, to or from device. + * @status: dma controller status. + * @sg: array of sgs. + */ +struct ls2x_dma_desc { + struct virt_dma_desc vdesc; + bool cyclic; + size_t burst_size; + u32 desc_num; + enum dma_transfer_direction direction; + enum dma_status status; + struct ls2x_dma_sg sg[] __counted_by(desc_num); +}; + +/*-- Channels --------------------------------------------------------*/ + +/* + * struct ls2x_dma_chan - internal representation of an LS2X APB DMA channel + * @vchan: virtual dma channel entry. + * @desc: pointer to the ls2x sw dma descriptor. + * @pool: hw desc table + * @irq: irq line + * @sconfig: configuration for slave transfers, passed via .device_config + */ +struct ls2x_dma_chan { + struct virt_dma_chan vchan; + struct ls2x_dma_desc *desc; + void *pool; + int irq; + struct dma_slave_config sconfig; +}; + +/*-- Controller ------------------------------------------------------*/ + +/* + * struct ls2x_dma_priv - LS2X APB DMAC specific information + * @ddev: dmaengine dma_device object members + * @dma_clk: DMAC clock source + * @regs: memory mapped register base + * @lchan: channel to store ls2x_dma_chan structures + */ +struct ls2x_dma_priv { + struct dma_device ddev; + struct clk *dma_clk; + void __iomem *regs; + struct ls2x_dma_chan lchan; +}; + +/*-- Helper functions ------------------------------------------------*/ + +static inline struct ls2x_dma_desc *to_ldma_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct ls2x_dma_desc, vdesc); +} + +static inline struct ls2x_dma_chan *to_ldma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct ls2x_dma_chan, vchan.chan); +} + +static inline struct ls2x_dma_priv *to_ldma_priv(struct dma_device *ddev) +{ + return container_of(ddev, struct ls2x_dma_priv, ddev); +} + +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} + +static void ls2x_dma_desc_free(struct virt_dma_desc *vdesc) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(vdesc->tx.chan); + struct ls2x_dma_desc *desc = to_ldma_desc(vdesc); + int i; + + for (i = 0; i < desc->desc_num; i++) { + if (desc->sg[i].hw) + dma_pool_free(lchan->pool, desc->sg[i].hw, + desc->sg[i].llp); + } + + kfree(desc); +} + +static void ls2x_dma_write_cmd(struct ls2x_dma_chan *lchan, bool cmd) +{ + struct ls2x_dma_priv *priv = to_ldma_priv(lchan->vchan.chan.device); + u64 val; + + val = lo_hi_readq(priv->regs + LDMA_ORDER_ERG) & ~LDMA_CONFIG_MASK; + val |= LDMA_64BIT_EN | cmd; + lo_hi_writeq(val, priv->regs + LDMA_ORDER_ERG); +} + +static void ls2x_dma_start_transfer(struct ls2x_dma_chan *lchan) +{ + struct ls2x_dma_priv *priv = to_ldma_priv(lchan->vchan.chan.device); + struct ls2x_dma_sg *ldma_sg; + struct virt_dma_desc *vdesc; + u64 val; + + /* Get the next descriptor */ + vdesc = vchan_next_desc(&lchan->vchan); + if (!vdesc) { + lchan->desc = NULL; + return; + } + + list_del(&vdesc->node); + lchan->desc = to_ldma_desc(vdesc); + ldma_sg = &lchan->desc->sg[0]; + + /* Start DMA */ + lo_hi_writeq(0, priv->regs + LDMA_ORDER_ERG); + val = (ldma_sg->llp & ~LDMA_CONFIG_MASK) | LDMA_64BIT_EN | LDMA_START; + lo_hi_writeq(val, priv->regs + LDMA_ORDER_ERG); +} + +static size_t ls2x_dmac_detect_burst(struct ls2x_dma_chan *lchan) +{ + u32 maxburst, buswidth; + + /* Reject definitely invalid configurations */ + if ((lchan->sconfig.src_addr_width & LDMA_SLAVE_BUSWIDTHS) && + (lchan->sconfig.dst_addr_width & LDMA_SLAVE_BUSWIDTHS)) + return 0; + + if (lchan->sconfig.direction == DMA_MEM_TO_DEV) { + maxburst = lchan->sconfig.dst_maxburst; + buswidth = lchan->sconfig.dst_addr_width; + } else { + maxburst = lchan->sconfig.src_maxburst; + buswidth = lchan->sconfig.src_addr_width; + } + + /* If maxburst is zero, fallback to LDMA_MAX_TRANS_LEN */ + return maxburst ? (maxburst * buswidth) >> 2 : LDMA_MAX_TRANS_LEN; +} + +static void ls2x_dma_fill_desc(struct ls2x_dma_chan *lchan, u32 sg_index, + struct ls2x_dma_desc *desc) +{ + struct ls2x_dma_sg *ldma_sg = &desc->sg[sg_index]; + u32 num_segments, segment_size; + + if (desc->direction == DMA_MEM_TO_DEV) { + ldma_sg->hw->cmd = LDMA_INT | LDMA_DATA_DIRECTION; + ldma_sg->hw->apb_addr = lchan->sconfig.dst_addr; + } else { + ldma_sg->hw->cmd = LDMA_INT; + ldma_sg->hw->apb_addr = lchan->sconfig.src_addr; + } + + ldma_sg->hw->mem_addr = lower_32_bits(ldma_sg->phys); + ldma_sg->hw->high_mem_addr = upper_32_bits(ldma_sg->phys); + + /* Split into multiple equally sized segments if necessary */ + num_segments = DIV_ROUND_UP((ldma_sg->len + 3) >> 2, desc->burst_size); + segment_size = DIV_ROUND_UP((ldma_sg->len + 3) >> 2, num_segments); + + /* Word count register takes input in words */ + ldma_sg->hw->len = segment_size; + ldma_sg->hw->step_times = num_segments; + ldma_sg->hw->step_len = 0; + + /* lets make a link list */ + if (sg_index) { + desc->sg[sg_index - 1].hw->ndesc_addr = ldma_sg->llp | LDMA_DESC_EN; + desc->sg[sg_index - 1].hw->high_ndesc_addr = upper_32_bits(ldma_sg->llp); + } +} + +/*-- DMA Engine API --------------------------------------------------*/ + +/* + * ls2x_dma_alloc_chan_resources - allocate resources for DMA channel + * @chan: allocate descriptor resources for this channel + * + * return - the number of allocated descriptors + */ +static int ls2x_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + + /* Create a pool of consistent memory blocks for hardware descriptors */ + lchan->pool = dma_pool_create(dev_name(chan2dev(chan)), + chan->device->dev, PAGE_SIZE, + __alignof__(struct ls2x_dma_hw_desc), 0); + if (!lchan->pool) { + dev_err(chan2dev(chan), "No memory for descriptors\n"); + return -ENOMEM; + } + + return 1; +} + +/* + * ls2x_dma_free_chan_resources - free all channel resources + * @chan: DMA channel + */ +static void ls2x_dma_free_chan_resources(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + + vchan_free_chan_resources(to_virt_chan(chan)); + dma_pool_destroy(lchan->pool); + lchan->pool = NULL; +} + +/* + * ls2x_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction + * @chan: DMA channel + * @sgl: scatterlist to transfer to/from + * @sg_len: number of entries in @scatterlist + * @direction: DMA direction + * @flags: tx descriptor status flags + * @context: transaction context (ignored) + * + * Return: Async transaction descriptor on success and NULL on failure + */ +static struct dma_async_tx_descriptor * +ls2x_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + u32 sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + struct ls2x_dma_desc *desc; + struct scatterlist *sg; + size_t burst_size; + int i; + + if (unlikely(!sg_len || !is_slave_direction(direction))) + return NULL; + + burst_size = ls2x_dmac_detect_burst(lchan); + if (!burst_size) + return NULL; + + desc = kzalloc(struct_size(desc, sg, sg_len), GFP_NOWAIT); + if (!desc) + return NULL; + + desc->desc_num = sg_len; + desc->direction = direction; + desc->burst_size = burst_size; + + for_each_sg(sgl, sg, sg_len, i) { + struct ls2x_dma_sg *ldma_sg = &desc->sg[i]; + + /* Allocate DMA capable memory for hardware descriptor */ + ldma_sg->hw = dma_pool_alloc(lchan->pool, GFP_NOWAIT, &ldma_sg->llp); + if (!ldma_sg->hw) { + desc->desc_num = i; + ls2x_dma_desc_free(&desc->vdesc); + return NULL; + } + + ldma_sg->phys = sg_dma_address(sg); + ldma_sg->len = sg_dma_len(sg); + + ls2x_dma_fill_desc(lchan, i, desc); + } + + /* Setting the last descriptor enable bit */ + desc->sg[sg_len - 1].hw->ndesc_addr &= ~LDMA_DESC_EN; + desc->status = DMA_IN_PROGRESS; + + return vchan_tx_prep(&lchan->vchan, &desc->vdesc, flags); +} + +/* + * ls2x_dma_prep_dma_cyclic - prepare the cyclic DMA transfer + * @chan: the DMA channel to prepare + * @buf_addr: physical DMA address where the buffer starts + * @buf_len: total number of bytes for the entire buffer + * @period_len: number of bytes for each period + * @direction: transfer direction, to or from device + * @flags: tx descriptor status flags + * + * Return: Async transaction descriptor on success and NULL on failure + */ +static struct dma_async_tx_descriptor * +ls2x_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + struct ls2x_dma_desc *desc; + size_t burst_size; + u32 num_periods; + int i; + + if (unlikely(!buf_len || !period_len)) + return NULL; + + if (unlikely(!is_slave_direction(direction))) + return NULL; + + burst_size = ls2x_dmac_detect_burst(lchan); + if (!burst_size) + return NULL; + + num_periods = buf_len / period_len; + desc = kzalloc(struct_size(desc, sg, num_periods), GFP_NOWAIT); + if (!desc) + return NULL; + + desc->desc_num = num_periods; + desc->direction = direction; + desc->burst_size = burst_size; + + /* Build cyclic linked list */ + for (i = 0; i < num_periods; i++) { + struct ls2x_dma_sg *ldma_sg = &desc->sg[i]; + + /* Allocate DMA capable memory for hardware descriptor */ + ldma_sg->hw = dma_pool_alloc(lchan->pool, GFP_NOWAIT, &ldma_sg->llp); + if (!ldma_sg->hw) { + desc->desc_num = i; + ls2x_dma_desc_free(&desc->vdesc); + return NULL; + } + + ldma_sg->phys = buf_addr + period_len * i; + ldma_sg->len = period_len; + + ls2x_dma_fill_desc(lchan, i, desc); + } + + /* Lets make a cyclic list */ + desc->sg[num_periods - 1].hw->ndesc_addr = desc->sg[0].llp | LDMA_DESC_EN; + desc->sg[num_periods - 1].hw->high_ndesc_addr = upper_32_bits(desc->sg[0].llp); + desc->cyclic = true; + desc->status = DMA_IN_PROGRESS; + + return vchan_tx_prep(&lchan->vchan, &desc->vdesc, flags); +} + +/* + * ls2x_slave_config - set slave configuration for channel + * @chan: dma channel + * @cfg: slave configuration + * + * Sets slave configuration for channel + */ +static int ls2x_dma_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + + memcpy(&lchan->sconfig, config, sizeof(*config)); + return 0; +} + +/* + * ls2x_dma_issue_pending - push pending transactions to the hardware + * @chan: channel + * + * When this function is called, all pending transactions are pushed to the + * hardware and executed. + */ +static void ls2x_dma_issue_pending(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&lchan->vchan.lock, flags); + if (vchan_issue_pending(&lchan->vchan) && !lchan->desc) + ls2x_dma_start_transfer(lchan); + spin_unlock_irqrestore(&lchan->vchan.lock, flags); +} + +/* + * ls2x_dma_terminate_all - terminate all transactions + * @chan: channel + * + * Stops all DMA transactions. + */ +static int ls2x_dma_terminate_all(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&lchan->vchan.lock, flags); + /* Setting stop cmd */ + ls2x_dma_write_cmd(lchan, LDMA_STOP); + if (lchan->desc) { + vchan_terminate_vdesc(&lchan->desc->vdesc); + lchan->desc = NULL; + } + + vchan_get_all_descriptors(&lchan->vchan, &head); + spin_unlock_irqrestore(&lchan->vchan.lock, flags); + + vchan_dma_desc_free_list(&lchan->vchan, &head); + return 0; +} + +/* + * ls2x_dma_synchronize - Synchronizes the termination of transfers to the + * current context. + * @chan: channel + */ +static void ls2x_dma_synchronize(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + + vchan_synchronize(&lchan->vchan); +} + +static int ls2x_dma_pause(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&lchan->vchan.lock, flags); + if (lchan->desc && lchan->desc->status == DMA_IN_PROGRESS) { + ls2x_dma_write_cmd(lchan, LDMA_STOP); + lchan->desc->status = DMA_PAUSED; + } + spin_unlock_irqrestore(&lchan->vchan.lock, flags); + + return 0; +} + +static int ls2x_dma_resume(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&lchan->vchan.lock, flags); + if (lchan->desc && lchan->desc->status == DMA_PAUSED) { + lchan->desc->status = DMA_IN_PROGRESS; + ls2x_dma_write_cmd(lchan, LDMA_START); + } + spin_unlock_irqrestore(&lchan->vchan.lock, flags); + + return 0; +} + +/* + * ls2x_dma_isr - LS2X DMA Interrupt handler + * @irq: IRQ number + * @dev_id: Pointer to ls2x_dma_chan + * + * Return: IRQ_HANDLED/IRQ_NONE + */ +static irqreturn_t ls2x_dma_isr(int irq, void *dev_id) +{ + struct ls2x_dma_chan *lchan = dev_id; + struct ls2x_dma_desc *desc; + + spin_lock(&lchan->vchan.lock); + desc = lchan->desc; + if (desc) { + if (desc->cyclic) { + vchan_cyclic_callback(&desc->vdesc); + } else { + desc->status = DMA_COMPLETE; + vchan_cookie_complete(&desc->vdesc); + ls2x_dma_start_transfer(lchan); + } + + /* ls2x_dma_start_transfer() updates lchan->desc */ + if (!lchan->desc) + ls2x_dma_write_cmd(lchan, LDMA_STOP); + } + spin_unlock(&lchan->vchan.lock); + + return IRQ_HANDLED; +} + +static int ls2x_dma_chan_init(struct platform_device *pdev, + struct ls2x_dma_priv *priv) +{ + struct ls2x_dma_chan *lchan = &priv->lchan; + struct device *dev = &pdev->dev; + int ret; + + lchan->irq = platform_get_irq(pdev, 0); + if (lchan->irq < 0) + return lchan->irq; + + ret = devm_request_irq(dev, lchan->irq, ls2x_dma_isr, IRQF_TRIGGER_RISING, + dev_name(&pdev->dev), lchan); + if (ret) + return ret; + + /* Initialize channels related values */ + INIT_LIST_HEAD(&priv->ddev.channels); + lchan->vchan.desc_free = ls2x_dma_desc_free; + vchan_init(&lchan->vchan, &priv->ddev); + + return 0; +} + +/* + * ls2x_dma_probe - Driver probe function + * @pdev: Pointer to the platform_device structure + * + * Return: '0' on success and failure value on error + */ +static int ls2x_dma_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ls2x_dma_priv *priv; + struct dma_device *ddev; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->regs)) + return dev_err_probe(dev, PTR_ERR(priv->regs), + "devm_platform_ioremap_resource failed.\n"); + + priv->dma_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->dma_clk)) + return dev_err_probe(dev, PTR_ERR(priv->dma_clk), "devm_clk_get failed.\n"); + + ret = clk_prepare_enable(priv->dma_clk); + if (ret) + return dev_err_probe(dev, ret, "clk_prepare_enable failed.\n"); + + ret = ls2x_dma_chan_init(pdev, priv); + if (ret) + goto disable_clk; + + ddev = &priv->ddev; + ddev->dev = dev; + dma_cap_zero(ddev->cap_mask); + dma_cap_set(DMA_SLAVE, ddev->cap_mask); + dma_cap_set(DMA_CYCLIC, ddev->cap_mask); + + ddev->device_alloc_chan_resources = ls2x_dma_alloc_chan_resources; + ddev->device_free_chan_resources = ls2x_dma_free_chan_resources; + ddev->device_tx_status = dma_cookie_status; + ddev->device_issue_pending = ls2x_dma_issue_pending; + ddev->device_prep_slave_sg = ls2x_dma_prep_slave_sg; + ddev->device_prep_dma_cyclic = ls2x_dma_prep_dma_cyclic; + ddev->device_config = ls2x_dma_slave_config; + ddev->device_terminate_all = ls2x_dma_terminate_all; + ddev->device_synchronize = ls2x_dma_synchronize; + ddev->device_pause = ls2x_dma_pause; + ddev->device_resume = ls2x_dma_resume; + + ddev->src_addr_widths = LDMA_SLAVE_BUSWIDTHS; + ddev->dst_addr_widths = LDMA_SLAVE_BUSWIDTHS; + ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + + ret = dma_async_device_register(&priv->ddev); + if (ret < 0) + goto disable_clk; + + ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id, priv); + if (ret < 0) + goto unregister_dmac; + + platform_set_drvdata(pdev, priv); + + dev_info(dev, "Loongson LS2X APB DMA driver registered successfully.\n"); + return 0; + +unregister_dmac: + dma_async_device_unregister(&priv->ddev); +disable_clk: + clk_disable_unprepare(priv->dma_clk); + + return ret; +} + +/* + * ls2x_dma_remove - Driver remove function + * @pdev: Pointer to the platform_device structure + */ +static void ls2x_dma_remove(struct platform_device *pdev) +{ + struct ls2x_dma_priv *priv = platform_get_drvdata(pdev); + + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&priv->ddev); + clk_disable_unprepare(priv->dma_clk); +} + +static const struct of_device_id ls2x_dma_of_match_table[] = { + { .compatible = "loongson,ls2k1000-apbdma" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ls2x_dma_of_match_table); + +static struct platform_driver ls2x_dmac_driver = { + .probe = ls2x_dma_probe, + .remove = ls2x_dma_remove, + .driver = { + .name = "ls2x-apbdma", + .of_match_table = ls2x_dma_of_match_table, + }, +}; +module_platform_driver(ls2x_dmac_driver); + +MODULE_DESCRIPTION("Loongson-2 APB DMA Controller driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/ls2x-apb-dma.c b/drivers/dma/ls2x-apb-dma.c deleted file mode 100644 index 9652e86667224b..00000000000000 --- a/drivers/dma/ls2x-apb-dma.c +++ /dev/null @@ -1,705 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Driver for the Loongson LS2X APB DMA Controller - * - * Copyright (C) 2017-2023 Loongson Corporation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dmaengine.h" -#include "virt-dma.h" - -/* Global Configuration Register */ -#define LDMA_ORDER_ERG 0x0 - -/* Bitfield definitions */ - -/* Bitfields in Global Configuration Register */ -#define LDMA_64BIT_EN BIT(0) /* 1: 64 bit support */ -#define LDMA_UNCOHERENT_EN BIT(1) /* 0: cache, 1: uncache */ -#define LDMA_ASK_VALID BIT(2) -#define LDMA_START BIT(3) /* DMA start operation */ -#define LDMA_STOP BIT(4) /* DMA stop operation */ -#define LDMA_CONFIG_MASK GENMASK(4, 0) /* DMA controller config bits mask */ - -/* Bitfields in ndesc_addr field of HW descriptor */ -#define LDMA_DESC_EN BIT(0) /*1: The next descriptor is valid */ -#define LDMA_DESC_ADDR_LOW GENMASK(31, 1) - -/* Bitfields in cmd field of HW descriptor */ -#define LDMA_INT BIT(1) /* Enable DMA interrupts */ -#define LDMA_DATA_DIRECTION BIT(12) /* 1: write to device, 0: read from device */ - -#define LDMA_SLAVE_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ - BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) - -#define LDMA_MAX_TRANS_LEN U32_MAX - -/*-- descriptors -----------------------------------------------------*/ - -/* - * struct ls2x_dma_hw_desc - DMA HW descriptor - * @ndesc_addr: the next descriptor low address. - * @mem_addr: memory low address. - * @apb_addr: device buffer address. - * @len: length of a piece of carried content, in words. - * @step_len: length between two moved memory data blocks. - * @step_times: number of blocks to be carried in a single DMA operation. - * @cmd: descriptor command or state. - * @stats: DMA status. - * @high_ndesc_addr: the next descriptor high address. - * @high_mem_addr: memory high address. - * @reserved: reserved - */ -struct ls2x_dma_hw_desc { - u32 ndesc_addr; - u32 mem_addr; - u32 apb_addr; - u32 len; - u32 step_len; - u32 step_times; - u32 cmd; - u32 stats; - u32 high_ndesc_addr; - u32 high_mem_addr; - u32 reserved[2]; -} __packed; - -/* - * struct ls2x_dma_sg - ls2x dma scatter gather entry - * @hw: the pointer to DMA HW descriptor. - * @llp: physical address of the DMA HW descriptor. - * @phys: destination or source address(mem). - * @len: number of Bytes to read. - */ -struct ls2x_dma_sg { - struct ls2x_dma_hw_desc *hw; - dma_addr_t llp; - dma_addr_t phys; - u32 len; -}; - -/* - * struct ls2x_dma_desc - software descriptor - * @vdesc: pointer to the virtual dma descriptor. - * @cyclic: flag to dma cyclic - * @burst_size: burst size of transaction, in words. - * @desc_num: number of sg entries. - * @direction: transfer direction, to or from device. - * @status: dma controller status. - * @sg: array of sgs. - */ -struct ls2x_dma_desc { - struct virt_dma_desc vdesc; - bool cyclic; - size_t burst_size; - u32 desc_num; - enum dma_transfer_direction direction; - enum dma_status status; - struct ls2x_dma_sg sg[] __counted_by(desc_num); -}; - -/*-- Channels --------------------------------------------------------*/ - -/* - * struct ls2x_dma_chan - internal representation of an LS2X APB DMA channel - * @vchan: virtual dma channel entry. - * @desc: pointer to the ls2x sw dma descriptor. - * @pool: hw desc table - * @irq: irq line - * @sconfig: configuration for slave transfers, passed via .device_config - */ -struct ls2x_dma_chan { - struct virt_dma_chan vchan; - struct ls2x_dma_desc *desc; - void *pool; - int irq; - struct dma_slave_config sconfig; -}; - -/*-- Controller ------------------------------------------------------*/ - -/* - * struct ls2x_dma_priv - LS2X APB DMAC specific information - * @ddev: dmaengine dma_device object members - * @dma_clk: DMAC clock source - * @regs: memory mapped register base - * @lchan: channel to store ls2x_dma_chan structures - */ -struct ls2x_dma_priv { - struct dma_device ddev; - struct clk *dma_clk; - void __iomem *regs; - struct ls2x_dma_chan lchan; -}; - -/*-- Helper functions ------------------------------------------------*/ - -static inline struct ls2x_dma_desc *to_ldma_desc(struct virt_dma_desc *vdesc) -{ - return container_of(vdesc, struct ls2x_dma_desc, vdesc); -} - -static inline struct ls2x_dma_chan *to_ldma_chan(struct dma_chan *chan) -{ - return container_of(chan, struct ls2x_dma_chan, vchan.chan); -} - -static inline struct ls2x_dma_priv *to_ldma_priv(struct dma_device *ddev) -{ - return container_of(ddev, struct ls2x_dma_priv, ddev); -} - -static struct device *chan2dev(struct dma_chan *chan) -{ - return &chan->dev->device; -} - -static void ls2x_dma_desc_free(struct virt_dma_desc *vdesc) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(vdesc->tx.chan); - struct ls2x_dma_desc *desc = to_ldma_desc(vdesc); - int i; - - for (i = 0; i < desc->desc_num; i++) { - if (desc->sg[i].hw) - dma_pool_free(lchan->pool, desc->sg[i].hw, - desc->sg[i].llp); - } - - kfree(desc); -} - -static void ls2x_dma_write_cmd(struct ls2x_dma_chan *lchan, bool cmd) -{ - struct ls2x_dma_priv *priv = to_ldma_priv(lchan->vchan.chan.device); - u64 val; - - val = lo_hi_readq(priv->regs + LDMA_ORDER_ERG) & ~LDMA_CONFIG_MASK; - val |= LDMA_64BIT_EN | cmd; - lo_hi_writeq(val, priv->regs + LDMA_ORDER_ERG); -} - -static void ls2x_dma_start_transfer(struct ls2x_dma_chan *lchan) -{ - struct ls2x_dma_priv *priv = to_ldma_priv(lchan->vchan.chan.device); - struct ls2x_dma_sg *ldma_sg; - struct virt_dma_desc *vdesc; - u64 val; - - /* Get the next descriptor */ - vdesc = vchan_next_desc(&lchan->vchan); - if (!vdesc) { - lchan->desc = NULL; - return; - } - - list_del(&vdesc->node); - lchan->desc = to_ldma_desc(vdesc); - ldma_sg = &lchan->desc->sg[0]; - - /* Start DMA */ - lo_hi_writeq(0, priv->regs + LDMA_ORDER_ERG); - val = (ldma_sg->llp & ~LDMA_CONFIG_MASK) | LDMA_64BIT_EN | LDMA_START; - lo_hi_writeq(val, priv->regs + LDMA_ORDER_ERG); -} - -static size_t ls2x_dmac_detect_burst(struct ls2x_dma_chan *lchan) -{ - u32 maxburst, buswidth; - - /* Reject definitely invalid configurations */ - if ((lchan->sconfig.src_addr_width & LDMA_SLAVE_BUSWIDTHS) && - (lchan->sconfig.dst_addr_width & LDMA_SLAVE_BUSWIDTHS)) - return 0; - - if (lchan->sconfig.direction == DMA_MEM_TO_DEV) { - maxburst = lchan->sconfig.dst_maxburst; - buswidth = lchan->sconfig.dst_addr_width; - } else { - maxburst = lchan->sconfig.src_maxburst; - buswidth = lchan->sconfig.src_addr_width; - } - - /* If maxburst is zero, fallback to LDMA_MAX_TRANS_LEN */ - return maxburst ? (maxburst * buswidth) >> 2 : LDMA_MAX_TRANS_LEN; -} - -static void ls2x_dma_fill_desc(struct ls2x_dma_chan *lchan, u32 sg_index, - struct ls2x_dma_desc *desc) -{ - struct ls2x_dma_sg *ldma_sg = &desc->sg[sg_index]; - u32 num_segments, segment_size; - - if (desc->direction == DMA_MEM_TO_DEV) { - ldma_sg->hw->cmd = LDMA_INT | LDMA_DATA_DIRECTION; - ldma_sg->hw->apb_addr = lchan->sconfig.dst_addr; - } else { - ldma_sg->hw->cmd = LDMA_INT; - ldma_sg->hw->apb_addr = lchan->sconfig.src_addr; - } - - ldma_sg->hw->mem_addr = lower_32_bits(ldma_sg->phys); - ldma_sg->hw->high_mem_addr = upper_32_bits(ldma_sg->phys); - - /* Split into multiple equally sized segments if necessary */ - num_segments = DIV_ROUND_UP((ldma_sg->len + 3) >> 2, desc->burst_size); - segment_size = DIV_ROUND_UP((ldma_sg->len + 3) >> 2, num_segments); - - /* Word count register takes input in words */ - ldma_sg->hw->len = segment_size; - ldma_sg->hw->step_times = num_segments; - ldma_sg->hw->step_len = 0; - - /* lets make a link list */ - if (sg_index) { - desc->sg[sg_index - 1].hw->ndesc_addr = ldma_sg->llp | LDMA_DESC_EN; - desc->sg[sg_index - 1].hw->high_ndesc_addr = upper_32_bits(ldma_sg->llp); - } -} - -/*-- DMA Engine API --------------------------------------------------*/ - -/* - * ls2x_dma_alloc_chan_resources - allocate resources for DMA channel - * @chan: allocate descriptor resources for this channel - * - * return - the number of allocated descriptors - */ -static int ls2x_dma_alloc_chan_resources(struct dma_chan *chan) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - - /* Create a pool of consistent memory blocks for hardware descriptors */ - lchan->pool = dma_pool_create(dev_name(chan2dev(chan)), - chan->device->dev, PAGE_SIZE, - __alignof__(struct ls2x_dma_hw_desc), 0); - if (!lchan->pool) { - dev_err(chan2dev(chan), "No memory for descriptors\n"); - return -ENOMEM; - } - - return 1; -} - -/* - * ls2x_dma_free_chan_resources - free all channel resources - * @chan: DMA channel - */ -static void ls2x_dma_free_chan_resources(struct dma_chan *chan) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - - vchan_free_chan_resources(to_virt_chan(chan)); - dma_pool_destroy(lchan->pool); - lchan->pool = NULL; -} - -/* - * ls2x_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction - * @chan: DMA channel - * @sgl: scatterlist to transfer to/from - * @sg_len: number of entries in @scatterlist - * @direction: DMA direction - * @flags: tx descriptor status flags - * @context: transaction context (ignored) - * - * Return: Async transaction descriptor on success and NULL on failure - */ -static struct dma_async_tx_descriptor * -ls2x_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, - u32 sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - struct ls2x_dma_desc *desc; - struct scatterlist *sg; - size_t burst_size; - int i; - - if (unlikely(!sg_len || !is_slave_direction(direction))) - return NULL; - - burst_size = ls2x_dmac_detect_burst(lchan); - if (!burst_size) - return NULL; - - desc = kzalloc(struct_size(desc, sg, sg_len), GFP_NOWAIT); - if (!desc) - return NULL; - - desc->desc_num = sg_len; - desc->direction = direction; - desc->burst_size = burst_size; - - for_each_sg(sgl, sg, sg_len, i) { - struct ls2x_dma_sg *ldma_sg = &desc->sg[i]; - - /* Allocate DMA capable memory for hardware descriptor */ - ldma_sg->hw = dma_pool_alloc(lchan->pool, GFP_NOWAIT, &ldma_sg->llp); - if (!ldma_sg->hw) { - desc->desc_num = i; - ls2x_dma_desc_free(&desc->vdesc); - return NULL; - } - - ldma_sg->phys = sg_dma_address(sg); - ldma_sg->len = sg_dma_len(sg); - - ls2x_dma_fill_desc(lchan, i, desc); - } - - /* Setting the last descriptor enable bit */ - desc->sg[sg_len - 1].hw->ndesc_addr &= ~LDMA_DESC_EN; - desc->status = DMA_IN_PROGRESS; - - return vchan_tx_prep(&lchan->vchan, &desc->vdesc, flags); -} - -/* - * ls2x_dma_prep_dma_cyclic - prepare the cyclic DMA transfer - * @chan: the DMA channel to prepare - * @buf_addr: physical DMA address where the buffer starts - * @buf_len: total number of bytes for the entire buffer - * @period_len: number of bytes for each period - * @direction: transfer direction, to or from device - * @flags: tx descriptor status flags - * - * Return: Async transaction descriptor on success and NULL on failure - */ -static struct dma_async_tx_descriptor * -ls2x_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_transfer_direction direction, - unsigned long flags) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - struct ls2x_dma_desc *desc; - size_t burst_size; - u32 num_periods; - int i; - - if (unlikely(!buf_len || !period_len)) - return NULL; - - if (unlikely(!is_slave_direction(direction))) - return NULL; - - burst_size = ls2x_dmac_detect_burst(lchan); - if (!burst_size) - return NULL; - - num_periods = buf_len / period_len; - desc = kzalloc(struct_size(desc, sg, num_periods), GFP_NOWAIT); - if (!desc) - return NULL; - - desc->desc_num = num_periods; - desc->direction = direction; - desc->burst_size = burst_size; - - /* Build cyclic linked list */ - for (i = 0; i < num_periods; i++) { - struct ls2x_dma_sg *ldma_sg = &desc->sg[i]; - - /* Allocate DMA capable memory for hardware descriptor */ - ldma_sg->hw = dma_pool_alloc(lchan->pool, GFP_NOWAIT, &ldma_sg->llp); - if (!ldma_sg->hw) { - desc->desc_num = i; - ls2x_dma_desc_free(&desc->vdesc); - return NULL; - } - - ldma_sg->phys = buf_addr + period_len * i; - ldma_sg->len = period_len; - - ls2x_dma_fill_desc(lchan, i, desc); - } - - /* Lets make a cyclic list */ - desc->sg[num_periods - 1].hw->ndesc_addr = desc->sg[0].llp | LDMA_DESC_EN; - desc->sg[num_periods - 1].hw->high_ndesc_addr = upper_32_bits(desc->sg[0].llp); - desc->cyclic = true; - desc->status = DMA_IN_PROGRESS; - - return vchan_tx_prep(&lchan->vchan, &desc->vdesc, flags); -} - -/* - * ls2x_slave_config - set slave configuration for channel - * @chan: dma channel - * @cfg: slave configuration - * - * Sets slave configuration for channel - */ -static int ls2x_dma_slave_config(struct dma_chan *chan, - struct dma_slave_config *config) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - - memcpy(&lchan->sconfig, config, sizeof(*config)); - return 0; -} - -/* - * ls2x_dma_issue_pending - push pending transactions to the hardware - * @chan: channel - * - * When this function is called, all pending transactions are pushed to the - * hardware and executed. - */ -static void ls2x_dma_issue_pending(struct dma_chan *chan) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - unsigned long flags; - - spin_lock_irqsave(&lchan->vchan.lock, flags); - if (vchan_issue_pending(&lchan->vchan) && !lchan->desc) - ls2x_dma_start_transfer(lchan); - spin_unlock_irqrestore(&lchan->vchan.lock, flags); -} - -/* - * ls2x_dma_terminate_all - terminate all transactions - * @chan: channel - * - * Stops all DMA transactions. - */ -static int ls2x_dma_terminate_all(struct dma_chan *chan) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - unsigned long flags; - LIST_HEAD(head); - - spin_lock_irqsave(&lchan->vchan.lock, flags); - /* Setting stop cmd */ - ls2x_dma_write_cmd(lchan, LDMA_STOP); - if (lchan->desc) { - vchan_terminate_vdesc(&lchan->desc->vdesc); - lchan->desc = NULL; - } - - vchan_get_all_descriptors(&lchan->vchan, &head); - spin_unlock_irqrestore(&lchan->vchan.lock, flags); - - vchan_dma_desc_free_list(&lchan->vchan, &head); - return 0; -} - -/* - * ls2x_dma_synchronize - Synchronizes the termination of transfers to the - * current context. - * @chan: channel - */ -static void ls2x_dma_synchronize(struct dma_chan *chan) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - - vchan_synchronize(&lchan->vchan); -} - -static int ls2x_dma_pause(struct dma_chan *chan) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - unsigned long flags; - - spin_lock_irqsave(&lchan->vchan.lock, flags); - if (lchan->desc && lchan->desc->status == DMA_IN_PROGRESS) { - ls2x_dma_write_cmd(lchan, LDMA_STOP); - lchan->desc->status = DMA_PAUSED; - } - spin_unlock_irqrestore(&lchan->vchan.lock, flags); - - return 0; -} - -static int ls2x_dma_resume(struct dma_chan *chan) -{ - struct ls2x_dma_chan *lchan = to_ldma_chan(chan); - unsigned long flags; - - spin_lock_irqsave(&lchan->vchan.lock, flags); - if (lchan->desc && lchan->desc->status == DMA_PAUSED) { - lchan->desc->status = DMA_IN_PROGRESS; - ls2x_dma_write_cmd(lchan, LDMA_START); - } - spin_unlock_irqrestore(&lchan->vchan.lock, flags); - - return 0; -} - -/* - * ls2x_dma_isr - LS2X DMA Interrupt handler - * @irq: IRQ number - * @dev_id: Pointer to ls2x_dma_chan - * - * Return: IRQ_HANDLED/IRQ_NONE - */ -static irqreturn_t ls2x_dma_isr(int irq, void *dev_id) -{ - struct ls2x_dma_chan *lchan = dev_id; - struct ls2x_dma_desc *desc; - - spin_lock(&lchan->vchan.lock); - desc = lchan->desc; - if (desc) { - if (desc->cyclic) { - vchan_cyclic_callback(&desc->vdesc); - } else { - desc->status = DMA_COMPLETE; - vchan_cookie_complete(&desc->vdesc); - ls2x_dma_start_transfer(lchan); - } - - /* ls2x_dma_start_transfer() updates lchan->desc */ - if (!lchan->desc) - ls2x_dma_write_cmd(lchan, LDMA_STOP); - } - spin_unlock(&lchan->vchan.lock); - - return IRQ_HANDLED; -} - -static int ls2x_dma_chan_init(struct platform_device *pdev, - struct ls2x_dma_priv *priv) -{ - struct ls2x_dma_chan *lchan = &priv->lchan; - struct device *dev = &pdev->dev; - int ret; - - lchan->irq = platform_get_irq(pdev, 0); - if (lchan->irq < 0) - return lchan->irq; - - ret = devm_request_irq(dev, lchan->irq, ls2x_dma_isr, IRQF_TRIGGER_RISING, - dev_name(&pdev->dev), lchan); - if (ret) - return ret; - - /* Initialize channels related values */ - INIT_LIST_HEAD(&priv->ddev.channels); - lchan->vchan.desc_free = ls2x_dma_desc_free; - vchan_init(&lchan->vchan, &priv->ddev); - - return 0; -} - -/* - * ls2x_dma_probe - Driver probe function - * @pdev: Pointer to the platform_device structure - * - * Return: '0' on success and failure value on error - */ -static int ls2x_dma_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct ls2x_dma_priv *priv; - struct dma_device *ddev; - int ret; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->regs)) - return dev_err_probe(dev, PTR_ERR(priv->regs), - "devm_platform_ioremap_resource failed.\n"); - - priv->dma_clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(priv->dma_clk)) - return dev_err_probe(dev, PTR_ERR(priv->dma_clk), "devm_clk_get failed.\n"); - - ret = clk_prepare_enable(priv->dma_clk); - if (ret) - return dev_err_probe(dev, ret, "clk_prepare_enable failed.\n"); - - ret = ls2x_dma_chan_init(pdev, priv); - if (ret) - goto disable_clk; - - ddev = &priv->ddev; - ddev->dev = dev; - dma_cap_zero(ddev->cap_mask); - dma_cap_set(DMA_SLAVE, ddev->cap_mask); - dma_cap_set(DMA_CYCLIC, ddev->cap_mask); - - ddev->device_alloc_chan_resources = ls2x_dma_alloc_chan_resources; - ddev->device_free_chan_resources = ls2x_dma_free_chan_resources; - ddev->device_tx_status = dma_cookie_status; - ddev->device_issue_pending = ls2x_dma_issue_pending; - ddev->device_prep_slave_sg = ls2x_dma_prep_slave_sg; - ddev->device_prep_dma_cyclic = ls2x_dma_prep_dma_cyclic; - ddev->device_config = ls2x_dma_slave_config; - ddev->device_terminate_all = ls2x_dma_terminate_all; - ddev->device_synchronize = ls2x_dma_synchronize; - ddev->device_pause = ls2x_dma_pause; - ddev->device_resume = ls2x_dma_resume; - - ddev->src_addr_widths = LDMA_SLAVE_BUSWIDTHS; - ddev->dst_addr_widths = LDMA_SLAVE_BUSWIDTHS; - ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); - - ret = dma_async_device_register(&priv->ddev); - if (ret < 0) - goto disable_clk; - - ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id, priv); - if (ret < 0) - goto unregister_dmac; - - platform_set_drvdata(pdev, priv); - - dev_info(dev, "Loongson LS2X APB DMA driver registered successfully.\n"); - return 0; - -unregister_dmac: - dma_async_device_unregister(&priv->ddev); -disable_clk: - clk_disable_unprepare(priv->dma_clk); - - return ret; -} - -/* - * ls2x_dma_remove - Driver remove function - * @pdev: Pointer to the platform_device structure - */ -static void ls2x_dma_remove(struct platform_device *pdev) -{ - struct ls2x_dma_priv *priv = platform_get_drvdata(pdev); - - of_dma_controller_free(pdev->dev.of_node); - dma_async_device_unregister(&priv->ddev); - clk_disable_unprepare(priv->dma_clk); -} - -static const struct of_device_id ls2x_dma_of_match_table[] = { - { .compatible = "loongson,ls2k1000-apbdma" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, ls2x_dma_of_match_table); - -static struct platform_driver ls2x_dmac_driver = { - .probe = ls2x_dma_probe, - .remove_new = ls2x_dma_remove, - .driver = { - .name = "ls2x-apbdma", - .of_match_table = ls2x_dma_of_match_table, - }, -}; -module_platform_driver(ls2x_dmac_driver); - -MODULE_DESCRIPTION("Loongson LS2X APB DMA Controller driver"); -MODULE_AUTHOR("Loongson Technology Corporation Limited"); -MODULE_LICENSE("GPL"); diff --git a/drivers/dma/mcf-edma-main.c b/drivers/dma/mcf-edma-main.c index 0c5862bf26f8a5..9e1c6400c77be2 100644 --- a/drivers/dma/mcf-edma-main.c +++ b/drivers/dma/mcf-edma-main.c @@ -267,7 +267,7 @@ static struct platform_driver mcf_edma_driver = { .name = "mcf-edma", }, .probe = mcf_edma_probe, - .remove_new = mcf_edma_remove, + .remove = mcf_edma_remove, }; bool mcf_edma_filter_fn(struct dma_chan *chan, void *param) diff --git a/drivers/dma/mediatek/mtk-cqdma.c b/drivers/dma/mediatek/mtk-cqdma.c index b69eabf12a24fa..d5ddb4e30e7150 100644 --- a/drivers/dma/mediatek/mtk-cqdma.c +++ b/drivers/dma/mediatek/mtk-cqdma.c @@ -922,7 +922,7 @@ static void mtk_cqdma_remove(struct platform_device *pdev) static struct platform_driver mtk_cqdma_driver = { .probe = mtk_cqdma_probe, - .remove_new = mtk_cqdma_remove, + .remove = mtk_cqdma_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = mtk_cqdma_match, diff --git a/drivers/dma/mediatek/mtk-hsdma.c b/drivers/dma/mediatek/mtk-hsdma.c index 58c7961ab9ad15..fa77bb24a43074 100644 --- a/drivers/dma/mediatek/mtk-hsdma.c +++ b/drivers/dma/mediatek/mtk-hsdma.c @@ -1038,7 +1038,7 @@ static void mtk_hsdma_remove(struct platform_device *pdev) static struct platform_driver mtk_hsdma_driver = { .probe = mtk_hsdma_probe, - .remove_new = mtk_hsdma_remove, + .remove = mtk_hsdma_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = mtk_hsdma_match, diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c index 1bdc1500be40fc..08e15177427b94 100644 --- a/drivers/dma/mediatek/mtk-uart-apdma.c +++ b/drivers/dma/mediatek/mtk-uart-apdma.c @@ -637,7 +637,7 @@ static const struct dev_pm_ops mtk_uart_apdma_pm_ops = { static struct platform_driver mtk_uart_apdma_driver = { .probe = mtk_uart_apdma_probe, - .remove_new = mtk_uart_apdma_remove, + .remove = mtk_uart_apdma_remove, .driver = { .name = KBUILD_MODNAME, .pm = &mtk_uart_apdma_pm_ops, diff --git a/drivers/dma/milbeaut-hdmac.c b/drivers/dma/milbeaut-hdmac.c index 7b41c670970a65..9a5ec247ed6d92 100644 --- a/drivers/dma/milbeaut-hdmac.c +++ b/drivers/dma/milbeaut-hdmac.c @@ -571,7 +571,7 @@ MODULE_DEVICE_TABLE(of, milbeaut_hdmac_match); static struct platform_driver milbeaut_hdmac_driver = { .probe = milbeaut_hdmac_probe, - .remove_new = milbeaut_hdmac_remove, + .remove = milbeaut_hdmac_remove, .driver = { .name = "milbeaut-m10v-hdmac", .of_match_table = milbeaut_hdmac_match, diff --git a/drivers/dma/milbeaut-xdmac.c b/drivers/dma/milbeaut-xdmac.c index 2cce529b448eb7..58d4fd6df0bf46 100644 --- a/drivers/dma/milbeaut-xdmac.c +++ b/drivers/dma/milbeaut-xdmac.c @@ -409,7 +409,7 @@ MODULE_DEVICE_TABLE(of, milbeaut_xdmac_match); static struct platform_driver milbeaut_xdmac_driver = { .probe = milbeaut_xdmac_probe, - .remove_new = milbeaut_xdmac_remove, + .remove = milbeaut_xdmac_remove, .driver = { .name = "milbeaut-m10v-xdmac", .of_match_table = milbeaut_xdmac_match, diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 136fcaeff8dda9..a95d31103d3063 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -1137,7 +1137,7 @@ static struct platform_driver mmp_pdma_driver = { }, .id_table = mmp_pdma_id_table, .probe = mmp_pdma_probe, - .remove_new = mmp_pdma_remove, + .remove = mmp_pdma_remove, }; module_platform_driver(mmp_pdma_driver); diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index b76fe99e115163..c8dc504510f1e3 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -736,7 +736,7 @@ static struct platform_driver mmp_tdma_driver = { .of_match_table = mmp_tdma_dt_ids, }, .probe = mmp_tdma_probe, - .remove_new = mmp_tdma_remove, + .remove = mmp_tdma_remove, }; module_platform_driver(mmp_tdma_driver); diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c index 66dc6d31b603dc..de09e1ab77676d 100644 --- a/drivers/dma/moxart-dma.c +++ b/drivers/dma/moxart-dma.c @@ -644,7 +644,7 @@ MODULE_DEVICE_TABLE(of, moxart_dma_match); static struct platform_driver moxart_driver = { .probe = moxart_probe, - .remove_new = moxart_remove, + .remove = moxart_remove, .driver = { .name = "moxart-dma-engine", .of_match_table = moxart_dma_match, diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 68c247a46321cb..bf131cb5db6649 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -1110,7 +1110,7 @@ MODULE_DEVICE_TABLE(of, mpc_dma_match); static struct platform_driver mpc_dma_driver = { .probe = mpc_dma_probe, - .remove_new = mpc_dma_remove, + .remove = mpc_dma_remove, .driver = { .name = DRV_NAME, .of_match_table = mpc_dma_match, diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c index c8c67f4d982c01..cad4d4fb51ac35 100644 --- a/drivers/dma/mv_xor_v2.c +++ b/drivers/dma/mv_xor_v2.c @@ -635,7 +635,7 @@ static int mv_xor_v2_descq_init(struct mv_xor_v2_device *xor_dev) writel(MV_XOR_V2_DESC_NUM, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_SIZE_OFF); - /* write the DESQ address to the DMA enngine*/ + /* write the DESQ address to the DMA engine*/ writel(lower_32_bits(xor_dev->hw_desq), xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BALR_OFF); writel(upper_32_bits(xor_dev->hw_desq), @@ -884,7 +884,7 @@ static struct platform_driver mv_xor_v2_driver = { .probe = mv_xor_v2_probe, .suspend = mv_xor_v2_suspend, .resume = mv_xor_v2_resume, - .remove_new = mv_xor_v2_remove, + .remove = mv_xor_v2_remove, .driver = { .name = "mv_xor_v2", .of_match_table = of_match_ptr(mv_xor_v2_dt_ids), diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index 3b011a91d48ec7..0d6324c4e2be0b 100644 --- a/drivers/dma/nbpfaxi.c +++ b/drivers/dma/nbpfaxi.c @@ -1515,7 +1515,7 @@ static struct platform_driver nbpf_driver = { }, .id_table = nbpf_ids, .probe = nbpf_probe, - .remove_new = nbpf_remove, + .remove = nbpf_remove, }; module_platform_driver(nbpf_driver); diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c index aa436f9e357185..57cec757d8f568 100644 --- a/drivers/dma/owl-dma.c +++ b/drivers/dma/owl-dma.c @@ -1252,7 +1252,7 @@ static void owl_dma_remove(struct platform_device *pdev) static struct platform_driver owl_dma_driver = { .probe = owl_dma_probe, - .remove_new = owl_dma_remove, + .remove = owl_dma_remove, .driver = { .name = "dma-owl", .of_match_table = of_match_ptr(owl_dma_match), diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index 7b78759ac734dc..9d2a5a967a99c8 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4549,7 +4549,7 @@ MODULE_DEVICE_TABLE(of, ppc440spe_adma_of_match); static struct platform_driver ppc440spe_adma_driver = { .probe = ppc440spe_adma_probe, - .remove_new = ppc440spe_adma_remove, + .remove = ppc440spe_adma_remove, .driver = { .name = "PPC440SP(E)-ADMA", .of_match_table = ppc440spe_adma_of_match, diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index 31f8da810c055a..e50cf3357e5ef6 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -1442,7 +1442,7 @@ static struct platform_driver pxad_driver = { }, .id_table = pxad_id_table, .probe = pxad_probe, - .remove_new = pxad_remove, + .remove = pxad_remove, }; static bool pxad_filter_fn(struct dma_chan *chan, void *param) diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index d43a881e43b904..bbc3276992bb01 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -1469,7 +1469,7 @@ static const struct dev_pm_ops bam_dma_pm_ops = { static struct platform_driver bam_dma_driver = { .probe = bam_dma_probe, - .remove_new = bam_dma_remove, + .remove = bam_dma_remove, .driver = { .name = "bam-dma-engine", .pm = &bam_dma_pm_ops, diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 4d2cd8d9ec74a1..c2b3e4452e7150 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -948,7 +948,7 @@ MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); static struct platform_driver hidma_driver = { .probe = hidma_probe, - .remove_new = hidma_remove, + .remove = hidma_remove, .shutdown = hidma_shutdown, .driver = { .name = "hidma", diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c index c1db398adc84d7..6be54fddcee18f 100644 --- a/drivers/dma/qcom/qcom_adm.c +++ b/drivers/dma/qcom/qcom_adm.c @@ -937,7 +937,7 @@ MODULE_DEVICE_TABLE(of, adm_of_match); static struct platform_driver adm_dma_driver = { .probe = adm_dma_probe, - .remove_new = adm_dma_remove, + .remove = adm_dma_remove, .driver = { .name = "adm-dma-engine", .of_match_table = adm_of_match, diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index 01e656c69e6c1f..dc1a9a05252ec6 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -1079,7 +1079,7 @@ static struct platform_driver sa11x0_dma_driver = { .pm = &sa11x0_dma_pm_ops, }, .probe = sa11x0_dma_probe, - .remove_new = sa11x0_dma_remove, + .remove = sa11x0_dma_remove, }; static int __init sa11x0_dma_init(void) diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c index 428473611115d1..7ad3c29be14679 100644 --- a/drivers/dma/sf-pdma/sf-pdma.c +++ b/drivers/dma/sf-pdma/sf-pdma.c @@ -354,7 +354,7 @@ static irqreturn_t sf_pdma_done_isr(int irq, void *dev_id) if (!residue) { tasklet_hi_schedule(&chan->done_tasklet); } else { - /* submit next trascatioin if possible */ + /* submit next transaction if possible */ struct sf_pdma_desc *desc = chan->desc; desc->src_addr += desc->xfer_size - residue; @@ -633,7 +633,7 @@ MODULE_DEVICE_TABLE(of, sf_pdma_dt_ids); static struct platform_driver sf_pdma_driver = { .probe = sf_pdma_probe, - .remove_new = sf_pdma_remove, + .remove = sf_pdma_remove, .driver = { .name = "sf-pdma", .of_match_table = sf_pdma_dt_ids, diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig index c0b2997ab7fd93..6ea5a880b43393 100644 --- a/drivers/dma/sh/Kconfig +++ b/drivers/dma/sh/Kconfig @@ -49,10 +49,10 @@ config RENESAS_USB_DMAC SoCs. config RZ_DMAC - tristate "Renesas RZ/{G2L,V2L} DMA Controller" - depends on ARCH_RZG2L || COMPILE_TEST + tristate "Renesas RZ DMA Controller" + depends on ARCH_R7S72100 || ARCH_RZG2L || COMPILE_TEST select RENESAS_DMA select DMA_VIRTUAL_CHANNELS help - This driver supports the general purpose DMA controller found in the - Renesas RZ/{G2L,V2L} SoC variants. + This driver supports the general purpose DMA controller typically + found in the Renesas RZ SoC variants. diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 1094a2f821649c..2679c1f09faf07 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -2037,7 +2037,7 @@ static struct platform_driver rcar_dmac_driver = { .of_match_table = rcar_dmac_of_ids, }, .probe = rcar_dmac_probe, - .remove_new = rcar_dmac_remove, + .remove = rcar_dmac_remove, .shutdown = rcar_dmac_shutdown, }; diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 811389fc9cb823..9235db5510266a 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -893,7 +893,7 @@ 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); + dmac->rstc = devm_reset_control_array_get_optional_exclusive(&pdev->dev); if (IS_ERR(dmac->rstc)) return dev_err_probe(&pdev->dev, PTR_ERR(dmac->rstc), "failed to get resets\n"); @@ -1004,7 +1004,7 @@ static struct platform_driver rz_dmac_driver = { .of_match_table = of_rz_dmac_match, }, .probe = rz_dmac_probe, - .remove_new = rz_dmac_remove, + .remove = rz_dmac_remove, }; module_platform_driver(rz_dmac_driver); diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 588c5f409a8087..fdd41e1c226360 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -961,7 +961,7 @@ void shdma_chan_probe(struct shdma_dev *sdev, spin_lock_init(&schan->chan_lock); - /* Init descripter manage list */ + /* Init descriptor manage list */ INIT_LIST_HEAD(&schan->ld_queue); INIT_LIST_HEAD(&schan->ld_free); diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index 8ead0a1fd2371b..093e449e19eeeb 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -906,7 +906,7 @@ static struct platform_driver sh_dmae_driver = { .pm = &sh_dmae_pm, .name = SH_DMAE_DRV_NAME, }, - .remove_new = sh_dmae_remove, + .remove = sh_dmae_remove, }; static int __init sh_dmae_init(void) diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index f7cd0cad056c16..7e2b6c97fa2f97 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -301,7 +301,7 @@ static struct usb_dmac_desc *usb_dmac_desc_get(struct usb_dmac_chan *chan, struct usb_dmac_desc *desc = NULL; unsigned long flags; - /* Get a freed descritpor */ + /* Get a freed descriptor */ spin_lock_irqsave(&chan->vc.lock, flags); list_for_each_entry(desc, &chan->desc_freed, node) { if (sg_len <= desc->sg_allocated_len) { @@ -899,7 +899,7 @@ static struct platform_driver usb_dmac_driver = { .of_match_table = usb_dmac_of_ids, }, .probe = usb_dmac_probe, - .remove_new = usb_dmac_remove, + .remove = usb_dmac_remove, .shutdown = usb_dmac_shutdown, }; diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 3f54ff37c5e051..187a090463cedf 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -1298,7 +1298,7 @@ static const struct dev_pm_ops sprd_dma_pm_ops = { static struct platform_driver sprd_dma_driver = { .probe = sprd_dma_probe, - .remove_new = sprd_dma_remove, + .remove = sprd_dma_remove, .driver = { .name = "sprd-dma", .of_match_table = sprd_dma_match, diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c index 8880b5e336f8d4..c65ee0c7bfbdb2 100644 --- a/drivers/dma/st_fdma.c +++ b/drivers/dma/st_fdma.c @@ -858,7 +858,7 @@ static struct platform_driver st_fdma_platform_driver = { .of_match_table = st_fdma_match, }, .probe = st_fdma_probe, - .remove_new = st_fdma_remove, + .remove = st_fdma_remove, }; module_platform_driver(st_fdma_platform_driver); diff --git a/drivers/dma/stm32/stm32-dma3.c b/drivers/dma/stm32/stm32-dma3.c index 0be6e944df6fd5..0c6c4258b19561 100644 --- a/drivers/dma/stm32/stm32-dma3.c +++ b/drivers/dma/stm32/stm32-dma3.c @@ -221,6 +221,8 @@ enum stm32_dma3_port_data_width { #define STM32_DMA3_DT_BREQ BIT(8) /* CTR2_BREQ */ #define STM32_DMA3_DT_PFREQ BIT(9) /* CTR2_PFREQ */ #define STM32_DMA3_DT_TCEM GENMASK(13, 12) /* CTR2_TCEM */ +#define STM32_DMA3_DT_NOPACK BIT(16) /* CTR1_PAM */ +#define STM32_DMA3_DT_NOREFACT BIT(17) /* struct stm32_dma3_chan .config_set bitfield */ #define STM32_DMA3_CFG_SET_DT BIT(0) @@ -228,6 +230,8 @@ enum stm32_dma3_port_data_width { #define STM32_DMA3_CFG_SET_BOTH (STM32_DMA3_CFG_SET_DT | STM32_DMA3_CFG_SET_DMA) #define STM32_DMA3_MAX_BLOCK_SIZE ALIGN_DOWN(CBR1_BNDT, 64) +#define STM32_DMA3_MAX_BURST_LEN (1 + min_t(u32, FIELD_MAX(CTR1_SBL_1), \ + FIELD_MAX(CTR1_DBL_1))) #define port_is_ahb(maxdw) ({ typeof(maxdw) (_maxdw) = (maxdw); \ ((_maxdw) != DW_INVALID) && ((_maxdw) == DW_32); }) #define port_is_axi(maxdw) ({ typeof(maxdw) (_maxdw) = (maxdw); \ @@ -293,6 +297,10 @@ struct stm32_dma3_chan { u32 dma_status; }; +struct stm32_dma3_pdata { + u32 axi_max_burst_len; +}; + struct stm32_dma3_ddata { struct dma_device dma_dev; void __iomem *base; @@ -301,6 +309,7 @@ struct stm32_dma3_ddata { u32 dma_channels; u32 dma_requests; enum stm32_dma3_port_data_width ports_max_dw[2]; + u32 axi_max_burst_len; }; static inline struct stm32_dma3_ddata *to_stm32_dma3_ddata(struct stm32_dma3_chan *chan) @@ -533,7 +542,8 @@ static enum dma_slave_buswidth stm32_dma3_get_max_dw(u32 chan_max_burst, return 1 << __ffs(len | addr | max_dw); } -static u32 stm32_dma3_get_max_burst(u32 len, enum dma_slave_buswidth dw, u32 chan_max_burst) +static u32 stm32_dma3_get_max_burst(u32 len, enum dma_slave_buswidth dw, + u32 chan_max_burst, u32 bus_max_burst) { u32 max_burst = chan_max_burst ? chan_max_burst / dw : 1; @@ -544,8 +554,9 @@ static u32 stm32_dma3_get_max_burst(u32 len, enum dma_slave_buswidth dw, u32 cha /* * HW doesn't modify the burst if burst size <= half of the fifo size. * If len is not a multiple of burst size, last burst is shortened by HW. + * Take care of maximum burst supported on interconnect bus. */ - return max_burst; + return min_t(u32, max_burst, bus_max_burst); } static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transfer_direction dir, @@ -554,6 +565,7 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf { struct stm32_dma3_ddata *ddata = to_stm32_dma3_ddata(chan); struct dma_device dma_device = ddata->dma_dev; + u32 src_max_burst = STM32_DMA3_MAX_BURST_LEN, dst_max_burst = STM32_DMA3_MAX_BURST_LEN; u32 sdw, ddw, sbl_max, dbl_max, tcem, init_dw, init_bl_max; u32 _ctr1 = 0, _ctr2 = 0; u32 ch_conf = chan->dt_config.ch_conf; @@ -594,10 +606,14 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf _ctr1 |= CTR1_SINC; if (sap) _ctr1 |= CTR1_SAP; + if (port_is_axi(sap_max_dw)) /* AXI - apply axi maximum burst limitation */ + src_max_burst = ddata->axi_max_burst_len; if (FIELD_GET(STM32_DMA3_DT_DINC, tr_conf)) _ctr1 |= CTR1_DINC; if (dap) _ctr1 |= CTR1_DAP; + if (port_is_axi(dap_max_dw)) /* AXI - apply axi maximum burst limitation */ + dst_max_burst = ddata->axi_max_burst_len; _ctr2 |= FIELD_PREP(CTR2_REQSEL, chan->dt_config.req_line) & ~CTR2_SWREQ; if (FIELD_GET(STM32_DMA3_DT_BREQ, tr_conf)) @@ -617,11 +633,16 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf /* Set destination (device) data width and burst */ ddw = min_t(u32, ddw, stm32_dma3_get_max_dw(chan->max_burst, dap_max_dw, len, dst_addr)); - dbl_max = min_t(u32, dbl_max, stm32_dma3_get_max_burst(len, ddw, chan->max_burst)); + dbl_max = min_t(u32, dbl_max, stm32_dma3_get_max_burst(len, ddw, chan->max_burst, + dst_max_burst)); /* Set source (memory) data width and burst */ sdw = stm32_dma3_get_max_dw(chan->max_burst, sap_max_dw, len, src_addr); - sbl_max = stm32_dma3_get_max_burst(len, sdw, chan->max_burst); + sbl_max = stm32_dma3_get_max_burst(len, sdw, chan->max_burst, src_max_burst); + if (!!FIELD_GET(STM32_DMA3_DT_NOPACK, tr_conf)) { + sdw = ddw; + sbl_max = dbl_max; + } _ctr1 |= FIELD_PREP(CTR1_SDW_LOG2, ilog2(sdw)); _ctr1 |= FIELD_PREP(CTR1_SBL_1, sbl_max - 1); @@ -647,11 +668,17 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf /* Set source (device) data width and burst */ sdw = min_t(u32, sdw, stm32_dma3_get_max_dw(chan->max_burst, sap_max_dw, len, src_addr)); - sbl_max = min_t(u32, sbl_max, stm32_dma3_get_max_burst(len, sdw, chan->max_burst)); + sbl_max = min_t(u32, sbl_max, stm32_dma3_get_max_burst(len, sdw, chan->max_burst, + src_max_burst)); /* Set destination (memory) data width and burst */ ddw = stm32_dma3_get_max_dw(chan->max_burst, dap_max_dw, len, dst_addr); - dbl_max = stm32_dma3_get_max_burst(len, ddw, chan->max_burst); + dbl_max = stm32_dma3_get_max_burst(len, ddw, chan->max_burst, dst_max_burst); + if (!!FIELD_GET(STM32_DMA3_DT_NOPACK, tr_conf) || + ((_ctr2 & CTR2_PFREQ) && ddw > sdw)) { /* Packing to wider ddw not supported */ + ddw = sdw; + dbl_max = sbl_max; + } _ctr1 |= FIELD_PREP(CTR1_SDW_LOG2, ilog2(sdw)); _ctr1 |= FIELD_PREP(CTR1_SBL_1, sbl_max - 1); @@ -678,22 +705,24 @@ static int stm32_dma3_chan_prep_hw(struct stm32_dma3_chan *chan, enum dma_transf init_dw = sdw; init_bl_max = sbl_max; sdw = stm32_dma3_get_max_dw(chan->max_burst, sap_max_dw, len, src_addr); - sbl_max = stm32_dma3_get_max_burst(len, sdw, chan->max_burst); + sbl_max = stm32_dma3_get_max_burst(len, sdw, chan->max_burst, src_max_burst); if (chan->config_set & STM32_DMA3_CFG_SET_DMA) { sdw = min_t(u32, init_dw, sdw); - sbl_max = min_t(u32, init_bl_max, - stm32_dma3_get_max_burst(len, sdw, chan->max_burst)); + sbl_max = min_t(u32, init_bl_max, stm32_dma3_get_max_burst(len, sdw, + chan->max_burst, + src_max_burst)); } /* Set destination (memory) data width and burst */ init_dw = ddw; init_bl_max = dbl_max; ddw = stm32_dma3_get_max_dw(chan->max_burst, dap_max_dw, len, dst_addr); - dbl_max = stm32_dma3_get_max_burst(len, ddw, chan->max_burst); + dbl_max = stm32_dma3_get_max_burst(len, ddw, chan->max_burst, dst_max_burst); if (chan->config_set & STM32_DMA3_CFG_SET_DMA) { ddw = min_t(u32, init_dw, ddw); - dbl_max = min_t(u32, init_bl_max, - stm32_dma3_get_max_burst(len, ddw, chan->max_burst)); + dbl_max = min_t(u32, init_bl_max, stm32_dma3_get_max_burst(len, ddw, + chan->max_burst, + dst_max_burst)); } _ctr1 |= FIELD_PREP(CTR1_SDW_LOG2, ilog2(sdw)); @@ -1116,6 +1145,28 @@ static void stm32_dma3_free_chan_resources(struct dma_chan *c) chan->config_set = 0; } +static u32 stm32_dma3_get_ll_count(struct stm32_dma3_chan *chan, size_t len, bool prevent_refactor) +{ + u32 count; + + if (prevent_refactor) + return DIV_ROUND_UP(len, STM32_DMA3_MAX_BLOCK_SIZE); + + count = len / STM32_DMA3_MAX_BLOCK_SIZE; + len -= (len / STM32_DMA3_MAX_BLOCK_SIZE) * STM32_DMA3_MAX_BLOCK_SIZE; + + if (len >= chan->max_burst) { + count += 1; /* len < STM32_DMA3_MAX_BLOCK_SIZE here, so it fits in one item */ + len -= (len / chan->max_burst) * chan->max_burst; + } + + /* Unaligned remainder fits in one extra item */ + if (len > 0) + count += 1; + + return count; +} + static void stm32_dma3_init_chan_config_for_memcpy(struct stm32_dma3_chan *chan, dma_addr_t dst, dma_addr_t src) { @@ -1150,8 +1201,10 @@ static struct dma_async_tx_descriptor *stm32_dma3_prep_dma_memcpy(struct dma_cha struct stm32_dma3_swdesc *swdesc; size_t next_size, offset; u32 count, i, ctr1, ctr2; + bool prevent_refactor = !!FIELD_GET(STM32_DMA3_DT_NOPACK, chan->dt_config.tr_conf) || + !!FIELD_GET(STM32_DMA3_DT_NOREFACT, chan->dt_config.tr_conf); - count = DIV_ROUND_UP(len, STM32_DMA3_MAX_BLOCK_SIZE); + count = stm32_dma3_get_ll_count(chan, len, prevent_refactor); swdesc = stm32_dma3_chan_desc_alloc(chan, count); if (!swdesc) @@ -1167,6 +1220,10 @@ static struct dma_async_tx_descriptor *stm32_dma3_prep_dma_memcpy(struct dma_cha remaining = len - offset; next_size = min_t(size_t, remaining, STM32_DMA3_MAX_BLOCK_SIZE); + if (!prevent_refactor && + (next_size < STM32_DMA3_MAX_BLOCK_SIZE && next_size >= chan->max_burst)) + next_size = chan->max_burst * (remaining / chan->max_burst); + ret = stm32_dma3_chan_prep_hw(chan, DMA_MEM_TO_MEM, &swdesc->ccr, &ctr1, &ctr2, src + offset, dst + offset, next_size); if (ret) @@ -1203,14 +1260,13 @@ static struct dma_async_tx_descriptor *stm32_dma3_prep_slave_sg(struct dma_chan size_t len; dma_addr_t sg_addr, dev_addr, src, dst; u32 i, j, count, ctr1, ctr2; + bool prevent_refactor = !!FIELD_GET(STM32_DMA3_DT_NOPACK, chan->dt_config.tr_conf) || + !!FIELD_GET(STM32_DMA3_DT_NOREFACT, chan->dt_config.tr_conf); int ret; - count = sg_len; - for_each_sg(sgl, sg, sg_len, i) { - len = sg_dma_len(sg); - if (len > STM32_DMA3_MAX_BLOCK_SIZE) - count += DIV_ROUND_UP(len, STM32_DMA3_MAX_BLOCK_SIZE) - 1; - } + count = 0; + for_each_sg(sgl, sg, sg_len, i) + count += stm32_dma3_get_ll_count(chan, sg_dma_len(sg), prevent_refactor); swdesc = stm32_dma3_chan_desc_alloc(chan, count); if (!swdesc) @@ -1227,6 +1283,10 @@ static struct dma_async_tx_descriptor *stm32_dma3_prep_slave_sg(struct dma_chan do { size_t chunk = min_t(size_t, len, STM32_DMA3_MAX_BLOCK_SIZE); + if (!prevent_refactor && + (chunk < STM32_DMA3_MAX_BLOCK_SIZE && chunk >= chan->max_burst)) + chunk = chan->max_burst * (len / chan->max_burst); + if (dir == DMA_MEM_TO_DEV) { src = sg_addr; dst = dev_addr; @@ -1259,6 +1319,10 @@ static struct dma_async_tx_descriptor *stm32_dma3_prep_slave_sg(struct dma_chan } while (len); } + if (count != sg_len && chan->tcem != CTR2_TCEM_CHANNEL) + dev_warn(chan2dev(chan), "Linked-list refactored, %d items instead of %d\n", + count, sg_len); + /* Enable Error interrupts */ swdesc->ccr |= CCR_USEIE | CCR_ULEIE | CCR_DTEIE; /* Enable Transfer state interrupts */ @@ -1601,8 +1665,12 @@ static u32 stm32_dma3_check_rif(struct stm32_dma3_ddata *ddata) return chan_reserved; } +static struct stm32_dma3_pdata stm32mp25_pdata = { + .axi_max_burst_len = 16, +}; + static const struct of_device_id stm32_dma3_of_match[] = { - { .compatible = "st,stm32mp25-dma3", }, + { .compatible = "st,stm32mp25-dma3", .data = &stm32mp25_pdata, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, stm32_dma3_of_match); @@ -1610,6 +1678,7 @@ MODULE_DEVICE_TABLE(of, stm32_dma3_of_match); static int stm32_dma3_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + const struct stm32_dma3_pdata *pdata; struct stm32_dma3_ddata *ddata; struct reset_control *reset; struct stm32_dma3_chan *chan; @@ -1704,6 +1773,16 @@ static int stm32_dma3_probe(struct platform_device *pdev) else /* Dual master ports */ ddata->ports_max_dw[1] = FIELD_GET(G_M1_DATA_WIDTH_ENC, hwcfgr); + /* axi_max_burst_len is optional, if not defined, use STM32_DMA3_MAX_BURST_LEN */ + ddata->axi_max_burst_len = STM32_DMA3_MAX_BURST_LEN; + pdata = device_get_match_data(&pdev->dev); + if (pdata && pdata->axi_max_burst_len) { + ddata->axi_max_burst_len = min_t(u32, pdata->axi_max_burst_len, + STM32_DMA3_MAX_BURST_LEN); + dev_dbg(&pdev->dev, "Burst is limited to %u beats through AXI port\n", + ddata->axi_max_burst_len); + } + ddata->chans = devm_kcalloc(&pdev->dev, ddata->dma_channels, sizeof(*ddata->chans), GFP_KERNEL); if (!ddata->chans) { @@ -1827,7 +1906,7 @@ static const struct dev_pm_ops stm32_dma3_pm_ops = { static struct platform_driver stm32_dma3_driver = { .probe = stm32_dma3_probe, - .remove_new = stm32_dma3_remove, + .remove = stm32_dma3_remove, .driver = { .name = "stm32-dma3", .of_match_table = stm32_dma3_of_match, diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c index 2e7f9b07fdd29e..f37cdf6f21796d 100644 --- a/drivers/dma/sun4i-dma.c +++ b/drivers/dma/sun4i-dma.c @@ -1292,7 +1292,7 @@ MODULE_DEVICE_TABLE(of, sun4i_dma_match); static struct platform_driver sun4i_dma_driver = { .probe = sun4i_dma_probe, - .remove_new = sun4i_dma_remove, + .remove = sun4i_dma_remove, .driver = { .name = "sun4i-dma", .of_match_table = sun4i_dma_match, diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index 583bf49031cf2d..95ecb12caaa5e5 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -1488,7 +1488,7 @@ static void sun6i_dma_remove(struct platform_device *pdev) static struct platform_driver sun6i_dma_driver = { .probe = sun6i_dma_probe, - .remove_new = sun6i_dma_remove, + .remove = sun6i_dma_remove, .driver = { .name = "sun6i-dma", .of_match_table = sun6i_dma_match, diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c index 3642508e88bb22..cacf3757adc2e2 100644 --- a/drivers/dma/tegra186-gpc-dma.c +++ b/drivers/dma/tegra186-gpc-dma.c @@ -1532,7 +1532,7 @@ static struct platform_driver tegra_dma_driver = { .of_match_table = tegra_dma_of_match, }, .probe = tegra_dma_probe, - .remove_new = tegra_dma_remove, + .remove = tegra_dma_remove, }; module_platform_driver(tegra_dma_driver); diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 7d1acda2d72b35..14a61e53a41b73 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -1675,7 +1675,7 @@ static struct platform_driver tegra_dmac_driver = { .of_match_table = tegra_dma_of_match, }, .probe = tegra_dma_probe, - .remove_new = tegra_dma_remove, + .remove = tegra_dma_remove, }; module_platform_driver(tegra_dmac_driver); diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 24ad7077c53ba8..2953008d42efad 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -1008,7 +1008,7 @@ static struct platform_driver tegra_admac_driver = { .of_match_table = tegra_adma_of_match, }, .probe = tegra_adma_probe, - .remove_new = tegra_adma_remove, + .remove = tegra_adma_remove, }; module_platform_driver(tegra_admac_driver); diff --git a/drivers/dma/ti/cppi41.c b/drivers/dma/ti/cppi41.c index a8bb70c2d10992..8d8c3d6038fcc2 100644 --- a/drivers/dma/ti/cppi41.c +++ b/drivers/dma/ti/cppi41.c @@ -1243,7 +1243,7 @@ static const struct dev_pm_ops cppi41_pm_ops = { static struct platform_driver cpp41_dma_driver = { .probe = cppi41_dma_probe, - .remove_new = cppi41_dma_remove, + .remove = cppi41_dma_remove, .driver = { .name = "cppi41-dma-engine", .pm = &cppi41_pm_ops, diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 5f8d2e93ff3fb5..343e986e66e7ce 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -2636,7 +2636,7 @@ static const struct dev_pm_ops edma_pm_ops = { static struct platform_driver edma_driver = { .probe = edma_probe, - .remove_new = edma_remove, + .remove = edma_remove, .driver = { .name = "edma", .pm = &edma_pm_ops, diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index 6ab9bfbdc4809e..8c023c6e623a5a 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -1915,7 +1915,7 @@ MODULE_DEVICE_TABLE(of, omap_dma_match); static struct platform_driver omap_dma_driver = { .probe = omap_dma_probe, - .remove_new = omap_dma_remove, + .remove = omap_dma_remove, .driver = { .name = "omap-dma-engine", .of_match_table = omap_dma_match, diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index 7410025605e034..ecaf002558afc1 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -761,7 +761,7 @@ static struct platform_driver td_driver = { .name = DRIVER_NAME, }, .probe = td_probe, - .remove_new = td_remove, + .remove = td_remove, }; module_platform_driver(td_driver); diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c index 44ba377b4b5a5e..35d5221683b283 100644 --- a/drivers/dma/txx9dmac.c +++ b/drivers/dma/txx9dmac.c @@ -1260,14 +1260,14 @@ static const struct dev_pm_ops txx9dmac_dev_pm_ops = { }; static struct platform_driver txx9dmac_chan_driver = { - .remove_new = txx9dmac_chan_remove, + .remove = txx9dmac_chan_remove, .driver = { .name = "txx9dmac-chan", }, }; static struct platform_driver txx9dmac_driver = { - .remove_new = txx9dmac_remove, + .remove = txx9dmac_remove, .shutdown = txx9dmac_shutdown, .driver = { .name = "txx9dmac", diff --git a/drivers/dma/uniphier-mdmac.c b/drivers/dma/uniphier-mdmac.c index ad7125f6e2ca8e..7a99f86ecb5a03 100644 --- a/drivers/dma/uniphier-mdmac.c +++ b/drivers/dma/uniphier-mdmac.c @@ -493,7 +493,7 @@ MODULE_DEVICE_TABLE(of, uniphier_mdmac_match); static struct platform_driver uniphier_mdmac_driver = { .probe = uniphier_mdmac_probe, - .remove_new = uniphier_mdmac_remove, + .remove = uniphier_mdmac_remove, .driver = { .name = "uniphier-mio-dmac", .of_match_table = uniphier_mdmac_match, diff --git a/drivers/dma/uniphier-xdmac.c b/drivers/dma/uniphier-xdmac.c index 3ce2dc2ad9de42..ceeb6171c9d117 100644 --- a/drivers/dma/uniphier-xdmac.c +++ b/drivers/dma/uniphier-xdmac.c @@ -603,7 +603,7 @@ MODULE_DEVICE_TABLE(of, uniphier_xdmac_match); static struct platform_driver uniphier_xdmac_driver = { .probe = uniphier_xdmac_probe, - .remove_new = uniphier_xdmac_remove, + .remove = uniphier_xdmac_remove, .driver = { .name = "uniphier-xdmac", .of_match_table = uniphier_xdmac_match, diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c index 275848a9c4502c..f64624ea44add9 100644 --- a/drivers/dma/xgene-dma.c +++ b/drivers/dma/xgene-dma.c @@ -1815,7 +1815,7 @@ MODULE_DEVICE_TABLE(of, xgene_dma_of_match_ptr); static struct platform_driver xgene_dma_driver = { .probe = xgene_dma_probe, - .remove_new = xgene_dma_remove, + .remove = xgene_dma_remove, .driver = { .name = "X-Gene-DMA", .of_match_table = xgene_dma_of_match_ptr, diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 718842fdaf98ed..93772abc3b49f3 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -1315,7 +1315,7 @@ static struct platform_driver xdma_driver = { }, .id_table = xdma_id_table, .probe = xdma_probe, - .remove_new = xdma_remove, + .remove = xdma_remove, }; module_platform_driver(xdma_driver); diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 5eb51ae93e89d0..1bdd57de87a6e8 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -3271,7 +3271,7 @@ static struct platform_driver xilinx_vdma_driver = { .of_match_table = xilinx_dma_of_ids, }, .probe = xilinx_dma_probe, - .remove_new = xilinx_dma_remove, + .remove = xilinx_dma_remove, }; module_platform_driver(xilinx_vdma_driver); diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c index be87764af9e836..ee5d9fdbfd7fa8 100644 --- a/drivers/dma/xilinx/xilinx_dpdma.c +++ b/drivers/dma/xilinx/xilinx_dpdma.c @@ -1863,7 +1863,7 @@ MODULE_DEVICE_TABLE(of, xilinx_dpdma_of_match); static struct platform_driver xilinx_dpdma_driver = { .probe = xilinx_dpdma_probe, - .remove_new = xilinx_dpdma_remove, + .remove = xilinx_dpdma_remove, .driver = { .name = "xilinx-zynqmp-dpdma", .of_match_table = xilinx_dpdma_of_match, diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 9ae46f1198fe60..d05fc5fcc77dce 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -366,7 +366,7 @@ static void zynqmp_dma_init(struct zynqmp_dma_chan *chan) } writel(val, chan->regs + ZYNQMP_DMA_DATA_ATTR); - /* Clearing the interrupt account rgisters */ + /* Clearing the interrupt account registers */ val = readl(chan->regs + ZYNQMP_DMA_IRQ_SRC_ACCT); val = readl(chan->regs + ZYNQMP_DMA_IRQ_DST_ACCT); @@ -1192,7 +1192,7 @@ static struct platform_driver zynqmp_dma_driver = { .pm = &zynqmp_dma_dev_pm_ops, }, .probe = zynqmp_dma_probe, - .remove_new = zynqmp_dma_remove, + .remove = zynqmp_dma_remove, }; module_platform_driver(zynqmp_dma_driver); diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index fc0280dcddd107..c130f87147fa3f 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -169,6 +169,27 @@ dpll_msg_add_temp(struct sk_buff *msg, struct dpll_device *dpll, return 0; } +static int +dpll_msg_add_clock_quality_level(struct sk_buff *msg, struct dpll_device *dpll, + struct netlink_ext_ack *extack) +{ + const struct dpll_device_ops *ops = dpll_device_ops(dpll); + DECLARE_BITMAP(qls, DPLL_CLOCK_QUALITY_LEVEL_MAX) = { 0 }; + enum dpll_clock_quality_level ql; + int ret; + + if (!ops->clock_quality_level_get) + return 0; + ret = ops->clock_quality_level_get(dpll, dpll_priv(dpll), qls, extack); + if (ret) + return ret; + for_each_set_bit(ql, qls, DPLL_CLOCK_QUALITY_LEVEL_MAX) + if (nla_put_u32(msg, DPLL_A_CLOCK_QUALITY_LEVEL, ql)) + return -EMSGSIZE; + + return 0; +} + static int dpll_msg_add_pin_prio(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, @@ -557,6 +578,9 @@ dpll_device_get_one(struct dpll_device *dpll, struct sk_buff *msg, if (ret) return ret; ret = dpll_msg_add_lock_status(msg, dpll, extack); + if (ret) + return ret; + ret = dpll_msg_add_clock_quality_level(msg, dpll, extack); if (ret) return ret; ret = dpll_msg_add_mode(msg, dpll, extack); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 81af6c344d6baa..06f7b43a6f7884 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -311,24 +311,6 @@ config EDAC_CELL Cell Broadband Engine internal memory controller on platform without a hypervisor -config EDAC_AMD8131 - tristate "AMD8131 HyperTransport PCI-X Tunnel" - depends on PCI && PPC_MAPLE - help - Support for error detection and correction on the - AMD8131 HyperTransport PCI-X Tunnel chip. - Note, add more Kconfig dependency if it's adopted - on some machine other than Maple. - -config EDAC_AMD8111 - tristate "AMD8111 HyperTransport I/O Hub" - depends on PCI && PPC_MAPLE - help - Support for error detection and correction on the - AMD8111 HyperTransport I/O Hub chip. - Note, add more Kconfig dependency if it's adopted - on some machine other than Maple. - config EDAC_CPC925 tristate "IBM CPC925 Memory Controller (PPC970FX)" depends on PPC64 diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index faf310eec4a678..f9cf19d8d13d47 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -63,8 +63,6 @@ i10nm_edac-y := i10nm_base.o obj-$(CONFIG_EDAC_I10NM) += i10nm_edac.o skx_edac_common.o obj-$(CONFIG_EDAC_CELL) += cell_edac.o -obj-$(CONFIG_EDAC_AMD8111) += amd8111_edac.o -obj-$(CONFIG_EDAC_AMD8131) += amd8131_edac.o obj-$(CONFIG_EDAC_HIGHBANK_MC) += highbank_mc_edac.o obj-$(CONFIG_EDAC_HIGHBANK_L2) += highbank_l2_edac.o diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index fe89f5c4837f49..3e971f90236330 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -482,7 +482,7 @@ static const struct dev_pm_ops altr_sdram_pm_ops = { static struct platform_driver altr_sdram_edac_driver = { .probe = altr_sdram_probe, - .remove_new = altr_sdram_remove, + .remove = altr_sdram_remove, .driver = { .name = "altr_sdram_edac", #ifdef CONFIG_PM @@ -816,7 +816,7 @@ static void altr_edac_device_remove(struct platform_device *pdev) static struct platform_driver altr_edac_device_driver = { .probe = altr_edac_device_probe, - .remove_new = altr_edac_device_remove, + .remove = altr_edac_device_remove, .driver = { .name = "altr_edac_device", .of_match_table = altr_edac_device_of_match, diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index ddfbdb66b794d7..5d356b7c45897c 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3362,36 +3362,24 @@ static bool dct_ecc_enabled(struct amd64_pvt *pvt) static bool umc_ecc_enabled(struct amd64_pvt *pvt) { - u8 umc_en_mask = 0, ecc_en_mask = 0; - u16 nid = pvt->mc_node_id; struct amd64_umc *umc; - u8 ecc_en = 0, i; + bool ecc_en = false; + int i; + /* Check whether at least one UMC is enabled: */ for_each_umc(i) { umc = &pvt->umc[i]; - /* Only check enabled UMCs. */ - if (!(umc->sdp_ctrl & UMC_SDP_INIT)) - continue; - - umc_en_mask |= BIT(i); - - if (umc->umc_cap_hi & UMC_ECC_ENABLED) - ecc_en_mask |= BIT(i); + if (umc->sdp_ctrl & UMC_SDP_INIT && + umc->umc_cap_hi & UMC_ECC_ENABLED) { + ecc_en = true; + break; + } } - /* Check whether at least one UMC is enabled: */ - if (umc_en_mask) - ecc_en = umc_en_mask == ecc_en_mask; - else - edac_dbg(0, "Node %d: No enabled UMCs.\n", nid); - - edac_dbg(3, "Node %d: DRAM ECC %s.\n", nid, (ecc_en ? "enabled" : "disabled")); + edac_dbg(3, "Node %d: DRAM ECC %s.\n", pvt->mc_node_id, (ecc_en ? "enabled" : "disabled")); - if (!ecc_en) - return false; - else - return true; + return ecc_en; } static inline void diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c deleted file mode 100644 index a6d3013d582347..00000000000000 --- a/drivers/edac/amd8111_edac.c +++ /dev/null @@ -1,596 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module - * - * Copyright (c) 2008 Wind River Systems, Inc. - * - * Authors: Cao Qingtao - * Benjamin Walsh - * Hu Yongqi - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "edac_module.h" -#include "amd8111_edac.h" - -#define AMD8111_EDAC_REVISION " Ver: 1.0.0" -#define AMD8111_EDAC_MOD_STR "amd8111_edac" - -#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460 - -enum amd8111_edac_devs { - LPC_BRIDGE = 0, -}; - -enum amd8111_edac_pcis { - PCI_BRIDGE = 0, -}; - -/* Wrapper functions for accessing PCI configuration space */ -static int edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32) -{ - int ret; - - ret = pci_read_config_dword(dev, reg, val32); - if (ret != 0) - printk(KERN_ERR AMD8111_EDAC_MOD_STR - " PCI Access Read Error at 0x%x\n", reg); - - return ret; -} - -static void edac_pci_read_byte(struct pci_dev *dev, int reg, u8 *val8) -{ - int ret; - - ret = pci_read_config_byte(dev, reg, val8); - if (ret != 0) - printk(KERN_ERR AMD8111_EDAC_MOD_STR - " PCI Access Read Error at 0x%x\n", reg); -} - -static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32) -{ - int ret; - - ret = pci_write_config_dword(dev, reg, val32); - if (ret != 0) - printk(KERN_ERR AMD8111_EDAC_MOD_STR - " PCI Access Write Error at 0x%x\n", reg); -} - -static void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8) -{ - int ret; - - ret = pci_write_config_byte(dev, reg, val8); - if (ret != 0) - printk(KERN_ERR AMD8111_EDAC_MOD_STR - " PCI Access Write Error at 0x%x\n", reg); -} - -/* - * device-specific methods for amd8111 PCI Bridge Controller - * - * Error Reporting and Handling for amd8111 chipset could be found - * in its datasheet 3.1.2 section, P37 - */ -static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info) -{ - u32 val32; - struct pci_dev *dev = pci_info->dev; - - /* First clear error detection flags on the host interface */ - - /* Clear SSE/SMA/STA flags in the global status register*/ - edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); - if (val32 & PCI_STSCMD_CLEAR_MASK) - edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); - - /* Clear CRC and Link Fail flags in HT Link Control reg */ - edac_pci_read_dword(dev, REG_HT_LINK, &val32); - if (val32 & HT_LINK_CLEAR_MASK) - edac_pci_write_dword(dev, REG_HT_LINK, val32); - - /* Second clear all fault on the secondary interface */ - - /* Clear error flags in the memory-base limit reg. */ - edac_pci_read_dword(dev, REG_MEM_LIM, &val32); - if (val32 & MEM_LIMIT_CLEAR_MASK) - edac_pci_write_dword(dev, REG_MEM_LIM, val32); - - /* Clear Discard Timer Expired flag in Interrupt/Bridge Control reg */ - edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); - if (val32 & PCI_INTBRG_CTRL_CLEAR_MASK) - edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); - - /* Last enable error detections */ - if (edac_op_state == EDAC_OPSTATE_POLL) { - /* Enable System Error reporting in global status register */ - edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); - val32 |= PCI_STSCMD_SERREN; - edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); - - /* Enable CRC Sync flood packets to HyperTransport Link */ - edac_pci_read_dword(dev, REG_HT_LINK, &val32); - val32 |= HT_LINK_CRCFEN; - edac_pci_write_dword(dev, REG_HT_LINK, val32); - - /* Enable SSE reporting etc in Interrupt control reg */ - edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); - val32 |= PCI_INTBRG_CTRL_POLL_MASK; - edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); - } -} - -static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info) -{ - u32 val32; - struct pci_dev *dev = pci_info->dev; - - if (edac_op_state == EDAC_OPSTATE_POLL) { - /* Disable System Error reporting */ - edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); - val32 &= ~PCI_STSCMD_SERREN; - edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); - - /* Disable CRC flood packets */ - edac_pci_read_dword(dev, REG_HT_LINK, &val32); - val32 &= ~HT_LINK_CRCFEN; - edac_pci_write_dword(dev, REG_HT_LINK, val32); - - /* Disable DTSERREN/MARSP/SERREN in Interrupt Control reg */ - edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); - val32 &= ~PCI_INTBRG_CTRL_POLL_MASK; - edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); - } -} - -static void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev) -{ - struct amd8111_pci_info *pci_info = edac_dev->pvt_info; - struct pci_dev *dev = pci_info->dev; - u32 val32; - - /* Check out PCI Bridge Status and Command Register */ - edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); - if (val32 & PCI_STSCMD_CLEAR_MASK) { - printk(KERN_INFO "Error(s) in PCI bridge status and command" - "register on device %s\n", pci_info->ctl_name); - printk(KERN_INFO "SSE: %d, RMA: %d, RTA: %d\n", - (val32 & PCI_STSCMD_SSE) != 0, - (val32 & PCI_STSCMD_RMA) != 0, - (val32 & PCI_STSCMD_RTA) != 0); - - val32 |= PCI_STSCMD_CLEAR_MASK; - edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); - - edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); - } - - /* Check out HyperTransport Link Control Register */ - edac_pci_read_dword(dev, REG_HT_LINK, &val32); - if (val32 & HT_LINK_LKFAIL) { - printk(KERN_INFO "Error(s) in hypertransport link control" - "register on device %s\n", pci_info->ctl_name); - printk(KERN_INFO "LKFAIL: %d\n", - (val32 & HT_LINK_LKFAIL) != 0); - - val32 |= HT_LINK_LKFAIL; - edac_pci_write_dword(dev, REG_HT_LINK, val32); - - edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); - } - - /* Check out PCI Interrupt and Bridge Control Register */ - edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); - if (val32 & PCI_INTBRG_CTRL_DTSTAT) { - printk(KERN_INFO "Error(s) in PCI interrupt and bridge control" - "register on device %s\n", pci_info->ctl_name); - printk(KERN_INFO "DTSTAT: %d\n", - (val32 & PCI_INTBRG_CTRL_DTSTAT) != 0); - - val32 |= PCI_INTBRG_CTRL_DTSTAT; - edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); - - edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); - } - - /* Check out PCI Bridge Memory Base-Limit Register */ - edac_pci_read_dword(dev, REG_MEM_LIM, &val32); - if (val32 & MEM_LIMIT_CLEAR_MASK) { - printk(KERN_INFO - "Error(s) in mem limit register on %s device\n", - pci_info->ctl_name); - printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n" - "RTA: %d, STA: %d, MDPE: %d\n", - (val32 & MEM_LIMIT_DPE) != 0, - (val32 & MEM_LIMIT_RSE) != 0, - (val32 & MEM_LIMIT_RMA) != 0, - (val32 & MEM_LIMIT_RTA) != 0, - (val32 & MEM_LIMIT_STA) != 0, - (val32 & MEM_LIMIT_MDPE) != 0); - - val32 |= MEM_LIMIT_CLEAR_MASK; - edac_pci_write_dword(dev, REG_MEM_LIM, val32); - - edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); - } -} - -static struct resource *legacy_io_res; -static int at_compat_reg_broken; -#define LEGACY_NR_PORTS 1 - -/* device-specific methods for amd8111 LPC Bridge device */ -static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info) -{ - u8 val8; - struct pci_dev *dev = dev_info->dev; - - /* First clear REG_AT_COMPAT[SERR, IOCHK] if necessary */ - legacy_io_res = request_region(REG_AT_COMPAT, LEGACY_NR_PORTS, - AMD8111_EDAC_MOD_STR); - if (!legacy_io_res) - printk(KERN_INFO "%s: failed to request legacy I/O region " - "start %d, len %d\n", __func__, - REG_AT_COMPAT, LEGACY_NR_PORTS); - else { - val8 = __do_inb(REG_AT_COMPAT); - if (val8 == 0xff) { /* buggy port */ - printk(KERN_INFO "%s: port %d is buggy, not supported" - " by hardware?\n", __func__, REG_AT_COMPAT); - at_compat_reg_broken = 1; - release_region(REG_AT_COMPAT, LEGACY_NR_PORTS); - legacy_io_res = NULL; - } else { - u8 out8 = 0; - if (val8 & AT_COMPAT_SERR) - out8 = AT_COMPAT_CLRSERR; - if (val8 & AT_COMPAT_IOCHK) - out8 |= AT_COMPAT_CLRIOCHK; - if (out8 > 0) - __do_outb(out8, REG_AT_COMPAT); - } - } - - /* Second clear error flags on LPC bridge */ - edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8); - if (val8 & IO_CTRL_1_CLEAR_MASK) - edac_pci_write_byte(dev, REG_IO_CTRL_1, val8); -} - -static void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info) -{ - if (legacy_io_res) - release_region(REG_AT_COMPAT, LEGACY_NR_PORTS); -} - -static void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev) -{ - struct amd8111_dev_info *dev_info = edac_dev->pvt_info; - struct pci_dev *dev = dev_info->dev; - u8 val8; - - edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8); - if (val8 & IO_CTRL_1_CLEAR_MASK) { - printk(KERN_INFO - "Error(s) in IO control register on %s device\n", - dev_info->ctl_name); - printk(KERN_INFO "LPC ERR: %d, PW2LPC: %d\n", - (val8 & IO_CTRL_1_LPC_ERR) != 0, - (val8 & IO_CTRL_1_PW2LPC) != 0); - - val8 |= IO_CTRL_1_CLEAR_MASK; - edac_pci_write_byte(dev, REG_IO_CTRL_1, val8); - - edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); - } - - if (at_compat_reg_broken == 0) { - u8 out8 = 0; - val8 = __do_inb(REG_AT_COMPAT); - if (val8 & AT_COMPAT_SERR) - out8 = AT_COMPAT_CLRSERR; - if (val8 & AT_COMPAT_IOCHK) - out8 |= AT_COMPAT_CLRIOCHK; - if (out8 > 0) { - __do_outb(out8, REG_AT_COMPAT); - edac_device_handle_ue(edac_dev, 0, 0, - edac_dev->ctl_name); - } - } -} - -/* General devices represented by edac_device_ctl_info */ -static struct amd8111_dev_info amd8111_devices[] = { - [LPC_BRIDGE] = { - .err_dev = PCI_DEVICE_ID_AMD_8111_LPC, - .ctl_name = "lpc", - .init = amd8111_lpc_bridge_init, - .exit = amd8111_lpc_bridge_exit, - .check = amd8111_lpc_bridge_check, - }, - {0}, -}; - -/* PCI controllers represented by edac_pci_ctl_info */ -static struct amd8111_pci_info amd8111_pcis[] = { - [PCI_BRIDGE] = { - .err_dev = PCI_DEVICE_ID_AMD_8111_PCI, - .ctl_name = "AMD8111_PCI_Controller", - .init = amd8111_pci_bridge_init, - .exit = amd8111_pci_bridge_exit, - .check = amd8111_pci_bridge_check, - }, - {0}, -}; - -static int amd8111_dev_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data]; - int ret = -ENODEV; - - dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD, - dev_info->err_dev, NULL); - - if (!dev_info->dev) { - printk(KERN_ERR "EDAC device not found:" - "vendor %x, device %x, name %s\n", - PCI_VENDOR_ID_AMD, dev_info->err_dev, - dev_info->ctl_name); - goto err; - } - - if (pci_enable_device(dev_info->dev)) { - printk(KERN_ERR "failed to enable:" - "vendor %x, device %x, name %s\n", - PCI_VENDOR_ID_AMD, dev_info->err_dev, - dev_info->ctl_name); - goto err_dev_put; - } - - /* - * we do not allocate extra private structure for - * edac_device_ctl_info, but make use of existing - * one instead. - */ - dev_info->edac_idx = edac_device_alloc_index(); - dev_info->edac_dev = - edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1, - NULL, 0, 0, dev_info->edac_idx); - if (!dev_info->edac_dev) { - ret = -ENOMEM; - goto err_dev_put; - } - - dev_info->edac_dev->pvt_info = dev_info; - dev_info->edac_dev->dev = &dev_info->dev->dev; - dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR; - dev_info->edac_dev->ctl_name = dev_info->ctl_name; - dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev); - - if (edac_op_state == EDAC_OPSTATE_POLL) - dev_info->edac_dev->edac_check = dev_info->check; - - if (dev_info->init) - dev_info->init(dev_info); - - if (edac_device_add_device(dev_info->edac_dev) > 0) { - printk(KERN_ERR "failed to add edac_dev for %s\n", - dev_info->ctl_name); - goto err_edac_free_ctl; - } - - printk(KERN_INFO "added one edac_dev on AMD8111 " - "vendor %x, device %x, name %s\n", - PCI_VENDOR_ID_AMD, dev_info->err_dev, - dev_info->ctl_name); - - return 0; - -err_edac_free_ctl: - edac_device_free_ctl_info(dev_info->edac_dev); -err_dev_put: - pci_dev_put(dev_info->dev); -err: - return ret; -} - -static void amd8111_dev_remove(struct pci_dev *dev) -{ - struct amd8111_dev_info *dev_info; - - for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++) - if (dev_info->dev->device == dev->device) - break; - - if (!dev_info->err_dev) /* should never happen */ - return; - - if (dev_info->edac_dev) { - edac_device_del_device(dev_info->edac_dev->dev); - edac_device_free_ctl_info(dev_info->edac_dev); - } - - if (dev_info->exit) - dev_info->exit(dev_info); - - pci_dev_put(dev_info->dev); -} - -static int amd8111_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data]; - int ret = -ENODEV; - - pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD, - pci_info->err_dev, NULL); - - if (!pci_info->dev) { - printk(KERN_ERR "EDAC device not found:" - "vendor %x, device %x, name %s\n", - PCI_VENDOR_ID_AMD, pci_info->err_dev, - pci_info->ctl_name); - goto err; - } - - if (pci_enable_device(pci_info->dev)) { - printk(KERN_ERR "failed to enable:" - "vendor %x, device %x, name %s\n", - PCI_VENDOR_ID_AMD, pci_info->err_dev, - pci_info->ctl_name); - goto err_dev_put; - } - - /* - * we do not allocate extra private structure for - * edac_pci_ctl_info, but make use of existing - * one instead. - */ - pci_info->edac_idx = edac_pci_alloc_index(); - pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name); - if (!pci_info->edac_dev) { - ret = -ENOMEM; - goto err_dev_put; - } - - pci_info->edac_dev->pvt_info = pci_info; - pci_info->edac_dev->dev = &pci_info->dev->dev; - pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR; - pci_info->edac_dev->ctl_name = pci_info->ctl_name; - pci_info->edac_dev->dev_name = dev_name(&pci_info->dev->dev); - - if (edac_op_state == EDAC_OPSTATE_POLL) - pci_info->edac_dev->edac_check = pci_info->check; - - if (pci_info->init) - pci_info->init(pci_info); - - if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) { - printk(KERN_ERR "failed to add edac_pci for %s\n", - pci_info->ctl_name); - goto err_edac_free_ctl; - } - - printk(KERN_INFO "added one edac_pci on AMD8111 " - "vendor %x, device %x, name %s\n", - PCI_VENDOR_ID_AMD, pci_info->err_dev, - pci_info->ctl_name); - - return 0; - -err_edac_free_ctl: - edac_pci_free_ctl_info(pci_info->edac_dev); -err_dev_put: - pci_dev_put(pci_info->dev); -err: - return ret; -} - -static void amd8111_pci_remove(struct pci_dev *dev) -{ - struct amd8111_pci_info *pci_info; - - for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++) - if (pci_info->dev->device == dev->device) - break; - - if (!pci_info->err_dev) /* should never happen */ - return; - - if (pci_info->edac_dev) { - edac_pci_del_device(pci_info->edac_dev->dev); - edac_pci_free_ctl_info(pci_info->edac_dev); - } - - if (pci_info->exit) - pci_info->exit(pci_info); - - pci_dev_put(pci_info->dev); -} - -/* PCI Device ID talbe for general EDAC device */ -static const struct pci_device_id amd8111_edac_dev_tbl[] = { - { - PCI_VEND_DEV(AMD, 8111_LPC), - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = 0, - .class_mask = 0, - .driver_data = LPC_BRIDGE, - }, - { - 0, - } /* table is NULL-terminated */ -}; -MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl); - -static struct pci_driver amd8111_edac_dev_driver = { - .name = "AMD8111_EDAC_DEV", - .probe = amd8111_dev_probe, - .remove = amd8111_dev_remove, - .id_table = amd8111_edac_dev_tbl, -}; - -/* PCI Device ID table for EDAC PCI controller */ -static const struct pci_device_id amd8111_edac_pci_tbl[] = { - { - PCI_VEND_DEV(AMD, 8111_PCI), - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = 0, - .class_mask = 0, - .driver_data = PCI_BRIDGE, - }, - { - 0, - } /* table is NULL-terminated */ -}; -MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl); - -static struct pci_driver amd8111_edac_pci_driver = { - .name = "AMD8111_EDAC_PCI", - .probe = amd8111_pci_probe, - .remove = amd8111_pci_remove, - .id_table = amd8111_edac_pci_tbl, -}; - -static int __init amd8111_edac_init(void) -{ - int val; - - printk(KERN_INFO "AMD8111 EDAC driver " AMD8111_EDAC_REVISION "\n"); - printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n"); - - /* Only POLL mode supported so far */ - edac_op_state = EDAC_OPSTATE_POLL; - - val = pci_register_driver(&amd8111_edac_dev_driver); - val |= pci_register_driver(&amd8111_edac_pci_driver); - - return val; -} - -static void __exit amd8111_edac_exit(void) -{ - pci_unregister_driver(&amd8111_edac_pci_driver); - pci_unregister_driver(&amd8111_edac_dev_driver); -} - - -module_init(amd8111_edac_init); -module_exit(amd8111_edac_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Cao Qingtao "); -MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module"); diff --git a/drivers/edac/amd8111_edac.h b/drivers/edac/amd8111_edac.h deleted file mode 100644 index 200cab1b3e4255..00000000000000 --- a/drivers/edac/amd8111_edac.h +++ /dev/null @@ -1,118 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * amd8111_edac.h, EDAC defs for AMD8111 hypertransport chip - * - * Copyright (c) 2008 Wind River Systems, Inc. - * - * Authors: Cao Qingtao - * Benjamin Walsh - * Hu Yongqi - */ - -#ifndef _AMD8111_EDAC_H_ -#define _AMD8111_EDAC_H_ - -/************************************************************ - * PCI Bridge Status and Command Register, DevA:0x04 - ************************************************************/ -#define REG_PCI_STSCMD 0x04 -enum pci_stscmd_bits { - PCI_STSCMD_SSE = BIT(30), - PCI_STSCMD_RMA = BIT(29), - PCI_STSCMD_RTA = BIT(28), - PCI_STSCMD_SERREN = BIT(8), - PCI_STSCMD_CLEAR_MASK = (PCI_STSCMD_SSE | - PCI_STSCMD_RMA | - PCI_STSCMD_RTA) -}; - -/************************************************************ - * PCI Bridge Memory Base-Limit Register, DevA:0x1c - ************************************************************/ -#define REG_MEM_LIM 0x1c -enum mem_limit_bits { - MEM_LIMIT_DPE = BIT(31), - MEM_LIMIT_RSE = BIT(30), - MEM_LIMIT_RMA = BIT(29), - MEM_LIMIT_RTA = BIT(28), - MEM_LIMIT_STA = BIT(27), - MEM_LIMIT_MDPE = BIT(24), - MEM_LIMIT_CLEAR_MASK = (MEM_LIMIT_DPE | - MEM_LIMIT_RSE | - MEM_LIMIT_RMA | - MEM_LIMIT_RTA | - MEM_LIMIT_STA | - MEM_LIMIT_MDPE) -}; - -/************************************************************ - * HyperTransport Link Control Register, DevA:0xc4 - ************************************************************/ -#define REG_HT_LINK 0xc4 -enum ht_link_bits { - HT_LINK_LKFAIL = BIT(4), - HT_LINK_CRCFEN = BIT(1), - HT_LINK_CLEAR_MASK = (HT_LINK_LKFAIL) -}; - -/************************************************************ - * PCI Bridge Interrupt and Bridge Control, DevA:0x3c - ************************************************************/ -#define REG_PCI_INTBRG_CTRL 0x3c -enum pci_intbrg_ctrl_bits { - PCI_INTBRG_CTRL_DTSERREN = BIT(27), - PCI_INTBRG_CTRL_DTSTAT = BIT(26), - PCI_INTBRG_CTRL_MARSP = BIT(21), - PCI_INTBRG_CTRL_SERREN = BIT(17), - PCI_INTBRG_CTRL_PEREN = BIT(16), - PCI_INTBRG_CTRL_CLEAR_MASK = (PCI_INTBRG_CTRL_DTSTAT), - PCI_INTBRG_CTRL_POLL_MASK = (PCI_INTBRG_CTRL_DTSERREN | - PCI_INTBRG_CTRL_MARSP | - PCI_INTBRG_CTRL_SERREN) -}; - -/************************************************************ - * I/O Control 1 Register, DevB:0x40 - ************************************************************/ -#define REG_IO_CTRL_1 0x40 -enum io_ctrl_1_bits { - IO_CTRL_1_NMIONERR = BIT(7), - IO_CTRL_1_LPC_ERR = BIT(6), - IO_CTRL_1_PW2LPC = BIT(1), - IO_CTRL_1_CLEAR_MASK = (IO_CTRL_1_LPC_ERR | IO_CTRL_1_PW2LPC) -}; - -/************************************************************ - * Legacy I/O Space Registers - ************************************************************/ -#define REG_AT_COMPAT 0x61 -enum at_compat_bits { - AT_COMPAT_SERR = BIT(7), - AT_COMPAT_IOCHK = BIT(6), - AT_COMPAT_CLRIOCHK = BIT(3), - AT_COMPAT_CLRSERR = BIT(2), -}; - -struct amd8111_dev_info { - u16 err_dev; /* PCI Device ID */ - struct pci_dev *dev; - int edac_idx; /* device index */ - char *ctl_name; - struct edac_device_ctl_info *edac_dev; - void (*init)(struct amd8111_dev_info *dev_info); - void (*exit)(struct amd8111_dev_info *dev_info); - void (*check)(struct edac_device_ctl_info *edac_dev); -}; - -struct amd8111_pci_info { - u16 err_dev; /* PCI Device ID */ - struct pci_dev *dev; - int edac_idx; /* pci index */ - const char *ctl_name; - struct edac_pci_ctl_info *edac_dev; - void (*init)(struct amd8111_pci_info *dev_info); - void (*exit)(struct amd8111_pci_info *dev_info); - void (*check)(struct edac_pci_ctl_info *edac_dev); -}; - -#endif /* _AMD8111_EDAC_H_ */ diff --git a/drivers/edac/amd8131_edac.c b/drivers/edac/amd8131_edac.c deleted file mode 100644 index 28610ba514f4d4..00000000000000 --- a/drivers/edac/amd8131_edac.c +++ /dev/null @@ -1,358 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * amd8131_edac.c, AMD8131 hypertransport chip EDAC kernel module - * - * Copyright (c) 2008 Wind River Systems, Inc. - * - * Authors: Cao Qingtao - * Benjamin Walsh - * Hu Yongqi - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "edac_module.h" -#include "amd8131_edac.h" - -#define AMD8131_EDAC_REVISION " Ver: 1.0.0" -#define AMD8131_EDAC_MOD_STR "amd8131_edac" - -/* Wrapper functions for accessing PCI configuration space */ -static void edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32) -{ - int ret; - - ret = pci_read_config_dword(dev, reg, val32); - if (ret != 0) - printk(KERN_ERR AMD8131_EDAC_MOD_STR - " PCI Access Read Error at 0x%x\n", reg); -} - -static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32) -{ - int ret; - - ret = pci_write_config_dword(dev, reg, val32); - if (ret != 0) - printk(KERN_ERR AMD8131_EDAC_MOD_STR - " PCI Access Write Error at 0x%x\n", reg); -} - -/* Support up to two AMD8131 chipsets on a platform */ -static struct amd8131_dev_info amd8131_devices[] = { - { - .inst = NORTH_A, - .devfn = DEVFN_PCIX_BRIDGE_NORTH_A, - .ctl_name = "AMD8131_PCIX_NORTH_A", - }, - { - .inst = NORTH_B, - .devfn = DEVFN_PCIX_BRIDGE_NORTH_B, - .ctl_name = "AMD8131_PCIX_NORTH_B", - }, - { - .inst = SOUTH_A, - .devfn = DEVFN_PCIX_BRIDGE_SOUTH_A, - .ctl_name = "AMD8131_PCIX_SOUTH_A", - }, - { - .inst = SOUTH_B, - .devfn = DEVFN_PCIX_BRIDGE_SOUTH_B, - .ctl_name = "AMD8131_PCIX_SOUTH_B", - }, - {.inst = NO_BRIDGE,}, -}; - -static void amd8131_pcix_init(struct amd8131_dev_info *dev_info) -{ - u32 val32; - struct pci_dev *dev = dev_info->dev; - - /* First clear error detection flags */ - edac_pci_read_dword(dev, REG_MEM_LIM, &val32); - if (val32 & MEM_LIMIT_MASK) - edac_pci_write_dword(dev, REG_MEM_LIM, val32); - - /* Clear Discard Timer Timedout flag */ - edac_pci_read_dword(dev, REG_INT_CTLR, &val32); - if (val32 & INT_CTLR_DTS) - edac_pci_write_dword(dev, REG_INT_CTLR, val32); - - /* Clear CRC Error flag on link side A */ - edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); - if (val32 & LNK_CTRL_CRCERR_A) - edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); - - /* Clear CRC Error flag on link side B */ - edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); - if (val32 & LNK_CTRL_CRCERR_B) - edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); - - /* - * Then enable all error detections. - * - * Setup Discard Timer Sync Flood Enable, - * System Error Enable and Parity Error Enable. - */ - edac_pci_read_dword(dev, REG_INT_CTLR, &val32); - val32 |= INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE; - edac_pci_write_dword(dev, REG_INT_CTLR, val32); - - /* Enable overall SERR Error detection */ - edac_pci_read_dword(dev, REG_STS_CMD, &val32); - val32 |= STS_CMD_SERREN; - edac_pci_write_dword(dev, REG_STS_CMD, val32); - - /* Setup CRC Flood Enable for link side A */ - edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); - val32 |= LNK_CTRL_CRCFEN; - edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); - - /* Setup CRC Flood Enable for link side B */ - edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); - val32 |= LNK_CTRL_CRCFEN; - edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); -} - -static void amd8131_pcix_exit(struct amd8131_dev_info *dev_info) -{ - u32 val32; - struct pci_dev *dev = dev_info->dev; - - /* Disable SERR, PERR and DTSE Error detection */ - edac_pci_read_dword(dev, REG_INT_CTLR, &val32); - val32 &= ~(INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE); - edac_pci_write_dword(dev, REG_INT_CTLR, val32); - - /* Disable overall System Error detection */ - edac_pci_read_dword(dev, REG_STS_CMD, &val32); - val32 &= ~STS_CMD_SERREN; - edac_pci_write_dword(dev, REG_STS_CMD, val32); - - /* Disable CRC Sync Flood on link side A */ - edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); - val32 &= ~LNK_CTRL_CRCFEN; - edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); - - /* Disable CRC Sync Flood on link side B */ - edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); - val32 &= ~LNK_CTRL_CRCFEN; - edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); -} - -static void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev) -{ - struct amd8131_dev_info *dev_info = edac_dev->pvt_info; - struct pci_dev *dev = dev_info->dev; - u32 val32; - - /* Check PCI-X Bridge Memory Base-Limit Register for errors */ - edac_pci_read_dword(dev, REG_MEM_LIM, &val32); - if (val32 & MEM_LIMIT_MASK) { - printk(KERN_INFO "Error(s) in mem limit register " - "on %s bridge\n", dev_info->ctl_name); - printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n" - "RTA: %d, STA: %d, MDPE: %d\n", - val32 & MEM_LIMIT_DPE, - val32 & MEM_LIMIT_RSE, - val32 & MEM_LIMIT_RMA, - val32 & MEM_LIMIT_RTA, - val32 & MEM_LIMIT_STA, - val32 & MEM_LIMIT_MDPE); - - val32 |= MEM_LIMIT_MASK; - edac_pci_write_dword(dev, REG_MEM_LIM, val32); - - edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); - } - - /* Check if Discard Timer timed out */ - edac_pci_read_dword(dev, REG_INT_CTLR, &val32); - if (val32 & INT_CTLR_DTS) { - printk(KERN_INFO "Error(s) in interrupt and control register " - "on %s bridge\n", dev_info->ctl_name); - printk(KERN_INFO "DTS: %d\n", val32 & INT_CTLR_DTS); - - val32 |= INT_CTLR_DTS; - edac_pci_write_dword(dev, REG_INT_CTLR, val32); - - edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); - } - - /* Check if CRC error happens on link side A */ - edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); - if (val32 & LNK_CTRL_CRCERR_A) { - printk(KERN_INFO "Error(s) in link conf and control register " - "on %s bridge\n", dev_info->ctl_name); - printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_A); - - val32 |= LNK_CTRL_CRCERR_A; - edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); - - edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); - } - - /* Check if CRC error happens on link side B */ - edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); - if (val32 & LNK_CTRL_CRCERR_B) { - printk(KERN_INFO "Error(s) in link conf and control register " - "on %s bridge\n", dev_info->ctl_name); - printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_B); - - val32 |= LNK_CTRL_CRCERR_B; - edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); - - edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); - } -} - -static struct amd8131_info amd8131_chipset = { - .err_dev = PCI_DEVICE_ID_AMD_8131_APIC, - .devices = amd8131_devices, - .init = amd8131_pcix_init, - .exit = amd8131_pcix_exit, - .check = amd8131_pcix_check, -}; - -/* - * There are 4 PCIX Bridges on ATCA-6101 that share the same PCI Device ID, - * so amd8131_probe() would be called by kernel 4 times, with different - * address of pci_dev for each of them each time. - */ -static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct amd8131_dev_info *dev_info; - - for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE; - dev_info++) - if (dev_info->devfn == dev->devfn) - break; - - if (dev_info->inst == NO_BRIDGE) /* should never happen */ - return -ENODEV; - - /* - * We can't call pci_get_device() as we are used to do because - * there are 4 of them but pci_dev_get() instead. - */ - dev_info->dev = pci_dev_get(dev); - - if (pci_enable_device(dev_info->dev)) { - pci_dev_put(dev_info->dev); - printk(KERN_ERR "failed to enable:" - "vendor %x, device %x, devfn %x, name %s\n", - PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev, - dev_info->devfn, dev_info->ctl_name); - return -ENODEV; - } - - /* - * we do not allocate extra private structure for - * edac_pci_ctl_info, but make use of existing - * one instead. - */ - dev_info->edac_idx = edac_pci_alloc_index(); - dev_info->edac_dev = edac_pci_alloc_ctl_info(0, dev_info->ctl_name); - if (!dev_info->edac_dev) - return -ENOMEM; - - dev_info->edac_dev->pvt_info = dev_info; - dev_info->edac_dev->dev = &dev_info->dev->dev; - dev_info->edac_dev->mod_name = AMD8131_EDAC_MOD_STR; - dev_info->edac_dev->ctl_name = dev_info->ctl_name; - dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev); - - if (edac_op_state == EDAC_OPSTATE_POLL) - dev_info->edac_dev->edac_check = amd8131_chipset.check; - - if (amd8131_chipset.init) - amd8131_chipset.init(dev_info); - - if (edac_pci_add_device(dev_info->edac_dev, dev_info->edac_idx) > 0) { - printk(KERN_ERR "failed edac_pci_add_device() for %s\n", - dev_info->ctl_name); - edac_pci_free_ctl_info(dev_info->edac_dev); - return -ENODEV; - } - - printk(KERN_INFO "added one device on AMD8131 " - "vendor %x, device %x, devfn %x, name %s\n", - PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev, - dev_info->devfn, dev_info->ctl_name); - - return 0; -} - -static void amd8131_remove(struct pci_dev *dev) -{ - struct amd8131_dev_info *dev_info; - - for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE; - dev_info++) - if (dev_info->devfn == dev->devfn) - break; - - if (dev_info->inst == NO_BRIDGE) /* should never happen */ - return; - - if (dev_info->edac_dev) { - edac_pci_del_device(dev_info->edac_dev->dev); - edac_pci_free_ctl_info(dev_info->edac_dev); - } - - if (amd8131_chipset.exit) - amd8131_chipset.exit(dev_info); - - pci_dev_put(dev_info->dev); -} - -static const struct pci_device_id amd8131_edac_pci_tbl[] = { - { - PCI_VEND_DEV(AMD, 8131_BRIDGE), - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = 0, - .class_mask = 0, - .driver_data = 0, - }, - { - 0, - } /* table is NULL-terminated */ -}; -MODULE_DEVICE_TABLE(pci, amd8131_edac_pci_tbl); - -static struct pci_driver amd8131_edac_driver = { - .name = AMD8131_EDAC_MOD_STR, - .probe = amd8131_probe, - .remove = amd8131_remove, - .id_table = amd8131_edac_pci_tbl, -}; - -static int __init amd8131_edac_init(void) -{ - printk(KERN_INFO "AMD8131 EDAC driver " AMD8131_EDAC_REVISION "\n"); - printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n"); - - /* Only POLL mode supported so far */ - edac_op_state = EDAC_OPSTATE_POLL; - - return pci_register_driver(&amd8131_edac_driver); -} - -static void __exit amd8131_edac_exit(void) -{ - pci_unregister_driver(&amd8131_edac_driver); -} - -module_init(amd8131_edac_init); -module_exit(amd8131_edac_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Cao Qingtao "); -MODULE_DESCRIPTION("AMD8131 HyperTransport PCI-X Tunnel EDAC kernel module"); diff --git a/drivers/edac/amd8131_edac.h b/drivers/edac/amd8131_edac.h deleted file mode 100644 index 5f362abdaf12ce..00000000000000 --- a/drivers/edac/amd8131_edac.h +++ /dev/null @@ -1,107 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * amd8131_edac.h, EDAC defs for AMD8131 hypertransport chip - * - * Copyright (c) 2008 Wind River Systems, Inc. - * - * Authors: Cao Qingtao - * Benjamin Walsh - * Hu Yongqi - */ - -#ifndef _AMD8131_EDAC_H_ -#define _AMD8131_EDAC_H_ - -#define DEVFN_PCIX_BRIDGE_NORTH_A 8 -#define DEVFN_PCIX_BRIDGE_NORTH_B 16 -#define DEVFN_PCIX_BRIDGE_SOUTH_A 24 -#define DEVFN_PCIX_BRIDGE_SOUTH_B 32 - -/************************************************************ - * PCI-X Bridge Status and Command Register, DevA:0x04 - ************************************************************/ -#define REG_STS_CMD 0x04 -enum sts_cmd_bits { - STS_CMD_SSE = BIT(30), - STS_CMD_SERREN = BIT(8) -}; - -/************************************************************ - * PCI-X Bridge Interrupt and Bridge Control Register, - ************************************************************/ -#define REG_INT_CTLR 0x3c -enum int_ctlr_bits { - INT_CTLR_DTSE = BIT(27), - INT_CTLR_DTS = BIT(26), - INT_CTLR_SERR = BIT(17), - INT_CTLR_PERR = BIT(16) -}; - -/************************************************************ - * PCI-X Bridge Memory Base-Limit Register, DevA:0x1C - ************************************************************/ -#define REG_MEM_LIM 0x1c -enum mem_limit_bits { - MEM_LIMIT_DPE = BIT(31), - MEM_LIMIT_RSE = BIT(30), - MEM_LIMIT_RMA = BIT(29), - MEM_LIMIT_RTA = BIT(28), - MEM_LIMIT_STA = BIT(27), - MEM_LIMIT_MDPE = BIT(24), - MEM_LIMIT_MASK = MEM_LIMIT_DPE|MEM_LIMIT_RSE|MEM_LIMIT_RMA| - MEM_LIMIT_RTA|MEM_LIMIT_STA|MEM_LIMIT_MDPE -}; - -/************************************************************ - * Link Configuration And Control Register, side A - ************************************************************/ -#define REG_LNK_CTRL_A 0xc4 - -/************************************************************ - * Link Configuration And Control Register, side B - ************************************************************/ -#define REG_LNK_CTRL_B 0xc8 - -enum lnk_ctrl_bits { - LNK_CTRL_CRCERR_A = BIT(9), - LNK_CTRL_CRCERR_B = BIT(8), - LNK_CTRL_CRCFEN = BIT(1) -}; - -enum pcix_bridge_inst { - NORTH_A = 0, - NORTH_B = 1, - SOUTH_A = 2, - SOUTH_B = 3, - NO_BRIDGE = 4 -}; - -struct amd8131_dev_info { - int devfn; - enum pcix_bridge_inst inst; - struct pci_dev *dev; - int edac_idx; /* pci device index */ - char *ctl_name; - struct edac_pci_ctl_info *edac_dev; -}; - -/* - * AMD8131 chipset has two pairs of PCIX Bridge and related IOAPIC - * Controller, and ATCA-6101 has two AMD8131 chipsets, so there are - * four PCIX Bridges on ATCA-6101 altogether. - * - * These PCIX Bridges share the same PCI Device ID and are all of - * Function Zero, they could be discrimated by their pci_dev->devfn. - * They share the same set of init/check/exit methods, and their - * private structures are collected in the devices[] array. - */ -struct amd8131_info { - u16 err_dev; /* PCI Device ID for AMD8131 APIC*/ - struct amd8131_dev_info *devices; - void (*init)(struct amd8131_dev_info *dev_info); - void (*exit)(struct amd8131_dev_info *dev_info); - void (*check)(struct edac_pci_ctl_info *edac_dev); -}; - -#endif /* _AMD8131_EDAC_H_ */ - diff --git a/drivers/edac/armada_xp_edac.c b/drivers/edac/armada_xp_edac.c index 589bc81f124902..d64248fcf4c055 100644 --- a/drivers/edac/armada_xp_edac.c +++ b/drivers/edac/armada_xp_edac.c @@ -364,7 +364,7 @@ static void axp_mc_remove(struct platform_device *pdev) static struct platform_driver axp_mc_driver = { .probe = axp_mc_probe, - .remove_new = axp_mc_remove, + .remove = axp_mc_remove, .driver = { .name = "armada_xp_mc_edac", .of_match_table = of_match_ptr(axp_mc_of_match), @@ -579,7 +579,7 @@ static void aurora_l2_remove(struct platform_device *pdev) static struct platform_driver aurora_l2_driver = { .probe = aurora_l2_probe, - .remove_new = aurora_l2_remove, + .remove = aurora_l2_remove, .driver = { .name = "aurora_l2_edac", .of_match_table = of_match_ptr(aurora_l2_of_match), diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index 157a480eb761b1..dadb8acbee3d6c 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -387,7 +387,7 @@ static struct platform_driver aspeed_driver = { .of_match_table = aspeed_of_match }, .probe = aspeed_probe, - .remove_new = aspeed_remove + .remove = aspeed_remove }; module_platform_driver(aspeed_driver); diff --git a/drivers/edac/bluefield_edac.c b/drivers/edac/bluefield_edac.c index 5b3164560648ee..4942a240c30f25 100644 --- a/drivers/edac/bluefield_edac.c +++ b/drivers/edac/bluefield_edac.c @@ -47,13 +47,22 @@ #define MLXBF_EDAC_MAX_DIMM_PER_MC 2 #define MLXBF_EDAC_ERROR_GRAIN 8 +#define MLXBF_WRITE_REG_32 (0x82000009) +#define MLXBF_READ_REG_32 (0x8200000A) +#define MLXBF_SIP_SVC_VERSION (0x8200ff03) + +#define MLXBF_SMCCC_ACCESS_VIOLATION (-4) + +#define MLXBF_SVC_REQ_MAJOR 0 +#define MLXBF_SVC_REQ_MINOR 3 + /* - * Request MLNX_SIP_GET_DIMM_INFO + * Request MLXBF_SIP_GET_DIMM_INFO * * Retrieve information about DIMM on a certain slot. * * Call register usage: - * a0: MLNX_SIP_GET_DIMM_INFO + * a0: MLXBF_SIP_GET_DIMM_INFO * a1: (Memory controller index) << 16 | (Dimm index in memory controller) * a2-7: not used. * @@ -61,7 +70,7 @@ * a0: MLXBF_DIMM_INFO defined below describing the DIMM. * a1-3: not used. */ -#define MLNX_SIP_GET_DIMM_INFO 0x82000008 +#define MLXBF_SIP_GET_DIMM_INFO 0x82000008 /* Format for the SMC response about the memory information */ #define MLXBF_DIMM_INFO__SIZE_GB GENMASK_ULL(15, 0) @@ -72,9 +81,15 @@ #define MLXBF_DIMM_INFO__PACKAGE_X GENMASK_ULL(31, 24) struct bluefield_edac_priv { + /* pointer to device structure */ + struct device *dev; int dimm_ranks[MLXBF_EDAC_MAX_DIMM_PER_MC]; void __iomem *emi_base; int dimm_per_mc; + /* access to secure regs supported */ + bool svc_sreg_support; + /* SMC table# for secure regs access */ + u32 sreg_tbl; }; static u64 smc_call1(u64 smc_op, u64 smc_arg) @@ -86,6 +101,71 @@ static u64 smc_call1(u64 smc_op, u64 smc_arg) return res.a0; } +static int secure_readl(void __iomem *addr, u32 *result, u32 sreg_tbl) +{ + struct arm_smccc_res res; + int status; + + arm_smccc_smc(MLXBF_READ_REG_32, sreg_tbl, (uintptr_t)addr, + 0, 0, 0, 0, 0, &res); + + status = res.a0; + + if (status == SMCCC_RET_NOT_SUPPORTED || + status == MLXBF_SMCCC_ACCESS_VIOLATION) + return -1; + + *result = (u32)res.a1; + return 0; +} + +static int secure_writel(void __iomem *addr, u32 data, u32 sreg_tbl) +{ + struct arm_smccc_res res; + int status; + + arm_smccc_smc(MLXBF_WRITE_REG_32, sreg_tbl, data, (uintptr_t)addr, + 0, 0, 0, 0, &res); + + status = res.a0; + + if (status == SMCCC_RET_NOT_SUPPORTED || + status == MLXBF_SMCCC_ACCESS_VIOLATION) + return -1; + else + return 0; +} + +static int bluefield_edac_readl(struct bluefield_edac_priv *priv, u32 offset, u32 *result) +{ + void __iomem *addr; + int err = 0; + + addr = priv->emi_base + offset; + + if (priv->svc_sreg_support) + err = secure_readl(addr, result, priv->sreg_tbl); + else + *result = readl(addr); + + return err; +} + +static int bluefield_edac_writel(struct bluefield_edac_priv *priv, u32 offset, u32 data) +{ + void __iomem *addr; + int err = 0; + + addr = priv->emi_base + offset; + + if (priv->svc_sreg_support) + err = secure_writel(addr, data, priv->sreg_tbl); + else + writel(data, addr); + + return err; +} + /* * Gather the ECC information from the External Memory Interface registers * and report it to the edac handler. @@ -99,7 +179,7 @@ static void bluefield_gather_report_ecc(struct mem_ctl_info *mci, u32 ecc_latch_select, dram_syndrom, serr, derr, syndrom; enum hw_event_mc_err_type ecc_type; u64 ecc_dimm_addr; - int ecc_dimm; + int ecc_dimm, err; ecc_type = is_single_ecc ? HW_EVENT_ERR_CORRECTED : HW_EVENT_ERR_UNCORRECTED; @@ -109,14 +189,19 @@ static void bluefield_gather_report_ecc(struct mem_ctl_info *mci, * registers with information about the last ECC error occurrence. */ ecc_latch_select = MLXBF_ECC_LATCH_SEL__START; - writel(ecc_latch_select, priv->emi_base + MLXBF_ECC_LATCH_SEL); + err = bluefield_edac_writel(priv, MLXBF_ECC_LATCH_SEL, ecc_latch_select); + if (err) + dev_err(priv->dev, "ECC latch select write failed.\n"); /* * Verify that the ECC reported info in the registers is of the * same type as the one asked to report. If not, just report the * error without the detailed information. */ - dram_syndrom = readl(priv->emi_base + MLXBF_SYNDROM); + err = bluefield_edac_readl(priv, MLXBF_SYNDROM, &dram_syndrom); + if (err) + dev_err(priv->dev, "DRAM syndrom read failed.\n"); + serr = FIELD_GET(MLXBF_SYNDROM__SERR, dram_syndrom); derr = FIELD_GET(MLXBF_SYNDROM__DERR, dram_syndrom); syndrom = FIELD_GET(MLXBF_SYNDROM__SYN, dram_syndrom); @@ -127,13 +212,21 @@ static void bluefield_gather_report_ecc(struct mem_ctl_info *mci, return; } - dram_additional_info = readl(priv->emi_base + MLXBF_ADD_INFO); + err = bluefield_edac_readl(priv, MLXBF_ADD_INFO, &dram_additional_info); + if (err) + dev_err(priv->dev, "DRAM additional info read failed.\n"); + err_prank = FIELD_GET(MLXBF_ADD_INFO__ERR_PRANK, dram_additional_info); ecc_dimm = (err_prank >= 2 && priv->dimm_ranks[0] <= 2) ? 1 : 0; - edea0 = readl(priv->emi_base + MLXBF_ERR_ADDR_0); - edea1 = readl(priv->emi_base + MLXBF_ERR_ADDR_1); + err = bluefield_edac_readl(priv, MLXBF_ERR_ADDR_0, &edea0); + if (err) + dev_err(priv->dev, "Error addr 0 read failed.\n"); + + err = bluefield_edac_readl(priv, MLXBF_ERR_ADDR_1, &edea1); + if (err) + dev_err(priv->dev, "Error addr 1 read failed.\n"); ecc_dimm_addr = ((u64)edea1 << 32) | edea0; @@ -147,6 +240,7 @@ static void bluefield_edac_check(struct mem_ctl_info *mci) { struct bluefield_edac_priv *priv = mci->pvt_info; u32 ecc_count, single_error_count, double_error_count, ecc_error = 0; + int err; /* * The memory controller might not be initialized by the firmware @@ -155,7 +249,10 @@ static void bluefield_edac_check(struct mem_ctl_info *mci) if (mci->edac_cap == EDAC_FLAG_NONE) return; - ecc_count = readl(priv->emi_base + MLXBF_ECC_CNT); + err = bluefield_edac_readl(priv, MLXBF_ECC_CNT, &ecc_count); + if (err) + dev_err(priv->dev, "ECC count read failed.\n"); + single_error_count = FIELD_GET(MLXBF_ECC_CNT__SERR_CNT, ecc_count); double_error_count = FIELD_GET(MLXBF_ECC_CNT__DERR_CNT, ecc_count); @@ -172,15 +269,18 @@ static void bluefield_edac_check(struct mem_ctl_info *mci) } /* Write to clear reported errors. */ - if (ecc_count) - writel(ecc_error, priv->emi_base + MLXBF_ECC_ERR); + if (ecc_count) { + err = bluefield_edac_writel(priv, MLXBF_ECC_ERR, ecc_error); + if (err) + dev_err(priv->dev, "ECC Error write failed.\n"); + } } /* Initialize the DIMMs information for the given memory controller. */ static void bluefield_edac_init_dimms(struct mem_ctl_info *mci) { struct bluefield_edac_priv *priv = mci->pvt_info; - int mem_ctrl_idx = mci->mc_idx; + u64 mem_ctrl_idx = mci->mc_idx; struct dimm_info *dimm; u64 smc_info, smc_arg; int is_empty = 1, i; @@ -189,7 +289,7 @@ static void bluefield_edac_init_dimms(struct mem_ctl_info *mci) dimm = mci->dimms[i]; smc_arg = mem_ctrl_idx << 16 | i; - smc_info = smc_call1(MLNX_SIP_GET_DIMM_INFO, smc_arg); + smc_info = smc_call1(MLXBF_SIP_GET_DIMM_INFO, smc_arg); if (!FIELD_GET(MLXBF_DIMM_INFO__SIZE_GB, smc_info)) { dimm->mtype = MEM_EMPTY; @@ -244,6 +344,7 @@ static int bluefield_edac_mc_probe(struct platform_device *pdev) struct bluefield_edac_priv *priv; struct device *dev = &pdev->dev; struct edac_mc_layer layers[1]; + struct arm_smccc_res res; struct mem_ctl_info *mci; struct resource *emi_res; unsigned int mc_idx, dimm_count; @@ -279,13 +380,43 @@ static int bluefield_edac_mc_probe(struct platform_device *pdev) return -ENOMEM; priv = mci->pvt_info; + priv->dev = dev; + + /* + * The "sec_reg_block" property in the ACPI table determines the method + * the driver uses to access the EMI registers: + * a) property is not present - directly access registers via readl/writel + * b) property is present - indirectly access registers via SMC calls + * (assuming required Silicon Provider service version found) + */ + if (device_property_read_u32(dev, "sec_reg_block", &priv->sreg_tbl)) { + priv->svc_sreg_support = false; + } else { + /* + * Check for minimum required Arm Silicon Provider (SiP) service + * version, ensuring support of required SMC function IDs. + */ + arm_smccc_smc(MLXBF_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); + if (res.a0 == MLXBF_SVC_REQ_MAJOR && + res.a1 >= MLXBF_SVC_REQ_MINOR) { + priv->svc_sreg_support = true; + } else { + dev_err(dev, "Required SMCs are not supported.\n"); + ret = -EINVAL; + goto err; + } + } priv->dimm_per_mc = dimm_count; - priv->emi_base = devm_ioremap_resource(dev, emi_res); - if (IS_ERR(priv->emi_base)) { - dev_err(dev, "failed to map EMI IO resource\n"); - ret = PTR_ERR(priv->emi_base); - goto err; + if (!priv->svc_sreg_support) { + priv->emi_base = devm_ioremap_resource(dev, emi_res); + if (IS_ERR(priv->emi_base)) { + dev_err(dev, "failed to map EMI IO resource\n"); + ret = PTR_ERR(priv->emi_base); + goto err; + } + } else { + priv->emi_base = (void __iomem *)emi_res->start; } mci->pdev = dev; @@ -320,7 +451,6 @@ static int bluefield_edac_mc_probe(struct platform_device *pdev) edac_mc_free(mci); return ret; - } static void bluefield_edac_mc_remove(struct platform_device *pdev) @@ -344,7 +474,7 @@ static struct platform_driver bluefield_edac_mc_driver = { .acpi_match_table = bluefield_mc_acpi_ids, }, .probe = bluefield_edac_mc_probe, - .remove_new = bluefield_edac_mc_remove, + .remove = bluefield_edac_mc_remove, }; module_platform_driver(bluefield_edac_mc_driver); diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index 2000f66fbf5c46..c2420e2287ff7f 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -246,7 +246,7 @@ static struct platform_driver cell_edac_driver = { .name = "cbe-mic", }, .probe = cell_edac_probe, - .remove_new = cell_edac_remove, + .remove = cell_edac_remove, }; static int __init cell_edac_init(void) diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index eb702bc3aa29a5..9c9e4369c04118 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -1027,7 +1027,7 @@ static void cpc925_remove(struct platform_device *pdev) static struct platform_driver cpc925_edac_driver = { .probe = cpc925_probe, - .remove_new = cpc925_remove, + .remove = cpc925_remove, .driver = { .name = "cpc925_edac", } diff --git a/drivers/edac/dmc520_edac.c b/drivers/edac/dmc520_edac.c index 5e52d31db3b8f5..64a4d0a07032cc 100644 --- a/drivers/edac/dmc520_edac.c +++ b/drivers/edac/dmc520_edac.c @@ -640,7 +640,7 @@ static struct platform_driver dmc520_edac_driver = { }, .probe = dmc520_edac_probe, - .remove_new = dmc520_edac_remove + .remove = dmc520_edac_remove }; module_platform_driver(dmc520_edac_driver); diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index d148d262d0d4de..e4eaec0aa81d5b 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -31,18 +31,30 @@ static int edac_mc_idx; -static u32 orig_ddr_err_disable; -static u32 orig_ddr_err_sbe; -static bool little_endian; +static inline void __iomem *ddr_reg_addr(struct fsl_mc_pdata *pdata, unsigned int off) +{ + if (pdata->flag == TYPE_IMX9 && off >= FSL_MC_DATA_ERR_INJECT_HI && off <= FSL_MC_ERR_SBE) + return pdata->inject_vbase + off - FSL_MC_DATA_ERR_INJECT_HI + + IMX9_MC_DATA_ERR_INJECT_OFF; + + if (pdata->flag == TYPE_IMX9 && off >= IMX9_MC_ERR_EN) + return pdata->inject_vbase + off - IMX9_MC_ERR_EN; -static inline u32 ddr_in32(void __iomem *addr) + return pdata->mc_vbase + off; +} + +static inline u32 ddr_in32(struct fsl_mc_pdata *pdata, unsigned int off) { - return little_endian ? ioread32(addr) : ioread32be(addr); + void __iomem *addr = ddr_reg_addr(pdata, off); + + return pdata->little_endian ? ioread32(addr) : ioread32be(addr); } -static inline void ddr_out32(void __iomem *addr, u32 value) +static inline void ddr_out32(struct fsl_mc_pdata *pdata, unsigned int off, u32 value) { - if (little_endian) + void __iomem *addr = ddr_reg_addr(pdata, off); + + if (pdata->little_endian) iowrite32(value, addr); else iowrite32be(value, addr); @@ -60,7 +72,7 @@ static ssize_t fsl_mc_inject_data_hi_show(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", - ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI)); + ddr_in32(pdata, FSL_MC_DATA_ERR_INJECT_HI)); } static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, @@ -70,7 +82,7 @@ static ssize_t fsl_mc_inject_data_lo_show(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", - ddr_in32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO)); + ddr_in32(pdata, FSL_MC_DATA_ERR_INJECT_LO)); } static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, @@ -80,7 +92,7 @@ static ssize_t fsl_mc_inject_ctrl_show(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct fsl_mc_pdata *pdata = mci->pvt_info; return sprintf(data, "0x%08x", - ddr_in32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT)); + ddr_in32(pdata, FSL_MC_ECC_ERR_INJECT)); } static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, @@ -97,7 +109,7 @@ static ssize_t fsl_mc_inject_data_hi_store(struct device *dev, if (rc) return rc; - ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_HI, val); + ddr_out32(pdata, FSL_MC_DATA_ERR_INJECT_HI, val); return count; } return 0; @@ -117,7 +129,7 @@ static ssize_t fsl_mc_inject_data_lo_store(struct device *dev, if (rc) return rc; - ddr_out32(pdata->mc_vbase + FSL_MC_DATA_ERR_INJECT_LO, val); + ddr_out32(pdata, FSL_MC_DATA_ERR_INJECT_LO, val); return count; } return 0; @@ -137,7 +149,7 @@ static ssize_t fsl_mc_inject_ctrl_store(struct device *dev, if (rc) return rc; - ddr_out32(pdata->mc_vbase + FSL_MC_ECC_ERR_INJECT, val); + ddr_out32(pdata, FSL_MC_ECC_ERR_INJECT, val); return count; } return 0; @@ -286,7 +298,7 @@ static void fsl_mc_check(struct mem_ctl_info *mci) int bad_data_bit; int bad_ecc_bit; - err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); + err_detect = ddr_in32(pdata, FSL_MC_ERR_DETECT); if (!err_detect) return; @@ -295,14 +307,14 @@ static void fsl_mc_check(struct mem_ctl_info *mci) /* no more processing if not ECC bit errors */ if (!(err_detect & (DDR_EDE_SBE | DDR_EDE_MBE))) { - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); + ddr_out32(pdata, FSL_MC_ERR_DETECT, err_detect); return; } - syndrome = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ECC); + syndrome = ddr_in32(pdata, FSL_MC_CAPTURE_ECC); /* Mask off appropriate bits of syndrome based on bus width */ - bus_width = (ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG) & + bus_width = (ddr_in32(pdata, FSL_MC_DDR_SDRAM_CFG) & DSC_DBW_MASK) ? 32 : 64; if (bus_width == 64) syndrome &= 0xff; @@ -310,8 +322,8 @@ static void fsl_mc_check(struct mem_ctl_info *mci) syndrome &= 0xffff; err_addr = make64( - ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_EXT_ADDRESS), - ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_ADDRESS)); + ddr_in32(pdata, FSL_MC_CAPTURE_EXT_ADDRESS), + ddr_in32(pdata, FSL_MC_CAPTURE_ADDRESS)); pfn = err_addr >> PAGE_SHIFT; for (row_index = 0; row_index < mci->nr_csrows; row_index++) { @@ -320,29 +332,33 @@ static void fsl_mc_check(struct mem_ctl_info *mci) break; } - cap_high = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_HI); - cap_low = ddr_in32(pdata->mc_vbase + FSL_MC_CAPTURE_DATA_LO); + cap_high = ddr_in32(pdata, FSL_MC_CAPTURE_DATA_HI); + cap_low = ddr_in32(pdata, FSL_MC_CAPTURE_DATA_LO); /* * Analyze single-bit errors on 64-bit wide buses * TODO: Add support for 32-bit wide buses */ if ((err_detect & DDR_EDE_SBE) && (bus_width == 64)) { + u64 cap = (u64)cap_high << 32 | cap_low; + u32 s = syndrome; + sbe_ecc_decode(cap_high, cap_low, syndrome, &bad_data_bit, &bad_ecc_bit); - if (bad_data_bit != -1) - fsl_mc_printk(mci, KERN_ERR, - "Faulty Data bit: %d\n", bad_data_bit); - if (bad_ecc_bit != -1) - fsl_mc_printk(mci, KERN_ERR, - "Faulty ECC bit: %d\n", bad_ecc_bit); + if (bad_data_bit >= 0) { + fsl_mc_printk(mci, KERN_ERR, "Faulty Data bit: %d\n", bad_data_bit); + cap ^= 1ULL << bad_data_bit; + } + + if (bad_ecc_bit >= 0) { + fsl_mc_printk(mci, KERN_ERR, "Faulty ECC bit: %d\n", bad_ecc_bit); + s ^= 1 << bad_ecc_bit; + } fsl_mc_printk(mci, KERN_ERR, "Expected Data / ECC:\t%#8.8x_%08x / %#2.2x\n", - cap_high ^ (1 << (bad_data_bit - 32)), - cap_low ^ (1 << bad_data_bit), - syndrome ^ (1 << bad_ecc_bit)); + upper_32_bits(cap), lower_32_bits(cap), s); } fsl_mc_printk(mci, KERN_ERR, @@ -367,7 +383,7 @@ static void fsl_mc_check(struct mem_ctl_info *mci) row_index, 0, -1, mci->ctl_name, ""); - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, err_detect); + ddr_out32(pdata, FSL_MC_ERR_DETECT, err_detect); } static irqreturn_t fsl_mc_isr(int irq, void *dev_id) @@ -376,7 +392,7 @@ static irqreturn_t fsl_mc_isr(int irq, void *dev_id) struct fsl_mc_pdata *pdata = mci->pvt_info; u32 err_detect; - err_detect = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DETECT); + err_detect = ddr_in32(pdata, FSL_MC_ERR_DETECT); if (!err_detect) return IRQ_NONE; @@ -396,7 +412,7 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) u32 cs_bnds; int index; - sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); + sdram_ctl = ddr_in32(pdata, FSL_MC_DDR_SDRAM_CFG); sdtype = sdram_ctl & DSC_SDTYPE_MASK; if (sdram_ctl & DSC_RD_EN) { @@ -431,6 +447,9 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) case 0x05000000: mtype = MEM_DDR4; break; + case 0x04000000: + mtype = MEM_LPDDR4; + break; default: mtype = MEM_UNKNOWN; break; @@ -444,7 +463,7 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) csrow = mci->csrows[index]; dimm = csrow->channels[0]->dimm; - cs_bnds = ddr_in32(pdata->mc_vbase + FSL_MC_CS_BNDS_0 + + cs_bnds = ddr_in32(pdata, FSL_MC_CS_BNDS_0 + (index * FSL_MC_CS_BNDS_OFS)); start = (cs_bnds & 0xffff0000) >> 16; @@ -464,7 +483,9 @@ static void fsl_ddr_init_csrows(struct mem_ctl_info *mci) dimm->grain = 8; dimm->mtype = mtype; dimm->dtype = DEV_UNKNOWN; - if (sdram_ctl & DSC_X32_EN) + if (pdata->flag == TYPE_IMX9) + dimm->dtype = DEV_X16; + else if (sdram_ctl & DSC_X32_EN) dimm->dtype = DEV_X32; dimm->edac_mode = EDAC_SECDED; } @@ -476,6 +497,7 @@ int fsl_mc_err_probe(struct platform_device *op) struct edac_mc_layer layers[2]; struct fsl_mc_pdata *pdata; struct resource r; + u32 ecc_en_mask; u32 sdram_ctl; int res; @@ -503,11 +525,13 @@ int fsl_mc_err_probe(struct platform_device *op) mci->ctl_name = pdata->name; mci->dev_name = pdata->name; + pdata->flag = (unsigned long)device_get_match_data(&op->dev); + /* * Get the endianness of DDR controller registers. * Default is big endian. */ - little_endian = of_property_read_bool(op->dev.of_node, "little-endian"); + pdata->little_endian = of_property_read_bool(op->dev.of_node, "little-endian"); res = of_address_to_resource(op->dev.of_node, 0, &r); if (res) { @@ -531,8 +555,23 @@ int fsl_mc_err_probe(struct platform_device *op) goto err; } - sdram_ctl = ddr_in32(pdata->mc_vbase + FSL_MC_DDR_SDRAM_CFG); - if (!(sdram_ctl & DSC_ECC_EN)) { + if (pdata->flag == TYPE_IMX9) { + pdata->inject_vbase = devm_platform_ioremap_resource_byname(op, "inject"); + if (IS_ERR(pdata->inject_vbase)) { + res = -ENOMEM; + goto err; + } + } + + if (pdata->flag == TYPE_IMX9) { + sdram_ctl = ddr_in32(pdata, IMX9_MC_ERR_EN); + ecc_en_mask = ERR_ECC_EN | ERR_INLINE_ECC; + } else { + sdram_ctl = ddr_in32(pdata, FSL_MC_DDR_SDRAM_CFG); + ecc_en_mask = DSC_ECC_EN; + } + + if ((sdram_ctl & ecc_en_mask) != ecc_en_mask) { /* no ECC */ pr_warn("%s: No ECC DIMMs discovered\n", __func__); res = -ENODEV; @@ -543,7 +582,8 @@ int fsl_mc_err_probe(struct platform_device *op) mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR | MEM_FLAG_DDR2 | MEM_FLAG_RDDR2 | MEM_FLAG_DDR3 | MEM_FLAG_RDDR3 | - MEM_FLAG_DDR4 | MEM_FLAG_RDDR4; + MEM_FLAG_DDR4 | MEM_FLAG_RDDR4 | + MEM_FLAG_LPDDR4; mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; mci->edac_cap = EDAC_FLAG_SECDED; mci->mod_name = EDAC_MOD_STR; @@ -558,11 +598,11 @@ int fsl_mc_err_probe(struct platform_device *op) fsl_ddr_init_csrows(mci); /* store the original error disable bits */ - orig_ddr_err_disable = ddr_in32(pdata->mc_vbase + FSL_MC_ERR_DISABLE); - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, 0); + pdata->orig_ddr_err_disable = ddr_in32(pdata, FSL_MC_ERR_DISABLE); + ddr_out32(pdata, FSL_MC_ERR_DISABLE, 0); /* clear all error bits */ - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DETECT, ~0); + ddr_out32(pdata, FSL_MC_ERR_DETECT, ~0); res = edac_mc_add_mc_with_groups(mci, fsl_ddr_dev_groups); if (res) { @@ -571,15 +611,15 @@ int fsl_mc_err_probe(struct platform_device *op) } if (edac_op_state == EDAC_OPSTATE_INT) { - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, + ddr_out32(pdata, FSL_MC_ERR_INT_EN, DDR_EIE_MBEE | DDR_EIE_SBEE); /* store the original error management threshold */ - orig_ddr_err_sbe = ddr_in32(pdata->mc_vbase + - FSL_MC_ERR_SBE) & 0xff0000; + pdata->orig_ddr_err_sbe = ddr_in32(pdata, + FSL_MC_ERR_SBE) & 0xff0000; /* set threshold to 1 error per interrupt */ - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, 0x10000); + ddr_out32(pdata, FSL_MC_ERR_SBE, 0x10000); /* register interrupts */ pdata->irq = platform_get_irq(op, 0); @@ -620,12 +660,13 @@ void fsl_mc_err_remove(struct platform_device *op) edac_dbg(0, "\n"); if (edac_op_state == EDAC_OPSTATE_INT) { - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_INT_EN, 0); + ddr_out32(pdata, FSL_MC_ERR_INT_EN, 0); } - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_DISABLE, - orig_ddr_err_disable); - ddr_out32(pdata->mc_vbase + FSL_MC_ERR_SBE, orig_ddr_err_sbe); + ddr_out32(pdata, FSL_MC_ERR_DISABLE, + pdata->orig_ddr_err_disable); + ddr_out32(pdata, FSL_MC_ERR_SBE, pdata->orig_ddr_err_sbe); + edac_mc_del_mc(&op->dev); edac_mc_free(mci); diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h index c0994a2a003c28..73618f79e587f9 100644 --- a/drivers/edac/fsl_ddr_edac.h +++ b/drivers/edac/fsl_ddr_edac.h @@ -39,6 +39,9 @@ #define FSL_MC_CAPTURE_EXT_ADDRESS 0x0e54 #define FSL_MC_ERR_SBE 0x0e58 +#define IMX9_MC_ERR_EN 0x1000 +#define IMX9_MC_DATA_ERR_INJECT_OFF 0x100 + #define DSC_MEM_EN 0x80000000 #define DSC_ECC_EN 0x20000000 #define DSC_RD_EN 0x10000000 @@ -46,6 +49,9 @@ #define DSC_DBW_32 0x00080000 #define DSC_DBW_64 0x00000000 +#define ERR_ECC_EN 0x80000000 +#define ERR_INLINE_ECC 0x40000000 + #define DSC_SDTYPE_MASK 0x07000000 #define DSC_X32_EN 0x00000020 @@ -65,11 +71,18 @@ #define DDR_EDI_SBED 0x4 /* single-bit ECC error disable */ #define DDR_EDI_MBED 0x8 /* multi-bit ECC error disable */ +#define TYPE_IMX9 0x1 /* MC used by iMX9 having registers changed */ + struct fsl_mc_pdata { char *name; int edac_idx; void __iomem *mc_vbase; + void __iomem *inject_vbase; int irq; + u32 orig_ddr_err_disable; + u32 orig_ddr_err_sbe; + bool little_endian; + unsigned long flag; }; int fsl_mc_err_probe(struct platform_device *op); void fsl_mc_err_remove(struct platform_device *op); diff --git a/drivers/edac/highbank_l2_edac.c b/drivers/edac/highbank_l2_edac.c index 282ca6535f8f63..24f163ff323f6a 100644 --- a/drivers/edac/highbank_l2_edac.c +++ b/drivers/edac/highbank_l2_edac.c @@ -128,7 +128,7 @@ static void highbank_l2_err_remove(struct platform_device *pdev) static struct platform_driver highbank_l2_edac_driver = { .probe = highbank_l2_err_probe, - .remove_new = highbank_l2_err_remove, + .remove = highbank_l2_err_remove, .driver = { .name = "hb_l2_edac", .of_match_table = hb_l2_err_of_match, diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c index 1c5b888ab11de3..a8879d72d064a0 100644 --- a/drivers/edac/highbank_mc_edac.c +++ b/drivers/edac/highbank_mc_edac.c @@ -261,7 +261,7 @@ static void highbank_mc_remove(struct platform_device *pdev) static struct platform_driver highbank_mc_edac_driver = { .probe = highbank_mc_probe, - .remove_new = highbank_mc_remove, + .remove = highbank_mc_remove, .driver = { .name = "hb_mc_edac", .of_match_table = hb_ddr_ctrl_of_match, diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index e2a954de913b42..51556c72a96746 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -1036,6 +1036,7 @@ static int __init i10nm_init(void) return -ENODEV; cfg = (struct res_config *)id->driver_data; + skx_set_res_cfg(cfg); res_cfg = cfg; rc = skx_get_hi_lo(0x09a2, off, &tolm, &tohm); diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c index 9ef13570f2e540..4fc16922dc1af5 100644 --- a/drivers/edac/ie31200_edac.c +++ b/drivers/edac/ie31200_edac.c @@ -19,7 +19,8 @@ * 0c04: Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller * 0c08: Xeon E3-1200 v3 Processor DRAM Controller * 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers - * 5918: Xeon E3-1200 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers + * 590f: Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers + * 5918: Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers * 190f: 6th Gen Core Dual-Core Processor Host Bridge/DRAM Registers * 191f: 6th Gen Core Quad-Core Processor Host Bridge/DRAM Registers * 3e..: 8th/9th Gen Core Processor Host Bridge/DRAM Registers @@ -67,7 +68,8 @@ #define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x190F #define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x1918 #define PCI_DEVICE_ID_INTEL_IE31200_HB_10 0x191F -#define PCI_DEVICE_ID_INTEL_IE31200_HB_11 0x5918 +#define PCI_DEVICE_ID_INTEL_IE31200_HB_11 0x590f +#define PCI_DEVICE_ID_INTEL_IE31200_HB_12 0x5918 /* Coffee Lake-S */ #define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK 0x3e00 @@ -88,6 +90,7 @@ ((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_9) || \ ((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_10) || \ ((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_11) || \ + ((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_12) || \ (((did) & PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK) == \ PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK)) @@ -587,6 +590,7 @@ static const struct pci_device_id ie31200_pci_tbl[] = { { PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, { PCI_VEND_DEV(INTEL, IE31200_HB_10), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, { PCI_VEND_DEV(INTEL, IE31200_HB_11), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, + { PCI_VEND_DEV(INTEL, IE31200_HB_12), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, { PCI_VEND_DEV(INTEL, IE31200_HB_CFL_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 }, diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index 189a2fc29e74f5..fdf3a84fe6988b 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -263,6 +263,11 @@ static struct work_struct ecclog_work; #define DID_ARL_UH_SKU2 0x7d20 #define DID_ARL_UH_SKU3 0x7d30 +/* Compute die IDs for Panther Lake-H with IBECC */ +#define DID_PTL_H_SKU1 0xb000 +#define DID_PTL_H_SKU2 0xb001 +#define DID_PTL_H_SKU3 0xb002 + static int get_mchbar(struct pci_dev *pdev, u64 *mchbar) { union { @@ -605,6 +610,9 @@ static const struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU1), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU2), (kernel_ulong_t)&mtl_p_cfg }, { PCI_VDEVICE(INTEL, DID_ARL_UH_SKU3), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU1), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU2), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_PTL_H_SKU3), (kernel_ulong_t)&mtl_p_cfg }, { }, }; MODULE_DEVICE_TABLE(pci, igen6_pci_tbl); @@ -1170,6 +1178,20 @@ static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar) return -ENODEV; } +static void igen6_check(struct mem_ctl_info *mci) +{ + struct igen6_imc *imc = mci->pvt_info; + u64 ecclog; + + /* errsts_clear() isn't NMI-safe. Delay it in the IRQ context */ + ecclog = ecclog_read_and_clear(imc); + if (!ecclog) + return; + + if (!ecclog_gen_pool_add(imc->mc, ecclog)) + irq_work_queue(&ecclog_irq_work); +} + static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev) { struct edac_mc_layer layers[2]; @@ -1211,6 +1233,8 @@ static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev) mci->edac_cap = EDAC_FLAG_SECDED; mci->mod_name = EDAC_MOD_STR; mci->dev_name = pci_name(pdev); + if (edac_op_state == EDAC_OPSTATE_POLL) + mci->edac_check = igen6_check; mci->pvt_info = &igen6_pvt->imc[mc]; imc = mci->pvt_info; @@ -1245,6 +1269,7 @@ static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev) imc->mci = mci; return 0; fail3: + mci->pvt_info = NULL; kfree(mci->ctl_name); fail2: edac_mc_free(mci); @@ -1269,6 +1294,7 @@ static void igen6_unregister_mcis(void) edac_mc_del_mc(mci->pdev); kfree(mci->ctl_name); + mci->pvt_info = NULL; edac_mc_free(mci); iounmap(imc->window); } @@ -1348,6 +1374,25 @@ static void unregister_err_handler(void) unregister_nmi_handler(NMI_SERR, IGEN6_NMI_NAME); } +static void opstate_set(struct res_config *cfg, const struct pci_device_id *ent) +{ + /* + * Quirk: Certain SoCs' error reporting interrupts don't work. + * Force polling mode for them to ensure that memory error + * events can be handled. + */ + if (ent->device == DID_ADL_N_SKU4) { + edac_op_state = EDAC_OPSTATE_POLL; + return; + } + + /* Set the mode according to the configuration data. */ + if (cfg->machine_check) + edac_op_state = EDAC_OPSTATE_INT; + else + edac_op_state = EDAC_OPSTATE_NMI; +} + static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u64 mchbar; @@ -1365,6 +1410,8 @@ static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto fail; + opstate_set(res_cfg, ent); + for (i = 0; i < res_cfg->num_imc; i++) { rc = igen6_register_mci(i, mchbar, pdev); if (rc) @@ -1448,8 +1495,6 @@ static int __init igen6_init(void) if (owner && strncmp(owner, EDAC_MOD_STR, sizeof(EDAC_MOD_STR))) return -EBUSY; - edac_op_state = EDAC_OPSTATE_NMI; - rc = pci_register_driver(&igen6_driver); if (rc) return rc; diff --git a/drivers/edac/layerscape_edac.c b/drivers/edac/layerscape_edac.c index 0d42c1238908bd..a2caa7fc54122d 100644 --- a/drivers/edac/layerscape_edac.c +++ b/drivers/edac/layerscape_edac.c @@ -21,13 +21,14 @@ static const struct of_device_id fsl_ddr_mc_err_of_match[] = { { .compatible = "fsl,qoriq-memory-controller", }, + { .compatible = "nxp,imx9-memory-controller", .data = (void *)TYPE_IMX9, }, {}, }; MODULE_DEVICE_TABLE(of, fsl_ddr_mc_err_of_match); static struct platform_driver fsl_ddr_mc_err_driver = { .probe = fsl_mc_err_probe, - .remove_new = fsl_mc_err_remove, + .remove = fsl_mc_err_remove, .driver = { .name = "fsl_ddr_mc_err", .of_match_table = fsl_ddr_mc_err_of_match, diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 8130c3dc64da56..50d74d3bf0f55f 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -793,7 +793,9 @@ static int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) { struct mce *m = (struct mce *)data; + struct mce_hw_err *err = to_mce_hw_err(m); unsigned int fam = x86_family(m->cpuid); + u32 mca_config_lo = 0, dummy; int ecc; if (m->kflags & MCE_HANDLED_CEC) @@ -813,11 +815,9 @@ amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) ((m->status & MCI_STATUS_PCC) ? "PCC" : "-")); if (boot_cpu_has(X86_FEATURE_SMCA)) { - u32 low, high; - u32 addr = MSR_AMD64_SMCA_MCx_CONFIG(m->bank); + rdmsr_safe(MSR_AMD64_SMCA_MCx_CONFIG(m->bank), &mca_config_lo, &dummy); - if (!rdmsr_safe(addr, &low, &high) && - (low & MCI_CONFIG_MCAX)) + if (mca_config_lo & MCI_CONFIG_MCAX) pr_cont("|%s", ((m->status & MCI_STATUS_TCC) ? "TCC" : "-")); pr_cont("|%s", ((m->status & MCI_STATUS_SYNDV) ? "SyndV" : "-")); @@ -850,8 +850,18 @@ amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) if (boot_cpu_has(X86_FEATURE_SMCA)) { pr_emerg(HW_ERR "IPID: 0x%016llx", m->ipid); - if (m->status & MCI_STATUS_SYNDV) - pr_cont(", Syndrome: 0x%016llx", m->synd); + if (m->status & MCI_STATUS_SYNDV) { + pr_cont(", Syndrome: 0x%016llx\n", m->synd); + if (mca_config_lo & MCI_CONFIG_FRUTEXT) { + char frutext[17]; + + frutext[16] = '\0'; + memcpy(&frutext[0], &err->vendor.amd.synd1, 8); + memcpy(&frutext[8], &err->vendor.amd.synd2, 8); + + pr_emerg(HW_ERR "FRU Text: %s", frutext); + } + } pr_cont("\n"); diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index d0266cbcbeda77..a45dc6b35edefe 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -323,7 +323,7 @@ static const struct platform_device_id mpc85xx_pci_err_match[] = { static struct platform_driver mpc85xx_pci_err_driver = { .probe = mpc85xx_pci_err_probe, - .remove_new = mpc85xx_pci_err_remove, + .remove = mpc85xx_pci_err_remove, .id_table = mpc85xx_pci_err_match, .driver = { .name = "mpc85xx_pci_err", @@ -627,7 +627,7 @@ MODULE_DEVICE_TABLE(of, mpc85xx_l2_err_of_match); static struct platform_driver mpc85xx_l2_err_driver = { .probe = mpc85xx_l2_err_probe, - .remove_new = mpc85xx_l2_err_remove, + .remove = mpc85xx_l2_err_remove, .driver = { .name = "mpc85xx_l2_err", .of_match_table = mpc85xx_l2_err_of_match, @@ -656,7 +656,7 @@ MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match); static struct platform_driver mpc85xx_mc_err_driver = { .probe = fsl_mc_err_probe, - .remove_new = fsl_mc_err_remove, + .remove = fsl_mc_err_remove, .driver = { .name = "mpc85xx_mc_err", .of_match_table = mpc85xx_mc_err_of_match, diff --git a/drivers/edac/npcm_edac.c b/drivers/edac/npcm_edac.c index 2e2133b784e922..e60a99eb8cfbb5 100644 --- a/drivers/edac/npcm_edac.c +++ b/drivers/edac/npcm_edac.c @@ -531,7 +531,7 @@ static struct platform_driver npcm_edac_driver = { .of_match_table = npcm_edac_of_match, }, .probe = edac_probe, - .remove_new = edac_remove, + .remove = edac_remove, }; module_platform_driver(npcm_edac_driver); diff --git a/drivers/edac/octeon_edac-l2c.c b/drivers/edac/octeon_edac-l2c.c index 2adb9c8093f86b..e6b1595a3cb586 100644 --- a/drivers/edac/octeon_edac-l2c.c +++ b/drivers/edac/octeon_edac-l2c.c @@ -194,7 +194,7 @@ static void octeon_l2c_remove(struct platform_device *pdev) static struct platform_driver octeon_l2c_driver = { .probe = octeon_l2c_probe, - .remove_new = octeon_l2c_remove, + .remove = octeon_l2c_remove, .driver = { .name = "octeon_l2c_edac", } diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c index 4112c2ee34b86f..f7176b95b4feeb 100644 --- a/drivers/edac/octeon_edac-lmc.c +++ b/drivers/edac/octeon_edac-lmc.c @@ -312,7 +312,7 @@ static void octeon_lmc_edac_remove(struct platform_device *pdev) static struct platform_driver octeon_lmc_edac_driver = { .probe = octeon_lmc_edac_probe, - .remove_new = octeon_lmc_edac_remove, + .remove = octeon_lmc_edac_remove, .driver = { .name = "octeon_lmc_edac", } diff --git a/drivers/edac/octeon_edac-pc.c b/drivers/edac/octeon_edac-pc.c index d9eeb40d2784c7..aa1219db0b1726 100644 --- a/drivers/edac/octeon_edac-pc.c +++ b/drivers/edac/octeon_edac-pc.c @@ -130,7 +130,7 @@ static void co_cache_error_remove(struct platform_device *pdev) static struct platform_driver co_cache_error_driver = { .probe = co_cache_error_probe, - .remove_new = co_cache_error_remove, + .remove = co_cache_error_remove, .driver = { .name = "octeon_pc_edac", } diff --git a/drivers/edac/octeon_edac-pci.c b/drivers/edac/octeon_edac-pci.c index 4d368af2c5f0c6..c4f3bc33a97148 100644 --- a/drivers/edac/octeon_edac-pci.c +++ b/drivers/edac/octeon_edac-pci.c @@ -97,7 +97,7 @@ static void octeon_pci_remove(struct platform_device *pdev) static struct platform_driver octeon_pci_driver = { .probe = octeon_pci_probe, - .remove_new = octeon_pci_remove, + .remove = octeon_pci_remove, .driver = { .name = "octeon_pci_edac", } diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c index a9a8ba067007a9..04c42c83a2bad5 100644 --- a/drivers/edac/qcom_edac.c +++ b/drivers/edac/qcom_edac.c @@ -407,7 +407,7 @@ MODULE_DEVICE_TABLE(platform, qcom_llcc_edac_id_table); static struct platform_driver qcom_llcc_edac_driver = { .probe = qcom_llcc_edac_probe, - .remove_new = qcom_llcc_edac_remove, + .remove = qcom_llcc_edac_remove, .driver = { .name = "qcom_llcc_edac", }, diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index 85713646957b3e..6cf17af7d9112b 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -47,6 +47,7 @@ static skx_show_retry_log_f skx_show_retry_rd_err_log; static u64 skx_tolm, skx_tohm; static LIST_HEAD(dev_edac_list); static bool skx_mem_cfg_2lm; +static struct res_config *skx_res_cfg; int skx_adxl_get(void) { @@ -119,7 +120,7 @@ void skx_adxl_put(void) } EXPORT_SYMBOL_GPL(skx_adxl_put); -static bool skx_adxl_decode(struct decoded_addr *res, bool error_in_1st_level_mem) +static bool skx_adxl_decode(struct decoded_addr *res, enum error_source err_src) { struct skx_dev *d; int i, len = 0; @@ -135,8 +136,24 @@ static bool skx_adxl_decode(struct decoded_addr *res, bool error_in_1st_level_me return false; } + /* + * GNR with a Flat2LM memory configuration may mistakenly classify + * a near-memory error(DDR5) as a far-memory error(CXL), resulting + * in the incorrect selection of decoded ADXL components. + * To address this, prefetch the decoded far-memory controller ID + * and adjust the error source to near-memory if the far-memory + * controller ID is invalid. + */ + if (skx_res_cfg && skx_res_cfg->type == GNR && err_src == ERR_SRC_2LM_FM) { + res->imc = (int)adxl_values[component_indices[INDEX_MEMCTRL]]; + if (res->imc == -1) { + err_src = ERR_SRC_2LM_NM; + edac_dbg(0, "Adjust the error source to near-memory.\n"); + } + } + res->socket = (int)adxl_values[component_indices[INDEX_SOCKET]]; - if (error_in_1st_level_mem) { + if (err_src == ERR_SRC_2LM_NM) { res->imc = (adxl_nm_bitmap & BIT_NM_MEMCTRL) ? (int)adxl_values[component_indices[INDEX_NM_MEMCTRL]] : -1; res->channel = (adxl_nm_bitmap & BIT_NM_CHANNEL) ? @@ -191,6 +208,12 @@ void skx_set_mem_cfg(bool mem_cfg_2lm) } EXPORT_SYMBOL_GPL(skx_set_mem_cfg); +void skx_set_res_cfg(struct res_config *cfg) +{ + skx_res_cfg = cfg; +} +EXPORT_SYMBOL_GPL(skx_set_res_cfg); + void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log) { driver_decode = decode; @@ -620,31 +643,27 @@ static void skx_mce_output_error(struct mem_ctl_info *mci, optype, skx_msg); } -static bool skx_error_in_1st_level_mem(const struct mce *m) +static enum error_source skx_error_source(const struct mce *m) { - u32 errcode; + u32 errcode = GET_BITFIELD(m->status, 0, 15) & MCACOD_MEM_ERR_MASK; - if (!skx_mem_cfg_2lm) - return false; - - errcode = GET_BITFIELD(m->status, 0, 15) & MCACOD_MEM_ERR_MASK; - - return errcode == MCACOD_EXT_MEM_ERR; -} + if (errcode != MCACOD_MEM_CTL_ERR && errcode != MCACOD_EXT_MEM_ERR) + return ERR_SRC_NOT_MEMORY; -static bool skx_error_in_mem(const struct mce *m) -{ - u32 errcode; + if (!skx_mem_cfg_2lm) + return ERR_SRC_1LM; - errcode = GET_BITFIELD(m->status, 0, 15) & MCACOD_MEM_ERR_MASK; + if (errcode == MCACOD_EXT_MEM_ERR) + return ERR_SRC_2LM_NM; - return (errcode == MCACOD_MEM_CTL_ERR || errcode == MCACOD_EXT_MEM_ERR); + return ERR_SRC_2LM_FM; } int skx_mce_check_error(struct notifier_block *nb, unsigned long val, void *data) { struct mce *mce = (struct mce *)data; + enum error_source err_src; struct decoded_addr res; struct mem_ctl_info *mci; char *type; @@ -652,8 +671,10 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val, if (mce->kflags & MCE_HANDLED_CEC) return NOTIFY_DONE; + err_src = skx_error_source(mce); + /* Ignore unless this is memory related with an address */ - if (!skx_error_in_mem(mce) || !(mce->status & MCI_STATUS_ADDRV)) + if (err_src == ERR_SRC_NOT_MEMORY || !(mce->status & MCI_STATUS_ADDRV)) return NOTIFY_DONE; memset(&res, 0, sizeof(res)); @@ -667,7 +688,7 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val, /* Try driver decoder first */ if (!(driver_decode && driver_decode(&res))) { /* Then try firmware decoder (ACPI DSM methods) */ - if (!(adxl_component_count && skx_adxl_decode(&res, skx_error_in_1st_level_mem(mce)))) + if (!(adxl_component_count && skx_adxl_decode(&res, err_src))) return NOTIFY_DONE; } diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index f945c1bf5ca465..54bba8a62f727c 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -146,6 +146,13 @@ enum { INDEX_MAX }; +enum error_source { + ERR_SRC_1LM, + ERR_SRC_2LM_NM, + ERR_SRC_2LM_FM, + ERR_SRC_NOT_MEMORY, +}; + #define BIT_NM_MEMCTRL BIT_ULL(INDEX_NM_MEMCTRL) #define BIT_NM_CHANNEL BIT_ULL(INDEX_NM_CHANNEL) #define BIT_NM_DIMM BIT_ULL(INDEX_NM_DIMM) @@ -234,6 +241,7 @@ int skx_adxl_get(void); void skx_adxl_put(void); void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log); void skx_set_mem_cfg(bool mem_cfg_2lm); +void skx_set_res_cfg(struct res_config *cfg); int skx_get_src_id(struct skx_dev *d, int off, u8 *id); int skx_get_node_id(struct skx_dev *d, u8 *id); diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index d7416166fd8a42..5ed32a3299c44e 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -1488,7 +1488,7 @@ static struct platform_driver synps_edac_mc_driver = { .of_match_table = synps_edac_match, }, .probe = mc_probe, - .remove_new = mc_remove, + .remove = mc_remove, }; module_platform_driver(synps_edac_mc_driver); diff --git a/drivers/edac/ti_edac.c b/drivers/edac/ti_edac.c index 29723c9592f79e..39cc2ef9cac429 100644 --- a/drivers/edac/ti_edac.c +++ b/drivers/edac/ti_edac.c @@ -322,7 +322,7 @@ static void ti_edac_remove(struct platform_device *pdev) static struct platform_driver ti_edac_driver = { .probe = ti_edac_probe, - .remove_new = ti_edac_remove, + .remove = ti_edac_remove, .driver = { .name = EDAC_MOD_NAME, .of_match_table = ti_edac_of_match, diff --git a/drivers/edac/versal_edac.c b/drivers/edac/versal_edac.c index a556d23e8261c6..5a43b5d43ca280 100644 --- a/drivers/edac/versal_edac.c +++ b/drivers/edac/versal_edac.c @@ -1186,7 +1186,7 @@ static struct platform_driver xilinx_ddr_edac_mc_driver = { .of_match_table = xlnx_edac_match, }, .probe = mc_probe, - .remove_new = mc_remove, + .remove = mc_remove, }; module_platform_driver(xilinx_ddr_edac_mc_driver); diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c index fd87f1b2c1453e..699c7d29d80cd6 100644 --- a/drivers/edac/xgene_edac.c +++ b/drivers/edac/xgene_edac.c @@ -1989,7 +1989,7 @@ MODULE_DEVICE_TABLE(of, xgene_edac_of_match); static struct platform_driver xgene_edac_driver = { .probe = xgene_edac_probe, - .remove_new = xgene_edac_remove, + .remove = xgene_edac_remove, .driver = { .name = "xgene-edac", .of_match_table = xgene_edac_of_match, diff --git a/drivers/edac/zynqmp_edac.c b/drivers/edac/zynqmp_edac.c index c9dc78d8c824f5..cdffc9e4194d42 100644 --- a/drivers/edac/zynqmp_edac.c +++ b/drivers/edac/zynqmp_edac.c @@ -455,7 +455,7 @@ static struct platform_driver zynqmp_ocm_edac_driver = { .of_match_table = zynqmp_ocm_edac_match, }, .probe = edac_probe, - .remove_new = edac_remove, + .remove = edac_remove, }; module_platform_driver(zynqmp_ocm_edac_driver); diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 125016da7fde3f..46c40d85c2ac89 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -196,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(adc_jack_pm_ops, static struct platform_driver adc_jack_driver = { .probe = adc_jack_probe, - .remove_new = adc_jack_remove, + .remove = adc_jack_remove, .driver = { .name = "adc-jack", .pm = &adc_jack_pm_ops, diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 93552dc3c895c6..8131a3d7d5620d 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -627,7 +627,7 @@ MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table); static struct platform_driver cht_wc_extcon_driver = { .probe = cht_wc_extcon_probe, - .remove_new = cht_wc_extcon_remove, + .remove = cht_wc_extcon_remove, .id_table = cht_wc_extcon_table, .driver = { .name = "cht_wcove_pwrsrc", diff --git a/drivers/extcon/extcon-intel-mrfld.c b/drivers/extcon/extcon-intel-mrfld.c index a1f737f13d4991..9219f4328d70af 100644 --- a/drivers/extcon/extcon-intel-mrfld.c +++ b/drivers/extcon/extcon-intel-mrfld.c @@ -275,7 +275,7 @@ static struct platform_driver mrfld_extcon_driver = { .name = "mrfld_bcove_pwrsrc", }, .probe = mrfld_extcon_probe, - .remove_new = mrfld_extcon_remove, + .remove = mrfld_extcon_remove, .id_table = mrfld_extcon_id_table, }; module_platform_driver(mrfld_extcon_driver); diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c index e62ce7a8d1317c..b2ee4ff8b04d2b 100644 --- a/drivers/extcon/extcon-max3355.c +++ b/drivers/extcon/extcon-max3355.c @@ -127,7 +127,7 @@ MODULE_DEVICE_TABLE(of, max3355_match_table); static struct platform_driver max3355_driver = { .probe = max3355_probe, - .remove_new = max3355_remove, + .remove = max3355_remove, .driver = { .name = "extcon-max3355", .of_match_table = max3355_match_table, diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index 9849e3b8327edc..2ae9f7f1a67fc2 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -956,7 +956,7 @@ static struct platform_driver max77843_muic_driver = { .of_match_table = of_max77843_muic_dt_match, }, .probe = max77843_muic_probe, - .remove_new = max77843_muic_remove, + .remove = max77843_muic_remove, .id_table = max77843_muic_id, }; diff --git a/drivers/extcon/extcon-rtk-type-c.c b/drivers/extcon/extcon-rtk-type-c.c index 19a01e66373304..bdc2b7b3a24656 100644 --- a/drivers/extcon/extcon-rtk-type-c.c +++ b/drivers/extcon/extcon-rtk-type-c.c @@ -1778,7 +1778,7 @@ static const struct dev_pm_ops extcon_rtk_type_c_pm_ops = { static struct platform_driver extcon_rtk_type_c_driver = { .probe = extcon_rtk_type_c_probe, - .remove_new = extcon_rtk_type_c_remove, + .remove = extcon_rtk_type_c_remove, .driver = { .name = "extcon-rtk-type_c", .of_match_table = extcon_rtk_type_c_match, diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 9b61eb99b7dc95..5e8ad21ad206b8 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -279,7 +279,7 @@ MODULE_DEVICE_TABLE(platform, usb_extcon_platform_ids); static struct platform_driver usb_extcon_driver = { .probe = usb_extcon_probe, - .remove_new = usb_extcon_remove, + .remove = usb_extcon_remove, .driver = { .name = "extcon-usb-gpio", .pm = &usb_extcon_pm_ops, diff --git a/drivers/extcon/extcon-usbc-cros-ec.c b/drivers/extcon/extcon-usbc-cros-ec.c index 805a47230689d2..1fb627ea8b508f 100644 --- a/drivers/extcon/extcon-usbc-cros-ec.c +++ b/drivers/extcon/extcon-usbc-cros-ec.c @@ -529,7 +529,7 @@ static struct platform_driver extcon_cros_ec_driver = { .of_match_table = of_match_ptr(extcon_cros_ec_of_match), .pm = DEV_PM_OPS, }, - .remove_new = extcon_cros_ec_remove, + .remove = extcon_cros_ec_remove, .probe = extcon_cros_ec_probe, }; diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 892b94cfd62603..74a6aa7d8cc92c 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -56,7 +56,7 @@ static struct fw_node *fw_node_create(u32 sid, int port_count, int color) * two cases: either the path goes through this node, in which case * the hop count is the sum of the two biggest child depths plus 2. * Or it could be the case that the max hop path is entirely - * containted in a child tree, in which case the max hop count is just + * contained in a child tree, in which case the max hop count is just * the max hop count of this child. */ static void update_hop_count(struct fw_node *node) diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 0ae2c84ecafedb..9b298af1cac0b8 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -80,7 +80,7 @@ struct fw_card_driver { /* * Allow the specified node ID to do direct DMA out and in of * host memory. The card will disable this for all node when - * a bus reset happens, so driver need to reenable this after + * a bus reset happens, so driver need to re-enable this after * bus reset. Returns 0 on success, -ENODEV if the card * doesn't support this, -ESTALE if the generation doesn't * match. diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 7ee55c2804dedf..c02aed11b59020 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1384,7 +1384,7 @@ struct driver_data { }; /* - * This function apppends a packet to the DMA queue for transmission. + * This function appends a packet to the DMA queue for transmission. * Must always be called with the ochi->lock held to ensure proper * generation handling and locking around packet queue manipulation. */ @@ -2213,7 +2213,7 @@ static irqreturn_t irq_handler(int irq, void *data) if (unlikely(param_debug > 0)) { dev_notice_ratelimited(ohci->card.device, - "The debug parameter is superceded by tracepoints events, and deprecated."); + "The debug parameter is superseded by tracepoints events, and deprecated."); } /* @@ -2614,7 +2614,7 @@ static int ohci_set_config_rom(struct fw_card *card, * ConfigRomHeader and BusOptions doesn't honor the * noByteSwapData bit, so with a be32 config rom, the * controller will load be32 values in to these registers - * during the atomic update, even on litte endian + * during the atomic update, even on little endian * architectures. The workaround we use is to put a 0 in the * header quadlet; 0 is endian agnostic and means that the * config rom isn't ready yet. In the bus reset tasklet we @@ -3726,12 +3726,11 @@ static int pci_probe(struct pci_dev *dev, return -ENXIO; } - err = pcim_iomap_regions(dev, 1 << 0, ohci_driver_name); - if (err) { + ohci->registers = pcim_iomap_region(dev, 0, ohci_driver_name); + if (IS_ERR(ohci->registers)) { ohci_err(ohci, "request and map MMIO resource unavailable\n"); return -ENXIO; } - ohci->registers = pcim_iomap_table(dev)[0]; for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++) if ((ohci_quirks[i].vendor == dev->vendor) && diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c index eb17d03b66fec9..dfda5ffc14db72 100644 --- a/drivers/firmware/arm_ffa/bus.c +++ b/drivers/firmware/arm_ffa/bus.c @@ -187,13 +187,18 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) return valid; } -struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, - const struct ffa_ops *ops) +struct ffa_device * +ffa_device_register(const struct ffa_partition_info *part_info, + const struct ffa_ops *ops) { int id, ret; + uuid_t uuid; struct device *dev; struct ffa_device *ffa_dev; + if (!part_info) + return NULL; + id = ida_alloc_min(&ffa_bus_id, 1, GFP_KERNEL); if (id < 0) return NULL; @@ -210,9 +215,11 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); ffa_dev->id = id; - ffa_dev->vm_id = vm_id; + ffa_dev->vm_id = part_info->id; + ffa_dev->properties = part_info->properties; ffa_dev->ops = ops; - uuid_copy(&ffa_dev->uuid, uuid); + import_uuid(&uuid, (u8 *)part_info->uuid); + uuid_copy(&ffa_dev->uuid, &uuid); ret = device_register(&ffa_dev->dev); if (ret) { diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index b14cbdae94e82b..2c2ec3c35f1561 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -1387,7 +1387,6 @@ static struct notifier_block ffa_bus_nb = { static int ffa_setup_partitions(void) { int count, idx, ret; - uuid_t uuid; struct ffa_device *ffa_dev; struct ffa_dev_part_info *info; struct ffa_partition_info *pbuf, *tpbuf; @@ -1406,23 +1405,19 @@ static int ffa_setup_partitions(void) xa_init(&drv_info->partition_info); for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) { - import_uuid(&uuid, (u8 *)tpbuf->uuid); - /* Note that if the UUID will be uuid_null, that will require * ffa_bus_notifier() to find the UUID of this partition id * with help of ffa_device_match_uuid(). FF-A v1.1 and above * provides UUID here for each partition as part of the * discovery API and the same is passed. */ - ffa_dev = ffa_device_register(&uuid, tpbuf->id, &ffa_drv_ops); + ffa_dev = ffa_device_register(tpbuf, &ffa_drv_ops); if (!ffa_dev) { pr_err("%s: failed to register partition ID 0x%x\n", __func__, tpbuf->id); continue; } - ffa_dev->properties = tpbuf->properties; - if (drv_info->version > FFA_VERSION_1_0 && !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) ffa_mode_32bit_set(ffa_dev); diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index cdec50a698a106..48b12f81141ddc 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -31,6 +31,8 @@ #define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC) +#define SCMI_SHMEM_MAX_PAYLOAD_SIZE 104 + enum scmi_error_codes { SCMI_SUCCESS = 0, /* Success */ SCMI_ERR_SUPPORT = -1, /* Not supported */ @@ -165,6 +167,7 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id); * channel * @is_p2a: A flag to identify a channel as P2A (RX) * @rx_timeout_ms: The configured RX timeout in milliseconds. + * @max_msg_size: Maximum size of message payload. * @handle: Pointer to SCMI entity handle * @no_completion_irq: Flag to indicate that this channel has no completion * interrupt mechanism for synchronous commands. @@ -177,6 +180,7 @@ struct scmi_chan_info { struct device *dev; bool is_p2a; unsigned int rx_timeout_ms; + unsigned int max_msg_size; struct scmi_handle *handle; bool no_completion_irq; void *transport_info; @@ -224,7 +228,13 @@ struct scmi_transport_ops { * @max_msg: Maximum number of messages for a channel type (tx or rx) that can * be pending simultaneously in the system. May be overridden by the * get_max_msg op. - * @max_msg_size: Maximum size of data per message that can be handled. + * @max_msg_size: Maximum size of data payload per message that can be handled. + * @atomic_threshold: Optional system wide DT-configured threshold, expressed + * in microseconds, for atomic operations. + * Only SCMI synchronous commands reported by the platform + * to have an execution latency lesser-equal to the threshold + * should be considered for atomic mode operation: such + * decision is finally left up to the SCMI drivers. * @force_polling: Flag to force this whole transport to use SCMI core polling * mechanism instead of completion interrupts even if available. * @sync_cmds_completed_on_ret: Flag to indicate that the transport assures @@ -243,6 +253,7 @@ struct scmi_desc { int max_rx_timeout_ms; int max_msg; int max_msg_size; + unsigned int atomic_threshold; const bool force_polling; const bool sync_cmds_completed_on_ret; const bool atomic_enabled; @@ -311,6 +322,26 @@ enum scmi_bad_msg { MSG_MBOX_SPURIOUS = -5, }; +/* Used for compactness and signature validation of the function pointers being + * passed. + */ +typedef void (*shmem_copy_toio_t)(void __iomem *to, const void *from, + size_t count); +typedef void (*shmem_copy_fromio_t)(void *to, const void __iomem *from, + size_t count); + +/** + * struct scmi_shmem_io_ops - I/O operations to read from/write to + * Shared Memory + * + * @toio: Copy data to the shared memory area + * @fromio: Copy data from the shared memory area + */ +struct scmi_shmem_io_ops { + shmem_copy_fromio_t fromio; + shmem_copy_toio_t toio; +}; + /* shmem related declarations */ struct scmi_shared_mem; @@ -331,13 +362,16 @@ struct scmi_shared_mem; struct scmi_shared_mem_operations { void (*tx_prepare)(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer, - struct scmi_chan_info *cinfo); + struct scmi_chan_info *cinfo, + shmem_copy_toio_t toio); u32 (*read_header)(struct scmi_shared_mem __iomem *shmem); void (*fetch_response)(struct scmi_shared_mem __iomem *shmem, - struct scmi_xfer *xfer); + struct scmi_xfer *xfer, + shmem_copy_fromio_t fromio); void (*fetch_notification)(struct scmi_shared_mem __iomem *shmem, - size_t max_len, struct scmi_xfer *xfer); + size_t max_len, struct scmi_xfer *xfer, + shmem_copy_fromio_t fromio); void (*clear_channel)(struct scmi_shared_mem __iomem *shmem); bool (*poll_done)(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); @@ -345,7 +379,8 @@ struct scmi_shared_mem_operations { bool (*channel_intr_enabled)(struct scmi_shared_mem __iomem *shmem); void __iomem *(*setup_iomap)(struct scmi_chan_info *cinfo, struct device *dev, - bool tx, struct resource *res); + bool tx, struct resource *res, + struct scmi_shmem_io_ops **ops); }; const struct scmi_shared_mem_operations *scmi_shared_mem_operations_get(void); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index f8934d049d686f..1b5fb2c4ce8682 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -149,12 +149,6 @@ struct scmi_debug_info { * base protocol * @active_protocols: IDR storing device_nodes for protocols actually defined * in the DT and confirmed as implemented by fw. - * @atomic_threshold: Optional system wide DT-configured threshold, expressed - * in microseconds, for atomic operations. - * Only SCMI synchronous commands reported by the platform - * to have an execution latency lesser-equal to the threshold - * should be considered for atomic mode operation: such - * decision is finally left up to the SCMI drivers. * @notify_priv: Pointer to private data structure specific to notifications. * @node: List head * @users: Number of users of this instance @@ -180,7 +174,6 @@ struct scmi_info { struct mutex protocols_mtx; u8 *protocols_imp; struct idr active_protocols; - unsigned int atomic_threshold; void *notify_priv; struct list_head node; int users; @@ -2445,7 +2438,7 @@ static bool scmi_is_transport_atomic(const struct scmi_handle *handle, ret = info->desc->atomic_enabled && is_transport_polling_capable(info->desc); if (ret && atomic_threshold) - *atomic_threshold = info->atomic_threshold; + *atomic_threshold = info->desc->atomic_threshold; return ret; } @@ -2645,6 +2638,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node, cinfo->is_p2a = !tx; cinfo->rx_timeout_ms = info->desc->max_rx_timeout_ms; + cinfo->max_msg_size = info->desc->max_msg_size; /* Create a unique name for this transport device */ snprintf(name, 32, "__scmi_transport_device_%s_%02X", @@ -2958,7 +2952,7 @@ static struct scmi_debug_info *scmi_debugfs_common_setup(struct scmi_info *info) (char **)&dbg->name); debugfs_create_u32("atomic_threshold_us", 0400, top_dentry, - &info->atomic_threshold); + (u32 *)&info->desc->atomic_threshold); debugfs_create_str("type", 0400, trans, (char **)&dbg->type); @@ -3053,8 +3047,27 @@ static const struct scmi_desc *scmi_transport_setup(struct device *dev) if (ret && ret != -EINVAL) dev_err(dev, "Malformed arm,max-rx-timeout-ms DT property.\n"); - dev_info(dev, "SCMI max-rx-timeout: %dms\n", - trans->desc->max_rx_timeout_ms); + ret = of_property_read_u32(dev->of_node, "arm,max-msg-size", + &trans->desc->max_msg_size); + if (ret && ret != -EINVAL) + dev_err(dev, "Malformed arm,max-msg-size DT property.\n"); + + ret = of_property_read_u32(dev->of_node, "arm,max-msg", + &trans->desc->max_msg); + if (ret && ret != -EINVAL) + dev_err(dev, "Malformed arm,max-msg DT property.\n"); + + dev_info(dev, + "SCMI max-rx-timeout: %dms / max-msg-size: %dbytes / max-msg: %d\n", + trans->desc->max_rx_timeout_ms, trans->desc->max_msg_size, + trans->desc->max_msg); + + /* System wide atomic threshold for atomic ops .. if any */ + if (!of_property_read_u32(dev->of_node, "atomic-threshold-us", + &trans->desc->atomic_threshold)) + dev_info(dev, + "SCMI System wide atomic threshold set to %u us\n", + trans->desc->atomic_threshold); return trans->desc; } @@ -3105,13 +3118,6 @@ static int scmi_probe(struct platform_device *pdev) handle->devm_protocol_acquire = scmi_devm_protocol_acquire; handle->devm_protocol_get = scmi_devm_protocol_get; handle->devm_protocol_put = scmi_devm_protocol_put; - - /* System wide atomic threshold for atomic ops .. if any */ - if (!of_property_read_u32(np, "atomic-threshold-us", - &info->atomic_threshold)) - dev_info(dev, - "SCMI System wide atomic threshold set to %d us\n", - info->atomic_threshold); handle->is_transport_atomic = scmi_is_transport_atomic; /* Setup all channels described in the DT at first */ @@ -3327,7 +3333,7 @@ static struct platform_driver scmi_driver = { .dev_groups = versions_groups, }, .probe = scmi_probe, - .remove_new = scmi_remove, + .remove = scmi_remove, }; static struct dentry *scmi_debugfs_init(void) diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index 01d8a9398fe8e0..11c347bff76676 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -16,6 +16,8 @@ #include "common.h" +#define SCMI_SHMEM_LAYOUT_OVERHEAD 24 + /* * SCMI specification requires all parameters, message headers, return * arguments or any protocol data to be expressed in little endian @@ -34,9 +36,59 @@ struct scmi_shared_mem { u8 msg_payload[]; }; +static inline void shmem_memcpy_fromio32(void *to, + const void __iomem *from, + size_t count) +{ + WARN_ON(!IS_ALIGNED((unsigned long)from, 4) || + !IS_ALIGNED((unsigned long)to, 4) || + count % 4); + + __ioread32_copy(to, from, count / 4); +} + +static inline void shmem_memcpy_toio32(void __iomem *to, + const void *from, + size_t count) +{ + WARN_ON(!IS_ALIGNED((unsigned long)to, 4) || + !IS_ALIGNED((unsigned long)from, 4) || + count % 4); + + __iowrite32_copy(to, from, count / 4); +} + +static struct scmi_shmem_io_ops shmem_io_ops32 = { + .fromio = shmem_memcpy_fromio32, + .toio = shmem_memcpy_toio32, +}; + +/* Wrappers are needed for proper memcpy_{from,to}_io expansion by the + * pre-processor. + */ +static inline void shmem_memcpy_fromio(void *to, + const void __iomem *from, + size_t count) +{ + memcpy_fromio(to, from, count); +} + +static inline void shmem_memcpy_toio(void __iomem *to, + const void *from, + size_t count) +{ + memcpy_toio(to, from, count); +} + +static struct scmi_shmem_io_ops shmem_io_ops_default = { + .fromio = shmem_memcpy_fromio, + .toio = shmem_memcpy_toio, +}; + static void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer, - struct scmi_chan_info *cinfo) + struct scmi_chan_info *cinfo, + shmem_copy_toio_t copy_toio) { ktime_t stop; @@ -73,7 +125,7 @@ static void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, iowrite32(sizeof(shmem->msg_header) + xfer->tx.len, &shmem->length); iowrite32(pack_scmi_header(&xfer->hdr), &shmem->msg_header); if (xfer->tx.buf) - memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len); + copy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len); } static u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) @@ -82,7 +134,8 @@ static u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) } static void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, - struct scmi_xfer *xfer) + struct scmi_xfer *xfer, + shmem_copy_fromio_t copy_fromio) { size_t len = ioread32(&shmem->length); @@ -91,11 +144,12 @@ static void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, xfer->rx.len = min_t(size_t, xfer->rx.len, len > 8 ? len - 8 : 0); /* Take a copy to the rx buffer.. */ - memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); + copy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); } static void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, - size_t max_len, struct scmi_xfer *xfer) + size_t max_len, struct scmi_xfer *xfer, + shmem_copy_fromio_t copy_fromio) { size_t len = ioread32(&shmem->length); @@ -103,7 +157,7 @@ static void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, xfer->rx.len = min_t(size_t, max_len, len > 4 ? len - 4 : 0); /* Take a copy to the rx buffer.. */ - memcpy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len); + copy_fromio(xfer->rx.buf, shmem->msg_payload, xfer->rx.len); } static void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem) @@ -139,7 +193,8 @@ static bool shmem_channel_intr_enabled(struct scmi_shared_mem __iomem *shmem) static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo, struct device *dev, bool tx, - struct resource *res) + struct resource *res, + struct scmi_shmem_io_ops **ops) { struct device_node *shmem __free(device_node); const char *desc = tx ? "Tx" : "Rx"; @@ -148,6 +203,7 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo, struct resource lres = {}; resource_size_t size; void __iomem *addr; + u32 reg_io_width; shmem = of_parse_phandle(cdev->of_node, "shmem", idx); if (!shmem) @@ -167,12 +223,27 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo, } size = resource_size(res); + if (cinfo->max_msg_size + SCMI_SHMEM_LAYOUT_OVERHEAD > size) { + dev_err(dev, "misconfigured SCMI shared memory\n"); + return IOMEM_ERR_PTR(-ENOSPC); + } + addr = devm_ioremap(dev, res->start, size); if (!addr) { dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc); return IOMEM_ERR_PTR(-EADDRNOTAVAIL); } + of_property_read_u32(shmem, "reg-io-width", ®_io_width); + switch (reg_io_width) { + case 4: + *ops = &shmem_io_ops32; + break; + default: + *ops = &shmem_io_ops_default; + break; + } + return addr; } diff --git a/drivers/firmware/arm_scmi/transports/mailbox.c b/drivers/firmware/arm_scmi/transports/mailbox.c index e3d5f75609905f..b66df298145662 100644 --- a/drivers/firmware/arm_scmi/transports/mailbox.c +++ b/drivers/firmware/arm_scmi/transports/mailbox.c @@ -26,6 +26,7 @@ * @cinfo: SCMI channel info * @shmem: Transmit/Receive shared memory area * @chan_lock: Lock that prevents multiple xfers from being queued + * @io_ops: Transport specific I/O operations */ struct scmi_mailbox { struct mbox_client cl; @@ -35,6 +36,7 @@ struct scmi_mailbox { struct scmi_chan_info *cinfo; struct scmi_shared_mem __iomem *shmem; struct mutex chan_lock; + struct scmi_shmem_io_ops *io_ops; }; #define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl) @@ -45,7 +47,8 @@ static void tx_prepare(struct mbox_client *cl, void *m) { struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); - core->shmem->tx_prepare(smbox->shmem, m, smbox->cinfo); + core->shmem->tx_prepare(smbox->shmem, m, smbox->cinfo, + smbox->io_ops->toio); } static void rx_callback(struct mbox_client *cl, void *m) @@ -197,7 +200,8 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!smbox) return -ENOMEM; - smbox->shmem = core->shmem->setup_iomap(cinfo, dev, tx, NULL); + smbox->shmem = core->shmem->setup_iomap(cinfo, dev, tx, NULL, + &smbox->io_ops); if (IS_ERR(smbox->shmem)) return PTR_ERR(smbox->shmem); @@ -305,7 +309,7 @@ static void mailbox_fetch_response(struct scmi_chan_info *cinfo, { struct scmi_mailbox *smbox = cinfo->transport_info; - core->shmem->fetch_response(smbox->shmem, xfer); + core->shmem->fetch_response(smbox->shmem, xfer, smbox->io_ops->fromio); } static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, @@ -313,7 +317,8 @@ static void mailbox_fetch_notification(struct scmi_chan_info *cinfo, { struct scmi_mailbox *smbox = cinfo->transport_info; - core->shmem->fetch_notification(smbox->shmem, max_len, xfer); + core->shmem->fetch_notification(smbox->shmem, max_len, xfer, + smbox->io_ops->fromio); } static void mailbox_clear_channel(struct scmi_chan_info *cinfo) @@ -366,7 +371,7 @@ static struct scmi_desc scmi_mailbox_desc = { .ops = &scmi_mailbox_ops, .max_rx_timeout_ms = 30, /* We may increase this if required */ .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ - .max_msg_size = 128, + .max_msg_size = SCMI_SHMEM_MAX_PAYLOAD_SIZE, }; static const struct of_device_id scmi_of_match[] = { diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c index 56fc63edf51e23..3949a877e17dd6 100644 --- a/drivers/firmware/arm_scmi/transports/optee.c +++ b/drivers/firmware/arm_scmi/transports/optee.c @@ -17,8 +17,6 @@ #include "../common.h" -#define SCMI_OPTEE_MAX_MSG_SIZE 128 - enum scmi_optee_pta_cmd { /* * PTA_SCMI_CMD_CAPABILITIES - Get channel capabilities @@ -114,6 +112,7 @@ enum scmi_optee_pta_cmd { * @req.shmem: Virtual base address of the shared memory * @req.msg: Shared memory protocol handle for SCMI request and * synchronous response + * @io_ops: Transport specific I/O operations * @tee_shm: TEE shared memory handle @req or NULL if using IOMEM shmem * @link: Reference in agent's channel list */ @@ -128,6 +127,7 @@ struct scmi_optee_channel { struct scmi_shared_mem __iomem *shmem; struct scmi_msg_payld *msg; } req; + struct scmi_shmem_io_ops *io_ops; struct tee_shm *tee_shm; struct list_head link; }; @@ -297,7 +297,7 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; param[2].u.memref.shm = channel->tee_shm; - param[2].u.memref.size = SCMI_OPTEE_MAX_MSG_SIZE; + param[2].u.memref.size = SCMI_SHMEM_MAX_PAYLOAD_SIZE; ret = tee_client_invoke_func(scmi_optee_private->tee_ctx, &arg, param); if (ret < 0 || arg.ret) { @@ -330,7 +330,7 @@ static void scmi_optee_clear_channel(struct scmi_chan_info *cinfo) static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *channel) { - const size_t msg_size = SCMI_OPTEE_MAX_MSG_SIZE; + const size_t msg_size = SCMI_SHMEM_MAX_PAYLOAD_SIZE; void *shbuf; channel->tee_shm = tee_shm_alloc_kernel_buf(scmi_optee_private->tee_ctx, msg_size); @@ -350,7 +350,8 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch static int setup_static_shmem(struct device *dev, struct scmi_chan_info *cinfo, struct scmi_optee_channel *channel) { - channel->req.shmem = core->shmem->setup_iomap(cinfo, dev, true, NULL); + channel->req.shmem = core->shmem->setup_iomap(cinfo, dev, true, NULL, + &channel->io_ops); if (IS_ERR(channel->req.shmem)) return PTR_ERR(channel->req.shmem); @@ -465,7 +466,8 @@ static int scmi_optee_send_message(struct scmi_chan_info *cinfo, ret = invoke_process_msg_channel(channel, core->msg->command_size(xfer)); } else { - core->shmem->tx_prepare(channel->req.shmem, xfer, cinfo); + core->shmem->tx_prepare(channel->req.shmem, xfer, cinfo, + channel->io_ops->toio); ret = invoke_process_smt_channel(channel); } @@ -484,7 +486,8 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo, core->msg->fetch_response(channel->req.msg, channel->rx_len, xfer); else - core->shmem->fetch_response(channel->req.shmem, xfer); + core->shmem->fetch_response(channel->req.shmem, xfer, + channel->io_ops->fromio); } static void scmi_optee_mark_txdone(struct scmi_chan_info *cinfo, int ret, @@ -514,7 +517,7 @@ static struct scmi_desc scmi_optee_desc = { .ops = &scmi_optee_ops, .max_rx_timeout_ms = 30, .max_msg = 20, - .max_msg_size = SCMI_OPTEE_MAX_MSG_SIZE, + .max_msg_size = SCMI_SHMEM_MAX_PAYLOAD_SIZE, .sync_cmds_completed_on_ret = true, }; diff --git a/drivers/firmware/arm_scmi/transports/smc.c b/drivers/firmware/arm_scmi/transports/smc.c index f8dd108777f9b9..f632a62cfb3ec2 100644 --- a/drivers/firmware/arm_scmi/transports/smc.c +++ b/drivers/firmware/arm_scmi/transports/smc.c @@ -45,6 +45,7 @@ * @irq: An optional IRQ for completion * @cinfo: SCMI channel info * @shmem: Transmit/Receive shared memory area + * @io_ops: Transport specific I/O operations * @shmem_lock: Lock to protect access to Tx/Rx shared memory area. * Used when NOT operating in atomic mode. * @inflight: Atomic flag to protect access to Tx/Rx shared memory area. @@ -60,6 +61,7 @@ struct scmi_smc { int irq; struct scmi_chan_info *cinfo; struct scmi_shared_mem __iomem *shmem; + struct scmi_shmem_io_ops *io_ops; /* Protect access to shmem area */ struct mutex shmem_lock; #define INFLIGHT_NONE MSG_TOKEN_MAX @@ -144,7 +146,8 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!scmi_info) return -ENOMEM; - scmi_info->shmem = core->shmem->setup_iomap(cinfo, dev, tx, &res); + scmi_info->shmem = core->shmem->setup_iomap(cinfo, dev, tx, &res, + &scmi_info->io_ops); if (IS_ERR(scmi_info->shmem)) return PTR_ERR(scmi_info->shmem); @@ -229,7 +232,8 @@ static int smc_send_message(struct scmi_chan_info *cinfo, */ smc_channel_lock_acquire(scmi_info, xfer); - core->shmem->tx_prepare(scmi_info->shmem, xfer, cinfo); + core->shmem->tx_prepare(scmi_info->shmem, xfer, cinfo, + scmi_info->io_ops->toio); if (scmi_info->cap_id != ULONG_MAX) arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0, @@ -253,7 +257,8 @@ static void smc_fetch_response(struct scmi_chan_info *cinfo, { struct scmi_smc *scmi_info = cinfo->transport_info; - core->shmem->fetch_response(scmi_info->shmem, xfer); + core->shmem->fetch_response(scmi_info->shmem, xfer, + scmi_info->io_ops->fromio); } static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret, @@ -277,7 +282,7 @@ static struct scmi_desc scmi_smc_desc = { .ops = &scmi_smc_ops, .max_rx_timeout_ms = 30, .max_msg = 20, - .max_msg_size = 128, + .max_msg_size = SCMI_SHMEM_MAX_PAYLOAD_SIZE, /* * Setting .sync_cmds_atomic_replies to true for SMC assumes that, * once the SMC instruction has completed successfully, the issued diff --git a/drivers/firmware/arm_scmi/transports/virtio.c b/drivers/firmware/arm_scmi/transports/virtio.c index d349766bc0b267..41aea33776a9be 100644 --- a/drivers/firmware/arm_scmi/transports/virtio.c +++ b/drivers/firmware/arm_scmi/transports/virtio.c @@ -32,8 +32,8 @@ #define VIRTIO_MAX_RX_TIMEOUT_MS 60000 #define VIRTIO_SCMI_MAX_MSG_SIZE 128 /* Value may be increased. */ -#define VIRTIO_SCMI_MAX_PDU_SIZE \ - (VIRTIO_SCMI_MAX_MSG_SIZE + SCMI_MSG_MAX_PROT_OVERHEAD) +#define VIRTIO_SCMI_MAX_PDU_SIZE(ci) \ + ((ci)->max_msg_size + SCMI_MSG_MAX_PROT_OVERHEAD) #define DESCRIPTORS_PER_TX_MSG 2 /** @@ -90,6 +90,7 @@ enum poll_states { * @input: SDU used for (delayed) responses and notifications * @list: List which scmi_vio_msg may be part of * @rx_len: Input SDU size in bytes, once input has been received + * @max_len: Maximumm allowed SDU size in bytes * @poll_idx: Last used index registered for polling purposes if this message * transaction reply was configured for polling. * @poll_status: Polling state for this message. @@ -102,6 +103,7 @@ struct scmi_vio_msg { struct scmi_msg_payld *input; struct list_head list; unsigned int rx_len; + unsigned int max_len; unsigned int poll_idx; enum poll_states poll_status; /* Lock to protect access to poll_status */ @@ -234,7 +236,7 @@ static int scmi_vio_feed_vq_rx(struct scmi_vio_channel *vioch, unsigned long flags; struct device *dev = &vioch->vqueue->vdev->dev; - sg_init_one(&sg_in, msg->input, VIRTIO_SCMI_MAX_PDU_SIZE); + sg_init_one(&sg_in, msg->input, msg->max_len); spin_lock_irqsave(&vioch->lock, flags); @@ -439,9 +441,9 @@ static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (!msg) return -ENOMEM; + msg->max_len = VIRTIO_SCMI_MAX_PDU_SIZE(cinfo); if (tx) { - msg->request = devm_kzalloc(dev, - VIRTIO_SCMI_MAX_PDU_SIZE, + msg->request = devm_kzalloc(dev, msg->max_len, GFP_KERNEL); if (!msg->request) return -ENOMEM; @@ -449,8 +451,7 @@ static int virtio_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, refcount_set(&msg->users, 1); } - msg->input = devm_kzalloc(dev, VIRTIO_SCMI_MAX_PDU_SIZE, - GFP_KERNEL); + msg->input = devm_kzalloc(dev, msg->max_len, GFP_KERNEL); if (!msg->input) return -ENOMEM; diff --git a/drivers/firmware/arm_scmi/vendors/imx/Kconfig b/drivers/firmware/arm_scmi/vendors/imx/Kconfig index 2883ed24a84d65..a01bf5e47301d2 100644 --- a/drivers/firmware/arm_scmi/vendors/imx/Kconfig +++ b/drivers/firmware/arm_scmi/vendors/imx/Kconfig @@ -15,6 +15,7 @@ config IMX_SCMI_BBM_EXT config IMX_SCMI_MISC_EXT tristate "i.MX SCMI MISC EXTENSION" depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + depends on IMX_SCMI_MISC_DRV default y if ARCH_MXC help This enables i.MX System MISC control logic such as gpio expander diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 94a6b4e667de14..87c323de17b901 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -630,6 +630,9 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain) if (ret) return ERR_PTR(ret); + if (!buf.opp_count) + return ERR_PTR(-ENOENT); + info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); @@ -1046,7 +1049,7 @@ static struct platform_driver scpi_driver = { .dev_groups = versions_groups, }, .probe = scpi_probe, - .remove_new = scpi_remove, + .remove = scpi_remove, }; module_platform_driver(scpi_driver); diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 419220fa42fd7e..5365e9a4300070 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -378,7 +378,7 @@ const char *cs_dsp_mem_region_name(unsigned int type) return NULL; } } -EXPORT_SYMBOL_NS_GPL(cs_dsp_mem_region_name, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_mem_region_name, "FW_CS_DSP"); #ifdef CONFIG_DEBUG_FS static void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s) @@ -519,7 +519,7 @@ void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root) dsp->debugfs_root = root; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, "FW_CS_DSP"); /** * cs_dsp_cleanup_debugfs() - Removes DSP representation from debugfs @@ -531,17 +531,17 @@ void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp) debugfs_remove_recursive(dsp->debugfs_root); dsp->debugfs_root = ERR_PTR(-ENODEV); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, "FW_CS_DSP"); #else void cs_dsp_init_debugfs(struct cs_dsp *dsp, struct dentry *debugfs_root) { } -EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_init_debugfs, "FW_CS_DSP"); void cs_dsp_cleanup_debugfs(struct cs_dsp *dsp) { } -EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_cleanup_debugfs, "FW_CS_DSP"); static inline void cs_dsp_debugfs_save_wmfwname(struct cs_dsp *dsp, const char *s) @@ -749,7 +749,7 @@ int cs_dsp_coeff_write_acked_control(struct cs_dsp_coeff_ctl *ctl, unsigned int return -ETIMEDOUT; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_acked_control, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_acked_control, "FW_CS_DSP"); static int cs_dsp_coeff_write_ctrl_raw(struct cs_dsp_coeff_ctl *ctl, unsigned int off, const void *buf, size_t len) @@ -827,7 +827,7 @@ int cs_dsp_coeff_write_ctrl(struct cs_dsp_coeff_ctl *ctl, return 1; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_ctrl, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_write_ctrl, "FW_CS_DSP"); /** * cs_dsp_coeff_lock_and_write_ctrl() - Writes the given buffer to the given coefficient control @@ -926,7 +926,7 @@ int cs_dsp_coeff_read_ctrl(struct cs_dsp_coeff_ctl *ctl, return ret; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_read_ctrl, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_coeff_read_ctrl, "FW_CS_DSP"); /** * cs_dsp_coeff_lock_and_read_ctrl() - Reads the given coefficient control into the given buffer @@ -1679,7 +1679,7 @@ struct cs_dsp_coeff_ctl *cs_dsp_get_ctl(struct cs_dsp *dsp, const char *name, in return rslt; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_get_ctl, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_get_ctl, "FW_CS_DSP"); static void cs_dsp_ctl_fixup_base(struct cs_dsp *dsp, const struct cs_dsp_alg_region *alg_region) @@ -1769,7 +1769,7 @@ struct cs_dsp_alg_region *cs_dsp_find_alg_region(struct cs_dsp *dsp, return NULL; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_find_alg_region, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_find_alg_region, "FW_CS_DSP"); static struct cs_dsp_alg_region *cs_dsp_create_region(struct cs_dsp *dsp, int type, __be32 id, @@ -2404,7 +2404,7 @@ int cs_dsp_adsp1_init(struct cs_dsp *dsp) return cs_dsp_common_init(dsp); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_init, "FW_CS_DSP"); /** * cs_dsp_adsp1_power_up() - Load and start the named firmware @@ -2496,7 +2496,7 @@ int cs_dsp_adsp1_power_up(struct cs_dsp *dsp, mutex_unlock(&dsp->pwr_lock); return ret; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_up, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_up, "FW_CS_DSP"); /** * cs_dsp_adsp1_power_down() - Halts the DSP @@ -2528,7 +2528,7 @@ void cs_dsp_adsp1_power_down(struct cs_dsp *dsp) mutex_unlock(&dsp->pwr_lock); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_down, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp1_power_down, "FW_CS_DSP"); static int cs_dsp_adsp2v2_enable_core(struct cs_dsp *dsp) { @@ -2680,7 +2680,7 @@ int cs_dsp_set_dspclk(struct cs_dsp *dsp, unsigned int freq) return ret; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_set_dspclk, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_set_dspclk, "FW_CS_DSP"); static void cs_dsp_stop_watchdog(struct cs_dsp *dsp) { @@ -2770,7 +2770,7 @@ int cs_dsp_power_up(struct cs_dsp *dsp, return ret; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_power_up, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_power_up, "FW_CS_DSP"); /** * cs_dsp_power_down() - Powers-down the DSP @@ -2804,7 +2804,7 @@ void cs_dsp_power_down(struct cs_dsp *dsp) cs_dsp_dbg(dsp, "Shutdown complete\n"); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_power_down, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_power_down, "FW_CS_DSP"); static int cs_dsp_adsp2_start_core(struct cs_dsp *dsp) { @@ -2890,7 +2890,7 @@ int cs_dsp_run(struct cs_dsp *dsp) return ret; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_run, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_run, "FW_CS_DSP"); /** * cs_dsp_stop() - Stops the firmware @@ -2929,7 +2929,7 @@ void cs_dsp_stop(struct cs_dsp *dsp) cs_dsp_dbg(dsp, "Execution stopped\n"); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_stop, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_stop, "FW_CS_DSP"); static int cs_dsp_halo_start_core(struct cs_dsp *dsp) { @@ -2991,7 +2991,7 @@ int cs_dsp_adsp2_init(struct cs_dsp *dsp) return cs_dsp_common_init(dsp); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_init, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_init, "FW_CS_DSP"); /** * cs_dsp_halo_init() - Initialise a cs_dsp structure representing a HALO Core DSP @@ -3008,7 +3008,7 @@ int cs_dsp_halo_init(struct cs_dsp *dsp) return cs_dsp_common_init(dsp); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_init, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_init, "FW_CS_DSP"); /** * cs_dsp_remove() - Clean a cs_dsp before deletion @@ -3028,7 +3028,7 @@ void cs_dsp_remove(struct cs_dsp *dsp) cs_dsp_free_ctl_blk(ctl); } } -EXPORT_SYMBOL_NS_GPL(cs_dsp_remove, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_remove, "FW_CS_DSP"); /** * cs_dsp_read_raw_data_block() - Reads a block of data from DSP memory @@ -3065,7 +3065,7 @@ int cs_dsp_read_raw_data_block(struct cs_dsp *dsp, int mem_type, unsigned int me return 0; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_read_raw_data_block, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_read_raw_data_block, "FW_CS_DSP"); /** * cs_dsp_read_data_word() - Reads a word from DSP memory @@ -3089,7 +3089,7 @@ int cs_dsp_read_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_add return 0; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_read_data_word, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_read_data_word, "FW_CS_DSP"); /** * cs_dsp_write_data_word() - Writes a word to DSP memory @@ -3115,7 +3115,7 @@ int cs_dsp_write_data_word(struct cs_dsp *dsp, int mem_type, unsigned int mem_ad return regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_write_data_word, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_write_data_word, "FW_CS_DSP"); /** * cs_dsp_remove_padding() - Convert unpacked words to packed bytes @@ -3139,7 +3139,7 @@ void cs_dsp_remove_padding(u32 *buf, int nwords) *pack_out++ = (u8)(word >> 16); } } -EXPORT_SYMBOL_NS_GPL(cs_dsp_remove_padding, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_remove_padding, "FW_CS_DSP"); /** * cs_dsp_adsp2_bus_error() - Handle a DSP bus error interrupt @@ -3209,7 +3209,7 @@ void cs_dsp_adsp2_bus_error(struct cs_dsp *dsp) error: mutex_unlock(&dsp->pwr_lock); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_bus_error, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_bus_error, "FW_CS_DSP"); /** * cs_dsp_halo_bus_error() - Handle a DSP bus error interrupt @@ -3269,7 +3269,7 @@ void cs_dsp_halo_bus_error(struct cs_dsp *dsp) exit_unlock: mutex_unlock(&dsp->pwr_lock); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_bus_error, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_bus_error, "FW_CS_DSP"); /** * cs_dsp_halo_wdt_expire() - Handle DSP watchdog expiry @@ -3289,7 +3289,7 @@ void cs_dsp_halo_wdt_expire(struct cs_dsp *dsp) mutex_unlock(&dsp->pwr_lock); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_wdt_expire, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_halo_wdt_expire, "FW_CS_DSP"); static const struct cs_dsp_ops cs_dsp_adsp1_ops = { .validate_version = cs_dsp_validate_version, @@ -3419,7 +3419,7 @@ int cs_dsp_chunk_write(struct cs_dsp_chunk *ch, int nbits, u32 val) return 0; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, "FW_CS_DSP"); /** * cs_dsp_chunk_flush() - Pad remaining data with zero and commit to chunk @@ -3438,7 +3438,7 @@ int cs_dsp_chunk_flush(struct cs_dsp_chunk *ch) return cs_dsp_chunk_write(ch, CS_DSP_DATA_WORD_BITS - ch->cachebits, 0); } -EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_flush, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_flush, "FW_CS_DSP"); /** * cs_dsp_chunk_read() - Parse data from a DSP memory chunk @@ -3480,7 +3480,7 @@ int cs_dsp_chunk_read(struct cs_dsp_chunk *ch, int nbits) return result; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, "FW_CS_DSP"); struct cs_dsp_wseq_op { @@ -3605,7 +3605,7 @@ int cs_dsp_wseq_init(struct cs_dsp *dsp, struct cs_dsp_wseq *wseqs, unsigned int return 0; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_init, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_init, "FW_CS_DSP"); static struct cs_dsp_wseq_op *cs_dsp_wseq_find_op(u32 addr, u8 op_code, struct list_head *wseq_ops) @@ -3720,7 +3720,7 @@ int cs_dsp_wseq_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, return ret; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_write, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_write, "FW_CS_DSP"); /** * cs_dsp_wseq_multi_write() - Add or update multiple entries in a write sequence @@ -3752,7 +3752,7 @@ int cs_dsp_wseq_multi_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, return 0; } -EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_multi_write, FW_CS_DSP); +EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_multi_write, "FW_CS_DSP"); MODULE_DESCRIPTION("Cirrus Logic DSP Support"); MODULE_AUTHOR("Simon Trimmer "); diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 72f2537d90cafd..5fe61b9ab5f969 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -76,20 +76,14 @@ config EFI_ZBOOT bool "Enable the generic EFI decompressor" depends on EFI_GENERIC_STUB && !ARM select HAVE_KERNEL_GZIP - select HAVE_KERNEL_LZ4 - select HAVE_KERNEL_LZMA - select HAVE_KERNEL_LZO - select HAVE_KERNEL_XZ select HAVE_KERNEL_ZSTD help Create the bootable image as an EFI application that carries the actual kernel image in compressed form, and decompresses it into - memory before executing it via LoadImage/StartImage EFI boot service - calls. For compatibility with non-EFI loaders, the payload can be - decompressed and executed by the loader as well, provided that the - loader implements the decompression algorithm and that non-EFI boot - is supported by the encapsulated image. (The compression algorithm - used is described in the zboot image header) + memory before executing it. For compatibility with non-EFI loaders, + the payload can be decompressed and executed by the loader as well, + provided that the loader implements the decompression algorithm. + (The compression algorithm used is described in the zboot header) config EFI_ARMSTUB_DTB_LOADER bool "Enable the DTB loader" diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 552c78f5f05902..a253b61449459e 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c @@ -6,7 +6,7 @@ #include #include -MODULE_IMPORT_NS(EFIVAR); +MODULE_IMPORT_NS("EFIVAR"); #define DUMP_NAME_LEN 66 diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 70490bf2697b16..60c64b81d2c32c 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -273,6 +273,7 @@ static __init int efivar_ssdt_load(void) efi_char16_t *name = NULL; efi_status_t status; efi_guid_t guid; + int ret = 0; if (!efivar_ssdt[0]) return 0; @@ -294,8 +295,8 @@ static __init int efivar_ssdt_load(void) efi_char16_t *name_tmp = krealloc(name, name_size, GFP_KERNEL); if (!name_tmp) { - kfree(name); - return -ENOMEM; + ret = -ENOMEM; + goto out; } name = name_tmp; continue; @@ -309,26 +310,38 @@ static __init int efivar_ssdt_load(void) pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt, &guid); status = efi.get_variable(name, &guid, NULL, &data_size, NULL); - if (status != EFI_BUFFER_TOO_SMALL || !data_size) - return -EIO; + if (status != EFI_BUFFER_TOO_SMALL || !data_size) { + ret = -EIO; + goto out; + } data = kmalloc(data_size, GFP_KERNEL); - if (!data) - return -ENOMEM; + if (!data) { + ret = -ENOMEM; + goto out; + } status = efi.get_variable(name, &guid, NULL, &data_size, data); if (status == EFI_SUCCESS) { - acpi_status ret = acpi_load_table(data, NULL); - if (ret) - pr_err("failed to load table: %u\n", ret); - else + acpi_status acpi_ret = acpi_load_table(data, NULL); + if (ACPI_FAILURE(acpi_ret)) { + pr_err("efivar_ssdt: failed to load table: %u\n", + acpi_ret); + } else { + /* + * The @data will be in use by ACPI engine, + * do not free it! + */ continue; + } } else { - pr_err("failed to get var data: 0x%lx\n", status); + pr_err("efivar_ssdt: failed to get var data: 0x%lx\n", status); } kfree(data); } - return 0; +out: + kfree(name); + return ret; } #else static inline int efivar_ssdt_load(void) { return 0; } @@ -433,7 +446,9 @@ static int __init efisubsys_init(void) error = generic_ops_register(); if (error) goto err_put; - efivar_ssdt_load(); + error = efivar_ssdt_load(); + if (error) + pr_err("efi: failed to load SSDT, error %d.\n", error); platform_device_register_simple("efivars", 0, NULL, 0); } diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c index f5be8e22305be4..b49a09d7e66519 100644 --- a/drivers/firmware/efi/embedded-firmware.c +++ b/drivers/firmware/efi/embedded-firmware.c @@ -16,9 +16,9 @@ /* Exported for use by lib/test_firmware.c only */ LIST_HEAD(efi_embedded_fw_list); -EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_list, TEST_FIRMWARE); +EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_list, "TEST_FIRMWARE"); bool efi_embedded_fw_checked; -EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_checked, TEST_FIRMWARE); +EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_checked, "TEST_FIRMWARE"); static const struct dmi_system_id * const embedded_fw_table[] = { #ifdef CONFIG_TOUCHSCREEN_DMI diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index 7a81c0ce478059..4bb7b0584bc904 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -75,8 +75,6 @@ static LIST_HEAD(entry_list); struct esre_attribute { struct attribute attr; ssize_t (*show)(struct esre_entry *entry, char *buf); - ssize_t (*store)(struct esre_entry *entry, - const char *buf, size_t count); }; static struct esre_entry *to_entry(struct kobject *kobj) diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot index 65ffd0b760b2fb..48842b5c106b83 100644 --- a/drivers/firmware/efi/libstub/Makefile.zboot +++ b/drivers/firmware/efi/libstub/Makefile.zboot @@ -12,22 +12,16 @@ quiet_cmd_copy_and_pad = PAD $@ $(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 -comp-type-$(CONFIG_KERNEL_LZMA) := lzma -comp-type-$(CONFIG_KERNEL_LZO) := lzo -comp-type-$(CONFIG_KERNEL_XZ) := xzkern -comp-type-$(CONFIG_KERNEL_ZSTD) := zstd22 - # 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 +comp-type-y := gzip +zboot-method-y := gzip +zboot-size-len-y := 0 -zboot-method-$(CONFIG_KERNEL_GZIP) := gzip -zboot-size-len-$(CONFIG_KERNEL_GZIP) := 0 +comp-type-$(CONFIG_KERNEL_ZSTD) := zstd +zboot-method-$(CONFIG_KERNEL_ZSTD) := zstd22_with_size +zboot-size-len-$(CONFIG_KERNEL_ZSTD) := 4 $(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE $(call if_changed,$(zboot-method-y)) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index de659f6a815fd4..c0c81ca4237e98 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -327,7 +327,7 @@ static efi_status_t efi_measure_tagged_event(unsigned long load_addr, * Size of memory allocated return in *cmd_line_len. * Returns NULL on error. */ -char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len) +char *efi_convert_cmdline(efi_loaded_image_t *image) { const efi_char16_t *options = efi_table_attr(image, load_options); u32 options_size = efi_table_attr(image, load_options_size); @@ -405,7 +405,6 @@ char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len) snprintf((char *)cmdline_addr, options_bytes, "%.*ls", options_bytes - 1, options); - *cmd_line_len = options_bytes; return (char *)cmdline_addr; } @@ -621,10 +620,6 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image, status = efi_load_initrd_dev_path(&initrd, hard_limit); if (status == EFI_SUCCESS) { efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n"); - if (initrd.size > 0 && - efi_measure_tagged_event(initrd.base, initrd.size, - EFISTUB_EVT_INITRD) == EFI_SUCCESS) - efi_info("Measured initrd data into PCR 9\n"); } else if (status == EFI_NOT_FOUND) { status = efi_load_initrd_cmdline(image, &initrd, soft_limit, hard_limit); @@ -637,6 +632,11 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image, if (status != EFI_SUCCESS) goto failed; + if (initrd.size > 0 && + efi_measure_tagged_event(initrd.base, initrd.size, + EFISTUB_EVT_INITRD) == EFI_SUCCESS) + efi_info("Measured initrd data into PCR 9\n"); + status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(initrd), (void **)&tbl); if (status != EFI_SUCCESS) diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index 958a680e0660d4..382b54f40603bf 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -112,7 +112,6 @@ static u32 get_supported_rt_services(void) efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr) { - int cmdline_size = 0; efi_status_t status; char *cmdline; @@ -121,35 +120,32 @@ efi_status_t efi_handle_cmdline(efi_loaded_image_t *image, char **cmdline_ptr) * protocol. We are going to copy the command line into the * device tree, so this can be allocated anywhere. */ - cmdline = efi_convert_cmdline(image, &cmdline_size); + cmdline = efi_convert_cmdline(image); if (!cmdline) { efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n"); return EFI_OUT_OF_RESOURCES; } - if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || - IS_ENABLED(CONFIG_CMDLINE_FORCE) || - cmdline_size == 0) { - status = efi_parse_options(CONFIG_CMDLINE); - if (status != EFI_SUCCESS) { - efi_err("Failed to parse options\n"); + if (!IS_ENABLED(CONFIG_CMDLINE_FORCE)) { + status = efi_parse_options(cmdline); + if (status != EFI_SUCCESS) goto fail_free_cmdline; - } } - if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) { - status = efi_parse_options(cmdline); - if (status != EFI_SUCCESS) { - efi_err("Failed to parse options\n"); + if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || + IS_ENABLED(CONFIG_CMDLINE_FORCE) || + cmdline[0] == 0) { + status = efi_parse_options(CONFIG_CMDLINE); + if (status != EFI_SUCCESS) goto fail_free_cmdline; - } } *cmdline_ptr = cmdline; return EFI_SUCCESS; fail_free_cmdline: - efi_bs_call(free_pool, cmdline_ptr); + efi_err("Failed to parse options\n"); + efi_bs_call(free_pool, cmdline); return status; } diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 685098f9626f2b..76e44c185f29e1 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1056,7 +1056,7 @@ void efi_free(unsigned long size, unsigned long addr); void efi_apply_loadoptions_quirk(const void **load_options, u32 *load_options_size); -char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len); +char *efi_convert_cmdline(efi_loaded_image_t *image); efi_status_t efi_get_memory_map(struct efi_boot_memmap **map, bool install_cfg_tbl); diff --git a/drivers/firmware/efi/libstub/file.c b/drivers/firmware/efi/libstub/file.c index d6a025df07dcf9..bd626d55dcbc2f 100644 --- a/drivers/firmware/efi/libstub/file.c +++ b/drivers/firmware/efi/libstub/file.c @@ -175,6 +175,12 @@ static efi_status_t efi_open_device_path(efi_file_protocol_t **volume, return status; } +#ifndef CONFIG_CMDLINE +#define CONFIG_CMDLINE +#endif + +static const efi_char16_t builtin_cmdline[] = L"" CONFIG_CMDLINE; + /* * Check the cmdline for a LILO-style file= arguments. * @@ -189,6 +195,8 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image, unsigned long *load_addr, unsigned long *load_size) { + const bool ignore_load_options = IS_ENABLED(CONFIG_CMDLINE_OVERRIDE) || + IS_ENABLED(CONFIG_CMDLINE_FORCE); const efi_char16_t *cmdline = efi_table_attr(image, load_options); u32 cmdline_len = efi_table_attr(image, load_options_size); unsigned long efi_chunk_size = ULONG_MAX; @@ -197,6 +205,7 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image, unsigned long alloc_addr; unsigned long alloc_size; efi_status_t status; + bool twopass; int offset; if (!load_addr || !load_size) @@ -209,6 +218,16 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image, efi_chunk_size = EFI_READ_CHUNK_SIZE; alloc_addr = alloc_size = 0; + + if (!ignore_load_options && cmdline_len > 0) { + twopass = IS_ENABLED(CONFIG_CMDLINE_BOOL) || + IS_ENABLED(CONFIG_CMDLINE_EXTEND); + } else { +do_builtin: cmdline = builtin_cmdline; + cmdline_len = ARRAY_SIZE(builtin_cmdline) - 1; + twopass = false; + } + do { struct finfo fi; unsigned long size; @@ -290,6 +309,9 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image, efi_call_proto(volume, close); } while (offset > 0); + if (twopass) + goto do_builtin; + *load_addr = alloc_addr; *load_size = alloc_size; diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 1fd6823248ab6e..a5c6c4f163fce4 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -57,7 +57,7 @@ static void efi_retrieve_tcg2_eventlog(int version, efi_physical_addr_t log_loca struct linux_efi_tpm_eventlog *log_tbl = NULL; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; - int final_events_size = 0; + u32 final_events_size = 0; first_entry_addr = (unsigned long) log_location; @@ -110,9 +110,9 @@ static void efi_retrieve_tcg2_eventlog(int version, efi_physical_addr_t log_loca */ if (final_events_table && final_events_table->nr_events) { struct tcg_pcr_event2_head *header; - int offset; + u32 offset; void *data; - int event_size; + u32 event_size; int i = final_events_table->nr_events; data = (void *)final_events_table; @@ -124,6 +124,9 @@ static void efi_retrieve_tcg2_eventlog(int version, efi_physical_addr_t log_loca event_size = __calc_tpm2_event_size(header, (void *)(long)log_location, false); + /* If calc fails this is a malformed log */ + if (!event_size) + break; final_events_size += event_size; i--; } diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c index f8e465da344d54..188c8000d245ec 100644 --- a/drivers/firmware/efi/libstub/x86-stub.c +++ b/drivers/firmware/efi/libstub/x86-stub.c @@ -537,7 +537,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; struct boot_params *boot_params; struct setup_header *hdr; - int options_size = 0; efi_status_t status; unsigned long alloc; char *cmdline_ptr; @@ -569,7 +568,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, hdr->initrd_addr_max = INT_MAX; /* Convert unicode cmdline to ascii */ - cmdline_ptr = efi_convert_cmdline(image, &options_size); + cmdline_ptr = efi_convert_cmdline(image); if (!cmdline_ptr) { efi_free(PARAM_SIZE, alloc); efi_exit(handle, EFI_OUT_OF_RESOURCES); diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c index 164203429fa7a3..c38b1a335590d4 100644 --- a/drivers/firmware/efi/memattr.c +++ b/drivers/firmware/efi/memattr.c @@ -22,6 +22,7 @@ unsigned long __ro_after_init efi_mem_attr_table = EFI_INVALID_TABLE_ADDR; int __init efi_memattr_init(void) { efi_memory_attributes_table_t *tbl; + unsigned long size; if (efi_mem_attr_table == EFI_INVALID_TABLE_ADDR) return 0; @@ -39,7 +40,22 @@ int __init efi_memattr_init(void) goto unmap; } - tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size; + + /* + * Sanity check: the Memory Attributes Table contains up to 3 entries + * for each entry of type EfiRuntimeServicesCode in the EFI memory map. + * So if the size of the table exceeds 3x the size of the entire EFI + * memory map, there is clearly something wrong, and the table should + * just be ignored altogether. + */ + size = tbl->num_entries * tbl->desc_size; + if (size > 3 * efi.memmap.nr_map * efi.memmap.desc_size) { + pr_warn(FW_BUG "Corrupted EFI Memory Attributes Table detected! (version == %u, desc_size == %u, num_entries == %u)\n", + tbl->version, tbl->desc_size, tbl->num_entries); + goto unmap; + } + + tbl_size = sizeof(*tbl) + size; memblock_reserve(efi_mem_attr_table, tbl_size); set_bit(EFI_MEM_ATTR, &efi.flags); diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c index e8d69bd548f3fe..cdd431027065d1 100644 --- a/drivers/firmware/efi/tpm.c +++ b/drivers/firmware/efi/tpm.c @@ -19,7 +19,7 @@ EXPORT_SYMBOL(efi_tpm_final_log_size); static int __init tpm2_calc_event_log_size(void *data, int count, void *size_info) { struct tcg_pcr_event2_head *header; - int event_size, size = 0; + u32 event_size, size = 0; while (count > 0) { header = data + size; @@ -40,7 +40,8 @@ int __init efi_tpm_eventlog_init(void) { struct linux_efi_tpm_eventlog *log_tbl; struct efi_tcg2_final_events_table *final_tbl; - int tbl_size; + unsigned int tbl_size; + int final_tbl_size; int ret = 0; if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) { @@ -60,7 +61,12 @@ int __init efi_tpm_eventlog_init(void) } tbl_size = sizeof(*log_tbl) + log_tbl->size; - memblock_reserve(efi.tpm_log, tbl_size); + if (memblock_reserve(efi.tpm_log, tbl_size)) { + pr_err("TPM Event Log memblock reserve fails (0x%lx, 0x%x)\n", + efi.tpm_log, tbl_size); + ret = -ENOMEM; + goto out; + } if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR) { pr_info("TPM Final Events table not present\n"); @@ -80,26 +86,26 @@ int __init efi_tpm_eventlog_init(void) goto out; } - tbl_size = 0; + final_tbl_size = 0; if (final_tbl->nr_events != 0) { void *events = (void *)efi.tpm_final_log + sizeof(final_tbl->version) + sizeof(final_tbl->nr_events); - tbl_size = tpm2_calc_event_log_size(events, - final_tbl->nr_events, - log_tbl->log); + final_tbl_size = tpm2_calc_event_log_size(events, + final_tbl->nr_events, + log_tbl->log); } - if (tbl_size < 0) { + if (final_tbl_size < 0) { pr_err(FW_BUG "Failed to parse event in TPM Final Events Log\n"); ret = -EINVAL; goto out_calc; } memblock_reserve(efi.tpm_final_log, - tbl_size + sizeof(*final_tbl)); - efi_tpm_final_log_size = tbl_size; + final_tbl_size + sizeof(*final_tbl)); + efi_tpm_final_log_size = final_tbl_size; out_calc: early_memunmap(final_tbl, sizeof(*final_tbl)); diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 4056ba7f344085..3700e98697676d 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -149,7 +149,7 @@ int efivar_lock(void) } return 0; } -EXPORT_SYMBOL_NS_GPL(efivar_lock, EFIVAR); +EXPORT_SYMBOL_NS_GPL(efivar_lock, "EFIVAR"); /* * efivar_lock() - obtain the efivar lock if it is free @@ -165,7 +165,7 @@ int efivar_trylock(void) } return 0; } -EXPORT_SYMBOL_NS_GPL(efivar_trylock, EFIVAR); +EXPORT_SYMBOL_NS_GPL(efivar_trylock, "EFIVAR"); /* * efivar_unlock() - release the efivar lock @@ -174,7 +174,7 @@ void efivar_unlock(void) { up(&efivars_lock); } -EXPORT_SYMBOL_NS_GPL(efivar_unlock, EFIVAR); +EXPORT_SYMBOL_NS_GPL(efivar_unlock, "EFIVAR"); /* * efivar_get_variable() - retrieve a variable identified by name/vendor @@ -186,7 +186,7 @@ efi_status_t efivar_get_variable(efi_char16_t *name, efi_guid_t *vendor, { return __efivars->ops->get_variable(name, vendor, attr, size, data); } -EXPORT_SYMBOL_NS_GPL(efivar_get_variable, EFIVAR); +EXPORT_SYMBOL_NS_GPL(efivar_get_variable, "EFIVAR"); /* * efivar_get_next_variable() - enumerate the next name/vendor pair @@ -198,7 +198,7 @@ efi_status_t efivar_get_next_variable(unsigned long *name_size, { return __efivars->ops->get_next_variable(name_size, name, vendor); } -EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, EFIVAR); +EXPORT_SYMBOL_NS_GPL(efivar_get_next_variable, "EFIVAR"); /* * efivar_set_variable_locked() - set a variable identified by name/vendor @@ -230,7 +230,7 @@ efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor, return setvar(name, vendor, attr, data_size, data); } -EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, EFIVAR); +EXPORT_SYMBOL_NS_GPL(efivar_set_variable_locked, "EFIVAR"); /* * efivar_set_variable() - set a variable identified by name/vendor @@ -252,7 +252,7 @@ efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor, efivar_unlock(); return status; } -EXPORT_SYMBOL_NS_GPL(efivar_set_variable, EFIVAR); +EXPORT_SYMBOL_NS_GPL(efivar_set_variable, "EFIVAR"); efi_status_t efivar_query_variable_info(u32 attr, u64 *storage_space, @@ -264,4 +264,4 @@ efi_status_t efivar_query_variable_info(u32 attr, return __efivars->ops->query_variable_info(attr, storage_space, remaining_space, max_variable_size); } -EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, EFIVAR); +EXPORT_SYMBOL_NS_GPL(efivar_query_variable_info, "EFIVAR"); diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 208652a8087cd2..882db32e51be97 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -220,7 +220,7 @@ MODULE_DEVICE_TABLE(of, coreboot_of_match); static struct platform_driver coreboot_table_driver = { .probe = coreboot_table_probe, - .remove_new = coreboot_table_remove, + .remove = coreboot_table_remove, .driver = { .name = "coreboot_table", .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match), diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c index daadd71d8ddd37..c68c9f56370f28 100644 --- a/drivers/firmware/google/framebuffer-coreboot.c +++ b/drivers/firmware/google/framebuffer-coreboot.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "coreboot_table.h" @@ -36,6 +37,19 @@ static int framebuffer_probe(struct coreboot_device *dev) .format = NULL, }; + /* + * On coreboot systems, the advertised LB_TAG_FRAMEBUFFER entry + * in the coreboot table should only be used if the payload did + * not pass a framebuffer information to the Linux kernel. + * + * If the global screen_info data has been filled, the Generic + * System Framebuffers (sysfb) will already register a platform + * device and pass that screen_info as platform_data to a driver + * that can scan-out using the system provided framebuffer. + */ + if (sysfb_handles_screen_info()) + return -ENODEV; + if (!fb->physical_address) return -ENODEV; diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c index d304913314e494..24e666d5c3d1a2 100644 --- a/drivers/firmware/google/gsmi.c +++ b/drivers/firmware/google/gsmi.c @@ -918,7 +918,8 @@ static __init int gsmi_init(void) gsmi_dev.pdev = platform_device_register_full(&gsmi_dev_info); if (IS_ERR(gsmi_dev.pdev)) { printk(KERN_ERR "gsmi: unable to register platform device\n"); - return PTR_ERR(gsmi_dev.pdev); + ret = PTR_ERR(gsmi_dev.pdev); + goto out_unregister; } /* SMI access needs to be serialized */ @@ -1056,10 +1057,11 @@ static __init int gsmi_init(void) gsmi_buf_free(gsmi_dev.name_buf); kmem_cache_destroy(gsmi_dev.mem_pool); platform_device_unregister(gsmi_dev.pdev); - pr_info("gsmi: failed to load: %d\n", ret); +out_unregister: #ifdef CONFIG_PM platform_driver_unregister(&gsmi_driver_info); #endif + pr_info("gsmi: failed to load: %d\n", ret); return ret; } diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig index 477d3f32d99a6b..907cd149c40a8b 100644 --- a/drivers/firmware/imx/Kconfig +++ b/drivers/firmware/imx/Kconfig @@ -25,7 +25,6 @@ config IMX_SCU config IMX_SCMI_MISC_DRV tristate "IMX SCMI MISC Protocol driver" - depends on IMX_SCMI_MISC_EXT || COMPILE_TEST default y if ARCH_MXC help The System Controller Management Interface firmware (SCMI FW) is diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c index 01c8ef14eaec3f..ed79e823157afb 100644 --- a/drivers/firmware/imx/imx-dsp.c +++ b/drivers/firmware/imx/imx-dsp.c @@ -180,7 +180,7 @@ static struct platform_driver imx_dsp_driver = { .name = "imx-dsp", }, .probe = imx_dsp_probe, - .remove_new = imx_dsp_remove, + .remove = imx_dsp_remove, }; builtin_platform_driver(imx_dsp_driver); diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index 8e59be3782cbb7..55b9cfad8a042b 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c @@ -116,7 +116,7 @@ static void __meminit release_firmware_map_entry(struct kobject *kobj) kfree(entry); } -static struct kobj_type __refdata memmap_ktype = { +static const struct kobj_type memmap_ktype = { .release = release_firmware_map_entry, .sysfs_ops = &memmap_attr_ops, .default_groups = def_groups, diff --git a/drivers/firmware/microchip/mpfs-auto-update.c b/drivers/firmware/microchip/mpfs-auto-update.c index 0f7ec88482022c..e194f7acb2a9b0 100644 --- a/drivers/firmware/microchip/mpfs-auto-update.c +++ b/drivers/firmware/microchip/mpfs-auto-update.c @@ -402,10 +402,10 @@ static int mpfs_auto_update_available(struct mpfs_auto_update_priv *priv) return -EIO; /* - * Bit 5 of byte 1 is "UL_Auto Update" & if it is set, Auto Update is + * Bit 5 of byte 1 is "UL_IAP" & if it is set, Auto Update is * not possible. */ - if (response_msg[1] & AUTO_UPDATE_FEATURE_ENABLED) + if ((((u8 *)response_msg)[1] & AUTO_UPDATE_FEATURE_ENABLED)) return -EPERM; return 0; @@ -458,7 +458,7 @@ static struct platform_driver mpfs_auto_update_driver = { .name = "mpfs-auto-update", }, .probe = mpfs_auto_update_probe, - .remove_new = mpfs_auto_update_remove, + .remove = mpfs_auto_update_remove, }; module_platform_driver(mpfs_auto_update_driver); diff --git a/drivers/firmware/mtk-adsp-ipc.c b/drivers/firmware/mtk-adsp-ipc.c index a762302978de0f..2b79371c61c9bf 100644 --- a/drivers/firmware/mtk-adsp-ipc.c +++ b/drivers/firmware/mtk-adsp-ipc.c @@ -95,10 +95,9 @@ static int mtk_adsp_ipc_probe(struct platform_device *pdev) adsp_chan->idx = i; adsp_chan->ch = mbox_request_channel_byname(cl, adsp_mbox_ch_names[i]); if (IS_ERR(adsp_chan->ch)) { - ret = PTR_ERR(adsp_chan->ch); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to request mbox chan %s ret %d\n", - adsp_mbox_ch_names[i], ret); + ret = dev_err_probe(dev, PTR_ERR(adsp_chan->ch), + "Failed to request mbox channel %s\n", + adsp_mbox_ch_names[i]); for (j = 0; j < i; j++) { adsp_chan = &adsp_ipc->chans[j]; @@ -133,7 +132,7 @@ static struct platform_driver mtk_adsp_ipc_driver = { .name = "mtk-adsp-ipc", }, .probe = mtk_adsp_ipc_probe, - .remove_new = mtk_adsp_ipc_remove, + .remove = mtk_adsp_ipc_remove, }; builtin_platform_driver(mtk_adsp_ipc_driver); diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index 2328ca58bba61f..a1ebbe9b73b136 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -78,6 +78,7 @@ struct psci_0_1_function_ids get_psci_0_1_function_ids(void) static u32 psci_cpu_suspend_feature; static bool psci_system_reset2_supported; +static bool psci_system_off2_hibernate_supported; static inline bool psci_has_ext_power_state(void) { @@ -333,6 +334,36 @@ static void psci_sys_poweroff(void) invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); } +#ifdef CONFIG_HIBERNATION +static int psci_sys_hibernate(struct sys_off_data *data) +{ + /* + * If no hibernate type is specified SYSTEM_OFF2 defaults to selecting + * HIBERNATE_OFF. + * + * There are hypervisors in the wild that do not align with the spec and + * reject calls that explicitly provide a hibernate type. For + * compatibility with these nonstandard implementations, pass 0 as the + * type. + */ + if (system_entering_hibernation()) + invoke_psci_fn(PSCI_FN_NATIVE(1_3, SYSTEM_OFF2), 0, 0, 0); + return NOTIFY_DONE; +} + +static int __init psci_hibernate_init(void) +{ + if (psci_system_off2_hibernate_supported) { + /* Higher priority than EFI shutdown, but only for hibernate */ + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_FIRMWARE + 2, + psci_sys_hibernate, NULL); + } + return 0; +} +subsys_initcall(psci_hibernate_init); +#endif + static int psci_features(u32 psci_func_id) { return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES, @@ -364,6 +395,7 @@ static const struct { PSCI_ID_NATIVE(1_1, SYSTEM_RESET2), PSCI_ID(1_1, MEM_PROTECT), PSCI_ID_NATIVE(1_1, MEM_PROTECT_CHECK_RANGE), + PSCI_ID_NATIVE(1_3, SYSTEM_OFF2), }; static int psci_debugfs_read(struct seq_file *s, void *data) @@ -525,6 +557,18 @@ static void __init psci_init_system_reset2(void) psci_system_reset2_supported = true; } +static void __init psci_init_system_off2(void) +{ + int ret; + + ret = psci_features(PSCI_FN_NATIVE(1_3, SYSTEM_OFF2)); + if (ret < 0) + return; + + if (ret & PSCI_1_3_OFF_TYPE_HIBERNATE_OFF) + psci_system_off2_hibernate_supported = true; +} + static void __init psci_init_system_suspend(void) { int ret; @@ -655,6 +699,7 @@ static int __init psci_probe(void) psci_init_cpu_suspend(); psci_init_system_suspend(); psci_init_system_reset2(); + psci_init_system_off2(); kvm_init_hyp_services(); } diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 2e4260ba5f793c..72bf87ddcd9698 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -904,6 +904,32 @@ int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) } EXPORT_SYMBOL_GPL(qcom_scm_restore_sec_cfg); +#define QCOM_SCM_CP_APERTURE_CONTEXT_MASK GENMASK(7, 0) + +bool qcom_scm_set_gpu_smmu_aperture_is_available(void) +{ + return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_MP, + QCOM_SCM_MP_CP_SMMU_APERTURE_ID); +} +EXPORT_SYMBOL_GPL(qcom_scm_set_gpu_smmu_aperture_is_available); + +int qcom_scm_set_gpu_smmu_aperture(unsigned int context_bank) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_MP, + .cmd = QCOM_SCM_MP_CP_SMMU_APERTURE_ID, + .arginfo = QCOM_SCM_ARGS(4), + .args[0] = 0xffff0000 | FIELD_PREP(QCOM_SCM_CP_APERTURE_CONTEXT_MASK, context_bank), + .args[1] = 0xffffffff, + .args[2] = 0xffffffff, + .args[3] = 0xffffffff, + .owner = ARM_SMCCC_OWNER_SIP + }; + + return qcom_scm_call(__scm->dev, &desc, NULL); +} +EXPORT_SYMBOL_GPL(qcom_scm_set_gpu_smmu_aperture); + int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { struct qcom_scm_desc desc = { @@ -1742,12 +1768,16 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send); + any potential issues with this, only allow validated machines for now. */ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { + { .compatible = "dell,xps13-9345" }, { .compatible = "lenovo,flex-5g" }, { .compatible = "lenovo,thinkpad-t14s" }, { .compatible = "lenovo,thinkpad-x13s", }, + { .compatible = "lenovo,yoga-slim7x" }, + { .compatible = "microsoft,arcata", }, { .compatible = "microsoft,romulus13", }, { .compatible = "microsoft,romulus15", }, { .compatible = "qcom,sc8180x-primus" }, + { .compatible = "qcom,x1e001de-devkit" }, { .compatible = "qcom,x1e80100-crd" }, { .compatible = "qcom,x1e80100-qcp" }, { } diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h index 685b8f59e7a64e..e36b2f67607fc1 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -116,6 +116,7 @@ struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void); #define QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE 0x05 #define QCOM_SCM_MP_VIDEO_VAR 0x08 #define QCOM_SCM_MP_ASSIGN 0x16 +#define QCOM_SCM_MP_CP_SMMU_APERTURE_ID 0x1b #define QCOM_SCM_MP_SHM_BRIDGE_ENABLE 0x1c #define QCOM_SCM_MP_SHM_BRIDGE_DELETE 0x1d #define QCOM_SCM_MP_SHM_BRIDGE_CREATE 0x1e diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 85c525745b311f..d58da3e4500a5e 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -757,7 +757,7 @@ MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match); static struct platform_driver fw_cfg_sysfs_driver = { .probe = fw_cfg_sysfs_probe, - .remove_new = fw_cfg_sysfs_remove, + .remove = fw_cfg_sysfs_remove, .driver = { .name = "fw_cfg", .of_match_table = fw_cfg_sysfs_mmio_match, diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 18cc3498710853..7ecde6921a0ac2 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -406,7 +406,7 @@ static struct platform_driver rpi_firmware_driver = { }, .probe = rpi_firmware_probe, .shutdown = rpi_firmware_shutdown, - .remove_new = rpi_firmware_remove, + .remove = rpi_firmware_remove, }; module_platform_driver(rpi_firmware_driver); diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c index e20cee9c2d320a..1ea39a0a76c787 100644 --- a/drivers/firmware/stratix10-rsu.c +++ b/drivers/firmware/stratix10-rsu.c @@ -802,7 +802,7 @@ static void stratix10_rsu_remove(struct platform_device *pdev) static struct platform_driver stratix10_rsu_driver = { .probe = stratix10_rsu_probe, - .remove_new = stratix10_rsu_remove, + .remove = stratix10_rsu_remove, .driver = { .name = "stratix10-rsu", .dev_groups = rsu_groups, diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index 528f37417aea48..c5c78b869561b0 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -1271,7 +1271,7 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev) static struct platform_driver stratix10_svc_driver = { .probe = stratix10_svc_drv_probe, - .remove_new = stratix10_svc_drv_remove, + .remove = stratix10_svc_drv_remove, .driver = { .name = "stratix10-svc", .of_match_table = stratix10_svc_drv_match, diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c index a3df782fa687b0..7c5c03f274b951 100644 --- a/drivers/firmware/sysfb.c +++ b/drivers/firmware/sysfb.c @@ -79,6 +79,25 @@ void sysfb_disable(struct device *dev) } EXPORT_SYMBOL_GPL(sysfb_disable); +/** + * sysfb_handles_screen_info() - reports if sysfb handles the global screen_info + * + * Callers can use sysfb_handles_screen_info() to determine whether the Generic + * System Framebuffers (sysfb) can handle the global screen_info data structure + * or not. Drivers might need this information to know if they have to setup the + * system framebuffer, or if they have to delegate this action to sysfb instead. + * + * Returns: + * True if sysfb handles the global screen_info data structure. + */ +bool sysfb_handles_screen_info(void) +{ + const struct screen_info *si = &screen_info; + + return !!screen_info_video_type(si); +} +EXPORT_SYMBOL_GPL(sysfb_handles_screen_info); + #if defined(CONFIG_PCI) static bool sysfb_pci_dev_is_enabled(struct pci_dev *pdev) { diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 2bee6e918f8117..c3a1dc3449617f 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -3,7 +3,6 @@ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. */ -#include #include #include #include @@ -35,24 +34,29 @@ channel_to_ops(struct tegra_bpmp_channel *channel) struct tegra_bpmp *tegra_bpmp_get(struct device *dev) { - struct device_node *np __free(device_node); struct platform_device *pdev; struct tegra_bpmp *bpmp; + struct device_node *np; np = of_parse_phandle(dev->of_node, "nvidia,bpmp", 0); if (!np) return ERR_PTR(-ENOENT); pdev = of_find_device_by_node(np); - if (!pdev) - return ERR_PTR(-ENODEV); + if (!pdev) { + bpmp = ERR_PTR(-ENODEV); + goto put; + } bpmp = platform_get_drvdata(pdev); if (!bpmp) { + bpmp = ERR_PTR(-EPROBE_DEFER); put_device(&pdev->dev); - return ERR_PTR(-EPROBE_DEFER); + goto put; } +put: + of_node_put(np); return bpmp; } EXPORT_SYMBOL_GPL(tegra_bpmp_get); diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 160968301b1fbc..806a975fff22ae 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -2,13 +2,14 @@ /* * Texas Instruments System Control Interface Protocol Driver * - * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com/ * Nishanth Menon */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include +#include #include #include #include @@ -19,11 +20,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include "ti_sci.h" @@ -98,6 +102,7 @@ struct ti_sci_desc { * @minfo: Message info * @node: list head * @host_id: Host ID + * @fw_caps: FW/SoC low power capabilities * @users: Number of users of this instance */ struct ti_sci_info { @@ -114,6 +119,7 @@ struct ti_sci_info { struct ti_sci_xfers_info minfo; struct list_head node; u8 host_id; + u64 fw_caps; /* protected by ti_sci_list_mutex */ int users; }; @@ -1651,6 +1657,364 @@ static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle, return ret; } +/** + * ti_sci_cmd_prepare_sleep() - Prepare system for system suspend + * @handle: pointer to TI SCI handle + * @mode: Device identifier + * @ctx_lo: Low part of address for context save + * @ctx_hi: High part of address for context save + * @debug_flags: Debug flags to pass to firmware + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_prepare_sleep(const struct ti_sci_handle *handle, u8 mode, + u32 ctx_lo, u32 ctx_hi, u32 debug_flags) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_prepare_sleep *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_PREPARE_SLEEP, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + req = (struct ti_sci_msg_req_prepare_sleep *)xfer->xfer_buf; + req->mode = mode; + req->ctx_lo = ctx_lo; + req->ctx_hi = ctx_hi; + req->debug_flags = debug_flags; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + dev_err(dev, "Failed to prepare sleep\n"); + ret = -ENODEV; + } + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_msg_cmd_query_fw_caps() - Get the FW/SoC capabilities + * @handle: Pointer to TI SCI handle + * @fw_caps: Each bit in fw_caps indicating one FW/SOC capability + * + * Check if the firmware supports any optional low power modes. + * Old revisions of TIFS (< 08.04) will NACK the request which results in + * -ENODEV being returned. + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_msg_cmd_query_fw_caps(const struct ti_sci_handle *handle, + u64 *fw_caps) +{ + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + struct ti_sci_msg_resp_query_fw_caps *resp; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_QUERY_FW_CAPS, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(struct ti_sci_msg_hdr), + sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_query_fw_caps *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + dev_err(dev, "Failed to get capabilities\n"); + ret = -ENODEV; + goto fail; + } + + if (fw_caps) + *fw_caps = resp->fw_caps; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_set_io_isolation() - Enable IO isolation in LPM + * @handle: Pointer to TI SCI handle + * @state: The desired state of the IO isolation + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_set_io_isolation(const struct ti_sci_handle *handle, + u8 state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_io_isolation *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_IO_ISOLATION, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_set_io_isolation *)xfer->xfer_buf; + req->state = state; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + dev_err(dev, "Failed to set IO isolation\n"); + ret = -ENODEV; + } + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_msg_cmd_lpm_wake_reason() - Get the wakeup source from LPM + * @handle: Pointer to TI SCI handle + * @source: The wakeup source that woke the SoC from LPM + * @timestamp: Timestamp of the wakeup event + * @pin: The pin that has triggered wake up + * @mode: The last entered low power mode + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_msg_cmd_lpm_wake_reason(const struct ti_sci_handle *handle, + u32 *source, u64 *timestamp, u8 *pin, u8 *mode) +{ + struct ti_sci_info *info; + struct ti_sci_xfer *xfer; + struct ti_sci_msg_resp_lpm_wake_reason *resp; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_LPM_WAKE_REASON, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(struct ti_sci_msg_hdr), + sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_lpm_wake_reason *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + dev_err(dev, "Failed to get wake reason\n"); + ret = -ENODEV; + goto fail; + } + + if (source) + *source = resp->wake_source; + if (timestamp) + *timestamp = resp->wake_timestamp; + if (pin) + *pin = resp->wake_pin; + if (mode) + *mode = resp->mode; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_set_device_constraint() - Set LPM constraint on behalf of a device + * @handle: pointer to TI SCI handle + * @id: Device identifier + * @state: The desired state of device constraint: set or clear + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_set_device_constraint(const struct ti_sci_handle *handle, + u32 id, u8 state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_lpm_set_device_constraint *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_LPM_SET_DEVICE_CONSTRAINT, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_lpm_set_device_constraint *)xfer->xfer_buf; + req->id = id; + req->state = state; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + dev_err(dev, "Failed to set device constraint\n"); + ret = -ENODEV; + } + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_set_latency_constraint() - Set LPM resume latency constraint + * @handle: pointer to TI SCI handle + * @latency: maximum acceptable latency (in ms) to wake up from LPM + * @state: The desired state of latency constraint: set or clear + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_set_latency_constraint(const struct ti_sci_handle *handle, + u16 latency, u8 state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_lpm_set_latency_constraint *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_LPM_SET_LATENCY_CONSTRAINT, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_lpm_set_latency_constraint *)xfer->xfer_buf; + req->latency = latency; + req->state = state; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + dev_err(dev, "Failed to set device constraint\n"); + ret = -ENODEV; + } + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle) { struct ti_sci_info *info; @@ -2793,6 +3157,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) struct ti_sci_core_ops *core_ops = &ops->core_ops; struct ti_sci_dev_ops *dops = &ops->dev_ops; struct ti_sci_clk_ops *cops = &ops->clk_ops; + struct ti_sci_pm_ops *pmops = &ops->pm_ops; struct ti_sci_rm_core_ops *rm_core_ops = &ops->rm_core_ops; struct ti_sci_rm_irq_ops *iops = &ops->rm_irq_ops; struct ti_sci_rm_ringacc_ops *rops = &ops->rm_ring_ops; @@ -2832,6 +3197,13 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) cops->set_freq = ti_sci_cmd_clk_set_freq; cops->get_freq = ti_sci_cmd_clk_get_freq; + if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) { + pr_debug("detected DM managed LPM in fw_caps\n"); + pmops->lpm_wake_reason = ti_sci_msg_cmd_lpm_wake_reason; + pmops->set_device_constraint = ti_sci_cmd_set_device_constraint; + pmops->set_latency_constraint = ti_sci_cmd_set_latency_constraint; + } + rm_core_ops->get_range = ti_sci_cmd_get_resource_range; rm_core_ops->get_range_from_shost = ti_sci_cmd_get_resource_range_from_shost; @@ -3262,6 +3634,111 @@ static int tisci_reboot_handler(struct sys_off_data *data) return NOTIFY_BAD; } +static int ti_sci_prepare_system_suspend(struct ti_sci_info *info) +{ + /* + * Map and validate the target Linux suspend state to TISCI LPM. + * Default is to let Device Manager select the low power mode. + */ + switch (pm_suspend_target_state) { + case PM_SUSPEND_MEM: + if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) { + /* + * For the DM_MANAGED mode the context is reserved for + * internal use and can be 0 + */ + return ti_sci_cmd_prepare_sleep(&info->handle, + TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED, + 0, 0, 0); + } else { + /* DM Managed is not supported by the firmware. */ + dev_err(info->dev, "Suspend to memory is not supported by the firmware\n"); + return -EOPNOTSUPP; + } + break; + default: + /* + * Do not fail if we don't have action to take for a + * specific suspend mode. + */ + return 0; + } +} + +static int __maybe_unused ti_sci_suspend(struct device *dev) +{ + struct ti_sci_info *info = dev_get_drvdata(dev); + struct device *cpu_dev, *cpu_dev_max = NULL; + s32 val, cpu_lat = 0; + int i, ret; + + if (info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED) { + for_each_possible_cpu(i) { + cpu_dev = get_cpu_device(i); + val = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_RESUME_LATENCY); + if (val != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT) { + cpu_lat = max(cpu_lat, val); + cpu_dev_max = cpu_dev; + } + } + if (cpu_dev_max) { + dev_dbg(cpu_dev_max, "%s: sending max CPU latency=%u\n", __func__, cpu_lat); + ret = ti_sci_cmd_set_latency_constraint(&info->handle, + cpu_lat, TISCI_MSG_CONSTRAINT_SET); + if (ret) + return ret; + } + } + + ret = ti_sci_prepare_system_suspend(info); + if (ret) + return ret; + + return 0; +} + +static int __maybe_unused ti_sci_suspend_noirq(struct device *dev) +{ + struct ti_sci_info *info = dev_get_drvdata(dev); + int ret = 0; + + ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_ENABLE); + if (ret) + return ret; + + return 0; +} + +static int __maybe_unused ti_sci_resume_noirq(struct device *dev) +{ + struct ti_sci_info *info = dev_get_drvdata(dev); + int ret = 0; + u32 source; + u64 time; + u8 pin; + u8 mode; + + ret = ti_sci_cmd_set_io_isolation(&info->handle, TISCI_MSG_VALUE_IO_DISABLE); + if (ret) + return ret; + + ret = ti_sci_msg_cmd_lpm_wake_reason(&info->handle, &source, &time, &pin, &mode); + /* Do not fail to resume on error as the wake reason is not critical */ + if (!ret) + dev_info(dev, "ti_sci: wakeup source:0x%x, pin:0x%x, mode:0x%x\n", + source, pin, mode); + + return 0; +} + +static const struct dev_pm_ops ti_sci_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = ti_sci_suspend, + .suspend_noirq = ti_sci_suspend_noirq, + .resume_noirq = ti_sci_resume_noirq, +#endif +}; + /* Description for K2G */ static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = { .default_host_id = 2, @@ -3390,6 +3867,13 @@ static int ti_sci_probe(struct platform_device *pdev) goto out; } + ti_sci_msg_cmd_query_fw_caps(&info->handle, &info->fw_caps); + dev_dbg(dev, "Detected firmware capabilities: %s%s%s\n", + info->fw_caps & MSG_FLAG_CAPS_GENERIC ? "Generic" : "", + info->fw_caps & MSG_FLAG_CAPS_LPM_PARTIAL_IO ? " Partial-IO" : "", + info->fw_caps & MSG_FLAG_CAPS_LPM_DM_MANAGED ? " DM-Managed" : "" + ); + ti_sci_setup_ops(info); ret = devm_register_restart_handler(dev, tisci_reboot_handler, info); @@ -3421,8 +3905,9 @@ static struct platform_driver ti_sci_driver = { .probe = ti_sci_probe, .driver = { .name = "ti-sci", - .of_match_table = of_match_ptr(ti_sci_of_match), + .of_match_table = ti_sci_of_match, .suppress_bind_attrs = true, + .pm = &ti_sci_pm_ops, }, }; module_platform_driver(ti_sci_driver); diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 5846c60220f50c..053387d7baa064 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -6,7 +6,7 @@ * The system works in a message response protocol * See: https://software-dl.ti.com/tisci/esd/latest/index.html for details * - * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ + * Copyright (C) 2015-2024 Texas Instruments Incorporated - https://www.ti.com/ */ #ifndef __TI_SCI_H @@ -19,6 +19,7 @@ #define TI_SCI_MSG_WAKE_REASON 0x0003 #define TI_SCI_MSG_GOODBYE 0x0004 #define TI_SCI_MSG_SYS_RESET 0x0005 +#define TI_SCI_MSG_QUERY_FW_CAPS 0x0022 /* Device requests */ #define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 @@ -35,6 +36,13 @@ #define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d #define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e +/* Low Power Mode Requests */ +#define TI_SCI_MSG_PREPARE_SLEEP 0x0300 +#define TI_SCI_MSG_LPM_WAKE_REASON 0x0306 +#define TI_SCI_MSG_SET_IO_ISOLATION 0x0307 +#define TI_SCI_MSG_LPM_SET_DEVICE_CONSTRAINT 0x0309 +#define TI_SCI_MSG_LPM_SET_LATENCY_CONSTRAINT 0x030A + /* Resource Management Requests */ #define TI_SCI_MSG_GET_RESOURCE_RANGE 0x1500 @@ -132,6 +140,27 @@ struct ti_sci_msg_req_reboot { struct ti_sci_msg_hdr hdr; } __packed; +/** + * struct ti_sci_msg_resp_query_fw_caps - Response for query firmware caps + * @hdr: Generic header + * @fw_caps: Each bit in fw_caps indicating one FW/SOC capability + * MSG_FLAG_CAPS_GENERIC: Generic capability (LPM not supported) + * MSG_FLAG_CAPS_LPM_PARTIAL_IO: Partial IO in LPM + * MSG_FLAG_CAPS_LPM_DM_MANAGED: LPM can be managed by DM + * + * Response to a generic message with message type TI_SCI_MSG_QUERY_FW_CAPS + * providing currently available SOC/firmware capabilities. SoC that don't + * support low power modes return only MSG_FLAG_CAPS_GENERIC capability. + */ +struct ti_sci_msg_resp_query_fw_caps { + struct ti_sci_msg_hdr hdr; +#define MSG_FLAG_CAPS_GENERIC TI_SCI_MSG_FLAG(0) +#define MSG_FLAG_CAPS_LPM_PARTIAL_IO TI_SCI_MSG_FLAG(4) +#define MSG_FLAG_CAPS_LPM_DM_MANAGED TI_SCI_MSG_FLAG(5) +#define MSG_MASK_CAPS_LPM GENMASK_ULL(4, 1) + u64 fw_caps; +} __packed; + /** * struct ti_sci_msg_req_set_device_state - Set the desired state of the device * @hdr: Generic header @@ -545,6 +574,118 @@ struct ti_sci_msg_resp_get_clock_freq { u64 freq_hz; } __packed; +/** + * struct tisci_msg_req_prepare_sleep - Request for TISCI_MSG_PREPARE_SLEEP. + * + * @hdr TISCI header to provide ACK/NAK flags to the host. + * @mode Low power mode to enter. + * @ctx_lo Low 32-bits of physical pointer to address to use for context save. + * @ctx_hi High 32-bits of physical pointer to address to use for context save. + * @debug_flags Flags that can be set to halt the sequence during suspend or + * resume to allow JTAG connection and debug. + * + * This message is used as the first step of entering a low power mode. It + * allows configurable information, including which state to enter to be + * easily shared from the application, as this is a non-secure message and + * therefore can be sent by anyone. + */ +struct ti_sci_msg_req_prepare_sleep { + struct ti_sci_msg_hdr hdr; + +#define TISCI_MSG_VALUE_SLEEP_MODE_DM_MANAGED 0xfd + u8 mode; + u32 ctx_lo; + u32 ctx_hi; + u32 debug_flags; +} __packed; + +/** + * struct tisci_msg_set_io_isolation_req - Request for TI_SCI_MSG_SET_IO_ISOLATION. + * + * @hdr: Generic header + * @state: The deseared state of the IO isolation. + * + * This message is used to enable/disable IO isolation for low power modes. + * Response is generic ACK / NACK message. + */ +struct ti_sci_msg_req_set_io_isolation { + struct ti_sci_msg_hdr hdr; + u8 state; +} __packed; + +/** + * struct ti_sci_msg_resp_lpm_wake_reason - Response for TI_SCI_MSG_LPM_WAKE_REASON. + * + * @hdr: Generic header. + * @wake_source: The wake up source that woke soc from LPM. + * @wake_timestamp: Timestamp at which soc woke. + * @wake_pin: The pin that has triggered wake up. + * @mode: The last entered low power mode. + * @rsvd: Reserved for future use. + * + * Response to a generic message with message type TI_SCI_MSG_LPM_WAKE_REASON, + * used to query the wake up source, pin and entered low power mode. + */ +struct ti_sci_msg_resp_lpm_wake_reason { + struct ti_sci_msg_hdr hdr; + u32 wake_source; + u64 wake_timestamp; + u8 wake_pin; + u8 mode; + u32 rsvd[2]; +} __packed; + +/** + * struct ti_sci_msg_req_lpm_set_device_constraint - Request for + * TISCI_MSG_LPM_SET_DEVICE_CONSTRAINT. + * + * @hdr: TISCI header to provide ACK/NAK flags to the host. + * @id: Device ID of device whose constraint has to be modified. + * @state: The desired state of device constraint: set or clear. + * @rsvd: Reserved for future use. + * + * This message is used by host to set constraint on the device. This can be + * sent anytime after boot before prepare sleep message. Any device can set a + * constraint on the low power mode that the SoC can enter. It allows + * configurable information to be easily shared from the application, as this + * is a non-secure message and therefore can be sent by anyone. By setting a + * constraint, the device ensures that it will not be powered off or reset in + * the selected mode. Note: Access Restriction: Exclusivity flag of Device will + * be honored. If some other host already has constraint on this device ID, + * NACK will be returned. + */ +struct ti_sci_msg_req_lpm_set_device_constraint { + struct ti_sci_msg_hdr hdr; + u32 id; + u8 state; + u32 rsvd[2]; +} __packed; + +/** + * struct ti_sci_msg_req_lpm_set_latency_constraint - Request for + * TISCI_MSG_LPM_SET_LATENCY_CONSTRAINT. + * + * @hdr: TISCI header to provide ACK/NAK flags to the host. + * @wkup_latency: The maximum acceptable latency to wake up from low power mode + * in milliseconds. The deeper the state, the higher the latency. + * @state: The desired state of wakeup latency constraint: set or clear. + * @rsvd: Reserved for future use. + * + * This message is used by host to set wakeup latency from low power mode. This can + * be sent anytime after boot before prepare sleep message, and can be sent after + * current low power mode is exited. Any device can set a constraint on the low power + * mode that the SoC can enter. It allows configurable information to be easily shared + * from the application, as this is a non-secure message and therefore can be sent by + * anyone. By setting a wakeup latency constraint, the host ensures that the resume time + * from selected low power mode will be less than the constraint value. + */ +struct ti_sci_msg_req_lpm_set_latency_constraint { + struct ti_sci_msg_hdr hdr; + u16 latency; + u8 state; + u32 rsvd; +} __packed; + #define TI_SCI_IRQ_SECONDARY_HOST_INVALID 0xff /** diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index f3bc0d4278256b..47fe6261f5a32b 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -61,6 +61,27 @@ enum mbox_cmd { MBOX_CMD_OTP_WRITE = 8, }; +/** + * struct mox_rwtm - driver private data structure + * @mbox_client: rWTM mailbox client + * @mbox: rWTM mailbox channel + * @hwrng: RNG driver structure + * @reply: last mailbox reply, filled in receive callback + * @buf: DMA buffer + * @buf_phys: physical address of the DMA buffer + * @busy: mutex to protect mailbox command execution + * @cmd_done: command done completion + * @has_board_info: whether board information is present + * @serial_number: serial number of the device + * @board_version: board version / revision of the device + * @ram_size: RAM size of the device + * @mac_address1: first MAC address of the device + * @mac_address2: second MAC address of the device + * @has_pubkey: whether board ECDSA public key is present + * @pubkey: board ECDSA public key + * @last_sig: last ECDSA signature generated with board ECDSA private key + * @last_sig_done: whether the last ECDSA signing is complete + */ struct mox_rwtm { struct mbox_client mbox_client; struct mbox_chan *mbox; @@ -74,13 +95,11 @@ struct mox_rwtm { struct mutex busy; struct completion cmd_done; - /* board information */ bool has_board_info; u64 serial_number; int board_version, ram_size; u8 mac_address1[ETH_ALEN], mac_address2[ETH_ALEN]; - /* public key burned in eFuse */ bool has_pubkey; u8 pubkey[135]; diff --git a/drivers/firmware/xilinx/zynqmp-debug.c b/drivers/firmware/xilinx/zynqmp-debug.c index 8528850af88926..22853ae0efdfa8 100644 --- a/drivers/firmware/xilinx/zynqmp-debug.c +++ b/drivers/firmware/xilinx/zynqmp-debug.c @@ -31,12 +31,50 @@ static char debugfs_buf[PAGE_SIZE]; #define PM_API(id) {id, #id, strlen(#id)} static struct pm_api_info pm_api_list[] = { + PM_API(PM_FORCE_POWERDOWN), + PM_API(PM_REQUEST_WAKEUP), + PM_API(PM_SYSTEM_SHUTDOWN), + PM_API(PM_REQUEST_NODE), + PM_API(PM_RELEASE_NODE), + PM_API(PM_SET_REQUIREMENT), PM_API(PM_GET_API_VERSION), + PM_API(PM_REGISTER_NOTIFIER), + PM_API(PM_RESET_ASSERT), + PM_API(PM_RESET_GET_STATUS), + PM_API(PM_GET_CHIPID), + PM_API(PM_PINCTRL_SET_FUNCTION), + PM_API(PM_PINCTRL_CONFIG_PARAM_GET), + PM_API(PM_PINCTRL_CONFIG_PARAM_SET), + PM_API(PM_IOCTL), + PM_API(PM_CLOCK_ENABLE), + PM_API(PM_CLOCK_DISABLE), + PM_API(PM_CLOCK_GETSTATE), + PM_API(PM_CLOCK_SETDIVIDER), + PM_API(PM_CLOCK_GETDIVIDER), + PM_API(PM_CLOCK_SETPARENT), + PM_API(PM_CLOCK_GETPARENT), PM_API(PM_QUERY_DATA), }; static struct dentry *firmware_debugfs_root; +/** + * zynqmp_pm_ioctl - PM IOCTL for device control and configs + * @node: Node ID of the device + * @ioctl: ID of the requested IOCTL + * @arg1: Argument 1 of requested IOCTL call + * @arg2: Argument 2 of requested IOCTL call + * @arg3: Argument 3 of requested IOCTL call + * @out: Returned output value + * + * Return: Returns status, either success or error+reason + */ +static int zynqmp_pm_ioctl(const u32 node, const u32 ioctl, const u32 arg1, + const u32 arg2, const u32 arg3, u32 *out) +{ + return zynqmp_pm_invoke_fn(PM_IOCTL, out, 5, node, ioctl, arg1, arg2, arg3); +} + /** * zynqmp_pm_argument_value() - Extract argument value from a PM-API request * @arg: Entered PM-API argument in string format @@ -95,6 +133,128 @@ static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret) sprintf(debugfs_buf, "PM-API Version = %d.%d\n", pm_api_version >> 16, pm_api_version & 0xffff); break; + case PM_FORCE_POWERDOWN: + ret = zynqmp_pm_force_pwrdwn(pm_api_arg[0], + pm_api_arg[1] ? pm_api_arg[1] : + ZYNQMP_PM_REQUEST_ACK_NO); + break; + case PM_REQUEST_WAKEUP: + ret = zynqmp_pm_request_wake(pm_api_arg[0], + pm_api_arg[1], pm_api_arg[2], + pm_api_arg[3] ? pm_api_arg[3] : + ZYNQMP_PM_REQUEST_ACK_NO); + break; + case PM_SYSTEM_SHUTDOWN: + ret = zynqmp_pm_system_shutdown(pm_api_arg[0], pm_api_arg[1]); + break; + case PM_REQUEST_NODE: + ret = zynqmp_pm_request_node(pm_api_arg[0], + pm_api_arg[1] ? pm_api_arg[1] : + ZYNQMP_PM_CAPABILITY_ACCESS, + pm_api_arg[2] ? pm_api_arg[2] : 0, + pm_api_arg[3] ? pm_api_arg[3] : + ZYNQMP_PM_REQUEST_ACK_BLOCKING); + break; + case PM_RELEASE_NODE: + ret = zynqmp_pm_release_node(pm_api_arg[0]); + break; + case PM_SET_REQUIREMENT: + ret = zynqmp_pm_set_requirement(pm_api_arg[0], + pm_api_arg[1] ? pm_api_arg[1] : + ZYNQMP_PM_CAPABILITY_CONTEXT, + pm_api_arg[2] ? + pm_api_arg[2] : 0, + pm_api_arg[3] ? pm_api_arg[3] : + ZYNQMP_PM_REQUEST_ACK_BLOCKING); + break; + case PM_REGISTER_NOTIFIER: + ret = zynqmp_pm_register_notifier(pm_api_arg[0], + pm_api_arg[1] ? + pm_api_arg[1] : 0, + pm_api_arg[2] ? + pm_api_arg[2] : 0, + pm_api_arg[3] ? + pm_api_arg[3] : 0); + break; + case PM_RESET_ASSERT: + ret = zynqmp_pm_reset_assert(pm_api_arg[0], pm_api_arg[1]); + break; + case PM_RESET_GET_STATUS: + ret = zynqmp_pm_reset_get_status(pm_api_arg[0], &pm_api_ret[0]); + if (!ret) + sprintf(debugfs_buf, "Reset status: %u\n", + pm_api_ret[0]); + break; + case PM_GET_CHIPID: + ret = zynqmp_pm_get_chipid(&pm_api_ret[0], &pm_api_ret[1]); + if (!ret) + sprintf(debugfs_buf, "Idcode: %#x, Version:%#x\n", + pm_api_ret[0], pm_api_ret[1]); + break; + case PM_PINCTRL_SET_FUNCTION: + ret = zynqmp_pm_pinctrl_set_function(pm_api_arg[0], + pm_api_arg[1]); + break; + case PM_PINCTRL_CONFIG_PARAM_GET: + ret = zynqmp_pm_pinctrl_get_config(pm_api_arg[0], pm_api_arg[1], + &pm_api_ret[0]); + if (!ret) + sprintf(debugfs_buf, + "Pin: %llu, Param: %llu, Value: %u\n", + pm_api_arg[0], pm_api_arg[1], + pm_api_ret[0]); + break; + case PM_PINCTRL_CONFIG_PARAM_SET: + ret = zynqmp_pm_pinctrl_set_config(pm_api_arg[0], + pm_api_arg[1], + pm_api_arg[2]); + break; + case PM_IOCTL: + ret = zynqmp_pm_ioctl(pm_api_arg[0], pm_api_arg[1], + pm_api_arg[2], pm_api_arg[3], + pm_api_arg[4], &pm_api_ret[0]); + if (!ret && (pm_api_arg[1] == IOCTL_GET_RPU_OPER_MODE || + pm_api_arg[1] == IOCTL_GET_PLL_FRAC_MODE || + pm_api_arg[1] == IOCTL_GET_PLL_FRAC_DATA || + pm_api_arg[1] == IOCTL_READ_GGS || + pm_api_arg[1] == IOCTL_READ_PGGS || + pm_api_arg[1] == IOCTL_READ_REG)) + sprintf(debugfs_buf, "IOCTL return value: %u\n", + pm_api_ret[1]); + if (!ret && pm_api_arg[1] == IOCTL_GET_QOS) + sprintf(debugfs_buf, "Default QoS: %u\nCurrent QoS: %u\n", + pm_api_ret[1], pm_api_ret[2]); + break; + case PM_CLOCK_ENABLE: + ret = zynqmp_pm_clock_enable(pm_api_arg[0]); + break; + case PM_CLOCK_DISABLE: + ret = zynqmp_pm_clock_disable(pm_api_arg[0]); + break; + case PM_CLOCK_GETSTATE: + ret = zynqmp_pm_clock_getstate(pm_api_arg[0], &pm_api_ret[0]); + if (!ret) + sprintf(debugfs_buf, "Clock state: %u\n", + pm_api_ret[0]); + break; + case PM_CLOCK_SETDIVIDER: + ret = zynqmp_pm_clock_setdivider(pm_api_arg[0], pm_api_arg[1]); + break; + case PM_CLOCK_GETDIVIDER: + ret = zynqmp_pm_clock_getdivider(pm_api_arg[0], &pm_api_ret[0]); + if (!ret) + sprintf(debugfs_buf, "Divider Value: %d\n", + pm_api_ret[0]); + break; + case PM_CLOCK_SETPARENT: + ret = zynqmp_pm_clock_setparent(pm_api_arg[0], pm_api_arg[1]); + break; + case PM_CLOCK_GETPARENT: + ret = zynqmp_pm_clock_getparent(pm_api_arg[0], &pm_api_ret[0]); + if (!ret) + sprintf(debugfs_buf, + "Clock parent Index: %u\n", pm_api_ret[0]); + break; case PM_QUERY_DATA: qdata.qid = pm_api_arg[0]; qdata.arg1 = pm_api_arg[1]; @@ -150,7 +310,7 @@ static ssize_t zynqmp_pm_debugfs_api_write(struct file *file, char *kern_buff, *tmp_buff; char *pm_api_req; u32 pm_id = 0; - u64 pm_api_arg[4] = {0, 0, 0, 0}; + u64 pm_api_arg[5] = {0, 0, 0, 0, 0}; /* Return values from PM APIs calls */ u32 pm_api_ret[4] = {0, 0, 0, 0}; diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index add8acf66a9c7c..720fa8b5d8e95d 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -3,7 +3,7 @@ * Xilinx Zynq MPSoC Firmware layer * * Copyright (C) 2014-2022 Xilinx, Inc. - * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc. * * Michal Simek * Davorin Mista @@ -46,6 +46,7 @@ static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER); static u32 ioctl_features[FEATURE_PAYLOAD_SIZE]; static u32 query_features[FEATURE_PAYLOAD_SIZE]; +static u32 sip_svc_version; static struct platform_device *em_dev; /** @@ -151,6 +152,9 @@ static noinline int do_fw_call_smc(u32 *ret_payload, u32 num_args, ...) ret_payload[1] = upper_32_bits(res.a0); ret_payload[2] = lower_32_bits(res.a1); ret_payload[3] = upper_32_bits(res.a1); + ret_payload[4] = lower_32_bits(res.a2); + ret_payload[5] = upper_32_bits(res.a2); + ret_payload[6] = lower_32_bits(res.a3); } return zynqmp_pm_ret_code((enum pm_ret_status)res.a0); @@ -191,6 +195,9 @@ static noinline int do_fw_call_hvc(u32 *ret_payload, u32 num_args, ...) ret_payload[1] = upper_32_bits(res.a0); ret_payload[2] = lower_32_bits(res.a1); ret_payload[3] = upper_32_bits(res.a1); + ret_payload[4] = lower_32_bits(res.a2); + ret_payload[5] = upper_32_bits(res.a2); + ret_payload[6] = lower_32_bits(res.a3); } return zynqmp_pm_ret_code((enum pm_ret_status)res.a0); @@ -218,11 +225,14 @@ static int __do_feature_check_call(const u32 api_id, u32 *ret_payload) * Feature check of TF-A APIs is done in the TF-A layer and it expects for * MODULE_ID_MASK bits of SMC's arg[0] to be the same as PM_MODULE_ID. */ - if (module_id == TF_A_MODULE_ID) + if (module_id == TF_A_MODULE_ID) { module_id = PM_MODULE_ID; + smc_arg[1] = api_id; + } else { + smc_arg[1] = (api_id & API_ID_MASK); + } smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, module_id) | feature_check_api_id; - smc_arg[1] = (api_id & API_ID_MASK); ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]); if (ret) @@ -331,6 +341,70 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) } EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported); +/** + * zynqmp_pm_invoke_fw_fn() - Invoke the system-level platform management layer + * caller function depending on the configuration + * @pm_api_id: Requested PM-API call + * @ret_payload: Returned value array + * @num_args: Number of arguments to requested PM-API call + * + * Invoke platform management function for SMC or HVC call, depending on + * configuration. + * Following SMC Calling Convention (SMCCC) for SMC64: + * Pm Function Identifier, + * PM_SIP_SVC + PASS_THROUGH_FW_CMD_ID = + * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) + * ((SMC_64) << FUNCID_CC_SHIFT) + * ((SIP_START) << FUNCID_OEN_SHIFT) + * (PASS_THROUGH_FW_CMD_ID)) + * + * PM_SIP_SVC - Registered ZynqMP SIP Service Call. + * PASS_THROUGH_FW_CMD_ID - Fixed SiP SVC call ID for FW specific calls. + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_invoke_fw_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...) +{ + /* + * Added SIP service call Function Identifier + * Make sure to stay in x0 register + */ + u64 smc_arg[SMC_ARG_CNT_64]; + int ret, i; + va_list arg_list; + u32 args[SMC_ARG_CNT_32] = {0}; + u32 module_id; + + if (num_args > SMC_ARG_CNT_32) + return -EINVAL; + + va_start(arg_list, num_args); + + /* Check if feature is supported or not */ + ret = zynqmp_pm_feature(pm_api_id); + if (ret < 0) + return ret; + + for (i = 0; i < num_args; i++) + args[i] = va_arg(arg_list, u32); + + va_end(arg_list); + + module_id = FIELD_GET(PLM_MODULE_ID_MASK, pm_api_id); + + if (module_id == 0) + module_id = XPM_MODULE_ID; + + smc_arg[0] = PM_SIP_SVC | PASS_THROUGH_FW_CMD_ID; + smc_arg[1] = ((u64)args[0] << 32U) | FIELD_PREP(PLM_MODULE_ID_MASK, module_id) | + (pm_api_id & API_ID_MASK); + for (i = 1; i < (SMC_ARG_CNT_64 - 1); i++) + smc_arg[i + 1] = ((u64)args[(i * 2)] << 32U) | args[(i * 2) - 1]; + + return do_fw_call(ret_payload, 8, smc_arg[0], smc_arg[1], smc_arg[2], smc_arg[3], + smc_arg[4], smc_arg[5], smc_arg[6], smc_arg[7]); +} + /** * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer * caller function depending on the configuration @@ -488,6 +562,35 @@ int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily) } EXPORT_SYMBOL_GPL(zynqmp_pm_get_family_info); +/** + * zynqmp_pm_get_sip_svc_version() - Get SiP service call version + * @version: Returned version value + * + * Return: Returns status, either success or error+reason + */ +static int zynqmp_pm_get_sip_svc_version(u32 *version) +{ + struct arm_smccc_res res; + u64 args[SMC_ARG_CNT_64] = {0}; + + if (!version) + return -EINVAL; + + /* Check if SiP SVC version already verified */ + if (sip_svc_version > 0) { + *version = sip_svc_version; + return 0; + } + + args[0] = GET_SIP_SVC_VERSION; + + arm_smccc_smc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res); + + *version = ((lower_32_bits(res.a0) << 16U) | lower_32_bits(res.a1)); + + return zynqmp_pm_ret_code(XST_PM_SUCCESS); +} + /** * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version * @version: Returned version value @@ -552,10 +655,34 @@ static int get_set_conduit_method(struct device_node *np) */ int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out) { - int ret; + int ret, i = 0; + u32 ret_payload[PAYLOAD_ARG_CNT] = {0}; + + if (sip_svc_version >= SIP_SVC_PASSTHROUGH_VERSION) { + ret = zynqmp_pm_invoke_fw_fn(PM_QUERY_DATA, ret_payload, 4, + qdata.qid, qdata.arg1, + qdata.arg2, qdata.arg3); + /* To support backward compatibility */ + if (!ret && !ret_payload[0]) { + /* + * TF-A passes return status on 0th index but + * api to get clock name reads data from 0th + * index so pass data at 0th index instead of + * return status + */ + if (qdata.qid == PM_QID_CLOCK_GET_NAME || + qdata.qid == PM_QID_PINCTRL_GET_FUNCTION_NAME) + i = 1; + + for (; i < PAYLOAD_ARG_CNT; i++, out++) + *out = ret_payload[i]; + + return ret; + } + } - ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid, qdata.arg1, qdata.arg2, - qdata.arg3); + ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid, + qdata.arg1, qdata.arg2, qdata.arg3); /* * For clock name query, all bytes in SMC response are clock name @@ -920,7 +1047,7 @@ int zynqmp_pm_set_boot_health_status(u32 value) * * Return: Returns status, either success or error+reason */ -int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset, +int zynqmp_pm_reset_assert(const u32 reset, const enum zynqmp_pm_reset_action assert_flag) { return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, NULL, 2, reset, assert_flag); @@ -934,7 +1061,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_reset_assert); * * Return: Returns status, either success or error+reason */ -int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, u32 *status) +int zynqmp_pm_reset_get_status(const u32 reset, u32 *status) { u32 ret_payload[PAYLOAD_ARG_CNT]; int ret; @@ -1118,8 +1245,11 @@ int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, if (pm_family_code == ZYNQMP_FAMILY_CODE && param == PM_PINCTRL_CONFIG_TRI_STATE) { ret = zynqmp_pm_feature(PM_PINCTRL_CONFIG_PARAM_SET); - if (ret < PM_PINCTRL_PARAM_SET_VERSION) + if (ret < PM_PINCTRL_PARAM_SET_VERSION) { + pr_warn("The requested pinctrl feature is not supported in the current firmware.\n" + "Expected firmware version is 2023.1 and above for this feature to work.\r\n"); return -EOPNOTSUPP; + } } return zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_SET, NULL, 3, pin, param, value); @@ -1887,6 +2017,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) if (ret) return ret; + /* Get SiP SVC version number */ + ret = zynqmp_pm_get_sip_svc_version(&sip_svc_version); + if (ret) + return ret; + ret = do_feature_check_call(PM_FEATURE_CHECK); if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1)) feature_check_enabled = true; @@ -1983,6 +2118,6 @@ static struct platform_driver zynqmp_firmware_driver = { .dev_groups = zynqmp_firmware_groups, }, .probe = zynqmp_firmware_probe, - .remove_new = zynqmp_firmware_remove, + .remove = zynqmp_firmware_remove, }; module_platform_driver(zynqmp_firmware_driver); diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c index f4de3fea0b2dcd..e41492988dd633 100644 --- a/drivers/fpga/altera-fpga2sdram.c +++ b/drivers/fpga/altera-fpga2sdram.c @@ -152,7 +152,7 @@ MODULE_DEVICE_TABLE(of, altera_fpga_of_match); static struct platform_driver altera_fpga_driver = { .probe = alt_fpga_bridge_probe, - .remove_new = alt_fpga_bridge_remove, + .remove = alt_fpga_bridge_remove, .driver = { .name = "altera_fpga2sdram_bridge", .of_match_table = of_match_ptr(altera_fpga_of_match), diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c index 44061cb16f8770..594693ff786e25 100644 --- a/drivers/fpga/altera-freeze-bridge.c +++ b/drivers/fpga/altera-freeze-bridge.c @@ -262,7 +262,7 @@ static void altera_freeze_br_remove(struct platform_device *pdev) static struct platform_driver altera_freeze_br_driver = { .probe = altera_freeze_br_probe, - .remove_new = altera_freeze_br_remove, + .remove = altera_freeze_br_remove, .driver = { .name = "altera_freeze_br", .of_match_table = altera_freeze_br_of_match, diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c index 6f8e24be19c6df..f2f1250689cb0a 100644 --- a/drivers/fpga/altera-hps2fpga.c +++ b/drivers/fpga/altera-hps2fpga.c @@ -205,7 +205,7 @@ MODULE_DEVICE_TABLE(of, altera_fpga_of_match); static struct platform_driver alt_fpga_bridge_driver = { .probe = alt_fpga_bridge_probe, - .remove_new = alt_fpga_bridge_remove, + .remove = alt_fpga_bridge_remove, .driver = { .name = "altera_hps2fpga_bridge", .of_match_table = of_match_ptr(altera_fpga_of_match), diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index 6b97c073849ea9..2fd4f07ed081ad 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c @@ -947,12 +947,12 @@ static const struct attribute_group *afu_dev_groups[] = { }; static struct platform_driver afu_driver = { - .driver = { - .name = DFL_FPGA_FEATURE_DEV_PORT, + .driver = { + .name = DFL_FPGA_FEATURE_DEV_PORT, .dev_groups = afu_dev_groups, }, - .probe = afu_probe, - .remove_new = afu_remove, + .probe = afu_probe, + .remove = afu_remove, }; static int __init afu_init(void) diff --git a/drivers/fpga/dfl-fme-br.c b/drivers/fpga/dfl-fme-br.c index 0b01b389527760..950c606c59d446 100644 --- a/drivers/fpga/dfl-fme-br.c +++ b/drivers/fpga/dfl-fme-br.c @@ -92,11 +92,11 @@ static void fme_br_remove(struct platform_device *pdev) } static struct platform_driver fme_br_driver = { - .driver = { - .name = DFL_FPGA_FME_BRIDGE, + .driver = { + .name = DFL_FPGA_FME_BRIDGE, }, - .probe = fme_br_probe, - .remove_new = fme_br_remove, + .probe = fme_br_probe, + .remove = fme_br_remove, }; module_platform_driver(fme_br_driver); diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c index 864924f68f5e2c..f8d89a4a6ccbfb 100644 --- a/drivers/fpga/dfl-fme-main.c +++ b/drivers/fpga/dfl-fme-main.c @@ -742,12 +742,12 @@ static const struct attribute_group *fme_dev_groups[] = { }; static struct platform_driver fme_driver = { - .driver = { - .name = DFL_FPGA_FEATURE_DEV_FME, + .driver = { + .name = DFL_FPGA_FEATURE_DEV_FME, .dev_groups = fme_dev_groups, }, - .probe = fme_probe, - .remove_new = fme_remove, + .probe = fme_probe, + .remove = fme_remove, }; module_platform_driver(fme_driver); diff --git a/drivers/fpga/dfl-fme-region.c b/drivers/fpga/dfl-fme-region.c index 71616f8b4982de..c6cd63063c8200 100644 --- a/drivers/fpga/dfl-fme-region.c +++ b/drivers/fpga/dfl-fme-region.c @@ -71,11 +71,11 @@ static void fme_region_remove(struct platform_device *pdev) } static struct platform_driver fme_region_driver = { - .driver = { - .name = DFL_FPGA_FME_REGION, + .driver = { + .name = DFL_FPGA_FME_REGION, }, - .probe = fme_region_probe, - .remove_new = fme_region_remove, + .probe = fme_region_probe, + .remove = fme_region_remove, }; module_platform_driver(fme_region_driver); diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index 80cac3a5f97678..602807d6afcc09 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -39,14 +39,6 @@ struct cci_drvdata { struct dfl_fpga_cdev *cdev; /* container device */ }; -static void __iomem *cci_pci_ioremap_bar0(struct pci_dev *pcidev) -{ - if (pcim_iomap_regions(pcidev, BIT(0), DRV_NAME)) - return NULL; - - return pcim_iomap_table(pcidev)[0]; -} - static int cci_pci_alloc_irq(struct pci_dev *pcidev) { int ret, nvec = pci_msix_vec_count(pcidev); @@ -235,9 +227,9 @@ static int find_dfls_by_default(struct pci_dev *pcidev, u64 v; /* start to find Device Feature List from Bar 0 */ - base = cci_pci_ioremap_bar0(pcidev); - if (!base) - return -ENOMEM; + base = pcim_iomap_region(pcidev, 0, DRV_NAME); + if (IS_ERR(base)) + return PTR_ERR(base); /* * PF device has FME and Ports/AFUs, and VF device only has one @@ -296,7 +288,7 @@ static int find_dfls_by_default(struct pci_dev *pcidev, } /* release I/O mappings for next step enumeration */ - pcim_iounmap_regions(pcidev, BIT(0)); + pcim_iounmap_region(pcidev, 0); return ret; } diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index 7ac9f9f5af129b..10f678b9ed3662 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -759,7 +759,7 @@ MODULE_DEVICE_TABLE(platform, intel_m10bmc_sec_ids); static struct platform_driver intel_m10bmc_sec_driver = { .probe = m10bmc_sec_probe, - .remove_new = m10bmc_sec_remove, + .remove = m10bmc_sec_remove, .driver = { .name = "intel-m10bmc-sec-update", .dev_groups = m10bmc_sec_attr_groups, @@ -771,4 +771,4 @@ module_platform_driver(intel_m10bmc_sec_driver); MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Intel MAX10 BMC Secure Update"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); +MODULE_IMPORT_NS("INTEL_M10_BMC_CORE"); diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c index 8526a5a86f0cbe..43db4bb77138a8 100644 --- a/drivers/fpga/of-fpga-region.c +++ b/drivers/fpga/of-fpga-region.c @@ -436,7 +436,7 @@ static void of_fpga_region_remove(struct platform_device *pdev) static struct platform_driver of_fpga_region_driver = { .probe = of_fpga_region_probe, - .remove_new = of_fpga_region_remove, + .remove = of_fpga_region_remove, .driver = { .name = "of-fpga-region", .of_match_table = of_match_ptr(fpga_region_of_match), diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c index 4c03513b8f03b5..0165a3c8693223 100644 --- a/drivers/fpga/socfpga-a10.c +++ b/drivers/fpga/socfpga-a10.c @@ -535,7 +535,7 @@ MODULE_DEVICE_TABLE(of, socfpga_a10_fpga_of_match); static struct platform_driver socfpga_a10_fpga_driver = { .probe = socfpga_a10_fpga_probe, - .remove_new = socfpga_a10_fpga_remove, + .remove = socfpga_a10_fpga_remove, .driver = { .name = "socfpga_a10_fpga_manager", .of_match_table = socfpga_a10_fpga_of_match, diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c index 2c0def7d7cbb16..0a295ccf1644a8 100644 --- a/drivers/fpga/stratix10-soc.c +++ b/drivers/fpga/stratix10-soc.c @@ -455,7 +455,7 @@ MODULE_DEVICE_TABLE(of, s10_of_match); static struct platform_driver s10_driver = { .probe = s10_probe, - .remove_new = s10_remove, + .remove = s10_remove, .driver = { .name = "Stratix10 SoC FPGA manager", .of_match_table = of_match_ptr(s10_of_match), diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 788dd2f63a652e..822751fad18ae7 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -162,7 +162,7 @@ static void xlnx_pr_decoupler_remove(struct platform_device *pdev) static struct platform_driver xlnx_pr_decoupler_driver = { .probe = xlnx_pr_decoupler_probe, - .remove_new = xlnx_pr_decoupler_remove, + .remove = xlnx_pr_decoupler_remove, .driver = { .name = "xlnx_pr_decoupler", .of_match_table = xlnx_pr_decoupler_of_match, diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 4db3d80e10b090..f7e08f7ea9ef3c 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -642,7 +642,7 @@ MODULE_DEVICE_TABLE(of, zynq_fpga_of_match); static struct platform_driver zynq_fpga_driver = { .probe = zynq_fpga_probe, - .remove_new = zynq_fpga_remove, + .remove = zynq_fpga_remove, .driver = { .name = "zynq_fpga_manager", .of_match_table = of_match_ptr(zynq_fpga_of_match), diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index 6f5e1bdf7e40e4..bff897f77fe5fd 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -666,7 +666,7 @@ static struct platform_driver fsi_master_aspeed_driver = { .of_match_table = fsi_master_aspeed_match, }, .probe = fsi_master_aspeed_probe, - .remove_new = fsi_master_aspeed_remove, + .remove = fsi_master_aspeed_remove, }; module_platform_driver(fsi_master_aspeed_driver); diff --git a/drivers/fsi/fsi-master-ast-cf.c b/drivers/fsi/fsi-master-ast-cf.c index a4c37ff8edd69d..9f2fd444ceb604 100644 --- a/drivers/fsi/fsi-master-ast-cf.c +++ b/drivers/fsi/fsi-master-ast-cf.c @@ -1434,7 +1434,7 @@ static struct platform_driver fsi_master_acf = { .of_match_table = fsi_master_acf_match, }, .probe = fsi_master_acf_probe, - .remove_new = fsi_master_acf_remove, + .remove = fsi_master_acf_remove, }; module_platform_driver(fsi_master_acf); diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c index f761344f487329..69de0b5b9cbd18 100644 --- a/drivers/fsi/fsi-master-gpio.c +++ b/drivers/fsi/fsi-master-gpio.c @@ -888,7 +888,7 @@ static struct platform_driver fsi_master_gpio_driver = { .of_match_table = fsi_master_gpio_match, }, .probe = fsi_master_gpio_probe, - .remove_new = fsi_master_gpio_remove, + .remove = fsi_master_gpio_remove, }; module_platform_driver(fsi_master_gpio_driver); diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index a6d4c8f123a5a9..d3e6bf37878a76 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -740,7 +740,7 @@ static struct platform_driver occ_driver = { .of_match_table = occ_match, }, .probe = occ_probe, - .remove_new = occ_remove, + .remove = occ_remove, }; static int occ_init(void) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d93cd4f722b401..93ee3aa092f81c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -70,8 +70,7 @@ config GPIO_SYSFS ioctl() operations instead. config GPIO_CDEV - bool - prompt "Character device (/dev/gpiochipN) support" if EXPERT + bool "Character device (/dev/gpiochipN) support" if EXPERT default y help Say Y here to add the character device /dev/gpiochipN interface @@ -149,9 +148,7 @@ config GPIO_74XX_MMIO config GPIO_ALTERA tristate "Altera GPIO" - depends on OF_GPIO select GPIOLIB_IRQCHIP - select OF_GPIO_MM_GPIOCHIP help Say Y or M here to build support for the Altera PIO device. @@ -243,7 +240,7 @@ config GPIO_CLPS711X config GPIO_DAVINCI tristate "TI Davinci/Keystone GPIO support" default y if ARCH_DAVINCI - depends on (ARM || ARM64) && (ARCH_DAVINCI || ARCH_KEYSTONE || ARCH_K3) + depends on ((ARM || ARM64) && (ARCH_DAVINCI || ARCH_KEYSTONE || ARCH_K3)) || COMPILE_TEST help Say yes here to enable GPIO support for TI Davinci/Keystone SoCs. @@ -341,7 +338,6 @@ config GPIO_GRANITERAPIDS config GPIO_GRGPIO tristate "Aeroflex Gaisler GRGPIO support" - depends on OF_GPIO select GPIO_GENERIC select IRQ_DOMAIN help @@ -486,9 +482,9 @@ config GPIO_MT7621 Say yes here to support the Mediatek MT7621 SoC GPIO device. config GPIO_MVEBU - def_bool y - depends on PLAT_ORION || ARCH_MVEBU - depends on OF_GPIO + bool "Marvell Orion and EBU GPIO support" if COMPILE_TEST + depends on PLAT_ORION || ARCH_MVEBU || COMPILE_TEST + default PLAT_ORION || ARCH_MVEBU select GENERIC_IRQ_CHIP select REGMAP_MMIO @@ -549,6 +545,12 @@ config GPIO_PL061 help Say yes here to support the PrimeCell PL061 GPIO device. +config GPIO_POLARFIRE_SOC + bool "Microchip FPGA GPIO support" + select REGMAP_MMIO + help + Say yes here to support the GPIO controllers on Microchip FPGAs. + config GPIO_PXA bool "PXA GPIO support" depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST @@ -714,13 +716,13 @@ config GPIO_TEGRA config GPIO_TEGRA186 tristate "NVIDIA Tegra186 GPIO support" - default ARCH_TEGRA_186_SOC || ARCH_TEGRA_194_SOC - depends on ARCH_TEGRA_186_SOC || ARCH_TEGRA_194_SOC || COMPILE_TEST + default ARCH_TEGRA_186_SOC || ARCH_TEGRA_194_SOC || ARCH_TEGRA_234_SOC + depends on ARCH_TEGRA_186_SOC || ARCH_TEGRA_194_SOC || ARCH_TEGRA_234_SOC || COMPILE_TEST depends on OF_GPIO select GPIOLIB_IRQCHIP select IRQ_DOMAIN_HIERARCHY help - Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs. + Say yes here to support GPIO pins on NVIDIA Tegra186, 194 and 234 SoCs. config GPIO_TS4800 tristate "TS-4800 DIO blocks and compatibles" @@ -796,7 +798,6 @@ config GPIO_XGENE_SB config GPIO_XILINX tristate "Xilinx GPIO support" select GPIOLIB_IRQCHIP - depends on OF_GPIO help Say yes here to support the Xilinx FPGA GPIO device. @@ -1287,6 +1288,16 @@ config GPIO_BD9571MWV This driver can also be built as a module. If so, the module will be called gpio-bd9571mwv. +config GPIO_CGBC + tristate "Congatec Board Controller GPIO support" + depends on MFD_CGBC + help + Select this option to enable GPIO support for the Congatec Board + Controller. + + This driver can also be built as a module. If so, the module will be + called gpio-cgbc. + config GPIO_CROS_EC tristate "ChromeOS EC GPIO support" depends on CROS_EC @@ -1844,6 +1855,13 @@ config GPIO_VIPERBOARD River Tech's viperboard.h for detailed meaning of the module parameters. +config GPIO_MPSSE + tristate "FTDI MPSSE GPIO support" + select GPIOLIB_IRQCHIP + help + GPIO driver for FTDI's MPSSE interface. These can do input and + output. Each MPSSE provides 16 IO pins. + endmenu menu "Virtual GPIO drivers" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1429e8c0229b92..af3ba4d81b5838 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o +obj-$(CONFIG_GPIO_CGBC) += gpio-cgbc.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o obj-$(CONFIG_GPIO_CROS_EC) += gpio-cros-ec.o @@ -114,6 +115,7 @@ obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o +obj-$(CONFIG_GPIO_MPSSE) += gpio-mpsse.o obj-$(CONFIG_GPIO_MSC313) += gpio-msc313.o obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o @@ -133,6 +135,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o +obj-$(CONFIG_GPIO_POLARFIRE_SOC) += gpio-mpfs.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 189c3abe7e79d4..942d1cd2bd3c99 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -61,8 +61,8 @@ Work items: - Change all consumer drivers that #include to #include and stop doing custom parsing of the - GPIO lines from the device tree. This can be tricky and often ivolves - changing boardfiles, etc. + GPIO lines from the device tree. This can be tricky and often involves + changing board files, etc. - Pull semantics for legacy device tree (OF) GPIO lookups into gpiolib-of.c: in some cases subsystems are doing custom flags and diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 4df9becaf3490c..cf5a50102d4916 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -22,7 +22,7 @@ #include "gpio-i8255.h" -MODULE_IMPORT_NS(I8255); +MODULE_IMPORT_NS("I8255"); #define DIO48E_EXTENT 16 #define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT) @@ -339,4 +339,4 @@ module_isa_driver_with_irq(dio48e_driver, num_dio48e, num_irq); MODULE_AUTHOR("William Breathitt Gray "); MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(I8254); +MODULE_IMPORT_NS("I8254"); diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index f03ccd0f534cff..ffe7e1cb6b2388 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -126,4 +126,4 @@ module_isa_driver_with_irq(idio_16_driver, num_idio_16, num_irq); MODULE_AUTHOR("William Breathitt Gray "); MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(GPIO_IDIO_16); +MODULE_IMPORT_NS("GPIO_IDIO_16"); diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 753e7be039e4d9..fca6cd2eb1ddac 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -143,24 +143,17 @@ static int gen_74x164_probe(struct spi_device *spi) chip->gpio_chip.parent = &spi->dev; chip->gpio_chip.owner = THIS_MODULE; - mutex_init(&chip->lock); + ret = devm_mutex_init(&spi->dev, &chip->lock); + if (ret) + return ret; ret = __gen_74x164_write_config(chip); - if (ret) { - dev_err(&spi->dev, "Failed writing: %d\n", ret); - goto exit_destroy; - } + if (ret) + return dev_err_probe(&spi->dev, ret, "Config write failed\n"); gpiod_set_value_cansleep(chip->gpiod_oe, 1); - ret = gpiochip_add_data(&chip->gpio_chip, chip); - if (!ret) - return 0; - -exit_destroy: - mutex_destroy(&chip->lock); - - return ret; + return devm_gpiochip_add_data(&spi->dev, &chip->gpio_chip, chip); } static void gen_74x164_remove(struct spi_device *spi) @@ -168,8 +161,6 @@ static void gen_74x164_remove(struct spi_device *spi) struct gen_74x164_chip *chip = spi_get_drvdata(spi); gpiod_set_value_cansleep(chip->gpiod_oe, 0); - gpiochip_remove(&chip->gpio_chip); - mutex_destroy(&chip->lock); } static const struct spi_device_id gen_74x164_spi_ids[] = { diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 38e0fff9afe722..65f41cc3eafcc4 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -65,11 +65,11 @@ static int aggr_parse(struct gpio_aggregator *aggr) { char *args = skip_spaces(aggr->args); char *name, *offsets, *p; - unsigned long *bitmap; unsigned int i, n = 0; int error = 0; - bitmap = bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); + unsigned long *bitmap __free(bitmap) = + bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); if (!bitmap) return -ENOMEM; @@ -82,7 +82,7 @@ static int aggr_parse(struct gpio_aggregator *aggr) /* Named GPIO line */ error = aggr_add_gpio(aggr, name, U16_MAX, &n); if (error) - goto free_bitmap; + return error; name = offsets; continue; @@ -92,13 +92,13 @@ static int aggr_parse(struct gpio_aggregator *aggr) error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS); if (error) { pr_err("Cannot parse %s: %d\n", offsets, error); - goto free_bitmap; + return error; } for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { error = aggr_add_gpio(aggr, name, i, &n); if (error) - goto free_bitmap; + return error; } args = next_arg(args, &name, &p); @@ -106,12 +106,10 @@ static int aggr_parse(struct gpio_aggregator *aggr) if (!n) { pr_err("No GPIOs specified\n"); - error = -EINVAL; + return -EINVAL; } -free_bitmap: - bitmap_free(bitmap); - return error; + return 0; } static ssize_t new_device_store(struct device_driver *driver, const char *buf, diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index c2edfbb231fc4d..73e660c5e38a14 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -4,11 +4,19 @@ * Based on gpio-mpc8xxx.c */ +#include +#include +#include #include +#include +#include #include -#include -#include #include +#include +#include +#include + +#include #define ALTERA_GPIO_MAX_NGPIO 32 #define ALTERA_GPIO_DATA 0x0 @@ -18,7 +26,8 @@ /** * struct altera_gpio_chip -* @mmchip : memory mapped chip structure. +* @gc : GPIO chip structure. +* @regs : memory mapped IO address for the controller registers. * @gpio_lock : synchronization lock so that new irq/set/get requests * will be blocked until the current one completes. * @interrupt_trigger : specifies the hardware configured IRQ trigger type @@ -26,7 +35,8 @@ * @mapped_irq : kernel mapped irq number. */ struct altera_gpio_chip { - struct of_mm_gpio_chip mmchip; + struct gpio_chip gc; + void __iomem *regs; raw_spinlock_t gpio_lock; int interrupt_trigger; int mapped_irq; @@ -34,40 +44,36 @@ struct altera_gpio_chip { static void altera_gpio_irq_unmask(struct irq_data *d) { - struct altera_gpio_chip *altera_gc; - struct of_mm_gpio_chip *mm_gc; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); unsigned long flags; u32 intmask; - altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); - mm_gc = &altera_gc->mmchip; - gpiochip_enable_irq(&mm_gc->gc, irqd_to_hwirq(d)); + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); - intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + intmask = readl(altera_gc->regs + ALTERA_GPIO_IRQ_MASK); /* Set ALTERA_GPIO_IRQ_MASK bit to unmask */ intmask |= BIT(irqd_to_hwirq(d)); - writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + writel(intmask, altera_gc->regs + ALTERA_GPIO_IRQ_MASK); raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); } static void altera_gpio_irq_mask(struct irq_data *d) { - struct altera_gpio_chip *altera_gc; - struct of_mm_gpio_chip *mm_gc; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); unsigned long flags; u32 intmask; - altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); - mm_gc = &altera_gc->mmchip; - raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); - intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + intmask = readl(altera_gc->regs + ALTERA_GPIO_IRQ_MASK); /* Clear ALTERA_GPIO_IRQ_MASK bit to mask */ intmask &= ~BIT(irqd_to_hwirq(d)); - writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + writel(intmask, altera_gc->regs + ALTERA_GPIO_IRQ_MASK); raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); - gpiochip_disable_irq(&mm_gc->gc, irqd_to_hwirq(d)); + + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } /* @@ -77,9 +83,8 @@ static void altera_gpio_irq_mask(struct irq_data *d) static int altera_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct altera_gpio_chip *altera_gc; - - altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); if (type == IRQ_TYPE_NONE) { irq_set_handler_locked(d, handle_bad_irq); @@ -105,49 +110,39 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d) static int altera_gpio_get(struct gpio_chip *gc, unsigned offset) { - struct of_mm_gpio_chip *mm_gc; - - mm_gc = to_of_mm_gpio_chip(gc); + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); - return !!(readl(mm_gc->regs + ALTERA_GPIO_DATA) & BIT(offset)); + return !!(readl(altera_gc->regs + ALTERA_GPIO_DATA) & BIT(offset)); } static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { - struct of_mm_gpio_chip *mm_gc; - struct altera_gpio_chip *chip; + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); unsigned long flags; unsigned int data_reg; - mm_gc = to_of_mm_gpio_chip(gc); - chip = gpiochip_get_data(gc); - - raw_spin_lock_irqsave(&chip->gpio_lock, flags); - data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); + raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); + data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA); if (value) data_reg |= BIT(offset); else data_reg &= ~BIT(offset); - writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); - raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); + writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA); + raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); } static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset) { - struct of_mm_gpio_chip *mm_gc; - struct altera_gpio_chip *chip; + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); unsigned long flags; unsigned int gpio_ddr; - mm_gc = to_of_mm_gpio_chip(gc); - chip = gpiochip_get_data(gc); - - raw_spin_lock_irqsave(&chip->gpio_lock, flags); + raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); /* Set pin as input, assumes software controlled IP */ - gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); + gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR); gpio_ddr &= ~BIT(offset); - writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); - raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); + writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR); + raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); return 0; } @@ -155,53 +150,46 @@ static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset) static int altera_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int value) { - struct of_mm_gpio_chip *mm_gc; - struct altera_gpio_chip *chip; + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); unsigned long flags; unsigned int data_reg, gpio_ddr; - mm_gc = to_of_mm_gpio_chip(gc); - chip = gpiochip_get_data(gc); - - raw_spin_lock_irqsave(&chip->gpio_lock, flags); + raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); /* Sets the GPIO value */ - data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); + data_reg = readl(altera_gc->regs + ALTERA_GPIO_DATA); if (value) data_reg |= BIT(offset); else data_reg &= ~BIT(offset); - writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); + writel(data_reg, altera_gc->regs + ALTERA_GPIO_DATA); /* Set pin as output, assumes software controlled IP */ - gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); + gpio_ddr = readl(altera_gc->regs + ALTERA_GPIO_DIR); gpio_ddr |= BIT(offset); - writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); - raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); + writel(gpio_ddr, altera_gc->regs + ALTERA_GPIO_DIR); + raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); return 0; } static void altera_gpio_irq_edge_handler(struct irq_desc *desc) { - struct altera_gpio_chip *altera_gc; + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); + struct irq_domain *irqdomain = gc->irq.domain; struct irq_chip *chip; - struct of_mm_gpio_chip *mm_gc; - struct irq_domain *irqdomain; unsigned long status; int i; - altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc)); chip = irq_desc_get_chip(desc); - mm_gc = &altera_gc->mmchip; - irqdomain = altera_gc->mmchip.gc.irq.domain; chained_irq_enter(chip, desc); while ((status = - (readl(mm_gc->regs + ALTERA_GPIO_EDGE_CAP) & - readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK)))) { - writel(status, mm_gc->regs + ALTERA_GPIO_EDGE_CAP); - for_each_set_bit(i, &status, mm_gc->gc.ngpio) + (readl(altera_gc->regs + ALTERA_GPIO_EDGE_CAP) & + readl(altera_gc->regs + ALTERA_GPIO_IRQ_MASK)))) { + writel(status, altera_gc->regs + ALTERA_GPIO_EDGE_CAP); + for_each_set_bit(i, &status, gc->ngpio) generic_handle_domain_irq(irqdomain, i); } @@ -210,24 +198,21 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc) static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc) { - struct altera_gpio_chip *altera_gc; + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct altera_gpio_chip *altera_gc = gpiochip_get_data(gc); + struct irq_domain *irqdomain = gc->irq.domain; struct irq_chip *chip; - struct of_mm_gpio_chip *mm_gc; - struct irq_domain *irqdomain; unsigned long status; int i; - altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc)); chip = irq_desc_get_chip(desc); - mm_gc = &altera_gc->mmchip; - irqdomain = altera_gc->mmchip.gc.irq.domain; chained_irq_enter(chip, desc); - status = readl(mm_gc->regs + ALTERA_GPIO_DATA); - status &= readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); + status = readl(altera_gc->regs + ALTERA_GPIO_DATA); + status &= readl(altera_gc->regs + ALTERA_GPIO_IRQ_MASK); - for_each_set_bit(i, &status, mm_gc->gc.ngpio) + for_each_set_bit(i, &status, gc->ngpio) generic_handle_domain_irq(irqdomain, i); chained_irq_exit(chip, desc); @@ -246,7 +231,7 @@ static const struct irq_chip altera_gpio_irq_chip = { static int altera_gpio_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; int reg, ret; struct altera_gpio_chip *altera_gc; struct gpio_irq_chip *girq; @@ -257,39 +242,47 @@ static int altera_gpio_probe(struct platform_device *pdev) raw_spin_lock_init(&altera_gc->gpio_lock); - if (of_property_read_u32(node, "altr,ngpio", ®)) + if (device_property_read_u32(dev, "altr,ngpio", ®)) /* By default assume maximum ngpio */ - altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO; + altera_gc->gc.ngpio = ALTERA_GPIO_MAX_NGPIO; else - altera_gc->mmchip.gc.ngpio = reg; + altera_gc->gc.ngpio = reg; - if (altera_gc->mmchip.gc.ngpio > ALTERA_GPIO_MAX_NGPIO) { + if (altera_gc->gc.ngpio > ALTERA_GPIO_MAX_NGPIO) { dev_warn(&pdev->dev, "ngpio is greater than %d, defaulting to %d\n", ALTERA_GPIO_MAX_NGPIO, ALTERA_GPIO_MAX_NGPIO); - altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO; + altera_gc->gc.ngpio = ALTERA_GPIO_MAX_NGPIO; } - altera_gc->mmchip.gc.direction_input = altera_gpio_direction_input; - altera_gc->mmchip.gc.direction_output = altera_gpio_direction_output; - altera_gc->mmchip.gc.get = altera_gpio_get; - altera_gc->mmchip.gc.set = altera_gpio_set; - altera_gc->mmchip.gc.owner = THIS_MODULE; - altera_gc->mmchip.gc.parent = &pdev->dev; + altera_gc->gc.direction_input = altera_gpio_direction_input; + altera_gc->gc.direction_output = altera_gpio_direction_output; + altera_gc->gc.get = altera_gpio_get; + altera_gc->gc.set = altera_gpio_set; + altera_gc->gc.owner = THIS_MODULE; + altera_gc->gc.parent = &pdev->dev; + altera_gc->gc.base = -1; - altera_gc->mapped_irq = platform_get_irq_optional(pdev, 0); + altera_gc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev)); + if (!altera_gc->gc.label) + return -ENOMEM; + altera_gc->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(altera_gc->regs)) + return dev_err_probe(dev, PTR_ERR(altera_gc->regs), "failed to ioremap memory resource\n"); + + altera_gc->mapped_irq = platform_get_irq_optional(pdev, 0); if (altera_gc->mapped_irq < 0) goto skip_irq; - if (of_property_read_u32(node, "altr,interrupt-type", ®)) { + if (device_property_read_u32(dev, "altr,interrupt-type", ®)) { dev_err(&pdev->dev, "altr,interrupt-type value not set in device tree\n"); return -EINVAL; } altera_gc->interrupt_trigger = reg; - girq = &altera_gc->mmchip.gc.irq; + girq = &altera_gc->gc.irq; gpio_irq_chip_set_chip(girq, &altera_gpio_irq_chip); if (altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH) @@ -306,24 +299,15 @@ static int altera_gpio_probe(struct platform_device *pdev) girq->parents[0] = altera_gc->mapped_irq; skip_irq: - ret = of_mm_gpiochip_add_data(node, &altera_gc->mmchip, altera_gc); + ret = devm_gpiochip_add_data(dev, &altera_gc->gc, altera_gc); if (ret) { dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); return ret; } - platform_set_drvdata(pdev, altera_gc); - return 0; } -static void altera_gpio_remove(struct platform_device *pdev) -{ - struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev); - - of_mm_gpiochip_remove(&altera_gc->mmchip); -} - static const struct of_device_id altera_gpio_of_match[] = { { .compatible = "altr,pio-1.0", }, {}, @@ -336,7 +320,6 @@ static struct platform_driver altera_gpio_driver = { .of_match_table = altera_gpio_of_match, }, .probe = altera_gpio_probe, - .remove_new = altera_gpio_remove, }; static int __init altera_gpio_init(void) diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c index 0a2ea9db468247..b70036587d9c3f 100644 --- a/drivers/gpio/gpio-amdpt.c +++ b/drivers/gpio/gpio-amdpt.c @@ -106,7 +106,7 @@ static int pt_gpio_probe(struct platform_device *pdev) pt_gpio->gc.free = pt_gpio_free; pt_gpio->gc.ngpio = (uintptr_t)device_get_match_data(dev); - ret = gpiochip_add_data(&pt_gpio->gc, pt_gpio); + ret = devm_gpiochip_add_data(dev, &pt_gpio->gc, pt_gpio); if (ret) { dev_err(dev, "Failed to register GPIO lib\n"); return ret; @@ -122,13 +122,6 @@ static int pt_gpio_probe(struct platform_device *pdev) return ret; } -static void pt_gpio_remove(struct platform_device *pdev) -{ - struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev); - - gpiochip_remove(&pt_gpio->gc); -} - static const struct acpi_device_id pt_gpio_acpi_match[] = { { "AMDF030", PT_TOTAL_GPIO }, { "AMDIF030", PT_TOTAL_GPIO }, @@ -143,7 +136,6 @@ static struct platform_driver pt_gpio_driver = { .acpi_match_table = ACPI_PTR(pt_gpio_acpi_match), }, .probe = pt_gpio_probe, - .remove_new = pt_gpio_remove, }; module_platform_driver(pt_gpio_driver); diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c index 72755fee647847..34eb26298e3241 100644 --- a/drivers/gpio/gpio-aspeed-sgpio.c +++ b/drivers/gpio/gpio-aspeed-sgpio.c @@ -420,7 +420,7 @@ static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p) int offset; irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); - seq_printf(p, dev_name(gpio->dev)); + seq_puts(p, dev_name(gpio->dev)); } static const struct irq_chip aspeed_sgpio_irq_chip = { diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index ea40ad43a79baa..40c1bd80f8b043 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -30,6 +30,27 @@ #include #include "gpiolib.h" +/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + +#define GPIO_G7_IRQ_STS_BASE 0x100 +#define GPIO_G7_IRQ_STS_OFFSET(x) (GPIO_G7_IRQ_STS_BASE + (x) * 0x4) +#define GPIO_G7_CTRL_REG_BASE 0x180 +#define GPIO_G7_CTRL_REG_OFFSET(x) (GPIO_G7_CTRL_REG_BASE + (x) * 0x4) +#define GPIO_G7_CTRL_OUT_DATA BIT(0) +#define GPIO_G7_CTRL_DIR BIT(1) +#define GPIO_G7_CTRL_IRQ_EN BIT(2) +#define GPIO_G7_CTRL_IRQ_TYPE0 BIT(3) +#define GPIO_G7_CTRL_IRQ_TYPE1 BIT(4) +#define GPIO_G7_CTRL_IRQ_TYPE2 BIT(5) +#define GPIO_G7_CTRL_RST_TOLERANCE BIT(6) +#define GPIO_G7_CTRL_DEBOUNCE_SEL1 BIT(7) +#define GPIO_G7_CTRL_DEBOUNCE_SEL2 BIT(8) +#define GPIO_G7_CTRL_INPUT_MASK BIT(9) +#define GPIO_G7_CTRL_IRQ_STS BIT(12) +#define GPIO_G7_CTRL_IN_DATA BIT(13) + struct aspeed_bank_props { unsigned int bank; u32 input; @@ -39,6 +60,10 @@ struct aspeed_bank_props { struct aspeed_gpio_config { unsigned int nr_gpios; const struct aspeed_bank_props *props; + const struct aspeed_gpio_llops *llops; + const int *debounce_timers_array; + int debounce_timers_num; + bool require_dcache; }; /* @@ -77,7 +102,6 @@ struct aspeed_gpio_bank { uint16_t debounce_regs; uint16_t tolerance_regs; uint16_t cmdsrc_regs; - const char names[4][3]; }; /* @@ -92,6 +116,22 @@ struct aspeed_gpio_bank { */ static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 }; +static const int g7_debounce_timers[4] = { 0x00, 0x00, 0x04, 0x08 }; + +/* + * The debounce timers array is used to configure the debounce timer settings.Here’s how it works: + * Array Value: Indicates the offset for configuring the debounce timer. + * Array Index: Corresponds to the debounce setting register. + * The debounce timers array follows this pattern for configuring the debounce setting registers: + * Array Index 0: No debounce timer is set; + * Array Value is irrelevant (don’t care). + * Array Index 1: Debounce setting #2 is set to 1, and debounce setting #1 is set to 0. + * Array Value: offset for configuring debounce timer 0 (g4: 0x50, g7: 0x00) + * Array Index 2: Debounce setting #2 is set to 0, and debounce setting #1 is set to 1. + * Array Value: offset for configuring debounce timer 1 (g4: 0x54, g7: 0x04) + * Array Index 3: Debounce setting #2 is set to 1, and debounce setting #1 is set to 1. + * Array Value: offset for configuring debounce timer 2 (g4: 0x58, g7: 0x8) + */ static const struct aspeed_gpio_copro_ops *copro_ops; static void *copro_data; @@ -104,7 +144,6 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .debounce_regs = 0x0040, .tolerance_regs = 0x001c, .cmdsrc_regs = 0x0060, - .names = { "A", "B", "C", "D" }, }, { .val_regs = 0x0020, @@ -113,7 +152,6 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .debounce_regs = 0x0048, .tolerance_regs = 0x003c, .cmdsrc_regs = 0x0068, - .names = { "E", "F", "G", "H" }, }, { .val_regs = 0x0070, @@ -122,7 +160,6 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .debounce_regs = 0x00b0, .tolerance_regs = 0x00ac, .cmdsrc_regs = 0x0090, - .names = { "I", "J", "K", "L" }, }, { .val_regs = 0x0078, @@ -131,7 +168,6 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .debounce_regs = 0x0100, .tolerance_regs = 0x00fc, .cmdsrc_regs = 0x00e0, - .names = { "M", "N", "O", "P" }, }, { .val_regs = 0x0080, @@ -140,7 +176,6 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .debounce_regs = 0x0130, .tolerance_regs = 0x012c, .cmdsrc_regs = 0x0110, - .names = { "Q", "R", "S", "T" }, }, { .val_regs = 0x0088, @@ -149,7 +184,6 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .debounce_regs = 0x0160, .tolerance_regs = 0x015c, .cmdsrc_regs = 0x0140, - .names = { "U", "V", "W", "X" }, }, { .val_regs = 0x01E0, @@ -158,7 +192,6 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .debounce_regs = 0x0190, .tolerance_regs = 0x018c, .cmdsrc_regs = 0x0170, - .names = { "Y", "Z", "AA", "AB" }, }, { .val_regs = 0x01e8, @@ -167,7 +200,6 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { .debounce_regs = 0x01c0, .tolerance_regs = 0x01bc, .cmdsrc_regs = 0x01a0, - .names = { "AC", "", "", "" }, }, }; @@ -187,6 +219,19 @@ enum aspeed_gpio_reg { reg_cmdsrc1, }; +struct aspeed_gpio_llops { + void (*reg_bit_set)(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg, bool val); + bool (*reg_bit_get)(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg); + int (*reg_bank_get)(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg); + void (*privilege_ctrl)(struct aspeed_gpio *gpio, unsigned int offset, int owner); + void (*privilege_init)(struct aspeed_gpio *gpio); + bool (*copro_request)(struct aspeed_gpio *gpio, unsigned int offset); + void (*copro_release)(struct aspeed_gpio *gpio, unsigned int offset); +}; + #define GPIO_VAL_VALUE 0x00 #define GPIO_VAL_DIR 0x04 @@ -207,9 +252,9 @@ enum aspeed_gpio_reg { #define GPIO_CMDSRC_RESERVED 3 /* This will be resolved at compile time */ -static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, - const struct aspeed_gpio_bank *bank, - const enum aspeed_gpio_reg reg) +static void __iomem *aspeed_gpio_g4_bank_reg(struct aspeed_gpio *gpio, + const struct aspeed_gpio_bank *bank, + const enum aspeed_gpio_reg reg) { switch (reg) { case reg_val: @@ -242,14 +287,43 @@ static inline void __iomem *bank_reg(struct aspeed_gpio *gpio, BUG(); } +static u32 aspeed_gpio_g7_reg_mask(const enum aspeed_gpio_reg reg) +{ + switch (reg) { + case reg_val: + return GPIO_G7_CTRL_OUT_DATA; + case reg_dir: + return GPIO_G7_CTRL_DIR; + case reg_irq_enable: + return GPIO_G7_CTRL_IRQ_EN; + case reg_irq_type0: + return GPIO_G7_CTRL_IRQ_TYPE0; + case reg_irq_type1: + return GPIO_G7_CTRL_IRQ_TYPE1; + case reg_irq_type2: + return GPIO_G7_CTRL_IRQ_TYPE2; + case reg_tolerance: + return GPIO_G7_CTRL_RST_TOLERANCE; + case reg_debounce_sel1: + return GPIO_G7_CTRL_DEBOUNCE_SEL1; + case reg_debounce_sel2: + return GPIO_G7_CTRL_DEBOUNCE_SEL2; + case reg_rdata: + return GPIO_G7_CTRL_OUT_DATA; + case reg_irq_status: + return GPIO_G7_CTRL_IRQ_STS; + case reg_cmdsrc0: + case reg_cmdsrc1: + default: + WARN_ON_ONCE(1); + return 0; + } +} + #define GPIO_BANK(x) ((x) >> 5) #define GPIO_OFFSET(x) ((x) & 0x1f) #define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) -#define _GPIO_SET_DEBOUNCE(t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o)) -#define GPIO_SET_DEBOUNCE1(t, o) _GPIO_SET_DEBOUNCE(t, o, 1) -#define GPIO_SET_DEBOUNCE2(t, o) _GPIO_SET_DEBOUNCE(t, o, 0) - static const struct aspeed_gpio_bank *to_bank(unsigned int offset) { unsigned int bank = GPIO_BANK(offset); @@ -280,11 +354,11 @@ static inline const struct aspeed_bank_props *find_bank_props( static inline bool have_gpio(struct aspeed_gpio *gpio, unsigned int offset) { const struct aspeed_bank_props *props = find_bank_props(gpio, offset); - const struct aspeed_gpio_bank *bank = to_bank(offset); - unsigned int group = GPIO_OFFSET(offset) / 8; - return bank->names[group][0] != '\0' && - (!props || ((props->input | props->output) & GPIO_BIT(offset))); + if (offset >= gpio->chip.ngpio) + return false; + + return (!props || ((props->input | props->output) & GPIO_BIT(offset))); } static inline bool have_input(struct aspeed_gpio *gpio, unsigned int offset) @@ -304,110 +378,49 @@ static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset) return !props || (props->output & GPIO_BIT(offset)); } -static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, - const struct aspeed_gpio_bank *bank, - int bindex, int cmdsrc) +static void aspeed_gpio_change_cmd_source(struct aspeed_gpio *gpio, unsigned int offset, int cmdsrc) { - void __iomem *c0 = bank_reg(gpio, bank, reg_cmdsrc0); - void __iomem *c1 = bank_reg(gpio, bank, reg_cmdsrc1); - u32 bit, reg; - - /* - * Each register controls 4 banks, so take the bottom 2 - * bits of the bank index, and use them to select the - * right control bit (0, 8, 16 or 24). - */ - bit = BIT((bindex & 3) << 3); - - /* Source 1 first to avoid illegal 11 combination */ - reg = ioread32(c1); - if (cmdsrc & 2) - reg |= bit; - else - reg &= ~bit; - iowrite32(reg, c1); - - /* Then Source 0 */ - reg = ioread32(c0); - if (cmdsrc & 1) - reg |= bit; - else - reg &= ~bit; - iowrite32(reg, c0); + if (gpio->config->llops->privilege_ctrl) + gpio->config->llops->privilege_ctrl(gpio, offset, cmdsrc); } static bool aspeed_gpio_copro_request(struct aspeed_gpio *gpio, unsigned int offset) { - const struct aspeed_gpio_bank *bank = to_bank(offset); - - if (!copro_ops || !gpio->cf_copro_bankmap) - return false; - if (!gpio->cf_copro_bankmap[offset >> 3]) - return false; - if (!copro_ops->request_access) - return false; - - /* Pause the coprocessor */ - copro_ops->request_access(copro_data); - - /* Change command source back to ARM */ - aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, GPIO_CMDSRC_ARM); - - /* Update cache */ - gpio->dcache[GPIO_BANK(offset)] = ioread32(bank_reg(gpio, bank, reg_rdata)); + if (gpio->config->llops->copro_request) + return gpio->config->llops->copro_request(gpio, offset); - return true; + return false; } static void aspeed_gpio_copro_release(struct aspeed_gpio *gpio, unsigned int offset) { - const struct aspeed_gpio_bank *bank = to_bank(offset); - - if (!copro_ops || !gpio->cf_copro_bankmap) - return; - if (!gpio->cf_copro_bankmap[offset >> 3]) - return; - if (!copro_ops->release_access) - return; - - /* Change command source back to ColdFire */ - aspeed_gpio_change_cmd_source(gpio, bank, offset >> 3, - GPIO_CMDSRC_COLDFIRE); + if (gpio->config->llops->copro_release) + gpio->config->llops->copro_release(gpio, offset); +} - /* Restart the coprocessor */ - copro_ops->release_access(copro_data); +static bool aspeed_gpio_support_copro(struct aspeed_gpio *gpio) +{ + return gpio->config->llops->copro_request && gpio->config->llops->copro_release && + gpio->config->llops->privilege_ctrl && gpio->config->llops->privilege_init; } static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - const struct aspeed_gpio_bank *bank = to_bank(offset); - return !!(ioread32(bank_reg(gpio, bank, reg_val)) & GPIO_BIT(offset)); + return gpio->config->llops->reg_bit_get(gpio, offset, reg_val); } static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - const struct aspeed_gpio_bank *bank = to_bank(offset); - void __iomem *addr; - u32 reg; - - addr = bank_reg(gpio, bank, reg_val); - reg = gpio->dcache[GPIO_BANK(offset)]; - if (val) - reg |= GPIO_BIT(offset); - else - reg &= ~GPIO_BIT(offset); - gpio->dcache[GPIO_BANK(offset)] = reg; - - iowrite32(reg, addr); + gpio->config->llops->reg_bit_set(gpio, offset, reg_val, val); /* Flush write */ - ioread32(addr); + gpio->config->llops->reg_bit_get(gpio, offset, reg_val); } static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, @@ -415,7 +428,7 @@ static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, { struct aspeed_gpio *gpio = gpiochip_get_data(gc); unsigned long flags; - bool copro; + bool copro = false; raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); @@ -430,22 +443,16 @@ static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset, static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - const struct aspeed_gpio_bank *bank = to_bank(offset); - void __iomem *addr = bank_reg(gpio, bank, reg_dir); unsigned long flags; - bool copro; - u32 reg; + bool copro = false; if (!have_input(gpio, offset)) return -ENOTSUPP; raw_spin_lock_irqsave(&gpio->lock, flags); - reg = ioread32(addr); - reg &= ~GPIO_BIT(offset); - copro = aspeed_gpio_copro_request(gpio, offset); - iowrite32(reg, addr); + gpio->config->llops->reg_bit_set(gpio, offset, reg_dir, 0); if (copro) aspeed_gpio_copro_release(gpio, offset); @@ -458,23 +465,17 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - const struct aspeed_gpio_bank *bank = to_bank(offset); - void __iomem *addr = bank_reg(gpio, bank, reg_dir); unsigned long flags; - bool copro; - u32 reg; + bool copro = false; if (!have_output(gpio, offset)) return -ENOTSUPP; raw_spin_lock_irqsave(&gpio->lock, flags); - reg = ioread32(addr); - reg |= GPIO_BIT(offset); - copro = aspeed_gpio_copro_request(gpio, offset); __aspeed_gpio_set(gc, offset, val); - iowrite32(reg, addr); + gpio->config->llops->reg_bit_set(gpio, offset, reg_dir, 1); if (copro) aspeed_gpio_copro_release(gpio, offset); @@ -486,7 +487,6 @@ static int aspeed_gpio_dir_out(struct gpio_chip *gc, static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) { struct aspeed_gpio *gpio = gpiochip_get_data(gc); - const struct aspeed_gpio_bank *bank = to_bank(offset); unsigned long flags; u32 val; @@ -498,7 +498,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) raw_spin_lock_irqsave(&gpio->lock, flags); - val = ioread32(bank_reg(gpio, bank, reg_dir)) & GPIO_BIT(offset); + val = gpio->config->llops->reg_bit_get(gpio, offset, reg_dir); raw_spin_unlock_irqrestore(&gpio->lock, flags); @@ -507,8 +507,7 @@ static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, struct aspeed_gpio **gpio, - const struct aspeed_gpio_bank **bank, - u32 *bit, int *offset) + int *offset) { struct aspeed_gpio *internal; @@ -521,32 +520,25 @@ static inline int irqd_to_aspeed_gpio_data(struct irq_data *d, return -ENOTSUPP; *gpio = internal; - *bank = to_bank(*offset); - *bit = GPIO_BIT(*offset); return 0; } static void aspeed_gpio_irq_ack(struct irq_data *d) { - const struct aspeed_gpio_bank *bank; struct aspeed_gpio *gpio; unsigned long flags; - void __iomem *status_addr; int rc, offset; - bool copro; - u32 bit; + bool copro = false; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); if (rc) return; - status_addr = bank_reg(gpio, bank, reg_irq_status); - raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); - iowrite32(bit, status_addr); + gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_status, 1); if (copro) aspeed_gpio_copro_release(gpio, offset); @@ -555,20 +547,15 @@ static void aspeed_gpio_irq_ack(struct irq_data *d) static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) { - const struct aspeed_gpio_bank *bank; struct aspeed_gpio *gpio; unsigned long flags; - u32 reg, bit; - void __iomem *addr; int rc, offset; - bool copro; + bool copro = false; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); if (rc) return; - addr = bank_reg(gpio, bank, reg_irq_enable); - /* Unmasking the IRQ */ if (set) gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d)); @@ -576,12 +563,7 @@ static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set) raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); - reg = ioread32(addr); - if (set) - reg |= bit; - else - reg &= ~bit; - iowrite32(reg, addr); + gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_enable, set); if (copro) aspeed_gpio_copro_release(gpio, offset); @@ -607,34 +589,31 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) u32 type0 = 0; u32 type1 = 0; u32 type2 = 0; - u32 bit, reg; - const struct aspeed_gpio_bank *bank; irq_flow_handler_t handler; struct aspeed_gpio *gpio; unsigned long flags; - void __iomem *addr; int rc, offset; - bool copro; + bool copro = false; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); if (rc) return -EINVAL; switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_BOTH: - type2 |= bit; + type2 = 1; fallthrough; case IRQ_TYPE_EDGE_RISING: - type0 |= bit; + type0 = 1; fallthrough; case IRQ_TYPE_EDGE_FALLING: handler = handle_edge_irq; break; case IRQ_TYPE_LEVEL_HIGH: - type0 |= bit; + type0 = 1; fallthrough; case IRQ_TYPE_LEVEL_LOW: - type1 |= bit; + type1 = 1; handler = handle_level_irq; break; default: @@ -644,20 +623,9 @@ static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type) raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); - addr = bank_reg(gpio, bank, reg_irq_type0); - reg = ioread32(addr); - reg = (reg & ~bit) | type0; - iowrite32(reg, addr); - - addr = bank_reg(gpio, bank, reg_irq_type1); - reg = ioread32(addr); - reg = (reg & ~bit) | type1; - iowrite32(reg, addr); - - addr = bank_reg(gpio, bank, reg_irq_type2); - reg = ioread32(addr); - reg = (reg & ~bit) | type2; - iowrite32(reg, addr); + gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0); + gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1); + gpio->config->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2); if (copro) aspeed_gpio_copro_release(gpio, offset); @@ -672,7 +640,6 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct irq_chip *ic = irq_desc_get_chip(desc); - struct aspeed_gpio *data = gpiochip_get_data(gc); unsigned int i, p, banks; unsigned long reg; struct aspeed_gpio *gpio = gpiochip_get_data(gc); @@ -681,9 +648,7 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc) banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); for (i = 0; i < banks; i++) { - const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - - reg = ioread32(bank_reg(data, bank, reg_irq_status)); + reg = gpio->config->llops->reg_bank_get(gpio, i * 32, reg_irq_status); for_each_set_bit(p, ®, 32) generic_handle_domain_irq(gc->irq.domain, i * 32 + p); @@ -722,23 +687,12 @@ static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip, { struct aspeed_gpio *gpio = gpiochip_get_data(chip); unsigned long flags; - void __iomem *treg; - bool copro; - u32 val; - - treg = bank_reg(gpio, to_bank(offset), reg_tolerance); + bool copro = false; raw_spin_lock_irqsave(&gpio->lock, flags); copro = aspeed_gpio_copro_request(gpio, offset); - val = readl(treg); - - if (enable) - val |= GPIO_BIT(offset); - else - val &= ~GPIO_BIT(offset); - - writel(val, treg); + gpio->config->llops->reg_bit_set(gpio, offset, reg_tolerance, enable); if (copro) aspeed_gpio_copro_release(gpio, offset); @@ -832,21 +786,11 @@ static inline bool timer_allocation_registered(struct aspeed_gpio *gpio, static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset, unsigned int timer) { - const struct aspeed_gpio_bank *bank = to_bank(offset); - const u32 mask = GPIO_BIT(offset); - void __iomem *addr; - u32 val; - /* Note: Debounce timer isn't under control of the command * source registers, so no need to sync with the coprocessor */ - addr = bank_reg(gpio, bank, reg_debounce_sel1); - val = ioread32(addr); - iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr); - - addr = bank_reg(gpio, bank, reg_debounce_sel2); - val = ioread32(addr); - iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE2(timer, offset), addr); + gpio->config->llops->reg_bit_set(gpio, offset, reg_debounce_sel1, !!(timer & BIT(1))); + gpio->config->llops->reg_bit_set(gpio, offset, reg_debounce_sel2, !!(timer & BIT(0))); } static int enable_debounce(struct gpio_chip *chip, unsigned int offset, @@ -877,15 +821,15 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, } /* Try to find a timer already configured for the debounce period */ - for (i = 1; i < ARRAY_SIZE(debounce_timers); i++) { + for (i = 1; i < gpio->config->debounce_timers_num; i++) { u32 cycles; - cycles = ioread32(gpio->base + debounce_timers[i]); + cycles = ioread32(gpio->base + gpio->config->debounce_timers_array[i]); if (requested_cycles == cycles) break; } - if (i == ARRAY_SIZE(debounce_timers)) { + if (i == gpio->config->debounce_timers_num) { int j; /* @@ -899,8 +843,8 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, if (j == ARRAY_SIZE(gpio->timer_users)) { dev_warn(chip->parent, - "Debounce timers exhausted, cannot debounce for period %luus\n", - usecs); + "Debounce timers exhausted, cannot debounce for period %luus\n", + usecs); rc = -EPERM; @@ -916,7 +860,7 @@ static int enable_debounce(struct gpio_chip *chip, unsigned int offset, i = j; - iowrite32(requested_cycles, gpio->base + debounce_timers[i]); + iowrite32(requested_cycles, gpio->base + gpio->config->debounce_timers_array[i]); } if (WARN(i == 0, "Cannot register index of disabled timer\n")) { @@ -1019,6 +963,9 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, const struct aspeed_gpio_bank *bank = to_bank(offset); unsigned long flags; + if (!aspeed_gpio_support_copro(gpio)) + return -EOPNOTSUPP; + if (!gpio->cf_copro_bankmap) gpio->cf_copro_bankmap = kzalloc(gpio->chip.ngpio >> 3, GFP_KERNEL); if (!gpio->cf_copro_bankmap) @@ -1038,7 +985,7 @@ int aspeed_gpio_copro_grab_gpio(struct gpio_desc *desc, /* Switch command source */ if (gpio->cf_copro_bankmap[bindex] == 1) - aspeed_gpio_change_cmd_source(gpio, bank, bindex, + aspeed_gpio_change_cmd_source(gpio, offset, GPIO_CMDSRC_COLDFIRE); if (vreg_offset) @@ -1062,9 +1009,11 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) struct gpio_chip *chip = gpiod_to_chip(desc); struct aspeed_gpio *gpio = gpiochip_get_data(chip); int rc = 0, bindex, offset = gpio_chip_hwgpio(desc); - const struct aspeed_gpio_bank *bank = to_bank(offset); unsigned long flags; + if (!aspeed_gpio_support_copro(gpio)) + return -EOPNOTSUPP; + if (!gpio->cf_copro_bankmap) return -ENXIO; @@ -1083,7 +1032,7 @@ int aspeed_gpio_copro_release_gpio(struct gpio_desc *desc) /* Switch command source */ if (gpio->cf_copro_bankmap[bindex] == 0) - aspeed_gpio_change_cmd_source(gpio, bank, bindex, + aspeed_gpio_change_cmd_source(gpio, offset, GPIO_CMDSRC_ARM); bail: raw_spin_unlock_irqrestore(&gpio->lock, flags); @@ -1093,16 +1042,14 @@ EXPORT_SYMBOL_GPL(aspeed_gpio_copro_release_gpio); static void aspeed_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) { - const struct aspeed_gpio_bank *bank; struct aspeed_gpio *gpio; - u32 bit; int rc, offset; - rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit, &offset); + rc = irqd_to_aspeed_gpio_data(d, &gpio, &offset); if (rc) return; - seq_printf(p, dev_name(gpio->dev)); + seq_puts(p, dev_name(gpio->dev)); } static const struct irq_chip aspeed_gpio_irq_chip = { @@ -1115,6 +1062,173 @@ static const struct irq_chip aspeed_gpio_irq_chip = { GPIOCHIP_IRQ_RESOURCE_HELPERS, }; +static void aspeed_g4_reg_bit_set(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg, bool val) +{ + const struct aspeed_gpio_bank *bank = to_bank(offset); + void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); + u32 temp; + + if (reg == reg_val) + temp = gpio->dcache[GPIO_BANK(offset)]; + else + temp = ioread32(addr); + + if (val) + temp |= GPIO_BIT(offset); + else + temp &= ~GPIO_BIT(offset); + + if (reg == reg_val) + gpio->dcache[GPIO_BANK(offset)] = temp; + iowrite32(temp, addr); +} + +static bool aspeed_g4_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg) +{ + const struct aspeed_gpio_bank *bank = to_bank(offset); + void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); + + return !!(ioread32(addr) & GPIO_BIT(offset)); +} + +static int aspeed_g4_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg) +{ + const struct aspeed_gpio_bank *bank = to_bank(offset); + void __iomem *addr = aspeed_gpio_g4_bank_reg(gpio, bank, reg); + + if (reg == reg_rdata || reg == reg_irq_status) + return ioread32(addr); + else + return -EOPNOTSUPP; +} + +static void aspeed_g4_privilege_ctrl(struct aspeed_gpio *gpio, unsigned int offset, int cmdsrc) +{ + /* + * The command source register is only valid in bits 0, 8, 16, and 24, so we use + * (offset & ~(0x7)) to ensure that reg_bits_set always targets a valid bit. + */ + /* Source 1 first to avoid illegal 11 combination */ + aspeed_g4_reg_bit_set(gpio, offset & ~(0x7), reg_cmdsrc1, !!(cmdsrc & BIT(1))); + /* Then Source 0 */ + aspeed_g4_reg_bit_set(gpio, offset & ~(0x7), reg_cmdsrc0, !!(cmdsrc & BIT(0))); +} + +static void aspeed_g4_privilege_init(struct aspeed_gpio *gpio) +{ + u32 i; + + /* Switch all command sources to the ARM by default */ + for (i = 0; i < DIV_ROUND_UP(gpio->chip.ngpio, 32); i++) { + aspeed_g4_privilege_ctrl(gpio, (i << 5) + 0, GPIO_CMDSRC_ARM); + aspeed_g4_privilege_ctrl(gpio, (i << 5) + 8, GPIO_CMDSRC_ARM); + aspeed_g4_privilege_ctrl(gpio, (i << 5) + 16, GPIO_CMDSRC_ARM); + aspeed_g4_privilege_ctrl(gpio, (i << 5) + 24, GPIO_CMDSRC_ARM); + } +} + +static bool aspeed_g4_copro_request(struct aspeed_gpio *gpio, unsigned int offset) +{ + if (!copro_ops || !gpio->cf_copro_bankmap) + return false; + if (!gpio->cf_copro_bankmap[offset >> 3]) + return false; + if (!copro_ops->request_access) + return false; + + /* Pause the coprocessor */ + copro_ops->request_access(copro_data); + + /* Change command source back to ARM */ + aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_ARM); + + /* Update cache */ + gpio->dcache[GPIO_BANK(offset)] = aspeed_g4_reg_bank_get(gpio, offset, reg_rdata); + + return true; +} + +static void aspeed_g4_copro_release(struct aspeed_gpio *gpio, unsigned int offset) +{ + if (!copro_ops || !gpio->cf_copro_bankmap) + return; + if (!gpio->cf_copro_bankmap[offset >> 3]) + return; + if (!copro_ops->release_access) + return; + + /* Change command source back to ColdFire */ + aspeed_g4_privilege_ctrl(gpio, offset, GPIO_CMDSRC_COLDFIRE); + + /* Restart the coprocessor */ + copro_ops->release_access(copro_data); +} + +static const struct aspeed_gpio_llops aspeed_g4_llops = { + .reg_bit_set = aspeed_g4_reg_bit_set, + .reg_bit_get = aspeed_g4_reg_bit_get, + .reg_bank_get = aspeed_g4_reg_bank_get, + .privilege_ctrl = aspeed_g4_privilege_ctrl, + .privilege_init = aspeed_g4_privilege_init, + .copro_request = aspeed_g4_copro_request, + .copro_release = aspeed_g4_copro_release, +}; + +static void aspeed_g7_reg_bit_set(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg, bool val) +{ + u32 mask = aspeed_gpio_g7_reg_mask(reg); + void __iomem *addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); + u32 write_val; + + if (mask) { + write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val); + iowrite32(write_val, addr); + } +} + +static bool aspeed_g7_reg_bit_get(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg) +{ + u32 mask = aspeed_gpio_g7_reg_mask(reg); + void __iomem *addr; + + addr = gpio->base + GPIO_G7_CTRL_REG_OFFSET(offset); + if (reg == reg_val) + mask = GPIO_G7_CTRL_IN_DATA; + + if (mask) + return field_get(mask, ioread32(addr)); + else + return 0; +} + +static int aspeed_g7_reg_bank_get(struct aspeed_gpio *gpio, unsigned int offset, + const enum aspeed_gpio_reg reg) +{ + void __iomem *addr; + + if (reg == reg_irq_status) { + addr = gpio->base + GPIO_G7_IRQ_STS_OFFSET(offset >> 5); + return ioread32(addr); + } else { + return -EOPNOTSUPP; + } +} + +static const struct aspeed_gpio_llops aspeed_g7_llops = { + .reg_bit_set = aspeed_g7_reg_bit_set, + .reg_bit_get = aspeed_g7_reg_bit_get, + .reg_bank_get = aspeed_g7_reg_bank_get, + .privilege_ctrl = NULL, + .privilege_init = NULL, + .copro_request = NULL, + .copro_release = NULL, +}; + /* * Any banks not specified in a struct aspeed_bank_props array are assumed to * have the properties: @@ -1131,7 +1245,14 @@ static const struct aspeed_bank_props ast2400_bank_props[] = { static const struct aspeed_gpio_config ast2400_config = /* 220 for simplicity, really 216 with two 4-GPIO holes, four at end */ - { .nr_gpios = 220, .props = ast2400_bank_props, }; + { + .nr_gpios = 220, + .props = ast2400_bank_props, + .llops = &aspeed_g4_llops, + .debounce_timers_array = debounce_timers, + .debounce_timers_num = ARRAY_SIZE(debounce_timers), + .require_dcache = true, + }; static const struct aspeed_bank_props ast2500_bank_props[] = { /* input output */ @@ -1143,7 +1264,14 @@ static const struct aspeed_bank_props ast2500_bank_props[] = { static const struct aspeed_gpio_config ast2500_config = /* 232 for simplicity, actual number is 228 (4-GPIO hole in GPIOAB) */ - { .nr_gpios = 232, .props = ast2500_bank_props, }; + { + .nr_gpios = 232, + .props = ast2500_bank_props, + .llops = &aspeed_g4_llops, + .debounce_timers_array = debounce_timers, + .debounce_timers_num = ARRAY_SIZE(debounce_timers), + .require_dcache = true, + }; static const struct aspeed_bank_props ast2600_bank_props[] = { /* input output */ @@ -1159,17 +1287,48 @@ static const struct aspeed_gpio_config ast2600_config = * We expect ngpio being set in the device tree and this is a fallback * option. */ - { .nr_gpios = 208, .props = ast2600_bank_props, }; + { + .nr_gpios = 208, + .props = ast2600_bank_props, + .llops = &aspeed_g4_llops, + .debounce_timers_array = debounce_timers, + .debounce_timers_num = ARRAY_SIZE(debounce_timers), + .require_dcache = true, + }; + +static const struct aspeed_bank_props ast2700_bank_props[] = { + /* input output */ + { 1, 0x0fffffff, 0x0fffffff }, /* E/F/G/H, 4-GPIO hole */ + { 6, 0x00ffffff, 0x00ff0000 }, /* Y/Z/AA */ + {}, +}; + +static const struct aspeed_gpio_config ast2700_config = + /* + * ast2700 has two controllers one with 212 GPIOs and one with 16 GPIOs. + * 216 for simplicity, actual number is 212 (4-GPIO hole in GPIOH) + * We expect ngpio being set in the device tree and this is a fallback + * option. + */ + { + .nr_gpios = 216, + .props = ast2700_bank_props, + .llops = &aspeed_g7_llops, + .debounce_timers_array = g7_debounce_timers, + .debounce_timers_num = ARRAY_SIZE(g7_debounce_timers), + .require_dcache = false, + }; static const struct of_device_id aspeed_gpio_of_table[] = { { .compatible = "aspeed,ast2400-gpio", .data = &ast2400_config, }, { .compatible = "aspeed,ast2500-gpio", .data = &ast2500_config, }, { .compatible = "aspeed,ast2600-gpio", .data = &ast2600_config, }, + { .compatible = "aspeed,ast2700-gpio", .data = &ast2700_config, }, {} }; MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table); -static int __init aspeed_gpio_probe(struct platform_device *pdev) +static int aspeed_gpio_probe(struct platform_device *pdev) { const struct of_device_id *gpio_id; struct gpio_irq_chip *girq; @@ -1202,6 +1361,10 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->config = gpio_id->data; + if (!gpio->config->llops->reg_bit_set || !gpio->config->llops->reg_bit_get || + !gpio->config->llops->reg_bank_get) + return -EINVAL; + gpio->chip.parent = &pdev->dev; err = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpio); gpio->chip.ngpio = (u16) ngpio; @@ -1218,27 +1381,23 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->chip.label = dev_name(&pdev->dev); gpio->chip.base = -1; - /* Allocate a cache of the output registers */ - banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); - gpio->dcache = devm_kcalloc(&pdev->dev, - banks, sizeof(u32), GFP_KERNEL); - if (!gpio->dcache) - return -ENOMEM; - - /* - * Populate it with initial values read from the HW and switch - * all command sources to the ARM by default - */ - for (i = 0; i < banks; i++) { - const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i]; - void __iomem *addr = bank_reg(gpio, bank, reg_rdata); - gpio->dcache[i] = ioread32(addr); - aspeed_gpio_change_cmd_source(gpio, bank, 0, GPIO_CMDSRC_ARM); - aspeed_gpio_change_cmd_source(gpio, bank, 1, GPIO_CMDSRC_ARM); - aspeed_gpio_change_cmd_source(gpio, bank, 2, GPIO_CMDSRC_ARM); - aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM); + if (gpio->config->require_dcache) { + /* Allocate a cache of the output registers */ + banks = DIV_ROUND_UP(gpio->chip.ngpio, 32); + gpio->dcache = devm_kcalloc(&pdev->dev, banks, sizeof(u32), GFP_KERNEL); + if (!gpio->dcache) + return -ENOMEM; + /* + * Populate it with initial values read from the HW + */ + for (i = 0; i < banks; i++) + gpio->dcache[i] = + gpio->config->llops->reg_bank_get(gpio, (i << 5), reg_rdata); } + if (gpio->config->llops->privilege_init) + gpio->config->llops->privilege_init(gpio); + /* Set up an irqchip */ irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -1270,13 +1429,14 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) } static struct platform_driver aspeed_gpio_driver = { + .probe = aspeed_gpio_probe, .driver = { .name = KBUILD_MODNAME, .of_match_table = aspeed_gpio_of_table, }, }; -module_platform_driver_probe(aspeed_gpio_driver, aspeed_gpio_probe); +module_platform_driver(aspeed_gpio_driver); MODULE_DESCRIPTION("Aspeed GPIO Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 5762e517338eea..491b529d25f8d3 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -751,7 +751,7 @@ static struct platform_driver brcmstb_gpio_driver = { .pm = &brcmstb_gpio_pm_ops, }, .probe = brcmstb_gpio_probe, - .remove_new = brcmstb_gpio_remove, + .remove = brcmstb_gpio_remove, .shutdown = brcmstb_gpio_shutdown, }; module_platform_driver(brcmstb_gpio_driver); diff --git a/drivers/gpio/gpio-cadence.c b/drivers/gpio/gpio-cadence.c index 1b8ffd0ddab65b..e9dd2564c54f87 100644 --- a/drivers/gpio/gpio-cadence.c +++ b/drivers/gpio/gpio-cadence.c @@ -277,7 +277,7 @@ static struct platform_driver cdns_gpio_driver = { .of_match_table = cdns_of_ids, }, .probe = cdns_gpio_probe, - .remove_new = cdns_gpio_remove, + .remove = cdns_gpio_remove, }; module_platform_driver(cdns_gpio_driver); diff --git a/drivers/gpio/gpio-cgbc.c b/drivers/gpio/gpio-cgbc.c new file mode 100644 index 00000000000000..9213faa115225f --- /dev/null +++ b/drivers/gpio/gpio-cgbc.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Congatec Board Controller GPIO driver + * + * Copyright (C) 2024 Bootlin + * Author: Thomas Richard + */ + +#include +#include +#include +#include +#include + +#define CGBC_GPIO_NGPIO 14 + +#define CGBC_GPIO_CMD_GET 0x64 +#define CGBC_GPIO_CMD_SET 0x65 +#define CGBC_GPIO_CMD_DIR_GET 0x66 +#define CGBC_GPIO_CMD_DIR_SET 0x67 + +struct cgbc_gpio_data { + struct gpio_chip chip; + struct cgbc_device_data *cgbc; + struct mutex lock; +}; + +static int cgbc_gpio_cmd(struct cgbc_device_data *cgbc, + u8 cmd0, u8 cmd1, u8 cmd2, u8 *value) +{ + u8 cmd[3] = {cmd0, cmd1, cmd2}; + + return cgbc_command(cgbc, cmd, sizeof(cmd), value, 1, NULL); +} + +static int cgbc_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct cgbc_gpio_data *gpio = gpiochip_get_data(chip); + struct cgbc_device_data *cgbc = gpio->cgbc; + int ret; + u8 val; + + scoped_guard(mutex, &gpio->lock) + ret = cgbc_gpio_cmd(cgbc, CGBC_GPIO_CMD_GET, (offset > 7) ? 1 : 0, 0, &val); + + offset %= 8; + + if (ret) + return ret; + else + return (int)(val & (u8)BIT(offset)); +} + +static void __cgbc_gpio_set(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct cgbc_gpio_data *gpio = gpiochip_get_data(chip); + struct cgbc_device_data *cgbc = gpio->cgbc; + u8 val; + int ret; + + ret = cgbc_gpio_cmd(cgbc, CGBC_GPIO_CMD_GET, (offset > 7) ? 1 : 0, 0, &val); + if (ret) + return; + + if (value) + val |= BIT(offset % 8); + else + val &= ~(BIT(offset % 8)); + + cgbc_gpio_cmd(cgbc, CGBC_GPIO_CMD_SET, (offset > 7) ? 1 : 0, val, &val); +} + +static void cgbc_gpio_set(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct cgbc_gpio_data *gpio = gpiochip_get_data(chip); + + scoped_guard(mutex, &gpio->lock) + __cgbc_gpio_set(chip, offset, value); +} + +static int cgbc_gpio_direction_set(struct gpio_chip *chip, + unsigned int offset, int direction) +{ + struct cgbc_gpio_data *gpio = gpiochip_get_data(chip); + struct cgbc_device_data *cgbc = gpio->cgbc; + int ret; + u8 val; + + ret = cgbc_gpio_cmd(cgbc, CGBC_GPIO_CMD_DIR_GET, (offset > 7) ? 1 : 0, 0, &val); + if (ret) + goto end; + + if (direction == GPIO_LINE_DIRECTION_IN) + val &= ~(BIT(offset % 8)); + else + val |= BIT(offset % 8); + + ret = cgbc_gpio_cmd(cgbc, CGBC_GPIO_CMD_DIR_SET, (offset > 7) ? 1 : 0, val, &val); + +end: + return ret; +} + +static int cgbc_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct cgbc_gpio_data *gpio = gpiochip_get_data(chip); + + guard(mutex)(&gpio->lock); + return cgbc_gpio_direction_set(chip, offset, GPIO_LINE_DIRECTION_IN); +} + +static int cgbc_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct cgbc_gpio_data *gpio = gpiochip_get_data(chip); + + guard(mutex)(&gpio->lock); + + __cgbc_gpio_set(chip, offset, value); + return cgbc_gpio_direction_set(chip, offset, GPIO_LINE_DIRECTION_OUT); +} + +static int cgbc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct cgbc_gpio_data *gpio = gpiochip_get_data(chip); + struct cgbc_device_data *cgbc = gpio->cgbc; + int ret; + u8 val; + + scoped_guard(mutex, &gpio->lock) + ret = cgbc_gpio_cmd(cgbc, CGBC_GPIO_CMD_DIR_GET, (offset > 7) ? 1 : 0, 0, &val); + + if (ret) + return ret; + + if (val & BIT(offset % 8)) + return GPIO_LINE_DIRECTION_OUT; + else + return GPIO_LINE_DIRECTION_IN; +} + +static int cgbc_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cgbc_device_data *cgbc = dev_get_drvdata(dev->parent); + struct cgbc_gpio_data *gpio; + struct gpio_chip *chip; + int ret; + + gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + gpio->cgbc = cgbc; + + platform_set_drvdata(pdev, gpio); + + chip = &gpio->chip; + chip->label = dev_name(&pdev->dev); + chip->owner = THIS_MODULE; + chip->parent = dev; + chip->base = -1; + chip->direction_input = cgbc_gpio_direction_input; + chip->direction_output = cgbc_gpio_direction_output; + chip->get_direction = cgbc_gpio_get_direction; + chip->get = cgbc_gpio_get; + chip->set = cgbc_gpio_set; + chip->ngpio = CGBC_GPIO_NGPIO; + + ret = devm_mutex_init(dev, &gpio->lock); + if (ret) + return ret; + + ret = devm_gpiochip_add_data(dev, chip, gpio); + if (ret) + return dev_err_probe(dev, ret, "Could not register GPIO chip\n"); + + return 0; +} + +static struct platform_driver cgbc_gpio_driver = { + .driver = { + .name = "cgbc-gpio", + }, + .probe = cgbc_gpio_probe, +}; + +module_platform_driver(cgbc_gpio_driver); + +MODULE_DESCRIPTION("Congatec Board Controller GPIO Driver"); +MODULE_AUTHOR("Thomas Richard "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cgbc-gpio"); diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 76b58c70b2577f..8c033e8cf3c98d 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -159,14 +158,13 @@ static int davinci_gpio_probe(struct platform_device *pdev) unsigned int ngpio, nbank, nirq, gpio_unbanked; struct davinci_gpio_controller *chips; struct device *dev = &pdev->dev; - struct device_node *dn = dev_of_node(dev); /* * The gpio banks conceptually expose a segmented bitmap, * and "ngpio" is one more than the largest zero-based * bit index that's valid. */ - ret = of_property_read_u32(dn, "ti,ngpio", &ngpio); + ret = device_property_read_u32(dev, "ti,ngpio", &ngpio); if (ret) return dev_err_probe(dev, ret, "Failed to get the number of GPIOs\n"); if (ngpio == 0) @@ -177,8 +175,8 @@ static int davinci_gpio_probe(struct platform_device *pdev) * interrupts is equal to number of gpios else all are banked so * number of interrupts is equal to number of banks(each with 16 gpios) */ - ret = of_property_read_u32(dn, "ti,davinci-gpio-unbanked", - &gpio_unbanked); + ret = device_property_read_u32(dev, "ti,davinci-gpio-unbanked", + &gpio_unbanked); if (ret) return dev_err_probe(dev, ret, "Failed to get the unbanked GPIOs property\n"); @@ -662,7 +660,7 @@ static struct platform_driver davinci_gpio_driver = { .driver = { .name = "davinci_gpio", .pm = pm_sleep_ptr(&davinci_gpio_dev_pm_ops), - .of_match_table = of_match_ptr(davinci_gpio_ids), + .of_match_table = davinci_gpio_ids, }, }; diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c index 7ead1f51128ad9..596da59d4b1338 100644 --- a/drivers/gpio/gpio-dln2.c +++ b/drivers/gpio/gpio-dln2.c @@ -512,7 +512,7 @@ static void dln2_gpio_remove(struct platform_device *pdev) static struct platform_driver dln2_gpio_driver = { .driver.name = "dln2-gpio", .probe = dln2_gpio_probe, - .remove_new = dln2_gpio_remove, + .remove = dln2_gpio_remove, }; module_platform_driver(dln2_gpio_driver); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 798235791f701f..43b667b41f5dce 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -571,7 +571,6 @@ static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode, static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev) { - struct fwnode_handle *fwnode; struct dwapb_platform_data *pdata; struct dwapb_port_property *pp; int nports; @@ -592,7 +591,7 @@ static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev) pdata->nports = nports; i = 0; - device_for_each_child_node(dev, fwnode) { + device_for_each_child_node_scoped(dev, fwnode) { pp = &pdata->properties[i++]; pp->fwnode = fwnode; @@ -600,7 +599,6 @@ static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev) pp->idx >= DWAPB_MAX_PORTS) { dev_err(dev, "missing/invalid port index for port%d\n", i); - fwnode_handle_put(fwnode); return ERR_PTR(-EINVAL); } @@ -694,6 +692,7 @@ static const struct acpi_device_id dwapb_acpi_match[] = { {"HISI0181", GPIO_REG_OFFSET_V1}, {"APMC0D07", GPIO_REG_OFFSET_V1}, {"APMC0D81", GPIO_REG_OFFSET_V2}, + {"FUJI200A", GPIO_REG_OFFSET_V1}, { } }; MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match); diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c index 2dd0e46c42adde..d4bf8d187e1664 100644 --- a/drivers/gpio/gpio-eic-sprd.c +++ b/drivers/gpio/gpio-eic-sprd.c @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include /* EIC registers definition */ @@ -617,7 +617,7 @@ static int sprd_eic_probe(struct platform_device *pdev) u16 num_banks = 0; int ret, i; - pdata = of_device_get_match_data(dev); + pdata = device_get_match_data(dev); if (!pdata) { dev_err(dev, "No matching driver data found.\n"); return -EINVAL; diff --git a/drivers/gpio/gpio-elkhartlake.c b/drivers/gpio/gpio-elkhartlake.c index 887c0fe99d3950..95de52d2cc634a 100644 --- a/drivers/gpio/gpio-elkhartlake.c +++ b/drivers/gpio/gpio-elkhartlake.c @@ -75,4 +75,4 @@ MODULE_AUTHOR("Pandith N "); MODULE_AUTHOR("Raag Jadav "); MODULE_DESCRIPTION("Intel Elkhart Lake PSE GPIO driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(GPIO_TANGIER); +MODULE_IMPORT_NS("GPIO_TANGIER"); diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index ab798c848215ad..58d2464c07bc36 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -249,7 +249,7 @@ static void ep93xx_irq_print_chip(struct irq_data *data, struct seq_file *p) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); - seq_printf(p, dev_name(gc->parent)); + seq_puts(p, dev_name(gc->parent)); } static const struct irq_chip gpio_eic_irq_chip = { diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c index 5170fe7599cdf8..d5909a4f0433c1 100644 --- a/drivers/gpio/gpio-exar.c +++ b/drivers/gpio/gpio-exar.c @@ -99,11 +99,13 @@ static void exar_set_value(struct gpio_chip *chip, unsigned int offset, struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); unsigned int bit = exar_offset_to_bit(exar_gpio, offset); + unsigned int bit_value = value ? BIT(bit) : 0; - if (value) - regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); - else - regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); + /* + * regmap_write_bits() forces value to be written when an external + * pull up/down might otherwise indicate value was already set. + */ + regmap_write_bits(exar_gpio->regmap, addr, BIT(bit), bit_value); } static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c index 97d345b5935251..c35eaa2851d853 100644 --- a/drivers/gpio/gpio-ftgpio010.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -253,18 +253,13 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) if (irq < 0) return irq; - g->clk = devm_clk_get(dev, NULL); - if (!IS_ERR(g->clk)) { - ret = clk_prepare_enable(g->clk); - if (ret) - return ret; - } else if (PTR_ERR(g->clk) == -EPROBE_DEFER) { + g->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(g->clk) && PTR_ERR(g->clk) == -EPROBE_DEFER) /* * Percolate deferrals, for anything else, * just live without the clocking. */ return PTR_ERR(g->clk); - } ret = bgpio_init(&g->gc, dev, 4, g->base + GPIO_DATA_IN, @@ -273,10 +268,9 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) g->base + GPIO_DIR, NULL, 0); - if (ret) { - dev_err(dev, "unable to init generic GPIO\n"); - goto dis_clk; - } + if (ret) + return dev_err_probe(dev, ret, "unable to init generic GPIO\n"); + g->gc.label = dev_name(dev); g->gc.base = -1; g->gc.parent = dev; @@ -293,10 +287,9 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) girq->num_parents = 1; girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), GFP_KERNEL); - if (!girq->parents) { - ret = -ENOMEM; - goto dis_clk; - } + if (!girq->parents) + return -ENOMEM; + girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; girq->parents[0] = irq; @@ -309,26 +302,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev) /* Clear any use of debounce */ writel(0x0, g->base + GPIO_DEBOUNCE_EN); - ret = devm_gpiochip_add_data(dev, &g->gc, g); - if (ret) - goto dis_clk; - - platform_set_drvdata(pdev, g); - dev_info(dev, "FTGPIO010 @%p registered\n", g->base); - - return 0; - -dis_clk: - clk_disable_unprepare(g->clk); - - return ret; -} - -static void ftgpio_gpio_remove(struct platform_device *pdev) -{ - struct ftgpio_gpio *g = platform_get_drvdata(pdev); - - clk_disable_unprepare(g->clk); + return devm_gpiochip_add_data(dev, &g->gc, g); } static const struct of_device_id ftgpio_gpio_of_match[] = { @@ -350,6 +324,5 @@ static struct platform_driver ftgpio_gpio_driver = { .of_match_table = ftgpio_gpio_of_match, }, .probe = ftgpio_gpio_probe, - .remove_new = ftgpio_gpio_remove, }; builtin_platform_driver(ftgpio_gpio_driver); diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 43d823a56e59e2..fb7c510bf2fad4 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -18,7 +18,7 @@ #include "gpio-i8255.h" -MODULE_IMPORT_NS(I8255); +MODULE_IMPORT_NS("I8255"); #define GPIOMM_EXTENT 8 #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT) diff --git a/drivers/gpio/gpio-graniterapids.c b/drivers/gpio/gpio-graniterapids.c index f2e911a3d2ca02..ad6a045fd3d2d2 100644 --- a/drivers/gpio/gpio-graniterapids.c +++ b/drivers/gpio/gpio-graniterapids.c @@ -32,12 +32,14 @@ #define GNR_PINS_PER_REG 32 #define GNR_NUM_REGS DIV_ROUND_UP(GNR_NUM_PINS, GNR_PINS_PER_REG) -#define GNR_CFG_BAR 0x00 +#define GNR_CFG_PADBAR 0x00 #define GNR_CFG_LOCK_OFFSET 0x04 -#define GNR_GPI_STATUS_OFFSET 0x20 +#define GNR_GPI_STATUS_OFFSET 0x14 #define GNR_GPI_ENABLE_OFFSET 0x24 -#define GNR_CFG_DW_RX_MASK GENMASK(25, 22) +#define GNR_CFG_DW_HOSTSW_MODE BIT(27) +#define GNR_CFG_DW_RX_MASK GENMASK(23, 22) +#define GNR_CFG_DW_INTSEL_MASK GENMASK(21, 14) #define GNR_CFG_DW_RX_DISABLE FIELD_PREP(GNR_CFG_DW_RX_MASK, 2) #define GNR_CFG_DW_RX_EDGE FIELD_PREP(GNR_CFG_DW_RX_MASK, 1) #define GNR_CFG_DW_RX_LEVEL FIELD_PREP(GNR_CFG_DW_RX_MASK, 0) @@ -50,6 +52,7 @@ * struct gnr_gpio - Intel Granite Rapids-D vGPIO driver state * @gc: GPIO controller interface * @reg_base: base address of the GPIO registers + * @pad_base: base address of the vGPIO pad configuration registers * @ro_bitmap: bitmap of read-only pins * @lock: guard the registers * @pad_backup: backup of the register state for suspend @@ -57,6 +60,7 @@ struct gnr_gpio { struct gpio_chip gc; void __iomem *reg_base; + void __iomem *pad_base; DECLARE_BITMAP(ro_bitmap, GNR_NUM_PINS); raw_spinlock_t lock; u32 pad_backup[]; @@ -65,7 +69,7 @@ struct gnr_gpio { static void __iomem *gnr_gpio_get_padcfg_addr(const struct gnr_gpio *priv, unsigned int gpio) { - return priv->reg_base + gpio * sizeof(u32); + return priv->pad_base + gpio * sizeof(u32); } static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio, @@ -88,6 +92,20 @@ static int gnr_gpio_configure_line(struct gpio_chip *gc, unsigned int gpio, return 0; } +static int gnr_gpio_request(struct gpio_chip *gc, unsigned int gpio) +{ + struct gnr_gpio *priv = gpiochip_get_data(gc); + u32 dw; + + dw = readl(gnr_gpio_get_padcfg_addr(priv, gpio)); + if (!(dw & GNR_CFG_DW_HOSTSW_MODE)) { + dev_warn(gc->parent, "GPIO %u is not owned by host", gpio); + return -EBUSY; + } + + return 0; +} + static int gnr_gpio_get(struct gpio_chip *gc, unsigned int gpio) { const struct gnr_gpio *priv = gpiochip_get_data(gc); @@ -139,6 +157,7 @@ static int gnr_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio, in static const struct gpio_chip gnr_gpio_chip = { .owner = THIS_MODULE, + .request = gnr_gpio_request, .get = gnr_gpio_get, .set = gnr_gpio_set, .get_direction = gnr_gpio_get_direction, @@ -166,7 +185,7 @@ static void gnr_gpio_irq_ack(struct irq_data *d) guard(raw_spinlock_irqsave)(&priv->lock); reg = readl(addr); - reg &= ~BIT(bit_idx); + reg |= BIT(bit_idx); writel(reg, addr); } @@ -209,10 +228,18 @@ static void gnr_gpio_irq_unmask(struct irq_data *d) static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - irq_hw_number_t pin = irqd_to_hwirq(d); - u32 mask = GNR_CFG_DW_RX_MASK; + struct gnr_gpio *priv = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 reg; u32 set; + /* Allow interrupts only if Interrupt Select field is non-zero */ + reg = readl(gnr_gpio_get_padcfg_addr(priv, hwirq)); + if (!(reg & GNR_CFG_DW_INTSEL_MASK)) { + dev_dbg(gc->parent, "GPIO %lu cannot be used as IRQ", hwirq); + return -EPERM; + } + /* Falling edge and level low triggers not supported by the GPIO controller */ switch (type) { case IRQ_TYPE_NONE: @@ -230,10 +257,11 @@ static int gnr_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - return gnr_gpio_configure_line(gc, pin, mask, set); + return gnr_gpio_configure_line(gc, hwirq, GNR_CFG_DW_RX_MASK, set); } static const struct irq_chip gnr_gpio_irq_chip = { + .name = "gpio-graniterapids", .irq_ack = gnr_gpio_irq_ack, .irq_mask = gnr_gpio_irq_mask, .irq_unmask = gnr_gpio_irq_unmask, @@ -291,6 +319,7 @@ static int gnr_gpio_probe(struct platform_device *pdev) struct gnr_gpio *priv; void __iomem *regs; int irq, ret; + u32 offset; priv = devm_kzalloc(dev, struct_size(priv, pad_backup, num_backup_pins), GFP_KERNEL); if (!priv) @@ -302,6 +331,10 @@ static int gnr_gpio_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); + priv->reg_base = regs; + offset = readl(priv->reg_base + GNR_CFG_PADBAR); + priv->pad_base = priv->reg_base + offset; + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -311,8 +344,6 @@ static int gnr_gpio_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "failed to request interrupt\n"); - priv->reg_base = regs + readl(regs + GNR_CFG_BAR); - gnr_gpio_init_pin_ro_bits(dev, priv->reg_base + GNR_CFG_LOCK_OFFSET, priv->ro_bitmap); @@ -324,7 +355,6 @@ static int gnr_gpio_probe(struct platform_device *pdev) girq = &priv->gc.irq; gpio_irq_chip_set_chip(girq, &gnr_gpio_irq_chip); - girq->chip->name = dev_name(dev); girq->parent_handler = NULL; girq->num_parents = 0; girq->parents = NULL; diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 017c7170eb57c4..169f33c41c5925 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -16,20 +16,20 @@ * Contributors: Andreas Larsson */ -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include +#include +#include #include +#include #include #include -#include +#include +#include +#include +#include +#include +#include #define GRGPIO_MAX_NGPIO 32 @@ -318,6 +318,13 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) raw_spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); } +static void grgpio_irq_domain_remove(void *data) +{ + struct irq_domain *domain = data; + + irq_domain_remove(domain); +} + static const struct irq_domain_ops grgpio_irq_domain_ops = { .map = grgpio_irq_map, .unmap = grgpio_irq_unmap, @@ -328,6 +335,7 @@ static const struct irq_domain_ops grgpio_irq_domain_ops = { static int grgpio_probe(struct platform_device *ofdev) { struct device_node *np = ofdev->dev.of_node; + struct device *dev = &ofdev->dev; void __iomem *regs; struct gpio_chip *gc; struct grgpio_priv *priv; @@ -337,7 +345,7 @@ static int grgpio_probe(struct platform_device *ofdev) int size; int i; - priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -346,28 +354,31 @@ static int grgpio_probe(struct platform_device *ofdev) return PTR_ERR(regs); gc = &priv->gc; - err = bgpio_init(gc, &ofdev->dev, 4, regs + GRGPIO_DATA, + err = bgpio_init(gc, dev, 4, regs + GRGPIO_DATA, regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL, BGPIOF_BIG_ENDIAN_BYTE_ORDER); if (err) { - dev_err(&ofdev->dev, "bgpio_init() failed\n"); + dev_err(dev, "bgpio_init() failed\n"); return err; } priv->regs = regs; priv->imask = gc->read_reg(regs + GRGPIO_IMASK); - priv->dev = &ofdev->dev; + priv->dev = dev; gc->owner = THIS_MODULE; gc->to_irq = grgpio_to_irq; - gc->label = devm_kasprintf(&ofdev->dev, GFP_KERNEL, "%pOF", np); + gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np); + if (!gc->label) + return -ENOMEM; + gc->base = -1; err = of_property_read_u32(np, "nbits", &prop); if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) { gc->ngpio = GRGPIO_MAX_NGPIO; - dev_dbg(&ofdev->dev, - "No or invalid nbits property: assume %d\n", gc->ngpio); + dev_dbg(dev, "No or invalid nbits property: assume %d\n", + gc->ngpio); } else { gc->ngpio = prop; } @@ -379,7 +390,7 @@ static int grgpio_probe(struct platform_device *ofdev) irqmap = (s32 *)of_get_property(np, "irqmap", &size); if (irqmap) { if (size < gc->ngpio) { - dev_err(&ofdev->dev, + dev_err(dev, "irqmap shorter than ngpio (%d < %d)\n", size, gc->ngpio); return -EINVAL; @@ -389,10 +400,15 @@ static int grgpio_probe(struct platform_device *ofdev) &grgpio_irq_domain_ops, priv); if (!priv->domain) { - dev_err(&ofdev->dev, "Could not add irq domain\n"); + dev_err(dev, "Could not add irq domain\n"); return -EINVAL; } + err = devm_add_action_or_reset(dev, grgpio_irq_domain_remove, + priv->domain); + if (err) + return err; + for (i = 0; i < gc->ngpio; i++) { struct grgpio_lirq *lirq; int ret; @@ -415,32 +431,18 @@ static int grgpio_probe(struct platform_device *ofdev) } } - platform_set_drvdata(ofdev, priv); - - err = gpiochip_add_data(gc, priv); + err = devm_gpiochip_add_data(dev, gc, priv); if (err) { - dev_err(&ofdev->dev, "Could not add gpiochip\n"); - if (priv->domain) - irq_domain_remove(priv->domain); + dev_err(dev, "Could not add gpiochip\n"); return err; } - dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n", + dev_info(dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n", priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off"); return 0; } -static void grgpio_remove(struct platform_device *ofdev) -{ - struct grgpio_priv *priv = platform_get_drvdata(ofdev); - - gpiochip_remove(&priv->gc); - - if (priv->domain) - irq_domain_remove(priv->domain); -} - static const struct of_device_id grgpio_match[] = { {.name = "GAISLER_GPIO"}, {.name = "01_01a"}, @@ -455,7 +457,6 @@ static struct platform_driver grgpio_driver = { .of_match_table = grgpio_match, }, .probe = grgpio_probe, - .remove_new = grgpio_remove, }; module_platform_driver(grgpio_driver); diff --git a/drivers/gpio/gpio-hlwd.c b/drivers/gpio/gpio-hlwd.c index 1bcfc1835dae8c..0580f6712bea9a 100644 --- a/drivers/gpio/gpio-hlwd.c +++ b/drivers/gpio/gpio-hlwd.c @@ -210,7 +210,7 @@ static void hlwd_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p) struct hlwd_gpio *hlwd = gpiochip_get_data(irq_data_get_irq_chip_data(data)); - seq_printf(p, dev_name(hlwd->dev)); + seq_puts(p, dev_name(hlwd->dev)); } static const struct irq_chip hlwd_gpio_irq_chip = { diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c index 64ab80fc4a1e5c..953018bfa2b1e8 100644 --- a/drivers/gpio/gpio-i8255.c +++ b/drivers/gpio/gpio-i8255.c @@ -134,7 +134,7 @@ int devm_i8255_regmap_register(struct device *const dev, return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config)); } -EXPORT_SYMBOL_NS_GPL(devm_i8255_regmap_register, I8255); +EXPORT_SYMBOL_NS_GPL(devm_i8255_regmap_register, "I8255"); MODULE_AUTHOR("William Breathitt Gray"); MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface"); diff --git a/drivers/gpio/gpio-idio-16.c b/drivers/gpio/gpio-idio-16.c index 53b1eb876a1257..0103be977c66bb 100644 --- a/drivers/gpio/gpio-idio-16.c +++ b/drivers/gpio/gpio-idio-16.c @@ -3,6 +3,9 @@ * GPIO library for the ACCES IDIO-16 family * Copyright (C) 2022 William Breathitt Gray */ + +#define DEFAULT_SYMBOL_NAMESPACE "GPIO_IDIO_16" + #include #include #include @@ -14,8 +17,6 @@ #include "gpio-idio-16.h" -#define DEFAULT_SYMBOL_NAMESPACE GPIO_IDIO_16 - #define IDIO_16_DAT_BASE 0x0 #define IDIO_16_OUT_BASE IDIO_16_DAT_BASE #define IDIO_16_IN_BASE (IDIO_16_DAT_BASE + 1) diff --git a/drivers/gpio/gpio-ljca.c b/drivers/gpio/gpio-ljca.c index dfec9fbfc7a9bd..817ecb12d5509a 100644 --- a/drivers/gpio/gpio-ljca.c +++ b/drivers/gpio/gpio-ljca.c @@ -82,9 +82,9 @@ static int ljca_gpio_config(struct ljca_gpio_dev *ljca_gpio, u8 gpio_id, int ret; mutex_lock(&ljca_gpio->trans_lock); + packet->num = 1; 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->ljca, LJCA_GPIO_CONFIG, (u8 *)packet, struct_size(packet, item, packet->num), NULL, 0); @@ -420,8 +420,14 @@ static int ljca_gpio_probe(struct auxiliary_device *auxdev, if (!ljca_gpio->connect_mode) return -ENOMEM; - mutex_init(&ljca_gpio->irq_lock); - mutex_init(&ljca_gpio->trans_lock); + ret = devm_mutex_init(&auxdev->dev, &ljca_gpio->irq_lock); + if (ret) + return ret; + + ret = devm_mutex_init(&auxdev->dev, &ljca_gpio->trans_lock); + if (ret) + return ret; + ljca_gpio->gc.direction_input = ljca_gpio_direction_input; ljca_gpio->gc.direction_output = ljca_gpio_direction_output; ljca_gpio->gc.get_direction = ljca_gpio_get_direction; @@ -453,11 +459,8 @@ static int ljca_gpio_probe(struct auxiliary_device *auxdev, INIT_WORK(&ljca_gpio->work, ljca_gpio_async); ret = gpiochip_add_data(&ljca_gpio->gc, ljca_gpio); - if (ret) { + if (ret) ljca_unregister_event_cb(ljca); - mutex_destroy(&ljca_gpio->irq_lock); - mutex_destroy(&ljca_gpio->trans_lock); - } return ret; } @@ -469,8 +472,6 @@ static void ljca_gpio_remove(struct auxiliary_device *auxdev) gpiochip_remove(&ljca_gpio->gc); ljca_unregister_event_cb(ljca_gpio->ljca); cancel_work_sync(&ljca_gpio->work); - mutex_destroy(&ljca_gpio->irq_lock); - mutex_destroy(&ljca_gpio->trans_lock); } static const struct auxiliary_device_id ljca_gpio_id_table[] = { @@ -491,4 +492,4 @@ MODULE_AUTHOR("Zhifeng Wang "); MODULE_AUTHOR("Lixu Zhang "); MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-GPIO driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(LJCA); +MODULE_IMPORT_NS("LJCA"); diff --git a/drivers/gpio/gpio-lpc18xx.c b/drivers/gpio/gpio-lpc18xx.c index e7c0ef6e54fabc..2cf9fb4637a2bb 100644 --- a/drivers/gpio/gpio-lpc18xx.c +++ b/drivers/gpio/gpio-lpc18xx.c @@ -388,7 +388,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match); static struct platform_driver lpc18xx_gpio_driver = { .probe = lpc18xx_gpio_probe, - .remove_new = lpc18xx_gpio_remove, + .remove = lpc18xx_gpio_remove, .driver = { .name = "lpc18xx-gpio", .of_match_table = lpc18xx_gpio_match, diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 701795b9d3290c..e688c13c8cc32a 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -165,7 +165,10 @@ int __max730x_probe(struct max7301 *ts) pdata = dev_get_platdata(dev); - mutex_init(&ts->lock); + ret = devm_mutex_init(ts->dev, &ts->lock); + if (ret) + return ret; + dev_set_drvdata(dev, ts); /* Power up the chip and disable IRQ output */ @@ -206,17 +209,11 @@ int __max730x_probe(struct max7301 *ts) int offset = (i - 1) * 4 + j; ret = max7301_direction_input(&ts->chip, offset); if (ret) - goto exit_destroy; + return ret; } } - ret = gpiochip_add_data(&ts->chip, ts); - if (!ret) - return ret; - -exit_destroy: - mutex_destroy(&ts->lock); - return ret; + return devm_gpiochip_add_data(ts->dev, &ts->chip, ts); } EXPORT_SYMBOL_GPL(__max730x_probe); @@ -226,8 +223,6 @@ void __max730x_remove(struct device *dev) /* Power down the chip and disable IRQ output */ ts->write(dev, 0x04, 0x00); - gpiochip_remove(&ts->chip); - mutex_destroy(&ts->lock); } EXPORT_SYMBOL_GPL(__max730x_remove); diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index ccbb63c21d6f05..7ee891ef6905cc 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -145,8 +145,6 @@ static int mb86s70_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) irq = platform_get_irq(to_platform_device(gc->parent), index); if (irq < 0) return irq; - if (irq == 0) - break; if (irq_get_irq_data(irq)->hwirq == offset) return irq; } @@ -227,7 +225,7 @@ static struct platform_driver mb86s70_gpio_driver = { .acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids), }, .probe = mb86s70_gpio_probe, - .remove_new = mb86s70_gpio_remove, + .remove = mb86s70_gpio_remove, }; module_platform_driver(mb86s70_gpio_driver); diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c index a035a9bcb57c67..ebe5da4933bce7 100644 --- a/drivers/gpio/gpio-menz127.c +++ b/drivers/gpio/gpio-menz127.c @@ -127,6 +127,13 @@ static int men_z127_set_config(struct gpio_chip *gc, unsigned offset, return -ENOTSUPP; } +static void men_z127_release_mem(void *data) +{ + struct resource *res = data; + + mcb_release_mem(res); +} + static int men_z127_probe(struct mcb_device *mdev, const struct mcb_device_id *id) { @@ -140,17 +147,19 @@ static int men_z127_probe(struct mcb_device *mdev, return -ENOMEM; men_z127_gpio->mem = mcb_request_mem(mdev, dev_name(dev)); - if (IS_ERR(men_z127_gpio->mem)) { - dev_err(dev, "failed to request device memory"); - return PTR_ERR(men_z127_gpio->mem); - } + if (IS_ERR(men_z127_gpio->mem)) + return dev_err_probe(dev, PTR_ERR(men_z127_gpio->mem), + "failed to request device memory"); - men_z127_gpio->reg_base = ioremap(men_z127_gpio->mem->start, - resource_size(men_z127_gpio->mem)); - if (men_z127_gpio->reg_base == NULL) { - ret = -ENXIO; - goto err_release; - } + ret = devm_add_action_or_reset(dev, men_z127_release_mem, + men_z127_gpio->mem); + if (ret) + return ret; + + men_z127_gpio->reg_base = devm_ioremap(dev, men_z127_gpio->mem->start, + resource_size(men_z127_gpio->mem)); + if (men_z127_gpio->reg_base == NULL) + return -ENXIO; mcb_set_drvdata(mdev, men_z127_gpio); @@ -161,34 +170,16 @@ static int men_z127_probe(struct mcb_device *mdev, men_z127_gpio->reg_base + MEN_Z127_GPIODR, NULL, 0); if (ret) - goto err_unmap; + return ret; men_z127_gpio->gc.set_config = men_z127_set_config; - ret = gpiochip_add_data(&men_z127_gpio->gc, men_z127_gpio); - if (ret) { - dev_err(dev, "failed to register MEN 16Z127 GPIO controller"); - goto err_unmap; - } - - dev_info(dev, "MEN 16Z127 GPIO driver registered"); + ret = devm_gpiochip_add_data(dev, &men_z127_gpio->gc, men_z127_gpio); + if (ret) + return dev_err_probe(dev, ret, + "failed to register MEN 16Z127 GPIO controller"); return 0; - -err_unmap: - iounmap(men_z127_gpio->reg_base); -err_release: - mcb_release_mem(men_z127_gpio->mem); - return ret; -} - -static void men_z127_remove(struct mcb_device *mdev) -{ - struct men_z127_gpio *men_z127_gpio = mcb_get_drvdata(mdev); - - gpiochip_remove(&men_z127_gpio->gc); - iounmap(men_z127_gpio->reg_base); - mcb_release_mem(men_z127_gpio->mem); } static const struct mcb_device_id men_z127_ids[] = { @@ -202,7 +193,6 @@ static struct mcb_driver men_z127_driver = { .name = "z127-gpio", }, .probe = men_z127_probe, - .remove = men_z127_remove, .id_table = men_z127_ids, }; module_mcb_driver(men_z127_driver); @@ -211,4 +201,4 @@ MODULE_AUTHOR("Andreas Werner "); MODULE_DESCRIPTION("MEN 16z127 GPIO Controller"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("mcb:16z127"); -MODULE_IMPORT_NS(MCB); +MODULE_IMPORT_NS("MCB"); diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 421d7e3a6c66ef..4335a5d8e4f6d5 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -78,24 +78,25 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id if (retval) return retval; - retval = pcim_iomap_regions(pdev, BIT(1) | BIT(0), pci_name(pdev)); - if (retval) - return dev_err_probe(dev, retval, "I/O memory mapping error\n"); - - base = pcim_iomap_table(pdev)[1]; + base = pcim_iomap_region(pdev, 1, pci_name(pdev)); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), "I/O memory mapping error\n"); irq_base = readl(base + 0 * sizeof(u32)); gpio_base = readl(base + 1 * sizeof(u32)); /* Release the IO mapping, since we already get the info from BAR1 */ - pcim_iounmap_regions(pdev, BIT(1)); + pcim_iounmap_region(pdev, 1); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->dev = dev; - priv->reg_base = pcim_iomap_table(pdev)[0]; + priv->reg_base = pcim_iomap_region(pdev, 0, pci_name(pdev)); + if (IS_ERR(priv->reg_base)) + return dev_err_probe(dev, PTR_ERR(priv->reg_base), + "I/O memory mapping error\n"); priv->pin_info.pin_ranges = mrfld_gpio_ranges; priv->pin_info.nranges = ARRAY_SIZE(mrfld_gpio_ranges); @@ -141,4 +142,4 @@ module_pci_driver(mrfld_gpio_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Merrifield SoC GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(GPIO_TANGIER); +MODULE_IMPORT_NS("GPIO_TANGIER"); diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index 6abe01bc39c3e1..6f3dda6b635fa2 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -331,7 +331,7 @@ static void mlxbf2_gpio_irq_print_chip(struct irq_data *irqd, struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd); struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc); - seq_printf(p, dev_name(gs->dev)); + seq_puts(p, dev_name(gs->dev)); } static const struct irq_chip mlxbf2_gpio_irq_chip = { diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c index e855c68c981bed..14ae2578343811 100644 --- a/drivers/gpio/gpio-mm-lantiq.c +++ b/drivers/gpio/gpio-mm-lantiq.c @@ -136,7 +136,7 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match); static struct platform_driver ltq_mm_driver = { .probe = ltq_mm_probe, - .remove_new = ltq_mm_remove, + .remove = ltq_mm_remove, .driver = { .name = "gpio-mm-ltq", .of_match_table = ltq_mm_match, diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c index a199dce3394a2e..091d96f2d68294 100644 --- a/drivers/gpio/gpio-mpc5200.c +++ b/drivers/gpio/gpio-mpc5200.c @@ -183,7 +183,7 @@ static struct platform_driver mpc52xx_wkup_gpiochip_driver = { .of_match_table = mpc52xx_wkup_gpiochip_match, }, .probe = mpc52xx_wkup_gpiochip_probe, - .remove_new = mpc52xx_gpiochip_remove, + .remove = mpc52xx_gpiochip_remove, }; /* @@ -336,7 +336,7 @@ static struct platform_driver mpc52xx_simple_gpiochip_driver = { .of_match_table = mpc52xx_simple_gpiochip_match, }, .probe = mpc52xx_simple_gpiochip_probe, - .remove_new = mpc52xx_gpiochip_remove, + .remove = mpc52xx_gpiochip_remove, }; static struct platform_driver * const drivers[] = { diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 685ec31db409d4..24417c3247b0a8 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -300,14 +299,14 @@ static const struct of_device_id mpc8xxx_gpio_ids[] = { static int mpc8xxx_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; - struct mpc8xxx_gpio_chip *mpc8xxx_gc; - struct gpio_chip *gc; const struct mpc8xxx_gpio_devtype *devtype = NULL; + struct mpc8xxx_gpio_chip *mpc8xxx_gc; + struct device *dev = &pdev->dev; struct fwnode_handle *fwnode; + struct gpio_chip *gc; int ret; - mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); + mpc8xxx_gc = devm_kzalloc(dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); if (!mpc8xxx_gc) return -ENOMEM; @@ -320,32 +319,28 @@ static int mpc8xxx_probe(struct platform_device *pdev) return PTR_ERR(mpc8xxx_gc->regs); gc = &mpc8xxx_gc->gc; - gc->parent = &pdev->dev; - - if (device_property_read_bool(&pdev->dev, "little-endian")) { - ret = bgpio_init(gc, &pdev->dev, 4, - mpc8xxx_gc->regs + GPIO_DAT, - NULL, NULL, - mpc8xxx_gc->regs + GPIO_DIR, NULL, - BGPIOF_BIG_ENDIAN); + gc->parent = dev; + + if (device_property_read_bool(dev, "little-endian")) { + ret = bgpio_init(gc, dev, 4, mpc8xxx_gc->regs + GPIO_DAT, + NULL, NULL, mpc8xxx_gc->regs + GPIO_DIR, + NULL, BGPIOF_BIG_ENDIAN); if (ret) return ret; - dev_dbg(&pdev->dev, "GPIO registers are LITTLE endian\n"); + dev_dbg(dev, "GPIO registers are LITTLE endian\n"); } else { - ret = bgpio_init(gc, &pdev->dev, 4, - mpc8xxx_gc->regs + GPIO_DAT, - NULL, NULL, - mpc8xxx_gc->regs + GPIO_DIR, NULL, - BGPIOF_BIG_ENDIAN + ret = bgpio_init(gc, dev, 4, mpc8xxx_gc->regs + GPIO_DAT, + NULL, NULL, mpc8xxx_gc->regs + GPIO_DIR, + NULL, BGPIOF_BIG_ENDIAN | BGPIOF_BIG_ENDIAN_BYTE_ORDER); if (ret) return ret; - dev_dbg(&pdev->dev, "GPIO registers are BIG endian\n"); + dev_dbg(dev, "GPIO registers are BIG endian\n"); } mpc8xxx_gc->direction_output = gc->direction_output; - devtype = device_get_match_data(&pdev->dev); + devtype = device_get_match_data(dev); if (!devtype) devtype = &mpc8xxx_gpio_devtype_default; @@ -370,10 +365,10 @@ static int mpc8xxx_probe(struct platform_device *pdev) * associated input enable must be set (GPIOxGPIE[IEn]=1) to propagate * the port value to the GPIO Data Register. */ - fwnode = dev_fwnode(&pdev->dev); - if (of_device_is_compatible(np, "fsl,qoriq-gpio") || - of_device_is_compatible(np, "fsl,ls1028a-gpio") || - of_device_is_compatible(np, "fsl,ls1088a-gpio") || + fwnode = dev_fwnode(dev); + if (device_is_compatible(dev, "fsl,qoriq-gpio") || + device_is_compatible(dev, "fsl,ls1028a-gpio") || + device_is_compatible(dev, "fsl,ls1088a-gpio") || is_acpi_node(fwnode)) { gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff); /* Also, latch state of GPIOs configured as output by bootloader. */ @@ -381,9 +376,9 @@ static int mpc8xxx_probe(struct platform_device *pdev) gc->read_reg(mpc8xxx_gc->regs + GPIO_DIR); } - ret = devm_gpiochip_add_data(&pdev->dev, gc, mpc8xxx_gc); + ret = devm_gpiochip_add_data(dev, gc, mpc8xxx_gc); if (ret) { - dev_err(&pdev->dev, + dev_err(dev, "GPIO chip registration failed with status %d\n", ret); return ret; } @@ -404,18 +399,17 @@ static int mpc8xxx_probe(struct platform_device *pdev) gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff); gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0); - ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn, + ret = devm_request_irq(dev, mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade, IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade", mpc8xxx_gc); if (ret) { - dev_err(&pdev->dev, - "failed to devm_request_irq(%d), ret = %d\n", + dev_err(dev, "failed to devm_request_irq(%d), ret = %d\n", mpc8xxx_gc->irqn, ret); goto err; } - device_init_wakeup(&pdev->dev, true); + device_init_wakeup(dev, true); return 0; err: @@ -466,7 +460,7 @@ MODULE_DEVICE_TABLE(acpi, gpio_acpi_ids); static struct platform_driver mpc8xxx_plat_driver = { .probe = mpc8xxx_probe, - .remove_new = mpc8xxx_remove, + .remove = mpc8xxx_remove, .driver = { .name = "gpio-mpc8xxx", .of_match_table = mpc8xxx_gpio_ids, diff --git a/drivers/gpio/gpio-mpfs.c b/drivers/gpio/gpio-mpfs.c new file mode 100644 index 00000000000000..561a961c97a69f --- /dev/null +++ b/drivers/gpio/gpio-mpfs.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: (GPL-2.0) +/* + * Microchip PolarFire SoC (MPFS) GPIO controller driver + * + * Copyright (c) 2018-2024 Microchip Technology Inc. and its subsidiaries + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MPFS_GPIO_CTRL(i) (0x4 * (i)) +#define MPFS_MAX_NUM_GPIO 32 +#define MPFS_GPIO_EN_INT 3 +#define MPFS_GPIO_EN_OUT_BUF BIT(2) +#define MPFS_GPIO_EN_IN BIT(1) +#define MPFS_GPIO_EN_OUT BIT(0) +#define MPFS_GPIO_DIR_MASK GENMASK(2, 0) + +#define MPFS_GPIO_TYPE_INT_EDGE_BOTH 0x80 +#define MPFS_GPIO_TYPE_INT_EDGE_NEG 0x60 +#define MPFS_GPIO_TYPE_INT_EDGE_POS 0x40 +#define MPFS_GPIO_TYPE_INT_LEVEL_LOW 0x20 +#define MPFS_GPIO_TYPE_INT_LEVEL_HIGH 0x00 +#define MPFS_GPIO_TYPE_INT_MASK GENMASK(7, 5) +#define MPFS_IRQ_REG 0x80 + +#define MPFS_INP_REG 0x84 +#define COREGPIO_INP_REG 0x90 +#define MPFS_OUTP_REG 0x88 +#define COREGPIO_OUTP_REG 0xA0 + +struct mpfs_gpio_reg_offsets { + u8 inp; + u8 outp; +}; + +struct mpfs_gpio_chip { + struct regmap *regs; + const struct mpfs_gpio_reg_offsets *offsets; + struct gpio_chip gc; +}; + +static const struct regmap_config mpfs_gpio_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static int mpfs_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio_index) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + + regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index), + MPFS_GPIO_DIR_MASK, MPFS_GPIO_EN_IN); + + return 0; +} + +static int mpfs_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio_index, int value) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + + regmap_update_bits(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index), + MPFS_GPIO_DIR_MASK, MPFS_GPIO_EN_IN); + regmap_update_bits(mpfs_gpio->regs, mpfs_gpio->offsets->outp, BIT(gpio_index), + value << gpio_index); + + return 0; +} + +static int mpfs_gpio_get_direction(struct gpio_chip *gc, + unsigned int gpio_index) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + unsigned int gpio_cfg; + + regmap_read(mpfs_gpio->regs, MPFS_GPIO_CTRL(gpio_index), &gpio_cfg); + if (gpio_cfg & MPFS_GPIO_EN_IN) + return GPIO_LINE_DIRECTION_IN; + + return GPIO_LINE_DIRECTION_OUT; +} + +static int mpfs_gpio_get(struct gpio_chip *gc, unsigned int gpio_index) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + + if (mpfs_gpio_get_direction(gc, gpio_index) == GPIO_LINE_DIRECTION_OUT) + return regmap_test_bits(mpfs_gpio->regs, mpfs_gpio->offsets->outp, BIT(gpio_index)); + else + return regmap_test_bits(mpfs_gpio->regs, mpfs_gpio->offsets->inp, BIT(gpio_index)); +} + +static void mpfs_gpio_set(struct gpio_chip *gc, unsigned int gpio_index, int value) +{ + struct mpfs_gpio_chip *mpfs_gpio = gpiochip_get_data(gc); + + mpfs_gpio_get(gc, gpio_index); + + regmap_update_bits(mpfs_gpio->regs, mpfs_gpio->offsets->outp, BIT(gpio_index), + value << gpio_index); + + mpfs_gpio_get(gc, gpio_index); +} + +static int mpfs_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mpfs_gpio_chip *mpfs_gpio; + struct clk *clk; + void __iomem *base; + int ngpios; + + mpfs_gpio = devm_kzalloc(dev, sizeof(*mpfs_gpio), GFP_KERNEL); + if (!mpfs_gpio) + return -ENOMEM; + + mpfs_gpio->offsets = device_get_match_data(&pdev->dev); + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), "failed to ioremap memory resource\n"); + + mpfs_gpio->regs = devm_regmap_init_mmio(dev, base, &mpfs_gpio_regmap_config); + if (IS_ERR(mpfs_gpio->regs)) + return dev_err_probe(dev, PTR_ERR(mpfs_gpio->regs), + "failed to initialise regmap\n"); + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get and enable clock\n"); + + ngpios = MPFS_MAX_NUM_GPIO; + device_property_read_u32(dev, "ngpios", &ngpios); + if (ngpios > MPFS_MAX_NUM_GPIO) + ngpios = MPFS_MAX_NUM_GPIO; + + mpfs_gpio->gc.direction_input = mpfs_gpio_direction_input; + mpfs_gpio->gc.direction_output = mpfs_gpio_direction_output; + mpfs_gpio->gc.get_direction = mpfs_gpio_get_direction; + mpfs_gpio->gc.get = mpfs_gpio_get; + mpfs_gpio->gc.set = mpfs_gpio_set; + mpfs_gpio->gc.base = -1; + mpfs_gpio->gc.ngpio = ngpios; + mpfs_gpio->gc.label = dev_name(dev); + mpfs_gpio->gc.parent = dev; + mpfs_gpio->gc.owner = THIS_MODULE; + + return devm_gpiochip_add_data(dev, &mpfs_gpio->gc, mpfs_gpio); +} + +static const struct mpfs_gpio_reg_offsets mpfs_reg_offsets = { + .inp = MPFS_INP_REG, + .outp = MPFS_OUTP_REG, +}; + +static const struct mpfs_gpio_reg_offsets coregpio_reg_offsets = { + .inp = COREGPIO_INP_REG, + .outp = COREGPIO_OUTP_REG, +}; + +static const struct of_device_id mpfs_gpio_of_ids[] = { + { + .compatible = "microchip,mpfs-gpio", + .data = &mpfs_reg_offsets, + }, { + .compatible = "microchip,coregpio-rtl-v3", + .data = &coregpio_reg_offsets, + }, + { /* end of list */ } +}; + +static struct platform_driver mpfs_gpio_driver = { + .probe = mpfs_gpio_probe, + .driver = { + .name = "microchip,mpfs-gpio", + .of_match_table = mpfs_gpio_of_ids, + }, +}; +builtin_platform_driver(mpfs_gpio_driver); diff --git a/drivers/gpio/gpio-mpsse.c b/drivers/gpio/gpio-mpsse.c new file mode 100644 index 00000000000000..3ea32c5e33d1a4 --- /dev/null +++ b/drivers/gpio/gpio-mpsse.c @@ -0,0 +1,527 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * FTDI MPSSE GPIO support + * + * Based on code by Anatolij Gustschin + * + * Copyright (C) 2024 Mary Strodl + */ + +#include +#include +#include +#include + +struct mpsse_priv { + struct gpio_chip gpio; + struct usb_device *udev; /* USB device encompassing all MPSSEs */ + struct usb_interface *intf; /* USB interface for this MPSSE */ + u8 intf_id; /* USB interface number for this MPSSE */ + struct work_struct irq_work; /* polling work thread */ + struct mutex irq_mutex; /* lock over irq_data */ + atomic_t irq_type[16]; /* pin -> edge detection type */ + atomic_t irq_enabled; + int id; + + u8 gpio_outputs[2]; /* Output states for GPIOs [L, H] */ + u8 gpio_dir[2]; /* Directions for GPIOs [L, H] */ + + u8 *bulk_in_buf; /* Extra recv buffer to grab status bytes */ + + struct usb_endpoint_descriptor *bulk_in; + struct usb_endpoint_descriptor *bulk_out; + + struct mutex io_mutex; /* sync I/O with disconnect */ +}; + +struct bulk_desc { + bool tx; /* direction of bulk transfer */ + u8 *data; /* input (tx) or output (rx) */ + int len; /* Length of `data` if tx, or length of */ + /* Data to read if rx */ + int len_actual; /* Length successfully transferred */ + int timeout; +}; + +static const struct usb_device_id gpio_mpsse_table[] = { + { USB_DEVICE(0x0c52, 0xa064) }, /* SeaLevel Systems, Inc. */ + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, gpio_mpsse_table); + +static DEFINE_IDA(gpio_mpsse_ida); + +/* MPSSE commands */ +#define SET_BITS_CMD 0x80 +#define GET_BITS_CMD 0x81 + +#define SET_BITMODE_REQUEST 0x0B +#define MODE_MPSSE (2 << 8) +#define MODE_RESET 0 + +/* Arbitrarily decided. This could probably be much less */ +#define MPSSE_WRITE_TIMEOUT 5000 +#define MPSSE_READ_TIMEOUT 5000 + +/* 1 millisecond, also pretty arbitrary */ +#define MPSSE_POLL_INTERVAL 1000 + +static int mpsse_bulk_xfer(struct usb_interface *intf, struct bulk_desc *desc) +{ + struct mpsse_priv *priv = usb_get_intfdata(intf); + struct usb_device *udev = priv->udev; + unsigned int pipe; + int ret; + + if (desc->tx) + pipe = usb_sndbulkpipe(udev, priv->bulk_out->bEndpointAddress); + else + pipe = usb_rcvbulkpipe(udev, priv->bulk_in->bEndpointAddress); + + ret = usb_bulk_msg(udev, pipe, desc->data, desc->len, + &desc->len_actual, desc->timeout); + if (ret) + dev_dbg(&udev->dev, "mpsse: bulk transfer failed: %d\n", ret); + + return ret; +} + +static int mpsse_write(struct usb_interface *intf, + u8 *buf, size_t len) +{ + int ret; + struct bulk_desc desc; + + desc.len_actual = 0; + desc.tx = true; + desc.data = buf; + desc.len = len; + desc.timeout = MPSSE_WRITE_TIMEOUT; + + ret = mpsse_bulk_xfer(intf, &desc); + + return ret; +} + +static int mpsse_read(struct usb_interface *intf, u8 *buf, size_t len) +{ + int ret; + struct bulk_desc desc; + struct mpsse_priv *priv = usb_get_intfdata(intf); + + desc.len_actual = 0; + desc.tx = false; + desc.data = priv->bulk_in_buf; + /* Device sends 2 additional status bytes, read len + 2 */ + desc.len = min_t(size_t, len + 2, usb_endpoint_maxp(priv->bulk_in)); + desc.timeout = MPSSE_READ_TIMEOUT; + + ret = mpsse_bulk_xfer(intf, &desc); + if (ret) + return ret; + + /* Did we get enough data? */ + if (desc.len_actual < desc.len) + return -EIO; + + memcpy(buf, desc.data + 2, desc.len_actual - 2); + + return ret; +} + +static int gpio_mpsse_set_bank(struct mpsse_priv *priv, u8 bank) +{ + int ret; + u8 tx_buf[3] = { + SET_BITS_CMD | (bank << 1), + priv->gpio_outputs[bank], + priv->gpio_dir[bank], + }; + + ret = mpsse_write(priv->intf, tx_buf, 3); + + return ret; +} + +static int gpio_mpsse_get_bank(struct mpsse_priv *priv, u8 bank) +{ + int ret; + u8 buf = GET_BITS_CMD | (bank << 1); + + ret = mpsse_write(priv->intf, &buf, 1); + if (ret) + return ret; + + ret = mpsse_read(priv->intf, &buf, 1); + if (ret) + return ret; + + return buf; +} + +static void gpio_mpsse_set_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + unsigned long i, bank, bank_mask, bank_bits; + int ret; + struct mpsse_priv *priv = gpiochip_get_data(chip); + + guard(mutex)(&priv->io_mutex); + for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { + bank = i / 8; + + if (bank_mask) { + bank_bits = bitmap_get_value8(bits, i); + /* Zero out pins we want to change */ + priv->gpio_outputs[bank] &= ~bank_mask; + /* Set pins we care about */ + priv->gpio_outputs[bank] |= bank_bits & bank_mask; + + ret = gpio_mpsse_set_bank(priv, bank); + if (ret) + dev_err(&priv->intf->dev, + "Couldn't set values for bank %ld!", + bank); + } + } +} + +static int gpio_mpsse_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + unsigned long i, bank, bank_mask; + int ret; + struct mpsse_priv *priv = gpiochip_get_data(chip); + + guard(mutex)(&priv->io_mutex); + for_each_set_clump8(i, bank_mask, mask, chip->ngpio) { + bank = i / 8; + + if (bank_mask) { + ret = gpio_mpsse_get_bank(priv, bank); + if (ret < 0) + return ret; + + bitmap_set_value8(bits, ret & bank_mask, i); + } + } + + return 0; +} + +static int gpio_mpsse_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + int err; + unsigned long mask = 0, bits = 0; + + __set_bit(offset, &mask); + err = gpio_mpsse_get_multiple(chip, &mask, &bits); + if (err) + return err; + + /* == is not guaranteed to give 1 if true */ + if (bits) + return 1; + else + return 0; +} + +static void gpio_mpsse_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + unsigned long mask = 0, bits = 0; + + __set_bit(offset, &mask); + if (value) + __set_bit(offset, &bits); + + gpio_mpsse_set_multiple(chip, &mask, &bits); +} + +static int gpio_mpsse_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct mpsse_priv *priv = gpiochip_get_data(chip); + int bank = (offset & 8) >> 3; + int bank_offset = offset & 7; + + scoped_guard(mutex, &priv->io_mutex) + priv->gpio_dir[bank] |= BIT(bank_offset); + + gpio_mpsse_gpio_set(chip, offset, value); + + return 0; +} + +static int gpio_mpsse_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct mpsse_priv *priv = gpiochip_get_data(chip); + int bank = (offset & 8) >> 3; + int bank_offset = offset & 7; + + guard(mutex)(&priv->io_mutex); + priv->gpio_dir[bank] &= ~BIT(bank_offset); + gpio_mpsse_set_bank(priv, bank); + + return 0; +} + +static int gpio_mpsse_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + int ret; + int bank = (offset & 8) >> 3; + int bank_offset = offset & 7; + struct mpsse_priv *priv = gpiochip_get_data(chip); + + guard(mutex)(&priv->io_mutex); + /* MPSSE directions are inverted */ + if (priv->gpio_dir[bank] & BIT(bank_offset)) + ret = GPIO_LINE_DIRECTION_OUT; + else + ret = GPIO_LINE_DIRECTION_IN; + + return ret; +} + +static void gpio_mpsse_poll(struct work_struct *work) +{ + unsigned long pin_mask, pin_states, flags; + int irq_enabled, offset, err, value, fire_irq, + irq, old_value[16], irq_type[16]; + struct mpsse_priv *priv = container_of(work, struct mpsse_priv, + irq_work); + + for (offset = 0; offset < priv->gpio.ngpio; ++offset) + old_value[offset] = -1; + + while ((irq_enabled = atomic_read(&priv->irq_enabled))) { + usleep_range(MPSSE_POLL_INTERVAL, MPSSE_POLL_INTERVAL + 1000); + /* Cleanup will trigger at the end of the loop */ + guard(mutex)(&priv->irq_mutex); + + pin_mask = 0; + pin_states = 0; + for (offset = 0; offset < priv->gpio.ngpio; ++offset) { + irq_type[offset] = atomic_read(&priv->irq_type[offset]); + if (irq_type[offset] != IRQ_TYPE_NONE && + irq_enabled & BIT(offset)) + pin_mask |= BIT(offset); + else + old_value[offset] = -1; + } + + err = gpio_mpsse_get_multiple(&priv->gpio, &pin_mask, + &pin_states); + if (err) { + dev_err_ratelimited(&priv->intf->dev, + "Error polling!\n"); + continue; + } + + /* Check each value */ + for (offset = 0; offset < priv->gpio.ngpio; ++offset) { + if (old_value[offset] == -1) + continue; + + fire_irq = 0; + value = pin_states & BIT(offset); + + switch (irq_type[offset]) { + case IRQ_TYPE_EDGE_RISING: + fire_irq = value > old_value[offset]; + break; + case IRQ_TYPE_EDGE_FALLING: + fire_irq = value < old_value[offset]; + break; + case IRQ_TYPE_EDGE_BOTH: + fire_irq = value != old_value[offset]; + break; + } + if (!fire_irq) + continue; + + irq = irq_find_mapping(priv->gpio.irq.domain, + offset); + local_irq_save(flags); + generic_handle_irq(irq); + local_irq_disable(); + local_irq_restore(flags); + } + + /* Sync back values so we can refer to them next tick */ + for (offset = 0; offset < priv->gpio.ngpio; ++offset) + if (irq_type[offset] != IRQ_TYPE_NONE && + irq_enabled & BIT(offset)) + old_value[offset] = pin_states & BIT(offset); + } +} + +static int gpio_mpsse_set_irq_type(struct irq_data *irqd, unsigned int type) +{ + int offset; + struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); + + offset = irqd->hwirq; + atomic_set(&priv->irq_type[offset], type & IRQ_TYPE_EDGE_BOTH); + + return 0; +} + +static void gpio_mpsse_irq_disable(struct irq_data *irqd) +{ + struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); + + atomic_and(~BIT(irqd->hwirq), &priv->irq_enabled); + gpiochip_disable_irq(&priv->gpio, irqd->hwirq); +} + +static void gpio_mpsse_irq_enable(struct irq_data *irqd) +{ + struct mpsse_priv *priv = irq_data_get_irq_chip_data(irqd); + + gpiochip_enable_irq(&priv->gpio, irqd->hwirq); + /* If no-one else was using the IRQ, enable it */ + if (!atomic_fetch_or(BIT(irqd->hwirq), &priv->irq_enabled)) { + INIT_WORK(&priv->irq_work, gpio_mpsse_poll); + schedule_work(&priv->irq_work); + } +} + +static const struct irq_chip gpio_mpsse_irq_chip = { + .name = "gpio-mpsse-irq", + .irq_enable = gpio_mpsse_irq_enable, + .irq_disable = gpio_mpsse_irq_disable, + .irq_set_type = gpio_mpsse_set_irq_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void gpio_mpsse_ida_remove(void *data) +{ + struct mpsse_priv *priv = data; + + ida_free(&gpio_mpsse_ida, priv->id); +} + +static int gpio_mpsse_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct mpsse_priv *priv; + struct device *dev; + int err; + + dev = &interface->dev; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->udev = usb_get_dev(interface_to_usbdev(interface)); + priv->intf = interface; + priv->intf_id = interface->cur_altsetting->desc.bInterfaceNumber; + + priv->id = ida_alloc(&gpio_mpsse_ida, GFP_KERNEL); + if (priv->id < 0) + return priv->id; + + err = devm_add_action_or_reset(dev, gpio_mpsse_ida_remove, priv); + if (err) + return err; + + err = devm_mutex_init(dev, &priv->io_mutex); + if (err) + return err; + + err = devm_mutex_init(dev, &priv->irq_mutex); + if (err) + return err; + + priv->gpio.label = devm_kasprintf(dev, GFP_KERNEL, + "gpio-mpsse.%d.%d", + priv->id, priv->intf_id); + if (!priv->gpio.label) + return -ENOMEM; + + priv->gpio.owner = THIS_MODULE; + priv->gpio.parent = interface->usb_dev; + priv->gpio.get_direction = gpio_mpsse_get_direction; + priv->gpio.direction_input = gpio_mpsse_direction_input; + priv->gpio.direction_output = gpio_mpsse_direction_output; + priv->gpio.get = gpio_mpsse_gpio_get; + priv->gpio.set = gpio_mpsse_gpio_set; + priv->gpio.get_multiple = gpio_mpsse_get_multiple; + priv->gpio.set_multiple = gpio_mpsse_set_multiple; + priv->gpio.base = -1; + priv->gpio.ngpio = 16; + priv->gpio.offset = priv->intf_id * priv->gpio.ngpio; + priv->gpio.can_sleep = 1; + + err = usb_find_common_endpoints(interface->cur_altsetting, + &priv->bulk_in, &priv->bulk_out, + NULL, NULL); + if (err) + return err; + + priv->bulk_in_buf = devm_kmalloc(dev, usb_endpoint_maxp(priv->bulk_in), + GFP_KERNEL); + if (!priv->bulk_in_buf) + return -ENOMEM; + + usb_set_intfdata(interface, priv); + + /* Reset mode, needed to correctly enter MPSSE mode */ + err = usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + SET_BITMODE_REQUEST, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + MODE_RESET, priv->intf_id + 1, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (err) + return err; + + /* Enter MPSSE mode */ + err = usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0), + SET_BITMODE_REQUEST, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + MODE_MPSSE, priv->intf_id + 1, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (err) + return err; + + gpio_irq_chip_set_chip(&priv->gpio.irq, &gpio_mpsse_irq_chip); + + priv->gpio.irq.parent_handler = NULL; + priv->gpio.irq.num_parents = 0; + priv->gpio.irq.parents = NULL; + priv->gpio.irq.default_type = IRQ_TYPE_NONE; + priv->gpio.irq.handler = handle_simple_irq; + + err = devm_gpiochip_add_data(dev, &priv->gpio, priv); + if (err) + return err; + + return 0; +} + +static void gpio_mpsse_disconnect(struct usb_interface *intf) +{ + struct mpsse_priv *priv = usb_get_intfdata(intf); + + priv->intf = NULL; + usb_set_intfdata(intf, NULL); + usb_put_dev(priv->udev); +} + +static struct usb_driver gpio_mpsse_driver = { + .name = "gpio-mpsse", + .probe = gpio_mpsse_probe, + .disconnect = gpio_mpsse_disconnect, + .id_table = gpio_mpsse_table, +}; + +module_usb_driver(gpio_mpsse_driver); + +MODULE_AUTHOR("Mary Strodl "); +MODULE_DESCRIPTION("MPSSE GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 8cfd3a89c0184d..5ffb332e984935 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -794,8 +794,8 @@ static int mvebu_pwm_probe(struct platform_device *pdev, u32 set; if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { - int ret = of_property_read_u32(dev->of_node, - "marvell,pwm-offset", &offset); + int ret = device_property_read_u32(dev, "marvell,pwm-offset", + &offset); if (ret < 0) return 0; } else { @@ -1106,7 +1106,7 @@ static int mvebu_gpio_probe_syscon(struct platform_device *pdev, if (IS_ERR(mvchip->regs)) return PTR_ERR(mvchip->regs); - if (of_property_read_u32(pdev->dev.of_node, "offset", &mvchip->offset)) + if (device_property_read_u32(&pdev->dev, "offset", &mvchip->offset)) return -EINVAL; return 0; @@ -1147,7 +1147,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mvchip); - if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { + if (device_property_read_u32(&pdev->dev, "ngpios", &ngpios)) { dev_err(&pdev->dev, "Missing ngpios OF property\n"); return -ENODEV; } diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 76d5d87e9681eb..54c4bfdccf5681 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -715,7 +715,7 @@ static void omap_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) { struct gpio_bank *bank = omap_irq_data_get_bank(d); - seq_printf(p, dev_name(bank->dev)); + seq_puts(p, dev_name(bank->dev)); } static const struct irq_chip omap_gpio_irq_chip = { @@ -1557,7 +1557,7 @@ static const struct dev_pm_ops gpio_pm_ops = { static struct platform_driver omap_gpio_driver = { .probe = omap_gpio_probe, - .remove_new = omap_gpio_remove, + .remove = omap_gpio_remove, .driver = { .name = "omap_gpio", .pm = &gpio_pm_ops, diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 3f2d33ee20cca9..272febc3230e90 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -815,7 +815,7 @@ static void pca953x_irq_print_chip(struct irq_data *data, struct seq_file *p) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); - seq_printf(p, dev_name(gc->parent)); + seq_puts(p, dev_name(gc->parent)); } static const struct irq_chip pca953x_irq_chip = { diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c index 44c0a21b1d1d9f..476cea1b5ed774 100644 --- a/drivers/gpio/gpio-pci-idio-16.c +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -70,24 +70,17 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct device *const dev = &pdev->dev; int err; const size_t pci_bar_index = 2; - const char *const name = pci_name(pdev); struct idio_16_regmap_config config = {}; void __iomem *regs; struct regmap *map; err = pcim_enable_device(pdev); - if (err) { - dev_err(dev, "Failed to enable PCI device (%d)\n", err); - return err; - } - - err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); - if (err) { - dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); - return err; - } + if (err) + return dev_err_probe(dev, err, "Failed to enable PCI device\n"); - regs = pcim_iomap_table(pdev)[pci_bar_index]; + regs = pcim_iomap_region(pdev, pci_bar_index, pci_name(pdev)); + if (IS_ERR(regs)) + return dev_err_probe(dev, PTR_ERR(regs), "Unable to map PCI I/O addresses\n"); map = devm_regmap_init_mmio(dev, regs, &idio_16_regmap_config); if (IS_ERR(map)) @@ -119,4 +112,4 @@ module_pci_driver(idio_16_driver); MODULE_AUTHOR("William Breathitt Gray "); MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(GPIO_IDIO_16); +MODULE_IMPORT_NS("GPIO_IDIO_16"); diff --git a/drivers/gpio/gpio-pcie-idio-24.c b/drivers/gpio/gpio-pcie-idio-24.c index 7f7f95ad4343d9..80c0ba0afa672d 100644 --- a/drivers/gpio/gpio-pcie-idio-24.c +++ b/drivers/gpio/gpio-pcie-idio-24.c @@ -305,19 +305,16 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct regmap_irq_chip_data *chip_data; err = pcim_enable_device(pdev); - if (err) { - dev_err(dev, "Failed to enable PCI device (%d)\n", err); - return err; - } + if (err) + return dev_err_probe(dev, err, "Failed to enable PCI device\n"); - err = pcim_iomap_regions(pdev, BIT(pci_plx_bar_index) | BIT(pci_bar_index), name); - if (err) { - dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); - return err; - } + pex8311_regs = pcim_iomap_region(pdev, pci_plx_bar_index, "pex8311"); + if (IS_ERR(pex8311_regs)) + return dev_err_probe(dev, PTR_ERR(pex8311_regs), "Unable to map PEX 8311 I/O addresses\n"); - pex8311_regs = pcim_iomap_table(pdev)[pci_plx_bar_index]; - idio_24_regs = pcim_iomap_table(pdev)[pci_bar_index]; + idio_24_regs = pcim_iomap_region(pdev, pci_bar_index, name); + if (IS_ERR(idio_24_regs)) + return dev_err_probe(dev, PTR_ERR(idio_24_regs), "Unable to map PCIe-IDIO-24 I/O addresses\n"); intcsr_map = devm_regmap_init_mmio(dev, pex8311_regs, &pex8311_intcsr_regmap_config); if (IS_ERR(intcsr_map)) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index a211a02d4b4a63..1c273727ffa3ac 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -291,7 +291,7 @@ static void pl061_irq_print_chip(struct irq_data *data, struct seq_file *p) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); - seq_printf(p, dev_name(gc->parent)); + seq_puts(p, dev_name(gc->parent)); } static const struct irq_chip pl061_irq_chip = { diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 6159fda38d5da1..2ecee3269a0cc3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -657,7 +657,7 @@ static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume); static struct platform_driver gpio_rcar_device_driver = { .probe = gpio_rcar_probe, - .remove_new = gpio_rcar_remove, + .remove = gpio_rcar_remove, .driver = { .name = "gpio_rcar", .pm = &gpio_rcar_pm_ops, diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index 365ab947983caf..01a3b3dac58bf1 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -26,9 +26,16 @@ #include "../pinctrl/core.h" #include "../pinctrl/pinctrl-rockchip.h" +/* + * Version ID Register + * Bits [31:24] - Major Version + * Bits [23:16] - Minor Version + * Bits [15:0] - Revision Number + */ #define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */ -#define GPIO_TYPE_V2 (0x01000C2B) /* GPIO Version ID 0x01000C2B */ -#define GPIO_TYPE_V2_1 (0x0101157C) /* GPIO Version ID 0x0101157C */ +#define GPIO_TYPE_V2 (0x01000C2B) +#define GPIO_TYPE_V2_1 (0x0101157C) +#define GPIO_TYPE_V2_2 (0x010219C8) static const struct rockchip_gpio_regs gpio_regs_v1 = { .port_dr = 0x00, @@ -602,7 +609,7 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank) * files which don't set the "gpio-ranges" property or systems that * utilize ACPI the driver has to call gpiochip_add_pin_range(). */ - if (!of_property_read_bool(bank->of_node, "gpio-ranges")) { + if (!of_property_present(bank->of_node, "gpio-ranges")) { struct device_node *pctlnp = of_get_parent(bank->of_node); struct pinctrl_dev *pctldev = NULL; @@ -661,8 +668,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) clk_prepare_enable(bank->clk); id = readl(bank->reg_base + gpio_regs_v2.version_id); - /* If not gpio v2, that is default to v1. */ - if (id == GPIO_TYPE_V2 || id == GPIO_TYPE_V2_1) { + switch (id) { + case GPIO_TYPE_V2: + case GPIO_TYPE_V2_1: + case GPIO_TYPE_V2_2: bank->gpio_regs = &gpio_regs_v2; bank->gpio_type = GPIO_TYPE_V2; bank->db_clk = of_clk_get(bank->of_node, 1); @@ -671,9 +680,14 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) clk_disable_unprepare(bank->clk); return -EINVAL; } - } else { + break; + case GPIO_TYPE_V1: bank->gpio_regs = &gpio_regs_v1; bank->gpio_type = GPIO_TYPE_V1; + break; + default: + dev_err(bank->dev, "unsupported version ID: 0x%08x\n", id); + return -ENODEV; } return 0; @@ -795,7 +809,7 @@ static const struct of_device_id rockchip_gpio_match[] = { static struct platform_driver rockchip_gpio_driver = { .probe = rockchip_gpio_probe, - .remove_new = rockchip_gpio_remove, + .remove = rockchip_gpio_remove, .driver = { .name = "rockchip-gpio", .of_match_table = rockchip_gpio_match, diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index dcca1d7f173e5f..f387dad81f2960 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -520,15 +520,12 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) static int gpio_sim_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct fwnode_handle *swnode; int ret; - device_for_each_child_node(dev, swnode) { + device_for_each_child_node_scoped(dev, swnode) { ret = gpio_sim_add_bank(swnode, dev); - if (ret) { - fwnode_handle_put(swnode); + if (ret) return ret; - } } return 0; diff --git a/drivers/gpio/gpio-sloppy-logic-analyzer.c b/drivers/gpio/gpio-sloppy-logic-analyzer.c index 59a8f3a5c4e484..8cf3b171c599b8 100644 --- a/drivers/gpio/gpio-sloppy-logic-analyzer.c +++ b/drivers/gpio/gpio-sloppy-logic-analyzer.c @@ -313,7 +313,7 @@ MODULE_DEVICE_TABLE(of, gpio_la_poll_of_match); static struct platform_driver gpio_la_poll_device_driver = { .probe = gpio_la_poll_probe, - .remove_new = gpio_la_poll_remove, + .remove = gpio_la_poll_remove, .driver = { .name = GPIO_LA_NAME, .of_match_table = gpio_la_poll_of_match, diff --git a/drivers/gpio/gpio-tangier.c b/drivers/gpio/gpio-tangier.c index 4b29abafecf6a4..a415e6d361731e 100644 --- a/drivers/gpio/gpio-tangier.c +++ b/drivers/gpio/gpio-tangier.c @@ -459,7 +459,7 @@ int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio) return 0; } -EXPORT_SYMBOL_NS_GPL(devm_tng_gpio_probe, GPIO_TANGIER); +EXPORT_SYMBOL_NS_GPL(devm_tng_gpio_probe, "GPIO_TANGIER"); static int tng_gpio_suspend(struct device *dev) { diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index e8c1485b9c7356..b6335cde455f72 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -235,7 +235,7 @@ MODULE_DEVICE_TABLE(of, tb10x_gpio_dt_ids); static struct platform_driver tb10x_gpio_driver = { .probe = tb10x_gpio_probe, - .remove_new = tb10x_gpio_remove, + .remove = tb10x_gpio_remove, .driver = { .name = "tb10x-gpio", .of_match_table = tb10x_gpio_dt_ids, diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 6d3a39a03f58e2..9ad286adf2632f 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -600,7 +600,7 @@ static void tegra_gpio_irq_print_chip(struct irq_data *d, struct seq_file *s) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); - seq_printf(s, dev_name(chip->parent)); + seq_puts(s, dev_name(chip->parent)); } static const struct irq_chip tegra_gpio_irq_chip = { diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 1ecb733a5e88b4..6895b65c86aff5 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -610,7 +610,7 @@ static void tegra186_irq_print_chip(struct irq_data *data, struct seq_file *p) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); - seq_printf(p, dev_name(gc->parent)); + seq_puts(p, dev_name(gc->parent)); } static const struct irq_chip tegra186_gpio_irq_chip = { diff --git a/drivers/gpio/gpio-tqmx86.c b/drivers/gpio/gpio-tqmx86.c index f2e7e8754d95d6..5e26eb3adabbf4 100644 --- a/drivers/gpio/gpio-tqmx86.c +++ b/drivers/gpio/gpio-tqmx86.c @@ -275,7 +275,7 @@ static void tqmx86_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - seq_printf(p, gc->label); + seq_puts(p, gc->label); } static const struct irq_chip tqmx86_gpio_irq_chip = { diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c index 0f6397b77c9d97..5c806140fdf0d6 100644 --- a/drivers/gpio/gpio-ts4900.c +++ b/drivers/gpio/gpio-ts4900.c @@ -8,8 +8,8 @@ #include #include -#include #include +#include #include #define DEFAULT_PIN_NUMBER 32 @@ -142,7 +142,7 @@ static int ts4900_gpio_probe(struct i2c_client *client) u32 ngpio; int ret; - if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio)) + if (device_property_read_u32(&client->dev, "ngpios", &ngpio)) ngpio = DEFAULT_PIN_NUMBER; priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); @@ -153,7 +153,7 @@ static int ts4900_gpio_probe(struct i2c_client *client) priv->gpio_chip.label = "ts4900-gpio"; priv->gpio_chip.ngpio = ngpio; priv->gpio_chip.parent = &client->dev; - priv->input_bit = (uintptr_t)of_device_get_match_data(&client->dev); + priv->input_bit = (uintptr_t)device_get_match_data(&client->dev); priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config); if (IS_ERR(priv->regmap)) { diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c index 90f8e9e9915e17..61cbec5c06a75b 100644 --- a/drivers/gpio/gpio-ts5500.c +++ b/drivers/gpio/gpio-ts5500.c @@ -433,7 +433,7 @@ static struct platform_driver ts5500_dio_driver = { .name = "ts5500-dio", }, .probe = ts5500_dio_probe, - .remove_new = ts5500_dio_remove, + .remove = ts5500_dio_remove, .id_table = ts5500_dio_ids, }; diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index da99ba13e82d0c..d738da8718f9cf 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -481,7 +481,7 @@ MODULE_DEVICE_TABLE(of, uniphier_gpio_match); static struct platform_driver uniphier_gpio_driver = { .probe = uniphier_gpio_probe, - .remove_new = uniphier_gpio_remove, + .remove = uniphier_gpio_remove, .driver = { .name = "uniphier-gpio", .of_match_table = uniphier_gpio_match, diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 27eff741fe9a2a..c4f34a347cb6ea 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -15,10 +15,9 @@ #include #include #include -#include -#include -#include #include +#include +#include #define VF610_GPIO_PER_PORT 32 @@ -297,7 +296,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) if (!port) return -ENOMEM; - port->sdata = of_device_get_match_data(dev); + port->sdata = device_get_match_data(dev); dual_base = port->sdata->have_dual_base; diff --git a/drivers/gpio/gpio-visconti.c b/drivers/gpio/gpio-visconti.c index ebc71ecdb6cf5d..5bd965c18a465f 100644 --- a/drivers/gpio/gpio-visconti.c +++ b/drivers/gpio/gpio-visconti.c @@ -142,7 +142,7 @@ static void visconti_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct visconti_gpio *priv = gpiochip_get_data(gc); - seq_printf(p, dev_name(priv->dev)); + seq_puts(p, dev_name(priv->dev)); } static const struct irq_chip visconti_gpio_irq_chip = { diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index bd5befa807c328..48b829733b1509 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -8,20 +8,22 @@ * Quan Nguyen . */ -#include +#include +#include #include +#include +#include +#include +#include #include #include +#include +#include + #include -#include #include "gpiolib-acpi.h" -/* Common property names */ -#define XGENE_NIRQ_PROPERTY "apm,nr-irqs" -#define XGENE_NGPIO_PROPERTY "apm,nr-gpios" -#define XGENE_IRQ_START_PROPERTY "apm,irq-start" - #define XGENE_DFLT_MAX_NGPIO 22 #define XGENE_DFLT_MAX_NIRQ 6 #define XGENE_DFLT_IRQ_START_PIN 8 @@ -252,18 +254,17 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) /* Retrieve start irq pin, use default if property not found */ priv->irq_start = XGENE_DFLT_IRQ_START_PIN; - if (!device_property_read_u32(&pdev->dev, - XGENE_IRQ_START_PROPERTY, &val32)) + if (!device_property_read_u32(&pdev->dev, "apm,irq-start", &val32)) priv->irq_start = val32; /* Retrieve number irqs, use default if property not found */ priv->nirq = XGENE_DFLT_MAX_NIRQ; - if (!device_property_read_u32(&pdev->dev, XGENE_NIRQ_PROPERTY, &val32)) + if (!device_property_read_u32(&pdev->dev, "apm,nr-irqs", &val32)) priv->nirq = val32; /* Retrieve number gpio, use default if property not found */ priv->gc.ngpio = XGENE_DFLT_MAX_NGPIO; - if (!device_property_read_u32(&pdev->dev, XGENE_NGPIO_PROPERTY, &val32)) + if (!device_property_read_u32(&pdev->dev, "apm,nr-gpios", &val32)) priv->gc.ngpio = val32; dev_info(&pdev->dev, "Support %d gpios, %d irqs start from pin %d\n", @@ -305,27 +306,25 @@ static void xgene_gpio_sb_remove(struct platform_device *pdev) } static const struct of_device_id xgene_gpio_sb_of_match[] = { - {.compatible = "apm,xgene-gpio-sb", }, - {}, + { .compatible = "apm,xgene-gpio-sb" }, + {} }; MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match); -#ifdef CONFIG_ACPI static const struct acpi_device_id xgene_gpio_sb_acpi_match[] = { - {"APMC0D15", 0}, - {}, + { "APMC0D15" }, + {} }; MODULE_DEVICE_TABLE(acpi, xgene_gpio_sb_acpi_match); -#endif static struct platform_driver xgene_gpio_sb_driver = { .driver = { .name = "xgene-gpio-sb", .of_match_table = xgene_gpio_sb_of_match, - .acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match), - }, + .acpi_match_table = xgene_gpio_sb_acpi_match, + }, .probe = xgene_gpio_sb_probe, - .remove_new = xgene_gpio_sb_remove, + .remove = xgene_gpio_sb_remove, }; module_platform_driver(xgene_gpio_sb_driver); diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c index d445eea0368796..93544e98ccbd3f 100644 --- a/drivers/gpio/gpio-xgs-iproc.c +++ b/drivers/gpio/gpio-xgs-iproc.c @@ -198,7 +198,7 @@ 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 *chip = to_iproc_gpio(gc); - seq_printf(p, dev_name(chip->dev)); + seq_puts(p, dev_name(chip->dev)); } static const struct irq_chip iproc_gpio_irq_chip = { @@ -316,7 +316,7 @@ static struct platform_driver bcm_iproc_gpio_driver = { .of_match_table = bcm_iproc_gpio_of_match, }, .probe = iproc_gpio_probe, - .remove_new = iproc_gpio_remove, + .remove = iproc_gpio_remove, }; module_platform_driver(bcm_iproc_gpio_driver); diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index afcf432a1573ed..c6a8f2c8268001 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -15,9 +15,9 @@ #include #include #include -#include #include #include +#include #include /* Register Offset Definitions */ @@ -561,9 +561,9 @@ static const struct irq_chip xgpio_irq_chip = { */ static int xgpio_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct xgpio_instance *chip; int status = 0; - struct device_node *np = pdev->dev.of_node; u32 is_dual = 0; u32 width[2]; u32 state[2]; @@ -571,14 +571,14 @@ static int xgpio_probe(struct platform_device *pdev) struct gpio_irq_chip *girq; u32 temp; - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; platform_set_drvdata(pdev, chip); /* First, check if the device is dual-channel */ - of_property_read_u32(np, "xlnx,is-dual", &is_dual); + device_property_read_u32(dev, "xlnx,is-dual", &is_dual); /* Setup defaults */ memset32(width, 0, ARRAY_SIZE(width)); @@ -586,14 +586,14 @@ static int xgpio_probe(struct platform_device *pdev) memset32(dir, 0xFFFFFFFF, ARRAY_SIZE(dir)); /* Update GPIO state shadow register with default value */ - of_property_read_u32(np, "xlnx,dout-default", &state[0]); - of_property_read_u32(np, "xlnx,dout-default-2", &state[1]); + device_property_read_u32(dev, "xlnx,dout-default", &state[0]); + device_property_read_u32(dev, "xlnx,dout-default-2", &state[1]); bitmap_from_arr32(chip->state, state, 64); /* Update GPIO direction shadow register with default value */ - of_property_read_u32(np, "xlnx,tri-default", &dir[0]); - of_property_read_u32(np, "xlnx,tri-default-2", &dir[1]); + device_property_read_u32(dev, "xlnx,tri-default", &dir[0]); + device_property_read_u32(dev, "xlnx,tri-default-2", &dir[1]); bitmap_from_arr32(chip->dir, dir, 64); @@ -601,13 +601,13 @@ static int xgpio_probe(struct platform_device *pdev) * Check device node and parent device node for device width * and assume default width of 32 */ - if (of_property_read_u32(np, "xlnx,gpio-width", &width[0])) + if (device_property_read_u32(dev, "xlnx,gpio-width", &width[0])) width[0] = 32; if (width[0] > 32) return -EINVAL; - if (is_dual && of_property_read_u32(np, "xlnx,gpio2-width", &width[1])) + if (is_dual && device_property_read_u32(dev, "xlnx,gpio2-width", &width[1])) width[1] = 32; if (width[1] > 32) @@ -624,7 +624,7 @@ static int xgpio_probe(struct platform_device *pdev) chip->gc.base = -1; chip->gc.ngpio = bitmap_weight(chip->hw_map, 64); - chip->gc.parent = &pdev->dev; + chip->gc.parent = dev; chip->gc.direction_input = xgpio_dir_in; chip->gc.direction_output = xgpio_dir_out; chip->gc.get = xgpio_get; @@ -633,21 +633,21 @@ static int xgpio_probe(struct platform_device *pdev) chip->gc.free = xgpio_free; chip->gc.set_multiple = xgpio_set_multiple; - chip->gc.label = dev_name(&pdev->dev); + chip->gc.label = dev_name(dev); chip->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->regs)) { - dev_err(&pdev->dev, "failed to ioremap memory resource\n"); + dev_err(dev, "failed to ioremap memory resource\n"); return PTR_ERR(chip->regs); } - chip->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); + chip->clk = devm_clk_get_optional_enabled(dev, NULL); if (IS_ERR(chip->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(chip->clk), "input clock not found.\n"); + return dev_err_probe(dev, PTR_ERR(chip->clk), "input clock not found.\n"); - pm_runtime_get_noresume(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); xgpio_save_regs(chip); @@ -667,8 +667,7 @@ static int xgpio_probe(struct platform_device *pdev) gpio_irq_chip_set_chip(girq, &xgpio_irq_chip); girq->parent_handler = xgpio_irqhandler; girq->num_parents = 1; - girq->parents = devm_kcalloc(&pdev->dev, 1, - sizeof(*girq->parents), + girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents), GFP_KERNEL); if (!girq->parents) { status = -ENOMEM; @@ -679,18 +678,18 @@ static int xgpio_probe(struct platform_device *pdev) girq->handler = handle_bad_irq; skip_irq: - status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); + status = devm_gpiochip_add_data(dev, &chip->gc, chip); if (status) { - dev_err(&pdev->dev, "failed to add GPIO chip\n"); + dev_err(dev, "failed to add GPIO chip\n"); goto err_pm_put; } - pm_runtime_put(&pdev->dev); + pm_runtime_put(dev); return 0; err_pm_put: - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); return status; } @@ -703,7 +702,7 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match); static struct platform_driver xgpio_plat_driver = { .probe = xgpio_probe, - .remove_new = xgpio_remove, + .remove = xgpio_remove, .driver = { .name = "gpio-xilinx", .of_match_table = xgpio_of_match, diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index 2de61337ad3b54..d7230fd83f5d68 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -169,6 +170,7 @@ static const struct gpio_chip zevio_gpio_chip = { /* Initialization */ static int zevio_gpio_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct zevio_gpio *controller; int status, i; @@ -180,6 +182,10 @@ static int zevio_gpio_probe(struct platform_device *pdev) controller->chip = zevio_gpio_chip; controller->chip.parent = &pdev->dev; + controller->chip.label = devm_kasprintf(dev, GFP_KERNEL, "%pfw", dev_fwnode(dev)); + if (!controller->chip.label) + return -ENOMEM; + controller->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(controller->regs)) return dev_err_probe(&pdev->dev, PTR_ERR(controller->regs), diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 1a42336dfc1d4a..be81fa2b17abc6 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -1023,7 +1023,7 @@ static struct platform_driver zynq_gpio_driver = { .of_match_table = zynq_gpio_of_match, }, .probe = zynq_gpio_probe, - .remove_new = zynq_gpio_remove, + .remove = zynq_gpio_remove, }; module_platform_driver(zynq_gpio_driver); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 78ecd56123a3b6..1f9fe50bba0058 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1315,9 +1315,8 @@ acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip *achip, static void acpi_gpiochip_scan_gpios(struct acpi_gpio_chip *achip) { struct gpio_chip *chip = achip->chip; - struct fwnode_handle *fwnode; - device_for_each_child_node(chip->parent, fwnode) { + device_for_each_child_node_scoped(chip->parent, fwnode) { unsigned long lflags; enum gpiod_flags dflags; struct gpio_desc *desc; @@ -1335,7 +1334,6 @@ static void acpi_gpiochip_scan_gpios(struct acpi_gpio_chip *achip) ret = gpiod_hog(desc, name, lflags, dflags); if (ret) { dev_err(chip->parent, "Failed to hog GPIO\n"); - fwnode_handle_put(fwnode); return; } } diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 78c9d9ed3d687f..40f76a90fd7db9 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -16,16 +16,15 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include +#include #include #include #include @@ -143,18 +142,22 @@ static int linehandle_validate_flags(u32 flags) static void linehandle_flags_to_desc_flags(u32 lflags, unsigned long *flagsp) { - assign_bit(FLAG_ACTIVE_LOW, flagsp, + unsigned long flags = READ_ONCE(*flagsp); + + assign_bit(FLAG_ACTIVE_LOW, &flags, lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW); - assign_bit(FLAG_OPEN_DRAIN, flagsp, + assign_bit(FLAG_OPEN_DRAIN, &flags, lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN); - assign_bit(FLAG_OPEN_SOURCE, flagsp, + assign_bit(FLAG_OPEN_SOURCE, &flags, lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE); - assign_bit(FLAG_PULL_UP, flagsp, + assign_bit(FLAG_PULL_UP, &flags, lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP); - assign_bit(FLAG_PULL_DOWN, flagsp, + assign_bit(FLAG_PULL_DOWN, &flags, lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN); - assign_bit(FLAG_BIAS_DISABLE, flagsp, + assign_bit(FLAG_BIAS_DISABLE, &flags, lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE); + + WRITE_ONCE(*flagsp, flags); } static long linehandle_set_config(struct linehandle_state *lh, @@ -184,11 +187,11 @@ static long linehandle_set_config(struct linehandle_state *lh, if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { int val = !!gcnf.default_values[i]; - ret = gpiod_direction_output(desc, val); + ret = gpiod_direction_output_nonotify(desc, val); if (ret) return ret; } else { - ret = gpiod_direction_input(desc); + ret = gpiod_direction_input_nonotify(desc); if (ret) return ret; } @@ -359,11 +362,11 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { int val = !!handlereq.default_values[i]; - ret = gpiod_direction_output(desc, val); + ret = gpiod_direction_output_nonotify(desc, val); if (ret) goto out_free_lh; } else if (lflags & GPIOHANDLE_REQUEST_INPUT) { - ret = gpiod_direction_input(desc); + ret = gpiod_direction_input_nonotify(desc); if (ret) goto out_free_lh; } @@ -417,7 +420,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) /** * struct line - contains the state of a requested line - * @node: to store the object in supinfo_tree if supplemental * @desc: the GPIO descriptor for this line. * @req: the corresponding line request * @irq: the interrupt triggered in response to events on this GPIO @@ -430,7 +432,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) * @line_seqno: the seqno for the current edge event in the sequence of * events for this line. * @work: the worker that implements software debouncing - * @debounce_period_us: the debounce period in microseconds * @sw_debounced: flag indicating if the software debouncer is active * @level: the current debounced physical level of the line * @hdesc: the Hardware Timestamp Engine (HTE) descriptor @@ -439,7 +440,6 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) * @last_seqno: the last sequence number before debounce period expires */ struct line { - struct rb_node node; struct gpio_desc *desc; /* * -- edge detector specific fields -- @@ -450,7 +450,7 @@ struct line { * The flags for the active edge detector configuration. * * edflags is set by linereq_create(), linereq_free(), and - * linereq_set_config_unlocked(), which are themselves mutually + * linereq_set_config(), which are themselves mutually * exclusive, and is accessed by edge_irq_thread(), * process_hw_ts_thread() and debounce_work_func(), * which can all live with a slightly stale value. @@ -473,15 +473,6 @@ struct line { * -- debouncer specific fields -- */ struct delayed_work work; - /* - * debounce_period_us is accessed by debounce_irq_handler() and - * process_hw_ts() which are disabled when modified by - * debounce_setup(), edge_detector_setup() or edge_detector_stop() - * or can live with a stale version when updated by - * edge_detector_update(). - * The modifying functions are themselves mutually exclusive. - */ - unsigned int debounce_period_us; /* * sw_debounce is accessed by linereq_set_config(), which is the * only setter, and linereq_get_values(), which can live with a @@ -514,17 +505,6 @@ struct line { #endif /* CONFIG_HTE */ }; -/* - * a rbtree of the struct lines containing supplemental info. - * Used to populate gpio_v2_line_info with cdev specific fields not contained - * in the struct gpio_desc. - * A line is determined to contain supplemental information by - * line_has_supinfo(). - */ -static struct rb_root supinfo_tree = RB_ROOT; -/* covers supinfo_tree */ -static DEFINE_SPINLOCK(supinfo_lock); - /** * struct linereq - contains the state of a userspace line request * @gdev: the GPIO device the line request pertains to @@ -538,8 +518,7 @@ static DEFINE_SPINLOCK(supinfo_lock); * this line request. Note that this is not used when @num_lines is 1, as * the line_seqno is then the same and is cheaper to calculate. * @config_mutex: mutex for serializing ioctl() calls to ensure consistency - * of configuration, particularly multi-step accesses to desc flags and - * changes to supinfo status. + * of configuration, particularly multi-step accesses to desc flags. * @lines: the lines held by this line request, with @num_lines elements. */ struct linereq { @@ -555,103 +534,6 @@ struct linereq { struct line lines[] __counted_by(num_lines); }; -static void supinfo_insert(struct line *line) -{ - struct rb_node **new = &(supinfo_tree.rb_node), *parent = NULL; - struct line *entry; - - guard(spinlock)(&supinfo_lock); - - while (*new) { - entry = container_of(*new, struct line, node); - - parent = *new; - if (line->desc < entry->desc) { - new = &((*new)->rb_left); - } else if (line->desc > entry->desc) { - new = &((*new)->rb_right); - } else { - /* this should never happen */ - WARN(1, "duplicate line inserted"); - return; - } - } - - rb_link_node(&line->node, parent, new); - rb_insert_color(&line->node, &supinfo_tree); -} - -static void supinfo_erase(struct line *line) -{ - guard(spinlock)(&supinfo_lock); - - rb_erase(&line->node, &supinfo_tree); -} - -static struct line *supinfo_find(struct gpio_desc *desc) -{ - struct rb_node *node = supinfo_tree.rb_node; - struct line *line; - - while (node) { - line = container_of(node, struct line, node); - if (desc < line->desc) - node = node->rb_left; - else if (desc > line->desc) - node = node->rb_right; - else - return line; - } - return NULL; -} - -static void supinfo_to_lineinfo(struct gpio_desc *desc, - struct gpio_v2_line_info *info) -{ - struct gpio_v2_line_attribute *attr; - struct line *line; - - guard(spinlock)(&supinfo_lock); - - line = supinfo_find(desc); - if (!line) - return; - - attr = &info->attrs[info->num_attrs]; - attr->id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; - attr->debounce_period_us = READ_ONCE(line->debounce_period_us); - info->num_attrs++; -} - -static inline bool line_has_supinfo(struct line *line) -{ - return READ_ONCE(line->debounce_period_us); -} - -/* - * Checks line_has_supinfo() before and after the change to avoid unnecessary - * supinfo_tree access. - * Called indirectly by linereq_create() or linereq_set_config() so line - * is already protected from concurrent changes. - */ -static void line_set_debounce_period(struct line *line, - unsigned int debounce_period_us) -{ - bool was_suppl = line_has_supinfo(line); - - WRITE_ONCE(line->debounce_period_us, debounce_period_us); - - /* if supinfo status is unchanged then we're done */ - if (line_has_supinfo(line) == was_suppl) - return; - - /* supinfo status has changed, so update the tree */ - if (was_suppl) - supinfo_erase(line); - else - supinfo_insert(line); -} - #define GPIO_V2_LINE_BIAS_FLAGS \ (GPIO_V2_LINE_FLAG_BIAS_PULL_UP | \ GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN | \ @@ -819,7 +701,7 @@ static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p) line->total_discard_seq++; line->last_seqno = ts->seq; mod_delayed_work(system_wq, &line->work, - usecs_to_jiffies(READ_ONCE(line->debounce_period_us))); + usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); } else { if (unlikely(ts->seq < line->line_seqno)) return HTE_CB_HANDLED; @@ -960,7 +842,7 @@ static irqreturn_t debounce_irq_handler(int irq, void *p) struct line *line = p; mod_delayed_work(system_wq, &line->work, - usecs_to_jiffies(READ_ONCE(line->debounce_period_us))); + usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); return IRQ_HANDLED; } @@ -1040,12 +922,13 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us) int ret, level, irq; char *label; - /* try hardware */ - ret = gpiod_set_debounce(line->desc, debounce_period_us); - if (!ret) { - line_set_debounce_period(line, debounce_period_us); - return ret; - } + /* + * Try hardware. Skip gpiod_set_config() to avoid emitting two + * CHANGED_CONFIG line state events. + */ + ret = gpio_do_set_config(line->desc, + pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, + debounce_period_us)); if (ret != -ENOTSUPP) return ret; @@ -1128,7 +1011,8 @@ static void edge_detector_stop(struct line *line) cancel_delayed_work_sync(&line->work); WRITE_ONCE(line->sw_debounced, 0); WRITE_ONCE(line->edflags, 0); - line_set_debounce_period(line, 0); + if (line->desc) + WRITE_ONCE(line->desc->debounce_period_us, 0); /* do not change line->level - see comment in debounced_value() */ } @@ -1161,7 +1045,7 @@ static int edge_detector_setup(struct line *line, ret = debounce_setup(line, debounce_period_us); if (ret) return ret; - line_set_debounce_period(line, debounce_period_us); + WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); } /* detection disabled or sw debouncer will provide edge detection */ @@ -1209,12 +1093,12 @@ static int edge_detector_update(struct line *line, gpio_v2_line_config_debounce_period(lc, line_idx); if ((active_edflags == edflags) && - (READ_ONCE(line->debounce_period_us) == debounce_period_us)) + (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)) return 0; /* sw debounced and still will be...*/ if (debounce_period_us && READ_ONCE(line->sw_debounced)) { - line_set_debounce_period(line, debounce_period_us); + WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); /* * ensure event fifo is initialised if edge detection * is now enabled. @@ -1331,7 +1215,7 @@ static int gpio_v2_line_config_validate(struct gpio_v2_line_config *lc, if (lc->num_attrs > GPIO_V2_LINE_NUM_ATTRS_MAX) return -EINVAL; - if (memchr_inv(lc->padding, 0, sizeof(lc->padding))) + if (!mem_is_zero(lc->padding, sizeof(lc->padding))) return -EINVAL; for (i = 0; i < num_lines; i++) { @@ -1348,38 +1232,42 @@ static int gpio_v2_line_config_validate(struct gpio_v2_line_config *lc, return 0; } -static void gpio_v2_line_config_flags_to_desc_flags(u64 flags, +static void gpio_v2_line_config_flags_to_desc_flags(u64 lflags, unsigned long *flagsp) { - assign_bit(FLAG_ACTIVE_LOW, flagsp, - flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW); + unsigned long flags = READ_ONCE(*flagsp); + + assign_bit(FLAG_ACTIVE_LOW, &flags, + lflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW); - if (flags & GPIO_V2_LINE_FLAG_OUTPUT) - set_bit(FLAG_IS_OUT, flagsp); - else if (flags & GPIO_V2_LINE_FLAG_INPUT) - clear_bit(FLAG_IS_OUT, flagsp); + if (lflags & GPIO_V2_LINE_FLAG_OUTPUT) + set_bit(FLAG_IS_OUT, &flags); + else if (lflags & GPIO_V2_LINE_FLAG_INPUT) + clear_bit(FLAG_IS_OUT, &flags); - assign_bit(FLAG_EDGE_RISING, flagsp, - flags & GPIO_V2_LINE_FLAG_EDGE_RISING); - assign_bit(FLAG_EDGE_FALLING, flagsp, - flags & GPIO_V2_LINE_FLAG_EDGE_FALLING); + assign_bit(FLAG_EDGE_RISING, &flags, + lflags & GPIO_V2_LINE_FLAG_EDGE_RISING); + assign_bit(FLAG_EDGE_FALLING, &flags, + lflags & GPIO_V2_LINE_FLAG_EDGE_FALLING); - assign_bit(FLAG_OPEN_DRAIN, flagsp, - flags & GPIO_V2_LINE_FLAG_OPEN_DRAIN); - assign_bit(FLAG_OPEN_SOURCE, flagsp, - flags & GPIO_V2_LINE_FLAG_OPEN_SOURCE); + assign_bit(FLAG_OPEN_DRAIN, &flags, + lflags & GPIO_V2_LINE_FLAG_OPEN_DRAIN); + assign_bit(FLAG_OPEN_SOURCE, &flags, + lflags & GPIO_V2_LINE_FLAG_OPEN_SOURCE); - assign_bit(FLAG_PULL_UP, flagsp, - flags & GPIO_V2_LINE_FLAG_BIAS_PULL_UP); - assign_bit(FLAG_PULL_DOWN, flagsp, - flags & GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN); - assign_bit(FLAG_BIAS_DISABLE, flagsp, - flags & GPIO_V2_LINE_FLAG_BIAS_DISABLED); + assign_bit(FLAG_PULL_UP, &flags, + lflags & GPIO_V2_LINE_FLAG_BIAS_PULL_UP); + assign_bit(FLAG_PULL_DOWN, &flags, + lflags & GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN); + assign_bit(FLAG_BIAS_DISABLE, &flags, + lflags & GPIO_V2_LINE_FLAG_BIAS_DISABLED); - assign_bit(FLAG_EVENT_CLOCK_REALTIME, flagsp, - flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME); - assign_bit(FLAG_EVENT_CLOCK_HTE, flagsp, - flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE); + assign_bit(FLAG_EVENT_CLOCK_REALTIME, &flags, + lflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME); + assign_bit(FLAG_EVENT_CLOCK_HTE, &flags, + lflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE); + + WRITE_ONCE(*flagsp, flags); } static long linereq_get_values(struct linereq *lr, void __user *ip) @@ -1546,11 +1434,11 @@ static long linereq_set_config(struct linereq *lr, void __user *ip) int val = gpio_v2_line_config_output_value(&lc, i); edge_detector_stop(line); - ret = gpiod_direction_output(desc, val); + ret = gpiod_direction_output_nonotify(desc, val); if (ret) return ret; } else { - ret = gpiod_direction_input(desc); + ret = gpiod_direction_input_nonotify(desc); if (ret) return ret; @@ -1669,7 +1557,6 @@ static ssize_t linereq_read(struct file *file, char __user *buf, static void linereq_free(struct linereq *lr) { - struct line *line; unsigned int i; if (lr->device_unregistered_nb.notifier_call) @@ -1677,14 +1564,10 @@ static void linereq_free(struct linereq *lr) &lr->device_unregistered_nb); for (i = 0; i < lr->num_lines; i++) { - line = &lr->lines[i]; - if (!line->desc) - continue; - - edge_detector_stop(line); - if (line_has_supinfo(line)) - supinfo_erase(line); - gpiod_free(line->desc); + if (lr->lines[i].desc) { + edge_detector_stop(&lr->lines[i]); + gpiod_free(lr->lines[i].desc); + } } kfifo_free(&lr->events); kfree(lr->label); @@ -1746,7 +1629,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) if ((ulr.num_lines == 0) || (ulr.num_lines > GPIO_V2_LINES_MAX)) return -EINVAL; - if (memchr_inv(ulr.padding, 0, sizeof(ulr.padding))) + if (!mem_is_zero(ulr.padding, sizeof(ulr.padding))) return -EINVAL; lc = &ulr.config; @@ -1818,11 +1701,11 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { int val = gpio_v2_line_config_output_value(lc, i); - ret = gpiod_direction_output(desc, val); + ret = gpiod_direction_output_nonotify(desc, val); if (ret) goto out_free_linereq; } else if (flags & GPIO_V2_LINE_FLAG_INPUT) { - ret = gpiod_direction_input(desc); + ret = gpiod_direction_input_nonotify(desc); if (ret) goto out_free_linereq; @@ -2353,8 +2236,9 @@ static void gpio_v2_line_info_changed_to_v1( #endif /* CONFIG_GPIO_CDEV_V1 */ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, - struct gpio_v2_line_info *info) + struct gpio_v2_line_info *info, bool atomic) { + u32 debounce_period_us; unsigned long dflags; const char *label; @@ -2391,12 +2275,14 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, */ if (test_bit(FLAG_REQUESTED, &dflags) || test_bit(FLAG_IS_HOGGED, &dflags) || - test_bit(FLAG_USED_AS_IRQ, &dflags) || test_bit(FLAG_EXPORT, &dflags) || test_bit(FLAG_SYSFS, &dflags) || - !gpiochip_line_is_valid(guard.gc, info->offset) || - !pinctrl_gpio_can_use_line(guard.gc, info->offset)) + !gpiochip_line_is_valid(guard.gc, info->offset)) { info->flags |= GPIO_V2_LINE_FLAG_USED; + } else if (!atomic) { + if (!pinctrl_gpio_can_use_line(guard.gc, info->offset)) + info->flags |= GPIO_V2_LINE_FLAG_USED; + } if (test_bit(FLAG_IS_OUT, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_OUTPUT; @@ -2427,6 +2313,14 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME; else if (test_bit(FLAG_EVENT_CLOCK_HTE, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE; + + debounce_period_us = READ_ONCE(desc->debounce_period_us); + if (debounce_period_us) { + info->attrs[info->num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; + info->attrs[info->num_attrs].debounce_period_us = + debounce_period_us; + info->num_attrs++; + } } struct gpio_chardev_data { @@ -2439,6 +2333,7 @@ struct gpio_chardev_data { #ifdef CONFIG_GPIO_CDEV_V1 atomic_t watch_abi_version; #endif + struct file *fp; }; static int chipinfo_get(struct gpio_chardev_data *cdev, void __user *ip) @@ -2494,7 +2389,7 @@ static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip, return -EBUSY; } - gpio_desc_to_lineinfo(desc, &lineinfo_v2); + gpio_desc_to_lineinfo(desc, &lineinfo_v2, false); gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { @@ -2516,7 +2411,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) return -EFAULT; - if (memchr_inv(lineinfo.padding, 0, sizeof(lineinfo.padding))) + if (!mem_is_zero(lineinfo.padding, sizeof(lineinfo.padding))) return -EINVAL; desc = gpio_device_get_desc(cdev->gdev, lineinfo.offset); @@ -2531,8 +2426,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, if (test_and_set_bit(lineinfo.offset, cdev->watched_lines)) return -EBUSY; } - gpio_desc_to_lineinfo(desc, &lineinfo); - supinfo_to_lineinfo(desc, &lineinfo); + gpio_desc_to_lineinfo(desc, &lineinfo, false); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { if (watch) @@ -2609,29 +2503,86 @@ static long gpio_ioctl_compat(struct file *file, unsigned int cmd, } #endif +struct lineinfo_changed_ctx { + struct work_struct work; + struct gpio_v2_line_info_changed chg; + struct gpio_device *gdev; + struct gpio_chardev_data *cdev; +}; + +static void lineinfo_changed_func(struct work_struct *work) +{ + struct lineinfo_changed_ctx *ctx = + container_of(work, struct lineinfo_changed_ctx, work); + struct gpio_chip *gc; + int ret; + + if (!(ctx->chg.info.flags & GPIO_V2_LINE_FLAG_USED)) { + /* + * If nobody set the USED flag earlier, let's see with pinctrl + * now. We're doing this late because it's a sleeping function. + * Pin functions are in general much more static and while it's + * not 100% bullet-proof, it's good enough for most cases. + */ + scoped_guard(srcu, &ctx->gdev->srcu) { + gc = srcu_dereference(ctx->gdev->chip, &ctx->gdev->srcu); + if (gc && + !pinctrl_gpio_can_use_line(gc, ctx->chg.info.offset)) + ctx->chg.info.flags |= GPIO_V2_LINE_FLAG_USED; + } + } + + ret = kfifo_in_spinlocked(&ctx->cdev->events, &ctx->chg, 1, + &ctx->cdev->wait.lock); + if (ret) + wake_up_poll(&ctx->cdev->wait, EPOLLIN); + else + pr_debug_ratelimited("lineinfo event FIFO is full - event dropped\n"); + + gpio_device_put(ctx->gdev); + fput(ctx->cdev->fp); + kfree(ctx); +} + static int lineinfo_changed_notify(struct notifier_block *nb, unsigned long action, void *data) { struct gpio_chardev_data *cdev = container_of(nb, struct gpio_chardev_data, lineinfo_changed_nb); - struct gpio_v2_line_info_changed chg; + struct lineinfo_changed_ctx *ctx; struct gpio_desc *desc = data; - int ret; if (!test_bit(gpio_chip_hwgpio(desc), cdev->watched_lines)) return NOTIFY_DONE; - memset(&chg, 0, sizeof(chg)); - chg.event_type = action; - chg.timestamp_ns = ktime_get_ns(); - gpio_desc_to_lineinfo(desc, &chg.info); - supinfo_to_lineinfo(desc, &chg.info); + /* + * If this is called from atomic context (for instance: with a spinlock + * taken by the atomic notifier chain), any sleeping calls must be done + * outside of this function in process context of the dedicated + * workqueue. + * + * Let's gather as much info as possible from the descriptor and + * postpone just the call to pinctrl_gpio_can_use_line() until the work + * is executed. + */ - ret = kfifo_in_spinlocked(&cdev->events, &chg, 1, &cdev->wait.lock); - if (ret) - wake_up_poll(&cdev->wait, EPOLLIN); - else - pr_debug_ratelimited("lineinfo event FIFO is full - event dropped\n"); + ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC); + if (!ctx) { + pr_err("Failed to allocate memory for line info notification\n"); + return NOTIFY_DONE; + } + + ctx->chg.event_type = action; + ctx->chg.timestamp_ns = ktime_get_ns(); + gpio_desc_to_lineinfo(desc, &ctx->chg.info, true); + /* Keep the GPIO device alive until we emit the event. */ + ctx->gdev = gpio_device_get(desc->gdev); + ctx->cdev = cdev; + /* Keep the file descriptor alive too. */ + get_file(ctx->cdev->fp); + + INIT_WORK(&ctx->work, lineinfo_changed_func); + queue_work(ctx->gdev->line_state_wq, &ctx->work); return NOTIFY_OK; } @@ -2778,8 +2729,8 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) cdev->gdev = gpio_device_get(gdev); cdev->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify; - ret = blocking_notifier_chain_register(&gdev->line_state_notifier, - &cdev->lineinfo_changed_nb); + ret = atomic_notifier_chain_register(&gdev->line_state_notifier, + &cdev->lineinfo_changed_nb); if (ret) goto out_free_bitmap; @@ -2791,6 +2742,7 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) goto out_unregister_line_notifier; file->private_data = cdev; + cdev->fp = file; ret = nonseekable_open(inode, file); if (ret) @@ -2802,8 +2754,8 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) blocking_notifier_chain_unregister(&gdev->device_notifier, &cdev->device_unregistered_nb); out_unregister_line_notifier: - blocking_notifier_chain_unregister(&gdev->line_state_notifier, - &cdev->lineinfo_changed_nb); + atomic_notifier_chain_unregister(&gdev->line_state_notifier, + &cdev->lineinfo_changed_nb); out_free_bitmap: gpio_device_put(gdev); bitmap_free(cdev->watched_lines); @@ -2827,8 +2779,8 @@ static int gpio_chrdev_release(struct inode *inode, struct file *file) blocking_notifier_chain_unregister(&gdev->device_notifier, &cdev->device_unregistered_nb); - blocking_notifier_chain_unregister(&gdev->line_state_notifier, - &cdev->lineinfo_changed_nb); + atomic_notifier_chain_unregister(&gdev->line_state_notifier, + &cdev->lineinfo_changed_nb); bitmap_free(cdev->watched_lines); gpio_device_put(gdev); kfree(cdev); @@ -2857,6 +2809,11 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt) gdev->chrdev.owner = THIS_MODULE; gdev->dev.devt = MKDEV(MAJOR(devt), gdev->id); + gdev->line_state_wq = alloc_ordered_workqueue("%s", WQ_HIGHPRI, + dev_name(&gdev->dev)); + if (!gdev->line_state_wq) + return -ENOMEM; + ret = cdev_device_add(&gdev->chrdev, &gdev->dev); if (ret) return ret; @@ -2873,6 +2830,7 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt) void gpiolib_cdev_unregister(struct gpio_device *gdev) { + destroy_workqueue(gdev->line_state_wq); cdev_device_del(&gdev->chrdev, &gdev->dev); blocking_notifier_call_chain(&gdev->device_notifier, 0, NULL); } diff --git a/drivers/gpio/gpiolib-legacy.c b/drivers/gpio/gpiolib-legacy.c index 28f1046fb6704d..aeae6df8bec993 100644 --- a/drivers/gpio/gpiolib-legacy.c +++ b/drivers/gpio/gpiolib-legacy.c @@ -46,9 +46,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (err) return err; - if (flags & GPIOF_ACTIVE_LOW) - set_bit(FLAG_ACTIVE_LOW, &desc->flags); - if (flags & GPIOF_IN) err = gpiod_direction_input(desc); else diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 880f1efcaca534..2e537ee979f3e2 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -337,7 +337,7 @@ static void of_gpio_flags_quirks(const struct device_node *np, * to determine if the flags should have inverted semantics. */ if (IS_ENABLED(CONFIG_SPI_MASTER) && !strcmp(propname, "cs-gpios") && - of_property_read_bool(np, "cs-gpios")) { + of_property_present(np, "cs-gpios")) { u32 cs; int ret; diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c index 51d2475c05c57c..f21dbc28cf2c8c 100644 --- a/drivers/gpio/gpiolib-swnode.c +++ b/drivers/gpio/gpiolib-swnode.c @@ -141,7 +141,7 @@ int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id) const struct software_node swnode_gpio_undefined = { .name = GPIOLIB_SWNODE_UNDEFINED_NAME, }; -EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, GPIO_SWNODE); +EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, "GPIO_SWNODE"); static int __init swnode_gpio_init(void) { diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 17ed229412af99..1acfa43bf1ab02 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -21,6 +21,8 @@ #include #include +#include + #include "gpiolib.h" #include "gpiolib-sysfs.h" @@ -77,12 +79,10 @@ static ssize_t direction_show(struct device *dev, struct gpio_desc *desc = data->desc; int value; - mutex_lock(&data->mutex); - - gpiod_get_direction(desc); - value = !!test_bit(FLAG_IS_OUT, &desc->flags); - - mutex_unlock(&data->mutex); + scoped_guard(mutex, &data->mutex) { + gpiod_get_direction(desc); + value = !!test_bit(FLAG_IS_OUT, &desc->flags); + } return sysfs_emit(buf, "%s\n", value ? "out" : "in"); } @@ -94,7 +94,7 @@ static ssize_t direction_store(struct device *dev, struct gpio_desc *desc = data->desc; ssize_t status; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); if (sysfs_streq(buf, "high")) status = gpiod_direction_output_raw(desc, 1); @@ -105,8 +105,6 @@ static ssize_t direction_store(struct device *dev, else status = -EINVAL; - mutex_unlock(&data->mutex); - return status ? : size; } static DEVICE_ATTR_RW(direction); @@ -118,11 +116,8 @@ static ssize_t value_show(struct device *dev, struct gpio_desc *desc = data->desc; ssize_t status; - mutex_lock(&data->mutex); - - status = gpiod_get_value_cansleep(desc); - - mutex_unlock(&data->mutex); + scoped_guard(mutex, &data->mutex) + status = gpiod_get_value_cansleep(desc); if (status < 0) return status; @@ -140,18 +135,17 @@ static ssize_t value_store(struct device *dev, status = kstrtol(buf, 0, &value); - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); - if (!test_bit(FLAG_IS_OUT, &desc->flags)) { - status = -EPERM; - } else if (status == 0) { - gpiod_set_value_cansleep(desc, value); - status = size; - } + if (!test_bit(FLAG_IS_OUT, &desc->flags)) + return -EPERM; + + if (status) + return status; - mutex_unlock(&data->mutex); + gpiod_set_value_cansleep(desc, value); - return status; + return size; } static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store); @@ -185,12 +179,16 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) return -ENODEV; irq_flags = IRQF_SHARED; - if (flags & GPIO_IRQF_TRIGGER_FALLING) + if (flags & GPIO_IRQF_TRIGGER_FALLING) { irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; - if (flags & GPIO_IRQF_TRIGGER_RISING) + set_bit(FLAG_EDGE_FALLING, &desc->flags); + } + if (flags & GPIO_IRQF_TRIGGER_RISING) { irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; + set_bit(FLAG_EDGE_RISING, &desc->flags); + } /* * FIXME: This should be done in the irq_request_resources callback @@ -216,6 +214,8 @@ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) err_unlock: gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc)); err_put_kn: + clear_bit(FLAG_EDGE_RISING, &desc->flags); + clear_bit(FLAG_EDGE_FALLING, &desc->flags); sysfs_put(data->value_kn); return ret; @@ -237,6 +237,8 @@ static void gpio_sysfs_free_irq(struct device *dev) data->irq_flags = 0; free_irq(data->irq, data); gpiochip_unlock_as_irq(guard.gc, gpio_chip_hwgpio(desc)); + clear_bit(FLAG_EDGE_RISING, &desc->flags); + clear_bit(FLAG_EDGE_FALLING, &desc->flags); sysfs_put(data->value_kn); } @@ -253,11 +255,8 @@ static ssize_t edge_show(struct device *dev, struct gpiod_data *data = dev_get_drvdata(dev); int flags; - mutex_lock(&data->mutex); - - flags = data->irq_flags; - - mutex_unlock(&data->mutex); + scoped_guard(mutex, &data->mutex) + flags = data->irq_flags; if (flags >= ARRAY_SIZE(trigger_names)) return 0; @@ -276,26 +275,24 @@ static ssize_t edge_store(struct device *dev, if (flags < 0) return flags; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); - if (flags == data->irq_flags) { - status = size; - goto out_unlock; - } + if (flags == data->irq_flags) + return size; if (data->irq_flags) gpio_sysfs_free_irq(dev); - if (flags) { - status = gpio_sysfs_request_irq(dev, flags); - if (!status) - status = size; - } + if (!flags) + return size; -out_unlock: - mutex_unlock(&data->mutex); + status = gpio_sysfs_request_irq(dev, flags); + if (status) + return status; - return status; + gpiod_line_state_notify(data->desc, GPIO_V2_LINE_CHANGED_CONFIG); + + return size; } static DEVICE_ATTR_RW(edge); @@ -320,6 +317,8 @@ static int gpio_sysfs_set_active_low(struct device *dev, int value) status = gpio_sysfs_request_irq(dev, flags); } + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG); + return status; } @@ -330,11 +329,8 @@ static ssize_t active_low_show(struct device *dev, struct gpio_desc *desc = data->desc; int value; - mutex_lock(&data->mutex); - - value = !!test_bit(FLAG_ACTIVE_LOW, &desc->flags); - - mutex_unlock(&data->mutex); + scoped_guard(mutex, &data->mutex) + value = !!test_bit(FLAG_ACTIVE_LOW, &desc->flags); return sysfs_emit(buf, "%d\n", value); } @@ -350,13 +346,9 @@ static ssize_t active_low_store(struct device *dev, if (status) return status; - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); - status = gpio_sysfs_set_active_low(dev, value); - - mutex_unlock(&data->mutex); - - return status ? : size; + return gpio_sysfs_set_active_low(dev, value) ?: size; } static DEVICE_ATTR_RW(active_low); @@ -463,7 +455,7 @@ static ssize_t export_store(const struct class *class, desc = gpio_to_desc(gpio); /* reject invalid GPIOs */ if (!desc) { - pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); + pr_debug_ratelimited("%s: invalid GPIO %ld\n", __func__, gpio); return -EINVAL; } @@ -473,7 +465,7 @@ static ssize_t export_store(const struct class *class, offset = gpio_chip_hwgpio(desc); if (!gpiochip_line_is_valid(guard.gc, offset)) { - pr_warn("%s: GPIO %ld masked\n", __func__, gpio); + pr_debug_ratelimited("%s: GPIO %ld masked\n", __func__, gpio); return -EINVAL; } @@ -493,10 +485,12 @@ static ssize_t export_store(const struct class *class, } status = gpiod_export(desc, true); - if (status < 0) + if (status < 0) { gpiod_free(desc); - else + } else { set_bit(FLAG_SYSFS, &desc->flags); + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED); + } done: if (status) @@ -520,7 +514,7 @@ static ssize_t unexport_store(const struct class *class, desc = gpio_to_desc(gpio); /* reject bogus commands (gpiod_unexport() ignores them) */ if (!desc) { - pr_warn("%s: invalid GPIO %ld\n", __func__, gpio); + pr_debug_ratelimited("%s: invalid GPIO %ld\n", __func__, gpio); return -EINVAL; } @@ -549,12 +543,11 @@ static struct attribute *gpio_class_attrs[] = { }; ATTRIBUTE_GROUPS(gpio_class); -static struct class gpio_class = { +static const struct class gpio_class = { .name = "gpio", - .class_groups = gpio_class_groups, + .class_groups = gpio_class_groups, }; - /** * gpiod_export - export a GPIO through sysfs * @desc: GPIO to make available, already requested @@ -573,11 +566,10 @@ static struct class gpio_class = { */ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { - const char *ioname = NULL; struct gpio_device *gdev; struct gpiod_data *data; struct device *dev; - int status, offset; + int status; /* can't export until sysfs is available ... */ if (!class_is_registered(&gpio_class)) { @@ -599,24 +591,24 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) gdev = desc->gdev; - mutex_lock(&sysfs_lock); + guard(mutex)(&sysfs_lock); /* check if chip is being removed */ if (!gdev->mockdev) { status = -ENODEV; - goto err_unlock; + goto err_clear_bit; } if (!test_bit(FLAG_REQUESTED, &desc->flags)) { gpiod_dbg(desc, "%s: unavailable (not requested)\n", __func__); status = -EPERM; - goto err_unlock; + goto err_clear_bit; } data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) { status = -ENOMEM; - goto err_unlock; + goto err_clear_bit; } data->desc = desc; @@ -626,26 +618,19 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) else data->direction_can_change = false; - offset = gpio_chip_hwgpio(desc); - if (guard.gc->names && guard.gc->names[offset]) - ioname = guard.gc->names[offset]; - dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), data, gpio_groups, - ioname ? ioname : "gpio%u", - desc_to_gpio(desc)); + "gpio%u", desc_to_gpio(desc)); if (IS_ERR(dev)) { status = PTR_ERR(dev); goto err_free_data; } - mutex_unlock(&sysfs_lock); return 0; err_free_data: kfree(data); -err_unlock: - mutex_unlock(&sysfs_lock); +err_clear_bit: clear_bit(FLAG_EXPORT, &desc->flags); gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; @@ -709,36 +694,28 @@ void gpiod_unexport(struct gpio_desc *desc) return; } - mutex_lock(&sysfs_lock); - - if (!test_bit(FLAG_EXPORT, &desc->flags)) - goto err_unlock; - - dev = class_find_device(&gpio_class, NULL, desc, match_export); - if (!dev) - goto err_unlock; - - data = dev_get_drvdata(dev); + scoped_guard(mutex, &sysfs_lock) { + if (!test_bit(FLAG_EXPORT, &desc->flags)) + return; - clear_bit(FLAG_EXPORT, &desc->flags); + dev = class_find_device(&gpio_class, NULL, desc, match_export); + if (!dev) + return; - device_unregister(dev); + data = dev_get_drvdata(dev); + clear_bit(FLAG_EXPORT, &desc->flags); + device_unregister(dev); - /* - * Release irq after deregistration to prevent race with edge_store. - */ - if (data->irq_flags) - gpio_sysfs_free_irq(dev); - - mutex_unlock(&sysfs_lock); + /* + * Release irq after deregistration to prevent race with + * edge_store. + */ + if (data->irq_flags) + gpio_sysfs_free_irq(dev); + } put_device(dev); kfree(data); - - return; - -err_unlock: - mutex_unlock(&sysfs_lock); } EXPORT_SYMBOL_GPL(gpiod_unexport); @@ -779,9 +756,8 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) if (IS_ERR(dev)) return PTR_ERR(dev); - mutex_lock(&sysfs_lock); + guard(mutex)(&sysfs_lock); gdev->mockdev = dev; - mutex_unlock(&sysfs_lock); return 0; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2b02655abb56ea..679ed764cb143c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,6 @@ #include #include #include -#include #include #include @@ -713,6 +713,45 @@ bool gpiochip_line_is_valid(const struct gpio_chip *gc, } EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); +static void gpiod_free_irqs(struct gpio_desc *desc) +{ + int irq = gpiod_to_irq(desc); + struct irq_desc *irqd = irq_to_desc(irq); + void *cookie; + + for (;;) { + /* + * Make sure the action doesn't go away while we're + * dereferencing it. Retrieve and store the cookie value. + * If the irq is freed after we release the lock, that's + * alright - the underlying maple tree lookup will return NULL + * and nothing will happen in free_irq(). + */ + scoped_guard(mutex, &irqd->request_mutex) { + if (!irq_desc_has_action(irqd)) + return; + + cookie = irqd->action->dev_id; + } + + free_irq(irq, cookie); + } +} + +/* + * The chip is going away but there may be users who had requested interrupts + * on its GPIO lines who have no idea about its removal and have no way of + * being notified about it. We need to free any interrupts still in use here or + * we'll leak memory and resources (like procfs files). + */ +static void gpiochip_free_remaining_irqs(struct gpio_chip *gc) +{ + struct gpio_desc *desc; + + for_each_gpio_desc_with_flag(gc, desc, FLAG_USED_AS_IRQ) + gpiod_free_irqs(desc); +} + static void gpiodev_release(struct device *dev) { struct gpio_device *gdev = to_gpio_device(dev); @@ -986,10 +1025,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, } } - for (desc_index = 0; desc_index < gc->ngpio; desc_index++) - gdev->descs[desc_index].gdev = gdev; - - BLOCKING_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier); + ATOMIC_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier); BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier); ret = init_srcu_struct(&gdev->srcu); @@ -1018,6 +1054,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, for (desc_index = 0; desc_index < gc->ngpio; desc_index++) { struct gpio_desc *desc = &gdev->descs[desc_index]; + desc->gdev = gdev; + if (gc->get_direction && gpiochip_line_is_valid(gc, desc_index)) { assign_bit(FLAG_IS_OUT, &desc->flags, !gc->get_direction(gc, desc_index)); @@ -1125,6 +1163,7 @@ void gpiochip_remove(struct gpio_chip *gc) /* FIXME: should the legacy sysfs handling be moved to gpio_device? */ gpiochip_sysfs_unregister(gdev); gpiochip_free_hogs(gc); + gpiochip_free_remaining_irqs(gc); scoped_guard(mutex, &gpio_devices_lock) list_del_rcu(&gdev->list); @@ -1183,11 +1222,6 @@ struct gpio_device *gpio_device_find(const void *data, struct gpio_device *gdev; struct gpio_chip *gc; - /* - * Not yet but in the future the spinlock below will become a mutex. - * Annotate this function before anyone tries to use it in interrupt - * context like it happened with gpiochip_find(). - */ might_sleep(); guard(srcu)(&gpio_devices_srcu); @@ -2392,8 +2426,10 @@ static void gpiod_free_commit(struct gpio_desc *desc) #endif desc_set_label(desc, NULL); WRITE_ONCE(desc->flags, flags); - - gpiod_line_state_notify(desc, GPIOLINE_CHANGED_RELEASED); +#ifdef CONFIG_GPIO_CDEV + WRITE_ONCE(desc->debounce_period_us, 0); +#endif + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_RELEASED); } } @@ -2492,6 +2528,8 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc, return ERR_PTR(ret); } + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED); + return desc; } EXPORT_SYMBOL_GPL(gpiochip_request_own_desc); @@ -2520,13 +2558,28 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); * rely on gpio_request() having been called beforehand. */ -static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset, - unsigned long config) +int gpio_do_set_config(struct gpio_desc *desc, unsigned long config) { - if (!gc->set_config) + int ret; + + CLASS(gpio_chip_guard, guard)(desc); + if (!guard.gc) + return -ENODEV; + + if (!guard.gc->set_config) return -ENOTSUPP; - return gc->set_config(gc, offset, config); + ret = guard.gc->set_config(guard.gc, gpio_chip_hwgpio(desc), config); +#ifdef CONFIG_GPIO_CDEV + /* + * Special case - if we're setting debounce period, we need to store + * it in the descriptor in case user-space wants to know it. + */ + if (!ret && pinconf_to_config_param(config) == PIN_CONFIG_INPUT_DEBOUNCE) + WRITE_ONCE(desc->debounce_period_us, + pinconf_to_config_argument(config)); +#endif + return ret; } static int gpio_set_config_with_argument(struct gpio_desc *desc, @@ -2535,12 +2588,8 @@ static int gpio_set_config_with_argument(struct gpio_desc *desc, { unsigned long config; - CLASS(gpio_chip_guard, guard)(desc); - if (!guard.gc) - return -ENODEV; - config = pinconf_to_config_packed(mode, argument); - return gpio_do_set_config(guard.gc, gpio_chip_hwgpio(desc), config); + return gpio_do_set_config(desc, config); } static int gpio_set_config_with_argument_optional(struct gpio_desc *desc, @@ -2615,9 +2664,15 @@ static int gpio_set_bias(struct gpio_desc *desc) */ int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce) { - return gpio_set_config_with_argument_optional(desc, - PIN_CONFIG_INPUT_DEBOUNCE, - debounce); + int ret; + + ret = gpio_set_config_with_argument_optional(desc, + PIN_CONFIG_INPUT_DEBOUNCE, + debounce); + if (!ret) + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG); + + return ret; } /** @@ -2632,10 +2687,22 @@ int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce) */ int gpiod_direction_input(struct gpio_desc *desc) { - int ret = 0; + int ret; VALIDATE_DESC(desc); + ret = gpiod_direction_input_nonotify(desc); + if (ret == 0) + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG); + + return ret; +} +EXPORT_SYMBOL_GPL(gpiod_direction_input); + +int gpiod_direction_input_nonotify(struct gpio_desc *desc) +{ + int ret = 0; + CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) return -ENODEV; @@ -2678,7 +2745,6 @@ int gpiod_direction_input(struct gpio_desc *desc) return ret; } -EXPORT_SYMBOL_GPL(gpiod_direction_input); static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) { @@ -2740,8 +2806,15 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value) */ int gpiod_direction_output_raw(struct gpio_desc *desc, int value) { + int ret; + VALIDATE_DESC(desc); - return gpiod_direction_output_raw_commit(desc, value); + + ret = gpiod_direction_output_raw_commit(desc, value); + if (ret == 0) + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG); + + return ret; } EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); @@ -2760,11 +2833,23 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); */ int gpiod_direction_output(struct gpio_desc *desc, int value) { - unsigned long flags; int ret; VALIDATE_DESC(desc); + ret = gpiod_direction_output_nonotify(desc, value); + if (ret == 0) + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG); + + return ret; +} +EXPORT_SYMBOL_GPL(gpiod_direction_output); + +int gpiod_direction_output_nonotify(struct gpio_desc *desc, int value) +{ + unsigned long flags; + int ret; + flags = READ_ONCE(desc->flags); if (test_bit(FLAG_ACTIVE_LOW, &flags)) @@ -2788,7 +2873,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) goto set_output_value; /* Emulate open drain by not actively driving the line high */ if (value) { - ret = gpiod_direction_input(desc); + ret = gpiod_direction_input_nonotify(desc); goto set_output_flag; } } else if (test_bit(FLAG_OPEN_SOURCE, &flags)) { @@ -2797,7 +2882,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) goto set_output_value; /* Emulate open source by not actively driving the line low */ if (!value) { - ret = gpiod_direction_input(desc); + ret = gpiod_direction_input_nonotify(desc); goto set_output_flag; } } else { @@ -2821,7 +2906,6 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) set_bit(FLAG_IS_OUT, &desc->flags); return ret; } -EXPORT_SYMBOL_GPL(gpiod_direction_output); /** * gpiod_enable_hw_timestamp_ns - Enable hardware timestamp in nanoseconds. @@ -2900,13 +2984,30 @@ EXPORT_SYMBOL_GPL(gpiod_disable_hw_timestamp_ns); */ int gpiod_set_config(struct gpio_desc *desc, unsigned long config) { + int ret; + VALIDATE_DESC(desc); - CLASS(gpio_chip_guard, guard)(desc); - if (!guard.gc) - return -ENODEV; + ret = gpio_do_set_config(desc, config); + if (!ret) { + /* These are the only options we notify the userspace about. */ + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + case PIN_CONFIG_DRIVE_OPEN_SOURCE: + case PIN_CONFIG_DRIVE_PUSH_PULL: + case PIN_CONFIG_INPUT_DEBOUNCE: + gpiod_line_state_notify(desc, + GPIO_V2_LINE_CHANGED_CONFIG); + break; + default: + break; + } + } - return gpio_do_set_config(guard.gc, gpio_chip_hwgpio(desc), config); + return ret; } EXPORT_SYMBOL_GPL(gpiod_set_config); @@ -2973,6 +3074,7 @@ void gpiod_toggle_active_low(struct gpio_desc *desc) { VALIDATE_DESC_VOID(desc); change_bit(FLAG_ACTIVE_LOW, &desc->flags); + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG); } EXPORT_SYMBOL_GPL(gpiod_toggle_active_low); @@ -3617,9 +3719,15 @@ EXPORT_SYMBOL_GPL(gpiod_cansleep); */ int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name) { + int ret; + VALIDATE_DESC(desc); - return desc_set_label(desc, name); + ret = desc_set_label(desc, name); + if (ret == 0) + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_CONFIG); + + return ret; } EXPORT_SYMBOL_GPL(gpiod_set_consumer_name); @@ -4047,8 +4155,8 @@ EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action) { - blocking_notifier_call_chain(&desc->gdev->line_state_notifier, - action, desc); + atomic_notifier_call_chain(&desc->gdev->line_state_notifier, + action, desc); } /** @@ -4325,7 +4433,7 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer, return ERR_PTR(ret); } - gpiod_line_state_notify(desc, GPIOLINE_CHANGED_REQUESTED); + gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED); return desc; } @@ -4497,10 +4605,10 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, /* Process flags */ if (dflags & GPIOD_FLAGS_BIT_DIR_OUT) - ret = gpiod_direction_output(desc, + ret = gpiod_direction_output_nonotify(desc, !!(dflags & GPIOD_FLAGS_BIT_DIR_VAL)); else - ret = gpiod_direction_input(desc); + ret = gpiod_direction_input_nonotify(desc); return ret; } @@ -4967,19 +5075,19 @@ static int gpiolib_seq_show(struct seq_file *s, void *v) struct gpio_chip *gc; struct device *parent; + if (priv->newline) + seq_putc(s, '\n'); + guard(srcu)(&gdev->srcu); gc = srcu_dereference(gdev->chip, &gdev->srcu); if (!gc) { - seq_printf(s, "%s%s: (dangling chip)\n", - priv->newline ? "\n" : "", - dev_name(&gdev->dev)); + seq_printf(s, "%s: (dangling chip)\n", dev_name(&gdev->dev)); return 0; } - seq_printf(s, "%s%s: GPIOs %u-%u", priv->newline ? "\n" : "", - dev_name(&gdev->dev), - gdev->base, gdev->base + gdev->ngpio - 1); + seq_printf(s, "%s: GPIOs %u-%u", dev_name(&gdev->dev), gdev->base, + gdev->base + gdev->ngpio - 1); parent = gc->parent; if (parent) seq_printf(s, ", parent: %s/%s", diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 067197d61d57e4..83690f72f7e5cb 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -17,6 +17,7 @@ #include #include #include +#include #define GPIOCHIP_NAME "gpiochip" @@ -44,6 +45,8 @@ * @list: links gpio_device:s together for traversal * @line_state_notifier: used to notify subscribers about lines being * requested, released or reconfigured + * @line_state_wq: used to emit line state events from a separate thread in + * process context * @device_notifier: used to notify character device wait queues about the GPIO * device being unregistered * @srcu: protects the pointer to the underlying GPIO chip @@ -69,7 +72,8 @@ struct gpio_device { const char *label; void *data; struct list_head list; - struct blocking_notifier_head line_state_notifier; + struct atomic_notifier_head line_state_notifier; + struct workqueue_struct *line_state_wq; struct blocking_notifier_head device_notifier; struct srcu_struct srcu; @@ -151,6 +155,8 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, int gpiod_set_transitory(struct gpio_desc *desc, bool transitory); void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action); +int gpiod_direction_output_nonotify(struct gpio_desc *desc, int value); +int gpiod_direction_input_nonotify(struct gpio_desc *desc); struct gpio_desc_label { struct rcu_head rh; @@ -165,6 +171,7 @@ struct gpio_desc_label { * @label: Name of the consumer * @name: Line name * @hog: Pointer to the device node that hogs this line (if any) + * @debounce_period_us: Debounce period in microseconds * * These are obtained using gpiod_get() and are preferable to the old * integer-based handles. @@ -202,6 +209,10 @@ struct gpio_desc { #ifdef CONFIG_OF_DYNAMIC struct device_node *hog; #endif +#ifdef CONFIG_GPIO_CDEV + /* debounce period in microseconds */ + unsigned int debounce_period_us; +#endif }; #define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) @@ -249,6 +260,7 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer, const char *label, bool platform_lookup_allowed); +int gpio_do_set_config(struct gpio_desc *desc, unsigned long config); int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, unsigned long lflags, enum gpiod_flags dflags); int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce); diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 1cb5a4f1929335..772fc7625639de 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -9,9 +9,6 @@ menuconfig DRM tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && HAS_DMA select DRM_PANEL_ORIENTATION_QUIRKS - select DRM_KMS_HELPER if DRM_FBDEV_EMULATION - select FB_CORE if DRM_FBDEV_EMULATION - select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION select HDMI select I2C select DMA_SHARED_BUFFER @@ -102,6 +99,7 @@ config DRM_KUNIT_TEST config DRM_KMS_HELPER tristate depends on DRM + select FB_CORE if DRM_FBDEV_EMULATION help CRTC helpers for KMS drivers. @@ -152,6 +150,7 @@ config DRM_PANIC_SCREEN config DRM_PANIC_SCREEN_QR_CODE bool "Add a panic screen with a QR code" depends on DRM_PANIC && RUST + select ZLIB_DEFLATE help This option adds a QR code generator, and a panic screen with a QR code. The QR code will contain the last lines of kmsg and other debug @@ -210,9 +209,47 @@ config DRM_DEBUG_MODESET_LOCK If in doubt, say "N". +config DRM_CLIENT + bool + depends on DRM + help + Enables support for DRM clients. DRM drivers that need + struct drm_client_dev and its interfaces should select this + option. Drivers that support the default clients should + select DRM_CLIENT_SELECTION instead. + +config DRM_CLIENT_LIB + tristate + depends on DRM + select DRM_KMS_HELPER if DRM_FBDEV_EMULATION + select FB_CORE if DRM_FBDEV_EMULATION + help + This option enables the DRM client library and selects all + modules and components according to the enabled clients. + +config DRM_CLIENT_SELECTION + tristate + depends on DRM + select DRM_CLIENT_LIB if DRM_FBDEV_EMULATION + help + Drivers that support in-kernel DRM clients have to select this + option. + +config DRM_CLIENT_SETUP + bool + depends on DRM_CLIENT_SELECTION + help + Enables the DRM client selection. DRM drivers that support the + default clients should select DRM_CLIENT_SELECTION instead. + +menu "Supported DRM clients" + depends on DRM_CLIENT_SELECTION + config DRM_FBDEV_EMULATION bool "Enable legacy fbdev support for your modesetting driver" - depends on DRM + depends on DRM_CLIENT_SELECTION + select DRM_CLIENT + select DRM_CLIENT_SETUP select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE default FB help @@ -251,6 +288,8 @@ config DRM_FBDEV_LEAK_PHYS_SMEM If in doubt, say "N" or spread the word to your closed source library vendor. +endmenu + config DRM_LOAD_EDID_FIRMWARE bool "Allow to specify an EDID data set instead of probing for it" depends on DRM @@ -320,19 +359,24 @@ config DRM_TTM_HELPER tristate depends on DRM select DRM_TTM + select FB_CORE if DRM_FBDEV_EMULATION + select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION help Helpers for ttm-based gem objects config DRM_GEM_DMA_HELPER tristate depends on DRM - select FB_DMAMEM_HELPERS if DRM_FBDEV_EMULATION + select FB_CORE if DRM_FBDEV_EMULATION + select FB_DMAMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION help Choose this if you need the GEM DMA helper functions config DRM_GEM_SHMEM_HELPER tristate depends on DRM && MMU + select FB_CORE if DRM_FBDEV_EMULATION + select FB_SYSMEM_HELPERS_DEFERRED if DRM_FBDEV_EMULATION help Choose this if you need the GEM shmem helper functions @@ -472,6 +516,7 @@ source "drivers/gpu/drm/imagination/Kconfig" config DRM_HYPERV tristate "DRM Support for Hyper-V synthetic video device" depends on DRM && PCI && MMU && HYPERV + select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_GEM_SHMEM_HELPER help diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 784229d4504dcb..463afad1b5ca62 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -34,15 +34,12 @@ endif subdir-ccflags-$(CONFIG_DRM_WERROR) += -Werror drm-y := \ - drm_aperture.o \ drm_atomic.o \ drm_atomic_uapi.o \ drm_auth.o \ drm_blend.o \ drm_bridge.o \ drm_cache.o \ - drm_client.o \ - drm_client_modeset.o \ drm_color_mgmt.o \ drm_connector.o \ drm_crtc.o \ @@ -68,6 +65,7 @@ drm-y := \ drm_prime.o \ drm_print.o \ drm_property.o \ + drm_rect.o \ drm_syncobj.o \ drm_sysfs.o \ drm_trace_points.o \ @@ -75,6 +73,10 @@ drm-y := \ drm_vblank_work.o \ drm_vma_manager.o \ drm_writeback.o +drm-$(CONFIG_DRM_CLIENT) += \ + drm_client.o \ + drm_client_event.o \ + drm_client_modeset.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o @@ -140,13 +142,20 @@ drm_kms_helper-y := \ drm_modeset_helper.o \ drm_plane_helper.o \ drm_probe_helper.o \ - drm_rect.o \ drm_self_refresh_helper.o \ drm_simple_kms_helper.o drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o +# +# DRM clients +# + +drm_client_lib-y := drm_client_setup.o +drm_client_lib-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fbdev_client.o +obj-$(CONFIG_DRM_CLIENT_LIB) += drm_client_lib.o + # # Drivers and the rest # diff --git a/drivers/gpu/drm/amd/amdgpu/Kconfig b/drivers/gpu/drm/amd/amdgpu/Kconfig index 0051fb1b437fb8..41fa3377d9cf56 100644 --- a/drivers/gpu/drm/amd/amdgpu/Kconfig +++ b/drivers/gpu/drm/amd/amdgpu/Kconfig @@ -5,7 +5,10 @@ config DRM_AMDGPU depends on DRM && PCI && MMU depends on !UML select FW_LOADER + select DRM_CLIENT + select DRM_CLIENT_SELECTION select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_DSC_HELPER select DRM_DISPLAY_HDMI_HELPER select DRM_DISPLAY_HDCP_HELPER select DRM_DISPLAY_HELPER diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index b0f95a7649bfed..f44de9d4b6a17f 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -85,16 +85,9 @@ static int aldebaran_mode2_suspend_ip(struct amdgpu_device *adev) AMD_IP_BLOCK_TYPE_SDMA)) continue; - r = adev->ip_blocks[i].version->funcs->suspend(adev); - - if (r) { - dev_err(adev->dev, - "suspend of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_suspend(&adev->ip_blocks[i]); + if (r) return r; - } - - adev->ip_blocks[i].status.hw = false; } return 0; @@ -246,7 +239,7 @@ static int aldebaran_mode2_restore_ip(struct amdgpu_device *adev) dev_err(adev->dev, "Failed to get BIF handle\n"); return -EINVAL; } - r = cmn_block->version->funcs->resume(adev); + r = amdgpu_ip_block_resume(cmn_block); if (r) return r; @@ -282,15 +275,10 @@ static int aldebaran_mode2_restore_ip(struct amdgpu_device *adev) adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; - r = adev->ip_blocks[i].version->funcs->resume(adev); - if (r) { - dev_err(adev->dev, - "resume of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); - return r; - } - adev->ip_blocks[i].status.hw = true; + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); + if (r) + return r; } for (i = 0; i < adev->num_ip_blocks; i++) { @@ -304,7 +292,7 @@ static int aldebaran_mode2_restore_ip(struct amdgpu_device *adev) if (adev->ip_blocks[i].version->funcs->late_init) { r = adev->ip_blocks[i].version->funcs->late_init( - (void *)adev); + &adev->ip_blocks[i]); if (r) { dev_err(adev->dev, "late_init of IP block <%s> failed %d after reset\n", @@ -342,6 +330,8 @@ aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, } list_for_each_entry(tmp_adev, reset_device_list, reset_list) { + amdgpu_set_init_level(tmp_adev, + AMDGPU_INIT_LEVEL_RESET_RECOVERY); dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); r = aldebaran_mode2_restore_ip(tmp_adev); @@ -387,6 +377,8 @@ aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, tmp_adev); if (!r) { + amdgpu_set_init_level(tmp_adev, + AMDGPU_INIT_LEVEL_DEFAULT); amdgpu_irq_gpu_reset_resume_helper(tmp_adev); r = amdgpu_ib_ring_tests(tmp_adev); @@ -417,6 +409,7 @@ static struct amdgpu_reset_handler aldebaran_mode2_handler = { static struct amdgpu_reset_handler *aldebaran_rst_handlers[AMDGPU_RESET_MAX_HANDLERS] = { &aldebaran_mode2_handler, + &xgmi_reset_on_init_handler, }; int aldebaran_reset_init(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 9b1e0ede05a452..4653a8d2823a6d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -118,7 +118,7 @@ #define MAX_GPU_INSTANCE 64 -#define GFX_SLICE_PERIOD msecs_to_jiffies(250) +#define GFX_SLICE_PERIOD_MS 250 struct amdgpu_gpu_instance { struct amdgpu_device *adev; @@ -131,10 +131,6 @@ struct amdgpu_mgpu_info { uint32_t num_gpu; uint32_t num_dgpu; uint32_t num_apu; - - /* delayed reset_func for XGMI configuration if necessary */ - struct delayed_work delayed_reset_work; - bool pending_reset; }; enum amdgpu_ss { @@ -303,6 +299,12 @@ extern int amdgpu_wbrf; #define AMDGPU_RESET_VCE (1 << 13) #define AMDGPU_RESET_VCE1 (1 << 14) +/* reset mask */ +#define AMDGPU_RESET_TYPE_FULL (1 << 0) /* full adapter reset, mode1/mode2/BACO/etc. */ +#define AMDGPU_RESET_TYPE_SOFT_RESET (1 << 1) /* IP level soft reset */ +#define AMDGPU_RESET_TYPE_PER_QUEUE (1 << 2) /* per queue */ +#define AMDGPU_RESET_TYPE_PER_PIPE (1 << 3) /* per pipe */ + /* max cursor sizes (in pixels) */ #define CIK_CURSOR_WIDTH 128 #define CIK_CURSOR_HEIGHT 128 @@ -365,8 +367,11 @@ void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev, u64 *flags); int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev, enum amd_ip_block_type block_type); -bool amdgpu_device_ip_is_idle(struct amdgpu_device *adev, +bool amdgpu_device_ip_is_valid(struct amdgpu_device *adev, enum amd_ip_block_type block_type); +int amdgpu_ip_block_suspend(struct amdgpu_ip_block *ip_block); + +int amdgpu_ip_block_resume(struct amdgpu_ip_block *ip_block); #define AMDGPU_MAX_IP_NUM 16 @@ -389,6 +394,7 @@ struct amdgpu_ip_block_version { struct amdgpu_ip_block { struct amdgpu_ip_block_status status; const struct amdgpu_ip_block_version *version; + struct amdgpu_device *adev; }; int amdgpu_device_ip_block_version_cmp(struct amdgpu_device *adev, @@ -563,6 +569,7 @@ enum amd_reset_method { AMD_RESET_METHOD_MODE2, AMD_RESET_METHOD_BACO, AMD_RESET_METHOD_PCI, + AMD_RESET_METHOD_ON_INIT, }; struct amdgpu_video_codec_info { @@ -821,6 +828,25 @@ struct amdgpu_mqd { struct amdgpu_mqd_prop *p); }; +/* + * Custom Init levels could be defined for different situations where a full + * initialization of all hardware blocks are not expected. Sample cases are + * custom init sequences after resume after S0i3/S3, reset on initialization, + * partial reset of blocks etc. Presently, this defines only two levels. Levels + * are described in corresponding struct definitions - amdgpu_init_default, + * amdgpu_init_minimal_xgmi. + */ +enum amdgpu_init_lvl_id { + AMDGPU_INIT_LEVEL_DEFAULT, + AMDGPU_INIT_LEVEL_MINIMAL_XGMI, + AMDGPU_INIT_LEVEL_RESET_RECOVERY, +}; + +struct amdgpu_init_level { + enum amdgpu_init_lvl_id level; + uint32_t hwini_ip_block_mask; +}; + #define AMDGPU_RESET_MAGIC_NUM 64 #define AMDGPU_MAX_DF_PERFMONS 4 struct amdgpu_reset_domain; @@ -1092,8 +1118,6 @@ struct amdgpu_device { bool in_s3; bool in_s4; bool in_s0ix; - /* indicate amdgpu suspension status */ - bool suspend_complete; enum pp_mp1_state mp1_state; struct amdgpu_doorbell_index doorbell_index; @@ -1166,6 +1190,8 @@ struct amdgpu_device { bool enforce_isolation[MAX_XCP]; /* Added this mutex for cleaner shader isolation between GFX and compute processes */ struct mutex enforce_isolation_mutex; + + struct amdgpu_init_level *init_lvl; }; static inline uint32_t amdgpu_ip_version(const struct amdgpu_device *adev, @@ -1261,6 +1287,8 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, int amdgpu_do_asic_reset(struct list_head *device_list_handle, struct amdgpu_reset_context *reset_context); +int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context); + int emu_soc_asic_init(struct amdgpu_device *adev); /* @@ -1443,6 +1471,8 @@ struct dma_fence *amdgpu_device_get_gang(struct amdgpu_device *adev); struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev, struct dma_fence *gang); bool amdgpu_device_has_display_hardware(struct amdgpu_device *adev); +ssize_t amdgpu_get_soft_full_reset_mask(struct amdgpu_ring *ring); +ssize_t amdgpu_show_reset_mask(char *buf, uint32_t supported_reset); /* atpx handler */ #if defined(CONFIG_VGA_SWITCHEROO) @@ -1450,23 +1480,15 @@ void amdgpu_register_atpx_handler(void); void amdgpu_unregister_atpx_handler(void); bool amdgpu_has_atpx_dgpu_power_cntl(void); bool amdgpu_is_atpx_hybrid(void); -bool amdgpu_atpx_dgpu_req_power_for_displays(void); bool amdgpu_has_atpx(void); #else static inline void amdgpu_register_atpx_handler(void) {} static inline void amdgpu_unregister_atpx_handler(void) {} static inline bool amdgpu_has_atpx_dgpu_power_cntl(void) { return false; } static inline bool amdgpu_is_atpx_hybrid(void) { return false; } -static inline bool amdgpu_atpx_dgpu_req_power_for_displays(void) { return false; } static inline bool amdgpu_has_atpx(void) { return false; } #endif -#if defined(CONFIG_VGA_SWITCHEROO) && defined(CONFIG_ACPI) -void *amdgpu_atpx_get_dhandle(void); -#else -static inline void *amdgpu_atpx_get_dhandle(void) { return NULL; } -#endif - /* * KMS */ @@ -1619,4 +1641,6 @@ extern const struct attribute_group amdgpu_vram_mgr_attr_group; extern const struct attribute_group amdgpu_gtt_mgr_attr_group; extern const struct attribute_group amdgpu_flash_attr_group; +void amdgpu_set_init_level(struct amdgpu_device *adev, + enum amdgpu_init_lvl_id lvl); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c index 2ca12717313573..9d6345146495fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c @@ -158,7 +158,7 @@ static int aca_smu_get_valid_aca_banks(struct amdgpu_device *adev, enum aca_smu_ return -EINVAL; } - if (start + count >= max_count) + if (start + count > max_count) return -EINVAL; count = min_t(int, count, max_count); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index bf6c4a0d052524..ec5e0dcf86135c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c @@ -98,9 +98,9 @@ enum { ACP_TILE_DSP2, }; -static int acp_sw_init(void *handle) +static int acp_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->acp.parent = adev->dev; @@ -112,9 +112,9 @@ static int acp_sw_init(void *handle) return 0; } -static int acp_sw_fini(void *handle) +static int acp_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->acp.cgs_device) amdgpu_cgs_destroy_device(adev->acp.cgs_device); @@ -219,10 +219,10 @@ static const struct dmi_system_id acp_quirk_table[] = { /** * acp_hw_init - start and test ACP block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int acp_hw_init(void *handle) +static int acp_hw_init(struct amdgpu_ip_block *ip_block) { int r; u64 acp_base; @@ -230,13 +230,7 @@ static int acp_hw_init(void *handle) u32 count = 0; struct i2s_platform_data *i2s_pdata = NULL; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - const struct amdgpu_ip_block *ip_block = - amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ACP); - - if (!ip_block) - return -EINVAL; + struct amdgpu_device *adev = ip_block->adev; r = amd_acp_hw_init(adev->acp.cgs_device, ip_block->version->major, ip_block->version->minor); @@ -503,14 +497,14 @@ static int acp_hw_init(void *handle) /** * acp_hw_fini - stop the hardware block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int acp_hw_fini(void *handle) +static int acp_hw_fini(struct amdgpu_ip_block *ip_block) { u32 val = 0; u32 count = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* return early if no ACP */ if (!adev->acp.acp_genpd) { @@ -565,9 +559,9 @@ static int acp_hw_fini(void *handle) return 0; } -static int acp_suspend(void *handle) +static int acp_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* power up on suspend */ if (!adev->acp.acp_cell) @@ -575,9 +569,9 @@ static int acp_suspend(void *handle) return 0; } -static int acp_resume(void *handle) +static int acp_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* power down again on resume */ if (!adev->acp.acp_cell) @@ -585,26 +579,11 @@ static int acp_resume(void *handle) return 0; } -static int acp_early_init(void *handle) -{ - return 0; -} - static bool acp_is_idle(void *handle) { return true; } -static int acp_wait_for_idle(void *handle) -{ - return 0; -} - -static int acp_soft_reset(void *handle) -{ - return 0; -} - static int acp_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -624,8 +603,6 @@ static int acp_set_powergating_state(void *handle, static const struct amd_ip_funcs acp_ip_funcs = { .name = "acp_ip", - .early_init = acp_early_init, - .late_init = NULL, .sw_init = acp_sw_init, .sw_fini = acp_sw_fini, .hw_init = acp_hw_init, @@ -633,12 +610,8 @@ static const struct amd_ip_funcs acp_ip_funcs = { .suspend = acp_suspend, .resume = acp_resume, .is_idle = acp_is_idle, - .wait_for_idle = acp_wait_for_idle, - .soft_reset = acp_soft_reset, .set_clockgating_state = acp_set_clockgating_state, .set_powergating_state = acp_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version acp_ip_block = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 7dd55ed57c1d97..b8d4e07d2043ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -800,6 +800,7 @@ int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev, return -EIO; } + kfree(info); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 4f08b153cb66d8..3afcd1e8aa5435 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -834,6 +834,9 @@ int amdgpu_amdkfd_unmap_hiq(struct amdgpu_device *adev, u32 doorbell_off, if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues) return -EINVAL; + if (!kiq_ring->sched.ready || adev->job_hang) + return 0; + ring_funcs = kzalloc(sizeof(*ring_funcs), GFP_KERNEL); if (!ring_funcs) return -ENOMEM; @@ -858,8 +861,14 @@ int amdgpu_amdkfd_unmap_hiq(struct amdgpu_device *adev, u32 doorbell_off, kiq->pmf->kiq_unmap_queues(kiq_ring, ring, RESET_QUEUES, 0, 0); - if (kiq_ring->sched.ready && !adev->job_hang) - r = amdgpu_ring_test_helper(kiq_ring); + /* Submit unmap queue packet */ + amdgpu_ring_commit(kiq_ring); + /* + * Ring test will do a basic scratch register change check. Just run + * this to ensure that unmap queues that is submitted before got + * processed successfully before returning. + */ + r = amdgpu_ring_test_helper(kiq_ring); spin_unlock(&kiq->ring_lock); @@ -889,3 +898,27 @@ int amdgpu_amdkfd_start_sched(struct amdgpu_device *adev, uint32_t node_id) return kgd2kfd_start_sched(adev->kfd.dev, node_id); } + +/* check if there are KFD queues active */ +bool amdgpu_amdkfd_compute_active(struct amdgpu_device *adev, uint32_t node_id) +{ + if (!adev->kfd.init_complete) + return false; + + return kgd2kfd_compute_active(adev->kfd.dev, node_id); +} + +/* Config CGTT_SQ_CLK_CTRL */ +int amdgpu_amdkfd_config_sq_perfmon(struct amdgpu_device *adev, uint32_t xcp_id, + bool core_override_enable, bool reg_override_enable, bool perfmon_override_enable) +{ + int r; + + if (!adev->kfd.init_complete) + return 0; + + r = psp_config_sq_perfmon(&adev->psp, xcp_id, core_override_enable, + reg_override_enable, perfmon_override_enable); + + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index f9d1194484423a..4b80ad860639c7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -266,6 +266,10 @@ int amdgpu_amdkfd_unmap_hiq(struct amdgpu_device *adev, u32 doorbell_off, u32 inst); int amdgpu_amdkfd_start_sched(struct amdgpu_device *adev, uint32_t node_id); int amdgpu_amdkfd_stop_sched(struct amdgpu_device *adev, uint32_t node_id); +int amdgpu_amdkfd_config_sq_perfmon(struct amdgpu_device *adev, uint32_t xcp_id, + bool core_override_enable, bool reg_override_enable, bool perfmon_override_enable); +bool amdgpu_amdkfd_compute_active(struct amdgpu_device *adev, uint32_t node_id); + /* Read user wptr from a specified user address space with page fault * disabled. The memory must be pinned and mapped to the hardware when @@ -428,6 +432,7 @@ int kgd2kfd_check_and_lock_kfd(void); void kgd2kfd_unlock_kfd(void); int kgd2kfd_start_sched(struct kfd_dev *kfd, uint32_t node_id); int kgd2kfd_stop_sched(struct kfd_dev *kfd, uint32_t node_id); +bool kgd2kfd_compute_active(struct kfd_dev *kfd, uint32_t node_id); #else static inline int kgd2kfd_init(void) { @@ -508,5 +513,10 @@ static inline int kgd2kfd_stop_sched(struct kfd_dev *kfd, uint32_t node_id) { return 0; } + +static inline bool kgd2kfd_compute_active(struct kfd_dev *kfd, uint32_t node_id) +{ + return false; +} #endif #endif /* AMDGPU_AMDKFD_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c index 9435af2e6bdc01..9abf29b58ac75a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c @@ -299,7 +299,7 @@ static int suspend_resume_compute_scheduler(struct amdgpu_device *adev, bool sus if (r) goto out; } else { - drm_sched_start(&ring->sched); + drm_sched_start(&ring->sched, 0); } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index 3bc0cbf45bc59a..cc66ebb7bae15f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -944,9 +944,7 @@ static void unlock_spi_csq_mutexes(struct amdgpu_device *adev) * * @adev: Handle of device whose registers are to be read * @queue_idx: Index of queue in the queue-map bit-field - * @wave_cnt: Output parameter updated with number of waves in flight - * @vmid: Output parameter updated with VMID of queue whose wave count - * is being collected + * @queue_cnt: Stores the wave count and doorbell offset for an active queue * @inst: xcc's instance number on a multi-XCC setup */ static void get_wave_count(struct amdgpu_device *adev, int queue_idx, @@ -1133,10 +1131,6 @@ uint64_t kgd_gfx_v9_hqd_get_pq_addr(struct amdgpu_device *adev, uint32_t low, high; uint64_t queue_addr = 0; - if (!adev->debug_exp_resets && - !adev->gfx.num_gfx_rings) - return 0; - kgd_gfx_v9_acquire_queue(adev, pipe_id, queue_id, inst); amdgpu_gfx_rlc_enter_safe_mode(adev, inst); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index fa572ba7f9fc1c..f30548f4c3b3e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2524,11 +2524,14 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni, /* First eviction, stop the queues */ r = kgd2kfd_quiesce_mm(mni->mm, KFD_QUEUE_EVICTION_TRIGGER_USERPTR); - if (r) + + if (r && r != -ESRCH) pr_err("Failed to quiesce KFD\n"); - queue_delayed_work(system_freezable_wq, - &process_info->restore_userptr_work, - msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS)); + + if (r != -ESRCH) + queue_delayed_work(system_freezable_wq, + &process_info->restore_userptr_work, + msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS)); } mutex_unlock(&process_info->notifier_lock); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index 0c8975ac5af9ed..093141ad6ed011 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -1145,8 +1145,8 @@ int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev, return 0; } -void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev, - u32 eng_clock, u32 mem_clock) +int amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev, + u32 eng_clock, u32 mem_clock) { SET_ENGINE_CLOCK_PS_ALLOCATION args; int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings); @@ -1161,8 +1161,8 @@ void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev, if (mem_clock) args.sReserved.ulClock = cpu_to_le32(mem_clock & SET_CLOCK_FREQ_MASK); - amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args, - sizeof(args)); + return amdgpu_atom_execute_table(adev->mode_info.atom_context, index, + (uint32_t *)&args, sizeof(args)); } void amdgpu_atombios_get_default_voltages(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h index 0811474e8fd336..0e16432d9a7256 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.h @@ -163,8 +163,8 @@ int amdgpu_atombios_get_memory_pll_dividers(struct amdgpu_device *adev, bool strobe_mode, struct atom_mpll_param *mpll_param); -void amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev, - u32 eng_clock, u32 mem_clock); +int amdgpu_atombios_set_engine_dram_timings(struct amdgpu_device *adev, + u32 eng_clock, u32 mem_clock); bool amdgpu_atombios_is_voltage_gpio(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 375f0200257977..3893e6fc2f037b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -89,18 +89,6 @@ bool amdgpu_is_atpx_hybrid(void) return amdgpu_atpx_priv.atpx.is_hybrid; } -bool amdgpu_atpx_dgpu_req_power_for_displays(void) -{ - return amdgpu_atpx_priv.atpx.dgpu_req_power_for_displays; -} - -#if defined(CONFIG_ACPI) -void *amdgpu_atpx_get_dhandle(void) -{ - return amdgpu_atpx_priv.dhandle; -} -#endif - /** * amdgpu_atpx_call - call an ATPX method * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index d891ab779ca7f5..5df21529b3b13e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -1801,13 +1801,18 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, if (dma_resv_locking_ctx((*bo)->tbo.base.resv) != &parser->exec.ticket) return -EINVAL; + /* Make sure VRAM is allocated contigiously */ (*bo)->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; - amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains); - for (i = 0; i < (*bo)->placement.num_placement; i++) - (*bo)->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS; - r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx); - if (r) - return r; + if ((*bo)->tbo.resource->mem_type == TTM_PL_VRAM && + !((*bo)->tbo.resource->placement & TTM_PL_FLAG_CONTIGUOUS)) { + + amdgpu_bo_placement_from_domain(*bo, (*bo)->allowed_domains); + for (i = 0; i < (*bo)->placement.num_placement; i++) + (*bo)->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS; + r = ttm_bo_validate(&(*bo)->tbo, &(*bo)->placement, &ctx); + if (r) + return r; + } return amdgpu_ttm_alloc_gart(&(*bo)->tbo); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 9da4414de6177d..a68338cb7b4afb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -2095,6 +2095,11 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev) if (amdgpu_umsch_mm & amdgpu_umsch_mm_fwlog) amdgpu_debugfs_umsch_fwlog_init(adev, &adev->umsch_mm); + amdgpu_debugfs_jpeg_sched_mask_init(adev); + amdgpu_debugfs_gfx_sched_mask_init(adev); + amdgpu_debugfs_compute_sched_mask_init(adev); + amdgpu_debugfs_sdma_sched_mask_init(adev); + amdgpu_ras_debugfs_create_all(adev); amdgpu_rap_debugfs_init(adev); amdgpu_securedisplay_debugfs_init(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index 5ac59b62020cf2..824f9da5b6cea9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -203,6 +203,7 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count, struct amdgpu_coredump_info *coredump = data; struct drm_print_iterator iter; struct amdgpu_vm_fault_info *fault_info; + struct amdgpu_ip_block *ip_block; int ver; iter.data = buffer; @@ -282,13 +283,10 @@ amdgpu_devcoredump_read(char *buffer, loff_t offset, size_t count, /* dump the ip state for each ip */ drm_printf(&p, "IP Dump\n"); for (int i = 0; i < coredump->adev->num_ip_blocks; i++) { - if (coredump->adev->ip_blocks[i].version->funcs->print_ip_state) { - drm_printf(&p, "IP: %s\n", - coredump->adev->ip_blocks[i] - .version->funcs->name); - coredump->adev->ip_blocks[i] - .version->funcs->print_ip_state( - (void *)coredump->adev, &p); + ip_block = &coredump->adev->ip_blocks[i]; + if (ip_block->version->funcs->print_ip_state) { + drm_printf(&p, "IP: %s\n", ip_block->version->funcs->name); + ip_block->version->funcs->print_ip_state(ip_block, &p); drm_printf(&p, "\n"); } } @@ -345,11 +343,10 @@ void amdgpu_coredump(struct amdgpu_device *adev, bool skip_vram_check, coredump->skip_vram_check = skip_vram_check; coredump->reset_vram_lost = vram_lost; - if (job && job->vm) { - struct amdgpu_vm *vm = job->vm; + if (job && job->pasid) { struct amdgpu_task_info *ti; - ti = amdgpu_vm_get_task_info_vm(vm); + ti = amdgpu_vm_get_task_info_pasid(adev, job->pasid); if (ti) { coredump->reset_task_info = *ti; amdgpu_vm_put_task_info(ti); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index c2394c8b4d6b21..cd4fac12083422 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -25,6 +25,8 @@ * Alex Deucher * Jerome Glisse */ + +#include #include #include #include @@ -35,10 +37,9 @@ #include #include -#include #include +#include #include -#include #include #include #include @@ -144,6 +145,59 @@ const char *amdgpu_asic_name[] = { "LAST", }; +#define AMDGPU_IP_BLK_MASK_ALL GENMASK(AMD_IP_BLOCK_TYPE_NUM - 1, 0) +/* + * Default init level where all blocks are expected to be initialized. This is + * the level of initialization expected by default and also after a full reset + * of the device. + */ +struct amdgpu_init_level amdgpu_init_default = { + .level = AMDGPU_INIT_LEVEL_DEFAULT, + .hwini_ip_block_mask = AMDGPU_IP_BLK_MASK_ALL, +}; + +struct amdgpu_init_level amdgpu_init_recovery = { + .level = AMDGPU_INIT_LEVEL_RESET_RECOVERY, + .hwini_ip_block_mask = AMDGPU_IP_BLK_MASK_ALL, +}; + +/* + * Minimal blocks needed to be initialized before a XGMI hive can be reset. This + * is used for cases like reset on initialization where the entire hive needs to + * be reset before first use. + */ +struct amdgpu_init_level amdgpu_init_minimal_xgmi = { + .level = AMDGPU_INIT_LEVEL_MINIMAL_XGMI, + .hwini_ip_block_mask = + BIT(AMD_IP_BLOCK_TYPE_GMC) | BIT(AMD_IP_BLOCK_TYPE_SMC) | + BIT(AMD_IP_BLOCK_TYPE_COMMON) | BIT(AMD_IP_BLOCK_TYPE_IH) | + BIT(AMD_IP_BLOCK_TYPE_PSP) +}; + +static inline bool amdgpu_ip_member_of_hwini(struct amdgpu_device *adev, + enum amd_ip_block_type block) +{ + return (adev->init_lvl->hwini_ip_block_mask & (1U << block)) != 0; +} + +void amdgpu_set_init_level(struct amdgpu_device *adev, + enum amdgpu_init_lvl_id lvl) +{ + switch (lvl) { + case AMDGPU_INIT_LEVEL_MINIMAL_XGMI: + adev->init_lvl = &amdgpu_init_minimal_xgmi; + break; + case AMDGPU_INIT_LEVEL_RESET_RECOVERY: + adev->init_lvl = &amdgpu_init_recovery; + break; + case AMDGPU_INIT_LEVEL_DEFAULT: + fallthrough; + default: + adev->init_lvl = &amdgpu_init_default; + break; + } +} + static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev); /** @@ -227,6 +281,42 @@ void amdgpu_reg_state_sysfs_fini(struct amdgpu_device *adev) sysfs_remove_bin_file(&adev->dev->kobj, &bin_attr_reg_state); } +int amdgpu_ip_block_suspend(struct amdgpu_ip_block *ip_block) +{ + int r; + + if (ip_block->version->funcs->suspend) { + r = ip_block->version->funcs->suspend(ip_block); + if (r) { + dev_err(ip_block->adev->dev, + "suspend of IP block <%s> failed %d\n", + ip_block->version->funcs->name, r); + return r; + } + } + + ip_block->status.hw = false; + return 0; +} + +int amdgpu_ip_block_resume(struct amdgpu_ip_block *ip_block) +{ + int r; + + if (ip_block->version->funcs->resume) { + r = ip_block->version->funcs->resume(ip_block); + if (r) { + dev_err(ip_block->adev->dev, + "resume of IP block <%s> failed %d\n", + ip_block->version->funcs->name, r); + return r; + } + } + + ip_block->status.hw = true; + return 0; +} + /** * DOC: board_info * @@ -327,6 +417,9 @@ bool amdgpu_device_supports_boco(struct drm_device *dev) { struct amdgpu_device *adev = drm_to_adev(dev); + if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) + return false; + if (adev->has_pr3 || ((adev->flags & AMD_IS_PX) && amdgpu_is_atpx_hybrid())) return true; @@ -1655,7 +1748,7 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev) } /* Don't post if we need to reset whole hive on init */ - if (adev->gmc.xgmi.pending_reset) + if (adev->init_lvl->level == AMDGPU_INIT_LEVEL_MINIMAL_XGMI) return false; if (adev->has_hw_reset) { @@ -2159,9 +2252,12 @@ int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev, if (!adev->ip_blocks[i].status.valid) continue; if (adev->ip_blocks[i].version->type == block_type) { - r = adev->ip_blocks[i].version->funcs->wait_for_idle((void *)adev); - if (r) - return r; + if (adev->ip_blocks[i].version->funcs->wait_for_idle) { + r = adev->ip_blocks[i].version->funcs->wait_for_idle( + &adev->ip_blocks[i]); + if (r) + return r; + } break; } } @@ -2170,26 +2266,24 @@ int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev, } /** - * amdgpu_device_ip_is_idle - is the hardware IP idle + * amdgpu_device_ip_is_valid - is the hardware IP enabled * * @adev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * - * Check if the hardware IP is idle or not. - * Returns true if it the IP is idle, false if not. + * Check if the hardware IP is enable or not. + * Returns true if it the IP is enable, false if not. */ -bool amdgpu_device_ip_is_idle(struct amdgpu_device *adev, - enum amd_ip_block_type block_type) +bool amdgpu_device_ip_is_valid(struct amdgpu_device *adev, + enum amd_ip_block_type block_type) { int i; for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; if (adev->ip_blocks[i].version->type == block_type) - return adev->ip_blocks[i].version->funcs->is_idle((void *)adev); + return adev->ip_blocks[i].status.valid; } - return true; + return false; } @@ -2271,6 +2365,8 @@ int amdgpu_device_ip_block_add(struct amdgpu_device *adev, DRM_INFO("add ip block number %d <%s>\n", adev->num_ip_blocks, ip_block_version->funcs->name); + adev->ip_blocks[adev->num_ip_blocks].adev = adev; + adev->ip_blocks[adev->num_ip_blocks++].version = ip_block_version; return 0; @@ -2566,25 +2662,25 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) total = true; for (i = 0; i < adev->num_ip_blocks; i++) { + ip_block = &adev->ip_blocks[i]; + if ((amdgpu_ip_block_mask & (1 << i)) == 0) { DRM_WARN("disabled ip block: %d <%s>\n", i, adev->ip_blocks[i].version->funcs->name); adev->ip_blocks[i].status.valid = false; - } else { - if (adev->ip_blocks[i].version->funcs->early_init) { - r = adev->ip_blocks[i].version->funcs->early_init((void *)adev); - if (r == -ENOENT) { - adev->ip_blocks[i].status.valid = false; - } else if (r) { - DRM_ERROR("early_init of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); - total = false; - } else { - adev->ip_blocks[i].status.valid = true; - } + } else if (ip_block->version->funcs->early_init) { + r = ip_block->version->funcs->early_init(ip_block); + if (r == -ENOENT) { + adev->ip_blocks[i].status.valid = false; + } else if (r) { + DRM_ERROR("early_init of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + total = false; } else { adev->ip_blocks[i].status.valid = true; } + } else { + adev->ip_blocks[i].status.valid = true; } /* get the vbios after the asic_funcs are set up */ if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) { @@ -2633,10 +2729,13 @@ static int amdgpu_device_ip_hw_init_phase1(struct amdgpu_device *adev) continue; if (adev->ip_blocks[i].status.hw) continue; + if (!amdgpu_ip_member_of_hwini( + adev, adev->ip_blocks[i].version->type)) + continue; if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || (amdgpu_sriov_vf(adev) && (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)) || adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) { - r = adev->ip_blocks[i].version->funcs->hw_init(adev); + r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) { DRM_ERROR("hw_init of IP block <%s> failed %d\n", adev->ip_blocks[i].version->funcs->name, r); @@ -2658,7 +2757,10 @@ static int amdgpu_device_ip_hw_init_phase2(struct amdgpu_device *adev) continue; if (adev->ip_blocks[i].status.hw) continue; - r = adev->ip_blocks[i].version->funcs->hw_init(adev); + if (!amdgpu_ip_member_of_hwini( + adev, adev->ip_blocks[i].version->type)) + continue; + r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) { DRM_ERROR("hw_init of IP block <%s> failed %d\n", adev->ip_blocks[i].version->funcs->name, r); @@ -2681,6 +2783,10 @@ static int amdgpu_device_fw_loading(struct amdgpu_device *adev) if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_PSP) continue; + if (!amdgpu_ip_member_of_hwini(adev, + AMD_IP_BLOCK_TYPE_PSP)) + break; + if (!adev->ip_blocks[i].status.sw) continue; @@ -2689,22 +2795,18 @@ static int amdgpu_device_fw_loading(struct amdgpu_device *adev) break; if (amdgpu_in_reset(adev) || adev->in_suspend) { - r = adev->ip_blocks[i].version->funcs->resume(adev); - if (r) { - DRM_ERROR("resume of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); + if (r) return r; - } } else { - r = adev->ip_blocks[i].version->funcs->hw_init(adev); + r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) { DRM_ERROR("hw_init of IP block <%s> failed %d\n", adev->ip_blocks[i].version->funcs->name, r); return r; } + adev->ip_blocks[i].status.hw = true; } - - adev->ip_blocks[i].status.hw = true; break; } } @@ -2786,6 +2888,7 @@ static int amdgpu_device_init_schedulers(struct amdgpu_device *adev) */ static int amdgpu_device_ip_init(struct amdgpu_device *adev) { + bool init_badpage; int i, r; r = amdgpu_ras_init(adev); @@ -2795,17 +2898,23 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; - r = adev->ip_blocks[i].version->funcs->sw_init((void *)adev); - if (r) { - DRM_ERROR("sw_init of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); - goto init_failed; + if (adev->ip_blocks[i].version->funcs->sw_init) { + r = adev->ip_blocks[i].version->funcs->sw_init(&adev->ip_blocks[i]); + if (r) { + DRM_ERROR("sw_init of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + goto init_failed; + } } adev->ip_blocks[i].status.sw = true; + if (!amdgpu_ip_member_of_hwini( + adev, adev->ip_blocks[i].version->type)) + continue; + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) { /* need to do common hw init early so everything is set up for gmc */ - r = adev->ip_blocks[i].version->funcs->hw_init((void *)adev); + r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) { DRM_ERROR("hw_init %d failed %d\n", i, r); goto init_failed; @@ -2822,7 +2931,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) DRM_ERROR("amdgpu_mem_scratch_init failed %d\n", r); goto init_failed; } - r = adev->ip_blocks[i].version->funcs->hw_init((void *)adev); + r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) { DRM_ERROR("hw_init %d failed %d\n", i, r); goto init_failed; @@ -2895,7 +3004,8 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) * Note: theoretically, this should be called before all vram allocations * to protect retired page from abusing */ - r = amdgpu_ras_recovery_init(adev); + init_badpage = (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI); + r = amdgpu_ras_recovery_init(adev, init_badpage); if (r) goto init_failed; @@ -2935,7 +3045,7 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) amdgpu_ttm_set_buffer_funcs_status(adev, true); /* Don't init kfd if whole hive need to be reset during init */ - if (!adev->gmc.xgmi.pending_reset) { + if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) { kgd2kfd_init_zone_device(adev); amdgpu_amdkfd_device_init(adev); } @@ -3135,7 +3245,7 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) if (!adev->ip_blocks[i].status.hw) continue; if (adev->ip_blocks[i].version->funcs->late_init) { - r = adev->ip_blocks[i].version->funcs->late_init((void *)adev); + r = adev->ip_blocks[i].version->funcs->late_init(&adev->ip_blocks[i]); if (r) { DRM_ERROR("late_init of IP block <%s> failed %d\n", adev->ip_blocks[i].version->funcs->name, r); @@ -3151,7 +3261,7 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) return r; } - if (!amdgpu_in_reset(adev)) + if (!amdgpu_reset_in_recovery(adev)) amdgpu_ras_set_error_query_ready(adev, true); amdgpu_device_set_cg_state(adev, AMD_CG_STATE_GATE); @@ -3206,6 +3316,25 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) return 0; } +static void amdgpu_ip_block_hw_fini(struct amdgpu_ip_block *ip_block) +{ + int r; + + if (!ip_block->version->funcs->hw_fini) { + DRM_ERROR("hw_fini of IP block <%s> not defined\n", + ip_block->version->funcs->name); + } else { + r = ip_block->version->funcs->hw_fini(ip_block); + /* XXX handle errors */ + if (r) { + DRM_DEBUG("hw_fini of IP block <%s> failed %d\n", + ip_block->version->funcs->name, r); + } + } + + ip_block->status.hw = false; +} + /** * amdgpu_device_smu_fini_early - smu hw_fini wrapper * @@ -3215,7 +3344,7 @@ static int amdgpu_device_ip_late_init(struct amdgpu_device *adev) */ static void amdgpu_device_smu_fini_early(struct amdgpu_device *adev) { - int i, r; + int i; if (amdgpu_ip_version(adev, GC_HWIP, 0) > IP_VERSION(9, 0, 0)) return; @@ -3224,13 +3353,7 @@ static void amdgpu_device_smu_fini_early(struct amdgpu_device *adev) if (!adev->ip_blocks[i].status.hw) continue; if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) { - r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev); - /* XXX handle errors */ - if (r) { - DRM_DEBUG("hw_fini of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); - } - adev->ip_blocks[i].status.hw = false; + amdgpu_ip_block_hw_fini(&adev->ip_blocks[i]); break; } } @@ -3244,7 +3367,7 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev) if (!adev->ip_blocks[i].version->funcs->early_fini) continue; - r = adev->ip_blocks[i].version->funcs->early_fini((void *)adev); + r = adev->ip_blocks[i].version->funcs->early_fini(&adev->ip_blocks[i]); if (r) { DRM_DEBUG("early_fini of IP block <%s> failed %d\n", adev->ip_blocks[i].version->funcs->name, r); @@ -3263,14 +3386,7 @@ static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev) if (!adev->ip_blocks[i].status.hw) continue; - r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev); - /* XXX handle errors */ - if (r) { - DRM_DEBUG("hw_fini of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); - } - - adev->ip_blocks[i].status.hw = false; + amdgpu_ip_block_hw_fini(&adev->ip_blocks[i]); } if (amdgpu_sriov_vf(adev)) { @@ -3316,12 +3432,13 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) amdgpu_ib_pool_fini(adev); amdgpu_seq64_fini(adev); } - - r = adev->ip_blocks[i].version->funcs->sw_fini((void *)adev); - /* XXX handle errors */ - if (r) { - DRM_DEBUG("sw_fini of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + if (adev->ip_blocks[i].version->funcs->sw_fini) { + r = adev->ip_blocks[i].version->funcs->sw_fini(&adev->ip_blocks[i]); + /* XXX handle errors */ + if (r) { + DRM_DEBUG("sw_fini of IP block <%s> failed %d\n", + adev->ip_blocks[i].version->funcs->name, r); + } } adev->ip_blocks[i].status.sw = false; adev->ip_blocks[i].status.valid = false; @@ -3331,7 +3448,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) if (!adev->ip_blocks[i].status.late_initialized) continue; if (adev->ip_blocks[i].version->funcs->late_fini) - adev->ip_blocks[i].version->funcs->late_fini((void *)adev); + adev->ip_blocks[i].version->funcs->late_fini(&adev->ip_blocks[i]); adev->ip_blocks[i].status.late_initialized = false; } @@ -3403,15 +3520,9 @@ static int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev) continue; /* XXX handle errors */ - r = adev->ip_blocks[i].version->funcs->suspend(adev); - /* XXX handle errors */ - if (r) { - DRM_ERROR("suspend of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_suspend(&adev->ip_blocks[i]); + if (r) return r; - } - - adev->ip_blocks[i].status.hw = false; } return 0; @@ -3449,14 +3560,9 @@ static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev) } /* skip unnecessary suspend if we do not initialize them yet */ - if (adev->gmc.xgmi.pending_reset && - !(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH)) { - adev->ip_blocks[i].status.hw = false; + if (!amdgpu_ip_member_of_hwini( + adev, adev->ip_blocks[i].version->type)) continue; - } /* skip suspend of gfx/mes and psp for S0ix * gfx is in gfxoff state, so on resume it will exit gfxoff just @@ -3490,13 +3596,9 @@ static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev) continue; /* XXX handle errors */ - r = adev->ip_blocks[i].version->funcs->suspend(adev); - /* XXX handle errors */ - if (r) { - DRM_ERROR("suspend of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); - } + r = amdgpu_ip_block_suspend(&adev->ip_blocks[i]); adev->ip_blocks[i].status.hw = false; + /* handle putting the SMC in the appropriate state */ if (!amdgpu_sriov_vf(adev)) { if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) { @@ -3570,10 +3672,12 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev) !block->status.valid) continue; - r = block->version->funcs->hw_init(adev); - DRM_INFO("RE-INIT-early: %s %s\n", block->version->funcs->name, r?"failed":"succeeded"); - if (r) + r = block->version->funcs->hw_init(&adev->ip_blocks[i]); + if (r) { + dev_err(adev->dev, "RE-INIT-early: %s failed\n", + block->version->funcs->name); return r; + } block->status.hw = true; } } @@ -3583,7 +3687,8 @@ static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev) static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev) { - int i, r; + struct amdgpu_ip_block *block; + int i, r = 0; static enum amd_ip_block_type ip_order[] = { AMD_IP_BLOCK_TYPE_SMC, @@ -3598,30 +3703,28 @@ static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev) }; for (i = 0; i < ARRAY_SIZE(ip_order); i++) { - int j; - struct amdgpu_ip_block *block; - - for (j = 0; j < adev->num_ip_blocks; j++) { - block = &adev->ip_blocks[j]; + block = amdgpu_device_ip_get_ip_block(adev, ip_order[i]); - if (block->version->type != ip_order[i] || - !block->status.valid || - block->status.hw) - continue; + if (!block) + continue; - if (block->version->type == AMD_IP_BLOCK_TYPE_SMC) - r = block->version->funcs->resume(adev); - else - r = block->version->funcs->hw_init(adev); + if (block->status.valid && !block->status.hw) { + if (block->version->type == AMD_IP_BLOCK_TYPE_SMC) { + r = amdgpu_ip_block_resume(block); + } else { + r = block->version->funcs->hw_init(block); + } - DRM_INFO("RE-INIT-late: %s %s\n", block->version->funcs->name, r?"failed":"succeeded"); - if (r) - return r; + if (r) { + dev_err(adev->dev, "RE-INIT-late: %s failed\n", + block->version->funcs->name); + break; + } block->status.hw = true; } } - return 0; + return r; } /** @@ -3648,13 +3751,9 @@ static int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev) adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH || (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP && amdgpu_sriov_vf(adev))) { - r = adev->ip_blocks[i].version->funcs->resume(adev); - if (r) { - DRM_ERROR("resume of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); + if (r) return r; - } - adev->ip_blocks[i].status.hw = true; } } @@ -3666,7 +3765,7 @@ static int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev) * * @adev: amdgpu_device pointer * - * First resume function for hardware IPs. The list of all the hardware + * Second resume function for hardware IPs. The list of all the hardware * IPs that make up the asic is walked and the resume callbacks are run for * all blocks except COMMON, GMC, and IH. resume puts the hardware into a * functional state after a suspend and updates the software state as @@ -3684,15 +3783,42 @@ static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev) if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC || adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH || + adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE || adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) continue; - r = adev->ip_blocks[i].version->funcs->resume(adev); - if (r) { - DRM_ERROR("resume of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); + if (r) return r; + } + + return 0; +} + +/** + * amdgpu_device_ip_resume_phase3 - run resume for hardware IPs + * + * @adev: amdgpu_device pointer + * + * Third resume function for hardware IPs. The list of all the hardware + * IPs that make up the asic is walked and the resume callbacks are run for + * all DCE. resume puts the hardware into a functional state after a suspend + * and updates the software state as necessary. This function is also used + * for restoring the GPU after a GPU reset. + * + * Returns 0 on success, negative error code on failure. + */ +static int amdgpu_device_ip_resume_phase3(struct amdgpu_device *adev) +{ + int i, r; + + for (i = 0; i < adev->num_ip_blocks; i++) { + if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw) + continue; + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) { + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); + if (r) + return r; } - adev->ip_blocks[i].status.hw = true; } return 0; @@ -3727,6 +3853,13 @@ static int amdgpu_device_ip_resume(struct amdgpu_device *adev) if (adev->mman.buffer_funcs_ring->sched.ready) amdgpu_ttm_set_buffer_funcs_status(adev, true); + if (r) + return r; + + amdgpu_fence_driver_hw_init(adev); + + r = amdgpu_device_ip_resume_phase3(adev); + return r; } @@ -4149,7 +4282,10 @@ int amdgpu_device_init(struct amdgpu_device *adev, * for throttling interrupt) = 60 seconds. */ ratelimit_state_init(&adev->throttling_logging_rs, (60 - 1) * HZ, 1); + ratelimit_state_init(&adev->virt.ras_telemetry_rs, 5 * HZ, 1); + ratelimit_set_flags(&adev->throttling_logging_rs, RATELIMIT_MSG_ON_RELEASE); + ratelimit_set_flags(&adev->virt.ras_telemetry_rs, RATELIMIT_MSG_ON_RELEASE); /* Registers mapping */ /* TODO: block userspace mapping of io register */ @@ -4193,13 +4329,19 @@ int amdgpu_device_init(struct amdgpu_device *adev, amdgpu_device_set_mcbp(adev); + /* + * By default, use default mode where all blocks are expected to be + * initialized. At present a 'swinit' of blocks is required to be + * completed before the need for a different level is detected. + */ + amdgpu_set_init_level(adev, AMDGPU_INIT_LEVEL_DEFAULT); /* early init functions */ r = amdgpu_device_ip_early_init(adev); if (r) return r; /* Get rid of things like offb */ - r = drm_aperture_remove_conflicting_pci_framebuffers(adev->pdev, &amdgpu_kms_driver); + r = aperture_remove_conflicting_pci_devices(adev->pdev, amdgpu_kms_driver.name); if (r) return r; @@ -4265,20 +4407,8 @@ int amdgpu_device_init(struct amdgpu_device *adev, if (!amdgpu_sriov_vf(adev) && amdgpu_asic_need_reset_on_init(adev)) { if (adev->gmc.xgmi.num_physical_nodes) { dev_info(adev->dev, "Pending hive reset.\n"); - adev->gmc.xgmi.pending_reset = true; - /* Only need to init necessary block for SMU to handle the reset */ - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (!(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC)) { - DRM_DEBUG("IP %s disabled for hw_init.\n", - adev->ip_blocks[i].version->funcs->name); - adev->ip_blocks[i].status.hw = true; - } - } + amdgpu_set_init_level(adev, + AMDGPU_INIT_LEVEL_MINIMAL_XGMI); } else if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) && !amdgpu_device_has_display_hardware(adev)) { r = psp_gpu_reset(adev); @@ -4386,7 +4516,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, /* enable clockgating, etc. after ib tests, etc. since some blocks require * explicit gating rather than handling it automatically. */ - if (!adev->gmc.xgmi.pending_reset) { + if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) { r = amdgpu_device_ip_late_init(adev); if (r) { dev_err(adev->dev, "amdgpu_device_ip_late_init failed\n"); @@ -4436,6 +4566,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, amdgpu_fru_sysfs_init(adev); amdgpu_reg_state_sysfs_init(adev); + amdgpu_xcp_cfg_sysfs_init(adev); if (IS_ENABLED(CONFIG_PERF_EVENTS)) r = amdgpu_pmu_init(adev); @@ -4463,9 +4594,8 @@ int amdgpu_device_init(struct amdgpu_device *adev, if (px) vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain); - if (adev->gmc.xgmi.pending_reset) - queue_delayed_work(system_wq, &mgpu_info.delayed_reset_work, - msecs_to_jiffies(AMDGPU_RESUME_MS)); + if (adev->init_lvl->level == AMDGPU_INIT_LEVEL_MINIMAL_XGMI) + amdgpu_xgmi_reset_on_init(adev); amdgpu_device_check_iommu_direct_map(adev); @@ -4559,6 +4689,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_fru_sysfs_fini(adev); amdgpu_reg_state_sysfs_fini(adev); + amdgpu_xcp_cfg_sysfs_fini(adev); /* disable ras feature must before hw fini */ amdgpu_ras_pre_fini(adev); @@ -4584,8 +4715,8 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) int idx; bool px; - amdgpu_fence_driver_sw_fini(adev); amdgpu_device_ip_fini(adev); + amdgpu_fence_driver_sw_fini(adev); amdgpu_ucode_release(&adev->firmware.gpu_info_fw); adev->accel_working = false; dma_fence_put(rcu_dereference_protected(adev->gang_submit, true)); @@ -4694,7 +4825,7 @@ int amdgpu_device_prepare(struct drm_device *dev) continue; if (!adev->ip_blocks[i].version->funcs->prepare_suspend) continue; - r = adev->ip_blocks[i].version->funcs->prepare_suspend((void *)adev); + r = adev->ip_blocks[i].version->funcs->prepare_suspend(&adev->ip_blocks[i]); if (r) goto unprepare; } @@ -4711,13 +4842,13 @@ int amdgpu_device_prepare(struct drm_device *dev) * amdgpu_device_suspend - initiate device suspend * * @dev: drm dev pointer - * @fbcon : notify the fbdev of suspend + * @notify_clients: notify in-kernel DRM clients * * Puts the hw in the suspend state (all asics). * Returns 0 for success or an error on failure. * Called at driver suspend. */ -int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) +int amdgpu_device_suspend(struct drm_device *dev, bool notify_clients) { struct amdgpu_device *adev = drm_to_adev(dev); int r = 0; @@ -4737,8 +4868,8 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D3)) DRM_WARN("smart shift update failed\n"); - if (fbcon) - drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true); + if (notify_clients) + drm_client_dev_suspend(adev_to_drm(adev), false); cancel_delayed_work_sync(&adev->delayed_init_work); @@ -4773,13 +4904,13 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon) * amdgpu_device_resume - initiate device resume * * @dev: drm dev pointer - * @fbcon : notify the fbdev of resume + * @notify_clients: notify in-kernel DRM clients * * Bring the hw back to operating state (all asics). * Returns 0 for success or an error on failure. * Called at driver resume. */ -int amdgpu_device_resume(struct drm_device *dev, bool fbcon) +int amdgpu_device_resume(struct drm_device *dev, bool notify_clients) { struct amdgpu_device *adev = drm_to_adev(dev); int r = 0; @@ -4809,7 +4940,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r); goto exit; } - amdgpu_fence_driver_hw_init(adev); if (!adev->in_s0ix) { r = amdgpu_amdkfd_resume(adev, adev->in_runpm); @@ -4835,8 +4965,8 @@ int amdgpu_device_resume(struct drm_device *dev, bool fbcon) /* Make sure IB tests flushed */ flush_delayed_work(&adev->delayed_init_work); - if (fbcon) - drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, false); + if (notify_clients) + drm_client_dev_resume(adev_to_drm(adev), false); amdgpu_ras_resume(adev); @@ -4898,7 +5028,8 @@ static bool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev) continue; if (adev->ip_blocks[i].version->funcs->check_soft_reset) adev->ip_blocks[i].status.hang = - adev->ip_blocks[i].version->funcs->check_soft_reset(adev); + adev->ip_blocks[i].version->funcs->check_soft_reset( + &adev->ip_blocks[i]); if (adev->ip_blocks[i].status.hang) { dev_info(adev->dev, "IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name); asic_hang = true; @@ -4927,7 +5058,7 @@ static int amdgpu_device_ip_pre_soft_reset(struct amdgpu_device *adev) continue; if (adev->ip_blocks[i].status.hang && adev->ip_blocks[i].version->funcs->pre_soft_reset) { - r = adev->ip_blocks[i].version->funcs->pre_soft_reset(adev); + r = adev->ip_blocks[i].version->funcs->pre_soft_reset(&adev->ip_blocks[i]); if (r) return r; } @@ -4989,7 +5120,7 @@ static int amdgpu_device_ip_soft_reset(struct amdgpu_device *adev) continue; if (adev->ip_blocks[i].status.hang && adev->ip_blocks[i].version->funcs->soft_reset) { - r = adev->ip_blocks[i].version->funcs->soft_reset(adev); + r = adev->ip_blocks[i].version->funcs->soft_reset(&adev->ip_blocks[i]); if (r) return r; } @@ -5018,7 +5149,7 @@ static int amdgpu_device_ip_post_soft_reset(struct amdgpu_device *adev) continue; if (adev->ip_blocks[i].status.hang && adev->ip_blocks[i].version->funcs->post_soft_reset) - r = adev->ip_blocks[i].version->funcs->post_soft_reset(adev); + r = adev->ip_blocks[i].version->funcs->post_soft_reset(&adev->ip_blocks[i]); if (r) return r; } @@ -5103,6 +5234,9 @@ static int amdgpu_device_reset_sriov(struct amdgpu_device *adev, amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) || amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 0, 3)) amdgpu_ras_resume(adev); + + amdgpu_virt_ras_telemetry_post_reset(adev); + return 0; } @@ -5309,7 +5443,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, for (i = 0; i < tmp_adev->num_ip_blocks; i++) if (tmp_adev->ip_blocks[i].version->funcs->dump_ip_state) tmp_adev->ip_blocks[i].version->funcs - ->dump_ip_state((void *)tmp_adev); + ->dump_ip_state((void *)&tmp_adev->ip_blocks[i]); dev_info(tmp_adev->dev, "Dumping IP State Completed\n"); } @@ -5325,74 +5459,33 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, return r; } -int amdgpu_do_asic_reset(struct list_head *device_list_handle, - struct amdgpu_reset_context *reset_context) +int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context) { - struct amdgpu_device *tmp_adev = NULL; - bool need_full_reset, skip_hw_reset, vram_lost = false; - int r = 0; + struct list_head *device_list_handle; + bool full_reset, vram_lost = false; + struct amdgpu_device *tmp_adev; + int r, init_level; - /* Try reset handler method first */ - tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device, - reset_list); + device_list_handle = reset_context->reset_device_list; - reset_context->reset_device_list = device_list_handle; - r = amdgpu_reset_perform_reset(tmp_adev, reset_context); - /* If reset handler not implemented, continue; otherwise return */ - if (r == -EOPNOTSUPP) - r = 0; - else - return r; + if (!device_list_handle) + return -EINVAL; - /* Reset handler not implemented, use the default method */ - need_full_reset = - test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); - skip_hw_reset = test_bit(AMDGPU_SKIP_HW_RESET, &reset_context->flags); + full_reset = test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); - /* - * ASIC reset has to be done on all XGMI hive nodes ASAP - * to allow proper links negotiation in FW (within 1 sec) + /** + * If it's reset on init, it's default init level, otherwise keep level + * as recovery level. */ - if (!skip_hw_reset && need_full_reset) { - list_for_each_entry(tmp_adev, device_list_handle, reset_list) { - /* For XGMI run all resets in parallel to speed up the process */ - if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { - tmp_adev->gmc.xgmi.pending_reset = false; - if (!queue_work(system_unbound_wq, &tmp_adev->xgmi_reset_work)) - r = -EALREADY; - } else - r = amdgpu_asic_reset(tmp_adev); - - if (r) { - dev_err(tmp_adev->dev, "ASIC reset failed with error, %d for drm dev, %s", - r, adev_to_drm(tmp_adev)->unique); - goto out; - } - } - - /* For XGMI wait for all resets to complete before proceed */ - if (!r) { - list_for_each_entry(tmp_adev, device_list_handle, reset_list) { - if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { - flush_work(&tmp_adev->xgmi_reset_work); - r = tmp_adev->asic_reset_res; - if (r) - break; - } - } - } - } - - if (!r && amdgpu_ras_intr_triggered()) { - list_for_each_entry(tmp_adev, device_list_handle, reset_list) { - amdgpu_ras_reset_error_count(tmp_adev, AMDGPU_RAS_BLOCK__MMHUB); - } - - amdgpu_ras_intr_cleared(); - } + if (reset_context->method == AMD_RESET_METHOD_ON_INIT) + init_level = AMDGPU_INIT_LEVEL_DEFAULT; + else + init_level = AMDGPU_INIT_LEVEL_RESET_RECOVERY; + r = 0; list_for_each_entry(tmp_adev, device_list_handle, reset_list) { - if (need_full_reset) { + amdgpu_set_init_level(tmp_adev, init_level); + if (full_reset) { /* post card */ amdgpu_ras_set_fed(tmp_adev, false); r = amdgpu_device_asic_init(tmp_adev); @@ -5431,6 +5524,10 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, if (tmp_adev->mman.buffer_funcs_ring->sched.ready) amdgpu_ttm_set_buffer_funcs_status(tmp_adev, true); + r = amdgpu_device_ip_resume_phase3(tmp_adev); + if (r) + goto out; + if (vram_lost) amdgpu_device_fill_reset_magic(tmp_adev); @@ -5448,7 +5545,7 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, if (r) goto out; - drm_fb_helper_set_suspend_unlocked(adev_to_drm(tmp_adev)->fb_helper, false); + drm_client_dev_resume(adev_to_drm(tmp_adev), false); /* * The GPU enters bad state once faulty pages @@ -5478,11 +5575,13 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, out: if (!r) { + /* IP init is complete now, set level as default */ + amdgpu_set_init_level(tmp_adev, + AMDGPU_INIT_LEVEL_DEFAULT); amdgpu_irq_gpu_reset_resume_helper(tmp_adev); r = amdgpu_ib_ring_tests(tmp_adev); if (r) { dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r); - need_full_reset = true; r = -EAGAIN; goto end; } @@ -5493,10 +5592,85 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, } end: - if (need_full_reset) + return r; +} + +int amdgpu_do_asic_reset(struct list_head *device_list_handle, + struct amdgpu_reset_context *reset_context) +{ + struct amdgpu_device *tmp_adev = NULL; + bool need_full_reset, skip_hw_reset; + int r = 0; + + /* Try reset handler method first */ + tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device, + reset_list); + + reset_context->reset_device_list = device_list_handle; + r = amdgpu_reset_perform_reset(tmp_adev, reset_context); + /* If reset handler not implemented, continue; otherwise return */ + if (r == -EOPNOTSUPP) + r = 0; + else + return r; + + /* Reset handler not implemented, use the default method */ + need_full_reset = + test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); + skip_hw_reset = test_bit(AMDGPU_SKIP_HW_RESET, &reset_context->flags); + + /* + * ASIC reset has to be done on all XGMI hive nodes ASAP + * to allow proper links negotiation in FW (within 1 sec) + */ + if (!skip_hw_reset && need_full_reset) { + list_for_each_entry(tmp_adev, device_list_handle, reset_list) { + /* For XGMI run all resets in parallel to speed up the process */ + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { + if (!queue_work(system_unbound_wq, + &tmp_adev->xgmi_reset_work)) + r = -EALREADY; + } else + r = amdgpu_asic_reset(tmp_adev); + + if (r) { + dev_err(tmp_adev->dev, + "ASIC reset failed with error, %d for drm dev, %s", + r, adev_to_drm(tmp_adev)->unique); + goto out; + } + } + + /* For XGMI wait for all resets to complete before proceed */ + if (!r) { + list_for_each_entry(tmp_adev, device_list_handle, + reset_list) { + if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { + flush_work(&tmp_adev->xgmi_reset_work); + r = tmp_adev->asic_reset_res; + if (r) + break; + } + } + } + } + + if (!r && amdgpu_ras_intr_triggered()) { + list_for_each_entry(tmp_adev, device_list_handle, reset_list) { + amdgpu_ras_reset_error_count(tmp_adev, + AMDGPU_RAS_BLOCK__MMHUB); + } + + amdgpu_ras_intr_cleared(); + } + + r = amdgpu_device_reinit_after_reset(reset_context); + if (r == -EAGAIN) set_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); else clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); + +out: return r; } @@ -5734,7 +5908,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, */ amdgpu_unregister_gpu_instance(tmp_adev); - drm_fb_helper_set_suspend_unlocked(adev_to_drm(tmp_adev)->fb_helper, true); + drm_client_dev_suspend(adev_to_drm(tmp_adev), false); /* disable ras on ALL IPs */ if (!need_emergency_restart && @@ -5824,7 +5998,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, if (!amdgpu_ring_sched_ready(ring)) continue; - drm_sched_start(&ring->sched); + drm_sched_start(&ring->sched, 0); } if (!drm_drv_uses_atomic_modeset(adev_to_drm(tmp_adev)) && !job_signaled) @@ -6092,6 +6266,9 @@ bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, bool p2p_access = !adev->gmc.xgmi.connected_to_cpu && !(pci_p2pdma_distance(adev->pdev, peer_adev->dev, false) < 0); + if (!p2p_access) + dev_info(adev->dev, "PCIe P2P access from peer device %s is not supported by the chipset\n", + pci_name(peer_adev->pdev)); bool is_large_bar = adev->gmc.visible_vram_size && adev->gmc.real_vram_size == adev->gmc.visible_vram_size; @@ -6331,7 +6508,7 @@ void amdgpu_pci_resume(struct pci_dev *pdev) if (!amdgpu_ring_sched_ready(ring)) continue; - drm_sched_start(&ring->sched); + drm_sched_start(&ring->sched, 0); } amdgpu_device_unset_mp1_state(adev); @@ -6344,6 +6521,9 @@ bool amdgpu_device_cache_pci_state(struct pci_dev *pdev) struct amdgpu_device *adev = drm_to_adev(dev); int r; + if (amdgpu_sriov_vf(adev)) + return false; + r = pci_save_state(pdev); if (!r) { kfree(adev->pci_state); @@ -6604,3 +6784,47 @@ uint32_t amdgpu_device_wait_on_rreg(struct amdgpu_device *adev, } return ret; } + +ssize_t amdgpu_get_soft_full_reset_mask(struct amdgpu_ring *ring) +{ + ssize_t size = 0; + + if (!ring || !ring->adev) + return size; + + if (amdgpu_device_should_recover_gpu(ring->adev)) + size |= AMDGPU_RESET_TYPE_FULL; + + if (unlikely(!ring->adev->debug_disable_soft_recovery) && + !amdgpu_sriov_vf(ring->adev) && ring->funcs->soft_recovery) + size |= AMDGPU_RESET_TYPE_SOFT_RESET; + + return size; +} + +ssize_t amdgpu_show_reset_mask(char *buf, uint32_t supported_reset) +{ + ssize_t size = 0; + + if (supported_reset == 0) { + size += sysfs_emit_at(buf, size, "unsupported"); + size += sysfs_emit_at(buf, size, "\n"); + return size; + + } + + if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RESET) + size += sysfs_emit_at(buf, size, "soft "); + + if (supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE) + size += sysfs_emit_at(buf, size, "queue "); + + if (supported_reset & AMDGPU_RESET_TYPE_PER_PIPE) + size += sysfs_emit_at(buf, size, "pipe "); + + if (supported_reset & AMDGPU_RESET_TYPE_FULL) + size += sysfs_emit_at(buf, size, "full "); + + size += sysfs_emit_at(buf, size, "\n"); + return size; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 4bd61c169ca8d4..1040204ac8b97c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -1723,45 +1723,85 @@ union nps_info { struct nps_info_v1_0 v1; }; +static int amdgpu_discovery_refresh_nps_info(struct amdgpu_device *adev, + union nps_info *nps_data) +{ + uint64_t vram_size, pos, offset; + struct nps_info_header *nhdr; + struct binary_header bhdr; + uint16_t checksum; + + vram_size = (uint64_t)RREG32(mmRCC_CONFIG_MEMSIZE) << 20; + pos = vram_size - DISCOVERY_TMR_OFFSET; + amdgpu_device_vram_access(adev, pos, &bhdr, sizeof(bhdr), false); + + offset = le16_to_cpu(bhdr.table_list[NPS_INFO].offset); + checksum = le16_to_cpu(bhdr.table_list[NPS_INFO].checksum); + + amdgpu_device_vram_access(adev, (pos + offset), nps_data, + sizeof(*nps_data), false); + + nhdr = (struct nps_info_header *)(nps_data); + if (!amdgpu_discovery_verify_checksum((uint8_t *)nps_data, + le32_to_cpu(nhdr->size_bytes), + checksum)) { + dev_err(adev->dev, "nps data refresh, checksum mismatch\n"); + return -EINVAL; + } + + return 0; +} + int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev, uint32_t *nps_type, struct amdgpu_gmc_memrange **ranges, - int *range_cnt) + int *range_cnt, bool refresh) { struct amdgpu_gmc_memrange *mem_ranges; struct binary_header *bhdr; union nps_info *nps_info; + union nps_info nps_data; u16 offset; - int i; + int i, r; if (!nps_type || !range_cnt || !ranges) return -EINVAL; - if (!adev->mman.discovery_bin) { - dev_err(adev->dev, - "fetch mem range failed, ip discovery uninitialized\n"); - return -EINVAL; - } + if (refresh) { + r = amdgpu_discovery_refresh_nps_info(adev, &nps_data); + if (r) + return r; + nps_info = &nps_data; + } else { + if (!adev->mman.discovery_bin) { + dev_err(adev->dev, + "fetch mem range failed, ip discovery uninitialized\n"); + return -EINVAL; + } - bhdr = (struct binary_header *)adev->mman.discovery_bin; - offset = le16_to_cpu(bhdr->table_list[NPS_INFO].offset); + bhdr = (struct binary_header *)adev->mman.discovery_bin; + offset = le16_to_cpu(bhdr->table_list[NPS_INFO].offset); - if (!offset) - return -ENOENT; + if (!offset) + return -ENOENT; - /* If verification fails, return as if NPS table doesn't exist */ - if (amdgpu_discovery_verify_npsinfo(adev, bhdr)) - return -ENOENT; + /* If verification fails, return as if NPS table doesn't exist */ + if (amdgpu_discovery_verify_npsinfo(adev, bhdr)) + return -ENOENT; - nps_info = (union nps_info *)(adev->mman.discovery_bin + offset); + nps_info = + (union nps_info *)(adev->mman.discovery_bin + offset); + } switch (le16_to_cpu(nps_info->v1.header.version_major)) { case 1: + mem_ranges = kvcalloc(nps_info->v1.count, + sizeof(*mem_ranges), + GFP_KERNEL); + if (!mem_ranges) + return -ENOMEM; *nps_type = nps_info->v1.nps_type; *range_cnt = nps_info->v1.count; - mem_ranges = kvzalloc( - *range_cnt * sizeof(struct amdgpu_gmc_memrange), - GFP_KERNEL); for (i = 0; i < *range_cnt; i++) { mem_ranges[i].base_address = nps_info->v1.instance_info[i].base_address; @@ -2492,6 +2532,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[GC_HWIP][0] = IP_VERSION(9, 2, 2); adev->ip_versions[UVD_HWIP][0] = IP_VERSION(1, 0, 1); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 1); + adev->ip_versions[ISP_HWIP][0] = IP_VERSION(2, 0, 0); } else { adev->ip_versions[MMHUB_HWIP][0] = IP_VERSION(9, 1, 0); adev->ip_versions[ATHUB_HWIP][0] = IP_VERSION(9, 1, 0); @@ -2508,6 +2549,7 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) adev->ip_versions[GC_HWIP][0] = IP_VERSION(9, 1, 0); adev->ip_versions[UVD_HWIP][0] = IP_VERSION(1, 0, 0); adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0); + adev->ip_versions[ISP_HWIP][0] = IP_VERSION(2, 0, 0); } break; case CHIP_VEGA20: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h index f5d36525ec3efa..b44d56465c5b90 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h @@ -33,6 +33,6 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev); int amdgpu_discovery_get_nps_info(struct amdgpu_device *adev, uint32_t *nps_type, struct amdgpu_gmc_memrange **ranges, - int *range_cnt); + int *range_cnt, bool refresh); #endif /* __AMDGPU_DISCOVERY__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 81d9877c87357d..38686203bea630 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -231,8 +232,6 @@ int amdgpu_wbrf = -1; int amdgpu_damage_clips = -1; /* auto */ int amdgpu_umsch_mm_fwlog; -static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); - DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, "DRM_UT_CORE", "DRM_UT_DRIVER", @@ -247,9 +246,6 @@ DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, struct amdgpu_mgpu_info mgpu_info = { .mutex = __MUTEX_INITIALIZER(mgpu_info.mutex), - .delayed_reset_work = __DELAYED_WORK_INITIALIZER( - mgpu_info.delayed_reset_work, - amdgpu_drv_delayed_reset_work_handler, 0), }; int amdgpu_ras_enable = -1; uint amdgpu_ras_mask = 0xffffffff; @@ -892,7 +888,7 @@ module_param_named(visualconfirm, amdgpu_dc_visual_confirm, uint, 0444); * the ABM algorithm, with 1 being the least reduction and 4 being the most * reduction. * - * Defaults to -1, or disabled. Userspace can only override this level after + * Defaults to -1, or auto. Userspace can only override this level after * boot if it's set to auto. */ int amdgpu_dm_abm_level = -1; @@ -2365,11 +2361,15 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, */ if (adev->mode_info.mode_config_initialized && !list_empty(&adev_to_drm(adev)->mode_config.connector_list)) { + const struct drm_format_info *format; + /* select 8 bpp console on low vram cards */ if (adev->gmc.real_vram_size <= (32*1024*1024)) - drm_fbdev_ttm_setup(adev_to_drm(adev), 8); + format = drm_format_info(DRM_FORMAT_C8); else - drm_fbdev_ttm_setup(adev_to_drm(adev), 32); + format = NULL; + + drm_client_setup(adev_to_drm(adev), format); } ret = amdgpu_debugfs_init(adev); @@ -2434,6 +2434,7 @@ amdgpu_pci_remove(struct pci_dev *pdev) struct amdgpu_device *adev = drm_to_adev(dev); amdgpu_xcp_dev_unplug(adev); + amdgpu_gmc_prepare_nps_mode_change(adev); drm_dev_unplug(dev); if (adev->pm.rpm_mode != AMDGPU_RUNPM_NONE) { @@ -2472,82 +2473,6 @@ amdgpu_pci_shutdown(struct pci_dev *pdev) adev->mp1_state = PP_MP1_STATE_NONE; } -/** - * amdgpu_drv_delayed_reset_work_handler - work handler for reset - * - * @work: work_struct. - */ -static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work) -{ - struct list_head device_list; - struct amdgpu_device *adev; - int i, r; - struct amdgpu_reset_context reset_context; - - memset(&reset_context, 0, sizeof(reset_context)); - - mutex_lock(&mgpu_info.mutex); - if (mgpu_info.pending_reset == true) { - mutex_unlock(&mgpu_info.mutex); - return; - } - mgpu_info.pending_reset = true; - mutex_unlock(&mgpu_info.mutex); - - /* Use a common context, just need to make sure full reset is done */ - reset_context.method = AMD_RESET_METHOD_NONE; - set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - - for (i = 0; i < mgpu_info.num_dgpu; i++) { - adev = mgpu_info.gpu_ins[i].adev; - reset_context.reset_req_dev = adev; - r = amdgpu_device_pre_asic_reset(adev, &reset_context); - if (r) { - dev_err(adev->dev, "GPU pre asic reset failed with err, %d for drm dev, %s ", - r, adev_to_drm(adev)->unique); - } - if (!queue_work(system_unbound_wq, &adev->xgmi_reset_work)) - r = -EALREADY; - } - for (i = 0; i < mgpu_info.num_dgpu; i++) { - adev = mgpu_info.gpu_ins[i].adev; - flush_work(&adev->xgmi_reset_work); - adev->gmc.xgmi.pending_reset = false; - } - - /* reset function will rebuild the xgmi hive info , clear it now */ - for (i = 0; i < mgpu_info.num_dgpu; i++) - amdgpu_xgmi_remove_device(mgpu_info.gpu_ins[i].adev); - - INIT_LIST_HEAD(&device_list); - - for (i = 0; i < mgpu_info.num_dgpu; i++) - list_add_tail(&mgpu_info.gpu_ins[i].adev->reset_list, &device_list); - - /* unregister the GPU first, reset function will add them back */ - list_for_each_entry(adev, &device_list, reset_list) - amdgpu_unregister_gpu_instance(adev); - - /* Use a common context, just need to make sure full reset is done */ - set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags); - set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags); - r = amdgpu_do_asic_reset(&device_list, &reset_context); - - if (r) { - DRM_ERROR("reinit gpus failure"); - return; - } - for (i = 0; i < mgpu_info.num_dgpu; i++) { - adev = mgpu_info.gpu_ins[i].adev; - if (!adev->kfd.init_complete) { - kgd2kfd_init_zone_device(adev); - amdgpu_amdkfd_device_init(adev); - amdgpu_amdkfd_drm_client_create(adev); - } - amdgpu_ttm_set_buffer_funcs_status(adev, true); - } -} - static int amdgpu_pmops_prepare(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); @@ -2580,7 +2505,6 @@ static int amdgpu_pmops_suspend(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(drm_dev); - adev->suspend_complete = false; if (amdgpu_acpi_is_s0ix_active(adev)) adev->in_s0ix = true; else if (amdgpu_acpi_is_s3_active(adev)) @@ -2595,7 +2519,6 @@ static int amdgpu_pmops_suspend_noirq(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(drm_dev); - adev->suspend_complete = true; if (amdgpu_acpi_should_gpu_reset(adev)) return amdgpu_asic_reset(adev); @@ -2982,6 +2905,7 @@ static const struct drm_driver amdgpu_kms_driver = { .num_ioctls = ARRAY_SIZE(amdgpu_ioctls_kms), .dumb_create = amdgpu_mode_dumb_create, .dumb_map_offset = amdgpu_mode_dumb_mmap, + DRM_FBDEV_TTM_DRIVER_OPS, .fops = &amdgpu_driver_kms_fops, .release = &amdgpu_driver_release_kms, #ifdef CONFIG_PROC_FS @@ -3008,6 +2932,7 @@ const struct drm_driver amdgpu_partition_driver = { .num_ioctls = ARRAY_SIZE(amdgpu_ioctls_kms), .dumb_create = amdgpu_mode_dumb_create, .dumb_map_offset = amdgpu_mode_dumb_mmap, + DRM_FBDEV_TTM_DRIVER_OPS, .fops = &amdgpu_driver_kms_fops, .release = &amdgpu_driver_release_kms, @@ -3068,6 +2993,12 @@ static int __init amdgpu_init(void) /* Ignore KFD init failures. Normal when CONFIG_HSA_AMD is not set. */ amdgpu_amdkfd_init(); + if (amdgpu_pp_feature_mask & PP_OVERDRIVE_MASK) { + add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); + pr_crit("Overdrive is enabled, please disable it before " + "reporting any bugs unrelated to overdrive.\n"); + } + /* let modprobe override vga console setting */ return pci_register_driver(&amdgpu_kms_pci_driver); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c index 35fee3e8cde2b1..8cd69836dd9939 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eeprom.c @@ -200,7 +200,7 @@ static int amdgpu_eeprom_xfer(struct i2c_adapter *i2c_adap, u32 eeprom_addr, dev_err_ratelimited(&i2c_adap->dev, "maddr:0x%04X size:0x%02X:quirk max_%s_len must be > %d", eeprom_addr, buf_size, - read ? "read" : "write", EEPROM_OFFSET_SIZE); + str_read_write(read), EEPROM_OFFSET_SIZE); return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c index c7df7fa3459f12..df2cf5c3392554 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fdinfo.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "amdgpu.h" #include "amdgpu_vm.h" @@ -59,18 +60,25 @@ void amdgpu_show_fdinfo(struct drm_printer *p, struct drm_file *file) struct amdgpu_fpriv *fpriv = file->driver_priv; struct amdgpu_vm *vm = &fpriv->vm; - struct amdgpu_mem_stats stats; + struct amdgpu_mem_stats stats[__AMDGPU_PL_LAST + 1] = { }; ktime_t usage[AMDGPU_HW_IP_NUM]; - unsigned int hw_ip; + const char *pl_name[] = { + [TTM_PL_VRAM] = "vram", + [TTM_PL_TT] = "gtt", + [TTM_PL_SYSTEM] = "cpu", + [AMDGPU_PL_GDS] = "gds", + [AMDGPU_PL_GWS] = "gws", + [AMDGPU_PL_OA] = "oa", + [AMDGPU_PL_DOORBELL] = "doorbell", + }; + unsigned int hw_ip, i; int ret; - memset(&stats, 0, sizeof(stats)); - ret = amdgpu_bo_reserve(vm->root.bo, false); if (ret) return; - amdgpu_vm_get_memory(vm, &stats); + amdgpu_vm_get_memory(vm, stats, ARRAY_SIZE(stats)); amdgpu_bo_unreserve(vm->root.bo); amdgpu_ctx_mgr_usage(&fpriv->ctx_mgr, usage); @@ -82,24 +90,33 @@ void amdgpu_show_fdinfo(struct drm_printer *p, struct drm_file *file) */ drm_printf(p, "pasid:\t%u\n", fpriv->vm.pasid); - drm_printf(p, "drm-memory-vram:\t%llu KiB\n", stats.vram/1024UL); - drm_printf(p, "drm-memory-gtt: \t%llu KiB\n", stats.gtt/1024UL); - drm_printf(p, "drm-memory-cpu: \t%llu KiB\n", stats.cpu/1024UL); - drm_printf(p, "amd-memory-visible-vram:\t%llu KiB\n", - stats.visible_vram/1024UL); + + for (i = 0; i < ARRAY_SIZE(pl_name); i++) { + if (!pl_name[i]) + continue; + + drm_print_memory_stats(p, + &stats[i].drm, + DRM_GEM_OBJECT_RESIDENT | + DRM_GEM_OBJECT_PURGEABLE, + pl_name[i]); + } + + /* Legacy amdgpu keys, alias to drm-resident-memory-: */ + drm_printf(p, "drm-memory-vram:\t%llu KiB\n", + stats[TTM_PL_VRAM].drm.resident/1024UL); + drm_printf(p, "drm-memory-gtt: \t%llu KiB\n", + stats[TTM_PL_TT].drm.resident/1024UL); + drm_printf(p, "drm-memory-cpu: \t%llu KiB\n", + stats[TTM_PL_SYSTEM].drm.resident/1024UL); + + /* Amdgpu specific memory accounting keys: */ drm_printf(p, "amd-evicted-vram:\t%llu KiB\n", - stats.evicted_vram/1024UL); - drm_printf(p, "amd-evicted-visible-vram:\t%llu KiB\n", - stats.evicted_visible_vram/1024UL); + stats[TTM_PL_VRAM].evicted/1024UL); drm_printf(p, "amd-requested-vram:\t%llu KiB\n", - stats.requested_vram/1024UL); - drm_printf(p, "amd-requested-visible-vram:\t%llu KiB\n", - stats.requested_visible_vram/1024UL); + stats[TTM_PL_VRAM].requested/1024UL); drm_printf(p, "amd-requested-gtt:\t%llu KiB\n", - stats.requested_gtt/1024UL); - drm_printf(p, "drm-shared-vram:\t%llu KiB\n", stats.vram_shared/1024UL); - drm_printf(p, "drm-shared-gtt:\t%llu KiB\n", stats.gtt_shared/1024UL); - drm_printf(p, "drm-shared-cpu:\t%llu KiB\n", stats.cpu_shared/1024UL); + stats[TTM_PL_TT].requested/1024UL); for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { if (!usage[hw_ip]) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 256b95232de541..b2033f8352f50e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -78,8 +78,9 @@ static int amdgpu_gart_dummy_page_init(struct amdgpu_device *adev) if (adev->dummy_page_addr) return 0; - adev->dummy_page_addr = dma_map_page(&adev->pdev->dev, dummy_page, 0, - PAGE_SIZE, DMA_BIDIRECTIONAL); + adev->dummy_page_addr = dma_map_page_attrs(&adev->pdev->dev, dummy_page, 0, + PAGE_SIZE, DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); if (dma_mapping_error(&adev->pdev->dev, adev->dummy_page_addr)) { dev_err(&adev->pdev->dev, "Failed to DMA MAP the dummy page\n"); adev->dummy_page_addr = 0; @@ -99,8 +100,9 @@ void amdgpu_gart_dummy_page_fini(struct amdgpu_device *adev) { if (!adev->dummy_page_addr) return; - dma_unmap_page(&adev->pdev->dev, adev->dummy_page_addr, PAGE_SIZE, - DMA_BIDIRECTIONAL); + dma_unmap_page_attrs(&adev->pdev->dev, adev->dummy_page_addr, PAGE_SIZE, + DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); adev->dummy_page_addr = 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index f1ffab5a1eaed9..69a6b6dba0a540 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -87,16 +87,6 @@ int amdgpu_gfx_me_queue_to_bit(struct amdgpu_device *adev, return bit; } -void amdgpu_gfx_bit_to_me_queue(struct amdgpu_device *adev, int bit, - int *me, int *pipe, int *queue) -{ - *queue = bit % adev->gfx.me.num_queue_per_pipe; - *pipe = (bit / adev->gfx.me.num_queue_per_pipe) - % adev->gfx.me.num_pipe_per_me; - *me = (bit / adev->gfx.me.num_queue_per_pipe) - / adev->gfx.me.num_pipe_per_me; -} - bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev, int me, int pipe, int queue) { @@ -415,7 +405,7 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, } /* prepare MQD backup */ - kiq->mqd_backup = kmalloc(mqd_size, GFP_KERNEL); + kiq->mqd_backup = kzalloc(mqd_size, GFP_KERNEL); if (!kiq->mqd_backup) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); @@ -438,7 +428,7 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, ring->mqd_size = mqd_size; /* prepare MQD backup */ - adev->gfx.me.mqd_backup[i] = kmalloc(mqd_size, GFP_KERNEL); + adev->gfx.me.mqd_backup[i] = kzalloc(mqd_size, GFP_KERNEL); if (!adev->gfx.me.mqd_backup[i]) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); return -ENOMEM; @@ -462,7 +452,7 @@ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, ring->mqd_size = mqd_size; /* prepare MQD backup */ - adev->gfx.mec.mqd_backup[j] = kmalloc(mqd_size, GFP_KERNEL); + adev->gfx.mec.mqd_backup[j] = kzalloc(mqd_size, GFP_KERNEL); if (!adev->gfx.mec.mqd_backup[j]) { dev_warn(adev->dev, "no memory to create MQD backup for ring %s\n", ring->name); return -ENOMEM; @@ -525,6 +515,9 @@ int amdgpu_gfx_disable_kcq(struct amdgpu_device *adev, int xcc_id) if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues) return -EINVAL; + if (!kiq_ring->sched.ready || adev->job_hang || amdgpu_in_reset(adev)) + return 0; + spin_lock(&kiq->ring_lock); if (amdgpu_ring_alloc(kiq_ring, kiq->pmf->unmap_queues_size * adev->gfx.num_compute_rings)) { @@ -538,20 +531,15 @@ int amdgpu_gfx_disable_kcq(struct amdgpu_device *adev, int xcc_id) &adev->gfx.compute_ring[j], RESET_QUEUES, 0, 0); } - - /** - * This is workaround: only skip kiq_ring test - * during ras recovery in suspend stage for gfx9.4.3 + /* Submit unmap queue packet */ + amdgpu_ring_commit(kiq_ring); + /* + * Ring test will do a basic scratch register change check. Just run + * this to ensure that unmap queues that is submitted before got + * processed successfully before returning. */ - if ((amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) || - amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4)) && - amdgpu_ras_in_recovery(adev)) { - spin_unlock(&kiq->ring_lock); - return 0; - } + r = amdgpu_ring_test_helper(kiq_ring); - if (kiq_ring->sched.ready && !adev->job_hang) - r = amdgpu_ring_test_helper(kiq_ring); spin_unlock(&kiq->ring_lock); return r; @@ -579,8 +567,11 @@ int amdgpu_gfx_disable_kgq(struct amdgpu_device *adev, int xcc_id) if (!kiq->pmf || !kiq->pmf->kiq_unmap_queues) return -EINVAL; - spin_lock(&kiq->ring_lock); + if (!adev->gfx.kiq[0].ring.sched.ready || adev->job_hang) + return 0; + if (amdgpu_gfx_is_master_xcc(adev, xcc_id)) { + spin_lock(&kiq->ring_lock); if (amdgpu_ring_alloc(kiq_ring, kiq->pmf->unmap_queues_size * adev->gfx.num_gfx_rings)) { spin_unlock(&kiq->ring_lock); @@ -593,11 +584,17 @@ int amdgpu_gfx_disable_kgq(struct amdgpu_device *adev, int xcc_id) &adev->gfx.gfx_ring[j], PREEMPT_QUEUES, 0, 0); } - } + /* Submit unmap queue packet */ + amdgpu_ring_commit(kiq_ring); - if (adev->gfx.kiq[0].ring.sched.ready && !adev->job_hang) + /* + * Ring test will do a basic scratch register change check. + * Just run this to ensure that unmap queues that is submitted + * before got processed successfully before returning. + */ r = amdgpu_ring_test_helper(kiq_ring); - spin_unlock(&kiq->ring_lock); + spin_unlock(&kiq->ring_lock); + } return r; } @@ -702,7 +699,13 @@ int amdgpu_gfx_enable_kcq(struct amdgpu_device *adev, int xcc_id) kiq->pmf->kiq_map_queues(kiq_ring, &adev->gfx.compute_ring[j]); } - + /* Submit map queue packet */ + amdgpu_ring_commit(kiq_ring); + /* + * Ring test will do a basic scratch register change check. Just run + * this to ensure that map queues that is submitted before got + * processed successfully before returning. + */ r = amdgpu_ring_test_helper(kiq_ring); spin_unlock(&kiq->ring_lock); if (r) @@ -753,7 +756,13 @@ int amdgpu_gfx_enable_kgq(struct amdgpu_device *adev, int xcc_id) &adev->gfx.gfx_ring[j]); } } - + /* Submit map queue packet */ + amdgpu_ring_commit(kiq_ring); + /* + * Ring test will do a basic scratch register change check. Just run + * this to ensure that map queues that is submitted before got + * processed successfully before returning. + */ r = amdgpu_ring_test_helper(kiq_ring); spin_unlock(&kiq->ring_lock); if (r) @@ -895,6 +904,9 @@ int amdgpu_gfx_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r if (r) return r; + if (amdgpu_sriov_vf(adev)) + return r; + if (adev->gfx.cp_ecc_error_irq.funcs) { r = amdgpu_irq_get(adev, &adev->gfx.cp_ecc_error_irq, 0); if (r) @@ -1363,35 +1375,35 @@ static ssize_t amdgpu_gfx_set_compute_partition(struct device *dev, return count; } +static const char *xcp_desc[] = { + [AMDGPU_SPX_PARTITION_MODE] = "SPX", + [AMDGPU_DPX_PARTITION_MODE] = "DPX", + [AMDGPU_TPX_PARTITION_MODE] = "TPX", + [AMDGPU_QPX_PARTITION_MODE] = "QPX", + [AMDGPU_CPX_PARTITION_MODE] = "CPX", +}; + static ssize_t amdgpu_gfx_get_available_compute_partition(struct device *dev, struct device_attribute *addr, char *buf) { struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - char *supported_partition; + struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr; + int size = 0, mode; + char *sep = ""; - /* TBD */ - switch (NUM_XCC(adev->gfx.xcc_mask)) { - case 8: - supported_partition = "SPX, DPX, QPX, CPX"; - break; - case 6: - supported_partition = "SPX, TPX, CPX"; - break; - case 4: - supported_partition = "SPX, DPX, CPX"; - break; - /* this seems only existing in emulation phase */ - case 2: - supported_partition = "SPX, CPX"; - break; - default: - supported_partition = "Not supported"; - break; + if (!xcp_mgr || !xcp_mgr->avail_xcp_modes) + return sysfs_emit(buf, "Not supported\n"); + + for_each_inst(mode, xcp_mgr->avail_xcp_modes) { + size += sysfs_emit_at(buf, size, "%s%s", sep, xcp_desc[mode]); + sep = ", "; } - return sysfs_emit(buf, "%s\n", supported_partition); + size += sysfs_emit_at(buf, size, "\n"); + + return size; } static int amdgpu_gfx_run_cleaner_shader_job(struct amdgpu_ring *ring) @@ -1586,9 +1598,11 @@ static ssize_t amdgpu_gfx_set_enforce_isolation(struct device *dev, if (adev->enforce_isolation[i] && !partition_values[i]) { /* Going from enabled to disabled */ amdgpu_vmid_free_reserved(adev, AMDGPU_GFXHUB(i)); + amdgpu_mes_set_enforce_isolation(adev, i, false); } else if (!adev->enforce_isolation[i] && partition_values[i]) { /* Going from disabled to enabled */ amdgpu_vmid_alloc_reserved(adev, AMDGPU_GFXHUB(i)); + amdgpu_mes_set_enforce_isolation(adev, i, true); } adev->enforce_isolation[i] = partition_values[i]; } @@ -1598,6 +1612,32 @@ static ssize_t amdgpu_gfx_set_enforce_isolation(struct device *dev, return count; } +static ssize_t amdgpu_gfx_get_gfx_reset_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (!adev) + return -ENODEV; + + return amdgpu_show_reset_mask(buf, adev->gfx.gfx_supported_reset); +} + +static ssize_t amdgpu_gfx_get_compute_reset_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (!adev) + return -ENODEV; + + return amdgpu_show_reset_mask(buf, adev->gfx.compute_supported_reset); +} + static DEVICE_ATTR(run_cleaner_shader, 0200, NULL, amdgpu_gfx_set_run_cleaner_shader); @@ -1611,45 +1651,138 @@ static DEVICE_ATTR(current_compute_partition, 0644, static DEVICE_ATTR(available_compute_partition, 0444, amdgpu_gfx_get_available_compute_partition, NULL); +static DEVICE_ATTR(gfx_reset_mask, 0444, + amdgpu_gfx_get_gfx_reset_mask, NULL); -int amdgpu_gfx_sysfs_init(struct amdgpu_device *adev) +static DEVICE_ATTR(compute_reset_mask, 0444, + amdgpu_gfx_get_compute_reset_mask, NULL); + +static int amdgpu_gfx_sysfs_xcp_init(struct amdgpu_device *adev) { + struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr; + bool xcp_switch_supported; int r; + if (!xcp_mgr) + return 0; + + xcp_switch_supported = + (xcp_mgr->funcs && xcp_mgr->funcs->switch_partition_mode); + + if (!xcp_switch_supported) + dev_attr_current_compute_partition.attr.mode &= + ~(S_IWUSR | S_IWGRP | S_IWOTH); + r = device_create_file(adev->dev, &dev_attr_current_compute_partition); if (r) return r; - r = device_create_file(adev->dev, &dev_attr_available_compute_partition); + if (xcp_switch_supported) + r = device_create_file(adev->dev, + &dev_attr_available_compute_partition); return r; } -void amdgpu_gfx_sysfs_fini(struct amdgpu_device *adev) +static void amdgpu_gfx_sysfs_xcp_fini(struct amdgpu_device *adev) { + struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr; + bool xcp_switch_supported; + + if (!xcp_mgr) + return; + + xcp_switch_supported = + (xcp_mgr->funcs && xcp_mgr->funcs->switch_partition_mode); device_remove_file(adev->dev, &dev_attr_current_compute_partition); - device_remove_file(adev->dev, &dev_attr_available_compute_partition); + + if (xcp_switch_supported) + device_remove_file(adev->dev, + &dev_attr_available_compute_partition); } -int amdgpu_gfx_sysfs_isolation_shader_init(struct amdgpu_device *adev) +static int amdgpu_gfx_sysfs_isolation_shader_init(struct amdgpu_device *adev) { int r; r = device_create_file(adev->dev, &dev_attr_enforce_isolation); if (r) return r; + if (adev->gfx.enable_cleaner_shader) + r = device_create_file(adev->dev, &dev_attr_run_cleaner_shader); - r = device_create_file(adev->dev, &dev_attr_run_cleaner_shader); - if (r) + return r; +} + +static void amdgpu_gfx_sysfs_isolation_shader_fini(struct amdgpu_device *adev) +{ + device_remove_file(adev->dev, &dev_attr_enforce_isolation); + if (adev->gfx.enable_cleaner_shader) + device_remove_file(adev->dev, &dev_attr_run_cleaner_shader); +} + +static int amdgpu_gfx_sysfs_reset_mask_init(struct amdgpu_device *adev) +{ + int r = 0; + + if (!amdgpu_gpu_recovery) return r; - return 0; + if (adev->gfx.num_gfx_rings) { + r = device_create_file(adev->dev, &dev_attr_gfx_reset_mask); + if (r) + return r; + } + + if (adev->gfx.num_compute_rings) { + r = device_create_file(adev->dev, &dev_attr_compute_reset_mask); + if (r) + return r; + } + + return r; } -void amdgpu_gfx_sysfs_isolation_shader_fini(struct amdgpu_device *adev) +static void amdgpu_gfx_sysfs_reset_mask_fini(struct amdgpu_device *adev) { - device_remove_file(adev->dev, &dev_attr_enforce_isolation); - device_remove_file(adev->dev, &dev_attr_run_cleaner_shader); + if (!amdgpu_gpu_recovery) + return; + + if (adev->gfx.num_gfx_rings) + device_remove_file(adev->dev, &dev_attr_gfx_reset_mask); + + if (adev->gfx.num_compute_rings) + device_remove_file(adev->dev, &dev_attr_compute_reset_mask); +} + +int amdgpu_gfx_sysfs_init(struct amdgpu_device *adev) +{ + int r; + + r = amdgpu_gfx_sysfs_xcp_init(adev); + if (r) { + dev_err(adev->dev, "failed to create xcp sysfs files"); + return r; + } + + r = amdgpu_gfx_sysfs_isolation_shader_init(adev); + if (r) + dev_err(adev->dev, "failed to create isolation sysfs files"); + + r = amdgpu_gfx_sysfs_reset_mask_init(adev); + if (r) + dev_err(adev->dev, "failed to create reset mask sysfs files"); + + return r; +} + +void amdgpu_gfx_sysfs_fini(struct amdgpu_device *adev) +{ + if (adev->dev->kobj.sd) { + amdgpu_gfx_sysfs_xcp_fini(adev); + amdgpu_gfx_sysfs_isolation_shader_fini(adev); + amdgpu_gfx_sysfs_reset_mask_fini(adev); + } } int amdgpu_gfx_cleaner_shader_sw_init(struct amdgpu_device *adev, @@ -1737,7 +1870,7 @@ static void amdgpu_gfx_kfd_sch_ctrl(struct amdgpu_device *adev, u32 idx, if (adev->gfx.kfd_sch_req_count[idx] == 0 && adev->gfx.kfd_sch_inactive[idx]) { schedule_delayed_work(&adev->gfx.enforce_isolation[idx].work, - GFX_SLICE_PERIOD); + msecs_to_jiffies(adev->gfx.enforce_isolation_time[idx])); } } else { if (adev->gfx.kfd_sch_req_count[idx] == 0) { @@ -1792,8 +1925,9 @@ void amdgpu_gfx_enforce_isolation_handler(struct work_struct *work) fences += amdgpu_fence_count_emitted(&adev->gfx.compute_ring[i]); } if (fences) { + /* we've already had our timeslice, so let's wrap this up */ schedule_delayed_work(&adev->gfx.enforce_isolation[idx].work, - GFX_SLICE_PERIOD); + msecs_to_jiffies(1)); } else { /* Tell KFD to resume the runqueue */ if (adev->kfd.init_complete) { @@ -1806,6 +1940,51 @@ void amdgpu_gfx_enforce_isolation_handler(struct work_struct *work) mutex_unlock(&adev->enforce_isolation_mutex); } +static void +amdgpu_gfx_enforce_isolation_wait_for_kfd(struct amdgpu_device *adev, + u32 idx) +{ + unsigned long cjiffies; + bool wait = false; + + mutex_lock(&adev->enforce_isolation_mutex); + if (adev->enforce_isolation[idx]) { + /* set the initial values if nothing is set */ + if (!adev->gfx.enforce_isolation_jiffies[idx]) { + adev->gfx.enforce_isolation_jiffies[idx] = jiffies; + adev->gfx.enforce_isolation_time[idx] = GFX_SLICE_PERIOD_MS; + } + /* Make sure KFD gets a chance to run */ + if (amdgpu_amdkfd_compute_active(adev, idx)) { + cjiffies = jiffies; + if (time_after(cjiffies, adev->gfx.enforce_isolation_jiffies[idx])) { + cjiffies -= adev->gfx.enforce_isolation_jiffies[idx]; + if ((jiffies_to_msecs(cjiffies) >= GFX_SLICE_PERIOD_MS)) { + /* if our time is up, let KGD work drain before scheduling more */ + wait = true; + /* reset the timer period */ + adev->gfx.enforce_isolation_time[idx] = GFX_SLICE_PERIOD_MS; + } else { + /* set the timer period to what's left in our time slice */ + adev->gfx.enforce_isolation_time[idx] = + GFX_SLICE_PERIOD_MS - jiffies_to_msecs(cjiffies); + } + } else { + /* if jiffies wrap around we will just wait a little longer */ + adev->gfx.enforce_isolation_jiffies[idx] = jiffies; + } + } else { + /* if there is no KFD work, then set the full slice period */ + adev->gfx.enforce_isolation_jiffies[idx] = jiffies; + adev->gfx.enforce_isolation_time[idx] = GFX_SLICE_PERIOD_MS; + } + } + mutex_unlock(&adev->enforce_isolation_mutex); + + if (wait) + msleep(GFX_SLICE_PERIOD_MS); +} + void amdgpu_gfx_enforce_isolation_ring_begin_use(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; @@ -1822,6 +2001,9 @@ void amdgpu_gfx_enforce_isolation_ring_begin_use(struct amdgpu_ring *ring) if (idx >= MAX_XCP) return; + /* Don't submit more work until KFD has had some time */ + amdgpu_gfx_enforce_isolation_wait_for_kfd(adev, idx); + mutex_lock(&adev->enforce_isolation_mutex); if (adev->enforce_isolation[idx]) { if (adev->kfd.init_complete) @@ -1853,3 +2035,144 @@ void amdgpu_gfx_enforce_isolation_ring_end_use(struct amdgpu_ring *ring) } mutex_unlock(&adev->enforce_isolation_mutex); } + +/* + * debugfs for to enable/disable gfx job submission to specific core. + */ +#if defined(CONFIG_DEBUG_FS) +static int amdgpu_debugfs_gfx_sched_mask_set(void *data, u64 val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + u32 i; + u64 mask = 0; + struct amdgpu_ring *ring; + + if (!adev) + return -ENODEV; + + mask = (1 << adev->gfx.num_gfx_rings) - 1; + if ((val & mask) == 0) + return -EINVAL; + + for (i = 0; i < adev->gfx.num_gfx_rings; ++i) { + ring = &adev->gfx.gfx_ring[i]; + if (val & (1 << i)) + ring->sched.ready = true; + else + ring->sched.ready = false; + } + /* publish sched.ready flag update effective immediately across smp */ + smp_rmb(); + return 0; +} + +static int amdgpu_debugfs_gfx_sched_mask_get(void *data, u64 *val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + u32 i; + u64 mask = 0; + struct amdgpu_ring *ring; + + if (!adev) + return -ENODEV; + for (i = 0; i < adev->gfx.num_gfx_rings; ++i) { + ring = &adev->gfx.gfx_ring[i]; + if (ring->sched.ready) + mask |= 1 << i; + } + + *val = mask; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_gfx_sched_mask_fops, + amdgpu_debugfs_gfx_sched_mask_get, + amdgpu_debugfs_gfx_sched_mask_set, "%llx\n"); + +#endif + +void amdgpu_debugfs_gfx_sched_mask_init(struct amdgpu_device *adev) +{ +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = adev_to_drm(adev)->primary; + struct dentry *root = minor->debugfs_root; + char name[32]; + + if (!(adev->gfx.num_gfx_rings > 1)) + return; + sprintf(name, "amdgpu_gfx_sched_mask"); + debugfs_create_file(name, 0600, root, adev, + &amdgpu_debugfs_gfx_sched_mask_fops); +#endif +} + +/* + * debugfs for to enable/disable compute job submission to specific core. + */ +#if defined(CONFIG_DEBUG_FS) +static int amdgpu_debugfs_compute_sched_mask_set(void *data, u64 val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + u32 i; + u64 mask = 0; + struct amdgpu_ring *ring; + + if (!adev) + return -ENODEV; + + mask = (1 << adev->gfx.num_compute_rings) - 1; + if ((val & mask) == 0) + return -EINVAL; + + for (i = 0; i < adev->gfx.num_compute_rings; ++i) { + ring = &adev->gfx.compute_ring[i]; + if (val & (1 << i)) + ring->sched.ready = true; + else + ring->sched.ready = false; + } + + /* publish sched.ready flag update effective immediately across smp */ + smp_rmb(); + return 0; +} + +static int amdgpu_debugfs_compute_sched_mask_get(void *data, u64 *val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + u32 i; + u64 mask = 0; + struct amdgpu_ring *ring; + + if (!adev) + return -ENODEV; + for (i = 0; i < adev->gfx.num_compute_rings; ++i) { + ring = &adev->gfx.compute_ring[i]; + if (ring->sched.ready) + mask |= 1 << i; + } + + *val = mask; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_compute_sched_mask_fops, + amdgpu_debugfs_compute_sched_mask_get, + amdgpu_debugfs_compute_sched_mask_set, "%llx\n"); + +#endif + +void amdgpu_debugfs_compute_sched_mask_init(struct amdgpu_device *adev) +{ +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = adev_to_drm(adev)->primary; + struct dentry *root = minor->debugfs_root; + char name[32]; + + if (!(adev->gfx.num_compute_rings > 1)) + return; + sprintf(name, "amdgpu_compute_sched_mask"); + debugfs_create_file(name, 0600, root, adev, + &amdgpu_debugfs_compute_sched_mask_fops); +#endif +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 5644e10a86a99c..8b5bd63b577300 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -424,6 +424,8 @@ struct amdgpu_gfx { /* reset mask */ uint32_t grbm_soft_reset; uint32_t srbm_soft_reset; + uint32_t gfx_supported_reset; + uint32_t compute_supported_reset; /* gfx off */ bool gfx_off_state; /* true: enabled, false: disabled */ @@ -472,6 +474,8 @@ struct amdgpu_gfx { struct mutex kfd_sch_mutex; u64 kfd_sch_req_count[MAX_XCP]; bool kfd_sch_inactive[MAX_XCP]; + unsigned long enforce_isolation_jiffies[MAX_XCP]; + unsigned long enforce_isolation_time[MAX_XCP]; }; struct amdgpu_gfx_ras_reg_entry { @@ -540,8 +544,6 @@ bool amdgpu_gfx_is_high_priority_graphics_queue(struct amdgpu_device *adev, struct amdgpu_ring *ring); int amdgpu_gfx_me_queue_to_bit(struct amdgpu_device *adev, int me, int pipe, int queue); -void amdgpu_gfx_bit_to_me_queue(struct amdgpu_device *adev, int bit, - int *me, int *pipe, int *queue); bool amdgpu_gfx_is_me_queue_enabled(struct amdgpu_device *adev, int me, int pipe, int queue); void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable); @@ -579,11 +581,11 @@ void amdgpu_gfx_cleaner_shader_sw_fini(struct amdgpu_device *adev); void amdgpu_gfx_cleaner_shader_init(struct amdgpu_device *adev, unsigned int cleaner_shader_size, const void *cleaner_shader_ptr); -int amdgpu_gfx_sysfs_isolation_shader_init(struct amdgpu_device *adev); -void amdgpu_gfx_sysfs_isolation_shader_fini(struct amdgpu_device *adev); void amdgpu_gfx_enforce_isolation_handler(struct work_struct *work); void amdgpu_gfx_enforce_isolation_ring_begin_use(struct amdgpu_ring *ring); void amdgpu_gfx_enforce_isolation_ring_end_use(struct amdgpu_ring *ring); +void amdgpu_debugfs_gfx_sched_mask_init(struct amdgpu_device *adev); +void amdgpu_debugfs_compute_sched_mask_init(struct amdgpu_device *adev); static inline const char *amdgpu_gfx_compute_mode_desc(int mode) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 17a19d49d30a57..1c19a65e655337 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -1065,18 +1065,6 @@ uint64_t amdgpu_gmc_vram_pa(struct amdgpu_device *adev, struct amdgpu_bo *bo) return amdgpu_gmc_vram_mc2pa(adev, amdgpu_bo_gpu_offset(bo)); } -/** - * amdgpu_gmc_vram_cpu_pa - calculate vram buffer object's physical address - * from CPU's view - * - * @adev: amdgpu_device pointer - * @bo: amdgpu buffer object - */ -uint64_t amdgpu_gmc_vram_cpu_pa(struct amdgpu_device *adev, struct amdgpu_bo *bo) -{ - return amdgpu_bo_gpu_offset(bo) - adev->gmc.vram_start + adev->gmc.aper_base; -} - int amdgpu_gmc_vram_checking(struct amdgpu_device *adev) { struct amdgpu_bo *vram_bo = NULL; @@ -1130,6 +1118,79 @@ int amdgpu_gmc_vram_checking(struct amdgpu_device *adev) return ret; } +static const char *nps_desc[] = { + [AMDGPU_NPS1_PARTITION_MODE] = "NPS1", + [AMDGPU_NPS2_PARTITION_MODE] = "NPS2", + [AMDGPU_NPS3_PARTITION_MODE] = "NPS3", + [AMDGPU_NPS4_PARTITION_MODE] = "NPS4", + [AMDGPU_NPS6_PARTITION_MODE] = "NPS6", + [AMDGPU_NPS8_PARTITION_MODE] = "NPS8", +}; + +static ssize_t available_memory_partition_show(struct device *dev, + struct device_attribute *addr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + int size = 0, mode; + char *sep = ""; + + for_each_inst(mode, adev->gmc.supported_nps_modes) { + size += sysfs_emit_at(buf, size, "%s%s", sep, nps_desc[mode]); + sep = ", "; + } + size += sysfs_emit_at(buf, size, "\n"); + + return size; +} + +static ssize_t current_memory_partition_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + enum amdgpu_memory_partition mode; + struct amdgpu_hive_info *hive; + int i; + + mode = UNKNOWN_MEMORY_PARTITION_MODE; + for_each_inst(i, adev->gmc.supported_nps_modes) { + if (!strncasecmp(nps_desc[i], buf, strlen(nps_desc[i]))) { + mode = i; + break; + } + } + + if (mode == UNKNOWN_MEMORY_PARTITION_MODE) + return -EINVAL; + + if (mode == adev->gmc.gmc_funcs->query_mem_partition_mode(adev)) { + dev_info( + adev->dev, + "requested NPS mode is same as current NPS mode, skipping\n"); + return count; + } + + /* If device is part of hive, all devices in the hive should request the + * same mode. Hence store the requested mode in hive. + */ + hive = amdgpu_get_xgmi_hive(adev); + if (hive) { + atomic_set(&hive->requested_nps_mode, mode); + amdgpu_put_xgmi_hive(hive); + } else { + adev->gmc.requested_nps_mode = mode; + } + + dev_info( + adev->dev, + "NPS mode change requested, please remove and reload the driver\n"); + + return count; +} + static ssize_t current_memory_partition_show( struct device *dev, struct device_attribute *addr, char *buf) { @@ -1138,53 +1199,65 @@ static ssize_t current_memory_partition_show( enum amdgpu_memory_partition mode; mode = adev->gmc.gmc_funcs->query_mem_partition_mode(adev); - switch (mode) { - case AMDGPU_NPS1_PARTITION_MODE: - return sysfs_emit(buf, "NPS1\n"); - case AMDGPU_NPS2_PARTITION_MODE: - return sysfs_emit(buf, "NPS2\n"); - case AMDGPU_NPS3_PARTITION_MODE: - return sysfs_emit(buf, "NPS3\n"); - case AMDGPU_NPS4_PARTITION_MODE: - return sysfs_emit(buf, "NPS4\n"); - case AMDGPU_NPS6_PARTITION_MODE: - return sysfs_emit(buf, "NPS6\n"); - case AMDGPU_NPS8_PARTITION_MODE: - return sysfs_emit(buf, "NPS8\n"); - default: + if ((mode >= ARRAY_SIZE(nps_desc)) || + (BIT(mode) & AMDGPU_ALL_NPS_MASK) != BIT(mode)) return sysfs_emit(buf, "UNKNOWN\n"); - } + + return sysfs_emit(buf, "%s\n", nps_desc[mode]); } -static DEVICE_ATTR_RO(current_memory_partition); +static DEVICE_ATTR_RW(current_memory_partition); +static DEVICE_ATTR_RO(available_memory_partition); int amdgpu_gmc_sysfs_init(struct amdgpu_device *adev) { + bool nps_switch_support; + int r = 0; + if (!adev->gmc.gmc_funcs->query_mem_partition_mode) return 0; + nps_switch_support = (hweight32(adev->gmc.supported_nps_modes & + AMDGPU_ALL_NPS_MASK) > 1); + if (!nps_switch_support) + dev_attr_current_memory_partition.attr.mode &= + ~(S_IWUSR | S_IWGRP | S_IWOTH); + else + r = device_create_file(adev->dev, + &dev_attr_available_memory_partition); + + if (r) + return r; + return device_create_file(adev->dev, &dev_attr_current_memory_partition); } void amdgpu_gmc_sysfs_fini(struct amdgpu_device *adev) { + if (!adev->gmc.gmc_funcs->query_mem_partition_mode) + return; + device_remove_file(adev->dev, &dev_attr_current_memory_partition); + device_remove_file(adev->dev, &dev_attr_available_memory_partition); } int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev, struct amdgpu_mem_partition_info *mem_ranges, - int exp_ranges) + uint8_t *exp_ranges) { struct amdgpu_gmc_memrange *ranges; int range_cnt, ret, i, j; uint32_t nps_type; + bool refresh; - if (!mem_ranges) + if (!mem_ranges || !exp_ranges) return -EINVAL; + refresh = (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) && + (adev->gmc.reset_flags & AMDGPU_GMC_INIT_RESET_NPS); ret = amdgpu_discovery_get_nps_info(adev, &nps_type, &ranges, - &range_cnt); + &range_cnt, refresh); if (ret) return ret; @@ -1192,16 +1265,16 @@ int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev, /* TODO: For now, expect ranges and partition count to be the same. * Adjust if there are holes expected in any NPS domain. */ - if (range_cnt != exp_ranges) { + if (*exp_ranges && (range_cnt != *exp_ranges)) { dev_warn( adev->dev, "NPS config mismatch - expected ranges: %d discovery - nps mode: %d, nps ranges: %d", - exp_ranges, nps_type, range_cnt); + *exp_ranges, nps_type, range_cnt); ret = -EINVAL; goto err; } - for (i = 0; i < exp_ranges; ++i) { + for (i = 0; i < range_cnt; ++i) { if (ranges[i].base_address >= ranges[i].limit_address) { dev_warn( adev->dev, @@ -1242,8 +1315,81 @@ int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev, ranges[i].limit_address - ranges[i].base_address + 1; } + if (!*exp_ranges) + *exp_ranges = range_cnt; err: kfree(ranges); return ret; } + +int amdgpu_gmc_request_memory_partition(struct amdgpu_device *adev, + int nps_mode) +{ + /* Not supported on VF devices and APUs */ + if (amdgpu_sriov_vf(adev) || (adev->flags & AMD_IS_APU)) + return -EOPNOTSUPP; + + if (!adev->psp.funcs) { + dev_err(adev->dev, + "PSP interface not available for nps mode change request"); + return -EINVAL; + } + + return psp_memory_partition(&adev->psp, nps_mode); +} + +static inline bool amdgpu_gmc_need_nps_switch_req(struct amdgpu_device *adev, + int req_nps_mode, + int cur_nps_mode) +{ + return (((BIT(req_nps_mode) & adev->gmc.supported_nps_modes) == + BIT(req_nps_mode)) && + req_nps_mode != cur_nps_mode); +} + +void amdgpu_gmc_prepare_nps_mode_change(struct amdgpu_device *adev) +{ + int req_nps_mode, cur_nps_mode, r; + struct amdgpu_hive_info *hive; + + if (amdgpu_sriov_vf(adev) || !adev->gmc.supported_nps_modes || + !adev->gmc.gmc_funcs->request_mem_partition_mode) + return; + + cur_nps_mode = adev->gmc.gmc_funcs->query_mem_partition_mode(adev); + hive = amdgpu_get_xgmi_hive(adev); + if (hive) { + req_nps_mode = atomic_read(&hive->requested_nps_mode); + if (!amdgpu_gmc_need_nps_switch_req(adev, req_nps_mode, + cur_nps_mode)) { + amdgpu_put_xgmi_hive(hive); + return; + } + r = amdgpu_xgmi_request_nps_change(adev, hive, req_nps_mode); + amdgpu_put_xgmi_hive(hive); + goto out; + } + + req_nps_mode = adev->gmc.requested_nps_mode; + if (!amdgpu_gmc_need_nps_switch_req(adev, req_nps_mode, cur_nps_mode)) + return; + + /* even if this fails, we should let driver unload w/o blocking */ + r = adev->gmc.gmc_funcs->request_mem_partition_mode(adev, req_nps_mode); +out: + if (r) + dev_err(adev->dev, "NPS mode change request failed\n"); + else + dev_info( + adev->dev, + "NPS mode change request done, reload driver to complete the change\n"); +} + +bool amdgpu_gmc_need_reset_on_init(struct amdgpu_device *adev) +{ + if (adev->gmc.gmc_funcs->need_reset_on_init) + return adev->gmc.gmc_funcs->need_reset_on_init(adev); + + return false; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index 4d951a1baefab7..459a30fe239f7f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -73,6 +73,13 @@ enum amdgpu_memory_partition { AMDGPU_NPS8_PARTITION_MODE = 8, }; +#define AMDGPU_ALL_NPS_MASK \ + (BIT(AMDGPU_NPS1_PARTITION_MODE) | BIT(AMDGPU_NPS2_PARTITION_MODE) | \ + BIT(AMDGPU_NPS3_PARTITION_MODE) | BIT(AMDGPU_NPS4_PARTITION_MODE) | \ + BIT(AMDGPU_NPS6_PARTITION_MODE) | BIT(AMDGPU_NPS8_PARTITION_MODE)) + +#define AMDGPU_GMC_INIT_RESET_NPS BIT(0) + /* * GMC page fault information */ @@ -161,6 +168,10 @@ struct amdgpu_gmc_funcs { enum amdgpu_memory_partition (*query_mem_partition_mode)( struct amdgpu_device *adev); + /* Request NPS mode */ + int (*request_mem_partition_mode)(struct amdgpu_device *adev, + int nps_mode); + bool (*need_reset_on_init)(struct amdgpu_device *adev); }; struct amdgpu_xgmi_ras { @@ -182,7 +193,6 @@ struct amdgpu_xgmi { bool supported; struct ras_common_if *ras_if; bool connected_to_cpu; - bool pending_reset; struct amdgpu_xgmi_ras *ras; }; @@ -305,6 +315,9 @@ struct amdgpu_gmc { struct amdgpu_mem_partition_info *mem_partitions; uint8_t num_mem_partitions; const struct amdgpu_gmc_funcs *gmc_funcs; + enum amdgpu_memory_partition requested_nps_mode; + uint32_t supported_nps_modes; + uint32_t reset_flags; struct amdgpu_xgmi xgmi; struct amdgpu_irq_src ecc_irq; @@ -447,13 +460,17 @@ void amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev); void amdgpu_gmc_init_pdb0(struct amdgpu_device *adev); uint64_t amdgpu_gmc_vram_mc2pa(struct amdgpu_device *adev, uint64_t mc_addr); uint64_t amdgpu_gmc_vram_pa(struct amdgpu_device *adev, struct amdgpu_bo *bo); -uint64_t amdgpu_gmc_vram_cpu_pa(struct amdgpu_device *adev, struct amdgpu_bo *bo); int amdgpu_gmc_vram_checking(struct amdgpu_device *adev); int amdgpu_gmc_sysfs_init(struct amdgpu_device *adev); void amdgpu_gmc_sysfs_fini(struct amdgpu_device *adev); int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev, struct amdgpu_mem_partition_info *mem_ranges, - int exp_ranges); + uint8_t *exp_ranges); + +int amdgpu_gmc_request_memory_partition(struct amdgpu_device *adev, + int nps_mode); +void amdgpu_gmc_prepare_nps_mode_change(struct amdgpu_device *adev); +bool amdgpu_gmc_need_reset_on_init(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c index 00d6211e0fbf91..f0765ccde6680f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c @@ -225,15 +225,6 @@ void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c) kfree(i2c); } -/* Add the default buses */ -void amdgpu_i2c_init(struct amdgpu_device *adev) -{ - if (amdgpu_hw_i2c) - DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n"); - - amdgpu_atombios_i2c_init(adev); -} - /* remove all the buses */ void amdgpu_i2c_fini(struct amdgpu_device *adev) { @@ -247,22 +238,6 @@ void amdgpu_i2c_fini(struct amdgpu_device *adev) } } -/* Add additional buses */ -void amdgpu_i2c_add(struct amdgpu_device *adev, - const struct amdgpu_i2c_bus_rec *rec, - const char *name) -{ - struct drm_device *dev = adev_to_drm(adev); - int i; - - for (i = 0; i < AMDGPU_MAX_I2C_BUS; i++) { - if (!adev->i2c_bus[i]) { - adev->i2c_bus[i] = amdgpu_i2c_create(dev, rec, name); - return; - } - } -} - /* looks up bus based on id */ struct amdgpu_i2c_chan * amdgpu_i2c_lookup(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h index 63c2ff7499e175..21e3d1dad0a126 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.h @@ -28,11 +28,7 @@ struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev, const struct amdgpu_i2c_bus_rec *rec, const char *name); void amdgpu_i2c_destroy(struct amdgpu_i2c_chan *i2c); -void amdgpu_i2c_init(struct amdgpu_device *adev); void amdgpu_i2c_fini(struct amdgpu_device *adev); -void amdgpu_i2c_add(struct amdgpu_device *adev, - const struct amdgpu_i2c_bus_rec *rec, - const char *name); struct amdgpu_i2c_chan * amdgpu_i2c_lookup(struct amdgpu_device *adev, const struct amdgpu_i2c_bus_rec *i2c_bus); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 92d27d32de41ba..8e712a11aba5d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -342,15 +342,13 @@ static int amdgpu_vmid_grab_reserved(struct amdgpu_vm *vm, * @ring: ring we want to submit job to * @job: job who wants to use the VMID * @id: resulting VMID - * @fence: fence to wait for if no id could be grabbed * * Try to reuse a VMID for this submission. */ static int amdgpu_vmid_grab_used(struct amdgpu_vm *vm, struct amdgpu_ring *ring, struct amdgpu_job *job, - struct amdgpu_vmid **id, - struct dma_fence **fence) + struct amdgpu_vmid **id) { struct amdgpu_device *adev = ring->adev; unsigned vmhub = ring->vm_hub; @@ -429,7 +427,7 @@ int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring, if (r || !id) goto error; } else { - r = amdgpu_vmid_grab_used(vm, ring, job, &id, fence); + r = amdgpu_vmid_grab_used(vm, ring, job, &id); if (r) goto error; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c index 4766e99dd98fb0..263ce1811cc842 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_isp.c @@ -33,33 +33,17 @@ #include "isp_v4_1_0.h" #include "isp_v4_1_1.h" -static int isp_sw_init(void *handle) -{ - return 0; -} - -static int isp_sw_fini(void *handle) -{ - return 0; -} - /** * isp_hw_init - start and test isp block * - * @handle: handle for amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int isp_hw_init(void *handle) +static int isp_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_isp *isp = &adev->isp; - const struct amdgpu_ip_block *ip_block = - amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ISP); - - if (!ip_block) - return -EINVAL; - if (isp->funcs->hw_init != NULL) return isp->funcs->hw_init(isp); @@ -69,13 +53,12 @@ static int isp_hw_init(void *handle) /** * isp_hw_fini - stop the hardware block * - * @handle: handle for amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int isp_hw_fini(void *handle) +static int isp_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - struct amdgpu_isp *isp = &adev->isp; + struct amdgpu_isp *isp = &ip_block->adev->isp; if (isp->funcs->hw_fini != NULL) return isp->funcs->hw_fini(isp); @@ -83,16 +66,6 @@ static int isp_hw_fini(void *handle) return -ENODEV; } -static int isp_suspend(void *handle) -{ - return 0; -} - -static int isp_resume(void *handle) -{ - return 0; -} - static int isp_load_fw_by_psp(struct amdgpu_device *adev) { const struct common_firmware_header *hdr; @@ -122,9 +95,10 @@ static int isp_load_fw_by_psp(struct amdgpu_device *adev) return r; } -static int isp_early_init(void *handle) +static int isp_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_isp *isp = &adev->isp; switch (amdgpu_ip_version(adev, ISP_HWIP, 0)) { @@ -154,16 +128,6 @@ static bool isp_is_idle(void *handle) return true; } -static int isp_wait_for_idle(void *handle) -{ - return 0; -} - -static int isp_soft_reset(void *handle) -{ - return 0; -} - static int isp_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -179,16 +143,9 @@ static int isp_set_powergating_state(void *handle, static const struct amd_ip_funcs isp_ip_funcs = { .name = "isp_ip", .early_init = isp_early_init, - .late_init = NULL, - .sw_init = isp_sw_init, - .sw_fini = isp_sw_fini, .hw_init = isp_hw_init, .hw_fini = isp_hw_fini, - .suspend = isp_suspend, - .resume = isp_resume, .is_idle = isp_is_idle, - .wait_for_idle = isp_wait_for_idle, - .soft_reset = isp_soft_reset, .set_clockgating_state = isp_set_clockgating_state, .set_powergating_state = isp_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 16f2605ac50b99..a21c510c408ee2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -42,7 +42,7 @@ static void amdgpu_job_do_core_dump(struct amdgpu_device *adev, for (i = 0; i < adev->num_ip_blocks; i++) if (adev->ip_blocks[i].version->funcs->dump_ip_state) adev->ip_blocks[i].version->funcs - ->dump_ip_state((void *)adev); + ->dump_ip_state((void *)&adev->ip_blocks[i]); dev_info(adev->dev, "Dumping IP State Completed\n"); amdgpu_coredump(adev, true, false, job); @@ -137,6 +137,7 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) /* attempt a per ring reset */ if (amdgpu_gpu_recovery && ring->funcs->reset) { + dev_err(adev->dev, "Starting %s ring reset\n", s_job->sched->name); /* stop the scheduler, but don't mess with the * bad job yet because if ring reset fails * we'll fall back to full GPU reset. @@ -149,9 +150,10 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) atomic_inc(&ring->adev->gpu_reset_counter); amdgpu_fence_driver_force_completion(ring); if (amdgpu_ring_sched_ready(ring)) - drm_sched_start(&ring->sched); + drm_sched_start(&ring->sched, 0); goto exit; } + dev_err(adev->dev, "Ring %s reset failure\n", ring->sched.name); } if (amdgpu_device_should_recover_gpu(ring->adev)) { @@ -253,7 +255,6 @@ void amdgpu_job_set_resources(struct amdgpu_job *job, struct amdgpu_bo *gds, void amdgpu_job_free_resources(struct amdgpu_job *job) { - struct amdgpu_ring *ring = to_amdgpu_ring(job->base.sched); struct dma_fence *f; unsigned i; @@ -266,7 +267,7 @@ void amdgpu_job_free_resources(struct amdgpu_job *job) f = NULL; for (i = 0; i < job->num_ibs; ++i) - amdgpu_ib_free(ring->adev, &job->ibs[i], f); + amdgpu_ib_free(NULL, &job->ibs[i], f); } static void amdgpu_job_free_cb(struct drm_sched_job *s_job) @@ -356,10 +357,10 @@ amdgpu_job_prepare_job(struct drm_sched_job *sched_job, if (r) goto error; - if (!fence && job->gang_submit) + if (job->gang_submit) fence = amdgpu_device_switch_gang(ring->adev, job->gang_submit); - while (!fence && job->vm && !job->vmid) { + if (!fence && job->vm && !job->vmid) { r = amdgpu_vmid_grab(job->vm, ring, job, &fence); if (r) { dev_err(ring->adev->dev, "Error getting VM ID (%d)\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c index 6df99cb00d9a54..b6d2eb049f5408 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c @@ -47,7 +47,7 @@ int amdgpu_jpeg_sw_init(struct amdgpu_device *adev) adev->jpeg.indirect_sram = true; for (i = 0; i < adev->jpeg.num_jpeg_inst; i++) { - if (adev->jpeg.harvest_config & (1 << i)) + if (adev->jpeg.harvest_config & (1U << i)) continue; if (adev->jpeg.indirect_sram) { @@ -73,7 +73,7 @@ int amdgpu_jpeg_sw_fini(struct amdgpu_device *adev) int i, j; for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { - if (adev->jpeg.harvest_config & (1 << i)) + if (adev->jpeg.harvest_config & (1U << i)) continue; amdgpu_bo_free_kernel( @@ -110,7 +110,7 @@ static void amdgpu_jpeg_idle_work_handler(struct work_struct *work) unsigned int i, j; for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { - if (adev->jpeg.harvest_config & (1 << i)) + if (adev->jpeg.harvest_config & (1U << i)) continue; for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) @@ -342,3 +342,113 @@ int amdgpu_jpeg_psp_update_sram(struct amdgpu_device *adev, int inst_idx, return psp_execute_ip_fw_load(&adev->psp, &ucode); } + +/* + * debugfs for to enable/disable jpeg job submission to specific core. + */ +#if defined(CONFIG_DEBUG_FS) +static int amdgpu_debugfs_jpeg_sched_mask_set(void *data, u64 val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + u32 i, j; + u64 mask = 0; + struct amdgpu_ring *ring; + + if (!adev) + return -ENODEV; + + mask = (1ULL << (adev->jpeg.num_jpeg_inst * adev->jpeg.num_jpeg_rings)) - 1; + if ((val & mask) == 0) + return -EINVAL; + + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + ring = &adev->jpeg.inst[i].ring_dec[j]; + if (val & (1 << ((i * adev->jpeg.num_jpeg_rings) + j))) + ring->sched.ready = true; + else + ring->sched.ready = false; + } + } + /* publish sched.ready flag update effective immediately across smp */ + smp_rmb(); + return 0; +} + +static int amdgpu_debugfs_jpeg_sched_mask_get(void *data, u64 *val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + u32 i, j; + u64 mask = 0; + struct amdgpu_ring *ring; + + if (!adev) + return -ENODEV; + for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + ring = &adev->jpeg.inst[i].ring_dec[j]; + if (ring->sched.ready) + mask |= 1ULL << ((i * adev->jpeg.num_jpeg_rings) + j); + } + } + *val = mask; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_jpeg_sched_mask_fops, + amdgpu_debugfs_jpeg_sched_mask_get, + amdgpu_debugfs_jpeg_sched_mask_set, "%llx\n"); + +#endif + +void amdgpu_debugfs_jpeg_sched_mask_init(struct amdgpu_device *adev) +{ +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = adev_to_drm(adev)->primary; + struct dentry *root = minor->debugfs_root; + char name[32]; + + if (!(adev->jpeg.num_jpeg_inst > 1) && !(adev->jpeg.num_jpeg_rings > 1)) + return; + sprintf(name, "amdgpu_jpeg_sched_mask"); + debugfs_create_file(name, 0600, root, adev, + &amdgpu_debugfs_jpeg_sched_mask_fops); +#endif +} + +static ssize_t amdgpu_get_jpeg_reset_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (!adev) + return -ENODEV; + + return amdgpu_show_reset_mask(buf, adev->jpeg.supported_reset); +} + +static DEVICE_ATTR(jpeg_reset_mask, 0444, + amdgpu_get_jpeg_reset_mask, NULL); + +int amdgpu_jpeg_sysfs_reset_mask_init(struct amdgpu_device *adev) +{ + int r = 0; + + if (adev->jpeg.num_jpeg_inst) { + r = device_create_file(adev->dev, &dev_attr_jpeg_reset_mask); + if (r) + return r; + } + + return r; +} + +void amdgpu_jpeg_sysfs_reset_mask_fini(struct amdgpu_device *adev) +{ + if (adev->dev->kobj.sd) { + if (adev->jpeg.num_jpeg_inst) + device_remove_file(adev->dev, &dev_attr_jpeg_reset_mask); + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h index f9cdd873ac9b02..3eb4a4653fceeb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h @@ -128,6 +128,7 @@ struct amdgpu_jpeg { uint16_t inst_mask; uint8_t num_inst_per_aid; bool indirect_sram; + uint32_t supported_reset; }; int amdgpu_jpeg_sw_init(struct amdgpu_device *adev); @@ -149,5 +150,8 @@ int amdgpu_jpeg_ras_late_init(struct amdgpu_device *adev, int amdgpu_jpeg_ras_sw_init(struct amdgpu_device *adev); int amdgpu_jpeg_psp_update_sram(struct amdgpu_device *adev, int inst_idx, enum AMDGPU_UCODE_ID ucode_id); +void amdgpu_debugfs_jpeg_sched_mask_init(struct amdgpu_device *adev); +int amdgpu_jpeg_sysfs_reset_mask_init(struct amdgpu_device *adev); +void amdgpu_jpeg_sysfs_reset_mask_fini(struct amdgpu_device *adev); #endif /*__AMDGPU_JPEG_H__*/ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c index 18ee60378727fc..3ca03b5e0f9139 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c @@ -348,6 +348,24 @@ static bool amdgpu_mca_bank_should_update(struct amdgpu_device *adev, enum amdgp return ret; } +static bool amdgpu_mca_bank_should_dump(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, + struct mca_bank_entry *entry) +{ + bool ret; + + switch (type) { + case AMDGPU_MCA_ERROR_TYPE_CE: + ret = amdgpu_mca_is_deferred_error(adev, entry->regs[MCA_REG_IDX_STATUS]); + break; + case AMDGPU_MCA_ERROR_TYPE_UE: + default: + ret = true; + break; + } + + return ret; +} + static int amdgpu_mca_smu_get_mca_set(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, struct mca_bank_set *mca_set, struct ras_query_context *qctx) { @@ -373,7 +391,8 @@ static int amdgpu_mca_smu_get_mca_set(struct amdgpu_device *adev, enum amdgpu_mc amdgpu_mca_bank_set_add_entry(mca_set, &entry); - amdgpu_mca_smu_mca_bank_dump(adev, i, &entry, qctx); + if (amdgpu_mca_bank_should_dump(adev, type, &entry)) + amdgpu_mca_smu_mca_bank_dump(adev, i, &entry, qctx); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 7d4b540340e021..59ec20b07a6af3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -104,7 +104,7 @@ static int amdgpu_mes_event_log_init(struct amdgpu_device *adev) return 0; r = amdgpu_bo_create_kernel(adev, adev->mes.event_log_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_DOMAIN_VRAM, &adev->mes.event_log_gpu_obj, &adev->mes.event_log_gpu_addr, &adev->mes.event_log_cpu_addr); @@ -192,17 +192,6 @@ int amdgpu_mes_init(struct amdgpu_device *adev) (uint64_t *)&adev->wb.wb[adev->mes.query_status_fence_offs[i]]; } - r = amdgpu_device_wb_get(adev, &adev->mes.read_val_offs); - if (r) { - dev_err(adev->dev, - "(%d) read_val_offs alloc failed\n", r); - goto error; - } - adev->mes.read_val_gpu_addr = - adev->wb.gpu_addr + (adev->mes.read_val_offs * 4); - adev->mes.read_val_ptr = - (uint32_t *)&adev->wb.wb[adev->mes.read_val_offs]; - r = amdgpu_mes_doorbell_init(adev); if (r) goto error; @@ -223,8 +212,6 @@ int amdgpu_mes_init(struct amdgpu_device *adev) amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs[i]); } - if (adev->mes.read_val_ptr) - amdgpu_device_wb_free(adev, adev->mes.read_val_offs); idr_destroy(&adev->mes.pasid_idr); idr_destroy(&adev->mes.gang_id_idr); @@ -249,8 +236,6 @@ void amdgpu_mes_fini(struct amdgpu_device *adev) amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs[i]); } - if (adev->mes.read_val_ptr) - amdgpu_device_wb_free(adev, adev->mes.read_val_offs); amdgpu_mes_doorbell_free(adev); @@ -905,7 +890,7 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev, queue_input.me_id = ring->me; queue_input.pipe_id = ring->pipe; queue_input.queue_id = ring->queue; - queue_input.mqd_addr = amdgpu_bo_gpu_offset(ring->mqd_obj); + queue_input.mqd_addr = ring->mqd_obj ? amdgpu_bo_gpu_offset(ring->mqd_obj) : 0; queue_input.wptr_addr = ring->wptr_gpu_addr; queue_input.vmid = vmid; queue_input.use_mmio = use_mmio; @@ -921,10 +906,19 @@ uint32_t amdgpu_mes_rreg(struct amdgpu_device *adev, uint32_t reg) { struct mes_misc_op_input op_input; int r, val = 0; + uint32_t addr_offset = 0; + uint64_t read_val_gpu_addr; + uint32_t *read_val_ptr; + if (amdgpu_device_wb_get(adev, &addr_offset)) { + DRM_ERROR("critical bug! too many mes readers\n"); + goto error; + } + read_val_gpu_addr = adev->wb.gpu_addr + (addr_offset * 4); + read_val_ptr = (uint32_t *)&adev->wb.wb[addr_offset]; op_input.op = MES_MISC_OP_READ_REG; op_input.read_reg.reg_offset = reg; - op_input.read_reg.buffer_addr = adev->mes.read_val_gpu_addr; + op_input.read_reg.buffer_addr = read_val_gpu_addr; if (!adev->mes.funcs->misc_op) { DRM_ERROR("mes rreg is not supported!\n"); @@ -935,9 +929,11 @@ uint32_t amdgpu_mes_rreg(struct amdgpu_device *adev, uint32_t reg) if (r) DRM_ERROR("failed to read reg (0x%x)\n", reg); else - val = *(adev->mes.read_val_ptr); + val = *(read_val_ptr); error: + if (addr_offset) + amdgpu_device_wb_free(adev, addr_offset); return val; } @@ -1594,6 +1590,7 @@ int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe) char ucode_prefix[30]; char fw_name[50]; bool need_retry = false; + u32 *ucode_ptr; int r; amdgpu_ucode_ip_version_decode(adev, GC_HWIP, ucode_prefix, @@ -1631,6 +1628,10 @@ int amdgpu_mes_init_microcode(struct amdgpu_device *adev, int pipe) adev->mes.data_start_addr[pipe] = le32_to_cpu(mes_hdr->mes_data_start_addr_lo) | ((uint64_t)(le32_to_cpu(mes_hdr->mes_data_start_addr_hi)) << 32); + ucode_ptr = (u32 *)(adev->mes.fw[pipe]->data + + sizeof(union amdgpu_firmware_header)); + adev->mes.fw_version[pipe] = + le32_to_cpu(ucode_ptr[24]) & AMDGPU_MES_VERSION_MASK; if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { int ucode, ucode_data; @@ -1677,6 +1678,29 @@ bool amdgpu_mes_suspend_resume_all_supported(struct amdgpu_device *adev) return is_supported; } +/* Fix me -- node_id is used to identify the correct MES instances in the future */ +int amdgpu_mes_set_enforce_isolation(struct amdgpu_device *adev, uint32_t node_id, bool enable) +{ + struct mes_misc_op_input op_input = {0}; + int r; + + op_input.op = MES_MISC_OP_CHANGE_CONFIG; + op_input.change_config.option.limit_single_process = enable ? 1 : 0; + + if (!adev->mes.funcs->misc_op) { + dev_err(adev->dev, "mes change config is not supported!\n"); + r = -EINVAL; + goto error; + } + + r = adev->mes.funcs->misc_op(&adev->mes, &op_input); + if (r) + dev_err(adev->dev, "failed to change_config.\n"); + +error: + return r; +} + #if defined(CONFIG_DEBUG_FS) static int amdgpu_debugfs_mes_event_log_show(struct seq_file *m, void *unused) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index 96788c0f42f1be..c6f93cbd6739f0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -40,6 +40,7 @@ #define AMDGPU_MES_VERSION_MASK 0x00000fff #define AMDGPU_MES_API_VERSION_MASK 0x00fff000 #define AMDGPU_MES_FEAT_VERSION_MASK 0xff000000 +#define AMDGPU_MES_MSCRATCH_SIZE 0x8000 enum amdgpu_mes_priority_level { AMDGPU_MES_PRIORITY_LEVEL_LOW = 0, @@ -75,6 +76,7 @@ struct amdgpu_mes { uint32_t sched_version; uint32_t kiq_version; + uint32_t fw_version[AMDGPU_MAX_MES_PIPES]; bool enable_legacy_queue_map; uint32_t total_max_queue; @@ -119,9 +121,6 @@ struct amdgpu_mes { uint32_t query_status_fence_offs[AMDGPU_MAX_MES_PIPES]; uint64_t query_status_fence_gpu_addr[AMDGPU_MAX_MES_PIPES]; uint64_t *query_status_fence_ptr[AMDGPU_MAX_MES_PIPES]; - uint32_t read_val_offs; - uint64_t read_val_gpu_addr; - uint32_t *read_val_ptr; uint32_t saved_flags; @@ -310,6 +309,7 @@ enum mes_misc_opcode { MES_MISC_OP_WRM_REG_WAIT, MES_MISC_OP_WRM_REG_WR_WAIT, MES_MISC_OP_SET_SHADER_DEBUGGER, + MES_MISC_OP_CHANGE_CONFIG, }; struct mes_misc_op_input { @@ -348,6 +348,21 @@ struct mes_misc_op_input { uint32_t tcp_watch_cntl[4]; uint32_t trap_en; } set_shader_debugger; + + struct { + union { + struct { + uint32_t limit_single_process : 1; + uint32_t enable_hws_logging_buffer : 1; + uint32_t reserved : 30; + }; + uint32_t all; + } option; + struct { + uint32_t tdr_level; + uint32_t tdr_delay; + } tdr_config; + } change_config; }; }; @@ -518,4 +533,7 @@ static inline void amdgpu_mes_unlock(struct amdgpu_mes *mes) } bool amdgpu_mes_suspend_resume_all_supported(struct amdgpu_device *adev); + +int amdgpu_mes_set_enforce_isolation(struct amdgpu_device *adev, uint32_t node_id, bool enable); + #endif /* __AMDGPU_MES_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h index f61d117b0cafe3..79c2f807b9fe87 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_nbio.h @@ -101,6 +101,7 @@ struct amdgpu_nbio_funcs { int (*get_compute_partition_mode)(struct amdgpu_device *adev); u32 (*get_memory_partition_mode)(struct amdgpu_device *adev, u32 *supp_modes); + bool (*is_nps_switch_requested)(struct amdgpu_device *adev); u64 (*get_pcie_replay_count)(struct amdgpu_device *adev); void (*set_reg_remap)(struct amdgpu_device *adev); }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 971419e3a9bbdf..6852d50caa89a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -40,6 +40,7 @@ #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" #include "amdgpu_vram_mgr.h" +#include "amdgpu_vm.h" /** * DOC: amdgpu_object @@ -1171,54 +1172,71 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, } void amdgpu_bo_get_memory(struct amdgpu_bo *bo, - struct amdgpu_mem_stats *stats) + struct amdgpu_mem_stats *stats, + unsigned int sz) { + const unsigned int domain_to_pl[] = { + [ilog2(AMDGPU_GEM_DOMAIN_CPU)] = TTM_PL_SYSTEM, + [ilog2(AMDGPU_GEM_DOMAIN_GTT)] = TTM_PL_TT, + [ilog2(AMDGPU_GEM_DOMAIN_VRAM)] = TTM_PL_VRAM, + [ilog2(AMDGPU_GEM_DOMAIN_GDS)] = AMDGPU_PL_GDS, + [ilog2(AMDGPU_GEM_DOMAIN_GWS)] = AMDGPU_PL_GWS, + [ilog2(AMDGPU_GEM_DOMAIN_OA)] = AMDGPU_PL_OA, + [ilog2(AMDGPU_GEM_DOMAIN_DOORBELL)] = AMDGPU_PL_DOORBELL, + }; struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct ttm_resource *res = bo->tbo.resource; + struct drm_gem_object *obj = &bo->tbo.base; uint64_t size = amdgpu_bo_size(bo); - struct drm_gem_object *obj; - bool shared; + unsigned int type; + + if (!res) { + /* + * If no backing store use one of the preferred domain for basic + * stats. We take the MSB since that should give a reasonable + * view. + */ + BUILD_BUG_ON(TTM_PL_VRAM < TTM_PL_TT || + TTM_PL_VRAM < TTM_PL_SYSTEM); + type = fls(bo->preferred_domains & AMDGPU_GEM_DOMAIN_MASK); + if (!type) + return; + type--; + if (drm_WARN_ON_ONCE(&adev->ddev, + type >= ARRAY_SIZE(domain_to_pl))) + return; + type = domain_to_pl[type]; + } else { + type = res->mem_type; + } - /* Abort if the BO doesn't currently have a backing store */ - if (!res) + if (drm_WARN_ON_ONCE(&adev->ddev, type >= sz)) return; - obj = &bo->tbo.base; - shared = drm_gem_object_is_shared_for_memory_stats(obj); - - switch (res->mem_type) { - case TTM_PL_VRAM: - stats->vram += size; - if (amdgpu_res_cpu_visible(adev, res)) - stats->visible_vram += size; - if (shared) - stats->vram_shared += size; - break; - case TTM_PL_TT: - stats->gtt += size; - if (shared) - stats->gtt_shared += size; - break; - case TTM_PL_SYSTEM: - default: - stats->cpu += size; - if (shared) - stats->cpu_shared += size; - break; + /* DRM stats common fields: */ + + if (drm_gem_object_is_shared_for_memory_stats(obj)) + stats[type].drm.shared += size; + else + stats[type].drm.private += size; + + if (res) { + stats[type].drm.resident += size; + + if (!dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_BOOKKEEP)) + stats[type].drm.active += size; + else if (bo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) + stats[type].drm.purgeable += size; } + /* amdgpu specific stats: */ + if (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) { - stats->requested_vram += size; - if (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) - stats->requested_visible_vram += size; - - if (res->mem_type != TTM_PL_VRAM) { - stats->evicted_vram += size; - if (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) - stats->evicted_visible_vram += size; - } + stats[TTM_PL_VRAM].requested += size; + if (type != TTM_PL_VRAM) + stats[TTM_PL_VRAM].evicted += size; } else if (bo->preferred_domains & AMDGPU_GEM_DOMAIN_GTT) { - stats->requested_gtt += size; + stats[TTM_PL_TT].requested += size; } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 717e47b46167a4..be6769852ece4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -139,33 +139,6 @@ struct amdgpu_bo_vm { struct amdgpu_vm_bo_base entries[]; }; -struct amdgpu_mem_stats { - /* current VRAM usage, includes visible VRAM */ - uint64_t vram; - /* current shared VRAM usage, includes visible VRAM */ - uint64_t vram_shared; - /* current visible VRAM usage */ - uint64_t visible_vram; - /* current GTT usage */ - uint64_t gtt; - /* current shared GTT usage */ - uint64_t gtt_shared; - /* current system memory usage */ - uint64_t cpu; - /* current shared system memory usage */ - uint64_t cpu_shared; - /* sum of evicted buffers, includes visible VRAM */ - uint64_t evicted_vram; - /* sum of evicted buffers due to CPU access */ - uint64_t evicted_visible_vram; - /* how much userspace asked for, includes vis.VRAM */ - uint64_t requested_vram; - /* how much userspace asked for */ - uint64_t requested_visible_vram; - /* how much userspace asked for */ - uint64_t requested_gtt; -}; - static inline struct amdgpu_bo *ttm_to_amdgpu_bo(struct ttm_buffer_object *tbo) { return container_of(tbo, struct amdgpu_bo, tbo); @@ -328,7 +301,8 @@ int amdgpu_bo_sync_wait(struct amdgpu_bo *bo, void *owner, bool intr); u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo); u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo); void amdgpu_bo_get_memory(struct amdgpu_bo *bo, - struct amdgpu_mem_stats *stats); + struct amdgpu_mem_stats *stats, + unsigned int size); uint32_t amdgpu_bo_get_preferred_domain(struct amdgpu_device *adev, uint32_t domain); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c index e8adfd0a570a2b..34b5e22b44e5f2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c @@ -137,7 +137,8 @@ void amdgpu_preempt_mgr_fini(struct amdgpu_device *adev) if (ret) return; - device_remove_file(adev->dev, &dev_attr_mem_info_preempt_used); + if (adev->dev->kobj.sd) + device_remove_file(adev->dev, &dev_attr_mem_info_preempt_used); ttm_resource_manager_cleanup(man); ttm_set_driver_manager(&adev->mman.bdev, AMDGPU_PL_PREEMPT, NULL); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 0b28b2cf1517d1..448f9e742983f3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -159,9 +159,9 @@ static int psp_init_sriov_microcode(struct psp_context *psp) return ret; } -static int psp_early_init(void *handle) +static int psp_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; psp->autoload_supported = true; @@ -421,9 +421,9 @@ static bool psp_get_runtime_db_entry(struct amdgpu_device *adev, return ret; } -static int psp_sw_init(void *handle) +static int psp_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; int ret; struct psp_runtime_boot_cfg_entry boot_cfg_entry; @@ -527,9 +527,9 @@ static int psp_sw_init(void *handle) return ret; } -static int psp_sw_fini(void *handle) +static int psp_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; struct psp_gfx_cmd_resp *cmd = psp->cmd; @@ -639,6 +639,8 @@ static const char *psp_gfx_cmd_name(enum psp_gfx_cmd_id cmd_id) return "AUTOLOAD_RLC"; case GFX_CMD_ID_BOOT_CFG: return "BOOT_CFG"; + case GFX_CMD_ID_CONFIG_SQ_PERFMON: + return "CONFIG_SQ_PERFMON"; default: return "UNKNOWN CMD"; } @@ -1043,6 +1045,31 @@ static int psp_rl_load(struct amdgpu_device *adev) return ret; } +int psp_memory_partition(struct psp_context *psp, int mode) +{ + struct psp_gfx_cmd_resp *cmd; + int ret; + + if (amdgpu_sriov_vf(psp->adev)) + return 0; + + cmd = acquire_psp_cmd_buf(psp); + + cmd->cmd_id = GFX_CMD_ID_FB_NPS_MODE; + cmd->cmd.cmd_memory_part.mode = mode; + + dev_info(psp->adev->dev, + "Requesting %d memory partition change through PSP", mode); + ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + if (ret) + dev_err(psp->adev->dev, + "PSP request failed to change to NPS%d mode\n", mode); + + release_psp_cmd_buf(psp); + + return ret; +} + int psp_spatial_partition(struct psp_context *psp, int mode) { struct psp_gfx_cmd_resp *cmd; @@ -1807,6 +1834,9 @@ int psp_ras_initialize(struct psp_context *psp) ras_cmd->ras_in_message.init_flags.xcc_mask = adev->gfx.xcc_mask; ras_cmd->ras_in_message.init_flags.channel_dis_num = hweight32(adev->gmc.m_half_use) * 2; + if (adev->gmc.gmc_funcs->query_mem_partition_mode) + ras_cmd->ras_in_message.init_flags.nps_mode = + adev->gmc.gmc_funcs->query_mem_partition_mode(adev); ret = psp_ta_load(psp, &psp->ras_context.context); @@ -2264,6 +2294,19 @@ bool amdgpu_psp_get_ras_capability(struct psp_context *psp) } } +bool amdgpu_psp_tos_reload_needed(struct amdgpu_device *adev) +{ + struct psp_context *psp = &adev->psp; + + if (amdgpu_sriov_vf(adev) || (adev->flags & AMD_IS_APU)) + return false; + + if (psp->funcs && psp->funcs->is_reload_needed) + return psp->funcs->is_reload_needed(psp); + + return false; +} + static int psp_hw_start(struct psp_context *psp) { struct amdgpu_device *adev = psp->adev; @@ -2958,10 +3001,10 @@ static int psp_load_fw(struct amdgpu_device *adev) return ret; } -static int psp_hw_init(void *handle) +static int psp_hw_init(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; mutex_lock(&adev->firmware.mutex); /* @@ -2987,9 +3030,9 @@ static int psp_hw_init(void *handle) return -EINVAL; } -static int psp_hw_fini(void *handle) +static int psp_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; if (psp->ta_fw) { @@ -3011,10 +3054,10 @@ static int psp_hw_fini(void *handle) return 0; } -static int psp_suspend(void *handle) +static int psp_suspend(struct amdgpu_ip_block *ip_block) { int ret = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; if (adev->gmc.xgmi.num_physical_nodes > 1 && @@ -3074,10 +3117,10 @@ static int psp_suspend(void *handle) return ret; } -static int psp_resume(void *handle) +static int psp_resume(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct psp_context *psp = &adev->psp; dev_info(adev->dev, "PSP is resuming...\n"); @@ -3523,6 +3566,36 @@ int psp_init_sos_microcode(struct psp_context *psp, const char *chip_name) return err; } +static bool is_ta_fw_applicable(struct psp_context *psp, + const struct psp_fw_bin_desc *desc) +{ + struct amdgpu_device *adev = psp->adev; + uint32_t fw_version; + + switch (desc->fw_type) { + case TA_FW_TYPE_PSP_XGMI: + case TA_FW_TYPE_PSP_XGMI_AUX: + /* for now, AUX TA only exists on 13.0.6 ta bin, + * from v20.00.0x.14 + */ + if (amdgpu_ip_version(adev, MP0_HWIP, 0) == + IP_VERSION(13, 0, 6)) { + fw_version = le32_to_cpu(desc->fw_version); + + if (adev->flags & AMD_IS_APU && + (fw_version & 0xff) >= 0x14) + return desc->fw_type == TA_FW_TYPE_PSP_XGMI_AUX; + else + return desc->fw_type == TA_FW_TYPE_PSP_XGMI; + } + break; + default: + break; + } + + return true; +} + static int parse_ta_bin_descriptor(struct psp_context *psp, const struct psp_fw_bin_desc *desc, const struct ta_firmware_header_v2_0 *ta_hdr) @@ -3532,6 +3605,9 @@ static int parse_ta_bin_descriptor(struct psp_context *psp, if (!psp || !desc || !ta_hdr) return -EINVAL; + if (!is_ta_fw_applicable(psp, desc)) + return 0; + ucode_start_addr = (uint8_t *)ta_hdr + le32_to_cpu(desc->offset_bytes) + le32_to_cpu(ta_hdr->header.ucode_array_offset_bytes); @@ -3544,6 +3620,7 @@ static int parse_ta_bin_descriptor(struct psp_context *psp, psp->asd_context.bin_desc.start_addr = ucode_start_addr; break; case TA_FW_TYPE_PSP_XGMI: + case TA_FW_TYPE_PSP_XGMI_AUX: psp->xgmi_context.context.bin_desc.fw_version = le32_to_cpu(desc->fw_version); psp->xgmi_context.context.bin_desc.size_bytes = le32_to_cpu(desc->size_bytes); psp->xgmi_context.context.bin_desc.start_addr = ucode_start_addr; @@ -3736,8 +3813,44 @@ int psp_init_cap_microcode(struct psp_context *psp, const char *chip_name) return err; } +int psp_config_sq_perfmon(struct psp_context *psp, + uint32_t xcp_id, bool core_override_enable, + bool reg_override_enable, bool perfmon_override_enable) +{ + int ret; + + if (amdgpu_sriov_vf(psp->adev)) + return 0; + + if (xcp_id > MAX_XCP) { + dev_err(psp->adev->dev, "invalid xcp_id %d\n", xcp_id); + return -EINVAL; + } + + if (amdgpu_ip_version(psp->adev, MP0_HWIP, 0) != IP_VERSION(13, 0, 6)) { + dev_err(psp->adev->dev, "Unsupported MP0 version 0x%x for CONFIG_SQ_PERFMON command\n", + amdgpu_ip_version(psp->adev, MP0_HWIP, 0)); + return -EINVAL; + } + struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp); + + cmd->cmd_id = GFX_CMD_ID_CONFIG_SQ_PERFMON; + cmd->cmd.config_sq_perfmon.gfx_xcp_mask = BIT_MASK(xcp_id); + cmd->cmd.config_sq_perfmon.core_override = core_override_enable; + cmd->cmd.config_sq_perfmon.reg_override = reg_override_enable; + cmd->cmd.config_sq_perfmon.perfmon_override = perfmon_override_enable; + + ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr); + if (ret) + dev_warn(psp->adev->dev, "PSP failed to config sq: xcp%d core%d reg%d perfmon%d\n", + xcp_id, core_override_enable, reg_override_enable, perfmon_override_enable); + + release_psp_cmd_buf(psp); + return ret; +} + static int psp_set_clockgating_state(void *handle, - enum amd_clockgating_state state) + enum amd_clockgating_state state) { return 0; } @@ -3999,7 +4112,7 @@ static umode_t amdgpu_flash_attr_is_visible(struct kobject *kobj, struct attribu } static umode_t amdgpu_bin_flash_attr_is_visible(struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, int idx) { struct device *dev = kobj_to_dev(kobj); @@ -4019,17 +4132,12 @@ const struct attribute_group amdgpu_flash_attr_group = { const struct amd_ip_funcs psp_ip_funcs = { .name = "psp", .early_init = psp_early_init, - .late_init = NULL, .sw_init = psp_sw_init, .sw_fini = psp_sw_fini, .hw_init = psp_hw_init, .hw_fini = psp_hw_fini, .suspend = psp_suspend, .resume = psp_resume, - .is_idle = NULL, - .check_soft_reset = NULL, - .wait_for_idle = NULL, - .soft_reset = NULL, .set_clockgating_state = psp_set_clockgating_state, .set_powergating_state = psp_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h index e8abbbcb432662..567cb1f924ca89 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h @@ -139,6 +139,7 @@ struct psp_funcs { int (*fatal_error_recovery_quirk)(struct psp_context *psp); bool (*get_ras_capability)(struct psp_context *psp); bool (*is_aux_sos_load_required)(struct psp_context *psp); + bool (*is_reload_needed)(struct psp_context *psp); }; struct ta_funcs { @@ -552,9 +553,15 @@ int psp_load_fw_list(struct psp_context *psp, void psp_copy_fw(struct psp_context *psp, uint8_t *start_addr, uint32_t bin_size); int psp_spatial_partition(struct psp_context *psp, int mode); +int psp_memory_partition(struct psp_context *psp, int mode); int is_psp_fw_valid(struct psp_bin_desc bin); int amdgpu_psp_wait_for_bootloader(struct amdgpu_device *adev); bool amdgpu_psp_get_ras_capability(struct psp_context *psp); + +int psp_config_sq_perfmon(struct psp_context *psp, uint32_t xcp_id, + bool core_override_enable, bool reg_override_enable, bool perfmon_override_enable); +bool amdgpu_psp_tos_reload_needed(struct amdgpu_device *adev); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 1a1395c5fff15a..4c9fa24dd9726a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -1214,6 +1214,42 @@ static void amdgpu_ras_error_generate_report(struct amdgpu_device *adev, } } +static void amdgpu_ras_virt_error_generate_report(struct amdgpu_device *adev, + struct ras_query_if *query_if, + struct ras_err_data *err_data, + struct ras_query_context *qctx) +{ + unsigned long new_ue, new_ce, new_de; + struct ras_manager *obj = amdgpu_ras_find_obj(adev, &query_if->head); + const char *blk_name = get_ras_block_str(&query_if->head); + u64 event_id = qctx->evid.event_id; + + new_ce = err_data->ce_count - obj->err_data.ce_count; + new_ue = err_data->ue_count - obj->err_data.ue_count; + new_de = err_data->de_count - obj->err_data.de_count; + + if (new_ce) { + RAS_EVENT_LOG(adev, event_id, "%lu correctable hardware errors " + "detected in %s block\n", + new_ce, + blk_name); + } + + if (new_ue) { + RAS_EVENT_LOG(adev, event_id, "%lu uncorrectable hardware errors " + "detected in %s block\n", + new_ue, + blk_name); + } + + if (new_de) { + RAS_EVENT_LOG(adev, event_id, "%lu deferred hardware errors " + "detected in %s block\n", + new_de, + blk_name); + } +} + static void amdgpu_rasmgr_error_data_statistic_update(struct ras_manager *obj, struct ras_err_data *err_data) { struct ras_err_node *err_node; @@ -1237,6 +1273,15 @@ static void amdgpu_rasmgr_error_data_statistic_update(struct ras_manager *obj, s } } +static void amdgpu_ras_mgr_virt_error_data_statistics_update(struct ras_manager *obj, + struct ras_err_data *err_data) +{ + /* Host reports absolute counts */ + obj->err_data.ue_count = err_data->ue_count; + obj->err_data.ce_count = err_data->ce_count; + obj->err_data.de_count = err_data->de_count; +} + static struct ras_manager *get_ras_manager(struct amdgpu_device *adev, enum amdgpu_ras_block blk) { struct ras_common_if head; @@ -1253,7 +1298,7 @@ int amdgpu_ras_bind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk, struct ras_manager *obj; /* in resume phase, no need to create aca fs node */ - if (adev->in_suspend || amdgpu_in_reset(adev)) + if (adev->in_suspend || amdgpu_reset_in_recovery(adev)) return 0; obj = get_ras_manager(adev, blk); @@ -1323,7 +1368,9 @@ static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, if (error_query_mode == AMDGPU_RAS_INVALID_ERROR_QUERY) return -EINVAL; - if (error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) { + if (error_query_mode == AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY) { + return amdgpu_virt_req_ras_err_count(adev, blk, err_data); + } else if (error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) { if (info->head.block == AMDGPU_RAS_BLOCK__UMC) { amdgpu_ras_get_ecc_info(adev, err_data); } else { @@ -1405,14 +1452,22 @@ static int amdgpu_ras_query_error_status_with_event(struct amdgpu_device *adev, if (ret) goto out_fini_err_data; - amdgpu_rasmgr_error_data_statistic_update(obj, &err_data); + if (error_query_mode != AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY) { + amdgpu_rasmgr_error_data_statistic_update(obj, &err_data); + amdgpu_ras_error_generate_report(adev, info, &err_data, &qctx); + } else { + /* Host provides absolute error counts. First generate the report + * using the previous VF internal count against new host count. + * Then Update VF internal count. + */ + amdgpu_ras_virt_error_generate_report(adev, info, &err_data, &qctx); + amdgpu_ras_mgr_virt_error_data_statistics_update(obj, &err_data); + } info->ue_count = obj->err_data.ue_count; info->ce_count = obj->err_data.ce_count; info->de_count = obj->err_data.de_count; - amdgpu_ras_error_generate_report(adev, info, &err_data, &qctx); - out_fini_err_data: amdgpu_ras_error_data_fini(&err_data); @@ -2605,6 +2660,7 @@ static void amdgpu_ras_do_recovery(struct work_struct *work) reset_context.method = AMD_RESET_METHOD_NONE; reset_context.reset_req_dev = adev; reset_context.src = AMDGPU_RESET_SRC_RAS; + set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags); /* Perform full reset in fatal error mode */ if (!amdgpu_ras_is_poison_mode_supported(ras->adev)) @@ -3146,7 +3202,42 @@ static int amdgpu_ras_page_retirement_thread(void *param) return 0; } -int amdgpu_ras_recovery_init(struct amdgpu_device *adev) +int amdgpu_ras_init_badpage_info(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + int ret; + + if (!con || amdgpu_sriov_vf(adev)) + return 0; + + ret = amdgpu_ras_eeprom_init(&con->eeprom_control); + + if (ret) + return ret; + + /* HW not usable */ + if (amdgpu_ras_is_rma(adev)) + return -EHWPOISON; + + if (con->eeprom_control.ras_num_recs) { + ret = amdgpu_ras_load_bad_pages(adev); + if (ret) + return ret; + + amdgpu_dpm_send_hbm_bad_pages_num( + adev, con->eeprom_control.ras_num_recs); + + if (con->update_channel_flag == true) { + amdgpu_dpm_send_hbm_bad_channel_flag( + adev, con->eeprom_control.bad_channel_bitmap); + con->update_channel_flag = false; + } + } + + return ret; +} + +int amdgpu_ras_recovery_init(struct amdgpu_device *adev, bool init_bp_info) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct ras_err_handler_data **data; @@ -3181,31 +3272,10 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) max_eeprom_records_count = amdgpu_ras_eeprom_max_record_count(&con->eeprom_control); amdgpu_ras_validate_threshold(adev, max_eeprom_records_count); - /* Todo: During test the SMU might fail to read the eeprom through I2C - * when the GPU is pending on XGMI reset during probe time - * (Mostly after second bus reset), skip it now - */ - if (adev->gmc.xgmi.pending_reset) - return 0; - ret = amdgpu_ras_eeprom_init(&con->eeprom_control); - /* - * This calling fails when is_rma is true or - * ret != 0. - */ - if (amdgpu_ras_is_rma(adev) || ret) - goto free; - - if (con->eeprom_control.ras_num_recs) { - ret = amdgpu_ras_load_bad_pages(adev); + if (init_bp_info) { + ret = amdgpu_ras_init_badpage_info(adev); if (ret) goto free; - - amdgpu_dpm_send_hbm_bad_pages_num(adev, con->eeprom_control.ras_num_recs); - - if (con->update_channel_flag == true) { - amdgpu_dpm_send_hbm_bad_channel_flag(adev, con->eeprom_control.bad_channel_bitmap); - con->update_channel_flag = false; - } } mutex_init(&con->page_rsv_lock); @@ -3438,6 +3508,11 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev) if (!amdgpu_ras_asic_supported(adev)) return; + if (amdgpu_sriov_vf(adev)) { + if (amdgpu_virt_get_ras_capability(adev)) + goto init_ras_enabled_flag; + } + /* query ras capability from psp */ if (amdgpu_psp_get_ras_capability(&adev->psp)) goto init_ras_enabled_flag; @@ -3535,7 +3610,7 @@ static void amdgpu_ras_event_mgr_init(struct amdgpu_device *adev) ras->event_mgr = hive ? &hive->event_mgr : &ras->__event_mgr; /* init event manager with node 0 on xgmi system */ - if (!amdgpu_in_reset(adev)) { + if (!amdgpu_reset_in_recovery(adev)) { if (!hive || adev->gmc.xgmi.node_id == 0) ras_event_mgr_init(ras->event_mgr); } @@ -3750,7 +3825,7 @@ int amdgpu_ras_block_late_init(struct amdgpu_device *adev, r = amdgpu_ras_feature_enable_on_boot(adev, ras_block, 1); if (r) { - if (adev->in_suspend || amdgpu_in_reset(adev)) { + if (adev->in_suspend || amdgpu_reset_in_recovery(adev)) { /* in resume phase, if fail to enable ras, * clean up all ras fs nodes, and disable ras */ goto cleanup; @@ -3762,7 +3837,7 @@ int amdgpu_ras_block_late_init(struct amdgpu_device *adev, amdgpu_persistent_edc_harvesting(adev, ras_block); /* in resume phase, no need to create ras fs node */ - if (adev->in_suspend || amdgpu_in_reset(adev)) + if (adev->in_suspend || amdgpu_reset_in_recovery(adev)) return 0; ras_obj = container_of(ras_block, struct amdgpu_ras_block_object, ras_comm); @@ -3892,7 +3967,7 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev) amdgpu_ras_event_mgr_init(adev); if (amdgpu_ras_aca_is_supported(adev)) { - if (amdgpu_in_reset(adev)) { + if (amdgpu_reset_in_recovery(adev)) { if (amdgpu_aca_is_enabled(adev)) r = amdgpu_aca_reset(adev); else @@ -3910,7 +3985,7 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev) } /* Guest side doesn't need init ras feature */ - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_ras_telemetry_en(adev)) return 0; list_for_each_entry_safe(node, tmp, &adev->ras_list, node) { @@ -4294,8 +4369,27 @@ int amdgpu_ras_reset_gpu(struct amdgpu_device *adev) ras->gpu_reset_flags |= AMDGPU_RAS_GPU_RESET_MODE1_RESET; } - if (atomic_cmpxchg(&ras->in_recovery, 0, 1) == 0) + if (atomic_cmpxchg(&ras->in_recovery, 0, 1) == 0) { + struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev); + int hive_ras_recovery = 0; + + if (hive) { + hive_ras_recovery = atomic_read(&hive->ras_recovery); + amdgpu_put_xgmi_hive(hive); + } + /* In the case of multiple GPUs, after a GPU has started + * resetting all GPUs on hive, other GPUs do not need to + * trigger GPU reset again. + */ + if (!hive_ras_recovery) + amdgpu_reset_domain_schedule(ras->adev->reset_domain, &ras->recovery_work); + else + atomic_set(&ras->in_recovery, 0); + } else { + flush_work(&ras->recovery_work); amdgpu_reset_domain_schedule(ras->adev->reset_domain, &ras->recovery_work); + } + return 0; } @@ -4358,11 +4452,14 @@ bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev, return false; } - if ((smu_funcs && smu_funcs->set_debug_mode) || (mca_funcs && mca_funcs->mca_set_debug_mode)) + if (amdgpu_sriov_vf(adev)) { + *error_query_mode = AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY; + } else if ((smu_funcs && smu_funcs->set_debug_mode) || (mca_funcs && mca_funcs->mca_set_debug_mode)) { *error_query_mode = (con->is_aca_debug_mode) ? AMDGPU_RAS_DIRECT_ERROR_QUERY : AMDGPU_RAS_FIRMWARE_ERROR_QUERY; - else + } else { *error_query_mode = AMDGPU_RAS_DIRECT_ERROR_QUERY; + } return true; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index 669720a9c60afd..6db772ecfee47f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -365,6 +365,7 @@ enum amdgpu_ras_error_query_mode { AMDGPU_RAS_INVALID_ERROR_QUERY = 0, AMDGPU_RAS_DIRECT_ERROR_QUERY = 1, AMDGPU_RAS_FIRMWARE_ERROR_QUERY = 2, + AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY = 3, }; /* ras error status reisger fields */ @@ -736,8 +737,8 @@ struct amdgpu_ras_block_hw_ops { * 8: feature disable */ - -int amdgpu_ras_recovery_init(struct amdgpu_device *adev); +int amdgpu_ras_init_badpage_info(struct amdgpu_device *adev); +int amdgpu_ras_recovery_init(struct amdgpu_device *adev, bool init_bp_info); void amdgpu_ras_resume(struct amdgpu_device *adev); void amdgpu_ras_suspend(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c index 66c1a868c0e16b..a0acb65f4b40af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.c @@ -26,6 +26,156 @@ #include "sienna_cichlid.h" #include "smu_v13_0_10.h" +static int amdgpu_reset_xgmi_reset_on_init_suspend(struct amdgpu_device *adev) +{ + int i; + + for (i = adev->num_ip_blocks - 1; i >= 0; i--) { + if (!adev->ip_blocks[i].status.valid) + continue; + if (!adev->ip_blocks[i].status.hw) + continue; + /* displays are handled in phase1 */ + if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) + continue; + + /* XXX handle errors */ + amdgpu_ip_block_suspend(&adev->ip_blocks[i]); + adev->ip_blocks[i].status.hw = false; + } + + /* VCN FW shared region is in frambuffer, there are some flags + * initialized in that region during sw_init. Make sure the region is + * backed up. + */ + amdgpu_vcn_save_vcpu_bo(adev); + + return 0; +} + +static int amdgpu_reset_xgmi_reset_on_init_prep_hwctxt( + struct amdgpu_reset_control *reset_ctl, + struct amdgpu_reset_context *reset_context) +{ + struct list_head *reset_device_list = reset_context->reset_device_list; + struct amdgpu_device *tmp_adev; + int r; + + list_for_each_entry(tmp_adev, reset_device_list, reset_list) { + amdgpu_unregister_gpu_instance(tmp_adev); + r = amdgpu_reset_xgmi_reset_on_init_suspend(tmp_adev); + if (r) { + dev_err(tmp_adev->dev, + "xgmi reset on init: prepare for reset failed"); + return r; + } + } + + return r; +} + +static int amdgpu_reset_xgmi_reset_on_init_restore_hwctxt( + struct amdgpu_reset_control *reset_ctl, + struct amdgpu_reset_context *reset_context) +{ + struct list_head *reset_device_list = reset_context->reset_device_list; + struct amdgpu_device *tmp_adev = NULL; + int r; + + r = amdgpu_device_reinit_after_reset(reset_context); + if (r) + return r; + list_for_each_entry(tmp_adev, reset_device_list, reset_list) { + if (!tmp_adev->kfd.init_complete) { + kgd2kfd_init_zone_device(tmp_adev); + amdgpu_amdkfd_device_init(tmp_adev); + amdgpu_amdkfd_drm_client_create(tmp_adev); + } + } + + return r; +} + +static int amdgpu_reset_xgmi_reset_on_init_perform_reset( + struct amdgpu_reset_control *reset_ctl, + struct amdgpu_reset_context *reset_context) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)reset_ctl->handle; + struct list_head *reset_device_list = reset_context->reset_device_list; + struct amdgpu_device *tmp_adev = NULL; + int r; + + dev_dbg(adev->dev, "xgmi roi - hw reset\n"); + + list_for_each_entry(tmp_adev, reset_device_list, reset_list) { + mutex_lock(&tmp_adev->reset_cntl->reset_lock); + tmp_adev->reset_cntl->active_reset = + amdgpu_asic_reset_method(adev); + } + r = 0; + /* Mode1 reset needs to be triggered on all devices together */ + list_for_each_entry(tmp_adev, reset_device_list, reset_list) { + /* For XGMI run all resets in parallel to speed up the process */ + if (!queue_work(system_unbound_wq, &tmp_adev->xgmi_reset_work)) + r = -EALREADY; + if (r) { + dev_err(tmp_adev->dev, + "xgmi reset on init: reset failed with error, %d", + r); + break; + } + } + + /* For XGMI wait for all resets to complete before proceed */ + if (!r) { + list_for_each_entry(tmp_adev, reset_device_list, reset_list) { + flush_work(&tmp_adev->xgmi_reset_work); + r = tmp_adev->asic_reset_res; + if (r) + break; + } + } + + list_for_each_entry(tmp_adev, reset_device_list, reset_list) { + mutex_unlock(&tmp_adev->reset_cntl->reset_lock); + tmp_adev->reset_cntl->active_reset = AMD_RESET_METHOD_NONE; + } + + return r; +} + +int amdgpu_reset_do_xgmi_reset_on_init( + struct amdgpu_reset_context *reset_context) +{ + struct list_head *reset_device_list = reset_context->reset_device_list; + struct amdgpu_device *adev; + int r; + + if (!reset_device_list || list_empty(reset_device_list) || + list_is_singular(reset_device_list)) + return -EINVAL; + + adev = list_first_entry(reset_device_list, struct amdgpu_device, + reset_list); + r = amdgpu_reset_prepare_hwcontext(adev, reset_context); + if (r) + return r; + + r = amdgpu_reset_perform_reset(adev, reset_context); + + return r; +} + +struct amdgpu_reset_handler xgmi_reset_on_init_handler = { + .reset_method = AMD_RESET_METHOD_ON_INIT, + .prepare_env = NULL, + .prepare_hwcontext = amdgpu_reset_xgmi_reset_on_init_prep_hwctxt, + .perform_reset = amdgpu_reset_xgmi_reset_on_init_perform_reset, + .restore_hwcontext = amdgpu_reset_xgmi_reset_on_init_restore_hwctxt, + .restore_env = NULL, + .do_reset = NULL, +}; + int amdgpu_reset_init(struct amdgpu_device *adev) { int ret = 0; @@ -192,3 +342,8 @@ void amdgpu_reset_get_desc(struct amdgpu_reset_context *rst_ctxt, char *buf, strscpy(buf, "unknown", len); } } + +bool amdgpu_reset_in_recovery(struct amdgpu_device *adev) +{ + return (adev->init_lvl->level == AMDGPU_INIT_LEVEL_RESET_RECOVERY); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h index 1cb920abc2fe9e..4d9b9701139be5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h @@ -153,4 +153,11 @@ void amdgpu_reset_get_desc(struct amdgpu_reset_context *rst_ctxt, char *buf, for (i = 0; (i < AMDGPU_RESET_MAX_HANDLERS) && \ (handler = (*reset_ctl->reset_handlers)[i]); \ ++i) + +extern struct amdgpu_reset_handler xgmi_reset_on_init_handler; +int amdgpu_reset_do_xgmi_reset_on_init( + struct amdgpu_reset_context *reset_context); + +bool amdgpu_reset_in_recovery(struct amdgpu_device *adev); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 690976665cf699..a6e28fe3f8d66b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -108,10 +108,22 @@ int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned int ndw) */ void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) { - int i; + uint32_t occupied, chunk1, chunk2; - for (i = 0; i < count; i++) - amdgpu_ring_write(ring, ring->funcs->nop); + occupied = ring->wptr & ring->buf_mask; + chunk1 = ring->buf_mask + 1 - occupied; + chunk1 = (chunk1 >= count) ? count : chunk1; + chunk2 = count - chunk1; + + if (chunk1) + memset32(&ring->ring[occupied], ring->funcs->nop, chunk1); + + if (chunk2) + memset32(ring->ring, ring->funcs->nop, chunk2); + + ring->wptr += count; + ring->wptr &= ring->ptr_mask; + ring->count_dw -= count; } /** @@ -141,6 +153,9 @@ void amdgpu_ring_commit(struct amdgpu_ring *ring) { uint32_t count; + if (ring->count_dw < 0) + DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n"); + /* We pad to match fetch size */ count = ring->funcs->align_mask + 1 - (ring->wptr & ring->funcs->align_mask); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index f93f5100220182..36fc9578c53c03 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -246,7 +246,7 @@ struct amdgpu_ring { struct drm_gpu_scheduler sched; struct amdgpu_bo *ring_obj; - volatile uint32_t *ring; + uint32_t *ring; unsigned rptr_offs; u64 rptr_gpu_addr; volatile u32 *rptr_cpu_addr; @@ -288,7 +288,7 @@ struct amdgpu_ring { u64 cond_exe_gpu_addr; volatile u32 *cond_exe_cpu_addr; unsigned int set_q_mode_offs; - volatile u32 *set_q_mode_ptr; + u32 *set_q_mode_ptr; u64 set_q_mode_token; unsigned vm_hub; unsigned vm_inv_eng; @@ -377,8 +377,6 @@ static inline void amdgpu_ring_clear_ring(struct amdgpu_ring *ring) static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v) { - if (ring->count_dw <= 0) - DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n"); ring->ring[ring->wptr++ & ring->buf_mask] = v; ring->wptr &= ring->ptr_mask; ring->count_dw--; @@ -388,13 +386,8 @@ static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring, void *src, int count_dw) { unsigned occupied, chunk1, chunk2; - void *dst; - - if (unlikely(ring->count_dw < count_dw)) - DRM_ERROR("amdgpu: writing more dwords to the ring than expected!\n"); occupied = ring->wptr & ring->buf_mask; - dst = (void *)&ring->ring[occupied]; chunk1 = ring->buf_mask + 1 - occupied; chunk1 = (chunk1 >= count_dw) ? count_dw : chunk1; chunk2 = count_dw - chunk1; @@ -402,12 +395,11 @@ static inline void amdgpu_ring_write_multiple(struct amdgpu_ring *ring, chunk2 <<= 2; if (chunk1) - memcpy(dst, src, chunk1); + memcpy(&ring->ring[occupied], src, chunk1); if (chunk2) { src += chunk1; - dst = (void *)ring->ring; - memcpy(dst, src, chunk2); + memcpy(ring->ring, src, chunk2); } ring->wptr += count_dw; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index b0a8abc7a8ecfd..341beec595375c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -35,21 +35,19 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, int fd, int32_t priority) { - struct fd f = fdget(fd); + CLASS(fd, f)(fd); struct amdgpu_fpriv *fpriv; struct amdgpu_ctx_mgr *mgr; struct amdgpu_ctx *ctx; uint32_t id; int r; - if (!fd_file(f)) + if (fd_empty(f)) return -EINVAL; r = amdgpu_file_to_fpriv(fd_file(f), &fpriv); - if (r) { - fdput(f); + if (r) return r; - } mgr = &fpriv->ctx_mgr; mutex_lock(&mgr->lock); @@ -57,7 +55,6 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, amdgpu_ctx_priority_override(ctx, priority); mutex_unlock(&mgr->lock); - fdput(f); return 0; } @@ -66,31 +63,25 @@ static int amdgpu_sched_context_priority_override(struct amdgpu_device *adev, unsigned ctx_id, int32_t priority) { - struct fd f = fdget(fd); + CLASS(fd, f)(fd); struct amdgpu_fpriv *fpriv; struct amdgpu_ctx *ctx; int r; - if (!fd_file(f)) + if (fd_empty(f)) return -EINVAL; r = amdgpu_file_to_fpriv(fd_file(f), &fpriv); - if (r) { - fdput(f); + if (r) return r; - } ctx = amdgpu_ctx_get(fpriv, ctx_id); - if (!ctx) { - fdput(f); + if (!ctx) return -EINVAL; - } amdgpu_ctx_priority_override(ctx, priority); amdgpu_ctx_put(ctx); - fdput(f); - return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c index 183a976ba29dd0..113f0d2426187e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c @@ -343,3 +343,116 @@ int amdgpu_sdma_ras_sw_init(struct amdgpu_device *adev) return 0; } + +/* + * debugfs for to enable/disable sdma job submission to specific core. + */ +#if defined(CONFIG_DEBUG_FS) +static int amdgpu_debugfs_sdma_sched_mask_set(void *data, u64 val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + u32 i; + u64 mask = 0; + struct amdgpu_ring *ring; + + if (!adev) + return -ENODEV; + + mask = (1 << adev->sdma.num_instances) - 1; + if ((val & mask) == 0) + return -EINVAL; + + for (i = 0; i < adev->sdma.num_instances; ++i) { + ring = &adev->sdma.instance[i].ring; + if (val & (1 << i)) + ring->sched.ready = true; + else + ring->sched.ready = false; + } + /* publish sched.ready flag update effective immediately across smp */ + smp_rmb(); + return 0; +} + +static int amdgpu_debugfs_sdma_sched_mask_get(void *data, u64 *val) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)data; + u32 i; + u64 mask = 0; + struct amdgpu_ring *ring; + + if (!adev) + return -ENODEV; + for (i = 0; i < adev->sdma.num_instances; ++i) { + ring = &adev->sdma.instance[i].ring; + if (ring->sched.ready) + mask |= 1 << i; + } + + *val = mask; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_sdma_sched_mask_fops, + amdgpu_debugfs_sdma_sched_mask_get, + amdgpu_debugfs_sdma_sched_mask_set, "%llx\n"); + +#endif + +void amdgpu_debugfs_sdma_sched_mask_init(struct amdgpu_device *adev) +{ +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = adev_to_drm(adev)->primary; + struct dentry *root = minor->debugfs_root; + char name[32]; + + if (!(adev->sdma.num_instances > 1)) + return; + sprintf(name, "amdgpu_sdma_sched_mask"); + debugfs_create_file(name, 0600, root, adev, + &amdgpu_debugfs_sdma_sched_mask_fops); +#endif +} + +static ssize_t amdgpu_get_sdma_reset_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (!adev) + return -ENODEV; + + return amdgpu_show_reset_mask(buf, adev->sdma.supported_reset); +} + +static DEVICE_ATTR(sdma_reset_mask, 0444, + amdgpu_get_sdma_reset_mask, NULL); + +int amdgpu_sdma_sysfs_reset_mask_init(struct amdgpu_device *adev) +{ + int r = 0; + + if (!amdgpu_gpu_recovery) + return r; + + if (adev->sdma.num_instances) { + r = device_create_file(adev->dev, &dev_attr_sdma_reset_mask); + if (r) + return r; + } + + return r; +} + +void amdgpu_sdma_sysfs_reset_mask_fini(struct amdgpu_device *adev) +{ + if (!amdgpu_gpu_recovery) + return; + + if (adev->dev->kobj.sd) { + if (adev->sdma.num_instances) + device_remove_file(adev->dev, &dev_attr_sdma_reset_mask); + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h index 087ce0f6fa0763..2db58b5812a892 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h @@ -116,6 +116,7 @@ struct amdgpu_sdma { struct ras_common_if *ras_if; struct amdgpu_sdma_ras *ras; uint32_t *ip_dump; + uint32_t supported_reset; }; /* @@ -175,5 +176,7 @@ int amdgpu_sdma_init_microcode(struct amdgpu_device *adev, u32 instance, void amdgpu_sdma_destroy_inst_ctx(struct amdgpu_device *adev, bool duplicate); int amdgpu_sdma_ras_sw_init(struct amdgpu_device *adev); - +void amdgpu_debugfs_sdma_sched_mask_init(struct amdgpu_device *adev); +int amdgpu_sdma_sysfs_reset_mask_init(struct amdgpu_device *adev); +void amdgpu_sdma_sysfs_reset_mask_fini(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 74adb983ab03e0..c8180cad0abdd8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -61,7 +61,7 @@ #include "amdgpu_res_cursor.h" #include "bif/bif_4_1_d.h" -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); #define AMDGPU_TTM_VRAM_MAX_DW_READ ((size_t)128) @@ -812,7 +812,7 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev, /* Map SG to device */ r = dma_map_sgtable(adev->dev, ttm->sg, direction, 0); if (r) - goto release_sg; + goto release_sg_table; /* convert SG to linear array of pages and dma addresses */ drm_prime_sg_to_dma_addr_array(ttm->sg, gtt->ttm.dma_address, @@ -820,6 +820,8 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev, return 0; +release_sg_table: + sg_free_table(ttm->sg); release_sg: kfree(ttm->sg); ttm->sg = NULL; @@ -1849,6 +1851,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) mutex_init(&adev->mman.gtt_window_lock); + dma_set_max_seg_size(adev->dev, UINT_MAX); /* No others user of address space so set it to 0 */ r = ttm_device_init(&adev->mman.bdev, &amdgpu_bo_driver, adev->dev, adev_to_drm(adev)->anon_inode->i_mapping, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 138d80017f3564..2852a6064c9ac5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -34,6 +34,7 @@ #define AMDGPU_PL_OA (TTM_PL_PRIV + 2) #define AMDGPU_PL_PREEMPT (TTM_PL_PRIV + 3) #define AMDGPU_PL_DOORBELL (TTM_PL_PRIV + 4) +#define __AMDGPU_PL_LAST (TTM_PL_PRIV + 4) #define AMDGPU_GTT_MAX_TRANSFER_SIZE 512 #define AMDGPU_GTT_NUM_TRANSFER_WINDOWS 2 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 4e23419b92d4eb..4150ec0aa10d65 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -163,6 +163,7 @@ enum ta_fw_type { TA_FW_TYPE_PSP_DTM, TA_FW_TYPE_PSP_RAP, TA_FW_TYPE_PSP_SECUREDISPLAY, + TA_FW_TYPE_PSP_XGMI_AUX, TA_FW_TYPE_MAX_INDEX, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index bb7b9b2eaac1a5..896f3609b0eedd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -318,6 +318,9 @@ int amdgpu_umc_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *r if (r) return r; + if (amdgpu_sriov_vf(adev)) + return r; + if (amdgpu_ras_is_supported(adev, ras_block->block)) { r = amdgpu_irq_get(adev, &adev->gmc.ecc_irq, 0); if (r) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c index 6162582d0aa272..bd2d3863c3ed1f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c @@ -765,9 +765,9 @@ static int umsch_mm_init(struct amdgpu_device *adev) } -static int umsch_mm_early_init(void *handle) +static int umsch_mm_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; switch (amdgpu_ip_version(adev, VCN_HWIP, 0)) { case IP_VERSION(4, 0, 5): @@ -784,9 +784,9 @@ static int umsch_mm_early_init(void *handle) return 0; } -static int umsch_mm_late_init(void *handle) +static int umsch_mm_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_in_reset(adev) || adev->in_s0ix || adev->in_suspend) return 0; @@ -794,9 +794,9 @@ static int umsch_mm_late_init(void *handle) return umsch_mm_test(adev); } -static int umsch_mm_sw_init(void *handle) +static int umsch_mm_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = umsch_mm_init(adev); @@ -815,9 +815,9 @@ static int umsch_mm_sw_init(void *handle) return 0; } -static int umsch_mm_sw_fini(void *handle) +static int umsch_mm_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; release_firmware(adev->umsch_mm.fw); adev->umsch_mm.fw = NULL; @@ -839,9 +839,9 @@ static int umsch_mm_sw_fini(void *handle) return 0; } -static int umsch_mm_hw_init(void *handle) +static int umsch_mm_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = umsch_mm_load_microcode(&adev->umsch_mm); @@ -857,9 +857,9 @@ static int umsch_mm_hw_init(void *handle) return 0; } -static int umsch_mm_hw_fini(void *handle) +static int umsch_mm_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; umsch_mm_ring_stop(&adev->umsch_mm); @@ -873,18 +873,14 @@ static int umsch_mm_hw_fini(void *handle) return 0; } -static int umsch_mm_suspend(void *handle) +static int umsch_mm_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return umsch_mm_hw_fini(adev); + return umsch_mm_hw_fini(ip_block); } -static int umsch_mm_resume(void *handle) +static int umsch_mm_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return umsch_mm_hw_init(adev); + return umsch_mm_hw_init(ip_block); } void amdgpu_umsch_fwlog_init(struct amdgpu_umsch_mm *umsch_mm) @@ -997,8 +993,6 @@ static const struct amd_ip_funcs umsch_mm_v4_0_ip_funcs = { .hw_fini = umsch_mm_hw_fini, .suspend = umsch_mm_suspend, .resume = umsch_mm_resume, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version umsch_mm_v4_0_ip_block = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 31fd30dcd593ba..65bb26215e867a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -551,6 +551,8 @@ static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo) for (i = 0; i < abo->placement.num_placement; ++i) { abo->placements[i].fpfn = 0 >> PAGE_SHIFT; abo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; + if (abo->placements[i].mem_type == TTM_PL_VRAM) + abo->placements[i].flags |= TTM_PL_FLAG_CONTIGUOUS; } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 74fdbf71d95b74..599d3ca4e0ef9e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -214,15 +214,15 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev) drm_sched_entity_destroy(&adev->vce.entity); - amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr, - (void **)&adev->vce.cpu_addr); - for (i = 0; i < adev->vce.num_rings; i++) amdgpu_ring_fini(&adev->vce.ring[i]); amdgpu_ucode_release(&adev->vce.fw); mutex_destroy(&adev->vce.idle_mutex); + amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr, + (void **)&adev->vce.cpu_addr); + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 43f44cc201cb80..3e94c3ba1ba2cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -294,21 +294,12 @@ bool amdgpu_vcn_is_disabled_vcn(struct amdgpu_device *adev, enum vcn_ring_type t return ret; } -int amdgpu_vcn_suspend(struct amdgpu_device *adev) +int amdgpu_vcn_save_vcpu_bo(struct amdgpu_device *adev) { unsigned int size; void *ptr; int i, idx; - bool in_ras_intr = amdgpu_ras_intr_triggered(); - - cancel_delayed_work_sync(&adev->vcn.idle_work); - - /* err_event_athub will corrupt VCPU buffer, so we need to - * restore fw data and clear buffer in amdgpu_vcn_resume() */ - if (in_ras_intr) - return 0; - for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { if (adev->vcn.harvest_config & (1 << i)) continue; @@ -327,9 +318,24 @@ int amdgpu_vcn_suspend(struct amdgpu_device *adev) drm_dev_exit(idx); } } + return 0; } +int amdgpu_vcn_suspend(struct amdgpu_device *adev) +{ + bool in_ras_intr = amdgpu_ras_intr_triggered(); + + cancel_delayed_work_sync(&adev->vcn.idle_work); + + /* err_event_athub will corrupt VCPU buffer, so we need to + * restore fw data and clear buffer in amdgpu_vcn_resume() */ + if (in_ras_intr) + return 0; + + return amdgpu_vcn_save_vcpu_bo(adev); +} + int amdgpu_vcn_resume(struct amdgpu_device *adev) { unsigned int size; @@ -1277,3 +1283,40 @@ int amdgpu_vcn_psp_update_sram(struct amdgpu_device *adev, int inst_idx, return psp_execute_ip_fw_load(&adev->psp, &ucode); } + +static ssize_t amdgpu_get_vcn_reset_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (!adev) + return -ENODEV; + + return amdgpu_show_reset_mask(buf, adev->vcn.supported_reset); +} + +static DEVICE_ATTR(vcn_reset_mask, 0444, + amdgpu_get_vcn_reset_mask, NULL); + +int amdgpu_vcn_sysfs_reset_mask_init(struct amdgpu_device *adev) +{ + int r = 0; + + if (adev->vcn.num_vcn_inst) { + r = device_create_file(adev->dev, &dev_attr_vcn_reset_mask); + if (r) + return r; + } + + return r; +} + +void amdgpu_vcn_sysfs_reset_mask_fini(struct amdgpu_device *adev) +{ + if (adev->dev->kobj.sd) { + if (adev->vcn.num_vcn_inst) + device_remove_file(adev->dev, &dev_attr_vcn_reset_mask); + } +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 2a1f3dbb14d3f4..1e32311c1dff73 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -333,6 +333,8 @@ struct amdgpu_vcn { /* IP reg dump */ uint32_t *ip_dump; + + uint32_t supported_reset; }; struct amdgpu_fw_shared_rb_ptrs_struct { @@ -518,5 +520,8 @@ int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev); int amdgpu_vcn_psp_update_sram(struct amdgpu_device *adev, int inst_idx, enum AMDGPU_UCODE_ID ucode_id); +int amdgpu_vcn_save_vcpu_bo(struct amdgpu_device *adev); +int amdgpu_vcn_sysfs_reset_mask_init(struct amdgpu_device *adev); +void amdgpu_vcn_sysfs_reset_mask_fini(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index b6397d3229e1ba..c704e9803e1107 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -523,6 +523,9 @@ static int amdgpu_virt_read_pf2vf_data(struct amdgpu_device *adev) adev->unique_id = ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->uuid; + adev->virt.ras_en_caps.all = ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->ras_en_caps.all; + adev->virt.ras_telemetry_en_caps.all = + ((struct amd_sriov_msg_pf2vf_info *)pf2vf_info)->ras_telemetry_en_caps.all; break; default: dev_err(adev->dev, "invalid pf2vf version: 0x%x\n", pf2vf_info->version); @@ -703,6 +706,8 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev) adev->virt.fw_reserve.p_vf2pf = (struct amd_sriov_msg_vf2pf_info_header *) (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10)); + adev->virt.fw_reserve.ras_telemetry = + (adev->mman.fw_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB << 10)); } else if (adev->mman.drv_vram_usage_va) { adev->virt.fw_reserve.p_pf2vf = (struct amd_sriov_msg_pf2vf_info_header *) @@ -710,6 +715,8 @@ void amdgpu_virt_exchange_data(struct amdgpu_device *adev) adev->virt.fw_reserve.p_vf2pf = (struct amd_sriov_msg_vf2pf_info_header *) (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_VF2PF_OFFSET_KB << 10)); + adev->virt.fw_reserve.ras_telemetry = + (adev->mman.drv_vram_usage_va + (AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB << 10)); } amdgpu_virt_read_pf2vf_data(adev); @@ -1144,3 +1151,185 @@ bool amdgpu_sriov_xnack_support(struct amdgpu_device *adev) return xnack_mode; } + +bool amdgpu_virt_get_ras_capability(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + + if (!amdgpu_sriov_ras_caps_en(adev)) + return false; + + if (adev->virt.ras_en_caps.bits.block_umc) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__UMC); + if (adev->virt.ras_en_caps.bits.block_sdma) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__SDMA); + if (adev->virt.ras_en_caps.bits.block_gfx) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__GFX); + if (adev->virt.ras_en_caps.bits.block_mmhub) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__MMHUB); + if (adev->virt.ras_en_caps.bits.block_athub) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__ATHUB); + if (adev->virt.ras_en_caps.bits.block_pcie_bif) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__PCIE_BIF); + if (adev->virt.ras_en_caps.bits.block_hdp) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__HDP); + if (adev->virt.ras_en_caps.bits.block_xgmi_wafl) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__XGMI_WAFL); + if (adev->virt.ras_en_caps.bits.block_df) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__DF); + if (adev->virt.ras_en_caps.bits.block_smn) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__SMN); + if (adev->virt.ras_en_caps.bits.block_sem) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__SEM); + if (adev->virt.ras_en_caps.bits.block_mp0) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__MP0); + if (adev->virt.ras_en_caps.bits.block_mp1) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__MP1); + if (adev->virt.ras_en_caps.bits.block_fuse) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__FUSE); + if (adev->virt.ras_en_caps.bits.block_mca) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__MCA); + if (adev->virt.ras_en_caps.bits.block_vcn) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__VCN); + if (adev->virt.ras_en_caps.bits.block_jpeg) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__JPEG); + if (adev->virt.ras_en_caps.bits.block_ih) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__IH); + if (adev->virt.ras_en_caps.bits.block_mpio) + adev->ras_hw_enabled |= BIT(AMDGPU_RAS_BLOCK__MPIO); + + if (adev->virt.ras_en_caps.bits.poison_propogation_mode) + con->poison_supported = true; /* Poison is handled by host */ + + return true; +} + +static inline enum amd_sriov_ras_telemetry_gpu_block +amdgpu_ras_block_to_sriov(struct amdgpu_device *adev, enum amdgpu_ras_block block) { + switch (block) { + case AMDGPU_RAS_BLOCK__UMC: + return RAS_TELEMETRY_GPU_BLOCK_UMC; + case AMDGPU_RAS_BLOCK__SDMA: + return RAS_TELEMETRY_GPU_BLOCK_SDMA; + case AMDGPU_RAS_BLOCK__GFX: + return RAS_TELEMETRY_GPU_BLOCK_GFX; + case AMDGPU_RAS_BLOCK__MMHUB: + return RAS_TELEMETRY_GPU_BLOCK_MMHUB; + case AMDGPU_RAS_BLOCK__ATHUB: + return RAS_TELEMETRY_GPU_BLOCK_ATHUB; + case AMDGPU_RAS_BLOCK__PCIE_BIF: + return RAS_TELEMETRY_GPU_BLOCK_PCIE_BIF; + case AMDGPU_RAS_BLOCK__HDP: + return RAS_TELEMETRY_GPU_BLOCK_HDP; + case AMDGPU_RAS_BLOCK__XGMI_WAFL: + return RAS_TELEMETRY_GPU_BLOCK_XGMI_WAFL; + case AMDGPU_RAS_BLOCK__DF: + return RAS_TELEMETRY_GPU_BLOCK_DF; + case AMDGPU_RAS_BLOCK__SMN: + return RAS_TELEMETRY_GPU_BLOCK_SMN; + case AMDGPU_RAS_BLOCK__SEM: + return RAS_TELEMETRY_GPU_BLOCK_SEM; + case AMDGPU_RAS_BLOCK__MP0: + return RAS_TELEMETRY_GPU_BLOCK_MP0; + case AMDGPU_RAS_BLOCK__MP1: + return RAS_TELEMETRY_GPU_BLOCK_MP1; + case AMDGPU_RAS_BLOCK__FUSE: + return RAS_TELEMETRY_GPU_BLOCK_FUSE; + case AMDGPU_RAS_BLOCK__MCA: + return RAS_TELEMETRY_GPU_BLOCK_MCA; + case AMDGPU_RAS_BLOCK__VCN: + return RAS_TELEMETRY_GPU_BLOCK_VCN; + case AMDGPU_RAS_BLOCK__JPEG: + return RAS_TELEMETRY_GPU_BLOCK_JPEG; + case AMDGPU_RAS_BLOCK__IH: + return RAS_TELEMETRY_GPU_BLOCK_IH; + case AMDGPU_RAS_BLOCK__MPIO: + return RAS_TELEMETRY_GPU_BLOCK_MPIO; + default: + dev_err(adev->dev, "Unsupported SRIOV RAS telemetry block 0x%x\n", block); + return RAS_TELEMETRY_GPU_BLOCK_COUNT; + } +} + +static int amdgpu_virt_cache_host_error_counts(struct amdgpu_device *adev, + struct amdsriov_ras_telemetry *host_telemetry) +{ + struct amd_sriov_ras_telemetry_error_count *tmp = NULL; + uint32_t checksum, used_size; + + checksum = host_telemetry->header.checksum; + used_size = host_telemetry->header.used_size; + + if (used_size > (AMD_SRIOV_RAS_TELEMETRY_SIZE_KB << 10)) + return 0; + + tmp = kmalloc(used_size, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + memcpy(tmp, &host_telemetry->body.error_count, used_size); + + if (checksum != amd_sriov_msg_checksum(tmp, used_size, 0, 0)) + goto out; + + memcpy(&adev->virt.count_cache, tmp, + min(used_size, sizeof(adev->virt.count_cache))); +out: + kfree(tmp); + + return 0; +} + +static int amdgpu_virt_req_ras_err_count_internal(struct amdgpu_device *adev, bool force_update) +{ + struct amdgpu_virt *virt = &adev->virt; + + /* Host allows 15 ras telemetry requests per 60 seconds. Afterwhich, the Host + * will ignore incoming guest messages. Ratelimit the guest messages to + * prevent guest self DOS. + */ + if (__ratelimit(&adev->virt.ras_telemetry_rs) || force_update) { + if (!virt->ops->req_ras_err_count(adev)) + amdgpu_virt_cache_host_error_counts(adev, + adev->virt.fw_reserve.ras_telemetry); + } + + return 0; +} + +/* Bypass ACA interface and query ECC counts directly from host */ +int amdgpu_virt_req_ras_err_count(struct amdgpu_device *adev, enum amdgpu_ras_block block, + struct ras_err_data *err_data) +{ + enum amd_sriov_ras_telemetry_gpu_block sriov_block; + + sriov_block = amdgpu_ras_block_to_sriov(adev, block); + + if (sriov_block >= RAS_TELEMETRY_GPU_BLOCK_COUNT || + !amdgpu_sriov_ras_telemetry_block_en(adev, sriov_block)) + return -EOPNOTSUPP; + + /* Host Access may be lost during reset, just return last cached data. */ + if (down_read_trylock(&adev->reset_domain->sem)) { + amdgpu_virt_req_ras_err_count_internal(adev, false); + up_read(&adev->reset_domain->sem); + } + + err_data->ue_count = adev->virt.count_cache.block[sriov_block].ue_count; + err_data->ce_count = adev->virt.count_cache.block[sriov_block].ce_count; + err_data->de_count = adev->virt.count_cache.block[sriov_block].de_count; + + return 0; +} + +int amdgpu_virt_ras_telemetry_post_reset(struct amdgpu_device *adev) +{ + unsigned long ue_count, ce_count; + + if (amdgpu_sriov_ras_telemetry_en(adev)) { + amdgpu_virt_req_ras_err_count_internal(adev, true); + amdgpu_ras_query_error_count(adev, &ce_count, &ue_count, NULL); + } + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h index b650a2032c42bd..5381b8d596e622 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.h @@ -95,6 +95,7 @@ struct amdgpu_virt_ops { void (*ras_poison_handler)(struct amdgpu_device *adev, enum amdgpu_ras_block block); bool (*rcvd_ras_intr)(struct amdgpu_device *adev); + int (*req_ras_err_count)(struct amdgpu_device *adev); }; /* @@ -103,6 +104,7 @@ struct amdgpu_virt_ops { struct amdgpu_virt_fw_reserve { struct amd_sriov_msg_pf2vf_info_header *p_pf2vf; struct amd_sriov_msg_vf2pf_info_header *p_vf2pf; + void *ras_telemetry; unsigned int checksum_key; }; @@ -136,6 +138,8 @@ enum AMDGIM_FEATURE_FLAG { AMDGIM_FEATURE_VCN_RB_DECOUPLE = (1 << 7), /* MES info */ AMDGIM_FEATURE_MES_INFO_ENABLE = (1 << 8), + AMDGIM_FEATURE_RAS_CAPS = (1 << 9), + AMDGIM_FEATURE_RAS_TELEMETRY = (1 << 10), }; enum AMDGIM_REG_ACCESS_FLAG { @@ -276,6 +280,12 @@ struct amdgpu_virt { uint32_t autoload_ucode_id; struct mutex rlcg_reg_lock; + + union amd_sriov_ras_caps ras_en_caps; + union amd_sriov_ras_caps ras_telemetry_en_caps; + + struct ratelimit_state ras_telemetry_rs; + struct amd_sriov_ras_telemetry_error_count count_cache; }; struct amdgpu_video_codec_info; @@ -320,6 +330,15 @@ struct amdgpu_video_codec_info; #define amdgpu_sriov_vf_mmio_access_protection(adev) \ ((adev)->virt.caps & AMDGPU_VF_MMIO_ACCESS_PROTECT) +#define amdgpu_sriov_ras_caps_en(adev) \ +((adev)->virt.gim_feature & AMDGIM_FEATURE_RAS_CAPS) + +#define amdgpu_sriov_ras_telemetry_en(adev) \ +(((adev)->virt.gim_feature & AMDGIM_FEATURE_RAS_TELEMETRY) && (adev)->virt.fw_reserve.ras_telemetry) + +#define amdgpu_sriov_ras_telemetry_block_en(adev, sriov_blk) \ +(amdgpu_sriov_ras_telemetry_en((adev)) && (adev)->virt.ras_telemetry_en_caps.all & BIT(sriov_blk)) + static inline bool is_virtual_machine(void) { #if defined(CONFIG_X86) @@ -383,4 +402,8 @@ bool amdgpu_virt_get_rlcg_reg_access_flag(struct amdgpu_device *adev, u32 acc_flags, u32 hwip, bool write, u32 *rlcg_flag); u32 amdgpu_virt_rlcg_reg_rw(struct amdgpu_device *adev, u32 offset, u32 v, u32 flag, u32 xcc_id); +bool amdgpu_virt_get_ras_capability(struct amdgpu_device *adev); +int amdgpu_virt_req_ras_err_count(struct amdgpu_device *adev, enum amdgpu_ras_block block, + struct ras_err_data *err_data); +int amdgpu_virt_ras_telemetry_post_reset(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c index d4c2afafbb73cc..8bf28d33680753 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c @@ -493,10 +493,10 @@ const struct drm_mode_config_funcs amdgpu_vkms_mode_funcs = { .atomic_commit = drm_atomic_helper_commit, }; -static int amdgpu_vkms_sw_init(void *handle) +static int amdgpu_vkms_sw_init(struct amdgpu_ip_block *ip_block) { int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->amdgpu_vkms_output = kcalloc(adev->mode_info.num_crtc, sizeof(struct amdgpu_vkms_output), GFP_KERNEL); @@ -536,9 +536,9 @@ static int amdgpu_vkms_sw_init(void *handle) return 0; } -static int amdgpu_vkms_sw_fini(void *handle) +static int amdgpu_vkms_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i = 0; for (i = 0; i < adev->mode_info.num_crtc; i++) @@ -555,9 +555,9 @@ static int amdgpu_vkms_sw_fini(void *handle) return 0; } -static int amdgpu_vkms_hw_init(void *handle) +static int amdgpu_vkms_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; switch (adev->asic_type) { #ifdef CONFIG_DRM_AMDGPU_SI @@ -600,31 +600,31 @@ static int amdgpu_vkms_hw_init(void *handle) return 0; } -static int amdgpu_vkms_hw_fini(void *handle) +static int amdgpu_vkms_hw_fini(struct amdgpu_ip_block *ip_block) { return 0; } -static int amdgpu_vkms_suspend(void *handle) +static int amdgpu_vkms_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = drm_mode_config_helper_suspend(adev_to_drm(adev)); if (r) return r; - return amdgpu_vkms_hw_fini(handle); + + return 0; } -static int amdgpu_vkms_resume(void *handle) +static int amdgpu_vkms_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_vkms_hw_init(handle); + r = amdgpu_vkms_hw_init(ip_block); if (r) return r; - return drm_mode_config_helper_resume(adev_to_drm(adev)); + return drm_mode_config_helper_resume(adev_to_drm(ip_block->adev)); } static bool amdgpu_vkms_is_idle(void *handle) @@ -632,16 +632,6 @@ static bool amdgpu_vkms_is_idle(void *handle) return true; } -static int amdgpu_vkms_wait_for_idle(void *handle) -{ - return 0; -} - -static int amdgpu_vkms_soft_reset(void *handle) -{ - return 0; -} - static int amdgpu_vkms_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -656,8 +646,6 @@ static int amdgpu_vkms_set_powergating_state(void *handle, static const struct amd_ip_funcs amdgpu_vkms_ip_funcs = { .name = "amdgpu_vkms", - .early_init = NULL, - .late_init = NULL, .sw_init = amdgpu_vkms_sw_init, .sw_fini = amdgpu_vkms_sw_fini, .hw_init = amdgpu_vkms_hw_init, @@ -665,12 +653,8 @@ static const struct amd_ip_funcs amdgpu_vkms_ip_funcs = { .suspend = amdgpu_vkms_suspend, .resume = amdgpu_vkms_resume, .is_idle = amdgpu_vkms_is_idle, - .wait_for_idle = amdgpu_vkms_wait_for_idle, - .soft_reset = amdgpu_vkms_soft_reset, .set_clockgating_state = amdgpu_vkms_set_clockgating_state, .set_powergating_state = amdgpu_vkms_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version amdgpu_vkms_ip_block = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 6005280f5f38f0..c9c48b782ec1b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -674,12 +674,8 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, pasid_mapping_needed &= adev->gmc.gmc_funcs->emit_pasid_mapping && ring->funcs->emit_wreg; - if (adev->gfx.enable_cleaner_shader && - ring->funcs->emit_cleaner_shader && - job->enforce_isolation) - ring->funcs->emit_cleaner_shader(ring); - - if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync) + if (!vm_flush_needed && !gds_switch_needed && !need_pipe_sync && + !(job->enforce_isolation && !job->vmid)) return 0; amdgpu_ring_ib_begin(ring); @@ -690,6 +686,11 @@ int amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_job *job, if (need_pipe_sync) amdgpu_ring_emit_pipeline_sync(ring); + if (adev->gfx.enable_cleaner_shader && + ring->funcs->emit_cleaner_shader && + job->enforce_isolation) + ring->funcs->emit_cleaner_shader(ring); + if (vm_flush_needed) { trace_amdgpu_vm_flush(ring, job->vmid, job->vm_pd_addr); amdgpu_ring_emit_vm_flush(ring, job->vmid, job->vm_pd_addr); @@ -1083,7 +1084,8 @@ int amdgpu_vm_update_range(struct amdgpu_device *adev, struct amdgpu_vm *vm, } static void amdgpu_vm_bo_get_memory(struct amdgpu_bo_va *bo_va, - struct amdgpu_mem_stats *stats) + struct amdgpu_mem_stats *stats, + unsigned int size) { struct amdgpu_vm *vm = bo_va->base.vm; struct amdgpu_bo *bo = bo_va->base.bo; @@ -1099,34 +1101,35 @@ static void amdgpu_vm_bo_get_memory(struct amdgpu_bo_va *bo_va, !dma_resv_trylock(bo->tbo.base.resv)) return; - amdgpu_bo_get_memory(bo, stats); + amdgpu_bo_get_memory(bo, stats, size); if (!amdgpu_vm_is_bo_always_valid(vm, bo)) dma_resv_unlock(bo->tbo.base.resv); } void amdgpu_vm_get_memory(struct amdgpu_vm *vm, - struct amdgpu_mem_stats *stats) + struct amdgpu_mem_stats *stats, + unsigned int size) { struct amdgpu_bo_va *bo_va, *tmp; spin_lock(&vm->status_lock); list_for_each_entry_safe(bo_va, tmp, &vm->idle, base.vm_status) - amdgpu_vm_bo_get_memory(bo_va, stats); + amdgpu_vm_bo_get_memory(bo_va, stats, size); list_for_each_entry_safe(bo_va, tmp, &vm->evicted, base.vm_status) - amdgpu_vm_bo_get_memory(bo_va, stats); + amdgpu_vm_bo_get_memory(bo_va, stats, size); list_for_each_entry_safe(bo_va, tmp, &vm->relocated, base.vm_status) - amdgpu_vm_bo_get_memory(bo_va, stats); + amdgpu_vm_bo_get_memory(bo_va, stats, size); list_for_each_entry_safe(bo_va, tmp, &vm->moved, base.vm_status) - amdgpu_vm_bo_get_memory(bo_va, stats); + amdgpu_vm_bo_get_memory(bo_va, stats, size); list_for_each_entry_safe(bo_va, tmp, &vm->invalidated, base.vm_status) - amdgpu_vm_bo_get_memory(bo_va, stats); + amdgpu_vm_bo_get_memory(bo_va, stats, size); list_for_each_entry_safe(bo_va, tmp, &vm->done, base.vm_status) - amdgpu_vm_bo_get_memory(bo_va, stats); + amdgpu_vm_bo_get_memory(bo_va, stats, size); spin_unlock(&vm->status_lock); } @@ -1159,7 +1162,7 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, int r; amdgpu_sync_create(&sync); - if (clear || !bo) { + if (clear) { mem = NULL; /* Implicitly sync to command submissions in the same VM before @@ -1174,6 +1177,10 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, if (r) goto error_free; } + } else if (!bo) { + mem = NULL; + + /* PRT map operations don't need to sync to anything. */ } else { struct drm_gem_object *obj = &bo->tbo.base; @@ -1259,10 +1266,9 @@ int amdgpu_vm_bo_update(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va, * next command submission. */ if (amdgpu_vm_is_bo_always_valid(vm, bo)) { - uint32_t mem_type = bo->tbo.resource->mem_type; - - if (!(bo->preferred_domains & - amdgpu_mem_type_to_domain(mem_type))) + if (bo->tbo.resource && + !(bo->preferred_domains & + amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type))) amdgpu_vm_bo_evicted(&bo_va->base); else amdgpu_vm_bo_idle(&bo_va->base); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 52dd7cdfdc8145..5d119ac26c4fe4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -42,7 +42,6 @@ struct amdgpu_bo_va; struct amdgpu_job; struct amdgpu_bo_list_entry; struct amdgpu_bo_vm; -struct amdgpu_mem_stats; /* * GPUVM handling @@ -322,6 +321,16 @@ struct amdgpu_vm_fault_info { unsigned int vmhub; }; +struct amdgpu_mem_stats { + struct drm_memory_stats drm; + + /* buffers that requested this placement */ + uint64_t requested; + /* buffers that requested this placement + * but are currently evicted */ + uint64_t evicted; +}; + struct amdgpu_vm { /* tree of virtual addresses mapped */ struct rb_root_cached va; @@ -567,7 +576,8 @@ void amdgpu_vm_set_task_info(struct amdgpu_vm *vm); void amdgpu_vm_move_to_lru_tail(struct amdgpu_device *adev, struct amdgpu_vm *vm); void amdgpu_vm_get_memory(struct amdgpu_vm *vm, - struct amdgpu_mem_stats *stats); + struct amdgpu_mem_stats *stats, + unsigned int size); int amdgpu_vm_pt_clear(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct amdgpu_bo_vm *vmbo, bool immediate); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c index 5acd20ff59797b..110b120d7375d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c @@ -295,9 +295,9 @@ int amdgpu_vpe_ring_fini(struct amdgpu_vpe *vpe) return 0; } -static int vpe_early_init(void *handle) +static int vpe_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_vpe *vpe = &adev->vpe; switch (amdgpu_ip_version(adev, VPE_HWIP, 0)) { @@ -356,9 +356,9 @@ static int vpe_common_init(struct amdgpu_vpe *vpe) return 0; } -static int vpe_sw_init(void *handle) +static int vpe_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_vpe *vpe = &adev->vpe; int ret; @@ -377,18 +377,26 @@ static int vpe_sw_init(void *handle) ret = vpe_init_microcode(vpe); if (ret) goto out; + + /* TODO: Add queue reset mask when FW fully supports it */ + adev->vpe.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->vpe.ring); + ret = amdgpu_vpe_sysfs_reset_mask_init(adev); + if (ret) + goto out; out: return ret; } -static int vpe_sw_fini(void *handle) +static int vpe_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_vpe *vpe = &adev->vpe; release_firmware(vpe->fw); vpe->fw = NULL; + amdgpu_vpe_sysfs_reset_mask_fini(adev); vpe_ring_fini(vpe); amdgpu_bo_free_kernel(&adev->vpe.cmdbuf_obj, @@ -398,9 +406,9 @@ static int vpe_sw_fini(void *handle) return 0; } -static int vpe_hw_init(void *handle) +static int vpe_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_vpe *vpe = &adev->vpe; int ret; @@ -421,9 +429,9 @@ static int vpe_hw_init(void *handle) return 0; } -static int vpe_hw_fini(void *handle) +static int vpe_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_vpe *vpe = &adev->vpe; vpe_ring_stop(vpe); @@ -434,20 +442,18 @@ static int vpe_hw_fini(void *handle) return 0; } -static int vpe_suspend(void *handle) +static int vpe_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->vpe.idle_work); - return vpe_hw_fini(adev); + return vpe_hw_fini(ip_block); } -static int vpe_resume(void *handle) +static int vpe_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return vpe_hw_init(adev); + return vpe_hw_init(ip_block); } static void vpe_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) @@ -867,6 +873,43 @@ static void vpe_ring_end_use(struct amdgpu_ring *ring) schedule_delayed_work(&adev->vpe.idle_work, VPE_IDLE_TIMEOUT); } +static ssize_t amdgpu_get_vpe_reset_mask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (!adev) + return -ENODEV; + + return amdgpu_show_reset_mask(buf, adev->vpe.supported_reset); +} + +static DEVICE_ATTR(vpe_reset_mask, 0444, + amdgpu_get_vpe_reset_mask, NULL); + +int amdgpu_vpe_sysfs_reset_mask_init(struct amdgpu_device *adev) +{ + int r = 0; + + if (adev->vpe.num_instances) { + r = device_create_file(adev->dev, &dev_attr_vpe_reset_mask); + if (r) + return r; + } + + return r; +} + +void amdgpu_vpe_sysfs_reset_mask_fini(struct amdgpu_device *adev) +{ + if (adev->dev->kobj.sd) { + if (adev->vpe.num_instances) + device_remove_file(adev->dev, &dev_attr_vpe_reset_mask); + } +} + static const struct amdgpu_ring_funcs vpe_ring_funcs = { .type = AMDGPU_RING_TYPE_VPE, .align_mask = 0xf, @@ -908,14 +951,12 @@ static void vpe_set_ring_funcs(struct amdgpu_device *adev) const struct amd_ip_funcs vpe_ip_funcs = { .name = "vpe_v6_1", .early_init = vpe_early_init, - .late_init = NULL, .sw_init = vpe_sw_init, .sw_fini = vpe_sw_fini, .hw_init = vpe_hw_init, .hw_fini = vpe_hw_fini, .suspend = vpe_suspend, .resume = vpe_resume, - .soft_reset = NULL, .set_clockgating_state = vpe_set_clockgating_state, .set_powergating_state = vpe_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.h index 231d86d0953e91..695da740a97ea5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.h @@ -79,6 +79,7 @@ struct amdgpu_vpe { uint32_t num_instances; bool collaborate_mode; + uint32_t supported_reset; }; int amdgpu_vpe_psp_update_sram(struct amdgpu_device *adev); @@ -86,6 +87,8 @@ int amdgpu_vpe_init_microcode(struct amdgpu_vpe *vpe); int amdgpu_vpe_ring_init(struct amdgpu_vpe *vpe); int amdgpu_vpe_ring_fini(struct amdgpu_vpe *vpe); int amdgpu_vpe_configure_dpm(struct amdgpu_vpe *vpe); +void amdgpu_vpe_sysfs_reset_mask_fini(struct amdgpu_device *adev); +int amdgpu_vpe_sysfs_reset_mask_init(struct amdgpu_device *adev); #define vpe_ring_init(vpe) ((vpe)->funcs->ring_init ? (vpe)->funcs->ring_init((vpe)) : 0) #define vpe_ring_start(vpe) ((vpe)->funcs->ring_start ? (vpe)->funcs->ring_start((vpe)) : 0) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c index a6d456ec6aeb1a..e209b5e101dfdf 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c @@ -433,3 +433,292 @@ void amdgpu_xcp_release_sched(struct amdgpu_device *adev, } } +#define XCP_CFG_SYSFS_RES_ATTR_SHOW(_name) \ + static ssize_t amdgpu_xcp_res_sysfs_##_name##_show( \ + struct amdgpu_xcp_res_details *xcp_res, char *buf) \ + { \ + return sysfs_emit(buf, "%d\n", xcp_res->_name); \ + } + +struct amdgpu_xcp_res_sysfs_attribute { + struct attribute attr; + ssize_t (*show)(struct amdgpu_xcp_res_details *xcp_res, char *buf); +}; + +#define XCP_CFG_SYSFS_RES_ATTR(_name) \ + struct amdgpu_xcp_res_sysfs_attribute xcp_res_sysfs_attr_##_name = { \ + .attr = { .name = __stringify(_name), .mode = 0400 }, \ + .show = amdgpu_xcp_res_sysfs_##_name##_show, \ + } + +XCP_CFG_SYSFS_RES_ATTR_SHOW(num_inst) +XCP_CFG_SYSFS_RES_ATTR(num_inst); +XCP_CFG_SYSFS_RES_ATTR_SHOW(num_shared) +XCP_CFG_SYSFS_RES_ATTR(num_shared); + +#define XCP_CFG_SYSFS_RES_ATTR_PTR(_name) xcp_res_sysfs_attr_##_name.attr + +static struct attribute *xcp_cfg_res_sysfs_attrs[] = { + &XCP_CFG_SYSFS_RES_ATTR_PTR(num_inst), + &XCP_CFG_SYSFS_RES_ATTR_PTR(num_shared), NULL +}; + +static const char *xcp_desc[] = { + [AMDGPU_SPX_PARTITION_MODE] = "SPX", + [AMDGPU_DPX_PARTITION_MODE] = "DPX", + [AMDGPU_TPX_PARTITION_MODE] = "TPX", + [AMDGPU_QPX_PARTITION_MODE] = "QPX", + [AMDGPU_CPX_PARTITION_MODE] = "CPX", +}; + +static const char *nps_desc[] = { + [UNKNOWN_MEMORY_PARTITION_MODE] = "UNKNOWN", + [AMDGPU_NPS1_PARTITION_MODE] = "NPS1", + [AMDGPU_NPS2_PARTITION_MODE] = "NPS2", + [AMDGPU_NPS3_PARTITION_MODE] = "NPS3", + [AMDGPU_NPS4_PARTITION_MODE] = "NPS4", + [AMDGPU_NPS6_PARTITION_MODE] = "NPS6", + [AMDGPU_NPS8_PARTITION_MODE] = "NPS8", +}; + +ATTRIBUTE_GROUPS(xcp_cfg_res_sysfs); + +#define to_xcp_attr(x) \ + container_of(x, struct amdgpu_xcp_res_sysfs_attribute, attr) +#define to_xcp_res(x) container_of(x, struct amdgpu_xcp_res_details, kobj) + +static ssize_t xcp_cfg_res_sysfs_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct amdgpu_xcp_res_sysfs_attribute *attribute; + struct amdgpu_xcp_res_details *xcp_res; + + attribute = to_xcp_attr(attr); + xcp_res = to_xcp_res(kobj); + + if (!attribute->show) + return -EIO; + + return attribute->show(xcp_res, buf); +} + +static const struct sysfs_ops xcp_cfg_res_sysfs_ops = { + .show = xcp_cfg_res_sysfs_attr_show, +}; + +static const struct kobj_type xcp_cfg_res_sysfs_ktype = { + .sysfs_ops = &xcp_cfg_res_sysfs_ops, + .default_groups = xcp_cfg_res_sysfs_groups, +}; + +const char *xcp_res_names[] = { + [AMDGPU_XCP_RES_XCC] = "xcc", + [AMDGPU_XCP_RES_DMA] = "dma", + [AMDGPU_XCP_RES_DEC] = "dec", + [AMDGPU_XCP_RES_JPEG] = "jpeg", +}; + +static int amdgpu_xcp_get_res_info(struct amdgpu_xcp_mgr *xcp_mgr, + int mode, + struct amdgpu_xcp_cfg *xcp_cfg) +{ + if (xcp_mgr->funcs && xcp_mgr->funcs->get_xcp_res_info) + return xcp_mgr->funcs->get_xcp_res_info(xcp_mgr, mode, xcp_cfg); + + return -EOPNOTSUPP; +} + +#define to_xcp_cfg(x) container_of(x, struct amdgpu_xcp_cfg, kobj) +static ssize_t supported_xcp_configs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct amdgpu_xcp_cfg *xcp_cfg = to_xcp_cfg(kobj); + struct amdgpu_xcp_mgr *xcp_mgr = xcp_cfg->xcp_mgr; + int size = 0, mode; + char *sep = ""; + + if (!xcp_mgr || !xcp_mgr->supp_xcp_modes) + return sysfs_emit(buf, "Not supported\n"); + + for_each_inst(mode, xcp_mgr->supp_xcp_modes) { + size += sysfs_emit_at(buf, size, "%s%s", sep, xcp_desc[mode]); + sep = ", "; + } + + size += sysfs_emit_at(buf, size, "\n"); + + return size; +} + +static ssize_t supported_nps_configs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct amdgpu_xcp_cfg *xcp_cfg = to_xcp_cfg(kobj); + int size = 0, mode; + char *sep = ""; + + if (!xcp_cfg || !xcp_cfg->compatible_nps_modes) + return sysfs_emit(buf, "Not supported\n"); + + for_each_inst(mode, xcp_cfg->compatible_nps_modes) { + size += sysfs_emit_at(buf, size, "%s%s", sep, nps_desc[mode]); + sep = ", "; + } + + size += sysfs_emit_at(buf, size, "\n"); + + return size; +} + +static ssize_t xcp_config_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct amdgpu_xcp_cfg *xcp_cfg = to_xcp_cfg(kobj); + + return sysfs_emit(buf, "%s\n", + amdgpu_gfx_compute_mode_desc(xcp_cfg->mode)); +} + +static ssize_t xcp_config_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t size) +{ + struct amdgpu_xcp_cfg *xcp_cfg = to_xcp_cfg(kobj); + int mode, r; + + if (!strncasecmp("SPX", buf, strlen("SPX"))) + mode = AMDGPU_SPX_PARTITION_MODE; + else if (!strncasecmp("DPX", buf, strlen("DPX"))) + mode = AMDGPU_DPX_PARTITION_MODE; + else if (!strncasecmp("TPX", buf, strlen("TPX"))) + mode = AMDGPU_TPX_PARTITION_MODE; + else if (!strncasecmp("QPX", buf, strlen("QPX"))) + mode = AMDGPU_QPX_PARTITION_MODE; + else if (!strncasecmp("CPX", buf, strlen("CPX"))) + mode = AMDGPU_CPX_PARTITION_MODE; + else + return -EINVAL; + + r = amdgpu_xcp_get_res_info(xcp_cfg->xcp_mgr, mode, xcp_cfg); + + if (r) + return r; + + xcp_cfg->mode = mode; + return size; +} + +static struct kobj_attribute xcp_cfg_sysfs_mode = + __ATTR_RW_MODE(xcp_config, 0644); + +static void xcp_cfg_sysfs_release(struct kobject *kobj) +{ + struct amdgpu_xcp_cfg *xcp_cfg = to_xcp_cfg(kobj); + + kfree(xcp_cfg); +} + +static const struct kobj_type xcp_cfg_sysfs_ktype = { + .release = xcp_cfg_sysfs_release, + .sysfs_ops = &kobj_sysfs_ops, +}; + +static struct kobj_attribute supp_part_sysfs_mode = + __ATTR_RO(supported_xcp_configs); + +static struct kobj_attribute supp_nps_sysfs_mode = + __ATTR_RO(supported_nps_configs); + +static const struct attribute *xcp_attrs[] = { + &supp_part_sysfs_mode.attr, + &xcp_cfg_sysfs_mode.attr, + NULL, +}; + +void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev) +{ + struct amdgpu_xcp_res_details *xcp_res; + struct amdgpu_xcp_cfg *xcp_cfg; + int i, r, j, rid, mode; + + if (!adev->xcp_mgr) + return; + + xcp_cfg = kzalloc(sizeof(*xcp_cfg), GFP_KERNEL); + if (!xcp_cfg) + return; + xcp_cfg->xcp_mgr = adev->xcp_mgr; + + r = kobject_init_and_add(&xcp_cfg->kobj, &xcp_cfg_sysfs_ktype, + &adev->dev->kobj, "compute_partition_config"); + if (r) + goto err1; + + r = sysfs_create_files(&xcp_cfg->kobj, xcp_attrs); + if (r) + goto err1; + + if (adev->gmc.supported_nps_modes != 0) { + r = sysfs_create_file(&xcp_cfg->kobj, &supp_nps_sysfs_mode.attr); + if (r) { + sysfs_remove_files(&xcp_cfg->kobj, xcp_attrs); + goto err1; + } + } + + mode = (xcp_cfg->xcp_mgr->mode == + AMDGPU_UNKNOWN_COMPUTE_PARTITION_MODE) ? + AMDGPU_SPX_PARTITION_MODE : + xcp_cfg->xcp_mgr->mode; + r = amdgpu_xcp_get_res_info(xcp_cfg->xcp_mgr, mode, xcp_cfg); + if (r) { + sysfs_remove_file(&xcp_cfg->kobj, &supp_nps_sysfs_mode.attr); + sysfs_remove_files(&xcp_cfg->kobj, xcp_attrs); + goto err1; + } + + xcp_cfg->mode = mode; + for (i = 0; i < xcp_cfg->num_res; i++) { + xcp_res = &xcp_cfg->xcp_res[i]; + rid = xcp_res->id; + r = kobject_init_and_add(&xcp_res->kobj, + &xcp_cfg_res_sysfs_ktype, + &xcp_cfg->kobj, "%s", + xcp_res_names[rid]); + if (r) + goto err; + } + + adev->xcp_mgr->xcp_cfg = xcp_cfg; + return; +err: + for (j = 0; j < i; j++) { + xcp_res = &xcp_cfg->xcp_res[i]; + kobject_put(&xcp_res->kobj); + } + + sysfs_remove_file(&xcp_cfg->kobj, &supp_nps_sysfs_mode.attr); + sysfs_remove_files(&xcp_cfg->kobj, xcp_attrs); +err1: + kobject_put(&xcp_cfg->kobj); +} + +void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev) +{ + struct amdgpu_xcp_res_details *xcp_res; + struct amdgpu_xcp_cfg *xcp_cfg; + int i; + + if (!adev->xcp_mgr) + return; + + xcp_cfg = adev->xcp_mgr->xcp_cfg; + for (i = 0; i < xcp_cfg->num_res; i++) { + xcp_res = &xcp_cfg->xcp_res[i]; + kobject_put(&xcp_res->kobj); + } + + sysfs_remove_file(&xcp_cfg->kobj, &supp_nps_sysfs_mode.attr); + sysfs_remove_files(&xcp_cfg->kobj, xcp_attrs); + kobject_put(&xcp_cfg->kobj); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h index 32775260556f44..b63f53242c5734 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.h @@ -56,6 +56,30 @@ enum AMDGPU_XCP_STATE { AMDGPU_XCP_RESUME, }; +enum amdgpu_xcp_res_id { + AMDGPU_XCP_RES_XCC, + AMDGPU_XCP_RES_DMA, + AMDGPU_XCP_RES_DEC, + AMDGPU_XCP_RES_JPEG, + AMDGPU_XCP_RES_MAX, +}; + +struct amdgpu_xcp_res_details { + enum amdgpu_xcp_res_id id; + u8 num_inst; + u8 num_shared; + struct kobject kobj; +}; + +struct amdgpu_xcp_cfg { + u8 mode; + struct amdgpu_xcp_res_details xcp_res[AMDGPU_XCP_RES_MAX]; + u8 num_res; + struct amdgpu_xcp_mgr *xcp_mgr; + struct kobject kobj; + u16 compatible_nps_modes; +}; + struct amdgpu_xcp_ip_funcs { int (*prepare_suspend)(void *handle, uint32_t inst_mask); int (*suspend)(void *handle, uint32_t inst_mask); @@ -97,6 +121,9 @@ struct amdgpu_xcp_mgr { /* Used to determine KFD memory size limits per XCP */ unsigned int num_xcp_per_mem_partition; + struct amdgpu_xcp_cfg *xcp_cfg; + uint32_t supp_xcp_modes; + uint32_t avail_xcp_modes; }; struct amdgpu_xcp_mgr_funcs { @@ -108,7 +135,9 @@ struct amdgpu_xcp_mgr_funcs { struct amdgpu_xcp_ip *ip); int (*get_xcp_mem_id)(struct amdgpu_xcp_mgr *xcp_mgr, struct amdgpu_xcp *xcp, uint8_t *mem_id); - + int (*get_xcp_res_info)(struct amdgpu_xcp_mgr *xcp_mgr, + int mode, + struct amdgpu_xcp_cfg *xcp_cfg); int (*prepare_suspend)(struct amdgpu_xcp_mgr *xcp_mgr, int xcp_id); int (*suspend)(struct amdgpu_xcp_mgr *xcp_mgr, int xcp_id); int (*prepare_resume)(struct amdgpu_xcp_mgr *xcp_mgr, int xcp_id); @@ -146,6 +175,9 @@ int amdgpu_xcp_open_device(struct amdgpu_device *adev, void amdgpu_xcp_release_sched(struct amdgpu_device *adev, struct amdgpu_ctx_entity *entity); +void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev); +void amdgpu_xcp_cfg_sysfs_fini(struct amdgpu_device *adev); + #define amdgpu_xcp_select_scheds(adev, e, c, d, x, y) \ ((adev)->xcp_mgr && (adev)->xcp_mgr->funcs && \ (adev)->xcp_mgr->funcs->select_scheds ? \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index 7de449fae1e3ad..74b4349e345a6b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -40,6 +40,11 @@ #define smnPCS_GOPX1_PCS_ERROR_STATUS 0x12200210 #define smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK 0x12200218 +#define XGMI_STATE_DISABLE 0xD1 +#define XGMI_STATE_LS0 0x81 +#define XGMI_LINK_ACTIVE 1 +#define XGMI_LINK_INACTIVE 0 + static DEFINE_MUTEX(xgmi_mutex); #define AMDGPU_MAX_XGMI_DEVICE_PER_HIVE 4 @@ -289,6 +294,42 @@ static const struct amdgpu_pcs_ras_field xgmi3x16_pcs_ras_fields[] = { SOC15_REG_FIELD(PCS_XGMI3X16_PCS_ERROR_STATUS, RxCMDPktErr)}, }; +static u32 xgmi_v6_4_get_link_status(struct amdgpu_device *adev, int global_link_num) +{ + const u32 smnpcs_xgmi3x16_pcs_state_hist1 = 0x11a00070; + const int xgmi_inst = 2; + u32 link_inst; + u64 addr; + + link_inst = global_link_num % xgmi_inst; + + addr = (smnpcs_xgmi3x16_pcs_state_hist1 | (link_inst << 20)) + + adev->asic_funcs->encode_ext_smn_addressing(global_link_num / xgmi_inst); + + return RREG32_PCIE_EXT(addr); +} + +int amdgpu_get_xgmi_link_status(struct amdgpu_device *adev, int global_link_num) +{ + u32 xgmi_state_reg_val; + + switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) { + case IP_VERSION(6, 4, 0): + xgmi_state_reg_val = xgmi_v6_4_get_link_status(adev, global_link_num); + break; + default: + return -EOPNOTSUPP; + } + + if ((xgmi_state_reg_val & 0xFF) == XGMI_STATE_DISABLE) + return -ENOLINK; + + if ((xgmi_state_reg_val & 0xFF) == XGMI_STATE_LS0) + return XGMI_LINK_ACTIVE; + + return XGMI_LINK_INACTIVE; +} + /** * DOC: AMDGPU XGMI Support * @@ -667,6 +708,7 @@ struct amdgpu_hive_info *amdgpu_get_xgmi_hive(struct amdgpu_device *adev) task_barrier_init(&hive->tb); hive->pstate = AMDGPU_XGMI_PSTATE_UNKNOWN; hive->hi_req_gpu = NULL; + atomic_set(&hive->requested_nps_mode, UNKNOWN_MEMORY_PARTITION_MODE); /* * hive pstate on boot is high in vega20 so we have to go to low @@ -800,6 +842,23 @@ int amdgpu_xgmi_get_num_links(struct amdgpu_device *adev, return -EINVAL; } +bool amdgpu_xgmi_get_is_sharing_enabled(struct amdgpu_device *adev, + struct amdgpu_device *peer_adev) +{ + struct psp_xgmi_topology_info *top = &adev->psp.xgmi_context.top_info; + int i; + + /* Sharing should always be enabled for non-SRIOV. */ + if (!amdgpu_sriov_vf(adev)) + return true; + + for (i = 0 ; i < top->num_nodes; ++i) + if (top->nodes[i].node_id == peer_adev->gmc.xgmi.node_id) + return !!top->nodes[i].is_sharing_enabled; + + return false; +} + /* * Devices that support extended data require the entire hive to initialize with * the shared memory buffer flag set. @@ -860,8 +919,7 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) if (!adev->gmc.xgmi.supported) return 0; - if (!adev->gmc.xgmi.pending_reset && - amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_PSP)) { + if (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_PSP)) { ret = psp_xgmi_initialize(&adev->psp, false, true); if (ret) { dev_err(adev->dev, @@ -907,8 +965,7 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) task_barrier_add_task(&hive->tb); - if (!adev->gmc.xgmi.pending_reset && - amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_PSP)) { + if (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_PSP)) { list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { /* update node list for other device in the hive */ if (tmp_adev != adev) { @@ -985,7 +1042,7 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) } } - if (!ret && !adev->gmc.xgmi.pending_reset) + if (!ret) ret = amdgpu_xgmi_sysfs_add_dev_info(adev, hive); exit_unlock: @@ -1500,3 +1557,117 @@ int amdgpu_xgmi_ras_sw_init(struct amdgpu_device *adev) return 0; } + +static void amdgpu_xgmi_reset_on_init_work(struct work_struct *work) +{ + struct amdgpu_hive_info *hive = + container_of(work, struct amdgpu_hive_info, reset_on_init_work); + struct amdgpu_reset_context reset_context; + struct amdgpu_device *tmp_adev; + struct list_head device_list; + int r; + + mutex_lock(&hive->hive_lock); + + INIT_LIST_HEAD(&device_list); + list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) + list_add_tail(&tmp_adev->reset_list, &device_list); + + tmp_adev = list_first_entry(&device_list, struct amdgpu_device, + reset_list); + amdgpu_device_lock_reset_domain(tmp_adev->reset_domain); + + reset_context.method = AMD_RESET_METHOD_ON_INIT; + reset_context.reset_req_dev = tmp_adev; + reset_context.hive = hive; + reset_context.reset_device_list = &device_list; + set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); + set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags); + + amdgpu_reset_do_xgmi_reset_on_init(&reset_context); + mutex_unlock(&hive->hive_lock); + amdgpu_device_unlock_reset_domain(tmp_adev->reset_domain); + + list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { + r = amdgpu_ras_init_badpage_info(tmp_adev); + if (r && r != -EHWPOISON) + dev_err(tmp_adev->dev, + "error during bad page data initialization"); + } +} + +static void amdgpu_xgmi_schedule_reset_on_init(struct amdgpu_hive_info *hive) +{ + INIT_WORK(&hive->reset_on_init_work, amdgpu_xgmi_reset_on_init_work); + amdgpu_reset_domain_schedule(hive->reset_domain, + &hive->reset_on_init_work); +} + +int amdgpu_xgmi_reset_on_init(struct amdgpu_device *adev) +{ + struct amdgpu_hive_info *hive; + bool reset_scheduled; + int num_devs; + + hive = amdgpu_get_xgmi_hive(adev); + if (!hive) + return -EINVAL; + + mutex_lock(&hive->hive_lock); + num_devs = atomic_read(&hive->number_devices); + reset_scheduled = false; + if (num_devs == adev->gmc.xgmi.num_physical_nodes) { + amdgpu_xgmi_schedule_reset_on_init(hive); + reset_scheduled = true; + } + + mutex_unlock(&hive->hive_lock); + amdgpu_put_xgmi_hive(hive); + + if (reset_scheduled) + flush_work(&hive->reset_on_init_work); + + return 0; +} + +int amdgpu_xgmi_request_nps_change(struct amdgpu_device *adev, + struct amdgpu_hive_info *hive, + int req_nps_mode) +{ + struct amdgpu_device *tmp_adev; + int cur_nps_mode, r; + + /* This is expected to be called only during unload of driver. The + * request needs to be placed only once for all devices in the hive. If + * one of them fail, revert the request for previous successful devices. + * After placing the request, make hive mode as UNKNOWN so that other + * devices don't request anymore. + */ + mutex_lock(&hive->hive_lock); + if (atomic_read(&hive->requested_nps_mode) == + UNKNOWN_MEMORY_PARTITION_MODE) { + dev_dbg(adev->dev, "Unexpected entry for hive NPS change"); + mutex_unlock(&hive->hive_lock); + return 0; + } + list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { + r = adev->gmc.gmc_funcs->request_mem_partition_mode( + tmp_adev, req_nps_mode); + if (r) + break; + } + if (r) { + /* Request back current mode if one of the requests failed */ + cur_nps_mode = + adev->gmc.gmc_funcs->query_mem_partition_mode(tmp_adev); + list_for_each_entry_continue_reverse( + tmp_adev, &hive->device_list, gmc.xgmi.head) + adev->gmc.gmc_funcs->request_mem_partition_mode( + tmp_adev, cur_nps_mode); + } + /* Set to UNKNOWN so that other devices don't request anymore */ + atomic_set(&hive->requested_nps_mode, UNKNOWN_MEMORY_PARTITION_MODE); + mutex_unlock(&hive->hive_lock); + + return r; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h index a3bfc16de6d496..d1282b4c63488b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h @@ -45,6 +45,8 @@ struct amdgpu_hive_info { struct amdgpu_reset_domain *reset_domain; atomic_t ras_recovery; struct ras_event_manager event_mgr; + struct work_struct reset_on_init_work; + atomic_t requested_nps_mode; }; struct amdgpu_pcs_ras_field { @@ -64,6 +66,8 @@ int amdgpu_xgmi_get_hops_count(struct amdgpu_device *adev, struct amdgpu_device *peer_adev); int amdgpu_xgmi_get_num_links(struct amdgpu_device *adev, struct amdgpu_device *peer_adev); +bool amdgpu_xgmi_get_is_sharing_enabled(struct amdgpu_device *adev, + struct amdgpu_device *peer_adev); uint64_t amdgpu_xgmi_get_relative_phy_addr(struct amdgpu_device *adev, uint64_t addr); static inline bool amdgpu_xgmi_same_hive(struct amdgpu_device *adev, @@ -75,5 +79,12 @@ static inline bool amdgpu_xgmi_same_hive(struct amdgpu_device *adev, adev->gmc.xgmi.hive_id == bo_adev->gmc.xgmi.hive_id); } int amdgpu_xgmi_ras_sw_init(struct amdgpu_device *adev); +int amdgpu_xgmi_reset_on_init(struct amdgpu_device *adev); + +int amdgpu_xgmi_request_nps_change(struct amdgpu_device *adev, + struct amdgpu_hive_info *hive, + int req_nps_mode); +int amdgpu_get_xgmi_link_status(struct amdgpu_device *adev, + int global_link_num); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h index 6e9eeaeb3de1dd..b4f9c2f4e92cc1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgv_sriovmsg.h @@ -28,17 +28,21 @@ #define AMD_SRIOV_MSG_VBIOS_SIZE_KB 64 #define AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB AMD_SRIOV_MSG_VBIOS_SIZE_KB #define AMD_SRIOV_MSG_DATAEXCHANGE_SIZE_KB 4 - +#define AMD_SRIOV_MSG_TMR_OFFSET_KB 2048 +#define AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB 2 +#define AMD_SRIOV_RAS_TELEMETRY_SIZE_KB 64 /* * layout - * 0 64KB 65KB 66KB - * | VBIOS | PF2VF | VF2PF | Bad Page | ... - * | 64KB | 1KB | 1KB | + * 0 64KB 65KB 66KB 68KB 132KB + * | VBIOS | PF2VF | VF2PF | Bad Page | RAS Telemetry Region | ... + * | 64KB | 1KB | 1KB | 2KB | 64KB | ... */ + #define AMD_SRIOV_MSG_SIZE_KB 1 #define AMD_SRIOV_MSG_PF2VF_OFFSET_KB AMD_SRIOV_MSG_DATAEXCHANGE_OFFSET_KB #define AMD_SRIOV_MSG_VF2PF_OFFSET_KB (AMD_SRIOV_MSG_PF2VF_OFFSET_KB + AMD_SRIOV_MSG_SIZE_KB) #define AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB (AMD_SRIOV_MSG_VF2PF_OFFSET_KB + AMD_SRIOV_MSG_SIZE_KB) +#define AMD_SRIOV_MSG_RAS_TELEMETRY_OFFSET_KB (AMD_SRIOV_MSG_BAD_PAGE_OFFSET_KB + AMD_SRIOV_MSG_BAD_PAGE_SIZE_KB) /* * PF2VF history log: @@ -86,30 +90,59 @@ enum amd_sriov_ucode_engine_id { union amd_sriov_msg_feature_flags { struct { - uint32_t error_log_collect : 1; - uint32_t host_load_ucodes : 1; - uint32_t host_flr_vramlost : 1; - uint32_t mm_bw_management : 1; - uint32_t pp_one_vf_mode : 1; - uint32_t reg_indirect_acc : 1; - uint32_t av1_support : 1; - uint32_t vcn_rb_decouple : 1; - uint32_t mes_info_enable : 1; - uint32_t reserved : 23; + uint32_t error_log_collect : 1; + uint32_t host_load_ucodes : 1; + uint32_t host_flr_vramlost : 1; + uint32_t mm_bw_management : 1; + uint32_t pp_one_vf_mode : 1; + uint32_t reg_indirect_acc : 1; + uint32_t av1_support : 1; + uint32_t vcn_rb_decouple : 1; + uint32_t mes_info_dump_enable : 1; + uint32_t ras_caps : 1; + uint32_t ras_telemetry : 1; + uint32_t reserved : 21; } flags; uint32_t all; }; union amd_sriov_reg_access_flags { struct { - uint32_t vf_reg_access_ih : 1; - uint32_t vf_reg_access_mmhub : 1; - uint32_t vf_reg_access_gc : 1; - uint32_t reserved : 29; + uint32_t vf_reg_access_ih : 1; + uint32_t vf_reg_access_mmhub : 1; + uint32_t vf_reg_access_gc : 1; + uint32_t reserved : 29; } flags; uint32_t all; }; +union amd_sriov_ras_caps { + struct { + uint64_t block_umc : 1; + uint64_t block_sdma : 1; + uint64_t block_gfx : 1; + uint64_t block_mmhub : 1; + uint64_t block_athub : 1; + uint64_t block_pcie_bif : 1; + uint64_t block_hdp : 1; + uint64_t block_xgmi_wafl : 1; + uint64_t block_df : 1; + uint64_t block_smn : 1; + uint64_t block_sem : 1; + uint64_t block_mp0 : 1; + uint64_t block_mp1 : 1; + uint64_t block_fuse : 1; + uint64_t block_mca : 1; + uint64_t block_vcn : 1; + uint64_t block_jpeg : 1; + uint64_t block_ih : 1; + uint64_t block_mpio : 1; + uint64_t poison_propogation_mode : 1; + uint64_t reserved : 44; + } bits; + uint64_t all; +}; + union amd_sriov_msg_os_info { struct { uint32_t windows : 1; @@ -158,7 +191,7 @@ struct amd_sriov_msg_pf2vf_info_header { uint32_t reserved[2]; }; -#define AMD_SRIOV_MSG_PF2VF_INFO_FILLED_SIZE (49) +#define AMD_SRIOV_MSG_PF2VF_INFO_FILLED_SIZE (55) struct amd_sriov_msg_pf2vf_info { /* header contains size and version */ struct amd_sriov_msg_pf2vf_info_header header; @@ -211,6 +244,12 @@ struct amd_sriov_msg_pf2vf_info { uint32_t pcie_atomic_ops_support_flags; /* Portion of GPU memory occupied by VF. MAX value is 65535, but set to uint32_t to maintain alignment with reserved size */ uint32_t gpu_capacity; + /* vf bdf on host pci tree for debug only */ + uint32_t bdf_on_host; + uint32_t more_bp; //Reserved for future use. + union amd_sriov_ras_caps ras_en_caps; + union amd_sriov_ras_caps ras_telemetry_en_caps; + /* reserved */ uint32_t reserved[256 - AMD_SRIOV_MSG_PF2VF_INFO_FILLED_SIZE]; } __packed; @@ -283,8 +322,12 @@ enum amd_sriov_mailbox_request_message { MB_REQ_MSG_REL_GPU_FINI_ACCESS, MB_REQ_MSG_REQ_GPU_RESET_ACCESS, MB_REQ_MSG_REQ_GPU_INIT_DATA, + MB_REQ_MSG_PSP_VF_CMD_RELAY, MB_REQ_MSG_LOG_VF_ERROR = 200, + MB_REQ_MSG_READY_TO_RESET = 201, + MB_REQ_MSG_RAS_POISON = 202, + MB_REQ_RAS_ERROR_COUNT = 203, }; /* mailbox message send from host to guest */ @@ -297,10 +340,60 @@ enum amd_sriov_mailbox_response_message { MB_RES_MSG_FAIL, MB_RES_MSG_QUERY_ALIVE, MB_RES_MSG_GPU_INIT_DATA_READY, + MB_RES_MSG_RAS_ERROR_COUNT_READY = 11, MB_RES_MSG_TEXT_MESSAGE = 255 }; +enum amd_sriov_ras_telemetry_gpu_block { + RAS_TELEMETRY_GPU_BLOCK_UMC = 0, + RAS_TELEMETRY_GPU_BLOCK_SDMA = 1, + RAS_TELEMETRY_GPU_BLOCK_GFX = 2, + RAS_TELEMETRY_GPU_BLOCK_MMHUB = 3, + RAS_TELEMETRY_GPU_BLOCK_ATHUB = 4, + RAS_TELEMETRY_GPU_BLOCK_PCIE_BIF = 5, + RAS_TELEMETRY_GPU_BLOCK_HDP = 6, + RAS_TELEMETRY_GPU_BLOCK_XGMI_WAFL = 7, + RAS_TELEMETRY_GPU_BLOCK_DF = 8, + RAS_TELEMETRY_GPU_BLOCK_SMN = 9, + RAS_TELEMETRY_GPU_BLOCK_SEM = 10, + RAS_TELEMETRY_GPU_BLOCK_MP0 = 11, + RAS_TELEMETRY_GPU_BLOCK_MP1 = 12, + RAS_TELEMETRY_GPU_BLOCK_FUSE = 13, + RAS_TELEMETRY_GPU_BLOCK_MCA = 14, + RAS_TELEMETRY_GPU_BLOCK_VCN = 15, + RAS_TELEMETRY_GPU_BLOCK_JPEG = 16, + RAS_TELEMETRY_GPU_BLOCK_IH = 17, + RAS_TELEMETRY_GPU_BLOCK_MPIO = 18, + RAS_TELEMETRY_GPU_BLOCK_COUNT = 19, +}; + +struct amd_sriov_ras_telemetry_header { + uint32_t checksum; + uint32_t used_size; + uint32_t reserved[2]; +}; + +struct amd_sriov_ras_telemetry_error_count { + struct { + uint32_t ce_count; + uint32_t ue_count; + uint32_t de_count; + uint32_t ce_overflow_count; + uint32_t ue_overflow_count; + uint32_t de_overflow_count; + uint32_t reserved[6]; + } block[RAS_TELEMETRY_GPU_BLOCK_COUNT]; +}; + +struct amdsriov_ras_telemetry { + struct amd_sriov_ras_telemetry_header header; + + union { + struct amd_sriov_ras_telemetry_error_count error_count; + } body; +}; + /* version data stored in MAILBOX_MSGBUF_RCV_DW1 for future expansion */ enum amd_sriov_gpu_init_data_version { GPU_INIT_DATA_READY_V1 = 1, diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c index ccfd2a4b4acc85..e157d6d857b6ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c @@ -447,6 +447,72 @@ static int __aqua_vanjaram_get_xcp_ip_info(struct amdgpu_xcp_mgr *xcp_mgr, int x return 0; } +static int aqua_vanjaram_get_xcp_res_info(struct amdgpu_xcp_mgr *xcp_mgr, + int mode, + struct amdgpu_xcp_cfg *xcp_cfg) +{ + struct amdgpu_device *adev = xcp_mgr->adev; + int max_res[AMDGPU_XCP_RES_MAX] = {}; + bool res_lt_xcp; + int num_xcp, i; + u16 nps_modes; + + if (!(xcp_mgr->supp_xcp_modes & BIT(mode))) + return -EINVAL; + + max_res[AMDGPU_XCP_RES_XCC] = NUM_XCC(adev->gfx.xcc_mask); + max_res[AMDGPU_XCP_RES_DMA] = adev->sdma.num_instances; + max_res[AMDGPU_XCP_RES_DEC] = adev->vcn.num_vcn_inst; + max_res[AMDGPU_XCP_RES_JPEG] = adev->jpeg.num_jpeg_inst; + + switch (mode) { + case AMDGPU_SPX_PARTITION_MODE: + num_xcp = 1; + nps_modes = BIT(AMDGPU_NPS1_PARTITION_MODE); + break; + case AMDGPU_DPX_PARTITION_MODE: + num_xcp = 2; + nps_modes = BIT(AMDGPU_NPS1_PARTITION_MODE); + break; + case AMDGPU_TPX_PARTITION_MODE: + num_xcp = 3; + nps_modes = BIT(AMDGPU_NPS1_PARTITION_MODE) | + BIT(AMDGPU_NPS4_PARTITION_MODE); + break; + case AMDGPU_QPX_PARTITION_MODE: + num_xcp = 4; + nps_modes = BIT(AMDGPU_NPS1_PARTITION_MODE) | + BIT(AMDGPU_NPS4_PARTITION_MODE); + break; + case AMDGPU_CPX_PARTITION_MODE: + num_xcp = NUM_XCC(adev->gfx.xcc_mask); + nps_modes = BIT(AMDGPU_NPS1_PARTITION_MODE) | + BIT(AMDGPU_NPS4_PARTITION_MODE); + break; + default: + return -EINVAL; + } + + xcp_cfg->compatible_nps_modes = + (adev->gmc.supported_nps_modes & nps_modes); + xcp_cfg->num_res = ARRAY_SIZE(max_res); + + for (i = 0; i < xcp_cfg->num_res; i++) { + res_lt_xcp = max_res[i] < num_xcp; + xcp_cfg->xcp_res[i].id = i; + xcp_cfg->xcp_res[i].num_inst = + res_lt_xcp ? 1 : max_res[i] / num_xcp; + xcp_cfg->xcp_res[i].num_inst = + i == AMDGPU_XCP_RES_JPEG ? + xcp_cfg->xcp_res[i].num_inst * + adev->jpeg.num_jpeg_rings : xcp_cfg->xcp_res[i].num_inst; + xcp_cfg->xcp_res[i].num_shared = + res_lt_xcp ? num_xcp / max_res[i] : 1; + } + + return 0; +} + static enum amdgpu_gfx_partition __aqua_vanjaram_get_auto_mode(struct amdgpu_xcp_mgr *xcp_mgr) { @@ -530,6 +596,57 @@ static int __aqua_vanjaram_post_partition_switch(struct amdgpu_xcp_mgr *xcp_mgr, return ret; } +static void +__aqua_vanjaram_update_supported_modes(struct amdgpu_xcp_mgr *xcp_mgr) +{ + struct amdgpu_device *adev = xcp_mgr->adev; + + xcp_mgr->supp_xcp_modes = 0; + + switch (NUM_XCC(adev->gfx.xcc_mask)) { + case 8: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_DPX_PARTITION_MODE) | + BIT(AMDGPU_QPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + case 6: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_TPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + case 4: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_DPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + /* this seems only existing in emulation phase */ + case 2: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + case 1: + xcp_mgr->supp_xcp_modes = BIT(AMDGPU_SPX_PARTITION_MODE) | + BIT(AMDGPU_CPX_PARTITION_MODE); + break; + + default: + break; + } +} + +static void __aqua_vanjaram_update_available_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr) +{ + int mode; + + xcp_mgr->avail_xcp_modes = 0; + + for_each_inst(mode, xcp_mgr->supp_xcp_modes) { + if (__aqua_vanjaram_is_valid_mode(xcp_mgr, mode)) + xcp_mgr->avail_xcp_modes |= BIT(mode); + } +} + static int aqua_vanjaram_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr, int mode, int *num_xcps) { @@ -578,6 +695,8 @@ static int aqua_vanjaram_switch_partition_mode(struct amdgpu_xcp_mgr *xcp_mgr, amdgpu_xcp_init(xcp_mgr, *num_xcps, mode); ret = __aqua_vanjaram_post_partition_switch(xcp_mgr, flags); + if (!ret) + __aqua_vanjaram_update_available_partition_mode(xcp_mgr); unlock: if (flags & AMDGPU_XCP_OPS_KFD) amdgpu_amdkfd_unlock_kfd(adev); @@ -656,9 +775,11 @@ struct amdgpu_xcp_mgr_funcs aqua_vanjaram_xcp_funcs = { .switch_partition_mode = &aqua_vanjaram_switch_partition_mode, .query_partition_mode = &aqua_vanjaram_query_partition_mode, .get_ip_details = &aqua_vanjaram_get_xcp_ip_details, + .get_xcp_res_info = &aqua_vanjaram_get_xcp_res_info, .get_xcp_mem_id = &aqua_vanjaram_get_xcp_mem_id, .select_scheds = &aqua_vanjaram_select_scheds, - .update_partition_sched_list = &aqua_vanjaram_update_partition_sched_list + .update_partition_sched_list = + &aqua_vanjaram_update_partition_sched_list }; static int aqua_vanjaram_xcp_mgr_init(struct amdgpu_device *adev) @@ -673,6 +794,7 @@ static int aqua_vanjaram_xcp_mgr_init(struct amdgpu_device *adev) if (ret) return ret; + __aqua_vanjaram_update_supported_modes(adev->xcp_mgr); /* TODO: Default memory node affinity init */ return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index cf1d5d462b676a..e2cb1f080e8823 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1985,9 +1985,9 @@ static const struct amdgpu_asic_funcs cik_asic_funcs = .query_video_codecs = &cik_query_video_codecs, }; -static int cik_common_early_init(void *handle) +static int cik_common_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->smc_rreg = &cik_smc_rreg; adev->smc_wreg = &cik_smc_wreg; @@ -2124,19 +2124,9 @@ static int cik_common_early_init(void *handle) return 0; } -static int cik_common_sw_init(void *handle) +static int cik_common_hw_init(struct amdgpu_ip_block *ip_block) { - return 0; -} - -static int cik_common_sw_fini(void *handle) -{ - return 0; -} - -static int cik_common_hw_init(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* move the golden regs per IP block */ cik_init_golden_registers(adev); @@ -2148,23 +2138,14 @@ static int cik_common_hw_init(void *handle) return 0; } -static int cik_common_hw_fini(void *handle) +static int cik_common_hw_fini(struct amdgpu_ip_block *ip_block) { return 0; } -static int cik_common_suspend(void *handle) +static int cik_common_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return cik_common_hw_fini(adev); -} - -static int cik_common_resume(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return cik_common_hw_init(adev); + return cik_common_hw_init(ip_block); } static bool cik_common_is_idle(void *handle) @@ -2172,12 +2153,9 @@ static bool cik_common_is_idle(void *handle) return true; } -static int cik_common_wait_for_idle(void *handle) -{ - return 0; -} -static int cik_common_soft_reset(void *handle) + +static int cik_common_soft_reset(struct amdgpu_ip_block *ip_block) { /* XXX hard reset?? */ return 0; @@ -2198,20 +2176,13 @@ static int cik_common_set_powergating_state(void *handle, static const struct amd_ip_funcs cik_common_ip_funcs = { .name = "cik_common", .early_init = cik_common_early_init, - .late_init = NULL, - .sw_init = cik_common_sw_init, - .sw_fini = cik_common_sw_fini, .hw_init = cik_common_hw_init, .hw_fini = cik_common_hw_fini, - .suspend = cik_common_suspend, .resume = cik_common_resume, .is_idle = cik_common_is_idle, - .wait_for_idle = cik_common_wait_for_idle, .soft_reset = cik_common_soft_reset, .set_clockgating_state = cik_common_set_clockgating_state, .set_powergating_state = cik_common_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ip_block_version cik_common_ip_block = diff --git a/drivers/gpu/drm/amd/amdgpu/cik_ih.c b/drivers/gpu/drm/amd/amdgpu/cik_ih.c index 576baa9dbb0e1c..1da17755ad538e 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_ih.c @@ -283,9 +283,9 @@ static void cik_ih_set_rptr(struct amdgpu_device *adev, WREG32(mmIH_RB_RPTR, ih->rptr); } -static int cik_ih_early_init(void *handle) +static int cik_ih_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; ret = amdgpu_irq_add_domain(adev); @@ -297,10 +297,10 @@ static int cik_ih_early_init(void *handle) return 0; } -static int cik_ih_sw_init(void *handle) +static int cik_ih_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 64 * 1024, false); if (r) @@ -311,9 +311,9 @@ static int cik_ih_sw_init(void *handle) return r; } -static int cik_ih_sw_fini(void *handle) +static int cik_ih_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); amdgpu_irq_remove_domain(adev); @@ -321,34 +321,28 @@ static int cik_ih_sw_fini(void *handle) return 0; } -static int cik_ih_hw_init(void *handle) +static int cik_ih_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return cik_ih_irq_init(adev); } -static int cik_ih_hw_fini(void *handle) +static int cik_ih_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - cik_ih_irq_disable(adev); + cik_ih_irq_disable(ip_block->adev); return 0; } -static int cik_ih_suspend(void *handle) +static int cik_ih_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return cik_ih_hw_fini(adev); + return cik_ih_hw_fini(ip_block); } -static int cik_ih_resume(void *handle) +static int cik_ih_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return cik_ih_hw_init(adev); + return cik_ih_hw_init(ip_block); } static bool cik_ih_is_idle(void *handle) @@ -362,11 +356,11 @@ static bool cik_ih_is_idle(void *handle) return true; } -static int cik_ih_wait_for_idle(void *handle) +static int cik_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -378,9 +372,9 @@ static int cik_ih_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int cik_ih_soft_reset(void *handle) +static int cik_ih_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; u32 tmp = RREG32(mmSRBM_STATUS); @@ -423,7 +417,6 @@ static int cik_ih_set_powergating_state(void *handle, static const struct amd_ip_funcs cik_ih_ip_funcs = { .name = "cik_ih", .early_init = cik_ih_early_init, - .late_init = NULL, .sw_init = cik_ih_sw_init, .sw_fini = cik_ih_sw_fini, .hw_init = cik_ih_hw_init, @@ -435,8 +428,6 @@ static const struct amd_ip_funcs cik_ih_ip_funcs = { .soft_reset = cik_ih_soft_reset, .set_clockgating_state = cik_ih_set_clockgating_state, .set_powergating_state = cik_ih_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs cik_ih_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index 952737de94111c..ede1a028d48d54 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -54,7 +54,7 @@ static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev); static void cik_sdma_set_irq_funcs(struct amdgpu_device *adev); static void cik_sdma_set_buffer_funcs(struct amdgpu_device *adev); static void cik_sdma_set_vm_pte_funcs(struct amdgpu_device *adev); -static int cik_sdma_soft_reset(void *handle); +static int cik_sdma_soft_reset(struct amdgpu_ip_block *ip_block); MODULE_FIRMWARE("amdgpu/bonaire_sdma.bin"); MODULE_FIRMWARE("amdgpu/bonaire_sdma1.bin"); @@ -918,9 +918,9 @@ static void cik_enable_sdma_mgls(struct amdgpu_device *adev, } } -static int cik_sdma_early_init(void *handle) +static int cik_sdma_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; adev->sdma.num_instances = SDMA_MAX_INSTANCE; @@ -937,10 +937,10 @@ static int cik_sdma_early_init(void *handle) return 0; } -static int cik_sdma_sw_init(void *handle) +static int cik_sdma_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r, i; /* SDMA trap event */ @@ -977,9 +977,9 @@ static int cik_sdma_sw_init(void *handle) return r; } -static int cik_sdma_sw_fini(void *handle) +static int cik_sdma_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) @@ -989,10 +989,10 @@ static int cik_sdma_sw_fini(void *handle) return 0; } -static int cik_sdma_hw_init(void *handle) +static int cik_sdma_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = cik_sdma_start(adev); if (r) @@ -1001,9 +1001,9 @@ static int cik_sdma_hw_init(void *handle) return r; } -static int cik_sdma_hw_fini(void *handle) +static int cik_sdma_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cik_ctx_switch_enable(adev, false); cik_sdma_enable(adev, false); @@ -1011,20 +1011,16 @@ static int cik_sdma_hw_fini(void *handle) return 0; } -static int cik_sdma_suspend(void *handle) +static int cik_sdma_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return cik_sdma_hw_fini(adev); + return cik_sdma_hw_fini(ip_block); } -static int cik_sdma_resume(void *handle) +static int cik_sdma_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - cik_sdma_soft_reset(handle); + cik_sdma_soft_reset(ip_block); - return cik_sdma_hw_init(adev); + return cik_sdma_hw_init(ip_block); } static bool cik_sdma_is_idle(void *handle) @@ -1039,11 +1035,11 @@ static bool cik_sdma_is_idle(void *handle) return true; } -static int cik_sdma_wait_for_idle(void *handle) +static int cik_sdma_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { tmp = RREG32(mmSRBM_STATUS2) & (SRBM_STATUS2__SDMA_BUSY_MASK | @@ -1056,10 +1052,10 @@ static int cik_sdma_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int cik_sdma_soft_reset(void *handle) +static int cik_sdma_soft_reset(struct amdgpu_ip_block *ip_block) { u32 srbm_soft_reset = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 tmp; /* sdma0 */ @@ -1217,7 +1213,6 @@ static int cik_sdma_set_powergating_state(void *handle, static const struct amd_ip_funcs cik_sdma_ip_funcs = { .name = "cik_sdma", .early_init = cik_sdma_early_init, - .late_init = NULL, .sw_init = cik_sdma_sw_init, .sw_fini = cik_sdma_sw_fini, .hw_init = cik_sdma_hw_init, @@ -1229,8 +1224,6 @@ static const struct amd_ip_funcs cik_sdma_ip_funcs = { .soft_reset = cik_sdma_soft_reset, .set_clockgating_state = cik_sdma_set_clockgating_state, .set_powergating_state = cik_sdma_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/cz_ih.c b/drivers/gpu/drm/amd/amdgpu/cz_ih.c index 07264378738459..d72973bd570dfd 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_ih.c @@ -274,9 +274,9 @@ static void cz_ih_set_rptr(struct amdgpu_device *adev, WREG32(mmIH_RB_RPTR, ih->rptr); } -static int cz_ih_early_init(void *handle) +static int cz_ih_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; ret = amdgpu_irq_add_domain(adev); @@ -288,10 +288,10 @@ static int cz_ih_early_init(void *handle) return 0; } -static int cz_ih_sw_init(void *handle) +static int cz_ih_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 64 * 1024, false); if (r) @@ -302,9 +302,9 @@ static int cz_ih_sw_init(void *handle) return r; } -static int cz_ih_sw_fini(void *handle) +static int cz_ih_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); amdgpu_irq_remove_domain(adev); @@ -312,10 +312,10 @@ static int cz_ih_sw_fini(void *handle) return 0; } -static int cz_ih_hw_init(void *handle) +static int cz_ih_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = cz_ih_irq_init(adev); if (r) @@ -324,27 +324,21 @@ static int cz_ih_hw_init(void *handle) return 0; } -static int cz_ih_hw_fini(void *handle) +static int cz_ih_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - cz_ih_irq_disable(adev); + cz_ih_irq_disable(ip_block->adev); return 0; } -static int cz_ih_suspend(void *handle) +static int cz_ih_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return cz_ih_hw_fini(adev); + return cz_ih_hw_fini(ip_block); } -static int cz_ih_resume(void *handle) +static int cz_ih_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return cz_ih_hw_init(adev); + return cz_ih_hw_init(ip_block); } static bool cz_ih_is_idle(void *handle) @@ -358,11 +352,11 @@ static bool cz_ih_is_idle(void *handle) return true; } -static int cz_ih_wait_for_idle(void *handle) +static int cz_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -374,10 +368,10 @@ static int cz_ih_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int cz_ih_soft_reset(void *handle) +static int cz_ih_soft_reset(struct amdgpu_ip_block *ip_block) { u32 srbm_soft_reset = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 tmp = RREG32(mmSRBM_STATUS); if (tmp & SRBM_STATUS__IH_BUSY_MASK) @@ -421,7 +415,6 @@ static int cz_ih_set_powergating_state(void *handle, static const struct amd_ip_funcs cz_ih_ip_funcs = { .name = "cz_ih", .early_init = cz_ih_early_init, - .late_init = NULL, .sw_init = cz_ih_sw_init, .sw_fini = cz_ih_sw_fini, .hw_init = cz_ih_hw_init, @@ -433,8 +426,6 @@ static const struct amd_ip_funcs cz_ih_ip_funcs = { .soft_reset = cz_ih_soft_reset, .set_clockgating_state = cz_ih_set_clockgating_state, .set_powergating_state = cz_ih_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs cz_ih_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 70c1399f738def..5098c50d54c85a 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2738,9 +2738,9 @@ static int dce_v10_0_crtc_init(struct amdgpu_device *adev, int index) return 0; } -static int dce_v10_0_early_init(void *handle) +static int dce_v10_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->audio_endpt_rreg = &dce_v10_0_audio_endpt_rreg; adev->audio_endpt_wreg = &dce_v10_0_audio_endpt_wreg; @@ -2765,10 +2765,10 @@ static int dce_v10_0_early_init(void *handle) return 0; } -static int dce_v10_0_sw_init(void *handle) +static int dce_v10_0_sw_init(struct amdgpu_ip_block *ip_block) { int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->mode_info.num_crtc; i++) { r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, i + 1, &adev->crtc_irq); @@ -2844,9 +2844,9 @@ static int dce_v10_0_sw_init(void *handle) return 0; } -static int dce_v10_0_sw_fini(void *handle) +static int dce_v10_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; drm_edid_free(adev->mode_info.bios_hardcoded_edid); @@ -2862,10 +2862,10 @@ static int dce_v10_0_sw_fini(void *handle) return 0; } -static int dce_v10_0_hw_init(void *handle) +static int dce_v10_0_hw_init(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; dce_v10_0_init_golden_registers(adev); @@ -2887,10 +2887,10 @@ static int dce_v10_0_hw_init(void *handle) return 0; } -static int dce_v10_0_hw_fini(void *handle) +static int dce_v10_0_hw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; dce_v10_0_hpd_fini(adev); @@ -2905,9 +2905,9 @@ static int dce_v10_0_hw_fini(void *handle) return 0; } -static int dce_v10_0_suspend(void *handle) +static int dce_v10_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_display_suspend_helper(adev); @@ -2917,18 +2917,18 @@ static int dce_v10_0_suspend(void *handle) adev->mode_info.bl_level = amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); - return dce_v10_0_hw_fini(handle); + return dce_v10_0_hw_fini(ip_block); } -static int dce_v10_0_resume(void *handle) +static int dce_v10_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, adev->mode_info.bl_level); - ret = dce_v10_0_hw_init(handle); + ret = dce_v10_0_hw_init(ip_block); /* turn on the BL */ if (adev->mode_info.bl_encoder) { @@ -2948,22 +2948,17 @@ static bool dce_v10_0_is_idle(void *handle) return true; } -static int dce_v10_0_wait_for_idle(void *handle) +static bool dce_v10_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { - return 0; -} - -static bool dce_v10_0_check_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return dce_v10_0_is_display_hung(adev); } -static int dce_v10_0_soft_reset(void *handle) +static int dce_v10_0_soft_reset(struct amdgpu_ip_block *ip_block) { u32 srbm_soft_reset = 0, tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (dce_v10_0_is_display_hung(adev)) srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; @@ -3322,7 +3317,6 @@ static int dce_v10_0_set_powergating_state(void *handle, static const struct amd_ip_funcs dce_v10_0_ip_funcs = { .name = "dce_v10_0", .early_init = dce_v10_0_early_init, - .late_init = NULL, .sw_init = dce_v10_0_sw_init, .sw_fini = dce_v10_0_sw_fini, .hw_init = dce_v10_0_hw_init, @@ -3330,13 +3324,10 @@ static const struct amd_ip_funcs dce_v10_0_ip_funcs = { .suspend = dce_v10_0_suspend, .resume = dce_v10_0_resume, .is_idle = dce_v10_0_is_idle, - .wait_for_idle = dce_v10_0_wait_for_idle, .check_soft_reset = dce_v10_0_check_soft_reset, .soft_reset = dce_v10_0_soft_reset, .set_clockgating_state = dce_v10_0_set_clockgating_state, .set_powergating_state = dce_v10_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static void diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index f154c24499c8a4..c5680ff4ab9fd8 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -2851,9 +2851,9 @@ static int dce_v11_0_crtc_init(struct amdgpu_device *adev, int index) return 0; } -static int dce_v11_0_early_init(void *handle) +static int dce_v11_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->audio_endpt_rreg = &dce_v11_0_audio_endpt_rreg; adev->audio_endpt_wreg = &dce_v11_0_audio_endpt_wreg; @@ -2891,10 +2891,10 @@ static int dce_v11_0_early_init(void *handle) return 0; } -static int dce_v11_0_sw_init(void *handle) +static int dce_v11_0_sw_init(struct amdgpu_ip_block *ip_block) { int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->mode_info.num_crtc; i++) { r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, i + 1, &adev->crtc_irq); @@ -2971,9 +2971,9 @@ static int dce_v11_0_sw_init(void *handle) return 0; } -static int dce_v11_0_sw_fini(void *handle) +static int dce_v11_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; drm_edid_free(adev->mode_info.bios_hardcoded_edid); @@ -2989,10 +2989,10 @@ static int dce_v11_0_sw_fini(void *handle) return 0; } -static int dce_v11_0_hw_init(void *handle) +static int dce_v11_0_hw_init(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; dce_v11_0_init_golden_registers(adev); @@ -3025,10 +3025,10 @@ static int dce_v11_0_hw_init(void *handle) return 0; } -static int dce_v11_0_hw_fini(void *handle) +static int dce_v11_0_hw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; dce_v11_0_hpd_fini(adev); @@ -3043,9 +3043,9 @@ static int dce_v11_0_hw_fini(void *handle) return 0; } -static int dce_v11_0_suspend(void *handle) +static int dce_v11_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_display_suspend_helper(adev); @@ -3055,18 +3055,18 @@ static int dce_v11_0_suspend(void *handle) adev->mode_info.bl_level = amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); - return dce_v11_0_hw_fini(handle); + return dce_v11_0_hw_fini(ip_block); } -static int dce_v11_0_resume(void *handle) +static int dce_v11_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, adev->mode_info.bl_level); - ret = dce_v11_0_hw_init(handle); + ret = dce_v11_0_hw_init(ip_block); /* turn on the BL */ if (adev->mode_info.bl_encoder) { @@ -3086,15 +3086,10 @@ static bool dce_v11_0_is_idle(void *handle) return true; } -static int dce_v11_0_wait_for_idle(void *handle) -{ - return 0; -} - -static int dce_v11_0_soft_reset(void *handle) +static int dce_v11_0_soft_reset(struct amdgpu_ip_block *ip_block) { u32 srbm_soft_reset = 0, tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (dce_v11_0_is_display_hung(adev)) srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; @@ -3454,7 +3449,6 @@ static int dce_v11_0_set_powergating_state(void *handle, static const struct amd_ip_funcs dce_v11_0_ip_funcs = { .name = "dce_v11_0", .early_init = dce_v11_0_early_init, - .late_init = NULL, .sw_init = dce_v11_0_sw_init, .sw_fini = dce_v11_0_sw_fini, .hw_init = dce_v11_0_hw_init, @@ -3462,12 +3456,9 @@ static const struct amd_ip_funcs dce_v11_0_ip_funcs = { .suspend = dce_v11_0_suspend, .resume = dce_v11_0_resume, .is_idle = dce_v11_0_is_idle, - .wait_for_idle = dce_v11_0_wait_for_idle, .soft_reset = dce_v11_0_soft_reset, .set_clockgating_state = dce_v11_0_set_clockgating_state, .set_powergating_state = dce_v11_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static void diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index a7fcb135827f8b..eb7de9122d99f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -2633,9 +2633,9 @@ static int dce_v6_0_crtc_init(struct amdgpu_device *adev, int index) return 0; } -static int dce_v6_0_early_init(void *handle) +static int dce_v6_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->audio_endpt_rreg = &dce_v6_0_audio_endpt_rreg; adev->audio_endpt_wreg = &dce_v6_0_audio_endpt_wreg; @@ -2664,11 +2664,11 @@ static int dce_v6_0_early_init(void *handle) return 0; } -static int dce_v6_0_sw_init(void *handle) +static int dce_v6_0_sw_init(struct amdgpu_ip_block *ip_block) { int r, i; bool ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->mode_info.num_crtc; i++) { r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, i + 1, &adev->crtc_irq); @@ -2743,9 +2743,9 @@ static int dce_v6_0_sw_init(void *handle) return r; } -static int dce_v6_0_sw_fini(void *handle) +static int dce_v6_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; drm_edid_free(adev->mode_info.bios_hardcoded_edid); @@ -2760,10 +2760,10 @@ static int dce_v6_0_sw_fini(void *handle) return 0; } -static int dce_v6_0_hw_init(void *handle) +static int dce_v6_0_hw_init(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* disable vga render */ dce_v6_0_set_vga_render_state(adev, false); @@ -2783,10 +2783,10 @@ static int dce_v6_0_hw_init(void *handle) return 0; } -static int dce_v6_0_hw_fini(void *handle) +static int dce_v6_0_hw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; dce_v6_0_hpd_fini(adev); @@ -2801,9 +2801,9 @@ static int dce_v6_0_hw_fini(void *handle) return 0; } -static int dce_v6_0_suspend(void *handle) +static int dce_v6_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_display_suspend_helper(adev); @@ -2812,18 +2812,18 @@ static int dce_v6_0_suspend(void *handle) adev->mode_info.bl_level = amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); - return dce_v6_0_hw_fini(handle); + return dce_v6_0_hw_fini(ip_block); } -static int dce_v6_0_resume(void *handle) +static int dce_v6_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, adev->mode_info.bl_level); - ret = dce_v6_0_hw_init(handle); + ret = dce_v6_0_hw_init(ip_block); /* turn on the BL */ if (adev->mode_info.bl_encoder) { @@ -2843,12 +2843,7 @@ static bool dce_v6_0_is_idle(void *handle) return true; } -static int dce_v6_0_wait_for_idle(void *handle) -{ - return 0; -} - -static int dce_v6_0_soft_reset(void *handle) +static int dce_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) { DRM_INFO("xxxx: dce_v6_0_soft_reset --- no impl!!\n"); return 0; @@ -3144,7 +3139,6 @@ static int dce_v6_0_set_powergating_state(void *handle, static const struct amd_ip_funcs dce_v6_0_ip_funcs = { .name = "dce_v6_0", .early_init = dce_v6_0_early_init, - .late_init = NULL, .sw_init = dce_v6_0_sw_init, .sw_fini = dce_v6_0_sw_fini, .hw_init = dce_v6_0_hw_init, @@ -3152,12 +3146,9 @@ static const struct amd_ip_funcs dce_v6_0_ip_funcs = { .suspend = dce_v6_0_suspend, .resume = dce_v6_0_resume, .is_idle = dce_v6_0_is_idle, - .wait_for_idle = dce_v6_0_wait_for_idle, .soft_reset = dce_v6_0_soft_reset, .set_clockgating_state = dce_v6_0_set_clockgating_state, .set_powergating_state = dce_v6_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static void diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 77ac3f114d2411..04b79ff87f756c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2644,9 +2644,9 @@ static int dce_v8_0_crtc_init(struct amdgpu_device *adev, int index) return 0; } -static int dce_v8_0_early_init(void *handle) +static int dce_v8_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->audio_endpt_rreg = &dce_v8_0_audio_endpt_rreg; adev->audio_endpt_wreg = &dce_v8_0_audio_endpt_wreg; @@ -2680,10 +2680,10 @@ static int dce_v8_0_early_init(void *handle) return 0; } -static int dce_v8_0_sw_init(void *handle) +static int dce_v8_0_sw_init(struct amdgpu_ip_block *ip_block) { int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->mode_info.num_crtc; i++) { r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, i + 1, &adev->crtc_irq); @@ -2764,9 +2764,9 @@ static int dce_v8_0_sw_init(void *handle) return 0; } -static int dce_v8_0_sw_fini(void *handle) +static int dce_v8_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; drm_edid_free(adev->mode_info.bios_hardcoded_edid); @@ -2782,10 +2782,10 @@ static int dce_v8_0_sw_fini(void *handle) return 0; } -static int dce_v8_0_hw_init(void *handle) +static int dce_v8_0_hw_init(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* disable vga render */ dce_v8_0_set_vga_render_state(adev, false); @@ -2805,10 +2805,10 @@ static int dce_v8_0_hw_init(void *handle) return 0; } -static int dce_v8_0_hw_fini(void *handle) +static int dce_v8_0_hw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; dce_v8_0_hpd_fini(adev); @@ -2823,9 +2823,9 @@ static int dce_v8_0_hw_fini(void *handle) return 0; } -static int dce_v8_0_suspend(void *handle) +static int dce_v8_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_display_suspend_helper(adev); @@ -2835,18 +2835,18 @@ static int dce_v8_0_suspend(void *handle) adev->mode_info.bl_level = amdgpu_atombios_encoder_get_backlight_level_from_reg(adev); - return dce_v8_0_hw_fini(handle); + return dce_v8_0_hw_fini(ip_block); } -static int dce_v8_0_resume(void *handle) +static int dce_v8_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, adev->mode_info.bl_level); - ret = dce_v8_0_hw_init(handle); + ret = dce_v8_0_hw_init(ip_block); /* turn on the BL */ if (adev->mode_info.bl_encoder) { @@ -2866,15 +2866,10 @@ static bool dce_v8_0_is_idle(void *handle) return true; } -static int dce_v8_0_wait_for_idle(void *handle) -{ - return 0; -} - -static int dce_v8_0_soft_reset(void *handle) +static int dce_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) { u32 srbm_soft_reset = 0, tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (dce_v8_0_is_display_hung(adev)) srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; @@ -3232,7 +3227,6 @@ static int dce_v8_0_set_powergating_state(void *handle, static const struct amd_ip_funcs dce_v8_0_ip_funcs = { .name = "dce_v8_0", .early_init = dce_v8_0_early_init, - .late_init = NULL, .sw_init = dce_v8_0_sw_init, .sw_fini = dce_v8_0_sw_fini, .hw_init = dce_v8_0_hw_init, @@ -3240,12 +3234,9 @@ static const struct amd_ip_funcs dce_v8_0_ip_funcs = { .suspend = dce_v8_0_suspend, .resume = dce_v8_0_resume, .is_idle = dce_v8_0_is_idle, - .wait_for_idle = dce_v8_0_wait_for_idle, .soft_reset = dce_v8_0_soft_reset, .set_clockgating_state = dce_v8_0_set_clockgating_state, .set_powergating_state = dce_v8_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static void diff --git a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c index 483a441b46aa10..621aeca5388033 100644 --- a/drivers/gpu/drm/amd/amdgpu/df_v3_6.c +++ b/drivers/gpu/drm/amd/amdgpu/df_v3_6.c @@ -254,8 +254,8 @@ static void df_v3_6_sw_init(struct amdgpu_device *adev) static void df_v3_6_sw_fini(struct amdgpu_device *adev) { - - device_remove_file(adev->dev, &dev_attr_df_cntr_avail); + if (adev->dev->kobj.sd) + device_remove_file(adev->dev, &dev_attr_df_cntr_avail); } diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 45ed97038df0c8..24dce803a829cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -3677,13 +3677,19 @@ static int gfx_v10_0_set_powergating_state(void *handle, enum amd_powergating_state state); static void gfx10_kiq_set_resources(struct amdgpu_ring *kiq_ring, uint64_t queue_mask) { + struct amdgpu_device *adev = kiq_ring->adev; + u64 shader_mc_addr; + + /* Cleaner shader MC address */ + shader_mc_addr = adev->gfx.cleaner_shader_gpu_addr >> 8; + amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_SET_RESOURCES, 6)); amdgpu_ring_write(kiq_ring, PACKET3_SET_RESOURCES_VMID_MASK(0) | PACKET3_SET_RESOURCES_QUEUE_TYPE(0)); /* vmid_mask:0 queue_type:0 (KIQ) */ amdgpu_ring_write(kiq_ring, lower_32_bits(queue_mask)); /* queue mask lo */ amdgpu_ring_write(kiq_ring, upper_32_bits(queue_mask)); /* queue mask hi */ - amdgpu_ring_write(kiq_ring, 0); /* gws mask lo */ - amdgpu_ring_write(kiq_ring, 0); /* gws mask hi */ + amdgpu_ring_write(kiq_ring, lower_32_bits(shader_mc_addr)); /* cleaner shader addr lo */ + amdgpu_ring_write(kiq_ring, upper_32_bits(shader_mc_addr)); /* cleaner shader addr hi */ amdgpu_ring_write(kiq_ring, 0); /* oac mask */ amdgpu_ring_write(kiq_ring, 0); /* gds heap base:0, gds heap size:0 */ } @@ -4683,11 +4689,11 @@ static void gfx_v10_0_alloc_ip_dump(struct amdgpu_device *adev) } } -static int gfx_v10_0_sw_init(void *handle) +static int gfx_v10_0_sw_init(struct amdgpu_ip_block *ip_block) { int i, j, k, r, ring_id = 0; int xcc_id = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(10, 1, 10): @@ -4726,6 +4732,11 @@ static int gfx_v10_0_sw_init(void *handle) adev->gfx.mec.num_queue_per_pipe = 8; break; } + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + default: + adev->gfx.enable_cleaner_shader = false; + break; + } /* KIQ event */ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_GRBM_CP, @@ -4814,6 +4825,11 @@ static int gfx_v10_0_sw_init(void *handle) } } } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->gfx.gfx_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.gfx_ring[0]); + adev->gfx.compute_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]); r = amdgpu_gfx_kiq_init(adev, GFX10_MEC_HPD_SIZE, 0); if (r) { @@ -4842,6 +4858,10 @@ static int gfx_v10_0_sw_init(void *handle) gfx_v10_0_alloc_ip_dump(adev); + r = amdgpu_gfx_sysfs_init(adev); + if (r) + return r; + return 0; } @@ -4866,10 +4886,10 @@ static void gfx_v10_0_me_fini(struct amdgpu_device *adev) (void **)&adev->gfx.me.me_fw_ptr); } -static int gfx_v10_0_sw_fini(void *handle) +static int gfx_v10_0_sw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->gfx.num_gfx_rings; i++) amdgpu_ring_fini(&adev->gfx.gfx_ring[i]); @@ -4881,6 +4901,8 @@ static int gfx_v10_0_sw_fini(void *handle) amdgpu_gfx_kiq_free_ring(&adev->gfx.kiq[0].ring); amdgpu_gfx_kiq_fini(adev, 0); + amdgpu_gfx_cleaner_shader_sw_fini(adev); + gfx_v10_0_pfp_fini(adev); gfx_v10_0_ce_fini(adev); gfx_v10_0_me_fini(adev); @@ -4891,6 +4913,7 @@ static int gfx_v10_0_sw_fini(void *handle) gfx_v10_0_rlc_backdoor_autoload_buffer_fini(adev); gfx_v10_0_free_microcode(adev); + amdgpu_gfx_sysfs_fini(adev); kfree(adev->gfx.ip_dump_core); kfree(adev->gfx.ip_dump_compute_queues); @@ -6374,7 +6397,7 @@ static int gfx_v10_0_cp_gfx_resume(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, mmCP_RB0_WPTR, lower_32_bits(ring->wptr)); WREG32_SOC15(GC, 0, mmCP_RB0_WPTR_HI, upper_32_bits(ring->wptr)); - /* set the wb address wether it's enabled or not */ + /* set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; WREG32_SOC15(GC, 0, mmCP_RB0_RPTR_ADDR, lower_32_bits(rptr_addr)); WREG32_SOC15(GC, 0, mmCP_RB0_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & @@ -6412,7 +6435,7 @@ static int gfx_v10_0_cp_gfx_resume(struct amdgpu_device *adev) ring->wptr = 0; WREG32_SOC15(GC, 0, mmCP_RB1_WPTR, lower_32_bits(ring->wptr)); WREG32_SOC15(GC, 0, mmCP_RB1_WPTR_HI, upper_32_bits(ring->wptr)); - /* Set the wb address wether it's enabled or not */ + /* Set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr)); WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & @@ -7366,14 +7389,17 @@ static void gfx_v10_0_disable_gpa_mode(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, mmCPG_PSP_DEBUG, data); } -static int gfx_v10_0_hw_init(void *handle) +static int gfx_v10_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!amdgpu_emu_mode) gfx_v10_0_init_golden_registers(adev); + amdgpu_gfx_cleaner_shader_init(adev, adev->gfx.cleaner_shader_size, + adev->gfx.cleaner_shader_ptr); + if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) { /** * For gfx 10, rlc firmware loading relies on smu firmware is @@ -7418,9 +7444,9 @@ static int gfx_v10_0_hw_init(void *handle) return r; } -static int gfx_v10_0_hw_fini(void *handle) +static int gfx_v10_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -7431,7 +7457,7 @@ static int gfx_v10_0_hw_fini(void *handle) * otherwise the gfxoff disallowing will be failed to set. */ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(10, 3, 1)) - gfx_v10_0_set_powergating_state(handle, AMD_PG_STATE_UNGATE); + gfx_v10_0_set_powergating_state(ip_block->adev, AMD_PG_STATE_UNGATE); if (!adev->no_hw_access) { if (amdgpu_async_gfx_ring) { @@ -7456,14 +7482,14 @@ static int gfx_v10_0_hw_fini(void *handle) return 0; } -static int gfx_v10_0_suspend(void *handle) +static int gfx_v10_0_suspend(struct amdgpu_ip_block *ip_block) { - return gfx_v10_0_hw_fini(handle); + return gfx_v10_0_hw_fini(ip_block); } -static int gfx_v10_0_resume(void *handle) +static int gfx_v10_0_resume(struct amdgpu_ip_block *ip_block) { - return gfx_v10_0_hw_init(handle); + return gfx_v10_0_hw_init(ip_block); } static bool gfx_v10_0_is_idle(void *handle) @@ -7477,11 +7503,11 @@ static bool gfx_v10_0_is_idle(void *handle) return true; } -static int gfx_v10_0_wait_for_idle(void *handle) +static int gfx_v10_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned int i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -7495,11 +7521,11 @@ static int gfx_v10_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int gfx_v10_0_soft_reset(void *handle) +static int gfx_v10_0_soft_reset(struct amdgpu_ip_block *ip_block) { u32 grbm_soft_reset = 0; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* GRBM_STATUS */ tmp = RREG32_SOC15(GC, 0, mmGRBM_STATUS); @@ -7678,9 +7704,9 @@ static void gfx_v10_0_ring_emit_gds_switch(struct amdgpu_ring *ring, (1 << (oa_size + oa_base)) - (1 << oa_base)); } -static int gfx_v10_0_early_init(void *handle) +static int gfx_v10_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfx.funcs = &gfx_v10_0_gfx_funcs; @@ -7722,9 +7748,9 @@ static int gfx_v10_0_early_init(void *handle) return gfx_v10_0_init_microcode(adev); } -static int gfx_v10_0_late_init(void *handle) +static int gfx_v10_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0); @@ -9402,8 +9428,6 @@ static void gfx_v10_0_emit_mem_sync(struct amdgpu_ring *ring) static void gfx_v10_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) { - int i; - /* Header itself is a NOP packet */ if (num_nop == 1) { amdgpu_ring_write(ring, ring->funcs->nop); @@ -9414,8 +9438,7 @@ static void gfx_v10_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) amdgpu_ring_write(ring, PACKET3(PACKET3_NOP, min(num_nop - 2, 0x3ffe))); /* Header is at index 0, followed by num_nops - 1 NOP packet's */ - for (i = 1; i < num_nop; i++) - amdgpu_ring_write(ring, ring->funcs->nop); + amdgpu_ring_insert_nop(ring, num_nop - 1); } static int gfx_v10_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid) @@ -9568,9 +9591,9 @@ static int gfx_v10_0_reset_kcq(struct amdgpu_ring *ring, return amdgpu_ring_test_ring(ring); } -static void gfx_v10_ip_print(void *handle, struct drm_printer *p) +static void gfx_v10_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k, reg, index = 0; uint32_t reg_count = ARRAY_SIZE(gc_reg_list_10_1); @@ -9632,9 +9655,9 @@ static void gfx_v10_ip_print(void *handle, struct drm_printer *p) } } -static void gfx_v10_ip_dump(void *handle) +static void gfx_v10_ip_dump(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k, reg, index = 0; uint32_t reg_count = ARRAY_SIZE(gc_reg_list_10_1); @@ -9699,6 +9722,13 @@ static void gfx_v10_ip_dump(void *handle) amdgpu_gfx_off_ctrl(adev, true); } +static void gfx_v10_0_ring_emit_cleaner_shader(struct amdgpu_ring *ring) +{ + /* Emit the cleaner shader */ + amdgpu_ring_write(ring, PACKET3(PACKET3_RUN_CLEANER_SHADER, 0)); + amdgpu_ring_write(ring, 0); /* RESERVED field, programmed to zero */ +} + static const struct amd_ip_funcs gfx_v10_0_ip_funcs = { .name = "gfx_v10_0", .early_init = gfx_v10_0_early_init, @@ -9749,7 +9779,8 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_gfx = { 5 + /* HDP_INVL */ 8 + 8 + /* FENCE x2 */ 2 + /* SWITCH_BUFFER */ - 8, /* gfx_v10_0_emit_mem_sync */ + 8 + /* gfx_v10_0_emit_mem_sync */ + 2, /* gfx_v10_0_ring_emit_cleaner_shader */ .emit_ib_size = 4, /* gfx_v10_0_ring_emit_ib_gfx */ .emit_ib = gfx_v10_0_ring_emit_ib_gfx, .emit_fence = gfx_v10_0_ring_emit_fence, @@ -9772,6 +9803,9 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_gfx = { .soft_recovery = gfx_v10_0_ring_soft_recovery, .emit_mem_sync = gfx_v10_0_emit_mem_sync, .reset = gfx_v10_0_reset_kgq, + .emit_cleaner_shader = gfx_v10_0_ring_emit_cleaner_shader, + .begin_use = amdgpu_gfx_enforce_isolation_ring_begin_use, + .end_use = amdgpu_gfx_enforce_isolation_ring_end_use, }; static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_compute = { @@ -9791,7 +9825,8 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_compute = { SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + 2 + /* gfx_v10_0_ring_emit_vm_flush */ 8 + 8 + 8 + /* gfx_v10_0_ring_emit_fence x3 for user fence, vm fence */ - 8, /* gfx_v10_0_emit_mem_sync */ + 8 + /* gfx_v10_0_emit_mem_sync */ + 2, /* gfx_v10_0_ring_emit_cleaner_shader */ .emit_ib_size = 7, /* gfx_v10_0_ring_emit_ib_compute */ .emit_ib = gfx_v10_0_ring_emit_ib_compute, .emit_fence = gfx_v10_0_ring_emit_fence, @@ -9809,6 +9844,9 @@ static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_compute = { .soft_recovery = gfx_v10_0_ring_soft_recovery, .emit_mem_sync = gfx_v10_0_emit_mem_sync, .reset = gfx_v10_0_reset_kcq, + .emit_cleaner_shader = gfx_v10_0_ring_emit_cleaner_shader, + .begin_use = amdgpu_gfx_enforce_isolation_ring_begin_use, + .end_use = amdgpu_gfx_enforce_isolation_ring_end_use, }; static const struct amdgpu_ring_funcs gfx_v10_0_ring_funcs_kiq = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index d3e8be82a1727a..2ae058a224f4dc 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -46,6 +46,7 @@ #include "clearstate_gfx11.h" #include "v11_structs.h" #include "gfx_v11_0.h" +#include "gfx_v11_0_cleaner_shader.h" #include "gfx_v11_0_3.h" #include "nbio_v4_3.h" #include "mes_v11_0.h" @@ -293,14 +294,20 @@ static void gfx_v11_0_update_perf_clk(struct amdgpu_device *adev, static void gfx11_kiq_set_resources(struct amdgpu_ring *kiq_ring, uint64_t queue_mask) { + struct amdgpu_device *adev = kiq_ring->adev; + u64 shader_mc_addr; + + /* Cleaner shader MC address */ + shader_mc_addr = adev->gfx.cleaner_shader_gpu_addr >> 8; + amdgpu_ring_write(kiq_ring, PACKET3(PACKET3_SET_RESOURCES, 6)); amdgpu_ring_write(kiq_ring, PACKET3_SET_RESOURCES_VMID_MASK(0) | PACKET3_SET_RESOURCES_UNMAP_LATENTY(0xa) | /* unmap_latency: 0xa (~ 1s) */ PACKET3_SET_RESOURCES_QUEUE_TYPE(0)); /* vmid_mask:0 queue_type:0 (KIQ) */ amdgpu_ring_write(kiq_ring, lower_32_bits(queue_mask)); /* queue mask lo */ amdgpu_ring_write(kiq_ring, upper_32_bits(queue_mask)); /* queue mask hi */ - amdgpu_ring_write(kiq_ring, 0); /* gws mask lo */ - amdgpu_ring_write(kiq_ring, 0); /* gws mask hi */ + amdgpu_ring_write(kiq_ring, lower_32_bits(shader_mc_addr)); /* cleaner shader addr lo */ + amdgpu_ring_write(kiq_ring, upper_32_bits(shader_mc_addr)); /* cleaner shader addr hi */ amdgpu_ring_write(kiq_ring, 0); /* oac mask */ amdgpu_ring_write(kiq_ring, 0); /* gds heap base:0, gds heap size:0 */ } @@ -483,8 +490,6 @@ static void gfx_v11_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, static void gfx_v11_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) { - int i; - /* Header itself is a NOP packet */ if (num_nop == 1) { amdgpu_ring_write(ring, ring->funcs->nop); @@ -495,8 +500,7 @@ static void gfx_v11_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) amdgpu_ring_write(ring, PACKET3(PACKET3_NOP, min(num_nop - 2, 0x3ffe))); /* Header is at index 0, followed by num_nops - 1 NOP packet's */ - for (i = 1; i < num_nop; i++) - amdgpu_ring_write(ring, ring->funcs->nop); + amdgpu_ring_insert_nop(ring, num_nop - 1); } static int gfx_v11_0_ring_test_ring(struct amdgpu_ring *ring) @@ -1536,11 +1540,11 @@ static void gfx_v11_0_alloc_ip_dump(struct amdgpu_device *adev) } } -static int gfx_v11_0_sw_init(void *handle) +static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block) { int i, j, k, r, ring_id = 0; int xcc_id = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(11, 0, 0): @@ -1575,6 +1579,29 @@ static int gfx_v11_0_sw_init(void *handle) break; } + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + case IP_VERSION(11, 0, 0): + case IP_VERSION(11, 0, 2): + case IP_VERSION(11, 0, 3): + adev->gfx.cleaner_shader_ptr = gfx_11_0_3_cleaner_shader_hex; + adev->gfx.cleaner_shader_size = sizeof(gfx_11_0_3_cleaner_shader_hex); + if (adev->gfx.me_fw_version >= 2280 && + adev->gfx.pfp_fw_version >= 2370 && + adev->gfx.mec_fw_version >= 2450 && + adev->mes.fw_version[0] >= 99) { + adev->gfx.enable_cleaner_shader = true; + r = amdgpu_gfx_cleaner_shader_sw_init(adev, adev->gfx.cleaner_shader_size); + if (r) { + adev->gfx.enable_cleaner_shader = false; + dev_err(adev->dev, "Failed to initialize cleaner shader\n"); + } + } + break; + default: + adev->gfx.enable_cleaner_shader = false; + break; + } + /* Enable CG flag in one VF mode for enabling RLC safe mode enter/exit */ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 0, 3) && amdgpu_sriov_is_pp_one_vf(adev)) @@ -1666,6 +1693,24 @@ static int gfx_v11_0_sw_init(void *handle) } } + adev->gfx.gfx_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.gfx_ring[0]); + adev->gfx.compute_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]); + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + case IP_VERSION(11, 0, 0): + case IP_VERSION(11, 0, 2): + case IP_VERSION(11, 0, 3): + if ((adev->gfx.me_fw_version >= 2280) && + (adev->gfx.mec_fw_version >= 2410)) { + adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + adev->gfx.gfx_supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + } + break; + default: + break; + } + if (!adev->enable_mes_kiq) { r = amdgpu_gfx_kiq_init(adev, GFX11_MEC_HPD_SIZE, 0); if (r) { @@ -1700,6 +1745,10 @@ static int gfx_v11_0_sw_init(void *handle) gfx_v11_0_alloc_ip_dump(adev); + r = amdgpu_gfx_sysfs_init(adev); + if (r) + return r; + return 0; } @@ -1732,10 +1781,10 @@ static void gfx_v11_0_rlc_autoload_buffer_fini(struct amdgpu_device *adev) (void **)&adev->gfx.rlc.rlc_autoload_ptr); } -static int gfx_v11_0_sw_fini(void *handle) +static int gfx_v11_0_sw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->gfx.num_gfx_rings; i++) amdgpu_ring_fini(&adev->gfx.gfx_ring[i]); @@ -1749,6 +1798,8 @@ static int gfx_v11_0_sw_fini(void *handle) amdgpu_gfx_kiq_fini(adev, 0); } + amdgpu_gfx_cleaner_shader_sw_fini(adev); + gfx_v11_0_pfp_fini(adev); gfx_v11_0_me_fini(adev); gfx_v11_0_rlc_fini(adev); @@ -1759,6 +1810,8 @@ static int gfx_v11_0_sw_fini(void *handle) gfx_v11_0_free_microcode(adev); + amdgpu_gfx_sysfs_fini(adev); + kfree(adev->gfx.ip_dump_core); kfree(adev->gfx.ip_dump_compute_queues); kfree(adev->gfx.ip_dump_gfx_queues); @@ -1893,8 +1946,10 @@ static void gfx_v11_0_init_compute_vmid(struct amdgpu_device *adev) soc21_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); - /* Initialize all compute VMIDs to have no GDS, GWS, or OA - acccess. These should be enabled by FW for target VMIDs. */ + /* + * Initialize all compute VMIDs to have no GDS, GWS, or OA + * access. These should be enabled by FW for target VMIDs. + */ for (i = adev->vm_manager.first_kfd_vmid; i < AMDGPU_NUM_VMID; i++) { WREG32_SOC15_OFFSET(GC, 0, regGDS_VMID0_BASE, 2 * i, 0); WREG32_SOC15_OFFSET(GC, 0, regGDS_VMID0_SIZE, 2 * i, 0); @@ -3555,7 +3610,7 @@ static int gfx_v11_0_cp_gfx_resume(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, regCP_RB0_WPTR, lower_32_bits(ring->wptr)); WREG32_SOC15(GC, 0, regCP_RB0_WPTR_HI, upper_32_bits(ring->wptr)); - /* set the wb address wether it's enabled or not */ + /* set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; WREG32_SOC15(GC, 0, regCP_RB0_RPTR_ADDR, lower_32_bits(rptr_addr)); WREG32_SOC15(GC, 0, regCP_RB0_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & @@ -3593,7 +3648,7 @@ static int gfx_v11_0_cp_gfx_resume(struct amdgpu_device *adev) ring->wptr = 0; WREG32_SOC15(GC, 0, regCP_RB1_WPTR, lower_32_bits(ring->wptr)); WREG32_SOC15(GC, 0, regCP_RB1_WPTR_HI, upper_32_bits(ring->wptr)); - /* Set the wb address wether it's enabled or not */ + /* Set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; WREG32_SOC15(GC, 0, regCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr)); WREG32_SOC15(GC, 0, regCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & @@ -4568,10 +4623,13 @@ static void gfx_v11_0_disable_gpa_mode(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, regCPG_PSP_DEBUG, data); } -static int gfx_v11_0_hw_init(void *handle) +static int gfx_v11_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; + + amdgpu_gfx_cleaner_shader_init(adev, adev->gfx.cleaner_shader_size, + adev->gfx.cleaner_shader_ptr); if (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO) { if (adev->gfx.imu.funcs) { @@ -4665,9 +4723,9 @@ static int gfx_v11_0_hw_init(void *handle) return r; } -static int gfx_v11_0_hw_fini(void *handle) +static int gfx_v11_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -4703,14 +4761,14 @@ static int gfx_v11_0_hw_fini(void *handle) return 0; } -static int gfx_v11_0_suspend(void *handle) +static int gfx_v11_0_suspend(struct amdgpu_ip_block *ip_block) { - return gfx_v11_0_hw_fini(handle); + return gfx_v11_0_hw_fini(ip_block); } -static int gfx_v11_0_resume(void *handle) +static int gfx_v11_0_resume(struct amdgpu_ip_block *ip_block) { - return gfx_v11_0_hw_init(handle); + return gfx_v11_0_hw_init(ip_block); } static bool gfx_v11_0_is_idle(void *handle) @@ -4724,11 +4782,11 @@ static bool gfx_v11_0_is_idle(void *handle) return true; } -static int gfx_v11_0_wait_for_idle(void *handle) +static int gfx_v11_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -4774,12 +4832,12 @@ int gfx_v11_0_request_gfx_index_mutex(struct amdgpu_device *adev, return 0; } -static int gfx_v11_0_soft_reset(void *handle) +static int gfx_v11_0_soft_reset(struct amdgpu_ip_block *ip_block) { u32 grbm_soft_reset = 0; u32 tmp; int r, i, j, k; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_gfx_rlc_enter_safe_mode(adev, 0); @@ -4905,10 +4963,10 @@ static int gfx_v11_0_soft_reset(void *handle) return gfx_v11_0_cp_resume(adev); } -static bool gfx_v11_0_check_soft_reset(void *handle) +static bool gfx_v11_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { int i, r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; long tmo = msecs_to_jiffies(1000); @@ -4929,12 +4987,13 @@ static bool gfx_v11_0_check_soft_reset(void *handle) return false; } -static int gfx_v11_0_post_soft_reset(void *handle) +static int gfx_v11_0_post_soft_reset(struct amdgpu_ip_block *ip_block) { + struct amdgpu_device *adev = ip_block->adev; /** * GFX soft reset will impact MES, need resume MES when do GFX soft reset */ - return amdgpu_mes_resume((struct amdgpu_device *)handle); + return amdgpu_mes_resume(adev); } static uint64_t gfx_v11_0_get_gpu_clock_counter(struct amdgpu_device *adev) @@ -4995,9 +5054,9 @@ static void gfx_v11_0_ring_emit_gds_switch(struct amdgpu_ring *ring, (1 << (oa_size + oa_base)) - (1 << oa_base)); } -static int gfx_v11_0_early_init(void *handle) +static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfx.funcs = &gfx_v11_0_gfx_funcs; @@ -5018,9 +5077,9 @@ static int gfx_v11_0_early_init(void *handle) return gfx_v11_0_init_microcode(adev); } -static int gfx_v11_0_late_init(void *handle) +static int gfx_v11_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0); @@ -6639,9 +6698,9 @@ static int gfx_v11_0_reset_kcq(struct amdgpu_ring *ring, unsigned int vmid) return amdgpu_ring_test_ring(ring); } -static void gfx_v11_ip_print(void *handle, struct drm_printer *p) +static void gfx_v11_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k, reg, index = 0; uint32_t reg_count = ARRAY_SIZE(gc_reg_list_11_0); @@ -6703,9 +6762,9 @@ static void gfx_v11_ip_print(void *handle, struct drm_printer *p) } } -static void gfx_v11_ip_dump(void *handle) +static void gfx_v11_ip_dump(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k, reg, index = 0; uint32_t reg_count = ARRAY_SIZE(gc_reg_list_11_0); @@ -6769,6 +6828,13 @@ static void gfx_v11_ip_dump(void *handle) amdgpu_gfx_off_ctrl(adev, true); } +static void gfx_v11_0_ring_emit_cleaner_shader(struct amdgpu_ring *ring) +{ + /* Emit the cleaner shader */ + amdgpu_ring_write(ring, PACKET3(PACKET3_RUN_CLEANER_SHADER, 0)); + amdgpu_ring_write(ring, 0); /* RESERVED field, programmed to zero */ +} + static const struct amd_ip_funcs gfx_v11_0_ip_funcs = { .name = "gfx_v11_0", .early_init = gfx_v11_0_early_init, @@ -6818,7 +6884,8 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = { 5 + /* HDP_INVL */ 22 + /* SET_Q_PREEMPTION_MODE */ 8 + 8 + /* FENCE x2 */ - 8, /* gfx_v11_0_emit_mem_sync */ + 8 + /* gfx_v11_0_emit_mem_sync */ + 2, /* gfx_v11_0_ring_emit_cleaner_shader */ .emit_ib_size = 4, /* gfx_v11_0_ring_emit_ib_gfx */ .emit_ib = gfx_v11_0_ring_emit_ib_gfx, .emit_fence = gfx_v11_0_ring_emit_fence, @@ -6841,6 +6908,9 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_gfx = { .soft_recovery = gfx_v11_0_ring_soft_recovery, .emit_mem_sync = gfx_v11_0_emit_mem_sync, .reset = gfx_v11_0_reset_kgq, + .emit_cleaner_shader = gfx_v11_0_ring_emit_cleaner_shader, + .begin_use = amdgpu_gfx_enforce_isolation_ring_begin_use, + .end_use = amdgpu_gfx_enforce_isolation_ring_end_use, }; static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_compute = { @@ -6861,7 +6931,8 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_compute = { SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + 2 + /* gfx_v11_0_ring_emit_vm_flush */ 8 + 8 + 8 + /* gfx_v11_0_ring_emit_fence x3 for user fence, vm fence */ - 8, /* gfx_v11_0_emit_mem_sync */ + 8 + /* gfx_v11_0_emit_mem_sync */ + 2, /* gfx_v11_0_ring_emit_cleaner_shader */ .emit_ib_size = 7, /* gfx_v11_0_ring_emit_ib_compute */ .emit_ib = gfx_v11_0_ring_emit_ib_compute, .emit_fence = gfx_v11_0_ring_emit_fence, @@ -6879,6 +6950,9 @@ static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_compute = { .soft_recovery = gfx_v11_0_ring_soft_recovery, .emit_mem_sync = gfx_v11_0_emit_mem_sync, .reset = gfx_v11_0_reset_kcq, + .emit_cleaner_shader = gfx_v11_0_ring_emit_cleaner_shader, + .begin_use = amdgpu_gfx_enforce_isolation_ring_begin_use, + .end_use = amdgpu_gfx_enforce_isolation_ring_end_use, }; static const struct amdgpu_ring_funcs gfx_v11_0_ring_funcs_kiq = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3_cleaner_shader.asm b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3_cleaner_shader.asm new file mode 100644 index 00000000000000..9b90b66368c7ab --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_3_cleaner_shader.asm @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2024 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +// This shader is to clean LDS, SGPRs and VGPRs. It is first 64 Dwords or 256 bytes of 192 Dwords cleaner shader. +//To turn this shader program on for complitaion change this to main and lower shader main to main_1 + +// Navi3 : Clear SGPRs, VGPRs and LDS +// Launch 32 waves per CU (16 per SIMD) as a workgroup (threadgroup) to fill every wave slot +// Waves are "wave32" and have 64 VGPRs each, which uses all 1024 VGPRs per SIMD +// Waves are launched in "CU" mode, and the workgroup shares 64KB of LDS (half of the WGP's LDS) +// It takes 2 workgroups to use all of LDS: one on each CU of the WGP +// Each wave clears SGPRs 0 - 107 +// Each wave clears VGPRs 0 - 63 +// The first wave of the workgroup clears its 64KB of LDS +// The shader starts with "S_BARRIER" to ensure SPI has launched all waves of the workgroup +// before any wave in the workgroup could end. Without this, it is possible not all SGPRs get cleared. + +shader main + asic(GFX11) + type(CS) + wave_size(32) +// Note: original source code from SQ team + +// Takes about 2500 clocks to run. +// (theorhetical fastest = 1024clks vgpr + 640lds = 1660 clks) +// + S_BARRIER + + // + // CLEAR VGPRs + // + s_mov_b32 m0, 0x00000058 // Loop 96/8=12 times (loop unrolled for performance) + +label_0005: + v_movreld_b32 v0, 0 + v_movreld_b32 v1, 0 + v_movreld_b32 v2, 0 + v_movreld_b32 v3, 0 + v_movreld_b32 v4, 0 + v_movreld_b32 v5, 0 + v_movreld_b32 v6, 0 + v_movreld_b32 v7, 0 + s_sub_u32 m0, m0, 8 + s_cbranch_scc0 label_0005 + // + // + + s_mov_b32 s2, 0x80000000 // Bit31 is first_wave + s_and_b32 s2, s2, s0 // sgpr0 has tg_size (first_wave) term as in ucode only COMPUTE_PGM_RSRC2.tg_size_en is set + s_cbranch_scc0 label_0023 // Clean LDS if its first wave of ThreadGroup/WorkGroup + // CLEAR LDS + // + s_mov_b32 exec_lo, 0xffffffff + s_mov_b32 exec_hi, 0xffffffff + v_mbcnt_lo_u32_b32 v1, exec_hi, 0 // Set V1 to thread-ID (0..63) + v_mbcnt_hi_u32_b32 v1, exec_lo, v1 // Set V1 to thread-ID (0..63) + v_mul_u32_u24 v1, 0x00000008, v1 // * 8, so each thread is a double-dword address (8byte) + s_mov_b32 s2, 0x00000003f // 64 loop iterations + s_mov_b32 m0, 0xffffffff + // Clear all of LDS space + // Each FirstWave of WorkGroup clears 64kbyte block + +label_001F: + ds_write2_b64 v1, v[2:3], v[2:3] offset1:32 + ds_write2_b64 v1, v[4:5], v[4:5] offset0:64 offset1:96 + v_add_co_u32 v1, vcc, 0x00000400, v1 + s_sub_u32 s2, s2, 1 + s_cbranch_scc0 label_001F + // + // CLEAR SGPRs + // +label_0023: + s_mov_b32 m0, 0x00000068 // Loop 108/4=27 times (loop unrolled for performance) +label_sgpr_loop: + s_movreld_b32 s0, 0 + s_movreld_b32 s1, 0 + s_movreld_b32 s2, 0 + s_movreld_b32 s3, 0 + s_sub_u32 m0, m0, 4 + s_cbranch_scc0 label_sgpr_loop + + //clear vcc + s_mov_b64 vcc, 0 //clear vcc + s_mov_b32 flat_scratch_lo, 0 //clear flat scratch lo SGPR + s_mov_b32 flat_scratch_hi, 0 //clear flat scratch hi SGPR + s_mov_b64 ttmp0, 0 //Clear ttmp0 and ttmp1 + s_mov_b64 ttmp2, 0 //Clear ttmp2 and ttmp3 + s_mov_b64 ttmp4, 0 //Clear ttmp4 and ttmp5 + s_mov_b64 ttmp6, 0 //Clear ttmp6 and ttmp7 + s_mov_b64 ttmp8, 0 //Clear ttmp8 and ttmp9 + s_mov_b64 ttmp10, 0 //Clear ttmp10 and ttmp11 + s_mov_b64 ttmp12, 0 //Clear ttmp12 and ttmp13 + s_mov_b64 ttmp14, 0 //Clear ttmp14 and ttmp15 + + s_endpgm + +end + diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_cleaner_shader.h b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_cleaner_shader.h new file mode 100644 index 00000000000000..3218cc04f543e4 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0_cleaner_shader.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2024 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/* Define the cleaner shader gfx_11_0_3 */ +static const u32 gfx_11_0_3_cleaner_shader_hex[] = { + 0xb0804006, 0xbe8200ff, + 0x00000058, 0xbefd0080, + 0x7e008480, 0x7e028480, + 0x7e048480, 0x7e068480, + 0x7e088480, 0x7e0a8480, + 0x7e0c8480, 0x7e0e8480, + 0xbefd0002, 0x80828802, + 0xbfa1fff5, 0xbe8200ff, + 0x80000000, 0x8b020002, + 0xbfa10012, 0xbefe00c1, + 0xbeff00c1, 0xd71f0001, + 0x0001007f, 0xd7200001, + 0x0002027e, 0x16020288, + 0xbe8200bf, 0xbefd00c1, + 0xd9382000, 0x00020201, + 0xd9386040, 0x00040401, + 0xd7006a01, 0x000202ff, + 0x00000400, 0x80828102, + 0xbfa1fff7, 0xbefd00ff, + 0x00000068, 0xbe804280, + 0xbe814280, 0xbe824280, + 0xbe834280, 0x80fd847d, + 0xbfa1fffa, 0xbeea0180, + 0xbeec0180, 0xbeee0180, + 0xbef00180, 0xbef20180, + 0xbef40180, 0xbef60180, + 0xbef80180, 0xbefa0180, + 0xbfb00000, 0xbf9f0000, + 0xbf9f0000, 0xbf9f0000, + 0xbf9f0000, 0xbf9f0000, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index 47b47d21f46447..da327ab48a572c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -1319,12 +1319,12 @@ static void gfx_v12_0_alloc_ip_dump(struct amdgpu_device *adev) } } -static int gfx_v12_0_sw_init(void *handle) +static int gfx_v12_0_sw_init(struct amdgpu_ip_block *ip_block) { int i, j, k, r, ring_id = 0; unsigned num_compute_rings; int xcc_id = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(12, 0, 0): @@ -1346,6 +1346,12 @@ static int gfx_v12_0_sw_init(void *handle) break; } + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + default: + adev->gfx.enable_cleaner_shader = false; + break; + } + /* recalculate compute rings to use based on hardware configuration */ num_compute_rings = (adev->gfx.mec.num_pipe_per_mec * adev->gfx.mec.num_queue_per_pipe) / 2; @@ -1431,6 +1437,12 @@ static int gfx_v12_0_sw_init(void *handle) } } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->gfx.gfx_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.gfx_ring[0]); + adev->gfx.compute_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]); + if (!adev->enable_mes_kiq) { r = amdgpu_gfx_kiq_init(adev, GFX12_MEC_HPD_SIZE, 0); if (r) { @@ -1460,6 +1472,10 @@ static int gfx_v12_0_sw_init(void *handle) gfx_v12_0_alloc_ip_dump(adev); + r = amdgpu_gfx_sysfs_init(adev); + if (r) + return r; + return 0; } @@ -1492,10 +1508,10 @@ static void gfx_v12_0_rlc_autoload_buffer_fini(struct amdgpu_device *adev) (void **)&adev->gfx.rlc.rlc_autoload_ptr); } -static int gfx_v12_0_sw_fini(void *handle) +static int gfx_v12_0_sw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->gfx.num_gfx_rings; i++) amdgpu_ring_fini(&adev->gfx.gfx_ring[i]); @@ -1519,6 +1535,8 @@ static int gfx_v12_0_sw_fini(void *handle) gfx_v12_0_free_microcode(adev); + amdgpu_gfx_sysfs_fini(adev); + kfree(adev->gfx.ip_dump_core); kfree(adev->gfx.ip_dump_compute_queues); kfree(adev->gfx.ip_dump_gfx_queues); @@ -2601,7 +2619,7 @@ static int gfx_v12_0_cp_gfx_resume(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, regCP_RB0_WPTR, lower_32_bits(ring->wptr)); WREG32_SOC15(GC, 0, regCP_RB0_WPTR_HI, upper_32_bits(ring->wptr)); - /* set the wb address wether it's enabled or not */ + /* set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; WREG32_SOC15(GC, 0, regCP_RB0_RPTR_ADDR, lower_32_bits(rptr_addr)); WREG32_SOC15(GC, 0, regCP_RB0_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & @@ -3513,10 +3531,10 @@ static void gfx_v12_0_init_golden_registers(struct amdgpu_device *adev) } } -static int gfx_v12_0_hw_init(void *handle) +static int gfx_v12_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->firmware.load_type == AMDGPU_FW_LOAD_RLC_BACKDOOR_AUTO) { if (adev->gfx.imu.funcs && (amdgpu_dpm > 0)) { @@ -3603,9 +3621,9 @@ static int gfx_v12_0_hw_init(void *handle) return r; } -static int gfx_v12_0_hw_fini(void *handle) +static int gfx_v12_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t tmp; amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); @@ -3643,14 +3661,14 @@ static int gfx_v12_0_hw_fini(void *handle) return 0; } -static int gfx_v12_0_suspend(void *handle) +static int gfx_v12_0_suspend(struct amdgpu_ip_block *ip_block) { - return gfx_v12_0_hw_fini(handle); + return gfx_v12_0_hw_fini(ip_block); } -static int gfx_v12_0_resume(void *handle) +static int gfx_v12_0_resume(struct amdgpu_ip_block *ip_block) { - return gfx_v12_0_hw_init(handle); + return gfx_v12_0_hw_init(ip_block); } static bool gfx_v12_0_is_idle(void *handle) @@ -3664,11 +3682,11 @@ static bool gfx_v12_0_is_idle(void *handle) return true; } -static int gfx_v12_0_wait_for_idle(void *handle) +static int gfx_v12_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -3695,9 +3713,9 @@ static uint64_t gfx_v12_0_get_gpu_clock_counter(struct amdgpu_device *adev) return clock; } -static int gfx_v12_0_early_init(void *handle) +static int gfx_v12_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfx.funcs = &gfx_v12_0_gfx_funcs; @@ -3717,9 +3735,9 @@ static int gfx_v12_0_early_init(void *handle) return gfx_v12_0_init_microcode(adev); } -static int gfx_v12_0_late_init(void *handle) +static int gfx_v12_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0); @@ -4105,7 +4123,7 @@ static int gfx_v12_0_set_clockgating_state(void *handle, if (amdgpu_sriov_vf(adev)) return 0; - switch (adev->ip_versions[GC_HWIP][0]) { + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(12, 0, 0): case IP_VERSION(12, 0, 1): gfx_v12_0_update_gfx_clock_gating(adev, @@ -5022,8 +5040,6 @@ static void gfx_v12_0_emit_mem_sync(struct amdgpu_ring *ring) static void gfx_v12_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) { - int i; - /* Header itself is a NOP packet */ if (num_nop == 1) { amdgpu_ring_write(ring, ring->funcs->nop); @@ -5034,13 +5050,19 @@ static void gfx_v12_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) amdgpu_ring_write(ring, PACKET3(PACKET3_NOP, min(num_nop - 2, 0x3ffe))); /* Header is at index 0, followed by num_nops - 1 NOP packet's */ - for (i = 1; i < num_nop; i++) - amdgpu_ring_write(ring, ring->funcs->nop); + amdgpu_ring_insert_nop(ring, num_nop - 1); } -static void gfx_v12_ip_print(void *handle, struct drm_printer *p) +static void gfx_v12_0_ring_emit_cleaner_shader(struct amdgpu_ring *ring) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + /* Emit the cleaner shader */ + amdgpu_ring_write(ring, PACKET3(PACKET3_RUN_CLEANER_SHADER, 0)); + amdgpu_ring_write(ring, 0); /* RESERVED field, programmed to zero */ +} + +static void gfx_v12_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p) +{ + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k, reg, index = 0; uint32_t reg_count = ARRAY_SIZE(gc_reg_list_12_0); @@ -5102,9 +5124,9 @@ static void gfx_v12_ip_print(void *handle, struct drm_printer *p) } } -static void gfx_v12_ip_dump(void *handle) +static void gfx_v12_ip_dump(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k, reg, index = 0; uint32_t reg_count = ARRAY_SIZE(gc_reg_list_12_0); @@ -5297,7 +5319,8 @@ static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_gfx = { 3 + /* CNTX_CTRL */ 5 + /* HDP_INVL */ 8 + 8 + /* FENCE x2 */ - 8, /* gfx_v12_0_emit_mem_sync */ + 8 + /* gfx_v12_0_emit_mem_sync */ + 2, /* gfx_v12_0_ring_emit_cleaner_shader */ .emit_ib_size = 4, /* gfx_v12_0_ring_emit_ib_gfx */ .emit_ib = gfx_v12_0_ring_emit_ib_gfx, .emit_fence = gfx_v12_0_ring_emit_fence, @@ -5318,6 +5341,9 @@ static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_gfx = { .soft_recovery = gfx_v12_0_ring_soft_recovery, .emit_mem_sync = gfx_v12_0_emit_mem_sync, .reset = gfx_v12_0_reset_kgq, + .emit_cleaner_shader = gfx_v12_0_ring_emit_cleaner_shader, + .begin_use = amdgpu_gfx_enforce_isolation_ring_begin_use, + .end_use = amdgpu_gfx_enforce_isolation_ring_end_use, }; static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_compute = { @@ -5336,7 +5362,8 @@ static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_compute = { SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 7 + 2 + /* gfx_v12_0_ring_emit_vm_flush */ 8 + 8 + 8 + /* gfx_v12_0_ring_emit_fence x3 for user fence, vm fence */ - 8, /* gfx_v12_0_emit_mem_sync */ + 8 + /* gfx_v12_0_emit_mem_sync */ + 2, /* gfx_v12_0_ring_emit_cleaner_shader */ .emit_ib_size = 7, /* gfx_v12_0_ring_emit_ib_compute */ .emit_ib = gfx_v12_0_ring_emit_ib_compute, .emit_fence = gfx_v12_0_ring_emit_fence, @@ -5353,6 +5380,9 @@ static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_compute = { .soft_recovery = gfx_v12_0_ring_soft_recovery, .emit_mem_sync = gfx_v12_0_emit_mem_sync, .reset = gfx_v12_0_reset_kcq, + .emit_cleaner_shader = gfx_v12_0_ring_emit_cleaner_shader, + .begin_use = amdgpu_gfx_enforce_isolation_ring_begin_use, + .end_use = amdgpu_gfx_enforce_isolation_ring_end_use, }; static const struct amdgpu_ring_funcs gfx_v12_0_ring_funcs_kiq = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 564f0b9336b6aa..41f50bf380c405 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -3023,9 +3023,9 @@ static const struct amdgpu_rlc_funcs gfx_v6_0_rlc_funcs = { .start = gfx_v6_0_rlc_start }; -static int gfx_v6_0_early_init(void *handle) +static int gfx_v6_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfx.xcc_mask = 1; adev->gfx.num_gfx_rings = GFX6_NUM_GFX_RINGS; @@ -3039,10 +3039,10 @@ static int gfx_v6_0_early_init(void *handle) return 0; } -static int gfx_v6_0_sw_init(void *handle) +static int gfx_v6_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r; r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 181, &adev->gfx.eop_irq); @@ -3107,10 +3107,10 @@ static int gfx_v6_0_sw_init(void *handle) return r; } -static int gfx_v6_0_sw_fini(void *handle) +static int gfx_v6_0_sw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->gfx.num_gfx_rings; i++) amdgpu_ring_fini(&adev->gfx.gfx_ring[i]); @@ -3122,10 +3122,10 @@ static int gfx_v6_0_sw_fini(void *handle) return 0; } -static int gfx_v6_0_hw_init(void *handle) +static int gfx_v6_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gfx_v6_0_constants_init(adev); @@ -3142,9 +3142,9 @@ static int gfx_v6_0_hw_init(void *handle) return r; } -static int gfx_v6_0_hw_fini(void *handle) +static int gfx_v6_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gfx_v6_0_cp_enable(adev, false); adev->gfx.rlc.funcs->stop(adev); @@ -3153,18 +3153,14 @@ static int gfx_v6_0_hw_fini(void *handle) return 0; } -static int gfx_v6_0_suspend(void *handle) +static int gfx_v6_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return gfx_v6_0_hw_fini(adev); + return gfx_v6_0_hw_fini(ip_block); } -static int gfx_v6_0_resume(void *handle) +static int gfx_v6_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return gfx_v6_0_hw_init(adev); + return gfx_v6_0_hw_init(ip_block); } static bool gfx_v6_0_is_idle(void *handle) @@ -3177,24 +3173,19 @@ static bool gfx_v6_0_is_idle(void *handle) return true; } -static int gfx_v6_0_wait_for_idle(void *handle) +static int gfx_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { - if (gfx_v6_0_is_idle(handle)) + if (gfx_v6_0_is_idle(adev)) return 0; udelay(1); } return -ETIMEDOUT; } -static int gfx_v6_0_soft_reset(void *handle) -{ - return 0; -} - static void gfx_v6_0_set_gfx_eop_interrupt_state(struct amdgpu_device *adev, enum amdgpu_interrupt_state state) { @@ -3444,7 +3435,6 @@ static void gfx_v6_0_emit_mem_sync(struct amdgpu_ring *ring) static const struct amd_ip_funcs gfx_v6_0_ip_funcs = { .name = "gfx_v6_0", .early_init = gfx_v6_0_early_init, - .late_init = NULL, .sw_init = gfx_v6_0_sw_init, .sw_fini = gfx_v6_0_sw_fini, .hw_init = gfx_v6_0_hw_init, @@ -3453,11 +3443,8 @@ static const struct amd_ip_funcs gfx_v6_0_ip_funcs = { .resume = gfx_v6_0_resume, .is_idle = gfx_v6_0_is_idle, .wait_for_idle = gfx_v6_0_wait_for_idle, - .soft_reset = gfx_v6_0_soft_reset, .set_clockgating_state = gfx_v6_0_set_clockgating_state, .set_powergating_state = gfx_v6_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs gfx_v6_0_ring_funcs_gfx = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index f146806c4633ba..824d5913103b37 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -2559,7 +2559,7 @@ static int gfx_v7_0_cp_gfx_resume(struct amdgpu_device *adev) ring->wptr = 0; WREG32(mmCP_RB0_WPTR, lower_32_bits(ring->wptr)); - /* set the wb address wether it's enabled or not */ + /* set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; WREG32(mmCP_RB0_RPTR_ADDR, lower_32_bits(rptr_addr)); WREG32(mmCP_RB0_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF); @@ -2876,7 +2876,7 @@ static void gfx_v7_0_mqd_init(struct amdgpu_device *adev, mqd->cp_hqd_pq_wptr_poll_addr_lo = wb_gpu_addr & 0xfffffffc; mqd->cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff; - /* set the wb address wether it's enabled or not */ + /* set the wb address whether it's enabled or not */ wb_gpu_addr = ring->rptr_gpu_addr; mqd->cp_hqd_pq_rptr_report_addr_lo = wb_gpu_addr & 0xfffffffc; mqd->cp_hqd_pq_rptr_report_addr_hi = @@ -4134,9 +4134,9 @@ static const struct amdgpu_rlc_funcs gfx_v7_0_rlc_funcs = { .update_spm_vmid = gfx_v7_0_update_spm_vmid }; -static int gfx_v7_0_early_init(void *handle) +static int gfx_v7_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfx.xcc_mask = 1; adev->gfx.num_gfx_rings = GFX7_NUM_GFX_RINGS; @@ -4151,9 +4151,9 @@ static int gfx_v7_0_early_init(void *handle) return 0; } -static int gfx_v7_0_late_init(void *handle) +static int gfx_v7_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0); @@ -4343,10 +4343,10 @@ static int gfx_v7_0_compute_ring_init(struct amdgpu_device *adev, int ring_id, return 0; } -static int gfx_v7_0_sw_init(void *handle) +static int gfx_v7_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j, k, r, ring_id; switch (adev->asic_type) { @@ -4439,9 +4439,9 @@ static int gfx_v7_0_sw_init(void *handle) return r; } -static int gfx_v7_0_sw_fini(void *handle) +static int gfx_v7_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->gfx.num_gfx_rings; i++) @@ -4465,10 +4465,10 @@ static int gfx_v7_0_sw_fini(void *handle) return 0; } -static int gfx_v7_0_hw_init(void *handle) +static int gfx_v7_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gfx_v7_0_constants_init(adev); @@ -4486,9 +4486,9 @@ static int gfx_v7_0_hw_init(void *handle) return r; } -static int gfx_v7_0_hw_fini(void *handle) +static int gfx_v7_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -4499,18 +4499,14 @@ static int gfx_v7_0_hw_fini(void *handle) return 0; } -static int gfx_v7_0_suspend(void *handle) +static int gfx_v7_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return gfx_v7_0_hw_fini(adev); + return gfx_v7_0_hw_fini(ip_block); } -static int gfx_v7_0_resume(void *handle) +static int gfx_v7_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return gfx_v7_0_hw_init(adev); + return gfx_v7_0_hw_init(ip_block); } static bool gfx_v7_0_is_idle(void *handle) @@ -4523,11 +4519,11 @@ static bool gfx_v7_0_is_idle(void *handle) return true; } -static int gfx_v7_0_wait_for_idle(void *handle) +static int gfx_v7_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -4540,11 +4536,11 @@ static int gfx_v7_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int gfx_v7_0_soft_reset(void *handle) +static int gfx_v7_0_soft_reset(struct amdgpu_ip_block *ip_block) { u32 grbm_soft_reset = 0, srbm_soft_reset = 0; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* GRBM_STATUS */ tmp = RREG32(mmGRBM_STATUS); @@ -5009,8 +5005,6 @@ static const struct amd_ip_funcs gfx_v7_0_ip_funcs = { .soft_reset = gfx_v7_0_soft_reset, .set_clockgating_state = gfx_v7_0_set_clockgating_state, .set_powergating_state = gfx_v7_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index bc8295812cc842..b7006c41e270b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1894,12 +1894,12 @@ static int gfx_v8_0_compute_ring_init(struct amdgpu_device *adev, int ring_id, static void gfx_v8_0_sq_irq_work_func(struct work_struct *work); -static int gfx_v8_0_sw_init(void *handle) +static int gfx_v8_0_sw_init(struct amdgpu_ip_block *ip_block) { int i, j, k, r, ring_id; int xcc_id = 0; struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; switch (adev->asic_type) { case CHIP_TONGA: @@ -2037,9 +2037,9 @@ static int gfx_v8_0_sw_init(void *handle) return 0; } -static int gfx_v8_0_sw_fini(void *handle) +static int gfx_v8_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->gfx.num_gfx_rings; i++) @@ -4260,7 +4260,7 @@ static int gfx_v8_0_cp_gfx_resume(struct amdgpu_device *adev) ring->wptr = 0; WREG32(mmCP_RB0_WPTR, lower_32_bits(ring->wptr)); - /* set the wb address wether it's enabled or not */ + /* set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; WREG32(mmCP_RB0_RPTR_ADDR, lower_32_bits(rptr_addr)); WREG32(mmCP_RB0_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & 0xFF); @@ -4783,10 +4783,10 @@ static void gfx_v8_0_cp_enable(struct amdgpu_device *adev, bool enable) gfx_v8_0_cp_compute_enable(adev, enable); } -static int gfx_v8_0_hw_init(void *handle) +static int gfx_v8_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gfx_v8_0_init_golden_registers(adev); gfx_v8_0_constants_init(adev); @@ -4823,6 +4823,13 @@ static int gfx_v8_0_kcq_disable(struct amdgpu_device *adev) amdgpu_ring_write(kiq_ring, 0); amdgpu_ring_write(kiq_ring, 0); } + /* Submit unmap queue packet */ + amdgpu_ring_commit(kiq_ring); + /* + * Ring test will do a basic scratch register change check. Just run + * this to ensure that unmap queues that is submitted before got + * processed successfully before returning. + */ r = amdgpu_ring_test_helper(kiq_ring); if (r) DRM_ERROR("KCQ disable failed\n"); @@ -4865,13 +4872,13 @@ static int gfx_v8_0_wait_for_rlc_idle(void *handle) return -ETIMEDOUT; } -static int gfx_v8_0_wait_for_idle(void *handle) +static int gfx_v8_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { - if (gfx_v8_0_is_idle(handle)) + if (gfx_v8_0_is_idle(adev)) return 0; udelay(1); @@ -4879,9 +4886,9 @@ static int gfx_v8_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int gfx_v8_0_hw_fini(void *handle) +static int gfx_v8_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); @@ -4897,8 +4904,9 @@ static int gfx_v8_0_hw_fini(void *handle) pr_debug("For SRIOV client, shouldn't do anything.\n"); return 0; } + amdgpu_gfx_rlc_enter_safe_mode(adev, 0); - if (!gfx_v8_0_wait_for_idle(adev)) + if (!gfx_v8_0_wait_for_idle(ip_block)) gfx_v8_0_cp_enable(adev, false); else pr_err("cp is busy, skip halt cp\n"); @@ -4911,19 +4919,19 @@ static int gfx_v8_0_hw_fini(void *handle) return 0; } -static int gfx_v8_0_suspend(void *handle) +static int gfx_v8_0_suspend(struct amdgpu_ip_block *ip_block) { - return gfx_v8_0_hw_fini(handle); + return gfx_v8_0_hw_fini(ip_block); } -static int gfx_v8_0_resume(void *handle) +static int gfx_v8_0_resume(struct amdgpu_ip_block *ip_block) { - return gfx_v8_0_hw_init(handle); + return gfx_v8_0_hw_init(ip_block); } -static bool gfx_v8_0_check_soft_reset(void *handle) +static bool gfx_v8_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 grbm_soft_reset = 0, srbm_soft_reset = 0; u32 tmp; @@ -4983,9 +4991,9 @@ static bool gfx_v8_0_check_soft_reset(void *handle) } } -static int gfx_v8_0_pre_soft_reset(void *handle) +static int gfx_v8_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 grbm_soft_reset = 0; if ((!adev->gfx.grbm_soft_reset) && @@ -5024,9 +5032,9 @@ static int gfx_v8_0_pre_soft_reset(void *handle) return 0; } -static int gfx_v8_0_soft_reset(void *handle) +static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 grbm_soft_reset = 0, srbm_soft_reset = 0; u32 tmp; @@ -5086,9 +5094,9 @@ static int gfx_v8_0_soft_reset(void *handle) return 0; } -static int gfx_v8_0_post_soft_reset(void *handle) +static int gfx_v8_0_post_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 grbm_soft_reset = 0; if ((!adev->gfx.grbm_soft_reset) && @@ -5254,9 +5262,9 @@ static const struct amdgpu_gfx_funcs gfx_v8_0_gfx_funcs = { .select_me_pipe_q = &gfx_v8_0_select_me_pipe_q }; -static int gfx_v8_0_early_init(void *handle) +static int gfx_v8_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfx.xcc_mask = 1; adev->gfx.num_gfx_rings = GFX8_NUM_GFX_RINGS; @@ -5271,9 +5279,9 @@ static int gfx_v8_0_early_init(void *handle) return 0; } -static int gfx_v8_0_late_init(void *handle) +static int gfx_v8_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0); @@ -6947,8 +6955,6 @@ static const struct amd_ip_funcs gfx_v8_0_ip_funcs = { .set_clockgating_state = gfx_v8_0_set_clockgating_state, .set_powergating_state = gfx_v8_0_set_powergating_state, .get_clockgating_state = gfx_v8_0_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 23f0573ae47b33..0b6f09f2cc9bd0 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -2198,12 +2198,12 @@ static void gfx_v9_0_alloc_ip_dump(struct amdgpu_device *adev) } } -static int gfx_v9_0_sw_init(void *handle) +static int gfx_v9_0_sw_init(struct amdgpu_ip_block *ip_block) { int i, j, k, r, ring_id; int xcc_id = 0; struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; unsigned int hw_prio; switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { @@ -2223,6 +2223,18 @@ static int gfx_v9_0_sw_init(void *handle) } switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + case IP_VERSION(9, 4, 2): + adev->gfx.cleaner_shader_ptr = gfx_9_4_2_cleaner_shader_hex; + adev->gfx.cleaner_shader_size = sizeof(gfx_9_4_2_cleaner_shader_hex); + if (adev->gfx.mec_fw_version >= 88) { + adev->gfx.enable_cleaner_shader = true; + r = amdgpu_gfx_cleaner_shader_sw_init(adev, adev->gfx.cleaner_shader_size); + if (r) { + adev->gfx.enable_cleaner_shader = false; + dev_err(adev->dev, "Failed to initialize cleaner shader\n"); + } + } + break; default: adev->gfx.enable_cleaner_shader = false; break; @@ -2362,6 +2374,12 @@ static int gfx_v9_0_sw_init(void *handle) } } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->gfx.gfx_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.gfx_ring[0]); + adev->gfx.compute_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]); + r = amdgpu_gfx_kiq_init(adev, GFX9_MEC_HPD_SIZE, 0); if (r) { DRM_ERROR("Failed to init KIQ BOs!\n"); @@ -2390,7 +2408,7 @@ static int gfx_v9_0_sw_init(void *handle) gfx_v9_0_alloc_ip_dump(adev); - r = amdgpu_gfx_sysfs_isolation_shader_init(adev); + r = amdgpu_gfx_sysfs_init(adev); if (r) return r; @@ -2398,10 +2416,10 @@ static int gfx_v9_0_sw_init(void *handle) } -static int gfx_v9_0_sw_fini(void *handle) +static int gfx_v9_0_sw_fini(struct amdgpu_ip_block *ip_block) { int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->gfx.mcbp && adev->gfx.num_gfx_rings) { for (i = 0; i < GFX9_NUM_SW_GFX_RINGS; i++) @@ -2418,6 +2436,8 @@ static int gfx_v9_0_sw_fini(void *handle) amdgpu_gfx_kiq_free_ring(&adev->gfx.kiq[0].ring); amdgpu_gfx_kiq_fini(adev, 0); + amdgpu_gfx_cleaner_shader_sw_fini(adev); + gfx_v9_0_mec_fini(adev); amdgpu_bo_free_kernel(&adev->gfx.rlc.clear_state_obj, &adev->gfx.rlc.clear_state_gpu_addr, @@ -2429,7 +2449,7 @@ static int gfx_v9_0_sw_fini(void *handle) } gfx_v9_0_free_microcode(adev); - amdgpu_gfx_sysfs_isolation_shader_fini(adev); + amdgpu_gfx_sysfs_fini(adev); kfree(adev->gfx.ip_dump_core); kfree(adev->gfx.ip_dump_compute_queues); @@ -3184,6 +3204,15 @@ static void gfx_v9_0_cp_gfx_enable(struct amdgpu_device *adev, bool enable) { u32 tmp = RREG32_SOC15(GC, 0, mmCP_ME_CNTL); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, CE_INVALIDATE_ICACHE, enable ? 0 : 1); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, PFP_INVALIDATE_ICACHE, enable ? 0 : 1); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, ME_INVALIDATE_ICACHE, enable ? 0 : 1); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, CE_PIPE0_RESET, enable ? 0 : 1); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, CE_PIPE1_RESET, enable ? 0 : 1); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, PFP_PIPE0_RESET, enable ? 0 : 1); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, PFP_PIPE1_RESET, enable ? 0 : 1); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, ME_PIPE0_RESET, enable ? 0 : 1); + tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, ME_PIPE1_RESET, enable ? 0 : 1); tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, ME_HALT, enable ? 0 : 1); tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, PFP_HALT, enable ? 0 : 1); tmp = REG_SET_FIELD(tmp, CP_ME_CNTL, CE_HALT, enable ? 0 : 1); @@ -3265,8 +3294,8 @@ static int gfx_v9_0_cp_gfx_start(struct amdgpu_device *adev) * confirmed that the APU gfx10/gfx11 needn't such update. */ if (adev->flags & AMD_IS_APU && - adev->in_s3 && !adev->suspend_complete) { - DRM_INFO(" Will skip the CSB packet resubmit\n"); + adev->in_s3 && !pm_resume_via_firmware()) { + DRM_INFO("Will skip the CSB packet resubmit\n"); return 0; } r = amdgpu_ring_alloc(ring, gfx_v9_0_get_csb_size(adev) + 4 + 3); @@ -3346,7 +3375,7 @@ static int gfx_v9_0_cp_gfx_resume(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, mmCP_RB0_WPTR, lower_32_bits(ring->wptr)); WREG32_SOC15(GC, 0, mmCP_RB0_WPTR_HI, upper_32_bits(ring->wptr)); - /* set the wb address wether it's enabled or not */ + /* set the wb address whether it's enabled or not */ rptr_addr = ring->rptr_gpu_addr; WREG32_SOC15(GC, 0, mmCP_RB0_RPTR_ADDR, lower_32_bits(rptr_addr)); WREG32_SOC15(GC, 0, mmCP_RB0_RPTR_ADDR_HI, upper_32_bits(rptr_addr) & CP_RB_RPTR_ADDR_HI__RB_RPTR_ADDR_HI_MASK); @@ -3393,7 +3422,15 @@ static void gfx_v9_0_cp_compute_enable(struct amdgpu_device *adev, bool enable) WREG32_SOC15_RLC(GC, 0, mmCP_MEC_CNTL, 0); } else { WREG32_SOC15_RLC(GC, 0, mmCP_MEC_CNTL, - (CP_MEC_CNTL__MEC_ME1_HALT_MASK | CP_MEC_CNTL__MEC_ME2_HALT_MASK)); + (CP_MEC_CNTL__MEC_INVALIDATE_ICACHE_MASK | + CP_MEC_CNTL__MEC_ME1_PIPE0_RESET_MASK | + CP_MEC_CNTL__MEC_ME1_PIPE1_RESET_MASK | + CP_MEC_CNTL__MEC_ME1_PIPE2_RESET_MASK | + CP_MEC_CNTL__MEC_ME1_PIPE3_RESET_MASK | + CP_MEC_CNTL__MEC_ME2_PIPE0_RESET_MASK | + CP_MEC_CNTL__MEC_ME2_PIPE1_RESET_MASK | + CP_MEC_CNTL__MEC_ME1_HALT_MASK | + CP_MEC_CNTL__MEC_ME2_HALT_MASK)); adev->gfx.kiq[0].ring.sched.ready = false; } udelay(50); @@ -3914,6 +3951,10 @@ static int gfx_v9_0_cp_resume(struct amdgpu_device *adev) return r; } + if (adev->gfx.num_gfx_rings) + gfx_v9_0_cp_gfx_enable(adev, false); + gfx_v9_0_cp_compute_enable(adev, false); + r = gfx_v9_0_kiq_resume(adev); if (r) return r; @@ -3970,10 +4011,10 @@ static void gfx_v9_0_cp_enable(struct amdgpu_device *adev, bool enable) gfx_v9_0_cp_compute_enable(adev, enable); } -static int gfx_v9_0_hw_init(void *handle) +static int gfx_v9_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_gfx_cleaner_shader_init(adev, adev->gfx.cleaner_shader_size, adev->gfx.cleaner_shader_ptr); @@ -3999,9 +4040,9 @@ static int gfx_v9_0_hw_init(void *handle) return r; } -static int gfx_v9_0_hw_fini(void *handle) +static int gfx_v9_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__GFX)) amdgpu_irq_put(adev, &adev->gfx.cp_ecc_error_irq, 0); @@ -4051,14 +4092,14 @@ static int gfx_v9_0_hw_fini(void *handle) return 0; } -static int gfx_v9_0_suspend(void *handle) +static int gfx_v9_0_suspend(struct amdgpu_ip_block *ip_block) { - return gfx_v9_0_hw_fini(handle); + return gfx_v9_0_hw_fini(ip_block); } -static int gfx_v9_0_resume(void *handle) +static int gfx_v9_0_resume(struct amdgpu_ip_block *ip_block) { - return gfx_v9_0_hw_init(handle); + return gfx_v9_0_hw_init(ip_block); } static bool gfx_v9_0_is_idle(void *handle) @@ -4072,24 +4113,24 @@ static bool gfx_v9_0_is_idle(void *handle) return true; } -static int gfx_v9_0_wait_for_idle(void *handle) +static int gfx_v9_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { - if (gfx_v9_0_is_idle(handle)) + if (gfx_v9_0_is_idle(adev)) return 0; udelay(1); } return -ETIMEDOUT; } -static int gfx_v9_0_soft_reset(void *handle) +static int gfx_v9_0_soft_reset(struct amdgpu_ip_block *ip_block) { u32 grbm_soft_reset = 0; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* GRBM_STATUS */ tmp = RREG32_SOC15(GC, 0, mmGRBM_STATUS); @@ -4745,9 +4786,9 @@ static int gfx_v9_0_do_edc_gpr_workarounds(struct amdgpu_device *adev) return r; } -static int gfx_v9_0_early_init(void *handle) +static int gfx_v9_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfx.funcs = &gfx_v9_0_gfx_funcs; @@ -4771,9 +4812,9 @@ static int gfx_v9_0_early_init(void *handle) return gfx_v9_0_init_microcode(adev); } -static int gfx_v9_0_ecc_late_init(void *handle) +static int gfx_v9_0_ecc_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; /* @@ -4805,9 +4846,9 @@ static int gfx_v9_0_ecc_late_init(void *handle) return 0; } -static int gfx_v9_0_late_init(void *handle) +static int gfx_v9_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0); @@ -4822,7 +4863,7 @@ static int gfx_v9_0_late_init(void *handle) if (r) return r; - r = gfx_v9_0_ecc_late_init(handle); + r = gfx_v9_0_ecc_late_init(ip_block); if (r) return r; @@ -7167,8 +7208,6 @@ static void gfx_v9_0_emit_wave_limit(struct amdgpu_ring *ring, bool enable) static void gfx_v9_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) { - int i; - /* Header itself is a NOP packet */ if (num_nop == 1) { amdgpu_ring_write(ring, ring->funcs->nop); @@ -7179,8 +7218,7 @@ static void gfx_v9_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) amdgpu_ring_write(ring, PACKET3(PACKET3_NOP, min(num_nop - 2, 0x3ffe))); /* Header is at index 0, followed by num_nops - 1 NOP packet's */ - for (i = 1; i < num_nop; i++) - amdgpu_ring_write(ring, ring->funcs->nop); + amdgpu_ring_insert_nop(ring, num_nop - 1); } static int gfx_v9_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid) @@ -7237,10 +7275,6 @@ static int gfx_v9_0_reset_kcq(struct amdgpu_ring *ring, unsigned long flags; int i, r; - if (!adev->debug_exp_resets && - !adev->gfx.num_gfx_rings) - return -EINVAL; - if (amdgpu_sriov_vf(adev)) return -EINVAL; @@ -7316,9 +7350,9 @@ static int gfx_v9_0_reset_kcq(struct amdgpu_ring *ring, return amdgpu_ring_test_ring(ring); } -static void gfx_v9_ip_print(void *handle, struct drm_printer *p) +static void gfx_v9_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k, reg, index = 0; uint32_t reg_count = ARRAY_SIZE(gc_reg_list_9); @@ -7356,9 +7390,9 @@ static void gfx_v9_ip_print(void *handle, struct drm_printer *p) } -static void gfx_v9_ip_dump(void *handle) +static void gfx_v9_ip_dump(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k, reg, index = 0; uint32_t reg_count = ARRAY_SIZE(gc_reg_list_9); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0_cleaner_shader.h b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0_cleaner_shader.h index 36c0292b511067..0b6bd09b752993 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0_cleaner_shader.h +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0_cleaner_shader.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: MIT */ /* - * Copyright 2018 Advanced Micro Devices, Inc. + * Copyright 2024 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -24,3 +24,45 @@ static const u32 __maybe_unused gfx_9_0_cleaner_shader_hex[] = { /* Add the cleaner shader code here */ }; + +/* Define the cleaner shader gfx_9_4_2 */ +static const u32 gfx_9_4_2_cleaner_shader_hex[] = { + 0xbf068100, 0xbf84003b, + 0xbf8a0000, 0xb07c0000, + 0xbe8200ff, 0x00000078, + 0xbf110802, 0x7e000280, + 0x7e020280, 0x7e040280, + 0x7e060280, 0x7e080280, + 0x7e0a0280, 0x7e0c0280, + 0x7e0e0280, 0x80828802, + 0xbe803202, 0xbf84fff5, + 0xbf9c0000, 0xbe8200ff, + 0x80000000, 0x86020102, + 0xbf840011, 0xbefe00c1, + 0xbeff00c1, 0xd28c0001, + 0x0001007f, 0xd28d0001, + 0x0002027e, 0x10020288, + 0xbe8200bf, 0xbefc00c1, + 0xd89c2000, 0x00020201, + 0xd89c6040, 0x00040401, + 0x320202ff, 0x00000400, + 0x80828102, 0xbf84fff8, + 0xbefc00ff, 0x0000005c, + 0xbf800000, 0xbe802c80, + 0xbe812c80, 0xbe822c80, + 0xbe832c80, 0x80fc847c, + 0xbf84fffa, 0xbee60080, + 0xbee70080, 0xbeea0180, + 0xbeec0180, 0xbeee0180, + 0xbef00180, 0xbef20180, + 0xbef40180, 0xbef60180, + 0xbef80180, 0xbefa0180, + 0xbf810000, 0xbf8d0001, + 0xbefc00ff, 0x0000005c, + 0xbf800000, 0xbe802c80, + 0xbe812c80, 0xbe822c80, + 0xbe832c80, 0x80fc847c, + 0xbf84fffa, 0xbee60080, + 0xbee70080, 0xbeea01ff, + 0x000000ee, 0xbf810000, +}; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2_cleaner_shader.asm b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2_cleaner_shader.asm new file mode 100644 index 00000000000000..35b8cf9070bd98 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_2_cleaner_shader.asm @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2024 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +// This shader is to clean LDS, SGPRs and VGPRs. It is first 64 Dwords or 256 bytes of 192 Dwords cleaner shader. +//To turn this shader program on for complitaion change this to main and lower shader main to main_1 + +// MI200 : Clear SGPRs, VGPRs and LDS +// Uses two kernels launched separately: +// 1. Clean VGPRs, LDS, and lower SGPRs +// Launches one workgroup per CU, each workgroup with 4x wave64 per SIMD in the CU +// Waves are "wave64" and have 128 VGPRs each, which uses all 512 VGPRs per SIMD +// Waves in the workgroup share the 64KB of LDS +// Each wave clears SGPRs 0 - 95. Because there are 4 waves/SIMD, this is physical SGPRs 0-383 +// Each wave clears 128 VGPRs, so all 512 in the SIMD +// The first wave of the workgroup clears its 64KB of LDS +// The shader starts with "S_BARRIER" to ensure SPI has launched all waves of the workgroup +// before any wave in the workgroup could end. Without this, it is possible not all SGPRs get cleared. +// 2. Clean remaining SGPRs +// Launches a workgroup with 24 waves per workgroup, yielding 6 waves per SIMD in each CU +// Waves are allocating 96 SGPRs +// CP sets up SPI_RESOURCE_RESERVE_* registers to prevent these waves from allocating SGPRs 0-223. +// As such, these 6 waves per SIMD are allocated physical SGPRs 224-799 +// Barriers do not work for >16 waves per workgroup, so we cannot start with S_BARRIER +// Instead, the shader starts with an S_SETHALT 1. Once all waves are launched CP will send unhalt command +// The shader then clears all SGPRs allocated to it, cleaning out physical SGPRs 224-799 + +shader main + asic(MI200) + type(CS) + wave_size(64) +// Note: original source code from SQ team + +// (theorhetical fastest = ~512clks vgpr + 1536 lds + ~128 sgpr = 2176 clks) + + s_cmp_eq_u32 s0, 1 // Bit0 is set, sgpr0 is set then clear VGPRS and LDS as FW set COMPUTE_USER_DATA_3 + s_cbranch_scc0 label_0023 // Clean VGPRs and LDS if sgpr0 of wave is set, scc = (s3 == 1) + S_BARRIER + + s_movk_i32 m0, 0x0000 + s_mov_b32 s2, 0x00000078 // Loop 128/8=16 times (loop unrolled for performance) + // + // CLEAR VGPRs + // + s_set_gpr_idx_on s2, 0x8 // enable Dest VGPR indexing +label_0005: + v_mov_b32 v0, 0 + v_mov_b32 v1, 0 + v_mov_b32 v2, 0 + v_mov_b32 v3, 0 + v_mov_b32 v4, 0 + v_mov_b32 v5, 0 + v_mov_b32 v6, 0 + v_mov_b32 v7, 0 + s_sub_u32 s2, s2, 8 + s_set_gpr_idx_idx s2 + s_cbranch_scc0 label_0005 + s_set_gpr_idx_off + + // + // + + s_mov_b32 s2, 0x80000000 // Bit31 is first_wave + s_and_b32 s2, s2, s1 // sgpr0 has tg_size (first_wave) term as in ucode only COMPUTE_PGM_RSRC2.tg_size_en is set + s_cbranch_scc0 label_clean_sgpr_1 // Clean LDS if its first wave of ThreadGroup/WorkGroup + // CLEAR LDS + // + s_mov_b32 exec_lo, 0xffffffff + s_mov_b32 exec_hi, 0xffffffff + v_mbcnt_lo_u32_b32 v1, exec_hi, 0 // Set V1 to thread-ID (0..63) + v_mbcnt_hi_u32_b32 v1, exec_lo, v1 // Set V1 to thread-ID (0..63) + v_mul_u32_u24 v1, 0x00000008, v1 // * 8, so each thread is a double-dword address (8byte) + s_mov_b32 s2, 0x00000003f // 64 loop iterations + s_mov_b32 m0, 0xffffffff + // Clear all of LDS space + // Each FirstWave of WorkGroup clears 64kbyte block + +label_001F: + ds_write2_b64 v1, v[2:3], v[2:3] offset1:32 + ds_write2_b64 v1, v[4:5], v[4:5] offset0:64 offset1:96 + v_add_co_u32 v1, vcc, 0x00000400, v1 + s_sub_u32 s2, s2, 1 + s_cbranch_scc0 label_001F + // + // CLEAR SGPRs + // +label_clean_sgpr_1: + s_mov_b32 m0, 0x0000005c // Loop 96/4=24 times (loop unrolled for performance) + s_nop 0 +label_sgpr_loop: + s_movreld_b32 s0, 0 + s_movreld_b32 s1, 0 + s_movreld_b32 s2, 0 + s_movreld_b32 s3, 0 + s_sub_u32 m0, m0, 4 + s_cbranch_scc0 label_sgpr_loop + + //clear vcc, flat scratch + s_mov_b32 flat_scratch_lo, 0 //clear flat scratch lo SGPR + s_mov_b32 flat_scratch_hi, 0 //clear flat scratch hi SGPR + s_mov_b64 vcc, 0 //clear vcc + s_mov_b64 ttmp0, 0 //Clear ttmp0 and ttmp1 + s_mov_b64 ttmp2, 0 //Clear ttmp2 and ttmp3 + s_mov_b64 ttmp4, 0 //Clear ttmp4 and ttmp5 + s_mov_b64 ttmp6, 0 //Clear ttmp6 and ttmp7 + s_mov_b64 ttmp8, 0 //Clear ttmp8 and ttmp9 + s_mov_b64 ttmp10, 0 //Clear ttmp10 and ttmp11 + s_mov_b64 ttmp12, 0 //Clear ttmp12 and ttmp13 + s_mov_b64 ttmp14, 0 //Clear ttmp14 and ttmp15 +s_endpgm + +label_0023: + + s_sethalt 1 + + s_mov_b32 m0, 0x0000005c // Loop 96/4=24 times (loop unrolled for performance) + s_nop 0 +label_sgpr_loop1: + + s_movreld_b32 s0, 0 + s_movreld_b32 s1, 0 + s_movreld_b32 s2, 0 + s_movreld_b32 s3, 0 + s_sub_u32 m0, m0, 4 + s_cbranch_scc0 label_sgpr_loop1 + + //clear vcc, flat scratch + s_mov_b32 flat_scratch_lo, 0 //clear flat scratch lo SGPR + s_mov_b32 flat_scratch_hi, 0 //clear flat scratch hi SGPR + s_mov_b64 vcc, 0xee //clear vcc + +s_endpgm +end + diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index c100845409f794..54459254bd37bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -45,6 +45,8 @@ MODULE_FIRMWARE("amdgpu/gc_9_4_3_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_9_4_4_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_9_4_3_rlc.bin"); MODULE_FIRMWARE("amdgpu/gc_9_4_4_rlc.bin"); +MODULE_FIRMWARE("amdgpu/gc_9_4_3_sjt_mec.bin"); +MODULE_FIRMWARE("amdgpu/gc_9_4_4_sjt_mec.bin"); #define GFX9_MEC_HPD_SIZE 4096 #define RLCG_UCODE_LOADING_START_ADDRESS 0x00002000L @@ -574,8 +576,12 @@ static int gfx_v9_4_3_init_cp_compute_microcode(struct amdgpu_device *adev, { int err; - err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, - "amdgpu/%s_mec.bin", chip_name); + if (amdgpu_sriov_vf(adev)) + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, + "amdgpu/%s_sjt_mec.bin", chip_name); + else + err = amdgpu_ucode_request(adev, &adev->gfx.mec_fw, + "amdgpu/%s_mec.bin", chip_name); if (err) goto out; amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1); @@ -1049,10 +1055,10 @@ static void gfx_v9_4_3_alloc_ip_dump(struct amdgpu_device *adev) } } -static int gfx_v9_4_3_sw_init(void *handle) +static int gfx_v9_4_3_sw_init(struct amdgpu_ip_block *ip_block) { int i, j, k, r, ring_id, xcc_id, num_xcc; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(9, 4, 3): @@ -1157,6 +1163,19 @@ static int gfx_v9_4_3_sw_init(void *handle) return r; } + adev->gfx.compute_supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]); + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + case IP_VERSION(9, 4, 3): + case IP_VERSION(9, 4, 4): + if (adev->gfx.mec_fw_version >= 155) { + adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_PER_PIPE; + } + break; + default: + break; + } r = gfx_v9_4_3_gpu_early_init(adev); if (r) return r; @@ -1165,26 +1184,19 @@ static int gfx_v9_4_3_sw_init(void *handle) if (r) return r; - - if (!amdgpu_sriov_vf(adev)) { - r = amdgpu_gfx_sysfs_init(adev); - if (r) - return r; - } - - gfx_v9_4_3_alloc_ip_dump(adev); - - r = amdgpu_gfx_sysfs_isolation_shader_init(adev); + r = amdgpu_gfx_sysfs_init(adev); if (r) return r; + gfx_v9_4_3_alloc_ip_dump(adev); + return 0; } -static int gfx_v9_4_3_sw_fini(void *handle) +static int gfx_v9_4_3_sw_fini(struct amdgpu_ip_block *ip_block) { int i, num_xcc; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; num_xcc = NUM_XCC(adev->gfx.xcc_mask); for (i = 0; i < adev->gfx.num_compute_rings * num_xcc; i++) @@ -1201,9 +1213,7 @@ static int gfx_v9_4_3_sw_fini(void *handle) gfx_v9_4_3_mec_fini(adev); amdgpu_bo_unref(&adev->gfx.rlc.clear_state_obj); gfx_v9_4_3_free_microcode(adev); - if (!amdgpu_sriov_vf(adev)) - amdgpu_gfx_sysfs_fini(adev); - amdgpu_gfx_sysfs_isolation_shader_fini(adev); + amdgpu_gfx_sysfs_fini(adev); kfree(adev->gfx.ip_dump_core); kfree(adev->gfx.ip_dump_compute_queues); @@ -1247,8 +1257,10 @@ static void gfx_v9_4_3_xcc_init_compute_vmid(struct amdgpu_device *adev, soc15_grbm_select(adev, 0, 0, 0, 0, GET_INST(GC, xcc_id)); mutex_unlock(&adev->srbm_mutex); - /* Initialize all compute VMIDs to have no GDS, GWS, or OA - acccess. These should be enabled by FW for target VMIDs. */ + /* + * Initialize all compute VMIDs to have no GDS, GWS, or OA + * access. These should be enabled by FW for target VMIDs. + */ for (i = adev->vm_manager.first_kfd_vmid; i < AMDGPU_NUM_VMID; i++) { WREG32_SOC15_OFFSET(GC, GET_INST(GC, xcc_id), regGDS_VMID0_BASE, 2 * i, 0); WREG32_SOC15_OFFSET(GC, GET_INST(GC, xcc_id), regGDS_VMID0_SIZE, 2 * i, 0); @@ -2343,10 +2355,10 @@ static void gfx_v9_4_3_xcc_fini(struct amdgpu_device *adev, int xcc_id) gfx_v9_4_3_xcc_cp_compute_enable(adev, false, xcc_id); } -static int gfx_v9_4_3_hw_init(void *handle) +static int gfx_v9_4_3_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_gfx_cleaner_shader_init(adev, adev->gfx.cleaner_shader_size, adev->gfx.cleaner_shader_ptr); @@ -2367,9 +2379,9 @@ static int gfx_v9_4_3_hw_init(void *handle) return r; } -static int gfx_v9_4_3_hw_fini(void *handle) +static int gfx_v9_4_3_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, num_xcc; amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); @@ -2384,14 +2396,14 @@ static int gfx_v9_4_3_hw_fini(void *handle) return 0; } -static int gfx_v9_4_3_suspend(void *handle) +static int gfx_v9_4_3_suspend(struct amdgpu_ip_block *ip_block) { - return gfx_v9_4_3_hw_fini(handle); + return gfx_v9_4_3_hw_fini(ip_block); } -static int gfx_v9_4_3_resume(void *handle) +static int gfx_v9_4_3_resume(struct amdgpu_ip_block *ip_block) { - return gfx_v9_4_3_hw_init(handle); + return gfx_v9_4_3_hw_init(ip_block); } static bool gfx_v9_4_3_is_idle(void *handle) @@ -2408,24 +2420,24 @@ static bool gfx_v9_4_3_is_idle(void *handle) return true; } -static int gfx_v9_4_3_wait_for_idle(void *handle) +static int gfx_v9_4_3_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { - if (gfx_v9_4_3_is_idle(handle)) + if (gfx_v9_4_3_is_idle(adev)) return 0; udelay(1); } return -ETIMEDOUT; } -static int gfx_v9_4_3_soft_reset(void *handle) +static int gfx_v9_4_3_soft_reset(struct amdgpu_ip_block *ip_block) { u32 grbm_soft_reset = 0; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* GRBM_STATUS */ tmp = RREG32_SOC15(GC, GET_INST(GC, 0), regGRBM_STATUS); @@ -2509,9 +2521,9 @@ static void gfx_v9_4_3_ring_emit_gds_switch(struct amdgpu_ring *ring, (1 << (oa_size + oa_base)) - (1 << oa_base)); } -static int gfx_v9_4_3_early_init(void *handle) +static int gfx_v9_4_3_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev), AMDGPU_MAX_COMPUTE_RINGS); @@ -2527,9 +2539,9 @@ static int gfx_v9_4_3_early_init(void *handle) return gfx_v9_4_3_init_microcode(adev); } -static int gfx_v9_4_3_late_init(void *handle) +static int gfx_v9_4_3_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0); @@ -3056,9 +3068,6 @@ static void gfx_v9_4_3_ring_soft_recovery(struct amdgpu_ring *ring, struct amdgpu_device *adev = ring->adev; uint32_t value = 0; - if (!adev->debug_exp_resets) - return; - value = REG_SET_FIELD(value, SQ_CMD, CMD, 0x03); value = REG_SET_FIELD(value, SQ_CMD, MODE, 0x01); value = REG_SET_FIELD(value, SQ_CMD, CHECK_VMID, 1); @@ -3574,9 +3583,6 @@ static int gfx_v9_4_3_reset_kcq(struct amdgpu_ring *ring, unsigned long flags; int r; - if (!adev->debug_exp_resets) - return -EINVAL; - if (amdgpu_sriov_vf(adev)) return -EINVAL; @@ -4567,8 +4573,6 @@ static void gfx_v9_4_3_enable_watchdog_timer(struct amdgpu_device *adev) static void gfx_v9_4_3_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_nop) { - int i; - /* Header itself is a NOP packet */ if (num_nop == 1) { amdgpu_ring_write(ring, ring->funcs->nop); @@ -4579,13 +4583,12 @@ static void gfx_v9_4_3_ring_insert_nop(struct amdgpu_ring *ring, uint32_t num_no amdgpu_ring_write(ring, PACKET3(PACKET3_NOP, min(num_nop - 2, 0x3ffe))); /* Header is at index 0, followed by num_nops - 1 NOP packet's */ - for (i = 1; i < num_nop; i++) - amdgpu_ring_write(ring, ring->funcs->nop); + amdgpu_ring_insert_nop(ring, num_nop - 1); } -static void gfx_v9_4_3_ip_print(void *handle, struct drm_printer *p) +static void gfx_v9_4_3_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k; uint32_t xcc_id, xcc_offset, inst_offset; uint32_t num_xcc, reg, num_inst; @@ -4643,9 +4646,9 @@ static void gfx_v9_4_3_ip_print(void *handle, struct drm_printer *p) } } -static void gfx_v9_4_3_ip_dump(void *handle) +static void gfx_v9_4_3_ip_dump(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t i, j, k; uint32_t num_xcc, reg, num_inst; uint32_t xcc_id, xcc_offset, inst_offset; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index 9784a28921853f..697599c46240ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -175,7 +175,10 @@ static int gmc_v10_0_process_interrupt(struct amdgpu_device *adev, addr, entry->client_id, soc15_ih_clientid_name[entry->client_id]); - if (!amdgpu_sriov_vf(adev)) + /* Only print L2 fault status if the status register could be read and + * contains useful information + */ + if (status != 0) hub->vmhub_funcs->print_l2_protection_fault_status(adev, status); @@ -630,9 +633,9 @@ static void gmc_v10_0_set_gfxhub_funcs(struct amdgpu_device *adev) } -static int gmc_v10_0_early_init(void *handle) +static int gmc_v10_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v10_0_set_mmhub_funcs(adev); gmc_v10_0_set_gfxhub_funcs(adev); @@ -651,9 +654,9 @@ static int gmc_v10_0_early_init(void *handle) return 0; } -static int gmc_v10_0_late_init(void *handle) +static int gmc_v10_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_gmc_allocate_vm_inv_eng(adev); @@ -769,10 +772,10 @@ static int gmc_v10_0_gart_init(struct amdgpu_device *adev) return amdgpu_gart_table_vram_alloc(adev); } -static int gmc_v10_0_sw_init(void *handle) +static int gmc_v10_0_sw_init(struct amdgpu_ip_block *ip_block) { int r, vram_width = 0, vram_type = 0, vram_vendor = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->gfxhub.funcs->init(adev); @@ -920,9 +923,9 @@ static void gmc_v10_0_gart_fini(struct amdgpu_device *adev) amdgpu_gart_table_vram_free(adev); } -static int gmc_v10_0_sw_fini(void *handle) +static int gmc_v10_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_vm_manager_fini(adev); gmc_v10_0_gart_fini(adev); @@ -985,9 +988,9 @@ static int gmc_v10_0_gart_enable(struct amdgpu_device *adev) return 0; } -static int gmc_v10_0_hw_init(void *handle) +static int gmc_v10_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; adev->gmc.flush_pasid_uses_kiq = !amdgpu_emu_mode; @@ -1032,9 +1035,9 @@ static void gmc_v10_0_gart_disable(struct amdgpu_device *adev) adev->mmhub.funcs->gart_disable(adev); } -static int gmc_v10_0_hw_fini(void *handle) +static int gmc_v10_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v10_0_gart_disable(adev); @@ -1053,25 +1056,22 @@ static int gmc_v10_0_hw_fini(void *handle) return 0; } -static int gmc_v10_0_suspend(void *handle) +static int gmc_v10_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - gmc_v10_0_hw_fini(adev); + gmc_v10_0_hw_fini(ip_block); return 0; } -static int gmc_v10_0_resume(void *handle) +static int gmc_v10_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = gmc_v10_0_hw_init(adev); + r = gmc_v10_0_hw_init(ip_block); if (r) return r; - amdgpu_vmid_reset_all(adev); + amdgpu_vmid_reset_all(ip_block->adev); return 0; } @@ -1082,17 +1082,12 @@ static bool gmc_v10_0_is_idle(void *handle) return true; } -static int gmc_v10_0_wait_for_idle(void *handle) +static int gmc_v10_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* There is no need to wait for MC idle in GMC v10.*/ return 0; } -static int gmc_v10_0_soft_reset(void *handle) -{ - return 0; -} - static int gmc_v10_0_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -1154,7 +1149,6 @@ const struct amd_ip_funcs gmc_v10_0_ip_funcs = { .resume = gmc_v10_0_resume, .is_idle = gmc_v10_0_is_idle, .wait_for_idle = gmc_v10_0_wait_for_idle, - .soft_reset = gmc_v10_0_soft_reset, .set_clockgating_state = gmc_v10_0_set_clockgating_state, .set_powergating_state = gmc_v10_0_set_powergating_state, .get_clockgating_state = gmc_v10_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index 2797fd84432b22..f893ab4c14df35 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -144,7 +144,10 @@ static int gmc_v11_0_process_interrupt(struct amdgpu_device *adev, dev_err(adev->dev, " in page starting at address 0x%016llx from client %d\n", addr, entry->client_id); - if (!amdgpu_sriov_vf(adev)) + /* Only print L2 fault status if the status register could be read and + * contains useful information + */ + if (status != 0) hub->vmhub_funcs->print_l2_protection_fault_status(adev, status); } @@ -601,9 +604,9 @@ static void gmc_v11_0_set_gfxhub_funcs(struct amdgpu_device *adev) } } -static int gmc_v11_0_early_init(void *handle) +static int gmc_v11_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v11_0_set_gfxhub_funcs(adev); gmc_v11_0_set_mmhub_funcs(adev); @@ -622,9 +625,9 @@ static int gmc_v11_0_early_init(void *handle) return 0; } -static int gmc_v11_0_late_init(void *handle) +static int gmc_v11_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_gmc_allocate_vm_inv_eng(adev); @@ -729,10 +732,10 @@ static int gmc_v11_0_gart_init(struct amdgpu_device *adev) return amdgpu_gart_table_vram_alloc(adev); } -static int gmc_v11_0_sw_init(void *handle) +static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block) { int r, vram_width = 0, vram_type = 0, vram_vendor = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->mmhub.funcs->init(adev); @@ -849,9 +852,9 @@ static void gmc_v11_0_gart_fini(struct amdgpu_device *adev) amdgpu_gart_table_vram_free(adev); } -static int gmc_v11_0_sw_fini(void *handle) +static int gmc_v11_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_vm_manager_fini(adev); gmc_v11_0_gart_fini(adev); @@ -908,9 +911,9 @@ static int gmc_v11_0_gart_enable(struct amdgpu_device *adev) return 0; } -static int gmc_v11_0_hw_init(void *handle) +static int gmc_v11_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; adev->gmc.flush_pasid_uses_kiq = !amdgpu_emu_mode; @@ -940,9 +943,9 @@ static void gmc_v11_0_gart_disable(struct amdgpu_device *adev) adev->mmhub.funcs->gart_disable(adev); } -static int gmc_v11_0_hw_fini(void *handle) +static int gmc_v11_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) { /* full access mode, so don't touch any GMC register */ @@ -961,25 +964,22 @@ static int gmc_v11_0_hw_fini(void *handle) return 0; } -static int gmc_v11_0_suspend(void *handle) +static int gmc_v11_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - gmc_v11_0_hw_fini(adev); + gmc_v11_0_hw_fini(ip_block); return 0; } -static int gmc_v11_0_resume(void *handle) +static int gmc_v11_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = gmc_v11_0_hw_init(adev); + r = gmc_v11_0_hw_init(ip_block); if (r) return r; - amdgpu_vmid_reset_all(adev); + amdgpu_vmid_reset_all(ip_block->adev); return 0; } @@ -990,17 +990,12 @@ static bool gmc_v11_0_is_idle(void *handle) return true; } -static int gmc_v11_0_wait_for_idle(void *handle) +static int gmc_v11_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* There is no need to wait for MC idle in GMC v11.*/ return 0; } -static int gmc_v11_0_soft_reset(void *handle) -{ - return 0; -} - static int gmc_v11_0_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -1041,7 +1036,6 @@ const struct amd_ip_funcs gmc_v11_0_ip_funcs = { .resume = gmc_v11_0_resume, .is_idle = gmc_v11_0_is_idle, .wait_for_idle = gmc_v11_0_wait_for_idle, - .soft_reset = gmc_v11_0_soft_reset, .set_clockgating_state = gmc_v11_0_set_clockgating_state, .set_powergating_state = gmc_v11_0_set_powergating_state, .get_clockgating_state = gmc_v11_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c index edcb5351f8cca7..d22b027fd0bb8f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v12_0.c @@ -137,7 +137,10 @@ static int gmc_v12_0_process_interrupt(struct amdgpu_device *adev, dev_err(adev->dev, " in page starting at address 0x%016llx from client %d\n", addr, entry->client_id); - if (!amdgpu_sriov_vf(adev)) + /* Only print L2 fault status if the status register could be read and + * contains useful information + */ + if (status != 0) hub->vmhub_funcs->print_l2_protection_fault_status(adev, status); } @@ -604,9 +607,9 @@ static void gmc_v12_0_set_gfxhub_funcs(struct amdgpu_device *adev) } } -static int gmc_v12_0_early_init(void *handle) +static int gmc_v12_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v12_0_set_gfxhub_funcs(adev); gmc_v12_0_set_mmhub_funcs(adev); @@ -624,9 +627,9 @@ static int gmc_v12_0_early_init(void *handle) return 0; } -static int gmc_v12_0_late_init(void *handle) +static int gmc_v12_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_gmc_allocate_vm_inv_eng(adev); @@ -731,10 +734,10 @@ static int gmc_v12_0_gart_init(struct amdgpu_device *adev) return amdgpu_gart_table_vram_alloc(adev); } -static int gmc_v12_0_sw_init(void *handle) +static int gmc_v12_0_sw_init(struct amdgpu_ip_block *ip_block) { int r, vram_width = 0, vram_type = 0, vram_vendor = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->mmhub.funcs->init(adev); @@ -841,9 +844,9 @@ static void gmc_v12_0_gart_fini(struct amdgpu_device *adev) amdgpu_gart_table_vram_free(adev); } -static int gmc_v12_0_sw_fini(void *handle) +static int gmc_v12_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_vm_manager_fini(adev); gmc_v12_0_gart_fini(adev); @@ -894,10 +897,10 @@ static int gmc_v12_0_gart_enable(struct amdgpu_device *adev) return 0; } -static int gmc_v12_0_hw_init(void *handle) +static int gmc_v12_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* The sequence of these two function calls matters.*/ gmc_v12_0_init_golden_registers(adev); @@ -924,9 +927,9 @@ static void gmc_v12_0_gart_disable(struct amdgpu_device *adev) adev->mmhub.funcs->gart_disable(adev); } -static int gmc_v12_0_hw_fini(void *handle) +static int gmc_v12_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) { /* full access mode, so don't touch any GMC register */ @@ -945,25 +948,22 @@ static int gmc_v12_0_hw_fini(void *handle) return 0; } -static int gmc_v12_0_suspend(void *handle) +static int gmc_v12_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - gmc_v12_0_hw_fini(adev); + gmc_v12_0_hw_fini(ip_block); return 0; } -static int gmc_v12_0_resume(void *handle) +static int gmc_v12_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = gmc_v12_0_hw_init(adev); + r = gmc_v12_0_hw_init(ip_block); if (r) return r; - amdgpu_vmid_reset_all(adev); + amdgpu_vmid_reset_all(ip_block->adev); return 0; } @@ -974,17 +974,12 @@ static bool gmc_v12_0_is_idle(void *handle) return true; } -static int gmc_v12_0_wait_for_idle(void *handle) +static int gmc_v12_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* There is no need to wait for MC idle in GMC v11.*/ return 0; } -static int gmc_v12_0_soft_reset(void *handle) -{ - return 0; -} - static int gmc_v12_0_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -1025,7 +1020,6 @@ const struct amd_ip_funcs gmc_v12_0_ip_funcs = { .resume = gmc_v12_0_resume, .is_idle = gmc_v12_0_is_idle, .wait_for_idle = gmc_v12_0_wait_for_idle, - .soft_reset = gmc_v12_0_soft_reset, .set_clockgating_state = gmc_v12_0_set_clockgating_state, .set_powergating_state = gmc_v12_0_set_powergating_state, .get_clockgating_state = gmc_v12_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index d36725666b54cc..ca000b3d1afcd1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -43,7 +43,7 @@ static void gmc_v6_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v6_0_set_irq_funcs(struct amdgpu_device *adev); -static int gmc_v6_0_wait_for_idle(void *handle); +static int gmc_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block); MODULE_FIRMWARE("amdgpu/tahiti_mc.bin"); MODULE_FIRMWARE("amdgpu/pitcairn_mc.bin"); @@ -64,8 +64,13 @@ MODULE_FIRMWARE("amdgpu/si58_mc.bin"); static void gmc_v6_0_mc_stop(struct amdgpu_device *adev) { u32 blackout; + struct amdgpu_ip_block *ip_block; - gmc_v6_0_wait_for_idle((void *)adev); + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GMC); + if (!ip_block) + return; + + gmc_v6_0_wait_for_idle(ip_block); blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL); if (REG_GET_FIELD(blackout, MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE) != 1) { @@ -213,6 +218,8 @@ static void gmc_v6_0_vram_gtt_location(struct amdgpu_device *adev, static void gmc_v6_0_mc_program(struct amdgpu_device *adev) { int i, j; + struct amdgpu_ip_block *ip_block; + /* Initialize HDP */ for (i = 0, j = 0; i < 32; i++, j += 0x6) { @@ -224,7 +231,11 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev) } WREG32(mmHDP_REG_COHERENCY_FLUSH_CNTL, 0); - if (gmc_v6_0_wait_for_idle((void *)adev)) + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GMC); + if (!ip_block) + return; + + if (gmc_v6_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for MC idle timedout !\n"); if (adev->mode_info.num_crtc) { @@ -251,7 +262,7 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev) WREG32(mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 22); WREG32(mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 22); - if (gmc_v6_0_wait_for_idle((void *)adev)) + if (gmc_v6_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for MC idle timedout !\n"); } @@ -762,9 +773,9 @@ static int gmc_v6_0_convert_vram_type(int mc_seq_vram_type) } } -static int gmc_v6_0_early_init(void *handle) +static int gmc_v6_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v6_0_set_gmc_funcs(adev); gmc_v6_0_set_irq_funcs(adev); @@ -772,9 +783,9 @@ static int gmc_v6_0_early_init(void *handle) return 0; } -static int gmc_v6_0_late_init(void *handle) +static int gmc_v6_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS) return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0); @@ -799,10 +810,10 @@ static unsigned int gmc_v6_0_get_vbios_fb_size(struct amdgpu_device *adev) return size; } -static int gmc_v6_0_sw_init(void *handle) +static int gmc_v6_0_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; set_bit(AMDGPU_GFXHUB(0), adev->vmhubs_mask); @@ -876,9 +887,9 @@ static int gmc_v6_0_sw_init(void *handle) return 0; } -static int gmc_v6_0_sw_fini(void *handle) +static int gmc_v6_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_gem_force_release(adev); amdgpu_vm_manager_fini(adev); @@ -889,10 +900,10 @@ static int gmc_v6_0_sw_fini(void *handle) return 0; } -static int gmc_v6_0_hw_init(void *handle) +static int gmc_v6_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v6_0_mc_program(adev); @@ -914,9 +925,9 @@ static int gmc_v6_0_hw_init(void *handle) return 0; } -static int gmc_v6_0_hw_fini(void *handle) +static int gmc_v6_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v6_0_gart_disable(adev); @@ -924,21 +935,19 @@ static int gmc_v6_0_hw_fini(void *handle) return 0; } -static int gmc_v6_0_suspend(void *handle) +static int gmc_v6_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - gmc_v6_0_hw_fini(adev); + gmc_v6_0_hw_fini(ip_block); return 0; } -static int gmc_v6_0_resume(void *handle) +static int gmc_v6_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; - r = gmc_v6_0_hw_init(adev); + r = gmc_v6_0_hw_init(ip_block); if (r) return r; @@ -950,6 +959,7 @@ static int gmc_v6_0_resume(void *handle) static bool gmc_v6_0_is_idle(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + u32 tmp = RREG32(mmSRBM_STATUS); if (tmp & (SRBM_STATUS__MCB_BUSY_MASK | SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK | @@ -959,13 +969,13 @@ static bool gmc_v6_0_is_idle(void *handle) return true; } -static int gmc_v6_0_wait_for_idle(void *handle) +static int gmc_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned int i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { - if (gmc_v6_0_is_idle(handle)) + if (gmc_v6_0_is_idle(adev)) return 0; udelay(1); } @@ -973,9 +983,10 @@ static int gmc_v6_0_wait_for_idle(void *handle) } -static int gmc_v6_0_soft_reset(void *handle) +static int gmc_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; + u32 srbm_soft_reset = 0; u32 tmp = RREG32(mmSRBM_STATUS); @@ -992,7 +1003,8 @@ static int gmc_v6_0_soft_reset(void *handle) if (srbm_soft_reset) { gmc_v6_0_mc_stop(adev); - if (gmc_v6_0_wait_for_idle(adev)) + + if (gmc_v6_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for GMC idle timed out !\n"); tmp = RREG32(mmSRBM_SOFT_RESET); @@ -1109,8 +1121,6 @@ static const struct amd_ip_funcs gmc_v6_0_ip_funcs = { .soft_reset = gmc_v6_0_soft_reset, .set_clockgating_state = gmc_v6_0_set_clockgating_state, .set_powergating_state = gmc_v6_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_gmc_funcs gmc_v6_0_gmc_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 994432fb57eafa..b6016f11956ec1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -52,7 +52,7 @@ static void gmc_v7_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev); -static int gmc_v7_0_wait_for_idle(void *handle); +static int gmc_v7_0_wait_for_idle(struct amdgpu_ip_block *ip_block); MODULE_FIRMWARE("amdgpu/bonaire_mc.bin"); MODULE_FIRMWARE("amdgpu/hawaii_mc.bin"); @@ -87,9 +87,14 @@ static void gmc_v7_0_init_golden_registers(struct amdgpu_device *adev) static void gmc_v7_0_mc_stop(struct amdgpu_device *adev) { + struct amdgpu_ip_block *ip_block; u32 blackout; - gmc_v7_0_wait_for_idle((void *)adev); + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GMC); + if (!ip_block) + return; + + gmc_v7_0_wait_for_idle(ip_block); blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL); if (REG_GET_FIELD(blackout, MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE) != 1) { @@ -251,9 +256,14 @@ static void gmc_v7_0_vram_gtt_location(struct amdgpu_device *adev, */ static void gmc_v7_0_mc_program(struct amdgpu_device *adev) { + struct amdgpu_ip_block *ip_block; u32 tmp; int i, j; + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GMC); + if (!ip_block) + return; + /* Initialize HDP */ for (i = 0, j = 0; i < 32; i++, j += 0x6) { WREG32((0xb05 + j), 0x00000000); @@ -264,7 +274,7 @@ static void gmc_v7_0_mc_program(struct amdgpu_device *adev) } WREG32(mmHDP_REG_COHERENCY_FLUSH_CNTL, 0); - if (gmc_v7_0_wait_for_idle((void *)adev)) + if (gmc_v7_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for MC idle timedout !\n"); if (adev->mode_info.num_crtc) { @@ -288,7 +298,7 @@ static void gmc_v7_0_mc_program(struct amdgpu_device *adev) WREG32(mmMC_VM_AGP_BASE, 0); WREG32(mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 22); WREG32(mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 22); - if (gmc_v7_0_wait_for_idle((void *)adev)) + if (gmc_v7_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for MC idle timedout !\n"); WREG32(mmBIF_FB_EN, BIF_FB_EN__FB_READ_EN_MASK | BIF_FB_EN__FB_WRITE_EN_MASK); @@ -921,9 +931,9 @@ static int gmc_v7_0_convert_vram_type(int mc_seq_vram_type) } } -static int gmc_v7_0_early_init(void *handle) +static int gmc_v7_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v7_0_set_gmc_funcs(adev); gmc_v7_0_set_irq_funcs(adev); @@ -940,9 +950,9 @@ static int gmc_v7_0_early_init(void *handle) return 0; } -static int gmc_v7_0_late_init(void *handle) +static int gmc_v7_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS) return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0); @@ -968,10 +978,10 @@ static unsigned int gmc_v7_0_get_vbios_fb_size(struct amdgpu_device *adev) return size; } -static int gmc_v7_0_sw_init(void *handle) +static int gmc_v7_0_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; set_bit(AMDGPU_GFXHUB(0), adev->vmhubs_mask); @@ -1060,9 +1070,9 @@ static int gmc_v7_0_sw_init(void *handle) return 0; } -static int gmc_v7_0_sw_fini(void *handle) +static int gmc_v7_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_gem_force_release(adev); amdgpu_vm_manager_fini(adev); @@ -1074,10 +1084,10 @@ static int gmc_v7_0_sw_fini(void *handle) return 0; } -static int gmc_v7_0_hw_init(void *handle) +static int gmc_v7_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v7_0_init_golden_registers(adev); @@ -1101,9 +1111,9 @@ static int gmc_v7_0_hw_init(void *handle) return 0; } -static int gmc_v7_0_hw_fini(void *handle) +static int gmc_v7_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v7_0_gart_disable(adev); @@ -1111,25 +1121,22 @@ static int gmc_v7_0_hw_fini(void *handle) return 0; } -static int gmc_v7_0_suspend(void *handle) +static int gmc_v7_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - gmc_v7_0_hw_fini(adev); + gmc_v7_0_hw_fini(ip_block); return 0; } -static int gmc_v7_0_resume(void *handle) +static int gmc_v7_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = gmc_v7_0_hw_init(adev); + r = gmc_v7_0_hw_init(ip_block); if (r) return r; - amdgpu_vmid_reset_all(adev); + amdgpu_vmid_reset_all(ip_block->adev); return 0; } @@ -1146,11 +1153,11 @@ static bool gmc_v7_0_is_idle(void *handle) return true; } -static int gmc_v7_0_wait_for_idle(void *handle) +static int gmc_v7_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned int i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -1167,9 +1174,9 @@ static int gmc_v7_0_wait_for_idle(void *handle) } -static int gmc_v7_0_soft_reset(void *handle) +static int gmc_v7_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; u32 tmp = RREG32(mmSRBM_STATUS); @@ -1186,7 +1193,7 @@ static int gmc_v7_0_soft_reset(void *handle) if (srbm_soft_reset) { gmc_v7_0_mc_stop(adev); - if (gmc_v7_0_wait_for_idle((void *)adev)) + if (gmc_v7_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for GMC idle timed out !\n"); tmp = RREG32(mmSRBM_SOFT_RESET); @@ -1351,8 +1358,6 @@ static const struct amd_ip_funcs gmc_v7_0_ip_funcs = { .soft_reset = gmc_v7_0_soft_reset, .set_clockgating_state = gmc_v7_0_set_clockgating_state, .set_powergating_state = gmc_v7_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_gmc_funcs gmc_v7_0_gmc_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 86488c052f8224..12d5967ecd45fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -53,7 +53,7 @@ static void gmc_v8_0_set_gmc_funcs(struct amdgpu_device *adev); static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev); -static int gmc_v8_0_wait_for_idle(void *handle); +static int gmc_v8_0_wait_for_idle(struct amdgpu_ip_block *ip_block); MODULE_FIRMWARE("amdgpu/tonga_mc.bin"); MODULE_FIRMWARE("amdgpu/polaris11_mc.bin"); @@ -170,8 +170,13 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev) static void gmc_v8_0_mc_stop(struct amdgpu_device *adev) { u32 blackout; + struct amdgpu_ip_block *ip_block; - gmc_v8_0_wait_for_idle(adev); + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GMC); + if (!ip_block) + return; + + gmc_v8_0_wait_for_idle(ip_block); blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL); if (REG_GET_FIELD(blackout, MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE) != 1) { @@ -426,6 +431,7 @@ static void gmc_v8_0_vram_gtt_location(struct amdgpu_device *adev, */ static void gmc_v8_0_mc_program(struct amdgpu_device *adev) { + struct amdgpu_ip_block *ip_block; u32 tmp; int i, j; @@ -439,7 +445,11 @@ static void gmc_v8_0_mc_program(struct amdgpu_device *adev) } WREG32(mmHDP_REG_COHERENCY_FLUSH_CNTL, 0); - if (gmc_v8_0_wait_for_idle((void *)adev)) + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GMC); + if (!ip_block) + return; + + if (gmc_v8_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for MC idle timedout !\n"); if (adev->mode_info.num_crtc) { @@ -474,7 +484,7 @@ static void gmc_v8_0_mc_program(struct amdgpu_device *adev) WREG32(mmMC_VM_AGP_BASE, 0); WREG32(mmMC_VM_AGP_TOP, adev->gmc.agp_end >> 22); WREG32(mmMC_VM_AGP_BOT, adev->gmc.agp_start >> 22); - if (gmc_v8_0_wait_for_idle((void *)adev)) + if (gmc_v8_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for MC idle timedout !\n"); WREG32(mmBIF_FB_EN, BIF_FB_EN__FB_READ_EN_MASK | BIF_FB_EN__FB_WRITE_EN_MASK); @@ -1027,9 +1037,9 @@ static int gmc_v8_0_convert_vram_type(int mc_seq_vram_type) } } -static int gmc_v8_0_early_init(void *handle) +static int gmc_v8_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v8_0_set_gmc_funcs(adev); gmc_v8_0_set_irq_funcs(adev); @@ -1046,9 +1056,9 @@ static int gmc_v8_0_early_init(void *handle) return 0; } -static int gmc_v8_0_late_init(void *handle) +static int gmc_v8_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS) return amdgpu_irq_get(adev, &adev->gmc.vm_fault, 0); @@ -1076,10 +1086,10 @@ static unsigned int gmc_v8_0_get_vbios_fb_size(struct amdgpu_device *adev) #define mmMC_SEQ_MISC0_FIJI 0xA71 -static int gmc_v8_0_sw_init(void *handle) +static int gmc_v8_0_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; set_bit(AMDGPU_GFXHUB(0), adev->vmhubs_mask); @@ -1173,9 +1183,9 @@ static int gmc_v8_0_sw_init(void *handle) return 0; } -static int gmc_v8_0_sw_fini(void *handle) +static int gmc_v8_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_gem_force_release(adev); amdgpu_vm_manager_fini(adev); @@ -1187,10 +1197,10 @@ static int gmc_v8_0_sw_fini(void *handle) return 0; } -static int gmc_v8_0_hw_init(void *handle) +static int gmc_v8_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v8_0_init_golden_registers(adev); @@ -1222,9 +1232,9 @@ static int gmc_v8_0_hw_init(void *handle) return 0; } -static int gmc_v8_0_hw_fini(void *handle) +static int gmc_v8_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); gmc_v8_0_gart_disable(adev); @@ -1232,25 +1242,22 @@ static int gmc_v8_0_hw_fini(void *handle) return 0; } -static int gmc_v8_0_suspend(void *handle) +static int gmc_v8_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - gmc_v8_0_hw_fini(adev); + gmc_v8_0_hw_fini(ip_block); return 0; } -static int gmc_v8_0_resume(void *handle) +static int gmc_v8_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = gmc_v8_0_hw_init(adev); + r = gmc_v8_0_hw_init(ip_block); if (r) return r; - amdgpu_vmid_reset_all(adev); + amdgpu_vmid_reset_all(ip_block->adev); return 0; } @@ -1267,11 +1274,11 @@ static bool gmc_v8_0_is_idle(void *handle) return true; } -static int gmc_v8_0_wait_for_idle(void *handle) +static int gmc_v8_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned int i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -1289,10 +1296,10 @@ static int gmc_v8_0_wait_for_idle(void *handle) } -static bool gmc_v8_0_check_soft_reset(void *handle) +static bool gmc_v8_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { u32 srbm_soft_reset = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 tmp = RREG32(mmSRBM_STATUS); if (tmp & SRBM_STATUS__VMC_BUSY_MASK) @@ -1316,23 +1323,23 @@ static bool gmc_v8_0_check_soft_reset(void *handle) return false; } -static int gmc_v8_0_pre_soft_reset(void *handle) +static int gmc_v8_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->gmc.srbm_soft_reset) return 0; gmc_v8_0_mc_stop(adev); - if (gmc_v8_0_wait_for_idle(adev)) + if (gmc_v8_0_wait_for_idle(ip_block)) dev_warn(adev->dev, "Wait for GMC idle timed out !\n"); return 0; } -static int gmc_v8_0_soft_reset(void *handle) +static int gmc_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset; if (!adev->gmc.srbm_soft_reset) @@ -1361,9 +1368,9 @@ static int gmc_v8_0_soft_reset(void *handle) return 0; } -static int gmc_v8_0_post_soft_reset(void *handle) +static int gmc_v8_0_post_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->gmc.srbm_soft_reset) return 0; @@ -1715,8 +1722,6 @@ static const struct amd_ip_funcs gmc_v8_0_ip_funcs = { .set_clockgating_state = gmc_v8_0_set_clockgating_state, .set_powergating_state = gmc_v8_0_set_powergating_state, .get_clockgating_state = gmc_v8_0_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_gmc_funcs gmc_v8_0_gmc_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 7a45f3fdc73410..50c5da3020cb31 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -672,6 +672,12 @@ static int gmc_v9_0_process_interrupt(struct amdgpu_device *adev, (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(9, 4, 2))) return 0; + /* Only print L2 fault status if the status register could be read and + * contains useful information + */ + if (!status) + return 0; + if (!amdgpu_sriov_vf(adev)) WREG32_P(hub->vm_l2_pro_fault_cntl, 1, ~1); @@ -1389,15 +1395,45 @@ gmc_v9_0_get_memory_partition(struct amdgpu_device *adev, u32 *supp_modes) return mode; } +static enum amdgpu_memory_partition +gmc_v9_0_query_vf_memory_partition(struct amdgpu_device *adev) +{ + switch (adev->gmc.num_mem_partitions) { + case 0: + return UNKNOWN_MEMORY_PARTITION_MODE; + case 1: + return AMDGPU_NPS1_PARTITION_MODE; + case 2: + return AMDGPU_NPS2_PARTITION_MODE; + case 4: + return AMDGPU_NPS4_PARTITION_MODE; + default: + return AMDGPU_NPS1_PARTITION_MODE; + } + + return AMDGPU_NPS1_PARTITION_MODE; +} + static enum amdgpu_memory_partition gmc_v9_0_query_memory_partition(struct amdgpu_device *adev) { if (amdgpu_sriov_vf(adev)) - return AMDGPU_NPS1_PARTITION_MODE; + return gmc_v9_0_query_vf_memory_partition(adev); return gmc_v9_0_get_memory_partition(adev, NULL); } +static bool gmc_v9_0_need_reset_on_init(struct amdgpu_device *adev) +{ + if (adev->nbio.funcs && adev->nbio.funcs->is_nps_switch_requested && + adev->nbio.funcs->is_nps_switch_requested(adev)) { + adev->gmc.reset_flags |= AMDGPU_GMC_INIT_RESET_NPS; + return true; + } + + return false; +} + static const struct amdgpu_gmc_funcs gmc_v9_0_gmc_funcs = { .flush_gpu_tlb = gmc_v9_0_flush_gpu_tlb, .flush_gpu_tlb_pasid = gmc_v9_0_flush_gpu_tlb_pasid, @@ -1409,6 +1445,8 @@ static const struct amdgpu_gmc_funcs gmc_v9_0_gmc_funcs = { .override_vm_pte_flags = gmc_v9_0_override_vm_pte_flags, .get_vbios_fb_size = gmc_v9_0_get_vbios_fb_size, .query_mem_partition_mode = &gmc_v9_0_query_memory_partition, + .request_mem_partition_mode = &amdgpu_gmc_request_memory_partition, + .need_reset_on_init = &gmc_v9_0_need_reset_on_init, }; static void gmc_v9_0_set_gmc_funcs(struct amdgpu_device *adev) @@ -1548,9 +1586,31 @@ static void gmc_v9_0_set_xgmi_ras_funcs(struct amdgpu_device *adev) adev->gmc.xgmi.ras = &xgmi_ras; } -static int gmc_v9_0_early_init(void *handle) +static void gmc_v9_0_init_nps_details(struct amdgpu_device *adev) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + adev->gmc.supported_nps_modes = 0; + + if (amdgpu_sriov_vf(adev) || (adev->flags & AMD_IS_APU)) + return; + + /*TODO: Check PSP version also which supports NPS switch. Otherwise keep + * supported modes as 0. + */ + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + case IP_VERSION(9, 4, 3): + case IP_VERSION(9, 4, 4): + adev->gmc.supported_nps_modes = + BIT(AMDGPU_NPS1_PARTITION_MODE) | + BIT(AMDGPU_NPS4_PARTITION_MODE); + break; + default: + break; + } +} + +static int gmc_v9_0_early_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; /* * 9.4.0, 9.4.1 and 9.4.3 don't have XGMI defined @@ -1604,9 +1664,9 @@ static int gmc_v9_0_early_init(void *handle) return 0; } -static int gmc_v9_0_late_init(void *handle) +static int gmc_v9_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_gmc_allocate_vm_inv_eng(adev); @@ -1903,6 +1963,8 @@ gmc_v9_0_init_sw_mem_ranges(struct amdgpu_device *adev, switch (mode) { case UNKNOWN_MEMORY_PARTITION_MODE: + adev->gmc.num_mem_partitions = 0; + break; case AMDGPU_NPS1_PARTITION_MODE: adev->gmc.num_mem_partitions = 1; break; @@ -1922,7 +1984,7 @@ gmc_v9_0_init_sw_mem_ranges(struct amdgpu_device *adev, /* Use NPS range info, if populated */ r = amdgpu_gmc_get_nps_memranges(adev, mem_ranges, - adev->gmc.num_mem_partitions); + &adev->gmc.num_mem_partitions); if (!r) { l = 0; for (i = 1; i < adev->gmc.num_mem_partitions; ++i) { @@ -1932,6 +1994,11 @@ gmc_v9_0_init_sw_mem_ranges(struct amdgpu_device *adev, } } else { + if (!adev->gmc.num_mem_partitions) { + dev_err(adev->dev, + "Not able to detect NPS mode, fall back to NPS1"); + adev->gmc.num_mem_partitions = 1; + } /* Fallback to sw based calculation */ size = (adev->gmc.real_vram_size + SZ_16M) >> AMDGPU_GPU_PAGE_SHIFT; size /= adev->gmc.num_mem_partitions; @@ -1990,10 +2057,10 @@ static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev) adev->gmc.vram_width = 128 * 64; } -static int gmc_v9_0_sw_init(void *handle) +static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block) { int r, vram_width = 0, vram_type = 0, vram_vendor = 0, dma_addr_bits; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; unsigned long inst_mask = adev->aid_mask; adev->gfxhub.funcs->init(adev); @@ -2168,6 +2235,7 @@ static int gmc_v9_0_sw_init(void *handle) if (r) return r; + gmc_v9_0_init_nps_details(adev); /* * number of VMs * VMID 0 is reserved for System @@ -2201,9 +2269,9 @@ static int gmc_v9_0_sw_init(void *handle) return 0; } -static int gmc_v9_0_sw_fini(void *handle) +static int gmc_v9_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) || amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4)) @@ -2311,9 +2379,9 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev) return 0; } -static int gmc_v9_0_hw_init(void *handle) +static int gmc_v9_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; bool value; int i, r; @@ -2396,9 +2464,9 @@ static void gmc_v9_0_gart_disable(struct amdgpu_device *adev) adev->mmhub.funcs->gart_disable(adev); } -static int gmc_v9_0_hw_fini(void *handle) +static int gmc_v9_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; gmc_v9_0_gart_disable(adev); @@ -2416,32 +2484,44 @@ 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.vm_fault, 0); + /* + * For minimal init, late_init is not called, hence VM fault/RAS irqs + * are not enabled. + */ + if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) { + amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); - if (adev->gmc.ecc_irq.funcs && - amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) - amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); + if (adev->gmc.ecc_irq.funcs && + amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) + amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); + } return 0; } -static int gmc_v9_0_suspend(void *handle) +static int gmc_v9_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return gmc_v9_0_hw_fini(adev); + return gmc_v9_0_hw_fini(ip_block); } -static int gmc_v9_0_resume(void *handle) +static int gmc_v9_0_resume(struct amdgpu_ip_block *ip_block) { + struct amdgpu_device *adev = ip_block->adev; int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = gmc_v9_0_hw_init(adev); + /* If a reset is done for NPS mode switch, read the memory range + * information again. + */ + if (adev->gmc.reset_flags & AMDGPU_GMC_INIT_RESET_NPS) { + gmc_v9_0_init_sw_mem_ranges(adev, adev->gmc.mem_partitions); + adev->gmc.reset_flags &= ~AMDGPU_GMC_INIT_RESET_NPS; + } + + r = gmc_v9_0_hw_init(ip_block); if (r) return r; - amdgpu_vmid_reset_all(adev); + amdgpu_vmid_reset_all(ip_block->adev); return 0; } @@ -2452,13 +2532,13 @@ static bool gmc_v9_0_is_idle(void *handle) return true; } -static int gmc_v9_0_wait_for_idle(void *handle) +static int gmc_v9_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* There is no need to wait for MC idle in GMC v9.*/ return 0; } -static int gmc_v9_0_soft_reset(void *handle) +static int gmc_v9_0_soft_reset(struct amdgpu_ip_block *ip_block) { /* XXX for emulation.*/ return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c index e019249883fb2f..194026e9be3331 100644 --- a/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/hdp_v4_0.c @@ -40,10 +40,12 @@ static void hdp_v4_0_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) { - if (!ring || !ring->funcs->emit_wreg) + if (!ring || !ring->funcs->emit_wreg) { WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); - else + RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); + } else { amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } } static void hdp_v4_0_invalidate_hdp(struct amdgpu_device *adev, @@ -54,11 +56,13 @@ static void hdp_v4_0_invalidate_hdp(struct amdgpu_device *adev, amdgpu_ip_version(adev, HDP_HWIP, 0) == IP_VERSION(4, 4, 5)) return; - if (!ring || !ring->funcs->emit_wreg) + if (!ring || !ring->funcs->emit_wreg) { WREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE, 1); - else + RREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE); + } else { amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET( HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1); + } } static void hdp_v4_0_query_ras_error_count(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c index ed7facacf2fe30..d3962d46908811 100644 --- a/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/hdp_v5_0.c @@ -31,10 +31,12 @@ static void hdp_v5_0_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) { - if (!ring || !ring->funcs->emit_wreg) + if (!ring || !ring->funcs->emit_wreg) { WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); - else + RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); + } else { amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } } static void hdp_v5_0_invalidate_hdp(struct amdgpu_device *adev, @@ -42,6 +44,7 @@ static void hdp_v5_0_invalidate_hdp(struct amdgpu_device *adev, { if (!ring || !ring->funcs->emit_wreg) { WREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE, 1); + RREG32_SOC15_NO_KIQ(HDP, 0, mmHDP_READ_CACHE_INVALIDATE); } else { amdgpu_ring_emit_wreg(ring, SOC15_REG_OFFSET( HDP, 0, mmHDP_READ_CACHE_INVALIDATE), 1); diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c b/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c index 29c3484ae1f166..f52552c5fa27b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/hdp_v5_2.c @@ -31,13 +31,15 @@ static void hdp_v5_2_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) { - if (!ring || !ring->funcs->emit_wreg) + if (!ring || !ring->funcs->emit_wreg) { WREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); - else + RREG32_NO_KIQ((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); + } else { amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } } static void hdp_v5_2_update_mem_power_gating(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c index 33736d361dd0bc..6948fe9956ce47 100644 --- a/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/hdp_v6_0.c @@ -34,10 +34,12 @@ static void hdp_v6_0_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) { - if (!ring || !ring->funcs->emit_wreg) + if (!ring || !ring->funcs->emit_wreg) { WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); - else + RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); + } else { amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } } static void hdp_v6_0_update_clock_gating(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/hdp_v7_0.c b/drivers/gpu/drm/amd/amdgpu/hdp_v7_0.c index 1c99bb09e2a129..63820329f67eb6 100644 --- a/drivers/gpu/drm/amd/amdgpu/hdp_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/hdp_v7_0.c @@ -31,10 +31,12 @@ static void hdp_v7_0_flush_hdp(struct amdgpu_device *adev, struct amdgpu_ring *ring) { - if (!ring || !ring->funcs->emit_wreg) + if (!ring || !ring->funcs->emit_wreg) { WREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); - else + RREG32((adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2); + } else { amdgpu_ring_emit_wreg(ring, (adev->rmmio_remap.reg_offset + KFD_MMIO_REMAP_HDP_MEM_FLUSH_CNTL) >> 2, 0); + } } static void hdp_v7_0_update_clock_gating(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c index 07984f7c3ae773..7f45e93c0397b3 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/iceland_ih.c @@ -273,9 +273,9 @@ static void iceland_ih_set_rptr(struct amdgpu_device *adev, WREG32(mmIH_RB_RPTR, ih->rptr); } -static int iceland_ih_early_init(void *handle) +static int iceland_ih_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; ret = amdgpu_irq_add_domain(adev); @@ -287,10 +287,10 @@ static int iceland_ih_early_init(void *handle) return 0; } -static int iceland_ih_sw_init(void *handle) +static int iceland_ih_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 64 * 1024, false); if (r) @@ -301,9 +301,9 @@ static int iceland_ih_sw_init(void *handle) return r; } -static int iceland_ih_sw_fini(void *handle) +static int iceland_ih_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); amdgpu_irq_remove_domain(adev); @@ -311,34 +311,28 @@ static int iceland_ih_sw_fini(void *handle) return 0; } -static int iceland_ih_hw_init(void *handle) +static int iceland_ih_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return iceland_ih_irq_init(adev); } -static int iceland_ih_hw_fini(void *handle) +static int iceland_ih_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - iceland_ih_irq_disable(adev); + iceland_ih_irq_disable(ip_block->adev); return 0; } -static int iceland_ih_suspend(void *handle) +static int iceland_ih_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return iceland_ih_hw_fini(adev); + return iceland_ih_hw_fini(ip_block); } -static int iceland_ih_resume(void *handle) +static int iceland_ih_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return iceland_ih_hw_init(adev); + return iceland_ih_hw_init(ip_block); } static bool iceland_ih_is_idle(void *handle) @@ -352,11 +346,11 @@ static bool iceland_ih_is_idle(void *handle) return true; } -static int iceland_ih_wait_for_idle(void *handle) +static int iceland_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -368,10 +362,10 @@ static int iceland_ih_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int iceland_ih_soft_reset(void *handle) +static int iceland_ih_soft_reset(struct amdgpu_ip_block *ip_block) { u32 srbm_soft_reset = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 tmp = RREG32(mmSRBM_STATUS); if (tmp & SRBM_STATUS__IH_BUSY_MASK) @@ -413,7 +407,6 @@ static int iceland_ih_set_powergating_state(void *handle, static const struct amd_ip_funcs iceland_ih_ip_funcs = { .name = "iceland_ih", .early_init = iceland_ih_early_init, - .late_init = NULL, .sw_init = iceland_ih_sw_init, .sw_fini = iceland_ih_sw_fini, .hw_init = iceland_ih_hw_init, @@ -425,8 +418,6 @@ static const struct amd_ip_funcs iceland_ih_ip_funcs = { .soft_reset = iceland_ih_soft_reset, .set_clockgating_state = iceland_ih_set_clockgating_state, .set_powergating_state = iceland_ih_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs iceland_ih_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c index 18a761d6ef3306..38f953fd65d9df 100644 --- a/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_0.c @@ -559,19 +559,19 @@ static void ih_v6_0_set_self_irq_funcs(struct amdgpu_device *adev) adev->irq.self_irq.funcs = &ih_v6_0_self_irq_funcs; } -static int ih_v6_0_early_init(void *handle) +static int ih_v6_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; ih_v6_0_set_interrupt_funcs(adev); ih_v6_0_set_self_irq_funcs(adev); return 0; } -static int ih_v6_0_sw_init(void *handle) +static int ih_v6_0_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; bool use_bus_addr; r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_IH, 0, @@ -614,19 +614,19 @@ static int ih_v6_0_sw_init(void *handle) return r; } -static int ih_v6_0_sw_fini(void *handle) +static int ih_v6_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); return 0; } -static int ih_v6_0_hw_init(void *handle) +static int ih_v6_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = ih_v6_0_irq_init(adev); if (r) @@ -635,27 +635,21 @@ static int ih_v6_0_hw_init(void *handle) return 0; } -static int ih_v6_0_hw_fini(void *handle) +static int ih_v6_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - ih_v6_0_irq_disable(adev); + ih_v6_0_irq_disable(ip_block->adev); return 0; } -static int ih_v6_0_suspend(void *handle) +static int ih_v6_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return ih_v6_0_hw_fini(adev); + return ih_v6_0_hw_fini(ip_block); } -static int ih_v6_0_resume(void *handle) +static int ih_v6_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return ih_v6_0_hw_init(adev); + return ih_v6_0_hw_init(ip_block); } static bool ih_v6_0_is_idle(void *handle) @@ -664,13 +658,13 @@ static bool ih_v6_0_is_idle(void *handle) return true; } -static int ih_v6_0_wait_for_idle(void *handle) +static int ih_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* todo */ return -ETIMEDOUT; } -static int ih_v6_0_soft_reset(void *handle) +static int ih_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ return 0; @@ -785,7 +779,6 @@ static void ih_v6_0_get_clockgating_state(void *handle, u64 *flags) static const struct amd_ip_funcs ih_v6_0_ip_funcs = { .name = "ih_v6_0", .early_init = ih_v6_0_early_init, - .late_init = NULL, .sw_init = ih_v6_0_sw_init, .sw_fini = ih_v6_0_sw_fini, .hw_init = ih_v6_0_hw_init, @@ -798,8 +791,6 @@ static const struct amd_ip_funcs ih_v6_0_ip_funcs = { .set_clockgating_state = ih_v6_0_set_clockgating_state, .set_powergating_state = ih_v6_0_set_powergating_state, .get_clockgating_state = ih_v6_0_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs ih_v6_0_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c index 2e0469feca1e92..61381e0c379514 100644 --- a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c +++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c @@ -532,9 +532,9 @@ static void ih_v6_1_set_self_irq_funcs(struct amdgpu_device *adev) adev->irq.self_irq.funcs = &ih_v6_1_self_irq_funcs; } -static int ih_v6_1_early_init(void *handle) +static int ih_v6_1_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; ret = amdgpu_irq_add_domain(adev); @@ -547,10 +547,10 @@ static int ih_v6_1_early_init(void *handle) return 0; } -static int ih_v6_1_sw_init(void *handle) +static int ih_v6_1_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; bool use_bus_addr; r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_IH, 0, @@ -593,19 +593,19 @@ static int ih_v6_1_sw_init(void *handle) return r; } -static int ih_v6_1_sw_fini(void *handle) +static int ih_v6_1_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); return 0; } -static int ih_v6_1_hw_init(void *handle) +static int ih_v6_1_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = ih_v6_1_irq_init(adev); if (r) @@ -614,27 +614,21 @@ static int ih_v6_1_hw_init(void *handle) return 0; } -static int ih_v6_1_hw_fini(void *handle) +static int ih_v6_1_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - ih_v6_1_irq_disable(adev); + ih_v6_1_irq_disable(ip_block->adev); return 0; } -static int ih_v6_1_suspend(void *handle) +static int ih_v6_1_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return ih_v6_1_hw_fini(adev); + return ih_v6_1_hw_fini(ip_block); } -static int ih_v6_1_resume(void *handle) +static int ih_v6_1_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return ih_v6_1_hw_init(adev); + return ih_v6_1_hw_init(ip_block); } static bool ih_v6_1_is_idle(void *handle) @@ -643,13 +637,13 @@ static bool ih_v6_1_is_idle(void *handle) return true; } -static int ih_v6_1_wait_for_idle(void *handle) +static int ih_v6_1_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* todo */ return -ETIMEDOUT; } -static int ih_v6_1_soft_reset(void *handle) +static int ih_v6_1_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ return 0; @@ -768,7 +762,6 @@ static void ih_v6_1_get_clockgating_state(void *handle, u64 *flags) static const struct amd_ip_funcs ih_v6_1_ip_funcs = { .name = "ih_v6_1", .early_init = ih_v6_1_early_init, - .late_init = NULL, .sw_init = ih_v6_1_sw_init, .sw_fini = ih_v6_1_sw_fini, .hw_init = ih_v6_1_hw_init, @@ -781,8 +774,6 @@ static const struct amd_ip_funcs ih_v6_1_ip_funcs = { .set_clockgating_state = ih_v6_1_set_clockgating_state, .set_powergating_state = ih_v6_1_set_powergating_state, .get_clockgating_state = ih_v6_1_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs ih_v6_1_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c index 6852081fcff216..d2428cf5d3858b 100644 --- a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c @@ -528,19 +528,19 @@ static void ih_v7_0_set_self_irq_funcs(struct amdgpu_device *adev) adev->irq.self_irq.funcs = &ih_v7_0_self_irq_funcs; } -static int ih_v7_0_early_init(void *handle) +static int ih_v7_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; ih_v7_0_set_interrupt_funcs(adev); ih_v7_0_set_self_irq_funcs(adev); return 0; } -static int ih_v7_0_sw_init(void *handle) +static int ih_v7_0_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; bool use_bus_addr; r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_IH, 0, @@ -583,19 +583,19 @@ static int ih_v7_0_sw_init(void *handle) return r; } -static int ih_v7_0_sw_fini(void *handle) +static int ih_v7_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); return 0; } -static int ih_v7_0_hw_init(void *handle) +static int ih_v7_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = ih_v7_0_irq_init(adev); if (r) @@ -604,27 +604,21 @@ static int ih_v7_0_hw_init(void *handle) return 0; } -static int ih_v7_0_hw_fini(void *handle) +static int ih_v7_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - ih_v7_0_irq_disable(adev); + ih_v7_0_irq_disable(ip_block->adev); return 0; } -static int ih_v7_0_suspend(void *handle) +static int ih_v7_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return ih_v7_0_hw_fini(adev); + return ih_v7_0_hw_fini(ip_block); } -static int ih_v7_0_resume(void *handle) +static int ih_v7_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return ih_v7_0_hw_init(adev); + return ih_v7_0_hw_init(ip_block); } static bool ih_v7_0_is_idle(void *handle) @@ -633,13 +627,13 @@ static bool ih_v7_0_is_idle(void *handle) return true; } -static int ih_v7_0_wait_for_idle(void *handle) +static int ih_v7_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* todo */ return -ETIMEDOUT; } -static int ih_v7_0_soft_reset(void *handle) +static int ih_v7_0_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ return 0; @@ -758,7 +752,6 @@ static void ih_v7_0_get_clockgating_state(void *handle, u64 *flags) static const struct amd_ip_funcs ih_v7_0_ip_funcs = { .name = "ih_v7_0", .early_init = ih_v7_0_early_init, - .late_init = NULL, .sw_init = ih_v7_0_sw_init, .sw_fini = ih_v7_0_sw_fini, .hw_init = ih_v7_0_hw_init, @@ -771,8 +764,6 @@ static const struct amd_ip_funcs ih_v7_0_ip_funcs = { .set_clockgating_state = ih_v7_0_set_clockgating_state, .set_powergating_state = ih_v7_0_set_powergating_state, .get_clockgating_state = ih_v7_0_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs ih_v7_0_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c index 6e0e88076224bc..03b8b7cd5229b9 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.c @@ -458,13 +458,13 @@ static int jpeg_v1_0_process_interrupt(struct amdgpu_device *adev, /** * jpeg_v1_0_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -int jpeg_v1_0_early_init(void *handle) +int jpeg_v1_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->jpeg.num_jpeg_inst = 1; adev->jpeg.num_jpeg_rings = 1; @@ -478,12 +478,12 @@ int jpeg_v1_0_early_init(void *handle) /** * jpeg_v1_0_sw_init - sw init for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -int jpeg_v1_0_sw_init(void *handle) +int jpeg_v1_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int r; @@ -509,13 +509,13 @@ int jpeg_v1_0_sw_init(void *handle) /** * jpeg_v1_0_sw_fini - sw fini for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * JPEG free up sw allocation */ -void jpeg_v1_0_sw_fini(void *handle) +void jpeg_v1_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_ring_fini(adev->jpeg.inst->ring_dec); } diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h index 9654d22e03763c..0973286350835a 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v1_0.h @@ -24,9 +24,9 @@ #ifndef __JPEG_V1_0_H__ #define __JPEG_V1_0_H__ -int jpeg_v1_0_early_init(void *handle); -int jpeg_v1_0_sw_init(void *handle); -void jpeg_v1_0_sw_fini(void *handle); +int jpeg_v1_0_early_init(struct amdgpu_ip_block *ip_block); +int jpeg_v1_0_sw_init(struct amdgpu_ip_block *ip_block); +void jpeg_v1_0_sw_fini(struct amdgpu_ip_block *ip_block); void jpeg_v1_0_start(struct amdgpu_device *adev, int mode); #define JPEG_V1_REG_RANGE_START 0x8000 diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c index 41c0f8750dc1db..6e29b69894a57d 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c @@ -41,13 +41,13 @@ static int jpeg_v2_0_set_powergating_state(void *handle, /** * jpeg_v2_0_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -static int jpeg_v2_0_early_init(void *handle) +static int jpeg_v2_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->jpeg.num_jpeg_inst = 1; adev->jpeg.num_jpeg_rings = 1; @@ -61,13 +61,13 @@ static int jpeg_v2_0_early_init(void *handle) /** * jpeg_v2_0_sw_init - sw init for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int jpeg_v2_0_sw_init(void *handle) +static int jpeg_v2_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int r; @@ -104,14 +104,14 @@ static int jpeg_v2_0_sw_init(void *handle) /** * jpeg_v2_0_sw_fini - sw fini for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * JPEG suspend and free up sw allocation */ -static int jpeg_v2_0_sw_fini(void *handle) +static int jpeg_v2_0_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_jpeg_suspend(adev); if (r) @@ -125,12 +125,12 @@ static int jpeg_v2_0_sw_fini(void *handle) /** * jpeg_v2_0_hw_init - start and test JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int jpeg_v2_0_hw_init(void *handle) +static int jpeg_v2_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = adev->jpeg.inst->ring_dec; adev->nbio.funcs->vcn_doorbell_range(adev, ring->use_doorbell, @@ -142,15 +142,15 @@ static int jpeg_v2_0_hw_init(void *handle) /** * jpeg_v2_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the JPEG block, mark ring as not ready any more */ -static int jpeg_v2_0_hw_fini(void *handle) +static int jpeg_v2_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; - cancel_delayed_work_sync(&adev->vcn.idle_work); + cancel_delayed_work_sync(&adev->jpeg.idle_work); if (adev->jpeg.cur_state != AMD_PG_STATE_GATE && RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS)) @@ -162,20 +162,19 @@ static int jpeg_v2_0_hw_fini(void *handle) /** * jpeg_v2_0_suspend - suspend JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend JPEG block */ -static int jpeg_v2_0_suspend(void *handle) +static int jpeg_v2_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = jpeg_v2_0_hw_fini(adev); + r = jpeg_v2_0_hw_fini(ip_block); if (r) return r; - r = amdgpu_jpeg_suspend(adev); + r = amdgpu_jpeg_suspend(ip_block->adev); return r; } @@ -183,20 +182,19 @@ static int jpeg_v2_0_suspend(void *handle) /** * jpeg_v2_0_resume - resume JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init JPEG block */ -static int jpeg_v2_0_resume(void *handle) +static int jpeg_v2_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_jpeg_resume(adev); + r = amdgpu_jpeg_resume(ip_block->adev); if (r) return r; - r = jpeg_v2_0_hw_init(adev); + r = jpeg_v2_0_hw_init(ip_block); return r; } @@ -666,9 +664,9 @@ static bool jpeg_v2_0_is_idle(void *handle) UVD_JRBC_STATUS__RB_JOB_DONE_MASK); } -static int jpeg_v2_0_wait_for_idle(void *handle) +static int jpeg_v2_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; ret = SOC15_WAIT_ON_RREG(JPEG, 0, mmUVD_JRBC_STATUS, UVD_JRBC_STATUS__RB_JOB_DONE_MASK, @@ -744,7 +742,6 @@ static int jpeg_v2_0_process_interrupt(struct amdgpu_device *adev, static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { .name = "jpeg_v2_0", .early_init = jpeg_v2_0_early_init, - .late_init = NULL, .sw_init = jpeg_v2_0_sw_init, .sw_fini = jpeg_v2_0_sw_fini, .hw_init = jpeg_v2_0_hw_init, @@ -753,14 +750,8 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = { .resume = jpeg_v2_0_resume, .is_idle = jpeg_v2_0_is_idle, .wait_for_idle = jpeg_v2_0_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v2_0_set_clockgating_state, .set_powergating_state = jpeg_v2_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c index eedb9a829d9500..9ac421486f05fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c @@ -50,13 +50,13 @@ static int amdgpu_ih_clientid_jpeg[] = { /** * jpeg_v2_5_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -static int jpeg_v2_5_early_init(void *handle) +static int jpeg_v2_5_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 harvest; int i; @@ -81,15 +81,15 @@ static int jpeg_v2_5_early_init(void *handle) /** * jpeg_v2_5_sw_init - sw init for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int jpeg_v2_5_sw_init(void *handle) +static int jpeg_v2_5_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int i, r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { if (adev->jpeg.harvest_config & (1 << i)) @@ -153,14 +153,14 @@ static int jpeg_v2_5_sw_init(void *handle) /** * jpeg_v2_5_sw_fini - sw fini for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * JPEG suspend and free up sw allocation */ -static int jpeg_v2_5_sw_fini(void *handle) +static int jpeg_v2_5_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_jpeg_suspend(adev); if (r) @@ -174,12 +174,12 @@ static int jpeg_v2_5_sw_fini(void *handle) /** * jpeg_v2_5_hw_init - start and test JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int jpeg_v2_5_hw_init(void *handle) +static int jpeg_v2_5_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r; @@ -202,16 +202,16 @@ static int jpeg_v2_5_hw_init(void *handle) /** * jpeg_v2_5_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the JPEG block, mark ring as not ready any more */ -static int jpeg_v2_5_hw_fini(void *handle) +static int jpeg_v2_5_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; - cancel_delayed_work_sync(&adev->vcn.idle_work); + cancel_delayed_work_sync(&adev->jpeg.idle_work); for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { if (adev->jpeg.harvest_config & (1 << i)) @@ -231,20 +231,19 @@ static int jpeg_v2_5_hw_fini(void *handle) /** * jpeg_v2_5_suspend - suspend JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend JPEG block */ -static int jpeg_v2_5_suspend(void *handle) +static int jpeg_v2_5_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = jpeg_v2_5_hw_fini(adev); + r = jpeg_v2_5_hw_fini(ip_block); if (r) return r; - r = amdgpu_jpeg_suspend(adev); + r = amdgpu_jpeg_suspend(ip_block->adev); return r; } @@ -252,20 +251,19 @@ static int jpeg_v2_5_suspend(void *handle) /** * jpeg_v2_5_resume - resume JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init JPEG block */ -static int jpeg_v2_5_resume(void *handle) +static int jpeg_v2_5_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_jpeg_resume(adev); + r = amdgpu_jpeg_resume(ip_block->adev); if (r) return r; - r = jpeg_v2_5_hw_init(adev); + r = jpeg_v2_5_hw_init(ip_block); return r; } @@ -501,9 +499,9 @@ static bool jpeg_v2_5_is_idle(void *handle) return ret; } -static int jpeg_v2_5_wait_for_idle(void *handle) +static int jpeg_v2_5_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, ret; for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { @@ -615,7 +613,6 @@ static int jpeg_v2_5_process_interrupt(struct amdgpu_device *adev, static const struct amd_ip_funcs jpeg_v2_5_ip_funcs = { .name = "jpeg_v2_5", .early_init = jpeg_v2_5_early_init, - .late_init = NULL, .sw_init = jpeg_v2_5_sw_init, .sw_fini = jpeg_v2_5_sw_fini, .hw_init = jpeg_v2_5_hw_init, @@ -624,20 +621,13 @@ static const struct amd_ip_funcs jpeg_v2_5_ip_funcs = { .resume = jpeg_v2_5_resume, .is_idle = jpeg_v2_5_is_idle, .wait_for_idle = jpeg_v2_5_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v2_5_set_clockgating_state, .set_powergating_state = jpeg_v2_5_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { .name = "jpeg_v2_6", .early_init = jpeg_v2_5_early_init, - .late_init = NULL, .sw_init = jpeg_v2_5_sw_init, .sw_fini = jpeg_v2_5_sw_fini, .hw_init = jpeg_v2_5_hw_init, @@ -646,14 +636,8 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = { .resume = jpeg_v2_5_resume, .is_idle = jpeg_v2_5_is_idle, .wait_for_idle = jpeg_v2_5_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v2_5_set_clockgating_state, .set_powergating_state = jpeg_v2_5_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c index b1e7fd25afbcb9..e0df6800502ca8 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c @@ -42,13 +42,13 @@ static int jpeg_v3_0_set_powergating_state(void *handle, /** * jpeg_v3_0_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -static int jpeg_v3_0_early_init(void *handle) +static int jpeg_v3_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 harvest; @@ -75,13 +75,13 @@ static int jpeg_v3_0_early_init(void *handle) /** * jpeg_v3_0_sw_init - sw init for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int jpeg_v3_0_sw_init(void *handle) +static int jpeg_v3_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int r; @@ -118,13 +118,13 @@ static int jpeg_v3_0_sw_init(void *handle) /** * jpeg_v3_0_sw_fini - sw fini for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * JPEG suspend and free up sw allocation */ -static int jpeg_v3_0_sw_fini(void *handle) +static int jpeg_v3_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_jpeg_suspend(adev); @@ -139,12 +139,12 @@ static int jpeg_v3_0_sw_fini(void *handle) /** * jpeg_v3_0_hw_init - start and test JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int jpeg_v3_0_hw_init(void *handle) +static int jpeg_v3_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = adev->jpeg.inst->ring_dec; adev->nbio.funcs->vcn_doorbell_range(adev, ring->use_doorbell, @@ -156,15 +156,15 @@ static int jpeg_v3_0_hw_init(void *handle) /** * jpeg_v3_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the JPEG block, mark ring as not ready any more */ -static int jpeg_v3_0_hw_fini(void *handle) +static int jpeg_v3_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; - cancel_delayed_work_sync(&adev->vcn.idle_work); + cancel_delayed_work_sync(&adev->jpeg.idle_work); if (adev->jpeg.cur_state != AMD_PG_STATE_GATE && RREG32_SOC15(JPEG, 0, mmUVD_JRBC_STATUS)) @@ -176,20 +176,19 @@ static int jpeg_v3_0_hw_fini(void *handle) /** * jpeg_v3_0_suspend - suspend JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend JPEG block */ -static int jpeg_v3_0_suspend(void *handle) +static int jpeg_v3_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = jpeg_v3_0_hw_fini(adev); + r = jpeg_v3_0_hw_fini(ip_block); if (r) return r; - r = amdgpu_jpeg_suspend(adev); + r = amdgpu_jpeg_suspend(ip_block->adev); return r; } @@ -197,20 +196,19 @@ static int jpeg_v3_0_suspend(void *handle) /** * jpeg_v3_0_resume - resume JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init JPEG block */ -static int jpeg_v3_0_resume(void *handle) +static int jpeg_v3_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_jpeg_resume(adev); + r = amdgpu_jpeg_resume(ip_block->adev); if (r) return r; - r = jpeg_v3_0_hw_init(adev); + r = jpeg_v3_0_hw_init(ip_block); return r; } @@ -459,9 +457,9 @@ static bool jpeg_v3_0_is_idle(void *handle) return ret; } -static int jpeg_v3_0_wait_for_idle(void *handle) +static int jpeg_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return SOC15_WAIT_ON_RREG(JPEG, 0, mmUVD_JRBC_STATUS, UVD_JRBC_STATUS__RB_JOB_DONE_MASK, @@ -535,7 +533,6 @@ static int jpeg_v3_0_process_interrupt(struct amdgpu_device *adev, static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { .name = "jpeg_v3_0", .early_init = jpeg_v3_0_early_init, - .late_init = NULL, .sw_init = jpeg_v3_0_sw_init, .sw_fini = jpeg_v3_0_sw_fini, .hw_init = jpeg_v3_0_hw_init, @@ -544,14 +541,8 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = { .resume = jpeg_v3_0_resume, .is_idle = jpeg_v3_0_is_idle, .wait_for_idle = jpeg_v3_0_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v3_0_set_clockgating_state, .set_powergating_state = jpeg_v3_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c index 6c5c1a68a9b7b8..eca1963c33b6bf 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c @@ -48,13 +48,13 @@ static void jpeg_v4_0_dec_ring_set_wptr(struct amdgpu_ring *ring); /** * jpeg_v4_0_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -static int jpeg_v4_0_early_init(void *handle) +static int jpeg_v4_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->jpeg.num_jpeg_inst = 1; @@ -70,13 +70,13 @@ static int jpeg_v4_0_early_init(void *handle) /** * jpeg_v4_0_sw_init - sw init for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int jpeg_v4_0_sw_init(void *handle) +static int jpeg_v4_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int r; @@ -121,6 +121,12 @@ static int jpeg_v4_0_sw_init(void *handle) adev->jpeg.inst->external.jpeg_pitch[0] = SOC15_REG_OFFSET(JPEG, 0, regUVD_JPEG_PITCH); r = amdgpu_jpeg_ras_sw_init(adev); + if (r) + return r; + /* TODO: Add queue reset mask when FW fully supports it */ + adev->jpeg.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->jpeg.inst[0].ring_dec[0]); + r = amdgpu_jpeg_sysfs_reset_mask_init(adev); if (r) return r; @@ -130,19 +136,20 @@ static int jpeg_v4_0_sw_init(void *handle) /** * jpeg_v4_0_sw_fini - sw fini for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * JPEG suspend and free up sw allocation */ -static int jpeg_v4_0_sw_fini(void *handle) +static int jpeg_v4_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_jpeg_suspend(adev); if (r) return r; + amdgpu_jpeg_sysfs_reset_mask_fini(adev); r = amdgpu_jpeg_sw_fini(adev); return r; @@ -151,12 +158,12 @@ static int jpeg_v4_0_sw_fini(void *handle) /** * jpeg_v4_0_hw_init - start and test JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int jpeg_v4_0_hw_init(void *handle) +static int jpeg_v4_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = adev->jpeg.inst->ring_dec; int r; @@ -187,15 +194,15 @@ static int jpeg_v4_0_hw_init(void *handle) /** * jpeg_v4_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the JPEG block, mark ring as not ready any more */ -static int jpeg_v4_0_hw_fini(void *handle) +static int jpeg_v4_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; - cancel_delayed_work_sync(&adev->vcn.idle_work); + cancel_delayed_work_sync(&adev->jpeg.idle_work); if (!amdgpu_sriov_vf(adev)) { if (adev->jpeg.cur_state != AMD_PG_STATE_GATE && RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS)) @@ -210,20 +217,19 @@ static int jpeg_v4_0_hw_fini(void *handle) /** * jpeg_v4_0_suspend - suspend JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend JPEG block */ -static int jpeg_v4_0_suspend(void *handle) +static int jpeg_v4_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = jpeg_v4_0_hw_fini(adev); + r = jpeg_v4_0_hw_fini(ip_block); if (r) return r; - r = amdgpu_jpeg_suspend(adev); + r = amdgpu_jpeg_suspend(ip_block->adev); return r; } @@ -231,20 +237,19 @@ static int jpeg_v4_0_suspend(void *handle) /** * jpeg_v4_0_resume - resume JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init JPEG block */ -static int jpeg_v4_0_resume(void *handle) +static int jpeg_v4_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_jpeg_resume(adev); + r = amdgpu_jpeg_resume(ip_block->adev); if (r) return r; - r = jpeg_v4_0_hw_init(adev); + r = jpeg_v4_0_hw_init(ip_block); return r; } @@ -621,9 +626,9 @@ static bool jpeg_v4_0_is_idle(void *handle) return ret; } -static int jpeg_v4_0_wait_for_idle(void *handle) +static int jpeg_v4_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return SOC15_WAIT_ON_RREG(JPEG, 0, regUVD_JRBC_STATUS, UVD_JRBC_STATUS__RB_JOB_DONE_MASK, @@ -702,7 +707,6 @@ static int jpeg_v4_0_process_interrupt(struct amdgpu_device *adev, static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { .name = "jpeg_v4_0", .early_init = jpeg_v4_0_early_init, - .late_init = NULL, .sw_init = jpeg_v4_0_sw_init, .sw_fini = jpeg_v4_0_sw_fini, .hw_init = jpeg_v4_0_hw_init, @@ -711,14 +715,8 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = { .resume = jpeg_v4_0_resume, .is_idle = jpeg_v4_0_is_idle, .wait_for_idle = jpeg_v4_0_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v4_0_set_clockgating_state, .set_powergating_state = jpeg_v4_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c index 86958cb2c2ab2b..67b51bcbacd197 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c @@ -68,13 +68,13 @@ static inline bool jpeg_v4_0_3_normalizn_reqd(struct amdgpu_device *adev) /** * jpeg_v4_0_3_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -static int jpeg_v4_0_3_early_init(void *handle) +static int jpeg_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS; @@ -88,13 +88,13 @@ static int jpeg_v4_0_3_early_init(void *handle) /** * jpeg_v4_0_3_sw_init - sw init for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int jpeg_v4_0_3_sw_init(void *handle) +static int jpeg_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, j, r, jpeg_inst; @@ -159,25 +159,33 @@ static int jpeg_v4_0_3_sw_init(void *handle) } } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->jpeg.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->jpeg.inst[0].ring_dec[0]); + r = amdgpu_jpeg_sysfs_reset_mask_init(adev); + if (r) + return r; + return 0; } /** * jpeg_v4_0_3_sw_fini - sw fini for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * JPEG suspend and free up sw allocation */ -static int jpeg_v4_0_3_sw_fini(void *handle) +static int jpeg_v4_0_3_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_jpeg_suspend(adev); if (r) return r; + amdgpu_jpeg_sysfs_reset_mask_fini(adev); r = amdgpu_jpeg_sw_fini(adev); return r; @@ -299,12 +307,12 @@ static int jpeg_v4_0_3_start_sriov(struct amdgpu_device *adev) /** * jpeg_v4_0_3_hw_init - start and test JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int jpeg_v4_0_3_hw_init(void *handle) +static int jpeg_v4_0_3_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, j, r, jpeg_inst; @@ -358,13 +366,13 @@ static int jpeg_v4_0_3_hw_init(void *handle) /** * jpeg_v4_0_3_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the JPEG block, mark ring as not ready any more */ -static int jpeg_v4_0_3_hw_fini(void *handle) +static int jpeg_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret = 0; cancel_delayed_work_sync(&adev->jpeg.idle_work); @@ -380,20 +388,19 @@ static int jpeg_v4_0_3_hw_fini(void *handle) /** * jpeg_v4_0_3_suspend - suspend JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend JPEG block */ -static int jpeg_v4_0_3_suspend(void *handle) +static int jpeg_v4_0_3_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = jpeg_v4_0_3_hw_fini(adev); + r = jpeg_v4_0_3_hw_fini(ip_block); if (r) return r; - r = amdgpu_jpeg_suspend(adev); + r = amdgpu_jpeg_suspend(ip_block->adev); return r; } @@ -401,20 +408,19 @@ static int jpeg_v4_0_3_suspend(void *handle) /** * jpeg_v4_0_3_resume - resume JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init JPEG block */ -static int jpeg_v4_0_3_resume(void *handle) +static int jpeg_v4_0_3_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_jpeg_resume(adev); + r = amdgpu_jpeg_resume(ip_block->adev); if (r) return r; - r = jpeg_v4_0_3_hw_init(adev); + r = jpeg_v4_0_3_hw_init(ip_block); return r; } @@ -674,11 +680,12 @@ void jpeg_v4_0_3_dec_ring_insert_start(struct amdgpu_ring *ring) amdgpu_ring_write(ring, PACKETJ(regUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, 0, 0, PACKETJ_TYPE0)); amdgpu_ring_write(ring, 0x62a04); /* PCTL0_MMHUB_DEEPSLEEP_IB */ - } - amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x80004000); + amdgpu_ring_write(ring, + PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, 0, + 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x80004000); + } } /** @@ -694,11 +701,12 @@ void jpeg_v4_0_3_dec_ring_insert_end(struct amdgpu_ring *ring) amdgpu_ring_write(ring, PACKETJ(regUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, 0, 0, PACKETJ_TYPE0)); amdgpu_ring_write(ring, 0x62a04); - } - amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x00004000); + amdgpu_ring_write(ring, + PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, 0, + 0, PACKETJ_TYPE0)); + amdgpu_ring_write(ring, 0x00004000); + } } /** @@ -743,14 +751,6 @@ void jpeg_v4_0_3_dec_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6)); amdgpu_ring_write(ring, 0); - amdgpu_ring_write(ring, PACKETJ(regUVD_JRBC_EXTERNAL_REG_INTERNAL_OFFSET, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x3fbc); - - amdgpu_ring_write(ring, PACKETJ(JRBC_DEC_EXTERNAL_REG_WRITE_ADDR, - 0, 0, PACKETJ_TYPE0)); - amdgpu_ring_write(ring, 0x1); - amdgpu_ring_write(ring, PACKETJ(0, 0, 0, PACKETJ_TYPE6)); amdgpu_ring_write(ring, 0); @@ -929,9 +929,9 @@ static bool jpeg_v4_0_3_is_idle(void *handle) return ret; } -static int jpeg_v4_0_3_wait_for_idle(void *handle) +static int jpeg_v4_0_3_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret = 0; int i, j; @@ -1058,7 +1058,6 @@ static int jpeg_v4_0_3_process_interrupt(struct amdgpu_device *adev, static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = { .name = "jpeg_v4_0_3", .early_init = jpeg_v4_0_3_early_init, - .late_init = NULL, .sw_init = jpeg_v4_0_3_sw_init, .sw_fini = jpeg_v4_0_3_sw_fini, .hw_init = jpeg_v4_0_3_hw_init, @@ -1067,14 +1066,8 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = { .resume = jpeg_v4_0_3_resume, .is_idle = jpeg_v4_0_3_is_idle, .wait_for_idle = jpeg_v4_0_3_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v4_0_3_set_clockgating_state, .set_powergating_state = jpeg_v4_0_3_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { @@ -1088,7 +1081,7 @@ static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { SOC15_FLUSH_GPU_TLB_NUM_WREG * 6 + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 8 + 8 + /* jpeg_v4_0_3_dec_ring_emit_vm_flush */ - 22 + 22 + /* jpeg_v4_0_3_dec_ring_emit_fence x2 vm fence */ + 18 + 18 + /* jpeg_v4_0_3_dec_ring_emit_fence x2 vm fence */ 8 + 16, .emit_ib_size = 22, /* jpeg_v4_0_3_dec_ring_emit_ib */ .emit_ib = jpeg_v4_0_3_dec_ring_emit_ib, diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c index 44eeed445ea917..1d9e3b101c3a32 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c @@ -61,13 +61,13 @@ static int amdgpu_ih_clientid_jpeg[] = { /** * jpeg_v4_0_5_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -static int jpeg_v4_0_5_early_init(void *handle) +static int jpeg_v4_0_5_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) { case IP_VERSION(4, 0, 5): @@ -94,13 +94,13 @@ static int jpeg_v4_0_5_early_init(void *handle) /** * jpeg_v4_0_5_sw_init - sw init for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int jpeg_v4_0_5_sw_init(void *handle) +static int jpeg_v4_0_5_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int r, i; @@ -153,25 +153,33 @@ static int jpeg_v4_0_5_sw_init(void *handle) adev->jpeg.inst[i].external.jpeg_pitch[0] = SOC15_REG_OFFSET(JPEG, i, regUVD_JPEG_PITCH); } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->jpeg.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->jpeg.inst[0].ring_dec[0]); + r = amdgpu_jpeg_sysfs_reset_mask_init(adev); + if (r) + return r; + return 0; } /** * jpeg_v4_0_5_sw_fini - sw fini for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * JPEG suspend and free up sw allocation */ -static int jpeg_v4_0_5_sw_fini(void *handle) +static int jpeg_v4_0_5_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_jpeg_suspend(adev); if (r) return r; + amdgpu_jpeg_sysfs_reset_mask_fini(adev); r = amdgpu_jpeg_sw_fini(adev); return r; @@ -180,12 +188,12 @@ static int jpeg_v4_0_5_sw_fini(void *handle) /** * jpeg_v4_0_5_hw_init - start and test JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int jpeg_v4_0_5_hw_init(void *handle) +static int jpeg_v4_0_5_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r = 0; @@ -210,16 +218,16 @@ static int jpeg_v4_0_5_hw_init(void *handle) /** * jpeg_v4_0_5_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the JPEG block, mark ring as not ready any more */ -static int jpeg_v4_0_5_hw_fini(void *handle) +static int jpeg_v4_0_5_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; - cancel_delayed_work_sync(&adev->vcn.idle_work); + cancel_delayed_work_sync(&adev->jpeg.idle_work); for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { if (adev->jpeg.harvest_config & (1 << i)) @@ -237,20 +245,19 @@ static int jpeg_v4_0_5_hw_fini(void *handle) /** * jpeg_v4_0_5_suspend - suspend JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend JPEG block */ -static int jpeg_v4_0_5_suspend(void *handle) +static int jpeg_v4_0_5_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = jpeg_v4_0_5_hw_fini(adev); + r = jpeg_v4_0_5_hw_fini(ip_block); if (r) return r; - r = amdgpu_jpeg_suspend(adev); + r = amdgpu_jpeg_suspend(ip_block->adev); return r; } @@ -258,20 +265,19 @@ static int jpeg_v4_0_5_suspend(void *handle) /** * jpeg_v4_0_5_resume - resume JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init JPEG block */ -static int jpeg_v4_0_5_resume(void *handle) +static int jpeg_v4_0_5_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_jpeg_resume(adev); + r = amdgpu_jpeg_resume(ip_block->adev); if (r) return r; - r = jpeg_v4_0_5_hw_init(adev); + r = jpeg_v4_0_5_hw_init(ip_block); return r; } @@ -637,9 +643,9 @@ static bool jpeg_v4_0_5_is_idle(void *handle) return ret; } -static int jpeg_v4_0_5_wait_for_idle(void *handle) +static int jpeg_v4_0_5_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { @@ -743,7 +749,6 @@ static int jpeg_v4_0_5_process_interrupt(struct amdgpu_device *adev, static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = { .name = "jpeg_v4_0_5", .early_init = jpeg_v4_0_5_early_init, - .late_init = NULL, .sw_init = jpeg_v4_0_5_sw_init, .sw_fini = jpeg_v4_0_5_sw_fini, .hw_init = jpeg_v4_0_5_hw_init, @@ -752,14 +757,8 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = { .resume = jpeg_v4_0_5_resume, .is_idle = jpeg_v4_0_5_is_idle, .wait_for_idle = jpeg_v4_0_5_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v4_0_5_set_clockgating_state, .set_powergating_state = jpeg_v4_0_5_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c index d662aa841f9718..58fb1e5fa89c48 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c @@ -42,13 +42,13 @@ static int jpeg_v5_0_0_set_powergating_state(void *handle, /** * jpeg_v5_0_0_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -static int jpeg_v5_0_0_early_init(void *handle) +static int jpeg_v5_0_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->jpeg.num_jpeg_inst = 1; adev->jpeg.num_jpeg_rings = 1; @@ -62,13 +62,13 @@ static int jpeg_v5_0_0_early_init(void *handle) /** * jpeg_v5_0_0_sw_init - sw init for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int jpeg_v5_0_0_sw_init(void *handle) +static int jpeg_v5_0_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int r; @@ -100,25 +100,32 @@ static int jpeg_v5_0_0_sw_init(void *handle) adev->jpeg.internal.jpeg_pitch[0] = regUVD_JPEG_PITCH_INTERNAL_OFFSET; adev->jpeg.inst->external.jpeg_pitch[0] = SOC15_REG_OFFSET(JPEG, 0, regUVD_JPEG_PITCH); + /* TODO: Add queue reset mask when FW fully supports it */ + adev->jpeg.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->jpeg.inst[0].ring_dec[0]); + r = amdgpu_jpeg_sysfs_reset_mask_init(adev); + if (r) + return r; return 0; } /** * jpeg_v5_0_0_sw_fini - sw fini for JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * JPEG suspend and free up sw allocation */ -static int jpeg_v5_0_0_sw_fini(void *handle) +static int jpeg_v5_0_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_jpeg_suspend(adev); if (r) return r; + amdgpu_jpeg_sysfs_reset_mask_fini(adev); r = amdgpu_jpeg_sw_fini(adev); return r; @@ -127,12 +134,12 @@ static int jpeg_v5_0_0_sw_fini(void *handle) /** * jpeg_v5_0_0_hw_init - start and test JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * */ -static int jpeg_v5_0_0_hw_init(void *handle) +static int jpeg_v5_0_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = adev->jpeg.inst->ring_dec; int r; @@ -153,15 +160,15 @@ static int jpeg_v5_0_0_hw_init(void *handle) /** * jpeg_v5_0_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the JPEG block, mark ring as not ready any more */ -static int jpeg_v5_0_0_hw_fini(void *handle) +static int jpeg_v5_0_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; - cancel_delayed_work_sync(&adev->vcn.idle_work); + cancel_delayed_work_sync(&adev->jpeg.idle_work); if (adev->jpeg.cur_state != AMD_PG_STATE_GATE && RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS)) @@ -173,20 +180,19 @@ static int jpeg_v5_0_0_hw_fini(void *handle) /** * jpeg_v5_0_0_suspend - suspend JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend JPEG block */ -static int jpeg_v5_0_0_suspend(void *handle) +static int jpeg_v5_0_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = jpeg_v5_0_0_hw_fini(adev); + r = jpeg_v5_0_0_hw_fini(ip_block); if (r) return r; - r = amdgpu_jpeg_suspend(adev); + r = amdgpu_jpeg_suspend(ip_block->adev); return r; } @@ -194,20 +200,19 @@ static int jpeg_v5_0_0_suspend(void *handle) /** * jpeg_v5_0_0_resume - resume JPEG block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init JPEG block */ -static int jpeg_v5_0_0_resume(void *handle) +static int jpeg_v5_0_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_jpeg_resume(adev); + r = amdgpu_jpeg_resume(ip_block->adev); if (r) return r; - r = jpeg_v5_0_0_hw_init(adev); + r = jpeg_v5_0_0_hw_init(ip_block); return r; } @@ -546,9 +551,9 @@ static bool jpeg_v5_0_0_is_idle(void *handle) return ret; } -static int jpeg_v5_0_0_wait_for_idle(void *handle) +static int jpeg_v5_0_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return SOC15_WAIT_ON_RREG(JPEG, 0, regUVD_JRBC_STATUS, UVD_JRBC_STATUS__RB_JOB_DONE_MASK, @@ -622,7 +627,6 @@ static int jpeg_v5_0_0_process_interrupt(struct amdgpu_device *adev, static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = { .name = "jpeg_v5_0_0", .early_init = jpeg_v5_0_0_early_init, - .late_init = NULL, .sw_init = jpeg_v5_0_0_sw_init, .sw_fini = jpeg_v5_0_0_sw_fini, .hw_init = jpeg_v5_0_0_hw_init, @@ -631,14 +635,8 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = { .resume = jpeg_v5_0_0_resume, .is_idle = jpeg_v5_0_0_is_idle, .wait_for_idle = jpeg_v5_0_0_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v5_0_0_set_clockgating_state, .set_powergating_state = jpeg_v5_0_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 231a3d490ea8e3..9c905b9e937637 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -55,8 +55,8 @@ MODULE_FIRMWARE("amdgpu/gc_11_5_1_mes1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_2_mes_2.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_2_mes1.bin"); -static int mes_v11_0_hw_init(void *handle); -static int mes_v11_0_hw_fini(void *handle); +static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block); +static int mes_v11_0_hw_fini(struct amdgpu_ip_block *ip_block); static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev); static int mes_v11_0_kiq_hw_fini(struct amdgpu_device *adev); @@ -366,7 +366,7 @@ static int mes_v11_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ uint32_t queue_id, uint32_t vmid) { struct amdgpu_device *adev = mes->adev; - uint32_t value; + uint32_t value, reg; int i, r = 0; amdgpu_gfx_rlc_enter_safe_mode(adev, 0); @@ -424,6 +424,31 @@ static int mes_v11_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ } soc21_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); + } else if (queue_type == AMDGPU_RING_TYPE_SDMA) { + dev_info(adev->dev, "reset sdma queue (%d:%d:%d)\n", + me_id, pipe_id, queue_id); + switch (me_id) { + case 1: + reg = SOC15_REG_OFFSET(GC, 0, regSDMA1_QUEUE_RESET_REQ); + break; + case 0: + default: + reg = SOC15_REG_OFFSET(GC, 0, regSDMA0_QUEUE_RESET_REQ); + break; + } + + value = 1 << queue_id; + WREG32(reg, value); + /* wait for queue reset done */ + for (i = 0; i < adev->usec_timeout; i++) { + if (!(RREG32(reg) & value)) + break; + udelay(1); + } + if (i >= adev->usec_timeout) { + dev_err(adev->dev, "failed to wait on sdma queue reset done\n"); + r = -ETIMEDOUT; + } } amdgpu_gfx_rlc_exit_safe_mode(adev, 0); @@ -619,6 +644,18 @@ static int mes_v11_0_misc_op(struct amdgpu_mes *mes, sizeof(misc_pkt.set_shader_debugger.tcp_watch_cntl)); misc_pkt.set_shader_debugger.trap_en = input->set_shader_debugger.trap_en; break; + case MES_MISC_OP_CHANGE_CONFIG: + if ((mes->adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) < 0x63) { + dev_err(mes->adev->dev, "MES FW versoin must be larger than 0x63 to support limit single process feature.\n"); + return -EINVAL; + } + misc_pkt.opcode = MESAPI_MISC__CHANGE_CONFIG; + misc_pkt.change_config.opcode = + MESAPI_MISC__CHANGE_CONFIG_OPTION_LIMIT_SINGLE_PROCESS; + misc_pkt.change_config.option.bits.limit_single_process = + input->change_config.option.limit_single_process; + break; + default: DRM_ERROR("unsupported misc op (%d) \n", input->op); return -EINVAL; @@ -683,6 +720,9 @@ static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes) mes->event_log_gpu_addr; } + if (enforce_isolation) + mes_set_hw_res_pkt.limit_single_process = 1; + return mes_v11_0_submit_pkt_and_poll_completion(mes, &mes_set_hw_res_pkt, sizeof(mes_set_hw_res_pkt), offsetof(union MESAPI_SET_HW_RESOURCES, api_status)); @@ -883,6 +923,16 @@ static void mes_v11_0_enable(struct amdgpu_device *adev, bool enable) uint32_t pipe, data = 0; if (enable) { + if (amdgpu_mes_log_enable) { + WREG32_SOC15(GC, 0, regCP_MES_MSCRATCH_LO, + lower_32_bits(adev->mes.event_log_gpu_addr + AMDGPU_MES_LOG_BUFFER_SIZE)); + WREG32_SOC15(GC, 0, regCP_MES_MSCRATCH_HI, + upper_32_bits(adev->mes.event_log_gpu_addr + AMDGPU_MES_LOG_BUFFER_SIZE)); + dev_info(adev->dev, "Setup CP MES MSCRATCH address : 0x%x. 0x%x\n", + RREG32_SOC15(GC, 0, regCP_MES_MSCRATCH_HI), + RREG32_SOC15(GC, 0, regCP_MES_MSCRATCH_LO)); + } + data = RREG32_SOC15(GC, 0, regCP_MES_CNTL); data = REG_SET_FIELD(data, CP_MES_CNTL, MES_PIPE0_RESET, 1); data = REG_SET_FIELD(data, CP_MES_CNTL, @@ -1336,16 +1386,16 @@ static int mes_v11_0_mqd_sw_init(struct amdgpu_device *adev, return 0; } -static int mes_v11_0_sw_init(void *handle) +static int mes_v11_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int pipe, r; adev->mes.funcs = &mes_v11_0_funcs; adev->mes.kiq_hw_init = &mes_v11_0_kiq_hw_init; adev->mes.kiq_hw_fini = &mes_v11_0_kiq_hw_fini; - adev->mes.event_log_size = AMDGPU_MES_LOG_BUFFER_SIZE; + adev->mes.event_log_size = AMDGPU_MES_LOG_BUFFER_SIZE + AMDGPU_MES_MSCRATCH_SIZE; r = amdgpu_mes_init(adev); if (r) @@ -1377,9 +1427,9 @@ static int mes_v11_0_sw_init(void *handle) return 0; } -static int mes_v11_0_sw_fini(void *handle) +static int mes_v11_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int pipe; for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { @@ -1473,6 +1523,7 @@ static void mes_v11_0_kiq_clear(struct amdgpu_device *adev) static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev) { int r = 0; + struct amdgpu_ip_block *ip_block; if (adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) { @@ -1496,6 +1547,12 @@ static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev) mes_v11_0_kiq_setting(&adev->gfx.kiq[0].ring); + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_MES); + if (unlikely(!ip_block)) { + dev_err(adev->dev, "Failed to get MES handle\n"); + return -EINVAL; + } + r = mes_v11_0_queue_init(adev, AMDGPU_MES_KIQ_PIPE); if (r) goto failure; @@ -1506,7 +1563,7 @@ static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev) adev->mes.enable_legacy_queue_map = false; if (adev->mes.enable_legacy_queue_map) { - r = mes_v11_0_hw_init(adev); + r = mes_v11_0_hw_init(ip_block); if (r) goto failure; } @@ -1514,7 +1571,7 @@ static int mes_v11_0_kiq_hw_init(struct amdgpu_device *adev) return r; failure: - mes_v11_0_hw_fini(adev); + mes_v11_0_hw_fini(ip_block); return r; } @@ -1535,10 +1592,10 @@ static int mes_v11_0_kiq_hw_fini(struct amdgpu_device *adev) return 0; } -static int mes_v11_0_hw_init(void *handle) +static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->mes.ring[0].sched.ready) goto out; @@ -1590,13 +1647,13 @@ static int mes_v11_0_hw_init(void *handle) return 0; failure: - mes_v11_0_hw_fini(adev); + mes_v11_0_hw_fini(ip_block); return r; } -static int mes_v11_0_hw_fini(void *handle) +static int mes_v11_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_is_mes_info_enable(adev)) { amdgpu_bo_free_kernel(&adev->mes.resource_1, &adev->mes.resource_1_gpu_addr, &adev->mes.resource_1_addr); @@ -1604,33 +1661,31 @@ static int mes_v11_0_hw_fini(void *handle) return 0; } -static int mes_v11_0_suspend(void *handle) +static int mes_v11_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_mes_suspend(adev); + r = amdgpu_mes_suspend(ip_block->adev); if (r) return r; - return mes_v11_0_hw_fini(adev); + return mes_v11_0_hw_fini(ip_block); } -static int mes_v11_0_resume(void *handle) +static int mes_v11_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = mes_v11_0_hw_init(adev); + r = mes_v11_0_hw_init(ip_block); if (r) return r; - return amdgpu_mes_resume(adev); + return amdgpu_mes_resume(ip_block->adev); } -static int mes_v11_0_early_init(void *handle) +static int mes_v11_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int pipe, r; for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { @@ -1644,9 +1699,9 @@ static int mes_v11_0_early_init(void *handle) return 0; } -static int mes_v11_0_late_init(void *handle) +static int mes_v11_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* it's only intended for use in mes_self_test case, not for s0ix and reset */ if (!amdgpu_in_reset(adev) && !adev->in_s0ix && !adev->in_suspend && @@ -1666,8 +1721,6 @@ static const struct amd_ip_funcs mes_v11_0_ip_funcs = { .hw_fini = mes_v11_0_hw_fini, .suspend = mes_v11_0_suspend, .resume = mes_v11_0_resume, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version mes_v11_0_ip_block = { diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c index b3175ff676f33c..9ecc5d61e49ba3 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c @@ -39,8 +39,8 @@ MODULE_FIRMWARE("amdgpu/gc_12_0_1_mes.bin"); MODULE_FIRMWARE("amdgpu/gc_12_0_1_mes1.bin"); MODULE_FIRMWARE("amdgpu/gc_12_0_1_uni_mes.bin"); -static int mes_v12_0_hw_init(void *handle); -static int mes_v12_0_hw_fini(void *handle); +static int mes_v12_0_hw_init(struct amdgpu_ip_block *ip_block); +static int mes_v12_0_hw_fini(struct amdgpu_ip_block *ip_block); static int mes_v12_0_kiq_hw_init(struct amdgpu_device *adev); static int mes_v12_0_kiq_hw_fini(struct amdgpu_device *adev); @@ -531,6 +531,14 @@ static int mes_v12_0_misc_op(struct amdgpu_mes *mes, sizeof(misc_pkt.set_shader_debugger.tcp_watch_cntl)); misc_pkt.set_shader_debugger.trap_en = input->set_shader_debugger.trap_en; break; + case MES_MISC_OP_CHANGE_CONFIG: + misc_pkt.opcode = MESAPI_MISC__CHANGE_CONFIG; + misc_pkt.change_config.opcode = + MESAPI_MISC__CHANGE_CONFIG_OPTION_LIMIT_SINGLE_PROCESS; + misc_pkt.change_config.option.bits.limit_single_process = + input->change_config.option.limit_single_process; + break; + default: DRM_ERROR("unsupported misc op (%d) \n", input->op); return -EINVAL; @@ -624,6 +632,9 @@ static int mes_v12_0_set_hw_resources(struct amdgpu_mes *mes, int pipe) mes_set_hw_res_pkt.event_intr_history_gpu_mc_ptr = mes->event_log_gpu_addr + pipe * AMDGPU_MES_LOG_BUFFER_SIZE; } + if (enforce_isolation) + mes_set_hw_res_pkt.limit_single_process = 1; + return mes_v12_0_submit_pkt_and_poll_completion(mes, pipe, &mes_set_hw_res_pkt, sizeof(mes_set_hw_res_pkt), offsetof(union MESAPI_SET_HW_RESOURCES, api_status)); @@ -1326,9 +1337,9 @@ static int mes_v12_0_mqd_sw_init(struct amdgpu_device *adev, return 0; } -static int mes_v12_0_sw_init(void *handle) +static int mes_v12_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int pipe, r; adev->mes.funcs = &mes_v12_0_funcs; @@ -1362,9 +1373,9 @@ static int mes_v12_0_sw_init(void *handle) return 0; } -static int mes_v12_0_sw_fini(void *handle) +static int mes_v12_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int pipe; for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { @@ -1452,6 +1463,7 @@ static void mes_v12_0_kiq_setting(struct amdgpu_ring *ring) static int mes_v12_0_kiq_hw_init(struct amdgpu_device *adev) { int r = 0; + struct amdgpu_ip_block *ip_block; if (adev->enable_uni_mes) mes_v12_0_kiq_setting(&adev->mes.ring[AMDGPU_MES_KIQ_PIPE]); @@ -1479,6 +1491,12 @@ static int mes_v12_0_kiq_hw_init(struct amdgpu_device *adev) mes_v12_0_enable(adev, true); + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_MES); + if (unlikely(!ip_block)) { + dev_err(adev->dev, "Failed to get MES handle\n"); + return -EINVAL; + } + r = mes_v12_0_queue_init(adev, AMDGPU_MES_KIQ_PIPE); if (r) goto failure; @@ -1492,7 +1510,7 @@ static int mes_v12_0_kiq_hw_init(struct amdgpu_device *adev) } if (adev->mes.enable_legacy_queue_map) { - r = mes_v12_0_hw_init(adev); + r = mes_v12_0_hw_init(ip_block); if (r) goto failure; } @@ -1500,7 +1518,7 @@ static int mes_v12_0_kiq_hw_init(struct amdgpu_device *adev) return r; failure: - mes_v12_0_hw_fini(adev); + mes_v12_0_hw_fini(ip_block); return r; } @@ -1522,10 +1540,10 @@ static int mes_v12_0_kiq_hw_fini(struct amdgpu_device *adev) return 0; } -static int mes_v12_0_hw_init(void *handle) +static int mes_v12_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->mes.ring[0].sched.ready) goto out; @@ -1584,42 +1602,40 @@ static int mes_v12_0_hw_init(void *handle) return 0; failure: - mes_v12_0_hw_fini(adev); + mes_v12_0_hw_fini(ip_block); return r; } -static int mes_v12_0_hw_fini(void *handle) +static int mes_v12_0_hw_fini(struct amdgpu_ip_block *ip_block) { return 0; } -static int mes_v12_0_suspend(void *handle) +static int mes_v12_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_mes_suspend(adev); + r = amdgpu_mes_suspend(ip_block->adev); if (r) return r; - return mes_v12_0_hw_fini(adev); + return mes_v12_0_hw_fini(ip_block); } -static int mes_v12_0_resume(void *handle) +static int mes_v12_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = mes_v12_0_hw_init(adev); + r = mes_v12_0_hw_init(ip_block); if (r) return r; - return amdgpu_mes_resume(adev); + return amdgpu_mes_resume(ip_block->adev); } -static int mes_v12_0_early_init(void *handle) +static int mes_v12_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int pipe, r; for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { @@ -1631,9 +1647,9 @@ static int mes_v12_0_early_init(void *handle) return 0; } -static int mes_v12_0_late_init(void *handle) +static int mes_v12_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* it's only intended for use in mes_self_test case, not for s0ix and reset */ if (!amdgpu_in_reset(adev) && !adev->in_s0ix && !adev->in_suspend) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index e3ddd22aa1728e..e9a6f33ca7109d 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -229,6 +229,52 @@ static void mmhub_v1_0_disable_identity_aperture(struct amdgpu_device *adev) 0); } +static void mmhub_v1_0_init_saw(struct amdgpu_device *adev) +{ + uint64_t pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); + uint32_t tmp; + + /* VM_9_X_REGISTER_VM_L2_SAW_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32 */ + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, + lower_32_bits(pt_base >> 12)); + + /* VM_9_X_REGISTER_VM_L2_SAW_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32 */ + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, + upper_32_bits(pt_base >> 12)); + + /* VM_9_X_REGISTER_VM_L2_SAW_CONTEXT0_PAGE_TABLE_START_ADDR_LO32 */ + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, + (u32)(adev->gmc.gart_start >> 12)); + + /* VM_9_X_REGISTER_VM_L2_SAW_CONTEXT0_PAGE_TABLE_START_ADDR_HI32 */ + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, + (u32)(adev->gmc.gart_start >> 44)); + + /* VM_9_X_REGISTER_VM_L2_SAW_CONTEXT0_PAGE_TABLE_END_ADDR_LO32 */ + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, + (u32)(adev->gmc.gart_end >> 12)); + + /* VM_9_X_REGISTER_VM_L2_SAW_CONTEXT0_PAGE_TABLE_END_ADDR_HI32 */ + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, + (u32)(adev->gmc.gart_end >> 44)); + + /* Program SAW CONTEXT0 CNTL */ + tmp = RREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXT0_CNTL); + tmp |= 1 << CONTEXT0_CNTL_ENABLE_OFFSET; + tmp &= ~(3 << CONTEXT0_CNTL_PAGE_TABLE_DEPTH_OFFSET); + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXT0_CNTL, tmp); + + /* Disable all Contexts except Context0 */ + tmp = 0xfffe; + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CONTEXTS_DISABLE, tmp); + + /* Program SAW CNTL4 */ + tmp = RREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CNTL4); + tmp |= 1 << VMC_TAP_PDE_REQUEST_SNOOP_OFFSET; + tmp |= 1 << VMC_TAP_PTE_REQUEST_SNOOP_OFFSET; + WREG32_SOC15(MMHUB, 0, mmVM_L2_SAW_CNTL4, tmp); +} + static void mmhub_v1_0_setup_vmid_config(struct amdgpu_device *adev) { struct amdgpu_vmhub *hub = &adev->vmhub[AMDGPU_MMHUB0(0)]; @@ -283,6 +329,9 @@ static void mmhub_v1_0_setup_vmid_config(struct amdgpu_device *adev) i * hub->ctx_addr_distance, upper_32_bits(adev->vm_manager.max_pfn - 1)); } + + if (amdgpu_ip_version(adev, ISP_HWIP, 0)) + mmhub_v1_0_init_saw(adev); } static void mmhub_v1_0_program_invalidation(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c index 0fbc3be81f140f..f2ab5001b49249 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v4_1_0.c @@ -108,7 +108,7 @@ mmhub_v4_1_0_print_l2_protection_fault_status(struct amdgpu_device *adev, dev_err(adev->dev, "MMVM_L2_PROTECTION_FAULT_STATUS_LO32:0x%08X\n", status); - switch (adev->ip_versions[MMHUB_HWIP][0]) { + switch (amdgpu_ip_version(adev, MMHUB_HWIP, 0)) { case IP_VERSION(4, 1, 0): mmhub_cid = mmhub_client_ids_v4_1_0[cid][rw]; break; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c index f47bd7ada4d79c..4dcb72d1bdda21 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.c @@ -61,15 +61,18 @@ static enum idh_event xgpu_nv_mailbox_peek_msg(struct amdgpu_device *adev) static int xgpu_nv_mailbox_rcv_msg(struct amdgpu_device *adev, enum idh_event event) { + int r = 0; u32 reg; reg = RREG32_NO_KIQ(mmMAILBOX_MSGBUF_RCV_DW0); - if (reg != event) + if (reg == IDH_FAIL) + r = -EINVAL; + else if (reg != event) return -ENOENT; xgpu_nv_mailbox_send_ack(adev); - return 0; + return r; } static uint8_t xgpu_nv_peek_ack(struct amdgpu_device *adev) @@ -178,6 +181,9 @@ static int xgpu_nv_send_access_requests_with_param(struct amdgpu_device *adev, if (data1 != 0) event = IDH_RAS_POISON_READY; break; + case IDH_REQ_RAS_ERROR_COUNT: + event = IDH_RAS_ERROR_COUNT_READY; + break; default: break; } @@ -456,6 +462,11 @@ static bool xgpu_nv_rcvd_ras_intr(struct amdgpu_device *adev) return (msg == IDH_RAS_ERROR_DETECTED || msg == 0xFFFFFFFF); } +static int xgpu_nv_req_ras_err_count(struct amdgpu_device *adev) +{ + return xgpu_nv_send_access_requests(adev, IDH_REQ_RAS_ERROR_COUNT); +} + const struct amdgpu_virt_ops xgpu_nv_virt_ops = { .req_full_gpu = xgpu_nv_request_full_gpu_access, .rel_full_gpu = xgpu_nv_release_full_gpu_access, @@ -466,4 +477,5 @@ const struct amdgpu_virt_ops xgpu_nv_virt_ops = { .trans_msg = xgpu_nv_mailbox_trans_msg, .ras_poison_handler = xgpu_nv_ras_poison_handler, .rcvd_ras_intr = xgpu_nv_rcvd_ras_intr, + .req_ras_err_count = xgpu_nv_req_ras_err_count, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h index 1d099ffb3a5a2c..9d61d76e1bf966 100644 --- a/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h +++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_nv.h @@ -40,6 +40,7 @@ enum idh_request { IDH_LOG_VF_ERROR = 200, IDH_READY_TO_RESET = 201, IDH_RAS_POISON = 202, + IDH_REQ_RAS_ERROR_COUNT = 203, }; enum idh_event { @@ -54,6 +55,8 @@ enum idh_event { IDH_RAS_POISON_READY, IDH_PF_SOFT_FLR_NOTIFICATION, IDH_RAS_ERROR_DETECTED, + IDH_RAS_ERROR_COUNT_READY = 11, + IDH_TEXT_MESSAGE = 255, }; diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c index b281462093f117..0820ed62e2e8ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/navi10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/navi10_ih.c @@ -542,19 +542,19 @@ static void navi10_ih_set_self_irq_funcs(struct amdgpu_device *adev) adev->irq.self_irq.funcs = &navi10_ih_self_irq_funcs; } -static int navi10_ih_early_init(void *handle) +static int navi10_ih_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; navi10_ih_set_interrupt_funcs(adev); navi10_ih_set_self_irq_funcs(adev); return 0; } -static int navi10_ih_sw_init(void *handle) +static int navi10_ih_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; bool use_bus_addr; r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0, @@ -593,43 +593,37 @@ static int navi10_ih_sw_init(void *handle) return r; } -static int navi10_ih_sw_fini(void *handle) +static int navi10_ih_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); return 0; } -static int navi10_ih_hw_init(void *handle) +static int navi10_ih_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return navi10_ih_irq_init(adev); } -static int navi10_ih_hw_fini(void *handle) +static int navi10_ih_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - navi10_ih_irq_disable(adev); + navi10_ih_irq_disable(ip_block->adev); return 0; } -static int navi10_ih_suspend(void *handle) +static int navi10_ih_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return navi10_ih_hw_fini(adev); + return navi10_ih_hw_fini(ip_block); } -static int navi10_ih_resume(void *handle) +static int navi10_ih_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return navi10_ih_hw_init(adev); + return navi10_ih_hw_init(ip_block); } static bool navi10_ih_is_idle(void *handle) @@ -638,13 +632,13 @@ static bool navi10_ih_is_idle(void *handle) return true; } -static int navi10_ih_wait_for_idle(void *handle) +static int navi10_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* todo */ return -ETIMEDOUT; } -static int navi10_ih_soft_reset(void *handle) +static int navi10_ih_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ return 0; @@ -700,7 +694,6 @@ static void navi10_ih_get_clockgating_state(void *handle, u64 *flags) static const struct amd_ip_funcs navi10_ih_ip_funcs = { .name = "navi10_ih", .early_init = navi10_ih_early_init, - .late_init = NULL, .sw_init = navi10_ih_sw_init, .sw_fini = navi10_ih_sw_fini, .hw_init = navi10_ih_hw_init, @@ -713,8 +706,6 @@ static const struct amd_ip_funcs navi10_ih_ip_funcs = { .set_clockgating_state = navi10_ih_set_clockgating_state, .set_powergating_state = navi10_ih_set_powergating_state, .get_clockgating_state = navi10_ih_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs navi10_ih_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/navi10_sdma_pkt_open.h b/drivers/gpu/drm/amd/amdgpu/navi10_sdma_pkt_open.h index a5b60c9a24189d..c88284ff92d851 100644 --- a/drivers/gpu/drm/amd/amdgpu/navi10_sdma_pkt_open.h +++ b/drivers/gpu/drm/amd/amdgpu/navi10_sdma_pkt_open.h @@ -68,6 +68,7 @@ #define SDMA_SUBOP_POLL_REG_WRITE_MEM 1 #define SDMA_SUBOP_POLL_DBIT_WRITE_MEM 2 #define SDMA_SUBOP_POLL_MEM_VERIFY 3 +#define SDMA_SUBOP_VM_INVALIDATION 4 #define HEADER_AGENT_DISPATCH 4 #define HEADER_BARRIER 5 #define SDMA_OP_AQL_COPY 0 @@ -4040,6 +4041,69 @@ #define SDMA_PKT_POLL_MEM_VERIFY_RESERVED_RESERVED(x) (((x) & SDMA_PKT_POLL_MEM_VERIFY_RESERVED_reserved_mask) << SDMA_PKT_POLL_MEM_VERIFY_RESERVED_reserved_shift) +/* +** Definitions for SDMA_PKT_VM_INVALIDATION packet +*/ + +/*define for HEADER word*/ +/*define for op field*/ +#define SDMA_PKT_VM_INVALIDATION_HEADER_op_offset 0 +#define SDMA_PKT_VM_INVALIDATION_HEADER_op_mask 0x000000FF +#define SDMA_PKT_VM_INVALIDATION_HEADER_op_shift 0 +#define SDMA_PKT_VM_INVALIDATION_HEADER_OP(x) (((x) & SDMA_PKT_VM_INVALIDATION_HEADER_op_mask) << SDMA_PKT_VM_INVALIDATION_HEADER_op_shift) + +/*define for sub_op field*/ +#define SDMA_PKT_VM_INVALIDATION_HEADER_sub_op_offset 0 +#define SDMA_PKT_VM_INVALIDATION_HEADER_sub_op_mask 0x000000FF +#define SDMA_PKT_VM_INVALIDATION_HEADER_sub_op_shift 8 +#define SDMA_PKT_VM_INVALIDATION_HEADER_SUB_OP(x) (((x) & SDMA_PKT_VM_INVALIDATION_HEADER_sub_op_mask) << SDMA_PKT_VM_INVALIDATION_HEADER_sub_op_shift) + +/*define for gfx_eng_id field*/ +#define SDMA_PKT_VM_INVALIDATION_HEADER_gfx_eng_id_offset 0 +#define SDMA_PKT_VM_INVALIDATION_HEADER_gfx_eng_id_mask 0x0000001F +#define SDMA_PKT_VM_INVALIDATION_HEADER_gfx_eng_id_shift 16 +#define SDMA_PKT_VM_INVALIDATION_HEADER_GFX_ENG_ID(x) (((x) & SDMA_PKT_VM_INVALIDATION_HEADER_gfx_eng_id_mask) << SDMA_PKT_VM_INVALIDATION_HEADER_gfx_eng_id_shift) + +/*define for mm_eng_id field*/ +#define SDMA_PKT_VM_INVALIDATION_HEADER_mm_eng_id_offset 0 +#define SDMA_PKT_VM_INVALIDATION_HEADER_mm_eng_id_mask 0x0000001F +#define SDMA_PKT_VM_INVALIDATION_HEADER_mm_eng_id_shift 24 +#define SDMA_PKT_VM_INVALIDATION_HEADER_MM_ENG_ID(x) (((x) & SDMA_PKT_VM_INVALIDATION_HEADER_mm_eng_id_mask) << SDMA_PKT_VM_INVALIDATION_HEADER_mm_eng_id_shift) + +/*define for INVALIDATEREQ word*/ +/*define for invalidatereq field*/ +#define SDMA_PKT_VM_INVALIDATION_INVALIDATEREQ_invalidatereq_offset 1 +#define SDMA_PKT_VM_INVALIDATION_INVALIDATEREQ_invalidatereq_mask 0xFFFFFFFF +#define SDMA_PKT_VM_INVALIDATION_INVALIDATEREQ_invalidatereq_shift 0 +#define SDMA_PKT_VM_INVALIDATION_INVALIDATEREQ_INVALIDATEREQ(x) (((x) & SDMA_PKT_VM_INVALIDATION_INVALIDATEREQ_invalidatereq_mask) << SDMA_PKT_VM_INVALIDATION_INVALIDATEREQ_invalidatereq_shift) + +/*define for ADDRESSRANGELO word*/ +/*define for addressrangelo field*/ +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGELO_addressrangelo_offset 2 +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGELO_addressrangelo_mask 0xFFFFFFFF +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGELO_addressrangelo_shift 0 +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGELO_ADDRESSRANGELO(x) (((x) & SDMA_PKT_VM_INVALIDATION_ADDRESSRANGELO_addressrangelo_mask) << SDMA_PKT_VM_INVALIDATION_ADDRESSRANGELO_addressrangelo_shift) + +/*define for ADDRESSRANGEHI word*/ +/*define for invalidateack field*/ +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_invalidateack_offset 3 +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_invalidateack_mask 0x0000FFFF +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_invalidateack_shift 0 +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_INVALIDATEACK(x) (((x) & SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_invalidateack_mask) << SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_invalidateack_shift) + +/*define for addressrangehi field*/ +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_addressrangehi_offset 3 +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_addressrangehi_mask 0x0000001F +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_addressrangehi_shift 16 +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_ADDRESSRANGEHI(x) (((x) & SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_addressrangehi_mask) << SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_addressrangehi_shift) + +/*define for reserved field*/ +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_reserved_offset 3 +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_reserved_mask 0x000001FF +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_reserved_shift 23 +#define SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_RESERVED(x) (((x) & SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_reserved_mask) << SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_reserved_shift) + + /* ** Definitions for SDMA_PKT_ATOMIC packet */ diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c index b1b57dcc5a7370..d1032e9992b49c 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_0.c @@ -271,8 +271,19 @@ const struct nbio_hdp_flush_reg nbio_v7_0_hdp_flush_reg = { .ref_and_mask_sdma1 = GPU_HDP_FLUSH_DONE__SDMA1_MASK, }; +#define regRCC_DEV0_EPF6_STRAP4 0xd304 +#define regRCC_DEV0_EPF6_STRAP4_BASE_IDX 5 + static void nbio_v7_0_init_registers(struct amdgpu_device *adev) { + uint32_t data; + + switch (amdgpu_ip_version(adev, NBIO_HWIP, 0)) { + case IP_VERSION(2, 5, 0): + data = RREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF6_STRAP4) & ~BIT(23); + WREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF6_STRAP4, data); + break; + } } #define MMIO_REG_HOLE_OFFSET (0x80000 - PAGE_SIZE) diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c index 7a9adfda5814a6..41421da63a0846 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_11.c @@ -275,6 +275,15 @@ static void nbio_v7_11_init_registers(struct amdgpu_device *adev) if (def != data) WREG32_SOC15(NBIO, 0, regBIF_BIF256_CI256_RC3X4_USB4_PCIE_MST_CTRL_3, data); + switch (amdgpu_ip_version(adev, NBIO_HWIP, 0)) { + case IP_VERSION(7, 11, 0): + case IP_VERSION(7, 11, 1): + case IP_VERSION(7, 11, 2): + case IP_VERSION(7, 11, 3): + data = RREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF5_STRAP4) & ~BIT(23); + WREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF5_STRAP4, data); + break; + } } static void nbio_v7_11_update_medium_grain_clock_gating(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c index 8d80df94bd8b51..a26a9be58eac23 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c @@ -414,8 +414,7 @@ static void nbio_v7_4_handle_ras_controller_intr_no_bifring(struct amdgpu_device /* ras_controller_int is dedicated for nbif ras error, * not the global interrupt for sync flood */ - amdgpu_ras_set_fed(adev, true); - amdgpu_ras_reset_gpu(adev); + amdgpu_ras_global_ras_isr(adev); } amdgpu_ras_error_data_fini(&err_data); diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_7.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_7.c index 1ac730328516ff..3fb6d2aa7e3b39 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_7.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_7.c @@ -247,7 +247,7 @@ static void nbio_v7_7_init_registers(struct amdgpu_device *adev) if (def != data) WREG32_SOC15(NBIO, 0, regBIF0_PCIE_MST_CTRL_3, data); - switch (adev->ip_versions[NBIO_HWIP][0]) { + switch (amdgpu_ip_version(adev, NBIO_HWIP, 0)) { case IP_VERSION(7, 7, 0): data = RREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF5_STRAP4) & ~BIT(23); WREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF5_STRAP4, data); diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c index d1bd79bbae532f..8a0a63ac88d2b6 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c @@ -401,6 +401,17 @@ static int nbio_v7_9_get_compute_partition_mode(struct amdgpu_device *adev) return px; } +static bool nbio_v7_9_is_nps_switch_requested(struct amdgpu_device *adev) +{ + u32 tmp; + + tmp = RREG32_SOC15(NBIO, 0, regBIF_BX_PF0_PARTITION_MEM_STATUS); + tmp = REG_GET_FIELD(tmp, BIF_BX_PF0_PARTITION_MEM_STATUS, + CHANGE_STATUE); + + /* 0x8 - NPS switch requested */ + return (tmp == 0x8); +} static u32 nbio_v7_9_get_memory_partition_mode(struct amdgpu_device *adev, u32 *supp_modes) { @@ -508,6 +519,7 @@ const struct amdgpu_nbio_funcs nbio_v7_9_funcs = { .remap_hdp_registers = nbio_v7_9_remap_hdp_registers, .get_compute_partition_mode = nbio_v7_9_get_compute_partition_mode, .get_memory_partition_mode = nbio_v7_9_get_memory_partition_mode, + .is_nps_switch_requested = nbio_v7_9_is_nps_switch_requested, .init_registers = nbio_v7_9_init_registers, .get_pcie_replay_count = nbio_v7_9_get_pcie_replay_count, .set_reg_remap = nbio_v7_9_set_reg_remap, diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 73065a85e0d264..3bad565ded73d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -634,9 +634,9 @@ static const struct amdgpu_asic_funcs nv_asic_funcs = { .query_video_codecs = &nv_query_video_codecs, }; -static int nv_common_early_init(void *handle) +static int nv_common_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->nbio.funcs->set_reg_remap(adev); adev->smc_rreg = NULL; @@ -944,9 +944,9 @@ static int nv_common_early_init(void *handle) return 0; } -static int nv_common_late_init(void *handle) +static int nv_common_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) { xgpu_nv_mailbox_get_irq(adev); @@ -973,9 +973,9 @@ static int nv_common_late_init(void *handle) return 0; } -static int nv_common_sw_init(void *handle) +static int nv_common_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) xgpu_nv_mailbox_add_irq_id(adev); @@ -983,14 +983,9 @@ static int nv_common_sw_init(void *handle) return 0; } -static int nv_common_sw_fini(void *handle) +static int nv_common_hw_init(struct amdgpu_ip_block *ip_block) { - return 0; -} - -static int nv_common_hw_init(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->nbio.funcs->apply_lc_spc_mode_wa) adev->nbio.funcs->apply_lc_spc_mode_wa(adev); @@ -1014,9 +1009,9 @@ static int nv_common_hw_init(void *handle) return 0; } -static int nv_common_hw_fini(void *handle) +static int nv_common_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* Disable the doorbell aperture and selfring doorbell aperture * separately in hw_fini because nv_enable_doorbell_aperture @@ -1029,18 +1024,14 @@ static int nv_common_hw_fini(void *handle) return 0; } -static int nv_common_suspend(void *handle) +static int nv_common_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return nv_common_hw_fini(adev); + return nv_common_hw_fini(ip_block); } -static int nv_common_resume(void *handle) +static int nv_common_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return nv_common_hw_init(adev); + return nv_common_hw_init(ip_block); } static bool nv_common_is_idle(void *handle) @@ -1048,16 +1039,6 @@ static bool nv_common_is_idle(void *handle) return true; } -static int nv_common_wait_for_idle(void *handle) -{ - return 0; -} - -static int nv_common_soft_reset(void *handle) -{ - return 0; -} - static int nv_common_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -1115,17 +1096,12 @@ static const struct amd_ip_funcs nv_common_ip_funcs = { .early_init = nv_common_early_init, .late_init = nv_common_late_init, .sw_init = nv_common_sw_init, - .sw_fini = nv_common_sw_fini, .hw_init = nv_common_hw_init, .hw_fini = nv_common_hw_fini, .suspend = nv_common_suspend, .resume = nv_common_resume, .is_idle = nv_common_is_idle, - .wait_for_idle = nv_common_wait_for_idle, - .soft_reset = nv_common_soft_reset, .set_clockgating_state = nv_common_set_clockgating_state, .set_powergating_state = nv_common_set_powergating_state, .get_clockgating_state = nv_common_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; diff --git a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h index 37b5ddd6f13b33..f4a91b126c73c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h +++ b/drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h @@ -103,6 +103,10 @@ enum psp_gfx_cmd_id GFX_CMD_ID_AUTOLOAD_RLC = 0x00000021, /* Indicates all graphics fw loaded, start RLC autoload */ GFX_CMD_ID_BOOT_CFG = 0x00000022, /* Boot Config */ GFX_CMD_ID_SRIOV_SPATIAL_PART = 0x00000027, /* Configure spatial partitioning mode */ + /*IDs of performance monitoring/profiling*/ + GFX_CMD_ID_CONFIG_SQ_PERFMON = 0x00000046, /* Config CGTT_SQ_CLK_CTRL */ + /* Dynamic memory partitioninig (NPS mode change)*/ + GFX_CMD_ID_FB_NPS_MODE = 0x00000048, /* Configure memory partitioning mode */ }; /* PSP boot config sub-commands */ @@ -351,6 +355,20 @@ struct psp_gfx_cmd_sriov_spatial_part { uint32_t override_this_aid; }; +/*Structure for sq performance monitoring/profiling enable/disable*/ +struct psp_gfx_cmd_config_sq_perfmon { + uint32_t gfx_xcp_mask; + uint8_t core_override; + uint8_t reg_override; + uint8_t perfmon_override; + uint8_t reserved[5]; +}; + +struct psp_gfx_cmd_fb_memory_part { + uint32_t mode; /* requested NPS mode */ + uint32_t resvd; +}; + /* All GFX ring buffer commands. */ union psp_gfx_commands { @@ -365,6 +383,8 @@ union psp_gfx_commands struct psp_gfx_cmd_load_toc cmd_load_toc; struct psp_gfx_cmd_boot_cfg boot_cfg; struct psp_gfx_cmd_sriov_spatial_part cmd_spatial_part; + struct psp_gfx_cmd_config_sq_perfmon config_sq_perfmon; + struct psp_gfx_cmd_fb_memory_part cmd_memory_part; }; struct psp_gfx_uresp_reserved diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c index 51e470e8d67d9e..c4b775aaee9fe7 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c @@ -823,6 +823,30 @@ static bool psp_v13_0_is_aux_sos_load_required(struct psp_context *psp) return (pmfw_ver < 0x557300); } +static bool psp_v13_0_is_reload_needed(struct psp_context *psp) +{ + uint32_t ucode_ver; + + if (!psp_v13_0_is_sos_alive(psp)) + return false; + + /* Restrict reload support only to specific IP versions */ + switch (amdgpu_ip_version(psp->adev, MP0_HWIP, 0)) { + case IP_VERSION(13, 0, 2): + case IP_VERSION(13, 0, 6): + case IP_VERSION(13, 0, 14): + /* TOS version read from microcode header */ + ucode_ver = psp->sos.fw_version; + /* Read TOS version from hardware */ + psp_v13_0_init_sos_version(psp); + return (ucode_ver != psp->sos.fw_version); + default: + return false; + } + + return false; +} + static const struct psp_funcs psp_v13_0_funcs = { .init_microcode = psp_v13_0_init_microcode, .wait_for_bootloader = psp_v13_0_wait_for_bootloader_steady_state, @@ -847,6 +871,7 @@ static const struct psp_funcs psp_v13_0_funcs = { .fatal_error_recovery_quirk = psp_v13_0_fatal_error_recovery_quirk, .get_ras_capability = psp_v13_0_get_ras_capability, .is_aux_sos_load_required = psp_v13_0_is_aux_sos_load_required, + .is_reload_needed = psp_v13_0_is_reload_needed, }; void psp_v13_0_set_psp_funcs(struct psp_context *psp) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 725392522267ff..7948d74f872256 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -807,9 +807,9 @@ static void sdma_v2_4_ring_emit_wreg(struct amdgpu_ring *ring, amdgpu_ring_write(ring, val); } -static int sdma_v2_4_early_init(void *handle) +static int sdma_v2_4_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; adev->sdma.num_instances = SDMA_MAX_INSTANCE; @@ -826,11 +826,11 @@ static int sdma_v2_4_early_init(void *handle) return 0; } -static int sdma_v2_4_sw_init(void *handle) +static int sdma_v2_4_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* SDMA trap event */ r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SDMA_TRAP, @@ -866,9 +866,9 @@ static int sdma_v2_4_sw_init(void *handle) return r; } -static int sdma_v2_4_sw_fini(void *handle) +static int sdma_v2_4_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) @@ -878,10 +878,10 @@ static int sdma_v2_4_sw_fini(void *handle) return 0; } -static int sdma_v2_4_hw_init(void *handle) +static int sdma_v2_4_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; sdma_v2_4_init_golden_registers(adev); @@ -892,27 +892,21 @@ static int sdma_v2_4_hw_init(void *handle) return r; } -static int sdma_v2_4_hw_fini(void *handle) +static int sdma_v2_4_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - sdma_v2_4_enable(adev, false); + sdma_v2_4_enable(ip_block->adev, false); return 0; } -static int sdma_v2_4_suspend(void *handle) +static int sdma_v2_4_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v2_4_hw_fini(adev); + return sdma_v2_4_hw_fini(ip_block); } -static int sdma_v2_4_resume(void *handle) +static int sdma_v2_4_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v2_4_hw_init(adev); + return sdma_v2_4_hw_init(ip_block); } static bool sdma_v2_4_is_idle(void *handle) @@ -927,11 +921,11 @@ static bool sdma_v2_4_is_idle(void *handle) return true; } -static int sdma_v2_4_wait_for_idle(void *handle) +static int sdma_v2_4_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { tmp = RREG32(mmSRBM_STATUS2) & (SRBM_STATUS2__SDMA_BUSY_MASK | @@ -944,10 +938,10 @@ static int sdma_v2_4_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int sdma_v2_4_soft_reset(void *handle) +static int sdma_v2_4_soft_reset(struct amdgpu_ip_block *ip_block) { u32 srbm_soft_reset = 0; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 tmp = RREG32(mmSRBM_STATUS2); if (tmp & SRBM_STATUS2__SDMA_BUSY_MASK) { @@ -1102,7 +1096,6 @@ static int sdma_v2_4_set_powergating_state(void *handle, static const struct amd_ip_funcs sdma_v2_4_ip_funcs = { .name = "sdma_v2_4", .early_init = sdma_v2_4_early_init, - .late_init = NULL, .sw_init = sdma_v2_4_sw_init, .sw_fini = sdma_v2_4_sw_fini, .hw_init = sdma_v2_4_hw_init, @@ -1114,8 +1107,6 @@ static const struct amd_ip_funcs sdma_v2_4_ip_funcs = { .soft_reset = sdma_v2_4_soft_reset, .set_clockgating_state = sdma_v2_4_set_clockgating_state, .set_powergating_state = sdma_v2_4_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs sdma_v2_4_ring_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index e65194fe94af65..9a3d729545a7c6 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -1080,9 +1080,9 @@ static void sdma_v3_0_ring_emit_wreg(struct amdgpu_ring *ring, amdgpu_ring_write(ring, val); } -static int sdma_v3_0_early_init(void *handle) +static int sdma_v3_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; switch (adev->asic_type) { @@ -1106,11 +1106,11 @@ static int sdma_v3_0_early_init(void *handle) return 0; } -static int sdma_v3_0_sw_init(void *handle) +static int sdma_v3_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* SDMA trap event */ r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SDMA_TRAP, @@ -1152,9 +1152,9 @@ static int sdma_v3_0_sw_init(void *handle) return r; } -static int sdma_v3_0_sw_fini(void *handle) +static int sdma_v3_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) @@ -1164,10 +1164,10 @@ static int sdma_v3_0_sw_fini(void *handle) return 0; } -static int sdma_v3_0_hw_init(void *handle) +static int sdma_v3_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; sdma_v3_0_init_golden_registers(adev); @@ -1178,9 +1178,9 @@ static int sdma_v3_0_hw_init(void *handle) return r; } -static int sdma_v3_0_hw_fini(void *handle) +static int sdma_v3_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; sdma_v3_0_ctx_switch_enable(adev, false); sdma_v3_0_enable(adev, false); @@ -1188,18 +1188,14 @@ static int sdma_v3_0_hw_fini(void *handle) return 0; } -static int sdma_v3_0_suspend(void *handle) +static int sdma_v3_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v3_0_hw_fini(adev); + return sdma_v3_0_hw_fini(ip_block); } -static int sdma_v3_0_resume(void *handle) +static int sdma_v3_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v3_0_hw_init(adev); + return sdma_v3_0_hw_init(ip_block); } static bool sdma_v3_0_is_idle(void *handle) @@ -1214,11 +1210,11 @@ static bool sdma_v3_0_is_idle(void *handle) return true; } -static int sdma_v3_0_wait_for_idle(void *handle) +static int sdma_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { tmp = RREG32(mmSRBM_STATUS2) & (SRBM_STATUS2__SDMA_BUSY_MASK | @@ -1231,9 +1227,9 @@ static int sdma_v3_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static bool sdma_v3_0_check_soft_reset(void *handle) +static bool sdma_v3_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; u32 tmp = RREG32(mmSRBM_STATUS2); @@ -1252,9 +1248,9 @@ static bool sdma_v3_0_check_soft_reset(void *handle) } } -static int sdma_v3_0_pre_soft_reset(void *handle) +static int sdma_v3_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; if (!adev->sdma.srbm_soft_reset) @@ -1271,9 +1267,9 @@ static int sdma_v3_0_pre_soft_reset(void *handle) return 0; } -static int sdma_v3_0_post_soft_reset(void *handle) +static int sdma_v3_0_post_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; if (!adev->sdma.srbm_soft_reset) @@ -1290,9 +1286,9 @@ static int sdma_v3_0_post_soft_reset(void *handle) return 0; } -static int sdma_v3_0_soft_reset(void *handle) +static int sdma_v3_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; u32 tmp; @@ -1538,7 +1534,6 @@ static void sdma_v3_0_get_clockgating_state(void *handle, u64 *flags) static const struct amd_ip_funcs sdma_v3_0_ip_funcs = { .name = "sdma_v3_0", .early_init = sdma_v3_0_early_init, - .late_init = NULL, .sw_init = sdma_v3_0_sw_init, .sw_fini = sdma_v3_0_sw_fini, .hw_init = sdma_v3_0_hw_init, @@ -1554,8 +1549,6 @@ static const struct amd_ip_funcs sdma_v3_0_ip_funcs = { .set_clockgating_state = sdma_v3_0_set_clockgating_state, .set_powergating_state = sdma_v3_0_set_powergating_state, .get_clockgating_state = sdma_v3_0_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index 23ef4eb36b407a..c1f98f6cf20d48 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -1751,9 +1751,9 @@ static bool sdma_v4_0_fw_support_paging_queue(struct amdgpu_device *adev) } } -static int sdma_v4_0_early_init(void *handle) +static int sdma_v4_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = sdma_v4_0_init_microcode(adev); @@ -1780,9 +1780,9 @@ static int sdma_v4_0_process_ras_data_cb(struct amdgpu_device *adev, void *err_data, struct amdgpu_iv_entry *entry); -static int sdma_v4_0_late_init(void *handle) +static int sdma_v4_0_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; sdma_v4_0_setup_ulv(adev); @@ -1792,11 +1792,11 @@ static int sdma_v4_0_late_init(void *handle) return 0; } -static int sdma_v4_0_sw_init(void *handle) +static int sdma_v4_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_4_0); uint32_t *ptr; @@ -1929,9 +1929,9 @@ static int sdma_v4_0_sw_init(void *handle) return r; } -static int sdma_v4_0_sw_fini(void *handle) +static int sdma_v4_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) { @@ -1951,9 +1951,9 @@ static int sdma_v4_0_sw_fini(void *handle) return 0; } -static int sdma_v4_0_hw_init(void *handle) +static int sdma_v4_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->flags & AMD_IS_APU) amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_SDMA, false); @@ -1964,9 +1964,9 @@ static int sdma_v4_0_hw_init(void *handle) return sdma_v4_0_start(adev); } -static int sdma_v4_0_hw_fini(void *handle) +static int sdma_v4_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; if (amdgpu_sriov_vf(adev)) @@ -1988,9 +1988,9 @@ static int sdma_v4_0_hw_fini(void *handle) return 0; } -static int sdma_v4_0_suspend(void *handle) +static int sdma_v4_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* SMU saves SDMA state for us */ if (adev->in_s0ix) { @@ -1998,12 +1998,12 @@ static int sdma_v4_0_suspend(void *handle) return 0; } - return sdma_v4_0_hw_fini(adev); + return sdma_v4_0_hw_fini(ip_block); } -static int sdma_v4_0_resume(void *handle) +static int sdma_v4_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* SMU restores SDMA state for us */ if (adev->in_s0ix) { @@ -2012,7 +2012,7 @@ static int sdma_v4_0_resume(void *handle) return 0; } - return sdma_v4_0_hw_init(adev); + return sdma_v4_0_hw_init(ip_block); } static bool sdma_v4_0_is_idle(void *handle) @@ -2030,11 +2030,11 @@ static bool sdma_v4_0_is_idle(void *handle) return true; } -static int sdma_v4_0_wait_for_idle(void *handle) +static int sdma_v4_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i, j; u32 sdma[AMDGPU_MAX_SDMA_INSTANCES]; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { for (j = 0; j < adev->sdma.num_instances; j++) { @@ -2049,7 +2049,7 @@ static int sdma_v4_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int sdma_v4_0_soft_reset(void *handle) +static int sdma_v4_0_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ @@ -2350,9 +2350,9 @@ static void sdma_v4_0_get_clockgating_state(void *handle, u64 *flags) *flags |= AMD_CG_SUPPORT_SDMA_LS; } -static void sdma_v4_0_print_ip_state(void *handle, struct drm_printer *p) +static void sdma_v4_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_4_0); uint32_t instance_offset; @@ -2371,9 +2371,9 @@ static void sdma_v4_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void sdma_v4_0_dump_ip_state(void *handle) +static void sdma_v4_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t instance_offset; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_4_0); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c index c77889040760ad..a38553f38fdc87 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c @@ -1290,9 +1290,9 @@ static bool sdma_v4_4_2_fw_support_paging_queue(struct amdgpu_device *adev) } } -static int sdma_v4_4_2_early_init(void *handle) +static int sdma_v4_4_2_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = sdma_v4_4_2_init_microcode(adev); @@ -1318,9 +1318,9 @@ static int sdma_v4_4_2_process_ras_data_cb(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry); #endif -static int sdma_v4_4_2_late_init(void *handle) +static int sdma_v4_4_2_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; #if 0 struct ras_ih_if ih_info = { .cb = sdma_v4_4_2_process_ras_data_cb, @@ -1332,11 +1332,11 @@ static int sdma_v4_4_2_late_init(void *handle) return 0; } -static int sdma_v4_4_2_sw_init(void *handle) +static int sdma_v4_4_2_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 aid_id; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_4_4_2); uint32_t *ptr; @@ -1430,6 +1430,10 @@ static int sdma_v4_4_2_sw_init(void *handle) } } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->sdma.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring); + if (amdgpu_sdma_ras_sw_init(adev)) { dev_err(adev->dev, "fail to initialize sdma ras block\n"); return -EINVAL; @@ -1442,12 +1446,16 @@ static int sdma_v4_4_2_sw_init(void *handle) else DRM_ERROR("Failed to allocated memory for SDMA IP Dump\n"); + r = amdgpu_sdma_sysfs_reset_mask_init(adev); + if (r) + return r; + return r; } -static int sdma_v4_4_2_sw_fini(void *handle) +static int sdma_v4_4_2_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) { @@ -1456,6 +1464,7 @@ static int sdma_v4_4_2_sw_fini(void *handle) amdgpu_ring_fini(&adev->sdma.instance[i].page); } + amdgpu_sdma_sysfs_reset_mask_fini(adev); if (amdgpu_ip_version(adev, SDMA0_HWIP, 0) == IP_VERSION(4, 4, 2) || amdgpu_ip_version(adev, SDMA0_HWIP, 0) == IP_VERSION(4, 4, 5)) amdgpu_sdma_destroy_inst_ctx(adev, true); @@ -1467,10 +1476,10 @@ static int sdma_v4_4_2_sw_fini(void *handle) return 0; } -static int sdma_v4_4_2_hw_init(void *handle) +static int sdma_v4_4_2_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t inst_mask; inst_mask = GENMASK(adev->sdma.num_instances - 1, 0); @@ -1482,9 +1491,9 @@ static int sdma_v4_4_2_hw_init(void *handle) return r; } -static int sdma_v4_4_2_hw_fini(void *handle) +static int sdma_v4_4_2_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t inst_mask; int i; @@ -1508,21 +1517,19 @@ static int sdma_v4_4_2_hw_fini(void *handle) static int sdma_v4_4_2_set_clockgating_state(void *handle, enum amd_clockgating_state state); -static int sdma_v4_4_2_suspend(void *handle) +static int sdma_v4_4_2_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_in_reset(adev)) sdma_v4_4_2_set_clockgating_state(adev, AMD_CG_STATE_UNGATE); - return sdma_v4_4_2_hw_fini(adev); + return sdma_v4_4_2_hw_fini(ip_block); } -static int sdma_v4_4_2_resume(void *handle) +static int sdma_v4_4_2_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v4_4_2_hw_init(adev); + return sdma_v4_4_2_hw_init(ip_block); } static bool sdma_v4_4_2_is_idle(void *handle) @@ -1540,11 +1547,11 @@ static bool sdma_v4_4_2_is_idle(void *handle) return true; } -static int sdma_v4_4_2_wait_for_idle(void *handle) +static int sdma_v4_4_2_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i, j; u32 sdma[AMDGPU_MAX_SDMA_INSTANCES]; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { for (j = 0; j < adev->sdma.num_instances; j++) { @@ -1559,7 +1566,7 @@ static int sdma_v4_4_2_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int sdma_v4_4_2_soft_reset(void *handle) +static int sdma_v4_4_2_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ @@ -1857,9 +1864,9 @@ static void sdma_v4_4_2_get_clockgating_state(void *handle, u64 *flags) *flags |= AMD_CG_SUPPORT_SDMA_LS; } -static void sdma_v4_4_2_print_ip_state(void *handle, struct drm_printer *p) +static void sdma_v4_4_2_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_4_4_2); uint32_t instance_offset; @@ -1878,9 +1885,9 @@ static void sdma_v4_4_2_print_ip_state(void *handle, struct drm_printer *p) } } -static void sdma_v4_4_2_dump_ip_state(void *handle) +static void sdma_v4_4_2_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t instance_offset; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_4_4_2); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c index 3e48ea38385de7..fa9b4093495702 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c @@ -705,14 +705,16 @@ static void sdma_v5_0_enable(struct amdgpu_device *adev, bool enable) } /** - * sdma_v5_0_gfx_resume - setup and start the async dma engines + * sdma_v5_0_gfx_resume_instance - start/restart a certain sdma engine * * @adev: amdgpu_device pointer + * @i: instance + * @restore: used to restore wptr when restart * - * Set up the gfx DMA ring buffers and enable them (NAVI10). - * Returns 0 for success, error for failure. + * Set up the gfx DMA ring buffers and enable them. On restart, we will restore wptr and rptr. + * Return 0 for success. */ -static int sdma_v5_0_gfx_resume(struct amdgpu_device *adev) +static int sdma_v5_0_gfx_resume_instance(struct amdgpu_device *adev, int i, bool restore) { struct amdgpu_ring *ring; u32 rb_cntl, ib_cntl; @@ -722,142 +724,163 @@ static int sdma_v5_0_gfx_resume(struct amdgpu_device *adev) u32 temp; u32 wptr_poll_cntl; u64 wptr_gpu_addr; - int i, r; - for (i = 0; i < adev->sdma.num_instances; i++) { - ring = &adev->sdma.instance[i].ring; + ring = &adev->sdma.instance[i].ring; - if (!amdgpu_sriov_vf(adev)) - WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0); + if (!amdgpu_sriov_vf(adev)) + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0); - /* Set ring buffer size in dwords */ - rb_bufsz = order_base_2(ring->ring_size / 4); - rb_cntl = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL)); - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SIZE, rb_bufsz); + /* Set ring buffer size in dwords */ + rb_bufsz = order_base_2(ring->ring_size / 4); + rb_cntl = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL)); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SIZE, rb_bufsz); #ifdef __BIG_ENDIAN - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SWAP_ENABLE, 1); - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, - RPTR_WRITEBACK_SWAP_ENABLE, 1); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SWAP_ENABLE, 1); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, + RPTR_WRITEBACK_SWAP_ENABLE, 1); #endif - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); - - /* Initialize the ring buffer's read and write pointers */ + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); + + /* Initialize the ring buffer's read and write pointers */ + if (restore) { + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR), lower_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_HI), upper_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); + } else { WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR), 0); WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_HI), 0); WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), 0); WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), 0); - - /* setup the wptr shadow polling */ - wptr_gpu_addr = ring->wptr_gpu_addr; - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_LO), - lower_32_bits(wptr_gpu_addr)); - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_HI), - upper_32_bits(wptr_gpu_addr)); - wptr_poll_cntl = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, - mmSDMA0_GFX_RB_WPTR_POLL_CNTL)); - wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl, - SDMA0_GFX_RB_WPTR_POLL_CNTL, - F32_POLL_ENABLE, 1); - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL), - wptr_poll_cntl); - - /* set the wb address whether it's enabled or not */ - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_HI), - upper_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFF); - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_LO), - lower_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFC); - - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1); - - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE), - ring->gpu_addr >> 8); - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE_HI), - ring->gpu_addr >> 40); - + } + /* setup the wptr shadow polling */ + wptr_gpu_addr = ring->wptr_gpu_addr; + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_LO), + lower_32_bits(wptr_gpu_addr)); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_HI), + upper_32_bits(wptr_gpu_addr)); + wptr_poll_cntl = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, + mmSDMA0_GFX_RB_WPTR_POLL_CNTL)); + wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl, + SDMA0_GFX_RB_WPTR_POLL_CNTL, + F32_POLL_ENABLE, 1); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL), + wptr_poll_cntl); + + /* set the wb address whether it's enabled or not */ + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_HI), + upper_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFF); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_LO), + lower_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFC); + + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1); + + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE), + ring->gpu_addr >> 8); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE_HI), + ring->gpu_addr >> 40); + + if (!restore) ring->wptr = 0; - /* before programing wptr to a less value, need set minor_ptr_update first */ - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 1); + /* before programing wptr to a less value, need set minor_ptr_update first */ + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 1); - if (!amdgpu_sriov_vf(adev)) { /* only bare-metal use register write for wptr */ - WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), - lower_32_bits(ring->wptr << 2)); - WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), - upper_32_bits(ring->wptr << 2)); - } + if (!amdgpu_sriov_vf(adev)) { /* only bare-metal use register write for wptr */ + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), + lower_32_bits(ring->wptr << 2)); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), + upper_32_bits(ring->wptr << 2)); + } - doorbell = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL)); - doorbell_offset = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, - mmSDMA0_GFX_DOORBELL_OFFSET)); + doorbell = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL)); + doorbell_offset = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, + mmSDMA0_GFX_DOORBELL_OFFSET)); - if (ring->use_doorbell) { - doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 1); - doorbell_offset = REG_SET_FIELD(doorbell_offset, SDMA0_GFX_DOORBELL_OFFSET, - OFFSET, ring->doorbell_index); - } else { - doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 0); - } - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL), doorbell); - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET), - doorbell_offset); + if (ring->use_doorbell) { + doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 1); + doorbell_offset = REG_SET_FIELD(doorbell_offset, SDMA0_GFX_DOORBELL_OFFSET, + OFFSET, ring->doorbell_index); + } else { + doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 0); + } + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL), doorbell); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET), + doorbell_offset); - adev->nbio.funcs->sdma_doorbell_range(adev, i, ring->use_doorbell, - ring->doorbell_index, 20); + adev->nbio.funcs->sdma_doorbell_range(adev, i, ring->use_doorbell, + ring->doorbell_index, 20); - if (amdgpu_sriov_vf(adev)) - sdma_v5_0_ring_set_wptr(ring); + if (amdgpu_sriov_vf(adev)) + sdma_v5_0_ring_set_wptr(ring); - /* set minor_ptr_update to 0 after wptr programed */ - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 0); + /* set minor_ptr_update to 0 after wptr programed */ + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 0); - if (!amdgpu_sriov_vf(adev)) { - /* set utc l1 enable flag always to 1 */ - temp = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1); - - /* enable MCBP */ - temp = REG_SET_FIELD(temp, SDMA0_CNTL, MIDCMD_PREEMPT_ENABLE, 1); - WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_CNTL), temp); - - /* Set up RESP_MODE to non-copy addresses */ - temp = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, RESP_MODE, 3); - temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, REDO_DELAY, 9); - WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL), temp); - - /* program default cache read and write policy */ - temp = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE)); - /* clean read policy and write policy bits */ - temp &= 0xFF0FFF; - temp |= ((CACHE_READ_POLICY_L2__DEFAULT << 12) | (CACHE_WRITE_POLICY_L2__DEFAULT << 14)); - WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE), temp); - } + if (!amdgpu_sriov_vf(adev)) { + /* set utc l1 enable flag always to 1 */ + temp = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1); + + /* enable MCBP */ + temp = REG_SET_FIELD(temp, SDMA0_CNTL, MIDCMD_PREEMPT_ENABLE, 1); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_CNTL), temp); + + /* Set up RESP_MODE to non-copy addresses */ + temp = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, RESP_MODE, 3); + temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, REDO_DELAY, 9); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL), temp); + + /* program default cache read and write policy */ + temp = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE)); + /* clean read policy and write policy bits */ + temp &= 0xFF0FFF; + temp |= ((CACHE_READ_POLICY_L2__DEFAULT << 12) | (CACHE_WRITE_POLICY_L2__DEFAULT << 14)); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE), temp); + } - if (!amdgpu_sriov_vf(adev)) { - /* unhalt engine */ - temp = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0); - WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), temp); - } + if (!amdgpu_sriov_vf(adev)) { + /* unhalt engine */ + temp = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), temp); + } - /* enable DMA RB */ - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 1); - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); + /* enable DMA RB */ + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 1); + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); - ib_cntl = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL)); - ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 1); + ib_cntl = RREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL)); + ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 1); #ifdef __BIG_ENDIAN - ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_SWAP_ENABLE, 1); + ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_SWAP_ENABLE, 1); #endif - /* enable DMA IBs */ - WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl); + /* enable DMA IBs */ + WREG32_SOC15_IP(GC, sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl); - if (amdgpu_sriov_vf(adev)) { /* bare-metal sequence doesn't need below to lines */ - sdma_v5_0_ctx_switch_enable(adev, true); - sdma_v5_0_enable(adev, true); - } + if (amdgpu_sriov_vf(adev)) { /* bare-metal sequence doesn't need below to lines */ + sdma_v5_0_ctx_switch_enable(adev, true); + sdma_v5_0_enable(adev, true); + } + + return amdgpu_ring_test_helper(ring); +} + +/** + * sdma_v5_0_gfx_resume - setup and start the async dma engines + * + * @adev: amdgpu_device pointer + * + * Set up the gfx DMA ring buffers and enable them (NAVI10). + * Returns 0 for success, error for failure. + */ +static int sdma_v5_0_gfx_resume(struct amdgpu_device *adev) +{ + int i, r; - r = amdgpu_ring_test_helper(ring); + for (i = 0; i < adev->sdma.num_instances; i++) { + r = sdma_v5_0_gfx_resume_instance(adev, i, false); if (r) return r; } @@ -1366,9 +1389,9 @@ static void sdma_v5_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring, amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); } -static int sdma_v5_0_early_init(void *handle) +static int sdma_v5_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = sdma_v5_0_init_microcode(adev); @@ -1385,11 +1408,11 @@ static int sdma_v5_0_early_init(void *handle) } -static int sdma_v5_0_sw_init(void *handle) +static int sdma_v5_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_5_0); uint32_t *ptr; @@ -1429,6 +1452,19 @@ static int sdma_v5_0_sw_init(void *handle) return r; } + adev->sdma.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring); + switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) { + case IP_VERSION(5, 0, 0): + case IP_VERSION(5, 0, 2): + case IP_VERSION(5, 0, 5): + if (adev->sdma.instance[0].fw_version >= 35) + adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + break; + default: + break; + } + /* Allocate memory for SDMA IP Dump buffer */ ptr = kcalloc(adev->sdma.num_instances * reg_count, sizeof(uint32_t), GFP_KERNEL); if (ptr) @@ -1436,17 +1472,22 @@ static int sdma_v5_0_sw_init(void *handle) else DRM_ERROR("Failed to allocated memory for SDMA IP Dump\n"); + r = amdgpu_sdma_sysfs_reset_mask_init(adev); + if (r) + return r; + return r; } -static int sdma_v5_0_sw_fini(void *handle) +static int sdma_v5_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) amdgpu_ring_fini(&adev->sdma.instance[i].ring); + amdgpu_sdma_sysfs_reset_mask_fini(adev); amdgpu_sdma_destroy_inst_ctx(adev, false); kfree(adev->sdma.ip_dump); @@ -1454,10 +1495,10 @@ static int sdma_v5_0_sw_fini(void *handle) return 0; } -static int sdma_v5_0_hw_init(void *handle) +static int sdma_v5_0_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; sdma_v5_0_init_golden_registers(adev); @@ -1466,9 +1507,9 @@ static int sdma_v5_0_hw_init(void *handle) return r; } -static int sdma_v5_0_hw_fini(void *handle) +static int sdma_v5_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) return 0; @@ -1479,18 +1520,14 @@ static int sdma_v5_0_hw_fini(void *handle) return 0; } -static int sdma_v5_0_suspend(void *handle) +static int sdma_v5_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v5_0_hw_fini(adev); + return sdma_v5_0_hw_fini(ip_block); } -static int sdma_v5_0_resume(void *handle) +static int sdma_v5_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v5_0_hw_init(adev); + return sdma_v5_0_hw_init(ip_block); } static bool sdma_v5_0_is_idle(void *handle) @@ -1508,11 +1545,11 @@ static bool sdma_v5_0_is_idle(void *handle) return true; } -static int sdma_v5_0_wait_for_idle(void *handle) +static int sdma_v5_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 sdma0, sdma1; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { sdma0 = RREG32(sdma_v5_0_get_reg_offset(adev, 0, mmSDMA0_STATUS_REG)); @@ -1525,13 +1562,100 @@ static int sdma_v5_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int sdma_v5_0_soft_reset(void *handle) +static int sdma_v5_0_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ return 0; } +static int sdma_v5_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid) +{ + struct amdgpu_device *adev = ring->adev; + int i, j, r; + u32 rb_cntl, ib_cntl, f32_cntl, freeze, cntl, preempt, soft_reset, stat1_reg; + + if (amdgpu_sriov_vf(adev)) + return -EINVAL; + + for (i = 0; i < adev->sdma.num_instances; i++) { + if (ring == &adev->sdma.instance[i].ring) + break; + } + + if (i == adev->sdma.num_instances) { + DRM_ERROR("sdma instance not found\n"); + return -EINVAL; + } + + amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + + /* stop queue */ + ib_cntl = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL)); + ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl); + + rb_cntl = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL)); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 0); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); + + /* engine stop SDMA1_F32_CNTL.HALT to 1 and SDMAx_FREEZE freeze bit to 1 */ + freeze = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_FREEZE)); + freeze = REG_SET_FIELD(freeze, SDMA0_FREEZE, FREEZE, 1); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_FREEZE), freeze); + + for (j = 0; j < adev->usec_timeout; j++) { + freeze = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_FREEZE)); + if (REG_GET_FIELD(freeze, SDMA0_FREEZE, FROZEN) & 1) + break; + udelay(1); + } + + /* check sdma copy engine all idle if frozen not received*/ + if (j == adev->usec_timeout) { + stat1_reg = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_STATUS1_REG)); + if ((stat1_reg & 0x3FF) != 0x3FF) { + DRM_ERROR("cannot soft reset as sdma not idle\n"); + r = -ETIMEDOUT; + goto err0; + } + } + + f32_cntl = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, 1); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), f32_cntl); + + cntl = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_CNTL)); + cntl = REG_SET_FIELD(cntl, SDMA0_CNTL, UTC_L1_ENABLE, 0); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_CNTL), cntl); + + /* soft reset SDMA_GFX_PREEMPT.IB_PREEMPT = 0 mmGRBM_SOFT_RESET.SOFT_RESET_SDMA0/1 = 1 */ + preempt = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_PREEMPT)); + preempt = REG_SET_FIELD(preempt, SDMA0_GFX_PREEMPT, IB_PREEMPT, 0); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_GFX_PREEMPT), preempt); + + soft_reset = RREG32_SOC15(GC, 0, mmGRBM_SOFT_RESET); + soft_reset |= 1 << GRBM_SOFT_RESET__SOFT_RESET_SDMA0__SHIFT << i; + + WREG32_SOC15(GC, 0, mmGRBM_SOFT_RESET, soft_reset); + + udelay(50); + + soft_reset &= ~(1 << GRBM_SOFT_RESET__SOFT_RESET_SDMA0__SHIFT << i); + WREG32_SOC15(GC, 0, mmGRBM_SOFT_RESET, soft_reset); + + /* unfreeze*/ + freeze = RREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_FREEZE)); + freeze = REG_SET_FIELD(freeze, SDMA0_FREEZE, FREEZE, 0); + WREG32(sdma_v5_0_get_reg_offset(adev, i, mmSDMA0_FREEZE), freeze); + + r = sdma_v5_0_gfx_resume_instance(adev, i, true); + +err0: + amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + return r; +} + static int sdma_v5_0_ring_preempt_ib(struct amdgpu_ring *ring) { int i, r = 0; @@ -1778,9 +1902,9 @@ static void sdma_v5_0_get_clockgating_state(void *handle, u64 *flags) *flags |= AMD_CG_SUPPORT_SDMA_LS; } -static void sdma_v5_0_print_ip_state(void *handle, struct drm_printer *p) +static void sdma_v5_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_5_0); uint32_t instance_offset; @@ -1799,9 +1923,9 @@ static void sdma_v5_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void sdma_v5_0_dump_ip_state(void *handle) +static void sdma_v5_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t instance_offset; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_5_0); @@ -1823,7 +1947,6 @@ static void sdma_v5_0_dump_ip_state(void *handle) static const struct amd_ip_funcs sdma_v5_0_ip_funcs = { .name = "sdma_v5_0", .early_init = sdma_v5_0_early_init, - .late_init = NULL, .sw_init = sdma_v5_0_sw_init, .sw_fini = sdma_v5_0_sw_fini, .hw_init = sdma_v5_0_hw_init, @@ -1874,6 +1997,7 @@ static const struct amdgpu_ring_funcs sdma_v5_0_ring_funcs = { .emit_reg_write_reg_wait = sdma_v5_0_ring_emit_reg_write_reg_wait, .init_cond_exec = sdma_v5_0_ring_init_cond_exec, .preempt_ib = sdma_v5_0_ring_preempt_ib, + .reset = sdma_v5_0_reset_queue, }; static void sdma_v5_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c index bc9b240a3488e6..ba5160399ab2a0 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c @@ -522,14 +522,17 @@ static void sdma_v5_2_enable(struct amdgpu_device *adev, bool enable) } /** - * sdma_v5_2_gfx_resume - setup and start the async dma engines + * sdma_v5_2_gfx_resume_instance - start/restart a certain sdma engine * * @adev: amdgpu_device pointer + * @i: instance + * @restore: used to restore wptr when restart * - * Set up the gfx DMA ring buffers and enable them. - * Returns 0 for success, error for failure. + * Set up the gfx DMA ring buffers and enable them. On restart, we will restore wptr and rptr. + * Return 0 for success. */ -static int sdma_v5_2_gfx_resume(struct amdgpu_device *adev) + +static int sdma_v5_2_gfx_resume_instance(struct amdgpu_device *adev, int i, bool restore) { struct amdgpu_ring *ring; u32 rb_cntl, ib_cntl; @@ -539,139 +542,161 @@ static int sdma_v5_2_gfx_resume(struct amdgpu_device *adev) u32 temp; u32 wptr_poll_cntl; u64 wptr_gpu_addr; - int i, r; - for (i = 0; i < adev->sdma.num_instances; i++) { - ring = &adev->sdma.instance[i].ring; + ring = &adev->sdma.instance[i].ring; - if (!amdgpu_sriov_vf(adev)) - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0); + if (!amdgpu_sriov_vf(adev)) + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0); - /* Set ring buffer size in dwords */ - rb_bufsz = order_base_2(ring->ring_size / 4); - rb_cntl = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL)); - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SIZE, rb_bufsz); + /* Set ring buffer size in dwords */ + rb_bufsz = order_base_2(ring->ring_size / 4); + rb_cntl = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL)); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SIZE, rb_bufsz); #ifdef __BIG_ENDIAN - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SWAP_ENABLE, 1); - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, - RPTR_WRITEBACK_SWAP_ENABLE, 1); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_SWAP_ENABLE, 1); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, + RPTR_WRITEBACK_SWAP_ENABLE, 1); #endif - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); - - /* Initialize the ring buffer's read and write pointers */ + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); + + /* Initialize the ring buffer's read and write pointers */ + if (restore) { + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR), lower_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_HI), upper_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); + } else { WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR), 0); WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_HI), 0); WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), 0); WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), 0); + } - /* setup the wptr shadow polling */ - wptr_gpu_addr = ring->wptr_gpu_addr; - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_LO), - lower_32_bits(wptr_gpu_addr)); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_HI), - upper_32_bits(wptr_gpu_addr)); - wptr_poll_cntl = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, - mmSDMA0_GFX_RB_WPTR_POLL_CNTL)); - wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl, - SDMA0_GFX_RB_WPTR_POLL_CNTL, - F32_POLL_ENABLE, 1); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL), - wptr_poll_cntl); - - /* set the wb address whether it's enabled or not */ - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_HI), - upper_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFF); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_LO), - lower_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFC); - - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1); - - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE), ring->gpu_addr >> 8); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE_HI), ring->gpu_addr >> 40); - + /* setup the wptr shadow polling */ + wptr_gpu_addr = ring->wptr_gpu_addr; + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_LO), + lower_32_bits(wptr_gpu_addr)); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_ADDR_HI), + upper_32_bits(wptr_gpu_addr)); + wptr_poll_cntl = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, + mmSDMA0_GFX_RB_WPTR_POLL_CNTL)); + wptr_poll_cntl = REG_SET_FIELD(wptr_poll_cntl, + SDMA0_GFX_RB_WPTR_POLL_CNTL, + F32_POLL_ENABLE, 1); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_POLL_CNTL), + wptr_poll_cntl); + + /* set the wb address whether it's enabled or not */ + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_HI), + upper_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFF); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_RPTR_ADDR_LO), + lower_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFC); + + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1); + + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE), ring->gpu_addr >> 8); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_BASE_HI), ring->gpu_addr >> 40); + + if (!restore) ring->wptr = 0; - /* before programing wptr to a less value, need set minor_ptr_update first */ - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 1); + /* before programing wptr to a less value, need set minor_ptr_update first */ + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 1); - if (!amdgpu_sriov_vf(adev)) { /* only bare-metal use register write for wptr */ - WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2)); - WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); - } + if (!amdgpu_sriov_vf(adev)) { /* only bare-metal use register write for wptr */ + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR), lower_32_bits(ring->wptr << 2)); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); + } - doorbell = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL)); - doorbell_offset = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET)); + doorbell = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL)); + doorbell_offset = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET)); - if (ring->use_doorbell) { - doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 1); - doorbell_offset = REG_SET_FIELD(doorbell_offset, SDMA0_GFX_DOORBELL_OFFSET, - OFFSET, ring->doorbell_index); - } else { - doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 0); - } - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL), doorbell); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET), doorbell_offset); + if (ring->use_doorbell) { + doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 1); + doorbell_offset = REG_SET_FIELD(doorbell_offset, SDMA0_GFX_DOORBELL_OFFSET, + OFFSET, ring->doorbell_index); + } else { + doorbell = REG_SET_FIELD(doorbell, SDMA0_GFX_DOORBELL, ENABLE, 0); + } + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL), doorbell); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_DOORBELL_OFFSET), doorbell_offset); - adev->nbio.funcs->sdma_doorbell_range(adev, i, ring->use_doorbell, - ring->doorbell_index, - adev->doorbell_index.sdma_doorbell_range); + adev->nbio.funcs->sdma_doorbell_range(adev, i, ring->use_doorbell, + ring->doorbell_index, + adev->doorbell_index.sdma_doorbell_range); - if (amdgpu_sriov_vf(adev)) - sdma_v5_2_ring_set_wptr(ring); + if (amdgpu_sriov_vf(adev)) + sdma_v5_2_ring_set_wptr(ring); - /* set minor_ptr_update to 0 after wptr programed */ + /* set minor_ptr_update to 0 after wptr programed */ - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 0); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_MINOR_PTR_UPDATE), 0); - /* SRIOV VF has no control of any of registers below */ - if (!amdgpu_sriov_vf(adev)) { - /* set utc l1 enable flag always to 1 */ - temp = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1); - - /* enable MCBP */ - temp = REG_SET_FIELD(temp, SDMA0_CNTL, MIDCMD_PREEMPT_ENABLE, 1); - WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL), temp); - - /* Set up RESP_MODE to non-copy addresses */ - temp = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, RESP_MODE, 3); - temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, REDO_DELAY, 9); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL), temp); - - /* program default cache read and write policy */ - temp = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE)); - /* clean read policy and write policy bits */ - temp &= 0xFF0FFF; - temp |= ((CACHE_READ_POLICY_L2__DEFAULT << 12) | - (CACHE_WRITE_POLICY_L2__DEFAULT << 14) | - SDMA0_UTCL1_PAGE__LLC_NOALLOC_MASK); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE), temp); - - /* unhalt engine */ - temp = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0); - WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), temp); - } + /* SRIOV VF has no control of any of registers below */ + if (!amdgpu_sriov_vf(adev)) { + /* set utc l1 enable flag always to 1 */ + temp = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_CNTL, UTC_L1_ENABLE, 1); + + /* enable MCBP */ + temp = REG_SET_FIELD(temp, SDMA0_CNTL, MIDCMD_PREEMPT_ENABLE, 1); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL), temp); + + /* Set up RESP_MODE to non-copy addresses */ + temp = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, RESP_MODE, 3); + temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, REDO_DELAY, 9); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_CNTL), temp); + + /* program default cache read and write policy */ + temp = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE)); + /* clean read policy and write policy bits */ + temp &= 0xFF0FFF; + temp |= ((CACHE_READ_POLICY_L2__DEFAULT << 12) | + (CACHE_WRITE_POLICY_L2__DEFAULT << 14) | + SDMA0_UTCL1_PAGE__LLC_NOALLOC_MASK); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_UTCL1_PAGE), temp); + + /* unhalt engine */ + temp = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), temp); + } - /* enable DMA RB */ - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 1); - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); + /* enable DMA RB */ + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 1); + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); - ib_cntl = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL)); - ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 1); + ib_cntl = RREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL)); + ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 1); #ifdef __BIG_ENDIAN - ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_SWAP_ENABLE, 1); + ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_SWAP_ENABLE, 1); #endif - /* enable DMA IBs */ - WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl); + /* enable DMA IBs */ + WREG32_SOC15_IP(GC, sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl); - if (amdgpu_sriov_vf(adev)) { /* bare-metal sequence doesn't need below to lines */ - sdma_v5_2_ctx_switch_enable(adev, true); - sdma_v5_2_enable(adev, true); - } + if (amdgpu_sriov_vf(adev)) { /* bare-metal sequence doesn't need below to lines */ + sdma_v5_2_ctx_switch_enable(adev, true); + sdma_v5_2_enable(adev, true); + } + + return amdgpu_ring_test_helper(ring); +} - r = amdgpu_ring_test_helper(ring); +/** + * sdma_v5_2_gfx_resume - setup and start the async dma engines + * + * @adev: amdgpu_device pointer + * + * Set up the gfx DMA ring buffers and enable them. + * Returns 0 for success, error for failure. + */ +static int sdma_v5_2_gfx_resume(struct amdgpu_device *adev) +{ + int i, r; + + for (i = 0; i < adev->sdma.num_instances; i++) { + r = sdma_v5_2_gfx_resume_instance(adev, i, false); if (r) return r; } @@ -736,9 +761,9 @@ static int sdma_v5_2_load_microcode(struct amdgpu_device *adev) return 0; } -static int sdma_v5_2_soft_reset(void *handle) +static int sdma_v5_2_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 grbm_soft_reset; u32 tmp; int i; @@ -778,6 +803,7 @@ static int sdma_v5_2_soft_reset(void *handle) static int sdma_v5_2_start(struct amdgpu_device *adev) { int r = 0; + struct amdgpu_ip_block *ip_block; if (amdgpu_sriov_vf(adev)) { sdma_v5_2_ctx_switch_enable(adev, false); @@ -798,7 +824,11 @@ static int sdma_v5_2_start(struct amdgpu_device *adev) msleep(1000); } - sdma_v5_2_soft_reset(adev); + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_SDMA); + if (!ip_block) + return -EINVAL; + + sdma_v5_2_soft_reset(ip_block); /* unhalt the MEs */ sdma_v5_2_enable(adev, true); /* enable sdma ring preemption */ @@ -1180,7 +1210,28 @@ static void sdma_v5_2_ring_emit_pipeline_sync(struct amdgpu_ring *ring) static void sdma_v5_2_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vmid, uint64_t pd_addr) { - amdgpu_gmc_emit_flush_gpu_tlb(ring, vmid, pd_addr); + struct amdgpu_vmhub *hub = &ring->adev->vmhub[ring->vm_hub]; + uint32_t req = hub->vmhub_funcs->get_invalidate_req(vmid, 0); + + /* Update the PD address for this VMID. */ + amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_lo32 + + (hub->ctx_addr_distance * vmid), + lower_32_bits(pd_addr)); + amdgpu_ring_emit_wreg(ring, hub->ctx0_ptb_addr_hi32 + + (hub->ctx_addr_distance * vmid), + upper_32_bits(pd_addr)); + + /* Trigger invalidation. */ + amdgpu_ring_write(ring, + SDMA_PKT_VM_INVALIDATION_HEADER_OP(SDMA_OP_POLL_REGMEM) | + SDMA_PKT_VM_INVALIDATION_HEADER_SUB_OP(SDMA_SUBOP_VM_INVALIDATION) | + SDMA_PKT_VM_INVALIDATION_HEADER_GFX_ENG_ID(ring->vm_inv_eng) | + SDMA_PKT_VM_INVALIDATION_HEADER_MM_ENG_ID(0x1f)); + amdgpu_ring_write(ring, req); + amdgpu_ring_write(ring, 0xFFFFFFFF); + amdgpu_ring_write(ring, + SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_INVALIDATEACK(1 << vmid) | + SDMA_PKT_VM_INVALIDATION_ADDRESSRANGEHI_ADDRESSRANGEHI(0x1F)); } static void sdma_v5_2_ring_emit_wreg(struct amdgpu_ring *ring, @@ -1216,9 +1267,9 @@ static void sdma_v5_2_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring, amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); } -static int sdma_v5_2_early_init(void *handle) +static int sdma_v5_2_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_sdma_init_microcode(adev, 0, true); @@ -1268,11 +1319,11 @@ static unsigned sdma_v5_2_seq_to_trap_id(int seq_num) return -EINVAL; } -static int sdma_v5_2_sw_init(void *handle) +static int sdma_v5_2_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_5_2); uint32_t *ptr; @@ -1306,6 +1357,24 @@ static int sdma_v5_2_sw_init(void *handle) return r; } + adev->sdma.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring); + switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) { + case IP_VERSION(5, 2, 0): + case IP_VERSION(5, 2, 2): + case IP_VERSION(5, 2, 3): + case IP_VERSION(5, 2, 4): + if (adev->sdma.instance[0].fw_version >= 76) + adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + break; + case IP_VERSION(5, 2, 5): + if (adev->sdma.instance[0].fw_version >= 34) + adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + break; + default: + break; + } + /* Allocate memory for SDMA IP Dump buffer */ ptr = kcalloc(adev->sdma.num_instances * reg_count, sizeof(uint32_t), GFP_KERNEL); if (ptr) @@ -1313,17 +1382,22 @@ static int sdma_v5_2_sw_init(void *handle) else DRM_ERROR("Failed to allocated memory for SDMA IP Dump\n"); + r = amdgpu_sdma_sysfs_reset_mask_init(adev); + if (r) + return r; + return r; } -static int sdma_v5_2_sw_fini(void *handle) +static int sdma_v5_2_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) amdgpu_ring_fini(&adev->sdma.instance[i].ring); + amdgpu_sdma_sysfs_reset_mask_fini(adev); amdgpu_sdma_destroy_inst_ctx(adev, true); kfree(adev->sdma.ip_dump); @@ -1331,16 +1405,16 @@ static int sdma_v5_2_sw_fini(void *handle) return 0; } -static int sdma_v5_2_hw_init(void *handle) +static int sdma_v5_2_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return sdma_v5_2_start(adev); } -static int sdma_v5_2_hw_fini(void *handle) +static int sdma_v5_2_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) return 0; @@ -1351,18 +1425,14 @@ static int sdma_v5_2_hw_fini(void *handle) return 0; } -static int sdma_v5_2_suspend(void *handle) +static int sdma_v5_2_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v5_2_hw_fini(adev); + return sdma_v5_2_hw_fini(ip_block); } -static int sdma_v5_2_resume(void *handle) +static int sdma_v5_2_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v5_2_hw_init(adev); + return sdma_v5_2_hw_init(ip_block); } static bool sdma_v5_2_is_idle(void *handle) @@ -1380,11 +1450,11 @@ static bool sdma_v5_2_is_idle(void *handle) return true; } -static int sdma_v5_2_wait_for_idle(void *handle) +static int sdma_v5_2_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 sdma0, sdma1, sdma2, sdma3; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { sdma0 = RREG32(sdma_v5_2_get_reg_offset(adev, 0, mmSDMA0_STATUS_REG)); @@ -1399,6 +1469,96 @@ static int sdma_v5_2_wait_for_idle(void *handle) return -ETIMEDOUT; } +static int sdma_v5_2_reset_queue(struct amdgpu_ring *ring, unsigned int vmid) +{ + struct amdgpu_device *adev = ring->adev; + int i, j, r; + u32 rb_cntl, ib_cntl, f32_cntl, freeze, cntl, preempt, soft_reset, stat1_reg; + + if (amdgpu_sriov_vf(adev)) + return -EINVAL; + + for (i = 0; i < adev->sdma.num_instances; i++) { + if (ring == &adev->sdma.instance[i].ring) + break; + } + + if (i == adev->sdma.num_instances) { + DRM_ERROR("sdma instance not found\n"); + return -EINVAL; + } + + amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + + /* stop queue */ + ib_cntl = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL)); + ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_GFX_IB_CNTL, IB_ENABLE, 0); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_IB_CNTL), ib_cntl); + + rb_cntl = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL)); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_GFX_RB_CNTL, RB_ENABLE, 0); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_RB_CNTL), rb_cntl); + + /*engine stop SDMA1_F32_CNTL.HALT to 1 and SDMAx_FREEZE freeze bit to 1 */ + freeze = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_FREEZE)); + freeze = REG_SET_FIELD(freeze, SDMA0_FREEZE, FREEZE, 1); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_FREEZE), freeze); + + for (j = 0; j < adev->usec_timeout; j++) { + freeze = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_FREEZE)); + + if (REG_GET_FIELD(freeze, SDMA0_FREEZE, FROZEN) & 1) + break; + udelay(1); + } + + + if (j == adev->usec_timeout) { + stat1_reg = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_STATUS1_REG)); + if ((stat1_reg & 0x3FF) != 0x3FF) { + DRM_ERROR("cannot soft reset as sdma not idle\n"); + r = -ETIMEDOUT; + goto err0; + } + } + + f32_cntl = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL)); + f32_cntl = REG_SET_FIELD(f32_cntl, SDMA0_F32_CNTL, HALT, 1); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_F32_CNTL), f32_cntl); + + cntl = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL)); + cntl = REG_SET_FIELD(cntl, SDMA0_CNTL, UTC_L1_ENABLE, 0); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_CNTL), cntl); + + /* soft reset SDMA_GFX_PREEMPT.IB_PREEMPT = 0 mmGRBM_SOFT_RESET.SOFT_RESET_SDMA0/1 = 1 */ + preempt = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_PREEMPT)); + preempt = REG_SET_FIELD(preempt, SDMA0_GFX_PREEMPT, IB_PREEMPT, 0); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_GFX_PREEMPT), preempt); + + soft_reset = RREG32_SOC15(GC, 0, mmGRBM_SOFT_RESET); + soft_reset |= 1 << GRBM_SOFT_RESET__SOFT_RESET_SDMA0__SHIFT << i; + + + WREG32_SOC15(GC, 0, mmGRBM_SOFT_RESET, soft_reset); + + udelay(50); + + soft_reset &= ~(1 << GRBM_SOFT_RESET__SOFT_RESET_SDMA0__SHIFT << i); + + WREG32_SOC15(GC, 0, mmGRBM_SOFT_RESET, soft_reset); + + /* unfreeze and unhalt */ + freeze = RREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_FREEZE)); + freeze = REG_SET_FIELD(freeze, SDMA0_FREEZE, FREEZE, 0); + WREG32(sdma_v5_2_get_reg_offset(adev, i, mmSDMA0_FREEZE), freeze); + + r = sdma_v5_2_gfx_resume_instance(adev, i, true); + +err0: + amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + return r; +} + static int sdma_v5_2_ring_preempt_ib(struct amdgpu_ring *ring) { int i, r = 0; @@ -1736,9 +1896,9 @@ static void sdma_v5_2_ring_end_use(struct amdgpu_ring *ring) amdgpu_gfx_off_ctrl(adev, true); } -static void sdma_v5_2_print_ip_state(void *handle, struct drm_printer *p) +static void sdma_v5_2_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_5_2); uint32_t instance_offset; @@ -1757,9 +1917,9 @@ static void sdma_v5_2_print_ip_state(void *handle, struct drm_printer *p) } } -static void sdma_v5_2_dump_ip_state(void *handle) +static void sdma_v5_2_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t instance_offset; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_5_2); @@ -1781,7 +1941,6 @@ static void sdma_v5_2_dump_ip_state(void *handle) static const struct amd_ip_funcs sdma_v5_2_ip_funcs = { .name = "sdma_v5_2", .early_init = sdma_v5_2_early_init, - .late_init = NULL, .sw_init = sdma_v5_2_sw_init, .sw_fini = sdma_v5_2_sw_fini, .hw_init = sdma_v5_2_hw_init, @@ -1834,6 +1993,7 @@ static const struct amdgpu_ring_funcs sdma_v5_2_ring_funcs = { .emit_reg_write_reg_wait = sdma_v5_2_ring_emit_reg_write_reg_wait, .init_cond_exec = sdma_v5_2_ring_init_cond_exec, .preempt_ib = sdma_v5_2_ring_preempt_ib, + .reset = sdma_v5_2_reset_queue, }; static void sdma_v5_2_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index 208a1fa9d4e7f2..d46128b0ec9202 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -469,14 +469,16 @@ static void sdma_v6_0_enable(struct amdgpu_device *adev, bool enable) } /** - * sdma_v6_0_gfx_resume - setup and start the async dma engines + * sdma_v6_0_gfx_resume_instance - start/restart a certain sdma engine * * @adev: amdgpu_device pointer + * @i: instance + * @restore: used to restore wptr when restart * - * Set up the gfx DMA ring buffers and enable them. - * Returns 0 for success, error for failure. + * Set up the gfx DMA ring buffers and enable them. On restart, we will restore wptr and rptr. + * Return 0 for success. */ -static int sdma_v6_0_gfx_resume(struct amdgpu_device *adev) +static int sdma_v6_0_gfx_resume_instance(struct amdgpu_device *adev, int i, bool restore) { struct amdgpu_ring *ring; u32 rb_cntl, ib_cntl; @@ -485,132 +487,152 @@ static int sdma_v6_0_gfx_resume(struct amdgpu_device *adev) u32 doorbell_offset; u32 temp; u64 wptr_gpu_addr; - int i, r; - - for (i = 0; i < adev->sdma.num_instances; i++) { - ring = &adev->sdma.instance[i].ring; - if (!amdgpu_sriov_vf(adev)) - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0); + ring = &adev->sdma.instance[i].ring; + if (!amdgpu_sriov_vf(adev)) + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_SEM_WAIT_FAIL_TIMER_CNTL), 0); - /* Set ring buffer size in dwords */ - rb_bufsz = order_base_2(ring->ring_size / 4); - rb_cntl = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_CNTL)); - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RB_SIZE, rb_bufsz); + /* Set ring buffer size in dwords */ + rb_bufsz = order_base_2(ring->ring_size / 4); + rb_cntl = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_CNTL)); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RB_SIZE, rb_bufsz); #ifdef __BIG_ENDIAN - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RB_SWAP_ENABLE, 1); - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, - RPTR_WRITEBACK_SWAP_ENABLE, 1); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RB_SWAP_ENABLE, 1); + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, + RPTR_WRITEBACK_SWAP_ENABLE, 1); #endif - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RB_PRIV, 1); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_CNTL), rb_cntl); - - /* Initialize the ring buffer's read and write pointers */ + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RB_PRIV, 1); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_CNTL), rb_cntl); + + /* Initialize the ring buffer's read and write pointers */ + if (restore) { + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_RPTR), lower_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_RPTR_HI), upper_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR), lower_32_bits(ring->wptr << 2)); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR_HI), upper_32_bits(ring->wptr << 2)); + } else { WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_RPTR), 0); WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_RPTR_HI), 0); WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR), 0); WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR_HI), 0); + } + /* setup the wptr shadow polling */ + wptr_gpu_addr = ring->wptr_gpu_addr; + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR_POLL_ADDR_LO), + lower_32_bits(wptr_gpu_addr)); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR_POLL_ADDR_HI), + upper_32_bits(wptr_gpu_addr)); + + /* set the wb address whether it's enabled or not */ + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_RPTR_ADDR_HI), + upper_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFF); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_RPTR_ADDR_LO), + lower_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFC); + + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1); + 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); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_BASE_HI), ring->gpu_addr >> 40); + + if (!restore) + ring->wptr = 0; - /* setup the wptr shadow polling */ - wptr_gpu_addr = ring->wptr_gpu_addr; - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR_POLL_ADDR_LO), - lower_32_bits(wptr_gpu_addr)); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR_POLL_ADDR_HI), - upper_32_bits(wptr_gpu_addr)); - - /* set the wb address whether it's enabled or not */ - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_RPTR_ADDR_HI), - upper_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFF); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_RPTR_ADDR_LO), - lower_32_bits(ring->rptr_gpu_addr) & 0xFFFFFFFC); - - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RPTR_WRITEBACK_ENABLE, 1); - 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); + /* before programing wptr to a less value, need set minor_ptr_update first */ + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_MINOR_PTR_UPDATE), 1); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_BASE), ring->gpu_addr >> 8); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_BASE_HI), ring->gpu_addr >> 40); + if (!amdgpu_sriov_vf(adev)) { /* only bare-metal use register write for wptr */ + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR), lower_32_bits(ring->wptr) << 2); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR_HI), upper_32_bits(ring->wptr) << 2); + } - ring->wptr = 0; + doorbell = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_DOORBELL)); + doorbell_offset = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_DOORBELL_OFFSET)); - /* before programing wptr to a less value, need set minor_ptr_update first */ - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_MINOR_PTR_UPDATE), 1); + if (ring->use_doorbell) { + doorbell = REG_SET_FIELD(doorbell, SDMA0_QUEUE0_DOORBELL, ENABLE, 1); + doorbell_offset = REG_SET_FIELD(doorbell_offset, SDMA0_QUEUE0_DOORBELL_OFFSET, + OFFSET, ring->doorbell_index); + } else { + doorbell = REG_SET_FIELD(doorbell, SDMA0_QUEUE0_DOORBELL, ENABLE, 0); + } + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_DOORBELL), doorbell); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_DOORBELL_OFFSET), doorbell_offset); - if (!amdgpu_sriov_vf(adev)) { /* only bare-metal use register write for wptr */ - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR), lower_32_bits(ring->wptr) << 2); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_WPTR_HI), upper_32_bits(ring->wptr) << 2); - } + if (i == 0) + adev->nbio.funcs->sdma_doorbell_range(adev, i, ring->use_doorbell, + ring->doorbell_index, + adev->doorbell_index.sdma_doorbell_range * adev->sdma.num_instances); - doorbell = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_DOORBELL)); - doorbell_offset = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_DOORBELL_OFFSET)); + if (amdgpu_sriov_vf(adev)) + sdma_v6_0_ring_set_wptr(ring); + + /* set minor_ptr_update to 0 after wptr programed */ + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_MINOR_PTR_UPDATE), 0); + + /* Set up sdma hang watchdog */ + temp = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_WATCHDOG_CNTL)); + /* 100ms per unit */ + temp = REG_SET_FIELD(temp, SDMA0_WATCHDOG_CNTL, QUEUE_HANG_COUNT, + max(adev->usec_timeout/100000, 1)); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_WATCHDOG_CNTL), temp); + + /* Set up RESP_MODE to non-copy addresses */ + temp = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_UTCL1_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, RESP_MODE, 3); + temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, REDO_DELAY, 9); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_UTCL1_CNTL), temp); + + /* program default cache read and write policy */ + temp = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_UTCL1_PAGE)); + /* clean read policy and write policy bits */ + temp &= 0xFF0FFF; + temp |= ((CACHE_READ_POLICY_L2__DEFAULT << 12) | + (CACHE_WRITE_POLICY_L2__DEFAULT << 14) | + SDMA0_UTCL1_PAGE__LLC_NOALLOC_MASK); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_UTCL1_PAGE), temp); - if (ring->use_doorbell) { - doorbell = REG_SET_FIELD(doorbell, SDMA0_QUEUE0_DOORBELL, ENABLE, 1); - doorbell_offset = REG_SET_FIELD(doorbell_offset, SDMA0_QUEUE0_DOORBELL_OFFSET, - OFFSET, ring->doorbell_index); - } else { - doorbell = REG_SET_FIELD(doorbell, SDMA0_QUEUE0_DOORBELL, ENABLE, 0); - } - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_DOORBELL), doorbell); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_DOORBELL_OFFSET), doorbell_offset); - - if (i == 0) - adev->nbio.funcs->sdma_doorbell_range(adev, i, ring->use_doorbell, - ring->doorbell_index, - adev->doorbell_index.sdma_doorbell_range * adev->sdma.num_instances); - - if (amdgpu_sriov_vf(adev)) - sdma_v6_0_ring_set_wptr(ring); - - /* set minor_ptr_update to 0 after wptr programed */ - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_MINOR_PTR_UPDATE), 0); - - /* Set up sdma hang watchdog */ - temp = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_WATCHDOG_CNTL)); - /* 100ms per unit */ - temp = REG_SET_FIELD(temp, SDMA0_WATCHDOG_CNTL, QUEUE_HANG_COUNT, - max(adev->usec_timeout/100000, 1)); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_WATCHDOG_CNTL), temp); - - /* Set up RESP_MODE to non-copy addresses */ - temp = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_UTCL1_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, RESP_MODE, 3); - temp = REG_SET_FIELD(temp, SDMA0_UTCL1_CNTL, REDO_DELAY, 9); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_UTCL1_CNTL), temp); - - /* program default cache read and write policy */ - temp = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_UTCL1_PAGE)); - /* clean read policy and write policy bits */ - temp &= 0xFF0FFF; - temp |= ((CACHE_READ_POLICY_L2__DEFAULT << 12) | - (CACHE_WRITE_POLICY_L2__DEFAULT << 14) | - SDMA0_UTCL1_PAGE__LLC_NOALLOC_MASK); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_UTCL1_PAGE), temp); - - if (!amdgpu_sriov_vf(adev)) { - /* unhalt engine */ - temp = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_F32_CNTL)); - temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0); - temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, TH1_RESET, 0); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_F32_CNTL), temp); - } + if (!amdgpu_sriov_vf(adev)) { + /* unhalt engine */ + temp = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_F32_CNTL)); + temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, HALT, 0); + temp = REG_SET_FIELD(temp, SDMA0_F32_CNTL, TH1_RESET, 0); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_F32_CNTL), temp); + } - /* enable DMA RB */ - rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RB_ENABLE, 1); - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_CNTL), rb_cntl); + /* enable DMA RB */ + rb_cntl = REG_SET_FIELD(rb_cntl, SDMA0_QUEUE0_RB_CNTL, RB_ENABLE, 1); + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_RB_CNTL), rb_cntl); - ib_cntl = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_IB_CNTL)); - ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_QUEUE0_IB_CNTL, IB_ENABLE, 1); + ib_cntl = RREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_IB_CNTL)); + ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_QUEUE0_IB_CNTL, IB_ENABLE, 1); #ifdef __BIG_ENDIAN - ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_QUEUE0_IB_CNTL, IB_SWAP_ENABLE, 1); + ib_cntl = REG_SET_FIELD(ib_cntl, SDMA0_QUEUE0_IB_CNTL, IB_SWAP_ENABLE, 1); #endif - /* enable DMA IBs */ - WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_IB_CNTL), ib_cntl); + /* enable DMA IBs */ + WREG32_SOC15_IP(GC, sdma_v6_0_get_reg_offset(adev, i, regSDMA0_QUEUE0_IB_CNTL), ib_cntl); + + if (amdgpu_sriov_vf(adev)) + sdma_v6_0_enable(adev, true); + + return amdgpu_ring_test_helper(ring); +} - if (amdgpu_sriov_vf(adev)) - sdma_v6_0_enable(adev, true); +/** + * sdma_v6_0_gfx_resume - setup and start the async dma engines + * + * @adev: amdgpu_device pointer + * + * Set up the gfx DMA ring buffers and enable them. + * Returns 0 for success, error for failure. + */ +static int sdma_v6_0_gfx_resume(struct amdgpu_device *adev) +{ + int i, r; - r = amdgpu_ring_test_helper(ring); + for (i = 0; i < adev->sdma.num_instances; i++) { + r = sdma_v6_0_gfx_resume_instance(adev, i, false); if (r) return r; } @@ -733,9 +755,9 @@ static int sdma_v6_0_load_microcode(struct amdgpu_device *adev) return 0; } -static int sdma_v6_0_soft_reset(void *handle) +static int sdma_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 tmp; int i; @@ -769,9 +791,9 @@ static int sdma_v6_0_soft_reset(void *handle) return sdma_v6_0_start(adev); } -static bool sdma_v6_0_check_soft_reset(void *handle) +static bool sdma_v6_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r; long tmo = msecs_to_jiffies(1000); @@ -1272,9 +1294,9 @@ static void sdma_v6_0_set_ras_funcs(struct amdgpu_device *adev) } } -static int sdma_v6_0_early_init(void *handle) +static int sdma_v6_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_sdma_init_microcode(adev, 0, true); @@ -1291,11 +1313,11 @@ static int sdma_v6_0_early_init(void *handle) return 0; } -static int sdma_v6_0_sw_init(void *handle) +static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_6_0); uint32_t *ptr; @@ -1328,6 +1350,19 @@ static int sdma_v6_0_sw_init(void *handle) return r; } + adev->sdma.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring); + switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) { + case IP_VERSION(6, 0, 0): + case IP_VERSION(6, 0, 2): + case IP_VERSION(6, 0, 3): + if (adev->sdma.instance[0].fw_version >= 21) + adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE; + break; + default: + break; + } + if (amdgpu_sdma_ras_sw_init(adev)) { dev_err(adev->dev, "Failed to initialize sdma ras block!\n"); return -EINVAL; @@ -1340,17 +1375,22 @@ static int sdma_v6_0_sw_init(void *handle) else DRM_ERROR("Failed to allocated memory for SDMA IP Dump\n"); + r = amdgpu_sdma_sysfs_reset_mask_init(adev); + if (r) + return r; + return r; } -static int sdma_v6_0_sw_fini(void *handle) +static int sdma_v6_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) amdgpu_ring_fini(&adev->sdma.instance[i].ring); + amdgpu_sdma_sysfs_reset_mask_fini(adev); amdgpu_sdma_destroy_inst_ctx(adev, true); kfree(adev->sdma.ip_dump); @@ -1358,16 +1398,16 @@ static int sdma_v6_0_sw_fini(void *handle) return 0; } -static int sdma_v6_0_hw_init(void *handle) +static int sdma_v6_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return sdma_v6_0_start(adev); } -static int sdma_v6_0_hw_fini(void *handle) +static int sdma_v6_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) return 0; @@ -1378,18 +1418,14 @@ static int sdma_v6_0_hw_fini(void *handle) return 0; } -static int sdma_v6_0_suspend(void *handle) +static int sdma_v6_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v6_0_hw_fini(adev); + return sdma_v6_0_hw_fini(ip_block); } -static int sdma_v6_0_resume(void *handle) +static int sdma_v6_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v6_0_hw_init(adev); + return sdma_v6_0_hw_init(ip_block); } static bool sdma_v6_0_is_idle(void *handle) @@ -1407,11 +1443,11 @@ static bool sdma_v6_0_is_idle(void *handle) return true; } -static int sdma_v6_0_wait_for_idle(void *handle) +static int sdma_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 sdma0, sdma1; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { sdma0 = RREG32(sdma_v6_0_get_reg_offset(adev, 0, regSDMA0_STATUS_REG)); @@ -1469,6 +1505,31 @@ static int sdma_v6_0_ring_preempt_ib(struct amdgpu_ring *ring) return r; } +static int sdma_v6_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid) +{ + struct amdgpu_device *adev = ring->adev; + int i, r; + + if (amdgpu_sriov_vf(adev)) + return -EINVAL; + + for (i = 0; i < adev->sdma.num_instances; i++) { + if (ring == &adev->sdma.instance[i].ring) + break; + } + + if (i == adev->sdma.num_instances) { + DRM_ERROR("sdma instance not found\n"); + return -EINVAL; + } + + r = amdgpu_mes_reset_legacy_queue(adev, ring, vmid, true); + if (r) + return r; + + return sdma_v6_0_gfx_resume_instance(adev, i, true); +} + static int sdma_v6_0_set_trap_irq_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned type, @@ -1556,9 +1617,9 @@ static void sdma_v6_0_get_clockgating_state(void *handle, u64 *flags) { } -static void sdma_v6_0_print_ip_state(void *handle, struct drm_printer *p) +static void sdma_v6_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_6_0); uint32_t instance_offset; @@ -1577,9 +1638,9 @@ static void sdma_v6_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void sdma_v6_0_dump_ip_state(void *handle) +static void sdma_v6_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t instance_offset; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_6_0); @@ -1601,7 +1662,6 @@ static void sdma_v6_0_dump_ip_state(void *handle) const struct amd_ip_funcs sdma_v6_0_ip_funcs = { .name = "sdma_v6_0", .early_init = sdma_v6_0_early_init, - .late_init = NULL, .sw_init = sdma_v6_0_sw_init, .sw_fini = sdma_v6_0_sw_fini, .hw_init = sdma_v6_0_hw_init, @@ -1652,6 +1712,7 @@ static const struct amdgpu_ring_funcs sdma_v6_0_ring_funcs = { .emit_reg_write_reg_wait = sdma_v6_0_ring_emit_reg_write_reg_wait, .init_cond_exec = sdma_v6_0_ring_init_cond_exec, .preempt_ib = sdma_v6_0_ring_preempt_ib, + .reset = sdma_v6_0_reset_queue, }; static void sdma_v6_0_set_ring_funcs(struct amdgpu_device *adev) @@ -1726,7 +1787,7 @@ static void sdma_v6_0_emit_fill_buffer(struct amdgpu_ib *ib, uint64_t dst_offset, uint32_t byte_count) { - ib->ptr[ib->length_dw++] = SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_CONST_FILL); + ib->ptr[ib->length_dw++] = SDMA_PKT_CONSTANT_FILL_HEADER_OP(SDMA_OP_CONST_FILL); ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); ib->ptr[ib->length_dw++] = src_data; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c index 9288f37a3cc5c3..d2ce6b6a7ff64e 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c @@ -753,9 +753,9 @@ static int sdma_v7_0_load_microcode(struct amdgpu_device *adev) return 0; } -static int sdma_v7_0_soft_reset(void *handle) +static int sdma_v7_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 tmp; int i; @@ -789,9 +789,9 @@ static int sdma_v7_0_soft_reset(void *handle) return sdma_v7_0_start(adev); } -static bool sdma_v7_0_check_soft_reset(void *handle) +static bool sdma_v7_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r; long tmo = msecs_to_jiffies(1000); @@ -1259,9 +1259,9 @@ static void sdma_v7_0_ring_emit_reg_write_reg_wait(struct amdgpu_ring *ring, amdgpu_ring_emit_reg_wait(ring, reg1, mask, mask); } -static int sdma_v7_0_early_init(void *handle) +static int sdma_v7_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_sdma_init_microcode(adev, 0, true); @@ -1279,11 +1279,11 @@ static int sdma_v7_0_early_init(void *handle) return 0; } -static int sdma_v7_0_sw_init(void *handle) +static int sdma_v7_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_7_0); uint32_t *ptr; @@ -1326,9 +1326,9 @@ static int sdma_v7_0_sw_init(void *handle) return r; } -static int sdma_v7_0_sw_fini(void *handle) +static int sdma_v7_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) @@ -1344,16 +1344,16 @@ static int sdma_v7_0_sw_fini(void *handle) return 0; } -static int sdma_v7_0_hw_init(void *handle) +static int sdma_v7_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return sdma_v7_0_start(adev); } -static int sdma_v7_0_hw_fini(void *handle) +static int sdma_v7_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) return 0; @@ -1364,18 +1364,14 @@ static int sdma_v7_0_hw_fini(void *handle) return 0; } -static int sdma_v7_0_suspend(void *handle) +static int sdma_v7_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v7_0_hw_fini(adev); + return sdma_v7_0_hw_fini(ip_block); } -static int sdma_v7_0_resume(void *handle) +static int sdma_v7_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return sdma_v7_0_hw_init(adev); + return sdma_v7_0_hw_init(ip_block); } static bool sdma_v7_0_is_idle(void *handle) @@ -1393,11 +1389,11 @@ static bool sdma_v7_0_is_idle(void *handle) return true; } -static int sdma_v7_0_wait_for_idle(void *handle) +static int sdma_v7_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 sdma0, sdma1; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { sdma0 = RREG32(sdma_v7_0_get_reg_offset(adev, 0, regSDMA0_STATUS_REG)); @@ -1544,9 +1540,9 @@ static void sdma_v7_0_get_clockgating_state(void *handle, u64 *flags) { } -static void sdma_v7_0_print_ip_state(void *handle, struct drm_printer *p) +static void sdma_v7_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_7_0); uint32_t instance_offset; @@ -1565,9 +1561,9 @@ static void sdma_v7_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void sdma_v7_0_dump_ip_state(void *handle) +static void sdma_v7_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t instance_offset; uint32_t reg_count = ARRAY_SIZE(sdma_reg_list_7_0); diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 85235470e872c8..00f63d3fbea715 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -2022,9 +2022,9 @@ static uint32_t si_get_rev_id(struct amdgpu_device *adev) >> CC_DRM_ID_STRAPS__ATI_REV_ID__SHIFT; } -static int si_common_early_init(void *handle) +static int si_common_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->smc_rreg = &si_smc_rreg; adev->smc_wreg = &si_smc_wreg; @@ -2148,17 +2148,6 @@ static int si_common_early_init(void *handle) return 0; } -static int si_common_sw_init(void *handle) -{ - return 0; -} - -static int si_common_sw_fini(void *handle) -{ - return 0; -} - - static void si_init_golden_registers(struct amdgpu_device *adev) { switch (adev->asic_type) { @@ -2633,9 +2622,9 @@ static void si_fix_pci_max_read_req_size(struct amdgpu_device *adev) pcie_set_readrq(adev->pdev, 512); } -static int si_common_hw_init(void *handle) +static int si_common_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; si_fix_pci_max_read_req_size(adev); si_init_golden_registers(adev); @@ -2645,23 +2634,14 @@ static int si_common_hw_init(void *handle) return 0; } -static int si_common_hw_fini(void *handle) +static int si_common_hw_fini(struct amdgpu_ip_block *ip_block) { return 0; } -static int si_common_suspend(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return si_common_hw_fini(adev); -} - -static int si_common_resume(void *handle) +static int si_common_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return si_common_hw_init(adev); + return si_common_hw_init(ip_block); } static bool si_common_is_idle(void *handle) @@ -2669,16 +2649,6 @@ static bool si_common_is_idle(void *handle) return true; } -static int si_common_wait_for_idle(void *handle) -{ - return 0; -} - -static int si_common_soft_reset(void *handle) -{ - return 0; -} - static int si_common_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -2694,20 +2664,12 @@ static int si_common_set_powergating_state(void *handle, static const struct amd_ip_funcs si_common_ip_funcs = { .name = "si_common", .early_init = si_common_early_init, - .late_init = NULL, - .sw_init = si_common_sw_init, - .sw_fini = si_common_sw_fini, .hw_init = si_common_hw_init, .hw_fini = si_common_hw_fini, - .suspend = si_common_suspend, .resume = si_common_resume, .is_idle = si_common_is_idle, - .wait_for_idle = si_common_wait_for_idle, - .soft_reset = si_common_soft_reset, .set_clockgating_state = si_common_set_clockgating_state, .set_powergating_state = si_common_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ip_block_version si_common_ip_block = diff --git a/drivers/gpu/drm/amd/amdgpu/si_dma.c b/drivers/gpu/drm/amd/amdgpu/si_dma.c index 11db5b75583218..47647a6083e8b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dma.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dma.c @@ -457,9 +457,9 @@ static void si_dma_ring_emit_wreg(struct amdgpu_ring *ring, amdgpu_ring_write(ring, val); } -static int si_dma_early_init(void *handle) +static int si_dma_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->sdma.num_instances = 2; @@ -471,11 +471,11 @@ static int si_dma_early_init(void *handle) return 0; } -static int si_dma_sw_init(void *handle) +static int si_dma_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* DMA0 trap event */ r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 224, @@ -506,9 +506,9 @@ static int si_dma_sw_init(void *handle) return r; } -static int si_dma_sw_fini(void *handle) +static int si_dma_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; for (i = 0; i < adev->sdma.num_instances; i++) @@ -517,39 +517,34 @@ static int si_dma_sw_fini(void *handle) return 0; } -static int si_dma_hw_init(void *handle) +static int si_dma_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return si_dma_start(adev); } -static int si_dma_hw_fini(void *handle) +static int si_dma_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - si_dma_stop(adev); + si_dma_stop(ip_block->adev); return 0; } -static int si_dma_suspend(void *handle) +static int si_dma_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return si_dma_hw_fini(adev); + return si_dma_hw_fini(ip_block); } -static int si_dma_resume(void *handle) +static int si_dma_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return si_dma_hw_init(adev); + return si_dma_hw_init(ip_block); } static bool si_dma_is_idle(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + u32 tmp = RREG32(SRBM_STATUS2); if (tmp & (DMA_BUSY_MASK | DMA1_BUSY_MASK)) @@ -558,20 +553,20 @@ static bool si_dma_is_idle(void *handle) return true; } -static int si_dma_wait_for_idle(void *handle) +static int si_dma_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { - if (si_dma_is_idle(handle)) + if (si_dma_is_idle(adev)) return 0; udelay(1); } return -ETIMEDOUT; } -static int si_dma_soft_reset(void *handle) +static int si_dma_soft_reset(struct amdgpu_ip_block *ip_block) { DRM_INFO("si_dma_soft_reset --- not implemented !!!!!!!\n"); return 0; @@ -696,7 +691,6 @@ static int si_dma_set_powergating_state(void *handle, static const struct amd_ip_funcs si_dma_ip_funcs = { .name = "si_dma", .early_init = si_dma_early_init, - .late_init = NULL, .sw_init = si_dma_sw_init, .sw_fini = si_dma_sw_fini, .hw_init = si_dma_hw_init, @@ -708,8 +702,6 @@ static const struct amd_ip_funcs si_dma_ip_funcs = { .soft_reset = si_dma_soft_reset, .set_clockgating_state = si_dma_set_clockgating_state, .set_powergating_state = si_dma_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs si_dma_ring_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/si_ih.c b/drivers/gpu/drm/amd/amdgpu/si_ih.c index 5237395e4fab5e..2ec1ebe4db11fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/si_ih.c @@ -156,19 +156,19 @@ static void si_ih_set_rptr(struct amdgpu_device *adev, WREG32(IH_RB_RPTR, ih->rptr); } -static int si_ih_early_init(void *handle) +static int si_ih_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; si_ih_set_interrupt_funcs(adev); return 0; } -static int si_ih_sw_init(void *handle) +static int si_ih_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 64 * 1024, false); if (r) @@ -177,43 +177,37 @@ static int si_ih_sw_init(void *handle) return amdgpu_irq_init(adev); } -static int si_ih_sw_fini(void *handle) +static int si_ih_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); return 0; } -static int si_ih_hw_init(void *handle) +static int si_ih_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return si_ih_irq_init(adev); } -static int si_ih_hw_fini(void *handle) +static int si_ih_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - si_ih_irq_disable(adev); + si_ih_irq_disable(ip_block->adev); return 0; } -static int si_ih_suspend(void *handle) +static int si_ih_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return si_ih_hw_fini(adev); + return si_ih_hw_fini(ip_block); } -static int si_ih_resume(void *handle) +static int si_ih_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return si_ih_hw_init(adev); + return si_ih_hw_init(ip_block); } static bool si_ih_is_idle(void *handle) @@ -227,22 +221,22 @@ static bool si_ih_is_idle(void *handle) return true; } -static int si_ih_wait_for_idle(void *handle) +static int si_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { - if (si_ih_is_idle(handle)) + if (si_ih_is_idle(adev)) return 0; udelay(1); } return -ETIMEDOUT; } -static int si_ih_soft_reset(void *handle) +static int si_ih_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; u32 tmp = RREG32(SRBM_STATUS); @@ -284,7 +278,6 @@ static int si_ih_set_powergating_state(void *handle, static const struct amd_ip_funcs si_ih_ip_funcs = { .name = "si_ih", .early_init = si_ih_early_init, - .late_init = NULL, .sw_init = si_ih_sw_init, .sw_fini = si_ih_sw_fini, .hw_init = si_ih_hw_init, @@ -296,8 +289,6 @@ static const struct amd_ip_funcs si_ih_ip_funcs = { .soft_reset = si_ih_soft_reset, .set_clockgating_state = si_ih_set_clockgating_state, .set_powergating_state = si_ih_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs si_ih_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c index 481217c32d8531..2594467bdd8735 100644 --- a/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c +++ b/drivers/gpu/drm/amd/amdgpu/sienna_cichlid.c @@ -81,15 +81,9 @@ static int sienna_cichlid_mode2_suspend_ip(struct amdgpu_device *adev) AMD_IP_BLOCK_TYPE_SDMA)) continue; - r = adev->ip_blocks[i].version->funcs->suspend(adev); - - if (r) { - dev_err(adev->dev, - "suspend of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_suspend(&adev->ip_blocks[i]); + if (r) return r; - } - adev->ip_blocks[i].status.hw = false; } return 0; @@ -175,15 +169,9 @@ static int sienna_cichlid_mode2_restore_ip(struct amdgpu_device *adev) for (i = 0; i < adev->num_ip_blocks; i++) { if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) { - r = adev->ip_blocks[i].version->funcs->resume(adev); - if (r) { - dev_err(adev->dev, - "resume of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); + if (r) return r; - } - - adev->ip_blocks[i].status.hw = true; } } @@ -193,15 +181,9 @@ static int sienna_cichlid_mode2_restore_ip(struct amdgpu_device *adev) adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; - r = adev->ip_blocks[i].version->funcs->resume(adev); - if (r) { - dev_err(adev->dev, - "resume of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); + if (r) return r; - } - - adev->ip_blocks[i].status.hw = true; } for (i = 0; i < adev->num_ip_blocks; i++) { @@ -213,7 +195,7 @@ static int sienna_cichlid_mode2_restore_ip(struct amdgpu_device *adev) if (adev->ip_blocks[i].version->funcs->late_init) { r = adev->ip_blocks[i].version->funcs->late_init( - (void *)adev); + &adev->ip_blocks[i]); if (r) { dev_err(adev->dev, "late_init of IP block <%s> failed %d after reset\n", @@ -238,6 +220,7 @@ sienna_cichlid_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, int r; struct amdgpu_device *tmp_adev = (struct amdgpu_device *)reset_ctl->handle; + amdgpu_set_init_level(tmp_adev, AMDGPU_INIT_LEVEL_RESET_RECOVERY); dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); r = sienna_cichlid_mode2_restore_ip(tmp_adev); @@ -255,6 +238,7 @@ sienna_cichlid_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, amdgpu_irq_gpu_reset_resume_helper(tmp_adev); + amdgpu_set_init_level(tmp_adev, AMDGPU_INIT_LEVEL_DEFAULT); r = amdgpu_ib_ring_tests(tmp_adev); if (r) { dev_err(tmp_adev->dev, diff --git a/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c b/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c index 0af648931df580..70569ea906bca7 100644 --- a/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c +++ b/drivers/gpu/drm/amd/amdgpu/smu_v13_0_10.c @@ -80,15 +80,9 @@ static int smu_v13_0_10_mode2_suspend_ip(struct amdgpu_device *adev) AMD_IP_BLOCK_TYPE_MES)) continue; - r = adev->ip_blocks[i].version->funcs->suspend(adev); - - if (r) { - dev_err(adev->dev, - "suspend of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_suspend(&adev->ip_blocks[i]); + if (r) return r; - } - adev->ip_blocks[i].status.hw = false; } return 0; @@ -186,15 +180,9 @@ static int smu_v13_0_10_mode2_restore_ip(struct amdgpu_device *adev) adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; - r = adev->ip_blocks[i].version->funcs->resume(adev); - if (r) { - dev_err(adev->dev, - "resume of IP block <%s> failed %d\n", - adev->ip_blocks[i].version->funcs->name, r); + r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); + if (r) return r; - } - - adev->ip_blocks[i].status.hw = true; } for (i = 0; i < adev->num_ip_blocks; i++) { @@ -208,7 +196,7 @@ static int smu_v13_0_10_mode2_restore_ip(struct amdgpu_device *adev) if (adev->ip_blocks[i].version->funcs->late_init) { r = adev->ip_blocks[i].version->funcs->late_init( - (void *)adev); + &adev->ip_blocks[i]); if (r) { dev_err(adev->dev, "late_init of IP block <%s> failed %d after reset\n", @@ -233,6 +221,7 @@ smu_v13_0_10_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, int r; struct amdgpu_device *tmp_adev = (struct amdgpu_device *)reset_ctl->handle; + amdgpu_set_init_level(tmp_adev, AMDGPU_INIT_LEVEL_RESET_RECOVERY); dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); r = smu_v13_0_10_mode2_restore_ip(tmp_adev); @@ -246,6 +235,7 @@ smu_v13_0_10_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, amdgpu_irq_gpu_reset_resume_helper(tmp_adev); + amdgpu_set_init_level(tmp_adev, AMDGPU_INIT_LEVEL_DEFAULT); r = amdgpu_ib_ring_tests(tmp_adev); if (r) { dev_err(tmp_adev->dev, diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 307185c0e1b8f2..ede072758dabf1 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -578,20 +578,16 @@ soc15_asic_reset_method(struct amdgpu_device *adev) static bool soc15_need_reset_on_resume(struct amdgpu_device *adev) { - u32 sol_reg; - - sol_reg = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); - /* Will reset for the following suspend abort cases. - * 1) Only reset limit on APU side, dGPU hasn't checked yet. - * 2) S3 suspend abort and TOS already launched. + * 1) Only reset on APU side, dGPU hasn't checked yet. + * 2) S3 suspend aborted in the normal S3 suspend or + * performing pm core test. */ if (adev->flags & AMD_IS_APU && adev->in_s3 && - !adev->suspend_complete && - sol_reg) + !pm_resume_via_firmware()) return true; - - return false; + else + return false; } static int soc15_asic_reset(struct amdgpu_device *adev) @@ -601,11 +597,17 @@ static int soc15_asic_reset(struct amdgpu_device *adev) * successfully. So now, temporarily enable it for the * S3 suspend abort case. */ - if (((adev->apu_flags & AMD_APU_IS_RAVEN) || - (adev->apu_flags & AMD_APU_IS_RAVEN2)) && - !soc15_need_reset_on_resume(adev)) + + if ((adev->apu_flags & AMD_APU_IS_PICASSO || + !(adev->apu_flags & AMD_APU_IS_RAVEN)) && + soc15_need_reset_on_resume(adev)) + goto asic_reset; + + if ((adev->apu_flags & AMD_APU_IS_RAVEN) || + (adev->apu_flags & AMD_APU_IS_RAVEN2)) return 0; +asic_reset: switch (soc15_asic_reset_method(adev)) { case AMD_RESET_METHOD_PCI: dev_info(adev->dev, "PCI reset\n"); @@ -829,6 +831,10 @@ static bool soc15_need_reset_on_init(struct amdgpu_device *adev) if (adev->asic_type == CHIP_RENOIR) return true; + if (amdgpu_gmc_need_reset_on_init(adev)) + return true; + if (amdgpu_psp_tos_reload_needed(adev)) + return true; /* Just return false for soc15 GPUs. Reset does not seem to * be necessary. */ @@ -929,9 +935,9 @@ static const struct amdgpu_asic_funcs aqua_vanjaram_asic_funcs = .get_reg_state = &aqua_vanjaram_get_reg_state, }; -static int soc15_common_early_init(void *handle) +static int soc15_common_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->nbio.funcs->set_reg_remap(adev); adev->smc_rreg = NULL; @@ -1198,9 +1204,9 @@ static int soc15_common_early_init(void *handle) return 0; } -static int soc15_common_late_init(void *handle) +static int soc15_common_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) xgpu_ai_mailbox_get_irq(adev); @@ -1213,9 +1219,9 @@ static int soc15_common_late_init(void *handle) return 0; } -static int soc15_common_sw_init(void *handle) +static int soc15_common_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) xgpu_ai_mailbox_add_irq_id(adev); @@ -1227,9 +1233,9 @@ static int soc15_common_sw_init(void *handle) return 0; } -static int soc15_common_sw_fini(void *handle) +static int soc15_common_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->df.funcs && adev->df.funcs->sw_fini) @@ -1251,9 +1257,9 @@ static void soc15_sdma_doorbell_range_init(struct amdgpu_device *adev) } } -static int soc15_common_hw_init(void *handle) +static int soc15_common_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* enable aspm */ soc15_program_aspm(adev); @@ -1280,9 +1286,9 @@ static int soc15_common_hw_init(void *handle) return 0; } -static int soc15_common_hw_fini(void *handle) +static int soc15_common_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* Disable the doorbell aperture and selfring doorbell aperture * separately in hw_fini because soc15_enable_doorbell_aperture @@ -1295,7 +1301,12 @@ static int soc15_common_hw_fini(void *handle) if (amdgpu_sriov_vf(adev)) xgpu_ai_mailbox_put_irq(adev); + /* + * For minimal init, late_init is not called, hence RAS irqs are not + * enabled. + */ if ((!amdgpu_sriov_vf(adev)) && + (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) && adev->nbio.ras_if && amdgpu_ras_is_supported(adev, adev->nbio.ras_if->block)) { if (adev->nbio.ras && @@ -1309,22 +1320,20 @@ static int soc15_common_hw_fini(void *handle) return 0; } -static int soc15_common_suspend(void *handle) +static int soc15_common_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return soc15_common_hw_fini(adev); + return soc15_common_hw_fini(ip_block); } -static int soc15_common_resume(void *handle) +static int soc15_common_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (soc15_need_reset_on_resume(adev)) { dev_info(adev->dev, "S3 suspend abort case, let's reset ASIC.\n"); soc15_asic_reset(adev); } - return soc15_common_hw_init(adev); + return soc15_common_hw_init(ip_block); } static bool soc15_common_is_idle(void *handle) @@ -1332,16 +1341,6 @@ static bool soc15_common_is_idle(void *handle) return true; } -static int soc15_common_wait_for_idle(void *handle) -{ - return 0; -} - -static int soc15_common_soft_reset(void *handle) -{ - return 0; -} - static void soc15_update_drm_clock_gating(struct amdgpu_device *adev, bool enable) { uint32_t def, data; @@ -1492,11 +1491,7 @@ static const struct amd_ip_funcs soc15_common_ip_funcs = { .suspend = soc15_common_suspend, .resume = soc15_common_resume, .is_idle = soc15_common_is_idle, - .wait_for_idle = soc15_common_wait_for_idle, - .soft_reset = soc15_common_soft_reset, .set_clockgating_state = soc15_common_set_clockgating_state, .set_powergating_state = soc15_common_set_powergating_state, .get_clockgating_state= soc15_common_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index bba35880badb9f..d6999835918fa0 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -556,9 +556,9 @@ static const struct amdgpu_asic_funcs soc21_asic_funcs = { .update_umd_stable_pstate = &soc21_update_umd_stable_pstate, }; -static int soc21_common_early_init(void *handle) +static int soc21_common_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->nbio.funcs->set_reg_remap(adev); adev->smc_rreg = NULL; @@ -794,9 +794,9 @@ static int soc21_common_early_init(void *handle) return 0; } -static int soc21_common_late_init(void *handle) +static int soc21_common_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) { xgpu_nv_mailbox_get_irq(adev); @@ -832,9 +832,9 @@ static int soc21_common_late_init(void *handle) return 0; } -static int soc21_common_sw_init(void *handle) +static int soc21_common_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) xgpu_nv_mailbox_add_irq_id(adev); @@ -842,14 +842,9 @@ static int soc21_common_sw_init(void *handle) return 0; } -static int soc21_common_sw_fini(void *handle) -{ - return 0; -} - -static int soc21_common_hw_init(void *handle) +static int soc21_common_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* enable aspm */ soc21_program_aspm(adev); @@ -867,9 +862,9 @@ static int soc21_common_hw_init(void *handle) return 0; } -static int soc21_common_hw_fini(void *handle) +static int soc21_common_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* Disable the doorbell aperture and selfring doorbell aperture * separately in hw_fini because soc21_enable_doorbell_aperture @@ -890,11 +885,9 @@ static int soc21_common_hw_fini(void *handle) return 0; } -static int soc21_common_suspend(void *handle) +static int soc21_common_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return soc21_common_hw_fini(adev); + return soc21_common_hw_fini(ip_block); } static bool soc21_need_reset_on_resume(struct amdgpu_device *adev) @@ -904,9 +897,10 @@ static bool soc21_need_reset_on_resume(struct amdgpu_device *adev) /* Will reset for the following suspend abort cases. * 1) Only reset dGPU side. * 2) S3 suspend got aborted and TOS is active. + * As for dGPU suspend abort cases the SOL value + * will be kept as zero at this resume point. */ - if (!(adev->flags & AMD_IS_APU) && adev->in_s3 && - !adev->suspend_complete) { + if (!(adev->flags & AMD_IS_APU) && adev->in_s3) { sol_reg1 = RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_81); msleep(100); sol_reg2 = RREG32_SOC15(MP0, 0, regMP0_SMN_C2PMSG_81); @@ -917,16 +911,16 @@ static bool soc21_need_reset_on_resume(struct amdgpu_device *adev) return false; } -static int soc21_common_resume(void *handle) +static int soc21_common_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (soc21_need_reset_on_resume(adev)) { dev_info(adev->dev, "S3 suspend aborted, resetting..."); soc21_asic_reset(adev); } - return soc21_common_hw_init(adev); + return soc21_common_hw_init(ip_block); } static bool soc21_common_is_idle(void *handle) @@ -934,16 +928,6 @@ static bool soc21_common_is_idle(void *handle) return true; } -static int soc21_common_wait_for_idle(void *handle) -{ - return 0; -} - -static int soc21_common_soft_reset(void *handle) -{ - return 0; -} - static int soc21_common_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -1002,17 +986,12 @@ static const struct amd_ip_funcs soc21_common_ip_funcs = { .early_init = soc21_common_early_init, .late_init = soc21_common_late_init, .sw_init = soc21_common_sw_init, - .sw_fini = soc21_common_sw_fini, .hw_init = soc21_common_hw_init, .hw_fini = soc21_common_hw_fini, .suspend = soc21_common_suspend, .resume = soc21_common_resume, .is_idle = soc21_common_is_idle, - .wait_for_idle = soc21_common_wait_for_idle, - .soft_reset = soc21_common_soft_reset, .set_clockgating_state = soc21_common_set_clockgating_state, .set_powergating_state = soc21_common_set_powergating_state, .get_clockgating_state = soc21_common_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; diff --git a/drivers/gpu/drm/amd/amdgpu/soc24.c b/drivers/gpu/drm/amd/amdgpu/soc24.c index 29a848f2466bb9..be96de92b2f5df 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc24.c +++ b/drivers/gpu/drm/amd/amdgpu/soc24.c @@ -363,9 +363,9 @@ static const struct amdgpu_asic_funcs soc24_asic_funcs = { .update_umd_stable_pstate = &soc24_update_umd_stable_pstate, }; -static int soc24_common_early_init(void *handle) +static int soc24_common_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->nbio.funcs->set_reg_remap(adev); adev->smc_rreg = NULL; @@ -440,9 +440,9 @@ static int soc24_common_early_init(void *handle) return 0; } -static int soc24_common_late_init(void *handle) +static int soc24_common_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) xgpu_nv_mailbox_get_irq(adev); @@ -455,9 +455,9 @@ static int soc24_common_late_init(void *handle) return 0; } -static int soc24_common_sw_init(void *handle) +static int soc24_common_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) xgpu_nv_mailbox_add_irq_id(adev); @@ -465,14 +465,9 @@ static int soc24_common_sw_init(void *handle) return 0; } -static int soc24_common_sw_fini(void *handle) +static int soc24_common_hw_init(struct amdgpu_ip_block *ip_block) { - return 0; -} - -static int soc24_common_hw_init(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* enable aspm */ soc24_program_aspm(adev); @@ -494,9 +489,9 @@ static int soc24_common_hw_init(void *handle) return 0; } -static int soc24_common_hw_fini(void *handle) +static int soc24_common_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* Disable the doorbell aperture and selfring doorbell aperture * separately in hw_fini because soc21_enable_doorbell_aperture @@ -512,18 +507,14 @@ static int soc24_common_hw_fini(void *handle) return 0; } -static int soc24_common_suspend(void *handle) +static int soc24_common_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return soc24_common_hw_fini(adev); + return soc24_common_hw_fini(ip_block); } -static int soc24_common_resume(void *handle) +static int soc24_common_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return soc24_common_hw_init(adev); + return soc24_common_hw_init(ip_block); } static bool soc24_common_is_idle(void *handle) @@ -531,16 +522,6 @@ static bool soc24_common_is_idle(void *handle) return true; } -static int soc24_common_wait_for_idle(void *handle) -{ - return 0; -} - -static int soc24_common_soft_reset(void *handle) -{ - return 0; -} - static int soc24_common_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -595,14 +576,11 @@ static const struct amd_ip_funcs soc24_common_ip_funcs = { .early_init = soc24_common_early_init, .late_init = soc24_common_late_init, .sw_init = soc24_common_sw_init, - .sw_fini = soc24_common_sw_fini, .hw_init = soc24_common_hw_init, .hw_fini = soc24_common_hw_fini, .suspend = soc24_common_suspend, .resume = soc24_common_resume, .is_idle = soc24_common_is_idle, - .wait_for_idle = soc24_common_wait_for_idle, - .soft_reset = soc24_common_soft_reset, .set_clockgating_state = soc24_common_set_clockgating_state, .set_powergating_state = soc24_common_set_powergating_state, .get_clockgating_state = soc24_common_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h b/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h index 3ac56a9645ebdf..21b71a427b1fdf 100644 --- a/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h +++ b/drivers/gpu/drm/amd/amdgpu/ta_ras_if.h @@ -113,6 +113,14 @@ enum ta_ras_address_type { TA_RAS_PA_TO_MCA, }; +enum ta_ras_nps_mode { + TA_RAS_UNKNOWN_MODE = 0, + TA_RAS_NPS1_MODE = 1, + TA_RAS_NPS2_MODE = 2, + TA_RAS_NPS4_MODE = 4, + TA_RAS_NPS8_MODE = 8, +}; + /* Input/output structures for RAS commands */ /**********************************************************/ @@ -139,6 +147,7 @@ struct ta_ras_init_flags { uint8_t dgpu_mode; uint16_t xcc_mask; uint8_t channel_dis_num; + uint8_t nps_mode; }; struct ta_ras_mca_addr { diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c index 24d49d813607f7..5a04a677013808 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c @@ -283,9 +283,9 @@ static void tonga_ih_set_rptr(struct amdgpu_device *adev, } } -static int tonga_ih_early_init(void *handle) +static int tonga_ih_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; ret = amdgpu_irq_add_domain(adev); @@ -297,10 +297,10 @@ static int tonga_ih_early_init(void *handle) return 0; } -static int tonga_ih_sw_init(void *handle) +static int tonga_ih_sw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 64 * 1024, true); if (r) @@ -314,9 +314,9 @@ static int tonga_ih_sw_init(void *handle) return r; } -static int tonga_ih_sw_fini(void *handle) +static int tonga_ih_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); amdgpu_irq_remove_domain(adev); @@ -324,10 +324,10 @@ static int tonga_ih_sw_fini(void *handle) return 0; } -static int tonga_ih_hw_init(void *handle) +static int tonga_ih_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = tonga_ih_irq_init(adev); if (r) @@ -336,27 +336,21 @@ static int tonga_ih_hw_init(void *handle) return 0; } -static int tonga_ih_hw_fini(void *handle) +static int tonga_ih_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - tonga_ih_irq_disable(adev); + tonga_ih_irq_disable(ip_block->adev); return 0; } -static int tonga_ih_suspend(void *handle) +static int tonga_ih_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return tonga_ih_hw_fini(adev); + return tonga_ih_hw_fini(ip_block); } -static int tonga_ih_resume(void *handle) +static int tonga_ih_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return tonga_ih_hw_init(adev); + return tonga_ih_hw_init(ip_block); } static bool tonga_ih_is_idle(void *handle) @@ -370,11 +364,11 @@ static bool tonga_ih_is_idle(void *handle) return true; } -static int tonga_ih_wait_for_idle(void *handle) +static int tonga_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; u32 tmp; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { /* read MC_STATUS */ @@ -386,9 +380,9 @@ static int tonga_ih_wait_for_idle(void *handle) return -ETIMEDOUT; } -static bool tonga_ih_check_soft_reset(void *handle) +static bool tonga_ih_check_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; u32 tmp = RREG32(mmSRBM_STATUS); @@ -405,29 +399,27 @@ static bool tonga_ih_check_soft_reset(void *handle) } } -static int tonga_ih_pre_soft_reset(void *handle) +static int tonga_ih_pre_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (!adev->irq.srbm_soft_reset) + if (!ip_block->adev->irq.srbm_soft_reset) return 0; - return tonga_ih_hw_fini(adev); + return tonga_ih_hw_fini(ip_block); } -static int tonga_ih_post_soft_reset(void *handle) +static int tonga_ih_post_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->irq.srbm_soft_reset) return 0; - return tonga_ih_hw_init(adev); + return tonga_ih_hw_init(ip_block); } -static int tonga_ih_soft_reset(void *handle) +static int tonga_ih_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset; if (!adev->irq.srbm_soft_reset) @@ -471,7 +463,6 @@ static int tonga_ih_set_powergating_state(void *handle, static const struct amd_ip_funcs tonga_ih_ip_funcs = { .name = "tonga_ih", .early_init = tonga_ih_early_init, - .late_init = NULL, .sw_init = tonga_ih_sw_init, .sw_fini = tonga_ih_sw_fini, .hw_init = tonga_ih_hw_init, @@ -486,8 +477,6 @@ static const struct amd_ip_funcs tonga_ih_ip_funcs = { .post_soft_reset = tonga_ih_post_soft_reset, .set_clockgating_state = tonga_ih_set_clockgating_state, .set_powergating_state = tonga_ih_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ih_funcs tonga_ih_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c index 805d6662c88b6d..bdbca25d80c498 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c @@ -531,9 +531,9 @@ static void uvd_v3_1_set_irq_funcs(struct amdgpu_device *adev) } -static int uvd_v3_1_early_init(void *handle) +static int uvd_v3_1_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->uvd.num_uvd_inst = 1; uvd_v3_1_set_ring_funcs(adev); @@ -542,10 +542,10 @@ static int uvd_v3_1_early_init(void *handle) return 0; } -static int uvd_v3_1_sw_init(void *handle) +static int uvd_v3_1_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; void *ptr; uint32_t ucode_len; @@ -580,10 +580,10 @@ static int uvd_v3_1_sw_init(void *handle) return r; } -static int uvd_v3_1_sw_fini(void *handle) +static int uvd_v3_1_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_uvd_suspend(adev); if (r) @@ -621,13 +621,13 @@ static void uvd_v3_1_enable_mgcg(struct amdgpu_device *adev, /** * uvd_v3_1_hw_init - start and test UVD block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int uvd_v3_1_hw_init(void *handle) +static int uvd_v3_1_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = &adev->uvd.inst->ring; uint32_t tmp; int r; @@ -688,13 +688,13 @@ static int uvd_v3_1_hw_init(void *handle) /** * uvd_v3_1_hw_fini - stop the hardware block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the UVD block, mark ring as not ready any more */ -static int uvd_v3_1_hw_fini(void *handle) +static int uvd_v3_1_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->uvd.idle_work); @@ -704,17 +704,17 @@ static int uvd_v3_1_hw_fini(void *handle) return 0; } -static int uvd_v3_1_prepare_suspend(void *handle) +static int uvd_v3_1_prepare_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return amdgpu_uvd_prepare_suspend(adev); } -static int uvd_v3_1_suspend(void *handle) +static int uvd_v3_1_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* * Proper cleanups before halting the HW engine: @@ -740,23 +740,22 @@ static int uvd_v3_1_suspend(void *handle) AMD_CG_STATE_GATE); } - r = uvd_v3_1_hw_fini(adev); + r = uvd_v3_1_hw_fini(ip_block); if (r) return r; return amdgpu_uvd_suspend(adev); } -static int uvd_v3_1_resume(void *handle) +static int uvd_v3_1_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_uvd_resume(adev); + r = amdgpu_uvd_resume(ip_block->adev); if (r) return r; - return uvd_v3_1_hw_init(adev); + return uvd_v3_1_hw_init(ip_block); } static bool uvd_v3_1_is_idle(void *handle) @@ -766,10 +765,10 @@ static bool uvd_v3_1_is_idle(void *handle) return !(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK); } -static int uvd_v3_1_wait_for_idle(void *handle) +static int uvd_v3_1_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { if (!(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK)) @@ -778,9 +777,9 @@ static int uvd_v3_1_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int uvd_v3_1_soft_reset(void *handle) +static int uvd_v3_1_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uvd_v3_1_stop(adev); @@ -806,7 +805,6 @@ static int uvd_v3_1_set_powergating_state(void *handle, static const struct amd_ip_funcs uvd_v3_1_ip_funcs = { .name = "uvd_v3_1", .early_init = uvd_v3_1_early_init, - .late_init = NULL, .sw_init = uvd_v3_1_sw_init, .sw_fini = uvd_v3_1_sw_fini, .hw_init = uvd_v3_1_hw_init, @@ -819,8 +817,6 @@ static const struct amd_ip_funcs uvd_v3_1_ip_funcs = { .soft_reset = uvd_v3_1_soft_reset, .set_clockgating_state = uvd_v3_1_set_clockgating_state, .set_powergating_state = uvd_v3_1_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version uvd_v3_1_ip_block = { diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c index 3f19c606f4de51..a836dc9cfcadeb 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c @@ -90,9 +90,9 @@ static void uvd_v4_2_ring_set_wptr(struct amdgpu_ring *ring) WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr)); } -static int uvd_v4_2_early_init(void *handle) +static int uvd_v4_2_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->uvd.num_uvd_inst = 1; uvd_v4_2_set_ring_funcs(adev); @@ -101,10 +101,10 @@ static int uvd_v4_2_early_init(void *handle) return 0; } -static int uvd_v4_2_sw_init(void *handle) +static int uvd_v4_2_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; /* UVD TRAP */ @@ -130,10 +130,10 @@ static int uvd_v4_2_sw_init(void *handle) return r; } -static int uvd_v4_2_sw_fini(void *handle) +static int uvd_v4_2_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_uvd_suspend(adev); if (r) @@ -147,13 +147,13 @@ static void uvd_v4_2_enable_mgcg(struct amdgpu_device *adev, /** * uvd_v4_2_hw_init - start and test UVD block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int uvd_v4_2_hw_init(void *handle) +static int uvd_v4_2_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = &adev->uvd.inst->ring; uint32_t tmp; int r; @@ -202,13 +202,13 @@ static int uvd_v4_2_hw_init(void *handle) /** * uvd_v4_2_hw_fini - stop the hardware block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the UVD block, mark ring as not ready any more */ -static int uvd_v4_2_hw_fini(void *handle) +static int uvd_v4_2_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->uvd.idle_work); @@ -218,17 +218,17 @@ static int uvd_v4_2_hw_fini(void *handle) return 0; } -static int uvd_v4_2_prepare_suspend(void *handle) +static int uvd_v4_2_prepare_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return amdgpu_uvd_prepare_suspend(adev); } -static int uvd_v4_2_suspend(void *handle) +static int uvd_v4_2_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* * Proper cleanups before halting the HW engine: @@ -254,23 +254,22 @@ static int uvd_v4_2_suspend(void *handle) AMD_CG_STATE_GATE); } - r = uvd_v4_2_hw_fini(adev); + r = uvd_v4_2_hw_fini(ip_block); if (r) return r; return amdgpu_uvd_suspend(adev); } -static int uvd_v4_2_resume(void *handle) +static int uvd_v4_2_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_uvd_resume(adev); + r = amdgpu_uvd_resume(ip_block->adev); if (r) return r; - return uvd_v4_2_hw_init(adev); + return uvd_v4_2_hw_init(ip_block); } /** @@ -666,10 +665,10 @@ static bool uvd_v4_2_is_idle(void *handle) return !(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK); } -static int uvd_v4_2_wait_for_idle(void *handle) +static int uvd_v4_2_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { if (!(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK)) @@ -678,9 +677,9 @@ static int uvd_v4_2_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int uvd_v4_2_soft_reset(void *handle) +static int uvd_v4_2_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uvd_v4_2_stop(adev); @@ -756,7 +755,6 @@ static int uvd_v4_2_set_powergating_state(void *handle, static const struct amd_ip_funcs uvd_v4_2_ip_funcs = { .name = "uvd_v4_2", .early_init = uvd_v4_2_early_init, - .late_init = NULL, .sw_init = uvd_v4_2_sw_init, .sw_fini = uvd_v4_2_sw_fini, .hw_init = uvd_v4_2_hw_init, @@ -769,8 +767,6 @@ static const struct amd_ip_funcs uvd_v4_2_ip_funcs = { .soft_reset = uvd_v4_2_soft_reset, .set_clockgating_state = uvd_v4_2_set_clockgating_state, .set_powergating_state = uvd_v4_2_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs uvd_v4_2_ring_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c index efd903c21d48eb..ab55fae3569e49 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c @@ -88,9 +88,9 @@ static void uvd_v5_0_ring_set_wptr(struct amdgpu_ring *ring) WREG32(mmUVD_RBC_RB_WPTR, lower_32_bits(ring->wptr)); } -static int uvd_v5_0_early_init(void *handle) +static int uvd_v5_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->uvd.num_uvd_inst = 1; uvd_v5_0_set_ring_funcs(adev); @@ -99,10 +99,10 @@ static int uvd_v5_0_early_init(void *handle) return 0; } -static int uvd_v5_0_sw_init(void *handle) +static int uvd_v5_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; /* UVD TRAP */ @@ -128,10 +128,10 @@ static int uvd_v5_0_sw_init(void *handle) return r; } -static int uvd_v5_0_sw_fini(void *handle) +static int uvd_v5_0_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_uvd_suspend(adev); if (r) @@ -143,13 +143,13 @@ static int uvd_v5_0_sw_fini(void *handle) /** * uvd_v5_0_hw_init - start and test UVD block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int uvd_v5_0_hw_init(void *handle) +static int uvd_v5_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = &adev->uvd.inst->ring; uint32_t tmp; int r; @@ -200,13 +200,13 @@ static int uvd_v5_0_hw_init(void *handle) /** * uvd_v5_0_hw_fini - stop the hardware block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the UVD block, mark ring as not ready any more */ -static int uvd_v5_0_hw_fini(void *handle) +static int uvd_v5_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->uvd.idle_work); @@ -216,17 +216,17 @@ static int uvd_v5_0_hw_fini(void *handle) return 0; } -static int uvd_v5_0_prepare_suspend(void *handle) +static int uvd_v5_0_prepare_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return amdgpu_uvd_prepare_suspend(adev); } -static int uvd_v5_0_suspend(void *handle) +static int uvd_v5_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* * Proper cleanups before halting the HW engine: @@ -252,23 +252,22 @@ static int uvd_v5_0_suspend(void *handle) AMD_CG_STATE_GATE); } - r = uvd_v5_0_hw_fini(adev); + r = uvd_v5_0_hw_fini(ip_block); if (r) return r; return amdgpu_uvd_suspend(adev); } -static int uvd_v5_0_resume(void *handle) +static int uvd_v5_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_uvd_resume(adev); + r = amdgpu_uvd_resume(ip_block->adev); if (r) return r; - return uvd_v5_0_hw_init(adev); + return uvd_v5_0_hw_init(ip_block); } /** @@ -588,10 +587,10 @@ static bool uvd_v5_0_is_idle(void *handle) return !(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK); } -static int uvd_v5_0_wait_for_idle(void *handle) +static int uvd_v5_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { if (!(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK)) @@ -600,9 +599,9 @@ static int uvd_v5_0_wait_for_idle(void *handle) return -ETIMEDOUT; } -static int uvd_v5_0_soft_reset(void *handle) +static int uvd_v5_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; uvd_v5_0_stop(adev); @@ -796,10 +795,15 @@ static int uvd_v5_0_set_clockgating_state(void *handle, { struct amdgpu_device *adev = (struct amdgpu_device *)handle; bool enable = (state == AMD_CG_STATE_GATE); + struct amdgpu_ip_block *ip_block; + + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_UVD); + if (!ip_block) + return -EINVAL; if (enable) { /* wait for STATUS to clear */ - if (uvd_v5_0_wait_for_idle(handle)) + if (uvd_v5_0_wait_for_idle(ip_block)) return -EBUSY; uvd_v5_0_enable_clock_gating(adev, true); @@ -863,7 +867,6 @@ static void uvd_v5_0_get_clockgating_state(void *handle, u64 *flags) static const struct amd_ip_funcs uvd_v5_0_ip_funcs = { .name = "uvd_v5_0", .early_init = uvd_v5_0_early_init, - .late_init = NULL, .sw_init = uvd_v5_0_sw_init, .sw_fini = uvd_v5_0_sw_fini, .hw_init = uvd_v5_0_hw_init, @@ -877,8 +880,6 @@ static const struct amd_ip_funcs uvd_v5_0_ip_funcs = { .set_clockgating_state = uvd_v5_0_set_clockgating_state, .set_powergating_state = uvd_v5_0_set_powergating_state, .get_clockgating_state = uvd_v5_0_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs uvd_v5_0_ring_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 495de506845540..39f8c3d3a135f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -354,9 +354,9 @@ static int uvd_v6_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) return r; } -static int uvd_v6_0_early_init(void *handle) +static int uvd_v6_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->uvd.num_uvd_inst = 1; if (!(adev->flags & AMD_IS_APU) && @@ -375,11 +375,11 @@ static int uvd_v6_0_early_init(void *handle) return 0; } -static int uvd_v6_0_sw_init(void *handle) +static int uvd_v6_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int i, r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* UVD TRAP */ r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_UVD_SYSTEM_MESSAGE, &adev->uvd.inst->irq); @@ -435,10 +435,10 @@ static int uvd_v6_0_sw_init(void *handle) return r; } -static int uvd_v6_0_sw_fini(void *handle) +static int uvd_v6_0_sw_fini(struct amdgpu_ip_block *ip_block) { int i, r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_uvd_suspend(adev); if (r) @@ -455,13 +455,13 @@ static int uvd_v6_0_sw_fini(void *handle) /** * uvd_v6_0_hw_init - start and test UVD block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int uvd_v6_0_hw_init(void *handle) +static int uvd_v6_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = &adev->uvd.inst->ring; uint32_t tmp; int i, r; @@ -524,13 +524,13 @@ static int uvd_v6_0_hw_init(void *handle) /** * uvd_v6_0_hw_fini - stop the hardware block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the UVD block, mark ring as not ready any more */ -static int uvd_v6_0_hw_fini(void *handle) +static int uvd_v6_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->uvd.idle_work); @@ -540,17 +540,17 @@ static int uvd_v6_0_hw_fini(void *handle) return 0; } -static int uvd_v6_0_prepare_suspend(void *handle) +static int uvd_v6_0_prepare_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return amdgpu_uvd_prepare_suspend(adev); } -static int uvd_v6_0_suspend(void *handle) +static int uvd_v6_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* * Proper cleanups before halting the HW engine: @@ -576,23 +576,22 @@ static int uvd_v6_0_suspend(void *handle) AMD_CG_STATE_GATE); } - r = uvd_v6_0_hw_fini(adev); + r = uvd_v6_0_hw_fini(ip_block); if (r) return r; return amdgpu_uvd_suspend(adev); } -static int uvd_v6_0_resume(void *handle) +static int uvd_v6_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_uvd_resume(adev); + r = amdgpu_uvd_resume(ip_block->adev); if (r) return r; - return uvd_v6_0_hw_init(adev); + return uvd_v6_0_hw_init(ip_block); } /** @@ -1151,22 +1150,22 @@ static bool uvd_v6_0_is_idle(void *handle) return !(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK); } -static int uvd_v6_0_wait_for_idle(void *handle) +static int uvd_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) { - if (uvd_v6_0_is_idle(handle)) + if (uvd_v6_0_is_idle(adev)) return 0; } return -ETIMEDOUT; } #define AMDGPU_UVD_STATUS_BUSY_MASK 0xfd -static bool uvd_v6_0_check_soft_reset(void *handle) +static bool uvd_v6_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; u32 tmp = RREG32(mmSRBM_STATUS); @@ -1184,9 +1183,9 @@ static bool uvd_v6_0_check_soft_reset(void *handle) } } -static int uvd_v6_0_pre_soft_reset(void *handle) +static int uvd_v6_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->uvd.inst->srbm_soft_reset) return 0; @@ -1195,9 +1194,9 @@ static int uvd_v6_0_pre_soft_reset(void *handle) return 0; } -static int uvd_v6_0_soft_reset(void *handle) +static int uvd_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset; if (!adev->uvd.inst->srbm_soft_reset) @@ -1226,9 +1225,9 @@ static int uvd_v6_0_soft_reset(void *handle) return 0; } -static int uvd_v6_0_post_soft_reset(void *handle) +static int uvd_v6_0_post_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->uvd.inst->srbm_soft_reset) return 0; @@ -1455,11 +1454,16 @@ static int uvd_v6_0_set_clockgating_state(void *handle, enum amd_clockgating_state state) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_ip_block *ip_block; bool enable = (state == AMD_CG_STATE_GATE); + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_UVD); + if (!ip_block) + return -EINVAL; + if (enable) { /* wait for STATUS to clear */ - if (uvd_v6_0_wait_for_idle(handle)) + if (uvd_v6_0_wait_for_idle(ip_block)) return -EBUSY; uvd_v6_0_enable_clock_gating(adev, true); /* enable HW gates because UVD is idle */ @@ -1528,7 +1532,6 @@ static void uvd_v6_0_get_clockgating_state(void *handle, u64 *flags) static const struct amd_ip_funcs uvd_v6_0_ip_funcs = { .name = "uvd_v6_0", .early_init = uvd_v6_0_early_init, - .late_init = NULL, .sw_init = uvd_v6_0_sw_init, .sw_fini = uvd_v6_0_sw_fini, .hw_init = uvd_v6_0_hw_init, @@ -1545,8 +1548,6 @@ static const struct amd_ip_funcs uvd_v6_0_ip_funcs = { .set_clockgating_state = uvd_v6_0_set_clockgating_state, .set_powergating_state = uvd_v6_0_set_powergating_state, .get_clockgating_state = uvd_v6_0_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs uvd_v6_0_ring_phys_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c index 6068b784dc6938..3c8ab8698af833 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v7_0.c @@ -361,9 +361,9 @@ static int uvd_v7_0_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) return r; } -static int uvd_v7_0_early_init(void *handle) +static int uvd_v7_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->asic_type == CHIP_VEGA20) { u32 harvest; @@ -395,12 +395,12 @@ static int uvd_v7_0_early_init(void *handle) return 0; } -static int uvd_v7_0_sw_init(void *handle) +static int uvd_v7_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int i, j, r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (j = 0; j < adev->uvd.num_uvd_inst; j++) { if (adev->uvd.harvest_config & (1 << j)) @@ -487,10 +487,10 @@ static int uvd_v7_0_sw_init(void *handle) return r; } -static int uvd_v7_0_sw_fini(void *handle) +static int uvd_v7_0_sw_fini(struct amdgpu_ip_block *ip_block) { int i, j, r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_virt_free_mm_table(adev); @@ -510,13 +510,13 @@ static int uvd_v7_0_sw_fini(void *handle) /** * uvd_v7_0_hw_init - start and test UVD block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int uvd_v7_0_hw_init(void *handle) +static int uvd_v7_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; uint32_t tmp; int i, j, r; @@ -588,13 +588,13 @@ static int uvd_v7_0_hw_init(void *handle) /** * uvd_v7_0_hw_fini - stop the hardware block * - * @handle: handle used to pass amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the UVD block, mark ring as not ready any more */ -static int uvd_v7_0_hw_fini(void *handle) +static int uvd_v7_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->uvd.idle_work); @@ -608,17 +608,17 @@ static int uvd_v7_0_hw_fini(void *handle) return 0; } -static int uvd_v7_0_prepare_suspend(void *handle) +static int uvd_v7_0_prepare_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; return amdgpu_uvd_prepare_suspend(adev); } -static int uvd_v7_0_suspend(void *handle) +static int uvd_v7_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* * Proper cleanups before halting the HW engine: @@ -644,23 +644,22 @@ static int uvd_v7_0_suspend(void *handle) AMD_CG_STATE_GATE); } - r = uvd_v7_0_hw_fini(adev); + r = uvd_v7_0_hw_fini(ip_block); if (r) return r; return amdgpu_uvd_suspend(adev); } -static int uvd_v7_0_resume(void *handle) +static int uvd_v7_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_uvd_resume(adev); + r = amdgpu_uvd_resume(ip_block->adev); if (r) return r; - return uvd_v7_0_hw_init(adev); + return uvd_v7_0_hw_init(ip_block); } /** @@ -1289,7 +1288,7 @@ static int uvd_v7_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, struct amdgpu_job *job, struct amdgpu_ib *ib) { - struct amdgpu_ring *ring = to_amdgpu_ring(job->base.sched); + struct amdgpu_ring *ring = amdgpu_job_ring(job); unsigned i; /* No patching necessary for the first instance */ @@ -1463,104 +1462,6 @@ static void uvd_v7_0_enc_ring_emit_wreg(struct amdgpu_ring *ring, amdgpu_ring_write(ring, val); } -#if 0 -static bool uvd_v7_0_is_idle(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return !(RREG32(mmSRBM_STATUS) & SRBM_STATUS__UVD_BUSY_MASK); -} - -static int uvd_v7_0_wait_for_idle(void *handle) -{ - unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - for (i = 0; i < adev->usec_timeout; i++) { - if (uvd_v7_0_is_idle(handle)) - return 0; - } - return -ETIMEDOUT; -} - -#define AMDGPU_UVD_STATUS_BUSY_MASK 0xfd -static bool uvd_v7_0_check_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - u32 srbm_soft_reset = 0; - u32 tmp = RREG32(mmSRBM_STATUS); - - if (REG_GET_FIELD(tmp, SRBM_STATUS, UVD_RQ_PENDING) || - REG_GET_FIELD(tmp, SRBM_STATUS, UVD_BUSY) || - (RREG32_SOC15(UVD, ring->me, mmUVD_STATUS) & - AMDGPU_UVD_STATUS_BUSY_MASK)) - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, - SRBM_SOFT_RESET, SOFT_RESET_UVD, 1); - - if (srbm_soft_reset) { - adev->uvd.inst[ring->me].srbm_soft_reset = srbm_soft_reset; - return true; - } else { - adev->uvd.inst[ring->me].srbm_soft_reset = 0; - return false; - } -} - -static int uvd_v7_0_pre_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (!adev->uvd.inst[ring->me].srbm_soft_reset) - return 0; - - uvd_v7_0_stop(adev); - return 0; -} - -static int uvd_v7_0_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - u32 srbm_soft_reset; - - if (!adev->uvd.inst[ring->me].srbm_soft_reset) - return 0; - srbm_soft_reset = adev->uvd.inst[ring->me].srbm_soft_reset; - - if (srbm_soft_reset) { - u32 tmp; - - tmp = RREG32(mmSRBM_SOFT_RESET); - tmp |= srbm_soft_reset; - dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - udelay(50); - - tmp &= ~srbm_soft_reset; - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - /* Wait a little for things to settle down */ - udelay(50); - } - - return 0; -} - -static int uvd_v7_0_post_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (!adev->uvd.inst[ring->me].srbm_soft_reset) - return 0; - - mdelay(5); - - return uvd_v7_0_start(adev); -} -#endif - static int uvd_v7_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned type, @@ -1610,171 +1511,6 @@ static int uvd_v7_0_process_interrupt(struct amdgpu_device *adev, return 0; } -#if 0 -static void uvd_v7_0_set_sw_clock_gating(struct amdgpu_device *adev) -{ - uint32_t data, data1, data2, suvd_flags; - - data = RREG32_SOC15(UVD, ring->me, mmUVD_CGC_CTRL); - data1 = RREG32_SOC15(UVD, ring->me, mmUVD_SUVD_CGC_GATE); - data2 = RREG32_SOC15(UVD, ring->me, mmUVD_SUVD_CGC_CTRL); - - data &= ~(UVD_CGC_CTRL__CLK_OFF_DELAY_MASK | - UVD_CGC_CTRL__CLK_GATE_DLY_TIMER_MASK); - - suvd_flags = UVD_SUVD_CGC_GATE__SRE_MASK | - UVD_SUVD_CGC_GATE__SIT_MASK | - UVD_SUVD_CGC_GATE__SMP_MASK | - UVD_SUVD_CGC_GATE__SCM_MASK | - UVD_SUVD_CGC_GATE__SDB_MASK; - - data |= UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK | - (1 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_GATE_DLY_TIMER)) | - (4 << REG_FIELD_SHIFT(UVD_CGC_CTRL, CLK_OFF_DELAY)); - - data &= ~(UVD_CGC_CTRL__UDEC_RE_MODE_MASK | - UVD_CGC_CTRL__UDEC_CM_MODE_MASK | - UVD_CGC_CTRL__UDEC_IT_MODE_MASK | - UVD_CGC_CTRL__UDEC_DB_MODE_MASK | - UVD_CGC_CTRL__UDEC_MP_MODE_MASK | - UVD_CGC_CTRL__SYS_MODE_MASK | - UVD_CGC_CTRL__UDEC_MODE_MASK | - UVD_CGC_CTRL__MPEG2_MODE_MASK | - UVD_CGC_CTRL__REGS_MODE_MASK | - UVD_CGC_CTRL__RBC_MODE_MASK | - UVD_CGC_CTRL__LMI_MC_MODE_MASK | - UVD_CGC_CTRL__LMI_UMC_MODE_MASK | - UVD_CGC_CTRL__IDCT_MODE_MASK | - UVD_CGC_CTRL__MPRD_MODE_MASK | - UVD_CGC_CTRL__MPC_MODE_MASK | - UVD_CGC_CTRL__LBSI_MODE_MASK | - UVD_CGC_CTRL__LRBBM_MODE_MASK | - UVD_CGC_CTRL__WCB_MODE_MASK | - UVD_CGC_CTRL__VCPU_MODE_MASK | - UVD_CGC_CTRL__JPEG_MODE_MASK | - UVD_CGC_CTRL__JPEG2_MODE_MASK | - UVD_CGC_CTRL__SCPU_MODE_MASK); - data2 &= ~(UVD_SUVD_CGC_CTRL__SRE_MODE_MASK | - UVD_SUVD_CGC_CTRL__SIT_MODE_MASK | - UVD_SUVD_CGC_CTRL__SMP_MODE_MASK | - UVD_SUVD_CGC_CTRL__SCM_MODE_MASK | - UVD_SUVD_CGC_CTRL__SDB_MODE_MASK); - data1 |= suvd_flags; - - WREG32_SOC15(UVD, ring->me, mmUVD_CGC_CTRL, data); - WREG32_SOC15(UVD, ring->me, mmUVD_CGC_GATE, 0); - WREG32_SOC15(UVD, ring->me, mmUVD_SUVD_CGC_GATE, data1); - WREG32_SOC15(UVD, ring->me, mmUVD_SUVD_CGC_CTRL, data2); -} - -static void uvd_v7_0_set_hw_clock_gating(struct amdgpu_device *adev) -{ - uint32_t data, data1, cgc_flags, suvd_flags; - - data = RREG32_SOC15(UVD, ring->me, mmUVD_CGC_GATE); - data1 = RREG32_SOC15(UVD, ring->me, mmUVD_SUVD_CGC_GATE); - - cgc_flags = UVD_CGC_GATE__SYS_MASK | - UVD_CGC_GATE__UDEC_MASK | - UVD_CGC_GATE__MPEG2_MASK | - UVD_CGC_GATE__RBC_MASK | - UVD_CGC_GATE__LMI_MC_MASK | - UVD_CGC_GATE__IDCT_MASK | - UVD_CGC_GATE__MPRD_MASK | - UVD_CGC_GATE__MPC_MASK | - UVD_CGC_GATE__LBSI_MASK | - UVD_CGC_GATE__LRBBM_MASK | - UVD_CGC_GATE__UDEC_RE_MASK | - UVD_CGC_GATE__UDEC_CM_MASK | - UVD_CGC_GATE__UDEC_IT_MASK | - UVD_CGC_GATE__UDEC_DB_MASK | - UVD_CGC_GATE__UDEC_MP_MASK | - UVD_CGC_GATE__WCB_MASK | - UVD_CGC_GATE__VCPU_MASK | - UVD_CGC_GATE__SCPU_MASK | - UVD_CGC_GATE__JPEG_MASK | - UVD_CGC_GATE__JPEG2_MASK; - - suvd_flags = UVD_SUVD_CGC_GATE__SRE_MASK | - UVD_SUVD_CGC_GATE__SIT_MASK | - UVD_SUVD_CGC_GATE__SMP_MASK | - UVD_SUVD_CGC_GATE__SCM_MASK | - UVD_SUVD_CGC_GATE__SDB_MASK; - - data |= cgc_flags; - data1 |= suvd_flags; - - WREG32_SOC15(UVD, ring->me, mmUVD_CGC_GATE, data); - WREG32_SOC15(UVD, ring->me, mmUVD_SUVD_CGC_GATE, data1); -} - -static void uvd_v7_0_set_bypass_mode(struct amdgpu_device *adev, bool enable) -{ - u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); - - if (enable) - tmp |= (GCK_DFS_BYPASS_CNTL__BYPASSDCLK_MASK | - GCK_DFS_BYPASS_CNTL__BYPASSVCLK_MASK); - else - tmp &= ~(GCK_DFS_BYPASS_CNTL__BYPASSDCLK_MASK | - GCK_DFS_BYPASS_CNTL__BYPASSVCLK_MASK); - - WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); -} - - -static int uvd_v7_0_set_clockgating_state(void *handle, - enum amd_clockgating_state state) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - bool enable = (state == AMD_CG_STATE_GATE); - - uvd_v7_0_set_bypass_mode(adev, enable); - - if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) - return 0; - - if (enable) { - /* disable HW gating and enable Sw gating */ - uvd_v7_0_set_sw_clock_gating(adev); - } else { - /* wait for STATUS to clear */ - if (uvd_v7_0_wait_for_idle(handle)) - return -EBUSY; - - /* enable HW gates because UVD is idle */ - /* uvd_v7_0_set_hw_clock_gating(adev); */ - } - - return 0; -} - -static int uvd_v7_0_set_powergating_state(void *handle, - enum amd_powergating_state state) -{ - /* This doesn't actually powergate the UVD block. - * That's done in the dpm code via the SMC. This - * just re-inits the block as necessary. The actual - * gating still happens in the dpm code. We should - * revisit this when there is a cleaner line between - * the smc and the hw blocks - */ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD)) - return 0; - - WREG32_SOC15(UVD, ring->me, mmUVD_POWER_STATUS, UVD_POWER_STATUS__UVD_PG_EN_MASK); - - if (state == AMD_PG_STATE_GATE) { - uvd_v7_0_stop(adev); - return 0; - } else { - return uvd_v7_0_start(adev); - } -} -#endif - static int uvd_v7_0_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -1785,7 +1521,6 @@ static int uvd_v7_0_set_clockgating_state(void *handle, const struct amd_ip_funcs uvd_v7_0_ip_funcs = { .name = "uvd_v7_0", .early_init = uvd_v7_0_early_init, - .late_init = NULL, .sw_init = uvd_v7_0_sw_init, .sw_fini = uvd_v7_0_sw_fini, .hw_init = uvd_v7_0_hw_init, @@ -1793,12 +1528,6 @@ const struct amd_ip_funcs uvd_v7_0_ip_funcs = { .prepare_suspend = uvd_v7_0_prepare_suspend, .suspend = uvd_v7_0_suspend, .resume = uvd_v7_0_resume, - .is_idle = NULL /* uvd_v7_0_is_idle */, - .wait_for_idle = NULL /* uvd_v7_0_wait_for_idle */, - .check_soft_reset = NULL /* uvd_v7_0_check_soft_reset */, - .pre_soft_reset = NULL /* uvd_v7_0_pre_soft_reset */, - .soft_reset = NULL /* uvd_v7_0_soft_reset */, - .post_soft_reset = NULL /* uvd_v7_0_post_soft_reset */, .set_clockgating_state = uvd_v7_0_set_clockgating_state, .set_powergating_state = NULL /* uvd_v7_0_set_powergating_state */, }; diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c index 66fada199bda23..c1ed91b3941543 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c @@ -208,13 +208,13 @@ static bool vce_v2_0_is_idle(void *handle) return !(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK); } -static int vce_v2_0_wait_for_idle(void *handle) +static int vce_v2_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; unsigned i; for (i = 0; i < adev->usec_timeout; i++) { - if (vce_v2_0_is_idle(handle)) + if (vce_v2_0_is_idle(adev)) return 0; } return -ETIMEDOUT; @@ -274,15 +274,21 @@ static int vce_v2_0_start(struct amdgpu_device *adev) static int vce_v2_0_stop(struct amdgpu_device *adev) { + struct amdgpu_ip_block *ip_block; int i; int status; + if (vce_v2_0_lmi_clean(adev)) { DRM_INFO("vce is not idle \n"); return 0; } - if (vce_v2_0_wait_for_idle(adev)) { + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_VCN); + if (!ip_block) + return -EINVAL; + + if (vce_v2_0_wait_for_idle(ip_block)) { DRM_INFO("VCE is busy, Can't set clock gating"); return 0; } @@ -398,9 +404,9 @@ static void vce_v2_0_enable_mgcg(struct amdgpu_device *adev, bool enable, } } -static int vce_v2_0_early_init(void *handle) +static int vce_v2_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->vce.num_rings = 2; @@ -410,11 +416,11 @@ static int vce_v2_0_early_init(void *handle) return 0; } -static int vce_v2_0_sw_init(void *handle) +static int vce_v2_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* VCE */ r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 167, &adev->vce.irq); @@ -444,10 +450,10 @@ static int vce_v2_0_sw_init(void *handle) return r; } -static int vce_v2_0_sw_fini(void *handle) +static int vce_v2_0_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_vce_suspend(adev); if (r) @@ -456,10 +462,10 @@ static int vce_v2_0_sw_fini(void *handle) return amdgpu_vce_sw_fini(adev); } -static int vce_v2_0_hw_init(void *handle) +static int vce_v2_0_hw_init(struct amdgpu_ip_block *ip_block) { int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_asic_set_vce_clocks(adev, 10000, 10000); vce_v2_0_enable_mgcg(adev, true, false); @@ -475,19 +481,17 @@ static int vce_v2_0_hw_init(void *handle) return 0; } -static int vce_v2_0_hw_fini(void *handle) +static int vce_v2_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - cancel_delayed_work_sync(&adev->vce.idle_work); + cancel_delayed_work_sync(&ip_block->adev->vce.idle_work); return 0; } -static int vce_v2_0_suspend(void *handle) +static int vce_v2_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* @@ -513,28 +517,27 @@ static int vce_v2_0_suspend(void *handle) AMD_CG_STATE_GATE); } - r = vce_v2_0_hw_fini(adev); + r = vce_v2_0_hw_fini(ip_block); if (r) return r; return amdgpu_vce_suspend(adev); } -static int vce_v2_0_resume(void *handle) +static int vce_v2_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vce_resume(adev); + r = amdgpu_vce_resume(ip_block->adev); if (r) return r; - return vce_v2_0_hw_init(adev); + return vce_v2_0_hw_init(ip_block); } -static int vce_v2_0_soft_reset(void *handle) +static int vce_v2_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; WREG32_FIELD(SRBM_SOFT_RESET, SOFT_RESET_VCE, 1); mdelay(5); @@ -614,7 +617,6 @@ static int vce_v2_0_set_powergating_state(void *handle, static const struct amd_ip_funcs vce_v2_0_ip_funcs = { .name = "vce_v2_0", .early_init = vce_v2_0_early_init, - .late_init = NULL, .sw_init = vce_v2_0_sw_init, .sw_fini = vce_v2_0_sw_fini, .hw_init = vce_v2_0_hw_init, @@ -626,8 +628,6 @@ static const struct amd_ip_funcs vce_v2_0_ip_funcs = { .soft_reset = vce_v2_0_soft_reset, .set_clockgating_state = vce_v2_0_set_clockgating_state, .set_powergating_state = vce_v2_0_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs vce_v2_0_ring_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 4bfba2931b088c..6bb318a06f1976 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -64,7 +64,7 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); -static int vce_v3_0_wait_for_idle(void *handle); +static int vce_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block); static int vce_v3_0_set_clockgating_state(void *handle, enum amd_clockgating_state state); /** @@ -396,9 +396,9 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) } } -static int vce_v3_0_early_init(void *handle) +static int vce_v3_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->vce.harvest_config = vce_v3_0_get_harvest_config(adev); @@ -415,9 +415,9 @@ static int vce_v3_0_early_init(void *handle) return 0; } -static int vce_v3_0_sw_init(void *handle) +static int vce_v3_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int r, i; @@ -453,10 +453,10 @@ static int vce_v3_0_sw_init(void *handle) return r; } -static int vce_v3_0_sw_fini(void *handle) +static int vce_v3_0_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_vce_suspend(adev); if (r) @@ -465,10 +465,10 @@ static int vce_v3_0_sw_fini(void *handle) return amdgpu_vce_sw_fini(adev); } -static int vce_v3_0_hw_init(void *handle) +static int vce_v3_0_hw_init(struct amdgpu_ip_block *ip_block) { int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; vce_v3_0_override_vce_clock_gating(adev, true); @@ -485,14 +485,14 @@ static int vce_v3_0_hw_init(void *handle) return 0; } -static int vce_v3_0_hw_fini(void *handle) +static int vce_v3_0_hw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->vce.idle_work); - r = vce_v3_0_wait_for_idle(handle); + r = vce_v3_0_wait_for_idle(ip_block); if (r) return r; @@ -500,10 +500,10 @@ static int vce_v3_0_hw_fini(void *handle) return vce_v3_0_set_clockgating_state(adev, AMD_CG_STATE_GATE); } -static int vce_v3_0_suspend(void *handle) +static int vce_v3_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* * Proper cleanups before halting the HW engine: @@ -528,23 +528,22 @@ static int vce_v3_0_suspend(void *handle) AMD_CG_STATE_GATE); } - r = vce_v3_0_hw_fini(adev); + r = vce_v3_0_hw_fini(ip_block); if (r) return r; return amdgpu_vce_suspend(adev); } -static int vce_v3_0_resume(void *handle) +static int vce_v3_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vce_resume(adev); + r = amdgpu_vce_resume(ip_block->adev); if (r) return r; - return vce_v3_0_hw_init(adev); + return vce_v3_0_hw_init(ip_block); } static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) @@ -609,13 +608,13 @@ static bool vce_v3_0_is_idle(void *handle) return !(RREG32(mmSRBM_STATUS2) & mask); } -static int vce_v3_0_wait_for_idle(void *handle) +static int vce_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (i = 0; i < adev->usec_timeout; i++) - if (vce_v3_0_is_idle(handle)) + if (vce_v3_0_is_idle(adev)) return 0; return -ETIMEDOUT; @@ -627,9 +626,9 @@ static int vce_v3_0_wait_for_idle(void *handle) #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) -static bool vce_v3_0_check_soft_reset(void *handle) +static bool vce_v3_0_check_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset = 0; /* According to VCE team , we should use VCE_STATUS instead @@ -668,9 +667,9 @@ static bool vce_v3_0_check_soft_reset(void *handle) } } -static int vce_v3_0_soft_reset(void *handle) +static int vce_v3_0_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; u32 srbm_soft_reset; if (!adev->vce.srbm_soft_reset) @@ -699,29 +698,29 @@ static int vce_v3_0_soft_reset(void *handle) return 0; } -static int vce_v3_0_pre_soft_reset(void *handle) +static int vce_v3_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->vce.srbm_soft_reset) return 0; mdelay(5); - return vce_v3_0_suspend(adev); + return vce_v3_0_suspend(ip_block); } -static int vce_v3_0_post_soft_reset(void *handle) +static int vce_v3_0_post_soft_reset(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->vce.srbm_soft_reset) return 0; mdelay(5); - return vce_v3_0_resume(adev); + return vce_v3_0_resume(ip_block); } static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, @@ -897,7 +896,6 @@ static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring) static const struct amd_ip_funcs vce_v3_0_ip_funcs = { .name = "vce_v3_0", .early_init = vce_v3_0_early_init, - .late_init = NULL, .sw_init = vce_v3_0_sw_init, .sw_fini = vce_v3_0_sw_fini, .hw_init = vce_v3_0_hw_init, @@ -913,8 +911,6 @@ static const struct amd_ip_funcs vce_v3_0_ip_funcs = { .set_clockgating_state = vce_v3_0_set_clockgating_state, .set_powergating_state = vce_v3_0_set_powergating_state, .get_clockgating_state = vce_v3_0_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c index 0748bf44c88086..79ee555768a589 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v4_0.c @@ -407,9 +407,9 @@ static int vce_v4_0_stop(struct amdgpu_device *adev) return 0; } -static int vce_v4_0_early_init(void *handle) +static int vce_v4_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) /* currently only VCN0 support SRIOV */ adev->vce.num_rings = 1; @@ -422,9 +422,9 @@ static int vce_v4_0_early_init(void *handle) return 0; } -static int vce_v4_0_sw_init(void *handle) +static int vce_v4_0_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; unsigned size; @@ -493,10 +493,10 @@ static int vce_v4_0_sw_init(void *handle) return r; } -static int vce_v4_0_sw_fini(void *handle) +static int vce_v4_0_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* free MM table */ amdgpu_virt_free_mm_table(adev); @@ -513,10 +513,10 @@ static int vce_v4_0_sw_fini(void *handle) return amdgpu_vce_sw_fini(adev); } -static int vce_v4_0_hw_init(void *handle) +static int vce_v4_0_hw_init(struct amdgpu_ip_block *ip_block) { int r, i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) r = vce_v4_0_sriov_start(adev); @@ -536,14 +536,14 @@ static int vce_v4_0_hw_init(void *handle) return 0; } -static int vce_v4_0_hw_fini(void *handle) +static int vce_v4_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->vce.idle_work); if (!amdgpu_sriov_vf(adev)) { - /* vce_v4_0_wait_for_idle(handle); */ + /* vce_v4_0_wait_for_idle(ip_block); */ vce_v4_0_stop(adev); } else { /* full access mode, so don't touch any VCE register */ @@ -553,9 +553,9 @@ static int vce_v4_0_hw_fini(void *handle) return 0; } -static int vce_v4_0_suspend(void *handle) +static int vce_v4_0_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r, idx; if (adev->vce.vcpu_bo == NULL) @@ -594,16 +594,16 @@ static int vce_v4_0_suspend(void *handle) AMD_CG_STATE_GATE); } - r = vce_v4_0_hw_fini(adev); + r = vce_v4_0_hw_fini(ip_block); if (r) return r; return amdgpu_vce_suspend(adev); } -static int vce_v4_0_resume(void *handle) +static int vce_v4_0_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r, idx; if (adev->vce.vcpu_bo == NULL) @@ -624,7 +624,7 @@ static int vce_v4_0_resume(void *handle) return r; } - return vce_v4_0_hw_init(adev); + return vce_v4_0_hw_init(ip_block); } static void vce_v4_0_mc_resume(struct amdgpu_device *adev) @@ -691,273 +691,6 @@ static int vce_v4_0_set_clockgating_state(void *handle, return 0; } -#if 0 -static bool vce_v4_0_is_idle(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - u32 mask = 0; - - mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE0) ? 0 : SRBM_STATUS2__VCE0_BUSY_MASK; - mask |= (adev->vce.harvest_config & AMDGPU_VCE_HARVEST_VCE1) ? 0 : SRBM_STATUS2__VCE1_BUSY_MASK; - - return !(RREG32(mmSRBM_STATUS2) & mask); -} - -static int vce_v4_0_wait_for_idle(void *handle) -{ - unsigned i; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - for (i = 0; i < adev->usec_timeout; i++) - if (vce_v4_0_is_idle(handle)) - return 0; - - return -ETIMEDOUT; -} - -#define VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK 0x00000008L /* AUTO_BUSY */ -#define VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK 0x00000010L /* RB0_BUSY */ -#define VCE_STATUS_VCPU_REPORT_RB1_BUSY_MASK 0x00000020L /* RB1_BUSY */ -#define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ - VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) - -static bool vce_v4_0_check_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - u32 srbm_soft_reset = 0; - - /* According to VCE team , we should use VCE_STATUS instead - * SRBM_STATUS.VCE_BUSY bit for busy status checking. - * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE - * instance's registers are accessed - * (0 for 1st instance, 10 for 2nd instance). - * - *VCE_STATUS - *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | - *|----+----+-----------+----+----+----+----------+---------+----| - *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| - * - * VCE team suggest use bit 3--bit 6 for busy status check - */ - mutex_lock(&adev->grbm_idx_mutex); - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); - if (RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); - } - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); - if (RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); - } - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); - mutex_unlock(&adev->grbm_idx_mutex); - - if (srbm_soft_reset) { - adev->vce.srbm_soft_reset = srbm_soft_reset; - return true; - } else { - adev->vce.srbm_soft_reset = 0; - return false; - } -} - -static int vce_v4_0_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - u32 srbm_soft_reset; - - if (!adev->vce.srbm_soft_reset) - return 0; - srbm_soft_reset = adev->vce.srbm_soft_reset; - - if (srbm_soft_reset) { - u32 tmp; - - tmp = RREG32(mmSRBM_SOFT_RESET); - tmp |= srbm_soft_reset; - dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - udelay(50); - - tmp &= ~srbm_soft_reset; - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - /* Wait a little for things to settle down */ - udelay(50); - } - - return 0; -} - -static int vce_v4_0_pre_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (!adev->vce.srbm_soft_reset) - return 0; - - mdelay(5); - - return vce_v4_0_suspend(adev); -} - - -static int vce_v4_0_post_soft_reset(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (!adev->vce.srbm_soft_reset) - return 0; - - mdelay(5); - - return vce_v4_0_resume(adev); -} - -static void vce_v4_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override) -{ - u32 tmp, data; - - tmp = data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_ARB_CTRL)); - if (override) - data |= VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; - else - data &= ~VCE_RB_ARB_CTRL__VCE_CGTT_OVERRIDE_MASK; - - if (tmp != data) - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_RB_ARB_CTRL), data); -} - -static void vce_v4_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, - bool gated) -{ - u32 data; - - /* Set Override to disable Clock Gating */ - vce_v4_0_override_vce_clock_gating(adev, true); - - /* This function enables MGCG which is controlled by firmware. - With the clocks in the gated state the core is still - accessible but the firmware will throttle the clocks on the - fly as necessary. - */ - if (gated) { - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_CLOCK_GATING_B)); - data |= 0x1ff; - data &= ~0xef0000; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_CLOCK_GATING_B), data); - - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING)); - data |= 0x3ff000; - data &= ~0xffc00000; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING), data); - - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING_2)); - data |= 0x2; - data &= ~0x00010000; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING_2), data); - - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_REG_CLOCK_GATING)); - data |= 0x37f; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_REG_CLOCK_GATING), data); - - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_DMA_DCLK_CTRL)); - data |= VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | - VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | - VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | - 0x8; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_DMA_DCLK_CTRL), data); - } else { - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_CLOCK_GATING_B)); - data &= ~0x80010; - data |= 0xe70008; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_CLOCK_GATING_B), data); - - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING)); - data |= 0xffc00000; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING), data); - - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING_2)); - data |= 0x10000; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING_2), data); - - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_REG_CLOCK_GATING)); - data &= ~0xffc00000; - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_REG_CLOCK_GATING), data); - - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_DMA_DCLK_CTRL)); - data &= ~(VCE_UENC_DMA_DCLK_CTRL__WRDMCLK_FORCEON_MASK | - VCE_UENC_DMA_DCLK_CTRL__RDDMCLK_FORCEON_MASK | - VCE_UENC_DMA_DCLK_CTRL__REGCLK_FORCEON_MASK | - 0x8); - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_DMA_DCLK_CTRL), data); - } - vce_v4_0_override_vce_clock_gating(adev, false); -} - -static void vce_v4_0_set_bypass_mode(struct amdgpu_device *adev, bool enable) -{ - u32 tmp = RREG32_SMC(ixGCK_DFS_BYPASS_CNTL); - - if (enable) - tmp |= GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; - else - tmp &= ~GCK_DFS_BYPASS_CNTL__BYPASSECLK_MASK; - - WREG32_SMC(ixGCK_DFS_BYPASS_CNTL, tmp); -} - -static int vce_v4_0_set_clockgating_state(void *handle, - enum amd_clockgating_state state) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - bool enable = (state == AMD_CG_STATE_GATE); - int i; - - if ((adev->asic_type == CHIP_POLARIS10) || - (adev->asic_type == CHIP_TONGA) || - (adev->asic_type == CHIP_FIJI)) - vce_v4_0_set_bypass_mode(adev, enable); - - if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) - return 0; - - mutex_lock(&adev->grbm_idx_mutex); - for (i = 0; i < 2; i++) { - /* Program VCE Instance 0 or 1 if not harvested */ - if (adev->vce.harvest_config & (1 << i)) - continue; - - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i); - - if (enable) { - /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ - uint32_t data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_CLOCK_GATING_A); - data &= ~(0xf | 0xff0); - data |= ((0x0 << 0) | (0x04 << 4)); - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_CLOCK_GATING_A, data); - - /* initialize VCE_UENC_CLOCK_GATING: Clock ON/OFF delay */ - data = RREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING); - data &= ~(0xf | 0xff0); - data |= ((0x0 << 0) | (0x04 << 4)); - WREG32(SOC15_REG_OFFSET(VCE, 0, mmVCE_UENC_CLOCK_GATING, data); - } - - vce_v4_0_set_vce_sw_clock_gating(adev, enable); - } - - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); - mutex_unlock(&adev->grbm_idx_mutex); - - return 0; -} -#endif - static int vce_v4_0_set_powergating_state(void *handle, enum amd_powergating_state state) { @@ -1076,19 +809,12 @@ static int vce_v4_0_process_interrupt(struct amdgpu_device *adev, const struct amd_ip_funcs vce_v4_0_ip_funcs = { .name = "vce_v4_0", .early_init = vce_v4_0_early_init, - .late_init = NULL, .sw_init = vce_v4_0_sw_init, .sw_fini = vce_v4_0_sw_fini, .hw_init = vce_v4_0_hw_init, .hw_fini = vce_v4_0_hw_fini, .suspend = vce_v4_0_suspend, .resume = vce_v4_0_resume, - .is_idle = NULL /* vce_v4_0_is_idle */, - .wait_for_idle = NULL /* vce_v4_0_wait_for_idle */, - .check_soft_reset = NULL /* vce_v4_0_check_soft_reset */, - .pre_soft_reset = NULL /* vce_v4_0_pre_soft_reset */, - .soft_reset = NULL /* vce_v4_0_soft_reset */, - .post_soft_reset = NULL /* vce_v4_0_post_soft_reset */, .set_clockgating_state = vce_v4_0_set_clockgating_state, .set_powergating_state = vce_v4_0_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index ecdfbfefd66ad2..10e99c926fb8b0 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -95,14 +95,14 @@ static void vcn_v1_0_ring_begin_use(struct amdgpu_ring *ring); /** * vcn_v1_0_early_init - set function pointers and load microcode * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers * Load microcode from filesystem */ -static int vcn_v1_0_early_init(void *handle) +static int vcn_v1_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->vcn.num_enc_rings = 2; @@ -110,7 +110,7 @@ static int vcn_v1_0_early_init(void *handle) vcn_v1_0_set_enc_ring_funcs(adev); vcn_v1_0_set_irq_funcs(adev); - jpeg_v1_0_early_init(handle); + jpeg_v1_0_early_init(ip_block); return amdgpu_vcn_early_init(adev); } @@ -118,17 +118,17 @@ static int vcn_v1_0_early_init(void *handle) /** * vcn_v1_0_sw_init - sw init for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int vcn_v1_0_sw_init(void *handle) +static int vcn_v1_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int i, r; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_1_0); uint32_t *ptr; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* VCN DEC TRAP */ r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN, @@ -197,7 +197,7 @@ static int vcn_v1_0_sw_init(void *handle) amdgpu_vcn_fwlog_init(adev->vcn.inst); } - r = jpeg_v1_0_sw_init(handle); + r = jpeg_v1_0_sw_init(ip_block); /* Allocate memory for VCN IP Dump buffer */ ptr = kcalloc(adev->vcn.num_vcn_inst * reg_count, sizeof(uint32_t), GFP_KERNEL); @@ -213,20 +213,20 @@ static int vcn_v1_0_sw_init(void *handle) /** * vcn_v1_0_sw_fini - sw fini for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * VCN suspend and free up sw allocation */ -static int vcn_v1_0_sw_fini(void *handle) +static int vcn_v1_0_sw_fini(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_vcn_suspend(adev); if (r) return r; - jpeg_v1_0_sw_fini(handle); + jpeg_v1_0_sw_fini(ip_block); r = amdgpu_vcn_sw_fini(adev); @@ -238,13 +238,13 @@ static int vcn_v1_0_sw_fini(void *handle) /** * vcn_v1_0_hw_init - start and test VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int vcn_v1_0_hw_init(void *handle) +static int vcn_v1_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = &adev->vcn.inst->ring_dec; int i, r; @@ -268,13 +268,13 @@ static int vcn_v1_0_hw_init(void *handle) /** * vcn_v1_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the VCN block, mark ring as not ready any more */ -static int vcn_v1_0_hw_fini(void *handle) +static int vcn_v1_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -290,14 +290,14 @@ static int vcn_v1_0_hw_fini(void *handle) /** * vcn_v1_0_suspend - suspend VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend VCN block */ -static int vcn_v1_0_suspend(void *handle) +static int vcn_v1_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; bool idle_work_unexecuted; idle_work_unexecuted = cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -306,7 +306,7 @@ static int vcn_v1_0_suspend(void *handle) amdgpu_dpm_enable_uvd(adev, false); } - r = vcn_v1_0_hw_fini(adev); + r = vcn_v1_0_hw_fini(ip_block); if (r) return r; @@ -318,20 +318,19 @@ static int vcn_v1_0_suspend(void *handle) /** * vcn_v1_0_resume - resume VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init VCN block */ -static int vcn_v1_0_resume(void *handle) +static int vcn_v1_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vcn_resume(adev); + r = amdgpu_vcn_resume(ip_block->adev); if (r) return r; - r = vcn_v1_0_hw_init(adev); + r = vcn_v1_0_hw_init(ip_block); return r; } @@ -1384,9 +1383,9 @@ static bool vcn_v1_0_is_idle(void *handle) return (RREG32_SOC15(VCN, 0, mmUVD_STATUS) == UVD_STATUS__IDLE); } -static int vcn_v1_0_wait_for_idle(void *handle) +static int vcn_v1_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; ret = SOC15_WAIT_ON_RREG(VCN, 0, mmUVD_STATUS, UVD_STATUS__IDLE, @@ -1925,9 +1924,9 @@ void vcn_v1_0_ring_end_use(struct amdgpu_ring *ring) mutex_unlock(&ring->adev->vcn.vcn1_jpeg1_workaround); } -static void vcn_v1_0_print_ip_state(void *handle, struct drm_printer *p) +static void vcn_v1_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_1_0); uint32_t inst_off, is_powered; @@ -1957,9 +1956,9 @@ static void vcn_v1_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void vcn_v1_0_dump_ip_state(void *handle) +static void vcn_v1_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; bool is_powered; uint32_t inst_off; @@ -1988,7 +1987,6 @@ static void vcn_v1_0_dump_ip_state(void *handle) static const struct amd_ip_funcs vcn_v1_0_ip_funcs = { .name = "vcn_v1_0", .early_init = vcn_v1_0_early_init, - .late_init = NULL, .sw_init = vcn_v1_0_sw_init, .sw_fini = vcn_v1_0_sw_fini, .hw_init = vcn_v1_0_hw_init, @@ -1997,10 +1995,6 @@ static const struct amd_ip_funcs vcn_v1_0_ip_funcs = { .resume = vcn_v1_0_resume, .is_idle = vcn_v1_0_is_idle, .wait_for_idle = vcn_v1_0_wait_for_idle, - .check_soft_reset = NULL /* vcn_v1_0_check_soft_reset */, - .pre_soft_reset = NULL /* vcn_v1_0_pre_soft_reset */, - .soft_reset = NULL /* vcn_v1_0_soft_reset */, - .post_soft_reset = NULL /* vcn_v1_0_post_soft_reset */, .set_clockgating_state = vcn_v1_0_set_clockgating_state, .set_powergating_state = vcn_v1_0_set_powergating_state, .dump_ip_state = vcn_v1_0_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c index bfd067e2d2f1d2..e0322cbca3ecf6 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c @@ -100,14 +100,14 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev); /** * vcn_v2_0_early_init - set function pointers and load microcode * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers * Load microcode from filesystem */ -static int vcn_v2_0_early_init(void *handle) +static int vcn_v2_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) adev->vcn.num_enc_rings = 1; @@ -124,17 +124,17 @@ static int vcn_v2_0_early_init(void *handle) /** * vcn_v2_0_sw_init - sw init for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int vcn_v2_0_sw_init(void *handle) +static int vcn_v2_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int i, r; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_0); uint32_t *ptr; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; volatile struct amdgpu_fw_shared *fw_shared; /* VCN DEC TRAP */ @@ -237,14 +237,14 @@ static int vcn_v2_0_sw_init(void *handle) /** * vcn_v2_0_sw_fini - sw fini for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * VCN suspend and free up sw allocation */ -static int vcn_v2_0_sw_fini(void *handle) +static int vcn_v2_0_sw_fini(struct amdgpu_ip_block *ip_block) { int r, idx; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; volatile struct amdgpu_fw_shared *fw_shared = adev->vcn.inst->fw_shared.cpu_addr; if (drm_dev_enter(adev_to_drm(adev), &idx)) { @@ -268,13 +268,13 @@ static int vcn_v2_0_sw_fini(void *handle) /** * vcn_v2_0_hw_init - start and test VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int vcn_v2_0_hw_init(void *handle) +static int vcn_v2_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring = &adev->vcn.inst->ring_dec; int i, r; @@ -305,13 +305,13 @@ static int vcn_v2_0_hw_init(void *handle) /** * vcn_v2_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the VCN block, mark ring as not ready any more */ -static int vcn_v2_0_hw_fini(void *handle) +static int vcn_v2_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -326,20 +326,19 @@ static int vcn_v2_0_hw_fini(void *handle) /** * vcn_v2_0_suspend - suspend VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend VCN block */ -static int vcn_v2_0_suspend(void *handle) +static int vcn_v2_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = vcn_v2_0_hw_fini(adev); + r = vcn_v2_0_hw_fini(ip_block); if (r) return r; - r = amdgpu_vcn_suspend(adev); + r = amdgpu_vcn_suspend(ip_block->adev); return r; } @@ -347,20 +346,19 @@ static int vcn_v2_0_suspend(void *handle) /** * vcn_v2_0_resume - resume VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init VCN block */ -static int vcn_v2_0_resume(void *handle) +static int vcn_v2_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vcn_resume(adev); + r = amdgpu_vcn_resume(ip_block->adev); if (r) return r; - r = vcn_v2_0_hw_init(adev); + r = vcn_v2_0_hw_init(ip_block); return r; } @@ -1326,9 +1324,9 @@ static bool vcn_v2_0_is_idle(void *handle) return (RREG32_SOC15(VCN, 0, mmUVD_STATUS) == UVD_STATUS__IDLE); } -static int vcn_v2_0_wait_for_idle(void *handle) +static int vcn_v2_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int ret; ret = SOC15_WAIT_ON_RREG(VCN, 0, mmUVD_STATUS, UVD_STATUS__IDLE, @@ -2034,9 +2032,9 @@ static int vcn_v2_0_start_sriov(struct amdgpu_device *adev) return vcn_v2_0_start_mmsch(adev, &adev->virt.mm_table); } -static void vcn_v2_0_print_ip_state(void *handle, struct drm_printer *p) +static void vcn_v2_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_0); uint32_t inst_off, is_powered; @@ -2066,9 +2064,9 @@ static void vcn_v2_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void vcn_v2_0_dump_ip_state(void *handle) +static void vcn_v2_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; bool is_powered; uint32_t inst_off; @@ -2097,7 +2095,6 @@ static void vcn_v2_0_dump_ip_state(void *handle) static const struct amd_ip_funcs vcn_v2_0_ip_funcs = { .name = "vcn_v2_0", .early_init = vcn_v2_0_early_init, - .late_init = NULL, .sw_init = vcn_v2_0_sw_init, .sw_fini = vcn_v2_0_sw_fini, .hw_init = vcn_v2_0_hw_init, @@ -2106,10 +2103,6 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = { .resume = vcn_v2_0_resume, .is_idle = vcn_v2_0_is_idle, .wait_for_idle = vcn_v2_0_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v2_0_set_clockgating_state, .set_powergating_state = vcn_v2_0_set_powergating_state, .dump_ip_state = vcn_v2_0_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index 04e9e806e3187f..6aa08281d09458 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -110,14 +110,14 @@ static int amdgpu_ih_clientid_vcns[] = { /** * vcn_v2_5_early_init - set function pointers and load microcode * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers * Load microcode from filesystem */ -static int vcn_v2_5_early_init(void *handle) +static int vcn_v2_5_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) { adev->vcn.num_vcn_inst = 2; @@ -151,17 +151,17 @@ static int vcn_v2_5_early_init(void *handle) /** * vcn_v2_5_sw_init - sw init for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int vcn_v2_5_sw_init(void *handle) +static int vcn_v2_5_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int i, j, r; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5); uint32_t *ptr; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; for (j = 0; j < adev->vcn.num_vcn_inst; j++) { if (adev->vcn.harvest_config & (1 << j)) @@ -295,14 +295,14 @@ static int vcn_v2_5_sw_init(void *handle) /** * vcn_v2_5_sw_fini - sw fini for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * VCN suspend and free up sw allocation */ -static int vcn_v2_5_sw_fini(void *handle) +static int vcn_v2_5_sw_fini(struct amdgpu_ip_block *ip_block) { int i, r, idx; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; volatile struct amdgpu_fw_shared *fw_shared; if (drm_dev_enter(adev_to_drm(adev), &idx)) { @@ -333,13 +333,13 @@ static int vcn_v2_5_sw_fini(void *handle) /** * vcn_v2_5_hw_init - start and test VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int vcn_v2_5_hw_init(void *handle) +static int vcn_v2_5_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, j, r = 0; @@ -381,13 +381,13 @@ static int vcn_v2_5_hw_init(void *handle) /** * vcn_v2_5_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the VCN block, mark ring as not ready any more */ -static int vcn_v2_5_hw_fini(void *handle) +static int vcn_v2_5_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -411,20 +411,19 @@ static int vcn_v2_5_hw_fini(void *handle) /** * vcn_v2_5_suspend - suspend VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend VCN block */ -static int vcn_v2_5_suspend(void *handle) +static int vcn_v2_5_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = vcn_v2_5_hw_fini(adev); + r = vcn_v2_5_hw_fini(ip_block); if (r) return r; - r = amdgpu_vcn_suspend(adev); + r = amdgpu_vcn_suspend(ip_block->adev); return r; } @@ -432,20 +431,19 @@ static int vcn_v2_5_suspend(void *handle) /** * vcn_v2_5_resume - resume VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init VCN block */ -static int vcn_v2_5_resume(void *handle) +static int vcn_v2_5_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vcn_resume(adev); + r = amdgpu_vcn_resume(ip_block->adev); if (r) return r; - r = vcn_v2_5_hw_init(adev); + r = vcn_v2_5_hw_init(ip_block); return r; } @@ -1786,9 +1784,9 @@ static bool vcn_v2_5_is_idle(void *handle) return ret; } -static int vcn_v2_5_wait_for_idle(void *handle) +static int vcn_v2_5_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, ret = 0; for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { @@ -1926,9 +1924,9 @@ static void vcn_v2_5_set_irq_funcs(struct amdgpu_device *adev) } } -static void vcn_v2_5_print_ip_state(void *handle, struct drm_printer *p) +static void vcn_v2_5_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_2_5); uint32_t inst_off, is_powered; @@ -1958,9 +1956,9 @@ static void vcn_v2_5_print_ip_state(void *handle, struct drm_printer *p) } } -static void vcn_v2_5_dump_ip_state(void *handle) +static void vcn_v2_5_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; bool is_powered; uint32_t inst_off; @@ -1989,7 +1987,6 @@ static void vcn_v2_5_dump_ip_state(void *handle) static const struct amd_ip_funcs vcn_v2_5_ip_funcs = { .name = "vcn_v2_5", .early_init = vcn_v2_5_early_init, - .late_init = NULL, .sw_init = vcn_v2_5_sw_init, .sw_fini = vcn_v2_5_sw_fini, .hw_init = vcn_v2_5_hw_init, @@ -1998,10 +1995,6 @@ static const struct amd_ip_funcs vcn_v2_5_ip_funcs = { .resume = vcn_v2_5_resume, .is_idle = vcn_v2_5_is_idle, .wait_for_idle = vcn_v2_5_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v2_5_set_clockgating_state, .set_powergating_state = vcn_v2_5_set_powergating_state, .dump_ip_state = vcn_v2_5_dump_ip_state, @@ -2011,7 +2004,6 @@ static const struct amd_ip_funcs vcn_v2_5_ip_funcs = { static const struct amd_ip_funcs vcn_v2_6_ip_funcs = { .name = "vcn_v2_6", .early_init = vcn_v2_5_early_init, - .late_init = NULL, .sw_init = vcn_v2_5_sw_init, .sw_fini = vcn_v2_5_sw_fini, .hw_init = vcn_v2_5_hw_init, @@ -2020,10 +2012,6 @@ static const struct amd_ip_funcs vcn_v2_6_ip_funcs = { .resume = vcn_v2_5_resume, .is_idle = vcn_v2_5_is_idle, .wait_for_idle = vcn_v2_5_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v2_5_set_clockgating_state, .set_powergating_state = vcn_v2_5_set_powergating_state, .dump_ip_state = vcn_v2_5_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c index 65dd68b322806e..6732ad7f16f549 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c @@ -116,14 +116,14 @@ static void vcn_v3_0_enc_ring_set_wptr(struct amdgpu_ring *ring); /** * vcn_v3_0_early_init - set function pointers and load microcode * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers * Load microcode from filesystem */ -static int vcn_v3_0_early_init(void *handle) +static int vcn_v3_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) { adev->vcn.num_vcn_inst = VCN_INSTANCES_SIENNA_CICHLID; @@ -153,18 +153,18 @@ static int vcn_v3_0_early_init(void *handle) /** * vcn_v3_0_sw_init - sw init for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int vcn_v3_0_sw_init(void *handle) +static int vcn_v3_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; int i, j, r; int vcn_doorbell_index = 0; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_3_0); uint32_t *ptr; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = amdgpu_vcn_sw_init(adev); if (r) @@ -299,13 +299,13 @@ static int vcn_v3_0_sw_init(void *handle) /** * vcn_v3_0_sw_fini - sw fini for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * VCN suspend and free up sw allocation */ -static int vcn_v3_0_sw_fini(void *handle) +static int vcn_v3_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r, idx; if (drm_dev_enter(adev_to_drm(adev), &idx)) { @@ -338,13 +338,13 @@ static int vcn_v3_0_sw_fini(void *handle) /** * vcn_v3_0_hw_init - start and test VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int vcn_v3_0_hw_init(void *handle) +static int vcn_v3_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, j, r; @@ -413,13 +413,13 @@ static int vcn_v3_0_hw_init(void *handle) /** * vcn_v3_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the VCN block, mark ring as not ready any more */ -static int vcn_v3_0_hw_fini(void *handle) +static int vcn_v3_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -443,20 +443,19 @@ static int vcn_v3_0_hw_fini(void *handle) /** * vcn_v3_0_suspend - suspend VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend VCN block */ -static int vcn_v3_0_suspend(void *handle) +static int vcn_v3_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = vcn_v3_0_hw_fini(adev); + r = vcn_v3_0_hw_fini(ip_block); if (r) return r; - r = amdgpu_vcn_suspend(adev); + r = amdgpu_vcn_suspend(ip_block->adev); return r; } @@ -464,20 +463,19 @@ static int vcn_v3_0_suspend(void *handle) /** * vcn_v3_0_resume - resume VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init VCN block */ -static int vcn_v3_0_resume(void *handle) +static int vcn_v3_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vcn_resume(adev); + r = amdgpu_vcn_resume(ip_block->adev); if (r) return r; - r = vcn_v3_0_hw_init(adev); + r = vcn_v3_0_hw_init(ip_block); return r; } @@ -2116,9 +2114,9 @@ static bool vcn_v3_0_is_idle(void *handle) return ret; } -static int vcn_v3_0_wait_for_idle(void *handle) +static int vcn_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, ret = 0; for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { @@ -2251,9 +2249,9 @@ static void vcn_v3_0_set_irq_funcs(struct amdgpu_device *adev) } } -static void vcn_v3_0_print_ip_state(void *handle, struct drm_printer *p) +static void vcn_v3_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_3_0); uint32_t inst_off; @@ -2284,9 +2282,9 @@ static void vcn_v3_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void vcn_v3_0_dump_ip_state(void *handle) +static void vcn_v3_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; bool is_powered; uint32_t inst_off; @@ -2315,7 +2313,6 @@ static void vcn_v3_0_dump_ip_state(void *handle) static const struct amd_ip_funcs vcn_v3_0_ip_funcs = { .name = "vcn_v3_0", .early_init = vcn_v3_0_early_init, - .late_init = NULL, .sw_init = vcn_v3_0_sw_init, .sw_fini = vcn_v3_0_sw_fini, .hw_init = vcn_v3_0_hw_init, @@ -2324,10 +2321,6 @@ static const struct amd_ip_funcs vcn_v3_0_ip_funcs = { .resume = vcn_v3_0_resume, .is_idle = vcn_v3_0_is_idle, .wait_for_idle = vcn_v3_0_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v3_0_set_clockgating_state, .set_powergating_state = vcn_v3_0_set_powergating_state, .dump_ip_state = vcn_v3_0_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 26c6f10a8c8fae..fcc8511e91ee0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -106,14 +106,14 @@ static void vcn_v4_0_set_ras_funcs(struct amdgpu_device *adev); /** * vcn_v4_0_early_init - set function pointers and load microcode * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers * Load microcode from filesystem */ -static int vcn_v4_0_early_init(void *handle) +static int vcn_v4_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; if (amdgpu_sriov_vf(adev)) { @@ -164,14 +164,14 @@ static int vcn_v4_0_fw_shared_init(struct amdgpu_device *adev, int inst_idx) /** * vcn_v4_0_sw_init - sw init for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int vcn_v4_0_sw_init(void *handle) +static int vcn_v4_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0); uint32_t *ptr; @@ -225,6 +225,10 @@ static int vcn_v4_0_sw_init(void *handle) vcn_v4_0_fw_shared_init(adev, i); } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->vcn.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->vcn.inst[0].ring_enc[0]); + if (amdgpu_sriov_vf(adev)) { r = amdgpu_virt_alloc_mm_table(adev); if (r) @@ -247,19 +251,23 @@ static int vcn_v4_0_sw_init(void *handle) adev->vcn.ip_dump = ptr; } + r = amdgpu_vcn_sysfs_reset_mask_init(adev); + if (r) + return r; + return 0; } /** * vcn_v4_0_sw_fini - sw fini for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * VCN suspend and free up sw allocation */ -static int vcn_v4_0_sw_fini(void *handle) +static int vcn_v4_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r, idx; if (drm_dev_enter(adev_to_drm(adev), &idx)) { @@ -284,6 +292,7 @@ static int vcn_v4_0_sw_fini(void *handle) if (r) return r; + amdgpu_vcn_sysfs_reset_mask_fini(adev); r = amdgpu_vcn_sw_fini(adev); kfree(adev->vcn.ip_dump); @@ -294,13 +303,13 @@ static int vcn_v4_0_sw_fini(void *handle) /** * vcn_v4_0_hw_init - start and test VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int vcn_v4_0_hw_init(void *handle) +static int vcn_v4_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r; @@ -341,13 +350,13 @@ static int vcn_v4_0_hw_init(void *handle) /** * vcn_v4_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the VCN block, mark ring as not ready any more */ -static int vcn_v4_0_hw_fini(void *handle) +static int vcn_v4_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -372,20 +381,19 @@ static int vcn_v4_0_hw_fini(void *handle) /** * vcn_v4_0_suspend - suspend VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend VCN block */ -static int vcn_v4_0_suspend(void *handle) +static int vcn_v4_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = vcn_v4_0_hw_fini(adev); + r = vcn_v4_0_hw_fini(ip_block); if (r) return r; - r = amdgpu_vcn_suspend(adev); + r = amdgpu_vcn_suspend(ip_block->adev); return r; } @@ -393,20 +401,19 @@ static int vcn_v4_0_suspend(void *handle) /** * vcn_v4_0_resume - resume VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init VCN block */ -static int vcn_v4_0_resume(void *handle) +static int vcn_v4_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vcn_resume(adev); + r = amdgpu_vcn_resume(ip_block->adev); if (r) return r; - r = vcn_v4_0_hw_init(adev); + r = vcn_v4_0_hw_init(ip_block); return r; } @@ -1975,13 +1982,13 @@ static bool vcn_v4_0_is_idle(void *handle) /** * vcn_v4_0_wait_for_idle - wait for VCN block idle * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Wait for VCN block idle */ -static int vcn_v4_0_wait_for_idle(void *handle) +static int vcn_v4_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, ret = 0; for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { @@ -2158,9 +2165,9 @@ static void vcn_v4_0_set_irq_funcs(struct amdgpu_device *adev) } } -static void vcn_v4_0_print_ip_state(void *handle, struct drm_printer *p) +static void vcn_v4_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0); uint32_t inst_off, is_powered; @@ -2190,9 +2197,9 @@ static void vcn_v4_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void vcn_v4_0_dump_ip_state(void *handle) +static void vcn_v4_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; bool is_powered; uint32_t inst_off; @@ -2222,7 +2229,6 @@ static void vcn_v4_0_dump_ip_state(void *handle) static const struct amd_ip_funcs vcn_v4_0_ip_funcs = { .name = "vcn_v4_0", .early_init = vcn_v4_0_early_init, - .late_init = NULL, .sw_init = vcn_v4_0_sw_init, .sw_fini = vcn_v4_0_sw_fini, .hw_init = vcn_v4_0_hw_init, @@ -2231,10 +2237,6 @@ static const struct amd_ip_funcs vcn_v4_0_ip_funcs = { .resume = vcn_v4_0_resume, .is_idle = vcn_v4_0_is_idle, .wait_for_idle = vcn_v4_0_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v4_0_set_clockgating_state, .set_powergating_state = vcn_v4_0_set_powergating_state, .dump_ip_state = vcn_v4_0_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c index 0fda703363004f..3f69b9b2bcd079 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c @@ -95,16 +95,23 @@ static void vcn_v4_0_3_unified_ring_set_wptr(struct amdgpu_ring *ring); static void vcn_v4_0_3_set_ras_funcs(struct amdgpu_device *adev); static void vcn_v4_0_3_enable_ras(struct amdgpu_device *adev, int inst_idx, bool indirect); + +static inline bool vcn_v4_0_3_normalizn_reqd(struct amdgpu_device *adev) +{ + return (amdgpu_sriov_vf(adev) || + (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4))); +} + /** * vcn_v4_0_3_early_init - set function pointers * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers */ -static int vcn_v4_0_3_early_init(void *handle) +static int vcn_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* re-use enc ring as unified ring */ adev->vcn.num_enc_rings = 1; @@ -116,16 +123,30 @@ static int vcn_v4_0_3_early_init(void *handle) return amdgpu_vcn_early_init(adev); } +static int vcn_v4_0_3_fw_shared_init(struct amdgpu_device *adev, int inst_idx) +{ + struct amdgpu_vcn4_fw_shared *fw_shared; + + fw_shared = adev->vcn.inst[inst_idx].fw_shared.cpu_addr; + fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE); + fw_shared->sq.is_enabled = 1; + + if (amdgpu_vcnfw_log) + amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst_idx]); + + return 0; +} + /** * vcn_v4_0_3_sw_init - sw init for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int vcn_v4_0_3_sw_init(void *handle) +static int vcn_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r, vcn_inst; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0_3); @@ -148,8 +169,6 @@ static int vcn_v4_0_3_sw_init(void *handle) return r; for (i = 0; i < adev->vcn.num_vcn_inst; i++) { - volatile struct amdgpu_vcn4_fw_shared *fw_shared; - vcn_inst = GET_INST(VCN, i); ring = &adev->vcn.inst[i].ring_enc[0]; @@ -172,14 +191,13 @@ static int vcn_v4_0_3_sw_init(void *handle) if (r) return r; - fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr; - fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE); - fw_shared->sq.is_enabled = true; - - if (amdgpu_vcnfw_log) - amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]); + vcn_v4_0_3_fw_shared_init(adev, i); } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->vcn.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->vcn.inst[0].ring_enc[0]); + if (amdgpu_sriov_vf(adev)) { r = amdgpu_virt_alloc_mm_table(adev); if (r) @@ -206,19 +224,23 @@ static int vcn_v4_0_3_sw_init(void *handle) adev->vcn.ip_dump = ptr; } + r = amdgpu_vcn_sysfs_reset_mask_init(adev); + if (r) + return r; + return 0; } /** * vcn_v4_0_3_sw_fini - sw fini for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * VCN suspend and free up sw allocation */ -static int vcn_v4_0_3_sw_fini(void *handle) +static int vcn_v4_0_3_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r, idx; if (drm_dev_enter(&adev->ddev, &idx)) { @@ -239,6 +261,7 @@ static int vcn_v4_0_3_sw_fini(void *handle) if (r) return r; + amdgpu_vcn_sysfs_reset_mask_fini(adev); r = amdgpu_vcn_sw_fini(adev); kfree(adev->vcn.ip_dump); @@ -249,13 +272,13 @@ static int vcn_v4_0_3_sw_fini(void *handle) /** * vcn_v4_0_3_hw_init - start and test VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int vcn_v4_0_3_hw_init(void *handle) +static int vcn_v4_0_3_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r, vcn_inst; @@ -273,6 +296,8 @@ static int vcn_v4_0_3_hw_init(void *handle) } } else { for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { + struct amdgpu_vcn4_fw_shared *fw_shared; + vcn_inst = GET_INST(VCN, i); ring = &adev->vcn.inst[i].ring_enc[0]; @@ -296,6 +321,11 @@ static int vcn_v4_0_3_hw_init(void *handle) regVCN_RB1_DB_CTRL); } + /* Re-init fw_shared when RAS fatal error occurred */ + fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr; + if (!fw_shared->sq.is_enabled) + vcn_v4_0_3_fw_shared_init(adev, i); + r = amdgpu_ring_test_helper(ring); if (r) return r; @@ -308,13 +338,13 @@ static int vcn_v4_0_3_hw_init(void *handle) /** * vcn_v4_0_3_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the VCN block, mark ring as not ready any more */ -static int vcn_v4_0_3_hw_fini(void *handle) +static int vcn_v4_0_3_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -327,20 +357,19 @@ static int vcn_v4_0_3_hw_fini(void *handle) /** * vcn_v4_0_3_suspend - suspend VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend VCN block */ -static int vcn_v4_0_3_suspend(void *handle) +static int vcn_v4_0_3_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = vcn_v4_0_3_hw_fini(adev); + r = vcn_v4_0_3_hw_fini(ip_block); if (r) return r; - r = amdgpu_vcn_suspend(adev); + r = amdgpu_vcn_suspend(ip_block->adev); return r; } @@ -348,20 +377,19 @@ static int vcn_v4_0_3_suspend(void *handle) /** * vcn_v4_0_3_resume - resume VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init VCN block */ -static int vcn_v4_0_3_resume(void *handle) +static int vcn_v4_0_3_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; int r; - r = amdgpu_vcn_resume(adev); + r = amdgpu_vcn_resume(ip_block->adev); if (r) return r; - r = vcn_v4_0_3_hw_init(adev); + r = vcn_v4_0_3_hw_init(ip_block); return r; } @@ -1430,8 +1458,8 @@ static uint64_t vcn_v4_0_3_unified_ring_get_wptr(struct amdgpu_ring *ring) static void vcn_v4_0_3_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t reg, uint32_t val, uint32_t mask) { - /* For VF, only local offsets should be used */ - if (amdgpu_sriov_vf(ring->adev)) + /* Use normalized offsets when required */ + if (vcn_v4_0_3_normalizn_reqd(ring->adev)) reg = NORMALIZE_VCN_REG_OFFSET(reg); amdgpu_ring_write(ring, VCN_ENC_CMD_REG_WAIT); @@ -1442,8 +1470,8 @@ static void vcn_v4_0_3_enc_ring_emit_reg_wait(struct amdgpu_ring *ring, uint32_t static void vcn_v4_0_3_enc_ring_emit_wreg(struct amdgpu_ring *ring, uint32_t reg, uint32_t val) { - /* For VF, only local offsets should be used */ - if (amdgpu_sriov_vf(ring->adev)) + /* Use normalized offsets when required */ + if (vcn_v4_0_3_normalizn_reqd(ring->adev)) reg = NORMALIZE_VCN_REG_OFFSET(reg); amdgpu_ring_write(ring, VCN_ENC_CMD_REG_WRITE); @@ -1567,13 +1595,13 @@ static bool vcn_v4_0_3_is_idle(void *handle) /** * vcn_v4_0_3_wait_for_idle - wait for VCN block idle * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Wait for VCN block idle */ -static int vcn_v4_0_3_wait_for_idle(void *handle) +static int vcn_v4_0_3_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, ret = 0; for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { @@ -1733,9 +1761,9 @@ static void vcn_v4_0_3_set_irq_funcs(struct amdgpu_device *adev) adev->vcn.inst->irq.funcs = &vcn_v4_0_3_irq_funcs; } -static void vcn_v4_0_3_print_ip_state(void *handle, struct drm_printer *p) +static void vcn_v4_0_3_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0_3); uint32_t inst_off, is_powered; @@ -1765,9 +1793,9 @@ static void vcn_v4_0_3_print_ip_state(void *handle, struct drm_printer *p) } } -static void vcn_v4_0_3_dump_ip_state(void *handle) +static void vcn_v4_0_3_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; bool is_powered; uint32_t inst_off, inst_id; @@ -1798,7 +1826,6 @@ static void vcn_v4_0_3_dump_ip_state(void *handle) static const struct amd_ip_funcs vcn_v4_0_3_ip_funcs = { .name = "vcn_v4_0_3", .early_init = vcn_v4_0_3_early_init, - .late_init = NULL, .sw_init = vcn_v4_0_3_sw_init, .sw_fini = vcn_v4_0_3_sw_fini, .hw_init = vcn_v4_0_3_hw_init, @@ -1807,10 +1834,6 @@ static const struct amd_ip_funcs vcn_v4_0_3_ip_funcs = { .resume = vcn_v4_0_3_resume, .is_idle = vcn_v4_0_3_is_idle, .wait_for_idle = vcn_v4_0_3_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v4_0_3_set_clockgating_state, .set_powergating_state = vcn_v4_0_3_set_powergating_state, .dump_ip_state = vcn_v4_0_3_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c index 9d4f5352a62c8c..71961fb3f7ff5f 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c @@ -104,14 +104,14 @@ static void vcn_v4_0_5_unified_ring_set_wptr(struct amdgpu_ring *ring); /** * vcn_v4_0_5_early_init - set function pointers and load microcode * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers * Load microcode from filesystem */ -static int vcn_v4_0_5_early_init(void *handle) +static int vcn_v4_0_5_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* re-use enc ring as unified ring */ adev->vcn.num_enc_rings = 1; @@ -124,14 +124,14 @@ static int vcn_v4_0_5_early_init(void *handle) /** * vcn_v4_0_5_sw_init - sw init for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int vcn_v4_0_5_sw_init(void *handle) +static int vcn_v4_0_5_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0_5); uint32_t *ptr; @@ -220,13 +220,13 @@ static int vcn_v4_0_5_sw_init(void *handle) /** * vcn_v4_0_5_sw_fini - sw fini for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * VCN suspend and free up sw allocation */ -static int vcn_v4_0_5_sw_fini(void *handle) +static int vcn_v4_0_5_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r, idx; if (drm_dev_enter(adev_to_drm(adev), &idx)) { @@ -261,13 +261,13 @@ static int vcn_v4_0_5_sw_fini(void *handle) /** * vcn_v4_0_5_hw_init - start and test VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int vcn_v4_0_5_hw_init(void *handle) +static int vcn_v4_0_5_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r; @@ -291,13 +291,13 @@ static int vcn_v4_0_5_hw_init(void *handle) /** * vcn_v4_0_5_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the VCN block, mark ring as not ready any more */ -static int vcn_v4_0_5_hw_fini(void *handle) +static int vcn_v4_0_5_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -320,20 +320,19 @@ static int vcn_v4_0_5_hw_fini(void *handle) /** * vcn_v4_0_5_suspend - suspend VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend VCN block */ -static int vcn_v4_0_5_suspend(void *handle) +static int vcn_v4_0_5_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = vcn_v4_0_5_hw_fini(adev); + r = vcn_v4_0_5_hw_fini(ip_block); if (r) return r; - r = amdgpu_vcn_suspend(adev); + r = amdgpu_vcn_suspend(ip_block->adev); return r; } @@ -341,20 +340,19 @@ static int vcn_v4_0_5_suspend(void *handle) /** * vcn_v4_0_5_resume - resume VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init VCN block */ -static int vcn_v4_0_5_resume(void *handle) +static int vcn_v4_0_5_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vcn_resume(adev); + r = amdgpu_vcn_resume(ip_block->adev); if (r) return r; - r = vcn_v4_0_5_hw_init(adev); + r = vcn_v4_0_5_hw_init(ip_block); return r; } @@ -1469,13 +1467,13 @@ static bool vcn_v4_0_5_is_idle(void *handle) /** * vcn_v4_0_5_wait_for_idle - wait for VCN block idle * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Wait for VCN block idle */ -static int vcn_v4_0_5_wait_for_idle(void *handle) +static int vcn_v4_0_5_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, ret = 0; for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { @@ -1616,9 +1614,9 @@ static void vcn_v4_0_5_set_irq_funcs(struct amdgpu_device *adev) } } -static void vcn_v4_0_5_print_ip_state(void *handle, struct drm_printer *p) +static void vcn_v4_0_5_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_4_0_5); uint32_t inst_off, is_powered; @@ -1648,9 +1646,9 @@ static void vcn_v4_0_5_print_ip_state(void *handle, struct drm_printer *p) } } -static void vcn_v4_0_5_dump_ip_state(void *handle) +static void vcn_v4_0_5_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; bool is_powered; uint32_t inst_off; @@ -1680,7 +1678,6 @@ static void vcn_v4_0_5_dump_ip_state(void *handle) static const struct amd_ip_funcs vcn_v4_0_5_ip_funcs = { .name = "vcn_v4_0_5", .early_init = vcn_v4_0_5_early_init, - .late_init = NULL, .sw_init = vcn_v4_0_5_sw_init, .sw_fini = vcn_v4_0_5_sw_fini, .hw_init = vcn_v4_0_5_hw_init, @@ -1689,10 +1686,6 @@ static const struct amd_ip_funcs vcn_v4_0_5_ip_funcs = { .resume = vcn_v4_0_5_resume, .is_idle = vcn_v4_0_5_is_idle, .wait_for_idle = vcn_v4_0_5_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v4_0_5_set_clockgating_state, .set_powergating_state = vcn_v4_0_5_set_powergating_state, .dump_ip_state = vcn_v4_0_5_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c index c305386358b4b4..bd3d2bbdc16bb6 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c @@ -87,14 +87,14 @@ static void vcn_v5_0_0_unified_ring_set_wptr(struct amdgpu_ring *ring); /** * vcn_v5_0_0_early_init - set function pointers and load microcode * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Set ring and irq function pointers * Load microcode from filesystem */ -static int vcn_v5_0_0_early_init(void *handle) +static int vcn_v5_0_0_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* re-use enc ring as unified ring */ adev->vcn.num_enc_rings = 1; @@ -108,14 +108,14 @@ static int vcn_v5_0_0_early_init(void *handle) /** * vcn_v5_0_0_sw_init - sw init for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Load firmware and sw initialization */ -static int vcn_v5_0_0_sw_init(void *handle) +static int vcn_v5_0_0_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_ring *ring; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_5_0); uint32_t *ptr; @@ -170,6 +170,10 @@ static int vcn_v5_0_0_sw_init(void *handle) amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]); } + /* TODO: Add queue reset mask when FW fully supports it */ + adev->vcn.supported_reset = + amdgpu_get_soft_full_reset_mask(&adev->vcn.inst[0].ring_enc[0]); + if (adev->pg_flags & AMD_PG_SUPPORT_VCN_DPG) adev->vcn.pause_dpg_mode = vcn_v5_0_0_pause_dpg_mode; @@ -181,19 +185,24 @@ static int vcn_v5_0_0_sw_init(void *handle) } else { adev->vcn.ip_dump = ptr; } + + r = amdgpu_vcn_sysfs_reset_mask_init(adev); + if (r) + return r; + return 0; } /** * vcn_v5_0_0_sw_fini - sw fini for VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * VCN suspend and free up sw allocation */ -static int vcn_v5_0_0_sw_fini(void *handle) +static int vcn_v5_0_0_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, r, idx; if (drm_dev_enter(adev_to_drm(adev), &idx)) { @@ -215,6 +224,7 @@ static int vcn_v5_0_0_sw_fini(void *handle) if (r) return r; + amdgpu_vcn_sysfs_reset_mask_fini(adev); r = amdgpu_vcn_sw_fini(adev); kfree(adev->vcn.ip_dump); @@ -225,13 +235,13 @@ static int vcn_v5_0_0_sw_fini(void *handle) /** * vcn_v5_0_0_hw_init - start and test VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the hardware, boot up the VCPU and do some testing */ -static int vcn_v5_0_0_hw_init(void *handle) +static int vcn_v5_0_0_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_ring *ring; int i, r; @@ -255,13 +265,13 @@ static int vcn_v5_0_0_hw_init(void *handle) /** * vcn_v5_0_0_hw_fini - stop the hardware block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Stop the VCN block, mark ring as not ready any more */ -static int vcn_v5_0_0_hw_fini(void *handle) +static int vcn_v5_0_0_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i; cancel_delayed_work_sync(&adev->vcn.idle_work); @@ -284,20 +294,19 @@ static int vcn_v5_0_0_hw_fini(void *handle) /** * vcn_v5_0_0_suspend - suspend VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * HW fini and suspend VCN block */ -static int vcn_v5_0_0_suspend(void *handle) +static int vcn_v5_0_0_suspend(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = vcn_v5_0_0_hw_fini(adev); + r = vcn_v5_0_0_hw_fini(ip_block); if (r) return r; - r = amdgpu_vcn_suspend(adev); + r = amdgpu_vcn_suspend(ip_block->adev); return r; } @@ -305,20 +314,19 @@ static int vcn_v5_0_0_suspend(void *handle) /** * vcn_v5_0_0_resume - resume VCN block * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Resume firmware and hw init VCN block */ -static int vcn_v5_0_0_resume(void *handle) +static int vcn_v5_0_0_resume(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - r = amdgpu_vcn_resume(adev); + r = amdgpu_vcn_resume(ip_block->adev); if (r) return r; - r = vcn_v5_0_0_hw_init(adev); + r = vcn_v5_0_0_hw_init(ip_block); return r; } @@ -1196,13 +1204,13 @@ static bool vcn_v5_0_0_is_idle(void *handle) /** * vcn_v5_0_0_wait_for_idle - wait for VCN block idle * - * @handle: amdgpu_device pointer + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Wait for VCN block idle */ -static int vcn_v5_0_0_wait_for_idle(void *handle) +static int vcn_v5_0_0_wait_for_idle(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, ret = 0; for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { @@ -1343,9 +1351,9 @@ static void vcn_v5_0_0_set_irq_funcs(struct amdgpu_device *adev) } } -static void vcn_v5_0_print_ip_state(void *handle, struct drm_printer *p) +static void vcn_v5_0_print_ip_state(struct amdgpu_ip_block *ip_block, struct drm_printer *p) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; uint32_t reg_count = ARRAY_SIZE(vcn_reg_list_5_0); uint32_t inst_off, is_powered; @@ -1375,9 +1383,9 @@ static void vcn_v5_0_print_ip_state(void *handle, struct drm_printer *p) } } -static void vcn_v5_0_dump_ip_state(void *handle) +static void vcn_v5_0_dump_ip_state(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int i, j; bool is_powered; uint32_t inst_off; @@ -1406,7 +1414,6 @@ static void vcn_v5_0_dump_ip_state(void *handle) static const struct amd_ip_funcs vcn_v5_0_0_ip_funcs = { .name = "vcn_v5_0_0", .early_init = vcn_v5_0_0_early_init, - .late_init = NULL, .sw_init = vcn_v5_0_0_sw_init, .sw_fini = vcn_v5_0_0_sw_fini, .hw_init = vcn_v5_0_0_hw_init, @@ -1415,10 +1422,6 @@ static const struct amd_ip_funcs vcn_v5_0_0_ip_funcs = { .resume = vcn_v5_0_0_resume, .is_idle = vcn_v5_0_0_is_idle, .wait_for_idle = vcn_v5_0_0_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, - .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v5_0_0_set_clockgating_state, .set_powergating_state = vcn_v5_0_0_set_powergating_state, .dump_ip_state = vcn_v5_0_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c index bf68e18e3824b8..0fedadd0a6a43e 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega10_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega10_ih.c @@ -472,18 +472,18 @@ static void vega10_ih_set_self_irq_funcs(struct amdgpu_device *adev) adev->irq.self_irq.funcs = &vega10_ih_self_irq_funcs; } -static int vega10_ih_early_init(void *handle) +static int vega10_ih_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; vega10_ih_set_interrupt_funcs(adev); vega10_ih_set_self_irq_funcs(adev); return 0; } -static int vega10_ih_sw_init(void *handle) +static int vega10_ih_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0, @@ -525,43 +525,35 @@ static int vega10_ih_sw_init(void *handle) return r; } -static int vega10_ih_sw_fini(void *handle) +static int vega10_ih_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); return 0; } -static int vega10_ih_hw_init(void *handle) +static int vega10_ih_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return vega10_ih_irq_init(adev); + return vega10_ih_irq_init(ip_block->adev); } -static int vega10_ih_hw_fini(void *handle) +static int vega10_ih_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - vega10_ih_irq_disable(adev); + vega10_ih_irq_disable(ip_block->adev); return 0; } -static int vega10_ih_suspend(void *handle) +static int vega10_ih_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return vega10_ih_hw_fini(adev); + return vega10_ih_hw_fini(ip_block); } -static int vega10_ih_resume(void *handle) +static int vega10_ih_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return vega10_ih_hw_init(adev); + return vega10_ih_hw_init(ip_block); } static bool vega10_ih_is_idle(void *handle) @@ -570,13 +562,13 @@ static bool vega10_ih_is_idle(void *handle) return true; } -static int vega10_ih_wait_for_idle(void *handle) +static int vega10_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* todo */ return -ETIMEDOUT; } -static int vega10_ih_soft_reset(void *handle) +static int vega10_ih_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ @@ -633,7 +625,6 @@ static int vega10_ih_set_powergating_state(void *handle, const struct amd_ip_funcs vega10_ih_ip_funcs = { .name = "vega10_ih", .early_init = vega10_ih_early_init, - .late_init = NULL, .sw_init = vega10_ih_sw_init, .sw_fini = vega10_ih_sw_fini, .hw_init = vega10_ih_hw_init, diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c index ac439f0565e357..1c9aff742e4328 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega20_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/vega20_ih.c @@ -114,6 +114,33 @@ static int vega20_ih_toggle_ring_interrupts(struct amdgpu_device *adev, tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0)); tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_GPU_TS_ENABLE, 1); + if (enable) { + /* Unset the CLEAR_OVERFLOW bit to make sure the next step + * is switching the bit from 0 to 1 + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + if (amdgpu_sriov_vf(adev) && amdgpu_sriov_reg_indirect_ih(adev)) { + if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) + return -ETIMEDOUT; + } else { + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + } + + /* Clear RB_OVERFLOW bit */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1); + if (amdgpu_sriov_vf(adev) && amdgpu_sriov_reg_indirect_ih(adev)) { + if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) + return -ETIMEDOUT; + } else { + WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp); + } + + /* Unset the CLEAR_OVERFLOW bit immediately so new overflows + * can be detected. + */ + tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 0); + } + /* enable_intr field is only valid in ring0 */ if (ih == &adev->irq.ih) tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, ENABLE_INTR, (enable ? 1 : 0)); @@ -526,18 +553,18 @@ static void vega20_ih_set_self_irq_funcs(struct amdgpu_device *adev) adev->irq.self_irq.funcs = &vega20_ih_self_irq_funcs; } -static int vega20_ih_early_init(void *handle) +static int vega20_ih_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; vega20_ih_set_interrupt_funcs(adev); vega20_ih_set_self_irq_funcs(adev); return 0; } -static int vega20_ih_sw_init(void *handle) +static int vega20_ih_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; bool use_bus_addr = true; int r; @@ -586,19 +613,19 @@ static int vega20_ih_sw_init(void *handle) return r; } -static int vega20_ih_sw_fini(void *handle) +static int vega20_ih_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_irq_fini_sw(adev); return 0; } -static int vega20_ih_hw_init(void *handle) +static int vega20_ih_hw_init(struct amdgpu_ip_block *ip_block) { int r; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; r = vega20_ih_irq_init(adev); if (r) @@ -607,27 +634,21 @@ static int vega20_ih_hw_init(void *handle) return 0; } -static int vega20_ih_hw_fini(void *handle) +static int vega20_ih_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - vega20_ih_irq_disable(adev); + vega20_ih_irq_disable(ip_block->adev); return 0; } -static int vega20_ih_suspend(void *handle) +static int vega20_ih_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return vega20_ih_hw_fini(adev); + return vega20_ih_hw_fini(ip_block); } -static int vega20_ih_resume(void *handle) +static int vega20_ih_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return vega20_ih_hw_init(adev); + return vega20_ih_hw_init(ip_block); } static bool vega20_ih_is_idle(void *handle) @@ -636,13 +657,13 @@ static bool vega20_ih_is_idle(void *handle) return true; } -static int vega20_ih_wait_for_idle(void *handle) +static int vega20_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* todo */ return -ETIMEDOUT; } -static int vega20_ih_soft_reset(void *handle) +static int vega20_ih_soft_reset(struct amdgpu_ip_block *ip_block) { /* todo */ @@ -696,7 +717,6 @@ static int vega20_ih_set_powergating_state(void *handle, const struct amd_ip_funcs vega20_ih_ip_funcs = { .name = "vega20_ih", .early_init = vega20_ih_early_init, - .late_init = NULL, .sw_init = vega20_ih_sw_init, .sw_fini = vega20_ih_sw_fini, .hw_init = vega20_ih_hw_init, diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 792b2eb6bbacea..a83505815d398c 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1455,9 +1455,9 @@ static const struct amdgpu_asic_funcs vi_asic_funcs = #define CZ_REV_BRISTOL(rev) \ ((rev >= 0xC8 && rev <= 0xCE) || (rev >= 0xE1 && rev <= 0xE6)) -static int vi_common_early_init(void *handle) +static int vi_common_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->flags & AMD_IS_APU) { adev->smc_rreg = &cz_smc_rreg; @@ -1679,9 +1679,9 @@ static int vi_common_early_init(void *handle) return 0; } -static int vi_common_late_init(void *handle) +static int vi_common_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) xgpu_vi_mailbox_get_irq(adev); @@ -1689,9 +1689,9 @@ static int vi_common_late_init(void *handle) return 0; } -static int vi_common_sw_init(void *handle) +static int vi_common_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (amdgpu_sriov_vf(adev)) xgpu_vi_mailbox_add_irq_id(adev); @@ -1699,14 +1699,9 @@ static int vi_common_sw_init(void *handle) return 0; } -static int vi_common_sw_fini(void *handle) +static int vi_common_hw_init(struct amdgpu_ip_block *ip_block) { - return 0; -} - -static int vi_common_hw_init(void *handle) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* move the golden regs per IP block */ vi_init_golden_registers(adev); @@ -1718,9 +1713,9 @@ static int vi_common_hw_init(void *handle) return 0; } -static int vi_common_hw_fini(void *handle) +static int vi_common_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; /* enable the doorbell aperture */ vi_enable_doorbell_aperture(adev, false); @@ -1731,18 +1726,14 @@ static int vi_common_hw_fini(void *handle) return 0; } -static int vi_common_suspend(void *handle) +static int vi_common_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return vi_common_hw_fini(adev); + return vi_common_hw_fini(ip_block); } -static int vi_common_resume(void *handle) +static int vi_common_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - return vi_common_hw_init(adev); + return vi_common_hw_init(ip_block); } static bool vi_common_is_idle(void *handle) @@ -1750,16 +1741,6 @@ static bool vi_common_is_idle(void *handle) return true; } -static int vi_common_wait_for_idle(void *handle) -{ - return 0; -} - -static int vi_common_soft_reset(void *handle) -{ - return 0; -} - static void vi_update_bif_medium_grain_light_sleep(struct amdgpu_device *adev, bool enable) { @@ -2047,19 +2028,14 @@ static const struct amd_ip_funcs vi_common_ip_funcs = { .early_init = vi_common_early_init, .late_init = vi_common_late_init, .sw_init = vi_common_sw_init, - .sw_fini = vi_common_sw_fini, .hw_init = vi_common_hw_init, .hw_fini = vi_common_hw_fini, .suspend = vi_common_suspend, .resume = vi_common_resume, .is_idle = vi_common_is_idle, - .wait_for_idle = vi_common_wait_for_idle, - .soft_reset = vi_common_soft_reset, .set_clockgating_state = vi_common_set_clockgating_state, .set_powergating_state = vi_common_set_powergating_state, .get_clockgating_state = vi_common_get_clockgating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; static const struct amdgpu_ip_block_version vi_common_ip_block = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 3e6b4736a7feaa..065d8784145918 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -365,7 +365,7 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p, p->pasid, dev->id); - err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, &queue_id, + err = pqm_create_queue(&p->pqm, dev, &q_properties, &queue_id, NULL, NULL, NULL, &doorbell_offset_in_process); if (err != 0) goto err_create_queue; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 48caecf7e72ed1..e5324c5bc6c714 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -28,6 +28,7 @@ #include "kfd_topology.h" #include "amdgpu.h" #include "amdgpu_amdkfd.h" +#include "amdgpu_xgmi.h" /* GPU Processor ID base for dGPUs for which VCRAT needs to be created. * GPU processor ID are expressed with Bit[31]=1. @@ -1422,6 +1423,7 @@ int kfd_parse_crat_table(void *crat_image, struct list_head *device_list, static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, + bool cache_line_size_missing, struct kfd_gpu_cache_info *pcache_info) { struct amdgpu_device *adev = kdev->adev; @@ -1436,6 +1438,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, CRAT_CACHE_FLAGS_SIMD_CACHE); pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_tcp_per_wpg / 2; pcache_info[i].cache_line_size = adev->gfx.config.gc_tcp_cache_line_size; + if (cache_line_size_missing && !pcache_info[i].cache_line_size) + pcache_info[i].cache_line_size = 128; i++; } /* Scalar L1 Instruction Cache per SQC */ @@ -1448,6 +1452,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, CRAT_CACHE_FLAGS_SIMD_CACHE); pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_sqc_per_wgp * 2; pcache_info[i].cache_line_size = adev->gfx.config.gc_instruction_cache_line_size; + if (cache_line_size_missing && !pcache_info[i].cache_line_size) + pcache_info[i].cache_line_size = 128; i++; } /* Scalar L1 Data Cache per SQC */ @@ -1459,6 +1465,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, CRAT_CACHE_FLAGS_SIMD_CACHE); pcache_info[i].num_cu_shared = adev->gfx.config.gc_num_sqc_per_wgp * 2; pcache_info[i].cache_line_size = adev->gfx.config.gc_scalar_data_cache_line_size; + if (cache_line_size_missing && !pcache_info[i].cache_line_size) + pcache_info[i].cache_line_size = 64; i++; } /* GL1 Data Cache per SA */ @@ -1471,7 +1479,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE); pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; - pcache_info[i].cache_line_size = 0; + if (cache_line_size_missing) + pcache_info[i].cache_line_size = 128; i++; } /* L2 Data Cache per GPU (Total Tex Cache) */ @@ -1483,6 +1492,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, CRAT_CACHE_FLAGS_SIMD_CACHE); pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; pcache_info[i].cache_line_size = adev->gfx.config.gc_tcc_cache_line_size; + if (cache_line_size_missing && !pcache_info[i].cache_line_size) + pcache_info[i].cache_line_size = 128; i++; } /* L3 Data Cache per GPU */ @@ -1493,7 +1504,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config(struct kfd_dev *kdev, CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE); pcache_info[i].num_cu_shared = adev->gfx.config.max_cu_per_sh; - pcache_info[i].cache_line_size = 0; + pcache_info[i].cache_line_size = 64; i++; } return i; @@ -1509,6 +1520,8 @@ static int kfd_fill_gpu_cache_info_from_gfx_config_v2(struct kfd_dev *kdev, if (adev->gfx.config.gc_tcp_size_per_cu) { pcache_info[i].cache_size = adev->gfx.config.gc_tcp_size_per_cu; pcache_info[i].cache_level = 1; + /* Cacheline size not available in IP discovery for gc943,gc944 */ + pcache_info[i].cache_line_size = 128; pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE); @@ -1520,6 +1533,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config_v2(struct kfd_dev *kdev, pcache_info[i].cache_size = adev->gfx.config.gc_l1_instruction_cache_size_per_sqc; pcache_info[i].cache_level = 1; + pcache_info[i].cache_line_size = 64; pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_INST_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE); @@ -1530,6 +1544,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config_v2(struct kfd_dev *kdev, if (adev->gfx.config.gc_l1_data_cache_size_per_sqc) { pcache_info[i].cache_size = adev->gfx.config.gc_l1_data_cache_size_per_sqc; pcache_info[i].cache_level = 1; + pcache_info[i].cache_line_size = 64; pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE); @@ -1540,6 +1555,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config_v2(struct kfd_dev *kdev, if (adev->gfx.config.gc_tcc_size) { pcache_info[i].cache_size = adev->gfx.config.gc_tcc_size; pcache_info[i].cache_level = 2; + pcache_info[i].cache_line_size = 128; pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE); @@ -1550,6 +1566,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config_v2(struct kfd_dev *kdev, if (adev->gmc.mall_size) { pcache_info[i].cache_size = adev->gmc.mall_size / 1024; pcache_info[i].cache_level = 3; + pcache_info[i].cache_line_size = 64; pcache_info[i].flags = (CRAT_CACHE_FLAGS_ENABLED | CRAT_CACHE_FLAGS_DATA_CACHE | CRAT_CACHE_FLAGS_SIMD_CACHE); @@ -1562,6 +1579,7 @@ static int kfd_fill_gpu_cache_info_from_gfx_config_v2(struct kfd_dev *kdev, int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pcache_info) { int num_of_cache_types = 0; + bool cache_line_size_missing = false; switch (kdev->adev->asic_type) { case CHIP_KAVERI: @@ -1685,10 +1703,17 @@ int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pc case IP_VERSION(11, 5, 0): case IP_VERSION(11, 5, 1): case IP_VERSION(11, 5, 2): + /* Cacheline size not available in IP discovery for gc11. + * kfd_fill_gpu_cache_info_from_gfx_config to hard code it + */ + cache_line_size_missing = true; + fallthrough; case IP_VERSION(12, 0, 0): case IP_VERSION(12, 0, 1): num_of_cache_types = - kfd_fill_gpu_cache_info_from_gfx_config(kdev->kfd, *pcache_info); + kfd_fill_gpu_cache_info_from_gfx_config(kdev->kfd, + cache_line_size_missing, + *pcache_info); break; default: *pcache_info = dummy_cache_info; @@ -2329,6 +2354,8 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image, continue; if (peer_dev->gpu->kfd->hive_id != kdev->kfd->hive_id) continue; + if (!amdgpu_xgmi_get_is_sharing_enabled(kdev->adev, peer_dev->gpu->adev)) + continue; sub_type_hdr = (typeof(sub_type_hdr))( (char *)sub_type_hdr + sizeof(struct crat_subtype_iolink)); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index fad1c8f2bc8334..9b51dd75fefc7d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -235,6 +235,9 @@ static void kfd_device_info_init(struct kfd_dev *kfd, */ kfd->device_info.needs_pci_atomics = true; kfd->device_info.no_atomic_fw_version = kfd->adev->gfx.rs64_enable ? 509 : 0; + } else if (gc_version < IP_VERSION(13, 0, 0)) { + kfd->device_info.needs_pci_atomics = true; + kfd->device_info.no_atomic_fw_version = 2090; } else { kfd->device_info.needs_pci_atomics = true; } @@ -534,7 +537,8 @@ static void kfd_cwsr_init(struct kfd_dev *kfd) kfd->cwsr_isa = cwsr_trap_gfx11_hex; kfd->cwsr_isa_size = sizeof(cwsr_trap_gfx11_hex); } else { - BUILD_BUG_ON(sizeof(cwsr_trap_gfx12_hex) > PAGE_SIZE); + BUILD_BUG_ON(sizeof(cwsr_trap_gfx12_hex) + > KFD_CWSR_TMA_OFFSET); kfd->cwsr_isa = cwsr_trap_gfx12_hex; kfd->cwsr_isa_size = sizeof(cwsr_trap_gfx12_hex); } @@ -1392,6 +1396,13 @@ void kfd_dec_compute_active(struct kfd_node *node) WARN_ONCE(count < 0, "Compute profile ref. count error"); } +static bool kfd_compute_active(struct kfd_node *node) +{ + if (atomic_read(&node->kfd->compute_profile)) + return true; + return false; +} + void kgd2kfd_smi_event_throttle(struct kfd_dev *kfd, uint64_t throttle_bitmask) { /* @@ -1485,6 +1496,24 @@ int kgd2kfd_stop_sched(struct kfd_dev *kfd, uint32_t node_id) return node->dqm->ops.halt(node->dqm); } +bool kgd2kfd_compute_active(struct kfd_dev *kfd, uint32_t node_id) +{ + struct kfd_node *node; + + if (!kfd->init_complete) + return false; + + if (node_id >= kfd->num_nodes) { + dev_warn(kfd->adev->dev, "Invalid node ID: %u exceeds %u\n", + node_id, kfd->num_nodes - 1); + return false; + } + + node = kfd->nodes[node_id]; + + return kfd_compute_active(node); +} + #if defined(CONFIG_DEBUG_FS) /* This function will send a package to HIQ to hang the HWS diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 648f40091aa395..16b5daaa272f13 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -202,9 +202,26 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, int r, queue_type; uint64_t wptr_addr_off; + if (!dqm->sched_running || dqm->sched_halt) + return 0; if (!down_read_trylock(&adev->reset_domain->sem)) return -EIO; + if (!pdd->proc_ctx_cpu_ptr) { + r = amdgpu_amdkfd_alloc_gtt_mem(adev, + AMDGPU_MES_PROC_CTX_SIZE, + &pdd->proc_ctx_bo, + &pdd->proc_ctx_gpu_addr, + &pdd->proc_ctx_cpu_ptr, + false); + if (r) { + dev_err(adev->dev, + "failed to allocate process context bo\n"); + return r; + } + memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE); + } + memset(&queue_input, 0x0, sizeof(struct mes_add_queue_input)); queue_input.process_id = qpd->pqm->process->pasid; queue_input.page_table_base_addr = qpd->page_table_base; @@ -270,6 +287,8 @@ static int remove_queue_mes(struct device_queue_manager *dqm, struct queue *q, int r; struct mes_remove_queue_input queue_input; + if (!dqm->sched_running || dqm->sched_halt) + return 0; if (!down_read_trylock(&adev->reset_domain->sem)) return -EIO; @@ -292,7 +311,7 @@ static int remove_queue_mes(struct device_queue_manager *dqm, struct queue *q, return r; } -static int remove_all_queues_mes(struct device_queue_manager *dqm) +static int remove_all_kfd_queues_mes(struct device_queue_manager *dqm) { struct device_process_node *cur; struct device *dev = dqm->dev->adev->dev; @@ -319,6 +338,33 @@ static int remove_all_queues_mes(struct device_queue_manager *dqm) return retval; } +static int add_all_kfd_queues_mes(struct device_queue_manager *dqm) +{ + struct device_process_node *cur; + struct device *dev = dqm->dev->adev->dev; + struct qcm_process_device *qpd; + struct queue *q; + int retval = 0; + + list_for_each_entry(cur, &dqm->queues, list) { + qpd = cur->qpd; + list_for_each_entry(q, &qpd->queues_list, list) { + if (!q->properties.is_active) + continue; + retval = add_queue_mes(dqm, q, qpd); + if (retval) { + dev_err(dev, "%s: Failed to add queue %d for dev %d", + __func__, + q->properties.queue_id, + dqm->dev->id); + return retval; + } + } + } + + return retval; +} + static int suspend_all_queues_mes(struct device_queue_manager *dqm) { struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; @@ -1742,7 +1788,7 @@ static int halt_cpsch(struct device_queue_manager *dqm) KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD, false); else - ret = remove_all_queues_mes(dqm); + ret = remove_all_kfd_queues_mes(dqm); } dqm->sched_halt = true; dqm_unlock(dqm); @@ -1768,6 +1814,9 @@ static int unhalt_cpsch(struct device_queue_manager *dqm) ret = execute_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD); + else + ret = add_all_kfd_queues_mes(dqm); + dqm_unlock(dqm); return ret; @@ -1867,7 +1916,7 @@ static int stop_cpsch(struct device_queue_manager *dqm) if (!dqm->dev->kfd->shared_resources.enable_mes) unmap_queues_cpsch(dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD, false); else - remove_all_queues_mes(dqm); + remove_all_kfd_queues_mes(dqm); dqm->sched_running = false; @@ -2048,7 +2097,7 @@ int amdkfd_fence_wait_timeout(struct device_queue_manager *dqm, { unsigned long end_jiffies = msecs_to_jiffies(timeout_ms) + jiffies; struct device *dev = dqm->dev->adev->dev; - uint64_t *fence_addr = dqm->fence_addr; + uint64_t *fence_addr = dqm->fence_addr; while (*fence_addr != fence_value) { /* Fatal err detected, this response won't come */ @@ -2254,6 +2303,7 @@ static int unmap_queues_cpsch(struct device_queue_manager *dqm, goto out; *dqm->fence_addr = KFD_FENCE_INIT; + mb(); pm_send_query_status(&dqm->packet_mgr, dqm->fence_gpu_addr, KFD_FENCE_COMPLETED); /* should be timed out */ @@ -3173,7 +3223,7 @@ struct copy_context_work_handler_workarea { struct kfd_process *p; }; -static void copy_context_work_handler (struct work_struct *work) +static void copy_context_work_handler(struct work_struct *work) { struct copy_context_work_handler_workarea *workarea; struct mqd_manager *mqd_mgr; @@ -3200,6 +3250,9 @@ static void copy_context_work_handler (struct work_struct *work) struct qcm_process_device *qpd = &pdd->qpd; list_for_each_entry(q, &qpd->queues_list, list) { + if (q->properties.type != KFD_QUEUE_TYPE_COMPUTE) + continue; + mqd_mgr = dqm->mqd_mgrs[KFD_MQD_TYPE_CP]; /* We ignore the return value from get_wave_state diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c index 4843dcb9a5f796..2b0a830f5b2946 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c @@ -125,7 +125,7 @@ static bool kq_initialize(struct kernel_queue *kq, struct kfd_node *dev, memset(kq->pq_kernel_addr, 0, queue_size); memset(kq->rptr_kernel, 0, sizeof(*kq->rptr_kernel)); - memset(kq->wptr_kernel, 0, sizeof(*kq->wptr_kernel)); + memset(kq->wptr_kernel, 0, dev->kfd->device_info.doorbell_size); prop.queue_size = queue_size; prop.is_interop = false; @@ -306,12 +306,17 @@ int kq_submit_packet(struct kernel_queue *kq) if (amdgpu_amdkfd_is_fed(kq->dev->adev)) return -EIO; + /* Make sure ring buffer is updated before wptr updated */ + mb(); + if (kq->dev->kfd->device_info.doorbell_size == 8) { *kq->wptr64_kernel = kq->pending_wptr64; + mb(); /* Make sure wptr updated before ring doorbell */ write_kernel_doorbell64(kq->queue->properties.doorbell_ptr, kq->pending_wptr64); } else { *kq->wptr_kernel = kq->pending_wptr; + mb(); /* Make sure wptr updated before ring doorbell */ write_kernel_doorbell(kq->queue->properties.doorbell_ptr, kq->pending_wptr); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 8ee3d07ffbdfa2..4b275937d05e93 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -306,7 +306,7 @@ svm_migrate_copy_to_vram(struct kfd_node *node, struct svm_range *prange, spage = migrate_pfn_to_page(migrate->src[i]); if (spage && !is_zone_device_page(spage)) { src[i] = dma_map_page(dev, spage, 0, PAGE_SIZE, - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); r = dma_mapping_error(dev, src[i]); if (r) { dev_err(dev, "%s: fail %d dma_map_page\n", @@ -445,14 +445,13 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange, pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n", mpages, cpages, migrate.npages); - kfd_smi_event_migration_end(node, p->lead_thread->pid, - start >> PAGE_SHIFT, end >> PAGE_SHIFT, - 0, node->id, trigger); - svm_range_dma_unmap_dev(adev->dev, scratch, 0, npages); out_free: kvfree(buf); + kfd_smi_event_migration_end(node, p->lead_thread->pid, + start >> PAGE_SHIFT, end >> PAGE_SHIFT, + 0, node->id, trigger, r); out: if (!r && mpages) { pdd = svm_range_get_pdd_by_node(prange, node); @@ -630,7 +629,7 @@ svm_migrate_copy_to_ram(struct amdgpu_device *adev, struct svm_range *prange, goto out_oom; } - dst[i] = dma_map_page(dev, dpage, 0, PAGE_SIZE, DMA_FROM_DEVICE); + dst[i] = dma_map_page(dev, dpage, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); r = dma_mapping_error(dev, dst[i]); if (r) { dev_err(adev->dev, "%s: fail %d dma_map_page\n", __func__, r); @@ -751,14 +750,13 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, svm_migrate_copy_done(adev, mfence); migrate_vma_finalize(&migrate); - kfd_smi_event_migration_end(node, p->lead_thread->pid, - start >> PAGE_SHIFT, end >> PAGE_SHIFT, - node->id, 0, trigger); - svm_range_dma_unmap_dev(adev->dev, scratch, 0, npages); out_free: kvfree(buf); + kfd_smi_event_migration_end(node, p->lead_thread->pid, + start >> PAGE_SHIFT, end >> PAGE_SHIFT, + node->id, 0, trigger, r); out: if (!r && cpages) { mpages = cpages - upages; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 26e48fdc872896..9e5ca0b93b2a25 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -1347,7 +1347,6 @@ int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p); void pqm_uninit(struct process_queue_manager *pqm); int pqm_create_queue(struct process_queue_manager *pqm, struct kfd_node *dev, - struct file *f, struct queue_properties *properties, unsigned int *qid, const struct kfd_criu_queue_priv_data *q_data, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index d4aa843aacfdd9..d0ee173acf8246 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -271,11 +271,9 @@ static int kfd_get_cu_occupancy(struct attribute *attr, char *buffer) struct kfd_process *proc = NULL; struct kfd_process_device *pdd = NULL; int i; - struct kfd_cu_occupancy cu_occupancy[AMDGPU_MAX_QUEUES]; + struct kfd_cu_occupancy *cu_occupancy; u32 queue_format; - memset(cu_occupancy, 0x0, sizeof(cu_occupancy)); - pdd = container_of(attr, struct kfd_process_device, attr_cu_occupancy); dev = pdd->dev; if (dev->kfd2kgd->get_cu_occupancy == NULL) @@ -293,6 +291,10 @@ static int kfd_get_cu_occupancy(struct attribute *attr, char *buffer) wave_cnt = 0; max_waves_per_cu = 0; + cu_occupancy = kcalloc(AMDGPU_MAX_QUEUES, sizeof(*cu_occupancy), GFP_KERNEL); + if (!cu_occupancy) + return -ENOMEM; + /* * For GFX 9.4.3, fetch the CU occupancy from the first XCC in the partition. * For AQL queues, because of cooperative dispatch we multiply the wave count @@ -318,6 +320,7 @@ static int kfd_get_cu_occupancy(struct attribute *attr, char *buffer) /* Translate wave count to number of compute units */ cu_cnt = (wave_cnt + (max_waves_per_cu - 1)) / max_waves_per_cu; + kfree(cu_occupancy); return snprintf(buffer, PAGE_SIZE, "%d\n", cu_cnt); } @@ -338,8 +341,8 @@ static ssize_t kfd_procfs_show(struct kobject *kobj, struct attribute *attr, attr_sdma); struct kfd_sdma_activity_handler_workarea sdma_activity_work_handler; - INIT_WORK(&sdma_activity_work_handler.sdma_activity_work, - kfd_sdma_activity_worker); + INIT_WORK_ONSTACK(&sdma_activity_work_handler.sdma_activity_work, + kfd_sdma_activity_worker); sdma_activity_work_handler.pdd = pdd; sdma_activity_work_handler.sdma_activity_counter = 0; @@ -347,6 +350,7 @@ static ssize_t kfd_procfs_show(struct kobject *kobj, struct attribute *attr, schedule_work(&sdma_activity_work_handler.sdma_activity_work); flush_work(&sdma_activity_work_handler.sdma_activity_work); + destroy_work_on_stack(&sdma_activity_work_handler.sdma_activity_work); return snprintf(buffer, PAGE_SIZE, "%llu\n", (sdma_activity_work_handler.sdma_activity_counter)/ @@ -850,8 +854,10 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) goto out; } - /* A prior open of /dev/kfd could have already created the process. */ - process = find_process(thread, false); + /* A prior open of /dev/kfd could have already created the process. + * find_process will increase process kref in this case + */ + process = find_process(thread, true); if (process) { pr_debug("Process already found\n"); } else { @@ -899,8 +905,6 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) init_waitqueue_head(&process->wait_irq_drain); } out: - if (!IS_ERR(process)) - kref_get(&process->ref); mutex_unlock(&kfd_processes_mutex); mmput(thread->mm); @@ -1072,7 +1076,8 @@ static void kfd_process_destroy_pdds(struct kfd_process *p) kfd_free_process_doorbells(pdd->dev->kfd, pdd); - if (pdd->dev->kfd->shared_resources.enable_mes) + if (pdd->dev->kfd->shared_resources.enable_mes && + pdd->proc_ctx_cpu_ptr) amdgpu_amdkfd_free_gtt_mem(pdd->dev->adev, &pdd->proc_ctx_bo); /* @@ -1186,10 +1191,8 @@ static void kfd_process_ref_release(struct kref *ref) static struct mmu_notifier *kfd_process_alloc_notifier(struct mm_struct *mm) { - int idx = srcu_read_lock(&kfd_processes_srcu); - struct kfd_process *p = find_process_by_mm(mm); - - srcu_read_unlock(&kfd_processes_srcu, idx); + /* This increments p->ref counter if kfd process p exists */ + struct kfd_process *p = kfd_lookup_process_by_mm(mm); return p ? &p->mmu_notifier : ERR_PTR(-ESRCH); } @@ -1606,7 +1609,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev, struct kfd_process *p) { struct kfd_process_device *pdd = NULL; - int retval = 0; if (WARN_ON_ONCE(p->n_pdds >= MAX_GPU_INSTANCE)) return NULL; @@ -1630,21 +1632,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev, pdd->user_gpu_id = dev->id; atomic64_set(&pdd->evict_duration_counter, 0); - if (dev->kfd->shared_resources.enable_mes) { - retval = amdgpu_amdkfd_alloc_gtt_mem(dev->adev, - AMDGPU_MES_PROC_CTX_SIZE, - &pdd->proc_ctx_bo, - &pdd->proc_ctx_gpu_addr, - &pdd->proc_ctx_cpu_ptr, - false); - if (retval) { - dev_err(dev->adev->dev, - "failed to allocate process context bo\n"); - goto err_free_pdd; - } - memset(pdd->proc_ctx_cpu_ptr, 0, AMDGPU_MES_PROC_CTX_SIZE); - } - p->pdds[p->n_pdds++] = pdd; if (kfd_dbg_is_per_vmid_supported(pdd->dev)) pdd->spi_dbg_override = pdd->dev->kfd2kgd->disable_debug_trap( @@ -1656,10 +1643,6 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev, idr_init(&pdd->alloc_idr); return pdd; - -err_free_pdd: - kfree(pdd); - return NULL; } /** diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 01b960b152743d..59b92d66e95890 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -212,13 +212,17 @@ static void pqm_clean_queue_resource(struct process_queue_manager *pqm, void pqm_uninit(struct process_queue_manager *pqm) { struct process_queue_node *pqn, *next; - struct kfd_process_device *pdd; list_for_each_entry_safe(pqn, next, &pqm->queues, process_queue_list) { if (pqn->q) { - pdd = kfd_get_process_device_data(pqn->q->device, pqm->process); - kfd_queue_unref_bo_vas(pdd, &pqn->q->properties); - kfd_queue_release_buffers(pdd, &pqn->q->properties); + struct kfd_process_device *pdd = kfd_get_process_device_data(pqn->q->device, + pqm->process); + if (pdd) { + kfd_queue_unref_bo_vas(pdd, &pqn->q->properties); + kfd_queue_release_buffers(pdd, &pqn->q->properties); + } else { + WARN_ON(!pdd); + } pqm_clean_queue_resource(pqm, pqn); } @@ -235,7 +239,7 @@ void pqm_uninit(struct process_queue_manager *pqm) static int init_user_queue(struct process_queue_manager *pqm, struct kfd_node *dev, struct queue **q, struct queue_properties *q_properties, - struct file *f, unsigned int qid) + unsigned int qid) { int retval; @@ -300,7 +304,6 @@ static int init_user_queue(struct process_queue_manager *pqm, int pqm_create_queue(struct process_queue_manager *pqm, struct kfd_node *dev, - struct file *f, struct queue_properties *properties, unsigned int *qid, const struct kfd_criu_queue_priv_data *q_data, @@ -374,7 +377,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, * allocate_sdma_queue() in create_queue() has the * corresponding check logic. */ - retval = init_user_queue(pqm, dev, &q, properties, f, *qid); + retval = init_user_queue(pqm, dev, &q, properties, *qid); if (retval != 0) goto err_create_queue; pqn->q = q; @@ -395,7 +398,7 @@ int pqm_create_queue(struct process_queue_manager *pqm, goto err_create_queue; } - retval = init_user_queue(pqm, dev, &q, properties, f, *qid); + retval = init_user_queue(pqm, dev, &q, properties, *qid); if (retval != 0) goto err_create_queue; pqn->q = q; @@ -1029,8 +1032,7 @@ int kfd_criu_restore_queue(struct kfd_process *p, print_queue_properties(&qp); - ret = pqm_create_queue(&p->pqm, pdd->dev, NULL, &qp, &queue_id, q_data, mqd, ctl_stack, - NULL); + ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL); if (ret) { pr_err("Failed to create new queue err:%d\n", ret); goto exit; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c index de8b9abf7afcf3..9b8169761ec5be 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c @@ -44,7 +44,7 @@ struct kfd_smi_client { bool suser; }; -#define MAX_KFIFO_SIZE 1024 +#define KFD_MAX_KFIFO_SIZE 8192 static __poll_t kfd_smi_ev_poll(struct file *, struct poll_table_struct *); static ssize_t kfd_smi_ev_read(struct file *, char __user *, size_t, loff_t *); @@ -86,7 +86,7 @@ static ssize_t kfd_smi_ev_read(struct file *filep, char __user *user, struct kfd_smi_client *client = filep->private_data; unsigned char *buf; - size = min_t(size_t, size, MAX_KFIFO_SIZE); + size = min_t(size_t, size, KFD_MAX_KFIFO_SIZE); buf = kmalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -292,12 +292,13 @@ void kfd_smi_event_migration_start(struct kfd_node *node, pid_t pid, void kfd_smi_event_migration_end(struct kfd_node *node, pid_t pid, unsigned long start, unsigned long end, - uint32_t from, uint32_t to, uint32_t trigger) + uint32_t from, uint32_t to, uint32_t trigger, + int error_code) { kfd_smi_event_add(pid, node, KFD_SMI_EVENT_MIGRATE_END, KFD_EVENT_FMT_MIGRATE_END( ktime_get_boottime_ns(), pid, start, end - start, - from, to, trigger)); + from, to, trigger, error_code)); } void kfd_smi_event_queue_eviction(struct kfd_node *node, pid_t pid, @@ -354,7 +355,7 @@ int kfd_smi_event_open(struct kfd_node *dev, uint32_t *fd) return -ENOMEM; INIT_LIST_HEAD(&client->list); - ret = kfifo_alloc(&client->fifo, MAX_KFIFO_SIZE, GFP_KERNEL); + ret = kfifo_alloc(&client->fifo, KFD_MAX_KFIFO_SIZE, GFP_KERNEL); if (ret) { kfree(client); return ret; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h index 85010b8307f885..503bff13d81533 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h @@ -44,7 +44,8 @@ void kfd_smi_event_migration_start(struct kfd_node *node, pid_t pid, uint32_t trigger); void kfd_smi_event_migration_end(struct kfd_node *node, pid_t pid, unsigned long start, unsigned long end, - uint32_t from, uint32_t to, uint32_t trigger); + uint32_t from, uint32_t to, uint32_t trigger, + int error_code); void kfd_smi_event_queue_eviction(struct kfd_node *node, pid_t pid, uint32_t trigger); void kfd_smi_event_queue_restore(struct kfd_node *node, pid_t pid); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 1893c27746a523..3e2911895c740d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -3111,8 +3111,6 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, start = max_t(unsigned long, ALIGN_DOWN(addr, size), prange->start); last = min_t(unsigned long, ALIGN(addr + 1, size) - 1, prange->last); if (prange->actual_loc != 0 || best_loc != 0) { - migration = true; - if (best_loc) { r = svm_migrate_to_vram(prange, best_loc, start, last, mm, KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU); @@ -3135,7 +3133,9 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, if (r) { pr_debug("failed %d to migrate svms %p [0x%lx 0x%lx]\n", r, svms, start, last); - goto out_unlock_range; + goto out_migrate_fail; + } else { + migration = true; } } @@ -3145,6 +3145,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, pr_debug("failed %d to map svms 0x%p [0x%lx 0x%lx] to gpus\n", r, svms, start, last); +out_migrate_fail: kfd_smi_event_page_fault_end(node, p->lead_thread->pid, addr, migration); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 3871591c9aec98..9476e30d6baa1b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1998,6 +1998,8 @@ static void kfd_topology_set_capabilities(struct kfd_topology_device *dev) if (KFD_GC_VERSION(dev->gpu) >= IP_VERSION(9, 4, 2)) dev->node_props.capability |= HSA_CAP_TRAP_DEBUG_PRECISE_MEMORY_OPERATIONS_SUPPORTED; + + dev->node_props.capability |= HSA_CAP_PER_QUEUE_RESET_SUPPORTED; } else { dev->node_props.debug_prop |= HSA_DBG_WATCH_ADDR_MASK_LO_BIT_GFX10 | HSA_DBG_WATCH_ADDR_MASK_HI_BIT; diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index df17e79c45c767..11e3f2f3b1745e 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -7,20 +7,21 @@ menu "Display Engine Configuration" config DRM_AMD_DC bool "AMD DC - Enable new display engine" default y - depends on BROKEN || !CC_IS_CLANG || ARM64 || RISCV || SPARC64 || X86_64 + depends on BROKEN || !CC_IS_CLANG || ARM64 || LOONGARCH || RISCV || SPARC64 || X86_64 select SND_HDA_COMPONENT if SND_HDA_CORE # !CC_IS_CLANG: https://github.com/ClangBuiltLinux/linux/issues/1752 - select DRM_AMD_DC_FP if ARCH_HAS_KERNEL_FPU_SUPPORT && !(CC_IS_CLANG && (ARM64 || RISCV)) + select DRM_AMD_DC_FP if ARCH_HAS_KERNEL_FPU_SUPPORT && !(CC_IS_CLANG && (ARM64 || LOONGARCH || RISCV)) help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and Raven ASICs. - calculate_bandwidth() is presently broken on all !(X86_64 || SPARC64 || ARM64) - architectures built with Clang (all released versions), whereby the stack - frame gets blown up to well over 5k. This would cause an immediate kernel - panic on most architectures. We'll revert this when the following bug report - has been resolved: https://github.com/llvm/llvm-project/issues/41896. + calculate_bandwidth() is presently broken on all !(X86_64 || SPARC64 || + ARM64 || LOONGARCH || RISCV) architectures built with Clang (all released + versions), whereby the stack frame gets blown up to well over 5k. This + would cause an immediate kernel panic on most architectures. We'll revert + this when the following bug report has been resolved: + https://github.com/llvm/llvm-project/issues/41896. config DRM_AMD_DC_FP def_bool n 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 8d97f17ffe662a..48be917e7bc550 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -320,18 +320,18 @@ static bool dm_is_idle(void *handle) return true; } -static int dm_wait_for_idle(void *handle) +static int dm_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* XXX todo */ return 0; } -static bool dm_check_soft_reset(void *handle) +static bool dm_check_soft_reset(struct amdgpu_ip_block *ip_block) { return false; } -static int dm_soft_reset(void *handle) +static int dm_soft_reset(struct amdgpu_ip_block *ip_block) { /* XXX todo */ return 0; @@ -968,7 +968,7 @@ static int dm_set_powergating_state(void *handle, } /* Prototypes of private functions */ -static int dm_early_init(void *handle); +static int dm_early_init(struct amdgpu_ip_block *ip_block); /* Allocate memory for FBC compressed data */ static void amdgpu_dm_fbc_init(struct drm_connector *connector) @@ -1307,6 +1307,29 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev) DRM_INFO("DMUB hardware initialized: version=0x%08X\n", adev->dm.dmcub_fw_version); + /* Keeping sanity checks off if + * DCN31 >= 4.0.59.0 + * DCN314 >= 8.0.16.0 + * Otherwise, turn on sanity checks + */ + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(3, 1, 2): + case IP_VERSION(3, 1, 3): + if (adev->dm.dmcub_fw_version && + adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) && + adev->dm.dmcub_fw_version < DMUB_FW_VERSION(4, 0, 59)) + adev->dm.dc->debug.sanity_checks = true; + break; + case IP_VERSION(3, 1, 4): + if (adev->dm.dmcub_fw_version && + adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) && + adev->dm.dmcub_fw_version < DMUB_FW_VERSION(8, 0, 16)) + adev->dm.dc->debug.sanity_checks = true; + break; + default: + break; + } + return 0; } @@ -1696,6 +1719,26 @@ dm_allocate_gpu_mem( return da->cpu_ptr; } +void +dm_free_gpu_mem( + struct amdgpu_device *adev, + enum dc_gpu_mem_alloc_type type, + void *pvMem) +{ + struct dal_allocation *da; + + /* walk the da list in DM */ + list_for_each_entry(da, &adev->dm.da_list, list) { + if (pvMem == da->cpu_ptr) { + amdgpu_bo_free_kernel(&da->bo, &da->gpu_addr, &da->cpu_ptr); + list_del(&da->list); + kfree(da); + break; + } + } + +} + static enum dmub_status dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev, enum dmub_gpint_command command_code, @@ -1762,16 +1805,20 @@ static struct dml2_soc_bb *dm_dmub_get_vbios_bounding_box(struct amdgpu_device * /* Send the chunk */ ret = dm_dmub_send_vbios_gpint_command(adev, send_addrs[i], chunk, 30000); if (ret != DMUB_STATUS_OK) - /* No need to free bb here since it shall be done in dm_sw_fini() */ - return NULL; + goto free_bb; } /* Now ask DMUB to copy the bb */ ret = dm_dmub_send_vbios_gpint_command(adev, DMUB_GPINT__BB_COPY, 1, 200000); if (ret != DMUB_STATUS_OK) - return NULL; + goto free_bb; return bb; + +free_bb: + dm_free_gpu_mem(adev, DC_MEM_ALLOC_TYPE_GART, (void *) bb); + return NULL; + } static enum dmub_ips_disable_type dm_get_default_ips_mode( @@ -1886,7 +1933,11 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) else init_data.flags.gpu_vm_support = (amdgpu_sg_display != 0); } else { - init_data.flags.gpu_vm_support = (amdgpu_sg_display != 0) && (adev->flags & AMD_IS_APU); + if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(2, 0, 3)) + init_data.flags.gpu_vm_support = (amdgpu_sg_display == 1); + else + init_data.flags.gpu_vm_support = + (amdgpu_sg_display != 0) && (adev->flags & AMD_IS_APU); } adev->mode_info.gpu_vm_support = init_data.flags.gpu_vm_support; @@ -2115,9 +2166,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) return -EINVAL; } -static int amdgpu_dm_early_fini(void *handle) +static int amdgpu_dm_early_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_dm_audio_fini(adev); @@ -2509,9 +2560,9 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev) return 0; } -static int dm_sw_init(void *handle) +static int dm_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; adev->dm.cgs_device = amdgpu_cgs_create_device(adev); @@ -2531,9 +2582,9 @@ static int dm_sw_init(void *handle) return load_dmcu_fw(adev); } -static int dm_sw_fini(void *handle) +static int dm_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct dal_allocation *da; list_for_each_entry(da, &adev->dm.da_list, list) { @@ -2541,11 +2592,11 @@ static int dm_sw_fini(void *handle) amdgpu_bo_free_kernel(&da->bo, &da->gpu_addr, &da->cpu_ptr); list_del(&da->list); kfree(da); + adev->dm.bb_from_dmub = NULL; break; } } - adev->dm.bb_from_dmub = NULL; kfree(adev->dm.dmub_fb_info); adev->dm.dmub_fb_info = NULL; @@ -2598,9 +2649,9 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev) return ret; } -static int dm_late_init(void *handle) +static int dm_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct dmcu_iram_parameters params; unsigned int linear_lut[16]; @@ -2790,7 +2841,7 @@ static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev) /** * dm_hw_init() - Initialize DC device - * @handle: The base driver device containing the amdgpu_dm device. + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Initialize the &struct amdgpu_display_manager device. This involves calling * the initializers of each DM component, then populating the struct with them. @@ -2808,9 +2859,9 @@ static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev) * - Vblank support * - Debug FS entries, if enabled */ -static int dm_hw_init(void *handle) +static int dm_hw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; int r; /* Create DAL display manager */ @@ -2824,15 +2875,15 @@ static int dm_hw_init(void *handle) /** * dm_hw_fini() - Teardown DC device - * @handle: The base driver device containing the amdgpu_dm device. + * @ip_block: Pointer to the amdgpu_ip_block for this hw instance. * * Teardown components within &struct amdgpu_display_manager that require * cleanup. This involves cleaning up the DRM device, DC, and any modules that * were loaded. Also flush IRQ workqueues and disable them. */ -static int dm_hw_fini(void *handle) +static int dm_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; amdgpu_dm_hpd_fini(adev); @@ -2936,9 +2987,9 @@ static void hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm) } } -static int dm_suspend(void *handle) +static int dm_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_display_manager *dm = &adev->dm; int ret = 0; @@ -3125,9 +3176,9 @@ static void dm_gpureset_commit_state(struct dc_state *dc_state, kfree(bundle); } -static int dm_resume(void *handle) +static int dm_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; struct drm_device *ddev = adev_to_drm(adev); struct amdgpu_display_manager *dm = &adev->dm; struct amdgpu_dm_connector *aconnector; @@ -3142,8 +3193,7 @@ static int dm_resume(void *handle) struct dm_atomic_state *dm_state = to_dm_atomic_state(dm->atomic_obj.state); enum dc_connection_type new_connection_type = dc_connection_none; struct dc_state *dc_state; - int i, r, j, ret; - bool need_hotplug = false; + int i, r, j; struct dc_commit_streams_params commit_params = {}; if (dm->dc->caps.ips_support) { @@ -3332,23 +3382,16 @@ static int dm_resume(void *handle) aconnector->mst_root) continue; - ret = drm_dp_mst_topology_mgr_resume(&aconnector->mst_mgr, true); - - if (ret < 0) { - dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx, - aconnector->dc_link); - need_hotplug = true; - } + drm_dp_mst_topology_queue_probe(&aconnector->mst_mgr); } drm_connector_list_iter_end(&iter); - if (need_hotplug) - drm_kms_helper_hotplug_event(ddev); - amdgpu_dm_irq_resume_late(adev); amdgpu_dm_smu_write_watermarks_table(adev); + drm_kms_helper_hotplug_event(ddev); + return 0; } @@ -3379,8 +3422,6 @@ static const struct amd_ip_funcs amdgpu_dm_funcs = { .soft_reset = dm_soft_reset, .set_clockgating_state = dm_set_clockgating_state, .set_powergating_state = dm_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version dm_ip_block = { @@ -3440,6 +3481,8 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) caps->aux_support = false; else if (amdgpu_backlight == 1) caps->aux_support = true; + if (caps->aux_support) + aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX; luminance_range = &conn_base->display_info.luminance_range; @@ -3495,7 +3538,7 @@ void amdgpu_dm_update_connector_after_detect( aconnector->dc_sink = sink; dc_sink_retain(aconnector->dc_sink); amdgpu_dm_update_freesync_caps(connector, - aconnector->edid); + aconnector->drm_edid); } else { amdgpu_dm_update_freesync_caps(connector, NULL); if (!aconnector->dc_sink) { @@ -3554,18 +3597,19 @@ void amdgpu_dm_update_connector_after_detect( aconnector->dc_sink = sink; dc_sink_retain(aconnector->dc_sink); if (sink->dc_edid.length == 0) { - aconnector->edid = NULL; + aconnector->drm_edid = NULL; if (aconnector->dc_link->aux_mode) { - drm_dp_cec_unset_edid( - &aconnector->dm_dp_aux.aux); + drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); } } else { - aconnector->edid = - (struct edid *)sink->dc_edid.raw_edid; + const struct edid *edid = (const struct edid *)sink->dc_edid.raw_edid; + + aconnector->drm_edid = drm_edid_alloc(edid, sink->dc_edid.length); + drm_edid_connector_update(connector, aconnector->drm_edid); if (aconnector->dc_link->aux_mode) - drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux, - aconnector->edid); + drm_dp_cec_attach(&aconnector->dm_dp_aux.aux, + connector->display_info.source_physical_address); } if (!aconnector->timing_requested) { @@ -3576,17 +3620,16 @@ void amdgpu_dm_update_connector_after_detect( "failed to create aconnector->requested_timing\n"); } - drm_connector_update_edid_property(connector, aconnector->edid); - amdgpu_dm_update_freesync_caps(connector, aconnector->edid); + amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid); update_connector_ext_caps(aconnector); } else { drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); amdgpu_dm_update_freesync_caps(connector, NULL); - drm_connector_update_edid_property(connector, NULL); aconnector->num_modes = 0; dc_sink_release(aconnector->dc_sink); aconnector->dc_sink = NULL; - aconnector->edid = NULL; + drm_edid_free(aconnector->drm_edid); + aconnector->drm_edid = NULL; kfree(aconnector->timing_requested); aconnector->timing_requested = NULL; /* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */ @@ -4622,7 +4665,12 @@ static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, if (!rc) DRM_DEBUG("DM: Failed to update backlight via AUX on eDP[%d]\n", bl_idx); } else { - rc = dc_link_set_backlight_level(link, brightness, 0); + struct set_backlight_level_params backlight_level_params = { 0 }; + + backlight_level_params.backlight_pwm_u16_16 = brightness; + backlight_level_params.transition_time_in_ms = 0; + + rc = dc_link_set_backlight_level(link, &backlight_level_params); if (!rc) DRM_DEBUG("DM: Failed to update backlight on eDP[%d]\n", bl_idx); } @@ -5177,15 +5225,20 @@ static ssize_t s3_debug_store(struct device *device, int s3_state; struct drm_device *drm_dev = dev_get_drvdata(device); struct amdgpu_device *adev = drm_to_adev(drm_dev); + struct amdgpu_ip_block *ip_block; + + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_DCE); + if (!ip_block) + return -EINVAL; ret = kstrtoint(buf, 0, &s3_state); if (ret == 0) { if (s3_state) { - dm_resume(adev); + dm_resume(ip_block); drm_kms_helper_hotplug_event(adev_to_drm(adev)); } else - dm_suspend(adev); + dm_suspend(ip_block); } return ret == 0 ? count : 0; @@ -5257,9 +5310,9 @@ static int dm_init_microcode(struct amdgpu_device *adev) return r; } -static int dm_early_init(void *handle) +static int dm_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct amdgpu_mode_info *mode_info = &adev->mode_info; struct atom_context *ctx = mode_info->atom_context; int index = GetIndexIntoMasterTable(DATA, Object_Header); @@ -7122,32 +7175,24 @@ static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector) struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); struct dc_link *dc_link = aconnector->dc_link; struct dc_sink *dc_em_sink = aconnector->dc_em_sink; - struct edid *edid; - struct i2c_adapter *ddc; - - if (dc_link && dc_link->aux_mode) - ddc = &aconnector->dm_dp_aux.aux.ddc; - else - ddc = &aconnector->i2c->base; + const struct drm_edid *drm_edid; - /* - * Note: drm_get_edid gets edid in the following order: - * 1) override EDID if set via edid_override debugfs, - * 2) firmware EDID if set via edid_firmware module parameter - * 3) regular DDC read. - */ - edid = drm_get_edid(connector, ddc); - if (!edid) { + drm_edid = drm_edid_read(connector); + drm_edid_connector_update(connector, drm_edid); + if (!drm_edid) { DRM_ERROR("No EDID found on connector: %s.\n", connector->name); return; } - aconnector->edid = edid; - + aconnector->drm_edid = drm_edid; /* Update emulated (virtual) sink's EDID */ if (dc_em_sink && dc_link) { + // FIXME: Get rid of drm_edid_raw() + const struct edid *edid = drm_edid_raw(drm_edid); + memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps)); - memmove(dc_em_sink->dc_edid.raw_edid, edid, (edid->extensions + 1) * EDID_LENGTH); + memmove(dc_em_sink->dc_edid.raw_edid, edid, + (edid->extensions + 1) * EDID_LENGTH); dm_helpers_parse_edid_caps( dc_link, &dc_em_sink->dc_edid, @@ -7177,36 +7222,26 @@ static int get_modes(struct drm_connector *connector) static void create_eml_sink(struct amdgpu_dm_connector *aconnector) { struct drm_connector *connector = &aconnector->base; - struct dc_link *dc_link = aconnector->dc_link; struct dc_sink_init_data init_params = { .link = aconnector->dc_link, .sink_signal = SIGNAL_TYPE_VIRTUAL }; - struct edid *edid; - struct i2c_adapter *ddc; - - if (dc_link->aux_mode) - ddc = &aconnector->dm_dp_aux.aux.ddc; - else - ddc = &aconnector->i2c->base; + const struct drm_edid *drm_edid; + const struct edid *edid; - /* - * Note: drm_get_edid gets edid in the following order: - * 1) override EDID if set via edid_override debugfs, - * 2) firmware EDID if set via edid_firmware module parameter - * 3) regular DDC read. - */ - edid = drm_get_edid(connector, ddc); - if (!edid) { + drm_edid = drm_edid_read(connector); + drm_edid_connector_update(connector, drm_edid); + if (!drm_edid) { DRM_ERROR("No EDID found on connector: %s.\n", connector->name); return; } - if (drm_detect_hdmi_monitor(edid)) + if (connector->display_info.is_hdmi) init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; - aconnector->edid = edid; + aconnector->drm_edid = drm_edid; + edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw() aconnector->dc_em_sink = dc_link_add_remote_sink( aconnector->dc_link, (uint8_t *)edid, @@ -7313,10 +7348,15 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL; int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8; enum dc_status dc_result = DC_OK; + uint8_t bpc_limit = 6; if (!dm_state) return NULL; + if (aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A || + aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) + bpc_limit = 8; + do { stream = create_stream_for_sink(connector, drm_mode, dm_state, old_stream, @@ -7337,11 +7377,12 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, dc_result = dm_validate_stream_and_context(adev->dm.dc, stream); if (dc_result != DC_OK) { - DRM_DEBUG_KMS("Mode %dx%d (clk %d) failed DC validation with error %d (%s)\n", + DRM_DEBUG_KMS("Mode %dx%d (clk %d) pixel_encoding:%s color_depth:%s failed validation -- %s\n", drm_mode->hdisplay, drm_mode->vdisplay, drm_mode->clock, - dc_result, + dc_pixel_encoding_to_str(stream->timing.pixel_encoding), + dc_color_depth_to_str(stream->timing.display_color_depth), dc_status_to_str(dc_result)); dc_stream_release(stream); @@ -7349,10 +7390,13 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, requested_bpc -= 2; /* lower bpc to retry validation */ } - } while (stream == NULL && requested_bpc >= 6); + } while (stream == NULL && requested_bpc >= bpc_limit); - if (dc_result == DC_FAIL_ENC_VALIDATE && !aconnector->force_yuv420_output) { - DRM_DEBUG_KMS("Retry forcing YCbCr420 encoding\n"); + if ((dc_result == DC_FAIL_ENC_VALIDATE || + dc_result == DC_EXCEED_DONGLE_CAP) && + !aconnector->force_yuv420_output) { + DRM_DEBUG_KMS("%s:%d Retry forcing yuv420 encoding\n", + __func__, __LINE__); aconnector->force_yuv420_output = true; stream = create_validate_stream_for_sink(aconnector, drm_mode, @@ -7893,16 +7937,16 @@ static void amdgpu_set_panel_orientation(struct drm_connector *connector) } static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector, - struct edid *edid) + const struct drm_edid *drm_edid) { struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); - if (edid) { + if (drm_edid) { /* empty probed_modes */ INIT_LIST_HEAD(&connector->probed_modes); amdgpu_dm_connector->num_modes = - drm_add_edid_modes(connector, edid); + drm_edid_connector_add_modes(connector); /* sorting the probed modes before calling function * amdgpu_dm_get_native_mode() since EDID can have @@ -7916,10 +7960,10 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector, amdgpu_dm_get_native_mode(connector); /* Freesync capabilities are reset by calling - * drm_add_edid_modes() and need to be + * drm_edid_connector_add_modes() and need to be * restored here. */ - amdgpu_dm_update_freesync_caps(connector, edid); + amdgpu_dm_update_freesync_caps(connector, drm_edid); } else { amdgpu_dm_connector->num_modes = 0; } @@ -8015,12 +8059,12 @@ static uint add_fs_modes(struct amdgpu_dm_connector *aconnector) } static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector, - struct edid *edid) + const struct drm_edid *drm_edid) { struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); - if (!(amdgpu_freesync_vid_mode && edid)) + if (!(amdgpu_freesync_vid_mode && drm_edid)) return; if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) @@ -8033,24 +8077,24 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); struct drm_encoder *encoder; - struct edid *edid = amdgpu_dm_connector->edid; + const struct drm_edid *drm_edid = amdgpu_dm_connector->drm_edid; struct dc_link_settings *verified_link_cap = &amdgpu_dm_connector->dc_link->verified_link_cap; const struct dc *dc = amdgpu_dm_connector->dc_link->dc; encoder = amdgpu_dm_connector_to_encoder(connector); - if (!drm_edid_is_valid(edid)) { + if (!drm_edid) { amdgpu_dm_connector->num_modes = drm_add_modes_noedid(connector, 640, 480); if (dc->link_srv->dp_get_encoding_format(verified_link_cap) == DP_128b_132b_ENCODING) amdgpu_dm_connector->num_modes += drm_add_modes_noedid(connector, 1920, 1080); } else { - amdgpu_dm_connector_ddc_get_modes(connector, edid); + amdgpu_dm_connector_ddc_get_modes(connector, drm_edid); if (encoder) amdgpu_dm_connector_add_common_modes(encoder, connector); - amdgpu_dm_connector_add_freesync_modes(connector, edid); + amdgpu_dm_connector_add_freesync_modes(connector, drm_edid); } amdgpu_dm_fbc_init(connector); @@ -9580,7 +9624,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, WARN_ON(!dc_commit_streams(dm->dc, ¶ms)); /* Allow idle optimization when vblank count is 0 for display off */ - if (dm->active_vblank_irq_count == 0) + if ((dm->active_vblank_irq_count == 0) && amdgpu_dm_is_headless(dm->adev)) dc_allow_idle_optimizations(dm->dc, true); mutex_unlock(&dm->dc_lock); @@ -10124,6 +10168,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) for (i = 0; i < crtc_disable_count; i++) pm_runtime_put_autosuspend(dev->dev); pm_runtime_mark_last_busy(dev->dev); + + trace_amdgpu_dm_atomic_commit_tail_finish(state); } static int dm_force_atomic_commit(struct drm_connector *connector) @@ -12024,7 +12070,7 @@ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, } static void parse_edid_displayid_vrr(struct drm_connector *connector, - struct edid *edid) + const struct edid *edid) { u8 *edid_ext = NULL; int i; @@ -12067,7 +12113,7 @@ static void parse_edid_displayid_vrr(struct drm_connector *connector, } static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector, - struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info) + const struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info) { u8 *edid_ext = NULL; int i; @@ -12102,7 +12148,8 @@ static int parse_amd_vsdb(struct amdgpu_dm_connector *aconnector, } static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, - struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info) + const struct edid *edid, + struct amdgpu_hdmi_vsdb_info *vsdb_info) { u8 *edid_ext = NULL; int i; @@ -12136,7 +12183,7 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, * amdgpu_dm_update_freesync_caps - Update Freesync capabilities * * @connector: Connector to query. - * @edid: EDID from monitor + * @drm_edid: DRM EDID from monitor * * Amdgpu supports Freesync in DP and HDMI displays, and it is required to keep * track of some of the display information in the internal data struct used by @@ -12144,19 +12191,16 @@ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, * FreeSync parameters. */ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - struct edid *edid) + const struct drm_edid *drm_edid) { int i = 0; - struct detailed_timing *timing; - struct detailed_non_pixel *data; - struct detailed_data_monitor_range *range; struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); struct dm_connector_state *dm_con_state = NULL; struct dc_sink *sink; - struct amdgpu_device *adev = drm_to_adev(connector->dev); struct amdgpu_hdmi_vsdb_info vsdb_info = {0}; + const struct edid *edid; bool freesync_capable = false; enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE; @@ -12169,13 +12213,13 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, amdgpu_dm_connector->dc_sink : amdgpu_dm_connector->dc_em_sink; - if (!edid || !sink) { + drm_edid_connector_update(connector, drm_edid); + + if (!drm_edid || !sink) { dm_con_state = to_dm_connector_state(connector->state); amdgpu_dm_connector->min_vfreq = 0; amdgpu_dm_connector->max_vfreq = 0; - connector->display_info.monitor_range.min_vfreq = 0; - connector->display_info.monitor_range.max_vfreq = 0; freesync_capable = false; goto update; @@ -12186,6 +12230,8 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, if (!adev->dm.freesync_module) goto update; + edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw() + /* Some eDP panels only have the refresh rate range info in DisplayID */ if ((connector->display_info.monitor_range.min_vfreq == 0 || connector->display_info.monitor_range.max_vfreq == 0)) @@ -12193,67 +12239,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT || sink->sink_signal == SIGNAL_TYPE_EDP)) { - bool edid_check_required = false; - - if (amdgpu_dm_connector->dc_link && - amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) { - if (edid->features & DRM_EDID_FEATURE_CONTINUOUS_FREQ) { - amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq; - amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq; - if (amdgpu_dm_connector->max_vfreq - - amdgpu_dm_connector->min_vfreq > 10) - freesync_capable = true; - } else { - edid_check_required = edid->version > 1 || - (edid->version == 1 && - edid->revision > 1); - } - } - - if (edid_check_required) { - for (i = 0; i < 4; i++) { - - timing = &edid->detailed_timings[i]; - data = &timing->data.other_data; - range = &data->data.range; - /* - * Check if monitor has continuous frequency mode - */ - if (data->type != EDID_DETAIL_MONITOR_RANGE) - continue; - /* - * Check for flag range limits only. If flag == 1 then - * no additional timing information provided. - * Default GTF, GTF Secondary curve and CVT are not - * supported - */ - if (range->flags != 1) - continue; - - connector->display_info.monitor_range.min_vfreq = range->min_vfreq; - connector->display_info.monitor_range.max_vfreq = range->max_vfreq; - - if (edid->revision >= 4) { - if (data->pad2 & DRM_EDID_RANGE_OFFSET_MIN_VFREQ) - connector->display_info.monitor_range.min_vfreq += 255; - if (data->pad2 & DRM_EDID_RANGE_OFFSET_MAX_VFREQ) - connector->display_info.monitor_range.max_vfreq += 255; - } - - amdgpu_dm_connector->min_vfreq = - connector->display_info.monitor_range.min_vfreq; - amdgpu_dm_connector->max_vfreq = - connector->display_info.monitor_range.max_vfreq; - - break; - } - - if (amdgpu_dm_connector->max_vfreq - - amdgpu_dm_connector->min_vfreq > 10) { - - freesync_capable = true; - } - } + amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq; + amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq; + if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) + freesync_capable = true; parse_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); if (vsdb_info.replay_mode) { @@ -12262,12 +12251,9 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP; } - } else if (edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) { + } else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) { i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); if (i >= 0 && vsdb_info.freesync_supported) { - timing = &edid->detailed_timings[i]; - data = &timing->data.other_data; - amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 90dfffec33cf49..6464a8378387c7 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -673,7 +673,7 @@ struct amdgpu_dm_connector { /* we need to mind the EDID between detect and get modes due to analog/digital/tvencoder */ - struct edid *edid; + const struct drm_edid *drm_edid; /* shared with amdgpu */ struct amdgpu_hpd hpd; @@ -951,7 +951,7 @@ void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector); void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - struct edid *edid); + const struct drm_edid *drm_edid); void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); @@ -1004,6 +1004,9 @@ void *dm_allocate_gpu_mem(struct amdgpu_device *adev, enum dc_gpu_mem_alloc_type type, size_t size, long long *addr); +void dm_free_gpu_mem(struct amdgpu_device *adev, + enum dc_gpu_mem_alloc_type type, + void *addr); bool amdgpu_dm_is_headless(struct amdgpu_device *adev); 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 288be19db7c1b8..64a041c2af05c3 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 @@ -35,8 +35,8 @@ #include "amdgpu_dm_trace.h" #include "amdgpu_dm_debugfs.h" -#define HPD_DETECTION_PERIOD_uS 5000000 -#define HPD_DETECTION_TIME_uS 1000 +#define HPD_DETECTION_PERIOD_uS 2000000 +#define HPD_DETECTION_TIME_uS 100000 void amdgpu_dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc) { @@ -154,6 +154,7 @@ static void amdgpu_dm_crtc_set_panel_sr_feature( amdgpu_dm_psr_enable(vblank_work->stream); if (dm->idle_workqueue && + (dm->dc->config.disable_ips == DMUB_IPS_ENABLE) && dm->dc->idle_optimizations_allowed && dm->idle_workqueue->enable && !dm->idle_workqueue->running) @@ -251,10 +252,8 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) else if (dm->active_vblank_irq_count) dm->active_vblank_irq_count--; - if (dm->active_vblank_irq_count > 0) { - DRM_DEBUG_KMS("Allow idle optimizations (MALL): false\n"); + if (dm->active_vblank_irq_count > 0) dc_allow_idle_optimizations(dm->dc, false); - } /* * Control PSR based on vblank requirements from OS @@ -272,10 +271,8 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) vblank_work->acrtc->dm_irq_params.allow_sr_entry); } - if (dm->active_vblank_irq_count == 0) { - DRM_DEBUG_KMS("Allow idle optimizations (MALL): true\n"); + if (dm->active_vblank_irq_count == 0) dc_allow_idle_optimizations(dm->dc, true); - } mutex_unlock(&dm->dc_lock); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index db56b0aa545454..6a97bb2d916015 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -1529,7 +1529,6 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { char *rd_buf = NULL; - char *rd_buf_ptr = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; @@ -1543,8 +1542,6 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, if (!rd_buf) return -ENOMEM; - rd_buf_ptr = rd_buf; - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && @@ -1558,10 +1555,9 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf, if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); - snprintf(rd_buf_ptr, str_len, + snprintf(rd_buf, str_len, "%d\n", dsc_state.dsc_clock_en); - rd_buf_ptr += str_len; while (size) { if (*pos >= rd_buf_size) @@ -1719,7 +1715,6 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { char *rd_buf = NULL; - char *rd_buf_ptr = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; @@ -1733,8 +1728,6 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf, if (!rd_buf) return -ENOMEM; - rd_buf_ptr = rd_buf; - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && @@ -1748,10 +1741,9 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf, if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); - snprintf(rd_buf_ptr, str_len, + snprintf(rd_buf, str_len, "%d\n", dsc_state.dsc_slice_width); - rd_buf_ptr += str_len; while (size) { if (*pos >= rd_buf_size) @@ -1907,7 +1899,6 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { char *rd_buf = NULL; - char *rd_buf_ptr = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; @@ -1921,8 +1912,6 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf, if (!rd_buf) return -ENOMEM; - rd_buf_ptr = rd_buf; - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && @@ -1936,10 +1925,9 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf, if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); - snprintf(rd_buf_ptr, str_len, + snprintf(rd_buf, str_len, "%d\n", dsc_state.dsc_slice_height); - rd_buf_ptr += str_len; while (size) { if (*pos >= rd_buf_size) @@ -2091,7 +2079,6 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { char *rd_buf = NULL; - char *rd_buf_ptr = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; @@ -2105,8 +2092,6 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf, if (!rd_buf) return -ENOMEM; - rd_buf_ptr = rd_buf; - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && @@ -2120,10 +2105,9 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf, if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); - snprintf(rd_buf_ptr, str_len, + snprintf(rd_buf, str_len, "%d\n", dsc_state.dsc_bits_per_pixel); - rd_buf_ptr += str_len; while (size) { if (*pos >= rd_buf_size) @@ -2270,7 +2254,6 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { char *rd_buf = NULL; - char *rd_buf_ptr = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; @@ -2284,8 +2267,6 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf, if (!rd_buf) return -ENOMEM; - rd_buf_ptr = rd_buf; - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && @@ -2299,10 +2280,9 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf, if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); - snprintf(rd_buf_ptr, str_len, + snprintf(rd_buf, str_len, "%d\n", dsc_state.dsc_pic_width); - rd_buf_ptr += str_len; while (size) { if (*pos >= rd_buf_size) @@ -2328,7 +2308,6 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { char *rd_buf = NULL; - char *rd_buf_ptr = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; @@ -2342,8 +2321,6 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf, if (!rd_buf) return -ENOMEM; - rd_buf_ptr = rd_buf; - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && @@ -2357,10 +2334,9 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf, if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); - snprintf(rd_buf_ptr, str_len, + snprintf(rd_buf, str_len, "%d\n", dsc_state.dsc_pic_height); - rd_buf_ptr += str_len; while (size) { if (*pos >= rd_buf_size) @@ -2401,7 +2377,6 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { char *rd_buf = NULL; - char *rd_buf_ptr = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; @@ -2415,8 +2390,6 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf, if (!rd_buf) return -ENOMEM; - rd_buf_ptr = rd_buf; - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && @@ -2430,10 +2403,9 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf, if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); - snprintf(rd_buf_ptr, str_len, + snprintf(rd_buf, str_len, "%d\n", dsc_state.dsc_chunk_size); - rd_buf_ptr += str_len; while (size) { if (*pos >= rd_buf_size) @@ -2474,7 +2446,6 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { char *rd_buf = NULL; - char *rd_buf_ptr = NULL; struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; struct display_stream_compressor *dsc; struct dcn_dsc_state dsc_state = {0}; @@ -2488,8 +2459,6 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf, if (!rd_buf) return -ENOMEM; - rd_buf_ptr = rd_buf; - for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &aconnector->dc_link->dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream && @@ -2503,10 +2472,9 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf, if (dsc) dsc->funcs->dsc_read_state(dsc, &dsc_state); - snprintf(rd_buf_ptr, str_len, + snprintf(rd_buf, str_len, "%d\n", dsc_state.dsc_slice_bpg_offset); - rd_buf_ptr += str_len; while (size) { if (*pos >= rd_buf_size) 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 eea317dcbe8c34..6cbbb71d752bec 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 @@ -23,6 +23,8 @@ * */ +#include + #include #include #include @@ -642,6 +644,8 @@ static bool execute_synaptics_rc_command(struct drm_dp_aux *aux, // write rc data memmove(rc_data, data, length); ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_DATA, rc_data, sizeof(rc_data)); + if (ret < 0) + goto err; } // write rc offset @@ -650,20 +654,21 @@ static bool execute_synaptics_rc_command(struct drm_dp_aux *aux, rc_offset[2] = (unsigned char) (offset >> 16) & 0xFF; rc_offset[3] = (unsigned char) (offset >> 24) & 0xFF; ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_OFFSET, rc_offset, sizeof(rc_offset)); + if (ret < 0) + goto err; // write rc length rc_length[0] = (unsigned char) length & 0xFF; rc_length[1] = (unsigned char) (length >> 8) & 0xFF; ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_LENGTH, rc_length, sizeof(rc_length)); + if (ret < 0) + goto err; // write rc cmd rc_cmd = cmd | 0x80; ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_COMMAND, &rc_cmd, sizeof(rc_cmd)); - - if (ret < 0) { - DRM_ERROR("%s: write cmd ..., err = %d\n", __func__, ret); - return false; - } + if (ret < 0) + goto err; // poll until active is 0 for (i = 0; i < 10; i++) { @@ -686,6 +691,10 @@ static bool execute_synaptics_rc_command(struct drm_dp_aux *aux, drm_dbg_dp(aux->drm_dev, "success = %d\n", success); return success; + +err: + DRM_ERROR("%s: write cmd ..., err = %d\n", __func__, ret); + return false; } static void apply_synaptics_fifo_reset_wa(struct drm_dp_aux *aux) @@ -892,6 +901,67 @@ bool dm_helpers_is_dp_sink_present(struct dc_link *link) return dp_sink_present; } +static int +dm_helpers_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len) +{ + struct drm_connector *connector = data; + struct acpi_device *acpidev = ACPI_COMPANION(connector->dev->dev); + unsigned char start = block * EDID_LENGTH; + struct edid *edid; + int r; + + if (!acpidev) + return -ENODEV; + + /* fetch the entire edid from BIOS */ + r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, (void *)&edid); + if (r < 0) { + drm_dbg(connector->dev, "Failed to get EDID from ACPI: %d\n", r); + return r; + } + if (len > r || start > r || start + len > r) { + r = -EINVAL; + goto cleanup; + } + + /* sanity check */ + if (edid->revision < 4 || !(edid->input & DRM_EDID_INPUT_DIGITAL) || + (edid->input & DRM_EDID_DIGITAL_TYPE_MASK) == DRM_EDID_DIGITAL_TYPE_UNDEF) { + r = -EINVAL; + goto cleanup; + } + + memcpy(buf, (void *)edid + start, len); + r = 0; + +cleanup: + kfree(edid); + + return r; +} + +static const struct drm_edid * +dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector) +{ + struct drm_connector *connector = &aconnector->base; + + if (amdgpu_dc_debug_mask & DC_DISABLE_ACPI_EDID) + return NULL; + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_LVDS: + case DRM_MODE_CONNECTOR_eDP: + break; + default: + return NULL; + } + + if (connector->force == DRM_FORCE_OFF) + return NULL; + + return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector); +} + enum dc_edid_status dm_helpers_read_local_edid( struct dc_context *ctx, struct dc_link *link, @@ -902,7 +972,8 @@ enum dc_edid_status dm_helpers_read_local_edid( struct i2c_adapter *ddc; int retry = 3; enum dc_edid_status edid_status; - struct edid *edid; + const struct drm_edid *drm_edid; + const struct edid *edid; if (link->aux_mode) ddc = &aconnector->dm_dp_aux.aux.ddc; @@ -913,26 +984,31 @@ enum dc_edid_status dm_helpers_read_local_edid( * do check sum and retry to make sure read correct edid. */ do { - - edid = drm_get_edid(&aconnector->base, ddc); + drm_edid = dm_helpers_read_acpi_edid(aconnector); + if (drm_edid) + drm_info(connector->dev, "Using ACPI provided EDID for %s\n", connector->name); + else + drm_edid = drm_edid_read_ddc(connector, ddc); + drm_edid_connector_update(connector, drm_edid); /* DP Compliance Test 4.2.2.6 */ if (link->aux_mode && connector->edid_corrupt) drm_dp_send_real_edid_checksum(&aconnector->dm_dp_aux.aux, connector->real_edid_checksum); - if (!edid && connector->edid_corrupt) { + if (!drm_edid && connector->edid_corrupt) { connector->edid_corrupt = false; return EDID_BAD_CHECKSUM; } - if (!edid) + if (!drm_edid) return EDID_NO_RESPONSE; + edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw() sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1); memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length); /* We don't need the original edid anymore */ - kfree(edid); + drm_edid_free(drm_edid); edid_status = dm_helpers_parse_edid_caps( link, @@ -1055,17 +1131,8 @@ void dm_helpers_free_gpu_mem( void *pvMem) { struct amdgpu_device *adev = ctx->driver_context; - struct dal_allocation *da; - - /* walk the da list in DM */ - list_for_each_entry(da, &adev->dm.da_list, list) { - if (pvMem == da->cpu_ptr) { - amdgpu_bo_free_kernel(&da->bo, &da->gpu_addr, &da->cpu_ptr); - list_del(&da->list); - kfree(da); - break; - } - } + + dm_free_gpu_mem(adev, type, pvMem); } bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enable) @@ -1314,4 +1381,4 @@ bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream { // TODO return false; -} \ No newline at end of file +} 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 a08e8a0b696c60..6e43594906130c 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 @@ -129,7 +129,7 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector) dc_sink_release(aconnector->dc_sink); } - kfree(aconnector->edid); + drm_edid_free(aconnector->drm_edid); drm_connector_cleanup(connector); drm_dp_mst_put_port_malloc(aconnector->mst_output_port); @@ -182,7 +182,7 @@ amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector) dc_sink_release(dc_sink); aconnector->dc_sink = NULL; - aconnector->edid = NULL; + aconnector->drm_edid = NULL; aconnector->dsc_aux = NULL; port->passthrough_aux = NULL; } @@ -302,16 +302,18 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) if (!aconnector) return drm_add_edid_modes(connector, NULL); - if (!aconnector->edid) { - struct edid *edid; + if (!aconnector->drm_edid) { + const struct drm_edid *drm_edid; - edid = drm_dp_mst_get_edid(connector, &aconnector->mst_root->mst_mgr, aconnector->mst_output_port); + drm_edid = drm_dp_mst_edid_read(connector, + &aconnector->mst_root->mst_mgr, + aconnector->mst_output_port); - if (!edid) { + if (!drm_edid) { amdgpu_dm_set_mst_status(&aconnector->mst_status, MST_REMOTE_EDID, false); - drm_connector_update_edid_property( + drm_edid_connector_update( &aconnector->base, NULL); @@ -345,7 +347,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) return ret; } - aconnector->edid = edid; + aconnector->drm_edid = drm_edid; amdgpu_dm_set_mst_status(&aconnector->mst_status, MST_REMOTE_EDID, true); } @@ -360,10 +362,13 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) struct dc_sink_init_data init_params = { .link = aconnector->dc_link, .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST }; + const struct edid *edid; + + edid = drm_edid_raw(aconnector->drm_edid); // FIXME: Get rid of drm_edid_raw() dc_sink = dc_link_add_remote_sink( aconnector->dc_link, - (uint8_t *)aconnector->edid, - (aconnector->edid->extensions + 1) * EDID_LENGTH, + (uint8_t *)edid, + (edid->extensions + 1) * EDID_LENGTH, &init_params); if (!dc_sink) { @@ -405,7 +410,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) if (aconnector->dc_sink) { amdgpu_dm_update_freesync_caps( - connector, aconnector->edid); + connector, aconnector->drm_edid); #if defined(CONFIG_DRM_AMD_DC_FP) if (!validate_dsc_caps_on_connector(aconnector)) @@ -419,10 +424,9 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) } } - drm_connector_update_edid_property( - &aconnector->base, aconnector->edid); + drm_edid_connector_update(&aconnector->base, aconnector->drm_edid); - ret = drm_add_edid_modes(connector, aconnector->edid); + ret = drm_edid_connector_add_modes(connector); return ret; } @@ -500,7 +504,7 @@ dm_dp_mst_detect(struct drm_connector *connector, dc_sink_release(aconnector->dc_sink); aconnector->dc_sink = NULL; - aconnector->edid = NULL; + aconnector->drm_edid = NULL; aconnector->dsc_aux = NULL; port->passthrough_aux = NULL; @@ -1120,6 +1124,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, int i, k, ret; bool debugfs_overwrite = false; uint16_t fec_overhead_multiplier_x1000 = get_fec_overhead_multiplier(dc_link); + struct drm_connector_state *new_conn_state; memset(params, 0, sizeof(params)); @@ -1127,7 +1132,7 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, return PTR_ERR(mst_state); /* Set up params */ - DRM_DEBUG_DRIVER("%s: MST_DSC Set up params for %d streams\n", __func__, dc_state->stream_count); + DRM_DEBUG_DRIVER("%s: MST_DSC Try to set up params from %d streams\n", __func__, dc_state->stream_count); for (i = 0; i < dc_state->stream_count; i++) { struct dc_dsc_policy dsc_policy = {0}; @@ -1143,6 +1148,14 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, if (!aconnector->mst_output_port) continue; + new_conn_state = drm_atomic_get_new_connector_state(state, &aconnector->base); + + if (!new_conn_state) { + DRM_DEBUG_DRIVER("%s:%d MST_DSC Skip the stream 0x%p with invalid new_conn_state\n", + __func__, __LINE__, stream); + continue; + } + stream->timing.flags.DSC = 0; params[count].timing = &stream->timing; @@ -1175,6 +1188,8 @@ static int compute_mst_dsc_configs_for_link(struct drm_atomic_state *state, count++; } + DRM_DEBUG_DRIVER("%s: MST_DSC Params set up for %d streams\n", __func__, count); + if (count == 0) { ASSERT(0); return 0; @@ -1302,7 +1317,7 @@ static bool is_dsc_need_re_compute( continue; aconnector = (struct amdgpu_dm_connector *) stream->dm_stream_context; - if (!aconnector || !aconnector->dsc_aux) + if (!aconnector) continue; stream_on_link[new_stream_on_link_num] = aconnector; diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c index adc710fe4a4539..8d2cf95ae73930 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c @@ -78,10 +78,3 @@ void bios_set_scratch_critical_state( uint32_t critial_state = state ? 1 : 0; REG_UPDATE(BIOS_SCRATCH_6, S6_CRITICAL_STATE, critial_state); } - -uint32_t bios_get_vga_enabled_displays( - struct dc_bios *bios) -{ - return REG_READ(BIOS_SCRATCH_3) & 0XFFFF; -} - diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h index e1b4a40a353db1..ab162f2fe57766 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h @@ -34,7 +34,6 @@ uint8_t *bios_get_image(struct dc_bios *bp, uint32_t offset, bool bios_is_accelerated_mode(struct dc_bios *bios); void bios_set_scratch_acc_mode_change(struct dc_bios *bios, uint32_t state); void bios_set_scratch_critical_state(struct dc_bios *bios, bool state); -uint32_t bios_get_vga_enabled_displays(struct dc_bios *bios); #define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type))) diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c index e93df3d6222e68..bc123f1884da32 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c @@ -50,12 +50,13 @@ #include "link.h" #include "logger_types.h" + + +#include "yellow_carp_offset.h" #undef DC_LOGGER #define DC_LOGGER \ clk_mgr->base.base.ctx->logger -#include "yellow_carp_offset.h" - #define regCLK1_CLK_PLL_REQ 0x0237 #define regCLK1_CLK_PLL_REQ_BASE_IDX 0 diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c index 29eff386505ab5..91d872d6d392b1 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c @@ -53,9 +53,6 @@ #include "logger_types.h" -#undef DC_LOGGER -#define DC_LOGGER \ - clk_mgr->base.base.ctx->logger #define MAX_INSTANCE 7 @@ -77,6 +74,9 @@ static const struct IP_BASE CLK_BASE = { { { { 0x00016C00, 0x02401800, 0, 0, 0, { { 0x0001B200, 0x0242DC00, 0, 0, 0, 0, 0, 0 } }, { { 0x0001B400, 0x0242E000, 0, 0, 0, 0, 0, 0 } } } }; +#undef DC_LOGGER +#define DC_LOGGER \ + clk_mgr->base.base.ctx->logger #define regCLK1_CLK_PLL_REQ 0x0237 #define regCLK1_CLK_PLL_REQ_BASE_IDX 0 diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index b46a3afe48ca7c..b77333817f1895 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -55,6 +55,7 @@ #define DC_LOGGER \ clk_mgr->base.base.ctx->logger + #define regCLK1_CLK_PLL_REQ 0x0237 #define regCLK1_CLK_PLL_REQ_BASE_IDX 0 @@ -132,6 +133,8 @@ static void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state * for (i = 0; i < dc->res_pool->pipe_count; ++i) { struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; + struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dccg *dccg = clk_mgr_internal->dccg; struct pipe_ctx *pipe = safe_to_lower ? &context->res_ctx.pipe_ctx[i] : &dc->current_state->res_ctx.pipe_ctx[i]; @@ -148,8 +151,21 @@ static void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state * new_pipe->stream_res.stream_enc && new_pipe->stream_res.stream_enc->funcs->is_fifo_enabled && new_pipe->stream_res.stream_enc->funcs->is_fifo_enabled(new_pipe->stream_res.stream_enc); - if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal) || - !pipe->stream->link_enc) && !stream_changed_otg_dig_on) { + + bool has_active_hpo = false; + + if (old_pipe->stream && new_pipe->stream && old_pipe->stream == new_pipe->stream) { + has_active_hpo = dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(old_pipe) && + dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(new_pipe); + + } + + + if (!has_active_hpo && !dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe) && + (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal) || + !pipe->stream->link_enc) && !stream_changed_otg_dig_on)) { + + /* This w/a should not trigger when we have a dig active */ if (disable) { if (pipe->stream_res.tg && pipe->stream_res.tg->funcs->immediate_disable_crtc) @@ -257,11 +273,11 @@ static void dcn35_notify_host_router_bw(struct clk_mgr *clk_mgr_base, struct dc_ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); uint32_t host_router_bw_kbps[MAX_HOST_ROUTERS_NUM] = { 0 }; int i; - for (i = 0; i < context->stream_count; ++i) { const struct dc_stream_state *stream = context->streams[i]; const struct dc_link *link = stream->link; - uint8_t lowest_dpia_index = 0, hr_index = 0; + uint8_t lowest_dpia_index = 0; + unsigned int hr_index = 0; if (!link) continue; @@ -271,6 +287,8 @@ static void dcn35_notify_host_router_bw(struct clk_mgr *clk_mgr_base, struct dc_ continue; hr_index = (link->link_index - lowest_dpia_index) / 2; + if (hr_index >= MAX_HOST_ROUTERS_NUM) + continue; host_router_bw_kbps[hr_index] += dc_bandwidth_in_kbps_from_timing( &stream->timing, dc_link_get_highest_encoding_format(link)); } @@ -975,11 +993,8 @@ static void dcn35_exit_low_power_state(struct clk_mgr *clk_mgr_base) static bool dcn35_is_ips_supported(struct clk_mgr *clk_mgr_base) { struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); - bool ips_supported = true; - - ips_supported = dcn35_smu_get_ips_supported(clk_mgr) ? true : false; - return ips_supported; + return dcn35_smu_get_ips_supported(clk_mgr) ? true : false; } static void dcn35_init_clocks_fpga(struct clk_mgr *clk_mgr) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index a88f1b6ea64cfa..49fe7dcf9372e4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -621,8 +621,8 @@ dc_stream_forward_crc_window(struct dc_stream_state *stream, * dc_stream_configure_crc() - Configure CRC capture for the given stream. * @dc: DC Object * @stream: The stream to configure CRC on. - * @enable: Enable CRC if true, disable otherwise. * @crc_window: CRC window (x/y start/end) information + * @enable: Enable CRC if true, disable otherwise. * @continuous: Capture CRC on every frame if true. Otherwise, only capture * once. * @@ -1157,6 +1157,8 @@ static void dc_update_visual_confirm_color(struct dc *dc, struct dc_state *conte get_surface_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color)); else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SWIZZLE) get_surface_tile_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color)); + else if (dc->debug.visual_confirm == VISUAL_CONFIRM_HW_CURSOR) + get_cursor_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color)); else { if (dc->ctx->dce_version < DCN_VERSION_2_0) color_space_to_black_color( @@ -1233,16 +1235,8 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) */ if (is_phantom) { if (tg->funcs->enable_crtc) { - int main_pipe_width = 0, main_pipe_height = 0; - struct dc_stream_state *old_paired_stream = dc_state_get_paired_subvp_stream(dc->current_state, old_stream); - - if (old_paired_stream) { - main_pipe_width = old_paired_stream->dst.width; - main_pipe_height = old_paired_stream->dst.height; - } - - if (dc->hwss.blank_phantom) - dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height); + if (dc->hwseq->funcs.blank_pixel_data) + dc->hwseq->funcs.blank_pixel_data(dc, pipe, true); tg->funcs->enable_crtc(tg); } } @@ -1437,6 +1431,7 @@ void dc_hardware_init(struct dc *dc) detect_edp_presence(dc); if (dc->ctx->dce_environment != DCE_ENV_VIRTUAL_HW) dc->hwss.init_hw(dc); + dc_dmub_srv_notify_fw_dc_power_state(dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D0); } void dc_init_callbacks(struct dc *dc, @@ -1876,6 +1871,41 @@ void dc_z10_save_init(struct dc *dc) dc->hwss.z10_save_init(dc); } +/* Set a pipe unlock order based on the change in DET allocation and stores it in dc scratch memory + * Prevents over allocation of DET during unlock process + * e.g. 2 pipe config with different streams with a max of 20 DET segments + * Before: After: + * - Pipe0: 10 DET segments - Pipe0: 12 DET segments + * - Pipe1: 10 DET segments - Pipe1: 8 DET segments + * If Pipe0 gets updated first, 22 DET segments will be allocated + */ +static void determine_pipe_unlock_order(struct dc *dc, struct dc_state *context) +{ + unsigned int i = 0; + struct pipe_ctx *pipe = NULL; + struct timing_generator *tg = NULL; + + if (!dc->config.set_pipe_unlock_order) + return; + + memset(dc->scratch.pipes_to_unlock_first, 0, sizeof(dc->scratch.pipes_to_unlock_first)); + for (i = 0; i < dc->res_pool->pipe_count; i++) { + pipe = &context->res_ctx.pipe_ctx[i]; + tg = pipe->stream_res.tg; + + if (!resource_is_pipe_type(pipe, OTG_MASTER) || + !tg->funcs->is_tg_enabled(tg) || + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { + continue; + } + + if (resource_calculate_det_for_stream(context, pipe) < + resource_calculate_det_for_stream(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i])) { + dc->scratch.pipes_to_unlock_first[i] = true; + } + } +} + /** * dc_commit_state_no_check - Apply context to the hardware * @@ -1974,6 +2004,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c context->streams[i]->update_flags.bits.dsc_changed = prev_dsc_changed; } + determine_pipe_unlock_order(dc, context); /* Program all planes within new context*/ if (dc->res_pool->funcs->prepare_mcache_programming) dc->res_pool->funcs->prepare_mcache_programming(dc, context); @@ -2156,6 +2187,14 @@ enum dc_status dc_commit_streams(struct dc *dc, struct dc_commit_streams_params context->power_source = params->power_source; res = dc_validate_with_context(dc, set, params->stream_count, context, false); + + /* + * Only update link encoder to stream assignment after bandwidth validation passed. + */ + if (res == DC_OK && dc->res_pool->funcs->link_encs_assign) + dc->res_pool->funcs->link_encs_assign( + dc, context, context->streams, context->stream_count); + if (res != DC_OK) { BREAK_TO_DEBUGGER(); goto fail; @@ -2477,41 +2516,35 @@ static enum surface_update_type get_scaling_info_update_type( if (!u->scaling_info) return UPDATE_TYPE_FAST; - if (u->scaling_info->dst_rect.width != u->surface->dst_rect.width + if (u->scaling_info->src_rect.width != u->surface->src_rect.width + || u->scaling_info->src_rect.height != u->surface->src_rect.height + || u->scaling_info->dst_rect.width != u->surface->dst_rect.width || u->scaling_info->dst_rect.height != u->surface->dst_rect.height + || u->scaling_info->clip_rect.width != u->surface->clip_rect.width + || u->scaling_info->clip_rect.height != u->surface->clip_rect.height || u->scaling_info->scaling_quality.integer_scaling != - u->surface->scaling_quality.integer_scaling - ) { + u->surface->scaling_quality.integer_scaling) { update_flags->bits.scaling_change = 1; + if (u->scaling_info->src_rect.width > u->surface->src_rect.width + || u->scaling_info->src_rect.height > u->surface->src_rect.height) + /* Making src rect bigger requires a bandwidth change */ + update_flags->bits.clock_change = 1; + if ((u->scaling_info->dst_rect.width < u->surface->dst_rect.width || u->scaling_info->dst_rect.height < u->surface->dst_rect.height) && (u->scaling_info->dst_rect.width < u->surface->src_rect.width || u->scaling_info->dst_rect.height < u->surface->src_rect.height)) /* Making dst rect smaller requires a bandwidth change */ update_flags->bits.bandwidth_change = 1; - } - if (u->scaling_info->src_rect.width != u->surface->src_rect.width - || u->scaling_info->src_rect.height != u->surface->src_rect.height) { - - update_flags->bits.scaling_change = 1; - if (u->scaling_info->src_rect.width > u->surface->src_rect.width - || u->scaling_info->src_rect.height > u->surface->src_rect.height) - /* Making src rect bigger requires a bandwidth change */ - update_flags->bits.clock_change = 1; + if (u->scaling_info->src_rect.width > dc->caps.max_optimizable_video_width && + (u->scaling_info->clip_rect.width > u->surface->clip_rect.width || + u->scaling_info->clip_rect.height > u->surface->clip_rect.height)) + /* Changing clip size of a large surface may result in MPC slice count change */ + update_flags->bits.bandwidth_change = 1; } - if (u->scaling_info->src_rect.width > dc->caps.max_optimizable_video_width && - (u->scaling_info->clip_rect.width > u->surface->clip_rect.width || - u->scaling_info->clip_rect.height > u->surface->clip_rect.height)) - /* Changing clip size of a large surface may result in MPC slice count change */ - update_flags->bits.bandwidth_change = 1; - - if (u->scaling_info->clip_rect.width != u->surface->clip_rect.width || - u->scaling_info->clip_rect.height != u->surface->clip_rect.height) - update_flags->bits.clip_size_change = 1; - if (u->scaling_info->src_rect.x != u->surface->src_rect.x || u->scaling_info->src_rect.y != u->surface->src_rect.y || u->scaling_info->clip_rect.x != u->surface->clip_rect.x @@ -2520,13 +2553,13 @@ static enum surface_update_type get_scaling_info_update_type( || u->scaling_info->dst_rect.y != u->surface->dst_rect.y) update_flags->bits.position_change = 1; + /* process every update flag before returning */ if (update_flags->bits.clock_change || update_flags->bits.bandwidth_change || update_flags->bits.scaling_change) return UPDATE_TYPE_FULL; - if (update_flags->bits.position_change || - update_flags->bits.clip_size_change) + if (update_flags->bits.position_change) return UPDATE_TYPE_MED; return UPDATE_TYPE_FAST; @@ -2617,7 +2650,8 @@ static enum surface_update_type det_surface_update(const struct dc *dc, elevate_update_type(&overall_type, type); } - if (update_flags->bits.lut_3d) { + if (update_flags->bits.lut_3d && + u->surface->mcm_luts.lut3d_data.lut3d_src != DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) { type = UPDATE_TYPE_FULL; elevate_update_type(&overall_type, type); } @@ -2637,6 +2671,29 @@ static enum surface_update_type det_surface_update(const struct dc *dc, return overall_type; } +/* May need to flip the desktop plane in cases where MPO plane receives a flip but desktop plane doesn't + * while both planes are flip_immediate + */ +static void force_immediate_gsl_plane_flip(struct dc *dc, struct dc_surface_update *updates, int surface_count) +{ + bool has_flip_immediate_plane = false; + int i; + + for (i = 0; i < surface_count; i++) { + if (updates[i].surface->flip_immediate) { + has_flip_immediate_plane = true; + break; + } + } + + if (has_flip_immediate_plane && surface_count > 1) { + for (i = 0; i < surface_count; i++) { + if (updates[i].surface->flip_immediate) + updates[i].surface->update_flags.bits.addr_update = 1; + } + } +} + static enum surface_update_type check_update_surfaces_for_stream( struct dc *dc, struct dc_surface_update *updates, @@ -2699,6 +2756,9 @@ static enum surface_update_type check_update_surfaces_for_stream( if (stream_update->scaler_sharpener_update) su_flags->bits.scaler_sharpener = 1; + if (stream_update->sharpening_required) + su_flags->bits.sharpening_required = 1; + if (su_flags->raw != 0) overall_type = UPDATE_TYPE_FULL; @@ -2870,10 +2930,20 @@ static void copy_surface_update_to_plane( sizeof(struct dc_transfer_func_distributed_points)); } - if (srf_update->func_shaper) + if (srf_update->cm2_params) { + surface->mcm_shaper_3dlut_setting = srf_update->cm2_params->component_settings.shaper_3dlut_setting; + surface->mcm_lut1d_enable = srf_update->cm2_params->component_settings.lut1d_enable; + surface->mcm_luts = srf_update->cm2_params->cm2_luts; + } + + if (srf_update->func_shaper) { memcpy(&surface->in_shaper_func, srf_update->func_shaper, sizeof(surface->in_shaper_func)); + if (surface->mcm_shaper_3dlut_setting >= DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER) + surface->mcm_luts.shaper = &surface->in_shaper_func; + } + if (srf_update->lut3d_func) memcpy(&surface->lut3d_func, srf_update->lut3d_func, sizeof(surface->lut3d_func)); @@ -2886,10 +2956,17 @@ static void copy_surface_update_to_plane( surface->sdr_white_level_nits = srf_update->sdr_white_level_nits; - if (srf_update->blend_tf) + if (srf_update->blend_tf) { memcpy(&surface->blend_tf, srf_update->blend_tf, sizeof(surface->blend_tf)); + if (surface->mcm_lut1d_enable) + surface->mcm_luts.lut1d_func = &surface->blend_tf; + } + + if (srf_update->cm2_params || srf_update->blend_tf) + surface->lut_bank_a = !surface->lut_bank_a; + if (srf_update->input_csc_color_matrix) surface->input_csc_color_matrix = *srf_update->input_csc_color_matrix; @@ -2901,11 +2978,7 @@ static void copy_surface_update_to_plane( if (srf_update->gamut_remap_matrix) surface->gamut_remap_matrix = *srf_update->gamut_remap_matrix; - if (srf_update->cm2_params) { - surface->mcm_shaper_3dlut_setting = srf_update->cm2_params->component_settings.shaper_3dlut_setting; - surface->mcm_lut1d_enable = srf_update->cm2_params->component_settings.lut1d_enable; - surface->mcm_luts = srf_update->cm2_params->cm2_luts; - } + if (srf_update->cursor_csc_color_matrix) surface->cursor_csc_color_matrix = *srf_update->cursor_csc_color_matrix; @@ -3037,6 +3110,8 @@ static void copy_stream_update_to_stream(struct dc *dc, } if (update->scaler_sharpener_update) stream->scaler_sharpener_update = *update->scaler_sharpener_update; + if (update->sharpening_required) + stream->sharpening_required = *update->sharpening_required; } static void backup_planes_and_stream_state( @@ -3066,7 +3141,10 @@ static void restore_planes_and_stream_state( return; for (i = 0; i < status->plane_count; i++) { + /* refcount will always be valid, restore everything else */ + struct kref refcount = status->plane_states[i]->refcount; *status->plane_states[i] = scratch->plane_states[i]; + status->plane_states[i]->refcount = refcount; } *stream = scratch->stream_state; } @@ -3153,6 +3231,11 @@ static bool update_planes_and_stream_state(struct dc *dc, context = dc->current_state; update_type = dc_check_update_surfaces_for_stream( dc, srf_updates, surface_count, stream_update, stream_status); + /* It is possible to receive a flip for one plane while there are multiple flip_immediate planes in the same stream. + * E.g. Desktop and MPO plane are flip_immediate but only the MPO plane received a flip + * Force the other flip_immediate planes to flip so GSL doesn't wait for a flip that won't come. + */ + force_immediate_gsl_plane_flip(dc, srf_updates, surface_count); if (update_type == UPDATE_TYPE_FULL) backup_planes_and_stream_state(&dc->scratch.current_state, stream); @@ -3225,8 +3308,7 @@ static bool update_planes_and_stream_state(struct dc *dc, if (update_type != UPDATE_TYPE_MED) continue; - if (surface->update_flags.bits.clip_size_change || - surface->update_flags.bits.position_change) { + if (surface->update_flags.bits.position_change) { for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; @@ -3625,6 +3707,10 @@ static void commit_planes_for_stream_fast(struct dc *dc, struct pipe_ctx *top_pipe_to_program = NULL; struct dc_stream_status *stream_status = NULL; bool should_offload_fams2_flip = false; + bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST); + + if (should_lock_all_pipes) + determine_pipe_unlock_order(dc, context); if (dc->debug.fams2_config.bits.enable && dc->debug.fams2_config.bits.enable_offload_flip && @@ -3677,13 +3763,14 @@ static void commit_planes_for_stream_fast(struct dc *dc, if (!pipe_ctx->plane_state) continue; - if (should_update_pipe_for_plane(context, pipe_ctx, plane_state)) + if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state)) continue; + pipe_ctx->plane_state->triplebuffer_flips = false; if (update_type == UPDATE_TYPE_FAST && - dc->hwss.program_triplebuffer != NULL && - !pipe_ctx->plane_state->flip_immediate && dc->debug.enable_tri_buf) { - /*triple buffer for VUpdate only*/ + dc->hwss.program_triplebuffer != NULL && + !pipe_ctx->plane_state->flip_immediate && dc->debug.enable_tri_buf) { + /*triple buffer for VUpdate only*/ pipe_ctx->plane_state->triplebuffer_flips = true; } } @@ -3742,6 +3829,8 @@ static void commit_planes_for_stream(struct dc *dc, bool subvp_curr_use = false; uint8_t current_stream_mask = 0; + if (should_lock_all_pipes) + determine_pipe_unlock_order(dc, context); // Once we apply the new subvp context to hardware it won't be in the // dc->current_state anymore, so we have to cache it before we apply // the new SubVP context @@ -3749,7 +3838,7 @@ static void commit_planes_for_stream(struct dc *dc, dc_exit_ips_for_hw_access(dc); dc_z10_restore(dc); - if (update_type == UPDATE_TYPE_FULL) + if (update_type == UPDATE_TYPE_FULL && dc->optimized_required) hwss_process_outstanding_hw_updates(dc, dc->current_state); for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -3776,6 +3865,9 @@ static void commit_planes_for_stream(struct dc *dc, context_clock_trace(dc, context); } + if (update_type == UPDATE_TYPE_FULL) + hwss_wait_for_outstanding_hw_updates(dc, dc->current_state); + top_pipe_to_program = resource_get_otg_master_for_stream( &context->res_ctx, stream); @@ -3920,19 +4012,20 @@ static void commit_planes_for_stream(struct dc *dc, struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; if (!pipe_ctx->plane_state) continue; - if (should_update_pipe_for_plane(context, pipe_ctx, plane_state)) + if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state)) continue; pipe_ctx->plane_state->triplebuffer_flips = false; if (update_type == UPDATE_TYPE_FAST && - dc->hwss.program_triplebuffer != NULL && - !pipe_ctx->plane_state->flip_immediate && dc->debug.enable_tri_buf) { - /*triple buffer for VUpdate only*/ - pipe_ctx->plane_state->triplebuffer_flips = true; + dc->hwss.program_triplebuffer != NULL && + !pipe_ctx->plane_state->flip_immediate && dc->debug.enable_tri_buf) { + /*triple buffer for VUpdate only*/ + pipe_ctx->plane_state->triplebuffer_flips = true; } } if (update_type == UPDATE_TYPE_FULL) { /* force vsync flip when reconfiguring pipes to prevent underflow */ plane_state->flip_immediate = false; + plane_state->triplebuffer_flips = false; } } @@ -3953,7 +4046,6 @@ static void commit_planes_for_stream(struct dc *dc, continue; ASSERT(!pipe_ctx->plane_state->triplebuffer_flips); - if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { /*turn off triple buffer for full update*/ dc->hwss.program_triplebuffer( @@ -4028,7 +4120,7 @@ static void commit_planes_for_stream(struct dc *dc, /*program triple buffer after lock based on flip type*/ if (dc->hwss.program_triplebuffer != NULL && dc->debug.enable_tri_buf) { - /*only enable triplebuffer for fast_update*/ + /*only enable triplebuffer for fast_update*/ dc->hwss.program_triplebuffer( dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); } @@ -4777,6 +4869,11 @@ static bool update_planes_and_stream_v1(struct dc *dc, update_type = dc_check_update_surfaces_for_stream( dc, srf_updates, surface_count, stream_update, stream_status); + /* It is possible to receive a flip for one plane while there are multiple flip_immediate planes in the same stream. + * E.g. Desktop and MPO plane are flip_immediate but only the MPO plane received a flip + * Force the other flip_immediate planes to flip so GSL doesn't wait for a flip that won't come. + */ + force_immediate_gsl_plane_flip(dc, srf_updates, surface_count); if (update_type >= UPDATE_TYPE_FULL) { @@ -5338,8 +5435,10 @@ bool dc_set_ips_disable(struct dc *dc, unsigned int disable_ips) void dc_allow_idle_optimizations_internal(struct dc *dc, bool allow, char const *caller_name) { - if (dc->debug.disable_idle_power_optimizations) + if (dc->debug.disable_idle_power_optimizations) { + DC_LOG_DEBUG("%s: disabled\n", __func__); return; + } if (allow != dc->idle_optimizations_allowed) DC_LOG_IPS("%s: allow_idle old=%d new=%d (caller=%s)\n", __func__, @@ -5356,8 +5455,10 @@ void dc_allow_idle_optimizations_internal(struct dc *dc, bool allow, char const return; if (dc->hwss.apply_idle_power_optimizations && dc->clk_mgr != NULL && - dc->hwss.apply_idle_power_optimizations(dc, allow)) + dc->hwss.apply_idle_power_optimizations(dc, allow)) { dc->idle_optimizations_allowed = allow; + DC_LOG_DEBUG("%s: %s\n", __func__, allow ? "enabled" : "disabled"); + } } void dc_exit_ips_for_hw_access_internal(struct dc *dc, const char *caller_name) @@ -5999,7 +6100,30 @@ struct dc_power_profile dc_get_power_profile_for_dc_state(const struct dc_state { struct dc_power_profile profile = { 0 }; - profile.power_level += !context->bw_ctx.bw.dcn.clk.p_state_change_support; + profile.power_level = !context->bw_ctx.bw.dcn.clk.p_state_change_support; + if (!context->clk_mgr || !context->clk_mgr->ctx || !context->clk_mgr->ctx->dc) + return profile; + struct dc *dc = context->clk_mgr->ctx->dc; + if (dc->res_pool->funcs->get_power_profile) + profile.power_level = dc->res_pool->funcs->get_power_profile(context); return profile; } + +/* + ********************************************************************************** + * dc_get_det_buffer_size_from_state() - extracts detile buffer size from dc state + * + * Called when DM wants to log detile buffer size from dc_state + * + ********************************************************************************** + */ +unsigned int dc_get_det_buffer_size_from_state(const struct dc_state *context) +{ + struct dc *dc = context->clk_mgr->ctx->dc; + + if (dc->res_pool->funcs->get_det_buffer_size) + return dc->res_pool->funcs->get_det_buffer_size(context); + else + return 0; +} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 801cdbc8117d9b..af1ea579256003 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -46,11 +46,6 @@ DC_LOG_IF_TRACE(__VA_ARGS__); \ } while (0) -#define TIMING_TRACE(...) do {\ - if (dc->debug.timing_trace) \ - DC_LOG_SYNC(__VA_ARGS__); \ -} while (0) - #define CLOCK_TRACE(...) do {\ if (dc->debug.clock_trace) \ DC_LOG_BANDWIDTH_CALCS(__VA_ARGS__); \ @@ -306,43 +301,6 @@ void post_surface_trace(struct dc *dc) } -void context_timing_trace( - struct dc *dc, - struct resource_context *res_ctx) -{ - int i; - int h_pos[MAX_PIPES] = {0}, v_pos[MAX_PIPES] = {0}; - struct crtc_position position; - unsigned int underlay_idx = dc->res_pool->underlay_pipe_index; - DC_LOGGER_INIT(dc->ctx->logger); - - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - /* get_position() returns CRTC vertical/horizontal counter - * hence not applicable for underlay pipe - */ - if (pipe_ctx->stream == NULL || pipe_ctx->pipe_idx == underlay_idx) - continue; - - pipe_ctx->stream_res.tg->funcs->get_position(pipe_ctx->stream_res.tg, &position); - h_pos[i] = position.horizontal_count; - v_pos[i] = position.vertical_count; - } - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i]; - - if (pipe_ctx->stream == NULL || pipe_ctx->pipe_idx == underlay_idx) - continue; - - TIMING_TRACE("OTG_%d H_tot:%d V_tot:%d H_pos:%d V_pos:%d\n", - pipe_ctx->stream_res.tg->inst, - pipe_ctx->stream->timing.h_total, - pipe_ctx->stream->timing.v_total, - h_pos[i], v_pos[i]); - } -} - void context_clock_trace( struct dc *dc, struct dc_state *context) @@ -434,3 +392,43 @@ char *dc_status_to_str(enum dc_status status) return "Unexpected status error"; } + +char *dc_pixel_encoding_to_str(enum dc_pixel_encoding pixel_encoding) +{ + switch (pixel_encoding) { + case PIXEL_ENCODING_RGB: + return "RGB"; + case PIXEL_ENCODING_YCBCR422: + return "YUV422"; + case PIXEL_ENCODING_YCBCR444: + return "YUV444"; + case PIXEL_ENCODING_YCBCR420: + return "YUV420"; + default: + return "Unknown"; + } +} + +char *dc_color_depth_to_str(enum dc_color_depth color_depth) +{ + switch (color_depth) { + case COLOR_DEPTH_666: + return "6-bpc"; + case COLOR_DEPTH_888: + return "8-bpc"; + case COLOR_DEPTH_101010: + return "10-bpc"; + case COLOR_DEPTH_121212: + return "12-bpc"; + case COLOR_DEPTH_141414: + return "14-bpc"; + case COLOR_DEPTH_161616: + return "16-bpc"; + case COLOR_DEPTH_999: + return "9-bpc"; + case COLOR_DEPTH_111111: + return "11-bpc"; + default: + return "Unknown"; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 7ee2be8f82c467..252af83e34a530 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -312,11 +312,11 @@ void get_mpctree_visual_confirm_color( { const struct tg_color pipe_colors[6] = { {MAX_TG_COLOR_VALUE, 0, 0}, /* red */ - {MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE / 4, 0}, /* orange */ {MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE, 0}, /* yellow */ {0, MAX_TG_COLOR_VALUE, 0}, /* green */ + {0, MAX_TG_COLOR_VALUE, MAX_TG_COLOR_VALUE}, /* cyan */ {0, 0, MAX_TG_COLOR_VALUE}, /* blue */ - {MAX_TG_COLOR_VALUE / 2, 0, MAX_TG_COLOR_VALUE / 2}, /* purple */ + {MAX_TG_COLOR_VALUE, 0, MAX_TG_COLOR_VALUE}, /* magenta */ }; struct pipe_ctx *top_pipe = pipe_ctx; @@ -497,6 +497,23 @@ void get_mclk_switch_visual_confirm_color( } } +void get_cursor_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + uint32_t color_value = MAX_TG_COLOR_VALUE; + + if (pipe_ctx->stream && pipe_ctx->stream->cursor_position.enable) { + color->color_r_cr = color_value; + color->color_g_y = 0; + color->color_b_cb = 0; + } else { + color->color_r_cr = 0; + color->color_g_y = 0; + color->color_b_cb = color_value; + } +} + void set_p_state_switch_method( struct dc *dc, struct dc_state *context, @@ -881,6 +898,9 @@ void hwss_setup_dpp(union block_sequence_params *params) struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_plane_state *plane_state = pipe_ctx->plane_state; + if (!plane_state) + return; + if (dpp && dpp->funcs->dpp_setup) { // program the input csc dpp->funcs->dpp_setup(dpp, @@ -1071,8 +1091,13 @@ void hwss_wait_for_outstanding_hw_updates(struct dc *dc, struct dc_state *dc_con if (!pipe_ctx->stream) continue; - if (pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear) - pipe_ctx->stream_res.tg->funcs->wait_drr_doublebuffer_pending_clear(pipe_ctx->stream_res.tg); + /* For full update we must wait for all double buffer updates, not just DRR updates. This + * is particularly important for minimal transitions. Only check for OTG_MASTER pipes, + * as non-OTG Master pipes share the same OTG as + */ + if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && dc->hwss.wait_for_all_pending_updates) { + dc->hwss.wait_for_all_pending_updates(pipe_ctx); + } hubp = pipe_ctx->plane_res.hubp; if (!hubp) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c index dfdfe22d9e8510..457d60eeb486c2 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c @@ -430,11 +430,10 @@ bool dc_link_get_backlight_level_nits(struct dc_link *link, } bool dc_link_set_backlight_level(const struct dc_link *link, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp) + struct set_backlight_level_params *backlight_level_params) { return link->dc->link_srv->edp_set_backlight_level(link, - backlight_pwm_u16_16, frame_ramp); + backlight_level_params); } bool dc_link_set_backlight_level_nits(struct dc_link *link, 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 c7599c40d4be38..626f75b6ad0037 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -765,25 +765,6 @@ static inline void get_vp_scan_direction( *flip_horz_scan_dir = !*flip_horz_scan_dir; } -/* - * This is a preliminary vp size calculation to allow us to check taps support. - * The result is completely overridden afterwards. - */ -static void calculate_viewport_size(struct pipe_ctx *pipe_ctx) -{ - struct scaler_data *data = &pipe_ctx->plane_res.scl_data; - - data->viewport.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz, data->recout.width)); - data->viewport.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert, data->recout.height)); - data->viewport_c.width = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.horz_c, data->recout.width)); - data->viewport_c.height = dc_fixpt_ceil(dc_fixpt_mul_int(data->ratios.vert_c, data->recout.height)); - if (pipe_ctx->plane_state->rotation == ROTATION_ANGLE_90 || - pipe_ctx->plane_state->rotation == ROTATION_ANGLE_270) { - swap(data->viewport.width, data->viewport.height); - swap(data->viewport_c.width, data->viewport_c.height); - } -} - static struct rect intersect_rec(const struct rect *r0, const struct rect *r1) { struct rect rec; @@ -1468,6 +1449,7 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) const struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; const struct rect odm_slice_src = resource_get_odm_slice_src_rect(pipe_ctx); + struct scaling_taps temp = {0}; bool res = false; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); @@ -1519,14 +1501,16 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) res = spl_calculate_scaler_params(spl_in, spl_out); // Convert respective out params from SPL to scaler data translate_SPL_out_params_to_pipe_ctx(pipe_ctx, spl_out); + + /* Ignore scaler failure if pipe context plane is phantom plane */ + if (!res && plane_state->is_phantom) + res = true; } else { #endif /* depends on h_active */ calculate_recout(pipe_ctx); /* depends on pixel format */ calculate_scaling_ratios(pipe_ctx); - /* depends on scaling ratios and recout, does not calculate offset yet */ - calculate_viewport_size(pipe_ctx); /* * LB calculations depend on vp size, h/v_active and scaling ratios @@ -1547,6 +1531,24 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.scl_data.lb_params.alpha_en = plane_state->per_pixel_alpha; + // get TAP value with 100x100 dummy data for max scaling qualify, override + // if a new scaling quality required + pipe_ctx->plane_res.scl_data.viewport.width = 100; + pipe_ctx->plane_res.scl_data.viewport.height = 100; + pipe_ctx->plane_res.scl_data.viewport_c.width = 100; + pipe_ctx->plane_res.scl_data.viewport_c.height = 100; + if (pipe_ctx->plane_res.xfm != NULL) + res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( + pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); + + if (pipe_ctx->plane_res.dpp != NULL) + res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( + pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); + + temp = pipe_ctx->plane_res.scl_data.taps; + + calculate_inits_and_viewports(pipe_ctx); + if (pipe_ctx->plane_res.xfm != NULL) res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps( pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); @@ -1573,11 +1575,14 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) &plane_state->scaling_quality); } - /* - * Depends on recout, scaling ratios, h_active and taps - * May need to re-check lb size after this in some obscure scenario - */ - if (res) + /* Ignore scaler failure if pipe context plane is phantom plane */ + if (!res && plane_state->is_phantom) + res = true; + + if (res && (pipe_ctx->plane_res.scl_data.taps.v_taps != temp.v_taps || + pipe_ctx->plane_res.scl_data.taps.h_taps != temp.h_taps || + pipe_ctx->plane_res.scl_data.taps.v_taps_c != temp.v_taps_c || + pipe_ctx->plane_res.scl_data.taps.h_taps_c != temp.h_taps_c)) calculate_inits_and_viewports(pipe_ctx); /* @@ -2089,7 +2094,8 @@ int resource_get_odm_slice_dst_width(struct pipe_ctx *otg_master, count = resource_get_odm_slice_count(otg_master); h_active = timing->h_addressable + timing->h_border_left + - timing->h_border_right; + timing->h_border_right + + otg_master->hblank_borrow; width = h_active / count; if (otg_master->stream_res.tg) @@ -4021,6 +4027,41 @@ enum dc_status dc_validate_with_context(struct dc *dc, return res; } +/** + * decide_hblank_borrow - Decides the horizontal blanking borrow value for a given pipe context. + * @pipe_ctx: Pointer to the pipe context structure. + * + * This function calculates the horizontal blanking borrow value for a given pipe context based on the + * display stream compression (DSC) configuration. If the horizontal active pixels (hactive) are less + * than the total width of the DSC slices, it sets the hblank_borrow value to the difference. If the + * total horizontal timing minus the hblank_borrow value is less than 32, it resets the hblank_borrow + * value to 0. + */ +static void decide_hblank_borrow(struct pipe_ctx *pipe_ctx) +{ + uint32_t hactive; + uint32_t ceil_slice_width; + struct dc_stream_state *stream = NULL; + + if (!pipe_ctx) + return; + + stream = pipe_ctx->stream; + + if (stream->timing.flags.DSC) { + hactive = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; + + /* Assume if determined slices does not divide Hactive evenly, Hborrow is needed for padding*/ + if (hactive % stream->timing.dsc_cfg.num_slices_h != 0) { + ceil_slice_width = (hactive / stream->timing.dsc_cfg.num_slices_h) + 1; + pipe_ctx->hblank_borrow = ceil_slice_width * stream->timing.dsc_cfg.num_slices_h - hactive; + + if (stream->timing.h_total - hactive - pipe_ctx->hblank_borrow < 32) + pipe_ctx->hblank_borrow = 0; + } + } +} + /** * dc_validate_global_state() - Determine if hardware can support a given state * @@ -4059,6 +4100,10 @@ enum dc_status dc_validate_global_state( if (pipe_ctx->stream != stream) continue; + /* Decide whether hblank borrow is needed and save it in pipe_ctx */ + if (dc->debug.enable_hblank_borrow) + decide_hblank_borrow(pipe_ctx); + if (dc->res_pool->funcs->patch_unknown_plane_state && pipe_ctx->plane_state && pipe_ctx->plane_state->tiling_info.gfx9.swizzle == DC_SW_UNKNOWN) { @@ -4094,14 +4139,6 @@ enum dc_status dc_validate_global_state( if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate)) result = DC_FAIL_BANDWIDTH_VALIDATE; - /* - * Only update link encoder to stream assignment after bandwidth validation passed. - * TODO: Split out assignment and validation. - */ - if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false) - dc->res_pool->funcs->link_encs_assign( - dc, new_ctx, new_ctx->streams, new_ctx->stream_count); - return result; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 9a406d74c0dd76..55dc482d9b3660 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -292,7 +292,9 @@ bool dc_stream_set_cursor_attributes( * 2. If not subvp high refresh, for single display cases, if resolution is >= 5K and refresh rate < 120hz * 3. If not subvp high refresh, for multi display cases, if resolution is >= 4K and refresh rate < 120hz */ - if (dc->debug.allow_sw_cursor_fallback && attributes->height * attributes->width * 4 > 16384) { + if (dc->debug.allow_sw_cursor_fallback && + attributes->height * attributes->width * 4 > 16384 && + !stream->hw_cursor_req) { if (check_subvp_sw_cursor_fallback_req(dc, stream)) return false; } @@ -421,7 +423,6 @@ bool dc_stream_program_cursor_position( /* apply/update visual confirm */ if (dc->debug.visual_confirm == VISUAL_CONFIRM_HW_CURSOR) { /* update software state */ - uint32_t color_value = MAX_TG_COLOR_VALUE; int i; for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -429,15 +430,7 @@ bool dc_stream_program_cursor_position( /* adjust visual confirm color for all pipes with current stream */ if (stream == pipe_ctx->stream) { - if (stream->cursor_position.enable) { - pipe_ctx->visual_confirm_color.color_r_cr = color_value; - pipe_ctx->visual_confirm_color.color_g_y = 0; - pipe_ctx->visual_confirm_color.color_b_cb = 0; - } else { - pipe_ctx->visual_confirm_color.color_r_cr = 0; - pipe_ctx->visual_confirm_color.color_g_y = 0; - pipe_ctx->visual_confirm_color.color_b_cb = color_value; - } + get_cursor_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color)); /* programming hardware */ if (pipe_ctx->plane_state) @@ -819,12 +812,12 @@ void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream) stream->dst.height, stream->output_color_space); DC_LOG_DC( - "\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixelencoder:%d, displaycolorDepth:%d\n", + "\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixel_encoding:%s, color_depth:%s\n", stream->timing.pix_clk_100hz / 10, stream->timing.h_total, stream->timing.v_total, - stream->timing.pixel_encoding, - stream->timing.display_color_depth); + dc_pixel_encoding_to_str(stream->timing.pixel_encoding), + dc_color_depth_to_str(stream->timing.display_color_depth)); DC_LOG_DC( "\tlink: %d\n", stream->link->link_index); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 3992ad73165bc6..e9b9126c040170 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -55,7 +55,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.301" +#define DC_VER "3.2.310" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -225,6 +225,11 @@ struct dc_dmub_caps { bool subvp_psr; bool gecc_enable; uint8_t fams_ver; + bool aux_backlight_support; +}; + +struct dc_scl_caps { + bool sharpener_support; }; struct dc_caps { @@ -285,6 +290,7 @@ struct dc_caps { uint16_t subvp_vertical_int_margin_us; bool seamless_odm; uint32_t max_v_total; + bool vtotal_limited_by_fp2; uint32_t max_disp_clock_khz_at_vmin; uint8_t subvp_drr_vblank_start_margin_us; bool cursor_not_scaled; @@ -292,6 +298,7 @@ struct dc_caps { bool sequential_ono; /* Conservative limit for DCC cases which require ODM4:1 to support*/ uint32_t dcc_plane_width_limit; + struct dc_scl_caps scl_caps; }; struct dc_bug_wa { @@ -463,6 +470,7 @@ struct dc_config { unsigned int enable_fpo_flicker_detection; bool disable_hbr_audio_dp2; bool consolidated_dpia_dp_lt; + bool set_pipe_unlock_order; }; enum visual_confirm { @@ -862,7 +870,6 @@ struct dc_debug_options { bool sanity_checks; bool max_disp_clk; bool surface_trace; - bool timing_trace; bool clock_trace; bool validation_trace; bool bandwidth_calcs_trace; @@ -1061,6 +1068,8 @@ struct dc_debug_options { unsigned int sharpen_policy; unsigned int scale_to_sharpness_policy; bool skip_full_updated_if_possible; + unsigned int enable_oled_edp_power_up_opt; + bool enable_hblank_borrow; }; @@ -1253,7 +1262,6 @@ union surface_update_flags { uint32_t rotation_change:1; uint32_t swizzle_change:1; uint32_t scaling_change:1; - uint32_t clip_size_change: 1; uint32_t position_change:1; uint32_t in_transfer_func_change:1; uint32_t input_csc_change:1; @@ -1355,6 +1363,7 @@ struct dc_plane_state { enum mpcc_movable_cm_location mcm_location; struct dc_csc_transform cursor_csc_color_matrix; bool adaptive_sharpness_en; + int adaptive_sharpness_policy; int sharpness_level; enum linear_light_scaling linear_light_scaling; unsigned int sdr_white_level_nits; @@ -1461,6 +1470,7 @@ struct dc { struct dc_scratch_space current_state; struct dc_scratch_space new_state; struct dc_stream_state temp_stream; // Used so we don't need to allocate stream on the stack + bool pipes_to_unlock_first[MAX_PIPES]; /* Any of the pipes indicated here should be unlocked first */ } scratch; struct dml2_configuration_options dml2_options; @@ -1513,7 +1523,7 @@ struct dc_surface_update { * change cm2_params.component_settings: Full update * change cm2_params.cm2_luts: Fast update */ - struct dc_cm2_parameters *cm2_params; + const struct dc_cm2_parameters *cm2_params; const struct dc_csc_transform *cursor_csc_color_matrix; unsigned int sdr_white_level_nits; }; @@ -1770,7 +1780,6 @@ struct dc_link { bool dongle_mode_timing_override; bool blank_stream_on_ocs_change; bool read_dpcd204h_on_irq_hpd; - bool disable_assr_for_uhbr; } wa_flags; struct link_mst_stream_allocation_table mst_stream_alloc_table; @@ -1786,6 +1795,7 @@ struct dc_link { // BW ALLOCATON USB4 ONLY struct dc_dpia_bw_alloc dpia_bw_alloc_config; bool skip_implict_edp_power_control; + enum backlight_control_type backlight_control_type; }; /* Return an enumerated dc_link. @@ -2203,8 +2213,7 @@ void dc_link_edp_panel_backlight_power_on(struct dc_link *link, * and 16 bit fractional, where 1.0 is max backlight value. */ bool dc_link_set_backlight_level(const struct dc_link *dc_link, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); + struct set_backlight_level_params *backlight_level_params); /* Set/get nits-based backlight level of an embedded panel (eDP, LVDS). */ bool dc_link_set_backlight_level_nits(struct dc_link *link, @@ -2543,6 +2552,8 @@ struct dc_power_profile { struct dc_power_profile dc_get_power_profile_for_dc_state(const struct dc_state *context); +unsigned int dc_get_det_buffer_size_from_state(const struct dc_state *context); + /* DSC Interfaces */ #include "dc_dsc.h" diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 1e7de0f03290a3..f90fc154549a80 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -519,7 +519,8 @@ void dc_dmub_srv_get_visual_confirm_color_cmd(struct dc *dc, struct pipe_ctx *pi union dmub_rb_cmd cmd = { 0 }; unsigned int panel_inst = 0; - if (!dc_get_edp_link_panel_inst(dc, pipe_ctx->stream->link, &panel_inst)) + if (!dc_get_edp_link_panel_inst(dc, pipe_ctx->stream->link, &panel_inst) && + dc->debug.visual_confirm == VISUAL_CONFIRM_DISABLE) return; memset(&cmd, 0, sizeof(cmd)); @@ -1012,7 +1013,6 @@ static bool dc_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) r2 = test_pipe->plane_res.scl_data.recout; r2_r = r2.x + r2.width; r2_b = r2.y + r2.height; - split_pipe = test_pipe; /** * There is another half plane on same layer because of @@ -1294,6 +1294,8 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle) memset(&new_signals, 0, sizeof(new_signals)); + new_signals.bits.allow_idle = 1; /* always set */ + if (dc->config.disable_ips == DMUB_IPS_ENABLE || dc->config.disable_ips == DMUB_IPS_DISABLE_DYNAMIC) { new_signals.bits.allow_pg = 1; @@ -1389,7 +1391,7 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc) */ dc_dmub_srv->needs_idle_wake = false; - if (prev_driver_signals.bits.allow_ips2 && + if ((prev_driver_signals.bits.allow_ips2 || prev_driver_signals.all == 0) && (!dc->debug.optimize_ips_handshake || ips_fw->signals.bits.ips2_commit || !ips_fw->signals.bits.in_idle)) { DC_LOG_IPS( @@ -1450,7 +1452,7 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc) } dc_dmub_srv_notify_idle(dc, false); - if (prev_driver_signals.bits.allow_ips1) { + if (prev_driver_signals.bits.allow_ips1 || prev_driver_signals.all == 0) { DC_LOG_IPS( "wait for IPS1 commit clear (ips1_commit=%u ips2_commit=%u)", ips_fw->signals.bits.ips1_commit, @@ -1862,3 +1864,81 @@ void dc_dmub_srv_fams2_passthrough_flip( dm_execute_dmub_cmd_list(dc->ctx, num_cmds, cmds, DM_DMUB_WAIT_TYPE_WAIT); } } + +bool dc_dmub_srv_ips_residency_cntl(struct dc_dmub_srv *dc_dmub_srv, bool start_measurement) +{ + bool result; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return false; + + result = dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__IPS_RESIDENCY, + start_measurement, NULL, DM_DMUB_WAIT_TYPE_WAIT); + + return result; +} + +void dc_dmub_srv_ips_query_residency_info(struct dc_dmub_srv *dc_dmub_srv, struct ips_residency_info *output) +{ + uint32_t i; + enum dmub_gpint_command command_code; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return; + + switch (output->ips_mode) { + case DMUB_IPS_MODE_IPS1_MAX: + command_code = DMUB_GPINT__GET_IPS1_HISTOGRAM_COUNTER; + break; + case DMUB_IPS_MODE_IPS2: + command_code = DMUB_GPINT__GET_IPS2_HISTOGRAM_COUNTER; + break; + case DMUB_IPS_MODE_IPS1_RCG: + command_code = DMUB_GPINT__GET_IPS1_RCG_HISTOGRAM_COUNTER; + break; + case DMUB_IPS_MODE_IPS1_ONO2_ON: + command_code = DMUB_GPINT__GET_IPS1_ONO2_ON_HISTOGRAM_COUNTER; + break; + default: + command_code = DMUB_GPINT__INVALID_COMMAND; + break; + } + + if (command_code == DMUB_GPINT__INVALID_COMMAND) + return; + + // send gpint commands and wait for ack + if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_RESIDENCY_PERCENT, + (uint16_t)(output->ips_mode), + &output->residency_percent, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + output->residency_percent = 0; + + if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_RESIDENCY_ENTRY_COUNTER, + (uint16_t)(output->ips_mode), + &output->entry_counter, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + output->entry_counter = 0; + + if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_RESIDENCY_DURATION_US_LO, + (uint16_t)(output->ips_mode), + &output->total_active_time_us[0], DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + output->total_active_time_us[0] = 0; + if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_RESIDENCY_DURATION_US_HI, + (uint16_t)(output->ips_mode), + &output->total_active_time_us[1], DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + output->total_active_time_us[1] = 0; + + if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_INACTIVE_RESIDENCY_DURATION_US_LO, + (uint16_t)(output->ips_mode), + &output->total_inactive_time_us[0], DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + output->total_inactive_time_us[0] = 0; + if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__GET_IPS_INACTIVE_RESIDENCY_DURATION_US_HI, + (uint16_t)(output->ips_mode), + &output->total_inactive_time_us[1], DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + output->total_inactive_time_us[1] = 0; + + // NUM_IPS_HISTOGRAM_BUCKETS = 16 + for (i = 0; i < 16; i++) + if (!dc_wake_and_execute_gpint(dc_dmub_srv->ctx, command_code, i, &output->histogram[i], + DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + output->histogram[i] = 0; +} diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index 42f0cb672d8bb2..10b48198b7a620 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -209,4 +209,43 @@ void dc_dmub_srv_fams2_passthrough_flip( struct dc_stream_state *stream, struct dc_surface_update *srf_updates, int surface_count); + +/** + * struct ips_residency_info - struct containing info from dmub_ips_residency_stats + * + * @ips_mode: The mode of IPS that the follow stats appertain to + * @residency_percent: The percentage of time spent in given IPS mode in millipercent + * @entry_counter: The number of entries made in to this IPS state + * @total_active_time_us: uint32_t array of length 2 representing time in the given IPS mode + * in microseconds. Index 0 is lower 32 bits, index 1 is upper 32 bits. + * @total_inactive_time_us: uint32_t array of length 2 representing time outside the given IPS mode + * in microseconds. Index 0 is lower 32 bits, index 1 is upper 32 bits. + * @histogram: Histogram of given IPS state durations - bucket definitions in dmub_ips.c + */ +struct ips_residency_info { + enum dmub_ips_mode ips_mode; + unsigned int residency_percent; + unsigned int entry_counter; + unsigned int total_active_time_us[2]; + unsigned int total_inactive_time_us[2]; + unsigned int histogram[16]; +}; + +/** + * bool dc_dmub_srv_ips_residency_cntl() - Controls IPS residency measurement status + * + * @dc_dmub_srv: The DC DMUB service pointer + * @start_measurement: Describes whether to start or stop measurement + * + * Return: true if GPINT was sent successfully, false otherwise + */ +bool dc_dmub_srv_ips_residency_cntl(struct dc_dmub_srv *dc_dmub_srv, bool start_measurement); + +/** + * bool dc_dmub_srv_ips_query_residency_info() - Queries DMCUB for residency info + * + * @dc_dmub_srv: The DC DMUB service pointer + * @output: Output struct to copy the the residency info to + */ +void dc_dmub_srv_ips_query_residency_info(struct dc_dmub_srv *dc_dmub_srv, struct ips_residency_info *output); #endif /* _DMUB_DC_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index 41bd95e9177a41..8dd6eb044829a7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -1166,6 +1166,7 @@ struct dpcd_caps { int8_t branch_dev_name[6]; int8_t branch_hw_revision; int8_t branch_fw_revision[2]; + int8_t branch_vendor_specific_data[4]; bool allow_invalid_MSA_timing_param; bool panel_mode_edp; @@ -1191,6 +1192,7 @@ struct dpcd_caps { struct edp_psr_info psr_info; struct replay_info pr_info; + uint16_t edp_oled_emission_rate; }; union dpcd_sink_ext_caps { @@ -1204,7 +1206,7 @@ union dpcd_sink_ext_caps { uint8_t oled : 1; uint8_t reserved_2 : 1; uint8_t miniled : 1; - uint8_t reserved : 1; + uint8_t emission_output : 1; } bits; uint8_t raw; }; @@ -1358,6 +1360,9 @@ struct dp_trace { #ifndef DP_TUNNELING_IRQ #define DP_TUNNELING_IRQ (1 << 5) #endif +#ifndef DP_BRANCH_VENDOR_SPECIFIC_START +#define DP_BRANCH_VENDOR_SPECIFIC_START 0x50C +#endif /** USB4 DPCD BW Allocation Registers Chapter 10.7 **/ #ifndef DP_TUNNELING_CAPABILITIES #define DP_TUNNELING_CAPABILITIES 0xE000D /* 1.4a */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_plane.h b/drivers/gpu/drm/amd/display/dc/dc_plane.h index 44afcd98922480..bd37ec82b42d13 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_plane.h +++ b/drivers/gpu/drm/amd/display/dc/dc_plane.h @@ -26,7 +26,6 @@ #ifndef _DC_PLANE_H_ #define _DC_PLANE_H_ -#include "dc.h" #include "dc_hw_types.h" struct dc_plane_state *dc_create_plane_state(const struct dc *dc); diff --git a/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c b/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c index 603552dbd77164..0e310fd48b5c52 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c +++ b/drivers/gpu/drm/amd/display/dc/dc_spl_translate.c @@ -8,13 +8,13 @@ #include "dcn32/dcn32_dpp.h" #include "dcn401/dcn401_dpp.h" -static struct spl_funcs dcn2_spl_funcs = { +static struct spl_callbacks dcn2_spl_callbacks = { .spl_calc_lb_num_partitions = dscl2_spl_calc_lb_num_partitions, }; -static struct spl_funcs dcn32_spl_funcs = { +static struct spl_callbacks dcn32_spl_callbacks = { .spl_calc_lb_num_partitions = dscl32_spl_calc_lb_num_partitions, }; -static struct spl_funcs dcn401_spl_funcs = { +static struct spl_callbacks dcn401_spl_callbacks = { .spl_calc_lb_num_partitions = dscl401_spl_calc_lb_num_partitions, }; static void populate_splrect_from_rect(struct spl_rect *spl_rect, const struct rect *rect) @@ -38,6 +38,7 @@ static void populate_spltaps_from_taps(struct spl_taps *spl_scaling_quality, spl_scaling_quality->h_taps = scaling_quality->h_taps; spl_scaling_quality->v_taps_c = scaling_quality->v_taps_c; spl_scaling_quality->v_taps = scaling_quality->v_taps; + spl_scaling_quality->integer_scaling = scaling_quality->integer_scaling; } static void populate_taps_from_spltaps(struct scaling_taps *scaling_quality, const struct spl_taps *spl_scaling_quality) @@ -76,16 +77,16 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl // This is used to determine the vtap support switch (plane_state->ctx->dce_version) { case DCN_VERSION_2_0: - spl_in->funcs = &dcn2_spl_funcs; + spl_in->callbacks = dcn2_spl_callbacks; break; case DCN_VERSION_3_2: - spl_in->funcs = &dcn32_spl_funcs; + spl_in->callbacks = dcn32_spl_callbacks; break; case DCN_VERSION_4_01: - spl_in->funcs = &dcn401_spl_funcs; + spl_in->callbacks = dcn401_spl_callbacks; break; default: - spl_in->funcs = &dcn2_spl_funcs; + spl_in->callbacks = dcn2_spl_callbacks; } // Make format field from spl_in point to plane_res scl_data format spl_in->basic_in.format = (enum spl_pixel_format)pipe_ctx->plane_res.scl_data.format; @@ -119,7 +120,7 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl spl_in->odm_slice_index = resource_get_odm_slice_index(pipe_ctx); // Make spl input basic out info output_size width point to stream h active spl_in->basic_out.output_size.width = - stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; + stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right + pipe_ctx->hblank_borrow; // Make spl input basic out info output_size height point to v active spl_in->basic_out.output_size.height = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; @@ -187,14 +188,14 @@ void translate_SPL_in_params_from_pipe_ctx(struct pipe_ctx *pipe_ctx, struct spl spl_in->h_active = pipe_ctx->plane_res.scl_data.h_active; spl_in->v_active = pipe_ctx->plane_res.scl_data.v_active; - spl_in->debug.sharpen_policy = (enum sharpen_policy)pipe_ctx->stream->ctx->dc->debug.sharpen_policy; + spl_in->sharpen_policy = (enum sharpen_policy)plane_state->adaptive_sharpness_policy; spl_in->debug.scale_to_sharpness_policy = (enum scale_to_sharpness_policy)pipe_ctx->stream->ctx->dc->debug.scale_to_sharpness_policy; /* Check if it is stream is in fullscreen and if its HDR. * Use this to determine sharpness levels */ - spl_in->is_fullscreen = dm_helpers_is_fullscreen(pipe_ctx->stream->ctx, pipe_ctx->stream); + spl_in->is_fullscreen = pipe_ctx->stream->sharpening_required; spl_in->is_hdr_on = dm_helpers_is_hdr_on(pipe_ctx->stream->ctx, pipe_ctx->stream); spl_in->sdr_white_level_nits = plane_state->sdr_white_level_nits; } diff --git a/drivers/gpu/drm/amd/display/dc/dc_state.h b/drivers/gpu/drm/amd/display/dc/dc_state.h index caa45db502329b..db1e63a7d460e8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_state.h +++ b/drivers/gpu/drm/amd/display/dc/dc_state.h @@ -26,7 +26,6 @@ #ifndef _DC_STATE_H_ #define _DC_STATE_H_ -#include "dc.h" #include "inc/core_status.h" struct dc_state *dc_state_create(struct dc *dc, struct dc_state_create_params *params); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 14ea47eda0c873..413970588a26da 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -143,6 +143,7 @@ union stream_update_flags { uint32_t crtc_timing_adjust : 1; uint32_t fams_changed : 1; uint32_t scaler_sharpener : 1; + uint32_t sharpening_required : 1; } bits; uint32_t raw; @@ -310,6 +311,7 @@ struct dc_stream_state { struct luminance_data lumin_data; bool scaler_sharpener_update; + bool sharpening_required; }; #define ABM_LEVEL_IMMEDIATE_DISABLE 255 @@ -356,6 +358,7 @@ struct dc_stream_update { struct dc_cursor_position *cursor_position; bool *hw_cursor_req; bool *scaler_sharpener_update; + bool *sharpening_required; }; bool dc_is_stream_unchanged( diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 6d7989b751e2ce..edf4df1d03b58c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -179,6 +179,9 @@ struct dc_panel_patch { unsigned int mst_start_top_delay; unsigned int remove_sink_ext_caps; unsigned int disable_colorimetry; + uint8_t blankstream_before_otg_off; + bool oled_optimize_display_on; + unsigned int force_mst_blocked_discovery; }; struct dc_edid_caps { @@ -922,6 +925,12 @@ struct display_endpoint_id { enum display_endpoint_type ep_type; }; +enum backlight_control_type { + BACKLIGHT_CONTROL_PWM = 0, + BACKLIGHT_CONTROL_VESA_AUX = 1, + BACKLIGHT_CONTROL_AMD_AUX = 2, +}; + #if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) struct otg_phy_mux { uint8_t phy_output_num; @@ -1295,4 +1304,31 @@ struct dc_commit_streams_params { enum dc_power_source_type power_source; }; +struct set_backlight_level_params { + /* backlight in pwm */ + uint32_t backlight_pwm_u16_16; + /* brightness ramping */ + uint32_t frame_ramp; + /* backlight control type + * 0: PWM backlight control + * 1: VESA AUX backlight control + * 2: AMD AUX backlight control + */ + enum backlight_control_type control_type; + /* backlight in millinits */ + uint32_t backlight_millinits; + /* transition time in ms */ + uint32_t transition_time_in_ms; + /* minimum luminance in nits */ + uint32_t min_luminance; + /* maximum luminance in nits */ + uint32_t max_luminance; + /* minimum backlight in pwm */ + uint32_t min_backlight_pwm; + /* maximum backlight in pwm */ + uint32_t max_backlight_pwm; + /* AUX HW instance */ + uint8_t aux_inst; +}; + #endif /* DC_TYPES_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c index 838d72eaa87fbd..b363f5360818d8 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c @@ -1392,10 +1392,10 @@ static void dccg35_set_dtbclk_dto( /* The recommended programming sequence to enable DTBCLK DTO to generate * valid pixel HPO DPSTREAM ENCODER, specifies that DTO source select should - * be set only after DTO is enabled + * be set only after DTO is enabled. + * PIPEx_DTO_SRC_SEL should not be programmed during DTBCLK update since OTG may still be on, and the + * programming is handled in program_pix_clk() regardless, so it can be removed from here. */ - REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst], - PIPE_DTO_SRC_SEL[params->otg_inst], 2); } else { switch (params->otg_inst) { case 0: @@ -1412,9 +1412,12 @@ static void dccg35_set_dtbclk_dto( break; } - REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[params->otg_inst], - DTBCLK_DTO_ENABLE[params->otg_inst], 0, - PIPE_DTO_SRC_SEL[params->otg_inst], params->is_hdmi ? 0 : 1); + /** + * PIPEx_DTO_SRC_SEL should not be programmed during DTBCLK update since OTG may still be on, and the + * programming is handled in program_pix_clk() regardless, so it can be removed from here. + */ + REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst], + DTBCLK_DTO_ENABLE[params->otg_inst], 0); REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], 0); REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], 0); diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c index 0b889004509ad0..d3e46c3cfa5750 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c @@ -580,9 +580,6 @@ static void dccg401_set_dpstreamclk( int otg_inst, int dp_hpo_inst) { - /* set the dtbclk_p source */ - dccg401_set_dtbclk_p_src(dccg, src, otg_inst); - /* enabled to select one of the DTBCLKs for pipe */ if (src == REFCLK) dccg401_disable_dpstreamclk(dccg, dp_hpo_inst); @@ -805,33 +802,6 @@ static void dccg401_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); - switch (link_enc_inst) { - case 0: - REG_UPDATE(SYMCLKA_CLOCK_ENABLE, - SYMCLKA_CLOCK_ENABLE, 1); - if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) - REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_ROOT_GATE_DISABLE, 1); - break; - case 1: - REG_UPDATE(SYMCLKB_CLOCK_ENABLE, - SYMCLKB_CLOCK_ENABLE, 1); - if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) - REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_ROOT_GATE_DISABLE, 1); - break; - case 2: - REG_UPDATE(SYMCLKC_CLOCK_ENABLE, - SYMCLKC_CLOCK_ENABLE, 1); - if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) - REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_ROOT_GATE_DISABLE, 1); - break; - case 3: - REG_UPDATE(SYMCLKD_CLOCK_ENABLE, - SYMCLKD_CLOCK_ENABLE, 1); - if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) - REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, 1); - break; - } - switch (stream_enc_inst) { case 0: REG_UPDATE_2(SYMCLKA_CLOCK_ENABLE, @@ -864,37 +834,8 @@ static void dccg401_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst } } -/*get other front end connected to this backend*/ -static uint8_t dccg401_get_number_enabled_symclk_fe_connected_to_be(struct dccg *dccg, uint32_t link_enc_inst) -{ - uint8_t num_enabled_symclk_fe = 0; - uint32_t fe_clk_en[4] = {0}, be_clk_sel[4] = {0}; - struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); - uint8_t i; - - REG_GET_2(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_EN, &fe_clk_en[0], - SYMCLKA_FE_SRC_SEL, &be_clk_sel[0]); - - REG_GET_2(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_EN, &fe_clk_en[1], - SYMCLKB_FE_SRC_SEL, &be_clk_sel[1]); - - REG_GET_2(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_EN, &fe_clk_en[2], - SYMCLKC_FE_SRC_SEL, &be_clk_sel[2]); - - REG_GET_2(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_EN, &fe_clk_en[3], - SYMCLKD_FE_SRC_SEL, &be_clk_sel[3]); - - for (i = 0; i < ARRAY_SIZE(fe_clk_en); i++) { - if (fe_clk_en[i] && be_clk_sel[i] == link_enc_inst) - num_enabled_symclk_fe++; - } - - return num_enabled_symclk_fe; -} - static void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst) { - uint8_t num_enabled_symclk_fe = 0; struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); switch (stream_enc_inst) { @@ -919,31 +860,6 @@ static void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_ins SYMCLKD_FE_SRC_SEL, 0); break; } - - /*check other enabled symclk fe connected to this be */ - num_enabled_symclk_fe = dccg401_get_number_enabled_symclk_fe_connected_to_be(dccg, link_enc_inst); - /*only turn off backend clk if other front ends attached to this backend are all off, - for mst, only turn off the backend if this is the last front end*/ - if (num_enabled_symclk_fe == 0) { - switch (link_enc_inst) { - case 0: - REG_UPDATE(SYMCLKA_CLOCK_ENABLE, - SYMCLKA_CLOCK_ENABLE, 0); - break; - case 1: - REG_UPDATE(SYMCLKB_CLOCK_ENABLE, - SYMCLKB_CLOCK_ENABLE, 0); - break; - case 2: - REG_UPDATE(SYMCLKC_CLOCK_ENABLE, - SYMCLKC_CLOCK_ENABLE, 0); - break; - case 3: - REG_UPDATE(SYMCLKD_CLOCK_ENABLE, - SYMCLKD_CLOCK_ENABLE, 0); - break; - } - } } static const struct dccg_funcs dccg401_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index 5c2825bc9a8766..d199e4ed2e59e6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -277,7 +277,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute( uint32_t misc1 = 0; uint32_t h_blank; uint32_t h_back_porch; - uint8_t synchronous_clock = 0; /* asynchronous mode */ uint8_t colorimetry_bpc; uint8_t dynamic_range_rgb = 0; /*full range*/ uint8_t dynamic_range_ycbcr = 1; /*bt709*/ @@ -380,7 +379,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute( break; } - misc0 = misc0 | synchronous_clock; misc0 = colorimetry_bpc << 5; if (REG(DP_MSA_TIMING_PARAM1)) { diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c index db7557a1c61347..8a3fbf95c48f2a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c @@ -76,7 +76,6 @@ UNP_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_C__GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_C_MAS mmUNP_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_C, value); - temp = 0; value = 0; temp = address.low_part >> UNP_GRPH_PRIMARY_SURFACE_ADDRESS_C__GRPH_PRIMARY_SURFACE_ADDRESS_C__SHIFT; @@ -112,7 +111,6 @@ UNP_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_L__GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_L_MAS mmUNP_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_L, value); - temp = 0; value = 0; temp = address.low_part >> UNP_GRPH_PRIMARY_SURFACE_ADDRESS_L__GRPH_PRIMARY_SURFACE_ADDRESS_L__SHIFT; diff --git a/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c index 8db9f75144662e..889f314cac65cb 100644 --- a/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce60/dce60_resource.c @@ -717,7 +717,7 @@ static struct link_encoder *dce60_link_encoder_create( kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc110) + if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index eaed5d1c398aa0..dcd2cdfe91eb68 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -365,23 +365,18 @@ bool cm_helper_translate_curve_to_hw_format(struct dc_context *ctx, region_start = -MAX_LOW_POINT; region_end = NUMBER_REGIONS - MAX_LOW_POINT; } else { - /* 11 segments - * segment is from 2^-10 to 2^1 + /* 13 segments + * segment is from 2^-12 to 2^0 * There are less than 256 points, for optimization */ - seg_distr[0] = 3; - seg_distr[1] = 4; - seg_distr[2] = 4; - seg_distr[3] = 4; - seg_distr[4] = 4; - seg_distr[5] = 4; - seg_distr[6] = 4; - seg_distr[7] = 4; - seg_distr[8] = 4; - seg_distr[9] = 4; - seg_distr[10] = 1; - - region_start = -10; + const uint8_t SEG_COUNT = 12; + + for (i = 0; i < SEG_COUNT; i++) + seg_distr[i] = 4; + + seg_distr[SEG_COUNT] = 1; + + region_start = -SEG_COUNT; region_end = 1; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 05df502a54f27a..88cf47a5ea7518 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -46,7 +46,7 @@ #include "clk_mgr.h" __printf(3, 4) -unsigned int snprintf_count(char *pbuf, unsigned int bufsize, char *fmt, ...) +unsigned int snprintf_count(char *pbuf, unsigned int bufsize, const char *fmt, ...) { int ret_vsnprintf; unsigned int chars_printed; diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c index f31f0e3abfc0fa..0690c346f2c521 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c @@ -140,23 +140,18 @@ bool cm3_helper_translate_curve_to_hw_format( region_start = -MAX_LOW_POINT; region_end = NUMBER_REGIONS - MAX_LOW_POINT; } else { - /* 11 segments - * segment is from 2^-10 to 2^0 + /* 13 segments + * segment is from 2^-12 to 2^0 * There are less than 256 points, for optimization */ - seg_distr[0] = 3; - seg_distr[1] = 4; - seg_distr[2] = 4; - seg_distr[3] = 4; - seg_distr[4] = 4; - seg_distr[5] = 4; - seg_distr[6] = 4; - seg_distr[7] = 4; - seg_distr[8] = 4; - seg_distr[9] = 4; - seg_distr[10] = 1; - - region_start = -10; + const uint8_t SEG_COUNT = 12; + + for (i = 0; i < SEG_COUNT; i++) + seg_distr[i] = 4; + + seg_distr[SEG_COUNT] = 1; + + region_start = -SEG_COUNT; region_end = 1; } @@ -285,157 +280,6 @@ bool cm3_helper_translate_curve_to_hw_format( return true; } -#define NUM_DEGAMMA_REGIONS 12 - - -bool cm3_helper_translate_curve_to_degamma_hw_format( - const struct dc_transfer_func *output_tf, - struct pwl_params *lut_params) -{ - struct curve_points3 *corner_points; - struct pwl_result_data *rgb_resulted; - struct pwl_result_data *rgb; - struct pwl_result_data *rgb_plus_1; - - int32_t region_start, region_end; - int32_t i; - uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points; - - if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) - return false; - - corner_points = lut_params->corner_points; - rgb_resulted = lut_params->rgb_resulted; - hw_points = 0; - - memset(lut_params, 0, sizeof(struct pwl_params)); - memset(seg_distr, 0, sizeof(seg_distr)); - - region_start = -NUM_DEGAMMA_REGIONS; - region_end = 0; - - - for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) - seg_distr[i] = -1; - /* 12 segments - * segments are from 2^-12 to 0 - */ - for (i = 0; i < NUM_DEGAMMA_REGIONS ; i++) - seg_distr[i] = 4; - - for (k = 0; k < MAX_REGIONS_NUMBER; k++) { - if (seg_distr[k] != -1) - hw_points += (1 << seg_distr[k]); - } - - j = 0; - for (k = 0; k < (region_end - region_start); k++) { - increment = NUMBER_SW_SEGMENTS / (1 << seg_distr[k]); - start_index = (region_start + k + MAX_LOW_POINT) * - NUMBER_SW_SEGMENTS; - for (i = start_index; i < start_index + NUMBER_SW_SEGMENTS; - i += increment) { - if (j == hw_points - 1) - break; - if (i >= TRANSFER_FUNC_POINTS) - return false; - rgb_resulted[j].red = output_tf->tf_pts.red[i]; - rgb_resulted[j].green = output_tf->tf_pts.green[i]; - rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; - j++; - } - } - - /* last point */ - start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; - rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; - rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; - rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; - - corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2), - dc_fixpt_from_int(region_start)); - corner_points[0].green.x = corner_points[0].red.x; - corner_points[0].blue.x = corner_points[0].red.x; - corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2), - dc_fixpt_from_int(region_end)); - corner_points[1].green.x = corner_points[1].red.x; - corner_points[1].blue.x = corner_points[1].red.x; - - corner_points[0].red.y = rgb_resulted[0].red; - corner_points[0].green.y = rgb_resulted[0].green; - corner_points[0].blue.y = rgb_resulted[0].blue; - - /* see comment above, m_arrPoints[1].y should be the Y value for the - * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) - */ - corner_points[1].red.y = rgb_resulted[hw_points - 1].red; - corner_points[1].green.y = rgb_resulted[hw_points - 1].green; - corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue; - corner_points[1].red.slope = dc_fixpt_zero; - corner_points[1].green.slope = dc_fixpt_zero; - corner_points[1].blue.slope = dc_fixpt_zero; - - if (output_tf->tf == TRANSFER_FUNCTION_PQ) { - /* for PQ, we want to have a straight line from last HW X point, - * and the slope to be such that we hit 1.0 at 10000 nits. - */ - const struct fixed31_32 end_value = - dc_fixpt_from_int(125); - - corner_points[1].red.slope = dc_fixpt_div( - dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y), - dc_fixpt_sub(end_value, corner_points[1].red.x)); - corner_points[1].green.slope = dc_fixpt_div( - dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y), - dc_fixpt_sub(end_value, corner_points[1].green.x)); - corner_points[1].blue.slope = dc_fixpt_div( - dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y), - dc_fixpt_sub(end_value, corner_points[1].blue.x)); - } - - lut_params->hw_points_num = hw_points; - - k = 0; - for (i = 1; i < MAX_REGIONS_NUMBER; i++) { - if (seg_distr[k] != -1) { - lut_params->arr_curve_points[k].segments_num = - seg_distr[k]; - lut_params->arr_curve_points[i].offset = - lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]); - } - k++; - } - - if (seg_distr[k] != -1) - lut_params->arr_curve_points[k].segments_num = seg_distr[k]; - - rgb = rgb_resulted; - rgb_plus_1 = rgb_resulted + 1; - - i = 1; - while (i != hw_points + 1) { - if (dc_fixpt_lt(rgb_plus_1->red, rgb->red)) - rgb_plus_1->red = rgb->red; - if (dc_fixpt_lt(rgb_plus_1->green, rgb->green)) - rgb_plus_1->green = rgb->green; - if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue)) - rgb_plus_1->blue = rgb->blue; - - rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red); - rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green); - rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue); - - ++rgb_plus_1; - ++rgb; - ++i; - } - cm3_helper_convert_to_custom_float(rgb_resulted, - lut_params->corner_points, - hw_points, false); - - return true; -} - bool cm3_helper_convert_to_custom_float( struct pwl_result_data *rgb_resulted, struct curve_points3 *corner_points, diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c index f496e952ceecb8..d01a8b8f95954e 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn10/dcn10_stream_encoder.c @@ -255,7 +255,6 @@ void enc1_stream_encoder_dp_set_stream_attribute( uint32_t misc1 = 0; uint32_t h_blank; uint32_t h_back_porch; - uint8_t synchronous_clock = 0; /* asynchronous mode */ uint8_t colorimetry_bpc; uint8_t dp_pixel_encoding = 0; uint8_t dp_component_depth = 0; @@ -362,7 +361,6 @@ void enc1_stream_encoder_dp_set_stream_attribute( break; } - misc0 = misc0 | synchronous_clock; misc0 = colorimetry_bpc << 5; switch (output_color_space) { diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c index 5b343f745cf333..ae81451a3a725c 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn314/dcn314_dio_stream_encoder.c @@ -83,6 +83,15 @@ void enc314_disable_fifo(struct stream_encoder *enc) REG_UPDATE(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, 0); } +static bool enc314_is_fifo_enabled(struct stream_encoder *enc) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + uint32_t reset_val; + + REG_GET(DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, &reset_val); + return (reset_val != 0); +} + void enc314_dp_set_odm_combine( struct stream_encoder *enc, bool odm_combine) @@ -468,6 +477,7 @@ static const struct stream_encoder_funcs dcn314_str_enc_funcs = { .enable_fifo = enc314_enable_fifo, .disable_fifo = enc314_disable_fifo, + .is_fifo_enabled = enc314_is_fifo_enabled, .set_input_mode = enc314_set_dig_input_mode, }; diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c index 0a27e0942a1234..098c2a01a85099 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn401/dcn401_dio_stream_encoder.c @@ -447,7 +447,6 @@ void enc401_stream_encoder_dp_set_stream_attribute( uint32_t misc1 = 0; uint32_t h_blank; uint32_t h_back_porch; - uint8_t synchronous_clock = 0; /* asynchronous mode */ uint8_t colorimetry_bpc; uint8_t dp_pixel_encoding = 0; uint8_t dp_component_depth = 0; @@ -603,7 +602,6 @@ void enc401_stream_encoder_dp_set_stream_attribute( break; } - misc0 = misc0 | synchronous_clock; misc0 = colorimetry_bpc << 5; switch (output_color_space) { diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index 9405c47ee2a9a9..f81e5a4e1d6dd3 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -143,7 +143,7 @@ void generic_reg_wait(const struct dc_context *ctx, unsigned int delay_between_poll_us, unsigned int time_out_num_tries, const char *func_name, int line); -unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt, ...); +unsigned int snprintf_count(char *pBuf, unsigned int bufSize, const char *fmt, ...); /* These macros need to be used with soc15 registers in order to retrieve * the actual offset. diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c index 565f3c49247701..0c8c4a080c50e0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c @@ -785,12 +785,9 @@ static bool CalculatePrefetchSchedule( if (MyError) { *PrefetchBandwidth = 0; - TimeForFetchingMetaPTE = 0; - TimeForFetchingRowInVBlank = 0; *DestinationLinesToRequestVMInVBlank = 0; *DestinationLinesToRequestRowInVBlank = 0; *DestinationLinesForPrefetch = 0; - LinesToRequestPrefetchPixelData = 0; *VRatioPrefetchY = 0; *VRatioPrefetchC = 0; *RequiredPrefetchPixDataBW = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c index 9d6675ecc5f11a..c935903b68e10e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c @@ -845,12 +845,9 @@ static bool CalculatePrefetchSchedule( if (MyError) { *PrefetchBandwidth = 0; - TimeForFetchingMetaPTE = 0; - TimeForFetchingRowInVBlank = 0; *DestinationLinesToRequestVMInVBlank = 0; *DestinationLinesToRequestRowInVBlank = 0; *DestinationLinesForPrefetch = 0; - LinesToRequestPrefetchPixelData = 0; *VRatioPrefetchY = 0; *VRatioPrefetchC = 0; *RequiredPrefetchPixDataBW = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c index 4fce64a030b60a..390c1a77fda6a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c @@ -443,8 +443,6 @@ static void get_meta_and_pte_attr(struct display_mode_lib *mode_lib, blk_bytes = surf_linear ? 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); log2_blk_bytes = dml_log2((double) blk_bytes); - log2_blk_height = 0; - log2_blk_width = 0; // remember log rule // "+" in log is multiply @@ -491,8 +489,6 @@ static void get_meta_and_pte_attr(struct display_mode_lib *mode_lib, - log2_meta_req_height; meta_req_width = 1 << log2_meta_req_width; meta_req_height = 1 << log2_meta_req_height; - log2_meta_row_height = 0; - meta_row_width_ub = 0; // the dimensions of a meta row are meta_row_width x meta_row_height in elements. // calculate upper bound of the meta_row_width diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c index 3fa9a5da02f6a4..843d6004258ce9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c @@ -443,8 +443,6 @@ static void get_meta_and_pte_attr(struct display_mode_lib *mode_lib, blk_bytes = surf_linear ? 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); log2_blk_bytes = dml_log2((double) blk_bytes); - log2_blk_height = 0; - log2_blk_width = 0; // remember log rule // "+" in log is multiply @@ -491,8 +489,6 @@ static void get_meta_and_pte_attr(struct display_mode_lib *mode_lib, - log2_meta_req_height; meta_req_width = 1 << log2_meta_req_width; meta_req_height = 1 << log2_meta_req_height; - log2_meta_row_height = 0; - meta_row_width_ub = 0; // the dimensions of a meta row are meta_row_width x meta_row_height in elements. // calculate upper bound of the meta_row_width diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c index eb3ed965e48b7b..cd8cca65141967 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c @@ -1049,12 +1049,9 @@ static bool CalculatePrefetchSchedule( if (MyError) { *PrefetchBandwidth = 0; - TimeForFetchingMetaPTE = 0; - TimeForFetchingRowInVBlank = 0; *DestinationLinesToRequestVMInVBlank = 0; *DestinationLinesToRequestRowInVBlank = 0; *DestinationLinesForPrefetch = 0; - LinesToRequestPrefetchPixelData = 0; *VRatioPrefetchY = 0; *VRatioPrefetchC = 0; *RequiredPrefetchPixDataBWLuma = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c index 9e1c18b90805d2..5718000627b08b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c @@ -435,8 +435,6 @@ static void get_meta_and_pte_attr( blk_bytes = surf_linear ? 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); log2_blk_bytes = dml_log2((double) blk_bytes); - log2_blk_height = 0; - log2_blk_width = 0; // remember log rule // "+" in log is multiply @@ -485,8 +483,6 @@ static void get_meta_and_pte_attr( - log2_meta_req_height; meta_req_width = 1 << log2_meta_req_width; meta_req_height = 1 << log2_meta_req_height; - log2_meta_row_height = 0; - meta_row_width_ub = 0; // the dimensions of a meta row are meta_row_width x meta_row_height in elements. // calculate upper bound of the meta_row_width diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c index 1c10ba4dcddea4..cee1b351e10589 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c @@ -1280,12 +1280,9 @@ static bool CalculatePrefetchSchedule( if (MyError) { *PrefetchBandwidth = 0; - TimeForFetchingMetaPTE = 0; - TimeForFetchingRowInVBlank = 0; *DestinationLinesToRequestVMInVBlank = 0; *DestinationLinesToRequestRowInVBlank = 0; *DestinationLinesForPrefetch = 0; - LinesToRequestPrefetchPixelData = 0; *VRatioPrefetchY = 0; *VRatioPrefetchC = 0; *RequiredPrefetchPixDataBWLuma = 0; @@ -1775,15 +1772,6 @@ static unsigned int CalculateVMAndRowBytes( *PixelPTEReqWidth = 32768.0 / BytePerPixel; *PTERequestSize = 64; FractionOfPTEReturnDrop = 0; - } else if (MacroTileSizeBytes == 4096) { - PixelPTEReqHeightPTEs = 1; - *PixelPTEReqHeight = MacroTileHeight; - *PixelPTEReqWidth = 8 * *MacroTileWidth; - *PTERequestSize = 64; - if (ScanDirection != dm_vert) - FractionOfPTEReturnDrop = 0; - else - FractionOfPTEReturnDrop = 7.0 / 8; } else if (GPUVMMinPageSize == 4 && MacroTileSizeBytes > 4096) { PixelPTEReqHeightPTEs = 16; *PixelPTEReqHeight = 16 * BlockHeight256Bytes; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c index b28fcc8608ff86..76d3bb3c91550c 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_rq_dlg_calc_30.c @@ -392,8 +392,6 @@ static void get_meta_and_pte_attr(struct display_mode_lib *mode_lib, blk_bytes = surf_linear ? 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); log2_blk_bytes = dml_log2((double)blk_bytes); - log2_blk_height = 0; - log2_blk_width = 0; // remember log rule // "+" in log is multiply @@ -464,8 +462,6 @@ static void get_meta_and_pte_attr(struct display_mode_lib *mode_lib, - log2_meta_req_height; meta_req_width = 1 << log2_meta_req_width; meta_req_height = 1 << log2_meta_req_height; - log2_meta_row_height = 0; - meta_row_width_ub = 0; // the dimensions of a meta row are meta_row_width x meta_row_height in elements. // calculate upper bound of the meta_row_width diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index 2b275e6803797a..f567a9023682d1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -1444,12 +1444,9 @@ static bool CalculatePrefetchSchedule( if (MyError) { *PrefetchBandwidth = 0; - TimeForFetchingMetaPTE = 0; - TimeForFetchingRowInVBlank = 0; *DestinationLinesToRequestVMInVBlank = 0; *DestinationLinesToRequestRowInVBlank = 0; *DestinationLinesForPrefetch = 0; - LinesToRequestPrefetchPixelData = 0; *VRatioPrefetchY = 0; *VRatioPrefetchC = 0; *RequiredPrefetchPixDataBWLuma = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c index b57b095cd4a814..c46bda2141acd5 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c @@ -413,8 +413,6 @@ static void get_meta_and_pte_attr( log2_blk256_height = dml_log2((double) blk256_height); blk_bytes = surf_linear ? 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); log2_blk_bytes = dml_log2((double) blk_bytes); - log2_blk_height = 0; - log2_blk_width = 0; // remember log rule // "+" in log is multiply @@ -481,8 +479,6 @@ static void get_meta_and_pte_attr( log2_meta_req_width = log2_meta_req_bytes + 8 - log2_bytes_per_element - log2_meta_req_height; meta_req_width = 1 << log2_meta_req_width; meta_req_height = 1 << log2_meta_req_height; - log2_meta_row_height = 0; - meta_row_width_ub = 0; // the dimensions of a meta row are meta_row_width x meta_row_height in elements. // calculate upper bound of the meta_row_width diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index debfa31583a698..5865e8fa2d8e8f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -1461,12 +1461,9 @@ static bool CalculatePrefetchSchedule( if (MyError) { *PrefetchBandwidth = 0; - TimeForFetchingMetaPTE = 0; - TimeForFetchingRowInVBlank = 0; *DestinationLinesToRequestVMInVBlank = 0; *DestinationLinesToRequestRowInVBlank = 0; *DestinationLinesForPrefetch = 0; - LinesToRequestPrefetchPixelData = 0; *VRatioPrefetchY = 0; *VRatioPrefetchC = 0; *RequiredPrefetchPixDataBWLuma = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c index 61b3bebf24c96c..b7d2a0caec11b0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_rq_dlg_calc_314.c @@ -501,8 +501,6 @@ static void get_meta_and_pte_attr( log2_blk256_height = dml_log2((double) blk256_height); blk_bytes = surf_linear ? 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); log2_blk_bytes = dml_log2((double) blk_bytes); - log2_blk_height = 0; - log2_blk_width = 0; // remember log rule // "+" in log is multiply @@ -569,8 +567,6 @@ static void get_meta_and_pte_attr( log2_meta_req_width = log2_meta_req_bytes + 8 - log2_bytes_per_element - log2_meta_req_height; meta_req_width = 1 << log2_meta_req_width; meta_req_height = 1 << log2_meta_req_height; - log2_meta_row_height = 0; - meta_row_width_ub = 0; // the dimensions of a meta row are meta_row_width x meta_row_height in elements. // calculate upper bound of the meta_row_width diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c index d92fb428ee96f0..86ac7d59fd325e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn32/display_mode_vba_util_32.c @@ -4097,12 +4097,9 @@ bool dml32_CalculatePrefetchSchedule( if (MyError) { *PrefetchBandwidth = 0; - TimeForFetchingMetaPTE = 0; - TimeForFetchingRowInVBlank = 0; *DestinationLinesToRequestVMInVBlank = 0; *DestinationLinesToRequestRowInVBlank = 0; *DestinationLinesForPrefetch = 0; - LinesToRequestPrefetchPixelData = 0; *VRatioPrefetchY = 0; *VRatioPrefetchC = 0; *RequiredPrefetchPixDataBWLuma = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c index a201dbb743d791..d9e63c4fdd95cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn351/dcn351_fpu.c @@ -204,8 +204,8 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_51_soc = { .num_states = 8, .sr_exit_time_us = 28.0, .sr_enter_plus_exit_time_us = 30.0, - .sr_exit_z8_time_us = 250.0, - .sr_enter_plus_exit_z8_time_us = 350.0, + .sr_exit_z8_time_us = 263.0, + .sr_enter_plus_exit_z8_time_us = 363.0, .fclk_change_latency_us = 24.0, .usr_retraining_latency_us = 2, .writeback_latency_us = 12.0, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c index d8bfc85e5dcd0f..88dc2b97e7bf5b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c @@ -559,12 +559,11 @@ static void get_surf_rq_param( const struct _vcs_dpi_display_pipe_source_params_st *pipe_src_param, bool is_chroma) { - bool mode_422 = 0; unsigned int vp_width = 0; unsigned int vp_height = 0; unsigned int data_pitch = 0; unsigned int meta_pitch = 0; - unsigned int ppe = mode_422 ? 2 : 1; + unsigned int ppe = 1; bool surf_linear; bool surf_vert; unsigned int bytes_per_element; diff --git a/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c b/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c index d851c081e3768a..8dabb1ac0b684d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c @@ -1222,6 +1222,7 @@ static dml_bool_t CalculatePrefetchSchedule(struct display_mode_lib_scratch_st * s->dst_y_prefetch_oto = s->Tvm_oto_lines + 2 * s->Tr0_oto_lines + s->Lsw_oto; s->dst_y_prefetch_equ = p->VStartup - (*p->TSetup + dml_max(p->TWait + p->TCalc, *p->Tdmdl)) / s->LineTime - (*p->DSTYAfterScaler + (dml_float_t) *p->DSTXAfterScaler / (dml_float_t)p->myPipe->HTotal); + s->dst_y_prefetch_equ = dml_min(s->dst_y_prefetch_equ, 63.75); // limit to the reg limit of U6.2 for DST_Y_PREFETCH #ifdef __DML_VBA_DEBUG__ dml_print("DML::%s: HTotal = %u\n", __func__, p->myPipe->HTotal); diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c index 8697eac1e1f7e1..c6a5a861467976 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_translation_helper.c @@ -339,11 +339,22 @@ void dml21_apply_soc_bb_overrides(struct dml2_initialize_instance_in_out *dml_in // } } +static unsigned int calc_max_hardware_v_total(const struct dc_stream_state *stream) +{ + unsigned int max_hw_v_total = stream->ctx->dc->caps.max_v_total; + + if (stream->ctx->dc->caps.vtotal_limited_by_fp2) { + max_hw_v_total -= stream->timing.v_front_porch + 1; + } + + return max_hw_v_total; +} + static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cfg *timing, struct dc_stream_state *stream, struct dml2_context *dml_ctx) { - unsigned int hblank_start, vblank_start; + unsigned int hblank_start, vblank_start, min_hardware_refresh_in_uhz; timing->h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; timing->v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; @@ -371,11 +382,23 @@ static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf - stream->timing.v_border_top - stream->timing.v_border_bottom; timing->drr_config.enabled = stream->ignore_msa_timing_param; - timing->drr_config.min_refresh_uhz = stream->timing.min_refresh_in_uhz; timing->drr_config.drr_active_variable = stream->vrr_active_variable; timing->drr_config.drr_active_fixed = stream->vrr_active_fixed; timing->drr_config.disallowed = !stream->allow_freesync; + /* limit min refresh rate to DC cap */ + min_hardware_refresh_in_uhz = stream->timing.min_refresh_in_uhz; + if (stream->ctx->dc->caps.max_v_total != 0) { + min_hardware_refresh_in_uhz = div64_u64((stream->timing.pix_clk_100hz * 100000000ULL), + (stream->timing.h_total * (long long)calc_max_hardware_v_total(stream))); + } + + if (stream->timing.min_refresh_in_uhz > min_hardware_refresh_in_uhz) { + timing->drr_config.min_refresh_uhz = stream->timing.min_refresh_in_uhz; + } else { + timing->drr_config.min_refresh_uhz = min_hardware_refresh_in_uhz; + } + if (dml_ctx->config.callbacks.get_max_flickerless_instant_vtotal_increase && stream->ctx->dc->config.enable_fpo_flicker_detection == 1) timing->drr_config.max_instant_vtotal_delta = dml_ctx->config.callbacks.get_max_flickerless_instant_vtotal_increase(stream, false); @@ -422,6 +445,21 @@ static void populate_dml21_timing_config_from_stream_state(struct dml2_timing_cf timing->vblank_nom = timing->v_total - timing->v_active; } +/** + * adjust_dml21_hblank_timing_config_from_pipe_ctx - Adjusts the horizontal blanking timing configuration + * based on the pipe context. + * @timing: Pointer to the dml2_timing_cfg structure to be adjusted. + * @pipe: Pointer to the pipe_ctx structure containing the horizontal blanking borrow value. + * + * This function modifies the horizontal active and blank end timings by adding and subtracting + * the horizontal blanking borrow value from the pipe context, respectively. + */ +static void adjust_dml21_hblank_timing_config_from_pipe_ctx(struct dml2_timing_cfg *timing, struct pipe_ctx *pipe) +{ + timing->h_active += pipe->hblank_borrow; + timing->h_blank_end -= pipe->hblank_borrow; +} + static void populate_dml21_output_config_from_stream_state(struct dml2_link_output_cfg *output, struct dc_stream_state *stream, const struct pipe_ctx *pipe) { @@ -709,6 +747,7 @@ static const struct scaler_data *get_scaler_data_for_plane( temp_pipe->plane_state = pipe->plane_state; temp_pipe->plane_res.scl_data.taps = pipe->plane_res.scl_data.taps; temp_pipe->stream_res = pipe->stream_res; + temp_pipe->hblank_borrow = pipe->hblank_borrow; dml_ctx->config.callbacks.build_scaling_params(temp_pipe); break; } @@ -859,7 +898,7 @@ static void populate_dml21_plane_config_from_plane_state(struct dml2_context *dm plane->immediate_flip = plane_state->flip_immediate; plane->composition.rect_out_height_spans_vactive = - plane_state->dst_rect.height >= stream->timing.v_addressable && + plane_state->dst_rect.height >= stream->src.height && stream->dst.height >= stream->timing.v_addressable; } @@ -973,6 +1012,7 @@ bool dml21_map_dc_state_into_dml_display_cfg(const struct dc *in_dc, struct dc_s ASSERT(disp_cfg_stream_location >= 0 && disp_cfg_stream_location <= __DML2_WRAPPER_MAX_STREAMS_PLANES__); populate_dml21_timing_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing, context->streams[stream_index], dml_ctx); + adjust_dml21_hblank_timing_config_from_pipe_ctx(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].timing, &context->res_ctx.pipe_ctx[stream_index]); populate_dml21_output_config_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location].output, context->streams[stream_index], &context->res_ctx.pipe_ctx[stream_index]); populate_dml21_stream_overrides_from_stream_state(&dml_dispcfg->stream_descriptors[disp_cfg_stream_location], context->streams[stream_index]); @@ -1036,6 +1076,7 @@ void dml21_copy_clocks_to_dc_state(struct dml2_context *in_ctx, struct dc_state context->bw_ctx.bw.dcn.clk.p_state_change_support = in_ctx->v21.mode_programming.programming->uclk_pstate_supported; context->bw_ctx.bw.dcn.clk.dtbclk_en = in_ctx->v21.mode_programming.programming->min_clocks.dcn4x.dtbrefclk_khz > 0; context->bw_ctx.bw.dcn.clk.ref_dtbclk_khz = in_ctx->v21.mode_programming.programming->min_clocks.dcn4x.dtbrefclk_khz; + context->bw_ctx.bw.dcn.clk.socclk_khz = in_ctx->v21.mode_programming.programming->min_clocks.dcn4x.socclk_khz; } void dml21_extract_legacy_watermark_set(const struct dc *in_dc, struct dcn_watermarks *watermark, enum dml2_dchub_watermark_reg_set_index reg_set_idx, struct dml2_context *in_ctx) @@ -1110,12 +1151,12 @@ void dml21_populate_pipe_ctx_dlg_params(struct dml2_context *dml_ctx, struct dc_ struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; union dml2_global_sync_programming *global_sync = &stream_programming->global_sync; - hactive = timing->h_addressable + timing->h_border_left + timing->h_border_right; + hactive = timing->h_addressable + timing->h_border_left + timing->h_border_right + pipe_ctx->hblank_borrow; vactive = timing->v_addressable + timing->v_border_bottom + timing->v_border_top; hblank_start = pipe_ctx->stream->timing.h_total - pipe_ctx->stream->timing.h_front_porch; vblank_start = pipe_ctx->stream->timing.v_total - pipe_ctx->stream->timing.v_front_porch; - hblank_end = hblank_start - timing->h_addressable - timing->h_border_left - timing->h_border_right; + hblank_end = hblank_start - timing->h_addressable - timing->h_border_left - timing->h_border_right - pipe_ctx->hblank_borrow; vblank_end = vblank_start - timing->v_addressable - timing->v_border_top - timing->v_border_bottom; if (dml_ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) { diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c index d35dd507cb9f85..bbc28b9a15a36d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/dml21_wrapper.c @@ -13,11 +13,11 @@ static bool dml21_allocate_memory(struct dml2_context **dml_ctx) { - *dml_ctx = (struct dml2_context *)kzalloc(sizeof(struct dml2_context), GFP_KERNEL); + *dml_ctx = kzalloc(sizeof(struct dml2_context), GFP_KERNEL); if (!(*dml_ctx)) return false; - (*dml_ctx)->v21.dml_init.dml2_instance = (struct dml2_instance *)kzalloc(sizeof(struct dml2_instance), GFP_KERNEL); + (*dml_ctx)->v21.dml_init.dml2_instance = kzalloc(sizeof(struct dml2_instance), GFP_KERNEL); if (!((*dml_ctx)->v21.dml_init.dml2_instance)) return false; @@ -27,7 +27,7 @@ static bool dml21_allocate_memory(struct dml2_context **dml_ctx) (*dml_ctx)->v21.mode_support.display_config = &(*dml_ctx)->v21.display_config; (*dml_ctx)->v21.mode_programming.display_config = (*dml_ctx)->v21.mode_support.display_config; - (*dml_ctx)->v21.mode_programming.programming = (struct dml2_display_cfg_programming *)kzalloc(sizeof(struct dml2_display_cfg_programming), GFP_KERNEL); + (*dml_ctx)->v21.mode_programming.programming = kzalloc(sizeof(struct dml2_display_cfg_programming), GFP_KERNEL); if (!((*dml_ctx)->v21.mode_programming.programming)) return false; diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/inc/dml_top_dchub_registers.h b/drivers/gpu/drm/amd/display/dc/dml2/dml21/inc/dml_top_dchub_registers.h index 83fc15bf13cf7c..25b607e7b726e9 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/inc/dml_top_dchub_registers.h +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/inc/dml_top_dchub_registers.h @@ -88,6 +88,7 @@ struct dml2_display_arb_regs { uint32_t sdpif_request_rate_limit; uint32_t allow_sdpif_rate_limit_when_cstate_req; uint32_t dcfclk_deep_sleep_hysteresis; + uint32_t pstate_stall_threshold; }; struct dml2_cursor_dlg_regs{ diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4.c index 0aa4e4d343b04e..3d41ffde91c1b5 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4.c @@ -159,6 +159,7 @@ static void create_phantom_stream_from_main_stream(struct dml2_stream_parameters phantom->timing.v_total = meta->v_total; phantom->timing.v_active = meta->v_active; phantom->timing.v_front_porch = meta->v_front_porch; + phantom->timing.v_blank_end = phantom->timing.v_total - phantom->timing.v_front_porch - phantom->timing.v_active; phantom->timing.vblank_nom = phantom->timing.v_total - phantom->timing.v_active; phantom->timing.drr_config.enabled = false; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index 3ea54fd52e4683..601320b1be8171 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -11,6 +11,7 @@ #define DML2_MAX_FMT_420_BUFFER_WIDTH 4096 #define DML_MAX_NUM_OF_SLICES_PER_DSC 4 +#define ALLOW_SDPIF_RATE_LIMIT_PRE_CSTATE const char *dml2_core_internal_bw_type_str(enum dml2_core_internal_bw_type bw_type) { @@ -3886,6 +3887,10 @@ static void CalculateSwathAndDETConfiguration(struct dml2_core_internal_scratch #endif *p->hw_debug5 = false; +#ifdef ALLOW_SDPIF_RATE_LIMIT_PRE_CSTATE + if (p->NumberOfActiveSurfaces > 1) + *p->hw_debug5 = true; +#else for (unsigned int k = 0; k < p->NumberOfActiveSurfaces; ++k) { if (!(p->mrq_present) && (!(*p->UnboundedRequestEnabled)) && (TotalActiveDPP == 1) && p->display_cfg->plane_descriptors[k].surface.dcc.enable @@ -3901,6 +3906,7 @@ static void CalculateSwathAndDETConfiguration(struct dml2_core_internal_scratch dml2_printf("DML::%s: k=%u hw_debug5 = %u\n", __func__, k, *p->hw_debug5); #endif } +#endif } static enum dml2_odm_mode DecideODMMode(unsigned int HActive, @@ -12236,6 +12242,8 @@ static void rq_dlg_get_dlg_reg( static void rq_dlg_get_arb_params(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, struct dml2_display_arb_regs *arb_param) { + double refclk_freq_in_mhz = (display_cfg->overrides.hw.dlg_ref_clk_mhz > 0) ? (double)display_cfg->overrides.hw.dlg_ref_clk_mhz : mode_lib->soc.dchub_refclk_mhz; + arb_param->max_req_outstanding = mode_lib->soc.max_outstanding_reqs; arb_param->min_req_outstanding = mode_lib->soc.max_outstanding_reqs; // turn off the sat level feature if this set to max arb_param->sdpif_request_rate_limit = (3 * mode_lib->ip.words_per_channel * mode_lib->soc.clk_table.dram_config.channel_count) / 4; @@ -12247,6 +12255,7 @@ static void rq_dlg_get_arb_params(const struct dml2_display_cfg *display_cfg, co arb_param->compbuf_size = mode_lib->mp.CompressedBufferSizeInkByte / mode_lib->ip.compressed_buffer_segment_size_in_kbytes; arb_param->allow_sdpif_rate_limit_when_cstate_req = dml_get_hw_debug5(mode_lib); arb_param->dcfclk_deep_sleep_hysteresis = dml_get_dcfclk_deep_sleep_hysteresis(mode_lib); + arb_param->pstate_stall_threshold = (unsigned int)(mode_lib->ip_caps.fams2.max_allow_delay_us * refclk_freq_in_mhz); #ifdef __DML_VBA_DEBUG__ dml2_printf("DML::%s: max_req_outstanding = %d\n", __func__, arb_param->max_req_outstanding); diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_utils.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_utils.c index ab229e1598aef1..714b5c39b7e6cb 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_core/dml2_core_utils.c @@ -425,6 +425,7 @@ static void create_phantom_stream_from_main_stream(struct dml2_stream_parameters phantom->timing.v_total = meta->v_total; phantom->timing.v_active = meta->v_active; phantom->timing.v_front_porch = meta->v_front_porch; + phantom->timing.v_blank_end = phantom->timing.v_total - phantom->timing.v_front_porch - phantom->timing.v_active; phantom->timing.vblank_nom = phantom->timing.v_total - phantom->timing.v_active; phantom->timing.drr_config.enabled = false; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c index dd9971867f7494..92269f0e50ed24 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml21/src/dml2_pmo/dml2_pmo_dcn4_fams2.c @@ -1799,6 +1799,7 @@ bool pmo_dcn4_fams2_init_for_pstate_support(struct dml2_pmo_init_for_pstate_supp } if (s->pmo_dcn4.num_pstate_candidates > 0) { + s->pmo_dcn4.pstate_strategy_candidates[s->pmo_dcn4.num_pstate_candidates - 1].allow_state_increase = true; s->pmo_dcn4.cur_pstate_candidate = -1; return true; } else { diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c index 6eccf0241d857d..1ed21c1b86a5bb 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c @@ -258,12 +258,25 @@ static unsigned int find_preferred_pipe_candidates(const struct dc_state *existi * However this condition comes with a caveat. We need to ignore pipes that will * require a change in OPP but still have the same stream id. For example during * an MPC to ODM transiton. + * + * Adding check to avoid pipe select on the head pipe by utilizing dc resource + * helper function resource_get_primary_dpp_pipe and comparing the pipe index. */ if (existing_state) { for (i = 0; i < pipe_count; i++) { if (existing_state->res_ctx.pipe_ctx[i].stream && existing_state->res_ctx.pipe_ctx[i].stream->stream_id == stream_id) { + struct pipe_ctx *head_pipe = + resource_is_pipe_type(&existing_state->res_ctx.pipe_ctx[i], DPP_PIPE) ? + resource_get_primary_dpp_pipe(&existing_state->res_ctx.pipe_ctx[i]) : + NULL; + + // we should always respect the head pipe from selection + if (head_pipe && head_pipe->pipe_idx == i) + continue; if (existing_state->res_ctx.pipe_ctx[i].plane_res.hubp && - existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i) + existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i && + (existing_state->res_ctx.pipe_ctx[i].prev_odm_pipe || + existing_state->res_ctx.pipe_ctx[i].next_odm_pipe)) continue; preferred_pipe_candidates[num_preferred_candidates++] = i; @@ -292,6 +305,14 @@ static unsigned int find_last_resort_pipe_candidates(const struct dc_state *exis */ if (existing_state) { for (i = 0; i < pipe_count; i++) { + struct pipe_ctx *head_pipe = + resource_is_pipe_type(&existing_state->res_ctx.pipe_ctx[i], DPP_PIPE) ? + resource_get_primary_dpp_pipe(&existing_state->res_ctx.pipe_ctx[i]) : + NULL; + + // we should always respect the head pipe from selection + if (head_pipe && head_pipe->pipe_idx == i) + continue; if ((existing_state->res_ctx.pipe_ctx[i].plane_res.hubp && existing_state->res_ctx.pipe_ctx[i].plane_res.hubp->opp_id != i) || existing_state->res_ctx.pipe_ctx[i].stream_res.tg) diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c index 866b0abcff1bad..9190c1328d5b2d 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c @@ -209,8 +209,6 @@ static bool optimize_configuration(struct dml2_context *dml2, struct dml2_wrappe p->cur_display_config->output.OutputEncoder[0], p->cur_mode_support_info->DSCEnabled[0]) - 1; if (odms_needed <= unused_dpps) { - unused_dpps -= odms_needed; - if (odms_needed == 1) { p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_2to1; optimization_done = true; diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp.h b/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp.h index cd1706d301e775..f09cba8e29ccef 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn20/dcn20_dpp.h @@ -690,6 +690,7 @@ struct dcn20_dpp { int lb_memory_size; int lb_bits_per_entry; bool is_write_to_ram_a_safe; + bool dispclk_r_gate_disable; struct scaler_data scl_data; struct pwl_params pwl_data; }; diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h index b110f35ef66bd7..f236824126e940 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn30/dcn30_dpp.h @@ -572,6 +572,7 @@ struct dcn3_dpp { int lb_memory_size; int lb_bits_per_entry; bool is_write_to_ram_a_safe; + bool dispclk_r_gate_disable; struct scaler_data scl_data; struct pwl_params pwl_data; }; diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn35/dcn35_dpp.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn35/dcn35_dpp.c index 8473c694bfdc2e..62b7012cda4304 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn35/dcn35_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn35/dcn35_dpp.c @@ -50,13 +50,21 @@ void dpp35_dppclk_control( DPPCLK_RATE_CONTROL, dppclk_div, DPP_CLOCK_ENABLE, 1); else - REG_UPDATE_2(DPP_CONTROL, + if (dpp->dispclk_r_gate_disable) + REG_UPDATE_2(DPP_CONTROL, DPP_CLOCK_ENABLE, 1, DISPCLK_R_GATE_DISABLE, 1); + else + REG_UPDATE(DPP_CONTROL, + DPP_CLOCK_ENABLE, 1); } else - REG_UPDATE_2(DPP_CONTROL, + if (dpp->dispclk_r_gate_disable) + REG_UPDATE_2(DPP_CONTROL, DPP_CLOCK_ENABLE, 0, DISPCLK_R_GATE_DISABLE, 0); + else + REG_UPDATE(DPP_CONTROL, + DPP_CLOCK_ENABLE, 0); } void dpp35_program_bias_and_scale_fcnv( @@ -128,6 +136,10 @@ bool dpp35_construct( (const struct dcn3_dpp_mask *)(tf_mask)); dpp->base.funcs = &dcn35_dpp_funcs; + + // w/a for cursor memory stuck in LS by programming DISPCLK_R_GATE_DISABLE, limit w/a to some ASIC revs + if (dpp->base.ctx->asic_id.hw_internal_rev <= 0x10) + dpp->dispclk_r_gate_disable = true; return ret; } diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_dscl.c index 5105fd580017c3..2f92e7d4981bae 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn401/dcn401_dpp_dscl.c @@ -1091,7 +1091,8 @@ void dpp401_dscl_set_scaler_manual_scale(struct dpp *dpp_base, /* ISHARP_DELTA_LUT */ dpp401_dscl_set_isharp_filter(dpp, scl_data->dscl_prog_data.isharp_delta); dpp->scl_data.dscl_prog_data.sharpness_level = scl_data->dscl_prog_data.sharpness_level; - dpp->scl_data.dscl_prog_data.isharp_delta = scl_data->dscl_prog_data.isharp_delta; + memcpy(dpp->scl_data.dscl_prog_data.isharp_delta, scl_data->dscl_prog_data.isharp_delta, + sizeof(uint32_t) * ISHARP_LUT_TABLE_SIZE); if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0) return; diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c index ebd5df1a36e8bc..d9aaebfa3a0a76 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -1093,14 +1093,11 @@ static bool setup_dsc_config( if (!is_dsc_possible) goto done; - // Final decission: can we do DSC or not? - if (is_dsc_possible) { - // Fill out the rest of DSC settings - dsc_cfg->block_pred_enable = dsc_common_caps.is_block_pred_supported; - dsc_cfg->linebuf_depth = dsc_common_caps.lb_bit_depth; - dsc_cfg->version_minor = (dsc_common_caps.dsc_version & 0xf0) >> 4; - dsc_cfg->is_dp = dsc_sink_caps->is_dp; - } + /* Fill out the rest of DSC settings */ + dsc_cfg->block_pred_enable = dsc_common_caps.is_block_pred_supported; + dsc_cfg->linebuf_depth = dsc_common_caps.lb_bit_depth; + dsc_cfg->version_minor = (dsc_common_caps.dsc_version & 0xf0) >> 4; + dsc_cfg->is_dp = dsc_sink_caps->is_dp; done: if (!is_dsc_possible) diff --git a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h index bd98b327a6c70e..b86347c9b0389d 100644 --- a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h +++ b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h @@ -63,10 +63,6 @@ bool cm3_helper_translate_curve_to_hw_format( const struct dc_transfer_func *output_tf, struct pwl_params *lut_params, bool fixpoint); -bool cm3_helper_translate_curve_to_degamma_hw_format( - const struct dc_transfer_func *output_tf, - struct pwl_params *lut_params); - bool cm3_helper_convert_to_custom_float( struct pwl_result_data *rgb_resulted, struct curve_points3 *corner_points, diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index f344478e9bd473..b099989d9364f6 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -443,7 +443,6 @@ struct gpio *dal_gpio_create_irq( case GPIO_ID_GPIO_PAD: break; default: - id = GPIO_ID_HPD; ASSERT_CRITICAL(false); return NULL; } diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.h index a1e2cde9c4cca3..9fbd45c7dfef27 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn10/dcn10_hubbub.h @@ -198,6 +198,9 @@ struct dcn_hubbub_registers { uint32_t DCHUBBUB_ARB_REFCYC_PER_META_TRIP_B; uint32_t DCHUBBUB_ARB_FRAC_URG_BW_MALL_A; uint32_t DCHUBBUB_ARB_FRAC_URG_BW_MALL_B; + uint32_t DCHUBBUB_TIMEOUT_DETECTION_CTRL1; + uint32_t DCHUBBUB_TIMEOUT_DETECTION_CTRL2; + uint32_t DCHUBBUB_CTRL_STATUS; }; #define HUBBUB_REG_FIELD_LIST_DCN32(type) \ @@ -313,7 +316,17 @@ struct dcn_hubbub_registers { type DCN_VM_ERROR_VMID;\ type DCN_VM_ERROR_TABLE_LEVEL;\ type DCN_VM_ERROR_PIPE;\ - type DCN_VM_ERROR_INTERRUPT_STATUS + type DCN_VM_ERROR_INTERRUPT_STATUS;\ + type DCHUBBUB_TIMEOUT_ERROR_STATUS;\ + type DCHUBBUB_TIMEOUT_REQ_STALL_THRESHOLD;\ + type DCHUBBUB_TIMEOUT_PSTATE_STALL_THRESHOLD;\ + type DCHUBBUB_TIMEOUT_DETECTION_EN;\ + type DCHUBBUB_TIMEOUT_TIMER_RESET;\ + type ROB_UNDERFLOW_STATUS;\ + type ROB_OVERFLOW_STATUS;\ + type ROB_OVERFLOW_CLEAR;\ + type DCHUBBUB_HW_DEBUG;\ + type CSTATE_SWATH_CHK_GOOD_MODE #define HUBBUB_STUTTER_REG_FIELD_LIST(type) \ type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A;\ diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.h b/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.h index 036bb3e6c95751..46d8f5c70750a3 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn20/dcn20_hubbub.h @@ -96,6 +96,7 @@ struct dcn20_hubbub { unsigned int det1_size; unsigned int det2_size; unsigned int det3_size; + bool allow_sdpif_rate_limit_when_cstate_req; }; void hubbub2_construct(struct dcn20_hubbub *hubbub, diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c index 37d26fa0b6fbb9..92fab471b18369 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.c @@ -1192,6 +1192,37 @@ static void dcn401_wait_for_det_update(struct hubbub *hubbub, int hubp_inst) } } +static bool dcn401_program_arbiter(struct hubbub *hubbub, struct dml2_display_arb_regs *arb_regs, bool safe_to_lower) +{ + struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub); + + bool wm_pending = false; + uint32_t temp; + + /* request backpressure and outstanding return threshold (unused)*/ + //REG_UPDATE(DCHUBBUB_TIMEOUT_DETECTION_CTRL1, DCHUBBUB_TIMEOUT_REQ_STALL_THRESHOLD, arb_regs->req_stall_threshold); + + /* P-State stall threshold */ + REG_UPDATE(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_PSTATE_STALL_THRESHOLD, arb_regs->pstate_stall_threshold); + + if (safe_to_lower || arb_regs->allow_sdpif_rate_limit_when_cstate_req > hubbub2->allow_sdpif_rate_limit_when_cstate_req) { + hubbub2->allow_sdpif_rate_limit_when_cstate_req = arb_regs->allow_sdpif_rate_limit_when_cstate_req; + + /* only update the required bits */ + REG_GET(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, &temp); + if (hubbub2->allow_sdpif_rate_limit_when_cstate_req) { + temp |= (1 << 5); + } else { + temp &= ~(1 << 5); + } + REG_UPDATE(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, temp); + } else { + wm_pending = true; + } + + return wm_pending; +} + static const struct hubbub_funcs hubbub4_01_funcs = { .update_dchub = hubbub2_update_dchub, .init_dchub_sys_ctx = hubbub3_init_dchub_sys_ctx, @@ -1215,6 +1246,7 @@ static const struct hubbub_funcs hubbub4_01_funcs = { .program_det_segments = dcn401_program_det_segments, .program_compbuf_segments = dcn401_program_compbuf_segments, .wait_for_det_update = dcn401_wait_for_det_update, + .program_arbiter = dcn401_program_arbiter, }; void hubbub401_construct(struct dcn20_hubbub *hubbub2, diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.h b/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.h index f35f19ba3e18b8..b1d9ea9d1c3d61 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn401/dcn401_hubbub.h @@ -123,8 +123,17 @@ HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DCFCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\ HUBBUB_SF(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, mask_sh),\ HUBBUB_SF(DCHUBBUB_SDPIF_CFG1, SDPIF_MAX_NUM_OUTSTANDING, mask_sh),\ - HUBBUB_SF(DCHUBBUB_MEM_PWR_MODE_CTRL, DET_MEM_PWR_LS_MODE, mask_sh) - + HUBBUB_SF(DCHUBBUB_MEM_PWR_MODE_CTRL, DET_MEM_PWR_LS_MODE, mask_sh),\ + HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL1, DCHUBBUB_TIMEOUT_ERROR_STATUS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL1, DCHUBBUB_TIMEOUT_REQ_STALL_THRESHOLD, mask_sh),\ + HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_PSTATE_STALL_THRESHOLD, mask_sh),\ + HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_DETECTION_EN, mask_sh),\ + HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_TIMER_RESET, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CTRL_STATUS, ROB_UNDERFLOW_STATUS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CTRL_STATUS, ROB_OVERFLOW_STATUS, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CTRL_STATUS, ROB_OVERFLOW_CLEAR, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, mask_sh),\ + HUBBUB_SF(DCHUBBUB_CTRL_STATUS, CSTATE_SWATH_CHK_GOOD_MODE, mask_sh) bool hubbub401_program_urgent_watermarks( struct hubbub *hubbub, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 4fbed0298adfa7..81f4c386c28751 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -1039,7 +1039,8 @@ void dce110_edp_backlight_control( link_transmitter_control(ctx->dc_bios, &cntl); if (enable && link->dpcd_sink_ext_caps.bits.oled && - !link->dc->config.edp_no_power_sequencing) { + !link->dc->config.edp_no_power_sequencing && + !link->local_sink->edid_caps.panel_patch.oled_optimize_display_on) { post_T7_delay += link->panel_config.pps.extra_post_t7_ms; msleep(post_T7_delay); } @@ -3142,9 +3143,10 @@ static void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) } bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp) + struct set_backlight_level_params *backlight_level_params) { + uint32_t backlight_pwm_u16_16 = backlight_level_params->backlight_pwm_u16_16; + uint32_t frame_ramp = backlight_level_params->frame_ramp; struct dc_link *link = pipe_ctx->stream->link; struct dc *dc = link->ctx->dc; struct abm *abm = pipe_ctx->stream_res.abm; @@ -3315,7 +3317,7 @@ void dce110_disable_link_output(struct dc_link *link, * 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) + if (dmcu != NULL && dmcu->funcs->unlock_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/hwss/dce110/dce110_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h index ed3cc3648e8e23..06789ac3a2245d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h @@ -88,8 +88,7 @@ void dce110_edp_wait_for_hpd_ready( bool power_up); bool dce110_set_backlight_level(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); + struct set_backlight_level_params *params); void dce110_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx); void dce110_set_pipe(struct pipe_ctx *pipe_ctx); void dce110_disable_link_output(struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index a6a1db5ba8bad1..681bb92c60690d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -3453,7 +3453,6 @@ static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) r2 = test_pipe->plane_res.scl_data.recout; r2_r = r2.x + r2.width; r2_b = r2.y + r2.height; - split_pipe = test_pipe; /** * There is another half plane on same layer because of diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index a80c0858293207..b029ec1b26d36e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -1458,8 +1458,12 @@ void dcn20_pipe_control_lock( } else { if (lock) pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); - else - pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); + else { + if (dc->hwseq->funcs.perform_3dlut_wa_unlock) + dc->hwseq->funcs.perform_3dlut_wa_unlock(pipe); + else + pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); + } } } @@ -1732,7 +1736,6 @@ static void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.scaler || plane_state->update_flags.bits.scaling_change || plane_state->update_flags.bits.position_change || - plane_state->update_flags.bits.clip_size_change || plane_state->update_flags.bits.per_pixel_alpha_change || pipe_ctx->stream->update_flags.bits.scaling) { pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; @@ -1745,7 +1748,6 @@ static void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.viewport || (context == dc->current_state && plane_state->update_flags.bits.position_change) || (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || - (context == dc->current_state && plane_state->update_flags.bits.clip_size_change) || (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { hubp->funcs->mem_program_viewport( @@ -1923,9 +1925,9 @@ static void dcn20_program_pipe( dc->res_pool->hubbub, pipe_ctx->plane_res.hubp->inst, pipe_ctx->hubp_regs.det_size); } - if (pipe_ctx->update_flags.raw || - (pipe_ctx->plane_state && pipe_ctx->plane_state->update_flags.raw) || - pipe_ctx->stream->update_flags.raw) + if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw || + pipe_ctx->plane_state->update_flags.raw || + pipe_ctx->stream->update_flags.raw)) dcn20_update_dchubp_dpp(dc, pipe_ctx, context); if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable || @@ -2056,22 +2058,15 @@ void dcn20_program_front_end_for_ctx( */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct dc_stream_state *stream = dc->current_state->res_ctx.pipe_ctx[i].stream; + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable && stream && - dc_state_get_pipe_subvp_type(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM) { + dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) { struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg; if (tg->funcs->enable_crtc) { - if (dc->hwss.blank_phantom) { - int main_pipe_width = 0, main_pipe_height = 0; - struct dc_stream_state *phantom_stream = dc_state_get_paired_subvp_stream(dc->current_state, dc->current_state->res_ctx.pipe_ctx[i].stream); - - if (phantom_stream) { - main_pipe_width = phantom_stream->dst.width; - main_pipe_height = phantom_stream->dst.height; - } - - dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height); + if (dc->hwseq->funcs.blank_pixel_data) { + dc->hwseq->funcs.blank_pixel_data(dc, pipe, true); } tg->funcs->enable_crtc(tg); } @@ -2255,9 +2250,9 @@ void dcn20_post_unlock_program_front_end( struct timing_generator *tg = pipe->stream_res.tg; - if (tg->funcs->get_double_buffer_pending) { + if (tg->funcs->get_optc_double_buffer_pending) { for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_US / polling_interval_us - && tg->funcs->get_double_buffer_pending(tg); j++) + && tg->funcs->get_optc_double_buffer_pending(tg); j++) udelay(polling_interval_us); } } @@ -2771,7 +2766,6 @@ void dcn20_reset_back_end_for_pipe( struct pipe_ctx *pipe_ctx, struct dc_state *context) { - int i; struct dc_link *link = pipe_ctx->stream->link; const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); @@ -2838,19 +2832,16 @@ void dcn20_reset_back_end_for_pipe( } } - for (i = 0; i < dc->res_pool->pipe_count; i++) - if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) - break; - - if (i == dc->res_pool->pipe_count) - return; - /* * In case of a dangling plane, setting this to NULL unconditionally * causes failures during reset hw ctx where, if stream is NULL, * it is expected that the pipe_ctx pointers to pipes and plane are NULL. */ pipe_ctx->stream = NULL; + pipe_ctx->top_pipe = NULL; + pipe_ctx->bottom_pipe = NULL; + pipe_ctx->next_odm_pipe = NULL; + pipe_ctx->prev_odm_pipe = NULL; DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c index 1ea95f8d4cbccb..61efb15572ff0d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c @@ -137,7 +137,7 @@ void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx) pipe_ctx->stream->dpms_off = true; } -static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, +bool dcn21_dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst) { union dmub_rb_cmd cmd; @@ -199,7 +199,7 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, panel_cntl->inst, panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, + dcn21_dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, panel_cntl->inst, @@ -234,7 +234,7 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) panel_cntl->inst, panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, otg_inst, + dcn21_dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst, panel_cntl->pwrseq_inst); @@ -242,14 +242,15 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) } bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp) + struct set_backlight_level_params *backlight_level_params) { struct dc_context *dc = pipe_ctx->stream->ctx; struct abm *abm = pipe_ctx->stream_res.abm; struct timing_generator *tg = pipe_ctx->stream_res.tg; struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; uint32_t otg_inst; + uint32_t backlight_pwm_u16_16 = backlight_level_params->backlight_pwm_u16_16; + uint32_t frame_ramp = backlight_level_params->frame_ramp; if (!abm || !tg || !panel_cntl) return false; @@ -257,7 +258,7 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, otg_inst = tg->inst; if (dc->dc->res_pool->dmcu) { - dce110_set_backlight_level(pipe_ctx, backlight_pwm_u16_16, frame_ramp); + dce110_set_backlight_level(pipe_ctx, backlight_level_params); return true; } @@ -268,7 +269,7 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, panel_cntl->inst, panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, + dcn21_dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h index 9cee9bdb8de95c..f72a27ac1bf1b3 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.h @@ -47,11 +47,12 @@ void dcn21_optimize_pwr_state( void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx); +bool dcn21_dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, + uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst); void dcn21_set_pipe(struct pipe_ctx *pipe_ctx); void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx); bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); + struct set_backlight_level_params *params); bool dcn21_is_abm_supported(struct dc *dc, struct dc_state *context, struct dc_stream_state *stream); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index bded33575493b6..e89ebfda4873dd 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -245,6 +245,7 @@ static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx, { struct dpp *dpp_base = pipe_ctx->plane_res.dpp; int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; bool result = false; int acquired_rmu = 0; @@ -283,8 +284,14 @@ static bool dcn30_set_mpc_shaper_3dlut(struct pipe_ctx *pipe_ctx, result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d, stream->lut3d_func->state.bits.rmu_mux_num); + if (!result) + DC_LOG_ERROR("%s: program_3dlut failed\n", __func__); + result = mpc->funcs->program_shaper(mpc, shaper_lut, stream->lut3d_func->state.bits.rmu_mux_num); + if (!result) + DC_LOG_ERROR("%s: program_shaper failed\n", __func__); + } else { // loop through the available mux and release the requested mpcc_id mpc->funcs->release_rmu(mpc, mpcc_id); @@ -486,7 +493,6 @@ bool dcn30_mmhubbub_warmup( } /*following is the original: warmup each DWB's mcif buffer*/ for (i = 0; i < num_dwb; i++) { - dwb = dc->res_pool->dwbc[wb_info[i].dwb_pipe_inst]; mcif_wb = dc->res_pool->mcif_wb[wb_info[i].dwb_pipe_inst]; /*warmup is for VM mode only*/ if (wb_info[i].mcif_buf_params.p_vmid == 0) @@ -1185,3 +1191,30 @@ void dcn30_prepare_bandwidth(struct dc *dc, if (!dc->clk_mgr->clks.fw_based_mclk_switching) dc_dmub_srv_p_state_delegate(dc, false, context); } + +void dcn30_wait_for_all_pending_updates(const struct pipe_ctx *pipe_ctx) +{ + struct timing_generator *tg = pipe_ctx->stream_res.tg; + bool pending_updates = false; + unsigned int i; + + if (tg && tg->funcs->is_tg_enabled(tg)) { + // Poll for 100ms maximum + for (i = 0; i < 100000; i++) { + pending_updates = false; + if (tg->funcs->get_optc_double_buffer_pending) + pending_updates |= tg->funcs->get_optc_double_buffer_pending(tg); + + if (tg->funcs->get_otg_double_buffer_pending) + pending_updates |= tg->funcs->get_otg_double_buffer_pending(tg); + + if (tg->funcs->get_pipe_update_pending && pipe_ctx->plane_state) + pending_updates |= tg->funcs->get_pipe_update_pending(tg); + + if (!pending_updates) + break; + + udelay(1); + } + } +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h index 6a153e7ce910ef..4b90b781c4f2d9 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h @@ -96,4 +96,6 @@ void dcn30_set_hubp_blank(const struct dc *dc, void dcn30_prepare_bandwidth(struct dc *dc, struct dc_state *context); +void dcn30_wait_for_all_pending_updates(const struct pipe_ctx *pipe_ctx); + #endif /* __DC_HWSS_DCN30_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c index 2a8dc40d28477b..0e8d32e3dbae1d 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c @@ -108,7 +108,8 @@ static const struct hw_sequencer_funcs dcn30_funcs = { .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, .update_visual_confirm_color = dcn10_update_visual_confirm_color, - .is_abm_supported = dcn21_is_abm_supported + .is_abm_supported = dcn21_is_abm_supported, + .wait_for_all_pending_updates = dcn30_wait_for_all_pending_updates, }; static const struct hwseq_private_funcs dcn30_private_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c index 93e49d87a67ce0..780ce4c064aa58 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c @@ -107,6 +107,7 @@ static const struct hw_sequencer_funcs dcn301_funcs = { .optimize_pwr_state = dcn21_optimize_pwr_state, .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, .update_visual_confirm_color = dcn10_update_visual_confirm_color, + .wait_for_all_pending_updates = dcn30_wait_for_all_pending_updates, }; static const struct hwseq_private_funcs dcn301_private_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.h index 0bca48ccbfa200..a6e0115a53eeb5 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.h @@ -23,8 +23,8 @@ * */ -#ifndef __DC_DCN30_INIT_H__ -#define __DC_DCN30_INIT_H__ +#ifndef __DC_DCN301_INIT_H__ +#define __DC_DCN301_INIT_H__ struct dc; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c index 3d4b31bd994691..03ba01f4ace18a 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -47,9 +47,11 @@ #include "dce/dmub_outbox.h" #include "link.h" #include "dcn10/dcn10_hwseq.h" +#include "dcn21/dcn21_hwseq.h" #include "inc/link_enc_cfg.h" #include "dcn30/dcn30_vpg.h" #include "dce/dce_i2c_hw.h" +#include "dce/dmub_abm_lcd.h" #define DC_LOGGER_INIT(logger) @@ -517,10 +519,18 @@ static void dcn31_reset_back_end_for_pipe( dc->hwss.set_abm_immediate_disable(pipe_ctx); + link = pipe_ctx->stream->link; + + if ((!pipe_ctx->stream->dpms_off || link->link_status.link_active) && + (link->connector_signal == SIGNAL_TYPE_EDP)) + dc->hwss.blank_stream(pipe_ctx); + pipe_ctx->stream_res.tg->funcs->set_dsc_config( pipe_ctx->stream_res.tg, OPTC_DSC_DISABLED, 0, 0); + pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) pipe_ctx->stream_res.tg->funcs->set_odm_bypass( @@ -532,7 +542,6 @@ static void dcn31_reset_back_end_for_pipe( pipe_ctx->stream_res.tg->funcs->set_drr( pipe_ctx->stream_res.tg, NULL); - link = pipe_ctx->stream->link; /* DPMS may already disable or */ /* dpms_off status is incorrect due to fastboot * feature. When system resume from S4 with second @@ -633,3 +642,51 @@ void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx, pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(pipe_ctx[i]->stream_res.tg, triggers, params->num_frames); } + +static void dmub_abm_set_backlight(struct dc_context *dc, + struct set_backlight_level_params *backlight_level_params, uint32_t panel_inst) +{ + union dmub_rb_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.abm_set_backlight.header.type = DMUB_CMD__ABM; + cmd.abm_set_backlight.header.sub_type = DMUB_CMD__ABM_SET_BACKLIGHT; + cmd.abm_set_backlight.abm_set_backlight_data.frame_ramp = backlight_level_params->frame_ramp; + cmd.abm_set_backlight.abm_set_backlight_data.backlight_user_level = backlight_level_params->backlight_pwm_u16_16; + cmd.abm_set_backlight.abm_set_backlight_data.backlight_control_type = + (enum dmub_backlight_control_type) backlight_level_params->control_type; + cmd.abm_set_backlight.abm_set_backlight_data.min_luminance = backlight_level_params->min_luminance; + cmd.abm_set_backlight.abm_set_backlight_data.max_luminance = backlight_level_params->max_luminance; + cmd.abm_set_backlight.abm_set_backlight_data.min_backlight_pwm = backlight_level_params->min_backlight_pwm; + cmd.abm_set_backlight.abm_set_backlight_data.max_backlight_pwm = backlight_level_params->max_backlight_pwm; + cmd.abm_set_backlight.abm_set_backlight_data.version = DMUB_CMD_ABM_CONTROL_VERSION_1; + cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_inst); + cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data); + + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); +} + +bool dcn31_set_backlight_level(struct pipe_ctx *pipe_ctx, + struct set_backlight_level_params *backlight_level_params) +{ + struct dc_context *dc = pipe_ctx->stream->ctx; + struct abm *abm = pipe_ctx->stream_res.abm; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; + uint32_t otg_inst; + + if (!abm || !tg || !panel_cntl) + return false; + + otg_inst = tg->inst; + + dcn21_dmub_abm_set_pipe(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); + + dmub_abm_set_backlight(dc, backlight_level_params, panel_cntl->inst); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h index b8bc939da1554f..0d09aa8cfb65d7 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.h @@ -51,6 +51,8 @@ int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_ void dcn31_reset_hw_ctx_wrap( struct dc *dc, struct dc_state *context); +bool dcn31_set_backlight_level(struct pipe_ctx *pipe_ctx, + struct set_backlight_level_params *params); bool dcn31_is_abm_supported(struct dc *dc, struct dc_state *context, struct dc_stream_state *stream); void dcn31_init_pipes(struct dc *dc, struct dc_state *context); @@ -59,5 +61,4 @@ void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); void dcn31_set_static_screen_control(struct pipe_ctx **pipe_ctx, int num_pipes, const struct dc_static_screen_params *params); - #endif /* __DC_HWSS_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c index 56f3c70d4b5548..5f8f45b4872050 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c @@ -98,7 +98,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = { .set_flip_control_gsl = dcn20_set_flip_control_gsl, .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, .calc_vupdate_position = dcn10_calc_vupdate_position, - .set_backlight_level = dcn21_set_backlight_level, + .set_backlight_level = dcn31_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_pipe = dcn21_set_pipe, .enable_lvds_link_output = dce110_enable_lvds_link_output, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c index 4e93eeedfc1bbd..9b88eb72086db5 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c @@ -355,6 +355,20 @@ void dcn314_calculate_pix_rate_divider( } } +static bool dcn314_is_pipe_dig_fifo_on(struct pipe_ctx *pipe) +{ + return pipe && pipe->stream + // Check dig's otg instance. + && pipe->stream_res.stream_enc + && pipe->stream_res.stream_enc->funcs->dig_source_otg + && pipe->stream_res.tg->inst == pipe->stream_res.stream_enc->funcs->dig_source_otg(pipe->stream_res.stream_enc) + && pipe->stream->link && pipe->stream->link->link_enc + && pipe->stream->link->link_enc->funcs->is_dig_enabled + && pipe->stream->link->link_enc->funcs->is_dig_enabled(pipe->stream->link->link_enc) + && pipe->stream_res.stream_enc->funcs->is_fifo_enabled + && pipe->stream_res.stream_enc->funcs->is_fifo_enabled(pipe->stream_res.stream_enc); +} + void dcn314_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context, unsigned int current_pipe_idx) { unsigned int i; @@ -371,7 +385,11 @@ void dcn314_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc if (pipe->top_pipe || pipe->prev_odm_pipe) continue; - if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { + if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal)) && + !pipe->stream->apply_seamless_boot_optimization && + !pipe->stream->apply_edp_fast_boot_optimization) { + if (dcn314_is_pipe_dig_fifo_on(pipe)) + continue; pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg); reset_sync_context_for_pipe(dc, context, i); otg_disabled[i] = true; @@ -478,7 +496,7 @@ void dcn314_disable_link_output(struct dc_link *link, * 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) + if (dmcu != NULL && dmcu->funcs->unlock_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/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c index 68e6de6b5758d5..6bdfbf22ce8728 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c @@ -100,7 +100,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = { .set_flip_control_gsl = dcn20_set_flip_control_gsl, .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, .calc_vupdate_position = dcn10_calc_vupdate_position, - .set_backlight_level = dcn21_set_backlight_level, + .set_backlight_level = dcn31_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_pipe = dcn21_set_pipe, .enable_lvds_link_output = dce110_enable_lvds_link_output, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index 2e8c9f73825968..fa11f075d1f9aa 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -439,6 +439,7 @@ bool dcn32_set_mpc_shaper_3dlut( { struct dpp *dpp_base = pipe_ctx->plane_res.dpp; int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct dc *dc = pipe_ctx->stream->ctx->dc; struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; bool result = false; @@ -458,13 +459,13 @@ bool dcn32_set_mpc_shaper_3dlut( if (stream->lut3d_func && stream->lut3d_func->state.bits.initialized == 1) { - result = mpc->funcs->program_3dlut(mpc, - &stream->lut3d_func->lut_3d, - mpcc_id); + result = mpc->funcs->program_3dlut(mpc, &stream->lut3d_func->lut_3d, mpcc_id); + if (!result) + DC_LOG_ERROR("%s: program_3dlut failed\n", __func__); - result = mpc->funcs->program_shaper(mpc, - shaper_lut, - mpcc_id); + result = mpc->funcs->program_shaper(mpc, shaper_lut, mpcc_id); + if (!result) + DC_LOG_ERROR("%s: program_shaper failed\n", __func__); } return result; @@ -1048,7 +1049,8 @@ void dcn32_update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) } /* Enable DSC hw block */ - dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; + dsc_cfg.pic_width = (stream->timing.h_addressable + pipe_ctx->hblank_borrow + + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; dsc_cfg.color_depth = stream->timing.display_color_depth; @@ -1398,10 +1400,10 @@ void dcn32_disable_link_output(struct dc_link *link, 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->skip_implict_edp_power_control) link->dc->hwss.edp_power_control(link, false); - else if (dmcu != NULL && dmcu->funcs->lock_phy) + else if (dmcu != NULL && dmcu->funcs->unlock_phy) dmcu->funcs->unlock_phy(dmcu); dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); @@ -1698,52 +1700,6 @@ void dcn32_init_blank( hws->funcs.wait_for_blank_complete(opp); } -void dcn32_blank_phantom(struct dc *dc, - struct timing_generator *tg, - int width, - int height) -{ - struct dce_hwseq *hws = dc->hwseq; - enum dc_color_space color_space; - struct tg_color black_color = {0}; - struct output_pixel_processor *opp = NULL; - uint32_t num_opps, opp_id_src0, opp_id_src1; - uint32_t otg_active_width, otg_active_height; - uint32_t i; - - /* program opp dpg blank color */ - color_space = COLOR_SPACE_SRGB; - color_space_to_black_color(dc, color_space, &black_color); - - otg_active_width = width; - otg_active_height = height; - - /* get the OPTC source */ - tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); - ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); - - for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { - if (dc->res_pool->opps[i] != NULL && dc->res_pool->opps[i]->inst == opp_id_src0) { - opp = dc->res_pool->opps[i]; - break; - } - } - - if (opp && opp->funcs->opp_set_disp_pattern_generator) - opp->funcs->opp_set_disp_pattern_generator( - opp, - CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - COLOR_DEPTH_UNDEFINED, - &black_color, - otg_active_width, - otg_active_height, - 0); - - if (tg->funcs->is_tg_enabled(tg)) - hws->funcs.wait_for_blank_complete(opp); -} - /* phantom stream id's can change often, but can be identical between contexts. * This function checks for the condition the streams are identical to avoid * redundant pipe transitions. diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h index cac4a08b92a4d3..0303a595367372 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h @@ -119,11 +119,6 @@ void dcn32_init_blank( struct dc *dc, struct timing_generator *tg); -void dcn32_blank_phantom(struct dc *dc, - struct timing_generator *tg, - int width, - int height); - bool dcn32_is_pipe_topology_transition_seamless(struct dc *dc, const struct dc_state *cur_ctx, const struct dc_state *new_ctx); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c index 3422b564ae9847..5ecee7e320da96 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c @@ -98,7 +98,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = { .calc_vupdate_position = dcn10_calc_vupdate_position, .apply_idle_power_optimizations = dcn32_apply_idle_power_optimizations, .does_plane_fit_in_mall = NULL, - .set_backlight_level = dcn21_set_backlight_level, + .set_backlight_level = dcn31_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .hardware_release = dcn30_hardware_release, .set_pipe = dcn21_set_pipe, @@ -117,10 +117,10 @@ static const struct hw_sequencer_funcs dcn32_funcs = { .update_phantom_vp_position = dcn32_update_phantom_vp_position, .update_dsc_pg = dcn32_update_dsc_pg, .apply_update_flags_for_phantom = dcn32_apply_update_flags_for_phantom, - .blank_phantom = dcn32_blank_phantom, .is_pipe_topology_transition_seamless = dcn32_is_pipe_topology_transition_seamless, .calculate_pix_rate_divider = dcn32_calculate_pix_rate_divider, .program_outstanding_updates = dcn32_program_outstanding_updates, + .wait_for_all_pending_updates = dcn30_wait_for_all_pending_updates, }; static const struct hwseq_private_funcs dcn32_private_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index bd309dbdf7b2a7..e599cdc465bfd2 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -309,6 +309,7 @@ void dcn35_init_hw(struct dc *dc) dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv); 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_ver; + dc->caps.dmub_caps.aux_backlight_support = dc->ctx->dmub_srv->dmub->feature_caps.abm_aux_backlight_support; } if (dc->res_pool->pg_cntl) { @@ -841,6 +842,7 @@ void dcn35_init_pipes(struct dc *dc, struct dc_state *context) uint32_t num_opps = 0; uint32_t opp_id_src0 = OPP_ID_INVALID; uint32_t opp_id_src1 = OPP_ID_INVALID; + uint32_t optc_dsc_state = 0; // Step 1: To find out which OPTC is running & OPTC DSC is ON // We can't use res_pool->res_cap->num_timing_generator to check @@ -849,7 +851,6 @@ void dcn35_init_pipes(struct dc *dc, struct dc_state *context) // Some ASICs would be fused display pipes less than the default setting. // In dcnxx_resource_construct function, driver would obatin real information. for (i = 0; i < dc->res_pool->timing_generator_count; i++) { - uint32_t optc_dsc_state = 0; struct timing_generator *tg = dc->res_pool->timing_generators[i]; if (tg->funcs->is_tg_enabled(tg)) { @@ -864,15 +865,18 @@ void dcn35_init_pipes(struct dc *dc, struct dc_state *context) } } - // Step 2: To power down DSC but skip DSC of running OPTC + // Step 2: To power down DSC but skip DSC of running OPTC for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { struct dcn_dsc_state s = {0}; - dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); + /* avoid reading DSC state when it is not in use as it may be power gated */ + if (optc_dsc_state) { + dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); - if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && - s.dsc_clock_en && s.dsc_fw_en) - continue; + if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && + s.dsc_clock_en && s.dsc_fw_en) + continue; + } pg_cntl->funcs->dsc_pg_control(pg_cntl, dc->res_pool->dscs[i]->inst, false); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c index 2bbf1fef94fd25..fd67779c27a948 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c @@ -101,7 +101,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = { .set_flip_control_gsl = dcn20_set_flip_control_gsl, .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, .calc_vupdate_position = dcn10_calc_vupdate_position, - .set_backlight_level = dcn21_set_backlight_level, + .set_backlight_level = dcn31_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_pipe = dcn21_set_pipe, .enable_lvds_link_output = dce110_enable_lvds_link_output, @@ -123,7 +123,6 @@ static const struct hw_sequencer_funcs dcn35_funcs = { .root_clock_control = dcn35_root_clock_control, .set_long_vtotal = dcn35_set_long_vblank, .calculate_pix_rate_divider = dcn32_calculate_pix_rate_divider, - .program_outstanding_updates = dcn32_program_outstanding_updates, }; static const struct hwseq_private_funcs dcn35_private_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c index d00822e8daa52e..3c275a1eff589b 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c @@ -100,7 +100,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = { .set_flip_control_gsl = dcn20_set_flip_control_gsl, .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, .calc_vupdate_position = dcn10_calc_vupdate_position, - .set_backlight_level = dcn21_set_backlight_level, + .set_backlight_level = dcn31_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_pipe = dcn21_set_pipe, .enable_lvds_link_output = dce110_enable_lvds_link_output, @@ -122,7 +122,6 @@ static const struct hw_sequencer_funcs dcn351_funcs = { .root_clock_control = dcn35_root_clock_control, .set_long_vtotal = dcn35_set_long_vblank, .calculate_pix_rate_divider = dcn32_calculate_pix_rate_divider, - .program_outstanding_updates = dcn32_program_outstanding_updates, .setup_hpo_hw_control = dcn35_setup_hpo_hw_control, }; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index 0b743669f23b44..307782592789c8 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -506,7 +506,7 @@ void dcn401_populate_mcm_luts(struct dc *dc, dcn401_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable); /* 1D LUT */ - if (mcm_luts.lut1d_func && lut3d_xable != MCM_LUT_DISABLE) { + if (mcm_luts.lut1d_func) { memset(&m_lut_params, 0, sizeof(m_lut_params)); if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL) m_lut_params.pwl = &mcm_luts.lut1d_func->pwl; @@ -521,7 +521,7 @@ void dcn401_populate_mcm_luts(struct dc *dc, mpc->funcs->populate_lut(mpc, MCM_LUT_1DLUT, m_lut_params, lut_bank_a, mpcc_id); } if (mpc->funcs->program_lut_mode) - mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut1d_xable, lut_bank_a, mpcc_id); + mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut1d_xable && m_lut_params.pwl, lut_bank_a, mpcc_id); } /* Shaper */ @@ -669,11 +669,17 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx, { struct dpp *dpp_base = pipe_ctx->plane_res.dpp; int mpcc_id = pipe_ctx->plane_res.hubp->inst; - struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + struct dc *dc = pipe_ctx->stream_res.opp->ctx->dc; + struct mpc *mpc = dc->res_pool->mpc; bool result; const struct pwl_params *lut_params = NULL; bool rval; + if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) { + dcn401_populate_mcm_luts(dc, pipe_ctx, plane_state->mcm_luts, plane_state->lut_bank_a); + return true; + } + mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id); pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE; // 1D LUT @@ -814,6 +820,7 @@ enum dc_status dcn401_enable_stream_timing( int opp_cnt = 1; int opp_inst[MAX_PIPES] = {0}; struct pipe_ctx *opp_heads[MAX_PIPES] = {0}; + struct dc_crtc_timing patched_crtc_timing = stream->timing; bool manual_mode; unsigned int tmds_div = PIXEL_RATE_DIV_NA; unsigned int unused_div = PIXEL_RATE_DIV_NA; @@ -844,6 +851,13 @@ enum dc_status dcn401_enable_stream_timing( odm_slice_width, last_odm_slice_width); } + /* set DTBCLK_P */ + if (dc->res_pool->dccg->funcs->set_dtbclk_p_src) { + if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) { + dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, DPREFCLK, pipe_ctx->stream_res.tg->inst); + } + } + /* HW program guide assume display already disable * by unplug sequence. OTG assume stop. */ @@ -861,9 +875,13 @@ enum dc_status dcn401_enable_stream_timing( if (dc->hwseq->funcs.PLAT_58856_wa && (!dc_is_dp_signal(stream->signal))) dc->hwseq->funcs.PLAT_58856_wa(context, pipe_ctx); + /* if we are borrowing from hblank, h_addressable needs to be adjusted */ + if (dc->debug.enable_hblank_borrow) + patched_crtc_timing.h_addressable = patched_crtc_timing.h_addressable + pipe_ctx->hblank_borrow; + pipe_ctx->stream_res.tg->funcs->program_timing( pipe_ctx->stream_res.tg, - &stream->timing, + &patched_crtc_timing, pipe_ctx->pipe_dlg_param.vready_offset, pipe_ctx->pipe_dlg_param.vstartup_start, pipe_ctx->pipe_dlg_param.vupdate_offset, @@ -1004,8 +1022,6 @@ void dcn401_enable_stream(struct pipe_ctx *pipe_ctx) dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk); } else { - /* need to set DTBCLK_P source to DPREFCLK for DP8B10B */ - dccg->funcs->set_dtbclk_p_src(dccg, DPREFCLK, tg->inst); dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst, link_enc->transmitter - TRANSMITTER_UNIPHY_A); } @@ -1063,7 +1079,6 @@ static bool dcn401_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx) r2 = test_pipe->plane_res.scl_data.recout; r2_r = r2.x + r2.width; r2_b = r2.y + r2.height; - split_pipe = test_pipe; /** * There is another half plane on same layer because of @@ -1097,6 +1112,58 @@ void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct } } +static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding) +{ + struct dc *dc = link->ctx->dc; + struct pipe_ctx *pipe_ctx = NULL; + uint8_t i; + + 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, + link_encoding, + &pipe_ctx->pll_settings); + break; + } + } +} + +void dcn401_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->skip_implict_edp_power_control) + link->dc->hwss.edp_backlight_control(link, false); + else if (dmcu != NULL && dmcu->funcs->lock_phy) + dmcu->funcs->lock_phy(dmcu); + + if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) { + disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING); + link->phy_state.symclk_state = SYMCLK_ON_TX_OFF; + } else { + 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->skip_implict_edp_power_control) + link->dc->hwss.edp_power_control(link, false); + else 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); +} + void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx) { struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; @@ -1426,6 +1493,10 @@ void dcn401_prepare_bandwidth(struct dc *dc, &context->bw_ctx.bw.dcn.watermarks, dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, false); + /* update timeout thresholds */ + if (hubbub->funcs->program_arbiter) { + dc->wm_optimized_required |= hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, false); + } /* decrease compbuf size */ if (hubbub->funcs->program_compbuf_segments) { @@ -1467,6 +1538,10 @@ void dcn401_optimize_bandwidth( &context->bw_ctx.bw.dcn.watermarks, dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, true); + /* update timeout thresholds */ + if (hubbub->funcs->program_arbiter) { + hubbub->funcs->program_arbiter(hubbub, &context->bw_ctx.bw.dcn.arb_regs, true); + } 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 && @@ -1669,7 +1744,7 @@ void dcn401_hardware_release(struct dc *dc) } } -void dcn401_wait_for_det_buffer_update(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master) +void dcn401_wait_for_det_buffer_update_under_otg_master(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master) { struct pipe_ctx *opp_heads[MAX_PIPES]; struct pipe_ctx *dpp_pipes[MAX_PIPES]; @@ -1695,6 +1770,9 @@ void dcn401_wait_for_det_buffer_update(struct dc *dc, struct dc_state *context, hubbub->funcs->wait_for_det_update) hubbub->funcs->wait_for_det_update(hubbub, dpp_pipe->plane_res.hubp->inst); } + } else { + if (hubbub && opp_heads[slice_idx]->plane_res.hubp && hubbub->funcs->wait_for_det_update) + hubbub->funcs->wait_for_det_update(hubbub, opp_heads[slice_idx]->plane_res.hubp->inst); } } } @@ -1705,7 +1783,6 @@ void dcn401_interdependent_update_lock(struct dc *dc, unsigned int i = 0; struct pipe_ctx *pipe = NULL; struct timing_generator *tg = NULL; - bool pipe_unlocked[MAX_PIPES] = {0}; if (lock) { for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -1719,48 +1796,91 @@ void dcn401_interdependent_update_lock(struct dc *dc, dc->hwss.pipe_control_lock(dc, pipe, true); } } else { - /* Unlock pipes based on the change in DET allocation instead of pipe index - * Prevents over allocation of DET during unlock process - * e.g. 2 pipe config with different streams with a max of 20 DET segments - * Before: After: - * - Pipe0: 10 DET segments - Pipe0: 12 DET segments - * - Pipe1: 10 DET segments - Pipe1: 8 DET segments - * If Pipe0 gets updated first, 22 DET segments will be allocated - */ + /* Need to free DET being used first and have pipe update, then unlock the remaining pipes*/ for (i = 0; i < dc->res_pool->pipe_count; i++) { pipe = &context->res_ctx.pipe_ctx[i]; tg = pipe->stream_res.tg; - int current_pipe_idx = i; if (!resource_is_pipe_type(pipe, OTG_MASTER) || !tg->funcs->is_tg_enabled(tg) || dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { - pipe_unlocked[i] = true; continue; } - // If the same stream exists in old context, ensure the OTG_MASTER pipes for the same stream get compared - struct pipe_ctx *old_otg_master = resource_get_otg_master_for_stream(&dc->current_state->res_ctx, pipe->stream); - - if (old_otg_master) - current_pipe_idx = old_otg_master->pipe_idx; - if (resource_calculate_det_for_stream(context, pipe) < - resource_calculate_det_for_stream(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[current_pipe_idx])) { + if (dc->scratch.pipes_to_unlock_first[i]) { + struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; dc->hwss.pipe_control_lock(dc, pipe, false); - pipe_unlocked[i] = true; - dcn401_wait_for_det_buffer_update(dc, context, pipe); + /* Assumes pipe of the same index in current_state is also an OTG_MASTER pipe*/ + dcn401_wait_for_det_buffer_update_under_otg_master(dc, dc->current_state, old_pipe); } } + /* Unlocking the rest of the pipes */ for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (pipe_unlocked[i]) + if (dc->scratch.pipes_to_unlock_first[i]) continue; + pipe = &context->res_ctx.pipe_ctx[i]; + tg = pipe->stream_res.tg; + if (!resource_is_pipe_type(pipe, OTG_MASTER) || + !tg->funcs->is_tg_enabled(tg) || + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { + continue; + } + dc->hwss.pipe_control_lock(dc, pipe, false); } } } +void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx) +{ + /* If 3DLUT FL is enabled and 3DLUT is in use, follow the workaround sequence for pipe unlock to make sure that + * HUBP will properly fetch 3DLUT contents after unlock. + * + * This is meant to work around a known HW issue where VREADY will cancel the pending 3DLUT_ENABLE signal regardless + * of whether OTG lock is currently being held or not. + */ + struct pipe_ctx *wa_pipes[MAX_PIPES] = { NULL }; + struct pipe_ctx *odm_pipe, *mpc_pipe; + int i, wa_pipe_ct = 0; + + for (odm_pipe = pipe_ctx; odm_pipe != NULL; odm_pipe = odm_pipe->next_odm_pipe) { + for (mpc_pipe = odm_pipe; mpc_pipe != NULL; mpc_pipe = mpc_pipe->bottom_pipe) { + if (mpc_pipe->plane_state && mpc_pipe->plane_state->mcm_luts.lut3d_data.lut3d_src + == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM + && mpc_pipe->plane_state->mcm_shaper_3dlut_setting + == DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT) { + wa_pipes[wa_pipe_ct++] = mpc_pipe; + } + } + } + + if (wa_pipe_ct > 0) { + if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout) + pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, true); + + for (i = 0; i < wa_pipe_ct; ++i) { + if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl) + wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true); + } + + pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg); + if (pipe_ctx->stream_res.tg->funcs->wait_update_lock_status) + pipe_ctx->stream_res.tg->funcs->wait_update_lock_status(pipe_ctx->stream_res.tg, false); + + for (i = 0; i < wa_pipe_ct; ++i) { + if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl) + wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true); + } + + if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout) + pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, false); + } else { + pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg); + } +} + void dcn401_program_outstanding_updates(struct dc *dc, struct dc_state *context) { @@ -1770,3 +1890,125 @@ void dcn401_program_outstanding_updates(struct dc *dc, if (hubbub->funcs->program_compbuf_segments) hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true); } + +void dcn401_reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dc_link *link = pipe_ctx->stream->link; + const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res); + + DC_LOGGER_INIT(dc->ctx->logger); + if (pipe_ctx->stream_res.stream_enc == NULL) { + pipe_ctx->stream = NULL; + return; + } + + /* DPMS may already disable or */ + /* dpms_off status is incorrect due to fastboot + * feature. When system resume from S4 with second + * screen only, the dpms_off would be true but + * VBIOS lit up eDP, so check link status too. + */ + if (!pipe_ctx->stream->dpms_off || link->link_status.link_active) + dc->link_srv->set_dpms_off(pipe_ctx); + else if (pipe_ctx->stream_res.audio) + dc->hwss.disable_audio_stream(pipe_ctx); + + /* free acquired resources */ + if (pipe_ctx->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; + } + } + + /* by upper caller loop, parent pipe: pipe0, will be reset last. + * back end share by all pipes and will be disable only when disable + * parent pipe. + */ + if (pipe_ctx->top_pipe == NULL) { + + dc->hwss.set_abm_immediate_disable(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); + + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); + if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); + /* TODO - convert symclk_ref_cnts for otg to a bit map to solve + * the case where the same symclk is shared across multiple otg + * instances + */ + if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) + link->phy_state.symclk_ref_cnts.otg = 0; + if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { + link_hwss->disable_link_output(link, + &pipe_ctx->link_res, pipe_ctx->stream->signal); + link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF; + } + + /* reset DTBCLK_P */ + if (dc->res_pool->dccg->funcs->set_dtbclk_p_src) + dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, REFCLK, pipe_ctx->stream_res.tg->inst); + } + +/* + * In case of a dangling plane, setting this to NULL unconditionally + * causes failures during reset hw ctx where, if stream is NULL, + * it is expected that the pipe_ctx pointers to pipes and plane are NULL. + */ + pipe_ctx->stream = NULL; + pipe_ctx->top_pipe = NULL; + pipe_ctx->bottom_pipe = NULL; + pipe_ctx->next_odm_pipe = NULL; + pipe_ctx->prev_odm_pipe = NULL; + DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", + pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); +} + +void dcn401_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context) +{ + int i; + struct dce_hwseq *hws = dc->hwseq; + + /* Reset Back End*/ + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx_old->stream) + continue; + + if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) + continue; + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + if (hws->funcs.reset_back_end_for_pipe) + hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); + if (hws->funcs.enable_stream_gating) + hws->funcs.enable_stream_gating(dc, pipe_ctx_old); + if (old_clk) + old_clk->funcs->cs_power_down(old_clk); + } + } +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h index a27e62081685d2..28a513dfc00535 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h @@ -55,6 +55,10 @@ void dcn401_populate_mcm_luts(struct dc *dc, bool lut_bank_a); void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); +void dcn401_disable_link_output(struct dc_link *link, + const struct link_resource *link_res, + enum signal_type signal); + void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx); bool dcn401_apply_idle_power_optimizations(struct dc *dc, bool enable); @@ -81,7 +85,16 @@ void dcn401_hardware_release(struct dc *dc); void dcn401_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master); void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct dc_cursor_position *pos_cpy); -void dcn401_wait_for_det_buffer_update(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master); +void dcn401_wait_for_det_buffer_update_under_otg_master(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master); void dcn401_interdependent_update_lock(struct dc *dc, struct dc_state *context, bool lock); void dcn401_program_outstanding_updates(struct dc *dc, struct dc_state *context); +void dcn401_reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context); +void dcn401_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context); +void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx); + #endif /* __DC_HWSS_DCN401_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c index a2ca07235c83d9..23e4f208152efd 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c @@ -77,14 +77,14 @@ static const struct hw_sequencer_funcs dcn401_funcs = { .calc_vupdate_position = dcn10_calc_vupdate_position, .apply_idle_power_optimizations = dcn401_apply_idle_power_optimizations, .does_plane_fit_in_mall = NULL, - .set_backlight_level = dcn21_set_backlight_level, + .set_backlight_level = dcn31_set_backlight_level, .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .hardware_release = dcn401_hardware_release, .set_pipe = dcn21_set_pipe, .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 = dcn32_disable_link_output, + .disable_link_output = dcn401_disable_link_output, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, .get_dcc_en_bits = dcn10_get_dcc_en_bits, .enable_phantom_streams = dcn32_enable_phantom_streams, @@ -93,13 +93,13 @@ static const struct hw_sequencer_funcs dcn401_funcs = { .update_phantom_vp_position = dcn32_update_phantom_vp_position, .update_dsc_pg = dcn32_update_dsc_pg, .apply_update_flags_for_phantom = dcn32_apply_update_flags_for_phantom, - .blank_phantom = dcn32_blank_phantom, .wait_for_dcc_meta_propagation = dcn401_wait_for_dcc_meta_propagation, .is_pipe_topology_transition_seamless = dcn32_is_pipe_topology_transition_seamless, .fams2_global_control_lock = dcn401_fams2_global_control_lock, .fams2_update_config = dcn401_fams2_update_config, .fams2_global_control_lock_fast = dcn401_fams2_global_control_lock_fast, .program_outstanding_updates = dcn401_program_outstanding_updates, + .wait_for_all_pending_updates = dcn30_wait_for_all_pending_updates, }; static const struct hwseq_private_funcs dcn401_private_funcs = { @@ -111,7 +111,7 @@ static const struct hwseq_private_funcs dcn401_private_funcs = { .power_down = dce110_power_down, .enable_display_power_gating = dcn10_dummy_display_power_gating, .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, + .reset_hw_ctx_wrap = dcn401_reset_hw_ctx_wrap, .enable_stream_timing = dcn401_enable_stream_timing, .edp_backlight_control = dce110_edp_backlight_control, .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, @@ -136,8 +136,9 @@ static const struct hwseq_private_funcs dcn401_private_funcs = { .update_mall_sel = dcn32_update_mall_sel, .calculate_dccg_k1_k2_values = NULL, .apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw, - .reset_back_end_for_pipe = dcn20_reset_back_end_for_pipe, + .reset_back_end_for_pipe = dcn401_reset_back_end_for_pipe, .populate_mcm_luts = NULL, + .perform_3dlut_wa_unlock = dcn401_perform_3dlut_wa_unlock, }; void dcn401_hw_sequencer_init_functions(struct dc *dc) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index ac920562562336..66fdc5805d0a93 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -365,8 +365,7 @@ struct hw_sequencer_funcs { void (*clear_status_bits)(struct dc *dc, unsigned int mask); bool (*set_backlight_level)(struct pipe_ctx *pipe_ctx, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); + struct set_backlight_level_params *params); void (*set_abm_immediate_disable)(struct pipe_ctx *pipe_ctx); @@ -462,6 +461,7 @@ struct hw_sequencer_funcs { void (*program_outstanding_updates)(struct dc *dc, struct dc_state *context); void (*setup_hpo_hw_control)(const struct dce_hwseq *hws, bool enable); + void (*wait_for_all_pending_updates)(const struct pipe_ctx *pipe_ctx); }; void color_space_to_black_color( @@ -504,6 +504,10 @@ void get_mclk_switch_visual_confirm_color( struct pipe_ctx *pipe_ctx, struct tg_color *color); +void get_cursor_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color); + void set_p_state_switch_method( struct dc *dc, struct dc_state *context, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h index 0ac67545697923..22a5d4a03c988c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -182,6 +182,7 @@ struct hwseq_private_funcs { struct pipe_ctx *pipe_ctx, struct dc_cm2_func_luts mcm_luts, bool lut_bank_a); + void (*perform_3dlut_wa_unlock)(struct pipe_ctx *pipe_ctx); }; struct dce_hwseq { diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h index fa5edd03d00439..b5afd8c3103dba 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h @@ -60,5 +60,7 @@ enum dc_status { }; char *dc_status_to_str(enum dc_status status); +char *dc_pixel_encoding_to_str(enum dc_pixel_encoding pixel_encoding); +char *dc_color_depth_to_str(enum dc_color_depth color_depth); #endif /* _CORE_STATUS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index bfb8b8502d2026..2edd5b38ce4f85 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -215,6 +215,11 @@ struct resource_funcs { void (*get_panel_config_defaults)(struct dc_panel_config *panel_config); void (*build_pipe_pix_clk_params)(struct pipe_ctx *pipe_ctx); + /* + * Get indicator of power from a context that went through full validation + */ + int (*get_power_profile)(const struct dc_state *context); + unsigned int (*get_det_buffer_size)(const struct dc_state *context); }; struct audio_support{ @@ -473,6 +478,8 @@ struct pipe_ctx { /* subvp_index: only valid if the pipe is a SUBVP_MAIN*/ uint8_t subvp_index; struct pixel_rate_divider pixel_rate_divider; + /* pixels borrowed from hblank to hactive */ + uint8_t hblank_borrow; }; /* Data used for dynamic link encoder assignment. diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index 67c32401893e86..52b745667ef756 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -228,6 +228,7 @@ struct hubbub_funcs { void (*program_det_segments)(struct hubbub *hubbub, int hubp_inst, unsigned det_buffer_size_seg); void (*program_compbuf_segments)(struct hubbub *hubbub, unsigned compbuf_size_seg, bool safe_to_increase); void (*wait_for_det_update)(struct hubbub *hubbub, int hubp_inst); + bool (*program_arbiter)(struct hubbub *hubbub, struct dml2_display_arb_regs *arb_regs, bool safe_to_lower); }; struct hubbub { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index 3d4c8bd42b4920..b74e18cc1e667e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -342,7 +342,11 @@ struct timing_generator_funcs { void (*wait_drr_doublebuffer_pending_clear)(struct timing_generator *tg); void (*set_long_vtotal)(struct timing_generator *optc, const struct long_vtotal_params *params); void (*wait_odm_doublebuffer_pending_clear)(struct timing_generator *tg); - bool (*get_double_buffer_pending)(struct timing_generator *tg); + bool (*get_optc_double_buffer_pending)(struct timing_generator *tg); + bool (*get_otg_double_buffer_pending)(struct timing_generator *tg); + bool (*get_pipe_update_pending)(struct timing_generator *tg); + void (*set_vupdate_keepout)(struct timing_generator *tg, bool enable); + bool (*wait_update_lock_status)(struct timing_generator *tg, bool locked); }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h index 72a8479e1f2d73..f04292086c08a0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link.h @@ -248,8 +248,7 @@ struct link_service { uint32_t *backlight_millinits_avg, uint32_t *backlight_millinits_peak); bool (*edp_set_backlight_level)(const struct dc_link *link, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); + struct set_backlight_level_params *backlight_level_params); bool (*edp_set_backlight_level_nits)(struct dc_link *link, bool isHDR, uint32_t backlight_millinits, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index d21ee9d12d269b..e026c728042a5f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -48,6 +48,9 @@ #include "dm_helpers.h" #include "clk_mgr.h" + // Offset DPCD 050Eh == 0x5A +#define MST_HUB_ID_0x5A 0x5A + #define DC_LOGGER \ link->ctx->logger #define DC_LOGGER_INIT(logger) @@ -692,6 +695,15 @@ static void apply_dpia_mst_dsc_always_on_wa(struct dc_link *link) link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT && !link->dc->debug.dpia_debug.bits.disable_mst_dsc_work_around) link->wa_flags.dpia_mst_dsc_always_on = true; + + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && + link->type == dc_connection_mst_branch && + link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 && + link->dpcd_caps.branch_vendor_specific_data[2] == MST_HUB_ID_0x5A && + link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT && + !link->dc->debug.dpia_debug.bits.disable_mst_dsc_work_around) { + link->wa_flags.dpia_mst_dsc_always_on = true; + } } static void revert_dpia_mst_dsc_always_on_wa(struct dc_link *link) 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 c4e03482ba9ae4..5d66bfc7fe6e6d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -808,7 +808,8 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) enum optc_dsc_mode optc_dsc_mode; /* Enable DSC hw block */ - dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; + dsc_cfg.pic_width = (stream->timing.h_addressable + pipe_ctx->hblank_borrow + + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; dsc_cfg.color_depth = stream->timing.display_color_depth; @@ -2082,6 +2083,9 @@ static enum dc_status enable_link_dp(struct dc_state *state, if (link_settings->link_rate == LINK_RATE_LOW) skip_video_pattern = false; + if (stream->sink_patches.oled_optimize_display_on) + set_default_brightness_aux(link); + if (perform_link_training_with_retries(link_settings, skip_video_pattern, lt_attempts, @@ -2105,10 +2109,14 @@ static enum dc_status enable_link_dp(struct dc_state *state, if (link->dpcd_sink_ext_caps.bits.oled == 1 || link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1 || link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1) { - set_default_brightness_aux(link); - if (link->dpcd_sink_ext_caps.bits.oled == 1) - msleep(bl_oled_enable_delay); - edp_backlight_enable_aux(link, true); + if (!stream->sink_patches.oled_optimize_display_on) { + set_default_brightness_aux(link); + if (link->dpcd_sink_ext_caps.bits.oled == 1) + msleep(bl_oled_enable_delay); + edp_backlight_enable_aux(link, true); + } else { + edp_backlight_enable_aux(link, true); + } } return status; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index d78c8ec4de79e7..9dabaf682171d2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -51,9 +51,10 @@ #include "dc_dmub_srv.h" #include "gpio_service_interface.h" +#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ + #define DC_LOGGER \ link->ctx->logger -#define DC_TRACE_LEVEL_MESSAGE(...) /* do nothing */ #ifndef MAX #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) @@ -1207,6 +1208,13 @@ static void get_active_converter_info( dp_hw_fw_revision.ieee_fw_rev, sizeof(dp_hw_fw_revision.ieee_fw_rev)); } + + core_link_read_dpcd( + link, + DP_BRANCH_VENDOR_SPECIFIC_START, + (uint8_t *)link->dpcd_caps.branch_vendor_specific_data, + sizeof(link->dpcd_caps.branch_vendor_specific_data)); + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) { union dp_dfp_cap_ext dfp_cap_ext; @@ -1625,7 +1633,11 @@ static bool retrieve_link_cap(struct dc_link *link) } /* Read DP tunneling information. */ - status = dpcd_get_tunneling_device_data(link); + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + status = dpcd_get_tunneling_device_data(link); + if (status != DC_OK) + dm_error("%s: Read tunneling device data failed.\n", __func__); + } dpcd_set_source_specific_data(link); /* Sink may need to configure internals based on vendor, so allow some @@ -1842,6 +1854,9 @@ static bool retrieve_link_cap(struct dc_link *link) DP_FEC_CAPABILITY, &link->dpcd_caps.fec_cap.raw, sizeof(link->dpcd_caps.fec_cap.raw)); + if (status != DC_OK) + DC_LOG_ERROR("%s:%d: core_link_read_dpcd (DP_FEC_CAPABILITY) failed\n", __func__, __LINE__); + status = core_link_read_dpcd( link, DP_DSC_SUPPORT, @@ -1864,6 +1879,9 @@ static bool retrieve_link_cap(struct dc_link *link) DP_DSC_BRANCH_OVERALL_THROUGHPUT_0, link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw)); + if (status != DC_OK) + DC_LOG_ERROR("%s:%d: core_link_read_dpcd (DP_DSC_BRANCH_OVERALL_THROUGHPUT_0) failed\n", __func__, __LINE__); + DC_LOG_DSC("DSC branch decoder capability is read at link %d", link->link_index); DC_LOG_DSC("\tBRANCH_OVERALL_THROUGHPUT_0 = 0x%02x", link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_OVERALL_THROUGHPUT_0); @@ -2055,6 +2073,14 @@ void detect_edp_sink_caps(struct dc_link *link) core_link_read_dpcd(link, DP_SINK_PR_MAX_NUMBER_OF_DEVIATION_LINE, &link->dpcd_caps.pr_info.max_deviation_line, sizeof(link->dpcd_caps.pr_info.max_deviation_line)); + + /* + * OLED Emission Rate info + */ + if (link->dpcd_sink_ext_caps.bits.emission_output) + core_link_read_dpcd(link, DP_SINK_EMISSION_RATE, + (uint8_t *)&link->dpcd_caps.edp_oled_emission_rate, + sizeof(link->dpcd_caps.edp_oled_emission_rate)); } bool dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c index 6af42ba9885c05..0d123e647652ea 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c @@ -59,12 +59,18 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link) dpcd_dp_tun_data, sizeof(dpcd_dp_tun_data)); + if (status != DC_OK) + goto err; + status = core_link_read_dpcd( link, DP_USB4_ROUTER_TOPOLOGY_ID, dpcd_topology_data, sizeof(dpcd_topology_data)); + if (status != DC_OK) + goto err; + link->dpcd_caps.usb4_dp_tun_info.dp_tun_cap.raw = dpcd_dp_tun_data[DP_TUNNELING_CAPABILITIES_SUPPORT - DP_TUNNELING_CAPABILITIES_SUPPORT]; link->dpcd_caps.usb4_dp_tun_info.dpia_info.raw = @@ -75,6 +81,7 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link) for (i = 0; i < DPCD_USB4_TOPOLOGY_ID_LEN; i++) link->dpcd_caps.usb4_dp_tun_info.usb4_topology_id[i] = dpcd_topology_data[i]; +err: return status; } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c index 96bf135b6f05af..48abeaa886780f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c @@ -221,21 +221,11 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) &replay_error_status.raw, sizeof(replay_error_status.raw)); - link->replay_settings.config.replay_error_status.bits.LINK_CRC_ERROR = - replay_error_status.bits.LINK_CRC_ERROR; - link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR = - replay_configuration.bits.DESYNC_ERROR_STATUS; - link->replay_settings.config.replay_error_status.bits.STATE_TRANSITION_ERROR = - replay_configuration.bits.STATE_TRANSITION_ERROR_STATUS; - - if (link->replay_settings.config.replay_error_status.bits.LINK_CRC_ERROR || - link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR || - link->replay_settings.config.replay_error_status.bits.STATE_TRANSITION_ERROR) { + if (replay_error_status.bits.LINK_CRC_ERROR || + replay_configuration.bits.DESYNC_ERROR_STATUS || + replay_configuration.bits.STATE_TRANSITION_ERROR_STATUS) { bool allow_active; - if (link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR) - link->replay_settings.config.received_desync_error_hpd = 1; - if (link->replay_settings.config.force_disable_desync_error_check) return; 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 27b881f947e8b8..754c895e1bfbde 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 @@ -272,7 +272,7 @@ void dp_wait_for_training_aux_rd_interval( struct dc_link *link, uint32_t wait_in_micro_secs) { - fsleep(wait_in_micro_secs); + usleep_range_state(wait_in_micro_secs, wait_in_micro_secs, TASK_UNINTERRUPTIBLE); DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n", __func__, @@ -1107,9 +1107,13 @@ enum dc_status dpcd_set_link_settings( status = core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, &downspread.raw, sizeof(downspread)); + if (status != DC_OK) + DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_DOWNSPREAD_CTRL) failed\n", __func__, __LINE__); status = core_link_write_dpcd(link, DP_LANE_COUNT_SET, &lane_count_set.raw, 1); + if (status != DC_OK) + DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LANE_COUNT_SET) failed\n", __func__, __LINE__); if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_13 && lt_settings->link_settings.use_link_rate_set == true) { @@ -1125,12 +1129,19 @@ enum dc_status dpcd_set_link_settings( supported_link_rates, sizeof(supported_link_rates)); } status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + if (status != DC_OK) + DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_BW_SET) failed\n", __func__, __LINE__); + status = core_link_write_dpcd(link, DP_LINK_RATE_SET, <_settings->link_settings.link_rate_set, 1); + if (status != DC_OK) + DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_RATE_SET) failed\n", __func__, __LINE__); } else { rate = get_dpcd_link_rate(<_settings->link_settings); status = core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + if (status != DC_OK) + DC_LOG_ERROR("%s:%d: core_link_write_dpcd (DP_LINK_BW_SET) failed\n", __func__, __LINE__); } if (rate) { diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c index b5cf75975fffd6..ccf8096dde2909 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c @@ -412,7 +412,6 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( /* 5. check CR done*/ if (dp_is_cr_done(lane_count, dpcd_lane_status)) { - status = LINK_TRAINING_SUCCESS; break; } 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 3aa05a2be6c09f..e0e3bb86535952 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 @@ -157,31 +157,13 @@ bool edp_set_backlight_level_nits(struct dc_link *link, uint32_t backlight_millinits, uint32_t transition_time_in_ms) { - struct dpcd_source_backlight_set dpcd_backlight_set; - uint8_t backlight_control = isHDR ? 1 : 0; - if (!link || (link->connector_signal != SIGNAL_TYPE_EDP && link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT)) return false; - // OLEDs have no PWM, they can only use AUX - if (link->dpcd_sink_ext_caps.bits.oled == 1) - backlight_control = 1; - - *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits; - *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms; - - - if (!link->dpcd_caps.panel_luminance_control) { - if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL, - (uint8_t *)(&dpcd_backlight_set), - sizeof(dpcd_backlight_set)) != DC_OK) - return false; - - if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL, - &backlight_control, 1) != DC_OK) - return false; - } else { + // use internal backlight control if dmub capabilities are not present + if (link->backlight_control_type == BACKLIGHT_CONTROL_VESA_AUX && + !link->dc->caps.dmub_caps.aux_backlight_support) { uint8_t backlight_enable = 0; struct target_luminance_value *target_luminance = NULL; @@ -205,6 +187,24 @@ bool edp_set_backlight_level_nits(struct dc_link *link, (uint8_t *)(target_luminance), sizeof(struct target_luminance_value)) != DC_OK) return false; + } else if (link->backlight_control_type == BACKLIGHT_CONTROL_AMD_AUX) { + struct dpcd_source_backlight_set dpcd_backlight_set; + *(uint32_t *)&dpcd_backlight_set.backlight_level_millinits = backlight_millinits; + *(uint16_t *)&dpcd_backlight_set.backlight_transition_time_ms = (uint16_t)transition_time_in_ms; + + uint8_t backlight_control = isHDR ? 1 : 0; + // OLEDs have no PWM, they can only use AUX + if (link->dpcd_sink_ext_caps.bits.oled == 1) + backlight_control = 1; + + if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_LEVEL, + (uint8_t *)(&dpcd_backlight_set), + sizeof(dpcd_backlight_set)) != DC_OK) + return false; + + if (core_link_write_dpcd(link, DP_SOURCE_BACKLIGHT_CONTROL, + &backlight_control, 1) != DC_OK) + return false; } return true; @@ -519,11 +519,11 @@ static struct pipe_ctx *get_pipe_from_link(const struct dc_link *link) } bool edp_set_backlight_level(const struct dc_link *link, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp) + struct set_backlight_level_params *backlight_level_params) { struct dc *dc = link->ctx->dc; - + uint32_t backlight_pwm_u16_16 = backlight_level_params->backlight_pwm_u16_16; + uint32_t frame_ramp = backlight_level_params->frame_ramp; DC_LOGGER_INIT(link->ctx->logger); DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", backlight_pwm_u16_16, backlight_pwm_u16_16); @@ -544,10 +544,11 @@ bool edp_set_backlight_level(const struct dc_link *link, return false; } + backlight_level_params->frame_ramp = frame_ramp; + dc->hwss.set_backlight_level( pipe_ctx, - backlight_pwm_u16_16, - frame_ramp); + backlight_level_params); } return true; } @@ -940,8 +941,7 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream struct replay_context replay_context = { 0 }; unsigned int lineTimeInNs = 0; - - union replay_enable_and_configuration replay_config; + union replay_enable_and_configuration replay_config = { 0 }; union dpcd_alpm_configuration alpm_config; @@ -1168,9 +1168,6 @@ static void edp_set_assr_enable(const struct dc *pDC, struct dc_link *link, link_enc_index = link->link_enc->transmitter - TRANSMITTER_UNIPHY_A; if (link_res->hpo_dp_link_enc) { - if (link->wa_flags.disable_assr_for_uhbr) - return; - link_enc_index = link_res->hpo_dp_link_enc->inst; use_hpo_dp_link_enc = true; } diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index 30dc8c24c008c4..bcfa6ac5d4e7b6 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -36,8 +36,7 @@ bool edp_get_backlight_level_nits(struct dc_link *link, uint32_t *backlight_millinits_avg, uint32_t *backlight_millinits_peak); bool edp_set_backlight_level(const struct dc_link *link, - uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp); + struct set_backlight_level_params *backlight_level_params); bool edp_set_backlight_level_nits(struct dc_link *link, bool isHDR, uint32_t backlight_millinits, diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h index b7a57f98553d78..40757f20d73f41 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h @@ -202,6 +202,7 @@ struct dcn_optc_registers { uint32_t OPTC_CLOCK_CONTROL; uint32_t OPTC_WIDTH_CONTROL2; uint32_t OTG_PSTATE_REGISTER; + uint32_t OTG_PIPE_UPDATE_STATUS; }; #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ @@ -566,6 +567,12 @@ struct dcn_optc_registers { type OTG_H_TIMING_DIV_MODE_DB_UPDATE_PENDING;\ type OPTC_DOUBLE_BUFFER_PENDING;\ +#define TG_REG_FIELD_LIST_DCN2_0(type) \ + type OTG_FLIP_PENDING;\ + type OTG_DC_REG_UPDATE_PENDING;\ + type OTG_CURSOR_UPDATE_PENDING;\ + type OTG_VUPDATE_KEEPOUT_STATUS;\ + #define TG_REG_FIELD_LIST_DCN3_2(type) \ type OTG_H_TIMING_DIV_MODE_MANUAL; @@ -600,6 +607,7 @@ struct dcn_optc_registers { struct dcn_optc_shift { TG_REG_FIELD_LIST(uint8_t) + TG_REG_FIELD_LIST_DCN2_0(uint8_t) TG_REG_FIELD_LIST_DCN3_2(uint8_t) TG_REG_FIELD_LIST_DCN3_5(uint8_t) TG_REG_FIELD_LIST_DCN401(uint8_t) @@ -607,6 +615,7 @@ struct dcn_optc_shift { struct dcn_optc_mask { TG_REG_FIELD_LIST(uint32_t) + TG_REG_FIELD_LIST_DCN2_0(uint32_t) TG_REG_FIELD_LIST_DCN3_2(uint32_t) TG_REG_FIELD_LIST_DCN3_5(uint32_t) TG_REG_FIELD_LIST_DCN401(uint32_t) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h index 364034b190281b..928e110b95fb5c 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h @@ -43,7 +43,8 @@ SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ SR(DWB_SOURCE_SELECT),\ SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst), \ - SRI(OTG_DRR_CONTROL, OTG, inst) + SRI(OTG_DRR_CONTROL, OTG, inst),\ + SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst) #define TG_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\ TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ @@ -53,6 +54,10 @@ SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ SF(OTG0_OTG_GLOBAL_CONTROL2, DIG_UPDATE_LOCATION, mask_sh),\ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\ SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c index abcd03d7866843..4c95c095861229 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c @@ -271,6 +271,48 @@ void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_c optc1->opp_count = opp_cnt; } +/* OTG status register that indicates OPTC update is pending */ +bool optc3_get_optc_double_buffer_pending(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t update_pending = 0; + + REG_GET(OPTC_INPUT_GLOBAL_CONTROL, + OPTC_DOUBLE_BUFFER_PENDING, + &update_pending); + + return (update_pending == 1); +} + +/* OTG status register that indicates OTG update is pending */ +bool optc3_get_otg_update_pending(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t update_pending = 0; + + REG_GET(OTG_DOUBLE_BUFFER_CONTROL, + OTG_UPDATE_PENDING, + &update_pending); + + return (update_pending == 1); +} + +/* OTG status register that indicates surface update is pending */ +bool optc3_get_pipe_update_pending(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t flip_pending = 0; + uint32_t dc_update_pending = 0; + + REG_GET_2(OTG_PIPE_UPDATE_STATUS, + OTG_FLIP_PENDING, + &flip_pending, + OTG_DC_REG_UPDATE_PENDING, + &dc_update_pending); + + return (flip_pending == 1 || dc_update_pending == 1); +} + /** * optc3_set_timing_double_buffer() - DRR double buffering control * @@ -375,6 +417,9 @@ static struct timing_generator_funcs dcn30_tg_funcs = { .get_hw_timing = optc1_get_hw_timing, .wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear, .is_two_pixels_per_container = optc1_is_two_pixels_per_container, + .get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending, + .get_otg_double_buffer_pending = optc3_get_otg_update_pending, + .get_pipe_update_pending = optc3_get_pipe_update_pending, }; void dcn30_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h index bda974d432ea6a..e2303f9eaf13b6 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h @@ -109,7 +109,8 @@ SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ - SR(DWB_SOURCE_SELECT) + SR(DWB_SOURCE_SELECT),\ + SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst) #define DCN30_VTOTAL_REGS_SF(mask_sh) @@ -209,6 +210,7 @@ SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_DOUBLE_BUFFER_PENDING, mask_sh),\ SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ @@ -319,7 +321,11 @@ SF(OTG0_OTG_DRR_V_TOTAL_CHANGE, OTG_DRR_V_TOTAL_CHANGE_LIMIT, mask_sh),\ SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, mask_sh),\ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_PENDING, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh) + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\ void dcn30_timing_generator_init(struct optc *optc1); @@ -356,4 +362,7 @@ void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_c void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *optc); void optc3_tg_init(struct timing_generator *optc); void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max); +bool optc3_get_optc_double_buffer_pending(struct timing_generator *optc); +bool optc3_get_otg_update_pending(struct timing_generator *optc); +bool optc3_get_pipe_update_pending(struct timing_generator *optc); #endif /* __DC_OPTC_DCN30_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c index 1a22ae89fb5555..d7a45ef2d01b38 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c @@ -169,6 +169,9 @@ static struct timing_generator_funcs dcn30_tg_funcs = { .get_hw_timing = optc1_get_hw_timing, .wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear, .is_two_pixels_per_container = optc1_is_two_pixels_per_container, + .get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending, + .get_otg_double_buffer_pending = optc3_get_otg_update_pending, + .get_pipe_update_pending = optc3_get_pipe_update_pending, }; void dcn301_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h index 30b81a448ce2d1..fbbe86d00c2e3e 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h @@ -99,7 +99,8 @@ SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ SRI(OTG_CRC_CNTL2, OTG, inst),\ SR(DWB_SOURCE_SELECT),\ - SRI(OTG_DRR_CONTROL, OTG, inst) + SRI(OTG_DRR_CONTROL, OTG, inst),\ + SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst) #define OPTC_COMMON_MASK_SH_LIST_DCN3_1(mask_sh)\ SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ @@ -254,7 +255,11 @@ SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ - SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\ void dcn31_timing_generator_init(struct optc *optc1); diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h index 99c098e76116fc..0ff72b97b465c5 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h @@ -98,7 +98,8 @@ SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ - SRI(OTG_DRR_CONTROL, OTG, inst) + SRI(OTG_DRR_CONTROL, OTG, inst),\ + SRI(OTG_PIPE_UPDATE_STATUS, OTG, inst) #define OPTC_COMMON_MASK_SH_LIST_DCN3_14(mask_sh)\ SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ @@ -248,7 +249,11 @@ SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, mask_sh),\ SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE_MANUAL, mask_sh),\ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh),\ void dcn314_timing_generator_init(struct optc *optc1); diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c index 00094f0e847065..c217f653b3c815 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c @@ -297,18 +297,6 @@ static void optc32_set_drr( optc32_setup_manual_trigger(optc); } -bool optc32_get_double_buffer_pending(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t update_pending = 0; - - REG_GET(OPTC_INPUT_GLOBAL_CONTROL, - OPTC_DOUBLE_BUFFER_PENDING, - &update_pending); - - return (update_pending == 1); -} - static struct timing_generator_funcs dcn32_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, @@ -373,7 +361,9 @@ static struct timing_generator_funcs dcn32_tg_funcs = { .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, .is_two_pixels_per_container = optc1_is_two_pixels_per_container, - .get_double_buffer_pending = optc32_get_double_buffer_pending, + .get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending, + .get_otg_double_buffer_pending = optc3_get_otg_update_pending, + .get_pipe_update_pending = optc3_get_pipe_update_pending, }; void dcn32_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h index 665d7c52f67cd3..0b0964a9da7487 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h @@ -177,7 +177,11 @@ SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, mask_sh),\ SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE_MANUAL, mask_sh),\ SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh) void dcn32_timing_generator_init(struct optc *optc1); void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode); @@ -185,6 +189,5 @@ void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combi void optc32_set_odm_bypass(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); void optc32_wait_odm_doublebuffer_pending_clear(struct timing_generator *tg); -bool optc32_get_double_buffer_pending(struct timing_generator *optc); #endif /* __DC_OPTC_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h index d077e2392379ca..be749ab41dce79 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h @@ -67,7 +67,11 @@ SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG_CRC1_WINDOWB_Y_END_READBACK, mask_sh),\ SF(OPTC_CLOCK_CONTROL, OPTC_FGCG_REP_DIS, mask_sh),\ SF(OTG0_OTG_V_COUNT_STOP_CONTROL, OTG_V_COUNT_STOP, mask_sh),\ - SF(OTG0_OTG_V_COUNT_STOP_CONTROL2, OTG_V_COUNT_STOP_TIMER, mask_sh) + SF(OTG0_OTG_V_COUNT_STOP_CONTROL2, OTG_V_COUNT_STOP_TIMER, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh) void dcn35_timing_generator_init(struct optc *optc1); diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c index a5d6a7dca554c3..783ca9acc76266 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c @@ -430,6 +430,35 @@ static void optc401_program_global_sync( REG_UPDATE(OTG_PSTATE_REGISTER, OTG_PSTATE_KEEPOUT_START, pstate_keepout); } +static void optc401_set_vupdate_keepout(struct timing_generator *tg, bool enable) +{ + struct optc *optc1 = DCN10TG_FROM_TG(tg); + + REG_SET_3(OTG_VUPDATE_KEEPOUT, 0, + MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, 0, + MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, optc1->vready_offset + 10, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, enable); + + return; +} + +static bool optc401_wait_update_lock_status(struct timing_generator *tg, bool locked) +{ + struct optc *optc1 = DCN10TG_FROM_TG(tg); + uint32_t lock_status = 0; + + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, locked, + 1, 150000); + + REG_GET(OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, &lock_status); + + if (lock_status != locked) + return false; + + return true; +} + static struct timing_generator_funcs dcn401_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, @@ -493,7 +522,11 @@ static struct timing_generator_funcs dcn401_tg_funcs = { .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, .is_two_pixels_per_container = optc1_is_two_pixels_per_container, - .get_double_buffer_pending = optc32_get_double_buffer_pending, + .get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending, + .get_otg_double_buffer_pending = optc3_get_otg_update_pending, + .get_pipe_update_pending = optc3_get_pipe_update_pending, + .set_vupdate_keepout = optc401_set_vupdate_keepout, + .wait_update_lock_status = optc401_wait_update_lock_status, }; void dcn401_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.h index bb13a645802d0e..1be89571986fff 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.h @@ -159,7 +159,11 @@ SF(OTG0_OTG_PSTATE_REGISTER, OTG_PSTATE_KEEPOUT_START, mask_sh),\ SF(OTG0_OTG_PSTATE_REGISTER, OTG_PSTATE_EXTEND, mask_sh),\ SF(OTG0_OTG_PSTATE_REGISTER, OTG_UNBLANK, mask_sh),\ - SF(OTG0_OTG_PSTATE_REGISTER, OTG_PSTATE_ALLOW_WIDTH_MIN, mask_sh) + SF(OTG0_OTG_PSTATE_REGISTER, OTG_PSTATE_ALLOW_WIDTH_MIN, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_FLIP_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_DC_REG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_CURSOR_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_PIPE_UPDATE_STATUS, OTG_VUPDATE_KEEPOUT_STATUS, mask_sh) void dcn401_timing_generator_init(struct optc *optc1); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c index 53a5f4cb648cbd..e698543ec93747 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c @@ -623,7 +623,7 @@ static struct link_encoder *dce100_link_encoder_create( kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc110) + if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c index 91da5cf85b69fa..035c6cfdaee570 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c @@ -668,7 +668,7 @@ static struct link_encoder *dce110_link_encoder_create( kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc110) + if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c index 162856c523e40c..480a5096738516 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c @@ -629,7 +629,7 @@ static struct link_encoder *dce112_link_encoder_create( kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc110) + if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c index 621825a51f46e1..c63c5962343332 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c @@ -706,7 +706,7 @@ static struct link_encoder *dce120_link_encoder_create( kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc110) + if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c index a73d3c6ef42585..3d5113f010bb4f 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c @@ -723,7 +723,7 @@ static struct link_encoder *dce80_link_encoder_create( kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc110) + if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c index 563c5eec83ff3d..770a380cc03d79 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c @@ -533,7 +533,6 @@ static const struct dc_debug_options debug_defaults_drv = { .sanity_checks = true, .disable_dmcu = false, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, /* raven smu dones't allow 0 disp clk, @@ -560,18 +559,6 @@ static const struct dc_debug_options debug_defaults_drv = { .using_dml2 = false, }; -static const struct dc_debug_options debug_defaults_diags = { - .disable_dmcu = false, - .force_abm_enable = false, - .timing_trace = true, - .clock_trace = true, - .disable_stutter = true, - .disable_pplib_clock_request = true, - .disable_pplib_wm_range = true, - .underflow_assert_delay_us = 0xFFFFFFFF, - .enable_legacy_fast_update = true, -}; - static void dcn10_dpp_destroy(struct dpp **dpp) { kfree(TO_DCN10_DPP(*dpp)); @@ -751,7 +738,7 @@ static struct link_encoder *dcn10_link_encoder_create( kzalloc(sizeof(struct dcn10_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc10) + if (!enc10 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = @@ -1400,8 +1387,6 @@ static bool dcn10_resource_construct( if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) dc->debug = debug_defaults_drv; - else - dc->debug = debug_defaults_diags; /************************************************* * Create resources * diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c index eea2b3b307cd5f..7a5b9aa5292cda 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c @@ -706,7 +706,6 @@ static const struct resource_caps res_cap_nv14 = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = false, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, @@ -920,7 +919,7 @@ struct link_encoder *dcn20_link_encoder_create( kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = @@ -1511,6 +1510,7 @@ bool dcn20_split_stream_for_odm( if (prev_odm_pipe->plane_state) { struct scaler_data *sd = &prev_odm_pipe->plane_res.scl_data; + struct output_pixel_processor *opp = next_odm_pipe->stream_res.opp; int new_width; /* HACTIVE halved for odm combine */ @@ -1544,7 +1544,28 @@ bool dcn20_split_stream_for_odm( sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int( sd->ratios.horz_c, sd->h_active - sd->recout.x)); sd->recout.x = 0; + + /* + * When odm is used in YcbCr422 or 420 colour space, a split screen + * will be seen with the previous calculations since the extra left + * edge pixel is accounted for in fmt but not in viewport. + * + * Below are calculations which fix the split by fixing the calculations + * if there is an extra left edge pixel. + */ + if (opp && opp->funcs->opp_get_left_edge_extra_pixel_count + && opp->funcs->opp_get_left_edge_extra_pixel_count( + opp, next_odm_pipe->stream->timing.pixel_encoding, + resource_is_pipe_type(next_odm_pipe, OTG_MASTER)) == 1) { + sd->h_active += 1; + sd->recout.width += 1; + sd->viewport.x -= dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1)); + sd->viewport_c.x -= dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1)); + sd->viewport_c.width += dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1)); + sd->viewport.width += dc_fixpt_ceil(dc_fixpt_mul_int(sd->ratios.horz, 1)); + } } + if (!next_odm_pipe->top_pipe) next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx]; else @@ -2133,6 +2154,7 @@ bool dcn20_fast_validate_bw( ASSERT(0); } } + /* Actual dsc count per stream dsc validation*/ if (!dcn20_validate_dsc(dc, context)) { context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] = diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c index fc54483b91047a..d3d67d36652308 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c @@ -600,7 +600,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, .pipe_split_policy = MPC_SPLIT_DYNAMIC, @@ -797,7 +796,7 @@ static struct link_encoder *dcn201_link_encoder_create( kzalloc(sizeof(struct dcn20_link_encoder), GFP_ATOMIC); struct dcn10_link_encoder *enc10; - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; enc10 = &enc20->enc10; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c index 347e6aaea582fb..021ba8ac5c8c9c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c @@ -610,7 +610,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = false, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, .min_disp_clk_khz = 100000, @@ -1298,7 +1297,7 @@ static struct link_encoder *dcn21_link_encoder_create( kzalloc(sizeof(struct dcn21_link_encoder), GFP_KERNEL); int link_regs_id; - if (!enc21) + if (!enc21 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; link_regs_id = diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c index 5040a4c6ed1862..bfd0eccbed28c8 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -711,7 +711,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, //No DMCU on DCN30 .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, .pipe_split_policy = MPC_SPLIT_DYNAMIC, @@ -927,7 +926,7 @@ static struct link_encoder *dcn30_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; dcn30_link_encoder_construct(enc20, @@ -2354,6 +2353,7 @@ static bool dcn30_resource_construct( dc->caps.dp_hdmi21_pcon_support = true; dc->caps.max_v_total = (1 << 15) - 1; + dc->caps.vtotal_limited_by_fp2 = true; /* read VBIOS LTTPR caps */ { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c index 7d04739c3ba146..a9816affd312db 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c @@ -682,7 +682,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_dpp_power_gate = false, .disable_hubp_power_gate = false, @@ -883,7 +882,7 @@ static struct link_encoder *dcn301_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; dcn301_link_encoder_construct(enc20, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c index 5791b5cc287529..7baefc910a3dc7 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c @@ -81,7 +81,6 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, .pipe_split_policy = MPC_SPLIT_DYNAMIC, @@ -893,7 +892,7 @@ static struct link_encoder *dcn302_link_encoder_create( { struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; dcn30_link_encoder_construct(enc20, enc_init_data, &link_enc_feature, @@ -1234,6 +1233,7 @@ static bool dcn302_resource_construct( dc->caps.extended_aux_timeout_support = true; dc->caps.dmcub_support = true; dc->caps.max_v_total = (1 << 15) - 1; + dc->caps.vtotal_limited_by_fp2 = true; /* Color pipeline capabilities */ dc->caps.color.dpp.dcn_arch = 1; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c index 63f0f882c8610c..8a57d46ad15f8c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c @@ -82,7 +82,6 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = true, .pipe_split_policy = MPC_SPLIT_AVOID, @@ -839,7 +838,7 @@ static struct link_encoder *dcn303_link_encoder_create( { struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; dcn30_link_encoder_construct(enc20, enc_init_data, &link_enc_feature, @@ -1179,6 +1178,7 @@ static bool dcn303_resource_construct( dc->caps.extended_aux_timeout_support = true; dc->caps.dmcub_support = true; dc->caps.max_v_total = (1 << 15) - 1; + dc->caps.vtotal_limited_by_fp2 = true; /* Color pipeline capabilities */ dc->caps.color.dpp.dcn_arch = 1; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index ac8cb20e2e3b64..54ec3d8e920c9c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -858,7 +858,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_DYNAMIC, @@ -869,7 +868,7 @@ static const struct dc_debug_options debug_defaults_drv = { .max_downscale_src_width = 4096,/*upto true 4K*/ .disable_pplib_wm_range = false, .scl_reset_length10 = true, - .sanity_checks = true, + .sanity_checks = false, .underflow_assert_delay_us = 0xFFFFFFFF, .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true, @@ -1093,7 +1092,7 @@ static struct link_encoder *dcn31_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; dcn31_link_encoder_construct(enc20, @@ -1721,6 +1720,12 @@ int dcn31_populate_dml_pipes_from_context( return pipe_cnt; } +unsigned int dcn31_get_det_buffer_size( + const struct dc_state *context) +{ + return context->bw_ctx.dml.ip.det_buffer_size_kbytes; +} + void dcn31_calculate_wm_and_dlg( struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes, @@ -1843,6 +1848,7 @@ static struct resource_funcs dcn31_res_pool_funcs = { .update_bw_bounding_box = dcn31_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn31_get_panel_config_defaults, + .get_det_buffer_size = dcn31_get_det_buffer_size, }; static struct clock_source *dcn30_clock_source_create( diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h index 901436591ed45c..551ad912f7bea8 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h @@ -63,6 +63,9 @@ struct resource_pool *dcn31_create_resource_pool( const struct dc_init_data *init_data, struct dc *dc); +unsigned int dcn31_get_det_buffer_size( + const struct dc_state *context); + /*temp: B0 specific before switch to dcn313 headers*/ #ifndef regPHYPLLF_PIXCLK_RESYNC_CNTL #define regPHYPLLF_PIXCLK_RESYNC_CNTL 0x007e diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c index 169924d0a8393e..2794473f2aff6d 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c @@ -876,7 +876,6 @@ static const struct dc_debug_options debug_defaults_drv = { .replay_skip_crtc_disabled = true, .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_dpp_power_gate = false, .disable_hubp_power_gate = false, @@ -889,7 +888,7 @@ static const struct dc_debug_options debug_defaults_drv = { .max_downscale_src_width = 4096,/*upto true 4k*/ .disable_pplib_wm_range = false, .scl_reset_length10 = true, - .sanity_checks = true, + .sanity_checks = false, .underflow_assert_delay_us = 0xFFFFFFFF, .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true, @@ -1149,7 +1148,7 @@ static struct link_encoder *dcn31_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; dcn31_link_encoder_construct(enc20, @@ -1778,6 +1777,7 @@ static struct resource_funcs dcn314_res_pool_funcs = { .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn314_get_panel_config_defaults, .get_preferred_eng_id_dpia = dcn314_get_preferred_eng_id_dpia, + .get_det_buffer_size = dcn31_get_det_buffer_size, }; static struct clock_source *dcn30_clock_source_create( diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c index 3f4b9dba411244..4ee33eb3381d17 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -858,7 +858,6 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = true, /*hw not support it*/ .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_DYNAMIC, @@ -1091,7 +1090,7 @@ static struct link_encoder *dcn31_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; dcn31_link_encoder_construct(enc20, @@ -1812,6 +1811,11 @@ static void dcn315_get_panel_config_defaults(struct dc_panel_config *panel_confi *panel_config = panel_config_defaults; } +static int dcn315_get_power_profile(const struct dc_state *context) +{ + return !context->bw_ctx.bw.dcn.clk.p_state_change_support; +} + static struct dc_cap_funcs cap_funcs = { .get_dcc_compression_cap = dcn20_get_dcc_compression_cap }; @@ -1840,6 +1844,8 @@ static struct resource_funcs dcn315_res_pool_funcs = { .update_bw_bounding_box = dcn315_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn315_get_panel_config_defaults, + .get_power_profile = dcn315_get_power_profile, + .get_det_buffer_size = dcn31_get_det_buffer_size, }; static bool dcn315_resource_construct( diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c index 5fd52c5fcee458..79eddbafe3c292 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c @@ -853,7 +853,6 @@ static const struct dc_debug_options debug_defaults_drv = { .disable_z10 = true, /*hw not support it*/ .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_DYNAMIC, @@ -1085,7 +1084,7 @@ static struct link_encoder *dcn31_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; dcn31_link_encoder_construct(enc20, @@ -1720,6 +1719,7 @@ static struct resource_funcs dcn316_res_pool_funcs = { .update_bw_bounding_box = dcn316_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn316_get_panel_config_defaults, + .get_det_buffer_size = dcn31_get_det_buffer_size, }; static bool dcn316_resource_construct( diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c index a124ad9bd108c8..12d247a7ec4543 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -689,7 +689,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_AVOID, // Due to CRB, no need to MPC split anymore @@ -1039,7 +1038,7 @@ static struct link_encoder *dcn32_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; #undef REG_STRUCT @@ -1990,6 +1989,10 @@ unsigned int dcn32_calculate_mall_ways_from_bytes(const struct dc *dc, unsigned return 0; } + if (dc->caps.max_cab_allocation_bytes == 0) { + return 0xffffffff; + } + /* add 2 lines for worst case alignment */ cache_lines_used = total_size_in_mall_bytes / dc->caps.cache_line_size + 2; @@ -2186,6 +2189,7 @@ static bool dcn32_resource_construct( dc->caps.dmcub_support = true; dc->caps.seamless_odm = true; dc->caps.max_v_total = (1 << 15) - 1; + dc->caps.vtotal_limited_by_fp2 = true; /* Color pipeline capabilities */ dc->caps.color.dpp.dcn_arch = 1; @@ -2800,6 +2804,7 @@ struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_opp_head( free_pipe->plane_res.xfm = pool->transforms[free_pipe_idx]; free_pipe->plane_res.dpp = pool->dpps[free_pipe_idx]; free_pipe->plane_res.mpcc_inst = pool->dpps[free_pipe_idx]->inst; + free_pipe->hblank_borrow = otg_master->hblank_borrow; if (free_pipe->stream->timing.flags.DSC == 1) { dcn20_acquire_dsc(free_pipe->stream->ctx->dc, &new_ctx->res_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h index 7901792afb7b3a..86c6e5e8c42eb8 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h @@ -1054,7 +1054,8 @@ unsigned int dcn32_calculate_mall_ways_from_bytes(const struct dc *dc, unsigned SRI_ARR(OPTC_BYTES_PER_PIXEL, ODM, inst), \ SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst), \ SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst), \ - SRI_ARR(OTG_DRR_CONTROL, OTG, inst) + SRI_ARR(OTG_DRR_CONTROL, OTG, inst), \ + SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst) /* HUBP */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c index 827a94f84f1001..06b9479c8bd3a3 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -686,7 +686,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_AVOID, @@ -1035,7 +1034,7 @@ static struct link_encoder *dcn321_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; #undef REG_STRUCT @@ -1743,6 +1742,7 @@ static bool dcn321_resource_construct( dc->caps.extended_aux_timeout_support = true; dc->caps.dmcub_support = true; dc->caps.max_v_total = (1 << 15) - 1; + dc->caps.vtotal_limited_by_fp2 = true; /* Color pipeline capabilities */ dc->caps.color.dpp.dcn_arch = 1; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 893a9d9ee870df..89e2adcf2a2858 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -712,7 +712,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_AVOID, @@ -1074,7 +1073,7 @@ static struct link_encoder *dcn35_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; #undef REG_STRUCT @@ -1779,6 +1778,7 @@ static struct resource_funcs dcn35_res_pool_funcs = { .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn35_get_panel_config_defaults, .get_preferred_eng_id_dpia = dcn35_get_preferred_eng_id_dpia, + .get_det_buffer_size = dcn31_get_det_buffer_size, }; static bool dcn35_resource_construct( @@ -1850,6 +1850,7 @@ static bool dcn35_resource_construct( dc->caps.zstate_support = true; dc->caps.ips_support = true; dc->caps.max_v_total = (1 << 15) - 1; + dc->caps.vtotal_limited_by_fp2 = true; /* Color pipeline capabilities */ dc->caps.color.dpp.dcn_arch = 1; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c index 70abd32ce2ad18..263a37c1cd3ae8 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c @@ -692,7 +692,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_AVOID, @@ -1054,7 +1053,7 @@ static struct link_encoder *dcn35_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; #undef REG_STRUCT @@ -1758,6 +1757,7 @@ static struct resource_funcs dcn351_res_pool_funcs = { .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn35_get_panel_config_defaults, .get_preferred_eng_id_dpia = dcn351_get_preferred_eng_id_dpia, + .get_det_buffer_size = dcn31_get_det_buffer_size, }; static bool dcn351_resource_construct( @@ -1829,6 +1829,7 @@ static bool dcn351_resource_construct( dc->caps.zstate_support = true; dc->caps.ips_support = true; dc->caps.max_v_total = (1 << 15) - 1; + dc->caps.vtotal_limited_by_fp2 = true; /* Color pipeline capabilities */ dc->caps.color.dpp.dcn_arch = 1; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c index 9d56fbdcd06afd..2a3dabfe3ceac4 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.c @@ -685,7 +685,6 @@ static const struct dc_plane_cap plane_cap = { static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, .force_abm_enable = false, - .timing_trace = false, .clock_trace = true, .disable_pplib_clock_request = false, .pipe_split_policy = MPC_SPLIT_AVOID, @@ -1032,7 +1031,7 @@ static struct link_encoder *dcn401_link_encoder_create( struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) + if (!enc20 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) return NULL; #undef REG_STRUCT @@ -1579,7 +1578,8 @@ static void dcn401_destroy_resource_pool(struct resource_pool **pool) } static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap, + .get_subvp_en = dcn32_subvp_in_use, }; static void dcn401_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) @@ -1688,6 +1688,45 @@ static void dcn401_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx) } } +static int dcn401_get_power_profile(const struct dc_state *context) +{ + int uclk_mhz = context->bw_ctx.bw.dcn.clk.dramclk_khz / 1000; + int dpm_level = 0; + + for (int i = 0; i < context->clk_mgr->bw_params->clk_table.num_entries_per_clk.num_memclk_levels; i++) { + if (context->clk_mgr->bw_params->clk_table.entries[i].memclk_mhz == 0 || + uclk_mhz < context->clk_mgr->bw_params->clk_table.entries[i].memclk_mhz) + break; + if (uclk_mhz > context->clk_mgr->bw_params->clk_table.entries[i].memclk_mhz) + dpm_level++; + } + + return dpm_level; +} + +static unsigned int dcn401_calc_num_avail_chans_for_mall(struct dc *dc, unsigned int num_chans) +{ + unsigned int num_available_chans = 1; + + /* channels for MALL must be a power of 2 */ + while (num_chans > 1) { + num_available_chans = (num_available_chans << 1); + num_chans = (num_chans >> 1); + } + + /* cannot be odd */ + num_available_chans &= ~1; + + /* clamp to max available channels for MALL per ASIC */ + if (ASICREV_IS_GC_12_0_0_A0(dc->ctx->asic_id.hw_internal_rev)) { + num_available_chans = num_available_chans > 16 ? 16 : num_available_chans; + } else if (ASICREV_IS_GC_12_0_1_A0(dc->ctx->asic_id.hw_internal_rev)) { + num_available_chans = num_available_chans > 8 ? 8 : num_available_chans; + } + + return num_available_chans; +} + static struct resource_funcs dcn401_res_pool_funcs = { .destroy = dcn401_destroy_resource_pool, .link_enc_create = dcn401_link_encoder_create, @@ -1714,6 +1753,7 @@ static struct resource_funcs dcn401_res_pool_funcs = { .prepare_mcache_programming = dcn401_prepare_mcache_programming, .build_pipe_pix_clk_params = dcn401_build_pipe_pix_clk_params, .calculate_mall_ways_from_bytes = dcn32_calculate_mall_ways_from_bytes, + .get_power_profile = dcn401_get_power_profile, }; static uint32_t read_pipe_fuses(struct dc_context *ctx) @@ -1795,14 +1835,12 @@ static bool dcn401_resource_construct( dc->caps.min_horizontal_blanking_period = 80; dc->caps.dmdata_alloc_size = 2048; dc->caps.mall_size_per_mem_channel = 4; - /* total size = mall per channel * num channels * 1024 * 1024 */ - dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576; dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8; dc->caps.cache_line_size = 64; dc->caps.cache_num_ways = 16; /* Calculate the available MALL space */ - dc->caps.max_cab_allocation_bytes = dcn32_calc_num_avail_chans_for_mall( + dc->caps.max_cab_allocation_bytes = dcn401_calc_num_avail_chans_for_mall( dc, dc->ctx->dc_bios->vram_info.num_chans) * dc->caps.mall_size_per_mem_channel * 1024 * 1024; dc->caps.mall_size_total = dc->caps.max_cab_allocation_bytes; @@ -1826,6 +1864,7 @@ static bool dcn401_resource_construct( dc->caps.extended_aux_timeout_support = true; dc->caps.dmcub_support = true; dc->caps.max_v_total = (1 << 15) - 1; + dc->caps.vtotal_limited_by_fp2 = true; if (ASICREV_IS_GC_12_0_1_A0(dc->ctx->asic_id.hw_internal_rev)) dc->caps.dcc_plane_width_limit = 7680; @@ -1867,6 +1906,7 @@ static bool dcn401_resource_construct( dc->config.prefer_easf = true; dc->config.dc_mode_clk_limit_support = true; dc->config.enable_windowed_mpo_odm = true; + dc->config.set_pipe_unlock_order = true; /* Need to ensure DET gets freed before allocating */ /* read VBIOS LTTPR caps */ { if (ctx->dc_bios->funcs->get_lttpr_caps) { @@ -2132,6 +2172,7 @@ static bool dcn401_resource_construct( /* SPL */ spl_init_easf_filter_coeffs(); spl_init_blur_scale_coeffs(); + dc->caps.scl_caps.sharpener_support = true; return true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.h index 514d1ce20df9ef..19568c35966942 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.h +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn401/dcn401_resource.h @@ -536,8 +536,9 @@ void dcn401_prepare_mcache_programming(struct dc *dc, struct dc_state *context); SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst), \ SRI_ARR(OPTC_WIDTH_CONTROL2, ODM, inst), \ SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst), \ - SRI_ARR(OTG_DRR_CONTROL, OTG, inst), \ - SRI_ARR(OTG_PSTATE_REGISTER, OTG, inst) + SRI_ARR(OTG_DRR_CONTROL, OTG, inst), \ + SRI_ARR(OTG_PSTATE_REGISTER, OTG, inst), \ + SRI_ARR(OTG_PIPE_UPDATE_STATUS, OTG, inst) /* HUBBUB */ #define HUBBUB_REG_LIST_DCN4_01_RI(id) \ @@ -609,7 +610,10 @@ void dcn401_prepare_mcache_programming(struct dc *dc, struct dc_state *context); SR(DCHUBBUB_CLOCK_CNTL), \ SR(DCHUBBUB_SDPIF_CFG0), \ SR(DCHUBBUB_SDPIF_CFG1), \ - SR(DCHUBBUB_MEM_PWR_MODE_CTRL) + SR(DCHUBBUB_MEM_PWR_MODE_CTRL), \ + SR(DCHUBBUB_TIMEOUT_DETECTION_CTRL1), \ + SR(DCHUBBUB_TIMEOUT_DETECTION_CTRL2), \ + SR(DCHUBBUB_CTRL_STATUS) /* DCCG */ diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c index 014e8a296f0c78..73a65913cb1247 100644 --- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c +++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.c @@ -99,7 +99,7 @@ static struct spl_rect calculate_plane_rec_in_timing_active( * * recout_x = 128 + round(plane_x * 2304 / 1920) * recout_w = 128 + round((plane_x + plane_w) * 2304 / 1920) - recout_x - * recout_y = 0 + round(plane_y * 1440 / 1280) + * recout_y = 0 + round(plane_y * 1440 / 1200) * recout_h = 0 + round((plane_y + plane_h) * 1440 / 1200) - recout_y * * NOTE: fixed point division is not error free. To reduce errors @@ -739,14 +739,13 @@ static enum scl_mode spl_get_dscl_mode(const struct spl_in *spl_in, return SCL_MODE_SCALING_444_RGB_ENABLE; } - /* Bypass YUV if at 1:1 with no ISHARP or if doing 2:1 YUV - * downscale without EASF + /* + * Bypass YUV if Y is 1:1 with no ISHARP + * Do not bypass UV at 1:1 for cositing to be applied */ - if ((!enable_isharp) && (!enable_easf)) { + if (!enable_isharp) { if (data->ratios.horz.value == one && data->ratios.vert.value == one) return SCL_MODE_SCALING_420_LUMA_BYPASS; - if (data->ratios.horz_c.value == one && data->ratios.vert_c.value == one) - return SCL_MODE_SCALING_420_CHROMA_BYPASS; } return SCL_MODE_SCALING_420_YCBCR_ENABLE; @@ -848,13 +847,13 @@ static bool spl_get_isharp_en(struct spl_in *spl_in, * surfaces based on policy setting */ if (!spl_is_yuv420(spl_in->basic_in.format) && - (spl_in->debug.sharpen_policy == SHARPEN_YUV)) + (spl_in->sharpen_policy == SHARPEN_YUV)) return enable_isharp; else if ((spl_is_yuv420(spl_in->basic_in.format) && !fullscreen) && - (spl_in->debug.sharpen_policy == SHARPEN_RGB_FULLSCREEN_YUV)) + (spl_in->sharpen_policy == SHARPEN_RGB_FULLSCREEN_YUV)) return enable_isharp; else if (!spl_in->is_fullscreen && - spl_in->debug.sharpen_policy == SHARPEN_FULLSCREEN_ALL) + spl_in->sharpen_policy == SHARPEN_FULLSCREEN_ALL) return enable_isharp; /* @@ -868,6 +867,60 @@ static bool spl_get_isharp_en(struct spl_in *spl_in, return enable_isharp; } +/* Calculate number of tap with adaptive scaling off */ +static void spl_get_taps_non_adaptive_scaler( + struct spl_scratch *spl_scratch, const struct spl_taps *in_taps) +{ + if (in_taps->h_taps == 0) { + if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz) > 1) + spl_scratch->scl_data.taps.h_taps = spl_min(2 * spl_fixpt_ceil( + spl_scratch->scl_data.ratios.horz), 8); + else + spl_scratch->scl_data.taps.h_taps = 4; + } else + spl_scratch->scl_data.taps.h_taps = in_taps->h_taps; + + if (in_taps->v_taps == 0) { + if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) > 1) + spl_scratch->scl_data.taps.v_taps = spl_min(spl_fixpt_ceil(spl_fixpt_mul_int( + spl_scratch->scl_data.ratios.vert, 2)), 8); + else + spl_scratch->scl_data.taps.v_taps = 4; + } else + spl_scratch->scl_data.taps.v_taps = in_taps->v_taps; + + if (in_taps->v_taps_c == 0) { + if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c) > 1) + spl_scratch->scl_data.taps.v_taps_c = spl_min(spl_fixpt_ceil(spl_fixpt_mul_int( + spl_scratch->scl_data.ratios.vert_c, 2)), 8); + else + spl_scratch->scl_data.taps.v_taps_c = 4; + } else + spl_scratch->scl_data.taps.v_taps_c = in_taps->v_taps_c; + + if (in_taps->h_taps_c == 0) { + if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz_c) > 1) + spl_scratch->scl_data.taps.h_taps_c = spl_min(2 * spl_fixpt_ceil( + spl_scratch->scl_data.ratios.horz_c), 8); + else + spl_scratch->scl_data.taps.h_taps_c = 4; + } else if ((in_taps->h_taps_c % 2) != 0 && in_taps->h_taps_c != 1) + /* Only 1 and even h_taps_c are supported by hw */ + spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c - 1; + else + spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c; + + if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz)) + spl_scratch->scl_data.taps.h_taps = 1; + if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert)) + spl_scratch->scl_data.taps.v_taps = 1; + if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c)) + spl_scratch->scl_data.taps.h_taps_c = 1; + if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c)) + spl_scratch->scl_data.taps.v_taps_c = 1; + +} + /* Calculate optimal number of taps */ static bool spl_get_optimal_number_of_taps( int max_downscale_src_width, struct spl_in *spl_in, struct spl_scratch *spl_scratch, @@ -879,11 +932,26 @@ static bool spl_get_optimal_number_of_taps( int min_taps_y, min_taps_c; enum lb_memory_config lb_config; bool skip_easf = false; + bool is_ycbcr = spl_dscl_is_video_format(spl_in->basic_in.format); if (spl_scratch->scl_data.viewport.width > spl_scratch->scl_data.h_active && max_downscale_src_width != 0 && - spl_scratch->scl_data.viewport.width > max_downscale_src_width) + spl_scratch->scl_data.viewport.width > max_downscale_src_width) { + spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps); + *enable_easf_v = false; + *enable_easf_h = false; + *enable_isharp = false; return false; + } + + /* Disable adaptive scaler and sharpener when integer scaling is enabled */ + if (spl_in->scaling_quality.integer_scaling) { + spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps); + *enable_easf_v = false; + *enable_easf_h = false; + *enable_isharp = false; + return true; + } /* Check if we are using EASF or not */ skip_easf = enable_easf(spl_in, spl_scratch); @@ -893,43 +961,9 @@ static bool spl_get_optimal_number_of_taps( * From programming guide: taps = min{ ceil(2*H_RATIO,1), 8} for downscaling * taps = 4 for upscaling */ - if (skip_easf) { - if (in_taps->h_taps == 0) { - if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz) > 1) - spl_scratch->scl_data.taps.h_taps = spl_min(2 * spl_fixpt_ceil( - spl_scratch->scl_data.ratios.horz), 8); - else - spl_scratch->scl_data.taps.h_taps = 4; - } else - spl_scratch->scl_data.taps.h_taps = in_taps->h_taps; - if (in_taps->v_taps == 0) { - if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) > 1) - spl_scratch->scl_data.taps.v_taps = spl_min(spl_fixpt_ceil(spl_fixpt_mul_int( - spl_scratch->scl_data.ratios.vert, 2)), 8); - else - spl_scratch->scl_data.taps.v_taps = 4; - } else - spl_scratch->scl_data.taps.v_taps = in_taps->v_taps; - if (in_taps->v_taps_c == 0) { - if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert_c) > 1) - spl_scratch->scl_data.taps.v_taps_c = spl_min(spl_fixpt_ceil(spl_fixpt_mul_int( - spl_scratch->scl_data.ratios.vert_c, 2)), 8); - else - spl_scratch->scl_data.taps.v_taps_c = 4; - } else - spl_scratch->scl_data.taps.v_taps_c = in_taps->v_taps_c; - if (in_taps->h_taps_c == 0) { - if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.horz_c) > 1) - spl_scratch->scl_data.taps.h_taps_c = spl_min(2 * spl_fixpt_ceil( - spl_scratch->scl_data.ratios.horz_c), 8); - else - spl_scratch->scl_data.taps.h_taps_c = 4; - } else if ((in_taps->h_taps_c % 2) != 0 && in_taps->h_taps_c != 1) - /* Only 1 and even h_taps_c are supported by hw */ - spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c - 1; - else - spl_scratch->scl_data.taps.h_taps_c = in_taps->h_taps_c; - } else { + if (skip_easf) + spl_get_taps_non_adaptive_scaler(spl_scratch, in_taps); + else { if (spl_is_yuv420(spl_in->basic_in.format)) { spl_scratch->scl_data.taps.h_taps = 6; spl_scratch->scl_data.taps.v_taps = 6; @@ -954,7 +988,7 @@ static bool spl_get_optimal_number_of_taps( else lb_config = LB_MEMORY_CONFIG_0; // Determine max vtap support by calculating how much line buffer can fit - spl_in->funcs->spl_calc_lb_num_partitions(spl_in->basic_out.alpha_en, &spl_scratch->scl_data, + spl_in->callbacks.spl_calc_lb_num_partitions(spl_in->basic_out.alpha_en, &spl_scratch->scl_data, lb_config, &num_part_y, &num_part_c); /* MAX_V_TAPS = MIN (NUM_LINES - MAX(CEILING(V_RATIO,1)-2, 0), 8) */ if (spl_fixpt_ceil(spl_scratch->scl_data.ratios.vert) > 2) @@ -1040,10 +1074,9 @@ static bool spl_get_optimal_number_of_taps( /* Sharpener requires scaler to be enabled, including for 1:1 * Check if ISHARP can be enabled - * If ISHARP is not enabled, for 1:1, set taps to 1 and disable - * EASF - * For case of 2:1 YUV where chroma is 1:1, set taps to 1 if - * EASF is not enabled + * If ISHARP is not enabled, set taps to 1 if ratio is 1:1 + * except for chroma taps. Keep previous taps so it can + * handle cositing */ *enable_isharp = spl_get_isharp_en(spl_in, spl_scratch); @@ -1053,20 +1086,28 @@ static bool spl_get_optimal_number_of_taps( spl_scratch->scl_data.taps.h_taps = 1; spl_scratch->scl_data.taps.v_taps = 1; - if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c)) + if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c) && !is_ycbcr) spl_scratch->scl_data.taps.h_taps_c = 1; - if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c)) + if (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c) && !is_ycbcr) spl_scratch->scl_data.taps.v_taps_c = 1; *enable_easf_v = false; *enable_easf_h = false; } else { if ((!*enable_easf_h) && + (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz))) + spl_scratch->scl_data.taps.h_taps = 1; + + if ((!*enable_easf_v) && + (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert))) + spl_scratch->scl_data.taps.v_taps = 1; + + if ((!*enable_easf_h) && !is_ycbcr && (IDENTITY_RATIO(spl_scratch->scl_data.ratios.horz_c))) spl_scratch->scl_data.taps.h_taps_c = 1; - if ((!*enable_easf_v) && + if ((!*enable_easf_v) && !is_ycbcr && (IDENTITY_RATIO(spl_scratch->scl_data.ratios.vert_c))) spl_scratch->scl_data.taps.v_taps_c = 1; } @@ -1077,8 +1118,7 @@ static bool spl_get_optimal_number_of_taps( static void spl_set_black_color_data(enum spl_pixel_format format, struct scl_black_color *scl_black_color) { - bool ycbcr = format >= SPL_PIXEL_FORMAT_VIDEO_BEGIN - && format <= SPL_PIXEL_FORMAT_VIDEO_END; + bool ycbcr = spl_dscl_is_video_format(format); if (ycbcr) { scl_black_color->offset_rgb_y = BLACK_OFFSET_RGB_Y; scl_black_color->offset_rgb_cbcr = BLACK_OFFSET_CBCR; @@ -1590,7 +1630,8 @@ static void spl_set_isharp_data(struct dscl_prog_data *dscl_prog_data, spl_build_isharp_1dlut_from_reference_curve(ratio, setup, adp_sharpness, scale_to_sharpness_policy); - dscl_prog_data->isharp_delta = spl_get_pregen_filter_isharp_1D_lut(setup); + memcpy(dscl_prog_data->isharp_delta, spl_get_pregen_filter_isharp_1D_lut(setup), + sizeof(uint32_t) * ISHARP_LUT_TABLE_SIZE); dscl_prog_data->sharpness_level = adp_sharpness.sharpness_level; dscl_prog_data->isharp_en = 1; // ISHARP_EN @@ -1711,6 +1752,32 @@ static void spl_set_isharp_data(struct dscl_prog_data *dscl_prog_data, spl_set_blur_scale_data(dscl_prog_data, data); } +/* Calculate recout, scaling ratio, and viewport, then get optimal number of taps */ +static bool spl_calculate_number_of_taps(struct spl_in *spl_in, struct spl_scratch *spl_scratch, struct spl_out *spl_out, + bool *enable_easf_v, bool *enable_easf_h, bool *enable_isharp) +{ + bool res = false; + + memset(spl_scratch, 0, sizeof(struct spl_scratch)); + spl_scratch->scl_data.h_active = spl_in->h_active; + spl_scratch->scl_data.v_active = spl_in->v_active; + + // All SPL calls + /* recout calculation */ + /* depends on h_active */ + spl_calculate_recout(spl_in, spl_scratch, spl_out); + /* depends on pixel format */ + spl_calculate_scaling_ratios(spl_in, spl_scratch, spl_out); + /* depends on scaling ratios and recout, does not calculate offset yet */ + spl_calculate_viewport_size(spl_in, spl_scratch); + + res = spl_get_optimal_number_of_taps( + spl_in->basic_out.max_downscale_src_width, spl_in, + spl_scratch, &spl_in->scaling_quality, enable_easf_v, + enable_easf_h, enable_isharp); + return res; +} + /* Calculate scaler parameters */ bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out) { @@ -1725,23 +1792,9 @@ bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out) bool enable_isharp = false; const struct spl_scaler_data *data = &spl_scratch.scl_data; - memset(&spl_scratch, 0, sizeof(struct spl_scratch)); - spl_scratch.scl_data.h_active = spl_in->h_active; - spl_scratch.scl_data.v_active = spl_in->v_active; - - // All SPL calls - /* recout calculation */ - /* depends on h_active */ - spl_calculate_recout(spl_in, &spl_scratch, spl_out); - /* depends on pixel format */ - spl_calculate_scaling_ratios(spl_in, &spl_scratch, spl_out); - /* depends on scaling ratios and recout, does not calculate offset yet */ - spl_calculate_viewport_size(spl_in, &spl_scratch); + res = spl_calculate_number_of_taps(spl_in, &spl_scratch, spl_out, + &enable_easf_v, &enable_easf_h, &enable_isharp); - res = spl_get_optimal_number_of_taps( - spl_in->basic_out.max_downscale_src_width, spl_in, - &spl_scratch, &spl_in->scaling_quality, &enable_easf_v, - &enable_easf_h, &enable_isharp); /* * Depends on recout, scaling ratios, h_active and taps * May need to re-check lb size after this in some obscure scenario @@ -1753,12 +1806,12 @@ bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out) // Clamp spl_clamp_viewport(&spl_scratch.scl_data.viewport); - if (!res) - return res; - // Save all calculated parameters in dscl_prog_data structure to program hw registers spl_set_dscl_prog_data(spl_in, &spl_scratch, spl_out, enable_easf_v, enable_easf_h, enable_isharp); + if (!res) + return res; + if (spl_in->lls_pref == LLS_PREF_YES) { if (spl_in->is_hdr_on) setup = HDR_L; @@ -1789,3 +1842,20 @@ bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out) return res; } + +/* External interface to get number of taps only */ +bool spl_get_number_of_taps(struct spl_in *spl_in, struct spl_out *spl_out) +{ + bool res = false; + bool enable_easf_v = false; + bool enable_easf_h = false; + bool enable_isharp = false; + struct spl_scratch spl_scratch; + struct dscl_prog_data *dscl_prog_data = spl_out->dscl_prog_data; + const struct spl_scaler_data *data = &spl_scratch.scl_data; + + res = spl_calculate_number_of_taps(spl_in, &spl_scratch, spl_out, + &enable_easf_v, &enable_easf_h, &enable_isharp); + spl_set_taps_data(dscl_prog_data, data); + return res; +} diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.h b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.h index 205e59a2a8ee8f..02a2d6725ed58d 100644 --- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl.h +++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl.h @@ -13,4 +13,6 @@ bool spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out); +bool spl_get_number_of_taps(struct spl_in *spl_in, struct spl_out *spl_out); + #endif /* __DC_SPL_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl_isharp_filters.h b/drivers/gpu/drm/amd/display/dc/spl/dc_spl_isharp_filters.h index afcc66206ca2a7..89af91e19b6ce8 100644 --- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl_isharp_filters.h +++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl_isharp_filters.h @@ -7,7 +7,6 @@ #include "dc_spl_types.h" -#define ISHARP_LUT_TABLE_SIZE 32 const uint32_t *spl_get_filter_isharp_1D_lut_0(void); const uint32_t *spl_get_filter_isharp_1D_lut_0p5x(void); const uint32_t *spl_get_filter_isharp_1D_lut_1p0x(void); diff --git a/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h b/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h index 2a74ff5fdfdbc6..55d557df4aa5bf 100644 --- a/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h +++ b/drivers/gpu/drm/amd/display/dc/spl/dc_spl_types.h @@ -5,10 +5,8 @@ #ifndef __DC_SPL_TYPES_H__ #define __DC_SPL_TYPES_H__ +#include "spl_debug.h" #include "spl_os_types.h" // swap -#ifndef SPL_ASSERT -#define SPL_ASSERT(_bool) ((void *)0) -#endif #include "spl_fixpt31_32.h" // fixed31_32 and related functions #include "spl_custom_float.h" // custom float and related functions @@ -252,6 +250,7 @@ enum isharp_en { ISHARP_DISABLE, ISHARP_ENABLE }; +#define ISHARP_LUT_TABLE_SIZE 32 // Below struct holds values that can be directly used to program // hardware registers. No conversion/clamping is required struct dscl_prog_data { @@ -402,7 +401,7 @@ struct dscl_prog_data { uint32_t isharp_nl_en; // ISHARP_NL_EN ? TODO:check this struct isharp_lba isharp_lba; // ISHARP_LBA struct isharp_fmt isharp_fmt; // ISHARP_FMT - const uint32_t *isharp_delta; + uint32_t isharp_delta[ISHARP_LUT_TABLE_SIZE]; struct isharp_nldelta_sclip isharp_nldelta_sclip; // ISHARP_NLDELTA_SCLIP /* blur and scale filter */ const uint16_t *filter_blur_scale_v; @@ -498,7 +497,7 @@ enum scale_to_sharpness_policy { SCALE_TO_SHARPNESS_ADJ_YUV = 1, SCALE_TO_SHARPNESS_ADJ_ALL = 2 }; -struct spl_funcs { +struct spl_callbacks { void (*spl_calc_lb_num_partitions) (bool alpha_en, const struct spl_scaler_data *scl_data, @@ -510,7 +509,6 @@ struct spl_funcs { struct spl_debug { int visual_confirm_base_offset; int visual_confirm_dpp_offset; - enum sharpen_policy sharpen_policy; enum scale_to_sharpness_policy scale_to_sharpness_policy; }; @@ -520,7 +518,7 @@ struct spl_in { // Basic slice information int odm_slice_index; // ODM Slice Index using get_odm_split_index struct spl_taps scaling_quality; // Explicit Scaling Quality - struct spl_funcs *funcs; + struct spl_callbacks callbacks; // Inputs for isharp and EASF struct adaptive_sharpness adaptive_sharpness; // Adaptive Sharpness enum linear_light_scaling lls_pref; // Linear Light Scaling @@ -532,6 +530,7 @@ struct spl_in { int h_active; int v_active; int sdr_white_level_nits; + enum sharpen_policy sharpen_policy; }; // end of SPL inputs diff --git a/drivers/gpu/drm/amd/display/dc/spl/spl_debug.h b/drivers/gpu/drm/amd/display/dc/spl/spl_debug.h index 5696dafd0894d5..a6f6132df2416a 100644 --- a/drivers/gpu/drm/amd/display/dc/spl/spl_debug.h +++ b/drivers/gpu/drm/amd/display/dc/spl/spl_debug.h @@ -5,21 +5,26 @@ #ifndef SPL_DEBUG_H #define SPL_DEBUG_H -#ifdef SPL_ASSERT -#undef SPL_ASSERT -#endif -#define SPL_ASSERT(b) +#if defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB) +#define SPL_ASSERT_CRITICAL(expr) do { \ + if (WARN_ON(!(expr))) { \ + kgdb_breakpoint(); \ + } \ +} while (0) +#else +#define SPL_ASSERT_CRITICAL(expr) do { \ + if (WARN_ON(!(expr))) { \ + ; \ + } \ +} while (0) +#endif /* CONFIG_HAVE_KGDB || CONFIG_KGDB */ -#define SPL_ASSERT_CRITICAL(expr) do {if (expr)/* Do nothing */; } while (0) +#if defined(CONFIG_DEBUG_KERNEL_DC) +#define SPL_ASSERT(expr) SPL_ASSERT_CRITICAL(expr) +#else +#define SPL_ASSERT(expr) WARN_ON(!(expr)) +#endif /* CONFIG_DEBUG_KERNEL_DC */ -#ifdef SPL_DALMSG -#undef SPL_DALMSG -#endif -#define SPL_DALMSG(b) - -#ifdef SPL_DAL_ASSERT_MSG -#undef SPL_DAL_ASSERT_MSG -#endif -#define SPL_DAL_ASSERT_MSG(b, m) +#define SPL_BREAK_TO_DEBUGGER() SPL_ASSERT(0) #endif // SPL_DEBUG_H diff --git a/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c index a95565df5487cf..131f1e3949d33f 100644 --- a/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c +++ b/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.c @@ -22,14 +22,14 @@ static inline unsigned long long abs_i64( * result = dividend / divisor * *remainder = dividend % divisor */ -static inline unsigned long long complete_integer_division_u64( +static inline unsigned long long spl_complete_integer_division_u64( unsigned long long dividend, unsigned long long divisor, unsigned long long *remainder) { unsigned long long result; - ASSERT(divisor); + SPL_ASSERT(divisor); result = spl_div64_u64_rem(dividend, divisor, remainder); @@ -60,10 +60,10 @@ struct spl_fixed31_32 spl_fixpt_from_fraction(long long numerator, long long den /* determine integer part */ - unsigned long long res_value = complete_integer_division_u64( + unsigned long long res_value = spl_complete_integer_division_u64( arg1_value, arg2_value, &remainder); - ASSERT(res_value <= LONG_MAX); + SPL_ASSERT(res_value <= (unsigned long long)LONG_MAX); /* determine fractional part */ { @@ -85,7 +85,7 @@ struct spl_fixed31_32 spl_fixpt_from_fraction(long long numerator, long long den { unsigned long long summand = (remainder << 1) >= arg2_value; - ASSERT(res_value <= LLONG_MAX - summand); + SPL_ASSERT(res_value <= (unsigned long long)LLONG_MAX - summand); res_value += summand; } @@ -118,19 +118,19 @@ struct spl_fixed31_32 spl_fixpt_mul(struct spl_fixed31_32 arg1, struct spl_fixed res.value = arg1_int * arg2_int; - ASSERT(res.value <= (long long)LONG_MAX); + SPL_ASSERT(res.value <= (long long)LONG_MAX); res.value <<= FIXED31_32_BITS_PER_FRACTIONAL_PART; tmp = arg1_int * arg2_fra; - ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); + SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); res.value += tmp; tmp = arg2_int * arg1_fra; - ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); + SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); res.value += tmp; @@ -139,7 +139,7 @@ struct spl_fixed31_32 spl_fixpt_mul(struct spl_fixed31_32 arg1, struct spl_fixed tmp = (tmp >> FIXED31_32_BITS_PER_FRACTIONAL_PART) + (tmp >= (unsigned long long)spl_fixpt_half.value); - ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); + SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); res.value += tmp; @@ -163,17 +163,17 @@ struct spl_fixed31_32 spl_fixpt_sqr(struct spl_fixed31_32 arg) res.value = arg_int * arg_int; - ASSERT(res.value <= (long long)LONG_MAX); + SPL_ASSERT(res.value <= (long long)LONG_MAX); res.value <<= FIXED31_32_BITS_PER_FRACTIONAL_PART; tmp = arg_int * arg_fra; - ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); + SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); res.value += tmp; - ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); + SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); res.value += tmp; @@ -182,7 +182,7 @@ struct spl_fixed31_32 spl_fixpt_sqr(struct spl_fixed31_32 arg) tmp = (tmp >> FIXED31_32_BITS_PER_FRACTIONAL_PART) + (tmp >= (unsigned long long)spl_fixpt_half.value); - ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); + SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); res.value += tmp; @@ -196,7 +196,7 @@ struct spl_fixed31_32 spl_fixpt_recip(struct spl_fixed31_32 arg) * Good idea to use Newton's method */ - ASSERT(arg.value); + SPL_ASSERT(arg.value); return spl_fixpt_from_fraction( spl_fixpt_one.value, @@ -286,7 +286,7 @@ struct spl_fixed31_32 spl_fixpt_cos(struct spl_fixed31_32 arg) * * Calculated as Taylor series. */ -static struct spl_fixed31_32 fixed31_32_exp_from_taylor_series(struct spl_fixed31_32 arg) +static struct spl_fixed31_32 spl_fixed31_32_exp_from_taylor_series(struct spl_fixed31_32 arg) { unsigned int n = 9; @@ -295,7 +295,7 @@ static struct spl_fixed31_32 fixed31_32_exp_from_taylor_series(struct spl_fixed3 n + 1); /* TODO find correct res */ - ASSERT(spl_fixpt_lt(arg, spl_fixpt_one)); + SPL_ASSERT(spl_fixpt_lt(arg, spl_fixpt_one)); do res = spl_fixpt_add( @@ -337,22 +337,22 @@ struct spl_fixed31_32 spl_fixpt_exp(struct spl_fixed31_32 arg) spl_fixpt_ln2, m)); - ASSERT(m != 0); + SPL_ASSERT(m != 0); - ASSERT(spl_fixpt_lt( + SPL_ASSERT(spl_fixpt_lt( spl_fixpt_abs(r), spl_fixpt_one)); if (m > 0) return spl_fixpt_shl( - fixed31_32_exp_from_taylor_series(r), + spl_fixed31_32_exp_from_taylor_series(r), (unsigned char)m); else return spl_fixpt_div_int( - fixed31_32_exp_from_taylor_series(r), + spl_fixed31_32_exp_from_taylor_series(r), 1LL << -m); } else if (arg.value != 0) - return fixed31_32_exp_from_taylor_series(arg); + return spl_fixed31_32_exp_from_taylor_series(arg); else return spl_fixpt_one; } @@ -364,7 +364,7 @@ struct spl_fixed31_32 spl_fixpt_log(struct spl_fixed31_32 arg) struct spl_fixed31_32 error; - ASSERT(arg.value > 0); + SPL_ASSERT(arg.value > 0); /* TODO if arg is negative, return NaN */ /* TODO if arg is zero, return -INF */ @@ -396,7 +396,7 @@ struct spl_fixed31_32 spl_fixpt_log(struct spl_fixed31_32 arg) * part in 32 bits. It is used in hw programming (scaler) */ -static inline unsigned int ux_dy( +static inline unsigned int spl_ux_dy( long long value, unsigned int integer_bits, unsigned int fractional_bits) @@ -415,13 +415,13 @@ static inline unsigned int ux_dy( return result | fractional_part; } -static inline unsigned int clamp_ux_dy( +static inline unsigned int spl_clamp_ux_dy( long long value, unsigned int integer_bits, unsigned int fractional_bits, unsigned int min_clamp) { - unsigned int truncated_val = ux_dy(value, integer_bits, fractional_bits); + unsigned int truncated_val = spl_ux_dy(value, integer_bits, fractional_bits); if (value >= (1LL << (integer_bits + FIXED31_32_BITS_PER_FRACTIONAL_PART))) return (1 << (integer_bits + fractional_bits)) - 1; @@ -433,40 +433,40 @@ static inline unsigned int clamp_ux_dy( unsigned int spl_fixpt_u4d19(struct spl_fixed31_32 arg) { - return ux_dy(arg.value, 4, 19); + return spl_ux_dy(arg.value, 4, 19); } unsigned int spl_fixpt_u3d19(struct spl_fixed31_32 arg) { - return ux_dy(arg.value, 3, 19); + return spl_ux_dy(arg.value, 3, 19); } unsigned int spl_fixpt_u2d19(struct spl_fixed31_32 arg) { - return ux_dy(arg.value, 2, 19); + return spl_ux_dy(arg.value, 2, 19); } unsigned int spl_fixpt_u0d19(struct spl_fixed31_32 arg) { - return ux_dy(arg.value, 0, 19); + return spl_ux_dy(arg.value, 0, 19); } unsigned int spl_fixpt_clamp_u0d14(struct spl_fixed31_32 arg) { - return clamp_ux_dy(arg.value, 0, 14, 1); + return spl_clamp_ux_dy(arg.value, 0, 14, 1); } unsigned int spl_fixpt_clamp_u0d10(struct spl_fixed31_32 arg) { - return clamp_ux_dy(arg.value, 0, 10, 1); + return spl_clamp_ux_dy(arg.value, 0, 10, 1); } int spl_fixpt_s4d19(struct spl_fixed31_32 arg) { if (arg.value < 0) - return -(int)ux_dy(spl_fixpt_abs(arg).value, 4, 19); + return -(int)spl_ux_dy(spl_fixpt_abs(arg).value, 4, 19); else - return ux_dy(arg.value, 4, 19); + return spl_ux_dy(arg.value, 4, 19); } struct spl_fixed31_32 spl_fixpt_from_ux_dy(unsigned int value, diff --git a/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h b/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h index 8a045e2f8699a4..ed2647f9a09997 100644 --- a/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h +++ b/drivers/gpu/drm/amd/display/dc/spl/spl_fixpt31_32.h @@ -5,11 +5,8 @@ #ifndef __SPL_FIXED31_32_H__ #define __SPL_FIXED31_32_H__ -#include "os_types.h" +#include "spl_debug.h" #include "spl_os_types.h" // swap -#ifndef ASSERT -#define ASSERT(_bool) ((void *)0) -#endif #ifndef LLONG_MAX #define LLONG_MAX 9223372036854775807ll @@ -194,7 +191,7 @@ static inline struct spl_fixed31_32 spl_fixpt_clamp( */ static inline struct spl_fixed31_32 spl_fixpt_shl(struct spl_fixed31_32 arg, unsigned char shift) { - ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) || + SPL_ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) || ((arg.value < 0) && (arg.value >= ~(LLONG_MAX >> shift)))); arg.value = arg.value << shift; @@ -231,7 +228,7 @@ static inline struct spl_fixed31_32 spl_fixpt_add(struct spl_fixed31_32 arg1, st { struct spl_fixed31_32 res; - ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) || + SPL_ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) || ((arg1.value < 0) && (LLONG_MIN - arg1.value <= arg2.value))); res.value = arg1.value + arg2.value; @@ -256,7 +253,7 @@ static inline struct spl_fixed31_32 spl_fixpt_sub(struct spl_fixed31_32 arg1, st { struct spl_fixed31_32 res; - ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) || + SPL_ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) || ((arg2.value < 0) && (LLONG_MAX + arg2.value >= arg1.value))); res.value = arg1.value - arg2.value; @@ -448,7 +445,7 @@ static inline int spl_fixpt_round(struct spl_fixed31_32 arg) const long long summand = spl_fixpt_half.value; - ASSERT(LLONG_MAX - (long long)arg_value >= summand); + SPL_ASSERT(LLONG_MAX - (long long)arg_value >= summand); arg_value += summand; @@ -469,7 +466,7 @@ static inline int spl_fixpt_ceil(struct spl_fixed31_32 arg) const long long summand = spl_fixpt_one.value - spl_fixpt_epsilon.value; - ASSERT(LLONG_MAX - (long long)arg_value >= summand); + SPL_ASSERT(LLONG_MAX - (long long)arg_value >= summand); arg_value += summand; @@ -504,7 +501,7 @@ static inline struct spl_fixed31_32 spl_fixpt_truncate(struct spl_fixed31_32 arg bool negative = arg.value < 0; if (frac_bits >= FIXED31_32_BITS_PER_FRACTIONAL_PART) { - ASSERT(frac_bits == FIXED31_32_BITS_PER_FRACTIONAL_PART); + SPL_ASSERT(frac_bits == FIXED31_32_BITS_PER_FRACTIONAL_PART); return arg; } diff --git a/drivers/gpu/drm/amd/display/dc/spl/spl_os_types.h b/drivers/gpu/drm/amd/display/dc/spl/spl_os_types.h index 709706ed4f2c9e..2e6ba71960acf7 100644 --- a/drivers/gpu/drm/amd/display/dc/spl/spl_os_types.h +++ b/drivers/gpu/drm/amd/display/dc/spl/spl_os_types.h @@ -6,6 +6,8 @@ #ifndef _SPL_OS_TYPES_H_ #define _SPL_OS_TYPES_H_ +#include "spl_debug.h" + #include #include #include @@ -18,7 +20,6 @@ * general debug capabilities * */ -#define SPL_BREAK_TO_DEBUGGER() ASSERT(0) static inline uint64_t spl_div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder) { diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index fe5b6f7a3eb1ee..b353c4ceb60dce 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -301,6 +301,7 @@ struct dmub_srv_hw_params { bool disallow_phy_access; bool disable_sldo_opt; bool enable_non_transparent_setconfig; + bool lower_hbr3_phy_ssc; }; /** @@ -570,6 +571,14 @@ struct dmub_notification { }; }; +/* enum dmub_ips_mode - IPS mode identifier */ +enum dmub_ips_mode { + DMUB_IPS_MODE_IPS1_MAX = 0, + DMUB_IPS_MODE_IPS2, + DMUB_IPS_MODE_IPS1_RCG, + DMUB_IPS_MODE_IPS1_ONO2_ON +}; + /** * DMUB firmware version helper macro - useful for checking if the version * of a firmware to know if feature or functionality is supported or present. diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index ebcf68bfae2b32..b800a507d1e074 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -170,6 +170,11 @@ #pragma pack(push, 1) #define ABM_NUM_OF_ACE_SEGMENTS 5 +/** + * Debug FW state offset + */ +#define DMUB_DEBUG_FW_STATE_OFFSET 0x300 + union abm_flags { struct { /** @@ -490,6 +495,7 @@ struct dmub_feature_caps { uint8_t gecc_enable; uint8_t replay_supported; uint8_t replay_reserved[3]; + uint8_t abm_aux_backlight_support; }; struct dmub_visual_confirm_color { @@ -689,7 +695,8 @@ union dmub_fw_boot_options { uint32_t ips_disable: 3; /* options to disable ips support*/ uint32_t ips_sequential_ono: 1; /**< 1 to enable sequential ONO IPS sequence */ uint32_t disable_sldo_opt: 1; /**< 1 to disable SLDO optimizations */ - uint32_t reserved : 7; /**< reserved */ + uint32_t lower_hbr3_phy_ssc: 1; /**< 1 to lower hbr3 phy ssc to 0.125 percent */ + uint32_t reserved : 6; /**< reserved */ } bits; /**< boot bits */ uint32_t all; /**< 32-bit access to bits */ }; @@ -721,6 +728,7 @@ enum dmub_shared_state_feature_id { DMUB_SHARED_SHARE_FEATURE__INVALID = 0, DMUB_SHARED_SHARE_FEATURE__IPS_FW = 1, DMUB_SHARED_SHARE_FEATURE__IPS_DRIVER = 2, + DMUB_SHARED_SHARE_FEATURE__DEBUG_SETUP = 3, DMUB_SHARED_STATE_FEATURE__LAST, /* Total number of features. */ }; @@ -747,7 +755,8 @@ union dmub_shared_state_ips_driver_signals { uint32_t allow_ips1 : 1; /**< 1 is IPS1 is allowed */ uint32_t allow_ips2 : 1; /**< 1 is IPS1 is allowed */ uint32_t allow_z10 : 1; /**< 1 if Z10 is allowed */ - uint32_t reserved_bits : 28; /**< Reversed bits */ + uint32_t allow_idle: 1; /**< 1 if driver is allowing idle */ + uint32_t reserved_bits : 27; /**< Reversed bits */ } bits; uint32_t all; }; @@ -757,6 +766,14 @@ union dmub_shared_state_ips_driver_signals { */ #define DMUB_SHARED_STATE__IPS_FW_VERSION 1 +struct dmub_shared_state_debug_setup { + union { + struct { + uint32_t exclude_points[62]; + } profile_mode; + }; +}; + /** * struct dmub_shared_state_ips_fw - Firmware state for IPS. */ @@ -809,6 +826,7 @@ struct dmub_shared_state_feature_block { struct dmub_shared_state_feature_common common; /**< Generic data */ struct dmub_shared_state_ips_fw ips_fw; /**< IPS firmware state */ struct dmub_shared_state_ips_driver ips_driver; /**< IPS driver state */ + struct dmub_shared_state_debug_setup debug_setup; /**< Debug setup */ } data; /**< Shared state data. */ }; /* 256-bytes, fixed */ @@ -1050,12 +1068,111 @@ enum dmub_gpint_command { */ DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD3 = 119, + /** + * DESC: Set IPS residency measurement + * ARGS: 0 - Disable ips measurement + * 1 - Enable ips measurement + */ + DMUB_GPINT__IPS_RESIDENCY = 121, + /** * DESC: Enable measurements for various task duration * ARGS: 0 - Disable measurement * 1 - Enable measurement */ DMUB_GPINT__TRACE_DMUB_WAKE_ACTIVITY = 123, + + /** + * DESC: Gets IPS residency in microseconds + * ARGS: 0 - Return IPS1 residency + * 1 - Return IPS2 residency + * 2 - Return IPS1_RCG residency + * 3 - Return IPS1_ONO2_ON residency + * RETURN: Total residency in microseconds - lower 32 bits + */ + DMUB_GPINT__GET_IPS_RESIDENCY_DURATION_US_LO = 124, + + /** + * DESC: Gets IPS1 histogram counts + * ARGS: Bucket index + * RETURN: Total count for the bucket + */ + DMUB_GPINT__GET_IPS1_HISTOGRAM_COUNTER = 125, + + /** + * DESC: Gets IPS2 histogram counts + * ARGS: Bucket index + * RETURN: Total count for the bucket + */ + DMUB_GPINT__GET_IPS2_HISTOGRAM_COUNTER = 126, + + /** + * DESC: Gets IPS residency + * ARGS: 0 - Return IPS1 residency + * 1 - Return IPS2 residency + * 2 - Return IPS1_RCG residency + * 3 - Return IPS1_ONO2_ON residency + * RETURN: Total residency in milli-percent. + */ + DMUB_GPINT__GET_IPS_RESIDENCY_PERCENT = 127, + + /** + * DESC: Gets IPS1_RCG histogram counts + * ARGS: Bucket index + * RETURN: Total count for the bucket + */ + DMUB_GPINT__GET_IPS1_RCG_HISTOGRAM_COUNTER = 128, + + /** + * DESC: Gets IPS1_ONO2_ON histogram counts + * ARGS: Bucket index + * RETURN: Total count for the bucket + */ + DMUB_GPINT__GET_IPS1_ONO2_ON_HISTOGRAM_COUNTER = 129, + + /** + * DESC: Gets IPS entry counter during residency measurement + * ARGS: 0 - Return IPS1 entry counts + * 1 - Return IPS2 entry counts + * 2 - Return IPS1_RCG entry counts + * 3 - Return IPS2_ONO2_ON entry counts + * RETURN: Entry counter for selected IPS mode + */ + DMUB_GPINT__GET_IPS_RESIDENCY_ENTRY_COUNTER = 130, + + /** + * DESC: Gets IPS inactive residency in microseconds + * ARGS: 0 - Return IPS1_MAX residency + * 1 - Return IPS2 residency + * 2 - Return IPS1_RCG residency + * 3 - Return IPS1_ONO2_ON residency + * RETURN: Total inactive residency in microseconds - lower 32 bits + */ + DMUB_GPINT__GET_IPS_INACTIVE_RESIDENCY_DURATION_US_LO = 131, + + /** + * DESC: Gets IPS inactive residency in microseconds + * ARGS: 0 - Return IPS1_MAX residency + * 1 - Return IPS2 residency + * 2 - Return IPS1_RCG residency + * 3 - Return IPS1_ONO2_ON residency + * RETURN: Total inactive residency in microseconds - upper 32 bits + */ + DMUB_GPINT__GET_IPS_INACTIVE_RESIDENCY_DURATION_US_HI = 132, + + /** + * DESC: Gets IPS residency in microseconds + * ARGS: 0 - Return IPS1 residency + * 1 - Return IPS2 residency + * 2 - Return IPS1_RCG residency + * 3 - Return IPS1_ONO2_ON residency + * RETURN: Total residency in microseconds - upper 32 bits + */ + DMUB_GPINT__GET_IPS_RESIDENCY_DURATION_US_HI = 133, + /** + * DESC: Setup debug configs. + */ + DMUB_GPINT__SETUP_DEBUG_MODE = 136, }; /** @@ -1306,9 +1423,10 @@ enum dmub_out_cmd_type { /* DMUB_CMD__DPIA command sub-types. */ enum dmub_cmd_dpia_type { DMUB_CMD__DPIA_DIG1_DPIA_CONTROL = 0, - DMUB_CMD__DPIA_SET_CONFIG_ACCESS = 1, + DMUB_CMD__DPIA_SET_CONFIG_ACCESS = 1, // will be replaced by DPIA_SET_CONFIG_REQUEST DMUB_CMD__DPIA_MST_ALLOC_SLOTS = 2, DMUB_CMD__DPIA_SET_TPS_NOTIFICATION = 3, + DMUB_CMD__DPIA_SET_CONFIG_REQUEST = 4, }; /* DMUB_OUT_CMD__DPIA_NOTIFICATION command types. */ @@ -2097,7 +2215,7 @@ struct dmub_rb_cmd_dig1_dpia_control { }; /** - * SET_CONFIG Command Payload + * SET_CONFIG Command Payload (deprecated) */ struct set_config_cmd_payload { uint8_t msg_type; /* set config message type */ @@ -2105,7 +2223,7 @@ struct set_config_cmd_payload { }; /** - * Data passed from driver to FW in a DMUB_CMD__DPIA_SET_CONFIG_ACCESS command. + * Data passed from driver to FW in a DMUB_CMD__DPIA_SET_CONFIG_ACCESS command. (deprecated) */ struct dmub_cmd_set_config_control_data { struct set_config_cmd_payload cmd_pkt; @@ -2113,6 +2231,17 @@ struct dmub_cmd_set_config_control_data { uint8_t immed_status; /* Immediate status returned in case of error */ }; +/** + * SET_CONFIG Request Command Payload + */ +struct set_config_request_cmd_payload { + uint8_t instance; /* DPIA instance */ + uint8_t immed_status; /* Immediate status returned in case of error */ + uint8_t msg_type; /* set config message type */ + uint8_t reserved; + uint32_t msg_data; /* set config message data */ +}; + /** * DMUB command structure for SET_CONFIG command. */ @@ -2121,6 +2250,14 @@ struct dmub_rb_cmd_set_config_access { struct dmub_cmd_set_config_control_data set_config_control; /* set config data */ }; +/** + * DMUB command structure for SET_CONFIG request command. + */ +struct dmub_rb_cmd_set_config_request { + struct dmub_cmd_header header; /* header */ + struct set_config_request_cmd_payload payload; /* set config request payload */ +}; + /** * Data passed from driver to FW in a DMUB_CMD__DPIA_MST_ALLOC_SLOTS command. */ @@ -4289,6 +4426,24 @@ struct dmub_rb_cmd_abm_set_pipe { struct dmub_cmd_abm_set_pipe_data abm_set_pipe_data; }; +/** + * Type of backlight control method to be used by ABM module + */ +enum dmub_backlight_control_type { + /** + * PWM Backlight control + */ + DMU_BACKLIGHT_CONTROL_PWM = 0, + /** + * VESA Aux-based backlight control + */ + DMU_BACKLIGHT_CONTROL_VESA_AUX = 1, + /** + * AMD DPCD Aux-based backlight control + */ + DMU_BACKLIGHT_CONTROL_AMD_AUX = 2, +}; + /** * Data passed from driver to FW in a DMUB_CMD__ABM_SET_BACKLIGHT command. */ @@ -4315,10 +4470,43 @@ struct dmub_cmd_abm_set_backlight_data { */ uint8_t panel_mask; + /** + * AUX HW Instance. + */ + uint8_t aux_inst; + /** * Explicit padding to 4 byte boundary. */ - uint8_t pad[2]; + uint8_t pad[1]; + + /** + * Backlight control type. + * Value 0 is PWM backlight control. + * Value 1 is VAUX backlight control. + * Value 2 is AMD DPCD AUX backlight control. + */ + enum dmub_backlight_control_type backlight_control_type; + + /** + * Minimum luminance in nits. + */ + uint32_t min_luminance; + + /** + * Maximum luminance in nits. + */ + uint32_t max_luminance; + + /** + * Minimum backlight in pwm. + */ + uint32_t min_backlight_pwm; + + /** + * Maximum backlight in pwm. + */ + uint32_t max_backlight_pwm; }; /** @@ -5022,7 +5210,34 @@ struct dmub_rb_cmd_get_usbc_cable_id { enum dmub_cmd_secure_display_type { DMUB_CMD__SECURE_DISPLAY_TEST_CMD = 0, /* test command to only check if inbox message works */ DMUB_CMD__SECURE_DISPLAY_CRC_STOP_UPDATE, - DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY + DMUB_CMD__SECURE_DISPLAY_CRC_WIN_NOTIFY, + DMUB_CMD__SECURE_DISPLAY_MULTIPLE_CRC_STOP_UPDATE, + DMUB_CMD__SECURE_DISPLAY_MULTIPLE_CRC_WIN_NOTIFY +}; + +#define MAX_ROI_NUM 2 + +struct dmub_cmd_roi_info { + uint16_t x_start; + uint16_t x_end; + uint16_t y_start; + uint16_t y_end; + uint8_t otg_id; + uint8_t phy_id; +}; + +struct dmub_cmd_roi_window_ctl { + uint16_t x_start; + uint16_t x_end; + uint16_t y_start; + uint16_t y_end; + bool enable; +}; + +struct dmub_cmd_roi_ctl_info { + uint8_t otg_id; + uint8_t phy_id; + struct dmub_cmd_roi_window_ctl roi_ctl[MAX_ROI_NUM]; }; /** @@ -5033,14 +5248,8 @@ struct dmub_rb_cmd_secure_display { /** * Data passed from driver to dmub firmware. */ - struct dmub_cmd_roi_info { - uint16_t x_start; - uint16_t x_end; - uint16_t y_start; - uint16_t y_end; - uint8_t otg_id; - uint8_t phy_id; - } roi_info; + struct dmub_cmd_roi_info roi_info; + struct dmub_cmd_roi_ctl_info mul_roi_ctl; }; /** @@ -5318,7 +5527,11 @@ union dmub_rb_cmd { /** * Definition of a DMUB_CMD__DPIA_SET_CONFIG_ACCESS command. */ - struct dmub_rb_cmd_set_config_access set_config_access; + struct dmub_rb_cmd_set_config_access set_config_access; // (deprecated) + /** + * Definition of a DMUB_CMD__DPIA_SET_CONFIG_ACCESS command. + */ + struct dmub_rb_cmd_set_config_request set_config_request; /** * Definition of a DMUB_CMD__DPIA_MST_ALLOC_SLOTS command. */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c index 2ccad79053c586..e5e77bd3c31ea1 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c @@ -426,6 +426,7 @@ void dmub_dcn35_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmu boot_options.bits.ips_sequential_ono = params->ips_sequential_ono; boot_options.bits.disable_sldo_opt = params->disable_sldo_opt; boot_options.bits.enable_non_transparent_setconfig = params->enable_non_transparent_setconfig; + boot_options.bits.lower_hbr3_phy_ssc = params->lower_hbr3_phy_ssc; REG_WRITE(DMCUB_SCRATCH14, boot_options.all); } @@ -463,7 +464,7 @@ uint32_t dmub_dcn35_get_current_time(struct dmub_srv *dmub) void dmub_dcn35_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data) { - uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset; + uint32_t is_dmub_enabled, is_soft_reset; uint32_t is_traceport_enabled, is_cw6_enabled; if (!dmub || !diag_data) @@ -513,9 +514,6 @@ void dmub_dcn35_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnosti REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); diag_data->is_dmcub_soft_reset = is_soft_reset; - REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); - diag_data->is_dmcub_secure_reset = is_sec_reset; - REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); diag_data->is_traceport_en = is_traceport_enabled; diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index db16066bc8939b..a3f3ff5d49ace0 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -497,6 +497,7 @@ enum dmub_status const struct dmub_fw_meta_info *fw_info; uint32_t fw_state_size = DMUB_FW_STATE_SIZE; uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE; + uint32_t shared_state_size = DMUB_FW_HEADER_SHARED_STATE_SIZE; uint32_t window_sizes[DMUB_WINDOW_TOTAL] = { 0 }; if (!dmub->sw_init) @@ -514,6 +515,7 @@ enum dmub_status fw_state_size = fw_info->fw_region_size; trace_buffer_size = fw_info->trace_buffer_size; + shared_state_size = fw_info->shared_state_size; /** * If DM didn't fill in a version, then fill it in based on @@ -534,7 +536,7 @@ enum dmub_status window_sizes[DMUB_WINDOW_5_TRACEBUFF] = trace_buffer_size; window_sizes[DMUB_WINDOW_6_FW_STATE] = fw_state_size; window_sizes[DMUB_WINDOW_7_SCRATCH_MEM] = DMUB_SCRATCH_MEM_SIZE; - window_sizes[DMUB_WINDOW_SHARED_STATE] = DMUB_FW_HEADER_SHARED_STATE_SIZE; + window_sizes[DMUB_WINDOW_SHARED_STATE] = max(DMUB_FW_HEADER_SHARED_STATE_SIZE, shared_state_size); out->fb_size = dmub_srv_calc_regions_for_memory_type(params, out, window_sizes, DMUB_WINDOW_MEMORY_TYPE_FB); diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h index aee5170f5fb231..de8f3cfed6c84f 100644 --- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h +++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h @@ -164,18 +164,19 @@ enum dpcd_psr_sink_states { PSR_SINK_STATE_SINK_INTERNAL_ERROR = 7, }; -#define DP_SOURCE_SEQUENCE 0x30c -#define DP_SOURCE_TABLE_REVISION 0x310 -#define DP_SOURCE_PAYLOAD_SIZE 0x311 -#define DP_SOURCE_SINK_CAP 0x317 -#define DP_SOURCE_BACKLIGHT_LEVEL 0x320 -#define DP_SOURCE_BACKLIGHT_CURRENT_PEAK 0x326 -#define DP_SOURCE_BACKLIGHT_CONTROL 0x32E -#define DP_SOURCE_BACKLIGHT_ENABLE 0x32F -#define DP_SOURCE_MINIMUM_HBLANK_SUPPORTED 0x340 +#define DP_SOURCE_SEQUENCE 0x30C +#define DP_SOURCE_TABLE_REVISION 0x310 +#define DP_SOURCE_PAYLOAD_SIZE 0x311 +#define DP_SOURCE_SINK_CAP 0x317 +#define DP_SOURCE_BACKLIGHT_LEVEL 0x320 +#define DP_SOURCE_BACKLIGHT_CURRENT_PEAK 0x326 +#define DP_SOURCE_BACKLIGHT_CONTROL 0x32E +#define DP_SOURCE_BACKLIGHT_ENABLE 0x32F +#define DP_SOURCE_MINIMUM_HBLANK_SUPPORTED 0x340 #define DP_SINK_PR_REPLAY_STATUS 0x378 #define DP_SINK_PR_PIXEL_DEVIATION_PER_LINE 0x379 #define DP_SINK_PR_MAX_NUMBER_OF_DEVIATION_LINE 0x37A +#define DP_SINK_EMISSION_RATE 0x37E /* Remove once drm_dp_helper.h is updated upstream */ #ifndef DP_TOTAL_LTTPR_CNT diff --git a/drivers/gpu/drm/amd/display/include/logger_interface.h b/drivers/gpu/drm/amd/display/include/logger_interface.h index 02c23b04d34be3..058f882d5bddc9 100644 --- a/drivers/gpu/drm/amd/display/include/logger_interface.h +++ b/drivers/gpu/drm/amd/display/include/logger_interface.h @@ -52,10 +52,6 @@ void update_surface_trace( void post_surface_trace(struct dc *dc); -void context_timing_trace( - struct dc *dc, - struct resource_context *res_ctx); - void context_clock_trace( struct dc *dc, struct dc_state *context); diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index a48d564d1660c3..4d68c1c6e21006 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -61,11 +61,13 @@ #define DC_LOG_ALL_TF_CHANNELS(...) pr_debug("[GAMMA]:"__VA_ARGS__) #define DC_LOG_DSC(...) drm_dbg_dp((DC_LOGGER)->dev, __VA_ARGS__) #define DC_LOG_SMU(...) pr_debug("[SMU_MSG]:"__VA_ARGS__) -#define DC_LOG_MALL(...) pr_debug("[MALL]:"__VA_ARGS__) #define DC_LOG_DWB(...) drm_dbg((DC_LOGGER)->dev, __VA_ARGS__) #define DC_LOG_DP2(...) drm_dbg_dp((DC_LOGGER)->dev, __VA_ARGS__) #define DC_LOG_AUTO_DPM_TEST(...) pr_debug("[AutoDPMTest]: "__VA_ARGS__) #define DC_LOG_IPS(...) pr_debug("[IPS]: "__VA_ARGS__) +#define DC_LOG_MALL(...) pr_debug("[MALL]:"__VA_ARGS__) +#define DC_LOG_REGISTER_READ(...) pr_debug("[REGISTER_READ]: "__VA_ARGS__) +#define DC_LOG_REGISTER_WRITE(...) pr_debug("[REGISTER_WRITE]: "__VA_ARGS__) struct dc_log_buffer_ctx { char *buf; diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 3699e633801d2e..a71df052cf2523 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1399,71 +1399,6 @@ static void scale_gamma_dx(struct pwl_float_data *pwl_rgb, pwl_rgb[i-1].b, 2), pwl_rgb[i-2].b); } -/* todo: all these scale_gamma functions are inherently the same but - * take different structures as params or different format for ramp - * values. We could probably implement it in a more generic fashion - */ -static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb, - const struct regamma_ramp *ramp, - struct dividers dividers) -{ - unsigned short max_driver = 0xFFFF; - unsigned short max_os = 0xFF00; - unsigned short scaler = max_os; - uint32_t i; - struct pwl_float_data *rgb = pwl_rgb; - struct pwl_float_data *rgb_last = rgb + GAMMA_RGB_256_ENTRIES - 1; - - i = 0; - do { - if (ramp->gamma[i] > max_os || - ramp->gamma[i + 256] > max_os || - ramp->gamma[i + 512] > max_os) { - scaler = max_driver; - break; - } - i++; - } while (i != GAMMA_RGB_256_ENTRIES); - - i = 0; - do { - rgb->r = dc_fixpt_from_fraction( - ramp->gamma[i], scaler); - rgb->g = dc_fixpt_from_fraction( - ramp->gamma[i + 256], scaler); - rgb->b = dc_fixpt_from_fraction( - ramp->gamma[i + 512], scaler); - - ++rgb; - ++i; - } while (i != GAMMA_RGB_256_ENTRIES); - - rgb->r = dc_fixpt_mul(rgb_last->r, - dividers.divider1); - rgb->g = dc_fixpt_mul(rgb_last->g, - dividers.divider1); - rgb->b = dc_fixpt_mul(rgb_last->b, - dividers.divider1); - - ++rgb; - - rgb->r = dc_fixpt_mul(rgb_last->r, - dividers.divider2); - rgb->g = dc_fixpt_mul(rgb_last->g, - dividers.divider2); - rgb->b = dc_fixpt_mul(rgb_last->b, - dividers.divider2); - - ++rgb; - - rgb->r = dc_fixpt_mul(rgb_last->r, - dividers.divider3); - rgb->g = dc_fixpt_mul(rgb_last->g, - dividers.divider3); - rgb->b = dc_fixpt_mul(rgb_last->b, - dividers.divider3); -} - /* * RS3+ color transform DDI - 1D LUT adjustment is composed with regamma here * Input is evenly distributed in the output color space as specified in @@ -1663,106 +1598,6 @@ static bool calculate_interpolated_hardware_curve( return true; } -/* The "old" interpolation uses a complicated scheme to build an array of - * coefficients while also using an array of 0-255 normalized to 0-1 - * Then there's another loop using both of the above + new scaled user ramp - * and we concatenate them. It also searches for points of interpolation and - * uses enums for positions. - * - * This function uses a different approach: - * user ramp is always applied on X with 0/255, 1/255, 2/255, ..., 255/255 - * To find index for hwX , we notice the following: - * i/255 <= hwX < (i+1)/255 <=> i <= 255*hwX < i+1 - * See apply_lut_1d which is the same principle, but on 4K entry 1D LUT - * - * Once the index is known, combined Y is simply: - * user_ramp(index) + (hwX-index/255)*(user_ramp(index+1) - user_ramp(index) - * - * We should switch to this method in all cases, it's simpler and faster - * ToDo one day - for now this only applies to ADL regamma to avoid regression - * for regular use cases (sRGB and PQ) - */ -static void interpolate_user_regamma(uint32_t hw_points_num, - struct pwl_float_data *rgb_user, - bool apply_degamma, - struct dc_transfer_func_distributed_points *tf_pts) -{ - uint32_t i; - uint32_t color = 0; - int32_t index; - int32_t index_next; - struct fixed31_32 *tf_point; - struct fixed31_32 hw_x; - struct fixed31_32 norm_factor = - dc_fixpt_from_int(255); - struct fixed31_32 norm_x; - struct fixed31_32 index_f; - struct fixed31_32 lut1; - struct fixed31_32 lut2; - struct fixed31_32 delta_lut; - struct fixed31_32 delta_index; - const struct fixed31_32 one = dc_fixpt_from_int(1); - - i = 0; - /* fixed_pt library has problems handling too small values */ - while (i != 32) { - tf_pts->red[i] = dc_fixpt_zero; - tf_pts->green[i] = dc_fixpt_zero; - tf_pts->blue[i] = dc_fixpt_zero; - ++i; - } - while (i <= hw_points_num + 1) { - for (color = 0; color < 3; color++) { - if (color == 0) - tf_point = &tf_pts->red[i]; - else if (color == 1) - tf_point = &tf_pts->green[i]; - else - tf_point = &tf_pts->blue[i]; - - if (apply_degamma) { - if (color == 0) - hw_x = coordinates_x[i].regamma_y_red; - else if (color == 1) - hw_x = coordinates_x[i].regamma_y_green; - else - hw_x = coordinates_x[i].regamma_y_blue; - } else - hw_x = coordinates_x[i].x; - - if (dc_fixpt_le(one, hw_x)) - hw_x = one; - - norm_x = dc_fixpt_mul(norm_factor, hw_x); - index = dc_fixpt_floor(norm_x); - if (index < 0 || index > 255) - continue; - - index_f = dc_fixpt_from_int(index); - index_next = (index == 255) ? index : index + 1; - - if (color == 0) { - lut1 = rgb_user[index].r; - lut2 = rgb_user[index_next].r; - } else if (color == 1) { - lut1 = rgb_user[index].g; - lut2 = rgb_user[index_next].g; - } else { - lut1 = rgb_user[index].b; - lut2 = rgb_user[index_next].b; - } - - // we have everything now, so interpolate - delta_lut = dc_fixpt_sub(lut2, lut1); - delta_index = dc_fixpt_sub(norm_x, index_f); - - *tf_point = dc_fixpt_add(lut1, - dc_fixpt_mul(delta_index, delta_lut)); - } - ++i; - } -} - static void build_new_custom_resulted_curve( uint32_t hw_points_num, struct dc_transfer_func_distributed_points *tf_pts) @@ -1784,29 +1619,6 @@ static void build_new_custom_resulted_curve( } } -static void apply_degamma_for_user_regamma(struct pwl_float_data_ex *rgb_regamma, - uint32_t hw_points_num, struct calculate_buffer *cal_buffer) -{ - uint32_t i; - - struct gamma_coefficients coeff; - struct pwl_float_data_ex *rgb = rgb_regamma; - const struct hw_x_point *coord_x = coordinates_x; - - build_coefficients(&coeff, TRANSFER_FUNCTION_SRGB); - - i = 0; - while (i != hw_points_num + 1) { - rgb->r = translate_from_linear_space_ex( - coord_x->x, &coeff, 0, cal_buffer); - rgb->g = rgb->r; - rgb->b = rgb->r; - ++coord_x; - ++rgb; - ++i; - } -} - static bool map_regamma_hw_to_x_user( const struct dc_gamma *ramp, struct pixel_gamma_point *coeff128, @@ -1855,125 +1667,6 @@ static bool map_regamma_hw_to_x_user( #define _EXTRA_POINTS 3 -bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, - const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer, - const struct dc_gamma *ramp) -{ - struct gamma_coefficients coeff; - const struct hw_x_point *coord_x = coordinates_x; - uint32_t i = 0; - - do { - coeff.a0[i] = dc_fixpt_from_fraction( - regamma->coeff.A0[i], 10000000); - coeff.a1[i] = dc_fixpt_from_fraction( - regamma->coeff.A1[i], 1000); - coeff.a2[i] = dc_fixpt_from_fraction( - regamma->coeff.A2[i], 1000); - coeff.a3[i] = dc_fixpt_from_fraction( - regamma->coeff.A3[i], 1000); - coeff.user_gamma[i] = dc_fixpt_from_fraction( - regamma->coeff.gamma[i], 1000); - - ++i; - } while (i != 3); - - i = 0; - /* fixed_pt library has problems handling too small values */ - while (i != 32) { - output_tf->tf_pts.red[i] = dc_fixpt_zero; - output_tf->tf_pts.green[i] = dc_fixpt_zero; - output_tf->tf_pts.blue[i] = dc_fixpt_zero; - ++coord_x; - ++i; - } - while (i != MAX_HW_POINTS + 1) { - output_tf->tf_pts.red[i] = translate_from_linear_space_ex( - coord_x->x, &coeff, 0, cal_buffer); - output_tf->tf_pts.green[i] = translate_from_linear_space_ex( - coord_x->x, &coeff, 1, cal_buffer); - output_tf->tf_pts.blue[i] = translate_from_linear_space_ex( - coord_x->x, &coeff, 2, cal_buffer); - ++coord_x; - ++i; - } - - if (ramp && ramp->type == GAMMA_CS_TFM_1D) - apply_lut_1d(ramp, MAX_HW_POINTS, &output_tf->tf_pts); - - // this function just clamps output to 0-1 - build_new_custom_resulted_curve(MAX_HW_POINTS, &output_tf->tf_pts); - output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - - return true; -} - -bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, - const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer, - const struct dc_gamma *ramp) -{ - struct dc_transfer_func_distributed_points *tf_pts = &output_tf->tf_pts; - struct dividers dividers; - - struct pwl_float_data *rgb_user = NULL; - struct pwl_float_data_ex *rgb_regamma = NULL; - bool ret = false; - - if (regamma == NULL) - return false; - - output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - - rgb_user = kcalloc(GAMMA_RGB_256_ENTRIES + _EXTRA_POINTS, - sizeof(*rgb_user), - GFP_KERNEL); - if (!rgb_user) - goto rgb_user_alloc_fail; - - rgb_regamma = kcalloc(MAX_HW_POINTS + _EXTRA_POINTS, - sizeof(*rgb_regamma), - GFP_KERNEL); - if (!rgb_regamma) - goto rgb_regamma_alloc_fail; - - dividers.divider1 = dc_fixpt_from_fraction(3, 2); - dividers.divider2 = dc_fixpt_from_int(2); - dividers.divider3 = dc_fixpt_from_fraction(5, 2); - - scale_user_regamma_ramp(rgb_user, ®amma->ramp, dividers); - - if (regamma->flags.bits.applyDegamma == 1) { - apply_degamma_for_user_regamma(rgb_regamma, MAX_HW_POINTS, cal_buffer); - copy_rgb_regamma_to_coordinates_x(coordinates_x, - MAX_HW_POINTS, rgb_regamma); - } - - interpolate_user_regamma(MAX_HW_POINTS, rgb_user, - regamma->flags.bits.applyDegamma, tf_pts); - - // no custom HDR curves! - tf_pts->end_exponent = 0; - tf_pts->x_point_at_y1_red = 1; - tf_pts->x_point_at_y1_green = 1; - tf_pts->x_point_at_y1_blue = 1; - - if (ramp && ramp->type == GAMMA_CS_TFM_1D) - apply_lut_1d(ramp, MAX_HW_POINTS, &output_tf->tf_pts); - - // this function just clamps output to 0-1 - build_new_custom_resulted_curve(MAX_HW_POINTS, tf_pts); - - ret = true; - - kfree(rgb_regamma); -rgb_regamma_alloc_fail: - kfree(rgb_user); -rgb_user_alloc_fail: - return ret; -} - bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps, struct dc_transfer_func *input_tf, const struct dc_gamma *ramp, bool map_user_ramp) diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h index ee5c466613de7b..97e55278940e23 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h @@ -115,15 +115,4 @@ bool mod_color_calculate_degamma_params(struct dc_color_caps *dc_caps, struct dc_transfer_func *output_tf, const struct dc_gamma *ramp, bool mapUserRamp); -bool calculate_user_regamma_coeff(struct dc_transfer_func *output_tf, - const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer, - const struct dc_gamma *ramp); - -bool calculate_user_regamma_ramp(struct dc_transfer_func *output_tf, - const struct regamma_lut *regamma, - struct calculate_buffer *cal_buffer, - const struct dc_gamma *ramp); - - #endif /* COLOR_MOD_COLOR_GAMMA_H_ */ diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index bbd259cea4f4f6..2b3964529539f0 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -48,6 +48,7 @@ #define VSYNCS_BETWEEN_FLIP_THRESHOLD 2 #define FREESYNC_CONSEC_FLIP_AFTER_VSYNC 5 #define FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US 500 +#define MICRO_HZ_TO_HZ(x) (x / 1000000) struct core_freesync { struct mod_freesync public; @@ -121,6 +122,17 @@ static unsigned int calc_duration_in_us_from_v_total( return duration_in_us; } +static unsigned int calc_max_hardware_v_total(const struct dc_stream_state *stream) +{ + unsigned int max_hw_v_total = stream->ctx->dc->caps.max_v_total; + + if (stream->ctx->dc->caps.vtotal_limited_by_fp2) { + max_hw_v_total -= stream->timing.v_front_porch + 1; + } + + return max_hw_v_total; +} + unsigned int mod_freesync_calc_v_total_from_refresh( const struct dc_stream_state *stream, unsigned int refresh_in_uhz) @@ -128,13 +140,26 @@ unsigned int mod_freesync_calc_v_total_from_refresh( unsigned int v_total; unsigned int frame_duration_in_ns; + if (refresh_in_uhz == 0) + return stream->timing.v_total; + frame_duration_in_ns = ((unsigned int)(div64_u64((1000000000ULL * 1000000), refresh_in_uhz))); - v_total = div64_u64(div64_u64(((unsigned long long)( - frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), - stream->timing.h_total) + 500000, 1000000); + if (MICRO_HZ_TO_HZ(refresh_in_uhz) <= stream->timing.min_refresh_in_uhz) { + /* When the target refresh rate is the minimum panel refresh rate, + * round down the vtotal value to avoid stretching vblank over + * panel's vtotal boundary. + */ + v_total = div64_u64(div64_u64(((unsigned long long)( + frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), + stream->timing.h_total), 1000000); + } else { + v_total = div64_u64(div64_u64(((unsigned long long)( + frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), + stream->timing.h_total) + 500000, 1000000); + } /* v_total cannot be less than nominal */ if (v_total < stream->timing.v_total) { @@ -1002,7 +1027,7 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, if (stream->ctx->dc->caps.max_v_total != 0 && stream->timing.h_total != 0) { min_hardware_refresh_in_uhz = div64_u64((stream->timing.pix_clk_100hz * 100000000ULL), - (stream->timing.h_total * (long long)stream->ctx->dc->caps.max_v_total)); + (stream->timing.h_total * (long long)calc_max_hardware_v_total(stream))); } /* Limit minimum refresh rate to what can be supported by hardware */ min_refresh_in_uhz = min_hardware_refresh_in_uhz > in_config->min_refresh_in_uhz ? diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c index c996365e84b015..1d41dd58f6bce1 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c @@ -27,6 +27,11 @@ #include "hdcp.h" +static inline uint16_t get_hdmi_rxstatus_msg_size(const uint8_t rxstatus[2]) +{ + return HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(rxstatus[1]) << 8 | rxstatus[0]; +} + static inline enum mod_hdcp_status check_receiver_id_list_ready(struct mod_hdcp *hdcp) { uint8_t is_ready = 0; @@ -35,8 +40,7 @@ static inline enum mod_hdcp_status check_receiver_id_list_ready(struct mod_hdcp is_ready = HDCP_2_2_DP_RXSTATUS_READY(hdcp->auth.msg.hdcp2.rxstatus_dp) ? 1 : 0; else is_ready = (HDCP_2_2_HDMI_RXSTATUS_READY(hdcp->auth.msg.hdcp2.rxstatus[1]) && - (HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | - hdcp->auth.msg.hdcp2.rxstatus[0])) ? 1 : 0; + get_hdmi_rxstatus_msg_size(hdcp->auth.msg.hdcp2.rxstatus) != 0) ? 1 : 0; return is_ready ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_RX_ID_LIST_NOT_READY; } @@ -84,15 +88,13 @@ static inline enum mod_hdcp_status check_link_integrity_failure_dp( static enum mod_hdcp_status check_ake_cert_available(struct mod_hdcp *hdcp) { enum mod_hdcp_status status; - uint16_t size; if (is_dp_hdcp(hdcp)) { status = MOD_HDCP_STATUS_SUCCESS; } else { status = mod_hdcp_read_rxstatus(hdcp); if (status == MOD_HDCP_STATUS_SUCCESS) { - size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | - hdcp->auth.msg.hdcp2.rxstatus[0]; + const uint16_t size = get_hdmi_rxstatus_msg_size(hdcp->auth.msg.hdcp2.rxstatus); status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_cert)) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_AKE_CERT_PENDING; @@ -104,7 +106,6 @@ static enum mod_hdcp_status check_ake_cert_available(struct mod_hdcp *hdcp) static enum mod_hdcp_status check_h_prime_available(struct mod_hdcp *hdcp) { enum mod_hdcp_status status; - uint8_t size; status = mod_hdcp_read_rxstatus(hdcp); if (status != MOD_HDCP_STATUS_SUCCESS) @@ -115,8 +116,7 @@ static enum mod_hdcp_status check_h_prime_available(struct mod_hdcp *hdcp) MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING; } else { - size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | - hdcp->auth.msg.hdcp2.rxstatus[0]; + const uint16_t size = get_hdmi_rxstatus_msg_size(hdcp->auth.msg.hdcp2.rxstatus); status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_h_prime)) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_H_PRIME_PENDING; @@ -128,7 +128,6 @@ static enum mod_hdcp_status check_h_prime_available(struct mod_hdcp *hdcp) static enum mod_hdcp_status check_pairing_info_available(struct mod_hdcp *hdcp) { enum mod_hdcp_status status; - uint8_t size; status = mod_hdcp_read_rxstatus(hdcp); if (status != MOD_HDCP_STATUS_SUCCESS) @@ -139,8 +138,7 @@ static enum mod_hdcp_status check_pairing_info_available(struct mod_hdcp *hdcp) MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING; } else { - size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | - hdcp->auth.msg.hdcp2.rxstatus[0]; + const uint16_t size = get_hdmi_rxstatus_msg_size(hdcp->auth.msg.hdcp2.rxstatus); status = (size == sizeof(hdcp->auth.msg.hdcp2.ake_pairing_info)) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_PAIRING_INFO_PENDING; @@ -152,7 +150,6 @@ static enum mod_hdcp_status check_pairing_info_available(struct mod_hdcp *hdcp) static enum mod_hdcp_status poll_l_prime_available(struct mod_hdcp *hdcp) { enum mod_hdcp_status status = MOD_HDCP_STATUS_FAILURE; - uint8_t size; uint16_t max_wait = 20; // units of ms uint16_t num_polls = 5; uint16_t wait_time = max_wait / num_polls; @@ -167,8 +164,7 @@ static enum mod_hdcp_status poll_l_prime_available(struct mod_hdcp *hdcp) if (status != MOD_HDCP_STATUS_SUCCESS) break; - size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | - hdcp->auth.msg.hdcp2.rxstatus[0]; + const uint16_t size = get_hdmi_rxstatus_msg_size(hdcp->auth.msg.hdcp2.rxstatus); status = (size == sizeof(hdcp->auth.msg.hdcp2.lc_l_prime)) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_L_PRIME_PENDING; @@ -181,7 +177,6 @@ static enum mod_hdcp_status poll_l_prime_available(struct mod_hdcp *hdcp) static enum mod_hdcp_status check_stream_ready_available(struct mod_hdcp *hdcp) { enum mod_hdcp_status status; - uint8_t size; if (is_dp_hdcp(hdcp)) { status = MOD_HDCP_STATUS_INVALID_OPERATION; @@ -189,8 +184,7 @@ static enum mod_hdcp_status check_stream_ready_available(struct mod_hdcp *hdcp) status = mod_hdcp_read_rxstatus(hdcp); if (status != MOD_HDCP_STATUS_SUCCESS) goto out; - size = HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | - hdcp->auth.msg.hdcp2.rxstatus[0]; + const uint16_t size = get_hdmi_rxstatus_msg_size(hdcp->auth.msg.hdcp2.rxstatus); status = (size == sizeof(hdcp->auth.msg.hdcp2.repeater_auth_stream_ready)) ? MOD_HDCP_STATUS_SUCCESS : MOD_HDCP_STATUS_HDCP2_STREAM_READY_PENDING; @@ -249,8 +243,7 @@ static uint8_t process_rxstatus(struct mod_hdcp *hdcp, sizeof(hdcp->auth.msg.hdcp2.rx_id_list); else hdcp->auth.msg.hdcp2.rx_id_list_size = - HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(hdcp->auth.msg.hdcp2.rxstatus[1]) << 8 | - hdcp->auth.msg.hdcp2.rxstatus[0]; + get_hdmi_rxstatus_msg_size(hdcp->auth.msg.hdcp2.rxstatus); } out: return (*status == MOD_HDCP_STATUS_SUCCESS); diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 3f91926a50e99b..7eefcb0f50703f 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -28,6 +28,8 @@ #define AMD_MAX_USEC_TIMEOUT 1000000 /* 1000 ms */ +struct amdgpu_ip_block; + /* * Chip flags @@ -337,6 +339,11 @@ enum DC_DEBUG_MASK { * @DC_FORCE_IPS_ENABLE: If set, force enable all IPS, all the time. */ DC_FORCE_IPS_ENABLE = 0x4000, + /** + * @DC_DISABLE_ACPI_EDID: If set, don't attempt to fetch EDID for + * eDP display from ACPI _DDC method. + */ + DC_DISABLE_ACPI_EDID = 0x8000, }; enum amd_dpm_forced_level; @@ -377,30 +384,30 @@ enum amd_dpm_forced_level; */ struct amd_ip_funcs { char *name; - int (*early_init)(void *handle); - int (*late_init)(void *handle); - int (*sw_init)(void *handle); - int (*sw_fini)(void *handle); - int (*early_fini)(void *handle); - int (*hw_init)(void *handle); - int (*hw_fini)(void *handle); - void (*late_fini)(void *handle); - int (*prepare_suspend)(void *handle); - int (*suspend)(void *handle); - int (*resume)(void *handle); + int (*early_init)(struct amdgpu_ip_block *ip_block); + int (*late_init)(struct amdgpu_ip_block *ip_block); + int (*sw_init)(struct amdgpu_ip_block *ip_block); + int (*sw_fini)(struct amdgpu_ip_block *ip_block); + int (*early_fini)(struct amdgpu_ip_block *ip_block); + int (*hw_init)(struct amdgpu_ip_block *ip_block); + int (*hw_fini)(struct amdgpu_ip_block *ip_block); + void (*late_fini)(struct amdgpu_ip_block *ip_block); + int (*prepare_suspend)(struct amdgpu_ip_block *ip_block); + int (*suspend)(struct amdgpu_ip_block *ip_block); + int (*resume)(struct amdgpu_ip_block *ip_block); bool (*is_idle)(void *handle); - int (*wait_for_idle)(void *handle); - bool (*check_soft_reset)(void *handle); - int (*pre_soft_reset)(void *handle); - int (*soft_reset)(void *handle); - int (*post_soft_reset)(void *handle); + int (*wait_for_idle)(struct amdgpu_ip_block *ip_block); + bool (*check_soft_reset)(struct amdgpu_ip_block *ip_block); + int (*pre_soft_reset)(struct amdgpu_ip_block *ip_block); + int (*soft_reset)(struct amdgpu_ip_block *ip_block); + int (*post_soft_reset)(struct amdgpu_ip_block *ip_block); int (*set_clockgating_state)(void *handle, enum amd_clockgating_state state); int (*set_powergating_state)(void *handle, enum amd_powergating_state state); void (*get_clockgating_state)(void *handle, u64 *flags); - void (*dump_ip_state)(void *handle); - void (*print_ip_state)(void *handle, struct drm_printer *p); + void (*dump_ip_state)(struct amdgpu_ip_block *ip_block); + void (*print_ip_state)(struct amdgpu_ip_block *ip_block, struct drm_printer *p); }; diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h index f42a276499cd1c..5d9d5fea6e06b5 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_4_1_0_sh_mask.h @@ -6199,10 +6199,12 @@ #define DCHUBBUB_CTRL_STATUS__ROB_UNDERFLOW_STATUS__SHIFT 0x1 #define DCHUBBUB_CTRL_STATUS__ROB_OVERFLOW_STATUS__SHIFT 0x2 #define DCHUBBUB_CTRL_STATUS__ROB_OVERFLOW_CLEAR__SHIFT 0x3 +#define DCHUBBUB_CTRL_STATUS__DCHUBBUB_HW_DEBUG__SHIFT 0x4 #define DCHUBBUB_CTRL_STATUS__CSTATE_SWATH_CHK_GOOD_MODE__SHIFT 0x1f #define DCHUBBUB_CTRL_STATUS__ROB_UNDERFLOW_STATUS_MASK 0x00000002L #define DCHUBBUB_CTRL_STATUS__ROB_OVERFLOW_STATUS_MASK 0x00000004L #define DCHUBBUB_CTRL_STATUS__ROB_OVERFLOW_CLEAR_MASK 0x00000008L +#define DCHUBBUB_CTRL_STATUS__DCHUBBUB_HW_DEBUG_MASK 0x3FFFFFF0L #define DCHUBBUB_CTRL_STATUS__CSTATE_SWATH_CHK_GOOD_MODE_MASK 0x80000000L //DCHUBBUB_TIMEOUT_DETECTION_CTRL1 #define DCHUBBUB_TIMEOUT_DETECTION_CTRL1__DCHUBBUB_TIMEOUT_ERROR_STATUS__SHIFT 0x0 diff --git a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_offset.h index 2c3ce243861a7e..380e44230bdad0 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/mmhub/mmhub_1_0_offset.h @@ -1232,6 +1232,29 @@ #define mmMC_VM_MX_L1_PERFCOUNTER_HI 0x059d #define mmMC_VM_MX_L1_PERFCOUNTER_HI_BASE_IDX 0 +// Stand Alone Walker Registers +#define VMC_TAP_PDE_REQUEST_SNOOP_OFFSET 8 +#define VMC_TAP_PTE_REQUEST_SNOOP_OFFSET 11 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32 0x0606 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32_BASE_IDX 0 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32 0x0607 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32_BASE_IDX 0 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_START_ADDR_LO32 0x0608 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_START_ADDR_LO32_BASE_IDX 0 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_START_ADDR_HI32 0x0609 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_START_ADDR_HI32_BASE_IDX 0 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_END_ADDR_LO32 0x060a +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_END_ADDR_LO32_BASE_IDX 0 +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_END_ADDR_HI32 0x060b +#define mmVM_L2_SAW_CONTEXT0_PAGE_TABLE_END_ADDR_HI32_BASE_IDX 0 +#define mmVM_L2_SAW_CONTEXT0_CNTL 0x0604 +#define mmVM_L2_SAW_CONTEXT0_CNTL_BASE_IDX 0 +#define CONTEXT0_CNTL_ENABLE_OFFSET 0 +#define CONTEXT0_CNTL_PAGE_TABLE_DEPTH_OFFSET 1 +#define mmVM_L2_SAW_CONTEXTS_DISABLE 0x060c +#define mmVM_L2_SAW_CONTEXTS_DISABLE_BASE_IDX 0 +#define mmVM_L2_SAW_CNTL4 0x0603 +#define mmVM_L2_SAW_CNTL4_BASE_IDX 0 // addressBlock: mmhub_utcl2_atcl2dec // base address: 0x69900 diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h index 5ebe4cb40f9db6..c38a01742d6f0e 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h @@ -7571,6 +7571,8 @@ // base address: 0x10100000 #define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0 0xd000 #define regRCC_STRAP0_RCC_DEV0_EPF0_STRAP0_BASE_IDX 5 +#define regRCC_DEV0_EPF5_STRAP4 0xd284 +#define regRCC_DEV0_EPF5_STRAP4_BASE_IDX 5 // addressBlock: nbio_nbif0_bif_rst_bif_rst_regblk diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_sh_mask.h index eb8c556d9c9300..3b96f1e5a1802c 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_sh_mask.h @@ -50665,6 +50665,19 @@ #define RCC_STRAP0_RCC_DEV0_EPF0_STRAP0__STRAP_D1_SUPPORT_DEV0_F0_MASK 0x40000000L #define RCC_STRAP0_RCC_DEV0_EPF0_STRAP0__STRAP_D2_SUPPORT_DEV0_F0_MASK 0x80000000L +//RCC_DEV0_EPF5_STRAP4 +#define RCC_DEV0_EPF5_STRAP4__STRAP_ATOMIC_64BIT_EN_DEV0_F5__SHIFT 0x14 +#define RCC_DEV0_EPF5_STRAP4__STRAP_ATOMIC_EN_DEV0_F5__SHIFT 0x15 +#define RCC_DEV0_EPF5_STRAP4__STRAP_FLR_EN_DEV0_F5__SHIFT 0x16 +#define RCC_DEV0_EPF5_STRAP4__STRAP_PME_SUPPORT_DEV0_F5__SHIFT 0x17 +#define RCC_DEV0_EPF5_STRAP4__STRAP_INTERRUPT_PIN_DEV0_F5__SHIFT 0x1c +#define RCC_DEV0_EPF5_STRAP4__STRAP_AUXPWR_SUPPORT_DEV0_F5__SHIFT 0x1f +#define RCC_DEV0_EPF5_STRAP4__STRAP_ATOMIC_64BIT_EN_DEV0_F5_MASK 0x00100000L +#define RCC_DEV0_EPF5_STRAP4__STRAP_ATOMIC_EN_DEV0_F5_MASK 0x00200000L +#define RCC_DEV0_EPF5_STRAP4__STRAP_FLR_EN_DEV0_F5_MASK 0x00400000L +#define RCC_DEV0_EPF5_STRAP4__STRAP_PME_SUPPORT_DEV0_F5_MASK 0x0F800000L +#define RCC_DEV0_EPF5_STRAP4__STRAP_INTERRUPT_PIN_DEV0_F5_MASK 0x70000000L +#define RCC_DEV0_EPF5_STRAP4__STRAP_AUXPWR_SUPPORT_DEV0_F5_MASK 0x80000000L // addressBlock: nbio_nbif0_bif_rst_bif_rst_regblk //HARD_RST_CTRL diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 19a48d98830a39..d7acdd42d80f6c 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -119,6 +119,8 @@ enum pp_clock_type { OD_ACOUSTIC_TARGET, OD_FAN_TARGET_TEMPERATURE, OD_FAN_MINIMUM_PWM, + OD_FAN_ZERO_RPM_ENABLE, + OD_FAN_ZERO_RPM_STOP_TEMP, }; enum amd_pp_sensors { @@ -162,6 +164,7 @@ enum amd_pp_task { }; enum PP_SMC_POWER_PROFILE { + PP_SMC_POWER_PROFILE_UNKNOWN = -1, PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT = 0x0, PP_SMC_POWER_PROFILE_FULLSCREEN3D = 0x1, PP_SMC_POWER_PROFILE_POWERSAVING = 0x2, @@ -199,6 +202,8 @@ enum PP_OD_DPM_TABLE_COMMAND { PP_OD_EDIT_ACOUSTIC_TARGET, PP_OD_EDIT_FAN_TARGET_TEMPERATURE, PP_OD_EDIT_FAN_MINIMUM_PWM, + PP_OD_EDIT_FAN_ZERO_RPM_ENABLE, + PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP, }; struct pp_states_info { @@ -336,7 +341,8 @@ enum pp_policy_soc_pstate { #define MAX_CLKS 4 #define NUM_VCN 4 #define NUM_JPEG_ENG 32 - +#define MAX_XCC 8 +#define NUM_XCP 8 struct seq_file; enum amd_pp_clock_type; struct amd_pp_simple_clock_info; @@ -350,6 +356,26 @@ struct pp_smu_wm_range_sets; struct pp_smu_nv_clock_table; struct dpm_clocks; +struct amdgpu_xcp_metrics { + /* Utilization Instantaneous (%) */ + uint32_t gfx_busy_inst[MAX_XCC]; + uint16_t jpeg_busy[NUM_JPEG_ENG]; + uint16_t vcn_busy[NUM_VCN]; + /* Utilization Accumulated (%) */ + uint64_t gfx_busy_acc[MAX_XCC]; +}; + +struct amdgpu_xcp_metrics_v1_1 { + /* Utilization Instantaneous (%) */ + uint32_t gfx_busy_inst[MAX_XCC]; + uint16_t jpeg_busy[NUM_JPEG_ENG]; + uint16_t vcn_busy[NUM_VCN]; + /* Utilization Accumulated (%) */ + uint64_t gfx_busy_acc[MAX_XCC]; + /* Total App Clock Counter Accumulated */ + uint64_t gfx_below_host_limit_acc[MAX_XCC]; +}; + struct amd_pm_funcs { /* export for dpm on ci and si */ int (*pre_set_power_state)(void *handle); @@ -872,6 +898,196 @@ struct gpu_metrics_v1_5 { uint16_t padding; }; +struct gpu_metrics_v1_6 { + struct metrics_table_header common_header; + + /* Temperature (Celsius) */ + uint16_t temperature_hotspot; + uint16_t temperature_mem; + uint16_t temperature_vrsoc; + + /* Power (Watts) */ + uint16_t curr_socket_power; + + /* Utilization (%) */ + uint16_t average_gfx_activity; + uint16_t average_umc_activity; // memory controller + + /* Energy (15.259uJ (2^-16) units) */ + uint64_t energy_accumulator; + + /* Driver attached timestamp (in ns) */ + uint64_t system_clock_counter; + + /* Accumulation cycle counter */ + uint32_t accumulation_counter; + + /* Accumulated throttler residencies */ + uint32_t prochot_residency_acc; + uint32_t ppt_residency_acc; + uint32_t socket_thm_residency_acc; + uint32_t vr_thm_residency_acc; + uint32_t hbm_thm_residency_acc; + + /* Clock Lock Status. Each bit corresponds to clock instance */ + uint32_t gfxclk_lock_status; + + /* Link width (number of lanes) and speed (in 0.1 GT/s) */ + uint16_t pcie_link_width; + uint16_t pcie_link_speed; + + /* XGMI bus width and bitrate (in Gbps) */ + uint16_t xgmi_link_width; + uint16_t xgmi_link_speed; + + /* Utilization Accumulated (%) */ + uint32_t gfx_activity_acc; + uint32_t mem_activity_acc; + + /*PCIE accumulated bandwidth (GB/sec) */ + uint64_t pcie_bandwidth_acc; + + /*PCIE instantaneous bandwidth (GB/sec) */ + uint64_t pcie_bandwidth_inst; + + /* PCIE L0 to recovery state transition accumulated count */ + uint64_t pcie_l0_to_recov_count_acc; + + /* PCIE replay accumulated count */ + uint64_t pcie_replay_count_acc; + + /* PCIE replay rollover accumulated count */ + uint64_t pcie_replay_rover_count_acc; + + /* PCIE NAK sent accumulated count */ + uint32_t pcie_nak_sent_count_acc; + + /* PCIE NAK received accumulated count */ + uint32_t pcie_nak_rcvd_count_acc; + + /* XGMI accumulated data transfer size(KiloBytes) */ + uint64_t xgmi_read_data_acc[NUM_XGMI_LINKS]; + uint64_t xgmi_write_data_acc[NUM_XGMI_LINKS]; + + /* PMFW attached timestamp (10ns resolution) */ + uint64_t firmware_timestamp; + + /* Current clocks (Mhz) */ + uint16_t current_gfxclk[MAX_GFX_CLKS]; + uint16_t current_socclk[MAX_CLKS]; + uint16_t current_vclk0[MAX_CLKS]; + uint16_t current_dclk0[MAX_CLKS]; + uint16_t current_uclk; + + /* Number of current partition */ + uint16_t num_partition; + + /* XCP metrics stats */ + struct amdgpu_xcp_metrics xcp_stats[NUM_XCP]; + + /* PCIE other end recovery counter */ + uint32_t pcie_lc_perf_other_end_recovery; +}; + +struct gpu_metrics_v1_7 { + struct metrics_table_header common_header; + + /* Temperature (Celsius) */ + uint16_t temperature_hotspot; + uint16_t temperature_mem; + uint16_t temperature_vrsoc; + + /* Power (Watts) */ + uint16_t curr_socket_power; + + /* Utilization (%) */ + uint16_t average_gfx_activity; + uint16_t average_umc_activity; // memory controller + + /* VRAM max bandwidthi (in GB/sec) at max memory clock */ + uint64_t mem_max_bandwidth; + + /* Energy (15.259uJ (2^-16) units) */ + uint64_t energy_accumulator; + + /* Driver attached timestamp (in ns) */ + uint64_t system_clock_counter; + + /* Accumulation cycle counter */ + uint32_t accumulation_counter; + + /* Accumulated throttler residencies */ + uint32_t prochot_residency_acc; + uint32_t ppt_residency_acc; + uint32_t socket_thm_residency_acc; + uint32_t vr_thm_residency_acc; + uint32_t hbm_thm_residency_acc; + + /* Clock Lock Status. Each bit corresponds to clock instance */ + uint32_t gfxclk_lock_status; + + /* Link width (number of lanes) and speed (in 0.1 GT/s) */ + uint16_t pcie_link_width; + uint16_t pcie_link_speed; + + /* XGMI bus width and bitrate (in Gbps) */ + uint16_t xgmi_link_width; + uint16_t xgmi_link_speed; + + /* Utilization Accumulated (%) */ + uint32_t gfx_activity_acc; + uint32_t mem_activity_acc; + + /*PCIE accumulated bandwidth (GB/sec) */ + uint64_t pcie_bandwidth_acc; + + /*PCIE instantaneous bandwidth (GB/sec) */ + uint64_t pcie_bandwidth_inst; + + /* PCIE L0 to recovery state transition accumulated count */ + uint64_t pcie_l0_to_recov_count_acc; + + /* PCIE replay accumulated count */ + uint64_t pcie_replay_count_acc; + + /* PCIE replay rollover accumulated count */ + uint64_t pcie_replay_rover_count_acc; + + /* PCIE NAK sent accumulated count */ + uint32_t pcie_nak_sent_count_acc; + + /* PCIE NAK received accumulated count */ + uint32_t pcie_nak_rcvd_count_acc; + + /* XGMI accumulated data transfer size(KiloBytes) */ + uint64_t xgmi_read_data_acc[NUM_XGMI_LINKS]; + uint64_t xgmi_write_data_acc[NUM_XGMI_LINKS]; + + /* XGMI link status(active/inactive) */ + uint16_t xgmi_link_status[NUM_XGMI_LINKS]; + + uint16_t padding; + + /* PMFW attached timestamp (10ns resolution) */ + uint64_t firmware_timestamp; + + /* Current clocks (Mhz) */ + uint16_t current_gfxclk[MAX_GFX_CLKS]; + uint16_t current_socclk[MAX_CLKS]; + uint16_t current_vclk0[MAX_CLKS]; + uint16_t current_dclk0[MAX_CLKS]; + uint16_t current_uclk; + + /* Number of current partition */ + uint16_t num_partition; + + /* XCP metrics stats */ + struct amdgpu_xcp_metrics_v1_1 xcp_stats[NUM_XCP]; + + /* PCIE other end recovery counter */ + uint32_t pcie_lc_perf_other_end_recovery; +}; + /* * gpu_metrics_v2_0 is not recommended as it's not naturally aligned. * Use gpu_metrics_v2_1 or later instead. diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h index 21ceafce1f9b27..eb46cb10c24d43 100644 --- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h @@ -230,13 +230,23 @@ union MESAPI_SET_HW_RESOURCES { uint32_t disable_add_queue_wptr_mc_addr : 1; uint32_t enable_mes_event_int_logging : 1; uint32_t enable_reg_active_poll : 1; - uint32_t reserved : 21; + uint32_t use_disable_queue_in_legacy_uq_preemption : 1; + uint32_t send_write_data : 1; + uint32_t os_tdr_timeout_override : 1; + uint32_t use_rs64mem_for_proc_gang_ctx : 1; + uint32_t use_add_queue_unmap_flag_addr : 1; + uint32_t enable_mes_sch_stb_log : 1; + uint32_t limit_single_process : 1; + uint32_t is_strix_tmz_wa_enabled :1; + uint32_t reserved : 13; }; uint32_t uint32_t_all; }; uint32_t oversubscription_timer; uint64_t doorbell_info; uint64_t event_intr_history_gpu_mc_ptr; + uint64_t timestamp; + uint32_t os_tdr_timeout_in_sec; }; uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; @@ -563,6 +573,11 @@ enum MESAPI_MISC_OPCODE { MESAPI_MISC__READ_REG, MESAPI_MISC__WAIT_REG_MEM, MESAPI_MISC__SET_SHADER_DEBUGGER, + MESAPI_MISC__NOTIFY_WORK_ON_UNMAPPED_QUEUE, + MESAPI_MISC__NOTIFY_TO_UNMAP_PROCESSES, + MESAPI_MISC__CHANGE_CONFIG, + MESAPI_MISC__LAUNCH_CLEANER_SHADER, + MESAPI_MISC__MAX, }; @@ -617,6 +632,31 @@ struct SET_SHADER_DEBUGGER { uint32_t trap_en; }; +enum MESAPI_MISC__CHANGE_CONFIG_OPTION { + MESAPI_MISC__CHANGE_CONFIG_OPTION_LIMIT_SINGLE_PROCESS = 0, + MESAPI_MISC__CHANGE_CONFIG_OPTION_ENABLE_HWS_LOGGING_BUFFER = 1, + MESAPI_MISC__CHANGE_CONFIG_OPTION_CHANGE_TDR_CONFIG = 2, + + MESAPI_MISC__CHANGE_CONFIG_OPTION_MAX = 0x1F +}; + +struct CHANGE_CONFIG { + enum MESAPI_MISC__CHANGE_CONFIG_OPTION opcode; + union { + struct { + uint32_t limit_single_process : 1; + uint32_t enable_hws_logging_buffer : 1; + uint32_t reserved : 31; + } bits; + uint32_t all; + } option; + + struct { + uint32_t tdr_level; + uint32_t tdr_delay; + } tdr_config; +}; + union MESAPI__MISC { struct { union MES_API_HEADER header; @@ -631,6 +671,7 @@ union MESAPI__MISC { struct WAIT_REG_MEM wait_reg_mem; struct SET_SHADER_DEBUGGER set_shader_debugger; enum MES_AMD_PRIORITY_LEVEL queue_sch_level; + struct CHANGE_CONFIG change_config; uint32_t data[MISC_DATA_MAX_SIZE_IN_DWORDS]; }; diff --git a/drivers/gpu/drm/amd/include/mes_v12_api_def.h b/drivers/gpu/drm/amd/include/mes_v12_api_def.h index 101e2fe962c6a6..c9b2ca5cf75f4d 100644 --- a/drivers/gpu/drm/amd/include/mes_v12_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v12_api_def.h @@ -643,6 +643,10 @@ enum MESAPI_MISC_OPCODE { MESAPI_MISC__SET_SHADER_DEBUGGER, MESAPI_MISC__NOTIFY_WORK_ON_UNMAPPED_QUEUE, MESAPI_MISC__NOTIFY_TO_UNMAP_PROCESSES, + MESAPI_MISC__QUERY_HUNG_ENGINE_ID, + MESAPI_MISC__CHANGE_CONFIG, + MESAPI_MISC__LAUNCH_CLEANER_SHADER, + MESAPI_MISC__SETUP_MES_DBGEXT, MESAPI_MISC__MAX, }; @@ -713,6 +717,31 @@ struct SET_GANG_SUBMIT { uint32_t slave_gang_context_array_index; }; +enum MESAPI_MISC__CHANGE_CONFIG_OPTION { + MESAPI_MISC__CHANGE_CONFIG_OPTION_LIMIT_SINGLE_PROCESS = 0, + MESAPI_MISC__CHANGE_CONFIG_OPTION_ENABLE_HWS_LOGGING_BUFFER = 1, + MESAPI_MISC__CHANGE_CONFIG_OPTION_CHANGE_TDR_CONFIG = 2, + + MESAPI_MISC__CHANGE_CONFIG_OPTION_MAX = 0x1F +}; + +struct CHANGE_CONFIG { + enum MESAPI_MISC__CHANGE_CONFIG_OPTION opcode; + union { + struct { + uint32_t limit_single_process : 1; + uint32_t enable_hws_logging_buffer : 1; + uint32_t reserved : 30; + } bits; + uint32_t all; + } option; + + struct { + uint32_t tdr_level; + uint32_t tdr_delay; + } tdr_config; +}; + union MESAPI__MISC { struct { union MES_API_HEADER header; @@ -726,7 +755,7 @@ union MESAPI__MISC { struct WAIT_REG_MEM wait_reg_mem; struct SET_SHADER_DEBUGGER set_shader_debugger; enum MES_AMD_PRIORITY_LEVEL queue_sch_level; - + struct CHANGE_CONFIG change_config; uint32_t data[MISC_DATA_MAX_SIZE_IN_DWORDS]; }; uint64_t timestamp; diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index d5d6ab484e5add..e8ae7681bf0a38 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -145,15 +145,12 @@ static ssize_t amdgpu_get_power_dpm_state(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; amdgpu_dpm_get_current_power_state(adev, &pm); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return sysfs_emit(buf, "%s\n", @@ -185,11 +182,9 @@ static ssize_t amdgpu_set_power_dpm_state(struct device *dev, else return -EINVAL; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } amdgpu_dpm_set_power_state(adev, state); @@ -273,15 +268,12 @@ static ssize_t amdgpu_get_power_dpm_force_performance_level(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; level = amdgpu_dpm_get_performance_level(adev); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return sysfs_emit(buf, "%s\n", @@ -336,11 +328,9 @@ static ssize_t amdgpu_set_power_dpm_force_performance_level(struct device *dev, return -EINVAL; } - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } mutex_lock(&adev->pm.stable_pstate_ctx_lock); if (amdgpu_dpm_force_performance_level(adev, level)) { @@ -374,16 +364,13 @@ static ssize_t amdgpu_get_pp_num_states(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; if (amdgpu_dpm_get_pp_num_states(adev, &data)) memset(&data, 0, sizeof(data)); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); buf_len = sysfs_emit(buf, "states: %d\n", data.nums); @@ -412,17 +399,14 @@ static ssize_t amdgpu_get_pp_cur_state(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; amdgpu_dpm_get_current_power_state(adev, &pm); ret = amdgpu_dpm_get_pp_num_states(adev, &data); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); if (ret) @@ -485,11 +469,9 @@ static ssize_t amdgpu_set_pp_force_state(struct device *dev, idx = array_index_nospec(idx, ARRAY_SIZE(data.states)); - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } ret = amdgpu_dpm_get_pp_num_states(adev, &data); if (ret) @@ -544,15 +526,12 @@ static ssize_t amdgpu_get_pp_table(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; size = amdgpu_dpm_get_pp_table(adev, &table); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); if (size <= 0) @@ -580,11 +559,9 @@ static ssize_t amdgpu_set_pp_table(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } ret = amdgpu_dpm_set_pp_table(adev, buf, count); @@ -808,11 +785,9 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, tmp_str++; } - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } if (amdgpu_dpm_set_fine_grain_clk_vol(adev, type, @@ -865,11 +840,9 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; for (clk_index = 0 ; clk_index < 6 ; clk_index++) { ret = amdgpu_dpm_emit_clock_levels(adev, od_clocks[clk_index], buf, &size); @@ -888,7 +861,6 @@ static ssize_t amdgpu_get_pp_od_clk_voltage(struct device *dev, if (size == 0) size = sysfs_emit(buf, "\n"); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return size; @@ -929,11 +901,9 @@ static ssize_t amdgpu_set_pp_features(struct device *dev, if (ret) return -EINVAL; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } ret = amdgpu_dpm_set_ppfeature_status(adev, featuremask); @@ -960,17 +930,14 @@ static ssize_t amdgpu_get_pp_features(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; size = amdgpu_dpm_get_ppfeature_status(adev, buf); if (size <= 0) size = sysfs_emit(buf, "\n"); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return size; @@ -1029,11 +996,9 @@ static ssize_t amdgpu_get_pp_dpm_clock(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; ret = amdgpu_dpm_emit_clock_levels(adev, type, buf, &size); if (ret == -ENOENT) @@ -1042,7 +1007,6 @@ static ssize_t amdgpu_get_pp_dpm_clock(struct device *dev, if (size == 0) size = sysfs_emit(buf, "\n"); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return size; @@ -1102,11 +1066,9 @@ static ssize_t amdgpu_set_pp_dpm_clock(struct device *dev, if (ret) return ret; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } ret = amdgpu_dpm_force_clock_level(adev, type, mask); @@ -1283,15 +1245,12 @@ static ssize_t amdgpu_get_pp_sclk_od(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; value = amdgpu_dpm_get_sclk_od(adev); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return sysfs_emit(buf, "%d\n", value); @@ -1317,11 +1276,9 @@ static ssize_t amdgpu_set_pp_sclk_od(struct device *dev, if (ret) return -EINVAL; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } amdgpu_dpm_set_sclk_od(adev, (uint32_t)value); @@ -1345,15 +1302,12 @@ static ssize_t amdgpu_get_pp_mclk_od(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; value = amdgpu_dpm_get_mclk_od(adev); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return sysfs_emit(buf, "%d\n", value); @@ -1379,11 +1333,9 @@ static ssize_t amdgpu_set_pp_mclk_od(struct device *dev, if (ret) return -EINVAL; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } amdgpu_dpm_set_mclk_od(adev, (uint32_t)value); @@ -1409,7 +1361,11 @@ static ssize_t amdgpu_set_pp_mclk_od(struct device *dev, * create a custom set of heuristics, write a string of numbers to the file * starting with the number of the custom profile along with a setting * for each heuristic parameter. Due to differences across asic families - * the heuristic parameters vary from family to family. + * the heuristic parameters vary from family to family. Additionally, + * you can apply the custom heuristics to different clock domains. Each + * clock domain is considered a distinct operation so if you modify the + * gfxclk heuristics and then the memclk heuristics, the all of the + * custom heuristics will be retained until you switch to another profile. * */ @@ -1427,17 +1383,14 @@ static ssize_t amdgpu_get_pp_power_profile_mode(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; size = amdgpu_dpm_get_power_profile_mode(adev, buf); if (size <= 0) size = sysfs_emit(buf, "\n"); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return size; @@ -1492,11 +1445,9 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, } parameter[parameter_size] = profile_mode; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } ret = amdgpu_dpm_set_power_profile_mode(adev, parameter, parameter_size); @@ -1520,16 +1471,13 @@ static int amdgpu_hwmon_get_sensor_generic(struct amdgpu_device *adev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (r < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return r; - } + r = pm_runtime_get_if_active(adev->dev); + if (r <= 0) + return r ?: -EPERM; /* get the sensor value */ r = amdgpu_dpm_read_sensor(adev, sensor, query, &size); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return r; @@ -1639,15 +1587,12 @@ static ssize_t amdgpu_get_pcie_bw(struct device *dev, if (!adev->asic_funcs->get_pcie_usage) return -ENODATA; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; amdgpu_asic_get_pcie_usage(adev, &count0, &count1); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return sysfs_emit(buf, "%llu %llu %i\n", @@ -1770,11 +1715,9 @@ static ssize_t amdgpu_get_apu_thermal_cap(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; ret = amdgpu_dpm_get_apu_thermal_limit(adev, &limit); if (!ret) @@ -1782,7 +1725,6 @@ static ssize_t amdgpu_get_apu_thermal_cap(struct device *dev, else size = sysfs_emit(buf, "failed to get thermal limit\n"); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return size; @@ -1807,14 +1749,14 @@ static ssize_t amdgpu_set_apu_thermal_cap(struct device *dev, return -EINVAL; } - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } ret = amdgpu_dpm_set_apu_thermal_limit(adev, value); if (ret) { + pm_runtime_mark_last_busy(ddev->dev); + pm_runtime_put_autosuspend(ddev->dev); dev_err(dev, "failed to update thermal limit\n"); return ret; } @@ -1849,15 +1791,12 @@ static ssize_t amdgpu_get_pm_metrics(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; size = amdgpu_dpm_get_pm_metrics(adev, buf, PAGE_SIZE); - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return size; @@ -1890,11 +1829,9 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); - return ret; - } + ret = pm_runtime_get_if_active(ddev->dev); + if (ret <= 0) + return ret ?: -EPERM; size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics); if (size <= 0) @@ -1906,7 +1843,6 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev, memcpy(buf, gpu_metrics, size); out: - pm_runtime_mark_last_busy(ddev->dev); pm_runtime_put_autosuspend(ddev->dev); return size; @@ -2008,11 +1944,9 @@ static ssize_t amdgpu_set_smartshift_bias(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - r = pm_runtime_get_sync(ddev->dev); - if (r < 0) { - pm_runtime_put_autosuspend(ddev->dev); + r = pm_runtime_resume_and_get(ddev->dev); + if (r < 0) return r; - } r = kstrtoint(buf, 10, &bias); if (r) @@ -2335,11 +2269,9 @@ static ssize_t amdgpu_set_pm_policy_attr(struct device *dev, policy_attr = container_of(attr, struct amdgpu_pm_policy_attr, dev_attr); - ret = pm_runtime_get_sync(ddev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(ddev->dev); + ret = pm_runtime_resume_and_get(ddev->dev); + if (ret < 0) return ret; - } ret = amdgpu_dpm_set_pm_policy(adev, policy_attr->id, val); @@ -2772,15 +2704,12 @@ static ssize_t amdgpu_hwmon_get_pwm1_enable(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return ret; - } + ret = pm_runtime_get_if_active(adev->dev); + if (ret <= 0) + return ret ?: -EPERM; ret = amdgpu_dpm_get_fan_control_mode(adev, &pwm_mode); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (ret) @@ -2817,11 +2746,9 @@ static ssize_t amdgpu_hwmon_set_pwm1_enable(struct device *dev, else return -EINVAL; - ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + ret = pm_runtime_resume_and_get(adev->dev); + if (ret < 0) return ret; - } ret = amdgpu_dpm_set_fan_control_mode(adev, pwm_mode); @@ -2866,11 +2793,9 @@ static ssize_t amdgpu_hwmon_set_pwm1(struct device *dev, if (err) return err; - err = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (err < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + err = pm_runtime_resume_and_get(adev->dev); + if (err < 0) return err; - } err = amdgpu_dpm_get_fan_control_mode(adev, &pwm_mode); if (err) @@ -2907,15 +2832,12 @@ static ssize_t amdgpu_hwmon_get_pwm1(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - err = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (err < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return err; - } + err = pm_runtime_get_if_active(adev->dev); + if (err <= 0) + return err ?: -EPERM; err = amdgpu_dpm_get_fan_speed_pwm(adev, &speed); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) @@ -2937,15 +2859,12 @@ static ssize_t amdgpu_hwmon_get_fan1_input(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - err = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (err < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return err; - } + err = pm_runtime_get_if_active(adev->dev); + if (err <= 0) + return err ?: -EPERM; err = amdgpu_dpm_get_fan_speed_rpm(adev, &speed); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) @@ -3001,15 +2920,12 @@ static ssize_t amdgpu_hwmon_get_fan1_target(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - err = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (err < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return err; - } + err = pm_runtime_get_if_active(adev->dev); + if (err <= 0) + return err ?: -EPERM; err = amdgpu_dpm_get_fan_speed_rpm(adev, &rpm); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (err) @@ -3036,11 +2952,9 @@ static ssize_t amdgpu_hwmon_set_fan1_target(struct device *dev, if (err) return err; - err = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (err < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + err = pm_runtime_resume_and_get(adev->dev); + if (err < 0) return err; - } err = amdgpu_dpm_get_fan_control_mode(adev, &pwm_mode); if (err) @@ -3076,15 +2990,12 @@ static ssize_t amdgpu_hwmon_get_fan1_enable(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return ret; - } + ret = pm_runtime_get_if_active(adev->dev); + if (ret <= 0) + return ret ?: -EPERM; ret = amdgpu_dpm_get_fan_control_mode(adev, &pwm_mode); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); if (ret) @@ -3119,11 +3030,9 @@ static ssize_t amdgpu_hwmon_set_fan1_enable(struct device *dev, else return -EINVAL; - err = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (err < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + err = pm_runtime_resume_and_get(adev->dev); + if (err < 0) return err; - } err = amdgpu_dpm_set_fan_control_mode(adev, pwm_mode); @@ -3248,11 +3157,9 @@ static ssize_t amdgpu_hwmon_show_power_cap_generic(struct device *dev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (r < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); - return r; - } + r = pm_runtime_get_if_active(adev->dev); + if (r <= 0) + return r ?: -EPERM; r = amdgpu_dpm_get_power_limit(adev, &limit, pp_limit_level, power_type); @@ -3262,7 +3169,6 @@ static ssize_t amdgpu_hwmon_show_power_cap_generic(struct device *dev, else size = sysfs_emit(buf, "\n"); - pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); return size; @@ -3339,11 +3245,9 @@ static ssize_t amdgpu_hwmon_set_power_cap(struct device *dev, value = value / 1000000; /* convert to Watt */ value |= limit_type << 24; - err = pm_runtime_get_sync(adev_to_drm(adev)->dev); - if (err < 0) { - pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + err = pm_runtime_resume_and_get(adev->dev); + if (err < 0) return err; - } err = amdgpu_dpm_set_power_limit(adev, value); @@ -3787,17 +3691,14 @@ static int amdgpu_retrieve_od_settings(struct amdgpu_device *adev, if (adev->in_suspend && !adev->in_runpm) return -EPERM; - ret = pm_runtime_get_sync(adev->dev); - if (ret < 0) { - pm_runtime_put_autosuspend(adev->dev); - return ret; - } + ret = pm_runtime_get_if_active(adev->dev); + if (ret <= 0) + return ret ?: -EPERM; size = amdgpu_dpm_print_clock_levels(adev, od_type, buf); if (size == 0) size = sysfs_emit(buf, "\n"); - pm_runtime_mark_last_busy(adev->dev); pm_runtime_put_autosuspend(adev->dev); return size; @@ -3879,23 +3780,23 @@ amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev, if (ret) return ret; - ret = pm_runtime_get_sync(adev->dev); + ret = pm_runtime_resume_and_get(adev->dev); if (ret < 0) - goto err_out0; + return ret; ret = amdgpu_dpm_odn_edit_dpm_table(adev, cmd_type, parameter, parameter_size); if (ret) - goto err_out1; + goto err_out; if (cmd_type == PP_OD_COMMIT_DPM_TABLE) { ret = amdgpu_dpm_dispatch_task(adev, AMD_PP_TASK_READJUST_POWER_STATE, NULL); if (ret) - goto err_out1; + goto err_out; } pm_runtime_mark_last_busy(adev->dev); @@ -3903,9 +3804,8 @@ amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev, return count; -err_out1: +err_out: pm_runtime_mark_last_busy(adev->dev); -err_out0: pm_runtime_put_autosuspend(adev->dev); return ret; @@ -4213,6 +4113,117 @@ static umode_t fan_minimum_pwm_visible(struct amdgpu_device *adev) return umode; } +/** + * DOC: fan_zero_rpm_enable + * + * The amdgpu driver provides a sysfs API for checking and adjusting the + * zero RPM feature. + * + * Reading back the file shows you the current setting and the permitted + * ranges if changable. + * + * Writing an integer to the file, change the setting accordingly. + * + * When you have finished the editing, write "c" (commit) to the file to commit + * your changes. + * + * If you want to reset to the default value, write "r" (reset) to the file to + * reset them. + */ +static ssize_t fan_zero_rpm_enable_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct od_kobj *container = container_of(kobj, struct od_kobj, kobj); + struct amdgpu_device *adev = (struct amdgpu_device *)container->priv; + + return (ssize_t)amdgpu_retrieve_od_settings(adev, OD_FAN_ZERO_RPM_ENABLE, buf); +} + +static ssize_t fan_zero_rpm_enable_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct od_kobj *container = container_of(kobj, struct od_kobj, kobj); + struct amdgpu_device *adev = (struct amdgpu_device *)container->priv; + + return (ssize_t)amdgpu_distribute_custom_od_settings(adev, + PP_OD_EDIT_FAN_ZERO_RPM_ENABLE, + buf, + count); +} + +static umode_t fan_zero_rpm_enable_visible(struct amdgpu_device *adev) +{ + umode_t umode = 0000; + + if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_RETRIEVE) + umode |= S_IRUSR | S_IRGRP | S_IROTH; + + if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET) + umode |= S_IWUSR; + + return umode; +} + +/** + * DOC: fan_zero_rpm_stop_temperature + * + * The amdgpu driver provides a sysfs API for checking and adjusting the + * zero RPM stop temperature feature. + * + * Reading back the file shows you the current setting and the permitted + * ranges if changable. + * + * Writing an integer to the file, change the setting accordingly. + * + * When you have finished the editing, write "c" (commit) to the file to commit + * your changes. + * + * If you want to reset to the default value, write "r" (reset) to the file to + * reset them. + * + * This setting works only if the Zero RPM setting is enabled. It adjusts the + * temperature below which the fan can stop. + */ +static ssize_t fan_zero_rpm_stop_temp_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct od_kobj *container = container_of(kobj, struct od_kobj, kobj); + struct amdgpu_device *adev = (struct amdgpu_device *)container->priv; + + return (ssize_t)amdgpu_retrieve_od_settings(adev, OD_FAN_ZERO_RPM_STOP_TEMP, buf); +} + +static ssize_t fan_zero_rpm_stop_temp_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct od_kobj *container = container_of(kobj, struct od_kobj, kobj); + struct amdgpu_device *adev = (struct amdgpu_device *)container->priv; + + return (ssize_t)amdgpu_distribute_custom_od_settings(adev, + PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP, + buf, + count); +} + +static umode_t fan_zero_rpm_stop_temp_visible(struct amdgpu_device *adev) +{ + umode_t umode = 0000; + + if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_RETRIEVE) + umode |= S_IRUSR | S_IRGRP | S_IROTH; + + if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_SET) + umode |= S_IWUSR; + + return umode; +} + static struct od_feature_set amdgpu_od_set = { .containers = { [0] = { @@ -4258,6 +4269,22 @@ static struct od_feature_set amdgpu_od_set = { .store = fan_minimum_pwm_store, }, }, + [5] = { + .name = "fan_zero_rpm_enable", + .ops = { + .is_visible = fan_zero_rpm_enable_visible, + .show = fan_zero_rpm_enable_show, + .store = fan_zero_rpm_enable_store, + }, + }, + [6] = { + .name = "fan_zero_rpm_stop_temperature", + .ops = { + .is_visible = fan_zero_rpm_stop_temp_visible, + .show = fan_zero_rpm_stop_temp_show, + .store = fan_zero_rpm_stop_temp_store, + }, + }, }, }, }, @@ -4758,11 +4785,9 @@ static int amdgpu_debugfs_pm_info_show(struct seq_file *m, void *unused) if (adev->in_suspend && !adev->in_runpm) return -EPERM; - r = pm_runtime_get_sync(dev->dev); - if (r < 0) { - pm_runtime_put_autosuspend(dev->dev); + r = pm_runtime_resume_and_get(dev->dev); + if (r < 0) return r; - } if (amdgpu_dpm_debugfs_print_current_performance_level(adev, m)) { r = amdgpu_debugfs_pm_info_pp(m, adev); @@ -4777,7 +4802,6 @@ static int amdgpu_debugfs_pm_info_show(struct seq_file *m, void *unused) seq_printf(m, "\n"); out: - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); return r; diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index f5bf41f21c4123..363af8990aa257 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -328,6 +328,10 @@ struct config_table_setting #define OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_SET BIT(7) #define OD_OPS_SUPPORT_FAN_MINIMUM_PWM_RETRIEVE BIT(8) #define OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET BIT(9) +#define OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_RETRIEVE BIT(10) +#define OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET BIT(11) +#define OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_RETRIEVE BIT(12) +#define OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_SET BIT(13) struct amdgpu_pm { struct mutex mutex; diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c index e8b6989a40f35a..8908646ad620d4 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c @@ -2954,9 +2954,9 @@ static int kv_dpm_get_temp(void *handle) return actual_temp; } -static int kv_dpm_early_init(void *handle) +static int kv_dpm_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->powerplay.pp_funcs = &kv_dpm_funcs; adev->powerplay.pp_handle = adev; @@ -2965,10 +2965,10 @@ static int kv_dpm_early_init(void *handle) return 0; } -static int kv_dpm_late_init(void *handle) +static int kv_dpm_late_init(struct amdgpu_ip_block *ip_block) { /* powerdown unused blocks for now */ - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->pm.dpm_enabled) return 0; @@ -2979,11 +2979,10 @@ static int kv_dpm_late_init(void *handle) return 0; } -static int kv_dpm_sw_init(void *handle) +static int kv_dpm_sw_init(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - + struct amdgpu_device *adev = ip_block->adev; ret = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 230, &adev->pm.dpm.thermal.irq); if (ret) @@ -3024,9 +3023,9 @@ static int kv_dpm_sw_init(void *handle) return ret; } -static int kv_dpm_sw_fini(void *handle) +static int kv_dpm_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; flush_work(&adev->pm.dpm.thermal.work); @@ -3035,10 +3034,10 @@ static int kv_dpm_sw_fini(void *handle) return 0; } -static int kv_dpm_hw_init(void *handle) +static int kv_dpm_hw_init(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!amdgpu_dpm) return 0; @@ -3053,9 +3052,9 @@ static int kv_dpm_hw_init(void *handle) return ret; } -static int kv_dpm_hw_fini(void *handle) +static int kv_dpm_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->pm.dpm_enabled) kv_dpm_disable(adev); @@ -3063,9 +3062,9 @@ static int kv_dpm_hw_fini(void *handle) return 0; } -static int kv_dpm_suspend(void *handle) +static int kv_dpm_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->pm.dpm_enabled) { /* disable dpm */ @@ -3076,10 +3075,10 @@ static int kv_dpm_suspend(void *handle) return 0; } -static int kv_dpm_resume(void *handle) +static int kv_dpm_resume(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->pm.dpm_enabled) { /* asic init will reset to the boot state */ @@ -3100,17 +3099,6 @@ static bool kv_dpm_is_idle(void *handle) return true; } -static int kv_dpm_wait_for_idle(void *handle) -{ - return 0; -} - - -static int kv_dpm_soft_reset(void *handle) -{ - return 0; -} - static int kv_dpm_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned type, @@ -3314,12 +3302,8 @@ static const struct amd_ip_funcs kv_dpm_ip_funcs = { .suspend = kv_dpm_suspend, .resume = kv_dpm_resume, .is_idle = kv_dpm_is_idle, - .wait_for_idle = kv_dpm_wait_for_idle, - .soft_reset = kv_dpm_soft_reset, .set_clockgating_state = kv_dpm_set_clockgating_state, .set_powergating_state = kv_dpm_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version kv_smu_ip_block = { 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 a1baa13ab2c263..ee23a0f897c50c 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c @@ -4755,13 +4755,15 @@ static int si_populate_memory_timing_parameters(struct amdgpu_device *adev, u32 dram_timing; u32 dram_timing2; u32 burst_time; + int ret; arb_regs->mc_arb_rfsh_rate = (u8)si_calculate_memory_refresh_rate(adev, pl->sclk); - amdgpu_atombios_set_engine_dram_timings(adev, - pl->sclk, - pl->mclk); + ret = amdgpu_atombios_set_engine_dram_timings(adev, pl->sclk, + pl->mclk); + if (ret) + return ret; dram_timing = RREG32(MC_ARB_DRAM_TIMING); dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2); @@ -7619,10 +7621,10 @@ static int si_dpm_process_interrupt(struct amdgpu_device *adev, return 0; } -static int si_dpm_late_init(void *handle) +static int si_dpm_late_init(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!adev->pm.dpm_enabled) return 0; @@ -7716,10 +7718,10 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev) return err; } -static int si_dpm_sw_init(void *handle) +static int si_dpm_sw_init(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; ret = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, 230, &adev->pm.dpm.thermal.irq); if (ret) @@ -7763,9 +7765,9 @@ static int si_dpm_sw_init(void *handle) return ret; } -static int si_dpm_sw_fini(void *handle) +static int si_dpm_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; flush_work(&adev->pm.dpm.thermal.work); @@ -7774,11 +7776,11 @@ static int si_dpm_sw_fini(void *handle) return 0; } -static int si_dpm_hw_init(void *handle) +static int si_dpm_hw_init(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (!amdgpu_dpm) return 0; @@ -7793,9 +7795,9 @@ static int si_dpm_hw_init(void *handle) return ret; } -static int si_dpm_hw_fini(void *handle) +static int si_dpm_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->pm.dpm_enabled) si_dpm_disable(adev); @@ -7803,9 +7805,9 @@ static int si_dpm_hw_fini(void *handle) return 0; } -static int si_dpm_suspend(void *handle) +static int si_dpm_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->pm.dpm_enabled) { /* disable dpm */ @@ -7816,10 +7818,10 @@ static int si_dpm_suspend(void *handle) return 0; } -static int si_dpm_resume(void *handle) +static int si_dpm_resume(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->pm.dpm_enabled) { /* asic init will reset to the boot state */ @@ -7841,17 +7843,12 @@ static bool si_dpm_is_idle(void *handle) return true; } -static int si_dpm_wait_for_idle(void *handle) +static int si_dpm_wait_for_idle(struct amdgpu_ip_block *ip_block) { /* XXX */ return 0; } -static int si_dpm_soft_reset(void *handle) -{ - return 0; -} - static int si_dpm_set_clockgating_state(void *handle, enum amd_clockgating_state state) { @@ -7928,10 +7925,10 @@ static void si_dpm_print_power_state(void *handle, amdgpu_dpm_print_ps_status(adev, rps); } -static int si_dpm_early_init(void *handle) +static int si_dpm_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; adev->powerplay.pp_funcs = &si_dpm_funcs; adev->powerplay.pp_handle = adev; @@ -8047,11 +8044,8 @@ static const struct amd_ip_funcs si_dpm_ip_funcs = { .resume = si_dpm_resume, .is_idle = si_dpm_is_idle, .wait_for_idle = si_dpm_wait_for_idle, - .soft_reset = si_dpm_soft_reset, .set_clockgating_state = si_dpm_set_clockgating_state, .set_powergating_state = si_dpm_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version si_smu_ip_block = diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index a71c6117d7e547..26624a716fc607 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -75,11 +75,10 @@ static void amd_powerplay_destroy(struct amdgpu_device *adev) hwmgr = NULL; } -static int pp_early_init(void *handle) +static int pp_early_init(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = handle; - + struct amdgpu_device *adev = ip_block->adev; ret = amd_powerplay_create(adev); if (ret != 0) @@ -131,9 +130,9 @@ static void pp_swctf_delayed_work_handler(struct work_struct *work) orderly_poweroff(true); } -static int pp_sw_init(void *handle) +static int pp_sw_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; int ret = 0; @@ -148,9 +147,9 @@ static int pp_sw_init(void *handle) return ret; } -static int pp_sw_fini(void *handle) +static int pp_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; hwmgr_sw_fini(hwmgr); @@ -160,10 +159,10 @@ static int pp_sw_fini(void *handle) return 0; } -static int pp_hw_init(void *handle) +static int pp_hw_init(struct amdgpu_ip_block *ip_block) { int ret = 0; - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; ret = hwmgr_hw_init(hwmgr); @@ -174,10 +173,9 @@ static int pp_hw_init(void *handle) return ret; } -static int pp_hw_fini(void *handle) +static int pp_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + struct pp_hwmgr *hwmgr = ip_block->adev->powerplay.pp_handle; cancel_delayed_work_sync(&hwmgr->swctf_delayed_work); @@ -217,9 +215,9 @@ static void pp_reserve_vram_for_smu(struct amdgpu_device *adev) } } -static int pp_late_init(void *handle) +static int pp_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; if (hwmgr && hwmgr->pm_en) @@ -231,9 +229,9 @@ static int pp_late_init(void *handle) return 0; } -static void pp_late_fini(void *handle) +static void pp_late_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; if (adev->pm.smu_prv_buffer) amdgpu_bo_free_kernel(&adev->pm.smu_prv_buffer, NULL, NULL); @@ -246,25 +244,15 @@ static bool pp_is_idle(void *handle) return false; } -static int pp_wait_for_idle(void *handle) -{ - return 0; -} - -static int pp_sw_reset(void *handle) -{ - return 0; -} - static int pp_set_powergating_state(void *handle, enum amd_powergating_state state) { return 0; } -static int pp_suspend(void *handle) +static int pp_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; cancel_delayed_work_sync(&hwmgr->swctf_delayed_work); @@ -272,10 +260,9 @@ static int pp_suspend(void *handle) return hwmgr_suspend(hwmgr); } -static int pp_resume(void *handle) +static int pp_resume(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; - struct pp_hwmgr *hwmgr = adev->powerplay.pp_handle; + struct pp_hwmgr *hwmgr = ip_block->adev->powerplay.pp_handle; return hwmgr_resume(hwmgr); } @@ -298,12 +285,8 @@ static const struct amd_ip_funcs pp_ip_funcs = { .suspend = pp_suspend, .resume = pp_resume, .is_idle = pp_is_idle, - .wait_for_idle = pp_wait_for_idle, - .soft_reset = pp_sw_reset, .set_clockgating_state = pp_set_clockgating_state, .set_powergating_state = pp_set_powergating_state, - .dump_ip_state = NULL, - .print_ip_state = NULL, }; const struct amdgpu_ip_block_version pp_smu_ip_block = diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c index b56298d9da98f3..fe24219c3bf48e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c @@ -28,7 +28,6 @@ #include "ppatomctrl.h" #include "atombios.h" #include "cgs_common.h" -#include "ppevvmath.h" #define MEM_ID_MASK 0xff000000 #define MEM_ID_SHIFT 24 @@ -677,433 +676,6 @@ bool atomctrl_get_pp_assign_pin( return bRet; } -int atomctrl_calculate_voltage_evv_on_sclk( - struct pp_hwmgr *hwmgr, - uint8_t voltage_type, - uint32_t sclk, - uint16_t virtual_voltage_Id, - uint16_t *voltage, - uint16_t dpm_level, - bool debug) -{ - ATOM_ASIC_PROFILING_INFO_V3_4 *getASICProfilingInfo; - struct amdgpu_device *adev = hwmgr->adev; - EFUSE_LINEAR_FUNC_PARAM sRO_fuse; - EFUSE_LINEAR_FUNC_PARAM sCACm_fuse; - EFUSE_LINEAR_FUNC_PARAM sCACb_fuse; - EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse; - EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse; - EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse; - EFUSE_INPUT_PARAMETER sInput_FuseValues; - READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues; - - uint32_t ul_RO_fused, ul_CACb_fused, ul_CACm_fused, ul_Kt_Beta_fused, ul_Kv_m_fused, ul_Kv_b_fused; - fInt fSM_A0, fSM_A1, fSM_A2, fSM_A3, fSM_A4, fSM_A5, fSM_A6, fSM_A7; - fInt fMargin_RO_a, fMargin_RO_b, fMargin_RO_c, fMargin_fixed, fMargin_FMAX_mean, fMargin_Plat_mean, fMargin_FMAX_sigma, fMargin_Plat_sigma, fMargin_DC_sigma; - fInt fLkg_FT, repeat; - fInt fMicro_FMAX, fMicro_CR, fSigma_FMAX, fSigma_CR, fSigma_DC, fDC_SCLK, fSquared_Sigma_DC, fSquared_Sigma_CR, fSquared_Sigma_FMAX; - fInt fRLL_LoadLine, fDerateTDP, fVDDC_base, fA_Term, fC_Term, fB_Term, fRO_DC_margin; - fInt fRO_fused, fCACm_fused, fCACb_fused, fKv_m_fused, fKv_b_fused, fKt_Beta_fused, fFT_Lkg_V0NORM; - fInt fSclk_margin, fSclk, fEVV_V; - fInt fV_min, fV_max, fT_prod, fLKG_Factor, fT_FT, fV_FT, fV_x, fTDP_Power, fTDP_Power_right, fTDP_Power_left, fTDP_Current, fV_NL; - uint32_t ul_FT_Lkg_V0NORM; - fInt fLn_MaxDivMin, fMin, fAverage, fRange; - fInt fRoots[2]; - fInt fStepSize = GetScaledFraction(625, 100000); - - int result; - - getASICProfilingInfo = (ATOM_ASIC_PROFILING_INFO_V3_4 *) - smu_atom_get_data_table(hwmgr->adev, - GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo), - NULL, NULL, NULL); - - if (!getASICProfilingInfo) - return -1; - - if (getASICProfilingInfo->asHeader.ucTableFormatRevision < 3 || - (getASICProfilingInfo->asHeader.ucTableFormatRevision == 3 && - getASICProfilingInfo->asHeader.ucTableContentRevision < 4)) - return -1; - - /*----------------------------------------------------------- - *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL - *----------------------------------------------------------- - */ - fRLL_LoadLine = Divide(getASICProfilingInfo->ulLoadLineSlop, 1000); - - switch (dpm_level) { - case 1: - fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM1), 1000); - break; - case 2: - fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM2), 1000); - break; - case 3: - fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM3), 1000); - break; - case 4: - fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM4), 1000); - break; - case 5: - fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM5), 1000); - break; - case 6: - fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM6), 1000); - break; - case 7: - fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM7), 1000); - break; - default: - pr_err("DPM Level not supported\n"); - fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM0), 1000); - } - - /*------------------------- - * DECODING FUSE VALUES - * ------------------------ - */ - /*Decode RO_Fused*/ - sRO_fuse = getASICProfilingInfo->sRoFuse; - - sInput_FuseValues.usEfuseIndex = sRO_fuse.usEfuseIndex; - sInput_FuseValues.ucBitShift = sRO_fuse.ucEfuseBitLSB; - sInput_FuseValues.ucBitLength = sRO_fuse.ucEfuseLength; - - sOutput_FuseValues.sEfuse = sInput_FuseValues; - - result = amdgpu_atom_execute_table(adev->mode_info.atom_context, - GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); - - if (result) - return result; - - /* Finally, the actual fuse value */ - ul_RO_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); - fMin = GetScaledFraction(le32_to_cpu(sRO_fuse.ulEfuseMin), 1); - fRange = GetScaledFraction(le32_to_cpu(sRO_fuse.ulEfuseEncodeRange), 1); - fRO_fused = fDecodeLinearFuse(ul_RO_fused, fMin, fRange, sRO_fuse.ucEfuseLength); - - sCACm_fuse = getASICProfilingInfo->sCACm; - - sInput_FuseValues.usEfuseIndex = sCACm_fuse.usEfuseIndex; - sInput_FuseValues.ucBitShift = sCACm_fuse.ucEfuseBitLSB; - sInput_FuseValues.ucBitLength = sCACm_fuse.ucEfuseLength; - - sOutput_FuseValues.sEfuse = sInput_FuseValues; - - result = amdgpu_atom_execute_table(adev->mode_info.atom_context, - GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); - - if (result) - return result; - - ul_CACm_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); - fMin = GetScaledFraction(le32_to_cpu(sCACm_fuse.ulEfuseMin), 1000); - fRange = GetScaledFraction(le32_to_cpu(sCACm_fuse.ulEfuseEncodeRange), 1000); - - fCACm_fused = fDecodeLinearFuse(ul_CACm_fused, fMin, fRange, sCACm_fuse.ucEfuseLength); - - sCACb_fuse = getASICProfilingInfo->sCACb; - - sInput_FuseValues.usEfuseIndex = sCACb_fuse.usEfuseIndex; - sInput_FuseValues.ucBitShift = sCACb_fuse.ucEfuseBitLSB; - sInput_FuseValues.ucBitLength = sCACb_fuse.ucEfuseLength; - sOutput_FuseValues.sEfuse = sInput_FuseValues; - - result = amdgpu_atom_execute_table(adev->mode_info.atom_context, - GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); - - if (result) - return result; - - ul_CACb_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); - fMin = GetScaledFraction(le32_to_cpu(sCACb_fuse.ulEfuseMin), 1000); - fRange = GetScaledFraction(le32_to_cpu(sCACb_fuse.ulEfuseEncodeRange), 1000); - - fCACb_fused = fDecodeLinearFuse(ul_CACb_fused, fMin, fRange, sCACb_fuse.ucEfuseLength); - - sKt_Beta_fuse = getASICProfilingInfo->sKt_b; - - sInput_FuseValues.usEfuseIndex = sKt_Beta_fuse.usEfuseIndex; - sInput_FuseValues.ucBitShift = sKt_Beta_fuse.ucEfuseBitLSB; - sInput_FuseValues.ucBitLength = sKt_Beta_fuse.ucEfuseLength; - - sOutput_FuseValues.sEfuse = sInput_FuseValues; - - result = amdgpu_atom_execute_table(adev->mode_info.atom_context, - GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); - - if (result) - return result; - - ul_Kt_Beta_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); - fAverage = GetScaledFraction(le32_to_cpu(sKt_Beta_fuse.ulEfuseEncodeAverage), 1000); - fRange = GetScaledFraction(le32_to_cpu(sKt_Beta_fuse.ulEfuseEncodeRange), 1000); - - fKt_Beta_fused = fDecodeLogisticFuse(ul_Kt_Beta_fused, - fAverage, fRange, sKt_Beta_fuse.ucEfuseLength); - - sKv_m_fuse = getASICProfilingInfo->sKv_m; - - sInput_FuseValues.usEfuseIndex = sKv_m_fuse.usEfuseIndex; - sInput_FuseValues.ucBitShift = sKv_m_fuse.ucEfuseBitLSB; - sInput_FuseValues.ucBitLength = sKv_m_fuse.ucEfuseLength; - - sOutput_FuseValues.sEfuse = sInput_FuseValues; - - result = amdgpu_atom_execute_table(adev->mode_info.atom_context, - GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); - if (result) - return result; - - ul_Kv_m_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); - fAverage = GetScaledFraction(le32_to_cpu(sKv_m_fuse.ulEfuseEncodeAverage), 1000); - fRange = GetScaledFraction((le32_to_cpu(sKv_m_fuse.ulEfuseEncodeRange) & 0x7fffffff), 1000); - fRange = fMultiply(fRange, ConvertToFraction(-1)); - - fKv_m_fused = fDecodeLogisticFuse(ul_Kv_m_fused, - fAverage, fRange, sKv_m_fuse.ucEfuseLength); - - sKv_b_fuse = getASICProfilingInfo->sKv_b; - - sInput_FuseValues.usEfuseIndex = sKv_b_fuse.usEfuseIndex; - sInput_FuseValues.ucBitShift = sKv_b_fuse.ucEfuseBitLSB; - sInput_FuseValues.ucBitLength = sKv_b_fuse.ucEfuseLength; - sOutput_FuseValues.sEfuse = sInput_FuseValues; - - result = amdgpu_atom_execute_table(adev->mode_info.atom_context, - GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); - - if (result) - return result; - - ul_Kv_b_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); - fAverage = GetScaledFraction(le32_to_cpu(sKv_b_fuse.ulEfuseEncodeAverage), 1000); - fRange = GetScaledFraction(le32_to_cpu(sKv_b_fuse.ulEfuseEncodeRange), 1000); - - fKv_b_fused = fDecodeLogisticFuse(ul_Kv_b_fused, - fAverage, fRange, sKv_b_fuse.ucEfuseLength); - - /* Decoding the Leakage - No special struct container */ - /* - * usLkgEuseIndex=56 - * ucLkgEfuseBitLSB=6 - * ucLkgEfuseLength=10 - * ulLkgEncodeLn_MaxDivMin=69077 - * ulLkgEncodeMax=1000000 - * ulLkgEncodeMin=1000 - * ulEfuseLogisticAlpha=13 - */ - - sInput_FuseValues.usEfuseIndex = getASICProfilingInfo->usLkgEuseIndex; - sInput_FuseValues.ucBitShift = getASICProfilingInfo->ucLkgEfuseBitLSB; - sInput_FuseValues.ucBitLength = getASICProfilingInfo->ucLkgEfuseLength; - - sOutput_FuseValues.sEfuse = sInput_FuseValues; - - result = amdgpu_atom_execute_table(adev->mode_info.atom_context, - GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), - (uint32_t *)&sOutput_FuseValues, sizeof(sOutput_FuseValues)); - - if (result) - return result; - - ul_FT_Lkg_V0NORM = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); - fLn_MaxDivMin = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLkgEncodeLn_MaxDivMin), 10000); - fMin = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLkgEncodeMin), 10000); - - fFT_Lkg_V0NORM = fDecodeLeakageID(ul_FT_Lkg_V0NORM, - fLn_MaxDivMin, fMin, getASICProfilingInfo->ucLkgEfuseLength); - fLkg_FT = fFT_Lkg_V0NORM; - - /*------------------------------------------- - * PART 2 - Grabbing all required values - *------------------------------------------- - */ - fSM_A0 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A0), 1000000), - ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A0_sign))); - fSM_A1 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A1), 1000000), - ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A1_sign))); - fSM_A2 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A2), 100000), - ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A2_sign))); - fSM_A3 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A3), 1000000), - ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A3_sign))); - fSM_A4 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A4), 1000000), - ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A4_sign))); - fSM_A5 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A5), 1000), - ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A5_sign))); - fSM_A6 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A6), 1000), - ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A6_sign))); - fSM_A7 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A7), 1000), - ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A7_sign))); - - fMargin_RO_a = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_a)); - fMargin_RO_b = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_b)); - fMargin_RO_c = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_c)); - - fMargin_fixed = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_fixed)); - - fMargin_FMAX_mean = GetScaledFraction( - le32_to_cpu(getASICProfilingInfo->ulMargin_Fmax_mean), 10000); - fMargin_Plat_mean = GetScaledFraction( - le32_to_cpu(getASICProfilingInfo->ulMargin_plat_mean), 10000); - fMargin_FMAX_sigma = GetScaledFraction( - le32_to_cpu(getASICProfilingInfo->ulMargin_Fmax_sigma), 10000); - fMargin_Plat_sigma = GetScaledFraction( - le32_to_cpu(getASICProfilingInfo->ulMargin_plat_sigma), 10000); - - fMargin_DC_sigma = GetScaledFraction( - le32_to_cpu(getASICProfilingInfo->ulMargin_DC_sigma), 100); - fMargin_DC_sigma = fDivide(fMargin_DC_sigma, ConvertToFraction(1000)); - - fCACm_fused = fDivide(fCACm_fused, ConvertToFraction(100)); - fCACb_fused = fDivide(fCACb_fused, ConvertToFraction(100)); - fKt_Beta_fused = fDivide(fKt_Beta_fused, ConvertToFraction(100)); - fKv_m_fused = fNegate(fDivide(fKv_m_fused, ConvertToFraction(100))); - fKv_b_fused = fDivide(fKv_b_fused, ConvertToFraction(10)); - - fSclk = GetScaledFraction(sclk, 100); - - fV_max = fDivide(GetScaledFraction( - le32_to_cpu(getASICProfilingInfo->ulMaxVddc), 1000), ConvertToFraction(4)); - fT_prod = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulBoardCoreTemp), 10); - fLKG_Factor = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulEvvLkgFactor), 100); - fT_FT = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLeakageTemp), 10); - fV_FT = fDivide(GetScaledFraction( - le32_to_cpu(getASICProfilingInfo->ulLeakageVoltage), 1000), ConvertToFraction(4)); - fV_min = fDivide(GetScaledFraction( - le32_to_cpu(getASICProfilingInfo->ulMinVddc), 1000), ConvertToFraction(4)); - - /*----------------------- - * PART 3 - *----------------------- - */ - - fA_Term = fAdd(fMargin_RO_a, fAdd(fMultiply(fSM_A4, fSclk), fSM_A5)); - fB_Term = fAdd(fAdd(fMultiply(fSM_A2, fSclk), fSM_A6), fMargin_RO_b); - fC_Term = fAdd(fMargin_RO_c, - fAdd(fMultiply(fSM_A0, fLkg_FT), - fAdd(fMultiply(fSM_A1, fMultiply(fLkg_FT, fSclk)), - fAdd(fMultiply(fSM_A3, fSclk), - fSubtract(fSM_A7, fRO_fused))))); - - fVDDC_base = fSubtract(fRO_fused, - fSubtract(fMargin_RO_c, - fSubtract(fSM_A3, fMultiply(fSM_A1, fSclk)))); - fVDDC_base = fDivide(fVDDC_base, fAdd(fMultiply(fSM_A0, fSclk), fSM_A2)); - - repeat = fSubtract(fVDDC_base, - fDivide(fMargin_DC_sigma, ConvertToFraction(1000))); - - fRO_DC_margin = fAdd(fMultiply(fMargin_RO_a, - fGetSquare(repeat)), - fAdd(fMultiply(fMargin_RO_b, repeat), - fMargin_RO_c)); - - fDC_SCLK = fSubtract(fRO_fused, - fSubtract(fRO_DC_margin, - fSubtract(fSM_A3, - fMultiply(fSM_A2, repeat)))); - fDC_SCLK = fDivide(fDC_SCLK, fAdd(fMultiply(fSM_A0, repeat), fSM_A1)); - - fSigma_DC = fSubtract(fSclk, fDC_SCLK); - - fMicro_FMAX = fMultiply(fSclk, fMargin_FMAX_mean); - fMicro_CR = fMultiply(fSclk, fMargin_Plat_mean); - fSigma_FMAX = fMultiply(fSclk, fMargin_FMAX_sigma); - fSigma_CR = fMultiply(fSclk, fMargin_Plat_sigma); - - fSquared_Sigma_DC = fGetSquare(fSigma_DC); - fSquared_Sigma_CR = fGetSquare(fSigma_CR); - fSquared_Sigma_FMAX = fGetSquare(fSigma_FMAX); - - fSclk_margin = fAdd(fMicro_FMAX, - fAdd(fMicro_CR, - fAdd(fMargin_fixed, - fSqrt(fAdd(fSquared_Sigma_FMAX, - fAdd(fSquared_Sigma_DC, fSquared_Sigma_CR)))))); - /* - fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5; - fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6; - fC_Term = fRO_DC_margin + fSM_A0 * fLkg_FT + fSM_A1 * fLkg_FT * (fSclk + fSclk_margin) + fSM_A3 * (fSclk + fSclk_margin) + fSM_A7 - fRO_fused; - */ - - fA_Term = fAdd(fMultiply(fSM_A4, fAdd(fSclk, fSclk_margin)), fSM_A5); - fB_Term = fAdd(fMultiply(fSM_A2, fAdd(fSclk, fSclk_margin)), fSM_A6); - fC_Term = fAdd(fRO_DC_margin, - fAdd(fMultiply(fSM_A0, fLkg_FT), - fAdd(fMultiply(fMultiply(fSM_A1, fLkg_FT), - fAdd(fSclk, fSclk_margin)), - fAdd(fMultiply(fSM_A3, - fAdd(fSclk, fSclk_margin)), - fSubtract(fSM_A7, fRO_fused))))); - - SolveQuadracticEqn(fA_Term, fB_Term, fC_Term, fRoots); - - if (GreaterThan(fRoots[0], fRoots[1])) - fEVV_V = fRoots[1]; - else - fEVV_V = fRoots[0]; - - if (GreaterThan(fV_min, fEVV_V)) - fEVV_V = fV_min; - else if (GreaterThan(fEVV_V, fV_max)) - fEVV_V = fSubtract(fV_max, fStepSize); - - fEVV_V = fRoundUpByStepSize(fEVV_V, fStepSize, 0); - - /*----------------- - * PART 4 - *----------------- - */ - - fV_x = fV_min; - - while (GreaterThan(fAdd(fV_max, fStepSize), fV_x)) { - fTDP_Power_left = fMultiply(fMultiply(fMultiply(fAdd( - fMultiply(fCACm_fused, fV_x), fCACb_fused), fSclk), - fGetSquare(fV_x)), fDerateTDP); - - fTDP_Power_right = fMultiply(fFT_Lkg_V0NORM, fMultiply(fLKG_Factor, - fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused, - fT_prod), fKv_b_fused), fV_x)), fV_x))); - fTDP_Power_right = fMultiply(fTDP_Power_right, fExponential(fMultiply( - fKt_Beta_fused, fT_prod))); - fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply( - fAdd(fMultiply(fKv_m_fused, fT_prod), fKv_b_fused), fV_FT))); - fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply( - fKt_Beta_fused, fT_FT))); - - fTDP_Power = fAdd(fTDP_Power_left, fTDP_Power_right); - - fTDP_Current = fDivide(fTDP_Power, fV_x); - - fV_NL = fAdd(fV_x, fDivide(fMultiply(fTDP_Current, fRLL_LoadLine), - ConvertToFraction(10))); - - fV_NL = fRoundUpByStepSize(fV_NL, fStepSize, 0); - - if (GreaterThan(fV_max, fV_NL) && - (GreaterThan(fV_NL, fEVV_V) || - Equal(fV_NL, fEVV_V))) { - fV_NL = fMultiply(fV_NL, ConvertToFraction(1000)); - - *voltage = (uint16_t)fV_NL.partial.real; - break; - } else - fV_x = fAdd(fV_x, fStepSize); - } - - return result; -} - /** * atomctrl_get_voltage_evv_on_sclk: gets voltage via call to ATOM COMMAND table. * @hwmgr: input: pointer to hwManager diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.h index 1f987e846628b7..22b0ac12df9748 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.h @@ -316,8 +316,6 @@ extern int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr, pp_atomctrl_clock_dividers_kong *dividers); extern int atomctrl_read_efuse(struct pp_hwmgr *hwmgr, uint16_t start_index, uint16_t end_index, uint32_t *efuse); -extern int atomctrl_calculate_voltage_evv_on_sclk(struct pp_hwmgr *hwmgr, uint8_t voltage_type, - uint32_t sclk, uint16_t virtual_voltage_Id, uint16_t *voltage, uint16_t dpm_level, bool debug); extern int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr *hwmgr, uint32_t clock_value, pp_atomctrl_clock_dividers_ai *dividers); extern int atomctrl_set_ac_timing_ai(struct pp_hwmgr *hwmgr, uint32_t memory_clock, uint8_t level); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppevvmath.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppevvmath.h deleted file mode 100644 index 409aeec6baa921..00000000000000 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppevvmath.h +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Copyright 2015 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include - -enum ppevvmath_constants { - /* We multiply all original integers with 2^SHIFT_AMOUNT to get the fInt representation */ - SHIFT_AMOUNT = 16, - - /* Change this value to change the number of decimal places in the final output - 5 is a good default */ - PRECISION = 5, - - SHIFTED_2 = (2 << SHIFT_AMOUNT), - - /* 32767 - Might change in the future */ - MAX = (1 << (SHIFT_AMOUNT - 1)) - 1, -}; - -/* ------------------------------------------------------------------------------- - * NEW TYPE - fINT - * ------------------------------------------------------------------------------- - * A variable of type fInt can be accessed in 3 ways using the dot (.) operator - * fInt A; - * A.full => The full number as it is. Generally not easy to read - * A.partial.real => Only the integer portion - * A.partial.decimal => Only the fractional portion - */ -typedef union _fInt { - int full; - struct _partial { - unsigned int decimal: SHIFT_AMOUNT; /*Needs to always be unsigned*/ - int real: 32 - SHIFT_AMOUNT; - } partial; -} fInt; - -/* ------------------------------------------------------------------------------- - * Function Declarations - * ------------------------------------------------------------------------------- - */ -static fInt ConvertToFraction(int); /* Use this to convert an INT to a FINT */ -static fInt Convert_ULONG_ToFraction(uint32_t); /* Use this to convert an uint32_t to a FINT */ -static fInt GetScaledFraction(int, int); /* Use this to convert an INT to a FINT after scaling it by a factor */ -static int ConvertBackToInteger(fInt); /* Convert a FINT back to an INT that is scaled by 1000 (i.e. last 3 digits are the decimal digits) */ - -static fInt fNegate(fInt); /* Returns -1 * input fInt value */ -static fInt fAdd (fInt, fInt); /* Returns the sum of two fInt numbers */ -static fInt fSubtract (fInt A, fInt B); /* Returns A-B - Sometimes easier than Adding negative numbers */ -static fInt fMultiply (fInt, fInt); /* Returns the product of two fInt numbers */ -static fInt fDivide (fInt A, fInt B); /* Returns A/B */ -static fInt fGetSquare(fInt); /* Returns the square of a fInt number */ -static fInt fSqrt(fInt); /* Returns the Square Root of a fInt number */ - -static int uAbs(int); /* Returns the Absolute value of the Int */ -static int uPow(int base, int exponent); /* Returns base^exponent an INT */ - -static void SolveQuadracticEqn(fInt, fInt, fInt, fInt[]); /* Returns the 2 roots via the array */ -static bool Equal(fInt, fInt); /* Returns true if two fInts are equal to each other */ -static bool GreaterThan(fInt A, fInt B); /* Returns true if A > B */ - -static fInt fExponential(fInt exponent); /* Can be used to calculate e^exponent */ -static fInt fNaturalLog(fInt value); /* Can be used to calculate ln(value) */ - -/* Fuse decoding functions - * ------------------------------------------------------------------------------------- - */ -static fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength); -static fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength); -static fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength); - -/* Internal Support Functions - Use these ONLY for testing or adding to internal functions - * ------------------------------------------------------------------------------------- - * Some of the following functions take two INTs as their input - This is unsafe for a variety of reasons. - */ -static fInt Divide (int, int); /* Divide two INTs and return result as FINT */ -static fInt fNegate(fInt); - -static int uGetScaledDecimal (fInt); /* Internal function */ -static int GetReal (fInt A); /* Internal function */ - -/* ------------------------------------------------------------------------------------- - * TROUBLESHOOTING INFORMATION - * ------------------------------------------------------------------------------------- - * 1) ConvertToFraction - InputOutOfRangeException: Only accepts numbers smaller than MAX (default: 32767) - * 2) fAdd - OutputOutOfRangeException: Output bigger than MAX (default: 32767) - * 3) fMultiply - OutputOutOfRangeException: - * 4) fGetSquare - OutputOutOfRangeException: - * 5) fDivide - DivideByZeroException - * 6) fSqrt - NegativeSquareRootException: Input cannot be a negative number - */ - -/* ------------------------------------------------------------------------------------- - * START OF CODE - * ------------------------------------------------------------------------------------- - */ -static fInt fExponential(fInt exponent) /*Can be used to calculate e^exponent*/ -{ - uint32_t i; - bool bNegated = false; - - fInt fPositiveOne = ConvertToFraction(1); - fInt fZERO = ConvertToFraction(0); - - fInt lower_bound = Divide(78, 10000); - fInt solution = fPositiveOne; /*Starting off with baseline of 1 */ - fInt error_term; - - static const uint32_t k_array[11] = {55452, 27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78}; - static const uint32_t expk_array[11] = {2560000, 160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078}; - - if (GreaterThan(fZERO, exponent)) { - exponent = fNegate(exponent); - bNegated = true; - } - - while (GreaterThan(exponent, lower_bound)) { - for (i = 0; i < 11; i++) { - if (GreaterThan(exponent, GetScaledFraction(k_array[i], 10000))) { - exponent = fSubtract(exponent, GetScaledFraction(k_array[i], 10000)); - solution = fMultiply(solution, GetScaledFraction(expk_array[i], 10000)); - } - } - } - - error_term = fAdd(fPositiveOne, exponent); - - solution = fMultiply(solution, error_term); - - if (bNegated) - solution = fDivide(fPositiveOne, solution); - - return solution; -} - -static fInt fNaturalLog(fInt value) -{ - uint32_t i; - fInt upper_bound = Divide(8, 1000); - fInt fNegativeOne = ConvertToFraction(-1); - fInt solution = ConvertToFraction(0); /*Starting off with baseline of 0 */ - fInt error_term; - - static const uint32_t k_array[10] = {160000, 40000, 20000, 15000, 12500, 11250, 10625, 10313, 10156, 10078}; - static const uint32_t logk_array[10] = {27726, 13863, 6931, 4055, 2231, 1178, 606, 308, 155, 78}; - - while (GreaterThan(fAdd(value, fNegativeOne), upper_bound)) { - for (i = 0; i < 10; i++) { - if (GreaterThan(value, GetScaledFraction(k_array[i], 10000))) { - value = fDivide(value, GetScaledFraction(k_array[i], 10000)); - solution = fAdd(solution, GetScaledFraction(logk_array[i], 10000)); - } - } - } - - error_term = fAdd(fNegativeOne, value); - - return fAdd(solution, error_term); -} - -static fInt fDecodeLinearFuse(uint32_t fuse_value, fInt f_min, fInt f_range, uint32_t bitlength) -{ - fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value); - fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1); - - fInt f_decoded_value; - - f_decoded_value = fDivide(f_fuse_value, f_bit_max_value); - f_decoded_value = fMultiply(f_decoded_value, f_range); - f_decoded_value = fAdd(f_decoded_value, f_min); - - return f_decoded_value; -} - - -static fInt fDecodeLogisticFuse(uint32_t fuse_value, fInt f_average, fInt f_range, uint32_t bitlength) -{ - fInt f_fuse_value = Convert_ULONG_ToFraction(fuse_value); - fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1); - - fInt f_CONSTANT_NEG13 = ConvertToFraction(-13); - fInt f_CONSTANT1 = ConvertToFraction(1); - - fInt f_decoded_value; - - f_decoded_value = fSubtract(fDivide(f_bit_max_value, f_fuse_value), f_CONSTANT1); - f_decoded_value = fNaturalLog(f_decoded_value); - f_decoded_value = fMultiply(f_decoded_value, fDivide(f_range, f_CONSTANT_NEG13)); - f_decoded_value = fAdd(f_decoded_value, f_average); - - return f_decoded_value; -} - -static fInt fDecodeLeakageID (uint32_t leakageID_fuse, fInt ln_max_div_min, fInt f_min, uint32_t bitlength) -{ - fInt fLeakage; - fInt f_bit_max_value = Convert_ULONG_ToFraction((uPow(2, bitlength)) - 1); - - fLeakage = fMultiply(ln_max_div_min, Convert_ULONG_ToFraction(leakageID_fuse)); - fLeakage = fDivide(fLeakage, f_bit_max_value); - fLeakage = fExponential(fLeakage); - fLeakage = fMultiply(fLeakage, f_min); - - return fLeakage; -} - -static fInt ConvertToFraction(int X) /*Add all range checking here. Is it possible to make fInt a private declaration? */ -{ - fInt temp; - - if (X <= MAX) - temp.full = (X << SHIFT_AMOUNT); - else - temp.full = 0; - - return temp; -} - -static fInt fNegate(fInt X) -{ - fInt CONSTANT_NEGONE = ConvertToFraction(-1); - return fMultiply(X, CONSTANT_NEGONE); -} - -static fInt Convert_ULONG_ToFraction(uint32_t X) -{ - fInt temp; - - if (X <= MAX) - temp.full = (X << SHIFT_AMOUNT); - else - temp.full = 0; - - return temp; -} - -static fInt GetScaledFraction(int X, int factor) -{ - int times_shifted, factor_shifted; - bool bNEGATED; - fInt fValue; - - times_shifted = 0; - factor_shifted = 0; - bNEGATED = false; - - if (X < 0) { - X = -1*X; - bNEGATED = true; - } - - if (factor < 0) { - factor = -1*factor; - bNEGATED = !bNEGATED; /*If bNEGATED = true due to X < 0, this will cover the case of negative cancelling negative */ - } - - if ((X > MAX) || factor > MAX) { - if ((X/factor) <= MAX) { - while (X > MAX) { - X = X >> 1; - times_shifted++; - } - - while (factor > MAX) { - factor = factor >> 1; - factor_shifted++; - } - } else { - fValue.full = 0; - return fValue; - } - } - - if (factor == 1) - return ConvertToFraction(X); - - fValue = fDivide(ConvertToFraction(X * uPow(-1, bNEGATED)), ConvertToFraction(factor)); - - fValue.full = fValue.full << times_shifted; - fValue.full = fValue.full >> factor_shifted; - - return fValue; -} - -/* Addition using two fInts */ -static fInt fAdd (fInt X, fInt Y) -{ - fInt Sum; - - Sum.full = X.full + Y.full; - - return Sum; -} - -/* Addition using two fInts */ -static fInt fSubtract (fInt X, fInt Y) -{ - fInt Difference; - - Difference.full = X.full - Y.full; - - return Difference; -} - -static bool Equal(fInt A, fInt B) -{ - if (A.full == B.full) - return true; - else - return false; -} - -static bool GreaterThan(fInt A, fInt B) -{ - if (A.full > B.full) - return true; - else - return false; -} - -static fInt fMultiply (fInt X, fInt Y) /* Uses 64-bit integers (int64_t) */ -{ - fInt Product; - int64_t tempProduct; - - /*The following is for a very specific common case: Non-zero number with ONLY fractional portion*/ - /* TEMPORARILY DISABLED - CAN BE USED TO IMPROVE PRECISION - bool X_LessThanOne, Y_LessThanOne; - - X_LessThanOne = (X.partial.real == 0 && X.partial.decimal != 0 && X.full >= 0); - Y_LessThanOne = (Y.partial.real == 0 && Y.partial.decimal != 0 && Y.full >= 0); - - if (X_LessThanOne && Y_LessThanOne) { - Product.full = X.full * Y.full; - return Product - }*/ - - tempProduct = ((int64_t)X.full) * ((int64_t)Y.full); /*Q(16,16)*Q(16,16) = Q(32, 32) - Might become a negative number! */ - tempProduct = tempProduct >> 16; /*Remove lagging 16 bits - Will lose some precision from decimal; */ - Product.full = (int)tempProduct; /*The int64_t will lose the leading 16 bits that were part of the integer portion */ - - return Product; -} - -static fInt fDivide (fInt X, fInt Y) -{ - fInt fZERO, fQuotient; - int64_t longlongX, longlongY; - - fZERO = ConvertToFraction(0); - - if (Equal(Y, fZERO)) - return fZERO; - - longlongX = (int64_t)X.full; - longlongY = (int64_t)Y.full; - - longlongX = longlongX << 16; /*Q(16,16) -> Q(32,32) */ - - div64_s64(longlongX, longlongY); /*Q(32,32) divided by Q(16,16) = Q(16,16) Back to original format */ - - fQuotient.full = (int)longlongX; - return fQuotient; -} - -static int ConvertBackToInteger (fInt A) /*THIS is the function that will be used to check with the Golden settings table*/ -{ - fInt fullNumber, scaledDecimal, scaledReal; - - scaledReal.full = GetReal(A) * uPow(10, PRECISION-1); /* DOUBLE CHECK THISSSS!!! */ - - scaledDecimal.full = uGetScaledDecimal(A); - - fullNumber = fAdd(scaledDecimal, scaledReal); - - return fullNumber.full; -} - -static fInt fGetSquare(fInt A) -{ - return fMultiply(A, A); -} - -/* x_new = x_old - (x_old^2 - C) / (2 * x_old) */ -static fInt fSqrt(fInt num) -{ - fInt F_divide_Fprime, Fprime; - fInt test; - fInt twoShifted; - int seed, counter, error; - fInt x_new, x_old, C, y; - - fInt fZERO = ConvertToFraction(0); - - /* (0 > num) is the same as (num < 0), i.e., num is negative */ - - if (GreaterThan(fZERO, num) || Equal(fZERO, num)) - return fZERO; - - C = num; - - if (num.partial.real > 3000) - seed = 60; - else if (num.partial.real > 1000) - seed = 30; - else if (num.partial.real > 100) - seed = 10; - else - seed = 2; - - counter = 0; - - if (Equal(num, fZERO)) /*Square Root of Zero is zero */ - return fZERO; - - twoShifted = ConvertToFraction(2); - x_new = ConvertToFraction(seed); - - do { - counter++; - - x_old.full = x_new.full; - - test = fGetSquare(x_old); /*1.75*1.75 is reverting back to 1 when shifted down */ - y = fSubtract(test, C); /*y = f(x) = x^2 - C; */ - - Fprime = fMultiply(twoShifted, x_old); - F_divide_Fprime = fDivide(y, Fprime); - - x_new = fSubtract(x_old, F_divide_Fprime); - - error = ConvertBackToInteger(x_new) - ConvertBackToInteger(x_old); - - if (counter > 20) /*20 is already way too many iterations. If we dont have an answer by then, we never will*/ - return x_new; - - } while (uAbs(error) > 0); - - return x_new; -} - -static void SolveQuadracticEqn(fInt A, fInt B, fInt C, fInt Roots[]) -{ - fInt *pRoots = &Roots[0]; - fInt temp, root_first, root_second; - fInt f_CONSTANT10, f_CONSTANT100; - - f_CONSTANT100 = ConvertToFraction(100); - f_CONSTANT10 = ConvertToFraction(10); - - while (GreaterThan(A, f_CONSTANT100) || GreaterThan(B, f_CONSTANT100) || GreaterThan(C, f_CONSTANT100)) { - A = fDivide(A, f_CONSTANT10); - B = fDivide(B, f_CONSTANT10); - C = fDivide(C, f_CONSTANT10); - } - - temp = fMultiply(ConvertToFraction(4), A); /* root = 4*A */ - temp = fMultiply(temp, C); /* root = 4*A*C */ - temp = fSubtract(fGetSquare(B), temp); /* root = b^2 - 4AC */ - temp = fSqrt(temp); /*root = Sqrt (b^2 - 4AC); */ - - root_first = fSubtract(fNegate(B), temp); /* b - Sqrt(b^2 - 4AC) */ - root_second = fAdd(fNegate(B), temp); /* b + Sqrt(b^2 - 4AC) */ - - root_first = fDivide(root_first, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */ - root_first = fDivide(root_first, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */ - - root_second = fDivide(root_second, ConvertToFraction(2)); /* [b +- Sqrt(b^2 - 4AC)]/[2] */ - root_second = fDivide(root_second, A); /*[b +- Sqrt(b^2 - 4AC)]/[2*A] */ - - *(pRoots + 0) = root_first; - *(pRoots + 1) = root_second; -} - -/* ----------------------------------------------------------------------------- - * SUPPORT FUNCTIONS - * ----------------------------------------------------------------------------- - */ - -/* Conversion Functions */ -static int GetReal (fInt A) -{ - return (A.full >> SHIFT_AMOUNT); -} - -static fInt Divide (int X, int Y) -{ - fInt A, B, Quotient; - - A.full = X << SHIFT_AMOUNT; - B.full = Y << SHIFT_AMOUNT; - - Quotient = fDivide(A, B); - - return Quotient; -} - -static int uGetScaledDecimal (fInt A) /*Converts the fractional portion to whole integers - Costly function */ -{ - int dec[PRECISION]; - int i, scaledDecimal = 0, tmp = A.partial.decimal; - - for (i = 0; i < PRECISION; i++) { - dec[i] = tmp / (1 << SHIFT_AMOUNT); - tmp = tmp - ((1 << SHIFT_AMOUNT)*dec[i]); - tmp *= 10; - scaledDecimal = scaledDecimal + dec[i]*uPow(10, PRECISION - 1 - i); - } - - return scaledDecimal; -} - -static int uPow(int base, int power) -{ - if (power == 0) - return 1; - else - return (base)*uPow(base, power - 1); -} - -static int uAbs(int X) -{ - if (X < 0) - return (X * -1); - else - return X; -} - -static fInt fRoundUpByStepSize(fInt A, fInt fStepSize, bool error_term) -{ - fInt solution; - - solution = fDivide(A, fStepSize); - solution.partial.decimal = 0; /*All fractional digits changes to 0 */ - - if (error_term) - solution.partial.real += 1; /*Error term of 1 added */ - - solution = fMultiply(solution, fStepSize); - solution = fAdd(solution, fStepSize); - - return solution; -} - diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c index 79c817752a3315..2b446f8866bac0 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c @@ -62,578 +62,6 @@ static const void *get_powerplay_table(struct pp_hwmgr *hwmgr) return table_address; } -#if 0 -static void dump_pptable(PPTable_t *pptable) -{ - int i; - - pr_info("Version = 0x%08x\n", pptable->Version); - - pr_info("FeaturesToRun[0] = 0x%08x\n", pptable->FeaturesToRun[0]); - pr_info("FeaturesToRun[1] = 0x%08x\n", pptable->FeaturesToRun[1]); - - pr_info("SocketPowerLimitAc0 = %d\n", pptable->SocketPowerLimitAc0); - pr_info("SocketPowerLimitAc0Tau = %d\n", pptable->SocketPowerLimitAc0Tau); - pr_info("SocketPowerLimitAc1 = %d\n", pptable->SocketPowerLimitAc1); - pr_info("SocketPowerLimitAc1Tau = %d\n", pptable->SocketPowerLimitAc1Tau); - pr_info("SocketPowerLimitAc2 = %d\n", pptable->SocketPowerLimitAc2); - pr_info("SocketPowerLimitAc2Tau = %d\n", pptable->SocketPowerLimitAc2Tau); - pr_info("SocketPowerLimitAc3 = %d\n", pptable->SocketPowerLimitAc3); - pr_info("SocketPowerLimitAc3Tau = %d\n", pptable->SocketPowerLimitAc3Tau); - pr_info("SocketPowerLimitDc = %d\n", pptable->SocketPowerLimitDc); - pr_info("SocketPowerLimitDcTau = %d\n", pptable->SocketPowerLimitDcTau); - pr_info("TdcLimitSoc = %d\n", pptable->TdcLimitSoc); - pr_info("TdcLimitSocTau = %d\n", pptable->TdcLimitSocTau); - pr_info("TdcLimitGfx = %d\n", pptable->TdcLimitGfx); - pr_info("TdcLimitGfxTau = %d\n", pptable->TdcLimitGfxTau); - - pr_info("TedgeLimit = %d\n", pptable->TedgeLimit); - pr_info("ThotspotLimit = %d\n", pptable->ThotspotLimit); - pr_info("ThbmLimit = %d\n", pptable->ThbmLimit); - pr_info("Tvr_gfxLimit = %d\n", pptable->Tvr_gfxLimit); - pr_info("Tvr_memLimit = %d\n", pptable->Tvr_memLimit); - pr_info("Tliquid1Limit = %d\n", pptable->Tliquid1Limit); - pr_info("Tliquid2Limit = %d\n", pptable->Tliquid2Limit); - pr_info("TplxLimit = %d\n", pptable->TplxLimit); - pr_info("FitLimit = %d\n", pptable->FitLimit); - - pr_info("PpmPowerLimit = %d\n", pptable->PpmPowerLimit); - pr_info("PpmTemperatureThreshold = %d\n", pptable->PpmTemperatureThreshold); - - pr_info("MemoryOnPackage = 0x%02x\n", pptable->MemoryOnPackage); - pr_info("padding8_limits = 0x%02x\n", pptable->padding8_limits); - pr_info("Tvr_SocLimit = %d\n", pptable->Tvr_SocLimit); - - pr_info("UlvVoltageOffsetSoc = %d\n", pptable->UlvVoltageOffsetSoc); - pr_info("UlvVoltageOffsetGfx = %d\n", pptable->UlvVoltageOffsetGfx); - - pr_info("UlvSmnclkDid = %d\n", pptable->UlvSmnclkDid); - pr_info("UlvMp1clkDid = %d\n", pptable->UlvMp1clkDid); - pr_info("UlvGfxclkBypass = %d\n", pptable->UlvGfxclkBypass); - pr_info("Padding234 = 0x%02x\n", pptable->Padding234); - - pr_info("MinVoltageGfx = %d\n", pptable->MinVoltageGfx); - pr_info("MinVoltageSoc = %d\n", pptable->MinVoltageSoc); - pr_info("MaxVoltageGfx = %d\n", pptable->MaxVoltageGfx); - pr_info("MaxVoltageSoc = %d\n", pptable->MaxVoltageSoc); - - pr_info("LoadLineResistanceGfx = %d\n", pptable->LoadLineResistanceGfx); - pr_info("LoadLineResistanceSoc = %d\n", pptable->LoadLineResistanceSoc); - - pr_info("[PPCLK_GFXCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_GFXCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_GFXCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_GFXCLK].padding, - pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.c); - - pr_info("[PPCLK_VCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_VCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_VCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_VCLK].padding, - pptable->DpmDescriptor[PPCLK_VCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_VCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.c); - - pr_info("[PPCLK_DCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_DCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_DCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_DCLK].padding, - pptable->DpmDescriptor[PPCLK_DCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_DCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.c); - - pr_info("[PPCLK_ECLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_ECLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_ECLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_ECLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_ECLK].padding, - pptable->DpmDescriptor[PPCLK_ECLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_ECLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_ECLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_ECLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_ECLK].SsCurve.c); - - pr_info("[PPCLK_SOCCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_SOCCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_SOCCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_SOCCLK].padding, - pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.c); - - pr_info("[PPCLK_UCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_UCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_UCLK].padding, - pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.c); - - pr_info("[PPCLK_DCEFCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_DCEFCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_DCEFCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_DCEFCLK].padding, - pptable->DpmDescriptor[PPCLK_DCEFCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_DCEFCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_DCEFCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_DCEFCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_DCEFCLK].SsCurve.c); - - pr_info("[PPCLK_DISPCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_DISPCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_DISPCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_DISPCLK].padding, - pptable->DpmDescriptor[PPCLK_DISPCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_DISPCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_DISPCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_DISPCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_DISPCLK].SsCurve.c); - - pr_info("[PPCLK_PIXCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_PIXCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_PIXCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_PIXCLK].padding, - pptable->DpmDescriptor[PPCLK_PIXCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_PIXCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_PIXCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_PIXCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_PIXCLK].SsCurve.c); - - pr_info("[PPCLK_PHYCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_PHYCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_PHYCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_PHYCLK].padding, - pptable->DpmDescriptor[PPCLK_PHYCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_PHYCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_PHYCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_PHYCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_PHYCLK].SsCurve.c); - - pr_info("[PPCLK_FCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n", - pptable->DpmDescriptor[PPCLK_FCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_FCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_FCLK].padding, - pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.c); - - - pr_info("FreqTableGfx\n"); - for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableGfx[i]); - - pr_info("FreqTableVclk\n"); - for (i = 0; i < NUM_VCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableVclk[i]); - - pr_info("FreqTableDclk\n"); - for (i = 0; i < NUM_DCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableDclk[i]); - - pr_info("FreqTableEclk\n"); - for (i = 0; i < NUM_ECLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableEclk[i]); - - pr_info("FreqTableSocclk\n"); - for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableSocclk[i]); - - pr_info("FreqTableUclk\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableUclk[i]); - - pr_info("FreqTableFclk\n"); - for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableFclk[i]); - - pr_info("FreqTableDcefclk\n"); - for (i = 0; i < NUM_DCEFCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableDcefclk[i]); - - pr_info("FreqTableDispclk\n"); - for (i = 0; i < NUM_DISPCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableDispclk[i]); - - pr_info("FreqTablePixclk\n"); - for (i = 0; i < NUM_PIXCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTablePixclk[i]); - - pr_info("FreqTablePhyclk\n"); - for (i = 0; i < NUM_PHYCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTablePhyclk[i]); - - pr_info("DcModeMaxFreq[PPCLK_GFXCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_GFXCLK]); - pr_info("DcModeMaxFreq[PPCLK_VCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_VCLK]); - pr_info("DcModeMaxFreq[PPCLK_DCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_DCLK]); - pr_info("DcModeMaxFreq[PPCLK_ECLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_ECLK]); - pr_info("DcModeMaxFreq[PPCLK_SOCCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_SOCCLK]); - pr_info("DcModeMaxFreq[PPCLK_UCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_UCLK]); - pr_info("DcModeMaxFreq[PPCLK_DCEFCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_DCEFCLK]); - pr_info("DcModeMaxFreq[PPCLK_DISPCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_DISPCLK]); - pr_info("DcModeMaxFreq[PPCLK_PIXCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_PIXCLK]); - pr_info("DcModeMaxFreq[PPCLK_PHYCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_PHYCLK]); - pr_info("DcModeMaxFreq[PPCLK_FCLK] = %d\n", pptable->DcModeMaxFreq[PPCLK_FCLK]); - pr_info("Padding8_Clks = %d\n", pptable->Padding8_Clks); - - pr_info("Mp0clkFreq\n"); - for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->Mp0clkFreq[i]); - - pr_info("Mp0DpmVoltage\n"); - for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->Mp0DpmVoltage[i]); - - pr_info("GfxclkFidle = 0x%x\n", pptable->GfxclkFidle); - pr_info("GfxclkSlewRate = 0x%x\n", pptable->GfxclkSlewRate); - pr_info("CksEnableFreq = 0x%x\n", pptable->CksEnableFreq); - pr_info("Padding789 = 0x%x\n", pptable->Padding789); - pr_info("CksVoltageOffset[a = 0x%08x b = 0x%08x c = 0x%08x]\n", - pptable->CksVoltageOffset.a, - pptable->CksVoltageOffset.b, - pptable->CksVoltageOffset.c); - pr_info("Padding567[0] = 0x%x\n", pptable->Padding567[0]); - pr_info("Padding567[1] = 0x%x\n", pptable->Padding567[1]); - pr_info("Padding567[2] = 0x%x\n", pptable->Padding567[2]); - pr_info("Padding567[3] = 0x%x\n", pptable->Padding567[3]); - pr_info("GfxclkDsMaxFreq = %d\n", pptable->GfxclkDsMaxFreq); - pr_info("GfxclkSource = 0x%x\n", pptable->GfxclkSource); - pr_info("Padding456 = 0x%x\n", pptable->Padding456); - - pr_info("LowestUclkReservedForUlv = %d\n", pptable->LowestUclkReservedForUlv); - pr_info("Padding8_Uclk[0] = 0x%x\n", pptable->Padding8_Uclk[0]); - pr_info("Padding8_Uclk[1] = 0x%x\n", pptable->Padding8_Uclk[1]); - pr_info("Padding8_Uclk[2] = 0x%x\n", pptable->Padding8_Uclk[2]); - - pr_info("PcieGenSpeed\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->PcieGenSpeed[i]); - - pr_info("PcieLaneCount\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->PcieLaneCount[i]); - - pr_info("LclkFreq\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->LclkFreq[i]); - - pr_info("EnableTdpm = %d\n", pptable->EnableTdpm); - pr_info("TdpmHighHystTemperature = %d\n", pptable->TdpmHighHystTemperature); - pr_info("TdpmLowHystTemperature = %d\n", pptable->TdpmLowHystTemperature); - pr_info("GfxclkFreqHighTempLimit = %d\n", pptable->GfxclkFreqHighTempLimit); - - pr_info("FanStopTemp = %d\n", pptable->FanStopTemp); - pr_info("FanStartTemp = %d\n", pptable->FanStartTemp); - - pr_info("FanGainEdge = %d\n", pptable->FanGainEdge); - pr_info("FanGainHotspot = %d\n", pptable->FanGainHotspot); - pr_info("FanGainLiquid = %d\n", pptable->FanGainLiquid); - pr_info("FanGainVrGfx = %d\n", pptable->FanGainVrGfx); - pr_info("FanGainVrSoc = %d\n", pptable->FanGainVrSoc); - pr_info("FanGainPlx = %d\n", pptable->FanGainPlx); - pr_info("FanGainHbm = %d\n", pptable->FanGainHbm); - pr_info("FanPwmMin = %d\n", pptable->FanPwmMin); - pr_info("FanAcousticLimitRpm = %d\n", pptable->FanAcousticLimitRpm); - pr_info("FanThrottlingRpm = %d\n", pptable->FanThrottlingRpm); - pr_info("FanMaximumRpm = %d\n", pptable->FanMaximumRpm); - pr_info("FanTargetTemperature = %d\n", pptable->FanTargetTemperature); - pr_info("FanTargetGfxclk = %d\n", pptable->FanTargetGfxclk); - pr_info("FanZeroRpmEnable = %d\n", pptable->FanZeroRpmEnable); - pr_info("FanTachEdgePerRev = %d\n", pptable->FanTachEdgePerRev); - - pr_info("FuzzyFan_ErrorSetDelta = %d\n", pptable->FuzzyFan_ErrorSetDelta); - pr_info("FuzzyFan_ErrorRateSetDelta = %d\n", pptable->FuzzyFan_ErrorRateSetDelta); - pr_info("FuzzyFan_PwmSetDelta = %d\n", pptable->FuzzyFan_PwmSetDelta); - pr_info("FuzzyFan_Reserved = %d\n", pptable->FuzzyFan_Reserved); - - pr_info("OverrideAvfsGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_GFX]); - pr_info("OverrideAvfsGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_SOC]); - pr_info("Padding8_Avfs[0] = %d\n", pptable->Padding8_Avfs[0]); - pr_info("Padding8_Avfs[1] = %d\n", pptable->Padding8_Avfs[1]); - - pr_info("qAvfsGb[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].a, - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].b, - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].c); - pr_info("qAvfsGb[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].a, - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].b, - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].c); - pr_info("dBtcGbGfxCksOn{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxCksOn.a, - pptable->dBtcGbGfxCksOn.b, - pptable->dBtcGbGfxCksOn.c); - pr_info("dBtcGbGfxCksOff{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxCksOff.a, - pptable->dBtcGbGfxCksOff.b, - pptable->dBtcGbGfxCksOff.c); - pr_info("dBtcGbGfxAfll{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxAfll.a, - pptable->dBtcGbGfxAfll.b, - pptable->dBtcGbGfxAfll.c); - pr_info("dBtcGbSoc{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbSoc.a, - pptable->dBtcGbSoc.b, - pptable->dBtcGbSoc.c); - pr_info("qAgingGb[AVFS_VOLTAGE_GFX]{m = 0x%x b = 0x%x}\n", - pptable->qAgingGb[AVFS_VOLTAGE_GFX].m, - pptable->qAgingGb[AVFS_VOLTAGE_GFX].b); - pr_info("qAgingGb[AVFS_VOLTAGE_SOC]{m = 0x%x b = 0x%x}\n", - pptable->qAgingGb[AVFS_VOLTAGE_SOC].m, - pptable->qAgingGb[AVFS_VOLTAGE_SOC].b); - - pr_info("qStaticVoltageOffset[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].a, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].b, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].c); - pr_info("qStaticVoltageOffset[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].a, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].b, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].c); - - pr_info("DcTol[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_GFX]); - pr_info("DcTol[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_SOC]); - - pr_info("DcBtcEnabled[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_GFX]); - pr_info("DcBtcEnabled[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_SOC]); - pr_info("Padding8_GfxBtc[0] = 0x%x\n", pptable->Padding8_GfxBtc[0]); - pr_info("Padding8_GfxBtc[1] = 0x%x\n", pptable->Padding8_GfxBtc[1]); - - pr_info("DcBtcMin[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_GFX]); - pr_info("DcBtcMin[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_SOC]); - pr_info("DcBtcMax[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_GFX]); - pr_info("DcBtcMax[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_SOC]); - - pr_info("XgmiLinkSpeed\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiLinkSpeed[i]); - pr_info("XgmiLinkWidth\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiLinkWidth[i]); - pr_info("XgmiFclkFreq\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiFclkFreq[i]); - pr_info("XgmiUclkFreq\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiUclkFreq[i]); - pr_info("XgmiSocclkFreq\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiSocclkFreq[i]); - pr_info("XgmiSocVoltage\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiSocVoltage[i]); - - pr_info("DebugOverrides = 0x%x\n", pptable->DebugOverrides); - pr_info("ReservedEquation0{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation0.a, - pptable->ReservedEquation0.b, - pptable->ReservedEquation0.c); - pr_info("ReservedEquation1{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation1.a, - pptable->ReservedEquation1.b, - pptable->ReservedEquation1.c); - pr_info("ReservedEquation2{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation2.a, - pptable->ReservedEquation2.b, - pptable->ReservedEquation2.c); - pr_info("ReservedEquation3{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation3.a, - pptable->ReservedEquation3.b, - pptable->ReservedEquation3.c); - - pr_info("MinVoltageUlvGfx = %d\n", pptable->MinVoltageUlvGfx); - pr_info("MinVoltageUlvSoc = %d\n", pptable->MinVoltageUlvSoc); - - pr_info("MGpuFanBoostLimitRpm = %d\n", pptable->MGpuFanBoostLimitRpm); - pr_info("padding16_Fan = %d\n", pptable->padding16_Fan); - - pr_info("FanGainVrMem0 = %d\n", pptable->FanGainVrMem0); - pr_info("FanGainVrMem0 = %d\n", pptable->FanGainVrMem0); - - pr_info("DcBtcGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_GFX]); - pr_info("DcBtcGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_SOC]); - - for (i = 0; i < 11; i++) - pr_info("Reserved[%d] = 0x%x\n", i, pptable->Reserved[i]); - - for (i = 0; i < 3; i++) - pr_info("Padding32[%d] = 0x%x\n", i, pptable->Padding32[i]); - - pr_info("MaxVoltageStepGfx = 0x%x\n", pptable->MaxVoltageStepGfx); - pr_info("MaxVoltageStepSoc = 0x%x\n", pptable->MaxVoltageStepSoc); - - pr_info("VddGfxVrMapping = 0x%x\n", pptable->VddGfxVrMapping); - pr_info("VddSocVrMapping = 0x%x\n", pptable->VddSocVrMapping); - pr_info("VddMem0VrMapping = 0x%x\n", pptable->VddMem0VrMapping); - pr_info("VddMem1VrMapping = 0x%x\n", pptable->VddMem1VrMapping); - - pr_info("GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); - pr_info("SocUlvPhaseSheddingMask = 0x%x\n", pptable->SocUlvPhaseSheddingMask); - pr_info("ExternalSensorPresent = 0x%x\n", pptable->ExternalSensorPresent); - pr_info("Padding8_V = 0x%x\n", pptable->Padding8_V); - - pr_info("GfxMaxCurrent = 0x%x\n", pptable->GfxMaxCurrent); - pr_info("GfxOffset = 0x%x\n", pptable->GfxOffset); - pr_info("Padding_TelemetryGfx = 0x%x\n", pptable->Padding_TelemetryGfx); - - pr_info("SocMaxCurrent = 0x%x\n", pptable->SocMaxCurrent); - pr_info("SocOffset = 0x%x\n", pptable->SocOffset); - pr_info("Padding_TelemetrySoc = 0x%x\n", pptable->Padding_TelemetrySoc); - - pr_info("Mem0MaxCurrent = 0x%x\n", pptable->Mem0MaxCurrent); - pr_info("Mem0Offset = 0x%x\n", pptable->Mem0Offset); - pr_info("Padding_TelemetryMem0 = 0x%x\n", pptable->Padding_TelemetryMem0); - - pr_info("Mem1MaxCurrent = 0x%x\n", pptable->Mem1MaxCurrent); - pr_info("Mem1Offset = 0x%x\n", pptable->Mem1Offset); - pr_info("Padding_TelemetryMem1 = 0x%x\n", pptable->Padding_TelemetryMem1); - - pr_info("AcDcGpio = %d\n", pptable->AcDcGpio); - pr_info("AcDcPolarity = %d\n", pptable->AcDcPolarity); - pr_info("VR0HotGpio = %d\n", pptable->VR0HotGpio); - pr_info("VR0HotPolarity = %d\n", pptable->VR0HotPolarity); - - pr_info("VR1HotGpio = %d\n", pptable->VR1HotGpio); - pr_info("VR1HotPolarity = %d\n", pptable->VR1HotPolarity); - pr_info("Padding1 = 0x%x\n", pptable->Padding1); - pr_info("Padding2 = 0x%x\n", pptable->Padding2); - - pr_info("LedPin0 = %d\n", pptable->LedPin0); - pr_info("LedPin1 = %d\n", pptable->LedPin1); - pr_info("LedPin2 = %d\n", pptable->LedPin2); - pr_info("padding8_4 = 0x%x\n", pptable->padding8_4); - - pr_info("PllGfxclkSpreadEnabled = %d\n", pptable->PllGfxclkSpreadEnabled); - pr_info("PllGfxclkSpreadPercent = %d\n", pptable->PllGfxclkSpreadPercent); - pr_info("PllGfxclkSpreadFreq = %d\n", pptable->PllGfxclkSpreadFreq); - - pr_info("UclkSpreadEnabled = %d\n", pptable->UclkSpreadEnabled); - pr_info("UclkSpreadPercent = %d\n", pptable->UclkSpreadPercent); - pr_info("UclkSpreadFreq = %d\n", pptable->UclkSpreadFreq); - - pr_info("FclkSpreadEnabled = %d\n", pptable->FclkSpreadEnabled); - pr_info("FclkSpreadPercent = %d\n", pptable->FclkSpreadPercent); - pr_info("FclkSpreadFreq = %d\n", pptable->FclkSpreadFreq); - - pr_info("FllGfxclkSpreadEnabled = %d\n", pptable->FllGfxclkSpreadEnabled); - pr_info("FllGfxclkSpreadPercent = %d\n", pptable->FllGfxclkSpreadPercent); - pr_info("FllGfxclkSpreadFreq = %d\n", pptable->FllGfxclkSpreadFreq); - - for (i = 0; i < I2C_CONTROLLER_NAME_COUNT; i++) { - pr_info("I2cControllers[%d]:\n", i); - pr_info(" .Enabled = %d\n", - pptable->I2cControllers[i].Enabled); - pr_info(" .SlaveAddress = 0x%x\n", - pptable->I2cControllers[i].SlaveAddress); - pr_info(" .ControllerPort = %d\n", - pptable->I2cControllers[i].ControllerPort); - pr_info(" .ControllerName = %d\n", - pptable->I2cControllers[i].ControllerName); - pr_info(" .ThermalThrottler = %d\n", - pptable->I2cControllers[i].ThermalThrottler); - pr_info(" .I2cProtocol = %d\n", - pptable->I2cControllers[i].I2cProtocol); - pr_info(" .I2cSpeed = %d\n", - pptable->I2cControllers[i].I2cSpeed); - } - - for (i = 0; i < 10; i++) - pr_info("BoardReserved[%d] = 0x%x\n", i, pptable->BoardReserved[i]); - - for (i = 0; i < 8; i++) - pr_info("MmHubPadding[%d] = 0x%x\n", i, pptable->MmHubPadding[i]); -} -#endif - static int check_powerplay_tables( struct pp_hwmgr *hwmgr, const ATOM_Vega20_POWERPLAYTABLE *powerplay_table) @@ -652,8 +80,6 @@ static int check_powerplay_tables( return -EINVAL; } - //dump_pptable(&powerplay_table->smcPPTable); - return 0; } diff --git a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c index b52ce135d84d46..d3ff6a831ed5dc 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/vega12_smumgr.c @@ -257,20 +257,18 @@ static int vega12_smu_init(struct pp_hwmgr *hwmgr) priv->smu_tables.entry[TABLE_WATERMARKS].size = sizeof(Watermarks_t); tools_size = 0x19000; - if (tools_size) { - ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, - tools_size, - PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM, - &priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle, - &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr, - &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table); - if (ret) - goto err1; + ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, + tools_size, + PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].handle, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].mc_addr, + &priv->smu_tables.entry[TABLE_PMSTATUSLOG].table); + if (ret) + goto err1; - priv->smu_tables.entry[TABLE_PMSTATUSLOG].version = 0x01; - priv->smu_tables.entry[TABLE_PMSTATUSLOG].size = tools_size; - } + priv->smu_tables.entry[TABLE_PMSTATUSLOG].version = 0x01; + priv->smu_tables.entry[TABLE_PMSTATUSLOG].size = tools_size; /* allocate space for AVFS Fuse table */ ret = amdgpu_bo_create_kernel((struct amdgpu_device *)hwmgr->adev, diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 80e60ea2d11e3c..21bd635bcdfc15 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -72,6 +72,10 @@ static int smu_set_power_limit(void *handle, uint32_t limit); static int smu_set_fan_speed_rpm(void *handle, uint32_t speed); static int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled); static int smu_set_mp1_state(void *handle, enum pp_mp1_state mp1_state); +static void smu_power_profile_mode_get(struct smu_context *smu, + enum PP_SMC_POWER_PROFILE profile_mode); +static void smu_power_profile_mode_put(struct smu_context *smu, + enum PP_SMC_POWER_PROFILE profile_mode); static int smu_sys_get_pp_feature_mask(void *handle, char *buf) @@ -140,7 +144,8 @@ int smu_set_soft_freq_range(struct smu_context *smu, ret = smu->ppt_funcs->set_soft_freq_limited_range(smu, clk_type, min, - max); + max, + false); return ret; } @@ -251,7 +256,7 @@ static int smu_dpm_set_vcn_enable(struct smu_context *smu, if (atomic_read(&power_gate->vcn_gated) ^ enable) return 0; - ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable); + ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable, 0xff); if (!ret) atomic_set(&power_gate->vcn_gated, !enable); @@ -549,7 +554,8 @@ bool is_support_sw_smu(struct amdgpu_device *adev) if (adev->asic_type == CHIP_VEGA20) return false; - if (amdgpu_ip_version(adev, MP1_HWIP, 0) >= IP_VERSION(11, 0, 0)) + if ((amdgpu_ip_version(adev, MP1_HWIP, 0) >= IP_VERSION(11, 0, 0)) && + amdgpu_device_ip_is_valid(adev, AMD_IP_BLOCK_TYPE_SMC)) return true; return false; @@ -741,9 +747,9 @@ static int smu_set_funcs(struct amdgpu_device *adev) return 0; } -static int smu_early_init(void *handle) +static int smu_early_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu; int r; @@ -758,6 +764,7 @@ static int smu_early_init(void *handle) smu->smu_baco.platform_support = false; smu->smu_baco.maco_support = false; smu->user_dpm_profile.fan_mode = -1; + smu->power_profile_mode = PP_SMC_POWER_PROFILE_UNKNOWN; mutex_init(&smu->message_lock); @@ -825,9 +832,9 @@ static int smu_apply_default_config_table_settings(struct smu_context *smu) return smu_set_config_table(smu, &adev->pm.config_table); } -static int smu_late_init(void *handle) +static int smu_late_init(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; int ret = 0; @@ -1242,9 +1249,24 @@ static bool smu_is_workload_profile_available(struct smu_context *smu, return smu->workload_map && smu->workload_map[profile].valid_mapping; } -static int smu_sw_init(void *handle) +static void smu_init_power_profile(struct smu_context *smu) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_UNKNOWN) { + if (smu->is_apu || + !smu_is_workload_profile_available( + smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D)) + smu->power_profile_mode = + PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; + else + smu->power_profile_mode = + PP_SMC_POWER_PROFILE_FULLSCREEN3D; + } + smu_power_profile_mode_get(smu, smu->power_profile_mode); +} + +static int smu_sw_init(struct amdgpu_ip_block *ip_block) +{ + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; int ret; @@ -1257,35 +1279,13 @@ static int smu_sw_init(void *handle) INIT_WORK(&smu->interrupt_work, smu_interrupt_work_fn); atomic64_set(&smu->throttle_int_counter, 0); smu->watermarks_bitmap = 0; - smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; - smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; atomic_set(&smu->smu_power.power_gate.vcn_gated, 1); atomic_set(&smu->smu_power.power_gate.jpeg_gated, 1); atomic_set(&smu->smu_power.power_gate.vpe_gated, 1); atomic_set(&smu->smu_power.power_gate.umsch_mm_gated, 1); - smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0; - smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1; - smu->workload_prority[PP_SMC_POWER_PROFILE_POWERSAVING] = 2; - smu->workload_prority[PP_SMC_POWER_PROFILE_VIDEO] = 3; - smu->workload_prority[PP_SMC_POWER_PROFILE_VR] = 4; - smu->workload_prority[PP_SMC_POWER_PROFILE_COMPUTE] = 5; - smu->workload_prority[PP_SMC_POWER_PROFILE_CUSTOM] = 6; - - if (smu->is_apu || - !smu_is_workload_profile_available(smu, PP_SMC_POWER_PROFILE_FULLSCREEN3D)) - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT]; - else - smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D]; - - smu->workload_setting[0] = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; - smu->workload_setting[1] = PP_SMC_POWER_PROFILE_FULLSCREEN3D; - smu->workload_setting[2] = PP_SMC_POWER_PROFILE_POWERSAVING; - smu->workload_setting[3] = PP_SMC_POWER_PROFILE_VIDEO; - smu->workload_setting[4] = PP_SMC_POWER_PROFILE_VR; - smu->workload_setting[5] = PP_SMC_POWER_PROFILE_COMPUTE; - smu->workload_setting[6] = PP_SMC_POWER_PROFILE_CUSTOM; + smu_init_power_profile(smu); smu->display_config = &adev->pm.pm_display_cfg; smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; @@ -1326,9 +1326,9 @@ static int smu_sw_init(void *handle) return 0; } -static int smu_sw_fini(void *handle) +static int smu_sw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; int ret; @@ -1338,6 +1338,11 @@ static int smu_sw_fini(void *handle) return ret; } + if (smu->custom_profile_params) { + kfree(smu->custom_profile_params); + smu->custom_profile_params = NULL; + } + smu_fini_microcode(smu); return 0; @@ -1695,7 +1700,9 @@ static int smu_smc_hw_setup(struct smu_context *smu) return ret; } - if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4) + if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN5) + pcie_gen = 4; + else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4) pcie_gen = 3; else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) pcie_gen = 2; @@ -1708,7 +1715,9 @@ static int smu_smc_hw_setup(struct smu_context *smu) * Bit 15:8: PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4 * Bit 7:0: PCIE lane width, 1 to 7 corresponds is x1 to x32 */ - if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16) + if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X32) + pcie_width = 7; + else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16) pcie_width = 6; else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12) pcie_width = 5; @@ -1799,10 +1808,10 @@ static int smu_start_smc_engine(struct smu_context *smu) return ret; } -static int smu_hw_init(void *handle) +static int smu_hw_init(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) { @@ -2021,9 +2030,9 @@ static int smu_reset_mp1_state(struct smu_context *smu) return ret; } -static int smu_hw_fini(void *handle) +static int smu_hw_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; int ret; @@ -2054,9 +2063,9 @@ static int smu_hw_fini(void *handle) return 0; } -static void smu_late_fini(void *handle) +static void smu_late_fini(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = handle; + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; kfree(smu); @@ -2065,26 +2074,31 @@ static void smu_late_fini(void *handle) static int smu_reset(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; + struct amdgpu_ip_block *ip_block; int ret; - ret = smu_hw_fini(adev); + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_SMC); + if (!ip_block) + return -EINVAL; + + ret = smu_hw_fini(ip_block); if (ret) return ret; - ret = smu_hw_init(adev); + ret = smu_hw_init(ip_block); if (ret) return ret; - ret = smu_late_init(adev); + ret = smu_late_init(ip_block); if (ret) return ret; return 0; } -static int smu_suspend(void *handle) +static int smu_suspend(struct amdgpu_ip_block *ip_block) { - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; int ret; uint64_t count; @@ -2113,13 +2127,16 @@ static int smu_suspend(void *handle) if (!ret) adev->gfx.gfx_off_entrycount = count; + /* clear this on suspend so it will get reprogrammed on resume */ + smu->workload_mask = 0; + return 0; } -static int smu_resume(void *handle) +static int smu_resume(struct amdgpu_ip_block *ip_block) { int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_device *adev = ip_block->adev; struct smu_context *smu = adev->powerplay.pp_handle; if (amdgpu_sriov_vf(adev)&& !amdgpu_sriov_is_pp_one_vf(adev)) @@ -2225,25 +2242,49 @@ static int smu_enable_umd_pstate(void *handle, } static int smu_bump_power_profile_mode(struct smu_context *smu, - long *param, - uint32_t param_size) + long *custom_params, + u32 custom_params_max_idx) { - int ret = 0; + u32 workload_mask = 0; + int i, ret = 0; + + for (i = 0; i < PP_SMC_POWER_PROFILE_COUNT; i++) { + if (smu->workload_refcount[i]) + workload_mask |= 1 << i; + } + + if (smu->workload_mask == workload_mask) + return 0; if (smu->ppt_funcs->set_power_profile_mode) - ret = smu->ppt_funcs->set_power_profile_mode(smu, param, param_size); + ret = smu->ppt_funcs->set_power_profile_mode(smu, workload_mask, + custom_params, + custom_params_max_idx); + + if (!ret) + smu->workload_mask = workload_mask; return ret; } +static void smu_power_profile_mode_get(struct smu_context *smu, + enum PP_SMC_POWER_PROFILE profile_mode) +{ + smu->workload_refcount[profile_mode]++; +} + +static void smu_power_profile_mode_put(struct smu_context *smu, + enum PP_SMC_POWER_PROFILE profile_mode) +{ + if (smu->workload_refcount[profile_mode]) + smu->workload_refcount[profile_mode]--; +} + static int smu_adjust_power_state_dynamic(struct smu_context *smu, enum amd_dpm_forced_level level, - bool skip_display_settings, - bool init) + bool skip_display_settings) { int ret = 0; - int index = 0; - long workload[1]; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); if (!skip_display_settings) { @@ -2280,14 +2321,8 @@ static int smu_adjust_power_state_dynamic(struct smu_context *smu, } if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL && - smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) { - index = fls(smu->workload_mask); - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; - workload[0] = smu->workload_setting[index]; - - if (init || smu->power_profile_mode != workload[0]) - smu_bump_power_profile_mode(smu, workload, 0); - } + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) + smu_bump_power_profile_mode(smu, NULL, 0); return ret; } @@ -2306,13 +2341,13 @@ static int smu_handle_task(struct smu_context *smu, ret = smu_pre_display_config_changed(smu); if (ret) return ret; - ret = smu_adjust_power_state_dynamic(smu, level, false, false); + ret = smu_adjust_power_state_dynamic(smu, level, false); break; case AMD_PP_TASK_COMPLETE_INIT: - ret = smu_adjust_power_state_dynamic(smu, level, true, true); + ret = smu_adjust_power_state_dynamic(smu, level, true); break; case AMD_PP_TASK_READJUST_POWER_STATE: - ret = smu_adjust_power_state_dynamic(smu, level, true, false); + ret = smu_adjust_power_state_dynamic(smu, level, true); break; default: break; @@ -2334,12 +2369,11 @@ static int smu_handle_dpm_task(void *handle, static int smu_switch_power_profile(void *handle, enum PP_SMC_POWER_PROFILE type, - bool en) + bool enable) { struct smu_context *smu = handle; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - long workload[1]; - uint32_t index; + int ret; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; @@ -2347,21 +2381,21 @@ static int smu_switch_power_profile(void *handle, if (!(type < PP_SMC_POWER_PROFILE_CUSTOM)) return -EINVAL; - if (!en) { - smu->workload_mask &= ~(1 << smu->workload_prority[type]); - index = fls(smu->workload_mask); - index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; - workload[0] = smu->workload_setting[index]; - } else { - smu->workload_mask |= (1 << smu->workload_prority[type]); - index = fls(smu->workload_mask); - index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; - workload[0] = smu->workload_setting[index]; - } - if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL && - smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) - smu_bump_power_profile_mode(smu, workload, 0); + smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_PERF_DETERMINISM) { + if (enable) + smu_power_profile_mode_get(smu, type); + else + smu_power_profile_mode_put(smu, type); + ret = smu_bump_power_profile_mode(smu, NULL, 0); + if (ret) { + if (enable) + smu_power_profile_mode_put(smu, type); + else + smu_power_profile_mode_get(smu, type); + return ret; + } + } return 0; } @@ -2878,6 +2912,10 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type) clk_type = SMU_OD_FAN_TARGET_TEMPERATURE; break; case OD_FAN_MINIMUM_PWM: clk_type = SMU_OD_FAN_MINIMUM_PWM; break; + case OD_FAN_ZERO_RPM_ENABLE: + clk_type = SMU_OD_FAN_ZERO_RPM_ENABLE; break; + case OD_FAN_ZERO_RPM_STOP_TEMP: + clk_type = SMU_OD_FAN_ZERO_RPM_STOP_TEMP; break; default: clk_type = SMU_CLK_COUNT; break; } @@ -3049,12 +3087,35 @@ static int smu_set_power_profile_mode(void *handle, uint32_t param_size) { struct smu_context *smu = handle; + bool custom = false; + int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled || !smu->ppt_funcs->set_power_profile_mode) return -EOPNOTSUPP; - return smu_bump_power_profile_mode(smu, param, param_size); + if (param[param_size] == PP_SMC_POWER_PROFILE_CUSTOM) { + custom = true; + /* clear frontend mask so custom changes propogate */ + smu->workload_mask = 0; + } + + if ((param[param_size] != smu->power_profile_mode) || custom) { + /* clear the old user preference */ + smu_power_profile_mode_put(smu, smu->power_profile_mode); + /* set the new user preference */ + smu_power_profile_mode_get(smu, param[param_size]); + ret = smu_bump_power_profile_mode(smu, + custom ? param : NULL, + custom ? param_size : 0); + if (ret) + smu_power_profile_mode_put(smu, param[param_size]); + else + /* store the user's preference */ + smu->power_profile_mode = param[param_size]; + } + + return ret; } static int smu_get_fan_control_mode(void *handle, u32 *fan_mode) diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index b44a185d07e84c..3925815358ce98 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -556,11 +556,13 @@ struct smu_context { uint32_t hard_min_uclk_req_from_dal; bool disable_uclk_switch; + /* asic agnostic workload mask */ uint32_t workload_mask; - uint32_t workload_prority[WORKLOAD_POLICY_MAX]; - uint32_t workload_setting[WORKLOAD_POLICY_MAX]; + /* default/user workload preference */ uint32_t power_profile_mode; - uint32_t default_power_profile_mode; + uint32_t workload_refcount[PP_SMC_POWER_PROFILE_COUNT]; + /* backend specific custom workload settings */ + long *custom_profile_params; bool pm_enabled; bool is_apu; @@ -731,15 +733,18 @@ struct pptable_funcs { * @set_power_profile_mode: Set a power profile mode. Also used to * create/set custom power profile modes. * &input: Power profile mode parameters. - * &size: Size of &input. + * &workload_mask: mask of workloads to enable + * &custom_params: custom profile parameters + * &custom_params_max_idx: max valid idx into custom_params */ - int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size); + int (*set_power_profile_mode)(struct smu_context *smu, u32 workload_mask, + long *custom_params, u32 custom_params_max_idx); /** * @dpm_set_vcn_enable: Enable/disable VCN engine dynamic power * management. */ - int (*dpm_set_vcn_enable)(struct smu_context *smu, bool enable); + int (*dpm_set_vcn_enable)(struct smu_context *smu, bool enable, int inst); /** * @dpm_set_jpeg_enable: Enable/disable JPEG engine dynamic power @@ -858,11 +863,6 @@ struct pptable_funcs { */ int (*display_disable_memory_clock_switch)(struct smu_context *smu, bool disable_memory_clock_switch); - /** - * @dump_pptable: Print the power play table to the system log. - */ - void (*dump_pptable)(struct smu_context *smu); - /** * @get_power_limit: Get the device's power limits. */ @@ -1260,7 +1260,8 @@ struct pptable_funcs { * @set_soft_freq_limited_range: Set the soft frequency range of a clock * domain in MHz. */ - int (*set_soft_freq_limited_range)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max); + int (*set_soft_freq_limited_range)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max, + bool automatic); /** * @set_power_source: Notify the SMU of the current power source. diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h index 822c6425d90e0e..0f96b8c59a0e01 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_6_pmfw.h @@ -123,7 +123,7 @@ typedef enum { VOLTAGE_GUARDBAND_COUNT } GFX_GUARDBAND_e; -#define SMU_METRICS_TABLE_VERSION 0xD +#define SMU_METRICS_TABLE_VERSION 0xE typedef struct __attribute__((packed, aligned(4))) { uint32_t AccumulationCounter; @@ -231,6 +231,9 @@ typedef struct __attribute__((packed, aligned(4))) { // PER XCD ACTIVITY uint32_t GfxBusy[8]; uint64_t GfxBusyAcc[8]; + + //PCIE BW Data and error count + uint32_t PCIeOtherEndRecoveryAcc; // The Pcie counter itself is accumulated } MetricsTableX_t; typedef struct __attribute__((packed, aligned(4))) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h index e71a721c12b985..a299dc4a807149 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -313,6 +313,8 @@ enum smu_clk_type { SMU_OD_ACOUSTIC_TARGET, SMU_OD_FAN_TARGET_TEMPERATURE, SMU_OD_FAN_MINIMUM_PWM, + SMU_OD_FAN_ZERO_RPM_ENABLE, + SMU_OD_FAN_ZERO_RPM_STOP_TEMP, SMU_CLK_COUNT, }; diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h index c2ab336bb53080..ed8304d828314a 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h @@ -255,7 +255,7 @@ int smu_v11_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c uint32_t *min, uint32_t *max); int smu_v11_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, uint32_t max); + uint32_t min, uint32_t max, bool automatic); int smu_v11_0_set_hard_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h index 1ad2dff71090b0..0886d8cffbd0a6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v12_0.h @@ -56,7 +56,7 @@ int smu_v12_0_set_default_dpm_tables(struct smu_context *smu); int smu_v12_0_mode2_reset(struct smu_context *smu); int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, uint32_t max); + uint32_t min, uint32_t max, bool automatic); int smu_v12_0_set_driver_table_location(struct smu_context *smu); 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 e58220a7ee2f70..ae3563d71fa0c7 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 @@ -219,7 +219,7 @@ int smu_v13_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c uint32_t *min, uint32_t *max); int smu_v13_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, uint32_t max); + uint32_t min, uint32_t max, bool automatic); int smu_v13_0_set_hard_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, @@ -255,7 +255,8 @@ int smu_v13_0_wait_for_event(struct smu_context *smu, enum smu_event_type event, uint64_t event_arg); int smu_v13_0_set_vcn_enable(struct smu_context *smu, - bool enable); + bool enable, + int inst); int smu_v13_0_set_jpeg_enable(struct smu_context *smu, bool enable); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h index 727d5b405435d0..29a4583db8734b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h @@ -53,7 +53,7 @@ #define CTF_OFFSET_MEM 5 extern const int decoded_link_speed[5]; -extern const int decoded_link_width[7]; +extern const int decoded_link_width[8]; #define DECODE_GEN_SPEED(gen_speed_idx) (decoded_link_speed[gen_speed_idx]) #define DECODE_LANE_WIDTH(lane_width_idx) (decoded_link_width[lane_width_idx]) @@ -186,7 +186,7 @@ int smu_v14_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c uint32_t *min, uint32_t *max); int smu_v14_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, uint32_t max); + uint32_t min, uint32_t max, bool automatic); int smu_v14_0_set_hard_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, @@ -210,7 +210,8 @@ int smu_v14_0_wait_for_event(struct smu_context *smu, enum smu_event_type event, uint64_t event_arg); int smu_v14_0_set_vcn_enable(struct smu_context *smu, - bool enable); + bool enable, + int inst); int smu_v14_0_set_jpeg_enable(struct smu_context *smu, bool enable); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index c0f6b59369b7c4..8aa61a9f77782b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1344,8 +1344,12 @@ static int arcturus_get_power_limit(struct smu_context *smu, *default_power_limit = power_limit; if (max_power_limit) *max_power_limit = power_limit; + /** + * No lower bound is imposed on the limit. Any unreasonable limit set + * will result in frequent throttling. + */ if (min_power_limit) - *min_power_limit = power_limit; + *min_power_limit = 0; return 0; } @@ -1441,98 +1445,120 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu, return size; } -static int arcturus_set_power_profile_mode(struct smu_context *smu, - long *input, - uint32_t size) +#define ARCTURUS_CUSTOM_PARAMS_COUNT 10 +#define ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT 2 +#define ARCTURUS_CUSTOM_PARAMS_SIZE (ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT * ARCTURUS_CUSTOM_PARAMS_COUNT * sizeof(long)) + +static int arcturus_set_power_profile_mode_coeff(struct smu_context *smu, + long *input) { DpmActivityMonitorCoeffInt_t activity_monitor; - int workload_type = 0; - uint32_t profile_mode = input[size]; - int ret = 0; + int ret, idx; - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); - return -EINVAL; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor), + false); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); + return ret; } + idx = 0 * ARCTURUS_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Gfxclk */ + activity_monitor.Gfx_FPS = input[idx + 1]; + activity_monitor.Gfx_UseRlcBusy = input[idx + 2]; + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3]; + activity_monitor.Gfx_MinActiveFreq = input[idx + 4]; + activity_monitor.Gfx_BoosterFreqType = input[idx + 5]; + activity_monitor.Gfx_BoosterFreq = input[idx + 6]; + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7]; + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8]; + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9]; + } + idx = 1 * ARCTURUS_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Uclk */ + activity_monitor.Mem_FPS = input[idx + 1]; + activity_monitor.Mem_UseRlcBusy = input[idx + 2]; + activity_monitor.Mem_MinActiveFreqType = input[idx + 3]; + activity_monitor.Mem_MinActiveFreq = input[idx + 4]; + activity_monitor.Mem_BoosterFreqType = input[idx + 5]; + activity_monitor.Mem_BoosterFreq = input[idx + 6]; + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7]; + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8]; + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9]; + } - if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) && - (smu->smc_fw_version >= 0x360d00)) { - if (size != 10) - return -EINVAL; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor), + true); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + return ret; + } - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, - WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor), - false); - if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); - return ret; - } + return ret; +} - switch (input[0]) { - case 0: /* Gfxclk */ - activity_monitor.Gfx_FPS = input[1]; - activity_monitor.Gfx_UseRlcBusy = input[2]; - activity_monitor.Gfx_MinActiveFreqType = input[3]; - activity_monitor.Gfx_MinActiveFreq = input[4]; - activity_monitor.Gfx_BoosterFreqType = input[5]; - activity_monitor.Gfx_BoosterFreq = input[6]; - activity_monitor.Gfx_PD_Data_limit_c = input[7]; - activity_monitor.Gfx_PD_Data_error_coeff = input[8]; - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9]; - break; - case 1: /* Uclk */ - activity_monitor.Mem_FPS = input[1]; - activity_monitor.Mem_UseRlcBusy = input[2]; - activity_monitor.Mem_MinActiveFreqType = input[3]; - activity_monitor.Mem_MinActiveFreq = input[4]; - activity_monitor.Mem_BoosterFreqType = input[5]; - activity_monitor.Mem_BoosterFreq = input[6]; - activity_monitor.Mem_PD_Data_limit_c = input[7]; - activity_monitor.Mem_PD_Data_error_coeff = input[8]; - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9]; - break; - default: +static int arcturus_set_power_profile_mode(struct smu_context *smu, + u32 workload_mask, + long *custom_params, + u32 custom_params_max_idx) +{ + u32 backend_workload_mask = 0; + int ret, idx = -1, i; + + smu_cmn_get_backend_workload_mask(smu, workload_mask, + &backend_workload_mask); + + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { + if (smu->smc_fw_version < 0x360d00) return -EINVAL; + if (!smu->custom_profile_params) { + smu->custom_profile_params = + kzalloc(ARCTURUS_CUSTOM_PARAMS_SIZE, GFP_KERNEL); + if (!smu->custom_profile_params) + return -ENOMEM; } - - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, - WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor), - true); + if (custom_params && custom_params_max_idx) { + if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT) + return -EINVAL; + if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT) + return -EINVAL; + idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT; + smu->custom_profile_params[idx] = 1; + for (i = 1; i < custom_params_max_idx; i++) + smu->custom_profile_params[idx + i] = custom_params[i]; + } + ret = arcturus_set_power_profile_mode_coeff(smu, + smu->custom_profile_params); if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + if (idx != -1) + smu->custom_profile_params[idx] = 0; return ret; } - } - - /* - * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT - * Not all profile modes are supported on arcturus. - */ - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - profile_mode); - if (workload_type < 0) { - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode); - return -EINVAL; + } else if (smu->custom_profile_params) { + memset(smu->custom_profile_params, 0, ARCTURUS_CUSTOM_PARAMS_SIZE); } ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetWorkloadMask, - 1 << workload_type, - NULL); + SMU_MSG_SetWorkloadMask, + backend_workload_mask, + NULL); if (ret) { - dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type); + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", + workload_mask); + if (idx != -1) + smu->custom_profile_params[idx] = 0; return ret; } - smu->power_profile_mode = profile_mode; - - return 0; + return ret; } static int arcturus_set_performance_level(struct smu_context *smu, @@ -1559,437 +1585,6 @@ static int arcturus_set_performance_level(struct smu_context *smu, return smu_v11_0_set_performance_level(smu, level); } -static void arcturus_dump_pptable(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - PPTable_t *pptable = table_context->driver_pptable; - int i; - - dev_info(smu->adev->dev, "Dumped PPTable:\n"); - - dev_info(smu->adev->dev, "Version = 0x%08x\n", pptable->Version); - - dev_info(smu->adev->dev, "FeaturesToRun[0] = 0x%08x\n", pptable->FeaturesToRun[0]); - dev_info(smu->adev->dev, "FeaturesToRun[1] = 0x%08x\n", pptable->FeaturesToRun[1]); - - for (i = 0; i < PPT_THROTTLER_COUNT; i++) { - dev_info(smu->adev->dev, "SocketPowerLimitAc[%d] = %d\n", i, pptable->SocketPowerLimitAc[i]); - dev_info(smu->adev->dev, "SocketPowerLimitAcTau[%d] = %d\n", i, pptable->SocketPowerLimitAcTau[i]); - } - - dev_info(smu->adev->dev, "TdcLimitSoc = %d\n", pptable->TdcLimitSoc); - dev_info(smu->adev->dev, "TdcLimitSocTau = %d\n", pptable->TdcLimitSocTau); - dev_info(smu->adev->dev, "TdcLimitGfx = %d\n", pptable->TdcLimitGfx); - dev_info(smu->adev->dev, "TdcLimitGfxTau = %d\n", pptable->TdcLimitGfxTau); - - dev_info(smu->adev->dev, "TedgeLimit = %d\n", pptable->TedgeLimit); - dev_info(smu->adev->dev, "ThotspotLimit = %d\n", pptable->ThotspotLimit); - dev_info(smu->adev->dev, "TmemLimit = %d\n", pptable->TmemLimit); - dev_info(smu->adev->dev, "Tvr_gfxLimit = %d\n", pptable->Tvr_gfxLimit); - dev_info(smu->adev->dev, "Tvr_memLimit = %d\n", pptable->Tvr_memLimit); - dev_info(smu->adev->dev, "Tvr_socLimit = %d\n", pptable->Tvr_socLimit); - dev_info(smu->adev->dev, "FitLimit = %d\n", pptable->FitLimit); - - dev_info(smu->adev->dev, "PpmPowerLimit = %d\n", pptable->PpmPowerLimit); - dev_info(smu->adev->dev, "PpmTemperatureThreshold = %d\n", pptable->PpmTemperatureThreshold); - - dev_info(smu->adev->dev, "ThrottlerControlMask = %d\n", pptable->ThrottlerControlMask); - - dev_info(smu->adev->dev, "UlvVoltageOffsetGfx = %d\n", pptable->UlvVoltageOffsetGfx); - dev_info(smu->adev->dev, "UlvPadding = 0x%08x\n", pptable->UlvPadding); - - dev_info(smu->adev->dev, "UlvGfxclkBypass = %d\n", pptable->UlvGfxclkBypass); - dev_info(smu->adev->dev, "Padding234[0] = 0x%02x\n", pptable->Padding234[0]); - dev_info(smu->adev->dev, "Padding234[1] = 0x%02x\n", pptable->Padding234[1]); - dev_info(smu->adev->dev, "Padding234[2] = 0x%02x\n", pptable->Padding234[2]); - - dev_info(smu->adev->dev, "MinVoltageGfx = %d\n", pptable->MinVoltageGfx); - dev_info(smu->adev->dev, "MinVoltageSoc = %d\n", pptable->MinVoltageSoc); - dev_info(smu->adev->dev, "MaxVoltageGfx = %d\n", pptable->MaxVoltageGfx); - dev_info(smu->adev->dev, "MaxVoltageSoc = %d\n", pptable->MaxVoltageSoc); - - dev_info(smu->adev->dev, "LoadLineResistanceGfx = %d\n", pptable->LoadLineResistanceGfx); - dev_info(smu->adev->dev, "LoadLineResistanceSoc = %d\n", pptable->LoadLineResistanceSoc); - - dev_info(smu->adev->dev, "[PPCLK_GFXCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_GFXCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_GFXCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_GFXCLK].padding, - pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_GFXCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_VCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_VCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_VCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_VCLK].padding, - pptable->DpmDescriptor[PPCLK_VCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_VCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_VCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_VCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_DCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_DCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_DCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_DCLK].padding, - pptable->DpmDescriptor[PPCLK_DCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_DCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_DCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_DCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_SOCCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_SOCCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_SOCCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_SOCCLK].padding, - pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_SOCCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_UCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_UCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_UCLK].padding, - pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_UCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_UCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_FCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_FCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_FCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_FCLK].padding, - pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_FCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_FCLK].Padding16); - - - dev_info(smu->adev->dev, "FreqTableGfx\n"); - for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableGfx[i]); - - dev_info(smu->adev->dev, "FreqTableVclk\n"); - for (i = 0; i < NUM_VCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableVclk[i]); - - dev_info(smu->adev->dev, "FreqTableDclk\n"); - for (i = 0; i < NUM_DCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableDclk[i]); - - dev_info(smu->adev->dev, "FreqTableSocclk\n"); - for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableSocclk[i]); - - dev_info(smu->adev->dev, "FreqTableUclk\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableUclk[i]); - - dev_info(smu->adev->dev, "FreqTableFclk\n"); - for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableFclk[i]); - - dev_info(smu->adev->dev, "Mp0clkFreq\n"); - for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->Mp0clkFreq[i]); - - dev_info(smu->adev->dev, "Mp0DpmVoltage\n"); - for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->Mp0DpmVoltage[i]); - - dev_info(smu->adev->dev, "GfxclkFidle = 0x%x\n", pptable->GfxclkFidle); - dev_info(smu->adev->dev, "GfxclkSlewRate = 0x%x\n", pptable->GfxclkSlewRate); - dev_info(smu->adev->dev, "Padding567[0] = 0x%x\n", pptable->Padding567[0]); - dev_info(smu->adev->dev, "Padding567[1] = 0x%x\n", pptable->Padding567[1]); - dev_info(smu->adev->dev, "Padding567[2] = 0x%x\n", pptable->Padding567[2]); - dev_info(smu->adev->dev, "Padding567[3] = 0x%x\n", pptable->Padding567[3]); - dev_info(smu->adev->dev, "GfxclkDsMaxFreq = %d\n", pptable->GfxclkDsMaxFreq); - dev_info(smu->adev->dev, "GfxclkSource = 0x%x\n", pptable->GfxclkSource); - dev_info(smu->adev->dev, "Padding456 = 0x%x\n", pptable->Padding456); - - dev_info(smu->adev->dev, "EnableTdpm = %d\n", pptable->EnableTdpm); - dev_info(smu->adev->dev, "TdpmHighHystTemperature = %d\n", pptable->TdpmHighHystTemperature); - dev_info(smu->adev->dev, "TdpmLowHystTemperature = %d\n", pptable->TdpmLowHystTemperature); - dev_info(smu->adev->dev, "GfxclkFreqHighTempLimit = %d\n", pptable->GfxclkFreqHighTempLimit); - - dev_info(smu->adev->dev, "FanStopTemp = %d\n", pptable->FanStopTemp); - dev_info(smu->adev->dev, "FanStartTemp = %d\n", pptable->FanStartTemp); - - dev_info(smu->adev->dev, "FanGainEdge = %d\n", pptable->FanGainEdge); - dev_info(smu->adev->dev, "FanGainHotspot = %d\n", pptable->FanGainHotspot); - dev_info(smu->adev->dev, "FanGainVrGfx = %d\n", pptable->FanGainVrGfx); - dev_info(smu->adev->dev, "FanGainVrSoc = %d\n", pptable->FanGainVrSoc); - dev_info(smu->adev->dev, "FanGainVrMem = %d\n", pptable->FanGainVrMem); - dev_info(smu->adev->dev, "FanGainHbm = %d\n", pptable->FanGainHbm); - - dev_info(smu->adev->dev, "FanPwmMin = %d\n", pptable->FanPwmMin); - dev_info(smu->adev->dev, "FanAcousticLimitRpm = %d\n", pptable->FanAcousticLimitRpm); - dev_info(smu->adev->dev, "FanThrottlingRpm = %d\n", pptable->FanThrottlingRpm); - dev_info(smu->adev->dev, "FanMaximumRpm = %d\n", pptable->FanMaximumRpm); - dev_info(smu->adev->dev, "FanTargetTemperature = %d\n", pptable->FanTargetTemperature); - dev_info(smu->adev->dev, "FanTargetGfxclk = %d\n", pptable->FanTargetGfxclk); - dev_info(smu->adev->dev, "FanZeroRpmEnable = %d\n", pptable->FanZeroRpmEnable); - dev_info(smu->adev->dev, "FanTachEdgePerRev = %d\n", pptable->FanTachEdgePerRev); - dev_info(smu->adev->dev, "FanTempInputSelect = %d\n", pptable->FanTempInputSelect); - - dev_info(smu->adev->dev, "FuzzyFan_ErrorSetDelta = %d\n", pptable->FuzzyFan_ErrorSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_ErrorRateSetDelta = %d\n", pptable->FuzzyFan_ErrorRateSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_PwmSetDelta = %d\n", pptable->FuzzyFan_PwmSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_Reserved = %d\n", pptable->FuzzyFan_Reserved); - - dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "Padding8_Avfs[0] = %d\n", pptable->Padding8_Avfs[0]); - dev_info(smu->adev->dev, "Padding8_Avfs[1] = %d\n", pptable->Padding8_Avfs[1]); - - dev_info(smu->adev->dev, "dBtcGbGfxPll{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxPll.a, - pptable->dBtcGbGfxPll.b, - pptable->dBtcGbGfxPll.c); - dev_info(smu->adev->dev, "dBtcGbGfxAfll{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxAfll.a, - pptable->dBtcGbGfxAfll.b, - pptable->dBtcGbGfxAfll.c); - dev_info(smu->adev->dev, "dBtcGbSoc{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbSoc.a, - pptable->dBtcGbSoc.b, - pptable->dBtcGbSoc.c); - - dev_info(smu->adev->dev, "qAgingGb[AVFS_VOLTAGE_GFX]{m = 0x%x b = 0x%x}\n", - pptable->qAgingGb[AVFS_VOLTAGE_GFX].m, - pptable->qAgingGb[AVFS_VOLTAGE_GFX].b); - dev_info(smu->adev->dev, "qAgingGb[AVFS_VOLTAGE_SOC]{m = 0x%x b = 0x%x}\n", - pptable->qAgingGb[AVFS_VOLTAGE_SOC].m, - pptable->qAgingGb[AVFS_VOLTAGE_SOC].b); - - dev_info(smu->adev->dev, "qStaticVoltageOffset[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].a, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].b, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].c); - dev_info(smu->adev->dev, "qStaticVoltageOffset[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].a, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].b, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].c); - - dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "Padding8_GfxBtc[0] = 0x%x\n", pptable->Padding8_GfxBtc[0]); - dev_info(smu->adev->dev, "Padding8_GfxBtc[1] = 0x%x\n", pptable->Padding8_GfxBtc[1]); - - dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "XgmiDpmPstates\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiDpmPstates[i]); - dev_info(smu->adev->dev, "XgmiDpmSpare[0] = 0x%02x\n", pptable->XgmiDpmSpare[0]); - dev_info(smu->adev->dev, "XgmiDpmSpare[1] = 0x%02x\n", pptable->XgmiDpmSpare[1]); - - dev_info(smu->adev->dev, "VDDGFX_TVmin = %d\n", pptable->VDDGFX_TVmin); - dev_info(smu->adev->dev, "VDDSOC_TVmin = %d\n", pptable->VDDSOC_TVmin); - dev_info(smu->adev->dev, "VDDGFX_Vmin_HiTemp = %d\n", pptable->VDDGFX_Vmin_HiTemp); - dev_info(smu->adev->dev, "VDDGFX_Vmin_LoTemp = %d\n", pptable->VDDGFX_Vmin_LoTemp); - dev_info(smu->adev->dev, "VDDSOC_Vmin_HiTemp = %d\n", pptable->VDDSOC_Vmin_HiTemp); - dev_info(smu->adev->dev, "VDDSOC_Vmin_LoTemp = %d\n", pptable->VDDSOC_Vmin_LoTemp); - dev_info(smu->adev->dev, "VDDGFX_TVminHystersis = %d\n", pptable->VDDGFX_TVminHystersis); - dev_info(smu->adev->dev, "VDDSOC_TVminHystersis = %d\n", pptable->VDDSOC_TVminHystersis); - - dev_info(smu->adev->dev, "DebugOverrides = 0x%x\n", pptable->DebugOverrides); - dev_info(smu->adev->dev, "ReservedEquation0{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation0.a, - pptable->ReservedEquation0.b, - pptable->ReservedEquation0.c); - dev_info(smu->adev->dev, "ReservedEquation1{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation1.a, - pptable->ReservedEquation1.b, - pptable->ReservedEquation1.c); - dev_info(smu->adev->dev, "ReservedEquation2{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation2.a, - pptable->ReservedEquation2.b, - pptable->ReservedEquation2.c); - dev_info(smu->adev->dev, "ReservedEquation3{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation3.a, - pptable->ReservedEquation3.b, - pptable->ReservedEquation3.c); - - dev_info(smu->adev->dev, "MinVoltageUlvGfx = %d\n", pptable->MinVoltageUlvGfx); - dev_info(smu->adev->dev, "PaddingUlv = %d\n", pptable->PaddingUlv); - - dev_info(smu->adev->dev, "TotalPowerConfig = %d\n", pptable->TotalPowerConfig); - dev_info(smu->adev->dev, "TotalPowerSpare1 = %d\n", pptable->TotalPowerSpare1); - dev_info(smu->adev->dev, "TotalPowerSpare2 = %d\n", pptable->TotalPowerSpare2); - - dev_info(smu->adev->dev, "PccThresholdLow = %d\n", pptable->PccThresholdLow); - dev_info(smu->adev->dev, "PccThresholdHigh = %d\n", pptable->PccThresholdHigh); - - dev_info(smu->adev->dev, "Board Parameters:\n"); - dev_info(smu->adev->dev, "MaxVoltageStepGfx = 0x%x\n", pptable->MaxVoltageStepGfx); - dev_info(smu->adev->dev, "MaxVoltageStepSoc = 0x%x\n", pptable->MaxVoltageStepSoc); - - dev_info(smu->adev->dev, "VddGfxVrMapping = 0x%x\n", pptable->VddGfxVrMapping); - dev_info(smu->adev->dev, "VddSocVrMapping = 0x%x\n", pptable->VddSocVrMapping); - dev_info(smu->adev->dev, "VddMemVrMapping = 0x%x\n", pptable->VddMemVrMapping); - dev_info(smu->adev->dev, "BoardVrMapping = 0x%x\n", pptable->BoardVrMapping); - - dev_info(smu->adev->dev, "GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); - dev_info(smu->adev->dev, "ExternalSensorPresent = 0x%x\n", pptable->ExternalSensorPresent); - - dev_info(smu->adev->dev, "GfxMaxCurrent = 0x%x\n", pptable->GfxMaxCurrent); - dev_info(smu->adev->dev, "GfxOffset = 0x%x\n", pptable->GfxOffset); - dev_info(smu->adev->dev, "Padding_TelemetryGfx = 0x%x\n", pptable->Padding_TelemetryGfx); - - dev_info(smu->adev->dev, "SocMaxCurrent = 0x%x\n", pptable->SocMaxCurrent); - dev_info(smu->adev->dev, "SocOffset = 0x%x\n", pptable->SocOffset); - dev_info(smu->adev->dev, "Padding_TelemetrySoc = 0x%x\n", pptable->Padding_TelemetrySoc); - - dev_info(smu->adev->dev, "MemMaxCurrent = 0x%x\n", pptable->MemMaxCurrent); - dev_info(smu->adev->dev, "MemOffset = 0x%x\n", pptable->MemOffset); - dev_info(smu->adev->dev, "Padding_TelemetryMem = 0x%x\n", pptable->Padding_TelemetryMem); - - dev_info(smu->adev->dev, "BoardMaxCurrent = 0x%x\n", pptable->BoardMaxCurrent); - dev_info(smu->adev->dev, "BoardOffset = 0x%x\n", pptable->BoardOffset); - dev_info(smu->adev->dev, "Padding_TelemetryBoardInput = 0x%x\n", pptable->Padding_TelemetryBoardInput); - - dev_info(smu->adev->dev, "VR0HotGpio = %d\n", pptable->VR0HotGpio); - dev_info(smu->adev->dev, "VR0HotPolarity = %d\n", pptable->VR0HotPolarity); - dev_info(smu->adev->dev, "VR1HotGpio = %d\n", pptable->VR1HotGpio); - dev_info(smu->adev->dev, "VR1HotPolarity = %d\n", pptable->VR1HotPolarity); - - dev_info(smu->adev->dev, "PllGfxclkSpreadEnabled = %d\n", pptable->PllGfxclkSpreadEnabled); - dev_info(smu->adev->dev, "PllGfxclkSpreadPercent = %d\n", pptable->PllGfxclkSpreadPercent); - dev_info(smu->adev->dev, "PllGfxclkSpreadFreq = %d\n", pptable->PllGfxclkSpreadFreq); - - dev_info(smu->adev->dev, "UclkSpreadEnabled = %d\n", pptable->UclkSpreadEnabled); - dev_info(smu->adev->dev, "UclkSpreadPercent = %d\n", pptable->UclkSpreadPercent); - dev_info(smu->adev->dev, "UclkSpreadFreq = %d\n", pptable->UclkSpreadFreq); - - dev_info(smu->adev->dev, "FclkSpreadEnabled = %d\n", pptable->FclkSpreadEnabled); - dev_info(smu->adev->dev, "FclkSpreadPercent = %d\n", pptable->FclkSpreadPercent); - dev_info(smu->adev->dev, "FclkSpreadFreq = %d\n", pptable->FclkSpreadFreq); - - dev_info(smu->adev->dev, "FllGfxclkSpreadEnabled = %d\n", pptable->FllGfxclkSpreadEnabled); - dev_info(smu->adev->dev, "FllGfxclkSpreadPercent = %d\n", pptable->FllGfxclkSpreadPercent); - dev_info(smu->adev->dev, "FllGfxclkSpreadFreq = %d\n", pptable->FllGfxclkSpreadFreq); - - for (i = 0; i < NUM_I2C_CONTROLLERS; i++) { - dev_info(smu->adev->dev, "I2cControllers[%d]:\n", i); - dev_info(smu->adev->dev, " .Enabled = %d\n", - pptable->I2cControllers[i].Enabled); - dev_info(smu->adev->dev, " .SlaveAddress = 0x%x\n", - pptable->I2cControllers[i].SlaveAddress); - dev_info(smu->adev->dev, " .ControllerPort = %d\n", - pptable->I2cControllers[i].ControllerPort); - dev_info(smu->adev->dev, " .ControllerName = %d\n", - pptable->I2cControllers[i].ControllerName); - dev_info(smu->adev->dev, " .ThermalThrottler = %d\n", - pptable->I2cControllers[i].ThermalThrotter); - dev_info(smu->adev->dev, " .I2cProtocol = %d\n", - pptable->I2cControllers[i].I2cProtocol); - dev_info(smu->adev->dev, " .Speed = %d\n", - pptable->I2cControllers[i].Speed); - } - - dev_info(smu->adev->dev, "MemoryChannelEnabled = %d\n", pptable->MemoryChannelEnabled); - dev_info(smu->adev->dev, "DramBitWidth = %d\n", pptable->DramBitWidth); - - dev_info(smu->adev->dev, "TotalBoardPower = %d\n", pptable->TotalBoardPower); - - dev_info(smu->adev->dev, "XgmiLinkSpeed\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiLinkSpeed[i]); - dev_info(smu->adev->dev, "XgmiLinkWidth\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiLinkWidth[i]); - dev_info(smu->adev->dev, "XgmiFclkFreq\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiFclkFreq[i]); - dev_info(smu->adev->dev, "XgmiSocVoltage\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiSocVoltage[i]); - -} - static bool arcturus_is_dpm_running(struct smu_context *smu) { int ret = 0; @@ -2002,7 +1597,9 @@ static bool arcturus_is_dpm_running(struct smu_context *smu) return !!(feature_enabled & SMC_DPM_FEATURE); } -static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, bool enable) +static int arcturus_dpm_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst) { int ret = 0; @@ -2365,8 +1962,6 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .get_power_profile_mode = arcturus_get_power_profile_mode, .set_power_profile_mode = arcturus_set_power_profile_mode, .set_performance_level = arcturus_set_performance_level, - /* debug (internal used) */ - .dump_pptable = arcturus_dump_pptable, .get_power_limit = arcturus_get_power_limit, .is_dpm_running = arcturus_is_dpm_running, .dpm_set_vcn_enable = arcturus_dpm_set_vcn_enable, 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 16af1a329621f1..7fad5dfb39c440 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -1135,7 +1135,9 @@ static int navi10_set_default_dpm_table(struct smu_context *smu) return 0; } -static int navi10_dpm_set_vcn_enable(struct smu_context *smu, bool enable) +static int navi10_dpm_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst) { int ret = 0; @@ -1689,7 +1691,7 @@ static int navi10_force_clk_levels(struct smu_context *smu, if (ret) return 0; - ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false); if (ret) return 0; break; @@ -2004,87 +2006,122 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf) return size; } -static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) +#define NAVI10_CUSTOM_PARAMS_COUNT 10 +#define NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT 3 +#define NAVI10_CUSTOM_PARAMS_SIZE (NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT * NAVI10_CUSTOM_PARAMS_COUNT * sizeof(long)) + +static int navi10_set_power_profile_mode_coeff(struct smu_context *smu, + long *input) { DpmActivityMonitorCoeffInt_t activity_monitor; - int workload_type, ret = 0; + int ret, idx; - smu->power_profile_mode = input[size]; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor), false); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); + return ret; + } - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); - return -EINVAL; + idx = 0 * NAVI10_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Gfxclk */ + activity_monitor.Gfx_FPS = input[idx + 1]; + activity_monitor.Gfx_MinFreqStep = input[idx + 2]; + activity_monitor.Gfx_MinActiveFreqType = input[idx + 3]; + activity_monitor.Gfx_MinActiveFreq = input[idx + 4]; + activity_monitor.Gfx_BoosterFreqType = input[idx + 5]; + activity_monitor.Gfx_BoosterFreq = input[idx + 6]; + activity_monitor.Gfx_PD_Data_limit_c = input[idx + 7]; + activity_monitor.Gfx_PD_Data_error_coeff = input[idx + 8]; + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[idx + 9]; + } + idx = 1 * NAVI10_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Socclk */ + activity_monitor.Soc_FPS = input[idx + 1]; + activity_monitor.Soc_MinFreqStep = input[idx + 2]; + activity_monitor.Soc_MinActiveFreqType = input[idx + 3]; + activity_monitor.Soc_MinActiveFreq = input[idx + 4]; + activity_monitor.Soc_BoosterFreqType = input[idx + 5]; + activity_monitor.Soc_BoosterFreq = input[idx + 6]; + activity_monitor.Soc_PD_Data_limit_c = input[idx + 7]; + activity_monitor.Soc_PD_Data_error_coeff = input[idx + 8]; + activity_monitor.Soc_PD_Data_error_rate_coeff = input[idx + 9]; + } + idx = 2 * NAVI10_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Memclk */ + activity_monitor.Mem_FPS = input[idx + 1]; + activity_monitor.Mem_MinFreqStep = input[idx + 2]; + activity_monitor.Mem_MinActiveFreqType = input[idx + 3]; + activity_monitor.Mem_MinActiveFreq = input[idx + 4]; + activity_monitor.Mem_BoosterFreqType = input[idx + 5]; + activity_monitor.Mem_BoosterFreq = input[idx + 6]; + activity_monitor.Mem_PD_Data_limit_c = input[idx + 7]; + activity_monitor.Mem_PD_Data_error_coeff = input[idx + 8]; + activity_monitor.Mem_PD_Data_error_rate_coeff = input[idx + 9]; + } + + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor), true); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + return ret; } - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { - if (size != 10) - return -EINVAL; + return ret; +} - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor), false); - if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); - return ret; - } +static int navi10_set_power_profile_mode(struct smu_context *smu, + u32 workload_mask, + long *custom_params, + u32 custom_params_max_idx) +{ + u32 backend_workload_mask = 0; + int ret, idx = -1, i; - switch (input[0]) { - case 0: /* Gfxclk */ - activity_monitor.Gfx_FPS = input[1]; - activity_monitor.Gfx_MinFreqStep = input[2]; - activity_monitor.Gfx_MinActiveFreqType = input[3]; - activity_monitor.Gfx_MinActiveFreq = input[4]; - activity_monitor.Gfx_BoosterFreqType = input[5]; - activity_monitor.Gfx_BoosterFreq = input[6]; - activity_monitor.Gfx_PD_Data_limit_c = input[7]; - activity_monitor.Gfx_PD_Data_error_coeff = input[8]; - activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9]; - break; - case 1: /* Socclk */ - activity_monitor.Soc_FPS = input[1]; - activity_monitor.Soc_MinFreqStep = input[2]; - activity_monitor.Soc_MinActiveFreqType = input[3]; - activity_monitor.Soc_MinActiveFreq = input[4]; - activity_monitor.Soc_BoosterFreqType = input[5]; - activity_monitor.Soc_BoosterFreq = input[6]; - activity_monitor.Soc_PD_Data_limit_c = input[7]; - activity_monitor.Soc_PD_Data_error_coeff = input[8]; - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9]; - break; - case 2: /* Memclk */ - activity_monitor.Mem_FPS = input[1]; - activity_monitor.Mem_MinFreqStep = input[2]; - activity_monitor.Mem_MinActiveFreqType = input[3]; - activity_monitor.Mem_MinActiveFreq = input[4]; - activity_monitor.Mem_BoosterFreqType = input[5]; - activity_monitor.Mem_BoosterFreq = input[6]; - activity_monitor.Mem_PD_Data_limit_c = input[7]; - activity_monitor.Mem_PD_Data_error_coeff = input[8]; - activity_monitor.Mem_PD_Data_error_rate_coeff = input[9]; - break; - default: - return -EINVAL; - } + smu_cmn_get_backend_workload_mask(smu, workload_mask, + &backend_workload_mask); - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor), true); + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { + if (!smu->custom_profile_params) { + smu->custom_profile_params = kzalloc(NAVI10_CUSTOM_PARAMS_SIZE, GFP_KERNEL); + if (!smu->custom_profile_params) + return -ENOMEM; + } + if (custom_params && custom_params_max_idx) { + if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT) + return -EINVAL; + if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT) + return -EINVAL; + idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT; + smu->custom_profile_params[idx] = 1; + for (i = 1; i < custom_params_max_idx; i++) + smu->custom_profile_params[idx + i] = custom_params[i]; + } + ret = navi10_set_power_profile_mode_coeff(smu, + smu->custom_profile_params); if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + if (idx != -1) + smu->custom_profile_params[idx] = 0; return ret; } + } else if (smu->custom_profile_params) { + memset(smu->custom_profile_params, 0, NAVI10_CUSTOM_PARAMS_SIZE); } - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - smu->power_profile_mode); - if (workload_type < 0) - return -EINVAL; ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, - 1 << workload_type, NULL); - if (ret) - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__); + backend_workload_mask, NULL); + if (ret) { + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", + workload_mask); + if (idx != -1) + smu->custom_profile_params[idx] = 0; + return ret; + } return ret; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 9c3c48297cba03..286777ada1dfc4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -1152,7 +1152,9 @@ static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) return 0; } -static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu, bool enable) +static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst) { struct amdgpu_device *adev = smu->adev; int i, ret = 0; @@ -1469,7 +1471,7 @@ static int sienna_cichlid_force_clk_levels(struct smu_context *smu, if (ret) goto forec_level_out; - ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false); if (ret) goto forec_level_out; break; @@ -1706,90 +1708,126 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char * return size; } -static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) +#define SIENNA_CICHLID_CUSTOM_PARAMS_COUNT 10 +#define SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT 3 +#define SIENNA_CICHLID_CUSTOM_PARAMS_SIZE (SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT * sizeof(long)) + +static int sienna_cichlid_set_power_profile_mode_coeff(struct smu_context *smu, + long *input) { DpmActivityMonitorCoeffIntExternal_t activity_monitor_external; DpmActivityMonitorCoeffInt_t *activity_monitor = &(activity_monitor_external.DpmActivityMonitorCoeffInt); - int workload_type, ret = 0; + int ret, idx; - smu->power_profile_mode = input[size]; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor_external), false); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); + return ret; + } - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); - return -EINVAL; + idx = 0 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Gfxclk */ + activity_monitor->Gfx_FPS = input[idx + 1]; + activity_monitor->Gfx_MinFreqStep = input[idx + 2]; + activity_monitor->Gfx_MinActiveFreqType = input[idx + 3]; + activity_monitor->Gfx_MinActiveFreq = input[idx + 4]; + activity_monitor->Gfx_BoosterFreqType = input[idx + 5]; + activity_monitor->Gfx_BoosterFreq = input[idx + 6]; + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 7]; + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 8]; + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 9]; + } + idx = 1 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Socclk */ + activity_monitor->Fclk_FPS = input[idx + 1]; + activity_monitor->Fclk_MinFreqStep = input[idx + 2]; + activity_monitor->Fclk_MinActiveFreqType = input[idx + 3]; + activity_monitor->Fclk_MinActiveFreq = input[idx + 4]; + activity_monitor->Fclk_BoosterFreqType = input[idx + 5]; + activity_monitor->Fclk_BoosterFreq = input[idx + 6]; + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 7]; + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 8]; + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 9]; + } + idx = 2 * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Memclk */ + activity_monitor->Mem_FPS = input[idx + 1]; + activity_monitor->Mem_MinFreqStep = input[idx + 2]; + activity_monitor->Mem_MinActiveFreqType = input[idx + 3]; + activity_monitor->Mem_MinActiveFreq = input[idx + 4]; + activity_monitor->Mem_BoosterFreqType = input[idx + 5]; + activity_monitor->Mem_BoosterFreq = input[idx + 6]; + activity_monitor->Mem_PD_Data_limit_c = input[idx + 7]; + activity_monitor->Mem_PD_Data_error_coeff = input[idx + 8]; + activity_monitor->Mem_PD_Data_error_rate_coeff = input[idx + 9]; } - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { - if (size != 10) - return -EINVAL; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor_external), true); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + return ret; + } - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor_external), false); - if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); - return ret; - } + return ret; +} - switch (input[0]) { - case 0: /* Gfxclk */ - activity_monitor->Gfx_FPS = input[1]; - activity_monitor->Gfx_MinFreqStep = input[2]; - activity_monitor->Gfx_MinActiveFreqType = input[3]; - activity_monitor->Gfx_MinActiveFreq = input[4]; - activity_monitor->Gfx_BoosterFreqType = input[5]; - activity_monitor->Gfx_BoosterFreq = input[6]; - activity_monitor->Gfx_PD_Data_limit_c = input[7]; - activity_monitor->Gfx_PD_Data_error_coeff = input[8]; - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[9]; - break; - case 1: /* Socclk */ - activity_monitor->Fclk_FPS = input[1]; - activity_monitor->Fclk_MinFreqStep = input[2]; - activity_monitor->Fclk_MinActiveFreqType = input[3]; - activity_monitor->Fclk_MinActiveFreq = input[4]; - activity_monitor->Fclk_BoosterFreqType = input[5]; - activity_monitor->Fclk_BoosterFreq = input[6]; - activity_monitor->Fclk_PD_Data_limit_c = input[7]; - activity_monitor->Fclk_PD_Data_error_coeff = input[8]; - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[9]; - break; - case 2: /* Memclk */ - activity_monitor->Mem_FPS = input[1]; - activity_monitor->Mem_MinFreqStep = input[2]; - activity_monitor->Mem_MinActiveFreqType = input[3]; - activity_monitor->Mem_MinActiveFreq = input[4]; - activity_monitor->Mem_BoosterFreqType = input[5]; - activity_monitor->Mem_BoosterFreq = input[6]; - activity_monitor->Mem_PD_Data_limit_c = input[7]; - activity_monitor->Mem_PD_Data_error_coeff = input[8]; - activity_monitor->Mem_PD_Data_error_rate_coeff = input[9]; - break; - default: - return -EINVAL; - } +static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, + u32 workload_mask, + long *custom_params, + u32 custom_params_max_idx) +{ + u32 backend_workload_mask = 0; + int ret, idx = -1, i; - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor_external), true); + smu_cmn_get_backend_workload_mask(smu, workload_mask, + &backend_workload_mask); + + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { + if (!smu->custom_profile_params) { + smu->custom_profile_params = + kzalloc(SIENNA_CICHLID_CUSTOM_PARAMS_SIZE, GFP_KERNEL); + if (!smu->custom_profile_params) + return -ENOMEM; + } + if (custom_params && custom_params_max_idx) { + if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT) + return -EINVAL; + if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT) + return -EINVAL; + idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; + smu->custom_profile_params[idx] = 1; + for (i = 1; i < custom_params_max_idx; i++) + smu->custom_profile_params[idx + i] = custom_params[i]; + } + ret = sienna_cichlid_set_power_profile_mode_coeff(smu, + smu->custom_profile_params); if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + if (idx != -1) + smu->custom_profile_params[idx] = 0; return ret; } + } else if (smu->custom_profile_params) { + memset(smu->custom_profile_params, 0, SIENNA_CICHLID_CUSTOM_PARAMS_SIZE); } - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - smu->power_profile_mode); - if (workload_type < 0) - return -EINVAL; ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, - 1 << workload_type, NULL); - if (ret) - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__); + backend_workload_mask, NULL); + if (ret) { + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", + workload_mask); + if (idx != -1) + smu->custom_profile_params[idx] = 0; + return ret; + } return ret; } @@ -2493,1274 +2531,6 @@ static bool sienna_cichlid_is_mode1_reset_supported(struct smu_context *smu) return val != 0x0; } -static void beige_goby_dump_pptable(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - PPTable_beige_goby_t *pptable = table_context->driver_pptable; - int i; - - dev_info(smu->adev->dev, "Dumped PPTable:\n"); - - dev_info(smu->adev->dev, "Version = 0x%08x\n", pptable->Version); - dev_info(smu->adev->dev, "FeaturesToRun[0] = 0x%08x\n", pptable->FeaturesToRun[0]); - dev_info(smu->adev->dev, "FeaturesToRun[1] = 0x%08x\n", pptable->FeaturesToRun[1]); - - for (i = 0; i < PPT_THROTTLER_COUNT; i++) { - dev_info(smu->adev->dev, "SocketPowerLimitAc[%d] = 0x%x\n", i, pptable->SocketPowerLimitAc[i]); - dev_info(smu->adev->dev, "SocketPowerLimitAcTau[%d] = 0x%x\n", i, pptable->SocketPowerLimitAcTau[i]); - dev_info(smu->adev->dev, "SocketPowerLimitDc[%d] = 0x%x\n", i, pptable->SocketPowerLimitDc[i]); - dev_info(smu->adev->dev, "SocketPowerLimitDcTau[%d] = 0x%x\n", i, pptable->SocketPowerLimitDcTau[i]); - } - - for (i = 0; i < TDC_THROTTLER_COUNT; i++) { - dev_info(smu->adev->dev, "TdcLimit[%d] = 0x%x\n", i, pptable->TdcLimit[i]); - dev_info(smu->adev->dev, "TdcLimitTau[%d] = 0x%x\n", i, pptable->TdcLimitTau[i]); - } - - for (i = 0; i < TEMP_COUNT; i++) { - dev_info(smu->adev->dev, "TemperatureLimit[%d] = 0x%x\n", i, pptable->TemperatureLimit[i]); - } - - dev_info(smu->adev->dev, "FitLimit = 0x%x\n", pptable->FitLimit); - dev_info(smu->adev->dev, "TotalPowerConfig = 0x%x\n", pptable->TotalPowerConfig); - dev_info(smu->adev->dev, "TotalPowerPadding[0] = 0x%x\n", pptable->TotalPowerPadding[0]); - dev_info(smu->adev->dev, "TotalPowerPadding[1] = 0x%x\n", pptable->TotalPowerPadding[1]); - dev_info(smu->adev->dev, "TotalPowerPadding[2] = 0x%x\n", pptable->TotalPowerPadding[2]); - - dev_info(smu->adev->dev, "ApccPlusResidencyLimit = 0x%x\n", pptable->ApccPlusResidencyLimit); - for (i = 0; i < NUM_SMNCLK_DPM_LEVELS; i++) { - dev_info(smu->adev->dev, "SmnclkDpmFreq[%d] = 0x%x\n", i, pptable->SmnclkDpmFreq[i]); - dev_info(smu->adev->dev, "SmnclkDpmVoltage[%d] = 0x%x\n", i, pptable->SmnclkDpmVoltage[i]); - } - dev_info(smu->adev->dev, "ThrottlerControlMask = 0x%x\n", pptable->ThrottlerControlMask); - - dev_info(smu->adev->dev, "FwDStateMask = 0x%x\n", pptable->FwDStateMask); - - dev_info(smu->adev->dev, "UlvVoltageOffsetSoc = 0x%x\n", pptable->UlvVoltageOffsetSoc); - dev_info(smu->adev->dev, "UlvVoltageOffsetGfx = 0x%x\n", pptable->UlvVoltageOffsetGfx); - dev_info(smu->adev->dev, "MinVoltageUlvGfx = 0x%x\n", pptable->MinVoltageUlvGfx); - dev_info(smu->adev->dev, "MinVoltageUlvSoc = 0x%x\n", pptable->MinVoltageUlvSoc); - - dev_info(smu->adev->dev, "SocLIVmin = 0x%x\n", pptable->SocLIVmin); - - dev_info(smu->adev->dev, "GceaLinkMgrIdleThreshold = 0x%x\n", pptable->GceaLinkMgrIdleThreshold); - - dev_info(smu->adev->dev, "MinVoltageGfx = 0x%x\n", pptable->MinVoltageGfx); - dev_info(smu->adev->dev, "MinVoltageSoc = 0x%x\n", pptable->MinVoltageSoc); - dev_info(smu->adev->dev, "MaxVoltageGfx = 0x%x\n", pptable->MaxVoltageGfx); - dev_info(smu->adev->dev, "MaxVoltageSoc = 0x%x\n", pptable->MaxVoltageSoc); - - dev_info(smu->adev->dev, "LoadLineResistanceGfx = 0x%x\n", pptable->LoadLineResistanceGfx); - dev_info(smu->adev->dev, "LoadLineResistanceSoc = 0x%x\n", pptable->LoadLineResistanceSoc); - - dev_info(smu->adev->dev, "VDDGFX_TVmin = 0x%x\n", pptable->VDDGFX_TVmin); - dev_info(smu->adev->dev, "VDDSOC_TVmin = 0x%x\n", pptable->VDDSOC_TVmin); - dev_info(smu->adev->dev, "VDDGFX_Vmin_HiTemp = 0x%x\n", pptable->VDDGFX_Vmin_HiTemp); - dev_info(smu->adev->dev, "VDDGFX_Vmin_LoTemp = 0x%x\n", pptable->VDDGFX_Vmin_LoTemp); - dev_info(smu->adev->dev, "VDDSOC_Vmin_HiTemp = 0x%x\n", pptable->VDDSOC_Vmin_HiTemp); - dev_info(smu->adev->dev, "VDDSOC_Vmin_LoTemp = 0x%x\n", pptable->VDDSOC_Vmin_LoTemp); - dev_info(smu->adev->dev, "VDDGFX_TVminHystersis = 0x%x\n", pptable->VDDGFX_TVminHystersis); - dev_info(smu->adev->dev, "VDDSOC_TVminHystersis = 0x%x\n", pptable->VDDSOC_TVminHystersis); - - dev_info(smu->adev->dev, "[PPCLK_GFXCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_GFXCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_GFXCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_GFXCLK].Padding, - pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_GFXCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_SOCCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_SOCCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_SOCCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_SOCCLK].Padding, - pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_SOCCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_UCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_UCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_UCLK].Padding, - pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_UCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_UCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_FCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_FCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_FCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_FCLK].Padding, - pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_FCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_FCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_DCLK_0]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_DCLK_0].VoltageMode, - pptable->DpmDescriptor[PPCLK_DCLK_0].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_DCLK_0].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_DCLK_0].Padding, - pptable->DpmDescriptor[PPCLK_DCLK_0].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_DCLK_0].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.a, - pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.b, - pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.c, - pptable->DpmDescriptor[PPCLK_DCLK_0].SsFmin, - pptable->DpmDescriptor[PPCLK_DCLK_0].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_VCLK_0]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_VCLK_0].VoltageMode, - pptable->DpmDescriptor[PPCLK_VCLK_0].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_VCLK_0].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_VCLK_0].Padding, - pptable->DpmDescriptor[PPCLK_VCLK_0].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_VCLK_0].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.a, - pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.b, - pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.c, - pptable->DpmDescriptor[PPCLK_VCLK_0].SsFmin, - pptable->DpmDescriptor[PPCLK_VCLK_0].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_DCLK_1]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_DCLK_1].VoltageMode, - pptable->DpmDescriptor[PPCLK_DCLK_1].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_DCLK_1].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_DCLK_1].Padding, - pptable->DpmDescriptor[PPCLK_DCLK_1].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_DCLK_1].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.a, - pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.b, - pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.c, - pptable->DpmDescriptor[PPCLK_DCLK_1].SsFmin, - pptable->DpmDescriptor[PPCLK_DCLK_1].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_VCLK_1]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_VCLK_1].VoltageMode, - pptable->DpmDescriptor[PPCLK_VCLK_1].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_VCLK_1].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_VCLK_1].Padding, - pptable->DpmDescriptor[PPCLK_VCLK_1].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_VCLK_1].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.a, - pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.b, - pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.c, - pptable->DpmDescriptor[PPCLK_VCLK_1].SsFmin, - pptable->DpmDescriptor[PPCLK_VCLK_1].Padding16); - - dev_info(smu->adev->dev, "FreqTableGfx\n"); - for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableGfx[i]); - - dev_info(smu->adev->dev, "FreqTableVclk\n"); - for (i = 0; i < NUM_VCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableVclk[i]); - - dev_info(smu->adev->dev, "FreqTableDclk\n"); - for (i = 0; i < NUM_DCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableDclk[i]); - - dev_info(smu->adev->dev, "FreqTableSocclk\n"); - for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableSocclk[i]); - - dev_info(smu->adev->dev, "FreqTableUclk\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableUclk[i]); - - dev_info(smu->adev->dev, "FreqTableFclk\n"); - for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableFclk[i]); - - dev_info(smu->adev->dev, "DcModeMaxFreq\n"); - dev_info(smu->adev->dev, " .PPCLK_GFXCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_GFXCLK]); - dev_info(smu->adev->dev, " .PPCLK_SOCCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_SOCCLK]); - dev_info(smu->adev->dev, " .PPCLK_UCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_UCLK]); - dev_info(smu->adev->dev, " .PPCLK_FCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_FCLK]); - dev_info(smu->adev->dev, " .PPCLK_DCLK_0 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_DCLK_0]); - dev_info(smu->adev->dev, " .PPCLK_VCLK_0 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_VCLK_0]); - dev_info(smu->adev->dev, " .PPCLK_DCLK_1 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_DCLK_1]); - dev_info(smu->adev->dev, " .PPCLK_VCLK_1 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_VCLK_1]); - - dev_info(smu->adev->dev, "FreqTableUclkDiv\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FreqTableUclkDiv[i]); - - dev_info(smu->adev->dev, "FclkBoostFreq = 0x%x\n", pptable->FclkBoostFreq); - dev_info(smu->adev->dev, "FclkParamPadding = 0x%x\n", pptable->FclkParamPadding); - - dev_info(smu->adev->dev, "Mp0clkFreq\n"); - for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->Mp0clkFreq[i]); - - dev_info(smu->adev->dev, "Mp0DpmVoltage\n"); - for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->Mp0DpmVoltage[i]); - - dev_info(smu->adev->dev, "MemVddciVoltage\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->MemVddciVoltage[i]); - - dev_info(smu->adev->dev, "MemMvddVoltage\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->MemMvddVoltage[i]); - - dev_info(smu->adev->dev, "GfxclkFgfxoffEntry = 0x%x\n", pptable->GfxclkFgfxoffEntry); - dev_info(smu->adev->dev, "GfxclkFinit = 0x%x\n", pptable->GfxclkFinit); - dev_info(smu->adev->dev, "GfxclkFidle = 0x%x\n", pptable->GfxclkFidle); - dev_info(smu->adev->dev, "GfxclkSource = 0x%x\n", pptable->GfxclkSource); - dev_info(smu->adev->dev, "GfxclkPadding = 0x%x\n", pptable->GfxclkPadding); - - dev_info(smu->adev->dev, "GfxGpoSubFeatureMask = 0x%x\n", pptable->GfxGpoSubFeatureMask); - - dev_info(smu->adev->dev, "GfxGpoEnabledWorkPolicyMask = 0x%x\n", pptable->GfxGpoEnabledWorkPolicyMask); - dev_info(smu->adev->dev, "GfxGpoDisabledWorkPolicyMask = 0x%x\n", pptable->GfxGpoDisabledWorkPolicyMask); - dev_info(smu->adev->dev, "GfxGpoPadding[0] = 0x%x\n", pptable->GfxGpoPadding[0]); - dev_info(smu->adev->dev, "GfxGpoVotingAllow = 0x%x\n", pptable->GfxGpoVotingAllow); - dev_info(smu->adev->dev, "GfxGpoPadding32[0] = 0x%x\n", pptable->GfxGpoPadding32[0]); - dev_info(smu->adev->dev, "GfxGpoPadding32[1] = 0x%x\n", pptable->GfxGpoPadding32[1]); - dev_info(smu->adev->dev, "GfxGpoPadding32[2] = 0x%x\n", pptable->GfxGpoPadding32[2]); - dev_info(smu->adev->dev, "GfxGpoPadding32[3] = 0x%x\n", pptable->GfxGpoPadding32[3]); - dev_info(smu->adev->dev, "GfxDcsFopt = 0x%x\n", pptable->GfxDcsFopt); - dev_info(smu->adev->dev, "GfxDcsFclkFopt = 0x%x\n", pptable->GfxDcsFclkFopt); - dev_info(smu->adev->dev, "GfxDcsUclkFopt = 0x%x\n", pptable->GfxDcsUclkFopt); - - dev_info(smu->adev->dev, "DcsGfxOffVoltage = 0x%x\n", pptable->DcsGfxOffVoltage); - dev_info(smu->adev->dev, "DcsMinGfxOffTime = 0x%x\n", pptable->DcsMinGfxOffTime); - dev_info(smu->adev->dev, "DcsMaxGfxOffTime = 0x%x\n", pptable->DcsMaxGfxOffTime); - dev_info(smu->adev->dev, "DcsMinCreditAccum = 0x%x\n", pptable->DcsMinCreditAccum); - dev_info(smu->adev->dev, "DcsExitHysteresis = 0x%x\n", pptable->DcsExitHysteresis); - dev_info(smu->adev->dev, "DcsTimeout = 0x%x\n", pptable->DcsTimeout); - - dev_info(smu->adev->dev, "DcsParamPadding[0] = 0x%x\n", pptable->DcsParamPadding[0]); - dev_info(smu->adev->dev, "DcsParamPadding[1] = 0x%x\n", pptable->DcsParamPadding[1]); - dev_info(smu->adev->dev, "DcsParamPadding[2] = 0x%x\n", pptable->DcsParamPadding[2]); - dev_info(smu->adev->dev, "DcsParamPadding[3] = 0x%x\n", pptable->DcsParamPadding[3]); - dev_info(smu->adev->dev, "DcsParamPadding[4] = 0x%x\n", pptable->DcsParamPadding[4]); - - dev_info(smu->adev->dev, "FlopsPerByteTable\n"); - for (i = 0; i < RLC_PACE_TABLE_NUM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FlopsPerByteTable[i]); - - dev_info(smu->adev->dev, "LowestUclkReservedForUlv = 0x%x\n", pptable->LowestUclkReservedForUlv); - dev_info(smu->adev->dev, "vddingMem[0] = 0x%x\n", pptable->PaddingMem[0]); - dev_info(smu->adev->dev, "vddingMem[1] = 0x%x\n", pptable->PaddingMem[1]); - dev_info(smu->adev->dev, "vddingMem[2] = 0x%x\n", pptable->PaddingMem[2]); - - dev_info(smu->adev->dev, "UclkDpmPstates\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->UclkDpmPstates[i]); - - dev_info(smu->adev->dev, "UclkDpmSrcFreqRange\n"); - dev_info(smu->adev->dev, " .Fmin = 0x%x\n", - pptable->UclkDpmSrcFreqRange.Fmin); - dev_info(smu->adev->dev, " .Fmax = 0x%x\n", - pptable->UclkDpmSrcFreqRange.Fmax); - dev_info(smu->adev->dev, "UclkDpmTargFreqRange\n"); - dev_info(smu->adev->dev, " .Fmin = 0x%x\n", - pptable->UclkDpmTargFreqRange.Fmin); - dev_info(smu->adev->dev, " .Fmax = 0x%x\n", - pptable->UclkDpmTargFreqRange.Fmax); - dev_info(smu->adev->dev, "UclkDpmMidstepFreq = 0x%x\n", pptable->UclkDpmMidstepFreq); - dev_info(smu->adev->dev, "UclkMidstepPadding = 0x%x\n", pptable->UclkMidstepPadding); - - dev_info(smu->adev->dev, "PcieGenSpeed\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->PcieGenSpeed[i]); - - dev_info(smu->adev->dev, "PcieLaneCount\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->PcieLaneCount[i]); - - dev_info(smu->adev->dev, "LclkFreq\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->LclkFreq[i]); - - dev_info(smu->adev->dev, "FanStopTemp = 0x%x\n", pptable->FanStopTemp); - dev_info(smu->adev->dev, "FanStartTemp = 0x%x\n", pptable->FanStartTemp); - - dev_info(smu->adev->dev, "FanGain\n"); - for (i = 0; i < TEMP_COUNT; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FanGain[i]); - - dev_info(smu->adev->dev, "FanPwmMin = 0x%x\n", pptable->FanPwmMin); - dev_info(smu->adev->dev, "FanAcousticLimitRpm = 0x%x\n", pptable->FanAcousticLimitRpm); - dev_info(smu->adev->dev, "FanThrottlingRpm = 0x%x\n", pptable->FanThrottlingRpm); - dev_info(smu->adev->dev, "FanMaximumRpm = 0x%x\n", pptable->FanMaximumRpm); - dev_info(smu->adev->dev, "MGpuFanBoostLimitRpm = 0x%x\n", pptable->MGpuFanBoostLimitRpm); - dev_info(smu->adev->dev, "FanTargetTemperature = 0x%x\n", pptable->FanTargetTemperature); - dev_info(smu->adev->dev, "FanTargetGfxclk = 0x%x\n", pptable->FanTargetGfxclk); - dev_info(smu->adev->dev, "FanPadding16 = 0x%x\n", pptable->FanPadding16); - dev_info(smu->adev->dev, "FanTempInputSelect = 0x%x\n", pptable->FanTempInputSelect); - dev_info(smu->adev->dev, "FanPadding = 0x%x\n", pptable->FanPadding); - dev_info(smu->adev->dev, "FanZeroRpmEnable = 0x%x\n", pptable->FanZeroRpmEnable); - dev_info(smu->adev->dev, "FanTachEdgePerRev = 0x%x\n", pptable->FanTachEdgePerRev); - - dev_info(smu->adev->dev, "FuzzyFan_ErrorSetDelta = 0x%x\n", pptable->FuzzyFan_ErrorSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_ErrorRateSetDelta = 0x%x\n", pptable->FuzzyFan_ErrorRateSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_PwmSetDelta = 0x%x\n", pptable->FuzzyFan_PwmSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_Reserved = 0x%x\n", pptable->FuzzyFan_Reserved); - - dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "dBtcGbGfxDfllModelSelect = 0x%x\n", pptable->dBtcGbGfxDfllModelSelect); - dev_info(smu->adev->dev, "Padding8_Avfs = 0x%x\n", pptable->Padding8_Avfs); - - dev_info(smu->adev->dev, "qAvfsGb[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].a, - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].b, - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].c); - dev_info(smu->adev->dev, "qAvfsGb[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].a, - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].b, - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].c); - dev_info(smu->adev->dev, "dBtcGbGfxPll{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxPll.a, - pptable->dBtcGbGfxPll.b, - pptable->dBtcGbGfxPll.c); - dev_info(smu->adev->dev, "dBtcGbGfxAfll{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxDfll.a, - pptable->dBtcGbGfxDfll.b, - pptable->dBtcGbGfxDfll.c); - dev_info(smu->adev->dev, "dBtcGbSoc{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbSoc.a, - pptable->dBtcGbSoc.b, - pptable->dBtcGbSoc.c); - dev_info(smu->adev->dev, "qAgingGb[AVFS_VOLTAGE_GFX]{m = 0x%x b = 0x%x}\n", - pptable->qAgingGb[AVFS_VOLTAGE_GFX].m, - pptable->qAgingGb[AVFS_VOLTAGE_GFX].b); - dev_info(smu->adev->dev, "qAgingGb[AVFS_VOLTAGE_SOC]{m = 0x%x b = 0x%x}\n", - pptable->qAgingGb[AVFS_VOLTAGE_SOC].m, - pptable->qAgingGb[AVFS_VOLTAGE_SOC].b); - - dev_info(smu->adev->dev, "PiecewiseLinearDroopIntGfxDfll\n"); - for (i = 0; i < NUM_PIECE_WISE_LINEAR_DROOP_MODEL_VF_POINTS; i++) { - dev_info(smu->adev->dev, " Fset[%d] = 0x%x\n", - i, pptable->PiecewiseLinearDroopIntGfxDfll.Fset[i]); - dev_info(smu->adev->dev, " Vdroop[%d] = 0x%x\n", - i, pptable->PiecewiseLinearDroopIntGfxDfll.Vdroop[i]); - } - - dev_info(smu->adev->dev, "qStaticVoltageOffset[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].a, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].b, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].c); - dev_info(smu->adev->dev, "qStaticVoltageOffset[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].a, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].b, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].c); - - dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "Padding8_GfxBtc[0] = 0x%x\n", pptable->Padding8_GfxBtc[0]); - dev_info(smu->adev->dev, "Padding8_GfxBtc[1] = 0x%x\n", pptable->Padding8_GfxBtc[1]); - - dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "XgmiDpmPstates\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiDpmPstates[i]); - dev_info(smu->adev->dev, "XgmiDpmSpare[0] = 0x%02x\n", pptable->XgmiDpmSpare[0]); - dev_info(smu->adev->dev, "XgmiDpmSpare[1] = 0x%02x\n", pptable->XgmiDpmSpare[1]); - - dev_info(smu->adev->dev, "DebugOverrides = 0x%x\n", pptable->DebugOverrides); - dev_info(smu->adev->dev, "ReservedEquation0{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation0.a, - pptable->ReservedEquation0.b, - pptable->ReservedEquation0.c); - dev_info(smu->adev->dev, "ReservedEquation1{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation1.a, - pptable->ReservedEquation1.b, - pptable->ReservedEquation1.c); - dev_info(smu->adev->dev, "ReservedEquation2{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation2.a, - pptable->ReservedEquation2.b, - pptable->ReservedEquation2.c); - dev_info(smu->adev->dev, "ReservedEquation3{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation3.a, - pptable->ReservedEquation3.b, - pptable->ReservedEquation3.c); - - dev_info(smu->adev->dev, "SkuReserved[0] = 0x%x\n", pptable->SkuReserved[0]); - dev_info(smu->adev->dev, "SkuReserved[1] = 0x%x\n", pptable->SkuReserved[1]); - dev_info(smu->adev->dev, "SkuReserved[2] = 0x%x\n", pptable->SkuReserved[2]); - dev_info(smu->adev->dev, "SkuReserved[3] = 0x%x\n", pptable->SkuReserved[3]); - dev_info(smu->adev->dev, "SkuReserved[4] = 0x%x\n", pptable->SkuReserved[4]); - dev_info(smu->adev->dev, "SkuReserved[5] = 0x%x\n", pptable->SkuReserved[5]); - dev_info(smu->adev->dev, "SkuReserved[6] = 0x%x\n", pptable->SkuReserved[6]); - dev_info(smu->adev->dev, "SkuReserved[7] = 0x%x\n", pptable->SkuReserved[7]); - - dev_info(smu->adev->dev, "GamingClk[0] = 0x%x\n", pptable->GamingClk[0]); - dev_info(smu->adev->dev, "GamingClk[1] = 0x%x\n", pptable->GamingClk[1]); - dev_info(smu->adev->dev, "GamingClk[2] = 0x%x\n", pptable->GamingClk[2]); - dev_info(smu->adev->dev, "GamingClk[3] = 0x%x\n", pptable->GamingClk[3]); - dev_info(smu->adev->dev, "GamingClk[4] = 0x%x\n", pptable->GamingClk[4]); - dev_info(smu->adev->dev, "GamingClk[5] = 0x%x\n", pptable->GamingClk[5]); - - for (i = 0; i < NUM_I2C_CONTROLLERS; i++) { - dev_info(smu->adev->dev, "I2cControllers[%d]:\n", i); - dev_info(smu->adev->dev, " .Enabled = 0x%x\n", - pptable->I2cControllers[i].Enabled); - dev_info(smu->adev->dev, " .Speed = 0x%x\n", - pptable->I2cControllers[i].Speed); - dev_info(smu->adev->dev, " .SlaveAddress = 0x%x\n", - pptable->I2cControllers[i].SlaveAddress); - dev_info(smu->adev->dev, " .ControllerPort = 0x%x\n", - pptable->I2cControllers[i].ControllerPort); - dev_info(smu->adev->dev, " .ControllerName = 0x%x\n", - pptable->I2cControllers[i].ControllerName); - dev_info(smu->adev->dev, " .ThermalThrottler = 0x%x\n", - pptable->I2cControllers[i].ThermalThrotter); - dev_info(smu->adev->dev, " .I2cProtocol = 0x%x\n", - pptable->I2cControllers[i].I2cProtocol); - dev_info(smu->adev->dev, " .PaddingConfig = 0x%x\n", - pptable->I2cControllers[i].PaddingConfig); - } - - dev_info(smu->adev->dev, "GpioScl = 0x%x\n", pptable->GpioScl); - dev_info(smu->adev->dev, "GpioSda = 0x%x\n", pptable->GpioSda); - dev_info(smu->adev->dev, "FchUsbPdSlaveAddr = 0x%x\n", pptable->FchUsbPdSlaveAddr); - dev_info(smu->adev->dev, "I2cSpare[0] = 0x%x\n", pptable->I2cSpare[0]); - - dev_info(smu->adev->dev, "Board Parameters:\n"); - dev_info(smu->adev->dev, "VddGfxVrMapping = 0x%x\n", pptable->VddGfxVrMapping); - dev_info(smu->adev->dev, "VddSocVrMapping = 0x%x\n", pptable->VddSocVrMapping); - dev_info(smu->adev->dev, "VddMem0VrMapping = 0x%x\n", pptable->VddMem0VrMapping); - dev_info(smu->adev->dev, "VddMem1VrMapping = 0x%x\n", pptable->VddMem1VrMapping); - dev_info(smu->adev->dev, "GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); - dev_info(smu->adev->dev, "SocUlvPhaseSheddingMask = 0x%x\n", pptable->SocUlvPhaseSheddingMask); - dev_info(smu->adev->dev, "VddciUlvPhaseSheddingMask = 0x%x\n", pptable->VddciUlvPhaseSheddingMask); - dev_info(smu->adev->dev, "MvddUlvPhaseSheddingMask = 0x%x\n", pptable->MvddUlvPhaseSheddingMask); - - dev_info(smu->adev->dev, "GfxMaxCurrent = 0x%x\n", pptable->GfxMaxCurrent); - dev_info(smu->adev->dev, "GfxOffset = 0x%x\n", pptable->GfxOffset); - dev_info(smu->adev->dev, "Padding_TelemetryGfx = 0x%x\n", pptable->Padding_TelemetryGfx); - - dev_info(smu->adev->dev, "SocMaxCurrent = 0x%x\n", pptable->SocMaxCurrent); - dev_info(smu->adev->dev, "SocOffset = 0x%x\n", pptable->SocOffset); - dev_info(smu->adev->dev, "Padding_TelemetrySoc = 0x%x\n", pptable->Padding_TelemetrySoc); - - dev_info(smu->adev->dev, "Mem0MaxCurrent = 0x%x\n", pptable->Mem0MaxCurrent); - dev_info(smu->adev->dev, "Mem0Offset = 0x%x\n", pptable->Mem0Offset); - dev_info(smu->adev->dev, "Padding_TelemetryMem0 = 0x%x\n", pptable->Padding_TelemetryMem0); - - dev_info(smu->adev->dev, "Mem1MaxCurrent = 0x%x\n", pptable->Mem1MaxCurrent); - dev_info(smu->adev->dev, "Mem1Offset = 0x%x\n", pptable->Mem1Offset); - dev_info(smu->adev->dev, "Padding_TelemetryMem1 = 0x%x\n", pptable->Padding_TelemetryMem1); - - dev_info(smu->adev->dev, "MvddRatio = 0x%x\n", pptable->MvddRatio); - - dev_info(smu->adev->dev, "AcDcGpio = 0x%x\n", pptable->AcDcGpio); - dev_info(smu->adev->dev, "AcDcPolarity = 0x%x\n", pptable->AcDcPolarity); - dev_info(smu->adev->dev, "VR0HotGpio = 0x%x\n", pptable->VR0HotGpio); - dev_info(smu->adev->dev, "VR0HotPolarity = 0x%x\n", pptable->VR0HotPolarity); - dev_info(smu->adev->dev, "VR1HotGpio = 0x%x\n", pptable->VR1HotGpio); - dev_info(smu->adev->dev, "VR1HotPolarity = 0x%x\n", pptable->VR1HotPolarity); - dev_info(smu->adev->dev, "GthrGpio = 0x%x\n", pptable->GthrGpio); - dev_info(smu->adev->dev, "GthrPolarity = 0x%x\n", pptable->GthrPolarity); - dev_info(smu->adev->dev, "LedPin0 = 0x%x\n", pptable->LedPin0); - dev_info(smu->adev->dev, "LedPin1 = 0x%x\n", pptable->LedPin1); - dev_info(smu->adev->dev, "LedPin2 = 0x%x\n", pptable->LedPin2); - dev_info(smu->adev->dev, "LedEnableMask = 0x%x\n", pptable->LedEnableMask); - dev_info(smu->adev->dev, "LedPcie = 0x%x\n", pptable->LedPcie); - dev_info(smu->adev->dev, "LedError = 0x%x\n", pptable->LedError); - dev_info(smu->adev->dev, "LedSpare1[0] = 0x%x\n", pptable->LedSpare1[0]); - dev_info(smu->adev->dev, "LedSpare1[1] = 0x%x\n", pptable->LedSpare1[1]); - - dev_info(smu->adev->dev, "PllGfxclkSpreadEnabled = 0x%x\n", pptable->PllGfxclkSpreadEnabled); - dev_info(smu->adev->dev, "PllGfxclkSpreadPercent = 0x%x\n", pptable->PllGfxclkSpreadPercent); - dev_info(smu->adev->dev, "PllGfxclkSpreadFreq = 0x%x\n", pptable->PllGfxclkSpreadFreq); - - dev_info(smu->adev->dev, "DfllGfxclkSpreadEnabled = 0x%x\n", pptable->DfllGfxclkSpreadEnabled); - dev_info(smu->adev->dev, "DfllGfxclkSpreadPercent = 0x%x\n", pptable->DfllGfxclkSpreadPercent); - dev_info(smu->adev->dev, "DfllGfxclkSpreadFreq = 0x%x\n", pptable->DfllGfxclkSpreadFreq); - - dev_info(smu->adev->dev, "UclkSpreadPadding = 0x%x\n", pptable->UclkSpreadPadding); - dev_info(smu->adev->dev, "UclkSpreadFreq = 0x%x\n", pptable->UclkSpreadFreq); - - dev_info(smu->adev->dev, "FclkSpreadEnabled = 0x%x\n", pptable->FclkSpreadEnabled); - dev_info(smu->adev->dev, "FclkSpreadPercent = 0x%x\n", pptable->FclkSpreadPercent); - dev_info(smu->adev->dev, "FclkSpreadFreq = 0x%x\n", pptable->FclkSpreadFreq); - - dev_info(smu->adev->dev, "MemoryChannelEnabled = 0x%x\n", pptable->MemoryChannelEnabled); - dev_info(smu->adev->dev, "DramBitWidth = 0x%x\n", pptable->DramBitWidth); - dev_info(smu->adev->dev, "PaddingMem1[0] = 0x%x\n", pptable->PaddingMem1[0]); - dev_info(smu->adev->dev, "PaddingMem1[1] = 0x%x\n", pptable->PaddingMem1[1]); - dev_info(smu->adev->dev, "PaddingMem1[2] = 0x%x\n", pptable->PaddingMem1[2]); - - dev_info(smu->adev->dev, "TotalBoardPower = 0x%x\n", pptable->TotalBoardPower); - dev_info(smu->adev->dev, "BoardPowerPadding = 0x%x\n", pptable->BoardPowerPadding); - - dev_info(smu->adev->dev, "XgmiLinkSpeed\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiLinkSpeed[i]); - dev_info(smu->adev->dev, "XgmiLinkWidth\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiLinkWidth[i]); - dev_info(smu->adev->dev, "XgmiFclkFreq\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiFclkFreq[i]); - dev_info(smu->adev->dev, "XgmiSocVoltage\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiSocVoltage[i]); - - dev_info(smu->adev->dev, "HsrEnabled = 0x%x\n", pptable->HsrEnabled); - dev_info(smu->adev->dev, "VddqOffEnabled = 0x%x\n", pptable->VddqOffEnabled); - dev_info(smu->adev->dev, "PaddingUmcFlags[0] = 0x%x\n", pptable->PaddingUmcFlags[0]); - dev_info(smu->adev->dev, "PaddingUmcFlags[1] = 0x%x\n", pptable->PaddingUmcFlags[1]); - - dev_info(smu->adev->dev, "BoardReserved[0] = 0x%x\n", pptable->BoardReserved[0]); - dev_info(smu->adev->dev, "BoardReserved[1] = 0x%x\n", pptable->BoardReserved[1]); - dev_info(smu->adev->dev, "BoardReserved[2] = 0x%x\n", pptable->BoardReserved[2]); - dev_info(smu->adev->dev, "BoardReserved[3] = 0x%x\n", pptable->BoardReserved[3]); - dev_info(smu->adev->dev, "BoardReserved[4] = 0x%x\n", pptable->BoardReserved[4]); - dev_info(smu->adev->dev, "BoardReserved[5] = 0x%x\n", pptable->BoardReserved[5]); - dev_info(smu->adev->dev, "BoardReserved[6] = 0x%x\n", pptable->BoardReserved[6]); - dev_info(smu->adev->dev, "BoardReserved[7] = 0x%x\n", pptable->BoardReserved[7]); - dev_info(smu->adev->dev, "BoardReserved[8] = 0x%x\n", pptable->BoardReserved[8]); - dev_info(smu->adev->dev, "BoardReserved[9] = 0x%x\n", pptable->BoardReserved[9]); - dev_info(smu->adev->dev, "BoardReserved[10] = 0x%x\n", pptable->BoardReserved[10]); - - dev_info(smu->adev->dev, "MmHubPadding[0] = 0x%x\n", pptable->MmHubPadding[0]); - dev_info(smu->adev->dev, "MmHubPadding[1] = 0x%x\n", pptable->MmHubPadding[1]); - dev_info(smu->adev->dev, "MmHubPadding[2] = 0x%x\n", pptable->MmHubPadding[2]); - dev_info(smu->adev->dev, "MmHubPadding[3] = 0x%x\n", pptable->MmHubPadding[3]); - dev_info(smu->adev->dev, "MmHubPadding[4] = 0x%x\n", pptable->MmHubPadding[4]); - dev_info(smu->adev->dev, "MmHubPadding[5] = 0x%x\n", pptable->MmHubPadding[5]); - dev_info(smu->adev->dev, "MmHubPadding[6] = 0x%x\n", pptable->MmHubPadding[6]); - dev_info(smu->adev->dev, "MmHubPadding[7] = 0x%x\n", pptable->MmHubPadding[7]); -} - -static void sienna_cichlid_dump_pptable(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - PPTable_t *pptable = table_context->driver_pptable; - int i; - - if (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == - IP_VERSION(11, 0, 13)) { - beige_goby_dump_pptable(smu); - return; - } - - dev_info(smu->adev->dev, "Dumped PPTable:\n"); - - dev_info(smu->adev->dev, "Version = 0x%08x\n", pptable->Version); - dev_info(smu->adev->dev, "FeaturesToRun[0] = 0x%08x\n", pptable->FeaturesToRun[0]); - dev_info(smu->adev->dev, "FeaturesToRun[1] = 0x%08x\n", pptable->FeaturesToRun[1]); - - for (i = 0; i < PPT_THROTTLER_COUNT; i++) { - dev_info(smu->adev->dev, "SocketPowerLimitAc[%d] = 0x%x\n", i, pptable->SocketPowerLimitAc[i]); - dev_info(smu->adev->dev, "SocketPowerLimitAcTau[%d] = 0x%x\n", i, pptable->SocketPowerLimitAcTau[i]); - dev_info(smu->adev->dev, "SocketPowerLimitDc[%d] = 0x%x\n", i, pptable->SocketPowerLimitDc[i]); - dev_info(smu->adev->dev, "SocketPowerLimitDcTau[%d] = 0x%x\n", i, pptable->SocketPowerLimitDcTau[i]); - } - - for (i = 0; i < TDC_THROTTLER_COUNT; i++) { - dev_info(smu->adev->dev, "TdcLimit[%d] = 0x%x\n", i, pptable->TdcLimit[i]); - dev_info(smu->adev->dev, "TdcLimitTau[%d] = 0x%x\n", i, pptable->TdcLimitTau[i]); - } - - for (i = 0; i < TEMP_COUNT; i++) { - dev_info(smu->adev->dev, "TemperatureLimit[%d] = 0x%x\n", i, pptable->TemperatureLimit[i]); - } - - dev_info(smu->adev->dev, "FitLimit = 0x%x\n", pptable->FitLimit); - dev_info(smu->adev->dev, "TotalPowerConfig = 0x%x\n", pptable->TotalPowerConfig); - dev_info(smu->adev->dev, "TotalPowerPadding[0] = 0x%x\n", pptable->TotalPowerPadding[0]); - dev_info(smu->adev->dev, "TotalPowerPadding[1] = 0x%x\n", pptable->TotalPowerPadding[1]); - dev_info(smu->adev->dev, "TotalPowerPadding[2] = 0x%x\n", pptable->TotalPowerPadding[2]); - - dev_info(smu->adev->dev, "ApccPlusResidencyLimit = 0x%x\n", pptable->ApccPlusResidencyLimit); - for (i = 0; i < NUM_SMNCLK_DPM_LEVELS; i++) { - dev_info(smu->adev->dev, "SmnclkDpmFreq[%d] = 0x%x\n", i, pptable->SmnclkDpmFreq[i]); - dev_info(smu->adev->dev, "SmnclkDpmVoltage[%d] = 0x%x\n", i, pptable->SmnclkDpmVoltage[i]); - } - dev_info(smu->adev->dev, "ThrottlerControlMask = 0x%x\n", pptable->ThrottlerControlMask); - - dev_info(smu->adev->dev, "FwDStateMask = 0x%x\n", pptable->FwDStateMask); - - dev_info(smu->adev->dev, "UlvVoltageOffsetSoc = 0x%x\n", pptable->UlvVoltageOffsetSoc); - dev_info(smu->adev->dev, "UlvVoltageOffsetGfx = 0x%x\n", pptable->UlvVoltageOffsetGfx); - dev_info(smu->adev->dev, "MinVoltageUlvGfx = 0x%x\n", pptable->MinVoltageUlvGfx); - dev_info(smu->adev->dev, "MinVoltageUlvSoc = 0x%x\n", pptable->MinVoltageUlvSoc); - - dev_info(smu->adev->dev, "SocLIVmin = 0x%x\n", pptable->SocLIVmin); - dev_info(smu->adev->dev, "PaddingLIVmin = 0x%x\n", pptable->PaddingLIVmin); - - dev_info(smu->adev->dev, "GceaLinkMgrIdleThreshold = 0x%x\n", pptable->GceaLinkMgrIdleThreshold); - dev_info(smu->adev->dev, "paddingRlcUlvParams[0] = 0x%x\n", pptable->paddingRlcUlvParams[0]); - dev_info(smu->adev->dev, "paddingRlcUlvParams[1] = 0x%x\n", pptable->paddingRlcUlvParams[1]); - dev_info(smu->adev->dev, "paddingRlcUlvParams[2] = 0x%x\n", pptable->paddingRlcUlvParams[2]); - - dev_info(smu->adev->dev, "MinVoltageGfx = 0x%x\n", pptable->MinVoltageGfx); - dev_info(smu->adev->dev, "MinVoltageSoc = 0x%x\n", pptable->MinVoltageSoc); - dev_info(smu->adev->dev, "MaxVoltageGfx = 0x%x\n", pptable->MaxVoltageGfx); - dev_info(smu->adev->dev, "MaxVoltageSoc = 0x%x\n", pptable->MaxVoltageSoc); - - dev_info(smu->adev->dev, "LoadLineResistanceGfx = 0x%x\n", pptable->LoadLineResistanceGfx); - dev_info(smu->adev->dev, "LoadLineResistanceSoc = 0x%x\n", pptable->LoadLineResistanceSoc); - - dev_info(smu->adev->dev, "VDDGFX_TVmin = 0x%x\n", pptable->VDDGFX_TVmin); - dev_info(smu->adev->dev, "VDDSOC_TVmin = 0x%x\n", pptable->VDDSOC_TVmin); - dev_info(smu->adev->dev, "VDDGFX_Vmin_HiTemp = 0x%x\n", pptable->VDDGFX_Vmin_HiTemp); - dev_info(smu->adev->dev, "VDDGFX_Vmin_LoTemp = 0x%x\n", pptable->VDDGFX_Vmin_LoTemp); - dev_info(smu->adev->dev, "VDDSOC_Vmin_HiTemp = 0x%x\n", pptable->VDDSOC_Vmin_HiTemp); - dev_info(smu->adev->dev, "VDDSOC_Vmin_LoTemp = 0x%x\n", pptable->VDDSOC_Vmin_LoTemp); - dev_info(smu->adev->dev, "VDDGFX_TVminHystersis = 0x%x\n", pptable->VDDGFX_TVminHystersis); - dev_info(smu->adev->dev, "VDDSOC_TVminHystersis = 0x%x\n", pptable->VDDSOC_TVminHystersis); - - dev_info(smu->adev->dev, "[PPCLK_GFXCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_GFXCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_GFXCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_GFXCLK].Padding, - pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_GFXCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_GFXCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_SOCCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_SOCCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_SOCCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_SOCCLK].Padding, - pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_SOCCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_SOCCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_UCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_UCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_UCLK].Padding, - pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_UCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_UCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_FCLK]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_FCLK].VoltageMode, - pptable->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_FCLK].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_FCLK].Padding, - pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.a, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.b, - pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.c, - pptable->DpmDescriptor[PPCLK_FCLK].SsFmin, - pptable->DpmDescriptor[PPCLK_FCLK].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_DCLK_0]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_DCLK_0].VoltageMode, - pptable->DpmDescriptor[PPCLK_DCLK_0].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_DCLK_0].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_DCLK_0].Padding, - pptable->DpmDescriptor[PPCLK_DCLK_0].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_DCLK_0].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.a, - pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.b, - pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.c, - pptable->DpmDescriptor[PPCLK_DCLK_0].SsFmin, - pptable->DpmDescriptor[PPCLK_DCLK_0].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_VCLK_0]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_VCLK_0].VoltageMode, - pptable->DpmDescriptor[PPCLK_VCLK_0].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_VCLK_0].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_VCLK_0].Padding, - pptable->DpmDescriptor[PPCLK_VCLK_0].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_VCLK_0].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.a, - pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.b, - pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.c, - pptable->DpmDescriptor[PPCLK_VCLK_0].SsFmin, - pptable->DpmDescriptor[PPCLK_VCLK_0].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_DCLK_1]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_DCLK_1].VoltageMode, - pptable->DpmDescriptor[PPCLK_DCLK_1].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_DCLK_1].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_DCLK_1].Padding, - pptable->DpmDescriptor[PPCLK_DCLK_1].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_DCLK_1].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.a, - pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.b, - pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.c, - pptable->DpmDescriptor[PPCLK_DCLK_1].SsFmin, - pptable->DpmDescriptor[PPCLK_DCLK_1].Padding16); - - dev_info(smu->adev->dev, "[PPCLK_VCLK_1]\n" - " .VoltageMode = 0x%02x\n" - " .SnapToDiscrete = 0x%02x\n" - " .NumDiscreteLevels = 0x%02x\n" - " .padding = 0x%02x\n" - " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" - " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" - " .SsFmin = 0x%04x\n" - " .Padding_16 = 0x%04x\n", - pptable->DpmDescriptor[PPCLK_VCLK_1].VoltageMode, - pptable->DpmDescriptor[PPCLK_VCLK_1].SnapToDiscrete, - pptable->DpmDescriptor[PPCLK_VCLK_1].NumDiscreteLevels, - pptable->DpmDescriptor[PPCLK_VCLK_1].Padding, - pptable->DpmDescriptor[PPCLK_VCLK_1].ConversionToAvfsClk.m, - pptable->DpmDescriptor[PPCLK_VCLK_1].ConversionToAvfsClk.b, - pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.a, - pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.b, - pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.c, - pptable->DpmDescriptor[PPCLK_VCLK_1].SsFmin, - pptable->DpmDescriptor[PPCLK_VCLK_1].Padding16); - - dev_info(smu->adev->dev, "FreqTableGfx\n"); - for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableGfx[i]); - - dev_info(smu->adev->dev, "FreqTableVclk\n"); - for (i = 0; i < NUM_VCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableVclk[i]); - - dev_info(smu->adev->dev, "FreqTableDclk\n"); - for (i = 0; i < NUM_DCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableDclk[i]); - - dev_info(smu->adev->dev, "FreqTableSocclk\n"); - for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableSocclk[i]); - - dev_info(smu->adev->dev, "FreqTableUclk\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableUclk[i]); - - dev_info(smu->adev->dev, "FreqTableFclk\n"); - for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableFclk[i]); - - dev_info(smu->adev->dev, "DcModeMaxFreq\n"); - dev_info(smu->adev->dev, " .PPCLK_GFXCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_GFXCLK]); - dev_info(smu->adev->dev, " .PPCLK_SOCCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_SOCCLK]); - dev_info(smu->adev->dev, " .PPCLK_UCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_UCLK]); - dev_info(smu->adev->dev, " .PPCLK_FCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_FCLK]); - dev_info(smu->adev->dev, " .PPCLK_DCLK_0 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_DCLK_0]); - dev_info(smu->adev->dev, " .PPCLK_VCLK_0 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_VCLK_0]); - dev_info(smu->adev->dev, " .PPCLK_DCLK_1 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_DCLK_1]); - dev_info(smu->adev->dev, " .PPCLK_VCLK_1 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_VCLK_1]); - - dev_info(smu->adev->dev, "FreqTableUclkDiv\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FreqTableUclkDiv[i]); - - dev_info(smu->adev->dev, "FclkBoostFreq = 0x%x\n", pptable->FclkBoostFreq); - dev_info(smu->adev->dev, "FclkParamPadding = 0x%x\n", pptable->FclkParamPadding); - - dev_info(smu->adev->dev, "Mp0clkFreq\n"); - for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->Mp0clkFreq[i]); - - dev_info(smu->adev->dev, "Mp0DpmVoltage\n"); - for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->Mp0DpmVoltage[i]); - - dev_info(smu->adev->dev, "MemVddciVoltage\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->MemVddciVoltage[i]); - - dev_info(smu->adev->dev, "MemMvddVoltage\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->MemMvddVoltage[i]); - - dev_info(smu->adev->dev, "GfxclkFgfxoffEntry = 0x%x\n", pptable->GfxclkFgfxoffEntry); - dev_info(smu->adev->dev, "GfxclkFinit = 0x%x\n", pptable->GfxclkFinit); - dev_info(smu->adev->dev, "GfxclkFidle = 0x%x\n", pptable->GfxclkFidle); - dev_info(smu->adev->dev, "GfxclkSource = 0x%x\n", pptable->GfxclkSource); - dev_info(smu->adev->dev, "GfxclkPadding = 0x%x\n", pptable->GfxclkPadding); - - dev_info(smu->adev->dev, "GfxGpoSubFeatureMask = 0x%x\n", pptable->GfxGpoSubFeatureMask); - - dev_info(smu->adev->dev, "GfxGpoEnabledWorkPolicyMask = 0x%x\n", pptable->GfxGpoEnabledWorkPolicyMask); - dev_info(smu->adev->dev, "GfxGpoDisabledWorkPolicyMask = 0x%x\n", pptable->GfxGpoDisabledWorkPolicyMask); - dev_info(smu->adev->dev, "GfxGpoPadding[0] = 0x%x\n", pptable->GfxGpoPadding[0]); - dev_info(smu->adev->dev, "GfxGpoVotingAllow = 0x%x\n", pptable->GfxGpoVotingAllow); - dev_info(smu->adev->dev, "GfxGpoPadding32[0] = 0x%x\n", pptable->GfxGpoPadding32[0]); - dev_info(smu->adev->dev, "GfxGpoPadding32[1] = 0x%x\n", pptable->GfxGpoPadding32[1]); - dev_info(smu->adev->dev, "GfxGpoPadding32[2] = 0x%x\n", pptable->GfxGpoPadding32[2]); - dev_info(smu->adev->dev, "GfxGpoPadding32[3] = 0x%x\n", pptable->GfxGpoPadding32[3]); - dev_info(smu->adev->dev, "GfxDcsFopt = 0x%x\n", pptable->GfxDcsFopt); - dev_info(smu->adev->dev, "GfxDcsFclkFopt = 0x%x\n", pptable->GfxDcsFclkFopt); - dev_info(smu->adev->dev, "GfxDcsUclkFopt = 0x%x\n", pptable->GfxDcsUclkFopt); - - dev_info(smu->adev->dev, "DcsGfxOffVoltage = 0x%x\n", pptable->DcsGfxOffVoltage); - dev_info(smu->adev->dev, "DcsMinGfxOffTime = 0x%x\n", pptable->DcsMinGfxOffTime); - dev_info(smu->adev->dev, "DcsMaxGfxOffTime = 0x%x\n", pptable->DcsMaxGfxOffTime); - dev_info(smu->adev->dev, "DcsMinCreditAccum = 0x%x\n", pptable->DcsMinCreditAccum); - dev_info(smu->adev->dev, "DcsExitHysteresis = 0x%x\n", pptable->DcsExitHysteresis); - dev_info(smu->adev->dev, "DcsTimeout = 0x%x\n", pptable->DcsTimeout); - - dev_info(smu->adev->dev, "DcsParamPadding[0] = 0x%x\n", pptable->DcsParamPadding[0]); - dev_info(smu->adev->dev, "DcsParamPadding[1] = 0x%x\n", pptable->DcsParamPadding[1]); - dev_info(smu->adev->dev, "DcsParamPadding[2] = 0x%x\n", pptable->DcsParamPadding[2]); - dev_info(smu->adev->dev, "DcsParamPadding[3] = 0x%x\n", pptable->DcsParamPadding[3]); - dev_info(smu->adev->dev, "DcsParamPadding[4] = 0x%x\n", pptable->DcsParamPadding[4]); - - dev_info(smu->adev->dev, "FlopsPerByteTable\n"); - for (i = 0; i < RLC_PACE_TABLE_NUM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FlopsPerByteTable[i]); - - dev_info(smu->adev->dev, "LowestUclkReservedForUlv = 0x%x\n", pptable->LowestUclkReservedForUlv); - dev_info(smu->adev->dev, "vddingMem[0] = 0x%x\n", pptable->PaddingMem[0]); - dev_info(smu->adev->dev, "vddingMem[1] = 0x%x\n", pptable->PaddingMem[1]); - dev_info(smu->adev->dev, "vddingMem[2] = 0x%x\n", pptable->PaddingMem[2]); - - dev_info(smu->adev->dev, "UclkDpmPstates\n"); - for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->UclkDpmPstates[i]); - - dev_info(smu->adev->dev, "UclkDpmSrcFreqRange\n"); - dev_info(smu->adev->dev, " .Fmin = 0x%x\n", - pptable->UclkDpmSrcFreqRange.Fmin); - dev_info(smu->adev->dev, " .Fmax = 0x%x\n", - pptable->UclkDpmSrcFreqRange.Fmax); - dev_info(smu->adev->dev, "UclkDpmTargFreqRange\n"); - dev_info(smu->adev->dev, " .Fmin = 0x%x\n", - pptable->UclkDpmTargFreqRange.Fmin); - dev_info(smu->adev->dev, " .Fmax = 0x%x\n", - pptable->UclkDpmTargFreqRange.Fmax); - dev_info(smu->adev->dev, "UclkDpmMidstepFreq = 0x%x\n", pptable->UclkDpmMidstepFreq); - dev_info(smu->adev->dev, "UclkMidstepPadding = 0x%x\n", pptable->UclkMidstepPadding); - - dev_info(smu->adev->dev, "PcieGenSpeed\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->PcieGenSpeed[i]); - - dev_info(smu->adev->dev, "PcieLaneCount\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->PcieLaneCount[i]); - - dev_info(smu->adev->dev, "LclkFreq\n"); - for (i = 0; i < NUM_LINK_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->LclkFreq[i]); - - dev_info(smu->adev->dev, "FanStopTemp = 0x%x\n", pptable->FanStopTemp); - dev_info(smu->adev->dev, "FanStartTemp = 0x%x\n", pptable->FanStartTemp); - - dev_info(smu->adev->dev, "FanGain\n"); - for (i = 0; i < TEMP_COUNT; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FanGain[i]); - - dev_info(smu->adev->dev, "FanPwmMin = 0x%x\n", pptable->FanPwmMin); - dev_info(smu->adev->dev, "FanAcousticLimitRpm = 0x%x\n", pptable->FanAcousticLimitRpm); - dev_info(smu->adev->dev, "FanThrottlingRpm = 0x%x\n", pptable->FanThrottlingRpm); - dev_info(smu->adev->dev, "FanMaximumRpm = 0x%x\n", pptable->FanMaximumRpm); - dev_info(smu->adev->dev, "MGpuFanBoostLimitRpm = 0x%x\n", pptable->MGpuFanBoostLimitRpm); - dev_info(smu->adev->dev, "FanTargetTemperature = 0x%x\n", pptable->FanTargetTemperature); - dev_info(smu->adev->dev, "FanTargetGfxclk = 0x%x\n", pptable->FanTargetGfxclk); - dev_info(smu->adev->dev, "FanPadding16 = 0x%x\n", pptable->FanPadding16); - dev_info(smu->adev->dev, "FanTempInputSelect = 0x%x\n", pptable->FanTempInputSelect); - dev_info(smu->adev->dev, "FanPadding = 0x%x\n", pptable->FanPadding); - dev_info(smu->adev->dev, "FanZeroRpmEnable = 0x%x\n", pptable->FanZeroRpmEnable); - dev_info(smu->adev->dev, "FanTachEdgePerRev = 0x%x\n", pptable->FanTachEdgePerRev); - - dev_info(smu->adev->dev, "FuzzyFan_ErrorSetDelta = 0x%x\n", pptable->FuzzyFan_ErrorSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_ErrorRateSetDelta = 0x%x\n", pptable->FuzzyFan_ErrorRateSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_PwmSetDelta = 0x%x\n", pptable->FuzzyFan_PwmSetDelta); - dev_info(smu->adev->dev, "FuzzyFan_Reserved = 0x%x\n", pptable->FuzzyFan_Reserved); - - dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "dBtcGbGfxDfllModelSelect = 0x%x\n", pptable->dBtcGbGfxDfllModelSelect); - dev_info(smu->adev->dev, "Padding8_Avfs = 0x%x\n", pptable->Padding8_Avfs); - - dev_info(smu->adev->dev, "qAvfsGb[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].a, - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].b, - pptable->qAvfsGb[AVFS_VOLTAGE_GFX].c); - dev_info(smu->adev->dev, "qAvfsGb[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].a, - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].b, - pptable->qAvfsGb[AVFS_VOLTAGE_SOC].c); - dev_info(smu->adev->dev, "dBtcGbGfxPll{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxPll.a, - pptable->dBtcGbGfxPll.b, - pptable->dBtcGbGfxPll.c); - dev_info(smu->adev->dev, "dBtcGbGfxAfll{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbGfxDfll.a, - pptable->dBtcGbGfxDfll.b, - pptable->dBtcGbGfxDfll.c); - dev_info(smu->adev->dev, "dBtcGbSoc{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->dBtcGbSoc.a, - pptable->dBtcGbSoc.b, - pptable->dBtcGbSoc.c); - dev_info(smu->adev->dev, "qAgingGb[AVFS_VOLTAGE_GFX]{m = 0x%x b = 0x%x}\n", - pptable->qAgingGb[AVFS_VOLTAGE_GFX].m, - pptable->qAgingGb[AVFS_VOLTAGE_GFX].b); - dev_info(smu->adev->dev, "qAgingGb[AVFS_VOLTAGE_SOC]{m = 0x%x b = 0x%x}\n", - pptable->qAgingGb[AVFS_VOLTAGE_SOC].m, - pptable->qAgingGb[AVFS_VOLTAGE_SOC].b); - - dev_info(smu->adev->dev, "PiecewiseLinearDroopIntGfxDfll\n"); - for (i = 0; i < NUM_PIECE_WISE_LINEAR_DROOP_MODEL_VF_POINTS; i++) { - dev_info(smu->adev->dev, " Fset[%d] = 0x%x\n", - i, pptable->PiecewiseLinearDroopIntGfxDfll.Fset[i]); - dev_info(smu->adev->dev, " Vdroop[%d] = 0x%x\n", - i, pptable->PiecewiseLinearDroopIntGfxDfll.Vdroop[i]); - } - - dev_info(smu->adev->dev, "qStaticVoltageOffset[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].a, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].b, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].c); - dev_info(smu->adev->dev, "qStaticVoltageOffset[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].a, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].b, - pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].c); - - dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "Padding8_GfxBtc[0] = 0x%x\n", pptable->Padding8_GfxBtc[0]); - dev_info(smu->adev->dev, "Padding8_GfxBtc[1] = 0x%x\n", pptable->Padding8_GfxBtc[1]); - - dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_SOC]); - dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_GFX]); - dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_SOC]); - - dev_info(smu->adev->dev, "XgmiDpmPstates\n"); - for (i = 0; i < NUM_XGMI_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiDpmPstates[i]); - dev_info(smu->adev->dev, "XgmiDpmSpare[0] = 0x%02x\n", pptable->XgmiDpmSpare[0]); - dev_info(smu->adev->dev, "XgmiDpmSpare[1] = 0x%02x\n", pptable->XgmiDpmSpare[1]); - - dev_info(smu->adev->dev, "DebugOverrides = 0x%x\n", pptable->DebugOverrides); - dev_info(smu->adev->dev, "ReservedEquation0{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation0.a, - pptable->ReservedEquation0.b, - pptable->ReservedEquation0.c); - dev_info(smu->adev->dev, "ReservedEquation1{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation1.a, - pptable->ReservedEquation1.b, - pptable->ReservedEquation1.c); - dev_info(smu->adev->dev, "ReservedEquation2{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation2.a, - pptable->ReservedEquation2.b, - pptable->ReservedEquation2.c); - dev_info(smu->adev->dev, "ReservedEquation3{a = 0x%x b = 0x%x c = 0x%x}\n", - pptable->ReservedEquation3.a, - pptable->ReservedEquation3.b, - pptable->ReservedEquation3.c); - - dev_info(smu->adev->dev, "SkuReserved[0] = 0x%x\n", pptable->SkuReserved[0]); - dev_info(smu->adev->dev, "SkuReserved[1] = 0x%x\n", pptable->SkuReserved[1]); - dev_info(smu->adev->dev, "SkuReserved[2] = 0x%x\n", pptable->SkuReserved[2]); - dev_info(smu->adev->dev, "SkuReserved[3] = 0x%x\n", pptable->SkuReserved[3]); - dev_info(smu->adev->dev, "SkuReserved[4] = 0x%x\n", pptable->SkuReserved[4]); - dev_info(smu->adev->dev, "SkuReserved[5] = 0x%x\n", pptable->SkuReserved[5]); - dev_info(smu->adev->dev, "SkuReserved[6] = 0x%x\n", pptable->SkuReserved[6]); - dev_info(smu->adev->dev, "SkuReserved[7] = 0x%x\n", pptable->SkuReserved[7]); - - dev_info(smu->adev->dev, "GamingClk[0] = 0x%x\n", pptable->GamingClk[0]); - dev_info(smu->adev->dev, "GamingClk[1] = 0x%x\n", pptable->GamingClk[1]); - dev_info(smu->adev->dev, "GamingClk[2] = 0x%x\n", pptable->GamingClk[2]); - dev_info(smu->adev->dev, "GamingClk[3] = 0x%x\n", pptable->GamingClk[3]); - dev_info(smu->adev->dev, "GamingClk[4] = 0x%x\n", pptable->GamingClk[4]); - dev_info(smu->adev->dev, "GamingClk[5] = 0x%x\n", pptable->GamingClk[5]); - - for (i = 0; i < NUM_I2C_CONTROLLERS; i++) { - dev_info(smu->adev->dev, "I2cControllers[%d]:\n", i); - dev_info(smu->adev->dev, " .Enabled = 0x%x\n", - pptable->I2cControllers[i].Enabled); - dev_info(smu->adev->dev, " .Speed = 0x%x\n", - pptable->I2cControllers[i].Speed); - dev_info(smu->adev->dev, " .SlaveAddress = 0x%x\n", - pptable->I2cControllers[i].SlaveAddress); - dev_info(smu->adev->dev, " .ControllerPort = 0x%x\n", - pptable->I2cControllers[i].ControllerPort); - dev_info(smu->adev->dev, " .ControllerName = 0x%x\n", - pptable->I2cControllers[i].ControllerName); - dev_info(smu->adev->dev, " .ThermalThrottler = 0x%x\n", - pptable->I2cControllers[i].ThermalThrotter); - dev_info(smu->adev->dev, " .I2cProtocol = 0x%x\n", - pptable->I2cControllers[i].I2cProtocol); - dev_info(smu->adev->dev, " .PaddingConfig = 0x%x\n", - pptable->I2cControllers[i].PaddingConfig); - } - - dev_info(smu->adev->dev, "GpioScl = 0x%x\n", pptable->GpioScl); - dev_info(smu->adev->dev, "GpioSda = 0x%x\n", pptable->GpioSda); - dev_info(smu->adev->dev, "FchUsbPdSlaveAddr = 0x%x\n", pptable->FchUsbPdSlaveAddr); - dev_info(smu->adev->dev, "I2cSpare[0] = 0x%x\n", pptable->I2cSpare[0]); - - dev_info(smu->adev->dev, "Board Parameters:\n"); - dev_info(smu->adev->dev, "VddGfxVrMapping = 0x%x\n", pptable->VddGfxVrMapping); - dev_info(smu->adev->dev, "VddSocVrMapping = 0x%x\n", pptable->VddSocVrMapping); - dev_info(smu->adev->dev, "VddMem0VrMapping = 0x%x\n", pptable->VddMem0VrMapping); - dev_info(smu->adev->dev, "VddMem1VrMapping = 0x%x\n", pptable->VddMem1VrMapping); - dev_info(smu->adev->dev, "GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); - dev_info(smu->adev->dev, "SocUlvPhaseSheddingMask = 0x%x\n", pptable->SocUlvPhaseSheddingMask); - dev_info(smu->adev->dev, "VddciUlvPhaseSheddingMask = 0x%x\n", pptable->VddciUlvPhaseSheddingMask); - dev_info(smu->adev->dev, "MvddUlvPhaseSheddingMask = 0x%x\n", pptable->MvddUlvPhaseSheddingMask); - - dev_info(smu->adev->dev, "GfxMaxCurrent = 0x%x\n", pptable->GfxMaxCurrent); - dev_info(smu->adev->dev, "GfxOffset = 0x%x\n", pptable->GfxOffset); - dev_info(smu->adev->dev, "Padding_TelemetryGfx = 0x%x\n", pptable->Padding_TelemetryGfx); - - dev_info(smu->adev->dev, "SocMaxCurrent = 0x%x\n", pptable->SocMaxCurrent); - dev_info(smu->adev->dev, "SocOffset = 0x%x\n", pptable->SocOffset); - dev_info(smu->adev->dev, "Padding_TelemetrySoc = 0x%x\n", pptable->Padding_TelemetrySoc); - - dev_info(smu->adev->dev, "Mem0MaxCurrent = 0x%x\n", pptable->Mem0MaxCurrent); - dev_info(smu->adev->dev, "Mem0Offset = 0x%x\n", pptable->Mem0Offset); - dev_info(smu->adev->dev, "Padding_TelemetryMem0 = 0x%x\n", pptable->Padding_TelemetryMem0); - - dev_info(smu->adev->dev, "Mem1MaxCurrent = 0x%x\n", pptable->Mem1MaxCurrent); - dev_info(smu->adev->dev, "Mem1Offset = 0x%x\n", pptable->Mem1Offset); - dev_info(smu->adev->dev, "Padding_TelemetryMem1 = 0x%x\n", pptable->Padding_TelemetryMem1); - - dev_info(smu->adev->dev, "MvddRatio = 0x%x\n", pptable->MvddRatio); - - dev_info(smu->adev->dev, "AcDcGpio = 0x%x\n", pptable->AcDcGpio); - dev_info(smu->adev->dev, "AcDcPolarity = 0x%x\n", pptable->AcDcPolarity); - dev_info(smu->adev->dev, "VR0HotGpio = 0x%x\n", pptable->VR0HotGpio); - dev_info(smu->adev->dev, "VR0HotPolarity = 0x%x\n", pptable->VR0HotPolarity); - dev_info(smu->adev->dev, "VR1HotGpio = 0x%x\n", pptable->VR1HotGpio); - dev_info(smu->adev->dev, "VR1HotPolarity = 0x%x\n", pptable->VR1HotPolarity); - dev_info(smu->adev->dev, "GthrGpio = 0x%x\n", pptable->GthrGpio); - dev_info(smu->adev->dev, "GthrPolarity = 0x%x\n", pptable->GthrPolarity); - dev_info(smu->adev->dev, "LedPin0 = 0x%x\n", pptable->LedPin0); - dev_info(smu->adev->dev, "LedPin1 = 0x%x\n", pptable->LedPin1); - dev_info(smu->adev->dev, "LedPin2 = 0x%x\n", pptable->LedPin2); - dev_info(smu->adev->dev, "LedEnableMask = 0x%x\n", pptable->LedEnableMask); - dev_info(smu->adev->dev, "LedPcie = 0x%x\n", pptable->LedPcie); - dev_info(smu->adev->dev, "LedError = 0x%x\n", pptable->LedError); - dev_info(smu->adev->dev, "LedSpare1[0] = 0x%x\n", pptable->LedSpare1[0]); - dev_info(smu->adev->dev, "LedSpare1[1] = 0x%x\n", pptable->LedSpare1[1]); - - dev_info(smu->adev->dev, "PllGfxclkSpreadEnabled = 0x%x\n", pptable->PllGfxclkSpreadEnabled); - dev_info(smu->adev->dev, "PllGfxclkSpreadPercent = 0x%x\n", pptable->PllGfxclkSpreadPercent); - dev_info(smu->adev->dev, "PllGfxclkSpreadFreq = 0x%x\n", pptable->PllGfxclkSpreadFreq); - - dev_info(smu->adev->dev, "DfllGfxclkSpreadEnabled = 0x%x\n", pptable->DfllGfxclkSpreadEnabled); - dev_info(smu->adev->dev, "DfllGfxclkSpreadPercent = 0x%x\n", pptable->DfllGfxclkSpreadPercent); - dev_info(smu->adev->dev, "DfllGfxclkSpreadFreq = 0x%x\n", pptable->DfllGfxclkSpreadFreq); - - dev_info(smu->adev->dev, "UclkSpreadPadding = 0x%x\n", pptable->UclkSpreadPadding); - dev_info(smu->adev->dev, "UclkSpreadFreq = 0x%x\n", pptable->UclkSpreadFreq); - - dev_info(smu->adev->dev, "FclkSpreadEnabled = 0x%x\n", pptable->FclkSpreadEnabled); - dev_info(smu->adev->dev, "FclkSpreadPercent = 0x%x\n", pptable->FclkSpreadPercent); - dev_info(smu->adev->dev, "FclkSpreadFreq = 0x%x\n", pptable->FclkSpreadFreq); - - dev_info(smu->adev->dev, "MemoryChannelEnabled = 0x%x\n", pptable->MemoryChannelEnabled); - dev_info(smu->adev->dev, "DramBitWidth = 0x%x\n", pptable->DramBitWidth); - dev_info(smu->adev->dev, "PaddingMem1[0] = 0x%x\n", pptable->PaddingMem1[0]); - dev_info(smu->adev->dev, "PaddingMem1[1] = 0x%x\n", pptable->PaddingMem1[1]); - dev_info(smu->adev->dev, "PaddingMem1[2] = 0x%x\n", pptable->PaddingMem1[2]); - - dev_info(smu->adev->dev, "TotalBoardPower = 0x%x\n", pptable->TotalBoardPower); - dev_info(smu->adev->dev, "BoardPowerPadding = 0x%x\n", pptable->BoardPowerPadding); - - dev_info(smu->adev->dev, "XgmiLinkSpeed\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiLinkSpeed[i]); - dev_info(smu->adev->dev, "XgmiLinkWidth\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiLinkWidth[i]); - dev_info(smu->adev->dev, "XgmiFclkFreq\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiFclkFreq[i]); - dev_info(smu->adev->dev, "XgmiSocVoltage\n"); - for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiSocVoltage[i]); - - dev_info(smu->adev->dev, "HsrEnabled = 0x%x\n", pptable->HsrEnabled); - dev_info(smu->adev->dev, "VddqOffEnabled = 0x%x\n", pptable->VddqOffEnabled); - dev_info(smu->adev->dev, "PaddingUmcFlags[0] = 0x%x\n", pptable->PaddingUmcFlags[0]); - dev_info(smu->adev->dev, "PaddingUmcFlags[1] = 0x%x\n", pptable->PaddingUmcFlags[1]); - - dev_info(smu->adev->dev, "BoardReserved[0] = 0x%x\n", pptable->BoardReserved[0]); - dev_info(smu->adev->dev, "BoardReserved[1] = 0x%x\n", pptable->BoardReserved[1]); - dev_info(smu->adev->dev, "BoardReserved[2] = 0x%x\n", pptable->BoardReserved[2]); - dev_info(smu->adev->dev, "BoardReserved[3] = 0x%x\n", pptable->BoardReserved[3]); - dev_info(smu->adev->dev, "BoardReserved[4] = 0x%x\n", pptable->BoardReserved[4]); - dev_info(smu->adev->dev, "BoardReserved[5] = 0x%x\n", pptable->BoardReserved[5]); - dev_info(smu->adev->dev, "BoardReserved[6] = 0x%x\n", pptable->BoardReserved[6]); - dev_info(smu->adev->dev, "BoardReserved[7] = 0x%x\n", pptable->BoardReserved[7]); - dev_info(smu->adev->dev, "BoardReserved[8] = 0x%x\n", pptable->BoardReserved[8]); - dev_info(smu->adev->dev, "BoardReserved[9] = 0x%x\n", pptable->BoardReserved[9]); - dev_info(smu->adev->dev, "BoardReserved[10] = 0x%x\n", pptable->BoardReserved[10]); - - dev_info(smu->adev->dev, "MmHubPadding[0] = 0x%x\n", pptable->MmHubPadding[0]); - dev_info(smu->adev->dev, "MmHubPadding[1] = 0x%x\n", pptable->MmHubPadding[1]); - dev_info(smu->adev->dev, "MmHubPadding[2] = 0x%x\n", pptable->MmHubPadding[2]); - dev_info(smu->adev->dev, "MmHubPadding[3] = 0x%x\n", pptable->MmHubPadding[3]); - dev_info(smu->adev->dev, "MmHubPadding[4] = 0x%x\n", pptable->MmHubPadding[4]); - dev_info(smu->adev->dev, "MmHubPadding[5] = 0x%x\n", pptable->MmHubPadding[5]); - dev_info(smu->adev->dev, "MmHubPadding[6] = 0x%x\n", pptable->MmHubPadding[6]); - dev_info(smu->adev->dev, "MmHubPadding[7] = 0x%x\n", pptable->MmHubPadding[7]); -} - static int sienna_cichlid_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, int num_msgs) { @@ -4397,7 +3167,6 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .display_disable_memory_clock_switch = sienna_cichlid_display_disable_memory_clock_switch, .get_power_limit = sienna_cichlid_get_power_limit, .update_pcie_parameters = sienna_cichlid_update_pcie_parameters, - .dump_pptable = sienna_cichlid_dump_pptable, .init_microcode = smu_v11_0_init_microcode, .load_microcode = smu_v11_0_load_microcode, .fini_microcode = smu_v11_0_fini_microcode, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 16fcd9dcd202e0..480cf3cb204d2d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -1616,7 +1616,8 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) break; default: if (!ras || !adev->ras_enabled || - adev->gmc.xgmi.pending_reset) { + (adev->init_lvl->level == + AMDGPU_INIT_LEVEL_MINIMAL_XGMI)) { if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 2)) { data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL_ARCT); @@ -1763,7 +1764,8 @@ int smu_v11_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c int smu_v11_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, - uint32_t max) + uint32_t max, + bool automatic) { int ret = 0, clk_id = 0; uint32_t param; @@ -1778,7 +1780,10 @@ int smu_v11_0_set_soft_freq_limited_range(struct smu_context *smu, return clk_id; if (max > 0) { - param = (uint32_t)((clk_id << 16) | (max & 0xffff)); + if (automatic) + param = (uint32_t)((clk_id << 16) | 0xffff); + else + param = (uint32_t)((clk_id << 16) | (max & 0xffff)); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq, param, NULL); if (ret) @@ -1786,7 +1791,10 @@ int smu_v11_0_set_soft_freq_limited_range(struct smu_context *smu, } if (min > 0) { - param = (uint32_t)((clk_id << 16) | (min & 0xffff)); + if (automatic) + param = (uint32_t)((clk_id << 16) | 0); + else + param = (uint32_t)((clk_id << 16) | (min & 0xffff)); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq, param, NULL); if (ret) @@ -1854,6 +1862,7 @@ int smu_v11_0_set_performance_level(struct smu_context *smu, uint32_t mclk_min = 0, mclk_max = 0; uint32_t socclk_min = 0, socclk_max = 0; int ret = 0; + bool auto_level = false; switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: @@ -1873,6 +1882,7 @@ int smu_v11_0_set_performance_level(struct smu_context *smu, mclk_max = mem_table->max; socclk_min = soc_table->min; socclk_max = soc_table->max; + auto_level = true; break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: sclk_min = sclk_max = pstate_table->gfxclk_pstate.standard; @@ -1905,13 +1915,15 @@ int smu_v11_0_set_performance_level(struct smu_context *smu, if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(11, 0, 2)) { mclk_min = mclk_max = 0; socclk_min = socclk_max = 0; + auto_level = false; } if (sclk_min && sclk_max) { ret = smu_v11_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, sclk_min, - sclk_max); + sclk_max, + auto_level); if (ret) return ret; } @@ -1920,7 +1932,8 @@ int smu_v11_0_set_performance_level(struct smu_context *smu, ret = smu_v11_0_set_soft_freq_limited_range(smu, SMU_MCLK, mclk_min, - mclk_max); + mclk_max, + auto_level); if (ret) return ret; } @@ -1929,7 +1942,8 @@ int smu_v11_0_set_performance_level(struct smu_context *smu, ret = smu_v11_0_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_min, - socclk_max); + socclk_max, + auto_level); if (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 1fe020f1f4dbe2..a55ea76d739969 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c @@ -461,7 +461,9 @@ static int vangogh_init_smc_tables(struct smu_context *smu) return smu_v11_0_init_smc_tables(smu); } -static int vangogh_dpm_set_vcn_enable(struct smu_context *smu, bool enable) +static int vangogh_dpm_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst) { int ret = 0; @@ -1054,48 +1056,34 @@ static int vangogh_get_power_profile_mode(struct smu_context *smu, return size; } -static int vangogh_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) +static int vangogh_set_power_profile_mode(struct smu_context *smu, + u32 workload_mask, + long *custom_params, + u32 custom_params_max_idx) { - int workload_type, ret; - uint32_t profile_mode = input[size]; + u32 backend_workload_mask = 0; + int ret; - if (profile_mode >= PP_SMC_POWER_PROFILE_COUNT) { - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); - return -EINVAL; - } - - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT || - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) - return 0; - - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - profile_mode); - if (workload_type < 0) { - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on VANGOGH\n", - profile_mode); - return -EINVAL; - } + smu_cmn_get_backend_workload_mask(smu, workload_mask, + &backend_workload_mask); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify, - 1 << workload_type, - NULL); + backend_workload_mask, + NULL); if (ret) { - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", - workload_type); + dev_err_once(smu->adev->dev, "Fail to set workload mask 0x%08x\n", + workload_mask); return ret; } - smu->power_profile_mode = profile_mode; - - return 0; + return ret; } static int vangogh_set_soft_freq_limited_range(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t min, - uint32_t max) + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max, + bool automatic) { int ret = 0; @@ -1301,7 +1289,7 @@ static int vangogh_force_dpm_limit_value(struct smu_context *smu, bool highest) return ret; force_freq = highest ? max_freq : min_freq; - ret = vangogh_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq); + ret = vangogh_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq, false); if (ret) return ret; } @@ -1337,7 +1325,7 @@ static int vangogh_unforce_dpm_levels(struct smu_context *smu) if (ret) return ret; - ret = vangogh_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + ret = vangogh_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false); if (ret) return ret; @@ -1356,7 +1344,7 @@ static int vangogh_set_peak_clock_by_device(struct smu_context *smu) if (ret) return ret; - ret = vangogh_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_freq, fclk_freq); + ret = vangogh_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_freq, fclk_freq, false); if (ret) return ret; @@ -1364,7 +1352,7 @@ static int vangogh_set_peak_clock_by_device(struct smu_context *smu) if (ret) return ret; - ret = vangogh_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_freq, socclk_freq); + ret = vangogh_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_freq, socclk_freq, false); if (ret) return ret; @@ -1372,7 +1360,7 @@ static int vangogh_set_peak_clock_by_device(struct smu_context *smu) if (ret) return ret; - ret = vangogh_set_soft_freq_limited_range(smu, SMU_VCLK, vclk_freq, vclk_freq); + ret = vangogh_set_soft_freq_limited_range(smu, SMU_VCLK, vclk_freq, vclk_freq, false); if (ret) return ret; @@ -1380,7 +1368,7 @@ static int vangogh_set_peak_clock_by_device(struct smu_context *smu) if (ret) return ret; - ret = vangogh_set_soft_freq_limited_range(smu, SMU_DCLK, dclk_freq, dclk_freq); + ret = vangogh_set_soft_freq_limited_range(smu, SMU_DCLK, dclk_freq, dclk_freq, false); if (ret) return ret; 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 cc0504b063fa3a..37d82a71a2d7cd 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -645,7 +645,9 @@ static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context return pm_type; } -static int renoir_dpm_set_vcn_enable(struct smu_context *smu, bool enable) +static int renoir_dpm_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst) { int ret = 0; @@ -707,7 +709,7 @@ static int renoir_force_dpm_limit_value(struct smu_context *smu, bool highest) return ret; force_freq = highest ? max_freq : min_freq; - ret = smu_v12_0_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq); + ret = smu_v12_0_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq, false); if (ret) return ret; } @@ -740,7 +742,7 @@ static int renoir_unforce_dpm_levels(struct smu_context *smu) { if (ret) return ret; - ret = smu_v12_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + ret = smu_v12_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false); if (ret) return ret; } @@ -862,44 +864,27 @@ static int renoir_force_clk_levels(struct smu_context *smu, return ret; } -static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) +static int renoir_set_power_profile_mode(struct smu_context *smu, + u32 workload_mask, + long *custom_params, + u32 custom_params_max_idx) { - int workload_type, ret; - uint32_t profile_mode = input[size]; + int ret; + u32 backend_workload_mask = 0; - if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); - return -EINVAL; - } - - if (profile_mode == PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT || - profile_mode == PP_SMC_POWER_PROFILE_POWERSAVING) - return 0; - - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - profile_mode); - if (workload_type < 0) { - /* - * TODO: If some case need switch to powersave/default power mode - * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving. - */ - dev_dbg(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode); - return -EINVAL; - } + smu_cmn_get_backend_workload_mask(smu, workload_mask, + &backend_workload_mask); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify, - 1 << workload_type, - NULL); + backend_workload_mask, + NULL); if (ret) { - dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type); + dev_err_once(smu->adev->dev, "Failed to set workload mask 0x08%x\n", + workload_mask); return ret; } - smu->power_profile_mode = profile_mode; - - return 0; + return ret; } static int renoir_set_peak_clock_by_device(struct smu_context *smu) @@ -911,7 +896,7 @@ static int renoir_set_peak_clock_by_device(struct smu_context *smu) if (ret) return ret; - ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_SCLK, sclk_freq, sclk_freq); + ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_SCLK, sclk_freq, sclk_freq, false); if (ret) return ret; @@ -919,7 +904,7 @@ static int renoir_set_peak_clock_by_device(struct smu_context *smu) if (ret) return ret; - ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_UCLK, uclk_freq, uclk_freq); + ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_UCLK, uclk_freq, uclk_freq, false); if (ret) return ret; @@ -961,13 +946,13 @@ static int renior_set_dpm_profile_freq(struct smu_context *smu, } if (sclk) - ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_SCLK, sclk, sclk); + ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_SCLK, sclk, sclk, false); if (socclk) - ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk, socclk); + ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk, socclk, false); if (fclk) - ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_FCLK, fclk, fclk); + ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_FCLK, fclk, fclk, false); return ret; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index ed15f5a0fd119f..3d3cd546f0adc4 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -211,7 +211,7 @@ int smu_v12_0_mode2_reset(struct smu_context *smu) } int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, uint32_t max) + uint32_t min, uint32_t max, bool automatic) { int ret = 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 2c35eb31475ab8..f6b0293543275b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1297,9 +1297,10 @@ static int aldebaran_set_performance_level(struct smu_context *smu, } static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t min, - uint32_t max) + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max, + bool automatic) { struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; @@ -1328,7 +1329,7 @@ static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu, return 0; ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, - min, max); + min, max, false); if (!ret) { pstate_table->gfxclk_pstate.curr.min = min; pstate_table->gfxclk_pstate.curr.max = max; @@ -1348,7 +1349,7 @@ static int aldebaran_set_soft_freq_limited_range(struct smu_context *smu, /* Restore default min/max clocks and enable determinism */ min_clk = dpm_context->dpm_tables.gfx_table.min; max_clk = dpm_context->dpm_tables.gfx_table.max; - ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk); + ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk, false); if (!ret) { usleep_range(500, 1000); ret = smu_cmn_send_smc_msg_with_param(smu, @@ -1422,7 +1423,7 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_ min_clk = dpm_context->dpm_tables.gfx_table.min; max_clk = dpm_context->dpm_tables.gfx_table.max; - return aldebaran_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk); + return aldebaran_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk, false); } break; case PP_OD_COMMIT_DPM_TABLE: @@ -1441,7 +1442,7 @@ static int aldebaran_usr_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_ min_clk = pstate_table->gfxclk_pstate.custom.min; max_clk = pstate_table->gfxclk_pstate.custom.max; - return aldebaran_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk); + return aldebaran_set_soft_freq_limited_range(smu, SMU_GFXCLK, min_clk, max_clk, false); } break; default: 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 e17466cc19522d..2bfea740daceed 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 @@ -1608,7 +1608,8 @@ int smu_v13_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c int smu_v13_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, - uint32_t max) + uint32_t max, + bool automatic) { int ret = 0, clk_id = 0; uint32_t param; @@ -1623,7 +1624,10 @@ int smu_v13_0_set_soft_freq_limited_range(struct smu_context *smu, return clk_id; if (max > 0) { - param = (uint32_t)((clk_id << 16) | (max & 0xffff)); + if (automatic) + param = (uint32_t)((clk_id << 16) | 0xffff); + else + param = (uint32_t)((clk_id << 16) | (max & 0xffff)); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq, param, NULL); if (ret) @@ -1631,7 +1635,10 @@ int smu_v13_0_set_soft_freq_limited_range(struct smu_context *smu, } if (min > 0) { - param = (uint32_t)((clk_id << 16) | (min & 0xffff)); + if (automatic) + param = (uint32_t)((clk_id << 16) | 0); + else + param = (uint32_t)((clk_id << 16) | (min & 0xffff)); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq, param, NULL); if (ret) @@ -1708,6 +1715,7 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, uint32_t dclk_min = 0, dclk_max = 0; uint32_t fclk_min = 0, fclk_max = 0; int ret = 0, i; + bool auto_level = false; switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: @@ -1739,6 +1747,7 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, dclk_max = dclk_table->max; fclk_min = fclk_table->min; fclk_max = fclk_table->max; + auto_level = true; break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: sclk_min = sclk_max = pstate_table->gfxclk_pstate.standard; @@ -1780,13 +1789,15 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, vclk_min = vclk_max = 0; dclk_min = dclk_max = 0; fclk_min = fclk_max = 0; + auto_level = false; } if (sclk_min && sclk_max) { ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, sclk_min, - sclk_max); + sclk_max, + auto_level); if (ret) return ret; @@ -1798,7 +1809,8 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_MCLK, mclk_min, - mclk_max); + mclk_max, + auto_level); if (ret) return ret; @@ -1810,7 +1822,8 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_min, - socclk_max); + socclk_max, + auto_level); if (ret) return ret; @@ -1825,7 +1838,8 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, ret = smu_v13_0_set_soft_freq_limited_range(smu, i ? SMU_VCLK1 : SMU_VCLK, vclk_min, - vclk_max); + vclk_max, + auto_level); if (ret) return ret; } @@ -1840,7 +1854,8 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, ret = smu_v13_0_set_soft_freq_limited_range(smu, i ? SMU_DCLK1 : SMU_DCLK, dclk_min, - dclk_max); + dclk_max, + auto_level); if (ret) return ret; } @@ -1852,7 +1867,8 @@ int smu_v13_0_set_performance_level(struct smu_context *smu, ret = smu_v13_0_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_min, - fclk_max); + fclk_max, + auto_level); if (ret) return ret; @@ -2088,7 +2104,8 @@ int smu_v13_0_get_current_pcie_link_speed(struct smu_context *smu) } int smu_v13_0_set_vcn_enable(struct smu_context *smu, - bool enable) + bool enable, + int inst) { struct amdgpu_device *adev = smu->adev; int i, ret = 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index d53e162dcd8de2..3aa705aae4c01c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -107,6 +107,8 @@ #define PP_OD_FEATURE_FAN_ACOUSTIC_TARGET 8 #define PP_OD_FEATURE_FAN_TARGET_TEMPERATURE 9 #define PP_OD_FEATURE_FAN_MINIMUM_PWM 10 +#define PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE 11 +#define PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP 12 #define LINK_SPEED_MAX 3 @@ -736,19 +738,6 @@ static bool smu_v13_0_0_is_dpm_running(struct smu_context *smu) return !!(feature_enabled & SMC_DPM_FEATURE); } -static void smu_v13_0_0_dump_pptable(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - PPTable_t *pptable = table_context->driver_pptable; - SkuTable_t *skutable = &pptable->SkuTable; - - dev_info(smu->adev->dev, "Dumped PPTable:\n"); - - dev_info(smu->adev->dev, "Version = 0x%08x\n", skutable->Version); - dev_info(smu->adev->dev, "FeaturesToRun[0] = 0x%08x\n", skutable->FeaturesToRun[0]); - dev_info(smu->adev->dev, "FeaturesToRun[1] = 0x%08x\n", skutable->FeaturesToRun[1]); -} - static int smu_v13_0_0_system_features_control(struct smu_context *smu, bool en) { @@ -1143,6 +1132,14 @@ static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, od_min_setting = overdrive_lowerlimits->FanMinimumPwm; od_max_setting = overdrive_upperlimits->FanMinimumPwm; break; + case PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE: + od_min_setting = overdrive_lowerlimits->FanZeroRpmEnable; + od_max_setting = overdrive_upperlimits->FanZeroRpmEnable; + break; + case PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP: + od_min_setting = overdrive_lowerlimits->FanZeroRpmStopTemp; + od_max_setting = overdrive_upperlimits->FanZeroRpmStopTemp; + break; default: od_min_setting = od_max_setting = INT_MAX; break; @@ -1463,6 +1460,42 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu, min_value, max_value); break; + case SMU_OD_FAN_ZERO_RPM_ENABLE: + if (!smu_v13_0_0_is_od_feature_supported(smu, + PP_OD_FEATURE_ZERO_FAN_BIT)) + break; + + size += sysfs_emit_at(buf, size, "FAN_ZERO_RPM_ENABLE:\n"); + size += sysfs_emit_at(buf, size, "%d\n", + (int)od_table->OverDriveTable.FanZeroRpmEnable); + + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + smu_v13_0_0_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE, + &min_value, + &max_value); + size += sysfs_emit_at(buf, size, "ZERO_RPM_ENABLE: %u %u\n", + min_value, max_value); + break; + + case SMU_OD_FAN_ZERO_RPM_STOP_TEMP: + if (!smu_v13_0_0_is_od_feature_supported(smu, + PP_OD_FEATURE_ZERO_FAN_BIT)) + break; + + size += sysfs_emit_at(buf, size, "FAN_ZERO_RPM_STOP_TEMPERATURE:\n"); + size += sysfs_emit_at(buf, size, "%d\n", + (int)od_table->OverDriveTable.FanZeroRpmStopTemp); + + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + smu_v13_0_0_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP, + &min_value, + &max_value); + size += sysfs_emit_at(buf, size, "ZERO_RPM_STOP_TEMPERATURE: %u %u\n", + min_value, max_value); + break; + case SMU_OD_RANGE: if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && !smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && @@ -1560,6 +1593,16 @@ static int smu_v13_0_0_od_restore_table_single(struct smu_context *smu, long inp od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; + case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: + od_table->OverDriveTable.FanZeroRpmEnable = + boot_overdrive_table->OverDriveTable.FanZeroRpmEnable; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; + case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: + od_table->OverDriveTable.FanZeroRpmStopTemp = + boot_overdrive_table->OverDriveTable.FanZeroRpmStopTemp; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; default: dev_info(adev->dev, "Invalid table index: %ld\n", input); return -EINVAL; @@ -1853,6 +1896,48 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; + case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: + if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_ZERO_FAN_BIT)) { + dev_warn(adev->dev, "Zero RPM setting not supported!\n"); + return -ENOTSUPP; + } + + smu_v13_0_0_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE, + &minimum, + &maximum); + if (input[0] < minimum || + input[0] > maximum) { + dev_info(adev->dev, "zero RPM enable setting(%ld) must be within [%d, %d]!\n", + input[0], minimum, maximum); + return -EINVAL; + } + + od_table->OverDriveTable.FanZeroRpmEnable = input[0]; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; + + case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: + if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_ZERO_FAN_BIT)) { + dev_warn(adev->dev, "Zero RPM setting not supported!\n"); + return -ENOTSUPP; + } + + smu_v13_0_0_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP, + &minimum, + &maximum); + if (input[0] < minimum || + input[0] > maximum) { + dev_info(adev->dev, "zero RPM stop temperature setting(%ld) must be within [%d, %d]!\n", + input[0], minimum, maximum); + return -EINVAL; + } + + od_table->OverDriveTable.FanZeroRpmStopTemp = input[0]; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; + case PP_OD_RESTORE_DEFAULT_TABLE: if (size == 1) { ret = smu_v13_0_0_od_restore_table_single(smu, input[0]); @@ -1975,7 +2060,8 @@ static int smu_v13_0_0_force_clk_levels(struct smu_context *smu, ret = smu_v13_0_set_soft_freq_limited_range(smu, clk_type, min_freq, - max_freq); + max_freq, + false); break; case SMU_DCEFCLK: case SMU_PCIE: @@ -2122,7 +2208,11 @@ static void smu_v13_0_0_set_supported_od_feature_mask(struct smu_context *smu) OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_RETRIEVE | OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_SET | OD_OPS_SUPPORT_FAN_MINIMUM_PWM_RETRIEVE | - OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET; + OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET | + OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_RETRIEVE | + OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET | + OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_RETRIEVE | + OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_SET; } static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu) @@ -2188,6 +2278,10 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu) user_od_table_bak.OverDriveTable.FanTargetTemperature; user_od_table->OverDriveTable.FanMinimumPwm = user_od_table_bak.OverDriveTable.FanMinimumPwm; + user_od_table->OverDriveTable.FanZeroRpmEnable = + user_od_table_bak.OverDriveTable.FanZeroRpmEnable; + user_od_table->OverDriveTable.FanZeroRpmStopTemp = + user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp; } smu_v13_0_0_set_supported_od_feature_mask(smu); @@ -2477,82 +2571,76 @@ static int smu_v13_0_0_get_power_profile_mode(struct smu_context *smu, return size; } -static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, - long *input, - uint32_t size) +#define SMU_13_0_0_CUSTOM_PARAMS_COUNT 9 +#define SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT 2 +#define SMU_13_0_0_CUSTOM_PARAMS_SIZE (SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_0_CUSTOM_PARAMS_COUNT * sizeof(long)) + +static int smu_v13_0_0_set_power_profile_mode_coeff(struct smu_context *smu, + long *input) { DpmActivityMonitorCoeffIntExternal_t activity_monitor_external; DpmActivityMonitorCoeffInt_t *activity_monitor = &(activity_monitor_external.DpmActivityMonitorCoeffInt); - int workload_type, ret = 0; - u32 workload_mask, selected_workload_mask; + int ret, idx; - smu->power_profile_mode = input[size]; - - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) { - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); - return -EINVAL; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor_external), + false); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); + return ret; } - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { - if (size != 9) - return -EINVAL; - - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, - WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor_external), - false); - if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); - return ret; - } - - switch (input[0]) { - case 0: /* Gfxclk */ - activity_monitor->Gfx_FPS = input[1]; - activity_monitor->Gfx_MinActiveFreqType = input[2]; - activity_monitor->Gfx_MinActiveFreq = input[3]; - activity_monitor->Gfx_BoosterFreqType = input[4]; - activity_monitor->Gfx_BoosterFreq = input[5]; - activity_monitor->Gfx_PD_Data_limit_c = input[6]; - activity_monitor->Gfx_PD_Data_error_coeff = input[7]; - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8]; - break; - case 1: /* Fclk */ - activity_monitor->Fclk_FPS = input[1]; - activity_monitor->Fclk_MinActiveFreqType = input[2]; - activity_monitor->Fclk_MinActiveFreq = input[3]; - activity_monitor->Fclk_BoosterFreqType = input[4]; - activity_monitor->Fclk_BoosterFreq = input[5]; - activity_monitor->Fclk_PD_Data_limit_c = input[6]; - activity_monitor->Fclk_PD_Data_error_coeff = input[7]; - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8]; - break; - default: - return -EINVAL; - } + idx = 0 * SMU_13_0_0_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Gfxclk */ + activity_monitor->Gfx_FPS = input[idx + 1]; + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2]; + activity_monitor->Gfx_MinActiveFreq = input[idx + 3]; + activity_monitor->Gfx_BoosterFreqType = input[idx + 4]; + activity_monitor->Gfx_BoosterFreq = input[idx + 5]; + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6]; + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7]; + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8]; + } + idx = 1 * SMU_13_0_0_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Fclk */ + activity_monitor->Fclk_FPS = input[idx + 1]; + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2]; + activity_monitor->Fclk_MinActiveFreq = input[idx + 3]; + activity_monitor->Fclk_BoosterFreqType = input[idx + 4]; + activity_monitor->Fclk_BoosterFreq = input[idx + 5]; + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6]; + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7]; + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8]; + } - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, - WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor_external), - true); - if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); - return ret; - } + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor_external), + true); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + return ret; } - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - smu->power_profile_mode); + return ret; +} - if (workload_type < 0) - return -EINVAL; +static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, + u32 workload_mask, + long *custom_params, + u32 custom_params_max_idx) +{ + u32 backend_workload_mask = 0; + int workload_type, ret, idx = -1, i; - selected_workload_mask = workload_mask = 1 << workload_type; + smu_cmn_get_backend_workload_mask(smu, workload_mask, + &backend_workload_mask); /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */ if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) && @@ -2564,15 +2652,48 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, CMN2ASIC_MAPPING_WORKLOAD, PP_SMC_POWER_PROFILE_POWERSAVING); if (workload_type >= 0) - workload_mask |= 1 << workload_type; + backend_workload_mask |= 1 << workload_type; + } + + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { + if (!smu->custom_profile_params) { + smu->custom_profile_params = + kzalloc(SMU_13_0_0_CUSTOM_PARAMS_SIZE, GFP_KERNEL); + if (!smu->custom_profile_params) + return -ENOMEM; + } + if (custom_params && custom_params_max_idx) { + if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT) + return -EINVAL; + if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT) + return -EINVAL; + idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT; + smu->custom_profile_params[idx] = 1; + for (i = 1; i < custom_params_max_idx; i++) + smu->custom_profile_params[idx + i] = custom_params[i]; + } + ret = smu_v13_0_0_set_power_profile_mode_coeff(smu, + smu->custom_profile_params); + if (ret) { + if (idx != -1) + smu->custom_profile_params[idx] = 0; + return ret; + } + } else if (smu->custom_profile_params) { + memset(smu->custom_profile_params, 0, SMU_13_0_0_CUSTOM_PARAMS_SIZE); } ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetWorkloadMask, - workload_mask, - NULL); - if (!ret) - smu->workload_mask = selected_workload_mask; + SMU_MSG_SetWorkloadMask, + backend_workload_mask, + NULL); + if (ret) { + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", + workload_mask); + if (idx != -1) + smu->custom_profile_params[idx] = 0; + return ret; + } return ret; } @@ -3024,7 +3145,6 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .i2c_init = smu_v13_0_0_i2c_control_init, .i2c_fini = smu_v13_0_0_i2c_control_fini, .is_dpm_running = smu_v13_0_0_is_dpm_running, - .dump_pptable = smu_v13_0_0_dump_pptable, .init_microcode = smu_v13_0_init_microcode, .load_microcode = smu_v13_0_load_microcode, .fini_microcode = smu_v13_0_fini_microcode, 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 9c2c43bfed0bba..f5db181ef489a2 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 @@ -193,7 +193,9 @@ static int smu_v13_0_5_system_features_control(struct smu_context *smu, bool en) return ret; } -static int smu_v13_0_5_dpm_set_vcn_enable(struct smu_context *smu, bool enable) +static int smu_v13_0_5_dpm_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst) { int ret = 0; @@ -811,9 +813,10 @@ static int smu_v13_0_5_get_dpm_ultimate_freq(struct smu_context *smu, } static int smu_v13_0_5_set_soft_freq_limited_range(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t min, - uint32_t max) + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max, + bool automatic) { enum smu_message_type msg_set_min, msg_set_max; uint32_t min_clk = min; @@ -950,7 +953,7 @@ static int smu_v13_0_5_force_clk_levels(struct smu_context *smu, if (ret) goto force_level_out; - ret = smu_v13_0_5_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + ret = smu_v13_0_5_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false); if (ret) goto force_level_out; break; @@ -1046,9 +1049,10 @@ static int smu_v13_0_5_set_performance_level(struct smu_context *smu, if (sclk_min && sclk_max) { ret = smu_v13_0_5_set_soft_freq_limited_range(smu, - SMU_SCLK, - sclk_min, - sclk_max); + SMU_SCLK, + sclk_min, + sclk_max, + false); if (ret) return ret; @@ -1060,7 +1064,8 @@ static int smu_v13_0_5_set_performance_level(struct smu_context *smu, ret = smu_v13_0_5_set_soft_freq_limited_range(smu, SMU_VCLK, vclk_min, - vclk_max); + vclk_max, + false); if (ret) return ret; } @@ -1069,7 +1074,8 @@ static int smu_v13_0_5_set_performance_level(struct smu_context *smu, ret = smu_v13_0_5_set_soft_freq_limited_range(smu, SMU_DCLK, dclk_min, - dclk_max); + dclk_max, + false); if (ret) return ret; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 55ed6247eb61f7..ab3c93ddce46ff 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -96,12 +96,29 @@ MODULE_FIRMWARE("amdgpu/smu_13_0_14.bin"); #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xE0 #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0x5 #define LINK_SPEED_MAX 4 - #define SMU_13_0_6_DSCLK_THRESHOLD 140 #define MCA_BANK_IPID(_ip, _hwid, _type) \ [AMDGPU_MCA_IP_##_ip] = { .hwid = _hwid, .mcatype = _type, } +static inline bool smu_v13_0_6_is_unified_metrics(struct smu_context *smu) +{ + return (smu->adev->flags & AMD_IS_APU) && + smu->smc_fw_version <= 0x4556900; +} + +static inline bool smu_v13_0_6_is_other_end_count_available(struct smu_context *smu) +{ + switch (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)) { + case IP_VERSION(13, 0, 6): + return smu->smc_fw_version >= 0x557600; + case IP_VERSION(13, 0, 14): + return smu->smc_fw_version >= 0x05550E00; + default: + return false; + } +} + struct mca_bank_ipid { enum amdgpu_mca_ip ip; uint16_t hwid; @@ -253,7 +270,7 @@ struct PPTable_t { #define SMUQ10_TO_UINT(x) ((x) >> 10) #define SMUQ10_FRAC(x) ((x) & 0x3ff) #define SMUQ10_ROUND(x) ((SMUQ10_TO_UINT(x)) + ((SMUQ10_FRAC(x)) >= 0x200)) -#define GET_METRIC_FIELD(field) ((adev->flags & AMD_IS_APU) ?\ +#define GET_METRIC_FIELD(field, flag) ((flag) ?\ (metrics_a->field) : (metrics_x->field)) struct smu_v13_0_6_dpm_map { @@ -352,7 +369,7 @@ static int smu_v13_0_6_tables_init(struct smu_context *smu) return -ENOMEM; smu_table->metrics_time = 0; - smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_5); + smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_7); smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL); if (!smu_table->gpu_metrics_table) { @@ -583,7 +600,7 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) MetricsTableA_t *metrics_a = (MetricsTableA_t *)smu_table->metrics_table; struct PPTable_t *pptable = (struct PPTable_t *)smu_table->driver_pptable; - struct amdgpu_device *adev = smu->adev; + bool flag = smu_v13_0_6_is_unified_metrics(smu); int ret, i, retry = 100; uint32_t table_version; @@ -595,7 +612,7 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) return ret; /* Ensure that metrics have been updated */ - if (GET_METRIC_FIELD(AccumulationCounter)) + if (GET_METRIC_FIELD(AccumulationCounter, flag)) break; usleep_range(1000, 1100); @@ -612,29 +629,29 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) table_version; pptable->MaxSocketPowerLimit = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketPowerLimit)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketPowerLimit, flag)); pptable->MaxGfxclkFrequency = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxGfxclkFrequency)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxGfxclkFrequency, flag)); pptable->MinGfxclkFrequency = - SMUQ10_ROUND(GET_METRIC_FIELD(MinGfxclkFrequency)); + SMUQ10_ROUND(GET_METRIC_FIELD(MinGfxclkFrequency, flag)); for (i = 0; i < 4; ++i) { pptable->FclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequencyTable)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequencyTable, flag)[i]); pptable->UclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequencyTable)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequencyTable, flag)[i]); pptable->SocclkFrequencyTable[i] = SMUQ10_ROUND( - GET_METRIC_FIELD(SocclkFrequencyTable)[i]); + GET_METRIC_FIELD(SocclkFrequencyTable, flag)[i]); pptable->VclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequencyTable)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequencyTable, flag)[i]); pptable->DclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequencyTable)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequencyTable, flag)[i]); pptable->LclkFrequencyTable[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(LclkFrequencyTable)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(LclkFrequencyTable, flag)[i]); } /* use AID0 serial number by default */ - pptable->PublicSerialNumber_AID = GET_METRIC_FIELD(PublicSerialNumber_AID)[0]; + pptable->PublicSerialNumber_AID = GET_METRIC_FIELD(PublicSerialNumber_AID, flag)[0]; pptable->Init = true; } @@ -957,6 +974,7 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, struct smu_table_context *smu_table = &smu->smu_table; MetricsTableX_t *metrics_x = (MetricsTableX_t *)smu_table->metrics_table; MetricsTableA_t *metrics_a = (MetricsTableA_t *)smu_table->metrics_table; + bool flag = smu_v13_0_6_is_unified_metrics(smu); struct amdgpu_device *adev = smu->adev; int ret = 0; int xcc_id; @@ -971,50 +989,50 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu, case METRICS_AVERAGE_GFXCLK: if (smu->smc_fw_version >= 0x552F00) { xcc_id = GET_INST(GC, 0); - *value = SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency)[xcc_id]); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, flag)[xcc_id]); } else { *value = 0; } break; case METRICS_CURR_SOCCLK: case METRICS_AVERAGE_SOCCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency)[0]); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, flag)[0]); break; case METRICS_CURR_UCLK: case METRICS_AVERAGE_UCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency)); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, flag)); break; case METRICS_CURR_VCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency)[0]); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, flag)[0]); break; case METRICS_CURR_DCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency)[0]); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, flag)[0]); break; case METRICS_CURR_FCLK: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequency)); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(FclkFrequency, flag)); break; case METRICS_AVERAGE_GFXACTIVITY: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy)); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, flag)); break; case METRICS_AVERAGE_MEMACTIVITY: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization)); + *value = SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, flag)); break; case METRICS_CURR_SOCKETPOWER: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower)) << 8; + *value = SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, flag)) << 8; break; case METRICS_TEMPERATURE_HOTSPOT: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature)) * + *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, flag)) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; case METRICS_TEMPERATURE_MEM: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature)) * + *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, flag)) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; /* This is the max of all VRs and not just SOC VR. * No need to define another data type for the same. */ case METRICS_TEMPERATURE_VRSOC: - *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature)) * + *value = SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, flag)) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; break; default: @@ -1739,7 +1757,7 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu, if (uclk_table->max != pstate_table->uclk_pstate.curr.max) { /* Min UCLK is not expected to be changed */ ret = smu_v13_0_set_soft_freq_limited_range( - smu, SMU_UCLK, 0, uclk_table->max); + smu, SMU_UCLK, 0, uclk_table->max, false); if (ret) return ret; pstate_table->uclk_pstate.curr.max = uclk_table->max; @@ -1758,7 +1776,8 @@ static int smu_v13_0_6_set_performance_level(struct smu_context *smu, static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, uint32_t max) + uint32_t min, uint32_t max, + bool automatic) { struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; @@ -1806,7 +1825,7 @@ static int smu_v13_0_6_set_soft_freq_limited_range(struct smu_context *smu, return -EOPNOTSUPP; /* Only max clock limiting is allowed for UCLK */ ret = smu_v13_0_set_soft_freq_limited_range( - smu, SMU_UCLK, 0, max); + smu, SMU_UCLK, 0, max, false); if (!ret) pstate_table->uclk_pstate.curr.max = max; } @@ -1946,7 +1965,7 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, max_clk = dpm_context->dpm_tables.gfx_table.max; ret = smu_v13_0_6_set_soft_freq_limited_range( - smu, SMU_GFXCLK, min_clk, max_clk); + smu, SMU_GFXCLK, min_clk, max_clk, false); if (ret) return ret; @@ -1954,7 +1973,7 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, min_clk = dpm_context->dpm_tables.uclk_table.min; max_clk = dpm_context->dpm_tables.uclk_table.max; ret = smu_v13_0_6_set_soft_freq_limited_range( - smu, SMU_UCLK, min_clk, max_clk); + smu, SMU_UCLK, min_clk, max_clk, false); if (ret) return ret; pstate_table->uclk_pstate.custom.max = 0; @@ -1978,7 +1997,7 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, max_clk = pstate_table->gfxclk_pstate.custom.max; ret = smu_v13_0_6_set_soft_freq_limited_range( - smu, SMU_GFXCLK, min_clk, max_clk); + smu, SMU_GFXCLK, min_clk, max_clk, false); if (ret) return ret; @@ -1989,7 +2008,7 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, min_clk = pstate_table->uclk_pstate.curr.min; max_clk = pstate_table->uclk_pstate.custom.max; return smu_v13_0_6_set_soft_freq_limited_range( - smu, SMU_UCLK, min_clk, max_clk); + smu, SMU_UCLK, min_clk, max_clk, false); } break; default: @@ -2299,14 +2318,18 @@ static int smu_v13_0_6_get_current_pcie_link_speed(struct smu_context *smu) static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table) { + bool per_inst, smu_13_0_6_per_inst, smu_13_0_14_per_inst, apu_per_inst; struct smu_table_context *smu_table = &smu->smu_table; - struct gpu_metrics_v1_5 *gpu_metrics = - (struct gpu_metrics_v1_5 *)smu_table->gpu_metrics_table; + struct gpu_metrics_v1_7 *gpu_metrics = + (struct gpu_metrics_v1_7 *)smu_table->gpu_metrics_table; + bool flag = smu_v13_0_6_is_unified_metrics(smu); + int ret = 0, xcc_id, inst, i, j, k, idx; struct amdgpu_device *adev = smu->adev; - int ret = 0, xcc_id, inst, i, j; MetricsTableX_t *metrics_x; MetricsTableA_t *metrics_a; + struct amdgpu_xcp *xcp; u16 link_width_level; + u32 inst_mask; metrics_x = kzalloc(max(sizeof(MetricsTableX_t), sizeof(MetricsTableA_t)), GFP_KERNEL); ret = smu_v13_0_6_get_metrics_table(smu, metrics_x, true); @@ -2317,53 +2340,60 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table metrics_a = (MetricsTableA_t *)metrics_x; - smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 5); + smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 7); gpu_metrics->temperature_hotspot = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketTemperature, flag)); /* Individual HBM stack temperature is not reported */ gpu_metrics->temperature_mem = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxHbmTemperature, flag)); /* Reports max temperature of all voltage rails */ gpu_metrics->temperature_vrsoc = - SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature)); + SMUQ10_ROUND(GET_METRIC_FIELD(MaxVrTemperature, flag)); gpu_metrics->average_gfx_activity = - SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy)); + SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusy, flag)); gpu_metrics->average_umc_activity = - SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization)); + SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilization, flag)); gpu_metrics->curr_socket_power = - SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower)); + SMUQ10_ROUND(GET_METRIC_FIELD(SocketPower, flag)); /* Energy counter reported in 15.259uJ (2^-16) units */ - gpu_metrics->energy_accumulator = GET_METRIC_FIELD(SocketEnergyAcc); + gpu_metrics->energy_accumulator = GET_METRIC_FIELD(SocketEnergyAcc, flag); for (i = 0; i < MAX_GFX_CLKS; i++) { xcc_id = GET_INST(GC, i); if (xcc_id >= 0) gpu_metrics->current_gfxclk[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency)[xcc_id]); + SMUQ10_ROUND(GET_METRIC_FIELD(GfxclkFrequency, flag)[xcc_id]); if (i < MAX_CLKS) { gpu_metrics->current_socclk[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(SocclkFrequency, flag)[i]); inst = GET_INST(VCN, i); if (inst >= 0) { gpu_metrics->current_vclk0[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency)[inst]); + SMUQ10_ROUND(GET_METRIC_FIELD(VclkFrequency, flag)[inst]); gpu_metrics->current_dclk0[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency)[inst]); + SMUQ10_ROUND(GET_METRIC_FIELD(DclkFrequency, flag)[inst]); } } } - gpu_metrics->current_uclk = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency)); + gpu_metrics->current_uclk = SMUQ10_ROUND(GET_METRIC_FIELD(UclkFrequency, flag)); + + /* Total accumulated cycle counter */ + gpu_metrics->accumulation_counter = GET_METRIC_FIELD(AccumulationCounter, flag); - /* Throttle status is not reported through metrics now */ - gpu_metrics->throttle_status = 0; + /* Accumulated throttler residencies */ + gpu_metrics->prochot_residency_acc = GET_METRIC_FIELD(ProchotResidencyAcc, flag); + gpu_metrics->ppt_residency_acc = GET_METRIC_FIELD(PptResidencyAcc, flag); + gpu_metrics->socket_thm_residency_acc = GET_METRIC_FIELD(SocketThmResidencyAcc, flag); + gpu_metrics->vr_thm_residency_acc = GET_METRIC_FIELD(VrThmResidencyAcc, flag); + gpu_metrics->hbm_thm_residency_acc = GET_METRIC_FIELD(HbmThmResidencyAcc, flag); /* Clock Lock Status. Each bit corresponds to each GFXCLK instance */ - gpu_metrics->gfxclk_lock_status = GET_METRIC_FIELD(GfxLockXCDMak) >> GET_INST(GC, 0); + gpu_metrics->gfxclk_lock_status = GET_METRIC_FIELD(GfxLockXCDMak, flag) >> GET_INST(GC, 0); if (!(adev->flags & AMD_IS_APU)) { /*Check smu version, PCIE link speed and width will be reported from pmfw metric @@ -2399,41 +2429,80 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table metrics_x->PCIeNAKSentCountAcc; gpu_metrics->pcie_nak_rcvd_count_acc = metrics_x->PCIeNAKReceivedCountAcc; + if (smu_v13_0_6_is_other_end_count_available(smu)) + gpu_metrics->pcie_lc_perf_other_end_recovery = + metrics_x->PCIeOtherEndRecoveryAcc; + } gpu_metrics->system_clock_counter = ktime_get_boottime_ns(); gpu_metrics->gfx_activity_acc = - SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusyAcc)); + SMUQ10_ROUND(GET_METRIC_FIELD(SocketGfxBusyAcc, flag)); gpu_metrics->mem_activity_acc = - SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilizationAcc)); + SMUQ10_ROUND(GET_METRIC_FIELD(DramBandwidthUtilizationAcc, flag)); for (i = 0; i < NUM_XGMI_LINKS; i++) { gpu_metrics->xgmi_read_data_acc[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(XgmiReadDataSizeAcc)[i]); + SMUQ10_ROUND(GET_METRIC_FIELD(XgmiReadDataSizeAcc, flag)[i]); gpu_metrics->xgmi_write_data_acc[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWriteDataSizeAcc)[i]); - } + SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWriteDataSizeAcc, flag)[i]); + ret = amdgpu_get_xgmi_link_status(adev, i); + if (ret >= 0) + gpu_metrics->xgmi_link_status[i] = ret; + } + + gpu_metrics->num_partition = adev->xcp_mgr->num_xcps; + + apu_per_inst = (adev->flags & AMD_IS_APU) && (smu->smc_fw_version >= 0x04556A00); + smu_13_0_6_per_inst = !(adev->flags & AMD_IS_APU) && + (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) + == IP_VERSION(13, 0, 6)) && + (smu->smc_fw_version >= 0x556F00); + smu_13_0_14_per_inst = !(adev->flags & AMD_IS_APU) && + (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) + == IP_VERSION(13, 0, 14)) && + (smu->smc_fw_version >= 0x05550B00); + + per_inst = apu_per_inst || smu_13_0_6_per_inst || smu_13_0_14_per_inst; + + for_each_xcp(adev->xcp_mgr, xcp, i) { + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_VCN, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + /* Both JPEG and VCN has same instances */ + inst = GET_INST(VCN, k); + + for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { + gpu_metrics->xcp_stats[i].jpeg_busy + [(idx * adev->jpeg.num_jpeg_rings) + j] = + SMUQ10_ROUND(GET_METRIC_FIELD(JpegBusy, flag) + [(inst * adev->jpeg.num_jpeg_rings) + j]); + } + gpu_metrics->xcp_stats[i].vcn_busy[idx] = + SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy, flag)[inst]); + idx++; - for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { - inst = GET_INST(JPEG, i); - for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { - gpu_metrics->jpeg_activity[(i * adev->jpeg.num_jpeg_rings) + j] = - SMUQ10_ROUND(GET_METRIC_FIELD(JpegBusy) - [(inst * adev->jpeg.num_jpeg_rings) + j]); } - } - for (i = 0; i < adev->vcn.num_vcn_inst; ++i) { - inst = GET_INST(VCN, i); - gpu_metrics->vcn_activity[i] = - SMUQ10_ROUND(GET_METRIC_FIELD(VcnBusy)[inst]); + if (per_inst) { + amdgpu_xcp_get_inst_details(xcp, AMDGPU_XCP_GFX, &inst_mask); + idx = 0; + for_each_inst(k, inst_mask) { + inst = GET_INST(GC, k); + gpu_metrics->xcp_stats[i].gfx_busy_inst[idx] = + SMUQ10_ROUND(metrics_x->GfxBusy[inst]); + gpu_metrics->xcp_stats[i].gfx_busy_acc[idx] = + SMUQ10_ROUND(metrics_x->GfxBusyAcc[inst]); + idx++; + } + } } - gpu_metrics->xgmi_link_width = SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWidth)); - gpu_metrics->xgmi_link_speed = SMUQ10_ROUND(GET_METRIC_FIELD(XgmiBitrate)); + gpu_metrics->xgmi_link_width = SMUQ10_ROUND(GET_METRIC_FIELD(XgmiWidth, flag)); + gpu_metrics->xgmi_link_speed = SMUQ10_ROUND(GET_METRIC_FIELD(XgmiBitrate, flag)); - gpu_metrics->firmware_timestamp = GET_METRIC_FIELD(Timestamp); + gpu_metrics->firmware_timestamp = GET_METRIC_FIELD(Timestamp, flag); *table = (void *)gpu_metrics; kfree(metrics_x); @@ -2974,6 +3043,16 @@ static int mmhub_err_codes[] = { CODE_VML2, CODE_VML2_WALKER, CODE_MMCANE, }; +static int vcn_err_codes[] = { + CODE_VIDD, CODE_VIDV, +}; +static int jpeg_err_codes[] = { + CODE_JPEG0S, CODE_JPEG0D, CODE_JPEG1S, CODE_JPEG1D, + CODE_JPEG2S, CODE_JPEG2D, CODE_JPEG3S, CODE_JPEG3D, + CODE_JPEG4S, CODE_JPEG4D, CODE_JPEG5S, CODE_JPEG5D, + CODE_JPEG6S, CODE_JPEG6D, CODE_JPEG7S, CODE_JPEG7D, +}; + static const struct mca_ras_info mca_ras_table[] = { { .blkid = AMDGPU_RAS_BLOCK__UMC, @@ -3002,6 +3081,20 @@ static const struct mca_ras_info mca_ras_table[] = { .blkid = AMDGPU_RAS_BLOCK__XGMI_WAFL, .ip = AMDGPU_MCA_IP_PCS_XGMI, .get_err_count = mca_pcs_xgmi_mca_get_err_count, + }, { + .blkid = AMDGPU_RAS_BLOCK__VCN, + .ip = AMDGPU_MCA_IP_SMU, + .err_code_array = vcn_err_codes, + .err_code_count = ARRAY_SIZE(vcn_err_codes), + .get_err_count = mca_smu_mca_get_err_count, + .bank_is_valid = mca_smu_bank_is_valid, + }, { + .blkid = AMDGPU_RAS_BLOCK__JPEG, + .ip = AMDGPU_MCA_IP_SMU, + .err_code_array = jpeg_err_codes, + .err_code_count = ARRAY_SIZE(jpeg_err_codes), + .get_err_count = mca_smu_mca_get_err_count, + .bank_is_valid = mca_smu_bank_is_valid, }, }; 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 b891a5e0a3969a..aabb9479600562 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 @@ -83,6 +83,8 @@ #define PP_OD_FEATURE_FAN_ACOUSTIC_TARGET 8 #define PP_OD_FEATURE_FAN_TARGET_TEMPERATURE 9 #define PP_OD_FEATURE_FAN_MINIMUM_PWM 10 +#define PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE 11 +#define PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP 12 #define LINK_SPEED_MAX 3 @@ -734,19 +736,6 @@ static bool smu_v13_0_7_is_dpm_running(struct smu_context *smu) return !!(feature_enabled & SMC_DPM_FEATURE); } -static void smu_v13_0_7_dump_pptable(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - PPTable_t *pptable = table_context->driver_pptable; - SkuTable_t *skutable = &pptable->SkuTable; - - dev_info(smu->adev->dev, "Dumped PPTable:\n"); - - dev_info(smu->adev->dev, "Version = 0x%08x\n", skutable->Version); - dev_info(smu->adev->dev, "FeaturesToRun[0] = 0x%08x\n", skutable->FeaturesToRun[0]); - dev_info(smu->adev->dev, "FeaturesToRun[1] = 0x%08x\n", skutable->FeaturesToRun[1]); -} - static uint32_t smu_v13_0_7_get_throttler_status(SmuMetrics_t *metrics) { uint32_t throttler_status = 0; @@ -1132,6 +1121,14 @@ static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, od_min_setting = overdrive_lowerlimits->FanMinimumPwm; od_max_setting = overdrive_upperlimits->FanMinimumPwm; break; + case PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE: + od_min_setting = overdrive_lowerlimits->FanZeroRpmEnable; + od_max_setting = overdrive_upperlimits->FanZeroRpmEnable; + break; + case PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP: + od_min_setting = overdrive_lowerlimits->FanZeroRpmStopTemp; + od_max_setting = overdrive_upperlimits->FanZeroRpmStopTemp; + break; default: od_min_setting = od_max_setting = INT_MAX; break; @@ -1452,6 +1449,42 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu, min_value, max_value); break; + case SMU_OD_FAN_ZERO_RPM_ENABLE: + if (!smu_v13_0_7_is_od_feature_supported(smu, + PP_OD_FEATURE_ZERO_FAN_BIT)) + break; + + size += sysfs_emit_at(buf, size, "FAN_ZERO_RPM_ENABLE:\n"); + size += sysfs_emit_at(buf, size, "%d\n", + (int)od_table->OverDriveTable.FanZeroRpmEnable); + + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + smu_v13_0_7_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE, + &min_value, + &max_value); + size += sysfs_emit_at(buf, size, "ZERO_RPM_ENABLE: %u %u\n", + min_value, max_value); + break; + + case SMU_OD_FAN_ZERO_RPM_STOP_TEMP: + if (!smu_v13_0_7_is_od_feature_supported(smu, + PP_OD_FEATURE_ZERO_FAN_BIT)) + break; + + size += sysfs_emit_at(buf, size, "FAN_ZERO_RPM_STOP_TEMPERATURE:\n"); + size += sysfs_emit_at(buf, size, "%d\n", + (int)od_table->OverDriveTable.FanZeroRpmStopTemp); + + size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE"); + smu_v13_0_7_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP, + &min_value, + &max_value); + size += sysfs_emit_at(buf, size, "ZERO_RPM_STOP_TEMPERATURE: %u %u\n", + min_value, max_value); + break; + case SMU_OD_RANGE: if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) && !smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) && @@ -1548,6 +1581,16 @@ static int smu_v13_0_7_od_restore_table_single(struct smu_context *smu, long inp od_table->OverDriveTable.FanMode = FAN_MODE_AUTO; od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; + case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: + od_table->OverDriveTable.FanZeroRpmEnable = + boot_overdrive_table->OverDriveTable.FanZeroRpmEnable; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; + case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: + od_table->OverDriveTable.FanZeroRpmStopTemp = + boot_overdrive_table->OverDriveTable.FanZeroRpmStopTemp; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; default: dev_info(adev->dev, "Invalid table index: %ld\n", input); return -EINVAL; @@ -1841,6 +1884,48 @@ static int smu_v13_0_7_od_edit_dpm_table(struct smu_context *smu, od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT); break; + case PP_OD_EDIT_FAN_ZERO_RPM_ENABLE: + if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_ZERO_FAN_BIT)) { + dev_warn(adev->dev, "Zero RPM setting not supported!\n"); + return -ENOTSUPP; + } + + smu_v13_0_7_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_ENABLE, + &minimum, + &maximum); + if (input[0] < minimum || + input[0] > maximum) { + dev_info(adev->dev, "zero RPM enable setting(%ld) must be within [%d, %d]!\n", + input[0], minimum, maximum); + return -EINVAL; + } + + od_table->OverDriveTable.FanZeroRpmEnable = input[0]; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; + + case PP_OD_EDIT_FAN_ZERO_RPM_STOP_TEMP: + if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_ZERO_FAN_BIT)) { + dev_warn(adev->dev, "Zero RPM setting not supported!\n"); + return -ENOTSUPP; + } + + smu_v13_0_7_get_od_setting_limits(smu, + PP_OD_FEATURE_FAN_ZERO_RPM_STOP_TEMP, + &minimum, + &maximum); + if (input[0] < minimum || + input[0] > maximum) { + dev_info(adev->dev, "zero RPM stop temperature setting(%ld) must be within [%d, %d]!\n", + input[0], minimum, maximum); + return -EINVAL; + } + + od_table->OverDriveTable.FanZeroRpmStopTemp = input[0]; + od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_ZERO_FAN_BIT); + break; + case PP_OD_RESTORE_DEFAULT_TABLE: if (size == 1) { ret = smu_v13_0_7_od_restore_table_single(smu, input[0]); @@ -1964,7 +2049,8 @@ static int smu_v13_0_7_force_clk_levels(struct smu_context *smu, ret = smu_v13_0_set_soft_freq_limited_range(smu, clk_type, min_freq, - max_freq); + max_freq, + false); break; case SMU_DCEFCLK: case SMU_PCIE: @@ -2061,6 +2147,8 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu, gpu_metrics->average_dclk1_frequency = metrics->AverageDclk1Frequency; gpu_metrics->current_gfxclk = metrics->CurrClock[PPCLK_GFXCLK]; + gpu_metrics->current_socclk = metrics->CurrClock[PPCLK_SOCCLK]; + gpu_metrics->current_uclk = metrics->CurrClock[PPCLK_UCLK]; gpu_metrics->current_vclk0 = metrics->CurrClock[PPCLK_VCLK_0]; gpu_metrics->current_dclk0 = metrics->CurrClock[PPCLK_DCLK_0]; gpu_metrics->current_vclk1 = metrics->CurrClock[PPCLK_VCLK_1]; @@ -2106,7 +2194,11 @@ static void smu_v13_0_7_set_supported_od_feature_mask(struct smu_context *smu) OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_RETRIEVE | OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_SET | OD_OPS_SUPPORT_FAN_MINIMUM_PWM_RETRIEVE | - OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET; + OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET | + OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_RETRIEVE | + OD_OPS_SUPPORT_FAN_ZERO_RPM_ENABLE_SET | + OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_RETRIEVE | + OD_OPS_SUPPORT_FAN_ZERO_RPM_STOP_TEMP_SET; } static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu) @@ -2172,6 +2264,10 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu) user_od_table_bak.OverDriveTable.FanTargetTemperature; user_od_table->OverDriveTable.FanMinimumPwm = user_od_table_bak.OverDriveTable.FanMinimumPwm; + user_od_table->OverDriveTable.FanZeroRpmEnable = + user_od_table_bak.OverDriveTable.FanZeroRpmEnable; + user_od_table->OverDriveTable.FanZeroRpmStopTemp = + user_od_table_bak.OverDriveTable.FanZeroRpmStopTemp; } smu_v13_0_7_set_supported_od_feature_mask(smu); @@ -2434,78 +2530,110 @@ do { \ return result; } -static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) +#define SMU_13_0_7_CUSTOM_PARAMS_COUNT 8 +#define SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT 2 +#define SMU_13_0_7_CUSTOM_PARAMS_SIZE (SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT * SMU_13_0_7_CUSTOM_PARAMS_COUNT * sizeof(long)) + +static int smu_v13_0_7_set_power_profile_mode_coeff(struct smu_context *smu, + long *input) { DpmActivityMonitorCoeffIntExternal_t activity_monitor_external; DpmActivityMonitorCoeffInt_t *activity_monitor = &(activity_monitor_external.DpmActivityMonitorCoeffInt); - int workload_type, ret = 0; + int ret, idx; - smu->power_profile_mode = input[size]; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor_external), false); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); + return ret; + } - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_WINDOW3D) { - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); - return -EINVAL; + idx = 0 * SMU_13_0_7_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Gfxclk */ + activity_monitor->Gfx_ActiveHystLimit = input[idx + 1]; + activity_monitor->Gfx_IdleHystLimit = input[idx + 2]; + activity_monitor->Gfx_FPS = input[idx + 3]; + activity_monitor->Gfx_MinActiveFreqType = input[idx + 4]; + activity_monitor->Gfx_BoosterFreqType = input[idx + 5]; + activity_monitor->Gfx_MinActiveFreq = input[idx + 6]; + activity_monitor->Gfx_BoosterFreq = input[idx + 7]; + } + idx = 1 * SMU_13_0_7_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Fclk */ + activity_monitor->Fclk_ActiveHystLimit = input[idx + 1]; + activity_monitor->Fclk_IdleHystLimit = input[idx + 2]; + activity_monitor->Fclk_FPS = input[idx + 3]; + activity_monitor->Fclk_MinActiveFreqType = input[idx + 4]; + activity_monitor->Fclk_BoosterFreqType = input[idx + 5]; + activity_monitor->Fclk_MinActiveFreq = input[idx + 6]; + activity_monitor->Fclk_BoosterFreq = input[idx + 7]; } - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { - if (size != 8) - return -EINVAL; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor_external), true); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + return ret; + } - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor_external), false); - if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); - return ret; - } + return ret; +} - switch (input[0]) { - case 0: /* Gfxclk */ - activity_monitor->Gfx_ActiveHystLimit = input[1]; - activity_monitor->Gfx_IdleHystLimit = input[2]; - activity_monitor->Gfx_FPS = input[3]; - activity_monitor->Gfx_MinActiveFreqType = input[4]; - activity_monitor->Gfx_BoosterFreqType = input[5]; - activity_monitor->Gfx_MinActiveFreq = input[6]; - activity_monitor->Gfx_BoosterFreq = input[7]; - break; - case 1: /* Fclk */ - activity_monitor->Fclk_ActiveHystLimit = input[1]; - activity_monitor->Fclk_IdleHystLimit = input[2]; - activity_monitor->Fclk_FPS = input[3]; - activity_monitor->Fclk_MinActiveFreqType = input[4]; - activity_monitor->Fclk_BoosterFreqType = input[5]; - activity_monitor->Fclk_MinActiveFreq = input[6]; - activity_monitor->Fclk_BoosterFreq = input[7]; - break; - default: - return -EINVAL; +static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, + u32 workload_mask, + long *custom_params, + u32 custom_params_max_idx) +{ + u32 backend_workload_mask = 0; + int ret, idx = -1, i; + + smu_cmn_get_backend_workload_mask(smu, workload_mask, + &backend_workload_mask); + + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { + if (!smu->custom_profile_params) { + smu->custom_profile_params = + kzalloc(SMU_13_0_7_CUSTOM_PARAMS_SIZE, GFP_KERNEL); + if (!smu->custom_profile_params) + return -ENOMEM; } - - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor_external), true); + if (custom_params && custom_params_max_idx) { + if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT) + return -EINVAL; + if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT) + return -EINVAL; + idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT; + smu->custom_profile_params[idx] = 1; + for (i = 1; i < custom_params_max_idx; i++) + smu->custom_profile_params[idx + i] = custom_params[i]; + } + ret = smu_v13_0_7_set_power_profile_mode_coeff(smu, + smu->custom_profile_params); if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + if (idx != -1) + smu->custom_profile_params[idx] = 0; return ret; } + } else if (smu->custom_profile_params) { + memset(smu->custom_profile_params, 0, SMU_13_0_7_CUSTOM_PARAMS_SIZE); } - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - smu->power_profile_mode); - if (workload_type < 0) - return -EINVAL; ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, - 1 << workload_type, NULL); + backend_workload_mask, NULL); - if (ret) - dev_err(smu->adev->dev, "[%s] Failed to set work load mask!", __func__); - else - smu->workload_mask = (1 << workload_type); + if (ret) { + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", + workload_mask); + if (idx != -1) + smu->custom_profile_params[idx] = 0; + return ret; + } return ret; } @@ -2605,7 +2733,6 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask, .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table, .is_dpm_running = smu_v13_0_7_is_dpm_running, - .dump_pptable = smu_v13_0_7_dump_pptable, .init_microcode = smu_v13_0_init_microcode, .load_microcode = smu_v13_0_load_microcode, .fini_microcode = smu_v13_0_fini_microcode, @@ -2683,4 +2810,5 @@ void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) smu->workload_map = smu_v13_0_7_workload_map; smu->smc_driver_if_version = SMU13_0_7_DRIVER_IF_VERSION; smu_v13_0_set_smu_mailbox_registers(smu); + smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; } 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 260c339f89c5dc..73b4506ef5a87f 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 @@ -220,7 +220,9 @@ static int yellow_carp_system_features_control(struct smu_context *smu, bool en) return ret; } -static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu, bool enable) +static int yellow_carp_dpm_set_vcn_enable(struct smu_context *smu, + bool enable, + int inst) { int ret = 0; @@ -945,9 +947,10 @@ static int yellow_carp_get_dpm_ultimate_freq(struct smu_context *smu, } static int yellow_carp_set_soft_freq_limited_range(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t min, - uint32_t max) + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max, + bool automatic) { enum smu_message_type msg_set_min, msg_set_max; uint32_t min_clk = min; @@ -1134,7 +1137,7 @@ static int yellow_carp_force_clk_levels(struct smu_context *smu, if (ret) goto force_level_out; - ret = yellow_carp_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + ret = yellow_carp_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq, false); if (ret) goto force_level_out; break; @@ -1254,9 +1257,10 @@ static int yellow_carp_set_performance_level(struct smu_context *smu, if (sclk_min && sclk_max) { ret = yellow_carp_set_soft_freq_limited_range(smu, - SMU_SCLK, - sclk_min, - sclk_max); + SMU_SCLK, + sclk_min, + sclk_max, + false); if (ret) return ret; @@ -1266,18 +1270,20 @@ static int yellow_carp_set_performance_level(struct smu_context *smu, if (fclk_min && fclk_max) { ret = yellow_carp_set_soft_freq_limited_range(smu, - SMU_FCLK, - fclk_min, - fclk_max); + SMU_FCLK, + fclk_min, + fclk_max, + false); if (ret) return ret; } if (socclk_min && socclk_max) { ret = yellow_carp_set_soft_freq_limited_range(smu, - SMU_SOCCLK, - socclk_min, - socclk_max); + SMU_SOCCLK, + socclk_min, + socclk_max, + false); if (ret) return ret; } @@ -1286,7 +1292,8 @@ static int yellow_carp_set_performance_level(struct smu_context *smu, ret = yellow_carp_set_soft_freq_limited_range(smu, SMU_VCLK, vclk_min, - vclk_max); + vclk_max, + false); if (ret) return ret; } @@ -1295,7 +1302,8 @@ static int yellow_carp_set_performance_level(struct smu_context *smu, ret = yellow_carp_set_soft_freq_limited_range(smu, SMU_DCLK, dclk_min, - dclk_max); + dclk_max, + false); if (ret) return ret; } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index 865e916fc42544..a87040cb2f2e52 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -49,7 +49,7 @@ #define regMP1_SMN_IH_SW_INT_CTRL_mp1_14_0_0_BASE_IDX 0 const int decoded_link_speed[5] = {1, 2, 3, 4, 5}; -const int decoded_link_width[7] = {0, 1, 2, 4, 8, 12, 16}; +const int decoded_link_width[8] = {0, 1, 2, 4, 8, 12, 16, 32}; /* * DO NOT use these for err/warn/info/debug messages. * Use dev_err, dev_warn, dev_info and dev_dbg instead. @@ -1102,7 +1102,8 @@ int smu_v14_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c int smu_v14_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, - uint32_t max) + uint32_t max, + bool automatic) { int ret = 0, clk_id = 0; uint32_t param; @@ -1117,7 +1118,10 @@ int smu_v14_0_set_soft_freq_limited_range(struct smu_context *smu, return clk_id; if (max > 0) { - param = (uint32_t)((clk_id << 16) | (max & 0xffff)); + if (automatic) + param = (uint32_t)((clk_id << 16) | 0xffff); + else + param = (uint32_t)((clk_id << 16) | (max & 0xffff)); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq, param, NULL); if (ret) @@ -1125,7 +1129,10 @@ int smu_v14_0_set_soft_freq_limited_range(struct smu_context *smu, } if (min > 0) { - param = (uint32_t)((clk_id << 16) | (min & 0xffff)); + if (automatic) + param = (uint32_t)((clk_id << 16) | 0); + else + param = (uint32_t)((clk_id << 16) | (min & 0xffff)); ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq, param, NULL); if (ret) @@ -1202,6 +1209,7 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, uint32_t dclk_min = 0, dclk_max = 0; uint32_t fclk_min = 0, fclk_max = 0; int ret = 0, i; + bool auto_level = false; switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: @@ -1233,6 +1241,7 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, dclk_max = dclk_table->max; fclk_min = fclk_table->min; fclk_max = fclk_table->max; + auto_level = true; break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: sclk_min = sclk_max = pstate_table->gfxclk_pstate.standard; @@ -1268,7 +1277,8 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, ret = smu_v14_0_set_soft_freq_limited_range(smu, SMU_GFXCLK, sclk_min, - sclk_max); + sclk_max, + auto_level); if (ret) return ret; @@ -1280,7 +1290,8 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, ret = smu_v14_0_set_soft_freq_limited_range(smu, SMU_MCLK, mclk_min, - mclk_max); + mclk_max, + auto_level); if (ret) return ret; @@ -1292,7 +1303,8 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, ret = smu_v14_0_set_soft_freq_limited_range(smu, SMU_SOCCLK, socclk_min, - socclk_max); + socclk_max, + auto_level); if (ret) return ret; @@ -1307,7 +1319,8 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, ret = smu_v14_0_set_soft_freq_limited_range(smu, i ? SMU_VCLK1 : SMU_VCLK, vclk_min, - vclk_max); + vclk_max, + auto_level); if (ret) return ret; } @@ -1322,7 +1335,8 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, ret = smu_v14_0_set_soft_freq_limited_range(smu, i ? SMU_DCLK1 : SMU_DCLK, dclk_min, - dclk_max); + dclk_max, + auto_level); if (ret) return ret; } @@ -1334,7 +1348,8 @@ int smu_v14_0_set_performance_level(struct smu_context *smu, ret = smu_v14_0_set_soft_freq_limited_range(smu, SMU_FCLK, fclk_min, - fclk_max); + fclk_max, + auto_level); if (ret) return ret; @@ -1492,7 +1507,8 @@ int smu_v14_0_set_single_dpm_table(struct smu_context *smu, } int smu_v14_0_set_vcn_enable(struct smu_context *smu, - bool enable) + bool enable, + int inst) { struct amdgpu_device *adev = smu->adev; int i, ret = 0; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 1e16a281f2dcde..5cad09c5f2ff2c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -670,19 +670,6 @@ static bool smu_v14_0_2_is_dpm_running(struct smu_context *smu) return !!(feature_enabled & SMC_DPM_FEATURE); } -static void smu_v14_0_2_dump_pptable(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - PPTable_t *pptable = table_context->driver_pptable; - PFE_Settings_t *PFEsettings = &pptable->PFE_Settings; - - dev_info(smu->adev->dev, "Dumped PPTable:\n"); - - dev_info(smu->adev->dev, "Version = 0x%08x\n", PFEsettings->Version); - dev_info(smu->adev->dev, "FeaturesToRun[0] = 0x%08x\n", PFEsettings->FeaturesToRun[0]); - dev_info(smu->adev->dev, "FeaturesToRun[1] = 0x%08x\n", PFEsettings->FeaturesToRun[1]); -} - static uint32_t smu_v14_0_2_get_throttler_status(SmuMetrics_t *metrics) { uint32_t throttler_status = 0; @@ -1186,13 +1173,15 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu, (pcie_table->pcie_gen[i] == 0) ? "2.5GT/s," : (pcie_table->pcie_gen[i] == 1) ? "5.0GT/s," : (pcie_table->pcie_gen[i] == 2) ? "8.0GT/s," : - (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," : "", + (pcie_table->pcie_gen[i] == 3) ? "16.0GT/s," : + (pcie_table->pcie_gen[i] == 4) ? "32.0GT/s," : "", (pcie_table->pcie_lane[i] == 1) ? "x1" : (pcie_table->pcie_lane[i] == 2) ? "x2" : (pcie_table->pcie_lane[i] == 3) ? "x4" : (pcie_table->pcie_lane[i] == 4) ? "x8" : (pcie_table->pcie_lane[i] == 5) ? "x12" : - (pcie_table->pcie_lane[i] == 6) ? "x16" : "", + (pcie_table->pcie_lane[i] == 6) ? "x16" : + (pcie_table->pcie_lane[i] == 7) ? "x32" : "", pcie_table->clk_freq[i], (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) && (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ? @@ -1457,7 +1446,8 @@ static int smu_v14_0_2_force_clk_levels(struct smu_context *smu, ret = smu_v14_0_set_soft_freq_limited_range(smu, clk_type, min_freq, - max_freq); + max_freq, + false); break; case SMU_DCEFCLK: case SMU_PCIE: @@ -1475,15 +1465,35 @@ static int smu_v14_0_2_update_pcie_parameters(struct smu_context *smu, struct smu_14_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; struct smu_14_0_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table; + int num_of_levels = pcie_table->num_of_link_levels; uint32_t smu_pcie_arg; int ret, i; - for (i = 0; i < pcie_table->num_of_link_levels; i++) { - if (pcie_table->pcie_gen[i] > pcie_gen_cap) + if (!num_of_levels) + return 0; + + if (!(smu->adev->pm.pp_feature & PP_PCIE_DPM_MASK)) { + if (pcie_table->pcie_gen[num_of_levels - 1] < pcie_gen_cap) + pcie_gen_cap = pcie_table->pcie_gen[num_of_levels - 1]; + + if (pcie_table->pcie_lane[num_of_levels - 1] < pcie_width_cap) + pcie_width_cap = pcie_table->pcie_lane[num_of_levels - 1]; + + /* Force all levels to use the same settings */ + for (i = 0; i < num_of_levels; i++) { pcie_table->pcie_gen[i] = pcie_gen_cap; - if (pcie_table->pcie_lane[i] > pcie_width_cap) pcie_table->pcie_lane[i] = pcie_width_cap; + } + } else { + for (i = 0; i < num_of_levels; i++) { + if (pcie_table->pcie_gen[i] > pcie_gen_cap) + pcie_table->pcie_gen[i] = pcie_gen_cap; + if (pcie_table->pcie_lane[i] > pcie_width_cap) + pcie_table->pcie_lane[i] = pcie_width_cap; + } + } + for (i = 0; i < num_of_levels; i++) { smu_pcie_arg = i << 16; smu_pcie_arg |= pcie_table->pcie_gen[i] << 8; smu_pcie_arg |= pcie_table->pcie_lane[i]; @@ -1729,90 +1739,120 @@ static int smu_v14_0_2_get_power_profile_mode(struct smu_context *smu, return size; } -static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu, - long *input, - uint32_t size) +#define SMU_14_0_2_CUSTOM_PARAMS_COUNT 9 +#define SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT 2 +#define SMU_14_0_2_CUSTOM_PARAMS_SIZE (SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT * SMU_14_0_2_CUSTOM_PARAMS_COUNT * sizeof(long)) + +static int smu_v14_0_2_set_power_profile_mode_coeff(struct smu_context *smu, + long *input) { DpmActivityMonitorCoeffIntExternal_t activity_monitor_external; DpmActivityMonitorCoeffInt_t *activity_monitor = &(activity_monitor_external.DpmActivityMonitorCoeffInt); - int workload_type, ret = 0; - uint32_t current_profile_mode = smu->power_profile_mode; - smu->power_profile_mode = input[size]; + int ret, idx; - if (smu->power_profile_mode >= PP_SMC_POWER_PROFILE_COUNT) { - dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); - return -EINVAL; + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor_external), + false); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); + return ret; } - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { - if (size != 9) - return -EINVAL; + idx = 0 * SMU_14_0_2_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Gfxclk */ + activity_monitor->Gfx_FPS = input[idx + 1]; + activity_monitor->Gfx_MinActiveFreqType = input[idx + 2]; + activity_monitor->Gfx_MinActiveFreq = input[idx + 3]; + activity_monitor->Gfx_BoosterFreqType = input[idx + 4]; + activity_monitor->Gfx_BoosterFreq = input[idx + 5]; + activity_monitor->Gfx_PD_Data_limit_c = input[idx + 6]; + activity_monitor->Gfx_PD_Data_error_coeff = input[idx + 7]; + activity_monitor->Gfx_PD_Data_error_rate_coeff = input[idx + 8]; + } + idx = 1 * SMU_14_0_2_CUSTOM_PARAMS_COUNT; + if (input[idx]) { + /* Fclk */ + activity_monitor->Fclk_FPS = input[idx + 1]; + activity_monitor->Fclk_MinActiveFreqType = input[idx + 2]; + activity_monitor->Fclk_MinActiveFreq = input[idx + 3]; + activity_monitor->Fclk_BoosterFreqType = input[idx + 4]; + activity_monitor->Fclk_BoosterFreq = input[idx + 5]; + activity_monitor->Fclk_PD_Data_limit_c = input[idx + 6]; + activity_monitor->Fclk_PD_Data_error_coeff = input[idx + 7]; + activity_monitor->Fclk_PD_Data_error_rate_coeff = input[idx + 8]; + } - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, - WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor_external), - false); - if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); - return ret; - } + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor_external), + true); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + return ret; + } - switch (input[0]) { - case 0: /* Gfxclk */ - activity_monitor->Gfx_FPS = input[1]; - activity_monitor->Gfx_MinActiveFreqType = input[2]; - activity_monitor->Gfx_MinActiveFreq = input[3]; - activity_monitor->Gfx_BoosterFreqType = input[4]; - activity_monitor->Gfx_BoosterFreq = input[5]; - activity_monitor->Gfx_PD_Data_limit_c = input[6]; - activity_monitor->Gfx_PD_Data_error_coeff = input[7]; - activity_monitor->Gfx_PD_Data_error_rate_coeff = input[8]; - break; - case 1: /* Fclk */ - activity_monitor->Fclk_FPS = input[1]; - activity_monitor->Fclk_MinActiveFreqType = input[2]; - activity_monitor->Fclk_MinActiveFreq = input[3]; - activity_monitor->Fclk_BoosterFreqType = input[4]; - activity_monitor->Fclk_BoosterFreq = input[5]; - activity_monitor->Fclk_PD_Data_limit_c = input[6]; - activity_monitor->Fclk_PD_Data_error_coeff = input[7]; - activity_monitor->Fclk_PD_Data_error_rate_coeff = input[8]; - break; - default: - return -EINVAL; - } + return ret; +} - ret = smu_cmn_update_table(smu, - SMU_TABLE_ACTIVITY_MONITOR_COEFF, - WORKLOAD_PPLIB_CUSTOM_BIT, - (void *)(&activity_monitor_external), - true); - if (ret) { - dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); - return ret; - } - } +static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu, + u32 workload_mask, + long *custom_params, + u32 custom_params_max_idx) +{ + u32 backend_workload_mask = 0; + int ret, idx = -1, i; - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE) + smu_cmn_get_backend_workload_mask(smu, workload_mask, + &backend_workload_mask); + + /* disable deep sleep if compute is enabled */ + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_COMPUTE)) smu_v14_0_deep_sleep_control(smu, false); - else if (current_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE) + else smu_v14_0_deep_sleep_control(smu, true); - /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - smu->power_profile_mode); - if (workload_type < 0) - return -EINVAL; + if (workload_mask & (1 << PP_SMC_POWER_PROFILE_CUSTOM)) { + if (!smu->custom_profile_params) { + smu->custom_profile_params = + kzalloc(SMU_14_0_2_CUSTOM_PARAMS_SIZE, GFP_KERNEL); + if (!smu->custom_profile_params) + return -ENOMEM; + } + if (custom_params && custom_params_max_idx) { + if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT) + return -EINVAL; + if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT) + return -EINVAL; + idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT; + smu->custom_profile_params[idx] = 1; + for (i = 1; i < custom_params_max_idx; i++) + smu->custom_profile_params[idx + i] = custom_params[i]; + } + ret = smu_v14_0_2_set_power_profile_mode_coeff(smu, + smu->custom_profile_params); + if (ret) { + if (idx != -1) + smu->custom_profile_params[idx] = 0; + return ret; + } + } else if (smu->custom_profile_params) { + memset(smu->custom_profile_params, 0, SMU_14_0_2_CUSTOM_PARAMS_SIZE); + } - ret = smu_cmn_send_smc_msg_with_param(smu, - SMU_MSG_SetWorkloadMask, - 1 << workload_type, - NULL); - if (!ret) - smu->workload_mask = 1 << workload_type; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, + backend_workload_mask, NULL); + if (ret) { + dev_err(smu->adev->dev, "Failed to set workload mask 0x%08x\n", + workload_mask); + if (idx != -1) + smu->custom_profile_params[idx] = 0; + return ret; + } return ret; } @@ -2056,7 +2096,7 @@ static int smu_v14_0_2_enable_gfx_features(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(14, 0, 2)) + if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(14, 0, 2)) return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableAllSmuFeatures, FEATURE_PWR_GFX, NULL); else @@ -2726,7 +2766,6 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { .i2c_init = smu_v14_0_2_i2c_control_init, .i2c_fini = smu_v14_0_2_i2c_control_fini, .is_dpm_running = smu_v14_0_2_is_dpm_running, - .dump_pptable = smu_v14_0_2_dump_pptable, .init_microcode = smu_v14_0_init_microcode, .load_microcode = smu_v14_0_load_microcode, .fini_microcode = smu_v14_0_fini_microcode, @@ -2767,7 +2806,6 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { .get_unique_id = smu_v14_0_2_get_unique_id, .get_power_limit = smu_v14_0_2_get_power_limit, .set_power_limit = smu_v14_0_2_set_power_limit, - .set_power_source = smu_v14_0_set_power_source, .get_power_profile_mode = smu_v14_0_2_get_power_profile_mode, .set_power_profile_mode = smu_v14_0_2_set_power_profile_mode, .run_btc = smu_v14_0_run_btc, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index 91ad434bcdaeb4..9f55207ea9bc38 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -1078,6 +1078,12 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev) case METRICS_VERSION(1, 5): structure_size = sizeof(struct gpu_metrics_v1_5); break; + case METRICS_VERSION(1, 6): + structure_size = sizeof(struct gpu_metrics_v1_6); + break; + case METRICS_VERSION(1, 7): + structure_size = sizeof(struct gpu_metrics_v1_7); + break; case METRICS_VERSION(2, 0): structure_size = sizeof(struct gpu_metrics_v2_0); break; @@ -1215,3 +1221,28 @@ void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy) { policy->desc = &xgmi_plpd_policy_desc; } + +void smu_cmn_get_backend_workload_mask(struct smu_context *smu, + u32 workload_mask, + u32 *backend_workload_mask) +{ + int workload_type; + u32 profile_mode; + + *backend_workload_mask = 0; + + for (profile_mode = 0; profile_mode < PP_SMC_POWER_PROFILE_COUNT; profile_mode++) { + if (!(workload_mask & (1 << profile_mode))) + continue; + + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + profile_mode); + + if (workload_type < 0) + continue; + + *backend_workload_mask |= 1 << workload_type; + } +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 1de685defe85b1..a020277dec3e96 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -147,5 +147,9 @@ bool smu_cmn_is_audio_func_enabled(struct amdgpu_device *adev); void smu_cmn_generic_soc_policy_desc(struct smu_dpm_policy *policy); void smu_cmn_generic_plpd_policy_desc(struct smu_dpm_policy *policy); +void smu_cmn_get_backend_workload_mask(struct smu_context *smu, + u32 workload_mask, + u32 *backend_workload_mask); + #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h index 6f4d212607d7f5..c09ecf1a68a0da 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h @@ -78,7 +78,6 @@ #define smu_register_irq_handler(smu) smu_ppt_funcs(register_irq_handler, 0, smu) #define smu_get_dpm_ultimate_freq(smu, param, min, max) smu_ppt_funcs(get_dpm_ultimate_freq, 0, smu, param, min, max) #define smu_asic_set_performance_level(smu, level) smu_ppt_funcs(set_performance_level, -EINVAL, smu, level) -#define smu_dump_pptable(smu) smu_ppt_funcs(dump_pptable, 0, smu) #define smu_update_pcie_parameters(smu, pcie_gen_cap, pcie_width_cap) smu_ppt_funcs(update_pcie_parameters, 0, smu, pcie_gen_cap, pcie_width_cap) #define smu_set_power_source(smu, power_src) smu_ppt_funcs(set_power_source, 0, smu, power_src) #define smu_i2c_init(smu) smu_ppt_funcs(i2c_init, 0, smu) diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig index ddf20708370f99..c901ac00c0c3a8 100644 --- a/drivers/gpu/drm/arm/Kconfig +++ b/drivers/gpu/drm/arm/Kconfig @@ -6,6 +6,7 @@ config DRM_HDLCD tristate "ARM HDLCD" depends on DRM && OF && (ARM || ARM64 || COMPILE_TEST) depends on COMMON_CLK + select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_GEM_DMA_HELPER help @@ -27,6 +28,7 @@ config DRM_MALI_DISPLAY tristate "ARM Mali Display Processor" depends on DRM && OF && (ARM || ARM64 || COMPILE_TEST) depends on COMMON_CLK + select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_GEM_DMA_HELPER select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/arm/display/Kconfig b/drivers/gpu/drm/arm/display/Kconfig index 4acc4285a4eb06..415c10a6374bc4 100644 --- a/drivers/gpu/drm/arm/display/Kconfig +++ b/drivers/gpu/drm/arm/display/Kconfig @@ -3,6 +3,7 @@ config DRM_KOMEDA tristate "ARM Komeda display driver" depends on DRM && OF depends on COMMON_CLK + select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_GEM_DMA_HELPER select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index 55c3773befde25..d981d721e7969b 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "komeda_dev.h" @@ -84,7 +84,7 @@ static int komeda_platform_probe(struct platform_device *pdev) } dev_set_drvdata(dev, mdrv); - drm_fbdev_dma_setup(&mdrv->kms->base, 32); + drm_client_setup(&mdrv->kms->base, NULL); return 0; @@ -153,7 +153,7 @@ static const struct dev_pm_ops komeda_pm_ops = { static struct platform_driver komeda_platform_driver = { .probe = komeda_platform_probe, - .remove_new = komeda_platform_remove, + .remove = komeda_platform_remove, .shutdown = komeda_platform_shutdown, .driver = { .name = "komeda", diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c index e5eb5d672bcd7d..1e7b1fcb2848e7 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_kms.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_kms.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ static irqreturn_t komeda_kms_irq_handler(int irq, void *data) static const struct drm_driver komeda_kms_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(komeda_gem_dma_dumb_create), + DRM_FBDEV_DMA_DRIVER_OPS, .fops = &komeda_cma_fops, .name = "komeda", .desc = "Arm Komeda Display Processor driver", diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c index 32be9e37004956..191b806624dfa5 100644 --- a/drivers/gpu/drm/arm/hdlcd_drv.c +++ b/drivers/gpu/drm/arm/hdlcd_drv.c @@ -9,6 +9,7 @@ * ARM HDLCD Driver */ +#include #include #include #include @@ -21,8 +22,8 @@ #include #include -#include #include +#include #include #include #include @@ -228,6 +229,7 @@ DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver hdlcd_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, DRM_GEM_DMA_DRIVER_OPS, + DRM_FBDEV_DMA_DRIVER_OPS, .fops = &fops, .name = "hdlcd", .desc = "ARM HDLCD Controller DRM", @@ -285,7 +287,7 @@ static int hdlcd_drm_bind(struct device *dev) */ if (hdlcd_read(hdlcd, HDLCD_REG_COMMAND)) { hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0); - drm_aperture_remove_framebuffers(&hdlcd_driver); + aperture_remove_all_conflicting_devices(hdlcd_driver.name); } drm_mode_config_reset(drm); @@ -299,7 +301,7 @@ static int hdlcd_drm_bind(struct device *dev) if (ret) goto err_register; - drm_fbdev_dma_setup(drm, 32); + drm_client_setup(drm, NULL); return 0; @@ -403,7 +405,7 @@ static SIMPLE_DEV_PM_OPS(hdlcd_pm_ops, hdlcd_pm_suspend, hdlcd_pm_resume); static struct platform_driver hdlcd_platform_driver = { .probe = hdlcd_probe, - .remove_new = hdlcd_remove, + .remove = hdlcd_remove, .shutdown = hdlcd_shutdown, .driver = { .name = "hdlcd", diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 6682131d291044..fd2be80f3bf5c0 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -562,6 +563,7 @@ static void malidp_debugfs_init(struct drm_minor *minor) static const struct drm_driver malidp_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(malidp_dumb_create), + DRM_FBDEV_DMA_DRIVER_OPS, #ifdef CONFIG_DEBUG_FS .debugfs_init = malidp_debugfs_init, #endif @@ -852,7 +854,7 @@ static int malidp_bind(struct device *dev) if (ret) goto register_fail; - drm_fbdev_dma_setup(drm, 32); + drm_client_setup(drm, NULL); return 0; @@ -986,7 +988,7 @@ static const struct dev_pm_ops malidp_pm_ops = { static struct platform_driver malidp_platform_driver = { .probe = malidp_platform_probe, - .remove_new = malidp_platform_remove, + .remove = malidp_platform_remove, .shutdown = malidp_platform_shutdown, .driver = { .name = "mali-dp", diff --git a/drivers/gpu/drm/armada/Kconfig b/drivers/gpu/drm/armada/Kconfig index e5597d7c9ae1a8..b22c891a670bee 100644 --- a/drivers/gpu/drm/armada/Kconfig +++ b/drivers/gpu/drm/armada/Kconfig @@ -2,6 +2,7 @@ config DRM_ARMADA tristate "DRM support for Marvell Armada SoCs" depends on DRM && HAVE_CLK && ARM && MMU + select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION help diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index c78687c755a869..0900e4466ffb3f 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1084,7 +1084,7 @@ MODULE_DEVICE_TABLE(platform, armada_lcd_platform_ids); struct platform_driver armada_lcd_platform_driver = { .probe = armada_lcd_probe, - .remove_new = armada_lcd_remove, + .remove = armada_lcd_remove, .driver = { .name = "armada-lcd", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index c303e8c7ff6c76..3c0ff221a43b50 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -16,6 +16,8 @@ struct armada_crtc; struct armada_gem_object; struct clk; struct drm_display_mode; +struct drm_fb_helper; +struct drm_fb_helper_surface_size; static inline void armada_updatel(uint32_t val, uint32_t mask, void __iomem *ptr) @@ -74,10 +76,13 @@ struct armada_private { #define drm_to_armada_dev(dev) container_of(dev, struct armada_private, drm) #if defined(CONFIG_DRM_FBDEV_EMULATION) -void armada_fbdev_setup(struct drm_device *dev); +int armada_fbdev_driver_fbdev_probe(struct drm_fb_helper *fbh, + struct drm_fb_helper_surface_size *sizes); +#define ARMADA_FBDEV_DRIVER_OPS \ + .fbdev_probe = armada_fbdev_driver_fbdev_probe #else -static inline void armada_fbdev_setup(struct drm_device *dev) -{ } +#define ARMADA_FBDEV_DRIVER_OPS \ + .fbdev_probe = NULL #endif int armada_overlay_plane_create(struct drm_device *, unsigned long); diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index e51ecc4f7ef448..650e450cc19b83 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -3,6 +3,7 @@ * Copyright (C) 2012 Russell King */ +#include #include #include #include @@ -10,8 +11,8 @@ #include #include -#include #include +#include #include #include #include @@ -39,6 +40,7 @@ DEFINE_DRM_GEM_FOPS(armada_drm_fops); static const struct drm_driver armada_drm_driver = { .gem_prime_import = armada_gem_prime_import, .dumb_create = armada_gem_dumb_create, + ARMADA_FBDEV_DRIVER_OPS, .major = 1, .minor = 0, .name = "armada-drm", @@ -91,7 +93,7 @@ static int armada_drm_bind(struct device *dev) } /* Remove early framebuffers */ - ret = drm_aperture_remove_framebuffers(&armada_drm_driver); + ret = aperture_remove_all_conflicting_devices(armada_drm_driver.name); if (ret) { dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n", __func__, ret); @@ -137,7 +139,7 @@ static int armada_drm_bind(struct device *dev) armada_drm_debugfs_init(priv->drm.primary); #endif - armada_fbdev_setup(&priv->drm); + drm_client_setup(&priv->drm, NULL); return 0; @@ -248,7 +250,7 @@ MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids); static struct platform_driver armada_drm_platform_driver = { .probe = armada_drm_probe, - .remove_new = armada_drm_remove, + .remove = armada_drm_remove, .shutdown = armada_drm_shutdown, .driver = { .name = "armada-drm", diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index d223176912b634..6ee7ce04ee7138 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -39,8 +39,10 @@ static const struct fb_ops armada_fb_ops = { .fb_destroy = armada_fbdev_fb_destroy, }; -static int armada_fbdev_create(struct drm_fb_helper *fbh, - struct drm_fb_helper_surface_size *sizes) +static const struct drm_fb_helper_funcs armada_fbdev_helper_funcs; + +int armada_fbdev_driver_fbdev_probe(struct drm_fb_helper *fbh, + struct drm_fb_helper_surface_size *sizes) { struct drm_device *dev = fbh->dev; struct drm_mode_fb_cmd2 mode; @@ -98,6 +100,7 @@ static int armada_fbdev_create(struct drm_fb_helper *fbh, info->fix.smem_len = obj->obj.size; info->screen_size = obj->obj.size; info->screen_base = ptr; + fbh->funcs = &armada_fbdev_helper_funcs; fbh->fb = &dfb->fb; drm_fb_helper_fill_info(info, fbh, sizes); @@ -112,109 +115,3 @@ static int armada_fbdev_create(struct drm_fb_helper *fbh, dfb->fb.funcs->destroy(&dfb->fb); return ret; } - -static int armada_fb_probe(struct drm_fb_helper *fbh, - struct drm_fb_helper_surface_size *sizes) -{ - int ret = 0; - - if (!fbh->fb) { - ret = armada_fbdev_create(fbh, sizes); - if (ret == 0) - ret = 1; - } - return ret; -} - -static const struct drm_fb_helper_funcs armada_fb_helper_funcs = { - .fb_probe = armada_fb_probe, -}; - -/* - * Fbdev client and struct drm_client_funcs - */ - -static void armada_fbdev_client_unregister(struct drm_client_dev *client) -{ - struct drm_fb_helper *fbh = drm_fb_helper_from_client(client); - - if (fbh->info) { - drm_fb_helper_unregister_info(fbh); - } else { - drm_client_release(&fbh->client); - drm_fb_helper_unprepare(fbh); - kfree(fbh); - } -} - -static int armada_fbdev_client_restore(struct drm_client_dev *client) -{ - drm_fb_helper_lastclose(client->dev); - - return 0; -} - -static int armada_fbdev_client_hotplug(struct drm_client_dev *client) -{ - struct drm_fb_helper *fbh = drm_fb_helper_from_client(client); - struct drm_device *dev = client->dev; - int ret; - - if (dev->fb_helper) - return drm_fb_helper_hotplug_event(dev->fb_helper); - - ret = drm_fb_helper_init(dev, fbh); - if (ret) - goto err_drm_err; - - if (!drm_drv_uses_atomic_modeset(dev)) - drm_helper_disable_unused_functions(dev); - - ret = drm_fb_helper_initial_config(fbh); - if (ret) - goto err_drm_fb_helper_fini; - - return 0; - -err_drm_fb_helper_fini: - drm_fb_helper_fini(fbh); -err_drm_err: - drm_err(dev, "armada: Failed to setup fbdev emulation (ret=%d)\n", ret); - return ret; -} - -static const struct drm_client_funcs armada_fbdev_client_funcs = { - .owner = THIS_MODULE, - .unregister = armada_fbdev_client_unregister, - .restore = armada_fbdev_client_restore, - .hotplug = armada_fbdev_client_hotplug, -}; - -void armada_fbdev_setup(struct drm_device *dev) -{ - struct drm_fb_helper *fbh; - int ret; - - drm_WARN(dev, !dev->registered, "Device has not been registered.\n"); - drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n"); - - fbh = kzalloc(sizeof(*fbh), GFP_KERNEL); - if (!fbh) - return; - drm_fb_helper_prepare(dev, fbh, 32, &armada_fb_helper_funcs); - - ret = drm_client_init(dev, &fbh->client, "fbdev", &armada_fbdev_client_funcs); - if (ret) { - drm_err(dev, "Failed to register client: %d\n", ret); - goto err_drm_client_init; - } - - drm_client_register(&fbh->client); - - return; - -err_drm_client_init: - drm_fb_helper_unprepare(fbh); - kfree(fbh); - return; -} diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 26d10065d5344e..1a1680d71486d6 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -15,7 +15,7 @@ #include "armada_gem.h" #include "armada_ioctlP.h" -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); static vm_fault_t armada_gem_vm_fault(struct vm_fault *vmf) { diff --git a/drivers/gpu/drm/aspeed/Kconfig b/drivers/gpu/drm/aspeed/Kconfig index 8137c39b057bb3..6e68f20aac21b1 100644 --- a/drivers/gpu/drm/aspeed/Kconfig +++ b/drivers/gpu/drm/aspeed/Kconfig @@ -4,6 +4,7 @@ config DRM_ASPEED_GFX depends on DRM && OF depends on (COMPILE_TEST || ARCH_ASPEED) depends on MMU + select DRM_CLIENT_SELECTION select DRM_KMS_HELPER select DRM_GEM_DMA_HELPER select DMA_CMA if HAVE_DMA_CONTIGUOUS diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index a7a6b70220eb8c..b7e608ba61941d 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -247,6 +248,7 @@ DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver aspeed_gfx_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, DRM_GEM_DMA_DRIVER_OPS, + DRM_FBDEV_DMA_DRIVER_OPS, .fops = &fops, .name = "aspeed-gfx-drm", .desc = "ASPEED GFX DRM", @@ -339,7 +341,7 @@ static int aspeed_gfx_probe(struct platform_device *pdev) if (ret) goto err_unload; - drm_fbdev_dma_setup(&priv->drm, 32); + drm_client_setup(&priv->drm, NULL); return 0; err_unload: @@ -366,7 +368,7 @@ static void aspeed_gfx_shutdown(struct platform_device *pdev) static struct platform_driver aspeed_gfx_platform_driver = { .probe = aspeed_gfx_probe, - .remove_new = aspeed_gfx_remove, + .remove = aspeed_gfx_remove, .shutdown = aspeed_gfx_shutdown, .driver = { .name = "aspeed_gfx", diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig index 563fa7a3b546c8..da0663542e8a45 100644 --- a/drivers/gpu/drm/ast/Kconfig +++ b/drivers/gpu/drm/ast/Kconfig @@ -2,6 +2,7 @@ config DRM_AST tristate "AST server chips" depends on DRM && PCI && MMU + select DRM_CLIENT_SELECTION select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER select I2C diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c index 00b364f9a71e54..0e282b7b167c6b 100644 --- a/drivers/gpu/drm/ast/ast_dp.c +++ b/drivers/gpu/drm/ast/ast_dp.c @@ -149,28 +149,22 @@ int ast_dp_launch(struct ast_device *ast) return 0; } -static bool ast_dp_power_is_on(struct ast_device *ast) +static bool ast_dp_get_phy_sleep(struct ast_device *ast) { - u8 vgacre3; + u8 vgacre3 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xe3); - vgacre3 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xe3); - - return !(vgacre3 & AST_DP_PHY_SLEEP); + return (vgacre3 & AST_IO_VGACRE3_DP_PHY_SLEEP); } -static void ast_dp_power_on_off(struct drm_device *dev, bool on) +static void ast_dp_set_phy_sleep(struct ast_device *ast, bool sleep) { - struct ast_device *ast = to_ast_device(dev); - // Read and Turn off DP PHY sleep - u8 bE3 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xE3, AST_DP_VIDEO_ENABLE); - - // Turn on DP PHY sleep - if (!on) - bE3 |= AST_DP_PHY_SLEEP; + u8 vgacre3 = 0x00; - // DP Power on/off - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE3, (u8) ~AST_DP_PHY_SLEEP, bE3); + if (sleep) + vgacre3 |= AST_IO_VGACRE3_DP_PHY_SLEEP; + ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xe3, (u8)~AST_IO_VGACRE3_DP_PHY_SLEEP, + vgacre3); msleep(50); } @@ -192,23 +186,39 @@ static void ast_dp_link_training(struct ast_device *ast) drm_err(dev, "Link training failed\n"); } -static void ast_dp_set_on_off(struct drm_device *dev, bool on) +static bool __ast_dp_wait_enable(struct ast_device *ast, bool enabled) { - struct ast_device *ast = to_ast_device(dev); - u8 video_on_off = on; - u32 i = 0; - - // Video On/Off - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE3, (u8) ~AST_DP_VIDEO_ENABLE, on); - - video_on_off <<= 4; - while (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, - ASTDP_MIRROR_VIDEO_ENABLE) != video_on_off) { - // wait 1 ms - mdelay(1); - if (++i > 200) - break; + u8 vgacrdf_test = 0x00; + u8 vgacrdf; + unsigned int i; + + if (enabled) + vgacrdf_test |= AST_IO_VGACRDF_DP_VIDEO_ENABLE; + + for (i = 0; i < 200; ++i) { + if (i) + mdelay(1); + vgacrdf = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xdf, + AST_IO_VGACRDF_DP_VIDEO_ENABLE); + if (vgacrdf == vgacrdf_test) + return true; } + + return false; +} + +static void ast_dp_set_enable(struct ast_device *ast, bool enabled) +{ + struct drm_device *dev = &ast->base; + u8 vgacre3 = 0x00; + + if (enabled) + vgacre3 |= AST_IO_VGACRE3_DP_VIDEO_ENABLE; + + ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xe3, (u8)~AST_IO_VGACRE3_DP_VIDEO_ENABLE, + vgacre3); + + drm_WARN_ON(dev, !__ast_dp_wait_enable(ast, enabled)); } static void ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode) @@ -317,26 +327,25 @@ static void ast_astdp_encoder_helper_atomic_mode_set(struct drm_encoder *encoder static void ast_astdp_encoder_helper_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct drm_device *dev = encoder->dev; - struct ast_device *ast = to_ast_device(dev); + struct ast_device *ast = to_ast_device(encoder->dev); struct ast_connector *ast_connector = &ast->output.astdp.connector; if (ast_connector->physical_status == connector_status_connected) { - ast_dp_power_on_off(dev, AST_DP_POWER_ON); + ast_dp_set_phy_sleep(ast, false); ast_dp_link_training(ast); ast_wait_for_vretrace(ast); - ast_dp_set_on_off(dev, 1); + ast_dp_set_enable(ast, true); } } static void ast_astdp_encoder_helper_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct drm_device *dev = encoder->dev; + struct ast_device *ast = to_ast_device(encoder->dev); - ast_dp_set_on_off(dev, 0); - ast_dp_power_on_off(dev, AST_DP_POWER_OFF); + ast_dp_set_enable(ast, false); + ast_dp_set_phy_sleep(ast, true); } static const struct drm_encoder_helper_funcs ast_astdp_encoder_helper_funcs = { @@ -383,22 +392,21 @@ static int ast_astdp_connector_helper_detect_ctx(struct drm_connector *connector bool force) { struct ast_connector *ast_connector = to_ast_connector(connector); - struct drm_device *dev = connector->dev; struct ast_device *ast = to_ast_device(connector->dev); enum drm_connector_status status = connector_status_disconnected; - bool power_is_on; + bool phy_sleep; mutex_lock(&ast->modeset_lock); - power_is_on = ast_dp_power_is_on(ast); - if (!power_is_on) - ast_dp_power_on_off(dev, true); + phy_sleep = ast_dp_get_phy_sleep(ast); + if (phy_sleep) + ast_dp_set_phy_sleep(ast, false); if (ast_astdp_is_connected(ast)) status = connector_status_connected; - if (!power_is_on && status == connector_status_disconnected) - ast_dp_power_on_off(dev, false); + if (phy_sleep && status == connector_status_disconnected) + ast_dp_set_phy_sleep(ast, true); mutex_unlock(&ast->modeset_lock); @@ -414,6 +422,10 @@ static const struct drm_connector_helper_funcs ast_astdp_connector_helper_funcs .detect_ctx = ast_astdp_connector_helper_detect_ctx, }; +/* + * Output + */ + static const struct drm_connector_funcs ast_astdp_connector_funcs = { .reset = drm_atomic_helper_connector_reset, .fill_modes = drm_helper_probe_single_connector_modes, @@ -422,34 +434,18 @@ static const struct drm_connector_funcs ast_astdp_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int ast_astdp_connector_init(struct drm_device *dev, struct drm_connector *connector) -{ - int ret; - - ret = drm_connector_init(dev, connector, &ast_astdp_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); - if (ret) - return ret; - - drm_connector_helper_add(connector, &ast_astdp_connector_helper_funcs); - - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - - return 0; -} - int ast_astdp_output_init(struct ast_device *ast) { struct drm_device *dev = &ast->base; struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.astdp.encoder; - struct ast_connector *ast_connector = &ast->output.astdp.connector; - struct drm_connector *connector = &ast_connector->base; + struct drm_encoder *encoder; + struct ast_connector *ast_connector; + struct drm_connector *connector; int ret; + /* encoder */ + + encoder = &ast->output.astdp.encoder; ret = drm_encoder_init(dev, encoder, &ast_astdp_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); if (ret) @@ -458,9 +454,20 @@ int ast_astdp_output_init(struct ast_device *ast) encoder->possible_crtcs = drm_crtc_mask(crtc); - ret = ast_astdp_connector_init(dev, connector); + /* connector */ + + ast_connector = &ast->output.astdp.connector; + connector = &ast_connector->base; + ret = drm_connector_init(dev, connector, &ast_astdp_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); if (ret) return ret; + drm_connector_helper_add(connector, &ast_astdp_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + ast_connector->physical_status = connector->status; ret = drm_connector_attach_encoder(connector, encoder); diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index e4c636f4508207..9e19d8c1773083 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -21,9 +21,9 @@ static void ast_release_firmware(void *data) ast->dp501_fw = NULL; } -static int ast_load_dp501_microcode(struct drm_device *dev) +static int ast_load_dp501_microcode(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); + struct drm_device *dev = &ast->base; int ret; ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev); @@ -109,10 +109,10 @@ static bool wait_fw_ready(struct ast_device *ast) } #endif -static bool ast_write_cmd(struct drm_device *dev, u8 data) +static bool ast_write_cmd(struct ast_device *ast, u8 data) { - struct ast_device *ast = to_ast_device(dev); int retry = 0; + if (wait_nack(ast)) { send_nack(ast); ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9a, 0x00, data); @@ -131,10 +131,8 @@ static bool ast_write_cmd(struct drm_device *dev, u8 data) return false; } -static bool ast_write_data(struct drm_device *dev, u8 data) +static bool ast_write_data(struct ast_device *ast, u8 data) { - struct ast_device *ast = to_ast_device(dev); - if (wait_nack(ast)) { send_nack(ast); ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0x9a, 0x00, data); @@ -175,10 +173,10 @@ static void clear_cmd(struct ast_device *ast) } #endif -static void ast_set_dp501_video_output(struct drm_device *dev, u8 mode) +static void ast_set_dp501_video_output(struct ast_device *ast, u8 mode) { - ast_write_cmd(dev, 0x40); - ast_write_data(dev, mode); + ast_write_cmd(ast, 0x40); + ast_write_data(ast, mode); msleep(10); } @@ -188,9 +186,8 @@ static u32 get_fw_base(struct ast_device *ast) return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff; } -bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size) +bool ast_backup_fw(struct ast_device *ast, u8 *addr, u32 size) { - struct ast_device *ast = to_ast_device(dev); u32 i, data; u32 boot_address; @@ -207,9 +204,8 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size) return false; } -static bool ast_launch_m68k(struct drm_device *dev) +static bool ast_launch_m68k(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); u32 i, data, len = 0; u32 boot_address; u8 *fw_addr = NULL; @@ -226,7 +222,7 @@ static bool ast_launch_m68k(struct drm_device *dev) len = 32*1024; } else { if (!ast->dp501_fw && - ast_load_dp501_microcode(dev) < 0) + ast_load_dp501_microcode(ast) < 0) return false; fw_addr = (u8 *)ast->dp501_fw->data; @@ -348,9 +344,8 @@ static int ast_dp512_read_edid_block(void *data, u8 *buf, unsigned int block, si return true; } -static bool ast_init_dvo(struct drm_device *dev) +static bool ast_init_dvo(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); u8 jreg; u32 data; ast_write32(ast, 0xf004, 0x1e6e0000); @@ -421,9 +416,8 @@ static bool ast_init_dvo(struct drm_device *dev) } -static void ast_init_analog(struct drm_device *dev) +static void ast_init_analog(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); u32 data; /* @@ -448,28 +442,28 @@ static void ast_init_analog(struct drm_device *dev) ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x00); } -void ast_init_3rdtx(struct drm_device *dev) +void ast_init_3rdtx(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); - u8 jreg; + u8 vgacrd1; if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast)) { - jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, 0xff); - switch (jreg & 0x0e) { - case 0x04: - ast_init_dvo(dev); + vgacrd1 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, + AST_IO_VGACRD1_TX_TYPE_MASK); + switch (vgacrd1) { + case AST_IO_VGACRD1_TX_SIL164_VBIOS: + ast_init_dvo(ast); break; - case 0x08: - ast_launch_m68k(dev); + case AST_IO_VGACRD1_TX_DP501_VBIOS: + ast_launch_m68k(ast); break; - case 0x0c: - ast_init_dvo(dev); + case AST_IO_VGACRD1_TX_FW_EMBEDDED_FW: + ast_init_dvo(ast); break; default: - if (ast->tx_chip_types & BIT(AST_TX_SIL164)) - ast_init_dvo(dev); + if (ast->tx_chip == AST_TX_SIL164) + ast_init_dvo(ast); else - ast_init_analog(dev); + ast_init_analog(ast); } } } @@ -485,17 +479,17 @@ static const struct drm_encoder_funcs ast_dp501_encoder_funcs = { static void ast_dp501_encoder_helper_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct drm_device *dev = encoder->dev; + struct ast_device *ast = to_ast_device(encoder->dev); - ast_set_dp501_video_output(dev, 1); + ast_set_dp501_video_output(ast, 1); } static void ast_dp501_encoder_helper_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { - struct drm_device *dev = encoder->dev; + struct ast_device *ast = to_ast_device(encoder->dev); - ast_set_dp501_video_output(dev, 0); + ast_set_dp501_video_output(ast, 0); } static const struct drm_encoder_helper_funcs ast_dp501_encoder_helper_funcs = { @@ -567,34 +561,22 @@ static const struct drm_connector_funcs ast_dp501_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int ast_dp501_connector_init(struct drm_device *dev, struct drm_connector *connector) -{ - int ret; - - ret = drm_connector_init(dev, connector, &ast_dp501_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); - if (ret) - return ret; - - drm_connector_helper_add(connector, &ast_dp501_connector_helper_funcs); - - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - - return 0; -} +/* + * Output + */ int ast_dp501_output_init(struct ast_device *ast) { struct drm_device *dev = &ast->base; struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.dp501.encoder; - struct ast_connector *ast_connector = &ast->output.dp501.connector; - struct drm_connector *connector = &ast_connector->base; + struct drm_encoder *encoder; + struct ast_connector *ast_connector; + struct drm_connector *connector; int ret; + /* encoder */ + + encoder = &ast->output.dp501.encoder; ret = drm_encoder_init(dev, encoder, &ast_dp501_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); if (ret) @@ -603,9 +585,20 @@ int ast_dp501_output_init(struct ast_device *ast) encoder->possible_crtcs = drm_crtc_mask(crtc); - ret = ast_dp501_connector_init(dev, connector); + /* connector */ + + ast_connector = &ast->output.dp501.connector; + connector = &ast_connector->base; + ret = drm_connector_init(dev, connector, &ast_dp501_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); if (ret) return ret; + drm_connector_helper_add(connector, &ast_dp501_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + ast_connector->physical_status = connector->status; ret = drm_connector_attach_encoder(connector, encoder); diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index 3a908bb015fe33..4afe4be072efc9 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -26,12 +26,13 @@ * Authors: Dave Airlie */ +#include #include #include #include -#include #include +#include #include #include #include @@ -64,7 +65,8 @@ static const struct drm_driver ast_driver = { .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, - DRM_GEM_SHMEM_DRIVER_OPS + DRM_GEM_SHMEM_DRIVER_OPS, + DRM_FBDEV_SHMEM_DRIVER_OPS, }; /* @@ -279,7 +281,7 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct drm_device *drm; bool need_post = false; - ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &ast_driver); + ret = aperture_remove_conflicting_pci_devices(pdev, ast_driver.name); if (ret) return ret; @@ -360,7 +362,7 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - drm_fbdev_shmem_setup(drm, 32); + drm_client_setup(drm, NULL); return 0; } @@ -396,7 +398,7 @@ static int ast_drm_thaw(struct drm_device *dev) ast_enable_vga(ast->ioregs); ast_open_key(ast->ioregs); ast_enable_mmio(dev->dev, ast->ioregs); - ast_post_gpu(dev); + ast_post_gpu(ast); return drm_mode_config_helper_resume(dev); } diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 91fe07cf7b07e3..21ce3769bf0d2c 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -91,11 +91,6 @@ enum ast_tx_chip { AST_TX_ASTDP, }; -#define AST_TX_NONE_BIT BIT(AST_TX_NONE) -#define AST_TX_SIL164_BIT BIT(AST_TX_SIL164) -#define AST_TX_DP501_BIT BIT(AST_TX_DP501) -#define AST_TX_ASTDP_BIT BIT(AST_TX_ASTDP) - enum ast_config_mode { ast_use_p2a, ast_use_dt, @@ -187,10 +182,12 @@ struct ast_device { struct mutex modeset_lock; /* Protects access to modeset I/O registers in ioregs */ + enum ast_tx_chip tx_chip; + struct ast_plane primary_plane; struct ast_plane cursor_plane; struct drm_crtc crtc; - struct { + union { struct { struct drm_encoder encoder; struct ast_connector connector; @@ -211,7 +208,6 @@ struct ast_device { bool support_wide_screen; - unsigned long tx_chip_types; /* bitfield of enum ast_chip_type */ u8 *dp501_fw_addr; const struct firmware *dp501_fw; /* dp501 fw */ }; @@ -407,9 +403,6 @@ int ast_mode_config_init(struct ast_device *ast); #define AST_DP501_LINKRATE 0xf014 #define AST_DP501_EDID_DATA 0xf020 -#define AST_DP_POWER_ON true -#define AST_DP_POWER_OFF false - /* * ASTDP resoultion table: * EX: ASTDP_A_B_C: @@ -453,7 +446,7 @@ int ast_mode_config_init(struct ast_device *ast); int ast_mm_init(struct ast_device *ast); /* ast post */ -void ast_post_gpu(struct drm_device *dev); +void ast_post_gpu(struct ast_device *ast); u32 ast_mindwm(struct ast_device *ast, u32 r); void ast_moutdwm(struct ast_device *ast, u32 r, u32 v); void ast_patch_ahb_2500(void __iomem *regs); @@ -462,8 +455,8 @@ int ast_vga_output_init(struct ast_device *ast); int ast_sil164_output_init(struct ast_device *ast); /* ast dp501 */ -bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); -void ast_init_3rdtx(struct drm_device *dev); +bool ast_backup_fw(struct ast_device *ast, u8 *addr, u32 size); +void ast_init_3rdtx(struct ast_device *ast); int ast_dp501_output_init(struct ast_device *ast); /* aspeed DP */ diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index d836f2a4f9f3e0..bc37c65305d486 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -68,11 +68,33 @@ static void ast_detect_widescreen(struct ast_device *ast) static void ast_detect_tx_chip(struct ast_device *ast, bool need_post) { + static const char * const info_str[] = { + "analog VGA", + "Sil164 TMDS transmitter", + "DP501 DisplayPort transmitter", + "ASPEED DisplayPort transmitter", + }; + struct drm_device *dev = &ast->base; - u8 jreg; + u8 jreg, vgacrd1; + + /* + * Several of the listed TX chips are not explicitly supported + * by the ast driver. If these exist in real-world devices, they + * are most likely reported as VGA or SIL164 outputs. We warn here + * to get bug reports for these devices. If none come in for some + * time, we can begin to fail device probing on these values. + */ + vgacrd1 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, AST_IO_VGACRD1_TX_TYPE_MASK); + drm_WARN(dev, vgacrd1 == AST_IO_VGACRD1_TX_ITE66121_VBIOS, + "ITE IT66121 detected, 0x%x, Gen%lu\n", vgacrd1, AST_GEN(ast)); + drm_WARN(dev, vgacrd1 == AST_IO_VGACRD1_TX_CH7003_VBIOS, + "Chrontel CH7003 detected, 0x%x, Gen%lu\n", vgacrd1, AST_GEN(ast)); + drm_WARN(dev, vgacrd1 == AST_IO_VGACRD1_TX_ANX9807_VBIOS, + "Analogix ANX9807 detected, 0x%x, Gen%lu\n", vgacrd1, AST_GEN(ast)); /* Check 3rd Tx option (digital output afaik) */ - ast->tx_chip_types |= AST_TX_NONE_BIT; + ast->tx_chip = AST_TX_NONE; /* * VGACRA3 Enhanced Color Mode Register, check if DVO is already @@ -85,7 +107,7 @@ static void ast_detect_tx_chip(struct ast_device *ast, bool need_post) if (!need_post) { jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xff); if (jreg & 0x80) - ast->tx_chip_types = AST_TX_SIL164_BIT; + ast->tx_chip = AST_TX_SIL164; } if (IS_AST_GEN4(ast) || IS_AST_GEN5(ast) || IS_AST_GEN6(ast)) { @@ -94,49 +116,42 @@ static void ast_detect_tx_chip(struct ast_device *ast, bool need_post) * the SOC scratch register #1 bits 11:8 (interestingly marked * as "reserved" in the spec) */ - jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, 0xff); + jreg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, + AST_IO_VGACRD1_TX_TYPE_MASK); switch (jreg) { - case 0x04: - ast->tx_chip_types = AST_TX_SIL164_BIT; + case AST_IO_VGACRD1_TX_SIL164_VBIOS: + ast->tx_chip = AST_TX_SIL164; break; - case 0x08: + case AST_IO_VGACRD1_TX_DP501_VBIOS: ast->dp501_fw_addr = drmm_kzalloc(dev, 32*1024, GFP_KERNEL); if (ast->dp501_fw_addr) { /* backup firmware */ - if (ast_backup_fw(dev, ast->dp501_fw_addr, 32*1024)) { + if (ast_backup_fw(ast, ast->dp501_fw_addr, 32*1024)) { drmm_kfree(dev, ast->dp501_fw_addr); ast->dp501_fw_addr = NULL; } } fallthrough; - case 0x0c: - ast->tx_chip_types = AST_TX_DP501_BIT; + case AST_IO_VGACRD1_TX_FW_EMBEDDED_FW: + ast->tx_chip = AST_TX_DP501; } } else if (IS_AST_GEN7(ast)) { - if (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, TX_TYPE_MASK) == - ASTDP_DPMCU_TX) { + if (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, AST_IO_VGACRD1_TX_TYPE_MASK) == + AST_IO_VGACRD1_TX_ASTDP) { int ret = ast_dp_launch(ast); if (!ret) - ast->tx_chip_types = AST_TX_ASTDP_BIT; + ast->tx_chip = AST_TX_ASTDP; } } - /* Print stuff for diagnostic purposes */ - if (ast->tx_chip_types & AST_TX_NONE_BIT) - drm_info(dev, "Using analog VGA\n"); - if (ast->tx_chip_types & AST_TX_SIL164_BIT) - drm_info(dev, "Using Sil164 TMDS transmitter\n"); - if (ast->tx_chip_types & AST_TX_DP501_BIT) - drm_info(dev, "Using DP501 DisplayPort transmitter\n"); - if (ast->tx_chip_types & AST_TX_ASTDP_BIT) - drm_info(dev, "Using ASPEED DisplayPort transmitter\n"); + drm_info(dev, "Using %s\n", info_str[ast->tx_chip]); } -static int ast_get_dram_info(struct drm_device *dev) +static int ast_get_dram_info(struct ast_device *ast) { + struct drm_device *dev = &ast->base; struct device_node *np = dev->dev->of_node; - struct ast_device *ast = to_ast_device(dev); uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap; uint32_t denum, num, div, ref_pll, dsel; @@ -278,7 +293,7 @@ struct drm_device *ast_device_create(struct pci_dev *pdev, ast_detect_widescreen(ast); ast_detect_tx_chip(ast, need_post); - ret = ast_get_dram_info(dev); + ret = ast_get_dram_info(ast); if (ret) return ERR_PTR(ret); @@ -286,7 +301,7 @@ struct drm_device *ast_device_create(struct pci_dev *pdev, ast->mclk, ast->dram_type, ast->dram_bus_width); if (need_post) - ast_post_gpu(dev); + ast_post_gpu(ast); ret = ast_mm_init(ast); if (ret) diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index ed496fb32bf349..9d5321c81e68d6 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1287,9 +1287,9 @@ static const struct drm_crtc_funcs ast_crtc_funcs = { .atomic_destroy_state = ast_crtc_atomic_destroy_state, }; -static int ast_crtc_init(struct drm_device *dev) +static int ast_crtc_init(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); + struct drm_device *dev = &ast->base; struct drm_crtc *crtc = &ast->crtc; int ret; @@ -1396,28 +1396,26 @@ int ast_mode_config_init(struct ast_device *ast) if (ret) return ret; - ast_crtc_init(dev); + ret = ast_crtc_init(ast); + if (ret) + return ret; - if (ast->tx_chip_types & AST_TX_NONE_BIT) { + switch (ast->tx_chip) { + case AST_TX_NONE: ret = ast_vga_output_init(ast); - if (ret) - return ret; - } - if (ast->tx_chip_types & AST_TX_SIL164_BIT) { + break; + case AST_TX_SIL164: ret = ast_sil164_output_init(ast); - if (ret) - return ret; - } - if (ast->tx_chip_types & AST_TX_DP501_BIT) { + break; + case AST_TX_DP501: ret = ast_dp501_output_init(ast); - if (ret) - return ret; - } - if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { + break; + case AST_TX_ASTDP: ret = ast_astdp_output_init(ast); - if (ret) - return ret; + break; } + if (ret) + return ret; drm_mode_config_reset(dev); diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 65755798ab94a5..364030f97571d7 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -34,16 +34,14 @@ #include "ast_dram_tables.h" #include "ast_drv.h" -static void ast_post_chip_2300(struct drm_device *dev); -static void ast_post_chip_2500(struct drm_device *dev); +static void ast_post_chip_2300(struct ast_device *ast); +static void ast_post_chip_2500(struct ast_device *ast); static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff }; static const u8 extreginfo_ast2300[] = { 0x0f, 0x04, 0x1f, 0xff }; -static void -ast_set_def_ext_reg(struct drm_device *dev) +static void ast_set_def_ext_reg(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); u8 i, index, reg; const u8 *ext_reg_info; @@ -252,9 +250,8 @@ static void cbrdlli_ast2150(struct ast_device *ast, int busw) -static void ast_init_dram_reg(struct drm_device *dev) +static void ast_init_dram_reg(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); u8 j; u32 data, temp, i; const struct ast_dramstruct *dram_reg_info; @@ -343,26 +340,24 @@ static void ast_init_dram_reg(struct drm_device *dev) } while ((j & 0x40) == 0); } -void ast_post_gpu(struct drm_device *dev) +void ast_post_gpu(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); - - ast_set_def_ext_reg(dev); + ast_set_def_ext_reg(ast); if (IS_AST_GEN7(ast)) { - if (ast->tx_chip_types & AST_TX_ASTDP_BIT) + if (ast->tx_chip == AST_TX_ASTDP) ast_dp_launch(ast); } else if (ast->config_mode == ast_use_p2a) { if (IS_AST_GEN6(ast)) - ast_post_chip_2500(dev); + ast_post_chip_2500(ast); else if (IS_AST_GEN5(ast) || IS_AST_GEN4(ast)) - ast_post_chip_2300(dev); + ast_post_chip_2300(ast); else - ast_init_dram_reg(dev); + ast_init_dram_reg(ast); - ast_init_3rdtx(dev); + ast_init_3rdtx(ast); } else { - if (ast->tx_chip_types & AST_TX_SIL164_BIT) + if (ast->tx_chip == AST_TX_SIL164) ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x80); /* Enable DVO */ } } @@ -1569,9 +1564,8 @@ static void ddr2_init(struct ast_device *ast, struct ast2300_dram_param *param) } -static void ast_post_chip_2300(struct drm_device *dev) +static void ast_post_chip_2300(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); struct ast2300_dram_param param; u32 temp; u8 reg; @@ -2038,9 +2032,9 @@ void ast_patch_ahb_2500(void __iomem *regs) __ast_moutdwm(regs, 0x1e6e207c, 0x08000000); /* clear fast reset */ } -void ast_post_chip_2500(struct drm_device *dev) +void ast_post_chip_2500(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); + struct drm_device *dev = &ast->base; u32 temp; u8 reg; diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 040961cc1a198d..2aadf07d135afa 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -37,28 +37,29 @@ #define AST_IO_VGACRCB_HWC_16BPP BIT(0) /* set: ARGB4444, cleared: 2bpp palette */ #define AST_IO_VGACRCB_HWC_ENABLED BIT(1) -#define AST_IO_VGACRD1_MCU_FW_EXECUTING BIT(5) +#define AST_IO_VGACRD1_MCU_FW_EXECUTING BIT(5) +/* Display Transmitter Type */ +#define AST_IO_VGACRD1_TX_TYPE_MASK GENMASK(3, 1) +#define AST_IO_VGACRD1_NO_TX 0x00 +#define AST_IO_VGACRD1_TX_ITE66121_VBIOS 0x02 +#define AST_IO_VGACRD1_TX_SIL164_VBIOS 0x04 +#define AST_IO_VGACRD1_TX_CH7003_VBIOS 0x06 +#define AST_IO_VGACRD1_TX_DP501_VBIOS 0x08 +#define AST_IO_VGACRD1_TX_ANX9807_VBIOS 0x0a +#define AST_IO_VGACRD1_TX_FW_EMBEDDED_FW 0x0c /* special case of DP501 */ +#define AST_IO_VGACRD1_TX_ASTDP 0x0e + #define AST_IO_VGACRD7_EDID_VALID_FLAG BIT(0) #define AST_IO_VGACRDC_LINK_SUCCESS BIT(0) #define AST_IO_VGACRDF_HPD BIT(0) +#define AST_IO_VGACRDF_DP_VIDEO_ENABLE BIT(4) /* mirrors AST_IO_VGACRE3_DP_VIDEO_ENABLE */ +#define AST_IO_VGACRE3_DP_VIDEO_ENABLE BIT(0) +#define AST_IO_VGACRE3_DP_PHY_SLEEP BIT(4) #define AST_IO_VGACRE5_EDID_READ_DONE BIT(0) #define AST_IO_VGAIR1_R (0x5A) #define AST_IO_VGAIR1_VREFRESH BIT(3) -/* - * Display Transmitter Type - */ - -#define TX_TYPE_MASK GENMASK(3, 1) -#define NO_TX (0 << 1) -#define ITE66121_VBIOS_TX (1 << 1) -#define SI164_VBIOS_TX (2 << 1) -#define CH7003_VBIOS_TX (3 << 1) -#define DP501_VBIOS_TX (4 << 1) -#define ANX9807_VBIOS_TX (5 << 1) -#define TX_FW_EMBEDDED_FW_TX (6 << 1) -#define ASTDP_DPMCU_TX (7 << 1) #define AST_VRAM_INIT_STATUS_MASK GENMASK(7, 6) //#define AST_VRAM_INIT_BY_BMC BIT(7) @@ -68,18 +69,6 @@ * AST DisplayPort */ -/* Define for Soc scratched reg used on ASTDP */ -#define AST_DP_PHY_SLEEP BIT(4) -#define AST_DP_VIDEO_ENABLE BIT(0) - -/* - * CRDF[b4]: Mirror of AST_DP_VIDEO_ENABLE - * Precondition: A. ~AST_DP_PHY_SLEEP && - * B. DP_HPD && - * C. DP_LINK_SUCCESS - */ -#define ASTDP_MIRROR_VIDEO_ENABLE BIT(4) - /* * ASTDP setmode registers: * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp) diff --git a/drivers/gpu/drm/ast/ast_sil164.c b/drivers/gpu/drm/ast/ast_sil164.c index c231389936bdab..be01254dd48a2a 100644 --- a/drivers/gpu/drm/ast/ast_sil164.c +++ b/drivers/gpu/drm/ast/ast_sil164.c @@ -73,52 +73,49 @@ static const struct drm_connector_funcs ast_sil164_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int ast_sil164_connector_init(struct drm_device *dev, struct drm_connector *connector) +/* + * Output + */ + +int ast_sil164_output_init(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; struct i2c_adapter *ddc; + struct drm_encoder *encoder; + struct ast_connector *ast_connector; + struct drm_connector *connector; int ret; + /* DDC */ + ddc = ast_ddc_create(ast); - if (IS_ERR(ddc)) { - ret = PTR_ERR(ddc); - drm_err(dev, "failed to add DDC bus for connector; ret=%d\n", ret); + if (IS_ERR(ddc)) + return PTR_ERR(ddc); + + /* encoder */ + + encoder = &ast->output.sil164.encoder; + ret = drm_encoder_init(dev, encoder, &ast_sil164_encoder_funcs, + DRM_MODE_ENCODER_TMDS, NULL); + if (ret) return ret; - } + encoder->possible_crtcs = drm_crtc_mask(crtc); + + /* connector */ + ast_connector = &ast->output.sil164.connector; + connector = &ast_connector->base; ret = drm_connector_init_with_ddc(dev, connector, &ast_sil164_connector_funcs, DRM_MODE_CONNECTOR_DVII, ddc); if (ret) return ret; - drm_connector_helper_add(connector, &ast_sil164_connector_helper_funcs); connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - return 0; -} - -int ast_sil164_output_init(struct ast_device *ast) -{ - struct drm_device *dev = &ast->base; - struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.sil164.encoder; - struct ast_connector *ast_connector = &ast->output.sil164.connector; - struct drm_connector *connector = &ast_connector->base; - int ret; - - ret = drm_encoder_init(dev, encoder, &ast_sil164_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); - if (ret) - return ret; - encoder->possible_crtcs = drm_crtc_mask(crtc); - - ret = ast_sil164_connector_init(dev, connector); - if (ret) - return ret; ast_connector->physical_status = connector->status; ret = drm_connector_attach_encoder(connector, encoder); diff --git a/drivers/gpu/drm/ast/ast_vga.c b/drivers/gpu/drm/ast/ast_vga.c index dd389a0a8f4a21..abe0fff8485cea 100644 --- a/drivers/gpu/drm/ast/ast_vga.c +++ b/drivers/gpu/drm/ast/ast_vga.c @@ -73,52 +73,49 @@ static const struct drm_connector_funcs ast_vga_connector_funcs = { .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; -static int ast_vga_connector_init(struct drm_device *dev, struct drm_connector *connector) +/* + * Output + */ + +int ast_vga_output_init(struct ast_device *ast) { - struct ast_device *ast = to_ast_device(dev); + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; struct i2c_adapter *ddc; + struct drm_encoder *encoder; + struct ast_connector *ast_connector; + struct drm_connector *connector; int ret; + /* DDC */ + ddc = ast_ddc_create(ast); - if (IS_ERR(ddc)) { - ret = PTR_ERR(ddc); - drm_err(dev, "failed to add DDC bus for connector; ret=%d\n", ret); + if (IS_ERR(ddc)) + return PTR_ERR(ddc); + + /* encoder */ + + encoder = &ast->output.vga.encoder; + ret = drm_encoder_init(dev, encoder, &ast_vga_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) return ret; - } + encoder->possible_crtcs = drm_crtc_mask(crtc); + + /* connector */ + ast_connector = &ast->output.vga.connector; + connector = &ast_connector->base; ret = drm_connector_init_with_ddc(dev, connector, &ast_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA, ddc); if (ret) return ret; - drm_connector_helper_add(connector, &ast_vga_connector_helper_funcs); connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - return 0; -} - -int ast_vga_output_init(struct ast_device *ast) -{ - struct drm_device *dev = &ast->base; - struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.vga.encoder; - struct ast_connector *ast_connector = &ast->output.vga.connector; - struct drm_connector *connector = &ast_connector->base; - int ret; - - ret = drm_encoder_init(dev, encoder, &ast_vga_encoder_funcs, - DRM_MODE_ENCODER_DAC, NULL); - if (ret) - return ret; - encoder->possible_crtcs = drm_crtc_mask(crtc); - - ret = ast_vga_connector_init(dev, connector); - if (ret) - return ret; ast_connector->physical_status = connector->status; ret = drm_connector_attach_encoder(connector, encoder); diff --git a/drivers/gpu/drm/atmel-hlcdc/Kconfig b/drivers/gpu/drm/atmel-hlcdc/Kconfig index 945f3aa7bb2409..f8b9c91907d8ec 100644 --- a/drivers/gpu/drm/atmel-hlcdc/Kconfig +++ b/drivers/gpu/drm/atmel-hlcdc/Kconfig @@ -2,6 +2,7 @@ config DRM_ATMEL_HLCDC tristate "DRM Support for ATMEL HLCDC Display Controller" depends on DRM && OF && COMMON_CLK && ((MFD_ATMEL_HLCDC && ARM) || COMPILE_TEST) + select DRM_CLIENT_SELECTION select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_PANEL diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 9ce429f889cac2..7b209af7cf457a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -18,8 +18,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -840,6 +842,7 @@ DEFINE_DRM_GEM_DMA_FOPS(fops); static const struct drm_driver atmel_hlcdc_dc_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, DRM_GEM_DMA_DRIVER_OPS, + DRM_FBDEV_DMA_DRIVER_OPS, .fops = &fops, .name = "atmel-hlcdc", .desc = "Atmel HLCD Controller DRM", @@ -865,7 +868,7 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev) if (ret) goto err_unload; - drm_fbdev_dma_setup(ddev, 24); + drm_client_setup_with_fourcc(ddev, DRM_FORMAT_RGB888); return 0; @@ -934,7 +937,7 @@ static const struct of_device_id atmel_hlcdc_dc_of_match[] = { static struct platform_driver atmel_hlcdc_dc_platform_driver = { .probe = atmel_hlcdc_dc_drm_probe, - .remove_new = atmel_hlcdc_dc_drm_remove, + .remove = atmel_hlcdc_dc_drm_remove, .shutdown = atmel_hlcdc_dc_drm_shutdown, .driver = { .name = "atmel-hlcdc-display-controller", diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 3eb955333c809e..6b4664d91faa80 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -90,6 +90,17 @@ config DRM_FSL_LDB help Support for i.MX8MP DPI-to-LVDS on-SoC encoder. +config DRM_ITE_IT6263 + tristate "ITE IT6263 LVDS/HDMI bridge" + depends on OF + select DRM_DISPLAY_HDMI_STATE_HELPER + select DRM_DISPLAY_HELPER + select DRM_BRIDGE_CONNECTOR + select DRM_KMS_HELPER + select REGMAP_I2C + help + ITE IT6263 LVDS to HDMI bridge chip driver. + config DRM_ITE_IT6505 tristate "ITE IT6505 DisplayPort bridge" depends on OF @@ -140,6 +151,8 @@ config DRM_LONTIUM_LT9611 select DRM_PANEL_BRIDGE select DRM_KMS_HELPER select DRM_MIPI_DSI + select DRM_DISPLAY_HELPER + select DRM_DISPLAY_HDMI_STATE_HELPER select REGMAP_I2C help Driver for Lontium LT9611 DSI to HDMI bridge @@ -368,6 +381,13 @@ config DRM_TI_DLPC3433 It supports up to 720p resolution with 60 and 120 Hz refresh rates. +config DRM_TI_TDP158 + tristate "TI TDP158 HDMI/TMDS bridge" + depends on OF + select DRM_PANEL_BRIDGE + help + Texas Instruments TDP158 HDMI/TMDS Bridge driver + config DRM_TI_TFP410 tristate "TI TFP410 DVI/HDMI bridge" depends on OF diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 7df87b582dca34..97304b429a530c 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_CHRONTEL_CH7033) += chrontel-ch7033.o obj-$(CONFIG_DRM_CROS_EC_ANX7688) += cros-ec-anx7688.o obj-$(CONFIG_DRM_DISPLAY_CONNECTOR) += display-connector.o obj-$(CONFIG_DRM_FSL_LDB) += fsl-ldb.o +obj-$(CONFIG_DRM_ITE_IT6263) += ite-it6263.o obj-$(CONFIG_DRM_ITE_IT6505) += ite-it6505.o obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o obj-$(CONFIG_DRM_LONTIUM_LT9211) += lontium-lt9211.o @@ -32,6 +33,7 @@ obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ obj-$(CONFIG_DRM_TI_DLPC3433) += ti-dlpc3433.o obj-$(CONFIG_DRM_TI_SN65DSI83) += ti-sn65dsi83.o obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o +obj-$(CONFIG_DRM_TI_TDP158) += ti-tdp158.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o obj-$(CONFIG_DRM_TI_TPD12S015) += ti-tpd12s015.o obj-$(CONFIG_DRM_NWL_MIPI_DSI) += nwl-dsi.o diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index a2e9bb485c366e..a2675b121fe44b 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -2551,6 +2551,8 @@ static int __maybe_unused anx7625_runtime_pm_suspend(struct device *dev) mutex_lock(&ctx->lock); anx7625_stop_dp_work(ctx); + if (!ctx->pdata.panel_bridge) + anx7625_remove_edid(ctx); anx7625_power_standby(ctx); mutex_unlock(&ctx->lock); diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c index 295e9d031e2dc8..015983c015e508 100644 --- a/drivers/gpu/drm/bridge/aux-bridge.c +++ b/drivers/gpu/drm/bridge/aux-bridge.c @@ -121,6 +121,10 @@ static int drm_aux_bridge_probe(struct auxiliary_device *auxdev, data->bridge.funcs = &drm_aux_bridge_funcs; data->bridge.of_node = data->dev->of_node; + /* passthrough data, allow everything */ + data->bridge.interlace_allowed = true; + data->bridge.ycbcr_420_allowed = true; + return devm_drm_bridge_add(data->dev, &data->bridge); } diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c index 6886db2d9e00c4..48f297c78ee67c 100644 --- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c +++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c @@ -180,6 +180,10 @@ static int drm_aux_hpd_bridge_probe(struct auxiliary_device *auxdev, data->bridge.ops = DRM_BRIDGE_OP_HPD; data->bridge.type = id->driver_data; + /* passthrough data, allow everything */ + data->bridge.interlace_allowed = true; + data->bridge.ycbcr_420_allowed = true; + auxiliary_set_drvdata(auxdev, data); return devm_drm_bridge_add(data->dev, &data->bridge); diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c index 7457d38622b0c7..c7a0247e06adf3 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c @@ -1300,7 +1300,7 @@ MODULE_DEVICE_TABLE(of, cdns_dsi_of_match); static struct platform_driver cdns_dsi_platform_driver = { .probe = cdns_dsi_drm_probe, - .remove_new = cdns_dsi_drm_remove, + .remove = cdns_dsi_drm_remove, .driver = { .name = "cdns-dsi", .of_match_table = cdns_dsi_of_match, diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 41f72d458487fb..d081850e3c03e9 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -2656,7 +2656,7 @@ static struct platform_driver mhdp_driver = { .of_match_table = mhdp_ids, }, .probe = cdns_mhdp_probe, - .remove_new = cdns_mhdp_remove, + .remove = cdns_mhdp_remove, }; module_platform_driver(mhdp_driver); diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index ab8e00baf3f163..72bc508d4e6e2b 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -270,6 +270,10 @@ static int display_connector_probe(struct platform_device *pdev) /* All the supported connector types support interlaced modes. */ conn->bridge.interlace_allowed = true; + if (type == DRM_MODE_CONNECTOR_HDMIA || + type == DRM_MODE_CONNECTOR_DisplayPort) + conn->bridge.ycbcr_420_allowed = true; + /* Get the optional connector label. */ of_property_read_string(pdev->dev.of_node, "label", &label); @@ -423,7 +427,7 @@ MODULE_DEVICE_TABLE(of, display_connector_match); static struct platform_driver display_connector_driver = { .probe = display_connector_probe, - .remove_new = display_connector_remove, + .remove = display_connector_remove, .driver = { .name = "display-connector", .of_match_table = display_connector_match, diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c index 0e4bac7dd04ff1..0fc8a14fd80062 100644 --- a/drivers/gpu/drm/bridge/fsl-ldb.c +++ b/drivers/gpu/drm/bridge/fsl-ldb.c @@ -393,7 +393,7 @@ MODULE_DEVICE_TABLE(of, fsl_ldb_match); static struct platform_driver fsl_ldb_driver = { .probe = fsl_ldb_probe, - .remove_new = fsl_ldb_remove, + .remove = fsl_ldb_remove, .driver = { .name = "fsl-ldb", .of_match_table = fsl_ldb_match, diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig index 8dd89efa8ea7d9..9a480c6abb8562 100644 --- a/drivers/gpu/drm/bridge/imx/Kconfig +++ b/drivers/gpu/drm/bridge/imx/Kconfig @@ -3,6 +3,16 @@ if ARCH_MXC || COMPILE_TEST config DRM_IMX_LDB_HELPER tristate +config DRM_IMX_LEGACY_BRIDGE + tristate + depends on DRM_IMX + help + This is a DRM bridge implementation for the DRM i.MX IPUv3 driver, + that uses of_get_drm_display_mode to acquire display mode. + + Newer designs should not use this bridge and should use proper panel + driver instead. + config DRM_IMX8MP_DW_HDMI_BRIDGE tristate "Freescale i.MX8MP HDMI-TX bridge support" depends on OF diff --git a/drivers/gpu/drm/bridge/imx/Makefile b/drivers/gpu/drm/bridge/imx/Makefile index edb0a7b71b30a3..dd5d4858480663 100644 --- a/drivers/gpu/drm/bridge/imx/Makefile +++ b/drivers/gpu/drm/bridge/imx/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_DRM_IMX_LDB_HELPER) += imx-ldb-helper.o +obj-$(CONFIG_DRM_IMX_LEGACY_BRIDGE) += imx-legacy-bridge.o obj-$(CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE) += imx8mp-hdmi-tx.o obj-$(CONFIG_DRM_IMX8MP_HDMI_PVI) += imx8mp-hdmi-pvi.o obj-$(CONFIG_DRM_IMX8QM_LDB) += imx8qm-ldb.o diff --git a/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c b/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c new file mode 100644 index 00000000000000..3ebf0b9866de13 --- /dev/null +++ b/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Freescale i.MX drm driver + * + * bridge driver for legacy DT bindings, utilizing display-timings node + */ + +#include +#include +#include +#include + +#include
), and the length is + * stored as number for triplets in dynamic_list_len. + */ + lock->dynamic_list_len = 0; +} + +static int a7xx_preempt_start(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct msm_ringbuffer *ring = gpu->rb[0]; + + if (gpu->nr_rings <= 1) + return 0; + + /* Turn CP protection off */ + OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1); + OUT_RING(ring, 0); + + a6xx_emit_set_pseudo_reg(ring, a6xx_gpu, NULL); + + /* Yield the floor on command completion */ + OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4); + OUT_RING(ring, 0x00); + OUT_RING(ring, 0x00); + OUT_RING(ring, 0x00); + /* Generate interrupt on preemption completion */ + OUT_RING(ring, 0x00); + + a6xx_flush(gpu, ring); + + return a6xx_idle(gpu, ring) ? 0 : -EINVAL; +} + static int a6xx_cp_init(struct msm_gpu *gpu) { struct msm_ringbuffer *ring = gpu->rb[0]; @@ -640,6 +804,8 @@ static int a6xx_cp_init(struct msm_gpu *gpu) static int a7xx_cp_init(struct msm_gpu *gpu) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); struct msm_ringbuffer *ring = gpu->rb[0]; u32 mask; @@ -677,11 +843,11 @@ static int a7xx_cp_init(struct msm_gpu *gpu) /* *Don't* send a power up reg list for concurrent binning (TODO) */ /* Lo address */ - OUT_RING(ring, 0x00000000); + OUT_RING(ring, lower_32_bits(a6xx_gpu->pwrup_reglist_iova)); /* Hi address */ - OUT_RING(ring, 0x00000000); + OUT_RING(ring, upper_32_bits(a6xx_gpu->pwrup_reglist_iova)); /* BIT(31) set => read the regs from the list */ - OUT_RING(ring, 0x00000000); + OUT_RING(ring, BIT(31)); a6xx_flush(gpu, ring); return a6xx_idle(gpu, ring) ? 0 : -EINVAL; @@ -805,6 +971,16 @@ static int a6xx_ucode_load(struct msm_gpu *gpu) msm_gem_object_set_name(a6xx_gpu->shadow_bo, "shadow"); } + a6xx_gpu->pwrup_reglist_ptr = msm_gem_kernel_new(gpu->dev, PAGE_SIZE, + MSM_BO_WC | MSM_BO_MAP_PRIV, + gpu->aspace, &a6xx_gpu->pwrup_reglist_bo, + &a6xx_gpu->pwrup_reglist_iova); + + if (IS_ERR(a6xx_gpu->pwrup_reglist_ptr)) + return PTR_ERR(a6xx_gpu->pwrup_reglist_ptr); + + msm_gem_object_set_name(a6xx_gpu->pwrup_reglist_bo, "pwrup_reglist"); + return 0; } @@ -864,6 +1040,7 @@ static int hw_init(struct msm_gpu *gpu) struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); struct a6xx_gmu *gmu = &a6xx_gpu->gmu; u64 gmem_range_min; + unsigned int i; int ret; if (!adreno_has_gmu_wrapper(adreno_gpu)) { @@ -1072,7 +1249,7 @@ static int hw_init(struct msm_gpu *gpu) if (adreno_is_a690(adreno_gpu)) gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, 0x90); /* Set dualQ + disable afull for A660 GPU */ - else if (adreno_is_a660(adreno_gpu)) + else if (adreno_is_a660(adreno_gpu) || adreno_is_a663(adreno_gpu)) gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, 0x66906); else if (adreno_is_a7xx(adreno_gpu)) gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, @@ -1134,22 +1311,32 @@ static int hw_init(struct msm_gpu *gpu) if (a6xx_gpu->shadow_bo) { gpu_write64(gpu, REG_A6XX_CP_RB_RPTR_ADDR, shadowptr(a6xx_gpu, gpu->rb[0])); + for (unsigned int i = 0; i < gpu->nr_rings; i++) + a6xx_gpu->shadow[i] = 0; } /* ..which means "always" on A7xx, also for BV shadow */ if (adreno_is_a7xx(adreno_gpu)) { gpu_write64(gpu, REG_A7XX_CP_BV_RB_RPTR_ADDR, - rbmemptr(gpu->rb[0], bv_fence)); + rbmemptr(gpu->rb[0], bv_rptr)); } + a6xx_preempt_hw_init(gpu); + /* Always come up on rb 0 */ a6xx_gpu->cur_ring = gpu->rb[0]; - gpu->cur_ctx_seqno = 0; + for (i = 0; i < gpu->nr_rings; i++) + gpu->rb[i]->cur_ctx_seqno = 0; /* Enable the SQE_to start the CP engine */ gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 1); + if (adreno_is_a7xx(adreno_gpu) && !a6xx_gpu->pwrup_reglist_emitted) { + a7xx_patch_pwrup_reglist(gpu); + a6xx_gpu->pwrup_reglist_emitted = true; + } + ret = adreno_is_a7xx(adreno_gpu) ? a7xx_cp_init(gpu) : a6xx_cp_init(gpu); if (ret) goto out; @@ -1187,6 +1374,10 @@ static int hw_init(struct msm_gpu *gpu) out: if (adreno_has_gmu_wrapper(adreno_gpu)) return ret; + + /* Last step - yield the ringbuffer */ + a7xx_preempt_start(gpu); + /* * Tell the GMU that we are done touching the GPU and it can start power * management @@ -1564,8 +1755,13 @@ static irqreturn_t a6xx_irq(struct msm_gpu *gpu) if (status & A6XX_RBBM_INT_0_MASK_SWFUSEVIOLATION) a7xx_sw_fuse_violation_irq(gpu); - if (status & A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) + if (status & A6XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) { msm_gpu_retire(gpu); + a6xx_preempt_trigger(gpu); + } + + if (status & A6XX_RBBM_INT_0_MASK_CP_SW) + a6xx_preempt_irq(gpu); return IRQ_HANDLED; } @@ -2259,6 +2455,7 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) struct a6xx_gpu *a6xx_gpu; struct adreno_gpu *adreno_gpu; struct msm_gpu *gpu; + extern int enable_preemption; bool is_a7xx; int ret; @@ -2297,7 +2494,10 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) return ERR_PTR(ret); } - if (is_a7xx) + if ((enable_preemption == 1) || (enable_preemption == -1 && + (config->info->quirks & ADRENO_QUIRK_PREEMPTION))) + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs_a7xx, 4); + else if (is_a7xx) ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs_a7xx, 1); else if (adreno_has_gmu_wrapper(adreno_gpu)) ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs_gmuwrapper, 1); @@ -2338,6 +2538,8 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) a6xx_fault_handler); a6xx_calc_ubwc_config(adreno_gpu); + /* Set up the preemption specific bits and pieces for each ringbuffer */ + a6xx_preempt_init(gpu); return gpu; } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index 0fb7febf70e73b..4aceffb6aae89c 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -12,15 +12,35 @@ extern bool hang_debug; +struct cpu_gpu_lock { + uint32_t gpu_req; + uint32_t cpu_req; + uint32_t turn; + union { + struct { + uint16_t list_length; + uint16_t list_offset; + }; + struct { + uint8_t ifpc_list_len; + uint8_t preemption_list_len; + uint16_t dynamic_list_len; + }; + }; + uint64_t regs[62]; +}; + /** * struct a6xx_info - a6xx specific information from device table * * @hwcg: hw clock gating register sequence * @protect: CP_PROTECT settings + * @pwrup_reglist pwrup reglist for preemption */ struct a6xx_info { const struct adreno_reglist *hwcg; const struct adreno_protect *protect; + const struct adreno_reglist_list *pwrup_reglist; u32 gmu_chipid; u32 gmu_cgc_mode; u32 prim_fifo_threshold; @@ -33,6 +53,29 @@ struct a6xx_gpu { uint64_t sqe_iova; struct msm_ringbuffer *cur_ring; + struct msm_ringbuffer *next_ring; + + struct drm_gem_object *preempt_bo[MSM_GPU_MAX_RINGS]; + void *preempt[MSM_GPU_MAX_RINGS]; + uint64_t preempt_iova[MSM_GPU_MAX_RINGS]; + struct drm_gem_object *preempt_smmu_bo[MSM_GPU_MAX_RINGS]; + void *preempt_smmu[MSM_GPU_MAX_RINGS]; + uint64_t preempt_smmu_iova[MSM_GPU_MAX_RINGS]; + uint32_t last_seqno[MSM_GPU_MAX_RINGS]; + + atomic_t preempt_state; + spinlock_t eval_lock; + struct timer_list preempt_timer; + + unsigned int preempt_level; + bool uses_gmem; + bool skip_save_restore; + + struct drm_gem_object *preempt_postamble_bo; + void *preempt_postamble_ptr; + uint64_t preempt_postamble_iova; + uint64_t preempt_postamble_len; + bool postamble_enabled; struct a6xx_gmu gmu; @@ -40,6 +83,11 @@ struct a6xx_gpu { uint64_t shadow_iova; uint32_t *shadow; + struct drm_gem_object *pwrup_reglist_bo; + void *pwrup_reglist_ptr; + uint64_t pwrup_reglist_iova; + bool pwrup_reglist_emitted; + bool has_whereami; void __iomem *llc_mmio; @@ -51,6 +99,100 @@ struct a6xx_gpu { #define to_a6xx_gpu(x) container_of(x, struct a6xx_gpu, base) +/* + * In order to do lockless preemption we use a simple state machine to progress + * through the process. + * + * PREEMPT_NONE - no preemption in progress. Next state START. + * PREEMPT_START - The trigger is evaluating if preemption is possible. Next + * states: TRIGGERED, NONE + * PREEMPT_FINISH - An intermediate state before moving back to NONE. Next + * state: NONE. + * PREEMPT_TRIGGERED: A preemption has been executed on the hardware. Next + * states: FAULTED, PENDING + * PREEMPT_FAULTED: A preemption timed out (never completed). This will trigger + * recovery. Next state: N/A + * PREEMPT_PENDING: Preemption complete interrupt fired - the callback is + * checking the success of the operation. Next state: FAULTED, NONE. + */ + +enum a6xx_preempt_state { + PREEMPT_NONE = 0, + PREEMPT_START, + PREEMPT_FINISH, + PREEMPT_TRIGGERED, + PREEMPT_FAULTED, + PREEMPT_PENDING, +}; + +/* + * struct a6xx_preempt_record is a shared buffer between the microcode and the + * CPU to store the state for preemption. The record itself is much larger + * (2112k) but most of that is used by the CP for storage. + * + * There is a preemption record assigned per ringbuffer. When the CPU triggers a + * preemption, it fills out the record with the useful information (wptr, ring + * base, etc) and the microcode uses that information to set up the CP following + * the preemption. When a ring is switched out, the CP will save the ringbuffer + * state back to the record. In this way, once the records are properly set up + * the CPU can quickly switch back and forth between ringbuffers by only + * updating a few registers (often only the wptr). + * + * These are the CPU aware registers in the record: + * @magic: Must always be 0xAE399D6EUL + * @info: Type of the record - written 0 by the CPU, updated by the CP + * @errno: preemption error record + * @data: Data field in YIELD and SET_MARKER packets, Written and used by CP + * @cntl: Value of RB_CNTL written by CPU, save/restored by CP + * @rptr: Value of RB_RPTR written by CPU, save/restored by CP + * @wptr: Value of RB_WPTR written by CPU, save/restored by CP + * @_pad: Reserved/padding + * @rptr_addr: Value of RB_RPTR_ADDR_LO|HI written by CPU, save/restored by CP + * @rbase: Value of RB_BASE written by CPU, save/restored by CP + * @counter: GPU address of the storage area for the preemption counters + * @bv_rptr_addr: Value of BV_RB_RPTR_ADDR_LO|HI written by CPU, save/restored by CP + */ +struct a6xx_preempt_record { + u32 magic; + u32 info; + u32 errno; + u32 data; + u32 cntl; + u32 rptr; + u32 wptr; + u32 _pad; + u64 rptr_addr; + u64 rbase; + u64 counter; + u64 bv_rptr_addr; +}; + +#define A6XX_PREEMPT_RECORD_MAGIC 0xAE399D6EUL + +#define PREEMPT_SMMU_INFO_SIZE 4096 + +#define PREEMPT_RECORD_SIZE(adreno_gpu) \ + ((adreno_gpu->info->preempt_record_size) == 0 ? \ + 4192 * SZ_1K : (adreno_gpu->info->preempt_record_size)) + +/* + * The preemption counter block is a storage area for the value of the + * preemption counters that are saved immediately before context switch. We + * append it on to the end of the allocation for the preemption record. + */ +#define A6XX_PREEMPT_COUNTER_SIZE (16 * 4) + +struct a7xx_cp_smmu_info { + u32 magic; + u32 _pad4; + u64 ttbr0; + u32 asid; + u32 context_idr; + u32 context_bank; +}; + +#define GEN7_CP_SMMU_INFO_MAGIC 0x241350d5UL + /* * Given a register and a count, return a value to program into * REG_CP_PROTECT_REG(n) - this will block both reads and writes for @@ -108,6 +250,34 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node); int a6xx_gmu_wrapper_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node); void a6xx_gmu_remove(struct a6xx_gpu *a6xx_gpu); +void a6xx_preempt_init(struct msm_gpu *gpu); +void a6xx_preempt_hw_init(struct msm_gpu *gpu); +void a6xx_preempt_trigger(struct msm_gpu *gpu); +void a6xx_preempt_irq(struct msm_gpu *gpu); +void a6xx_preempt_fini(struct msm_gpu *gpu); +int a6xx_preempt_submitqueue_setup(struct msm_gpu *gpu, + struct msm_gpu_submitqueue *queue); +void a6xx_preempt_submitqueue_close(struct msm_gpu *gpu, + struct msm_gpu_submitqueue *queue); + +/* Return true if we are in a preempt state */ +static inline bool a6xx_in_preempt(struct a6xx_gpu *a6xx_gpu) +{ + /* + * Make sure the read to preempt_state is ordered with respect to reads + * of other variables before ... + */ + smp_rmb(); + + int preempt_state = atomic_read(&a6xx_gpu->preempt_state); + + /* ... and after. */ + smp_rmb(); + + return !(preempt_state == PREEMPT_NONE || + preempt_state == PREEMPT_FINISH); +} + void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp, bool suspended); unsigned long a6xx_gmu_get_freq(struct msm_gpu *gpu); diff --git a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c index cdb3f6e74d3e63..cb8844ed46b29c 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_hfi.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_hfi.c @@ -478,6 +478,37 @@ static void a660_build_bw_table(struct a6xx_hfi_msg_bw_table *msg) msg->cnoc_cmds_data[1][0] = 0x60000001; } +static void a663_build_bw_table(struct a6xx_hfi_msg_bw_table *msg) +{ + /* + * Send a single "off" entry just to get things running + * TODO: bus scaling + */ + msg->bw_level_num = 1; + + msg->ddr_cmds_num = 3; + msg->ddr_wait_bitmask = 0x07; + + msg->ddr_cmds_addrs[0] = 0x50004; + msg->ddr_cmds_addrs[1] = 0x50000; + msg->ddr_cmds_addrs[2] = 0x500b4; + + msg->ddr_cmds_data[0][0] = 0x40000000; + msg->ddr_cmds_data[0][1] = 0x40000000; + msg->ddr_cmds_data[0][2] = 0x40000000; + + /* + * These are the CX (CNOC) votes - these are used by the GMU but the + * votes are known and fixed for the target + */ + msg->cnoc_cmds_num = 1; + msg->cnoc_wait_bitmask = 0x01; + + msg->cnoc_cmds_addrs[0] = 0x50058; + msg->cnoc_cmds_data[0][0] = 0x40000000; + msg->cnoc_cmds_data[1][0] = 0x60000001; +} + static void adreno_7c3_build_bw_table(struct a6xx_hfi_msg_bw_table *msg) { /* @@ -630,32 +661,44 @@ static void a6xx_build_bw_table(struct a6xx_hfi_msg_bw_table *msg) static int a6xx_hfi_send_bw_table(struct a6xx_gmu *gmu) { - struct a6xx_hfi_msg_bw_table msg = { 0 }; + struct a6xx_hfi_msg_bw_table *msg; struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + if (gmu->bw_table) + goto send; + + msg = devm_kzalloc(gmu->dev, sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + if (adreno_is_a618(adreno_gpu)) - a618_build_bw_table(&msg); + a618_build_bw_table(msg); else if (adreno_is_a619(adreno_gpu)) - a619_build_bw_table(&msg); + a619_build_bw_table(msg); else if (adreno_is_a640_family(adreno_gpu)) - a640_build_bw_table(&msg); + a640_build_bw_table(msg); else if (adreno_is_a650(adreno_gpu)) - a650_build_bw_table(&msg); + a650_build_bw_table(msg); else if (adreno_is_7c3(adreno_gpu)) - adreno_7c3_build_bw_table(&msg); + adreno_7c3_build_bw_table(msg); else if (adreno_is_a660(adreno_gpu)) - a660_build_bw_table(&msg); + a660_build_bw_table(msg); + else if (adreno_is_a663(adreno_gpu)) + a663_build_bw_table(msg); else if (adreno_is_a690(adreno_gpu)) - a690_build_bw_table(&msg); + a690_build_bw_table(msg); else if (adreno_is_a730(adreno_gpu)) - a730_build_bw_table(&msg); + a730_build_bw_table(msg); else if (adreno_is_a740_family(adreno_gpu)) - a740_build_bw_table(&msg); + a740_build_bw_table(msg); else - a6xx_build_bw_table(&msg); + a6xx_build_bw_table(msg); + + gmu->bw_table = msg; - return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_BW_TABLE, &msg, sizeof(msg), +send: + return a6xx_hfi_send_msg(gmu, HFI_H2F_MSG_BW_TABLE, gmu->bw_table, sizeof(*(gmu->bw_table)), NULL, 0); } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c new file mode 100644 index 00000000000000..2fd4e39f618f3d --- /dev/null +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2023 Collabora, Ltd. */ +/* Copyright (c) 2024 Valve Corporation */ + +#include "msm_gem.h" +#include "a6xx_gpu.h" +#include "a6xx_gmu.xml.h" +#include "msm_mmu.h" +#include "msm_gpu_trace.h" + +/* + * Try to transition the preemption state from old to new. Return + * true on success or false if the original state wasn't 'old' + */ +static inline bool try_preempt_state(struct a6xx_gpu *a6xx_gpu, + enum a6xx_preempt_state old, enum a6xx_preempt_state new) +{ + enum a6xx_preempt_state cur = atomic_cmpxchg(&a6xx_gpu->preempt_state, + old, new); + + return (cur == old); +} + +/* + * Force the preemption state to the specified state. This is used in cases + * where the current state is known and won't change + */ +static inline void set_preempt_state(struct a6xx_gpu *gpu, + enum a6xx_preempt_state new) +{ + /* + * preempt_state may be read by other cores trying to trigger a + * preemption or in the interrupt handler so barriers are needed + * before... + */ + smp_mb__before_atomic(); + atomic_set(&gpu->preempt_state, new); + /* ... and after*/ + smp_mb__after_atomic(); +} + +/* Write the most recent wptr for the given ring into the hardware */ +static inline void update_wptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring) +{ + unsigned long flags; + uint32_t wptr; + + spin_lock_irqsave(&ring->preempt_lock, flags); + + if (ring->restore_wptr) { + wptr = get_wptr(ring); + + gpu_write(gpu, REG_A6XX_CP_RB_WPTR, wptr); + + ring->restore_wptr = false; + } + + spin_unlock_irqrestore(&ring->preempt_lock, flags); +} + +/* Return the highest priority ringbuffer with something in it */ +static struct msm_ringbuffer *get_next_ring(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + + unsigned long flags; + int i; + + for (i = 0; i < gpu->nr_rings; i++) { + bool empty; + struct msm_ringbuffer *ring = gpu->rb[i]; + + spin_lock_irqsave(&ring->preempt_lock, flags); + empty = (get_wptr(ring) == gpu->funcs->get_rptr(gpu, ring)); + if (!empty && ring == a6xx_gpu->cur_ring) + empty = ring->memptrs->fence == a6xx_gpu->last_seqno[i]; + spin_unlock_irqrestore(&ring->preempt_lock, flags); + + if (!empty) + return ring; + } + + return NULL; +} + +static void a6xx_preempt_timer(struct timer_list *t) +{ + struct a6xx_gpu *a6xx_gpu = from_timer(a6xx_gpu, t, preempt_timer); + struct msm_gpu *gpu = &a6xx_gpu->base.base; + struct drm_device *dev = gpu->dev; + + if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_FAULTED)) + return; + + dev_err(dev->dev, "%s: preemption timed out\n", gpu->name); + kthread_queue_work(gpu->worker, &gpu->recover_work); +} + +static void preempt_prepare_postamble(struct a6xx_gpu *a6xx_gpu) +{ + u32 *postamble = a6xx_gpu->preempt_postamble_ptr; + u32 count = 0; + + postamble[count++] = PKT7(CP_REG_RMW, 3); + postamble[count++] = REG_A6XX_RBBM_PERFCTR_SRAM_INIT_CMD; + postamble[count++] = 0; + postamble[count++] = 1; + + postamble[count++] = PKT7(CP_WAIT_REG_MEM, 6); + postamble[count++] = CP_WAIT_REG_MEM_0_FUNCTION(WRITE_EQ); + postamble[count++] = CP_WAIT_REG_MEM_1_POLL_ADDR_LO( + REG_A6XX_RBBM_PERFCTR_SRAM_INIT_STATUS); + postamble[count++] = CP_WAIT_REG_MEM_2_POLL_ADDR_HI(0); + postamble[count++] = CP_WAIT_REG_MEM_3_REF(0x1); + postamble[count++] = CP_WAIT_REG_MEM_4_MASK(0x1); + postamble[count++] = CP_WAIT_REG_MEM_5_DELAY_LOOP_CYCLES(0); + + a6xx_gpu->preempt_postamble_len = count; + + a6xx_gpu->postamble_enabled = true; +} + +static void preempt_disable_postamble(struct a6xx_gpu *a6xx_gpu) +{ + u32 *postamble = a6xx_gpu->preempt_postamble_ptr; + + /* + * Disable the postamble by replacing the first packet header with a NOP + * that covers the whole buffer. + */ + *postamble = PKT7(CP_NOP, (a6xx_gpu->preempt_postamble_len - 1)); + + a6xx_gpu->postamble_enabled = false; +} + +void a6xx_preempt_irq(struct msm_gpu *gpu) +{ + uint32_t status; + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + struct drm_device *dev = gpu->dev; + + if (!try_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED, PREEMPT_PENDING)) + return; + + /* Delete the preemption watchdog timer */ + del_timer(&a6xx_gpu->preempt_timer); + + /* + * The hardware should be setting the stop bit of CP_CONTEXT_SWITCH_CNTL + * to zero before firing the interrupt, but there is a non zero chance + * of a hardware condition or a software race that could set it again + * before we have a chance to finish. If that happens, log and go for + * recovery + */ + status = gpu_read(gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL); + if (unlikely(status & A6XX_CP_CONTEXT_SWITCH_CNTL_STOP)) { + DRM_DEV_ERROR(&gpu->pdev->dev, + "!!!!!!!!!!!!!!!! preemption faulted !!!!!!!!!!!!!! irq\n"); + set_preempt_state(a6xx_gpu, PREEMPT_FAULTED); + dev_err(dev->dev, "%s: Preemption failed to complete\n", + gpu->name); + kthread_queue_work(gpu->worker, &gpu->recover_work); + return; + } + + a6xx_gpu->cur_ring = a6xx_gpu->next_ring; + a6xx_gpu->next_ring = NULL; + + set_preempt_state(a6xx_gpu, PREEMPT_FINISH); + + update_wptr(gpu, a6xx_gpu->cur_ring); + + set_preempt_state(a6xx_gpu, PREEMPT_NONE); + + trace_msm_gpu_preemption_irq(a6xx_gpu->cur_ring->id); + + /* + * Retrigger preemption to avoid a deadlock that might occur when preemption + * is skipped due to it being already in flight when requested. + */ + a6xx_preempt_trigger(gpu); +} + +void a6xx_preempt_hw_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + int i; + + /* No preemption if we only have one ring */ + if (gpu->nr_rings == 1) + return; + + for (i = 0; i < gpu->nr_rings; i++) { + struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[i]; + + record_ptr->wptr = 0; + record_ptr->rptr = 0; + record_ptr->rptr_addr = shadowptr(a6xx_gpu, gpu->rb[i]); + record_ptr->info = 0; + record_ptr->data = 0; + record_ptr->rbase = gpu->rb[i]->iova; + } + + /* Write a 0 to signal that we aren't switching pagetables */ + gpu_write64(gpu, REG_A6XX_CP_CONTEXT_SWITCH_SMMU_INFO, 0); + + /* Enable the GMEM save/restore feature for preemption */ + gpu_write(gpu, REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x1); + + /* Reset the preemption state */ + set_preempt_state(a6xx_gpu, PREEMPT_NONE); + + spin_lock_init(&a6xx_gpu->eval_lock); + + /* Always come up on rb 0 */ + a6xx_gpu->cur_ring = gpu->rb[0]; +} + +void a6xx_preempt_trigger(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + unsigned long flags; + struct msm_ringbuffer *ring; + unsigned int cntl; + bool sysprof; + + if (gpu->nr_rings == 1) + return; + + /* + * Lock to make sure another thread attempting preemption doesn't skip it + * while we are still evaluating the next ring. This makes sure the other + * thread does start preemption if we abort it and avoids a soft lock. + */ + spin_lock_irqsave(&a6xx_gpu->eval_lock, flags); + + /* + * Try to start preemption by moving from NONE to START. If + * unsuccessful, a preemption is already in flight + */ + if (!try_preempt_state(a6xx_gpu, PREEMPT_NONE, PREEMPT_START)) { + spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); + return; + } + + cntl = A6XX_CP_CONTEXT_SWITCH_CNTL_LEVEL(a6xx_gpu->preempt_level); + + if (a6xx_gpu->skip_save_restore) + cntl |= A6XX_CP_CONTEXT_SWITCH_CNTL_SKIP_SAVE_RESTORE; + + if (a6xx_gpu->uses_gmem) + cntl |= A6XX_CP_CONTEXT_SWITCH_CNTL_USES_GMEM; + + cntl |= A6XX_CP_CONTEXT_SWITCH_CNTL_STOP; + + /* Get the next ring to preempt to */ + ring = get_next_ring(gpu); + + /* + * If no ring is populated or the highest priority ring is the current + * one do nothing except to update the wptr to the latest and greatest + */ + if (!ring || (a6xx_gpu->cur_ring == ring)) { + set_preempt_state(a6xx_gpu, PREEMPT_FINISH); + update_wptr(gpu, a6xx_gpu->cur_ring); + set_preempt_state(a6xx_gpu, PREEMPT_NONE); + spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); + return; + } + + spin_unlock_irqrestore(&a6xx_gpu->eval_lock, flags); + + spin_lock_irqsave(&ring->preempt_lock, flags); + + struct a7xx_cp_smmu_info *smmu_info_ptr = + a6xx_gpu->preempt_smmu[ring->id]; + struct a6xx_preempt_record *record_ptr = a6xx_gpu->preempt[ring->id]; + u64 ttbr0 = ring->memptrs->ttbr0; + u32 context_idr = ring->memptrs->context_idr; + + smmu_info_ptr->ttbr0 = ttbr0; + smmu_info_ptr->context_idr = context_idr; + record_ptr->wptr = get_wptr(ring); + + /* + * The GPU will write the wptr we set above when we preempt. Reset + * restore_wptr to make sure that we don't write WPTR to the same + * thing twice. It's still possible subsequent submissions will update + * wptr again, in which case they will set the flag to true. This has + * to be protected by the lock for setting the flag and updating wptr + * to be atomic. + */ + ring->restore_wptr = false; + + trace_msm_gpu_preemption_trigger(a6xx_gpu->cur_ring->id, ring->id); + + spin_unlock_irqrestore(&ring->preempt_lock, flags); + + gpu_write64(gpu, + REG_A6XX_CP_CONTEXT_SWITCH_SMMU_INFO, + a6xx_gpu->preempt_smmu_iova[ring->id]); + + gpu_write64(gpu, + REG_A6XX_CP_CONTEXT_SWITCH_PRIV_NON_SECURE_RESTORE_ADDR, + a6xx_gpu->preempt_iova[ring->id]); + + a6xx_gpu->next_ring = ring; + + /* Start a timer to catch a stuck preemption */ + mod_timer(&a6xx_gpu->preempt_timer, jiffies + msecs_to_jiffies(10000)); + + /* Enable or disable postamble as needed */ + sysprof = refcount_read(&a6xx_gpu->base.base.sysprof_active) > 1; + + if (!sysprof && !a6xx_gpu->postamble_enabled) + preempt_prepare_postamble(a6xx_gpu); + + if (sysprof && a6xx_gpu->postamble_enabled) + preempt_disable_postamble(a6xx_gpu); + + /* Set the preemption state to triggered */ + set_preempt_state(a6xx_gpu, PREEMPT_TRIGGERED); + + /* Trigger the preemption */ + gpu_write(gpu, REG_A6XX_CP_CONTEXT_SWITCH_CNTL, cntl); +} + +static int preempt_init_ring(struct a6xx_gpu *a6xx_gpu, + struct msm_ringbuffer *ring) +{ + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + struct msm_gpu *gpu = &adreno_gpu->base; + struct drm_gem_object *bo = NULL; + phys_addr_t ttbr; + u64 iova = 0; + void *ptr; + int asid; + + ptr = msm_gem_kernel_new(gpu->dev, + PREEMPT_RECORD_SIZE(adreno_gpu), + MSM_BO_WC | MSM_BO_MAP_PRIV, gpu->aspace, &bo, &iova); + + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + + memset(ptr, 0, PREEMPT_RECORD_SIZE(adreno_gpu)); + + msm_gem_object_set_name(bo, "preempt_record ring%d", ring->id); + + a6xx_gpu->preempt_bo[ring->id] = bo; + a6xx_gpu->preempt_iova[ring->id] = iova; + a6xx_gpu->preempt[ring->id] = ptr; + + struct a6xx_preempt_record *record_ptr = ptr; + + ptr = msm_gem_kernel_new(gpu->dev, + PREEMPT_SMMU_INFO_SIZE, + MSM_BO_WC | MSM_BO_MAP_PRIV | MSM_BO_GPU_READONLY, + gpu->aspace, &bo, &iova); + + if (IS_ERR(ptr)) + return PTR_ERR(ptr); + + memset(ptr, 0, PREEMPT_SMMU_INFO_SIZE); + + msm_gem_object_set_name(bo, "preempt_smmu_info ring%d", ring->id); + + a6xx_gpu->preempt_smmu_bo[ring->id] = bo; + a6xx_gpu->preempt_smmu_iova[ring->id] = iova; + a6xx_gpu->preempt_smmu[ring->id] = ptr; + + struct a7xx_cp_smmu_info *smmu_info_ptr = ptr; + + msm_iommu_pagetable_params(gpu->aspace->mmu, &ttbr, &asid); + + smmu_info_ptr->magic = GEN7_CP_SMMU_INFO_MAGIC; + smmu_info_ptr->ttbr0 = ttbr; + smmu_info_ptr->asid = 0xdecafbad; + smmu_info_ptr->context_idr = 0; + + /* Set up the defaults on the preemption record */ + record_ptr->magic = A6XX_PREEMPT_RECORD_MAGIC; + record_ptr->info = 0; + record_ptr->data = 0; + record_ptr->rptr = 0; + record_ptr->wptr = 0; + record_ptr->cntl = MSM_GPU_RB_CNTL_DEFAULT; + record_ptr->rbase = ring->iova; + record_ptr->counter = 0; + record_ptr->bv_rptr_addr = rbmemptr(ring, bv_rptr); + + return 0; +} + +void a6xx_preempt_fini(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + int i; + + for (i = 0; i < gpu->nr_rings; i++) + msm_gem_kernel_put(a6xx_gpu->preempt_bo[i], gpu->aspace); +} + +void a6xx_preempt_init(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); + int i; + + /* No preemption if we only have one ring */ + if (gpu->nr_rings <= 1) + return; + + for (i = 0; i < gpu->nr_rings; i++) { + if (preempt_init_ring(a6xx_gpu, gpu->rb[i])) + goto fail; + } + + /* TODO: make this configurable? */ + a6xx_gpu->preempt_level = 1; + a6xx_gpu->uses_gmem = 1; + a6xx_gpu->skip_save_restore = 1; + + a6xx_gpu->preempt_postamble_ptr = msm_gem_kernel_new(gpu->dev, + PAGE_SIZE, + MSM_BO_WC | MSM_BO_MAP_PRIV | MSM_BO_GPU_READONLY, + gpu->aspace, &a6xx_gpu->preempt_postamble_bo, + &a6xx_gpu->preempt_postamble_iova); + + preempt_prepare_postamble(a6xx_gpu); + + if (IS_ERR(a6xx_gpu->preempt_postamble_ptr)) + goto fail; + + timer_setup(&a6xx_gpu->preempt_timer, a6xx_preempt_timer, 0); + + return; +fail: + /* + * On any failure our adventure is over. Clean up and + * set nr_rings to 1 to force preemption off + */ + a6xx_preempt_fini(gpu); + gpu->nr_rings = 1; + + DRM_DEV_ERROR(&gpu->pdev->dev, + "preemption init failed, disabling preemption\n"); + + return; +} diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index cfc74a9e2646d3..236b25c094cd5d 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -20,6 +20,10 @@ bool allow_vram_carveout = false; MODULE_PARM_DESC(allow_vram_carveout, "Allow using VRAM Carveout, in place of IOMMU"); module_param_named(allow_vram_carveout, allow_vram_carveout, bool, 0600); +int enable_preemption = -1; +MODULE_PARM_DESC(enable_preemption, "Enable preemption (A7xx only) (1=on , 0=disable, -1=auto (default))"); +module_param(enable_preemption, int, 0600); + extern const struct adreno_gpulist a2xx_gpulist; extern const struct adreno_gpulist a3xx_gpulist; extern const struct adreno_gpulist a4xx_gpulist; @@ -389,7 +393,7 @@ static const struct dev_pm_ops adreno_pm_ops = { static struct platform_driver adreno_driver = { .probe = adreno_probe, - .remove_new = adreno_remove, + .remove = adreno_remove, .shutdown = adreno_shutdown, .driver = { .name = "adreno", diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 465a4cd14a435b..75f5367e73caac 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -533,7 +533,7 @@ int adreno_load_fw(struct adreno_gpu *adreno_gpu) if (!adreno_gpu->info->fw[i]) continue; - /* Skip loading GMU firwmare with GMU Wrapper */ + /* Skip loading GMU firmware with GMU Wrapper */ if (adreno_has_gmu_wrapper(adreno_gpu) && i == ADRENO_FW_GMU) continue; @@ -572,8 +572,19 @@ struct drm_gem_object *adreno_fw_create_bo(struct msm_gpu *gpu, int adreno_hw_init(struct msm_gpu *gpu) { + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + int ret; + VERB("%s", gpu->name); + if (adreno_gpu->info->family >= ADRENO_6XX_GEN1 && + qcom_scm_set_gpu_smmu_aperture_is_available()) { + /* We currently always use context bank 0, so hard code this */ + ret = qcom_scm_set_gpu_smmu_aperture(0); + if (ret) + DRM_DEV_ERROR(gpu->dev->dev, "unable to set SMMU aperture: %d\n", ret); + } + for (int i = 0; i < gpu->nr_rings; i++) { struct msm_ringbuffer *ring = gpu->rb[i]; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 58d7e7915c5758..e71f420f8b3a8e 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -56,6 +56,7 @@ enum adreno_family { #define ADRENO_QUIRK_LMLOADKILL_DISABLE BIT(2) #define ADRENO_QUIRK_HAS_HW_APRIV BIT(3) #define ADRENO_QUIRK_HAS_CACHED_COHERENT BIT(4) +#define ADRENO_QUIRK_PREEMPTION BIT(5) /* Helper for formating the chip_id in the way that userspace tools like * crashdec expect. @@ -111,6 +112,7 @@ struct adreno_info { * {SHRT_MAX, 0} sentinal. */ struct adreno_speedbin *speedbins; + u64 preempt_record_size; }; #define ADRENO_CHIP_IDS(tbl...) (uint32_t[]) { tbl, 0 } @@ -156,6 +158,19 @@ static const struct adreno_protect name = { \ .count_max = __count_max, \ }; +struct adreno_reglist_list { + /** @reg: List of register **/ + const u32 *regs; + /** @count: Number of registers in the list **/ + u32 count; +}; + +#define DECLARE_ADRENO_REGLIST_LIST(name) \ +static const struct adreno_reglist_list name = { \ + .regs = name ## _regs, \ + .count = ARRAY_SIZE(name ## _regs), \ +}; + struct adreno_gpu { struct msm_gpu base; const struct adreno_info *info; @@ -455,6 +470,11 @@ static inline int adreno_is_a680(const struct adreno_gpu *gpu) return adreno_is_revn(gpu, 680); } +static inline int adreno_is_a663(const struct adreno_gpu *gpu) +{ + return gpu->info->chip_ids[0] == 0x06060300; +} + static inline int adreno_is_a690(const struct adreno_gpu *gpu) { return gpu->info->chip_ids[0] == 0x06090000; @@ -656,12 +676,15 @@ OUT_PKT4(struct msm_ringbuffer *ring, uint16_t regindx, uint16_t cnt) OUT_RING(ring, PKT4(regindx, cnt)); } +#define PKT7(opcode, cnt) \ + (CP_TYPE7_PKT | (cnt << 0) | (PM4_PARITY(cnt) << 15) | \ + ((opcode & 0x7F) << 16) | (PM4_PARITY(opcode) << 23)) + static inline void OUT_PKT7(struct msm_ringbuffer *ring, uint8_t opcode, uint16_t cnt) { adreno_wait_ring(ring, cnt + 1); - OUT_RING(ring, CP_TYPE7_PKT | (cnt << 0) | (PM4_PARITY(cnt) << 15) | - ((opcode & 0x7F) << 16) | (PM4_PARITY(opcode) << 23)); + OUT_RING(ring, PKT7(opcode, cnt)); } struct msm_gpu *a2xx_gpu_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_14_msm8937.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_14_msm8937.h new file mode 100644 index 00000000000000..ab3dfb0b374ead --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_14_msm8937.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef _DPU_1_14_MSM8937_H +#define _DPU_1_14_MSM8937_H + +static const struct dpu_caps msm8937_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_LINE_WIDTH, + .max_mixer_blendstages = 0x4, + .max_linewidth = DEFAULT_DPU_LINE_WIDTH, + .pixel_ram_size = 40 * 1024, + .max_hdeci_exp = MAX_HORZ_DECIMATION, + .max_vdeci_exp = MAX_VERT_DECIMATION, +}; + +static const struct dpu_mdp_cfg msm8937_mdp[] = { + { + .name = "top_0", + .base = 0x0, .len = 0x454, + .features = BIT(DPU_MDP_VSYNC_SEL), + .clk_ctrls = { + [DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0 }, + [DPU_CLK_CTRL_RGB0] = { .reg_off = 0x2ac, .bit_off = 4 }, + [DPU_CLK_CTRL_RGB1] = { .reg_off = 0x2b4, .bit_off = 4 }, + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_CURSOR0] = { .reg_off = 0x3a8, .bit_off = 16 }, + }, + }, +}; + +static const struct dpu_ctl_cfg msm8937_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0x64, + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0x64, + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0x64, + }, +}; + +static const struct dpu_sspp_cfg msm8937_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x150, + .features = VIG_MSM8953_MASK, + .sblk = &dpu_vig_sblk_qseed2, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_4", .id = SSPP_RGB0, + .base = 0x14000, .len = 0x150, + .features = RGB_MSM8953_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 1, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB0, + }, { + .name = "sspp_5", .id = SSPP_RGB1, + .base = 0x16000, .len = 0x150, + .features = RGB_MSM8953_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 5, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB1, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x150, + .features = DMA_MSM8953_MASK | BIT(DPU_SSPP_CURSOR), + .sblk = &dpu_dma_sblk, + .xin_id = 2, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA0, + }, +}; + +static const struct dpu_lm_cfg msm8937_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x320, + .sblk = &msm8998_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x320, + .sblk = &msm8998_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + }, +}; + +static const struct dpu_pingpong_cfg msm8937_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x70000, .len = 0xd4, + .features = PINGPONG_MSM8996_MASK, + .sblk = &msm8996_pp_sblk, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x70800, .len = 0xd4, + .features = PINGPONG_MSM8996_MASK, + .sblk = &msm8996_pp_sblk, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13), + }, +}; + +static const struct dpu_dspp_cfg msm8937_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &msm8998_dspp_sblk, + }, +}; + +static const struct dpu_intf_cfg msm8937_intf[] = { + { + .name = "intf_1", .id = INTF_1, + .base = 0x6a800, .len = 0x268, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 14, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = -1, + }, { + .name = "intf_2", .id = INTF_2, + .base = 0x6b000, .len = 0x268, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_1, + .prog_fetch_lines_worst_case = 14, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 28), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 29), + .intr_tear_rd_ptr = -1, + }, +}; + +static const struct dpu_perf_cfg msm8937_perf_data = { + .max_bw_low = 3100000, + .max_bw_high = 3100000, + .min_core_ib = 2400000, + .min_llcc_ib = 0, /* No LLCC on this SoC */ + .min_dram_ib = 800000, + .undersized_prefill_lines = 2, + .xtra_prefill_lines = 2, + .dest_scale_prefill_lines = 3, + .macrotile_prefill_lines = 4, + .yuv_nv12_prefill_lines = 8, + .linear_prefill_lines = 1, + .downscaling_prefill_lines = 1, + .amortizable_threshold = 25, + .min_prefill_lines = 14, + .danger_lut_tbl = {0xf, 0xffff, 0x0}, + .safe_lut_tbl = {0xfffc, 0xff00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(msm8998_qos_linear), + .entries = msm8998_qos_linear + }, + {.nentry = ARRAY_SIZE(msm8998_qos_macrotile), + .entries = msm8998_qos_macrotile + }, + {.nentry = ARRAY_SIZE(msm8998_qos_nrt), + .entries = msm8998_qos_nrt + }, + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version msm8937_mdss_ver = { + .core_major_ver = 1, + .core_minor_ver = 14, +}; + +const struct dpu_mdss_cfg dpu_msm8937_cfg = { + .mdss_ver = &msm8937_mdss_ver, + .caps = &msm8937_dpu_caps, + .mdp = msm8937_mdp, + .ctl_count = ARRAY_SIZE(msm8937_ctl), + .ctl = msm8937_ctl, + .sspp_count = ARRAY_SIZE(msm8937_sspp), + .sspp = msm8937_sspp, + .mixer_count = ARRAY_SIZE(msm8937_lm), + .mixer = msm8937_lm, + .dspp_count = ARRAY_SIZE(msm8937_dspp), + .dspp = msm8937_dspp, + .pingpong_count = ARRAY_SIZE(msm8937_pp), + .pingpong = msm8937_pp, + .intf_count = ARRAY_SIZE(msm8937_intf), + .intf = msm8937_intf, + .vbif_count = ARRAY_SIZE(msm8996_vbif), + .vbif = msm8996_vbif, + .perf = &msm8937_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_15_msm8917.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_15_msm8917.h new file mode 100644 index 00000000000000..6bdaecca676144 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_15_msm8917.h @@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef _DPU_1_14_MSM8917_H +#define _DPU_1_14_MSM8917_H + +static const struct dpu_caps msm8917_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_LINE_WIDTH, + .max_mixer_blendstages = 0x4, + .max_linewidth = DEFAULT_DPU_LINE_WIDTH, + .pixel_ram_size = 16 * 1024, + .max_hdeci_exp = MAX_HORZ_DECIMATION, + .max_vdeci_exp = MAX_VERT_DECIMATION, +}; + +static const struct dpu_mdp_cfg msm8917_mdp[] = { + { + .name = "top_0", + .base = 0x0, .len = 0x454, + .features = BIT(DPU_MDP_VSYNC_SEL), + .clk_ctrls = { + [DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0 }, + [DPU_CLK_CTRL_RGB0] = { .reg_off = 0x2ac, .bit_off = 4 }, + [DPU_CLK_CTRL_RGB1] = { .reg_off = 0x2b4, .bit_off = 4 }, + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_CURSOR0] = { .reg_off = 0x3a8, .bit_off = 16 }, + }, + }, +}; + +static const struct dpu_ctl_cfg msm8917_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0x64, + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0x64, + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0x64, + }, +}; + +static const struct dpu_sspp_cfg msm8917_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x150, + .features = VIG_MSM8953_MASK, + .sblk = &dpu_vig_sblk_qseed2, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_4", .id = SSPP_RGB0, + .base = 0x14000, .len = 0x150, + .features = RGB_MSM8953_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 1, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB0, + }, { + .name = "sspp_5", .id = SSPP_RGB1, + .base = 0x16000, .len = 0x150, + .features = RGB_MSM8953_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 5, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB1, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x150, + .features = DMA_MSM8953_MASK | BIT(DPU_SSPP_CURSOR), + .sblk = &dpu_dma_sblk, + .xin_id = 2, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA0, + }, +}; + +static const struct dpu_lm_cfg msm8917_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x320, + .sblk = &msm8998_lm_sblk, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, +}; + +static const struct dpu_pingpong_cfg msm8917_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x70000, .len = 0xd4, + .features = PINGPONG_MSM8996_MASK, + .sblk = &msm8996_pp_sblk, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), + }, +}; + +static const struct dpu_dspp_cfg msm8917_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &msm8998_dspp_sblk, + }, +}; + +static const struct dpu_intf_cfg msm8917_intf[] = { + { + .name = "intf_1", .id = INTF_1, + .base = 0x6a800, .len = 0x268, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 14, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = -1, + }, +}; + +static const struct dpu_perf_cfg msm8917_perf_data = { + .max_bw_low = 1800000, + .max_bw_high = 1800000, + .min_core_ib = 2400000, + .min_llcc_ib = 0, /* No LLCC on this SoC */ + .min_dram_ib = 800000, + .undersized_prefill_lines = 2, + .xtra_prefill_lines = 2, + .dest_scale_prefill_lines = 3, + .macrotile_prefill_lines = 4, + .yuv_nv12_prefill_lines = 8, + .linear_prefill_lines = 1, + .downscaling_prefill_lines = 1, + .amortizable_threshold = 25, + .min_prefill_lines = 21, + .danger_lut_tbl = {0xf, 0xffff, 0x0}, + .safe_lut_tbl = {0xfffc, 0xff00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(msm8998_qos_linear), + .entries = msm8998_qos_linear + }, + {.nentry = ARRAY_SIZE(msm8998_qos_macrotile), + .entries = msm8998_qos_macrotile + }, + {.nentry = ARRAY_SIZE(msm8998_qos_nrt), + .entries = msm8998_qos_nrt + }, + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version msm8917_mdss_ver = { + .core_major_ver = 1, + .core_minor_ver = 15, +}; + +const struct dpu_mdss_cfg dpu_msm8917_cfg = { + .mdss_ver = &msm8917_mdss_ver, + .caps = &msm8917_dpu_caps, + .mdp = msm8917_mdp, + .ctl_count = ARRAY_SIZE(msm8917_ctl), + .ctl = msm8917_ctl, + .sspp_count = ARRAY_SIZE(msm8917_sspp), + .sspp = msm8917_sspp, + .mixer_count = ARRAY_SIZE(msm8917_lm), + .mixer = msm8917_lm, + .dspp_count = ARRAY_SIZE(msm8917_dspp), + .dspp = msm8917_dspp, + .pingpong_count = ARRAY_SIZE(msm8917_pp), + .pingpong = msm8917_pp, + .intf_count = ARRAY_SIZE(msm8917_intf), + .intf = msm8917_intf, + .vbif_count = ARRAY_SIZE(msm8996_vbif), + .vbif = msm8996_vbif, + .perf = &msm8917_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h new file mode 100644 index 00000000000000..14f36ea6ad0eb6 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_16_msm8953.h @@ -0,0 +1,218 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef _DPU_1_16_MSM8953_H +#define _DPU_1_16_MSM8953_H + +static const struct dpu_caps msm8953_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_LINE_WIDTH, + .max_mixer_blendstages = 0x4, + .max_linewidth = DEFAULT_DPU_LINE_WIDTH, + .pixel_ram_size = 40 * 1024, + .max_hdeci_exp = MAX_HORZ_DECIMATION, + .max_vdeci_exp = MAX_VERT_DECIMATION, +}; + +static const struct dpu_mdp_cfg msm8953_mdp[] = { + { + .name = "top_0", + .base = 0x0, .len = 0x454, + .features = BIT(DPU_MDP_VSYNC_SEL), + .clk_ctrls = { + [DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0 }, + [DPU_CLK_CTRL_RGB0] = { .reg_off = 0x2ac, .bit_off = 4 }, + [DPU_CLK_CTRL_RGB1] = { .reg_off = 0x2b4, .bit_off = 4 }, + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_CURSOR0] = { .reg_off = 0x3a8, .bit_off = 16 }, + }, + }, +}; + +static const struct dpu_ctl_cfg msm8953_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0x64, + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0x64, + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0x64, + }, +}; + +static const struct dpu_sspp_cfg msm8953_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x150, + .features = VIG_MSM8953_MASK, + .sblk = &dpu_vig_sblk_qseed2, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_4", .id = SSPP_RGB0, + .base = 0x14000, .len = 0x150, + .features = RGB_MSM8953_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 1, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB0, + }, { + .name = "sspp_5", .id = SSPP_RGB1, + .base = 0x16000, .len = 0x150, + .features = RGB_MSM8953_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 5, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB1, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x150, + .features = DMA_MSM8953_MASK | BIT(DPU_SSPP_CURSOR), + .sblk = &dpu_dma_sblk, + .xin_id = 2, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA0, + }, +}; + +static const struct dpu_lm_cfg msm8953_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x320, + .sblk = &msm8998_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x320, + .sblk = &msm8998_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + }, +}; + +static const struct dpu_pingpong_cfg msm8953_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x70000, .len = 0xd4, + .features = PINGPONG_MSM8996_MASK, + .sblk = &msm8996_pp_sblk, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x70800, .len = 0xd4, + .features = PINGPONG_MSM8996_MASK, + .sblk = &msm8996_pp_sblk, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13), + }, +}; + +static const struct dpu_dspp_cfg msm8953_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &msm8998_dspp_sblk, + }, +}; + +static const struct dpu_intf_cfg msm8953_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x6a000, .len = 0x268, + .type = INTF_NONE, + .prog_fetch_lines_worst_case = 14, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), + .intr_tear_rd_ptr = -1, + }, { + .name = "intf_1", .id = INTF_1, + .base = 0x6a800, .len = 0x268, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 14, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = -1, + }, { + .name = "intf_2", .id = INTF_2, + .base = 0x6b000, .len = 0x268, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_1, + .prog_fetch_lines_worst_case = 14, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 28), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 29), + .intr_tear_rd_ptr = -1, + }, +}; + +static const struct dpu_perf_cfg msm8953_perf_data = { + .max_bw_low = 3400000, + .max_bw_high = 3400000, + .min_core_ib = 2400000, + .min_llcc_ib = 0, /* No LLCC on this SoC */ + .min_dram_ib = 800000, + .undersized_prefill_lines = 2, + .xtra_prefill_lines = 2, + .dest_scale_prefill_lines = 3, + .macrotile_prefill_lines = 4, + .yuv_nv12_prefill_lines = 8, + .linear_prefill_lines = 1, + .downscaling_prefill_lines = 1, + .amortizable_threshold = 25, + .min_prefill_lines = 14, + .danger_lut_tbl = {0xf, 0xffff, 0x0}, + .safe_lut_tbl = {0xfffc, 0xff00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(msm8998_qos_linear), + .entries = msm8998_qos_linear + }, + {.nentry = ARRAY_SIZE(msm8998_qos_macrotile), + .entries = msm8998_qos_macrotile + }, + {.nentry = ARRAY_SIZE(msm8998_qos_nrt), + .entries = msm8998_qos_nrt + }, + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version msm8953_mdss_ver = { + .core_major_ver = 1, + .core_minor_ver = 16, +}; + +const struct dpu_mdss_cfg dpu_msm8953_cfg = { + .mdss_ver = &msm8953_mdss_ver, + .caps = &msm8953_dpu_caps, + .mdp = msm8953_mdp, + .ctl_count = ARRAY_SIZE(msm8953_ctl), + .ctl = msm8953_ctl, + .sspp_count = ARRAY_SIZE(msm8953_sspp), + .sspp = msm8953_sspp, + .mixer_count = ARRAY_SIZE(msm8953_lm), + .mixer = msm8953_lm, + .dspp_count = ARRAY_SIZE(msm8953_dspp), + .dspp = msm8953_dspp, + .pingpong_count = ARRAY_SIZE(msm8953_pp), + .pingpong = msm8953_pp, + .intf_count = ARRAY_SIZE(msm8953_intf), + .intf = msm8953_intf, + .vbif_count = ARRAY_SIZE(msm8996_vbif), + .vbif = msm8996_vbif, + .perf = &msm8953_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_7_msm8996.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_7_msm8996.h new file mode 100644 index 00000000000000..491f6f5827d151 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_1_7_msm8996.h @@ -0,0 +1,338 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023, Linaro Limited + * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _DPU_1_7_MSM8996_H +#define _DPU_1_7_MSM8996_H + +static const struct dpu_caps msm8996_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0x7, + .has_src_split = true, + .max_linewidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, + .max_hdeci_exp = MAX_HORZ_DECIMATION, + .max_vdeci_exp = MAX_VERT_DECIMATION, +}; + +static const struct dpu_mdp_cfg msm8996_mdp[] = { + { + .name = "top_0", + .base = 0x0, .len = 0x454, + .features = BIT(DPU_MDP_VSYNC_SEL), + .clk_ctrls = { + [DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0 }, + [DPU_CLK_CTRL_VIG1] = { .reg_off = 0x2b4, .bit_off = 0 }, + [DPU_CLK_CTRL_VIG2] = { .reg_off = 0x2bc, .bit_off = 0 }, + [DPU_CLK_CTRL_VIG3] = { .reg_off = 0x2c4, .bit_off = 0 }, + [DPU_CLK_CTRL_RGB0] = { .reg_off = 0x2ac, .bit_off = 4 }, + [DPU_CLK_CTRL_RGB1] = { .reg_off = 0x2b4, .bit_off = 4 }, + [DPU_CLK_CTRL_RGB2] = { .reg_off = 0x2bc, .bit_off = 4 }, + [DPU_CLK_CTRL_RGB3] = { .reg_off = 0x2c4, .bit_off = 4 }, + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, + [DPU_CLK_CTRL_CURSOR0] = { .reg_off = 0x3a8, .bit_off = 16 }, + [DPU_CLK_CTRL_CURSOR1] = { .reg_off = 0x3b0, .bit_off = 16 }, + }, + }, +}; + +static const struct dpu_ctl_cfg msm8996_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x1000, .len = 0x64, + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x1200, .len = 0x64, + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x1400, .len = 0x64, + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x1600, .len = 0x64, + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x1800, .len = 0x64, + }, +}; + +static const struct dpu_sspp_cfg msm8996_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x150, + .features = VIG_MSM8996_MASK, + .sblk = &dpu_vig_sblk_qseed2, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x150, + .features = VIG_MSM8996_MASK, + .sblk = &dpu_vig_sblk_qseed2, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG1, + }, { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x150, + .features = VIG_MSM8996_MASK, + .sblk = &dpu_vig_sblk_qseed2, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG2, + }, { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x150, + .features = VIG_MSM8996_MASK, + .sblk = &dpu_vig_sblk_qseed2, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG3, + }, { + .name = "sspp_4", .id = SSPP_RGB0, + .base = 0x14000, .len = 0x150, + .features = RGB_MSM8996_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 1, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB0, + }, { + .name = "sspp_5", .id = SSPP_RGB1, + .base = 0x16000, .len = 0x150, + .features = RGB_MSM8996_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 5, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB1, + }, { + .name = "sspp_6", .id = SSPP_RGB2, + .base = 0x18000, .len = 0x150, + .features = RGB_MSM8996_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 9, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB2, + }, { + .name = "sspp_7", .id = SSPP_RGB3, + .base = 0x1a000, .len = 0x150, + .features = RGB_MSM8996_MASK, + .sblk = &dpu_rgb_sblk, + .xin_id = 13, + .type = SSPP_TYPE_RGB, + .clk_ctrl = DPU_CLK_CTRL_RGB3, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x150, + .features = DMA_MSM8996_MASK, + .sblk = &dpu_dma_sblk, + .xin_id = 2, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA0, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x150, + .features = DMA_MSM8996_MASK, + .sblk = &dpu_dma_sblk, + .xin_id = 10, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA1, + }, +}; + +static const struct dpu_lm_cfg msm8996_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x320, + .features = MIXER_MSM8998_MASK, + .sblk = &msm8998_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x320, + .features = MIXER_MSM8998_MASK, + .sblk = &msm8998_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + .dspp = DSPP_1, + }, { + .name = "lm_2", .id = LM_2, + .base = 0x46000, .len = 0x320, + .features = MIXER_MSM8998_MASK, + .sblk = &msm8998_lm_sblk, + .lm_pair = LM_5, + .pingpong = PINGPONG_2, + }, { + .name = "lm_5", .id = LM_5, + .base = 0x49000, .len = 0x320, + .features = MIXER_MSM8998_MASK, + .sblk = &msm8998_lm_sblk, + .lm_pair = LM_2, + .pingpong = PINGPONG_3, + }, +}; + +static const struct dpu_pingpong_cfg msm8996_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x70000, .len = 0xd4, + .features = PINGPONG_MSM8996_TE2_MASK, + .sblk = &msm8996_pp_sblk_te, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x70800, .len = 0xd4, + .features = PINGPONG_MSM8996_TE2_MASK, + .sblk = &msm8996_pp_sblk_te, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13), + }, { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x71000, .len = 0xd4, + .features = PINGPONG_MSM8996_MASK, + .sblk = &msm8996_pp_sblk, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 14), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x71800, .len = 0xd4, + .features = PINGPONG_MSM8996_MASK, + .sblk = &msm8996_pp_sblk, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + .intr_rdptr = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 15), + }, +}; + +static const struct dpu_dsc_cfg msm8996_dsc[] = { + { + .name = "dsc_0", .id = DSC_0, + .base = 0x80000, .len = 0x140, + }, { + .name = "dsc_1", .id = DSC_1, + .base = 0x80400, .len = 0x140, + }, +}; + +static const struct dpu_dspp_cfg msm8996_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &msm8998_dspp_sblk, + }, { + .name = "dspp_1", .id = DSPP_1, + .base = 0x56000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &msm8998_dspp_sblk, + }, +}; + +static const struct dpu_intf_cfg msm8996_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x6a000, .len = 0x268, + .type = INTF_NONE, + .prog_fetch_lines_worst_case = 25, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), + .intr_tear_rd_ptr = -1, + }, { + .name = "intf_1", .id = INTF_1, + .base = 0x6a800, .len = 0x268, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 25, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = -1, + }, { + .name = "intf_2", .id = INTF_2, + .base = 0x6b000, .len = 0x268, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_1, + .prog_fetch_lines_worst_case = 25, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 28), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 29), + .intr_tear_rd_ptr = -1, + }, { + .name = "intf_3", .id = INTF_3, + .base = 0x6b800, .len = 0x268, + .type = INTF_HDMI, + .prog_fetch_lines_worst_case = 25, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), + .intr_tear_rd_ptr = -1, + }, +}; + +static const struct dpu_perf_cfg msm8996_perf_data = { + .max_bw_low = 9600000, + .max_bw_high = 9600000, + .min_core_ib = 2400000, + .min_llcc_ib = 0, /* No LLCC on this SoC */ + .min_dram_ib = 800000, + .undersized_prefill_lines = 2, + .xtra_prefill_lines = 2, + .dest_scale_prefill_lines = 3, + .macrotile_prefill_lines = 4, + .yuv_nv12_prefill_lines = 8, + .linear_prefill_lines = 1, + .downscaling_prefill_lines = 1, + .amortizable_threshold = 25, + .min_prefill_lines = 21, + .danger_lut_tbl = {0xf, 0xffff, 0x0}, + .safe_lut_tbl = {0xfffc, 0xff00, 0xffff}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(msm8998_qos_linear), + .entries = msm8998_qos_linear + }, + {.nentry = ARRAY_SIZE(msm8998_qos_macrotile), + .entries = msm8998_qos_macrotile + }, + {.nentry = ARRAY_SIZE(msm8998_qos_nrt), + .entries = msm8998_qos_nrt + }, + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version msm8996_mdss_ver = { + .core_major_ver = 1, + .core_minor_ver = 7, +}; + +const struct dpu_mdss_cfg dpu_msm8996_cfg = { + .mdss_ver = &msm8996_mdss_ver, + .caps = &msm8996_dpu_caps, + .mdp = msm8996_mdp, + .ctl_count = ARRAY_SIZE(msm8996_ctl), + .ctl = msm8996_ctl, + .sspp_count = ARRAY_SIZE(msm8996_sspp), + .sspp = msm8996_sspp, + .mixer_count = ARRAY_SIZE(msm8996_lm), + .mixer = msm8996_lm, + .dspp_count = ARRAY_SIZE(msm8996_dspp), + .dspp = msm8996_dspp, + .pingpong_count = ARRAY_SIZE(msm8996_pp), + .pingpong = msm8996_pp, + .dsc_count = ARRAY_SIZE(msm8996_dsc), + .dsc = msm8996_dsc, + .intf_count = ARRAY_SIZE(msm8996_intf), + .intf = msm8996_intf, + .vbif_count = ARRAY_SIZE(msm8996_vbif), + .vbif = msm8996_vbif, + .perf = &msm8996_perf_data, +}; + +#endif 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 1d3e9666c7411e..64c94e919a6980 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 @@ -156,18 +156,6 @@ static const struct dpu_lm_cfg msm8998_lm[] = { .sblk = &msm8998_lm_sblk, .lm_pair = LM_5, .pingpong = PINGPONG_2, - }, { - .name = "lm_3", .id = LM_3, - .base = 0x47000, .len = 0x320, - .features = MIXER_MSM8998_MASK, - .sblk = &msm8998_lm_sblk, - .pingpong = PINGPONG_NONE, - }, { - .name = "lm_4", .id = LM_4, - .base = 0x48000, .len = 0x320, - .features = MIXER_MSM8998_MASK, - .sblk = &msm8998_lm_sblk, - .pingpong = PINGPONG_NONE, }, { .name = "lm_5", .id = LM_5, .base = 0x49000, .len = 0x320, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h index 7a23389a573272..72bd4f7e9e504c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h @@ -155,19 +155,6 @@ static const struct dpu_lm_cfg sdm845_lm[] = { .lm_pair = LM_5, .pingpong = PINGPONG_2, .dspp = DSPP_2, - }, { - .name = "lm_3", .id = LM_3, - .base = 0x0, .len = 0x320, - .features = MIXER_SDM845_MASK, - .sblk = &sdm845_lm_sblk, - .pingpong = PINGPONG_NONE, - .dspp = DSPP_3, - }, { - .name = "lm_4", .id = LM_4, - .base = 0x0, .len = 0x320, - .features = MIXER_SDM845_MASK, - .sblk = &sdm845_lm_sblk, - .pingpong = PINGPONG_NONE, }, { .name = "lm_5", .id = LM_5, .base = 0x49000, .len = 0x320, @@ -175,6 +162,7 @@ static const struct dpu_lm_cfg sdm845_lm[] = { .sblk = &sdm845_lm_sblk, .lm_pair = LM_2, .pingpong = PINGPONG_3, + .dspp = DSPP_3, }, }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h new file mode 100644 index 00000000000000..907b4d7ceb470b --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_4_sa8775p.h @@ -0,0 +1,485 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _DPU_8_4_SA8775P_H +#define _DPU_8_4_SA8775P_H + +static const struct dpu_caps sa8775p_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 5120, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + +static const struct dpu_mdp_cfg sa8775p_mdp = { + .name = "top_0", + .base = 0x0, .len = 0x494, + .features = BIT(DPU_MDP_PERIPH_0_REMOVED), + .clk_ctrls = { + [DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0 }, + [DPU_CLK_CTRL_VIG1] = { .reg_off = 0x2b4, .bit_off = 0 }, + [DPU_CLK_CTRL_VIG2] = { .reg_off = 0x2bc, .bit_off = 0 }, + [DPU_CLK_CTRL_VIG3] = { .reg_off = 0x2c4, .bit_off = 0 }, + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, + }, +}; + +/* FIXME: get rid of DPU_CTL_SPLIT_DISPLAY in favour of proper ACTIVE_CTL support */ +static const struct dpu_ctl_cfg sa8775p_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x204, + .features = BIT(DPU_CTL_SPLIT_DISPLAY) | CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 9), + }, { + .name = "ctl_1", .id = CTL_1, + .base = 0x16000, .len = 0x204, + .features = BIT(DPU_CTL_SPLIT_DISPLAY) | CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 10), + }, { + .name = "ctl_2", .id = CTL_2, + .base = 0x17000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x204, + .features = CTL_SC7280_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + +static const struct dpu_sspp_cfg sa8775p_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x32c, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_1, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x32c, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_1, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG1, + }, { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x32c, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_1, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG2, + }, { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x32c, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_1, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG3, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x32c, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA0, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x32c, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA1, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0x28000, .len = 0x32c, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA2, + }, { + .name = "sspp_11", .id = SSPP_DMA3, + .base = 0x2a000, .len = 0x32c, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 13, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA3, + }, +}; + +static const struct dpu_lm_cfg sa8775p_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + .dspp = DSPP_1, + }, { + .name = "lm_2", .id = LM_2, + .base = 0x46000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_3, + .pingpong = PINGPONG_2, + .dspp = DSPP_2, + }, { + .name = "lm_3", .id = LM_3, + .base = 0x47000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_2, + .pingpong = PINGPONG_3, + .dspp = DSPP_3, + }, { + .name = "lm_4", .id = LM_4, + .base = 0x48000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_5, + .pingpong = PINGPONG_4, + }, { + .name = "lm_5", .id = LM_5, + .base = 0x49000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_4, + .pingpong = PINGPONG_5, + }, +}; + +static const struct dpu_dspp_cfg sa8775p_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_1", .id = DSPP_1, + .base = 0x56000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_2", .id = DSPP_2, + .base = 0x58000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_3", .id = DSPP_3, + .base = 0x5a000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, +}; + +static const struct dpu_pingpong_cfg sa8775p_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x69000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x6a000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + }, { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x6b000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, { + .name = "pingpong_4", .id = PINGPONG_4, + .base = 0x6d000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + }, { + .name = "pingpong_5", .id = PINGPONG_5, + .base = 0x6e000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + }, { + .name = "pingpong_6", .id = PINGPONG_6, + .base = 0x65800, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + }, { + .name = "pingpong_7", .id = PINGPONG_7, + .base = 0x65c00, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + }, +}; + +static const struct dpu_merge_3d_cfg sa8775p_merge_3d[] = { + { + .name = "merge_3d_0", .id = MERGE_3D_0, + .base = 0x4e000, .len = 0x8, + }, { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x4f000, .len = 0x8, + }, { + .name = "merge_3d_2", .id = MERGE_3D_2, + .base = 0x50000, .len = 0x8, + }, { + .name = "merge_3d_3", .id = MERGE_3D_3, + .base = 0x65f00, .len = 0x8, + }, +}; + +/* + * NOTE: Each display compression engine (DCE) contains dual hard + * slice DSC encoders so both share same base address but with + * its own different sub block address. + */ +static const struct dpu_dsc_cfg sa8775p_dsc[] = { + { + .name = "dce_0_0", .id = DSC_0, + .base = 0x80000, .len = 0x4, + .features = BIT(DPU_DSC_HW_REV_1_2), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_0_1", .id = DSC_1, + .base = 0x80000, .len = 0x4, + .features = BIT(DPU_DSC_HW_REV_1_2), + .sblk = &dsc_sblk_1, + }, { + .name = "dce_1_0", .id = DSC_2, + .base = 0x81000, .len = 0x4, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_1_1", .id = DSC_3, + .base = 0x81000, .len = 0x4, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_1, + }, { + .name = "dce_2_0", .id = DSC_4, + .base = 0x82000, .len = 0x4, + .features = BIT(DPU_DSC_HW_REV_1_2), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_2_1", .id = DSC_5, + .base = 0x82000, .len = 0x4, + .features = BIT(DPU_DSC_HW_REV_1_2), + .sblk = &dsc_sblk_1, + }, +}; + +static const struct dpu_wb_cfg sa8775p_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SM8250_MASK, + .format_list = wb2_formats_rgb_yuv, + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), + .clk_ctrl = DPU_CLK_CTRL_WB2, + .xin_id = 6, + .vbif_idx = VBIF_RT, + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + +/* TODO: INTF 3, 6, 7 and 8 are used for MST, marked as INTF_NONE for now */ +static const struct dpu_intf_cfg sa8775p_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x34000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), + }, { + .name = "intf_1", .id = INTF_1, + .base = 0x35000, .len = 0x300, + .features = INTF_SC7280_MASK, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF1_TEAR_INTR, 2), + }, { + .name = "intf_2", .id = INTF_2, + .base = 0x36000, .len = 0x300, + .features = INTF_SC7280_MASK, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 28), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 29), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF2_TEAR_INTR, 2), + }, { + .name = "intf_3", .id = INTF_3, + .base = 0x37000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_NONE, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), + }, { + .name = "intf_4", .id = INTF_4, + .base = 0x38000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 20), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 21), + }, { + .name = "intf_6", .id = INTF_6, + .base = 0x3A000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_NONE, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 17), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 16), + }, { + .name = "intf_7", .id = INTF_7, + .base = 0x3b000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_NONE, + .controller_id = MSM_DP_CONTROLLER_0, /* pair with intf_0 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 18), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 19), + }, { + .name = "intf_8", .id = INTF_8, + .base = 0x3c000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_NONE, + .controller_id = MSM_DP_CONTROLLER_1, /* pair with intf_4 for DP MST */ + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 12), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 13), + }, +}; + +static const struct dpu_perf_cfg sa8775p_perf_data = { + .max_bw_low = 13600000, + .max_bw_high = 18200000, + .min_core_ib = 2500000, + .min_llcc_ib = 0, + .min_dram_ib = 800000, + .min_prefill_lines = 35, + /* FIXME: lut tables */ + .danger_lut_tbl = {0x3ffff, 0x3ffff, 0x0}, + .safe_lut_tbl = {0xfff0, 0xfff0, 0x1}, + .qos_lut_tbl = { + {.nentry = ARRAY_SIZE(sm6350_qos_linear_macrotile), + .entries = sm6350_qos_linear_macrotile + }, + {.nentry = ARRAY_SIZE(sm6350_qos_linear_macrotile), + .entries = sm6350_qos_linear_macrotile + }, + {.nentry = ARRAY_SIZE(sc7180_qos_nrt), + .entries = sc7180_qos_nrt + }, + /* TODO: macrotile-qseed is different from macrotile */ + }, + .cdp_cfg = { + {.rd_enable = 1, .wr_enable = 1}, + {.rd_enable = 1, .wr_enable = 0} + }, + .clk_inefficiency_factor = 105, + .bw_inefficiency_factor = 120, +}; + +static const struct dpu_mdss_version sa8775p_mdss_ver = { + .core_major_ver = 8, + .core_minor_ver = 4, +}; + +const struct dpu_mdss_cfg dpu_sa8775p_cfg = { + .mdss_ver = &sa8775p_mdss_ver, + .caps = &sa8775p_dpu_caps, + .mdp = &sa8775p_mdp, + .cdm = &sc7280_cdm, + .ctl_count = ARRAY_SIZE(sa8775p_ctl), + .ctl = sa8775p_ctl, + .sspp_count = ARRAY_SIZE(sa8775p_sspp), + .sspp = sa8775p_sspp, + .mixer_count = ARRAY_SIZE(sa8775p_lm), + .mixer = sa8775p_lm, + .dspp_count = ARRAY_SIZE(sa8775p_dspp), + .dspp = sa8775p_dspp, + .pingpong_count = ARRAY_SIZE(sa8775p_pp), + .pingpong = sa8775p_pp, + .dsc_count = ARRAY_SIZE(sa8775p_dsc), + .dsc = sa8775p_dsc, + .merge_3d_count = ARRAY_SIZE(sa8775p_merge_3d), + .merge_3d = sa8775p_merge_3d, + .wb_count = ARRAY_SIZE(sa8775p_wb), + .wb = sa8775p_wb, + .intf_count = ARRAY_SIZE(sa8775p_intf), + .intf = sa8775p_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .perf = &sa8775p_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h index 7c286bafb948d1..e7183cf057768f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_irq.h @@ -8,72 +8,26 @@ #include "dpu_kms.h" #include "dpu_hw_interrupts.h" -/** - * dpu_core_irq_preinstall - perform pre-installation of core IRQ handler - * @kms: MSM KMS handle - * @return: none - */ void dpu_core_irq_preinstall(struct msm_kms *kms); -/** - * dpu_core_irq_uninstall - uninstall core IRQ handler - * @kms: MSM KMS handle - * @return: none - */ void dpu_core_irq_uninstall(struct msm_kms *kms); -/** - * dpu_core_irq - core IRQ handler - * @kms: MSM KMS handle - * @return: interrupt handling status - */ irqreturn_t dpu_core_irq(struct msm_kms *kms); -/** - * dpu_core_irq_read - IRQ helper function for reading IRQ status - * @dpu_kms: DPU handle - * @irq_idx: irq index - * @return: non-zero if irq detected; otherwise no irq detected - */ u32 dpu_core_irq_read( struct dpu_kms *dpu_kms, unsigned int irq_idx); -/** - * dpu_core_irq_register_callback - For registering callback function on IRQ - * interrupt - * @dpu_kms: DPU handle - * @irq_idx: irq index - * @irq_cb: IRQ callback funcion. - * @irq_arg: IRQ callback argument. - * @return: 0 for success registering callback, otherwise failure - * - * This function supports registration of multiple callbacks for each interrupt. - */ int dpu_core_irq_register_callback( struct dpu_kms *dpu_kms, unsigned int irq_idx, void (*irq_cb)(void *arg), void *irq_arg); -/** - * dpu_core_irq_unregister_callback - For unregistering callback function on IRQ - * interrupt - * @dpu_kms: DPU handle - * @irq_idx: irq index - * @return: 0 for success registering callback, otherwise failure - * - * This function supports registration of multiple callbacks for each interrupt. - */ int dpu_core_irq_unregister_callback( struct dpu_kms *dpu_kms, unsigned int irq_idx); -/** - * dpu_debugfs_core_irq_init - register core irq debugfs - * @dpu_kms: pointer to kms - * @parent: debugfs directory root - */ void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, struct dentry *parent); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c index 68fae048a9a837..6f0a37f954fe87 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.c @@ -80,7 +80,7 @@ static u64 _dpu_core_perf_calc_clk(const struct dpu_perf_cfg *perf_cfg, mode = &state->adjusted_mode; - crtc_clk = mode->vtotal * mode->hdisplay * drm_mode_vrefresh(mode); + crtc_clk = (u64)mode->vtotal * mode->hdisplay * drm_mode_vrefresh(mode); drm_atomic_crtc_for_each_plane(plane, crtc) { pstate = to_dpu_plane_state(plane->state); @@ -140,6 +140,12 @@ static void _dpu_core_perf_calc_crtc(const struct dpu_core_perf *core_perf, perf->max_per_pipe_ib, perf->bw_ctl); } +/** + * dpu_core_perf_crtc_check - validate performance of the given crtc state + * @crtc: Pointer to crtc + * @state: Pointer to new crtc state + * return: zero if success, or error code otherwise + */ int dpu_core_perf_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -301,6 +307,12 @@ static u64 _dpu_core_perf_get_core_clk_rate(struct dpu_kms *kms) return clk_rate; } +/** + * dpu_core_perf_crtc_update - update performance of the given crtc + * @crtc: Pointer to crtc + * @params_changed: true if crtc parameters are modified + * return: zero if success, or error code otherwise + */ int dpu_core_perf_crtc_update(struct drm_crtc *crtc, int params_changed) { @@ -446,6 +458,11 @@ static const struct file_operations dpu_core_perf_mode_fops = { .write = _dpu_core_perf_mode_write, }; +/** + * dpu_core_perf_debugfs_init - initialize debugfs for core performance context + * @dpu_kms: Pointer to the dpu_kms struct + * @parent: Pointer to parent debugfs + */ int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent) { struct dpu_core_perf *perf = &dpu_kms->perf; @@ -482,6 +499,12 @@ int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent) } #endif +/** + * dpu_core_perf_init - initialize the given core performance context + * @perf: Pointer to core performance context + * @perf_cfg: Pointer to platform performance configuration + * @max_core_clk_rate: Maximum core clock rate + */ int dpu_core_perf_init(struct dpu_core_perf *perf, const struct dpu_perf_cfg *perf_cfg, unsigned long max_core_clk_rate) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h index 4186977390bd8c..451bf8021114d9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_core_perf.h @@ -54,47 +54,20 @@ struct dpu_core_perf { u64 fix_core_ab_vote; }; -/** - * dpu_core_perf_crtc_check - validate performance of the given crtc state - * @crtc: Pointer to crtc - * @state: Pointer to new crtc state - * return: zero if success, or error code otherwise - */ int dpu_core_perf_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *state); -/** - * dpu_core_perf_crtc_update - update performance of the given crtc - * @crtc: Pointer to crtc - * @params_changed: true if crtc parameters are modified - * return: zero if success, or error code otherwise - */ int dpu_core_perf_crtc_update(struct drm_crtc *crtc, int params_changed); -/** - * dpu_core_perf_crtc_release_bw - release bandwidth of the given crtc - * @crtc: Pointer to crtc - */ void dpu_core_perf_crtc_release_bw(struct drm_crtc *crtc); -/** - * dpu_core_perf_init - initialize the given core performance context - * @perf: Pointer to core performance context - * @perf_cfg: Pointer to platform performance configuration - * @max_core_clk_rate: Maximum core clock rate - */ int dpu_core_perf_init(struct dpu_core_perf *perf, const struct dpu_perf_cfg *perf_cfg, unsigned long max_core_clk_rate); struct dpu_kms; -/** - * dpu_core_perf_debugfs_init - initialize debugfs for core performance context - * @dpu_kms: Pointer to the dpu_kms struct - * @debugfs_parent: Pointer to parent debugfs - */ int dpu_core_perf_debugfs_init(struct dpu_kms *dpu_kms, struct dentry *parent); #endif /* _DPU_CORE_PERF_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index db6c57900781d9..9f6ffd344693ec 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -572,6 +572,10 @@ static void _dpu_crtc_complete_flip(struct drm_crtc *crtc) spin_unlock_irqrestore(&dev->event_lock, flags); } +/** + * dpu_crtc_get_intf_mode - get interface mode of the given crtc + * @crtc: Pointert to crtc + */ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) { struct drm_encoder *encoder; @@ -594,6 +598,10 @@ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc) return INTF_MODE_NONE; } +/** + * dpu_crtc_vblank_callback - called on vblank irq, issues completion events + * @crtc: Pointer to drm crtc object + */ void dpu_crtc_vblank_callback(struct drm_crtc *crtc) { struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); @@ -704,6 +712,10 @@ void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event) kthread_queue_work(priv->event_thread[crtc_id].worker, &fevent->work); } +/** + * dpu_crtc_complete_commit - callback signalling completion of current commit + * @crtc: Pointer to drm crtc object + */ void dpu_crtc_complete_commit(struct drm_crtc *crtc) { trace_dpu_crtc_complete_commit(DRMID(crtc)); @@ -934,6 +946,10 @@ static int _dpu_crtc_wait_for_frame_done(struct drm_crtc *crtc) return rc; } +/** + * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc + * @crtc: Pointer to drm crtc object + */ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc) { struct drm_encoder *encoder; @@ -1230,6 +1246,24 @@ static int dpu_crtc_atomic_check(struct drm_crtc *crtc, return 0; } +static enum drm_mode_status dpu_crtc_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); + + /* + * max crtc width is equal to the max mixer width * 2 and max height is 4K + */ + return drm_mode_validate_size(mode, + 2 * dpu_kms->catalog->caps->max_mixer_width, + 4096); +} + +/** + * dpu_crtc_vblank - enable or disable vblanks for this crtc + * @crtc: Pointer to drm crtc object + * @en: true to enable vblanks, false to disable + */ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) { struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); @@ -1445,10 +1479,19 @@ static const struct drm_crtc_helper_funcs dpu_crtc_helper_funcs = { .atomic_check = dpu_crtc_atomic_check, .atomic_begin = dpu_crtc_atomic_begin, .atomic_flush = dpu_crtc_atomic_flush, + .mode_valid = dpu_crtc_mode_valid, .get_scanout_position = dpu_crtc_get_scanout_position, }; -/* initialize crtc */ +/** + * dpu_crtc_init - create a new crtc object + * @dev: dpu device + * @plane: base plane + * @cursor: cursor plane + * @return: new crtc object or error + * + * initialize CRTC + */ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, struct drm_plane *cursor) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index febc3e764a6323..0b148f3ce0d7af 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -239,55 +239,17 @@ static inline int dpu_crtc_frame_pending(struct drm_crtc *crtc) return crtc ? atomic_read(&to_dpu_crtc(crtc)->frame_pending) : -EINVAL; } -/** - * dpu_crtc_vblank - enable or disable vblanks for this crtc - * @crtc: Pointer to drm crtc object - * @en: true to enable vblanks, false to disable - */ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en); -/** - * dpu_crtc_vblank_callback - called on vblank irq, issues completion events - * @crtc: Pointer to drm crtc object - */ void dpu_crtc_vblank_callback(struct drm_crtc *crtc); -/** - * dpu_crtc_commit_kickoff - trigger kickoff of the commit for this crtc - * @crtc: Pointer to drm crtc object - */ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc); -/** - * dpu_crtc_complete_commit - callback signalling completion of current commit - * @crtc: Pointer to drm crtc object - */ void dpu_crtc_complete_commit(struct drm_crtc *crtc); -/** - * dpu_crtc_init - create a new crtc object - * @dev: dpu device - * @plane: base plane - * @cursor: cursor plane - * @Return: new crtc object or error - */ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, struct drm_plane *cursor); -/** - * dpu_crtc_register_custom_event - api for enabling/disabling crtc event - * @kms: Pointer to dpu_kms - * @crtc_drm: Pointer to crtc object - * @event: Event that client is interested - * @en: Flag to enable/disable the event - */ -int dpu_crtc_register_custom_event(struct dpu_kms *kms, - struct drm_crtc *crtc_drm, u32 event, bool en); - -/** - * dpu_crtc_get_intf_mode - get interface mode of the given crtc - * @crtc: Pointert to crtc - */ enum dpu_intf_mode dpu_crtc_get_intf_mode(struct drm_crtc *crtc); /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index bd3698bf0cf740..83de7564e2c1fe 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -217,6 +217,10 @@ static u32 dither_matrix[DITHER_MATRIX_SZ] = { 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10 }; +/** + * dpu_encoder_get_drm_fmt - return DRM fourcc format + * @phys_enc: Pointer to physical encoder structure + */ u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc) { struct drm_encoder *drm_enc; @@ -235,6 +239,11 @@ u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc) return DRM_FORMAT_RGB888; } +/** + * dpu_encoder_needs_periph_flush - return true if physical encoder requires + * peripheral flush + * @phys_enc: Pointer to physical encoder structure + */ bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc) { struct drm_encoder *drm_enc; @@ -253,6 +262,10 @@ bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc) msm_dp_needs_periph_flush(priv->dp[disp_info->h_tile_instance[0]], mode); } +/** + * dpu_encoder_is_widebus_enabled - return bool value if widebus is enabled + * @drm_enc: Pointer to previously created drm encoder structure + */ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc) { const struct dpu_encoder_virt *dpu_enc; @@ -272,6 +285,11 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc) return false; } +/** + * dpu_encoder_is_dsc_enabled - indicate whether dsc is enabled + * for the encoder. + * @drm_enc: Pointer to previously created drm encoder structure + */ bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc) { const struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); @@ -279,6 +297,12 @@ bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc) return dpu_enc->dsc ? true : false; } +/** + * dpu_encoder_get_crc_values_cnt - get number of physical encoders contained + * in virtual encoder that can collect CRC values + * @drm_enc: Pointer to previously created drm encoder structure + * Returns: Number of physical encoders for given drm encoder + */ int dpu_encoder_get_crc_values_cnt(const struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; @@ -297,6 +321,10 @@ int dpu_encoder_get_crc_values_cnt(const struct drm_encoder *drm_enc) return num_intf; } +/** + * dpu_encoder_setup_misr - enable misr calculations + * @drm_enc: Pointer to previously created drm encoder structure + */ void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; @@ -315,6 +343,13 @@ void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc) } } +/** + * dpu_encoder_get_crc - get the crc value from interface blocks + * @drm_enc: Pointer to previously created drm encoder structure + * @crcs: array to fill with CRC data + * @pos: offset into the @crcs array + * Returns: 0 on success, error otherwise + */ int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos) { struct dpu_encoder_virt *dpu_enc; @@ -385,6 +420,12 @@ static char *dpu_encoder_helper_get_intf_type(enum dpu_intf_mode intf_mode) } } +/** + * dpu_encoder_helper_report_irq_timeout - utility to report error that irq has + * timed out, including reporting frame error event to crtc and debug dump + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: Failing interrupt index + */ void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, enum dpu_intr_idx intr_idx) { @@ -402,6 +443,15 @@ void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, static int dpu_encoder_helper_wait_event_timeout(int32_t drm_id, u32 irq_idx, struct dpu_encoder_wait_info *info); +/** + * dpu_encoder_helper_wait_for_irq - utility to wait on an irq. + * note: will call dpu_encoder_helper_wait_for_irq on timeout + * @phys_enc: Pointer to physical encoder structure + * @irq_idx: IRQ index + * @func: IRQ callback to be called in case of timeout + * @wait_info: wait info struct + * @return: 0 or -ERROR + */ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, unsigned int irq_idx, void (*func)(void *arg), @@ -473,6 +523,10 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, return ret; } +/** + * dpu_encoder_get_vsync_count - get vsync count for the encoder. + * @drm_enc: Pointer to previously created drm encoder structure + */ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); @@ -480,6 +534,10 @@ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc) return phys ? atomic_read(&phys->vsync_cnt) : 0; } +/** + * dpu_encoder_get_linecount - get interface line count for the encoder. + * @drm_enc: Pointer to previously created drm encoder structure + */ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; @@ -495,6 +553,13 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc) return linecount; } +/** + * dpu_encoder_helper_split_config - split display configuration helper function + * This helper function may be used by physical encoders to configure + * the split display related registers. + * @phys_enc: Pointer to physical encoder structure + * @interface: enum dpu_intf setting + */ void dpu_encoder_helper_split_config( struct dpu_encoder_phys *phys_enc, enum dpu_intf interface) @@ -544,6 +609,10 @@ void dpu_encoder_helper_split_config( } } +/** + * dpu_encoder_use_dsc_merge - returns true if the encoder uses DSC merge topology. + * @drm_enc: Pointer to previously created drm encoder structure + */ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); @@ -560,6 +629,12 @@ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc) return (num_dsc > 0) && (num_dsc > intf_count); } +/** + * dpu_encoder_get_dsc_config - get DSC config for the DPU encoder + * This helper function is used by physical encoder to get DSC config + * used for this encoder. + * @drm_enc: Pointer to encoder structure + */ struct drm_dsc_config *dpu_encoder_get_dsc_config(struct drm_encoder *drm_enc) { struct msm_drm_private *priv = drm_enc->dev->dev_private; @@ -1089,6 +1164,11 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc, return 0; } +/** + * dpu_encoder_prepare_wb_job - prepare writeback job for the encoder. + * @drm_enc: Pointer to previously created drm encoder structure + * @job: Pointer to the current drm writeback job + */ void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc, struct drm_writeback_job *job) { @@ -1106,6 +1186,11 @@ void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc, } } +/** + * dpu_encoder_cleanup_wb_job - cleanup writeback job for the encoder. + * @drm_enc: Pointer to previously created drm encoder structure + * @job: Pointer to the current drm writeback job + */ void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc, struct drm_writeback_job *job) { @@ -1248,6 +1333,10 @@ static void _dpu_encoder_virt_enable_helper(struct drm_encoder *drm_enc) } } +/** + * dpu_encoder_virt_runtime_resume - pm runtime resume the encoder configs + * @drm_enc: encoder pointer + */ void dpu_encoder_virt_runtime_resume(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); @@ -1389,6 +1478,12 @@ static struct dpu_hw_intf *dpu_encoder_get_intf(const struct dpu_mdss_cfg *catal return NULL; } +/** + * dpu_encoder_vblank_callback - Notify virtual encoder of vblank IRQ reception + * @drm_enc: Pointer to drm encoder structure + * @phy_enc: Pointer to physical encoder + * Note: This is called from IRQ handler context. + */ void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, struct dpu_encoder_phys *phy_enc) { @@ -1411,6 +1506,12 @@ void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, DPU_ATRACE_END("encoder_vblank_callback"); } +/** + * dpu_encoder_underrun_callback - Notify virtual encoder of underrun IRQ reception + * @drm_enc: Pointer to drm encoder structure + * @phy_enc: Pointer to physical encoder + * Note: This is called from IRQ handler context. + */ void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc, struct dpu_encoder_phys *phy_enc) { @@ -1429,6 +1530,11 @@ void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc, DPU_ATRACE_END("encoder_underrun_callback"); } +/** + * dpu_encoder_assign_crtc - Link the encoder to the crtc it's assigned to + * @drm_enc: encoder pointer + * @crtc: crtc pointer + */ void dpu_encoder_assign_crtc(struct drm_encoder *drm_enc, struct drm_crtc *crtc) { struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); @@ -1441,6 +1547,13 @@ void dpu_encoder_assign_crtc(struct drm_encoder *drm_enc, struct drm_crtc *crtc) spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); } +/** + * dpu_encoder_toggle_vblank_for_crtc - Toggles vblank interrupts on or off if + * the encoder is assigned to the given crtc + * @drm_enc: encoder pointer + * @crtc: crtc pointer + * @enable: true if vblank should be enabled + */ void dpu_encoder_toggle_vblank_for_crtc(struct drm_encoder *drm_enc, struct drm_crtc *crtc, bool enable) { @@ -1465,6 +1578,13 @@ void dpu_encoder_toggle_vblank_for_crtc(struct drm_encoder *drm_enc, } } +/** + * dpu_encoder_frame_done_callback - Notify virtual encoder that this phys + * encoder completes last request frame + * @drm_enc: Pointer to drm encoder structure + * @ready_phys: Pointer to physical encoder + * @event: Event to process + */ void dpu_encoder_frame_done_callback( struct drm_encoder *drm_enc, struct dpu_encoder_phys *ready_phys, u32 event) @@ -1587,6 +1707,12 @@ static void _dpu_encoder_trigger_start(struct dpu_encoder_phys *phys) phys->ops.trigger_start(phys); } +/** + * dpu_encoder_helper_trigger_start - control start helper function + * This helper function may be optionally specified by physical + * encoders if they require ctl_start triggering. + * @phys_enc: Pointer to physical encoder structure + */ void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc) { struct dpu_hw_ctl *ctl; @@ -1708,6 +1834,11 @@ static void _dpu_encoder_kickoff_phys(struct dpu_encoder_virt *dpu_enc) spin_unlock_irqrestore(&dpu_enc->enc_spinlock, lock_flags); } +/** + * dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous + * kickoff and trigger the ctl prepare progress for command mode display. + * @drm_enc: encoder pointer + */ void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; @@ -1784,6 +1915,11 @@ static u32 _dpu_encoder_calculate_linetime(struct dpu_encoder_virt *dpu_enc, return line_time; } +/** + * dpu_encoder_vsync_time - get the time of the next vsync + * @drm_enc: encoder pointer + * @wakeup_time: pointer to ktime_t to write the vsync time to + */ int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time) { struct drm_display_mode *mode; @@ -1930,6 +2066,13 @@ static void dpu_encoder_prep_dsc(struct dpu_encoder_virt *dpu_enc, dsc, dsc_common_mode, initial_lines); } +/** + * dpu_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl + * path (i.e. ctl flush and start) at next appropriate time. + * Immediately: if no previous commit is outstanding. + * Delayed: Block until next trigger can be issued. + * @drm_enc: encoder pointer + */ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; @@ -1966,6 +2109,10 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc) dpu_encoder_prep_dsc(dpu_enc, dpu_enc->dsc); } +/** + * dpu_encoder_is_valid_for_commit - check if encode has valid parameters for commit. + * @drm_enc: Pointer to drm encoder structure + */ bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; @@ -1987,6 +2134,11 @@ bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc) return true; } +/** + * dpu_encoder_kickoff - trigger a double buffer flip of the ctl path + * (i.e. ctl flush and start) immediately. + * @drm_enc: encoder pointer + */ void dpu_encoder_kickoff(struct drm_encoder *drm_enc) { struct dpu_encoder_virt *dpu_enc; @@ -2085,6 +2237,10 @@ static void dpu_encoder_unprep_dsc(struct dpu_encoder_virt *dpu_enc) } } +/** + * dpu_encoder_helper_phys_cleanup - helper to cleanup dpu pipeline + * @phys_enc: Pointer to physical encoder structure + */ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) { struct dpu_hw_ctl *ctl = phys_enc->hw_ctl; @@ -2168,6 +2324,12 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) ctl->ops.clear_pending_flush(ctl); } +/** + * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block + * @phys_enc: Pointer to physical encoder + * @dpu_fmt: Pinter to the format description + * @output_type: HDMI/WB + */ void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc, const struct msm_format *dpu_fmt, u32 output_type) @@ -2472,6 +2634,13 @@ static const struct drm_encoder_funcs dpu_encoder_funcs = { .debugfs_init = dpu_encoder_debugfs_init, }; +/** + * dpu_encoder_init - initialize virtual encoder object + * @dev: Pointer to drm device structure + * @drm_enc_mode: corresponding DRM_MODE_ENCODER_* constant + * @disp_info: Pointer to display information structure + * Returns: Pointer to newly created drm encoder + */ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, int drm_enc_mode, struct msm_display_info *disp_info) @@ -2593,6 +2762,10 @@ int dpu_encoder_wait_for_tx_complete(struct drm_encoder *drm_enc) return ret; } +/** + * dpu_encoder_get_intf_mode - get interface mode of the given encoder + * @encoder: Pointer to drm encoder object + */ enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder) { struct dpu_encoder_virt *dpu_enc = NULL; @@ -2612,6 +2785,12 @@ enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder) return INTF_MODE_NONE; } +/** + * dpu_encoder_helper_get_dsc - get DSC blocks mask for the DPU encoder + * This helper function is used by physical encoder to get DSC blocks mask + * used for this encoder. + * @phys_enc: Pointer to physical encoder structure + */ unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc) { struct drm_encoder *encoder = phys_enc->parent; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h index f7465a1774aa0d..92b5ee390788d1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h @@ -19,6 +19,8 @@ #define IDLE_TIMEOUT (66 - 16/2) +#define MAX_H_TILES_PER_DISPLAY 2 + /** * struct msm_display_info - defines display properties * @intf_type: INTF_ type @@ -36,159 +38,54 @@ struct msm_display_info { enum dpu_vsync_source vsync_source; }; -/** - * dpu_encoder_assign_crtc - Link the encoder to the crtc it's assigned to - * @encoder: encoder pointer - * @crtc: crtc pointer - */ void dpu_encoder_assign_crtc(struct drm_encoder *encoder, struct drm_crtc *crtc); -/** - * dpu_encoder_toggle_vblank_for_crtc - Toggles vblank interrupts on or off if - * the encoder is assigned to the given crtc - * @encoder: encoder pointer - * @crtc: crtc pointer - * @enable: true if vblank should be enabled - */ void dpu_encoder_toggle_vblank_for_crtc(struct drm_encoder *encoder, struct drm_crtc *crtc, bool enable); -/** - * dpu_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl - * path (i.e. ctl flush and start) at next appropriate time. - * Immediately: if no previous commit is outstanding. - * Delayed: Block until next trigger can be issued. - * @encoder: encoder pointer - */ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *encoder); -/** - * dpu_encoder_trigger_kickoff_pending - Clear the flush bits from previous - * kickoff and trigger the ctl prepare progress for command mode display. - * @encoder: encoder pointer - */ void dpu_encoder_trigger_kickoff_pending(struct drm_encoder *encoder); -/** - * dpu_encoder_kickoff - trigger a double buffer flip of the ctl path - * (i.e. ctl flush and start) immediately. - * @encoder: encoder pointer - */ void dpu_encoder_kickoff(struct drm_encoder *encoder); -/** - * dpu_encoder_wakeup_time - get the time of the next vsync - */ int dpu_encoder_vsync_time(struct drm_encoder *drm_enc, ktime_t *wakeup_time); int dpu_encoder_wait_for_commit_done(struct drm_encoder *drm_encoder); int dpu_encoder_wait_for_tx_complete(struct drm_encoder *drm_encoder); -/* - * dpu_encoder_get_intf_mode - get interface mode of the given encoder - * @encoder: Pointer to drm encoder object - */ enum dpu_intf_mode dpu_encoder_get_intf_mode(struct drm_encoder *encoder); -/** - * dpu_encoder_virt_runtime_resume - pm runtime resume the encoder configs - * @encoder: encoder pointer - */ void dpu_encoder_virt_runtime_resume(struct drm_encoder *encoder); -/** - * dpu_encoder_init - initialize virtual encoder object - * @dev: Pointer to drm device structure - * @drm_enc_mode: corresponding DRM_MODE_ENCODER_* constant - * @disp_info: Pointer to display information structure - * Returns: Pointer to newly created drm encoder - */ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, int drm_enc_mode, struct msm_display_info *disp_info); -/** - * dpu_encoder_set_idle_timeout - set the idle timeout for video - * and command mode encoders. - * @drm_enc: Pointer to previously created drm encoder structure - * @idle_timeout: idle timeout duration in milliseconds - */ -void dpu_encoder_set_idle_timeout(struct drm_encoder *drm_enc, - u32 idle_timeout); -/** - * dpu_encoder_get_linecount - get interface line count for the encoder. - * @drm_enc: Pointer to previously created drm encoder structure - */ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc); -/** - * dpu_encoder_get_vsync_count - get vsync count for the encoder. - * @drm_enc: Pointer to previously created drm encoder structure - */ int dpu_encoder_get_vsync_count(struct drm_encoder *drm_enc); -/** - * dpu_encoder_is_widebus_enabled - return bool value if widebus is enabled - * @drm_enc: Pointer to previously created drm encoder structure - */ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc); -/** - * dpu_encoder_is_dsc_enabled - indicate whether dsc is enabled - * for the encoder. - * @drm_enc: Pointer to previously created drm encoder structure - */ bool dpu_encoder_is_dsc_enabled(const struct drm_encoder *drm_enc); -/** - * dpu_encoder_get_crc_values_cnt - get number of physical encoders contained - * in virtual encoder that can collect CRC values - * @drm_enc: Pointer to previously created drm encoder structure - * Returns: Number of physical encoders for given drm encoder - */ int dpu_encoder_get_crc_values_cnt(const struct drm_encoder *drm_enc); -/** - * dpu_encoder_setup_misr - enable misr calculations - * @drm_enc: Pointer to previously created drm encoder structure - */ void dpu_encoder_setup_misr(const struct drm_encoder *drm_encoder); -/** - * dpu_encoder_get_crc - get the crc value from interface blocks - * @drm_enc: Pointer to previously created drm encoder structure - * Returns: 0 on success, error otherwise - */ int dpu_encoder_get_crc(const struct drm_encoder *drm_enc, u32 *crcs, int pos); -/** - * dpu_encoder_use_dsc_merge - returns true if the encoder uses DSC merge topology. - * @drm_enc: Pointer to previously created drm encoder structure - */ bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc); -/** - * dpu_encoder_prepare_wb_job - prepare writeback job for the encoder. - * @drm_enc: Pointer to previously created drm encoder structure - * @job: Pointer to the current drm writeback job - */ void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc, struct drm_writeback_job *job); -/** - * dpu_encoder_cleanup_wb_job - cleanup writeback job for the encoder. - * @drm_enc: Pointer to previously created drm encoder structure - * @job: Pointer to the current drm writeback job - */ void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc, struct drm_writeback_job *job); -/** - * dpu_encoder_is_valid_for_commit - check if encode has valid parameters for commit. - * @drm_enc: Pointer to drm encoder structure - */ bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc); #endif /* __DPU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index e77ebe3a68da99..63f09857025c20 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -279,37 +279,15 @@ struct dpu_encoder_wait_info { s64 timeout_ms; }; -/** - * dpu_encoder_phys_vid_init - Construct a new video mode physical encoder - * @p: Pointer to init params structure - * Return: Error code or newly allocated encoder - */ struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); -/** - * dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder - * @dev: Corresponding device for devres management - * @p: Pointer to init params structure - * Return: Error code or newly allocated encoder - */ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); -/** - * dpu_encoder_phys_wb_init - initialize writeback encoder - * @dev: Corresponding device for devres management - * @init: Pointer to init info structure with initialization params - */ struct dpu_encoder_phys *dpu_encoder_phys_wb_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); -/** - * dpu_encoder_helper_trigger_start - control start helper function - * This helper function may be optionally specified by physical - * encoders if they require ctl_start triggering. - * @phys_enc: Pointer to physical encoder structure - */ void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc); static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode( @@ -331,106 +309,38 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode( return BLEND_3D_NONE; } -/** - * dpu_encoder_helper_get_dsc - get DSC blocks mask for the DPU encoder - * This helper function is used by physical encoder to get DSC blocks mask - * used for this encoder. - * @phys_enc: Pointer to physical encoder structure - */ unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc); -/** - * dpu_encoder_get_dsc_config - get DSC config for the DPU encoder - * This helper function is used by physical encoder to get DSC config - * used for this encoder. - * @drm_enc: Pointer to encoder structure - */ struct drm_dsc_config *dpu_encoder_get_dsc_config(struct drm_encoder *drm_enc); -/** - * dpu_encoder_get_drm_fmt - return DRM fourcc format - * @phys_enc: Pointer to physical encoder structure - */ u32 dpu_encoder_get_drm_fmt(struct dpu_encoder_phys *phys_enc); -/** - * dpu_encoder_needs_periph_flush - return true if physical encoder requires - * peripheral flush - * @phys_enc: Pointer to physical encoder structure - */ bool dpu_encoder_needs_periph_flush(struct dpu_encoder_phys *phys_enc); -/** - * dpu_encoder_helper_split_config - split display configuration helper function - * This helper function may be used by physical encoders to configure - * the split display related registers. - * @phys_enc: Pointer to physical encoder structure - * @interface: enum dpu_intf setting - */ void dpu_encoder_helper_split_config( struct dpu_encoder_phys *phys_enc, enum dpu_intf interface); -/** - * dpu_encoder_helper_report_irq_timeout - utility to report error that irq has - * timed out, including reporting frame error event to crtc and debug dump - * @phys_enc: Pointer to physical encoder structure - * @intr_idx: Failing interrupt index - */ void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc, enum dpu_intr_idx intr_idx); -/** - * dpu_encoder_helper_wait_for_irq - utility to wait on an irq. - * note: will call dpu_encoder_helper_wait_for_irq on timeout - * @phys_enc: Pointer to physical encoder structure - * @irq: IRQ index - * @func: IRQ callback to be called in case of timeout - * @wait_info: wait info struct - * @Return: 0 or -ERROR - */ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc, unsigned int irq, void (*func)(void *arg), struct dpu_encoder_wait_info *wait_info); -/** - * dpu_encoder_helper_phys_cleanup - helper to cleanup dpu pipeline - * @phys_enc: Pointer to physical encoder structure - */ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc); -/** - * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block - * @phys_enc: Pointer to physical encoder - * @output_type: HDMI/WB - */ void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc, const struct msm_format *dpu_fmt, u32 output_type); -/** - * dpu_encoder_vblank_callback - Notify virtual encoder of vblank IRQ reception - * @drm_enc: Pointer to drm encoder structure - * @phys_enc: Pointer to physical encoder - * Note: This is called from IRQ handler context. - */ void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc, struct dpu_encoder_phys *phy_enc); -/** dpu_encoder_underrun_callback - Notify virtual encoder of underrun IRQ reception - * @drm_enc: Pointer to drm encoder structure - * @phys_enc: Pointer to physical encoder - * Note: This is called from IRQ handler context. - */ void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc, struct dpu_encoder_phys *phy_enc); -/** dpu_encoder_frame_done_callback -- Notify virtual encoder that this phys encoder completes last request frame - * @drm_enc: Pointer to drm encoder structure - * @phys_enc: Pointer to physical encoder - * @event: Event to process - */ void dpu_encoder_frame_done_callback( struct drm_encoder *drm_enc, struct dpu_encoder_phys *ready_phys, u32 event); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c index 6fc31d47cd1dc8..e9bbccc44dad8b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_cmd.c @@ -720,6 +720,12 @@ static void dpu_encoder_phys_cmd_init_ops( ops->get_line_count = dpu_encoder_phys_cmd_get_line_count; } +/** + * dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder + * @dev: Corresponding device for devres management + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c index d8a2edebfe8c3c..abd6600046cb3a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c @@ -746,6 +746,12 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->get_frame_count = dpu_encoder_phys_vid_get_frame_count; } +/** + * dpu_encoder_phys_vid_init - Construct a new video mode physical encoder + * @dev: Corresponding device for devres management + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c index 07035ab77b792e..4c006ec74575b2 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c @@ -166,10 +166,10 @@ static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc) /** * dpu_encoder_phys_wb_setup_fb - setup output framebuffer * @phys_enc: Pointer to physical encoder - * @fb: Pointer to output framebuffer + * @format: Format of the framebuffer */ static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc, - struct drm_framebuffer *fb) + const struct msm_format *format) { struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc); struct dpu_hw_wb *hw_wb; @@ -193,12 +193,12 @@ static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc, hw_wb->ops.setup_roi(hw_wb, wb_cfg); if (hw_wb->ops.setup_outformat) - hw_wb->ops.setup_outformat(hw_wb, wb_cfg); + hw_wb->ops.setup_outformat(hw_wb, wb_cfg, format); if (hw_wb->ops.setup_cdp) { const struct dpu_perf_cfg *perf = phys_enc->dpu_kms->catalog->perf; - hw_wb->ops.setup_cdp(hw_wb, wb_cfg->dest.format, + hw_wb->ops.setup_cdp(hw_wb, format, perf->cdp_cfg[DPU_PERF_CDP_USAGE_NRT].wr_enable); } @@ -321,15 +321,10 @@ static void dpu_encoder_phys_wb_setup( { struct dpu_hw_wb *hw_wb = phys_enc->hw_wb; struct drm_display_mode mode = phys_enc->cached_mode; - struct drm_framebuffer *fb = NULL; struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc); - struct drm_writeback_job *wb_job; const struct msm_format *format; - const struct msm_format *dpu_fmt; - wb_job = wb_enc->wb_job; format = msm_framebuffer_format(wb_enc->wb_job->fb); - dpu_fmt = mdp_get_format(&phys_enc->dpu_kms->base, format->pixel_format, wb_job->fb->modifier); DPU_DEBUG("[mode_set:%d, \"%s\",%d,%d]\n", hw_wb->idx - WB_0, mode.name, @@ -341,9 +336,9 @@ static void dpu_encoder_phys_wb_setup( dpu_encoder_phys_wb_set_qos(phys_enc); - dpu_encoder_phys_wb_setup_fb(phys_enc, fb); + dpu_encoder_phys_wb_setup_fb(phys_enc, format); - dpu_encoder_helper_phys_setup_cdm(phys_enc, dpu_fmt, CDM_CDWN_OUTPUT_WB); + dpu_encoder_helper_phys_setup_cdm(phys_enc, format, CDM_CDWN_OUTPUT_WB); dpu_encoder_phys_wb_setup_ctl(phys_enc); } @@ -587,26 +582,20 @@ static void dpu_encoder_phys_wb_prepare_wb_job(struct dpu_encoder_phys *phys_enc format = msm_framebuffer_format(job->fb); - wb_cfg->dest.format = mdp_get_format(&phys_enc->dpu_kms->base, - format->pixel_format, job->fb->modifier); - if (!wb_cfg->dest.format) { - /* this error should be detected during atomic_check */ - DPU_ERROR("failed to get format %p4cc\n", &format->pixel_format); - return; - } - - ret = dpu_format_populate_layout(aspace, job->fb, &wb_cfg->dest); + ret = dpu_format_populate_plane_sizes(job->fb, &wb_cfg->dest); if (ret) { - DPU_DEBUG("failed to populate layout %d\n", ret); + DPU_DEBUG("failed to populate plane sizes%d\n", ret); return; } + dpu_format_populate_addrs(aspace, job->fb, &wb_cfg->dest); + wb_cfg->dest.width = job->fb->width; wb_cfg->dest.height = job->fb->height; - wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes; + wb_cfg->dest.num_planes = format->num_planes; - if ((wb_cfg->dest.format->fetch_type == MDP_PLANE_PLANAR) && - (wb_cfg->dest.format->element[0] == C1_B_Cb)) + if ((format->fetch_type == MDP_PLANE_PLANAR) && + (format->element[0] == C1_B_Cb)) swap(wb_cfg->dest.plane_addr[1], wb_cfg->dest.plane_addr[2]); DPU_DEBUG("[fb_offset:%8.8x,%8.8x,%8.8x,%8.8x]\n", diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c index 6b1e9a617da329..59c9427da7dda0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.c @@ -13,9 +13,6 @@ #define DPU_UBWC_PLANE_SIZE_ALIGNMENT 4096 -#define DPU_MAX_IMG_WIDTH 0x3FFF -#define DPU_MAX_IMG_HEIGHT 0x3FFF - /* * struct dpu_media_color_map - maps drm format to media format * @format: DRM base pixel format @@ -93,10 +90,9 @@ static int _dpu_format_get_media_color_ubwc(const struct msm_format *fmt) return color_fmt; } -static int _dpu_format_get_plane_sizes_ubwc( +static int _dpu_format_populate_plane_sizes_ubwc( const struct msm_format *fmt, - const uint32_t width, - const uint32_t height, + struct drm_framebuffer *fb, struct dpu_hw_fmt_layout *layout) { int i; @@ -104,9 +100,8 @@ static int _dpu_format_get_plane_sizes_ubwc( bool meta = MSM_FORMAT_IS_UBWC(fmt); memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); - layout->format = fmt; - layout->width = width; - layout->height = height; + layout->width = fb->width; + layout->height = fb->height; layout->num_planes = fmt->num_planes; color = _dpu_format_get_media_color_ubwc(fmt); @@ -116,19 +111,19 @@ static int _dpu_format_get_plane_sizes_ubwc( return -EINVAL; } - if (MSM_FORMAT_IS_YUV(layout->format)) { + if (MSM_FORMAT_IS_YUV(fmt)) { uint32_t y_sclines, uv_sclines; uint32_t y_meta_scanlines = 0; uint32_t uv_meta_scanlines = 0; layout->num_planes = 2; - layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width); - y_sclines = VENUS_Y_SCANLINES(color, height); + layout->plane_pitch[0] = VENUS_Y_STRIDE(color, fb->width); + y_sclines = VENUS_Y_SCANLINES(color, fb->height); layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * y_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); - layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width); - uv_sclines = VENUS_UV_SCANLINES(color, height); + layout->plane_pitch[1] = VENUS_UV_STRIDE(color, fb->width); + uv_sclines = VENUS_UV_SCANLINES(color, fb->height); layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] * uv_sclines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); @@ -136,13 +131,13 @@ static int _dpu_format_get_plane_sizes_ubwc( goto done; layout->num_planes += 2; - layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width); - y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height); + layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, fb->width); + y_meta_scanlines = VENUS_Y_META_SCANLINES(color, fb->height); layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * y_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); - layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width); - uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height); + layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, fb->width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, fb->height); layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] * uv_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); @@ -151,16 +146,16 @@ static int _dpu_format_get_plane_sizes_ubwc( layout->num_planes = 1; - layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width); - rgb_scanlines = VENUS_RGB_SCANLINES(color, height); + layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, fb->width); + rgb_scanlines = VENUS_RGB_SCANLINES(color, fb->height); layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * rgb_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); if (!meta) goto done; layout->num_planes += 2; - layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width); - rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height); + layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, fb->width); + rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, fb->height); layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * rgb_meta_scanlines, DPU_UBWC_PLANE_SIZE_ALIGNMENT); } @@ -172,26 +167,23 @@ static int _dpu_format_get_plane_sizes_ubwc( return 0; } -static int _dpu_format_get_plane_sizes_linear( +static int _dpu_format_populate_plane_sizes_linear( const struct msm_format *fmt, - const uint32_t width, - const uint32_t height, - struct dpu_hw_fmt_layout *layout, - const uint32_t *pitches) + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout) { int i; memset(layout, 0, sizeof(struct dpu_hw_fmt_layout)); - layout->format = fmt; - layout->width = width; - layout->height = height; + layout->width = fb->width; + layout->height = fb->height; layout->num_planes = fmt->num_planes; /* Due to memset above, only need to set planes of interest */ if (fmt->fetch_type == MDP_PLANE_INTERLEAVED) { layout->num_planes = 1; - layout->plane_size[0] = width * height * layout->format->bpp; - layout->plane_pitch[0] = width * layout->format->bpp; + layout->plane_size[0] = fb->width * fb->height * fmt->bpp; + layout->plane_pitch[0] = fb->width * fmt->bpp; } else { uint32_t v_subsample, h_subsample; uint32_t chroma_samp; @@ -201,7 +193,7 @@ static int _dpu_format_get_plane_sizes_linear( _dpu_get_v_h_subsample_rate(chroma_samp, &v_subsample, &h_subsample); - if (width % h_subsample || height % v_subsample) { + if (fb->width % h_subsample || fb->height % v_subsample) { DRM_ERROR("mismatch in subsample vs dimensions\n"); return -EINVAL; } @@ -209,11 +201,11 @@ static int _dpu_format_get_plane_sizes_linear( if ((fmt->pixel_format == DRM_FORMAT_NV12) && (MSM_FORMAT_IS_DX(fmt))) bpp = 2; - layout->plane_pitch[0] = width * bpp; + layout->plane_pitch[0] = fb->width * bpp; layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample; - layout->plane_size[0] = layout->plane_pitch[0] * height; + layout->plane_size[0] = layout->plane_pitch[0] * fb->height; layout->plane_size[1] = layout->plane_pitch[1] * - (height / v_subsample); + (fb->height / v_subsample); if (fmt->fetch_type == MDP_PLANE_PSEUDO_PLANAR) { layout->num_planes = 2; @@ -234,8 +226,13 @@ static int _dpu_format_get_plane_sizes_linear( * all the components based on ubwc specifications. */ for (i = 0; i < layout->num_planes && i < DPU_MAX_PLANES; ++i) { - if (pitches && layout->plane_pitch[i] < pitches[i]) - layout->plane_pitch[i] = pitches[i]; + if (layout->plane_pitch[i] <= fb->pitches[i]) { + layout->plane_pitch[i] = fb->pitches[i]; + } else { + DRM_DEBUG("plane %u expected pitch %u, fb %u\n", + i, layout->plane_pitch[i], fb->pitches[i]); + return -EINVAL; + } } for (i = 0; i < DPU_MAX_PLANES; i++) @@ -244,53 +241,54 @@ static int _dpu_format_get_plane_sizes_linear( return 0; } -static int dpu_format_get_plane_sizes( - const struct msm_format *fmt, - const uint32_t w, - const uint32_t h, - struct dpu_hw_fmt_layout *layout, - const uint32_t *pitches) +/** + * dpu_format_populate_plane_sizes - populate non-address part of the layout based on + * fb, and format found in the fb + * @fb: framebuffer pointer + * @layout: format layout structure to populate + * + * Return: error code on failure or 0 if new addresses were populated + */ +int dpu_format_populate_plane_sizes( + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout) { - if (!layout || !fmt) { + const struct msm_format *fmt; + + if (!layout || !fb) { DRM_ERROR("invalid pointer\n"); return -EINVAL; } - if ((w > DPU_MAX_IMG_WIDTH) || (h > DPU_MAX_IMG_HEIGHT)) { + if (fb->width > DPU_MAX_IMG_WIDTH || + fb->height > DPU_MAX_IMG_HEIGHT) { DRM_ERROR("image dimensions outside max range\n"); return -ERANGE; } + fmt = msm_framebuffer_format(fb); + if (MSM_FORMAT_IS_UBWC(fmt) || MSM_FORMAT_IS_TILE(fmt)) - return _dpu_format_get_plane_sizes_ubwc(fmt, w, h, layout); + return _dpu_format_populate_plane_sizes_ubwc(fmt, fb, layout); - return _dpu_format_get_plane_sizes_linear(fmt, w, h, layout, pitches); + return _dpu_format_populate_plane_sizes_linear(fmt, fb, layout); } -static int _dpu_format_populate_addrs_ubwc( - struct msm_gem_address_space *aspace, - struct drm_framebuffer *fb, - struct dpu_hw_fmt_layout *layout) +static void _dpu_format_populate_addrs_ubwc(struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout) { + const struct msm_format *fmt; uint32_t base_addr = 0; bool meta; - if (!fb || !layout) { - DRM_ERROR("invalid pointers\n"); - return -EINVAL; - } - - if (aspace) - base_addr = msm_framebuffer_iova(fb, aspace, 0); - if (!base_addr) { - DRM_ERROR("failed to retrieve base addr\n"); - return -EFAULT; - } + base_addr = msm_framebuffer_iova(fb, aspace, 0); - meta = MSM_FORMAT_IS_UBWC(layout->format); + fmt = msm_framebuffer_format(fb); + meta = MSM_FORMAT_IS_UBWC(fmt); /* Per-format logic for verifying active planes */ - if (MSM_FORMAT_IS_YUV(layout->format)) { + if (MSM_FORMAT_IS_YUV(fmt)) { /************************************************/ /* UBWC ** */ /* buffer ** DPU PLANE */ @@ -319,7 +317,7 @@ static int _dpu_format_populate_addrs_ubwc( + layout->plane_size[2] + layout->plane_size[3]; if (!meta) - return 0; + return; /* configure Y metadata plane */ layout->plane_addr[2] = base_addr; @@ -350,119 +348,43 @@ static int _dpu_format_populate_addrs_ubwc( layout->plane_addr[1] = 0; if (!meta) - return 0; + return; layout->plane_addr[2] = base_addr; layout->plane_addr[3] = 0; } - return 0; } -static int _dpu_format_populate_addrs_linear( - struct msm_gem_address_space *aspace, - struct drm_framebuffer *fb, - struct dpu_hw_fmt_layout *layout) +static void _dpu_format_populate_addrs_linear(struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout) { unsigned int i; - /* Can now check the pitches given vs pitches expected */ - for (i = 0; i < layout->num_planes; ++i) { - if (layout->plane_pitch[i] > fb->pitches[i]) { - DRM_ERROR("plane %u expected pitch %u, fb %u\n", - i, layout->plane_pitch[i], fb->pitches[i]); - return -EINVAL; - } - } - /* Populate addresses for simple formats here */ - for (i = 0; i < layout->num_planes; ++i) { - if (aspace) - layout->plane_addr[i] = - msm_framebuffer_iova(fb, aspace, i); - if (!layout->plane_addr[i]) { - DRM_ERROR("failed to retrieve base addr\n"); - return -EFAULT; - } - } - - return 0; + for (i = 0; i < layout->num_planes; ++i) + layout->plane_addr[i] = msm_framebuffer_iova(fb, aspace, i); } -int dpu_format_populate_layout( - struct msm_gem_address_space *aspace, - struct drm_framebuffer *fb, - struct dpu_hw_fmt_layout *layout) +/** + * dpu_format_populate_addrs - populate buffer addresses based on + * mmu, fb, and format found in the fb + * @aspace: address space pointer + * @fb: framebuffer pointer + * @layout: format layout structure to populate + */ +void dpu_format_populate_addrs(struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout) { - int ret; - - if (!fb || !layout) { - DRM_ERROR("invalid arguments\n"); - return -EINVAL; - } + const struct msm_format *fmt; - if ((fb->width > DPU_MAX_IMG_WIDTH) || - (fb->height > DPU_MAX_IMG_HEIGHT)) { - DRM_ERROR("image dimensions outside max range\n"); - return -ERANGE; - } - - layout->format = msm_framebuffer_format(fb); - - /* Populate the plane sizes etc via get_format */ - ret = dpu_format_get_plane_sizes(layout->format, fb->width, fb->height, - layout, fb->pitches); - if (ret) - return ret; + fmt = msm_framebuffer_format(fb); /* Populate the addresses given the fb */ - if (MSM_FORMAT_IS_UBWC(layout->format) || - MSM_FORMAT_IS_TILE(layout->format)) - ret = _dpu_format_populate_addrs_ubwc(aspace, fb, layout); + if (MSM_FORMAT_IS_UBWC(fmt) || + MSM_FORMAT_IS_TILE(fmt)) + _dpu_format_populate_addrs_ubwc(aspace, fb, layout); else - ret = _dpu_format_populate_addrs_linear(aspace, fb, layout); - - return ret; -} - -int dpu_format_check_modified_format( - const struct msm_kms *kms, - const struct msm_format *fmt, - const struct drm_mode_fb_cmd2 *cmd, - struct drm_gem_object **bos) -{ - const struct drm_format_info *info; - struct dpu_hw_fmt_layout layout; - uint32_t bos_total_size = 0; - int ret, i; - - if (!fmt || !cmd || !bos) { - DRM_ERROR("invalid arguments\n"); - return -EINVAL; - } - - info = drm_format_info(fmt->pixel_format); - if (!info) - return -EINVAL; - - ret = dpu_format_get_plane_sizes(fmt, cmd->width, cmd->height, - &layout, cmd->pitches); - if (ret) - return ret; - - for (i = 0; i < info->num_planes; i++) { - if (!bos[i]) { - DRM_ERROR("invalid handle for plane %d\n", i); - return -EINVAL; - } - if ((i == 0) || (bos[i] != bos[0])) - bos_total_size += bos[i]->size; - } - - if (bos_total_size < layout.total_size) { - DRM_ERROR("buffers total size too small %u expected %u\n", - bos_total_size, layout.total_size); - return -EINVAL; - } - - return 0; + _dpu_format_populate_addrs_linear(aspace, fb, layout); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h index 210d0ed5f0af8e..c6145d43aa3f82 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_formats.h @@ -31,35 +31,12 @@ static inline bool dpu_find_format(u32 format, const u32 *supported_formats, return false; } -/** - * dpu_format_check_modified_format - validate format and buffers for - * dpu non-standard, i.e. modified format - * @kms: kms driver - * @msm_fmt: pointer to the msm_fmt base pointer of an msm_format - * @cmd: fb_cmd2 structure user request - * @bos: gem buffer object list - * - * Return: error code on failure, 0 on success - */ -int dpu_format_check_modified_format( - const struct msm_kms *kms, - const struct msm_format *msm_fmt, - const struct drm_mode_fb_cmd2 *cmd, - struct drm_gem_object **bos); +void dpu_format_populate_addrs(struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct dpu_hw_fmt_layout *layout); -/** - * dpu_format_populate_layout - populate the given format layout based on - * mmu, fb, and format found in the fb - * @aspace: address space pointer - * @fb: framebuffer pointer - * @fmtl: format layout structure to populate - * - * Return: error code on failure, -EAGAIN if success but the addresses - * are the same as before or 0 if new addresses were populated - */ -int dpu_format_populate_layout( - struct msm_gem_address_space *aspace, +int dpu_format_populate_plane_sizes( struct drm_framebuffer *fb, - struct dpu_hw_fmt_layout *fmtl); + struct dpu_hw_fmt_layout *layout); #endif /*_DPU_FORMATS_H */ 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 dcb4fd85e73b9c..2cbf41f33cc034 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -21,6 +21,16 @@ (VIG_BASE_MASK | \ BIT(DPU_SSPP_CSC_10BIT)) +#define VIG_MSM8953_MASK \ + (BIT(DPU_SSPP_QOS) |\ + BIT(DPU_SSPP_SCALER_QSEED2) |\ + BIT(DPU_SSPP_CSC)) + +#define VIG_MSM8996_MASK \ + (BIT(DPU_SSPP_QOS) | BIT(DPU_SSPP_CDP) |\ + BIT(DPU_SSPP_TS_PREFILL) | BIT(DPU_SSPP_SCALER_QSEED2) |\ + BIT(DPU_SSPP_CSC)) + #define VIG_MSM8998_MASK \ (VIG_MASK | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) @@ -32,6 +42,12 @@ #define VIG_QCM2290_MASK (VIG_BASE_MASK | BIT(DPU_SSPP_QOS_8LVL)) +#define DMA_MSM8953_MASK \ + (BIT(DPU_SSPP_QOS)) + +#define DMA_MSM8996_MASK \ + (BIT(DPU_SSPP_QOS) | BIT(DPU_SSPP_TS_PREFILL) | BIT(DPU_SSPP_CDP)) + #define DMA_MSM8998_MASK \ (BIT(DPU_SSPP_QOS) |\ BIT(DPU_SSPP_TS_PREFILL) | BIT(DPU_SSPP_TS_PREFILL_REC1) |\ @@ -57,9 +73,19 @@ #define DMA_CURSOR_SDM845_MASK_SDMA \ (DMA_CURSOR_SDM845_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) +#define DMA_CURSOR_MSM8996_MASK \ + (DMA_MSM8996_MASK | BIT(DPU_SSPP_CURSOR)) + #define DMA_CURSOR_MSM8998_MASK \ (DMA_MSM8998_MASK | BIT(DPU_SSPP_CURSOR)) +#define RGB_MSM8953_MASK \ + (BIT(DPU_SSPP_QOS)) + +#define RGB_MSM8996_MASK \ + (BIT(DPU_SSPP_QOS) | BIT(DPU_SSPP_CDP) |\ + BIT(DPU_SSPP_TS_PREFILL) | BIT(DPU_SSPP_SCALER_RGB)) + #define MIXER_MSM8998_MASK \ (BIT(DPU_MIXER_SOURCESPLIT)) @@ -69,6 +95,12 @@ #define MIXER_QCM2290_MASK \ (BIT(DPU_DIM_LAYER) | BIT(DPU_MIXER_COMBINED_ALPHA)) +#define PINGPONG_MSM8996_MASK \ + (BIT(DPU_PINGPONG_DSC)) + +#define PINGPONG_MSM8996_TE2_MASK \ + (PINGPONG_MSM8996_MASK | BIT(DPU_PINGPONG_TE2)) + #define PINGPONG_SDM845_MASK \ (BIT(DPU_PINGPONG_DITHER) | BIT(DPU_PINGPONG_DSC)) @@ -115,10 +147,6 @@ #define MAX_HORZ_DECIMATION 4 #define MAX_VERT_DECIMATION 4 -#define MAX_UPSCALE_RATIO 20 -#define MAX_DOWNSCALE_RATIO 4 -#define SSPP_UNITY_SCALE 1 - #define STRCAT(X, Y) (X Y) static const uint32_t plane_formats[] = { @@ -276,8 +304,6 @@ static const u32 wb2_formats_rgb_yuv[] = { /* SSPP common configuration */ #define _VIG_SBLK(scaler_ver) \ { \ - .maxdwnscale = MAX_DOWNSCALE_RATIO, \ - .maxupscale = MAX_UPSCALE_RATIO, \ .scaler_blk = {.name = "scaler", \ .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ @@ -285,15 +311,11 @@ static const u32 wb2_formats_rgb_yuv[] = { .base = 0x1a00, .len = 0x100,}, \ .format_list = plane_formats_yuv, \ .num_formats = ARRAY_SIZE(plane_formats_yuv), \ - .virt_format_list = plane_formats, \ - .virt_num_formats = ARRAY_SIZE(plane_formats), \ .rotation_cfg = NULL, \ } #define _VIG_SBLK_ROT(scaler_ver, rot_cfg) \ { \ - .maxdwnscale = MAX_DOWNSCALE_RATIO, \ - .maxupscale = MAX_UPSCALE_RATIO, \ .scaler_blk = {.name = "scaler", \ .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ @@ -301,29 +323,40 @@ static const u32 wb2_formats_rgb_yuv[] = { .base = 0x1a00, .len = 0x100,}, \ .format_list = plane_formats_yuv, \ .num_formats = ARRAY_SIZE(plane_formats_yuv), \ - .virt_format_list = plane_formats, \ - .virt_num_formats = ARRAY_SIZE(plane_formats), \ .rotation_cfg = rot_cfg, \ } #define _VIG_SBLK_NOSCALE() \ { \ - .maxdwnscale = SSPP_UNITY_SCALE, \ - .maxupscale = SSPP_UNITY_SCALE, \ .format_list = plane_formats, \ .num_formats = ARRAY_SIZE(plane_formats), \ - .virt_format_list = plane_formats, \ - .virt_num_formats = ARRAY_SIZE(plane_formats), \ + } + +/* qseed2 is not supported, so disabled scaling */ +#define _VIG_SBLK_QSEED2() \ + { \ + .scaler_blk = {.name = "scaler", \ + /* no version for qseed2 */ \ + .base = 0x200, .len = 0xa0,}, \ + .csc_blk = {.name = "csc", \ + .base = 0x320, .len = 0x100,}, \ + .format_list = plane_formats_yuv, \ + .num_formats = ARRAY_SIZE(plane_formats_yuv), \ + .rotation_cfg = NULL, \ + } + +#define _RGB_SBLK() \ + { \ + .scaler_blk = {.name = "scaler", \ + .base = 0x200, .len = 0x28,}, \ + .format_list = plane_formats, \ + .num_formats = ARRAY_SIZE(plane_formats), \ } #define _DMA_SBLK() \ { \ - .maxdwnscale = SSPP_UNITY_SCALE, \ - .maxupscale = SSPP_UNITY_SCALE, \ .format_list = plane_formats, \ .num_formats = ARRAY_SIZE(plane_formats), \ - .virt_format_list = plane_formats, \ - .virt_num_formats = ARRAY_SIZE(plane_formats), \ } static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { @@ -332,6 +365,9 @@ static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { .rot_format_list = rotation_v2_formats, }; +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed2 = + _VIG_SBLK_QSEED2(); + static const struct dpu_sspp_sub_blks dpu_vig_sblk_noscale = _VIG_SBLK_NOSCALE(); @@ -363,6 +399,8 @@ static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_2 = static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_3 = _VIG_SBLK(SSPP_SCALER_VER(3, 3)); +static const struct dpu_sspp_sub_blks dpu_rgb_sblk = _RGB_SBLK(); + static const struct dpu_sspp_sub_blks dpu_dma_sblk = _DMA_SBLK(); /************************************************************* @@ -427,6 +465,15 @@ static const struct dpu_dspp_sub_blks sdm845_dspp_sblk = { /************************************************************* * PINGPONG sub blocks config *************************************************************/ +static const struct dpu_pingpong_sub_blks msm8996_pp_sblk_te = { + .te2 = {.name = "te2", .base = 0x2000, .len = 0x0, + .version = 0x1}, +}; + +static const struct dpu_pingpong_sub_blks msm8996_pp_sblk = { + /* No dither block */ +}; + static const struct dpu_pingpong_sub_blks sdm845_pp_sblk_te = { .te2 = {.name = "te2", .base = 0x2000, .len = 0x0, .version = 0x1}, @@ -492,6 +539,34 @@ static const struct dpu_vbif_dynamic_ot_cfg msm8998_ot_rdwr_cfg[] = { }, }; +static const struct dpu_vbif_cfg msm8996_vbif[] = { + { + .name = "vbif_rt", .id = VBIF_RT, + .base = 0, .len = 0x1040, + .default_ot_rd_limit = 32, + .default_ot_wr_limit = 16, + .features = BIT(DPU_VBIF_QOS_REMAP) | BIT(DPU_VBIF_QOS_OTLIM), + .xin_halt_timeout = 0x4000, + .qos_rp_remap_size = 0x20, + .dynamic_ot_rd_tbl = { + .count = ARRAY_SIZE(msm8998_ot_rdwr_cfg), + .cfg = msm8998_ot_rdwr_cfg, + }, + .dynamic_ot_wr_tbl = { + .count = ARRAY_SIZE(msm8998_ot_rdwr_cfg), + .cfg = msm8998_ot_rdwr_cfg, + }, + .qos_rt_tbl = { + .npriority_lvl = ARRAY_SIZE(msm8998_rt_pri_lvl), + .priority_lvl = msm8998_rt_pri_lvl, + }, + .qos_nrt_tbl = { + .npriority_lvl = ARRAY_SIZE(msm8998_nrt_pri_lvl), + .priority_lvl = msm8998_nrt_pri_lvl, + }, + }, +}; + static const struct dpu_vbif_cfg msm8998_vbif[] = { { .name = "vbif_rt", .id = VBIF_RT, @@ -675,6 +750,11 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { * Hardware catalog *************************************************************/ +#include "catalog/dpu_1_7_msm8996.h" +#include "catalog/dpu_1_14_msm8937.h" +#include "catalog/dpu_1_15_msm8917.h" +#include "catalog/dpu_1_16_msm8953.h" + #include "catalog/dpu_3_0_msm8998.h" #include "catalog/dpu_3_2_sdm660.h" #include "catalog/dpu_3_3_sdm630.h" @@ -699,6 +779,7 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { #include "catalog/dpu_8_0_sc8280xp.h" #include "catalog/dpu_8_1_sm8450.h" +#include "catalog/dpu_8_4_sa8775p.h" #include "catalog/dpu_9_0_sm8550.h" diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 37e18e820a20a4..c701d18c352239 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -21,8 +21,8 @@ #define DPU_HW_BLK_NAME_LEN 16 -#define MAX_IMG_WIDTH 0x3fff -#define MAX_IMG_HEIGHT 0x3fff +#define DPU_MAX_IMG_WIDTH 0x3fff +#define DPU_MAX_IMG_HEIGHT 0x3fff #define CRTC_DUAL_MIXERS 2 @@ -364,21 +364,15 @@ struct dpu_caps { /** * struct dpu_sspp_sub_blks : SSPP sub-blocks * common: Pointer to common configurations shared by sub blocks - * @maxdwnscale: max downscale ratio supported(without DECIMATION) - * @maxupscale: maxupscale ratio supported * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps * @qseed_ver: qseed version * @scaler_blk: * @csc_blk: * @format_list: Pointer to list of supported formats * @num_formats: Number of supported formats - * @virt_format_list: Pointer to list of supported formats for virtual planes - * @virt_num_formats: Number of supported formats for virtual planes * @dpu_rotation_cfg: inline rotation configuration */ struct dpu_sspp_sub_blks { - u32 maxdwnscale; - u32 maxupscale; u32 max_per_pipe_bw; u32 qseed_ver; struct dpu_scaler_blk scaler_blk; @@ -386,8 +380,6 @@ struct dpu_sspp_sub_blks { const u32 *format_list; u32 num_formats; - const u32 *virt_format_list; - u32 virt_num_formats; const struct dpu_rotation_cfg *rotation_cfg; }; @@ -831,6 +823,10 @@ struct dpu_mdss_cfg { const struct dpu_format_extended *vig_formats; }; +extern const struct dpu_mdss_cfg dpu_msm8917_cfg; +extern const struct dpu_mdss_cfg dpu_msm8937_cfg; +extern const struct dpu_mdss_cfg dpu_msm8953_cfg; +extern const struct dpu_mdss_cfg dpu_msm8996_cfg; extern const struct dpu_mdss_cfg dpu_msm8998_cfg; extern const struct dpu_mdss_cfg dpu_sdm630_cfg; extern const struct dpu_mdss_cfg dpu_sdm660_cfg; @@ -850,6 +846,7 @@ extern const struct dpu_mdss_cfg dpu_sm8350_cfg; extern const struct dpu_mdss_cfg dpu_sc7280_cfg; extern const struct dpu_mdss_cfg dpu_sc8280xp_cfg; extern const struct dpu_mdss_cfg dpu_sm8450_cfg; +extern const struct dpu_mdss_cfg dpu_sa8775p_cfg; extern const struct dpu_mdss_cfg dpu_sm8550_cfg; extern const struct dpu_mdss_cfg dpu_sm8650_cfg; extern const struct dpu_mdss_cfg dpu_x1e80100_cfg; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c index 55d2768a6d4d98..ae1534c49ae02f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c @@ -222,6 +222,14 @@ static void dpu_hw_cdm_bind_pingpong_blk(struct dpu_hw_cdm *ctx, const enum dpu_ DPU_REG_WRITE(c, CDM_MUX, mux_cfg); } +/** + * dpu_hw_cdm_init - initializes the cdm hw driver object. + * should be called once before accessing every cdm. + * @dev: DRM device handle + * @cfg: CDM catalog entry for which driver object is required + * @addr : mapped register io address of MDSS + * @mdss_rev: mdss hw core revision + */ struct dpu_hw_cdm *dpu_hw_cdm_init(struct drm_device *dev, const struct dpu_cdm_cfg *cfg, void __iomem *addr, const struct dpu_mdss_version *mdss_rev) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h index ec71c9886d7537..6bb3476a05f80c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h @@ -122,14 +122,6 @@ struct dpu_hw_cdm { struct dpu_hw_cdm_ops ops; }; -/** - * dpu_hw_cdm_init - initializes the cdm hw driver object. - * should be called once before accessing every cdm. - * @dev: DRM device handle - * @cdm: CDM catalog entry for which driver object is required - * @addr : mapped register io address of MDSS - * @mdss_rev: mdss hw core revision - */ struct dpu_hw_cdm *dpu_hw_cdm_init(struct drm_device *dev, const struct dpu_cdm_cfg *cdm, void __iomem *addr, const struct dpu_mdss_version *mdss_rev); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index 2e50049f2f8509..4893f10d6a5832 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -736,6 +736,15 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, ops->set_active_pipes = dpu_hw_ctl_set_fetch_pipe_active; }; +/** + * dpu_hw_ctl_init() - Initializes the ctl_path hw driver object. + * Should be called before accessing any ctl_path register. + * @dev: Corresponding device for devres management + * @cfg: ctl_path catalog entry for which driver object is required + * @addr: mapped register io address of MDP + * @mixer_count: Number of mixers in @mixer + * @mixer: Pointer to an array of Layer Mixers defined in the catalog + */ struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev, const struct dpu_ctl_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 4401fdc0f3e4fe..85c6c835cc8780 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -294,15 +294,6 @@ static inline struct dpu_hw_ctl *to_dpu_hw_ctl(struct dpu_hw_blk *hw) return container_of(hw, struct dpu_hw_ctl, base); } -/** - * dpu_hw_ctl_init() - Initializes the ctl_path hw driver object. - * Should be called before accessing any ctl_path register. - * @dev: Corresponding device for devres management - * @cfg: ctl_path catalog entry for which driver object is required - * @addr: mapped register io address of MDP - * @mixer_count: Number of mixers in @mixer - * @mixer: Pointer to an array of Layer Mixers defined in the catalog - */ struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev, const struct dpu_ctl_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c index 5e9aad1b2aa283..657200401f5763 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c @@ -190,6 +190,13 @@ static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops, ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk; }; +/** + * dpu_hw_dsc_init() - Initializes the DSC hw driver object. + * @dev: Corresponding device for devres management + * @cfg: DSC catalog entry for which driver object is required + * @addr: Mapped register io address of MDP + * Return: Error code or allocated dpu_hw_dsc context + */ struct dpu_hw_dsc *dpu_hw_dsc_init(struct drm_device *dev, const struct dpu_dsc_cfg *cfg, void __iomem *addr) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index 989c88d2449b6a..fc171bdeca488f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -62,24 +62,10 @@ struct dpu_hw_dsc { struct dpu_hw_dsc_ops ops; }; -/** - * dpu_hw_dsc_init() - Initializes the DSC hw driver object. - * @dev: Corresponding device for devres management - * @cfg: DSC catalog entry for which driver object is required - * @addr: Mapped register io address of MDP - * Return: Error code or allocated dpu_hw_dsc context - */ struct dpu_hw_dsc *dpu_hw_dsc_init(struct drm_device *dev, const struct dpu_dsc_cfg *cfg, void __iomem *addr); -/** - * dpu_hw_dsc_init_1_2() - initializes the v1.2 DSC hw driver object - * @dev: Corresponding device for devres management - * @cfg: DSC catalog entry for which driver object is required - * @addr: Mapped register io address of MDP - * Returns: Error code or allocated dpu_hw_dsc context - */ struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(struct drm_device *dev, const struct dpu_dsc_cfg *cfg, void __iomem *addr); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c index ba193b0376fe82..b9c433567262a9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c @@ -369,6 +369,13 @@ static void _setup_dcs_ops_1_2(struct dpu_hw_dsc_ops *ops, ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2; } +/** + * dpu_hw_dsc_init_1_2() - initializes the v1.2 DSC hw driver object + * @dev: Corresponding device for devres management + * @cfg: DSC catalog entry for which driver object is required + * @addr: Mapped register io address of MDP + * Returns: Error code or allocated dpu_hw_dsc context + */ struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(struct drm_device *dev, const struct dpu_dsc_cfg *cfg, void __iomem *addr) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c index b1da88e2935f46..829ca272873e45 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c @@ -70,6 +70,14 @@ static void _setup_dspp_ops(struct dpu_hw_dspp *c, c->ops.setup_pcc = dpu_setup_dspp_pcc; } +/** + * dpu_hw_dspp_init() - Initializes the DSPP hw driver object. + * should be called once before accessing every DSPP. + * @dev: Corresponding device for devres management + * @cfg: DSPP catalog entry for which driver object is required + * @addr: Mapped register io address of MDP + * Return: pointer to structure or ERR_PTR + */ struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev, const struct dpu_dspp_cfg *cfg, void __iomem *addr) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h index 3b435690b6ccbf..45c26cd49fa3ed 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h @@ -78,14 +78,6 @@ static inline struct dpu_hw_dspp *to_dpu_hw_dspp(struct dpu_hw_blk *hw) return container_of(hw, struct dpu_hw_dspp, base); } -/** - * dpu_hw_dspp_init() - Initializes the DSPP hw driver object. - * should be called once before accessing every DSPP. - * @dev: Corresponding device for devres management - * @cfg: DSPP catalog entry for which driver object is required - * @addr: Mapped register io address of MDP - * Return: pointer to structure or ERR_PTR - */ struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev, const struct dpu_dspp_cfg *cfg, void __iomem *addr); 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 b85881aab04786..49bd77a755aa55 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -237,6 +237,11 @@ static void dpu_core_irq_callback_handler(struct dpu_kms *dpu_kms, unsigned int irq_entry->cb(irq_entry->arg); } +/** + * dpu_core_irq - core IRQ handler + * @kms: MSM KMS handle + * @return: interrupt handling status + */ irqreturn_t dpu_core_irq(struct msm_kms *kms) { struct dpu_kms *dpu_kms = to_dpu_kms(kms); @@ -442,6 +447,12 @@ static void dpu_disable_all_irqs(struct dpu_kms *dpu_kms) wmb(); } +/** + * dpu_core_irq_read - IRQ helper function for reading IRQ status + * @dpu_kms: DPU handle + * @irq_idx: irq index + * @return: non-zero if irq detected; otherwise no irq detected + */ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, unsigned int irq_idx) { @@ -476,6 +487,12 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, return intr_status; } +/** + * dpu_hw_intr_init(): Initializes the interrupts hw object + * @dev: Corresponding device for devres management + * @addr: mapped register io address of MDP + * @m: pointer to MDSS catalog data + */ struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev, void __iomem *addr, const struct dpu_mdss_cfg *m) @@ -517,6 +534,17 @@ struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev, return intr; } +/** + * dpu_core_irq_register_callback - For registering callback function on IRQ + * interrupt + * @dpu_kms: DPU handle + * @irq_idx: irq index + * @irq_cb: IRQ callback function. + * @irq_arg: IRQ callback argument. + * @return: 0 for success registering callback, otherwise failure + * + * This function supports registration of multiple callbacks for each interrupt. + */ int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, unsigned int irq_idx, void (*irq_cb)(void *arg), @@ -567,6 +595,15 @@ int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, return 0; } +/** + * dpu_core_irq_unregister_callback - For unregistering callback function on IRQ + * interrupt + * @dpu_kms: DPU handle + * @irq_idx: irq index + * @return: 0 for success registering callback, otherwise failure + * + * This function supports registration of multiple callbacks for each interrupt. + */ int dpu_core_irq_unregister_callback(struct dpu_kms *dpu_kms, unsigned int irq_idx) { @@ -628,6 +665,11 @@ static int dpu_debugfs_core_irq_show(struct seq_file *s, void *v) DEFINE_SHOW_ATTRIBUTE(dpu_debugfs_core_irq); +/** + * dpu_debugfs_core_irq_init - register core irq debugfs + * @dpu_kms: pointer to kms + * @parent: debugfs directory root + */ void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, struct dentry *parent) { @@ -636,6 +678,11 @@ void dpu_debugfs_core_irq_init(struct dpu_kms *dpu_kms, } #endif +/** + * dpu_core_irq_preinstall - perform pre-installation of core IRQ handler + * @kms: MSM KMS handle + * @return: none + */ void dpu_core_irq_preinstall(struct msm_kms *kms) { struct dpu_kms *dpu_kms = to_dpu_kms(kms); @@ -653,6 +700,11 @@ void dpu_core_irq_preinstall(struct msm_kms *kms) } } +/** + * dpu_core_irq_uninstall - uninstall core IRQ handler + * @kms: MSM KMS handle + * @return: none + */ void dpu_core_irq_uninstall(struct msm_kms *kms) { struct dpu_kms *dpu_kms = to_dpu_kms(kms); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h index 564b750a28fe28..142358a105c595 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -68,12 +68,6 @@ struct dpu_hw_intr { struct dpu_hw_intr_entry irq_tbl[DPU_NUM_IRQS]; }; -/** - * dpu_hw_intr_init(): Initializes the interrupts hw object - * @dev: Corresponding device for devres management - * @addr: mapped register io address of MDP - * @m: pointer to MDSS catalog data - */ struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev, void __iomem *addr, const struct dpu_mdss_cfg *m); 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 29cb854f831a3d..fb1d25baa51805 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -547,6 +547,14 @@ static void dpu_hw_intf_program_intf_cmd_cfg(struct dpu_hw_intf *intf, DPU_REG_WRITE(&intf->hw, INTF_CONFIG2, intf_cfg2); } +/** + * dpu_hw_intf_init() - Initializes the INTF driver for the passed + * interface catalog entry. + * @dev: Corresponding device for devres management + * @cfg: interface catalog entry for which driver object is required + * @addr: mapped register io address of MDP + * @mdss_rev: dpu core's major and minor versions + */ struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, const struct dpu_intf_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index fc23650dfbf05d..114be272ac0ae6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -130,14 +130,6 @@ struct dpu_hw_intf { struct dpu_hw_intf_ops ops; }; -/** - * dpu_hw_intf_init() - Initializes the INTF driver for the passed - * interface catalog entry. - * @dev: Corresponding device for devres management - * @cfg: interface catalog entry for which driver object is required - * @addr: mapped register io address of MDP - * @mdss_rev: dpu core's major and minor versions - */ struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, const struct dpu_intf_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c index 1d3ccf3228c62c..81b56f066519a6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -158,6 +158,13 @@ static void _setup_mixer_ops(struct dpu_hw_lm_ops *ops, ops->collect_misr = dpu_hw_lm_collect_misr; } +/** + * dpu_hw_lm_init() - Initializes the mixer hw driver object. + * should be called once before accessing every mixer. + * @dev: Corresponding device for devres management + * @cfg: mixer catalog entry for which driver object is required + * @addr: mapped register io address of MDP + */ struct dpu_hw_mixer *dpu_hw_lm_init(struct drm_device *dev, const struct dpu_lm_cfg *cfg, void __iomem *addr) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index 0a33817552499a..6f60fa9b3cd781 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -93,13 +93,6 @@ static inline struct dpu_hw_mixer *to_dpu_hw_mixer(struct dpu_hw_blk *hw) return container_of(hw, struct dpu_hw_mixer, base); } -/** - * dpu_hw_lm_init() - Initializes the mixer hw driver object. - * should be called once before accessing every mixer. - * @dev: Corresponding device for devres management - * @cfg: mixer catalog entry for which driver object is required - * @addr: mapped register io address of MDP - */ struct dpu_hw_mixer *dpu_hw_lm_init(struct drm_device *dev, const struct dpu_lm_cfg *cfg, void __iomem *addr); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index a2eff36a2224cc..f8806a4d317be0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -293,7 +293,6 @@ enum dpu_3d_blend_mode { /** * struct dpu_hw_fmt_layout - format information of the source pixel data - * @format: pixel format parameters * @num_planes: number of planes (including meta data planes) * @width: image width * @height: image height @@ -303,7 +302,6 @@ enum dpu_3d_blend_mode { * @plane_pitch: pitch of each plane */ struct dpu_hw_fmt_layout { - const struct msm_format *format; uint32_t num_planes; uint32_t width; uint32_t height; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c index ddfa40a959cbd0..0b3325f9c87059 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c @@ -39,6 +39,14 @@ static void _setup_merge_3d_ops(struct dpu_hw_merge_3d *c, c->ops.setup_3d_mode = dpu_hw_merge_3d_setup_3d_mode; }; +/** + * dpu_hw_merge_3d_init() - Initializes the merge_3d driver for the passed + * merge3d catalog entry. + * @dev: Corresponding device for devres management + * @cfg: Pingpong catalog entry for which driver object is required + * @addr: Mapped register io address of MDP + * Return: Error code or allocated dpu_hw_merge_3d context + */ struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(struct drm_device *dev, const struct dpu_merge_3d_cfg *cfg, void __iomem *addr) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h index c192f02ec1abcc..6833c020752366 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h @@ -45,14 +45,6 @@ static inline struct dpu_hw_merge_3d *to_dpu_hw_merge_3d(struct dpu_hw_blk *hw) return container_of(hw, struct dpu_hw_merge_3d, base); } -/** - * dpu_hw_merge_3d_init() - Initializes the merge_3d driver for the passed - * merge3d catalog entry. - * @dev: Corresponding device for devres management - * @cfg: Pingpong catalog entry for which driver object is required - * @addr: Mapped register io address of MDP - * Return: Error code or allocated dpu_hw_merge_3d context - */ struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(struct drm_device *dev, const struct dpu_merge_3d_cfg *cfg, void __iomem *addr); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c index 2db4c6fba37ac1..36c0ec775b9203 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c @@ -283,6 +283,15 @@ static int dpu_hw_pp_setup_dsc(struct dpu_hw_pingpong *pp) return 0; } +/** + * dpu_hw_pingpong_init() - initializes the pingpong driver for the passed + * pingpong catalog entry. + * @dev: Corresponding device for devres management + * @cfg: Pingpong catalog entry for which driver object is required + * @addr: Mapped register io address of MDP + * @mdss_rev: dpu core's major and minor versions + * Return: Error code or allocated dpu_hw_pingpong context + */ struct dpu_hw_pingpong *dpu_hw_pingpong_init(struct drm_device *dev, const struct dpu_pingpong_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index a48b69fd79a3b4..dd99e1c21a1eee 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -118,15 +118,6 @@ static inline struct dpu_hw_pingpong *to_dpu_hw_pingpong(struct dpu_hw_blk *hw) return container_of(hw, struct dpu_hw_pingpong, base); } -/** - * dpu_hw_pingpong_init() - initializes the pingpong driver for the passed - * pingpong catalog entry. - * @dev: Corresponding device for devres management - * @cfg: Pingpong catalog entry for which driver object is required - * @addr: Mapped register io address of MDP - * @mdss_rev: dpu core's major and minor versions - * Return: Error code or allocated dpu_hw_pingpong context - */ struct dpu_hw_pingpong *dpu_hw_pingpong_init(struct drm_device *dev, const struct dpu_pingpong_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index 2c720f1fc1b298..32c7c80845533d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -672,6 +672,15 @@ int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms, } #endif +/** + * dpu_hw_sspp_init() - Initializes the sspp hw driver object. + * Should be called once before accessing every pipe. + * @dev: Corresponding device for devres management + * @cfg: Pipe catalog entry for which driver object is required + * @addr: Mapped register io address of MDP + * @mdss_data: UBWC / MDSS configuration data + * @mdss_rev: dpu core's major and minor versions + */ struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev, const struct dpu_sspp_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index 4a910b808687a2..56a0edf2a57c6d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -12,6 +12,8 @@ struct dpu_hw_sspp; +#define DPU_SSPP_MAX_PITCH_SIZE 0xffff + /** * Flags */ @@ -142,10 +144,12 @@ struct dpu_hw_pixel_ext { * @src_rect: src ROI, caller takes into account the different operations * such as decimation, flip etc to program this field * @dest_rect: destination ROI. + * @rotation: simplified drm rotation hint */ struct dpu_sw_pipe_cfg { struct drm_rect src_rect; struct drm_rect dst_rect; + unsigned int rotation; }; /** @@ -315,15 +319,7 @@ struct dpu_hw_sspp { }; struct dpu_kms; -/** - * dpu_hw_sspp_init() - Initializes the sspp hw driver object. - * Should be called once before accessing every pipe. - * @dev: Corresponding device for devres management - * @cfg: Pipe catalog entry for which driver object is required - * @addr: Mapped register io address of MDP - * @mdss_data: UBWC / MDSS configuration data - * @mdss_rev: dpu core's major and minor versions - */ + struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev, const struct dpu_sspp_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c index 0f40eea7f5e247..ad19330de61abd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c @@ -284,6 +284,13 @@ static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops, ops->intf_audio_select = dpu_hw_intf_audio_select; } +/** + * dpu_hw_mdptop_init - initializes the top driver for the passed config + * @dev: Corresponding device for devres management + * @cfg: MDP TOP configuration from catalog + * @addr: Mapped register io address of MDP + * @mdss_rev: dpu core's major and minor versions + */ struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev, const struct dpu_mdp_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h index f1ab9fd106e513..04efdcd21ceb0a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h @@ -157,18 +157,9 @@ struct dpu_hw_mdp { struct dpu_hw_mdp_ops ops; }; -/** - * dpu_hw_mdptop_init - initializes the top driver for the passed config - * @dev: Corresponding device for devres management - * @cfg: MDP TOP configuration from catalog - * @addr: Mapped register io address of MDP - * @mdss_rev: dpu core's major and minor versions - */ struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev, const struct dpu_mdp_cfg *cfg, void __iomem *addr, const struct dpu_mdss_version *mdss_rev); -void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp); - #endif /*_DPU_HW_TOP_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c index 98e34afde2d259..af76ad8a81035c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c @@ -213,6 +213,13 @@ static void _setup_vbif_ops(struct dpu_hw_vbif_ops *ops, ops->set_write_gather_en = dpu_hw_set_write_gather_en; } +/** + * dpu_hw_vbif_init() - Initializes the VBIF driver for the passed + * VBIF catalog entry. + * @dev: Corresponding device for devres management + * @cfg: VBIF catalog entry for which driver object is required + * @addr: Mapped register io address of MDSS + */ struct dpu_hw_vbif *dpu_hw_vbif_init(struct drm_device *dev, const struct dpu_vbif_cfg *cfg, void __iomem *addr) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h index e2b4307500e42f..285121ec804cca 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h @@ -105,13 +105,6 @@ struct dpu_hw_vbif { struct dpu_hw_vbif_ops ops; }; -/** - * dpu_hw_vbif_init() - Initializes the VBIF driver for the passed - * VBIF catalog entry. - * @dev: Corresponding device for devres management - * @cfg: VBIF catalog entry for which driver object is required - * @addr: Mapped register io address of MDSS - */ struct dpu_hw_vbif *dpu_hw_vbif_init(struct drm_device *dev, const struct dpu_vbif_cfg *cfg, void __iomem *addr); 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 93ff01c889b5a8..fb9f9095776249 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c @@ -64,10 +64,10 @@ static void dpu_hw_wb_setup_outaddress(struct dpu_hw_wb *ctx, } static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx, - struct dpu_hw_wb_cfg *data) + struct dpu_hw_wb_cfg *data, + const struct msm_format *fmt) { struct dpu_hw_blk_reg_map *c = &ctx->hw; - const struct msm_format *fmt = data->dest.format; u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp; u32 write_config = 0; u32 opmode = 0; @@ -213,6 +213,14 @@ static void _setup_wb_ops(struct dpu_hw_wb_ops *ops, ops->setup_clk_force_ctrl = dpu_hw_wb_setup_clk_force_ctrl; } +/** + * dpu_hw_wb_init() - Initializes the writeback hw driver object. + * @dev: Corresponding device for devres management + * @cfg: wb_path catalog entry for which driver object is required + * @addr: mapped register io address of MDP + * @mdss_rev: dpu core's major and minor versions + * Return: Error code or allocated dpu_hw_wb context + */ struct dpu_hw_wb *dpu_hw_wb_init(struct drm_device *dev, const struct dpu_wb_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h index 37497473e16c07..ee5e5ab786e1b4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h @@ -37,7 +37,8 @@ struct dpu_hw_wb_ops { struct dpu_hw_wb_cfg *wb); void (*setup_outformat)(struct dpu_hw_wb *ctx, - struct dpu_hw_wb_cfg *wb); + struct dpu_hw_wb_cfg *wb, + const struct msm_format *fmt); void (*setup_roi)(struct dpu_hw_wb *ctx, struct dpu_hw_wb_cfg *wb); @@ -74,14 +75,6 @@ struct dpu_hw_wb { struct dpu_hw_wb_ops ops; }; -/** - * dpu_hw_wb_init() - Initializes the writeback hw driver object. - * @dev: Corresponding device for devres management - * @cfg: wb_path catalog entry for which driver object is required - * @addr: mapped register io address of MDP - * @mdss_rev: dpu core's major and minor versions - * Return: Error code or allocated dpu_hw_wb context - */ struct dpu_hw_wb *dpu_hw_wb_init(struct drm_device *dev, const struct dpu_wb_cfg *cfg, void __iomem *addr, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index 9bcae53c4f458c..8b251f87a0520d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -230,6 +230,21 @@ static int dpu_regset32_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(dpu_regset32); +/** + * dpu_debugfs_create_regset32 - Create register read back file for debugfs + * + * This function is almost identical to the standard debugfs_create_regset32() + * function, with the main difference being that a list of register + * names/offsets do not need to be provided. The 'read' function simply outputs + * sequential register values over a specified range. + * + * @name: File name within debugfs + * @mode: File mode within debugfs + * @parent: Parent directory entry within debugfs, can be NULL + * @offset: sub-block offset + * @length: sub-block length, in bytes + * @dpu_kms: pointer to dpu kms structure + */ void dpu_debugfs_create_regset32(const char *name, umode_t mode, void *parent, uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms) @@ -1025,7 +1040,6 @@ static const struct msm_kms_funcs kms_funcs = { .complete_commit = dpu_kms_complete_commit, .enable_vblank = dpu_kms_enable_vblank, .disable_vblank = dpu_kms_disable_vblank, - .check_modified_format = dpu_format_check_modified_format, .destroy = dpu_kms_destroy, .snapshot = dpu_kms_mdp_snapshot, #ifdef CONFIG_DEBUG_FS @@ -1061,6 +1075,13 @@ static int _dpu_kms_mmu_init(struct dpu_kms *dpu_kms) return 0; } +/** + * dpu_kms_get_clk_rate() - get the clock rate + * @dpu_kms: pointer to dpu_kms structure + * @clock_name: clock name to get the rate + * + * Return: current clock rate + */ unsigned long dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name) { struct clk *clk; @@ -1202,13 +1223,8 @@ static int dpu_kms_hw_init(struct msm_kms *kms) dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; - /* - * max crtc width is equal to the max mixer width * 2 and max height is - * is 4K - */ - dev->mode_config.max_width = - dpu_kms->catalog->caps->max_mixer_width * 2; - dev->mode_config.max_height = 4096; + dev->mode_config.max_width = DPU_MAX_IMG_WIDTH; + dev->mode_config.max_height = DPU_MAX_IMG_HEIGHT; dev->max_vblank_count = 0xffffffff; /* Disable vblank irqs aggressively for power-saving */ @@ -1445,8 +1461,13 @@ static const struct dev_pm_ops dpu_pm_ops = { }; static const struct of_device_id dpu_dt_match[] = { + { .compatible = "qcom,msm8917-mdp5", .data = &dpu_msm8917_cfg, }, + { .compatible = "qcom,msm8937-mdp5", .data = &dpu_msm8937_cfg, }, + { .compatible = "qcom,msm8953-mdp5", .data = &dpu_msm8953_cfg, }, + { .compatible = "qcom,msm8996-mdp5", .data = &dpu_msm8996_cfg, }, { .compatible = "qcom,msm8998-dpu", .data = &dpu_msm8998_cfg, }, { .compatible = "qcom,qcm2290-dpu", .data = &dpu_qcm2290_cfg, }, + { .compatible = "qcom,sa8775p-dpu", .data = &dpu_sa8775p_cfg, }, { .compatible = "qcom,sdm630-mdp5", .data = &dpu_sdm630_cfg, }, { .compatible = "qcom,sdm660-mdp5", .data = &dpu_sdm660_cfg, }, { .compatible = "qcom,sdm670-dpu", .data = &dpu_sdm670_cfg, }, @@ -1473,7 +1494,7 @@ MODULE_DEVICE_TABLE(of, dpu_dt_match); static struct platform_driver dpu_driver = { .probe = dpu_dev_probe, - .remove_new = dpu_dev_remove, + .remove = dpu_dev_remove, .shutdown = msm_kms_shutdown, .driver = { .name = "msm_dpu", diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index 935ff6fd172c41..88d64d43ea1a82 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -145,37 +145,10 @@ struct dpu_global_state * @dpu_debugfs_create_regset32: Create 32-bit register dump file */ -/** - * dpu_debugfs_create_regset32 - Create register read back file for debugfs - * - * This function is almost identical to the standard debugfs_create_regset32() - * function, with the main difference being that a list of register - * names/offsets do not need to be provided. The 'read' function simply outputs - * sequential register values over a specified range. - * - * @name: File name within debugfs - * @mode: File mode within debugfs - * @parent: Parent directory entry within debugfs, can be NULL - * @offset: sub-block offset - * @length: sub-block length, in bytes - * @dpu_kms: pointer to dpu kms structure - */ void dpu_debugfs_create_regset32(const char *name, umode_t mode, void *parent, uint32_t offset, uint32_t length, struct dpu_kms *dpu_kms); -/** - * dpu_debugfs_get_root - Return root directory entry for KMS's debugfs - * - * The return value should be passed as the 'parent' argument to subsequent - * debugfs create calls. - * - * @dpu_kms: Pointer to DPU's KMS structure - * - * Return: dentry pointer for DPU's debugfs location - */ -void *dpu_debugfs_get_root(struct dpu_kms *dpu_kms); - /** * DPU info management functions * These functions/definitions allow for building up a 'dpu_info' structure @@ -189,13 +162,6 @@ void *dpu_debugfs_get_root(struct dpu_kms *dpu_kms); int dpu_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); void dpu_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); -/** - * dpu_kms_get_clk_rate() - get the clock rate - * @dpu_kms: pointer to dpu_kms structure - * @clock_name: clock name to get the rate - * - * Return: current clock rate - */ unsigned long dpu_kms_get_clk_rate(struct dpu_kms *dpu_kms, char *clock_name); #endif /* __dpu_kms_H__ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 29298e06616359..3ffac24333a2a5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -528,8 +528,7 @@ static const struct dpu_csc_cfg *_dpu_plane_get_csc(struct dpu_sw_pipe *pipe, static void _dpu_plane_setup_scaler(struct dpu_sw_pipe *pipe, const struct msm_format *fmt, bool color_fill, - struct dpu_sw_pipe_cfg *pipe_cfg, - unsigned int rotation) + struct dpu_sw_pipe_cfg *pipe_cfg) { struct dpu_hw_sspp *pipe_hw = pipe->sspp; const struct drm_format_info *info = drm_format_info(fmt->pixel_format); @@ -552,7 +551,7 @@ static void _dpu_plane_setup_scaler(struct dpu_sw_pipe *pipe, dst_height, &scaler3_cfg, fmt, info->hsub, info->vsub, - rotation); + pipe_cfg->rotation); /* configure pixel extension based on scalar config */ _dpu_plane_setup_pixel_ext(&scaler3_cfg, &pixel_ext, @@ -604,7 +603,7 @@ static void _dpu_plane_color_fill_pipe(struct dpu_plane_state *pstate, if (pipe->sspp->ops.setup_rects) pipe->sspp->ops.setup_rects(pipe, &pipe_cfg); - _dpu_plane_setup_scaler(pipe, fmt, true, &pipe_cfg, pstate->rotation); + _dpu_plane_setup_scaler(pipe, fmt, true, &pipe_cfg); } /** @@ -648,7 +647,6 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane, struct drm_framebuffer *fb = new_state->fb; struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_state); - struct dpu_hw_fmt_layout layout; struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); int ret; @@ -676,17 +674,6 @@ static int dpu_plane_prepare_fb(struct drm_plane *plane, } } - /* validate framebuffer layout before commit */ - ret = dpu_format_populate_layout(pstate->aspace, - new_state->fb, &layout); - if (ret) { - DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret); - if (pstate->aspace) - msm_framebuffer_cleanup(new_state->fb, pstate->aspace, - pstate->needs_dirtyfb); - return ret; - } - return 0; } @@ -708,12 +695,17 @@ static void dpu_plane_cleanup_fb(struct drm_plane *plane, } static int dpu_plane_check_inline_rotation(struct dpu_plane *pdpu, - const struct dpu_sspp_sub_blks *sblk, - struct drm_rect src, const struct msm_format *fmt) + struct dpu_sw_pipe *pipe, + struct drm_rect src, + const struct msm_format *fmt) { + const struct dpu_sspp_sub_blks *sblk = pipe->sspp->cap->sblk; size_t num_formats; const u32 *supported_formats; + if (!test_bit(DPU_SSPP_INLINE_ROTATION, &pipe->sspp->cap->features)) + return -EINVAL; + if (!sblk->rotation_cfg) { DPU_ERROR("invalid rotation cfg\n"); return -EINVAL; @@ -743,6 +735,7 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu, { uint32_t min_src_size; struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); + int ret; min_src_size = MSM_FORMAT_IS_YUV(fmt) ? 2 : 1; @@ -780,6 +773,12 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu, return -EINVAL; } + if (pipe_cfg->rotation & DRM_MODE_ROTATE_90) { + ret = dpu_plane_check_inline_rotation(pdpu, pipe, pipe_cfg->src_rect, fmt); + if (ret) + return ret; + } + /* max clk check */ if (_dpu_plane_calc_clk(mode, pipe_cfg) > kms->perf.max_core_clk_rate) { DPU_DEBUG_PLANE(pdpu, "plane exceeds max mdp core clk limits\n"); @@ -789,37 +788,29 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu, return 0; } -static int dpu_plane_atomic_check(struct drm_plane *plane, - struct drm_atomic_state *state) +#define MAX_UPSCALE_RATIO 20 +#define MAX_DOWNSCALE_RATIO 4 + +static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, + struct drm_plane_state *new_plane_state, + const struct drm_crtc_state *crtc_state) { - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, - plane); - int ret = 0, min_scale; + int i, ret = 0, min_scale, max_scale; struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate; struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); - struct dpu_sw_pipe *pipe = &pstate->pipe; - struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; - const struct drm_crtc_state *crtc_state = NULL; - const struct msm_format *fmt; struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; struct drm_rect fb_rect = { 0 }; uint32_t max_linewidth; - unsigned int rotation; - uint32_t supported_rotations; - const struct dpu_sspp_cfg *pipe_hw_caps = pstate->pipe.sspp->cap; - const struct dpu_sspp_sub_blks *sblk = pstate->pipe.sspp->cap->sblk; - if (new_plane_state->crtc) - crtc_state = drm_atomic_get_new_crtc_state(state, - new_plane_state->crtc); + min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO); + max_scale = MAX_DOWNSCALE_RATIO << 16; - min_scale = FRAC_16_16(1, sblk->maxupscale); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, min_scale, - sblk->maxdwnscale << 16, + max_scale, true, true); if (ret) { DPU_DEBUG_PLANE(pdpu, "Check plane state failed (%d)\n", ret); @@ -828,12 +819,6 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, if (!new_plane_state->visible) return 0; - pipe->multirect_index = DPU_SSPP_RECT_SOLO; - pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; - r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; - r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; - r_pipe->sspp = NULL; - pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos; if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) { DPU_ERROR("> %d plane stages assigned\n", @@ -841,13 +826,8 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, return -EINVAL; } - pipe_cfg->src_rect = new_plane_state->src; - /* state->src is 16.16, src_rect is not */ - pipe_cfg->src_rect.x1 >>= 16; - pipe_cfg->src_rect.x2 >>= 16; - pipe_cfg->src_rect.y1 >>= 16; - pipe_cfg->src_rect.y2 >>= 16; + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); pipe_cfg->dst_rect = new_plane_state->dst; @@ -855,14 +835,22 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, fb_rect.y2 = new_plane_state->fb->height; /* Ensure fb size is supported */ - if (drm_rect_width(&fb_rect) > MAX_IMG_WIDTH || - drm_rect_height(&fb_rect) > MAX_IMG_HEIGHT) { + if (drm_rect_width(&fb_rect) > DPU_MAX_IMG_WIDTH || + drm_rect_height(&fb_rect) > DPU_MAX_IMG_HEIGHT) { DPU_DEBUG_PLANE(pdpu, "invalid framebuffer " DRM_RECT_FMT "\n", DRM_RECT_ARG(&fb_rect)); return -E2BIG; } - fmt = msm_framebuffer_format(new_plane_state->fb); + ret = dpu_format_populate_plane_sizes(new_plane_state->fb, &pstate->layout); + if (ret) { + DPU_ERROR_PLANE(pdpu, "failed to get format plane sizes, %d\n", ret); + return ret; + } + + for (i = 0; i < pstate->layout.num_planes; i++) + if (pstate->layout.plane_pitch[i] > DPU_SSPP_MAX_PITCH_SIZE) + return -E2BIG; max_linewidth = pdpu->catalog->caps->max_linewidth; @@ -872,6 +860,86 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { + if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); + return -E2BIG; + } + + *r_pipe_cfg = *pipe_cfg; + pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; + pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; + r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; + r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; + } else { + memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); + } + + drm_rect_rotate_inv(&pipe_cfg->src_rect, + new_plane_state->fb->width, new_plane_state->fb->height, + new_plane_state->rotation); + if (r_pipe_cfg->src_rect.x1 != 0) + drm_rect_rotate_inv(&r_pipe_cfg->src_rect, + new_plane_state->fb->width, new_plane_state->fb->height, + new_plane_state->rotation); + + pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state); + + return 0; +} + +static int dpu_plane_atomic_check_sspp(struct drm_plane *plane, + struct drm_atomic_state *state, + const struct drm_crtc_state *crtc_state) +{ + struct drm_plane_state *new_plane_state = + drm_atomic_get_new_plane_state(state, plane); + struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); + struct dpu_sw_pipe *pipe = &pstate->pipe; + struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; + const struct msm_format *fmt; + struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; + struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; + uint32_t max_linewidth; + uint32_t supported_rotations; + const struct dpu_sspp_cfg *pipe_hw_caps; + const struct dpu_sspp_sub_blks *sblk; + int ret = 0; + + pipe_hw_caps = pipe->sspp->cap; + sblk = pipe->sspp->cap->sblk; + + /* + * We already have verified scaling against platform limitations. + * Now check if the SSPP supports scaling at all. + */ + if (!sblk->scaler_blk.len && + ((drm_rect_width(&new_plane_state->src) >> 16 != + drm_rect_width(&new_plane_state->dst)) || + (drm_rect_height(&new_plane_state->src) >> 16 != + drm_rect_height(&new_plane_state->dst)))) + return -ERANGE; + + fmt = msm_framebuffer_format(new_plane_state->fb); + + max_linewidth = pdpu->catalog->caps->max_linewidth; + + supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0; + + if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION)) + supported_rotations |= DRM_MODE_ROTATE_90; + + pipe_cfg->rotation = drm_rotation_simplify(new_plane_state->rotation, + supported_rotations); + r_pipe_cfg->rotation = pipe_cfg->rotation; + + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, + &crtc_state->adjusted_mode); + if (ret) + return ret; + + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) { /* * In parallel multirect case only the half of the usual width * is supported for tiled formats. If we are here, we know that @@ -885,16 +953,11 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, return -E2BIG; } - if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { - DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); - return -E2BIG; - } - if (drm_rect_width(&pipe_cfg->src_rect) != drm_rect_width(&pipe_cfg->dst_rect) || drm_rect_height(&pipe_cfg->src_rect) != drm_rect_height(&pipe_cfg->dst_rect) || (!test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) && !test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features)) || + pipe_cfg->rotation & DRM_MODE_ROTATE_90 || MSM_FORMAT_IS_YUV(fmt)) { DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, can't use split source\n", DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); @@ -912,51 +975,48 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, r_pipe->multirect_index = DPU_SSPP_RECT_1; r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL; - *r_pipe_cfg = *pipe_cfg; - pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; - pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; - r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; - r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; - } - - drm_rect_rotate_inv(&pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, - new_plane_state->rotation); - if (r_pipe->sspp) - drm_rect_rotate_inv(&r_pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, - new_plane_state->rotation); - - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt, &crtc_state->adjusted_mode); - if (ret) - return ret; - - if (r_pipe->sspp) { ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt, &crtc_state->adjusted_mode); if (ret) return ret; } - supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0; + return 0; +} - if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION)) - supported_rotations |= DRM_MODE_ROTATE_90; +static int dpu_plane_atomic_check(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, + plane); + int ret = 0; + struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); + struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); + struct dpu_sw_pipe *pipe = &pstate->pipe; + struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; + const struct drm_crtc_state *crtc_state = NULL; - rotation = drm_rotation_simplify(new_plane_state->rotation, - supported_rotations); + if (new_plane_state->crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, + new_plane_state->crtc); - if ((pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION)) && - (rotation & DRM_MODE_ROTATE_90)) { - ret = dpu_plane_check_inline_rotation(pdpu, sblk, pipe_cfg->src_rect, fmt); - if (ret) - return ret; - } + pipe->sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe); + r_pipe->sspp = NULL; - pstate->rotation = rotation; - pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state); + ret = dpu_plane_atomic_check_nosspp(plane, new_plane_state, crtc_state); + if (ret) + return ret; - return 0; + if (!new_plane_state->visible) + return 0; + + pipe->multirect_index = DPU_SSPP_RECT_SOLO; + pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; + r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + + return dpu_plane_atomic_check_sspp(plane, state, crtc_state); } static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe) @@ -981,6 +1041,10 @@ static void dpu_plane_flush_csc(struct dpu_plane *pdpu, struct dpu_sw_pipe *pipe } +/** + * dpu_plane_flush - final plane operations before commit flush + * @plane: Pointer to drm plane structure + */ void dpu_plane_flush(struct drm_plane *plane) { struct dpu_plane *pdpu; @@ -1060,14 +1124,14 @@ static void dpu_plane_sspp_update_pipe(struct drm_plane *plane, pipe_cfg); } - _dpu_plane_setup_scaler(pipe, fmt, false, pipe_cfg, pstate->rotation); + _dpu_plane_setup_scaler(pipe, fmt, false, pipe_cfg); if (pipe->sspp->ops.setup_multirect) pipe->sspp->ops.setup_multirect( pipe); if (pipe->sspp->ops.setup_format) { - unsigned int rotation = pstate->rotation; + unsigned int rotation = pipe_cfg->rotation; src_flags = 0x0; @@ -1101,7 +1165,8 @@ static void dpu_plane_sspp_update_pipe(struct drm_plane *plane, _dpu_plane_set_qos_remap(plane, pipe); } -static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) +static void dpu_plane_sspp_atomic_update(struct drm_plane *plane, + struct drm_plane_state *new_state) { struct dpu_plane *pdpu = to_dpu_plane(plane); struct drm_plane_state *state = plane->state; @@ -1115,17 +1180,6 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) msm_framebuffer_format(fb); struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; - struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); - struct msm_gem_address_space *aspace = kms->base.aspace; - struct dpu_hw_fmt_layout layout; - bool layout_valid = false; - int ret; - - ret = dpu_format_populate_layout(aspace, fb, &layout); - if (ret) - DPU_ERROR_PLANE(pdpu, "failed to get format layout, %d\n", ret); - else - layout_valid = true; pstate->pending = true; @@ -1133,6 +1187,8 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) pstate->needs_qos_remap |= (is_rt_pipe != pdpu->is_rt_pipe); pdpu->is_rt_pipe = is_rt_pipe; + dpu_format_populate_addrs(pstate->aspace, new_state->fb, &pstate->layout); + DPU_DEBUG_PLANE(pdpu, "FB[%u] " DRM_RECT_FP_FMT "->crtc%u " DRM_RECT_FMT ", %p4cc ubwc %d\n", fb->base.id, DRM_RECT_FP_ARG(&state->src), crtc->base.id, DRM_RECT_ARG(&state->dst), @@ -1140,12 +1196,12 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) dpu_plane_sspp_update_pipe(plane, pipe, pipe_cfg, fmt, drm_mode_vrefresh(&crtc->mode), - layout_valid ? &layout : NULL); + &pstate->layout); if (r_pipe->sspp) { dpu_plane_sspp_update_pipe(plane, r_pipe, r_pipe_cfg, fmt, drm_mode_vrefresh(&crtc->mode), - layout_valid ? &layout : NULL); + &pstate->layout); } if (pstate->needs_qos_remap) @@ -1197,7 +1253,7 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, if (!new_state->visible) { _dpu_plane_atomic_disable(plane); } else { - dpu_plane_sspp_atomic_update(plane); + dpu_plane_sspp_atomic_update(plane, new_state); } } @@ -1301,7 +1357,6 @@ static void dpu_plane_reset(struct drm_plane *plane) { struct dpu_plane *pdpu; struct dpu_plane_state *pstate; - struct dpu_kms *dpu_kms = _dpu_plane_get_kms(plane); if (!plane) { DPU_ERROR("invalid plane\n"); @@ -1323,16 +1378,6 @@ static void dpu_plane_reset(struct drm_plane *plane) return; } - /* - * Set the SSPP here until we have proper virtualized DPU planes. - * This is the place where the state is allocated, so fill it fully. - */ - pstate->pipe.sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe); - pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO; - pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE; - - pstate->r_pipe.sspp = NULL; - __drm_atomic_helper_plane_reset(plane, &pstate->base); } @@ -1388,7 +1433,15 @@ static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = { .atomic_update = dpu_plane_atomic_update, }; -/* initialize plane */ +/** + * dpu_plane_init - create new dpu plane for the given pipe + * @dev: Pointer to DRM device + * @pipe: dpu hardware pipe identifier + * @type: Plane type - PRIMARY/OVERLAY/CURSOR + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe + * + * Initialize the plane. + */ struct drm_plane *dpu_plane_init(struct drm_device *dev, uint32_t pipe, enum drm_plane_type type, unsigned long possible_crtcs) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h index abd6b21a049bde..97090ca7842b41 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h @@ -30,7 +30,7 @@ * @plane_fetch_bw: calculated BW per plane * @plane_clk: calculated clk per plane * @needs_dirtyfb: whether attached CRTC needs pixel data explicitly flushed - * @rotation: simplified drm rotation hint + * @layout: framebuffer memory layout */ struct dpu_plane_state { struct drm_plane_state base; @@ -47,46 +47,21 @@ struct dpu_plane_state { u64 plane_clk; bool needs_dirtyfb; - unsigned int rotation; + + struct dpu_hw_fmt_layout layout; }; #define to_dpu_plane_state(x) \ container_of(x, struct dpu_plane_state, base) -/** - * dpu_plane_flush - final plane operations before commit flush - * @plane: Pointer to drm plane structure - */ void dpu_plane_flush(struct drm_plane *plane); -/** - * dpu_plane_set_error: enable/disable error condition - * @plane: pointer to drm_plane structure - */ void dpu_plane_set_error(struct drm_plane *plane, bool error); -/** - * dpu_plane_init - create new dpu plane for the given pipe - * @dev: Pointer to DRM device - * @pipe: dpu hardware pipe identifier - * @type: Plane type - PRIMARY/OVERLAY/CURSOR - * @possible_crtcs: bitmask of crtc that can be attached to the given pipe - * - */ struct drm_plane *dpu_plane_init(struct drm_device *dev, uint32_t pipe, enum drm_plane_type type, unsigned long possible_crtcs); -/** - * dpu_plane_color_fill - enables color fill on plane - * @plane: Pointer to DRM plane object - * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red - * @alpha: 8-bit fill alpha value, 255 selects 100% alpha - * Returns: 0 on success - */ -int dpu_plane_color_fill(struct drm_plane *plane, - uint32_t color, uint32_t alpha); - #ifdef CONFIG_DEBUG_FS void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable); #else diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 44938ba7a2b7e6..c247af03dc8ef7 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -34,6 +34,16 @@ struct dpu_rm_requirements { struct msm_display_topology topology; }; +/** + * dpu_rm_init - Read hardware catalog and create reservation tracking objects + * for all HW blocks. + * @dev: Corresponding device for devres management + * @rm: DPU Resource Manager handle + * @cat: Pointer to hardware catalog + * @mdss_data: Pointer to MDSS / UBWC configuration + * @mmio: mapped register io address of MDP + * @return: 0 on Success otherwise -ERROR + */ int dpu_rm_init(struct drm_device *dev, struct dpu_rm *rm, const struct dpu_mdss_cfg *cat, @@ -641,6 +651,13 @@ static void _dpu_rm_clear_mapping(uint32_t *res_mapping, int cnt, } } +/** + * dpu_rm_release - Given the encoder for the display chain, release any + * HW blocks previously reserved for that use case. + * @global_state: resources shared across multiple kms objects + * @enc: DRM Encoder handle + * @return: 0 on Success otherwise -ERROR + */ void dpu_rm_release(struct dpu_global_state *global_state, struct drm_encoder *enc) { @@ -657,6 +674,20 @@ void dpu_rm_release(struct dpu_global_state *global_state, _dpu_rm_clear_mapping(&global_state->cdm_to_enc_id, 1, enc->base.id); } +/** + * dpu_rm_reserve - Given a CRTC->Encoder->Connector display chain, analyze + * the use connections and user requirements, specified through related + * topology control properties, and reserve hardware blocks to that + * display chain. + * HW blocks can then be accessed through dpu_rm_get_* functions. + * HW Reservations should be released via dpu_rm_release_hw. + * @rm: DPU Resource Manager handle + * @global_state: resources shared across multiple kms objects + * @enc: DRM Encoder handle + * @crtc_state: Proposed Atomic DRM CRTC State handle + * @topology: Pointer to topology info for the display + * @return: 0 on Success otherwise -ERROR + */ int dpu_rm_reserve( struct dpu_rm *rm, struct dpu_global_state *global_state, @@ -694,6 +725,16 @@ int dpu_rm_reserve( return ret; } +/** + * dpu_rm_get_assigned_resources - Get hw resources of the given type that are + * assigned to this encoder + * @rm: DPU Resource Manager handle + * @global_state: resources shared across multiple kms objects + * @enc_id: encoder id requesting for allocation + * @type: resource type to return data for + * @blks: pointer to the array to be filled by HW resources + * @blks_size: size of the @blks array + */ int dpu_rm_get_assigned_resources(struct dpu_rm *rm, struct dpu_global_state *global_state, uint32_t enc_id, enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size) @@ -772,6 +813,11 @@ static void dpu_rm_print_state_helper(struct drm_printer *p, } +/** + * dpu_rm_print_state - output the RM private state + * @p: DRM printer + * @global_state: global state + */ void dpu_rm_print_state(struct drm_printer *p, const struct dpu_global_state *global_state) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index e63db8ace6b940..ea0e49cb7b0d3e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -38,62 +38,40 @@ struct dpu_rm { }; /** - * dpu_rm_init - Read hardware catalog and create reservation tracking objects - * for all HW blocks. - * @dev: Corresponding device for devres management - * @rm: DPU Resource Manager handle - * @cat: Pointer to hardware catalog - * @mdss_data: Pointer to MDSS / UBWC configuration - * @mmio: mapped register io address of MDP - * @Return: 0 on Success otherwise -ERROR + * struct msm_display_topology - defines a display topology pipeline + * @num_lm: number of layer mixers used + * @num_intf: number of interfaces the panel is mounted on + * @num_dspp: number of dspp blocks used + * @num_dsc: number of Display Stream Compression (DSC) blocks used + * @needs_cdm: indicates whether cdm block is needed for this display topology */ +struct msm_display_topology { + u32 num_lm; + u32 num_intf; + u32 num_dspp; + u32 num_dsc; + bool needs_cdm; +}; + int dpu_rm_init(struct drm_device *dev, struct dpu_rm *rm, const struct dpu_mdss_cfg *cat, const struct msm_mdss_data *mdss_data, void __iomem *mmio); -/** - * dpu_rm_reserve - Given a CRTC->Encoder->Connector display chain, analyze - * the use connections and user requirements, specified through related - * topology control properties, and reserve hardware blocks to that - * display chain. - * HW blocks can then be accessed through dpu_rm_get_* functions. - * HW Reservations should be released via dpu_rm_release_hw. - * @rm: DPU Resource Manager handle - * @drm_enc: DRM Encoder handle - * @crtc_state: Proposed Atomic DRM CRTC State handle - * @topology: Pointer to topology info for the display - * @Return: 0 on Success otherwise -ERROR - */ int dpu_rm_reserve(struct dpu_rm *rm, struct dpu_global_state *global_state, struct drm_encoder *drm_enc, struct drm_crtc_state *crtc_state, struct msm_display_topology topology); -/** - * dpu_rm_reserve - Given the encoder for the display chain, release any - * HW blocks previously reserved for that use case. - * @rm: DPU Resource Manager handle - * @enc: DRM Encoder handle - * @Return: 0 on Success otherwise -ERROR - */ void dpu_rm_release(struct dpu_global_state *global_state, struct drm_encoder *enc); -/** - * Get hw resources of the given type that are assigned to this encoder. - */ int dpu_rm_get_assigned_resources(struct dpu_rm *rm, struct dpu_global_state *global_state, uint32_t enc_id, enum dpu_hw_blk_type type, struct dpu_hw_blk **blks, int blks_size); -/** - * dpu_rm_print_state - output the RM private state - * @p: DRM printer - * @global_state: global state - */ void dpu_rm_print_state(struct drm_printer *p, const struct dpu_global_state *global_state); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c index 47c02b98eac37b..2a551e455aa30d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.c @@ -204,6 +204,11 @@ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, vbif->ops.set_halt_ctrl(vbif, params->xin_id, false); } +/** + * dpu_vbif_set_qos_remap - set QoS priority level remap + * @dpu_kms: DPU handler + * @params: Pointer to QoS configuration parameters + */ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, struct dpu_vbif_set_qos_params *params) { @@ -245,6 +250,10 @@ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, } } +/** + * dpu_vbif_clear_errors - clear any vbif errors + * @dpu_kms: DPU handler + */ void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms) { struct dpu_hw_vbif *vbif; @@ -262,6 +271,10 @@ void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms) } } +/** + * dpu_vbif_init_memtypes - initialize xin memory types for vbif + * @dpu_kms: DPU handler + */ void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms) { struct dpu_hw_vbif *vbif; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h index e1b1f7f4e4be29..62e47ae1e3ee70 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_vbif.h @@ -38,32 +38,14 @@ struct dpu_vbif_set_qos_params { bool is_rt; }; -/** - * dpu_vbif_set_ot_limit - set OT limit for vbif client - * @dpu_kms: DPU handler - * @params: Pointer to OT configuration parameters - */ void dpu_vbif_set_ot_limit(struct dpu_kms *dpu_kms, struct dpu_vbif_set_ot_params *params); -/** - * dpu_vbif_set_qos_remap - set QoS priority level remap - * @dpu_kms: DPU handler - * @params: Pointer to QoS configuration parameters - */ void dpu_vbif_set_qos_remap(struct dpu_kms *dpu_kms, struct dpu_vbif_set_qos_params *params); -/** - * dpu_vbif_clear_errors - clear any vbif errors - * @dpu_kms: DPU handler - */ void dpu_vbif_clear_errors(struct dpu_kms *dpu_kms); -/** - * dpu_vbif_init_memtypes - initialize xin memory types for vbif - * @dpu_kms: DPU handler - */ void dpu_vbif_init_memtypes(struct dpu_kms *dpu_kms); void dpu_debugfs_vbif_init(struct dpu_kms *dpu_kms, struct dentry *debugfs_root); diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c index 6e4e74f9d63d67..c469e66cfc1187 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_kms.c @@ -568,7 +568,7 @@ MODULE_DEVICE_TABLE(of, mdp4_dt_match); static struct platform_driver mdp4_platform_driver = { .probe = mdp4_probe, - .remove_new = mdp4_remove, + .remove = mdp4_remove, .shutdown = msm_kms_shutdown, .driver = { .name = "mdp4", diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index 374704cce65634..3fcca7a3d82e7a 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -908,7 +908,7 @@ MODULE_DEVICE_TABLE(of, mdp5_dt_match); static struct platform_driver mdp5_driver = { .probe = mdp5_dev_probe, - .remove_new = mdp5_dev_remove, + .remove = mdp5_dev_remove, .shutdown = msm_kms_shutdown, .driver = { .name = "msm_mdp", diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c index 4d55e3cf570f0b..07a2c1e872193b 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot_util.c @@ -25,24 +25,21 @@ static void msm_disp_state_dump_regs(u32 **reg, u32 aligned_len, void __iomem *b addr = base_addr; end_addr = base_addr + aligned_len; - if (!(*reg)) - *reg = kvzalloc(len_padded, GFP_KERNEL); - - if (*reg) - dump_addr = *reg; + *reg = kvzalloc(len_padded, GFP_KERNEL); + if (!*reg) + return; + dump_addr = *reg; for (i = 0; i < num_rows; i++) { x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0; x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 0x4) : 0; x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 0x8) : 0; xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 0xc) : 0; - if (dump_addr) { - dump_addr[i * 4] = x0; - dump_addr[i * 4 + 1] = x4; - dump_addr[i * 4 + 2] = x8; - dump_addr[i * 4 + 3] = xc; - } + dump_addr[i * 4] = x0; + dump_addr[i * 4 + 1] = x4; + dump_addr[i * 4 + 2] = x8; + dump_addr[i * 4 + 3] = xc; addr += REG_DUMP_ALIGN; } diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c index a599fc5d63c524..74e01a5dd4195d 100644 --- a/drivers/gpu/drm/msm/dp/dp_audio.c +++ b/drivers/gpu/drm/msm/dp/dp_audio.c @@ -17,281 +17,281 @@ #include "dp_display.h" #include "dp_utils.h" -struct dp_audio_private { +struct msm_dp_audio_private { struct platform_device *audio_pdev; struct platform_device *pdev; struct drm_device *drm_dev; - struct dp_catalog *catalog; + struct msm_dp_catalog *catalog; u32 channels; - struct dp_audio dp_audio; + struct msm_dp_audio msm_dp_audio; }; -static u32 dp_audio_get_header(struct dp_catalog *catalog, - enum dp_catalog_audio_sdp_type sdp, - enum dp_catalog_audio_header_type header) +static u32 msm_dp_audio_get_header(struct msm_dp_catalog *catalog, + enum msm_dp_catalog_audio_sdp_type sdp, + enum msm_dp_catalog_audio_header_type header) { - return dp_catalog_audio_get_header(catalog, sdp, header); + return msm_dp_catalog_audio_get_header(catalog, sdp, header); } -static void dp_audio_set_header(struct dp_catalog *catalog, +static void msm_dp_audio_set_header(struct msm_dp_catalog *catalog, u32 data, - enum dp_catalog_audio_sdp_type sdp, - enum dp_catalog_audio_header_type header) + enum msm_dp_catalog_audio_sdp_type sdp, + enum msm_dp_catalog_audio_header_type header) { - dp_catalog_audio_set_header(catalog, sdp, header, data); + msm_dp_catalog_audio_set_header(catalog, sdp, header, data); } -static void dp_audio_stream_sdp(struct dp_audio_private *audio) +static void msm_dp_audio_stream_sdp(struct msm_dp_audio_private *audio) { - struct dp_catalog *catalog = audio->catalog; + struct msm_dp_catalog *catalog = audio->catalog; u32 value, new_value; u8 parity_byte; /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); new_value = 0x02; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); new_value = value; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); /* Config header and parity byte 3 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); new_value = audio->channels - 1; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); } -static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) +static void msm_dp_audio_timestamp_sdp(struct msm_dp_audio_private *audio) { - struct dp_catalog *catalog = audio->catalog; + struct msm_dp_catalog *catalog = audio->catalog; u32 value, new_value; u8 parity_byte; /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); new_value = 0x1; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); new_value = 0x17; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); /* Config header and parity byte 3 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); new_value = (0x0 | (0x11 << 2)); - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); } -static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) +static void msm_dp_audio_infoframe_sdp(struct msm_dp_audio_private *audio) { - struct dp_catalog *catalog = audio->catalog; + struct msm_dp_catalog *catalog = audio->catalog; u32 value, new_value; u8 parity_byte; /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); new_value = 0x84; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); new_value = 0x1b; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); /* Config header and parity byte 3 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); new_value = (0x0 | (0x11 << 2)); - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", new_value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); } -static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) +static void msm_dp_audio_copy_management_sdp(struct msm_dp_audio_private *audio) { - struct dp_catalog *catalog = audio->catalog; + struct msm_dp_catalog *catalog = audio->catalog; u32 value, new_value; u8 parity_byte; /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); new_value = 0x05; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); new_value = 0x0F; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); /* Config header and parity byte 3 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); new_value = 0x0; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_3_BIT) | (parity_byte << PARITY_BYTE_3_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); } -static void dp_audio_isrc_sdp(struct dp_audio_private *audio) +static void msm_dp_audio_isrc_sdp(struct msm_dp_audio_private *audio) { - struct dp_catalog *catalog = audio->catalog; + struct msm_dp_catalog *catalog = audio->catalog; u32 value, new_value; u8 parity_byte; /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); new_value = 0x06; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_1_BIT) | (parity_byte << PARITY_BYTE_1_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, + value = msm_dp_audio_get_header(catalog, DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); new_value = 0x0F; - parity_byte = dp_utils_calculate_parity(new_value); + parity_byte = msm_dp_utils_calculate_parity(new_value); value |= ((new_value << HEADER_BYTE_2_BIT) | (parity_byte << PARITY_BYTE_2_BIT)); drm_dbg_dp(audio->drm_dev, "Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", value, parity_byte); - dp_audio_set_header(catalog, value, + msm_dp_audio_set_header(catalog, value, DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); } -static void dp_audio_setup_sdp(struct dp_audio_private *audio) +static void msm_dp_audio_setup_sdp(struct msm_dp_audio_private *audio) { - dp_catalog_audio_config_sdp(audio->catalog); + msm_dp_catalog_audio_config_sdp(audio->catalog); - dp_audio_stream_sdp(audio); - dp_audio_timestamp_sdp(audio); - dp_audio_infoframe_sdp(audio); - dp_audio_copy_management_sdp(audio); - dp_audio_isrc_sdp(audio); + msm_dp_audio_stream_sdp(audio); + msm_dp_audio_timestamp_sdp(audio); + msm_dp_audio_infoframe_sdp(audio); + msm_dp_audio_copy_management_sdp(audio); + msm_dp_audio_isrc_sdp(audio); } -static void dp_audio_setup_acr(struct dp_audio_private *audio) +static void msm_dp_audio_setup_acr(struct msm_dp_audio_private *audio) { u32 select = 0; - struct dp_catalog *catalog = audio->catalog; + struct msm_dp_catalog *catalog = audio->catalog; - switch (audio->dp_audio.bw_code) { + switch (audio->msm_dp_audio.bw_code) { case DP_LINK_BW_1_62: select = 0; break; @@ -310,15 +310,15 @@ static void dp_audio_setup_acr(struct dp_audio_private *audio) break; } - dp_catalog_audio_config_acr(catalog, select); + msm_dp_catalog_audio_config_acr(catalog, select); } -static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio) +static void msm_dp_audio_safe_to_exit_level(struct msm_dp_audio_private *audio) { - struct dp_catalog *catalog = audio->catalog; + struct msm_dp_catalog *catalog = audio->catalog; u32 safe_to_exit_level = 0; - switch (audio->dp_audio.lane_count) { + switch (audio->msm_dp_audio.lane_count) { case 1: safe_to_exit_level = 14; break; @@ -336,49 +336,49 @@ static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio) break; } - dp_catalog_audio_sfe_level(catalog, safe_to_exit_level); + msm_dp_catalog_audio_sfe_level(catalog, safe_to_exit_level); } -static void dp_audio_enable(struct dp_audio_private *audio, bool enable) +static void msm_dp_audio_enable(struct msm_dp_audio_private *audio, bool enable) { - struct dp_catalog *catalog = audio->catalog; + struct msm_dp_catalog *catalog = audio->catalog; - dp_catalog_audio_enable(catalog, enable); + msm_dp_catalog_audio_enable(catalog, enable); } -static struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev) +static struct msm_dp_audio_private *msm_dp_audio_get_data(struct platform_device *pdev) { - struct dp_audio *dp_audio; - struct msm_dp *dp_display; + struct msm_dp_audio *msm_dp_audio; + struct msm_dp *msm_dp_display; if (!pdev) { DRM_ERROR("invalid input\n"); return ERR_PTR(-ENODEV); } - dp_display = platform_get_drvdata(pdev); - if (!dp_display) { + msm_dp_display = platform_get_drvdata(pdev); + if (!msm_dp_display) { DRM_ERROR("invalid input\n"); return ERR_PTR(-ENODEV); } - dp_audio = dp_display->dp_audio; + msm_dp_audio = msm_dp_display->msm_dp_audio; - if (!dp_audio) { - DRM_ERROR("invalid dp_audio data\n"); + if (!msm_dp_audio) { + DRM_ERROR("invalid msm_dp_audio data\n"); return ERR_PTR(-EINVAL); } - return container_of(dp_audio, struct dp_audio_private, dp_audio); + return container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio); } -static int dp_audio_hook_plugged_cb(struct device *dev, void *data, +static int msm_dp_audio_hook_plugged_cb(struct device *dev, void *data, hdmi_codec_plugged_cb fn, struct device *codec_dev) { struct platform_device *pdev; - struct msm_dp *dp_display; + struct msm_dp *msm_dp_display; pdev = to_platform_device(dev); if (!pdev) { @@ -386,20 +386,20 @@ static int dp_audio_hook_plugged_cb(struct device *dev, void *data, return -ENODEV; } - dp_display = platform_get_drvdata(pdev); - if (!dp_display) { + msm_dp_display = platform_get_drvdata(pdev); + if (!msm_dp_display) { pr_err("invalid input\n"); return -ENODEV; } - return dp_display_set_plugged_cb(dp_display, fn, codec_dev); + return msm_dp_display_set_plugged_cb(msm_dp_display, fn, codec_dev); } -static int dp_audio_get_eld(struct device *dev, +static int msm_dp_audio_get_eld(struct device *dev, void *data, uint8_t *buf, size_t len) { struct platform_device *pdev; - struct msm_dp *dp_display; + struct msm_dp *msm_dp_display; pdev = to_platform_device(dev); @@ -408,30 +408,30 @@ static int dp_audio_get_eld(struct device *dev, return -ENODEV; } - dp_display = platform_get_drvdata(pdev); - if (!dp_display) { + msm_dp_display = platform_get_drvdata(pdev); + if (!msm_dp_display) { DRM_ERROR("invalid input\n"); return -ENODEV; } - memcpy(buf, dp_display->connector->eld, - min(sizeof(dp_display->connector->eld), len)); + memcpy(buf, msm_dp_display->connector->eld, + min(sizeof(msm_dp_display->connector->eld), len)); return 0; } -int dp_audio_hw_params(struct device *dev, +int msm_dp_audio_hw_params(struct device *dev, void *data, struct hdmi_codec_daifmt *daifmt, struct hdmi_codec_params *params) { int rc = 0; - struct dp_audio_private *audio; + struct msm_dp_audio_private *audio; struct platform_device *pdev; - struct msm_dp *dp_display; + struct msm_dp *msm_dp_display; pdev = to_platform_device(dev); - dp_display = platform_get_drvdata(pdev); + msm_dp_display = platform_get_drvdata(pdev); /* * there could be cases where sound card can be opened even @@ -441,12 +441,12 @@ int dp_audio_hw_params(struct device *dev, * such cases check for connection status and bail out if not * connected. */ - if (!dp_display->power_on) { + if (!msm_dp_display->power_on) { rc = -EINVAL; goto end; } - audio = dp_audio_get_data(pdev); + audio = msm_dp_audio_get_data(pdev); if (IS_ERR(audio)) { rc = PTR_ERR(audio); goto end; @@ -454,26 +454,26 @@ int dp_audio_hw_params(struct device *dev, audio->channels = params->channels; - dp_audio_setup_sdp(audio); - dp_audio_setup_acr(audio); - dp_audio_safe_to_exit_level(audio); - dp_audio_enable(audio, true); - dp_display_signal_audio_start(dp_display); - dp_display->audio_enabled = true; + msm_dp_audio_setup_sdp(audio); + msm_dp_audio_setup_acr(audio); + msm_dp_audio_safe_to_exit_level(audio); + msm_dp_audio_enable(audio, true); + msm_dp_display_signal_audio_start(msm_dp_display); + msm_dp_display->audio_enabled = true; end: return rc; } -static void dp_audio_shutdown(struct device *dev, void *data) +static void msm_dp_audio_shutdown(struct device *dev, void *data) { - struct dp_audio_private *audio; + struct msm_dp_audio_private *audio; struct platform_device *pdev; - struct msm_dp *dp_display; + struct msm_dp *msm_dp_display; pdev = to_platform_device(dev); - dp_display = platform_get_drvdata(pdev); - audio = dp_audio_get_data(pdev); + msm_dp_display = platform_get_drvdata(pdev); + audio = msm_dp_audio_get_data(pdev); if (IS_ERR(audio)) { DRM_ERROR("failed to get audio data\n"); return; @@ -487,32 +487,32 @@ static void dp_audio_shutdown(struct device *dev, void *data) * connected. is_connected cannot be used here as its set * to false earlier than this call */ - if (!dp_display->audio_enabled) + if (!msm_dp_display->audio_enabled) return; - dp_audio_enable(audio, false); + msm_dp_audio_enable(audio, false); /* signal the dp display to safely shutdown clocks */ - dp_display_signal_audio_complete(dp_display); + msm_dp_display_signal_audio_complete(msm_dp_display); } -static const struct hdmi_codec_ops dp_audio_codec_ops = { - .hw_params = dp_audio_hw_params, - .audio_shutdown = dp_audio_shutdown, - .get_eld = dp_audio_get_eld, - .hook_plugged_cb = dp_audio_hook_plugged_cb, +static const struct hdmi_codec_ops msm_dp_audio_codec_ops = { + .hw_params = msm_dp_audio_hw_params, + .audio_shutdown = msm_dp_audio_shutdown, + .get_eld = msm_dp_audio_get_eld, + .hook_plugged_cb = msm_dp_audio_hook_plugged_cb, }; static struct hdmi_codec_pdata codec_data = { - .ops = &dp_audio_codec_ops, + .ops = &msm_dp_audio_codec_ops, .max_i2s_channels = 8, .i2s = 1, }; -void dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio) +void msm_dp_unregister_audio_driver(struct device *dev, struct msm_dp_audio *msm_dp_audio) { - struct dp_audio_private *audio_priv; + struct msm_dp_audio_private *audio_priv; - audio_priv = container_of(dp_audio, struct dp_audio_private, dp_audio); + audio_priv = container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio); if (audio_priv->audio_pdev) { platform_device_unregister(audio_priv->audio_pdev); @@ -520,13 +520,13 @@ void dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio) } } -int dp_register_audio_driver(struct device *dev, - struct dp_audio *dp_audio) +int msm_dp_register_audio_driver(struct device *dev, + struct msm_dp_audio *msm_dp_audio) { - struct dp_audio_private *audio_priv; + struct msm_dp_audio_private *audio_priv; - audio_priv = container_of(dp_audio, - struct dp_audio_private, dp_audio); + audio_priv = container_of(msm_dp_audio, + struct msm_dp_audio_private, msm_dp_audio); audio_priv->audio_pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, @@ -536,13 +536,13 @@ int dp_register_audio_driver(struct device *dev, return PTR_ERR_OR_ZERO(audio_priv->audio_pdev); } -struct dp_audio *dp_audio_get(struct platform_device *pdev, - struct dp_panel *panel, - struct dp_catalog *catalog) +struct msm_dp_audio *msm_dp_audio_get(struct platform_device *pdev, + struct msm_dp_panel *panel, + struct msm_dp_catalog *catalog) { int rc = 0; - struct dp_audio_private *audio; - struct dp_audio *dp_audio; + struct msm_dp_audio_private *audio; + struct msm_dp_audio *msm_dp_audio; if (!pdev || !panel || !catalog) { DRM_ERROR("invalid input\n"); @@ -559,23 +559,23 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev, audio->pdev = pdev; audio->catalog = catalog; - dp_audio = &audio->dp_audio; + msm_dp_audio = &audio->msm_dp_audio; - dp_catalog_audio_init(catalog); + msm_dp_catalog_audio_init(catalog); - return dp_audio; + return msm_dp_audio; error: return ERR_PTR(rc); } -void dp_audio_put(struct dp_audio *dp_audio) +void msm_dp_audio_put(struct msm_dp_audio *msm_dp_audio) { - struct dp_audio_private *audio; + struct msm_dp_audio_private *audio; - if (!dp_audio) + if (!msm_dp_audio) return; - audio = container_of(dp_audio, struct dp_audio_private, dp_audio); + audio = container_of(msm_dp_audio, struct msm_dp_audio_private, msm_dp_audio); devm_kfree(&audio->pdev->dev, audio); } diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h index 4ab78880af8296..1c9efaaa40e587 100644 --- a/drivers/gpu/drm/msm/dp/dp_audio.h +++ b/drivers/gpu/drm/msm/dp/dp_audio.h @@ -13,58 +13,58 @@ #include /** - * struct dp_audio + * struct msm_dp_audio * @lane_count: number of lanes configured in current session * @bw_code: link rate's bandwidth code for current session */ -struct dp_audio { +struct msm_dp_audio { u32 lane_count; u32 bw_code; }; /** - * dp_audio_get() + * msm_dp_audio_get() * * Creates and instance of dp audio. * * @pdev: caller's platform device instance. - * @panel: an instance of dp_panel module. - * @catalog: an instance of dp_catalog module. + * @panel: an instance of msm_dp_panel module. + * @catalog: an instance of msm_dp_catalog module. * * Returns the error code in case of failure, otherwize - * an instance of newly created dp_module. + * an instance of newly created msm_dp_module. */ -struct dp_audio *dp_audio_get(struct platform_device *pdev, - struct dp_panel *panel, - struct dp_catalog *catalog); +struct msm_dp_audio *msm_dp_audio_get(struct platform_device *pdev, + struct msm_dp_panel *panel, + struct msm_dp_catalog *catalog); /** - * dp_register_audio_driver() + * msm_dp_register_audio_driver() * * Registers DP device with hdmi_codec interface. * * @dev: DP device instance. - * @dp_audio: an instance of dp_audio module. + * @msm_dp_audio: an instance of msm_dp_audio module. * * * Returns the error code in case of failure, otherwise * zero on success. */ -int dp_register_audio_driver(struct device *dev, - struct dp_audio *dp_audio); +int msm_dp_register_audio_driver(struct device *dev, + struct msm_dp_audio *msm_dp_audio); -void dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio); +void msm_dp_unregister_audio_driver(struct device *dev, struct msm_dp_audio *msm_dp_audio); /** - * dp_audio_put() + * msm_dp_audio_put() * - * Cleans the dp_audio instance. + * Cleans the msm_dp_audio instance. * - * @dp_audio: an instance of dp_audio. + * @msm_dp_audio: an instance of msm_dp_audio. */ -void dp_audio_put(struct dp_audio *dp_audio); +void msm_dp_audio_put(struct msm_dp_audio *msm_dp_audio); -int dp_audio_hw_params(struct device *dev, +int msm_dp_audio_hw_params(struct device *dev, void *data, struct hdmi_codec_daifmt *daifmt, struct hdmi_codec_params *params); diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index 00dfafbebe0e54..bc8d46abfc619d 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -20,9 +20,9 @@ enum msm_dp_aux_err { DP_AUX_ERR_PHY, }; -struct dp_aux_private { +struct msm_dp_aux_private { struct device *dev; - struct dp_catalog *catalog; + struct msm_dp_catalog *catalog; struct phy *phy; @@ -42,12 +42,12 @@ struct dp_aux_private { u32 offset; u32 segment; - struct drm_dp_aux dp_aux; + struct drm_dp_aux msm_dp_aux; }; #define MAX_AUX_RETRIES 5 -static ssize_t dp_aux_write(struct dp_aux_private *aux, +static ssize_t msm_dp_aux_write(struct msm_dp_aux_private *aux, struct drm_dp_aux_msg *msg) { u8 data[4]; @@ -88,11 +88,11 @@ static ssize_t dp_aux_write(struct dp_aux_private *aux, /* index = 0, write */ if (i == 0) reg |= DP_AUX_DATA_INDEX_WRITE; - dp_catalog_aux_write_data(aux->catalog, reg); + msm_dp_catalog_aux_write_data(aux->catalog, reg); } - dp_catalog_aux_clear_trans(aux->catalog, false); - dp_catalog_aux_clear_hw_interrupts(aux->catalog); + msm_dp_catalog_aux_clear_trans(aux->catalog, false); + msm_dp_catalog_aux_clear_hw_interrupts(aux->catalog); reg = 0; /* Transaction number == 1 */ if (!aux->native) { /* i2c */ @@ -106,12 +106,12 @@ static ssize_t dp_aux_write(struct dp_aux_private *aux, } reg |= DP_AUX_TRANS_CTRL_GO; - dp_catalog_aux_write_trans(aux->catalog, reg); + msm_dp_catalog_aux_write_trans(aux->catalog, reg); return len; } -static ssize_t dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, +static ssize_t msm_dp_aux_cmd_fifo_tx(struct msm_dp_aux_private *aux, struct drm_dp_aux_msg *msg) { ssize_t ret; @@ -119,7 +119,7 @@ static ssize_t dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, reinit_completion(&aux->comp); - ret = dp_aux_write(aux, msg); + ret = msm_dp_aux_write(aux, msg); if (ret < 0) return ret; @@ -131,7 +131,7 @@ static ssize_t dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, return ret; } -static ssize_t dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, +static ssize_t msm_dp_aux_cmd_fifo_rx(struct msm_dp_aux_private *aux, struct drm_dp_aux_msg *msg) { u32 data; @@ -139,20 +139,20 @@ static ssize_t dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, u32 i, actual_i; u32 len = msg->size; - dp_catalog_aux_clear_trans(aux->catalog, true); + msm_dp_catalog_aux_clear_trans(aux->catalog, true); data = DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */ data |= DP_AUX_DATA_READ; /* read */ - dp_catalog_aux_write_data(aux->catalog, data); + msm_dp_catalog_aux_write_data(aux->catalog, data); dp = msg->buffer; /* discard first byte */ - data = dp_catalog_aux_read_data(aux->catalog); + data = msm_dp_catalog_aux_read_data(aux->catalog); for (i = 0; i < len; i++) { - data = dp_catalog_aux_read_data(aux->catalog); + data = msm_dp_catalog_aux_read_data(aux->catalog); *dp++ = (u8)((data >> DP_AUX_DATA_OFFSET) & 0xff); actual_i = (data >> DP_AUX_DATA_INDEX_OFFSET) & 0xFF; @@ -163,7 +163,7 @@ static ssize_t dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, return i; } -static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, +static void msm_dp_aux_update_offset_and_segment(struct msm_dp_aux_private *aux, struct drm_dp_aux_msg *input_msg) { u32 edid_address = 0x50; @@ -185,7 +185,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, } /** - * dp_aux_transfer_helper() - helper function for EDID read transactions + * msm_dp_aux_transfer_helper() - helper function for EDID read transactions * * @aux: DP AUX private structure * @input_msg: input message from DRM upstream APIs @@ -196,7 +196,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, * This helper function is used to fix EDID reads for non-compliant * sinks that do not handle the i2c middle-of-transaction flag correctly. */ -static void dp_aux_transfer_helper(struct dp_aux_private *aux, +static void msm_dp_aux_transfer_helper(struct msm_dp_aux_private *aux, struct drm_dp_aux_msg *input_msg, bool send_seg) { @@ -238,7 +238,7 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, helper_msg.address = segment_address; helper_msg.buffer = &aux->segment; helper_msg.size = 1; - dp_aux_cmd_fifo_tx(aux, &helper_msg); + msm_dp_aux_cmd_fifo_tx(aux, &helper_msg); } /* @@ -252,7 +252,7 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, helper_msg.address = input_msg->address; helper_msg.buffer = &aux->offset; helper_msg.size = 1; - dp_aux_cmd_fifo_tx(aux, &helper_msg); + msm_dp_aux_cmd_fifo_tx(aux, &helper_msg); end: aux->offset += message_size; @@ -265,15 +265,15 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux, * It will call aux_reset() function to reset the AUX channel, * if the waiting is timeout. */ -static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, +static ssize_t msm_dp_aux_transfer(struct drm_dp_aux *msm_dp_aux, struct drm_dp_aux_msg *msg) { ssize_t ret; int const aux_cmd_native_max = 16; int const aux_cmd_i2c_max = 128; - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux); aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); @@ -292,7 +292,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, return -EINVAL; } - ret = pm_runtime_resume_and_get(dp_aux->dev); + ret = pm_runtime_resume_and_get(msm_dp_aux->dev); if (ret) return ret; @@ -313,8 +313,8 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, goto exit; } - dp_aux_update_offset_and_segment(aux, msg); - dp_aux_transfer_helper(aux, msg, true); + msm_dp_aux_update_offset_and_segment(aux, msg); + msm_dp_aux_transfer_helper(aux, msg, true); aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); aux->cmd_busy = true; @@ -327,7 +327,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, aux->no_send_stop = true; } - ret = dp_aux_cmd_fifo_tx(aux, msg); + ret = msm_dp_aux_cmd_fifo_tx(aux, msg); if (ret < 0) { if (aux->native) { aux->retry_cnt++; @@ -335,14 +335,14 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, phy_calibrate(aux->phy); } /* reset aux if link is in connected state */ - if (dp_catalog_link_is_connected(aux->catalog)) - dp_catalog_aux_reset(aux->catalog); + if (msm_dp_catalog_link_is_connected(aux->catalog)) + msm_dp_catalog_aux_reset(aux->catalog); } else { aux->retry_cnt = 0; switch (aux->aux_error_num) { case DP_AUX_ERR_NONE: if (aux->read) - ret = dp_aux_cmd_fifo_rx(aux, msg); + ret = msm_dp_aux_cmd_fifo_rx(aux, msg); msg->reply = aux->native ? DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; break; case DP_AUX_ERR_DEFER: @@ -364,24 +364,24 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, exit: mutex_unlock(&aux->mutex); - pm_runtime_put_sync(dp_aux->dev); + pm_runtime_put_sync(msm_dp_aux->dev); return ret; } -irqreturn_t dp_aux_isr(struct drm_dp_aux *dp_aux) +irqreturn_t msm_dp_aux_isr(struct drm_dp_aux *msm_dp_aux) { u32 isr; - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; - if (!dp_aux) { + if (!msm_dp_aux) { DRM_ERROR("invalid input\n"); return IRQ_NONE; } - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux); - isr = dp_catalog_aux_get_irq(aux->catalog); + isr = msm_dp_catalog_aux_get_irq(aux->catalog); /* no interrupts pending, return immediately */ if (!isr) @@ -403,7 +403,7 @@ irqreturn_t dp_aux_isr(struct drm_dp_aux *dp_aux) if (isr & DP_INTR_AUX_ERROR) { aux->aux_error_num = DP_AUX_ERR_PHY; - dp_catalog_aux_clear_hw_interrupts(aux->catalog); + msm_dp_catalog_aux_clear_hw_interrupts(aux->catalog); } else if (isr & DP_INTR_NACK_DEFER) { aux->aux_error_num = DP_AUX_ERR_NACK_DEFER; } else if (isr & DP_INTR_WRONG_ADDR) { @@ -429,68 +429,68 @@ irqreturn_t dp_aux_isr(struct drm_dp_aux *dp_aux) return IRQ_HANDLED; } -void dp_aux_enable_xfers(struct drm_dp_aux *dp_aux, bool enabled) +void msm_dp_aux_enable_xfers(struct drm_dp_aux *msm_dp_aux, bool enabled) { - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux); aux->enable_xfers = enabled; } -void dp_aux_reconfig(struct drm_dp_aux *dp_aux) +void msm_dp_aux_reconfig(struct drm_dp_aux *msm_dp_aux) { - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux); phy_calibrate(aux->phy); - dp_catalog_aux_reset(aux->catalog); + msm_dp_catalog_aux_reset(aux->catalog); } -void dp_aux_init(struct drm_dp_aux *dp_aux) +void msm_dp_aux_init(struct drm_dp_aux *msm_dp_aux) { - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; - if (!dp_aux) { + if (!msm_dp_aux) { DRM_ERROR("invalid input\n"); return; } - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux); mutex_lock(&aux->mutex); - dp_catalog_aux_enable(aux->catalog, true); + msm_dp_catalog_aux_enable(aux->catalog, true); aux->retry_cnt = 0; aux->initted = true; mutex_unlock(&aux->mutex); } -void dp_aux_deinit(struct drm_dp_aux *dp_aux) +void msm_dp_aux_deinit(struct drm_dp_aux *msm_dp_aux) { - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux); mutex_lock(&aux->mutex); aux->initted = false; - dp_catalog_aux_enable(aux->catalog, false); + msm_dp_catalog_aux_enable(aux->catalog, false); mutex_unlock(&aux->mutex); } -int dp_aux_register(struct drm_dp_aux *dp_aux) +int msm_dp_aux_register(struct drm_dp_aux *msm_dp_aux) { int ret; - if (!dp_aux) { + if (!msm_dp_aux) { DRM_ERROR("invalid input\n"); return -EINVAL; } - ret = drm_dp_aux_register(dp_aux); + ret = drm_dp_aux_register(msm_dp_aux); if (ret) { DRM_ERROR("%s: failed to register drm aux: %d\n", __func__, ret); @@ -500,34 +500,34 @@ int dp_aux_register(struct drm_dp_aux *dp_aux) return 0; } -void dp_aux_unregister(struct drm_dp_aux *dp_aux) +void msm_dp_aux_unregister(struct drm_dp_aux *msm_dp_aux) { - drm_dp_aux_unregister(dp_aux); + drm_dp_aux_unregister(msm_dp_aux); } -static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux, +static int msm_dp_wait_hpd_asserted(struct drm_dp_aux *msm_dp_aux, unsigned long wait_us) { int ret; - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux); ret = pm_runtime_resume_and_get(aux->dev); if (ret) return ret; - ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog, wait_us); + ret = msm_dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog, wait_us); pm_runtime_put_sync(aux->dev); return ret; } -struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog, +struct drm_dp_aux *msm_dp_aux_get(struct device *dev, struct msm_dp_catalog *catalog, struct phy *phy, bool is_edp) { - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; if (!catalog) { DRM_ERROR("invalid input\n"); @@ -553,23 +553,23 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog, * before registering AUX with the DRM device so that * msm eDP panel can be detected by generic_dep_panel_probe(). */ - aux->dp_aux.name = "dpu_dp_aux"; - aux->dp_aux.dev = dev; - aux->dp_aux.transfer = dp_aux_transfer; - aux->dp_aux.wait_hpd_asserted = dp_wait_hpd_asserted; - drm_dp_aux_init(&aux->dp_aux); + aux->msm_dp_aux.name = "dpu_dp_aux"; + aux->msm_dp_aux.dev = dev; + aux->msm_dp_aux.transfer = msm_dp_aux_transfer; + aux->msm_dp_aux.wait_hpd_asserted = msm_dp_wait_hpd_asserted; + drm_dp_aux_init(&aux->msm_dp_aux); - return &aux->dp_aux; + return &aux->msm_dp_aux; } -void dp_aux_put(struct drm_dp_aux *dp_aux) +void msm_dp_aux_put(struct drm_dp_aux *msm_dp_aux) { - struct dp_aux_private *aux; + struct msm_dp_aux_private *aux; - if (!dp_aux) + if (!msm_dp_aux) return; - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + aux = container_of(msm_dp_aux, struct msm_dp_aux_private, msm_dp_aux); mutex_destroy(&aux->mutex); diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h index 4f65e892a80760..39c5b4c8596ab2 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.h +++ b/drivers/gpu/drm/msm/dp/dp_aux.h @@ -9,18 +9,18 @@ #include "dp_catalog.h" #include -int dp_aux_register(struct drm_dp_aux *dp_aux); -void dp_aux_unregister(struct drm_dp_aux *dp_aux); -irqreturn_t dp_aux_isr(struct drm_dp_aux *dp_aux); -void dp_aux_enable_xfers(struct drm_dp_aux *dp_aux, bool enabled); -void dp_aux_init(struct drm_dp_aux *dp_aux); -void dp_aux_deinit(struct drm_dp_aux *dp_aux); -void dp_aux_reconfig(struct drm_dp_aux *dp_aux); +int msm_dp_aux_register(struct drm_dp_aux *msm_dp_aux); +void msm_dp_aux_unregister(struct drm_dp_aux *msm_dp_aux); +irqreturn_t msm_dp_aux_isr(struct drm_dp_aux *msm_dp_aux); +void msm_dp_aux_enable_xfers(struct drm_dp_aux *msm_dp_aux, bool enabled); +void msm_dp_aux_init(struct drm_dp_aux *msm_dp_aux); +void msm_dp_aux_deinit(struct drm_dp_aux *msm_dp_aux); +void msm_dp_aux_reconfig(struct drm_dp_aux *msm_dp_aux); struct phy; -struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog, +struct drm_dp_aux *msm_dp_aux_get(struct device *dev, struct msm_dp_catalog *catalog, struct phy *phy, bool is_edp); -void dp_aux_put(struct drm_dp_aux *aux); +void msm_dp_aux_put(struct drm_dp_aux *aux); #endif /*__DP_AUX_H_*/ diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 6e55cbf696748a..b4c8856fb25d01 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -75,18 +75,18 @@ struct dss_io_data { struct dss_io_region p0; }; -struct dp_catalog_private { +struct msm_dp_catalog_private { struct device *dev; struct drm_device *drm_dev; struct dss_io_data io; u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX]; - struct dp_catalog dp_catalog; + struct msm_dp_catalog msm_dp_catalog; }; -void dp_catalog_snapshot(struct dp_catalog *dp_catalog, struct msm_disp_state *disp_state) +void msm_dp_catalog_snapshot(struct msm_dp_catalog *msm_dp_catalog, struct msm_disp_state *disp_state) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); struct dss_io_data *dss = &catalog->io; msm_disp_snapshot_add_block(disp_state, dss->ahb.len, dss->ahb.base, "dp_ahb"); @@ -95,12 +95,12 @@ void dp_catalog_snapshot(struct dp_catalog *dp_catalog, struct msm_disp_state *d msm_disp_snapshot_add_block(disp_state, dss->p0.len, dss->p0.base, "dp_p0"); } -static inline u32 dp_read_aux(struct dp_catalog_private *catalog, u32 offset) +static inline u32 msm_dp_read_aux(struct msm_dp_catalog_private *catalog, u32 offset) { return readl_relaxed(catalog->io.aux.base + offset); } -static inline void dp_write_aux(struct dp_catalog_private *catalog, +static inline void msm_dp_write_aux(struct msm_dp_catalog_private *catalog, u32 offset, u32 data) { /* @@ -110,12 +110,12 @@ static inline void dp_write_aux(struct dp_catalog_private *catalog, writel(data, catalog->io.aux.base + offset); } -static inline u32 dp_read_ahb(const struct dp_catalog_private *catalog, u32 offset) +static inline u32 msm_dp_read_ahb(const struct msm_dp_catalog_private *catalog, u32 offset) { return readl_relaxed(catalog->io.ahb.base + offset); } -static inline void dp_write_ahb(struct dp_catalog_private *catalog, +static inline void msm_dp_write_ahb(struct msm_dp_catalog_private *catalog, u32 offset, u32 data) { /* @@ -125,7 +125,7 @@ static inline void dp_write_ahb(struct dp_catalog_private *catalog, writel(data, catalog->io.ahb.base + offset); } -static inline void dp_write_p0(struct dp_catalog_private *catalog, +static inline void msm_dp_write_p0(struct msm_dp_catalog_private *catalog, u32 offset, u32 data) { /* @@ -135,7 +135,7 @@ static inline void dp_write_p0(struct dp_catalog_private *catalog, writel(data, catalog->io.p0.base + offset); } -static inline u32 dp_read_p0(struct dp_catalog_private *catalog, +static inline u32 msm_dp_read_p0(struct msm_dp_catalog_private *catalog, u32 offset) { /* @@ -145,12 +145,12 @@ static inline u32 dp_read_p0(struct dp_catalog_private *catalog, return readl_relaxed(catalog->io.p0.base + offset); } -static inline u32 dp_read_link(struct dp_catalog_private *catalog, u32 offset) +static inline u32 msm_dp_read_link(struct msm_dp_catalog_private *catalog, u32 offset) { return readl_relaxed(catalog->io.link.base + offset); } -static inline void dp_write_link(struct dp_catalog_private *catalog, +static inline void msm_dp_write_link(struct msm_dp_catalog_private *catalog, u32 offset, u32 data) { /* @@ -161,64 +161,64 @@ static inline void dp_write_link(struct dp_catalog_private *catalog, } /* aux related catalog functions */ -u32 dp_catalog_aux_read_data(struct dp_catalog *dp_catalog) +u32 msm_dp_catalog_aux_read_data(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - return dp_read_aux(catalog, REG_DP_AUX_DATA); + return msm_dp_read_aux(catalog, REG_DP_AUX_DATA); } -int dp_catalog_aux_write_data(struct dp_catalog *dp_catalog, u32 data) +int msm_dp_catalog_aux_write_data(struct msm_dp_catalog *msm_dp_catalog, u32 data) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - dp_write_aux(catalog, REG_DP_AUX_DATA, data); + msm_dp_write_aux(catalog, REG_DP_AUX_DATA, data); return 0; } -int dp_catalog_aux_write_trans(struct dp_catalog *dp_catalog, u32 data) +int msm_dp_catalog_aux_write_trans(struct msm_dp_catalog *msm_dp_catalog, u32 data) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, data); + msm_dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, data); return 0; } -int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, bool read) +int msm_dp_catalog_aux_clear_trans(struct msm_dp_catalog *msm_dp_catalog, bool read) { u32 data; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); if (read) { - data = dp_read_aux(catalog, REG_DP_AUX_TRANS_CTRL); + data = msm_dp_read_aux(catalog, REG_DP_AUX_TRANS_CTRL); data &= ~DP_AUX_TRANS_CTRL_GO; - dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, data); + msm_dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, data); } else { - dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, 0); + msm_dp_write_aux(catalog, REG_DP_AUX_TRANS_CTRL, 0); } return 0; } -int dp_catalog_aux_clear_hw_interrupts(struct dp_catalog *dp_catalog) +int msm_dp_catalog_aux_clear_hw_interrupts(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - dp_read_aux(catalog, REG_DP_PHY_AUX_INTERRUPT_STATUS); - dp_write_aux(catalog, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f); - dp_write_aux(catalog, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f); - dp_write_aux(catalog, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0); + msm_dp_read_aux(catalog, REG_DP_PHY_AUX_INTERRUPT_STATUS); + msm_dp_write_aux(catalog, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f); + msm_dp_write_aux(catalog, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f); + msm_dp_write_aux(catalog, REG_DP_PHY_AUX_INTERRUPT_CLEAR, 0); return 0; } /** - * dp_catalog_aux_reset() - reset AUX controller + * msm_dp_catalog_aux_reset() - reset AUX controller * - * @dp_catalog: DP catalog structure + * @msm_dp_catalog: DP catalog structure * * return: void * @@ -227,47 +227,47 @@ int dp_catalog_aux_clear_hw_interrupts(struct dp_catalog *dp_catalog) * NOTE: reset AUX controller will also clear any pending HPD related interrupts * */ -void dp_catalog_aux_reset(struct dp_catalog *dp_catalog) +void msm_dp_catalog_aux_reset(struct msm_dp_catalog *msm_dp_catalog) { u32 aux_ctrl; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - aux_ctrl = dp_read_aux(catalog, REG_DP_AUX_CTRL); + aux_ctrl = msm_dp_read_aux(catalog, REG_DP_AUX_CTRL); aux_ctrl |= DP_AUX_CTRL_RESET; - dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl); + msm_dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl); usleep_range(1000, 1100); /* h/w recommended delay */ aux_ctrl &= ~DP_AUX_CTRL_RESET; - dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl); + msm_dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl); } -void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable) +void msm_dp_catalog_aux_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable) { u32 aux_ctrl; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - aux_ctrl = dp_read_aux(catalog, REG_DP_AUX_CTRL); + aux_ctrl = msm_dp_read_aux(catalog, REG_DP_AUX_CTRL); if (enable) { - dp_write_aux(catalog, REG_DP_TIMEOUT_COUNT, 0xffff); - dp_write_aux(catalog, REG_DP_AUX_LIMITS, 0xffff); + msm_dp_write_aux(catalog, REG_DP_TIMEOUT_COUNT, 0xffff); + msm_dp_write_aux(catalog, REG_DP_AUX_LIMITS, 0xffff); aux_ctrl |= DP_AUX_CTRL_ENABLE; } else { aux_ctrl &= ~DP_AUX_CTRL_ENABLE; } - dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl); + msm_dp_write_aux(catalog, REG_DP_AUX_CTRL, aux_ctrl); } -int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog, +int msm_dp_catalog_aux_wait_for_hpd_connect_state(struct msm_dp_catalog *msm_dp_catalog, unsigned long wait_us) { u32 state; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); /* poll for hpd connected status every 2ms and timeout after wait_us */ return readl_poll_timeout(catalog->io.aux.base + @@ -294,10 +294,10 @@ static void dump_regs(void __iomem *base, int len) } } -void dp_catalog_dump_regs(struct dp_catalog *dp_catalog) +void msm_dp_catalog_dump_regs(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); struct dss_io_data *io = &catalog->io; pr_info("AHB regs\n"); @@ -313,17 +313,17 @@ void dp_catalog_dump_regs(struct dp_catalog *dp_catalog) dump_regs(io->p0.base, io->p0.len); } -u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog) +u32 msm_dp_catalog_aux_get_irq(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 intr, intr_ack; - intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS); + intr = msm_dp_read_ahb(catalog, REG_DP_INTR_STATUS); intr &= ~DP_INTERRUPT_STATUS1_MASK; intr_ack = (intr & DP_INTERRUPT_STATUS1) << DP_INTERRUPT_STATUS_ACK_SHIFT; - dp_write_ahb(catalog, REG_DP_INTR_STATUS, intr_ack | + msm_dp_write_ahb(catalog, REG_DP_INTR_STATUS, intr_ack | DP_INTERRUPT_STATUS1_MASK); return intr; @@ -331,40 +331,40 @@ u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog) } /* controller related catalog functions */ -void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog *dp_catalog, - u32 dp_tu, u32 valid_boundary, +void msm_dp_catalog_ctrl_update_transfer_unit(struct msm_dp_catalog *msm_dp_catalog, + u32 msm_dp_tu, u32 valid_boundary, u32 valid_boundary2) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - dp_write_link(catalog, REG_DP_VALID_BOUNDARY, valid_boundary); - dp_write_link(catalog, REG_DP_TU, dp_tu); - dp_write_link(catalog, REG_DP_VALID_BOUNDARY_2, valid_boundary2); + msm_dp_write_link(catalog, REG_DP_VALID_BOUNDARY, valid_boundary); + msm_dp_write_link(catalog, REG_DP_TU, msm_dp_tu); + msm_dp_write_link(catalog, REG_DP_VALID_BOUNDARY_2, valid_boundary2); } -void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state) +void msm_dp_catalog_ctrl_state_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 state) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - dp_write_link(catalog, REG_DP_STATE_CTRL, state); + msm_dp_write_link(catalog, REG_DP_STATE_CTRL, state); } -void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 cfg) +void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 cfg) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); drm_dbg_dp(catalog->drm_dev, "DP_CONFIGURATION_CTRL=0x%x\n", cfg); - dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg); + msm_dp_write_link(catalog, REG_DP_CONFIGURATION_CTRL, cfg); } -void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog) +void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */ u32 ln_mapping; @@ -373,71 +373,71 @@ void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog) ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT; ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT; - dp_write_link(catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING, + msm_dp_write_link(catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING, ln_mapping); } -void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, +void msm_dp_catalog_ctrl_psr_mainlink_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable) { u32 val; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - val = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + val = msm_dp_read_link(catalog, REG_DP_MAINLINK_CTRL); if (enable) val |= DP_MAINLINK_CTRL_ENABLE; else val &= ~DP_MAINLINK_CTRL_ENABLE; - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, val); } -void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, +void msm_dp_catalog_ctrl_mainlink_ctrl(struct msm_dp_catalog *msm_dp_catalog, bool enable) { u32 mainlink_ctrl; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); drm_dbg_dp(catalog->drm_dev, "enable=%d\n", enable); if (enable) { /* * To make sure link reg writes happens before other operation, - * dp_write_link() function uses writel() + * msm_dp_write_link() function uses writel() */ - mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + mainlink_ctrl = msm_dp_read_link(catalog, REG_DP_MAINLINK_CTRL); mainlink_ctrl &= ~(DP_MAINLINK_CTRL_RESET | DP_MAINLINK_CTRL_ENABLE); - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); mainlink_ctrl |= DP_MAINLINK_CTRL_RESET; - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); mainlink_ctrl &= ~DP_MAINLINK_CTRL_RESET; - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); mainlink_ctrl |= (DP_MAINLINK_CTRL_ENABLE | DP_MAINLINK_FB_BOUNDARY_SEL); - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); } else { - mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + mainlink_ctrl = msm_dp_read_link(catalog, REG_DP_MAINLINK_CTRL); mainlink_ctrl &= ~DP_MAINLINK_CTRL_ENABLE; - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); } } -void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, +void msm_dp_catalog_ctrl_config_misc(struct msm_dp_catalog *msm_dp_catalog, u32 colorimetry_cfg, u32 test_bits_depth) { u32 misc_val; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - misc_val = dp_read_link(catalog, REG_DP_MISC1_MISC0); + misc_val = msm_dp_read_link(catalog, REG_DP_MISC1_MISC0); /* clear bpp bits */ misc_val &= ~(0x07 << DP_MISC0_TEST_BITS_DEPTH_SHIFT); @@ -447,27 +447,27 @@ void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, misc_val |= DP_MISC0_SYNCHRONOUS_CLK; drm_dbg_dp(catalog->drm_dev, "misc settings = 0x%x\n", misc_val); - dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val); + msm_dp_write_link(catalog, REG_DP_MISC1_MISC0, misc_val); } -void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog) +void msm_dp_catalog_setup_peripheral_flush(struct msm_dp_catalog *msm_dp_catalog) { u32 mainlink_ctrl, hw_revision; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - mainlink_ctrl = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + mainlink_ctrl = msm_dp_read_link(catalog, REG_DP_MAINLINK_CTRL); - hw_revision = dp_catalog_hw_revision(dp_catalog); + hw_revision = msm_dp_catalog_hw_revision(msm_dp_catalog); if (hw_revision >= DP_HW_VERSION_1_2) mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE; else mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP; - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl); } -void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, +void msm_dp_catalog_ctrl_config_msa(struct msm_dp_catalog *msm_dp_catalog, u32 rate, u32 stream_rate_khz, bool is_ycbcr_420) { @@ -478,8 +478,8 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 const link_rate_hbr3 = 810000; unsigned long den, num; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); if (rate == link_rate_hbr3) pixel_div = 6; @@ -522,22 +522,22 @@ void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, nvid *= 3; drm_dbg_dp(catalog->drm_dev, "mvid=0x%x, nvid=0x%x\n", mvid, nvid); - dp_write_link(catalog, REG_DP_SOFTWARE_MVID, mvid); - dp_write_link(catalog, REG_DP_SOFTWARE_NVID, nvid); - dp_write_p0(catalog, MMSS_DP_DSC_DTO, 0x0); + msm_dp_write_link(catalog, REG_DP_SOFTWARE_MVID, mvid); + msm_dp_write_link(catalog, REG_DP_SOFTWARE_NVID, nvid); + msm_dp_write_p0(catalog, MMSS_DP_DSC_DTO, 0x0); } -int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, +int msm_dp_catalog_ctrl_set_pattern_state_bit(struct msm_dp_catalog *msm_dp_catalog, u32 state_bit) { int bit, ret; u32 data; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); bit = BIT(state_bit - 1); drm_dbg_dp(catalog->drm_dev, "hw: bit=%d train=%d\n", bit, state_bit); - dp_catalog_ctrl_state_ctrl(dp_catalog, bit); + msm_dp_catalog_ctrl_state_ctrl(msm_dp_catalog, bit); bit = BIT(state_bit - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT; @@ -554,25 +554,25 @@ int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, } /** - * dp_catalog_hw_revision() - retrieve DP hw revision + * msm_dp_catalog_hw_revision() - retrieve DP hw revision * - * @dp_catalog: DP catalog structure + * @msm_dp_catalog: DP catalog structure * * Return: DP controller hw revision * */ -u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog) +u32 msm_dp_catalog_hw_revision(const struct msm_dp_catalog *msm_dp_catalog) { - const struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + const struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - return dp_read_ahb(catalog, REG_DP_HW_VERSION); + return msm_dp_read_ahb(catalog, REG_DP_HW_VERSION); } /** - * dp_catalog_ctrl_reset() - reset DP controller + * msm_dp_catalog_ctrl_reset() - reset DP controller * - * @dp_catalog: DP catalog structure + * @msm_dp_catalog: DP catalog structure * * return: void * @@ -581,28 +581,28 @@ u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog) * NOTE: reset DP controller will also clear any pending HPD related interrupts * */ -void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog) +void msm_dp_catalog_ctrl_reset(struct msm_dp_catalog *msm_dp_catalog) { u32 sw_reset; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - sw_reset = dp_read_ahb(catalog, REG_DP_SW_RESET); + sw_reset = msm_dp_read_ahb(catalog, REG_DP_SW_RESET); sw_reset |= DP_SW_RESET; - dp_write_ahb(catalog, REG_DP_SW_RESET, sw_reset); + msm_dp_write_ahb(catalog, REG_DP_SW_RESET, sw_reset); usleep_range(1000, 1100); /* h/w recommended delay */ sw_reset &= ~DP_SW_RESET; - dp_write_ahb(catalog, REG_DP_SW_RESET, sw_reset); + msm_dp_write_ahb(catalog, REG_DP_SW_RESET, sw_reset); } -bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog) +bool msm_dp_catalog_ctrl_mainlink_ready(struct msm_dp_catalog *msm_dp_catalog) { u32 data; int ret; - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); /* Poll for mainlink ready status */ ret = readl_poll_timeout(catalog->io.link.base + @@ -617,96 +617,96 @@ bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog) return true; } -void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, +void msm_dp_catalog_ctrl_enable_irq(struct msm_dp_catalog *msm_dp_catalog, bool enable) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); if (enable) { - dp_write_ahb(catalog, REG_DP_INTR_STATUS, + msm_dp_write_ahb(catalog, REG_DP_INTR_STATUS, DP_INTERRUPT_STATUS1_MASK); - dp_write_ahb(catalog, REG_DP_INTR_STATUS2, + msm_dp_write_ahb(catalog, REG_DP_INTR_STATUS2, DP_INTERRUPT_STATUS2_MASK); } else { - dp_write_ahb(catalog, REG_DP_INTR_STATUS, 0x00); - dp_write_ahb(catalog, REG_DP_INTR_STATUS2, 0x00); + msm_dp_write_ahb(catalog, REG_DP_INTR_STATUS, 0x00); + msm_dp_write_ahb(catalog, REG_DP_INTR_STATUS2, 0x00); } } -void dp_catalog_hpd_config_intr(struct dp_catalog *dp_catalog, +void msm_dp_catalog_hpd_config_intr(struct msm_dp_catalog *msm_dp_catalog, u32 intr_mask, bool en) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - u32 config = dp_read_aux(catalog, REG_DP_DP_HPD_INT_MASK); + u32 config = msm_dp_read_aux(catalog, REG_DP_DP_HPD_INT_MASK); config = (en ? config | intr_mask : config & ~intr_mask); drm_dbg_dp(catalog->drm_dev, "intr_mask=%#x config=%#x\n", intr_mask, config); - dp_write_aux(catalog, REG_DP_DP_HPD_INT_MASK, + msm_dp_write_aux(catalog, REG_DP_DP_HPD_INT_MASK, config & DP_DP_HPD_INT_MASK); } -void dp_catalog_ctrl_hpd_enable(struct dp_catalog *dp_catalog) +void msm_dp_catalog_ctrl_hpd_enable(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER); + u32 reftimer = msm_dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER); /* Configure REFTIMER and enable it */ reftimer |= DP_DP_HPD_REFTIMER_ENABLE; - dp_write_aux(catalog, REG_DP_DP_HPD_REFTIMER, reftimer); + msm_dp_write_aux(catalog, REG_DP_DP_HPD_REFTIMER, reftimer); /* Enable HPD */ - dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN); + msm_dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN); } -void dp_catalog_ctrl_hpd_disable(struct dp_catalog *dp_catalog) +void msm_dp_catalog_ctrl_hpd_disable(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER); + u32 reftimer = msm_dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER); reftimer &= ~DP_DP_HPD_REFTIMER_ENABLE; - dp_write_aux(catalog, REG_DP_DP_HPD_REFTIMER, reftimer); + msm_dp_write_aux(catalog, REG_DP_DP_HPD_REFTIMER, reftimer); - dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, 0); + msm_dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, 0); } -static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog) +static void msm_dp_catalog_enable_sdp(struct msm_dp_catalog_private *catalog) { /* trigger sdp */ - dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP); - dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x0); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x0); } -void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog) +void msm_dp_catalog_ctrl_config_psr(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 config; /* enable PSR1 function */ - config = dp_read_link(catalog, REG_PSR_CONFIG); + config = msm_dp_read_link(catalog, REG_PSR_CONFIG); config |= PSR1_SUPPORTED; - dp_write_link(catalog, REG_PSR_CONFIG, config); + msm_dp_write_link(catalog, REG_PSR_CONFIG, config); - dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4); - dp_catalog_enable_sdp(catalog); + msm_dp_write_ahb(catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4); + msm_dp_catalog_enable_sdp(catalog); } -void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter) +void msm_dp_catalog_ctrl_set_psr(struct msm_dp_catalog *msm_dp_catalog, bool enter) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 cmd; - cmd = dp_read_link(catalog, REG_PSR_CMD); + cmd = msm_dp_read_link(catalog, REG_PSR_CMD); cmd &= ~(PSR_ENTER | PSR_EXIT); @@ -715,17 +715,17 @@ void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter) else cmd |= PSR_EXIT; - dp_catalog_enable_sdp(catalog); - dp_write_link(catalog, REG_PSR_CMD, cmd); + msm_dp_catalog_enable_sdp(catalog); + msm_dp_write_link(catalog, REG_PSR_CMD, cmd); } -u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog) +u32 msm_dp_catalog_link_is_connected(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 status; - status = dp_read_aux(catalog, REG_DP_DP_HPD_INT_STATUS); + status = msm_dp_read_aux(catalog, REG_DP_DP_HPD_INT_STATUS); drm_dbg_dp(catalog->drm_dev, "aux status: %#x\n", status); status >>= DP_DP_HPD_STATE_STATUS_BITS_SHIFT; status &= DP_DP_HPD_STATE_STATUS_BITS_MASK; @@ -733,16 +733,16 @@ u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog) return status; } -u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog) +u32 msm_dp_catalog_hpd_get_intr_status(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); int isr, mask; - isr = dp_read_aux(catalog, REG_DP_DP_HPD_INT_STATUS); - dp_write_aux(catalog, REG_DP_DP_HPD_INT_ACK, + isr = msm_dp_read_aux(catalog, REG_DP_DP_HPD_INT_STATUS); + msm_dp_write_aux(catalog, REG_DP_DP_HPD_INT_ACK, (isr & DP_DP_HPD_INT_MASK)); - mask = dp_read_aux(catalog, REG_DP_DP_HPD_INT_MASK); + mask = msm_dp_read_aux(catalog, REG_DP_DP_HPD_INT_MASK); /* * We only want to return interrupts that are unmasked to the caller. @@ -754,115 +754,115 @@ u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog) return isr & (mask | ~DP_DP_HPD_INT_MASK); } -u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog) +u32 msm_dp_catalog_ctrl_read_psr_interrupt_status(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 intr, intr_ack; - intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS4); + intr = msm_dp_read_ahb(catalog, REG_DP_INTR_STATUS4); intr_ack = (intr & DP_INTERRUPT_STATUS4) << DP_INTERRUPT_STATUS_ACK_SHIFT; - dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack); + msm_dp_write_ahb(catalog, REG_DP_INTR_STATUS4, intr_ack); return intr; } -int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog) +int msm_dp_catalog_ctrl_get_interrupt(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 intr, intr_ack; - intr = dp_read_ahb(catalog, REG_DP_INTR_STATUS2); + intr = msm_dp_read_ahb(catalog, REG_DP_INTR_STATUS2); intr &= ~DP_INTERRUPT_STATUS2_MASK; intr_ack = (intr & DP_INTERRUPT_STATUS2) << DP_INTERRUPT_STATUS_ACK_SHIFT; - dp_write_ahb(catalog, REG_DP_INTR_STATUS2, + msm_dp_write_ahb(catalog, REG_DP_INTR_STATUS2, intr_ack | DP_INTERRUPT_STATUS2_MASK); return intr; } -void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog) +void msm_dp_catalog_ctrl_phy_reset(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - dp_write_ahb(catalog, REG_DP_PHY_CTRL, + msm_dp_write_ahb(catalog, REG_DP_PHY_CTRL, DP_PHY_CTRL_SW_RESET | DP_PHY_CTRL_SW_RESET_PLL); usleep_range(1000, 1100); /* h/w recommended delay */ - dp_write_ahb(catalog, REG_DP_PHY_CTRL, 0x0); + msm_dp_write_ahb(catalog, REG_DP_PHY_CTRL, 0x0); } -void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog, +void msm_dp_catalog_ctrl_send_phy_pattern(struct msm_dp_catalog *msm_dp_catalog, u32 pattern) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 value = 0x0; /* Make sure to clear the current pattern before starting a new one */ - dp_write_link(catalog, REG_DP_STATE_CTRL, 0x0); + msm_dp_write_link(catalog, REG_DP_STATE_CTRL, 0x0); drm_dbg_dp(catalog->drm_dev, "pattern: %#x\n", pattern); switch (pattern) { case DP_PHY_TEST_PATTERN_D10_2: - dp_write_link(catalog, REG_DP_STATE_CTRL, + msm_dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_TRAINING_PATTERN1); break; case DP_PHY_TEST_PATTERN_ERROR_COUNT: value &= ~(1 << 16); - dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, + msm_dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); value |= SCRAMBLER_RESET_COUNT_VALUE; - dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, + msm_dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); - dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, + msm_dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2); - dp_write_link(catalog, REG_DP_STATE_CTRL, + msm_dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE); break; case DP_PHY_TEST_PATTERN_PRBS7: - dp_write_link(catalog, REG_DP_STATE_CTRL, + msm_dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_PRBS7); break; case DP_PHY_TEST_PATTERN_80BIT_CUSTOM: - dp_write_link(catalog, REG_DP_STATE_CTRL, + msm_dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_TEST_CUSTOM_PATTERN); /* 00111110000011111000001111100000 */ - dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG0, + msm_dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0); /* 00001111100000111110000011111000 */ - dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG1, + msm_dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8); /* 1111100000111110 */ - dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2, + msm_dp_write_link(catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E); break; case DP_PHY_TEST_PATTERN_CP2520: - value = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + value = msm_dp_read_link(catalog, REG_DP_MAINLINK_CTRL); value &= ~DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER; - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, value); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, value); value = DP_HBR2_ERM_PATTERN; - dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, + msm_dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); value |= SCRAMBLER_RESET_COUNT_VALUE; - dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, + msm_dp_write_link(catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); - dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, + msm_dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2); - dp_write_link(catalog, REG_DP_STATE_CTRL, + msm_dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE); - value = dp_read_link(catalog, REG_DP_MAINLINK_CTRL); + value = msm_dp_read_link(catalog, REG_DP_MAINLINK_CTRL); value |= DP_MAINLINK_CTRL_ENABLE; - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, value); + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, value); break; case DP_PHY_TEST_PATTERN_SEL_MASK: - dp_write_link(catalog, REG_DP_MAINLINK_CTRL, + msm_dp_write_link(catalog, REG_DP_MAINLINK_CTRL, DP_MAINLINK_CTRL_ENABLE); - dp_write_link(catalog, REG_DP_STATE_CTRL, + msm_dp_write_link(catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_LINK_TRAINING_PATTERN4); break; default: @@ -872,94 +872,94 @@ void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog, } } -u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog) +u32 msm_dp_catalog_ctrl_read_phy_pattern(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - return dp_read_link(catalog, REG_DP_MAINLINK_READY); + return msm_dp_read_link(catalog, REG_DP_MAINLINK_READY); } /* panel related catalog functions */ -int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog, u32 total, - u32 sync_start, u32 width_blanking, u32 dp_active) +int msm_dp_catalog_panel_timing_cfg(struct msm_dp_catalog *msm_dp_catalog, u32 total, + u32 sync_start, u32 width_blanking, u32 msm_dp_active) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 reg; - dp_write_link(catalog, REG_DP_TOTAL_HOR_VER, total); - dp_write_link(catalog, REG_DP_START_HOR_VER_FROM_SYNC, sync_start); - dp_write_link(catalog, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY, width_blanking); - dp_write_link(catalog, REG_DP_ACTIVE_HOR_VER, dp_active); + msm_dp_write_link(catalog, REG_DP_TOTAL_HOR_VER, total); + msm_dp_write_link(catalog, REG_DP_START_HOR_VER_FROM_SYNC, sync_start); + msm_dp_write_link(catalog, REG_DP_HSYNC_VSYNC_WIDTH_POLARITY, width_blanking); + msm_dp_write_link(catalog, REG_DP_ACTIVE_HOR_VER, msm_dp_active); - reg = dp_read_p0(catalog, MMSS_DP_INTF_CONFIG); + reg = msm_dp_read_p0(catalog, MMSS_DP_INTF_CONFIG); - if (dp_catalog->wide_bus_en) + if (msm_dp_catalog->wide_bus_en) reg |= DP_INTF_CONFIG_DATABUS_WIDEN; else reg &= ~DP_INTF_CONFIG_DATABUS_WIDEN; - DRM_DEBUG_DP("wide_bus_en=%d reg=%#x\n", dp_catalog->wide_bus_en, reg); + DRM_DEBUG_DP("wide_bus_en=%d reg=%#x\n", msm_dp_catalog->wide_bus_en, reg); - dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, reg); + msm_dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, reg); return 0; } -static void dp_catalog_panel_send_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp) +static void msm_dp_catalog_panel_send_vsc_sdp(struct msm_dp_catalog *msm_dp_catalog, struct dp_sdp *vsc_sdp) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 header[2]; u32 val; int i; - catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, struct msm_dp_catalog_private, msm_dp_catalog); - dp_utils_pack_sdp_header(&vsc_sdp->sdp_header, header); + msm_dp_utils_pack_sdp_header(&vsc_sdp->sdp_header, header); - dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]); - dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]); + msm_dp_write_link(catalog, MMSS_DP_GENERIC0_0, header[0]); + msm_dp_write_link(catalog, MMSS_DP_GENERIC0_1, header[1]); for (i = 0; i < sizeof(vsc_sdp->db); i += 4) { val = ((vsc_sdp->db[i]) | (vsc_sdp->db[i + 1] << 8) | (vsc_sdp->db[i + 2] << 16) | (vsc_sdp->db[i + 3] << 24)); - dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val); + msm_dp_write_link(catalog, MMSS_DP_GENERIC0_2 + i, val); } } -static void dp_catalog_panel_update_sdp(struct dp_catalog *dp_catalog) +static void msm_dp_catalog_panel_update_sdp(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 hw_revision; - catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, struct msm_dp_catalog_private, msm_dp_catalog); - hw_revision = dp_catalog_hw_revision(dp_catalog); + hw_revision = msm_dp_catalog_hw_revision(msm_dp_catalog); if (hw_revision < DP_HW_VERSION_1_2 && hw_revision >= DP_HW_VERSION_1_0) { - dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01); - dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x01); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG3, 0x00); } } -void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp) +void msm_dp_catalog_panel_enable_vsc_sdp(struct msm_dp_catalog *msm_dp_catalog, struct dp_sdp *vsc_sdp) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 cfg, cfg2, misc; - catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, struct msm_dp_catalog_private, msm_dp_catalog); - cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG); - cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2); - misc = dp_read_link(catalog, REG_DP_MISC1_MISC0); + cfg = msm_dp_read_link(catalog, MMSS_DP_SDP_CFG); + cfg2 = msm_dp_read_link(catalog, MMSS_DP_SDP_CFG2); + misc = msm_dp_read_link(catalog, REG_DP_MISC1_MISC0); cfg |= GEN0_SDP_EN; - dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg); cfg2 |= GENERIC0_SDPSIZE_VALID; - dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2); - dp_catalog_panel_send_vsc_sdp(dp_catalog, vsc_sdp); + msm_dp_catalog_panel_send_vsc_sdp(msm_dp_catalog, vsc_sdp); /* indicates presence of VSC (BIT(6) of MISC1) */ misc |= DP_MISC1_VSC_SDP; @@ -967,27 +967,27 @@ void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sd drm_dbg_dp(catalog->drm_dev, "vsc sdp enable=1\n"); pr_debug("misc settings = 0x%x\n", misc); - dp_write_link(catalog, REG_DP_MISC1_MISC0, misc); + msm_dp_write_link(catalog, REG_DP_MISC1_MISC0, misc); - dp_catalog_panel_update_sdp(dp_catalog); + msm_dp_catalog_panel_update_sdp(msm_dp_catalog); } -void dp_catalog_panel_disable_vsc_sdp(struct dp_catalog *dp_catalog) +void msm_dp_catalog_panel_disable_vsc_sdp(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 cfg, cfg2, misc; - catalog = container_of(dp_catalog, struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, struct msm_dp_catalog_private, msm_dp_catalog); - cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG); - cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2); - misc = dp_read_link(catalog, REG_DP_MISC1_MISC0); + cfg = msm_dp_read_link(catalog, MMSS_DP_SDP_CFG); + cfg2 = msm_dp_read_link(catalog, MMSS_DP_SDP_CFG2); + misc = msm_dp_read_link(catalog, REG_DP_MISC1_MISC0); cfg &= ~GEN0_SDP_EN; - dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG, cfg); cfg2 &= ~GENERIC0_SDPSIZE_VALID; - dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG2, cfg2); /* switch back to MSA */ misc &= ~DP_MISC1_VSC_SDP; @@ -995,16 +995,16 @@ void dp_catalog_panel_disable_vsc_sdp(struct dp_catalog *dp_catalog) drm_dbg_dp(catalog->drm_dev, "vsc sdp enable=0\n"); pr_debug("misc settings = 0x%x\n", misc); - dp_write_link(catalog, REG_DP_MISC1_MISC0, misc); + msm_dp_write_link(catalog, REG_DP_MISC1_MISC0, misc); - dp_catalog_panel_update_sdp(dp_catalog); + msm_dp_catalog_panel_update_sdp(msm_dp_catalog); } -void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog, +void msm_dp_catalog_panel_tpg_enable(struct msm_dp_catalog *msm_dp_catalog, struct drm_display_mode *drm_mode) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); u32 hsync_period, vsync_period; u32 display_v_start, display_v_end; u32 hsync_start_x, hsync_end_x; @@ -1036,49 +1036,49 @@ void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog, display_hctl = (hsync_end_x << 16) | hsync_start_x; - dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, 0x0); - dp_write_p0(catalog, MMSS_DP_INTF_HSYNC_CTL, hsync_ctl); - dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PERIOD_F0, vsync_period * + msm_dp_write_p0(catalog, MMSS_DP_INTF_CONFIG, 0x0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_HSYNC_CTL, hsync_ctl); + msm_dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period); - dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, v_sync_width * + msm_dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, v_sync_width * hsync_period); - dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PERIOD_F1, 0); - dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0); - dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_HCTL, display_hctl); - dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_HCTL, 0); - dp_write_p0(catalog, MMSS_INTF_DISPLAY_V_START_F0, display_v_start); - dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_V_END_F0, display_v_end); - dp_write_p0(catalog, MMSS_INTF_DISPLAY_V_START_F1, 0); - dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_V_END_F1, 0); - dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_START_F0, 0); - dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_END_F0, 0); - dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_START_F1, 0); - dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_END_F1, 0); - dp_write_p0(catalog, MMSS_DP_INTF_POLARITY_CTL, 0); - - dp_write_p0(catalog, MMSS_DP_TPG_MAIN_CONTROL, + msm_dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PERIOD_F1, 0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_HCTL, display_hctl); + msm_dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_HCTL, 0); + msm_dp_write_p0(catalog, MMSS_INTF_DISPLAY_V_START_F0, display_v_start); + msm_dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_V_END_F0, display_v_end); + msm_dp_write_p0(catalog, MMSS_INTF_DISPLAY_V_START_F1, 0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_DISPLAY_V_END_F1, 0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_START_F0, 0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_END_F0, 0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_START_F1, 0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_ACTIVE_V_END_F1, 0); + msm_dp_write_p0(catalog, MMSS_DP_INTF_POLARITY_CTL, 0); + + msm_dp_write_p0(catalog, MMSS_DP_TPG_MAIN_CONTROL, DP_TPG_CHECKERED_RECT_PATTERN); - dp_write_p0(catalog, MMSS_DP_TPG_VIDEO_CONFIG, + msm_dp_write_p0(catalog, MMSS_DP_TPG_VIDEO_CONFIG, DP_TPG_VIDEO_CONFIG_BPP_8BIT | DP_TPG_VIDEO_CONFIG_RGB); - dp_write_p0(catalog, MMSS_DP_BIST_ENABLE, + msm_dp_write_p0(catalog, MMSS_DP_BIST_ENABLE, DP_BIST_ENABLE_DPBIST_EN); - dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, + msm_dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, DP_TIMING_ENGINE_EN_EN); drm_dbg_dp(catalog->drm_dev, "%s: enabled tpg\n", __func__); } -void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog) +void msm_dp_catalog_panel_tpg_disable(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - dp_write_p0(catalog, MMSS_DP_TPG_MAIN_CONTROL, 0x0); - dp_write_p0(catalog, MMSS_DP_BIST_ENABLE, 0x0); - dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, 0x0); + msm_dp_write_p0(catalog, MMSS_DP_TPG_MAIN_CONTROL, 0x0); + msm_dp_write_p0(catalog, MMSS_DP_BIST_ENABLE, 0x0); + msm_dp_write_p0(catalog, MMSS_DP_TIMING_ENGINE_EN, 0x0); } -static void __iomem *dp_ioremap(struct platform_device *pdev, int idx, size_t *len) +static void __iomem *msm_dp_ioremap(struct platform_device *pdev, int idx, size_t *len) { struct resource *res; void __iomem *base; @@ -1090,21 +1090,21 @@ static void __iomem *dp_ioremap(struct platform_device *pdev, int idx, size_t *l return base; } -static int dp_catalog_get_io(struct dp_catalog_private *catalog) +static int msm_dp_catalog_get_io(struct msm_dp_catalog_private *catalog) { struct platform_device *pdev = to_platform_device(catalog->dev); struct dss_io_data *dss = &catalog->io; - dss->ahb.base = dp_ioremap(pdev, 0, &dss->ahb.len); + dss->ahb.base = msm_dp_ioremap(pdev, 0, &dss->ahb.len); if (IS_ERR(dss->ahb.base)) return PTR_ERR(dss->ahb.base); - dss->aux.base = dp_ioremap(pdev, 1, &dss->aux.len); + dss->aux.base = msm_dp_ioremap(pdev, 1, &dss->aux.len); if (IS_ERR(dss->aux.base)) { /* * The initial binding had a single reg, but in order to * support variation in the sub-region sizes this was split. - * dp_ioremap() will fail with -EINVAL here if only a single + * msm_dp_ioremap() will fail with -EINVAL here if only a single * reg is specified, so fill in the sub-region offsets and * lengths based on this single region. */ @@ -1126,13 +1126,13 @@ static int dp_catalog_get_io(struct dp_catalog_private *catalog) return PTR_ERR(dss->aux.base); } } else { - dss->link.base = dp_ioremap(pdev, 2, &dss->link.len); + dss->link.base = msm_dp_ioremap(pdev, 2, &dss->link.len); if (IS_ERR(dss->link.base)) { DRM_ERROR("unable to remap link region: %pe\n", dss->link.base); return PTR_ERR(dss->link.base); } - dss->p0.base = dp_ioremap(pdev, 3, &dss->p0.len); + dss->p0.base = msm_dp_ioremap(pdev, 3, &dss->p0.len); if (IS_ERR(dss->p0.base)) { DRM_ERROR("unable to remap p0 region: %pe\n", dss->p0.base); return PTR_ERR(dss->p0.base); @@ -1142,9 +1142,9 @@ static int dp_catalog_get_io(struct dp_catalog_private *catalog) return 0; } -struct dp_catalog *dp_catalog_get(struct device *dev) +struct msm_dp_catalog *msm_dp_catalog_get(struct device *dev) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; int ret; catalog = devm_kzalloc(dev, sizeof(*catalog), GFP_KERNEL); @@ -1153,78 +1153,78 @@ struct dp_catalog *dp_catalog_get(struct device *dev) catalog->dev = dev; - ret = dp_catalog_get_io(catalog); + ret = msm_dp_catalog_get_io(catalog); if (ret) return ERR_PTR(ret); - return &catalog->dp_catalog; + return &catalog->msm_dp_catalog; } -u32 dp_catalog_audio_get_header(struct dp_catalog *dp_catalog, - enum dp_catalog_audio_sdp_type sdp, - enum dp_catalog_audio_header_type header) +u32 msm_dp_catalog_audio_get_header(struct msm_dp_catalog *msm_dp_catalog, + enum msm_dp_catalog_audio_sdp_type sdp, + enum msm_dp_catalog_audio_header_type header) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX]; - catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); sdp_map = catalog->audio_map; - return dp_read_link(catalog, sdp_map[sdp][header]); + return msm_dp_read_link(catalog, sdp_map[sdp][header]); } -void dp_catalog_audio_set_header(struct dp_catalog *dp_catalog, - enum dp_catalog_audio_sdp_type sdp, - enum dp_catalog_audio_header_type header, +void msm_dp_catalog_audio_set_header(struct msm_dp_catalog *msm_dp_catalog, + enum msm_dp_catalog_audio_sdp_type sdp, + enum msm_dp_catalog_audio_header_type header, u32 data) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX]; - if (!dp_catalog) + if (!msm_dp_catalog) return; - catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); sdp_map = catalog->audio_map; - dp_write_link(catalog, sdp_map[sdp][header], data); + msm_dp_write_link(catalog, sdp_map[sdp][header], data); } -void dp_catalog_audio_config_acr(struct dp_catalog *dp_catalog, u32 select) +void msm_dp_catalog_audio_config_acr(struct msm_dp_catalog *msm_dp_catalog, u32 select) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 acr_ctrl; - if (!dp_catalog) + if (!msm_dp_catalog) return; - catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14); drm_dbg_dp(catalog->drm_dev, "select: %#x, acr_ctrl: %#x\n", select, acr_ctrl); - dp_write_link(catalog, MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl); + msm_dp_write_link(catalog, MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl); } -void dp_catalog_audio_enable(struct dp_catalog *dp_catalog, bool enable) +void msm_dp_catalog_audio_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 audio_ctrl; - if (!dp_catalog) + if (!msm_dp_catalog) return; - catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - audio_ctrl = dp_read_link(catalog, MMSS_DP_AUDIO_CFG); + audio_ctrl = msm_dp_read_link(catalog, MMSS_DP_AUDIO_CFG); if (enable) audio_ctrl |= BIT(0); @@ -1233,24 +1233,24 @@ void dp_catalog_audio_enable(struct dp_catalog *dp_catalog, bool enable) drm_dbg_dp(catalog->drm_dev, "dp_audio_cfg = 0x%x\n", audio_ctrl); - dp_write_link(catalog, MMSS_DP_AUDIO_CFG, audio_ctrl); + msm_dp_write_link(catalog, MMSS_DP_AUDIO_CFG, audio_ctrl); /* make sure audio engine is disabled */ wmb(); } -void dp_catalog_audio_config_sdp(struct dp_catalog *dp_catalog) +void msm_dp_catalog_audio_config_sdp(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 sdp_cfg = 0; u32 sdp_cfg2 = 0; - if (!dp_catalog) + if (!msm_dp_catalog) return; - catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - sdp_cfg = dp_read_link(catalog, MMSS_DP_SDP_CFG); + sdp_cfg = msm_dp_read_link(catalog, MMSS_DP_SDP_CFG); /* AUDIO_TIMESTAMP_SDP_EN */ sdp_cfg |= BIT(1); /* AUDIO_STREAM_SDP_EN */ @@ -1264,9 +1264,9 @@ void dp_catalog_audio_config_sdp(struct dp_catalog *dp_catalog) drm_dbg_dp(catalog->drm_dev, "sdp_cfg = 0x%x\n", sdp_cfg); - dp_write_link(catalog, MMSS_DP_SDP_CFG, sdp_cfg); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG, sdp_cfg); - sdp_cfg2 = dp_read_link(catalog, MMSS_DP_SDP_CFG2); + sdp_cfg2 = msm_dp_read_link(catalog, MMSS_DP_SDP_CFG2); /* IFRM_REGSRC -> Do not use reg values */ sdp_cfg2 &= ~BIT(0); /* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */ @@ -1274,12 +1274,12 @@ void dp_catalog_audio_config_sdp(struct dp_catalog *dp_catalog) drm_dbg_dp(catalog->drm_dev, "sdp_cfg2 = 0x%x\n", sdp_cfg2); - dp_write_link(catalog, MMSS_DP_SDP_CFG2, sdp_cfg2); + msm_dp_write_link(catalog, MMSS_DP_SDP_CFG2, sdp_cfg2); } -void dp_catalog_audio_init(struct dp_catalog *dp_catalog) +void msm_dp_catalog_audio_init(struct msm_dp_catalog *msm_dp_catalog) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; static u32 sdp_map[][DP_AUDIO_SDP_HEADER_MAX] = { { @@ -1309,27 +1309,27 @@ void dp_catalog_audio_init(struct dp_catalog *dp_catalog) }, }; - if (!dp_catalog) + if (!msm_dp_catalog) return; - catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); catalog->audio_map = sdp_map; } -void dp_catalog_audio_sfe_level(struct dp_catalog *dp_catalog, u32 safe_to_exit_level) +void msm_dp_catalog_audio_sfe_level(struct msm_dp_catalog *msm_dp_catalog, u32 safe_to_exit_level) { - struct dp_catalog_private *catalog; + struct msm_dp_catalog_private *catalog; u32 mainlink_levels; - if (!dp_catalog) + if (!msm_dp_catalog) return; - catalog = container_of(dp_catalog, - struct dp_catalog_private, dp_catalog); + catalog = container_of(msm_dp_catalog, + struct msm_dp_catalog_private, msm_dp_catalog); - mainlink_levels = dp_read_link(catalog, REG_DP_MAINLINK_LEVELS); + mainlink_levels = msm_dp_read_link(catalog, REG_DP_MAINLINK_LEVELS); mainlink_levels &= 0xFE0; mainlink_levels |= safe_to_exit_level; @@ -1337,5 +1337,5 @@ void dp_catalog_audio_sfe_level(struct dp_catalog *dp_catalog, u32 safe_to_exit_ "mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n", mainlink_levels, safe_to_exit_level); - dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, mainlink_levels); + msm_dp_write_link(catalog, REG_DP_MAINLINK_LEVELS, mainlink_levels); } diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 4679d50b8c73cb..e932b17eecbf51 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -31,7 +31,7 @@ #define DP_HW_VERSION_1_0 0x10000000 #define DP_HW_VERSION_1_2 0x10020000 -enum dp_catalog_audio_sdp_type { +enum msm_dp_catalog_audio_sdp_type { DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_INFOFRAME, @@ -40,89 +40,89 @@ enum dp_catalog_audio_sdp_type { DP_AUDIO_SDP_MAX, }; -enum dp_catalog_audio_header_type { +enum msm_dp_catalog_audio_header_type { DP_AUDIO_SDP_HEADER_1, DP_AUDIO_SDP_HEADER_2, DP_AUDIO_SDP_HEADER_3, DP_AUDIO_SDP_HEADER_MAX, }; -struct dp_catalog { +struct msm_dp_catalog { bool wide_bus_en; }; /* Debug module */ -void dp_catalog_snapshot(struct dp_catalog *dp_catalog, struct msm_disp_state *disp_state); +void msm_dp_catalog_snapshot(struct msm_dp_catalog *msm_dp_catalog, struct msm_disp_state *disp_state); /* AUX APIs */ -u32 dp_catalog_aux_read_data(struct dp_catalog *dp_catalog); -int dp_catalog_aux_write_data(struct dp_catalog *dp_catalog, u32 data); -int dp_catalog_aux_write_trans(struct dp_catalog *dp_catalog, u32 data); -int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, bool read); -int dp_catalog_aux_clear_hw_interrupts(struct dp_catalog *dp_catalog); -void dp_catalog_aux_reset(struct dp_catalog *dp_catalog); -void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable); -int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog, +u32 msm_dp_catalog_aux_read_data(struct msm_dp_catalog *msm_dp_catalog); +int msm_dp_catalog_aux_write_data(struct msm_dp_catalog *msm_dp_catalog, u32 data); +int msm_dp_catalog_aux_write_trans(struct msm_dp_catalog *msm_dp_catalog, u32 data); +int msm_dp_catalog_aux_clear_trans(struct msm_dp_catalog *msm_dp_catalog, bool read); +int msm_dp_catalog_aux_clear_hw_interrupts(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_aux_reset(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_aux_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable); +int msm_dp_catalog_aux_wait_for_hpd_connect_state(struct msm_dp_catalog *msm_dp_catalog, unsigned long wait_us); -u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog); +u32 msm_dp_catalog_aux_get_irq(struct msm_dp_catalog *msm_dp_catalog); /* DP Controller APIs */ -void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state); -void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 config); -void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable); -void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, bool enable); -void dp_catalog_setup_peripheral_flush(struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb); -void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate, +void msm_dp_catalog_ctrl_state_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 state); +void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 config); +void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_mainlink_ctrl(struct msm_dp_catalog *msm_dp_catalog, bool enable); +void msm_dp_catalog_ctrl_psr_mainlink_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable); +void msm_dp_catalog_setup_peripheral_flush(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_config_misc(struct msm_dp_catalog *msm_dp_catalog, u32 cc, u32 tb); +void msm_dp_catalog_ctrl_config_msa(struct msm_dp_catalog *msm_dp_catalog, u32 rate, u32 stream_rate_khz, bool is_ycbcr_420); -int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 pattern); -u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog); -bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, bool enable); -void dp_catalog_hpd_config_intr(struct dp_catalog *dp_catalog, +int msm_dp_catalog_ctrl_set_pattern_state_bit(struct msm_dp_catalog *msm_dp_catalog, u32 pattern); +u32 msm_dp_catalog_hw_revision(const struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_reset(struct msm_dp_catalog *msm_dp_catalog); +bool msm_dp_catalog_ctrl_mainlink_ready(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_enable_irq(struct msm_dp_catalog *msm_dp_catalog, bool enable); +void msm_dp_catalog_hpd_config_intr(struct msm_dp_catalog *msm_dp_catalog, u32 intr_mask, bool en); -void dp_catalog_ctrl_hpd_enable(struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_hpd_disable(struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter); -u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog); -u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog); -int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog); -u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog); -void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog *dp_catalog, - u32 dp_tu, u32 valid_boundary, +void msm_dp_catalog_ctrl_hpd_enable(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_hpd_disable(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_config_psr(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_set_psr(struct msm_dp_catalog *msm_dp_catalog, bool enter); +u32 msm_dp_catalog_link_is_connected(struct msm_dp_catalog *msm_dp_catalog); +u32 msm_dp_catalog_hpd_get_intr_status(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_phy_reset(struct msm_dp_catalog *msm_dp_catalog); +int msm_dp_catalog_ctrl_get_interrupt(struct msm_dp_catalog *msm_dp_catalog); +u32 msm_dp_catalog_ctrl_read_psr_interrupt_status(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_ctrl_update_transfer_unit(struct msm_dp_catalog *msm_dp_catalog, + u32 msm_dp_tu, u32 valid_boundary, u32 valid_boundary2); -void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog, +void msm_dp_catalog_ctrl_send_phy_pattern(struct msm_dp_catalog *msm_dp_catalog, u32 pattern); -u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog); +u32 msm_dp_catalog_ctrl_read_phy_pattern(struct msm_dp_catalog *msm_dp_catalog); /* DP Panel APIs */ -int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog, u32 total, - u32 sync_start, u32 width_blanking, u32 dp_active); -void dp_catalog_panel_enable_vsc_sdp(struct dp_catalog *dp_catalog, struct dp_sdp *vsc_sdp); -void dp_catalog_panel_disable_vsc_sdp(struct dp_catalog *dp_catalog); -void dp_catalog_dump_regs(struct dp_catalog *dp_catalog); -void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog, +int msm_dp_catalog_panel_timing_cfg(struct msm_dp_catalog *msm_dp_catalog, u32 total, + u32 sync_start, u32 width_blanking, u32 msm_dp_active); +void msm_dp_catalog_panel_enable_vsc_sdp(struct msm_dp_catalog *msm_dp_catalog, struct dp_sdp *vsc_sdp); +void msm_dp_catalog_panel_disable_vsc_sdp(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_dump_regs(struct msm_dp_catalog *msm_dp_catalog); +void msm_dp_catalog_panel_tpg_enable(struct msm_dp_catalog *msm_dp_catalog, struct drm_display_mode *drm_mode); -void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog); +void msm_dp_catalog_panel_tpg_disable(struct msm_dp_catalog *msm_dp_catalog); -struct dp_catalog *dp_catalog_get(struct device *dev); +struct msm_dp_catalog *msm_dp_catalog_get(struct device *dev); /* DP Audio APIs */ -u32 dp_catalog_audio_get_header(struct dp_catalog *dp_catalog, - enum dp_catalog_audio_sdp_type sdp, - enum dp_catalog_audio_header_type header); -void dp_catalog_audio_set_header(struct dp_catalog *dp_catalog, - enum dp_catalog_audio_sdp_type sdp, - enum dp_catalog_audio_header_type header, +u32 msm_dp_catalog_audio_get_header(struct msm_dp_catalog *msm_dp_catalog, + enum msm_dp_catalog_audio_sdp_type sdp, + enum msm_dp_catalog_audio_header_type header); +void msm_dp_catalog_audio_set_header(struct msm_dp_catalog *msm_dp_catalog, + enum msm_dp_catalog_audio_sdp_type sdp, + enum msm_dp_catalog_audio_header_type header, u32 data); -void dp_catalog_audio_config_acr(struct dp_catalog *catalog, u32 select); -void dp_catalog_audio_enable(struct dp_catalog *catalog, bool enable); -void dp_catalog_audio_config_sdp(struct dp_catalog *catalog); -void dp_catalog_audio_init(struct dp_catalog *catalog); -void dp_catalog_audio_sfe_level(struct dp_catalog *catalog, u32 safe_to_exit_level); +void msm_dp_catalog_audio_config_acr(struct msm_dp_catalog *catalog, u32 select); +void msm_dp_catalog_audio_enable(struct msm_dp_catalog *catalog, bool enable); +void msm_dp_catalog_audio_config_sdp(struct msm_dp_catalog *catalog); +void msm_dp_catalog_audio_init(struct msm_dp_catalog *catalog); +void msm_dp_catalog_audio_sfe_level(struct msm_dp_catalog *catalog, u32 safe_to_exit_level); #endif /* _DP_CATALOG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index f342fc5ae41ecc..bc2ca8133b790f 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -40,7 +40,7 @@ enum { DP_TRAINING_2, }; -struct dp_tu_calc_input { +struct msm_dp_tu_calc_input { u64 lclk; /* 162, 270, 540 and 810 */ u64 pclk_khz; /* in KHz */ u64 hactive; /* active h-width */ @@ -55,7 +55,7 @@ struct dp_tu_calc_input { int num_of_dsc_slices; /* number of slices per line */ }; -struct dp_vc_tu_mapping_table { +struct msm_dp_vc_tu_mapping_table { u32 vic; u8 lanes; u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */ @@ -69,14 +69,14 @@ struct dp_vc_tu_mapping_table { u8 tu_size_minus1; }; -struct dp_ctrl_private { - struct dp_ctrl dp_ctrl; +struct msm_dp_ctrl_private { + struct msm_dp_ctrl msm_dp_ctrl; struct drm_device *drm_dev; struct device *dev; struct drm_dp_aux *aux; - struct dp_panel *panel; - struct dp_link *link; - struct dp_catalog *catalog; + struct msm_dp_panel *panel; + struct msm_dp_link *link; + struct msm_dp_catalog *catalog; struct phy *phy; @@ -99,8 +99,8 @@ struct dp_ctrl_private { bool stream_clks_on; }; -static int dp_aux_link_configure(struct drm_dp_aux *aux, - struct dp_link_info *link) +static int msm_dp_aux_link_configure(struct drm_dp_aux *aux, + struct msm_dp_link_info *link) { u8 values[2]; int err; @@ -118,14 +118,14 @@ static int dp_aux_link_configure(struct drm_dp_aux *aux, return 0; } -void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); reinit_completion(&ctrl->idle_comp); - dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_PUSH_IDLE); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_PUSH_IDLE); if (!wait_for_completion_timeout(&ctrl->idle_comp, IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES)) @@ -134,7 +134,7 @@ void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) drm_dbg_dp(ctrl->drm_dev, "mainlink off\n"); } -static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) +static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl) { u32 config = 0, tbd; const u8 *dpcd = ctrl->panel->dpcd; @@ -142,15 +142,15 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) /* Default-> LSCLK DIV: 1/4 LCLK */ config |= (2 << DP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT); - if (ctrl->panel->dp_mode.out_fmt_is_yuv_420) + if (ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420) config |= DP_CONFIGURATION_CTRL_RGB_YUV; /* YUV420 */ /* Scrambler reset enable */ if (drm_dp_alternate_scrambler_reset_cap(dpcd)) config |= DP_CONFIGURATION_CTRL_ASSR; - tbd = dp_link_get_test_bits_depth(ctrl->link, - ctrl->panel->dp_mode.bpp); + tbd = msm_dp_link_get_test_bits_depth(ctrl->link, + ctrl->panel->msm_dp_mode.bpp); config |= tbd << DP_CONFIGURATION_CTRL_BPC_SHIFT; @@ -170,24 +170,24 @@ static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) if (ctrl->panel->psr_cap.version) config |= DP_CONFIGURATION_CTRL_SEND_VSC; - dp_catalog_ctrl_config_ctrl(ctrl->catalog, config); + msm_dp_catalog_ctrl_config_ctrl(ctrl->catalog, config); } -static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl) +static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl) { u32 cc, tb; - dp_catalog_ctrl_lane_mapping(ctrl->catalog); - dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true); - dp_catalog_setup_peripheral_flush(ctrl->catalog); + msm_dp_catalog_ctrl_lane_mapping(ctrl->catalog); + msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true); + msm_dp_catalog_setup_peripheral_flush(ctrl->catalog); - dp_ctrl_config_ctrl(ctrl); + msm_dp_ctrl_config_ctrl(ctrl); - tb = dp_link_get_test_bits_depth(ctrl->link, - ctrl->panel->dp_mode.bpp); - cc = dp_link_get_colorimetry_config(ctrl->link); - dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb); - dp_panel_timing_cfg(ctrl->panel); + tb = msm_dp_link_get_test_bits_depth(ctrl->link, + ctrl->panel->msm_dp_mode.bpp); + cc = msm_dp_link_get_colorimetry_config(ctrl->link); + msm_dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb); + msm_dp_panel_timing_cfg(ctrl->panel); } /* @@ -310,7 +310,7 @@ static int _tu_param_compare(s64 a, s64 b) } } -static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, +static void msm_dp_panel_update_tu_timings(struct msm_dp_tu_calc_input *in, struct tu_algo_data *tu) { int nlanes = in->nlanes; @@ -622,9 +622,9 @@ static void _tu_valid_boundary_calc(struct tu_algo_data *tu) } } -static void _dp_ctrl_calc_tu(struct dp_ctrl_private *ctrl, - struct dp_tu_calc_input *in, - struct dp_vc_tu_mapping_table *tu_table) +static void _dp_ctrl_calc_tu(struct msm_dp_ctrl_private *ctrl, + struct msm_dp_tu_calc_input *in, + struct msm_dp_vc_tu_mapping_table *tu_table) { struct tu_algo_data *tu; int compare_result_1, compare_result_2; @@ -645,7 +645,7 @@ static void _dp_ctrl_calc_tu(struct dp_ctrl_private *ctrl, if (!tu) return; - dp_panel_update_tu_timings(in, tu); + msm_dp_panel_update_tu_timings(in, tu); tu->err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */ @@ -956,21 +956,21 @@ static void _dp_ctrl_calc_tu(struct dp_ctrl_private *ctrl, kfree(tu); } -static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, - struct dp_vc_tu_mapping_table *tu_table) +static void msm_dp_ctrl_calc_tu_parameters(struct msm_dp_ctrl_private *ctrl, + struct msm_dp_vc_tu_mapping_table *tu_table) { - struct dp_tu_calc_input in; + struct msm_dp_tu_calc_input in; struct drm_display_mode *drm_mode; - drm_mode = &ctrl->panel->dp_mode.drm_mode; + drm_mode = &ctrl->panel->msm_dp_mode.drm_mode; in.lclk = ctrl->link->link_params.rate / 1000; in.pclk_khz = drm_mode->clock; in.hactive = drm_mode->hdisplay; in.hporch = drm_mode->htotal - drm_mode->hdisplay; in.nlanes = ctrl->link->link_params.num_lanes; - in.bpp = ctrl->panel->dp_mode.bpp; - in.pixel_enc = ctrl->panel->dp_mode.out_fmt_is_yuv_420 ? 420 : 444; + in.bpp = ctrl->panel->msm_dp_mode.bpp; + in.pixel_enc = ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420 ? 420 : 444; in.dsc_en = 0; in.async_en = 0; in.fec_en = 0; @@ -980,16 +980,16 @@ static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, _dp_ctrl_calc_tu(ctrl, &in, tu_table); } -static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl) +static void msm_dp_ctrl_setup_tr_unit(struct msm_dp_ctrl_private *ctrl) { - u32 dp_tu = 0x0; + u32 msm_dp_tu = 0x0; u32 valid_boundary = 0x0; u32 valid_boundary2 = 0x0; - struct dp_vc_tu_mapping_table tu_calc_table; + struct msm_dp_vc_tu_mapping_table tu_calc_table; - dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table); + msm_dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table); - dp_tu |= tu_calc_table.tu_size_minus1; + msm_dp_tu |= tu_calc_table.tu_size_minus1; valid_boundary |= tu_calc_table.valid_boundary_link; valid_boundary |= (tu_calc_table.delay_start_link << 16); @@ -1001,13 +1001,13 @@ static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl) valid_boundary2 |= BIT(0); pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n", - dp_tu, valid_boundary, valid_boundary2); + msm_dp_tu, valid_boundary, valid_boundary2); - dp_catalog_ctrl_update_transfer_unit(ctrl->catalog, - dp_tu, valid_boundary, valid_boundary2); + msm_dp_catalog_ctrl_update_transfer_unit(ctrl->catalog, + msm_dp_tu, valid_boundary, valid_boundary2); } -static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_wait4video_ready(struct msm_dp_ctrl_private *ctrl) { int ret = 0; @@ -1019,7 +1019,7 @@ static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl) return ret; } -static int dp_ctrl_set_vx_px(struct dp_ctrl_private *ctrl, +static int msm_dp_ctrl_set_vx_px(struct msm_dp_ctrl_private *ctrl, u8 v_level, u8 p_level) { union phy_configure_opts *phy_opts = &ctrl->phy_opts; @@ -1034,9 +1034,9 @@ static int dp_ctrl_set_vx_px(struct dp_ctrl_private *ctrl, return 0; } -static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl) { - struct dp_link *link = ctrl->link; + struct msm_dp_link *link = ctrl->link; int ret = 0, lane, lane_cnt; u8 buf[4]; u32 max_level_reached = 0; @@ -1046,7 +1046,7 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) drm_dbg_dp(ctrl->drm_dev, "voltage level: %d emphasis level: %d\n", voltage_swing_level, pre_emphasis_level); - ret = dp_ctrl_set_vx_px(ctrl, + ret = msm_dp_ctrl_set_vx_px(ctrl, voltage_swing_level, pre_emphasis_level); if (ret) @@ -1083,7 +1083,7 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) return ret; } -static bool dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl, +static bool msm_dp_ctrl_train_pattern_set(struct msm_dp_ctrl_private *ctrl, u8 pattern) { u8 buf; @@ -1100,7 +1100,7 @@ static bool dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl, return ret == 1; } -static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl, +static int msm_dp_ctrl_read_link_status(struct msm_dp_ctrl_private *ctrl, u8 *link_status) { int ret = 0, len; @@ -1114,24 +1114,24 @@ static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl, return ret; } -static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl, +static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl, int *training_step) { int tries, old_v_level, ret = 0; u8 link_status[DP_LINK_STATUS_SIZE]; int const maximum_retries = 4; - dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); *training_step = DP_TRAINING_1; - ret = dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, 1); + ret = msm_dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, 1); if (ret) return ret; - dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 | + msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE); - ret = dp_ctrl_update_vx_px(ctrl); + ret = msm_dp_ctrl_update_vx_px(ctrl); if (ret) return ret; @@ -1140,7 +1140,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl, for (tries = 0; tries < maximum_retries; tries++) { drm_dp_link_train_clock_recovery_delay(ctrl->aux, ctrl->panel->dpcd); - ret = dp_ctrl_read_link_status(ctrl, link_status); + ret = msm_dp_ctrl_read_link_status(ctrl, link_status); if (ret) return ret; @@ -1160,8 +1160,8 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl, old_v_level = ctrl->link->phy_params.v_level; } - dp_link_adjust_levels(ctrl->link, link_status); - ret = dp_ctrl_update_vx_px(ctrl); + msm_dp_link_adjust_levels(ctrl->link, link_status); + ret = msm_dp_ctrl_update_vx_px(ctrl); if (ret) return ret; } @@ -1170,7 +1170,7 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl, return -ETIMEDOUT; } -static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_link_rate_down_shift(struct msm_dp_ctrl_private *ctrl) { int ret = 0; @@ -1198,7 +1198,7 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) return ret; } -static int dp_ctrl_link_lane_down_shift(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl) { if (ctrl->link->link_params.num_lanes == 1) @@ -1213,13 +1213,13 @@ static int dp_ctrl_link_lane_down_shift(struct dp_ctrl_private *ctrl) return 0; } -static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl) +static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl) { - dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE); + msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE); drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd); } -static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, +static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl, int *training_step) { int tries = 0, ret = 0; @@ -1228,7 +1228,7 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, int const maximum_retries = 5; u8 link_status[DP_LINK_STATUS_SIZE]; - dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); *training_step = DP_TRAINING_2; @@ -1243,16 +1243,16 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, state_ctrl_bit = 2; } - ret = dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, state_ctrl_bit); + ret = msm_dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, state_ctrl_bit); if (ret) return ret; - dp_ctrl_train_pattern_set(ctrl, pattern); + msm_dp_ctrl_train_pattern_set(ctrl, pattern); for (tries = 0; tries <= maximum_retries; tries++) { drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd); - ret = dp_ctrl_read_link_status(ctrl, link_status); + ret = msm_dp_ctrl_read_link_status(ctrl, link_status); if (ret) return ret; @@ -1261,8 +1261,8 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, return 0; } - dp_link_adjust_levels(ctrl->link, link_status); - ret = dp_ctrl_update_vx_px(ctrl); + msm_dp_link_adjust_levels(ctrl->link, link_status); + ret = msm_dp_ctrl_update_vx_px(ctrl); if (ret) return ret; @@ -1271,24 +1271,24 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl, return -ETIMEDOUT; } -static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, +static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl, int *training_step) { int ret = 0; const u8 *dpcd = ctrl->panel->dpcd; u8 encoding[] = { 0, DP_SET_ANSI_8B10B }; u8 assr; - struct dp_link_info link_info = {0}; + struct msm_dp_link_info link_info = {0}; - dp_ctrl_config_ctrl(ctrl); + msm_dp_ctrl_config_ctrl(ctrl); link_info.num_lanes = ctrl->link->link_params.num_lanes; link_info.rate = ctrl->link->link_params.rate; link_info.capabilities = DP_LINK_CAP_ENHANCED_FRAMING; - dp_link_reset_phy_params_vx_px(ctrl->link); + msm_dp_link_reset_phy_params_vx_px(ctrl->link); - dp_aux_link_configure(ctrl->aux, &link_info); + msm_dp_aux_link_configure(ctrl->aux, &link_info); if (drm_dp_max_downspread(dpcd)) encoding[0] |= DP_SPREAD_AMP_0_5; @@ -1302,7 +1302,7 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, &assr, 1); } - ret = dp_ctrl_link_train_1(ctrl, training_step); + ret = msm_dp_ctrl_link_train_1(ctrl, training_step); if (ret) { DRM_ERROR("link training #1 failed. ret=%d\n", ret); goto end; @@ -1311,7 +1311,7 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, /* print success info as this is a result of user initiated action */ drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n"); - ret = dp_ctrl_link_train_2(ctrl, training_step); + ret = msm_dp_ctrl_link_train_2(ctrl, training_step); if (ret) { DRM_ERROR("link training #2 failed. ret=%d\n", ret); goto end; @@ -1321,17 +1321,17 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl, drm_dbg_dp(ctrl->drm_dev, "link training #2 successful\n"); end: - dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); return ret; } -static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, +static int msm_dp_ctrl_setup_main_link(struct msm_dp_ctrl_private *ctrl, int *training_step) { int ret = 0; - dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true); + msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true); if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) return ret; @@ -1342,17 +1342,17 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, * a link training pattern, we have to first do soft reset. */ - ret = dp_ctrl_link_train(ctrl, training_step); + ret = msm_dp_ctrl_link_train(ctrl, training_step); return ret; } -int dp_ctrl_core_clk_enable(struct dp_ctrl *dp_ctrl) +int msm_dp_ctrl_core_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; int ret = 0; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); if (ctrl->core_clks_on) { drm_dbg_dp(ctrl->drm_dev, "core clks already enabled\n"); @@ -1374,11 +1374,11 @@ int dp_ctrl_core_clk_enable(struct dp_ctrl *dp_ctrl) return 0; } -void dp_ctrl_core_clk_disable(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); clk_bulk_disable_unprepare(ctrl->num_core_clks, ctrl->core_clks); @@ -1391,12 +1391,12 @@ void dp_ctrl_core_clk_disable(struct dp_ctrl *dp_ctrl) ctrl->core_clks_on ? "on" : "off"); } -static int dp_ctrl_link_clk_enable(struct dp_ctrl *dp_ctrl) +static int msm_dp_ctrl_link_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; int ret = 0; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); if (ctrl->link_clks_on) { drm_dbg_dp(ctrl->drm_dev, "links clks already enabled\n"); @@ -1406,7 +1406,7 @@ static int dp_ctrl_link_clk_enable(struct dp_ctrl *dp_ctrl) if (!ctrl->core_clks_on) { drm_dbg_dp(ctrl->drm_dev, "Enable core clks before link clks\n"); - dp_ctrl_core_clk_enable(dp_ctrl); + msm_dp_ctrl_core_clk_enable(msm_dp_ctrl); } ret = clk_bulk_prepare_enable(ctrl->num_link_clks, ctrl->link_clks); @@ -1424,11 +1424,11 @@ static int dp_ctrl_link_clk_enable(struct dp_ctrl *dp_ctrl) return 0; } -static void dp_ctrl_link_clk_disable(struct dp_ctrl *dp_ctrl) +static void msm_dp_ctrl_link_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); clk_bulk_disable_unprepare(ctrl->num_link_clks, ctrl->link_clks); @@ -1441,7 +1441,7 @@ static void dp_ctrl_link_clk_disable(struct dp_ctrl *dp_ctrl) ctrl->core_clks_on ? "on" : "off"); } -static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_enable_mainlink_clocks(struct msm_dp_ctrl_private *ctrl) { int ret = 0; struct phy *phy = ctrl->phy; @@ -1455,7 +1455,7 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) phy_power_on(phy); dev_pm_opp_set_rate(ctrl->dev, ctrl->link->link_params.rate * 1000); - ret = dp_ctrl_link_clk_enable(&ctrl->dp_ctrl); + ret = msm_dp_ctrl_link_clk_enable(&ctrl->msm_dp_ctrl); if (ret) DRM_ERROR("Unable to start link clocks. ret=%d\n", ret); @@ -1464,13 +1464,13 @@ static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) return ret; } -void dp_ctrl_reset_irq_ctrl(struct dp_ctrl *dp_ctrl, bool enable) +void msm_dp_ctrl_reset_irq_ctrl(struct msm_dp_ctrl *msm_dp_ctrl, bool enable) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); - dp_catalog_ctrl_reset(ctrl->catalog); + msm_dp_catalog_ctrl_reset(ctrl->catalog); /* * all dp controller programmable registers will not @@ -1478,28 +1478,28 @@ void dp_ctrl_reset_irq_ctrl(struct dp_ctrl *dp_ctrl, bool enable) * therefore interrupt mask bits have to be updated * to enable/disable interrupts */ - dp_catalog_ctrl_enable_irq(ctrl->catalog, enable); + msm_dp_catalog_ctrl_enable_irq(ctrl->catalog, enable); } -void dp_ctrl_config_psr(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl) { u8 cfg; - struct dp_ctrl_private *ctrl = container_of(dp_ctrl, - struct dp_ctrl_private, dp_ctrl); + struct msm_dp_ctrl_private *ctrl = container_of(msm_dp_ctrl, + struct msm_dp_ctrl_private, msm_dp_ctrl); if (!ctrl->panel->psr_cap.version) return; - dp_catalog_ctrl_config_psr(ctrl->catalog); + msm_dp_catalog_ctrl_config_psr(ctrl->catalog); cfg = DP_PSR_ENABLE; drm_dp_dpcd_write(ctrl->aux, DP_PSR_EN_CFG, &cfg, 1); } -void dp_ctrl_set_psr(struct dp_ctrl *dp_ctrl, bool enter) +void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl, bool enter) { - struct dp_ctrl_private *ctrl = container_of(dp_ctrl, - struct dp_ctrl_private, dp_ctrl); + struct msm_dp_ctrl_private *ctrl = container_of(msm_dp_ctrl, + struct msm_dp_ctrl_private, msm_dp_ctrl); if (!ctrl->panel->psr_cap.version) return; @@ -1516,64 +1516,64 @@ void dp_ctrl_set_psr(struct dp_ctrl *dp_ctrl, bool enter) */ if (enter) { reinit_completion(&ctrl->psr_op_comp); - dp_catalog_ctrl_set_psr(ctrl->catalog, true); + msm_dp_catalog_ctrl_set_psr(ctrl->catalog, true); if (!wait_for_completion_timeout(&ctrl->psr_op_comp, PSR_OPERATION_COMPLETION_TIMEOUT_JIFFIES)) { DRM_ERROR("PSR_ENTRY timedout\n"); - dp_catalog_ctrl_set_psr(ctrl->catalog, false); + msm_dp_catalog_ctrl_set_psr(ctrl->catalog, false); return; } - dp_ctrl_push_idle(dp_ctrl); - dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); + msm_dp_ctrl_push_idle(msm_dp_ctrl); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); - dp_catalog_ctrl_psr_mainlink_enable(ctrl->catalog, false); + msm_dp_catalog_ctrl_psr_mainlink_enable(ctrl->catalog, false); } else { - dp_catalog_ctrl_psr_mainlink_enable(ctrl->catalog, true); + msm_dp_catalog_ctrl_psr_mainlink_enable(ctrl->catalog, true); - dp_catalog_ctrl_set_psr(ctrl->catalog, false); - dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO); - dp_ctrl_wait4video_ready(ctrl); - dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); + msm_dp_catalog_ctrl_set_psr(ctrl->catalog, false); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO); + msm_dp_ctrl_wait4video_ready(ctrl); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0); } } -void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_phy_init(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; struct phy *phy; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); phy = ctrl->phy; - dp_catalog_ctrl_phy_reset(ctrl->catalog); + msm_dp_catalog_ctrl_phy_reset(ctrl->catalog); phy_init(phy); drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", phy, phy->init_count, phy->power_count); } -void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; struct phy *phy; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); phy = ctrl->phy; - dp_catalog_ctrl_phy_reset(ctrl->catalog); + msm_dp_catalog_ctrl_phy_reset(ctrl->catalog); phy_exit(phy); drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", phy, phy->init_count, phy->power_count); } -static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl) { struct phy *phy = ctrl->phy; int ret = 0; - dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); + msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes; phy_configure(phy, &ctrl->phy_opts); /* @@ -1583,13 +1583,13 @@ static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl) */ dev_pm_opp_set_rate(ctrl->dev, 0); - dp_ctrl_link_clk_disable(&ctrl->dp_ctrl); + msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); phy_power_off(phy); /* hw recommended delay before re-enabling clocks */ msleep(20); - ret = dp_ctrl_enable_mainlink_clocks(ctrl); + ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl); if (ret) { DRM_ERROR("Failed to enable mainlink clks. ret=%d\n", ret); return ret; @@ -1598,18 +1598,18 @@ static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl) return ret; } -static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl) { struct phy *phy; phy = ctrl->phy; - dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); + msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); - dp_catalog_ctrl_reset(ctrl->catalog); + msm_dp_catalog_ctrl_reset(ctrl->catalog); dev_pm_opp_set_rate(ctrl->dev, 0); - dp_ctrl_link_clk_disable(&ctrl->dp_ctrl); + msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); phy_power_off(phy); @@ -1622,30 +1622,30 @@ static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl) return 0; } -static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl) { int ret = 0; int training_step = DP_TRAINING_NONE; - dp_ctrl_push_idle(&ctrl->dp_ctrl); + msm_dp_ctrl_push_idle(&ctrl->msm_dp_ctrl); ctrl->link->phy_params.p_level = 0; ctrl->link->phy_params.v_level = 0; - ret = dp_ctrl_setup_main_link(ctrl, &training_step); + ret = msm_dp_ctrl_setup_main_link(ctrl, &training_step); if (ret) goto end; - dp_ctrl_clear_training_pattern(ctrl); + msm_dp_ctrl_clear_training_pattern(ctrl); - dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO); - ret = dp_ctrl_wait4video_ready(ctrl); + ret = msm_dp_ctrl_wait4video_ready(ctrl); end: return ret; } -static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) +static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl) { bool success = false; u32 pattern_sent = 0x0; @@ -1653,17 +1653,17 @@ static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) drm_dbg_dp(ctrl->drm_dev, "request: 0x%x\n", pattern_requested); - if (dp_ctrl_set_vx_px(ctrl, + if (msm_dp_ctrl_set_vx_px(ctrl, ctrl->link->phy_params.v_level, ctrl->link->phy_params.p_level)) { DRM_ERROR("Failed to set v/p levels\n"); return false; } - dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested); - dp_ctrl_update_vx_px(ctrl); - dp_link_send_test_response(ctrl->link); + msm_dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested); + msm_dp_ctrl_update_vx_px(ctrl); + msm_dp_link_send_test_response(ctrl->link); - pattern_sent = dp_catalog_ctrl_read_phy_pattern(ctrl->catalog); + pattern_sent = msm_dp_catalog_ctrl_read_phy_pattern(ctrl->catalog); switch (pattern_sent) { case MR_LINK_TRAINING1: @@ -1697,7 +1697,7 @@ static bool dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) return success; } -static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_process_phy_test_request(struct msm_dp_ctrl_private *ctrl) { int ret; unsigned long pixel_rate; @@ -1713,15 +1713,15 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) * running. Add the global reset just before disabling the * link clocks and core clocks. */ - dp_ctrl_off(&ctrl->dp_ctrl); + msm_dp_ctrl_off(&ctrl->msm_dp_ctrl); - ret = dp_ctrl_on_link(&ctrl->dp_ctrl); + ret = msm_dp_ctrl_on_link(&ctrl->msm_dp_ctrl); if (ret) { DRM_ERROR("failed to enable DP link controller\n"); return ret; } - pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; + pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock; ret = clk_set_rate(ctrl->pixel_clk, pixel_rate * 1000); if (ret) { DRM_ERROR("Failed to set pixel clock rate. ret=%d\n", ret); @@ -1739,49 +1739,49 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) ctrl->stream_clks_on = true; } - dp_ctrl_send_phy_test_pattern(ctrl); + msm_dp_ctrl_send_phy_test_pattern(ctrl); return 0; } -void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; u32 sink_request = 0x0; - if (!dp_ctrl) { + if (!msm_dp_ctrl) { DRM_ERROR("invalid input\n"); return; } - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); sink_request = ctrl->link->sink_request; if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { drm_dbg_dp(ctrl->drm_dev, "PHY_TEST_PATTERN request\n"); - if (dp_ctrl_process_phy_test_request(ctrl)) { + if (msm_dp_ctrl_process_phy_test_request(ctrl)) { DRM_ERROR("process phy_test_req failed\n"); return; } } if (sink_request & DP_LINK_STATUS_UPDATED) { - if (dp_ctrl_link_maintenance(ctrl)) { + if (msm_dp_ctrl_link_maintenance(ctrl)) { DRM_ERROR("LM failed: TEST_LINK_TRAINING\n"); return; } } if (sink_request & DP_TEST_LINK_TRAINING) { - dp_link_send_test_response(ctrl->link); - if (dp_ctrl_link_maintenance(ctrl)) { + msm_dp_link_send_test_response(ctrl->link); + if (msm_dp_ctrl_link_maintenance(ctrl)) { DRM_ERROR("LM failed: TEST_LINK_TRAINING\n"); return; } } } -static bool dp_ctrl_clock_recovery_any_ok( +static bool msm_dp_ctrl_clock_recovery_any_ok( const u8 link_status[DP_LINK_STATUS_SIZE], int lane_count) { @@ -1800,20 +1800,20 @@ static bool dp_ctrl_clock_recovery_any_ok( return drm_dp_clock_recovery_ok(link_status, reduced_cnt); } -static bool dp_ctrl_channel_eq_ok(struct dp_ctrl_private *ctrl) +static bool msm_dp_ctrl_channel_eq_ok(struct msm_dp_ctrl_private *ctrl) { u8 link_status[DP_LINK_STATUS_SIZE]; int num_lanes = ctrl->link->link_params.num_lanes; - dp_ctrl_read_link_status(ctrl, link_status); + msm_dp_ctrl_read_link_status(ctrl, link_status); return drm_dp_channel_eq_ok(link_status, num_lanes); } -int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) +int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl) { int rc = 0; - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; u32 rate; int link_train_max_retries = 5; u32 const phy_cts_pixel_clk_khz = 148500; @@ -1821,15 +1821,15 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) unsigned int training_step; unsigned long pixel_rate; - if (!dp_ctrl) + if (!msm_dp_ctrl) return -EINVAL; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); rate = ctrl->panel->link_info.rate; - pixel_rate = ctrl->panel->dp_mode.drm_mode.clock; + pixel_rate = ctrl->panel->msm_dp_mode.drm_mode.clock; - dp_ctrl_core_clk_enable(&ctrl->dp_ctrl); + msm_dp_ctrl_core_clk_enable(&ctrl->msm_dp_ctrl); if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { drm_dbg_dp(ctrl->drm_dev, @@ -1840,7 +1840,7 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) ctrl->link->link_params.rate = rate; ctrl->link->link_params.num_lanes = ctrl->panel->link_info.num_lanes; - if (ctrl->panel->dp_mode.out_fmt_is_yuv_420) + if (ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420) pixel_rate >>= 1; } @@ -1848,32 +1848,32 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) ctrl->link->link_params.rate, ctrl->link->link_params.num_lanes, pixel_rate); - rc = dp_ctrl_enable_mainlink_clocks(ctrl); + rc = msm_dp_ctrl_enable_mainlink_clocks(ctrl); if (rc) return rc; while (--link_train_max_retries) { training_step = DP_TRAINING_NONE; - rc = dp_ctrl_setup_main_link(ctrl, &training_step); + rc = msm_dp_ctrl_setup_main_link(ctrl, &training_step); if (rc == 0) { /* training completed successfully */ break; } else if (training_step == DP_TRAINING_1) { /* link train_1 failed */ - if (!dp_catalog_link_is_connected(ctrl->catalog)) + if (!msm_dp_catalog_link_is_connected(ctrl->catalog)) break; - dp_ctrl_read_link_status(ctrl, link_status); + msm_dp_ctrl_read_link_status(ctrl, link_status); - rc = dp_ctrl_link_rate_down_shift(ctrl); + rc = msm_dp_ctrl_link_rate_down_shift(ctrl); if (rc < 0) { /* already in RBR = 1.6G */ - if (dp_ctrl_clock_recovery_any_ok(link_status, + if (msm_dp_ctrl_clock_recovery_any_ok(link_status, ctrl->link->link_params.num_lanes)) { /* * some lanes are ready, * reduce lane number */ - rc = dp_ctrl_link_lane_down_shift(ctrl); + rc = msm_dp_ctrl_link_lane_down_shift(ctrl); if (rc < 0) { /* lane == 1 already */ /* end with failure */ break; @@ -1885,16 +1885,16 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) } } else if (training_step == DP_TRAINING_2) { /* link train_2 failed */ - if (!dp_catalog_link_is_connected(ctrl->catalog)) + if (!msm_dp_catalog_link_is_connected(ctrl->catalog)) break; - dp_ctrl_read_link_status(ctrl, link_status); + msm_dp_ctrl_read_link_status(ctrl, link_status); if (!drm_dp_clock_recovery_ok(link_status, ctrl->link->link_params.num_lanes)) - rc = dp_ctrl_link_rate_down_shift(ctrl); + rc = msm_dp_ctrl_link_rate_down_shift(ctrl); else - rc = dp_ctrl_link_lane_down_shift(ctrl); + rc = msm_dp_ctrl_link_lane_down_shift(ctrl); if (rc < 0) { /* end with failure */ @@ -1902,10 +1902,10 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) } /* stop link training before start re training */ - dp_ctrl_clear_training_pattern(ctrl); + msm_dp_ctrl_clear_training_pattern(ctrl); } - rc = dp_ctrl_reinitialize_mainlink(ctrl); + rc = msm_dp_ctrl_reinitialize_mainlink(ctrl); if (rc) { DRM_ERROR("Failed to reinitialize mainlink. rc=%d\n", rc); break; @@ -1926,38 +1926,38 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl) * link training failed * end txing train pattern here */ - dp_ctrl_clear_training_pattern(ctrl); + msm_dp_ctrl_clear_training_pattern(ctrl); - dp_ctrl_deinitialize_mainlink(ctrl); + msm_dp_ctrl_deinitialize_mainlink(ctrl); rc = -ECONNRESET; } return rc; } -static int dp_ctrl_link_retrain(struct dp_ctrl_private *ctrl) +static int msm_dp_ctrl_link_retrain(struct msm_dp_ctrl_private *ctrl) { int training_step = DP_TRAINING_NONE; - return dp_ctrl_setup_main_link(ctrl, &training_step); + return msm_dp_ctrl_setup_main_link(ctrl, &training_step); } -int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) +int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train) { int ret = 0; bool mainlink_ready = false; - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; unsigned long pixel_rate; unsigned long pixel_rate_orig; - if (!dp_ctrl) + if (!msm_dp_ctrl) return -EINVAL; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); - pixel_rate = pixel_rate_orig = ctrl->panel->dp_mode.drm_mode.clock; + pixel_rate = pixel_rate_orig = ctrl->panel->msm_dp_mode.drm_mode.clock; - if (dp_ctrl->wide_bus_en || ctrl->panel->dp_mode.out_fmt_is_yuv_420) + if (msm_dp_ctrl->wide_bus_en || ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420) pixel_rate >>= 1; drm_dbg_dp(ctrl->drm_dev, "rate=%d, num_lanes=%d, pixel_rate=%lu\n", @@ -1969,7 +1969,7 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) ctrl->core_clks_on, ctrl->link_clks_on, ctrl->stream_clks_on); if (!ctrl->link_clks_on) { /* link clk is off */ - ret = dp_ctrl_enable_mainlink_clocks(ctrl); + ret = msm_dp_ctrl_enable_mainlink_clocks(ctrl); if (ret) { DRM_ERROR("Failed to start link clocks. ret=%d\n", ret); goto end; @@ -1993,11 +1993,11 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) ctrl->stream_clks_on = true; } - if (force_link_train || !dp_ctrl_channel_eq_ok(ctrl)) - dp_ctrl_link_retrain(ctrl); + if (force_link_train || !msm_dp_ctrl_channel_eq_ok(ctrl)) + msm_dp_ctrl_link_retrain(ctrl); /* stop txing train pattern to end link training */ - dp_ctrl_clear_training_pattern(ctrl); + msm_dp_ctrl_clear_training_pattern(ctrl); /* * Set up transfer unit values and set controller state to send @@ -2005,22 +2005,22 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) */ reinit_completion(&ctrl->video_comp); - dp_ctrl_configure_source_params(ctrl); + msm_dp_ctrl_configure_source_params(ctrl); - dp_catalog_ctrl_config_msa(ctrl->catalog, + msm_dp_catalog_ctrl_config_msa(ctrl->catalog, ctrl->link->link_params.rate, pixel_rate_orig, - ctrl->panel->dp_mode.out_fmt_is_yuv_420); + ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420); - dp_ctrl_setup_tr_unit(ctrl); + msm_dp_ctrl_setup_tr_unit(ctrl); - dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO); + msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO); - ret = dp_ctrl_wait4video_ready(ctrl); + ret = msm_dp_ctrl_wait4video_ready(ctrl); if (ret) return ret; - mainlink_ready = dp_catalog_ctrl_mainlink_ready(ctrl->catalog); + mainlink_ready = msm_dp_catalog_ctrl_mainlink_ready(ctrl->catalog); drm_dbg_dp(ctrl->drm_dev, "mainlink %s\n", mainlink_ready ? "READY" : "NOT READY"); @@ -2028,20 +2028,20 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train) return ret; } -void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; struct phy *phy; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); phy = ctrl->phy; - dp_catalog_panel_disable_vsc_sdp(ctrl->catalog); + msm_dp_catalog_panel_disable_vsc_sdp(ctrl->catalog); /* set dongle to D3 (power off) mode */ - dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true); + msm_dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true); - dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); + msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); if (ctrl->stream_clks_on) { clk_disable_unprepare(ctrl->pixel_clk); @@ -2049,7 +2049,7 @@ void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) } dev_pm_opp_set_rate(ctrl->dev, 0); - dp_ctrl_link_clk_disable(&ctrl->dp_ctrl); + msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); phy_power_off(phy); @@ -2061,17 +2061,17 @@ void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl) phy, phy->init_count, phy->power_count); } -void dp_ctrl_off_link(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; struct phy *phy; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); phy = ctrl->phy; - dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); + msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); - dp_ctrl_link_clk_disable(&ctrl->dp_ctrl); + msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); DRM_DEBUG_DP("Before, phy=%p init_count=%d power_on=%d\n", phy, phy->init_count, phy->power_count); @@ -2082,19 +2082,19 @@ void dp_ctrl_off_link(struct dp_ctrl *dp_ctrl) phy, phy->init_count, phy->power_count); } -void dp_ctrl_off(struct dp_ctrl *dp_ctrl) +void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; struct phy *phy; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); phy = ctrl->phy; - dp_catalog_panel_disable_vsc_sdp(ctrl->catalog); + msm_dp_catalog_panel_disable_vsc_sdp(ctrl->catalog); - dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); + msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false); - dp_catalog_ctrl_reset(ctrl->catalog); + msm_dp_catalog_ctrl_reset(ctrl->catalog); if (ctrl->stream_clks_on) { clk_disable_unprepare(ctrl->pixel_clk); @@ -2102,26 +2102,26 @@ void dp_ctrl_off(struct dp_ctrl *dp_ctrl) } dev_pm_opp_set_rate(ctrl->dev, 0); - dp_ctrl_link_clk_disable(&ctrl->dp_ctrl); + msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl); phy_power_off(phy); drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n", phy, phy->init_count, phy->power_count); } -irqreturn_t dp_ctrl_isr(struct dp_ctrl *dp_ctrl) +irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; u32 isr; irqreturn_t ret = IRQ_NONE; - if (!dp_ctrl) + if (!msm_dp_ctrl) return IRQ_NONE; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); if (ctrl->panel->psr_cap.version) { - isr = dp_catalog_ctrl_read_psr_interrupt_status(ctrl->catalog); + isr = msm_dp_catalog_ctrl_read_psr_interrupt_status(ctrl->catalog); if (isr) complete(&ctrl->psr_op_comp); @@ -2136,7 +2136,7 @@ irqreturn_t dp_ctrl_isr(struct dp_ctrl *dp_ctrl) drm_dbg_dp(ctrl->drm_dev, "PSR frame capture done\n"); } - isr = dp_catalog_ctrl_get_interrupt(ctrl->catalog); + isr = msm_dp_catalog_ctrl_get_interrupt(ctrl->catalog); if (isr & DP_CTRL_INTR_READY_FOR_VIDEO) { @@ -2164,13 +2164,13 @@ static const char *ctrl_clks[] = { "ctrl_link_iface", }; -static int dp_ctrl_clk_init(struct dp_ctrl *dp_ctrl) +static int msm_dp_ctrl_clk_init(struct msm_dp_ctrl *msm_dp_ctrl) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; struct device *dev; int i, rc; - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl); dev = ctrl->dev; ctrl->num_core_clks = ARRAY_SIZE(core_clks); @@ -2204,12 +2204,12 @@ static int dp_ctrl_clk_init(struct dp_ctrl *dp_ctrl) return 0; } -struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link, - struct dp_panel *panel, struct drm_dp_aux *aux, - struct dp_catalog *catalog, +struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link, + struct msm_dp_panel *panel, struct drm_dp_aux *aux, + struct msm_dp_catalog *catalog, struct phy *phy) { - struct dp_ctrl_private *ctrl; + struct msm_dp_ctrl_private *ctrl; int ret; if (!dev || !panel || !aux || @@ -2228,7 +2228,7 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link, if (ret) { dev_err(dev, "invalid DP OPP table in device tree\n"); /* caller do PTR_ERR(opp_table) */ - return (struct dp_ctrl *)ERR_PTR(ret); + return (struct msm_dp_ctrl *)ERR_PTR(ret); } /* OPP table is optional */ @@ -2248,11 +2248,11 @@ struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link, ctrl->dev = dev; ctrl->phy = phy; - ret = dp_ctrl_clk_init(&ctrl->dp_ctrl); + ret = msm_dp_ctrl_clk_init(&ctrl->msm_dp_ctrl); if (ret) { dev_err(dev, "failed to init clocks\n"); return ERR_PTR(ret); } - return &ctrl->dp_ctrl; + return &ctrl->msm_dp_ctrl; } diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h index ffcbd9a2574802..b7abfedbf5749c 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h @@ -11,34 +11,34 @@ #include "dp_link.h" #include "dp_catalog.h" -struct dp_ctrl { +struct msm_dp_ctrl { bool wide_bus_en; }; struct phy; -int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl); -int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl, bool force_link_train); -void dp_ctrl_off_link_stream(struct dp_ctrl *dp_ctrl); -void dp_ctrl_off_link(struct dp_ctrl *dp_ctrl); -void dp_ctrl_off(struct dp_ctrl *dp_ctrl); -void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl); -irqreturn_t dp_ctrl_isr(struct dp_ctrl *dp_ctrl); -void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl); -struct dp_ctrl *dp_ctrl_get(struct device *dev, struct dp_link *link, - struct dp_panel *panel, struct drm_dp_aux *aux, - struct dp_catalog *catalog, +int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl); +int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train); +void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl); +irqreturn_t msm_dp_ctrl_isr(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_handle_sink_request(struct msm_dp_ctrl *msm_dp_ctrl); +struct msm_dp_ctrl *msm_dp_ctrl_get(struct device *dev, struct msm_dp_link *link, + struct msm_dp_panel *panel, struct drm_dp_aux *aux, + struct msm_dp_catalog *catalog, struct phy *phy); -void dp_ctrl_reset_irq_ctrl(struct dp_ctrl *dp_ctrl, bool enable); -void dp_ctrl_phy_init(struct dp_ctrl *dp_ctrl); -void dp_ctrl_phy_exit(struct dp_ctrl *dp_ctrl); -void dp_ctrl_irq_phy_exit(struct dp_ctrl *dp_ctrl); +void msm_dp_ctrl_reset_irq_ctrl(struct msm_dp_ctrl *msm_dp_ctrl, bool enable); +void msm_dp_ctrl_phy_init(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_irq_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl); -void dp_ctrl_set_psr(struct dp_ctrl *dp_ctrl, bool enable); -void dp_ctrl_config_psr(struct dp_ctrl *dp_ctrl); +void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl, bool enable); +void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl); -int dp_ctrl_core_clk_enable(struct dp_ctrl *dp_ctrl); -void dp_ctrl_core_clk_disable(struct dp_ctrl *dp_ctrl); +int msm_dp_ctrl_core_clk_enable(struct msm_dp_ctrl *msm_dp_ctrl); +void msm_dp_ctrl_core_clk_disable(struct msm_dp_ctrl *msm_dp_ctrl); #endif /* _DP_CTRL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index b8611f6d229677..22fd946ee20139 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -17,15 +17,15 @@ #define DEBUG_NAME "msm_dp" -struct dp_debug_private { - struct dp_link *link; - struct dp_panel *panel; +struct msm_dp_debug_private { + struct msm_dp_link *link; + struct msm_dp_panel *panel; struct drm_connector *connector; }; -static int dp_debug_show(struct seq_file *seq, void *p) +static int msm_dp_debug_show(struct seq_file *seq, void *p) { - struct dp_debug_private *debug = seq->private; + struct msm_dp_debug_private *debug = seq->private; u64 lclk = 0; u32 link_params_rate; const struct drm_display_mode *drm_mode; @@ -33,7 +33,7 @@ static int dp_debug_show(struct seq_file *seq, void *p) if (!debug) return -ENODEV; - drm_mode = &debug->panel->dp_mode.drm_mode; + drm_mode = &debug->panel->msm_dp_mode.drm_mode; seq_printf(seq, "\tname = %s\n", DEBUG_NAME); seq_printf(seq, "\tdrm_dp_link\n\t\trate = %u\n", @@ -55,8 +55,8 @@ static int dp_debug_show(struct seq_file *seq, void *p) drm_mode->hsync_end - drm_mode->hsync_start, drm_mode->vsync_end - drm_mode->vsync_start); seq_printf(seq, "\t\tactive_low = %dx%d\n", - debug->panel->dp_mode.h_active_low, - debug->panel->dp_mode.v_active_low); + debug->panel->msm_dp_mode.h_active_low, + debug->panel->msm_dp_mode.v_active_low); seq_printf(seq, "\t\th_skew = %d\n", drm_mode->hskew); seq_printf(seq, "\t\trefresh rate = %d\n", @@ -64,7 +64,7 @@ static int dp_debug_show(struct seq_file *seq, void *p) seq_printf(seq, "\t\tpixel clock khz = %d\n", drm_mode->clock); seq_printf(seq, "\t\tbpp = %d\n", - debug->panel->dp_mode.bpp); + debug->panel->msm_dp_mode.bpp); /* Link Information */ seq_printf(seq, "\tdp_link:\n\t\ttest_requested = %d\n", @@ -83,11 +83,11 @@ static int dp_debug_show(struct seq_file *seq, void *p) return 0; } -DEFINE_SHOW_ATTRIBUTE(dp_debug); +DEFINE_SHOW_ATTRIBUTE(msm_dp_debug); -static int dp_test_data_show(struct seq_file *m, void *data) +static int msm_dp_test_data_show(struct seq_file *m, void *data) { - const struct dp_debug_private *debug = m->private; + const struct msm_dp_debug_private *debug = m->private; const struct drm_connector *connector = debug->connector; u32 bpc; @@ -98,18 +98,18 @@ static int dp_test_data_show(struct seq_file *m, void *data) seq_printf(m, "vdisplay: %d\n", debug->link->test_video.test_v_height); seq_printf(m, "bpc: %u\n", - dp_link_bit_depth_to_bpp(bpc) / 3); + msm_dp_link_bit_depth_to_bpp(bpc) / 3); } else { seq_puts(m, "0"); } return 0; } -DEFINE_SHOW_ATTRIBUTE(dp_test_data); +DEFINE_SHOW_ATTRIBUTE(msm_dp_test_data); -static int dp_test_type_show(struct seq_file *m, void *data) +static int msm_dp_test_type_show(struct seq_file *m, void *data) { - const struct dp_debug_private *debug = m->private; + const struct msm_dp_debug_private *debug = m->private; const struct drm_connector *connector = debug->connector; if (connector->status == connector_status_connected) @@ -119,15 +119,15 @@ static int dp_test_type_show(struct seq_file *m, void *data) return 0; } -DEFINE_SHOW_ATTRIBUTE(dp_test_type); +DEFINE_SHOW_ATTRIBUTE(msm_dp_test_type); -static ssize_t dp_test_active_write(struct file *file, +static ssize_t msm_dp_test_active_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { char *input_buffer; int status = 0; - const struct dp_debug_private *debug; + const struct msm_dp_debug_private *debug; const struct drm_connector *connector; int val = 0; @@ -164,9 +164,9 @@ static ssize_t dp_test_active_write(struct file *file, return len; } -static int dp_test_active_show(struct seq_file *m, void *data) +static int msm_dp_test_active_show(struct seq_file *m, void *data) { - struct dp_debug_private *debug = m->private; + struct msm_dp_debug_private *debug = m->private; struct drm_connector *connector = debug->connector; if (connector->status == connector_status_connected) { @@ -181,28 +181,28 @@ static int dp_test_active_show(struct seq_file *m, void *data) return 0; } -static int dp_test_active_open(struct inode *inode, +static int msm_dp_test_active_open(struct inode *inode, struct file *file) { - return single_open(file, dp_test_active_show, + return single_open(file, msm_dp_test_active_show, inode->i_private); } static const struct file_operations test_active_fops = { .owner = THIS_MODULE, - .open = dp_test_active_open, + .open = msm_dp_test_active_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, - .write = dp_test_active_write + .write = msm_dp_test_active_write }; -int dp_debug_init(struct device *dev, struct dp_panel *panel, - struct dp_link *link, +int msm_dp_debug_init(struct device *dev, struct msm_dp_panel *panel, + struct msm_dp_link *link, struct drm_connector *connector, struct dentry *root, bool is_edp) { - struct dp_debug_private *debug; + struct msm_dp_debug_private *debug; if (!dev || !panel || !link) { DRM_ERROR("invalid input\n"); @@ -217,20 +217,20 @@ int dp_debug_init(struct device *dev, struct dp_panel *panel, debug->panel = panel; debugfs_create_file("dp_debug", 0444, root, - debug, &dp_debug_fops); + debug, &msm_dp_debug_fops); if (!is_edp) { - debugfs_create_file("msm_dp_test_active", 0444, + debugfs_create_file("dp_test_active", 0444, root, debug, &test_active_fops); - debugfs_create_file("msm_dp_test_data", 0444, + debugfs_create_file("dp_test_data", 0444, root, - debug, &dp_test_data_fops); + debug, &msm_dp_test_data_fops); - debugfs_create_file("msm_dp_test_type", 0444, + debugfs_create_file("dp_test_type", 0444, root, - debug, &dp_test_type_fops); + debug, &msm_dp_test_type_fops); } return 0; diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h index 7e1aa892fc091a..6dc0ff4f0f650f 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.h +++ b/drivers/gpu/drm/msm/dp/dp_debug.h @@ -12,7 +12,7 @@ #if defined(CONFIG_DEBUG_FS) /** - * dp_debug_get() - configure and get the DisplayPlot debug module data + * msm_dp_debug_get() - configure and get the DisplayPlot debug module data * * @dev: device instance of the caller * @panel: instance of panel module @@ -25,8 +25,8 @@ * This function sets up the debug module and provides a way * for debugfs input to be communicated with existing modules */ -int dp_debug_init(struct device *dev, struct dp_panel *panel, - struct dp_link *link, +int msm_dp_debug_init(struct device *dev, struct msm_dp_panel *panel, + struct msm_dp_link *link, struct drm_connector *connector, struct dentry *root, bool is_edp); @@ -34,8 +34,8 @@ int dp_debug_init(struct device *dev, struct dp_panel *panel, #else static inline -int dp_debug_init(struct device *dev, struct dp_panel *panel, - struct dp_link *link, +int msm_dp_debug_init(struct device *dev, struct msm_dp_panel *panel, + struct msm_dp_link *link, struct drm_connector *connector, struct dentry *root, bool is_edp) diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index e1228fb093ee01..aff51bb973ebe0 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -67,13 +67,13 @@ enum { #define WAIT_FOR_RESUME_TIMEOUT_JIFFIES (HZ / 2) -struct dp_event { +struct msm_dp_event { u32 event_id; u32 data; u32 delay; }; -struct dp_display_private { +struct msm_dp_display_private { int irq; unsigned int id; @@ -85,14 +85,14 @@ struct dp_display_private { struct drm_device *drm_dev; - struct dp_catalog *catalog; + struct msm_dp_catalog *catalog; struct drm_dp_aux *aux; - struct dp_link *link; - struct dp_panel *panel; - struct dp_ctrl *ctrl; + struct msm_dp_link *link; + struct msm_dp_panel *panel; + struct msm_dp_ctrl *ctrl; - struct dp_display_mode dp_mode; - struct msm_dp dp_display; + struct msm_dp_display_mode msm_dp_mode; + struct msm_dp msm_dp_display; /* wait for audio signaling */ struct completion audio_comp; @@ -104,12 +104,12 @@ struct dp_display_private { u32 event_pndx; u32 event_gndx; struct task_struct *ev_tsk; - struct dp_event event_list[DP_EVENT_Q_MAX]; + struct msm_dp_event event_list[DP_EVENT_Q_MAX]; spinlock_t event_lock; bool wide_bus_supported; - struct dp_audio *audio; + struct msm_dp_audio *audio; }; struct msm_dp_desc { @@ -118,25 +118,33 @@ struct msm_dp_desc { bool wide_bus_supported; }; -static const struct msm_dp_desc sc7180_dp_descs[] = { +static const struct msm_dp_desc msm_dp_desc_sa8775p[] = { + { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, + { .io_start = 0x0af5c000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, + { .io_start = 0x22154000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, + { .io_start = 0x2215c000, .id = MSM_DP_CONTROLLER_3, .wide_bus_supported = true }, + {} +}; + +static const struct msm_dp_desc msm_dp_desc_sc7180[] = { { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, {} }; -static const struct msm_dp_desc sc7280_dp_descs[] = { +static const struct msm_dp_desc msm_dp_desc_sc7280[] = { { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, {} }; -static const struct msm_dp_desc sc8180x_dp_descs[] = { +static const struct msm_dp_desc msm_dp_desc_sc8180x[] = { { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, {} }; -static const struct msm_dp_desc sc8280xp_dp_descs[] = { +static const struct msm_dp_desc msm_dp_desc_sc8280xp[] = { { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, @@ -148,12 +156,12 @@ static const struct msm_dp_desc sc8280xp_dp_descs[] = { {} }; -static const struct msm_dp_desc sm8650_dp_descs[] = { +static const struct msm_dp_desc msm_dp_desc_sm8650[] = { { .io_start = 0x0af54000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, {} }; -static const struct msm_dp_desc x1e80100_dp_descs[] = { +static const struct msm_dp_desc msm_dp_desc_x1e80100[] = { { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true }, { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .wide_bus_supported = true }, { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .wide_bus_supported = true }, @@ -161,70 +169,71 @@ static const struct msm_dp_desc x1e80100_dp_descs[] = { {} }; -static const struct of_device_id dp_dt_match[] = { - { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_descs }, - { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_descs }, - { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_descs }, - { .compatible = "qcom,sc8180x-dp", .data = &sc8180x_dp_descs }, - { .compatible = "qcom,sc8180x-edp", .data = &sc8180x_dp_descs }, - { .compatible = "qcom,sc8280xp-dp", .data = &sc8280xp_dp_descs }, - { .compatible = "qcom,sc8280xp-edp", .data = &sc8280xp_dp_descs }, - { .compatible = "qcom,sdm845-dp", .data = &sc7180_dp_descs }, - { .compatible = "qcom,sm8350-dp", .data = &sc7180_dp_descs }, - { .compatible = "qcom,sm8650-dp", .data = &sm8650_dp_descs }, - { .compatible = "qcom,x1e80100-dp", .data = &x1e80100_dp_descs }, +static const struct of_device_id msm_dp_dt_match[] = { + { .compatible = "qcom,sa8775p-dp", .data = &msm_dp_desc_sa8775p }, + { .compatible = "qcom,sc7180-dp", .data = &msm_dp_desc_sc7180 }, + { .compatible = "qcom,sc7280-dp", .data = &msm_dp_desc_sc7280 }, + { .compatible = "qcom,sc7280-edp", .data = &msm_dp_desc_sc7280 }, + { .compatible = "qcom,sc8180x-dp", .data = &msm_dp_desc_sc8180x }, + { .compatible = "qcom,sc8180x-edp", .data = &msm_dp_desc_sc8180x }, + { .compatible = "qcom,sc8280xp-dp", .data = &msm_dp_desc_sc8280xp }, + { .compatible = "qcom,sc8280xp-edp", .data = &msm_dp_desc_sc8280xp }, + { .compatible = "qcom,sdm845-dp", .data = &msm_dp_desc_sc7180 }, + { .compatible = "qcom,sm8350-dp", .data = &msm_dp_desc_sc7180 }, + { .compatible = "qcom,sm8650-dp", .data = &msm_dp_desc_sm8650 }, + { .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 }, {} }; -static struct dp_display_private *dev_get_dp_display_private(struct device *dev) +static struct msm_dp_display_private *dev_get_dp_display_private(struct device *dev) { struct msm_dp *dp = dev_get_drvdata(dev); - return container_of(dp, struct dp_display_private, dp_display); + return container_of(dp, struct msm_dp_display_private, msm_dp_display); } -static int dp_add_event(struct dp_display_private *dp_priv, u32 event, +static int msm_dp_add_event(struct msm_dp_display_private *msm_dp_priv, u32 event, u32 data, u32 delay) { unsigned long flag; - struct dp_event *todo; + struct msm_dp_event *todo; int pndx; - spin_lock_irqsave(&dp_priv->event_lock, flag); - pndx = dp_priv->event_pndx + 1; + spin_lock_irqsave(&msm_dp_priv->event_lock, flag); + pndx = msm_dp_priv->event_pndx + 1; pndx %= DP_EVENT_Q_MAX; - if (pndx == dp_priv->event_gndx) { + if (pndx == msm_dp_priv->event_gndx) { pr_err("event_q is full: pndx=%d gndx=%d\n", - dp_priv->event_pndx, dp_priv->event_gndx); - spin_unlock_irqrestore(&dp_priv->event_lock, flag); + msm_dp_priv->event_pndx, msm_dp_priv->event_gndx); + spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); return -EPERM; } - todo = &dp_priv->event_list[dp_priv->event_pndx++]; - dp_priv->event_pndx %= DP_EVENT_Q_MAX; + todo = &msm_dp_priv->event_list[msm_dp_priv->event_pndx++]; + msm_dp_priv->event_pndx %= DP_EVENT_Q_MAX; todo->event_id = event; todo->data = data; todo->delay = delay; - wake_up(&dp_priv->event_q); - spin_unlock_irqrestore(&dp_priv->event_lock, flag); + wake_up(&msm_dp_priv->event_q); + spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); return 0; } -static int dp_del_event(struct dp_display_private *dp_priv, u32 event) +static int msm_dp_del_event(struct msm_dp_display_private *msm_dp_priv, u32 event) { unsigned long flag; - struct dp_event *todo; + struct msm_dp_event *todo; u32 gndx; - spin_lock_irqsave(&dp_priv->event_lock, flag); - if (dp_priv->event_pndx == dp_priv->event_gndx) { - spin_unlock_irqrestore(&dp_priv->event_lock, flag); + spin_lock_irqsave(&msm_dp_priv->event_lock, flag); + if (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) { + spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); return -ENOENT; } - gndx = dp_priv->event_gndx; - while (dp_priv->event_pndx != gndx) { - todo = &dp_priv->event_list[gndx]; + gndx = msm_dp_priv->event_gndx; + while (msm_dp_priv->event_pndx != gndx) { + todo = &msm_dp_priv->event_list[gndx]; if (todo->event_id == event) { todo->event_id = EV_NO_EVENT; /* deleted */ todo->delay = 0; @@ -232,60 +241,60 @@ static int dp_del_event(struct dp_display_private *dp_priv, u32 event) gndx++; gndx %= DP_EVENT_Q_MAX; } - spin_unlock_irqrestore(&dp_priv->event_lock, flag); + spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); return 0; } -void dp_display_signal_audio_start(struct msm_dp *dp_display) +void msm_dp_display_signal_audio_start(struct msm_dp *msm_dp_display) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; - dp = container_of(dp_display, struct dp_display_private, dp_display); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); reinit_completion(&dp->audio_comp); } -void dp_display_signal_audio_complete(struct msm_dp *dp_display) +void msm_dp_display_signal_audio_complete(struct msm_dp *msm_dp_display) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; - dp = container_of(dp_display, struct dp_display_private, dp_display); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); complete_all(&dp->audio_comp); } -static int dp_hpd_event_thread_start(struct dp_display_private *dp_priv); +static int msm_dp_hpd_event_thread_start(struct msm_dp_display_private *msm_dp_priv); -static int dp_display_bind(struct device *dev, struct device *master, +static int msm_dp_display_bind(struct device *dev, struct device *master, void *data) { int rc = 0; - struct dp_display_private *dp = dev_get_dp_display_private(dev); + struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); struct msm_drm_private *priv = dev_get_drvdata(master); struct drm_device *drm = priv->dev; - dp->dp_display.drm_dev = drm; - priv->dp[dp->id] = &dp->dp_display; + dp->msm_dp_display.drm_dev = drm; + priv->dp[dp->id] = &dp->msm_dp_display; dp->drm_dev = drm; dp->aux->drm_dev = drm; - rc = dp_aux_register(dp->aux); + rc = msm_dp_aux_register(dp->aux); if (rc) { DRM_ERROR("DRM DP AUX register failed\n"); goto end; } - rc = dp_register_audio_driver(dev, dp->audio); + rc = msm_dp_register_audio_driver(dev, dp->audio); if (rc) { DRM_ERROR("Audio registration Dp failed\n"); goto end; } - rc = dp_hpd_event_thread_start(dp); + rc = msm_dp_hpd_event_thread_start(dp); if (rc) { DRM_ERROR("Event thread create failed\n"); goto end; @@ -296,44 +305,44 @@ static int dp_display_bind(struct device *dev, struct device *master, return rc; } -static void dp_display_unbind(struct device *dev, struct device *master, +static void msm_dp_display_unbind(struct device *dev, struct device *master, void *data) { - struct dp_display_private *dp = dev_get_dp_display_private(dev); + struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); struct msm_drm_private *priv = dev_get_drvdata(master); kthread_stop(dp->ev_tsk); of_dp_aux_depopulate_bus(dp->aux); - dp_unregister_audio_driver(dev, dp->audio); - dp_aux_unregister(dp->aux); + msm_dp_unregister_audio_driver(dev, dp->audio); + msm_dp_aux_unregister(dp->aux); dp->drm_dev = NULL; dp->aux->drm_dev = NULL; priv->dp[dp->id] = NULL; } -static const struct component_ops dp_display_comp_ops = { - .bind = dp_display_bind, - .unbind = dp_display_unbind, +static const struct component_ops msm_dp_display_comp_ops = { + .bind = msm_dp_display_bind, + .unbind = msm_dp_display_unbind, }; -static void dp_display_send_hpd_event(struct msm_dp *dp_display) +static void msm_dp_display_send_hpd_event(struct msm_dp *msm_dp_display) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; struct drm_connector *connector; - dp = container_of(dp_display, struct dp_display_private, dp_display); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - connector = dp->dp_display.connector; + connector = dp->msm_dp_display.connector; drm_helper_hpd_irq_event(connector->dev); } -static int dp_display_send_hpd_notification(struct dp_display_private *dp, +static int msm_dp_display_send_hpd_notification(struct msm_dp_display_private *dp, bool hpd) { - if ((hpd && dp->dp_display.link_ready) || - (!hpd && !dp->dp_display.link_ready)) { + if ((hpd && dp->msm_dp_display.link_ready) || + (!hpd && !dp->msm_dp_display.link_ready)) { drm_dbg_dp(dp->drm_dev, "HPD already %s\n", (hpd ? "on" : "off")); return 0; @@ -342,139 +351,139 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp, /* reset video pattern flag on disconnect */ if (!hpd) { dp->panel->video_test = false; - if (!dp->dp_display.is_edp) - drm_dp_set_subconnector_property(dp->dp_display.connector, + if (!dp->msm_dp_display.is_edp) + drm_dp_set_subconnector_property(dp->msm_dp_display.connector, connector_status_disconnected, dp->panel->dpcd, dp->panel->downstream_ports); } - dp->dp_display.link_ready = hpd; + dp->msm_dp_display.link_ready = hpd; drm_dbg_dp(dp->drm_dev, "type=%d hpd=%d\n", - dp->dp_display.connector_type, hpd); - dp_display_send_hpd_event(&dp->dp_display); + dp->msm_dp_display.connector_type, hpd); + msm_dp_display_send_hpd_event(&dp->msm_dp_display); return 0; } -static int dp_display_process_hpd_high(struct dp_display_private *dp) +static int msm_dp_display_process_hpd_high(struct msm_dp_display_private *dp) { - struct drm_connector *connector = dp->dp_display.connector; + struct drm_connector *connector = dp->msm_dp_display.connector; const struct drm_display_info *info = &connector->display_info; int rc = 0; - rc = dp_panel_read_sink_caps(dp->panel, connector); + rc = msm_dp_panel_read_sink_caps(dp->panel, connector); if (rc) goto end; - dp_link_process_request(dp->link); + msm_dp_link_process_request(dp->link); - if (!dp->dp_display.is_edp) + if (!dp->msm_dp_display.is_edp) drm_dp_set_subconnector_property(connector, connector_status_connected, dp->panel->dpcd, dp->panel->downstream_ports); - dp->dp_display.psr_supported = dp->panel->psr_cap.version && psr_enabled; + dp->msm_dp_display.psr_supported = dp->panel->psr_cap.version && psr_enabled; dp->audio_supported = info->has_audio; - dp_panel_handle_sink_request(dp->panel); + msm_dp_panel_handle_sink_request(dp->panel); /* * set sink to normal operation mode -- D0 * before dpcd read */ - dp_link_psm_config(dp->link, &dp->panel->link_info, false); + msm_dp_link_psm_config(dp->link, &dp->panel->link_info, false); - dp_link_reset_phy_params_vx_px(dp->link); - rc = dp_ctrl_on_link(dp->ctrl); + msm_dp_link_reset_phy_params_vx_px(dp->link); + rc = msm_dp_ctrl_on_link(dp->ctrl); if (rc) { DRM_ERROR("failed to complete DP link training\n"); goto end; } - dp_add_event(dp, EV_USER_NOTIFICATION, true, 0); + msm_dp_add_event(dp, EV_USER_NOTIFICATION, true, 0); end: return rc; } -static void dp_display_host_phy_init(struct dp_display_private *dp) +static void msm_dp_display_host_phy_init(struct msm_dp_display_private *dp) { drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n", - dp->dp_display.connector_type, dp->core_initialized, + dp->msm_dp_display.connector_type, dp->core_initialized, dp->phy_initialized); if (!dp->phy_initialized) { - dp_ctrl_phy_init(dp->ctrl); + msm_dp_ctrl_phy_init(dp->ctrl); dp->phy_initialized = true; } } -static void dp_display_host_phy_exit(struct dp_display_private *dp) +static void msm_dp_display_host_phy_exit(struct msm_dp_display_private *dp) { drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n", - dp->dp_display.connector_type, dp->core_initialized, + dp->msm_dp_display.connector_type, dp->core_initialized, dp->phy_initialized); if (dp->phy_initialized) { - dp_ctrl_phy_exit(dp->ctrl); + msm_dp_ctrl_phy_exit(dp->ctrl); dp->phy_initialized = false; } } -static void dp_display_host_init(struct dp_display_private *dp) +static void msm_dp_display_host_init(struct msm_dp_display_private *dp) { drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n", - dp->dp_display.connector_type, dp->core_initialized, + dp->msm_dp_display.connector_type, dp->core_initialized, dp->phy_initialized); - dp_ctrl_core_clk_enable(dp->ctrl); - dp_ctrl_reset_irq_ctrl(dp->ctrl, true); - dp_aux_init(dp->aux); + msm_dp_ctrl_core_clk_enable(dp->ctrl); + msm_dp_ctrl_reset_irq_ctrl(dp->ctrl, true); + msm_dp_aux_init(dp->aux); dp->core_initialized = true; } -static void dp_display_host_deinit(struct dp_display_private *dp) +static void msm_dp_display_host_deinit(struct msm_dp_display_private *dp) { drm_dbg_dp(dp->drm_dev, "type=%d core_init=%d phy_init=%d\n", - dp->dp_display.connector_type, dp->core_initialized, + dp->msm_dp_display.connector_type, dp->core_initialized, dp->phy_initialized); - dp_ctrl_reset_irq_ctrl(dp->ctrl, false); - dp_aux_deinit(dp->aux); - dp_ctrl_core_clk_disable(dp->ctrl); + msm_dp_ctrl_reset_irq_ctrl(dp->ctrl, false); + msm_dp_aux_deinit(dp->aux); + msm_dp_ctrl_core_clk_disable(dp->ctrl); dp->core_initialized = false; } -static int dp_display_usbpd_configure_cb(struct device *dev) +static int msm_dp_display_usbpd_configure_cb(struct device *dev) { - struct dp_display_private *dp = dev_get_dp_display_private(dev); + struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); - dp_display_host_phy_init(dp); + msm_dp_display_host_phy_init(dp); - return dp_display_process_hpd_high(dp); + return msm_dp_display_process_hpd_high(dp); } -static int dp_display_notify_disconnect(struct device *dev) +static int msm_dp_display_notify_disconnect(struct device *dev) { - struct dp_display_private *dp = dev_get_dp_display_private(dev); + struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); - dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); + msm_dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); return 0; } -static void dp_display_handle_video_request(struct dp_display_private *dp) +static void msm_dp_display_handle_video_request(struct msm_dp_display_private *dp) { if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) { dp->panel->video_test = true; - dp_link_send_test_response(dp->link); + msm_dp_link_send_test_response(dp->link); } } -static int dp_display_handle_port_status_changed(struct dp_display_private *dp) +static int msm_dp_display_handle_port_status_changed(struct msm_dp_display_private *dp) { int rc = 0; @@ -482,12 +491,12 @@ static int dp_display_handle_port_status_changed(struct dp_display_private *dp) drm_dbg_dp(dp->drm_dev, "sink count is zero, nothing to do\n"); if (dp->hpd_state != ST_DISCONNECTED) { dp->hpd_state = ST_DISCONNECT_PENDING; - dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); + msm_dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); } } else { if (dp->hpd_state == ST_DISCONNECTED) { dp->hpd_state = ST_MAINLINK_READY; - rc = dp_display_process_hpd_high(dp); + rc = msm_dp_display_process_hpd_high(dp); if (rc) dp->hpd_state = ST_DISCONNECTED; } @@ -496,7 +505,7 @@ static int dp_display_handle_port_status_changed(struct dp_display_private *dp) return rc; } -static int dp_display_handle_irq_hpd(struct dp_display_private *dp) +static int msm_dp_display_handle_irq_hpd(struct msm_dp_display_private *dp) { u32 sink_request = dp->link->sink_request; @@ -510,48 +519,48 @@ static int dp_display_handle_irq_hpd(struct dp_display_private *dp) } } - dp_ctrl_handle_sink_request(dp->ctrl); + msm_dp_ctrl_handle_sink_request(dp->ctrl); if (sink_request & DP_TEST_LINK_VIDEO_PATTERN) - dp_display_handle_video_request(dp); + msm_dp_display_handle_video_request(dp); return 0; } -static int dp_display_usbpd_attention_cb(struct device *dev) +static int msm_dp_display_usbpd_attention_cb(struct device *dev) { int rc = 0; u32 sink_request; - struct dp_display_private *dp = dev_get_dp_display_private(dev); + struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); /* check for any test request issued by sink */ - rc = dp_link_process_request(dp->link); + rc = msm_dp_link_process_request(dp->link); if (!rc) { sink_request = dp->link->sink_request; drm_dbg_dp(dp->drm_dev, "hpd_state=%d sink_request=%d\n", dp->hpd_state, sink_request); if (sink_request & DS_PORT_STATUS_CHANGED) - rc = dp_display_handle_port_status_changed(dp); + rc = msm_dp_display_handle_port_status_changed(dp); else - rc = dp_display_handle_irq_hpd(dp); + rc = msm_dp_display_handle_irq_hpd(dp); } return rc; } -static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) +static int msm_dp_hpd_plug_handle(struct msm_dp_display_private *dp, u32 data) { u32 state; int ret; - struct platform_device *pdev = dp->dp_display.pdev; + struct platform_device *pdev = dp->msm_dp_display.pdev; - dp_aux_enable_xfers(dp->aux, true); + msm_dp_aux_enable_xfers(dp->aux, true); mutex_lock(&dp->event_mutex); state = dp->hpd_state; drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", - dp->dp_display.connector_type, state); + dp->msm_dp_display.connector_type, state); if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); @@ -565,7 +574,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) if (state == ST_DISCONNECT_PENDING) { /* wait until ST_DISCONNECTED */ - dp_add_event(dp, EV_HPD_PLUG_INT, 0, 1); /* delay = 1 */ + msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 1); /* delay = 1 */ mutex_unlock(&dp->event_mutex); return 0; } @@ -577,7 +586,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) return ret; } - ret = dp_display_usbpd_configure_cb(&pdev->dev); + ret = msm_dp_display_usbpd_configure_cb(&pdev->dev); if (ret) { /* link train failed */ dp->hpd_state = ST_DISCONNECTED; pm_runtime_put_sync(&pdev->dev); @@ -586,60 +595,60 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) } drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n", - dp->dp_display.connector_type, state); + dp->msm_dp_display.connector_type, state); mutex_unlock(&dp->event_mutex); /* uevent will complete connection part */ return 0; }; -static void dp_display_handle_plugged_change(struct msm_dp *dp_display, +static void msm_dp_display_handle_plugged_change(struct msm_dp *msm_dp_display, bool plugged) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; - dp = container_of(dp_display, - struct dp_display_private, dp_display); + dp = container_of(msm_dp_display, + struct msm_dp_display_private, msm_dp_display); /* notify audio subsystem only if sink supports audio */ - if (dp_display->plugged_cb && dp_display->codec_dev && + if (msm_dp_display->plugged_cb && msm_dp_display->codec_dev && dp->audio_supported) - dp_display->plugged_cb(dp_display->codec_dev, plugged); + msm_dp_display->plugged_cb(msm_dp_display->codec_dev, plugged); } -static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) +static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp, u32 data) { u32 state; - struct platform_device *pdev = dp->dp_display.pdev; + struct platform_device *pdev = dp->msm_dp_display.pdev; - dp_aux_enable_xfers(dp->aux, false); + msm_dp_aux_enable_xfers(dp->aux, false); mutex_lock(&dp->event_mutex); state = dp->hpd_state; drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", - dp->dp_display.connector_type, state); + dp->msm_dp_display.connector_type, state); /* unplugged, no more irq_hpd handle */ - dp_del_event(dp, EV_IRQ_HPD_INT); + msm_dp_del_event(dp, EV_IRQ_HPD_INT); if (state == ST_DISCONNECTED) { /* triggered by irq_hdp with sink_count = 0 */ if (dp->link->sink_count == 0) { - dp_display_host_phy_exit(dp); + msm_dp_display_host_phy_exit(dp); } - dp_display_notify_disconnect(&dp->dp_display.pdev->dev); + msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev); mutex_unlock(&dp->event_mutex); return 0; } else if (state == ST_DISCONNECT_PENDING) { mutex_unlock(&dp->event_mutex); return 0; } else if (state == ST_MAINLINK_READY) { - dp_ctrl_off_link(dp->ctrl); - dp_display_host_phy_exit(dp); + msm_dp_ctrl_off_link(dp->ctrl); + msm_dp_display_host_phy_exit(dp); dp->hpd_state = ST_DISCONNECTED; - dp_display_notify_disconnect(&dp->dp_display.pdev->dev); + msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev); pm_runtime_put_sync(&pdev->dev); mutex_unlock(&dp->event_mutex); return 0; @@ -649,7 +658,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) * We don't need separate work for disconnect as * connect/attention interrupts are disabled */ - dp_display_notify_disconnect(&dp->dp_display.pdev->dev); + msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev); if (state == ST_DISPLAY_OFF) { dp->hpd_state = ST_DISCONNECTED; @@ -658,10 +667,10 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) } /* signal the disconnect event early to ensure proper teardown */ - dp_display_handle_plugged_change(&dp->dp_display, false); + msm_dp_display_handle_plugged_change(&dp->msm_dp_display, false); drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n", - dp->dp_display.connector_type, state); + dp->msm_dp_display.connector_type, state); /* uevent will complete disconnection part */ pm_runtime_put_sync(&pdev->dev); @@ -669,7 +678,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) return 0; } -static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) +static int msm_dp_irq_hpd_handle(struct msm_dp_display_private *dp, u32 data) { u32 state; @@ -678,7 +687,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) /* irq_hpd can happen at either connected or disconnected state */ state = dp->hpd_state; drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", - dp->dp_display.connector_type, state); + dp->msm_dp_display.connector_type, state); if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); @@ -687,33 +696,33 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) if (state == ST_MAINLINK_READY || state == ST_DISCONNECT_PENDING) { /* wait until ST_CONNECTED */ - dp_add_event(dp, EV_IRQ_HPD_INT, 0, 1); /* delay = 1 */ + msm_dp_add_event(dp, EV_IRQ_HPD_INT, 0, 1); /* delay = 1 */ mutex_unlock(&dp->event_mutex); return 0; } - dp_display_usbpd_attention_cb(&dp->dp_display.pdev->dev); + msm_dp_display_usbpd_attention_cb(&dp->msm_dp_display.pdev->dev); drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n", - dp->dp_display.connector_type, state); + dp->msm_dp_display.connector_type, state); mutex_unlock(&dp->event_mutex); return 0; } -static void dp_display_deinit_sub_modules(struct dp_display_private *dp) +static void msm_dp_display_deinit_sub_modules(struct msm_dp_display_private *dp) { - dp_audio_put(dp->audio); - dp_panel_put(dp->panel); - dp_aux_put(dp->aux); + msm_dp_audio_put(dp->audio); + msm_dp_panel_put(dp->panel); + msm_dp_aux_put(dp->aux); } -static int dp_init_sub_modules(struct dp_display_private *dp) +static int msm_dp_init_sub_modules(struct msm_dp_display_private *dp) { int rc = 0; - struct device *dev = &dp->dp_display.pdev->dev; - struct dp_panel_in panel_in = { + struct device *dev = &dp->msm_dp_display.pdev->dev; + struct msm_dp_panel_in panel_in = { .dev = dev, }; struct phy *phy; @@ -723,14 +732,14 @@ static int dp_init_sub_modules(struct dp_display_private *dp) return PTR_ERR(phy); rc = phy_set_mode_ext(phy, PHY_MODE_DP, - dp->dp_display.is_edp ? PHY_SUBMODE_EDP : PHY_SUBMODE_DP); + dp->msm_dp_display.is_edp ? PHY_SUBMODE_EDP : PHY_SUBMODE_DP); if (rc) { DRM_ERROR("failed to set phy submode, rc = %d\n", rc); dp->catalog = NULL; goto error; } - dp->catalog = dp_catalog_get(dev); + dp->catalog = msm_dp_catalog_get(dev); if (IS_ERR(dp->catalog)) { rc = PTR_ERR(dp->catalog); DRM_ERROR("failed to initialize catalog, rc = %d\n", rc); @@ -738,9 +747,9 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error; } - dp->aux = dp_aux_get(dev, dp->catalog, + dp->aux = msm_dp_aux_get(dev, dp->catalog, phy, - dp->dp_display.is_edp); + dp->msm_dp_display.is_edp); if (IS_ERR(dp->aux)) { rc = PTR_ERR(dp->aux); DRM_ERROR("failed to initialize aux, rc = %d\n", rc); @@ -748,7 +757,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error; } - dp->link = dp_link_get(dev, dp->aux); + dp->link = msm_dp_link_get(dev, dp->aux); if (IS_ERR(dp->link)) { rc = PTR_ERR(dp->link); DRM_ERROR("failed to initialize link, rc = %d\n", rc); @@ -760,7 +769,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) panel_in.catalog = dp->catalog; panel_in.link = dp->link; - dp->panel = dp_panel_get(&panel_in); + dp->panel = msm_dp_panel_get(&panel_in); if (IS_ERR(dp->panel)) { rc = PTR_ERR(dp->panel); DRM_ERROR("failed to initialize panel, rc = %d\n", rc); @@ -768,7 +777,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_link; } - dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux, + dp->ctrl = msm_dp_ctrl_get(dev, dp->link, dp->panel, dp->aux, dp->catalog, phy); if (IS_ERR(dp->ctrl)) { @@ -778,7 +787,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_ctrl; } - dp->audio = dp_audio_get(dp->dp_display.pdev, dp->panel, dp->catalog); + dp->audio = msm_dp_audio_get(dp->msm_dp_display.pdev, dp->panel, dp->catalog); if (IS_ERR(dp->audio)) { rc = PTR_ERR(dp->audio); pr_err("failed to initialize audio, rc = %d\n", rc); @@ -789,51 +798,51 @@ static int dp_init_sub_modules(struct dp_display_private *dp) return rc; error_ctrl: - dp_panel_put(dp->panel); + msm_dp_panel_put(dp->panel); error_link: - dp_aux_put(dp->aux); + msm_dp_aux_put(dp->aux); error: return rc; } -static int dp_display_set_mode(struct msm_dp *dp_display, - struct dp_display_mode *mode) +static int msm_dp_display_set_mode(struct msm_dp *msm_dp_display, + struct msm_dp_display_mode *mode) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; - dp = container_of(dp_display, struct dp_display_private, dp_display); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - drm_mode_copy(&dp->panel->dp_mode.drm_mode, &mode->drm_mode); - dp->panel->dp_mode.bpp = mode->bpp; - dp->panel->dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420; - dp_panel_init_panel_info(dp->panel); + drm_mode_copy(&dp->panel->msm_dp_mode.drm_mode, &mode->drm_mode); + dp->panel->msm_dp_mode.bpp = mode->bpp; + dp->panel->msm_dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420; + msm_dp_panel_init_panel_info(dp->panel); return 0; } -static int dp_display_enable(struct dp_display_private *dp, bool force_link_train) +static int msm_dp_display_enable(struct msm_dp_display_private *dp, bool force_link_train) { int rc = 0; - struct msm_dp *dp_display = &dp->dp_display; + struct msm_dp *msm_dp_display = &dp->msm_dp_display; drm_dbg_dp(dp->drm_dev, "sink_count=%d\n", dp->link->sink_count); - if (dp_display->power_on) { + if (msm_dp_display->power_on) { drm_dbg_dp(dp->drm_dev, "Link already setup, return\n"); return 0; } - rc = dp_ctrl_on_stream(dp->ctrl, force_link_train); + rc = msm_dp_ctrl_on_stream(dp->ctrl, force_link_train); if (!rc) - dp_display->power_on = true; + msm_dp_display->power_on = true; return rc; } -static int dp_display_post_enable(struct msm_dp *dp_display) +static int msm_dp_display_post_enable(struct msm_dp *msm_dp_display) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; u32 rate; - dp = container_of(dp_display, struct dp_display_private, dp_display); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); rate = dp->link->link_params.rate; @@ -843,85 +852,85 @@ static int dp_display_post_enable(struct msm_dp *dp_display) } /* signal the connect event late to synchronize video and display */ - dp_display_handle_plugged_change(dp_display, true); + msm_dp_display_handle_plugged_change(msm_dp_display, true); - if (dp_display->psr_supported) - dp_ctrl_config_psr(dp->ctrl); + if (msm_dp_display->psr_supported) + msm_dp_ctrl_config_psr(dp->ctrl); return 0; } -static int dp_display_disable(struct dp_display_private *dp) +static int msm_dp_display_disable(struct msm_dp_display_private *dp) { - struct msm_dp *dp_display = &dp->dp_display; + struct msm_dp *msm_dp_display = &dp->msm_dp_display; - if (!dp_display->power_on) + if (!msm_dp_display->power_on) return 0; /* wait only if audio was enabled */ - if (dp_display->audio_enabled) { + if (msm_dp_display->audio_enabled) { /* signal the disconnect event */ - dp_display_handle_plugged_change(dp_display, false); + msm_dp_display_handle_plugged_change(msm_dp_display, false); if (!wait_for_completion_timeout(&dp->audio_comp, HZ * 5)) DRM_ERROR("audio comp timeout\n"); } - dp_display->audio_enabled = false; + msm_dp_display->audio_enabled = false; if (dp->link->sink_count == 0) { /* * irq_hpd with sink_count = 0 * hdmi unplugged out of dongle */ - dp_ctrl_off_link_stream(dp->ctrl); + msm_dp_ctrl_off_link_stream(dp->ctrl); } else { /* * unplugged interrupt * dongle unplugged out of DUT */ - dp_ctrl_off(dp->ctrl); - dp_display_host_phy_exit(dp); + msm_dp_ctrl_off(dp->ctrl); + msm_dp_display_host_phy_exit(dp); } - dp_display->power_on = false; + msm_dp_display->power_on = false; drm_dbg_dp(dp->drm_dev, "sink count: %d\n", dp->link->sink_count); return 0; } -int dp_display_set_plugged_cb(struct msm_dp *dp_display, +int msm_dp_display_set_plugged_cb(struct msm_dp *msm_dp_display, hdmi_codec_plugged_cb fn, struct device *codec_dev) { bool plugged; - dp_display->plugged_cb = fn; - dp_display->codec_dev = codec_dev; - plugged = dp_display->link_ready; - dp_display_handle_plugged_change(dp_display, plugged); + msm_dp_display->plugged_cb = fn; + msm_dp_display->codec_dev = codec_dev; + plugged = msm_dp_display->link_ready; + msm_dp_display_handle_plugged_change(msm_dp_display, plugged); return 0; } /** - * dp_bridge_mode_valid - callback to determine if specified mode is valid + * msm_dp_bridge_mode_valid - callback to determine if specified mode is valid * @bridge: Pointer to drm bridge structure * @info: display info * @mode: Pointer to drm mode structure * Returns: Validity status for specified mode */ -enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge, +enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *info, const struct drm_display_mode *mode) { const u32 num_components = 3, default_bpp = 24; - struct dp_display_private *dp_display; - struct dp_link_info *link_info; + struct msm_dp_display_private *msm_dp_display; + struct msm_dp_link_info *link_info; u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; struct msm_dp *dp; int mode_pclk_khz = mode->clock; - dp = to_dp_bridge(bridge)->dp_display; + dp = to_dp_bridge(bridge)->msm_dp_display; if (!dp || !mode_pclk_khz || !dp->connector) { DRM_ERROR("invalid params\n"); @@ -931,18 +940,18 @@ enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge, if (mode->clock > DP_MAX_PIXEL_CLK_KHZ) return MODE_CLOCK_HIGH; - dp_display = container_of(dp, struct dp_display_private, dp_display); - link_info = &dp_display->panel->link_info; + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); + link_info = &msm_dp_display->panel->link_info; if (drm_mode_is_420_only(&dp->connector->display_info, mode) && - dp_display->panel->vsc_sdp_supported) + msm_dp_display->panel->vsc_sdp_supported) mode_pclk_khz /= 2; mode_bpp = dp->connector->display_info.bpc * num_components; if (!mode_bpp) mode_bpp = default_bpp; - mode_bpp = dp_panel_get_mode_bpp(dp_display->panel, + mode_bpp = msm_dp_panel_get_mode_bpp(msm_dp_display->panel, mode_bpp, mode_pclk_khz); mode_rate_khz = mode_pclk_khz * mode_bpp; @@ -954,50 +963,50 @@ enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -int dp_display_get_modes(struct msm_dp *dp) +int msm_dp_display_get_modes(struct msm_dp *dp) { - struct dp_display_private *dp_display; + struct msm_dp_display_private *msm_dp_display; if (!dp) { DRM_ERROR("invalid params\n"); return 0; } - dp_display = container_of(dp, struct dp_display_private, dp_display); + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); - return dp_panel_get_modes(dp_display->panel, + return msm_dp_panel_get_modes(msm_dp_display->panel, dp->connector); } -bool dp_display_check_video_test(struct msm_dp *dp) +bool msm_dp_display_check_video_test(struct msm_dp *dp) { - struct dp_display_private *dp_display; + struct msm_dp_display_private *msm_dp_display; - dp_display = container_of(dp, struct dp_display_private, dp_display); + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); - return dp_display->panel->video_test; + return msm_dp_display->panel->video_test; } -int dp_display_get_test_bpp(struct msm_dp *dp) +int msm_dp_display_get_test_bpp(struct msm_dp *dp) { - struct dp_display_private *dp_display; + struct msm_dp_display_private *msm_dp_display; if (!dp) { DRM_ERROR("invalid params\n"); return 0; } - dp_display = container_of(dp, struct dp_display_private, dp_display); + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); - return dp_link_bit_depth_to_bpp( - dp_display->link->test_video.test_bit_depth); + return msm_dp_link_bit_depth_to_bpp( + msm_dp_display->link->test_video.test_bit_depth); } void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) { - struct dp_display_private *dp_display; + struct msm_dp_display_private *msm_dp_display; - dp_display = container_of(dp, struct dp_display_private, dp_display); + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); /* * if we are reading registers we need the link clocks to be on @@ -1006,65 +1015,65 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp) * power_on status before dumping DP registers to avoid crash due * to unclocked access */ - mutex_lock(&dp_display->event_mutex); + mutex_lock(&msm_dp_display->event_mutex); if (!dp->power_on) { - mutex_unlock(&dp_display->event_mutex); + mutex_unlock(&msm_dp_display->event_mutex); return; } - dp_catalog_snapshot(dp_display->catalog, disp_state); + msm_dp_catalog_snapshot(msm_dp_display->catalog, disp_state); - mutex_unlock(&dp_display->event_mutex); + mutex_unlock(&msm_dp_display->event_mutex); } -void dp_display_set_psr(struct msm_dp *dp_display, bool enter) +void msm_dp_display_set_psr(struct msm_dp *msm_dp_display, bool enter) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; - if (!dp_display) { + if (!msm_dp_display) { DRM_ERROR("invalid params\n"); return; } - dp = container_of(dp_display, struct dp_display_private, dp_display); - dp_ctrl_set_psr(dp->ctrl, enter); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + msm_dp_ctrl_set_psr(dp->ctrl, enter); } static int hpd_event_thread(void *data) { - struct dp_display_private *dp_priv; + struct msm_dp_display_private *msm_dp_priv; unsigned long flag; - struct dp_event *todo; + struct msm_dp_event *todo; int timeout_mode = 0; - dp_priv = (struct dp_display_private *)data; + msm_dp_priv = (struct msm_dp_display_private *)data; while (1) { if (timeout_mode) { - wait_event_timeout(dp_priv->event_q, - (dp_priv->event_pndx == dp_priv->event_gndx) || + wait_event_timeout(msm_dp_priv->event_q, + (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) || kthread_should_stop(), EVENT_TIMEOUT); } else { - wait_event_interruptible(dp_priv->event_q, - (dp_priv->event_pndx != dp_priv->event_gndx) || + wait_event_interruptible(msm_dp_priv->event_q, + (msm_dp_priv->event_pndx != msm_dp_priv->event_gndx) || kthread_should_stop()); } if (kthread_should_stop()) break; - spin_lock_irqsave(&dp_priv->event_lock, flag); - todo = &dp_priv->event_list[dp_priv->event_gndx]; + spin_lock_irqsave(&msm_dp_priv->event_lock, flag); + todo = &msm_dp_priv->event_list[msm_dp_priv->event_gndx]; if (todo->delay) { - struct dp_event *todo_next; + struct msm_dp_event *todo_next; - dp_priv->event_gndx++; - dp_priv->event_gndx %= DP_EVENT_Q_MAX; + msm_dp_priv->event_gndx++; + msm_dp_priv->event_gndx %= DP_EVENT_Q_MAX; /* re enter delay event into q */ - todo_next = &dp_priv->event_list[dp_priv->event_pndx++]; - dp_priv->event_pndx %= DP_EVENT_Q_MAX; + todo_next = &msm_dp_priv->event_list[msm_dp_priv->event_pndx++]; + msm_dp_priv->event_pndx %= DP_EVENT_Q_MAX; todo_next->event_id = todo->event_id; todo_next->data = todo->data; todo_next->delay = todo->delay - 1; @@ -1075,33 +1084,33 @@ static int hpd_event_thread(void *data) /* switch to timeout mode */ timeout_mode = 1; - spin_unlock_irqrestore(&dp_priv->event_lock, flag); + spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); continue; } /* timeout with no events in q */ - if (dp_priv->event_pndx == dp_priv->event_gndx) { - spin_unlock_irqrestore(&dp_priv->event_lock, flag); + if (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) { + spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); continue; } - dp_priv->event_gndx++; - dp_priv->event_gndx %= DP_EVENT_Q_MAX; + msm_dp_priv->event_gndx++; + msm_dp_priv->event_gndx %= DP_EVENT_Q_MAX; timeout_mode = 0; - spin_unlock_irqrestore(&dp_priv->event_lock, flag); + spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag); switch (todo->event_id) { case EV_HPD_PLUG_INT: - dp_hpd_plug_handle(dp_priv, todo->data); + msm_dp_hpd_plug_handle(msm_dp_priv, todo->data); break; case EV_HPD_UNPLUG_INT: - dp_hpd_unplug_handle(dp_priv, todo->data); + msm_dp_hpd_unplug_handle(msm_dp_priv, todo->data); break; case EV_IRQ_HPD_INT: - dp_irq_hpd_handle(dp_priv, todo->data); + msm_dp_irq_hpd_handle(msm_dp_priv, todo->data); break; case EV_USER_NOTIFICATION: - dp_display_send_hpd_notification(dp_priv, + msm_dp_display_send_hpd_notification(msm_dp_priv, todo->data); break; default: @@ -1112,22 +1121,22 @@ static int hpd_event_thread(void *data) return 0; } -static int dp_hpd_event_thread_start(struct dp_display_private *dp_priv) +static int msm_dp_hpd_event_thread_start(struct msm_dp_display_private *msm_dp_priv) { /* set event q to empty */ - dp_priv->event_gndx = 0; - dp_priv->event_pndx = 0; + msm_dp_priv->event_gndx = 0; + msm_dp_priv->event_pndx = 0; - dp_priv->ev_tsk = kthread_run(hpd_event_thread, dp_priv, "dp_hpd_handler"); - if (IS_ERR(dp_priv->ev_tsk)) - return PTR_ERR(dp_priv->ev_tsk); + msm_dp_priv->ev_tsk = kthread_run(hpd_event_thread, msm_dp_priv, "dp_hpd_handler"); + if (IS_ERR(msm_dp_priv->ev_tsk)) + return PTR_ERR(msm_dp_priv->ev_tsk); return 0; } -static irqreturn_t dp_display_irq_handler(int irq, void *dev_id) +static irqreturn_t msm_dp_display_irq_handler(int irq, void *dev_id) { - struct dp_display_private *dp = dev_id; + struct msm_dp_display_private *dp = dev_id; irqreturn_t ret = IRQ_NONE; u32 hpd_isr_status; @@ -1136,43 +1145,43 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id) return IRQ_NONE; } - hpd_isr_status = dp_catalog_hpd_get_intr_status(dp->catalog); + hpd_isr_status = msm_dp_catalog_hpd_get_intr_status(dp->catalog); if (hpd_isr_status & 0x0F) { drm_dbg_dp(dp->drm_dev, "type=%d isr=0x%x\n", - dp->dp_display.connector_type, hpd_isr_status); + dp->msm_dp_display.connector_type, hpd_isr_status); /* hpd related interrupts */ if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK) - dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); + msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) { - dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0); + msm_dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0); } if (hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) { - dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); - dp_add_event(dp, EV_HPD_PLUG_INT, 0, 3); + msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); + msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 3); } if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK) - dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); + msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); ret = IRQ_HANDLED; } /* DP controller isr */ - ret |= dp_ctrl_isr(dp->ctrl); + ret |= msm_dp_ctrl_isr(dp->ctrl); /* DP aux isr */ - ret |= dp_aux_isr(dp->aux); + ret |= msm_dp_aux_isr(dp->aux); return ret; } -static int dp_display_request_irq(struct dp_display_private *dp) +static int msm_dp_display_request_irq(struct msm_dp_display_private *dp) { int rc = 0; - struct platform_device *pdev = dp->dp_display.pdev; + struct platform_device *pdev = dp->msm_dp_display.pdev; dp->irq = platform_get_irq(pdev, 0); if (dp->irq < 0) { @@ -1180,7 +1189,7 @@ static int dp_display_request_irq(struct dp_display_private *dp) return dp->irq; } - rc = devm_request_irq(&pdev->dev, dp->irq, dp_display_irq_handler, + rc = devm_request_irq(&pdev->dev, dp->irq, msm_dp_display_irq_handler, IRQF_TRIGGER_HIGH|IRQF_NO_AUTOEN, "dp_display_isr", dp); @@ -1193,7 +1202,7 @@ static int dp_display_request_irq(struct dp_display_private *dp) return 0; } -static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev) +static const struct msm_dp_desc *msm_dp_display_get_desc(struct platform_device *pdev) { const struct msm_dp_desc *descs = of_device_get_match_data(&pdev->dev); struct resource *res; @@ -1212,7 +1221,7 @@ static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pde return NULL; } -static int dp_display_probe_tail(struct device *dev) +static int msm_dp_display_probe_tail(struct device *dev) { struct msm_dp *dp = dev_get_drvdata(dev); int ret; @@ -1232,19 +1241,19 @@ static int dp_display_probe_tail(struct device *dev) return ret; } - ret = component_add(dev, &dp_display_comp_ops); + ret = component_add(dev, &msm_dp_display_comp_ops); if (ret) DRM_ERROR("component add failed, rc=%d\n", ret); return ret; } -static int dp_auxbus_done_probe(struct drm_dp_aux *aux) +static int msm_dp_auxbus_done_probe(struct drm_dp_aux *aux) { - return dp_display_probe_tail(aux->dev); + return msm_dp_display_probe_tail(aux->dev); } -static int dp_display_get_connector_type(struct platform_device *pdev, +static int msm_dp_display_get_connector_type(struct platform_device *pdev, const struct msm_dp_desc *desc) { struct device_node *node = pdev->dev.of_node; @@ -1263,10 +1272,10 @@ static int dp_display_get_connector_type(struct platform_device *pdev, return connector_type; } -static int dp_display_probe(struct platform_device *pdev) +static int msm_dp_display_probe(struct platform_device *pdev) { int rc = 0; - struct dp_display_private *dp; + struct msm_dp_display_private *dp; const struct msm_dp_desc *desc; if (!pdev || !pdev->dev.of_node) { @@ -1278,18 +1287,18 @@ static int dp_display_probe(struct platform_device *pdev) if (!dp) return -ENOMEM; - desc = dp_display_get_desc(pdev); + desc = msm_dp_display_get_desc(pdev); if (!desc) return -EINVAL; - dp->dp_display.pdev = pdev; + dp->msm_dp_display.pdev = pdev; dp->id = desc->id; - dp->dp_display.connector_type = dp_display_get_connector_type(pdev, desc); + dp->msm_dp_display.connector_type = msm_dp_display_get_connector_type(pdev, desc); dp->wide_bus_supported = desc->wide_bus_supported; - dp->dp_display.is_edp = - (dp->dp_display.connector_type == DRM_MODE_CONNECTOR_eDP); + dp->msm_dp_display.is_edp = + (dp->msm_dp_display.connector_type == DRM_MODE_CONNECTOR_eDP); - rc = dp_init_sub_modules(dp); + rc = msm_dp_init_sub_modules(dp); if (rc) { DRM_ERROR("init sub module failed\n"); return -EPROBE_DEFER; @@ -1301,28 +1310,28 @@ static int dp_display_probe(struct platform_device *pdev) spin_lock_init(&dp->event_lock); /* Store DP audio handle inside DP display */ - dp->dp_display.dp_audio = dp->audio; + dp->msm_dp_display.msm_dp_audio = dp->audio; init_completion(&dp->audio_comp); - platform_set_drvdata(pdev, &dp->dp_display); + platform_set_drvdata(pdev, &dp->msm_dp_display); rc = devm_pm_runtime_enable(&pdev->dev); if (rc) goto err; - rc = dp_display_request_irq(dp); + rc = msm_dp_display_request_irq(dp); if (rc) goto err; - if (dp->dp_display.is_edp) { - rc = devm_of_dp_aux_populate_bus(dp->aux, dp_auxbus_done_probe); + if (dp->msm_dp_display.is_edp) { + rc = devm_of_dp_aux_populate_bus(dp->aux, msm_dp_auxbus_done_probe); if (rc) { DRM_ERROR("eDP auxbus population failed, rc=%d\n", rc); goto err; } } else { - rc = dp_display_probe_tail(&pdev->dev); + rc = msm_dp_display_probe_tail(&pdev->dev); if (rc) goto err; } @@ -1330,70 +1339,70 @@ static int dp_display_probe(struct platform_device *pdev) return rc; err: - dp_display_deinit_sub_modules(dp); + msm_dp_display_deinit_sub_modules(dp); return rc; } -static void dp_display_remove(struct platform_device *pdev) +static void msm_dp_display_remove(struct platform_device *pdev) { - struct dp_display_private *dp = dev_get_dp_display_private(&pdev->dev); + struct msm_dp_display_private *dp = dev_get_dp_display_private(&pdev->dev); - component_del(&pdev->dev, &dp_display_comp_ops); - dp_display_deinit_sub_modules(dp); + component_del(&pdev->dev, &msm_dp_display_comp_ops); + msm_dp_display_deinit_sub_modules(dp); platform_set_drvdata(pdev, NULL); } -static int dp_pm_runtime_suspend(struct device *dev) +static int msm_dp_pm_runtime_suspend(struct device *dev) { - struct dp_display_private *dp = dev_get_dp_display_private(dev); + struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); disable_irq(dp->irq); - if (dp->dp_display.is_edp) { - dp_display_host_phy_exit(dp); - dp_catalog_ctrl_hpd_disable(dp->catalog); + if (dp->msm_dp_display.is_edp) { + msm_dp_display_host_phy_exit(dp); + msm_dp_catalog_ctrl_hpd_disable(dp->catalog); } - dp_display_host_deinit(dp); + msm_dp_display_host_deinit(dp); return 0; } -static int dp_pm_runtime_resume(struct device *dev) +static int msm_dp_pm_runtime_resume(struct device *dev) { - struct dp_display_private *dp = dev_get_dp_display_private(dev); + struct msm_dp_display_private *dp = dev_get_dp_display_private(dev); /* * for eDP, host cotroller, HPD block and PHY are enabled here * but with HPD irq disabled * * for DP, only host controller is enabled here. - * HPD block is enabled at dp_bridge_hpd_enable() + * HPD block is enabled at msm_dp_bridge_hpd_enable() * PHY will be enabled at plugin handler later */ - dp_display_host_init(dp); - if (dp->dp_display.is_edp) { - dp_catalog_ctrl_hpd_enable(dp->catalog); - dp_display_host_phy_init(dp); + msm_dp_display_host_init(dp); + if (dp->msm_dp_display.is_edp) { + msm_dp_catalog_ctrl_hpd_enable(dp->catalog); + msm_dp_display_host_phy_init(dp); } enable_irq(dp->irq); return 0; } -static const struct dev_pm_ops dp_pm_ops = { - SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) +static const struct dev_pm_ops msm_dp_pm_ops = { + SET_RUNTIME_PM_OPS(msm_dp_pm_runtime_suspend, msm_dp_pm_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; -static struct platform_driver dp_display_driver = { - .probe = dp_display_probe, - .remove_new = dp_display_remove, +static struct platform_driver msm_dp_display_driver = { + .probe = msm_dp_display_probe, + .remove = msm_dp_display_remove, .driver = { .name = "msm-dp-display", - .of_match_table = dp_dt_match, + .of_match_table = msm_dp_dt_match, .suppress_bind_attrs = true, - .pm = &dp_pm_ops, + .pm = &msm_dp_pm_ops, }, }; @@ -1401,7 +1410,7 @@ int __init msm_dp_register(void) { int ret; - ret = platform_driver_register(&dp_display_driver); + ret = platform_driver_register(&msm_dp_display_driver); if (ret) DRM_ERROR("Dp display driver register failed"); @@ -1410,294 +1419,294 @@ int __init msm_dp_register(void) void __exit msm_dp_unregister(void) { - platform_driver_unregister(&dp_display_driver); + platform_driver_unregister(&msm_dp_display_driver); } -bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display, +bool msm_dp_is_yuv_420_enabled(const struct msm_dp *msm_dp_display, const struct drm_display_mode *mode) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; const struct drm_display_info *info; - dp = container_of(dp_display, struct dp_display_private, dp_display); - info = &dp_display->connector->display_info; + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + info = &msm_dp_display->connector->display_info; return dp->panel->vsc_sdp_supported && drm_mode_is_420_only(info, mode); } -bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display, +bool msm_dp_needs_periph_flush(const struct msm_dp *msm_dp_display, const struct drm_display_mode *mode) { - return msm_dp_is_yuv_420_enabled(dp_display, mode); + return msm_dp_is_yuv_420_enabled(msm_dp_display, mode); } -bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) +bool msm_dp_wide_bus_available(const struct msm_dp *msm_dp_display) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; - dp = container_of(dp_display, struct dp_display_private, dp_display); + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - if (dp->dp_mode.out_fmt_is_yuv_420) + if (dp->msm_dp_mode.out_fmt_is_yuv_420) return false; return dp->wide_bus_supported; } -void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *root, bool is_edp) +void msm_dp_display_debugfs_init(struct msm_dp *msm_dp_display, struct dentry *root, bool is_edp) { - struct dp_display_private *dp; + struct msm_dp_display_private *dp; struct device *dev; int rc; - dp = container_of(dp_display, struct dp_display_private, dp_display); - dev = &dp->dp_display.pdev->dev; + dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); + dev = &dp->msm_dp_display.pdev->dev; - rc = dp_debug_init(dev, dp->panel, dp->link, dp->dp_display.connector, root, is_edp); + rc = msm_dp_debug_init(dev, dp->panel, dp->link, dp->msm_dp_display.connector, root, is_edp); if (rc) DRM_ERROR("failed to initialize debug, rc = %d\n", rc); } -int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, +int msm_dp_modeset_init(struct msm_dp *msm_dp_display, struct drm_device *dev, struct drm_encoder *encoder, bool yuv_supported) { - struct dp_display_private *dp_priv; + struct msm_dp_display_private *msm_dp_priv; int ret; - dp_display->drm_dev = dev; + msm_dp_display->drm_dev = dev; - dp_priv = container_of(dp_display, struct dp_display_private, dp_display); + msm_dp_priv = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - ret = dp_bridge_init(dp_display, dev, encoder); + ret = msm_dp_bridge_init(msm_dp_display, dev, encoder, yuv_supported); if (ret) { DRM_DEV_ERROR(dev->dev, "failed to create dp bridge: %d\n", ret); return ret; } - dp_display->connector = dp_drm_connector_init(dp_display, encoder, yuv_supported); - if (IS_ERR(dp_display->connector)) { - ret = PTR_ERR(dp_display->connector); + msm_dp_display->connector = msm_dp_drm_connector_init(msm_dp_display, encoder); + if (IS_ERR(msm_dp_display->connector)) { + ret = PTR_ERR(msm_dp_display->connector); DRM_DEV_ERROR(dev->dev, "failed to create dp connector: %d\n", ret); - dp_display->connector = NULL; + msm_dp_display->connector = NULL; return ret; } - dp_priv->panel->connector = dp_display->connector; + msm_dp_priv->panel->connector = msm_dp_display->connector; return 0; } -void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, +void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state) { - struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = dp_bridge->dp_display; + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = msm_dp_bridge->msm_dp_display; int rc = 0; - struct dp_display_private *dp_display; + struct msm_dp_display_private *msm_dp_display; u32 state; bool force_link_train = false; - dp_display = container_of(dp, struct dp_display_private, dp_display); - if (!dp_display->dp_mode.drm_mode.clock) { + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); + if (!msm_dp_display->msm_dp_mode.drm_mode.clock) { DRM_ERROR("invalid params\n"); return; } if (dp->is_edp) - dp_hpd_plug_handle(dp_display, 0); + msm_dp_hpd_plug_handle(msm_dp_display, 0); - mutex_lock(&dp_display->event_mutex); + mutex_lock(&msm_dp_display->event_mutex); if (pm_runtime_resume_and_get(&dp->pdev->dev)) { DRM_ERROR("failed to pm_runtime_resume\n"); - mutex_unlock(&dp_display->event_mutex); + mutex_unlock(&msm_dp_display->event_mutex); return; } - state = dp_display->hpd_state; + state = msm_dp_display->hpd_state; if (state != ST_DISPLAY_OFF && state != ST_MAINLINK_READY) { - mutex_unlock(&dp_display->event_mutex); + mutex_unlock(&msm_dp_display->event_mutex); return; } - rc = dp_display_set_mode(dp, &dp_display->dp_mode); + rc = msm_dp_display_set_mode(dp, &msm_dp_display->msm_dp_mode); if (rc) { DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc); - mutex_unlock(&dp_display->event_mutex); + mutex_unlock(&msm_dp_display->event_mutex); return; } - state = dp_display->hpd_state; + state = msm_dp_display->hpd_state; if (state == ST_DISPLAY_OFF) { - dp_display_host_phy_init(dp_display); + msm_dp_display_host_phy_init(msm_dp_display); force_link_train = true; } - dp_display_enable(dp_display, force_link_train); + msm_dp_display_enable(msm_dp_display, force_link_train); - rc = dp_display_post_enable(dp); + rc = msm_dp_display_post_enable(dp); if (rc) { DRM_ERROR("DP display post enable failed, rc=%d\n", rc); - dp_display_disable(dp_display); + msm_dp_display_disable(msm_dp_display); } /* completed connection */ - dp_display->hpd_state = ST_CONNECTED; + msm_dp_display->hpd_state = ST_CONNECTED; drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type); - mutex_unlock(&dp_display->event_mutex); + mutex_unlock(&msm_dp_display->event_mutex); } -void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge, +void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state) { - struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = dp_bridge->dp_display; - struct dp_display_private *dp_display; + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = msm_dp_bridge->msm_dp_display; + struct msm_dp_display_private *msm_dp_display; - dp_display = container_of(dp, struct dp_display_private, dp_display); + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); - dp_ctrl_push_idle(dp_display->ctrl); + msm_dp_ctrl_push_idle(msm_dp_display->ctrl); } -void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, +void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state) { - struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = dp_bridge->dp_display; + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = msm_dp_bridge->msm_dp_display; u32 state; - struct dp_display_private *dp_display; + struct msm_dp_display_private *msm_dp_display; - dp_display = container_of(dp, struct dp_display_private, dp_display); + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); if (dp->is_edp) - dp_hpd_unplug_handle(dp_display, 0); + msm_dp_hpd_unplug_handle(msm_dp_display, 0); - mutex_lock(&dp_display->event_mutex); + mutex_lock(&msm_dp_display->event_mutex); - state = dp_display->hpd_state; + state = msm_dp_display->hpd_state; if (state != ST_DISCONNECT_PENDING && state != ST_CONNECTED) drm_dbg_dp(dp->drm_dev, "type=%d wrong hpd_state=%d\n", dp->connector_type, state); - dp_display_disable(dp_display); + msm_dp_display_disable(msm_dp_display); - state = dp_display->hpd_state; + state = msm_dp_display->hpd_state; if (state == ST_DISCONNECT_PENDING) { /* completed disconnection */ - dp_display->hpd_state = ST_DISCONNECTED; + msm_dp_display->hpd_state = ST_DISCONNECTED; } else { - dp_display->hpd_state = ST_DISPLAY_OFF; + msm_dp_display->hpd_state = ST_DISPLAY_OFF; } drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type); pm_runtime_put_sync(&dp->pdev->dev); - mutex_unlock(&dp_display->event_mutex); + mutex_unlock(&msm_dp_display->event_mutex); } -void dp_bridge_mode_set(struct drm_bridge *drm_bridge, +void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode) { - struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = dp_bridge->dp_display; - struct dp_display_private *dp_display; - struct dp_panel *dp_panel; + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = msm_dp_bridge->msm_dp_display; + struct msm_dp_display_private *msm_dp_display; + struct msm_dp_panel *msm_dp_panel; - dp_display = container_of(dp, struct dp_display_private, dp_display); - dp_panel = dp_display->panel; + msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); + msm_dp_panel = msm_dp_display->panel; - memset(&dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode)); + memset(&msm_dp_display->msm_dp_mode, 0x0, sizeof(struct msm_dp_display_mode)); - if (dp_display_check_video_test(dp)) - dp_display->dp_mode.bpp = dp_display_get_test_bpp(dp); + if (msm_dp_display_check_video_test(dp)) + msm_dp_display->msm_dp_mode.bpp = msm_dp_display_get_test_bpp(dp); else /* Default num_components per pixel = 3 */ - dp_display->dp_mode.bpp = dp->connector->display_info.bpc * 3; + msm_dp_display->msm_dp_mode.bpp = dp->connector->display_info.bpc * 3; - if (!dp_display->dp_mode.bpp) - dp_display->dp_mode.bpp = 24; /* Default bpp */ + if (!msm_dp_display->msm_dp_mode.bpp) + msm_dp_display->msm_dp_mode.bpp = 24; /* Default bpp */ - drm_mode_copy(&dp_display->dp_mode.drm_mode, adjusted_mode); + drm_mode_copy(&msm_dp_display->msm_dp_mode.drm_mode, adjusted_mode); - dp_display->dp_mode.v_active_low = - !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC); + msm_dp_display->msm_dp_mode.v_active_low = + !!(msm_dp_display->msm_dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC); - dp_display->dp_mode.h_active_low = - !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC); + msm_dp_display->msm_dp_mode.h_active_low = + !!(msm_dp_display->msm_dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC); - dp_display->dp_mode.out_fmt_is_yuv_420 = + msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 = drm_mode_is_420_only(&dp->connector->display_info, adjusted_mode) && - dp_panel->vsc_sdp_supported; + msm_dp_panel->vsc_sdp_supported; /* populate wide_bus_support to different layers */ - dp_display->ctrl->wide_bus_en = - dp_display->dp_mode.out_fmt_is_yuv_420 ? false : dp_display->wide_bus_supported; - dp_display->catalog->wide_bus_en = - dp_display->dp_mode.out_fmt_is_yuv_420 ? false : dp_display->wide_bus_supported; + msm_dp_display->ctrl->wide_bus_en = + msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 ? false : msm_dp_display->wide_bus_supported; + msm_dp_display->catalog->wide_bus_en = + msm_dp_display->msm_dp_mode.out_fmt_is_yuv_420 ? false : msm_dp_display->wide_bus_supported; } -void dp_bridge_hpd_enable(struct drm_bridge *bridge) +void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge) { - struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge); - struct msm_dp *dp_display = dp_bridge->dp_display; - struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display); + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge); + struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display; + struct msm_dp_display_private *dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); /* * this is for external DP with hpd irq enabled case, - * step-1: dp_pm_runtime_resume() enable dp host only + * step-1: msm_dp_pm_runtime_resume() enable dp host only * step-2: enable hdp block and have hpd irq enabled here * step-3: waiting for plugin irq while phy is not initialized * step-4: DP PHY is initialized at plugin handler before link training * */ mutex_lock(&dp->event_mutex); - if (pm_runtime_resume_and_get(&dp_display->pdev->dev)) { + if (pm_runtime_resume_and_get(&msm_dp_display->pdev->dev)) { DRM_ERROR("failed to resume power\n"); mutex_unlock(&dp->event_mutex); return; } - dp_catalog_ctrl_hpd_enable(dp->catalog); + msm_dp_catalog_ctrl_hpd_enable(dp->catalog); /* enable HDP interrupts */ - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, true); + msm_dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, true); - dp_display->internal_hpd = true; + msm_dp_display->internal_hpd = true; mutex_unlock(&dp->event_mutex); } -void dp_bridge_hpd_disable(struct drm_bridge *bridge) +void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge) { - struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge); - struct msm_dp *dp_display = dp_bridge->dp_display; - struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display); + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge); + struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display; + struct msm_dp_display_private *dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); mutex_lock(&dp->event_mutex); /* disable HDP interrupts */ - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false); - dp_catalog_ctrl_hpd_disable(dp->catalog); + msm_dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false); + msm_dp_catalog_ctrl_hpd_disable(dp->catalog); - dp_display->internal_hpd = false; + msm_dp_display->internal_hpd = false; - pm_runtime_put_sync(&dp_display->pdev->dev); + pm_runtime_put_sync(&msm_dp_display->pdev->dev); mutex_unlock(&dp->event_mutex); } -void dp_bridge_hpd_notify(struct drm_bridge *bridge, +void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge, enum drm_connector_status status) { - struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge); - struct msm_dp *dp_display = dp_bridge->dp_display; - struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display); + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge); + struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display; + struct msm_dp_display_private *dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); /* Without next_bridge interrupts are handled by the DP core directly */ - if (dp_display->internal_hpd) + if (msm_dp_display->internal_hpd) return; - if (!dp_display->link_ready && status == connector_status_connected) - dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); - else if (dp_display->link_ready && status == connector_status_disconnected) - dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); + if (!msm_dp_display->link_ready && status == connector_status_connected) + msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); + else if (msm_dp_display->link_ready && status == connector_status_disconnected) + msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); } diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index ec7fa67e0569ee..ecbc2d92f546a3 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -27,18 +27,18 @@ struct msm_dp { hdmi_codec_plugged_cb plugged_cb; - struct dp_audio *dp_audio; + struct msm_dp_audio *msm_dp_audio; bool psr_supported; }; -int dp_display_set_plugged_cb(struct msm_dp *dp_display, +int msm_dp_display_set_plugged_cb(struct msm_dp *msm_dp_display, hdmi_codec_plugged_cb fn, struct device *codec_dev); -int dp_display_get_modes(struct msm_dp *dp_display); -bool dp_display_check_video_test(struct msm_dp *dp_display); -int dp_display_get_test_bpp(struct msm_dp *dp_display); -void dp_display_signal_audio_start(struct msm_dp *dp_display); -void dp_display_signal_audio_complete(struct msm_dp *dp_display); -void dp_display_set_psr(struct msm_dp *dp, bool enter); -void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *dentry, bool is_edp); +int msm_dp_display_get_modes(struct msm_dp *msm_dp_display); +bool msm_dp_display_check_video_test(struct msm_dp *msm_dp_display); +int msm_dp_display_get_test_bpp(struct msm_dp *msm_dp_display); +void msm_dp_display_signal_audio_start(struct msm_dp *msm_dp_display); +void msm_dp_display_signal_audio_complete(struct msm_dp *msm_dp_display); +void msm_dp_display_set_psr(struct msm_dp *dp, bool enter); +void msm_dp_display_debugfs_init(struct msm_dp *msm_dp_display, struct dentry *dentry, bool is_edp); #endif /* _DP_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 1b9be5bd97f12d..d3e241ea694161 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -14,15 +14,15 @@ #include "dp_drm.h" /** - * dp_bridge_detect - callback to determine if connector is connected + * msm_dp_bridge_detect - callback to determine if connector is connected * @bridge: Pointer to drm bridge structure * Returns: Bridge's 'is connected' status */ -static enum drm_connector_status dp_bridge_detect(struct drm_bridge *bridge) +static enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge) { struct msm_dp *dp; - dp = to_dp_bridge(bridge)->dp_display; + dp = to_dp_bridge(bridge)->msm_dp_display; drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", (dp->link_ready) ? "true" : "false"); @@ -31,14 +31,14 @@ static enum drm_connector_status dp_bridge_detect(struct drm_bridge *bridge) connector_status_disconnected; } -static int dp_bridge_atomic_check(struct drm_bridge *bridge, +static int msm_dp_bridge_atomic_check(struct drm_bridge *bridge, struct drm_bridge_state *bridge_state, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { struct msm_dp *dp; - dp = to_dp_bridge(bridge)->dp_display; + dp = to_dp_bridge(bridge)->msm_dp_display; drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", (dp->link_ready) ? "true" : "false"); @@ -62,12 +62,12 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge, /** - * dp_bridge_get_modes - callback to add drm modes via drm_mode_probed_add() + * msm_dp_bridge_get_modes - callback to add drm modes via drm_mode_probed_add() * @bridge: Poiner to drm bridge * @connector: Pointer to drm connector structure * Returns: Number of modes added */ -static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector) +static int msm_dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector) { int rc = 0; struct msm_dp *dp; @@ -75,11 +75,11 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector * if (!connector) return 0; - dp = to_dp_bridge(bridge)->dp_display; + dp = to_dp_bridge(bridge)->msm_dp_display; /* pluggable case assumes EDID is read when HPD */ if (dp->link_ready) { - rc = dp_display_get_modes(dp); + rc = msm_dp_display_get_modes(dp); if (rc <= 0) { DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc); return rc; @@ -90,37 +90,37 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector * return rc; } -static void dp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry *root) +static void msm_dp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry *root) { - struct msm_dp *dp = to_dp_bridge(bridge)->dp_display; + struct msm_dp *dp = to_dp_bridge(bridge)->msm_dp_display; - dp_display_debugfs_init(dp, root, false); + msm_dp_display_debugfs_init(dp, root, false); } -static const struct drm_bridge_funcs dp_bridge_ops = { +static const struct drm_bridge_funcs msm_dp_bridge_ops = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_reset = drm_atomic_helper_bridge_reset, - .atomic_enable = dp_bridge_atomic_enable, - .atomic_disable = dp_bridge_atomic_disable, - .atomic_post_disable = dp_bridge_atomic_post_disable, - .mode_set = dp_bridge_mode_set, - .mode_valid = dp_bridge_mode_valid, - .get_modes = dp_bridge_get_modes, - .detect = dp_bridge_detect, - .atomic_check = dp_bridge_atomic_check, - .hpd_enable = dp_bridge_hpd_enable, - .hpd_disable = dp_bridge_hpd_disable, - .hpd_notify = dp_bridge_hpd_notify, - .debugfs_init = dp_bridge_debugfs_init, + .atomic_enable = msm_dp_bridge_atomic_enable, + .atomic_disable = msm_dp_bridge_atomic_disable, + .atomic_post_disable = msm_dp_bridge_atomic_post_disable, + .mode_set = msm_dp_bridge_mode_set, + .mode_valid = msm_dp_bridge_mode_valid, + .get_modes = msm_dp_bridge_get_modes, + .detect = msm_dp_bridge_detect, + .atomic_check = msm_dp_bridge_atomic_check, + .hpd_enable = msm_dp_bridge_hpd_enable, + .hpd_disable = msm_dp_bridge_hpd_disable, + .hpd_notify = msm_dp_bridge_hpd_notify, + .debugfs_init = msm_dp_bridge_debugfs_init, }; -static int edp_bridge_atomic_check(struct drm_bridge *drm_bridge, +static int msm_edp_bridge_atomic_check(struct drm_bridge *drm_bridge, struct drm_bridge_state *bridge_state, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct msm_dp *dp = to_dp_bridge(drm_bridge)->dp_display; + struct msm_dp *dp = to_dp_bridge(drm_bridge)->msm_dp_display; if (WARN_ON(!conn_state)) return -ENODEV; @@ -136,18 +136,18 @@ static int edp_bridge_atomic_check(struct drm_bridge *drm_bridge, return 0; } -static void edp_bridge_atomic_enable(struct drm_bridge *drm_bridge, +static void msm_edp_bridge_atomic_enable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state) { struct drm_atomic_state *atomic_state = old_bridge_state->base.state; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; - struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = dp_bridge->dp_display; + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = msm_dp_bridge->msm_dp_display; /* * Check the old state of the crtc to determine if the panel - * was put into psr state previously by the edp_bridge_atomic_disable. + * was put into psr state previously by the msm_edp_bridge_atomic_disable. * If the panel is in psr, just exit psr state and skip the full * bridge enable sequence. */ @@ -159,21 +159,21 @@ static void edp_bridge_atomic_enable(struct drm_bridge *drm_bridge, old_crtc_state = drm_atomic_get_old_crtc_state(atomic_state, crtc); if (old_crtc_state && old_crtc_state->self_refresh_active) { - dp_display_set_psr(dp, false); + msm_dp_display_set_psr(dp, false); return; } - dp_bridge_atomic_enable(drm_bridge, old_bridge_state); + msm_dp_bridge_atomic_enable(drm_bridge, old_bridge_state); } -static void edp_bridge_atomic_disable(struct drm_bridge *drm_bridge, +static void msm_edp_bridge_atomic_disable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state) { struct drm_atomic_state *atomic_state = old_bridge_state->base.state; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state = NULL, *old_crtc_state = NULL; - struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge); - struct msm_dp *dp = dp_bridge->dp_display; + struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge); + struct msm_dp *dp = msm_dp_bridge->msm_dp_display; crtc = drm_atomic_get_old_crtc_for_encoder(atomic_state, drm_bridge->encoder); @@ -194,24 +194,24 @@ static void edp_bridge_atomic_disable(struct drm_bridge *drm_bridge, * If old crtc state is active, then this is a display disable * call while the sink is in psr state. So, exit psr here. * The eDP controller will be disabled in the - * edp_bridge_atomic_post_disable function. + * msm_edp_bridge_atomic_post_disable function. * * We observed sink is stuck in self refresh if psr exit is skipped * when display disable occurs while the sink is in psr state. */ if (new_crtc_state->self_refresh_active) { - dp_display_set_psr(dp, true); + msm_dp_display_set_psr(dp, true); return; } else if (old_crtc_state->self_refresh_active) { - dp_display_set_psr(dp, false); + msm_dp_display_set_psr(dp, false); return; } out: - dp_bridge_atomic_disable(drm_bridge, old_bridge_state); + msm_dp_bridge_atomic_disable(drm_bridge, old_bridge_state); } -static void edp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, +static void msm_edp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state) { struct drm_atomic_state *atomic_state = old_bridge_state->base.state; @@ -228,29 +228,29 @@ static void edp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, return; /* - * Self refresh mode is already set in edp_bridge_atomic_disable. + * Self refresh mode is already set in msm_edp_bridge_atomic_disable. */ if (new_crtc_state->self_refresh_active) return; - dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state); + msm_dp_bridge_atomic_post_disable(drm_bridge, old_bridge_state); } /** - * edp_bridge_mode_valid - callback to determine if specified mode is valid + * msm_edp_bridge_mode_valid - callback to determine if specified mode is valid * @bridge: Pointer to drm bridge structure * @info: display info * @mode: Pointer to drm mode structure * Returns: Validity status for specified mode */ -static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge, +static enum drm_mode_status msm_edp_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *info, const struct drm_display_mode *mode) { struct msm_dp *dp; int mode_pclk_khz = mode->clock; - dp = to_dp_bridge(bridge)->dp_display; + dp = to_dp_bridge(bridge)->msm_dp_display; if (!dp || !mode_pclk_khz || !dp->connector) { DRM_ERROR("invalid params\n"); @@ -268,42 +268,43 @@ static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } -static void edp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry *root) +static void msm_edp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry *root) { - struct msm_dp *dp = to_dp_bridge(bridge)->dp_display; + struct msm_dp *dp = to_dp_bridge(bridge)->msm_dp_display; - dp_display_debugfs_init(dp, root, true); + msm_dp_display_debugfs_init(dp, root, true); } -static const struct drm_bridge_funcs edp_bridge_ops = { - .atomic_enable = edp_bridge_atomic_enable, - .atomic_disable = edp_bridge_atomic_disable, - .atomic_post_disable = edp_bridge_atomic_post_disable, - .mode_set = dp_bridge_mode_set, - .mode_valid = edp_bridge_mode_valid, +static const struct drm_bridge_funcs msm_edp_bridge_ops = { + .atomic_enable = msm_edp_bridge_atomic_enable, + .atomic_disable = msm_edp_bridge_atomic_disable, + .atomic_post_disable = msm_edp_bridge_atomic_post_disable, + .mode_set = msm_dp_bridge_mode_set, + .mode_valid = msm_edp_bridge_mode_valid, .atomic_reset = drm_atomic_helper_bridge_reset, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, - .atomic_check = edp_bridge_atomic_check, - .debugfs_init = edp_bridge_debugfs_init, + .atomic_check = msm_edp_bridge_atomic_check, + .debugfs_init = msm_edp_bridge_debugfs_init, }; -int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, - struct drm_encoder *encoder) +int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev, + struct drm_encoder *encoder, bool yuv_supported) { int rc; - struct msm_dp_bridge *dp_bridge; + struct msm_dp_bridge *msm_dp_bridge; struct drm_bridge *bridge; - dp_bridge = devm_kzalloc(dev->dev, sizeof(*dp_bridge), GFP_KERNEL); - if (!dp_bridge) + msm_dp_bridge = devm_kzalloc(dev->dev, sizeof(*msm_dp_bridge), GFP_KERNEL); + if (!msm_dp_bridge) return -ENOMEM; - dp_bridge->dp_display = dp_display; + msm_dp_bridge->msm_dp_display = msm_dp_display; - bridge = &dp_bridge->bridge; - bridge->funcs = dp_display->is_edp ? &edp_bridge_ops : &dp_bridge_ops; - bridge->type = dp_display->connector_type; + bridge = &msm_dp_bridge->bridge; + bridge->funcs = msm_dp_display->is_edp ? &msm_edp_bridge_ops : &msm_dp_bridge_ops; + bridge->type = msm_dp_display->connector_type; + bridge->ycbcr_420_allowed = yuv_supported; /* * Many ops only make sense for DP. Why? @@ -316,7 +317,7 @@ int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, * allows the panel driver to properly power itself on to read the * modes. */ - if (!dp_display->is_edp) { + if (!msm_dp_display->is_edp) { bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_HPD | @@ -337,9 +338,9 @@ int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, return rc; } - if (dp_display->next_bridge) { + if (msm_dp_display->next_bridge) { rc = drm_bridge_attach(encoder, - dp_display->next_bridge, bridge, + msm_dp_display->next_bridge, bridge, DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (rc < 0) { DRM_ERROR("failed to attach panel bridge: %d\n", rc); @@ -351,21 +352,18 @@ int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, } /* connector initialization */ -struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder, - bool yuv_supported) +struct drm_connector *msm_dp_drm_connector_init(struct msm_dp *msm_dp_display, + struct drm_encoder *encoder) { struct drm_connector *connector = NULL; - connector = drm_bridge_connector_init(dp_display->drm_dev, encoder); + connector = drm_bridge_connector_init(msm_dp_display->drm_dev, encoder); if (IS_ERR(connector)) return connector; - if (!dp_display->is_edp) + if (!msm_dp_display->is_edp) drm_connector_attach_dp_subconnector_property(connector); - if (yuv_supported) - connector->ycbcr_420_allowed = true; - drm_connector_attach_encoder(connector, encoder); return connector; diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h index 45e57ac25a4d9f..8eae2f74839f71 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.h +++ b/drivers/gpu/drm/msm/dp/dp_drm.h @@ -14,31 +14,32 @@ struct msm_dp_bridge { struct drm_bridge bridge; - struct msm_dp *dp_display; + struct msm_dp *msm_dp_display; }; #define to_dp_bridge(x) container_of((x), struct msm_dp_bridge, bridge) -struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display, struct drm_encoder *encoder, - bool yuv_supported); -int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, - struct drm_encoder *encoder); +struct drm_connector *msm_dp_drm_connector_init(struct msm_dp *msm_dp_display, + struct drm_encoder *encoder); +int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev, + struct drm_encoder *encoder, + bool yuv_supported); -void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, +void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state); -void dp_bridge_atomic_disable(struct drm_bridge *drm_bridge, +void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state); -void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, +void msm_dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, struct drm_bridge_state *old_bridge_state); -enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge, +enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *info, const struct drm_display_mode *mode); -void dp_bridge_mode_set(struct drm_bridge *drm_bridge, +void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode); -void dp_bridge_hpd_enable(struct drm_bridge *bridge); -void dp_bridge_hpd_disable(struct drm_bridge *bridge); -void dp_bridge_hpd_notify(struct drm_bridge *bridge, +void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge); +void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge); +void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge, enum drm_connector_status status); #endif /* _DP_DRM_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index d8967615d84d42..1a1fbb2d7d4f2a 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -28,25 +28,25 @@ enum audio_pattern_type { AUDIO_TEST_PATTERN_SAWTOOTH = 0x01, }; -struct dp_link_request { +struct msm_dp_link_request { u32 test_requested; u32 test_link_rate; u32 test_lane_count; }; -struct dp_link_private { +struct msm_dp_link_private { u32 prev_sink_count; struct drm_device *drm_dev; struct drm_dp_aux *aux; - struct dp_link dp_link; + struct msm_dp_link msm_dp_link; - struct dp_link_request request; + struct msm_dp_link_request request; struct mutex psm_mutex; u8 link_status[DP_LINK_STATUS_SIZE]; }; -static int dp_aux_link_power_up(struct drm_dp_aux *aux, - struct dp_link_info *link) +static int msm_dp_aux_link_power_up(struct drm_dp_aux *aux, + struct msm_dp_link_info *link) { u8 value; ssize_t len; @@ -73,8 +73,8 @@ static int dp_aux_link_power_up(struct drm_dp_aux *aux, return 0; } -static int dp_aux_link_power_down(struct drm_dp_aux *aux, - struct dp_link_info *link) +static int msm_dp_aux_link_power_down(struct drm_dp_aux *aux, + struct msm_dp_link_info *link) { u8 value; int err; @@ -96,7 +96,7 @@ static int dp_aux_link_power_down(struct drm_dp_aux *aux, return 0; } -static int dp_link_get_period(struct dp_link_private *link, int const addr) +static int msm_dp_link_get_period(struct msm_dp_link_private *link, int const addr) { int ret = 0; u8 data; @@ -122,19 +122,19 @@ static int dp_link_get_period(struct dp_link_private *link, int const addr) return ret; } -static int dp_link_parse_audio_channel_period(struct dp_link_private *link) +static int msm_dp_link_parse_audio_channel_period(struct msm_dp_link_private *link) { int ret = 0; - struct dp_link_test_audio *req = &link->dp_link.test_audio; + struct msm_dp_link_test_audio *req = &link->msm_dp_link.test_audio; - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1); + ret = msm_dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1); if (ret == -EINVAL) goto exit; req->test_audio_period_ch_1 = ret; drm_dbg_dp(link->drm_dev, "test_audio_period_ch_1 = 0x%x\n", ret); - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2); + ret = msm_dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2); if (ret == -EINVAL) goto exit; @@ -142,42 +142,42 @@ static int dp_link_parse_audio_channel_period(struct dp_link_private *link) drm_dbg_dp(link->drm_dev, "test_audio_period_ch_2 = 0x%x\n", ret); /* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */ - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3); + ret = msm_dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3); if (ret == -EINVAL) goto exit; req->test_audio_period_ch_3 = ret; drm_dbg_dp(link->drm_dev, "test_audio_period_ch_3 = 0x%x\n", ret); - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4); + ret = msm_dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4); if (ret == -EINVAL) goto exit; req->test_audio_period_ch_4 = ret; drm_dbg_dp(link->drm_dev, "test_audio_period_ch_4 = 0x%x\n", ret); - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5); + ret = msm_dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5); if (ret == -EINVAL) goto exit; req->test_audio_period_ch_5 = ret; drm_dbg_dp(link->drm_dev, "test_audio_period_ch_5 = 0x%x\n", ret); - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6); + ret = msm_dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6); if (ret == -EINVAL) goto exit; req->test_audio_period_ch_6 = ret; drm_dbg_dp(link->drm_dev, "test_audio_period_ch_6 = 0x%x\n", ret); - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7); + ret = msm_dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7); if (ret == -EINVAL) goto exit; req->test_audio_period_ch_7 = ret; drm_dbg_dp(link->drm_dev, "test_audio_period_ch_7 = 0x%x\n", ret); - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8); + ret = msm_dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8); if (ret == -EINVAL) goto exit; @@ -187,7 +187,7 @@ static int dp_link_parse_audio_channel_period(struct dp_link_private *link) return ret; } -static int dp_link_parse_audio_pattern_type(struct dp_link_private *link) +static int msm_dp_link_parse_audio_pattern_type(struct msm_dp_link_private *link) { int ret = 0; u8 data; @@ -208,13 +208,13 @@ static int dp_link_parse_audio_pattern_type(struct dp_link_private *link) goto exit; } - link->dp_link.test_audio.test_audio_pattern_type = data; + link->msm_dp_link.test_audio.test_audio_pattern_type = data; drm_dbg_dp(link->drm_dev, "audio pattern type = 0x%x\n", data); exit: return ret; } -static int dp_link_parse_audio_mode(struct dp_link_private *link) +static int msm_dp_link_parse_audio_mode(struct msm_dp_link_private *link) { int ret = 0; u8 data; @@ -248,8 +248,8 @@ static int dp_link_parse_audio_mode(struct dp_link_private *link) goto exit; } - link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate; - link->dp_link.test_audio.test_audio_channel_count = channel_count; + link->msm_dp_link.test_audio.test_audio_sampling_rate = sampling_rate; + link->msm_dp_link.test_audio.test_audio_channel_count = channel_count; drm_dbg_dp(link->drm_dev, "sampling_rate = 0x%x, channel_count = 0x%x\n", sampling_rate, channel_count); @@ -257,25 +257,25 @@ static int dp_link_parse_audio_mode(struct dp_link_private *link) return ret; } -static int dp_link_parse_audio_pattern_params(struct dp_link_private *link) +static int msm_dp_link_parse_audio_pattern_params(struct msm_dp_link_private *link) { int ret = 0; - ret = dp_link_parse_audio_mode(link); + ret = msm_dp_link_parse_audio_mode(link); if (ret) goto exit; - ret = dp_link_parse_audio_pattern_type(link); + ret = msm_dp_link_parse_audio_pattern_type(link); if (ret) goto exit; - ret = dp_link_parse_audio_channel_period(link); + ret = msm_dp_link_parse_audio_channel_period(link); exit: return ret; } -static bool dp_link_is_video_pattern_valid(u32 pattern) +static bool msm_dp_link_is_video_pattern_valid(u32 pattern) { switch (pattern) { case DP_NO_TEST_PATTERN: @@ -289,12 +289,12 @@ static bool dp_link_is_video_pattern_valid(u32 pattern) } /** - * dp_link_is_bit_depth_valid() - validates the bit depth requested + * msm_dp_link_is_bit_depth_valid() - validates the bit depth requested * @tbd: bit depth requested by the sink * * Returns true if the requested bit depth is supported. */ -static bool dp_link_is_bit_depth_valid(u32 tbd) +static bool msm_dp_link_is_bit_depth_valid(u32 tbd) { /* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */ switch (tbd) { @@ -307,7 +307,7 @@ static bool dp_link_is_bit_depth_valid(u32 tbd) } } -static int dp_link_parse_timing_params1(struct dp_link_private *link, +static int msm_dp_link_parse_timing_params1(struct msm_dp_link_private *link, int addr, int len, u32 *val) { u8 bp[2]; @@ -328,7 +328,7 @@ static int dp_link_parse_timing_params1(struct dp_link_private *link, return 0; } -static int dp_link_parse_timing_params2(struct dp_link_private *link, +static int msm_dp_link_parse_timing_params2(struct msm_dp_link_private *link, int addr, int len, u32 *val1, u32 *val2) { @@ -351,7 +351,7 @@ static int dp_link_parse_timing_params2(struct dp_link_private *link, return 0; } -static int dp_link_parse_timing_params3(struct dp_link_private *link, +static int msm_dp_link_parse_timing_params3(struct msm_dp_link_private *link, int addr, u32 *val) { u8 bp; @@ -369,13 +369,13 @@ static int dp_link_parse_timing_params3(struct dp_link_private *link, } /** - * dp_link_parse_video_pattern_params() - parses video pattern parameters from DPCD + * msm_dp_link_parse_video_pattern_params() - parses video pattern parameters from DPCD * @link: Display Port Driver data * * Returns 0 if it successfully parses the video link pattern and the link * bit depth requested by the sink and, and if the values parsed are valid. */ -static int dp_link_parse_video_pattern_params(struct dp_link_private *link) +static int msm_dp_link_parse_video_pattern_params(struct msm_dp_link_private *link) { int ret = 0; ssize_t rlen; @@ -388,13 +388,13 @@ static int dp_link_parse_video_pattern_params(struct dp_link_private *link) return rlen; } - if (!dp_link_is_video_pattern_valid(bp)) { + if (!msm_dp_link_is_video_pattern_valid(bp)) { DRM_ERROR("invalid link video pattern = 0x%x\n", bp); ret = -EINVAL; return ret; } - link->dp_link.test_video.test_video_pattern = bp; + link->msm_dp_link.test_video.test_video_pattern = bp; /* Read the requested color bit depth and dynamic range (Byte 0x232) */ rlen = drm_dp_dpcd_readb(link->aux, DP_TEST_MISC0, &bp); @@ -404,88 +404,88 @@ static int dp_link_parse_video_pattern_params(struct dp_link_private *link) } /* Dynamic Range */ - link->dp_link.test_video.test_dyn_range = + link->msm_dp_link.test_video.test_dyn_range = (bp & DP_TEST_DYNAMIC_RANGE_CEA); /* Color bit depth */ bp &= DP_TEST_BIT_DEPTH_MASK; - if (!dp_link_is_bit_depth_valid(bp)) { + if (!msm_dp_link_is_bit_depth_valid(bp)) { DRM_ERROR("invalid link bit depth = 0x%x\n", bp); ret = -EINVAL; return ret; } - link->dp_link.test_video.test_bit_depth = bp; + link->msm_dp_link.test_video.test_bit_depth = bp; /* resolution timing params */ - ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2, - &link->dp_link.test_video.test_h_total); + ret = msm_dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2, + &link->msm_dp_link.test_video.test_h_total); if (ret) { DRM_ERROR("failed to parse test_htotal(DP_TEST_H_TOTAL_HI)\n"); return ret; } - ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2, - &link->dp_link.test_video.test_v_total); + ret = msm_dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2, + &link->msm_dp_link.test_video.test_v_total); if (ret) { DRM_ERROR("failed to parse test_v_total(DP_TEST_V_TOTAL_HI)\n"); return ret; } - ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2, - &link->dp_link.test_video.test_h_start); + ret = msm_dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2, + &link->msm_dp_link.test_video.test_h_start); if (ret) { DRM_ERROR("failed to parse test_h_start(DP_TEST_H_START_HI)\n"); return ret; } - ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2, - &link->dp_link.test_video.test_v_start); + ret = msm_dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2, + &link->msm_dp_link.test_video.test_v_start); if (ret) { DRM_ERROR("failed to parse test_v_start(DP_TEST_V_START_HI)\n"); return ret; } - ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2, - &link->dp_link.test_video.test_hsync_pol, - &link->dp_link.test_video.test_hsync_width); + ret = msm_dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2, + &link->msm_dp_link.test_video.test_hsync_pol, + &link->msm_dp_link.test_video.test_hsync_width); if (ret) { DRM_ERROR("failed to parse (DP_TEST_HSYNC_HI)\n"); return ret; } - ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2, - &link->dp_link.test_video.test_vsync_pol, - &link->dp_link.test_video.test_vsync_width); + ret = msm_dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2, + &link->msm_dp_link.test_video.test_vsync_pol, + &link->msm_dp_link.test_video.test_vsync_width); if (ret) { DRM_ERROR("failed to parse (DP_TEST_VSYNC_HI)\n"); return ret; } - ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2, - &link->dp_link.test_video.test_h_width); + ret = msm_dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2, + &link->msm_dp_link.test_video.test_h_width); if (ret) { DRM_ERROR("failed to parse test_h_width(DP_TEST_H_WIDTH_HI)\n"); return ret; } - ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2, - &link->dp_link.test_video.test_v_height); + ret = msm_dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2, + &link->msm_dp_link.test_video.test_v_height); if (ret) { DRM_ERROR("failed to parse test_v_height\n"); return ret; } - ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1, - &link->dp_link.test_video.test_rr_d); - link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR; + ret = msm_dp_link_parse_timing_params3(link, DP_TEST_MISC1, + &link->msm_dp_link.test_video.test_rr_d); + link->msm_dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR; if (ret) { DRM_ERROR("failed to parse test_rr_d (DP_TEST_MISC1)\n"); return ret; } - ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR, - &link->dp_link.test_video.test_rr_n); + ret = msm_dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR, + &link->msm_dp_link.test_video.test_rr_n); if (ret) { DRM_ERROR("failed to parse test_rr_n\n"); return ret; @@ -505,34 +505,34 @@ static int dp_link_parse_video_pattern_params(struct dp_link_private *link) "TEST_V_HEIGHT = %d\n" "TEST_REFRESH_DENOMINATOR = %d\n" "TEST_REFRESH_NUMERATOR = %d\n", - link->dp_link.test_video.test_video_pattern, - link->dp_link.test_video.test_dyn_range, - link->dp_link.test_video.test_bit_depth, - link->dp_link.test_video.test_h_total, - link->dp_link.test_video.test_v_total, - link->dp_link.test_video.test_h_start, - link->dp_link.test_video.test_v_start, - link->dp_link.test_video.test_hsync_pol, - link->dp_link.test_video.test_hsync_width, - link->dp_link.test_video.test_vsync_pol, - link->dp_link.test_video.test_vsync_width, - link->dp_link.test_video.test_h_width, - link->dp_link.test_video.test_v_height, - link->dp_link.test_video.test_rr_d, - link->dp_link.test_video.test_rr_n); + link->msm_dp_link.test_video.test_video_pattern, + link->msm_dp_link.test_video.test_dyn_range, + link->msm_dp_link.test_video.test_bit_depth, + link->msm_dp_link.test_video.test_h_total, + link->msm_dp_link.test_video.test_v_total, + link->msm_dp_link.test_video.test_h_start, + link->msm_dp_link.test_video.test_v_start, + link->msm_dp_link.test_video.test_hsync_pol, + link->msm_dp_link.test_video.test_hsync_width, + link->msm_dp_link.test_video.test_vsync_pol, + link->msm_dp_link.test_video.test_vsync_width, + link->msm_dp_link.test_video.test_h_width, + link->msm_dp_link.test_video.test_v_height, + link->msm_dp_link.test_video.test_rr_d, + link->msm_dp_link.test_video.test_rr_n); return ret; } /** - * dp_link_parse_link_training_params() - parses link training parameters from + * msm_dp_link_parse_link_training_params() - parses link training parameters from * DPCD * @link: Display Port Driver data * * Returns 0 if it successfully parses the link rate (Byte 0x219) and lane * count (Byte 0x220), and if these values parse are valid. */ -static int dp_link_parse_link_training_params(struct dp_link_private *link) +static int msm_dp_link_parse_link_training_params(struct msm_dp_link_private *link) { u8 bp; ssize_t rlen; @@ -571,13 +571,13 @@ static int dp_link_parse_link_training_params(struct dp_link_private *link) } /** - * dp_link_parse_phy_test_params() - parses the phy link parameters + * msm_dp_link_parse_phy_test_params() - parses the phy link parameters * @link: Display Port Driver data * * Parses the DPCD (Byte 0x248) for the DP PHY link pattern that is being * requested. */ -static int dp_link_parse_phy_test_params(struct dp_link_private *link) +static int msm_dp_link_parse_phy_test_params(struct msm_dp_link_private *link) { u8 data; ssize_t rlen; @@ -589,7 +589,7 @@ static int dp_link_parse_phy_test_params(struct dp_link_private *link) return rlen; } - link->dp_link.phy_params.phy_test_pattern_sel = data & 0x07; + link->msm_dp_link.phy_params.phy_test_pattern_sel = data & 0x07; drm_dbg_dp(link->drm_dev, "phy_test_pattern_sel = 0x%x\n", data); @@ -608,12 +608,12 @@ static int dp_link_parse_phy_test_params(struct dp_link_private *link) } /** - * dp_link_is_video_audio_test_requested() - checks for audio/video link request + * msm_dp_link_is_video_audio_test_requested() - checks for audio/video link request * @link: link requested by the sink * * Returns true if the requested link is a permitted audio/video link. */ -static bool dp_link_is_video_audio_test_requested(u32 link) +static bool msm_dp_link_is_video_audio_test_requested(u32 link) { u8 video_audio_test = (DP_TEST_LINK_VIDEO_PATTERN | DP_TEST_LINK_AUDIO_PATTERN | @@ -624,13 +624,13 @@ static bool dp_link_is_video_audio_test_requested(u32 link) } /** - * dp_link_parse_request() - parses link request parameters from sink + * msm_dp_link_parse_request() - parses link request parameters from sink * @link: Display Port Driver data * * Parses the DPCD to check if an automated link is requested (Byte 0x201), * and what type of link automation is being requested (Byte 0x218). */ -static int dp_link_parse_request(struct dp_link_private *link) +static int msm_dp_link_parse_request(struct msm_dp_link_private *link) { int ret = 0; u8 data; @@ -672,27 +672,27 @@ static int dp_link_parse_request(struct dp_link_private *link) drm_dbg_dp(link->drm_dev, "Test:(0x%x) requested\n", data); link->request.test_requested = data; if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) { - ret = dp_link_parse_phy_test_params(link); + ret = msm_dp_link_parse_phy_test_params(link); if (ret) goto end; - ret = dp_link_parse_link_training_params(link); + ret = msm_dp_link_parse_link_training_params(link); if (ret) goto end; } if (link->request.test_requested == DP_TEST_LINK_TRAINING) { - ret = dp_link_parse_link_training_params(link); + ret = msm_dp_link_parse_link_training_params(link); if (ret) goto end; } - if (dp_link_is_video_audio_test_requested( + if (msm_dp_link_is_video_audio_test_requested( link->request.test_requested)) { - ret = dp_link_parse_video_pattern_params(link); + ret = msm_dp_link_parse_video_pattern_params(link); if (ret) goto end; - ret = dp_link_parse_audio_pattern_params(link); + ret = msm_dp_link_parse_audio_pattern_params(link); } end: /* @@ -700,29 +700,29 @@ static int dp_link_parse_request(struct dp_link_private *link) * a DP_TEST_NAK. */ if (ret) { - link->dp_link.test_response = DP_TEST_NAK; + link->msm_dp_link.test_response = DP_TEST_NAK; } else { if (link->request.test_requested != DP_TEST_LINK_EDID_READ) - link->dp_link.test_response = DP_TEST_ACK; + link->msm_dp_link.test_response = DP_TEST_ACK; else - link->dp_link.test_response = + link->msm_dp_link.test_response = DP_TEST_EDID_CHECKSUM_WRITE; } return ret; } -static int dp_link_parse_sink_status_field(struct dp_link_private *link) +static int msm_dp_link_parse_sink_status_field(struct msm_dp_link_private *link) { int len; - link->prev_sink_count = link->dp_link.sink_count; + link->prev_sink_count = link->msm_dp_link.sink_count; len = drm_dp_read_sink_count(link->aux); if (len < 0) { DRM_ERROR("DP parse sink count failed\n"); return len; } - link->dp_link.sink_count = len; + link->msm_dp_link.sink_count = len; len = drm_dp_dpcd_read_link_status(link->aux, link->link_status); @@ -731,11 +731,11 @@ static int dp_link_parse_sink_status_field(struct dp_link_private *link) return len; } - return dp_link_parse_request(link); + return msm_dp_link_parse_request(link); } /** - * dp_link_process_link_training_request() - processes new training requests + * msm_dp_link_process_link_training_request() - processes new training requests * @link: Display Port link data * * This function will handle new link training requests that are initiated by @@ -745,7 +745,7 @@ static int dp_link_parse_sink_status_field(struct dp_link_private *link) * The function will return 0 if a link training request has been processed, * otherwise it will return -EINVAL. */ -static int dp_link_process_link_training_request(struct dp_link_private *link) +static int msm_dp_link_process_link_training_request(struct msm_dp_link_private *link) { if (link->request.test_requested != DP_TEST_LINK_TRAINING) return -EINVAL; @@ -756,49 +756,49 @@ static int dp_link_process_link_training_request(struct dp_link_private *link) link->request.test_link_rate, link->request.test_lane_count); - link->dp_link.link_params.num_lanes = link->request.test_lane_count; - link->dp_link.link_params.rate = + link->msm_dp_link.link_params.num_lanes = link->request.test_lane_count; + link->msm_dp_link.link_params.rate = drm_dp_bw_code_to_link_rate(link->request.test_link_rate); return 0; } -bool dp_link_send_test_response(struct dp_link *dp_link) +bool msm_dp_link_send_test_response(struct msm_dp_link *msm_dp_link) { - struct dp_link_private *link = NULL; + struct msm_dp_link_private *link = NULL; int ret = 0; - if (!dp_link) { + if (!msm_dp_link) { DRM_ERROR("invalid input\n"); return false; } - link = container_of(dp_link, struct dp_link_private, dp_link); + link = container_of(msm_dp_link, struct msm_dp_link_private, msm_dp_link); ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_RESPONSE, - dp_link->test_response); + msm_dp_link->test_response); return ret == 1; } -int dp_link_psm_config(struct dp_link *dp_link, - struct dp_link_info *link_info, bool enable) +int msm_dp_link_psm_config(struct msm_dp_link *msm_dp_link, + struct msm_dp_link_info *link_info, bool enable) { - struct dp_link_private *link = NULL; + struct msm_dp_link_private *link = NULL; int ret = 0; - if (!dp_link) { + if (!msm_dp_link) { DRM_ERROR("invalid params\n"); return -EINVAL; } - link = container_of(dp_link, struct dp_link_private, dp_link); + link = container_of(msm_dp_link, struct msm_dp_link_private, msm_dp_link); mutex_lock(&link->psm_mutex); if (enable) - ret = dp_aux_link_power_down(link->aux, link_info); + ret = msm_dp_aux_link_power_down(link->aux, link_info); else - ret = dp_aux_link_power_up(link->aux, link_info); + ret = msm_dp_aux_link_power_up(link->aux, link_info); if (ret) DRM_ERROR("Failed to %s low power mode\n", enable ? @@ -808,24 +808,24 @@ int dp_link_psm_config(struct dp_link *dp_link, return ret; } -bool dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum) +bool msm_dp_link_send_edid_checksum(struct msm_dp_link *msm_dp_link, u8 checksum) { - struct dp_link_private *link = NULL; + struct msm_dp_link_private *link = NULL; int ret = 0; - if (!dp_link) { + if (!msm_dp_link) { DRM_ERROR("invalid input\n"); return false; } - link = container_of(dp_link, struct dp_link_private, dp_link); + link = container_of(msm_dp_link, struct msm_dp_link_private, msm_dp_link); ret = drm_dp_dpcd_writeb(link->aux, DP_TEST_EDID_CHECKSUM, checksum); return ret == 1; } -static void dp_link_parse_vx_px(struct dp_link_private *link) +static void msm_dp_link_parse_vx_px(struct msm_dp_link_private *link) { drm_dbg_dp(link->drm_dev, "vx: 0=%d, 1=%d, 2=%d, 3=%d\n", drm_dp_get_adjust_request_voltage(link->link_status, 0), @@ -845,31 +845,31 @@ static void dp_link_parse_vx_px(struct dp_link_private *link) */ drm_dbg_dp(link->drm_dev, "Current: v_level = 0x%x, p_level = 0x%x\n", - link->dp_link.phy_params.v_level, - link->dp_link.phy_params.p_level); - link->dp_link.phy_params.v_level = + link->msm_dp_link.phy_params.v_level, + link->msm_dp_link.phy_params.p_level); + link->msm_dp_link.phy_params.v_level = drm_dp_get_adjust_request_voltage(link->link_status, 0); - link->dp_link.phy_params.p_level = + link->msm_dp_link.phy_params.p_level = drm_dp_get_adjust_request_pre_emphasis(link->link_status, 0); - link->dp_link.phy_params.p_level >>= DP_TRAIN_PRE_EMPHASIS_SHIFT; + link->msm_dp_link.phy_params.p_level >>= DP_TRAIN_PRE_EMPHASIS_SHIFT; drm_dbg_dp(link->drm_dev, "Requested: v_level = 0x%x, p_level = 0x%x\n", - link->dp_link.phy_params.v_level, - link->dp_link.phy_params.p_level); + link->msm_dp_link.phy_params.v_level, + link->msm_dp_link.phy_params.p_level); } /** - * dp_link_process_phy_test_pattern_request() - process new phy link requests + * msm_dp_link_process_phy_test_pattern_request() - process new phy link requests * @link: Display Port Driver data * * This function will handle new phy link pattern requests that are initiated * by the sink. The function will return 0 if a phy link pattern has been * processed, otherwise it will return -EINVAL. */ -static int dp_link_process_phy_test_pattern_request( - struct dp_link_private *link) +static int msm_dp_link_process_phy_test_pattern_request( + struct msm_dp_link_private *link) { if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) { drm_dbg_dp(link->drm_dev, "no phy test\n"); @@ -886,24 +886,24 @@ static int dp_link_process_phy_test_pattern_request( drm_dbg_dp(link->drm_dev, "Current: rate = 0x%x, lane count = 0x%x\n", - link->dp_link.link_params.rate, - link->dp_link.link_params.num_lanes); + link->msm_dp_link.link_params.rate, + link->msm_dp_link.link_params.num_lanes); drm_dbg_dp(link->drm_dev, "Requested: rate = 0x%x, lane count = 0x%x\n", link->request.test_link_rate, link->request.test_lane_count); - link->dp_link.link_params.num_lanes = link->request.test_lane_count; - link->dp_link.link_params.rate = + link->msm_dp_link.link_params.num_lanes = link->request.test_lane_count; + link->msm_dp_link.link_params.rate = drm_dp_bw_code_to_link_rate(link->request.test_link_rate); - dp_link_parse_vx_px(link); + msm_dp_link_parse_vx_px(link); return 0; } -static bool dp_link_read_psr_error_status(struct dp_link_private *link) +static bool msm_dp_link_read_psr_error_status(struct msm_dp_link_private *link) { u8 status; @@ -921,7 +921,7 @@ static bool dp_link_read_psr_error_status(struct dp_link_private *link) return true; } -static bool dp_link_psr_capability_changed(struct dp_link_private *link) +static bool msm_dp_link_psr_capability_changed(struct msm_dp_link_private *link) { u8 status; @@ -941,7 +941,7 @@ static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) } /** - * dp_link_process_link_status_update() - processes link status updates + * msm_dp_link_process_link_status_update() - processes link status updates * @link: Display Port link module data * * This function will check for changes in the link status, e.g. clock @@ -951,13 +951,13 @@ static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) * The function will return 0 if the a link status update has been processed, * otherwise it will return -EINVAL. */ -static int dp_link_process_link_status_update(struct dp_link_private *link) +static int msm_dp_link_process_link_status_update(struct msm_dp_link_private *link) { bool channel_eq_done = drm_dp_channel_eq_ok(link->link_status, - link->dp_link.link_params.num_lanes); + link->msm_dp_link.link_params.num_lanes); bool clock_recovery_done = drm_dp_clock_recovery_ok(link->link_status, - link->dp_link.link_params.num_lanes); + link->msm_dp_link.link_params.num_lanes); drm_dbg_dp(link->drm_dev, "channel_eq_done = %d, clock_recovery_done = %d\n", @@ -970,7 +970,7 @@ static int dp_link_process_link_status_update(struct dp_link_private *link) } /** - * dp_link_process_ds_port_status_change() - process port status changes + * msm_dp_link_process_ds_port_status_change() - process port status changes * @link: Display Port Driver data * * This function will handle downstream port updates that are initiated by @@ -980,122 +980,122 @@ static int dp_link_process_link_status_update(struct dp_link_private *link) * The function will return 0 if a downstream port update has been * processed, otherwise it will return -EINVAL. */ -static int dp_link_process_ds_port_status_change(struct dp_link_private *link) +static int msm_dp_link_process_ds_port_status_change(struct msm_dp_link_private *link) { if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) & DP_DOWNSTREAM_PORT_STATUS_CHANGED) goto reset; - if (link->prev_sink_count == link->dp_link.sink_count) + if (link->prev_sink_count == link->msm_dp_link.sink_count) return -EINVAL; reset: /* reset prev_sink_count */ - link->prev_sink_count = link->dp_link.sink_count; + link->prev_sink_count = link->msm_dp_link.sink_count; return 0; } -static bool dp_link_is_video_pattern_requested(struct dp_link_private *link) +static bool msm_dp_link_is_video_pattern_requested(struct msm_dp_link_private *link) { return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN) && !(link->request.test_requested & DP_TEST_LINK_AUDIO_DISABLED_VIDEO); } -static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link) +static bool msm_dp_link_is_audio_pattern_requested(struct msm_dp_link_private *link) { return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN); } -static void dp_link_reset_data(struct dp_link_private *link) +static void msm_dp_link_reset_data(struct msm_dp_link_private *link) { - link->request = (const struct dp_link_request){ 0 }; - link->dp_link.test_video = (const struct dp_link_test_video){ 0 }; - link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN; - link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 }; - link->dp_link.phy_params.phy_test_pattern_sel = 0; - link->dp_link.sink_request = 0; - link->dp_link.test_response = 0; + link->request = (const struct msm_dp_link_request){ 0 }; + link->msm_dp_link.test_video = (const struct msm_dp_link_test_video){ 0 }; + link->msm_dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN; + link->msm_dp_link.test_audio = (const struct msm_dp_link_test_audio){ 0 }; + link->msm_dp_link.phy_params.phy_test_pattern_sel = 0; + link->msm_dp_link.sink_request = 0; + link->msm_dp_link.test_response = 0; } /** - * dp_link_process_request() - handle HPD IRQ transition to HIGH - * @dp_link: pointer to link module data + * msm_dp_link_process_request() - handle HPD IRQ transition to HIGH + * @msm_dp_link: pointer to link module data * * This function will handle the HPD IRQ state transitions from LOW to HIGH * (including cases when there are back to back HPD IRQ HIGH) indicating * the start of a new link training request or sink status update. */ -int dp_link_process_request(struct dp_link *dp_link) +int msm_dp_link_process_request(struct msm_dp_link *msm_dp_link) { int ret = 0; - struct dp_link_private *link; + struct msm_dp_link_private *link; - if (!dp_link) { + if (!msm_dp_link) { DRM_ERROR("invalid input\n"); return -EINVAL; } - link = container_of(dp_link, struct dp_link_private, dp_link); + link = container_of(msm_dp_link, struct msm_dp_link_private, msm_dp_link); - dp_link_reset_data(link); + msm_dp_link_reset_data(link); - ret = dp_link_parse_sink_status_field(link); + ret = msm_dp_link_parse_sink_status_field(link); if (ret) return ret; if (link->request.test_requested == DP_TEST_LINK_EDID_READ) { - dp_link->sink_request |= DP_TEST_LINK_EDID_READ; - } else if (!dp_link_process_ds_port_status_change(link)) { - dp_link->sink_request |= DS_PORT_STATUS_CHANGED; - } else if (!dp_link_process_link_training_request(link)) { - dp_link->sink_request |= DP_TEST_LINK_TRAINING; - } else if (!dp_link_process_phy_test_pattern_request(link)) { - dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN; - } else if (dp_link_read_psr_error_status(link)) { + msm_dp_link->sink_request |= DP_TEST_LINK_EDID_READ; + } else if (!msm_dp_link_process_ds_port_status_change(link)) { + msm_dp_link->sink_request |= DS_PORT_STATUS_CHANGED; + } else if (!msm_dp_link_process_link_training_request(link)) { + msm_dp_link->sink_request |= DP_TEST_LINK_TRAINING; + } else if (!msm_dp_link_process_phy_test_pattern_request(link)) { + msm_dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN; + } else if (msm_dp_link_read_psr_error_status(link)) { DRM_ERROR("PSR IRQ_HPD received\n"); - } else if (dp_link_psr_capability_changed(link)) { + } else if (msm_dp_link_psr_capability_changed(link)) { drm_dbg_dp(link->drm_dev, "PSR Capability changed\n"); } else { - ret = dp_link_process_link_status_update(link); + ret = msm_dp_link_process_link_status_update(link); if (!ret) { - dp_link->sink_request |= DP_LINK_STATUS_UPDATED; + msm_dp_link->sink_request |= DP_LINK_STATUS_UPDATED; } else { - if (dp_link_is_video_pattern_requested(link)) { + if (msm_dp_link_is_video_pattern_requested(link)) { ret = 0; - dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN; + msm_dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN; } - if (dp_link_is_audio_pattern_requested(link)) { - dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN; + if (msm_dp_link_is_audio_pattern_requested(link)) { + msm_dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN; ret = -EINVAL; } } } drm_dbg_dp(link->drm_dev, "sink request=%#x\n", - dp_link->sink_request); + msm_dp_link->sink_request); return ret; } -int dp_link_get_colorimetry_config(struct dp_link *dp_link) +int msm_dp_link_get_colorimetry_config(struct msm_dp_link *msm_dp_link) { u32 cc = DP_MISC0_COLORIMERY_CFG_LEGACY_RGB; - struct dp_link_private *link; + struct msm_dp_link_private *link; - if (!dp_link) { + if (!msm_dp_link) { DRM_ERROR("invalid input\n"); return -EINVAL; } - link = container_of(dp_link, struct dp_link_private, dp_link); + link = container_of(msm_dp_link, struct msm_dp_link_private, msm_dp_link); /* * Unless a video pattern CTS test is ongoing, use RGB_VESA * Only RGB_VESA and RGB_CEA supported for now */ - if (dp_link_is_video_pattern_requested(link)) { - if (link->dp_link.test_video.test_dyn_range & + if (msm_dp_link_is_video_pattern_requested(link)) { + if (link->msm_dp_link.test_video.test_dyn_range & DP_TEST_DYNAMIC_RANGE_CEA) cc = DP_MISC0_COLORIMERY_CFG_CEA_RGB; } @@ -1103,22 +1103,22 @@ int dp_link_get_colorimetry_config(struct dp_link *dp_link) return cc; } -int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) +int msm_dp_link_adjust_levels(struct msm_dp_link *msm_dp_link, u8 *link_status) { int i; u8 max_p_level; int v_max = 0, p_max = 0; - struct dp_link_private *link; + struct msm_dp_link_private *link; - if (!dp_link) { + if (!msm_dp_link) { DRM_ERROR("invalid input\n"); return -EINVAL; } - link = container_of(dp_link, struct dp_link_private, dp_link); + link = container_of(msm_dp_link, struct msm_dp_link_private, msm_dp_link); /* use the max level across lanes */ - for (i = 0; i < dp_link->link_params.num_lanes; i++) { + for (i = 0; i < msm_dp_link->link_params.num_lanes; i++) { u8 data_v = drm_dp_get_adjust_request_voltage(link_status, i); u8 data_p = drm_dp_get_adjust_request_pre_emphasis(link_status, i); @@ -1131,56 +1131,56 @@ int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) p_max = data_p; } - dp_link->phy_params.v_level = v_max >> DP_TRAIN_VOLTAGE_SWING_SHIFT; - dp_link->phy_params.p_level = p_max >> DP_TRAIN_PRE_EMPHASIS_SHIFT; + msm_dp_link->phy_params.v_level = v_max >> DP_TRAIN_VOLTAGE_SWING_SHIFT; + msm_dp_link->phy_params.p_level = p_max >> DP_TRAIN_PRE_EMPHASIS_SHIFT; /** * Adjust the voltage swing and pre-emphasis level combination to within * the allowable range. */ - if (dp_link->phy_params.v_level > DP_TRAIN_LEVEL_MAX) { + if (msm_dp_link->phy_params.v_level > DP_TRAIN_LEVEL_MAX) { drm_dbg_dp(link->drm_dev, "Requested vSwingLevel=%d, change to %d\n", - dp_link->phy_params.v_level, + msm_dp_link->phy_params.v_level, DP_TRAIN_LEVEL_MAX); - dp_link->phy_params.v_level = DP_TRAIN_LEVEL_MAX; + msm_dp_link->phy_params.v_level = DP_TRAIN_LEVEL_MAX; } - if (dp_link->phy_params.p_level > DP_TRAIN_LEVEL_MAX) { + if (msm_dp_link->phy_params.p_level > DP_TRAIN_LEVEL_MAX) { drm_dbg_dp(link->drm_dev, "Requested preEmphasisLevel=%d, change to %d\n", - dp_link->phy_params.p_level, + msm_dp_link->phy_params.p_level, DP_TRAIN_LEVEL_MAX); - dp_link->phy_params.p_level = DP_TRAIN_LEVEL_MAX; + msm_dp_link->phy_params.p_level = DP_TRAIN_LEVEL_MAX; } - max_p_level = DP_TRAIN_LEVEL_MAX - dp_link->phy_params.v_level; - if (dp_link->phy_params.p_level > max_p_level) { + max_p_level = DP_TRAIN_LEVEL_MAX - msm_dp_link->phy_params.v_level; + if (msm_dp_link->phy_params.p_level > max_p_level) { drm_dbg_dp(link->drm_dev, "Requested preEmphasisLevel=%d, change to %d\n", - dp_link->phy_params.p_level, + msm_dp_link->phy_params.p_level, max_p_level); - dp_link->phy_params.p_level = max_p_level; + msm_dp_link->phy_params.p_level = max_p_level; } drm_dbg_dp(link->drm_dev, "adjusted: v_level=%d, p_level=%d\n", - dp_link->phy_params.v_level, dp_link->phy_params.p_level); + msm_dp_link->phy_params.v_level, msm_dp_link->phy_params.p_level); return 0; } -void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link) +void msm_dp_link_reset_phy_params_vx_px(struct msm_dp_link *msm_dp_link) { - dp_link->phy_params.v_level = 0; - dp_link->phy_params.p_level = 0; + msm_dp_link->phy_params.v_level = 0; + msm_dp_link->phy_params.p_level = 0; } -u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp) +u32 msm_dp_link_get_test_bits_depth(struct msm_dp_link *msm_dp_link, u32 bpp) { u32 tbd; - struct dp_link_private *link; + struct msm_dp_link_private *link; - link = container_of(dp_link, struct dp_link_private, dp_link); + link = container_of(msm_dp_link, struct msm_dp_link_private, msm_dp_link); /* * Few simplistic rules and assumptions made here: @@ -1209,10 +1209,10 @@ u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp) return tbd; } -struct dp_link *dp_link_get(struct device *dev, struct drm_dp_aux *aux) +struct msm_dp_link *msm_dp_link_get(struct device *dev, struct drm_dp_aux *aux) { - struct dp_link_private *link; - struct dp_link *dp_link; + struct msm_dp_link_private *link; + struct msm_dp_link *msm_dp_link; if (!dev || !aux) { DRM_ERROR("invalid input\n"); @@ -1226,7 +1226,7 @@ struct dp_link *dp_link_get(struct device *dev, struct drm_dp_aux *aux) link->aux = aux; mutex_init(&link->psm_mutex); - dp_link = &link->dp_link; + msm_dp_link = &link->msm_dp_link; - return dp_link; + return msm_dp_link; } diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index 5846337bb56f3e..8db5d5698a97cf 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -12,7 +12,7 @@ #define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF #define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0) -struct dp_link_info { +struct msm_dp_link_info { unsigned char revision; unsigned int rate; unsigned int num_lanes; @@ -21,7 +21,7 @@ struct dp_link_info { #define DP_TRAIN_LEVEL_MAX 3 -struct dp_link_test_video { +struct msm_dp_link_test_video { u32 test_video_pattern; u32 test_bit_depth; u32 test_dyn_range; @@ -39,7 +39,7 @@ struct dp_link_test_video { u32 test_rr_n; }; -struct dp_link_test_audio { +struct msm_dp_link_test_audio { u32 test_audio_sampling_rate; u32 test_audio_channel_count; u32 test_audio_pattern_type; @@ -53,21 +53,21 @@ struct dp_link_test_audio { u32 test_audio_period_ch_8; }; -struct dp_link_phy_params { +struct msm_dp_link_phy_params { u32 phy_test_pattern_sel; u8 v_level; u8 p_level; }; -struct dp_link { +struct msm_dp_link { u32 sink_request; u32 test_response; u8 sink_count; - struct dp_link_test_video test_video; - struct dp_link_test_audio test_audio; - struct dp_link_phy_params phy_params; - struct dp_link_info link_params; + struct msm_dp_link_test_video test_video; + struct msm_dp_link_test_audio test_audio; + struct msm_dp_link_phy_params phy_params; + struct msm_dp_link_info link_params; }; /** @@ -78,7 +78,7 @@ struct dp_link { * git bit depth value. This function assumes that bit depth has * already been validated. */ -static inline u32 dp_link_bit_depth_to_bpp(u32 tbd) +static inline u32 msm_dp_link_bit_depth_to_bpp(u32 tbd) { /* * Few simplistic rules and assumptions made here: @@ -99,22 +99,22 @@ static inline u32 dp_link_bit_depth_to_bpp(u32 tbd) } } -void dp_link_reset_phy_params_vx_px(struct dp_link *dp_link); -u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp); -int dp_link_process_request(struct dp_link *dp_link); -int dp_link_get_colorimetry_config(struct dp_link *dp_link); -int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status); -bool dp_link_send_test_response(struct dp_link *dp_link); -int dp_link_psm_config(struct dp_link *dp_link, - struct dp_link_info *link_info, bool enable); -bool dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum); +void msm_dp_link_reset_phy_params_vx_px(struct msm_dp_link *msm_dp_link); +u32 msm_dp_link_get_test_bits_depth(struct msm_dp_link *msm_dp_link, u32 bpp); +int msm_dp_link_process_request(struct msm_dp_link *msm_dp_link); +int msm_dp_link_get_colorimetry_config(struct msm_dp_link *msm_dp_link); +int msm_dp_link_adjust_levels(struct msm_dp_link *msm_dp_link, u8 *link_status); +bool msm_dp_link_send_test_response(struct msm_dp_link *msm_dp_link); +int msm_dp_link_psm_config(struct msm_dp_link *msm_dp_link, + struct msm_dp_link_info *link_info, bool enable); +bool msm_dp_link_send_edid_checksum(struct msm_dp_link *msm_dp_link, u8 checksum); /** - * dp_link_get() - get the functionalities of dp test module + * msm_dp_link_get() - get the functionalities of dp test module * * - * return: a pointer to dp_link struct + * return: a pointer to msm_dp_link struct */ -struct dp_link *dp_link_get(struct device *dev, struct drm_dp_aux *aux); +struct msm_dp_link *msm_dp_link_get(struct device *dev, struct drm_dp_aux *aux); #endif /* _DP_LINK_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 6ff6c9ef351ff2..5d7eaa31bf3176 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -14,52 +14,52 @@ #define DP_MAX_NUM_DP_LANES 4 #define DP_LINK_RATE_HBR2 540000 /* kbytes */ -struct dp_panel_private { +struct msm_dp_panel_private { struct device *dev; struct drm_device *drm_dev; - struct dp_panel dp_panel; + struct msm_dp_panel msm_dp_panel; struct drm_dp_aux *aux; - struct dp_link *link; - struct dp_catalog *catalog; + struct msm_dp_link *link; + struct msm_dp_catalog *catalog; bool panel_on; }; -static void dp_panel_read_psr_cap(struct dp_panel_private *panel) +static void msm_dp_panel_read_psr_cap(struct msm_dp_panel_private *panel) { ssize_t rlen; - struct dp_panel *dp_panel; + struct msm_dp_panel *msm_dp_panel; - dp_panel = &panel->dp_panel; + msm_dp_panel = &panel->msm_dp_panel; /* edp sink */ - if (dp_panel->dpcd[DP_EDP_CONFIGURATION_CAP]) { + if (msm_dp_panel->dpcd[DP_EDP_CONFIGURATION_CAP]) { rlen = drm_dp_dpcd_read(panel->aux, DP_PSR_SUPPORT, - &dp_panel->psr_cap, sizeof(dp_panel->psr_cap)); - if (rlen == sizeof(dp_panel->psr_cap)) { + &msm_dp_panel->psr_cap, sizeof(msm_dp_panel->psr_cap)); + if (rlen == sizeof(msm_dp_panel->psr_cap)) { drm_dbg_dp(panel->drm_dev, "psr version: 0x%x, psr_cap: 0x%x\n", - dp_panel->psr_cap.version, - dp_panel->psr_cap.capabilities); + msm_dp_panel->psr_cap.version, + msm_dp_panel->psr_cap.capabilities); } else DRM_ERROR("failed to read psr info, rlen=%zd\n", rlen); } } -static int dp_panel_read_dpcd(struct dp_panel *dp_panel) +static int msm_dp_panel_read_dpcd(struct msm_dp_panel *msm_dp_panel) { int rc; - struct dp_panel_private *panel; - struct dp_link_info *link_info; + struct msm_dp_panel_private *panel; + struct msm_dp_link_info *link_info; u8 *dpcd, major, minor; - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - dpcd = dp_panel->dpcd; + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); + dpcd = msm_dp_panel->dpcd; rc = drm_dp_read_dpcd_caps(panel->aux, dpcd); if (rc) return rc; - dp_panel->vsc_sdp_supported = drm_dp_vsc_sdp_supported(panel->aux, dpcd); - link_info = &dp_panel->link_info; + msm_dp_panel->vsc_sdp_supported = drm_dp_vsc_sdp_supported(panel->aux, dpcd); + link_info = &msm_dp_panel->link_info; link_info->revision = dpcd[DP_DPCD_REV]; major = (link_info->revision >> 4) & 0x0f; minor = link_info->revision & 0x0f; @@ -68,12 +68,12 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) link_info->num_lanes = drm_dp_max_lane_count(dpcd); /* Limit data lanes from data-lanes of endpoint property of dtsi */ - if (link_info->num_lanes > dp_panel->max_dp_lanes) - link_info->num_lanes = dp_panel->max_dp_lanes; + if (link_info->num_lanes > msm_dp_panel->max_dp_lanes) + link_info->num_lanes = msm_dp_panel->max_dp_lanes; /* Limit link rate from link-frequencies of endpoint property of dtsi */ - if (link_info->rate > dp_panel->max_dp_link_rate) - link_info->rate = dp_panel->max_dp_link_rate; + if (link_info->rate > msm_dp_panel->max_dp_link_rate) + link_info->rate = msm_dp_panel->max_dp_link_rate; drm_dbg_dp(panel->drm_dev, "version: %d.%d\n", major, minor); drm_dbg_dp(panel->drm_dev, "link_rate=%d\n", link_info->rate); @@ -82,21 +82,21 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel) if (drm_dp_enhanced_frame_cap(dpcd)) link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; - dp_panel_read_psr_cap(panel); + msm_dp_panel_read_psr_cap(panel); return rc; } -static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, +static u32 msm_dp_panel_get_supported_bpp(struct msm_dp_panel *msm_dp_panel, u32 mode_edid_bpp, u32 mode_pclk_khz) { - const struct dp_link_info *link_info; + const struct msm_dp_link_info *link_info; const u32 max_supported_bpp = 30, min_supported_bpp = 18; u32 bpp, data_rate_khz; bpp = min(mode_edid_bpp, max_supported_bpp); - link_info = &dp_panel->link_info; + link_info = &msm_dp_panel->link_info; data_rate_khz = link_info->num_lanes * link_info->rate * 8; do { @@ -108,39 +108,39 @@ static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, return min_supported_bpp; } -int dp_panel_read_sink_caps(struct dp_panel *dp_panel, +int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel, struct drm_connector *connector) { int rc, bw_code; int count; - struct dp_panel_private *panel; + struct msm_dp_panel_private *panel; - if (!dp_panel || !connector) { + if (!msm_dp_panel || !connector) { DRM_ERROR("invalid input\n"); return -EINVAL; } - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); drm_dbg_dp(panel->drm_dev, "max_lanes=%d max_link_rate=%d\n", - dp_panel->max_dp_lanes, dp_panel->max_dp_link_rate); + msm_dp_panel->max_dp_lanes, msm_dp_panel->max_dp_link_rate); - rc = dp_panel_read_dpcd(dp_panel); + rc = msm_dp_panel_read_dpcd(msm_dp_panel); if (rc) { DRM_ERROR("read dpcd failed %d\n", rc); return rc; } - bw_code = drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate); + bw_code = drm_dp_link_rate_to_bw_code(msm_dp_panel->link_info.rate); if (!is_link_rate_valid(bw_code) || - !is_lane_count_valid(dp_panel->link_info.num_lanes) || - (bw_code > dp_panel->max_bw_code)) { - DRM_ERROR("Illegal link rate=%d lane=%d\n", dp_panel->link_info.rate, - dp_panel->link_info.num_lanes); + !is_lane_count_valid(msm_dp_panel->link_info.num_lanes) || + (bw_code > msm_dp_panel->max_bw_code)) { + DRM_ERROR("Illegal link rate=%d lane=%d\n", msm_dp_panel->link_info.rate, + msm_dp_panel->link_info.num_lanes); return -EINVAL; } - if (drm_dp_is_branch(dp_panel->dpcd)) { + if (drm_dp_is_branch(msm_dp_panel->dpcd)) { count = drm_dp_read_sink_count(panel->aux); if (!count) { panel->link->sink_count = 0; @@ -148,21 +148,21 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, } } - rc = drm_dp_read_downstream_info(panel->aux, dp_panel->dpcd, - dp_panel->downstream_ports); + rc = drm_dp_read_downstream_info(panel->aux, msm_dp_panel->dpcd, + msm_dp_panel->downstream_ports); if (rc) return rc; - drm_edid_free(dp_panel->drm_edid); + drm_edid_free(msm_dp_panel->drm_edid); - dp_panel->drm_edid = drm_edid_read_ddc(connector, &panel->aux->ddc); + msm_dp_panel->drm_edid = drm_edid_read_ddc(connector, &panel->aux->ddc); - drm_edid_connector_update(connector, dp_panel->drm_edid); + drm_edid_connector_update(connector, msm_dp_panel->drm_edid); - if (!dp_panel->drm_edid) { + if (!msm_dp_panel->drm_edid) { DRM_ERROR("panel edid read failed\n"); /* check edid read fail is due to unplug */ - if (!dp_catalog_link_is_connected(panel->catalog)) { + if (!msm_dp_catalog_link_is_connected(panel->catalog)) { rc = -ETIMEDOUT; goto end; } @@ -172,87 +172,87 @@ int dp_panel_read_sink_caps(struct dp_panel *dp_panel, return rc; } -u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, +u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel, u32 mode_edid_bpp, u32 mode_pclk_khz) { - struct dp_panel_private *panel; + struct msm_dp_panel_private *panel; u32 bpp; - if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) { + if (!msm_dp_panel || !mode_edid_bpp || !mode_pclk_khz) { DRM_ERROR("invalid input\n"); return 0; } - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); - if (dp_panel->video_test) - bpp = dp_link_bit_depth_to_bpp( + if (msm_dp_panel->video_test) + bpp = msm_dp_link_bit_depth_to_bpp( panel->link->test_video.test_bit_depth); else - bpp = dp_panel_get_supported_bpp(dp_panel, mode_edid_bpp, + bpp = msm_dp_panel_get_supported_bpp(msm_dp_panel, mode_edid_bpp, mode_pclk_khz); return bpp; } -int dp_panel_get_modes(struct dp_panel *dp_panel, +int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel, struct drm_connector *connector) { - if (!dp_panel) { + if (!msm_dp_panel) { DRM_ERROR("invalid input\n"); return -EINVAL; } - if (dp_panel->drm_edid) + if (msm_dp_panel->drm_edid) return drm_edid_connector_add_modes(connector); return 0; } -static u8 dp_panel_get_edid_checksum(const struct edid *edid) +static u8 msm_dp_panel_get_edid_checksum(const struct edid *edid) { edid += edid->extensions; return edid->checksum; } -void dp_panel_handle_sink_request(struct dp_panel *dp_panel) +void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel) { - struct dp_panel_private *panel; + struct msm_dp_panel_private *panel; - if (!dp_panel) { + if (!msm_dp_panel) { DRM_ERROR("invalid input\n"); return; } - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { /* FIXME: get rid of drm_edid_raw() */ - const struct edid *edid = drm_edid_raw(dp_panel->drm_edid); + const struct edid *edid = drm_edid_raw(msm_dp_panel->drm_edid); u8 checksum; if (edid) - checksum = dp_panel_get_edid_checksum(edid); + checksum = msm_dp_panel_get_edid_checksum(edid); else - checksum = dp_panel->connector->real_edid_checksum; + checksum = msm_dp_panel->connector->real_edid_checksum; - dp_link_send_edid_checksum(panel->link, checksum); - dp_link_send_test_response(panel->link); + msm_dp_link_send_edid_checksum(panel->link, checksum); + msm_dp_link_send_test_response(panel->link); } } -void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable) +void msm_dp_panel_tpg_config(struct msm_dp_panel *msm_dp_panel, bool enable) { - struct dp_catalog *catalog; - struct dp_panel_private *panel; + struct msm_dp_catalog *catalog; + struct msm_dp_panel_private *panel; - if (!dp_panel) { + if (!msm_dp_panel) { DRM_ERROR("invalid input\n"); return; } - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); catalog = panel->catalog; if (!panel->panel_on) { @@ -262,31 +262,31 @@ void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable) } if (!enable) { - dp_catalog_panel_tpg_disable(catalog); + msm_dp_catalog_panel_tpg_disable(catalog); return; } drm_dbg_dp(panel->drm_dev, "calling catalog tpg_enable\n"); - dp_catalog_panel_tpg_enable(catalog, &panel->dp_panel.dp_mode.drm_mode); + msm_dp_catalog_panel_tpg_enable(catalog, &panel->msm_dp_panel.msm_dp_mode.drm_mode); } -static int dp_panel_setup_vsc_sdp_yuv_420(struct dp_panel *dp_panel) +static int msm_dp_panel_setup_vsc_sdp_yuv_420(struct msm_dp_panel *msm_dp_panel) { - struct dp_catalog *catalog; - struct dp_panel_private *panel; - struct dp_display_mode *dp_mode; + struct msm_dp_catalog *catalog; + struct msm_dp_panel_private *panel; + struct msm_dp_display_mode *msm_dp_mode; struct drm_dp_vsc_sdp vsc_sdp_data; struct dp_sdp vsc_sdp; ssize_t len; - if (!dp_panel) { + if (!msm_dp_panel) { DRM_ERROR("invalid input\n"); return -EINVAL; } - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); catalog = panel->catalog; - dp_mode = &dp_panel->dp_mode; + msm_dp_mode = &msm_dp_panel->msm_dp_mode; memset(&vsc_sdp_data, 0, sizeof(vsc_sdp_data)); @@ -300,7 +300,7 @@ static int dp_panel_setup_vsc_sdp_yuv_420(struct dp_panel *dp_panel) vsc_sdp_data.colorimetry = DP_COLORIMETRY_DEFAULT; /* VSC SDP Payload for DB17 */ - vsc_sdp_data.bpc = dp_mode->bpp / 3; + vsc_sdp_data.bpc = msm_dp_mode->bpp / 3; vsc_sdp_data.dynamic_range = DP_DYNAMIC_RANGE_CTA; /* VSC SDP Payload for DB18 */ @@ -312,36 +312,36 @@ static int dp_panel_setup_vsc_sdp_yuv_420(struct dp_panel *dp_panel) return len; } - dp_catalog_panel_enable_vsc_sdp(catalog, &vsc_sdp); + msm_dp_catalog_panel_enable_vsc_sdp(catalog, &vsc_sdp); return 0; } -void dp_panel_dump_regs(struct dp_panel *dp_panel) +void msm_dp_panel_dump_regs(struct msm_dp_panel *msm_dp_panel) { - struct dp_catalog *catalog; - struct dp_panel_private *panel; + struct msm_dp_catalog *catalog; + struct msm_dp_panel_private *panel; - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); catalog = panel->catalog; - dp_catalog_dump_regs(catalog); + msm_dp_catalog_dump_regs(catalog); } -int dp_panel_timing_cfg(struct dp_panel *dp_panel) +int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel) { u32 data, total_ver, total_hor; - struct dp_catalog *catalog; - struct dp_panel_private *panel; + struct msm_dp_catalog *catalog; + struct msm_dp_panel_private *panel; struct drm_display_mode *drm_mode; u32 width_blanking; u32 sync_start; - u32 dp_active; + u32 msm_dp_active; u32 total; - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); catalog = panel->catalog; - drm_mode = &panel->dp_panel.dp_mode.drm_mode; + drm_mode = &panel->msm_dp_panel.msm_dp_mode.drm_mode; drm_dbg_dp(panel->drm_dev, "width=%d hporch= %d %d %d\n", drm_mode->hdisplay, drm_mode->htotal - drm_mode->hsync_end, @@ -371,9 +371,9 @@ int dp_panel_timing_cfg(struct dp_panel *dp_panel) data = drm_mode->vsync_end - drm_mode->vsync_start; data <<= 16; - data |= (panel->dp_panel.dp_mode.v_active_low << 31); + data |= (panel->msm_dp_panel.msm_dp_mode.v_active_low << 31); data |= drm_mode->hsync_end - drm_mode->hsync_start; - data |= (panel->dp_panel.dp_mode.h_active_low << 15); + data |= (panel->msm_dp_panel.msm_dp_mode.h_active_low << 15); width_blanking = data; @@ -381,26 +381,26 @@ int dp_panel_timing_cfg(struct dp_panel *dp_panel) data <<= 16; data |= drm_mode->hdisplay; - dp_active = data; + msm_dp_active = data; - dp_catalog_panel_timing_cfg(catalog, total, sync_start, width_blanking, dp_active); + msm_dp_catalog_panel_timing_cfg(catalog, total, sync_start, width_blanking, msm_dp_active); - if (dp_panel->dp_mode.out_fmt_is_yuv_420) - dp_panel_setup_vsc_sdp_yuv_420(dp_panel); + if (msm_dp_panel->msm_dp_mode.out_fmt_is_yuv_420) + msm_dp_panel_setup_vsc_sdp_yuv_420(msm_dp_panel); panel->panel_on = true; return 0; } -int dp_panel_init_panel_info(struct dp_panel *dp_panel) +int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel) { struct drm_display_mode *drm_mode; - struct dp_panel_private *panel; + struct msm_dp_panel_private *panel; - drm_mode = &dp_panel->dp_mode.drm_mode; + drm_mode = &msm_dp_panel->msm_dp_mode.drm_mode; - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); /* * print resolution info as this is a result @@ -421,18 +421,18 @@ int dp_panel_init_panel_info(struct dp_panel *dp_panel) drm_mode->vsync_end - drm_mode->vsync_start); drm_dbg_dp(panel->drm_dev, "pixel clock (KHz)=(%d)\n", drm_mode->clock); - drm_dbg_dp(panel->drm_dev, "bpp = %d\n", dp_panel->dp_mode.bpp); + drm_dbg_dp(panel->drm_dev, "bpp = %d\n", msm_dp_panel->msm_dp_mode.bpp); - dp_panel->dp_mode.bpp = dp_panel_get_mode_bpp(dp_panel, dp_panel->dp_mode.bpp, - dp_panel->dp_mode.drm_mode.clock); + msm_dp_panel->msm_dp_mode.bpp = msm_dp_panel_get_mode_bpp(msm_dp_panel, msm_dp_panel->msm_dp_mode.bpp, + msm_dp_panel->msm_dp_mode.drm_mode.clock); drm_dbg_dp(panel->drm_dev, "updated bpp = %d\n", - dp_panel->dp_mode.bpp); + msm_dp_panel->msm_dp_mode.bpp); return 0; } -static u32 dp_panel_link_frequencies(struct device_node *of_node) +static u32 msm_dp_panel_link_frequencies(struct device_node *of_node) { struct device_node *endpoint; u64 frequency = 0; @@ -456,17 +456,17 @@ static u32 dp_panel_link_frequencies(struct device_node *of_node) return frequency; } -static int dp_panel_parse_dt(struct dp_panel *dp_panel) +static int msm_dp_panel_parse_dt(struct msm_dp_panel *msm_dp_panel) { - struct dp_panel_private *panel; + struct msm_dp_panel_private *panel; struct device_node *of_node; int cnt; - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel = container_of(msm_dp_panel, struct msm_dp_panel_private, msm_dp_panel); of_node = panel->dev->of_node; /* - * data-lanes is the property of dp_out endpoint + * data-lanes is the property of msm_dp_out endpoint */ cnt = drm_of_get_data_lanes_count_ep(of_node, 1, 0, 1, DP_MAX_NUM_DP_LANES); if (cnt < 0) { @@ -475,21 +475,21 @@ static int dp_panel_parse_dt(struct dp_panel *dp_panel) } if (cnt > 0) - dp_panel->max_dp_lanes = cnt; + msm_dp_panel->max_dp_lanes = cnt; else - dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ + msm_dp_panel->max_dp_lanes = DP_MAX_NUM_DP_LANES; /* 4 lanes */ - dp_panel->max_dp_link_rate = dp_panel_link_frequencies(of_node); - if (!dp_panel->max_dp_link_rate) - dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2; + msm_dp_panel->max_dp_link_rate = msm_dp_panel_link_frequencies(of_node); + if (!msm_dp_panel->max_dp_link_rate) + msm_dp_panel->max_dp_link_rate = DP_LINK_RATE_HBR2; return 0; } -struct dp_panel *dp_panel_get(struct dp_panel_in *in) +struct msm_dp_panel *msm_dp_panel_get(struct msm_dp_panel_in *in) { - struct dp_panel_private *panel; - struct dp_panel *dp_panel; + struct msm_dp_panel_private *panel; + struct msm_dp_panel *msm_dp_panel; int ret; if (!in->dev || !in->catalog || !in->aux || !in->link) { @@ -506,20 +506,20 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) panel->catalog = in->catalog; panel->link = in->link; - dp_panel = &panel->dp_panel; - dp_panel->max_bw_code = DP_LINK_BW_8_1; + msm_dp_panel = &panel->msm_dp_panel; + msm_dp_panel->max_bw_code = DP_LINK_BW_8_1; - ret = dp_panel_parse_dt(dp_panel); + ret = msm_dp_panel_parse_dt(msm_dp_panel); if (ret) return ERR_PTR(ret); - return dp_panel; + return msm_dp_panel; } -void dp_panel_put(struct dp_panel *dp_panel) +void msm_dp_panel_put(struct msm_dp_panel *msm_dp_panel) { - if (!dp_panel) + if (!msm_dp_panel) return; - drm_edid_free(dp_panel->drm_edid); + drm_edid_free(msm_dp_panel->drm_edid); } diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index 6722e3923fa596..0e944db3adf2f1 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -13,7 +13,7 @@ struct edid; -struct dp_display_mode { +struct msm_dp_display_mode { struct drm_display_mode drm_mode; u32 bpp; u32 h_active_low; @@ -21,28 +21,28 @@ struct dp_display_mode { bool out_fmt_is_yuv_420; }; -struct dp_panel_in { +struct msm_dp_panel_in { struct device *dev; struct drm_dp_aux *aux; - struct dp_link *link; - struct dp_catalog *catalog; + struct msm_dp_link *link; + struct msm_dp_catalog *catalog; }; -struct dp_panel_psr { +struct msm_dp_panel_psr { u8 version; u8 capabilities; }; -struct dp_panel { +struct msm_dp_panel { /* dpcd raw data */ u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; - struct dp_link_info link_info; + struct msm_dp_link_info link_info; const struct drm_edid *drm_edid; struct drm_connector *connector; - struct dp_display_mode dp_mode; - struct dp_panel_psr psr_cap; + struct msm_dp_display_mode msm_dp_mode; + struct msm_dp_panel_psr psr_cap; bool video_test; bool vsc_sdp_supported; @@ -52,18 +52,18 @@ struct dp_panel { u32 max_bw_code; }; -int dp_panel_init_panel_info(struct dp_panel *dp_panel); -int dp_panel_deinit(struct dp_panel *dp_panel); -int dp_panel_timing_cfg(struct dp_panel *dp_panel); -void dp_panel_dump_regs(struct dp_panel *dp_panel); -int dp_panel_read_sink_caps(struct dp_panel *dp_panel, +int msm_dp_panel_init_panel_info(struct msm_dp_panel *msm_dp_panel); +int msm_dp_panel_deinit(struct msm_dp_panel *msm_dp_panel); +int msm_dp_panel_timing_cfg(struct msm_dp_panel *msm_dp_panel); +void msm_dp_panel_dump_regs(struct msm_dp_panel *msm_dp_panel); +int msm_dp_panel_read_sink_caps(struct msm_dp_panel *msm_dp_panel, struct drm_connector *connector); -u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, u32 mode_max_bpp, +u32 msm_dp_panel_get_mode_bpp(struct msm_dp_panel *msm_dp_panel, u32 mode_max_bpp, u32 mode_pclk_khz); -int dp_panel_get_modes(struct dp_panel *dp_panel, +int msm_dp_panel_get_modes(struct msm_dp_panel *msm_dp_panel, struct drm_connector *connector); -void dp_panel_handle_sink_request(struct dp_panel *dp_panel); -void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable); +void msm_dp_panel_handle_sink_request(struct msm_dp_panel *msm_dp_panel); +void msm_dp_panel_tpg_config(struct msm_dp_panel *msm_dp_panel, bool enable); /** * is_link_rate_valid() - validates the link rate @@ -80,7 +80,7 @@ static inline bool is_link_rate_valid(u32 bw_code) } /** - * dp_link_is_lane_count_valid() - validates the lane count + * msm_dp_link_is_lane_count_valid() - validates the lane count * @lane_count: lane count requested by the sink * * Returns true if the requested lane count is supported. @@ -92,6 +92,6 @@ static inline bool is_lane_count_valid(u32 lane_count) lane_count == 4); } -struct dp_panel *dp_panel_get(struct dp_panel_in *in); -void dp_panel_put(struct dp_panel *dp_panel); +struct msm_dp_panel *msm_dp_panel_get(struct msm_dp_panel_in *in); +void msm_dp_panel_put(struct msm_dp_panel *msm_dp_panel); #endif /* _DP_PANEL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_utils.c b/drivers/gpu/drm/msm/dp/dp_utils.c index da9207caf72d7c..2a40f07fe2d5e2 100644 --- a/drivers/gpu/drm/msm/dp/dp_utils.c +++ b/drivers/gpu/drm/msm/dp/dp_utils.c @@ -9,7 +9,7 @@ #define DP_SDP_HEADER_SIZE 8 -u8 dp_utils_get_g0_value(u8 data) +u8 msm_dp_utils_get_g0_value(u8 data) { u8 c[4]; u8 g[4]; @@ -30,7 +30,7 @@ u8 dp_utils_get_g0_value(u8 data) return ret_data; } -u8 dp_utils_get_g1_value(u8 data) +u8 msm_dp_utils_get_g1_value(u8 data) { u8 c[4]; u8 g[4]; @@ -51,7 +51,7 @@ u8 dp_utils_get_g1_value(u8 data) return ret_data; } -u8 dp_utils_calculate_parity(u32 data) +u8 msm_dp_utils_calculate_parity(u32 data) { u8 x0 = 0; u8 x1 = 0; @@ -65,8 +65,8 @@ u8 dp_utils_calculate_parity(u32 data) iData = (data >> i * 4) & 0xF; ci = iData ^ x1; - x1 = x0 ^ dp_utils_get_g1_value(ci); - x0 = dp_utils_get_g0_value(ci); + x1 = x0 ^ msm_dp_utils_get_g1_value(ci); + x0 = msm_dp_utils_get_g0_value(ci); } parity_byte = x1 | (x0 << 4); @@ -74,7 +74,7 @@ u8 dp_utils_calculate_parity(u32 data) return parity_byte; } -ssize_t dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_buff) +ssize_t msm_dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_buff) { size_t length; @@ -83,14 +83,14 @@ ssize_t dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_b return -ENOSPC; header_buff[0] = FIELD_PREP(HEADER_0_MASK, sdp_header->HB0) | - FIELD_PREP(PARITY_0_MASK, dp_utils_calculate_parity(sdp_header->HB0)) | + FIELD_PREP(PARITY_0_MASK, msm_dp_utils_calculate_parity(sdp_header->HB0)) | FIELD_PREP(HEADER_1_MASK, sdp_header->HB1) | - FIELD_PREP(PARITY_1_MASK, dp_utils_calculate_parity(sdp_header->HB1)); + FIELD_PREP(PARITY_1_MASK, msm_dp_utils_calculate_parity(sdp_header->HB1)); header_buff[1] = FIELD_PREP(HEADER_2_MASK, sdp_header->HB2) | - FIELD_PREP(PARITY_2_MASK, dp_utils_calculate_parity(sdp_header->HB2)) | + FIELD_PREP(PARITY_2_MASK, msm_dp_utils_calculate_parity(sdp_header->HB2)) | FIELD_PREP(HEADER_3_MASK, sdp_header->HB3) | - FIELD_PREP(PARITY_3_MASK, dp_utils_calculate_parity(sdp_header->HB3)); + FIELD_PREP(PARITY_3_MASK, msm_dp_utils_calculate_parity(sdp_header->HB3)); return length; } diff --git a/drivers/gpu/drm/msm/dp/dp_utils.h b/drivers/gpu/drm/msm/dp/dp_utils.h index 7c056d9798dc3a..88d53157f5b59e 100644 --- a/drivers/gpu/drm/msm/dp/dp_utils.h +++ b/drivers/gpu/drm/msm/dp/dp_utils.h @@ -28,9 +28,9 @@ #define HEADER_3_MASK GENMASK(23, 16) #define PARITY_3_MASK GENMASK(31, 24) -u8 dp_utils_get_g0_value(u8 data); -u8 dp_utils_get_g1_value(u8 data); -u8 dp_utils_calculate_parity(u32 data); -ssize_t dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_buff); +u8 msm_dp_utils_get_g0_value(u8 data); +u8 msm_dp_utils_get_g1_value(u8 data); +u8 msm_dp_utils_calculate_parity(u32 data); +ssize_t msm_dp_utils_pack_sdp_header(struct dp_sdp_header *sdp_header, u32 *header_buff); #endif /* _DP_UTILS_H_ */ diff --git a/drivers/gpu/drm/msm/dsi/dsi.c b/drivers/gpu/drm/msm/dsi/dsi.c index efd7c23b662fff..2962158776135d 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.c +++ b/drivers/gpu/drm/msm/dsi/dsi.c @@ -207,7 +207,7 @@ static const struct dev_pm_ops dsi_pm_ops = { static struct platform_driver dsi_driver = { .probe = dsi_dev_probe, - .remove_new = dsi_dev_remove, + .remove = dsi_dev_remove, .driver = { .name = "msm_dsi", .of_match_table = dt_match, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 0bfee41c2e71a0..37b3809c6bdd7c 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -561,7 +561,7 @@ static const struct of_device_id msm_hdmi_dt_match[] = { static struct platform_driver msm_hdmi_driver = { .probe = msm_hdmi_dev_probe, - .remove_new = msm_hdmi_dev_remove, + .remove = msm_hdmi_dev_remove, .driver = { .name = "hdmi_msm", .of_match_table = msm_hdmi_dt_match, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index 95b3f7535d840e..03120c54ced686 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -203,7 +203,7 @@ static const struct of_device_id msm_hdmi_phy_dt_match[] = { static struct platform_driver msm_hdmi_phy_platform_driver = { .probe = msm_hdmi_phy_probe, - .remove_new = msm_hdmi_phy_remove, + .remove = msm_hdmi_phy_remove, .driver = { .name = "msm_hdmi_phy", .of_match_table = msm_hdmi_phy_dt_match, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c index e6ffaf92d26d32..a719fd33d9d8d5 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c @@ -157,9 +157,8 @@ static inline u32 pll_get_pll_cmp(u64 fdata, unsigned long ref_clk) #define HDMI_MHZ_TO_HZ ((u64)1000000) static int pll_get_post_div(struct hdmi_8998_post_divider *pd, u64 bclk) { - u32 const ratio_list[] = {1, 2, 3, 4, 5, 6, - 9, 10, 12, 15, 25}; - u32 const band_list[] = {0, 1, 2, 3}; + static const u32 ratio_list[] = {1, 2, 3, 4, 5, 6, 9, 10, 12, 15, 25}; + static const u32 band_list[] = {0, 1, 2, 3}; u32 const sz_ratio = ARRAY_SIZE(ratio_list); u32 const sz_band = ARRAY_SIZE(band_list); u32 const cmp_cnt = 1024; @@ -270,7 +269,7 @@ static int pll_get_post_div(struct hdmi_8998_post_divider *pd, u64 bclk) case 25: found_hsclk_divsel = 14; break; - }; + } pd->vco_freq = found_vco_freq; pd->tx_band_sel = found_tx_band_sel; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 8c13b08708d228..ffbcc97b5018b5 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -291,7 +292,7 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv) if (priv->kms_init) { drm_kms_helper_poll_init(ddev); - msm_fbdev_setup(ddev); + drm_client_setup(ddev, NULL); } return 0; @@ -902,6 +903,7 @@ static const struct drm_driver msm_driver = { #ifdef CONFIG_DEBUG_FS .debugfs_init = msm_debugfs_init, #endif + MSM_FBDEV_DRIVER_OPS, .show_fdinfo = msm_show_fdinfo, .ioctls = msm_ioctls, .num_ioctls = ARRAY_SIZE(msm_ioctls), @@ -983,6 +985,10 @@ module_param(prefer_mdp5, bool, 0444); /* list all platforms supported by both mdp5 and dpu drivers */ static const char *const msm_mdp5_dpu_migration[] = { + "qcom,msm8917-mdp5", + "qcom,msm8937-mdp5", + "qcom,msm8953-mdp5", + "qcom,msm8996-mdp5", "qcom,sdm630-mdp5", "qcom,sdm660-mdp5", NULL, @@ -1105,7 +1111,7 @@ static void msm_pdev_remove(struct platform_device *pdev) static struct platform_driver msm_platform_driver = { .probe = msm_pdev_probe, - .remove_new = msm_pdev_remove, + .remove = msm_pdev_remove, .driver = { .name = "msm", }, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 2e28a13446366c..d8c9a1b192632d 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -36,6 +36,9 @@ extern struct fault_attr fail_gem_alloc; extern struct fault_attr fail_gem_iova; +struct drm_fb_helper; +struct drm_fb_helper_surface_size; + struct msm_kms; struct msm_gpu; struct msm_mmu; @@ -49,7 +52,6 @@ struct msm_gem_vma; struct msm_disp_state; #define MAX_CRTCS 8 -#define MAX_BRIDGES 8 #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) @@ -68,23 +70,6 @@ enum msm_dsi_controller { }; #define MSM_GPU_MAX_RINGS 4 -#define MAX_H_TILES_PER_DISPLAY 2 - -/** - * struct msm_display_topology - defines a display topology pipeline - * @num_lm: number of layer mixers used - * @num_intf: number of interfaces the panel is mounted on - * @num_dspp: number of dspp blocks used - * @num_dsc: number of Display Stream Compression (DSC) blocks used - * @needs_cdm: indicates whether cdm block is needed for this display topology - */ -struct msm_display_topology { - u32 num_lm; - u32 num_intf; - u32 num_dspp; - u32 num_dsc; - bool needs_cdm; -}; /* Commit/Event thread specific structure */ struct msm_drm_thread { @@ -290,11 +275,13 @@ struct drm_framebuffer * msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format); #ifdef CONFIG_DRM_FBDEV_EMULATION -void msm_fbdev_setup(struct drm_device *dev); +int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes); +#define MSM_FBDEV_DRIVER_OPS \ + .fbdev_probe = msm_fbdev_driver_fbdev_probe #else -static inline void msm_fbdev_setup(struct drm_device *dev) -{ -} +#define MSM_FBDEV_DRIVER_OPS \ + .fbdev_probe = NULL #endif struct hdmi; diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 030bedac632d09..c62249b1ab3d0c 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -65,8 +65,31 @@ static const struct fb_ops msm_fb_ops = { .fb_destroy = msm_fbdev_fb_destroy, }; -static int msm_fbdev_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) +static int msm_fbdev_fb_dirty(struct drm_fb_helper *helper, + struct drm_clip_rect *clip) +{ + struct drm_device *dev = helper->dev; + int ret; + + /* Call damage handlers only if necessary */ + if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2)) + return 0; + + if (helper->fb->funcs->dirty) { + ret = helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1); + if (drm_WARN_ONCE(dev, ret, "Dirty helper failed: ret=%d\n", ret)) + return ret; + } + + return 0; +} + +static const struct drm_fb_helper_funcs msm_fbdev_helper_funcs = { + .fb_dirty = msm_fbdev_fb_dirty, +}; + +int msm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { struct drm_device *dev = helper->dev; struct msm_drm_private *priv = dev->dev_private; @@ -114,6 +137,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, DBG("fbi=%p, dev=%p", fbi, dev); + helper->funcs = &msm_fbdev_helper_funcs; helper->fb = fb; fbi->fbops = &msm_fb_ops; @@ -138,119 +162,3 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, drm_framebuffer_remove(fb); return ret; } - -static int msm_fbdev_fb_dirty(struct drm_fb_helper *helper, - struct drm_clip_rect *clip) -{ - struct drm_device *dev = helper->dev; - int ret; - - /* Call damage handlers only if necessary */ - if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2)) - return 0; - - if (helper->fb->funcs->dirty) { - ret = helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1); - if (drm_WARN_ONCE(dev, ret, "Dirty helper failed: ret=%d\n", ret)) - return ret; - } - - return 0; -} - -static const struct drm_fb_helper_funcs msm_fb_helper_funcs = { - .fb_probe = msm_fbdev_create, - .fb_dirty = msm_fbdev_fb_dirty, -}; - -/* - * struct drm_client - */ - -static void msm_fbdev_client_unregister(struct drm_client_dev *client) -{ - struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); - - if (fb_helper->info) { - drm_fb_helper_unregister_info(fb_helper); - } else { - drm_client_release(&fb_helper->client); - drm_fb_helper_unprepare(fb_helper); - kfree(fb_helper); - } -} - -static int msm_fbdev_client_restore(struct drm_client_dev *client) -{ - drm_fb_helper_lastclose(client->dev); - - return 0; -} - -static int msm_fbdev_client_hotplug(struct drm_client_dev *client) -{ - struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client); - struct drm_device *dev = client->dev; - int ret; - - if (dev->fb_helper) - return drm_fb_helper_hotplug_event(dev->fb_helper); - - ret = drm_fb_helper_init(dev, fb_helper); - if (ret) - goto err_drm_err; - - if (!drm_drv_uses_atomic_modeset(dev)) - drm_helper_disable_unused_functions(dev); - - ret = drm_fb_helper_initial_config(fb_helper); - if (ret) - goto err_drm_fb_helper_fini; - - return 0; - -err_drm_fb_helper_fini: - drm_fb_helper_fini(fb_helper); -err_drm_err: - drm_err(dev, "Failed to setup fbdev emulation (ret=%d)\n", ret); - return ret; -} - -static const struct drm_client_funcs msm_fbdev_client_funcs = { - .owner = THIS_MODULE, - .unregister = msm_fbdev_client_unregister, - .restore = msm_fbdev_client_restore, - .hotplug = msm_fbdev_client_hotplug, -}; - -/* initialize fbdev helper */ -void msm_fbdev_setup(struct drm_device *dev) -{ - struct drm_fb_helper *helper; - int ret; - - if (!fbdev) - return; - - drm_WARN(dev, !dev->registered, "Device has not been registered.\n"); - drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n"); - - helper = kzalloc(sizeof(*helper), GFP_KERNEL); - if (!helper) - return; - drm_fb_helper_prepare(dev, helper, 32, &msm_fb_helper_funcs); - - ret = drm_client_init(dev, &helper->client, "fbdev", &msm_fbdev_client_funcs); - if (ret) { - drm_err(dev, "Failed to register client: %d\n", ret); - goto err_drm_fb_helper_unprepare; - } - - drm_client_register(&helper->client); - - return; - -err_drm_fb_helper_unprepare: - drm_fb_helper_unprepare(helper); - kfree(helper); -} diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index a274b846642374..0d4a3744cfcbd2 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -783,7 +783,7 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) mutex_unlock(&gpu->active_lock); gpu->funcs->submit(gpu, submit); - gpu->cur_ctx_seqno = submit->queue->ctx->seqno; + submit->ring->cur_ctx_seqno = submit->queue->ctx->seqno; pm_runtime_put(&gpu->pdev->dev); hangcheck_timer_reset(gpu); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 1f02bb9956be27..7cabc8480d7c54 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -193,17 +193,6 @@ struct msm_gpu { */ refcount_t sysprof_active; - /** - * cur_ctx_seqno: - * - * The ctx->seqno value of the last context to submit rendering, - * and the one with current pgtables installed (for generations - * that support per-context pgtables). Tracked by seqno rather - * than pointer value to avoid dangling pointers, and cases where - * a ctx can be freed and a new one created with the same address. - */ - int cur_ctx_seqno; - /** * lock: * diff --git a/drivers/gpu/drm/msm/msm_gpu_devfreq.c b/drivers/gpu/drm/msm/msm_gpu_devfreq.c index ea70c1c32d9401..6970b0f7f457c8 100644 --- a/drivers/gpu/drm/msm/msm_gpu_devfreq.c +++ b/drivers/gpu/drm/msm/msm_gpu_devfreq.c @@ -140,6 +140,7 @@ void msm_devfreq_init(struct msm_gpu *gpu) { struct msm_gpu_devfreq *df = &gpu->devfreq; struct msm_drm_private *priv = gpu->dev->dev_private; + int ret; /* We need target support to do devfreq */ if (!gpu->funcs->gpu_busy) @@ -156,8 +157,12 @@ void msm_devfreq_init(struct msm_gpu *gpu) mutex_init(&df->lock); - dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq, - DEV_PM_QOS_MIN_FREQUENCY, 0); + ret = dev_pm_qos_add_request(&gpu->pdev->dev, &df->boost_freq, + DEV_PM_QOS_MIN_FREQUENCY, 0); + if (ret < 0) { + DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize QoS\n"); + return; + } msm_devfreq_profile.initial_freq = gpu->fast_rate; diff --git a/drivers/gpu/drm/msm/msm_gpu_trace.h b/drivers/gpu/drm/msm/msm_gpu_trace.h index ac40d857bc4578..7f863282db0d78 100644 --- a/drivers/gpu/drm/msm/msm_gpu_trace.h +++ b/drivers/gpu/drm/msm/msm_gpu_trace.h @@ -177,6 +177,34 @@ TRACE_EVENT(msm_gpu_resume, TP_printk("%u", __entry->dummy) ); +TRACE_EVENT(msm_gpu_preemption_trigger, + TP_PROTO(int ring_id_from, int ring_id_to), + TP_ARGS(ring_id_from, ring_id_to), + TP_STRUCT__entry( + __field(int, ring_id_from) + __field(int, ring_id_to) + ), + TP_fast_assign( + __entry->ring_id_from = ring_id_from; + __entry->ring_id_to = ring_id_to; + ), + TP_printk("preempting %u -> %u", + __entry->ring_id_from, + __entry->ring_id_to) +); + +TRACE_EVENT(msm_gpu_preemption_irq, + TP_PROTO(u32 ring_id), + TP_ARGS(ring_id), + TP_STRUCT__entry( + __field(u32, ring_id) + ), + TP_fast_assign( + __entry->ring_id = ring_id; + ), + TP_printk("preempted to %u", __entry->ring_id) +); + #endif #undef TRACE_INCLUDE_PATH diff --git a/drivers/gpu/drm/msm/msm_kms.c b/drivers/gpu/drm/msm/msm_kms.c index af6a6fcb11736f..f3326d09bdbce1 100644 --- a/drivers/gpu/drm/msm/msm_kms.c +++ b/drivers/gpu/drm/msm/msm_kms.c @@ -5,11 +5,11 @@ * Author: Rob Clark */ +#include #include #include #include -#include #include #include #include @@ -237,7 +237,7 @@ int msm_drm_kms_init(struct device *dev, const struct drm_driver *drv) int ret; /* the fw fb could be anywhere in memory */ - ret = drm_aperture_remove_framebuffers(drv); + ret = aperture_remove_all_conflicting_devices(drv->name); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 1e0c54de3716ca..e60162744c6697 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -92,12 +92,6 @@ struct msm_kms_funcs { * Format handling: */ - /* do format checking on format modified through fb_cmd2 modifiers */ - int (*check_modified_format)(const struct msm_kms *kms, - const struct msm_format *msm_fmt, - const struct drm_mode_fb_cmd2 *cmd, - struct drm_gem_object **bos); - /* misc: */ long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index faa88fd6eb4d6a..76b6ae35a3cb5d 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -19,13 +19,7 @@ #include "msm_mdss.h" #include "msm_kms.h" -#define HW_REV 0x0 -#define HW_INTR_STATUS 0x0010 - -#define UBWC_DEC_HW_VERSION 0x58 -#define UBWC_STATIC 0x144 -#define UBWC_CTRL_2 0x150 -#define UBWC_PREDICTION_MODE 0x154 +#include #define MIN_IB_BW 400000000UL /* Min ib vote 400MB */ @@ -83,7 +77,7 @@ static void msm_mdss_irq(struct irq_desc *desc) chained_irq_enter(chip, desc); - interrupts = readl_relaxed(msm_mdss->mmio + HW_INTR_STATUS); + interrupts = readl_relaxed(msm_mdss->mmio + REG_MDSS_HW_INTR_STATUS); while (interrupts) { irq_hw_number_t hwirq = fls(interrupts) - 1; @@ -173,7 +167,7 @@ static void msm_mdss_setup_ubwc_dec_20(struct msm_mdss *msm_mdss) { const struct msm_mdss_data *data = msm_mdss->mdss_data; - writel_relaxed(data->ubwc_static, msm_mdss->mmio + UBWC_STATIC); + writel_relaxed(data->ubwc_static, msm_mdss->mmio + REG_MDSS_UBWC_STATIC); } static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss) @@ -189,7 +183,7 @@ static void msm_mdss_setup_ubwc_dec_30(struct msm_mdss *msm_mdss) if (data->ubwc_enc_version == UBWC_1_0) value |= BIT(8); - writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); + writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC); } static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss) @@ -200,21 +194,22 @@ static void msm_mdss_setup_ubwc_dec_40(struct msm_mdss *msm_mdss) (data->highest_bank_bit & 0x7) << 4 | (data->macrotile_mode & 0x1) << 12; - writel_relaxed(value, msm_mdss->mmio + UBWC_STATIC); + writel_relaxed(value, msm_mdss->mmio + REG_MDSS_UBWC_STATIC); if (data->ubwc_enc_version == UBWC_3_0) { - writel_relaxed(1, msm_mdss->mmio + UBWC_CTRL_2); - writel_relaxed(0, msm_mdss->mmio + UBWC_PREDICTION_MODE); + writel_relaxed(1, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2); + writel_relaxed(0, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE); } else { if (data->ubwc_dec_version == UBWC_4_3) - writel_relaxed(3, msm_mdss->mmio + UBWC_CTRL_2); + writel_relaxed(3, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2); else - writel_relaxed(2, msm_mdss->mmio + UBWC_CTRL_2); - writel_relaxed(1, msm_mdss->mmio + UBWC_PREDICTION_MODE); + writel_relaxed(2, msm_mdss->mmio + REG_MDSS_UBWC_CTRL_2); + writel_relaxed(1, msm_mdss->mmio + REG_MDSS_UBWC_PREDICTION_MODE); } } -#define MDSS_HW_MAJ_MIN GENMASK(31, 16) +#define MDSS_HW_MAJ_MIN \ + (MDSS_HW_VERSION_MAJOR__MASK | MDSS_HW_VERSION_MINOR__MASK) #define MDSS_HW_MSM8996 0x1007 #define MDSS_HW_MSM8937 0x100e @@ -235,7 +230,7 @@ static const struct msm_mdss_data *msm_mdss_generate_mdp5_mdss_data(struct msm_m if (!data) return NULL; - hw_rev = readl_relaxed(mdss->mmio + HW_REV); + hw_rev = readl_relaxed(mdss->mmio + REG_MDSS_HW_VERSION); hw_rev = FIELD_GET(MDSS_HW_MAJ_MIN, hw_rev); if (hw_rev == MDSS_HW_MSM8996 || @@ -334,9 +329,9 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss) dev_err(msm_mdss->dev, "Unsupported UBWC decoder version %x\n", msm_mdss->mdss_data->ubwc_dec_version); dev_err(msm_mdss->dev, "HW_REV: 0x%x\n", - readl_relaxed(msm_mdss->mmio + HW_REV)); + readl_relaxed(msm_mdss->mmio + REG_MDSS_HW_VERSION)); dev_err(msm_mdss->dev, "UBWC_DEC_HW_VERSION: 0x%x\n", - readl_relaxed(msm_mdss->mmio + UBWC_DEC_HW_VERSION)); + readl_relaxed(msm_mdss->mmio + REG_MDSS_UBWC_DEC_HW_VERSION)); break; } @@ -573,6 +568,16 @@ static const struct msm_mdss_data qcm2290_data = { .reg_bus_bw = 76800, }; +static const struct msm_mdss_data sa8775p_data = { + .ubwc_enc_version = UBWC_4_0, + .ubwc_dec_version = UBWC_4_0, + .ubwc_swizzle = 4, + .ubwc_static = 1, + .highest_bank_bit = 0, + .macrotile_mode = 1, + .reg_bus_bw = 74000, +}; + static const struct msm_mdss_data sc7180_data = { .ubwc_enc_version = UBWC_2_0, .ubwc_dec_version = UBWC_2_0, @@ -710,6 +715,7 @@ static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,mdss" }, { .compatible = "qcom,msm8998-mdss", .data = &msm8998_data }, { .compatible = "qcom,qcm2290-mdss", .data = &qcm2290_data }, + { .compatible = "qcom,sa8775p-mdss", .data = &sa8775p_data }, { .compatible = "qcom,sdm670-mdss", .data = &sdm670_data }, { .compatible = "qcom,sdm845-mdss", .data = &sdm845_data }, { .compatible = "qcom,sc7180-mdss", .data = &sc7180_data }, @@ -734,7 +740,7 @@ MODULE_DEVICE_TABLE(of, mdss_dt_match); static struct platform_driver mdss_platform_driver = { .probe = mdss_probe, - .remove_new = mdss_remove, + .remove = mdss_remove, .driver = { .name = "msm-mdss", .of_match_table = mdss_dt_match, diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 9d6655f96f0ceb..c803556a8f64c7 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -64,7 +64,7 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id, char name[32]; int ret; - /* We assume everwhere that MSM_GPU_RINGBUFFER_SZ is a power of 2 */ + /* We assume everywhere that MSM_GPU_RINGBUFFER_SZ is a power of 2 */ BUILD_BUG_ON(!is_power_of_2(MSM_GPU_RINGBUFFER_SZ)); ring = kzalloc(sizeof(*ring), GFP_KERNEL); diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h index 0d6beb8cd39a7b..d1e49f701c8176 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.h +++ b/drivers/gpu/drm/msm/msm_ringbuffer.h @@ -31,10 +31,12 @@ struct msm_rbmemptrs { volatile uint32_t rptr; volatile uint32_t fence; /* Introduced on A7xx */ + volatile uint32_t bv_rptr; volatile uint32_t bv_fence; volatile struct msm_gpu_submit_stats stats[MSM_GPU_SUBMIT_STATS_COUNT]; volatile u64 ttbr0; + volatile u32 context_idr; }; struct msm_cp_state { @@ -99,6 +101,22 @@ struct msm_ringbuffer { * preemption. Can be aquired from irq context. */ spinlock_t preempt_lock; + + /* + * Whether we skipped writing wptr and it needs to be updated in the + * future when the ring becomes current. + */ + bool restore_wptr; + + /** + * cur_ctx_seqno: + * + * The ctx->seqno value of the last context to submit to this ring + * Tracked by seqno rather than pointer value to avoid dangling + * pointers, and cases where a ctx can be freed and a new one created + * with the same address. + */ + int cur_ctx_seqno; }; struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id, diff --git a/drivers/gpu/drm/msm/msm_submitqueue.c b/drivers/gpu/drm/msm/msm_submitqueue.c index 0e803125a325aa..2fc3eaf81f4461 100644 --- a/drivers/gpu/drm/msm/msm_submitqueue.c +++ b/drivers/gpu/drm/msm/msm_submitqueue.c @@ -161,6 +161,8 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx, struct msm_drm_private *priv = drm->dev_private; struct msm_gpu_submitqueue *queue; enum drm_sched_priority sched_prio; + extern int enable_preemption; + bool preemption_supported; unsigned ring_nr; int ret; @@ -170,6 +172,11 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_file_private *ctx, if (!priv->gpu) return -ENODEV; + preemption_supported = priv->gpu->nr_rings == 1 && enable_preemption != 0; + + if (flags & MSM_SUBMITQUEUE_ALLOW_PREEMPT && preemption_supported) + return -EINVAL; + ret = msm_gpu_convert_priority(priv->gpu, prio, &ring_nr, &sched_prio); if (ret) return ret; diff --git a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml index 97608603ea62d4..2db425abf0f3cc 100644 --- a/drivers/gpu/drm/msm/registers/adreno/a6xx.xml +++ b/drivers/gpu/drm/msm/registers/adreno/a6xx.xml @@ -2358,7 +2358,12 @@ to upconvert to 32b float internally? - + + + + + + diff --git a/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml b/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml index cab01af55d2226..55a35182858cca 100644 --- a/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml +++ b/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml @@ -581,8 +581,7 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd"> and forcibly switch to the indicated context. - - + alloc A: GuC input capture regs lists (registered to GuC via ADS). + * xe_guc_ads acquires the register lists by calling + * xe_guc_capture_getlistsize and xe_guc_capture_getlist 'n' times, + * where n = 1 for global-reg-list + + * num_engine_classes for class-reg-list + + * num_engine_classes for instance-reg-list + * (since all instances of the same engine-class type + * have an identical engine-instance register-list). + * ADS module also calls separately for PF vs VF. + * + * --> alloc B: GuC output capture buf (registered via guc_init_params(log_param)) + * Size = #define CAPTURE_BUFFER_SIZE (warns if on too-small) + * Note2: 'x 3' to hold multiple capture groups + * + * GUC Runtime notify capture: + * -------------------------- + * --> G2H STATE_CAPTURE_NOTIFICATION + * L--> xe_guc_capture_process + * L--> Loop through B (head..tail) and for each engine instance's + * err-state-captured register-list we find, we alloc 'C': + * --> alloc C: A capture-output-node structure that includes misc capture info along + * with 3 register list dumps (global, engine-class and engine-instance) + * This node is created from a pre-allocated list of blank nodes in + * guc->capture->cachelist and populated with the error-capture + * data from GuC and then it's added into guc->capture->outlist linked + * list. This list is used for matchup and printout by xe_devcoredump_read + * and xe_engine_snapshot_print, (when user invokes the devcoredump sysfs). + * + * GUC --> notify context reset: + * ----------------------------- + * --> guc_exec_queue_timedout_job + * L--> xe_devcoredump + * L--> devcoredump_snapshot + * --> xe_hw_engine_snapshot_capture + * --> xe_engine_manual_capture(For manual capture) + * + * User Sysfs / Debugfs + * -------------------- + * --> xe_devcoredump_read-> + * L--> xxx_snapshot_print + * L--> xe_engine_snapshot_print + * Print register lists values saved at + * guc->capture->outlist + * + */ + +static int guc_capture_buf_cnt(struct __guc_capture_bufstate *buf) +{ + if (buf->wr >= buf->rd) + return (buf->wr - buf->rd); + return (buf->size - buf->rd) + buf->wr; +} + +static int guc_capture_buf_cnt_to_end(struct __guc_capture_bufstate *buf) +{ + if (buf->rd > buf->wr) + return (buf->size - buf->rd); + return (buf->wr - buf->rd); +} + +/* + * GuC's error-capture output is a ring buffer populated in a byte-stream fashion: + * + * The GuC Log buffer region for error-capture is managed like a ring buffer. + * The GuC firmware dumps error capture logs into this ring in a byte-stream flow. + * Additionally, as per the current and foreseeable future, all packed error- + * capture output structures are dword aligned. + * + * That said, if the GuC firmware is in the midst of writing a structure that is larger + * than one dword but the tail end of the err-capture buffer-region has lesser space left, + * we would need to extract that structure one dword at a time straddled across the end, + * onto the start of the ring. + * + * Below function, guc_capture_log_remove_bytes is a helper for that. All callers of this + * function would typically do a straight-up memcpy from the ring contents and will only + * call this helper if their structure-extraction is straddling across the end of the + * ring. GuC firmware does not add any padding. The reason for the no-padding is to ease + * scalability for future expansion of output data types without requiring a redesign + * of the flow controls. + */ +static int +guc_capture_log_remove_bytes(struct xe_guc *guc, struct __guc_capture_bufstate *buf, + void *out, int bytes_needed) +{ +#define GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX 3 + + int fill_size = 0, tries = GUC_CAPTURE_LOG_BUF_COPY_RETRY_MAX; + int copy_size, avail; + + xe_assert(guc_to_xe(guc), bytes_needed % sizeof(u32) == 0); + + if (bytes_needed > guc_capture_buf_cnt(buf)) + return -1; + + while (bytes_needed > 0 && tries--) { + int misaligned; + + avail = guc_capture_buf_cnt_to_end(buf); + misaligned = avail % sizeof(u32); + /* wrap if at end */ + if (!avail) { + /* output stream clipped */ + if (!buf->rd) + return fill_size; + buf->rd = 0; + continue; + } + + /* Only copy to u32 aligned data */ + copy_size = avail < bytes_needed ? avail - misaligned : bytes_needed; + xe_map_memcpy_from(guc_to_xe(guc), out + fill_size, &guc->log.bo->vmap, + buf->data_offset + buf->rd, copy_size); + buf->rd += copy_size; + fill_size += copy_size; + bytes_needed -= copy_size; + + if (misaligned) + xe_gt_warn(guc_to_gt(guc), + "Bytes extraction not dword aligned, clipping.\n"); + } + + return fill_size; +} + +static int +guc_capture_log_get_group_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf, + struct guc_state_capture_group_header_t *ghdr) +{ + int fullsize = sizeof(struct guc_state_capture_group_header_t); + + if (guc_capture_log_remove_bytes(guc, buf, ghdr, fullsize) != fullsize) + return -1; + return 0; +} + +static int +guc_capture_log_get_data_hdr(struct xe_guc *guc, struct __guc_capture_bufstate *buf, + struct guc_state_capture_header_t *hdr) +{ + int fullsize = sizeof(struct guc_state_capture_header_t); + + if (guc_capture_log_remove_bytes(guc, buf, hdr, fullsize) != fullsize) + return -1; + return 0; +} + +static int +guc_capture_log_get_register(struct xe_guc *guc, struct __guc_capture_bufstate *buf, + struct guc_mmio_reg *reg) +{ + int fullsize = sizeof(struct guc_mmio_reg); + + if (guc_capture_log_remove_bytes(guc, buf, reg, fullsize) != fullsize) + return -1; + return 0; +} + +static struct __guc_capture_parsed_output * +guc_capture_get_prealloc_node(struct xe_guc *guc) +{ + struct __guc_capture_parsed_output *found = NULL; + + if (!list_empty(&guc->capture->cachelist)) { + struct __guc_capture_parsed_output *n, *ntmp; + + /* get first avail node from the cache list */ + list_for_each_entry_safe(n, ntmp, &guc->capture->cachelist, link) { + found = n; + break; + } + } else { + struct __guc_capture_parsed_output *n, *ntmp; + + /* + * traverse reversed and steal back the oldest node already + * allocated + */ + list_for_each_entry_safe_reverse(n, ntmp, &guc->capture->outlist, link) { + if (!n->locked) + found = n; + } + } + if (found) { + list_del(&found->link); + guc_capture_init_node(guc, found); + } + + return found; +} + +static struct __guc_capture_parsed_output * +guc_capture_clone_node(struct xe_guc *guc, struct __guc_capture_parsed_output *original, + u32 keep_reglist_mask) +{ + struct __guc_capture_parsed_output *new; + int i; + + new = guc_capture_get_prealloc_node(guc); + if (!new) + return NULL; + if (!original) + return new; + + new->is_partial = original->is_partial; + + /* copy reg-lists that we want to clone */ + for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) { + if (keep_reglist_mask & BIT(i)) { + XE_WARN_ON(original->reginfo[i].num_regs > + guc->capture->max_mmio_per_node); + + memcpy(new->reginfo[i].regs, original->reginfo[i].regs, + original->reginfo[i].num_regs * sizeof(struct guc_mmio_reg)); + + new->reginfo[i].num_regs = original->reginfo[i].num_regs; + new->reginfo[i].vfid = original->reginfo[i].vfid; + + if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS) { + new->eng_class = original->eng_class; + } else if (i == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) { + new->eng_inst = original->eng_inst; + new->guc_id = original->guc_id; + new->lrca = original->lrca; + } + } + } + + return new; +} + +static int +guc_capture_extract_reglists(struct xe_guc *guc, struct __guc_capture_bufstate *buf) +{ + struct xe_gt *gt = guc_to_gt(guc); + struct guc_state_capture_group_header_t ghdr = {0}; + struct guc_state_capture_header_t hdr = {0}; + struct __guc_capture_parsed_output *node = NULL; + struct guc_mmio_reg *regs = NULL; + int i, numlists, numregs, ret = 0; + enum guc_state_capture_type datatype; + struct guc_mmio_reg tmp; + bool is_partial = false; + + i = guc_capture_buf_cnt(buf); + if (!i) + return -ENODATA; + + if (i % sizeof(u32)) { + xe_gt_warn(gt, "Got mis-aligned register capture entries\n"); + ret = -EIO; + goto bailout; + } + + /* first get the capture group header */ + if (guc_capture_log_get_group_hdr(guc, buf, &ghdr)) { + ret = -EIO; + goto bailout; + } + /* + * we would typically expect a layout as below where n would be expected to be + * anywhere between 3 to n where n > 3 if we are seeing multiple dependent engine + * instances being reset together. + * ____________________________________________ + * | Capture Group | + * | ________________________________________ | + * | | Capture Group Header: | | + * | | - num_captures = 5 | | + * | |______________________________________| | + * | ________________________________________ | + * | | Capture1: | | + * | | Hdr: GLOBAL, numregs=a | | + * | | ____________________________________ | | + * | | | Reglist | | | + * | | | - reg1, reg2, ... rega | | | + * | | |__________________________________| | | + * | |______________________________________| | + * | ________________________________________ | + * | | Capture2: | | + * | | Hdr: CLASS=RENDER/COMPUTE, numregs=b| | + * | | ____________________________________ | | + * | | | Reglist | | | + * | | | - reg1, reg2, ... regb | | | + * | | |__________________________________| | | + * | |______________________________________| | + * | ________________________________________ | + * | | Capture3: | | + * | | Hdr: INSTANCE=RCS, numregs=c | | + * | | ____________________________________ | | + * | | | Reglist | | | + * | | | - reg1, reg2, ... regc | | | + * | | |__________________________________| | | + * | |______________________________________| | + * | ________________________________________ | + * | | Capture4: | | + * | | Hdr: CLASS=RENDER/COMPUTE, numregs=d| | + * | | ____________________________________ | | + * | | | Reglist | | | + * | | | - reg1, reg2, ... regd | | | + * | | |__________________________________| | | + * | |______________________________________| | + * | ________________________________________ | + * | | Capture5: | | + * | | Hdr: INSTANCE=CCS0, numregs=e | | + * | | ____________________________________ | | + * | | | Reglist | | | + * | | | - reg1, reg2, ... rege | | | + * | | |__________________________________| | | + * | |______________________________________| | + * |__________________________________________| + */ + is_partial = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_CAPTURE_GROUP_TYPE, ghdr.info); + numlists = FIELD_GET(GUC_STATE_CAPTURE_GROUP_HEADER_NUM_CAPTURES, ghdr.info); + + while (numlists--) { + if (guc_capture_log_get_data_hdr(guc, buf, &hdr)) { + ret = -EIO; + break; + } + + datatype = FIELD_GET(GUC_STATE_CAPTURE_HEADER_CAPTURE_TYPE, hdr.info); + if (datatype > GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) { + /* unknown capture type - skip over to next capture set */ + numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES, + hdr.num_mmio_entries); + while (numregs--) { + if (guc_capture_log_get_register(guc, buf, &tmp)) { + ret = -EIO; + break; + } + } + continue; + } else if (node) { + /* + * Based on the current capture type and what we have so far, + * decide if we should add the current node into the internal + * linked list for match-up when xe_devcoredump calls later + * (and alloc a blank node for the next set of reglists) + * or continue with the same node or clone the current node + * but only retain the global or class registers (such as the + * case of dependent engine resets). + */ + if (datatype == GUC_STATE_CAPTURE_TYPE_GLOBAL) { + guc_capture_add_node_to_outlist(guc->capture, node); + node = NULL; + } else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS && + node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS].num_regs) { + /* Add to list, clone node and duplicate global list */ + guc_capture_add_node_to_outlist(guc->capture, node); + node = guc_capture_clone_node(guc, node, + GCAP_PARSED_REGLIST_INDEX_GLOBAL); + } else if (datatype == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE && + node->reginfo[GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE].num_regs) { + /* Add to list, clone node and duplicate global + class lists */ + guc_capture_add_node_to_outlist(guc->capture, node); + node = guc_capture_clone_node(guc, node, + (GCAP_PARSED_REGLIST_INDEX_GLOBAL | + GCAP_PARSED_REGLIST_INDEX_ENGCLASS)); + } + } + + if (!node) { + node = guc_capture_get_prealloc_node(guc); + if (!node) { + ret = -ENOMEM; + break; + } + if (datatype != GUC_STATE_CAPTURE_TYPE_GLOBAL) + xe_gt_dbg(gt, "Register capture missing global dump: %08x!\n", + datatype); + } + node->is_partial = is_partial; + node->reginfo[datatype].vfid = FIELD_GET(GUC_STATE_CAPTURE_HEADER_VFID, hdr.owner); + node->source = XE_ENGINE_CAPTURE_SOURCE_GUC; + node->type = datatype; + + switch (datatype) { + case GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE: + node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS, + hdr.info); + node->eng_inst = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_INSTANCE, + hdr.info); + node->lrca = hdr.lrca; + node->guc_id = hdr.guc_id; + break; + case GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS: + node->eng_class = FIELD_GET(GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS, + hdr.info); + break; + default: + break; + } + + numregs = FIELD_GET(GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES, + hdr.num_mmio_entries); + if (numregs > guc->capture->max_mmio_per_node) { + xe_gt_dbg(gt, "Register capture list extraction clipped by prealloc!\n"); + numregs = guc->capture->max_mmio_per_node; + } + node->reginfo[datatype].num_regs = numregs; + regs = node->reginfo[datatype].regs; + i = 0; + while (numregs--) { + if (guc_capture_log_get_register(guc, buf, ®s[i++])) { + ret = -EIO; + break; + } + } + } + +bailout: + if (node) { + /* If we have data, add to linked list for match-up when xe_devcoredump calls */ + for (i = GUC_STATE_CAPTURE_TYPE_GLOBAL; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) { + if (node->reginfo[i].regs) { + guc_capture_add_node_to_outlist(guc->capture, node); + node = NULL; + break; + } + } + if (node) /* else return it back to cache list */ + guc_capture_add_node_to_cachelist(guc->capture, node); + } + return ret; +} + +static int __guc_capture_flushlog_complete(struct xe_guc *guc) +{ + u32 action[] = { + XE_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE, + GUC_LOG_BUFFER_CAPTURE + }; + + return xe_guc_ct_send_g2h_handler(&guc->ct, action, ARRAY_SIZE(action)); +} + +static void __guc_capture_process_output(struct xe_guc *guc) +{ + unsigned int buffer_size, read_offset, write_offset, full_count; + struct xe_uc *uc = container_of(guc, typeof(*uc), guc); + struct guc_log_buffer_state log_buf_state_local; + struct __guc_capture_bufstate buf; + bool new_overflow; + int ret, tmp; + u32 log_buf_state_offset; + u32 src_data_offset; + + log_buf_state_offset = sizeof(struct guc_log_buffer_state) * GUC_LOG_BUFFER_CAPTURE; + src_data_offset = xe_guc_get_log_buffer_offset(&guc->log, GUC_LOG_BUFFER_CAPTURE); + + /* + * Make a copy of the state structure, inside GuC log buffer + * (which is uncached mapped), on the stack to avoid reading + * from it multiple times. + */ + xe_map_memcpy_from(guc_to_xe(guc), &log_buf_state_local, &guc->log.bo->vmap, + log_buf_state_offset, sizeof(struct guc_log_buffer_state)); + + buffer_size = xe_guc_get_log_buffer_size(&guc->log, GUC_LOG_BUFFER_CAPTURE); + read_offset = log_buf_state_local.read_ptr; + write_offset = log_buf_state_local.sampled_write_ptr; + full_count = FIELD_GET(GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT, log_buf_state_local.flags); + + /* Bookkeeping stuff */ + tmp = FIELD_GET(GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE, log_buf_state_local.flags); + guc->log.stats[GUC_LOG_BUFFER_CAPTURE].flush += tmp; + new_overflow = xe_guc_check_log_buf_overflow(&guc->log, GUC_LOG_BUFFER_CAPTURE, + full_count); + + /* Now copy the actual logs. */ + if (unlikely(new_overflow)) { + /* copy the whole buffer in case of overflow */ + read_offset = 0; + write_offset = buffer_size; + } else if (unlikely((read_offset > buffer_size) || + (write_offset > buffer_size))) { + xe_gt_err(guc_to_gt(guc), + "Register capture buffer in invalid state: read = 0x%X, size = 0x%X!\n", + read_offset, buffer_size); + /* copy whole buffer as offsets are unreliable */ + read_offset = 0; + write_offset = buffer_size; + } + + buf.size = buffer_size; + buf.rd = read_offset; + buf.wr = write_offset; + buf.data_offset = src_data_offset; + + if (!xe_guc_read_stopped(guc)) { + do { + ret = guc_capture_extract_reglists(guc, &buf); + if (ret && ret != -ENODATA) + xe_gt_dbg(guc_to_gt(guc), "Capture extraction failed:%d\n", ret); + } while (ret >= 0); + } + + /* Update the state of log buffer err-cap state */ + xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap, + log_buf_state_offset + offsetof(struct guc_log_buffer_state, read_ptr), u32, + write_offset); + + /* + * Clear the flush_to_file from local first, the local was loaded by above + * xe_map_memcpy_from, then write out the "updated local" through + * xe_map_wr() + */ + log_buf_state_local.flags &= ~GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE; + xe_map_wr(guc_to_xe(guc), &guc->log.bo->vmap, + log_buf_state_offset + offsetof(struct guc_log_buffer_state, flags), u32, + log_buf_state_local.flags); + __guc_capture_flushlog_complete(guc); +} + +/* + * xe_guc_capture_process - Process GuC register captured data + * @guc: The GuC object + * + * When GuC captured data is ready, GuC will send message + * XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION to host, this function will be + * called to process the data comes with the message. + * + * Returns: None + */ +void xe_guc_capture_process(struct xe_guc *guc) +{ + if (guc->capture) + __guc_capture_process_output(guc); +} + +static struct __guc_capture_parsed_output * +guc_capture_alloc_one_node(struct xe_guc *guc) +{ + struct drm_device *drm = guc_to_drm(guc); + struct __guc_capture_parsed_output *new; + int i; + + new = drmm_kzalloc(drm, sizeof(*new), GFP_KERNEL); + if (!new) + return NULL; + + for (i = 0; i < GUC_STATE_CAPTURE_TYPE_MAX; ++i) { + new->reginfo[i].regs = drmm_kzalloc(drm, guc->capture->max_mmio_per_node * + sizeof(struct guc_mmio_reg), GFP_KERNEL); + if (!new->reginfo[i].regs) { + while (i) + drmm_kfree(drm, new->reginfo[--i].regs); + drmm_kfree(drm, new); + return NULL; + } + } + guc_capture_init_node(guc, new); + + return new; +} + +static void +__guc_capture_create_prealloc_nodes(struct xe_guc *guc) +{ + struct __guc_capture_parsed_output *node = NULL; + int i; + + for (i = 0; i < PREALLOC_NODES_MAX_COUNT; ++i) { + node = guc_capture_alloc_one_node(guc); + if (!node) { + xe_gt_warn(guc_to_gt(guc), "Register capture pre-alloc-cache failure\n"); + /* dont free the priors, use what we got and cleanup at shutdown */ + return; + } + guc_capture_add_node_to_cachelist(guc->capture, node); + } +} + +static int +guc_get_max_reglist_count(struct xe_guc *guc) +{ + int i, j, k, tmp, maxregcount = 0; + + for (i = 0; i < GUC_CAPTURE_LIST_INDEX_MAX; ++i) { + for (j = 0; j < GUC_STATE_CAPTURE_TYPE_MAX; ++j) { + for (k = 0; k < GUC_CAPTURE_LIST_CLASS_MAX; ++k) { + const struct __guc_mmio_reg_descr_group *match; + + if (j == GUC_STATE_CAPTURE_TYPE_GLOBAL && k > 0) + continue; + + tmp = 0; + match = guc_capture_get_one_list(guc->capture->reglists, i, j, k); + if (match) + tmp = match->num_regs; + + match = guc_capture_get_one_list(guc->capture->extlists, i, j, k); + if (match) + tmp += match->num_regs; + + if (tmp > maxregcount) + maxregcount = tmp; + } + } + } + if (!maxregcount) + maxregcount = PREALLOC_NODES_DEFAULT_NUMREGS; + + return maxregcount; +} + +static void +guc_capture_create_prealloc_nodes(struct xe_guc *guc) +{ + /* skip if we've already done the pre-alloc */ + if (guc->capture->max_mmio_per_node) + return; + + guc->capture->max_mmio_per_node = guc_get_max_reglist_count(guc); + __guc_capture_create_prealloc_nodes(guc); +} + +static void +read_reg_to_node(struct xe_hw_engine *hwe, const struct __guc_mmio_reg_descr_group *list, + struct guc_mmio_reg *regs) +{ + int i; + + if (!list || !list->list || list->num_regs == 0) + return; + + if (!regs) + return; + + for (i = 0; i < list->num_regs; i++) { + struct __guc_mmio_reg_descr desc = list->list[i]; + u32 value; + + if (list->type == GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE) { + value = xe_hw_engine_mmio_read32(hwe, desc.reg); + } else { + if (list->type == GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS && + FIELD_GET(GUC_REGSET_STEERING_NEEDED, desc.flags)) { + int group, instance; + + group = FIELD_GET(GUC_REGSET_STEERING_GROUP, desc.flags); + instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, desc.flags); + value = xe_gt_mcr_unicast_read(hwe->gt, XE_REG_MCR(desc.reg.addr), + group, instance); + } else { + value = xe_mmio_read32(&hwe->gt->mmio, desc.reg); + } + } + + regs[i].value = value; + regs[i].offset = desc.reg.addr; + regs[i].flags = desc.flags; + regs[i].mask = desc.mask; + } +} + +/** + * xe_engine_manual_capture - Take a manual engine snapshot from engine. + * @hwe: Xe HW Engine. + * @snapshot: The engine snapshot + * + * Take engine snapshot from engine read. + * + * Returns: None + */ +void +xe_engine_manual_capture(struct xe_hw_engine *hwe, struct xe_hw_engine_snapshot *snapshot) +{ + struct xe_gt *gt = hwe->gt; + struct xe_device *xe = gt_to_xe(gt); + struct xe_guc *guc = >->uc.guc; + struct xe_devcoredump *devcoredump = &xe->devcoredump; + enum guc_capture_list_class_type capture_class; + const struct __guc_mmio_reg_descr_group *list; + struct __guc_capture_parsed_output *new; + enum guc_state_capture_type type; + u16 guc_id = 0; + u32 lrca = 0; + + if (IS_SRIOV_VF(xe)) + return; + + new = guc_capture_get_prealloc_node(guc); + if (!new) + return; + + capture_class = xe_engine_class_to_guc_capture_class(hwe->class); + for (type = GUC_STATE_CAPTURE_TYPE_GLOBAL; type < GUC_STATE_CAPTURE_TYPE_MAX; type++) { + struct gcap_reg_list_info *reginfo = &new->reginfo[type]; + /* + * regsinfo->regs is allocated based on guc->capture->max_mmio_per_node + * which is based on the descriptor list driving the population so + * should not overflow + */ + + /* Get register list for the type/class */ + list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF, type, + capture_class, false); + if (!list) { + xe_gt_dbg(gt, "Empty GuC capture register descriptor for %s", + hwe->name); + continue; + } + + read_reg_to_node(hwe, list, reginfo->regs); + reginfo->num_regs = list->num_regs; + + /* Capture steering registers for rcs/ccs */ + if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) { + list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF, + type, capture_class, true); + if (list) { + read_reg_to_node(hwe, list, ®info->regs[reginfo->num_regs]); + reginfo->num_regs += list->num_regs; + } + } + } + + if (devcoredump && devcoredump->captured) { + struct xe_guc_submit_exec_queue_snapshot *ge = devcoredump->snapshot.ge; + + if (ge) { + guc_id = ge->guc.id; + if (ge->lrc[0]) + lrca = ge->lrc[0]->context_desc; + } + } + + new->eng_class = xe_engine_class_to_guc_class(hwe->class); + new->eng_inst = hwe->instance; + new->guc_id = guc_id; + new->lrca = lrca; + new->is_partial = 0; + new->locked = 1; + new->source = XE_ENGINE_CAPTURE_SOURCE_MANUAL; + + guc_capture_add_node_to_outlist(guc->capture, new); + devcoredump->snapshot.matched_node = new; +} + +static struct guc_mmio_reg * +guc_capture_find_reg(struct gcap_reg_list_info *reginfo, u32 addr, u32 flags) +{ + int i; + + if (reginfo && reginfo->num_regs > 0) { + struct guc_mmio_reg *regs = reginfo->regs; + + if (regs) + for (i = 0; i < reginfo->num_regs; i++) + if (regs[i].offset == addr && regs[i].flags == flags) + return ®s[i]; + } + + return NULL; +} + +static void +snapshot_print_by_list_order(struct xe_hw_engine_snapshot *snapshot, struct drm_printer *p, + u32 type, const struct __guc_mmio_reg_descr_group *list) +{ + struct xe_gt *gt = snapshot->hwe->gt; + struct xe_device *xe = gt_to_xe(gt); + struct xe_guc *guc = >->uc.guc; + struct xe_devcoredump *devcoredump = &xe->devcoredump; + struct xe_devcoredump_snapshot *devcore_snapshot = &devcoredump->snapshot; + struct gcap_reg_list_info *reginfo = NULL; + u32 i, last_value = 0; + bool is_ext, low32_ready = false; + + if (!list || !list->list || list->num_regs == 0) + return; + XE_WARN_ON(!devcore_snapshot->matched_node); + + is_ext = list == guc->capture->extlists; + reginfo = &devcore_snapshot->matched_node->reginfo[type]; + + /* + * loop through descriptor first and find the register in the node + * this is more scalable for developer maintenance as it will ensure + * the printout matched the ordering of the static descriptor + * table-of-lists + */ + for (i = 0; i < list->num_regs; i++) { + const struct __guc_mmio_reg_descr *reg_desc = &list->list[i]; + struct guc_mmio_reg *reg; + u32 value; + + reg = guc_capture_find_reg(reginfo, reg_desc->reg.addr, reg_desc->flags); + if (!reg) + continue; + + value = reg->value; + switch (reg_desc->data_type) { + case REG_64BIT_LOW_DW: + last_value = value; + + /* + * A 64 bit register define requires 2 consecutive + * entries in register list, with low dword first + * and hi dword the second, like: + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, + * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, "XXX_REG"}, + * + * Incorrect order will trigger XE_WARN. + * + * Possible double low here, for example: + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, + */ + XE_WARN_ON(low32_ready); + low32_ready = true; + /* Low 32 bit dword saved, continue for high 32 bit */ + break; + + case REG_64BIT_HI_DW: { + u64 value_qw = ((u64)value << 32) | last_value; + + /* + * Incorrect 64bit register order. Possible missing low. + * for example: + * { XXX_REG(0), REG_32BIT, 0, 0, NULL}, + * { XXX_REG_HI(0), REG_64BIT_HI_DW, 0, 0, NULL}, + */ + XE_WARN_ON(!low32_ready); + low32_ready = false; + + drm_printf(p, "\t%s: 0x%016llx\n", reg_desc->regname, value_qw); + break; + } + + case REG_32BIT: + /* + * Incorrect 64bit register order. Possible missing high. + * for example: + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, + * { XXX_REG(0), REG_32BIT, 0, 0, "XXX_REG"}, + */ + XE_WARN_ON(low32_ready); + + if (is_ext) { + int dss, group, instance; + + group = FIELD_GET(GUC_REGSET_STEERING_GROUP, reg_desc->flags); + instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, reg_desc->flags); + dss = xe_gt_mcr_steering_info_to_dss_id(gt, group, instance); + + drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname, dss, value); + } else { + drm_printf(p, "\t%s: 0x%08x\n", reg_desc->regname, value); + } + break; + } + } + + /* + * Incorrect 64bit register order. Possible missing high. + * for example: + * { XXX_REG_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, + * } // <- Register list end + */ + XE_WARN_ON(low32_ready); +} + +/** + * xe_engine_snapshot_print - Print out a given Xe HW Engine snapshot. + * @snapshot: Xe HW Engine snapshot object. + * @p: drm_printer where it will be printed out. + * + * This function prints out a given Xe HW Engine snapshot object. + */ +void xe_engine_snapshot_print(struct xe_hw_engine_snapshot *snapshot, struct drm_printer *p) +{ + const char *grptype[GUC_STATE_CAPTURE_GROUP_TYPE_MAX] = { + "full-capture", + "partial-capture" + }; + int type; + const struct __guc_mmio_reg_descr_group *list; + enum guc_capture_list_class_type capture_class; + + struct xe_gt *gt; + struct xe_device *xe; + struct xe_devcoredump *devcoredump; + struct xe_devcoredump_snapshot *devcore_snapshot; + + if (!snapshot) + return; + + gt = snapshot->hwe->gt; + xe = gt_to_xe(gt); + devcoredump = &xe->devcoredump; + devcore_snapshot = &devcoredump->snapshot; + + if (!devcore_snapshot->matched_node) + return; + + xe_gt_assert(gt, snapshot->source <= XE_ENGINE_CAPTURE_SOURCE_GUC); + xe_gt_assert(gt, snapshot->hwe); + + capture_class = xe_engine_class_to_guc_capture_class(snapshot->hwe->class); + + drm_printf(p, "%s (physical), logical instance=%d\n", + snapshot->name ? snapshot->name : "", + snapshot->logical_instance); + drm_printf(p, "\tCapture_source: %s\n", + snapshot->source == XE_ENGINE_CAPTURE_SOURCE_GUC ? "GuC" : "Manual"); + drm_printf(p, "\tCoverage: %s\n", grptype[devcore_snapshot->matched_node->is_partial]); + drm_printf(p, "\tForcewake: domain 0x%x, ref %d\n", + snapshot->forcewake.domain, snapshot->forcewake.ref); + drm_printf(p, "\tReserved: %s\n", + str_yes_no(snapshot->kernel_reserved)); + + for (type = GUC_STATE_CAPTURE_TYPE_GLOBAL; type < GUC_STATE_CAPTURE_TYPE_MAX; type++) { + list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF, type, + capture_class, false); + snapshot_print_by_list_order(snapshot, p, type, list); + } + + if (capture_class == GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE) { + list = xe_guc_capture_get_reg_desc_list(gt, GUC_CAPTURE_LIST_INDEX_PF, + GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS, + capture_class, true); + snapshot_print_by_list_order(snapshot, p, GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS, + list); + } + + drm_puts(p, "\n"); +} + +/** + * xe_guc_capture_get_matching_and_lock - Matching GuC capture for the job. + * @job: The job object. + * + * Search within the capture outlist for the job, could be used for check if + * GuC capture is ready for the job. + * If found, the locked boolean of the node will be flagged. + * + * Returns: found guc-capture node ptr else NULL + */ +struct __guc_capture_parsed_output * +xe_guc_capture_get_matching_and_lock(struct xe_sched_job *job) +{ + struct xe_hw_engine *hwe; + enum xe_hw_engine_id id; + struct xe_exec_queue *q; + struct xe_device *xe; + u16 guc_class = GUC_LAST_ENGINE_CLASS + 1; + struct xe_devcoredump_snapshot *ss; + + if (!job) + return NULL; + + q = job->q; + if (!q || !q->gt) + return NULL; + + xe = gt_to_xe(q->gt); + if (xe->wedged.mode >= 2 || !xe_device_uc_enabled(xe) || IS_SRIOV_VF(xe)) + return NULL; + + ss = &xe->devcoredump.snapshot; + if (ss->matched_node && ss->matched_node->source == XE_ENGINE_CAPTURE_SOURCE_GUC) + return ss->matched_node; + + /* Find hwe for the job */ + for_each_hw_engine(hwe, q->gt, id) { + if (hwe != q->hwe) + continue; + guc_class = xe_engine_class_to_guc_class(hwe->class); + break; + } + + if (guc_class <= GUC_LAST_ENGINE_CLASS) { + struct __guc_capture_parsed_output *n, *ntmp; + struct xe_guc *guc = &q->gt->uc.guc; + u16 guc_id = q->guc->id; + u32 lrca = xe_lrc_ggtt_addr(q->lrc[0]); + + /* + * Look for a matching GuC reported error capture node from + * the internal output link-list based on engine, guc id and + * lrca info. + */ + list_for_each_entry_safe(n, ntmp, &guc->capture->outlist, link) { + if (n->eng_class == guc_class && n->eng_inst == hwe->instance && + n->guc_id == guc_id && n->lrca == lrca && + n->source == XE_ENGINE_CAPTURE_SOURCE_GUC) { + n->locked = 1; + return n; + } + } + } + return NULL; +} + +/** + * xe_engine_snapshot_capture_for_job - Take snapshot of associated engine + * @job: The job object + * + * Take snapshot of associated HW Engine + * + * Returns: None. + */ +void +xe_engine_snapshot_capture_for_job(struct xe_sched_job *job) +{ + struct xe_exec_queue *q = job->q; + struct xe_device *xe = gt_to_xe(q->gt); + struct xe_devcoredump *coredump = &xe->devcoredump; + struct xe_hw_engine *hwe; + enum xe_hw_engine_id id; + u32 adj_logical_mask = q->logical_mask; + + if (IS_SRIOV_VF(xe)) + return; + + for_each_hw_engine(hwe, q->gt, id) { + if (hwe->class != q->hwe->class || + !(BIT(hwe->logical_instance) & adj_logical_mask)) { + coredump->snapshot.hwe[id] = NULL; + continue; + } + + if (!coredump->snapshot.hwe[id]) { + coredump->snapshot.hwe[id] = xe_hw_engine_snapshot_capture(hwe, job); + } else { + struct __guc_capture_parsed_output *new; + + new = xe_guc_capture_get_matching_and_lock(job); + if (new) { + struct xe_guc *guc = &q->gt->uc.guc; + + /* + * If we are in here, it means we found a fresh + * GuC-err-capture node for this engine after + * previously failing to find a match in the + * early part of guc_exec_queue_timedout_job. + * Thus we must free the manually captured node + */ + guc_capture_free_outlist_node(guc->capture, + coredump->snapshot.matched_node); + coredump->snapshot.matched_node = new; + } + } + + break; + } +} + +/* + * xe_guc_capture_put_matched_nodes - Cleanup macthed nodes + * @guc: The GuC object + * + * Free matched node and all nodes with the equal guc_id from + * GuC captured outlist + */ +void xe_guc_capture_put_matched_nodes(struct xe_guc *guc) +{ + struct xe_device *xe = guc_to_xe(guc); + struct xe_devcoredump *devcoredump = &xe->devcoredump; + struct __guc_capture_parsed_output *n = devcoredump->snapshot.matched_node; + + if (n) { + guc_capture_remove_stale_matches_from_list(guc->capture, n); + guc_capture_free_outlist_node(guc->capture, n); + devcoredump->snapshot.matched_node = NULL; + } +} + +/* + * xe_guc_capture_steered_list_init - Init steering register list + * @guc: The GuC object + * + * Init steering register list for GuC register capture, create pre-alloc node + */ +void xe_guc_capture_steered_list_init(struct xe_guc *guc) +{ + /* + * For certain engine classes, there are slice and subslice + * level registers requiring steering. We allocate and populate + * these based on hw config and add it as an extension list at + * the end of the pre-populated render list. + */ + guc_capture_alloc_steered_lists(guc); + check_guc_capture_size(guc); + guc_capture_create_prealloc_nodes(guc); +} + +/* + * xe_guc_capture_init - Init for GuC register capture + * @guc: The GuC object + * + * Init for GuC register capture, alloc memory for capture data structure. + * + * Returns: 0 if success. + * -ENOMEM if out of memory + */ +int xe_guc_capture_init(struct xe_guc *guc) +{ + guc->capture = drmm_kzalloc(guc_to_drm(guc), sizeof(*guc->capture), GFP_KERNEL); + if (!guc->capture) + return -ENOMEM; + + guc->capture->reglists = guc_capture_get_device_reglist(guc_to_xe(guc)); + + INIT_LIST_HEAD(&guc->capture->outlist); + INIT_LIST_HEAD(&guc->capture->cachelist); + + return 0; +} diff --git a/drivers/gpu/drm/xe/xe_guc_capture.h b/drivers/gpu/drm/xe/xe_guc_capture.h new file mode 100644 index 00000000000000..97a795d13dd139 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_capture.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021-2024 Intel Corporation + */ + +#ifndef _XE_GUC_CAPTURE_H +#define _XE_GUC_CAPTURE_H + +#include +#include "abi/guc_capture_abi.h" +#include "xe_guc.h" +#include "xe_guc_fwif.h" + +struct xe_guc; +struct xe_hw_engine; +struct xe_hw_engine_snapshot; +struct xe_sched_job; + +static inline enum guc_capture_list_class_type xe_guc_class_to_capture_class(u16 class) +{ + switch (class) { + case GUC_RENDER_CLASS: + case GUC_COMPUTE_CLASS: + return GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE; + case GUC_GSC_OTHER_CLASS: + return GUC_CAPTURE_LIST_CLASS_GSC_OTHER; + case GUC_VIDEO_CLASS: + case GUC_VIDEOENHANCE_CLASS: + case GUC_BLITTER_CLASS: + return class; + default: + XE_WARN_ON(class); + return GUC_CAPTURE_LIST_CLASS_MAX; + } +} + +static inline enum guc_capture_list_class_type +xe_engine_class_to_guc_capture_class(enum xe_engine_class class) +{ + return xe_guc_class_to_capture_class(xe_engine_class_to_guc_class(class)); +} + +void xe_guc_capture_process(struct xe_guc *guc); +int xe_guc_capture_getlist(struct xe_guc *guc, u32 owner, u32 type, + enum guc_capture_list_class_type capture_class, void **outptr); +int xe_guc_capture_getlistsize(struct xe_guc *guc, u32 owner, u32 type, + enum guc_capture_list_class_type capture_class, size_t *size); +int xe_guc_capture_getnullheader(struct xe_guc *guc, void **outptr, size_t *size); +size_t xe_guc_capture_ads_input_worst_size(struct xe_guc *guc); +const struct __guc_mmio_reg_descr_group * +xe_guc_capture_get_reg_desc_list(struct xe_gt *gt, u32 owner, u32 type, + enum guc_capture_list_class_type capture_class, bool is_ext); +struct __guc_capture_parsed_output *xe_guc_capture_get_matching_and_lock(struct xe_sched_job *job); +void xe_engine_manual_capture(struct xe_hw_engine *hwe, struct xe_hw_engine_snapshot *snapshot); +void xe_engine_snapshot_print(struct xe_hw_engine_snapshot *snapshot, struct drm_printer *p); +void xe_engine_snapshot_capture_for_job(struct xe_sched_job *job); +void xe_guc_capture_steered_list_init(struct xe_guc *guc); +void xe_guc_capture_put_matched_nodes(struct xe_guc *guc); +int xe_guc_capture_init(struct xe_guc *guc); + +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_capture_types.h b/drivers/gpu/drm/xe/xe_guc_capture_types.h new file mode 100644 index 00000000000000..2057125b1bfa13 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_capture_types.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021-2024 Intel Corporation + */ + +#ifndef _XE_GUC_CAPTURE_TYPES_H +#define _XE_GUC_CAPTURE_TYPES_H + +#include +#include "regs/xe_reg_defs.h" + +struct xe_guc; + +/* data type of the register in register list */ +enum capture_register_data_type { + REG_32BIT = 0, + REG_64BIT_LOW_DW, + REG_64BIT_HI_DW, +}; + +/** + * struct __guc_mmio_reg_descr - GuC mmio register descriptor + * + * xe_guc_capture module uses these structures to define a register + * (offsets, names, flags,...) that are used at the ADS regisration + * time as well as during runtime processing and reporting of error- + * capture states generated by GuC just prior to engine reset events. + */ +struct __guc_mmio_reg_descr { + /** @reg: the register */ + struct xe_reg reg; + /** + * @data_type: data type of the register + * Could be 32 bit, low or hi dword of a 64 bit, see enum + * register_data_type + */ + enum capture_register_data_type data_type; + /** @flags: Flags for the register */ + u32 flags; + /** @mask: The mask to apply */ + u32 mask; + /** @regname: Name of the register */ + const char *regname; +}; + +/** + * struct __guc_mmio_reg_descr_group - The group of register descriptor + * + * xe_guc_capture module uses these structures to maintain static + * tables (per unique platform) that consists of lists of registers + * (offsets, names, flags,...) that are used at the ADS regisration + * time as well as during runtime processing and reporting of error- + * capture states generated by GuC just prior to engine reset events. + */ +struct __guc_mmio_reg_descr_group { + /** @list: The register list */ + const struct __guc_mmio_reg_descr *list; + /** @num_regs: Count of registers in the list */ + u32 num_regs; + /** @owner: PF/VF owner, see enum guc_capture_list_index_type */ + u32 owner; + /** @type: Capture register type, see enum guc_state_capture_type */ + u32 type; + /** @engine: The engine class, see enum guc_capture_list_class_type */ + u32 engine; +}; + +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 9c505d3517cd1a..8aeb1789805c5e 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -17,6 +18,7 @@ #include "abi/guc_actions_sriov_abi.h" #include "abi/guc_klvs_abi.h" #include "xe_bo.h" +#include "xe_devcoredump.h" #include "xe_device.h" #include "xe_gt.h" #include "xe_gt_pagefault.h" @@ -25,12 +27,48 @@ #include "xe_gt_sriov_pf_monitor.h" #include "xe_gt_tlb_invalidation.h" #include "xe_guc.h" +#include "xe_guc_log.h" #include "xe_guc_relay.h" #include "xe_guc_submit.h" #include "xe_map.h" #include "xe_pm.h" #include "xe_trace_guc.h" +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG) +enum { + /* Internal states, not error conditions */ + CT_DEAD_STATE_REARM, /* 0x0001 */ + CT_DEAD_STATE_CAPTURE, /* 0x0002 */ + + /* Error conditions */ + CT_DEAD_SETUP, /* 0x0004 */ + CT_DEAD_H2G_WRITE, /* 0x0008 */ + CT_DEAD_H2G_HAS_ROOM, /* 0x0010 */ + CT_DEAD_G2H_READ, /* 0x0020 */ + CT_DEAD_G2H_RECV, /* 0x0040 */ + CT_DEAD_G2H_RELEASE, /* 0x0080 */ + CT_DEAD_DEADLOCK, /* 0x0100 */ + CT_DEAD_PROCESS_FAILED, /* 0x0200 */ + CT_DEAD_FAST_G2H, /* 0x0400 */ + CT_DEAD_PARSE_G2H_RESPONSE, /* 0x0800 */ + CT_DEAD_PARSE_G2H_UNKNOWN, /* 0x1000 */ + CT_DEAD_PARSE_G2H_ORIGIN, /* 0x2000 */ + CT_DEAD_PARSE_G2H_TYPE, /* 0x4000 */ +}; + +static void ct_dead_worker_func(struct work_struct *w); +static void ct_dead_capture(struct xe_guc_ct *ct, struct guc_ctb *ctb, u32 reason_code); + +#define CT_DEAD(ct, ctb, reason_code) ct_dead_capture((ct), (ctb), CT_DEAD_##reason_code) +#else +#define CT_DEAD(ct, ctb, reason) \ + do { \ + struct guc_ctb *_ctb = (ctb); \ + if (_ctb) \ + _ctb->info.broken = true; \ + } while (0) +#endif + /* Used when a CT send wants to block and / or receive data */ struct g2h_fence { u32 *response_buffer; @@ -175,14 +213,18 @@ int xe_guc_ct_init(struct xe_guc_ct *ct) xe_gt_assert(gt, !(guc_ct_size() % PAGE_SIZE)); - ct->g2h_wq = alloc_ordered_workqueue("xe-g2h-wq", 0); + ct->g2h_wq = alloc_ordered_workqueue("xe-g2h-wq", WQ_MEM_RECLAIM); if (!ct->g2h_wq) return -ENOMEM; spin_lock_init(&ct->fast_lock); xa_init(&ct->fence_lookup); INIT_WORK(&ct->g2h_worker, g2h_worker_func); - INIT_DELAYED_WORK(&ct->safe_mode_worker, safe_mode_worker_func); + INIT_DELAYED_WORK(&ct->safe_mode_worker, safe_mode_worker_func); +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG) + spin_lock_init(&ct->dead.lock); + INIT_WORK(&ct->dead.worker, ct_dead_worker_func); +#endif init_waitqueue_head(&ct->wq); init_waitqueue_head(&ct->g2h_fence_wq); @@ -209,6 +251,7 @@ int xe_guc_ct_init(struct xe_guc_ct *ct) ct->state = XE_GUC_CT_STATE_DISABLED; return 0; } +ALLOW_ERROR_INJECTION(xe_guc_ct_init, ERRNO); /* See xe_pci_probe() */ #define desc_read(xe_, guc_ctb__, field_) \ xe_map_rd_field(xe_, &guc_ctb__->desc, 0, \ @@ -395,6 +438,7 @@ int xe_guc_ct_enable(struct xe_guc_ct *ct) xe_gt_assert(gt, !xe_guc_ct_enabled(ct)); + xe_map_memset(xe, &ct->bo->vmap, 0, 0, ct->bo->size); guc_ct_ctb_h2g_init(xe, &ct->ctbs.h2g, &ct->bo->vmap); guc_ct_ctb_g2h_init(xe, &ct->ctbs.g2h, &ct->bo->vmap); @@ -419,10 +463,22 @@ int xe_guc_ct_enable(struct xe_guc_ct *ct) if (ct_needs_safe_mode(ct)) ct_enter_safe_mode(ct); +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG) + /* + * The CT has now been reset so the dumper can be re-armed + * after any existing dead state has been dumped. + */ + spin_lock_irq(&ct->dead.lock); + if (ct->dead.reason) + ct->dead.reason |= (1 << CT_DEAD_STATE_REARM); + spin_unlock_irq(&ct->dead.lock); +#endif + return 0; err_out: xe_gt_err(gt, "Failed to enable GuC CT (%pe)\n", ERR_PTR(err)); + CT_DEAD(ct, NULL, SETUP); return err; } @@ -466,6 +522,19 @@ static bool h2g_has_room(struct xe_guc_ct *ct, u32 cmd_len) if (cmd_len > h2g->info.space) { h2g->info.head = desc_read(ct_to_xe(ct), h2g, head); + + if (h2g->info.head > h2g->info.size) { + struct xe_device *xe = ct_to_xe(ct); + u32 desc_status = desc_read(xe, h2g, status); + + desc_write(xe, h2g, status, desc_status | GUC_CTB_STATUS_OVERFLOW); + + xe_gt_err(ct_to_gt(ct), "CT: invalid head offset %u >= %u)\n", + h2g->info.head, h2g->info.size); + CT_DEAD(ct, h2g, H2G_HAS_ROOM); + return false; + } + h2g->info.space = CIRC_SPACE(h2g->info.tail, h2g->info.head, h2g->info.size) - h2g->info.resv_space; @@ -521,10 +590,24 @@ static void __g2h_reserve_space(struct xe_guc_ct *ct, u32 g2h_len, u32 num_g2h) static void __g2h_release_space(struct xe_guc_ct *ct, u32 g2h_len) { + bool bad = false; + lockdep_assert_held(&ct->fast_lock); - xe_gt_assert(ct_to_gt(ct), ct->ctbs.g2h.info.space + g2h_len <= - ct->ctbs.g2h.info.size - ct->ctbs.g2h.info.resv_space); - xe_gt_assert(ct_to_gt(ct), ct->g2h_outstanding); + + bad = ct->ctbs.g2h.info.space + g2h_len > + ct->ctbs.g2h.info.size - ct->ctbs.g2h.info.resv_space; + bad |= !ct->g2h_outstanding; + + if (bad) { + xe_gt_err(ct_to_gt(ct), "Invalid G2H release: %d + %d vs %d - %d -> %d vs %d, outstanding = %d!\n", + ct->ctbs.g2h.info.space, g2h_len, + ct->ctbs.g2h.info.size, ct->ctbs.g2h.info.resv_space, + ct->ctbs.g2h.info.space + g2h_len, + ct->ctbs.g2h.info.size - ct->ctbs.g2h.info.resv_space, + ct->g2h_outstanding); + CT_DEAD(ct, &ct->ctbs.g2h, G2H_RELEASE); + return; + } ct->ctbs.g2h.info.space += g2h_len; if (!--ct->g2h_outstanding) @@ -551,12 +634,43 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len, u32 full_len; struct iosys_map map = IOSYS_MAP_INIT_OFFSET(&h2g->cmds, tail * sizeof(u32)); + u32 desc_status; full_len = len + GUC_CTB_HDR_LEN; lockdep_assert_held(&ct->lock); xe_gt_assert(gt, full_len <= GUC_CTB_MSG_MAX_LEN); - xe_gt_assert(gt, tail <= h2g->info.size); + + desc_status = desc_read(xe, h2g, status); + if (desc_status) { + xe_gt_err(gt, "CT write: non-zero status: %u\n", desc_status); + goto corrupted; + } + + if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) { + u32 desc_tail = desc_read(xe, h2g, tail); + u32 desc_head = desc_read(xe, h2g, head); + + if (tail != desc_tail) { + desc_write(xe, h2g, status, desc_status | GUC_CTB_STATUS_MISMATCH); + xe_gt_err(gt, "CT write: tail was modified %u != %u\n", desc_tail, tail); + goto corrupted; + } + + if (tail > h2g->info.size) { + desc_write(xe, h2g, status, desc_status | GUC_CTB_STATUS_OVERFLOW); + xe_gt_err(gt, "CT write: tail out of range: %u vs %u\n", + tail, h2g->info.size); + goto corrupted; + } + + if (desc_head >= h2g->info.size) { + desc_write(xe, h2g, status, desc_status | GUC_CTB_STATUS_OVERFLOW); + xe_gt_err(gt, "CT write: invalid head offset %u >= %u)\n", + desc_head, h2g->info.size); + goto corrupted; + } + } /* Command will wrap, zero fill (NOPs), return and check credits again */ if (tail + full_len > h2g->info.size) { @@ -609,6 +723,10 @@ static int h2g_write(struct xe_guc_ct *ct, const u32 *action, u32 len, desc_read(xe, h2g, head), h2g->info.tail); return 0; + +corrupted: + CT_DEAD(ct, &ct->ctbs.h2g, H2G_WRITE); + return -EPIPE; } /* @@ -716,7 +834,6 @@ static int guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len, { struct xe_device *xe = ct_to_xe(ct); struct xe_gt *gt = ct_to_gt(ct); - struct drm_printer p = xe_gt_info_printer(gt); unsigned int sleep_period_ms = 1; int ret; @@ -769,8 +886,13 @@ static int guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len, goto broken; #undef g2h_avail - if (dequeue_one_g2h(ct) < 0) + ret = dequeue_one_g2h(ct); + if (ret < 0) { + if (ret != -ECANCELED) + xe_gt_err(ct_to_gt(ct), "CTB receive failed (%pe)", + ERR_PTR(ret)); goto broken; + } goto try_again; } @@ -779,8 +901,7 @@ static int guc_ct_send_locked(struct xe_guc_ct *ct, const u32 *action, u32 len, broken: xe_gt_err(gt, "No forward process on H2G, reset required\n"); - xe_guc_ct_print(ct, &p, true); - ct->ctbs.h2g.info.broken = true; + CT_DEAD(ct, &ct->ctbs.h2g, DEADLOCK); return -EDEADLK; } @@ -848,7 +969,7 @@ static bool retry_failure(struct xe_guc_ct *ct, int ret) #define ct_alive(ct) \ (xe_guc_ct_enabled(ct) && !ct->ctbs.h2g.info.broken && \ !ct->ctbs.g2h.info.broken) - if (!wait_event_interruptible_timeout(ct->wq, ct_alive(ct), HZ * 5)) + if (!wait_event_interruptible_timeout(ct->wq, ct_alive(ct), HZ * 5)) return false; #undef ct_alive @@ -890,7 +1011,7 @@ static int guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len, goto retry_same_fence; if (!g2h_fence_needs_alloc(&g2h_fence)) - xa_erase_irq(&ct->fence_lookup, g2h_fence.seqno); + xa_erase(&ct->fence_lookup, g2h_fence.seqno); return ret; } @@ -916,7 +1037,7 @@ static int guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len, if (!ret) { xe_gt_err(gt, "Timed out wait for G2H, fence %u, action %04x, done %s", g2h_fence.seqno, action[0], str_yes_no(g2h_fence.done)); - xa_erase_irq(&ct->fence_lookup, g2h_fence.seqno); + xa_erase(&ct->fence_lookup, g2h_fence.seqno); mutex_unlock(&ct->lock); return -ETIME; } @@ -1028,6 +1149,7 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) else xe_gt_err(gt, "unexpected response %u for FAST_REQ H2G fence 0x%x!\n", type, fence); + CT_DEAD(ct, NULL, PARSE_G2H_RESPONSE); return -EPROTO; } @@ -1035,6 +1157,7 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) g2h_fence = xa_erase(&ct->fence_lookup, fence); if (unlikely(!g2h_fence)) { /* Don't tear down channel, as send could've timed out */ + /* CT_DEAD(ct, NULL, PARSE_G2H_UNKNOWN); */ xe_gt_warn(gt, "G2H fence (%u) not found!\n", fence); g2h_release_space(ct, GUC_CTB_HXG_MSG_MAX_LEN); return 0; @@ -1079,7 +1202,7 @@ static int parse_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) if (unlikely(origin != GUC_HXG_ORIGIN_GUC)) { xe_gt_err(gt, "G2H channel broken on read, origin=%u, reset required\n", origin); - ct->ctbs.g2h.info.broken = true; + CT_DEAD(ct, &ct->ctbs.g2h, PARSE_G2H_ORIGIN); return -EPROTO; } @@ -1097,7 +1220,7 @@ static int parse_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) default: xe_gt_err(gt, "G2H channel broken on read, type=%u, reset required\n", type); - ct->ctbs.g2h.info.broken = true; + CT_DEAD(ct, &ct->ctbs.g2h, PARSE_G2H_TYPE); ret = -EOPNOTSUPP; } @@ -1140,6 +1263,8 @@ static int process_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) /* Selftest only at the moment */ break; case XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION: + ret = xe_guc_error_capture_handler(guc, payload, adj_len); + break; case XE_GUC_ACTION_NOTIFY_FLUSH_LOG_BUFFER_TO_FILE: /* FIXME: Handle this */ break; @@ -1174,9 +1299,11 @@ static int process_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) xe_gt_err(gt, "unexpected G2H action 0x%04x\n", action); } - if (ret) + if (ret) { xe_gt_err(gt, "G2H action 0x%04x failed (%pe)\n", action, ERR_PTR(ret)); + CT_DEAD(ct, NULL, PROCESS_FAILED); + } return 0; } @@ -1186,7 +1313,7 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) struct xe_device *xe = ct_to_xe(ct); struct xe_gt *gt = ct_to_gt(ct); struct guc_ctb *g2h = &ct->ctbs.g2h; - u32 tail, head, len; + u32 tail, head, len, desc_status; s32 avail; u32 action; u32 *hxg; @@ -1205,6 +1332,63 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) xe_gt_assert(gt, xe_guc_ct_enabled(ct)); + desc_status = desc_read(xe, g2h, status); + if (desc_status) { + if (desc_status & GUC_CTB_STATUS_DISABLED) { + /* + * Potentially valid if a CLIENT_RESET request resulted in + * contexts/engines being reset. But should never happen as + * no contexts should be active when CLIENT_RESET is sent. + */ + xe_gt_err(gt, "CT read: unexpected G2H after GuC has stopped!\n"); + desc_status &= ~GUC_CTB_STATUS_DISABLED; + } + + if (desc_status) { + xe_gt_err(gt, "CT read: non-zero status: %u\n", desc_status); + goto corrupted; + } + } + + if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) { + u32 desc_tail = desc_read(xe, g2h, tail); + /* + u32 desc_head = desc_read(xe, g2h, head); + + * info.head and desc_head are updated back-to-back at the end of + * this function and nowhere else. Hence, they cannot be different + * unless two g2h_read calls are running concurrently. Which is not + * possible because it is guarded by ct->fast_lock. And yet, some + * discrete platforms are reguarly hitting this error :(. + * + * desc_head rolling backwards shouldn't cause any noticeable + * problems - just a delay in GuC being allowed to proceed past that + * point in the queue. So for now, just disable the error until it + * can be root caused. + * + if (g2h->info.head != desc_head) { + desc_write(xe, g2h, status, desc_status | GUC_CTB_STATUS_MISMATCH); + xe_gt_err(gt, "CT read: head was modified %u != %u\n", + desc_head, g2h->info.head); + goto corrupted; + } + */ + + if (g2h->info.head > g2h->info.size) { + desc_write(xe, g2h, status, desc_status | GUC_CTB_STATUS_OVERFLOW); + xe_gt_err(gt, "CT read: head out of range: %u vs %u\n", + g2h->info.head, g2h->info.size); + goto corrupted; + } + + if (desc_tail >= g2h->info.size) { + desc_write(xe, g2h, status, desc_status | GUC_CTB_STATUS_OVERFLOW); + xe_gt_err(gt, "CT read: invalid tail offset %u >= %u)\n", + desc_tail, g2h->info.size); + goto corrupted; + } + } + /* Calculate DW available to read */ tail = desc_read(xe, g2h, tail); avail = tail - g2h->info.head; @@ -1221,9 +1405,7 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) if (len > avail) { xe_gt_err(gt, "G2H channel broken on read, avail=%d, len=%d, reset required\n", avail, len); - g2h->info.broken = true; - - return -EPROTO; + goto corrupted; } head = (g2h->info.head + 1) % g2h->info.size; @@ -1269,6 +1451,10 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) action, len, g2h->info.head, tail); return len; + +corrupted: + CT_DEAD(ct, &ct->ctbs.g2h, G2H_READ); + return -EPROTO; } static void g2h_fast_path(struct xe_guc_ct *ct, u32 *msg, u32 len) @@ -1295,9 +1481,11 @@ static void g2h_fast_path(struct xe_guc_ct *ct, u32 *msg, u32 len) xe_gt_warn(gt, "NOT_POSSIBLE"); } - if (ret) + if (ret) { xe_gt_err(gt, "G2H action 0x%04x failed (%pe)\n", action, ERR_PTR(ret)); + CT_DEAD(ct, NULL, FAST_G2H); + } } /** @@ -1357,7 +1545,6 @@ static int dequeue_one_g2h(struct xe_guc_ct *ct) static void receive_g2h(struct xe_guc_ct *ct) { - struct xe_gt *gt = ct_to_gt(ct); bool ongoing; int ret; @@ -1394,9 +1581,8 @@ static void receive_g2h(struct xe_guc_ct *ct) mutex_unlock(&ct->lock); if (unlikely(ret == -EPROTO || ret == -EOPNOTSUPP)) { - struct drm_printer p = xe_gt_info_printer(gt); - - xe_guc_ct_print(ct, &p, false); + xe_gt_err(ct_to_gt(ct), "CT dequeue failed: %d", ret); + CT_DEAD(ct, NULL, G2H_RECV); kick_reset(ct); } } while (ret == 1); @@ -1412,49 +1598,34 @@ static void g2h_worker_func(struct work_struct *w) receive_g2h(ct); } -static void guc_ctb_snapshot_capture(struct xe_device *xe, struct guc_ctb *ctb, - struct guc_ctb_snapshot *snapshot, - bool atomic) +static struct xe_guc_ct_snapshot *guc_ct_snapshot_alloc(struct xe_guc_ct *ct, bool atomic, + bool want_ctb) { - u32 head, tail; - - xe_map_memcpy_from(xe, &snapshot->desc, &ctb->desc, 0, - sizeof(struct guc_ct_buffer_desc)); - memcpy(&snapshot->info, &ctb->info, sizeof(struct guc_ctb_info)); + struct xe_guc_ct_snapshot *snapshot; - snapshot->cmds = kmalloc_array(ctb->info.size, sizeof(u32), - atomic ? GFP_ATOMIC : GFP_KERNEL); + snapshot = kzalloc(sizeof(*snapshot), atomic ? GFP_ATOMIC : GFP_KERNEL); + if (!snapshot) + return NULL; - if (!snapshot->cmds) { - drm_err(&xe->drm, "Skipping CTB commands snapshot. Only CTB info will be available.\n"); - return; + if (ct->bo && want_ctb) { + snapshot->ctb_size = ct->bo->size; + snapshot->ctb = kmalloc(snapshot->ctb_size, atomic ? GFP_ATOMIC : GFP_KERNEL); } - head = snapshot->desc.head; - tail = snapshot->desc.tail; - - if (head != tail) { - struct iosys_map map = - IOSYS_MAP_INIT_OFFSET(&ctb->cmds, head * sizeof(u32)); - - while (head != tail) { - snapshot->cmds[head] = xe_map_rd(xe, &map, 0, u32); - ++head; - if (head == ctb->info.size) { - head = 0; - map = ctb->cmds; - } else { - iosys_map_incr(&map, sizeof(u32)); - } - } - } + return snapshot; +} + +static void guc_ctb_snapshot_capture(struct xe_device *xe, struct guc_ctb *ctb, + struct guc_ctb_snapshot *snapshot) +{ + xe_map_memcpy_from(xe, &snapshot->desc, &ctb->desc, 0, + sizeof(struct guc_ct_buffer_desc)); + memcpy(&snapshot->info, &ctb->info, sizeof(struct guc_ctb_info)); } static void guc_ctb_snapshot_print(struct guc_ctb_snapshot *snapshot, struct drm_printer *p) { - u32 head, tail; - drm_printf(p, "\tsize: %d\n", snapshot->info.size); drm_printf(p, "\tresv_space: %d\n", snapshot->info.resv_space); drm_printf(p, "\thead: %d\n", snapshot->info.head); @@ -1464,63 +1635,46 @@ static void guc_ctb_snapshot_print(struct guc_ctb_snapshot *snapshot, drm_printf(p, "\thead (memory): %d\n", snapshot->desc.head); drm_printf(p, "\ttail (memory): %d\n", snapshot->desc.tail); drm_printf(p, "\tstatus (memory): 0x%x\n", snapshot->desc.status); +} - if (!snapshot->cmds) - return; +static struct xe_guc_ct_snapshot *guc_ct_snapshot_capture(struct xe_guc_ct *ct, bool atomic, + bool want_ctb) +{ + struct xe_device *xe = ct_to_xe(ct); + struct xe_guc_ct_snapshot *snapshot; - head = snapshot->desc.head; - tail = snapshot->desc.tail; + snapshot = guc_ct_snapshot_alloc(ct, atomic, want_ctb); + if (!snapshot) { + xe_gt_err(ct_to_gt(ct), "Skipping CTB snapshot entirely.\n"); + return NULL; + } - while (head != tail) { - drm_printf(p, "\tcmd[%d]: 0x%08x\n", head, - snapshot->cmds[head]); - ++head; - if (head == snapshot->info.size) - head = 0; + if (xe_guc_ct_enabled(ct) || ct->state == XE_GUC_CT_STATE_STOPPED) { + snapshot->ct_enabled = true; + snapshot->g2h_outstanding = READ_ONCE(ct->g2h_outstanding); + guc_ctb_snapshot_capture(xe, &ct->ctbs.h2g, &snapshot->h2g); + guc_ctb_snapshot_capture(xe, &ct->ctbs.g2h, &snapshot->g2h); } -} -static void guc_ctb_snapshot_free(struct guc_ctb_snapshot *snapshot) -{ - kfree(snapshot->cmds); + if (ct->bo && snapshot->ctb) + xe_map_memcpy_from(xe, snapshot->ctb, &ct->bo->vmap, 0, snapshot->ctb_size); + + return snapshot; } /** * xe_guc_ct_snapshot_capture - Take a quick snapshot of the CT state. * @ct: GuC CT object. - * @atomic: Boolean to indicate if this is called from atomic context like - * reset or CTB handler or from some regular path like debugfs. * * This can be printed out in a later stage like during dev_coredump - * analysis. + * analysis. This is safe to be called during atomic context. * * Returns: a GuC CT snapshot object that must be freed by the caller * by using `xe_guc_ct_snapshot_free`. */ -struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct, - bool atomic) +struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct) { - struct xe_device *xe = ct_to_xe(ct); - struct xe_guc_ct_snapshot *snapshot; - - snapshot = kzalloc(sizeof(*snapshot), - atomic ? GFP_ATOMIC : GFP_KERNEL); - - if (!snapshot) { - drm_err(&xe->drm, "Skipping CTB snapshot entirely.\n"); - return NULL; - } - - if (xe_guc_ct_enabled(ct) || ct->state == XE_GUC_CT_STATE_STOPPED) { - snapshot->ct_enabled = true; - snapshot->g2h_outstanding = READ_ONCE(ct->g2h_outstanding); - guc_ctb_snapshot_capture(xe, &ct->ctbs.h2g, - &snapshot->h2g, atomic); - guc_ctb_snapshot_capture(xe, &ct->ctbs.g2h, - &snapshot->g2h, atomic); - } - - return snapshot; + return guc_ct_snapshot_capture(ct, true, true); } /** @@ -1540,11 +1694,13 @@ void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, drm_puts(p, "H2G CTB (all sizes in DW):\n"); guc_ctb_snapshot_print(&snapshot->h2g, p); - drm_puts(p, "\nG2H CTB (all sizes in DW):\n"); + drm_puts(p, "G2H CTB (all sizes in DW):\n"); guc_ctb_snapshot_print(&snapshot->g2h, p); - drm_printf(p, "\tg2h outstanding: %d\n", snapshot->g2h_outstanding); + + if (snapshot->ctb) + xe_print_blob_ascii85(p, "CTB data", snapshot->ctb, 0, snapshot->ctb_size); } else { drm_puts(p, "CT disabled\n"); } @@ -1562,8 +1718,7 @@ void xe_guc_ct_snapshot_free(struct xe_guc_ct_snapshot *snapshot) if (!snapshot) return; - guc_ctb_snapshot_free(&snapshot->h2g); - guc_ctb_snapshot_free(&snapshot->g2h); + kfree(snapshot->ctb); kfree(snapshot); } @@ -1571,16 +1726,121 @@ void xe_guc_ct_snapshot_free(struct xe_guc_ct_snapshot *snapshot) * xe_guc_ct_print - GuC CT Print. * @ct: GuC CT. * @p: drm_printer where it will be printed out. - * @atomic: Boolean to indicate if this is called from atomic context like - * reset or CTB handler or from some regular path like debugfs. + * @want_ctb: Should the full CTB content be dumped (vs just the headers) * - * This function quickly capture a snapshot and immediately print it out. + * This function will quickly capture a snapshot of the CT state + * and immediately print it out. */ -void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool atomic) +void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool want_ctb) { struct xe_guc_ct_snapshot *snapshot; - snapshot = xe_guc_ct_snapshot_capture(ct, atomic); + snapshot = guc_ct_snapshot_capture(ct, false, want_ctb); xe_guc_ct_snapshot_print(snapshot, p); xe_guc_ct_snapshot_free(snapshot); } + +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG) +static void ct_dead_capture(struct xe_guc_ct *ct, struct guc_ctb *ctb, u32 reason_code) +{ + struct xe_guc_log_snapshot *snapshot_log; + struct xe_guc_ct_snapshot *snapshot_ct; + struct xe_guc *guc = ct_to_guc(ct); + unsigned long flags; + bool have_capture; + + if (ctb) + ctb->info.broken = true; + + /* Ignore further errors after the first dump until a reset */ + if (ct->dead.reported) + return; + + spin_lock_irqsave(&ct->dead.lock, flags); + + /* And only capture one dump at a time */ + have_capture = ct->dead.reason & (1 << CT_DEAD_STATE_CAPTURE); + ct->dead.reason |= (1 << reason_code) | + (1 << CT_DEAD_STATE_CAPTURE); + + spin_unlock_irqrestore(&ct->dead.lock, flags); + + if (have_capture) + return; + + snapshot_log = xe_guc_log_snapshot_capture(&guc->log, true); + snapshot_ct = xe_guc_ct_snapshot_capture((ct)); + + spin_lock_irqsave(&ct->dead.lock, flags); + + if (ct->dead.snapshot_log || ct->dead.snapshot_ct) { + xe_gt_err(ct_to_gt(ct), "Got unexpected dead CT capture!\n"); + xe_guc_log_snapshot_free(snapshot_log); + xe_guc_ct_snapshot_free(snapshot_ct); + } else { + ct->dead.snapshot_log = snapshot_log; + ct->dead.snapshot_ct = snapshot_ct; + } + + spin_unlock_irqrestore(&ct->dead.lock, flags); + + queue_work(system_unbound_wq, &(ct)->dead.worker); +} + +static void ct_dead_print(struct xe_dead_ct *dead) +{ + struct xe_guc_ct *ct = container_of(dead, struct xe_guc_ct, dead); + struct xe_device *xe = ct_to_xe(ct); + struct xe_gt *gt = ct_to_gt(ct); + static int g_count; + struct drm_printer ip = xe_gt_info_printer(gt); + struct drm_printer lp = drm_line_printer(&ip, "Capture", ++g_count); + + if (!dead->reason) { + xe_gt_err(gt, "CTB is dead for no reason!?\n"); + return; + } + + drm_printf(&lp, "CTB is dead - reason=0x%X\n", dead->reason); + + /* Can't generate a genuine core dump at this point, so just do the good bits */ + drm_puts(&lp, "**** Xe Device Coredump ****\n"); + xe_device_snapshot_print(xe, &lp); + + drm_printf(&lp, "**** GT #%d ****\n", gt->info.id); + drm_printf(&lp, "\tTile: %d\n", gt->tile->id); + + drm_puts(&lp, "**** GuC Log ****\n"); + xe_guc_log_snapshot_print(dead->snapshot_log, &lp); + + drm_puts(&lp, "**** GuC CT ****\n"); + xe_guc_ct_snapshot_print(dead->snapshot_ct, &lp); + + drm_puts(&lp, "Done.\n"); +} + +static void ct_dead_worker_func(struct work_struct *w) +{ + struct xe_guc_ct *ct = container_of(w, struct xe_guc_ct, dead.worker); + + if (!ct->dead.reported) { + ct->dead.reported = true; + ct_dead_print(&ct->dead); + } + + spin_lock_irq(&ct->dead.lock); + + xe_guc_log_snapshot_free(ct->dead.snapshot_log); + ct->dead.snapshot_log = NULL; + xe_guc_ct_snapshot_free(ct->dead.snapshot_ct); + ct->dead.snapshot_ct = NULL; + + if (ct->dead.reason & (1 << CT_DEAD_STATE_REARM)) { + /* A reset has occurred so re-arm the error reporting */ + ct->dead.reason = 0; + ct->dead.reported = false; + } + + spin_unlock_irq(&ct->dead.lock); +} +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_ct.h b/drivers/gpu/drm/xe/xe_guc_ct.h index 190202fce2d048..82c4ae458dda39 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.h +++ b/drivers/gpu/drm/xe/xe_guc_ct.h @@ -9,6 +9,7 @@ #include "xe_guc_ct_types.h" struct drm_printer; +struct xe_device; int xe_guc_ct_init(struct xe_guc_ct *ct); int xe_guc_ct_enable(struct xe_guc_ct *ct); @@ -16,12 +17,10 @@ void xe_guc_ct_disable(struct xe_guc_ct *ct); void xe_guc_ct_stop(struct xe_guc_ct *ct); void xe_guc_ct_fast_path(struct xe_guc_ct *ct); -struct xe_guc_ct_snapshot * -xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct, bool atomic); -void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, - struct drm_printer *p); +struct xe_guc_ct_snapshot *xe_guc_ct_snapshot_capture(struct xe_guc_ct *ct); +void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, struct drm_printer *p); void xe_guc_ct_snapshot_free(struct xe_guc_ct_snapshot *snapshot); -void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool atomic); +void xe_guc_ct_print(struct xe_guc_ct *ct, struct drm_printer *p, bool want_ctb); static inline bool xe_guc_ct_enabled(struct xe_guc_ct *ct) { diff --git a/drivers/gpu/drm/xe/xe_guc_ct_types.h b/drivers/gpu/drm/xe/xe_guc_ct_types.h index 761cb903129843..8e1b9d981d61ec 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct_types.h +++ b/drivers/gpu/drm/xe/xe_guc_ct_types.h @@ -52,8 +52,6 @@ struct guc_ctb { struct guc_ctb_snapshot { /** @desc: snapshot of the CTB descriptor */ struct guc_ct_buffer_desc desc; - /** @cmds: snapshot of the CTB commands */ - u32 *cmds; /** @info: snapshot of the CTB info */ struct guc_ctb_info info; }; @@ -70,6 +68,10 @@ struct xe_guc_ct_snapshot { struct guc_ctb_snapshot g2h; /** @h2g: H2G CTB snapshot */ struct guc_ctb_snapshot h2g; + /** @ctb_size: size of the snapshot of the CTB */ + size_t ctb_size; + /** @ctb: snapshot of the entire CTB */ + u32 *ctb; }; /** @@ -86,6 +88,24 @@ enum xe_guc_ct_state { XE_GUC_CT_STATE_ENABLED, }; +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG) +/** struct xe_dead_ct - Information for debugging a dead CT */ +struct xe_dead_ct { + /** @lock: protects memory allocation/free operations, and @reason updates */ + spinlock_t lock; + /** @reason: bit mask of CT_DEAD_* reason codes */ + unsigned int reason; + /** @reported: for preventing multiple dumps per error sequence */ + bool reported; + /** @worker: worker thread to get out of interrupt context before dumping */ + struct work_struct worker; + /** snapshot_ct: copy of CT state and CTB content at point of error */ + struct xe_guc_ct_snapshot *snapshot_ct; + /** snapshot_log: copy of GuC log at point of error */ + struct xe_guc_log_snapshot *snapshot_log; +}; +#endif + /** * struct xe_guc_ct - GuC command transport (CT) layer * @@ -128,6 +148,11 @@ struct xe_guc_ct { u32 msg[GUC_CTB_MSG_MAX_LEN]; /** @fast_msg: Message buffer */ u32 fast_msg[GUC_CTB_MSG_MAX_LEN]; + +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG) + /** @dead: information for debugging dead CTs */ + struct xe_dead_ct dead; +#endif }; #endif diff --git a/drivers/gpu/drm/xe/xe_guc_debugfs.c b/drivers/gpu/drm/xe/xe_guc_debugfs.c index d3822cbea273a4..995b306aced771 100644 --- a/drivers/gpu/drm/xe/xe_guc_debugfs.c +++ b/drivers/gpu/drm/xe/xe_guc_debugfs.c @@ -47,9 +47,23 @@ static int guc_log(struct seq_file *m, void *data) return 0; } +static int guc_ctb(struct seq_file *m, void *data) +{ + struct xe_guc *guc = node_to_guc(m->private); + struct xe_device *xe = guc_to_xe(guc); + struct drm_printer p = drm_seq_file_printer(m); + + xe_pm_runtime_get(xe); + xe_guc_ct_print(&guc->ct, &p, true); + xe_pm_runtime_put(xe); + + return 0; +} + static const struct drm_info_list debugfs_list[] = { {"guc_info", guc_info, 0}, {"guc_log", guc_log, 0}, + {"guc_ctb", guc_ctb, 0}, }; void xe_guc_debugfs_register(struct xe_guc *guc, struct dentry *parent) diff --git a/drivers/gpu/drm/xe/xe_guc_fwif.h b/drivers/gpu/drm/xe/xe_guc_fwif.h index 19ee71aeaf17b5..08ffe59f22fae7 100644 --- a/drivers/gpu/drm/xe/xe_guc_fwif.h +++ b/drivers/gpu/drm/xe/xe_guc_fwif.h @@ -8,7 +8,9 @@ #include +#include "abi/guc_capture_abi.h" #include "abi/guc_klvs_abi.h" +#include "xe_hw_engine_types.h" #define G2H_LEN_DW_SCHED_CONTEXT_MODE_SET 4 #define G2H_LEN_DW_DEREGISTER_CONTEXT 3 @@ -103,6 +105,7 @@ struct guc_update_exec_queue_policy { #define GUC_CTL_FEATURE 2 #define GUC_CTL_ENABLE_SLPC BIT(2) +#define GUC_CTL_ENABLE_LITE_RESTORE BIT(4) #define GUC_CTL_DISABLE_SCHEDULER BIT(14) #define GUC_CTL_DEBUG 3 @@ -157,24 +160,6 @@ struct guc_policies { u32 reserved[4]; } __packed; -/* GuC MMIO reg state struct */ -struct guc_mmio_reg { - u32 offset; - u32 value; - u32 flags; - u32 mask; -#define GUC_REGSET_MASKED BIT(0) -#define GUC_REGSET_MASKED_WITH_VALUE BIT(2) -#define GUC_REGSET_RESTORE_ONLY BIT(3) -} __packed; - -/* GuC register sets */ -struct guc_mmio_reg_set { - u32 address; - u16 count; - u16 reserved; -} __packed; - /* Generic GT SysInfo data types */ #define GUC_GENERIC_GT_SYSINFO_SLICE_ENABLED 0 #define GUC_GENERIC_GT_SYSINFO_VDBOX_SFC_SUPPORT_MASK 1 @@ -188,12 +173,6 @@ struct guc_gt_system_info { u32 generic_gt_sysinfo[GUC_GENERIC_GT_SYSINFO_MAX]; } __packed; -enum { - GUC_CAPTURE_LIST_INDEX_PF = 0, - GUC_CAPTURE_LIST_INDEX_VF = 1, - GUC_CAPTURE_LIST_INDEX_MAX = 2, -}; - /* GuC Additional Data Struct */ struct guc_ads { struct guc_mmio_reg_set reg_state_list[GUC_MAX_ENGINE_CLASSES][GUC_MAX_INSTANCES_PER_CLASS]; diff --git a/drivers/gpu/drm/xe/xe_guc_klv_thresholds_set.h b/drivers/gpu/drm/xe/xe_guc_klv_thresholds_set.h index da0fedbbdbafea..da10cf0389cb7b 100644 --- a/drivers/gpu/drm/xe/xe_guc_klv_thresholds_set.h +++ b/drivers/gpu/drm/xe/xe_guc_klv_thresholds_set.h @@ -17,6 +17,13 @@ #define MAKE_GUC_KLV_VF_CFG_THRESHOLD_KEY(TAG) \ MAKE_GUC_KLV_KEY(CONCATENATE(VF_CFG_THRESHOLD_, TAG)) +/** + * MAKE_GUC_KLV_VF_CFG_THRESHOLD_LEN - Prepare the name of the KLV length constant. + * @TAG: unique tag of the GuC threshold KLV key. + */ +#define MAKE_GUC_KLV_VF_CFG_THRESHOLD_LEN(TAG) \ + MAKE_GUC_KLV_LEN(CONCATENATE(VF_CFG_THRESHOLD_, TAG)) + /** * xe_guc_klv_threshold_key_to_index - Find index of the tracked GuC threshold. * @key: GuC threshold KLV key. diff --git a/drivers/gpu/drm/xe/xe_guc_log.c b/drivers/gpu/drm/xe/xe_guc_log.c index a37ee341942844..df4cfb698cdbc7 100644 --- a/drivers/gpu/drm/xe/xe_guc_log.c +++ b/drivers/gpu/drm/xe/xe_guc_log.c @@ -5,13 +5,26 @@ #include "xe_guc_log.h" +#include + #include +#include "regs/xe_guc_regs.h" #include "xe_bo.h" +#include "xe_devcoredump.h" +#include "xe_force_wake.h" #include "xe_gt.h" +#include "xe_gt_printk.h" #include "xe_map.h" +#include "xe_mmio.h" #include "xe_module.h" +static struct xe_guc * +log_to_guc(struct xe_guc_log *log) +{ + return container_of(log, struct xe_guc, log); +} + static struct xe_gt * log_to_gt(struct xe_guc_log *log) { @@ -49,32 +62,194 @@ static size_t guc_log_size(void) CAPTURE_BUFFER_SIZE; } -void xe_guc_log_print(struct xe_guc_log *log, struct drm_printer *p) +#define GUC_LOG_CHUNK_SIZE SZ_2M + +static struct xe_guc_log_snapshot *xe_guc_log_snapshot_alloc(struct xe_guc_log *log, bool atomic) +{ + struct xe_guc_log_snapshot *snapshot; + size_t remain; + int i; + + snapshot = kzalloc(sizeof(*snapshot), atomic ? GFP_ATOMIC : GFP_KERNEL); + if (!snapshot) + return NULL; + + /* + * NB: kmalloc has a hard limit well below the maximum GuC log buffer size. + * Also, can't use vmalloc as might be called from atomic context. So need + * to break the buffer up into smaller chunks that can be allocated. + */ + snapshot->size = log->bo->size; + snapshot->num_chunks = DIV_ROUND_UP(snapshot->size, GUC_LOG_CHUNK_SIZE); + + snapshot->copy = kcalloc(snapshot->num_chunks, sizeof(*snapshot->copy), + atomic ? GFP_ATOMIC : GFP_KERNEL); + if (!snapshot->copy) + goto fail_snap; + + remain = snapshot->size; + for (i = 0; i < snapshot->num_chunks; i++) { + size_t size = min(GUC_LOG_CHUNK_SIZE, remain); + + snapshot->copy[i] = kmalloc(size, atomic ? GFP_ATOMIC : GFP_KERNEL); + if (!snapshot->copy[i]) + goto fail_copy; + remain -= size; + } + + return snapshot; + +fail_copy: + for (i = 0; i < snapshot->num_chunks; i++) + kfree(snapshot->copy[i]); + kfree(snapshot->copy); +fail_snap: + kfree(snapshot); + return NULL; +} + +/** + * xe_guc_log_snapshot_free - free a previously captured GuC log snapshot + * @snapshot: GuC log snapshot structure + * + * Return: pointer to a newly allocated snapshot object or null if out of memory. Caller is + * responsible for calling xe_guc_log_snapshot_free when done with the snapshot. + */ +void xe_guc_log_snapshot_free(struct xe_guc_log_snapshot *snapshot) +{ + int i; + + if (!snapshot) + return; + + if (snapshot->copy) { + for (i = 0; i < snapshot->num_chunks; i++) + kfree(snapshot->copy[i]); + kfree(snapshot->copy); + } + + kfree(snapshot); +} + +/** + * xe_guc_log_snapshot_capture - create a new snapshot copy the GuC log for later dumping + * @log: GuC log structure + * @atomic: is the call inside an atomic section of some kind? + * + * Return: pointer to a newly allocated snapshot object or null if out of memory. Caller is + * responsible for calling xe_guc_log_snapshot_free when done with the snapshot. + */ +struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log, bool atomic) { + struct xe_guc_log_snapshot *snapshot; struct xe_device *xe = log_to_xe(log); - size_t size; - int i, j; + struct xe_guc *guc = log_to_guc(log); + struct xe_gt *gt = log_to_gt(log); + unsigned int fw_ref; + size_t remain; + int i; - xe_assert(xe, log->bo); + if (!log->bo) { + xe_gt_err(gt, "GuC log buffer not allocated\n"); + return NULL; + } - size = log->bo->size; + snapshot = xe_guc_log_snapshot_alloc(log, atomic); + if (!snapshot) { + xe_gt_err(gt, "GuC log snapshot not allocated\n"); + return NULL; + } -#define DW_PER_READ 128 - xe_assert(xe, !(size % (DW_PER_READ * sizeof(u32)))); - for (i = 0; i < size / sizeof(u32); i += DW_PER_READ) { - u32 read[DW_PER_READ]; + remain = snapshot->size; + for (i = 0; i < snapshot->num_chunks; i++) { + size_t size = min(GUC_LOG_CHUNK_SIZE, remain); - xe_map_memcpy_from(xe, read, &log->bo->vmap, i * sizeof(u32), - DW_PER_READ * sizeof(u32)); -#define DW_PER_PRINT 4 - for (j = 0; j < DW_PER_READ / DW_PER_PRINT; ++j) { - u32 *print = read + j * DW_PER_PRINT; + xe_map_memcpy_from(xe, snapshot->copy[i], &log->bo->vmap, + i * GUC_LOG_CHUNK_SIZE, size); + remain -= size; + } - drm_printf(p, "0x%08x 0x%08x 0x%08x 0x%08x\n", - *(print + 0), *(print + 1), - *(print + 2), *(print + 3)); - } + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) { + snapshot->stamp = ~0ULL; + } else { + snapshot->stamp = xe_mmio_read64_2x32(>->mmio, GUC_PMTIMESTAMP_LO); + xe_force_wake_put(gt_to_fw(gt), fw_ref); } + snapshot->ktime = ktime_get_boottime_ns(); + snapshot->level = log->level; + snapshot->ver_found = guc->fw.versions.found[XE_UC_FW_VER_RELEASE]; + snapshot->ver_want = guc->fw.versions.wanted; + snapshot->path = guc->fw.path; + + return snapshot; +} + +/** + * xe_guc_log_snapshot_print - dump a previously saved copy of the GuC log to some useful location + * @snapshot: a snapshot of the GuC log + * @p: the printer object to output to + */ +void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_printer *p) +{ + size_t remain; + int i; + + if (!snapshot) { + drm_printf(p, "GuC log snapshot not allocated!\n"); + return; + } + + drm_printf(p, "GuC firmware: %s\n", snapshot->path); + drm_printf(p, "GuC version: %u.%u.%u (wanted %u.%u.%u)\n", + snapshot->ver_found.major, snapshot->ver_found.minor, snapshot->ver_found.patch, + snapshot->ver_want.major, snapshot->ver_want.minor, snapshot->ver_want.patch); + drm_printf(p, "Kernel timestamp: 0x%08llX [%llu]\n", snapshot->ktime, snapshot->ktime); + drm_printf(p, "GuC timestamp: 0x%08llX [%llu]\n", snapshot->stamp, snapshot->stamp); + drm_printf(p, "Log level: %u\n", snapshot->level); + + remain = snapshot->size; + for (i = 0; i < snapshot->num_chunks; i++) { + size_t size = min(GUC_LOG_CHUNK_SIZE, remain); + + xe_print_blob_ascii85(p, i ? NULL : "Log data", snapshot->copy[i], 0, size); + remain -= size; + } +} + +/** + * xe_guc_log_print_dmesg - dump a copy of the GuC log to dmesg + * @log: GuC log structure + */ +void xe_guc_log_print_dmesg(struct xe_guc_log *log) +{ + struct xe_gt *gt = log_to_gt(log); + static int g_count; + struct drm_printer ip = xe_gt_info_printer(gt); + struct drm_printer lp = drm_line_printer(&ip, "Capture", ++g_count); + + drm_printf(&lp, "Dumping GuC log for %ps...\n", __builtin_return_address(0)); + + xe_guc_log_print(log, &lp); + + drm_printf(&lp, "Done.\n"); +} + +/** + * xe_guc_log_print - dump a copy of the GuC log to some useful location + * @log: GuC log structure + * @p: the printer object to output to + */ +void xe_guc_log_print(struct xe_guc_log *log, struct drm_printer *p) +{ + struct xe_guc_log_snapshot *snapshot; + + drm_printf(p, "**** GuC Log ****\n"); + + snapshot = xe_guc_log_snapshot_capture(log, false); + drm_printf(p, "CS reference clock: %u\n", log_to_gt(log)->info.reference_clock); + xe_guc_log_snapshot_print(snapshot, p); + xe_guc_log_snapshot_free(snapshot); } int xe_guc_log_init(struct xe_guc_log *log) @@ -96,3 +271,105 @@ int xe_guc_log_init(struct xe_guc_log *log) return 0; } + +ALLOW_ERROR_INJECTION(xe_guc_log_init, ERRNO); /* See xe_pci_probe() */ + +static u32 xe_guc_log_section_size_crash(struct xe_guc_log *log) +{ + return CRASH_BUFFER_SIZE; +} + +static u32 xe_guc_log_section_size_debug(struct xe_guc_log *log) +{ + return DEBUG_BUFFER_SIZE; +} + +/** + * xe_guc_log_section_size_capture - Get capture buffer size within log sections. + * @log: The log object. + * + * This function will return the capture buffer size within log sections. + * + * Return: capture buffer size. + */ +u32 xe_guc_log_section_size_capture(struct xe_guc_log *log) +{ + return CAPTURE_BUFFER_SIZE; +} + +/** + * xe_guc_get_log_buffer_size - Get log buffer size for a type. + * @log: The log object. + * @type: The log buffer type + * + * Return: buffer size. + */ +u32 xe_guc_get_log_buffer_size(struct xe_guc_log *log, enum guc_log_buffer_type type) +{ + switch (type) { + case GUC_LOG_BUFFER_CRASH_DUMP: + return xe_guc_log_section_size_crash(log); + case GUC_LOG_BUFFER_DEBUG: + return xe_guc_log_section_size_debug(log); + case GUC_LOG_BUFFER_CAPTURE: + return xe_guc_log_section_size_capture(log); + } + return 0; +} + +/** + * xe_guc_get_log_buffer_offset - Get offset in log buffer for a type. + * @log: The log object. + * @type: The log buffer type + * + * This function will return the offset in the log buffer for a type. + * Return: buffer offset. + */ +u32 xe_guc_get_log_buffer_offset(struct xe_guc_log *log, enum guc_log_buffer_type type) +{ + enum guc_log_buffer_type i; + u32 offset = PAGE_SIZE;/* for the log_buffer_states */ + + for (i = GUC_LOG_BUFFER_CRASH_DUMP; i < GUC_LOG_BUFFER_TYPE_MAX; ++i) { + if (i == type) + break; + offset += xe_guc_get_log_buffer_size(log, i); + } + + return offset; +} + +/** + * xe_guc_check_log_buf_overflow - Check if log buffer overflowed + * @log: The log object. + * @type: The log buffer type + * @full_cnt: The count of buffer full + * + * This function will check count of buffer full against previous, mismatch + * indicate overflowed. + * Update the sampled_overflow counter, if the 4 bit counter overflowed, add + * up 16 to correct the value. + * + * Return: True if overflowed. + */ +bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, enum guc_log_buffer_type type, + unsigned int full_cnt) +{ + unsigned int prev_full_cnt = log->stats[type].sampled_overflow; + bool overflow = false; + + if (full_cnt != prev_full_cnt) { + overflow = true; + + log->stats[type].overflow = full_cnt; + log->stats[type].sampled_overflow += full_cnt - prev_full_cnt; + + if (full_cnt < prev_full_cnt) { + /* buffer_full_cnt is a 4 bit counter */ + log->stats[type].sampled_overflow += 16; + } + xe_gt_notice(log_to_gt(log), "log buffer overflow\n"); + } + + return overflow; +} diff --git a/drivers/gpu/drm/xe/xe_guc_log.h b/drivers/gpu/drm/xe/xe_guc_log.h index 2d25ab28b4b3ae..5b896f5fafafa5 100644 --- a/drivers/gpu/drm/xe/xe_guc_log.h +++ b/drivers/gpu/drm/xe/xe_guc_log.h @@ -7,8 +7,10 @@ #define _XE_GUC_LOG_H_ #include "xe_guc_log_types.h" +#include "abi/guc_log_abi.h" struct drm_printer; +struct xe_device; #if IS_ENABLED(CONFIG_DRM_XE_LARGE_GUC_BUFFER) #define CRASH_BUFFER_SIZE SZ_1M @@ -17,7 +19,7 @@ struct drm_printer; #else #define CRASH_BUFFER_SIZE SZ_8K #define DEBUG_BUFFER_SIZE SZ_64K -#define CAPTURE_BUFFER_SIZE SZ_16K +#define CAPTURE_BUFFER_SIZE SZ_1M #endif /* * While we're using plain log level in i915, GuC controls are much more... @@ -38,6 +40,10 @@ struct drm_printer; int xe_guc_log_init(struct xe_guc_log *log); void xe_guc_log_print(struct xe_guc_log *log, struct drm_printer *p); +void xe_guc_log_print_dmesg(struct xe_guc_log *log); +struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log, bool atomic); +void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_printer *p); +void xe_guc_log_snapshot_free(struct xe_guc_log_snapshot *snapshot); static inline u32 xe_guc_log_get_level(struct xe_guc_log *log) @@ -45,4 +51,11 @@ xe_guc_log_get_level(struct xe_guc_log *log) return log->level; } +u32 xe_guc_log_section_size_capture(struct xe_guc_log *log); +u32 xe_guc_get_log_buffer_size(struct xe_guc_log *log, enum guc_log_buffer_type type); +u32 xe_guc_get_log_buffer_offset(struct xe_guc_log *log, enum guc_log_buffer_type type); +bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, + enum guc_log_buffer_type type, + unsigned int full_cnt); + #endif diff --git a/drivers/gpu/drm/xe/xe_guc_log_types.h b/drivers/gpu/drm/xe/xe_guc_log_types.h index 125080d138a7ff..b3d5c72ac75247 100644 --- a/drivers/gpu/drm/xe/xe_guc_log_types.h +++ b/drivers/gpu/drm/xe/xe_guc_log_types.h @@ -7,9 +7,37 @@ #define _XE_GUC_LOG_TYPES_H_ #include +#include "abi/guc_log_abi.h" + +#include "xe_uc_fw_types.h" struct xe_bo; +/** + * struct xe_guc_log_snapshot: + * Capture of the GuC log plus various state useful for decoding the log + */ +struct xe_guc_log_snapshot { + /** @size: Size in bytes of the @copy allocation */ + size_t size; + /** @copy: Host memory copy of the log buffer for later dumping, split into chunks */ + void **copy; + /** @num_chunks: Number of chunks within @copy */ + int num_chunks; + /** @ktime: Kernel time the snapshot was taken */ + u64 ktime; + /** @stamp: GuC timestamp at which the snapshot was taken */ + u64 stamp; + /** @level: GuC log verbosity level */ + u32 level; + /** @ver_found: GuC firmware version */ + struct xe_uc_fw_version ver_found; + /** @ver_want: GuC firmware version that driver expected */ + struct xe_uc_fw_version ver_want; + /** @path: Path of GuC firmware blob */ + const char *path; +}; + /** * struct xe_guc_log - GuC log */ @@ -18,6 +46,12 @@ struct xe_guc_log { u32 level; /** @bo: XE BO for GuC log */ struct xe_bo *bo; + /** @stats: logging related stats */ + struct { + u32 sampled_overflow; + u32 overflow; + u32 flush; + } stats[GUC_LOG_BUFFER_TYPE_MAX]; }; #endif diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c index 034b29984d5ed4..e8b9faeaef645f 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.c +++ b/drivers/gpu/drm/xe/xe_guc_pc.c @@ -262,7 +262,7 @@ static void pc_set_manual_rp_ctrl(struct xe_guc_pc *pc, bool enable) u32 state = enable ? RPSWCTL_ENABLE : RPSWCTL_DISABLE; /* Allow/Disallow punit to process software freq requests */ - xe_mmio_write32(gt, RP_CONTROL, state); + xe_mmio_write32(>->mmio, RP_CONTROL, state); } static void pc_set_cur_freq(struct xe_guc_pc *pc, u32 freq) @@ -274,7 +274,7 @@ static void pc_set_cur_freq(struct xe_guc_pc *pc, u32 freq) /* Req freq is in units of 16.66 Mhz */ rpnswreq = REG_FIELD_PREP(REQ_RATIO_MASK, encode_freq(freq)); - xe_mmio_write32(gt, RPNSWREQ, rpnswreq); + xe_mmio_write32(>->mmio, RPNSWREQ, rpnswreq); /* Sleep for a small time to allow pcode to respond */ usleep_range(100, 300); @@ -334,9 +334,9 @@ static void mtl_update_rpe_value(struct xe_guc_pc *pc) u32 reg; if (xe_gt_is_media_type(gt)) - reg = xe_mmio_read32(gt, MTL_MPE_FREQUENCY); + reg = xe_mmio_read32(>->mmio, MTL_MPE_FREQUENCY); else - reg = xe_mmio_read32(gt, MTL_GT_RPE_FREQUENCY); + reg = xe_mmio_read32(>->mmio, MTL_GT_RPE_FREQUENCY); pc->rpe_freq = decode_freq(REG_FIELD_GET(MTL_RPE_MASK, reg)); } @@ -353,9 +353,9 @@ static void tgl_update_rpe_value(struct xe_guc_pc *pc) * PCODE at a different register */ if (xe->info.platform == XE_PVC) - reg = xe_mmio_read32(gt, PVC_RP_STATE_CAP); + reg = xe_mmio_read32(>->mmio, PVC_RP_STATE_CAP); else - reg = xe_mmio_read32(gt, FREQ_INFO_REC); + reg = xe_mmio_read32(>->mmio, FREQ_INFO_REC); pc->rpe_freq = REG_FIELD_GET(RPE_MASK, reg) * GT_FREQUENCY_MULTIPLIER; } @@ -392,10 +392,10 @@ u32 xe_guc_pc_get_act_freq(struct xe_guc_pc *pc) /* When in RC6, actual frequency reported will be 0. */ if (GRAPHICS_VERx100(xe) >= 1270) { - freq = xe_mmio_read32(gt, MTL_MIRROR_TARGET_WP1); + freq = xe_mmio_read32(>->mmio, MTL_MIRROR_TARGET_WP1); freq = REG_FIELD_GET(MTL_CAGF_MASK, freq); } else { - freq = xe_mmio_read32(gt, GT_PERF_STATUS); + freq = xe_mmio_read32(>->mmio, GT_PERF_STATUS); freq = REG_FIELD_GET(CAGF_MASK, freq); } @@ -415,22 +415,24 @@ u32 xe_guc_pc_get_act_freq(struct xe_guc_pc *pc) int xe_guc_pc_get_cur_freq(struct xe_guc_pc *pc, u32 *freq) { struct xe_gt *gt = pc_to_gt(pc); - int ret; + unsigned int fw_ref; /* * GuC SLPC plays with cur freq request when GuCRC is enabled * Block RC6 for a more reliable read. */ - ret = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); - if (ret) - return ret; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { + xe_force_wake_put(gt_to_fw(gt), fw_ref); + return -ETIMEDOUT; + } - *freq = xe_mmio_read32(gt, RPNSWREQ); + *freq = xe_mmio_read32(>->mmio, RPNSWREQ); *freq = REG_FIELD_GET(REQ_RATIO_MASK, *freq); *freq = decode_freq(*freq); - XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); + xe_force_wake_put(gt_to_fw(gt), fw_ref); return 0; } @@ -480,6 +482,7 @@ u32 xe_guc_pc_get_rpn_freq(struct xe_guc_pc *pc) int xe_guc_pc_get_min_freq(struct xe_guc_pc *pc, u32 *freq) { struct xe_gt *gt = pc_to_gt(pc); + unsigned int fw_ref; int ret; mutex_lock(&pc->freq_lock); @@ -493,9 +496,11 @@ int xe_guc_pc_get_min_freq(struct xe_guc_pc *pc, u32 *freq) * GuC SLPC plays with min freq request when GuCRC is enabled * Block RC6 for a more reliable read. */ - ret = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); - if (ret) - goto out; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { + ret = -ETIMEDOUT; + goto fw; + } ret = pc_action_query_task_state(pc); if (ret) @@ -504,7 +509,7 @@ int xe_guc_pc_get_min_freq(struct xe_guc_pc *pc, u32 *freq) *freq = pc_get_min_freq(pc); fw: - XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); + xe_force_wake_put(gt_to_fw(gt), fw_ref); out: mutex_unlock(&pc->freq_lock); return ret; @@ -612,10 +617,10 @@ enum xe_gt_idle_state xe_guc_pc_c_status(struct xe_guc_pc *pc) u32 reg, gt_c_state; if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 1270) { - reg = xe_mmio_read32(gt, MTL_MIRROR_TARGET_WP1); + reg = xe_mmio_read32(>->mmio, MTL_MIRROR_TARGET_WP1); gt_c_state = REG_FIELD_GET(MTL_CC_MASK, reg); } else { - reg = xe_mmio_read32(gt, GT_CORE_STATUS); + reg = xe_mmio_read32(>->mmio, GT_CORE_STATUS); gt_c_state = REG_FIELD_GET(RCN_MASK, reg); } @@ -638,7 +643,7 @@ u64 xe_guc_pc_rc6_residency(struct xe_guc_pc *pc) struct xe_gt *gt = pc_to_gt(pc); u32 reg; - reg = xe_mmio_read32(gt, GT_GFX_RC6); + reg = xe_mmio_read32(>->mmio, GT_GFX_RC6); return reg; } @@ -652,7 +657,7 @@ u64 xe_guc_pc_mc6_residency(struct xe_guc_pc *pc) struct xe_gt *gt = pc_to_gt(pc); u64 reg; - reg = xe_mmio_read32(gt, MTL_MEDIA_MC6); + reg = xe_mmio_read32(>->mmio, MTL_MEDIA_MC6); return reg; } @@ -665,9 +670,9 @@ static void mtl_init_fused_rp_values(struct xe_guc_pc *pc) xe_device_assert_mem_access(pc_to_xe(pc)); if (xe_gt_is_media_type(gt)) - reg = xe_mmio_read32(gt, MTL_MEDIAP_STATE_CAP); + reg = xe_mmio_read32(>->mmio, MTL_MEDIAP_STATE_CAP); else - reg = xe_mmio_read32(gt, MTL_RP_STATE_CAP); + reg = xe_mmio_read32(>->mmio, MTL_RP_STATE_CAP); pc->rp0_freq = decode_freq(REG_FIELD_GET(MTL_RP0_CAP_MASK, reg)); @@ -683,9 +688,9 @@ static void tgl_init_fused_rp_values(struct xe_guc_pc *pc) xe_device_assert_mem_access(pc_to_xe(pc)); if (xe->info.platform == XE_PVC) - reg = xe_mmio_read32(gt, PVC_RP_STATE_CAP); + reg = xe_mmio_read32(>->mmio, PVC_RP_STATE_CAP); else - reg = xe_mmio_read32(gt, RP_STATE_CAP); + reg = xe_mmio_read32(>->mmio, RP_STATE_CAP); pc->rp0_freq = REG_FIELD_GET(RP0_MASK, reg) * GT_FREQUENCY_MULTIPLIER; pc->rpn_freq = REG_FIELD_GET(RPN_MASK, reg) * GT_FREQUENCY_MULTIPLIER; } @@ -855,6 +860,7 @@ int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc) { struct xe_device *xe = pc_to_xe(pc); struct xe_gt *gt = pc_to_gt(pc); + unsigned int fw_ref; int ret = 0; if (xe->info.skip_guc_pc) @@ -864,13 +870,15 @@ int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc) if (ret) return ret; - ret = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); - if (ret) - return ret; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { + xe_force_wake_put(gt_to_fw(gt), fw_ref); + return -ETIMEDOUT; + } xe_gt_idle_disable_c6(gt); - XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); + xe_force_wake_put(gt_to_fw(gt), fw_ref); return 0; } @@ -956,13 +964,16 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) struct xe_device *xe = pc_to_xe(pc); struct xe_gt *gt = pc_to_gt(pc); u32 size = PAGE_ALIGN(sizeof(struct slpc_shared_data)); + unsigned int fw_ref; int ret; xe_gt_assert(gt, xe_device_uc_enabled(xe)); - ret = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); - if (ret) - return ret; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { + xe_force_wake_put(gt_to_fw(gt), fw_ref); + return -ETIMEDOUT; + } if (xe->info.skip_guc_pc) { if (xe->info.platform != XE_PVC) @@ -1005,7 +1016,7 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) ret = pc_action_setup_gucrc(pc, GUCRC_FIRMWARE_CONTROL); out: - XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); + xe_force_wake_put(gt_to_fw(gt), fw_ref); return ret; } @@ -1037,18 +1048,19 @@ static void xe_guc_pc_fini_hw(void *arg) { struct xe_guc_pc *pc = arg; struct xe_device *xe = pc_to_xe(pc); + unsigned int fw_ref; if (xe_device_wedged(xe)) return; - XE_WARN_ON(xe_force_wake_get(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL)); + fw_ref = xe_force_wake_get(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL); xe_guc_pc_gucrc_disable(pc); XE_WARN_ON(xe_guc_pc_stop(pc)); /* Bind requested freq to mert_freq_cap before unload */ pc_set_cur_freq(pc, min(pc_max_freq_cap(pc), pc->rpe_freq)); - xe_force_wake_put(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL); + xe_force_wake_put(gt_to_fw(pc_to_gt(pc)), fw_ref); } /** diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c index ade6162dc25987..8f62de026724cc 100644 --- a/drivers/gpu/drm/xe/xe_guc_relay.c +++ b/drivers/gpu/drm/xe/xe_guc_relay.c @@ -5,6 +5,7 @@ #include #include +#include #include @@ -355,6 +356,7 @@ int xe_guc_relay_init(struct xe_guc_relay *relay) return drmm_add_action_or_reset(&xe->drm, __fini_relay, relay); } +ALLOW_ERROR_INJECTION(xe_guc_relay_init, ERRNO); /* See xe_pci_probe() */ static u32 to_relay_error(int err) { diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 4f5d00aea7168b..6f4a9812b4f4a7 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -27,6 +27,7 @@ #include "xe_gt_clock.h" #include "xe_gt_printk.h" #include "xe_guc.h" +#include "xe_guc_capture.h" #include "xe_guc_ct.h" #include "xe_guc_exec_queue_types.h" #include "xe_guc_id_mgr.h" @@ -716,6 +717,7 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job) struct xe_exec_queue *q = job->q; struct xe_guc *guc = exec_queue_to_guc(q); struct xe_device *xe = guc_to_xe(guc); + struct dma_fence *fence = NULL; bool lr = xe_exec_queue_is_lr(q); xe_assert(xe, !(exec_queue_destroyed(q) || exec_queue_pending_disable(q)) || @@ -733,12 +735,12 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job) if (lr) { xe_sched_job_set_error(job, -EOPNOTSUPP); - return NULL; - } else if (test_and_set_bit(JOB_FLAG_SUBMIT, &job->fence->flags)) { - return job->fence; + dma_fence_put(job->fence); /* Drop ref from xe_sched_job_arm */ } else { - return dma_fence_get(job->fence); + fence = job->fence; } + + return fence; } static void guc_exec_queue_free_job(struct drm_sched_job *drm_job) @@ -749,7 +751,7 @@ static void guc_exec_queue_free_job(struct drm_sched_job *drm_job) xe_sched_job_put(job); } -static int guc_read_stopped(struct xe_guc *guc) +int xe_guc_read_stopped(struct xe_guc *guc) { return atomic_read(&guc->submission_state.stopped); } @@ -765,17 +767,19 @@ static void disable_scheduling_deregister(struct xe_guc *guc, struct xe_exec_queue *q) { MAKE_SCHED_CONTEXT_ACTION(q, DISABLE); - struct xe_device *xe = guc_to_xe(guc); int ret; set_min_preemption_timeout(guc, q); smp_rmb(); - ret = wait_event_timeout(guc->ct.wq, !exec_queue_pending_enable(q) || - guc_read_stopped(guc), HZ * 5); + ret = wait_event_timeout(guc->ct.wq, + (!exec_queue_pending_enable(q) && + !exec_queue_pending_disable(q)) || + xe_guc_read_stopped(guc), + HZ * 5); if (!ret) { struct xe_gpu_scheduler *sched = &q->guc->sched; - drm_warn(&xe->drm, "Pending enable failed to respond"); + xe_gt_warn(q->gt, "Pending enable/disable failed to respond\n"); xe_sched_submission_start(sched); xe_gt_reset_async(q->gt); xe_sched_tdr_queue_imm(sched); @@ -897,7 +901,7 @@ static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w) */ ret = wait_event_timeout(guc->ct.wq, !exec_queue_pending_disable(q) || - guc_read_stopped(guc), HZ * 5); + xe_guc_read_stopped(guc), HZ * 5); if (!ret) { drm_warn(&xe->drm, "Schedule disable failed to respond"); xe_sched_submission_start(sched); @@ -975,8 +979,8 @@ static void enable_scheduling(struct xe_exec_queue *q) ret = wait_event_timeout(guc->ct.wq, !exec_queue_pending_enable(q) || - guc_read_stopped(guc), HZ * 5); - if (!ret || guc_read_stopped(guc)) { + xe_guc_read_stopped(guc), HZ * 5); + if (!ret || xe_guc_read_stopped(guc)) { xe_gt_warn(guc_to_gt(guc), "Schedule enable failed to respond"); set_exec_queue_banned(q); xe_gt_reset_async(q->gt); @@ -1031,6 +1035,8 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) struct xe_gpu_scheduler *sched = &q->guc->sched; struct xe_guc *guc = exec_queue_to_guc(q); const char *process_name = "no process"; + struct xe_device *xe = guc_to_xe(guc); + unsigned int fw_ref; int err = -ETIME; pid_t pid = -1; int i = 0; @@ -1057,6 +1063,22 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) exec_queue_killed_or_banned_or_wedged(q) || exec_queue_destroyed(q); + /* + * If devcoredump not captured and GuC capture for the job is not ready + * do manual capture first and decide later if we need to use it + */ + if (!exec_queue_killed(q) && !xe->devcoredump.captured && + !xe_guc_capture_get_matching_and_lock(job)) { + /* take force wake before engine register manual capture */ + fw_ref = xe_force_wake_get(gt_to_fw(q->gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) + xe_gt_info(q->gt, "failed to get forcewake for coredump capture\n"); + + xe_engine_snapshot_capture_for_job(job); + + xe_force_wake_put(gt_to_fw(q->gt), fw_ref); + } + /* * XXX: Sampling timeout doesn't work in wedged mode as we have to * modify scheduling state to read timestamp. We could read the @@ -1079,9 +1101,10 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) * modifying state */ ret = wait_event_timeout(guc->ct.wq, - !exec_queue_pending_enable(q) || - guc_read_stopped(guc), HZ * 5); - if (!ret || guc_read_stopped(guc)) + (!exec_queue_pending_enable(q) && + !exec_queue_pending_disable(q)) || + xe_guc_read_stopped(guc), HZ * 5); + if (!ret || xe_guc_read_stopped(guc)) goto trigger_reset; /* @@ -1105,8 +1128,8 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) smp_rmb(); ret = wait_event_timeout(guc->ct.wq, !exec_queue_pending_disable(q) || - guc_read_stopped(guc), HZ * 5); - if (!ret || guc_read_stopped(guc)) { + xe_guc_read_stopped(guc), HZ * 5); + if (!ret || xe_guc_read_stopped(guc)) { trigger_reset: if (!ret) xe_gt_warn(guc_to_gt(guc), "Schedule disable failed to respond"); @@ -1295,7 +1318,7 @@ static void suspend_fence_signal(struct xe_exec_queue *q) struct xe_device *xe = guc_to_xe(guc); xe_assert(xe, exec_queue_suspended(q) || exec_queue_killed(q) || - guc_read_stopped(guc)); + xe_guc_read_stopped(guc)); xe_assert(xe, q->guc->suspend_pending); __suspend_fence_signal(q); @@ -1308,10 +1331,10 @@ static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg) if (guc_exec_queue_allowed_to_change_state(q) && !exec_queue_suspended(q) && exec_queue_enabled(q)) { - wait_event(guc->ct.wq, q->guc->resume_time != RESUME_PENDING || - guc_read_stopped(guc)); + wait_event(guc->ct.wq, (q->guc->resume_time != RESUME_PENDING || + xe_guc_read_stopped(guc)) && !exec_queue_pending_disable(q)); - if (!guc_read_stopped(guc)) { + if (!xe_guc_read_stopped(guc)) { s64 since_resume_ms = ktime_ms_delta(ktime_get(), q->guc->resume_time); @@ -1435,7 +1458,7 @@ static int guc_exec_queue_init(struct xe_exec_queue *q) q->entity = &ge->entity; - if (guc_read_stopped(guc)) + if (xe_guc_read_stopped(guc)) xe_sched_stop(sched); mutex_unlock(&guc->submission_state.lock); @@ -1591,7 +1614,7 @@ static int guc_exec_queue_suspend_wait(struct xe_exec_queue *q) ret = wait_event_interruptible_timeout(q->guc->suspend_wait, !READ_ONCE(q->guc->suspend_pending) || exec_queue_killed(q) || - guc_read_stopped(guc), + xe_guc_read_stopped(guc), HZ * 5); if (!ret) { @@ -1717,7 +1740,7 @@ int xe_guc_submit_reset_prepare(struct xe_guc *guc) void xe_guc_submit_reset_wait(struct xe_guc *guc) { wait_event(guc->ct.wq, xe_device_wedged(guc_to_xe(guc)) || - !guc_read_stopped(guc)); + !xe_guc_read_stopped(guc)); } void xe_guc_submit_stop(struct xe_guc *guc) @@ -1726,7 +1749,7 @@ void xe_guc_submit_stop(struct xe_guc *guc) unsigned long index; struct xe_device *xe = guc_to_xe(guc); - xe_assert(xe, guc_read_stopped(guc) == 1); + xe_assert(xe, xe_guc_read_stopped(guc) == 1); mutex_lock(&guc->submission_state.lock); @@ -1770,7 +1793,7 @@ int xe_guc_submit_start(struct xe_guc *guc) unsigned long index; struct xe_device *xe = guc_to_xe(guc); - xe_assert(xe, guc_read_stopped(guc) == 1); + xe_assert(xe, xe_guc_read_stopped(guc) == 1); mutex_lock(&guc->submission_state.lock); atomic_dec(&guc->submission_state.stopped); @@ -1846,16 +1869,29 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, xe_gt_assert(guc_to_gt(guc), runnable_state == 0); xe_gt_assert(guc_to_gt(guc), exec_queue_pending_disable(q)); - clear_exec_queue_pending_disable(q); if (q->guc->suspend_pending) { suspend_fence_signal(q); + clear_exec_queue_pending_disable(q); } else { if (exec_queue_banned(q) || check_timeout) { smp_wmb(); wake_up_all(&guc->ct.wq); } - if (!check_timeout) + if (!check_timeout && exec_queue_destroyed(q)) { + /* + * Make sure to clear the pending_disable only + * after sampling the destroyed state. We want + * to ensure we don't trigger the unregister too + * early with something intending to only + * disable scheduling. The caller doing the + * destroy must wait for an ongoing + * pending_disable before marking as destroyed. + */ + clear_exec_queue_pending_disable(q); deregister_exec_queue(guc, q); + } else { + clear_exec_queue_pending_disable(q); + } } } } @@ -1949,8 +1985,6 @@ int xe_guc_exec_queue_reset_handler(struct xe_guc *guc, u32 *msg, u32 len) xe_gt_info(gt, "Engine reset: engine_class=%s, logical_mask: 0x%x, guc_id=%d", xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); - /* FIXME: Do error capture, most likely async */ - trace_xe_exec_queue_reset(q); /* @@ -1966,6 +2000,36 @@ int xe_guc_exec_queue_reset_handler(struct xe_guc *guc, u32 *msg, u32 len) return 0; } +/* + * xe_guc_error_capture_handler - Handler of GuC captured message + * @guc: The GuC object + * @msg: Point to the message + * @len: The message length + * + * When GuC captured data is ready, GuC will send message + * XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION to host, this function will be + * called 1st to check status before process the data comes with the message. + * + * Returns: error code. 0 if success + */ +int xe_guc_error_capture_handler(struct xe_guc *guc, u32 *msg, u32 len) +{ + u32 status; + + if (unlikely(len != XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION_DATA_LEN)) { + xe_gt_dbg(guc_to_gt(guc), "Invalid length %u", len); + return -EPROTO; + } + + status = msg[0] & XE_GUC_STATE_CAPTURE_EVENT_STATUS_MASK; + if (status == XE_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE) + xe_gt_warn(guc_to_gt(guc), "G2H-Error capture no space"); + + xe_guc_capture_process(guc); + + return 0; +} + int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg, u32 len) { @@ -2180,7 +2244,7 @@ xe_guc_exec_queue_snapshot_print(struct xe_guc_submit_exec_queue_snapshot *snaps if (!snapshot) return; - drm_printf(p, "\nGuC ID: %d\n", snapshot->guc.id); + drm_printf(p, "GuC ID: %d\n", snapshot->guc.id); drm_printf(p, "\tName: %s\n", snapshot->name); drm_printf(p, "\tClass: %d\n", snapshot->class); drm_printf(p, "\tLogical mask: 0x%x\n", snapshot->logical_mask); diff --git a/drivers/gpu/drm/xe/xe_guc_submit.h b/drivers/gpu/drm/xe/xe_guc_submit.h index bdf8c9f3d24a22..9b71a986c6ca69 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.h +++ b/drivers/gpu/drm/xe/xe_guc_submit.h @@ -20,12 +20,14 @@ void xe_guc_submit_stop(struct xe_guc *guc); int xe_guc_submit_start(struct xe_guc *guc); void xe_guc_submit_wedge(struct xe_guc *guc); +int xe_guc_read_stopped(struct xe_guc *guc); int xe_guc_sched_done_handler(struct xe_guc *guc, u32 *msg, u32 len); int xe_guc_deregister_done_handler(struct xe_guc *guc, u32 *msg, u32 len); int xe_guc_exec_queue_reset_handler(struct xe_guc *guc, u32 *msg, u32 len); int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg, u32 len); int xe_guc_exec_queue_reset_failure_handler(struct xe_guc *guc, u32 *msg, u32 len); +int xe_guc_error_capture_handler(struct xe_guc *guc, u32 *msg, u32 len); struct xe_guc_submit_exec_queue_snapshot * xe_guc_exec_queue_snapshot_capture(struct xe_exec_queue *q); diff --git a/drivers/gpu/drm/xe/xe_guc_types.h b/drivers/gpu/drm/xe/xe_guc_types.h index ed150fc09ad04f..fa75f57bf5da82 100644 --- a/drivers/gpu/drm/xe/xe_guc_types.h +++ b/drivers/gpu/drm/xe/xe_guc_types.h @@ -58,6 +58,8 @@ struct xe_guc { struct xe_guc_ads ads; /** @ct: GuC ct */ struct xe_guc_ct ct; + /** @capture: the error-state-capture module's data and objects */ + struct xe_guc_state_capture *capture; /** @pc: GuC Power Conservation */ struct xe_guc_pc pc; /** @dbm: GuC Doorbell Manager */ diff --git a/drivers/gpu/drm/xe/xe_huc.c b/drivers/gpu/drm/xe/xe_huc.c index f5459f97af23f7..6a846e4cb2216d 100644 --- a/drivers/gpu/drm/xe/xe_huc.c +++ b/drivers/gpu/drm/xe/xe_huc.c @@ -229,7 +229,7 @@ bool xe_huc_is_authenticated(struct xe_huc *huc, enum xe_huc_auth_types type) { struct xe_gt *gt = huc_to_gt(huc); - return xe_mmio_read32(gt, huc_auth_modes[type].reg) & huc_auth_modes[type].val; + return xe_mmio_read32(>->mmio, huc_auth_modes[type].reg) & huc_auth_modes[type].val; } int xe_huc_auth(struct xe_huc *huc, enum xe_huc_auth_types type) @@ -268,7 +268,7 @@ int xe_huc_auth(struct xe_huc *huc, enum xe_huc_auth_types type) goto fail; } - ret = xe_mmio_wait32(gt, huc_auth_modes[type].reg, huc_auth_modes[type].val, + ret = xe_mmio_wait32(>->mmio, huc_auth_modes[type].reg, huc_auth_modes[type].val, huc_auth_modes[type].val, 100000, NULL, false); if (ret) { xe_gt_err(gt, "HuC: firmware not verified: %pe\n", ERR_PTR(ret)); @@ -296,19 +296,19 @@ void xe_huc_sanitize(struct xe_huc *huc) void xe_huc_print_info(struct xe_huc *huc, struct drm_printer *p) { struct xe_gt *gt = huc_to_gt(huc); - int err; + unsigned int fw_ref; xe_uc_fw_print(&huc->fw, p); if (!xe_uc_fw_is_enabled(&huc->fw)) return; - err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - if (err) + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) return; drm_printf(p, "\nHuC status: 0x%08x\n", - xe_mmio_read32(gt, HUC_KERNEL_LOAD_INFO)); + xe_mmio_read32(>->mmio, HUC_KERNEL_LOAD_INFO)); - xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); + xe_force_wake_put(gt_to_fw(gt), fw_ref); } diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index c9c3beb3ce8d06..1557acee3523f8 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -12,6 +12,7 @@ #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" +#include "regs/xe_irq_regs.h" #include "xe_assert.h" #include "xe_bo.h" #include "xe_device.h" @@ -23,6 +24,7 @@ #include "xe_gt_printk.h" #include "xe_gt_mcr.h" #include "xe_gt_topology.h" +#include "xe_guc_capture.h" #include "xe_hw_engine_group.h" #include "xe_hw_fence.h" #include "xe_irq.h" @@ -295,7 +297,7 @@ void xe_hw_engine_mmio_write32(struct xe_hw_engine *hwe, reg.addr += hwe->mmio_base; - xe_mmio_write32(hwe->gt, reg, val); + xe_mmio_write32(&hwe->gt->mmio, reg, val); } /** @@ -315,7 +317,7 @@ u32 xe_hw_engine_mmio_read32(struct xe_hw_engine *hwe, struct xe_reg reg) reg.addr += hwe->mmio_base; - return xe_mmio_read32(hwe->gt, reg); + return xe_mmio_read32(&hwe->gt->mmio, reg); } void xe_hw_engine_enable_ring(struct xe_hw_engine *hwe) @@ -324,7 +326,7 @@ void xe_hw_engine_enable_ring(struct xe_hw_engine *hwe) xe_hw_engine_mask_per_class(hwe->gt, XE_ENGINE_CLASS_COMPUTE); if (hwe->class == XE_ENGINE_CLASS_COMPUTE && ccs_mask) - xe_mmio_write32(hwe->gt, RCU_MODE, + xe_mmio_write32(&hwe->gt->mmio, RCU_MODE, _MASKED_BIT_ENABLE(RCU_MODE_CCS_ENABLE)); xe_hw_engine_mmio_write32(hwe, RING_HWSTAM(0), ~0x0); @@ -354,7 +356,7 @@ static bool xe_rtp_cfeg_wmtp_disabled(const struct xe_gt *gt, hwe->class != XE_ENGINE_CLASS_RENDER) return false; - return xe_mmio_read32(hwe->gt, XEHP_FUSE4) & CFEG_WMTP_DISABLE; + return xe_mmio_read32(&hwe->gt->mmio, XEHP_FUSE4) & CFEG_WMTP_DISABLE; } void @@ -460,6 +462,30 @@ hw_engine_setup_default_state(struct xe_hw_engine *hwe) xe_rtp_process_to_sr(&ctx, engine_entries, &hwe->reg_sr); } +static const struct engine_info *find_engine_info(enum xe_engine_class class, int instance) +{ + const struct engine_info *info; + enum xe_hw_engine_id id; + + for (id = 0; id < XE_NUM_HW_ENGINES; ++id) { + info = &engine_infos[id]; + if (info->class == class && info->instance == instance) + return info; + } + + return NULL; +} + +static u16 get_msix_irq_offset(struct xe_gt *gt, enum xe_engine_class class) +{ + /* For MSI-X, hw engines report to offset of engine instance zero */ + const struct engine_info *info = find_engine_info(class, 0); + + xe_gt_assert(gt, info); + + return info ? info->irq_offset : 0; +} + static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe, enum xe_hw_engine_id id) { @@ -479,7 +505,9 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe, hwe->class = info->class; hwe->instance = info->instance; hwe->mmio_base = info->mmio_base; - hwe->irq_offset = info->irq_offset; + hwe->irq_offset = xe_device_has_msix(gt_to_xe(gt)) ? + get_msix_irq_offset(gt, info->class) : + info->irq_offset; hwe->domain = info->domain; hwe->name = info->name; hwe->fence_irq = >->fence_irq[info->class]; @@ -612,7 +640,7 @@ static void read_media_fuses(struct xe_gt *gt) xe_force_wake_assert_held(gt_to_fw(gt), XE_FW_GT); - media_fuse = xe_mmio_read32(gt, GT_VEBOX_VDBOX_DISABLE); + media_fuse = xe_mmio_read32(>->mmio, GT_VEBOX_VDBOX_DISABLE); /* * Pre-Xe_HP platforms had register bits representing absent engines, @@ -657,7 +685,7 @@ static void read_copy_fuses(struct xe_gt *gt) xe_force_wake_assert_held(gt_to_fw(gt), XE_FW_GT); - bcs_mask = xe_mmio_read32(gt, MIRROR_FUSE3); + bcs_mask = xe_mmio_read32(>->mmio, MIRROR_FUSE3); bcs_mask = REG_FIELD_GET(MEML3_EN_MASK, bcs_mask); /* BCS0 is always present; only BCS1-BCS8 may be fused off */ @@ -704,7 +732,7 @@ static void read_compute_fuses_from_reg(struct xe_gt *gt) struct xe_device *xe = gt_to_xe(gt); u32 ccs_mask; - ccs_mask = xe_mmio_read32(gt, XEHP_FUSE4); + ccs_mask = xe_mmio_read32(>->mmio, XEHP_FUSE4); ccs_mask = REG_FIELD_GET(CCS_EN_MASK, ccs_mask); for (int i = XE_HW_ENGINE_CCS0, j = 0; i <= XE_HW_ENGINE_CCS3; ++i, ++j) { @@ -742,8 +770,8 @@ static void check_gsc_availability(struct xe_gt *gt) gt->info.engine_mask &= ~BIT(XE_HW_ENGINE_GSCCS0); /* interrupts where previously enabled, so turn them off */ - xe_mmio_write32(gt, GUNIT_GSC_INTR_ENABLE, 0); - xe_mmio_write32(gt, GUNIT_GSC_INTR_MASK, ~0); + xe_mmio_write32(>->mmio, GUNIT_GSC_INTR_ENABLE, 0); + xe_mmio_write32(>->mmio, GUNIT_GSC_INTR_MASK, ~0); drm_info(&xe->drm, "gsccs disabled due to lack of FW\n"); } @@ -798,60 +826,10 @@ void xe_hw_engine_handle_irq(struct xe_hw_engine *hwe, u16 intr_vec) xe_hw_fence_irq_run(hwe->fence_irq); } -static bool -is_slice_common_per_gslice(struct xe_device *xe) -{ - return GRAPHICS_VERx100(xe) >= 1255; -} - -static void -xe_hw_engine_snapshot_instdone_capture(struct xe_hw_engine *hwe, - struct xe_hw_engine_snapshot *snapshot) -{ - struct xe_gt *gt = hwe->gt; - struct xe_device *xe = gt_to_xe(gt); - unsigned int dss; - u16 group, instance; - - snapshot->reg.instdone.ring = xe_hw_engine_mmio_read32(hwe, RING_INSTDONE(0)); - - if (snapshot->hwe->class != XE_ENGINE_CLASS_RENDER) - return; - - if (is_slice_common_per_gslice(xe) == false) { - snapshot->reg.instdone.slice_common[0] = - xe_mmio_read32(gt, SC_INSTDONE); - snapshot->reg.instdone.slice_common_extra[0] = - xe_mmio_read32(gt, SC_INSTDONE_EXTRA); - snapshot->reg.instdone.slice_common_extra2[0] = - xe_mmio_read32(gt, SC_INSTDONE_EXTRA2); - } else { - for_each_geometry_dss(dss, gt, group, instance) { - snapshot->reg.instdone.slice_common[dss] = - xe_gt_mcr_unicast_read(gt, XEHPG_SC_INSTDONE, group, instance); - snapshot->reg.instdone.slice_common_extra[dss] = - xe_gt_mcr_unicast_read(gt, XEHPG_SC_INSTDONE_EXTRA, group, instance); - snapshot->reg.instdone.slice_common_extra2[dss] = - xe_gt_mcr_unicast_read(gt, XEHPG_SC_INSTDONE_EXTRA2, group, instance); - } - } - - for_each_geometry_dss(dss, gt, group, instance) { - snapshot->reg.instdone.sampler[dss] = - xe_gt_mcr_unicast_read(gt, SAMPLER_INSTDONE, group, instance); - snapshot->reg.instdone.row[dss] = - xe_gt_mcr_unicast_read(gt, ROW_INSTDONE, group, instance); - - if (GRAPHICS_VERx100(xe) >= 1255) - snapshot->reg.instdone.geom_svg[dss] = - xe_gt_mcr_unicast_read(gt, XEHPG_INSTDONE_GEOM_SVGUNIT, - group, instance); - } -} - /** * xe_hw_engine_snapshot_capture - Take a quick snapshot of the HW Engine. * @hwe: Xe HW Engine. + * @job: The job object. * * This can be printed out in a later stage like during dev_coredump * analysis. @@ -860,11 +838,10 @@ xe_hw_engine_snapshot_instdone_capture(struct xe_hw_engine *hwe, * caller, using `xe_hw_engine_snapshot_free`. */ struct xe_hw_engine_snapshot * -xe_hw_engine_snapshot_capture(struct xe_hw_engine *hwe) +xe_hw_engine_snapshot_capture(struct xe_hw_engine *hwe, struct xe_sched_job *job) { struct xe_hw_engine_snapshot *snapshot; - size_t len; - u64 val; + struct __guc_capture_parsed_output *node; if (!xe_hw_engine_is_valid(hwe)) return NULL; @@ -874,28 +851,6 @@ xe_hw_engine_snapshot_capture(struct xe_hw_engine *hwe) if (!snapshot) return NULL; - /* Because XE_MAX_DSS_FUSE_BITS is defined in xe_gt_types.h and it - * includes xe_hw_engine_types.h the length of this 3 registers can't be - * set in struct xe_hw_engine_snapshot, so here doing additional - * allocations. - */ - len = (XE_MAX_DSS_FUSE_BITS * sizeof(u32)); - snapshot->reg.instdone.slice_common = kzalloc(len, GFP_ATOMIC); - snapshot->reg.instdone.slice_common_extra = kzalloc(len, GFP_ATOMIC); - snapshot->reg.instdone.slice_common_extra2 = kzalloc(len, GFP_ATOMIC); - snapshot->reg.instdone.sampler = kzalloc(len, GFP_ATOMIC); - snapshot->reg.instdone.row = kzalloc(len, GFP_ATOMIC); - snapshot->reg.instdone.geom_svg = kzalloc(len, GFP_ATOMIC); - if (!snapshot->reg.instdone.slice_common || - !snapshot->reg.instdone.slice_common_extra || - !snapshot->reg.instdone.slice_common_extra2 || - !snapshot->reg.instdone.sampler || - !snapshot->reg.instdone.row || - !snapshot->reg.instdone.geom_svg) { - xe_hw_engine_snapshot_free(snapshot); - return NULL; - } - snapshot->name = kstrdup(hwe->name, GFP_ATOMIC); snapshot->hwe = hwe; snapshot->logical_instance = hwe->logical_instance; @@ -903,157 +858,32 @@ xe_hw_engine_snapshot_capture(struct xe_hw_engine *hwe) snapshot->forcewake.ref = xe_force_wake_ref(gt_to_fw(hwe->gt), hwe->domain); snapshot->mmio_base = hwe->mmio_base; + snapshot->kernel_reserved = xe_hw_engine_is_reserved(hwe); /* no more VF accessible data below this point */ if (IS_SRIOV_VF(gt_to_xe(hwe->gt))) return snapshot; - snapshot->reg.ring_execlist_status = - xe_hw_engine_mmio_read32(hwe, RING_EXECLIST_STATUS_LO(0)); - val = xe_hw_engine_mmio_read32(hwe, RING_EXECLIST_STATUS_HI(0)); - snapshot->reg.ring_execlist_status |= val << 32; - - snapshot->reg.ring_execlist_sq_contents = - xe_hw_engine_mmio_read32(hwe, RING_EXECLIST_SQ_CONTENTS_LO(0)); - val = xe_hw_engine_mmio_read32(hwe, RING_EXECLIST_SQ_CONTENTS_HI(0)); - snapshot->reg.ring_execlist_sq_contents |= val << 32; - - snapshot->reg.ring_acthd = xe_hw_engine_mmio_read32(hwe, RING_ACTHD(0)); - val = xe_hw_engine_mmio_read32(hwe, RING_ACTHD_UDW(0)); - snapshot->reg.ring_acthd |= val << 32; - - snapshot->reg.ring_bbaddr = xe_hw_engine_mmio_read32(hwe, RING_BBADDR(0)); - val = xe_hw_engine_mmio_read32(hwe, RING_BBADDR_UDW(0)); - snapshot->reg.ring_bbaddr |= val << 32; - - snapshot->reg.ring_dma_fadd = - xe_hw_engine_mmio_read32(hwe, RING_DMA_FADD(0)); - val = xe_hw_engine_mmio_read32(hwe, RING_DMA_FADD_UDW(0)); - snapshot->reg.ring_dma_fadd |= val << 32; - - snapshot->reg.ring_hwstam = xe_hw_engine_mmio_read32(hwe, RING_HWSTAM(0)); - snapshot->reg.ring_hws_pga = xe_hw_engine_mmio_read32(hwe, RING_HWS_PGA(0)); - snapshot->reg.ring_start = xe_hw_engine_mmio_read32(hwe, RING_START(0)); - if (GRAPHICS_VERx100(hwe->gt->tile->xe) >= 2000) { - val = xe_hw_engine_mmio_read32(hwe, RING_START_UDW(0)); - snapshot->reg.ring_start |= val << 32; - } - if (xe_gt_has_indirect_ring_state(hwe->gt)) { - snapshot->reg.indirect_ring_state = - xe_hw_engine_mmio_read32(hwe, INDIRECT_RING_STATE(0)); - } - - snapshot->reg.ring_head = - xe_hw_engine_mmio_read32(hwe, RING_HEAD(0)) & HEAD_ADDR; - snapshot->reg.ring_tail = - xe_hw_engine_mmio_read32(hwe, RING_TAIL(0)) & TAIL_ADDR; - snapshot->reg.ring_ctl = xe_hw_engine_mmio_read32(hwe, RING_CTL(0)); - snapshot->reg.ring_mi_mode = - xe_hw_engine_mmio_read32(hwe, RING_MI_MODE(0)); - snapshot->reg.ring_mode = xe_hw_engine_mmio_read32(hwe, RING_MODE(0)); - snapshot->reg.ring_imr = xe_hw_engine_mmio_read32(hwe, RING_IMR(0)); - snapshot->reg.ring_esr = xe_hw_engine_mmio_read32(hwe, RING_ESR(0)); - snapshot->reg.ring_emr = xe_hw_engine_mmio_read32(hwe, RING_EMR(0)); - snapshot->reg.ring_eir = xe_hw_engine_mmio_read32(hwe, RING_EIR(0)); - snapshot->reg.ipehr = xe_hw_engine_mmio_read32(hwe, RING_IPEHR(0)); - xe_hw_engine_snapshot_instdone_capture(hwe, snapshot); - - if (snapshot->hwe->class == XE_ENGINE_CLASS_COMPUTE) - snapshot->reg.rcu_mode = xe_mmio_read32(hwe->gt, RCU_MODE); - - return snapshot; -} - -static void -xe_hw_engine_snapshot_instdone_print(struct xe_hw_engine_snapshot *snapshot, struct drm_printer *p) -{ - struct xe_gt *gt = snapshot->hwe->gt; - struct xe_device *xe = gt_to_xe(gt); - u16 group, instance; - unsigned int dss; - - drm_printf(p, "\tRING_INSTDONE: 0x%08x\n", snapshot->reg.instdone.ring); - - if (snapshot->hwe->class != XE_ENGINE_CLASS_RENDER) - return; - - if (is_slice_common_per_gslice(xe) == false) { - drm_printf(p, "\tSC_INSTDONE[0]: 0x%08x\n", - snapshot->reg.instdone.slice_common[0]); - drm_printf(p, "\tSC_INSTDONE_EXTRA[0]: 0x%08x\n", - snapshot->reg.instdone.slice_common_extra[0]); - drm_printf(p, "\tSC_INSTDONE_EXTRA2[0]: 0x%08x\n", - snapshot->reg.instdone.slice_common_extra2[0]); - } else { - for_each_geometry_dss(dss, gt, group, instance) { - drm_printf(p, "\tSC_INSTDONE[%u]: 0x%08x\n", dss, - snapshot->reg.instdone.slice_common[dss]); - drm_printf(p, "\tSC_INSTDONE_EXTRA[%u]: 0x%08x\n", dss, - snapshot->reg.instdone.slice_common_extra[dss]); - drm_printf(p, "\tSC_INSTDONE_EXTRA2[%u]: 0x%08x\n", dss, - snapshot->reg.instdone.slice_common_extra2[dss]); + if (job) { + /* If got guc capture, set source to GuC */ + node = xe_guc_capture_get_matching_and_lock(job); + if (node) { + struct xe_device *xe = gt_to_xe(hwe->gt); + struct xe_devcoredump *coredump = &xe->devcoredump; + + coredump->snapshot.matched_node = node; + snapshot->source = XE_ENGINE_CAPTURE_SOURCE_GUC; + xe_gt_dbg(hwe->gt, "Found and locked GuC-err-capture node"); + return snapshot; } } - for_each_geometry_dss(dss, gt, group, instance) { - drm_printf(p, "\tSAMPLER_INSTDONE[%u]: 0x%08x\n", dss, - snapshot->reg.instdone.sampler[dss]); - drm_printf(p, "\tROW_INSTDONE[%u]: 0x%08x\n", dss, - snapshot->reg.instdone.row[dss]); - - if (GRAPHICS_VERx100(xe) >= 1255) - drm_printf(p, "\tINSTDONE_GEOM_SVGUNIT[%u]: 0x%08x\n", - dss, snapshot->reg.instdone.geom_svg[dss]); - } -} + /* otherwise, do manual capture */ + xe_engine_manual_capture(hwe, snapshot); + snapshot->source = XE_ENGINE_CAPTURE_SOURCE_MANUAL; + xe_gt_dbg(hwe->gt, "Proceeding with manual engine snapshot"); -/** - * xe_hw_engine_snapshot_print - Print out a given Xe HW Engine snapshot. - * @snapshot: Xe HW Engine snapshot object. - * @p: drm_printer where it will be printed out. - * - * This function prints out a given Xe HW Engine snapshot object. - */ -void xe_hw_engine_snapshot_print(struct xe_hw_engine_snapshot *snapshot, - struct drm_printer *p) -{ - if (!snapshot) - return; - - drm_printf(p, "%s (physical), logical instance=%d\n", - snapshot->name ? snapshot->name : "", - snapshot->logical_instance); - drm_printf(p, "\tForcewake: domain 0x%x, ref %d\n", - snapshot->forcewake.domain, snapshot->forcewake.ref); - drm_printf(p, "\tHWSTAM: 0x%08x\n", snapshot->reg.ring_hwstam); - drm_printf(p, "\tRING_HWS_PGA: 0x%08x\n", snapshot->reg.ring_hws_pga); - drm_printf(p, "\tRING_EXECLIST_STATUS: 0x%016llx\n", - snapshot->reg.ring_execlist_status); - drm_printf(p, "\tRING_EXECLIST_SQ_CONTENTS: 0x%016llx\n", - snapshot->reg.ring_execlist_sq_contents); - drm_printf(p, "\tRING_START: 0x%016llx\n", snapshot->reg.ring_start); - drm_printf(p, "\tRING_HEAD: 0x%08x\n", snapshot->reg.ring_head); - drm_printf(p, "\tRING_TAIL: 0x%08x\n", snapshot->reg.ring_tail); - drm_printf(p, "\tRING_CTL: 0x%08x\n", snapshot->reg.ring_ctl); - drm_printf(p, "\tRING_MI_MODE: 0x%08x\n", snapshot->reg.ring_mi_mode); - drm_printf(p, "\tRING_MODE: 0x%08x\n", - snapshot->reg.ring_mode); - drm_printf(p, "\tRING_IMR: 0x%08x\n", snapshot->reg.ring_imr); - drm_printf(p, "\tRING_ESR: 0x%08x\n", snapshot->reg.ring_esr); - drm_printf(p, "\tRING_EMR: 0x%08x\n", snapshot->reg.ring_emr); - drm_printf(p, "\tRING_EIR: 0x%08x\n", snapshot->reg.ring_eir); - drm_printf(p, "\tACTHD: 0x%016llx\n", snapshot->reg.ring_acthd); - drm_printf(p, "\tBBADDR: 0x%016llx\n", snapshot->reg.ring_bbaddr); - drm_printf(p, "\tDMA_FADDR: 0x%016llx\n", snapshot->reg.ring_dma_fadd); - drm_printf(p, "\tINDIRECT_RING_STATE: 0x%08x\n", - snapshot->reg.indirect_ring_state); - drm_printf(p, "\tIPEHR: 0x%08x\n", snapshot->reg.ipehr); - xe_hw_engine_snapshot_instdone_print(snapshot, p); - - if (snapshot->hwe->class == XE_ENGINE_CLASS_COMPUTE) - drm_printf(p, "\tRCU_MODE: 0x%08x\n", - snapshot->reg.rcu_mode); - drm_puts(p, "\n"); + return snapshot; } /** @@ -1065,15 +895,18 @@ void xe_hw_engine_snapshot_print(struct xe_hw_engine_snapshot *snapshot, */ void xe_hw_engine_snapshot_free(struct xe_hw_engine_snapshot *snapshot) { + struct xe_gt *gt; if (!snapshot) return; - kfree(snapshot->reg.instdone.slice_common); - kfree(snapshot->reg.instdone.slice_common_extra); - kfree(snapshot->reg.instdone.slice_common_extra2); - kfree(snapshot->reg.instdone.sampler); - kfree(snapshot->reg.instdone.row); - kfree(snapshot->reg.instdone.geom_svg); + gt = snapshot->hwe->gt; + /* + * xe_guc_capture_put_matched_nodes is called here and from + * xe_devcoredump_snapshot_free, to cover the 2 calling paths + * of hw_engines - debugfs and devcoredump free. + */ + xe_guc_capture_put_matched_nodes(>->uc.guc); + kfree(snapshot->name); kfree(snapshot); } @@ -1089,8 +922,8 @@ void xe_hw_engine_print(struct xe_hw_engine *hwe, struct drm_printer *p) { struct xe_hw_engine_snapshot *snapshot; - snapshot = xe_hw_engine_snapshot_capture(hwe); - xe_hw_engine_snapshot_print(snapshot, p); + snapshot = xe_hw_engine_snapshot_capture(hwe, NULL); + xe_engine_snapshot_print(snapshot, p); xe_hw_engine_snapshot_free(snapshot); } @@ -1150,7 +983,7 @@ const char *xe_hw_engine_class_to_str(enum xe_engine_class class) u64 xe_hw_engine_read_timestamp(struct xe_hw_engine *hwe) { - return xe_mmio_read64_2x32(hwe->gt, RING_TIMESTAMP(hwe->mmio_base)); + return xe_mmio_read64_2x32(&hwe->gt->mmio, RING_TIMESTAMP(hwe->mmio_base)); } enum xe_force_wake_domains xe_hw_engine_to_fw_domain(struct xe_hw_engine *hwe) diff --git a/drivers/gpu/drm/xe/xe_hw_engine.h b/drivers/gpu/drm/xe/xe_hw_engine.h index 022819a4a8ebb1..da0a6922a26f36 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.h +++ b/drivers/gpu/drm/xe/xe_hw_engine.h @@ -11,6 +11,7 @@ struct drm_printer; struct drm_xe_engine_class_instance; struct xe_device; +struct xe_sched_job; #ifdef CONFIG_DRM_XE_JOB_TIMEOUT_MIN #define XE_HW_ENGINE_JOB_TIMEOUT_MIN CONFIG_DRM_XE_JOB_TIMEOUT_MIN @@ -54,12 +55,9 @@ void xe_hw_engine_handle_irq(struct xe_hw_engine *hwe, u16 intr_vec); void xe_hw_engine_enable_ring(struct xe_hw_engine *hwe); u32 xe_hw_engine_mask_per_class(struct xe_gt *gt, enum xe_engine_class engine_class); - struct xe_hw_engine_snapshot * -xe_hw_engine_snapshot_capture(struct xe_hw_engine *hwe); +xe_hw_engine_snapshot_capture(struct xe_hw_engine *hwe, struct xe_sched_job *job); void xe_hw_engine_snapshot_free(struct xe_hw_engine_snapshot *snapshot); -void xe_hw_engine_snapshot_print(struct xe_hw_engine_snapshot *snapshot, - struct drm_printer *p); void xe_hw_engine_print(struct xe_hw_engine *hwe, struct drm_printer *p); void xe_hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe); diff --git a/drivers/gpu/drm/xe/xe_hw_engine_types.h b/drivers/gpu/drm/xe/xe_hw_engine_types.h index 8be6d420ece40b..719f27ef00a564 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine_types.h +++ b/drivers/gpu/drm/xe/xe_hw_engine_types.h @@ -152,6 +152,11 @@ struct xe_hw_engine { struct xe_hw_engine_group *hw_engine_group; }; +enum xe_hw_engine_snapshot_source_id { + XE_ENGINE_CAPTURE_SOURCE_MANUAL, + XE_ENGINE_CAPTURE_SOURCE_GUC +}; + /** * struct xe_hw_engine_snapshot - Hardware engine snapshot * @@ -160,6 +165,8 @@ struct xe_hw_engine { struct xe_hw_engine_snapshot { /** @name: name of the hw engine */ char *name; + /** @source: Data source, either manual or GuC */ + enum xe_hw_engine_snapshot_source_id source; /** @hwe: hw engine */ struct xe_hw_engine *hwe; /** @logical_instance: logical instance of this hw engine */ @@ -173,65 +180,8 @@ struct xe_hw_engine_snapshot { } forcewake; /** @mmio_base: MMIO base address of this hw engine*/ u32 mmio_base; - /** @reg: Useful MMIO register snapshot */ - struct { - /** @reg.ring_execlist_status: RING_EXECLIST_STATUS */ - u64 ring_execlist_status; - /** @reg.ring_execlist_sq_contents: RING_EXECLIST_SQ_CONTENTS */ - u64 ring_execlist_sq_contents; - /** @reg.ring_acthd: RING_ACTHD */ - u64 ring_acthd; - /** @reg.ring_bbaddr: RING_BBADDR */ - u64 ring_bbaddr; - /** @reg.ring_dma_fadd: RING_DMA_FADD */ - u64 ring_dma_fadd; - /** @reg.ring_hwstam: RING_HWSTAM */ - u32 ring_hwstam; - /** @reg.ring_hws_pga: RING_HWS_PGA */ - u32 ring_hws_pga; - /** @reg.ring_start: RING_START */ - u64 ring_start; - /** @reg.ring_head: RING_HEAD */ - u32 ring_head; - /** @reg.ring_tail: RING_TAIL */ - u32 ring_tail; - /** @reg.ring_ctl: RING_CTL */ - u32 ring_ctl; - /** @reg.ring_mi_mode: RING_MI_MODE */ - u32 ring_mi_mode; - /** @reg.ring_mode: RING_MODE */ - u32 ring_mode; - /** @reg.ring_imr: RING_IMR */ - u32 ring_imr; - /** @reg.ring_esr: RING_ESR */ - u32 ring_esr; - /** @reg.ring_emr: RING_EMR */ - u32 ring_emr; - /** @reg.ring_eir: RING_EIR */ - u32 ring_eir; - /** @reg.indirect_ring_state: INDIRECT_RING_STATE */ - u32 indirect_ring_state; - /** @reg.ipehr: IPEHR */ - u32 ipehr; - /** @reg.rcu_mode: RCU_MODE */ - u32 rcu_mode; - struct { - /** @reg.instdone.ring: RING_INSTDONE */ - u32 ring; - /** @reg.instdone.slice_common: SC_INSTDONE */ - u32 *slice_common; - /** @reg.instdone.slice_common_extra: SC_INSTDONE_EXTRA */ - u32 *slice_common_extra; - /** @reg.instdone.slice_common_extra2: SC_INSTDONE_EXTRA2 */ - u32 *slice_common_extra2; - /** @reg.instdone.sampler: SAMPLER_INSTDONE */ - u32 *sampler; - /** @reg.instdone.row: ROW_INSTDONE */ - u32 *row; - /** @reg.instdone.geom_svg: INSTDONE_GEOM_SVGUNIT */ - u32 *geom_svg; - } instdone; - } reg; + /** @kernel_reserved: Engine reserved, can't be used by userspace */ + bool kernel_reserved; }; #endif diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index aa11728e7e796c..fde56dad3ab7a2 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -149,7 +149,7 @@ static void xe_hwmon_power_max_read(struct xe_hwmon *hwmon, int channel, long *v u64 reg_val, min, max; struct xe_device *xe = hwmon->xe; struct xe_reg rapl_limit, pkg_power_sku; - struct xe_gt *mmio = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); rapl_limit = xe_hwmon_get_reg(hwmon, REG_PKG_RAPL_LIMIT, channel); pkg_power_sku = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel); @@ -190,7 +190,7 @@ static void xe_hwmon_power_max_read(struct xe_hwmon *hwmon, int channel, long *v static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long value) { - struct xe_gt *mmio = xe_root_mmio_gt(hwmon->xe); + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); int ret = 0; u64 reg_val; struct xe_reg rapl_limit; @@ -222,7 +222,7 @@ static int xe_hwmon_power_max_write(struct xe_hwmon *hwmon, int channel, long va static void xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, int channel, long *value) { - struct xe_gt *mmio = xe_root_mmio_gt(hwmon->xe); + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); struct xe_reg reg = xe_hwmon_get_reg(hwmon, REG_PKG_POWER_SKU, channel); u64 reg_val; @@ -259,7 +259,7 @@ static void xe_hwmon_power_rated_max_read(struct xe_hwmon *hwmon, int channel, l static void xe_hwmon_energy_get(struct xe_hwmon *hwmon, int channel, long *energy) { - struct xe_gt *mmio = xe_root_mmio_gt(hwmon->xe); + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); struct xe_hwmon_energy_info *ei = &hwmon->ei[channel]; u64 reg_val; @@ -282,7 +282,7 @@ xe_hwmon_power_max_interval_show(struct device *dev, struct device_attribute *at char *buf) { struct xe_hwmon *hwmon = dev_get_drvdata(dev); - struct xe_gt *mmio = xe_root_mmio_gt(hwmon->xe); + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); u32 x, y, x_w = 2; /* 2 bits */ u64 r, tau4, out; int sensor_index = to_sensor_dev_attr(attr)->index; @@ -323,7 +323,7 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a const char *buf, size_t count) { struct xe_hwmon *hwmon = dev_get_drvdata(dev); - struct xe_gt *mmio = xe_root_mmio_gt(hwmon->xe); + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); u32 x, y, rxy, x_w = 2; /* 2 bits */ u64 tau4, r, max_win; unsigned long val; @@ -498,7 +498,7 @@ static int xe_hwmon_power_curr_crit_write(struct xe_hwmon *hwmon, int channel, static void xe_hwmon_get_voltage(struct xe_hwmon *hwmon, int channel, long *value) { - struct xe_gt *mmio = xe_root_mmio_gt(hwmon->xe); + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); u64 reg_val; reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_GT_PERF_STATUS, channel)); @@ -781,7 +781,7 @@ static const struct hwmon_chip_info hwmon_chip_info = { static void xe_hwmon_get_preregistration_info(struct xe_device *xe) { - struct xe_gt *mmio = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); struct xe_hwmon *hwmon = xe->hwmon; long energy; u64 val_sku_unit = 0; diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c index 5f2c368c35adb1..b7995ebd54abde 100644 --- a/drivers/gpu/drm/xe/xe_irq.c +++ b/drivers/gpu/drm/xe/xe_irq.c @@ -10,8 +10,7 @@ #include #include "display/xe_display.h" -#include "regs/xe_gt_regs.h" -#include "regs/xe_regs.h" +#include "regs/xe_irq_regs.h" #include "xe_device.h" #include "xe_drv.h" #include "xe_gsc_proxy.h" @@ -30,14 +29,14 @@ #define IIR(offset) XE_REG(offset + 0x8) #define IER(offset) XE_REG(offset + 0xc) -static void assert_iir_is_zero(struct xe_gt *mmio, struct xe_reg reg) +static void assert_iir_is_zero(struct xe_mmio *mmio, struct xe_reg reg) { u32 val = xe_mmio_read32(mmio, reg); if (val == 0) return; - drm_WARN(>_to_xe(mmio)->drm, 1, + drm_WARN(&mmio->tile->xe->drm, 1, "Interrupt register 0x%x is not zero: 0x%08x\n", reg.addr, val); xe_mmio_write32(mmio, reg, 0xffffffff); @@ -52,7 +51,7 @@ static void assert_iir_is_zero(struct xe_gt *mmio, struct xe_reg reg) */ static void unmask_and_enable(struct xe_tile *tile, u32 irqregs, u32 bits) { - struct xe_gt *mmio = tile->primary_gt; + struct xe_mmio *mmio = &tile->mmio; /* * If we're just enabling an interrupt now, it shouldn't already @@ -70,7 +69,7 @@ static void unmask_and_enable(struct xe_tile *tile, u32 irqregs, u32 bits) /* Mask and disable all interrupts. */ static void mask_and_disable(struct xe_tile *tile, u32 irqregs) { - struct xe_gt *mmio = tile->primary_gt; + struct xe_mmio *mmio = &tile->mmio; xe_mmio_write32(mmio, IMR(irqregs), ~0); /* Posting read */ @@ -87,7 +86,7 @@ static void mask_and_disable(struct xe_tile *tile, u32 irqregs) static u32 xelp_intr_disable(struct xe_device *xe) { - struct xe_gt *mmio = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); xe_mmio_write32(mmio, GFX_MSTR_IRQ, 0); @@ -103,7 +102,7 @@ static u32 xelp_intr_disable(struct xe_device *xe) static u32 gu_misc_irq_ack(struct xe_device *xe, const u32 master_ctl) { - struct xe_gt *mmio = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); u32 iir; if (!(master_ctl & GU_MISC_IRQ)) @@ -118,7 +117,7 @@ gu_misc_irq_ack(struct xe_device *xe, const u32 master_ctl) static inline void xelp_intr_enable(struct xe_device *xe, bool stall) { - struct xe_gt *mmio = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); xe_mmio_write32(mmio, GFX_MSTR_IRQ, MASTER_IRQ); if (stall) @@ -129,12 +128,13 @@ static inline void xelp_intr_enable(struct xe_device *xe, bool stall) void xe_irq_enable_hwe(struct xe_gt *gt) { struct xe_device *xe = gt_to_xe(gt); + struct xe_mmio *mmio = >->mmio; u32 ccs_mask, bcs_mask; u32 irqs, dmask, smask; u32 gsc_mask = 0; u32 heci_mask = 0; - if (IS_SRIOV_VF(xe) && xe_device_has_memirq(xe)) + if (xe_device_uses_memirq(xe)) return; if (xe_device_uc_enabled(xe)) { @@ -155,35 +155,35 @@ void xe_irq_enable_hwe(struct xe_gt *gt) if (!xe_gt_is_media_type(gt)) { /* Enable interrupts for each engine class */ - xe_mmio_write32(gt, RENDER_COPY_INTR_ENABLE, dmask); + xe_mmio_write32(mmio, RENDER_COPY_INTR_ENABLE, dmask); if (ccs_mask) - xe_mmio_write32(gt, CCS_RSVD_INTR_ENABLE, smask); + xe_mmio_write32(mmio, CCS_RSVD_INTR_ENABLE, smask); /* Unmask interrupts for each engine instance */ - xe_mmio_write32(gt, RCS0_RSVD_INTR_MASK, ~smask); - xe_mmio_write32(gt, BCS_RSVD_INTR_MASK, ~smask); + xe_mmio_write32(mmio, RCS0_RSVD_INTR_MASK, ~smask); + xe_mmio_write32(mmio, BCS_RSVD_INTR_MASK, ~smask); if (bcs_mask & (BIT(1)|BIT(2))) - xe_mmio_write32(gt, XEHPC_BCS1_BCS2_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, XEHPC_BCS1_BCS2_INTR_MASK, ~dmask); if (bcs_mask & (BIT(3)|BIT(4))) - xe_mmio_write32(gt, XEHPC_BCS3_BCS4_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, XEHPC_BCS3_BCS4_INTR_MASK, ~dmask); if (bcs_mask & (BIT(5)|BIT(6))) - xe_mmio_write32(gt, XEHPC_BCS5_BCS6_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, XEHPC_BCS5_BCS6_INTR_MASK, ~dmask); if (bcs_mask & (BIT(7)|BIT(8))) - xe_mmio_write32(gt, XEHPC_BCS7_BCS8_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, XEHPC_BCS7_BCS8_INTR_MASK, ~dmask); if (ccs_mask & (BIT(0)|BIT(1))) - xe_mmio_write32(gt, CCS0_CCS1_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, CCS0_CCS1_INTR_MASK, ~dmask); if (ccs_mask & (BIT(2)|BIT(3))) - xe_mmio_write32(gt, CCS2_CCS3_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, CCS2_CCS3_INTR_MASK, ~dmask); } if (xe_gt_is_media_type(gt) || MEDIA_VER(xe) < 13) { /* Enable interrupts for each engine class */ - xe_mmio_write32(gt, VCS_VECS_INTR_ENABLE, dmask); + xe_mmio_write32(mmio, VCS_VECS_INTR_ENABLE, dmask); /* Unmask interrupts for each engine instance */ - xe_mmio_write32(gt, VCS0_VCS1_INTR_MASK, ~dmask); - xe_mmio_write32(gt, VCS2_VCS3_INTR_MASK, ~dmask); - xe_mmio_write32(gt, VECS0_VECS1_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, VCS0_VCS1_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, VCS2_VCS3_INTR_MASK, ~dmask); + xe_mmio_write32(mmio, VECS0_VECS1_INTR_MASK, ~dmask); /* * the heci2 interrupt is enabled via the same register as the @@ -197,17 +197,17 @@ void xe_irq_enable_hwe(struct xe_gt *gt) } if (gsc_mask) { - xe_mmio_write32(gt, GUNIT_GSC_INTR_ENABLE, gsc_mask | heci_mask); - xe_mmio_write32(gt, GUNIT_GSC_INTR_MASK, ~gsc_mask); + xe_mmio_write32(mmio, GUNIT_GSC_INTR_ENABLE, gsc_mask | heci_mask); + xe_mmio_write32(mmio, GUNIT_GSC_INTR_MASK, ~gsc_mask); } if (heci_mask) - xe_mmio_write32(gt, HECI2_RSVD_INTR_MASK, ~(heci_mask << 16)); + xe_mmio_write32(mmio, HECI2_RSVD_INTR_MASK, ~(heci_mask << 16)); } } static u32 gt_engine_identity(struct xe_device *xe, - struct xe_gt *mmio, + struct xe_mmio *mmio, const unsigned int bank, const unsigned int bit) { @@ -279,7 +279,7 @@ static struct xe_gt *pick_engine_gt(struct xe_tile *tile, return tile->media_gt; default: break; - }; + } fallthrough; default: return tile->primary_gt; @@ -291,7 +291,7 @@ static void gt_irq_handler(struct xe_tile *tile, u32 *identity) { struct xe_device *xe = tile_to_xe(tile); - struct xe_gt *mmio = tile->primary_gt; + struct xe_mmio *mmio = &tile->mmio; unsigned int bank, bit; u16 instance, intr_vec; enum xe_engine_class class; @@ -376,7 +376,7 @@ static irqreturn_t xelp_irq_handler(int irq, void *arg) static u32 dg1_intr_disable(struct xe_device *xe) { - struct xe_gt *mmio = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); u32 val; /* First disable interrupts */ @@ -394,7 +394,7 @@ static u32 dg1_intr_disable(struct xe_device *xe) static void dg1_intr_enable(struct xe_device *xe, bool stall) { - struct xe_gt *mmio = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); xe_mmio_write32(mmio, DG1_MSTR_TILE_INTR, DG1_MSTR_IRQ); if (stall) @@ -431,7 +431,7 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) } for_each_tile(tile, xe, id) { - struct xe_gt *mmio = tile->primary_gt; + struct xe_mmio *mmio = &tile->mmio; if ((master_tile_ctl & DG1_MSTR_TILE(tile->id)) == 0) continue; @@ -474,7 +474,7 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) static void gt_irq_reset(struct xe_tile *tile) { - struct xe_gt *mmio = tile->primary_gt; + struct xe_mmio *mmio = &tile->mmio; u32 ccs_mask = xe_hw_engine_mask_per_class(tile->primary_gt, XE_ENGINE_CLASS_COMPUTE); @@ -504,7 +504,7 @@ static void gt_irq_reset(struct xe_tile *tile) if (ccs_mask & (BIT(0)|BIT(1))) xe_mmio_write32(mmio, CCS0_CCS1_INTR_MASK, ~0); if (ccs_mask & (BIT(2)|BIT(3))) - xe_mmio_write32(mmio, CCS2_CCS3_INTR_MASK, ~0); + xe_mmio_write32(mmio, CCS2_CCS3_INTR_MASK, ~0); if ((tile->media_gt && xe_hw_engine_mask_per_class(tile->media_gt, XE_ENGINE_CLASS_OTHER)) || @@ -547,7 +547,7 @@ static void dg1_irq_reset(struct xe_tile *tile) static void dg1_irq_reset_mstr(struct xe_tile *tile) { - struct xe_gt *mmio = tile->primary_gt; + struct xe_mmio *mmio = &tile->mmio; xe_mmio_write32(mmio, GFX_MSTR_IRQ, ~0); } @@ -566,7 +566,7 @@ static void vf_irq_reset(struct xe_device *xe) for_each_tile(tile, xe, id) { if (xe_device_has_memirq(xe)) - xe_memirq_reset(&tile->sriov.vf.memirq); + xe_memirq_reset(&tile->memirq); else gt_irq_reset(tile); } @@ -609,7 +609,7 @@ static void vf_irq_postinstall(struct xe_device *xe) for_each_tile(tile, xe, id) if (xe_device_has_memirq(xe)) - xe_memirq_postinstall(&tile->sriov.vf.memirq); + xe_memirq_postinstall(&tile->memirq); if (GRAPHICS_VERx100(xe) < 1210) xelp_intr_enable(xe, true); @@ -652,7 +652,7 @@ static irqreturn_t vf_mem_irq_handler(int irq, void *arg) spin_unlock(&xe->irq.lock); for_each_tile(tile, xe, id) - xe_memirq_handler(&tile->sriov.vf.memirq); + xe_memirq_handler(&tile->memirq); return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/xe/xe_lmtt.c b/drivers/gpu/drm/xe/xe_lmtt.c index 8999ac511555f2..a60ceae4c6dd2a 100644 --- a/drivers/gpu/drm/xe/xe_lmtt.c +++ b/drivers/gpu/drm/xe/xe_lmtt.c @@ -193,7 +193,7 @@ static void lmtt_setup_dir_ptr(struct xe_lmtt *lmtt) lmtt_assert(lmtt, xe_bo_is_vram(lmtt->pd->bo)); lmtt_assert(lmtt, IS_ALIGNED(offset, SZ_64K)); - xe_mmio_write32(tile->primary_gt, + xe_mmio_write32(&tile->mmio, GRAPHICS_VER(xe) >= 20 ? XE2_LMEM_CFG : LMEM_CFG, LMEM_EN | REG_FIELD_PREP(LMTT_DIR_PTR, offset / SZ_64K)); } diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index aec7db39c061e6..4f64c7f4e68de4 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -38,24 +38,6 @@ #define LRC_INDIRECT_RING_STATE_SIZE SZ_4K -struct xe_lrc_snapshot { - struct xe_bo *lrc_bo; - void *lrc_snapshot; - unsigned long lrc_size, lrc_offset; - - u32 context_desc; - u32 indirect_context_desc; - u32 head; - struct { - u32 internal; - u32 memory; - } tail; - u32 start_seqno; - u32 seqno; - u32 ctx_timestamp; - u32 ctx_job_timestamp; -}; - static struct xe_device * lrc_to_xe(struct xe_lrc *lrc) { @@ -599,10 +581,10 @@ static void set_context_control(u32 *regs, struct xe_hw_engine *hwe) static void set_memory_based_intr(u32 *regs, struct xe_hw_engine *hwe) { - struct xe_memirq *memirq = >_to_tile(hwe->gt)->sriov.vf.memirq; + struct xe_memirq *memirq = >_to_tile(hwe->gt)->memirq; struct xe_device *xe = gt_to_xe(hwe->gt); - if (!IS_SRIOV_VF(xe) || !xe_device_has_memirq(xe)) + if (!xe_device_uses_memirq(xe)) return; regs[CTX_LRM_INT_MASK_ENABLE] = MI_LOAD_REGISTER_MEM | @@ -613,9 +595,9 @@ static void set_memory_based_intr(u32 *regs, struct xe_hw_engine *hwe) regs[CTX_LRI_INT_REPORT_PTR] = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(2) | MI_LRI_LRM_CS_MMIO | MI_LRI_FORCE_POSTED; regs[CTX_INT_STATUS_REPORT_REG] = RING_INT_STATUS_RPT_PTR(0).addr; - regs[CTX_INT_STATUS_REPORT_PTR] = xe_memirq_status_ptr(memirq); + regs[CTX_INT_STATUS_REPORT_PTR] = xe_memirq_status_ptr(memirq, hwe); regs[CTX_INT_SRC_REPORT_REG] = RING_INT_SRC_RPT_PTR(0).addr; - regs[CTX_INT_SRC_REPORT_PTR] = xe_memirq_source_ptr(memirq); + regs[CTX_INT_SRC_REPORT_PTR] = xe_memirq_source_ptr(memirq, hwe); } static int lrc_ring_mi_mode(struct xe_hw_engine *hwe) diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h index c24542e8931860..40d8f6906d3e41 100644 --- a/drivers/gpu/drm/xe/xe_lrc.h +++ b/drivers/gpu/drm/xe/xe_lrc.h @@ -17,9 +17,26 @@ enum xe_engine_class; struct xe_gt; struct xe_hw_engine; struct xe_lrc; -struct xe_lrc_snapshot; struct xe_vm; +struct xe_lrc_snapshot { + struct xe_bo *lrc_bo; + void *lrc_snapshot; + unsigned long lrc_size, lrc_offset; + + u32 context_desc; + u32 indirect_context_desc; + u32 head; + struct { + u32 internal; + u32 memory; + } tail; + u32 start_seqno; + u32 seqno; + u32 ctx_timestamp; + u32 ctx_job_timestamp; +}; + #define LRC_PPHWSP_SCRATCH_ADDR (0x34 * 4) struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, diff --git a/drivers/gpu/drm/xe/xe_memirq.c b/drivers/gpu/drm/xe/xe_memirq.c index 95b6e9d7b7dbd1..f833da88150a1c 100644 --- a/drivers/gpu/drm/xe/xe_memirq.c +++ b/drivers/gpu/drm/xe/xe_memirq.c @@ -5,8 +5,8 @@ #include -#include "regs/xe_gt_regs.h" #include "regs/xe_guc_regs.h" +#include "regs/xe_irq_regs.h" #include "regs/xe_regs.h" #include "xe_assert.h" @@ -19,15 +19,25 @@ #include "xe_hw_engine.h" #include "xe_map.h" #include "xe_memirq.h" -#include "xe_sriov.h" -#include "xe_sriov_printk.h" #define memirq_assert(m, condition) xe_tile_assert(memirq_to_tile(m), condition) -#define memirq_debug(m, msg...) xe_sriov_dbg_verbose(memirq_to_xe(m), "MEMIRQ: " msg) +#define memirq_printk(m, _level, _fmt, ...) \ + drm_##_level(&memirq_to_xe(m)->drm, "MEMIRQ%u: " _fmt, \ + memirq_to_tile(m)->id, ##__VA_ARGS__) + +#ifdef CONFIG_DRM_XE_DEBUG_MEMIRQ +#define memirq_debug(m, _fmt, ...) memirq_printk(m, dbg, _fmt, ##__VA_ARGS__) +#else +#define memirq_debug(...) +#endif + +#define memirq_err(m, _fmt, ...) memirq_printk(m, err, _fmt, ##__VA_ARGS__) +#define memirq_err_ratelimited(m, _fmt, ...) \ + memirq_printk(m, err_ratelimited, _fmt, ##__VA_ARGS__) static struct xe_tile *memirq_to_tile(struct xe_memirq *memirq) { - return container_of(memirq, struct xe_tile, sriov.vf.memirq); + return container_of(memirq, struct xe_tile, memirq); } static struct xe_device *memirq_to_xe(struct xe_memirq *memirq) @@ -105,6 +115,44 @@ static const char *guc_name(struct xe_guc *guc) * | | * | | * +-----------+ + * + * + * MSI-X use case + * + * When using MSI-X, hw engines report interrupt status and source to engine + * instance 0. For this scenario, in order to differentiate between the + * engines, we need to pass different status/source pointers in the LRC. + * + * The requirements on those pointers are: + * - Interrupt status should be 4KiB aligned + * - Interrupt source should be 64 bytes aligned + * + * To accommodate this, we duplicate the memirq page layout above - + * allocating a page for each engine instance and pass this page in the LRC. + * Note that the same page can be reused for different engine types. + * For example, an LRC executing on CCS #x will have pointers to page #x, + * and an LRC executing on BCS #x will have the same pointers. + * + * :: + * + * 0x0000 +==============================+ <== page for instance 0 (BCS0, CCS0, etc.) + * | Interrupt Status Report Page | + * 0x0400 +==============================+ + * | Interrupt Source Report Page | + * 0x0440 +==============================+ + * | Interrupt Enable Mask | + * +==============================+ + * | Not used | + * 0x1000 +==============================+ <== page for instance 1 (BCS1, CCS1, etc.) + * | Interrupt Status Report Page | + * 0x1400 +==============================+ + * | Interrupt Source Report Page | + * 0x1440 +==============================+ + * | Not used | + * 0x2000 +==============================+ <== page for instance 2 (BCS2, CCS2, etc.) + * | ... | + * +==============================+ + * */ static void __release_xe_bo(struct drm_device *drm, void *arg) @@ -114,18 +162,30 @@ static void __release_xe_bo(struct drm_device *drm, void *arg) xe_bo_unpin_map_no_vm(bo); } +static inline bool hw_reports_to_instance_zero(struct xe_memirq *memirq) +{ + /* + * When the HW engines are configured to use MSI-X, + * they report interrupt status and source to the offset of + * engine instance 0. + */ + return xe_device_has_msix(memirq_to_xe(memirq)); +} + static int memirq_alloc_pages(struct xe_memirq *memirq) { struct xe_device *xe = memirq_to_xe(memirq); struct xe_tile *tile = memirq_to_tile(memirq); + size_t bo_size = hw_reports_to_instance_zero(memirq) ? + XE_HW_ENGINE_MAX_INSTANCE * SZ_4K : SZ_4K; struct xe_bo *bo; int err; - BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_SOURCE_OFFSET, SZ_64)); - BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_STATUS_OFFSET, SZ_4K)); + BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_SOURCE_OFFSET(0), SZ_64)); + BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_STATUS_OFFSET(0), SZ_4K)); /* XXX: convert to managed bo */ - bo = xe_bo_create_pin_map(xe, tile, NULL, SZ_4K, + bo = xe_bo_create_pin_map(xe, tile, NULL, bo_size, ttm_bo_type_kernel, XE_BO_FLAG_SYSTEM | XE_BO_FLAG_GGTT | @@ -140,25 +200,25 @@ static int memirq_alloc_pages(struct xe_memirq *memirq) memirq_assert(memirq, !xe_bo_is_vram(bo)); memirq_assert(memirq, !memirq->bo); - iosys_map_memset(&bo->vmap, 0, 0, SZ_4K); + iosys_map_memset(&bo->vmap, 0, 0, bo_size); memirq->bo = bo; - memirq->source = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_SOURCE_OFFSET); - memirq->status = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_STATUS_OFFSET); + memirq->source = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_SOURCE_OFFSET(0)); + memirq->status = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_STATUS_OFFSET(0)); memirq->mask = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_ENABLE_OFFSET); memirq_assert(memirq, !memirq->source.is_iomem); memirq_assert(memirq, !memirq->status.is_iomem); memirq_assert(memirq, !memirq->mask.is_iomem); - memirq_debug(memirq, "page offsets: source %#x status %#x\n", - xe_memirq_source_ptr(memirq), xe_memirq_status_ptr(memirq)); + memirq_debug(memirq, "page offsets: bo %#x bo_size %zu source %#x status %#x\n", + xe_bo_ggtt_addr(bo), bo_size, XE_MEMIRQ_SOURCE_OFFSET(0), + XE_MEMIRQ_STATUS_OFFSET(0)); return drmm_add_action_or_reset(&xe->drm, __release_xe_bo, memirq->bo); out: - xe_sriov_err(memirq_to_xe(memirq), - "Failed to allocate memirq page (%pe)\n", ERR_PTR(err)); + memirq_err(memirq, "Failed to allocate memirq page (%pe)\n", ERR_PTR(err)); return err; } @@ -178,9 +238,7 @@ static void memirq_set_enable(struct xe_memirq *memirq, bool enable) * * These allocations are managed and will be implicitly released on unload. * - * Note: This function shall be called only by the VF driver. - * - * If this function fails then VF driver won't be able to operate correctly. + * If this function fails then the driver won't be able to operate correctly. * If `Memory Based Interrupts`_ are not used this function will return 0. * * Return: 0 on success or a negative error code on failure. @@ -190,9 +248,7 @@ int xe_memirq_init(struct xe_memirq *memirq) struct xe_device *xe = memirq_to_xe(memirq); int err; - memirq_assert(memirq, IS_SRIOV_VF(xe)); - - if (!xe_device_has_memirq(xe)) + if (!xe_device_uses_memirq(xe)) return 0; err = memirq_alloc_pages(memirq); @@ -205,55 +261,70 @@ int xe_memirq_init(struct xe_memirq *memirq) return 0; } +static u32 __memirq_source_page(struct xe_memirq *memirq, u16 instance) +{ + memirq_assert(memirq, instance <= XE_HW_ENGINE_MAX_INSTANCE); + memirq_assert(memirq, memirq->bo); + + instance = hw_reports_to_instance_zero(memirq) ? instance : 0; + return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET(instance); +} + /** * xe_memirq_source_ptr - Get GGTT's offset of the `Interrupt Source Report Page`_. * @memirq: the &xe_memirq to query + * @hwe: the hw engine for which we want the report page * - * Shall be called only on VF driver when `Memory Based Interrupts`_ are used + * Shall be called when `Memory Based Interrupts`_ are used * and xe_memirq_init() didn't fail. * * Return: GGTT's offset of the `Interrupt Source Report Page`_. */ -u32 xe_memirq_source_ptr(struct xe_memirq *memirq) +u32 xe_memirq_source_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe) { - memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); - memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); + + return __memirq_source_page(memirq, hwe->instance); +} + +static u32 __memirq_status_page(struct xe_memirq *memirq, u16 instance) +{ + memirq_assert(memirq, instance <= XE_HW_ENGINE_MAX_INSTANCE); memirq_assert(memirq, memirq->bo); - return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET; + instance = hw_reports_to_instance_zero(memirq) ? instance : 0; + return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_STATUS_OFFSET(instance); } /** * xe_memirq_status_ptr - Get GGTT's offset of the `Interrupt Status Report Page`_. * @memirq: the &xe_memirq to query + * @hwe: the hw engine for which we want the report page * - * Shall be called only on VF driver when `Memory Based Interrupts`_ are used + * Shall be called when `Memory Based Interrupts`_ are used * and xe_memirq_init() didn't fail. * * Return: GGTT's offset of the `Interrupt Status Report Page`_. */ -u32 xe_memirq_status_ptr(struct xe_memirq *memirq) +u32 xe_memirq_status_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe) { - memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); - memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); - memirq_assert(memirq, memirq->bo); + memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); - return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_STATUS_OFFSET; + return __memirq_status_page(memirq, hwe->instance); } /** * xe_memirq_enable_ptr - Get GGTT's offset of the Interrupt Enable Mask. * @memirq: the &xe_memirq to query * - * Shall be called only on VF driver when `Memory Based Interrupts`_ are used + * Shall be called when `Memory Based Interrupts`_ are used * and xe_memirq_init() didn't fail. * * Return: GGTT's offset of the Interrupt Enable Mask. */ u32 xe_memirq_enable_ptr(struct xe_memirq *memirq) { - memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); - memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); memirq_assert(memirq, memirq->bo); return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_ENABLE_OFFSET; @@ -267,7 +338,7 @@ u32 xe_memirq_enable_ptr(struct xe_memirq *memirq) * Register `Interrupt Source Report Page`_ and `Interrupt Status Report Page`_ * to be used by the GuC when `Memory Based Interrupts`_ are required. * - * Shall be called only on VF driver when `Memory Based Interrupts`_ are used + * Shall be called when `Memory Based Interrupts`_ are used * and xe_memirq_init() didn't fail. * * Return: 0 on success or a negative error code on failure. @@ -279,12 +350,10 @@ int xe_memirq_init_guc(struct xe_memirq *memirq, struct xe_guc *guc) u32 source, status; int err; - memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); - memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); - memirq_assert(memirq, memirq->bo); + memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); - source = xe_memirq_source_ptr(memirq) + offset; - status = xe_memirq_status_ptr(memirq) + offset * SZ_16; + source = __memirq_source_page(memirq, 0) + offset; + status = __memirq_status_page(memirq, 0) + offset * SZ_16; err = xe_guc_self_cfg64(guc, GUC_KLV_SELF_CFG_MEMIRQ_SOURCE_ADDR_KEY, source); @@ -299,9 +368,8 @@ int xe_memirq_init_guc(struct xe_memirq *memirq, struct xe_guc *guc) return 0; failed: - xe_sriov_err(memirq_to_xe(memirq), - "Failed to setup report pages in %s (%pe)\n", - guc_name(guc), ERR_PTR(err)); + memirq_err(memirq, "Failed to setup report pages in %s (%pe)\n", + guc_name(guc), ERR_PTR(err)); return err; } @@ -311,13 +379,12 @@ int xe_memirq_init_guc(struct xe_memirq *memirq, struct xe_guc *guc) * * This is part of the driver IRQ setup flow. * - * This function shall only be used by the VF driver on platforms that use + * This function shall only be used on platforms that use * `Memory Based Interrupts`_. */ void xe_memirq_reset(struct xe_memirq *memirq) { - memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); - memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); if (memirq->bo) memirq_set_enable(memirq, false); @@ -329,13 +396,12 @@ void xe_memirq_reset(struct xe_memirq *memirq) * * This is part of the driver IRQ setup flow. * - * This function shall only be used by the VF driver on platforms that use + * This function shall only be used on platforms that use * `Memory Based Interrupts`_. */ void xe_memirq_postinstall(struct xe_memirq *memirq) { - memirq_assert(memirq, IS_SRIOV_VF(memirq_to_xe(memirq))); - memirq_assert(memirq, xe_device_has_memirq(memirq_to_xe(memirq))); + memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); if (memirq->bo) memirq_set_enable(memirq, true); @@ -349,9 +415,9 @@ static bool memirq_received(struct xe_memirq *memirq, struct iosys_map *vector, value = iosys_map_rd(vector, offset, u8); if (value) { if (value != 0xff) - xe_sriov_err_ratelimited(memirq_to_xe(memirq), - "Unexpected memirq value %#x from %s at %u\n", - value, name, offset); + memirq_err_ratelimited(memirq, + "Unexpected memirq value %#x from %s at %u\n", + value, name, offset); iosys_map_wr(vector, offset, u8, 0x00); } @@ -378,6 +444,28 @@ static void memirq_dispatch_guc(struct xe_memirq *memirq, struct iosys_map *stat xe_guc_irq_handler(guc, GUC_INTR_GUC2HOST); } +/** + * xe_memirq_hwe_handler - Check and process interrupts for a specific HW engine. + * @memirq: the &xe_memirq + * @hwe: the hw engine to process + * + * This function reads and dispatches `Memory Based Interrupts` for the provided HW engine. + */ +void xe_memirq_hwe_handler(struct xe_memirq *memirq, struct xe_hw_engine *hwe) +{ + u16 offset = hwe->irq_offset; + u16 instance = hw_reports_to_instance_zero(memirq) ? hwe->instance : 0; + struct iosys_map src_offset = IOSYS_MAP_INIT_OFFSET(&memirq->bo->vmap, + XE_MEMIRQ_SOURCE_OFFSET(instance)); + + if (memirq_received(memirq, &src_offset, offset, "SRC")) { + struct iosys_map status_offset = + IOSYS_MAP_INIT_OFFSET(&memirq->bo->vmap, + XE_MEMIRQ_STATUS_OFFSET(instance) + offset * SZ_16); + memirq_dispatch_engine(memirq, &status_offset, hwe); + } +} + /** * xe_memirq_handler - The `Memory Based Interrupts`_ Handler. * @memirq: the &xe_memirq @@ -405,13 +493,8 @@ void xe_memirq_handler(struct xe_memirq *memirq) if (gt->tile != tile) continue; - for_each_hw_engine(hwe, gt, id) { - if (memirq_received(memirq, &memirq->source, hwe->irq_offset, "SRC")) { - map = IOSYS_MAP_INIT_OFFSET(&memirq->status, - hwe->irq_offset * SZ_16); - memirq_dispatch_engine(memirq, &map, hwe); - } - } + for_each_hw_engine(hwe, gt, id) + xe_memirq_hwe_handler(memirq, hwe); } /* GuC and media GuC (if present) must be checked separately */ diff --git a/drivers/gpu/drm/xe/xe_memirq.h b/drivers/gpu/drm/xe/xe_memirq.h index 2d40d03c309561..06130650e9d622 100644 --- a/drivers/gpu/drm/xe/xe_memirq.h +++ b/drivers/gpu/drm/xe/xe_memirq.h @@ -9,16 +9,18 @@ #include struct xe_guc; +struct xe_hw_engine; struct xe_memirq; int xe_memirq_init(struct xe_memirq *memirq); -u32 xe_memirq_source_ptr(struct xe_memirq *memirq); -u32 xe_memirq_status_ptr(struct xe_memirq *memirq); +u32 xe_memirq_source_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe); +u32 xe_memirq_status_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe); u32 xe_memirq_enable_ptr(struct xe_memirq *memirq); void xe_memirq_reset(struct xe_memirq *memirq); void xe_memirq_postinstall(struct xe_memirq *memirq); +void xe_memirq_hwe_handler(struct xe_memirq *memirq, struct xe_hw_engine *hwe); void xe_memirq_handler(struct xe_memirq *memirq); int xe_memirq_init_guc(struct xe_memirq *memirq, struct xe_guc *guc); diff --git a/drivers/gpu/drm/xe/xe_memirq_types.h b/drivers/gpu/drm/xe/xe_memirq_types.h index 625b6b8736cc42..9d0f6c1cdb9d5c 100644 --- a/drivers/gpu/drm/xe/xe_memirq_types.h +++ b/drivers/gpu/drm/xe/xe_memirq_types.h @@ -11,9 +11,9 @@ struct xe_bo; /* ISR */ -#define XE_MEMIRQ_STATUS_OFFSET 0x0 +#define XE_MEMIRQ_STATUS_OFFSET(inst) ((inst) * SZ_4K + 0x0) /* IIR */ -#define XE_MEMIRQ_SOURCE_OFFSET 0x400 +#define XE_MEMIRQ_SOURCE_OFFSET(inst) ((inst) * SZ_4K + 0x400) /* IMR */ #define XE_MEMIRQ_ENABLE_OFFSET 0x440 diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index cfd31ae49cc1f7..1b97d90aaddaf4 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -209,7 +209,8 @@ static int xe_migrate_prepare_vm(struct xe_tile *tile, struct xe_migrate *m, num_entries * XE_PAGE_SIZE, ttm_bo_type_kernel, XE_BO_FLAG_VRAM_IF_DGFX(tile) | - XE_BO_FLAG_PINNED); + XE_BO_FLAG_PINNED | + XE_BO_FLAG_PAGETABLE); if (IS_ERR(bo)) return PTR_ERR(bo); @@ -1350,6 +1351,7 @@ __xe_migrate_update_pgtables(struct xe_migrate *m, /* For sysmem PTE's, need to map them in our hole.. */ if (!IS_DGFX(xe)) { + u16 pat_index = xe->pat.idx[XE_CACHE_WB]; u32 ptes, ofs; ppgtt_ofs = NUM_KERNEL_PDE - 1; @@ -1409,7 +1411,7 @@ __xe_migrate_update_pgtables(struct xe_migrate *m, pt_bo->update_index = current_update; addr = vm->pt_ops->pte_encode_bo(pt_bo, 0, - XE_CACHE_WB, 0); + pat_index, 0); bb->cs[bb->len++] = lower_32_bits(addr); bb->cs[bb->len++] = upper_32_bits(addr); } diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 3fd462fda6255c..a48f239cad1c59 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -36,13 +36,19 @@ static void tiles_fini(void *arg) /* * On multi-tile devices, partition the BAR space for MMIO on each tile, * possibly accounting for register override on the number of tiles available. + * tile_mmio_size contains both the tile's 4MB register space, as well as + * additional space for the GTT and other (possibly unused) regions). * Resulting memory layout is like below: * * .----------------------. <- tile_count * tile_mmio_size * | .... | * |----------------------| <- 2 * tile_mmio_size + * | tile1 GTT + other | + * |----------------------| <- 1 * tile_mmio_size + 4MB * | tile1->mmio.regs | * |----------------------| <- 1 * tile_mmio_size + * | tile0 GTT + other | + * |----------------------| <- 4MB * | tile0->mmio.regs | * '----------------------' <- 0MB */ @@ -61,16 +67,16 @@ static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) /* Possibly override number of tile based on configuration register */ if (!xe->info.skip_mtcfg) { - struct xe_gt *gt = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); u8 tile_count; u32 mtcfg; /* * Although the per-tile mmio regs are not yet initialized, this - * is fine as it's going to the root gt, that's guaranteed to be - * initialized earlier in xe_mmio_init() + * is fine as it's going to the root tile's mmio, that's + * guaranteed to be initialized earlier in xe_mmio_init() */ - mtcfg = xe_mmio_read64_2x32(gt, XEHP_MTCFG_ADDR); + mtcfg = xe_mmio_read64_2x32(mmio, XEHP_MTCFG_ADDR); tile_count = REG_FIELD_GET(TILE_COUNT, mtcfg) + 1; if (tile_count < xe->info.tile_count) { @@ -90,8 +96,9 @@ static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) regs = xe->mmio.regs; for_each_tile(tile, xe, id) { - tile->mmio.size = tile_mmio_size; + tile->mmio.regs_size = SZ_4M; tile->mmio.regs = regs; + tile->mmio.tile = tile; regs += tile_mmio_size; } } @@ -126,8 +133,9 @@ static void mmio_extension_setup(struct xe_device *xe, size_t tile_mmio_size, regs = xe->mmio.regs + tile_mmio_size * xe->info.tile_count; for_each_tile(tile, xe, id) { - tile->mmio_ext.size = tile_mmio_ext_size; + tile->mmio_ext.regs_size = tile_mmio_ext_size; tile->mmio_ext.regs = regs; + tile->mmio_ext.tile = tile; regs += tile_mmio_ext_size; } } @@ -157,137 +165,132 @@ int xe_mmio_init(struct xe_device *xe) { struct xe_tile *root_tile = xe_device_get_root_tile(xe); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); - const int mmio_bar = 0; /* * Map the entire BAR. * The first 16MB of the BAR, belong to the root tile, and include: * registers (0-4MB), reserved space (4MB-8MB) and GGTT (8MB-16MB). */ - xe->mmio.size = pci_resource_len(pdev, mmio_bar); - xe->mmio.regs = pci_iomap(pdev, mmio_bar, GTTMMADR_BAR); + xe->mmio.size = pci_resource_len(pdev, GTTMMADR_BAR); + xe->mmio.regs = pci_iomap(pdev, GTTMMADR_BAR, 0); if (xe->mmio.regs == NULL) { drm_err(&xe->drm, "failed to map registers\n"); return -EIO; } /* Setup first tile; other tiles (if present) will be setup later. */ - root_tile->mmio.size = SZ_16M; + root_tile->mmio.regs_size = SZ_4M; root_tile->mmio.regs = xe->mmio.regs; + root_tile->mmio.tile = root_tile; return devm_add_action_or_reset(xe->drm.dev, mmio_fini, xe); } -static void mmio_flush_pending_writes(struct xe_gt *gt) +static void mmio_flush_pending_writes(struct xe_mmio *mmio) { #define DUMMY_REG_OFFSET 0x130030 - struct xe_tile *tile = gt_to_tile(gt); int i; - if (tile->xe->info.platform != XE_LUNARLAKE) + if (mmio->tile->xe->info.platform != XE_LUNARLAKE) return; /* 4 dummy writes */ for (i = 0; i < 4; i++) - writel(0, tile->mmio.regs + DUMMY_REG_OFFSET); + writel(0, mmio->regs + DUMMY_REG_OFFSET); } -u8 xe_mmio_read8(struct xe_gt *gt, struct xe_reg reg) +u8 xe_mmio_read8(struct xe_mmio *mmio, struct xe_reg reg) { - struct xe_tile *tile = gt_to_tile(gt); - u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); + u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u8 val; /* Wa_15015404425 */ - mmio_flush_pending_writes(gt); + mmio_flush_pending_writes(mmio); - val = readb((reg.ext ? tile->mmio_ext.regs : tile->mmio.regs) + addr); - trace_xe_reg_rw(gt, false, addr, val, sizeof(val)); + val = readb(mmio->regs + addr); + trace_xe_reg_rw(mmio, false, addr, val, sizeof(val)); return val; } -u16 xe_mmio_read16(struct xe_gt *gt, struct xe_reg reg) +u16 xe_mmio_read16(struct xe_mmio *mmio, struct xe_reg reg) { - struct xe_tile *tile = gt_to_tile(gt); - u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); + u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u16 val; /* Wa_15015404425 */ - mmio_flush_pending_writes(gt); + mmio_flush_pending_writes(mmio); - val = readw((reg.ext ? tile->mmio_ext.regs : tile->mmio.regs) + addr); - trace_xe_reg_rw(gt, false, addr, val, sizeof(val)); + val = readw(mmio->regs + addr); + trace_xe_reg_rw(mmio, false, addr, val, sizeof(val)); return val; } -void xe_mmio_write32(struct xe_gt *gt, struct xe_reg reg, u32 val) +void xe_mmio_write32(struct xe_mmio *mmio, struct xe_reg reg, u32 val) { - struct xe_tile *tile = gt_to_tile(gt); - u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); + u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); - trace_xe_reg_rw(gt, true, addr, val, sizeof(val)); + trace_xe_reg_rw(mmio, true, addr, val, sizeof(val)); - if (!reg.vf && IS_SRIOV_VF(gt_to_xe(gt))) - xe_gt_sriov_vf_write32(gt, reg, val); + if (!reg.vf && mmio->sriov_vf_gt) + xe_gt_sriov_vf_write32(mmio->sriov_vf_gt, reg, val); else - writel(val, (reg.ext ? tile->mmio_ext.regs : tile->mmio.regs) + addr); + writel(val, mmio->regs + addr); } -u32 xe_mmio_read32(struct xe_gt *gt, struct xe_reg reg) +u32 xe_mmio_read32(struct xe_mmio *mmio, struct xe_reg reg) { - struct xe_tile *tile = gt_to_tile(gt); - u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); + u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u32 val; /* Wa_15015404425 */ - mmio_flush_pending_writes(gt); + mmio_flush_pending_writes(mmio); - if (!reg.vf && IS_SRIOV_VF(gt_to_xe(gt))) - val = xe_gt_sriov_vf_read32(gt, reg); + if (!reg.vf && mmio->sriov_vf_gt) + val = xe_gt_sriov_vf_read32(mmio->sriov_vf_gt, reg); else - val = readl((reg.ext ? tile->mmio_ext.regs : tile->mmio.regs) + addr); + val = readl(mmio->regs + addr); - trace_xe_reg_rw(gt, false, addr, val, sizeof(val)); + trace_xe_reg_rw(mmio, false, addr, val, sizeof(val)); return val; } -u32 xe_mmio_rmw32(struct xe_gt *gt, struct xe_reg reg, u32 clr, u32 set) +u32 xe_mmio_rmw32(struct xe_mmio *mmio, struct xe_reg reg, u32 clr, u32 set) { u32 old, reg_val; - old = xe_mmio_read32(gt, reg); + old = xe_mmio_read32(mmio, reg); reg_val = (old & ~clr) | set; - xe_mmio_write32(gt, reg, reg_val); + xe_mmio_write32(mmio, reg, reg_val); return old; } -int xe_mmio_write32_and_verify(struct xe_gt *gt, +int xe_mmio_write32_and_verify(struct xe_mmio *mmio, struct xe_reg reg, u32 val, u32 mask, u32 eval) { u32 reg_val; - xe_mmio_write32(gt, reg, val); - reg_val = xe_mmio_read32(gt, reg); + xe_mmio_write32(mmio, reg, val); + reg_val = xe_mmio_read32(mmio, reg); return (reg_val & mask) != eval ? -EINVAL : 0; } -bool xe_mmio_in_range(const struct xe_gt *gt, +bool xe_mmio_in_range(const struct xe_mmio *mmio, const struct xe_mmio_range *range, struct xe_reg reg) { - u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); + u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); return range && addr >= range->start && addr <= range->end; } /** * xe_mmio_read64_2x32() - Read a 64-bit register as two 32-bit reads - * @gt: MMIO target GT + * @mmio: MMIO target * @reg: register to read value from * * Although Intel GPUs have some 64-bit registers, the hardware officially @@ -307,21 +310,21 @@ bool xe_mmio_in_range(const struct xe_gt *gt, * * Returns the value of the 64-bit register. */ -u64 xe_mmio_read64_2x32(struct xe_gt *gt, struct xe_reg reg) +u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg) { struct xe_reg reg_udw = { .addr = reg.addr + 0x4 }; u32 ldw, udw, oldudw, retries; - reg.addr = xe_mmio_adjusted_addr(gt, reg.addr); - reg_udw.addr = xe_mmio_adjusted_addr(gt, reg_udw.addr); + reg.addr = xe_mmio_adjusted_addr(mmio, reg.addr); + reg_udw.addr = xe_mmio_adjusted_addr(mmio, reg_udw.addr); /* we shouldn't adjust just one register address */ - xe_gt_assert(gt, reg_udw.addr == reg.addr + 0x4); + xe_tile_assert(mmio->tile, reg_udw.addr == reg.addr + 0x4); - oldudw = xe_mmio_read32(gt, reg_udw); + oldudw = xe_mmio_read32(mmio, reg_udw); for (retries = 5; retries; --retries) { - ldw = xe_mmio_read32(gt, reg); - udw = xe_mmio_read32(gt, reg_udw); + ldw = xe_mmio_read32(mmio, reg); + udw = xe_mmio_read32(mmio, reg_udw); if (udw == oldudw) break; @@ -329,13 +332,13 @@ u64 xe_mmio_read64_2x32(struct xe_gt *gt, struct xe_reg reg) oldudw = udw; } - xe_gt_WARN(gt, retries == 0, - "64-bit read of %#x did not stabilize\n", reg.addr); + drm_WARN(&mmio->tile->xe->drm, retries == 0, + "64-bit read of %#x did not stabilize\n", reg.addr); return (u64)udw << 32 | ldw; } -static int __xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, +static int __xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, u32 *out_val, bool atomic, bool expect_match) { ktime_t cur = ktime_get_raw(); @@ -346,7 +349,7 @@ static int __xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 v bool check; for (;;) { - read = xe_mmio_read32(gt, reg); + read = xe_mmio_read32(mmio, reg); check = (read & mask) == val; if (!expect_match) @@ -372,7 +375,7 @@ static int __xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 v } if (ret != 0) { - read = xe_mmio_read32(gt, reg); + read = xe_mmio_read32(mmio, reg); check = (read & mask) == val; if (!expect_match) @@ -390,7 +393,7 @@ static int __xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 v /** * xe_mmio_wait32() - Wait for a register to match the desired masked value - * @gt: MMIO target GT + * @mmio: MMIO target * @reg: register to read value from * @mask: mask to be applied to the value read from the register * @val: desired value after applying the mask @@ -407,15 +410,15 @@ static int __xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 v * @timeout_us for different reasons, specially in non-atomic contexts. Thus, * it is possible that this function succeeds even after @timeout_us has passed. */ -int xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, +int xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, u32 *out_val, bool atomic) { - return __xe_mmio_wait32(gt, reg, mask, val, timeout_us, out_val, atomic, true); + return __xe_mmio_wait32(mmio, reg, mask, val, timeout_us, out_val, atomic, true); } /** * xe_mmio_wait32_not() - Wait for a register to return anything other than the given masked value - * @gt: MMIO target GT + * @mmio: MMIO target * @reg: register to read value from * @mask: mask to be applied to the value read from the register * @val: value not to be matched after applying the mask @@ -426,8 +429,8 @@ int xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 t * This function works exactly like xe_mmio_wait32() with the exception that * @val is expected not to be matched. */ -int xe_mmio_wait32_not(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, +int xe_mmio_wait32_not(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, u32 *out_val, bool atomic) { - return __xe_mmio_wait32(gt, reg, mask, val, timeout_us, out_val, atomic, false); + return __xe_mmio_wait32(mmio, reg, mask, val, timeout_us, out_val, atomic, false); } diff --git a/drivers/gpu/drm/xe/xe_mmio.h b/drivers/gpu/drm/xe/xe_mmio.h index 26551410ecc872..8a46f4006a84ff 100644 --- a/drivers/gpu/drm/xe/xe_mmio.h +++ b/drivers/gpu/drm/xe/xe_mmio.h @@ -14,25 +14,30 @@ struct xe_reg; int xe_mmio_init(struct xe_device *xe); int xe_mmio_probe_tiles(struct xe_device *xe); -u8 xe_mmio_read8(struct xe_gt *gt, struct xe_reg reg); -u16 xe_mmio_read16(struct xe_gt *gt, struct xe_reg reg); -void xe_mmio_write32(struct xe_gt *gt, struct xe_reg reg, u32 val); -u32 xe_mmio_read32(struct xe_gt *gt, struct xe_reg reg); -u32 xe_mmio_rmw32(struct xe_gt *gt, struct xe_reg reg, u32 clr, u32 set); -int xe_mmio_write32_and_verify(struct xe_gt *gt, struct xe_reg reg, u32 val, u32 mask, u32 eval); -bool xe_mmio_in_range(const struct xe_gt *gt, const struct xe_mmio_range *range, struct xe_reg reg); - -u64 xe_mmio_read64_2x32(struct xe_gt *gt, struct xe_reg reg); -int xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, - u32 *out_val, bool atomic); -int xe_mmio_wait32_not(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, - u32 *out_val, bool atomic); - -static inline u32 xe_mmio_adjusted_addr(const struct xe_gt *gt, u32 addr) +u8 xe_mmio_read8(struct xe_mmio *mmio, struct xe_reg reg); +u16 xe_mmio_read16(struct xe_mmio *mmio, struct xe_reg reg); +void xe_mmio_write32(struct xe_mmio *mmio, struct xe_reg reg, u32 val); +u32 xe_mmio_read32(struct xe_mmio *mmio, struct xe_reg reg); +u32 xe_mmio_rmw32(struct xe_mmio *mmio, struct xe_reg reg, u32 clr, u32 set); +int xe_mmio_write32_and_verify(struct xe_mmio *mmio, struct xe_reg reg, u32 val, u32 mask, u32 eval); +bool xe_mmio_in_range(const struct xe_mmio *mmio, const struct xe_mmio_range *range, struct xe_reg reg); + +u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg); +int xe_mmio_wait32(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, u32 val, + u32 timeout_us, u32 *out_val, bool atomic); +int xe_mmio_wait32_not(struct xe_mmio *mmio, struct xe_reg reg, u32 mask, + u32 val, u32 timeout_us, u32 *out_val, bool atomic); + +static inline u32 xe_mmio_adjusted_addr(const struct xe_mmio *mmio, u32 addr) { - if (addr < gt->mmio.adj_limit) - addr += gt->mmio.adj_offset; + if (addr < mmio->adj_limit) + addr += mmio->adj_offset; return addr; } +static inline struct xe_mmio *xe_root_tile_mmio(struct xe_device *xe) +{ + return &xe->tiles[0].mmio; +} + #endif diff --git a/drivers/gpu/drm/xe/xe_mocs.c b/drivers/gpu/drm/xe/xe_mocs.c index 7ff0ac5b799a38..54d199b5cfb21a 100644 --- a/drivers/gpu/drm/xe/xe_mocs.c +++ b/drivers/gpu/drm/xe/xe_mocs.c @@ -278,7 +278,7 @@ static void xelp_lncf_dump(struct xe_mocs_info *info, struct xe_gt *gt, struct d if (regs_are_mcr(gt)) reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i)); else - reg_val = xe_mmio_read32(gt, XELP_LNCFCMOCS(i)); + reg_val = xe_mmio_read32(>->mmio, XELP_LNCFCMOCS(i)); drm_printf(p, "LNCFCMOCS[%2d] = [%u, %u, %u] (%#8x)\n", j++, @@ -310,7 +310,7 @@ static void xelp_mocs_dump(struct xe_mocs_info *info, unsigned int flags, if (regs_are_mcr(gt)) reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i)); else - reg_val = xe_mmio_read32(gt, XELP_GLOBAL_MOCS(i)); + reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i)); drm_printf(p, "GLOB_MOCS[%2d] = [%u, %u, %u, %u, %u, %u, %u, %u, %u, %u ] (%#8x)\n", i, @@ -383,7 +383,7 @@ static void xehp_lncf_dump(struct xe_mocs_info *info, unsigned int flags, if (regs_are_mcr(gt)) reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i)); else - reg_val = xe_mmio_read32(gt, XELP_LNCFCMOCS(i)); + reg_val = xe_mmio_read32(>->mmio, XELP_LNCFCMOCS(i)); drm_printf(p, "LNCFCMOCS[%2d] = [%u, %u, %u] (%#8x)\n", j++, @@ -428,7 +428,7 @@ static void pvc_mocs_dump(struct xe_mocs_info *info, unsigned int flags, struct if (regs_are_mcr(gt)) reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_LNCFCMOCS(i)); else - reg_val = xe_mmio_read32(gt, XELP_LNCFCMOCS(i)); + reg_val = xe_mmio_read32(>->mmio, XELP_LNCFCMOCS(i)); drm_printf(p, "LNCFCMOCS[%2d] = [ %u ] (%#8x)\n", j++, @@ -510,7 +510,7 @@ static void mtl_mocs_dump(struct xe_mocs_info *info, unsigned int flags, if (regs_are_mcr(gt)) reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i)); else - reg_val = xe_mmio_read32(gt, XELP_GLOBAL_MOCS(i)); + reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i)); drm_printf(p, "GLOB_MOCS[%2d] = [%u, %u] (%#8x)\n", i, @@ -553,7 +553,7 @@ static void xe2_mocs_dump(struct xe_mocs_info *info, unsigned int flags, if (regs_are_mcr(gt)) reg_val = xe_gt_mcr_unicast_read_any(gt, XEHP_GLOBAL_MOCS(i)); else - reg_val = xe_mmio_read32(gt, XELP_GLOBAL_MOCS(i)); + reg_val = xe_mmio_read32(>->mmio, XELP_GLOBAL_MOCS(i)); drm_printf(p, "GLOB_MOCS[%2d] = [%u, %u, %u] (%#8x)\n", i, @@ -576,6 +576,7 @@ static unsigned int get_mocs_settings(struct xe_device *xe, memset(info, 0, sizeof(struct xe_mocs_info)); switch (xe->info.platform) { + case XE_PANTHERLAKE: case XE_LUNARLAKE: case XE_BATTLEMAGE: info->ops = &xe2_mocs_ops; @@ -690,7 +691,7 @@ static void __init_mocs_table(struct xe_gt *gt, if (regs_are_mcr(gt)) xe_gt_mcr_multicast_write(gt, XEHP_GLOBAL_MOCS(i), mocs); else - xe_mmio_write32(gt, XELP_GLOBAL_MOCS(i), mocs); + xe_mmio_write32(>->mmio, XELP_GLOBAL_MOCS(i), mocs); } } @@ -730,7 +731,7 @@ static void init_l3cc_table(struct xe_gt *gt, if (regs_are_mcr(gt)) xe_gt_mcr_multicast_write(gt, XEHP_LNCFCMOCS(i), l3cc); else - xe_mmio_write32(gt, XELP_LNCFCMOCS(i), l3cc); + xe_mmio_write32(>->mmio, XELP_LNCFCMOCS(i), l3cc); } } @@ -773,25 +774,21 @@ void xe_mocs_init(struct xe_gt *gt) void xe_mocs_dump(struct xe_gt *gt, struct drm_printer *p) { - struct xe_mocs_info table; - unsigned int flags; - u32 ret; struct xe_device *xe = gt_to_xe(gt); + struct xe_mocs_info table; + unsigned int fw_ref, flags; flags = get_mocs_settings(xe, &table); xe_pm_runtime_get_noresume(xe); - ret = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - - if (ret) + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) goto err_fw; table.ops->dump(&table, flags, gt, p); - xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); - + xe_force_wake_put(gt_to_fw(gt), fw_ref); err_fw: - xe_assert(xe, !ret); xe_pm_runtime_put(xe); } diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 78823f53d2905d..8dd55798ab3120 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -36,11 +36,22 @@ #include "xe_pm.h" #include "xe_sched_job.h" #include "xe_sriov.h" +#include "xe_sync.h" #define DEFAULT_POLL_FREQUENCY_HZ 200 #define DEFAULT_POLL_PERIOD_NS (NSEC_PER_SEC / DEFAULT_POLL_FREQUENCY_HZ) #define XE_OA_UNIT_INVALID U32_MAX +enum xe_oa_submit_deps { + XE_OA_SUBMIT_NO_DEPS, + XE_OA_SUBMIT_ADD_DEPS, +}; + +enum xe_oa_user_extn_from { + XE_OA_USER_EXTN_FROM_OPEN, + XE_OA_USER_EXTN_FROM_CONFIG, +}; + struct xe_oa_reg { struct xe_reg addr; u32 value; @@ -70,6 +81,7 @@ struct flex { }; struct xe_oa_open_param { + struct xe_file *xef; u32 oa_unit_id; bool sample; u32 metric_set; @@ -81,6 +93,9 @@ struct xe_oa_open_param { struct xe_exec_queue *exec_q; struct xe_hw_engine *hwe; bool no_preempt; + struct drm_xe_sync __user *syncs_user; + int num_syncs; + struct xe_sync_entry *syncs; }; struct xe_oa_config_bo { @@ -90,6 +105,17 @@ struct xe_oa_config_bo { struct xe_bb *bb; }; +struct xe_oa_fence { + /* @base: dma fence base */ + struct dma_fence base; + /* @lock: lock for the fence */ + spinlock_t lock; + /* @work: work to signal @base */ + struct delayed_work work; + /* @cb: callback to schedule @work */ + struct dma_fence_cb cb; +}; + #define DRM_FMT(x) DRM_XE_OA_FMT_TYPE_##x static const struct xe_oa_format oa_formats[] = { @@ -162,10 +188,10 @@ static struct xe_oa_config *xe_oa_get_oa_config(struct xe_oa *oa, int metrics_se return oa_config; } -static void free_oa_config_bo(struct xe_oa_config_bo *oa_bo) +static void free_oa_config_bo(struct xe_oa_config_bo *oa_bo, struct dma_fence *last_fence) { xe_oa_config_put(oa_bo->oa_config); - xe_bb_free(oa_bo->bb, NULL); + xe_bb_free(oa_bo->bb, last_fence); kfree(oa_bo); } @@ -176,7 +202,7 @@ static const struct xe_oa_regs *__oa_regs(struct xe_oa_stream *stream) static u32 xe_oa_hw_tail_read(struct xe_oa_stream *stream) { - return xe_mmio_read32(stream->gt, __oa_regs(stream)->oa_tail_ptr) & + return xe_mmio_read32(&stream->gt->mmio, __oa_regs(stream)->oa_tail_ptr) & OAG_OATAILPTR_MASK; } @@ -366,7 +392,7 @@ static int xe_oa_append_reports(struct xe_oa_stream *stream, char __user *buf, struct xe_reg oaheadptr = __oa_regs(stream)->oa_head_ptr; spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags); - xe_mmio_write32(stream->gt, oaheadptr, + xe_mmio_write32(&stream->gt->mmio, oaheadptr, (head + gtt_offset) & OAG_OAHEADPTR_MASK); stream->oa_buffer.head = head; spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags); @@ -377,22 +403,23 @@ static int xe_oa_append_reports(struct xe_oa_stream *stream, char __user *buf, static void xe_oa_init_oa_buffer(struct xe_oa_stream *stream) { + struct xe_mmio *mmio = &stream->gt->mmio; u32 gtt_offset = xe_bo_ggtt_addr(stream->oa_buffer.bo); u32 oa_buf = gtt_offset | OABUFFER_SIZE_16M | OAG_OABUFFER_MEMORY_SELECT; unsigned long flags; spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags); - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_status, 0); - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_head_ptr, + xe_mmio_write32(mmio, __oa_regs(stream)->oa_status, 0); + xe_mmio_write32(mmio, __oa_regs(stream)->oa_head_ptr, gtt_offset & OAG_OAHEADPTR_MASK); stream->oa_buffer.head = 0; /* * PRM says: "This MMIO must be set before the OATAILPTR register and after the * OAHEADPTR register. This is to enable proper functionality of the overflow bit". */ - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_buffer, oa_buf); - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_tail_ptr, + xe_mmio_write32(mmio, __oa_regs(stream)->oa_buffer, oa_buf); + xe_mmio_write32(mmio, __oa_regs(stream)->oa_tail_ptr, gtt_offset & OAG_OATAILPTR_MASK); /* Mark that we need updated tail pointer to read from */ @@ -444,21 +471,23 @@ static void xe_oa_enable(struct xe_oa_stream *stream) stream->hwe->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAG) val |= OAG_OACONTROL_OA_PES_DISAG_EN; - xe_mmio_write32(stream->gt, regs->oa_ctrl, val); + xe_mmio_write32(&stream->gt->mmio, regs->oa_ctrl, val); } static void xe_oa_disable(struct xe_oa_stream *stream) { - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_ctrl, 0); - if (xe_mmio_wait32(stream->gt, __oa_regs(stream)->oa_ctrl, + struct xe_mmio *mmio = &stream->gt->mmio; + + xe_mmio_write32(mmio, __oa_regs(stream)->oa_ctrl, 0); + if (xe_mmio_wait32(mmio, __oa_regs(stream)->oa_ctrl, OAG_OACONTROL_OA_COUNTER_ENABLE, 0, 50000, NULL, false)) drm_err(&stream->oa->xe->drm, "wait for OA to be disabled timed out\n"); if (GRAPHICS_VERx100(stream->oa->xe) <= 1270 && GRAPHICS_VERx100(stream->oa->xe) != 1260) { /* <= XE_METEORLAKE except XE_PVC */ - xe_mmio_write32(stream->gt, OA_TLB_INV_CR, 1); - if (xe_mmio_wait32(stream->gt, OA_TLB_INV_CR, 1, 0, 50000, NULL, false)) + xe_mmio_write32(mmio, OA_TLB_INV_CR, 1); + if (xe_mmio_wait32(mmio, OA_TLB_INV_CR, 1, 0, 50000, NULL, false)) drm_err(&stream->oa->xe->drm, "wait for OA tlb invalidate timed out\n"); } @@ -481,7 +510,7 @@ static int __xe_oa_read(struct xe_oa_stream *stream, char __user *buf, size_t count, size_t *offset) { /* Only clear our bits to avoid side-effects */ - stream->oa_status = xe_mmio_rmw32(stream->gt, __oa_regs(stream)->oa_status, + stream->oa_status = xe_mmio_rmw32(&stream->gt->mmio, __oa_regs(stream)->oa_status, OASTATUS_RELEVANT_BITS, 0); /* * Signal to userspace that there is non-zero OA status to read via @@ -567,11 +596,11 @@ static __poll_t xe_oa_poll(struct file *file, poll_table *wait) return ret; } -static int xe_oa_submit_bb(struct xe_oa_stream *stream, struct xe_bb *bb) +static struct dma_fence *xe_oa_submit_bb(struct xe_oa_stream *stream, enum xe_oa_submit_deps deps, + struct xe_bb *bb) { struct xe_sched_job *job; struct dma_fence *fence; - long timeout; int err = 0; /* Kernel configuration is issued on stream->k_exec_q, not stream->exec_q */ @@ -581,18 +610,24 @@ static int xe_oa_submit_bb(struct xe_oa_stream *stream, struct xe_bb *bb) goto exit; } + if (deps == XE_OA_SUBMIT_ADD_DEPS) { + for (int i = 0; i < stream->num_syncs && !err; i++) + err = xe_sync_entry_add_deps(&stream->syncs[i], job); + if (err) { + drm_dbg(&stream->oa->xe->drm, "xe_sync_entry_add_deps err %d\n", err); + goto err_put_job; + } + } + xe_sched_job_arm(job); fence = dma_fence_get(&job->drm.s_fence->finished); xe_sched_job_push(job); - timeout = dma_fence_wait_timeout(fence, false, HZ); - dma_fence_put(fence); - if (timeout < 0) - err = timeout; - else if (!timeout) - err = -ETIME; + return fence; +err_put_job: + xe_sched_job_put(job); exit: - return err; + return ERR_PTR(err); } static void write_cs_mi_lri(struct xe_bb *bb, const struct xe_oa_reg *reg_data, u32 n_regs) @@ -636,7 +671,8 @@ static void xe_oa_free_configs(struct xe_oa_stream *stream) xe_oa_config_put(stream->oa_config); llist_for_each_entry_safe(oa_bo, tmp, stream->oa_config_bos.first, node) - free_oa_config_bo(oa_bo); + free_oa_config_bo(oa_bo, stream->last_fence); + dma_fence_put(stream->last_fence); } static void xe_oa_store_flex(struct xe_oa_stream *stream, struct xe_lrc *lrc, @@ -656,6 +692,7 @@ static void xe_oa_store_flex(struct xe_oa_stream *stream, struct xe_lrc *lrc, static int xe_oa_modify_ctx_image(struct xe_oa_stream *stream, struct xe_lrc *lrc, const struct flex *flex, u32 count) { + struct dma_fence *fence; struct xe_bb *bb; int err; @@ -667,7 +704,16 @@ static int xe_oa_modify_ctx_image(struct xe_oa_stream *stream, struct xe_lrc *lr xe_oa_store_flex(stream, lrc, bb, flex, count); - err = xe_oa_submit_bb(stream, bb); + fence = xe_oa_submit_bb(stream, XE_OA_SUBMIT_NO_DEPS, bb); + if (IS_ERR(fence)) { + err = PTR_ERR(fence); + goto free_bb; + } + xe_bb_free(bb, fence); + dma_fence_put(fence); + + return 0; +free_bb: xe_bb_free(bb, NULL); exit: return err; @@ -675,6 +721,7 @@ static int xe_oa_modify_ctx_image(struct xe_oa_stream *stream, struct xe_lrc *lr static int xe_oa_load_with_lri(struct xe_oa_stream *stream, struct xe_oa_reg *reg_lri) { + struct dma_fence *fence; struct xe_bb *bb; int err; @@ -686,7 +733,16 @@ static int xe_oa_load_with_lri(struct xe_oa_stream *stream, struct xe_oa_reg *re write_cs_mi_lri(bb, reg_lri, 1); - err = xe_oa_submit_bb(stream, bb); + fence = xe_oa_submit_bb(stream, XE_OA_SUBMIT_NO_DEPS, bb); + if (IS_ERR(fence)) { + err = PTR_ERR(fence); + goto free_bb; + } + xe_bb_free(bb, fence); + dma_fence_put(fence); + + return 0; +free_bb: xe_bb_free(bb, NULL); exit: return err; @@ -749,7 +805,8 @@ static int xe_oa_configure_oac_context(struct xe_oa_stream *stream, bool enable) int err; /* Set ccs select to enable programming of OAC_OACONTROL */ - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_ctrl, __oa_ccs_select(stream)); + xe_mmio_write32(&stream->gt->mmio, __oa_regs(stream)->oa_ctrl, + __oa_ccs_select(stream)); /* Modify stream hwe context image with regs_context */ err = xe_oa_modify_ctx_image(stream, stream->exec_q->lrc[0], @@ -785,6 +842,7 @@ static u32 oag_configure_mmio_trigger(const struct xe_oa_stream *stream, bool en static void xe_oa_disable_metric_set(struct xe_oa_stream *stream) { + struct xe_mmio *mmio = &stream->gt->mmio; u32 sqcnt1; /* @@ -798,7 +856,7 @@ static void xe_oa_disable_metric_set(struct xe_oa_stream *stream) _MASKED_BIT_DISABLE(DISABLE_DOP_GATING)); } - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_debug, + xe_mmio_write32(mmio, __oa_regs(stream)->oa_debug, oag_configure_mmio_trigger(stream, false)); /* disable the context save/restore or OAR counters */ @@ -806,13 +864,13 @@ static void xe_oa_disable_metric_set(struct xe_oa_stream *stream) xe_oa_configure_oa_context(stream, false); /* Make sure we disable noa to save power. */ - xe_mmio_rmw32(stream->gt, RPM_CONFIG1, GT_NOA_ENABLE, 0); + xe_mmio_rmw32(mmio, RPM_CONFIG1, GT_NOA_ENABLE, 0); sqcnt1 = SQCNT1_PMON_ENABLE | (HAS_OA_BPC_REPORTING(stream->oa->xe) ? SQCNT1_OABPC : 0); /* Reset PMON Enable to save power. */ - xe_mmio_rmw32(stream->gt, XELPMP_SQCNT1, sqcnt1, 0); + xe_mmio_rmw32(mmio, XELPMP_SQCNT1, sqcnt1, 0); } static void xe_oa_stream_destroy(struct xe_oa_stream *stream) @@ -832,7 +890,7 @@ static void xe_oa_stream_destroy(struct xe_oa_stream *stream) xe_oa_free_oa_buffer(stream); - XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); + xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL); xe_pm_runtime_put(stream->oa->xe); /* Wa_1509372804:pvc: Unset the override of GUCRC mode to enable rc6 */ @@ -840,6 +898,7 @@ static void xe_oa_stream_destroy(struct xe_oa_stream *stream) xe_gt_WARN_ON(gt, xe_guc_pc_unset_gucrc_mode(>->uc.guc.pc)); xe_oa_free_configs(stream); + xe_file_put(stream->xef); } static int xe_oa_alloc_oa_buffer(struct xe_oa_stream *stream) @@ -910,11 +969,62 @@ xe_oa_alloc_config_buffer(struct xe_oa_stream *stream, struct xe_oa_config *oa_c return oa_bo; } +static void xe_oa_update_last_fence(struct xe_oa_stream *stream, struct dma_fence *fence) +{ + dma_fence_put(stream->last_fence); + stream->last_fence = dma_fence_get(fence); +} + +static void xe_oa_fence_work_fn(struct work_struct *w) +{ + struct xe_oa_fence *ofence = container_of(w, typeof(*ofence), work.work); + + /* Signal fence to indicate new OA configuration is active */ + dma_fence_signal(&ofence->base); + dma_fence_put(&ofence->base); +} + +static void xe_oa_config_cb(struct dma_fence *fence, struct dma_fence_cb *cb) +{ + /* Additional empirical delay needed for NOA programming after registers are written */ +#define NOA_PROGRAM_ADDITIONAL_DELAY_US 500 + + struct xe_oa_fence *ofence = container_of(cb, typeof(*ofence), cb); + + INIT_DELAYED_WORK(&ofence->work, xe_oa_fence_work_fn); + queue_delayed_work(system_unbound_wq, &ofence->work, + usecs_to_jiffies(NOA_PROGRAM_ADDITIONAL_DELAY_US)); + dma_fence_put(fence); +} + +static const char *xe_oa_get_driver_name(struct dma_fence *fence) +{ + return "xe_oa"; +} + +static const char *xe_oa_get_timeline_name(struct dma_fence *fence) +{ + return "unbound"; +} + +static const struct dma_fence_ops xe_oa_fence_ops = { + .get_driver_name = xe_oa_get_driver_name, + .get_timeline_name = xe_oa_get_timeline_name, +}; + static int xe_oa_emit_oa_config(struct xe_oa_stream *stream, struct xe_oa_config *config) { #define NOA_PROGRAM_ADDITIONAL_DELAY_US 500 struct xe_oa_config_bo *oa_bo; - int err, us = NOA_PROGRAM_ADDITIONAL_DELAY_US; + struct xe_oa_fence *ofence; + int i, err, num_signal = 0; + struct dma_fence *fence; + + ofence = kzalloc(sizeof(*ofence), GFP_KERNEL); + if (!ofence) { + err = -ENOMEM; + goto exit; + } oa_bo = xe_oa_alloc_config_buffer(stream, config); if (IS_ERR(oa_bo)) { @@ -922,11 +1032,50 @@ static int xe_oa_emit_oa_config(struct xe_oa_stream *stream, struct xe_oa_config goto exit; } - err = xe_oa_submit_bb(stream, oa_bo->bb); + /* Emit OA configuration batch */ + fence = xe_oa_submit_bb(stream, XE_OA_SUBMIT_ADD_DEPS, oa_bo->bb); + if (IS_ERR(fence)) { + err = PTR_ERR(fence); + goto exit; + } - /* Additional empirical delay needed for NOA programming after registers are written */ - usleep_range(us, 2 * us); + /* Point of no return: initialize and set fence to signal */ + spin_lock_init(&ofence->lock); + dma_fence_init(&ofence->base, &xe_oa_fence_ops, &ofence->lock, 0, 0); + + for (i = 0; i < stream->num_syncs; i++) { + if (stream->syncs[i].flags & DRM_XE_SYNC_FLAG_SIGNAL) + num_signal++; + xe_sync_entry_signal(&stream->syncs[i], &ofence->base); + } + + /* Additional dma_fence_get in case we dma_fence_wait */ + if (!num_signal) + dma_fence_get(&ofence->base); + + /* Update last fence too before adding callback */ + xe_oa_update_last_fence(stream, fence); + + /* Add job fence callback to schedule work to signal ofence->base */ + err = dma_fence_add_callback(fence, &ofence->cb, xe_oa_config_cb); + xe_gt_assert(stream->gt, !err || err == -ENOENT); + if (err == -ENOENT) + xe_oa_config_cb(fence, &ofence->cb); + + /* If nothing needs to be signaled we wait synchronously */ + if (!num_signal) { + dma_fence_wait(&ofence->base, false); + dma_fence_put(&ofence->base); + } + + /* Done with syncs */ + for (i = 0; i < stream->num_syncs; i++) + xe_sync_entry_cleanup(&stream->syncs[i]); + kfree(stream->syncs); + + return 0; exit: + kfree(ofence); return err; } @@ -940,6 +1089,7 @@ static u32 oag_report_ctx_switches(const struct xe_oa_stream *stream) static int xe_oa_enable_metric_set(struct xe_oa_stream *stream) { + struct xe_mmio *mmio = &stream->gt->mmio; u32 oa_debug, sqcnt1; int ret; @@ -966,12 +1116,12 @@ static int xe_oa_enable_metric_set(struct xe_oa_stream *stream) OAG_OA_DEBUG_DISABLE_START_TRG_2_COUNT_QUAL | OAG_OA_DEBUG_DISABLE_START_TRG_1_COUNT_QUAL; - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_debug, + xe_mmio_write32(mmio, __oa_regs(stream)->oa_debug, _MASKED_BIT_ENABLE(oa_debug) | oag_report_ctx_switches(stream) | oag_configure_mmio_trigger(stream, true)); - xe_mmio_write32(stream->gt, __oa_regs(stream)->oa_ctx_ctrl, stream->periodic ? + xe_mmio_write32(mmio, __oa_regs(stream)->oa_ctx_ctrl, stream->periodic ? (OAG_OAGLBCTXCTRL_COUNTER_RESUME | OAG_OAGLBCTXCTRL_TIMER_ENABLE | REG_FIELD_PREP(OAG_OAGLBCTXCTRL_TIMER_PERIOD_MASK, @@ -985,7 +1135,7 @@ static int xe_oa_enable_metric_set(struct xe_oa_stream *stream) sqcnt1 = SQCNT1_PMON_ENABLE | (HAS_OA_BPC_REPORTING(stream->oa->xe) ? SQCNT1_OABPC : 0); - xe_mmio_rmw32(stream->gt, XELPMP_SQCNT1, 0, sqcnt1); + xe_mmio_rmw32(mmio, XELPMP_SQCNT1, 0, sqcnt1); /* Configure OAR/OAC */ if (stream->exec_q) { @@ -997,6 +1147,262 @@ static int xe_oa_enable_metric_set(struct xe_oa_stream *stream) return xe_oa_emit_oa_config(stream, stream->oa_config); } +static int decode_oa_format(struct xe_oa *oa, u64 fmt, enum xe_oa_format_name *name) +{ + u32 counter_size = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SIZE, fmt); + u32 counter_sel = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SEL, fmt); + u32 bc_report = FIELD_GET(DRM_XE_OA_FORMAT_MASK_BC_REPORT, fmt); + u32 type = FIELD_GET(DRM_XE_OA_FORMAT_MASK_FMT_TYPE, fmt); + int idx; + + for_each_set_bit(idx, oa->format_mask, __XE_OA_FORMAT_MAX) { + const struct xe_oa_format *f = &oa->oa_formats[idx]; + + if (counter_size == f->counter_size && bc_report == f->bc_report && + type == f->type && counter_sel == f->counter_select) { + *name = idx; + return 0; + } + } + + return -EINVAL; +} + +static int xe_oa_set_prop_oa_unit_id(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + if (value >= oa->oa_unit_ids) { + drm_dbg(&oa->xe->drm, "OA unit ID out of range %lld\n", value); + return -EINVAL; + } + param->oa_unit_id = value; + return 0; +} + +static int xe_oa_set_prop_sample_oa(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + param->sample = value; + return 0; +} + +static int xe_oa_set_prop_metric_set(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + param->metric_set = value; + return 0; +} + +static int xe_oa_set_prop_oa_format(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + int ret = decode_oa_format(oa, value, ¶m->oa_format); + + if (ret) { + drm_dbg(&oa->xe->drm, "Unsupported OA report format %#llx\n", value); + return ret; + } + return 0; +} + +static int xe_oa_set_prop_oa_exponent(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ +#define OA_EXPONENT_MAX 31 + + if (value > OA_EXPONENT_MAX) { + drm_dbg(&oa->xe->drm, "OA timer exponent too high (> %u)\n", OA_EXPONENT_MAX); + return -EINVAL; + } + param->period_exponent = value; + return 0; +} + +static int xe_oa_set_prop_disabled(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + param->disabled = value; + return 0; +} + +static int xe_oa_set_prop_exec_queue_id(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + param->exec_queue_id = value; + return 0; +} + +static int xe_oa_set_prop_engine_instance(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + param->engine_instance = value; + return 0; +} + +static int xe_oa_set_no_preempt(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + param->no_preempt = value; + return 0; +} + +static int xe_oa_set_prop_num_syncs(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + param->num_syncs = value; + return 0; +} + +static int xe_oa_set_prop_syncs_user(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + param->syncs_user = u64_to_user_ptr(value); + return 0; +} + +static int xe_oa_set_prop_ret_inval(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param) +{ + return -EINVAL; +} + +typedef int (*xe_oa_set_property_fn)(struct xe_oa *oa, u64 value, + struct xe_oa_open_param *param); +static const xe_oa_set_property_fn xe_oa_set_property_funcs_open[] = { + [DRM_XE_OA_PROPERTY_OA_UNIT_ID] = xe_oa_set_prop_oa_unit_id, + [DRM_XE_OA_PROPERTY_SAMPLE_OA] = xe_oa_set_prop_sample_oa, + [DRM_XE_OA_PROPERTY_OA_METRIC_SET] = xe_oa_set_prop_metric_set, + [DRM_XE_OA_PROPERTY_OA_FORMAT] = xe_oa_set_prop_oa_format, + [DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT] = xe_oa_set_prop_oa_exponent, + [DRM_XE_OA_PROPERTY_OA_DISABLED] = xe_oa_set_prop_disabled, + [DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID] = xe_oa_set_prop_exec_queue_id, + [DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE] = xe_oa_set_prop_engine_instance, + [DRM_XE_OA_PROPERTY_NO_PREEMPT] = xe_oa_set_no_preempt, + [DRM_XE_OA_PROPERTY_NUM_SYNCS] = xe_oa_set_prop_num_syncs, + [DRM_XE_OA_PROPERTY_SYNCS] = xe_oa_set_prop_syncs_user, +}; + +static const xe_oa_set_property_fn xe_oa_set_property_funcs_config[] = { + [DRM_XE_OA_PROPERTY_OA_UNIT_ID] = xe_oa_set_prop_ret_inval, + [DRM_XE_OA_PROPERTY_SAMPLE_OA] = xe_oa_set_prop_ret_inval, + [DRM_XE_OA_PROPERTY_OA_METRIC_SET] = xe_oa_set_prop_metric_set, + [DRM_XE_OA_PROPERTY_OA_FORMAT] = xe_oa_set_prop_ret_inval, + [DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT] = xe_oa_set_prop_ret_inval, + [DRM_XE_OA_PROPERTY_OA_DISABLED] = xe_oa_set_prop_ret_inval, + [DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID] = xe_oa_set_prop_ret_inval, + [DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE] = xe_oa_set_prop_ret_inval, + [DRM_XE_OA_PROPERTY_NO_PREEMPT] = xe_oa_set_prop_ret_inval, + [DRM_XE_OA_PROPERTY_NUM_SYNCS] = xe_oa_set_prop_num_syncs, + [DRM_XE_OA_PROPERTY_SYNCS] = xe_oa_set_prop_syncs_user, +}; + +static int xe_oa_user_ext_set_property(struct xe_oa *oa, enum xe_oa_user_extn_from from, + u64 extension, struct xe_oa_open_param *param) +{ + u64 __user *address = u64_to_user_ptr(extension); + struct drm_xe_ext_set_property ext; + int err; + u32 idx; + + err = __copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(oa->xe, err)) + return -EFAULT; + + BUILD_BUG_ON(ARRAY_SIZE(xe_oa_set_property_funcs_open) != + ARRAY_SIZE(xe_oa_set_property_funcs_config)); + + if (XE_IOCTL_DBG(oa->xe, ext.property >= ARRAY_SIZE(xe_oa_set_property_funcs_open)) || + XE_IOCTL_DBG(oa->xe, ext.pad)) + return -EINVAL; + + idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_oa_set_property_funcs_open)); + + if (from == XE_OA_USER_EXTN_FROM_CONFIG) + return xe_oa_set_property_funcs_config[idx](oa, ext.value, param); + else + return xe_oa_set_property_funcs_open[idx](oa, ext.value, param); +} + +typedef int (*xe_oa_user_extension_fn)(struct xe_oa *oa, enum xe_oa_user_extn_from from, + u64 extension, struct xe_oa_open_param *param); +static const xe_oa_user_extension_fn xe_oa_user_extension_funcs[] = { + [DRM_XE_OA_EXTENSION_SET_PROPERTY] = xe_oa_user_ext_set_property, +}; + +#define MAX_USER_EXTENSIONS 16 +static int xe_oa_user_extensions(struct xe_oa *oa, enum xe_oa_user_extn_from from, u64 extension, + int ext_number, struct xe_oa_open_param *param) +{ + u64 __user *address = u64_to_user_ptr(extension); + struct drm_xe_user_extension ext; + int err; + u32 idx; + + if (XE_IOCTL_DBG(oa->xe, ext_number >= MAX_USER_EXTENSIONS)) + return -E2BIG; + + err = __copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(oa->xe, err)) + return -EFAULT; + + if (XE_IOCTL_DBG(oa->xe, ext.pad) || + XE_IOCTL_DBG(oa->xe, ext.name >= ARRAY_SIZE(xe_oa_user_extension_funcs))) + return -EINVAL; + + idx = array_index_nospec(ext.name, ARRAY_SIZE(xe_oa_user_extension_funcs)); + err = xe_oa_user_extension_funcs[idx](oa, from, extension, param); + if (XE_IOCTL_DBG(oa->xe, err)) + return err; + + if (ext.next_extension) + return xe_oa_user_extensions(oa, from, ext.next_extension, ++ext_number, param); + + return 0; +} + +static int xe_oa_parse_syncs(struct xe_oa *oa, struct xe_oa_open_param *param) +{ + int ret, num_syncs, num_ufence = 0; + + if (param->num_syncs && !param->syncs_user) { + drm_dbg(&oa->xe->drm, "num_syncs specified without sync array\n"); + ret = -EINVAL; + goto exit; + } + + if (param->num_syncs) { + param->syncs = kcalloc(param->num_syncs, sizeof(*param->syncs), GFP_KERNEL); + if (!param->syncs) { + ret = -ENOMEM; + goto exit; + } + } + + for (num_syncs = 0; num_syncs < param->num_syncs; num_syncs++) { + ret = xe_sync_entry_parse(oa->xe, param->xef, ¶m->syncs[num_syncs], + ¶m->syncs_user[num_syncs], 0); + if (ret) + goto err_syncs; + + if (xe_sync_is_ufence(¶m->syncs[num_syncs])) + num_ufence++; + } + + if (XE_IOCTL_DBG(oa->xe, num_ufence > 1)) { + ret = -EINVAL; + goto err_syncs; + } + + return 0; + +err_syncs: + while (num_syncs--) + xe_sync_entry_cleanup(¶m->syncs[num_syncs]); + kfree(param->syncs); +exit: + return ret; +} + static void xe_oa_stream_enable(struct xe_oa_stream *stream) { stream->pollin = false; @@ -1090,36 +1496,38 @@ static int xe_oa_disable_locked(struct xe_oa_stream *stream) static long xe_oa_config_locked(struct xe_oa_stream *stream, u64 arg) { - struct drm_xe_ext_set_property ext; + struct xe_oa_open_param param = {}; long ret = stream->oa_config->id; struct xe_oa_config *config; int err; - err = __copy_from_user(&ext, u64_to_user_ptr(arg), sizeof(ext)); - if (XE_IOCTL_DBG(stream->oa->xe, err)) - return -EFAULT; - - if (XE_IOCTL_DBG(stream->oa->xe, ext.pad) || - XE_IOCTL_DBG(stream->oa->xe, ext.base.name != DRM_XE_OA_EXTENSION_SET_PROPERTY) || - XE_IOCTL_DBG(stream->oa->xe, ext.base.next_extension) || - XE_IOCTL_DBG(stream->oa->xe, ext.property != DRM_XE_OA_PROPERTY_OA_METRIC_SET)) - return -EINVAL; + err = xe_oa_user_extensions(stream->oa, XE_OA_USER_EXTN_FROM_CONFIG, arg, 0, ¶m); + if (err) + return err; - config = xe_oa_get_oa_config(stream->oa, ext.value); + config = xe_oa_get_oa_config(stream->oa, param.metric_set); if (!config) return -ENODEV; - if (config != stream->oa_config) { - err = xe_oa_emit_oa_config(stream, config); - if (!err) - config = xchg(&stream->oa_config, config); - else - ret = err; + param.xef = stream->xef; + err = xe_oa_parse_syncs(stream->oa, ¶m); + if (err) + goto err_config_put; + + stream->num_syncs = param.num_syncs; + stream->syncs = param.syncs; + + err = xe_oa_emit_oa_config(stream, config); + if (!err) { + config = xchg(&stream->oa_config, config); + drm_dbg(&stream->oa->xe->drm, "changed to oa config uuid=%s\n", + stream->oa_config->uuid); } +err_config_put: xe_oa_config_put(config); - return ret; + return err ?: ret; } static long xe_oa_status_locked(struct xe_oa_stream *stream, unsigned long arg) @@ -1349,6 +1757,7 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream, { struct xe_oa_unit *u = param->hwe->oa_unit; struct xe_gt *gt = param->hwe->gt; + unsigned int fw_ref; int ret; stream->exec_q = param->exec_q; @@ -1362,6 +1771,10 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream, stream->period_exponent = param->period_exponent; stream->no_preempt = param->no_preempt; + stream->xef = xe_file_get(param->xef); + stream->num_syncs = param->num_syncs; + stream->syncs = param->syncs; + /* * For Xe2+, when overrun mode is enabled, there are no partial reports at the end * of buffer, making the OA buffer effectively a non-power-of-2 size circular @@ -1409,7 +1822,11 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream, /* Take runtime pm ref and forcewake to disable RC6 */ xe_pm_runtime_get(stream->oa->xe); - XE_WARN_ON(xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL)); + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { + ret = -ETIMEDOUT; + goto err_fw_put; + } ret = xe_oa_alloc_oa_buffer(stream); if (ret) @@ -1451,13 +1868,14 @@ static int xe_oa_stream_init(struct xe_oa_stream *stream, err_free_oa_buf: xe_oa_free_oa_buffer(stream); err_fw_put: - XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); + xe_force_wake_put(gt_to_fw(gt), fw_ref); xe_pm_runtime_put(stream->oa->xe); if (stream->override_gucrc) xe_gt_WARN_ON(gt, xe_guc_pc_unset_gucrc_mode(>->uc.guc.pc)); err_free_configs: xe_oa_free_configs(stream); exit: + xe_file_put(stream->xef); return ret; } @@ -1535,7 +1953,7 @@ u32 xe_oa_timestamp_frequency(struct xe_gt *gt) case XE_PVC: case XE_METEORLAKE: xe_pm_runtime_get(gt_to_xe(gt)); - reg = xe_mmio_read32(gt, RPM_CONFIG0); + reg = xe_mmio_read32(>->mmio, RPM_CONFIG0); xe_pm_runtime_put(gt_to_xe(gt)); shift = REG_FIELD_GET(RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK, reg); @@ -1567,27 +1985,6 @@ static bool engine_supports_oa_format(const struct xe_hw_engine *hwe, int type) } } -static int decode_oa_format(struct xe_oa *oa, u64 fmt, enum xe_oa_format_name *name) -{ - u32 counter_size = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SIZE, fmt); - u32 counter_sel = FIELD_GET(DRM_XE_OA_FORMAT_MASK_COUNTER_SEL, fmt); - u32 bc_report = FIELD_GET(DRM_XE_OA_FORMAT_MASK_BC_REPORT, fmt); - u32 type = FIELD_GET(DRM_XE_OA_FORMAT_MASK_FMT_TYPE, fmt); - int idx; - - for_each_set_bit(idx, oa->format_mask, __XE_OA_FORMAT_MAX) { - const struct xe_oa_format *f = &oa->oa_formats[idx]; - - if (counter_size == f->counter_size && bc_report == f->bc_report && - type == f->type && counter_sel == f->counter_select) { - *name = idx; - return 0; - } - } - - return -EINVAL; -} - /** * xe_oa_unit_id - Return OA unit ID for a hardware engine * @hwe: @xe_hw_engine @@ -1634,155 +2031,6 @@ static int xe_oa_assign_hwe(struct xe_oa *oa, struct xe_oa_open_param *param) return ret; } -static int xe_oa_set_prop_oa_unit_id(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ - if (value >= oa->oa_unit_ids) { - drm_dbg(&oa->xe->drm, "OA unit ID out of range %lld\n", value); - return -EINVAL; - } - param->oa_unit_id = value; - return 0; -} - -static int xe_oa_set_prop_sample_oa(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ - param->sample = value; - return 0; -} - -static int xe_oa_set_prop_metric_set(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ - param->metric_set = value; - return 0; -} - -static int xe_oa_set_prop_oa_format(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ - int ret = decode_oa_format(oa, value, ¶m->oa_format); - - if (ret) { - drm_dbg(&oa->xe->drm, "Unsupported OA report format %#llx\n", value); - return ret; - } - return 0; -} - -static int xe_oa_set_prop_oa_exponent(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ -#define OA_EXPONENT_MAX 31 - - if (value > OA_EXPONENT_MAX) { - drm_dbg(&oa->xe->drm, "OA timer exponent too high (> %u)\n", OA_EXPONENT_MAX); - return -EINVAL; - } - param->period_exponent = value; - return 0; -} - -static int xe_oa_set_prop_disabled(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ - param->disabled = value; - return 0; -} - -static int xe_oa_set_prop_exec_queue_id(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ - param->exec_queue_id = value; - return 0; -} - -static int xe_oa_set_prop_engine_instance(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ - param->engine_instance = value; - return 0; -} - -static int xe_oa_set_no_preempt(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param) -{ - param->no_preempt = value; - return 0; -} - -typedef int (*xe_oa_set_property_fn)(struct xe_oa *oa, u64 value, - struct xe_oa_open_param *param); -static const xe_oa_set_property_fn xe_oa_set_property_funcs[] = { - [DRM_XE_OA_PROPERTY_OA_UNIT_ID] = xe_oa_set_prop_oa_unit_id, - [DRM_XE_OA_PROPERTY_SAMPLE_OA] = xe_oa_set_prop_sample_oa, - [DRM_XE_OA_PROPERTY_OA_METRIC_SET] = xe_oa_set_prop_metric_set, - [DRM_XE_OA_PROPERTY_OA_FORMAT] = xe_oa_set_prop_oa_format, - [DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT] = xe_oa_set_prop_oa_exponent, - [DRM_XE_OA_PROPERTY_OA_DISABLED] = xe_oa_set_prop_disabled, - [DRM_XE_OA_PROPERTY_EXEC_QUEUE_ID] = xe_oa_set_prop_exec_queue_id, - [DRM_XE_OA_PROPERTY_OA_ENGINE_INSTANCE] = xe_oa_set_prop_engine_instance, - [DRM_XE_OA_PROPERTY_NO_PREEMPT] = xe_oa_set_no_preempt, -}; - -static int xe_oa_user_ext_set_property(struct xe_oa *oa, u64 extension, - struct xe_oa_open_param *param) -{ - u64 __user *address = u64_to_user_ptr(extension); - struct drm_xe_ext_set_property ext; - int err; - u32 idx; - - err = __copy_from_user(&ext, address, sizeof(ext)); - if (XE_IOCTL_DBG(oa->xe, err)) - return -EFAULT; - - if (XE_IOCTL_DBG(oa->xe, ext.property >= ARRAY_SIZE(xe_oa_set_property_funcs)) || - XE_IOCTL_DBG(oa->xe, ext.pad)) - return -EINVAL; - - idx = array_index_nospec(ext.property, ARRAY_SIZE(xe_oa_set_property_funcs)); - return xe_oa_set_property_funcs[idx](oa, ext.value, param); -} - -typedef int (*xe_oa_user_extension_fn)(struct xe_oa *oa, u64 extension, - struct xe_oa_open_param *param); -static const xe_oa_user_extension_fn xe_oa_user_extension_funcs[] = { - [DRM_XE_OA_EXTENSION_SET_PROPERTY] = xe_oa_user_ext_set_property, -}; - -#define MAX_USER_EXTENSIONS 16 -static int xe_oa_user_extensions(struct xe_oa *oa, u64 extension, int ext_number, - struct xe_oa_open_param *param) -{ - u64 __user *address = u64_to_user_ptr(extension); - struct drm_xe_user_extension ext; - int err; - u32 idx; - - if (XE_IOCTL_DBG(oa->xe, ext_number >= MAX_USER_EXTENSIONS)) - return -E2BIG; - - err = __copy_from_user(&ext, address, sizeof(ext)); - if (XE_IOCTL_DBG(oa->xe, err)) - return -EFAULT; - - if (XE_IOCTL_DBG(oa->xe, ext.pad) || - XE_IOCTL_DBG(oa->xe, ext.name >= ARRAY_SIZE(xe_oa_user_extension_funcs))) - return -EINVAL; - - idx = array_index_nospec(ext.name, ARRAY_SIZE(xe_oa_user_extension_funcs)); - err = xe_oa_user_extension_funcs[idx](oa, extension, param); - if (XE_IOCTL_DBG(oa->xe, err)) - return err; - - if (ext.next_extension) - return xe_oa_user_extensions(oa, ext.next_extension, ++ext_number, param); - - return 0; -} - /** * xe_oa_stream_open_ioctl - Opens an OA stream * @dev: @drm_device @@ -1808,7 +2056,8 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f return -ENODEV; } - ret = xe_oa_user_extensions(oa, data, 0, ¶m); + param.xef = xef; + ret = xe_oa_user_extensions(oa, XE_OA_USER_EXTN_FROM_OPEN, data, 0, ¶m); if (ret) return ret; @@ -1876,11 +2125,24 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f drm_dbg(&oa->xe->drm, "Using periodic sampling freq %lld Hz\n", oa_freq_hz); } + ret = xe_oa_parse_syncs(oa, ¶m); + if (ret) + goto err_exec_q; + mutex_lock(¶m.hwe->gt->oa.gt_lock); ret = xe_oa_stream_open_ioctl_locked(oa, ¶m); mutex_unlock(¶m.hwe->gt->oa.gt_lock); + if (ret < 0) + goto err_sync_cleanup; + + return ret; + +err_sync_cleanup: + while (param.num_syncs--) + xe_sync_entry_cleanup(¶m.syncs[param.num_syncs]); + kfree(param.syncs); err_exec_q: - if (ret < 0 && param.exec_q) + if (param.exec_q) xe_exec_queue_put(param.exec_q); return ret; } @@ -2351,7 +2613,7 @@ static void __xe_oa_init_oa_units(struct xe_gt *gt) } /* Ensure MMIO trigger remains disabled till there is a stream */ - xe_mmio_write32(gt, u->regs.oa_debug, + xe_mmio_write32(>->mmio, u->regs.oa_debug, oag_configure_mmio_trigger(NULL, false)); /* Set oa_unit_ids now to ensure ids remain contiguous */ diff --git a/drivers/gpu/drm/xe/xe_oa_types.h b/drivers/gpu/drm/xe/xe_oa_types.h index 8862eca73fbe32..fea9d981e414fa 100644 --- a/drivers/gpu/drm/xe/xe_oa_types.h +++ b/drivers/gpu/drm/xe/xe_oa_types.h @@ -238,5 +238,17 @@ struct xe_oa_stream { /** @no_preempt: Whether preemption and timeslicing is disabled for stream exec_q */ u32 no_preempt; + + /** @xef: xe_file with which the stream was opened */ + struct xe_file *xef; + + /** @last_fence: fence to use in stream destroy when needed */ + struct dma_fence *last_fence; + + /** @num_syncs: size of @syncs array */ + u32 num_syncs; + + /** @syncs: syncs to wait on and to signal */ + struct xe_sync_entry *syncs; }; #endif diff --git a/drivers/gpu/drm/xe/xe_pat.c b/drivers/gpu/drm/xe/xe_pat.c index f291a1730024a0..30fdbdb9341e89 100644 --- a/drivers/gpu/drm/xe/xe_pat.c +++ b/drivers/gpu/drm/xe/xe_pat.c @@ -100,6 +100,10 @@ static const struct xe_pat_table_entry xelpg_pat_table[] = { * Reserved entries should be programmed with the maximum caching, minimum * coherency (which matches an all-0's encoding), so we can just omit them * in the table. + * + * Note: There is an implicit assumption in the driver that compression and + * coh_1way+ are mutually exclusive. If this is ever not true then userptr + * and imported dma-buf from external device will have uncleared ccs state. */ #define XE2_PAT(no_promote, comp_en, l3clos, l3_policy, l4_policy, __coh_mode) \ { \ @@ -109,7 +113,8 @@ static const struct xe_pat_table_entry xelpg_pat_table[] = { REG_FIELD_PREP(XE2_L3_POLICY, l3_policy) | \ REG_FIELD_PREP(XE2_L4_POLICY, l4_policy) | \ REG_FIELD_PREP(XE2_COH_MODE, __coh_mode), \ - .coh_mode = __coh_mode ? XE_COH_AT_LEAST_1WAY : XE_COH_NONE \ + .coh_mode = (BUILD_BUG_ON_ZERO(__coh_mode && comp_en) || __coh_mode) ? \ + XE_COH_AT_LEAST_1WAY : XE_COH_NONE \ } static const struct xe_pat_table_entry xe2_pat_table[] = { @@ -160,7 +165,7 @@ static void program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[ for (int i = 0; i < n_entries; i++) { struct xe_reg reg = XE_REG(_PAT_INDEX(i)); - xe_mmio_write32(gt, reg, table[i].value); + xe_mmio_write32(>->mmio, reg, table[i].value); } } @@ -177,25 +182,24 @@ static void program_pat_mcr(struct xe_gt *gt, const struct xe_pat_table_entry ta static void xelp_dump(struct xe_gt *gt, struct drm_printer *p) { struct xe_device *xe = gt_to_xe(gt); - int i, err; + unsigned int fw_ref; + int i; - err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - if (err) - goto err_fw; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) + return; drm_printf(p, "PAT table:\n"); for (i = 0; i < xe->pat.n_entries; i++) { - u32 pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i))); + u32 pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); u8 mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat); drm_printf(p, "PAT[%2d] = %s (%#8x)\n", i, XELP_MEM_TYPE_STR_MAP[mem_type], pat); } - err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); -err_fw: - xe_assert(xe, !err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); } static const struct xe_pat_ops xelp_pat_ops = { @@ -206,11 +210,12 @@ static const struct xe_pat_ops xelp_pat_ops = { static void xehp_dump(struct xe_gt *gt, struct drm_printer *p) { struct xe_device *xe = gt_to_xe(gt); - int i, err; + unsigned int fw_ref; + int i; - err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - if (err) - goto err_fw; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) + return; drm_printf(p, "PAT table:\n"); @@ -224,9 +229,7 @@ static void xehp_dump(struct xe_gt *gt, struct drm_printer *p) XELP_MEM_TYPE_STR_MAP[mem_type], pat); } - err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); -err_fw: - xe_assert(xe, !err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); } static const struct xe_pat_ops xehp_pat_ops = { @@ -237,11 +240,12 @@ static const struct xe_pat_ops xehp_pat_ops = { static void xehpc_dump(struct xe_gt *gt, struct drm_printer *p) { struct xe_device *xe = gt_to_xe(gt); - int i, err; + unsigned int fw_ref; + int i; - err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - if (err) - goto err_fw; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) + return; drm_printf(p, "PAT table:\n"); @@ -253,9 +257,7 @@ static void xehpc_dump(struct xe_gt *gt, struct drm_printer *p) REG_FIELD_GET(XEHPC_CLOS_LEVEL_MASK, pat), pat); } - err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); -err_fw: - xe_assert(xe, !err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); } static const struct xe_pat_ops xehpc_pat_ops = { @@ -266,11 +268,12 @@ static const struct xe_pat_ops xehpc_pat_ops = { static void xelpg_dump(struct xe_gt *gt, struct drm_printer *p) { struct xe_device *xe = gt_to_xe(gt); - int i, err; + unsigned int fw_ref; + int i; - err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - if (err) - goto err_fw; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) + return; drm_printf(p, "PAT table:\n"); @@ -278,7 +281,7 @@ static void xelpg_dump(struct xe_gt *gt, struct drm_printer *p) u32 pat; if (xe_gt_is_media_type(gt)) - pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i))); + pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); else pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); @@ -287,9 +290,7 @@ static void xelpg_dump(struct xe_gt *gt, struct drm_printer *p) REG_FIELD_GET(XELPG_INDEX_COH_MODE_MASK, pat), pat); } - err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); -err_fw: - xe_assert(xe, !err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); } /* @@ -316,27 +317,28 @@ static void xe2lpm_program_pat(struct xe_gt *gt, const struct xe_pat_table_entry int n_entries) { program_pat(gt, table, n_entries); - xe_mmio_write32(gt, XE_REG(_PAT_ATS), xe2_pat_ats.value); + xe_mmio_write32(>->mmio, XE_REG(_PAT_ATS), xe2_pat_ats.value); if (IS_DGFX(gt_to_xe(gt))) - xe_mmio_write32(gt, XE_REG(_PAT_PTA), xe2_pat_pta.value); + xe_mmio_write32(>->mmio, XE_REG(_PAT_PTA), xe2_pat_pta.value); } static void xe2_dump(struct xe_gt *gt, struct drm_printer *p) { struct xe_device *xe = gt_to_xe(gt); - int i, err; + unsigned int fw_ref; u32 pat; + int i; - err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - if (err) - goto err_fw; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) + return; drm_printf(p, "PAT table:\n"); for (i = 0; i < xe->pat.n_entries; i++) { if (xe_gt_is_media_type(gt)) - pat = xe_mmio_read32(gt, XE_REG(_PAT_INDEX(i))); + pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); else pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); @@ -355,7 +357,7 @@ static void xe2_dump(struct xe_gt *gt, struct drm_printer *p) * PPGTT entries. */ if (xe_gt_is_media_type(gt)) - pat = xe_mmio_read32(gt, XE_REG(_PAT_PTA)); + pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_PTA)); else pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA)); @@ -369,9 +371,7 @@ static void xe2_dump(struct xe_gt *gt, struct drm_printer *p) REG_FIELD_GET(XE2_COH_MODE, pat), pat); - err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); -err_fw: - xe_assert(xe, !err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); } static const struct xe_pat_ops xe2_pat_ops = { @@ -382,7 +382,7 @@ static const struct xe_pat_ops xe2_pat_ops = { void xe_pat_init_early(struct xe_device *xe) { - if (GRAPHICS_VER(xe) == 20) { + if (GRAPHICS_VER(xe) == 30 || GRAPHICS_VER(xe) == 20) { xe->pat.ops = &xe2_pat_ops; xe->pat.table = xe2_pat_table; diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 5e962e72c97ea6..6b7f77425c7f9f 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "display/xe_display.h" #include "regs/xe_gt_regs.h" @@ -103,7 +103,6 @@ static const struct xe_graphics_desc graphics_xelpp = { #define XE_HP_FEATURES \ .has_range_tlb_invalidation = true, \ - .has_flat_ccs = true, \ .dma_mask_size = 46, \ .va_bits = 48, \ .vm_max_level = 3 @@ -120,6 +119,8 @@ static const struct xe_graphics_desc graphics_xehpg = { XE_HP_FEATURES, .vram_flags = XE_VRAM_FLAGS_NEED64K, + + .has_flat_ccs = 1, }; static const struct xe_graphics_desc graphics_xehpc = { @@ -145,7 +146,6 @@ static const struct xe_graphics_desc graphics_xehpc = { .has_asid = 1, .has_atomic_enable_pte_bit = 1, - .has_flat_ccs = 0, .has_usm = 1, }; @@ -156,7 +156,6 @@ static const struct xe_graphics_desc graphics_xelpg = { BIT(XE_HW_ENGINE_CCS0), XE_HP_FEATURES, - .has_flat_ccs = 0, }; #define XE2_GFX_FEATURES \ @@ -175,7 +174,7 @@ static const struct xe_graphics_desc graphics_xelpg = { GENMASK(XE_HW_ENGINE_CCS3, XE_HW_ENGINE_CCS0) static const struct xe_graphics_desc graphics_xe2 = { - .name = "Xe2_LPG / Xe2_HPG", + .name = "Xe2_LPG / Xe2_HPG / Xe3_LPG", XE2_GFX_FEATURES, }; @@ -209,7 +208,7 @@ static const struct xe_media_desc media_xelpmp = { }; static const struct xe_media_desc media_xe2 = { - .name = "Xe2_LPM / Xe2_HPM", + .name = "Xe2_LPM / Xe2_HPM / Xe3_LPM", .hw_engine_mask = GENMASK(XE_HW_ENGINE_VCS7, XE_HW_ENGINE_VCS0) | GENMASK(XE_HW_ENGINE_VECS3, XE_HW_ENGINE_VECS0) | @@ -234,7 +233,7 @@ static const struct xe_device_desc rkl_desc = { .require_force_probe = true, }; -static const u16 adls_rpls_ids[] = { XE_RPLS_IDS(NOP), 0 }; +static const u16 adls_rpls_ids[] = { INTEL_RPLS_IDS(NOP), 0 }; static const struct xe_device_desc adl_s_desc = { .graphics = &graphics_xelp, @@ -249,7 +248,7 @@ static const struct xe_device_desc adl_s_desc = { }, }; -static const u16 adlp_rplu_ids[] = { XE_RPLU_IDS(NOP), 0 }; +static const u16 adlp_rplu_ids[] = { INTEL_RPLU_IDS(NOP), 0 }; static const struct xe_device_desc adl_p_desc = { .graphics = &graphics_xelp, @@ -286,9 +285,9 @@ static const struct xe_device_desc dg1_desc = { .require_force_probe = true, }; -static const u16 dg2_g10_ids[] = { XE_DG2_G10_IDS(NOP), XE_ATS_M150_IDS(NOP), 0 }; -static const u16 dg2_g11_ids[] = { XE_DG2_G11_IDS(NOP), XE_ATS_M75_IDS(NOP), 0 }; -static const u16 dg2_g12_ids[] = { XE_DG2_G12_IDS(NOP), 0 }; +static const u16 dg2_g10_ids[] = { INTEL_DG2_G10_IDS(NOP), INTEL_ATS_M150_IDS(NOP), 0 }; +static const u16 dg2_g11_ids[] = { INTEL_DG2_G11_IDS(NOP), INTEL_ATS_M75_IDS(NOP), 0 }; +static const u16 dg2_g12_ids[] = { INTEL_DG2_G12_IDS(NOP), 0 }; #define DG2_FEATURES \ DGFX_FEATURES, \ @@ -347,6 +346,12 @@ static const struct xe_device_desc bmg_desc = { .has_heci_cscfi = 1, }; +static const struct xe_device_desc ptl_desc = { + PLATFORM(PANTHERLAKE), + .has_display = true, + .require_force_probe = true, +}; + #undef PLATFORM __diag_pop(); @@ -357,6 +362,8 @@ static const struct gmdid_map graphics_ip_map[] = { { 1274, &graphics_xelpg }, /* Xe_LPG+ */ { 2001, &graphics_xe2 }, { 2004, &graphics_xe2 }, + { 3000, &graphics_xe2 }, + { 3001, &graphics_xe2 }, }; /* Map of GMD_ID values to media IP */ @@ -364,13 +371,9 @@ static const struct gmdid_map media_ip_map[] = { { 1300, &media_xelpmp }, { 1301, &media_xe2 }, { 2000, &media_xe2 }, + { 3000, &media_xe2 }, }; -#define INTEL_VGA_DEVICE(id, info) { \ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, id), \ - PCI_BASE_CLASS_DISPLAY << 16, 0xff << 16, \ - (unsigned long) info } - /* * Make sure any device matches here are from most specific to most * general. For example, since the Quanta match is based on the subsystem @@ -378,25 +381,26 @@ static const struct gmdid_map media_ip_map[] = { * PCI ID matches, otherwise we'll use the wrong info struct above. */ static const struct pci_device_id pciidlist[] = { - XE_TGL_IDS(INTEL_VGA_DEVICE, &tgl_desc), - XE_RKL_IDS(INTEL_VGA_DEVICE, &rkl_desc), - XE_ADLS_IDS(INTEL_VGA_DEVICE, &adl_s_desc), - XE_ADLP_IDS(INTEL_VGA_DEVICE, &adl_p_desc), - XE_ADLN_IDS(INTEL_VGA_DEVICE, &adl_n_desc), - XE_RPLP_IDS(INTEL_VGA_DEVICE, &adl_p_desc), - XE_RPLS_IDS(INTEL_VGA_DEVICE, &adl_s_desc), - XE_DG1_IDS(INTEL_VGA_DEVICE, &dg1_desc), - XE_ATS_M_IDS(INTEL_VGA_DEVICE, &ats_m_desc), - XE_DG2_IDS(INTEL_VGA_DEVICE, &dg2_desc), - XE_MTL_IDS(INTEL_VGA_DEVICE, &mtl_desc), - XE_LNL_IDS(INTEL_VGA_DEVICE, &lnl_desc), - XE_BMG_IDS(INTEL_VGA_DEVICE, &bmg_desc), + INTEL_TGL_IDS(INTEL_VGA_DEVICE, &tgl_desc), + INTEL_RKL_IDS(INTEL_VGA_DEVICE, &rkl_desc), + INTEL_ADLS_IDS(INTEL_VGA_DEVICE, &adl_s_desc), + INTEL_ADLP_IDS(INTEL_VGA_DEVICE, &adl_p_desc), + INTEL_ADLN_IDS(INTEL_VGA_DEVICE, &adl_n_desc), + INTEL_RPLU_IDS(INTEL_VGA_DEVICE, &adl_p_desc), + INTEL_RPLP_IDS(INTEL_VGA_DEVICE, &adl_p_desc), + INTEL_RPLS_IDS(INTEL_VGA_DEVICE, &adl_s_desc), + INTEL_DG1_IDS(INTEL_VGA_DEVICE, &dg1_desc), + INTEL_ATS_M_IDS(INTEL_VGA_DEVICE, &ats_m_desc), + INTEL_ARL_IDS(INTEL_VGA_DEVICE, &mtl_desc), + INTEL_DG2_IDS(INTEL_VGA_DEVICE, &dg2_desc), + INTEL_MTL_IDS(INTEL_VGA_DEVICE, &mtl_desc), + INTEL_LNL_IDS(INTEL_VGA_DEVICE, &lnl_desc), + INTEL_BMG_IDS(INTEL_VGA_DEVICE, &bmg_desc), + INTEL_PTL_IDS(INTEL_VGA_DEVICE, &ptl_desc), { } }; MODULE_DEVICE_TABLE(pci, pciidlist); -#undef INTEL_VGA_DEVICE - /* is device_id present in comma separated list of ids */ static bool device_id_in_list(u16 device_id, const char *devices, bool negative) { @@ -467,13 +471,15 @@ enum xe_gmdid_type { static void read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver, u32 *revid) { - struct xe_gt *gt = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); struct xe_reg gmdid_reg = GMD_ID; u32 val; KUNIT_STATIC_STUB_REDIRECT(read_gmdid, xe, type, ver, revid); if (IS_SRIOV_VF(xe)) { + struct xe_gt *gt = xe_root_mmio_gt(xe); + /* * To get the value of the GMDID register, VFs must obtain it * from the GuC using MMIO communication. @@ -509,14 +515,17 @@ static void read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver, gt->info.type = XE_GT_TYPE_UNINITIALIZED; } else { /* - * We need to apply the GSI offset explicitly here as at this - * point the xe_gt is not fully uninitialized and only basic - * access to MMIO registers is possible. + * GMD_ID is a GT register, but at this point in the driver + * init we haven't fully initialized the GT yet so we need to + * read the register with the tile's MMIO accessor. That means + * we need to apply the GSI offset manually since it won't get + * automatically added as it would if we were using a GT mmio + * accessor. */ if (type == GMDID_MEDIA) gmdid_reg.addr += MEDIA_GT_GSI_OFFSET; - val = xe_mmio_read32(gt, gmdid_reg); + val = xe_mmio_read32(mmio, gmdid_reg); } *ver = REG_FIELD_GET(GMD_ID_ARCH_MASK, val) * 100 + REG_FIELD_GET(GMD_ID_RELEASE_MASK, val); @@ -678,7 +687,10 @@ static int xe_info_init(struct xe_device *xe, xe->info.has_atomic_enable_pte_bit = graphics_desc->has_atomic_enable_pte_bit; if (xe->info.platform != XE_PVC) xe->info.has_device_atomics_on_smem = 1; + + /* Runtime detection may change this later */ xe->info.has_flat_ccs = graphics_desc->has_flat_ccs; + xe->info.has_range_tlb_invalidation = graphics_desc->has_range_tlb_invalidation; xe->info.has_usm = graphics_desc->has_usm; @@ -707,6 +719,7 @@ static int xe_info_init(struct xe_device *xe, gt->info.type = XE_GT_TYPE_MAIN; gt->info.has_indirect_ring_state = graphics_desc->has_indirect_ring_state; gt->info.engine_mask = graphics_desc->hw_engine_mask; + if (MEDIA_VER(xe) < 13 && media_desc) gt->info.engine_mask |= media_desc->hw_engine_mask; @@ -725,8 +738,6 @@ static int xe_info_init(struct xe_device *xe, gt->info.type = XE_GT_TYPE_MEDIA; gt->info.has_indirect_ring_state = media_desc->has_indirect_ring_state; gt->info.engine_mask = media_desc->hw_engine_mask; - gt->mmio.adj_offset = MEDIA_GT_GSI_OFFSET; - gt->mmio.adj_limit = MEDIA_GT_GSI_LENGTH; /* * FIXME: At the moment multi-tile and standalone media are @@ -757,6 +768,25 @@ static void xe_pci_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +/* + * Probe the PCI device, initialize various parts of the driver. + * + * Fault injection is used to test the error paths of some initialization + * functions called either directly from xe_pci_probe() or indirectly for + * example through xe_device_probe(). Those functions use the kernel fault + * injection capabilities infrastructure, see + * Documentation/fault-injection/fault-injection.rst for details. The macro + * ALLOW_ERROR_INJECTION() is used to conditionally skip function execution + * at runtime and use a provided return value. The first requirement for + * error injectable functions is proper handling of the error code by the + * caller for recovery, which is always the case here. The second + * requirement is that no state is changed before the first error return. + * It is not strictly fullfilled for all initialization functions using the + * ALLOW_ERROR_INJECTION() macro but this is acceptable because for those + * error cases at probe time, the error code is simply propagated up by the + * caller. Therefore there is no consequence on those specific callers when + * function error injection skips the whole function. + */ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { const struct xe_device_desc *desc = (const void *)ent->driver_data; diff --git a/drivers/gpu/drm/xe/xe_pcode.c b/drivers/gpu/drm/xe/xe_pcode.c index 7397d556996ad4..d95d9835de4238 100644 --- a/drivers/gpu/drm/xe/xe_pcode.c +++ b/drivers/gpu/drm/xe/xe_pcode.c @@ -44,7 +44,7 @@ static int pcode_mailbox_status(struct xe_tile *tile) [PCODE_ERROR_MASK] = {-EPROTO, "Unknown"}, }; - err = xe_mmio_read32(tile->primary_gt, PCODE_MAILBOX) & PCODE_ERROR_MASK; + err = xe_mmio_read32(&tile->mmio, PCODE_MAILBOX) & PCODE_ERROR_MASK; if (err) { drm_err(&tile_to_xe(tile)->drm, "PCODE Mailbox failed: %d %s", err, err_decode[err].str ?: "Unknown"); @@ -58,7 +58,7 @@ static int __pcode_mailbox_rw(struct xe_tile *tile, u32 mbox, u32 *data0, u32 *d unsigned int timeout_ms, bool return_data, bool atomic) { - struct xe_gt *mmio = tile->primary_gt; + struct xe_mmio *mmio = &tile->mmio; int err; if (tile_to_xe(tile)->info.skip_pcode) diff --git a/drivers/gpu/drm/xe/xe_platform_types.h b/drivers/gpu/drm/xe/xe_platform_types.h index 79b7042c4534ed..d08574c4cdb8b0 100644 --- a/drivers/gpu/drm/xe/xe_platform_types.h +++ b/drivers/gpu/drm/xe/xe_platform_types.h @@ -23,6 +23,7 @@ enum xe_platform { XE_METEORLAKE, XE_LUNARLAKE, XE_BATTLEMAGE, + XE_PANTHERLAKE, }; enum xe_subplatform { diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c index 33eb039053e4f5..40f7c844ed44ae 100644 --- a/drivers/gpu/drm/xe/xe_pm.c +++ b/drivers/gpu/drm/xe/xe_pm.c @@ -5,6 +5,7 @@ #include "xe_pm.h" +#include #include #include @@ -263,6 +264,7 @@ int xe_pm_init_early(struct xe_device *xe) return 0; } +ALLOW_ERROR_INJECTION(xe_pm_init_early, ERRNO); /* See xe_pci_probe() */ /** * xe_pm_init - Initialize Xe Power Management diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index f27f579f4d85aa..797576690356f2 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -1333,8 +1333,7 @@ static void invalidation_fence_cb(struct dma_fence *fence, queue_work(system_wq, &ifence->work); } else { ifence->base.base.error = ifence->fence->error; - dma_fence_signal(&ifence->base.base); - dma_fence_put(&ifence->base.base); + xe_gt_tlb_invalidation_fence_signal(&ifence->base); } dma_fence_put(ifence->fence); } diff --git a/drivers/gpu/drm/xe/xe_query.c b/drivers/gpu/drm/xe/xe_query.c index 848da8e68c7a83..170ae72d1a7bb7 100644 --- a/drivers/gpu/drm/xe/xe_query.c +++ b/drivers/gpu/drm/xe/xe_query.c @@ -9,6 +9,7 @@ #include #include +#include #include #include "regs/xe_engine_regs.h" @@ -23,6 +24,7 @@ #include "xe_macros.h" #include "xe_mmio.h" #include "xe_ttm_vram_mgr.h" +#include "xe_wa.h" static const u16 xe_to_user_engine_class[] = { [XE_ENGINE_CLASS_RENDER] = DRM_XE_ENGINE_CLASS_RENDER, @@ -83,24 +85,22 @@ static __ktime_func_t __clock_id_to_func(clockid_t clk_id) } static void -__read_timestamps(struct xe_gt *gt, - struct xe_reg lower_reg, - struct xe_reg upper_reg, - u64 *engine_ts, - u64 *cpu_ts, - u64 *cpu_delta, - __ktime_func_t cpu_clock) +hwe_read_timestamp(struct xe_hw_engine *hwe, u64 *engine_ts, u64 *cpu_ts, + u64 *cpu_delta, __ktime_func_t cpu_clock) { + struct xe_mmio *mmio = &hwe->gt->mmio; u32 upper, lower, old_upper, loop = 0; + struct xe_reg upper_reg = RING_TIMESTAMP_UDW(hwe->mmio_base), + lower_reg = RING_TIMESTAMP(hwe->mmio_base); - upper = xe_mmio_read32(gt, upper_reg); + upper = xe_mmio_read32(mmio, upper_reg); do { *cpu_delta = local_clock(); *cpu_ts = cpu_clock(); - lower = xe_mmio_read32(gt, lower_reg); + lower = xe_mmio_read32(mmio, lower_reg); *cpu_delta = local_clock() - *cpu_delta; old_upper = upper; - upper = xe_mmio_read32(gt, upper_reg); + upper = xe_mmio_read32(mmio, upper_reg); } while (upper != old_upper && loop++ < 2); *engine_ts = (u64)upper << 32 | lower; @@ -117,6 +117,7 @@ query_engine_cycles(struct xe_device *xe, __ktime_func_t cpu_clock; struct xe_hw_engine *hwe; struct xe_gt *gt; + unsigned int fw_ref; if (query->size == 0) { query->size = size; @@ -149,18 +150,16 @@ query_engine_cycles(struct xe_device *xe, if (!hwe) return -EINVAL; - if (xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL)) + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { + xe_force_wake_put(gt_to_fw(gt), fw_ref); return -EIO; + } - __read_timestamps(gt, - RING_TIMESTAMP(hwe->mmio_base), - RING_TIMESTAMP_UDW(hwe->mmio_base), - &resp.engine_cycles, - &resp.cpu_timestamp, - &resp.cpu_delta, - cpu_clock); + hwe_read_timestamp(hwe, &resp.engine_cycles, &resp.cpu_timestamp, + &resp.cpu_delta, cpu_clock); - xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL); + xe_force_wake_put(gt_to_fw(gt), fw_ref); if (GRAPHICS_VER(xe) >= 20) resp.width = 64; @@ -168,16 +167,10 @@ query_engine_cycles(struct xe_device *xe, resp.width = 36; /* Only write to the output fields of user query */ - if (put_user(resp.cpu_timestamp, &query_ptr->cpu_timestamp)) - return -EFAULT; - - if (put_user(resp.cpu_delta, &query_ptr->cpu_delta)) - return -EFAULT; - - if (put_user(resp.engine_cycles, &query_ptr->engine_cycles)) - return -EFAULT; - - if (put_user(resp.width, &query_ptr->width)) + if (put_user(resp.cpu_timestamp, &query_ptr->cpu_timestamp) || + put_user(resp.cpu_delta, &query_ptr->cpu_delta) || + put_user(resp.engine_cycles, &query_ptr->engine_cycles) || + put_user(resp.width, &query_ptr->width)) return -EFAULT; return 0; @@ -458,12 +451,23 @@ static int query_hwconfig(struct xe_device *xe, static size_t calc_topo_query_size(struct xe_device *xe) { - return xe->info.gt_count * - (4 * sizeof(struct drm_xe_query_topology_mask) + - sizeof_field(struct xe_gt, fuse_topo.g_dss_mask) + - sizeof_field(struct xe_gt, fuse_topo.c_dss_mask) + - sizeof_field(struct xe_gt, fuse_topo.l3_bank_mask) + - sizeof_field(struct xe_gt, fuse_topo.eu_mask_per_dss)); + struct xe_gt *gt; + size_t query_size = 0; + int id; + + for_each_gt(gt, xe, id) { + query_size += 3 * sizeof(struct drm_xe_query_topology_mask) + + sizeof_field(struct xe_gt, fuse_topo.g_dss_mask) + + sizeof_field(struct xe_gt, fuse_topo.c_dss_mask) + + sizeof_field(struct xe_gt, fuse_topo.eu_mask_per_dss); + + /* L3bank mask may not be available for some GTs */ + if (!XE_WA(gt, no_media_l3)) + query_size += sizeof(struct drm_xe_query_topology_mask) + + sizeof_field(struct xe_gt, fuse_topo.l3_bank_mask); + } + + return query_size; } static int copy_mask(void __user **ptr, @@ -516,11 +520,18 @@ static int query_gt_topology(struct xe_device *xe, if (err) return err; - topo.type = DRM_XE_TOPO_L3_BANK; - err = copy_mask(&query_ptr, &topo, gt->fuse_topo.l3_bank_mask, - sizeof(gt->fuse_topo.l3_bank_mask)); - if (err) - return err; + /* + * If the kernel doesn't have a way to obtain a correct L3bank + * mask, then it's better to omit L3 from the query rather than + * reporting bogus or zeroed information to userspace. + */ + if (!XE_WA(gt, no_media_l3)) { + topo.type = DRM_XE_TOPO_L3_BANK; + err = copy_mask(&query_ptr, &topo, gt->fuse_topo.l3_bank_mask, + sizeof(gt->fuse_topo.l3_bank_mask)); + if (err) + return err; + } topo.type = gt->fuse_topo.eu_type == XE_GT_EU_TYPE_SIMD16 ? DRM_XE_TOPO_SIMD16_EU_PER_DSS : @@ -659,7 +670,7 @@ static int query_oa_units(struct xe_device *xe, du->oa_unit_id = u->oa_unit_id; du->oa_unit_type = u->type; du->oa_timestamp_freq = xe_oa_timestamp_frequency(gt); - du->capabilities = DRM_XE_OA_CAPS_BASE; + du->capabilities = DRM_XE_OA_CAPS_BASE | DRM_XE_OA_CAPS_SYNCS; j = 0; for_each_hw_engine(hwe, gt, hwe_id) { diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c index 440ac572f6e5ef..c13123008e9036 100644 --- a/drivers/gpu/drm/xe/xe_reg_sr.c +++ b/drivers/gpu/drm/xe/xe_reg_sr.c @@ -15,6 +15,7 @@ #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" +#include "xe_device.h" #include "xe_device_types.h" #include "xe_force_wake.h" #include "xe_gt.h" @@ -26,46 +27,27 @@ #include "xe_reg_whitelist.h" #include "xe_rtp_types.h" -#define XE_REG_SR_GROW_STEP_DEFAULT 16 - static void reg_sr_fini(struct drm_device *drm, void *arg) { struct xe_reg_sr *sr = arg; + struct xe_reg_sr_entry *entry; + unsigned long reg; + + xa_for_each(&sr->xa, reg, entry) + kfree(entry); xa_destroy(&sr->xa); - kfree(sr->pool.arr); - memset(&sr->pool, 0, sizeof(sr->pool)); } int xe_reg_sr_init(struct xe_reg_sr *sr, const char *name, struct xe_device *xe) { xa_init(&sr->xa); - memset(&sr->pool, 0, sizeof(sr->pool)); - sr->pool.grow_step = XE_REG_SR_GROW_STEP_DEFAULT; sr->name = name; return drmm_add_action_or_reset(&xe->drm, reg_sr_fini, sr); } EXPORT_SYMBOL_IF_KUNIT(xe_reg_sr_init); -static struct xe_reg_sr_entry *alloc_entry(struct xe_reg_sr *sr) -{ - if (sr->pool.used == sr->pool.allocated) { - struct xe_reg_sr_entry *arr; - - arr = krealloc_array(sr->pool.arr, - ALIGN(sr->pool.allocated + 1, sr->pool.grow_step), - sizeof(*arr), GFP_KERNEL); - if (!arr) - return NULL; - - sr->pool.arr = arr; - sr->pool.allocated += sr->pool.grow_step; - } - - return &sr->pool.arr[sr->pool.used++]; -} - static bool compatible_entries(const struct xe_reg_sr_entry *e1, const struct xe_reg_sr_entry *e2) { @@ -111,7 +93,7 @@ int xe_reg_sr_add(struct xe_reg_sr *sr, return 0; } - pentry = alloc_entry(sr); + pentry = kmalloc(sizeof(*pentry), GFP_KERNEL); if (!pentry) { ret = -ENOMEM; goto fail; @@ -164,7 +146,7 @@ static void apply_one_mmio(struct xe_gt *gt, struct xe_reg_sr_entry *entry) else if (entry->clr_bits + 1) val = (reg.mcr ? xe_gt_mcr_unicast_read_any(gt, reg_mcr) : - xe_mmio_read32(gt, reg)) & (~entry->clr_bits); + xe_mmio_read32(>->mmio, reg)) & (~entry->clr_bits); else val = 0; @@ -180,34 +162,34 @@ static void apply_one_mmio(struct xe_gt *gt, struct xe_reg_sr_entry *entry) if (entry->reg.mcr) xe_gt_mcr_multicast_write(gt, reg_mcr, val); else - xe_mmio_write32(gt, reg, val); + xe_mmio_write32(>->mmio, reg, val); } void xe_reg_sr_apply_mmio(struct xe_reg_sr *sr, struct xe_gt *gt) { struct xe_reg_sr_entry *entry; unsigned long reg; - int err; + unsigned int fw_ref; if (xa_empty(&sr->xa)) return; xe_gt_dbg(gt, "Applying %s save-restore MMIOs\n", sr->name); - err = xe_force_wake_get(>->mmio.fw, XE_FORCEWAKE_ALL); - if (err) + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) goto err_force_wake; xa_for_each(&sr->xa, reg, entry) apply_one_mmio(gt, entry); - err = xe_force_wake_put(>->mmio.fw, XE_FORCEWAKE_ALL); - XE_WARN_ON(err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); return; err_force_wake: - xe_gt_err(gt, "Failed to apply, err=%d\n", err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); + xe_gt_err(gt, "Failed to apply, err=-ETIMEDOUT\n"); } void xe_reg_sr_apply_whitelist(struct xe_hw_engine *hwe) @@ -220,15 +202,15 @@ void xe_reg_sr_apply_whitelist(struct xe_hw_engine *hwe) u32 mmio_base = hwe->mmio_base; unsigned long reg; unsigned int slot = 0; - int err; + unsigned int fw_ref; if (xa_empty(&sr->xa)) return; drm_dbg(&xe->drm, "Whitelisting %s registers\n", sr->name); - err = xe_force_wake_get(>->mmio.fw, XE_FORCEWAKE_ALL); - if (err) + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) goto err_force_wake; p = drm_dbg_printer(&xe->drm, DRM_UT_DRIVER, NULL); @@ -241,7 +223,7 @@ void xe_reg_sr_apply_whitelist(struct xe_hw_engine *hwe) } xe_reg_whitelist_print_entry(&p, 0, reg, entry); - xe_mmio_write32(gt, RING_FORCE_TO_NONPRIV(mmio_base, slot), + xe_mmio_write32(>->mmio, RING_FORCE_TO_NONPRIV(mmio_base, slot), reg | entry->set_bits); slot++; } @@ -250,16 +232,16 @@ void xe_reg_sr_apply_whitelist(struct xe_hw_engine *hwe) for (; slot < RING_MAX_NONPRIV_SLOTS; slot++) { u32 addr = RING_NOPID(mmio_base).addr; - xe_mmio_write32(gt, RING_FORCE_TO_NONPRIV(mmio_base, slot), addr); + xe_mmio_write32(>->mmio, RING_FORCE_TO_NONPRIV(mmio_base, slot), addr); } - err = xe_force_wake_put(>->mmio.fw, XE_FORCEWAKE_ALL); - XE_WARN_ON(err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); return; err_force_wake: - drm_err(&xe->drm, "Failed to apply, err=%d\n", err); + xe_force_wake_put(gt_to_fw(gt), fw_ref); + drm_err(&xe->drm, "Failed to apply, err=-ETIMEDOUT\n"); } /** diff --git a/drivers/gpu/drm/xe/xe_reg_sr_types.h b/drivers/gpu/drm/xe/xe_reg_sr_types.h index ad48a52b824a18..ebe11f237fa26d 100644 --- a/drivers/gpu/drm/xe/xe_reg_sr_types.h +++ b/drivers/gpu/drm/xe/xe_reg_sr_types.h @@ -20,12 +20,6 @@ struct xe_reg_sr_entry { }; struct xe_reg_sr { - struct { - struct xe_reg_sr_entry *arr; - unsigned int used; - unsigned int allocated; - unsigned int grow_step; - } pool; struct xarray xa; const char *name; diff --git a/drivers/gpu/drm/xe/xe_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c index 86c705d18c0d35..b13d4d62f0b1e1 100644 --- a/drivers/gpu/drm/xe/xe_rtp.c +++ b/drivers/gpu/drm/xe/xe_rtp.c @@ -196,7 +196,7 @@ static void rtp_get_context(struct xe_rtp_process_ctx *ctx, *gt = (*hwe)->gt; *xe = gt_to_xe(*gt); break; - }; + } } /** diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c index fe2cb2a96f7885..e055bed7ae5555 100644 --- a/drivers/gpu/drm/xe/xe_sa.c +++ b/drivers/gpu/drm/xe/xe_sa.c @@ -53,7 +53,7 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 if (IS_ERR(bo)) { drm_err(&xe->drm, "failed to allocate bo for sa manager: %ld\n", PTR_ERR(bo)); - return (struct xe_sa_manager *)bo; + return ERR_CAST(bo); } sa_manager->bo = bo; sa_manager->is_iomem = bo->vmap.is_iomem; diff --git a/drivers/gpu/drm/xe/xe_sched_job.c b/drivers/gpu/drm/xe/xe_sched_job.c index eeccc1c318aef1..1905ca5909658b 100644 --- a/drivers/gpu/drm/xe/xe_sched_job.c +++ b/drivers/gpu/drm/xe/xe_sched_job.c @@ -280,7 +280,7 @@ void xe_sched_job_arm(struct xe_sched_job *job) fence = &chain->base; } - job->fence = fence; + job->fence = dma_fence_get(fence); /* Pairs with put in scheduler */ drm_sched_job_arm(&job->drm); } diff --git a/drivers/gpu/drm/xe/xe_sched_job_types.h b/drivers/gpu/drm/xe/xe_sched_job_types.h index 0d3f76fb05cea2..f13f333f00bebd 100644 --- a/drivers/gpu/drm/xe/xe_sched_job_types.h +++ b/drivers/gpu/drm/xe/xe_sched_job_types.h @@ -40,7 +40,6 @@ struct xe_sched_job { * @fence: dma fence to indicate completion. 1 way relationship - job * can safely reference fence, fence cannot safely reference job. */ -#define JOB_FLAG_SUBMIT DMA_FENCE_FLAG_USER_BITS struct dma_fence *fence; /** @user_fence: write back value when BB is complete */ struct { @@ -63,7 +62,7 @@ struct xe_sched_job { struct xe_sched_job_snapshot { u16 batch_addr_len; - u64 batch_addr[]; + u64 batch_addr[] __counted_by(batch_addr_len); }; #endif diff --git a/drivers/gpu/drm/xe/xe_sriov.c b/drivers/gpu/drm/xe/xe_sriov.c index 5a1d65e4f19f2b..ef10782af65603 100644 --- a/drivers/gpu/drm/xe/xe_sriov.c +++ b/drivers/gpu/drm/xe/xe_sriov.c @@ -3,6 +3,8 @@ * Copyright © 2023 Intel Corporation */ +#include + #include #include "regs/xe_regs.h" @@ -35,7 +37,7 @@ const char *xe_sriov_mode_to_string(enum xe_sriov_mode mode) static bool test_is_vf(struct xe_device *xe) { - u32 value = xe_mmio_read32(xe_root_mmio_gt(xe), VF_CAP_REG); + u32 value = xe_mmio_read32(xe_root_tile_mmio(xe), VF_CAP_REG); return value & VF_CAP; } @@ -119,6 +121,7 @@ int xe_sriov_init(struct xe_device *xe) return drmm_add_action_or_reset(&xe->drm, fini_sriov, xe); } +ALLOW_ERROR_INJECTION(xe_sriov_init, ERRNO); /* See xe_pci_probe() */ /** * xe_sriov_print_info - Print basic SR-IOV information. diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c index 2e72c06fd40d07..42f5bebd09e50c 100644 --- a/drivers/gpu/drm/xe/xe_sync.c +++ b/drivers/gpu/drm/xe/xe_sync.c @@ -83,10 +83,16 @@ static void user_fence_worker(struct work_struct *w) XE_WARN_ON("Copy to user failed"); kthread_unuse_mm(ufence->mm); mmput(ufence->mm); + } else { + drm_dbg(&ufence->xe->drm, "mmget_not_zero() failed, ufence wasn't signaled\n"); } - wake_up_all(&ufence->xe->ufence_wq); + /* + * Wake up waiters only after updating the ufence state, allowing the UMD + * to safely reuse the same ufence without encountering -EBUSY errors. + */ WRITE_ONCE(ufence->signalled, 1); + wake_up_all(&ufence->xe->ufence_wq); user_fence_put(ufence); } diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c index dda5268507d8e1..07cf7cfe4abd5a 100644 --- a/drivers/gpu/drm/xe/xe_tile.c +++ b/drivers/gpu/drm/xe/xe_tile.c @@ -3,6 +3,8 @@ * Copyright © 2023 Intel Corporation */ +#include + #include #include "xe_device.h" @@ -129,6 +131,7 @@ int xe_tile_init_early(struct xe_tile *tile, struct xe_device *xe, u8 id) return 0; } +ALLOW_ERROR_INJECTION(xe_tile_init_early, ERRNO); /* See xe_pci_probe() */ static int tile_ttm_mgr_init(struct xe_tile *tile) { diff --git a/drivers/gpu/drm/xe/xe_trace.h b/drivers/gpu/drm/xe/xe_trace.h index 8573d7a87d8400..91130ad8999cdd 100644 --- a/drivers/gpu/drm/xe/xe_trace.h +++ b/drivers/gpu/drm/xe/xe_trace.h @@ -21,6 +21,7 @@ #include "xe_vm.h" #define __dev_name_xe(xe) dev_name((xe)->drm.dev) +#define __dev_name_tile(tile) __dev_name_xe(tile_to_xe((tile))) #define __dev_name_gt(gt) __dev_name_xe(gt_to_xe((gt))) #define __dev_name_eq(q) __dev_name_gt((q)->gt) @@ -342,12 +343,12 @@ DEFINE_EVENT(xe_hw_fence, xe_hw_fence_try_signal, ); TRACE_EVENT(xe_reg_rw, - TP_PROTO(struct xe_gt *gt, bool write, u32 reg, u64 val, int len), + TP_PROTO(struct xe_mmio *mmio, bool write, u32 reg, u64 val, int len), - TP_ARGS(gt, write, reg, val, len), + TP_ARGS(mmio, write, reg, val, len), TP_STRUCT__entry( - __string(dev, __dev_name_gt(gt)) + __string(dev, __dev_name_tile(mmio->tile)) __field(u64, val) __field(u32, reg) __field(u16, write) diff --git a/drivers/gpu/drm/xe/xe_trace_bo.h b/drivers/gpu/drm/xe/xe_trace_bo.h index 9b1a1d4304ae18..30a3cfbaaa094d 100644 --- a/drivers/gpu/drm/xe/xe_trace_bo.h +++ b/drivers/gpu/drm/xe/xe_trace_bo.h @@ -189,7 +189,7 @@ DECLARE_EVENT_CLASS(xe_vm, ), TP_printk("dev=%s, vm=%p, asid=0x%05x", __get_str(dev), - __entry->vm, __entry->asid) + __entry->vm, __entry->asid) ); DEFINE_EVENT(xe_vm, xe_vm_kill, diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c index f7113cf6109d59..423856cc18d400 100644 --- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c @@ -60,7 +60,7 @@ bool xe_ttm_stolen_cpu_access_needs_ggtt(struct xe_device *xe) static s64 detect_bar2_dgfx(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr) { struct xe_tile *tile = xe_device_get_root_tile(xe); - struct xe_gt *mmio = xe_root_mmio_gt(xe); + struct xe_mmio *mmio = xe_root_tile_mmio(xe); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); u64 stolen_size; u64 tile_offset; @@ -94,7 +94,7 @@ static u32 get_wopcm_size(struct xe_device *xe) u32 wopcm_size; u64 val; - val = xe_mmio_read64_2x32(xe_root_mmio_gt(xe), STOLEN_RESERVED); + val = xe_mmio_read64_2x32(xe_root_tile_mmio(xe), STOLEN_RESERVED); val = REG_FIELD_GET64(WOPCM_SIZE_MASK, val); switch (val) { @@ -119,7 +119,7 @@ static u32 detect_bar2_integrated(struct xe_device *xe, struct xe_ttm_stolen_mgr u32 stolen_size, wopcm_size; u32 ggc, gms; - ggc = xe_mmio_read32(xe_root_mmio_gt(xe), GGC); + ggc = xe_mmio_read32(xe_root_tile_mmio(xe), GGC); /* * Check GGMS: it should be fixed 0x3 (8MB), which corresponds to the @@ -159,7 +159,7 @@ static u32 detect_bar2_integrated(struct xe_device *xe, struct xe_ttm_stolen_mgr stolen_size -= wopcm_size; if (media_gt && XE_WA(media_gt, 14019821291)) { - u64 gscpsmi_base = xe_mmio_read64_2x32(media_gt, GSCPSMI_BASE) + u64 gscpsmi_base = xe_mmio_read64_2x32(&media_gt->mmio, GSCPSMI_BASE) & ~GENMASK_ULL(5, 0); /* diff --git a/drivers/gpu/drm/xe/xe_tuning.c b/drivers/gpu/drm/xe/xe_tuning.c index 0d5e04158917be..d449de0fb6ecb9 100644 --- a/drivers/gpu/drm/xe/xe_tuning.c +++ b/drivers/gpu/drm/xe/xe_tuning.c @@ -33,7 +33,7 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f))) }, { XE_RTP_NAME("Tuning: L3 cache - media"), - XE_RTP_RULES(MEDIA_VERSION(2000)), + XE_RTP_RULES(MEDIA_VERSION_RANGE(2000, XE_RTP_END_VERSION_UNDEFINED)), XE_RTP_ACTIONS(FIELD_SET(XE2LPM_L3SQCREG5, L3_PWM_TIMER_INIT_VAL_MASK, REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f))) }, @@ -43,7 +43,7 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { SET(CCCHKNREG1, L3CMPCTRL)) }, { XE_RTP_NAME("Tuning: Compression Overfetch - media"), - XE_RTP_RULES(MEDIA_VERSION(2000)), + XE_RTP_RULES(MEDIA_VERSION_RANGE(2000, XE_RTP_END_VERSION_UNDEFINED)), XE_RTP_ACTIONS(CLR(XE2LPM_CCCHKNREG1, ENCOMPPERFFIX), SET(XE2LPM_CCCHKNREG1, L3CMPCTRL)) }, @@ -52,7 +52,7 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { XE_RTP_ACTIONS(SET(L3SQCREG3, COMPPWOVERFETCHEN)) }, { XE_RTP_NAME("Tuning: Enable compressible partial write overfetch in L3 - media"), - XE_RTP_RULES(MEDIA_VERSION(2000)), + XE_RTP_RULES(MEDIA_VERSION_RANGE(2000, XE_RTP_END_VERSION_UNDEFINED)), XE_RTP_ACTIONS(SET(XE2LPM_L3SQCREG3, COMPPWOVERFETCHEN)) }, { XE_RTP_NAME("Tuning: L2 Overfetch Compressible Only"), @@ -61,7 +61,7 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { COMPMEMRD256BOVRFETCHEN)) }, { XE_RTP_NAME("Tuning: L2 Overfetch Compressible Only - media"), - XE_RTP_RULES(MEDIA_VERSION(2000)), + XE_RTP_RULES(MEDIA_VERSION_RANGE(2000, XE_RTP_END_VERSION_UNDEFINED)), XE_RTP_ACTIONS(SET(XE2LPM_L3SQCREG2, COMPMEMRD256BOVRFETCHEN)) }, @@ -71,7 +71,7 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { REG_FIELD_PREP(UNIFIED_COMPRESSION_FORMAT, 0))) }, { XE_RTP_NAME("Tuning: Stateless compression control - media"), - XE_RTP_RULES(MEDIA_VERSION_RANGE(1301, 2000)), + XE_RTP_RULES(MEDIA_VERSION_RANGE(1301, XE_RTP_END_VERSION_UNDEFINED)), XE_RTP_ACTIONS(FIELD_SET(STATELESS_COMPRESSION_CTRL, UNIFIED_COMPRESSION_FORMAT, REG_FIELD_PREP(UNIFIED_COMPRESSION_FORMAT, 0))) }, diff --git a/drivers/gpu/drm/xe/xe_uc_fw.c b/drivers/gpu/drm/xe/xe_uc_fw.c index d431d0031185eb..fb0eda3d568290 100644 --- a/drivers/gpu/drm/xe/xe_uc_fw.c +++ b/drivers/gpu/drm/xe/xe_uc_fw.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -796,6 +797,7 @@ int xe_uc_fw_init(struct xe_uc_fw *uc_fw) return err; } +ALLOW_ERROR_INJECTION(xe_uc_fw_init, ERRNO); /* See xe_pci_probe() */ static u32 uc_fw_ggtt_offset(struct xe_uc_fw *uc_fw) { @@ -806,6 +808,7 @@ static int uc_fw_xfer(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) { struct xe_device *xe = uc_fw_to_xe(uc_fw); struct xe_gt *gt = uc_fw_to_gt(uc_fw); + struct xe_mmio *mmio = >->mmio; u64 src_offset; u32 dma_ctrl; int ret; @@ -814,34 +817,34 @@ static int uc_fw_xfer(struct xe_uc_fw *uc_fw, u32 offset, u32 dma_flags) /* Set the source address for the uCode */ src_offset = uc_fw_ggtt_offset(uc_fw) + uc_fw->css_offset; - xe_mmio_write32(gt, DMA_ADDR_0_LOW, lower_32_bits(src_offset)); - xe_mmio_write32(gt, DMA_ADDR_0_HIGH, + xe_mmio_write32(mmio, DMA_ADDR_0_LOW, lower_32_bits(src_offset)); + xe_mmio_write32(mmio, DMA_ADDR_0_HIGH, upper_32_bits(src_offset) | DMA_ADDRESS_SPACE_GGTT); /* Set the DMA destination */ - xe_mmio_write32(gt, DMA_ADDR_1_LOW, offset); - xe_mmio_write32(gt, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM); + xe_mmio_write32(mmio, DMA_ADDR_1_LOW, offset); + xe_mmio_write32(mmio, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM); /* * Set the transfer size. The header plus uCode will be copied to WOPCM * via DMA, excluding any other components */ - xe_mmio_write32(gt, DMA_COPY_SIZE, + xe_mmio_write32(mmio, DMA_COPY_SIZE, sizeof(struct uc_css_header) + uc_fw->ucode_size); /* Start the DMA */ - xe_mmio_write32(gt, DMA_CTRL, + xe_mmio_write32(mmio, DMA_CTRL, _MASKED_BIT_ENABLE(dma_flags | START_DMA)); /* Wait for DMA to finish */ - ret = xe_mmio_wait32(gt, DMA_CTRL, START_DMA, 0, 100000, &dma_ctrl, + ret = xe_mmio_wait32(mmio, DMA_CTRL, START_DMA, 0, 100000, &dma_ctrl, false); if (ret) drm_err(&xe->drm, "DMA for %s fw failed, DMA_CTRL=%u\n", xe_uc_fw_type_repr(uc_fw->type), dma_ctrl); /* Disable the bits once DMA is over */ - xe_mmio_write32(gt, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags)); + xe_mmio_write32(mmio, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags)); return ret; } diff --git a/drivers/gpu/drm/xe/xe_vram.c b/drivers/gpu/drm/xe/xe_vram.c index 80ba2fc78837ac..b1f81dca610dc3 100644 --- a/drivers/gpu/drm/xe/xe_vram.c +++ b/drivers/gpu/drm/xe/xe_vram.c @@ -169,7 +169,7 @@ static inline u64 get_flat_ccs_offset(struct xe_gt *gt, u64 tile_size) u64 offset_hi, offset_lo; u32 nodes, num_enabled; - reg = xe_mmio_read32(gt, MIRROR_FUSE3); + reg = xe_mmio_read32(>->mmio, MIRROR_FUSE3); nodes = REG_FIELD_GET(XE2_NODE_ENABLE_MASK, reg); num_enabled = hweight32(nodes); /* Number of enabled l3 nodes */ @@ -185,7 +185,8 @@ static inline u64 get_flat_ccs_offset(struct xe_gt *gt, u64 tile_size) offset = round_up(offset, SZ_128K); /* SW must round up to nearest 128K */ /* We don't expect any holes */ - xe_assert_msg(xe, offset == (xe_mmio_read64_2x32(gt, GSMBASE) - ccs_size), + xe_assert_msg(xe, offset == (xe_mmio_read64_2x32(>_to_tile(gt)->mmio, GSMBASE) - + ccs_size), "Hole between CCS and GSM.\n"); } else { reg = xe_gt_mcr_unicast_read_any(gt, XEHP_FLAT_CCS_BASE_ADDR); @@ -219,8 +220,8 @@ static int tile_vram_size(struct xe_tile *tile, u64 *vram_size, { struct xe_device *xe = tile_to_xe(tile); struct xe_gt *gt = tile->primary_gt; + unsigned int fw_ref; u64 offset; - int err; u32 reg; if (IS_SRIOV_VF(xe)) { @@ -239,9 +240,9 @@ static int tile_vram_size(struct xe_tile *tile, u64 *vram_size, return 0; } - err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - if (err) - return err; + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!fw_ref) + return -ETIMEDOUT; /* actual size */ if (unlikely(xe->info.platform == XE_DG1)) { @@ -257,13 +258,15 @@ static int tile_vram_size(struct xe_tile *tile, u64 *vram_size, if (xe->info.has_flat_ccs) { offset = get_flat_ccs_offset(gt, *tile_size); } else { - offset = xe_mmio_read64_2x32(gt, GSMBASE); + offset = xe_mmio_read64_2x32(&tile->mmio, GSMBASE); } /* remove the tile offset so we have just the available size */ *vram_size = offset - *tile_offset; - return xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); + xe_force_wake_put(gt_to_fw(gt), fw_ref); + + return 0; } static void vram_fini(void *arg) diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 353936a0f877de..02cf647f86d8ea 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -251,6 +252,34 @@ static const struct xe_rtp_entry_sr gt_was[] = { XE_RTP_ENTRY_FLAG(FOREACH_ENGINE), }, + /* Xe3_LPG */ + + { XE_RTP_NAME("14021871409"), + XE_RTP_RULES(GRAPHICS_VERSION(3000), GRAPHICS_STEP(A0, B0)), + XE_RTP_ACTIONS(SET(UNSLCGCTL9454, LSCFE_CLKGATE_DIS)) + }, + + /* Xe3_LPM */ + + { XE_RTP_NAME("16021867713"), + XE_RTP_RULES(MEDIA_VERSION(3000), + ENGINE_CLASS(VIDEO_DECODE)), + XE_RTP_ACTIONS(SET(VDBOX_CGCTL3F1C(0), MFXPIPE_CLKGATE_DIS)), + XE_RTP_ENTRY_FLAG(FOREACH_ENGINE), + }, + { XE_RTP_NAME("16021865536"), + XE_RTP_RULES(MEDIA_VERSION(3000), + ENGINE_CLASS(VIDEO_DECODE)), + XE_RTP_ACTIONS(SET(VDBOX_CGCTL3F10(0), IECPUNIT_CLKGATE_DIS)), + XE_RTP_ENTRY_FLAG(FOREACH_ENGINE), + }, + { XE_RTP_NAME("14021486841"), + XE_RTP_RULES(MEDIA_VERSION(3000), MEDIA_STEP(A0, B0), + ENGINE_CLASS(VIDEO_DECODE)), + XE_RTP_ACTIONS(SET(VDBOX_CGCTL3F10(0), RAMDFTUNIT_CLKGATE_DIS)), + XE_RTP_ENTRY_FLAG(FOREACH_ENGINE), + }, + {} }; @@ -567,6 +596,18 @@ static const struct xe_rtp_entry_sr engine_was[] = { XE_RTP_ACTION_FLAG(ENGINE_BASE))) }, + /* Xe3_LPG */ + + { XE_RTP_NAME("14021402888"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3001), FUNC(xe_rtp_match_first_render_or_compute)), + XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN7, CLEAR_OPTIMIZATION_DISABLE)) + }, + { XE_RTP_NAME("18034896535"), + XE_RTP_RULES(GRAPHICS_VERSION(3000), GRAPHICS_STEP(A0, B0), + FUNC(xe_rtp_match_first_render_or_compute)), + XE_RTP_ACTIONS(SET(ROW_CHICKEN4, DISABLE_TDL_PUSH)) + }, + {} }; @@ -742,6 +783,18 @@ static const struct xe_rtp_entry_sr lrc_was[] = { XE_RTP_ACTIONS(SET(CHICKEN_RASTER_1, DIS_CLIP_NEGATIVE_BOUNDING_BOX)) }, + /* Xe3_LPG */ + { XE_RTP_NAME("14021490052"), + XE_RTP_RULES(GRAPHICS_VERSION(3000), GRAPHICS_STEP(A0, B0), + ENGINE_CLASS(RENDER)), + XE_RTP_ACTIONS(SET(FF_MODE, + DIS_MESH_PARTIAL_AUTOSTRIP | + DIS_MESH_AUTOSTRIP), + SET(VFLSKPD, + DIS_PARTIAL_AUTOSTRIP | + DIS_AUTOSTRIP)) + }, + {} }; @@ -854,6 +907,7 @@ int xe_wa_init(struct xe_gt *gt) return 0; } +ALLOW_ERROR_INJECTION(xe_wa_init, ERRNO); /* See xe_pci_probe() */ void xe_wa_dump(struct xe_gt *gt, struct drm_printer *p) { @@ -891,11 +945,11 @@ void xe_wa_dump(struct xe_gt *gt, struct drm_printer *p) */ void xe_wa_apply_tile_workarounds(struct xe_tile *tile) { - struct xe_gt *mmio = tile->primary_gt; + struct xe_mmio *mmio = &tile->mmio; if (IS_SRIOV_VF(tile->xe)) return; - if (XE_WA(mmio, 22010954014)) + if (XE_WA(tile->primary_gt, 22010954014)) xe_mmio_rmw32(mmio, XEHP_CLOCK_GATE_DIS, 0, SGSI_SIDECLK_DIS); } diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules index 920ca506014661..bcd04464b85e88 100644 --- a/drivers/gpu/drm/xe/xe_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_wa_oob.rules @@ -33,7 +33,11 @@ GRAPHICS_VERSION(2004) 22019338487 MEDIA_VERSION(2000) GRAPHICS_VERSION(2001) + MEDIA_VERSION(3000), MEDIA_STEP(A0, B0) 22019338487_display PLATFORM(LUNARLAKE) 16023588340 GRAPHICS_VERSION(2001) 14019789679 GRAPHICS_VERSION(1255) GRAPHICS_VERSION_RANGE(1270, 2004) +no_media_l3 MEDIA_VERSION(3000) +14022866841 GRAPHICS_VERSION(3000), GRAPHICS_STEP(A0, B0) + MEDIA_VERSION(3000), MEDIA_STEP(A0, B0) diff --git a/drivers/gpu/drm/xe/xe_wopcm.c b/drivers/gpu/drm/xe/xe_wopcm.c index d3a99157e52338..ada0d0aa6b7494 100644 --- a/drivers/gpu/drm/xe/xe_wopcm.c +++ b/drivers/gpu/drm/xe/xe_wopcm.c @@ -5,6 +5,8 @@ #include "xe_wopcm.h" +#include + #include "regs/xe_guc_regs.h" #include "xe_device.h" #include "xe_force_wake.h" @@ -123,8 +125,8 @@ static bool __check_layout(struct xe_device *xe, u32 wopcm_size, static bool __wopcm_regs_locked(struct xe_gt *gt, u32 *guc_wopcm_base, u32 *guc_wopcm_size) { - u32 reg_base = xe_mmio_read32(gt, DMA_GUC_WOPCM_OFFSET); - u32 reg_size = xe_mmio_read32(gt, GUC_WOPCM_SIZE); + u32 reg_base = xe_mmio_read32(>->mmio, DMA_GUC_WOPCM_OFFSET); + u32 reg_size = xe_mmio_read32(>->mmio, GUC_WOPCM_SIZE); if (!(reg_size & GUC_WOPCM_SIZE_LOCKED) || !(reg_base & GUC_WOPCM_OFFSET_VALID)) @@ -150,13 +152,13 @@ static int __wopcm_init_regs(struct xe_device *xe, struct xe_gt *gt, XE_WARN_ON(size & ~GUC_WOPCM_SIZE_MASK); mask = GUC_WOPCM_SIZE_MASK | GUC_WOPCM_SIZE_LOCKED; - err = xe_mmio_write32_and_verify(gt, GUC_WOPCM_SIZE, size, mask, + err = xe_mmio_write32_and_verify(>->mmio, GUC_WOPCM_SIZE, size, mask, size | GUC_WOPCM_SIZE_LOCKED); if (err) goto err_out; mask = GUC_WOPCM_OFFSET_MASK | GUC_WOPCM_OFFSET_VALID | huc_agent; - err = xe_mmio_write32_and_verify(gt, DMA_GUC_WOPCM_OFFSET, + err = xe_mmio_write32_and_verify(>->mmio, DMA_GUC_WOPCM_OFFSET, base | huc_agent, mask, base | huc_agent | GUC_WOPCM_OFFSET_VALID); @@ -169,10 +171,10 @@ static int __wopcm_init_regs(struct xe_device *xe, struct xe_gt *gt, drm_notice(&xe->drm, "Failed to init uC WOPCM registers!\n"); drm_notice(&xe->drm, "%s(%#x)=%#x\n", "DMA_GUC_WOPCM_OFFSET", DMA_GUC_WOPCM_OFFSET.addr, - xe_mmio_read32(gt, DMA_GUC_WOPCM_OFFSET)); + xe_mmio_read32(>->mmio, DMA_GUC_WOPCM_OFFSET)); drm_notice(&xe->drm, "%s(%#x)=%#x\n", "GUC_WOPCM_SIZE", GUC_WOPCM_SIZE.addr, - xe_mmio_read32(gt, GUC_WOPCM_SIZE)); + xe_mmio_read32(>->mmio, GUC_WOPCM_SIZE)); return err; } @@ -268,3 +270,4 @@ int xe_wopcm_init(struct xe_wopcm *wopcm) return ret; } +ALLOW_ERROR_INJECTION(xe_wopcm_init, ERRNO); /* See xe_pci_probe() */ diff --git a/drivers/gpu/drm/xlnx/Kconfig b/drivers/gpu/drm/xlnx/Kconfig index 626e5ac4c33d9e..4197f44e202f0d 100644 --- a/drivers/gpu/drm/xlnx/Kconfig +++ b/drivers/gpu/drm/xlnx/Kconfig @@ -6,6 +6,7 @@ config DRM_ZYNQMP_DPSUB depends on PHY_XILINX_ZYNQMP depends on XILINX_ZYNQMP_DPDMA select DMA_ENGINE + select DRM_CLIENT_SELECTION select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HELPER select DRM_BRIDGE_CONNECTOR diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c b/drivers/gpu/drm/xlnx/zynqmp_disp.c index 9368acf56eaf79..e4e0e299e8a7d5 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_disp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c @@ -1200,6 +1200,9 @@ static void zynqmp_disp_layer_release_dma(struct zynqmp_disp *disp, { unsigned int i; + if (!layer->info) + return; + for (i = 0; i < layer->info->num_channels; i++) { struct zynqmp_disp_layer_dma *dma = &layer->dmas[i]; diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 129beac4c07306..25c5dc61ee88b2 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -18,7 +18,9 @@ #include #include +#include #include +#include #include #include #include @@ -51,6 +53,7 @@ MODULE_PARM_DESC(power_on_delay_ms, "DP power on delay in msec (default: 4)"); #define ZYNQMP_DP_LANE_COUNT_SET 0x4 #define ZYNQMP_DP_ENHANCED_FRAME_EN 0x8 #define ZYNQMP_DP_TRAINING_PATTERN_SET 0xc +#define ZYNQMP_DP_LINK_QUAL_PATTERN_SET 0x10 #define ZYNQMP_DP_SCRAMBLING_DISABLE 0x14 #define ZYNQMP_DP_DOWNSPREAD_CTL 0x18 #define ZYNQMP_DP_SOFTWARE_RESET 0x1c @@ -64,6 +67,9 @@ MODULE_PARM_DESC(power_on_delay_ms, "DP power on delay in msec (default: 4)"); ZYNQMP_DP_SOFTWARE_RESET_STREAM3 | \ ZYNQMP_DP_SOFTWARE_RESET_STREAM4 | \ ZYNQMP_DP_SOFTWARE_RESET_AUX) +#define ZYNQMP_DP_COMP_PATTERN_80BIT_1 0x20 +#define ZYNQMP_DP_COMP_PATTERN_80BIT_2 0x24 +#define ZYNQMP_DP_COMP_PATTERN_80BIT_3 0x28 /* Core enable registers */ #define ZYNQMP_DP_TRANSMITTER_ENABLE 0x80 @@ -207,6 +213,7 @@ MODULE_PARM_DESC(power_on_delay_ms, "DP power on delay in msec (default: 4)"); #define ZYNQMP_DP_TX_PHY_POWER_DOWN_LANE_2 BIT(2) #define ZYNQMP_DP_TX_PHY_POWER_DOWN_LANE_3 BIT(3) #define ZYNQMP_DP_TX_PHY_POWER_DOWN_ALL 0xf +#define ZYNQMP_DP_TRANSMIT_PRBS7 0x230 #define ZYNQMP_DP_PHY_PRECURSOR_LANE_0 0x23c #define ZYNQMP_DP_PHY_PRECURSOR_LANE_1 0x240 #define ZYNQMP_DP_PHY_PRECURSOR_LANE_2 0x244 @@ -274,31 +281,109 @@ struct zynqmp_dp_config { u8 bpp; }; +/** + * enum test_pattern - Test patterns for test testing + * @TEST_VIDEO: Use regular video input + * @TEST_SYMBOL_ERROR: Symbol error measurement pattern + * @TEST_PRBS7: Output of the PRBS7 (x^7 + x^6 + 1) polynomial + * @TEST_80BIT_CUSTOM: A custom 80-bit pattern + * @TEST_CP2520: HBR2 compliance eye pattern + * @TEST_TPS1: Link training symbol pattern TPS1 (/D10.2/) + * @TEST_TPS2: Link training symbol pattern TPS2 + * @TEST_TPS3: Link training symbol pattern TPS3 (for HBR2) + */ +enum test_pattern { + TEST_VIDEO, + TEST_TPS1, + TEST_TPS2, + TEST_TPS3, + TEST_SYMBOL_ERROR, + TEST_PRBS7, + TEST_80BIT_CUSTOM, + TEST_CP2520, +}; + +static const char *const test_pattern_str[] = { + [TEST_VIDEO] = "video", + [TEST_TPS1] = "tps1", + [TEST_TPS2] = "tps2", + [TEST_TPS3] = "tps3", + [TEST_SYMBOL_ERROR] = "symbol-error", + [TEST_PRBS7] = "prbs7", + [TEST_80BIT_CUSTOM] = "80bit-custom", + [TEST_CP2520] = "cp2520", +}; + +/** + * struct zynqmp_dp_test - Configuration for test mode + * @pattern: The test pattern + * @enhanced: Use enhanced framing + * @downspread: Use SSC + * @active: Whether test mode is active + * @custom: Custom pattern for %TEST_80BIT_CUSTOM + * @train_set: Voltage/preemphasis settings + * @bw_code: Bandwidth code for the link + * @link_cnt: Number of lanes + */ +struct zynqmp_dp_test { + enum test_pattern pattern; + bool enhanced, downspread, active; + u8 custom[10]; + u8 train_set[ZYNQMP_DP_MAX_LANES]; + u8 bw_code; + u8 link_cnt; +}; + +/** + * struct zynqmp_dp_train_set_priv - Private data for train_set debugfs files + * @dp: DisplayPort IP core structure + * @lane: The lane for this file + */ +struct zynqmp_dp_train_set_priv { + struct zynqmp_dp *dp; + int lane; +}; + /** * struct zynqmp_dp - Xilinx DisplayPort core * @dev: device structure * @dpsub: Display subsystem * @iomem: device I/O memory for register access * @reset: reset controller + * @lock: Mutex protecting this struct and register access (but not AUX) * @irq: irq * @bridge: DRM bridge for the DP encoder * @next_bridge: The downstream bridge + * @test: Configuration for test mode * @config: IP core configuration from DTS * @aux: aux channel + * @aux_done: Completed when we get an AUX reply or timeout + * @ignore_aux_errors: If set, AUX errors are suppressed * @phy: PHY handles for DP lanes * @num_lanes: number of enabled phy lanes * @hpd_work: hot plug detection worker + * @hpd_irq_work: hot plug detection IRQ worker + * @ignore_hpd: If set, HPD events and IRQs are ignored * @status: connection status * @enabled: flag to indicate if the device is enabled * @dpcd: DP configuration data from currently connected sink device * @link_config: common link configuration between IP core and sink device * @mode: current mode between IP core and sink device * @train_set: set of training data + * @debugfs_train_set: Debugfs private data for @train_set + * + * @lock covers the link configuration in this struct and the device's + * registers. It does not cover @aux or @ignore_aux_errors. It is not strictly + * required for any of the members which are only modified at probe/remove time + * (e.g. @dev). */ struct zynqmp_dp { struct drm_dp_aux aux; struct drm_bridge bridge; struct work_struct hpd_work; + struct work_struct hpd_irq_work; + struct completion aux_done; + struct mutex lock; struct drm_bridge *next_bridge; struct device *dev; @@ -310,9 +395,13 @@ struct zynqmp_dp { enum drm_connector_status status; int irq; bool enabled; + bool ignore_aux_errors; + bool ignore_hpd; + struct zynqmp_dp_train_set_priv debugfs_train_set[ZYNQMP_DP_MAX_LANES]; struct zynqmp_dp_mode mode; struct zynqmp_dp_link_config link_config; + struct zynqmp_dp_test test; struct zynqmp_dp_config config; u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 train_set[ZYNQMP_DP_MAX_LANES]; @@ -626,6 +715,7 @@ static void zynqmp_dp_adjust_train(struct zynqmp_dp *dp, /** * zynqmp_dp_update_vs_emph - Update the training values * @dp: DisplayPort IP core structure + * @train_set: A set of training values * * Update the training values based on the request from sink. The mapped values * are predefined, and values(vs, pe, pc) are from the device manual. @@ -633,12 +723,12 @@ static void zynqmp_dp_adjust_train(struct zynqmp_dp *dp, * Return: 0 if vs and emph are updated successfully, or the error code returned * by drm_dp_dpcd_write(). */ -static int zynqmp_dp_update_vs_emph(struct zynqmp_dp *dp) +static int zynqmp_dp_update_vs_emph(struct zynqmp_dp *dp, u8 *train_set) { unsigned int i; int ret; - ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dp->train_set, + ret = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, train_set, dp->mode.lane_cnt); if (ret < 0) return ret; @@ -646,7 +736,7 @@ static int zynqmp_dp_update_vs_emph(struct zynqmp_dp *dp) for (i = 0; i < dp->mode.lane_cnt; i++) { u32 reg = ZYNQMP_DP_SUB_TX_PHY_PRECURSOR_LANE_0 + i * 4; union phy_configure_opts opts = { 0 }; - u8 train = dp->train_set[i]; + u8 train = train_set[i]; opts.dp.voltage[0] = (train & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT; @@ -690,7 +780,7 @@ static int zynqmp_dp_link_train_cr(struct zynqmp_dp *dp) * So, This loop should exit before 512 iterations */ for (max_tries = 0; max_tries < 512; max_tries++) { - ret = zynqmp_dp_update_vs_emph(dp); + ret = zynqmp_dp_update_vs_emph(dp, dp->train_set); if (ret) return ret; @@ -755,7 +845,7 @@ static int zynqmp_dp_link_train_ce(struct zynqmp_dp *dp) return ret; for (tries = 0; tries < DP_MAX_TRAINING_TRIES; tries++) { - ret = zynqmp_dp_update_vs_emph(dp); + ret = zynqmp_dp_update_vs_emph(dp, dp->train_set); if (ret) return ret; @@ -778,28 +868,29 @@ static int zynqmp_dp_link_train_ce(struct zynqmp_dp *dp) } /** - * zynqmp_dp_train - Train the link + * zynqmp_dp_setup() - Set up major link parameters * @dp: DisplayPort IP core structure + * @bw_code: The link bandwidth as a multiple of 270 MHz + * @lane_cnt: The number of lanes to use + * @enhanced: Use enhanced framing + * @downspread: Enable spread-spectrum clocking * - * Return: 0 if all trains are done successfully, or corresponding error code. + * Return: 0 on success, or -errno on failure */ -static int zynqmp_dp_train(struct zynqmp_dp *dp) +static int zynqmp_dp_setup(struct zynqmp_dp *dp, u8 bw_code, u8 lane_cnt, + bool enhanced, bool downspread) { u32 reg; - u8 bw_code = dp->mode.bw_code; - u8 lane_cnt = dp->mode.lane_cnt; u8 aux_lane_cnt = lane_cnt; - bool enhanced; int ret; zynqmp_dp_write(dp, ZYNQMP_DP_LANE_COUNT_SET, lane_cnt); - enhanced = drm_dp_enhanced_frame_cap(dp->dpcd); if (enhanced) { zynqmp_dp_write(dp, ZYNQMP_DP_ENHANCED_FRAME_EN, 1); aux_lane_cnt |= DP_LANE_COUNT_ENHANCED_FRAME_EN; } - if (dp->dpcd[3] & 0x1) { + if (downspread) { zynqmp_dp_write(dp, ZYNQMP_DP_DOWNSPREAD_CTL, 1); drm_dp_dpcd_writeb(&dp->aux, DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); @@ -842,8 +933,24 @@ static int zynqmp_dp_train(struct zynqmp_dp *dp) } zynqmp_dp_write(dp, ZYNQMP_DP_PHY_CLOCK_SELECT, reg); - ret = zynqmp_dp_phy_ready(dp); - if (ret < 0) + return zynqmp_dp_phy_ready(dp); +} + +/** + * zynqmp_dp_train - Train the link + * @dp: DisplayPort IP core structure + * + * Return: 0 if all trains are done successfully, or corresponding error code. + */ +static int zynqmp_dp_train(struct zynqmp_dp *dp) +{ + int ret; + + ret = zynqmp_dp_setup(dp, dp->mode.bw_code, dp->mode.lane_cnt, + drm_dp_enhanced_frame_cap(dp->dpcd), + dp->dpcd[DP_MAX_DOWNSPREAD] & + DP_MAX_DOWNSPREAD_0_5); + if (ret) return ret; zynqmp_dp_write(dp, ZYNQMP_DP_SCRAMBLING_DISABLE, 1); @@ -934,12 +1041,15 @@ static int zynqmp_dp_aux_cmd_submit(struct zynqmp_dp *dp, u32 cmd, u16 addr, u8 *buf, u8 bytes, u8 *reply) { bool is_read = (cmd & AUX_READ_BIT) ? true : false; + unsigned long time_left; u32 reg, i; reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE); if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REQUEST) return -EBUSY; + reinit_completion(&dp->aux_done); + zynqmp_dp_write(dp, ZYNQMP_DP_AUX_ADDRESS, addr); if (!is_read) for (i = 0; i < bytes; i++) @@ -954,17 +1064,14 @@ static int zynqmp_dp_aux_cmd_submit(struct zynqmp_dp *dp, u32 cmd, u16 addr, zynqmp_dp_write(dp, ZYNQMP_DP_AUX_COMMAND, reg); /* Wait for reply to be delivered upto 2ms */ - for (i = 0; ; i++) { - reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE); - if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY) - break; - - if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT || - i == 2) - return -ETIMEDOUT; + time_left = wait_for_completion_timeout(&dp->aux_done, + msecs_to_jiffies(2)); + if (!time_left) + return -ETIMEDOUT; - usleep_range(1000, 1100); - } + reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE); + if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT) + return -ETIMEDOUT; reg = zynqmp_dp_read(dp, ZYNQMP_DP_AUX_REPLY_CODE); if (reply) @@ -1006,6 +1113,8 @@ zynqmp_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) if (dp->status == connector_status_disconnected) { dev_dbg(dp->dev, "no connected aux device\n"); + if (dp->ignore_aux_errors) + goto fake_response; return -ENODEV; } @@ -1014,7 +1123,13 @@ zynqmp_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) dev_dbg(dp->dev, "failed to do aux transfer (%d)\n", ret); - return ret; + if (!dp->ignore_aux_errors) + return ret; + +fake_response: + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + memset(msg->buffer, 0, msg->size); + return msg->size; } /** @@ -1048,6 +1163,9 @@ static int zynqmp_dp_aux_init(struct zynqmp_dp *dp) (w << ZYNQMP_DP_AUX_CLK_DIVIDER_AUX_FILTER_SHIFT) | (rate / (1000 * 1000))); + zynqmp_dp_write(dp, ZYNQMP_DP_INT_EN, ZYNQMP_DP_INT_REPLY_RECEIVED | + ZYNQMP_DP_INT_REPLY_TIMEOUT); + dp->aux.name = "ZynqMP DP AUX"; dp->aux.dev = dp->dev; dp->aux.drm_dev = dp->bridge.dev; @@ -1065,6 +1183,9 @@ static int zynqmp_dp_aux_init(struct zynqmp_dp *dp) static void zynqmp_dp_aux_cleanup(struct zynqmp_dp *dp) { drm_dp_aux_unregister(&dp->aux); + + zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_REPLY_RECEIVED | + ZYNQMP_DP_INT_REPLY_TIMEOUT); } /* ----------------------------------------------------------------------------- @@ -1386,8 +1507,10 @@ zynqmp_dp_bridge_mode_valid(struct drm_bridge *bridge, } /* Check with link rate and lane count */ + mutex_lock(&dp->lock); rate = zynqmp_dp_max_rate(dp->link_config.max_rate, dp->link_config.max_lanes, dp->config.bpp); + mutex_unlock(&dp->lock); if (mode->clock > rate) { dev_dbg(dp->dev, "filtered mode %s for high pixel rate\n", mode->name); @@ -1414,6 +1537,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, pm_runtime_get_sync(dp->dev); + mutex_lock(&dp->lock); zynqmp_dp_disp_enable(dp, old_bridge_state); /* @@ -1474,6 +1598,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, zynqmp_dp_write(dp, ZYNQMP_DP_SOFTWARE_RESET, ZYNQMP_DP_SOFTWARE_RESET_ALL); zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 1); + mutex_unlock(&dp->lock); } static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, @@ -1481,6 +1606,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, { struct zynqmp_dp *dp = bridge_to_dp(bridge); + mutex_lock(&dp->lock); dp->enabled = false; cancel_work(&dp->hpd_work); zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0); @@ -1491,6 +1617,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0); zynqmp_dp_disp_disable(dp, old_bridge_state); + mutex_unlock(&dp->lock); pm_runtime_put_sync(dp->dev); } @@ -1526,13 +1653,14 @@ static int zynqmp_dp_bridge_atomic_check(struct drm_bridge *bridge, return 0; } -static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *bridge) +static enum drm_connector_status __zynqmp_dp_bridge_detect(struct zynqmp_dp *dp) { - struct zynqmp_dp *dp = bridge_to_dp(bridge); struct zynqmp_dp_link_config *link_config = &dp->link_config; u32 state, i; int ret; + lockdep_assert_held(&dp->lock); + /* * This is from heuristic. It takes some delay (ex, 100 ~ 500 msec) to * get the HPD signal with some monitors. @@ -1568,6 +1696,18 @@ static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *brid return connector_status_disconnected; } +static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *bridge) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + enum drm_connector_status ret; + + mutex_lock(&dp->lock); + ret = __zynqmp_dp_bridge_detect(dp); + mutex_unlock(&dp->lock); + + return ret; +} + static const struct drm_edid *zynqmp_dp_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector) { @@ -1605,6 +1745,582 @@ zynqmp_dp_bridge_get_input_bus_fmts(struct drm_bridge *bridge, return zynqmp_dp_bridge_default_bus_fmts(num_input_fmts); } +/* ----------------------------------------------------------------------------- + * debugfs + */ + +/** + * zynqmp_dp_set_test_pattern() - Configure the link for a test pattern + * @dp: DisplayPort IP core structure + * @pattern: The test pattern to configure + * @custom: The custom pattern to use if @pattern is %TEST_80BIT_CUSTOM + * + * Return: 0 on success, or negative errno on (DPCD) failure + */ +static int zynqmp_dp_set_test_pattern(struct zynqmp_dp *dp, + enum test_pattern pattern, + u8 *const custom) +{ + bool scramble = false; + u32 train_pattern = 0; + u32 link_pattern = 0; + u8 dpcd_train = 0; + u8 dpcd_link = 0; + int ret; + + switch (pattern) { + case TEST_TPS1: + train_pattern = 1; + break; + case TEST_TPS2: + train_pattern = 2; + break; + case TEST_TPS3: + train_pattern = 3; + break; + case TEST_SYMBOL_ERROR: + scramble = true; + link_pattern = DP_PHY_TEST_PATTERN_ERROR_COUNT; + break; + case TEST_PRBS7: + /* We use a dedicated register to enable PRBS7 */ + dpcd_link = DP_LINK_QUAL_PATTERN_ERROR_RATE; + break; + case TEST_80BIT_CUSTOM: { + const u8 *p = custom; + + link_pattern = DP_LINK_QUAL_PATTERN_80BIT_CUSTOM; + + zynqmp_dp_write(dp, ZYNQMP_DP_COMP_PATTERN_80BIT_1, + (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); + zynqmp_dp_write(dp, ZYNQMP_DP_COMP_PATTERN_80BIT_2, + (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4]); + zynqmp_dp_write(dp, ZYNQMP_DP_COMP_PATTERN_80BIT_3, + (p[9] << 8) | p[8]); + break; + } + case TEST_CP2520: + link_pattern = DP_LINK_QUAL_PATTERN_CP2520_PAT_1; + break; + default: + WARN_ON_ONCE(1); + fallthrough; + case TEST_VIDEO: + scramble = true; + } + + zynqmp_dp_write(dp, ZYNQMP_DP_SCRAMBLING_DISABLE, !scramble); + zynqmp_dp_write(dp, ZYNQMP_DP_TRAINING_PATTERN_SET, train_pattern); + zynqmp_dp_write(dp, ZYNQMP_DP_LINK_QUAL_PATTERN_SET, link_pattern); + zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMIT_PRBS7, pattern == TEST_PRBS7); + + dpcd_link = dpcd_link ?: link_pattern; + dpcd_train = train_pattern; + if (!scramble) + dpcd_train |= DP_LINK_SCRAMBLING_DISABLE; + + if (dp->dpcd[DP_DPCD_REV] < 0x12) { + if (pattern == TEST_CP2520) + dev_warn(dp->dev, + "can't set sink link quality pattern to CP2520 for DPCD < r1.2; error counters will be invalid\n"); + else + dpcd_train |= FIELD_PREP(DP_LINK_QUAL_PATTERN_11_MASK, + dpcd_link); + } else { + u8 dpcd_link_lane[ZYNQMP_DP_MAX_LANES]; + + memset(dpcd_link_lane, dpcd_link, ZYNQMP_DP_MAX_LANES); + ret = drm_dp_dpcd_write(&dp->aux, DP_LINK_QUAL_LANE0_SET, + dpcd_link_lane, ZYNQMP_DP_MAX_LANES); + if (ret < 0) + return ret; + } + + ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, dpcd_train); + return ret < 0 ? ret : 0; +} + +static int zynqmp_dp_test_setup(struct zynqmp_dp *dp) +{ + return zynqmp_dp_setup(dp, dp->test.bw_code, dp->test.link_cnt, + dp->test.enhanced, dp->test.downspread); +} + +static ssize_t zynqmp_dp_pattern_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dentry *dentry = file->f_path.dentry; + struct zynqmp_dp *dp = file->private_data; + char buf[16]; + ssize_t ret; + + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + + mutex_lock(&dp->lock); + ret = snprintf(buf, sizeof(buf), "%s\n", + test_pattern_str[dp->test.pattern]); + mutex_unlock(&dp->lock); + + debugfs_file_put(dentry); + return simple_read_from_buffer(user_buf, count, ppos, buf, ret); +} + +static ssize_t zynqmp_dp_pattern_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dentry *dentry = file->f_path.dentry; + struct zynqmp_dp *dp = file->private_data; + char buf[16]; + ssize_t ret; + int pattern; + + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + + ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, + count); + if (ret < 0) + goto out; + buf[ret] = '\0'; + + pattern = sysfs_match_string(test_pattern_str, buf); + if (pattern < 0) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&dp->lock); + dp->test.pattern = pattern; + if (dp->test.active) + ret = zynqmp_dp_set_test_pattern(dp, dp->test.pattern, + dp->test.custom) ?: ret; + mutex_unlock(&dp->lock); + +out: + debugfs_file_put(dentry); + return ret; +} + +static const struct file_operations fops_zynqmp_dp_pattern = { + .read = zynqmp_dp_pattern_read, + .write = zynqmp_dp_pattern_write, + .open = simple_open, + .llseek = noop_llseek, +}; + +static int zynqmp_dp_enhanced_get(void *data, u64 *val) +{ + struct zynqmp_dp *dp = data; + + mutex_lock(&dp->lock); + *val = dp->test.enhanced; + mutex_unlock(&dp->lock); + return 0; +} + +static int zynqmp_dp_enhanced_set(void *data, u64 val) +{ + struct zynqmp_dp *dp = data; + int ret = 0; + + mutex_lock(&dp->lock); + dp->test.enhanced = val; + if (dp->test.active) + ret = zynqmp_dp_test_setup(dp); + mutex_unlock(&dp->lock); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_enhanced, zynqmp_dp_enhanced_get, + zynqmp_dp_enhanced_set, "%llu\n"); + +static int zynqmp_dp_downspread_get(void *data, u64 *val) +{ + struct zynqmp_dp *dp = data; + + mutex_lock(&dp->lock); + *val = dp->test.downspread; + mutex_unlock(&dp->lock); + return 0; +} + +static int zynqmp_dp_downspread_set(void *data, u64 val) +{ + struct zynqmp_dp *dp = data; + int ret = 0; + + mutex_lock(&dp->lock); + dp->test.downspread = val; + if (dp->test.active) + ret = zynqmp_dp_test_setup(dp); + mutex_unlock(&dp->lock); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_downspread, zynqmp_dp_downspread_get, + zynqmp_dp_downspread_set, "%llu\n"); + +static int zynqmp_dp_active_get(void *data, u64 *val) +{ + struct zynqmp_dp *dp = data; + + mutex_lock(&dp->lock); + *val = dp->test.active; + mutex_unlock(&dp->lock); + return 0; +} + +static int zynqmp_dp_active_set(void *data, u64 val) +{ + struct zynqmp_dp *dp = data; + int ret = 0; + + mutex_lock(&dp->lock); + if (val) { + if (val < 2) { + ret = zynqmp_dp_test_setup(dp); + if (ret) + goto out; + } + + ret = zynqmp_dp_set_test_pattern(dp, dp->test.pattern, + dp->test.custom); + if (ret) + goto out; + + ret = zynqmp_dp_update_vs_emph(dp, dp->test.train_set); + if (ret) + goto out; + + dp->test.active = true; + } else { + int err; + + dp->test.active = false; + err = zynqmp_dp_set_test_pattern(dp, TEST_VIDEO, NULL); + if (err) + dev_warn(dp->dev, "could not clear test pattern: %d\n", + err); + zynqmp_dp_train_loop(dp); + } +out: + mutex_unlock(&dp->lock); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_active, zynqmp_dp_active_get, + zynqmp_dp_active_set, "%llu\n"); + +static ssize_t zynqmp_dp_custom_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dentry *dentry = file->f_path.dentry; + struct zynqmp_dp *dp = file->private_data; + ssize_t ret; + + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + + mutex_lock(&dp->lock); + ret = simple_read_from_buffer(user_buf, count, ppos, &dp->test.custom, + sizeof(dp->test.custom)); + mutex_unlock(&dp->lock); + + debugfs_file_put(dentry); + return ret; +} + +static ssize_t zynqmp_dp_custom_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dentry *dentry = file->f_path.dentry; + struct zynqmp_dp *dp = file->private_data; + ssize_t ret; + char buf[sizeof(dp->test.custom)]; + + ret = debugfs_file_get(dentry); + if (unlikely(ret)) + return ret; + + ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count); + if (ret < 0) + goto out; + + mutex_lock(&dp->lock); + memcpy(dp->test.custom, buf, ret); + if (dp->test.active) + ret = zynqmp_dp_set_test_pattern(dp, dp->test.pattern, + dp->test.custom) ?: ret; + mutex_unlock(&dp->lock); + +out: + debugfs_file_put(dentry); + return ret; +} + +static const struct file_operations fops_zynqmp_dp_custom = { + .read = zynqmp_dp_custom_read, + .write = zynqmp_dp_custom_write, + .open = simple_open, + .llseek = noop_llseek, +}; + +static int zynqmp_dp_swing_get(void *data, u64 *val) +{ + struct zynqmp_dp_train_set_priv *priv = data; + struct zynqmp_dp *dp = priv->dp; + + mutex_lock(&dp->lock); + *val = dp->test.train_set[priv->lane] & DP_TRAIN_VOLTAGE_SWING_MASK; + mutex_unlock(&dp->lock); + return 0; +} + +static int zynqmp_dp_swing_set(void *data, u64 val) +{ + struct zynqmp_dp_train_set_priv *priv = data; + struct zynqmp_dp *dp = priv->dp; + u8 *train_set = &dp->test.train_set[priv->lane]; + int ret = 0; + + if (val > 3) + return -EINVAL; + + mutex_lock(&dp->lock); + *train_set &= ~(DP_TRAIN_MAX_SWING_REACHED | + DP_TRAIN_VOLTAGE_SWING_MASK); + *train_set |= val; + if (val == 3) + *train_set |= DP_TRAIN_MAX_SWING_REACHED; + + if (dp->test.active) + ret = zynqmp_dp_update_vs_emph(dp, dp->test.train_set); + mutex_unlock(&dp->lock); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_swing, zynqmp_dp_swing_get, + zynqmp_dp_swing_set, "%llu\n"); + +static int zynqmp_dp_preemphasis_get(void *data, u64 *val) +{ + struct zynqmp_dp_train_set_priv *priv = data; + struct zynqmp_dp *dp = priv->dp; + + mutex_lock(&dp->lock); + *val = FIELD_GET(DP_TRAIN_PRE_EMPHASIS_MASK, + dp->test.train_set[priv->lane]); + mutex_unlock(&dp->lock); + return 0; +} + +static int zynqmp_dp_preemphasis_set(void *data, u64 val) +{ + struct zynqmp_dp_train_set_priv *priv = data; + struct zynqmp_dp *dp = priv->dp; + u8 *train_set = &dp->test.train_set[priv->lane]; + int ret = 0; + + if (val > 2) + return -EINVAL; + + mutex_lock(&dp->lock); + *train_set &= ~(DP_TRAIN_MAX_PRE_EMPHASIS_REACHED | + DP_TRAIN_PRE_EMPHASIS_MASK); + *train_set |= val; + if (val == 2) + *train_set |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + + if (dp->test.active) + ret = zynqmp_dp_update_vs_emph(dp, dp->test.train_set); + mutex_unlock(&dp->lock); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_preemphasis, zynqmp_dp_preemphasis_get, + zynqmp_dp_preemphasis_set, "%llu\n"); + +static int zynqmp_dp_lanes_get(void *data, u64 *val) +{ + struct zynqmp_dp *dp = data; + + mutex_lock(&dp->lock); + *val = dp->test.link_cnt; + mutex_unlock(&dp->lock); + return 0; +} + +static int zynqmp_dp_lanes_set(void *data, u64 val) +{ + struct zynqmp_dp *dp = data; + int ret = 0; + + if (val > ZYNQMP_DP_MAX_LANES) + return -EINVAL; + + mutex_lock(&dp->lock); + if (val > dp->num_lanes) { + ret = -EINVAL; + } else { + dp->test.link_cnt = val; + if (dp->test.active) + ret = zynqmp_dp_test_setup(dp); + } + mutex_unlock(&dp->lock); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_lanes, zynqmp_dp_lanes_get, + zynqmp_dp_lanes_set, "%llu\n"); + +static int zynqmp_dp_rate_get(void *data, u64 *val) +{ + struct zynqmp_dp *dp = data; + + mutex_lock(&dp->lock); + *val = drm_dp_bw_code_to_link_rate(dp->test.bw_code) * 10000; + mutex_unlock(&dp->lock); + return 0; +} + +static int zynqmp_dp_rate_set(void *data, u64 val) +{ + struct zynqmp_dp *dp = data; + int link_rate; + int ret = 0; + u8 bw_code; + + if (do_div(val, 10000)) + return -EINVAL; + + bw_code = drm_dp_link_rate_to_bw_code(val); + link_rate = drm_dp_bw_code_to_link_rate(bw_code); + if (val != link_rate) + return -EINVAL; + + if (bw_code != DP_LINK_BW_1_62 && bw_code != DP_LINK_BW_2_7 && + bw_code != DP_LINK_BW_5_4) + return -EINVAL; + + mutex_lock(&dp->lock); + dp->test.bw_code = bw_code; + if (dp->test.active) + ret = zynqmp_dp_test_setup(dp); + mutex_unlock(&dp->lock); + + return ret; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_rate, zynqmp_dp_rate_get, + zynqmp_dp_rate_set, "%llu\n"); + +static int zynqmp_dp_ignore_aux_errors_get(void *data, u64 *val) +{ + struct zynqmp_dp *dp = data; + + mutex_lock(&dp->aux.hw_mutex); + *val = dp->ignore_aux_errors; + mutex_unlock(&dp->aux.hw_mutex); + return 0; +} + +static int zynqmp_dp_ignore_aux_errors_set(void *data, u64 val) +{ + struct zynqmp_dp *dp = data; + + if (val != !!val) + return -EINVAL; + + mutex_lock(&dp->aux.hw_mutex); + dp->ignore_aux_errors = val; + mutex_unlock(&dp->aux.hw_mutex); + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_ignore_aux_errors, + zynqmp_dp_ignore_aux_errors_get, + zynqmp_dp_ignore_aux_errors_set, "%llu\n"); + +static int zynqmp_dp_ignore_hpd_get(void *data, u64 *val) +{ + struct zynqmp_dp *dp = data; + + mutex_lock(&dp->lock); + *val = dp->ignore_hpd; + mutex_unlock(&dp->lock); + return 0; +} + +static int zynqmp_dp_ignore_hpd_set(void *data, u64 val) +{ + struct zynqmp_dp *dp = data; + + if (val != !!val) + return -EINVAL; + + mutex_lock(&dp->lock); + dp->ignore_hpd = val; + mutex_lock(&dp->lock); + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_zynqmp_dp_ignore_hpd, zynqmp_dp_ignore_hpd_get, + zynqmp_dp_ignore_hpd_set, "%llu\n"); + +static void zynqmp_dp_bridge_debugfs_init(struct drm_bridge *bridge, + struct dentry *root) +{ + struct zynqmp_dp *dp = bridge_to_dp(bridge); + struct dentry *test; + int i; + + dp->test.bw_code = DP_LINK_BW_5_4; + dp->test.link_cnt = dp->num_lanes; + + test = debugfs_create_dir("test", root); +#define CREATE_FILE(name) \ + debugfs_create_file(#name, 0600, test, dp, &fops_zynqmp_dp_##name) + CREATE_FILE(pattern); + CREATE_FILE(enhanced); + CREATE_FILE(downspread); + CREATE_FILE(active); + CREATE_FILE(custom); + CREATE_FILE(rate); + CREATE_FILE(lanes); + CREATE_FILE(ignore_aux_errors); + CREATE_FILE(ignore_hpd); + + for (i = 0; i < dp->num_lanes; i++) { + static const char fmt[] = "lane%d_preemphasis"; + char name[sizeof(fmt)]; + + dp->debugfs_train_set[i].dp = dp; + dp->debugfs_train_set[i].lane = i; + + snprintf(name, sizeof(name), fmt, i); + debugfs_create_file(name, 0600, test, + &dp->debugfs_train_set[i], + &fops_zynqmp_dp_preemphasis); + + snprintf(name, sizeof(name), "lane%d_swing", i); + debugfs_create_file(name, 0600, test, + &dp->debugfs_train_set[i], + &fops_zynqmp_dp_swing); + } +} + static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = { .attach = zynqmp_dp_bridge_attach, .detach = zynqmp_dp_bridge_detach, @@ -1618,6 +2334,7 @@ static const struct drm_bridge_funcs zynqmp_dp_bridge_funcs = { .detect = zynqmp_dp_bridge_detect, .edid_read = zynqmp_dp_bridge_edid_read, .atomic_get_input_bus_fmts = zynqmp_dp_bridge_get_input_bus_fmts, + .debugfs_init = zynqmp_dp_bridge_debugfs_init, }; /* ----------------------------------------------------------------------------- @@ -1651,10 +2368,46 @@ static void zynqmp_dp_hpd_work_func(struct work_struct *work) struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, hpd_work); enum drm_connector_status status; - status = zynqmp_dp_bridge_detect(&dp->bridge); + mutex_lock(&dp->lock); + if (dp->ignore_hpd) { + mutex_unlock(&dp->lock); + return; + } + + status = __zynqmp_dp_bridge_detect(dp); + mutex_unlock(&dp->lock); + drm_bridge_hpd_notify(&dp->bridge, status); } +static void zynqmp_dp_hpd_irq_work_func(struct work_struct *work) +{ + struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, + hpd_irq_work); + u8 status[DP_LINK_STATUS_SIZE + 2]; + int err; + + mutex_lock(&dp->lock); + if (dp->ignore_hpd) { + mutex_unlock(&dp->lock); + return; + } + + err = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, status, + DP_LINK_STATUS_SIZE + 2); + if (err < 0) { + dev_dbg_ratelimited(dp->dev, + "could not read sink status: %d\n", err); + } else { + if (status[4] & DP_LINK_STATUS_UPDATED || + !drm_dp_clock_recovery_ok(&status[2], dp->mode.lane_cnt) || + !drm_dp_channel_eq_ok(&status[2], dp->mode.lane_cnt)) { + zynqmp_dp_train_loop(dp); + } + } + mutex_unlock(&dp->lock); +} + static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) { struct zynqmp_dp *dp = (struct zynqmp_dp *)data; @@ -1686,23 +2439,15 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) if (status & ZYNQMP_DP_INT_HPD_EVENT) schedule_work(&dp->hpd_work); - if (status & ZYNQMP_DP_INT_HPD_IRQ) { - int ret; - u8 status[DP_LINK_STATUS_SIZE + 2]; + if (status & ZYNQMP_DP_INT_HPD_IRQ) + schedule_work(&dp->hpd_irq_work); - ret = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, status, - DP_LINK_STATUS_SIZE + 2); - if (ret < 0) - goto handled; + if (status & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY) + complete(&dp->aux_done); - if (status[4] & DP_LINK_STATUS_UPDATED || - !drm_dp_clock_recovery_ok(&status[2], dp->mode.lane_cnt) || - !drm_dp_channel_eq_ok(&status[2], dp->mode.lane_cnt)) { - zynqmp_dp_train_loop(dp); - } - } + if (status & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT) + complete(&dp->aux_done); -handled: return IRQ_HANDLED; } @@ -1725,8 +2470,11 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) dp->dev = &pdev->dev; dp->dpsub = dpsub; dp->status = connector_status_disconnected; + mutex_init(&dp->lock); + init_completion(&dp->aux_done); INIT_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func); + INIT_WORK(&dp->hpd_irq_work, zynqmp_dp_hpd_irq_work_func); /* Acquire all resources (IOMEM, IRQ and PHYs). */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp"); @@ -1802,9 +2550,8 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) * Now that the hardware is initialized and won't generate spurious * interrupts, request the IRQ. */ - ret = devm_request_threaded_irq(dp->dev, dp->irq, NULL, - zynqmp_dp_irq_handler, IRQF_ONESHOT, - dev_name(dp->dev), dp); + ret = devm_request_irq(dp->dev, dp->irq, zynqmp_dp_irq_handler, + IRQF_SHARED, dev_name(dp->dev), dp); if (ret < 0) goto err_phy_exit; @@ -1829,8 +2576,9 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub) struct zynqmp_dp *dp = dpsub->dp; zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_ALL); - disable_irq(dp->irq); + devm_free_irq(dp->dev, dp->irq, dp); + cancel_work_sync(&dp->hpd_irq_work); cancel_work_sync(&dp->hpd_work); zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMITTER_ENABLE, 0); @@ -1838,4 +2586,5 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub) zynqmp_dp_phy_exit(dp); zynqmp_dp_reset(dp, true); + mutex_destroy(&dp->lock); } diff --git a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c index f5781939de9c35..07c4d184e7a1fb 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dpsub.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dpsub.c @@ -320,7 +320,7 @@ MODULE_DEVICE_TABLE(of, zynqmp_dpsub_of_match); static struct platform_driver zynqmp_dpsub_driver = { .probe = zynqmp_dpsub_probe, - .remove_new = zynqmp_dpsub_remove, + .remove = zynqmp_dpsub_remove, .shutdown = zynqmp_dpsub_shutdown, .driver = { .name = "zynqmp-dpsub", diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c b/drivers/gpu/drm/xlnx/zynqmp_kms.c index bd1368df787034..fc81983d9e5e8c 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_kms.c +++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -402,6 +403,7 @@ static const struct drm_driver zynqmp_dpsub_drm_driver = { DRIVER_ATOMIC, DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(zynqmp_dpsub_dumb_create), + DRM_FBDEV_DMA_DRIVER_OPS, .fops = &zynqmp_dpsub_drm_fops, @@ -509,12 +511,12 @@ int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) if (ret) return ret; - drm_kms_helper_poll_init(drm); - ret = zynqmp_dpsub_kms_init(dpsub); if (ret < 0) goto err_poll_fini; + drm_kms_helper_poll_init(drm); + /* Reset all components and register the DRM device. */ drm_mode_config_reset(drm); @@ -523,7 +525,7 @@ int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub) goto err_poll_fini; /* Initialize fbdev generic emulation. */ - drm_fbdev_dma_setup(drm, 24); + drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB888); return 0; @@ -536,7 +538,7 @@ void zynqmp_dpsub_drm_cleanup(struct zynqmp_dpsub *dpsub) { struct drm_device *drm = &dpsub->drm->dev; - drm_dev_unregister(drm); + drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); drm_encoder_cleanup(&dpsub->drm->encoder); drm_kms_helper_poll_fini(drm); diff --git a/drivers/gpu/host1x/context_bus.c b/drivers/gpu/host1x/context_bus.c index d9421179d7b432..7cd0e1a5edd1b5 100644 --- a/drivers/gpu/host1x/context_bus.c +++ b/drivers/gpu/host1x/context_bus.c @@ -6,7 +6,7 @@ #include #include -struct bus_type host1x_context_device_bus_type = { +const struct bus_type host1x_context_device_bus_type = { .name = "host1x-context", }; EXPORT_SYMBOL_GPL(host1x_context_device_bus_type); diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index e98528777faaec..7b1d091f3c090c 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -142,18 +142,29 @@ static const struct host1x_info host1x05_info = { }; static const struct host1x_sid_entry tegra186_sid_table[] = { - { - /* VIC */ - .base = 0x1af0, - .offset = 0x30, - .limit = 0x34 - }, - { - /* NVDEC */ - .base = 0x1b00, - .offset = 0x30, - .limit = 0x34 - }, + { /* SE1 */ .base = 0x1ac8, .offset = 0x90, .limit = 0x90 }, + { /* SE2 */ .base = 0x1ad0, .offset = 0x90, .limit = 0x90 }, + { /* SE3 */ .base = 0x1ad8, .offset = 0x90, .limit = 0x90 }, + { /* SE4 */ .base = 0x1ae0, .offset = 0x90, .limit = 0x90 }, + { /* ISP */ .base = 0x1ae8, .offset = 0x50, .limit = 0x50 }, + { /* VIC */ .base = 0x1af0, .offset = 0x30, .limit = 0x34 }, + { /* NVENC */ .base = 0x1af8, .offset = 0x30, .limit = 0x34 }, + { /* NVDEC */ .base = 0x1b00, .offset = 0x30, .limit = 0x34 }, + { /* NVJPG */ .base = 0x1b08, .offset = 0x30, .limit = 0x34 }, + { /* TSEC */ .base = 0x1b10, .offset = 0x30, .limit = 0x34 }, + { /* TSECB */ .base = 0x1b18, .offset = 0x30, .limit = 0x34 }, + { /* VI 0 */ .base = 0x1b80, .offset = 0x10000, .limit = 0x10000 }, + { /* VI 1 */ .base = 0x1b88, .offset = 0x20000, .limit = 0x20000 }, + { /* VI 2 */ .base = 0x1b90, .offset = 0x30000, .limit = 0x30000 }, + { /* VI 3 */ .base = 0x1b98, .offset = 0x40000, .limit = 0x40000 }, + { /* VI 4 */ .base = 0x1ba0, .offset = 0x50000, .limit = 0x50000 }, + { /* VI 5 */ .base = 0x1ba8, .offset = 0x60000, .limit = 0x60000 }, + { /* VI 6 */ .base = 0x1bb0, .offset = 0x70000, .limit = 0x70000 }, + { /* VI 7 */ .base = 0x1bb8, .offset = 0x80000, .limit = 0x80000 }, + { /* VI 8 */ .base = 0x1bc0, .offset = 0x90000, .limit = 0x90000 }, + { /* VI 9 */ .base = 0x1bc8, .offset = 0xa0000, .limit = 0xa0000 }, + { /* VI 10 */ .base = 0x1bd0, .offset = 0xb0000, .limit = 0xb0000 }, + { /* VI 11 */ .base = 0x1bd8, .offset = 0xc0000, .limit = 0xc0000 }, }; static const struct host1x_info host1x06_info = { @@ -173,24 +184,26 @@ static const struct host1x_info host1x06_info = { }; static const struct host1x_sid_entry tegra194_sid_table[] = { - { - /* VIC */ - .base = 0x1af0, - .offset = 0x30, - .limit = 0x34 - }, - { - /* NVDEC */ - .base = 0x1b00, - .offset = 0x30, - .limit = 0x34 - }, - { - /* NVDEC1 */ - .base = 0x1bc0, - .offset = 0x30, - .limit = 0x34 - }, + { /* SE1 */ .base = 0x1ac8, .offset = 0x90, .limit = 0x90 }, + { /* SE2 */ .base = 0x1ad0, .offset = 0x90, .limit = 0x90 }, + { /* SE3 */ .base = 0x1ad8, .offset = 0x90, .limit = 0x90 }, + { /* SE4 */ .base = 0x1ae0, .offset = 0x90, .limit = 0x90 }, + { /* ISP */ .base = 0x1ae8, .offset = 0x800, .limit = 0x800 }, + { /* VIC */ .base = 0x1af0, .offset = 0x30, .limit = 0x34 }, + { /* NVENC */ .base = 0x1af8, .offset = 0x30, .limit = 0x34 }, + { /* NVDEC */ .base = 0x1b00, .offset = 0x30, .limit = 0x34 }, + { /* NVJPG */ .base = 0x1b08, .offset = 0x30, .limit = 0x34 }, + { /* TSEC */ .base = 0x1b10, .offset = 0x30, .limit = 0x34 }, + { /* TSECB */ .base = 0x1b18, .offset = 0x30, .limit = 0x34 }, + { /* VI */ .base = 0x1b80, .offset = 0x800, .limit = 0x800 }, + { /* VI_THI */ .base = 0x1b88, .offset = 0x30, .limit = 0x34 }, + { /* ISP_THI */ .base = 0x1b90, .offset = 0x30, .limit = 0x34 }, + { /* PVA0_CLUSTER */ .base = 0x1b98, .offset = 0x0, .limit = 0x0 }, + { /* PVA0_CLUSTER */ .base = 0x1ba0, .offset = 0x0, .limit = 0x0 }, + { /* NVDLA0 */ .base = 0x1ba8, .offset = 0x30, .limit = 0x34 }, + { /* NVDLA1 */ .base = 0x1bb0, .offset = 0x30, .limit = 0x34 }, + { /* NVENC1 */ .base = 0x1bb8, .offset = 0x30, .limit = 0x34 }, + { /* NVDEC1 */ .base = 0x1bc0, .offset = 0x30, .limit = 0x34 }, }; static const struct host1x_info host1x07_info = { @@ -215,54 +228,35 @@ static const struct host1x_info host1x07_info = { * and firmware stream ID in the MMIO path table. */ static const struct host1x_sid_entry tegra234_sid_table[] = { - { - /* SE2 MMIO */ - .base = 0x1658, - .offset = 0x90, - .limit = 0x90 - }, - { - /* SE4 MMIO */ - .base = 0x1660, - .offset = 0x90, - .limit = 0x90 - }, - { - /* SE2 channel */ - .base = 0x1738, - .offset = 0x90, - .limit = 0x90 - }, - { - /* SE4 channel */ - .base = 0x1740, - .offset = 0x90, - .limit = 0x90 - }, - { - /* VIC channel */ - .base = 0x17b8, - .offset = 0x30, - .limit = 0x30 - }, - { - /* VIC MMIO */ - .base = 0x1688, - .offset = 0x34, - .limit = 0x34 - }, - { - /* NVDEC channel */ - .base = 0x17c8, - .offset = 0x30, - .limit = 0x30, - }, - { - /* NVDEC MMIO */ - .base = 0x1698, - .offset = 0x34, - .limit = 0x34, - }, + { /* SE1 MMIO */ .base = 0x1650, .offset = 0x90, .limit = 0x90 }, + { /* SE1 ch */ .base = 0x1730, .offset = 0x90, .limit = 0x90 }, + { /* SE2 MMIO */ .base = 0x1658, .offset = 0x90, .limit = 0x90 }, + { /* SE2 ch */ .base = 0x1738, .offset = 0x90, .limit = 0x90 }, + { /* SE4 MMIO */ .base = 0x1660, .offset = 0x90, .limit = 0x90 }, + { /* SE4 ch */ .base = 0x1740, .offset = 0x90, .limit = 0x90 }, + { /* ISP MMIO */ .base = 0x1680, .offset = 0x800, .limit = 0x800 }, + { /* VIC MMIO */ .base = 0x1688, .offset = 0x34, .limit = 0x34 }, + { /* VIC ch */ .base = 0x17b8, .offset = 0x30, .limit = 0x30 }, + { /* NVENC MMIO */ .base = 0x1690, .offset = 0x34, .limit = 0x34 }, + { /* NVENC ch */ .base = 0x17c0, .offset = 0x30, .limit = 0x30 }, + { /* NVDEC MMIO */ .base = 0x1698, .offset = 0x34, .limit = 0x34 }, + { /* NVDEC ch */ .base = 0x17c8, .offset = 0x30, .limit = 0x30 }, + { /* NVJPG MMIO */ .base = 0x16a0, .offset = 0x34, .limit = 0x34 }, + { /* NVJPG ch */ .base = 0x17d0, .offset = 0x30, .limit = 0x30 }, + { /* TSEC MMIO */ .base = 0x16a8, .offset = 0x30, .limit = 0x34 }, + { /* NVJPG1 MMIO */ .base = 0x16b0, .offset = 0x34, .limit = 0x34 }, + { /* NVJPG1 ch */ .base = 0x17a8, .offset = 0x30, .limit = 0x30 }, + { /* VI MMIO */ .base = 0x16b8, .offset = 0x800, .limit = 0x800 }, + { /* VI_THI MMIO */ .base = 0x16c0, .offset = 0x30, .limit = 0x34 }, + { /* ISP_THI MMIO */ .base = 0x16c8, .offset = 0x30, .limit = 0x34 }, + { /* NVDLA MMIO */ .base = 0x16d8, .offset = 0x30, .limit = 0x34 }, + { /* NVDLA ch */ .base = 0x17e0, .offset = 0x30, .limit = 0x34 }, + { /* NVDLA1 MMIO */ .base = 0x16e0, .offset = 0x30, .limit = 0x34 }, + { /* NVDLA1 ch */ .base = 0x17e8, .offset = 0x30, .limit = 0x34 }, + { /* OFA MMIO */ .base = 0x16e8, .offset = 0x34, .limit = 0x34 }, + { /* OFA ch */ .base = 0x1768, .offset = 0x30, .limit = 0x30 }, + { /* VI2 MMIO */ .base = 0x16f0, .offset = 0x800, .limit = 0x800 }, + { /* VI2_THI MMIO */ .base = 0x16f8, .offset = 0x30, .limit = 0x34 }, }; static const struct host1x_info host1x08_info = { @@ -775,7 +769,7 @@ static struct platform_driver tegra_host1x_driver = { .pm = &host1x_pm_ops, }, .probe = host1x_probe, - .remove_new = host1x_remove, + .remove = host1x_remove, }; static struct platform_driver * const drivers[] = { diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 92031b240a1796..d3855a1c6b472a 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -175,11 +175,11 @@ struct host1x { }; void host1x_common_writel(struct host1x *host1x, u32 v, u32 r); -void host1x_hypervisor_writel(struct host1x *host1x, u32 r, u32 v); +void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r); u32 host1x_hypervisor_readl(struct host1x *host1x, u32 r); -void host1x_sync_writel(struct host1x *host1x, u32 r, u32 v); +void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r); u32 host1x_sync_readl(struct host1x *host1x, u32 r); -void host1x_ch_writel(struct host1x_channel *ch, u32 r, u32 v); +void host1x_ch_writel(struct host1x_channel *ch, u32 v, u32 r); u32 host1x_ch_readl(struct host1x_channel *ch, u32 r); static inline void host1x_hw_syncpt_restore(struct host1x *host, diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c index 1b65a10b9dfcf5..3f3f0018eee0d5 100644 --- a/drivers/gpu/host1x/hw/cdma_hw.c +++ b/drivers/gpu/host1x/hw/cdma_hw.c @@ -254,12 +254,24 @@ static void timeout_release_mlock(struct host1x_cdma *cdma) u32 offset; switch (ch->client->class) { + case HOST1X_CLASS_NVJPG1: + offset = HOST1X_COMMON_NVJPG1_MLOCK; + break; + case HOST1X_CLASS_NVENC: + offset = HOST1X_COMMON_NVENC_MLOCK; + break; case HOST1X_CLASS_VIC: offset = HOST1X_COMMON_VIC_MLOCK; break; + case HOST1X_CLASS_NVJPG: + offset = HOST1X_COMMON_NVJPG_MLOCK; + break; case HOST1X_CLASS_NVDEC: offset = HOST1X_COMMON_NVDEC_MLOCK; break; + case HOST1X_CLASS_OFA: + offset = HOST1X_COMMON_OFA_MLOCK; + break; default: WARN(1, "%s was not updated for class %u", __func__, ch->client->class); return; diff --git a/drivers/gpu/host1x/hw/debug_hw.c b/drivers/gpu/host1x/hw/debug_hw.c index 54e31d81517b07..4c32aa1b95e877 100644 --- a/drivers/gpu/host1x/hw/debug_hw.c +++ b/drivers/gpu/host1x/hw/debug_hw.c @@ -177,7 +177,16 @@ static void show_gather(struct output *o, dma_addr_t phys_addr, for (i = 0; i < words; i++) { dma_addr_t addr = phys_addr + i * 4; - u32 val = *(map_addr + offset / 4 + i); + u32 voffset = offset + i * 4; + u32 val; + + /* If we reach the RESTART opcode, continue at the beginning of pushbuffer */ + if (cdma && voffset >= cdma->push_buffer.size) { + addr -= cdma->push_buffer.size; + voffset -= cdma->push_buffer.size; + } + + val = *(map_addr + voffset / 4); if (!data_count) { host1x_debug_output(o, " %pad: %08x: ", &addr, val); @@ -203,7 +212,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) job->num_slots, job->num_unpins); show_gather(o, pb->dma + job->first_get, job->num_slots * 2, cdma, - pb->dma + job->first_get, pb->mapped + job->first_get); + pb->dma, pb->mapped); for (i = 0; i < job->num_cmds; i++) { struct host1x_job_gather *g; @@ -227,7 +236,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n", &g->base, g->offset, g->words); - show_gather(o, g->base + g->offset, g->words, cdma, + show_gather(o, g->base + g->offset, g->words, NULL, g->base, mapped); if (!job->gather_copy_mapped) diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 3535be9daa1f39..947323f4a23433 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1467,7 +1467,7 @@ static struct platform_driver imx_ipu_driver = { .of_match_table = imx_ipu_dt_ids, }, .probe = ipu_probe, - .remove_new = ipu_remove, + .remove = ipu_remove, }; static struct platform_driver * const drivers[] = { diff --git a/drivers/gpu/ipu-v3/ipu-pre.c b/drivers/gpu/ipu-v3/ipu-pre.c index 41bd5dbd7356c0..7aac70368b0080 100644 --- a/drivers/gpu/ipu-v3/ipu-pre.c +++ b/drivers/gpu/ipu-v3/ipu-pre.c @@ -374,7 +374,7 @@ static const struct of_device_id ipu_pre_dt_ids[] = { struct platform_driver ipu_pre_drv = { .probe = ipu_pre_probe, - .remove_new = ipu_pre_remove, + .remove = ipu_pre_remove, .driver = { .name = "imx-ipu-pre", .of_match_table = ipu_pre_dt_ids, diff --git a/drivers/gpu/ipu-v3/ipu-prg.c b/drivers/gpu/ipu-v3/ipu-prg.c index afb2d72e9175f3..d38d3ba54d722b 100644 --- a/drivers/gpu/ipu-v3/ipu-prg.c +++ b/drivers/gpu/ipu-v3/ipu-prg.c @@ -469,7 +469,7 @@ static const struct of_device_id ipu_prg_dt_ids[] = { struct platform_driver ipu_prg_drv = { .probe = ipu_prg_probe, - .remove_new = ipu_prg_remove, + .remove = ipu_prg_remove, .driver = { .name = "imx-ipu-prg", .pm = &prg_pm_ops, diff --git a/drivers/greybus/interface.c b/drivers/greybus/interface.c index d022bfb5e95d74..a0f3e942272155 100644 --- a/drivers/greybus/interface.c +++ b/drivers/greybus/interface.c @@ -780,7 +780,7 @@ const struct device_type greybus_interface_type = { * The position of interface within the Endo is encoded in "interface_id" * argument. * - * Returns a pointer to the new interfce or a null pointer if a + * Returns a pointer to the new interface or a null pointer if a * failure occurs due to memory exhaustion. */ struct gb_interface *gb_interface_create(struct gb_module *module, diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index f8a56d6312425a..4d2a89d65b6584 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -213,13 +213,16 @@ config HID_CHICONY config HID_CORSAIR tristate "Corsair devices" depends on USB_HID && LEDS_CLASS + select POWER_SUPPLY help Support for Corsair devices that are not fully compliant with the HID standard. + Support for Corsair Void headsets. Supported devices: - Vengeance K90 - Scimitar PRO RGB + - Corsair Void headsets config HID_COUGAR tristate "Cougar devices" @@ -465,6 +468,15 @@ config HID_KYE - MousePen i608X tablet - EasyPen M610X tablet +config HID_KYSONA + tristate "Kysona devices" + depends on USB_HID + help + Support for Kysona mice. + + Say Y here if you have a Kysona M600 mouse + and want to be able to read its battery capacity. + config HID_UCLOGIC tristate "UC-Logic" depends on USB_HID @@ -1096,6 +1108,7 @@ config HID_RMI select RMI4_F11 select RMI4_F12 select RMI4_F30 + select RMI4_F3A help Support for Synaptics RMI4 touchpads. Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 496dab54c73a82..24de45f3677d16 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -38,7 +38,7 @@ obj-$(CONFIG_HID_BIGBEN_FF) += hid-bigbenff.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o -obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o +obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o hid-corsair-void.o obj-$(CONFIG_HID_COUGAR) += hid-cougar.o obj-$(CONFIG_HID_CP2112) += hid-cp2112.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o @@ -70,6 +70,7 @@ obj-$(CONFIG_HID_JABRA) += hid-jabra.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o obj-$(CONFIG_HID_KYE) += hid-kye.o +obj-$(CONFIG_HID_KYSONA) += hid-kysona.o obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o obj-$(CONFIG_HID_LETSKETCH) += hid-letsketch.o diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 8420c227e21b3a..2e96ec6a3073da 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -19,7 +19,7 @@ #include #include "hid_bpf_dispatch.h" -struct hid_ops *hid_ops; +const struct hid_ops *hid_ops; EXPORT_SYMBOL(hid_ops); u8 * @@ -148,7 +148,7 @@ int dispatch_hid_bpf_output_report(struct hid_device *hdev, } EXPORT_SYMBOL_GPL(dispatch_hid_bpf_output_report); -u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size) +const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size) { int ret; struct hid_bpf_ctx_kern ctx_kern = { @@ -183,7 +183,7 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned ignore_bpf: kfree(ctx_kern.data); - return kmemdup(rdesc, *size, GFP_KERNEL); + return rdesc; } EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup); @@ -260,8 +260,11 @@ int hid_bpf_allocate_event_data(struct hid_device *hdev) int hid_bpf_reconnect(struct hid_device *hdev) { - if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) + if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) { + /* trigger call to call_hid_bpf_rdesc_fixup() during the next probe */ + hdev->bpf_rsize = 0; return device_reprobe(&hdev->dev); + } return 0; } @@ -349,7 +352,6 @@ __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz, { struct hid_report_enum *report_enum; struct hid_report *report; - struct hid_device *hdev; u32 report_len; /* check arguments */ @@ -368,9 +370,7 @@ __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz, if (*buf__sz < 1) return -EINVAL; - hdev = (struct hid_device *)ctx->hid; /* discard const */ - - report_enum = hdev->report_enum + rtype; + report_enum = ctx->hid->report_enum + rtype; report = hid_ops->hid_get_report(report_enum, buf); if (!report) return -EINVAL; @@ -399,7 +399,6 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, enum hid_report_type rtype, enum hid_class_request reqtype) { struct hid_bpf_ctx_kern *ctx_kern; - struct hid_device *hdev; size_t size = buf__sz; u8 *dma_data; int ret; @@ -426,13 +425,11 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, return -EINVAL; } - hdev = (struct hid_device *)ctx->hid; /* discard const */ - dma_data = kmemdup(buf, size, GFP_KERNEL); if (!dma_data) return -ENOMEM; - ret = hid_ops->hid_hw_raw_request(hdev, + ret = hid_ops->hid_hw_raw_request(ctx->hid, dma_data[0], dma_data, size, @@ -461,7 +458,6 @@ __bpf_kfunc int hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) { struct hid_bpf_ctx_kern *ctx_kern; - struct hid_device *hdev; size_t size = buf__sz; u8 *dma_data; int ret; @@ -475,13 +471,11 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) if (ret) return ret; - hdev = (struct hid_device *)ctx->hid; /* discard const */ - dma_data = kmemdup(buf, size, GFP_KERNEL); if (!dma_data) return -ENOMEM; - ret = hid_ops->hid_hw_output_report(hdev, dma_data, size, (u64)(long)ctx, true); + ret = hid_ops->hid_hw_output_report(ctx->hid, dma_data, size, (u64)(long)ctx, true); kfree(dma_data); return ret; diff --git a/drivers/hid/bpf/progs/Huion__Dial-2.bpf.c b/drivers/hid/bpf/progs/Huion__Dial-2.bpf.c index 2411dec6db08b6..9670e5ef8d54f0 100644 --- a/drivers/hid/bpf/progs/Huion__Dial-2.bpf.c +++ b/drivers/hid/bpf/progs/Huion__Dial-2.bpf.c @@ -214,7 +214,8 @@ static const __u8 fixed_rdesc_pad[] = { CollectionApplication( // -- Byte 0 in report ReportId(PAD_REPORT_ID) - LogicalRange_i8(0, 1) + LogicalMaximum_i8(0) + LogicalMaximum_i8(1) UsagePage_Digitizers Usage_Dig_TabletFunctionKeys CollectionPhysical( @@ -234,14 +235,17 @@ static const __u8 fixed_rdesc_pad[] = { Input(Var|Abs) // Byte 4 in report is the dial Usage_GD_Wheel - LogicalRange_i8(-1, 1) + LogicalMinimum_i8(-1) + LogicalMaximum_i8(1) ReportCount(1) ReportSize(8) Input(Var|Rel) // Byte 5 is the button state UsagePage_Button - UsageRange_i8(0x01, 0x8) - LogicalRange_i8(0x0, 0x1) + UsageMinimum_i8(0x01) + UsageMaximum_i8(0x08) + LogicalMinimum_i8(0x0) + LogicalMaximum_i8(0x1) ReportCount(7) ReportSize(1) Input(Var|Abs) @@ -265,7 +269,8 @@ static const __u8 fixed_rdesc_pen[] = { Usage_Dig_TipSwitch Usage_Dig_BarrelSwitch Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2 - LogicalRange_i8(0, 1) + LogicalMinimum_i8(0) + LogicalMaximum_i8(1) ReportSize(1) ReportCount(3) Input(Var|Abs) @@ -280,22 +285,28 @@ static const __u8 fixed_rdesc_pen[] = { UsagePage_GenericDesktop Unit(cm) UnitExponent(-1) - PhysicalRange_i16(0, 266) - LogicalRange_i16(0, 32767) + PhysicalMinimum_i16(0) + PhysicalMaximum_i16(266) + LogicalMinimum_i16(0) + LogicalMaximum_i16(32767) Usage_GD_X Input(Var|Abs) // Bytes 2+3 - PhysicalRange_i16(0, 166) - LogicalRange_i16(0, 32767) + PhysicalMinimum_i16(0) + PhysicalMaximum_i16(166) + LogicalMinimum_i16(0) + LogicalMaximum_i16(32767) Usage_GD_Y Input(Var|Abs) // Bytes 4+5 ) UsagePage_Digitizers Usage_Dig_TipPressure - LogicalRange_i16(0, 8191) + LogicalMinimum_i16(0) + LogicalMaximum_i16(8191) Input(Var|Abs) // Byte 6+7 ReportSize(8) ReportCount(2) - LogicalRange_i8(-60, 60) + LogicalMinimum_i8(-60) + LogicalMaximum_i8(60) Usage_Dig_XTilt Usage_Dig_YTilt Input(Var|Abs) // Byte 8+9 @@ -313,7 +324,8 @@ static const __u8 fixed_rdesc_vendor[] = { Usage_Dig_Pen CollectionPhysical( // Byte 1 are the buttons - LogicalRange_i8(0, 1) + LogicalMinimum_i8(0) + LogicalMaximum_i8(1) ReportSize(1) Usage_Dig_TipSwitch Usage_Dig_BarrelSwitch @@ -333,25 +345,31 @@ static const __u8 fixed_rdesc_vendor[] = { UnitExponent(-1) // Note: reported logical range differs // from the pen report ID for x and y - LogicalRange_i16(0, 53340) - PhysicalRange_i16(0, 266) + LogicalMinimum_i16(0) + LogicalMaximum_i16(53340) + PhysicalMinimum_i16(0) + PhysicalMaximum_i16(266) // Bytes 2/3 in report Usage_GD_X Input(Var|Abs) - LogicalRange_i16(0, 33340) - PhysicalRange_i16(0, 166) + LogicalMinimum_i16(0) + LogicalMaximum_i16(33340) + PhysicalMinimum_i16(0) + PhysicalMaximum_i16(166) // Bytes 4/5 in report Usage_GD_Y Input(Var|Abs) ) // Bytes 6/7 in report - LogicalRange_i16(0, 8191) + LogicalMinimum_i16(0) + LogicalMaximum_i16(8191) Usage_Dig_TipPressure Input(Var|Abs) // Bytes 8/9 in report ReportCount(1) // Padding Input(Const) - LogicalRange_i8(-60, 60) + LogicalMinimum_i8(-60) + LogicalMaximum_i8(60) // Byte 10 in report Usage_Dig_XTilt // Byte 11 in report @@ -366,7 +384,8 @@ static const __u8 fixed_rdesc_vendor[] = { CollectionApplication( // Byte 0 ReportId(PAD_REPORT_ID) - LogicalRange_i8(0, 1) + LogicalMinimum_i8(0) + LogicalMaximum_i8(1) UsagePage_Digitizers Usage_Dig_TabletFunctionKeys CollectionPhysical( @@ -386,15 +405,18 @@ static const __u8 fixed_rdesc_vendor[] = { Input(Var|Abs) // Byte 4 is the button state UsagePage_Button - UsageRange_i8(0x01, 0x8) - LogicalRange_i8(0x0, 0x1) + UsageMinimum_i8(0x1) + UsageMaximum_i8(0x8) + LogicalMinimum_i8(0x0) + LogicalMaximum_i8(0x1) ReportCount(8) ReportSize(1) Input(Var|Abs) // Byte 5 is the top dial UsagePage_GenericDesktop Usage_GD_Wheel - LogicalRange_i8(-1, 1) + LogicalMinimum_i8(-1) + LogicalMaximum_i8(1) ReportCount(1) ReportSize(8) Input(Var|Rel) diff --git a/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c b/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c index b09b80132368b6..13f64fb49800b1 100644 --- a/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c +++ b/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c @@ -170,7 +170,8 @@ static const __u8 fixed_rdesc_pad[] = { CollectionApplication( // -- Byte 0 in report ReportId(PAD_REPORT_ID) - LogicalRange_i8(0, 1) + LogicalMinimum_i8(0) + LogicalMaximum_i8(1) UsagePage_Digitizers Usage_Dig_TabletFunctionKeys CollectionPhysical( @@ -190,14 +191,17 @@ static const __u8 fixed_rdesc_pad[] = { Input(Var|Abs) // Byte 4 in report is the wheel Usage_GD_Wheel - LogicalRange_i8(-1, 1) + LogicalMinimum_i8(-1) + LogicalMaximum_i8(1) ReportCount(1) ReportSize(8) Input(Var|Rel) // Byte 5 is the button state UsagePage_Button - UsageRange_i8(0x01, 0x6) - LogicalRange_i8(0x01, 0x6) + UsageMinimum_i8(0x1) + UsageMaximum_i8(0x6) + LogicalMinimum_i8(0x1) + LogicalMaximum_i8(0x6) ReportCount(1) ReportSize(8) Input(Arr|Abs) @@ -219,7 +223,8 @@ static const __u8 fixed_rdesc_pen[] = { Usage_Dig_TipSwitch Usage_Dig_BarrelSwitch Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2 - LogicalRange_i8(0, 1) + LogicalMinimum_i8(0) + LogicalMaximum_i8(1) ReportSize(1) ReportCount(3) Input(Var|Abs) @@ -234,18 +239,23 @@ static const __u8 fixed_rdesc_pen[] = { UsagePage_GenericDesktop Unit(cm) UnitExponent(-1) - PhysicalRange_i16(0, 160) - LogicalRange_i16(0, 32767) + PhysicalMinimum_i16(0) + PhysicalMaximum_i16(160) + LogicalMinimum_i16(0) + LogicalMaximum_i16(32767) Usage_GD_X Input(Var|Abs) // Bytes 2+3 - PhysicalRange_i16(0, 100) - LogicalRange_i16(0, 32767) + PhysicalMinimum_i16(0) + PhysicalMaximum_i16(100) + LogicalMinimum_i16(0) + LogicalMaximum_i16(32767) Usage_GD_Y Input(Var|Abs) // Bytes 4+5 ) UsagePage_Digitizers Usage_Dig_TipPressure - LogicalRange_i16(0, 8191) + LogicalMinimum_i16(0) + LogicalMaximum_i16(8191) Input(Var|Abs) // Byte 6+7 // Two bytes padding so we don't need to change the report at all ReportSize(8) @@ -265,7 +275,8 @@ static const __u8 fixed_rdesc_vendor[] = { Usage_Dig_Pen CollectionPhysical( // Byte 1 are the buttons - LogicalRange_i8(0, 1) + LogicalMinimum_i8(0) + LogicalMaximum_i8(1) ReportSize(1) Usage_Dig_TipSwitch Usage_Dig_BarrelSwitch @@ -285,19 +296,24 @@ static const __u8 fixed_rdesc_vendor[] = { UnitExponent(-1) // Note: reported logical range differs // from the pen report ID for x and y - LogicalRange_i16(0, 32000) - PhysicalRange_i16(0, 160) + LogicalMinimum_i16(0) + LogicalMaximum_i16(32000) + PhysicalMinimum_i16(0) + PhysicalMaximum_i16(160) // Bytes 2/3 in report Usage_GD_X Input(Var|Abs) - LogicalRange_i16(0, 20000) - PhysicalRange_i16(0, 100) + LogicalMinimum_i16(0) + LogicalMaximum_i16(20000) + PhysicalMinimum_i16(0) + PhysicalMaximum_i16(100) // Bytes 4/5 in report Usage_GD_Y Input(Var|Abs) ) // Bytes 6/7 in report - LogicalRange_i16(0, 8192) + LogicalMinimum_i16(0) + LogicalMaximum_i16(8192) Usage_Dig_TipPressure Input(Var|Abs) ) @@ -307,7 +323,8 @@ static const __u8 fixed_rdesc_vendor[] = { CollectionApplication( // Byte 0 ReportId(PAD_REPORT_ID) - LogicalRange_i8(0, 1) + LogicalMinimum_i8(0) + LogicalMaximum_i8(1) UsagePage_Digitizers Usage_Dig_TabletFunctionKeys CollectionPhysical( @@ -327,8 +344,10 @@ static const __u8 fixed_rdesc_vendor[] = { Input(Var|Abs) // Byte 4 is the button state UsagePage_Button - UsageRange_i8(0x01, 0x6) - LogicalRange_i8(0x0, 0x1) + UsageMinimum_i8(0x1) + UsageMaximum_i8(0x6) + LogicalMinimum_i8(0x0) + LogicalMaximum_i8(0x1) ReportCount(6) ReportSize(1) Input(Var|Abs) @@ -337,7 +356,8 @@ static const __u8 fixed_rdesc_vendor[] = { // Byte 5 is the wheel UsagePage_GenericDesktop Usage_GD_Wheel - LogicalRange_i8(-1, 1) + LogicalMinimum_i8(-1) + LogicalMaximum_i8(1) ReportCount(1) ReportSize(8) Input(Var|Rel) diff --git a/drivers/hid/bpf/progs/Mistel__MD770.bpf.c b/drivers/hid/bpf/progs/Mistel__MD770.bpf.c new file mode 100644 index 00000000000000..fb8b5a6968b125 --- /dev/null +++ b/drivers/hid/bpf/progs/Mistel__MD770.bpf.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Tatsuyuki Ishi + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_HOLTEK 0x04D9 +#define PID_MD770 0x0339 +#define RDESC_SIZE 203 + +HID_BPF_CONFIG( + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HOLTEK, PID_MD770) +); + +/* + * The Mistel MD770 keyboard reports the first 6 simultaneous key presses + * through the first interface, and anything beyond that through a second + * interface. Unfortunately, the second interface's report descriptor has an + * error, causing events to be malformed and ignored. This HID-BPF driver + * fixes the descriptor to allow NKRO to work again. + * + * For reference, this is the original report descriptor: + * + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x80, // Usage (System Control) 2 + * 0xa1, 0x01, // Collection (Application) 4 + * 0x85, 0x01, // Report ID (1) 6 + * 0x19, 0x81, // Usage Minimum (129) 8 + * 0x29, 0x83, // Usage Maximum (131) 10 + * 0x15, 0x00, // Logical Minimum (0) 12 + * 0x25, 0x01, // Logical Maximum (1) 14 + * 0x95, 0x03, // Report Count (3) 16 + * 0x75, 0x01, // Report Size (1) 18 + * 0x81, 0x02, // Input (Data,Var,Abs) 20 + * 0x95, 0x01, // Report Count (1) 22 + * 0x75, 0x05, // Report Size (5) 24 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 26 + * 0xc0, // End Collection 28 + * 0x05, 0x0c, // Usage Page (Consumer Devices) 29 + * 0x09, 0x01, // Usage (Consumer Control) 31 + * 0xa1, 0x01, // Collection (Application) 33 + * 0x85, 0x02, // Report ID (2) 35 + * 0x15, 0x00, // Logical Minimum (0) 37 + * 0x25, 0x01, // Logical Maximum (1) 39 + * 0x95, 0x12, // Report Count (18) 41 + * 0x75, 0x01, // Report Size (1) 43 + * 0x0a, 0x83, 0x01, // Usage (AL Consumer Control Config) 45 + * 0x0a, 0x8a, 0x01, // Usage (AL Email Reader) 48 + * 0x0a, 0x92, 0x01, // Usage (AL Calculator) 51 + * 0x0a, 0x94, 0x01, // Usage (AL Local Machine Browser) 54 + * 0x09, 0xcd, // Usage (Play/Pause) 57 + * 0x09, 0xb7, // Usage (Stop) 59 + * 0x09, 0xb6, // Usage (Scan Previous Track) 61 + * 0x09, 0xb5, // Usage (Scan Next Track) 63 + * 0x09, 0xe2, // Usage (Mute) 65 + * 0x09, 0xea, // Usage (Volume Down) 67 + * 0x09, 0xe9, // Usage (Volume Up) 69 + * 0x0a, 0x21, 0x02, // Usage (AC Search) 71 + * 0x0a, 0x23, 0x02, // Usage (AC Home) 74 + * 0x0a, 0x24, 0x02, // Usage (AC Back) 77 + * 0x0a, 0x25, 0x02, // Usage (AC Forward) 80 + * 0x0a, 0x26, 0x02, // Usage (AC Stop) 83 + * 0x0a, 0x27, 0x02, // Usage (AC Refresh) 86 + * 0x0a, 0x2a, 0x02, // Usage (AC Bookmarks) 89 + * 0x81, 0x02, // Input (Data,Var,Abs) 92 + * 0x95, 0x01, // Report Count (1) 94 + * 0x75, 0x0e, // Report Size (14) 96 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 98 + * 0xc0, // End Collection 100 + * 0x05, 0x01, // Usage Page (Generic Desktop) 101 + * 0x09, 0x02, // Usage (Mouse) 103 + * 0xa1, 0x01, // Collection (Application) 105 + * 0x09, 0x01, // Usage (Pointer) 107 + * 0xa1, 0x00, // Collection (Physical) 109 + * 0x85, 0x03, // Report ID (3) 111 + * 0x05, 0x09, // Usage Page (Button) 113 + * 0x19, 0x01, // Usage Minimum (1) 115 + * 0x29, 0x08, // Usage Maximum (8) 117 + * 0x15, 0x00, // Logical Minimum (0) 119 + * 0x25, 0x01, // Logical Maximum (1) 121 + * 0x75, 0x01, // Report Size (1) 123 + * 0x95, 0x08, // Report Count (8) 125 + * 0x81, 0x02, // Input (Data,Var,Abs) 127 + * 0x05, 0x01, // Usage Page (Generic Desktop) 129 + * 0x09, 0x30, // Usage (X) 131 + * 0x09, 0x31, // Usage (Y) 133 + * 0x16, 0x01, 0x80, // Logical Minimum (-32767) 135 + * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 138 + * 0x75, 0x10, // Report Size (16) 141 + * 0x95, 0x02, // Report Count (2) 143 + * 0x81, 0x06, // Input (Data,Var,Rel) 145 + * 0x09, 0x38, // Usage (Wheel) 147 + * 0x15, 0x81, // Logical Minimum (-127) 149 + * 0x25, 0x7f, // Logical Maximum (127) 151 + * 0x75, 0x08, // Report Size (8) 153 + * 0x95, 0x01, // Report Count (1) 155 + * 0x81, 0x06, // Input (Data,Var,Rel) 157 + * 0x05, 0x0c, // Usage Page (Consumer Devices) 159 + * 0x0a, 0x38, 0x02, // Usage (AC Pan) 161 + * 0x95, 0x01, // Report Count (1) 164 + * 0x81, 0x06, // Input (Data,Var,Rel) 166 + * 0xc0, // End Collection 168 + * 0xc0, // End Collection 169 + * 0x05, 0x01, // Usage Page (Generic Desktop) 170 + * 0x09, 0x06, // Usage (Keyboard) 172 + * 0xa1, 0x01, // Collection (Application) 174 + * 0x85, 0x04, // Report ID (4) 176 + * 0x05, 0x07, // Usage Page (Keyboard) 178 + * 0x95, 0x01, // Report Count (1) 180 + * 0x75, 0x08, // Report Size (8) 182 + * 0x81, 0x03, // Input (Cnst,Var,Abs) 184 + * 0x95, 0xe8, // Report Count (232) 186 + * 0x75, 0x01, // Report Size (1) 188 + * 0x15, 0x00, // Logical Minimum (0) 190 + * 0x25, 0x01, // Logical Maximum (1) 192 + * 0x05, 0x07, // Usage Page (Keyboard) 194 + * 0x19, 0x00, // Usage Minimum (0) 196 + * 0x29, 0xe7, // Usage Maximum (231) 198 + * 0x81, 0x00, // Input (Data,Arr,Abs) 200 <- change to 0x81, 0x02 (Data,Var,Abs) + * 0xc0, // End Collection 202 + */ + +SEC(HID_BPF_RDESC_FIXUP) +int BPF_PROG(hid_rdesc_fixup_mistel_md770, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE); + + if (!data) + return 0; /* EPERM check */ + + if (data[201] == 0x00) + data[201] = 0x02; + + return 0; +} + +HID_BPF_OPS(mistel_md770) = { + .hid_rdesc_fixup = (void *)hid_rdesc_fixup_mistel_md770, +}; + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + ctx->retval = ctx->rdesc_size != RDESC_SIZE; + if (ctx->retval) + ctx->retval = -EINVAL; + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c b/drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c new file mode 100644 index 00000000000000..6b379e45f531db --- /dev/null +++ b/drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2024 José Expósito + */ + +#include "vmlinux.h" +#include "hid_bpf.h" +#include "hid_bpf_helpers.h" +#include + +#define VID_RAPOO 0x24AE +#define PID_M50 0x2015 +#define RDESC_SIZE 186 + +HID_BPF_CONFIG( + HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_RAPOO, PID_M50) +); + +/* + * The Rapoo M50 Plus Silent mouse has 2 side buttons in addition to the left, + * right and middle buttons. However, its original HID descriptor has a Usage + * Maximum of 3, preventing the side buttons to work. This HID-BPF driver + * changes that usage to 5. + * + * For reference, this is the original report descriptor: + * + * 0x05, 0x01, // Usage Page (Generic Desktop) 0 + * 0x09, 0x02, // Usage (Mouse) 2 + * 0xa1, 0x01, // Collection (Application) 4 + * 0x85, 0x01, // Report ID (1) 6 + * 0x09, 0x01, // Usage (Pointer) 8 + * 0xa1, 0x00, // Collection (Physical) 10 + * 0x05, 0x09, // Usage Page (Button) 12 + * 0x19, 0x01, // Usage Minimum (1) 14 + * 0x29, 0x03, // Usage Maximum (3) 16 <- change to 0x05 + * 0x15, 0x00, // Logical Minimum (0) 18 + * 0x25, 0x01, // Logical Maximum (1) 20 + * 0x75, 0x01, // Report Size (1) 22 + * 0x95, 0x05, // Report Count (5) 24 + * 0x81, 0x02, // Input (Data,Var,Abs) 26 + * 0x75, 0x03, // Report Size (3) 28 + * 0x95, 0x01, // Report Count (1) 30 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 32 + * 0x05, 0x01, // Usage Page (Generic Desktop) 34 + * 0x09, 0x30, // Usage (X) 36 + * 0x09, 0x31, // Usage (Y) 38 + * 0x16, 0x01, 0x80, // Logical Minimum (-32767) 40 + * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 43 + * 0x75, 0x10, // Report Size (16) 46 + * 0x95, 0x02, // Report Count (2) 48 + * 0x81, 0x06, // Input (Data,Var,Rel) 50 + * 0x09, 0x38, // Usage (Wheel) 52 + * 0x15, 0x81, // Logical Minimum (-127) 54 + * 0x25, 0x7f, // Logical Maximum (127) 56 + * 0x75, 0x08, // Report Size (8) 58 + * 0x95, 0x01, // Report Count (1) 60 + * 0x81, 0x06, // Input (Data,Var,Rel) 62 + * 0xc0, // End Collection 64 + * 0xc0, // End Collection 65 + * 0x05, 0x0c, // Usage Page (Consumer Devices) 66 + * 0x09, 0x01, // Usage (Consumer Control) 68 + * 0xa1, 0x01, // Collection (Application) 70 + * 0x85, 0x02, // Report ID (2) 72 + * 0x75, 0x10, // Report Size (16) 74 + * 0x95, 0x01, // Report Count (1) 76 + * 0x15, 0x01, // Logical Minimum (1) 78 + * 0x26, 0x8c, 0x02, // Logical Maximum (652) 80 + * 0x19, 0x01, // Usage Minimum (1) 83 + * 0x2a, 0x8c, 0x02, // Usage Maximum (652) 85 + * 0x81, 0x00, // Input (Data,Arr,Abs) 88 + * 0xc0, // End Collection 90 + * 0x05, 0x01, // Usage Page (Generic Desktop) 91 + * 0x09, 0x80, // Usage (System Control) 93 + * 0xa1, 0x01, // Collection (Application) 95 + * 0x85, 0x03, // Report ID (3) 97 + * 0x09, 0x82, // Usage (System Sleep) 99 + * 0x09, 0x81, // Usage (System Power Down) 101 + * 0x09, 0x83, // Usage (System Wake Up) 103 + * 0x15, 0x00, // Logical Minimum (0) 105 + * 0x25, 0x01, // Logical Maximum (1) 107 + * 0x19, 0x01, // Usage Minimum (1) 109 + * 0x29, 0x03, // Usage Maximum (3) 111 + * 0x75, 0x01, // Report Size (1) 113 + * 0x95, 0x03, // Report Count (3) 115 + * 0x81, 0x02, // Input (Data,Var,Abs) 117 + * 0x95, 0x05, // Report Count (5) 119 + * 0x81, 0x01, // Input (Cnst,Arr,Abs) 121 + * 0xc0, // End Collection 123 + * 0x05, 0x01, // Usage Page (Generic Desktop) 124 + * 0x09, 0x00, // Usage (Undefined) 126 + * 0xa1, 0x01, // Collection (Application) 128 + * 0x85, 0x05, // Report ID (5) 130 + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 132 + * 0x09, 0x01, // Usage (Vendor Usage 1) 135 + * 0x15, 0x81, // Logical Minimum (-127) 137 + * 0x25, 0x7f, // Logical Maximum (127) 139 + * 0x75, 0x08, // Report Size (8) 141 + * 0x95, 0x07, // Report Count (7) 143 + * 0xb1, 0x02, // Feature (Data,Var,Abs) 145 + * 0xc0, // End Collection 147 + * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 148 + * 0x09, 0x0e, // Usage (Vendor Usage 0x0e) 151 + * 0xa1, 0x01, // Collection (Application) 153 + * 0x85, 0xba, // Report ID (186) 155 + * 0x95, 0x1f, // Report Count (31) 157 + * 0x75, 0x08, // Report Size (8) 159 + * 0x26, 0xff, 0x00, // Logical Maximum (255) 161 + * 0x15, 0x00, // Logical Minimum (0) 164 + * 0x09, 0x01, // Usage (Vendor Usage 1) 166 + * 0x91, 0x02, // Output (Data,Var,Abs) 168 + * 0x85, 0xba, // Report ID (186) 170 + * 0x95, 0x1f, // Report Count (31) 172 + * 0x75, 0x08, // Report Size (8) 174 + * 0x26, 0xff, 0x00, // Logical Maximum (255) 176 + * 0x15, 0x00, // Logical Minimum (0) 179 + * 0x09, 0x01, // Usage (Vendor Usage 1) 181 + * 0x81, 0x02, // Input (Data,Var,Abs) 183 + * 0xc0, // End Collection 185 + */ + +SEC(HID_BPF_RDESC_FIXUP) +int BPF_PROG(hid_rdesc_fixup_rapoo_m50, struct hid_bpf_ctx *hctx) +{ + __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE); + + if (!data) + return 0; /* EPERM check */ + + if (data[17] == 0x03) + data[17] = 0x05; + + return 0; +} + +HID_BPF_OPS(rapoo_m50) = { + .hid_rdesc_fixup = (void *)hid_rdesc_fixup_rapoo_m50, +}; + +SEC("syscall") +int probe(struct hid_bpf_probe_args *ctx) +{ + ctx->retval = ctx->rdesc_size != RDESC_SIZE; + if (ctx->retval) + ctx->retval = -EINVAL; + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/drivers/hid/bpf/progs/hid_report_helpers.h b/drivers/hid/bpf/progs/hid_report_helpers.h index 0aa1df438eebac..9b2a48e4a311b3 100644 --- a/drivers/hid/bpf/progs/hid_report_helpers.h +++ b/drivers/hid/bpf/progs/hid_report_helpers.h @@ -52,7 +52,8 @@ * Usage_GD_Keyboard * CollectionApplication( ← Open the collection * ReportId(3) - * LogicalRange_i8(0, 1) + * LogicalMinimum_i8(0) + * LogicalMaximum_i8(1) * // other fields * ) ← End EndCollection * @@ -74,26 +75,43 @@ #define Arr 0x0 #define Abs 0x0 #define Rel 0x4 +#define Null 0x40 +#define Buff 0x0100 /* Use like this: Input(Var|Abs) */ #define Input(i_) 0x081, i8(i_), #define Output(i_) 0x091, i8(i_), #define Feature(i_) 0x0b1, i8(i_), +#define Input_i16(i_) 0x082, LE16(i_), +#define Output_i16(i_) 0x092, LE16(i_), +#define Feature_i16(i_) 0x0b2, LE16(i_), + #define ReportId(id_) 0x85, i8(id_), #define ReportSize(sz_) 0x75, i8(sz_), #define ReportCount(cnt_) 0x95, i8(cnt_), -#define LogicalRange_i8(min_, max_) 0x15, i8(min_), 0x25, i8(max_), -#define LogicalRange_i16(min_, max_) 0x16, LE16(min_), 0x26, LE16(max_), -#define LogicalRange_i32(min_, max_) 0x17, LE32(min_), 0x27, LE32(max_), +#define LogicalMinimum_i8(min_) 0x15, i8(min_), +#define LogicalMinimum_i16(min_) 0x16, LE16(min_), +#define LogicalMinimum_i32(min_) 0x17, LE32(min_), + +#define LogicalMaximum_i8(max_) 0x25, i8(max_), +#define LogicalMaximum_i16(max_) 0x26, LE16(max_), +#define LogicalMaximum_i32(max_) 0x27, LE32(max_), + +#define PhysicalMinimum_i8(min_) 0x35, i8(min_), +#define PhysicalMinimum_i16(min_) 0x36, LE16(min_), +#define PhysicalMinimum_i32(min_) 0x37, LE32(min_), + +#define PhysicalMaximum_i8(max_) 0x45, i8(max_), +#define PhysicalMaximum_i16(max_) 0x46, LE16(max_), +#define PhysicalMaximum_i32(max_) 0x47, LE32(max_), -#define PhysicalRange_i8(min_, max_) 0x35, i8(min_), 0x45, i8(max_), -#define PhysicalRange_i16(min_, max_) 0x36, LE16(min_), 0x46, LE16(max_), -#define PhysicalRange_i32(min_, max_) 0x37, LE32(min_), 0x47, LE32(max_), +#define UsageMinimum_i8(min_) 0x19, i8(min_), +#define UsageMinimum_i16(min_) 0x1a, LE16(min_), -#define UsageRange_i8(min_, max_) 0x19, i8(min_), 0x29, i8(max_), -#define UsageRange_i16(min_, max_) 0x1a, LE16(min_), 0x2a, LE16(max_), +#define UsageMaximum_i8(max_) 0x29, i8(max_), +#define UsageMaximum_i16(max_) 0x2a, LE16(max_), #define UsagePage_i8(p_) 0x05, i8(p_), #define UsagePage_i16(p_) 0x06, LE16(p_), diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index a4b47319ad8ead..506c6f377e7d6c 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -1183,7 +1183,7 @@ static const __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (drvdata->quirks & QUIRK_G752_KEYBOARD && *rsize == 75 && rdesc[61] == 0x15 && rdesc[62] == 0x00) { - /* report is missing usage mninum and maximum */ + /* report is missing usage minimum and maximum */ __u8 *new_rdesc; size_t new_size = *rsize + sizeof(asus_g752_fixed_rdesc); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 582fd234eec789..33a19197332488 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -45,6 +45,34 @@ static int hid_ignore_special_drivers = 0; module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600); MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver"); +/* + * Convert a signed n-bit integer to signed 32-bit integer. + */ + +static s32 snto32(__u32 value, unsigned int n) +{ + if (!value || !n) + return 0; + + if (n > 32) + n = 32; + + return sign_extend32(value, n - 1); +} + +/* + * Convert a signed 32-bit integer to a signed n-bit integer. + */ + +static u32 s32ton(__s32 value, unsigned int n) +{ + s32 a = value >> (n - 1); + + if (a && a != -1) + return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; + return value & ((1 << n) - 1); +} + /* * Register a new report for a device. */ @@ -425,7 +453,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) * both this and the standard encoding. */ raw_value = item_sdata(item); if (!(raw_value & 0xfffffff0)) - parser->global.unit_exponent = hid_snto32(raw_value, 4); + parser->global.unit_exponent = snto32(raw_value, 4); else parser->global.unit_exponent = raw_value; return 0; @@ -685,7 +713,14 @@ static void hid_close_report(struct hid_device *device) INIT_LIST_HEAD(&report_enum->report_list); } - kfree(device->rdesc); + /* + * If the HID driver had a rdesc_fixup() callback, dev->rdesc + * will be allocated by hid-core and needs to be freed. + * Otherwise, it is either equal to dev_rdesc or bpf_rdesc, in + * which cases it'll be freed later on device removal or destroy. + */ + if (device->rdesc != device->dev_rdesc && device->rdesc != device->bpf_rdesc) + kfree(device->rdesc); device->rdesc = NULL; device->rsize = 0; @@ -698,6 +733,14 @@ static void hid_close_report(struct hid_device *device) device->status &= ~HID_STAT_PARSED; } +static inline void hid_free_bpf_rdesc(struct hid_device *hdev) +{ + /* bpf_rdesc is either equal to dev_rdesc or allocated by call_hid_bpf_rdesc_fixup() */ + if (hdev->bpf_rdesc != hdev->dev_rdesc) + kfree(hdev->bpf_rdesc); + hdev->bpf_rdesc = NULL; +} + /* * Free a device structure, all reports, and all fields. */ @@ -707,6 +750,7 @@ void hiddev_free(struct kref *ref) struct hid_device *hid = container_of(ref, struct hid_device, ref); hid_close_report(hid); + hid_free_bpf_rdesc(hid); kfree(hid->dev_rdesc); kfree(hid); } @@ -754,35 +798,29 @@ static const u8 *fetch_item(const __u8 *start, const __u8 *end, struct hid_item } item->format = HID_ITEM_FORMAT_SHORT; - item->size = b & 3; + item->size = BIT(b & 3) >> 1; /* 0, 1, 2, 3 -> 0, 1, 2, 4 */ + + if (end - start < item->size) + return NULL; switch (item->size) { case 0: - return start; + break; case 1: - if ((end - start) < 1) - return NULL; - item->data.u8 = *start++; - return start; + item->data.u8 = *start; + break; case 2: - if ((end - start) < 2) - return NULL; item->data.u16 = get_unaligned_le16(start); - start = (__u8 *)((__le16 *)start + 1); - return start; + break; - case 3: - item->size++; - if ((end - start) < 4) - return NULL; + case 4: item->data.u32 = get_unaligned_le32(start); - start = (__u8 *)((__le32 *)start + 1); - return start; + break; } - return NULL; + return start + item->size; } static void hid_scan_input_usage(struct hid_parser *parser, u32 usage) @@ -1205,7 +1243,6 @@ int hid_open_report(struct hid_device *device) struct hid_item item; unsigned int size; const __u8 *start; - __u8 *buf; const __u8 *end; const __u8 *next; int ret; @@ -1221,25 +1258,34 @@ int hid_open_report(struct hid_device *device) if (WARN_ON(device->status & HID_STAT_PARSED)) return -EBUSY; - start = device->dev_rdesc; + start = device->bpf_rdesc; if (WARN_ON(!start)) return -ENODEV; - size = device->dev_rsize; + size = device->bpf_rsize; - /* call_hid_bpf_rdesc_fixup() ensures we work on a copy of rdesc */ - buf = call_hid_bpf_rdesc_fixup(device, start, &size); - if (buf == NULL) - return -ENOMEM; + if (device->driver->report_fixup) { + /* + * device->driver->report_fixup() needs to work + * on a copy of our report descriptor so it can + * change it. + */ + __u8 *buf = kmemdup(start, size, GFP_KERNEL); + + if (buf == NULL) + return -ENOMEM; - if (device->driver->report_fixup) start = device->driver->report_fixup(device, buf, &size); - else - start = buf; - start = kmemdup(start, size, GFP_KERNEL); - kfree(buf); - if (start == NULL) - return -ENOMEM; + /* + * The second kmemdup is required in case report_fixup() returns + * a static read-only memory, but we have no idea if that memory + * needs to be cleaned up or not at the end. + */ + start = kmemdup(start, size, GFP_KERNEL); + kfree(buf); + if (start == NULL) + return -ENOMEM; + } device->rdesc = start; device->rsize = size; @@ -1315,46 +1361,6 @@ int hid_open_report(struct hid_device *device) } EXPORT_SYMBOL_GPL(hid_open_report); -/* - * Convert a signed n-bit integer to signed 32-bit integer. Common - * cases are done through the compiler, the screwed things has to be - * done by hand. - */ - -static s32 snto32(__u32 value, unsigned n) -{ - if (!value || !n) - return 0; - - if (n > 32) - n = 32; - - switch (n) { - case 8: return ((__s8)value); - case 16: return ((__s16)value); - case 32: return ((__s32)value); - } - return value & (1 << (n - 1)) ? value | (~0U << n) : value; -} - -s32 hid_snto32(__u32 value, unsigned n) -{ - return snto32(value, n); -} -EXPORT_SYMBOL_GPL(hid_snto32); - -/* - * Convert a signed 32-bit integer to a signed n-bit integer. - */ - -static u32 s32ton(__s32 value, unsigned n) -{ - s32 a = value >> (n - 1); - if (a && a != -1) - return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; - return value & ((1 << n) - 1); -} - /* * Extract/implement a data field from/to a little endian report (bit array). * @@ -2674,9 +2680,10 @@ static bool hid_check_device_match(struct hid_device *hdev, /* * hid-generic implements .match(), so we must be dealing with a * different HID driver here, and can simply check if - * hid_ignore_special_drivers is set or not. + * hid_ignore_special_drivers or HID_QUIRK_IGNORE_SPECIAL_DRIVER + * are set or not. */ - return !hid_ignore_special_drivers; + return !hid_ignore_special_drivers && !(hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER); } static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) @@ -2684,6 +2691,18 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) const struct hid_device_id *id; int ret; + if (!hdev->bpf_rsize) { + /* in case a bpf program gets detached, we need to free the old one */ + hid_free_bpf_rdesc(hdev); + + /* keep this around so we know we called it once */ + hdev->bpf_rsize = hdev->dev_rsize; + + /* call_hid_bpf_rdesc_fixup will always return a valid pointer */ + hdev->bpf_rdesc = call_hid_bpf_rdesc_fixup(hdev, hdev->dev_rdesc, + &hdev->bpf_rsize); + } + if (!hid_check_device_match(hdev, hdrv, &id)) return -ENODEV; @@ -2940,9 +2959,11 @@ static void hid_remove_device(struct hid_device *hdev) hid_debug_unregister(hdev); hdev->status &= ~HID_STAT_ADDED; } + hid_free_bpf_rdesc(hdev); kfree(hdev->dev_rdesc); hdev->dev_rdesc = NULL; hdev->dev_rsize = 0; + hdev->bpf_rsize = 0; } /** @@ -3043,7 +3064,7 @@ int hid_check_keys_pressed(struct hid_device *hid) EXPORT_SYMBOL_GPL(hid_check_keys_pressed); #ifdef CONFIG_HID_BPF -static struct hid_ops __hid_ops = { +static const struct hid_ops __hid_ops = { .hid_get_report = hid_get_report, .hid_hw_raw_request = __hid_hw_raw_request, .hid_hw_output_report = __hid_hw_output_report, diff --git a/drivers/hid/hid-corsair-void.c b/drivers/hid/hid-corsair-void.c new file mode 100644 index 00000000000000..6ece56b850fc02 --- /dev/null +++ b/drivers/hid/hid-corsair-void.c @@ -0,0 +1,829 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HID driver for Corsair Void headsets + * + * Copyright (C) 2023-2024 Stuart Hayhurst + */ + +/* -------------------------------------------------------------------------- */ +/* Receiver report information: (ID 100) */ +/* -------------------------------------------------------------------------- */ +/* + * When queried, the receiver reponds with 5 bytes to describe the battery + * The power button, mute button and moving the mic also trigger this report + * This includes power button + mic + connection + battery status and capacity + * The information below may not be perfect, it's been gathered through guesses + * + * 0: REPORT ID + * 100 for the battery packet + * + * 1: POWER BUTTON + (?) + * Largest bit is 1 when power button pressed + * + * 2: BATTERY CAPACITY + MIC STATUS + * Battery capacity: + * Seems to report ~54 higher than reality when charging + * Capped at 100, charging or not + * Microphone status: + * Largest bit is set to 1 when the mic is physically up + * No bits change when the mic is muted, only when physically moved + * This report is sent every time the mic is moved, no polling required + * + * 3: CONNECTION STATUS + * 16: Wired headset + * 38: Initialising + * 49: Lost connection + * 51: Disconnected, searching + * 52: Disconnected, not searching + * 177: Normal + * + * 4: BATTERY STATUS + * 0: Disconnected + * 1: Normal + * 2: Low + * 3: Critical - sent during shutdown + * 4: Fully charged + * 5: Charging + */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* Receiver report information: (ID 102) */ +/* -------------------------------------------------------------------------- */ +/* + * When queried, the recevier responds with 4 bytes to describe the firmware + * The first 2 bytes are for the receiver, the second 2 are the headset + * The headset firmware version will be 0 if no headset is connected + * + * 0: Recevier firmware major version + * Major version of the receiver's firmware + * + * 1: Recevier firmware minor version + * Minor version of the receiver's firmware + * + * 2: Headset firmware major version + * Major version of the headset's firmware + * + * 3: Headset firmware minor version + * Minor version of the headset's firmware + */ +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hid-ids.h" + +#define CORSAIR_VOID_DEVICE(id, type) { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, (id)), \ + .driver_data = (type) } +#define CORSAIR_VOID_WIRELESS_DEVICE(id) CORSAIR_VOID_DEVICE((id), CORSAIR_VOID_WIRELESS) +#define CORSAIR_VOID_WIRED_DEVICE(id) CORSAIR_VOID_DEVICE((id), CORSAIR_VOID_WIRED) + +#define CORSAIR_VOID_STATUS_REQUEST_ID 0xC9 +#define CORSAIR_VOID_NOTIF_REQUEST_ID 0xCA +#define CORSAIR_VOID_SIDETONE_REQUEST_ID 0xFF +#define CORSAIR_VOID_STATUS_REPORT_ID 0x64 +#define CORSAIR_VOID_FIRMWARE_REPORT_ID 0x66 + +#define CORSAIR_VOID_USB_SIDETONE_REQUEST 0x1 +#define CORSAIR_VOID_USB_SIDETONE_REQUEST_TYPE 0x21 +#define CORSAIR_VOID_USB_SIDETONE_VALUE 0x200 +#define CORSAIR_VOID_USB_SIDETONE_INDEX 0xB00 + +#define CORSAIR_VOID_MIC_MASK GENMASK(7, 7) +#define CORSAIR_VOID_CAPACITY_MASK GENMASK(6, 0) + +#define CORSAIR_VOID_WIRELESS_CONNECTED 177 + +#define CORSAIR_VOID_SIDETONE_MAX_WIRELESS 55 +#define CORSAIR_VOID_SIDETONE_MAX_WIRED 4096 + +enum { + CORSAIR_VOID_WIRELESS, + CORSAIR_VOID_WIRED, +}; + +enum { + CORSAIR_VOID_BATTERY_NORMAL = 1, + CORSAIR_VOID_BATTERY_LOW = 2, + CORSAIR_VOID_BATTERY_CRITICAL = 3, + CORSAIR_VOID_BATTERY_CHARGED = 4, + CORSAIR_VOID_BATTERY_CHARGING = 5, +}; + +static enum power_supply_property corsair_void_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_SCOPE, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +struct corsair_void_battery_data { + int status; + bool present; + int capacity; + int capacity_level; +}; + +struct corsair_void_drvdata { + struct hid_device *hid_dev; + struct device *dev; + + char *name; + bool is_wired; + unsigned int sidetone_max; + + struct corsair_void_battery_data battery_data; + bool mic_up; + bool connected; + int fw_receiver_major; + int fw_receiver_minor; + int fw_headset_major; + int fw_headset_minor; + + struct power_supply *battery; + struct power_supply_desc battery_desc; + struct mutex battery_mutex; + + struct delayed_work delayed_status_work; + struct delayed_work delayed_firmware_work; + struct work_struct battery_remove_work; + struct work_struct battery_add_work; +}; + +/* + * Functions to process receiver data +*/ + +static void corsair_void_set_wireless_status(struct corsair_void_drvdata *drvdata) +{ + struct usb_interface *usb_if = to_usb_interface(drvdata->dev->parent); + + if (drvdata->is_wired) + return; + + usb_set_wireless_status(usb_if, drvdata->connected ? + USB_WIRELESS_STATUS_CONNECTED : + USB_WIRELESS_STATUS_DISCONNECTED); +} + +static void corsair_void_set_unknown_batt(struct corsair_void_drvdata *drvdata) +{ + struct corsair_void_battery_data *battery_data = &drvdata->battery_data; + + battery_data->status = POWER_SUPPLY_STATUS_UNKNOWN; + battery_data->present = false; + battery_data->capacity = 0; + battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; +} + +/* Reset data that may change between wireless connections */ +static void corsair_void_set_unknown_wireless_data(struct corsair_void_drvdata *drvdata) +{ + /* Only 0 out headset, receiver is always known if relevant */ + drvdata->fw_headset_major = 0; + drvdata->fw_headset_minor = 0; + + drvdata->connected = false; + drvdata->mic_up = false; + + corsair_void_set_wireless_status(drvdata); +} + +static void corsair_void_process_receiver(struct corsair_void_drvdata *drvdata, + int raw_battery_capacity, + int raw_connection_status, + int raw_battery_status) +{ + struct corsair_void_battery_data *battery_data = &drvdata->battery_data; + struct corsair_void_battery_data orig_battery_data; + + /* Save initial battery data, to compare later */ + orig_battery_data = *battery_data; + + /* Headset not connected, or it's wired */ + if (raw_connection_status != CORSAIR_VOID_WIRELESS_CONNECTED) + goto unknown_battery; + + /* Battery information unavailable */ + if (raw_battery_status == 0) + goto unknown_battery; + + /* Battery must be connected then */ + battery_data->present = true; + battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; + + /* Set battery status */ + switch (raw_battery_status) { + case CORSAIR_VOID_BATTERY_NORMAL: + case CORSAIR_VOID_BATTERY_LOW: + case CORSAIR_VOID_BATTERY_CRITICAL: + battery_data->status = POWER_SUPPLY_STATUS_DISCHARGING; + if (raw_battery_status == CORSAIR_VOID_BATTERY_LOW) + battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; + else if (raw_battery_status == CORSAIR_VOID_BATTERY_CRITICAL) + battery_data->capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + + break; + case CORSAIR_VOID_BATTERY_CHARGED: + battery_data->status = POWER_SUPPLY_STATUS_FULL; + break; + case CORSAIR_VOID_BATTERY_CHARGING: + battery_data->status = POWER_SUPPLY_STATUS_CHARGING; + break; + default: + hid_warn(drvdata->hid_dev, "unknown battery status '%d'", + raw_battery_status); + goto unknown_battery; + break; + } + + battery_data->capacity = raw_battery_capacity; + corsair_void_set_wireless_status(drvdata); + + goto success; +unknown_battery: + corsair_void_set_unknown_batt(drvdata); +success: + + /* Inform power supply if battery values changed */ + if (memcmp(&orig_battery_data, battery_data, sizeof(*battery_data))) { + scoped_guard(mutex, &drvdata->battery_mutex) { + if (drvdata->battery) { + power_supply_changed(drvdata->battery); + } + } + } +} + +/* + * Functions to report stored data +*/ + +static int corsair_void_battery_get_property(struct power_supply *psy, + enum power_supply_property prop, + union power_supply_propval *val) +{ + struct corsair_void_drvdata *drvdata = power_supply_get_drvdata(psy); + + switch (prop) { + case POWER_SUPPLY_PROP_SCOPE: + val->intval = POWER_SUPPLY_SCOPE_DEVICE; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + if (!strncmp(drvdata->hid_dev->name, "Corsair ", 8)) + val->strval = drvdata->hid_dev->name + 8; + else + val->strval = drvdata->hid_dev->name; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = "Corsair"; + break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = drvdata->battery_data.status; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = drvdata->battery_data.present; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = drvdata->battery_data.capacity; + break; + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: + val->intval = drvdata->battery_data.capacity_level; + break; + default: + return -EINVAL; + } + + return 0; +} + +static ssize_t microphone_up_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); + + if (!drvdata->connected) + return -ENODEV; + + return sysfs_emit(buf, "%d\n", drvdata->mic_up); +} + +static ssize_t fw_version_receiver_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata->fw_receiver_major == 0 && drvdata->fw_receiver_minor == 0) + return -ENODATA; + + return sysfs_emit(buf, "%d.%02d\n", drvdata->fw_receiver_major, + drvdata->fw_receiver_minor); +} + + +static ssize_t fw_version_headset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); + + if (drvdata->fw_headset_major == 0 && drvdata->fw_headset_minor == 0) + return -ENODATA; + + return sysfs_emit(buf, "%d.%02d\n", drvdata->fw_headset_major, + drvdata->fw_headset_minor); +} + +static ssize_t sidetone_max_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", drvdata->sidetone_max); +} + +/* + * Functions to send data to headset +*/ + +static ssize_t send_alert_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); + struct hid_device *hid_dev = drvdata->hid_dev; + unsigned char alert_id; + unsigned char *send_buf __free(kfree) = NULL; + int ret; + + if (!drvdata->connected || drvdata->is_wired) + return -ENODEV; + + /* Only accept 0 or 1 for alert ID */ + if (kstrtou8(buf, 10, &alert_id) || alert_id >= 2) + return -EINVAL; + + send_buf = kmalloc(3, GFP_KERNEL); + if (!send_buf) + return -ENOMEM; + + /* Packet format to send alert with ID alert_id */ + send_buf[0] = CORSAIR_VOID_NOTIF_REQUEST_ID; + send_buf[1] = 0x02; + send_buf[2] = alert_id; + + ret = hid_hw_raw_request(hid_dev, CORSAIR_VOID_NOTIF_REQUEST_ID, + send_buf, 3, HID_OUTPUT_REPORT, + HID_REQ_SET_REPORT); + if (ret < 0) + hid_warn(hid_dev, "failed to send alert request (reason: %d)", + ret); + else + ret = count; + + return ret; +} + +static int corsair_void_set_sidetone_wired(struct device *dev, const char *buf, + unsigned int sidetone) +{ + struct usb_interface *usb_if = to_usb_interface(dev->parent); + struct usb_device *usb_dev = interface_to_usbdev(usb_if); + + /* Packet format to set sidetone for wired headsets */ + __le16 sidetone_le = cpu_to_le16(sidetone); + + return usb_control_msg_send(usb_dev, 0, + CORSAIR_VOID_USB_SIDETONE_REQUEST, + CORSAIR_VOID_USB_SIDETONE_REQUEST_TYPE, + CORSAIR_VOID_USB_SIDETONE_VALUE, + CORSAIR_VOID_USB_SIDETONE_INDEX, + &sidetone_le, 2, USB_CTRL_SET_TIMEOUT, + GFP_KERNEL); +} + +static int corsair_void_set_sidetone_wireless(struct device *dev, + const char *buf, + unsigned char sidetone) +{ + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); + struct hid_device *hid_dev = drvdata->hid_dev; + unsigned char *send_buf __free(kfree) = NULL; + + send_buf = kmalloc(12, GFP_KERNEL); + if (!send_buf) + return -ENOMEM; + + /* Packet format to set sidetone for wireless headsets */ + send_buf[0] = CORSAIR_VOID_SIDETONE_REQUEST_ID; + send_buf[1] = 0x0B; + send_buf[2] = 0x00; + send_buf[3] = 0xFF; + send_buf[4] = 0x04; + send_buf[5] = 0x0E; + send_buf[6] = 0xFF; + send_buf[7] = 0x05; + send_buf[8] = 0x01; + send_buf[9] = 0x04; + send_buf[10] = 0x00; + send_buf[11] = sidetone + 200; + + return hid_hw_raw_request(hid_dev, CORSAIR_VOID_SIDETONE_REQUEST_ID, + send_buf, 12, HID_FEATURE_REPORT, + HID_REQ_SET_REPORT); +} + +static ssize_t set_sidetone_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct corsair_void_drvdata *drvdata = dev_get_drvdata(dev); + struct hid_device *hid_dev = drvdata->hid_dev; + unsigned int sidetone; + int ret; + + if (!drvdata->connected) + return -ENODEV; + + /* sidetone must be between 0 and drvdata->sidetone_max inclusive */ + if (kstrtouint(buf, 10, &sidetone) || sidetone > drvdata->sidetone_max) + return -EINVAL; + + if (drvdata->is_wired) + ret = corsair_void_set_sidetone_wired(dev, buf, sidetone); + else + ret = corsair_void_set_sidetone_wireless(dev, buf, sidetone); + + if (ret < 0) + hid_warn(hid_dev, "failed to send sidetone (reason: %d)", ret); + else + ret = count; + + return ret; +} + +static int corsair_void_request_status(struct hid_device *hid_dev, int id) +{ + unsigned char *send_buf __free(kfree) = NULL; + + send_buf = kmalloc(2, GFP_KERNEL); + if (!send_buf) + return -ENOMEM; + + /* Packet format to request data item (status / firmware) refresh */ + send_buf[0] = CORSAIR_VOID_STATUS_REQUEST_ID; + send_buf[1] = id; + + /* Send request for data refresh */ + return hid_hw_raw_request(hid_dev, CORSAIR_VOID_STATUS_REQUEST_ID, + send_buf, 2, HID_OUTPUT_REPORT, + HID_REQ_SET_REPORT); +} + +/* + * Headset connect / disconnect handlers and work handlers +*/ + +static void corsair_void_status_work_handler(struct work_struct *work) +{ + struct corsair_void_drvdata *drvdata; + struct delayed_work *delayed_work; + int battery_ret; + + delayed_work = container_of(work, struct delayed_work, work); + drvdata = container_of(delayed_work, struct corsair_void_drvdata, + delayed_status_work); + + battery_ret = corsair_void_request_status(drvdata->hid_dev, + CORSAIR_VOID_STATUS_REPORT_ID); + if (battery_ret < 0) { + hid_warn(drvdata->hid_dev, + "failed to request battery (reason: %d)", battery_ret); + } +} + +static void corsair_void_firmware_work_handler(struct work_struct *work) +{ + struct corsair_void_drvdata *drvdata; + struct delayed_work *delayed_work; + int firmware_ret; + + delayed_work = container_of(work, struct delayed_work, work); + drvdata = container_of(delayed_work, struct corsair_void_drvdata, + delayed_firmware_work); + + firmware_ret = corsair_void_request_status(drvdata->hid_dev, + CORSAIR_VOID_FIRMWARE_REPORT_ID); + if (firmware_ret < 0) { + hid_warn(drvdata->hid_dev, + "failed to request firmware (reason: %d)", firmware_ret); + } + +} + +static void corsair_void_battery_remove_work_handler(struct work_struct *work) +{ + struct corsair_void_drvdata *drvdata; + + drvdata = container_of(work, struct corsair_void_drvdata, + battery_remove_work); + scoped_guard(mutex, &drvdata->battery_mutex) { + if (drvdata->battery) { + power_supply_unregister(drvdata->battery); + drvdata->battery = NULL; + } + } +} + +static void corsair_void_battery_add_work_handler(struct work_struct *work) +{ + struct corsair_void_drvdata *drvdata; + struct power_supply_config psy_cfg; + struct power_supply *new_supply; + + drvdata = container_of(work, struct corsair_void_drvdata, + battery_add_work); + guard(mutex)(&drvdata->battery_mutex); + if (drvdata->battery) + return; + + psy_cfg.drv_data = drvdata; + new_supply = power_supply_register(drvdata->dev, + &drvdata->battery_desc, + &psy_cfg); + + if (IS_ERR(new_supply)) { + hid_err(drvdata->hid_dev, + "failed to register battery '%s' (reason: %ld)\n", + drvdata->battery_desc.name, + PTR_ERR(new_supply)); + return; + } + + if (power_supply_powers(new_supply, drvdata->dev)) { + power_supply_unregister(new_supply); + return; + } + + drvdata->battery = new_supply; +} + +static void corsair_void_headset_connected(struct corsair_void_drvdata *drvdata) +{ + schedule_work(&drvdata->battery_add_work); + schedule_delayed_work(&drvdata->delayed_firmware_work, + msecs_to_jiffies(100)); +} + +static void corsair_void_headset_disconnected(struct corsair_void_drvdata *drvdata) +{ + schedule_work(&drvdata->battery_remove_work); + + corsair_void_set_unknown_wireless_data(drvdata); + corsair_void_set_unknown_batt(drvdata); +} + +/* + * Driver setup, probing and HID event handling +*/ + +static DEVICE_ATTR_RO(fw_version_receiver); +static DEVICE_ATTR_RO(fw_version_headset); +static DEVICE_ATTR_RO(microphone_up); +static DEVICE_ATTR_RO(sidetone_max); + +static DEVICE_ATTR_WO(send_alert); +static DEVICE_ATTR_WO(set_sidetone); + +static struct attribute *corsair_void_attrs[] = { + &dev_attr_fw_version_receiver.attr, + &dev_attr_fw_version_headset.attr, + &dev_attr_microphone_up.attr, + &dev_attr_send_alert.attr, + &dev_attr_set_sidetone.attr, + &dev_attr_sidetone_max.attr, + NULL, +}; + +static const struct attribute_group corsair_void_attr_group = { + .attrs = corsair_void_attrs, +}; + +static int corsair_void_probe(struct hid_device *hid_dev, + const struct hid_device_id *hid_id) +{ + int ret; + struct corsair_void_drvdata *drvdata; + char *name; + + if (!hid_is_usb(hid_dev)) + return -EINVAL; + + drvdata = devm_kzalloc(&hid_dev->dev, sizeof(*drvdata), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + hid_set_drvdata(hid_dev, drvdata); + dev_set_drvdata(&hid_dev->dev, drvdata); + + drvdata->dev = &hid_dev->dev; + drvdata->hid_dev = hid_dev; + drvdata->is_wired = hid_id->driver_data == CORSAIR_VOID_WIRED; + + drvdata->sidetone_max = CORSAIR_VOID_SIDETONE_MAX_WIRELESS; + if (drvdata->is_wired) + drvdata->sidetone_max = CORSAIR_VOID_SIDETONE_MAX_WIRED; + + /* Set initial values for no wireless headset attached */ + /* If a headset is attached, it'll be prompted later */ + corsair_void_set_unknown_wireless_data(drvdata); + corsair_void_set_unknown_batt(drvdata); + + /* Receiver version won't be reset after init */ + /* Headset version already set via set_unknown_wireless_data */ + drvdata->fw_receiver_major = 0; + drvdata->fw_receiver_minor = 0; + + ret = hid_parse(hid_dev); + if (ret) { + hid_err(hid_dev, "parse failed (reason: %d)\n", ret); + return ret; + } + + name = devm_kasprintf(drvdata->dev, GFP_KERNEL, + "corsair-void-%d-battery", hid_dev->id); + if (!name) + return -ENOMEM; + + drvdata->battery_desc.name = name; + drvdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; + drvdata->battery_desc.properties = corsair_void_battery_props; + drvdata->battery_desc.num_properties = ARRAY_SIZE(corsair_void_battery_props); + drvdata->battery_desc.get_property = corsair_void_battery_get_property; + + drvdata->battery = NULL; + INIT_WORK(&drvdata->battery_remove_work, + corsair_void_battery_remove_work_handler); + INIT_WORK(&drvdata->battery_add_work, + corsair_void_battery_add_work_handler); + ret = devm_mutex_init(drvdata->dev, &drvdata->battery_mutex); + if (ret) + return ret; + + ret = sysfs_create_group(&hid_dev->dev.kobj, &corsair_void_attr_group); + if (ret) + return ret; + + /* Any failures after here will need to call hid_hw_stop */ + ret = hid_hw_start(hid_dev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(hid_dev, "hid_hw_start failed (reason: %d)\n", ret); + goto failed_after_sysfs; + } + + /* Refresh battery data, in case wireless headset is already connected */ + INIT_DELAYED_WORK(&drvdata->delayed_status_work, + corsair_void_status_work_handler); + schedule_delayed_work(&drvdata->delayed_status_work, + msecs_to_jiffies(100)); + + /* Refresh firmware versions */ + INIT_DELAYED_WORK(&drvdata->delayed_firmware_work, + corsair_void_firmware_work_handler); + schedule_delayed_work(&drvdata->delayed_firmware_work, + msecs_to_jiffies(100)); + + return 0; + +failed_after_sysfs: + sysfs_remove_group(&hid_dev->dev.kobj, &corsair_void_attr_group); + return ret; +} + +static void corsair_void_remove(struct hid_device *hid_dev) +{ + struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); + + hid_hw_stop(hid_dev); + cancel_work_sync(&drvdata->battery_remove_work); + cancel_work_sync(&drvdata->battery_add_work); + if (drvdata->battery) + power_supply_unregister(drvdata->battery); + + cancel_delayed_work_sync(&drvdata->delayed_firmware_work); + sysfs_remove_group(&hid_dev->dev.kobj, &corsair_void_attr_group); +} + +static int corsair_void_raw_event(struct hid_device *hid_dev, + struct hid_report *hid_report, + u8 *data, int size) +{ + struct corsair_void_drvdata *drvdata = hid_get_drvdata(hid_dev); + bool was_connected = drvdata->connected; + + /* Description of packets are documented at the top of this file */ + if (hid_report->id == CORSAIR_VOID_STATUS_REPORT_ID) { + drvdata->mic_up = FIELD_GET(CORSAIR_VOID_MIC_MASK, data[2]); + drvdata->connected = (data[3] == CORSAIR_VOID_WIRELESS_CONNECTED) || + drvdata->is_wired; + + corsair_void_process_receiver(drvdata, + FIELD_GET(CORSAIR_VOID_CAPACITY_MASK, data[2]), + data[3], data[4]); + } else if (hid_report->id == CORSAIR_VOID_FIRMWARE_REPORT_ID) { + drvdata->fw_receiver_major = data[1]; + drvdata->fw_receiver_minor = data[2]; + drvdata->fw_headset_major = data[3]; + drvdata->fw_headset_minor = data[4]; + } + + /* Handle wireless headset connect / disconnect */ + if ((was_connected != drvdata->connected) && !drvdata->is_wired) { + if (drvdata->connected) + corsair_void_headset_connected(drvdata); + else + corsair_void_headset_disconnected(drvdata); + } + + return 0; +} + +static const struct hid_device_id corsair_void_devices[] = { + /* Corsair Void Wireless */ + CORSAIR_VOID_WIRELESS_DEVICE(0x0a0c), + CORSAIR_VOID_WIRELESS_DEVICE(0x0a2b), + CORSAIR_VOID_WIRELESS_DEVICE(0x1b23), + CORSAIR_VOID_WIRELESS_DEVICE(0x1b25), + CORSAIR_VOID_WIRELESS_DEVICE(0x1b27), + + /* Corsair Void USB */ + CORSAIR_VOID_WIRED_DEVICE(0x0a0f), + CORSAIR_VOID_WIRED_DEVICE(0x1b1c), + CORSAIR_VOID_WIRED_DEVICE(0x1b29), + CORSAIR_VOID_WIRED_DEVICE(0x1b2a), + + /* Corsair Void Surround */ + CORSAIR_VOID_WIRED_DEVICE(0x0a30), + CORSAIR_VOID_WIRED_DEVICE(0x0a31), + + /* Corsair Void Pro Wireless */ + CORSAIR_VOID_WIRELESS_DEVICE(0x0a14), + CORSAIR_VOID_WIRELESS_DEVICE(0x0a16), + CORSAIR_VOID_WIRELESS_DEVICE(0x0a1a), + + /* Corsair Void Pro USB */ + CORSAIR_VOID_WIRED_DEVICE(0x0a17), + CORSAIR_VOID_WIRED_DEVICE(0x0a1d), + + /* Corsair Void Pro Surround */ + CORSAIR_VOID_WIRED_DEVICE(0x0a18), + CORSAIR_VOID_WIRED_DEVICE(0x0a1e), + CORSAIR_VOID_WIRED_DEVICE(0x0a1f), + + /* Corsair Void Elite Wireless */ + CORSAIR_VOID_WIRELESS_DEVICE(0x0a51), + CORSAIR_VOID_WIRELESS_DEVICE(0x0a55), + CORSAIR_VOID_WIRELESS_DEVICE(0x0a75), + + /* Corsair Void Elite USB */ + CORSAIR_VOID_WIRED_DEVICE(0x0a52), + CORSAIR_VOID_WIRED_DEVICE(0x0a56), + + /* Corsair Void Elite Surround */ + CORSAIR_VOID_WIRED_DEVICE(0x0a53), + CORSAIR_VOID_WIRED_DEVICE(0x0a57), + + {} +}; + +MODULE_DEVICE_TABLE(hid, corsair_void_devices); + +static struct hid_driver corsair_void_driver = { + .name = "hid-corsair-void", + .id_table = corsair_void_devices, + .probe = corsair_void_probe, + .remove = corsair_void_remove, + .raw_event = corsair_void_raw_event, +}; + +module_hid_driver(corsair_void_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Stuart Hayhurst "); +MODULE_DESCRIPTION("HID driver for Corsair Void headsets"); diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index dae2b84a149088..f4c8d981aa0a86 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -852,7 +852,8 @@ static int cp2112_set_usb_config(struct hid_device *hdev, { int ret; - BUG_ON(cfg->report != CP2112_USB_CONFIG); + if (WARN_ON(cfg->report != CP2112_USB_CONFIG)) + return -EINVAL; ret = cp2112_hid_output(hdev, (u8 *)cfg, sizeof(*cfg), HID_FEATURE_REPORT); diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index d5abfe652fb506..541d682af15aa2 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -3309,9 +3309,9 @@ static const char *keys[KEY_MAX + 1] = { [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", - [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", + [KEY_ANGLE] = "Angle", [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", - [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", + [KEY_PC] = "PC", [KEY_TV] = "TV", [KEY_TV2] = "TV2", [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", @@ -3409,8 +3409,7 @@ static const char *keys[KEY_MAX + 1] = { [BTN_TRIGGER_HAPPY35] = "TriggerHappy35", [BTN_TRIGGER_HAPPY36] = "TriggerHappy36", [BTN_TRIGGER_HAPPY37] = "TriggerHappy37", [BTN_TRIGGER_HAPPY38] = "TriggerHappy38", [BTN_TRIGGER_HAPPY39] = "TriggerHappy39", [BTN_TRIGGER_HAPPY40] = "TriggerHappy40", - [BTN_DIGI] = "Digi", [BTN_STYLUS3] = "Stylus3", - [BTN_TOOL_QUINTTAP] = "ToolQuintTap", [BTN_WHEEL] = "Wheel", + [BTN_STYLUS3] = "Stylus3", [BTN_TOOL_QUINTTAP] = "ToolQuintTap", [KEY_10CHANNELSDOWN] = "10ChannelsDown", [KEY_10CHANNELSUP] = "10ChannelsUp", [KEY_3D_MODE] = "3DMode", [KEY_ADDRESSBOOK] = "Addressbook", @@ -3440,7 +3439,7 @@ static const char *keys[KEY_MAX + 1] = { [KEY_FN_RIGHT_SHIFT] = "FnRightShift", [KEY_FRAMEBACK] = "FrameBack", [KEY_FRAMEFORWARD] = "FrameForward", [KEY_FULL_SCREEN] = "FullScreen", [KEY_GAMES] = "Games", [KEY_GRAPHICSEDITOR] = "GraphicsEditor", - [KEY_HANGEUL] = "HanGeul", [KEY_HANGUP_PHONE] = "HangUpPhone", + [KEY_HANGUP_PHONE] = "HangUpPhone", [KEY_IMAGES] = "Images", [KEY_KBD_LCD_MENU1] = "KbdLcdMenu1", [KEY_KBD_LCD_MENU2] = "KbdLcdMenu2", [KEY_KBD_LCD_MENU3] = "KbdLcdMenu3", [KEY_KBD_LCD_MENU4] = "KbdLcdMenu4", [KEY_KBD_LCD_MENU5] = "KbdLcdMenu5", diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c index d2439399fb357a..9e04c6d0fcc874 100644 --- a/drivers/hid/hid-generic.c +++ b/drivers/hid/hid-generic.c @@ -40,6 +40,9 @@ static bool hid_generic_match(struct hid_device *hdev, if (ignore_special_driver) return true; + if (hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER) + return true; + if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER) return false; diff --git a/drivers/hid/hid-goodix-spi.c b/drivers/hid/hid-goodix-spi.c index 0f87bf9c67cfb6..80c0288a3a38b0 100644 --- a/drivers/hid/hid-goodix-spi.c +++ b/drivers/hid/hid-goodix-spi.c @@ -19,6 +19,8 @@ #define GOODIX_HID_DESC_ADDR 0x1058C #define GOODIX_HID_REPORT_DESC_ADDR 0x105AA #define GOODIX_HID_SIGN_ADDR 0x10D32 +#define GOODIX_HID_CMD_ADDR 0x10364 +#define GOODIX_HID_REPORT_ADDR 0x22C8C #define GOODIX_HID_GET_REPORT_CMD 0x02 #define GOODIX_HID_SET_REPORT_CMD 0x03 @@ -348,7 +350,7 @@ static int goodix_hid_check_ack_status(struct goodix_ts_data *ts, u32 *resp_len) * - byte 0: Ack flag, value of 1 for data ready * - bytes 1-2: Response data length */ - error = goodix_spi_read(ts, ts->hid_report_addr, + error = goodix_spi_read(ts, GOODIX_HID_CMD_ADDR, &hdr, sizeof(hdr)); if (!error && (hdr.flag & GOODIX_HID_ACK_READY_FLAG)) { len = le16_to_cpu(hdr.size); @@ -356,7 +358,7 @@ static int goodix_hid_check_ack_status(struct goodix_ts_data *ts, u32 *resp_len) dev_err(ts->dev, "hrd.size too short: %d", len); return -EINVAL; } - *resp_len = len; + *resp_len = len - GOODIX_HID_PKG_LEN_SIZE; return 0; } @@ -431,7 +433,7 @@ static int goodix_hid_get_raw_report(struct hid_device *hid, tx_len += args_len; /* Step1: write report request info */ - error = goodix_spi_write(ts, ts->hid_report_addr, tmp_buf, tx_len); + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, tmp_buf, tx_len); if (error) { dev_err(ts->dev, "failed send read feature cmd, %d", error); return error; @@ -446,9 +448,12 @@ static int goodix_hid_get_raw_report(struct hid_device *hid, if (error) return error; - len = min(len, response_data_len - GOODIX_HID_PKG_LEN_SIZE); + /* Empty reprot response */ + if (!response_data_len) + return 0; + len = min(len, response_data_len); /* Step3: read response data(skip 2bytes of hid pkg length) */ - error = goodix_spi_read(ts, ts->hid_report_addr + + error = goodix_spi_read(ts, GOODIX_HID_CMD_ADDR + GOODIX_HID_ACK_HEADER_SIZE + GOODIX_HID_PKG_LEN_SIZE, buf, len); if (error) { @@ -518,7 +523,7 @@ static int goodix_hid_set_raw_report(struct hid_device *hid, memcpy(tmp_buf + tx_len, buf, len); tx_len += len; - error = goodix_spi_write(ts, ts->hid_report_addr, tmp_buf, tx_len); + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, tmp_buf, tx_len); if (error) { dev_err(ts->dev, "failed send report: %*ph", tx_len, tmp_buf); return error; @@ -697,12 +702,7 @@ static int goodix_spi_probe(struct spi_device *spi) return dev_err_probe(dev, PTR_ERR(ts->reset_gpio), "failed to request reset gpio\n"); - error = device_property_read_u32(dev, "goodix,hid-report-addr", - &ts->hid_report_addr); - if (error) - return dev_err_probe(dev, error, - "failed get hid report addr\n"); - + ts->hid_report_addr = GOODIX_HID_REPORT_ADDR; error = goodix_dev_confirm(ts); if (error) return error; @@ -749,7 +749,7 @@ static int goodix_spi_set_power(struct goodix_ts_data *ts, int power_state) power_control_cmd[5] = power_state; guard(mutex)(&ts->hid_request_lock); - error = goodix_spi_write(ts, ts->hid_report_addr, power_control_cmd, + error = goodix_spi_write(ts, GOODIX_HID_CMD_ADDR, power_control_cmd, sizeof(power_control_cmd)); if (error) { dev_err(ts->dev, "failed set power mode: %s", @@ -786,6 +786,14 @@ static const struct acpi_device_id goodix_spi_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, goodix_spi_acpi_match); #endif +#ifdef CONFIG_OF +static const struct of_device_id goodix_spi_of_match[] = { + { .compatible = "goodix,gt7986u-spifw", }, + { } +}; +MODULE_DEVICE_TABLE(of, goodix_spi_of_match); +#endif + static const struct spi_device_id goodix_spi_ids[] = { { "gt7986u" }, { }, @@ -796,6 +804,7 @@ static struct spi_driver goodix_spi_driver = { .driver = { .name = "goodix-spi-hid", .acpi_match_table = ACPI_PTR(goodix_spi_acpi_match), + .of_match_table = of_match_ptr(goodix_spi_of_match), .pm = pm_sleep_ptr(&goodix_spi_pm_ops), }, .probe = goodix_spi_probe, diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index 22683ec819aaca..0f292b5d3e26d2 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -284,7 +284,7 @@ MODULE_DEVICE_TABLE(of, cbas_ec_of_match); static struct platform_driver cbas_ec_driver = { .probe = cbas_ec_probe, - .remove_new = cbas_ec_remove, + .remove = cbas_ec_remove, .driver = { .name = "cbas_ec", .acpi_match_table = ACPI_PTR(cbas_ec_acpi_ids), diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index f33485d83d24ff..0fb210e40a4127 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -422,6 +422,25 @@ static int mousevsc_hid_raw_request(struct hid_device *hid, return 0; } +static int mousevsc_hid_probe(struct hid_device *hid_dev, const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hid_dev); + if (ret) { + hid_err(hid_dev, "parse failed\n"); + return ret; + } + + ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); + if (ret) { + hid_err(hid_dev, "hw start failed\n"); + return ret; + } + + return 0; +} + static const struct hid_ll_driver mousevsc_ll_driver = { .parse = mousevsc_hid_parse, .open = mousevsc_hid_open, @@ -431,7 +450,16 @@ static const struct hid_ll_driver mousevsc_ll_driver = { .raw_request = mousevsc_hid_raw_request, }; -static struct hid_driver mousevsc_hid_driver; +static const struct hid_device_id mousevsc_devices[] = { + { HID_DEVICE(BUS_VIRTUAL, HID_GROUP_ANY, 0x045E, 0x0621) }, + { } +}; + +static struct hid_driver mousevsc_hid_driver = { + .name = "hid-hyperv", + .id_table = mousevsc_devices, + .probe = mousevsc_hid_probe, +}; static int mousevsc_probe(struct hv_device *device, const struct hv_vmbus_device_id *dev_id) @@ -473,7 +501,6 @@ static int mousevsc_probe(struct hv_device *device, } hid_dev->ll_driver = &mousevsc_ll_driver; - hid_dev->driver = &mousevsc_hid_driver; hid_dev->bus = BUS_VIRTUAL; hid_dev->vendor = input_dev->hid_dev_info.vendor; hid_dev->product = input_dev->hid_dev_info.product; @@ -488,20 +515,6 @@ static int mousevsc_probe(struct hv_device *device, if (ret) goto probe_err2; - - ret = hid_parse(hid_dev); - if (ret) { - hid_err(hid_dev, "parse failed\n"); - goto probe_err2; - } - - ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); - - if (ret) { - hid_err(hid_dev, "hw start failed\n"); - goto probe_err2; - } - device_init_wakeup(&device->device, true); input_dev->connected = true; @@ -579,12 +592,23 @@ static struct hv_driver mousevsc_drv = { static int __init mousevsc_init(void) { - return vmbus_driver_register(&mousevsc_drv); + int ret; + + ret = hid_register_driver(&mousevsc_hid_driver); + if (ret) + return ret; + + ret = vmbus_driver_register(&mousevsc_drv); + if (ret) + hid_unregister_driver(&mousevsc_hid_driver); + + return ret; } static void __exit mousevsc_exit(void) { vmbus_driver_unregister(&mousevsc_drv); + hid_unregister_driver(&mousevsc_hid_driver); } MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 92cff3f2658cf5..1f47fda809b9a0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -94,6 +94,7 @@ #define USB_DEVICE_ID_APPLE_MAGICMOUSE2 0x0269 #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 0x0265 +#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC 0x0324 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f #define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 @@ -735,6 +736,10 @@ #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2 0x501A #define USB_DEVICE_ID_KYE_PENSKETCH_T609A 0x501B +#define USB_VENDOR_ID_KYSONA 0x3554 +#define USB_DEVICE_ID_KYSONA_M600_DONGLE 0xF57C +#define USB_DEVICE_ID_KYSONA_M600_WIRED 0xF57D + #define USB_VENDOR_ID_LABTEC 0x1020 #define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006 #define USB_DEVICE_ID_LABTEC_ODDOR_HANDBRAKE 0x8888 diff --git a/drivers/hid/hid-kysona.c b/drivers/hid/hid-kysona.c new file mode 100644 index 00000000000000..d4c0406b332358 --- /dev/null +++ b/drivers/hid/hid-kysona.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * USB HID driver for Kysona + * Kysona M600 mice. + * + * Copyright (c) 2024 Lode Willems + */ + +#include +#include +#include + +#include "hid-ids.h" + +#define BATTERY_TIMEOUT_MS 5000 + +#define BATTERY_REPORT_ID 4 + +struct kysona_drvdata { + struct hid_device *hdev; + bool online; + + struct power_supply_desc battery_desc; + struct power_supply *battery; + u8 battery_capacity; + bool battery_charging; + u16 battery_voltage; + struct delayed_work battery_work; +}; + +static enum power_supply_property kysona_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_SCOPE, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_ONLINE +}; + +static int kysona_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct kysona_drvdata *drv_data = power_supply_get_drvdata(psy); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = drv_data->online; + break; + case POWER_SUPPLY_PROP_STATUS: + if (drv_data->online) + val->intval = drv_data->battery_charging ? + POWER_SUPPLY_STATUS_CHARGING : + POWER_SUPPLY_STATUS_DISCHARGING; + else + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + break; + case POWER_SUPPLY_PROP_SCOPE: + val->intval = POWER_SUPPLY_SCOPE_DEVICE; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = drv_data->battery_capacity; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + /* hardware reports voltage in mV. sysfs expects uV */ + val->intval = drv_data->battery_voltage * 1000; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = drv_data->hdev->name; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static const char kysona_battery_request[] = { + 0x08, BATTERY_REPORT_ID, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49 +}; + +static int kysona_m600_fetch_battery(struct hid_device *hdev) +{ + u8 *write_buf; + int ret; + + /* Request battery information */ + write_buf = kmemdup(kysona_battery_request, sizeof(kysona_battery_request), GFP_KERNEL); + if (!write_buf) + return -ENOMEM; + + ret = hid_hw_raw_request(hdev, kysona_battery_request[0], + write_buf, sizeof(kysona_battery_request), + HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); + if (ret < (int)sizeof(kysona_battery_request)) { + hid_err(hdev, "hid_hw_raw_request() failed with %d\n", ret); + ret = -ENODATA; + } + kfree(write_buf); + return ret; +} + +static void kysona_fetch_battery(struct hid_device *hdev) +{ + int ret = kysona_m600_fetch_battery(hdev); + + if (ret < 0) + hid_dbg(hdev, + "Battery query failed (err: %d)\n", ret); +} + +static void kysona_battery_timer_tick(struct work_struct *work) +{ + struct kysona_drvdata *drv_data = container_of(work, + struct kysona_drvdata, battery_work.work); + struct hid_device *hdev = drv_data->hdev; + + kysona_fetch_battery(hdev); + schedule_delayed_work(&drv_data->battery_work, + msecs_to_jiffies(BATTERY_TIMEOUT_MS)); +} + +static int kysona_battery_probe(struct hid_device *hdev) +{ + struct kysona_drvdata *drv_data = hid_get_drvdata(hdev); + struct power_supply_config pscfg = { .drv_data = drv_data }; + int ret = 0; + + drv_data->online = false; + drv_data->battery_capacity = 100; + drv_data->battery_voltage = 4200; + + drv_data->battery_desc.properties = kysona_battery_props; + drv_data->battery_desc.num_properties = ARRAY_SIZE(kysona_battery_props); + drv_data->battery_desc.get_property = kysona_battery_get_property; + drv_data->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY; + drv_data->battery_desc.use_for_apm = 0; + drv_data->battery_desc.name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "kysona-%s-battery", + strlen(hdev->uniq) ? + hdev->uniq : dev_name(&hdev->dev)); + if (!drv_data->battery_desc.name) + return -ENOMEM; + + drv_data->battery = devm_power_supply_register(&hdev->dev, + &drv_data->battery_desc, &pscfg); + if (IS_ERR(drv_data->battery)) { + ret = PTR_ERR(drv_data->battery); + drv_data->battery = NULL; + hid_err(hdev, "Unable to register battery device\n"); + return ret; + } + + power_supply_powers(drv_data->battery, &hdev->dev); + + INIT_DELAYED_WORK(&drv_data->battery_work, kysona_battery_timer_tick); + kysona_fetch_battery(hdev); + schedule_delayed_work(&drv_data->battery_work, + msecs_to_jiffies(BATTERY_TIMEOUT_MS)); + + return ret; +} + +static int kysona_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + struct kysona_drvdata *drv_data; + struct usb_interface *usbif; + + if (!hid_is_usb(hdev)) + return -EINVAL; + + usbif = to_usb_interface(hdev->dev.parent); + + drv_data = devm_kzalloc(&hdev->dev, sizeof(*drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + hid_set_drvdata(hdev, drv_data); + drv_data->hdev = hdev; + + ret = hid_parse(hdev); + if (ret) + return ret; + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + if (ret) + return ret; + + if (usbif->cur_altsetting->desc.bInterfaceNumber == 1) { + if (kysona_battery_probe(hdev) < 0) + hid_err(hdev, "Kysona hid battery_probe failed: %d\n", ret); + } + + return 0; +} + +static int kysona_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) +{ + struct kysona_drvdata *drv_data = hid_get_drvdata(hdev); + + if (drv_data->battery && size == sizeof(kysona_battery_request) && + data[0] == 8 && data[1] == BATTERY_REPORT_ID) { + drv_data->battery_capacity = data[6]; + drv_data->battery_charging = data[7]; + drv_data->battery_voltage = (data[8] << 8) | data[9]; + drv_data->online = true; + } + + return 0; +} + +static void kysona_remove(struct hid_device *hdev) +{ + struct kysona_drvdata *drv_data = hid_get_drvdata(hdev); + + if (drv_data->battery) + cancel_delayed_work_sync(&drv_data->battery_work); + + hid_hw_stop(hdev); +} + +static const struct hid_device_id kysona_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_DONGLE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYSONA, USB_DEVICE_ID_KYSONA_M600_WIRED) }, + { } +}; +MODULE_DEVICE_TABLE(hid, kysona_devices); + +static struct hid_driver kysona_driver = { + .name = "kysona", + .id_table = kysona_devices, + .probe = kysona_probe, + .raw_event = kysona_raw_event, + .remove = kysona_remove +}; +module_hid_driver(kysona_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("HID driver for Kysona devices"); +MODULE_AUTHOR("Lode Willems "); diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index e3fcf1353fb3b7..c0a138f21ca499 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1350,7 +1350,8 @@ int lg4ff_init(struct hid_device *hid) /* Initialize device properties */ if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { - BUG_ON(mmode_idx == -1); + if (WARN_ON(mmode_idx == -1)) + return -EINVAL; mmode_wheel = &lg4ff_multimode_wheels[mmode_idx]; } lg4ff_init_wheel_data(&entry->wdata, &lg4ff_devices[i], mmode_wheel, real_product_id); diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index cf7a6986cf2013..10a3bc5f931b43 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -928,7 +928,7 @@ static int hidpp_unifying_init(struct hidpp_device *hidpp) #define CMD_ROOT_GET_PROTOCOL_VERSION 0x10 static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature, - u8 *feature_index, u8 *feature_type) + u8 *feature_index) { struct hidpp_report response; int ret; @@ -945,7 +945,6 @@ static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature, return -ENOENT; *feature_index = response.fap.params[0]; - *feature_type = response.fap.params[1]; return ret; } @@ -1012,13 +1011,11 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp) static int hidpp_get_serial(struct hidpp_device *hidpp, u32 *serial) { struct hidpp_report response; - u8 feature_type; u8 feature_index; int ret; ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_DEVICE_INFORMATION, - &feature_index, - &feature_type); + &feature_index); if (ret) return ret; @@ -1125,7 +1122,6 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp, static char *hidpp_get_device_name(struct hidpp_device *hidpp) { - u8 feature_type; u8 feature_index; u8 __name_length; char *name; @@ -1133,7 +1129,7 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp) int ret; ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_GET_DEVICE_NAME_TYPE, - &feature_index, &feature_type); + &feature_index); if (ret) return NULL; @@ -1300,15 +1296,13 @@ static int hidpp20_batterylevel_get_battery_info(struct hidpp_device *hidpp, static int hidpp20_query_battery_info_1000(struct hidpp_device *hidpp) { - u8 feature_type; int ret; int status, capacity, next_capacity, level; if (hidpp->battery.feature_index == 0xff) { ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_BATTERY_LEVEL_STATUS, - &hidpp->battery.feature_index, - &feature_type); + &hidpp->battery.feature_index); if (ret) return ret; } @@ -1489,14 +1483,12 @@ static int hidpp20_map_battery_capacity(struct hid_device *hid_dev, int voltage) static int hidpp20_query_battery_voltage_info(struct hidpp_device *hidpp) { - u8 feature_type; int ret; int status, voltage, level, charge_type; if (hidpp->battery.voltage_feature_index == 0xff) { ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_BATTERY_VOLTAGE, - &hidpp->battery.voltage_feature_index, - &feature_type); + &hidpp->battery.voltage_feature_index); if (ret) return ret; } @@ -1692,7 +1684,6 @@ static int hidpp20_unifiedbattery_get_status(struct hidpp_device *hidpp, static int hidpp20_query_battery_info_1004(struct hidpp_device *hidpp) { - u8 feature_type; int ret; u8 state_of_charge; int status, level; @@ -1700,8 +1691,7 @@ static int hidpp20_query_battery_info_1004(struct hidpp_device *hidpp) if (hidpp->battery.feature_index == 0xff) { ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_UNIFIED_BATTERY, - &hidpp->battery.feature_index, - &feature_type); + &hidpp->battery.feature_index); if (ret) return ret; } @@ -1834,14 +1824,9 @@ static int hidpp_battery_get_property(struct power_supply *psy, static int hidpp_get_wireless_feature_index(struct hidpp_device *hidpp, u8 *feature_index) { - u8 feature_type; - int ret; - - ret = hidpp_root_get_feature(hidpp, - HIDPP_PAGE_WIRELESS_DEVICE_STATUS, - feature_index, &feature_type); - - return ret; + return hidpp_root_get_feature(hidpp, + HIDPP_PAGE_WIRELESS_DEVICE_STATUS, + feature_index); } /* -------------------------------------------------------------------------- */ @@ -1952,14 +1937,11 @@ static bool hidpp20_get_adc_measurement_1f20(struct hidpp_device *hidpp, static int hidpp20_query_adc_measurement_info_1f20(struct hidpp_device *hidpp) { - u8 feature_type; - if (hidpp->battery.adc_measurement_feature_index == 0xff) { int ret; ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_ADC_MEASUREMENT, - &hidpp->battery.adc_measurement_feature_index, - &feature_type); + &hidpp->battery.adc_measurement_feature_index); if (ret) return ret; @@ -2014,15 +1996,13 @@ static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp, bool enabled, u8 *multiplier) { u8 feature_index; - u8 feature_type; int ret; u8 params[1]; struct hidpp_report response; ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HI_RESOLUTION_SCROLLING, - &feature_index, - &feature_type); + &feature_index); if (ret) return ret; @@ -2049,12 +2029,11 @@ static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, u8 *multiplier) { u8 feature_index; - u8 feature_type; int ret; struct hidpp_report response; ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, - &feature_index, &feature_type); + &feature_index); if (ret) goto return_default; @@ -2076,13 +2055,12 @@ static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert, bool high_resolution, bool use_hidpp) { u8 feature_index; - u8 feature_type; int ret; u8 params[1]; struct hidpp_report response; ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, - &feature_index, &feature_type); + &feature_index); if (ret) return ret; @@ -2111,14 +2089,12 @@ static int hidpp_solar_request_battery_event(struct hidpp_device *hidpp) { struct hidpp_report response; u8 params[2] = { 1, 1 }; - u8 feature_type; int ret; if (hidpp->battery.feature_index == 0xff) { ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_SOLAR_KEYBOARD, - &hidpp->battery.solar_feature_index, - &feature_type); + &hidpp->battery.solar_feature_index); if (ret) return ret; } @@ -2522,7 +2498,7 @@ static void hidpp_ff_work_handler(struct work_struct *w) /* regular effect destroyed */ data->effect_ids[wd->params[0]-1] = -1; else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER) - /* autocenter spring destoyed */ + /* autocenter spring destroyed */ data->slot_autocenter = 0; break; case HIDPP_FF_SET_GLOBAL_GAINS: @@ -3098,11 +3074,10 @@ static int wtp_get_config(struct hidpp_device *hidpp) { struct wtp_data *wd = hidpp->private_data; struct hidpp_touchpad_raw_info raw_info = {0}; - u8 feature_type; int ret; ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_TOUCHPAD_RAW_XY, - &wd->mt_feature_index, &feature_type); + &wd->mt_feature_index); if (ret) /* means that the device is not powered up */ return ret; @@ -3296,13 +3271,13 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) 120); } - v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); + v = sign_extend32(hid_field_extract(hdev, data + 3, 0, 12), 11); input_report_rel(hidpp->input, REL_X, v); - v = hid_snto32(hid_field_extract(hdev, data+3, 12, 12), 12); + v = sign_extend32(hid_field_extract(hdev, data + 3, 12, 12), 11); input_report_rel(hidpp->input, REL_Y, v); - v = hid_snto32(data[6], 8); + v = sign_extend32(data[6], 7); if (v != 0) hidpp_scroll_counter_handle_scroll(hidpp->input, &hidpp->vertical_wheel_counter, v); @@ -3362,12 +3337,11 @@ static int k400_disable_tap_to_click(struct hidpp_device *hidpp) struct k400_private_data *k400 = hidpp->private_data; struct hidpp_touchpad_fw_items items = {}; int ret; - u8 feature_type; if (!k400->feature_index) { ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_TOUCHPAD_FW_ITEMS, - &k400->feature_index, &feature_type); + &k400->feature_index); if (ret) /* means that the device is not powered up */ return ret; @@ -3439,14 +3413,13 @@ static int g920_get_config(struct hidpp_device *hidpp, struct hidpp_ff_private_data *data) { struct hidpp_report response; - u8 feature_type; int ret; memset(data, 0, sizeof(*data)); /* Find feature and store for later use */ ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK, - &data->feature_index, &feature_type); + &data->feature_index); if (ret) return ret; @@ -3735,17 +3708,16 @@ static int hidpp_initialize_hires_scroll(struct hidpp_device *hidpp) if (hidpp->protocol_major >= 2) { u8 feature_index; - u8 feature_type; ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, - &feature_index, &feature_type); + &feature_index); if (!ret) { hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL; hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scroll wheel\n"); return 0; } ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HI_RESOLUTION_SCROLLING, - &feature_index, &feature_type); + &feature_index); if (!ret) { hidpp->capabilities |= HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL; hid_dbg(hidpp->hid_dev, "Detected HID++ 2.0 hi-res scrolling\n"); diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 8a73b59e0827b9..ec110dea87726d 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -227,7 +227,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda touch_minor = tdata[4]; state = tdata[7] & TOUCH_STATE_MASK; down = state != TOUCH_STATE_NONE; - } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + input->id.product == + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { id = tdata[8] & 0xf; x = (tdata[1] << 27 | tdata[0] << 19) >> 19; y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19); @@ -259,8 +261,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda /* If requested, emulate a scroll wheel by detecting small * vertical touch motions. */ - if (emulate_scroll_wheel && (input->id.product != - USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) { + if (emulate_scroll_wheel && + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { unsigned long now = jiffies; int step_x = msc->touches[id].scroll_x - x; int step_y = msc->touches[id].scroll_y - y; @@ -359,7 +362,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); - if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) + if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + input->id.product == + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) input_report_abs(input, ABS_MT_PRESSURE, pressure); if (report_undeciphered) { @@ -367,7 +372,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) input_event(input, EV_MSC, MSC_RAW, tdata[7]); else if (input->id.product != - USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && + input->id.product != + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) input_event(input, EV_MSC, MSC_RAW, tdata[8]); } } @@ -493,7 +500,9 @@ static int magicmouse_raw_event(struct hid_device *hdev, magicmouse_emit_buttons(msc, clicks & 3); input_report_rel(input, REL_X, x); input_report_rel(input, REL_Y, y); - } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + input->id.product == + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { input_mt_sync_frame(input); input_report_key(input, BTN_MOUSE, clicks & 1); } else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */ @@ -545,7 +554,9 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd __set_bit(REL_WHEEL_HI_RES, input->relbit); __set_bit(REL_HWHEEL_HI_RES, input->relbit); } - } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + input->id.product == + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { /* If the trackpad has been connected to a Mac, the name is * automatically personalized, e.g., "José Expósito's Trackpad". * When connected through Bluetooth, the personalized name is @@ -621,7 +632,9 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd MOUSE_RES_X); input_abs_set_res(input, ABS_MT_POSITION_Y, MOUSE_RES_Y); - } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + } else if (input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + input->id.product == + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { input_set_abs_params(input, ABS_MT_PRESSURE, 0, 253, 0, 0); input_set_abs_params(input, ABS_PRESSURE, 0, 253, 0, 0); input_set_abs_params(input, ABS_MT_ORIENTATION, -3, 4, 0, 0); @@ -660,7 +673,8 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd input_set_events_per_packet(input, 60); if (report_undeciphered && - input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && + input->id.product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { __set_bit(EV_MSC, input->evbit); __set_bit(MSC_RAW, input->mscbit); } @@ -685,7 +699,9 @@ static int magicmouse_input_mapping(struct hid_device *hdev, /* Magic Trackpad does not give relative data after switching to MT */ if ((hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD || - hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && + hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + hi->input->id.product == + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) && field->flags & HID_MAIN_ITEM_RELATIVE) return -1; @@ -721,7 +737,8 @@ static int magicmouse_enable_multitouch(struct hid_device *hdev) int ret; int feature_size; - if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + if (hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { if (hdev->vendor == BT_VENDOR_ID_APPLE) { feature_size = sizeof(feature_mt_trackpad2_bt); feature = feature_mt_trackpad2_bt; @@ -766,7 +783,8 @@ static int magicmouse_fetch_battery(struct hid_device *hdev) if (!hdev->battery || hdev->vendor != USB_VENDOR_ID_APPLE || (hdev->product != USB_DEVICE_ID_APPLE_MAGICMOUSE2 && - hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2)) + hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && + hdev->product != USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC)) return -1; report_enum = &hdev->report_enum[hdev->battery_report_type]; @@ -835,7 +853,9 @@ static int magicmouse_probe(struct hid_device *hdev, if (id->vendor == USB_VENDOR_ID_APPLE && (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || - (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 && hdev->type != HID_TYPE_USBMOUSE))) + ((id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) && + hdev->type != HID_TYPE_USBMOUSE))) return 0; if (!msc->input) { @@ -850,7 +870,8 @@ static int magicmouse_probe(struct hid_device *hdev, else if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2) report = hid_register_report(hdev, HID_INPUT_REPORT, MOUSE2_REPORT_ID, 0); - else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) { + else if (id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + id->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) { if (id->vendor == BT_VENDOR_ID_APPLE) report = hid_register_report(hdev, HID_INPUT_REPORT, TRACKPAD2_BT_REPORT_ID, 0); @@ -920,7 +941,8 @@ static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc, */ if (hdev->vendor == USB_VENDOR_ID_APPLE && (hdev->product == USB_DEVICE_ID_APPLE_MAGICMOUSE2 || - hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2) && + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2 || + hdev->product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC) && *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) { hid_info(hdev, "fixing up magicmouse battery report descriptor\n"); @@ -951,6 +973,10 @@ static const struct hid_device_id magic_mice[] = { USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD2), .driver_data = 0 }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_MAGICTRACKPAD2_USBC), .driver_data = 0 }, { } }; MODULE_DEVICE_TABLE(hid, magic_mice); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index e936019d21fecf..785743036647ca 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -31,6 +31,7 @@ * [1] https://gitlab.freedesktop.org/libevdev/hid-tools */ +#include #include #include #include @@ -83,6 +84,13 @@ enum latency_mode { HID_LATENCY_HIGH = 1, }; +enum report_mode { + TOUCHPAD_REPORT_NONE = 0, + TOUCHPAD_REPORT_BUTTONS = BIT(0), + TOUCHPAD_REPORT_CONTACTS = BIT(1), + TOUCHPAD_REPORT_ALL = TOUCHPAD_REPORT_BUTTONS | TOUCHPAD_REPORT_CONTACTS, +}; + #define MT_IO_FLAGS_RUNNING 0 #define MT_IO_FLAGS_ACTIVE_SLOTS 1 #define MT_IO_FLAGS_PENDING_SLOTS 2 @@ -1493,8 +1501,7 @@ static bool mt_need_to_apply_feature(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, enum latency_mode latency, - bool surface_switch, - bool button_switch, + enum report_mode report_mode, bool *inputmode_found) { struct mt_device *td = hid_get_drvdata(hdev); @@ -1549,11 +1556,11 @@ static bool mt_need_to_apply_feature(struct hid_device *hdev, return true; case HID_DG_SURFACESWITCH: - field->value[index] = surface_switch; + field->value[index] = !!(report_mode & TOUCHPAD_REPORT_CONTACTS); return true; case HID_DG_BUTTONSWITCH: - field->value[index] = button_switch; + field->value[index] = !!(report_mode & TOUCHPAD_REPORT_BUTTONS); return true; } @@ -1561,7 +1568,7 @@ static bool mt_need_to_apply_feature(struct hid_device *hdev, } static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency, - bool surface_switch, bool button_switch) + enum report_mode report_mode) { struct hid_report_enum *rep_enum; struct hid_report *rep; @@ -1586,8 +1593,7 @@ static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency, rep->field[i], usage, latency, - surface_switch, - button_switch, + report_mode, &inputmode_found)) update_report = true; } @@ -1830,7 +1836,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) dev_warn(&hdev->dev, "Cannot allocate sysfs group for %s\n", hdev->name); - mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); return 0; } @@ -1842,9 +1848,9 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) /* High latency is desirable for power savings during S3/S0ix */ if ((td->mtclass.quirks & MT_QUIRK_DISABLE_WAKEUP) || !hid_hw_may_wakeup(hdev)) - mt_set_modes(hdev, HID_LATENCY_HIGH, false, false); + mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE); else - mt_set_modes(hdev, HID_LATENCY_HIGH, true, true); + mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_ALL); return 0; } @@ -1852,7 +1858,7 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) static int mt_reset_resume(struct hid_device *hdev) { mt_release_contacts(hdev); - mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); return 0; } @@ -1864,7 +1870,7 @@ static int mt_resume(struct hid_device *hdev) hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE); - mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); + mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL); return 0; } diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c index 83e3409d170c84..8c28e982e09d7a 100644 --- a/drivers/hid/hid-picolcd_fb.c +++ b/drivers/hid/hid-picolcd_fb.c @@ -296,7 +296,7 @@ static void picolcd_fb_destroy(struct fb_info *info) /* make sure no work is deferred */ fb_deferred_io_cleanup(info); - /* No thridparty should ever unregister our framebuffer! */ + /* No thirdparty should ever unregister our framebuffer! */ WARN_ON(fbdata->picolcd != NULL); vfree((u8 *)info->fix.smem_start); @@ -497,6 +497,10 @@ int picolcd_init_framebuffer(struct picolcd_data *data) #endif #endif +#ifdef CONFIG_HID_PICOLCD_LCD + info->lcd_dev = data->lcd; +#endif + fbdata = info->par; spin_lock_init(&fbdata->lock); fbdata->picolcd = data; diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c index 061a33ba7b1db9..318f19eac0e72f 100644 --- a/drivers/hid/hid-picolcd_lcd.c +++ b/drivers/hid/hid-picolcd_lcd.c @@ -41,15 +41,9 @@ static int picolcd_set_contrast(struct lcd_device *ldev, int contrast) return 0; } -static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb) -{ - return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev)); -} - static const struct lcd_ops picolcd_lcdops = { .get_contrast = picolcd_get_contrast, .set_contrast = picolcd_set_contrast, - .check_fb = picolcd_check_lcd_fb, }; int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report) diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c index 66f0675df24bdb..761760668f6d90 100644 --- a/drivers/hid/hid-sensor-custom.c +++ b/drivers/hid/hid-sensor-custom.c @@ -946,7 +946,7 @@ hid_sensor_register_platform_device(struct platform_device *pdev, memcpy(real_usage, match->luid, 4); - /* usage id are all lowcase */ + /* usage id are all lowercase */ for (c = real_usage; *c != '\0'; c++) *c = tolower(*c); @@ -1065,7 +1065,7 @@ static struct platform_driver hid_sensor_custom_platform_driver = { .name = KBUILD_MODNAME, }, .probe = hid_sensor_custom_probe, - .remove_new = hid_sensor_custom_remove, + .remove = hid_sensor_custom_remove, }; module_platform_driver(hid_sensor_custom_platform_driver); diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index d2486f3734f002..5258b45684e8d3 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1379,7 +1379,8 @@ static int sony_leds_init(struct sony_sc *sc) u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 }; u8 use_hw_blink[MAX_LEDS] = { 0 }; - BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); + if (WARN_ON(!(sc->quirks & SONY_LED_SUPPORT))) + return -EINVAL; if (sc->quirks & BUZZ_CONTROLLER) { sc->led_count = 4; diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c index bf8b633114be6a..6439913372a8a9 100644 --- a/drivers/hid/hid-steam.c +++ b/drivers/hid/hid-steam.c @@ -253,7 +253,7 @@ enum ID_CONTROLLER_DECK_STATE = 9 }; -/* String attribute idenitifiers */ +/* String attribute identifiers */ enum { ATTRIB_STR_BOARD_SERIAL, ATTRIB_STR_UNIT_SERIAL, diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c index 7e83fee1ffa043..f9ff5be9430962 100644 --- a/drivers/hid/hid-steelseries.c +++ b/drivers/hid/hid-steelseries.c @@ -411,6 +411,15 @@ static void steelseries_headset_fetch_battery(struct hid_device *hdev) "Battery query failed (err: %d)\n", ret); } +static int battery_capacity_to_level(int capacity) +{ + if (capacity >= 50) + return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; + if (capacity >= 20) + return POWER_SUPPLY_CAPACITY_LEVEL_LOW; + return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; +} + static void steelseries_headset_battery_timer_tick(struct work_struct *work) { struct steelseries_device *sd = container_of(work, @@ -442,6 +451,9 @@ static int steelseries_headset_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: val->intval = sd->battery_capacity; break; + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: + val->intval = battery_capacity_to_level(sd->battery_capacity); + break; default: ret = -EINVAL; break; @@ -469,6 +481,7 @@ static enum power_supply_property steelseries_headset_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, }; static int steelseries_headset_battery_register(struct steelseries_device *sd) @@ -603,8 +616,11 @@ static int steelseries_headset_raw_event(struct hid_device *hdev, hid_dbg(sd->hdev, "Parsing raw event for Arctis 1 headset (%*ph)\n", size, read_buf); if (size < ARCTIS_1_BATTERY_RESPONSE_LEN || - memcmp (read_buf, arctis_1_battery_request, sizeof(arctis_1_battery_request))) + memcmp(read_buf, arctis_1_battery_request, sizeof(arctis_1_battery_request))) { + if (!delayed_work_pending(&sd->battery_work)) + goto request_battery; return 0; + } if (read_buf[2] == 0x01) { connected = false; capacity = 100; @@ -631,6 +647,7 @@ static int steelseries_headset_raw_event(struct hid_device *hdev, power_supply_changed(sd->battery); } +request_battery: spin_lock_irqsave(&sd->lock, flags); if (!sd->removed) schedule_delayed_work(&sd->battery_work, diff --git a/drivers/hid/hid-uclogic-rdesc-test.c b/drivers/hid/hid-uclogic-rdesc-test.c index d6b18213f45f2c..066df622b6f2e4 100644 --- a/drivers/hid/hid-uclogic-rdesc-test.c +++ b/drivers/hid/hid-uclogic-rdesc-test.c @@ -9,7 +9,7 @@ #include #include "./hid-uclogic-rdesc.h" -MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); struct uclogic_template_case { const char *name; diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 43664a24176fca..4e87380d3edd6b 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -414,7 +414,19 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state) i2c_hid_dbg(ihid, "%s\n", __func__); + /* + * Some STM-based devices need 400µs after a rising clock edge to wake + * from deep sleep, in which case the first request will fail due to + * the address not being acknowledged. Try after a short sleep to see + * if the device came alive on the bus. Certain Weida Tech devices also + * need this. + */ ret = i2c_hid_set_power_command(ihid, power_state); + if (ret && power_state == I2C_HID_PWR_ON) { + usleep_range(400, 500); + ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON); + } + if (ret) dev_err(&ihid->client->dev, "failed to change power setting.\n"); @@ -976,14 +988,6 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid) enable_irq(client->irq); - /* Make sure the device is awake on the bus */ - ret = i2c_hid_probe_address(ihid); - if (ret < 0) { - dev_err(&client->dev, "nothing at address after resume: %d\n", - ret); - return -ENXIO; - } - /* On Goodix 27c6:0d42 wait extra time before device wakeup. * It's not clear why but if we send wakeup too early, the device will * never trigger input interrupts. diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c index 8be4d576da7733..57379b77e9778f 100644 --- a/drivers/hid/i2c-hid/i2c-hid-of.c +++ b/drivers/hid/i2c-hid/i2c-hid-of.c @@ -144,9 +144,9 @@ MODULE_DEVICE_TABLE(of, i2c_hid_of_match); #endif static const struct i2c_device_id i2c_hid_of_id_table[] = { - { "hid", 0 }, - { "hid-over-i2c", 0 }, - { }, + { "hid" }, + { "hid-over-i2c" }, + { } }; MODULE_DEVICE_TABLE(i2c, i2c_hid_of_id_table); diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index aae0d965b47b5e..9e2401291a2f67 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -381,6 +381,50 @@ static int __maybe_unused ish_resume(struct device *device) static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume); +static ssize_t base_version_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct ishtp_device *dev = dev_get_drvdata(cdev); + + return sysfs_emit(buf, "%u.%u.%u.%u\n", dev->base_ver.major, + dev->base_ver.minor, dev->base_ver.hotfix, + dev->base_ver.build); +} +static DEVICE_ATTR_RO(base_version); + +static ssize_t project_version_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct ishtp_device *dev = dev_get_drvdata(cdev); + + return sysfs_emit(buf, "%u.%u.%u.%u\n", dev->prj_ver.major, + dev->prj_ver.minor, dev->prj_ver.hotfix, + dev->prj_ver.build); +} +static DEVICE_ATTR_RO(project_version); + +static struct attribute *ish_firmware_attrs[] = { + &dev_attr_base_version.attr, + &dev_attr_project_version.attr, + NULL +}; + +static umode_t firmware_is_visible(struct kobject *kobj, struct attribute *attr, + int i) +{ + struct ishtp_device *dev = dev_get_drvdata(kobj_to_dev(kobj)); + + return dev->driver_data->fw_generation ? attr->mode : 0; +} + +static const struct attribute_group ish_firmware_group = { + .name = "firmware", + .attrs = ish_firmware_attrs, + .is_visible = firmware_is_visible, +}; + +__ATTRIBUTE_GROUPS(ish_firmware); + static struct pci_driver ish_driver = { .name = KBUILD_MODNAME, .id_table = ish_pci_tbl, @@ -388,6 +432,7 @@ static struct pci_driver ish_driver = { .remove = ish_remove, .shutdown = ish_shutdown, .driver.pm = &ish_pm_ops, + .dev_groups = ish_firmware_groups, }; module_pci_driver(ish_driver); diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c index b3c3cfcd97fc54..f4a671d6386ce5 100644 --- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c +++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c @@ -793,7 +793,7 @@ static int load_fw_from_host(struct ishtp_cl_data *client_data) if (rv < 0) goto end_err_fw_release; - /* Step 3: Start ISH main firmware exeuction */ + /* Step 3: Start ISH main firmware execution */ rv = ish_fw_start(client_data); if (rv < 0) diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index fbd4f8ea1951b8..cb04cd1d980bd0 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -70,10 +70,10 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, unsigned char *payload; struct device_info *dev_info; int i, j; - size_t payload_len, total_len, cur_pos, raw_len; + size_t payload_len, total_len, cur_pos, raw_len, msg_len; int report_type; struct report_list *reports_list; - char *reports; + struct report *report; size_t report_len; struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl); int curr_hid_dev = client_data->cur_hid_dev; @@ -280,14 +280,13 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, case HOSTIF_PUBLISH_INPUT_REPORT_LIST: report_type = HID_INPUT_REPORT; reports_list = (struct report_list *)payload; - reports = (char *)reports_list->reports; + report = reports_list->reports; for (j = 0; j < reports_list->num_of_reports; j++) { - recv_msg = (struct hostif_msg *)(reports + - sizeof(uint16_t)); - report_len = *(uint16_t *)reports; - payload = reports + sizeof(uint16_t) + - sizeof(struct hostif_msg_hdr); + recv_msg = container_of(&report->msg, + struct hostif_msg, hdr); + report_len = report->size; + payload = recv_msg->payload; payload_len = report_len - sizeof(struct hostif_msg_hdr); @@ -304,7 +303,7 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, 0); } - reports += sizeof(uint16_t) + report_len; + report += sizeof(*report) + payload_len; } break; default: @@ -316,12 +315,12 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, } - if (!cur_pos && cur_pos + payload_len + - sizeof(struct hostif_msg) < total_len) + msg_len = payload_len + sizeof(struct hostif_msg); + if (!cur_pos && cur_pos + msg_len < total_len) ++client_data->multi_packet_cnt; - cur_pos += payload_len + sizeof(struct hostif_msg); - payload += payload_len + sizeof(struct hostif_msg); + cur_pos += msg_len; + payload += msg_len; } while (cur_pos < total_len); } diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.h b/drivers/hid/intel-ish-hid/ishtp-hid.h index 35dddc5015b378..2bc19e8ba13e4d 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid.h +++ b/drivers/hid/intel-ish-hid/ishtp-hid.h @@ -31,6 +31,7 @@ struct hostif_msg_hdr { struct hostif_msg { struct hostif_msg_hdr hdr; + uint8_t payload[]; } __packed; struct hostif_msg_to_sensor { @@ -52,15 +53,17 @@ struct ishtp_version { uint16_t build; } __packed; +struct report { + uint16_t size; + struct hostif_msg_hdr msg; +} __packed; + /* struct for ISHTP aggregated input data */ struct report_list { uint16_t total_size; uint8_t num_of_reports; uint8_t flags; - struct { - uint16_t size_of_report; - uint8_t report[1]; - } __packed reports[1]; + struct report reports[]; } __packed; /* HOSTIF commands */ diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c index 8a7f2f6a4f8686..e61b01e9902ec6 100644 --- a/drivers/hid/intel-ish-hid/ishtp/client.c +++ b/drivers/hid/intel-ish-hid/ishtp/client.c @@ -863,7 +863,7 @@ static void ipc_tx_send(void *prm) /* Send ipc fragment */ ishtp_hdr.length = dev->mtu; ishtp_hdr.msg_complete = 0; - /* All fregments submitted to IPC queue with no callback */ + /* All fragments submitted to IPC queue with no callback */ ishtp_write_message(dev, &ishtp_hdr, pmsg); cl->tx_offs += dev->mtu; rem = cl_msg->send_buf.size - cl->tx_offs; diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h index cdacce0a4c9d7d..effbb442c72776 100644 --- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h +++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h @@ -140,6 +140,13 @@ struct ishtp_driver_data { char *fw_generation; }; +struct ish_version { + u16 major; + u16 minor; + u16 hotfix; + u16 build; +}; + /** * struct ishtp_device - ISHTP private device struct */ @@ -236,6 +243,11 @@ struct ishtp_device { /* Dump to trace buffers if enabled*/ ishtp_print_log print_log; + /* Base version of Intel's released firmware */ + struct ish_version base_ver; + /* Vendor-customized project version */ + struct ish_version prj_ver; + /* Debug stats */ unsigned int ipc_rx_cnt; unsigned long long ipc_rx_bytes_cnt; diff --git a/drivers/hid/intel-ish-hid/ishtp/loader.c b/drivers/hid/intel-ish-hid/ishtp/loader.c index f76c4437a1f5f1..f34086b29cf08a 100644 --- a/drivers/hid/intel-ish-hid/ishtp/loader.c +++ b/drivers/hid/intel-ish-hid/ishtp/loader.c @@ -308,6 +308,28 @@ static int request_ish_firmware(const struct firmware **firmware_p, return _request_ish_firmware(firmware_p, filename, dev); } +static int copy_manifest(const struct firmware *fw, struct ish_global_manifest *manifest) +{ + u32 offset; + + for (offset = 0; offset + sizeof(*manifest) < fw->size; offset += ISH_MANIFEST_ALIGNMENT) { + memcpy(manifest, fw->data + offset, sizeof(*manifest)); + + if (le32_to_cpu(manifest->sig_fourcc) == ISH_GLOBAL_SIG) + return 0; + } + + return -1; +} + +static void copy_ish_version(struct version_in_manifest *src, struct ish_version *dst) +{ + dst->major = le16_to_cpu(src->major); + dst->minor = le16_to_cpu(src->minor); + dst->hotfix = le16_to_cpu(src->hotfix); + dst->build = le16_to_cpu(src->build); +} + /** * ishtp_loader_work() - Load the ISHTP firmware * @work: The work structure @@ -336,6 +358,7 @@ void ishtp_loader_work(struct work_struct *work) struct loader_xfer_query query = { .header = cpu_to_le32(query_hdr.val32), }; struct loader_start start = { .header = cpu_to_le32(start_hdr.val32), }; union loader_recv_message recv_msg; + struct ish_global_manifest manifest; const struct firmware *ish_fw; void *dma_bufs[FRAGMENT_MAX_NUM] = {}; u32 fragment_size; @@ -372,7 +395,7 @@ void ishtp_loader_work(struct work_struct *work) if (rv) continue; /* try again if failed */ - dev_dbg(dev->devc, "ISH Version %u.%u.%u.%u\n", + dev_dbg(dev->devc, "ISH Bootloader Version %u.%u.%u.%u\n", recv_msg.query_ack.version_major, recv_msg.query_ack.version_minor, recv_msg.query_ack.version_hotfix, @@ -390,6 +413,16 @@ void ishtp_loader_work(struct work_struct *work) continue; /* try again if failed */ dev_info(dev->devc, "firmware loaded. size:%zu\n", ish_fw->size); + if (!copy_manifest(ish_fw, &manifest)) { + copy_ish_version(&manifest.base_ver, &dev->base_ver); + copy_ish_version(&manifest.prj_ver, &dev->prj_ver); + dev_info(dev->devc, "FW base version: %u.%u.%u.%u\n", + dev->base_ver.major, dev->base_ver.minor, + dev->base_ver.hotfix, dev->base_ver.build); + dev_info(dev->devc, "FW project version: %u.%u.%u.%u\n", + dev->prj_ver.major, dev->prj_ver.minor, + dev->prj_ver.hotfix, dev->prj_ver.build); + } break; } while (--retry); diff --git a/drivers/hid/intel-ish-hid/ishtp/loader.h b/drivers/hid/intel-ish-hid/ishtp/loader.h index 308b96085a4db4..4dda038b494708 100644 --- a/drivers/hid/intel-ish-hid/ishtp/loader.h +++ b/drivers/hid/intel-ish-hid/ishtp/loader.h @@ -10,6 +10,7 @@ #include #include +#include #include #include "ishtp-dev.h" @@ -228,4 +229,37 @@ struct ish_firmware_variant { */ void ishtp_loader_work(struct work_struct *work); +/* ISH Manifest alignment in binary is 4KB aligned */ +#define ISH_MANIFEST_ALIGNMENT SZ_4K + +/* Signature for ISH global manifest */ +#define ISH_GLOBAL_SIG 0x47485349 /* FourCC 'I', 'S', 'H', 'G' */ + +struct version_in_manifest { + __le16 major; + __le16 minor; + __le16 hotfix; + __le16 build; +}; + +/** + * struct ish_global_manifest - global manifest for ISH + * @sig_fourcc: Signature FourCC, should be 'I', 'S', 'H', 'G'. + * @len: Length of the manifest. + * @header_version: Version of the manifest header. + * @flags: Flags for additional information. + * @base_ver: Base version of Intel's released firmware. + * @reserved: Reserved space for future use. + * @prj_ver: Vendor-customized project version. + */ +struct ish_global_manifest { + __le32 sig_fourcc; + __le32 len; + __le32 header_version; + __le32 flags; + struct version_in_manifest base_ver; + __le32 reserved[13]; + struct version_in_manifest prj_ver; +}; + #endif /* _ISHTP_LOADER_H_ */ diff --git a/drivers/hid/surface-hid/surface_kbd.c b/drivers/hid/surface-hid/surface_kbd.c index 383200d9121ae8..0be01b5e742585 100644 --- a/drivers/hid/surface-hid/surface_kbd.c +++ b/drivers/hid/surface-hid/surface_kbd.c @@ -284,7 +284,7 @@ MODULE_DEVICE_TABLE(acpi, surface_kbd_match); static struct platform_driver surface_kbd_driver = { .probe = surface_kbd_probe, - .remove_new = surface_kbd_remove, + .remove = surface_kbd_remove, .driver = { .name = "surface_keyboard", .acpi_match_table = surface_kbd_match, diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index a9e85bdd4cc656..a6eb6fe6130d13 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1100,7 +1100,7 @@ static int usbhid_start(struct hid_device *hid) interval = endpoint->bInterval; - /* Some vendors give fullspeed interval on highspeed devides */ + /* Some vendors give fullspeed interval on highspeed devices */ if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL && dev->speed == USB_SPEED_HIGH) { interval = fls(endpoint->bInterval*8); diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 2bc45b24075c3f..9843b52bd017a0 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -2241,7 +2241,8 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix) if (hid_is_usb(wacom->hdev)) { struct usb_interface *intf = to_usb_interface(wacom->hdev->dev.parent); struct usb_device *dev = interface_to_usbdev(intf); - product_name = dev->product; + if (dev->product != NULL) + product_name = dev->product; } if (wacom->hdev->bus == BUS_I2C) { diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 413606bdf476df..5501a560fb07ff 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1353,9 +1353,9 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) rotation -= 1800; input_report_abs(pen_input, ABS_TILT_X, - (char)frame[7]); + (signed char)frame[7]); input_report_abs(pen_input, ABS_TILT_Y, - (char)frame[8]); + (signed char)frame[8]); input_report_abs(pen_input, ABS_Z, rotation); input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11])); @@ -2422,9 +2422,11 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field wacom_wac->hid_data.sense_state = value; return; case HID_DG_INVERT: - wacom_wac->hid_data.invert_state = value; + wacom_wac->hid_data.eraser |= value; return; case HID_DG_ERASER: + wacom_wac->hid_data.eraser |= value; + fallthrough; case HID_DG_TIPSWITCH: wacom_wac->hid_data.tipswitch |= value; return; @@ -2565,7 +2567,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev, if (entering_range) { /* first in range */ /* Going into range select tool */ - if (wacom_wac->hid_data.invert_state) + if (wacom_wac->hid_data.eraser) wacom_wac->tool[0] = BTN_TOOL_RUBBER; else if (wacom_wac->features.quirks & WACOM_QUIRK_AESPEN) wacom_wac->tool[0] = BTN_TOOL_PEN; @@ -2619,6 +2621,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev, } wacom_wac->hid_data.tipswitch = false; + wacom_wac->hid_data.eraser = false; input_sync(input); } diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index c8803d5c6a71e7..0c3c6a6aaae951 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -300,7 +300,7 @@ struct hid_data { __s16 inputmode_index; /* InputMode HID feature index in the report */ bool sense_state; bool inrange_state; - bool invert_state; + bool eraser; bool tipswitch; bool barrelswitch; bool barrelswitch2; diff --git a/drivers/hsi/controllers/omap_ssi_core.c b/drivers/hsi/controllers/omap_ssi_core.c index 15cb759151e669..eeacc427fd6590 100644 --- a/drivers/hsi/controllers/omap_ssi_core.c +++ b/drivers/hsi/controllers/omap_ssi_core.c @@ -607,7 +607,7 @@ MODULE_DEVICE_TABLE(of, omap_ssi_of_match); static struct platform_driver ssi_pdriver = { .probe = ssi_probe, - .remove_new = ssi_remove, + .remove = ssi_remove, .driver = { .name = "omap_ssi", .pm = DEV_PM_OPS, diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c index f0b3eca7376e44..aeb92b803a177a 100644 --- a/drivers/hsi/controllers/omap_ssi_port.c +++ b/drivers/hsi/controllers/omap_ssi_port.c @@ -1385,7 +1385,7 @@ MODULE_DEVICE_TABLE(of, omap_ssi_port_of_match); struct platform_driver ssi_port_pdriver = { .probe = ssi_port_probe, - .remove_new = ssi_port_remove, + .remove = ssi_port_remove, .driver = { .name = "omap_ssi_port", .of_match_table = omap_ssi_port_of_match, diff --git a/drivers/hte/hte-tegra194-test.c b/drivers/hte/hte-tegra194-test.c index df631b5100d230..f890b79723af36 100644 --- a/drivers/hte/hte-tegra194-test.c +++ b/drivers/hte/hte-tegra194-test.c @@ -226,7 +226,7 @@ static void tegra_hte_test_remove(struct platform_device *pdev) static struct platform_driver tegra_hte_test_driver = { .probe = tegra_hte_test_probe, - .remove_new = tegra_hte_test_remove, + .remove = tegra_hte_test_remove, .driver = { .name = "tegra_hte_test", .of_match_table = tegra_hte_test_of_match, diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index c38dcdfcb914dc..a99112e6f0b853 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -756,7 +756,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size, * adding succeeded, it is ok to proceed even if the memory was * not onlined in time. */ - wait_for_completion_timeout(&dm_device.ol_waitevent, 5 * HZ); + wait_for_completion_timeout(&dm_device.ol_waitevent, secs_to_jiffies(5)); post_status(&dm_device); } } @@ -1373,7 +1373,8 @@ static int dm_thread_func(void *dm_dev) struct hv_dynmem_device *dm = dm_dev; while (!kthread_should_stop()) { - wait_for_completion_interruptible_timeout(&dm_device.config_event, 1 * HZ); + wait_for_completion_interruptible_timeout(&dm_device.config_event, + secs_to_jiffies(1)); /* * The host expects us to post information on the memory * pressure every second. @@ -1748,7 +1749,7 @@ static int balloon_connect_vsp(struct hv_device *dev) if (ret) goto out; - t = wait_for_completion_timeout(&dm_device.host_event, 5 * HZ); + t = wait_for_completion_timeout(&dm_device.host_event, secs_to_jiffies(5)); if (t == 0) { ret = -ETIMEDOUT; goto out; @@ -1806,7 +1807,7 @@ static int balloon_connect_vsp(struct hv_device *dev) if (ret) goto out; - t = wait_for_completion_timeout(&dm_device.host_event, 5 * HZ); + t = wait_for_completion_timeout(&dm_device.host_event, secs_to_jiffies(5)); if (t == 0) { ret = -ETIMEDOUT; goto out; diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index d35b60c0611486..7400a5a4d2bd75 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -655,7 +655,7 @@ void hv_kvp_onchannelcallback(void *context) if (host_negotiatied == NEGO_NOT_STARTED) { host_negotiatied = NEGO_IN_PROGRESS; schedule_delayed_work(&kvp_host_handshake_work, - HV_UTIL_NEGO_TIMEOUT * HZ); + secs_to_jiffies(HV_UTIL_NEGO_TIMEOUT)); } return; } @@ -724,7 +724,7 @@ void hv_kvp_onchannelcallback(void *context) */ schedule_work(&kvp_sendkey_work); schedule_delayed_work(&kvp_timeout_work, - HV_UTIL_TIMEOUT * HZ); + secs_to_jiffies(HV_UTIL_TIMEOUT)); return; @@ -767,6 +767,12 @@ hv_kvp_init(struct hv_util_service *srv) */ kvp_transaction.state = HVUTIL_DEVICE_INIT; + return 0; +} + +int +hv_kvp_init_transport(void) +{ hvt = hvutil_transport_init(kvp_devname, CN_KVP_IDX, CN_KVP_VAL, kvp_on_msg, kvp_on_reset); if (!hvt) diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 0d2184be169125..bde637a96c379b 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -193,7 +193,8 @@ static void vss_send_op(void) vss_transaction.state = HVUTIL_USERSPACE_REQ; schedule_delayed_work(&vss_timeout_work, op == VSS_OP_FREEZE ? - VSS_FREEZE_TIMEOUT * HZ : HV_UTIL_TIMEOUT * HZ); + secs_to_jiffies(VSS_FREEZE_TIMEOUT) : + secs_to_jiffies(HV_UTIL_TIMEOUT)); rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg), NULL); if (rc) { @@ -388,6 +389,12 @@ hv_vss_init(struct hv_util_service *srv) */ vss_transaction.state = HVUTIL_DEVICE_INIT; + return 0; +} + +int +hv_vss_init_transport(void) +{ hvt = hvutil_transport_init(vss_devname, CN_VSS_IDX, CN_VSS_VAL, vss_on_msg, vss_on_reset); if (!hvt) { diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index c4f525325790fa..36ee89c0358bd0 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -141,6 +141,7 @@ static struct hv_util_service util_heartbeat = { static struct hv_util_service util_kvp = { .util_cb = hv_kvp_onchannelcallback, .util_init = hv_kvp_init, + .util_init_transport = hv_kvp_init_transport, .util_pre_suspend = hv_kvp_pre_suspend, .util_pre_resume = hv_kvp_pre_resume, .util_deinit = hv_kvp_deinit, @@ -149,6 +150,7 @@ static struct hv_util_service util_kvp = { static struct hv_util_service util_vss = { .util_cb = hv_vss_onchannelcallback, .util_init = hv_vss_init, + .util_init_transport = hv_vss_init_transport, .util_pre_suspend = hv_vss_pre_suspend, .util_pre_resume = hv_vss_pre_resume, .util_deinit = hv_vss_deinit, @@ -590,10 +592,8 @@ static int util_probe(struct hv_device *dev, srv->channel = dev->channel; if (srv->util_init) { ret = srv->util_init(srv); - if (ret) { - ret = -ENODEV; + if (ret) goto error1; - } } /* @@ -613,6 +613,13 @@ static int util_probe(struct hv_device *dev, if (ret) goto error; + if (srv->util_init_transport) { + ret = srv->util_init_transport(); + if (ret) { + vmbus_close(dev->channel); + goto error; + } + } return 0; error: diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index d2856023d53c9a..52cb744b4d7fde 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -370,12 +370,14 @@ void vmbus_on_event(unsigned long data); void vmbus_on_msg_dpc(unsigned long data); int hv_kvp_init(struct hv_util_service *srv); +int hv_kvp_init_transport(void); void hv_kvp_deinit(void); int hv_kvp_pre_suspend(void); int hv_kvp_pre_resume(void); void hv_kvp_onchannelcallback(void *context); int hv_vss_init(struct hv_util_service *srv); +int hv_vss_init_transport(void); void hv_vss_deinit(void); int hv_vss_pre_suspend(void); int hv_vss_pre_resume(void); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 9b15f7daf50597..2892b8da20a5e2 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -2507,7 +2507,7 @@ static int vmbus_bus_resume(struct device *dev) vmbus_request_offers(); if (wait_for_completion_timeout( - &vmbus_connection.ready_for_resume_event, 10 * HZ) == 0) + &vmbus_connection.ready_for_resume_event, secs_to_jiffies(10)) == 0) pr_err("Some vmbus device is missing after suspending?\n"); /* Reset the event for the next suspend. */ @@ -2560,7 +2560,7 @@ static const struct dev_pm_ops vmbus_bus_pm = { static struct platform_driver vmbus_platform_driver = { .probe = vmbus_platform_driver_probe, - .remove_new = vmbus_platform_driver_remove, + .remove = vmbus_platform_driver_remove, .driver = { .name = "vmbus", .acpi_match_table = ACPI_PTR(vmbus_acpi_device_ids), diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 08a3c863f80a27..dd376602f3f19c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -855,6 +855,17 @@ config SENSORS_CORETEMP sensor inside your CPU. Most of the family 6 CPUs are supported. Check Documentation/hwmon/coretemp.rst for details. +config SENSORS_ISL28022 + tristate "Renesas ISL28022" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for ISL28022 power monitor. + Check Documentation/hwmon/isl28022.rst for details. + + This driver can also be built as a module. If so, the module + will be called isl28022. + config SENSORS_IT87 tristate "ITE IT87xx and compatibles" depends on HAS_IOPORT @@ -1670,6 +1681,17 @@ config SENSORS_NCT6775_I2C This driver can also be built as a module. If so, the module will be called nct6775-i2c. +config SENSORS_NCT7363 + tristate "Nuvoton NCT7363Y" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the Nuvoton NCT7363Y + hardware monitoring chip. + + This driver can also be built as a module. If so, the module + will be called nct7363. + config SENSORS_NCT7802 tristate "Nuvoton NCT7802Y" depends on I2C @@ -1752,7 +1774,7 @@ source "drivers/hwmon/occ/Kconfig" config SENSORS_OXP tristate "OneXPlayer EC fan control" - depends on ACPI + depends on ACPI_EC depends on X86 help If you say yes here you get support for fan readings and control over @@ -2167,11 +2189,12 @@ config SENSORS_INA2XX select REGMAP_I2C help If you say yes here you get support for INA219, INA220, INA226, - INA230, and INA231 power monitor chips. + INA230, INA231, INA260, and SY24655 power monitor chips. The INA2xx driver is configured for the default configuration of the part as described in the datasheet. - Default value for Rshunt is 10 mOhms. + Default value for Rshunt is 10 mOhms except for INA260 which has an + internal 2 mOhm shunt resistor. This driver can also be built as a module. If so, the module will be called ina2xx. @@ -2274,10 +2297,12 @@ config SENSORS_TMP103 config SENSORS_TMP108 tristate "Texas Instruments TMP108" depends on I2C + depends on I3C || !I3C select REGMAP_I2C + select REGMAP_I3C if I3C help If you say yes here you get support for Texas Instruments TMP108 - sensor chips. + sensor chips and NXP P3T1085. This driver can also be built as a module. If so, the module will be called tmp108. @@ -2592,6 +2617,7 @@ config SENSORS_ASUS_WMI config SENSORS_ASUS_EC tristate "ASUS EC Sensors" depends on X86 + depends on ACPI_EC help If you say yes here you get support for the ACPI embedded controller hardware monitoring interface found in ASUS motherboards. The driver diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 9554d2fdcf7bb5..b827b92f2a7844 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o obj-$(CONFIG_SENSORS_INA238) += ina238.o obj-$(CONFIG_SENSORS_INA3221) += ina3221.o obj-$(CONFIG_SENSORS_INTEL_M10_BMC_HWMON) += intel-m10-bmc-hwmon.o +obj-$(CONFIG_SENSORS_ISL28022) += isl28022.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_JC42) += jc42.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o @@ -171,6 +172,7 @@ obj-$(CONFIG_SENSORS_NCT6775_CORE) += nct6775-core.o nct6775-objs := nct6775-platform.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NCT6775_I2C) += nct6775-i2c.o +obj-$(CONFIG_SENSORS_NCT7363) += nct7363.o obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o obj-$(CONFIG_SENSORS_NPCM7XX) += npcm750-pwm-fan.o diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 93653ea054308f..ba8c68ae45953b 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1531,7 +1531,7 @@ static struct platform_driver abituguru_driver = { .pm = pm_sleep_ptr(&abituguru_pm), }, .probe = abituguru_probe, - .remove_new = abituguru_remove, + .remove = abituguru_remove, }; static int __init abituguru_detect(void) diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 4501f0e49efb17..b70330dc219844 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -1147,12 +1147,12 @@ static int abituguru3_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume); static struct platform_driver abituguru3_driver = { - .driver = { + .driver = { .name = ABIT_UGURU3_NAME, .pm = pm_sleep_ptr(&abituguru3_pm), }, .probe = abituguru3_probe, - .remove_new = abituguru3_remove, + .remove = abituguru3_remove, }; static int __init abituguru3_dmi_detect(void) diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 6c8a9c863528ed..2f1c9d97ad2118 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -680,8 +680,9 @@ static int setup_attrs(struct acpi_power_meter_resource *resource) { int res = 0; + /* _PMD method is optional. */ res = read_domain_devices(resource); - if (res) + if (res != -ENODEV) return res; if (resource->caps.flags & POWER_METER_CAN_MEASURE) { diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index ac64b407ed0eaf..1e3c6acd89740f 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -893,7 +894,6 @@ static bool amc6821_volatile_reg(struct device *dev, unsigned int reg) static const struct regmap_config amc6821_regmap_config = { .reg_bits = 8, .val_bits = 8, - .max_register = AMC6821_REG_CONF3, .volatile_reg = amc6821_volatile_reg, .cache_type = REGCACHE_MAPLE, }; @@ -920,6 +920,13 @@ static int amc6821_probe(struct i2c_client *client) if (err) return err; + if (of_device_is_compatible(dev->of_node, "tsd,mule")) { + err = devm_of_platform_populate(dev); + if (err) + return dev_err_probe(dev, err, + "Failed to create sub-devices\n"); + } + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &amc6821_chip_info, amc6821_groups); @@ -927,7 +934,7 @@ static int amc6821_probe(struct i2c_client *client) } static const struct i2c_device_id amc6821_id[] = { - { "amc6821", 0 }, + { "amc6821" }, { } }; @@ -937,6 +944,9 @@ static const struct of_device_id __maybe_unused amc6821_of_match[] = { { .compatible = "ti,amc6821", }, + { + .compatible = "tsd,mule", + }, { } }; diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 34cac27e4ddec3..0dcb8a3a691d69 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -597,7 +597,7 @@ struct aqc_data { /* Sensor values */ s32 temp_input[20]; /* Max 4 physical and 16 virtual or 8 physical and 12 virtual */ - s32 speed_input[8]; + s32 speed_input[9]; u32 speed_input_min[1]; u32 speed_input_target[1]; u32 speed_input_max[1]; diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c index 75eadda738ab67..4174b129d1fce0 100644 --- a/drivers/hwmon/aspeed-g6-pwm-tach.c +++ b/drivers/hwmon/aspeed-g6-pwm-tach.c @@ -534,7 +534,7 @@ MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); static struct platform_driver aspeed_pwm_tach_driver = { .probe = aspeed_pwm_tach_probe, - .remove_new = aspeed_pwm_tach_remove, + .remove = aspeed_pwm_tach_remove, .driver = { .name = "aspeed-g6-pwm-tach", .of_match_table = aspeed_pwm_tach_match, diff --git a/drivers/hwmon/cros_ec_hwmon.c b/drivers/hwmon/cros_ec_hwmon.c index 5514cf780b8bea..9991c3fa020ac8 100644 --- a/drivers/hwmon/cros_ec_hwmon.c +++ b/drivers/hwmon/cros_ec_hwmon.c @@ -141,6 +141,7 @@ static umode_t cros_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_type } static const struct hwmon_channel_info * const cros_ec_hwmon_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT, HWMON_F_INPUT | HWMON_F_FAULT, diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c index 7fb0c57dfef504..588e96790850af 100644 --- a/drivers/hwmon/da9052-hwmon.c +++ b/drivers/hwmon/da9052-hwmon.c @@ -473,7 +473,7 @@ static void da9052_hwmon_remove(struct platform_device *pdev) static struct platform_driver da9052_hwmon_driver = { .probe = da9052_hwmon_probe, - .remove_new = da9052_hwmon_remove, + .remove = da9052_hwmon_remove, .driver = { .name = "da9052-hwmon", }, diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 1a9b28dc91e64e..3d4057309950dc 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -2721,7 +2721,7 @@ static struct platform_driver dme1737_isa_driver = { .name = "dme1737", }, .probe = dme1737_isa_probe, - .remove_new = dme1737_isa_remove, + .remove = dme1737_isa_remove, }; /* --------------------------------------------------------------------- diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 243c570dee4c1a..820f894d9ffda9 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1497,7 +1497,7 @@ static struct platform_driver f71805f_driver = { .name = DRVNAME, }, .probe = f71805f_probe, - .remove_new = f71805f_remove, + .remove = f71805f_remove, }; static int __init f71805f_device_add(unsigned short address, diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 7c941d320a186e..df83f9866fbcf7 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -2658,7 +2658,7 @@ static struct platform_driver f71882fg_driver = { .name = DRVNAME, }, .probe = f71882fg_probe, - .remove_new = f71882fg_remove, + .remove = f71882fg_remove, }; static int __init f71882fg_init(void) diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index 4514f3ed90ccd6..14a6385cd7cc78 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -231,15 +231,8 @@ gsc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, return 0; } -static umode_t -gsc_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr, - int ch) -{ - return 0444; -} - static const struct hwmon_ops gsc_hwmon_ops = { - .is_visible = gsc_hwmon_is_visible, + .visible = 0444, .read = gsc_hwmon_read, .read_string = gsc_hwmon_read_string, }; diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 9c35c4d0369d7a..bbb9cc44e29fbc 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -145,6 +145,17 @@ static const struct class hwmon_class = { static DEFINE_IDA(hwmon_ida); +static umode_t hwmon_is_visible(const struct hwmon_ops *ops, + const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (ops->visible) + return ops->visible; + + return ops->is_visible(drvdata, type, attr, channel); +} + /* Thermal zone handling */ /* @@ -267,8 +278,8 @@ static int hwmon_thermal_register_sensors(struct device *dev) int err; if (!(info[i]->config[j] & HWMON_T_INPUT) || - !chip->ops->is_visible(drvdata, hwmon_temp, - hwmon_temp_input, j)) + !hwmon_is_visible(chip->ops, drvdata, hwmon_temp, + hwmon_temp_input, j)) continue; err = hwmon_thermal_add_sensor(dev, j); @@ -506,7 +517,7 @@ static struct attribute *hwmon_genattr(const void *drvdata, const char *name; bool is_string = is_string_attr(type, attr); - mode = ops->is_visible(drvdata, type, attr, index); + mode = hwmon_is_visible(ops, drvdata, type, attr, index); if (!mode) return ERR_PTR(-ENOENT); @@ -1033,7 +1044,7 @@ hwmon_device_register_with_info(struct device *dev, const char *name, if (!dev || !name || !chip) return ERR_PTR(-EINVAL); - if (!chip->ops || !chip->ops->is_visible || !chip->info) + if (!chip->ops || !(chip->ops->visible || chip->ops->is_visible) || !chip->info) return ERR_PTR(-EINVAL); return __hwmon_device_register(dev, name, drvdata, chip, extra_groups); @@ -1063,7 +1074,7 @@ hwmon_device_register_for_thermal(struct device *dev, const char *name, return __hwmon_device_register(dev, name, drvdata, NULL, NULL); } -EXPORT_SYMBOL_NS_GPL(hwmon_device_register_for_thermal, HWMON_THERMAL); +EXPORT_SYMBOL_NS_GPL(hwmon_device_register_for_thermal, "HWMON_THERMAL"); /** * hwmon_device_register - register w/ hwmon diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c index 7b00b38c7f7bf2..2a530da2194999 100644 --- a/drivers/hwmon/i5500_temp.c +++ b/drivers/hwmon/i5500_temp.c @@ -29,12 +29,6 @@ #define REG_CTCTRL 0xF7 #define REG_TSTIMER 0xF8 -static umode_t i5500_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, - int channel) -{ - return 0444; -} - static int i5500_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -84,7 +78,7 @@ static int i5500_read(struct device *dev, enum hwmon_sensor_types type, u32 attr } static const struct hwmon_ops i5500_ops = { - .is_visible = i5500_is_visible, + .visible = 0444, .read = i5500_read, }; diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 02f5d35dd31990..b22e0423e32493 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -568,7 +568,7 @@ static struct platform_driver i5k_amb_driver = { .name = DRVNAME, }, .probe = i5k_amb_probe, - .remove_new = i5k_amb_remove, + .remove = i5k_amb_remove, }; static int __init i5k_amb_init(void) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index f0fa6d073627f7..345fe7db9de94a 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -51,17 +51,26 @@ #define INA226_ALERT_LIMIT 0x07 #define INA226_DIE_ID 0xFF -#define INA2XX_MAX_REGISTERS 8 +/* SY24655 register definitions */ +#define SY24655_EIN 0x0A +#define SY24655_ACCUM_CONFIG 0x0D +#define INA2XX_MAX_REGISTERS 0x0D /* settings - depend on use case */ #define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ #define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */ +#define INA260_CONFIG_DEFAULT 0x6527 /* averages=16 */ +#define SY24655_CONFIG_DEFAULT 0x4527 /* averages=16 */ + +/* (only for sy24655) */ +#define SY24655_ACCUM_CONFIG_DEFAULT 0x044C /* continuous mode, clear after read*/ /* worst case is 68.10 ms (~14.6Hz, ina219) */ #define INA2XX_CONVERSION_RATE 15 #define INA2XX_MAX_DELAY 69 /* worst case delay in ms */ #define INA2XX_RSHUNT_DEFAULT 10000 +#define INA260_RSHUNT 2000 /* bit mask for reading the averaging setting in the configuration register */ #define INA226_AVG_RD_MASK GENMASK(11, 9) @@ -95,6 +104,7 @@ static bool ina2xx_writeable_reg(struct device *dev, unsigned int reg) case INA2XX_CALIBRATION: case INA226_MASK_ENABLE: case INA226_ALERT_LIMIT: + case SY24655_ACCUM_CONFIG: return true; default: return false; @@ -125,10 +135,13 @@ static const struct regmap_config ina2xx_regmap_config = { .writeable_reg = ina2xx_writeable_reg, }; -enum ina2xx_ids { ina219, ina226 }; +enum ina2xx_ids { ina219, ina226, ina260, sy24655 }; struct ina2xx_config { u16 config_default; + bool has_alerts; /* chip supports alerts and limits */ + bool has_ishunt; /* chip has internal shunt resistor */ + bool has_power_average; /* chip has internal shunt resistor */ int calibration_value; int shunt_div; int bus_voltage_shift; @@ -145,6 +158,7 @@ struct ina2xx_data { long power_lsb_uW; struct mutex config_lock; struct regmap *regmap; + struct i2c_client *client; }; static const struct ina2xx_config ina2xx_config[] = { @@ -155,6 +169,9 @@ static const struct ina2xx_config ina2xx_config[] = { .bus_voltage_shift = 3, .bus_voltage_lsb = 4000, .power_lsb_factor = 20, + .has_alerts = false, + .has_ishunt = false, + .has_power_average = false, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, @@ -163,6 +180,30 @@ static const struct ina2xx_config ina2xx_config[] = { .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, .power_lsb_factor = 25, + .has_alerts = true, + .has_ishunt = false, + .has_power_average = false, + }, + [ina260] = { + .config_default = INA260_CONFIG_DEFAULT, + .shunt_div = 400, + .bus_voltage_shift = 0, + .bus_voltage_lsb = 1250, + .power_lsb_factor = 8, + .has_alerts = true, + .has_ishunt = true, + .has_power_average = false, + }, + [sy24655] = { + .config_default = SY24655_CONFIG_DEFAULT, + .calibration_value = 4096, + .shunt_div = 400, + .bus_voltage_shift = 0, + .bus_voltage_lsb = 1250, + .power_lsb_factor = 25, + .has_alerts = true, + .has_ishunt = false, + .has_power_average = true, }, }; @@ -254,6 +295,15 @@ static int ina2xx_read_init(struct device *dev, int reg, long *val) unsigned int regval; int ret, retry; + if (data->config->has_ishunt) { + /* No calibration needed */ + ret = regmap_read(regmap, reg, ®val); + if (ret < 0) + return ret; + *val = ina2xx_get_value(data, reg, regval); + return 0; + } + for (retry = 5; retry; retry--) { ret = regmap_read(regmap, reg, ®val); if (ret < 0) @@ -459,6 +509,41 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val) return 0; } +/* + * Configuring the READ_EIN (bit 10) of the ACCUM_CONFIG register to 1 + * can clear accumulator and sample_count after reading the EIN register. + * This way, the average power between the last read and the current + * read can be obtained. By combining with accurate time data from + * outside, the energy consumption during that period can be calculated. + */ +static int sy24655_average_power_read(struct ina2xx_data *data, u8 reg, long *val) +{ + u8 template[6]; + int ret; + long accumulator_24, sample_count; + + /* 48-bit register read */ + ret = i2c_smbus_read_i2c_block_data(data->client, reg, 6, template); + if (ret < 0) + return ret; + if (ret != 6) + return -EIO; + accumulator_24 = ((template[3] << 16) | + (template[4] << 8) | + template[5]); + sample_count = ((template[0] << 16) | + (template[1] << 8) | + template[2]); + if (sample_count <= 0) { + *val = 0; + return 0; + } + + *val = DIV_ROUND_CLOSEST(accumulator_24, sample_count) * data->power_lsb_uW; + + return 0; +} + static int ina2xx_power_read(struct device *dev, u32 attr, long *val) { struct ina2xx_data *data = dev_get_drvdata(dev); @@ -466,6 +551,8 @@ static int ina2xx_power_read(struct device *dev, u32 attr, long *val) switch (attr) { case hwmon_power_input: return ina2xx_read_init(dev, INA2XX_POWER, val); + case hwmon_power_average: + return sy24655_average_power_read(data, SY24655_EIN, val); case hwmon_power_crit: return ina226_alert_limit_read(data, INA226_POWER_OVER_LIMIT_MASK, INA2XX_POWER, val); @@ -624,6 +711,8 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type u32 attr, int channel) { const struct ina2xx_data *data = _data; + bool has_alerts = data->config->has_alerts; + bool has_power_average = data->config->has_power_average; enum ina2xx_ids chip = data->chip; switch (type) { @@ -633,12 +722,12 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type return 0444; case hwmon_in_lcrit: case hwmon_in_crit: - if (chip == ina226) + if (has_alerts) return 0644; break; case hwmon_in_lcrit_alarm: case hwmon_in_crit_alarm: - if (chip == ina226) + if (has_alerts) return 0444; break; default: @@ -651,12 +740,12 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type return 0444; case hwmon_curr_lcrit: case hwmon_curr_crit: - if (chip == ina226) + if (has_alerts) return 0644; break; case hwmon_curr_lcrit_alarm: case hwmon_curr_crit_alarm: - if (chip == ina226) + if (has_alerts) return 0444; break; default: @@ -668,11 +757,15 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type case hwmon_power_input: return 0444; case hwmon_power_crit: - if (chip == ina226) + if (has_alerts) return 0644; break; case hwmon_power_crit_alarm: - if (chip == ina226) + if (has_alerts) + return 0444; + break; + case hwmon_power_average: + if (has_power_average) return 0444; break; default: @@ -682,7 +775,7 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type case hwmon_chip: switch (attr) { case hwmon_chip_update_interval: - if (chip == ina226) + if (chip == ina226 || chip == ina260) return 0644; break; default: @@ -707,7 +800,8 @@ static const struct hwmon_channel_info * const ina2xx_info[] = { HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM), HWMON_CHANNEL_INFO(power, - HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM), + HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM | + HWMON_P_AVERAGE), NULL }; @@ -791,7 +885,9 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) u32 shunt; int ret; - if (device_property_read_u32(dev, "shunt-resistor", &shunt) < 0) + if (data->config->has_ishunt) + shunt = INA260_RSHUNT; + else if (device_property_read_u32(dev, "shunt-resistor", &shunt) < 0) shunt = INA2XX_RSHUNT_DEFAULT; ret = ina2xx_set_shunt(data, shunt); @@ -802,7 +898,7 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) if (ret < 0) return ret; - if (data->chip == ina226) { + if (data->config->has_alerts) { bool active_high = device_property_read_bool(dev, "ti,alert-polarity-active-high"); regmap_update_bits(regmap, INA226_MASK_ENABLE, @@ -810,6 +906,22 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) INA226_ALERT_LATCH_ENABLE | FIELD_PREP(INA226_ALERT_POLARITY, active_high)); } + if (data->config->has_power_average) { + if (data->chip == sy24655) { + /* + * Initialize the power accumulation method to continuous + * mode and clear the EIN register after each read of the + * EIN register + */ + ret = regmap_write(regmap, SY24655_ACCUM_CONFIG, + SY24655_ACCUM_CONFIG_DEFAULT); + if (ret < 0) + return ret; + } + } + + if (data->config->has_ishunt) + return 0; /* * Calibration register is set to the best value, which eliminates @@ -836,6 +948,7 @@ static int ina2xx_probe(struct i2c_client *client) return -ENOMEM; /* set the device type */ + data->client = client; data->config = &ina2xx_config[chip]; data->chip = chip; mutex_init(&data->config_lock); @@ -856,7 +969,8 @@ static int ina2xx_probe(struct i2c_client *client) hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &ina2xx_chip_info, - ina2xx_groups); + data->config->has_ishunt ? + NULL : ina2xx_groups); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); @@ -872,11 +986,17 @@ static const struct i2c_device_id ina2xx_id[] = { { "ina226", ina226 }, { "ina230", ina226 }, { "ina231", ina226 }, + { "ina260", ina260 }, + { "sy24655", sy24655 }, { } }; MODULE_DEVICE_TABLE(i2c, ina2xx_id); static const struct of_device_id __maybe_unused ina2xx_of_match[] = { + { + .compatible = "silergy,sy24655", + .data = (void *)sy24655 + }, { .compatible = "ti,ina219", .data = (void *)ina219 @@ -897,7 +1017,11 @@ static const struct of_device_id __maybe_unused ina2xx_of_match[] = { .compatible = "ti,ina231", .data = (void *)ina226 }, - { }, + { + .compatible = "ti,ina260", + .data = (void *)ina260 + }, + { } }; MODULE_DEVICE_TABLE(of, ina2xx_of_match); diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c index 96397ae6ff18fc..aa01a4bedc21b5 100644 --- a/drivers/hwmon/intel-m10-bmc-hwmon.c +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -565,13 +565,6 @@ static const struct m10bmc_hwmon_board_data n6000bmc_hwmon_bdata = { .hinfo = n6000bmc_hinfo, }; -static umode_t -m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static const struct m10bmc_sdata * find_sensor_data(struct m10bmc_hwmon *hw, enum hwmon_sensor_types type, int channel) @@ -729,7 +722,7 @@ static int m10bmc_hwmon_read_string(struct device *dev, } static const struct hwmon_ops m10bmc_hwmon_ops = { - .is_visible = m10bmc_hwmon_is_visible, + .visible = 0444, .read = m10bmc_hwmon_read, .read_string = m10bmc_hwmon_read_string, }; @@ -794,4 +787,4 @@ MODULE_DEVICE_TABLE(platform, intel_m10bmc_hwmon_ids); MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Intel MAX 10 BMC hardware monitor"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); +MODULE_IMPORT_NS("INTEL_M10_BMC_CORE"); diff --git a/drivers/hwmon/isl28022.c b/drivers/hwmon/isl28022.c new file mode 100644 index 00000000000000..f9edcfd164c201 --- /dev/null +++ b/drivers/hwmon/isl28022.c @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * isl28022.c - driver for Renesas ISL28022 power monitor chip monitoring + * + * Copyright (c) 2023 Carsten Spieß + */ + +#include +#include +#include +#include +#include +#include + +/* ISL28022 registers */ +#define ISL28022_REG_CONFIG 0x00 +#define ISL28022_REG_SHUNT 0x01 +#define ISL28022_REG_BUS 0x02 +#define ISL28022_REG_POWER 0x03 +#define ISL28022_REG_CURRENT 0x04 +#define ISL28022_REG_CALIB 0x05 +#define ISL28022_REG_SHUNT_THR 0x06 +#define ISL28022_REG_BUS_THR 0x07 +#define ISL28022_REG_INT 0x08 +#define ISL28022_REG_AUX 0x09 +#define ISL28022_REG_MAX ISL28022_REG_AUX + +/* ISL28022 config flags */ +/* mode flags */ +#define ISL28022_MODE_SHIFT 0 +#define ISL28022_MODE_MASK 0x0007 + +#define ISL28022_MODE_PWR_DOWN 0x0 +#define ISL28022_MODE_TRG_S 0x1 +#define ISL28022_MODE_TRG_B 0x2 +#define ISL28022_MODE_TRG_SB 0x3 +#define ISL28022_MODE_ADC_OFF 0x4 +#define ISL28022_MODE_CONT_S 0x5 +#define ISL28022_MODE_CONT_B 0x6 +#define ISL28022_MODE_CONT_SB 0x7 + +/* shunt ADC settings */ +#define ISL28022_SADC_SHIFT 3 +#define ISL28022_SADC_MASK 0x0078 + +#define ISL28022_BADC_SHIFT 7 +#define ISL28022_BADC_MASK 0x0780 + +#define ISL28022_ADC_12 0x0 /* 12 bit ADC */ +#define ISL28022_ADC_13 0x1 /* 13 bit ADC */ +#define ISL28022_ADC_14 0x2 /* 14 bit ADC */ +#define ISL28022_ADC_15 0x3 /* 15 bit ADC */ +#define ISL28022_ADC_15_1 0x8 /* 15 bit ADC, 1 sample */ +#define ISL28022_ADC_15_2 0x9 /* 15 bit ADC, 2 samples */ +#define ISL28022_ADC_15_4 0xA /* 15 bit ADC, 4 samples */ +#define ISL28022_ADC_15_8 0xB /* 15 bit ADC, 8 samples */ +#define ISL28022_ADC_15_16 0xC /* 15 bit ADC, 16 samples */ +#define ISL28022_ADC_15_32 0xD /* 15 bit ADC, 32 samples */ +#define ISL28022_ADC_15_64 0xE /* 15 bit ADC, 64 samples */ +#define ISL28022_ADC_15_128 0xF /* 15 bit ADC, 128 samples */ + +/* shunt voltage range */ +#define ISL28022_PG_SHIFT 11 +#define ISL28022_PG_MASK 0x1800 + +#define ISL28022_PG_40 0x0 /* +/-40 mV */ +#define ISL28022_PG_80 0x1 /* +/-80 mV */ +#define ISL28022_PG_160 0x2 /* +/-160 mV */ +#define ISL28022_PG_320 0x3 /* +/-3200 mV */ + +/* bus voltage range */ +#define ISL28022_BRNG_SHIFT 13 +#define ISL28022_BRNG_MASK 0x6000 + +#define ISL28022_BRNG_16 0x0 /* 16 V */ +#define ISL28022_BRNG_32 0x1 /* 32 V */ +#define ISL28022_BRNG_60 0x3 /* 60 V */ + +/* reset */ +#define ISL28022_RESET 0x8000 + +struct isl28022_data { + struct regmap *regmap; + u32 shunt; + u32 gain; + u32 average; +}; + +static int isl28022_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + struct isl28022_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + u16 sign_bit; + + switch (channel) { + case 0: + switch (attr) { + case hwmon_in_input: + err = regmap_read(data->regmap, + ISL28022_REG_BUS, ®val); + if (err < 0) + return err; + /* driver supports only 60V mode (BRNG 11) */ + *val = (long)(((u16)regval) & 0xFFFC); + break; + default: + return -EOPNOTSUPP; + } + break; + case 1: + switch (attr) { + case hwmon_in_input: + err = regmap_read(data->regmap, + ISL28022_REG_SHUNT, ®val); + if (err < 0) + return err; + switch (data->gain) { + case 8: + sign_bit = (regval >> 15) & 0x01; + *val = (long)((((u16)regval) & 0x7FFF) - + (sign_bit * 32768)) / 100; + break; + case 4: + sign_bit = (regval >> 14) & 0x01; + *val = (long)((((u16)regval) & 0x3FFF) - + (sign_bit * 16384)) / 100; + break; + case 2: + sign_bit = (regval >> 13) & 0x01; + *val = (long)((((u16)regval) & 0x1FFF) - + (sign_bit * 8192)) / 100; + break; + case 1: + sign_bit = (regval >> 12) & 0x01; + *val = (long)((((u16)regval) & 0x0FFF) - + (sign_bit * 4096)) / 100; + break; + } + break; + default: + return -EOPNOTSUPP; + } + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int isl28022_read_current(struct device *dev, u32 attr, long *val) +{ + struct isl28022_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + + switch (attr) { + case hwmon_curr_input: + err = regmap_read(data->regmap, + ISL28022_REG_CURRENT, ®val); + if (err < 0) + return err; + *val = ((long)regval * 1250L * (long)data->gain) / + (long)data->shunt; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int isl28022_read_power(struct device *dev, u32 attr, long *val) +{ + struct isl28022_data *data = dev_get_drvdata(dev); + unsigned int regval; + int err; + + switch (attr) { + case hwmon_power_input: + err = regmap_read(data->regmap, + ISL28022_REG_POWER, ®val); + if (err < 0) + return err; + *val = ((51200000L * ((long)data->gain)) / + (long)data->shunt) * (long)regval; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int isl28022_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_in: + return isl28022_read_in(dev, attr, channel, val); + case hwmon_curr: + return isl28022_read_current(dev, attr, val); + case hwmon_power: + return isl28022_read_power(dev, attr, val); + default: + return -EOPNOTSUPP; + } + return 0; +} + +static umode_t isl28022_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_in: + switch (attr) { + case hwmon_in_input: + return 0444; + default: + break; + } + break; + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + return 0444; + default: + break; + } + break; + case hwmon_power: + switch (attr) { + case hwmon_power_input: + return 0444; + default: + break; + } + break; + default: + break; + } + return 0; +} + +static const struct hwmon_channel_info *isl28022_info[] = { + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT, /* channel 0: bus voltage (mV) */ + HWMON_I_INPUT), /* channel 1: shunt voltage (mV) */ + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT), /* channel 1: current (mA) */ + HWMON_CHANNEL_INFO(power, + HWMON_P_INPUT), /* channel 1: power (µW) */ + NULL +}; + +static const struct hwmon_ops isl28022_hwmon_ops = { + .is_visible = isl28022_is_visible, + .read = isl28022_read, +}; + +static const struct hwmon_chip_info isl28022_chip_info = { + .ops = &isl28022_hwmon_ops, + .info = isl28022_info, +}; + +static bool isl28022_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ISL28022_REG_CONFIG: + case ISL28022_REG_CALIB: + case ISL28022_REG_SHUNT_THR: + case ISL28022_REG_BUS_THR: + case ISL28022_REG_INT: + case ISL28022_REG_AUX: + return true; + } + + return false; +} + +static bool isl28022_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ISL28022_REG_CONFIG: + case ISL28022_REG_SHUNT: + case ISL28022_REG_BUS: + case ISL28022_REG_POWER: + case ISL28022_REG_CURRENT: + case ISL28022_REG_INT: + case ISL28022_REG_AUX: + return true; + } + return true; +} + +static const struct regmap_config isl28022_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = ISL28022_REG_MAX, + .writeable_reg = isl28022_is_writeable_reg, + .volatile_reg = isl28022_is_volatile_reg, + .val_format_endian = REGMAP_ENDIAN_BIG, + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static int shunt_voltage_show(struct seq_file *seqf, void *unused) +{ + struct isl28022_data *data = seqf->private; + unsigned int regval; + int err; + + err = regmap_read(data->regmap, + ISL28022_REG_SHUNT, ®val); + if (err) + return err; + + /* print shunt voltage in micro volt */ + seq_printf(seqf, "%d\n", regval * 10); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(shunt_voltage); + +static struct dentry *isl28022_debugfs_root; + +static void isl28022_debugfs_remove(void *res) +{ + debugfs_remove_recursive(res); +} + +static void isl28022_debugfs_init(struct i2c_client *client, struct isl28022_data *data) +{ + char name[16]; + struct dentry *debugfs; + + scnprintf(name, sizeof(name), "%d-%04hx", client->adapter->nr, client->addr); + + debugfs = debugfs_create_dir(name, isl28022_debugfs_root); + debugfs_create_file("shunt_voltage", 0444, debugfs, data, &shunt_voltage_fops); + + devm_add_action_or_reset(&client->dev, isl28022_debugfs_remove, debugfs); +} + +/* + * read property values and make consistency checks. + * + * following values for shunt range and resistor are allowed: + * 40 mV -> gain 1, shunt min. 800 micro ohms + * 80 mV -> gain 2, shunt min. 1600 micro ohms + * 160 mV -> gain 4, shunt min. 3200 micro ohms + * 320 mV -> gain 8, shunt min. 6400 micro ohms + */ +static int isl28022_read_properties(struct device *dev, struct isl28022_data *data) +{ + u32 val; + int err; + + err = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val); + if (err == -EINVAL) + val = 10000; + else if (err < 0) + return err; + data->shunt = val; + + err = device_property_read_u32(dev, "renesas,shunt-range-microvolt", &val); + if (err == -EINVAL) + val = 320000; + else if (err < 0) + return err; + + switch (val) { + case 40000: + data->gain = 1; + if (data->shunt < 800) + goto shunt_invalid; + break; + case 80000: + data->gain = 2; + if (data->shunt < 1600) + goto shunt_invalid; + break; + case 160000: + data->gain = 4; + if (data->shunt < 3200) + goto shunt_invalid; + break; + case 320000: + data->gain = 8; + if (data->shunt < 6400) + goto shunt_invalid; + break; + default: + return dev_err_probe(dev, -EINVAL, + "renesas,shunt-range-microvolt invalid value %d\n", + val); + } + + err = device_property_read_u32(dev, "renesas,average-samples", &val); + if (err == -EINVAL) + val = 1; + else if (err < 0) + return err; + if (val > 128 || hweight32(val) != 1) + return dev_err_probe(dev, -EINVAL, + "renesas,average-samples invalid value %d\n", + val); + + data->average = val; + + return 0; + +shunt_invalid: + return dev_err_probe(dev, -EINVAL, + "renesas,shunt-resistor-microvolt invalid value %d\n", + data->shunt); +} + +/* + * write configuration and calibration registers + * + * The driver supports only shunt and bus continuous ADC mode at 15bit resolution + * with averaging from 1 to 128 samples (pow of 2) on both channels. + * Shunt voltage gain 1,2,4 or 8 is allowed. + * The bus voltage range is 60V fixed. + */ +static int isl28022_config(struct isl28022_data *data) +{ + int err; + u16 config; + u16 calib; + + config = (ISL28022_MODE_CONT_SB << ISL28022_MODE_SHIFT) | + (ISL28022_BRNG_60 << ISL28022_BRNG_SHIFT) | + (__ffs(data->gain) << ISL28022_PG_SHIFT) | + ((ISL28022_ADC_15_1 + __ffs(data->average)) << ISL28022_SADC_SHIFT) | + ((ISL28022_ADC_15_1 + __ffs(data->average)) << ISL28022_BADC_SHIFT); + + calib = data->shunt ? 0x8000 / data->gain : 0; + + err = regmap_write(data->regmap, ISL28022_REG_CONFIG, config); + if (err < 0) + return err; + + return regmap_write(data->regmap, ISL28022_REG_CALIB, calib); +} + +static int isl28022_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct isl28022_data *data; + int err; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + data = devm_kzalloc(dev, sizeof(struct isl28022_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + err = isl28022_read_properties(dev, data); + if (err) + return err; + + data->regmap = devm_regmap_init_i2c(client, &isl28022_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + err = isl28022_config(data); + if (err) + return err; + + isl28022_debugfs_init(client, data); + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + data, &isl28022_chip_info, NULL); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + return 0; +} + +static const struct i2c_device_id isl28022_ids[] = { + { "isl28022", 0}, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, isl28022_ids); + +static const struct of_device_id __maybe_unused isl28022_of_match[] = { + { .compatible = "renesas,isl28022"}, + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(of, isl28022_of_match); + +static struct i2c_driver isl28022_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "isl28022", + }, + .probe = isl28022_probe, + .id_table = isl28022_ids, +}; + +static int __init +isl28022_init(void) +{ + int err; + + isl28022_debugfs_root = debugfs_create_dir("isl28022", NULL); + err = i2c_add_driver(&isl28022_driver); + if (!err) + return 0; + + debugfs_remove_recursive(isl28022_debugfs_root); + return err; +} + +static void __exit +isl28022_exit(void) +{ + i2c_del_driver(&isl28022_driver); + debugfs_remove_recursive(isl28022_debugfs_root); +} + +module_init(isl28022_init); +module_exit(isl28022_exit); + +MODULE_AUTHOR("Carsten Spieß "); +MODULE_DESCRIPTION("ISL28022 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index c459dce496a6ed..06f0ab2f52fa2b 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include /* Addresses to scan */ @@ -595,20 +595,18 @@ static const struct i2c_device_id jc42_id[] = { }; MODULE_DEVICE_TABLE(i2c, jc42_id); -#ifdef CONFIG_OF static const struct of_device_id jc42_of_ids[] = { { .compatible = "jedec,jc-42.4-temp", }, { } }; MODULE_DEVICE_TABLE(of, jc42_of_ids); -#endif static struct i2c_driver jc42_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "jc42", .pm = JC42_DEV_PM_OPS, - .of_match_table = of_match_ptr(jc42_of_ids), + .of_match_table = jc42_of_ids, }, .probe = jc42_probe, .remove = jc42_remove, diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index bb30403f81caa0..f0048ff3760722 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -332,7 +332,7 @@ static struct platform_driver max197_driver = { .name = "max197", }, .probe = max197_probe, - .remove_new = max197_remove, + .remove = max197_remove, .id_table = max197_device_ids, }; module_platform_driver(max197_driver); diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index c955b0f3a8d31e..32b4d54b20766e 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -531,14 +530,49 @@ static int rpm_range_to_reg(int range) return 1; /* default: 4000 RPM */ } +static int max6639_probe_child_from_dt(struct i2c_client *client, + struct device_node *child, + struct max6639_data *data) + +{ + struct device *dev = &client->dev; + u32 i; + int err, val; + + err = of_property_read_u32(child, "reg", &i); + if (err) { + dev_err(dev, "missing reg property of %pOFn\n", child); + return err; + } + + if (i > 1) { + dev_err(dev, "Invalid fan index reg %d\n", i); + return -EINVAL; + } + + err = of_property_read_u32(child, "pulses-per-revolution", &val); + if (!err) { + if (val < 1 || val > 5) { + dev_err(dev, "invalid pulses-per-revolution %d of %pOFn\n", val, child); + return -EINVAL; + } + data->ppr[i] = val; + } + + err = of_property_read_u32(child, "max-rpm", &val); + if (!err) + data->rpm_range[i] = rpm_range_to_reg(val); + + return 0; +} + static int max6639_init_client(struct i2c_client *client, struct max6639_data *data) { - struct max6639_platform_data *max6639_info = - dev_get_platdata(&client->dev); - int i; - int rpm_range = 1; /* default: 4000 RPM */ - int err, ppr; + struct device *dev = &client->dev; + const struct device_node *np = dev->of_node; + struct device_node *child; + int i, err; /* Reset chip to default values, see below for GCONFIG setup */ err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR); @@ -546,21 +580,29 @@ static int max6639_init_client(struct i2c_client *client, return err; /* Fans pulse per revolution is 2 by default */ - if (max6639_info && max6639_info->ppr > 0 && - max6639_info->ppr < 5) - ppr = max6639_info->ppr; - else - ppr = 2; + data->ppr[0] = 2; + data->ppr[1] = 2; + + /* default: 4000 RPM */ + data->rpm_range[0] = 1; + data->rpm_range[1] = 1; - data->ppr[0] = ppr; - data->ppr[1] = ppr; + for_each_child_of_node(np, child) { + if (strcmp(child->name, "fan")) + continue; - if (max6639_info) - rpm_range = rpm_range_to_reg(max6639_info->rpm_range); - data->rpm_range[0] = rpm_range; - data->rpm_range[1] = rpm_range; + err = max6639_probe_child_from_dt(client, child, data); + if (err) { + of_node_put(child); + return err; + } + } for (i = 0; i < MAX6639_NUM_CHANNELS; i++) { + err = regmap_set_bits(data->regmap, MAX6639_REG_OUTPUT_MASK, BIT(1 - i)); + if (err) + return err; + /* Set Fan pulse per revolution */ err = max6639_set_ppr(data, i, data->ppr[i]); if (err) @@ -573,12 +615,7 @@ static int max6639_init_client(struct i2c_client *client, return err; /* Fans PWM polarity high by default */ - if (max6639_info) { - if (max6639_info->pwm_polarity == 0) - err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00); - else - err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02); - } + err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00); if (err) return err; diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 67471c9cd4d47d..66304d48d33a4f 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -315,7 +315,7 @@ static const struct platform_device_id mc13783_adc_idtable[] = { MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); static struct platform_driver mc13783_adc_driver = { - .remove_new = mc13783_adc_remove, + .remove = mc13783_adc_remove, .driver = { .name = DRIVER_NAME, }, diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index 934fed3dd58661..c243b51837d2fb 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -57,7 +57,7 @@ #include "nct6775.h" #undef DEFAULT_SYMBOL_NAMESPACE -#define DEFAULT_SYMBOL_NAMESPACE HWMON_NCT6775 +#define DEFAULT_SYMBOL_NAMESPACE "HWMON_NCT6775" #define USE_ALTERNATE @@ -2878,8 +2878,7 @@ store_target_temp(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, - data->target_temp_mask); + val = DIV_ROUND_CLOSEST(clamp_val(val, 0, data->target_temp_mask * 1000), 1000); mutex_lock(&data->update_lock); data->target_temp[nr] = val; @@ -2959,7 +2958,7 @@ store_temp_tolerance(struct device *dev, struct device_attribute *attr, return err; /* Limit tolerance as needed */ - val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask); + val = DIV_ROUND_CLOSEST(clamp_val(val, 0, data->tolerance_mask * 1000), 1000); mutex_lock(&data->update_lock); data->temp_tolerance[index][nr] = val; @@ -3085,7 +3084,7 @@ store_weight_temp(struct device *dev, struct device_attribute *attr, if (err < 0) return err; - val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255); + val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 255000), 1000); mutex_lock(&data->update_lock); data->weight_temp[index][nr] = val; diff --git a/drivers/hwmon/nct6775-i2c.c b/drivers/hwmon/nct6775-i2c.c index aff69fa50461e3..ba71d776a2911b 100644 --- a/drivers/hwmon/nct6775-i2c.c +++ b/drivers/hwmon/nct6775-i2c.c @@ -184,4 +184,4 @@ module_i2c_driver(nct6775_i2c_driver); MODULE_AUTHOR("Zev Weiss "); MODULE_DESCRIPTION("I2C driver for NCT6775F and compatible chips"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(HWMON_NCT6775); +MODULE_IMPORT_NS("HWMON_NCT6775"); diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index 096f1daa8f2bcf..0a040364b5127e 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -1350,6 +1350,8 @@ static const char * const asus_msi_boards[] = { "Pro H610M-CT D4", "Pro H610T D4", "Pro Q670M-C", + "Pro WS 600M-CL", + "Pro WS 665-ACE", "Pro WS W680-ACE", "Pro WS W680-ACE IPMI", "Pro WS W790-ACE", @@ -1620,7 +1622,7 @@ static void __exit sensors_nct6775_platform_exit(void) MODULE_AUTHOR("Guenter Roeck "); MODULE_DESCRIPTION("Platform driver for NCT6775F and compatible chips"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(HWMON_NCT6775); +MODULE_IMPORT_NS("HWMON_NCT6775"); module_init(sensors_nct6775_platform_init); module_exit(sensors_nct6775_platform_exit); diff --git a/drivers/hwmon/nct7363.c b/drivers/hwmon/nct7363.c new file mode 100644 index 00000000000000..be7bf32f6e689d --- /dev/null +++ b/drivers/hwmon/nct7363.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Nuvoton Technology corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NCT7363_REG_FUNC_CFG_BASE(x) (0x20 + (x)) +#define NCT7363_REG_LSRS(x) (0x34 + ((x) / 8)) +#define NCT7363_REG_PWMEN_BASE(x) (0x38 + (x)) +#define NCT7363_REG_FANINEN_BASE(x) (0x41 + (x)) +#define NCT7363_REG_FANINX_HVAL(x) (0x48 + ((x) * 2)) +#define NCT7363_REG_FANINX_LVAL(x) (0x49 + ((x) * 2)) +#define NCT7363_REG_FANINX_HL(x) (0x6C + ((x) * 2)) +#define NCT7363_REG_FANINX_LL(x) (0x6D + ((x) * 2)) +#define NCT7363_REG_FSCPXDUTY(x) (0x90 + ((x) * 2)) +#define NCT7363_REG_FSCPXDIV(x) (0x91 + ((x) * 2)) + +#define PWM_SEL(x) (BIT(0) << ((x) * 2)) +#define FANIN_SEL(_x) ({typeof(_x) (x) = (_x); \ + BIT(1) << (((x) < 8) ? \ + (((x) + 8) * 2) : \ + (((x) % 8) * 2)); }) +#define ALARM_SEL(x, y) ((x) & (BIT((y) % 8))) +#define VALUE_TO_REG(x, y) (((x) >> ((y) * 8)) & 0xFF) + +#define NCT7363_FANINX_LVAL_MASK GENMASK(4, 0) +#define NCT7363_FANIN_MASK GENMASK(12, 0) + +#define NCT7363_PWM_COUNT 16 + +static inline unsigned int fan_from_reg(u16 val) +{ + if (val == NCT7363_FANIN_MASK || val == 0) + return 0; + + return (1350000UL / val); +} + +static const struct of_device_id nct7363_of_match[] = { + { .compatible = "nuvoton,nct7363", }, + { .compatible = "nuvoton,nct7362", }, + { } +}; +MODULE_DEVICE_TABLE(of, nct7363_of_match); + +struct nct7363_data { + struct regmap *regmap; + + u16 fanin_mask; + u16 pwm_mask; +}; + +static int nct7363_read_fan(struct device *dev, u32 attr, int channel, + long *val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + unsigned int reg; + u8 regval[2]; + int ret; + u16 cnt; + + switch (attr) { + case hwmon_fan_input: + /* + * High-byte register should be read first to latch + * synchronous low-byte value + */ + ret = regmap_bulk_read(data->regmap, + NCT7363_REG_FANINX_HVAL(channel), + ®val, 2); + if (ret) + return ret; + + cnt = (regval[0] << 5) | (regval[1] & NCT7363_FANINX_LVAL_MASK); + *val = fan_from_reg(cnt); + return 0; + case hwmon_fan_min: + ret = regmap_bulk_read(data->regmap, + NCT7363_REG_FANINX_HL(channel), + ®val, 2); + if (ret) + return ret; + + cnt = (regval[0] << 5) | (regval[1] & NCT7363_FANINX_LVAL_MASK); + *val = fan_from_reg(cnt); + return 0; + case hwmon_fan_alarm: + ret = regmap_read(data->regmap, + NCT7363_REG_LSRS(channel), ®); + if (ret) + return ret; + + *val = (long)ALARM_SEL(reg, channel) > 0 ? 1 : 0; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write_fan(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + u8 regval[2]; + int ret; + + if (val <= 0) + return -EINVAL; + + switch (attr) { + case hwmon_fan_min: + val = clamp_val(DIV_ROUND_CLOSEST(1350000, val), + 1, NCT7363_FANIN_MASK); + regval[0] = val >> 5; + regval[1] = val & NCT7363_FANINX_LVAL_MASK; + + ret = regmap_bulk_write(data->regmap, + NCT7363_REG_FANINX_HL(channel), + regval, 2); + return ret; + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_fan_is_visible(const void *_data, u32 attr, int channel) +{ + const struct nct7363_data *data = _data; + + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_alarm: + if (data->fanin_mask & BIT(channel)) + return 0444; + break; + case hwmon_fan_min: + if (data->fanin_mask & BIT(channel)) + return 0644; + break; + default: + break; + } + + return 0; +} + +static int nct7363_read_pwm(struct device *dev, u32 attr, int channel, + long *val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + unsigned int regval; + int ret; + + switch (attr) { + case hwmon_pwm_input: + ret = regmap_read(data->regmap, + NCT7363_REG_FSCPXDUTY(channel), ®val); + if (ret) + return ret; + + *val = (long)regval; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write_pwm(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + int ret; + + switch (attr) { + case hwmon_pwm_input: + if (val < 0 || val > 255) + return -EINVAL; + + ret = regmap_write(data->regmap, + NCT7363_REG_FSCPXDUTY(channel), val); + + return ret; + + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_pwm_is_visible(const void *_data, u32 attr, int channel) +{ + const struct nct7363_data *data = _data; + + switch (attr) { + case hwmon_pwm_input: + if (data->pwm_mask & BIT(channel)) + return 0644; + break; + default: + break; + } + + return 0; +} + +static int nct7363_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_fan: + return nct7363_read_fan(dev, attr, channel, val); + case hwmon_pwm: + return nct7363_read_pwm(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_fan: + return nct7363_write_fan(dev, attr, channel, val); + case hwmon_pwm: + return nct7363_write_pwm(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_fan: + return nct7363_fan_is_visible(data, attr, channel); + case hwmon_pwm: + return nct7363_pwm_is_visible(data, attr, channel); + default: + return 0; + } +} + +static const struct hwmon_channel_info *nct7363_info[] = { + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT), + NULL +}; + +static const struct hwmon_ops nct7363_hwmon_ops = { + .is_visible = nct7363_is_visible, + .read = nct7363_read, + .write = nct7363_write, +}; + +static const struct hwmon_chip_info nct7363_chip_info = { + .ops = &nct7363_hwmon_ops, + .info = nct7363_info, +}; + +static int nct7363_init_chip(struct nct7363_data *data) +{ + u32 func_config = 0; + int i, ret; + + /* Pin Function Configuration */ + for (i = 0; i < NCT7363_PWM_COUNT; i++) { + if (data->pwm_mask & BIT(i)) + func_config |= PWM_SEL(i); + if (data->fanin_mask & BIT(i)) + func_config |= FANIN_SEL(i); + } + + for (i = 0; i < 4; i++) { + ret = regmap_write(data->regmap, NCT7363_REG_FUNC_CFG_BASE(i), + VALUE_TO_REG(func_config, i)); + if (ret < 0) + return ret; + } + + /* PWM and FANIN Monitoring Enable */ + for (i = 0; i < 2; i++) { + ret = regmap_write(data->regmap, NCT7363_REG_PWMEN_BASE(i), + VALUE_TO_REG(data->pwm_mask, i)); + if (ret < 0) + return ret; + + ret = regmap_write(data->regmap, NCT7363_REG_FANINEN_BASE(i), + VALUE_TO_REG(data->fanin_mask, i)); + if (ret < 0) + return ret; + } + + return 0; +} + +static int nct7363_present_pwm_fanin(struct device *dev, + struct device_node *child, + struct nct7363_data *data) +{ + u8 fanin_ch[NCT7363_PWM_COUNT]; + struct of_phandle_args args; + int ret, fanin_cnt; + u8 ch, index; + + ret = of_parse_phandle_with_args(child, "pwms", "#pwm-cells", + 0, &args); + if (ret) + return ret; + + if (args.args[0] >= NCT7363_PWM_COUNT) + return -EINVAL; + data->pwm_mask |= BIT(args.args[0]); + + fanin_cnt = of_property_count_u8_elems(child, "tach-ch"); + if (fanin_cnt < 1 || fanin_cnt > NCT7363_PWM_COUNT) + return -EINVAL; + + ret = of_property_read_u8_array(child, "tach-ch", fanin_ch, fanin_cnt); + if (ret) + return ret; + + for (ch = 0; ch < fanin_cnt; ch++) { + index = fanin_ch[ch]; + if (index >= NCT7363_PWM_COUNT) + return -EINVAL; + data->fanin_mask |= BIT(index); + } + + return 0; +} + +static bool nct7363_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NCT7363_REG_LSRS(0) ... NCT7363_REG_LSRS(15): + case NCT7363_REG_FANINX_HVAL(0) ... NCT7363_REG_FANINX_LVAL(15): + case NCT7363_REG_FANINX_HL(0) ... NCT7363_REG_FANINX_LL(15): + case NCT7363_REG_FSCPXDUTY(0) ... NCT7363_REG_FSCPXDIV(15): + return true; + default: + return false; + } +} + +static const struct regmap_config nct7363_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = nct7363_regmap_is_volatile, +}; + +static int nct7363_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device_node *child; + struct nct7363_data *data; + struct device *hwmon_dev; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->regmap = devm_regmap_init_i2c(client, &nct7363_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + for_each_child_of_node(dev->of_node, child) { + ret = nct7363_present_pwm_fanin(dev, child, data); + if (ret) { + of_node_put(child); + return ret; + } + } + + /* Initialize the chip */ + ret = nct7363_init_chip(data); + if (ret) + return ret; + + hwmon_dev = + devm_hwmon_device_register_with_info(dev, client->name, data, + &nct7363_chip_info, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static struct i2c_driver nct7363_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "nct7363", + .of_match_table = nct7363_of_match, + }, + .probe = nct7363_probe, +}; + +module_i2c_driver(nct7363_driver); + +MODULE_AUTHOR("CW Ho "); +MODULE_AUTHOR("Ban Feng "); +MODULE_DESCRIPTION("NCT7363 Hardware Monitoring Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/nzxt-kraken2.c b/drivers/hwmon/nzxt-kraken2.c index ed38645a1dc272..03469823275861 100644 --- a/drivers/hwmon/nzxt-kraken2.c +++ b/drivers/hwmon/nzxt-kraken2.c @@ -35,13 +35,6 @@ struct kraken2_priv_data { unsigned long updated; /* jiffies */ }; -static umode_t kraken2_is_visible(const void *data, - enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static int kraken2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -81,7 +74,7 @@ static int kraken2_read_string(struct device *dev, enum hwmon_sensor_types type, } static const struct hwmon_ops kraken2_hwmon_ops = { - .is_visible = kraken2_is_visible, + .visible = 0444, .read = kraken2_read, .read_string = kraken2_read_string, }; diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c index b5993c79c09ea6..89761a9c8892fe 100644 --- a/drivers/hwmon/occ/p9_sbe.c +++ b/drivers/hwmon/occ/p9_sbe.c @@ -192,8 +192,8 @@ static struct platform_driver p9_sbe_occ_driver = { .name = "occ-hwmon", .of_match_table = p9_sbe_occ_of_match, }, - .probe = p9_sbe_occ_probe, - .remove_new = p9_sbe_occ_remove, + .probe = p9_sbe_occ_probe, + .remove = p9_sbe_occ_remove, }; module_platform_driver(p9_sbe_occ_driver); diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 788b5d58f77eaf..0f8aa6b42164f4 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -1606,7 +1606,7 @@ static struct platform_driver pc87360_driver = { .name = DRIVER_NAME, }, .probe = pc87360_probe, - .remove_new = pc87360_remove, + .remove = pc87360_remove, }; /* diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 7bca04eb4ee4f5..571402a89368a5 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -1129,7 +1129,7 @@ static struct platform_driver pc87427_driver = { .name = DRVNAME, }, .probe = pc87427_probe, - .remove_new = pc87427_remove, + .remove = pc87427_remove, }; static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c index 5a682195b98f4c..c7112dbf008b77 100644 --- a/drivers/hwmon/peci/cputemp.c +++ b/drivers/hwmon/peci/cputemp.c @@ -607,4 +607,4 @@ MODULE_AUTHOR("Jae Hyun Yoo "); MODULE_AUTHOR("Iwona Winiarska "); MODULE_DESCRIPTION("PECI cputemp driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PECI_CPU); +MODULE_IMPORT_NS("PECI_CPU"); diff --git a/drivers/hwmon/peci/dimmtemp.c b/drivers/hwmon/peci/dimmtemp.c index 4a72e9712408e2..d6762259dd69c1 100644 --- a/drivers/hwmon/peci/dimmtemp.c +++ b/drivers/hwmon/peci/dimmtemp.c @@ -666,4 +666,4 @@ MODULE_AUTHOR("Jae Hyun Yoo "); MODULE_AUTHOR("Iwona Winiarska "); MODULE_DESCRIPTION("PECI dimmtemp driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PECI_CPU); +MODULE_IMPORT_NS("PECI_CPU"); diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index a4f02cad92fdad..f6d3528419536a 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -224,9 +224,9 @@ config SENSORS_LTC2978_REGULATOR depends on SENSORS_LTC2978 && REGULATOR help If you say yes here you get regulator support for Linear Technology - LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7880, - LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4686, - and LTM4700. + LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7841, + LTC7880, LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, + LTM4686, and LTM4700. config SENSORS_LTC3815 tristate "Linear Technologies LTC3815" diff --git a/drivers/hwmon/pmbus/acbel-fsg032.c b/drivers/hwmon/pmbus/acbel-fsg032.c index e0c55fd8f3a6dc..9f07fb4abaffd4 100644 --- a/drivers/hwmon/pmbus/acbel-fsg032.c +++ b/drivers/hwmon/pmbus/acbel-fsg032.c @@ -120,4 +120,4 @@ module_i2c_driver(acbel_fsg032_driver); MODULE_AUTHOR("Lakshmi Yadlapati"); MODULE_DESCRIPTION("PMBus driver for AcBel Power System power supplies"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index 2c4d94cc872943..d90f8f80be8e00 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -509,4 +509,4 @@ module_i2c_driver(adm1266_driver); MODULE_AUTHOR("Alexandru Tachici "); MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1266"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 59ffc08289bdf7..127593e10a03f2 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -866,4 +866,4 @@ module_i2c_driver(adm1275_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/adp1050.c b/drivers/hwmon/pmbus/adp1050.c index 20f22730fc0189..ef46c880b168bd 100644 --- a/drivers/hwmon/pmbus/adp1050.c +++ b/drivers/hwmon/pmbus/adp1050.c @@ -53,4 +53,4 @@ module_i2c_driver(adp1050_driver); MODULE_AUTHOR("Radu Sabau "); MODULE_DESCRIPTION("Analog Devices ADP1050 HWMON PMBus Driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c index 7c5f4b10a7c14e..ddf9d9a2958c4f 100644 --- a/drivers/hwmon/pmbus/bel-pfe.c +++ b/drivers/hwmon/pmbus/bel-pfe.c @@ -129,4 +129,4 @@ module_i2c_driver(pfe_pmbus_driver); MODULE_AUTHOR("Tao Ren "); MODULE_DESCRIPTION("PMBus driver for BEL PFE Family Power Supplies"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/bpa-rs600.c b/drivers/hwmon/pmbus/bpa-rs600.c index 0dce26c3555658..6c3875ba37a081 100644 --- a/drivers/hwmon/pmbus/bpa-rs600.c +++ b/drivers/hwmon/pmbus/bpa-rs600.c @@ -205,4 +205,4 @@ module_i2c_driver(bpa_rs600_driver); MODULE_AUTHOR("Chris Packham"); MODULE_DESCRIPTION("PMBus driver for BluTek BPA-RS600"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/delta-ahe50dc-fan.c b/drivers/hwmon/pmbus/delta-ahe50dc-fan.c index 4dd3b6686d6a44..3850eaea75da2a 100644 --- a/drivers/hwmon/pmbus/delta-ahe50dc-fan.c +++ b/drivers/hwmon/pmbus/delta-ahe50dc-fan.c @@ -127,4 +127,4 @@ module_i2c_driver(ahe50dc_fan_driver); MODULE_AUTHOR("Zev Weiss "); MODULE_DESCRIPTION("Driver for Delta AHE-50DC power shelf fan control module"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c index 04e0d598a6e544..cc5aac9dfdb3c8 100644 --- a/drivers/hwmon/pmbus/dps920ab.c +++ b/drivers/hwmon/pmbus/dps920ab.c @@ -203,4 +203,4 @@ module_i2c_driver(dps920ab_driver); MODULE_AUTHOR("Robert Marko "); MODULE_DESCRIPTION("PMBus driver for Delta DPS920AB PSU"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/fsp-3y.c b/drivers/hwmon/pmbus/fsp-3y.c index 72a7c261ef068d..a4dc09e2ef75ac 100644 --- a/drivers/hwmon/pmbus/fsp-3y.c +++ b/drivers/hwmon/pmbus/fsp-3y.c @@ -291,4 +291,4 @@ module_i2c_driver(fsp3y_driver); MODULE_AUTHOR("Václav Kubernát"); MODULE_DESCRIPTION("PMBus driver for FSP/3Y-Power power supplies"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index 1ba4c5e95820f2..d05ef7a968a965 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -614,4 +614,4 @@ module_i2c_driver(ibm_cffps_driver); MODULE_AUTHOR("Eddie James"); MODULE_DESCRIPTION("PMBus driver for IBM Common Form Factor power supplies"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c index 3e3cc9a0f116e7..074e0f164ee1c9 100644 --- a/drivers/hwmon/pmbus/inspur-ipsps.c +++ b/drivers/hwmon/pmbus/inspur-ipsps.c @@ -224,4 +224,4 @@ module_i2c_driver(ipsps_driver); MODULE_AUTHOR("John Wang"); MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index 503be59c6c7f19..46d8f334d49a45 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -145,4 +145,4 @@ module_i2c_driver(ir35221_driver); MODULE_AUTHOR("Samuel Mendoza-Jonas "); MODULE_DESCRIPTION("PMBus driver for Infineon IR36021"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c index d4bcc9c39774ec..7b4188e8bf4830 100644 --- a/drivers/hwmon/pmbus/ir38064.c +++ b/drivers/hwmon/pmbus/ir38064.c @@ -87,4 +87,4 @@ module_i2c_driver(ir38064_driver); MODULE_AUTHOR("Maxim Sloyko "); MODULE_DESCRIPTION("PMBus driver for Infineon IR38064 and compatible chips"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c index f0bdf55c95bf4d..43674c64841d5c 100644 --- a/drivers/hwmon/pmbus/irps5401.c +++ b/drivers/hwmon/pmbus/irps5401.c @@ -63,4 +63,4 @@ module_i2c_driver(irps5401_driver); MODULE_AUTHOR("Robert Hancock"); MODULE_DESCRIPTION("PMBus driver for Infineon IRPS5401"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 7e53fb1d5ea303..2af921039309a6 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #define ISL68137_VOUT_AVS 0x30 #define RAA_DMPVR2_READ_VMON 0xc8 +#define MAX_CHANNELS 4 enum chips { isl68137, @@ -72,6 +74,17 @@ enum variants { raa_dmpvr2_hv, }; +struct isl68137_channel { + u32 vout_voltage_divider[2]; +}; + +struct isl68137_data { + struct pmbus_driver_info info; + struct isl68137_channel channel[MAX_CHANNELS]; +}; + +#define to_isl68137_data(x) container_of(x, struct isl68137_data, info) + static const struct i2c_device_id raa_dmpvr_id[]; static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, @@ -163,13 +176,32 @@ static const struct attribute_group *isl68137_attribute_groups[] = { static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, int phase, int reg) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct isl68137_data *data = to_isl68137_data(info); int ret; + u64 temp; switch (reg) { case PMBUS_VIRT_READ_VMON: ret = pmbus_read_word_data(client, page, phase, RAA_DMPVR2_READ_VMON); break; + case PMBUS_READ_POUT: + case PMBUS_READ_VOUT: + /* + * In cases where a voltage divider is attached to the target + * rail between Vout and the Vsense pin, both Vout and Pout + * should be scaled by the voltage divider scaling factor. + * I.e. Vout = Vsense * Rtotal / Rout + */ + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret > 0) { + temp = DIV_U64_ROUND_CLOSEST((u64)ret * + data->channel[page].vout_voltage_divider[1], + data->channel[page].vout_voltage_divider[0]); + ret = clamp_val(temp, 0, 0xffff); + } + break; default: ret = -ENODATA; break; @@ -178,6 +210,40 @@ static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page, return ret; } +static int raa_dmpvr2_write_word_data(struct i2c_client *client, int page, + int reg, u16 word) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct isl68137_data *data = to_isl68137_data(info); + int ret; + u64 temp; + + switch (reg) { + case PMBUS_VOUT_MAX: + case PMBUS_VOUT_MARGIN_HIGH: + case PMBUS_VOUT_MARGIN_LOW: + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + case PMBUS_VOUT_COMMAND: + /* + * In cases where a voltage divider is attached to the target + * rail between Vout and the Vsense pin, Vout related PMBus + * commands should be scaled based on the expected voltage + * at the Vsense pin. + * I.e. Vsense = Vout * Rout / Rtotal + */ + temp = DIV_U64_ROUND_CLOSEST((u64)word * + data->channel[page].vout_voltage_divider[0], + data->channel[page].vout_voltage_divider[1]); + ret = clamp_val(temp, 0, 0xffff); + break; + default: + ret = -ENODATA; + break; + } + return ret; +} + static struct pmbus_driver_info raa_dmpvr_info = { .pages = 3, .format[PSC_VOLTAGE_IN] = direct, @@ -220,14 +286,90 @@ static struct pmbus_driver_info raa_dmpvr_info = { | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, }; +static int isl68137_probe_child_from_dt(struct device *dev, + struct device_node *child, + struct isl68137_data *data) +{ + u32 channel, rout, rtotal; + int err; + + err = of_property_read_u32(child, "reg", &channel); + if (err) { + dev_err(dev, "missing reg property of %pOFn\n", child); + return err; + } + if (channel >= data->info.pages) { + dev_err(dev, "invalid reg %d of %pOFn\n", channel, child); + return -EINVAL; + } + + err = of_property_read_u32_array(child, "vout-voltage-divider", + data->channel[channel].vout_voltage_divider, + ARRAY_SIZE(data->channel[channel].vout_voltage_divider)); + if (err && err != -EINVAL) { + dev_err(dev, + "malformed vout-voltage-divider value for channel %d\n", + channel); + return err; + } + + rout = data->channel[channel].vout_voltage_divider[0]; + rtotal = data->channel[channel].vout_voltage_divider[1]; + if (rout == 0) { + dev_err(dev, + "Voltage divider output resistance must be greater than 0\n"); + return -EINVAL; + } + if (rtotal < rout) { + dev_err(dev, + "Voltage divider total resistance is less than output resistance\n"); + return -EINVAL; + } + + return 0; +} + +static int isl68137_probe_from_dt(struct device *dev, + struct isl68137_data *data) +{ + const struct device_node *np = dev->of_node; + struct device_node *child; + int err; + + for_each_child_of_node(np, child) { + if (strcmp(child->name, "channel")) + continue; + + err = isl68137_probe_child_from_dt(dev, child, data); + if (err) + return err; + } + + return 0; +} + static int isl68137_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct pmbus_driver_info *info; + struct isl68137_data *data; + int i, err; - info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); - if (!info) + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) return -ENOMEM; - memcpy(info, &raa_dmpvr_info, sizeof(*info)); + + /* + * Initialize all voltage dividers to Rout=1 and Rtotal=1 to simplify + * logic in PMBus word read/write functions + */ + for (i = 0; i < MAX_CHANNELS; i++) + memset(data->channel[i].vout_voltage_divider, + 1, + sizeof(data->channel[i].vout_voltage_divider)); + + memcpy(&data->info, &raa_dmpvr_info, sizeof(data->info)); + info = &data->info; switch (i2c_match_id(raa_dmpvr_id, client)->driver_data) { case raa_dmpvr1_2rail: @@ -237,11 +379,14 @@ static int isl68137_probe(struct i2c_client *client) info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT; + info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; info->groups = isl68137_attribute_groups; break; case raa_dmpvr2_1rail: info->pages = 1; info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; break; case raa_dmpvr2_2rail_nontc: info->func[0] &= ~PMBUS_HAVE_TEMP3; @@ -250,9 +395,11 @@ static int isl68137_probe(struct i2c_client *client) case raa_dmpvr2_2rail: info->pages = 2; info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; break; case raa_dmpvr2_3rail: info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; break; case raa_dmpvr2_hv: info->pages = 1; @@ -263,11 +410,16 @@ static int isl68137_probe(struct i2c_client *client) info->m[PSC_POWER] = 2; info->R[PSC_POWER] = -1; info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; break; default: return -ENODEV; } + err = isl68137_probe_from_dt(dev, data); + if (err) + return err; + return pmbus_do_probe(client, info); } @@ -318,11 +470,59 @@ static const struct i2c_device_id raa_dmpvr_id[] = { MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id); +static const struct of_device_id isl68137_of_match[] = { + { .compatible = "isil,isl68137", .data = (void *)raa_dmpvr1_2rail }, + { .compatible = "renesas,isl68220", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68221", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl68222", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68223", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68224", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl68225", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68226", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl68227", .data = (void *)raa_dmpvr2_1rail }, + { .compatible = "renesas,isl68229", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl68233", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl68239", .data = (void *)raa_dmpvr2_3rail }, + + { .compatible = "renesas,isl69222", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69223", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69224", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69225", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69227", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69228", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69234", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69236", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69239", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69242", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69243", .data = (void *)raa_dmpvr2_1rail }, + { .compatible = "renesas,isl69247", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69248", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69254", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69255", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69256", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69259", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "isil,isl69260", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,isl69268", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "isil,isl69269", .data = (void *)raa_dmpvr2_3rail }, + { .compatible = "renesas,isl69298", .data = (void *)raa_dmpvr2_2rail }, + + { .compatible = "renesas,raa228000", .data = (void *)raa_dmpvr2_hv }, + { .compatible = "renesas,raa228004", .data = (void *)raa_dmpvr2_hv }, + { .compatible = "renesas,raa228006", .data = (void *)raa_dmpvr2_hv }, + { .compatible = "renesas,raa228228", .data = (void *)raa_dmpvr2_2rail_nontc }, + { .compatible = "renesas,raa229001", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,raa229004", .data = (void *)raa_dmpvr2_2rail }, + { }, +}; + +MODULE_DEVICE_TABLE(of, isl68137_of_match); + /* This is the driver that will be inserted */ static struct i2c_driver isl68137_driver = { .driver = { - .name = "isl68137", - }, + .name = "isl68137", + .of_match_table = isl68137_of_match, + }, .probe = isl68137_probe, .id_table = raa_dmpvr_id, }; @@ -332,4 +532,4 @@ module_i2c_driver(isl68137_driver); MODULE_AUTHOR("Maxim Sloyko "); MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index c36c124d1a2d86..40b0dda32ea6f0 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -569,4 +569,4 @@ module_i2c_driver(lm25066_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for LM25066 and compatible chips"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/lt7182s.c b/drivers/hwmon/pmbus/lt7182s.c index aebd97af274172..9d6d50f39bd653 100644 --- a/drivers/hwmon/pmbus/lt7182s.c +++ b/drivers/hwmon/pmbus/lt7182s.c @@ -192,4 +192,4 @@ module_i2c_driver(lt7182s_driver); MODULE_AUTHOR("Guenter Roeck "); MODULE_DESCRIPTION("PMBus driver for Analog Devices LT7182S"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 73a86f4d647288..4c306943383ab3 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -23,7 +23,8 @@ enum chips { /* Managers */ ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980, /* Controllers */ - ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, ltc7880, + ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, + ltc7841, ltc7880, /* Modules */ ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686, ltm4700, @@ -50,7 +51,7 @@ enum chips { #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 -/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7880 */ +/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7841 and LTC7880 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 /* LTC2975 only */ @@ -80,6 +81,7 @@ enum chips { #define LTC3887_ID 0x4700 #define LTC3889_ID 0x4900 #define LTC7132_ID 0x4CE0 +#define LTC7841_ID 0x40D0 #define LTC7880_ID 0x49E0 #define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ #define LTM2987_ID_B 0x8020 @@ -548,6 +550,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3887", ltc3887}, {"ltc3889", ltc3889}, {"ltc7132", ltc7132}, + {"ltc7841", ltc7841}, {"ltc7880", ltc7880}, {"ltm2987", ltm2987}, {"ltm4664", ltm4664}, @@ -654,6 +657,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3889; else if (chip_id == LTC7132_ID) return ltc7132; + else if (chip_id == LTC7841_ID) + return ltc7841; else if (chip_id == LTC7880_ID) return ltc7880; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) @@ -854,6 +859,16 @@ static int ltc2978_probe(struct i2c_client *client) | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; + case ltc7841: + data->features |= FEAT_CLEAR_PEAKS; + info->read_word_data = ltc3883_read_word_data; + info->pages = LTC3883_NUM_PAGES; + info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + break; default: return -ENODEV; } @@ -907,6 +922,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltc3889" }, { .compatible = "lltc,ltc7132" }, + { .compatible = "lltc,ltc7841" }, { .compatible = "lltc,ltc7880" }, { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4664" }, @@ -936,4 +952,4 @@ module_i2c_driver(ltc2978_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for LTC2978 and compatible chips"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index f58a8cedb0d7e3..824c16a75e2c01 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -208,4 +208,4 @@ module_i2c_driver(ltc3815_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for LTC3815"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max15301.c b/drivers/hwmon/pmbus/max15301.c index f5367a7bc0f519..50dfd477772ffe 100644 --- a/drivers/hwmon/pmbus/max15301.c +++ b/drivers/hwmon/pmbus/max15301.c @@ -97,4 +97,4 @@ module_i2c_driver(max15301_driver); MODULE_AUTHOR("Erik Rosen "); MODULE_DESCRIPTION("PMBus driver for Maxim MAX15301"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index 98e2b5dd58414d..eb84915c2a83de 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -111,4 +111,4 @@ module_i2c_driver(max16064_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index 3ab2195046007a..d696e506aafba3 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -366,4 +366,4 @@ module_i2c_driver(max16601_driver); MODULE_AUTHOR("Guenter Roeck "); MODULE_DESCRIPTION("PMBus driver for Maxim MAX16601"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index d56ec24764fdd6..95869d198ecf0a 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -787,4 +787,4 @@ module_i2c_driver(max20730_driver); MODULE_AUTHOR("Guenter Roeck "); MODULE_DESCRIPTION("PMBus driver for Maxim MAX20710 / MAX20730 / MAX20734 / MAX20743"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c index 8f23c1eb559e89..ac8c431221338b 100644 --- a/drivers/hwmon/pmbus/max20751.c +++ b/drivers/hwmon/pmbus/max20751.c @@ -51,4 +51,4 @@ module_i2c_driver(max20751_driver); MODULE_AUTHOR("Guenter Roeck "); MODULE_DESCRIPTION("PMBus driver for Maxim MAX20751"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index 09218dba89658e..1f94d38a163719 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -549,4 +549,4 @@ module_i2c_driver(max31785_driver); MODULE_AUTHOR("Andrew Jeffery "); MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index fe7f6b1b09851e..c9dda33831ff24 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -529,4 +529,4 @@ module_i2c_driver(max34440_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index 5d5b6aeefa804d..b3a2a7492bbfcf 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -191,4 +191,4 @@ module_i2c_driver(max8688_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp2856.c b/drivers/hwmon/pmbus/mp2856.c index 41bb8666709128..e83c70a3583f80 100644 --- a/drivers/hwmon/pmbus/mp2856.c +++ b/drivers/hwmon/pmbus/mp2856.c @@ -463,4 +463,4 @@ module_i2c_driver(mp2856_driver); MODULE_AUTHOR("Peter Yin "); MODULE_DESCRIPTION("PMBus driver for MPS MP2856/MP2857 device"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp2888.c b/drivers/hwmon/pmbus/mp2888.c index 3b45f126b611ce..772a623ca7d0a1 100644 --- a/drivers/hwmon/pmbus/mp2888.c +++ b/drivers/hwmon/pmbus/mp2888.c @@ -404,4 +404,4 @@ module_i2c_driver(mp2888_driver); MODULE_AUTHOR("Vadim Pasternak "); MODULE_DESCRIPTION("PMBus driver for MPS MP2888 device"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp2891.c b/drivers/hwmon/pmbus/mp2891.c index bb28b15a910384..f8f4c91ec23ccd 100644 --- a/drivers/hwmon/pmbus/mp2891.c +++ b/drivers/hwmon/pmbus/mp2891.c @@ -572,8 +572,8 @@ static int mp2891_probe(struct i2c_client *client) } static const struct i2c_device_id mp2891_id[] = { - {"mp2891", 0}, - {} + { "mp2891" }, + { } }; MODULE_DEVICE_TABLE(i2c, mp2891_id); @@ -597,4 +597,4 @@ module_i2c_driver(mp2891_driver); MODULE_AUTHOR("Noah Wang "); MODULE_DESCRIPTION("PMBus driver for MPS MP2891"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c index 280bb12f762c3d..c31982d8519623 100644 --- a/drivers/hwmon/pmbus/mp2975.c +++ b/drivers/hwmon/pmbus/mp2975.c @@ -1101,4 +1101,4 @@ module_i2c_driver(mp2975_driver); MODULE_AUTHOR("Vadim Pasternak "); MODULE_DESCRIPTION("PMBus driver for MPS MP2975 device"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp2993.c b/drivers/hwmon/pmbus/mp2993.c index 944593e13231fa..81c84fc8ed47d2 100644 --- a/drivers/hwmon/pmbus/mp2993.c +++ b/drivers/hwmon/pmbus/mp2993.c @@ -233,8 +233,8 @@ static int mp2993_probe(struct i2c_client *client) } static const struct i2c_device_id mp2993_id[] = { - {"mp2993", 0}, - {} + { "mp2993" }, + { } }; MODULE_DEVICE_TABLE(i2c, mp2993_id); @@ -258,4 +258,4 @@ module_i2c_driver(mp2993_driver); MODULE_AUTHOR("Noah Wang "); MODULE_DESCRIPTION("PMBus driver for MPS MP2993"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp5023.c b/drivers/hwmon/pmbus/mp5023.c index 21acb7fd9a1afe..c466d67e9a8f90 100644 --- a/drivers/hwmon/pmbus/mp5023.c +++ b/drivers/hwmon/pmbus/mp5023.c @@ -64,4 +64,4 @@ module_i2c_driver(mp5023_driver); MODULE_AUTHOR("Howard Chiu "); MODULE_DESCRIPTION("PMBus driver for MPS MP5023 HSC"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp5920.c b/drivers/hwmon/pmbus/mp5920.c index f6d7527ade7d90..319ae2721bcf45 100644 --- a/drivers/hwmon/pmbus/mp5920.c +++ b/drivers/hwmon/pmbus/mp5920.c @@ -87,4 +87,4 @@ MODULE_AUTHOR("Tony Ao "); MODULE_AUTHOR("Alex Vdovydchenko "); MODULE_DESCRIPTION("PMBus driver for MP5920 HSC"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp5990.c b/drivers/hwmon/pmbus/mp5990.c index 5d1d5eac89daa9..4ce381a394807e 100644 --- a/drivers/hwmon/pmbus/mp5990.c +++ b/drivers/hwmon/pmbus/mp5990.c @@ -176,4 +176,4 @@ module_i2c_driver(mp5990_driver); MODULE_AUTHOR("Peter Yin "); MODULE_DESCRIPTION("PMBus driver for MP5990 HSC"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp9941.c b/drivers/hwmon/pmbus/mp9941.c index 543955cfce67e8..42ca6748777afd 100644 --- a/drivers/hwmon/pmbus/mp9941.c +++ b/drivers/hwmon/pmbus/mp9941.c @@ -291,8 +291,8 @@ static int mp9941_probe(struct i2c_client *client) } static const struct i2c_device_id mp9941_id[] = { - {"mp9941", 0}, - {} + { "mp9941" }, + { } }; MODULE_DEVICE_TABLE(i2c, mp9941_id); @@ -316,4 +316,4 @@ module_i2c_driver(mp9941_driver); MODULE_AUTHOR("Noah Wang "); MODULE_DESCRIPTION("PMBus driver for MPS MP9941"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c index 2dcb6da853bd34..c1e2d0cb2fd086 100644 --- a/drivers/hwmon/pmbus/mpq7932.c +++ b/drivers/hwmon/pmbus/mpq7932.c @@ -164,4 +164,4 @@ module_i2c_driver(mpq7932_regulator_driver); MODULE_AUTHOR("Saravanan Sekar "); MODULE_DESCRIPTION("MPQ7932 PMIC regulator driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mpq8785.c b/drivers/hwmon/pmbus/mpq8785.c index 7f87e117b49deb..331c274ca89226 100644 --- a/drivers/hwmon/pmbus/mpq8785.c +++ b/drivers/hwmon/pmbus/mpq8785.c @@ -22,7 +22,7 @@ static int mpq8785_identify(struct i2c_client *client, break; case 1: case 2: - info->format[PSC_VOLTAGE_OUT] = direct, + info->format[PSC_VOLTAGE_OUT] = direct; info->m[PSC_VOLTAGE_OUT] = 64; info->b[PSC_VOLTAGE_OUT] = 0; info->R[PSC_VOLTAGE_OUT] = 1; @@ -87,4 +87,4 @@ module_i2c_driver(mpq8785_driver); MODULE_AUTHOR("Charles Hsu "); MODULE_DESCRIPTION("PMBus driver for MPS MPQ8785"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/pim4328.c b/drivers/hwmon/pmbus/pim4328.c index 31d9ae06379a1a..aa98284bbdd847 100644 --- a/drivers/hwmon/pmbus/pim4328.c +++ b/drivers/hwmon/pmbus/pim4328.c @@ -230,4 +230,4 @@ module_i2c_driver(pim4328_driver); MODULE_AUTHOR("Erik Rosen "); MODULE_DESCRIPTION("PMBus driver for PIM4006, PIM4328, PIM4820 power interface modules"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/pli1209bc.c b/drivers/hwmon/pmbus/pli1209bc.c index 178e0cdb7887ef..569b61dc1a32a6 100644 --- a/drivers/hwmon/pmbus/pli1209bc.c +++ b/drivers/hwmon/pmbus/pli1209bc.c @@ -145,4 +145,4 @@ module_i2c_driver(pli1209bc_driver); MODULE_AUTHOR("Marcello Sylvester Bauer "); MODULE_DESCRIPTION("PMBus driver for Vicor PLI1209BC"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/pm6764tr.c b/drivers/hwmon/pmbus/pm6764tr.c index 23f15b608dcf12..c96c0aecb920a8 100644 --- a/drivers/hwmon/pmbus/pm6764tr.c +++ b/drivers/hwmon/pmbus/pm6764tr.c @@ -73,4 +73,4 @@ module_i2c_driver(pm6764tr_driver); MODULE_AUTHOR("Charles Hsu"); MODULE_DESCRIPTION("PMBus driver for ST PM6764TR"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index ec40c5c599543a..77cf268e7d2d6d 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -261,4 +261,4 @@ module_i2c_driver(pmbus_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("Generic PMBus driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index ce7fd4ca9d89b0..a1375cb6b648c1 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -150,7 +150,7 @@ void pmbus_clear_cache(struct i2c_client *client) for (sensor = data->sensors; sensor; sensor = sensor->next) sensor->data = -ENODATA; } -EXPORT_SYMBOL_NS_GPL(pmbus_clear_cache, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_clear_cache, "PMBUS"); void pmbus_set_update(struct i2c_client *client, u8 reg, bool update) { @@ -161,7 +161,7 @@ void pmbus_set_update(struct i2c_client *client, u8 reg, bool update) if (sensor->reg == reg) sensor->update = update; } -EXPORT_SYMBOL_NS_GPL(pmbus_set_update, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_set_update, "PMBUS"); /* Some chips need a delay between accesses. */ static void pmbus_wait(struct i2c_client *client) @@ -236,7 +236,7 @@ int pmbus_set_page(struct i2c_client *client, int page, int phase) return 0; } -EXPORT_SYMBOL_NS_GPL(pmbus_set_page, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_set_page, "PMBUS"); int pmbus_write_byte(struct i2c_client *client, int page, u8 value) { @@ -252,7 +252,7 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value) return rv; } -EXPORT_SYMBOL_NS_GPL(pmbus_write_byte, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_write_byte, "PMBUS"); /* * _pmbus_write_byte() is similar to pmbus_write_byte(), but checks if @@ -287,7 +287,7 @@ int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, return rv; } -EXPORT_SYMBOL_NS_GPL(pmbus_write_word_data, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_write_word_data, "PMBUS"); static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg, @@ -393,7 +393,7 @@ int pmbus_update_fan(struct i2c_client *client, int page, int id, return _pmbus_write_word_data(client, page, pmbus_fan_command_registers[id], command); } -EXPORT_SYMBOL_NS_GPL(pmbus_update_fan, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_update_fan, "PMBUS"); int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) { @@ -409,7 +409,7 @@ int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) return rv; } -EXPORT_SYMBOL_NS_GPL(pmbus_read_word_data, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_read_word_data, "PMBUS"); static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg) { @@ -472,7 +472,7 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg) return rv; } -EXPORT_SYMBOL_NS_GPL(pmbus_read_byte_data, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_read_byte_data, "PMBUS"); int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) { @@ -488,7 +488,7 @@ int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value) return rv; } -EXPORT_SYMBOL_NS_GPL(pmbus_write_byte_data, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_write_byte_data, "PMBUS"); int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, u8 mask, u8 value) @@ -507,7 +507,7 @@ int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, return rv; } -EXPORT_SYMBOL_NS_GPL(pmbus_update_byte_data, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_update_byte_data, "PMBUS"); static int pmbus_read_block_data(struct i2c_client *client, int page, u8 reg, char *data_buf) @@ -578,14 +578,14 @@ int pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, { return pmbus_get_fan_rate(client, page, id, mode, false); } -EXPORT_SYMBOL_NS_GPL(pmbus_get_fan_rate_device, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_get_fan_rate_device, "PMBUS"); int pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, enum pmbus_fan_mode mode) { return pmbus_get_fan_rate(client, page, id, mode, true); } -EXPORT_SYMBOL_NS_GPL(pmbus_get_fan_rate_cached, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_get_fan_rate_cached, "PMBUS"); static void pmbus_clear_fault_page(struct i2c_client *client, int page) { @@ -600,7 +600,7 @@ void pmbus_clear_faults(struct i2c_client *client) for (i = 0; i < data->info->pages; i++) pmbus_clear_fault_page(client, i); } -EXPORT_SYMBOL_NS_GPL(pmbus_clear_faults, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_clear_faults, "PMBUS"); static int pmbus_check_status_cml(struct i2c_client *client) { @@ -655,13 +655,13 @@ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg) { return pmbus_check_register(client, _pmbus_read_byte_data, page, reg); } -EXPORT_SYMBOL_NS_GPL(pmbus_check_byte_register, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_check_byte_register, "PMBUS"); bool pmbus_check_word_register(struct i2c_client *client, int page, int reg) { return pmbus_check_register(client, __pmbus_read_word_data, page, reg); } -EXPORT_SYMBOL_NS_GPL(pmbus_check_word_register, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_check_word_register, "PMBUS"); static bool __maybe_unused pmbus_check_block_register(struct i2c_client *client, int page, int reg) @@ -685,7 +685,7 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) return data->info; } -EXPORT_SYMBOL_NS_GPL(pmbus_get_driver_info, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_get_driver_info, "PMBUS"); static int pmbus_get_status(struct i2c_client *client, int page, int reg) { @@ -2719,9 +2719,7 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, * limit registers need to be disabled. */ if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) { - pmbus_wait(client); - ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT); - pmbus_update_ts(client, false); + ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT); if (ret > 0 && (ret & PB_WP_ANY)) data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; @@ -3219,7 +3217,7 @@ const struct regulator_ops pmbus_regulator_ops = { .set_voltage = pmbus_regulator_set_voltage, .list_voltage = pmbus_regulator_list_voltage, }; -EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, "PMBUS"); static int pmbus_regulator_register(struct pmbus_data *data) { @@ -3279,7 +3277,17 @@ static int pmbus_regulator_notify(struct pmbus_data *data, int page, int event) static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, u8 val) { - return _pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8)); + int ret; + + ret = _pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8)); + + /* + * Clear fault systematically in case writing PMBUS_SMBALERT_MASK + * is not supported by the chip. + */ + pmbus_clear_fault_page(client, page); + + return ret; } static irqreturn_t pmbus_fault_handler(int irq, void *pdata) @@ -3735,7 +3743,7 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) return 0; } -EXPORT_SYMBOL_NS_GPL(pmbus_do_probe, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_do_probe, "PMBUS"); struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client) { @@ -3743,7 +3751,7 @@ struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client) return data->debugfs; } -EXPORT_SYMBOL_NS_GPL(pmbus_get_debugfs_dir, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_get_debugfs_dir, "PMBUS"); int pmbus_lock_interruptible(struct i2c_client *client) { @@ -3751,7 +3759,7 @@ int pmbus_lock_interruptible(struct i2c_client *client) return mutex_lock_interruptible(&data->update_lock); } -EXPORT_SYMBOL_NS_GPL(pmbus_lock_interruptible, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_lock_interruptible, "PMBUS"); void pmbus_unlock(struct i2c_client *client) { @@ -3759,7 +3767,7 @@ void pmbus_unlock(struct i2c_client *client) mutex_unlock(&data->update_lock); } -EXPORT_SYMBOL_NS_GPL(pmbus_unlock, PMBUS); +EXPORT_SYMBOL_NS_GPL(pmbus_unlock, "PMBUS"); static int __init pmbus_core_init(void) { diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c index 5ac476d3cdd2a9..6a4a978eca7e89 100644 --- a/drivers/hwmon/pmbus/pxe1610.c +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -148,4 +148,4 @@ module_i2c_driver(pxe1610_driver); MODULE_AUTHOR("Vijay Khemka "); MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c index a235c1cdf4fec5..4d7086d83aa366 100644 --- a/drivers/hwmon/pmbus/q54sj108a2.c +++ b/drivers/hwmon/pmbus/q54sj108a2.c @@ -421,4 +421,4 @@ module_i2c_driver(q54sj108a2_driver); MODULE_AUTHOR("Xiao.Ma "); MODULE_DESCRIPTION("PMBus driver for Delta Q54SJ108A2 series modules"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/stpddc60.c b/drivers/hwmon/pmbus/stpddc60.c index 34d0f06f48452b..5cb905ed8ae5f0 100644 --- a/drivers/hwmon/pmbus/stpddc60.c +++ b/drivers/hwmon/pmbus/stpddc60.c @@ -246,4 +246,4 @@ module_i2c_driver(stpddc60_driver); MODULE_AUTHOR("Erik Rosen "); MODULE_DESCRIPTION("PMBus driver for ST STPDDC60"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/tda38640.c b/drivers/hwmon/pmbus/tda38640.c index 044d5fbdf9eb93..07fe58c2448500 100644 --- a/drivers/hwmon/pmbus/tda38640.c +++ b/drivers/hwmon/pmbus/tda38640.c @@ -221,4 +221,4 @@ module_i2c_driver(tda38640_driver); MODULE_AUTHOR("Patrick Rudolph "); MODULE_DESCRIPTION("PMBus driver for Infineon TDA38640"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c index d99b9850ea36c1..7c9fedaa068c0b 100644 --- a/drivers/hwmon/pmbus/tps40422.c +++ b/drivers/hwmon/pmbus/tps40422.c @@ -51,4 +51,4 @@ module_i2c_driver(tps40422_driver); MODULE_AUTHOR("Zhu Laiwen "); MODULE_DESCRIPTION("PMBus driver for TI TPS40422"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 5c9466244d70d1..63524dff5e7553 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -308,4 +308,4 @@ module_i2c_driver(tps53679_driver); MODULE_AUTHOR("Vadim Pasternak "); MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/tps546d24.c b/drivers/hwmon/pmbus/tps546d24.c index 520ca37269f77e..44d7a6df1dbdfc 100644 --- a/drivers/hwmon/pmbus/tps546d24.c +++ b/drivers/hwmon/pmbus/tps546d24.c @@ -68,4 +68,4 @@ module_i2c_driver(tps546d24_driver); MODULE_AUTHOR("Duke Du "); MODULE_DESCRIPTION("PMBus driver for TI tps546d24"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 5d3d1773bf520d..9b0eadc81a2eea 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -642,4 +642,4 @@ module_i2c_driver(ucd9000_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 7920d1c06df0dc..f68adaf4a110e0 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -209,4 +209,4 @@ module_i2c_driver(ucd9200_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/xdp710.c b/drivers/hwmon/pmbus/xdp710.c index dd107e83f61254..660bbfe16e1e9d 100644 --- a/drivers/hwmon/pmbus/xdp710.c +++ b/drivers/hwmon/pmbus/xdp710.c @@ -128,4 +128,4 @@ module_i2c_driver(xdp710_driver); MODULE_AUTHOR("Peter Yin "); MODULE_DESCRIPTION("PMBus driver for XDP710 HSC"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c index facb1201aa4301..f3aa6339d60d0f 100644 --- a/drivers/hwmon/pmbus/xdpe12284.c +++ b/drivers/hwmon/pmbus/xdpe12284.c @@ -194,4 +194,4 @@ module_i2c_driver(xdpe122_driver); MODULE_AUTHOR("Vadim Pasternak "); MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/xdpe152c4.c b/drivers/hwmon/pmbus/xdpe152c4.c index 7f3b31d4f033f5..67a3d5fe1dafad 100644 --- a/drivers/hwmon/pmbus/xdpe152c4.c +++ b/drivers/hwmon/pmbus/xdpe152c4.c @@ -72,4 +72,4 @@ module_i2c_driver(xdpe152_driver); MODULE_AUTHOR("Greg Schwendimann "); MODULE_DESCRIPTION("PMBus driver for Infineon XDPE152 family"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index 7920a16203e137..97be69630cfbb4 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -420,4 +420,4 @@ module_i2c_driver(zl6100_driver); MODULE_AUTHOR("Guenter Roeck"); MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PMBUS); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/powerz.c b/drivers/hwmon/powerz.c index cfb635f94d6654..4e663d5b4e330b 100644 --- a/drivers/hwmon/powerz.c +++ b/drivers/hwmon/powerz.c @@ -54,12 +54,6 @@ static const struct hwmon_channel_info *const powerz_info[] = { NULL }; -static umode_t powerz_is_visible(const void *data, enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static int powerz_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, const char **str) { @@ -201,7 +195,7 @@ static int powerz_read(struct device *dev, enum hwmon_sensor_types type, } static const struct hwmon_ops powerz_hwmon_ops = { - .is_visible = powerz_is_visible, + .visible = 0444, .read = powerz_read, .read_string = powerz_read_string, }; diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index c434db4656e7df..53a1a968d00d4f 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -7,6 +7,7 @@ * Author: Kamil Debski */ +#include #include #include #include @@ -60,6 +61,9 @@ struct pwm_fan_ctx { struct hwmon_chip_info info; struct hwmon_channel_info fan_channel; + + u64 pwm_duty_cycle_from_stopped; + u32 pwm_usec_from_stopped; }; /* This handler assumes self resetting edge triggered interrupt. */ @@ -199,7 +203,9 @@ static int pwm_fan_power_off(struct pwm_fan_ctx *ctx, bool force_disable) static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) { struct pwm_state *state = &ctx->pwm_state; + unsigned long final_pwm = pwm; unsigned long period; + bool update = false; int ret = 0; if (pwm > 0) { @@ -208,11 +214,22 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) return 0; period = state->period; - state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + update = state->duty_cycle < ctx->pwm_duty_cycle_from_stopped; + if (update) + state->duty_cycle = ctx->pwm_duty_cycle_from_stopped; + else + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); ret = pwm_apply_might_sleep(ctx->pwm, state); if (ret) return ret; ret = pwm_fan_power_on(ctx); + if (!ret && update) { + pwm = final_pwm; + state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + usleep_range(ctx->pwm_usec_from_stopped, + ctx->pwm_usec_from_stopped * 2); + ret = pwm_apply_might_sleep(ctx->pwm, state); + } } else { ret = pwm_fan_power_off(ctx, false); } @@ -480,6 +497,7 @@ static int pwm_fan_probe(struct platform_device *pdev) struct device *hwmon; int ret; const struct hwmon_channel_info **channels; + u32 pwm_min_from_stopped = 0; u32 *fan_channel_config; int channel_count = 1; /* We always have a PWM channel. */ int i; @@ -620,6 +638,19 @@ static int pwm_fan_probe(struct platform_device *pdev) channels[1] = &ctx->fan_channel; } + ret = of_property_read_u32(dev->of_node, "fan-stop-to-start-percent", + &pwm_min_from_stopped); + if (!ret && pwm_min_from_stopped) { + ctx->pwm_duty_cycle_from_stopped = + DIV_ROUND_UP_ULL(pwm_min_from_stopped * + (ctx->pwm_state.period - 1), + 100); + } + ret = of_property_read_u32(dev->of_node, "fan-stop-to-start-us", + &ctx->pwm_usec_from_stopped); + if (ret) + ctx->pwm_usec_from_stopped = 250000; + ctx->info.ops = &pwm_fan_hwmon_ops; ctx->info.info = channels; diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c index 65cc52e47db081..10ef1e1f9458e3 100644 --- a/drivers/hwmon/raspberrypi-hwmon.c +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -81,12 +81,6 @@ static int rpi_read(struct device *dev, enum hwmon_sensor_types type, return 0; } -static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static const struct hwmon_channel_info * const rpi_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_LCRIT_ALARM), @@ -94,7 +88,7 @@ static const struct hwmon_channel_info * const rpi_info[] = { }; static const struct hwmon_ops rpi_hwmon_ops = { - .is_visible = rpi_is_visible, + .visible = 0444, .read = rpi_read, }; diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index a4b05ebb054609..d00bd5cc6b1547 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -512,7 +512,7 @@ static struct platform_driver sch5636_driver = { .name = DRVNAME, }, .probe = sch5636_probe, - .remove_new = sch5636_remove, + .remove = sch5636_remove, .id_table = sch5636_device_id, }; diff --git a/drivers/hwmon/sg2042-mcu.c b/drivers/hwmon/sg2042-mcu.c index 1410457693545b..aa3fb773602c9e 100644 --- a/drivers/hwmon/sg2042-mcu.c +++ b/drivers/hwmon/sg2042-mcu.c @@ -346,8 +346,8 @@ static void sg2042_mcu_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id sg2042_mcu_id[] = { - { "sg2042-hwmon-mcu", 0 }, - {}, + { "sg2042-hwmon-mcu" }, + { } }; MODULE_DEVICE_TABLE(i2c, sg2042_mcu_id); diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 494f9655f44f4a..3d55047e9baf9a 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -1051,7 +1051,7 @@ static struct platform_driver sht15_driver = { .of_match_table = of_match_ptr(sht15_dt_match), }, .probe = sht15_probe, - .remove_new = sht15_remove, + .remove = sht15_remove, .id_table = sht15_device_ids, }; module_platform_driver(sht15_driver); diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index b8916d2735b5a5..6c9b776237c236 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,12 @@ */ #define SHT4X_CMD_MEASURE_HPM 0b11111101 #define SHT4X_CMD_RESET 0b10010100 +#define SHT4X_CMD_HEATER_20_1 0b00011110 +#define SHT4X_CMD_HEATER_20_01 0b00010101 +#define SHT4X_CMD_HEATER_110_1 0b00101111 +#define SHT4X_CMD_HEATER_110_01 0b00100100 +#define SHT4X_CMD_HEATER_200_1 0b00111001 +#define SHT4X_CMD_HEATER_200_01 0b00110010 #define SHT4X_CMD_LEN 1 #define SHT4X_CRC8_LEN 1 @@ -49,6 +56,10 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table); * struct sht4x_data - All the data required to operate an SHT4X chip * @client: the i2c client associated with the SHT4X * @lock: a mutex that is used to prevent parallel access to the i2c client + * @heating_complete: the time that the last heating finished + * @data_pending: true if and only if there are measurements to retrieve after heating + * @heater_power: the power at which the heater will be started + * @heater_time: the time for which the heater will remain turned on * @valid: validity of fields below * @update_interval: the minimum poll interval * @last_updated: the previous time that the SHT4X was polled @@ -58,6 +69,10 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table); struct sht4x_data { struct i2c_client *client; struct mutex lock; /* atomic read data updates */ + unsigned long heating_complete; /* in jiffies */ + bool data_pending; + u32 heater_power; /* in milli-watts */ + u32 heater_time; /* in milli-seconds */ bool valid; /* validity of fields below */ long update_interval; /* in milli-seconds */ long last_updated; /* in jiffies */ @@ -79,19 +94,30 @@ static int sht4x_read_values(struct sht4x_data *data) u8 crc; u8 cmd[SHT4X_CMD_LEN] = {SHT4X_CMD_MEASURE_HPM}; u8 raw_data[SHT4X_RESPONSE_LENGTH]; + unsigned long curr_jiffies; mutex_lock(&data->lock); - next_update = data->last_updated + - msecs_to_jiffies(data->update_interval); - if (data->valid && time_before_eq(jiffies, next_update)) - goto unlock; + curr_jiffies = jiffies; + if (time_before(curr_jiffies, data->heating_complete)) + msleep(jiffies_to_msecs(data->heating_complete - curr_jiffies)); - ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN); - if (ret < 0) - goto unlock; + if (data->data_pending && + time_before(jiffies, data->heating_complete + data->update_interval)) { + data->data_pending = false; + } else { + next_update = data->last_updated + + msecs_to_jiffies(data->update_interval); - usleep_range(SHT4X_MEAS_DELAY_HPM, SHT4X_MEAS_DELAY_HPM + SHT4X_DELAY_EXTRA); + if (data->valid && time_before_eq(jiffies, next_update)) + goto unlock; + + ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN); + if (ret < 0) + goto unlock; + + usleep_range(SHT4X_MEAS_DELAY_HPM, SHT4X_MEAS_DELAY_HPM + SHT4X_DELAY_EXTRA); + } ret = i2c_master_recv(client, raw_data, SHT4X_RESPONSE_LENGTH); if (ret != SHT4X_RESPONSE_LENGTH) { @@ -215,6 +241,143 @@ static int sht4x_hwmon_write(struct device *dev, enum hwmon_sensor_types type, } } +static ssize_t heater_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", time_before(jiffies, data->heating_complete)); +} + +static ssize_t heater_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + bool status; + ssize_t ret; + u8 cmd; + u32 heating_time_bound; + + ret = kstrtobool(buf, &status); + if (ret) + return ret; + if (!status) + return -EINVAL; + + if (data->heater_time == 100) { + if (data->heater_power == 20) + cmd = SHT4X_CMD_HEATER_20_01; + else if (data->heater_power == 110) + cmd = SHT4X_CMD_HEATER_110_01; + else /* data->heater_power == 200 */ + cmd = SHT4X_CMD_HEATER_200_01; + + heating_time_bound = 110; + } else { /* data->heater_time == 1000 */ + if (data->heater_power == 20) + cmd = SHT4X_CMD_HEATER_20_1; + else if (data->heater_power == 110) + cmd = SHT4X_CMD_HEATER_110_1; + else /* data->heater_power == 200 */ + cmd = SHT4X_CMD_HEATER_200_1; + + heating_time_bound = 1100; + } + + mutex_lock(&data->lock); + + if (time_before(jiffies, data->heating_complete)) { + ret = -EBUSY; + goto unlock; + } + + ret = i2c_master_send(data->client, &cmd, SHT4X_CMD_LEN); + if (ret < 0) + goto unlock; + + data->heating_complete = jiffies + msecs_to_jiffies(heating_time_bound); + data->data_pending = true; +unlock: + mutex_unlock(&data->lock); + return ret; +} + +static ssize_t heater_power_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", data->heater_power); +} + +static ssize_t heater_power_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + u32 power; + ssize_t ret; + + ret = kstrtou32(buf, 10, &power); + if (ret) + return ret; + + if (power != 20 && power != 110 && power != 200) + return -EINVAL; + + data->heater_power = power; + + return count; +} + +static ssize_t heater_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", data->heater_time); +} + +static ssize_t heater_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct sht4x_data *data = dev_get_drvdata(dev); + u32 time; + ssize_t ret; + + ret = kstrtou32(buf, 10, &time); + if (ret) + return ret; + + if (time != 100 && time != 1000) + return -EINVAL; + + data->heater_time = time; + + return count; +} + +static DEVICE_ATTR_RW(heater_enable); +static DEVICE_ATTR_RW(heater_power); +static DEVICE_ATTR_RW(heater_time); + +static struct attribute *sht4x_attrs[] = { + &dev_attr_heater_enable.attr, + &dev_attr_heater_power.attr, + &dev_attr_heater_time.attr, + NULL +}; + +ATTRIBUTE_GROUPS(sht4x); + static const struct hwmon_channel_info * const sht4x_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), @@ -255,6 +418,9 @@ static int sht4x_probe(struct i2c_client *client) data->update_interval = SHT4X_MIN_POLL_INTERVAL; data->client = client; + data->heater_power = 200; + data->heater_time = 1000; + data->heating_complete = jiffies; mutex_init(&data->lock); @@ -270,7 +436,7 @@ static int sht4x_probe(struct i2c_client *client) client->name, data, &sht4x_chip_info, - NULL); + sht4x_groups); return PTR_ERR_OR_ZERO(hwmon_dev); } diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index e73b1522f3cefa..b7a7bcd6d3af0a 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -784,7 +784,7 @@ static struct platform_driver sis5595_driver = { .name = DRIVER_NAME, }, .probe = sis5595_probe, - .remove_new = sis5595_remove, + .remove = sis5595_remove, }; static int sis5595_pci_probe(struct pci_dev *dev, diff --git a/drivers/hwmon/sl28cpld-hwmon.c b/drivers/hwmon/sl28cpld-hwmon.c index e020f25c930050..454cc844fb9d35 100644 --- a/drivers/hwmon/sl28cpld-hwmon.c +++ b/drivers/hwmon/sl28cpld-hwmon.c @@ -23,13 +23,6 @@ struct sl28cpld_hwmon { u32 offset; }; -static umode_t sl28cpld_hwmon_is_visible(const void *data, - enum hwmon_sensor_types type, - u32 attr, int channel) -{ - return 0444; -} - static int sl28cpld_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *input) @@ -73,7 +66,7 @@ static const struct hwmon_channel_info * const sl28cpld_hwmon_info[] = { }; static const struct hwmon_ops sl28cpld_hwmon_ops = { - .is_visible = sl28cpld_hwmon_is_visible, + .visible = 0444, .read = sl28cpld_hwmon_read, }; diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 0d46edbcb144ba..595bceb78d7603 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -858,7 +858,7 @@ static struct platform_driver smsc47m1_driver __refdata = { .driver = { .name = DRVNAME, }, - .remove_new = __exit_p(smsc47m1_remove), + .remove = __exit_p(smsc47m1_remove), }; static int __init smsc47m1_device_add(unsigned short address, diff --git a/drivers/hwmon/spd5118.c b/drivers/hwmon/spd5118.c index fcbce5a01e5580..6cee48a3e5c33e 100644 --- a/drivers/hwmon/spd5118.c +++ b/drivers/hwmon/spd5118.c @@ -671,7 +671,7 @@ static int spd5118_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(spd5118_pm_ops, spd5118_suspend, spd5118_resume); static const struct i2c_device_id spd5118_id[] = { - { "spd5118", 0 }, + { "spd5118" }, { } }; MODULE_DEVICE_TABLE(i2c, spd5118_id); diff --git a/drivers/hwmon/surface_fan.c b/drivers/hwmon/surface_fan.c index de3c5a2409c618..aafb4ac92e6c6f 100644 --- a/drivers/hwmon/surface_fan.c +++ b/drivers/hwmon/surface_fan.c @@ -18,14 +18,6 @@ SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_fan_rpm_get, __le16, { .command_id = 0x01, }); -// hwmon -static umode_t surface_fan_hwmon_is_visible(const void *drvdata, - enum hwmon_sensor_types type, u32 attr, - int channel) -{ - return 0444; -} - static int surface_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) @@ -49,7 +41,7 @@ static const struct hwmon_channel_info *const surface_fan_info[] = { }; static const struct hwmon_ops surface_fan_hwmon_ops = { - .is_visible = surface_fan_hwmon_is_visible, + .visible = 0444, .read = surface_fan_hwmon_read, }; diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index a82bbc959eb153..fbe67300912611 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -323,33 +324,19 @@ static const struct regmap_config tmp108_regmap_config = { .use_single_write = true, }; -static int tmp108_probe(struct i2c_client *client) +static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *name) { - struct device *dev = &client->dev; struct device *hwmon_dev; struct tmp108 *tmp108; - int err; u32 config; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WORD_DATA)) { - dev_err(dev, - "adapter doesn't support SMBus word transactions\n"); - return -ENODEV; - } + int err; tmp108 = devm_kzalloc(dev, sizeof(*tmp108), GFP_KERNEL); if (!tmp108) return -ENOMEM; dev_set_drvdata(dev, tmp108); - - tmp108->regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config); - if (IS_ERR(tmp108->regmap)) { - err = PTR_ERR(tmp108->regmap); - dev_err(dev, "regmap init failed: %d", err); - return err; - } + tmp108->regmap = regmap; err = regmap_read(tmp108->regmap, TMP108_REG_CONF, &config); if (err < 0) { @@ -383,13 +370,30 @@ static int tmp108_probe(struct i2c_client *client) return err; } - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + hwmon_dev = devm_hwmon_device_register_with_info(dev, name, tmp108, &tmp108_chip_info, NULL); return PTR_ERR_OR_ZERO(hwmon_dev); } +static int tmp108_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WORD_DATA)) + return dev_err_probe(dev, -ENODEV, + "adapter doesn't support SMBus word transactions\n"); + + regmap = devm_regmap_init_i2c(client, &tmp108_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed"); + + return tmp108_common_probe(dev, regmap, client->name); +} + static int tmp108_suspend(struct device *dev) { struct tmp108 *tmp108 = dev_get_drvdata(dev); @@ -420,6 +424,7 @@ MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids); #ifdef CONFIG_OF static const struct of_device_id tmp108_of_ids[] = { + { .compatible = "nxp,p3t1085", }, { .compatible = "ti,tmp108", }, {} }; @@ -436,7 +441,34 @@ static struct i2c_driver tmp108_driver = { .id_table = tmp108_i2c_ids, }; -module_i2c_driver(tmp108_driver); +static const struct i3c_device_id p3t1085_i3c_ids[] = { + I3C_DEVICE(0x011b, 0x1529, NULL), + {} +}; +MODULE_DEVICE_TABLE(i3c, p3t1085_i3c_ids); + +static int p3t1085_i3c_probe(struct i3c_device *i3cdev) +{ + struct device *dev = i3cdev_to_dev(i3cdev); + struct regmap *regmap; + + regmap = devm_regmap_init_i3c(i3cdev, &tmp108_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to register i3c regmap\n"); + + return tmp108_common_probe(dev, regmap, "p3t1085_i3c"); +} + +static struct i3c_driver p3t1085_driver = { + .driver = { + .name = "p3t1085_i3c", + }, + .probe = p3t1085_i3c_probe, + .id_table = p3t1085_i3c_ids, +}; + +module_i3c_i2c_driver(p3t1085_driver, &tmp108_driver) MODULE_AUTHOR("John Muir "); MODULE_DESCRIPTION("Texas Instruments TMP108 temperature sensor driver"); diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index 926d28cd3fab55..1c2cb12071b808 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -182,7 +182,7 @@ struct tmp51x_data { struct regmap *regmap; }; -// Set the shift based on the gain 8=4, 4=3, 2=2, 1=1 +// Set the shift based on the gain: 8 -> 1, 4 -> 2, 2 -> 3, 1 -> 4 static inline u8 tmp51x_get_pga_shift(struct tmp51x_data *data) { return 5 - ffs(data->pga_gain); @@ -204,7 +204,9 @@ static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos, * 2's complement number shifted by one to four depending * on the pga gain setting. 1lsb = 10uV */ - *val = sign_extend32(regval, 17 - tmp51x_get_pga_shift(data)); + *val = sign_extend32(regval, + reg == TMP51X_SHUNT_CURRENT_RESULT ? + 16 - tmp51x_get_pga_shift(data) : 15); *val = DIV_ROUND_CLOSEST(*val * 10 * MILLI, data->shunt_uohms); break; case TMP51X_BUS_VOLTAGE_RESULT: @@ -220,7 +222,7 @@ static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos, break; case TMP51X_BUS_CURRENT_RESULT: // Current = (ShuntVoltage * CalibrationRegister) / 4096 - *val = sign_extend32(regval, 16) * data->curr_lsb_ua; + *val = sign_extend32(regval, 15) * (long)data->curr_lsb_ua; *val = DIV_ROUND_CLOSEST(*val, MILLI); break; case TMP51X_LOCAL_TEMP_RESULT: @@ -232,7 +234,7 @@ static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos, case TMP51X_REMOTE_TEMP_LIMIT_2: case TMP513_REMOTE_TEMP_LIMIT_3: // 1lsb = 0.0625 degrees centigrade - *val = sign_extend32(regval, 16) >> TMP51X_TEMP_SHIFT; + *val = sign_extend32(regval, 15) >> TMP51X_TEMP_SHIFT; *val = DIV_ROUND_CLOSEST(*val * 625, 10); break; case TMP51X_N_FACTOR_AND_HYST_1: diff --git a/drivers/hwmon/tps23861.c b/drivers/hwmon/tps23861.c index dfcfb09d9f3cdf..80fb03f30c302d 100644 --- a/drivers/hwmon/tps23861.c +++ b/drivers/hwmon/tps23861.c @@ -132,7 +132,7 @@ static int tps23861_read_temp(struct tps23861_data *data, long *val) if (err < 0) return err; - *val = (regval * TEMPERATURE_LSB) - 20000; + *val = ((long)regval * TEMPERATURE_LSB) - 20000; return 0; } diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 2765d5f1b7f05c..e4f1bb538628c7 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -317,7 +317,7 @@ static struct platform_driver env_driver = { .of_match_table = env_match, }, .probe = env_probe, - .remove_new = env_remove, + .remove = env_remove, }; module_platform_driver(env_driver); diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index 5abe95b683c027..823bff2871e1e9 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -197,7 +197,7 @@ static struct platform_driver via_cputemp_driver = { .name = DRVNAME, }, .probe = via_cputemp_probe, - .remove_new = via_cputemp_remove, + .remove = via_cputemp_remove, }; struct pdev_entry { diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 3a002ad3c005b8..bbaeb808cc15e2 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -799,7 +799,7 @@ static struct platform_driver via686a_driver = { .name = DRIVER_NAME, }, .probe = via686a_probe, - .remove_new = via686a_remove, + .remove = via686a_remove, }; static const struct pci_device_id via686a_pci_ids[] = { diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 2f3890463e18d7..386edea6b69e50 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -1221,7 +1221,7 @@ static struct platform_driver vt1211_driver = { .name = DRVNAME, }, .probe = vt1211_probe, - .remove_new = vt1211_remove, + .remove = vt1211_remove, }; static int __init vt1211_device_add(unsigned short address) diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index dcdd14ccd115c6..3bf27c21845ba5 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -910,11 +910,11 @@ static void vt8231_remove(struct platform_device *pdev) static struct platform_driver vt8231_driver = { - .driver = { + .driver = { .name = DRIVER_NAME, }, .probe = vt8231_probe, - .remove_new = vt8231_remove, + .remove = vt8231_remove, }; static const struct pci_device_id vt8231_pci_ids[] = { diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 2fc9b718e2aba1..95115d7b863e37 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -1844,7 +1844,7 @@ static struct platform_driver w83627hf_driver = { .pm = W83627HF_DEV_PM_OPS, }, .probe = w83627hf_probe, - .remove_new = w83627hf_remove, + .remove = w83627hf_remove, }; static int __init w83627hf_find(int sioaddr, unsigned short *addr, diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index b7957c84d23525..076200ed2ec914 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1828,7 +1828,7 @@ static struct platform_driver w83781d_isa_driver = { .name = "w83781d", }, .probe = w83781d_isa_probe, - .remove_new = w83781d_isa_remove, + .remove = w83781d_isa_remove, }; /* return 1 if a supported chip is found, 0 otherwise */ diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c index 5e0759a70f6d51..1e3bd129a922d2 100644 --- a/drivers/hwmon/xgene-hwmon.c +++ b/drivers/hwmon/xgene-hwmon.c @@ -772,7 +772,7 @@ MODULE_DEVICE_TABLE(of, xgene_hwmon_of_match); static struct platform_driver xgene_hwmon_driver = { .probe = xgene_hwmon_probe, - .remove_new = xgene_hwmon_remove, + .remove = xgene_hwmon_remove, .driver = { .name = "xgene-slimpro-hwmon", .of_match_table = xgene_hwmon_of_match, diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c index 1edca1092f29b0..5a2d8c3e0d80a9 100644 --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -131,7 +131,7 @@ static void u8500_hsem_remove(struct platform_device *pdev) static struct platform_driver u8500_hsem_driver = { .probe = u8500_hsem_probe, - .remove_new = u8500_hsem_remove, + .remove = u8500_hsem_remove, .driver = { .name = "u8500_hsem", }, diff --git a/drivers/hwtracing/coresight/coresight-catu.c b/drivers/hwtracing/coresight/coresight-catu.c index bfea880d6dfbf1..275cc0d9f505fb 100644 --- a/drivers/hwtracing/coresight/coresight-catu.c +++ b/drivers/hwtracing/coresight/coresight-catu.c @@ -689,7 +689,7 @@ MODULE_DEVICE_TABLE(acpi, catu_acpi_ids); static struct platform_driver catu_platform_driver = { .probe = catu_platform_probe, - .remove_new = catu_platform_remove, + .remove = catu_platform_remove, .driver = { .name = "coresight-catu-platform", .acpi_match_table = ACPI_PTR(catu_acpi_ids), diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 75962dae9aa185..342c3aaf414dd8 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -763,7 +763,7 @@ static const struct dev_pm_ops debug_dev_pm_ops = { static struct platform_driver debug_platform_driver = { .probe = debug_platform_probe, - .remove_new = debug_platform_remove, + .remove = debug_platform_remove, .driver = { .name = "coresight-debug-platform", .acpi_match_table = ACPI_PTR(debug_platform_ids), diff --git a/drivers/hwtracing/coresight/coresight-dummy.c b/drivers/hwtracing/coresight/coresight-dummy.c index bb85fa663ffcad..02ef2b945a0c12 100644 --- a/drivers/hwtracing/coresight/coresight-dummy.c +++ b/drivers/hwtracing/coresight/coresight-dummy.c @@ -144,7 +144,7 @@ static const struct of_device_id dummy_match[] = { static struct platform_driver dummy_driver = { .probe = dummy_probe, - .remove_new = dummy_remove, + .remove = dummy_remove, .driver = { .name = "coresight-dummy", .of_match_table = dummy_match, diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 66d44a404ad0cd..dd8c74f893dbdf 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -2399,7 +2399,7 @@ MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids); static struct platform_driver etm4_platform_driver = { .probe = etm4_probe_platform_dev, - .remove_new = etm4_remove_platform_dev, + .remove = etm4_remove_platform_dev, .driver = { .name = "coresight-etm4x", .of_match_table = etm4_sysreg_match, diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c index 5a819c8970fbf5..33efe1acbef754 100644 --- a/drivers/hwtracing/coresight/coresight-funnel.c +++ b/drivers/hwtracing/coresight/coresight-funnel.c @@ -377,7 +377,7 @@ MODULE_DEVICE_TABLE(acpi, funnel_acpi_ids); static struct platform_driver funnel_driver = { .probe = funnel_platform_probe, - .remove_new = funnel_platform_remove, + .remove = funnel_platform_remove, .driver = { .name = "coresight-funnel", /* THIS_MODULE is taken care of by platform_driver_register() */ diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 3e55be9c841861..0fba87de6d1af3 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -389,7 +389,7 @@ MODULE_DEVICE_TABLE(acpi, replicator_acpi_ids); static struct platform_driver replicator_driver = { .probe = replicator_platform_probe, - .remove_new = replicator_platform_remove, + .remove = replicator_platform_remove, .driver = { .name = "coresight-replicator", /* THIS_MODULE is taken care of by platform_driver_register() */ diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index cb3e04755c9929..b581a30a1cd98d 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -1036,7 +1036,7 @@ MODULE_DEVICE_TABLE(acpi, stm_acpi_ids); static struct platform_driver stm_platform_driver = { .probe = stm_platform_probe, - .remove_new = stm_platform_remove, + .remove = stm_platform_remove, .driver = { .name = "coresight-stm-platform", .acpi_match_table = ACPI_PTR(stm_acpi_ids), diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c index 3a482fd2cb225b..e9876252a789cb 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-core.c +++ b/drivers/hwtracing/coresight/coresight-tmc-core.c @@ -730,7 +730,7 @@ MODULE_DEVICE_TABLE(acpi, tmc_acpi_ids); static struct platform_driver tmc_platform_driver = { .probe = tmc_platform_probe, - .remove_new = tmc_platform_remove, + .remove = tmc_platform_remove, .driver = { .name = "coresight-tmc-platform", .acpi_match_table = ACPI_PTR(tmc_acpi_ids), diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index b048e146fbb108..97ef36f03ec207 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -307,7 +307,7 @@ MODULE_DEVICE_TABLE(acpi, tpiu_acpi_ids); static struct platform_driver tpiu_platform_driver = { .probe = tpiu_platform_probe, - .remove_new = tpiu_platform_remove, + .remove = tpiu_platform_remove, .driver = { .name = "coresight-tpiu-platform", .acpi_match_table = ACPI_PTR(tpiu_acpi_ids), diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c index 96a32b21366994..919804b12a67a4 100644 --- a/drivers/hwtracing/coresight/coresight-trbe.c +++ b/drivers/hwtracing/coresight/coresight-trbe.c @@ -1562,7 +1562,7 @@ static struct platform_driver arm_trbe_driver = { .suppress_bind_attrs = true, }, .probe = arm_trbe_device_probe, - .remove_new = arm_trbe_device_remove, + .remove = arm_trbe_device_remove, }; static int __init arm_trbe_init(void) diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c index ef7f560f0ffabb..dc3c9504dd7cd2 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.c +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c @@ -600,7 +600,7 @@ static struct platform_driver smb_driver = { .suppress_bind_attrs = true, }, .probe = smb_probe, - .remove_new = smb_remove, + .remove = smb_remove, }; module_platform_driver(smb_driver); diff --git a/drivers/hwtracing/intel_th/acpi.c b/drivers/hwtracing/intel_th/acpi.c index 503620e9fd1054..d229324978bd1c 100644 --- a/drivers/hwtracing/intel_th/acpi.c +++ b/drivers/hwtracing/intel_th/acpi.c @@ -69,7 +69,7 @@ static void intel_th_acpi_remove(struct platform_device *pdev) static struct platform_driver intel_th_acpi_driver = { .probe = intel_th_acpi_probe, - .remove_new = intel_th_acpi_remove, + .remove = intel_th_acpi_remove, .driver = { .name = DRIVER_NAME, .acpi_match_table = intel_th_acpi_ids, diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c index 0d7b9839e5b663..e9d8d28e055f36 100644 --- a/drivers/hwtracing/intel_th/pci.c +++ b/drivers/hwtracing/intel_th/pci.c @@ -23,7 +23,6 @@ enum { TH_PCI_RTIT_BAR = 4, }; -#define BAR_MASK (BIT(TH_PCI_CONFIG_BAR) | BIT(TH_PCI_STH_SW_BAR)) #define PCI_REG_NPKDSC 0x80 #define NPKDSC_TSACT BIT(5) @@ -83,10 +82,16 @@ static int intel_th_pci_probe(struct pci_dev *pdev, if (err) return err; - err = pcim_iomap_regions_request_all(pdev, BAR_MASK, DRIVER_NAME); + err = pcim_request_all_regions(pdev, DRIVER_NAME); if (err) return err; + if (!pcim_iomap(pdev, TH_PCI_CONFIG_BAR, 0)) + return -ENOMEM; + + if (!pcim_iomap(pdev, TH_PCI_STH_SW_BAR, 0)) + return -ENOMEM; + if (pdev->resource[TH_PCI_RTIT_BAR].start) { resource[TH_MMIO_RTIT] = pdev->resource[TH_PCI_RTIT_BAR]; r++; diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 3f71ce4711e35c..d27de18de46fe1 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -5,10 +5,11 @@ obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2c-core.o -i2c-core-objs := i2c-core-base.o i2c-core-smbus.o +i2c-core-y := i2c-core-base.o i2c-core-smbus.o i2c-core-$(CONFIG_ACPI) += i2c-core-acpi.o -i2c-core-$(CONFIG_I2C_SLAVE) += i2c-core-slave.o -i2c-core-$(CONFIG_OF) += i2c-core-of.o +i2c-core-$(CONFIG_I2C_SLAVE) += i2c-core-slave.o +i2c-core-$(CONFIG_OF) += i2c-core-of.o +i2c-core-$(CONFIG_OF_DYNAMIC) += i2c-core-of-prober.o obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 6b3ba7e5723aa1..ceb3ecdf884b52 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -62,19 +62,6 @@ config I2C_AMD756 This driver can also be built as a module. If so, the module will be called i2c-amd756. -config I2C_AMD756_S4882 - tristate "SMBus multiplexing on the Tyan S4882" - depends on I2C_AMD756 && X86 - help - Enabling this option will add specific SMBus support for the Tyan - S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 8 different channels, where the various memory module EEPROMs - and temperature sensors live. Saying yes here will give you access - to these in addition to the trunk. - - This driver can also be built as a module. If so, the module - will be called i2c-amd756-s4882. - config I2C_AMD8111 tristate "AMD 8111" depends on PCI && HAS_IOPORT @@ -95,6 +82,23 @@ config I2C_AMD_MP2 This driver can also be built as modules. If so, the modules will be called i2c-amd-mp2-pci and i2c-amd-mp2-plat. +config I2C_AMD_ASF + tristate "AMD ASF I2C Controller Support" + depends on I2C_PIIX4 + select I2C_SLAVE + help + This option enables support for the AMD ASF (Alert Standard Format) + I2C controller. The AMD ASF controller is an SMBus controller with + built-in ASF functionality, allowing it to issue generic SMBus + packets and communicate with the DASH controller using MCTP over + ASF. + + If you have an AMD system with ASF support and want to enable this + functionality, say Y or M here. If unsure, say N. + + To compile this driver as a module, choose M here: the module will + be called i2c_amd_asf_plat. + config I2C_HIX5HD2 tristate "Hix5hd2 high-speed I2C driver" depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST @@ -160,6 +164,7 @@ config I2C_I801 Meteor Lake (SOC and PCH) Birch Stream (SOC) Arrow Lake (SOC) + Panther Lake (SOC) This driver can also be built as a module. If so, the module will be called i2c-i801. @@ -250,19 +255,6 @@ config I2C_NFORCE2 This driver can also be built as a module. If so, the module will be called i2c-nforce2. -config I2C_NFORCE2_S4985 - tristate "SMBus multiplexing on the Tyan S4985" - depends on I2C_NFORCE2 && X86 - help - Enabling this option will add specific SMBus support for the Tyan - S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 4 different channels, where the various memory module EEPROMs - live. Saying yes here will give you access to these in addition - to the trunk. - - This driver can also be built as a module. If so, the module - will be called i2c-nforce2-s4985. - config I2C_NVIDIA_GPU tristate "NVIDIA GPU I2C controller" depends on PCI @@ -439,7 +431,7 @@ config I2C_AT91 are facing this situation, use the i2c-gpio driver. config I2C_AT91_SLAVE_EXPERIMENTAL - tristate "Microchip AT91 I2C experimental slave mode" + bool "Microchip AT91 I2C experimental slave mode" depends on I2C_AT91 select I2C_SLAVE help @@ -448,7 +440,7 @@ config I2C_AT91_SLAVE_EXPERIMENTAL been tested in a heavy way, help wanted. There are known bugs: - It can hang, on a SAMA5D4, after several transfers. - - There are some mismtaches with a SAMA5D4 as slave and a SAMA5D2 as + - There are some mismatches with a SAMA5D4 as slave and a SAMA5D2 as master. config I2C_AU1550 @@ -535,6 +527,16 @@ config I2C_CBUS_GPIO This driver can also be built as a module. If so, the module will be called i2c-cbus-gpio. +config I2C_CGBC + tristate "Congatec I2C Controller" + depends on MFD_CGBC + help + This driver supports the 2 I2C interfaces on the Congatec Board + Controller. + + This driver can also be built as a module. If so, the module will + be called i2c-cgbc.ko. + config I2C_CPM tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)" depends on CPM1 || CPM2 @@ -741,13 +743,14 @@ config I2C_IMG config I2C_IMX tristate "IMX I2C interface" - depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE || COMPILE_TEST + depends on ARCH_MXC || ARCH_LAYERSCAPE || ARCH_S32 || COLDFIRE \ + || COMPILE_TEST select I2C_SLAVE help Say Y here if you want to use the IIC bus controller on - the Freescale i.MX/MXC, Layerscape or ColdFire processors. + the Freescale i.MX/MXC/S32G, Layerscape or ColdFire processors. - This driver can also be built as a module. If so, the module + This driver can also be built as a module. If so, the module will be called i2c-imx. config I2C_IMX_LPI2C @@ -1060,6 +1063,16 @@ config I2C_RK3X This driver can also be built as a module. If so, the module will be called i2c-rk3x. +config I2C_RTL9300 + tristate "Realtek RTL9300 I2C controller" + depends on MACH_REALTEK_RTL || COMPILE_TEST + help + Say Y here to include support for the I2C controller in Realtek + RTL9300 SoCs. + + This driver can also be built as a module. If so, the module will + be called i2c-rtl9300. + config I2C_RZV2M tristate "Renesas RZ/V2M adapter" depends on ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index ecc07c50f2a0fe..1c2a4510abe44a 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -14,14 +14,12 @@ obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o -obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_CHT_WC) += i2c-cht-wc.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_ISCH) += i2c-isch.o obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o -obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o obj-$(CONFIG_I2C_NVIDIA_GPU) += i2c-nvidia-gpu.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o @@ -38,18 +36,18 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o # Embedded system I2C/SMBus host controller drivers obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o obj-$(CONFIG_I2C_AMD_MP2) += i2c-amd-mp2-pci.o i2c-amd-mp2-plat.o +obj-$(CONFIG_I2C_AMD_ASF) += i2c-amd-asf-plat.o obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o -i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o -ifeq ($(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL),y) - i2c-at91-objs += i2c-at91-slave.o -endif +i2c-at91-y := i2c-at91-core.o i2c-at91-master.o +i2c-at91-$(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL) += i2c-at91-slave.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o +obj-$(CONFIG_I2C_CGBC) += i2c-cgbc.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o @@ -103,6 +101,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o +obj-$(CONFIG_I2C_RTL9300) += i2c-rtl9300.o obj-$(CONFIG_I2C_RZV2M) += i2c-rzv2m.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o @@ -111,8 +110,8 @@ obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o -i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o +i2c-stm32f7-drv-y := i2c-stm32f7.o i2c-stm32.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o @@ -121,10 +120,10 @@ obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_WMT) += i2c-viai2c-wmt.o i2c-viai2c-common.o -i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o -i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o +i2c-octeon-y := i2c-octeon-core.o i2c-octeon-platdrv.o obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o +i2c-thunderx-y := i2c-octeon-core.o i2c-thunderx-pcidrv.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o diff --git a/drivers/i2c/busses/i2c-altera.c b/drivers/i2c/busses/i2c-altera.c index f4dde08a3b92cb..2da73173ce248f 100644 --- a/drivers/i2c/busses/i2c-altera.c +++ b/drivers/i2c/busses/i2c-altera.c @@ -482,7 +482,7 @@ MODULE_DEVICE_TABLE(of, altr_i2c_of_match); static struct platform_driver altr_i2c_driver = { .probe = altr_i2c_probe, - .remove_new = altr_i2c_remove, + .remove = altr_i2c_remove, .driver = { .name = "altera-i2c", .of_match_table = altr_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c new file mode 100644 index 00000000000000..7512614bf4b733 --- /dev/null +++ b/drivers/i2c/busses/i2c-amd-asf-plat.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Alert Standard Format Platform Driver + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Authors: Shyam Sundar S K + * Sanket Goswami + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-piix4.h" + +/* ASF register bits */ +#define ASF_SLV_LISTN 0 +#define ASF_SLV_INTR 1 +#define ASF_SLV_RST 4 +#define ASF_PEC_SP 5 +#define ASF_DATA_EN 7 +#define ASF_MSTR_EN 16 +#define ASF_CLK_EN 17 + +/* ASF address offsets */ +#define ASFINDEX (0x07 + piix4_smba) +#define ASFLISADDR (0x09 + piix4_smba) +#define ASFSTA (0x0A + piix4_smba) +#define ASFSLVSTA (0x0D + piix4_smba) +#define ASFDATARWPTR (0x11 + piix4_smba) +#define ASFSETDATARDPTR (0x12 + piix4_smba) +#define ASFDATABNKSEL (0x13 + piix4_smba) +#define ASFSLVEN (0x15 + piix4_smba) + +#define ASF_BLOCK_MAX_BYTES 72 +#define ASF_ERROR_STATUS GENMASK(3, 1) + +struct amd_asf_dev { + struct i2c_adapter adap; + void __iomem *eoi_base; + struct i2c_client *target; + struct delayed_work work_buf; + struct sb800_mmio_cfg mmio_cfg; + struct resource *port_addr; +}; + +static void amd_asf_process_target(struct work_struct *work) +{ + struct amd_asf_dev *dev = container_of(work, struct amd_asf_dev, work_buf.work); + unsigned short piix4_smba = dev->port_addr->start; + u8 data[ASF_BLOCK_MAX_BYTES]; + u8 bank, reg, cmd; + u8 len = 0, idx, val; + + /* Read target status register */ + reg = inb_p(ASFSLVSTA); + + /* Check if no error bits are set in target status register */ + if (reg & ASF_ERROR_STATUS) { + /* Set bank as full */ + cmd = 0; + reg |= GENMASK(3, 2); + outb_p(reg, ASFDATABNKSEL); + } else { + /* Read data bank */ + reg = inb_p(ASFDATABNKSEL); + bank = (reg & BIT(3)) ? 1 : 0; + + /* Set read data bank */ + if (bank) { + reg |= BIT(4); + reg &= ~BIT(3); + } else { + reg &= ~BIT(4); + reg &= ~BIT(2); + } + + /* Read command register */ + outb_p(reg, ASFDATABNKSEL); + cmd = inb_p(ASFINDEX); + len = inb_p(ASFDATARWPTR); + for (idx = 0; idx < len; idx++) + data[idx] = inb_p(ASFINDEX); + + /* Clear data bank status */ + if (bank) { + reg |= BIT(3); + outb_p(reg, ASFDATABNKSEL); + } else { + reg |= BIT(2); + outb_p(reg, ASFDATABNKSEL); + } + } + + outb_p(0, ASFSETDATARDPTR); + if (cmd & BIT(0)) + return; + + /* + * Although i2c_slave_event() returns an appropriate error code, we + * don't check it here because we're operating in the workqueue context. + */ + i2c_slave_event(dev->target, I2C_SLAVE_WRITE_REQUESTED, &val); + for (idx = 0; idx < len; idx++) { + val = data[idx]; + i2c_slave_event(dev->target, I2C_SLAVE_WRITE_RECEIVED, &val); + } + i2c_slave_event(dev->target, I2C_SLAVE_STOP, &val); +} + +static void amd_asf_update_ioport_target(unsigned short piix4_smba, u8 bit, + unsigned long offset, bool set) +{ + unsigned long reg; + + reg = inb_p(offset); + __assign_bit(bit, ®, set); + outb_p(reg, offset); +} + +static void amd_asf_update_mmio_target(struct amd_asf_dev *dev, u8 bit, bool set) +{ + unsigned long reg; + + reg = ioread32(dev->mmio_cfg.addr); + __assign_bit(bit, ®, set); + iowrite32(reg, dev->mmio_cfg.addr); +} + +static void amd_asf_setup_target(struct amd_asf_dev *dev) +{ + unsigned short piix4_smba = dev->port_addr->start; + + /* Reset both host and target before setting up */ + outb_p(0, SMBHSTSTS); + outb_p(0, ASFSLVSTA); + outb_p(0, ASFSTA); + + /* Update target address */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, true); + /* Enable target and set the clock */ + amd_asf_update_mmio_target(dev, ASF_MSTR_EN, false); + amd_asf_update_mmio_target(dev, ASF_CLK_EN, true); + /* Enable target interrupt */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, true); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, false); + /* Enable PEC and PEC append */ + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true); + amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true); +} + +static int amd_asf_access(struct i2c_adapter *adap, u16 addr, u8 command, u8 *data) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(adap); + unsigned short piix4_smba = dev->port_addr->start; + u8 i, len; + + outb_p((addr << 1), SMBHSTADD); + outb_p(command, SMBHSTCMD); + len = data[0]; + if (len == 0 || len > ASF_BLOCK_MAX_BYTES) + return -EINVAL; + + outb_p(len, SMBHSTDAT0); + /* Reset SMBBLKDAT */ + inb_p(SMBHSTCNT); + for (i = 1; i <= len; i++) + outb_p(data[i], SMBBLKDAT); + + outb_p(PIIX4_BLOCK_DATA, SMBHSTCNT); + /* Enable PEC and PEC append */ + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true); + amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true); + + return piix4_transaction(adap, piix4_smba); +} + +static int amd_asf_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(adap); + unsigned short piix4_smba = dev->port_addr->start; + u8 asf_data[ASF_BLOCK_MAX_BYTES]; + struct i2c_msg *dev_msgs = msgs; + u8 prev_port; + int ret; + + if (msgs->flags & I2C_M_RD) { + dev_err(&adap->dev, "ASF: Read not supported\n"); + return -EOPNOTSUPP; + } + + /* Exclude the receive header and PEC */ + if (msgs->len > ASF_BLOCK_MAX_BYTES - 3) { + dev_warn(&adap->dev, "ASF: max message length exceeded\n"); + return -EOPNOTSUPP; + } + + asf_data[0] = dev_msgs->len; + memcpy(asf_data + 1, dev_msgs[0].buf, dev_msgs->len); + + ret = piix4_sb800_region_request(&adap->dev, &dev->mmio_cfg); + if (ret) + return ret; + + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, false); + /* Clear ASF target status */ + outb_p(0, ASFSLVSTA); + + /* Enable ASF SMBus controller function */ + amd_asf_update_mmio_target(dev, ASF_MSTR_EN, true); + prev_port = piix4_sb800_port_sel(0, &dev->mmio_cfg); + ret = amd_asf_access(adap, msgs->addr, msgs[0].buf[0], asf_data); + piix4_sb800_port_sel(prev_port, &dev->mmio_cfg); + amd_asf_setup_target(dev); + piix4_sb800_region_release(&adap->dev, &dev->mmio_cfg); + return ret; +} + +static int amd_asf_reg_target(struct i2c_client *target) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter); + unsigned short piix4_smba = dev->port_addr->start; + int ret; + u8 reg; + + if (dev->target) + return -EBUSY; + + ret = piix4_sb800_region_request(&target->dev, &dev->mmio_cfg); + if (ret) + return ret; + + reg = (target->addr << 1) | I2C_M_RD; + outb_p(reg, ASFLISADDR); + + amd_asf_setup_target(dev); + dev->target = target; + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, ASFDATABNKSEL, false); + piix4_sb800_region_release(&target->dev, &dev->mmio_cfg); + + return 0; +} + +static int amd_asf_unreg_target(struct i2c_client *target) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter); + unsigned short piix4_smba = dev->port_addr->start; + + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, false); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true); + dev->target = NULL; + + return 0; +} + +static u32 amd_asf_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_PEC | I2C_FUNC_SLAVE; +} + +static const struct i2c_algorithm amd_asf_smbus_algorithm = { + .master_xfer = amd_asf_xfer, + .reg_slave = amd_asf_reg_target, + .unreg_slave = amd_asf_unreg_target, + .functionality = amd_asf_func, +}; + +static irqreturn_t amd_asf_irq_handler(int irq, void *ptr) +{ + struct amd_asf_dev *dev = ptr; + unsigned short piix4_smba = dev->port_addr->start; + u8 target_int = inb_p(ASFSTA); + + if (target_int & BIT(6)) { + /* Target Interrupt */ + outb_p(target_int | BIT(6), ASFSTA); + schedule_delayed_work(&dev->work_buf, HZ); + } else { + /* Controller Interrupt */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, SMBHSTSTS, true); + } + + return IRQ_HANDLED; +} + +static int amd_asf_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct amd_asf_dev *asf_dev; + struct resource *eoi_addr; + int ret, irq; + + asf_dev = devm_kzalloc(dev, sizeof(*asf_dev), GFP_KERNEL); + if (!asf_dev) + return dev_err_probe(dev, -ENOMEM, "Failed to allocate memory\n"); + + asf_dev->mmio_cfg.use_mmio = true; + asf_dev->port_addr = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!asf_dev->port_addr) + return dev_err_probe(dev, -EINVAL, "missing IO resources\n"); + + /* + * The resource obtained via ACPI might not belong to the ASF device address space. Instead, + * it could be within other IP blocks of the ASIC, which are crucial for generating + * subsequent interrupts. Therefore, we avoid using devm_platform_ioremap_resource() and + * use platform_get_resource() and devm_ioremap() separately to prevent any address space + * conflicts. + */ + eoi_addr = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!eoi_addr) + return dev_err_probe(dev, -EINVAL, "missing MEM resources\n"); + + asf_dev->eoi_base = devm_ioremap(dev, eoi_addr->start, resource_size(eoi_addr)); + if (!asf_dev->eoi_base) + return dev_err_probe(dev, -EBUSY, "failed mapping IO region\n"); + + ret = devm_delayed_work_autocancel(dev, &asf_dev->work_buf, amd_asf_process_target); + if (ret) + return dev_err_probe(dev, ret, "failed to create work queue\n"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "missing IRQ resources\n"); + + ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev); + if (ret) + return dev_err_probe(dev, ret, "Unable to request irq: %d for use\n", irq); + + asf_dev->adap.owner = THIS_MODULE; + asf_dev->adap.algo = &amd_asf_smbus_algorithm; + asf_dev->adap.dev.parent = dev; + + i2c_set_adapdata(&asf_dev->adap, asf_dev); + snprintf(asf_dev->adap.name, sizeof(asf_dev->adap.name), "AMD ASF adapter"); + + return devm_i2c_add_adapter(dev, &asf_dev->adap); +} + +static const struct acpi_device_id amd_asf_acpi_ids[] = { + { "AMDI001A" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, amd_asf_acpi_ids); + +static struct platform_driver amd_asf_driver = { + .driver = { + .name = "i2c-amd-asf", + .acpi_match_table = amd_asf_acpi_ids, + }, + .probe = amd_asf_probe, +}; +module_platform_driver(amd_asf_driver); + +MODULE_IMPORT_NS("PIIX4_SMBUS"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Alert Standard Format Driver"); diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c index 6f0ef587e76d14..d9dd0e475d1a38 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-plat.c +++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c @@ -346,7 +346,7 @@ MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match); static struct platform_driver i2c_amd_plat_driver = { .probe = i2c_amd_probe, - .remove_new = i2c_amd_remove, + .remove = i2c_amd_remove, .driver = { .name = "i2c_amd_mp2", .acpi_match_table = ACPI_PTR(i2c_amd_acpi_match), diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c deleted file mode 100644 index 063274388a7548..00000000000000 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ /dev/null @@ -1,245 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard - * - * Copyright (C) 2004, 2008 Jean Delvare - */ - -/* - * We select the channels by sending commands to the Philips - * PCA9556 chip at I2C address 0x18. The main adapter is used for - * the non-multiplexed part of the bus, and 4 virtual adapters - * are defined for the multiplexed addresses: 0x50-0x53 (memory - * module EEPROM) located on channels 1-4, and 0x4c (LM63) - * located on multiplexed channels 0 and 5-7. We define one - * virtual adapter per CPU, which corresponds to two multiplexed - * channels: - * CPU0: virtual adapter 1, channels 1 and 0 - * CPU1: virtual adapter 2, channels 2 and 5 - * CPU2: virtual adapter 3, channels 3 and 6 - * CPU3: virtual adapter 4, channels 4 and 7 - */ - -#include -#include -#include -#include -#include -#include - -extern struct i2c_adapter amd756_smbus; - -static struct i2c_adapter *s4882_adapter; -static struct i2c_algorithm *s4882_algo; - -/* Wrapper access functions for multiplexed SMBus */ -static DEFINE_MUTEX(amd756_lock); - -static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - int error; - - /* We exclude the multiplexed addresses */ - if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30 - || addr == 0x18) - return -ENXIO; - - mutex_lock(&amd756_lock); - - error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - - mutex_unlock(&amd756_lock); - - return error; -} - -/* We remember the last used channels combination so as to only switch - channels when it is really needed. This greatly reduces the SMBus - overhead, but also assumes that nobody will be writing to the PCA9556 - in our back. */ -static u8 last_channels; - -static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data, - u8 channels) -{ - int error; - - /* We exclude the non-multiplexed addresses */ - if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30) - return -ENXIO; - - mutex_lock(&amd756_lock); - - if (last_channels != channels) { - union i2c_smbus_data mplxdata; - mplxdata.byte = channels; - - error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0, - I2C_SMBUS_WRITE, 0x01, - I2C_SMBUS_BYTE_DATA, - &mplxdata); - if (error) - goto UNLOCK; - last_channels = channels; - } - error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - -UNLOCK: - mutex_unlock(&amd756_lock); - return error; -} - -static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU0: channels 1 and 0 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x03); -} - -static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU1: channels 2 and 5 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x24); -} - -static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU2: channels 3 and 6 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x48); -} - -static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU3: channels 4 and 7 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x90); -} - -static int __init amd756_s4882_init(void) -{ - int i, error; - union i2c_smbus_data ioconfig; - - if (!amd756_smbus.dev.parent) - return -ENODEV; - - /* Configure the PCA9556 multiplexer */ - ioconfig.byte = 0x00; /* All I/O to output mode */ - error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03, - I2C_SMBUS_BYTE_DATA, &ioconfig); - if (error) { - dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n"); - error = -EIO; - goto ERROR0; - } - - /* Unregister physical bus */ - i2c_del_adapter(&amd756_smbus); - - printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n"); - /* Define the 5 virtual adapters and algorithms structures */ - if (!(s4882_adapter = kcalloc(5, sizeof(struct i2c_adapter), - GFP_KERNEL))) { - error = -ENOMEM; - goto ERROR1; - } - if (!(s4882_algo = kcalloc(5, sizeof(struct i2c_algorithm), - GFP_KERNEL))) { - error = -ENOMEM; - goto ERROR2; - } - - /* Fill in the new structures */ - s4882_algo[0] = *(amd756_smbus.algo); - s4882_algo[0].smbus_xfer = amd756_access_virt0; - s4882_adapter[0] = amd756_smbus; - s4882_adapter[0].algo = s4882_algo; - s4882_adapter[0].dev.parent = amd756_smbus.dev.parent; - for (i = 1; i < 5; i++) { - s4882_algo[i] = *(amd756_smbus.algo); - s4882_adapter[i] = amd756_smbus; - snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name), - "SMBus 8111 adapter (CPU%d)", i-1); - s4882_adapter[i].algo = s4882_algo+i; - s4882_adapter[i].dev.parent = amd756_smbus.dev.parent; - } - s4882_algo[1].smbus_xfer = amd756_access_virt1; - s4882_algo[2].smbus_xfer = amd756_access_virt2; - s4882_algo[3].smbus_xfer = amd756_access_virt3; - s4882_algo[4].smbus_xfer = amd756_access_virt4; - - /* Register virtual adapters */ - for (i = 0; i < 5; i++) { - error = i2c_add_adapter(s4882_adapter+i); - if (error) { - printk(KERN_ERR "i2c-amd756-s4882: " - "Virtual adapter %d registration " - "failed, module not inserted\n", i); - for (i--; i >= 0; i--) - i2c_del_adapter(s4882_adapter+i); - goto ERROR3; - } - } - - return 0; - -ERROR3: - kfree(s4882_algo); - s4882_algo = NULL; -ERROR2: - kfree(s4882_adapter); - s4882_adapter = NULL; -ERROR1: - /* Restore physical bus */ - i2c_add_adapter(&amd756_smbus); -ERROR0: - return error; -} - -static void __exit amd756_s4882_exit(void) -{ - if (s4882_adapter) { - int i; - - for (i = 0; i < 5; i++) - i2c_del_adapter(s4882_adapter+i); - kfree(s4882_adapter); - s4882_adapter = NULL; - } - kfree(s4882_algo); - s4882_algo = NULL; - - /* Restore physical bus */ - if (i2c_add_adapter(&amd756_smbus)) - printk(KERN_ERR "i2c-amd756-s4882: " - "Physical bus restoration failed\n"); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("S4882 SMBus multiplexing"); -MODULE_LICENSE("GPL"); - -module_init(amd756_s4882_init); -module_exit(amd756_s4882_exit); diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 208310db906dfb..fa0d5a2c37323b 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -283,7 +283,7 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = amd756_func, }; -struct i2c_adapter amd756_smbus = { +static struct i2c_adapter amd756_smbus = { .owner = THIS_MODULE, .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, @@ -398,5 +398,3 @@ module_pci_driver(amd756_driver); MODULE_AUTHOR("Merlin Hughes "); MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(amd756_smbus); diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index cc5a26637fd540..1550d3d552aed4 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -1102,7 +1102,7 @@ static void aspeed_i2c_remove_bus(struct platform_device *pdev) static struct platform_driver aspeed_i2c_bus_driver = { .probe = aspeed_i2c_probe_bus, - .remove_new = aspeed_i2c_remove_bus, + .remove = aspeed_i2c_remove_bus, .driver = { .name = "aspeed-i2c-bus", .of_match_table = aspeed_i2c_bus_of_table, diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c index dc52b35307256d..edc047e3e535c8 100644 --- a/drivers/i2c/busses/i2c-at91-core.c +++ b/drivers/i2c/busses/i2c-at91-core.c @@ -330,7 +330,7 @@ static const struct dev_pm_ops __maybe_unused at91_twi_pm = { static struct platform_driver at91_twi_driver = { .probe = at91_twi_probe, - .remove_new = at91_twi_remove, + .remove = at91_twi_remove, .id_table = at91_twi_devtypes, .driver = { .name = "at91_i2c", diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 902e420e761ef5..b78b38ddac463b 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -368,7 +368,7 @@ static struct platform_driver au1xpsc_smbus_driver = { .pm = pm_sleep_ptr(&i2c_au1550_pmops), }, .probe = i2c_au1550_probe, - .remove_new = i2c_au1550_remove, + .remove = i2c_au1550_remove, }; module_platform_driver(au1xpsc_smbus_driver); diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index a66f7f67b3b880..48916cf45ff730 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -824,7 +824,7 @@ MODULE_DEVICE_TABLE(of, axxia_i2c_of_match); static struct platform_driver axxia_i2c_driver = { .probe = axxia_i2c_probe, - .remove_new = axxia_i2c_remove, + .remove = axxia_i2c_remove, .driver = { .name = "axxia-i2c", .of_match_table = axxia_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 133d02899c6bd7..15b632a146e1e2 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1264,7 +1264,7 @@ static struct platform_driver bcm_iproc_i2c_driver = { .pm = pm_sleep_ptr(&bcm_iproc_i2c_pm_ops), }, .probe = bcm_iproc_i2c_probe, - .remove_new = bcm_iproc_i2c_remove, + .remove = bcm_iproc_i2c_remove, }; module_platform_driver(bcm_iproc_i2c_driver); diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index eb5c46a8f824e4..340fe1305dd924 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -877,7 +877,7 @@ static struct platform_driver bcm_kona_i2c_driver = { .of_match_table = bcm_kona_i2c_of_match, }, .probe = bcm_kona_i2c_probe, - .remove_new = bcm_kona_i2c_remove, + .remove = bcm_kona_i2c_remove, }; module_platform_driver(bcm_kona_i2c_driver); diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index ae42e37052a886..8554e790f8e36c 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, bcm2835_i2c_of_match); static struct platform_driver bcm2835_i2c_driver = { .probe = bcm2835_i2c_probe, - .remove_new = bcm2835_i2c_remove, + .remove = bcm2835_i2c_remove, .driver = { .name = "i2c-bcm2835", .of_match_table = bcm2835_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 83b85011e3771b..00f1a046e98535 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -744,7 +744,7 @@ static struct platform_driver brcmstb_i2c_driver = { .pm = pm_sleep_ptr(&brcmstb_i2c_pm), }, .probe = brcmstb_i2c_probe, - .remove_new = brcmstb_i2c_remove, + .remove = brcmstb_i2c_remove, }; module_platform_driver(brcmstb_i2c_driver); diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 87b9ba95b2e134..b64026fbca665b 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -129,6 +129,7 @@ #define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) #define CDNS_I2C_POLL_US 100000 +#define CDNS_I2C_POLL_US_ATOMIC 10 #define CDNS_I2C_TIMEOUT_US 500000 #define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset) @@ -189,6 +190,8 @@ enum cdns_i2c_slave_state { * @slave_state: I2C Slave state(idle/read/write). * @fifo_depth: The depth of the transfer FIFO * @transfer_size: The maximum number of bytes in one transfer + * @atomic: Mode of transfer + * @err_status_atomic: Error status in atomic mode */ struct cdns_i2c { struct device *dev; @@ -219,6 +222,8 @@ struct cdns_i2c { #endif u32 fifo_depth; unsigned int transfer_size; + bool atomic; + int err_status_atomic; }; struct cdns_platform_data { @@ -228,6 +233,66 @@ struct cdns_platform_data { #define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \ clk_rate_change_nb) +/** + * cdns_i2c_init - Controller initialisation + * @id: Device private data structure + * + * Initialise the i2c controller. + * + */ +static void cdns_i2c_init(struct cdns_i2c *id) +{ + cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET); + /* + * Cadence I2C controller has a bug wherein it generates + * invalid read transaction after HW timeout in master receiver mode. + * HW timeout is not used by this driver and the interrupt is disabled. + * But the feature itself cannot be disabled. Hence maximum value + * is written to this register to reduce the chances of error. + */ + cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); +} + +/** + * cdns_i2c_runtime_suspend - Runtime suspend method for the driver + * @dev: Address of the platform_device structure + * + * Put the driver into low power mode. + * + * Return: 0 always + */ +static int cdns_i2c_runtime_suspend(struct device *dev) +{ + struct cdns_i2c *xi2c = dev_get_drvdata(dev); + + clk_disable(xi2c->clk); + + return 0; +} + +/** + * cdns_i2c_runtime_resume - Runtime resume + * @dev: Address of the platform_device structure + * + * Runtime resume callback. + * + * Return: 0 on success and error value on error + */ +static int cdns_i2c_runtime_resume(struct device *dev) +{ + struct cdns_i2c *xi2c = dev_get_drvdata(dev); + int ret; + + ret = clk_enable(xi2c->clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + cdns_i2c_init(xi2c); + + return 0; +} + /** * cdns_i2c_clear_bus_hold - Clear bus hold bit * @id: Pointer to driver data struct @@ -561,6 +626,89 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) return cdns_i2c_master_isr(ptr); } +static bool cdns_i2c_error_check(struct cdns_i2c *id) +{ + unsigned int isr_status; + + id->err_status = 0; + + isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); + cdns_i2c_writereg(isr_status & CDNS_I2C_IXR_ERR_INTR_MASK, CDNS_I2C_ISR_OFFSET); + + id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK; + + return !!id->err_status; +} + +static void cdns_i2c_mrecv_atomic(struct cdns_i2c *id) +{ + while (id->recv_count > 0) { + bool updatetx; + + /* + * Check if transfer size register needs to be updated again for a + * large data receive operation. + */ + updatetx = id->recv_count > id->curr_recv_count; + + while (id->curr_recv_count > 0) { + if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) { + *id->p_recv_buf = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); + id->p_recv_buf++; + id->recv_count--; + id->curr_recv_count--; + + /* + * Clear the hold bit that was set for FIFO control, + * if the remaining RX data is less than or equal to + * the FIFO depth, unless a repeated start is selected. + */ + if (id->recv_count <= id->fifo_depth && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); + } + if (cdns_i2c_error_check(id)) + return; + if (cdns_is_holdquirk(id, updatetx)) + break; + } + + /* + * The controller sends NACK to the slave/target when transfer size + * register reaches zero without considering the HOLD bit. + * This workaround is implemented for large data transfers to + * maintain transfer size non-zero while performing a large + * receive operation. + */ + if (cdns_is_holdquirk(id, updatetx)) { + /* wait while fifo is full */ + while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) != + (id->curr_recv_count - id->fifo_depth)) + ; + + /* + * Check number of bytes to be received against maximum + * transfer size and update register accordingly. + */ + if ((id->recv_count - id->fifo_depth) > + id->transfer_size) { + cdns_i2c_writereg(id->transfer_size, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->transfer_size + + id->fifo_depth; + } else { + cdns_i2c_writereg(id->recv_count - + id->fifo_depth, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->recv_count; + } + } + } + + /* Clear hold (if not repeated start) */ + if (!id->recv_count && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); +} + /** * cdns_i2c_mrecv - Prepare and start a master receive operation * @id: pointer to the i2c device structure @@ -655,7 +803,34 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET); } - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + if (!id->atomic) + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + else + cdns_i2c_mrecv_atomic(id); +} + +static void cdns_i2c_msend_rem_atomic(struct cdns_i2c *id) +{ + while (id->send_count) { + unsigned int avail_bytes; + unsigned int bytes_to_send; + + avail_bytes = id->fifo_depth - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); + if (id->send_count > avail_bytes) + bytes_to_send = avail_bytes; + else + bytes_to_send = id->send_count; + + while (bytes_to_send--) { + cdns_i2c_writereg((*id->p_send_buf++), CDNS_I2C_DATA_OFFSET); + id->send_count--; + } + if (cdns_i2c_error_check(id)) + return; + } + + if (!id->send_count && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); } /** @@ -718,7 +893,10 @@ static void cdns_i2c_msend(struct cdns_i2c *id) cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, CDNS_I2C_ADDR_OFFSET); - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + if (!id->atomic) + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + else if (id->send_count > 0) + cdns_i2c_msend_rem_atomic(id); } /** @@ -758,7 +936,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, id->p_msg = msg; id->err_status = 0; - reinit_completion(&id->xfer_done); + if (!id->atomic) + reinit_completion(&id->xfer_done); /* Check for the TEN Bit mode on each msg */ reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); @@ -780,14 +959,31 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, /* Minimal time to execute this message */ msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk); - /* Plus some wiggle room */ - msg_timeout += msecs_to_jiffies(500); + + /* + * Plus some wiggle room. + * For non-atomic contexts, 500 ms is added to the timeout. + * For atomic contexts, 2000 ms is added because transfers happen in polled + * mode, requiring more time to account for the polling overhead. + */ + if (!id->atomic) + msg_timeout += msecs_to_jiffies(500); + else + msg_timeout += msecs_to_jiffies(2000); if (msg_timeout < adap->timeout) msg_timeout = adap->timeout; - /* Wait for the signal of completion */ - time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); + if (!id->atomic) { + /* Wait for the signal of completion */ + time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); + } else { + /* 0 is success, -ETIMEDOUT is error */ + time_left = !readl_poll_timeout_atomic(id->membase + CDNS_I2C_ISR_OFFSET, + reg, (reg & CDNS_I2C_IXR_COMP), + CDNS_I2C_POLL_US_ATOMIC, msg_timeout); + } + if (time_left == 0) { cdns_i2c_master_reset(adap); return -ETIMEDOUT; @@ -806,58 +1002,31 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, return 0; } -/** - * cdns_i2c_master_xfer - The main i2c transfer function - * @adap: pointer to the i2c adapter driver instance - * @msgs: pointer to the i2c message structure - * @num: the number of messages to transfer - * - * Initiates the send/recv activity based on the transfer message received. - * - * Return: number of msgs processed on success, negative error otherwise - */ -static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +static int cdns_i2c_master_common_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, + int num) { int ret, count; u32 reg; struct cdns_i2c *id = adap->algo_data; bool hold_quirk; -#if IS_ENABLED(CONFIG_I2C_SLAVE) - bool change_role = false; -#endif - - ret = pm_runtime_resume_and_get(id->dev); - if (ret < 0) - return ret; - -#if IS_ENABLED(CONFIG_I2C_SLAVE) - /* Check i2c operating mode and switch if possible */ - if (id->dev_mode == CDNS_I2C_MODE_SLAVE) { - if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) { - ret = -EAGAIN; - goto out; - } - - /* Set mode to master */ - cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); - - /* Mark flag to change role once xfer is completed */ - change_role = true; - } -#endif /* Check if the bus is free */ - - ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, - reg, - !(reg & CDNS_I2C_SR_BA), - CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US); + if (!id->atomic) + ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, + reg, + !(reg & CDNS_I2C_SR_BA), + CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US); + else + ret = readl_poll_timeout_atomic(id->membase + CDNS_I2C_SR_OFFSET, + reg, + !(reg & CDNS_I2C_SR_BA), + CDNS_I2C_POLL_US_ATOMIC, CDNS_I2C_TIMEOUT_US); if (ret) { ret = -EAGAIN; if (id->adap.bus_recovery_info) i2c_recover_bus(adap); - goto out; + return ret; } hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT); @@ -877,8 +1046,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, if (msgs[count].flags & I2C_M_RD) { dev_warn(adap->dev.parent, "Can't do repeated start after a receive message\n"); - ret = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } } id->bus_hold_flag = 1; @@ -896,26 +1064,65 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ret = cdns_i2c_process_msg(id, msgs, adap); if (ret) - goto out; + return ret; /* Report the other error interrupts to application */ - if (id->err_status) { + if (id->err_status || id->err_status_atomic) { cdns_i2c_master_reset(adap); - if (id->err_status & CDNS_I2C_IXR_NACK) { - ret = -ENXIO; - goto out; - } - ret = -EIO; - goto out; + if (id->err_status & CDNS_I2C_IXR_NACK) + return -ENXIO; + + return -EIO; } } + return 0; +} + +/** + * cdns_i2c_master_xfer - The main i2c transfer function + * @adap: pointer to the i2c adapter driver instance + * @msgs: pointer to the i2c message structure + * @num: the number of messages to transfer + * + * Initiates the send/recv activity based on the transfer message received. + * + * Return: number of msgs processed on success, negative error otherwise + */ +static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int ret; + struct cdns_i2c *id = adap->algo_data; +#if IS_ENABLED(CONFIG_I2C_SLAVE) + bool change_role = false; +#endif - ret = num; + ret = pm_runtime_resume_and_get(id->dev); + if (ret < 0) + return ret; -out: +#if IS_ENABLED(CONFIG_I2C_SLAVE) + /* Check i2c operating mode and switch if possible */ + if (id->dev_mode == CDNS_I2C_MODE_SLAVE) { + if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) { + ret = -EAGAIN; + goto out; + } + + /* Set mode to master */ + cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); + + /* Mark flag to change role once xfer is completed */ + change_role = true; + } +#endif + ret = cdns_i2c_master_common_xfer(adap, msgs, num); + if (!ret) + ret = num; #if IS_ENABLED(CONFIG_I2C_SLAVE) +out: /* Switch i2c mode to slave */ if (change_role) cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id); @@ -926,6 +1133,41 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, return ret; } +/** + * cdns_i2c_master_xfer_atomic - The i2c transfer function in atomic mode + * @adap: pointer to the i2c adapter driver instance + * @msgs: pointer to the i2c message structure + * @num: the number of messages to transfer + * + * Return: number of msgs processed on success, negative error otherwise + */ +static int cdns_i2c_master_xfer_atomic(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int ret; + struct cdns_i2c *id = adap->algo_data; + + ret = cdns_i2c_runtime_resume(id->dev); + if (ret) + return ret; + + if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) { + dev_warn(id->adap.dev.parent, + "Atomic xfer not supported for version 1.0\n"); + return 0; + } + + id->atomic = true; + ret = cdns_i2c_master_common_xfer(adap, msgs, num); + if (!ret) + ret = num; + + id->atomic = false; + cdns_i2c_runtime_suspend(id->dev); + + return ret; +} + /** * cdns_i2c_func - Returns the supported features of the I2C driver * @adap: pointer to the i2c adapter structure @@ -990,6 +1232,7 @@ static int cdns_unreg_slave(struct i2c_client *slave) static const struct i2c_algorithm cdns_i2c_algo = { .master_xfer = cdns_i2c_master_xfer, + .master_xfer_atomic = cdns_i2c_master_xfer_atomic, .functionality = cdns_i2c_func, #if IS_ENABLED(CONFIG_I2C_SLAVE) .reg_slave = cdns_reg_slave, @@ -1158,23 +1401,6 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long } } -/** - * cdns_i2c_runtime_suspend - Runtime suspend method for the driver - * @dev: Address of the platform_device structure - * - * Put the driver into low power mode. - * - * Return: 0 always - */ -static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev) -{ - struct cdns_i2c *xi2c = dev_get_drvdata(dev); - - clk_disable(xi2c->clk); - - return 0; -} - static int __maybe_unused cdns_i2c_suspend(struct device *dev) { struct cdns_i2c *xi2c = dev_get_drvdata(dev); @@ -1187,49 +1413,6 @@ static int __maybe_unused cdns_i2c_suspend(struct device *dev) return 0; } -/** - * cdns_i2c_init - Controller initialisation - * @id: Device private data structure - * - * Initialise the i2c controller. - * - */ -static void cdns_i2c_init(struct cdns_i2c *id) -{ - cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET); - /* - * Cadence I2C controller has a bug wherein it generates - * invalid read transaction after HW timeout in master receiver mode. - * HW timeout is not used by this driver and the interrupt is disabled. - * But the feature itself cannot be disabled. Hence maximum value - * is written to this register to reduce the chances of error. - */ - cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); -} - -/** - * cdns_i2c_runtime_resume - Runtime resume - * @dev: Address of the platform_device structure - * - * Runtime resume callback. - * - * Return: 0 on success and error value on error - */ -static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev) -{ - struct cdns_i2c *xi2c = dev_get_drvdata(dev); - int ret; - - ret = clk_enable(xi2c->clk); - if (ret) { - dev_err(dev, "Cannot enable clock.\n"); - return ret; - } - cdns_i2c_init(xi2c); - - return 0; -} - static int __maybe_unused cdns_i2c_resume(struct device *dev) { struct cdns_i2c *xi2c = dev_get_drvdata(dev); @@ -1469,7 +1652,7 @@ static struct platform_driver cdns_i2c_drv = { .pm = &cdns_i2c_dev_pm_ops, }, .probe = cdns_i2c_probe, - .remove_new = cdns_i2c_remove, + .remove = cdns_i2c_remove, }; module_platform_driver(cdns_i2c_drv); diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c index fdc1758a32756e..8065c7e4462e8e 100644 --- a/drivers/i2c/busses/i2c-cbus-gpio.c +++ b/drivers/i2c/busses/i2c-cbus-gpio.c @@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids); static struct platform_driver cbus_i2c_driver = { .probe = cbus_i2c_probe, - .remove_new = cbus_i2c_remove, + .remove = cbus_i2c_remove, .driver = { .name = "i2c-cbus-gpio", .of_match_table = of_match_ptr(i2c_cbus_dt_ids), diff --git a/drivers/i2c/busses/i2c-cgbc.c b/drivers/i2c/busses/i2c-cgbc.c new file mode 100644 index 00000000000000..f054d167ac4760 --- /dev/null +++ b/drivers/i2c/busses/i2c-cgbc.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Congatec Board Controller I2C busses driver + * + * Copyright (C) 2024 Bootlin + * Author: Thomas Richard + */ + +#include +#include +#include +#include +#include + +#define CGBC_I2C_PRIMARY_BUS_ID 0 +#define CGBC_I2C_PM_BUS_ID 4 + +#define CGBC_I2C_CMD_START 0x40 +#define CGBC_I2C_CMD_STAT 0x48 +#define CGBC_I2C_CMD_DATA 0x50 +#define CGBC_I2C_CMD_SPEED 0x58 + +#define CGBC_I2C_STAT_IDL 0x00 +#define CGBC_I2C_STAT_DAT 0x01 +#define CGBC_I2C_STAT_BUSY 0x02 + +#define CGBC_I2C_START 0x80 +#define CGBC_I2C_STOP 0x40 + +#define CGBC_I2C_LAST_ACK 0x80 /* send ACK on last read byte */ + +/* + * Reference code defines 1kHz as min freq and 6.1MHz as max freq. + * But in practice, the board controller limits the frequency to 1MHz, and the + * 1kHz is not functional (minimal working freq is 50kHz). + * So use these values as limits. + */ +#define CGBC_I2C_FREQ_MIN_HZ 50000 /* 50 kHz */ +#define CGBC_I2C_FREQ_MAX_HZ 1000000 /* 1 MHz */ + +#define CGBC_I2C_FREQ_UNIT_1KHZ 0x40 +#define CGBC_I2C_FREQ_UNIT_10KHZ 0x80 +#define CGBC_I2C_FREQ_UNIT_100KHZ 0xC0 + +#define CGBC_I2C_FREQ_UNIT_MASK 0xC0 +#define CGBC_I2C_FREQ_VALUE_MASK 0x3F + +#define CGBC_I2C_READ_MAX_LEN 31 +#define CGBC_I2C_WRITE_MAX_LEN 32 + +#define CGBC_I2C_CMD_HEADER_SIZE 4 +#define CGBC_I2C_CMD_SIZE (CGBC_I2C_CMD_HEADER_SIZE + CGBC_I2C_WRITE_MAX_LEN) + +enum cgbc_i2c_state { + CGBC_I2C_STATE_DONE = 0, + CGBC_I2C_STATE_INIT, + CGBC_I2C_STATE_START, + CGBC_I2C_STATE_READ, + CGBC_I2C_STATE_WRITE, + CGBC_I2C_STATE_ERROR, +}; + +struct i2c_algo_cgbc_data { + u8 bus_id; + unsigned long read_maxtime_us; +}; + +struct cgbc_i2c_data { + struct device *dev; + struct cgbc_device_data *cgbc; + struct i2c_adapter adap; + struct i2c_msg *msg; + int nmsgs; + int pos; + enum cgbc_i2c_state state; +}; + +struct cgbc_i2c_transfer { + u8 bus_id; + bool start; + bool stop; + bool last_ack; + u8 read; + u8 write; + u8 addr; + u8 data[CGBC_I2C_WRITE_MAX_LEN]; +}; + +static u8 cgbc_i2c_freq_to_reg(unsigned int bus_frequency) +{ + u8 reg; + + if (bus_frequency <= 10000) + reg = CGBC_I2C_FREQ_UNIT_1KHZ | (bus_frequency / 1000); + else if (bus_frequency <= 100000) + reg = CGBC_I2C_FREQ_UNIT_10KHZ | (bus_frequency / 10000); + else + reg = CGBC_I2C_FREQ_UNIT_100KHZ | (bus_frequency / 100000); + + return reg; +} + +static unsigned int cgbc_i2c_reg_to_freq(u8 reg) +{ + unsigned int freq = reg & CGBC_I2C_FREQ_VALUE_MASK; + u8 unit = reg & CGBC_I2C_FREQ_UNIT_MASK; + + if (unit == CGBC_I2C_FREQ_UNIT_100KHZ) + return freq * 100000; + else if (unit == CGBC_I2C_FREQ_UNIT_10KHZ) + return freq * 10000; + else + return freq * 1000; +} + +static int cgbc_i2c_get_status(struct i2c_adapter *adap) +{ + struct i2c_algo_cgbc_data *algo_data = adap->algo_data; + struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap); + struct cgbc_device_data *cgbc = i2c->cgbc; + u8 cmd = CGBC_I2C_CMD_STAT | algo_data->bus_id; + u8 status; + int ret; + + ret = cgbc_command(cgbc, &cmd, sizeof(cmd), NULL, 0, &status); + if (ret) + return ret; + + return status; +} + +static int cgbc_i2c_set_frequency(struct i2c_adapter *adap, + unsigned int bus_frequency) +{ + struct i2c_algo_cgbc_data *algo_data = adap->algo_data; + struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap); + struct cgbc_device_data *cgbc = i2c->cgbc; + u8 cmd[2], data; + int ret; + + if (bus_frequency > CGBC_I2C_FREQ_MAX_HZ || + bus_frequency < CGBC_I2C_FREQ_MIN_HZ) { + dev_info(i2c->dev, "invalid frequency %u, using default\n", bus_frequency); + bus_frequency = I2C_MAX_STANDARD_MODE_FREQ; + } + + cmd[0] = CGBC_I2C_CMD_SPEED | algo_data->bus_id; + cmd[1] = cgbc_i2c_freq_to_reg(bus_frequency); + + ret = cgbc_command(cgbc, &cmd, sizeof(cmd), &data, 1, NULL); + if (ret) + return dev_err_probe(i2c->dev, ret, + "Failed to initialize I2C bus %s", + adap->name); + + cmd[1] = 0x00; + + ret = cgbc_command(cgbc, &cmd, sizeof(cmd), &data, 1, NULL); + if (ret) + return dev_err_probe(i2c->dev, ret, + "Failed to get I2C bus frequency"); + + bus_frequency = cgbc_i2c_reg_to_freq(data); + + dev_dbg(i2c->dev, "%s is running at %d Hz\n", adap->name, bus_frequency); + + /* + * The read_maxtime_us variable represents the maximum time to wait + * for data during a read operation. The maximum amount of data that + * can be read by a command is CGBC_I2C_READ_MAX_LEN. + * Therefore, calculate the max time to properly size the timeout. + */ + algo_data->read_maxtime_us = (BITS_PER_BYTE + 1) * CGBC_I2C_READ_MAX_LEN + * USEC_PER_SEC / bus_frequency; + + return 0; +} + +static unsigned int cgbc_i2c_xfer_to_cmd(struct cgbc_i2c_transfer xfer, u8 *cmd) +{ + int i = 0; + + cmd[i++] = CGBC_I2C_CMD_START | xfer.bus_id; + + cmd[i] = (xfer.start) ? CGBC_I2C_START : 0x00; + if (xfer.stop) + cmd[i] |= CGBC_I2C_STOP; + cmd[i++] |= (xfer.start) ? xfer.write + 1 : xfer.write; + + cmd[i++] = (xfer.last_ack) ? (xfer.read | CGBC_I2C_LAST_ACK) : xfer.read; + + if (xfer.start) + cmd[i++] = xfer.addr; + + if (xfer.write > 0) + memcpy(&cmd[i], &xfer.data, xfer.write); + + return i + xfer.write; +} + +static int cgbc_i2c_xfer_msg(struct i2c_adapter *adap) +{ + struct i2c_algo_cgbc_data *algo_data = adap->algo_data; + struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap); + struct cgbc_device_data *cgbc = i2c->cgbc; + struct i2c_msg *msg = i2c->msg; + u8 cmd[CGBC_I2C_CMD_SIZE]; + int ret, max_len, len, i; + unsigned int cmd_len; + u8 cmd_data; + + struct cgbc_i2c_transfer xfer = { + .bus_id = algo_data->bus_id, + .addr = i2c_8bit_addr_from_msg(msg), + }; + + if (i2c->state == CGBC_I2C_STATE_DONE) + return 0; + + ret = cgbc_i2c_get_status(adap); + + if (ret == CGBC_I2C_STAT_BUSY) + return -EBUSY; + else if (ret < 0) + goto err; + + if (i2c->state == CGBC_I2C_STATE_INIT || + (i2c->state == CGBC_I2C_STATE_WRITE && msg->flags & I2C_M_RD)) + xfer.start = true; + + i2c->state = (msg->flags & I2C_M_RD) ? CGBC_I2C_STATE_READ : CGBC_I2C_STATE_WRITE; + + max_len = (i2c->state == CGBC_I2C_STATE_READ) ? + CGBC_I2C_READ_MAX_LEN : CGBC_I2C_WRITE_MAX_LEN; + + if (msg->len - i2c->pos > max_len) { + len = max_len; + } else { + len = msg->len - i2c->pos; + + if (i2c->nmsgs == 1) + xfer.stop = true; + } + + if (i2c->state == CGBC_I2C_STATE_WRITE) { + xfer.write = len; + xfer.read = 0; + + for (i = 0; i < len; i++) + xfer.data[i] = msg->buf[i2c->pos + i]; + + cmd_len = cgbc_i2c_xfer_to_cmd(xfer, &cmd[0]); + + ret = cgbc_command(cgbc, &cmd, cmd_len, NULL, 0, NULL); + if (ret) + goto err; + } else if (i2c->state == CGBC_I2C_STATE_READ) { + xfer.write = 0; + xfer.read = len; + + if (i2c->nmsgs > 1 || msg->len - i2c->pos > max_len) + xfer.read |= CGBC_I2C_LAST_ACK; + + cmd_len = cgbc_i2c_xfer_to_cmd(xfer, &cmd[0]); + ret = cgbc_command(cgbc, &cmd, cmd_len, NULL, 0, NULL); + if (ret) + goto err; + + ret = read_poll_timeout(cgbc_i2c_get_status, ret, + ret != CGBC_I2C_STAT_BUSY, 0, + 2 * algo_data->read_maxtime_us, false, adap); + if (ret < 0) + goto err; + + cmd_data = CGBC_I2C_CMD_DATA | algo_data->bus_id; + ret = cgbc_command(cgbc, &cmd_data, sizeof(cmd_data), + msg->buf + i2c->pos, len, NULL); + if (ret) + goto err; + } + + if (len == (msg->len - i2c->pos)) { + i2c->msg++; + i2c->nmsgs--; + i2c->pos = 0; + } else { + i2c->pos += len; + } + + if (i2c->nmsgs == 0) + i2c->state = CGBC_I2C_STATE_DONE; + + return 0; + +err: + i2c->state = CGBC_I2C_STATE_ERROR; + return ret; +} + +static int cgbc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap); + unsigned long timeout = jiffies + HZ; + int ret; + + i2c->state = CGBC_I2C_STATE_INIT; + i2c->msg = msgs; + i2c->nmsgs = num; + i2c->pos = 0; + + while (time_before(jiffies, timeout)) { + ret = cgbc_i2c_xfer_msg(adap); + if (i2c->state == CGBC_I2C_STATE_DONE) + return num; + + if (i2c->state == CGBC_I2C_STATE_ERROR) + return ret; + + if (ret == 0) + timeout = jiffies + HZ; + } + + i2c->state = CGBC_I2C_STATE_ERROR; + return -ETIMEDOUT; +} + +static u32 cgbc_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~(I2C_FUNC_SMBUS_QUICK)); +} + +static const struct i2c_algorithm cgbc_i2c_algorithm = { + .master_xfer = cgbc_i2c_xfer, + .functionality = cgbc_i2c_func, +}; + +static struct i2c_algo_cgbc_data cgbc_i2c_algo_data[] = { + { .bus_id = CGBC_I2C_PRIMARY_BUS_ID }, + { .bus_id = CGBC_I2C_PM_BUS_ID }, +}; + +static const struct i2c_adapter cgbc_i2c_adapter[] = { + { + .owner = THIS_MODULE, + .name = "Congatec General Purpose I2C adapter", + .class = I2C_CLASS_DEPRECATED, + .algo = &cgbc_i2c_algorithm, + .algo_data = &cgbc_i2c_algo_data[0], + .nr = -1, + }, + { + .owner = THIS_MODULE, + .name = "Congatec Power Management I2C adapter", + .class = I2C_CLASS_DEPRECATED, + .algo = &cgbc_i2c_algorithm, + .algo_data = &cgbc_i2c_algo_data[1], + .nr = -1, + }, +}; + +static int cgbc_i2c_probe(struct platform_device *pdev) +{ + struct cgbc_device_data *cgbc = dev_get_drvdata(pdev->dev.parent); + struct cgbc_i2c_data *i2c; + int ret; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->cgbc = cgbc; + i2c->dev = &pdev->dev; + i2c->adap = cgbc_i2c_adapter[pdev->id]; + i2c->adap.dev.parent = i2c->dev; + i2c_set_adapdata(&i2c->adap, i2c); + platform_set_drvdata(pdev, i2c); + + ret = cgbc_i2c_set_frequency(&i2c->adap, I2C_MAX_STANDARD_MODE_FREQ); + if (ret) + return ret; + + return i2c_add_numbered_adapter(&i2c->adap); +} + +static void cgbc_i2c_remove(struct platform_device *pdev) +{ + struct cgbc_i2c_data *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); +} + +static struct platform_driver cgbc_i2c_driver = { + .driver = { + .name = "cgbc-i2c", + }, + .probe = cgbc_i2c_probe, + .remove = cgbc_i2c_remove, +}; + +module_platform_driver(cgbc_i2c_driver); + +MODULE_DESCRIPTION("Congatec Board Controller I2C Driver"); +MODULE_AUTHOR("Thomas Richard "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cgbc_i2c"); diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c index 52e3000626c5a1..26a36a65521e73 100644 --- a/drivers/i2c/busses/i2c-cht-wc.c +++ b/drivers/i2c/busses/i2c-cht-wc.c @@ -546,7 +546,7 @@ MODULE_DEVICE_TABLE(platform, cht_wc_i2c_adap_id_table); static struct platform_driver cht_wc_i2c_adap_driver = { .probe = cht_wc_i2c_adap_i2c_probe, - .remove_new = cht_wc_i2c_adap_i2c_remove, + .remove = cht_wc_i2c_adap_i2c_remove, .driver = { .name = "cht_wcove_ext_chgr", }, diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 4794ec066eb01e..260e1643c2cc0f 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -701,7 +701,7 @@ MODULE_DEVICE_TABLE(of, cpm_i2c_match); static struct platform_driver cpm_i2c_driver = { .probe = cpm_i2c_probe, - .remove_new = cpm_i2c_remove, + .remove = cpm_i2c_remove, .driver = { .name = "fsl-i2c-cpm", .of_match_table = cpm_i2c_match, diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index ab2688bd4d338a..43bf90d90eebab 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -304,7 +304,7 @@ MODULE_DEVICE_TABLE(acpi, cros_ec_i2c_tunnel_acpi_id); static struct platform_driver ec_i2c_tunnel_driver = { .probe = ec_i2c_probe, - .remove_new = ec_i2c_remove, + .remove = ec_i2c_remove, .driver = { .name = "cros-ec-i2c-tunnel", .acpi_match_table = ACPI_PTR(cros_ec_i2c_tunnel_acpi_id), diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index c4fb5e9ab50611..71dc0a6688b7ac 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -935,7 +935,7 @@ MODULE_DEVICE_TABLE(platform, davinci_i2c_driver_ids); static struct platform_driver davinci_i2c_driver = { .probe = davinci_i2c_probe, - .remove_new = davinci_i2c_remove, + .remove = davinci_i2c_remove, .id_table = davinci_i2c_driver_ids, .driver = { .name = "i2c_davinci", diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c index 63454b06e5da17..8fbd2a10c31aad 100644 --- a/drivers/i2c/busses/i2c-designware-amdpsp.c +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c @@ -155,7 +155,7 @@ static void psp_release_i2c_bus_deferred(struct work_struct *work) /* * If there is any pending transaction, cannot release the bus here. - * psp_release_i2c_bus will take care of this later. + * psp_release_i2c_bus() will take care of this later. */ if (psp_i2c_access_count) goto cleanup; @@ -210,12 +210,12 @@ static void psp_release_i2c_bus(void) { mutex_lock(&psp_i2c_access_mutex); - /* Return early if mailbox was malfunctional */ + /* Return early if mailbox was malfunctioned */ if (psp_i2c_mbox_fail) goto cleanup; /* - * If we are last owner of PSP semaphore, need to release aribtration + * If we are last owner of PSP semaphore, need to release arbitration * via mailbox. */ psp_i2c_access_count--; @@ -235,9 +235,9 @@ static void psp_release_i2c_bus(void) /* * Locking methods are based on the default implementation from - * drivers/i2c/i2c-core-base.c, but with psp acquire and release operations + * drivers/i2c/i2c-core-base.c, but with PSP acquire and release operations * added. With this in place we can ensure that i2c clients on the bus shared - * with psp are able to lock HW access to the bus for arbitrary number of + * with PSP are able to lock HW access to the bus for arbitrary number of * operations - that is e.g. write-wait-read. */ static void i2c_adapter_dw_psp_lock_bus(struct i2c_adapter *adapter, diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 9d88b4fa03e423..183a35038eef91 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -29,11 +29,11 @@ #include #include -#define DEFAULT_SYMBOL_NAMESPACE I2C_DW_COMMON +#define DEFAULT_SYMBOL_NAMESPACE "I2C_DW_COMMON" #include "i2c-designware-core.h" -static char *abort_sources[] = { +static const char *const abort_sources[] = { [ABRT_7B_ADDR_NOACK] = "slave address not acknowledged (7bit mode)", [ABRT_10ADDR1_NOACK] = @@ -127,6 +127,8 @@ static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val) * Autodetects needed register access mode and creates the regmap with * corresponding read/write callbacks. This must be called before doing any * other register access. + * + * Return: 0 on success, or negative errno otherwise. */ int i2c_dw_init_regmap(struct dw_i2c_dev *dev) { @@ -174,7 +176,7 @@ int i2c_dw_init_regmap(struct dw_i2c_dev *dev) /* * Note we'll check the return value of the regmap IO accessors only * at the probe stage. The rest of the code won't do this because - * basically we have MMIO-based regmap so non of the read/write methods + * basically we have MMIO-based regmap, so none of the read/write methods * can fail. */ dev->map = devm_regmap_init(dev->dev, NULL, dev, &map_cfg); @@ -336,7 +338,7 @@ static u32 i2c_dw_acpi_round_bus_speed(struct device *device) acpi_speed = i2c_acpi_find_bus_speed(device); /* - * Some DSTDs use a non standard speed, round down to the lowest + * Some DSDTs use a non standard speed, round down to the lowest * standard speed. */ for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) { @@ -380,6 +382,11 @@ int i2c_dw_fw_parse_and_configure(struct dw_i2c_dev *dev) i2c_parse_fw_timings(device, t, false); + if (device_property_read_u32(device, "snps,bus-capacitance-pf", &dev->bus_capacitance_pF)) + dev->bus_capacitance_pF = 100; + + dev->clk_freq_optimized = device_property_read_bool(device, "snps,clk-freq-optimized"); + i2c_dw_adjust_bus_speed(dev); if (is_of_node(fwnode)) @@ -407,47 +414,26 @@ static u32 i2c_dw_read_scl_reg(struct dw_i2c_dev *dev, u32 reg) } u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, - u32 tSYMBOL, u32 tf, int cond, int offset) + u32 tSYMBOL, u32 tf, int offset) { if (!ic_clk) return i2c_dw_read_scl_reg(dev, reg); /* - * DesignWare I2C core doesn't seem to have solid strategy to meet - * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec - * will result in violation of the tHD;STA spec. + * Conditional expression: + * + * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf) + * + * This is just experimental rule; the tHD;STA period turned + * out to be proportinal to (_HCNT + 3). With this setting, + * we could meet both tHIGH and tHD;STA timing specs. + * + * If unsure, you'd better to take this alternative. + * + * The reason why we need to take into account "tf" here, + * is the same as described in i2c_dw_scl_lcnt(). */ - if (cond) - /* - * Conditional expression: - * - * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH - * - * This is based on the DW manuals, and represents an ideal - * configuration. The resulting I2C bus speed will be - * faster than any of the others. - * - * If your hardware is free from tHD;STA issue, try this one. - */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tSYMBOL, MICRO) - - 8 + offset; - else - /* - * Conditional expression: - * - * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf) - * - * This is just experimental rule; the tHD;STA period turned - * out to be proportinal to (_HCNT + 3). With this setting, - * we could meet both tHIGH and tHD;STA timing specs. - * - * If unsure, you'd better to take this alternative. - * - * The reason why we need to take into account "tf" here, - * is the same as described in i2c_dw_scl_lcnt(). - */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - - 3 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset; } u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, @@ -467,8 +453,7 @@ u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, * account the fall time of SCL signal (tf). Default tf value * should be 0.3 us, for safety. */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - - 1 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - 1 + offset; } int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev) @@ -571,7 +556,7 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev) /* * Wait 10 times the signaling period of the highest I2C - * transfer supported by the driver (for 400KHz this is + * transfer supported by the driver (for 400kHz this is * 25us) as described in the DesignWare I2C databook. */ usleep_range(25, 250); @@ -678,10 +663,10 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) if (abort_source & DW_IC_TX_ARB_LOST) return -EAGAIN; - else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) + if (abort_source & DW_IC_TX_ABRT_GCALL_READ) return -EINVAL; /* wrong msgs[] data */ - else - return -EIO; + + return -EIO; } int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 2d32896d067346..347843b4f5dd7a 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -143,10 +143,10 @@ #define DW_IC_SLAVE 1 /* - * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register + * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register. * - * Only expected abort codes are listed here - * refer to the datasheet for the full list + * Only expected abort codes are listed here, + * refer to the datasheet for the full list. */ #define ABRT_7B_ADDR_NOACK 0 #define ABRT_10ADDR1_NOACK 1 @@ -201,7 +201,7 @@ struct reset_control; * @rst: optional reset for the controller * @slave: represent an I2C slave device * @get_clk_rate_khz: callback to retrieve IP specific bus speed - * @cmd_err: run time hadware error code + * @cmd_err: run time hardware error code * @msgs: points to an array of messages currently being transferred * @msgs_num: the number of elements in msgs * @msg_write_idx: the element index of the current tx message in the msgs array @@ -237,11 +237,15 @@ struct reset_control; * @release_lock: function to release a hardware lock on the bus * @semaphore_idx: Index of table with semaphore type attached to the bus. It's * -1 if there is no semaphore. - * @shared_with_punit: true if this bus is shared with the SoCs PUNIT + * @shared_with_punit: true if this bus is shared with the SoC's PUNIT * @init: function to initialize the I2C hardware * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE * @rinfo: I²C GPIO recovery information + * @bus_capacitance_pF: bus capacitance in picofarads + * @clk_freq_optimized: if this value is true, it means the hardware reduces + * its internal clock frequency by reducing the internal latency required + * to generate the high period and low period of SCL line. * * HCNT and LCNT parameters can be used if the platform knows more accurate * values than the one computed based only on the input clock frequency. @@ -299,6 +303,8 @@ struct dw_i2c_dev { int (*set_sda_hold_time)(struct dw_i2c_dev *dev); int mode; struct i2c_bus_recovery_info rinfo; + u32 bus_capacitance_pF; + bool clk_freq_optimized; }; #define ACCESS_INTR_MASK BIT(0) @@ -329,7 +335,7 @@ struct i2c_dw_semaphore_callbacks { int i2c_dw_init_regmap(struct dw_i2c_dev *dev); u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, - u32 tSYMBOL, u32 tf, int cond, int offset); + u32 tSYMBOL, u32 tf, int offset); u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, u32 tLOW, u32 tf, int offset); int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index e8ac9a7bf0b3d2..c8cbe5b1aeb197 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -22,7 +22,7 @@ #include #include -#define DEFAULT_SYMBOL_NAMESPACE I2C_DW +#define DEFAULT_SYMBOL_NAMESPACE "I2C_DW" #include "i2c-designware-core.h" @@ -71,7 +71,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) ic_clk, 4000, /* tHD;STA = tHIGH = 4.0 us */ sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ dev->ss_lcnt = i2c_dw_scl_lcnt(dev, @@ -105,7 +104,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) ic_clk, 260, /* tHIGH = 260 ns */ sda_falling_time, - 0, /* DW default */ 0); /* No offset */ dev->fs_lcnt = i2c_dw_scl_lcnt(dev, @@ -129,7 +127,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) ic_clk, 600, /* tHD;STA = tHIGH = 0.6 us */ sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ dev->fs_lcnt = i2c_dw_scl_lcnt(dev, @@ -154,20 +151,38 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) dev->hs_hcnt = 0; dev->hs_lcnt = 0; } else if (!dev->hs_hcnt || !dev->hs_lcnt) { + u32 t_high, t_low; + + /* + * The legal values stated in the databook for bus + * capacitance are only 100pF and 400pF. + * If dev->bus_capacitance_pF is greater than or equals + * to 400, t_high and t_low are assumed to be + * appropriate values for 400pF, otherwise 100pF. + */ + if (dev->bus_capacitance_pF >= 400) { + /* assume bus capacitance is 400pF */ + t_high = dev->clk_freq_optimized ? 160 : 120; + t_low = 320; + } else { + /* assume bus capacitance is 100pF */ + t_high = 60; + t_low = dev->clk_freq_optimized ? 120 : 160; + } + ic_clk = i2c_dw_clk_rate(dev); dev->hs_hcnt = i2c_dw_scl_hcnt(dev, DW_IC_HS_SCL_HCNT, ic_clk, - 160, /* tHIGH = 160 ns */ + t_high, sda_falling_time, - 0, /* DW default */ 0); /* No offset */ dev->hs_lcnt = i2c_dw_scl_lcnt(dev, DW_IC_HS_SCL_LCNT, ic_clk, - 320, /* tLOW = 320 ns */ + t_low, scl_falling_time, 0); /* No offset */ } @@ -184,12 +199,14 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) } /** - * i2c_dw_init_master() - Initialize the designware I2C master hardware + * i2c_dw_init_master() - Initialize the DesignWare I2C master hardware * @dev: device private data * * This functions configures and enables the I2C master. * This function is called during I2C init function, and in case of timeout at * run time. + * + * Return: 0 on success, or negative errno otherwise. */ static int i2c_dw_init_master(struct dw_i2c_dev *dev) { @@ -357,7 +374,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, /* * Initiate the i2c read/write transaction of buffer length, * and poll for bus busy status. For the last message transfer, - * update the command with stopbit enable. + * update the command with stop bit enable. */ for (msg_itr_lmt = buf_len; msg_itr_lmt > 0; msg_itr_lmt--) { if (msg_wrt_idx == num_msgs - 1 && msg_itr_lmt == 1) @@ -402,7 +419,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, /* * Initiate (and continue) low level master read/write transaction. - * This function is only called from i2c_dw_isr, and pumping i2c_msg + * This function is only called from i2c_dw_isr(), and pumping i2c_msg * messages into the tx buffer. Even if the size of i2c_msg data is * longer than the size of the tx buffer, it handles everything. */ @@ -440,7 +457,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) buf = msgs[dev->msg_write_idx].buf; buf_len = msgs[dev->msg_write_idx].len; - /* If both IC_EMPTYFIFO_HOLD_MASTER_EN and + /* + * If both IC_EMPTYFIFO_HOLD_MASTER_EN and * IC_RESTART_EN are set, we must manually * set restart bit between messages. */ @@ -971,7 +989,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) rinfo->unprepare_recovery = i2c_dw_unprepare_recovery; adap->bus_recovery_info = rinfo; - dev_info(dev->dev, "running with gpio recovery mode! scl%s", + dev_info(dev->dev, "running with GPIO recovery mode! scl%s", rinfo->sda_gpiod ? ",sda" : ""); return 0; @@ -1076,4 +1094,4 @@ EXPORT_SYMBOL_GPL(i2c_dw_probe_master); MODULE_DESCRIPTION("Synopsys DesignWare I2C bus master adapter"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(I2C_DW_COMMON); +MODULE_IMPORT_NS("I2C_DW_COMMON"); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 7b2c5d71a7fcec..8e0267c7cc294e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -51,7 +51,7 @@ struct dw_scl_sda_cfg { u16 fs_hcnt; u16 ss_lcnt; u16 fs_lcnt; - u32 sda_hold; + u32 sda_hold_time; }; struct dw_pci_controller { @@ -76,7 +76,7 @@ static struct dw_scl_sda_cfg byt_config = { .fs_hcnt = 0x55, .ss_lcnt = 0x200, .fs_lcnt = 0x99, - .sda_hold = 0x6, + .sda_hold_time = 0x6, }; /* Haswell HCNT/LCNT/SDA hold time */ @@ -85,14 +85,14 @@ static struct dw_scl_sda_cfg hsw_config = { .fs_hcnt = 0x48, .ss_lcnt = 0x01fb, .fs_lcnt = 0xa0, - .sda_hold = 0x9, + .sda_hold_time = 0x9, }; /* NAVI-AMD HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg navi_amd_config = { .ss_hcnt = 0x1ae, .ss_lcnt = 0x23a, - .sda_hold = 0x9, + .sda_hold_time = 0x9, }; static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev) @@ -207,6 +207,7 @@ static const struct software_node dgpu_node = { static int i2c_dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *device = &pdev->dev; struct dw_i2c_dev *dev; struct i2c_adapter *adap; int r; @@ -214,25 +215,22 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, struct dw_scl_sda_cfg *cfg; if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) - return dev_err_probe(&pdev->dev, -EINVAL, - "Invalid driver data %ld\n", + return dev_err_probe(device, -EINVAL, "Invalid driver data %ld\n", id->driver_data); controller = &dw_pci_controllers[id->driver_data]; r = pcim_enable_device(pdev); if (r) - return dev_err_probe(&pdev->dev, r, - "Failed to enable I2C PCI device\n"); + return dev_err_probe(device, r, "Failed to enable I2C PCI device\n"); pci_set_master(pdev); r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); if (r) - return dev_err_probe(&pdev->dev, r, - "I/O memory remapping failed\n"); + return dev_err_probe(device, r, "I/O memory remapping failed\n"); - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -242,7 +240,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->get_clk_rate_khz = controller->get_clk_rate_khz; dev->base = pcim_iomap_table(pdev)[0]; - dev->dev = &pdev->dev; + dev->dev = device; dev->irq = pci_irq_vector(pdev, 0); dev->flags |= controller->flags; @@ -266,7 +264,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->fs_hcnt = cfg->fs_hcnt; dev->ss_lcnt = cfg->ss_lcnt; dev->fs_lcnt = cfg->fs_lcnt; - dev->sda_hold_time = cfg->sda_hold; + dev->sda_hold_time = cfg->sda_hold_time; } adap = &dev->adapter; @@ -281,14 +279,14 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) { dev->slave = i2c_new_ccgx_ucsi(&dev->adapter, dev->irq, &dgpu_node); if (IS_ERR(dev->slave)) - return dev_err_probe(dev->dev, PTR_ERR(dev->slave), + return dev_err_probe(device, PTR_ERR(dev->slave), "register UCSI failed\n"); } - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); - pm_runtime_allow(&pdev->dev); + pm_runtime_set_autosuspend_delay(device, 1000); + pm_runtime_use_autosuspend(device); + pm_runtime_put_autosuspend(device); + pm_runtime_allow(device); return 0; } @@ -296,11 +294,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, static void i2c_dw_pci_remove(struct pci_dev *pdev) { struct dw_i2c_dev *dev = pci_get_drvdata(pdev); + struct device *device = &pdev->dev; i2c_dw_disable(dev); - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); + pm_runtime_forbid(device); + pm_runtime_get_noresume(device); i2c_del_adapter(&dev->adapter); } @@ -369,5 +368,5 @@ module_pci_driver(dw_i2c_driver); MODULE_AUTHOR("Baruch Siach "); MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(I2C_DW); -MODULE_IMPORT_NS(I2C_DW_COMMON); +MODULE_IMPORT_NS("I2C_DW"); +MODULE_IMPORT_NS("I2C_DW_COMMON"); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 2d0c7348e4917c..d6e1ee935399d7 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -72,7 +72,7 @@ static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val) return ret; return regmap_write(dev->sysmap, BT1_I2C_CTL, - BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK)); + BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK)); } static const struct regmap_config bt1_i2c_cfg = { @@ -205,6 +205,7 @@ static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) static int dw_i2c_plat_probe(struct platform_device *pdev) { + struct device *device = &pdev->dev; struct i2c_adapter *adap; struct dw_i2c_dev *dev; int irq, ret; @@ -213,15 +214,15 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (irq < 0) return irq; - dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); + dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - dev->flags = (uintptr_t)device_get_match_data(&pdev->dev); - if (device_property_present(&pdev->dev, "wx,i2c-snps-model")) + dev->flags = (uintptr_t)device_get_match_data(device); + if (device_property_present(device, "wx,i2c-snps-model")) dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING; - dev->dev = &pdev->dev; + dev->dev = device; dev->irq = irq; platform_set_drvdata(pdev, dev); @@ -229,7 +230,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (ret) return ret; - dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + dev->rst = devm_reset_control_get_optional_exclusive(device, NULL); if (IS_ERR(dev->rst)) return PTR_ERR(dev->rst); @@ -246,13 +247,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) i2c_dw_configure(dev); /* Optional interface clock */ - dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk"); + dev->pclk = devm_clk_get_optional(device, "pclk"); if (IS_ERR(dev->pclk)) { ret = PTR_ERR(dev->pclk); goto exit_reset; } - dev->clk = devm_clk_get_optional(&pdev->dev, NULL); + dev->clk = devm_clk_get_optional(device, NULL); if (IS_ERR(dev->clk)) { ret = PTR_ERR(dev->clk); goto exit_reset; @@ -277,31 +278,27 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) adap = &dev->adapter; adap->owner = THIS_MODULE; adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ? - I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED; + I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED; adap->nr = -1; - if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { - dev_pm_set_driver_flags(&pdev->dev, - DPM_FLAG_SMART_PREPARE); - } else { - dev_pm_set_driver_flags(&pdev->dev, - DPM_FLAG_SMART_PREPARE | - DPM_FLAG_SMART_SUSPEND); - } + if (dev->flags & ACCESS_NO_IRQ_SUSPEND) + dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE); + else + dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE | DPM_FLAG_SMART_SUSPEND); - device_enable_async_suspend(&pdev->dev); + device_enable_async_suspend(device); /* The code below assumes runtime PM to be disabled. */ - WARN_ON(pm_runtime_enabled(&pdev->dev)); + WARN_ON(pm_runtime_enabled(device)); - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(device, 1000); + pm_runtime_use_autosuspend(device); + pm_runtime_set_active(device); if (dev->shared_with_punit) - pm_runtime_get_noresume(&pdev->dev); + pm_runtime_get_noresume(device); - pm_runtime_enable(&pdev->dev); + pm_runtime_enable(device); ret = i2c_dw_probe(dev); if (ret) @@ -319,15 +316,16 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) static void dw_i2c_plat_remove(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + struct device *device = &pdev->dev; - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(device); i2c_del_adapter(&dev->adapter); i2c_dw_disable(dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_dont_use_autosuspend(device); + pm_runtime_put_sync(device); dw_i2c_plat_pm_cleanup(dev); i2c_dw_remove_lock_support(dev); @@ -351,9 +349,11 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { { "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE }, { "AMDI0510", 0 }, { "APMC0D0F", 0 }, + { "FUJI200B", 0 }, { "HISI02A1", 0 }, { "HISI02A2", 0 }, { "HISI02A3", 0 }, + { "HJMC3001", 0 }, { "HYGO0010", ACCESS_INTR_MASK }, { "INT33C2", 0 }, { "INT33C3", 0 }, @@ -372,7 +372,7 @@ MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids); static struct platform_driver dw_i2c_driver = { .probe = dw_i2c_plat_probe, - .remove_new = dw_i2c_plat_remove, + .remove = dw_i2c_plat_remove, .driver = { .name = "i2c_designware", .of_match_table = dw_i2c_of_match, @@ -397,5 +397,5 @@ module_exit(dw_i2c_exit_driver); MODULE_AUTHOR("Baruch Siach "); MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(I2C_DW); -MODULE_IMPORT_NS(I2C_DW_COMMON); +MODULE_IMPORT_NS("I2C_DW"); +MODULE_IMPORT_NS("I2C_DW_COMMON"); diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index 7035296aa24ce0..dc2b788eac5bdc 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -16,7 +16,7 @@ #include #include -#define DEFAULT_SYMBOL_NAMESPACE I2C_DW +#define DEFAULT_SYMBOL_NAMESPACE "I2C_DW" #include "i2c-designware-core.h" @@ -32,12 +32,14 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) } /** - * i2c_dw_init_slave() - Initialize the designware i2c slave hardware + * i2c_dw_init_slave() - Initialize the DesignWare i2c slave hardware * @dev: device private data * * This function configures and enables the I2C in slave mode. * This function is called during I2C init function, and in case of timeout at * run time. + * + * Return: 0 on success, or negative errno otherwise. */ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) { @@ -264,7 +266,7 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave, IRQF_SHARED, dev_name(dev->dev), dev); if (ret) { - dev_err(dev->dev, "failure requesting irq %i: %d\n", + dev_err(dev->dev, "failure requesting IRQ %i: %d\n", dev->irq, ret); return ret; } @@ -280,4 +282,4 @@ EXPORT_SYMBOL_GPL(i2c_dw_probe_slave); MODULE_AUTHOR("Luis Oliveira "); MODULE_DESCRIPTION("Synopsys DesignWare I2C bus slave adapter"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(I2C_DW_COMMON); +MODULE_IMPORT_NS("I2C_DW_COMMON"); diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c index 3dc5a46698fc95..38d7f31aee79c1 100644 --- a/drivers/i2c/busses/i2c-digicolor.c +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -363,7 +363,7 @@ MODULE_DEVICE_TABLE(of, dc_i2c_match); static struct platform_driver dc_i2c_driver = { .probe = dc_i2c_probe, - .remove_new = dc_i2c_remove, + .remove = dc_i2c_remove, .driver = { .name = "digicolor-i2c", .of_match_table = dc_i2c_match, diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c index 11ed055143d344..bde2ef09886268 100644 --- a/drivers/i2c/busses/i2c-dln2.c +++ b/drivers/i2c/busses/i2c-dln2.c @@ -245,7 +245,7 @@ static void dln2_i2c_remove(struct platform_device *pdev) static struct platform_driver dln2_i2c_driver = { .driver.name = "dln2-i2c", .probe = dln2_i2c_probe, - .remove_new = dln2_i2c_remove, + .remove = dln2_i2c_remove, }; module_platform_driver(dln2_i2c_driver); diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index d08be3f3cede3d..2512cef8e2a292 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -425,7 +425,7 @@ static const struct of_device_id em_i2c_ids[] = { static struct platform_driver em_i2c_driver = { .probe = em_i2c_probe, - .remove_new = em_i2c_remove, + .remove = em_i2c_remove, .driver = { .name = "em-i2c", .of_match_table = em_i2c_ids, diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index d8baca9b610c3b..e330015087ab8f 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -1009,7 +1009,7 @@ static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = { static struct platform_driver exynos5_i2c_driver = { .probe = exynos5_i2c_probe, - .remove_new = exynos5_i2c_remove, + .remove = exynos5_i2c_remove, .driver = { .name = "exynos5-hsi2c", .pm = pm_sleep_ptr(&exynos5_i2c_dev_pm_ops), diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index e0bd218e2f146c..f4355b17bfbf15 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -481,7 +481,7 @@ static struct platform_driver i2c_gpio_driver = { .acpi_match_table = i2c_gpio_acpi_match, }, .probe = i2c_gpio_probe, - .remove_new = i2c_gpio_remove, + .remove = i2c_gpio_remove, }; static int __init i2c_gpio_init(void) diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c index efafc0528c44da..0fc39caa6c871e 100644 --- a/drivers/i2c/busses/i2c-gxp.c +++ b/drivers/i2c/busses/i2c-gxp.c @@ -595,7 +595,7 @@ MODULE_DEVICE_TABLE(of, gxp_i2c_of_match); static struct platform_driver gxp_i2c_driver = { .probe = gxp_i2c_probe, - .remove_new = gxp_i2c_remove, + .remove = gxp_i2c_remove, .driver = { .name = "gxp-i2c", .of_match_table = gxp_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index ec1ebacb9aa8d1..78c5845e0877ae 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -454,7 +454,7 @@ static struct platform_driver highlander_i2c_driver = { }, .probe = highlander_i2c_probe, - .remove_new = highlander_i2c_remove, + .remove = highlander_i2c_remove, }; module_platform_driver(highlander_i2c_driver); diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index 64cade6ba92344..370f329747637c 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -508,7 +508,7 @@ MODULE_DEVICE_TABLE(of, hix5hd2_i2c_match); static struct platform_driver hix5hd2_i2c_driver = { .probe = hix5hd2_i2c_probe, - .remove_new = hix5hd2_i2c_remove, + .remove = hix5hd2_i2c_remove, .driver = { .name = "hix5hd2-i2c", .pm = pm_ptr(&hix5hd2_i2c_pm_ops), diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 299fe9d3afab0a..75dab01d43a750 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -81,6 +81,8 @@ * Meteor Lake PCH-S (PCH) 0x7f23 32 hard yes yes yes * Birch Stream (SOC) 0x5796 32 hard yes yes yes * Arrow Lake-H (SOC) 0x7722 32 hard yes yes yes + * Panther Lake-H (SOC) 0xe322 32 hard yes yes yes + * Panther Lake-P (SOC) 0xe422 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -261,6 +263,8 @@ #define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323 #define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3 #define PCI_DEVICE_ID_INTEL_METEOR_LAKE_SOC_S_SMBUS 0xae22 +#define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_H_SMBUS 0xe322 +#define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_P_SMBUS 0xe422 struct i801_mux_config { char *gpio_chip; @@ -1055,6 +1059,8 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 82dedb1bb5bee7..c76c4116ddc736 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -790,7 +790,7 @@ static struct platform_driver ibm_iic_driver = { .of_match_table = ibm_iic_match, }, .probe = iic_probe, - .remove_new = iic_remove, + .remove = iic_remove, }; module_platform_driver(ibm_iic_driver); diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index e0e87185f6bbfc..02f75cf310aaa7 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -1497,7 +1497,7 @@ static struct platform_driver img_scb_i2c_driver = { .pm = pm_ptr(&img_i2c_pm), }, .probe = img_i2c_probe, - .remove_new = img_i2c_remove, + .remove = img_i2c_remove, }; module_platform_driver(img_scb_i2c_driver); diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 976d43f73f3830..8adf2963d764eb 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -703,7 +703,7 @@ static const struct dev_pm_ops lpi2c_pm_ops = { static struct platform_driver lpi2c_imx_driver = { .probe = lpi2c_imx_probe, - .remove_new = lpi2c_imx_remove, + .remove = lpi2c_imx_remove, .driver = { .name = DRIVER_NAME, .of_match_table = lpi2c_imx_of_match, diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 98539313cbc970..f751d231ded87c 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -17,7 +17,7 @@ * Copyright (C) 2008 Darius Augulis * * Copyright 2013 Freescale Semiconductor, Inc. - * Copyright 2020 NXP + * Copyright 2020, 2024 NXP * */ @@ -84,6 +84,7 @@ #define IMX_I2C_REGSHIFT 2 #define VF610_I2C_REGSHIFT 0 +#define S32G_I2C_REGSHIFT 0 /* Bits of IMX I2C registers */ #define I2SR_RXAK 0x01 @@ -165,9 +166,34 @@ static struct imx_i2c_clk_pair vf610_i2c_clk_div[] = { { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E }, }; +/* S32G2/S32G3 clock divider, register value pairs */ +static struct imx_i2c_clk_pair s32g2_i2c_clk_div[] = { + { 34, 0x00 }, { 36, 0x01 }, { 38, 0x02 }, { 40, 0x03 }, + { 42, 0x04 }, { 44, 0x05 }, { 46, 0x06 }, { 48, 0x09 }, + { 52, 0x0A }, { 54, 0x07 }, { 56, 0x0B }, { 60, 0x0C }, + { 64, 0x0D }, { 68, 0x40 }, { 72, 0x0E }, { 76, 0x42 }, + { 80, 0x12 }, { 84, 0x0F }, { 88, 0x13 }, { 96, 0x14 }, + { 104, 0x15 }, { 108, 0x47 }, { 112, 0x19 }, { 120, 0x16 }, + { 128, 0x1A }, { 136, 0x80 }, { 144, 0x17 }, { 152, 0x82 }, + { 160, 0x1C }, { 168, 0x84 }, { 176, 0x1D }, { 192, 0x21 }, + { 208, 0x1E }, { 216, 0x87 }, { 224, 0x22 }, { 240, 0x56 }, + { 256, 0x1F }, { 288, 0x24 }, { 320, 0x25 }, { 336, 0x8F }, + { 352, 0x93 }, { 356, 0x5D }, { 358, 0x98 }, { 384, 0x26 }, + { 416, 0x56 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B }, + { 576, 0x2C }, { 640, 0x2D }, { 704, 0x9D }, { 768, 0x2E }, + { 832, 0x9D }, { 896, 0x32 }, { 960, 0x2F }, { 1024, 0x33 }, + { 1152, 0x34 }, { 1280, 0x35 }, { 1536, 0x36 }, { 1792, 0x3A }, + { 1920, 0x37 }, { 2048, 0x3B }, { 2304, 0x74 }, { 2560, 0x3D }, + { 3072, 0x3E }, { 3584, 0x7A }, { 3840, 0x3F }, { 4096, 0x7B }, + { 4608, 0x7C }, { 5120, 0x7D }, { 6144, 0x7E }, { 7168, 0xBA }, + { 7680, 0x7F }, { 8192, 0xBB }, { 9216, 0xBC }, { 10240, 0xBD }, + { 12288, 0xBE }, { 15360, 0xBF }, +}; + enum imx_i2c_type { IMX1_I2C, IMX21_I2C, + S32G_I2C, VF610_I2C, }; @@ -197,6 +223,17 @@ struct imx_i2c_dma { enum dma_data_direction dma_data_dir; }; +enum imx_i2c_state { + IMX_I2C_STATE_DONE, + IMX_I2C_STATE_FAILED, + IMX_I2C_STATE_WRITE, + IMX_I2C_STATE_DMA, + IMX_I2C_STATE_READ, + IMX_I2C_STATE_READ_CONTINUE, + IMX_I2C_STATE_READ_BLOCK_DATA, + IMX_I2C_STATE_READ_BLOCK_DATA_LEN, +}; + struct imx_i2c_struct { struct i2c_adapter adapter; struct clk *clk; @@ -216,6 +253,14 @@ struct imx_i2c_struct { struct i2c_client *slave; enum i2c_slave_event last_slave_event; + struct i2c_msg *msg; + unsigned int msg_buf_idx; + int isr_result; + bool is_lastmsg; + enum imx_i2c_state state; + + bool multi_master; + /* For checking slave events. */ spinlock_t slave_lock; struct hrtimer slave_timer; @@ -258,7 +303,15 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = { .ndivs = ARRAY_SIZE(vf610_i2c_clk_div), .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C, .i2cr_ien_opcode = I2CR_IEN_OPCODE_0, +}; +static const struct imx_i2c_hwdata s32g2_i2c_hwdata = { + .devtype = S32G_I2C, + .regshift = S32G_I2C_REGSHIFT, + .clk_div = s32g2_i2c_clk_div, + .ndivs = ARRAY_SIZE(s32g2_i2c_clk_div), + .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C, + .i2cr_ien_opcode = I2CR_IEN_OPCODE_0, }; static const struct platform_device_id imx_i2c_devtype[] = { @@ -288,6 +341,7 @@ static const struct of_device_id i2c_imx_dt_ids[] = { { .compatible = "fsl,imx8mp-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx8mq-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, }, + { .compatible = "nxp,s32g2-i2c", .data = &s32g2_i2c_hwdata, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); @@ -481,6 +535,9 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a unsigned long orig_jiffies = jiffies; unsigned int temp; + if (!i2c_imx->multi_master) + return 0; + while (1) { temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); @@ -540,8 +597,8 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic) return -ETIMEDOUT; } - /* check for arbitration lost */ - if (i2c_imx->i2csr & I2SR_IAL) { + /* In multi-master mode check for arbitration lost */ + if (i2c_imx->multi_master && (i2c_imx->i2csr & I2SR_IAL)) { dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__); i2c_imx_clear_irq(i2c_imx, I2SR_IAL); @@ -903,11 +960,156 @@ static int i2c_imx_unreg_slave(struct i2c_client *client) return ret; } +static inline int i2c_imx_isr_acked(struct imx_i2c_struct *i2c_imx) +{ + i2c_imx->isr_result = 0; + + if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) { + i2c_imx->state = IMX_I2C_STATE_FAILED; + i2c_imx->isr_result = -ENXIO; + wake_up(&i2c_imx->queue); + } + + return i2c_imx->isr_result; +} + +static inline int i2c_imx_isr_write(struct imx_i2c_struct *i2c_imx) +{ + int result; + + result = i2c_imx_isr_acked(i2c_imx); + if (result) + return result; + + if (i2c_imx->msg->len == i2c_imx->msg_buf_idx) + return 0; + + imx_i2c_write_reg(i2c_imx->msg->buf[i2c_imx->msg_buf_idx++], i2c_imx, IMX_I2C_I2DR); + + return 1; +} + +static inline int i2c_imx_isr_read(struct imx_i2c_struct *i2c_imx) +{ + int result; + unsigned int temp; + + result = i2c_imx_isr_acked(i2c_imx); + if (result) + return result; + + /* setup bus to read data */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~I2CR_MTX; + if (i2c_imx->msg->len - 1) + temp &= ~I2CR_TXAK; + + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ + + return 0; +} + +static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx) +{ + unsigned int temp; + + if ((i2c_imx->msg->len - 1) == i2c_imx->msg_buf_idx) { + if (i2c_imx->is_lastmsg) { + /* + * It must generate STOP before read I2DR to prevent + * controller from generating another clock cycle + */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + if (!(temp & I2CR_MSTA)) + i2c_imx->stopped = 1; + temp &= ~(I2CR_MSTA | I2CR_MTX); + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } else { + /* + * For i2c master receiver repeat restart operation like: + * read -> repeat MSTA -> read/write + * The controller must set MTX before read the last byte in + * the first read operation, otherwise the first read cost + * one extra clock cycle. + */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_MTX; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } + } else if (i2c_imx->msg_buf_idx == (i2c_imx->msg->len - 2)) { + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_TXAK; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } + + i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); +} + +static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx) +{ + u8 len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + + if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) { + i2c_imx->isr_result = -EPROTO; + i2c_imx->state = IMX_I2C_STATE_FAILED; + wake_up(&i2c_imx->queue); + } + i2c_imx->msg->len += len; +} + static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status) { - /* save status register */ - i2c_imx->i2csr = status; - wake_up(&i2c_imx->queue); + /* + * This state machine handles I2C reception and transmission in non-DMA + * mode. We must process all the data in the ISR to reduce the delay + * between two consecutive messages. If the data is not processed in + * the ISR, SMBus devices may timeout, leading to a bus error. + */ + switch (i2c_imx->state) { + case IMX_I2C_STATE_DMA: + i2c_imx->i2csr = status; + wake_up(&i2c_imx->queue); + break; + + case IMX_I2C_STATE_READ: + if (i2c_imx_isr_read(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE; + break; + + case IMX_I2C_STATE_READ_CONTINUE: + i2c_imx_isr_read_continue(i2c_imx); + if (i2c_imx->msg_buf_idx == i2c_imx->msg->len) { + i2c_imx->state = IMX_I2C_STATE_DONE; + wake_up(&i2c_imx->queue); + } + break; + + case IMX_I2C_STATE_READ_BLOCK_DATA: + if (i2c_imx_isr_read(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA_LEN; + break; + + case IMX_I2C_STATE_READ_BLOCK_DATA_LEN: + i2c_imx_isr_read_block_data_len(i2c_imx); + i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE; + break; + + case IMX_I2C_STATE_WRITE: + if (i2c_imx_isr_write(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_DONE; + wake_up(&i2c_imx->queue); + break; + + default: + i2c_imx->i2csr = status; + i2c_imx->state = IMX_I2C_STATE_FAILED; + i2c_imx->isr_result = -EINVAL; + wake_up(&i2c_imx->queue); + } return IRQ_HANDLED; } @@ -954,6 +1156,8 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, struct imx_i2c_dma *dma = i2c_imx->dma; struct device *dev = &i2c_imx->adapter.dev; + i2c_imx->state = IMX_I2C_STATE_DMA; + dma->chan_using = dma->chan_tx; dma->dma_transfer_dir = DMA_MEM_TO_DEV; dma->dma_data_dir = DMA_TO_DEVICE; @@ -1006,6 +1210,42 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, return i2c_imx_acked(i2c_imx); } +static int i2c_imx_prepare_read(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs, bool use_dma) +{ + int result; + unsigned int temp = 0; + + /* write slave address */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + result = i2c_imx_trx_complete(i2c_imx, !use_dma); + if (result) + return result; + result = i2c_imx_acked(i2c_imx); + if (result) + return result; + + dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__); + + /* setup bus to read data */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~I2CR_MTX; + + /* + * Reset the I2CR_TXAK flag initially for SMBus block read since the + * length is unknown + */ + if (msgs->len - 1) + temp &= ~I2CR_TXAK; + if (use_dma) + temp |= I2CR_DMAEN; + + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ + + return 0; +} + static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) { @@ -1016,6 +1256,13 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct imx_i2c_dma *dma = i2c_imx->dma; struct device *dev = &i2c_imx->adapter.dev; + i2c_imx->state = IMX_I2C_STATE_DMA; + + result = i2c_imx_prepare_read(i2c_imx, msgs, true); + if (result) + return result; + + dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); dma->chan_using = dma->chan_rx; dma->dma_transfer_dir = DMA_DEV_TO_MEM; @@ -1092,8 +1339,8 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, return 0; } -static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, - bool atomic) +static int i2c_imx_atomic_write(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs) { int i, result; @@ -1102,7 +1349,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, /* write slave address */ imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -1116,7 +1363,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, "<%s> write byte: B%d=0x%X\n", __func__, i, msgs->buf[i]); imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -1126,55 +1373,54 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, return 0; } -static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, - bool is_lastmsg, bool atomic) +static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) +{ + dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", + __func__, i2c_8bit_addr_from_msg(msgs)); + + i2c_imx->state = IMX_I2C_STATE_WRITE; + i2c_imx->msg = msgs; + i2c_imx->msg_buf_idx = 0; + + /* + * By writing the device address we start the state machine in the ISR. + * The ISR will report when it is done or when it fails. + */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + wait_event_timeout(i2c_imx->queue, + i2c_imx->state == IMX_I2C_STATE_DONE || + i2c_imx->state == IMX_I2C_STATE_FAILED, + (msgs->len + 1) * HZ / 10); + if (i2c_imx->state == IMX_I2C_STATE_FAILED) { + dev_dbg(&i2c_imx->adapter.dev, "<%s> write failed with %d\n", + __func__, i2c_imx->isr_result); + return i2c_imx->isr_result; + } + if (i2c_imx->state != IMX_I2C_STATE_DONE) { + dev_err(&i2c_imx->adapter.dev, "<%s> write timedout\n", __func__); + return -ETIMEDOUT; + } + return 0; +} + +static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs, bool is_lastmsg) { int i, result; unsigned int temp; int block_data = msgs->flags & I2C_M_RECV_LEN; - int use_dma = i2c_imx->dma && msgs->flags & I2C_M_DMA_SAFE && - msgs->len >= DMA_THRESHOLD && !block_data; - - dev_dbg(&i2c_imx->adapter.dev, - "<%s> write slave address: addr=0x%x\n", - __func__, i2c_8bit_addr_from_msg(msgs)); - /* write slave address */ - imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); - if (result) - return result; - result = i2c_imx_acked(i2c_imx); + result = i2c_imx_prepare_read(i2c_imx, msgs, false); if (result) return result; - dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__); - - /* setup bus to read data */ - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - temp &= ~I2CR_MTX; - - /* - * Reset the I2CR_TXAK flag initially for SMBus block read since the - * length is unknown - */ - if ((msgs->len - 1) || block_data) - temp &= ~I2CR_TXAK; - if (use_dma) - temp |= I2CR_DMAEN; - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ - dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); - if (use_dma) - return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); - /* read data */ for (i = 0; i < msgs->len; i++) { u8 len = 0; - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; /* @@ -1205,7 +1451,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, temp &= ~(I2CR_MSTA | I2CR_MTX); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); if (!i2c_imx->stopped) - i2c_imx_bus_busy(i2c_imx, 0, atomic); + i2c_imx_bus_busy(i2c_imx, 0, true); } else { /* * For i2c master receiver repeat restart operation like: @@ -1236,6 +1482,48 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, return 0; } +static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, + bool is_lastmsg) +{ + int block_data = msgs->flags & I2C_M_RECV_LEN; + + dev_dbg(&i2c_imx->adapter.dev, + "<%s> write slave address: addr=0x%x\n", + __func__, i2c_8bit_addr_from_msg(msgs)); + + i2c_imx->is_lastmsg = is_lastmsg; + + if (block_data) + i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA; + else + i2c_imx->state = IMX_I2C_STATE_READ; + i2c_imx->msg = msgs; + i2c_imx->msg_buf_idx = 0; + + /* + * By writing the device address we start the state machine in the ISR. + * The ISR will report when it is done or when it fails. + */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + wait_event_timeout(i2c_imx->queue, + i2c_imx->state == IMX_I2C_STATE_DONE || + i2c_imx->state == IMX_I2C_STATE_FAILED, + (msgs->len + 1) * HZ / 10); + if (i2c_imx->state == IMX_I2C_STATE_FAILED) { + dev_dbg(&i2c_imx->adapter.dev, "<%s> read failed with %d\n", + __func__, i2c_imx->isr_result); + return i2c_imx->isr_result; + } + if (i2c_imx->state != IMX_I2C_STATE_DONE) { + dev_err(&i2c_imx->adapter.dev, "<%s> read timedout\n", __func__); + return -ETIMEDOUT; + } + if (!i2c_imx->stopped) + return i2c_imx_bus_busy(i2c_imx, 0, false); + + return 0; +} + static int i2c_imx_xfer_common(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num, bool atomic) { @@ -1243,6 +1531,7 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, int result; bool is_lastmsg = false; struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); + int use_dma = 0; /* Start I2C transfer */ result = i2c_imx_start(i2c_imx, atomic); @@ -1295,15 +1584,25 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0), (temp & I2SR_RXAK ? 1 : 0)); #endif + + use_dma = i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD && + msgs[i].flags & I2C_M_DMA_SAFE; if (msgs[i].flags & I2C_M_RD) { - result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic); + int block_data = msgs->flags & I2C_M_RECV_LEN; + + if (atomic) + result = i2c_imx_atomic_read(i2c_imx, &msgs[i], is_lastmsg); + else if (use_dma && !block_data) + result = i2c_imx_dma_read(i2c_imx, &msgs[i], is_lastmsg); + else + result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg); } else { - if (!atomic && - i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD && - msgs[i].flags & I2C_M_DMA_SAFE) + if (atomic) + result = i2c_imx_atomic_write(i2c_imx, &msgs[i]); + else if (use_dma) result = i2c_imx_dma_write(i2c_imx, &msgs[i]); else - result = i2c_imx_write(i2c_imx, &msgs[i], atomic); + result = i2c_imx_write(i2c_imx, &msgs[i]); } if (result) goto fail0; @@ -1468,6 +1767,12 @@ static int i2c_imx_probe(struct platform_device *pdev) goto rpm_disable; } + /* + * We use the single-master property for backward compatibility. + * By default multi master mode is enabled. + */ + i2c_imx->multi_master = !of_property_read_bool(pdev->dev.of_node, "single-master"); + /* Set up clock divider */ i2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ; ret = of_property_read_u32(pdev->dev.of_node, @@ -1576,7 +1881,7 @@ static const struct dev_pm_ops i2c_imx_pm_ops = { static struct platform_driver i2c_imx_driver = { .probe = i2c_imx_probe, - .remove_new = i2c_imx_remove, + .remove = i2c_imx_remove, .driver = { .name = DRIVER_NAME, .pm = pm_ptr(&i2c_imx_pm_ops), diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 859c14e340e7e3..ce5ca5b90b395a 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -524,7 +524,7 @@ MODULE_DEVICE_TABLE(of, i2c_iop3xx_match); static struct platform_driver iop3xx_i2c_driver = { .probe = iop3xx_i2c_probe, - .remove_new = iop3xx_i2c_remove, + .remove = iop3xx_i2c_remove, .driver = { .name = "IOP3xx-I2C", .of_match_table = i2c_iop3xx_match, diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index f59158489ad9fa..2b3b65ef2900a4 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -1,41 +1,39 @@ // SPDX-License-Identifier: GPL-2.0-only /* - i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus - - Based on i2c-piix4.c - Copyright (c) 1998 - 2002 Frodo Looijaard and - Philip Edelbrock - - Intel SCH support - Copyright (c) 2007 - 2008 Jacob Jun Pan - -*/ + * Linux kernel driver for Intel SCH chipset SMBus + * - Based on i2c-piix4.c + * Copyright (c) 1998 - 2002 Frodo Looijaard and + * Philip Edelbrock + * - Intel SCH support + * Copyright (c) 2007 - 2008 Jacob Jun Pan + */ -/* - Supports: - Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L) - Note: we assume there can only be one device, with one SMBus interface. -*/ +/* Supports: Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L) */ +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include #include -#include -#include -#include +#include +#include /* SCH SMBus address offsets */ -#define SMBHSTCNT (0 + sch_smba) -#define SMBHSTSTS (1 + sch_smba) -#define SMBHSTCLK (2 + sch_smba) -#define SMBHSTADD (4 + sch_smba) /* TSA */ -#define SMBHSTCMD (5 + sch_smba) -#define SMBHSTDAT0 (6 + sch_smba) -#define SMBHSTDAT1 (7 + sch_smba) -#define SMBBLKDAT (0x20 + sch_smba) - -/* Other settings */ -#define MAX_RETRIES 5000 +#define SMBHSTCNT 0x00 +#define SMBHSTSTS 0x01 +#define SMBHSTCLK 0x02 +#define SMBHSTADD 0x04 /* TSA */ +#define SMBHSTCMD 0x05 +#define SMBHSTDAT0 0x06 +#define SMBHSTDAT1 0x07 +#define SMBBLKDAT 0x20 /* I2C constants */ #define SCH_QUICK 0x00 @@ -44,109 +42,134 @@ #define SCH_WORD_DATA 0x03 #define SCH_BLOCK_DATA 0x05 -static unsigned short sch_smba; -static struct i2c_adapter sch_adapter; +struct sch_i2c { + struct i2c_adapter adapter; + void __iomem *smba; +}; + static int backbone_speed = 33000; /* backbone speed in kHz */ -module_param(backbone_speed, int, S_IRUSR | S_IWUSR); +module_param(backbone_speed, int, 0600); MODULE_PARM_DESC(backbone_speed, "Backbone speed in kHz, (default = 33000)"); -/* - * Start the i2c transaction -- the i2c_access will prepare the transaction - * and this function will execute it. - * return 0 for success and others for failure. +static inline u8 sch_io_rd8(struct sch_i2c *priv, unsigned int offset) +{ + return ioread8(priv->smba + offset); +} + +static inline void sch_io_wr8(struct sch_i2c *priv, unsigned int offset, u8 value) +{ + iowrite8(value, priv->smba + offset); +} + +static inline u16 sch_io_rd16(struct sch_i2c *priv, unsigned int offset) +{ + return ioread16(priv->smba + offset); +} + +static inline void sch_io_wr16(struct sch_i2c *priv, unsigned int offset, u16 value) +{ + iowrite16(value, priv->smba + offset); +} + +/** + * sch_transaction - Start the i2c transaction + * @adap: the i2c adapter pointer + * + * The sch_access() will prepare the transaction and + * this function will execute it. + * + * Return: 0 for success and others for failure. */ -static int sch_transaction(void) +static int sch_transaction(struct i2c_adapter *adap) { + struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter); int temp; - int result = 0; - int retries = 0; + int rc; - dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT), - inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0), - inb(SMBHSTDAT1)); + dev_dbg(&adap->dev, + "Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD), + sch_io_rd8(priv, SMBHSTADD), + sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ - temp = inb(SMBHSTSTS) & 0x0f; + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp) { /* Can not be busy since we checked it in sch_access */ - if (temp & 0x01) { - dev_dbg(&sch_adapter.dev, "Completion (%02x). " - "Clear...\n", temp); - } - if (temp & 0x06) { - dev_dbg(&sch_adapter.dev, "SMBus error (%02x). " - "Resetting...\n", temp); - } - outb(temp, SMBHSTSTS); - temp = inb(SMBHSTSTS) & 0x0f; + if (temp & 0x01) + dev_dbg(&adap->dev, "Completion (%02x). Clear...\n", temp); + if (temp & 0x06) + dev_dbg(&adap->dev, "SMBus error (%02x). Resetting...\n", temp); + sch_io_wr8(priv, SMBHSTSTS, temp); + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp) { - dev_err(&sch_adapter.dev, - "SMBus is not ready: (%02x)\n", temp); + dev_err(&adap->dev, "SMBus is not ready: (%02x)\n", temp); return -EAGAIN; } } - /* start the transaction by setting bit 4 */ - outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT); - - do { - usleep_range(100, 200); - temp = inb(SMBHSTSTS) & 0x0f; - } while ((temp & 0x08) && (retries++ < MAX_RETRIES)); + /* Start the transaction by setting bit 4 */ + temp = sch_io_rd8(priv, SMBHSTCNT); + temp |= 0x10; + sch_io_wr8(priv, SMBHSTCNT, temp); + rc = read_poll_timeout(sch_io_rd8, temp, !(temp & 0x08), 200, 500000, true, priv, SMBHSTSTS); /* If the SMBus is still busy, we give up */ - if (retries > MAX_RETRIES) { - dev_err(&sch_adapter.dev, "SMBus Timeout!\n"); - result = -ETIMEDOUT; + if (rc) { + dev_err(&adap->dev, "SMBus Timeout!\n"); } else if (temp & 0x04) { - result = -EIO; - dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be " - "locked until next hard reset. (sorry!)\n"); + rc = -EIO; + dev_dbg(&adap->dev, "Bus collision! SMBus may be locked until next hard reset. (sorry!)\n"); /* Clock stops and target is stuck in mid-transmission */ } else if (temp & 0x02) { - result = -EIO; - dev_err(&sch_adapter.dev, "Error: no response!\n"); + rc = -EIO; + dev_err(&adap->dev, "Error: no response!\n"); } else if (temp & 0x01) { - dev_dbg(&sch_adapter.dev, "Post complete!\n"); - outb(temp, SMBHSTSTS); - temp = inb(SMBHSTSTS) & 0x07; + dev_dbg(&adap->dev, "Post complete!\n"); + sch_io_wr8(priv, SMBHSTSTS, temp & 0x0f); + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x07; if (temp & 0x06) { /* Completion clear failed */ - dev_dbg(&sch_adapter.dev, "Failed reset at end of " - "transaction (%02x), Bus error!\n", temp); + dev_dbg(&adap->dev, + "Failed reset at end of transaction (%02x), Bus error!\n", temp); } } else { - result = -ENXIO; - dev_dbg(&sch_adapter.dev, "No such address.\n"); + rc = -ENXIO; + dev_dbg(&adap->dev, "No such address.\n"); } - dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT), - inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0), - inb(SMBHSTDAT1)); - return result; + dev_dbg(&adap->dev, "Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD), + sch_io_rd8(priv, SMBHSTADD), + sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1)); + return rc; } -/* - * This is the main access entry for i2c-sch access - * adap is i2c_adapter pointer, addr is the i2c device bus address, read_write - * (0 for read and 1 for write), size is i2c transaction type and data is the - * union of transaction for data to be transferred or data read from bus. - * return 0 for success and others for failure. +/** + * sch_access - the main access entry for i2c-sch access + * @adap: the i2c adapter pointer + * @addr: the i2c device bus address + * @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC) + * @read_write: 0 for read and 1 for write + * @command: Byte interpreted by slave, for protocols which use such bytes + * @size: the i2c transaction type + * @data: the union of transaction for data to be transferred or data read from bus + * + * Return: 0 for success and others for failure. */ static s32 sch_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) { + struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter); int i, len, temp, rc; /* Make sure the SMBus host is not busy */ - temp = inb(SMBHSTSTS) & 0x0f; + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp & 0x08) { - dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp); + dev_dbg(&adap->dev, "SMBus busy (%02x)\n", temp); return -EAGAIN; } - temp = inw(SMBHSTCLK); + temp = sch_io_rd16(priv, SMBHSTCLK); if (!temp) { /* * We can't determine if we have 33 or 25 MHz clock for @@ -154,50 +177,48 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, * 100 kHz. If we actually run at 25 MHz the bus will be * run ~75 kHz instead which should do no harm. */ - dev_notice(&sch_adapter.dev, - "Clock divider uninitialized. Setting defaults\n"); - outw(backbone_speed / (4 * 100), SMBHSTCLK); + dev_notice(&adap->dev, "Clock divider uninitialized. Setting defaults\n"); + sch_io_wr16(priv, SMBHSTCLK, backbone_speed / (4 * 100)); } - dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size, - (read_write)?"READ":"WRITE"); + dev_dbg(&adap->dev, "access size: %d %s\n", size, str_read_write(read_write)); switch (size) { case I2C_SMBUS_QUICK: - outb((addr << 1) | read_write, SMBHSTADD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); size = SCH_QUICK; break; case I2C_SMBUS_BYTE: - outb((addr << 1) | read_write, SMBHSTADD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); if (read_write == I2C_SMBUS_WRITE) - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTCMD, command); size = SCH_BYTE; break; case I2C_SMBUS_BYTE_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) - outb(data->byte, SMBHSTDAT0); + sch_io_wr8(priv, SMBHSTDAT0, data->byte); size = SCH_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) { - outb(data->word & 0xff, SMBHSTDAT0); - outb((data->word & 0xff00) >> 8, SMBHSTDAT1); + sch_io_wr8(priv, SMBHSTDAT0, data->word >> 0); + sch_io_wr8(priv, SMBHSTDAT1, data->word >> 8); } size = SCH_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) return -EINVAL; - outb(len, SMBHSTDAT0); + sch_io_wr8(priv, SMBHSTDAT0, len); for (i = 1; i <= len; i++) - outb(data->block[i], SMBBLKDAT+i-1); + sch_io_wr8(priv, SMBBLKDAT + i - 1, data->block[i]); } size = SCH_BLOCK_DATA; break; @@ -205,10 +226,13 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -EOPNOTSUPP; } - dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT); - outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT); + dev_dbg(&adap->dev, "write size %d to 0x%04x\n", size, SMBHSTCNT); + + temp = sch_io_rd8(priv, SMBHSTCNT); + temp = (temp & 0xb0) | (size & 0x7); + sch_io_wr8(priv, SMBHSTCNT, temp); - rc = sch_transaction(); + rc = sch_transaction(adap); if (rc) /* Error in transaction */ return rc; @@ -218,17 +242,18 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, switch (size) { case SCH_BYTE: case SCH_BYTE_DATA: - data->byte = inb(SMBHSTDAT0); + data->byte = sch_io_rd8(priv, SMBHSTDAT0); break; case SCH_WORD_DATA: - data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8); + data->word = (sch_io_rd8(priv, SMBHSTDAT0) << 0) + + (sch_io_rd8(priv, SMBHSTDAT1) << 8); break; case SCH_BLOCK_DATA: - data->block[0] = inb(SMBHSTDAT0); + data->block[0] = sch_io_rd8(priv, SMBHSTDAT0); if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) return -EPROTO; for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb(SMBBLKDAT+i-1); + data->block[i] = sch_io_rd8(priv, SMBBLKDAT + i - 1); break; } return 0; @@ -246,51 +271,34 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = sch_func, }; -static struct i2c_adapter sch_adapter = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON, - .algo = &smbus_algorithm, -}; - -static int smbus_sch_probe(struct platform_device *dev) +static int smbus_sch_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct sch_i2c *priv; struct resource *res; - int retval; - res = platform_get_resource(dev, IORESOURCE_IO, 0); - if (!res) - return -EBUSY; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - if (!devm_request_region(&dev->dev, res->start, resource_size(res), - dev->name)) { - dev_err(&dev->dev, "SMBus region 0x%x already in use!\n", - sch_smba); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) return -EBUSY; - } - - sch_smba = res->start; - dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba); + priv->smba = devm_ioport_map(dev, res->start, resource_size(res)); + if (!priv->smba) + return dev_err_probe(dev, -EBUSY, "SMBus region %pR already in use!\n", res); - /* set up the sysfs linkage to our parent device */ - sch_adapter.dev.parent = &dev->dev; + /* Set up the sysfs linkage to our parent device */ + priv->adapter.dev.parent = dev; + priv->adapter.owner = THIS_MODULE, + priv->adapter.class = I2C_CLASS_HWMON, + priv->adapter.algo = &smbus_algorithm, - snprintf(sch_adapter.name, sizeof(sch_adapter.name), - "SMBus SCH adapter at %04x", sch_smba); + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "SMBus SCH adapter at %04x", (unsigned short)res->start); - retval = i2c_add_adapter(&sch_adapter); - if (retval) - sch_smba = 0; - - return retval; -} - -static void smbus_sch_remove(struct platform_device *pdev) -{ - if (sch_smba) { - i2c_del_adapter(&sch_adapter); - sch_smba = 0; - } + return devm_i2c_add_adapter(dev, &priv->adapter); } static struct platform_driver smbus_sch_driver = { @@ -298,7 +306,6 @@ static struct platform_driver smbus_sch_driver = { .name = "isch_smbus", }, .probe = smbus_sch_probe, - .remove_new = smbus_sch_remove, }; module_platform_driver(smbus_sch_driver); diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index 92cc5b09113760..664a5471d93357 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -847,7 +847,7 @@ static void jz4780_i2c_remove(struct platform_device *pdev) static struct platform_driver jz4780_i2c_driver = { .probe = jz4780_i2c_probe, - .remove_new = jz4780_i2c_remove, + .remove = jz4780_i2c_remove, .driver = { .name = "jz4780-i2c", .of_match_table = jz4780_i2c_of_matches, diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index eb66942e0b7d00..212196af68ba76 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -385,7 +385,7 @@ static struct platform_driver kempld_i2c_driver = { .pm = pm_sleep_ptr(&kempld_i2c_pm_ops), }, .probe = kempld_i2c_probe, - .remove_new = kempld_i2c_remove, + .remove = kempld_i2c_remove, }; module_platform_driver(kempld_i2c_driver); diff --git a/drivers/i2c/busses/i2c-ljca.c b/drivers/i2c/busses/i2c-ljca.c index 1dc516ef0fddc5..93274f0c2d7216 100644 --- a/drivers/i2c/busses/i2c-ljca.c +++ b/drivers/i2c/busses/i2c-ljca.c @@ -340,4 +340,4 @@ MODULE_AUTHOR("Zhifeng Wang "); MODULE_AUTHOR("Lixu Zhang "); MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-I2C driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(LJCA); +MODULE_IMPORT_NS("LJCA"); diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c index 9fb33cbf741940..6943a0de860ad0 100644 --- a/drivers/i2c/busses/i2c-lpc2k.c +++ b/drivers/i2c/busses/i2c-lpc2k.c @@ -462,7 +462,7 @@ MODULE_DEVICE_TABLE(of, lpc2k_i2c_match); static struct platform_driver i2c_lpc2k_driver = { .probe = i2c_lpc2k_probe, - .remove_new = i2c_lpc2k_remove, + .remove = i2c_lpc2k_remove, .driver = { .name = "lpc2k-i2c", .pm = pm_sleep_ptr(&i2c_lpc2k_dev_pm_ops), diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index c7b203cc443451..e1d69537353bf6 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -565,7 +565,7 @@ MODULE_DEVICE_TABLE(of, meson_i2c_match); static struct platform_driver meson_i2c_driver = { .probe = meson_i2c_probe, - .remove_new = meson_i2c_remove, + .remove = meson_i2c_remove, .driver = { .name = "meson-i2c", .of_match_table = meson_i2c_match, diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c index 0b0a1c4d17caef..d1543e7d838086 100644 --- a/drivers/i2c/busses/i2c-microchip-corei2c.c +++ b/drivers/i2c/busses/i2c-microchip-corei2c.c @@ -462,7 +462,7 @@ MODULE_DEVICE_TABLE(of, mchp_corei2c_of_match); static struct platform_driver mchp_corei2c_driver = { .probe = mchp_corei2c_probe, - .remove_new = mchp_corei2c_remove, + .remove = mchp_corei2c_remove, .driver = { .name = "microchip-corei2c", .of_match_table = mchp_corei2c_of_match, diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index b3a73921ab699c..21f67f3b65b6eb 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -2456,7 +2456,7 @@ static void mlxbf_i2c_remove(struct platform_device *pdev) static struct platform_driver mlxbf_i2c_driver = { .probe = mlxbf_i2c_probe, - .remove_new = mlxbf_i2c_remove, + .remove = mlxbf_i2c_remove, .driver = { .name = "i2c-mlxbf", .acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids), diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 8223f6d29eb3b2..07d3cadbf5102a 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -591,7 +591,7 @@ static void mlxcpld_i2c_remove(struct platform_device *pdev) static struct platform_driver mlxcpld_i2c_driver = { .probe = mlxcpld_i2c_probe, - .remove_new = mlxcpld_i2c_remove, + .remove = mlxcpld_i2c_remove, .driver = { .name = MLXCPLD_I2C_DEVICE_NAME, }, diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 236d6b8ba86757..28c5c5c1fb7a67 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -938,7 +938,7 @@ MODULE_DEVICE_TABLE(of, mpc_i2c_of_match); /* Structure for a device driver */ static struct platform_driver mpc_i2c_driver = { .probe = fsl_i2c_probe, - .remove_new = fsl_i2c_remove, + .remove = fsl_i2c_remove, .driver = { .name = "mpc-i2c", .of_match_table = mpc_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index e0ba653dec2d67..5bd342047d599e 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -1550,7 +1550,7 @@ static const struct dev_pm_ops mtk_i2c_pm = { static struct platform_driver mtk_i2c_driver = { .probe = mtk_i2c_probe, - .remove_new = mtk_i2c_remove, + .remove = mtk_i2c_remove, .driver = { .name = I2C_DRV_NAME, .pm = pm_sleep_ptr(&mtk_i2c_pm), diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c index 23d417ff5e71c8..2103f21f9dddad 100644 --- a/drivers/i2c/busses/i2c-mt7621.c +++ b/drivers/i2c/busses/i2c-mt7621.c @@ -331,7 +331,7 @@ static void mtk_i2c_remove(struct platform_device *pdev) static struct platform_driver mtk_i2c_driver = { .probe = mtk_i2c_probe, - .remove_new = mtk_i2c_remove, + .remove = mtk_i2c_remove, .driver = { .name = "i2c-mt7621", .of_match_table = i2c_mtk_dt_ids, diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 29f94efedf605a..874309580c33c3 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -1104,7 +1104,7 @@ static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { static struct platform_driver mv64xxx_i2c_driver = { .probe = mv64xxx_i2c_probe, - .remove_new = mv64xxx_i2c_remove, + .remove = mv64xxx_i2c_remove, .driver = { .name = MV64XXX_I2C_CTLR_NAME, .pm = &mv64xxx_i2c_pm_ops, diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 36def0a9c95c4f..ad62d56b2186e0 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -881,7 +881,7 @@ static struct platform_driver mxs_i2c_driver = { .of_match_table = mxs_i2c_dt_ids, }, .probe = mxs_i2c_probe, - .remove_new = mxs_i2c_remove, + .remove = mxs_i2c_remove, }; static int __init mxs_i2c_init(void) diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c deleted file mode 100644 index 69a71bc9830d9d..00000000000000 --- a/drivers/i2c/busses/i2c-nforce2-s4985.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard - * - * Copyright (C) 2008 Jean Delvare - */ - -/* - * We select the channels by sending commands to the Philips - * PCA9556 chip at I2C address 0x18. The main adapter is used for - * the non-multiplexed part of the bus, and 4 virtual adapters - * are defined for the multiplexed addresses: 0x50-0x53 (memory - * module EEPROM) located on channels 1-4. We define one virtual - * adapter per CPU, which corresponds to one multiplexed channel: - * CPU0: virtual adapter 1, channel 1 - * CPU1: virtual adapter 2, channel 2 - * CPU2: virtual adapter 3, channel 3 - * CPU3: virtual adapter 4, channel 4 - */ - -#include -#include -#include -#include -#include -#include - -extern struct i2c_adapter *nforce2_smbus; - -static struct i2c_adapter *s4985_adapter; -static struct i2c_algorithm *s4985_algo; - -/* Wrapper access functions for multiplexed SMBus */ -static DEFINE_MUTEX(nforce2_lock); - -static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - int error; - - /* We exclude the multiplexed addresses */ - if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30 - || addr == 0x18) - return -ENXIO; - - mutex_lock(&nforce2_lock); - error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - mutex_unlock(&nforce2_lock); - - return error; -} - -/* We remember the last used channels combination so as to only switch - channels when it is really needed. This greatly reduces the SMBus - overhead, but also assumes that nobody will be writing to the PCA9556 - in our back. */ -static u8 last_channels; - -static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data, - u8 channels) -{ - int error; - - /* We exclude the non-multiplexed addresses */ - if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30) - return -ENXIO; - - mutex_lock(&nforce2_lock); - if (last_channels != channels) { - union i2c_smbus_data mplxdata; - mplxdata.byte = channels; - - error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0, - I2C_SMBUS_WRITE, 0x01, - I2C_SMBUS_BYTE_DATA, - &mplxdata); - if (error) - goto UNLOCK; - last_channels = channels; - } - error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - -UNLOCK: - mutex_unlock(&nforce2_lock); - return error; -} - -static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU0: channel 1 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x02); -} - -static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU1: channel 2 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x04); -} - -static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU2: channel 3 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x08); -} - -static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU3: channel 4 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x10); -} - -static int __init nforce2_s4985_init(void) -{ - int i, error; - union i2c_smbus_data ioconfig; - - if (!nforce2_smbus) - return -ENODEV; - - /* Configure the PCA9556 multiplexer */ - ioconfig.byte = 0x00; /* All I/O to output mode */ - error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03, - I2C_SMBUS_BYTE_DATA, &ioconfig); - if (error) { - dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n"); - error = -EIO; - goto ERROR0; - } - - /* Unregister physical bus */ - i2c_del_adapter(nforce2_smbus); - - printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n"); - /* Define the 5 virtual adapters and algorithms structures */ - s4985_adapter = kcalloc(5, sizeof(struct i2c_adapter), GFP_KERNEL); - if (!s4985_adapter) { - error = -ENOMEM; - goto ERROR1; - } - s4985_algo = kcalloc(5, sizeof(struct i2c_algorithm), GFP_KERNEL); - if (!s4985_algo) { - error = -ENOMEM; - goto ERROR2; - } - - /* Fill in the new structures */ - s4985_algo[0] = *(nforce2_smbus->algo); - s4985_algo[0].smbus_xfer = nforce2_access_virt0; - s4985_adapter[0] = *nforce2_smbus; - s4985_adapter[0].algo = s4985_algo; - s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent; - for (i = 1; i < 5; i++) { - s4985_algo[i] = *(nforce2_smbus->algo); - s4985_adapter[i] = *nforce2_smbus; - snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name), - "SMBus nForce2 adapter (CPU%d)", i - 1); - s4985_adapter[i].algo = s4985_algo + i; - s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent; - } - s4985_algo[1].smbus_xfer = nforce2_access_virt1; - s4985_algo[2].smbus_xfer = nforce2_access_virt2; - s4985_algo[3].smbus_xfer = nforce2_access_virt3; - s4985_algo[4].smbus_xfer = nforce2_access_virt4; - - /* Register virtual adapters */ - for (i = 0; i < 5; i++) { - error = i2c_add_adapter(s4985_adapter + i); - if (error) { - printk(KERN_ERR "i2c-nforce2-s4985: " - "Virtual adapter %d registration " - "failed, module not inserted\n", i); - for (i--; i >= 0; i--) - i2c_del_adapter(s4985_adapter + i); - goto ERROR3; - } - } - - return 0; - -ERROR3: - kfree(s4985_algo); - s4985_algo = NULL; -ERROR2: - kfree(s4985_adapter); - s4985_adapter = NULL; -ERROR1: - /* Restore physical bus */ - i2c_add_adapter(nforce2_smbus); -ERROR0: - return error; -} - -static void __exit nforce2_s4985_exit(void) -{ - if (s4985_adapter) { - int i; - - for (i = 0; i < 5; i++) - i2c_del_adapter(s4985_adapter+i); - kfree(s4985_adapter); - s4985_adapter = NULL; - } - kfree(s4985_algo); - s4985_algo = NULL; - - /* Restore physical bus */ - if (i2c_add_adapter(nforce2_smbus)) - printk(KERN_ERR "i2c-nforce2-s4985: " - "Physical bus restoration failed\n"); -} - -MODULE_AUTHOR("Jean Delvare "); -MODULE_DESCRIPTION("S4985 SMBus multiplexing"); -MODULE_LICENSE("GPL"); - -module_init(nforce2_s4985_init); -module_exit(nforce2_s4985_exit); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index fab662e6bc084f..d58a308582e476 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -117,20 +117,6 @@ static const struct dmi_system_id nforce2_dmi_blacklist2[] = { static struct pci_driver nforce2_driver; -/* For multiplexing support, we need a global reference to the 1st - SMBus channel */ -#if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985) -struct i2c_adapter *nforce2_smbus; -EXPORT_SYMBOL_GPL(nforce2_smbus); - -static void nforce2_set_reference(struct i2c_adapter *adap) -{ - nforce2_smbus = adap; -} -#else -static inline void nforce2_set_reference(struct i2c_adapter *adap) { } -#endif - static void nforce2_abort(struct i2c_adapter *adap) { struct nforce2_smbus *smbus = adap->algo_data; @@ -411,7 +397,6 @@ static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } - nforce2_set_reference(&smbuses[0].adapter); return 0; } @@ -420,7 +405,6 @@ static void nforce2_remove(struct pci_dev *dev) { struct nforce2_smbus *smbuses = pci_get_drvdata(dev); - nforce2_set_reference(NULL); if (smbuses[0].base) { i2c_del_adapter(&smbuses[0].adapter); release_region(smbuses[0].base, smbuses[0].size); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index ad0f02acdb1215..d2877e4cc28d42 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -6,10 +6,10 @@ * I2C master mode controller driver, used in Nomadik 8815 * and Ux500 platforms. * - * The Mobileye EyeQ5 platform is also supported; it uses + * The Mobileye EyeQ5 and EyeQ6H platforms are also supported; they use * the same Ux500/DB8500 IP block with two quirks: * - The memory bus only supports 32-bit accesses. - * - A register must be configured for the I2C speed mode; + * - (only EyeQ5) A register must be configured for the I2C speed mode; * it is located in a shared register region called OLB. * * Author: Srinidhi Kasagar @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -396,7 +397,7 @@ static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *priv, u16 flags) */ static void setup_i2c_controller(struct nmk_i2c_dev *priv) { - u32 brcr1, brcr2; + u32 brcr; u32 i2c_clk, div; u32 ns; u16 slsu; @@ -443,7 +444,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv) /* * The spec says, in case of std. mode the divider is * 2 whereas it is 3 for fast and fastplus mode of - * operation. TODO - high speed support. + * operation. */ div = (priv->clk_freq > I2C_MAX_STANDARD_MODE_FREQ) ? 3 : 2; @@ -451,30 +452,23 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv) * generate the mask for baud rate counters. The controller * has two baud rate counters. One is used for High speed * operation, and the other is for std, fast mode, fast mode - * plus operation. Currently we do not supprt high speed mode - * so set brcr1 to 0. + * plus operation. + * + * BRCR is a clock divider amount. Pick highest value that + * leads to rate strictly below target. Eg when asking for + * 400kHz you want a bus rate <=400kHz (and not >=400kHz). */ - brcr1 = FIELD_PREP(I2C_BRCR_BRCNT1, 0); - brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2, i2c_clk / (priv->clk_freq * div)); + brcr = DIV_ROUND_UP(i2c_clk, priv->clk_freq * div); + + if (priv->sm == I2C_FREQ_MODE_HIGH_SPEED) + brcr = FIELD_PREP(I2C_BRCR_BRCNT1, brcr); + else + brcr = FIELD_PREP(I2C_BRCR_BRCNT2, brcr); /* set the baud rate counter register */ - writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR); + writel(brcr, priv->virtbase + I2C_BRCR); - /* - * set the speed mode. Currently we support - * only standard and fast mode of operation - * TODO - support for fast mode plus (up to 1Mb/s) - * and high speed (up to 3.4 Mb/s) - */ - if (priv->sm > I2C_FREQ_MODE_FAST) { - dev_err(&priv->adev->dev, - "do not support this mode defaulting to std. mode\n"); - brcr2 = FIELD_PREP(I2C_BRCR_BRCNT2, - i2c_clk / (I2C_MAX_STANDARD_MODE_FREQ * 2)); - writel((brcr1 | brcr2), priv->virtbase + I2C_BRCR); - writel(FIELD_PREP(I2C_CR_SM, I2C_FREQ_MODE_STANDARD), - priv->virtbase + I2C_CR); - } + /* set the speed mode */ writel(FIELD_PREP(I2C_CR_SM, priv->sm), priv->virtbase + I2C_CR); /* set the Tx and Rx FIFO threshold */ @@ -1015,11 +1009,14 @@ static void nmk_i2c_of_probe(struct device_node *np, if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq)) priv->clk_freq = I2C_MAX_STANDARD_MODE_FREQ; - /* This driver only supports 'standard' and 'fast' modes of operation. */ if (priv->clk_freq <= I2C_MAX_STANDARD_MODE_FREQ) priv->sm = I2C_FREQ_MODE_STANDARD; - else + else if (priv->clk_freq <= I2C_MAX_FAST_MODE_FREQ) priv->sm = I2C_FREQ_MODE_FAST; + else if (priv->clk_freq <= I2C_MAX_FAST_MODE_PLUS_FREQ) + priv->sm = I2C_FREQ_MODE_FAST_PLUS; + else + priv->sm = I2C_FREQ_MODE_HIGH_SPEED; priv->tft = 1; /* Tx FIFO threshold */ priv->rft = 8; /* Rx FIFO threshold */ @@ -1046,8 +1043,6 @@ static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv) struct regmap *olb; unsigned int id; - priv->has_32b_bus = true; - olb = syscon_regmap_lookup_by_phandle_args(np, "mobileye,olb", 1, &id); if (IS_ERR(olb)) return PTR_ERR(olb); @@ -1068,15 +1063,40 @@ static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv) return 0; } +#define NMK_I2C_EYEQ_FLAG_32B_BUS BIT(0) +#define NMK_I2C_EYEQ_FLAG_IS_EYEQ5 BIT(1) + +static const struct of_device_id nmk_i2c_eyeq_match_table[] = { + { + .compatible = "mobileye,eyeq5-i2c", + .data = (void *)(NMK_I2C_EYEQ_FLAG_32B_BUS | NMK_I2C_EYEQ_FLAG_IS_EYEQ5), + }, + { + .compatible = "mobileye,eyeq6h-i2c", + .data = (void *)NMK_I2C_EYEQ_FLAG_32B_BUS, + }, + { /* sentinel */ } +}; + static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { - int ret = 0; - struct nmk_i2c_dev *priv; + struct i2c_vendor_data *vendor = id->data; + u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1; struct device_node *np = adev->dev.of_node; + const struct of_device_id *match; struct device *dev = &adev->dev; + unsigned long match_flags = 0; + struct nmk_i2c_dev *priv; struct i2c_adapter *adap; - struct i2c_vendor_data *vendor = id->data; - u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1; + int ret = 0; + + /* + * We do not want to attach a .of_match_table to our amba driver. + * Do not convert to device_get_match_data(). + */ + match = of_match_device(nmk_i2c_eyeq_match_table, dev); + if (match) + match_flags = (unsigned long)match->data; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -1084,10 +1104,10 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) priv->vendor = vendor; priv->adev = adev; - priv->has_32b_bus = false; + priv->has_32b_bus = match_flags & NMK_I2C_EYEQ_FLAG_32B_BUS; nmk_i2c_of_probe(np, priv); - if (of_device_is_compatible(np, "mobileye,eyeq5-i2c")) { + if (match_flags & NMK_I2C_EYEQ_FLAG_IS_EYEQ5) { ret = nmk_i2c_eyeq5_probe(priv); if (ret) return dev_err_probe(dev, ret, "failed OLB lookup\n"); diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index bbcb4d6668ce63..482a0074d448cb 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -334,6 +334,7 @@ struct npcm_i2c { u64 nack_cnt; u64 timeout_cnt; u64 tx_complete_cnt; + bool ber_state; /* Indicate the bus error state */ }; static inline void npcm_i2c_select_bank(struct npcm_i2c *bus, @@ -1521,6 +1522,7 @@ static void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus) if (npcm_i2c_is_master(bus)) { npcm_i2c_master_abort(bus); } else { + bus->ber_state = true; npcm_i2c_clear_master_status(bus); /* Clear BB (BUS BUSY) bit */ @@ -1628,13 +1630,10 @@ static void npcm_i2c_irq_handle_sda(struct npcm_i2c *bus, u8 i2cst) npcm_i2c_wr_byte(bus, bus->dest_addr | BIT(0)); /* SDA interrupt, after start\restart */ } else { - if (NPCM_I2CST_XMIT & i2cst) { - bus->operation = I2C_WRITE_OPER; + if (bus->operation == I2C_WRITE_OPER) npcm_i2c_irq_master_handler_write(bus); - } else { - bus->operation = I2C_READ_OPER; + else if (bus->operation == I2C_READ_OPER) npcm_i2c_irq_master_handler_read(bus); - } } } @@ -1702,6 +1701,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck", bus->num, bus->dest_addr); npcm_i2c_reset(bus); + bus->ber_state = false; return 0; } @@ -1766,6 +1766,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) if (bus->rec_succ_cnt < ULLONG_MAX) bus->rec_succ_cnt++; } + bus->ber_state = false; return status; } @@ -2161,7 +2162,16 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } while (time_is_after_jiffies(time_left) && bus_busy); - if (bus_busy) { + /* + * Check the BER (bus error) state, when ber_state is true, it means that the module + * detects the bus error which is caused by some factor like that the electricity + * noise occurs on the bus. Under this condition, the module is reset and the bus + * gets recovered. + * + * While ber_state is false, the module reset and bus recovery also get done as the + * bus is busy. + */ + if (bus_busy || bus->ber_state) { iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); npcm_i2c_reset(bus); i2c_recover_bus(adap); @@ -2363,7 +2373,7 @@ MODULE_DEVICE_TABLE(of, npcm_i2c_bus_of_table); static struct platform_driver npcm_i2c_bus_driver = { .probe = npcm_i2c_probe_bus, - .remove_new = npcm_i2c_remove_bus, + .remove = npcm_i2c_remove_bus, .driver = { .name = "nuvoton-i2c", .of_match_table = npcm_i2c_bus_of_table, diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 482b37c8a12970..0f67e57cdeff6c 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -769,7 +769,7 @@ static DEFINE_NOIRQ_DEV_PM_OPS(ocores_i2c_pm, static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, - .remove_new = ocores_i2c_remove, + .remove = ocores_i2c_remove, .driver = { .name = "ocores-i2c", .of_match_table = ocores_i2c_match, diff --git a/drivers/i2c/busses/i2c-octeon-platdrv.c b/drivers/i2c/busses/i2c-octeon-platdrv.c index dc6dff95c68ce7..edfca7b20f2916 100644 --- a/drivers/i2c/busses/i2c-octeon-platdrv.c +++ b/drivers/i2c/busses/i2c-octeon-platdrv.c @@ -269,7 +269,7 @@ MODULE_DEVICE_TABLE(of, octeon_i2c_match); static struct platform_driver octeon_i2c_driver = { .probe = octeon_i2c_probe, - .remove_new = octeon_i2c_remove, + .remove = octeon_i2c_remove, .driver = { .name = DRV_NAME, .of_match_table = octeon_i2c_match, diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 1d9ad25c89ae55..92faf03d64cfb6 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1605,7 +1605,7 @@ static const struct dev_pm_ops omap_i2c_pm_ops = { static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, - .remove_new = omap_i2c_remove, + .remove = omap_i2c_remove, .driver = { .name = "omap_i2c", .pm = pm_ptr(&omap_i2c_pm_ops), diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c index d9dd71cf37fd29..c9b62892397a0f 100644 --- a/drivers/i2c/busses/i2c-opal.c +++ b/drivers/i2c/busses/i2c-opal.c @@ -249,7 +249,7 @@ MODULE_DEVICE_TABLE(of, i2c_opal_of_match); static struct platform_driver i2c_opal_driver = { .probe = i2c_opal_probe, - .remove_new = i2c_opal_remove, + .remove = i2c_opal_remove, .driver = { .name = "i2c-opal", .of_match_table = i2c_opal_of_match, diff --git a/drivers/i2c/busses/i2c-pasemi-platform.c b/drivers/i2c/busses/i2c-pasemi-platform.c index 5fbfb9b4174402..a486a37d386345 100644 --- a/drivers/i2c/busses/i2c-pasemi-platform.c +++ b/drivers/i2c/busses/i2c-pasemi-platform.c @@ -104,7 +104,7 @@ static struct platform_driver pasemi_platform_i2c_driver = { .of_match_table = pasemi_platform_i2c_of_match, }, .probe = pasemi_platform_i2c_probe, - .remove_new = pasemi_platform_i2c_remove, + .remove = pasemi_platform_i2c_remove, }; module_platform_driver(pasemi_platform_i2c_driver); diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index b8d5480c54f65a..87da8241b92707 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -238,7 +238,7 @@ MODULE_DEVICE_TABLE(of, i2c_pca_of_match_table); static struct platform_driver i2c_pca_pf_driver = { .probe = i2c_pca_pf_probe, - .remove_new = i2c_pca_pf_remove, + .remove = i2c_pca_pf_remove, .driver = { .name = "i2c-pca-platform", .of_match_table = of_match_ptr(i2c_pca_of_match_table), diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index febbd9950d8f89..dd75916157f051 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -35,20 +35,7 @@ #include #include - -/* PIIX4 SMBus address offsets */ -#define SMBHSTSTS (0 + piix4_smba) -#define SMBHSLVSTS (1 + piix4_smba) -#define SMBHSTCNT (2 + piix4_smba) -#define SMBHSTCMD (3 + piix4_smba) -#define SMBHSTADD (4 + piix4_smba) -#define SMBHSTDAT0 (5 + piix4_smba) -#define SMBHSTDAT1 (6 + piix4_smba) -#define SMBBLKDAT (7 + piix4_smba) -#define SMBSLVCNT (8 + piix4_smba) -#define SMBSHDWCMD (9 + piix4_smba) -#define SMBSLVEVT (0xA + piix4_smba) -#define SMBSLVDAT (0xC + piix4_smba) +#include "i2c-piix4.h" /* count for request_region */ #define SMBIOSIZE 9 @@ -70,7 +57,6 @@ #define PIIX4_BYTE 0x04 #define PIIX4_BYTE_DATA 0x08 #define PIIX4_WORD_DATA 0x0C -#define PIIX4_BLOCK_DATA 0x14 /* Multi-port constants */ #define PIIX4_MAX_ADAPTERS 4 @@ -101,6 +87,7 @@ #define SB800_PIIX4_FCH_PM_ADDR 0xFED80300 #define SB800_PIIX4_FCH_PM_SIZE 8 +#define SB800_ASF_ACPI_PATH "\\_SB.ASFC" /* insmod parameters */ @@ -160,11 +147,6 @@ static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = { }; static const char *piix4_aux_port_name_sb800 = " port 1"; -struct sb800_mmio_cfg { - void __iomem *addr; - bool use_mmio; -}; - struct i2c_piix4_adapdata { unsigned short smba; @@ -175,8 +157,7 @@ struct i2c_piix4_adapdata { struct sb800_mmio_cfg mmio_cfg; }; -static int piix4_sb800_region_request(struct device *dev, - struct sb800_mmio_cfg *mmio_cfg) +int piix4_sb800_region_request(struct device *dev, struct sb800_mmio_cfg *mmio_cfg) { if (mmio_cfg->use_mmio) { void __iomem *addr; @@ -214,9 +195,9 @@ static int piix4_sb800_region_request(struct device *dev, return 0; } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_request, "PIIX4_SMBUS"); -static void piix4_sb800_region_release(struct device *dev, - struct sb800_mmio_cfg *mmio_cfg) +void piix4_sb800_region_release(struct device *dev, struct sb800_mmio_cfg *mmio_cfg) { if (mmio_cfg->use_mmio) { iounmap(mmio_cfg->addr); @@ -227,6 +208,7 @@ static void piix4_sb800_region_release(struct device *dev, release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE); } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_release, "PIIX4_SMBUS"); static bool piix4_sb800_use_mmio(struct pci_dev *PIIX4_dev) { @@ -536,10 +518,8 @@ static int piix4_setup_aux(struct pci_dev *PIIX4_dev, return piix4_smba; } -static int piix4_transaction(struct i2c_adapter *piix4_adapter) +int piix4_transaction(struct i2c_adapter *piix4_adapter, unsigned short piix4_smba) { - struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter); - unsigned short piix4_smba = adapdata->smba; int temp; int result = 0; int timeout = 0; @@ -611,6 +591,7 @@ static int piix4_transaction(struct i2c_adapter *piix4_adapter) inb_p(SMBHSTDAT1)); return result; } +EXPORT_SYMBOL_NS_GPL(piix4_transaction, "PIIX4_SMBUS"); /* Return negative errno on error. */ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, @@ -675,7 +656,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); - status = piix4_transaction(adap); + status = piix4_transaction(adap, piix4_smba); if (status) return status; @@ -764,7 +745,7 @@ static void piix4_imc_wakeup(void) release_region(KERNCZ_IMC_IDX, 2); } -static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) +int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) { u8 smba_en_lo, val; @@ -786,6 +767,7 @@ static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) return (smba_en_lo & piix4_port_mask_sb800); } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_port_sel, "PIIX4_SMBUS"); /* * Handles access to multiple SMBus ports on the SB800. @@ -1043,6 +1025,9 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; bool is_sb800 = false; + bool is_asf = false; + acpi_status status; + acpi_handle handle; if ((dev->vendor == PCI_VENDOR_ID_ATI && dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && @@ -1105,10 +1090,16 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) } } + status = acpi_get_handle(NULL, (acpi_string)SB800_ASF_ACPI_PATH, &handle); + if (ACPI_SUCCESS(status)) + is_asf = true; + if (dev->vendor == PCI_VENDOR_ID_AMD && (dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS || dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) { - retval = piix4_setup_sb800(dev, id, 1); + /* Do not setup AUX port if ASF is enabled */ + if (!is_asf) + retval = piix4_setup_sb800(dev, id, 1); } if (retval > 0) { diff --git a/drivers/i2c/busses/i2c-piix4.h b/drivers/i2c/busses/i2c-piix4.h new file mode 100644 index 00000000000000..36bc6ce82a2795 --- /dev/null +++ b/drivers/i2c/busses/i2c-piix4.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * PIIX4/SB800 SMBus Interfaces + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Authors: Shyam Sundar S K + * Sanket Goswami + */ + +#ifndef I2C_PIIX4_H +#define I2C_PIIX4_H + +#include + +/* PIIX4 SMBus address offsets */ +#define SMBHSTSTS (0x00 + piix4_smba) +#define SMBHSLVSTS (0x01 + piix4_smba) +#define SMBHSTCNT (0x02 + piix4_smba) +#define SMBHSTCMD (0x03 + piix4_smba) +#define SMBHSTADD (0x04 + piix4_smba) +#define SMBHSTDAT0 (0x05 + piix4_smba) +#define SMBHSTDAT1 (0x06 + piix4_smba) +#define SMBBLKDAT (0x07 + piix4_smba) +#define SMBSLVCNT (0x08 + piix4_smba) +#define SMBSHDWCMD (0x09 + piix4_smba) +#define SMBSLVEVT (0x0A + piix4_smba) +#define SMBSLVDAT (0x0C + piix4_smba) + +/* PIIX4 constants */ +#define PIIX4_BLOCK_DATA 0x14 + +struct sb800_mmio_cfg { + void __iomem *addr; + bool use_mmio; +}; + +int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg); +int piix4_transaction(struct i2c_adapter *piix4_adapter, unsigned short piix4_smba); +int piix4_sb800_region_request(struct device *dev, struct sb800_mmio_cfg *mmio_cfg); +void piix4_sb800_region_release(struct device *dev, struct sb800_mmio_cfg *mmio_cfg); + +#endif /* I2C_PIIX4_H */ diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 1dafadda73af3a..9a1af5bbd604cd 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -95,7 +95,7 @@ enum { static inline int wait_timeout(struct i2c_pnx_algo_data *data) { - long timeout = data->timeout; + long timeout = jiffies_to_msecs(data->timeout); while (timeout > 0 && (ioread32(I2C_REG_STS(data)) & mstatus_active)) { mdelay(1); @@ -106,7 +106,7 @@ static inline int wait_timeout(struct i2c_pnx_algo_data *data) static inline int wait_reset(struct i2c_pnx_algo_data *data) { - long timeout = data->timeout; + long timeout = jiffies_to_msecs(data->timeout); while (timeout > 0 && (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { mdelay(1); @@ -733,7 +733,7 @@ static struct platform_driver i2c_pnx_driver = { .pm = pm_sleep_ptr(&i2c_pnx_pm), }, .probe = i2c_pnx_probe, - .remove_new = i2c_pnx_remove, + .remove = i2c_pnx_remove, }; static int __init i2c_adap_pnx_init(void) diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index b6b03539f62688..9a867c817db01e 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -437,7 +437,7 @@ static int i2c_powermac_probe(struct platform_device *dev) static struct platform_driver i2c_powermac_driver = { .probe = i2c_powermac_probe, - .remove_new = i2c_powermac_remove, + .remove = i2c_powermac_remove, .driver = { .name = "i2c-powermac", .bus = &platform_bus_type, diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 4d76e71cdd4be1..cb69884826739d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1574,7 +1574,7 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = { static struct platform_driver i2c_pxa_driver = { .probe = i2c_pxa_probe, - .remove_new = i2c_pxa_remove, + .remove = i2c_pxa_remove, .driver = { .name = "pxa2xx-i2c", .pm = pm_sleep_ptr(&i2c_pxa_dev_pm_ops), diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 414882c57d7f40..05b73326afd4a6 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -120,7 +120,6 @@ struct cci_data { unsigned int num_masters; struct i2c_adapter_quirks quirks; u16 queue_size[NUM_QUEUES]; - unsigned long cci_clk_rate; struct hw_params params[3]; }; @@ -523,7 +522,6 @@ static const struct dev_pm_ops qcom_cci_pm = { static int cci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - unsigned long cci_clk_rate = 0; struct device_node *child; struct resource *r; struct cci *cci; @@ -594,22 +592,6 @@ static int cci_probe(struct platform_device *pdev) return dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n"); cci->nclocks = ret; - /* Retrieve CCI clock rate */ - for (i = 0; i < cci->nclocks; i++) { - if (!strcmp(cci->clocks[i].id, "cci")) { - cci_clk_rate = clk_get_rate(cci->clocks[i].clk); - break; - } - } - - if (cci_clk_rate != cci->data->cci_clk_rate) { - /* cci clock set by the bootloader or via assigned clock rate - * in DT. - */ - dev_warn(dev, "Found %lu cci clk rate while %lu was expected\n", - cci_clk_rate, cci->data->cci_clk_rate); - } - ret = cci_enable_clocks(cci); if (ret < 0) return ret; @@ -699,7 +681,6 @@ static const struct cci_data cci_v1_data = { .max_write_len = 10, .max_read_len = 12, }, - .cci_clk_rate = 19200000, .params[I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, @@ -733,7 +714,6 @@ static const struct cci_data cci_v1_5_data = { .max_write_len = 10, .max_read_len = 12, }, - .cci_clk_rate = 19200000, .params[I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, @@ -767,7 +747,6 @@ static const struct cci_data cci_v2_data = { .max_write_len = 11, .max_read_len = 12, }, - .cci_clk_rate = 37500000, .params[I2C_MODE_STANDARD] = { .thigh = 201, .tlow = 174, @@ -826,7 +805,7 @@ MODULE_DEVICE_TABLE(of, cci_dt_match); static struct platform_driver qcom_cci_driver = { .probe = cci_probe, - .remove_new = cci_remove, + .remove = cci_remove, .driver = { .name = "i2c-qcom-cci", .of_match_table = cci_dt_match, diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 212336f724a693..7a22e1f46e60a5 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -16,6 +16,7 @@ #include #include #include +#include #define SE_I2C_TX_TRANS_LEN 0x26c #define SE_I2C_RX_TRANS_LEN 0x270 @@ -146,22 +147,36 @@ struct geni_i2c_clk_fld { * clk_freq_out = t / t_cycle * source_clock = 19.2 MHz */ -static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = { +static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = { {KHZ(100), 7, 10, 11, 26}, {KHZ(400), 2, 5, 12, 24}, {KHZ(1000), 1, 3, 9, 18}, + {}, +}; + +/* source_clock = 32 MHz */ +static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = { + {KHZ(100), 8, 14, 18, 40}, + {KHZ(400), 4, 3, 11, 20}, + {KHZ(1000), 2, 3, 6, 15}, + {}, }; static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) { - int i; - const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map; + const struct geni_i2c_clk_fld *itr; - for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) { + if (clk_get_rate(gi2c->se.clk) == 32 * HZ_PER_MHZ) + itr = geni_i2c_clk_map_32mhz; + else + itr = geni_i2c_clk_map_19p2mhz; + + while (itr->clk_freq_out != 0) { if (itr->clk_freq_out == gi2c->clk_freq_out) { gi2c->clk_fld = itr; return 0; } + itr++; } return -EINVAL; } @@ -818,6 +833,8 @@ static int geni_i2c_probe(struct platform_device *pdev) init_completion(&gi2c->done); spin_lock_init(&gi2c->lock); platform_set_drvdata(pdev, gi2c); + + /* Keep interrupts disabled initially to allow for low-power modes */ ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN, dev_name(dev), gi2c); if (ret) { @@ -1049,7 +1066,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); static struct platform_driver geni_i2c_driver = { .probe = geni_i2c_probe, - .remove_new = geni_i2c_remove, + .remove = geni_i2c_remove, .shutdown = geni_i2c_shutdown, .driver = { .name = "geni_i2c", diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index d480162a4d3941..da20b4487c9a54 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -17,9 +17,9 @@ #include #include #include -#include #include #include +#include #include /* QUP Registers */ @@ -1683,7 +1683,7 @@ static int qup_i2c_probe(struct platform_device *pdev) } } - if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) { + if (device_is_compatible(&pdev->dev, "qcom,i2c-qup-v1.1.1")) { qup->adap.algo = &qup_i2c_algo; qup->adap.quirks = &qup_i2c_quirks; is_qup_v1 = true; @@ -1974,7 +1974,7 @@ MODULE_DEVICE_TABLE(of, qup_i2c_dt_match); static struct platform_driver qup_i2c_driver = { .probe = qup_i2c_probe, - .remove_new = qup_i2c_remove, + .remove = qup_i2c_remove, .driver = { .name = "i2c_qup", .pm = pm_ptr(&qup_i2c_qup_pm_ops), diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 9267df38c2d0a1..a7b77d14ee8671 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1271,7 +1271,7 @@ static struct platform_driver rcar_i2c_driver = { .pm = pm_sleep_ptr(&rcar_i2c_pm_ops), }, .probe = rcar_i2c_probe, - .remove_new = rcar_i2c_remove, + .remove = rcar_i2c_remove, }; module_platform_driver(rcar_i2c_driver); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index c7f3a4c0247023..9264adc97ca9df 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -352,7 +352,7 @@ static int riic_init_hw(struct riic_dev *riic) if (brl <= (0x1F + 3)) break; - total_ticks /= 2; + total_ticks = DIV_ROUND_UP(total_ticks, 2); rate /= 2; } @@ -632,7 +632,7 @@ static const struct of_device_id riic_i2c_dt_ids[] = { static struct platform_driver riic_i2c_driver = { .probe = riic_i2c_probe, - .remove_new = riic_i2c_remove, + .remove = riic_i2c_remove, .driver = { .name = "i2c-riic", .of_match_table = riic_i2c_dt_ids, diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 4ef9bad77b856f..d4e9196445c030 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1398,7 +1398,7 @@ static SIMPLE_DEV_PM_OPS(rk3x_i2c_pm_ops, NULL, rk3x_i2c_resume); static struct platform_driver rk3x_i2c_driver = { .probe = rk3x_i2c_probe, - .remove_new = rk3x_i2c_remove, + .remove = rk3x_i2c_remove, .driver = { .name = "rk3x-i2c", .of_match_table = rk3x_i2c_match, diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c new file mode 100644 index 00000000000000..e064e8a4a1f082 --- /dev/null +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +enum rtl9300_bus_freq { + RTL9300_I2C_STD_FREQ, + RTL9300_I2C_FAST_FREQ, +}; + +struct rtl9300_i2c; + +struct rtl9300_i2c_chan { + struct i2c_adapter adap; + struct rtl9300_i2c *i2c; + enum rtl9300_bus_freq bus_freq; + u8 sda_pin; +}; + +#define RTL9300_I2C_MUX_NCHAN 8 + +struct rtl9300_i2c { + struct regmap *regmap; + struct device *dev; + struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN]; + u32 reg_base; + u8 sda_pin; + struct mutex lock; +}; + +#define RTL9300_I2C_MST_CTRL1 0x0 +#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS 8 +#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK GENMASK(31, 8) +#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS 4 +#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK GENMASK(6, 4) +#define RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL BIT(3) +#define RTL9300_I2C_MST_CTRL1_RWOP BIT(2) +#define RTL9300_I2C_MST_CTRL1_I2C_FAIL BIT(1) +#define RTL9300_I2C_MST_CTRL1_I2C_TRIG BIT(0) +#define RTL9300_I2C_MST_CTRL2 0x4 +#define RTL9300_I2C_MST_CTRL2_RD_MODE BIT(15) +#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS 8 +#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK GENMASK(14, 8) +#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS 4 +#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK GENMASK(7, 4) +#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS 2 +#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK GENMASK(3, 2) +#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS 0 +#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK GENMASK(1, 0) +#define RTL9300_I2C_MST_DATA_WORD0 0x8 +#define RTL9300_I2C_MST_DATA_WORD1 0xc +#define RTL9300_I2C_MST_DATA_WORD2 0x10 +#define RTL9300_I2C_MST_DATA_WORD3 0x14 + +#define RTL9300_I2C_MST_GLB_CTRL 0x384 + +static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len) +{ + u32 val, mask; + int ret; + + val = len << RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS; + mask = RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK; + + ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val); + if (ret) + return ret; + + val = reg << RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS; + mask = RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK; + + return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); +} + +static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin) +{ + int ret; + u32 val, mask; + + ret = regmap_update_bits(i2c->regmap, RTL9300_I2C_MST_GLB_CTRL, BIT(sda_pin), BIT(sda_pin)); + if (ret) + return ret; + + val = (sda_pin << RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS) | + RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL; + mask = RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK | RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL; + + return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); +} + +static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan, + u16 addr, u16 len) +{ + u32 val, mask; + + val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS; + mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK; + + val |= addr << RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS; + mask |= RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK; + + val |= ((len - 1) & 0xf) << RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS; + mask |= RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK; + + mask |= RTL9300_I2C_MST_CTRL2_RD_MODE; + + return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val); +} + +static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len) +{ + u32 vals[4] = {}; + int i, ret; + + if (len > 16) + return -EIO; + + ret = regmap_bulk_read(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, + vals, ARRAY_SIZE(vals)); + if (ret) + return ret; + + for (i = 0; i < len; i++) { + buf[i] = vals[i/4] & 0xff; + vals[i/4] >>= 8; + } + + return 0; +} + +static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len) +{ + u32 vals[4] = {}; + int i; + + if (len > 16) + return -EIO; + + for (i = 0; i < len; i++) { + if (i % 4 == 0) + vals[i/4] = 0; + vals[i/4] <<= 8; + vals[i/4] |= buf[i]; + } + + return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, + vals, ARRAY_SIZE(vals)); +} + +static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data) +{ + return regmap_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, data); +} + +static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write, + int size, union i2c_smbus_data *data, int len) +{ + u32 val, mask; + int ret; + + val = read_write == I2C_SMBUS_WRITE ? RTL9300_I2C_MST_CTRL1_RWOP : 0; + mask = RTL9300_I2C_MST_CTRL1_RWOP; + + val |= RTL9300_I2C_MST_CTRL1_I2C_TRIG; + mask |= RTL9300_I2C_MST_CTRL1_I2C_TRIG; + + ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, + val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 2000); + if (ret) + return ret; + + if (val & RTL9300_I2C_MST_CTRL1_I2C_FAIL) + return -EIO; + + if (read_write == I2C_SMBUS_READ) { + if (size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA) { + ret = regmap_read(i2c->regmap, + i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val); + if (ret) + return ret; + data->byte = val & 0xff; + } else if (size == I2C_SMBUS_WORD_DATA) { + ret = regmap_read(i2c->regmap, + i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val); + if (ret) + return ret; + data->word = val & 0xffff; + } else { + ret = rtl9300_i2c_read(i2c, &data->block[0], len); + if (ret) + return ret; + } + } + + return 0; +} + +static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data *data) +{ + struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap); + struct rtl9300_i2c *i2c = chan->i2c; + int len = 0, ret; + + mutex_lock(&i2c->lock); + if (chan->sda_pin != i2c->sda_pin) { + ret = rtl9300_i2c_config_io(i2c, chan->sda_pin); + if (ret) + goto out_unlock; + i2c->sda_pin = chan->sda_pin; + } + + switch (size) { + case I2C_SMBUS_QUICK: + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); + if (ret) + goto out_unlock; + ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0); + if (ret) + goto out_unlock; + break; + + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) { + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); + if (ret) + goto out_unlock; + ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); + if (ret) + goto out_unlock; + } else { + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1); + if (ret) + goto out_unlock; + ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0); + if (ret) + goto out_unlock; + } + break; + + case I2C_SMBUS_BYTE_DATA: + ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); + if (ret) + goto out_unlock; + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1); + if (ret) + goto out_unlock; + if (read_write == I2C_SMBUS_WRITE) { + ret = rtl9300_i2c_writel(i2c, data->byte); + if (ret) + goto out_unlock; + } + break; + + case I2C_SMBUS_WORD_DATA: + ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); + if (ret) + goto out_unlock; + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 2); + if (ret) + goto out_unlock; + if (read_write == I2C_SMBUS_WRITE) { + ret = rtl9300_i2c_writel(i2c, data->word); + if (ret) + goto out_unlock; + } + break; + + case I2C_SMBUS_BLOCK_DATA: + ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); + if (ret) + goto out_unlock; + ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); + if (ret) + goto out_unlock; + if (read_write == I2C_SMBUS_WRITE) { + ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]); + if (ret) + goto out_unlock; + } + len = data->block[0]; + break; + + default: + dev_err(&adap->dev, "Unsupported transaction %d\n", size); + ret = -EOPNOTSUPP; + goto out_unlock; + } + + ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len); + +out_unlock: + mutex_unlock(&i2c->lock); + + return ret; +} + +static u32 rtl9300_i2c_func(struct i2c_adapter *a) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm rtl9300_i2c_algo = { + .smbus_xfer = rtl9300_i2c_smbus_xfer, + .functionality = rtl9300_i2c_func, +}; + +static struct i2c_adapter_quirks rtl9300_i2c_quirks = { + .flags = I2C_AQ_NO_CLK_STRETCH, + .max_read_len = 16, + .max_write_len = 16, +}; + +static int rtl9300_i2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtl9300_i2c *i2c; + u32 clock_freq, sda_pin; + int ret, i = 0; + struct fwnode_handle *child; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->regmap = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(i2c->regmap)) + return PTR_ERR(i2c->regmap); + i2c->dev = dev; + + mutex_init(&i2c->lock); + + ret = device_property_read_u32(dev, "reg", &i2c->reg_base); + if (ret) + return ret; + + platform_set_drvdata(pdev, i2c); + + if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN) + return dev_err_probe(dev, -EINVAL, "Too many channels\n"); + + device_for_each_child_node(dev, child) { + struct rtl9300_i2c_chan *chan = &i2c->chans[i]; + struct i2c_adapter *adap = &chan->adap; + + ret = fwnode_property_read_u32(child, "reg", &sda_pin); + if (ret) + return ret; + + ret = fwnode_property_read_u32(child, "clock-frequency", &clock_freq); + if (ret) + clock_freq = I2C_MAX_STANDARD_MODE_FREQ; + + switch (clock_freq) { + case I2C_MAX_STANDARD_MODE_FREQ: + chan->bus_freq = RTL9300_I2C_STD_FREQ; + break; + + case I2C_MAX_FAST_MODE_FREQ: + chan->bus_freq = RTL9300_I2C_FAST_FREQ; + break; + default: + dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n", + sda_pin, clock_freq); + break; + } + + chan->sda_pin = sda_pin; + chan->i2c = i2c; + adap = &i2c->chans[i].adap; + adap->owner = THIS_MODULE; + adap->algo = &rtl9300_i2c_algo; + adap->quirks = &rtl9300_i2c_quirks; + adap->retries = 3; + adap->dev.parent = dev; + i2c_set_adapdata(adap, chan); + adap->dev.of_node = to_of_node(child); + snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_pin); + i++; + + ret = devm_i2c_add_adapter(dev, adap); + if (ret) + return ret; + } + i2c->sda_pin = 0xff; + + return 0; +} + +static const struct of_device_id i2c_rtl9300_dt_ids[] = { + { .compatible = "realtek,rtl9301-i2c" }, + { .compatible = "realtek,rtl9302b-i2c" }, + { .compatible = "realtek,rtl9302c-i2c" }, + { .compatible = "realtek,rtl9303-i2c" }, + {} +}; +MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids); + +static struct platform_driver rtl9300_i2c_driver = { + .probe = rtl9300_i2c_probe, + .driver = { + .name = "i2c-rtl9300", + .of_match_table = i2c_rtl9300_dt_ids, + }, +}; + +module_platform_driver(rtl9300_i2c_driver); + +MODULE_DESCRIPTION("RTL9300 I2C controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c index 8380a68538abc0..02b76e24a47698 100644 --- a/drivers/i2c/busses/i2c-rzv2m.c +++ b/drivers/i2c/busses/i2c-rzv2m.c @@ -536,7 +536,7 @@ static struct platform_driver rzv2m_i2c_driver = { .pm = pm_sleep_ptr(&rzv2m_i2c_pm_ops), }, .probe = rzv2m_i2c_probe, - .remove_new = rzv2m_i2c_remove, + .remove = rzv2m_i2c_remove, }; module_platform_driver(rzv2m_i2c_driver); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 7698d9d5974483..0f3cf500df6823 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1176,7 +1176,7 @@ static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, - .remove_new = s3c24xx_i2c_remove, + .remove = s3c24xx_i2c_remove, .id_table = s3c24xx_driver_ids, .driver = { .name = "s3c-i2c", diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index d7af8e0d7599ec..10a5146b3aa5fc 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -411,7 +411,7 @@ static void smbus_cmi_remove(struct platform_device *device) static struct platform_driver smbus_cmi_driver = { .probe = smbus_cmi_probe, - .remove_new = smbus_cmi_remove, + .remove = smbus_cmi_remove, .driver = { .name = "smbus_cmi", .acpi_match_table = acpi_smbus_cmi_ids, diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index 8a043f5fca1e06..620f1259676375 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -552,7 +552,7 @@ static struct platform_driver sh7760_i2c_drv = { .name = SH7760_I2C_DEVNAME, }, .probe = sh7760_i2c_probe, - .remove_new = sh7760_i2c_remove, + .remove = sh7760_i2c_remove, }; module_platform_driver(sh7760_i2c_drv); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index f86c29737df124..efe29621b8d7c1 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -983,7 +983,7 @@ static struct platform_driver sh_mobile_i2c_driver = { .pm = pm_sleep_ptr(&sh_mobile_i2c_pm_ops), }, .probe = sh_mobile_i2c_probe, - .remove_new = sh_mobile_i2c_remove, + .remove = sh_mobile_i2c_remove, }; static int __init sh_mobile_i2c_adap_init(void) diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 18516bc64e046b..d90606048611a0 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -144,7 +144,7 @@ static struct platform_driver simtec_i2c_driver = { .name = "simtec-i2c", }, .probe = simtec_i2c_probe, - .remove_new = simtec_i2c_remove, + .remove = simtec_i2c_remove, }; module_platform_driver(simtec_i2c_driver); diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index 9c45e75b918733..56b2e5c5fb49aa 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -643,7 +643,7 @@ MODULE_DEVICE_TABLE(of, sprd_i2c_of_match); static struct platform_driver sprd_i2c_driver = { .probe = sprd_i2c_probe, - .remove_new = sprd_i2c_remove, + .remove = sprd_i2c_remove, .driver = { .name = "sprd-i2c", .of_match_table = sprd_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 05b19ede65a0fe..750fff3d2389e6 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -893,7 +893,7 @@ static struct platform_driver st_i2c_driver = { .pm = pm_sleep_ptr(&st_i2c_pm), }, .probe = st_i2c_probe, - .remove_new = st_i2c_remove, + .remove = st_i2c_remove, }; module_platform_driver(st_i2c_driver); diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index 230fff0c0bf93e..b3d56d0aa9d0b8 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -869,7 +869,7 @@ static struct platform_driver stm32f4_i2c_driver = { .of_match_table = stm32f4_i2c_match, }, .probe = stm32f4_i2c_probe, - .remove_new = stm32f4_i2c_remove, + .remove = stm32f4_i2c_remove, }; module_platform_driver(stm32f4_i2c_driver); diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index 0174ead99de6c1..973a3a8c6d4a18 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -2532,7 +2532,7 @@ static struct platform_driver stm32f7_i2c_driver = { .pm = &stm32f7_i2c_pm_ops, }, .probe = stm32f7_i2c_probe, - .remove_new = stm32f7_i2c_remove, + .remove = stm32f7_i2c_remove, }; module_platform_driver(stm32f7_i2c_driver); diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c index 074eade6c4a4fc..fb5280b8cf7fc0 100644 --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -319,7 +319,7 @@ static void p2wi_remove(struct platform_device *dev) static struct platform_driver p2wi_driver = { .probe = p2wi_probe, - .remove_new = p2wi_remove, + .remove = p2wi_remove, .driver = { .name = "i2c-sunxi-p2wi", .of_match_table = p2wi_of_match_table, diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index bbb9062669e4b2..31f8d08e32a485 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -629,7 +629,7 @@ MODULE_DEVICE_TABLE(acpi, synquacer_i2c_acpi_ids); static struct platform_driver synquacer_i2c_driver = { .probe = synquacer_i2c_probe, - .remove_new = synquacer_i2c_remove, + .remove = synquacer_i2c_remove, .driver = { .name = "synquacer_i2c", .of_match_table = of_match_ptr(synquacer_i2c_dt_ids), diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c index dabadbcc6d6a2d..bb0de6db6391bc 100644 --- a/drivers/i2c/busses/i2c-tegra-bpmp.c +++ b/drivers/i2c/busses/i2c-tegra-bpmp.c @@ -335,7 +335,7 @@ static struct platform_driver tegra_bpmp_i2c_driver = { .of_match_table = tegra_bpmp_i2c_of_match, }, .probe = tegra_bpmp_i2c_probe, - .remove_new = tegra_bpmp_i2c_remove, + .remove = tegra_bpmp_i2c_remove, }; module_platform_driver(tegra_bpmp_i2c_driver); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 1df5b42041427c..87976e99e6d001 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -1964,7 +1964,7 @@ MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match); static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, - .remove_new = tegra_i2c_remove, + .remove = tegra_i2c_remove, .driver = { .name = "tegra-i2c", .of_match_table = tegra_i2c_of_match, diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index 10a99cd08972f4..d877f5a1f5798c 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -615,7 +615,7 @@ MODULE_DEVICE_TABLE(of, uniphier_fi2c_match); static struct platform_driver uniphier_fi2c_drv = { .probe = uniphier_fi2c_probe, - .remove_new = uniphier_fi2c_remove, + .remove = uniphier_fi2c_remove, .driver = { .name = "uniphier-fi2c", .of_match_table = uniphier_fi2c_match, diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index ef575330746919..b95d50d4d7db58 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -409,7 +409,7 @@ MODULE_DEVICE_TABLE(of, uniphier_i2c_match); static struct platform_driver uniphier_i2c_drv = { .probe = uniphier_i2c_probe, - .remove_new = uniphier_i2c_remove, + .remove = uniphier_i2c_remove, .driver = { .name = "uniphier-i2c", .of_match_table = uniphier_i2c_match, diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index 76abfa77e20017..a1ab6ef6f0716d 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -109,7 +109,7 @@ MODULE_DEVICE_TABLE(of, i2c_versatile_match); static struct platform_driver i2c_versatile_driver = { .probe = i2c_versatile_probe, - .remove_new = i2c_versatile_remove, + .remove = i2c_versatile_remove, .driver = { .name = "versatile-i2c", .of_match_table = i2c_versatile_match, diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c index 3415683dab91c5..4eb740faf268d9 100644 --- a/drivers/i2c/busses/i2c-viai2c-wmt.c +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -169,7 +169,7 @@ static const struct of_device_id wmt_i2c_dt_ids[] = { static struct platform_driver wmt_i2c_driver = { .probe = wmt_i2c_probe, - .remove_new = wmt_i2c_remove, + .remove = wmt_i2c_remove, .driver = { .name = "wmt-i2c", .of_match_table = wmt_i2c_dt_ids, diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index 2ed4130c033958..503e2f4d6f8449 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -415,7 +415,7 @@ static void vprbrd_i2c_remove(struct platform_device *pdev) static struct platform_driver vprbrd_i2c_driver = { .driver.name = "viperboard-i2c", .probe = vprbrd_i2c_probe, - .remove_new = vprbrd_i2c_remove, + .remove = vprbrd_i2c_remove, }; static int __init vprbrd_i2c_init(void) diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 658396c9eeabf9..663fe5604dd64b 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -581,7 +581,7 @@ MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids); static struct platform_driver xgene_slimpro_i2c_driver = { .probe = xgene_slimpro_i2c_probe, - .remove_new = xgene_slimpro_i2c_remove, + .remove = xgene_slimpro_i2c_remove, .driver = { .name = "xgene-slimpro-i2c", .of_match_table = of_match_ptr(xgene_slimpro_i2c_dt_ids), diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 1d68177241a6b3..c4d3eb02da09f4 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -1395,7 +1395,7 @@ static const struct dev_pm_ops xiic_dev_pm_ops = { static struct platform_driver xiic_i2c_driver = { .probe = xiic_i2c_probe, - .remove_new = xiic_i2c_remove, + .remove = xiic_i2c_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(xiic_of_match), diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 08a59a920929f3..4d5e49b6321b81 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -579,7 +579,7 @@ MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids); static struct platform_driver xlp9xx_i2c_driver = { .probe = xlp9xx_i2c_probe, - .remove_new = xlp9xx_i2c_remove, + .remove = xlp9xx_i2c_remove, .driver = { .name = "xlp9xx-i2c", .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids), diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 3648382b885a4e..4d6abd7e92ce82 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -536,7 +536,7 @@ static struct platform_driver scx200_pci_driver = { .name = "cs5535-smb", }, .probe = scx200_probe, - .remove_new = scx200_remove, + .remove = scx200_remove, }; static const struct pci_device_id scx200_isa[] = { diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c index f21475ae592183..b7c10ced5a4393 100644 --- a/drivers/i2c/i2c-atr.c +++ b/drivers/i2c/i2c-atr.c @@ -547,7 +547,7 @@ struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev, return ERR_PTR(ret); } -EXPORT_SYMBOL_NS_GPL(i2c_atr_new, I2C_ATR); +EXPORT_SYMBOL_NS_GPL(i2c_atr_new, "I2C_ATR"); void i2c_atr_delete(struct i2c_atr *atr) { @@ -562,7 +562,7 @@ void i2c_atr_delete(struct i2c_atr *atr) mutex_destroy(&atr->lock); kfree(atr); } -EXPORT_SYMBOL_NS_GPL(i2c_atr_delete, I2C_ATR); +EXPORT_SYMBOL_NS_GPL(i2c_atr_delete, "I2C_ATR"); int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id, struct device *adapter_parent, @@ -657,7 +657,7 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id, kfree(chan); return ret; } -EXPORT_SYMBOL_NS_GPL(i2c_atr_add_adapter, I2C_ATR); +EXPORT_SYMBOL_NS_GPL(i2c_atr_add_adapter, "I2C_ATR"); void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id) { @@ -690,19 +690,19 @@ void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id) kfree(chan->orig_addrs); kfree(chan); } -EXPORT_SYMBOL_NS_GPL(i2c_atr_del_adapter, I2C_ATR); +EXPORT_SYMBOL_NS_GPL(i2c_atr_del_adapter, "I2C_ATR"); void i2c_atr_set_driver_data(struct i2c_atr *atr, void *data) { atr->priv = data; } -EXPORT_SYMBOL_NS_GPL(i2c_atr_set_driver_data, I2C_ATR); +EXPORT_SYMBOL_NS_GPL(i2c_atr_set_driver_data, "I2C_ATR"); void *i2c_atr_get_driver_data(struct i2c_atr *atr) { return atr->priv; } -EXPORT_SYMBOL_NS_GPL(i2c_atr_get_driver_data, I2C_ATR); +EXPORT_SYMBOL_NS_GPL(i2c_atr_get_driver_data, "I2C_ATR"); MODULE_AUTHOR("Luca Ceresoli "); MODULE_AUTHOR("Tomi Valkeinen "); diff --git a/drivers/i2c/i2c-core-of-prober.c b/drivers/i2c/i2c-core-of-prober.c new file mode 100644 index 00000000000000..0a66267e483633 --- /dev/null +++ b/drivers/i2c/i2c-core-of-prober.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Linux I2C core OF component prober code + * + * Copyright (C) 2024 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Some devices, such as Google Hana Chromebooks, are produced by multiple + * vendors each using their preferred components. Such components are all + * in the device tree. Instead of having all of them enabled and having each + * driver separately try and probe its device while fighting over shared + * resources, they can be marked as "fail-needs-probe" and have a prober + * figure out which one is actually used beforehand. + * + * This prober assumes such drop-in parts are on the same I2C bus, have + * non-conflicting addresses, and can be directly probed by seeing which + * address responds. + * + * TODO: + * - Support I2C muxes + */ + +static struct device_node *i2c_of_probe_get_i2c_node(struct device *dev, const char *type) +{ + struct device_node *node __free(device_node) = of_find_node_by_name(NULL, type); + if (!node) { + dev_err(dev, "Could not find %s device node\n", type); + return NULL; + } + + struct device_node *i2c_node __free(device_node) = of_get_parent(node); + if (!of_node_name_eq(i2c_node, "i2c")) { + dev_err(dev, "%s device isn't on I2C bus\n", type); + return NULL; + } + + if (!of_device_is_available(i2c_node)) { + dev_err(dev, "I2C controller not available\n"); + return NULL; + } + + return no_free_ptr(i2c_node); +} + +static int i2c_of_probe_enable_node(struct device *dev, struct device_node *node) +{ + int ret; + + dev_dbg(dev, "Enabling %pOF\n", node); + + struct of_changeset *ocs __free(kfree) = kzalloc(sizeof(*ocs), GFP_KERNEL); + if (!ocs) + return -ENOMEM; + + of_changeset_init(ocs); + ret = of_changeset_update_prop_string(ocs, node, "status", "okay"); + if (ret) + return ret; + + ret = of_changeset_apply(ocs); + if (ret) { + /* ocs needs to be explicitly cleaned up before being freed. */ + of_changeset_destroy(ocs); + } else { + /* + * ocs is intentionally kept around as it needs to + * exist as long as the change is applied. + */ + void *ptr __always_unused = no_free_ptr(ocs); + } + + return ret; +} + +static const struct i2c_of_probe_ops i2c_of_probe_dummy_ops; + +/** + * i2c_of_probe_component() - probe for devices of "type" on the same i2c bus + * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages. + * @cfg: Pointer to the &struct i2c_of_probe_cfg containing callbacks and other options + * for the prober. + * @ctx: Context data for callbacks. + * + * Probe for possible I2C components of the same "type" (&i2c_of_probe_cfg->type) + * on the same I2C bus that have their status marked as "fail-needs-probe". + * + * Assumes that across the entire device tree the only instances of nodes + * with "type" prefixed node names (not including the address portion) are + * the ones that need handling for second source components. In other words, + * if "type" is "touchscreen", then all device nodes named "touchscreen*" + * are the ones that need probing. There cannot be another "touchscreen*" + * node that is already enabled. + * + * Assumes that for each "type" of component, only one actually exists. In + * other words, only one matching and existing device will be enabled. + * + * Context: Process context only. Does non-atomic I2C transfers. + * Should only be used from a driver probe function, as the function + * can return -EPROBE_DEFER if the I2C adapter or other resources + * are unavailable. + * Return: 0 on success or no-op, error code otherwise. + * A no-op can happen when it seems like the device tree already + * has components of the type to be probed already enabled. This + * can happen when the device tree had not been updated to mark + * the status of the to-be-probed components as "fail-needs-probe". + * Or this function was already run with the same parameters and + * succeeded in enabling a component. The latter could happen if + * the user had multiple types of components to probe, and one of + * them down the list caused a deferred probe. This is expected + * behavior. + */ +int i2c_of_probe_component(struct device *dev, const struct i2c_of_probe_cfg *cfg, void *ctx) +{ + const struct i2c_of_probe_ops *ops; + const char *type; + struct i2c_adapter *i2c; + int ret; + + ops = cfg->ops ?: &i2c_of_probe_dummy_ops; + type = cfg->type; + + struct device_node *i2c_node __free(device_node) = i2c_of_probe_get_i2c_node(dev, type); + if (!i2c_node) + return -ENODEV; + + /* + * If any devices of the given "type" are already enabled then this function is a no-op. + * Either the device tree hasn't been modified to work with this probe function, or the + * function had already run before and enabled some component. + */ + for_each_child_of_node_with_prefix(i2c_node, node, type) + if (of_device_is_available(node)) + return 0; + + i2c = of_get_i2c_adapter_by_node(i2c_node); + if (!i2c) + return dev_err_probe(dev, -EPROBE_DEFER, "Couldn't get I2C adapter\n"); + + /* Grab and enable resources */ + ret = 0; + if (ops->enable) + ret = ops->enable(dev, i2c_node, ctx); + if (ret) + goto out_put_i2c_adapter; + + for_each_child_of_node_with_prefix(i2c_node, node, type) { + union i2c_smbus_data data; + u32 addr; + + if (of_property_read_u32(node, "reg", &addr)) + continue; + if (i2c_smbus_xfer(i2c, addr, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data) < 0) + continue; + + /* Found a device that is responding */ + if (ops->cleanup_early) + ops->cleanup_early(dev, ctx); + ret = i2c_of_probe_enable_node(dev, node); + break; + } + + if (ops->cleanup) + ops->cleanup(dev, ctx); +out_put_i2c_adapter: + i2c_put_adapter(i2c); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_component, "I2C_OF_PROBER"); + +static int i2c_of_probe_simple_get_supply(struct device *dev, struct device_node *node, + struct i2c_of_probe_simple_ctx *ctx) +{ + const char *supply_name; + struct regulator *supply; + + /* + * It's entirely possible for the component's device node to not have the + * regulator supplies. While it does not make sense from a hardware perspective, + * the supplies could be always on or otherwise not modeled in the device tree, + * but the device would still work. + */ + supply_name = ctx->opts->supply_name; + if (!supply_name) + return 0; + + supply = of_regulator_get_optional(dev, node, supply_name); + if (IS_ERR(supply)) { + return dev_err_probe(dev, PTR_ERR(supply), + "Failed to get regulator supply \"%s\" from %pOF\n", + supply_name, node); + } + + ctx->supply = supply; + + return 0; +} + +static void i2c_of_probe_simple_put_supply(struct i2c_of_probe_simple_ctx *ctx) +{ + regulator_put(ctx->supply); + ctx->supply = NULL; +} + +static int i2c_of_probe_simple_enable_regulator(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) +{ + int ret; + + if (!ctx->supply) + return 0; + + dev_dbg(dev, "Enabling regulator supply \"%s\"\n", ctx->opts->supply_name); + + ret = regulator_enable(ctx->supply); + if (ret) + return ret; + + if (ctx->opts->post_power_on_delay_ms) + msleep(ctx->opts->post_power_on_delay_ms); + + return 0; +} + +static void i2c_of_probe_simple_disable_regulator(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) +{ + if (!ctx->supply) + return; + + dev_dbg(dev, "Disabling regulator supply \"%s\"\n", ctx->opts->supply_name); + + regulator_disable(ctx->supply); +} + +static int i2c_of_probe_simple_get_gpiod(struct device *dev, struct device_node *node, + struct i2c_of_probe_simple_ctx *ctx) +{ + struct fwnode_handle *fwnode = of_fwnode_handle(node); + struct gpio_desc *gpiod; + const char *con_id; + + /* NULL signals no GPIO needed */ + if (!ctx->opts->gpio_name) + return 0; + + /* An empty string signals an unnamed GPIO */ + if (!ctx->opts->gpio_name[0]) + con_id = NULL; + else + con_id = ctx->opts->gpio_name; + + gpiod = fwnode_gpiod_get_index(fwnode, con_id, 0, GPIOD_ASIS, "i2c-of-prober"); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + ctx->gpiod = gpiod; + + return 0; +} + +static void i2c_of_probe_simple_put_gpiod(struct i2c_of_probe_simple_ctx *ctx) +{ + gpiod_put(ctx->gpiod); + ctx->gpiod = NULL; +} + +static int i2c_of_probe_simple_set_gpio(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) +{ + int ret; + + if (!ctx->gpiod) + return 0; + + dev_dbg(dev, "Configuring GPIO\n"); + + ret = gpiod_direction_output(ctx->gpiod, ctx->opts->gpio_assert_to_enable); + if (ret) + return ret; + + if (ctx->opts->post_gpio_config_delay_ms) + msleep(ctx->opts->post_gpio_config_delay_ms); + + return 0; +} + +static void i2c_of_probe_simple_disable_gpio(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) +{ + gpiod_set_value(ctx->gpiod, !ctx->opts->gpio_assert_to_enable); +} + +/** + * i2c_of_probe_simple_enable - Simple helper for I2C OF prober to get and enable resources + * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages + * @bus_node: Pointer to the &struct device_node of the I2C adapter. + * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. + * + * If &i2c_of_probe_simple_opts->supply_name is given, request the named regulator supply. + * If &i2c_of_probe_simple_opts->gpio_name is given, request the named GPIO. Or if it is + * the empty string, request the unnamed GPIO. + * If a regulator supply was found, enable that regulator. + * If a GPIO line was found, configure the GPIO line to output and set value + * according to given options. + * + * Return: %0 on success or no-op, or a negative error number on failure. + */ +int i2c_of_probe_simple_enable(struct device *dev, struct device_node *bus_node, void *data) +{ + struct i2c_of_probe_simple_ctx *ctx = data; + struct device_node *node; + const char *compat; + int ret; + + dev_dbg(dev, "Requesting resources for components under I2C bus %pOF\n", bus_node); + + if (!ctx || !ctx->opts) + return -EINVAL; + + compat = ctx->opts->res_node_compatible; + if (!compat) + return -EINVAL; + + node = of_get_compatible_child(bus_node, compat); + if (!node) + return dev_err_probe(dev, -ENODEV, "No device compatible with \"%s\" found\n", + compat); + + ret = i2c_of_probe_simple_get_supply(dev, node, ctx); + if (ret) + goto out_put_node; + + ret = i2c_of_probe_simple_get_gpiod(dev, node, ctx); + if (ret) + goto out_put_supply; + + ret = i2c_of_probe_simple_enable_regulator(dev, ctx); + if (ret) + goto out_put_gpiod; + + ret = i2c_of_probe_simple_set_gpio(dev, ctx); + if (ret) + goto out_disable_regulator; + + return 0; + +out_disable_regulator: + i2c_of_probe_simple_disable_regulator(dev, ctx); +out_put_gpiod: + i2c_of_probe_simple_put_gpiod(ctx); +out_put_supply: + i2c_of_probe_simple_put_supply(ctx); +out_put_node: + of_node_put(node); + return ret; +} +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_enable, "I2C_OF_PROBER"); + +/** + * i2c_of_probe_simple_cleanup_early - \ + * Simple helper for I2C OF prober to release GPIOs before component is enabled + * @dev: Pointer to the &struct device of the caller; unused. + * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. + * + * GPIO descriptors are exclusive and have to be released before the + * actual driver probes so that the latter can acquire them. + */ +void i2c_of_probe_simple_cleanup_early(struct device *dev, void *data) +{ + struct i2c_of_probe_simple_ctx *ctx = data; + + i2c_of_probe_simple_put_gpiod(ctx); +} +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_cleanup_early, "I2C_OF_PROBER"); + +/** + * i2c_of_probe_simple_cleanup - Clean up and release resources for I2C OF prober simple helpers + * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages + * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. + * + * * If a GPIO line was found and not yet released, set its value to the opposite of that + * set in i2c_of_probe_simple_enable() and release it. + * * If a regulator supply was found, disable that regulator and release it. + */ +void i2c_of_probe_simple_cleanup(struct device *dev, void *data) +{ + struct i2c_of_probe_simple_ctx *ctx = data; + + /* GPIO operations here are no-ops if i2c_of_probe_simple_cleanup_early was called. */ + i2c_of_probe_simple_disable_gpio(dev, ctx); + i2c_of_probe_simple_put_gpiod(ctx); + + i2c_of_probe_simple_disable_regulator(dev, ctx); + i2c_of_probe_simple_put_supply(ctx); +} +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_cleanup, "I2C_OF_PROBER"); + +struct i2c_of_probe_ops i2c_of_probe_simple_ops = { + .enable = i2c_of_probe_simple_enable, + .cleanup_early = i2c_of_probe_simple_cleanup_early, + .cleanup = i2c_of_probe_simple_cleanup, +}; +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_ops, "I2C_OF_PROBER"); diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index e3b96fc53b5c25..e73afbefe2225f 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -122,7 +122,7 @@ EXPORT_SYMBOL(i2c_smbus_read_byte); s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value) { return i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); + I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); } EXPORT_SYMBOL(i2c_smbus_write_byte); @@ -712,12 +712,15 @@ int i2c_setup_smbus_alert(struct i2c_adapter *adapter) if (!parent) return 0; + /* Report serious errors */ irq = device_property_match_string(parent, "interrupt-names", "smbus_alert"); - if (irq == -EINVAL || irq == -ENODATA) - return 0; - else if (irq < 0) + if (irq < 0 && irq != -EINVAL && irq != -ENODATA) return irq; + /* Skip setup when no irq was found */ + if (irq < 0 && !device_property_present(parent, "smbalert-gpios")) + return 0; + return PTR_ERR_OR_ZERO(i2c_new_smbus_alert_device(adapter, NULL)); } #endif diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 61f7c4003d2ff7..e9577f920286d0 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -251,10 +251,8 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, return -EOPNOTSUPP; data_ptrs = kmalloc_array(nmsgs, sizeof(u8 __user *), GFP_KERNEL); - if (data_ptrs == NULL) { - kfree(msgs); + if (!data_ptrs) return -ENOMEM; - } res = 0; for (i = 0; i < nmsgs; i++) { @@ -302,7 +300,6 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, for (j = 0; j < i; ++j) kfree(msgs[j].buf); kfree(data_ptrs); - kfree(msgs); return res; } @@ -316,7 +313,6 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, kfree(msgs[i].buf); } kfree(data_ptrs); - kfree(msgs); return res; } @@ -446,6 +442,7 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case I2C_RDWR: { struct i2c_rdwr_ioctl_data rdwr_arg; struct i2c_msg *rdwr_pa; + int res; if (copy_from_user(&rdwr_arg, (struct i2c_rdwr_ioctl_data __user *)arg, @@ -467,7 +464,9 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (IS_ERR(rdwr_pa)) return PTR_ERR(rdwr_pa); - return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + res = i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + kfree(rdwr_pa); + return res; } case I2C_SMBUS: { @@ -540,7 +539,7 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo struct i2c_rdwr_ioctl_data32 rdwr_arg; struct i2c_msg32 __user *p; struct i2c_msg *rdwr_pa; - int i; + int i, res; if (copy_from_user(&rdwr_arg, (struct i2c_rdwr_ioctl_data32 __user *)arg, @@ -573,7 +572,9 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo }; } - return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + res = i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + kfree(rdwr_pa); + return res; } case I2C_SMBUS: { struct i2c_smbus_ioctl_data32 data32; diff --git a/drivers/i2c/i2c-slave-testunit.c b/drivers/i2c/i2c-slave-testunit.c index 9fe3150378e863..0d6fbaa4824879 100644 --- a/drivers/i2c/i2c-slave-testunit.c +++ b/drivers/i2c/i2c-slave-testunit.c @@ -183,6 +183,10 @@ static void i2c_slave_testunit_work(struct work_struct *work) break; case TU_CMD_SMBUS_ALERT_REQUEST: + if (!tu->gpio) { + ret = -ENOENT; + break; + } i2c_slave_unregister(tu->client); orig_addr = tu->client->addr; tu->client->addr = 0x0c; @@ -232,6 +236,9 @@ static int i2c_slave_testunit_probe(struct i2c_client *client) INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work); tu->gpio = devm_gpiod_get_index_optional(&client->dev, NULL, 0, GPIOD_OUT_LOW); + if (IS_ERR(tu->gpio)) + return PTR_ERR(tu->gpio); + if (gpiod_cansleep(tu->gpio)) { dev_err(&client->dev, "GPIO access which may sleep is not allowed\n"); return -EDEADLK; diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index 8256f7aed0cf86..7d40e7aa379928 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -167,6 +168,8 @@ static int smbalert_probe(struct i2c_client *ara) struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev); struct i2c_smbus_alert *alert; struct i2c_adapter *adapter = ara->adapter; + unsigned long irqflags = IRQF_SHARED | IRQF_ONESHOT; + struct gpio_desc *gpiod; int res, irq; alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), @@ -179,18 +182,25 @@ static int smbalert_probe(struct i2c_client *ara) } else { irq = fwnode_irq_get_byname(dev_fwnode(adapter->dev.parent), "smbus_alert"); - if (irq <= 0) - return irq; + if (irq <= 0) { + gpiod = devm_gpiod_get(adapter->dev.parent, "smbalert", GPIOD_IN); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + irq = gpiod_to_irq(gpiod); + if (irq <= 0) + return irq; + + irqflags |= IRQF_TRIGGER_FALLING; + } } INIT_WORK(&alert->alert, smbalert_work); alert->ara = ara; if (irq > 0) { - res = devm_request_threaded_irq(&ara->dev, irq, - NULL, smbus_alert, - IRQF_SHARED | IRQF_ONESHOT, - "smbus_alert", alert); + res = devm_request_threaded_irq(&ara->dev, irq, NULL, smbus_alert, + irqflags, "smbus_alert", alert); if (res) return res; } diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 7aa6e795d833d6..d6ef91b888c6a0 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -190,7 +190,7 @@ MODULE_DEVICE_TABLE(of, i2c_arbitrator_of_match); static struct platform_driver i2c_arbitrator_driver = { .probe = i2c_arbitrator_probe, - .remove_new = i2c_arbitrator_remove, + .remove = i2c_arbitrator_remove, .driver = { .name = "i2c-arb-gpio-challenge", .of_match_table = i2c_arbitrator_of_match, diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index 7e2686b606c04d..dce18f763a09ba 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -314,7 +314,7 @@ static struct platform_driver i2c_demux_pinctrl_driver = { .of_match_table = i2c_demux_pinctrl_of_match, }, .probe = i2c_demux_pinctrl_probe, - .remove_new = i2c_demux_pinctrl_remove, + .remove = i2c_demux_pinctrl_remove, }; module_platform_driver(i2c_demux_pinctrl_driver); diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 944577bb09c178..9b46b84e84fbdb 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -247,7 +247,7 @@ MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, - .remove_new = i2c_mux_gpio_remove, + .remove = i2c_mux_gpio_remove, .driver = { .name = "i2c-mux-gpio", .of_match_table = i2c_mux_gpio_of_match, diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c index 10d63307b14d01..ab8e116610522d 100644 --- a/drivers/i2c/muxes/i2c-mux-gpmux.c +++ b/drivers/i2c/muxes/i2c-mux-gpmux.c @@ -152,7 +152,7 @@ static void i2c_mux_remove(struct platform_device *pdev) static struct platform_driver i2c_mux_driver = { .probe = i2c_mux_probe, - .remove_new = i2c_mux_remove, + .remove = i2c_mux_remove, .driver = { .name = "i2c-mux-gpmux", .of_match_table = i2c_mux_of_match, diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 3f06aa3331a780..1c2debcf379c31 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -182,7 +182,7 @@ static struct platform_driver mlxcpld_mux_driver = { .name = "i2c-mux-mlxcpld", }, .probe = mlxcpld_mux_probe, - .remove_new = mlxcpld_mux_remove, + .remove = mlxcpld_mux_remove, }; module_platform_driver(mlxcpld_mux_driver); diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index 02aaf0781e9c82..fc686a350ae89f 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -186,7 +186,7 @@ static struct platform_driver i2c_mux_pinctrl_driver = { .of_match_table = i2c_mux_pinctrl_of_match, }, .probe = i2c_mux_pinctrl_probe, - .remove_new = i2c_mux_pinctrl_remove, + .remove = i2c_mux_pinctrl_remove, }; module_platform_driver(i2c_mux_pinctrl_driver); diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index ef765fcd33f547..dfa472d514ccd6 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -247,7 +247,7 @@ MODULE_DEVICE_TABLE(of, i2c_mux_reg_of_match); static struct platform_driver i2c_mux_reg_driver = { .probe = i2c_mux_reg_probe, - .remove_new = i2c_mux_reg_remove, + .remove = i2c_mux_reg_remove, .driver = { .name = "i2c-mux-reg", .of_match_table = of_match_ptr(i2c_mux_reg_of_match), diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c index 6f3eb710a75d60..42310c9a00c2d1 100644 --- a/drivers/i3c/master.c +++ b/drivers/i3c/master.c @@ -282,7 +282,8 @@ static int i3c_device_uevent(const struct device *dev, struct kobj_uevent_env *e struct i3c_device_info devinfo; u16 manuf, part, ext; - i3c_device_get_info(i3cdev, &devinfo); + if (i3cdev->desc) + devinfo = i3cdev->desc->info; manuf = I3C_PID_MANUF_ID(devinfo.pid); part = I3C_PID_PART_ID(devinfo.pid); ext = I3C_PID_EXTRA_INFO(devinfo.pid); @@ -345,10 +346,10 @@ const struct bus_type i3c_bus_type = { EXPORT_SYMBOL_GPL(i3c_bus_type); static enum i3c_addr_slot_status -i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) +i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask) { unsigned long status; - int bitpos = addr * 2; + int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS; if (addr > I2C_MAX_ADDR) return I3C_ADDR_SLOT_RSVD; @@ -356,22 +357,33 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) status = bus->addrslots[bitpos / BITS_PER_LONG]; status >>= bitpos % BITS_PER_LONG; - return status & I3C_ADDR_SLOT_STATUS_MASK; + return status & mask; } -static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr, - enum i3c_addr_slot_status status) +static enum i3c_addr_slot_status +i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) +{ + return i3c_bus_get_addr_slot_status_mask(bus, addr, I3C_ADDR_SLOT_STATUS_MASK); +} + +static void i3c_bus_set_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, + enum i3c_addr_slot_status status, u32 mask) { - int bitpos = addr * 2; + int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS; unsigned long *ptr; if (addr > I2C_MAX_ADDR) return; ptr = bus->addrslots + (bitpos / BITS_PER_LONG); - *ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK << - (bitpos % BITS_PER_LONG)); - *ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG); + *ptr &= ~((unsigned long)mask << (bitpos % BITS_PER_LONG)); + *ptr |= ((unsigned long)status & mask) << (bitpos % BITS_PER_LONG); +} + +static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr, + enum i3c_addr_slot_status status) +{ + i3c_bus_set_addr_slot_status_mask(bus, addr, status, I3C_ADDR_SLOT_STATUS_MASK); } static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr) @@ -383,13 +395,44 @@ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr) return status == I3C_ADDR_SLOT_FREE; } +/* + * ┌────┬─────────────┬───┬─────────┬───┐ + * │S/Sr│ 7'h7E RnW=0 │ACK│ ENTDAA │ T ├────┐ + * └────┴─────────────┴───┴─────────┴───┘ │ + * ┌─────────────────────────────────────────┘ + * │ ┌──┬─────────────┬───┬─────────────────┬────────────────┬───┬─────────┐ + * └─►│Sr│7'h7E RnW=1 │ACK│48bit UID BCR DCR│Assign 7bit Addr│PAR│ ACK/NACK│ + * └──┴─────────────┴───┴─────────────────┴────────────────┴───┴─────────┘ + * Some master controllers (such as HCI) need to prepare the entire above transaction before + * sending it out to the I3C bus. This means that a 7-bit dynamic address needs to be allocated + * before knowing the target device's UID information. + * + * However, some I3C targets may request specific addresses (called as "init_dyn_addr"), which is + * typically specified by the DT-'s assigned-address property. Lower addresses having higher IBI + * priority. If it is available, i3c_bus_get_free_addr() preferably return a free address that is + * not in the list of desired addresses (called as "init_dyn_addr"). This allows the device with + * the "init_dyn_addr" to switch to its "init_dyn_addr" when it hot-joins the I3C bus. Otherwise, + * if the "init_dyn_addr" is already in use by another I3C device, the target device will not be + * able to switch to its desired address. + * + * If the previous step fails, fallback returning one of the remaining unassigned address, + * regardless of its state in the desired list. + */ static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr) { enum i3c_addr_slot_status status; u8 addr; for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) { - status = i3c_bus_get_addr_slot_status(bus, addr); + status = i3c_bus_get_addr_slot_status_mask(bus, addr, + I3C_ADDR_SLOT_EXT_STATUS_MASK); + if (status == I3C_ADDR_SLOT_FREE) + return addr; + } + + for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) { + status = i3c_bus_get_addr_slot_status_mask(bus, addr, + I3C_ADDR_SLOT_STATUS_MASK); if (status == I3C_ADDR_SLOT_FREE) return addr; } @@ -1417,7 +1460,7 @@ static void i3c_master_put_i3c_addrs(struct i3c_dev_desc *dev) I3C_ADDR_SLOT_FREE); if (dev->boardinfo && dev->boardinfo->init_dyn_addr) - i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr, + i3c_bus_set_addr_slot_status(&master->bus, dev->boardinfo->init_dyn_addr, I3C_ADDR_SLOT_FREE); } @@ -1506,16 +1549,9 @@ static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, u8 old_dyn_addr) { struct i3c_master_controller *master = i3c_dev_get_master(dev); - enum i3c_addr_slot_status status; int ret; - if (dev->info.dyn_addr != old_dyn_addr && - (!dev->boardinfo || - dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) { - status = i3c_bus_get_addr_slot_status(&master->bus, - dev->info.dyn_addr); - if (status != I3C_ADDR_SLOT_FREE) - return -EBUSY; + if (dev->info.dyn_addr != old_dyn_addr) { i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr, I3C_ADDR_SLOT_I3C_DEV); @@ -1918,9 +1954,11 @@ static int i3c_master_bus_init(struct i3c_master_controller *master) goto err_rstdaa; } - i3c_bus_set_addr_slot_status(&master->bus, - i3cboardinfo->init_dyn_addr, - I3C_ADDR_SLOT_I3C_DEV); + /* Do not mark as occupied until real device exist in bus */ + i3c_bus_set_addr_slot_status_mask(&master->bus, + i3cboardinfo->init_dyn_addr, + I3C_ADDR_SLOT_EXT_DESIRED, + I3C_ADDR_SLOT_EXT_STATUS_MASK); /* * Only try to create/attach devices that have a static @@ -2051,11 +2089,16 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, ibireq.max_payload_len = olddev->ibi->max_payload_len; ibireq.num_slots = olddev->ibi->num_slots; - if (olddev->ibi->enabled) { + if (olddev->ibi->enabled) enable_ibi = true; - i3c_dev_disable_ibi_locked(olddev); - } - + /* + * The olddev should not receive any commands on the + * i3c bus as it does not exist and has been assigned + * a new address. This will result in NACK or timeout. + * So, update the olddev->ibi->enabled flag to false + * to avoid DISEC with OldAddr. + */ + olddev->ibi->enabled = false; i3c_dev_free_ibi_locked(olddev); } mutex_unlock(&olddev->ibi_lock); @@ -2083,7 +2126,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, else expected_dyn_addr = newdev->info.dyn_addr; - if (newdev->info.dyn_addr != expected_dyn_addr) { + if (newdev->info.dyn_addr != expected_dyn_addr && + i3c_bus_get_addr_slot_status(&master->bus, expected_dyn_addr) == I3C_ADDR_SLOT_FREE) { /* * Try to apply the expected dynamic address. If it fails, keep * the address assigned by the master. diff --git a/drivers/i3c/master/ast2600-i3c-master.c b/drivers/i3c/master/ast2600-i3c-master.c index 84942dbb6f8028..e05e83812c712c 100644 --- a/drivers/i3c/master/ast2600-i3c-master.c +++ b/drivers/i3c/master/ast2600-i3c-master.c @@ -174,7 +174,7 @@ 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, + .remove = ast2600_i3c_remove, .driver = { .name = "ast2600-i3c-master", .of_match_table = ast2600_i3c_master_of_match, diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c index 8d694672c1104f..d4b80eb8cecdf4 100644 --- a/drivers/i3c/master/dw-i3c-master.c +++ b/drivers/i3c/master/dw-i3c-master.c @@ -220,6 +220,14 @@ #define XFER_TIMEOUT (msecs_to_jiffies(1000)) #define RPM_AUTOSUSPEND_TIMEOUT 1000 /* ms */ + +/* Timing values to configure 12.5MHz frequency */ +#define AMD_I3C_OD_TIMING 0x4C007C +#define AMD_I3C_PP_TIMING 0x8001A + +/* List of quirks */ +#define AMD_I3C_OD_PP_TIMING BIT(1) + struct dw_i3c_cmd { u32 cmd_lo; u32 cmd_hi; @@ -794,6 +802,12 @@ static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc) return ret; } +static void amd_configure_od_pp_quirk(struct dw_i3c_master *master) +{ + master->i3c_od_timing = AMD_I3C_OD_TIMING; + master->i3c_pp_timing = AMD_I3C_PP_TIMING; +} + static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, struct i3c_ccc_cmd *ccc) { @@ -803,6 +817,13 @@ static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, if (ccc->id == I3C_CCC_ENTDAA) return -EINVAL; + /* AMD platform specific OD and PP timings */ + if (master->quirks & AMD_I3C_OD_PP_TIMING) { + amd_configure_od_pp_quirk(master); + writel(master->i3c_pp_timing, master->regs + SCL_I3C_PP_TIMING); + writel(master->i3c_od_timing, master->regs + SCL_I3C_OD_TIMING); + } + ret = pm_runtime_resume_and_get(master->dev); if (ret < 0) { dev_err(master->dev, @@ -1602,6 +1623,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master, master->maxdevs = ret >> 16; master->free_pos = GENMASK(master->maxdevs - 1, 0); + master->quirks = (unsigned long)device_get_match_data(&pdev->dev); + INIT_WORK(&master->hj_work, dw_i3c_hj_work); ret = i3c_master_register(&master->base, &pdev->dev, &dw_mipi_i3c_ops, false); @@ -1675,6 +1698,10 @@ static void dw_i3c_master_restore_addrs(struct dw_i3c_master *master) static void dw_i3c_master_restore_timing_regs(struct dw_i3c_master *master) { + /* AMD platform specific OD and PP timings */ + if (master->quirks & AMD_I3C_OD_PP_TIMING) + amd_configure_od_pp_quirk(master); + writel(master->i3c_pp_timing, master->regs + SCL_I3C_PP_TIMING); writel(master->bus_free_timing, master->regs + BUS_FREE_TIMING); writel(master->i3c_od_timing, master->regs + SCL_I3C_OD_TIMING); @@ -1748,12 +1775,19 @@ static const struct of_device_id dw_i3c_master_of_match[] = { }; MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match); +static const struct acpi_device_id amd_i3c_device_match[] = { + { "AMDI0015", AMD_I3C_OD_PP_TIMING }, + { } +}; +MODULE_DEVICE_TABLE(acpi, amd_i3c_device_match); + static struct platform_driver dw_i3c_driver = { .probe = dw_i3c_probe, - .remove_new = dw_i3c_remove, + .remove = dw_i3c_remove, .driver = { .name = "dw-i3c-master", .of_match_table = dw_i3c_master_of_match, + .acpi_match_table = amd_i3c_device_match, .pm = &dw_i3c_pm_ops, }, }; diff --git a/drivers/i3c/master/dw-i3c-master.h b/drivers/i3c/master/dw-i3c-master.h index 219ff815d3a734..c5cb695c16ab8f 100644 --- a/drivers/i3c/master/dw-i3c-master.h +++ b/drivers/i3c/master/dw-i3c-master.h @@ -50,6 +50,7 @@ struct dw_i3c_master { u32 bus_free_timing; u32 i2c_fm_timing; u32 i2c_fmp_timing; + u32 quirks; /* * Per-device hardware data, used to manage the device address table * (DAT) diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c index fe4d59833ad5f4..06c0592487d313 100644 --- a/drivers/i3c/master/i3c-master-cdns.c +++ b/drivers/i3c/master/i3c-master-cdns.c @@ -1676,7 +1676,7 @@ static void cdns_i3c_master_remove(struct platform_device *pdev) static struct platform_driver cdns_i3c_master = { .probe = cdns_i3c_master_probe, - .remove_new = cdns_i3c_master_remove, + .remove = 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 a82c47c9986d35..648c501407ced8 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -80,8 +80,6 @@ #define INTR_HC_CMD_SEQ_UFLOW_STAT BIT(12) /* Cmd Sequence Underflow */ #define INTR_HC_RESET_CANCEL BIT(11) /* HC Cancelled Reset */ #define INTR_HC_INTERNAL_ERR BIT(10) /* HC Internal Error */ -#define INTR_HC_PIO BIT(8) /* cascaded PIO interrupt */ -#define INTR_HC_RINGS GENMASK(7, 0) #define DAT_SECTION 0x30 /* Device Address Table */ #define DAT_ENTRY_SIZE GENMASK(31, 28) @@ -438,7 +436,8 @@ static int i3c_hci_attach_i3c_dev(struct i3c_dev_desc *dev) kfree(dev_data); return ret; } - mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, ret, dev->info.dyn_addr); + mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, ret, + dev->info.dyn_addr ?: dev->info.static_addr); dev_data->dat_idx = ret; } i3c_dev_set_master_data(dev, dev_data); @@ -597,9 +596,6 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) if (val) { reg_write(INTR_STATUS, val); - } else { - /* v1.0 does not have PIO cascaded notification bits */ - val |= INTR_HC_PIO; } if (val & INTR_HC_RESET_CANCEL) { @@ -610,14 +606,9 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id) dev_err(&hci->master.dev, "Host Controller Internal Error\n"); val &= ~INTR_HC_INTERNAL_ERR; } - if (val & INTR_HC_PIO) { - hci->io->irq_handler(hci, 0); - val &= ~INTR_HC_PIO; - } - if (val & INTR_HC_RINGS) { - hci->io->irq_handler(hci, val & INTR_HC_RINGS); - val &= ~INTR_HC_RINGS; - } + + hci->io->irq_handler(hci); + if (val) dev_err(&hci->master.dev, "unexpected INTR_STATUS %#x\n", val); else @@ -853,7 +844,7 @@ MODULE_DEVICE_TABLE(acpi, i3c_hci_acpi_match); static struct platform_driver i3c_hci_driver = { .probe = i3c_hci_probe, - .remove_new = i3c_hci_remove, + .remove = i3c_hci_remove, .driver = { .name = "mipi-i3c-hci", .of_match_table = of_match_ptr(i3c_hci_of_match), diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c index a918e96b21fddc..e8e56a8d20573f 100644 --- a/drivers/i3c/master/mipi-i3c-hci/dma.c +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c @@ -159,10 +159,10 @@ static void hci_dma_cleanup(struct i3c_hci *hci) for (i = 0; i < rings->total; i++) { rh = &rings->headers[i]; + rh_reg_write(INTR_SIGNAL_ENABLE, 0); rh_reg_write(RING_CONTROL, 0); rh_reg_write(CR_SETUP, 0); rh_reg_write(IBI_SETUP, 0); - rh_reg_write(INTR_SIGNAL_ENABLE, 0); if (rh->xfer) dma_free_coherent(&hci->master.dev, @@ -733,20 +733,16 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh) rh_reg_write(CHUNK_CONTROL, rh_reg_read(CHUNK_CONTROL) + ibi_chunks); } -static bool hci_dma_irq_handler(struct i3c_hci *hci, unsigned int mask) +static bool hci_dma_irq_handler(struct i3c_hci *hci) { struct hci_rings_data *rings = hci->io_data; unsigned int i; bool handled = false; - for (i = 0; mask && i < rings->total; i++) { + for (i = 0; i < rings->total; i++) { struct hci_rh_data *rh; u32 status; - if (!(mask & BIT(i))) - continue; - mask &= ~BIT(i); - rh = &rings->headers[i]; status = rh_reg_read(INTR_STATUS); DBG("rh%d status: %#x", i, status); diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h index aaa47ac473814a..69ea1d10414b8c 100644 --- a/drivers/i3c/master/mipi-i3c-hci/hci.h +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h @@ -115,7 +115,7 @@ static inline void hci_free_xfer(struct hci_xfer *xfer, unsigned int n) /* This abstracts PIO vs DMA operations */ struct hci_io_ops { - bool (*irq_handler)(struct i3c_hci *hci, unsigned int mask); + bool (*irq_handler)(struct i3c_hci *hci); int (*queue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n); bool (*dequeue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n); int (*request_ibi)(struct i3c_hci *hci, struct i3c_dev_desc *dev, diff --git a/drivers/i3c/master/mipi-i3c-hci/pio.c b/drivers/i3c/master/mipi-i3c-hci/pio.c index d0272aa93599c2..2fc71e6969111a 100644 --- a/drivers/i3c/master/mipi-i3c-hci/pio.c +++ b/drivers/i3c/master/mipi-i3c-hci/pio.c @@ -979,7 +979,7 @@ static void hci_pio_recycle_ibi_slot(struct i3c_hci *hci, i3c_generic_ibi_recycle_slot(dev_ibi->pool, slot); } -static bool hci_pio_irq_handler(struct i3c_hci *hci, unsigned int unused) +static bool hci_pio_irq_handler(struct i3c_hci *hci) { struct hci_pio_data *pio = hci->io_data; u32 status; diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c index a7bfc678153e6c..d6057d8c7dec4e 100644 --- a/drivers/i3c/master/svc-i3c-master.c +++ b/drivers/i3c/master/svc-i3c-master.c @@ -130,8 +130,8 @@ #define SVC_I3C_PPBAUD_MAX 15 #define SVC_I3C_QUICK_I2C_CLK 4170000 -#define SVC_I3C_EVENT_IBI BIT(0) -#define SVC_I3C_EVENT_HOTJOIN BIT(1) +#define SVC_I3C_EVENT_IBI GENMASK(7, 0) +#define SVC_I3C_EVENT_HOTJOIN BIT(31) struct svc_i3c_cmd { u8 addr; @@ -214,7 +214,7 @@ struct svc_i3c_master { spinlock_t lock; } ibi; struct mutex lock; - int enabled_events; + u32 enabled_events; u32 mctrl_config; }; @@ -388,10 +388,11 @@ static int svc_i3c_master_handle_ibi(struct svc_i3c_master *master, return 0; } -static void svc_i3c_master_ack_ibi(struct svc_i3c_master *master, +static int svc_i3c_master_ack_ibi(struct svc_i3c_master *master, bool mandatory_byte) { unsigned int ibi_ack_nack; + u32 reg; ibi_ack_nack = SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK; if (mandatory_byte) @@ -400,13 +401,43 @@ static void svc_i3c_master_ack_ibi(struct svc_i3c_master *master, ibi_ack_nack |= SVC_I3C_MCTRL_IBIRESP_ACK_WITHOUT_BYTE; writel(ibi_ack_nack, master->regs + SVC_I3C_MCTRL); + + return readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg, + SVC_I3C_MSTATUS_MCTRLDONE(reg), 1, 1000); + } -static void svc_i3c_master_nack_ibi(struct svc_i3c_master *master) +static int svc_i3c_master_nack_ibi(struct svc_i3c_master *master) { + int ret; + u32 reg; + writel(SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK | SVC_I3C_MCTRL_IBIRESP_NACK, master->regs + SVC_I3C_MCTRL); + + ret = readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg, + SVC_I3C_MSTATUS_MCTRLDONE(reg), 1, 1000); + return ret; +} + +static int svc_i3c_master_handle_ibi_won(struct svc_i3c_master *master, u32 mstatus) +{ + u32 ibitype; + int ret = 0; + + ibitype = SVC_I3C_MSTATUS_IBITYPE(mstatus); + + writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS); + + /* Hardware can't auto emit NACK for hot join and master request */ + switch (ibitype) { + case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN: + case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: + ret = svc_i3c_master_nack_ibi(master); + } + + return ret; } static void svc_i3c_master_ibi_work(struct work_struct *work) @@ -418,7 +449,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) u32 status, val; int ret; - mutex_lock(&master->lock); + /* + * According to I3C spec ver 1.1, 09-Jun-2021, section 5.1.2.5: + * + * The I3C Controller shall hold SCL low while the Bus is in ACK/NACK Phase of I3C/I2C + * transfer. But maximum stall time is 100us. The IRQs have to be disabled to prevent + * schedule during the whole I3C transaction, otherwise, the I3C bus timeout may happen if + * any irq or schedule happen during transaction. + */ + guard(spinlock_irqsave)(&master->xferqueue.lock); + /* * IBIWON may be set before SVC_I3C_MCTRL_REQUEST_AUTO_IBI, causing * readl_relaxed_poll_timeout() to return immediately. Consequently, @@ -438,8 +478,8 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) master->regs + SVC_I3C_MCTRL); /* Wait for IBIWON, should take approximately 100us */ - ret = readl_relaxed_poll_timeout(master->regs + SVC_I3C_MSTATUS, val, - SVC_I3C_MSTATUS_IBIWON(val), 0, 1000); + ret = readl_relaxed_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, val, + SVC_I3C_MSTATUS_IBIWON(val), 0, 100); if (ret) { dev_err(master->dev, "Timeout when polling for IBIWON\n"); svc_i3c_master_emit_stop(master); @@ -511,7 +551,6 @@ static void svc_i3c_master_ibi_work(struct work_struct *work) reenable_ibis: svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); - mutex_unlock(&master->lock); } static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id) @@ -854,6 +893,9 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, int ret, i; while (true) { + /* clean SVC_I3C_MINT_IBIWON w1c bits */ + writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS); + /* SVC_I3C_MCTRL_REQUEST_PROC_DAA have two mode, ENTER DAA or PROCESS DAA. * * ENTER DAA: @@ -905,6 +947,11 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master, ret = svc_i3c_master_readb(master, data, 2); if (ret) break; + } else if (SVC_I3C_MSTATUS_IBIWON(reg)) { + ret = svc_i3c_master_handle_ibi_won(master, reg); + if (ret) + break; + continue; } else if (SVC_I3C_MSTATUS_MCTRLDONE(reg)) { if (SVC_I3C_MSTATUS_STATE_IDLE(reg) && SVC_I3C_MSTATUS_COMPLETE(reg)) { @@ -1056,12 +1103,27 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m) if (ret) goto rpm_out; - /* Register all devices who participated to the core */ - for (i = 0; i < dev_nb; i++) { - ret = i3c_master_add_i3c_dev_locked(m, addrs[i]); - if (ret) - goto rpm_out; - } + /* + * Register all devices who participated to the core + * + * If two devices (A and B) are detected in DAA and address 0xa is assigned to + * device A and 0xb to device B, a failure in i3c_master_add_i3c_dev_locked() + * for device A (addr: 0xa) could prevent device B (addr: 0xb) from being + * registered on the bus. The I3C stack might still consider 0xb a free + * address. If a subsequent Hotjoin occurs, 0xb might be assigned to Device A, + * causing both devices A and B to use the same address 0xb, violating the I3C + * specification. + * + * The return value for i3c_master_add_i3c_dev_locked() should not be checked + * because subsequent steps will scan the entire I3C bus, independent of + * whether i3c_master_add_i3c_dev_locked() returns success. + * + * If device A registration fails, there is still a chance to register device + * B. i3c_master_add_i3c_dev_locked() can reset DAA if a failure occurs while + * retrieving device information. + */ + for (i = 0; i < dev_nb; i++) + i3c_master_add_i3c_dev_locked(m, addrs[i]); /* Configure IBI auto-rules */ ret = svc_i3c_update_ibirules(master); @@ -1163,6 +1225,26 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, if (ret) goto emit_stop; + /* + * According to I3C spec ver 1.1.1, 5.1.2.2.3 Consequence of Controller Starting a + * Frame with I3C Target Address. + * + * The I3C Controller normally should start a Frame, the Address may be arbitrated, + * and so the Controller shall monitor to see whether an In-Band Interrupt request, + * a Controller Role Request (i.e., Secondary Controller requests to become the + * Active Controller), or a Hot-Join Request has been made. + * + * If missed IBIWON check, the wrong data will be return. When IBIWON happen, issue + * repeat start. Address arbitrate only happen at START, never happen at REPEAT + * start. + */ + if (SVC_I3C_MSTATUS_IBIWON(reg)) { + ret = svc_i3c_master_handle_ibi_won(master, reg); + if (ret) + goto emit_stop; + continue; + } + if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) { /* * According to I3C Spec 1.1.1, 11-Jun-2021, section: 5.1.2.2.3. @@ -1196,24 +1278,6 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master, } } - /* - * According to I3C spec ver 1.1.1, 5.1.2.2.3 Consequence of Controller Starting a Frame - * with I3C Target Address. - * - * The I3C Controller normally should start a Frame, the Address may be arbitrated, and so - * the Controller shall monitor to see whether an In-Band Interrupt request, a Controller - * Role Request (i.e., Secondary Controller requests to become the Active Controller), or - * a Hot-Join Request has been made. - * - * If missed IBIWON check, the wrong data will be return. When IBIWON happen, return failure - * and yield the above events handler. - */ - if (SVC_I3C_MSTATUS_IBIWON(reg)) { - ret = -EAGAIN; - *actual_len = 0; - goto emit_stop; - } - if (rnw) ret = svc_i3c_master_read(master, in, xfer_len); else @@ -1624,7 +1688,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev) return ret; } - master->enabled_events |= SVC_I3C_EVENT_IBI; + master->enabled_events++; svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART); return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); @@ -1636,7 +1700,7 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev) struct svc_i3c_master *master = to_svc_i3c_master(m); int ret; - master->enabled_events &= ~SVC_I3C_EVENT_IBI; + master->enabled_events--; if (!master->enabled_events) svc_i3c_master_disable_interrupts(master); @@ -1827,8 +1891,8 @@ static int svc_i3c_master_probe(struct platform_device *pdev) rpm_disable: pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); err_disable_clks: svc_i3c_master_unprepare_clks(master); @@ -1902,7 +1966,7 @@ MODULE_DEVICE_TABLE(of, svc_i3c_master_of_match_tbl); static struct platform_driver svc_i3c_master = { .probe = svc_i3c_master_probe, - .remove_new = svc_i3c_master_remove, + .remove = 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 67aebfe0fed665..ac4d8faa3886c8 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -1069,6 +1069,47 @@ static struct cpuidle_state gnr_cstates[] __initdata = { .enter = NULL } }; +static struct cpuidle_state gnrd_cstates[] __initdata = { + { + .name = "C1", + .desc = "MWAIT 0x00", + .flags = MWAIT2flg(0x00), + .exit_latency = 1, + .target_residency = 1, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { + .name = "C1E", + .desc = "MWAIT 0x01", + .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, + .exit_latency = 4, + .target_residency = 4, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { + .name = "C6", + .desc = "MWAIT 0x20", + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | + CPUIDLE_FLAG_INIT_XSTATE | + CPUIDLE_FLAG_PARTIAL_HINT_MATCH, + .exit_latency = 220, + .target_residency = 650, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { + .name = "C6P", + .desc = "MWAIT 0x21", + .flags = MWAIT2flg(0x21) | CPUIDLE_FLAG_TLB_FLUSHED | + CPUIDLE_FLAG_INIT_XSTATE | + CPUIDLE_FLAG_PARTIAL_HINT_MATCH, + .exit_latency = 240, + .target_residency = 750, + .enter = &intel_idle, + .enter_s2idle = intel_idle_s2idle, }, + { + .enter = NULL } +}; + static struct cpuidle_state atom_cstates[] __initdata = { { .name = "C1E", @@ -1508,6 +1549,12 @@ static const struct idle_cpu idle_cpu_gnr __initconst = { .use_acpi = true, }; +static const struct idle_cpu idle_cpu_gnrd __initconst = { + .state_table = gnrd_cstates, + .disable_promotion_to_c1e = true, + .use_acpi = true, +}; + static const struct idle_cpu idle_cpu_avn __initconst = { .state_table = avn_cstates, .disable_promotion_to_c1e = true, @@ -1593,6 +1640,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = { X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, &idle_cpu_spr), X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &idle_cpu_spr), X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, &idle_cpu_gnr), + X86_MATCH_VFM(INTEL_GRANITERAPIDS_D, &idle_cpu_gnrd), X86_MATCH_VFM(INTEL_XEON_PHI_KNL, &idle_cpu_knl), X86_MATCH_VFM(INTEL_XEON_PHI_KNM, &idle_cpu_knl), X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, &idle_cpu_bxt), diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c index d054721859b3b5..8601b9a8b8e75c 100644 --- a/drivers/iio/accel/adis16201.c +++ b/drivers/iio/accel/adis16201.c @@ -300,4 +300,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16201"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c index 0035e4f4db63ff..41ffd92f27fdca 100644 --- a/drivers/iio/accel/adis16209.c +++ b/drivers/iio/accel/adis16209.c @@ -310,4 +310,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16209"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c index 4de0a41bd67967..46cca10e776f07 100644 --- a/drivers/iio/accel/adxl313_core.c +++ b/drivers/iio/accel/adxl313_core.c @@ -32,19 +32,19 @@ const struct regmap_access_table adxl312_readable_regs_table = { .yes_ranges = adxl312_readable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl312_readable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl312_readable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl312_readable_regs_table, "IIO_ADXL313"); const struct regmap_access_table adxl313_readable_regs_table = { .yes_ranges = adxl313_readable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, "IIO_ADXL313"); const struct regmap_access_table adxl314_readable_regs_table = { .yes_ranges = adxl312_readable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl312_readable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl314_readable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl314_readable_regs_table, "IIO_ADXL313"); static int adxl312_check_id(struct device *dev, struct adxl313_data *data) @@ -121,7 +121,7 @@ const struct adxl313_chip_info adxl31x_chip_info[] = { .check_id = &adxl312_check_id, }, }; -EXPORT_SYMBOL_NS_GPL(adxl31x_chip_info, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl31x_chip_info, "IIO_ADXL313"); static const struct regmap_range adxl312_writable_reg_range[] = { regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)), @@ -144,19 +144,19 @@ const struct regmap_access_table adxl312_writable_regs_table = { .yes_ranges = adxl312_writable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl312_writable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl312_writable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl312_writable_regs_table, "IIO_ADXL313"); const struct regmap_access_table adxl313_writable_regs_table = { .yes_ranges = adxl313_writable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, "IIO_ADXL313"); const struct regmap_access_table adxl314_writable_regs_table = { .yes_ranges = adxl312_writable_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl312_writable_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl314_writable_regs_table, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl314_writable_regs_table, "IIO_ADXL313"); static const int adxl313_odr_freqs[][2] = { [0] = { 6, 250000 }, @@ -417,7 +417,7 @@ int adxl313_core_probe(struct device *dev, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313); +EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, "IIO_ADXL313"); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c index a4cf0cf2c5aaa8..dfa51860cd83d6 100644 --- a/drivers/iio/accel/adxl313_i2c.c +++ b/drivers/iio/accel/adxl313_i2c.c @@ -92,4 +92,4 @@ module_i2c_driver(adxl313_i2c_driver); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL313); +MODULE_IMPORT_NS("IIO_ADXL313"); diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index 6f8d73f6e5a939..ebc5d09f108d16 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -119,4 +119,4 @@ module_spi_driver(adxl313_spi_driver); MODULE_AUTHOR("Lucas Stankus "); MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL313); +MODULE_IMPORT_NS("IIO_ADXL313"); diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 006ce66c0aa388..b1efab0f6404ba 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -248,7 +248,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, IIO_ADXL345); +EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, "IIO_ADXL345"); MODULE_AUTHOR("Eva Rachel Retuya "); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl345_i2c.c b/drivers/iio/accel/adxl345_i2c.c index 4065b8f7c8a8ae..cb23fb11fcd7d8 100644 --- a/drivers/iio/accel/adxl345_i2c.c +++ b/drivers/iio/accel/adxl345_i2c.c @@ -74,4 +74,4 @@ module_i2c_driver(adxl345_i2c_driver); MODULE_AUTHOR("Eva Rachel Retuya "); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL345); +MODULE_IMPORT_NS("IIO_ADXL345"); diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c index 57e16b44170214..968e7b390d4bb6 100644 --- a/drivers/iio/accel/adxl345_spi.c +++ b/drivers/iio/accel/adxl345_spi.c @@ -88,4 +88,4 @@ module_spi_driver(adxl345_spi_driver); MODULE_AUTHOR("Eva Rachel Retuya "); MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL345); +MODULE_IMPORT_NS("IIO_ADXL345"); diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index eabaefa92f19d1..e8cd21fa77a698 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -72,7 +72,7 @@ const struct regmap_access_table adxl355_readable_regs_tbl = { .yes_ranges = adxl355_read_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl355_read_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl355_readable_regs_tbl, IIO_ADXL355); +EXPORT_SYMBOL_NS_GPL(adxl355_readable_regs_tbl, "IIO_ADXL355"); static const struct regmap_range adxl355_write_reg_range[] = { regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_RESET_REG), @@ -82,7 +82,7 @@ const struct regmap_access_table adxl355_writeable_regs_tbl = { .yes_ranges = adxl355_write_reg_range, .n_yes_ranges = ARRAY_SIZE(adxl355_write_reg_range), }; -EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, IIO_ADXL355); +EXPORT_SYMBOL_NS_GPL(adxl355_writeable_regs_tbl, "IIO_ADXL355"); const struct adxl355_chip_info adxl35x_chip_info[] = { [ADXL355] = { @@ -136,7 +136,7 @@ const struct adxl355_chip_info adxl35x_chip_info[] = { }, }, }; -EXPORT_SYMBOL_NS_GPL(adxl35x_chip_info, IIO_ADXL355); +EXPORT_SYMBOL_NS_GPL(adxl35x_chip_info, "IIO_ADXL355"); enum adxl355_op_mode { ADXL355_MEASUREMENT, @@ -643,7 +643,7 @@ static irqreturn_t adxl355_trigger_handler(int irq, void *p) * The acceleration data is 24 bits and big endian. It has to be saved * in 32 bits, hence, it is saved in the 2nd byte of the 4 byte buffer. * The buf array is 14 bytes as it includes 3x4=12 bytes for - * accelaration data of x, y, and z axis. It also includes 2 bytes for + * acceleration data of x, y, and z axis. It also includes 2 bytes for * temperature data. */ ret = regmap_bulk_read(data->regmap, ADXL355_XDATA3_REG, @@ -801,7 +801,7 @@ int adxl355_core_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl355_core_probe, IIO_ADXL355); +EXPORT_SYMBOL_NS_GPL(adxl355_core_probe, "IIO_ADXL355"); MODULE_AUTHOR("Puranjay Mohan "); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer core driver"); diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c index 32398cde9608e2..1a512c7b792b6f 100644 --- a/drivers/iio/accel/adxl355_i2c.c +++ b/drivers/iio/accel/adxl355_i2c.c @@ -67,4 +67,4 @@ module_i2c_driver(adxl355_i2c_driver); MODULE_AUTHOR("Puranjay Mohan "); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL355); +MODULE_IMPORT_NS("IIO_ADXL355"); diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c index 5153ac815e4b09..869e3e57d6f728 100644 --- a/drivers/iio/accel/adxl355_spi.c +++ b/drivers/iio/accel/adxl355_spi.c @@ -70,4 +70,4 @@ module_spi_driver(adxl355_spi_driver); MODULE_AUTHOR("Puranjay Mohan "); MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADXL355); +MODULE_IMPORT_NS("IIO_ADXL355"); diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index e790a66d86c79f..a48ac0d7bd96b1 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -1073,7 +1073,7 @@ static int adxl367_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) + bool state) { enum adxl367_activity_type act; @@ -1475,7 +1475,7 @@ int adxl367_probe(struct device *dev, const struct adxl367_ops *ops, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl367_probe, IIO_ADXL367); +EXPORT_SYMBOL_NS_GPL(adxl367_probe, "IIO_ADXL367"); MODULE_AUTHOR("Cosmin Tanislav "); MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer driver"); diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c index deb82a43ec36fb..80f0b642b9b0a5 100644 --- a/drivers/iio/accel/adxl367_i2c.c +++ b/drivers/iio/accel/adxl367_i2c.c @@ -83,7 +83,7 @@ static struct i2c_driver adxl367_i2c_driver = { module_i2c_driver(adxl367_i2c_driver); -MODULE_IMPORT_NS(IIO_ADXL367); +MODULE_IMPORT_NS("IIO_ADXL367"); MODULE_AUTHOR("Cosmin Tanislav "); MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer I2C driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c index b7011726579151..49d7c8fbe8edc8 100644 --- a/drivers/iio/accel/adxl367_spi.c +++ b/drivers/iio/accel/adxl367_spi.c @@ -160,7 +160,7 @@ static struct spi_driver adxl367_spi_driver = { module_spi_driver(adxl367_spi_driver); -MODULE_IMPORT_NS(IIO_ADXL367); +MODULE_IMPORT_NS("IIO_ADXL367"); MODULE_AUTHOR("Cosmin Tanislav "); MODULE_DESCRIPTION("Analog Devices ADXL367 3-axis accelerometer SPI driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index ef8dd557877bd4..8ba5fbe6e1f50f 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -940,7 +940,7 @@ static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio static int adxl372_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) + bool state) { struct adxl372_state *st = iio_priv(indio_dev); @@ -1176,7 +1176,7 @@ bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg) { return (reg == ADXL372_FIFO_DATA); } -EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, IIO_ADXL372); +EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, "IIO_ADXL372"); int adxl372_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) @@ -1260,7 +1260,7 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl372_probe, IIO_ADXL372); +EXPORT_SYMBOL_NS_GPL(adxl372_probe, "IIO_ADXL372"); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver"); diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index 3571cfde1c0e7c..43d5fd921be7b9 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -67,4 +67,4 @@ module_i2c_driver(adxl372_i2c_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ADXL372); +MODULE_IMPORT_NS("IIO_ADXL372"); diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c index 787699773f96f9..1ab1997a55b1f8 100644 --- a/drivers/iio/accel/adxl372_spi.c +++ b/drivers/iio/accel/adxl372_spi.c @@ -58,4 +58,4 @@ module_spi_driver(adxl372_spi_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ADXL372); +MODULE_IMPORT_NS("IIO_ADXL372"); diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c index f80527d899be4d..90340f134722a3 100644 --- a/drivers/iio/accel/adxl380.c +++ b/drivers/iio/accel/adxl380.c @@ -194,7 +194,7 @@ const struct adxl380_chip_info adxl380_chip_info = { .temp_offset = 25 * 102 / 10 - 470, }; -EXPORT_SYMBOL_NS_GPL(adxl380_chip_info, IIO_ADXL380); +EXPORT_SYMBOL_NS_GPL(adxl380_chip_info, "IIO_ADXL380"); const struct adxl380_chip_info adxl382_chip_info = { .name = "adxl382", @@ -211,7 +211,7 @@ const struct adxl380_chip_info adxl382_chip_info = { */ .temp_offset = 25 * 102 / 10 - 570, }; -EXPORT_SYMBOL_NS_GPL(adxl382_chip_info, IIO_ADXL380); +EXPORT_SYMBOL_NS_GPL(adxl382_chip_info, "IIO_ADXL380"); static const unsigned int adxl380_th_reg_high_addr[2] = { [ADXL380_ACTIVITY] = ADXL380_THRESH_ACT_H_REG, @@ -263,7 +263,7 @@ bool adxl380_readable_noinc_reg(struct device *dev, unsigned int reg) { return reg == ADXL380_FIFO_DATA; } -EXPORT_SYMBOL_NS_GPL(adxl380_readable_noinc_reg, IIO_ADXL380); +EXPORT_SYMBOL_NS_GPL(adxl380_readable_noinc_reg, "IIO_ADXL380"); static int adxl380_set_measure_en(struct adxl380_state *st, bool en) { @@ -1181,7 +1181,7 @@ static int adxl380_read_raw(struct iio_dev *indio_dev, ret = adxl380_read_chn(st, chan->address); iio_device_release_direct_mode(indio_dev); - if (ret) + if (ret < 0) return ret; *val = sign_extend32(ret >> chan->scan_type.shift, @@ -1386,7 +1386,7 @@ static int adxl380_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) + bool state) { struct adxl380_state *st = iio_priv(indio_dev); enum adxl380_axis axis; @@ -1719,7 +1719,6 @@ static int adxl380_config_irq(struct iio_dev *indio_dev) { struct adxl380_state *st = iio_priv(indio_dev); unsigned long irq_flag; - struct irq_data *desc; u32 irq_type; u8 polarity; int ret; @@ -1737,11 +1736,7 @@ static int adxl380_config_irq(struct iio_dev *indio_dev) st->int_map[1] = ADXL380_INT1_MAP1_REG; } - desc = irq_get_irq_data(st->irq); - if (!desc) - return dev_err_probe(st->dev, -EINVAL, "Could not find IRQ %d\n", st->irq); - - irq_type = irqd_get_trigger_type(desc); + irq_type = irq_get_trigger_type(st->irq); if (irq_type == IRQ_TYPE_LEVEL_HIGH) { polarity = 0; irq_flag = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; @@ -1897,7 +1892,7 @@ int adxl380_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(adxl380_probe, IIO_ADXL380); +EXPORT_SYMBOL_NS_GPL(adxl380_probe, "IIO_ADXL380"); MODULE_AUTHOR("Ramona Gradinariu "); MODULE_AUTHOR("Antoniu Miclaus "); diff --git a/drivers/iio/accel/adxl380_i2c.c b/drivers/iio/accel/adxl380_i2c.c index 1dc1e77be815de..b4f86f97236148 100644 --- a/drivers/iio/accel/adxl380_i2c.c +++ b/drivers/iio/accel/adxl380_i2c.c @@ -61,4 +61,4 @@ MODULE_AUTHOR("Ramona Gradinariu "); MODULE_AUTHOR("Antoniu Miclaus "); MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer I2C driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ADXL380); +MODULE_IMPORT_NS("IIO_ADXL380"); diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c index e7b5778cb6cfe9..6edd0d211ffad9 100644 --- a/drivers/iio/accel/adxl380_spi.c +++ b/drivers/iio/accel/adxl380_spi.c @@ -63,4 +63,4 @@ MODULE_AUTHOR("Ramona Gradinariu "); MODULE_AUTHOR("Antoniu Miclaus "); MODULE_DESCRIPTION("Analog Devices ADXL380 3-axis accelerometer SPI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ADXL380); +MODULE_IMPORT_NS("IIO_ADXL380"); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 2445a0f7bc2bae..128db14ba726a3 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -144,7 +145,7 @@ struct bma180_data { /* Ensure timestamp is naturally aligned */ struct { s16 chan[4]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; }; diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index fcbd695e46549f..009e6243c6cba9 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index e4fe36768216da..ae806ed60271a7 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -115,7 +115,7 @@ struct bma400_data { struct { __le16 buff[3]; u8 temperature; - s64 ts __aligned(8); + aligned_s64 ts; } buffer __aligned(IIO_DMA_MINALIGN); __le16 status; __be16 duration; @@ -194,7 +194,7 @@ const struct regmap_config bma400_regmap_config = { .writeable_reg = bma400_is_writable_reg, .volatile_reg = bma400_is_volatile_reg, }; -EXPORT_SYMBOL_NS(bma400_regmap_config, IIO_BMA400); +EXPORT_SYMBOL_NS(bma400_regmap_config, "IIO_BMA400"); static const struct iio_mount_matrix * bma400_accel_get_mount_matrix(const struct iio_dev *indio_dev, @@ -1293,7 +1293,7 @@ static int bma400_disable_adv_interrupt(struct bma400_data *data) static int bma400_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) + enum iio_event_direction dir, bool state) { struct bma400_data *data = iio_priv(indio_dev); int ret; @@ -1763,7 +1763,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, int irq, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS(bma400_probe, IIO_BMA400); +EXPORT_SYMBOL_NS(bma400_probe, "IIO_BMA400"); MODULE_AUTHOR("Dan Robertson "); MODULE_AUTHOR("Jagath Jog J "); diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c index c1c72f577295a8..24a390c3ae66d1 100644 --- a/drivers/iio/accel/bma400_i2c.c +++ b/drivers/iio/accel/bma400_i2c.c @@ -53,4 +53,4 @@ module_i2c_driver(bma400_i2c_driver); MODULE_AUTHOR("Dan Robertson "); MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (I2C)"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_BMA400); +MODULE_IMPORT_NS("IIO_BMA400"); diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c index 765d8c4a4c4ddf..d386f643515bac 100644 --- a/drivers/iio/accel/bma400_spi.c +++ b/drivers/iio/accel/bma400_spi.c @@ -112,4 +112,4 @@ module_spi_driver(bma400_spi_driver); MODULE_AUTHOR("Dan Robertson "); MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (SPI)"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_BMA400); +MODULE_IMPORT_NS("IIO_BMA400"); diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 0f32c1e92b4dc1..744a034bb8b5f2 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -203,7 +203,7 @@ const struct regmap_config bmc150_regmap_conf = { .val_bits = 8, .max_register = 0x3f, }; -EXPORT_SYMBOL_NS_GPL(bmc150_regmap_conf, IIO_BMC150); +EXPORT_SYMBOL_NS_GPL(bmc150_regmap_conf, "IIO_BMC150"); static int bmc150_accel_set_mode(struct bmc150_accel_data *data, enum bmc150_power_modes mode, @@ -804,7 +804,7 @@ static int bmc150_accel_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) + bool state) { struct bmc150_accel_data *data = iio_priv(indio_dev); int ret; @@ -1760,7 +1760,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, return ret; } -EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_probe, IIO_BMC150); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_probe, "IIO_BMC150"); void bmc150_accel_core_remove(struct device *dev) { @@ -1783,7 +1783,7 @@ void bmc150_accel_core_remove(struct device *dev) regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); } -EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_remove, IIO_BMC150); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_core_remove, "IIO_BMC150"); #ifdef CONFIG_PM_SLEEP static int bmc150_accel_suspend(struct device *dev) @@ -1858,7 +1858,7 @@ const struct dev_pm_ops bmc150_accel_pm_ops = { SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, bmc150_accel_runtime_resume, NULL) }; -EXPORT_SYMBOL_NS_GPL(bmc150_accel_pm_ops, IIO_BMC150); +EXPORT_SYMBOL_NS_GPL(bmc150_accel_pm_ops, "IIO_BMC150"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index 1c2e40369839a3..0d4ce6c3893172 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -291,4 +291,4 @@ module_i2c_driver(bmc150_accel_driver); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMC150 I2C accelerometer driver"); -MODULE_IMPORT_NS(IIO_BMC150); +MODULE_IMPORT_NS("IIO_BMC150"); diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index a6b9f599eb7bdc..70b3642656abcd 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -81,4 +81,4 @@ module_spi_driver(bmc150_accel_driver); MODULE_AUTHOR("Markus Pargmann "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMC150 SPI accelerometer driver"); -MODULE_IMPORT_NS(IIO_BMC150); +MODULE_IMPORT_NS("IIO_BMC150"); diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h index 7775c5edaeefd4..7a7baf52e5955b 100644 --- a/drivers/iio/accel/bmc150-accel.h +++ b/drivers/iio/accel/bmc150-accel.h @@ -6,6 +6,7 @@ #include #include #include +#include #include struct regmap; @@ -69,7 +70,7 @@ struct bmc150_accel_data { */ struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; u8 bw_bits; u32 slope_dur; diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c index fc1c1613d673b5..9206fbdbf520c9 100644 --- a/drivers/iio/accel/bmi088-accel-core.c +++ b/drivers/iio/accel/bmi088-accel-core.c @@ -147,7 +147,7 @@ const struct regmap_config bmi088_regmap_conf = { .volatile_table = &bmi088_volatile_table, .cache_type = REGCACHE_RBTREE, }; -EXPORT_SYMBOL_NS_GPL(bmi088_regmap_conf, IIO_BMI088); +EXPORT_SYMBOL_NS_GPL(bmi088_regmap_conf, "IIO_BMI088"); static int bmi088_accel_power_up(struct bmi088_accel_data *data) { @@ -587,7 +587,7 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap, return ret; } -EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_probe, IIO_BMI088); +EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_probe, "IIO_BMI088"); void bmi088_accel_core_remove(struct device *dev) @@ -601,7 +601,7 @@ void bmi088_accel_core_remove(struct device *dev) pm_runtime_set_suspended(dev); bmi088_accel_power_down(data); } -EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_remove, IIO_BMI088); +EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_remove, "IIO_BMI088"); static int bmi088_accel_runtime_suspend(struct device *dev) { diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c index 17e9156bbe89e2..bd22bd0d3c250d 100644 --- a/drivers/iio/accel/bmi088-accel-i2c.c +++ b/drivers/iio/accel/bmi088-accel-i2c.c @@ -67,4 +67,4 @@ module_i2c_driver(bmi088_accel_driver); MODULE_AUTHOR("Jun Yan "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("BMI088 accelerometer driver (I2C)"); -MODULE_IMPORT_NS(IIO_BMI088); +MODULE_IMPORT_NS("IIO_BMI088"); diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c index df1adc059aa94b..c9d51a74c07fbb 100644 --- a/drivers/iio/accel/bmi088-accel-spi.c +++ b/drivers/iio/accel/bmi088-accel-spi.c @@ -94,4 +94,4 @@ module_spi_driver(bmi088_accel_driver); MODULE_AUTHOR("Niek van Agt "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMI088 accelerometer driver (SPI)"); -MODULE_IMPORT_NS(IIO_BMI088); +MODULE_IMPORT_NS("IIO_BMI088"); diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index acadabec4df7ad..65aac60f124510 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -163,7 +164,7 @@ struct fxls8962af_data { const struct fxls8962af_chip_info *chip_info; struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ struct iio_mount_matrix orientation; @@ -179,7 +180,7 @@ const struct regmap_config fxls8962af_i2c_regmap_conf = { .val_bits = 8, .max_register = FXLS8962AF_MAX_REG, }; -EXPORT_SYMBOL_NS_GPL(fxls8962af_i2c_regmap_conf, IIO_FXLS8962AF); +EXPORT_SYMBOL_NS_GPL(fxls8962af_i2c_regmap_conf, "IIO_FXLS8962AF"); const struct regmap_config fxls8962af_spi_regmap_conf = { .reg_bits = 8, @@ -187,7 +188,7 @@ const struct regmap_config fxls8962af_spi_regmap_conf = { .val_bits = 8, .max_register = FXLS8962AF_MAX_REG, }; -EXPORT_SYMBOL_NS_GPL(fxls8962af_spi_regmap_conf, IIO_FXLS8962AF); +EXPORT_SYMBOL_NS_GPL(fxls8962af_spi_regmap_conf, "IIO_FXLS8962AF"); enum { fxls8962af_idx_x, @@ -616,7 +617,7 @@ static int fxls8962af_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) + enum iio_event_direction dir, bool state) { struct fxls8962af_data *data = iio_priv(indio_dev); u8 enable_event, enable_bits; @@ -1103,8 +1104,7 @@ static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq) if (ret) return ret; - irq_type = irqd_get_trigger_type(irq_get_irq_data(irq)); - + irq_type = irq_get_trigger_type(irq); switch (irq_type) { case IRQF_TRIGGER_HIGH: case IRQF_TRIGGER_RISING: @@ -1220,7 +1220,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq) return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, IIO_FXLS8962AF); +EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, "IIO_FXLS8962AF"); static int fxls8962af_runtime_suspend(struct device *dev) { diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c index 16012467330830..2e1bb43ef2a142 100644 --- a/drivers/iio/accel/fxls8962af-i2c.c +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -55,4 +55,4 @@ module_i2c_driver(fxls8962af_driver); MODULE_AUTHOR("Sean Nyekjaer "); MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_FXLS8962AF); +MODULE_IMPORT_NS("IIO_FXLS8962AF"); diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c index a0d192211839f8..46fc6e002714f6 100644 --- a/drivers/iio/accel/fxls8962af-spi.c +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -55,4 +55,4 @@ module_spi_driver(fxls8962af_driver); MODULE_AUTHOR("Sean Nyekjaer "); MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_FXLS8962AF); +MODULE_IMPORT_NS("IIO_FXLS8962AF"); diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 9b7a73a4c48a52..078fab2abb68bf 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -28,7 +28,7 @@ struct accel_3d_state { /* Ensure timestamp is naturally aligned */ struct { u32 accel_val[3]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -328,6 +328,7 @@ static int accel_3d_parse_report(struct platform_device *pdev, /* Function to initialize the processing for usage id */ static int hid_accel_3d_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret = 0; const char *name; struct iio_dev *indio_dev; @@ -335,8 +336,6 @@ static int hid_accel_3d_probe(struct platform_device *pdev) const struct iio_chan_spec *channel_spec; int channel_size; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct accel_3d_state)); if (indio_dev == NULL) @@ -424,7 +423,7 @@ static int hid_accel_3d_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_accel_3d_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct accel_3d_state *accel_state = iio_priv(indio_dev); @@ -452,11 +451,11 @@ static struct platform_driver hid_accel_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_accel_3d_probe, - .remove_new = hid_accel_3d_remove, + .remove = hid_accel_3d_remove, }; module_platform_driver(hid_accel_3d_platform_driver); MODULE_DESCRIPTION("HID Sensor Accel 3D"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/accel/kionix-kx022a-i2c.c b/drivers/iio/accel/kionix-kx022a-i2c.c index 8a1d4fc28ddd5a..b39a43ecadffb0 100644 --- a/drivers/iio/accel/kionix-kx022a-i2c.c +++ b/drivers/iio/accel/kionix-kx022a-i2c.c @@ -65,4 +65,4 @@ module_i2c_driver(kx022a_i2c_driver); MODULE_DESCRIPTION("ROHM/Kionix KX022A accelerometer driver"); MODULE_AUTHOR("Matti Vaittinen "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_KX022A); +MODULE_IMPORT_NS("IIO_KX022A"); diff --git a/drivers/iio/accel/kionix-kx022a-spi.c b/drivers/iio/accel/kionix-kx022a-spi.c index f798b964d0b59e..c38a47806a0006 100644 --- a/drivers/iio/accel/kionix-kx022a-spi.c +++ b/drivers/iio/accel/kionix-kx022a-spi.c @@ -65,4 +65,4 @@ module_spi_driver(kx022a_spi_driver); MODULE_DESCRIPTION("ROHM/Kionix kx022A accelerometer driver"); MODULE_AUTHOR("Matti Vaittinen "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_KX022A); +MODULE_IMPORT_NS("IIO_KX022A"); diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 53d59a04ae15e9..670bac21965bde 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -292,7 +293,7 @@ struct kx022a_data { __le16 buffer[8] __aligned(IIO_DMA_MINALIGN); struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; }; @@ -594,7 +595,7 @@ static int kx022a_get_axis(struct kx022a_data *data, if (ret) return ret; - *val = le16_to_cpu(data->buffer[0]); + *val = (s16)le16_to_cpu(data->buffer[0]); return IIO_VAL_INT; } @@ -1175,7 +1176,7 @@ const struct kx022a_chip_info kx022a_chip_info = { .xout_l = KX022A_REG_XOUT_L, .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, }; -EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, IIO_KX022A); +EXPORT_SYMBOL_NS_GPL(kx022a_chip_info, "IIO_KX022A"); const struct kx022a_chip_info kx132_chip_info = { .name = "kx132-1211", @@ -1201,7 +1202,7 @@ const struct kx022a_chip_info kx132_chip_info = { .xout_l = KX132_REG_XOUT_L, .get_fifo_bytes_available = kx132_get_fifo_bytes_available, }; -EXPORT_SYMBOL_NS_GPL(kx132_chip_info, IIO_KX022A); +EXPORT_SYMBOL_NS_GPL(kx132_chip_info, "IIO_KX022A"); /* * Despite the naming, KX132ACR-LBZ is not similar to KX132-1211 but it is @@ -1233,7 +1234,7 @@ const struct kx022a_chip_info kx132acr_chip_info = { .xout_l = KX022A_REG_XOUT_L, .get_fifo_bytes_available = kx022a_get_fifo_bytes_available, }; -EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, IIO_KX022A); +EXPORT_SYMBOL_NS_GPL(kx132acr_chip_info, "IIO_KX022A"); int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chip_info) { @@ -1371,7 +1372,7 @@ int kx022a_probe_internal(struct device *dev, const struct kx022a_chip_info *chi return ret; } -EXPORT_SYMBOL_NS_GPL(kx022a_probe_internal, IIO_KX022A); +EXPORT_SYMBOL_NS_GPL(kx022a_probe_internal, "IIO_KX022A"); MODULE_DESCRIPTION("ROHM/Kionix KX022A accelerometer driver"); MODULE_AUTHOR("Matti Vaittinen "); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index b76df881632327..f2496cad8ec25f 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -4,13 +4,15 @@ * Copyright (c) 2014, Intel Corporation. */ -#include #include #include #include #include +#include +#include #include #include +#include #include #include #include @@ -168,14 +170,73 @@ #define KXCJK1013_DEFAULT_WAKE_THRES 1 -enum kx_chipset { - KXCJK1013, - KXCJ91008, - KXTJ21009, - KXTF9, - KX0221020, - KX0231025, - KX_MAX_CHIPS /* this must be last */ +/* Refer to section 4 of the specification */ +struct kx_odr_start_up_time { + int odr_bits; + int usec; +}; + +/* KXCJK-1013 */ +static const struct kx_odr_start_up_time kxcjk1013_odr_start_up_times[] = { + { 0x08, 100000 }, + { 0x09, 100000 }, + { 0x0A, 100000 }, + { 0x0B, 100000 }, + { 0x00, 80000 }, + { 0x01, 41000 }, + { 0x02, 21000 }, + { 0x03, 11000 }, + { 0x04, 6400 }, + { 0x05, 3900 }, + { 0x06, 2700 }, + { 0x07, 2100 }, + { } +}; + +/* KXCTJ2-1009 */ +static const struct kx_odr_start_up_time kxtj21009_odr_start_up_times[] = { + { 0x08, 1240000 }, + { 0x09, 621000 }, + { 0x0A, 309000 }, + { 0x0B, 151000 }, + { 0x00, 80000 }, + { 0x01, 41000 }, + { 0x02, 21000 }, + { 0x03, 11000 }, + { 0x04, 6000 }, + { 0x05, 4000 }, + { 0x06, 3000 }, + { 0x07, 2000 }, + { } +}; + +/* KXTF9 */ +static const struct kx_odr_start_up_time kxtf9_odr_start_up_times[] = { + { 0x01, 81000 }, + { 0x02, 41000 }, + { 0x03, 21000 }, + { 0x04, 11000 }, + { 0x05, 5100 }, + { 0x06, 2700 }, + { } +}; + +/* KX023-1025 */ +static const struct kx_odr_start_up_time kx0231025_odr_start_up_times[] = { + /* First 4 are not in datasheet, taken from KXCTJ2-1009 */ + { 0x08, 1240000 }, + { 0x09, 621000 }, + { 0x0A, 309000 }, + { 0x0B, 151000 }, + { 0x00, 81000 }, + { 0x01, 40000 }, + { 0x02, 22000 }, + { 0x03, 12000 }, + { 0x04, 7000 }, + { 0x05, 4400 }, + { 0x06, 3000 }, + { 0x07, 3000 }, + { } }; enum kx_acpi_type { @@ -234,6 +295,55 @@ static const struct kx_chipset_regs kx0231025_regs = { .wake_thres = KX023_REG_ATH, }; +struct kx_chipset_info { + const struct kx_chipset_regs *regs; + const struct kx_odr_start_up_time *times; + enum kx_acpi_type acpi_type; +}; + +static const struct kx_chipset_info kxcjk1013_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), +}; + +static const struct kx_chipset_info kxcj91008_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), +}; + +static const struct kx_chipset_info kxcj91008_kiox010a_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), + .acpi_type = ACPI_KIOX010A, +}; + +static const struct kx_chipset_info kxcj91008_kiox020a_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), + .acpi_type = ACPI_GENERIC, +}; + +static const struct kx_chipset_info kxcj91008_smo8500_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxcjk1013_odr_start_up_times), + .acpi_type = ACPI_SMO8500, +}; + +static const struct kx_chipset_info kxtj21009_info = { + .regs = &kxcjk1013_regs, + .times = pm_ptr(kxtj21009_odr_start_up_times), +}; + +static const struct kx_chipset_info kxtf9_info = { + .regs = &kxtf9_regs, + .times = pm_ptr(kxtf9_odr_start_up_times), +}; + +static const struct kx_chipset_info kx0231025_info = { + .regs = &kx0231025_regs, + .times = pm_ptr(kx0231025_odr_start_up_times), +}; + enum kxcjk1013_axis { AXIS_X, AXIS_Y, @@ -250,7 +360,7 @@ struct kxcjk1013_data { /* Ensure timestamp naturally aligned */ struct { s16 chans[AXIS_MAX]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; u8 odr_bits; u8 range; @@ -261,9 +371,7 @@ struct kxcjk1013_data { int ev_enable_state; bool motion_trigger_on; int64_t timestamp; - enum kx_chipset chipset; - enum kx_acpi_type acpi_type; - const struct kx_chipset_regs *regs; + const struct kx_chipset_info *info; }; enum kxcjk1013_mode { @@ -314,83 +422,6 @@ static const struct kx_odr_map kxtf9_samp_freq_table[] = { static const char *const kxtf9_samp_freq_avail = "25 50 100 200 400 800"; -/* Refer to section 4 of the specification */ -static __maybe_unused const struct { - int odr_bits; - int usec; -} odr_start_up_times[KX_MAX_CHIPS][12] = { - /* KXCJK-1013 */ - { - {0x08, 100000}, - {0x09, 100000}, - {0x0A, 100000}, - {0x0B, 100000}, - {0, 80000}, - {0x01, 41000}, - {0x02, 21000}, - {0x03, 11000}, - {0x04, 6400}, - {0x05, 3900}, - {0x06, 2700}, - {0x07, 2100}, - }, - /* KXCJ9-1008 */ - { - {0x08, 100000}, - {0x09, 100000}, - {0x0A, 100000}, - {0x0B, 100000}, - {0, 80000}, - {0x01, 41000}, - {0x02, 21000}, - {0x03, 11000}, - {0x04, 6400}, - {0x05, 3900}, - {0x06, 2700}, - {0x07, 2100}, - }, - /* KXCTJ2-1009 */ - { - {0x08, 1240000}, - {0x09, 621000}, - {0x0A, 309000}, - {0x0B, 151000}, - {0, 80000}, - {0x01, 41000}, - {0x02, 21000}, - {0x03, 11000}, - {0x04, 6000}, - {0x05, 4000}, - {0x06, 3000}, - {0x07, 2000}, - }, - /* KXTF9 */ - { - {0x01, 81000}, - {0x02, 41000}, - {0x03, 21000}, - {0x04, 11000}, - {0x05, 5100}, - {0x06, 2700}, - }, - /* KX023-1025 */ - { - /* First 4 are not in datasheet, taken from KXCTJ2-1009 */ - {0x08, 1240000}, - {0x09, 621000}, - {0x0A, 309000}, - {0x0B, 151000}, - {0, 81000}, - {0x01, 40000}, - {0x02, 22000}, - {0x03, 12000}, - {0x04, 7000}, - {0x05, 4400}, - {0x06, 3000}, - {0x07, 3000}, - }, -}; - static const struct { u16 scale; u8 gsel_0; @@ -424,30 +455,15 @@ static int kiox010a_dsm(struct device *dev, int fn_index) return 0; } -static const struct acpi_device_id kx_acpi_match[] = { - {"KXCJ1013", KXCJK1013}, - {"KXCJ1008", KXCJ91008}, - {"KXCJ9000", KXCJ91008}, - {"KIOX0008", KXCJ91008}, - {"KIOX0009", KXTJ21009}, - {"KIOX000A", KXCJ91008}, - {"KIOX010A", KXCJ91008}, /* KXCJ91008 in the display of a yoga 2-in-1 */ - {"KIOX020A", KXCJ91008}, /* KXCJ91008 in the base of a yoga 2-in-1 */ - {"KXTJ1009", KXTJ21009}, - {"KXJ2109", KXTJ21009}, - {"SMO8500", KXCJ91008}, - { } -}; -MODULE_DEVICE_TABLE(acpi, kx_acpi_match); - #endif static int kxcjk1013_set_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode mode) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -458,7 +474,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, else ret |= KXCJK1013_REG_CTRL1_BIT_PC1; - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -470,9 +486,10 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, static int kxcjk1013_get_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode *mode) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -488,9 +505,10 @@ static int kxcjk1013_get_mode(struct kxcjk1013_data *data, static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -501,7 +519,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3); ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4); - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -514,10 +532,11 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) static int kxcjk1013_chip_init(struct kxcjk1013_data *data) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; #ifdef CONFIG_ACPI - if (data->acpi_type == ACPI_KIOX010A) { + if (data->info->acpi_type == ACPI_KIOX010A) { /* Make sure the kbd and touchpad on 2-in-1s using 2 KXCJ91008-s work */ kiox010a_dsm(&data->client->dev, KIOX010A_SET_LAPTOP_MODE); } @@ -535,7 +554,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -544,7 +563,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) /* Set 12 bit mode */ ret |= KXCJK1013_REG_CTRL1_BIT_RES; - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl\n"); return ret; @@ -555,7 +574,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->data_ctrl); + ret = i2c_smbus_read_byte_data(data->client, regs->data_ctrl); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_data_ctrl\n"); return ret; @@ -564,7 +583,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) data->odr_bits = ret; /* Set up INT polarity */ - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); return ret; @@ -575,14 +594,14 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) else ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEA; - ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); return ret; } - /* On KX023 and KX022, route all used interrupts to INT1 for now */ - if ((data->chipset == KX0231025 || data->chipset == KX0221020) && data->client->irq > 0) { + /* On KX023, route all used interrupts to INT1 for now */ + if (data->info == &kx0231025_info && data->client->irq > 0) { ret = i2c_smbus_write_byte_data(data->client, KX023_REG_INC4, KX023_REG_INC4_DRDY1 | KX023_REG_INC4_WUFI1); @@ -601,20 +620,17 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return 0; } -#ifdef CONFIG_PM static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) { - int i; - int idx = data->chipset; + const struct kx_odr_start_up_time *times; - for (i = 0; i < ARRAY_SIZE(odr_start_up_times[idx]); ++i) { - if (odr_start_up_times[idx][i].odr_bits == data->odr_bits) - return odr_start_up_times[idx][i].usec; + for (times = data->info->times; times->usec; times++) { + if (times->odr_bits == data->odr_bits) + return times->usec; } return KXCJK1013_MAX_STARTUP_TIME_US; } -#endif static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) { @@ -639,18 +655,17 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_timer, - data->wake_dur); + ret = i2c_smbus_write_byte_data(data->client, regs->wake_timer, data->wake_dur); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_wake_timer\n"); return ret; } - ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_thres, - data->wake_thres); + ret = i2c_smbus_write_byte_data(data->client, regs->wake_thres, data->wake_thres); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_wake_thres\n"); return ret; @@ -662,6 +677,7 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, bool status) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; enum kxcjk1013_mode store_mode; @@ -678,7 +694,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); return ret; @@ -689,13 +705,13 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN; - ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); return ret; } - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -706,7 +722,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE; - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -724,6 +740,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, bool status) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; enum kxcjk1013_mode store_mode; @@ -736,7 +753,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, if (ret < 0) return ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->int_ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); return ret; @@ -747,13 +764,13 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN; - ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->int_ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); return ret; } - ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1); + ret = i2c_smbus_read_byte_data(data->client, regs->ctrl1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); return ret; @@ -764,7 +781,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, else ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; - ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret); + ret = i2c_smbus_write_byte_data(data->client, regs->ctrl1, ret); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); return ret; @@ -811,6 +828,7 @@ static int kxcjk1013_convert_odr_value(const struct kx_odr_map *map, static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) { + const struct kx_chipset_regs *regs = data->info->regs; int ret; enum kxcjk1013_mode store_mode; const struct kx_odr_map *odr_setting; @@ -819,7 +837,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) if (ret < 0) return ret; - if (data->chipset == KXTF9) + if (data->info == &kxtf9_info) odr_setting = kxcjk1013_find_odr_value(kxtf9_samp_freq_table, ARRAY_SIZE(kxtf9_samp_freq_table), val, val2); @@ -836,7 +854,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) if (ret < 0) return ret; - ret = i2c_smbus_write_byte_data(data->client, data->regs->data_ctrl, + ret = i2c_smbus_write_byte_data(data->client, regs->data_ctrl, odr_setting->odr_bits); if (ret < 0) { dev_err(&data->client->dev, "Error writing data_ctrl\n"); @@ -845,7 +863,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) data->odr_bits = odr_setting->odr_bits; - ret = i2c_smbus_write_byte_data(data->client, data->regs->wuf_ctrl, + ret = i2c_smbus_write_byte_data(data->client, regs->wuf_ctrl, odr_setting->wuf_bits); if (ret < 0) { dev_err(&data->client->dev, "Error writing reg_ctrl2\n"); @@ -863,7 +881,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) static int kxcjk1013_get_odr(struct kxcjk1013_data *data, int *val, int *val2) { - if (data->chipset == KXTF9) + if (data->info == &kxtf9_info) return kxcjk1013_convert_odr_value(kxtf9_samp_freq_table, ARRAY_SIZE(kxtf9_samp_freq_table), data->odr_bits, val, val2); @@ -1063,7 +1081,7 @@ static int kxcjk1013_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) + bool state) { struct kxcjk1013_data *data = iio_priv(indio_dev); int ret; @@ -1130,7 +1148,7 @@ static ssize_t kxcjk1013_get_samp_freq_avail(struct device *dev, struct kxcjk1013_data *data = iio_priv(indio_dev); const char *str; - if (data->chipset == KXTF9) + if (data->info == &kxtf9_info) str = kxtf9_samp_freq_avail; else str = kxcjk1013_samp_freq_avail; @@ -1207,7 +1225,7 @@ static const struct iio_buffer_setup_ops kxcjk1013_buffer_setup_ops = { .postdisable = kxcjk1013_buffer_postdisable, }; -static const struct iio_info kxcjk1013_info = { +static const struct iio_info kxcjk1013_iio_info = { .attrs = &kxcjk1013_attrs_group, .read_raw = kxcjk1013_read_raw, .write_raw = kxcjk1013_write_raw, @@ -1247,9 +1265,10 @@ static void kxcjk1013_trig_reen(struct iio_trigger *trig) { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct kxcjk1013_data *data = iio_priv(indio_dev); + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel); + ret = i2c_smbus_read_byte_data(data->client, regs->int_rel); if (ret < 0) dev_err(&data->client->dev, "Error reading reg_int_rel\n"); } @@ -1301,8 +1320,9 @@ static const struct iio_trigger_ops kxcjk1013_trigger_ops = { static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev) { struct kxcjk1013_data *data = iio_priv(indio_dev); + const struct kx_chipset_regs *regs = data->info->regs; - int ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src2); + int ret = i2c_smbus_read_byte_data(data->client, regs->int_src2); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_src2\n"); return; @@ -1367,16 +1387,17 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct kxcjk1013_data *data = iio_priv(indio_dev); + const struct kx_chipset_regs *regs = data->info->regs; int ret; - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src1); + ret = i2c_smbus_read_byte_data(data->client, regs->int_src1); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_int_src1\n"); goto ack_intr; } if (ret & KXCJK1013_REG_INT_SRC1_BIT_WUFS) { - if (data->chipset == KXTF9) + if (data->info == &kxtf9_info) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, @@ -1392,7 +1413,7 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private) if (data->dready_trigger_on) return IRQ_HANDLED; - ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel); + ret = i2c_smbus_read_byte_data(data->client, regs->int_rel); if (ret < 0) dev_err(&data->client->dev, "Error reading reg_int_rel\n"); @@ -1417,31 +1438,6 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } -static const char *kxcjk1013_match_acpi_device(struct device *dev, - enum kx_chipset *chipset, - enum kx_acpi_type *acpi_type, - const char **label) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - - if (strcmp(id->id, "SMO8500") == 0) { - *acpi_type = ACPI_SMO8500; - } else if (strcmp(id->id, "KIOX010A") == 0) { - *acpi_type = ACPI_KIOX010A; - *label = "accel-display"; - } else if (strcmp(id->id, "KIOX020A") == 0) { - *label = "accel-base"; - } - - *chipset = (enum kx_chipset)id->driver_data; - - return dev_name(dev); -} - static int kxcjk1013_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -1449,6 +1445,7 @@ static int kxcjk1013_probe(struct i2c_client *client) struct kxcjk1013_data *data; struct iio_dev *indio_dev; struct kxcjk_1013_platform_data *pdata; + const void *ddata = NULL; const char *name; int ret; @@ -1489,32 +1486,18 @@ static int kxcjk1013_probe(struct i2c_client *client) msleep(20); if (id) { - data->chipset = (enum kx_chipset)(id->driver_data); name = id->name; - } else if (ACPI_HANDLE(&client->dev)) { - name = kxcjk1013_match_acpi_device(&client->dev, - &data->chipset, - &data->acpi_type, - &indio_dev->label); - } else - return -ENODEV; - - switch (data->chipset) { - case KXCJK1013: - case KXCJ91008: - case KXTJ21009: - data->regs = &kxcjk1013_regs; - break; - case KXTF9: - data->regs = &kxtf9_regs; - break; - case KX0221020: - case KX0231025: - data->regs = &kx0231025_regs; - break; - default: - return -EINVAL; + data->info = (const struct kx_chipset_info *)(id->driver_data); + } else { + name = iio_get_acpi_device_name_and_data(&client->dev, &ddata); + data->info = ddata; + if (data->info == &kxcj91008_kiox010a_info) + indio_dev->label = "accel-display"; + else if (data->info == &kxcj91008_kiox020a_info) + indio_dev->label = "accel-base"; } + if (!name) + return -ENODEV; ret = kxcjk1013_chip_init(data); if (ret < 0) @@ -1527,9 +1510,9 @@ static int kxcjk1013_probe(struct i2c_client *client) indio_dev->available_scan_masks = kxcjk1013_scan_masks; indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->info = &kxcjk1013_info; + indio_dev->info = &kxcjk1013_iio_info; - if (client->irq > 0 && data->acpi_type != ACPI_SMO8500) { + if (client->irq > 0 && data->info->acpi_type != ACPI_SMO8500) { ret = devm_request_threaded_irq(&client->dev, client->irq, kxcjk1013_data_rdy_trig_poll, kxcjk1013_event_handler, @@ -1637,7 +1620,6 @@ static void kxcjk1013_remove(struct i2c_client *client) mutex_unlock(&data->mutex); } -#ifdef CONFIG_PM_SLEEP static int kxcjk1013_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1665,9 +1647,7 @@ static int kxcjk1013_resume(struct device *dev) return ret; } -#endif -#ifdef CONFIG_PM static int kxcjk1013_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -1701,44 +1681,56 @@ static int kxcjk1013_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops kxcjk1013_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume) - SET_RUNTIME_PM_OPS(kxcjk1013_runtime_suspend, - kxcjk1013_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume) + RUNTIME_PM_OPS(kxcjk1013_runtime_suspend, kxcjk1013_runtime_resume, NULL) }; static const struct i2c_device_id kxcjk1013_id[] = { - {"kxcjk1013", KXCJK1013}, - {"kxcj91008", KXCJ91008}, - {"kxtj21009", KXTJ21009}, - {"kxtf9", KXTF9}, - {"kx022-1020", KX0221020}, - {"kx023-1025", KX0231025}, - {"SMO8500", KXCJ91008}, - {} + { "kxcjk1013", (kernel_ulong_t)&kxcjk1013_info }, + { "kxcj91008", (kernel_ulong_t)&kxcj91008_info }, + { "kxtj21009", (kernel_ulong_t)&kxtj21009_info }, + { "kxtf9", (kernel_ulong_t)&kxtf9_info }, + { "kx023-1025", (kernel_ulong_t)&kx0231025_info }, + { } }; - MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); static const struct of_device_id kxcjk1013_of_match[] = { - { .compatible = "kionix,kxcjk1013", }, - { .compatible = "kionix,kxcj91008", }, - { .compatible = "kionix,kxtj21009", }, - { .compatible = "kionix,kxtf9", }, - { .compatible = "kionix,kx022-1020", }, - { .compatible = "kionix,kx023-1025", }, + { .compatible = "kionix,kxcjk1013", &kxcjk1013_info }, + { .compatible = "kionix,kxcj91008", &kxcj91008_info }, + { .compatible = "kionix,kxtj21009", &kxtj21009_info }, + { .compatible = "kionix,kxtf9", &kxtf9_info }, + { .compatible = "kionix,kx023-1025", &kx0231025_info }, { } }; MODULE_DEVICE_TABLE(of, kxcjk1013_of_match); +static const struct acpi_device_id kx_acpi_match[] = { + { "KIOX0008", (kernel_ulong_t)&kxcj91008_info }, + { "KIOX0009", (kernel_ulong_t)&kxtj21009_info }, + { "KIOX000A", (kernel_ulong_t)&kxcj91008_info }, + /* KXCJ91008 in the display of a yoga 2-in-1 */ + { "KIOX010A", (kernel_ulong_t)&kxcj91008_kiox010a_info }, + /* KXCJ91008 in the base of a yoga 2-in-1 */ + { "KIOX020A", (kernel_ulong_t)&kxcj91008_kiox020a_info }, + { "KXCJ1008", (kernel_ulong_t)&kxcj91008_info }, + { "KXCJ1013", (kernel_ulong_t)&kxcjk1013_info }, + { "KXCJ9000", (kernel_ulong_t)&kxcj91008_info }, + { "KXJ2109", (kernel_ulong_t)&kxtj21009_info }, + { "KXTJ1009", (kernel_ulong_t)&kxtj21009_info }, + { "SMO8500", (kernel_ulong_t)&kxcj91008_smo8500_info }, + { } +}; +MODULE_DEVICE_TABLE(acpi, kx_acpi_match); + static struct i2c_driver kxcjk1013_driver = { .driver = { .name = KXCJK1013_DRV_NAME, - .acpi_match_table = ACPI_PTR(kx_acpi_match), + .acpi_match_table = kx_acpi_match, .of_match_table = kxcjk1013_of_match, - .pm = &kxcjk1013_pm_ops, + .pm = pm_ptr(&kxcjk1013_pm_ops), }, .probe = kxcjk1013_probe, .remove = kxcjk1013_remove, diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index c4c7e2d4e98ad9..3857d2edf25075 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -62,4 +62,4 @@ module_i2c_driver(kxsd9_i2c_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("KXSD9 accelerometer I2C interface"); -MODULE_IMPORT_NS(IIO_KXSD9); +MODULE_IMPORT_NS("IIO_KXSD9"); diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c index 4414670dfb436b..a05f4467d94a4a 100644 --- a/drivers/iio/accel/kxsd9-spi.c +++ b/drivers/iio/accel/kxsd9-spi.c @@ -63,4 +63,4 @@ module_spi_driver(kxsd9_spi_driver); MODULE_AUTHOR("Jonathan Cameron "); MODULE_DESCRIPTION("Kionix KXSD9 SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_KXSD9); +MODULE_IMPORT_NS("IIO_KXSD9"); diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 70dfd6e354dbbb..0ededf8cfdca6b 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -215,7 +216,7 @@ static irqreturn_t kxsd9_trigger_handler(int irq, void *p) */ struct { __be16 chan[4]; - s64 ts __aligned(8); + aligned_s64 ts; } hw_values; int ret; @@ -473,7 +474,7 @@ int kxsd9_common_probe(struct device *dev, return ret; } -EXPORT_SYMBOL_NS(kxsd9_common_probe, IIO_KXSD9); +EXPORT_SYMBOL_NS(kxsd9_common_probe, "IIO_KXSD9"); void kxsd9_common_remove(struct device *dev) { @@ -487,7 +488,7 @@ void kxsd9_common_remove(struct device *dev) pm_runtime_disable(dev); kxsd9_power_down(st); } -EXPORT_SYMBOL_NS(kxsd9_common_remove, IIO_KXSD9); +EXPORT_SYMBOL_NS(kxsd9_common_remove, "IIO_KXSD9"); static int kxsd9_runtime_suspend(struct device *dev) { diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c index a34195b3215ddb..30746621052c7e 100644 --- a/drivers/iio/accel/mma7455_core.c +++ b/drivers/iio/accel/mma7455_core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "mma7455.h" @@ -58,7 +59,7 @@ struct mma7455_data { */ struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan; }; @@ -238,7 +239,7 @@ const struct regmap_config mma7455_core_regmap = { .val_bits = 8, .max_register = MMA7455_REG_TW, }; -EXPORT_SYMBOL_NS_GPL(mma7455_core_regmap, IIO_MMA7455); +EXPORT_SYMBOL_NS_GPL(mma7455_core_regmap, "IIO_MMA7455"); int mma7455_core_probe(struct device *dev, struct regmap *regmap, const char *name) @@ -293,7 +294,7 @@ int mma7455_core_probe(struct device *dev, struct regmap *regmap, return 0; } -EXPORT_SYMBOL_NS_GPL(mma7455_core_probe, IIO_MMA7455); +EXPORT_SYMBOL_NS_GPL(mma7455_core_probe, "IIO_MMA7455"); void mma7455_core_remove(struct device *dev) { @@ -306,7 +307,7 @@ void mma7455_core_remove(struct device *dev) regmap_write(mma7455->regmap, MMA7455_REG_MCTL, MMA7455_MCTL_MODE_STANDBY); } -EXPORT_SYMBOL_NS_GPL(mma7455_core_remove, IIO_MMA7455); +EXPORT_SYMBOL_NS_GPL(mma7455_core_remove, "IIO_MMA7455"); MODULE_AUTHOR("Joachim Eastwood "); MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver"); diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c index 36a357c8e9ed59..2ff8eb1f9ce960 100644 --- a/drivers/iio/accel/mma7455_i2c.c +++ b/drivers/iio/accel/mma7455_i2c.c @@ -59,4 +59,4 @@ module_i2c_driver(mma7455_i2c_driver); MODULE_AUTHOR("Joachim Eastwood "); MODULE_DESCRIPTION("Freescale MMA7455L I2C accelerometer driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MMA7455); +MODULE_IMPORT_NS("IIO_MMA7455"); diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c index fcdde2e8a84b2a..aca02e83f789d3 100644 --- a/drivers/iio/accel/mma7455_spi.c +++ b/drivers/iio/accel/mma7455_spi.c @@ -47,4 +47,4 @@ module_spi_driver(mma7455_spi_driver); MODULE_AUTHOR("Joachim Eastwood "); MODULE_DESCRIPTION("Freescale MMA7455L SPI accelerometer driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MMA7455); +MODULE_IMPORT_NS("IIO_MMA7455"); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 62e6369e22696c..962d289065ab7b 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -32,6 +32,7 @@ #include #include #include +#include #define MMA8452_STATUS 0x00 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) @@ -115,7 +116,7 @@ struct mma8452_data { /* Ensure correct alignment of time stamp when present */ struct { __be16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } buffer; }; @@ -973,7 +974,7 @@ static int mma8452_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) + bool state) { struct mma8452_data *data = iio_priv(indio_dev); int val, ret; diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index fa1799b0b0dff3..1b96687da01a69 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -4,11 +4,11 @@ * Copyright (c) 2014, Intel Corporation. */ -#include #include #include +#include +#include #include -#include #include #include #include @@ -45,7 +45,7 @@ enum mma9551_tilt_axis { struct mma9551_data { struct i2c_client *client; struct mutex mutex; - int event_enabled[3]; + bool event_enabled[3]; int irqs[MMA9551_GPIO_COUNT]; }; @@ -162,7 +162,7 @@ static int mma9551_read_event_config(struct iio_dev *indio_dev, static int mma9551_config_incli_event(struct iio_dev *indio_dev, enum iio_modifier axis, - int state) + bool state) { struct mma9551_data *data = iio_priv(indio_dev); enum mma9551_tilt_axis mma_axis; @@ -174,7 +174,7 @@ static int mma9551_config_incli_event(struct iio_dev *indio_dev, if (data->event_enabled[mma_axis] == state) return 0; - if (state == 0) { + if (!state) { ret = mma9551_gpio_config(data->client, (enum mma9551_gpio_pin)mma_axis, MMA9551_APPID_NONE, 0, 0); @@ -225,7 +225,7 @@ static int mma9551_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) + bool state) { struct mma9551_data *data = iio_priv(indio_dev); int ret; @@ -435,17 +435,6 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev) return 0; } -static const char *mma9551_match_acpi_device(struct device *dev) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - - return dev_name(dev); -} - static int mma9551_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -464,8 +453,8 @@ static int mma9551_probe(struct i2c_client *client) if (id) name = id->name; - else if (ACPI_HANDLE(&client->dev)) - name = mma9551_match_acpi_device(&client->dev); + else + name = iio_get_acpi_device_name(&client->dev); ret = mma9551_init(data); if (ret < 0) @@ -618,4 +607,4 @@ MODULE_AUTHOR("Irina Tirdea "); MODULE_AUTHOR("Vlad Dogaru "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver"); -MODULE_IMPORT_NS(IIO_MMA9551); +MODULE_IMPORT_NS("IIO_MMA9551"); diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index b898f865fb8759..3e7d9b79ed0ee9 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -219,7 +219,7 @@ int mma9551_read_config_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, reg, NULL, 0, val, 1); } -EXPORT_SYMBOL_NS(mma9551_read_config_byte, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_config_byte, "IIO_MMA9551"); /** * mma9551_write_config_byte() - write 1 configuration byte @@ -244,7 +244,7 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, &val, 1, NULL, 0); } -EXPORT_SYMBOL_NS(mma9551_write_config_byte, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_write_config_byte, "IIO_MMA9551"); /** * mma9551_read_status_byte() - read 1 status byte @@ -269,7 +269,7 @@ int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, reg, NULL, 0, val, 1); } -EXPORT_SYMBOL_NS(mma9551_read_status_byte, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_status_byte, "IIO_MMA9551"); /** * mma9551_read_config_word() - read 1 config word @@ -303,7 +303,7 @@ int mma9551_read_config_word(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL_NS(mma9551_read_config_word, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_config_word, "IIO_MMA9551"); /** * mma9551_write_config_word() - write 1 config word @@ -330,7 +330,7 @@ int mma9551_write_config_word(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, (u8 *)&v, 2, NULL, 0); } -EXPORT_SYMBOL_NS(mma9551_write_config_word, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_write_config_word, "IIO_MMA9551"); /** * mma9551_read_status_word() - read 1 status word @@ -364,7 +364,7 @@ int mma9551_read_status_word(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL_NS(mma9551_read_status_word, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_status_word, "IIO_MMA9551"); /** * mma9551_read_config_words() - read multiple config words @@ -403,7 +403,7 @@ int mma9551_read_config_words(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL_NS(mma9551_read_config_words, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_config_words, "IIO_MMA9551"); /** * mma9551_read_status_words() - read multiple status words @@ -442,7 +442,7 @@ int mma9551_read_status_words(struct i2c_client *client, u8 app_id, return 0; } -EXPORT_SYMBOL_NS(mma9551_read_status_words, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_status_words, "IIO_MMA9551"); /** * mma9551_write_config_words() - write multiple config words @@ -477,7 +477,7 @@ int mma9551_write_config_words(struct i2c_client *client, u8 app_id, return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, (u8 *)be_buf, len * sizeof(u16), NULL, 0); } -EXPORT_SYMBOL_NS(mma9551_write_config_words, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_write_config_words, "IIO_MMA9551"); /** * mma9551_update_config_bits() - update bits in register @@ -513,7 +513,7 @@ int mma9551_update_config_bits(struct i2c_client *client, u8 app_id, return mma9551_write_config_byte(client, app_id, reg, tmp); } -EXPORT_SYMBOL_NS(mma9551_update_config_bits, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_update_config_bits, "IIO_MMA9551"); /** * mma9551_gpio_config() - configure gpio @@ -592,7 +592,7 @@ int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin, return ret; } -EXPORT_SYMBOL_NS(mma9551_gpio_config, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_gpio_config, "IIO_MMA9551"); /** * mma9551_read_version() - read device version information @@ -622,7 +622,7 @@ int mma9551_read_version(struct i2c_client *client) return 0; } -EXPORT_SYMBOL_NS(mma9551_read_version, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_version, "IIO_MMA9551"); /** * mma9551_set_device_state() - sets HW power mode @@ -652,7 +652,7 @@ int mma9551_set_device_state(struct i2c_client *client, bool enable) MMA9551_SLEEP_CFG_FLEEN : MMA9551_SLEEP_CFG_SNCEN); } -EXPORT_SYMBOL_NS(mma9551_set_device_state, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_set_device_state, "IIO_MMA9551"); /** * mma9551_set_power_state() - sets runtime PM state @@ -686,7 +686,7 @@ int mma9551_set_power_state(struct i2c_client *client, bool on) return 0; } -EXPORT_SYMBOL_NS(mma9551_set_power_state, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_set_power_state, "IIO_MMA9551"); /** * mma9551_sleep() - sleep @@ -705,7 +705,7 @@ void mma9551_sleep(int freq) else msleep_interruptible(sleep_val); } -EXPORT_SYMBOL_NS(mma9551_sleep, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_sleep, "IIO_MMA9551"); /** * mma9551_read_accel_chan() - read accelerometer channel @@ -761,7 +761,7 @@ int mma9551_read_accel_chan(struct i2c_client *client, mma9551_set_power_state(client, false); return ret; } -EXPORT_SYMBOL_NS(mma9551_read_accel_chan, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_accel_chan, "IIO_MMA9551"); /** * mma9551_read_accel_scale() - read accelerometer scale @@ -779,7 +779,7 @@ int mma9551_read_accel_scale(int *val, int *val2) return IIO_VAL_INT_PLUS_MICRO; } -EXPORT_SYMBOL_NS(mma9551_read_accel_scale, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_read_accel_scale, "IIO_MMA9551"); /** * mma9551_app_reset() - reset application @@ -798,7 +798,7 @@ int mma9551_app_reset(struct i2c_client *client, u32 app_mask) MMA9551_RSC_OFFSET(app_mask), MMA9551_RSC_VAL(app_mask)); } -EXPORT_SYMBOL_NS(mma9551_app_reset, IIO_MMA9551); +EXPORT_SYMBOL_NS(mma9551_app_reset, "IIO_MMA9551"); MODULE_AUTHOR("Irina Tirdea "); MODULE_AUTHOR("Vlad Dogaru "); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 86543f34ef17cf..00e224efc8ed2d 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -4,11 +4,11 @@ * Copyright (c) 2014, Intel Corporation. */ -#include #include #include +#include +#include #include -#include #include #include #include @@ -725,7 +725,8 @@ static int mma9553_read_event_config(struct iio_dev *indio_dev, static int mma9553_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) + enum iio_event_direction dir, + bool state) { struct mma9553_data *data = iio_priv(indio_dev); struct mma9553_event *event; @@ -1030,9 +1031,9 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) { data->stepcnt = stepcnt; iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD, - IIO_EV_DIR_NONE, - IIO_EV_TYPE_CHANGE, 0, 0, 0), + IIO_UNMOD_EVENT_CODE(IIO_STEPS, 0, + IIO_EV_TYPE_CHANGE, + IIO_EV_DIR_NONE), data->timestamp); } @@ -1041,20 +1042,18 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) /* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */ if (ev_prev_activity && ev_prev_activity->enabled) iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_ACTIVITY, 0, - ev_prev_activity->info->mod, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, 0, 0, - 0), + IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0, + ev_prev_activity->info->mod, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), data->timestamp); if (ev_activity && ev_activity->enabled) iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_ACTIVITY, 0, - ev_activity->info->mod, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, 0, 0, - 0), + IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0, + ev_activity->info->mod, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), data->timestamp); } mutex_unlock(&data->mutex); @@ -1062,17 +1061,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) return IRQ_HANDLED; } -static const char *mma9553_match_acpi_device(struct device *dev) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - - return dev_name(dev); -} - static int mma9553_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -1091,9 +1079,9 @@ static int mma9553_probe(struct i2c_client *client) if (id) name = id->name; - else if (ACPI_HANDLE(&client->dev)) - name = mma9553_match_acpi_device(&client->dev); else + name = iio_get_acpi_device_name(&client->dev); + if (!name) return -ENOSYS; mutex_init(&data->mutex); @@ -1256,4 +1244,4 @@ module_i2c_driver(mma9553_driver); MODULE_AUTHOR("Irina Tirdea "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MMA9553L pedometer platform driver"); -MODULE_IMPORT_NS(IIO_MMA9551); +MODULE_IMPORT_NS("IIO_MMA9551"); diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 57025354c7cd58..e7fb860f32337c 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -893,7 +894,7 @@ static irqreturn_t msa311_buffer_thread(int irq, void *p) __le16 axis; struct { __le16 channels[MSA311_SI_Z + 1]; - s64 ts __aligned(8); + aligned_s64 ts; } buf; memset(&buf, 0, sizeof(buf)); diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index fc54a2a4693c0a..cb5c4e354fc044 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,7 @@ struct mxc4005_data { /* Ensure timestamp is naturally aligned */ struct { __be16 chans[3]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; bool trigger_enabled; unsigned int control; diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 87c54e41f6ccd2..3fb0f386c3db60 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -1158,7 +1158,7 @@ static int sca3000_read_event_config(struct iio_dev *indio_dev, return ret; } -static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) +static int sca3000_freefall_set_state(struct iio_dev *indio_dev, bool state) { struct sca3000_state *st = iio_priv(indio_dev); int ret; @@ -1181,7 +1181,7 @@ static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) } static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis, - int state) + bool state) { struct sca3000_state *st = iio_priv(indio_dev); int ret, ctrlval; @@ -1253,7 +1253,7 @@ static int sca3000_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) + bool state) { struct sca3000_state *st = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c index 7ca9d0d543e04c..3e572af2ec039b 100644 --- a/drivers/iio/accel/ssp_accel_sensor.c +++ b/drivers/iio/accel/ssp_accel_sensor.c @@ -141,4 +141,4 @@ module_platform_driver(ssp_accel_driver); MODULE_AUTHOR("Karol Wrona "); MODULE_DESCRIPTION("Samsung sensorhub accelerometers driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_SSP_SENSORS); +MODULE_IMPORT_NS("IIO_SSP_SENSORS"); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 0e371efbda705f..99cb661fabb2d9 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -1490,7 +1490,7 @@ const struct st_sensor_settings *st_accel_get_settings(const char *name) return &st_accel_sensors_settings[index]; } -EXPORT_SYMBOL_NS(st_accel_get_settings, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_accel_get_settings, "IIO_ST_SENSORS"); int st_accel_common_probe(struct iio_dev *indio_dev) { @@ -1544,9 +1544,9 @@ int st_accel_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL_NS(st_accel_common_probe, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_accel_common_probe, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics accelerometers driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 329a4d6fb2ec0b..ab4fdba75a0a90 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -216,4 +216,4 @@ module_i2c_driver(st_accel_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics accelerometers i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 825adab371059d..6146754fe47f70 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -184,4 +184,4 @@ module_spi_driver(st_accel_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics accelerometers spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index abead190254b5a..471c154c3631b0 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -105,7 +106,7 @@ struct stk8312_data { /* Ensure timestamp is naturally aligned */ struct { s8 chans[3]; - s64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; }; diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index a32a77324e92d0..cab592a6862256 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -94,7 +95,7 @@ struct stk8ba50_data { /* Ensure timestamp is naturally aligned */ struct { s16 chans[3]; - s64 timetamp __aligned(8); + aligned_s64 timetamp; } scan; }; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 6c4e74420fd25b..849c90203071a7 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -226,12 +226,14 @@ config AD7606_IFACE_PARALLEL tristate "Analog Devices AD7606 ADC driver with parallel interface support" depends on HAS_IOPORT select AD7606 + select IIO_BACKEND help Say yes here to build parallel interface support for Analog Devices: ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). + It also support iio_backended devices for AD7606B. To compile this driver as a module, choose M here: the - module will be called ad7606_parallel. + module will be called ad7606_par. config AD7606_IFACE_SPI tristate "Analog Devices AD7606 ADC driver with spi interface support" @@ -244,6 +246,22 @@ config AD7606_IFACE_SPI To compile this driver as a module, choose M here: the module will be called ad7606_spi. +config AD7625 + tristate "Analog Devices AD7625/AD7626 High Speed ADC driver" + depends on PWM + select IIO_BACKEND + help + Say yes here to build support for Analog Devices: + * AD7625 16-Bit, 6 MSPS PulSAR Analog-to-Digital Converter + * AD7626 16-Bit, 10 MSPS PulSAR Analog-to-Digital Converter + * AD7960 18-Bit, 5 MSPS PulSAR Analog-to-Digital Converter + * AD7961 16-Bit, 5 MSPS PulSAR Analog-to-Digital Converter + + The driver requires the assistance of the AXI ADC IP core to operate. + + To compile this driver as a module, choose M here: the module will be + called ad7625. + config AD7766 tristate "Analog Devices AD7766/AD7767 ADC driver" depends on SPI_MASTER @@ -269,6 +287,18 @@ config AD7768_1 To compile this driver as a module, choose M here: the module will be called ad7768-1. +config AD7779 + tristate "Analog Devices AD7779 ADC driver" + depends on SPI + select CRC8 + select IIO_BUFFER + help + Say yes here to build support for Analog Devices AD777X family + (AD7770, AD7771, AD7779) analog to digital converter (ADC). + + To compile this driver as a module, choose M here: the module will be + called ad7779. + config AD7780 tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI @@ -575,6 +605,16 @@ config FSL_MX25_ADC Generic Conversion Queue driver used for general purpose ADC in the MX25. This driver supports single measurements using the MX25 ADC. +config GEHC_PMC_ADC + tristate "GE HealthCare PMC ADC driver" + depends on I2C + help + Say yes here to build support for the GE HealthCare PMC 16-bit + 16-Channel ADC. + + To compile this driver as a module, choose M here: the module will be + called gehc-pmc-adc. + config HI8435 tristate "Holt Integrated Circuits HI-8435 threshold detector" select IIO_TRIGGERED_EVENT @@ -1580,7 +1620,6 @@ config TWL4030_MADC config TWL6030_GPADC tristate "TWL6030 GPADC (General Purpose A/D Converter) Support" depends on TWL4030_CORE - default n help Say yes here if you want support for the TWL6030/TWL6032 General Purpose A/D Converter. This will add support for battery type diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 7b91cd98c0e0bd..ee19afba62b7fe 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -25,8 +25,10 @@ obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o obj-$(CONFIG_AD7606) += ad7606.o +obj-$(CONFIG_AD7625) += ad7625.o obj-$(CONFIG_AD7766) += ad7766.o obj-$(CONFIG_AD7768_1) += ad7768-1.o +obj-$(CONFIG_AD7779) += ad7779.o obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o @@ -52,6 +54,7 @@ obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o +obj-$(CONFIG_GEHC_PMC_ADC) += gehc-pmc-adc.o obj-$(CONFIG_HI8435) += hi8435.o obj-$(CONFIG_HX711) += hx711.o obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c index 59f66e9cb0e867..f3b057f9231004 100644 --- a/drivers/iio/adc/ab8500-gpadc.c +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -1194,7 +1194,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ab8500_gpadc_pm_ops, static struct platform_driver ab8500_gpadc_driver = { .probe = ab8500_gpadc_probe, - .remove_new = ab8500_gpadc_remove, + .remove = ab8500_gpadc_remove, .driver = { .name = "ab8500-gpadc", .pm = pm_ptr(&ab8500_gpadc_pm_ops), diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c index 6ea49124508499..b3b82535f5c14d 100644 --- a/drivers/iio/adc/ad4000.c +++ b/drivers/iio/adc/ad4000.c @@ -344,6 +344,8 @@ static int ad4000_single_conversion(struct iio_dev *indio_dev, if (chan->scan_type.sign == 's') *val = sign_extend32(sample, chan->scan_type.realbits - 1); + else + *val = sample; return IIO_VAL_INT; } @@ -637,7 +639,9 @@ static int ad4000_probe(struct spi_device *spi) indio_dev->name = chip->dev_name; indio_dev->num_channels = 1; - devm_mutex_init(dev, &st->lock); + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; st->gain_milli = 1000; if (chip->has_hardware_gain) { diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c index d6876259ad1449..606486c4dfe858 100644 --- a/drivers/iio/adc/ad7091r-base.c +++ b/drivers/iio/adc/ad7091r-base.c @@ -35,7 +35,7 @@ const struct iio_event_spec ad7091r_events[] = { .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS), }, }; -EXPORT_SYMBOL_NS_GPL(ad7091r_events, IIO_AD7091R); +EXPORT_SYMBOL_NS_GPL(ad7091r_events, "IIO_AD7091R"); static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel) { @@ -150,7 +150,8 @@ static int ad7091r_read_event_config(struct iio_dev *indio_dev, static int ad7091r_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) + enum iio_event_direction dir, + bool state) { struct ad7091r_state *st = iio_priv(indio_dev); @@ -369,7 +370,7 @@ int ad7091r_probe(struct device *dev, const struct ad7091r_init_info *init_info, return devm_iio_device_register(dev, iio_dev); } -EXPORT_SYMBOL_NS_GPL(ad7091r_probe, IIO_AD7091R); +EXPORT_SYMBOL_NS_GPL(ad7091r_probe, "IIO_AD7091R"); bool ad7091r_writeable_reg(struct device *dev, unsigned int reg) { @@ -381,7 +382,7 @@ bool ad7091r_writeable_reg(struct device *dev, unsigned int reg) return true; } } -EXPORT_SYMBOL_NS_GPL(ad7091r_writeable_reg, IIO_AD7091R); +EXPORT_SYMBOL_NS_GPL(ad7091r_writeable_reg, "IIO_AD7091R"); bool ad7091r_volatile_reg(struct device *dev, unsigned int reg) { @@ -393,7 +394,7 @@ bool ad7091r_volatile_reg(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(ad7091r_volatile_reg, IIO_AD7091R); +EXPORT_SYMBOL_NS_GPL(ad7091r_volatile_reg, "IIO_AD7091R"); MODULE_AUTHOR("Beniamin Bia "); MODULE_DESCRIPTION("Analog Devices AD7091Rx multi-channel converters"); diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h index 696bf7a897bb51..092ddea0f395c0 100644 --- a/drivers/iio/adc/ad7091r-base.h +++ b/drivers/iio/adc/ad7091r-base.h @@ -65,7 +65,7 @@ struct ad7091r_state { struct regulator *vref; const struct ad7091r_chip_info *chip_info; enum ad7091r_mode mode; - struct mutex lock; /*lock to prevent concurent reads */ + struct mutex lock; /*lock to prevent concurrent reads */ __be16 tx_buf __aligned(IIO_DMA_MINALIGN); __be16 rx_buf; }; diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c index 1b59708abf3076..b472b9498fd130 100644 --- a/drivers/iio/adc/ad7091r5.c +++ b/drivers/iio/adc/ad7091r5.c @@ -135,4 +135,4 @@ module_i2c_driver(ad7091r5_driver); MODULE_AUTHOR("Beniamin Bia "); MODULE_DESCRIPTION("Analog Devices AD7091R5 multi-channel ADC driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD7091R); +MODULE_IMPORT_NS("IIO_AD7091R"); diff --git a/drivers/iio/adc/ad7091r8.c b/drivers/iio/adc/ad7091r8.c index c9e014d6a77cae..cebade4c2d49ed 100644 --- a/drivers/iio/adc/ad7091r8.c +++ b/drivers/iio/adc/ad7091r8.c @@ -269,4 +269,4 @@ module_spi_driver(ad7091r8_driver); MODULE_AUTHOR("Marcelo Schmitt "); MODULE_DESCRIPTION("Analog Devices AD7091R8 ADC driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_AD7091R); +MODULE_IMPORT_NS("IIO_AD7091R"); diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index b79c48d46cccf8..7314fb32bdecb4 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -1036,4 +1036,4 @@ module_spi_driver(ad71124_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices AD7124 SPI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); +MODULE_IMPORT_NS("IIO_AD_SIGMA_DELTA"); diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index 0702ec71aa2933..8a0c931ca83a83 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -3,7 +3,7 @@ * AD717x and AD411x family SPI ADC driver * * Supported devices: - * AD4111/AD4112/AD4114/AD4115/AD4116 + * AD4111/AD4112/AD4113/AD4114/AD4115/AD4116 * AD7172-2/AD7172-4/AD7173-8/AD7175-2 * AD7175-8/AD7176-2/AD7177-2 * @@ -76,14 +76,15 @@ (x) == AD7173_AIN_REF_NEG) #define AD7172_2_ID 0x00d0 -#define AD7175_ID 0x0cd0 #define AD7176_ID 0x0c90 +#define AD7175_ID 0x0cd0 #define AD7175_2_ID 0x0cd0 #define AD7172_4_ID 0x2050 #define AD7173_ID 0x30d0 #define AD4111_ID AD7173_ID #define AD4112_ID AD7173_ID #define AD4114_ID AD7173_ID +#define AD4113_ID 0x31d0 #define AD4116_ID 0x34d0 #define AD4115_ID 0x38d0 #define AD7175_8_ID 0x3cd0 @@ -170,6 +171,7 @@ struct ad7173_device_info { bool has_temp; /* ((AVDD1 − AVSS)/5) */ bool has_pow_supply_monitoring; + bool data_reg_only_16bit; bool has_input_buf; bool has_int_ref; bool has_ref2; @@ -294,6 +296,24 @@ static const struct ad7173_device_info ad4112_device_info = { .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), }; +static const struct ad7173_device_info ad4113_device_info = { + .name = "ad4113", + .id = AD4113_ID, + .num_voltage_in_div = 8, + .num_channels = 16, + .num_configs = 8, + .num_voltage_in = 8, + .num_gpios = 2, + .data_reg_only_16bit = true, + .higher_gpio_bits = true, + .has_vincom_input = true, + .has_input_buf = true, + .has_int_ref = true, + .clock = 2 * HZ_PER_MHZ, + .sinc5_data_rates = ad7173_sinc5_data_rates, + .num_sinc5_data_rates = ARRAY_SIZE(ad7173_sinc5_data_rates), +}; + static const struct ad7173_device_info ad4114_device_info = { .name = "ad4114", .id = AD4114_ID, @@ -985,6 +1005,13 @@ static const struct iio_info ad7173_info = { .update_scan_mode = ad7173_update_scan_mode, }; +static const struct iio_scan_type ad4113_scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, +}; + static const struct iio_chan_spec ad7173_channel_template = { .type = IIO_VOLTAGE, .indexed = 1, @@ -1226,6 +1253,8 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) chan_st_priv->cfg.input_buf = st->info->has_input_buf; chan_st_priv->cfg.ref_sel = AD7173_SETUP_REF_SEL_INT_REF; st->adc_mode |= AD7173_ADC_MODE_REF_EN; + if (st->info->data_reg_only_16bit) + chan_arr[chan_index].scan_type = ad4113_scan_type; chan_index++; } @@ -1306,6 +1335,9 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev) chan_st_priv->ain = AD7173_CH_ADDRESS(ain[0], ain[1]); } + if (st->info->data_reg_only_16bit) + chan_arr[chan_index].scan_type = ad4113_scan_type; + chan_index++; } return 0; @@ -1434,6 +1466,7 @@ static int ad7173_probe(struct spi_device *spi) static const struct of_device_id ad7173_of_match[] = { { .compatible = "adi,ad4111", .data = &ad4111_device_info }, { .compatible = "adi,ad4112", .data = &ad4112_device_info }, + { .compatible = "adi,ad4113", .data = &ad4113_device_info }, { .compatible = "adi,ad4114", .data = &ad4114_device_info }, { .compatible = "adi,ad4115", .data = &ad4115_device_info }, { .compatible = "adi,ad4116", .data = &ad4116_device_info }, @@ -1451,6 +1484,7 @@ MODULE_DEVICE_TABLE(of, ad7173_of_match); static const struct spi_device_id ad7173_id_table[] = { { "ad4111", (kernel_ulong_t)&ad4111_device_info }, { "ad4112", (kernel_ulong_t)&ad4112_device_info }, + { "ad4113", (kernel_ulong_t)&ad4113_device_info }, { "ad4114", (kernel_ulong_t)&ad4114_device_info }, { "ad4115", (kernel_ulong_t)&ad4115_device_info }, { "ad4116", (kernel_ulong_t)&ad4116_device_info }, @@ -1475,7 +1509,7 @@ static struct spi_driver ad7173_driver = { }; module_spi_driver(ad7173_driver); -MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); +MODULE_IMPORT_NS("IIO_AD_SIGMA_DELTA"); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_AUTHOR("Dumitru Ceclan "); MODULE_DESCRIPTION("Analog Devices AD7173 and similar ADC driver"); diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index 7042ddfdfc03ee..1c87db0e046050 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -1394,6 +1394,9 @@ static int ad7192_probe(struct spi_device *spi) st->int_vref_mv = ret == -ENODEV ? avdd_mv : ret / MILLI; st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; + indio_dev->name = st->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = st->chip_info->info; @@ -1458,4 +1461,4 @@ module_spi_driver(ad7192_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7192 and similar ADC"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); +MODULE_IMPORT_NS("IIO_AD_SIGMA_DELTA"); diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 7949b076fb87ea..858c8be2ff1a09 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -383,7 +383,7 @@ static const char * const ad7266_gpio_labels[] = { static int ad7266_probe(struct spi_device *spi) { - struct ad7266_platform_data *pdata = spi->dev.platform_data; + const struct ad7266_platform_data *pdata = dev_get_platdata(&spi->dev); struct iio_dev *indio_dev; struct ad7266_state *st; unsigned int i; diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index 35aa39fe4bde62..f9f32737db8079 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -822,17 +822,15 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) if (FIELD_GET(AD7280A_TRANS_READ_CONV_CHANADDR_MSK, channels[i]) <= AD7280A_CELL_VOLTAGE_6_REG) { if (val >= st->cell_threshhigh) { - u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, - 0, 0, 0); + u64 tmp = IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, 0, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING); iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); } else if (val <= st->cell_threshlow) { - u64 tmp = IIO_EVENT_CODE(IIO_VOLTAGE, 1, 0, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, - 0, 0, 0); + u64 tmp = IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, 0, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING); iio_push_event(indio_dev, tmp, iio_get_time_ns(indio_dev)); } diff --git a/drivers/iio/adc/ad7291.c b/drivers/iio/adc/ad7291.c index 4c7f887adbbf2f..60e12faa320701 100644 --- a/drivers/iio/adc/ad7291.c +++ b/drivers/iio/adc/ad7291.c @@ -269,7 +269,7 @@ static int ad7291_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) + bool state) { int ret = 0; struct ad7291_chip_info *chip = iio_priv(indio_dev); diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c index fb728570debe64..4f32cb22f14044 100644 --- a/drivers/iio/adc/ad7380.c +++ b/drivers/iio/adc/ad7380.c @@ -13,6 +13,8 @@ * ad7381-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7381-4.pdf * ad7383/4-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7383-4-ad7384-4.pdf * ad7386/7/8-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/ad7386-4-7387-4-7388-4.pdf + * adaq4370-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4370-4.pdf + * adaq4380-4 : https://www.analog.com/media/en/technical-documentation/data-sheets/adaq4380-4.pdf */ #include @@ -22,11 +24,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include @@ -36,6 +41,8 @@ #define MAX_NUM_CHANNELS 8 /* 2.5V internal reference voltage */ #define AD7380_INTERNAL_REF_MV 2500 +/* 3.3V internal reference voltage for ADAQ */ +#define ADAQ4380_INTERNAL_REF_MV 3300 /* reading and writing registers is more reliable at lower than max speed */ #define AD7380_REG_WR_SPEED_HZ 10000000 @@ -77,6 +84,13 @@ #define T_CONVERT_X_NS 500 /* xth conversion start time (oversampling) */ #define T_POWERUP_US 5000 /* Power up */ +/* + * AD738x support several SDO lines to increase throughput, but driver currently + * supports only 1 SDO line (standard SPI transaction) + */ +#define AD7380_NUM_SDO_LINES 1 +#define AD7380_DEFAULT_GAIN_MILLI 1000 + struct ad7380_timing_specs { const unsigned int t_csh_ns; /* CS minimum high time */ }; @@ -86,10 +100,12 @@ struct ad7380_chip_info { const struct iio_chan_spec *channels; unsigned int num_channels; unsigned int num_simult_channels; + bool has_hardware_gain; bool has_mux; const char * const *supplies; unsigned int num_supplies; bool external_ref_only; + bool adaq_internal_ref_only; const char * const *vcm_supplies; unsigned int num_vcm_supplies; const unsigned long *available_scan_masks; @@ -181,11 +197,12 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = { }, }; -#define AD7380_CHANNEL(index, bits, diff, sign) { \ +#define _AD7380_CHANNEL(index, bits, diff, sign, gain) { \ .type = IIO_VOLTAGE, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + ((gain) ? BIT(IIO_CHAN_INFO_SCALE) : 0) | \ ((diff) ? 0 : BIT(IIO_CHAN_INFO_OFFSET)), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + .info_mask_shared_by_type = ((gain) ? 0 : BIT(IIO_CHAN_INFO_SCALE)) | \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .info_mask_shared_by_type_available = \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ @@ -199,6 +216,12 @@ static const struct iio_scan_type ad7380_scan_type_16_u[] = { .num_ext_scan_type = ARRAY_SIZE(ad7380_scan_type_##bits##_##sign), \ } +#define AD7380_CHANNEL(index, bits, diff, sign) \ + _AD7380_CHANNEL(index, bits, diff, sign, false) + +#define ADAQ4380_CHANNEL(index, bits, diff, sign) \ + _AD7380_CHANNEL(index, bits, diff, sign, true) + #define DEFINE_AD7380_2_CHANNEL(name, bits, diff, sign) \ static const struct iio_chan_spec name[] = { \ AD7380_CHANNEL(0, bits, diff, sign), \ @@ -215,6 +238,15 @@ static const struct iio_chan_spec name[] = { \ IIO_CHAN_SOFT_TIMESTAMP(4), \ } +#define DEFINE_ADAQ4380_4_CHANNEL(name, bits, diff, sign) \ +static const struct iio_chan_spec name[] = { \ + ADAQ4380_CHANNEL(0, bits, diff, sign), \ + ADAQ4380_CHANNEL(1, bits, diff, sign), \ + ADAQ4380_CHANNEL(2, bits, diff, sign), \ + ADAQ4380_CHANNEL(3, bits, diff, sign), \ + IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + #define DEFINE_AD7380_8_CHANNEL(name, bits, diff, sign) \ static const struct iio_chan_spec name[] = { \ AD7380_CHANNEL(0, bits, diff, sign), \ @@ -233,6 +265,7 @@ DEFINE_AD7380_2_CHANNEL(ad7380_channels, 16, 1, s); DEFINE_AD7380_2_CHANNEL(ad7381_channels, 14, 1, s); DEFINE_AD7380_4_CHANNEL(ad7380_4_channels, 16, 1, s); DEFINE_AD7380_4_CHANNEL(ad7381_4_channels, 14, 1, s); +DEFINE_ADAQ4380_4_CHANNEL(adaq4380_4_channels, 16, 1, s); /* pseudo differential */ DEFINE_AD7380_2_CHANNEL(ad7383_channels, 16, 0, s); DEFINE_AD7380_2_CHANNEL(ad7384_channels, 14, 0, s); @@ -251,6 +284,10 @@ static const char * const ad7380_supplies[] = { "vcc", "vlogic", }; +static const char * const adaq4380_supplies[] = { + "ldo", "vcc", "vlogic", "vs-p", "vs-n", "refin", +}; + static const char * const ad7380_2_channel_vcm_supplies[] = { "aina", "ainb", }; @@ -341,6 +378,11 @@ static const int ad7380_oversampling_ratios[] = { 1, 2, 4, 8, 16, 32, }; +/* Gains stored as fractions of 1000 so they can be expressed by integers. */ +static const int ad7380_gains[] = { + 300, 600, 1000, 1600, +}; + static const struct ad7380_chip_info ad7380_chip_info = { .name = "ad7380", .channels = ad7380_channels, @@ -510,6 +552,32 @@ static const struct ad7380_chip_info ad7388_4_chip_info = { .timing_specs = &ad7380_4_timing, }; +static const struct ad7380_chip_info adaq4370_4_chip_info = { + .name = "adaq4370-4", + .channels = adaq4380_4_channels, + .num_channels = ARRAY_SIZE(adaq4380_4_channels), + .num_simult_channels = 4, + .supplies = adaq4380_supplies, + .num_supplies = ARRAY_SIZE(adaq4380_supplies), + .adaq_internal_ref_only = true, + .has_hardware_gain = true, + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + +static const struct ad7380_chip_info adaq4380_4_chip_info = { + .name = "adaq4380-4", + .channels = adaq4380_4_channels, + .num_channels = ARRAY_SIZE(adaq4380_4_channels), + .num_simult_channels = 4, + .supplies = adaq4380_supplies, + .num_supplies = ARRAY_SIZE(adaq4380_supplies), + .adaq_internal_ref_only = true, + .has_hardware_gain = true, + .available_scan_masks = ad7380_4_channel_scan_masks, + .timing_specs = &ad7380_4_timing, +}; + struct ad7380_state { const struct ad7380_chip_info *chip_info; struct spi_device *spi; @@ -520,6 +588,7 @@ struct ad7380_state { bool seq; unsigned int vref_mv; unsigned int vcm_mv[MAX_NUM_CHANNELS]; + unsigned int gain_milli[MAX_NUM_CHANNELS]; /* xfers, message an buffer for reading sample data */ struct spi_transfer normal_xfer[2]; struct spi_message normal_msg; @@ -649,7 +718,8 @@ static int ad7380_set_ch(struct ad7380_state *st, unsigned int ch) if (st->oversampling_ratio > 1) xfer.delay.value = T_CONVERT_0_NS + - T_CONVERT_X_NS * (st->oversampling_ratio - 1); + T_CONVERT_X_NS * (st->oversampling_ratio - 1) * + st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES; return spi_sync_transfer(st->spi, &xfer, 1); } @@ -672,7 +742,8 @@ static void ad7380_update_xfers(struct ad7380_state *st, */ if (st->oversampling_ratio > 1) t_convert = T_CONVERT_0_NS + T_CONVERT_X_NS * - (st->oversampling_ratio - 1); + (st->oversampling_ratio - 1) * + st->chip_info->num_simult_channels / AD7380_NUM_SDO_LINES; if (st->seq) { xfer[0].delay.value = xfer[1].delay.value = t_convert; @@ -868,8 +939,15 @@ static int ad7380_read_raw(struct iio_dev *indio_dev, * * (2 × VREF) / 2^N, for differential chips * * VREF / 2^N, for pseudo-differential chips * where N is the ADC resolution (i.e realbits) + * + * The gain is stored as a fraction of 1000 and, as we need to + * divide vref_mv by the gain, we invert the gain/1000 fraction. */ - *val = st->vref_mv; + if (st->chip_info->has_hardware_gain) + *val = mult_frac(st->vref_mv, MILLI, + st->gain_milli[chan->scan_index]); + else + *val = st->vref_mv; *val2 = scan_type->realbits - chan->differential; return IIO_VAL_FRACTIONAL_LOG2; @@ -1021,17 +1099,19 @@ static int ad7380_init(struct ad7380_state *st, bool external_ref_en) /* SPI 1-wire mode */ return regmap_update_bits(st->regmap, AD7380_REG_ADDR_CONFIG2, AD7380_CONFIG2_SDO, - FIELD_PREP(AD7380_CONFIG2_SDO, 1)); + FIELD_PREP(AD7380_CONFIG2_SDO, + AD7380_NUM_SDO_LINES)); } static int ad7380_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct ad7380_state *st; bool external_ref_en; int ret, i; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -1039,21 +1119,32 @@ static int ad7380_probe(struct spi_device *spi) st->spi = spi; st->chip_info = spi_get_device_match_data(spi); if (!st->chip_info) - return dev_err_probe(&spi->dev, -EINVAL, "missing match data\n"); + return dev_err_probe(dev, -EINVAL, "missing match data\n"); - ret = devm_regulator_bulk_get_enable(&spi->dev, st->chip_info->num_supplies, + ret = devm_regulator_bulk_get_enable(dev, st->chip_info->num_supplies, st->chip_info->supplies); if (ret) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to enable power supplies\n"); fsleep(T_POWERUP_US); - if (st->chip_info->external_ref_only) { - ret = devm_regulator_get_enable_read_voltage(&spi->dev, - "refin"); + if (st->chip_info->adaq_internal_ref_only) { + /* + * ADAQ chips use fixed internal reference but still + * require a specific reference supply to power it. + * "refin" is already enabled with other power supplies + * in bulk_get_enable(). + */ + + st->vref_mv = ADAQ4380_INTERNAL_REF_MV; + + /* these chips don't have a register bit for this */ + external_ref_en = false; + } else if (st->chip_info->external_ref_only) { + ret = devm_regulator_get_enable_read_voltage(dev, "refin"); if (ret < 0) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to get refin regulator\n"); st->vref_mv = ret / 1000; @@ -1065,10 +1156,9 @@ static int ad7380_probe(struct spi_device *spi) * If there is no REFIO supply, then it means that we are using * the internal reference, otherwise REFIO is reference voltage. */ - ret = devm_regulator_get_enable_read_voltage(&spi->dev, - "refio"); + ret = devm_regulator_get_enable_read_voltage(dev, "refio"); if (ret < 0 && ret != -ENODEV) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to get refio regulator\n"); external_ref_en = ret != -ENODEV; @@ -1076,7 +1166,7 @@ static int ad7380_probe(struct spi_device *spi) } if (st->chip_info->num_vcm_supplies > ARRAY_SIZE(st->vcm_mv)) - return dev_err_probe(&spi->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "invalid number of VCM supplies\n"); /* @@ -1086,18 +1176,54 @@ static int ad7380_probe(struct spi_device *spi) for (i = 0; i < st->chip_info->num_vcm_supplies; i++) { const char *vcm = st->chip_info->vcm_supplies[i]; - ret = devm_regulator_get_enable_read_voltage(&spi->dev, vcm); + ret = devm_regulator_get_enable_read_voltage(dev, vcm); if (ret < 0) - return dev_err_probe(&spi->dev, ret, + return dev_err_probe(dev, ret, "Failed to get %s regulator\n", vcm); st->vcm_mv[i] = ret / 1000; } - st->regmap = devm_regmap_init(&spi->dev, NULL, st, &ad7380_regmap_config); + for (i = 0; i < MAX_NUM_CHANNELS; i++) + st->gain_milli[i] = AD7380_DEFAULT_GAIN_MILLI; + + if (st->chip_info->has_hardware_gain) { + device_for_each_child_node_scoped(dev, node) { + unsigned int channel, gain; + int gain_idx; + + ret = fwnode_property_read_u32(node, "reg", &channel); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read reg property\n"); + + if (channel >= st->chip_info->num_channels - 1) + return dev_err_probe(dev, -EINVAL, + "Invalid channel number %i\n", + channel); + + ret = fwnode_property_read_u32(node, "adi,gain-milli", + &gain); + if (ret && ret != -EINVAL) + return dev_err_probe(dev, ret, + "Failed to read gain for channel %i\n", + channel); + if (ret != -EINVAL) { + /* + * Match gain value from dt to one of supported + * gains + */ + gain_idx = find_closest(gain, ad7380_gains, + ARRAY_SIZE(ad7380_gains)); + st->gain_milli[channel] = ad7380_gains[gain_idx]; + } + } + } + + st->regmap = devm_regmap_init(dev, NULL, st, &ad7380_regmap_config); if (IS_ERR(st->regmap)) - return dev_err_probe(&spi->dev, PTR_ERR(st->regmap), + return dev_err_probe(dev, PTR_ERR(st->regmap), "failed to allocate register map\n"); /* @@ -1148,7 +1274,7 @@ static int ad7380_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->available_scan_masks = st->chip_info->available_scan_masks; - ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, ad7380_trigger_handler, &ad7380_buffer_setup_ops); @@ -1159,7 +1285,7 @@ static int ad7380_probe(struct spi_device *spi) if (ret) return ret; - return devm_iio_device_register(&spi->dev, indio_dev); + return devm_iio_device_register(dev, indio_dev); } static const struct of_device_id ad7380_of_match_table[] = { @@ -1177,6 +1303,8 @@ static const struct of_device_id ad7380_of_match_table[] = { { .compatible = "adi,ad7386-4", .data = &ad7386_4_chip_info }, { .compatible = "adi,ad7387-4", .data = &ad7387_4_chip_info }, { .compatible = "adi,ad7388-4", .data = &ad7388_4_chip_info }, + { .compatible = "adi,adaq4370-4", .data = &adaq4370_4_chip_info }, + { .compatible = "adi,adaq4380-4", .data = &adaq4380_4_chip_info }, { } }; @@ -1195,6 +1323,8 @@ static const struct spi_device_id ad7380_id_table[] = { { "ad7386-4", (kernel_ulong_t)&ad7386_4_chip_info }, { "ad7387-4", (kernel_ulong_t)&ad7387_4_chip_info }, { "ad7388-4", (kernel_ulong_t)&ad7388_4_chip_info }, + { "adaq4370-4", (kernel_ulong_t)&adaq4370_4_chip_info }, + { "adaq4380-4", (kernel_ulong_t)&adaq4380_4_chip_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7380_id_table); diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c index 9b457472d49c17..e35d55d03d86ad 100644 --- a/drivers/iio/adc/ad7606.c +++ b/drivers/iio/adc/ad7606.c @@ -13,14 +13,17 @@ #include #include #include +#include #include #include #include #include +#include #include -#include +#include #include +#include #include #include #include @@ -30,15 +33,52 @@ /* * Scales are computed as 5000/32768 and 10000/32768 respectively, - * so that when applied to the raw values they provide mV values + * so that when applied to the raw values they provide mV values. + * The scale arrays are kept as IIO_VAL_INT_PLUS_MICRO, so index + * X is the integer part and X + 1 is the fractional part. */ -static const unsigned int ad7606_scale_avail[2] = { - 152588, 305176 +static const unsigned int ad7606_16bit_hw_scale_avail[2][2] = { + { 0, 152588 }, { 0, 305176 } +}; + +static const unsigned int ad7606_18bit_hw_scale_avail[2][2] = { + { 0, 38147 }, { 0, 76294 } +}; + +static const unsigned int ad7606c_16bit_single_ended_unipolar_scale_avail[3][2] = { + { 0, 76294 }, { 0, 152588 }, { 0, 190735 } +}; + +static const unsigned int ad7606c_16bit_single_ended_bipolar_scale_avail[5][2] = { + { 0, 76294 }, { 0, 152588 }, { 0, 190735 }, { 0, 305176 }, { 0, 381470 } +}; + +static const unsigned int ad7606c_16bit_differential_bipolar_scale_avail[4][2] = { + { 0, 152588 }, { 0, 305176 }, { 0, 381470 }, { 0, 610352 } +}; + +static const unsigned int ad7606c_18bit_single_ended_unipolar_scale_avail[3][2] = { + { 0, 19073 }, { 0, 38147 }, { 0, 47684 } +}; + +static const unsigned int ad7606c_18bit_single_ended_bipolar_scale_avail[5][2] = { + { 0, 19073 }, { 0, 38147 }, { 0, 47684 }, { 0, 76294 }, { 0, 95367 } }; +static const unsigned int ad7606c_18bit_differential_bipolar_scale_avail[4][2] = { + { 0, 38147 }, { 0, 76294 }, { 0, 95367 }, { 0, 152588 } +}; + +static const unsigned int ad7606_16bit_sw_scale_avail[3][2] = { + { 0, 76293 }, { 0, 152588 }, { 0, 305176 } +}; -static const unsigned int ad7616_sw_scale_avail[3] = { - 76293, 152588, 305176 +static const unsigned int ad7607_hw_scale_avail[2][2] = { + { 0, 610352 }, { 1, 220703 } +}; + +static const unsigned int ad7609_hw_scale_avail[2][2] = { + { 0, 152588 }, { 0, 305176 } }; static const unsigned int ad7606_oversampling_avail[7] = { @@ -49,6 +89,227 @@ static const unsigned int ad7616_oversampling_avail[8] = { 1, 2, 4, 8, 16, 32, 64, 128, }; +static const struct iio_chan_spec ad7605_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(4), + AD7605_CHANNEL(0), + AD7605_CHANNEL(1), + AD7605_CHANNEL(2), + AD7605_CHANNEL(3), +}; + +static const struct iio_chan_spec ad7606_channels_16bit[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0, 16), + AD7606_CHANNEL(1, 16), + AD7606_CHANNEL(2, 16), + AD7606_CHANNEL(3, 16), + AD7606_CHANNEL(4, 16), + AD7606_CHANNEL(5, 16), + AD7606_CHANNEL(6, 16), + AD7606_CHANNEL(7, 16), +}; + +static const struct iio_chan_spec ad7606_channels_18bit[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0, 18), + AD7606_CHANNEL(1, 18), + AD7606_CHANNEL(2, 18), + AD7606_CHANNEL(3, 18), + AD7606_CHANNEL(4, 18), + AD7606_CHANNEL(5, 18), + AD7606_CHANNEL(6, 18), + AD7606_CHANNEL(7, 18), +}; + +static const struct iio_chan_spec ad7607_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0, 14), + AD7606_CHANNEL(1, 14), + AD7606_CHANNEL(2, 14), + AD7606_CHANNEL(3, 14), + AD7606_CHANNEL(4, 14), + AD7606_CHANNEL(5, 14), + AD7606_CHANNEL(6, 14), + AD7606_CHANNEL(7, 14), +}; + +static const struct iio_chan_spec ad7608_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_CHANNEL(0, 18), + AD7606_CHANNEL(1, 18), + AD7606_CHANNEL(2, 18), + AD7606_CHANNEL(3, 18), + AD7606_CHANNEL(4, 18), + AD7606_CHANNEL(5, 18), + AD7606_CHANNEL(6, 18), + AD7606_CHANNEL(7, 18), +}; + +/* + * The current assumption that this driver makes for AD7616, is that it's + * working in Hardware Mode with Serial, Burst and Sequencer modes activated. + * To activate them, following pins must be pulled high: + * -SER/PAR + * -SEQEN + * And following pins must be pulled low: + * -WR/BURST + * -DB4/SER1W + */ +static const struct iio_chan_spec ad7616_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(16), + AD7606_CHANNEL(0, 16), + AD7606_CHANNEL(1, 16), + AD7606_CHANNEL(2, 16), + AD7606_CHANNEL(3, 16), + AD7606_CHANNEL(4, 16), + AD7606_CHANNEL(5, 16), + AD7606_CHANNEL(6, 16), + AD7606_CHANNEL(7, 16), + AD7606_CHANNEL(8, 16), + AD7606_CHANNEL(9, 16), + AD7606_CHANNEL(10, 16), + AD7606_CHANNEL(11, 16), + AD7606_CHANNEL(12, 16), + AD7606_CHANNEL(13, 16), + AD7606_CHANNEL(14, 16), + AD7606_CHANNEL(15, 16), +}; + +static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7606_16bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7607_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7608_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); +static int ad7609_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); + +const struct ad7606_chip_info ad7605_4_info = { + .channels = ad7605_channels, + .name = "ad7605-4", + .num_adc_channels = 4, + .num_channels = 5, + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7605_4_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7606_8_info = { + .channels = ad7606_channels_16bit, + .name = "ad7606-8", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606_8_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7606_6_info = { + .channels = ad7606_channels_16bit, + .name = "ad7606-6", + .num_adc_channels = 6, + .num_channels = 7, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606_6_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7606_4_info = { + .channels = ad7606_channels_16bit, + .name = "ad7606-4", + .num_adc_channels = 4, + .num_channels = 5, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606_4_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7606b_info = { + .channels = ad7606_channels_16bit, + .max_samplerate = 800 * KILO, + .name = "ad7606b", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7606c_16_info = { + .channels = ad7606_channels_16bit, + .name = "ad7606c16", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606c_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7607_info = { + .channels = ad7607_channels, + .name = "ad7607", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7607_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7607_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7608_info = { + .channels = ad7608_channels, + .name = "ad7608", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7608_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7608_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7609_info = { + .channels = ad7608_channels, + .name = "ad7609", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7609_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7609_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7606c_18_info = { + .channels = ad7606_channels_18bit, + .name = "ad7606c18", + .num_adc_channels = 8, + .num_channels = 9, + .oversampling_avail = ad7606_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), + .scale_setup_cb = ad7606c_18bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606"); + +const struct ad7606_chip_info ad7616_info = { + .channels = ad7616_channels, + .init_delay_ms = 15, + .name = "ad7616", + .num_adc_channels = 16, + .num_channels = 17, + .oversampling_avail = ad7616_oversampling_avail, + .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), + .os_req_reset = true, + .scale_setup_cb = ad7606_16bit_chan_scale_setup, +}; +EXPORT_SYMBOL_NS_GPL(ad7616_info, "IIO_AD7606"); + int ad7606_reset(struct ad7606_state *st) { if (st->gpio_reset) { @@ -60,7 +321,229 @@ int ad7606_reset(struct ad7606_state *st) return -ENODEV; } -EXPORT_SYMBOL_NS_GPL(ad7606_reset, IIO_AD7606); +EXPORT_SYMBOL_NS_GPL(ad7606_reset, "IIO_AD7606"); + +static int ad7606_16bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + + if (!st->sw_mode_en) { + /* tied to logic low, analog input range is +/- 5V */ + cs->range = 0; + cs->scale_avail = ad7606_16bit_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail); + return 0; + } + + /* Scale of 0.076293 is only available in sw mode */ + /* After reset, in software mode, ±10 V is set by default */ + cs->range = 2; + cs->scale_avail = ad7606_16bit_sw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail); + + return 0; +} + +static int ad7606_get_chan_config(struct ad7606_state *st, int ch, + bool *bipolar, bool *differential) +{ + unsigned int num_channels = st->chip_info->num_channels - 1; + struct device *dev = st->dev; + int ret; + + *bipolar = false; + *differential = false; + + device_for_each_child_node_scoped(dev, child) { + u32 pins[2]; + int reg; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + continue; + + /* channel number (here) is from 1 to num_channels */ + if (reg == 0 || reg > num_channels) { + dev_warn(dev, + "Invalid channel number (ignoring): %d\n", reg); + continue; + } + + if (reg != (ch + 1)) + continue; + + *bipolar = fwnode_property_read_bool(child, "bipolar"); + + ret = fwnode_property_read_u32_array(child, "diff-channels", + pins, ARRAY_SIZE(pins)); + /* Channel is differential, if pins are the same as 'reg' */ + if (ret == 0 && (pins[0] != reg || pins[1] != reg)) { + dev_err(dev, + "Differential pins must be the same as 'reg'"); + return -EINVAL; + } + + *differential = (ret == 0); + + if (*differential && !*bipolar) { + dev_err(dev, + "'bipolar' must be added for diff channel %d\n", + reg); + return -EINVAL; + } + + return 0; + } + + return 0; +} + +static int ad7606c_18bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + bool bipolar, differential; + int ret; + + if (!st->sw_mode_en) { + cs->range = 0; + cs->scale_avail = ad7606_18bit_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail); + return 0; + } + + ret = ad7606_get_chan_config(st, ch, &bipolar, &differential); + if (ret) + return ret; + + if (differential) { + cs->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail; + cs->num_scales = + ARRAY_SIZE(ad7606c_18bit_differential_bipolar_scale_avail); + /* Bipolar differential ranges start at 8 (b1000) */ + cs->reg_offset = 8; + cs->range = 1; + chan->differential = 1; + chan->channel2 = chan->channel; + + return 0; + } + + chan->differential = 0; + + if (bipolar) { + cs->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail; + cs->num_scales = + ARRAY_SIZE(ad7606c_18bit_single_ended_bipolar_scale_avail); + /* Bipolar single-ended ranges start at 0 (b0000) */ + cs->reg_offset = 0; + cs->range = 3; + chan->scan_type.sign = 's'; + + return 0; + } + + cs->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail; + cs->num_scales = + ARRAY_SIZE(ad7606c_18bit_single_ended_unipolar_scale_avail); + /* Unipolar single-ended ranges start at 5 (b0101) */ + cs->reg_offset = 5; + cs->range = 1; + chan->scan_type.sign = 'u'; + + return 0; +} + +static int ad7606c_16bit_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + bool bipolar, differential; + int ret; + + if (!st->sw_mode_en) { + cs->range = 0; + cs->scale_avail = ad7606_16bit_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail); + return 0; + } + + ret = ad7606_get_chan_config(st, ch, &bipolar, &differential); + if (ret) + return ret; + + if (differential) { + cs->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail; + cs->num_scales = + ARRAY_SIZE(ad7606c_16bit_differential_bipolar_scale_avail); + /* Bipolar differential ranges start at 8 (b1000) */ + cs->reg_offset = 8; + cs->range = 1; + chan->differential = 1; + chan->channel2 = chan->channel; + chan->scan_type.sign = 's'; + + return 0; + } + + chan->differential = 0; + + if (bipolar) { + cs->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail; + cs->num_scales = + ARRAY_SIZE(ad7606c_16bit_single_ended_bipolar_scale_avail); + /* Bipolar single-ended ranges start at 0 (b0000) */ + cs->reg_offset = 0; + cs->range = 3; + chan->scan_type.sign = 's'; + + return 0; + } + + cs->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail; + cs->num_scales = + ARRAY_SIZE(ad7606c_16bit_single_ended_unipolar_scale_avail); + /* Unipolar single-ended ranges start at 5 (b0101) */ + cs->reg_offset = 5; + cs->range = 1; + chan->scan_type.sign = 'u'; + + return 0; +} + +static int ad7607_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + + cs->range = 0; + cs->scale_avail = ad7607_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail); + return 0; +} + +static int ad7608_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + + cs->range = 0; + cs->scale_avail = ad7606_18bit_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail); + return 0; +} + +static int ad7609_chan_scale_setup(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch) +{ + struct ad7606_chan_scale *cs = &st->chan_scales[ch]; + + cs->range = 0; + cs->scale_avail = ad7609_hw_scale_avail; + cs->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail); + return 0; +} static int ad7606_reg_access(struct iio_dev *indio_dev, unsigned int reg, @@ -83,12 +566,85 @@ static int ad7606_reg_access(struct iio_dev *indio_dev, } } +static int ad7606_pwm_set_high(struct ad7606_state *st) +{ + struct pwm_state cnvst_pwm_state; + int ret; + + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + cnvst_pwm_state.enabled = true; + cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period; + + ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); + + return ret; +} + +static int ad7606_pwm_set_low(struct ad7606_state *st) +{ + struct pwm_state cnvst_pwm_state; + int ret; + + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + cnvst_pwm_state.enabled = true; + cnvst_pwm_state.duty_cycle = 0; + + ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); + + return ret; +} + +static int ad7606_pwm_set_swing(struct ad7606_state *st) +{ + struct pwm_state cnvst_pwm_state; + + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + cnvst_pwm_state.enabled = true; + cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2; + + return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); +} + +static bool ad7606_pwm_is_swinging(struct ad7606_state *st) +{ + struct pwm_state cnvst_pwm_state; + + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + + return cnvst_pwm_state.duty_cycle != cnvst_pwm_state.period && + cnvst_pwm_state.duty_cycle != 0; +} + +static int ad7606_set_sampling_freq(struct ad7606_state *st, unsigned long freq) +{ + struct pwm_state cnvst_pwm_state; + bool is_swinging = ad7606_pwm_is_swinging(st); + bool is_high; + + if (freq == 0) + return -EINVAL; + + /* Retrieve the previous state. */ + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + is_high = cnvst_pwm_state.duty_cycle == cnvst_pwm_state.period; + + cnvst_pwm_state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, freq); + cnvst_pwm_state.polarity = PWM_POLARITY_NORMAL; + if (is_high) + cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period; + else if (is_swinging) + cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2; + else + cnvst_pwm_state.duty_cycle = 0; + + return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state); +} + static int ad7606_read_samples(struct ad7606_state *st) { - unsigned int num = st->chip_info->num_channels - 1; - u16 *data = st->data; + unsigned int num = st->chip_info->num_adc_channels; - return st->bops->read_block(st->dev, num, data); + return st->bops->read_block(st->dev, num, &st->data); } static irqreturn_t ad7606_trigger_handler(int irq, void *p) @@ -104,7 +660,7 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p) if (ret) goto error_ret; - iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_push_to_buffers_with_timestamp(indio_dev, &st->data, iio_get_time_ns(indio_dev)); error_ret: iio_trigger_notify_done(indio_dev->trig); @@ -114,24 +670,62 @@ static irqreturn_t ad7606_trigger_handler(int irq, void *p) return IRQ_HANDLED; } -static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) +static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch, + int *val) { struct ad7606_state *st = iio_priv(indio_dev); + unsigned int realbits = st->chip_info->channels[1].scan_type.realbits; + const struct iio_chan_spec *chan; int ret; - gpiod_set_value(st->gpio_convst, 1); - ret = wait_for_completion_timeout(&st->completion, - msecs_to_jiffies(1000)); - if (!ret) { - ret = -ETIMEDOUT; - goto error_ret; + if (st->gpio_convst) { + gpiod_set_value(st->gpio_convst, 1); + } else { + ret = ad7606_pwm_set_high(st); + if (ret < 0) + return ret; + } + + /* + * If no backend, wait for the interruption on busy pin, otherwise just add + * a delay to leave time for the data to be available. For now, the latter + * will not happen because IIO_CHAN_INFO_RAW is not supported for the backend. + * TODO: Add support for reading a single value when the backend is used. + */ + if (!st->back) { + ret = wait_for_completion_timeout(&st->completion, + msecs_to_jiffies(1000)); + if (!ret) { + ret = -ETIMEDOUT; + goto error_ret; + } + } else { + fsleep(1); } ret = ad7606_read_samples(st); - if (ret == 0) - ret = st->data[ch]; + if (ret) + goto error_ret; + + chan = &indio_dev->channels[ch + 1]; + if (chan->scan_type.sign == 'u') { + if (realbits > 16) + *val = st->data.buf32[ch]; + else + *val = st->data.buf16[ch]; + } else { + if (realbits > 16) + *val = sign_extend32(st->data.buf32[ch], realbits - 1); + else + *val = sign_extend32(st->data.buf16[ch], realbits - 1); + } error_ret: + if (!st->gpio_convst) { + ret = ad7606_pwm_set_low(st); + if (ret < 0) + return ret; + } gpiod_set_value(st->gpio_convst, 0); return ret; @@ -145,53 +739,57 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, { int ret, ch = 0; struct ad7606_state *st = iio_priv(indio_dev); + struct ad7606_chan_scale *cs; + struct pwm_state cnvst_pwm_state; switch (m) { case IIO_CHAN_INFO_RAW: iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { - ret = ad7606_scan_direct(indio_dev, chan->address); + ret = ad7606_scan_direct(indio_dev, chan->address, val); if (ret < 0) return ret; - *val = (short) ret; return IIO_VAL_INT; } unreachable(); case IIO_CHAN_INFO_SCALE: if (st->sw_mode_en) ch = chan->address; - *val = 0; - *val2 = st->scale_avail[st->range[ch]]; + cs = &st->chan_scales[ch]; + *val = cs->scale_avail[cs->range][0]; + *val2 = cs->scale_avail[cs->range][1]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: *val = st->oversampling; return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + /* + * TODO: return the real frequency intead of the requested one once + * pwm_get_state_hw comes upstream. + */ + pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state); + *val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period); + return IIO_VAL_INT; } return -EINVAL; } -static ssize_t ad7606_show_avail(char *buf, const unsigned int *vals, - unsigned int n, bool micros) -{ - size_t len = 0; - int i; - - for (i = 0; i < n; i++) { - len += scnprintf(buf + len, PAGE_SIZE - len, - micros ? "0.%06u " : "%u ", vals[i]); - } - buf[len - 1] = '\n'; - - return len; -} - static ssize_t in_voltage_scale_available_show(struct device *dev, struct device_attribute *attr, char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); + struct ad7606_chan_scale *cs = &st->chan_scales[0]; + const unsigned int (*vals)[2] = cs->scale_avail; + unsigned int i; + size_t len = 0; + + for (i = 0; i < cs->num_scales; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ", + vals[i][0], vals[i][1]); + buf[len - 1] = '\n'; - return ad7606_show_avail(buf, st->scale_avail, st->num_scales, true); + return len; } static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); @@ -229,19 +827,27 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7606_state *st = iio_priv(indio_dev); + unsigned int scale_avail_uv[AD760X_MAX_SCALES]; + struct ad7606_chan_scale *cs; int i, ret, ch = 0; guard(mutex)(&st->lock); switch (mask) { case IIO_CHAN_INFO_SCALE: - i = find_closest(val2, st->scale_avail, st->num_scales); if (st->sw_mode_en) ch = chan->address; - ret = st->write_scale(indio_dev, ch, i); + cs = &st->chan_scales[ch]; + for (i = 0; i < cs->num_scales; i++) { + scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO + + cs->scale_avail[i][1]; + } + val = (val * MICRO) + val2; + i = find_closest(val, scale_avail_uv, cs->num_scales); + ret = st->write_scale(indio_dev, ch, i + cs->reg_offset); if (ret < 0) return ret; - st->range[ch] = i; + cs->range = i; return 0; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: @@ -252,8 +858,13 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, ret = st->write_os(indio_dev, i); if (ret < 0) return ret; + st->oversampling = st->oversampling_avail[i]; return 0; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val < 0 && val2 != 0) + return -EINVAL; + return ad7606_set_sampling_freq(st, val); default: return -EINVAL; } @@ -265,9 +876,15 @@ static ssize_t ad7606_oversampling_ratio_avail(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7606_state *st = iio_priv(indio_dev); + const unsigned int *vals = st->oversampling_avail; + unsigned int i; + size_t len = 0; - return ad7606_show_avail(buf, st->oversampling_avail, - st->num_os_ratios, false); + for (i = 0; i < st->num_os_ratios; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%u ", vals[i]); + buf[len - 1] = '\n'; + + return len; } static IIO_DEVICE_ATTR(oversampling_ratio_available, 0444, @@ -301,102 +918,13 @@ static const struct attribute_group ad7606_attribute_group_range = { .attrs = ad7606_attributes_range, }; -static const struct iio_chan_spec ad7605_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(4), - AD7605_CHANNEL(0), - AD7605_CHANNEL(1), - AD7605_CHANNEL(2), - AD7605_CHANNEL(3), -}; - -static const struct iio_chan_spec ad7606_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(8), - AD7606_CHANNEL(0), - AD7606_CHANNEL(1), - AD7606_CHANNEL(2), - AD7606_CHANNEL(3), - AD7606_CHANNEL(4), - AD7606_CHANNEL(5), - AD7606_CHANNEL(6), - AD7606_CHANNEL(7), -}; - -/* - * The current assumption that this driver makes for AD7616, is that it's - * working in Hardware Mode with Serial, Burst and Sequencer modes activated. - * To activate them, following pins must be pulled high: - * -SER/PAR - * -SEQEN - * And following pins must be pulled low: - * -WR/BURST - * -DB4/SER1W - */ -static const struct iio_chan_spec ad7616_channels[] = { - IIO_CHAN_SOFT_TIMESTAMP(16), - AD7606_CHANNEL(0), - AD7606_CHANNEL(1), - AD7606_CHANNEL(2), - AD7606_CHANNEL(3), - AD7606_CHANNEL(4), - AD7606_CHANNEL(5), - AD7606_CHANNEL(6), - AD7606_CHANNEL(7), - AD7606_CHANNEL(8), - AD7606_CHANNEL(9), - AD7606_CHANNEL(10), - AD7606_CHANNEL(11), - AD7606_CHANNEL(12), - AD7606_CHANNEL(13), - AD7606_CHANNEL(14), - AD7606_CHANNEL(15), -}; - -static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { - /* More devices added in future */ - [ID_AD7605_4] = { - .channels = ad7605_channels, - .num_channels = 5, - }, - [ID_AD7606_8] = { - .channels = ad7606_channels, - .num_channels = 9, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7606_6] = { - .channels = ad7606_channels, - .num_channels = 7, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7606_4] = { - .channels = ad7606_channels, - .num_channels = 5, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7606B] = { - .channels = ad7606_channels, - .num_channels = 9, - .oversampling_avail = ad7606_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail), - }, - [ID_AD7616] = { - .channels = ad7616_channels, - .num_channels = 17, - .oversampling_avail = ad7616_oversampling_avail, - .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail), - .os_req_reset = true, - .init_delay_ms = 15, - }, -}; - static int ad7606_request_gpios(struct ad7606_state *st) { struct device *dev = st->dev; - st->gpio_convst = devm_gpiod_get(dev, "adi,conversion-start", - GPIOD_OUT_LOW); + st->gpio_convst = devm_gpiod_get_optional(dev, "adi,conversion-start", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_convst)) return PTR_ERR(st->gpio_convst); @@ -438,14 +966,24 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id) { struct iio_dev *indio_dev = dev_id; struct ad7606_state *st = iio_priv(indio_dev); + int ret; if (iio_buffer_enabled(indio_dev)) { - gpiod_set_value(st->gpio_convst, 0); + if (st->gpio_convst) { + gpiod_set_value(st->gpio_convst, 0); + } else { + ret = ad7606_pwm_set_low(st); + if (ret < 0) { + dev_err(st->dev, "PWM set low failed"); + goto done; + } + } iio_trigger_poll_nested(st->trig); } else { complete(&st->completion); } +done: return IRQ_HANDLED; }; @@ -478,14 +1016,81 @@ static int ad7606_buffer_predisable(struct iio_dev *indio_dev) return 0; } +static int ad7606_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long info) +{ + struct ad7606_state *st = iio_priv(indio_dev); + struct ad7606_chan_scale *cs; + unsigned int ch = 0; + + switch (info) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = st->oversampling_avail; + *length = st->num_os_ratios; + *type = IIO_VAL_INT; + + return IIO_AVAIL_LIST; + + case IIO_CHAN_INFO_SCALE: + if (st->sw_mode_en) + ch = chan->address; + + cs = &st->chan_scales[ch]; + *vals = (int *)cs->scale_avail; + *length = cs->num_scales; + *type = IIO_VAL_INT_PLUS_MICRO; + + return IIO_AVAIL_LIST; + } + return -EINVAL; +} + +static int ad7606_backend_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_pwm_set_swing(st); +} + +static int ad7606_backend_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + return ad7606_pwm_set_low(st); +} + +static int ad7606_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + /* + * The update scan mode is only for iio backend compatible drivers. + * If the specific update_scan_mode is not defined in the bus ops, + * just do nothing and return 0. + */ + if (!st->bops->update_scan_mode) + return 0; + + return st->bops->update_scan_mode(indio_dev, scan_mask); +} + static const struct iio_buffer_setup_ops ad7606_buffer_ops = { .postenable = &ad7606_buffer_postenable, .predisable = &ad7606_buffer_predisable, }; +static const struct iio_buffer_setup_ops ad7606_backend_buffer_ops = { + .postenable = &ad7606_backend_buffer_postenable, + .predisable = &ad7606_backend_buffer_predisable, +}; + static const struct iio_info ad7606_info_no_os_or_range = { .read_raw = &ad7606_read_raw, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_info ad7606_info_os_and_range = { @@ -493,14 +1098,16 @@ static const struct iio_info ad7606_info_os_and_range = { .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os_and_range, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; -static const struct iio_info ad7606_info_os_range_and_debug = { +static const struct iio_info ad7606_info_sw_mode = { .read_raw = &ad7606_read_raw, .write_raw = &ad7606_write_raw, + .read_avail = &ad7606_read_avail, .debugfs_reg_access = &ad7606_reg_access, - .attrs = &ad7606_attribute_group_os_and_range, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_info ad7606_info_os = { @@ -508,6 +1115,7 @@ static const struct iio_info ad7606_info_os = { .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_info ad7606_info_range = { @@ -515,14 +1123,60 @@ static const struct iio_info ad7606_info_range = { .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_range, .validate_trigger = &ad7606_validate_trigger, + .update_scan_mode = &ad7606_update_scan_mode, }; static const struct iio_trigger_ops ad7606_trigger_ops = { .validate_device = iio_trigger_validate_own_device, }; +static int ad7606_sw_mode_setup(struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + + st->sw_mode_en = st->bops->sw_mode_config && + device_property_present(st->dev, "adi,sw-mode"); + if (!st->sw_mode_en) + return 0; + + indio_dev->info = &ad7606_info_sw_mode; + + return st->bops->sw_mode_config(indio_dev); +} + +static int ad7606_chan_scales_setup(struct iio_dev *indio_dev) +{ + unsigned int num_channels = indio_dev->num_channels - 1; + struct ad7606_state *st = iio_priv(indio_dev); + struct iio_chan_spec *chans; + size_t size; + int ch, ret; + + /* Clone IIO channels, since some may be differential */ + size = indio_dev->num_channels * sizeof(*indio_dev->channels); + chans = devm_kzalloc(st->dev, size, GFP_KERNEL); + if (!chans) + return -ENOMEM; + + memcpy(chans, indio_dev->channels, size); + indio_dev->channels = chans; + + for (ch = 0; ch < num_channels; ch++) { + ret = st->chip_info->scale_setup_cb(st, &chans[ch + 1], ch); + if (ret) + return ret; + } + + return 0; +} + +static void ad7606_pwm_disable(void *data) +{ + pwm_disable(data); +} + int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, - const char *name, unsigned int id, + const struct ad7606_chip_info *chip_info, const struct ad7606_bus_ops *bops) { struct ad7606_state *st; @@ -540,18 +1194,14 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, mutex_init(&st->lock); st->bops = bops; st->base_address = base_address; - /* tied to logic low, analog input range is +/- 5V */ - st->range[0] = 0; st->oversampling = 1; - st->scale_avail = ad7606_scale_avail; - st->num_scales = ARRAY_SIZE(ad7606_scale_avail); ret = devm_regulator_get_enable(dev, "avcc"); if (ret) return dev_err_probe(dev, ret, "Failed to enable specified AVcc supply\n"); - st->chip_info = &ad7606_chip_info_tbl[id]; + st->chip_info = chip_info; if (st->chip_info->oversampling_num) { st->oversampling_avail = st->chip_info->oversampling_avail; @@ -574,12 +1224,10 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, indio_dev->info = &ad7606_info_no_os_or_range; } indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = name; + indio_dev->name = chip_info->name; indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; - init_completion(&st->completion); - ret = ad7606_reset(st); if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); @@ -593,56 +1241,94 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, st->write_scale = ad7606_write_scale_hw; st->write_os = ad7606_write_os_hw; - if (st->bops->sw_mode_config) - st->sw_mode_en = device_property_present(st->dev, - "adi,sw-mode"); + ret = ad7606_sw_mode_setup(indio_dev); + if (ret) + return ret; + + ret = ad7606_chan_scales_setup(indio_dev); + if (ret) + return ret; + + /* If convst pin is not defined, setup PWM. */ + if (!st->gpio_convst) { + st->cnvst_pwm = devm_pwm_get(dev, NULL); + if (IS_ERR(st->cnvst_pwm)) + return PTR_ERR(st->cnvst_pwm); - if (st->sw_mode_en) { - /* Scale of 0.076293 is only available in sw mode */ - st->scale_avail = ad7616_sw_scale_avail; - st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail); + /* The PWM is initialized at 1MHz to have a fast enough GPIO emulation. */ + ret = ad7606_set_sampling_freq(st, 1 * MEGA); + if (ret) + return ret; - /* After reset, in software mode, ±10 V is set by default */ - memset32(st->range, 2, ARRAY_SIZE(st->range)); - indio_dev->info = &ad7606_info_os_range_and_debug; + ret = ad7606_pwm_set_low(st); + if (ret) + return ret; - ret = st->bops->sw_mode_config(indio_dev); - if (ret < 0) + /* + * PWM is not disabled when sampling stops, but instead its duty cycle is set + * to 0% to be sure we have a "low" state. After we unload the driver, let's + * disable the PWM. + */ + ret = devm_add_action_or_reset(dev, ad7606_pwm_disable, + st->cnvst_pwm); + if (ret) return ret; } - st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", - indio_dev->name, - iio_device_id(indio_dev)); - if (!st->trig) - return -ENOMEM; + if (st->bops->iio_backend_config) { + /* + * If there is a backend, the PWM should not overpass the maximum sampling + * frequency the chip supports. + */ + ret = ad7606_set_sampling_freq(st, + chip_info->max_samplerate ? : 2 * KILO); + if (ret) + return ret; - st->trig->ops = &ad7606_trigger_ops; - iio_trigger_set_drvdata(st->trig, indio_dev); - ret = devm_iio_trigger_register(dev, st->trig); - if (ret) - return ret; + ret = st->bops->iio_backend_config(dev, indio_dev); + if (ret) + return ret; - indio_dev->trig = iio_trigger_get(st->trig); + indio_dev->setup_ops = &ad7606_backend_buffer_ops; + } else { - ret = devm_request_threaded_irq(dev, irq, - NULL, - &ad7606_interrupt, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - name, indio_dev); - if (ret) - return ret; + /* Reserve the PWM use only for backend (force gpio_convst definition) */ + if (!st->gpio_convst) + return dev_err_probe(dev, -EINVAL, + "No backend, connect convst to a GPIO"); + + init_completion(&st->completion); + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7606_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return ret; - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, - &iio_pollfunc_store_time, - &ad7606_trigger_handler, - &ad7606_buffer_ops); - if (ret) - return ret; + indio_dev->trig = iio_trigger_get(st->trig); + + ret = devm_request_threaded_irq(dev, irq, NULL, &ad7606_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + chip_info->name, indio_dev); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &ad7606_trigger_handler, + &ad7606_buffer_ops); + if (ret) + return ret; + } return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(ad7606_probe, IIO_AD7606); +EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606"); #ifdef CONFIG_PM_SLEEP @@ -665,7 +1351,7 @@ static int ad7606_resume(struct device *dev) struct ad7606_state *st = iio_priv(indio_dev); if (st->gpio_standby) { - gpiod_set_value(st->gpio_range, st->range[0]); + gpiod_set_value(st->gpio_range, st->chan_scales[0].range); gpiod_set_value(st->gpio_standby, 1); ad7606_reset(st); } @@ -674,7 +1360,7 @@ static int ad7606_resume(struct device *dev) } SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume); -EXPORT_SYMBOL_NS_GPL(ad7606_pm_ops, IIO_AD7606); +EXPORT_SYMBOL_NS_GPL(ad7606_pm_ops, "IIO_AD7606"); #endif diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h index 6649e84d25de64..998814a92b8258 100644 --- a/drivers/iio/adc/ad7606.h +++ b/drivers/iio/adc/ad7606.h @@ -8,7 +8,9 @@ #ifndef IIO_ADC_AD7606_H_ #define IIO_ADC_AD7606_H_ -#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all) { \ +#define AD760X_MAX_CHANNELS 16 + +#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all, bits) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = num, \ @@ -19,56 +21,111 @@ .scan_index = num, \ .scan_type = { \ .sign = 's', \ - .realbits = 16, \ - .storagebits = 16, \ + .realbits = (bits), \ + .storagebits = (bits) > 16 ? 32 : 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define AD7606_SW_CHANNEL(num, bits) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = num, \ + .address = num, \ + .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_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_all_available = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .scan_index = num, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = (bits) > 16 ? 32 : 16, \ .endianness = IIO_CPU, \ }, \ } #define AD7605_CHANNEL(num) \ AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ - BIT(IIO_CHAN_INFO_SCALE), 0) + BIT(IIO_CHAN_INFO_SCALE), 0, 16) -#define AD7606_CHANNEL(num) \ +#define AD7606_CHANNEL(num, bits) \ AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \ BIT(IIO_CHAN_INFO_SCALE), \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), bits) + +#define AD7616_CHANNEL(num) AD7606_SW_CHANNEL(num, 16) + +#define AD7606_BI_CHANNEL(num) \ + AD760X_CHANNEL(num, 0, \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), 16) -#define AD7616_CHANNEL(num) \ - AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),\ - 0, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)) +struct ad7606_state; + +typedef int (*ad7606_scale_setup_cb_t)(struct ad7606_state *st, + struct iio_chan_spec *chan, int ch); /** * struct ad7606_chip_info - chip specific information * @channels: channel specification + * @max_samplerate: maximum supported samplerate + * @name device name * @num_channels: number of channels + * @num_adc_channels the number of channels the ADC actually inputs. + * @scale_setup_cb: callback to setup the scales for each channel * @oversampling_avail pointer to the array which stores the available * oversampling ratios. * @oversampling_num number of elements stored in oversampling_avail array * @os_req_reset some devices require a reset to update oversampling - * @init_delay_ms required delay in miliseconds for initialization + * @init_delay_ms required delay in milliseconds for initialization * after a restart */ struct ad7606_chip_info { const struct iio_chan_spec *channels; + unsigned int max_samplerate; + const char *name; + unsigned int num_adc_channels; unsigned int num_channels; + ad7606_scale_setup_cb_t scale_setup_cb; const unsigned int *oversampling_avail; unsigned int oversampling_num; bool os_req_reset; unsigned long init_delay_ms; }; +/** + * struct ad7606_chan_scale - channel scale configuration + * @scale_avail pointer to the array which stores the available scales + * @num_scales number of elements stored in the scale_avail array + * @range voltage range selection, selects which scale to apply + * @reg_offset offset for the register value, to be applied when + * writing the value of 'range' to the register value + */ +struct ad7606_chan_scale { +#define AD760X_MAX_SCALES 16 + const unsigned int (*scale_avail)[2]; + unsigned int num_scales; + unsigned int range; + unsigned int reg_offset; +}; + /** * struct ad7606_state - driver instance specific data * @dev pointer to kernel device * @chip_info entry in the table of chips that describes this device * @bops bus operations (SPI or parallel) - * @range voltage range selection, selects which scale to apply + * @chan_scales scale configuration for channels * @oversampling oversampling selection + * @cnvst_pwm pointer to the PWM device connected to the cnvst pin * @base_address address from where to read data in parallel operation * @sw_mode_en software mode enabled - * @scale_avail pointer to the array which stores the available scales - * @num_scales number of elements stored in the scale_avail array * @oversampling_avail pointer to the array which stores the available * oversampling ratios. * @num_os_ratios number of elements stored in oversampling_avail array @@ -92,14 +149,14 @@ struct ad7606_state { struct device *dev; const struct ad7606_chip_info *chip_info; const struct ad7606_bus_ops *bops; - unsigned int range[16]; + struct ad7606_chan_scale chan_scales[AD760X_MAX_CHANNELS]; unsigned int oversampling; + struct pwm_device *cnvst_pwm; void __iomem *base_address; bool sw_mode_en; - const unsigned int *scale_avail; - unsigned int num_scales; const unsigned int *oversampling_avail; unsigned int num_os_ratios; + struct iio_backend *back; int (*write_scale)(struct iio_dev *indio_dev, int ch, int val); int (*write_os)(struct iio_dev *indio_dev, int val); @@ -116,24 +173,33 @@ struct ad7606_state { /* * DMA (thus cache coherency maintenance) may require the * transfer buffers to live in their own cache lines. - * 16 * 16-bit samples + 64-bit timestamp + * 16 * 16-bit samples + 64-bit timestamp - for AD7616 + * 8 * 32-bit samples + 64-bit timestamp - for AD7616C-18 (and similar) */ - unsigned short data[20] __aligned(IIO_DMA_MINALIGN); + union { + u16 buf16[20]; + u32 buf32[10]; + } data __aligned(IIO_DMA_MINALIGN); __be16 d16[2]; }; /** * struct ad7606_bus_ops - driver bus operations + * @iio_backend_config function pointer for configuring the iio_backend for + * the compatibles that use it * @read_block function pointer for reading blocks of data * @sw_mode_config: pointer to a function which configured the device * for software mode * @reg_read function pointer for reading spi register * @reg_write function pointer for writing spi register * @write_mask function pointer for write spi register with mask + * @update_scan_mode function pointer for handling the calls to iio_info's update_scan + * mode when enabling/disabling channels. * @rd_wr_cmd pointer to the function which calculates the spi address */ struct ad7606_bus_ops { /* more methods added in future? */ + int (*iio_backend_config)(struct device *dev, struct iio_dev *indio_dev); int (*read_block)(struct device *dev, int num, void *data); int (*sw_mode_config)(struct iio_dev *indio_dev); int (*reg_read)(struct ad7606_state *st, unsigned int addr); @@ -144,23 +210,37 @@ struct ad7606_bus_ops { unsigned int addr, unsigned long mask, unsigned int val); + int (*update_scan_mode)(struct iio_dev *indio_dev, const unsigned long *scan_mask); u16 (*rd_wr_cmd)(int addr, char isWriteOp); }; +/** + * struct ad7606_bus_info - agregate ad7606_chip_info and ad7606_bus_ops + * @chip_info entry in the table of chips that describes this device + * @bops bus operations (SPI or parallel) + */ +struct ad7606_bus_info { + const struct ad7606_chip_info *chip_info; + const struct ad7606_bus_ops *bops; +}; + int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, - const char *name, unsigned int id, + const struct ad7606_chip_info *info, const struct ad7606_bus_ops *bops); int ad7606_reset(struct ad7606_state *st); -enum ad7606_supported_device_ids { - ID_AD7605_4, - ID_AD7606_8, - ID_AD7606_6, - ID_AD7606_4, - ID_AD7606B, - ID_AD7616, -}; +extern const struct ad7606_chip_info ad7605_4_info; +extern const struct ad7606_chip_info ad7606_8_info; +extern const struct ad7606_chip_info ad7606_6_info; +extern const struct ad7606_chip_info ad7606_4_info; +extern const struct ad7606_chip_info ad7606b_info; +extern const struct ad7606_chip_info ad7606c_16_info; +extern const struct ad7606_chip_info ad7606c_18_info; +extern const struct ad7606_chip_info ad7607_info; +extern const struct ad7606_chip_info ad7608_info; +extern const struct ad7606_chip_info ad7609_info; +extern const struct ad7606_chip_info ad7616_info; #ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops ad7606_pm_ops; diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c index 02d8c309304e24..64733b607aa87a 100644 --- a/drivers/iio/adc/ad7606_par.c +++ b/drivers/iio/adc/ad7606_par.c @@ -2,20 +2,95 @@ /* * AD7606 Parallel Interface ADC driver * - * Copyright 2011 Analog Devices Inc. + * Copyright 2011 - 2024 Analog Devices Inc. + * Copyright 2024 BayLibre SAS. */ +#include +#include +#include #include #include -#include #include +#include #include -#include -#include +#include #include + #include "ad7606.h" +static const struct iio_chan_spec ad7606b_bi_channels[] = { + AD7606_BI_CHANNEL(0), + AD7606_BI_CHANNEL(1), + AD7606_BI_CHANNEL(2), + AD7606_BI_CHANNEL(3), + AD7606_BI_CHANNEL(4), + AD7606_BI_CHANNEL(5), + AD7606_BI_CHANNEL(6), + AD7606_BI_CHANNEL(7), +}; + +static int ad7606_bi_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned int c, ret; + + for (c = 0; c < indio_dev->num_channels; c++) { + if (test_bit(c, scan_mask)) + ret = iio_backend_chan_enable(st->back, c); + else + ret = iio_backend_chan_disable(st->back, c); + if (ret) + return ret; + } + + return 0; +} + +static int ad7606_bi_setup_iio_backend(struct device *dev, struct iio_dev *indio_dev) +{ + struct ad7606_state *st = iio_priv(indio_dev); + unsigned int ret, c; + struct iio_backend_data_fmt data = { + .sign_extend = true, + .enable = true, + }; + + st->back = devm_iio_backend_get(dev, NULL); + if (IS_ERR(st->back)) + return PTR_ERR(st->back); + + /* If the device is iio_backend powered the PWM is mandatory */ + if (!st->cnvst_pwm) + return dev_err_probe(st->dev, -EINVAL, + "A PWM is mandatory when using backend.\n"); + + ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); + if (ret) + return ret; + + ret = devm_iio_backend_enable(dev, st->back); + if (ret) + return ret; + + for (c = 0; c < indio_dev->num_channels; c++) { + ret = iio_backend_data_format_set(st->back, c, &data); + if (ret) + return ret; + } + + indio_dev->channels = ad7606b_bi_channels; + indio_dev->num_channels = 8; + + return 0; +} + +static const struct ad7606_bus_ops ad7606_bi_bops = { + .iio_backend_config = ad7606_bi_setup_iio_backend, + .update_scan_mode = ad7606_bi_update_scan_mode, +}; + static int ad7606_par16_read_block(struct device *dev, int count, void *buf) { @@ -89,12 +164,32 @@ static const struct ad7606_bus_ops ad7606_par8_bops = { static int ad7606_par_probe(struct platform_device *pdev) { - const struct platform_device_id *id = platform_get_device_id(pdev); + const struct ad7606_chip_info *chip_info; + const struct platform_device_id *id; struct resource *res; void __iomem *addr; resource_size_t remap_size; int irq; + /* + * If a firmware node is available (ACPI or DT), platform_device_id is null + * and we must use get_match_data. + */ + if (dev_fwnode(&pdev->dev)) { + chip_info = device_get_match_data(&pdev->dev); + if (device_property_present(&pdev->dev, "io-backends")) + /* + * If a backend is available ,call the core probe with backend + * bops, otherwise use the former bops. + */ + return ad7606_probe(&pdev->dev, 0, NULL, + chip_info, + &ad7606_bi_bops); + } else { + id = platform_get_device_id(pdev); + chip_info = (const struct ad7606_chip_info *)id->driver_data; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -105,26 +200,33 @@ static int ad7606_par_probe(struct platform_device *pdev) remap_size = resource_size(res); - return ad7606_probe(&pdev->dev, irq, addr, - id->name, id->driver_data, + return ad7606_probe(&pdev->dev, irq, addr, chip_info, remap_size > 1 ? &ad7606_par16_bops : &ad7606_par8_bops); } static const struct platform_device_id ad7606_driver_ids[] = { - { .name = "ad7605-4", .driver_data = ID_AD7605_4, }, - { .name = "ad7606-4", .driver_data = ID_AD7606_4, }, - { .name = "ad7606-6", .driver_data = ID_AD7606_6, }, - { .name = "ad7606-8", .driver_data = ID_AD7606_8, }, + { .name = "ad7605-4", .driver_data = (kernel_ulong_t)&ad7605_4_info, }, + { .name = "ad7606-4", .driver_data = (kernel_ulong_t)&ad7606_4_info, }, + { .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_info, }, + { .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_info, }, + { .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_info, }, + { .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_info, }, + { .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_info, }, + { .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_info, }, { } }; MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); static const struct of_device_id ad7606_of_match[] = { - { .compatible = "adi,ad7605-4" }, - { .compatible = "adi,ad7606-4" }, - { .compatible = "adi,ad7606-6" }, - { .compatible = "adi,ad7606-8" }, + { .compatible = "adi,ad7605-4", .data = &ad7605_4_info }, + { .compatible = "adi,ad7606-4", .data = &ad7606_4_info }, + { .compatible = "adi,ad7606-6", .data = &ad7606_6_info }, + { .compatible = "adi,ad7606-8", .data = &ad7606_8_info }, + { .compatible = "adi,ad7606b", .data = &ad7606b_info }, + { .compatible = "adi,ad7607", .data = &ad7607_info }, + { .compatible = "adi,ad7608", .data = &ad7608_info }, + { .compatible = "adi,ad7609", .data = &ad7609_info }, { } }; MODULE_DEVICE_TABLE(of, ad7606_of_match); @@ -143,4 +245,5 @@ module_platform_driver(ad7606_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD7606); +MODULE_IMPORT_NS("IIO_AD7606"); +MODULE_IMPORT_NS("IIO_BACKEND"); diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c index 62ec1219530799..e2c1475257065c 100644 --- a/drivers/iio/adc/ad7606_spi.c +++ b/drivers/iio/adc/ad7606_spi.c @@ -5,10 +5,10 @@ * Copyright 2011 Analog Devices Inc. */ +#include #include #include #include -#include #include #include "ad7606.h" @@ -67,14 +67,26 @@ static const struct iio_chan_spec ad7616_sw_channels[] = { static const struct iio_chan_spec ad7606b_sw_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(8), - AD7616_CHANNEL(0), - AD7616_CHANNEL(1), - AD7616_CHANNEL(2), - AD7616_CHANNEL(3), - AD7616_CHANNEL(4), - AD7616_CHANNEL(5), - AD7616_CHANNEL(6), - AD7616_CHANNEL(7), + AD7606_SW_CHANNEL(0, 16), + AD7606_SW_CHANNEL(1, 16), + AD7606_SW_CHANNEL(2, 16), + AD7606_SW_CHANNEL(3, 16), + AD7606_SW_CHANNEL(4, 16), + AD7606_SW_CHANNEL(5, 16), + AD7606_SW_CHANNEL(6, 16), + AD7606_SW_CHANNEL(7, 16), +}; + +static const struct iio_chan_spec ad7606c_18_sw_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(8), + AD7606_SW_CHANNEL(0, 18), + AD7606_SW_CHANNEL(1, 18), + AD7606_SW_CHANNEL(2, 18), + AD7606_SW_CHANNEL(3, 18), + AD7606_SW_CHANNEL(4, 18), + AD7606_SW_CHANNEL(5, 18), + AD7606_SW_CHANNEL(6, 18), + AD7606_SW_CHANNEL(7, 18), }; static const unsigned int ad7606B_oversampling_avail[9] = { @@ -120,6 +132,32 @@ static int ad7606_spi_read_block(struct device *dev, return 0; } +static int ad7606_spi_read_block14to16(struct device *dev, + int count, void *buf) +{ + struct spi_device *spi = to_spi_device(dev); + struct spi_transfer xfer = { + .bits_per_word = 14, + .len = count * sizeof(u16), + .rx_buf = buf, + }; + + return spi_sync_transfer(spi, &xfer, 1); +} + +static int ad7606_spi_read_block18to32(struct device *dev, + int count, void *buf) +{ + struct spi_device *spi = to_spi_device(dev); + struct spi_transfer xfer = { + .bits_per_word = 18, + .len = count * sizeof(u32), + .rx_buf = buf, + }; + + return spi_sync_transfer(spi, &xfer, 1); +} + static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr) { struct spi_device *spi = to_spi_device(st->dev); @@ -283,10 +321,31 @@ static int ad7606B_sw_mode_config(struct iio_dev *indio_dev) return 0; } +static int ad7606c_18_sw_mode_config(struct iio_dev *indio_dev) +{ + int ret; + + ret = ad7606B_sw_mode_config(indio_dev); + if (ret) + return ret; + + indio_dev->channels = ad7606c_18_sw_channels; + + return 0; +} + static const struct ad7606_bus_ops ad7606_spi_bops = { .read_block = ad7606_spi_read_block, }; +static const struct ad7606_bus_ops ad7607_spi_bops = { + .read_block = ad7606_spi_read_block14to16, +}; + +static const struct ad7606_bus_ops ad7608_spi_bops = { + .read_block = ad7606_spi_read_block18to32, +}; + static const struct ad7606_bus_ops ad7616_spi_bops = { .read_block = ad7606_spi_read_block, .reg_read = ad7606_spi_reg_read, @@ -296,7 +355,7 @@ static const struct ad7606_bus_ops ad7616_spi_bops = { .sw_mode_config = ad7616_sw_mode_config, }; -static const struct ad7606_bus_ops ad7606B_spi_bops = { +static const struct ad7606_bus_ops ad7606b_spi_bops = { .read_block = ad7606_spi_read_block, .reg_read = ad7606_spi_reg_read, .reg_write = ad7606_spi_reg_write, @@ -305,46 +364,106 @@ static const struct ad7606_bus_ops ad7606B_spi_bops = { .sw_mode_config = ad7606B_sw_mode_config, }; +static const struct ad7606_bus_ops ad7606c_18_spi_bops = { + .read_block = ad7606_spi_read_block18to32, + .reg_read = ad7606_spi_reg_read, + .reg_write = ad7606_spi_reg_write, + .write_mask = ad7606_spi_write_mask, + .rd_wr_cmd = ad7606B_spi_rd_wr_cmd, + .sw_mode_config = ad7606c_18_sw_mode_config, +}; + +static const struct ad7606_bus_info ad7605_4_bus_info = { + .chip_info = &ad7605_4_info, + .bops = &ad7606_spi_bops, +}; + +static const struct ad7606_bus_info ad7606_8_bus_info = { + .chip_info = &ad7606_8_info, + .bops = &ad7606_spi_bops, +}; + +static const struct ad7606_bus_info ad7606_6_bus_info = { + .chip_info = &ad7606_6_info, + .bops = &ad7606_spi_bops, +}; + +static const struct ad7606_bus_info ad7606_4_bus_info = { + .chip_info = &ad7606_4_info, + .bops = &ad7606_spi_bops, +}; + +static const struct ad7606_bus_info ad7606b_bus_info = { + .chip_info = &ad7606b_info, + .bops = &ad7606b_spi_bops, +}; + +static const struct ad7606_bus_info ad7606c_16_bus_info = { + .chip_info = &ad7606c_16_info, + .bops = &ad7606b_spi_bops, +}; + +static const struct ad7606_bus_info ad7606c_18_bus_info = { + .chip_info = &ad7606c_18_info, + .bops = &ad7606c_18_spi_bops, +}; + +static const struct ad7606_bus_info ad7607_bus_info = { + .chip_info = &ad7607_info, + .bops = &ad7607_spi_bops, +}; + +static const struct ad7606_bus_info ad7608_bus_info = { + .chip_info = &ad7608_info, + .bops = &ad7608_spi_bops, +}; + +static const struct ad7606_bus_info ad7609_bus_info = { + .chip_info = &ad7609_info, + .bops = &ad7608_spi_bops, +}; + +static const struct ad7606_bus_info ad7616_bus_info = { + .chip_info = &ad7616_info, + .bops = &ad7616_spi_bops, +}; + static int ad7606_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); - const struct ad7606_bus_ops *bops; - - switch (id->driver_data) { - case ID_AD7616: - bops = &ad7616_spi_bops; - break; - case ID_AD7606B: - bops = &ad7606B_spi_bops; - break; - default: - bops = &ad7606_spi_bops; - break; - } + const struct ad7606_bus_info *bus_info = spi_get_device_match_data(spi); return ad7606_probe(&spi->dev, spi->irq, NULL, - id->name, id->driver_data, - bops); + bus_info->chip_info, bus_info->bops); } static const struct spi_device_id ad7606_id_table[] = { - { "ad7605-4", ID_AD7605_4 }, - { "ad7606-4", ID_AD7606_4 }, - { "ad7606-6", ID_AD7606_6 }, - { "ad7606-8", ID_AD7606_8 }, - { "ad7606b", ID_AD7606B }, - { "ad7616", ID_AD7616 }, + { "ad7605-4", (kernel_ulong_t)&ad7605_4_bus_info }, + { "ad7606-4", (kernel_ulong_t)&ad7606_4_bus_info }, + { "ad7606-6", (kernel_ulong_t)&ad7606_6_bus_info }, + { "ad7606-8", (kernel_ulong_t)&ad7606_8_bus_info }, + { "ad7606b", (kernel_ulong_t)&ad7606b_bus_info }, + { "ad7606c-16", (kernel_ulong_t)&ad7606c_16_bus_info }, + { "ad7606c-18", (kernel_ulong_t)&ad7606c_18_bus_info }, + { "ad7607", (kernel_ulong_t)&ad7607_bus_info }, + { "ad7608", (kernel_ulong_t)&ad7608_bus_info }, + { "ad7609", (kernel_ulong_t)&ad7609_bus_info }, + { "ad7616", (kernel_ulong_t)&ad7616_bus_info }, { } }; MODULE_DEVICE_TABLE(spi, ad7606_id_table); static const struct of_device_id ad7606_of_match[] = { - { .compatible = "adi,ad7605-4" }, - { .compatible = "adi,ad7606-4" }, - { .compatible = "adi,ad7606-6" }, - { .compatible = "adi,ad7606-8" }, - { .compatible = "adi,ad7606b" }, - { .compatible = "adi,ad7616" }, + { .compatible = "adi,ad7605-4", .data = &ad7605_4_bus_info }, + { .compatible = "adi,ad7606-4", .data = &ad7606_4_bus_info }, + { .compatible = "adi,ad7606-6", .data = &ad7606_6_bus_info }, + { .compatible = "adi,ad7606-8", .data = &ad7606_8_bus_info }, + { .compatible = "adi,ad7606b", .data = &ad7606b_bus_info }, + { .compatible = "adi,ad7606c-16", .data = &ad7606c_16_bus_info }, + { .compatible = "adi,ad7606c-18", .data = &ad7606c_18_bus_info }, + { .compatible = "adi,ad7607", .data = &ad7607_bus_info }, + { .compatible = "adi,ad7608", .data = &ad7608_bus_info }, + { .compatible = "adi,ad7609", .data = &ad7609_bus_info }, + { .compatible = "adi,ad7616", .data = &ad7616_bus_info }, { } }; MODULE_DEVICE_TABLE(of, ad7606_of_match); @@ -363,4 +482,4 @@ module_spi_driver(ad7606_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD7606); +MODULE_IMPORT_NS("IIO_AD7606"); diff --git a/drivers/iio/adc/ad7625.c b/drivers/iio/adc/ad7625.c new file mode 100644 index 00000000000000..aefe3bf75c9147 --- /dev/null +++ b/drivers/iio/adc/ad7625.c @@ -0,0 +1,684 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +/* + * Analog Devices Inc. AD7625 ADC driver + * + * Copyright 2024 Analog Devices Inc. + * Copyright 2024 BayLibre, SAS + * + * Note that this driver requires the AXI ADC IP block configured for + * LVDS to function. See Documentation/iio/ad7625.rst for more + * information. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AD7625_INTERNAL_REF_MV 4096 +#define AD7960_MAX_NBW_FREQ (2 * MEGA) + +struct ad7625_timing_spec { + /* Max conversion high time (t_{CNVH}). */ + unsigned int conv_high_ns; + /* Max conversion to MSB delay (t_{MSB}). */ + unsigned int conv_msb_ns; +}; + +struct ad7625_chip_info { + const char *name; + const unsigned int max_sample_freq_hz; + const struct ad7625_timing_spec *timing_spec; + const struct iio_chan_spec chan_spec; + const bool has_power_down_state; + const bool has_bandwidth_control; + const bool has_internal_vref; +}; + +/* AD7625_CHAN_SPEC - Define a chan spec structure for a specific chip */ +#define AD7625_CHAN_SPEC(_bits) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .differential = 1, \ + .channel = 0, \ + .channel2 = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = 0, \ + .scan_type.sign = 's', \ + .scan_type.storagebits = (_bits) > 16 ? 32 : 16, \ + .scan_type.realbits = (_bits), \ +} + +struct ad7625_state { + const struct ad7625_chip_info *info; + struct iio_backend *back; + /* rate of the clock gated by the "clk_gate" PWM */ + u32 ref_clk_rate_hz; + /* PWM burst signal for transferring acquired data to the host */ + struct pwm_device *clk_gate_pwm; + /* + * PWM control signal for initiating data conversion. Analog + * inputs are sampled beginning on this signal's rising edge. + */ + struct pwm_device *cnv_pwm; + /* + * Waveforms containing the last-requested and rounded + * properties for the clk_gate and cnv PWMs + */ + struct pwm_waveform clk_gate_wf; + struct pwm_waveform cnv_wf; + unsigned int vref_mv; + u32 sampling_freq_hz; + /* + * Optional GPIOs for controlling device state. EN0 and EN1 + * determine voltage reference configuration and on/off state. + * EN2 controls the device -3dB bandwidth (and by extension, max + * sample rate). EN3 controls the VCM reference output. EN2 and + * EN3 are only present for the AD796x devices. + */ + struct gpio_desc *en_gpios[4]; + bool can_power_down; + bool can_refin; + bool can_ref_4v096; + /* + * Indicate whether the bandwidth can be narrow (9MHz). + * When true, device sample rate must also be < 2MSPS. + */ + bool can_narrow_bandwidth; + /* Indicate whether the bandwidth can be wide (28MHz). */ + bool can_wide_bandwidth; + bool can_ref_5v; + bool can_snooze; + bool can_test_pattern; + /* Indicate whether there is a REFIN supply connected */ + bool have_refin; +}; + +static const struct ad7625_timing_spec ad7625_timing_spec = { + .conv_high_ns = 40, + .conv_msb_ns = 145, +}; + +static const struct ad7625_timing_spec ad7626_timing_spec = { + .conv_high_ns = 40, + .conv_msb_ns = 80, +}; + +/* + * conv_msb_ns is set to 0 instead of the datasheet maximum of 200ns to + * avoid exceeding the minimum conversion time, i.e. it is effectively + * modulo 200 and offset by a full period. Values greater than or equal + * to the period would be rejected by the PWM API. + */ +static const struct ad7625_timing_spec ad7960_timing_spec = { + .conv_high_ns = 80, + .conv_msb_ns = 0, +}; + +static const struct ad7625_chip_info ad7625_chip_info = { + .name = "ad7625", + .max_sample_freq_hz = 6 * MEGA, + .timing_spec = &ad7625_timing_spec, + .chan_spec = AD7625_CHAN_SPEC(16), + .has_power_down_state = false, + .has_bandwidth_control = false, + .has_internal_vref = true, +}; + +static const struct ad7625_chip_info ad7626_chip_info = { + .name = "ad7626", + .max_sample_freq_hz = 10 * MEGA, + .timing_spec = &ad7626_timing_spec, + .chan_spec = AD7625_CHAN_SPEC(16), + .has_power_down_state = true, + .has_bandwidth_control = false, + .has_internal_vref = true, +}; + +static const struct ad7625_chip_info ad7960_chip_info = { + .name = "ad7960", + .max_sample_freq_hz = 5 * MEGA, + .timing_spec = &ad7960_timing_spec, + .chan_spec = AD7625_CHAN_SPEC(18), + .has_power_down_state = true, + .has_bandwidth_control = true, + .has_internal_vref = false, +}; + +static const struct ad7625_chip_info ad7961_chip_info = { + .name = "ad7961", + .max_sample_freq_hz = 5 * MEGA, + .timing_spec = &ad7960_timing_spec, + .chan_spec = AD7625_CHAN_SPEC(16), + .has_power_down_state = true, + .has_bandwidth_control = true, + .has_internal_vref = false, +}; + +enum ad7960_mode { + AD7960_MODE_POWER_DOWN, + AD7960_MODE_SNOOZE, + AD7960_MODE_NARROW_BANDWIDTH, + AD7960_MODE_WIDE_BANDWIDTH, + AD7960_MODE_TEST_PATTERN, +}; + +static int ad7625_set_sampling_freq(struct ad7625_state *st, u32 freq) +{ + u32 target; + struct pwm_waveform clk_gate_wf = { }, cnv_wf = { }; + int ret; + + target = DIV_ROUND_UP(NSEC_PER_SEC, freq); + cnv_wf.period_length_ns = clamp(target, 100, 10 * KILO); + + /* + * Use the maximum conversion time t_CNVH from the datasheet as + * the duty_cycle for ref_clk, cnv, and clk_gate + */ + cnv_wf.duty_length_ns = st->info->timing_spec->conv_high_ns; + + ret = pwm_round_waveform_might_sleep(st->cnv_pwm, &cnv_wf); + if (ret) + return ret; + + /* + * Set up the burst signal for transferring data. period and + * offset should mirror the CNV signal + */ + clk_gate_wf.period_length_ns = cnv_wf.period_length_ns; + + clk_gate_wf.duty_length_ns = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC * + st->info->chan_spec.scan_type.realbits, + st->ref_clk_rate_hz); + + /* max t_MSB from datasheet */ + clk_gate_wf.duty_offset_ns = st->info->timing_spec->conv_msb_ns; + + ret = pwm_round_waveform_might_sleep(st->clk_gate_pwm, &clk_gate_wf); + if (ret) + return ret; + + st->cnv_wf = cnv_wf; + st->clk_gate_wf = clk_gate_wf; + + /* TODO: Add a rounding API for PWMs that can simplify this */ + target = DIV_ROUND_CLOSEST(st->ref_clk_rate_hz, freq); + st->sampling_freq_hz = DIV_ROUND_CLOSEST(st->ref_clk_rate_hz, + target); + + return 0; +} + +static int ad7625_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long info) +{ + struct ad7625_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->sampling_freq_hz; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = st->vref_mv; + *val2 = chan->scan_type.realbits - 1; + + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } +} + +static int ad7625_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long info) +{ + struct ad7625_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_SAMP_FREQ: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return ad7625_set_sampling_freq(st, val); + unreachable(); + default: + return -EINVAL; + } +} + +static int ad7625_parse_mode(struct device *dev, struct ad7625_state *st, + int num_gpios) +{ + bool en_always_on[4], en_always_off[4]; + bool en_may_be_on[4], en_may_be_off[4]; + char en_gpio_buf[4]; + char always_on_buf[18]; + int i; + + for (i = 0; i < num_gpios; i++) { + snprintf(en_gpio_buf, sizeof(en_gpio_buf), "en%d", i); + snprintf(always_on_buf, sizeof(always_on_buf), + "adi,en%d-always-on", i); + /* Set the device to 0b0000 (power-down mode) by default */ + st->en_gpios[i] = devm_gpiod_get_optional(dev, en_gpio_buf, + GPIOD_OUT_LOW); + if (IS_ERR(st->en_gpios[i])) + return dev_err_probe(dev, PTR_ERR(st->en_gpios[i]), + "failed to get EN%d GPIO\n", i); + + en_always_on[i] = device_property_read_bool(dev, always_on_buf); + if (st->en_gpios[i] && en_always_on[i]) + return dev_err_probe(dev, -EINVAL, + "cannot have adi,en%d-always-on and en%d-gpios\n", i, i); + + en_may_be_off[i] = !en_always_on[i]; + en_may_be_on[i] = en_always_on[i] || st->en_gpios[i]; + en_always_off[i] = !en_always_on[i] && !st->en_gpios[i]; + } + + /* + * Power down is mode 0bXX00, but not all devices have a valid + * power down state. + */ + st->can_power_down = en_may_be_off[1] && en_may_be_off[0] && + st->info->has_power_down_state; + /* + * The REFIN pin can take a 1.2V (AD762x) or 2.048V (AD796x) + * external reference when the mode is 0bXX01. + */ + st->can_refin = en_may_be_off[1] && en_may_be_on[0]; + /* 4.096V can be applied to REF when the EN mode is 0bXX10. */ + st->can_ref_4v096 = en_may_be_on[1] && en_may_be_off[0]; + + /* Avoid AD796x-specific setup if the part is an AD762x */ + if (num_gpios == 2) + return 0; + + /* mode 0b1100 (AD796x) is invalid */ + if (en_always_on[3] && en_always_on[2] && + en_always_off[1] && en_always_off[0]) + return dev_err_probe(dev, -EINVAL, + "EN GPIOs set to invalid mode 0b1100\n"); + /* + * 5V can be applied to the AD796x REF pin when the EN mode is + * the same (0bX001 or 0bX101) as for can_refin, and REFIN is + * 0V. + */ + st->can_ref_5v = st->can_refin; + /* + * Bandwidth (AD796x) is controlled solely by EN2. If it's + * specified and not hard-wired, then we can configure it to + * change the bandwidth between 28MHz and 9MHz. + */ + st->can_narrow_bandwidth = en_may_be_on[2]; + /* Wide bandwidth mode is possible if EN2 can be 0. */ + st->can_wide_bandwidth = en_may_be_off[2]; + /* Snooze mode (AD796x) is 0bXX11 when REFIN = 0V. */ + st->can_snooze = en_may_be_on[1] && en_may_be_on[0]; + /* Test pattern mode (AD796x) is 0b0100. */ + st->can_test_pattern = en_may_be_off[3] && en_may_be_on[2] && + en_may_be_off[1] && en_may_be_off[0]; + + return 0; +} + +/* Set EN1 and EN0 based on reference voltage source */ +static void ad7625_set_en_gpios_for_vref(struct ad7625_state *st, + bool have_refin, int ref_mv) +{ + if (have_refin || ref_mv == 5000) { + gpiod_set_value_cansleep(st->en_gpios[1], 0); + gpiod_set_value_cansleep(st->en_gpios[0], 1); + } else if (ref_mv == 4096) { + gpiod_set_value_cansleep(st->en_gpios[1], 1); + gpiod_set_value_cansleep(st->en_gpios[0], 0); + } else { + /* + * Unreachable by AD796x, since the driver will error if + * neither REF nor REFIN is provided + */ + gpiod_set_value_cansleep(st->en_gpios[1], 1); + gpiod_set_value_cansleep(st->en_gpios[0], 1); + } +} + +static int ad7960_set_mode(struct ad7625_state *st, enum ad7960_mode mode, + bool have_refin, int ref_mv) +{ + switch (mode) { + case AD7960_MODE_POWER_DOWN: + if (!st->can_power_down) + return -EINVAL; + + gpiod_set_value_cansleep(st->en_gpios[2], 0); + gpiod_set_value_cansleep(st->en_gpios[1], 0); + gpiod_set_value_cansleep(st->en_gpios[0], 0); + + return 0; + + case AD7960_MODE_SNOOZE: + if (!st->can_snooze) + return -EINVAL; + + gpiod_set_value_cansleep(st->en_gpios[1], 1); + gpiod_set_value_cansleep(st->en_gpios[0], 1); + + return 0; + + case AD7960_MODE_NARROW_BANDWIDTH: + if (!st->can_narrow_bandwidth) + return -EINVAL; + + gpiod_set_value_cansleep(st->en_gpios[2], 1); + ad7625_set_en_gpios_for_vref(st, have_refin, ref_mv); + + return 0; + + case AD7960_MODE_WIDE_BANDWIDTH: + if (!st->can_wide_bandwidth) + return -EINVAL; + + gpiod_set_value_cansleep(st->en_gpios[2], 0); + ad7625_set_en_gpios_for_vref(st, have_refin, ref_mv); + + return 0; + + case AD7960_MODE_TEST_PATTERN: + if (!st->can_test_pattern) + return -EINVAL; + + gpiod_set_value_cansleep(st->en_gpios[3], 0); + gpiod_set_value_cansleep(st->en_gpios[2], 1); + gpiod_set_value_cansleep(st->en_gpios[1], 0); + gpiod_set_value_cansleep(st->en_gpios[0], 0); + + return 0; + + default: + return -EINVAL; + } +} + +static int ad7625_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad7625_state *st = iio_priv(indio_dev); + int ret; + + ret = pwm_set_waveform_might_sleep(st->cnv_pwm, &st->cnv_wf, false); + if (ret) + return ret; + + ret = pwm_set_waveform_might_sleep(st->clk_gate_pwm, + &st->clk_gate_wf, false); + if (ret) { + /* Disable cnv PWM if clk_gate setup failed */ + pwm_disable(st->cnv_pwm); + return ret; + } + + return 0; +} + +static int ad7625_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad7625_state *st = iio_priv(indio_dev); + + pwm_disable(st->clk_gate_pwm); + pwm_disable(st->cnv_pwm); + + return 0; +} + +static const struct iio_info ad7625_info = { + .read_raw = ad7625_read_raw, + .write_raw = ad7625_write_raw, +}; + +static const struct iio_buffer_setup_ops ad7625_buffer_setup_ops = { + .preenable = &ad7625_buffer_preenable, + .postdisable = &ad7625_buffer_postdisable, +}; + +static int devm_ad7625_pwm_get(struct device *dev, + struct ad7625_state *st) +{ + struct clk *ref_clk; + u32 ref_clk_rate_hz; + + st->cnv_pwm = devm_pwm_get(dev, "cnv"); + if (IS_ERR(st->cnv_pwm)) + return dev_err_probe(dev, PTR_ERR(st->cnv_pwm), + "failed to get cnv pwm\n"); + + /* Preemptively disable the PWM in case it was enabled at boot */ + pwm_disable(st->cnv_pwm); + + st->clk_gate_pwm = devm_pwm_get(dev, "clk_gate"); + if (IS_ERR(st->clk_gate_pwm)) + return dev_err_probe(dev, PTR_ERR(st->clk_gate_pwm), + "failed to get clk_gate pwm\n"); + + /* Preemptively disable the PWM in case it was enabled at boot */ + pwm_disable(st->clk_gate_pwm); + + ref_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(ref_clk)) + return dev_err_probe(dev, PTR_ERR(ref_clk), + "failed to get ref_clk"); + + ref_clk_rate_hz = clk_get_rate(ref_clk); + if (!ref_clk_rate_hz) + return dev_err_probe(dev, -EINVAL, + "failed to get ref_clk rate"); + + st->ref_clk_rate_hz = ref_clk_rate_hz; + + return 0; +} + +/* + * There are three required input voltages for each device, plus two + * conditionally-optional (depending on part) REF and REFIN voltages + * where their validity depends upon the EN pin configuration. + * + * Power-up info for the device says to bring up vio, then vdd2, then + * vdd1, so list them in that order in the regulator_names array. + * + * The reference voltage source is determined like so: + * - internal reference: neither REF or REFIN is connected (invalid for + * AD796x) + * - internal buffer, external reference: REF not connected, REFIN + * connected + * - external reference: REF connected, REFIN not connected + */ +static int devm_ad7625_regulator_setup(struct device *dev, + struct ad7625_state *st) +{ + static const char * const regulator_names[] = { "vio", "vdd2", "vdd1" }; + int ret, ref_mv; + + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), + regulator_names); + if (ret) + return ret; + + ret = devm_regulator_get_enable_read_voltage(dev, "ref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get REF voltage\n"); + + ref_mv = ret == -ENODEV ? 0 : ret / 1000; + + ret = devm_regulator_get_enable_optional(dev, "refin"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "failed to get REFIN voltage\n"); + + st->have_refin = ret != -ENODEV; + + if (st->have_refin && !st->can_refin) + return dev_err_probe(dev, -EINVAL, + "REFIN provided in unsupported mode\n"); + + if (!st->info->has_internal_vref && !st->have_refin && !ref_mv) + return dev_err_probe(dev, -EINVAL, + "Need either REFIN or REF"); + + if (st->have_refin && ref_mv) + return dev_err_probe(dev, -EINVAL, + "cannot have both REFIN and REF supplies\n"); + + if (ref_mv == 4096 && !st->can_ref_4v096) + return dev_err_probe(dev, -EINVAL, + "REF is 4.096V in unsupported mode\n"); + + if (ref_mv == 5000 && !st->can_ref_5v) + return dev_err_probe(dev, -EINVAL, + "REF is 5V in unsupported mode\n"); + + st->vref_mv = ref_mv ?: AD7625_INTERNAL_REF_MV; + + return 0; +} + +static int ad7625_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct ad7625_state *st; + int ret; + u32 default_sample_freq; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + st->info = device_get_match_data(dev); + if (!st->info) + return dev_err_probe(dev, -EINVAL, "no chip info\n"); + + if (device_property_read_bool(dev, "adi,no-dco")) + return dev_err_probe(dev, -EINVAL, + "self-clocked mode not supported\n"); + + if (st->info->has_bandwidth_control) + ret = ad7625_parse_mode(dev, st, 4); + else + ret = ad7625_parse_mode(dev, st, 2); + + if (ret) + return ret; + + ret = devm_ad7625_regulator_setup(dev, st); + if (ret) + return ret; + + /* Set the device mode based on detected EN configuration. */ + if (!st->info->has_bandwidth_control) { + ad7625_set_en_gpios_for_vref(st, st->have_refin, st->vref_mv); + } else { + /* + * If neither sampling mode is available, then report an error, + * since the other modes are not useful defaults. + */ + if (st->can_wide_bandwidth) { + ret = ad7960_set_mode(st, AD7960_MODE_WIDE_BANDWIDTH, + st->have_refin, st->vref_mv); + } else if (st->can_narrow_bandwidth) { + ret = ad7960_set_mode(st, AD7960_MODE_NARROW_BANDWIDTH, + st->have_refin, st->vref_mv); + } else { + return dev_err_probe(dev, -EINVAL, + "couldn't set device to wide or narrow bandwidth modes\n"); + } + + if (ret) + return dev_err_probe(dev, -EINVAL, + "failed to set EN pins\n"); + } + + ret = devm_ad7625_pwm_get(dev, st); + if (ret) + return ret; + + indio_dev->channels = &st->info->chan_spec; + indio_dev->num_channels = 1; + indio_dev->name = st->info->name; + indio_dev->info = &ad7625_info; + indio_dev->setup_ops = &ad7625_buffer_setup_ops; + + st->back = devm_iio_backend_get(dev, NULL); + if (IS_ERR(st->back)) + return dev_err_probe(dev, PTR_ERR(st->back), + "failed to get IIO backend"); + + ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); + if (ret) + return ret; + + ret = devm_iio_backend_enable(dev, st->back); + if (ret) + return ret; + + /* + * Set the initial sampling frequency to the maximum, unless the + * AD796x device is limited to narrow bandwidth by EN2 == 1, in + * which case the sampling frequency should be limited to 2MSPS + */ + default_sample_freq = st->info->max_sample_freq_hz; + if (st->info->has_bandwidth_control && !st->can_wide_bandwidth) + default_sample_freq = AD7960_MAX_NBW_FREQ; + + ret = ad7625_set_sampling_freq(st, default_sample_freq); + if (ret) + dev_err_probe(dev, ret, + "failed to set valid sampling frequency\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ad7625_of_match[] = { + { .compatible = "adi,ad7625", .data = &ad7625_chip_info }, + { .compatible = "adi,ad7626", .data = &ad7626_chip_info }, + { .compatible = "adi,ad7960", .data = &ad7960_chip_info }, + { .compatible = "adi,ad7961", .data = &ad7961_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad7625_of_match); + +static const struct platform_device_id ad7625_device_ids[] = { + { .name = "ad7625", .driver_data = (kernel_ulong_t)&ad7625_chip_info }, + { .name = "ad7626", .driver_data = (kernel_ulong_t)&ad7626_chip_info }, + { .name = "ad7960", .driver_data = (kernel_ulong_t)&ad7960_chip_info }, + { .name = "ad7961", .driver_data = (kernel_ulong_t)&ad7961_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(platform, ad7625_device_ids); + +static struct platform_driver ad7625_driver = { + .probe = ad7625_probe, + .driver = { + .name = "ad7625", + .of_match_table = ad7625_of_match, + }, + .id_table = ad7625_device_ids, +}; +module_platform_driver(ad7625_driver); + +MODULE_AUTHOR("Trevor Gamblin "); +MODULE_DESCRIPTION("Analog Devices AD7625 ADC"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS("IIO_BACKEND"); diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c new file mode 100644 index 00000000000000..2537dab69a35c9 --- /dev/null +++ b/drivers/iio/adc/ad7779.c @@ -0,0 +1,914 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AD7770, AD7771, AD7779 ADC + * + * Copyright 2023-2024 Analog Devices 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 + +#define AD7779_SPI_READ_CMD BIT(7) + +#define AD7779_DISABLE_SD BIT(7) + +#define AD7779_REG_CH_DISABLE 0x08 +#define AD7779_REG_CH_SYNC_OFFSET(ch) (0x09 + (ch)) +#define AD7779_REG_CH_CONFIG(ch) (0x00 + (ch)) +#define AD7779_REG_GENERAL_USER_CONFIG_1 0x11 +#define AD7779_REG_GENERAL_USER_CONFIG_2 0x12 +#define AD7779_REG_GENERAL_USER_CONFIG_3 0x13 +#define AD7779_REG_DOUT_FORMAT 0x14 +#define AD7779_REG_ADC_MUX_CONFIG 0x15 +#define AD7779_REG_GPIO_CONFIG 0x17 +#define AD7779_REG_BUFFER_CONFIG_1 0x19 +#define AD7779_REG_GLOBAL_MUX_CONFIG 0x16 +#define AD7779_REG_BUFFER_CONFIG_2 0x1A +#define AD7779_REG_GPIO_DATA 0x18 +#define AD7779_REG_CH_OFFSET_UPPER_BYTE(ch) (0x1C + (ch) * 6) +#define AD7779_REG_CH_OFFSET_LOWER_BYTE(ch) (0x1E + (ch) * 6) +#define AD7779_REG_CH_GAIN_UPPER_BYTE(ch) (0x1F + (ch) * 6) +#define AD7779_REG_CH_OFFSET_MID_BYTE(ch) (0x1D + (ch) * 6) +#define AD7779_REG_CH_GAIN_MID_BYTE(ch) (0x20 + (ch) * 6) +#define AD7779_REG_CH_ERR_REG(ch) (0x4C + (ch)) +#define AD7779_REG_CH0_1_SAT_ERR 0x54 +#define AD7779_REG_CH_GAIN_LOWER_BYTE(ch) (0x21 + (ch) * 6) +#define AD7779_REG_CH2_3_SAT_ERR 0x55 +#define AD7779_REG_CH4_5_SAT_ERR 0x56 +#define AD7779_REG_CH6_7_SAT_ERR 0x57 +#define AD7779_REG_CHX_ERR_REG_EN 0x58 +#define AD7779_REG_GEN_ERR_REG_1 0x59 +#define AD7779_REG_GEN_ERR_REG_1_EN 0x5A +#define AD7779_REG_GEN_ERR_REG_2 0x5B +#define AD7779_REG_GEN_ERR_REG_2_EN 0x5C +#define AD7779_REG_STATUS_REG_1 0x5D +#define AD7779_REG_STATUS_REG_2 0x5E +#define AD7779_REG_STATUS_REG_3 0x5F +#define AD7779_REG_SRC_N_MSB 0x60 +#define AD7779_REG_SRC_N_LSB 0x61 +#define AD7779_REG_SRC_IF_MSB 0x62 +#define AD7779_REG_SRC_IF_LSB 0x63 +#define AD7779_REG_SRC_UPDATE 0x64 + +#define AD7779_FILTER_MSK BIT(6) +#define AD7779_MOD_POWERMODE_MSK BIT(6) +#define AD7779_MOD_PDB_REFOUT_MSK BIT(4) +#define AD7779_MOD_SPI_EN_MSK BIT(4) +#define AD7779_USRMOD_INIT_MSK GENMASK(6, 4) + +/* AD7779_REG_DOUT_FORMAT */ +#define AD7779_DOUT_FORMAT_MSK GENMASK(7, 6) +#define AD7779_DOUT_HEADER_FORMAT BIT(5) +#define AD7779_DCLK_CLK_DIV_MSK GENMASK(3, 1) + +#define AD7779_REFMUX_CTRL_MSK GENMASK(7, 6) +#define AD7779_SPI_CRC_EN_MSK BIT(0) + +#define AD7779_MAXCLK_LOWPOWER (4096 * HZ_PER_KHZ) +#define AD7779_NUM_CHANNELS 8 +#define AD7779_RESET_BUF_SIZE 8 +#define AD7779_CHAN_DATA_SIZE 4 + +#define AD7779_LOWPOWER_DIV 512 +#define AD7779_HIGHPOWER_DIV 2048 + +#define AD7779_SINC3_MAXFREQ (16 * HZ_PER_KHZ) +#define AD7779_SINC5_MAXFREQ (128 * HZ_PER_KHZ) + +#define AD7779_DEFAULT_SAMPLING_FREQ (8 * HZ_PER_KHZ) +#define AD7779_DEFAULT_SAMPLING_2LINE (4 * HZ_PER_KHZ) +#define AD7779_DEFAULT_SAMPLING_1LINE (2 * HZ_PER_KHZ) + +#define AD7779_SPIMODE_MAX_SAMP_FREQ (16 * HZ_PER_KHZ) + +#define GAIN_REL 0x555555 +#define AD7779_FREQ_MSB_MSK GENMASK(15, 8) +#define AD7779_FREQ_LSB_MSK GENMASK(7, 0) +#define AD7779_UPPER GENMASK(23, 16) +#define AD7779_MID GENMASK(15, 8) +#define AD7779_LOWER GENMASK(7, 0) + +#define AD7779_REG_MSK GENMASK(6, 0) + +#define AD7779_CRC8_POLY 0x07 +DECLARE_CRC8_TABLE(ad7779_crc8_table); + +enum ad7779_filter { + AD7779_SINC3, + AD7779_SINC5, +}; + +enum ad7779_variant { + ad7770, + ad7771, + ad7779, +}; + +enum ad7779_power_mode { + AD7779_LOW_POWER, + AD7779_HIGH_POWER, +}; + +struct ad7779_chip_info { + const char *name; + struct iio_chan_spec const *channels; +}; + +struct ad7779_state { + struct spi_device *spi; + const struct ad7779_chip_info *chip_info; + struct clk *mclk; + struct iio_trigger *trig; + struct completion completion; + unsigned int sampling_freq; + enum ad7779_filter filter_enabled; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + struct { + u32 chans[8]; + aligned_s64 timestamp; + } data __aligned(IIO_DMA_MINALIGN); + u32 spidata_tx[8]; + u8 reg_rx_buf[3]; + u8 reg_tx_buf[3]; + u8 reset_buf[8]; +}; + +static const char * const ad7779_filter_type[] = { + [AD7779_SINC3] = "sinc3", + [AD7779_SINC5] = "sinc5", +}; + +static const char * const ad7779_power_supplies[] = { + "avdd1", "avdd2", "avdd4", +}; + +static int ad7779_spi_read(struct ad7779_state *st, u8 reg, u8 *rbuf) +{ + int ret; + u8 crc_buf[2]; + u8 exp_crc; + struct spi_transfer t = { + .tx_buf = st->reg_tx_buf, + .rx_buf = st->reg_rx_buf, + }; + + st->reg_tx_buf[0] = AD7779_SPI_READ_CMD | FIELD_GET(AD7779_REG_MSK, reg); + st->reg_tx_buf[1] = 0; + + if (reg == AD7779_REG_GEN_ERR_REG_1_EN) { + t.len = 2; + } else { + t.len = 3; + st->reg_tx_buf[2] = crc8(ad7779_crc8_table, st->reg_tx_buf, + t.len - 1, 0); + } + + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) + return ret; + + crc_buf[0] = AD7779_SPI_READ_CMD | FIELD_GET(AD7779_REG_MSK, reg); + crc_buf[1] = st->reg_rx_buf[1]; + exp_crc = crc8(ad7779_crc8_table, crc_buf, ARRAY_SIZE(crc_buf), 0); + if (reg != AD7779_REG_GEN_ERR_REG_1_EN && exp_crc != st->reg_rx_buf[2]) { + dev_err(&st->spi->dev, "Bad CRC %x, expected %x", + st->reg_rx_buf[2], exp_crc); + return -EINVAL; + } + *rbuf = st->reg_rx_buf[1]; + + return 0; +} + +static int ad7779_spi_write(struct ad7779_state *st, u8 reg, u8 val) +{ + u8 length = 3; + + st->reg_tx_buf[0] = FIELD_GET(AD7779_REG_MSK, reg); + st->reg_tx_buf[1] = val; + if (reg == AD7779_REG_GEN_ERR_REG_1_EN) + length = 2; + else + st->reg_tx_buf[2] = crc8(ad7779_crc8_table, st->reg_tx_buf, + length - 1, 0); + + return spi_write(st->spi, st->reg_tx_buf, length); +} + +static int ad7779_spi_write_mask(struct ad7779_state *st, u8 reg, u8 mask, + u8 val) +{ + int ret; + u8 regval, data; + + ret = ad7779_spi_read(st, reg, &data); + if (ret) + return ret; + + regval = (data & ~mask) | (val & mask); + + if (regval == data) + return 0; + + return ad7779_spi_write(st, reg, regval); +} + +static int ad7779_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ad7779_state *st = iio_priv(indio_dev); + u8 rval; + int ret; + + if (readval) { + ret = ad7779_spi_read(st, reg, &rval); + *readval = rval; + return ret; + } + + return ad7779_spi_write(st, reg, writeval); +} + +static int ad7779_set_sampling_frequency(struct ad7779_state *st, + unsigned int sampling_freq) +{ + int ret; + unsigned int dec; + unsigned int frac; + unsigned int div; + unsigned int decimal; + unsigned int freq_khz; + + if (st->filter_enabled == AD7779_SINC3 && + sampling_freq > AD7779_SINC3_MAXFREQ) + return -EINVAL; + + if (st->filter_enabled == AD7779_SINC5 && + sampling_freq > AD7779_SINC5_MAXFREQ) + return -EINVAL; + + if (sampling_freq > AD7779_SPIMODE_MAX_SAMP_FREQ) + return -EINVAL; + + div = AD7779_HIGHPOWER_DIV; + + freq_khz = sampling_freq / HZ_PER_KHZ; + dec = div / freq_khz; + frac = div % freq_khz; + + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB, + FIELD_GET(AD7779_FREQ_MSB_MSK, dec)); + if (ret) + return ret; + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB, + FIELD_GET(AD7779_FREQ_LSB_MSK, dec)); + if (ret) + return ret; + + if (frac) { + /* + * In order to obtain the first three decimals of the decimation + * the initial number is multiplied with 10^3 prior to the + * division, then the original division result is subtracted and + * the number is divided by 10^3. + */ + decimal = ((mult_frac(div, KILO, freq_khz) - dec * KILO) << 16) + / KILO; + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB, + FIELD_GET(AD7779_FREQ_MSB_MSK, decimal)); + if (ret) + return ret; + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB, + FIELD_GET(AD7779_FREQ_LSB_MSK, decimal)); + if (ret) + return ret; + } else { + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_MSB, + FIELD_GET(AD7779_FREQ_MSB_MSK, 0x0)); + if (ret) + return ret; + ret = ad7779_spi_write(st, AD7779_REG_SRC_N_LSB, + FIELD_GET(AD7779_FREQ_LSB_MSK, 0x0)); + if (ret) + return ret; + } + ret = ad7779_spi_write(st, AD7779_REG_SRC_UPDATE, BIT(0)); + if (ret) + return ret; + + /* SRC update settling time */ + fsleep(15); + + ret = ad7779_spi_write(st, AD7779_REG_SRC_UPDATE, 0x0); + if (ret) + return ret; + + /* SRC update settling time */ + fsleep(15); + + st->sampling_freq = sampling_freq; + + return 0; +} + +static int ad7779_get_filter(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan) +{ + struct ad7779_state *st = iio_priv(indio_dev); + u8 temp; + int ret; + + ret = ad7779_spi_read(st, AD7779_REG_GENERAL_USER_CONFIG_2, &temp); + if (ret) + return ret; + + return FIELD_GET(AD7779_FILTER_MSK, temp); +} + +static int ad7779_set_filter(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + unsigned int mode) +{ + struct ad7779_state *st = iio_priv(indio_dev); + int ret; + + ret = ad7779_spi_write_mask(st, + AD7779_REG_GENERAL_USER_CONFIG_2, + AD7779_FILTER_MSK, + FIELD_PREP(AD7779_FILTER_MSK, mode)); + if (ret) + return ret; + + ret = ad7779_set_sampling_frequency(st, st->sampling_freq); + if (ret) + return ret; + + st->filter_enabled = mode; + + return 0; +} + +static int ad7779_get_calibscale(struct ad7779_state *st, int channel) +{ + int ret; + u8 calibscale[3]; + + ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_LOWER_BYTE(channel), + &calibscale[0]); + if (ret) + return ret; + + ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_MID_BYTE(channel), + &calibscale[1]); + if (ret) + return ret; + + ret = ad7779_spi_read(st, AD7779_REG_CH_GAIN_UPPER_BYTE(channel), + &calibscale[2]); + if (ret) + return ret; + + return get_unaligned_be24(calibscale); +} + +static int ad7779_set_calibscale(struct ad7779_state *st, int channel, int val) +{ + int ret; + unsigned int gain; + u8 gain_bytes[3]; + + /* + * The gain value is relative to 0x555555, which represents a gain of 1 + */ + gain = DIV_ROUND_CLOSEST_ULL((u64)val * 5592405LL, MEGA); + put_unaligned_be24(gain, gain_bytes); + ret = ad7779_spi_write(st, AD7779_REG_CH_GAIN_UPPER_BYTE(channel), + gain_bytes[0]); + if (ret) + return ret; + + ret = ad7779_spi_write(st, AD7779_REG_CH_GAIN_MID_BYTE(channel), + gain_bytes[1]); + if (ret) + return ret; + + return ad7779_spi_write(st, AD7779_REG_CH_GAIN_LOWER_BYTE(channel), + gain_bytes[2]); +} + +static int ad7779_get_calibbias(struct ad7779_state *st, int channel) +{ + int ret; + u8 calibbias[3]; + + ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_LOWER_BYTE(channel), + &calibbias[0]); + if (ret) + return ret; + + ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_MID_BYTE(channel), + &calibbias[1]); + if (ret) + return ret; + + ret = ad7779_spi_read(st, AD7779_REG_CH_OFFSET_UPPER_BYTE(channel), + &calibbias[2]); + if (ret) + return ret; + + return get_unaligned_be24(calibbias); +} + +static int ad7779_set_calibbias(struct ad7779_state *st, int channel, int val) +{ + int ret; + u8 calibbias[3]; + + put_unaligned_be24(val, calibbias); + ret = ad7779_spi_write(st, AD7779_REG_CH_OFFSET_UPPER_BYTE(channel), + calibbias[0]); + if (ret) + return ret; + + ret = ad7779_spi_write(st, AD7779_REG_CH_OFFSET_MID_BYTE(channel), + calibbias[1]); + if (ret) + return ret; + + return ad7779_spi_write(st, AD7779_REG_CH_OFFSET_LOWER_BYTE(channel), + calibbias[2]); +} + +static int ad7779_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct ad7779_state *st = iio_priv(indio_dev); + int ret; + + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + ret = ad7779_get_calibscale(st, chan->channel); + if (ret < 0) + return ret; + *val = ret; + *val2 = GAIN_REL; + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_CALIBBIAS: + ret = ad7779_get_calibbias(st, chan->channel); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->sampling_freq; + if (*val < 0) + return -EINVAL; + return IIO_VAL_INT; + default: + return -EINVAL; + } + } + unreachable(); +} + +static int ad7779_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct ad7779_state *st = iio_priv(indio_dev); + + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + return ad7779_set_calibscale(st, chan->channel, val2); + case IIO_CHAN_INFO_CALIBBIAS: + return ad7779_set_calibbias(st, chan->channel, val); + case IIO_CHAN_INFO_SAMP_FREQ: + return ad7779_set_sampling_frequency(st, val); + default: + return -EINVAL; + } + } + unreachable(); +} + +static int ad7779_buffer_preenable(struct iio_dev *indio_dev) +{ + int ret; + struct ad7779_state *st = iio_priv(indio_dev); + + ret = ad7779_spi_write_mask(st, + AD7779_REG_GENERAL_USER_CONFIG_3, + AD7779_MOD_SPI_EN_MSK, + FIELD_PREP(AD7779_MOD_SPI_EN_MSK, 1)); + if (ret) + return ret; + + /* + * DRDY output cannot be disabled at device level therefore we mask + * the irq at host end. + */ + enable_irq(st->spi->irq); + + return 0; +} + +static int ad7779_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad7779_state *st = iio_priv(indio_dev); + + disable_irq(st->spi->irq); + + return ad7779_spi_write(st, AD7779_REG_GENERAL_USER_CONFIG_3, + AD7779_DISABLE_SD); +} + +static irqreturn_t ad7779_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7779_state *st = iio_priv(indio_dev); + int ret; + struct spi_transfer t = { + .rx_buf = st->data.chans, + .tx_buf = st->spidata_tx, + .len = AD7779_NUM_CHANNELS * AD7779_CHAN_DATA_SIZE, + }; + + st->spidata_tx[0] = AD7779_SPI_READ_CMD; + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) { + dev_err(&st->spi->dev, "SPI transfer error in IRQ handler"); + goto exit_handler; + } + + iio_push_to_buffers_with_timestamp(indio_dev, &st->data, pf->timestamp); + +exit_handler: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int ad7779_reset(struct iio_dev *indio_dev, struct gpio_desc *reset_gpio) +{ + struct ad7779_state *st = iio_priv(indio_dev); + int ret; + struct spi_transfer t = { + .tx_buf = st->reset_buf, + .len = 8, + }; + + if (reset_gpio) { + gpiod_set_value(reset_gpio, 1); + /* Delay for reset to occur is 225 microseconds */ + fsleep(230); + ret = 0; + } else { + memset(st->reset_buf, 0xff, sizeof(st->reset_buf)); + ret = spi_sync_transfer(st->spi, &t, 1); + if (ret) + return ret; + } + + /* Delay for reset to occur is 225 microseconds */ + fsleep(230); + + return ret; +} + +static const struct iio_info ad7779_info = { + .read_raw = ad7779_read_raw, + .write_raw = ad7779_write_raw, + .debugfs_reg_access = &ad7779_reg_access, +}; + +static const struct iio_enum ad7779_filter_enum = { + .items = ad7779_filter_type, + .num_items = ARRAY_SIZE(ad7779_filter_type), + .get = ad7779_get_filter, + .set = ad7779_set_filter, +}; + +static const struct iio_chan_spec_ext_info ad7779_ext_filter[] = { + IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad7779_filter_enum), + IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, + &ad7779_filter_enum), + { } +}; + +#define AD777x_CHAN_S(index, _ext_info) \ + { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_CALIBSCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .address = (index), \ + .indexed = 1, \ + .channel = (index), \ + .scan_index = (index), \ + .ext_info = (_ext_info), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 24, \ + .storagebits = 32, \ + .endianness = IIO_BE, \ + }, \ + } + +#define AD777x_CHAN_NO_FILTER_S(index) \ + AD777x_CHAN_S(index, NULL) + +#define AD777x_CHAN_FILTER_S(index) \ + AD777x_CHAN_S(index, ad7779_ext_filter) +static const struct iio_chan_spec ad7779_channels[] = { + AD777x_CHAN_NO_FILTER_S(0), + AD777x_CHAN_NO_FILTER_S(1), + AD777x_CHAN_NO_FILTER_S(2), + AD777x_CHAN_NO_FILTER_S(3), + AD777x_CHAN_NO_FILTER_S(4), + AD777x_CHAN_NO_FILTER_S(5), + AD777x_CHAN_NO_FILTER_S(6), + AD777x_CHAN_NO_FILTER_S(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static const struct iio_chan_spec ad7779_channels_filter[] = { + AD777x_CHAN_FILTER_S(0), + AD777x_CHAN_FILTER_S(1), + AD777x_CHAN_FILTER_S(2), + AD777x_CHAN_FILTER_S(3), + AD777x_CHAN_FILTER_S(4), + AD777x_CHAN_FILTER_S(5), + AD777x_CHAN_FILTER_S(6), + AD777x_CHAN_FILTER_S(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static const struct iio_buffer_setup_ops ad7779_buffer_setup_ops = { + .preenable = ad7779_buffer_preenable, + .postdisable = ad7779_buffer_postdisable, +}; + +static const struct iio_trigger_ops ad7779_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + +static int ad7779_conf(struct ad7779_state *st, struct gpio_desc *start_gpio) +{ + int ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_GEN_ERR_REG_1_EN, + AD7779_SPI_CRC_EN_MSK, + FIELD_PREP(AD7779_SPI_CRC_EN_MSK, 1)); + if (ret) + return ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1, + AD7779_USRMOD_INIT_MSK, + FIELD_PREP(AD7779_USRMOD_INIT_MSK, 5)); + if (ret) + return ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT, + AD7779_DCLK_CLK_DIV_MSK, + FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 1)); + if (ret) + return ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_ADC_MUX_CONFIG, + AD7779_REFMUX_CTRL_MSK, + FIELD_PREP(AD7779_REFMUX_CTRL_MSK, 1)); + if (ret) + return ret; + + ret = ad7779_set_sampling_frequency(st, AD7779_DEFAULT_SAMPLING_FREQ); + if (ret) + return ret; + + gpiod_set_value(start_gpio, 0); + /* Start setup time */ + fsleep(15); + gpiod_set_value(start_gpio, 1); + /* Start setup time */ + fsleep(15); + gpiod_set_value(start_gpio, 0); + /* Start setup time */ + fsleep(15); + + return 0; +} + +static int ad7779_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ad7779_state *st; + struct gpio_desc *reset_gpio, *start_gpio; + struct device *dev = &spi->dev; + int ret = -EINVAL; + + if (!spi->irq) + return dev_err_probe(dev, ret, "DRDY irq not present\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + ret = devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(ad7779_power_supplies), + ad7779_power_supplies); + if (ret) + return dev_err_probe(dev, ret, + "failed to get and enable supplies\n"); + + st->mclk = devm_clk_get_enabled(dev, "mclk"); + if (IS_ERR(st->mclk)) + return PTR_ERR(st->mclk); + + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); + + start_gpio = devm_gpiod_get(dev, "start", GPIOD_OUT_HIGH); + if (IS_ERR(start_gpio)) + return PTR_ERR(start_gpio); + + crc8_populate_msb(ad7779_crc8_table, AD7779_CRC8_POLY); + st->spi = spi; + + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; + + ret = ad7779_reset(indio_dev, reset_gpio); + if (ret) + return ret; + + ret = ad7779_conf(st, start_gpio); + if (ret) + return ret; + + indio_dev->name = st->chip_info->name; + indio_dev->info = &ad7779_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = ARRAY_SIZE(ad7779_channels); + + st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, + iio_device_id(indio_dev)); + if (!st->trig) + return -ENOMEM; + + st->trig->ops = &ad7779_trigger_ops; + + iio_trigger_set_drvdata(st->trig, st); + + ret = devm_request_irq(dev, spi->irq, iio_trigger_generic_data_rdy_poll, + IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name, + st->trig); + if (ret) + return dev_err_probe(dev, ret, "request IRQ %d failed\n", + st->spi->irq); + + ret = devm_iio_trigger_register(dev, st->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(st->trig); + + init_completion(&st->completion); + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + &iio_pollfunc_store_time, + &ad7779_trigger_handler, + &ad7779_buffer_setup_ops); + if (ret) + return ret; + + ret = ad7779_spi_write_mask(st, AD7779_REG_DOUT_FORMAT, + AD7779_DCLK_CLK_DIV_MSK, + FIELD_PREP(AD7779_DCLK_CLK_DIV_MSK, 7)); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static int ad7779_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7779_state *st = iio_priv(indio_dev); + + return ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1, + AD7779_MOD_POWERMODE_MSK, + FIELD_PREP(AD7779_MOD_POWERMODE_MSK, + AD7779_LOW_POWER)); +} + +static int ad7779_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad7779_state *st = iio_priv(indio_dev); + + return ad7779_spi_write_mask(st, AD7779_REG_GENERAL_USER_CONFIG_1, + AD7779_MOD_POWERMODE_MSK, + FIELD_PREP(AD7779_MOD_POWERMODE_MSK, + AD7779_HIGH_POWER)); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ad7779_pm_ops, ad7779_suspend, ad7779_resume); + +static const struct ad7779_chip_info ad7770_chip_info = { + .name = "ad7770", + .channels = ad7779_channels, +}; + +static const struct ad7779_chip_info ad7771_chip_info = { + .name = "ad7771", + .channels = ad7779_channels_filter, +}; + +static const struct ad7779_chip_info ad7779_chip_info = { + .name = "ad7779", + .channels = ad7779_channels, +}; + +static const struct spi_device_id ad7779_id[] = { + { + .name = "ad7770", + .driver_data = (kernel_ulong_t)&ad7770_chip_info, + }, + { + .name = "ad7771", + .driver_data = (kernel_ulong_t)&ad7771_chip_info, + }, + { + .name = "ad7779", + .driver_data = (kernel_ulong_t)&ad7779_chip_info, + }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad7779_id); + +static const struct of_device_id ad7779_of_table[] = { + { + .compatible = "adi,ad7770", + .data = &ad7770_chip_info, + }, + { + .compatible = "adi,ad7771", + .data = &ad7771_chip_info, + }, + { + .compatible = "adi,ad7779", + .data = &ad7779_chip_info, + }, + { } +}; +MODULE_DEVICE_TABLE(of, ad7779_of_table); + +static struct spi_driver ad7779_driver = { + .driver = { + .name = "ad7779", + .pm = pm_sleep_ptr(&ad7779_pm_ops), + .of_match_table = ad7779_of_table, + }, + .probe = ad7779_probe, + .id_table = ad7779_id, +}; +module_spi_driver(ad7779_driver); + +MODULE_AUTHOR("Ramona Alexandra Nechita "); +MODULE_DESCRIPTION("Analog Devices AD7779 ADC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c index e9b0c577c9cca4..24d2dcad8f4da3 100644 --- a/drivers/iio/adc/ad7780.c +++ b/drivers/iio/adc/ad7780.c @@ -152,7 +152,7 @@ static int ad7780_write_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_SCALE: - if (val != 0) + if (val != 0 || val2 == 0) return -EINVAL; vref = st->int_vref_mv * 1000000LL; @@ -375,4 +375,4 @@ module_spi_driver(ad7780_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); +MODULE_IMPORT_NS("IIO_AD_SIGMA_DELTA"); diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index 86effe8501b440..e1bf13fe2cd76d 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -371,7 +371,7 @@ static const struct iio_info ad7791_no_filter_info = { }; static int ad7791_setup(struct ad7791_state *st, - struct ad7791_platform_data *pdata) + const struct ad7791_platform_data *pdata) { /* Set to poweron-reset default values */ st->mode = AD7791_MODE_BUFFER; @@ -401,7 +401,7 @@ static void ad7791_reg_disable(void *reg) static int ad7791_probe(struct spi_device *spi) { - struct ad7791_platform_data *pdata = spi->dev.platform_data; + const struct ad7791_platform_data *pdata = dev_get_platdata(&spi->dev); struct iio_dev *indio_dev; struct ad7791_state *st; int ret; @@ -474,4 +474,4 @@ module_spi_driver(ad7791_driver); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("Analog Devices AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); +MODULE_IMPORT_NS("IIO_AD_SIGMA_DELTA"); diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index abebd519cafa30..d55c71566707f3 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -770,7 +770,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { static int ad7793_probe(struct spi_device *spi) { - const struct ad7793_platform_data *pdata = spi->dev.platform_data; + const struct ad7793_platform_data *pdata = dev_get_platdata(&spi->dev); struct ad7793_state *st; struct iio_dev *indio_dev; int ret, vref_mv = 0; @@ -849,4 +849,4 @@ module_spi_driver(ad7793_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD7793 and similar ADCs"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); +MODULE_IMPORT_NS("IIO_AD_SIGMA_DELTA"); diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 6265ce7df70306..69add1dc4b5388 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -41,7 +41,7 @@ enum ad7887_channels { }; /** - * struct ad7887_chip_info - chip specifc information + * struct ad7887_chip_info - chip specific information * @int_vref_mv: the internal reference voltage * @channels: channels specification * @num_channels: number of channels @@ -234,7 +234,7 @@ static void ad7887_reg_disable(void *data) static int ad7887_probe(struct spi_device *spi) { - struct ad7887_platform_data *pdata = spi->dev.platform_data; + const struct ad7887_platform_data *pdata = dev_get_platdata(&spi->dev); struct ad7887_state *st; struct iio_dev *indio_dev; uint8_t mode; diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c index 09680015a7ab54..acc44cb34f8245 100644 --- a/drivers/iio/adc/ad7923.c +++ b/drivers/iio/adc/ad7923.c @@ -48,7 +48,7 @@ struct ad7923_state { struct spi_device *spi; - struct spi_transfer ring_xfer[5]; + struct spi_transfer ring_xfer[9]; struct spi_transfer scan_single_xfer[2]; struct spi_message ring_msg; struct spi_message scan_single_msg; @@ -64,7 +64,7 @@ struct ad7923_state { * Length = 8 channels + 4 extra for 8 byte timestamp */ __be16 rx_buf[12] __aligned(IIO_DMA_MINALIGN); - __be16 tx_buf[4]; + __be16 tx_buf[8]; }; struct ad7923_chip_info { diff --git a/drivers/iio/adc/ad7944.c b/drivers/iio/adc/ad7944.c index 0f36138a714456..a5aea4e9f1a7bd 100644 --- a/drivers/iio/adc/ad7944.c +++ b/drivers/iio/adc/ad7944.c @@ -80,7 +80,7 @@ struct ad7944_adc { }; /* quite time before CNV rising edge */ -#define T_QUIET_NS 20 +#define AD7944_T_QUIET_NS 20 static const struct ad7944_timing_spec ad7944_timing_spec = { .conv_ns = 420, @@ -150,7 +150,7 @@ static int ad7944_3wire_cs_mode_init_msg(struct device *dev, struct ad7944_adc * * CS is tied to CNV and we need a low to high transition to start the * conversion, so place CNV low for t_QUIET to prepare for this. */ - xfers[0].delay.value = T_QUIET_NS; + xfers[0].delay.value = AD7944_T_QUIET_NS; xfers[0].delay.unit = SPI_DELAY_UNIT_NSECS; /* diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 0f107e3fc2c855..aa44b4e2542b26 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -406,7 +406,7 @@ static int ad799x_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) + bool state) { struct ad799x_state *st = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c index 05fb7a75531fb7..d358958ab31084 100644 --- a/drivers/iio/adc/ad9467.c +++ b/drivers/iio/adc/ad9467.c @@ -1280,4 +1280,4 @@ module_spi_driver(ad9467_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD9467 ADC driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_BACKEND); +MODULE_IMPORT_NS("IIO_BACKEND"); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index ea4aabd3960a08..3fd200b34161c5 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -43,7 +43,7 @@ void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm) * to select the channel */ sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK; } -EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, "IIO_AD_SIGMA_DELTA"); /** * ad_sd_write_reg() - Write a register @@ -95,7 +95,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, return ret; } -EXPORT_SYMBOL_NS_GPL(ad_sd_write_reg, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sd_write_reg, "IIO_AD_SIGMA_DELTA"); static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta, unsigned int reg, unsigned int size, uint8_t *val) @@ -172,7 +172,7 @@ int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, out: return ret; } -EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, "IIO_AD_SIGMA_DELTA"); /** * ad_sd_reset() - Reset the serial interface @@ -200,7 +200,7 @@ int ad_sd_reset(struct ad_sigma_delta *sigma_delta, return ret; } -EXPORT_SYMBOL_NS_GPL(ad_sd_reset, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sd_reset, "IIO_AD_SIGMA_DELTA"); int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, unsigned int mode, unsigned int channel) @@ -239,7 +239,7 @@ int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, return ret; } -EXPORT_SYMBOL_NS_GPL(ad_sd_calibrate, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sd_calibrate, "IIO_AD_SIGMA_DELTA"); /** * ad_sd_calibrate_all() - Performs channel calibration @@ -263,7 +263,7 @@ int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta, return 0; } -EXPORT_SYMBOL_NS_GPL(ad_sd_calibrate_all, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sd_calibrate_all, "IIO_AD_SIGMA_DELTA"); /** * ad_sigma_delta_single_conversion() - Performs a single data conversion @@ -339,7 +339,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, return IIO_VAL_INT; } -EXPORT_SYMBOL_NS_GPL(ad_sigma_delta_single_conversion, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sigma_delta_single_conversion, "IIO_AD_SIGMA_DELTA"); static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) { @@ -469,7 +469,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p) /* * Data array after transfer will look like (if status is appended): * data[] = { [0][sample][sample][sample][status] } - * Keeping the first byte 0 shifts the status postion by 1 byte to the right. + * Keeping the first byte 0 shifts the status position by 1 byte to the right. */ status_pos = reg_size + 1; @@ -564,7 +564,7 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig) return 0; } -EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, "IIO_AD_SIGMA_DELTA"); static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev) { @@ -638,7 +638,7 @@ int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indi return devm_ad_sd_probe_trigger(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(devm_ad_sd_setup_buffer_and_trigger, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(devm_ad_sd_setup_buffer_and_trigger, "IIO_AD_SIGMA_DELTA"); /** * ad_sd_init() - Initializes a ad_sigma_delta struct @@ -656,7 +656,7 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, sigma_delta->spi = spi; sigma_delta->info = info; - /* If the field is unset in ad_sigma_delta_info, asume there can only be 1 slot. */ + /* If the field is unset in ad_sigma_delta_info, assume there can only be 1 slot. */ if (!info->num_slots) sigma_delta->num_slots = 1; else @@ -683,7 +683,7 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_NS_GPL(ad_sd_init, IIO_AD_SIGMA_DELTA); +EXPORT_SYMBOL_NS_GPL(ad_sd_init, "IIO_AD_SIGMA_DELTA"); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs"); diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 5c8c87eb36d19f..c7357601f0f869 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -437,5 +437,5 @@ module_platform_driver(adi_axi_adc_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); -MODULE_IMPORT_NS(IIO_BACKEND); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); +MODULE_IMPORT_NS("IIO_BACKEND"); diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index d7fd21e7c6e2a6..8e5aaf15a92150 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -2625,7 +2625,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_match); static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, - .remove_new = at91_adc_remove, + .remove = at91_adc_remove, .driver = { .name = "at91-sama5d2_adc", .of_match_table = at91_adc_dt_match, diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 9c39acff17e658..a3f0a232166613 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1341,7 +1341,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_ids); static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, - .remove_new = at91_adc_remove, + .remove = at91_adc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = at91_adc_dt_ids, diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index 6c1a5d1b0a83d4..9fd7027623d0c2 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -155,52 +155,22 @@ enum axp813_adc_channel_v { AXP813_BATT_V, }; -static struct iio_map axp20x_maps[] = { - { - .consumer_dev_name = "axp20x-usb-power-supply", - .consumer_channel = "vbus_v", - .adc_channel_label = "vbus_v", - }, { - .consumer_dev_name = "axp20x-usb-power-supply", - .consumer_channel = "vbus_i", - .adc_channel_label = "vbus_i", - }, { - .consumer_dev_name = "axp20x-ac-power-supply", - .consumer_channel = "acin_v", - .adc_channel_label = "acin_v", - }, { - .consumer_dev_name = "axp20x-ac-power-supply", - .consumer_channel = "acin_i", - .adc_channel_label = "acin_i", - }, { - .consumer_dev_name = "axp20x-battery-power-supply", - .consumer_channel = "batt_v", - .adc_channel_label = "batt_v", - }, { - .consumer_dev_name = "axp20x-battery-power-supply", - .consumer_channel = "batt_chrg_i", - .adc_channel_label = "batt_chrg_i", - }, { - .consumer_dev_name = "axp20x-battery-power-supply", - .consumer_channel = "batt_dischrg_i", - .adc_channel_label = "batt_dischrg_i", - }, { /* sentinel */ } +static const struct iio_map axp20x_maps[] = { + IIO_MAP("vbus_v", "axp20x-usb-power-supply", "vbus_v"), + IIO_MAP("vbus_i", "axp20x-usb-power-supply", "vbus_i"), + IIO_MAP("acin_v", "axp20x-ac-power-supply", "acin_v"), + IIO_MAP("acin_i", "axp20x-ac-power-supply", "acin_i"), + IIO_MAP("batt_v", "axp20x-battery-power-supply", "batt_v"), + IIO_MAP("batt_chrg_i", "axp20x-battery-power-supply", "batt_chrg_i"), + IIO_MAP("batt_dischrg_i", "axp20x-battery-power-supply", "batt_dischrg_i"), + { /* sentinel */ } }; -static struct iio_map axp22x_maps[] = { - { - .consumer_dev_name = "axp20x-battery-power-supply", - .consumer_channel = "batt_v", - .adc_channel_label = "batt_v", - }, { - .consumer_dev_name = "axp20x-battery-power-supply", - .consumer_channel = "batt_chrg_i", - .adc_channel_label = "batt_chrg_i", - }, { - .consumer_dev_name = "axp20x-battery-power-supply", - .consumer_channel = "batt_dischrg_i", - .adc_channel_label = "batt_dischrg_i", - }, { /* sentinel */ } +static const struct iio_map axp22x_maps[] = { + IIO_MAP("batt_v", "axp20x-battery-power-supply", "batt_v"), + IIO_MAP("batt_chrg_i", "axp20x-battery-power-supply", "batt_chrg_i"), + IIO_MAP("batt_dischrg_i", "axp20x-battery-power-supply", "batt_dischrg_i"), + { /* sentinel */ } }; static struct iio_map axp717_maps[] = { @@ -1044,7 +1014,7 @@ struct axp_data { unsigned long adc_en2_mask; int (*adc_rate)(struct axp20x_adc_iio *info, int rate); - struct iio_map *maps; + const struct iio_map *maps; }; static const struct axp_data axp192_data = { @@ -1212,7 +1182,7 @@ static struct platform_driver axp20x_adc_driver = { }, .id_table = axp20x_adc_id_match, .probe = axp20x_probe, - .remove_new = axp20x_remove, + .remove = axp20x_remove, }; module_platform_driver(axp20x_adc_driver); diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 8c3acc0cd7e99a..45542efc3ece0c 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -103,7 +103,7 @@ static const struct iio_chan_spec axp288_adc_channels[] = { }; /* for consumer drivers */ -static struct iio_map axp288_adc_default_maps[] = { +static const struct iio_map axp288_adc_default_maps[] = { IIO_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"), IIO_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"), IIO_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"), diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index cdfe304eaa2011..f258668b0dc71e 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -611,10 +611,10 @@ static const struct of_device_id iproc_adc_of_match[] = { MODULE_DEVICE_TABLE(of, iproc_adc_of_match); static struct platform_driver iproc_adc_driver = { - .probe = iproc_adc_probe, - .remove_new = iproc_adc_remove, - .driver = { - .name = "iproc-static-adc", + .probe = iproc_adc_probe, + .remove = iproc_adc_remove, + .driver = { + .name = "iproc-static-adc", .of_match_table = iproc_adc_of_match, }, }; diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c index 8f0d3fb63b677c..0290345ade8417 100644 --- a/drivers/iio/adc/da9150-gpadc.c +++ b/drivers/iio/adc/da9150-gpadc.c @@ -291,27 +291,11 @@ static const struct iio_chan_spec da9150_gpadc_channels[] = { }; /* Default maps used by da9150-charger */ -static struct iio_map da9150_gpadc_default_maps[] = { - { - .consumer_dev_name = "da9150-charger", - .consumer_channel = "CHAN_IBUS", - .adc_channel_label = "IBUS", - }, - { - .consumer_dev_name = "da9150-charger", - .consumer_channel = "CHAN_VBUS", - .adc_channel_label = "VBUS", - }, - { - .consumer_dev_name = "da9150-charger", - .consumer_channel = "CHAN_TJUNC", - .adc_channel_label = "TJUNC_CORE", - }, - { - .consumer_dev_name = "da9150-charger", - .consumer_channel = "CHAN_VBAT", - .adc_channel_label = "VBAT", - }, +static const struct iio_map da9150_gpadc_default_maps[] = { + IIO_MAP("IBUS", "da9150-charger", "CHAN_IBUS"), + IIO_MAP("VBUS", "da9150-charger", "CHAN_VBUS"), + IIO_MAP("TJUNC_CORE", "da9150-charger", "CHAN_TJUNC"), + IIO_MAP("VBAT", "da9150-charger", "CHAN_VBAT"), {}, }; diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c index de7252a10047d5..30328626d9beef 100644 --- a/drivers/iio/adc/dln2-adc.c +++ b/drivers/iio/adc/dln2-adc.c @@ -700,7 +700,7 @@ static void dln2_adc_remove(struct platform_device *pdev) static struct platform_driver dln2_adc_driver = { .driver.name = DLN2_ADC_MOD_NAME, .probe = dln2_adc_probe, - .remove_new = dln2_adc_remove, + .remove = dln2_adc_remove, }; module_platform_driver(dln2_adc_driver); diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index cc38d5e0608eed..a3e9c697e2cbee 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -238,7 +238,7 @@ static struct platform_driver ep93xx_adc_driver = { .of_match_table = ep93xx_adc_of_ids, }, .probe = ep93xx_adc_probe, - .remove_new = ep93xx_adc_remove, + .remove = ep93xx_adc_remove, }; module_platform_driver(ep93xx_adc_driver); diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 4d00ee8dd14d08..4614cf84853594 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -1008,7 +1008,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops, exynos_adc_suspend, static struct platform_driver exynos_adc_driver = { .probe = exynos_adc_probe, - .remove_new = exynos_adc_remove, + .remove = exynos_adc_remove, .driver = { .name = "exynos-adc", .of_match_table = exynos_adc_match, diff --git a/drivers/iio/adc/gehc-pmc-adc.c b/drivers/iio/adc/gehc-pmc-adc.c new file mode 100644 index 00000000000000..d1167818b17d65 --- /dev/null +++ b/drivers/iio/adc/gehc-pmc-adc.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The GE HealthCare PMC ADC is a 16-Channel (Voltage and current), 16-Bit + * ADC with an I2C Interface. + * + * Copyright (C) 2024, GE HealthCare + * + * Authors: + * Herve Codina + */ +#include +#include +#include +#include +#include +#include +#include +#include + +struct pmc_adc { + struct i2c_client *client; +}; + +#define PMC_ADC_CMD_REQUEST_PROTOCOL_VERSION 0x01 +#define PMC_ADC_CMD_READ_VOLTAGE(_ch) (0x10 | (_ch)) +#define PMC_ADC_CMD_READ_CURRENT(_ch) (0x20 | (_ch)) + +#define PMC_ADC_VOLTAGE_CHANNEL(_ch, _ds_name) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_ch), \ + .address = PMC_ADC_CMD_READ_VOLTAGE(_ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ + .datasheet_name = (_ds_name), \ +} + +#define PMC_ADC_CURRENT_CHANNEL(_ch, _ds_name) { \ + .type = IIO_CURRENT, \ + .indexed = 1, \ + .channel = (_ch), \ + .address = PMC_ADC_CMD_READ_CURRENT(_ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ + .datasheet_name = (_ds_name), \ +} + +static const struct iio_chan_spec pmc_adc_channels[] = { + PMC_ADC_VOLTAGE_CHANNEL(0, "CH0_V"), + PMC_ADC_VOLTAGE_CHANNEL(1, "CH1_V"), + PMC_ADC_VOLTAGE_CHANNEL(2, "CH2_V"), + PMC_ADC_VOLTAGE_CHANNEL(3, "CH3_V"), + PMC_ADC_VOLTAGE_CHANNEL(4, "CH4_V"), + PMC_ADC_VOLTAGE_CHANNEL(5, "CH5_V"), + PMC_ADC_VOLTAGE_CHANNEL(6, "CH6_V"), + PMC_ADC_VOLTAGE_CHANNEL(7, "CH7_V"), + PMC_ADC_VOLTAGE_CHANNEL(8, "CH8_V"), + PMC_ADC_VOLTAGE_CHANNEL(9, "CH9_V"), + PMC_ADC_VOLTAGE_CHANNEL(10, "CH10_V"), + PMC_ADC_VOLTAGE_CHANNEL(11, "CH11_V"), + PMC_ADC_VOLTAGE_CHANNEL(12, "CH12_V"), + PMC_ADC_VOLTAGE_CHANNEL(13, "CH13_V"), + PMC_ADC_VOLTAGE_CHANNEL(14, "CH14_V"), + PMC_ADC_VOLTAGE_CHANNEL(15, "CH15_V"), + + PMC_ADC_CURRENT_CHANNEL(0, "CH0_I"), + PMC_ADC_CURRENT_CHANNEL(1, "CH1_I"), + PMC_ADC_CURRENT_CHANNEL(2, "CH2_I"), + PMC_ADC_CURRENT_CHANNEL(3, "CH3_I"), + PMC_ADC_CURRENT_CHANNEL(4, "CH4_I"), + PMC_ADC_CURRENT_CHANNEL(5, "CH5_I"), + PMC_ADC_CURRENT_CHANNEL(6, "CH6_I"), + PMC_ADC_CURRENT_CHANNEL(7, "CH7_I"), + PMC_ADC_CURRENT_CHANNEL(8, "CH8_I"), + PMC_ADC_CURRENT_CHANNEL(9, "CH9_I"), + PMC_ADC_CURRENT_CHANNEL(10, "CH10_I"), + PMC_ADC_CURRENT_CHANNEL(11, "CH11_I"), + PMC_ADC_CURRENT_CHANNEL(12, "CH12_I"), + PMC_ADC_CURRENT_CHANNEL(13, "CH13_I"), + PMC_ADC_CURRENT_CHANNEL(14, "CH14_I"), + PMC_ADC_CURRENT_CHANNEL(15, "CH15_I"), +}; + +static int pmc_adc_read_raw_ch(struct pmc_adc *pmc_adc, u8 cmd, int *val) +{ + s32 ret; + + ret = i2c_smbus_read_word_swapped(pmc_adc->client, cmd); + if (ret < 0) { + dev_err(&pmc_adc->client->dev, "i2c read word failed (%d)\n", ret); + return ret; + } + + *val = sign_extend32(ret, 15); + return 0; +} + +static int pmc_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct pmc_adc *pmc_adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + /* Values are directly read in mV or mA */ + ret = pmc_adc_read_raw_ch(pmc_adc, chan->address, val); + if (ret) + return ret; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int pmc_adc_fwnode_xlate(struct iio_dev *indio_dev, + const struct fwnode_reference_args *iiospec) +{ + enum iio_chan_type expected_type; + unsigned int i; + + /* + * args[0]: Acquisition type (i.e. voltage or current) + * args[1]: PMC ADC channel number + */ + if (iiospec->nargs != 2) + return -EINVAL; + + switch (iiospec->args[0]) { + case GEHC_PMC_ADC_VOLTAGE: + expected_type = IIO_VOLTAGE; + break; + case GEHC_PMC_ADC_CURRENT: + expected_type = IIO_CURRENT; + break; + default: + dev_err(&indio_dev->dev, "Invalid channel type %llu\n", + iiospec->args[0]); + return -EINVAL; + } + + for (i = 0; i < indio_dev->num_channels; i++) + if (indio_dev->channels[i].type == expected_type && + indio_dev->channels[i].channel == iiospec->args[1]) + return i; + + dev_err(&indio_dev->dev, "Invalid channel type %llu number %llu\n", + iiospec->args[0], iiospec->args[1]); + return -EINVAL; +} + +static const struct iio_info pmc_adc_info = { + .read_raw = pmc_adc_read_raw, + .fwnode_xlate = pmc_adc_fwnode_xlate, +}; + +static const char *const pmc_adc_regulator_names[] = { + "vdd", + "vdda", + "vddio", + "vref", +}; + +static int pmc_adc_probe(struct i2c_client *client) +{ + struct iio_dev *indio_dev; + struct pmc_adc *pmc_adc; + struct clk *clk; + s32 val; + int ret; + + ret = devm_regulator_bulk_get_enable(&client->dev, ARRAY_SIZE(pmc_adc_regulator_names), + pmc_adc_regulator_names); + if (ret) + return dev_err_probe(&client->dev, ret, "Failed to get regulators\n"); + + clk = devm_clk_get_optional_enabled(&client->dev, "osc"); + if (IS_ERR(clk)) + return dev_err_probe(&client->dev, PTR_ERR(clk), "Failed to get osc clock\n"); + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*pmc_adc)); + if (!indio_dev) + return -ENOMEM; + + pmc_adc = iio_priv(indio_dev); + pmc_adc->client = client; + + val = i2c_smbus_read_byte_data(pmc_adc->client, PMC_ADC_CMD_REQUEST_PROTOCOL_VERSION); + if (val < 0) + return dev_err_probe(&client->dev, val, "Failed to get protocol version\n"); + + if (val != 0x01) + return dev_err_probe(&client->dev, -EINVAL, + "Unsupported protocol version 0x%02x\n", val); + + indio_dev->name = "pmc_adc"; + indio_dev->info = &pmc_adc_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = pmc_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(pmc_adc_channels); + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct of_device_id pmc_adc_of_match[] = { + { .compatible = "gehc,pmc-adc"}, + { } +}; +MODULE_DEVICE_TABLE(of, pmc_adc_of_match); + +static const struct i2c_device_id pmc_adc_id_table[] = { + { "pmc-adc" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pmc_adc_id_table); + +static struct i2c_driver pmc_adc_i2c_driver = { + .driver = { + .name = "pmc-adc", + .of_match_table = pmc_adc_of_match, + }, + .id_table = pmc_adc_id_table, + .probe = pmc_adc_probe, +}; + +module_i2c_driver(pmc_adc_i2c_driver); + +MODULE_AUTHOR("Herve Codina "); +MODULE_DESCRIPTION("GE HealthCare PMC ADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index fb635a75644030..689e34f069877e 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -132,7 +132,7 @@ static int hi8435_read_event_config(struct iio_dev *idev, static int hi8435_write_event_config(struct iio_dev *idev, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { struct hi8435_priv *priv = iio_priv(idev); int ret; diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index fe82198170d599..3d19d7d744aa46 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -487,7 +487,7 @@ MODULE_DEVICE_TABLE(of, imx8qxp_adc_match); static struct platform_driver imx8qxp_adc_driver = { .probe = imx8qxp_adc_probe, - .remove_new = imx8qxp_adc_remove, + .remove = imx8qxp_adc_remove, .driver = { .name = ADC_DRIVER_NAME, .of_match_table = imx8qxp_adc_match, diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index 4ccf4819f1f131..002eb19587d679 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -470,7 +470,7 @@ MODULE_DEVICE_TABLE(of, imx93_adc_match); static struct platform_driver imx93_adc_driver = { .probe = imx93_adc_probe, - .remove_new = imx93_adc_remove, + .remove = imx93_adc_remove, .driver = { .name = IMX93_ADC_DRIVER_NAME, .of_match_table = imx93_adc_match, diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index 30733252aa56f8..c178850eaaab10 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -164,7 +164,7 @@ static const struct iio_chan_spec mrfld_adc_channels[] = { BCOVE_ADC_CHANNEL(IIO_TEMP, 8, "CH8", 0xC6), }; -static struct iio_map iio_maps[] = { +static const struct iio_map iio_maps[] = { IIO_MAP("CH0", "bcove-battery", "VBATRSLT"), IIO_MAP("CH1", "bcove-battery", "BATTID"), IIO_MAP("CH2", "bcove-battery", "IBATRSLT"), diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c index 6d9b354bc705bb..33bf8aef79e362 100644 --- a/drivers/iio/adc/lp8788_adc.c +++ b/drivers/iio/adc/lp8788_adc.c @@ -26,7 +26,7 @@ struct lp8788_adc { struct lp8788 *lp; - struct iio_map *map; + const struct iio_map *map; struct mutex lock; }; @@ -149,17 +149,9 @@ static const struct iio_chan_spec lp8788_adc_channels[] = { }; /* default maps used by iio consumer (lp8788-charger driver) */ -static struct iio_map lp8788_default_iio_maps[] = { - { - .consumer_dev_name = "lp8788-charger", - .consumer_channel = "lp8788_vbatt_5p0", - .adc_channel_label = "VBATT_5P0", - }, - { - .consumer_dev_name = "lp8788-charger", - .consumer_channel = "lp8788_adc1", - .adc_channel_label = "ADC1", - }, +static const struct iio_map lp8788_default_iio_maps[] = { + IIO_MAP("VBATT_5P0", "lp8788-charger", "lp8788_vbatt_5p0"), + IIO_MAP("ADC1", "lp8788-charger", "lp8788_adc1"), { } }; @@ -168,7 +160,7 @@ static int lp8788_iio_map_register(struct device *dev, struct lp8788_platform_data *pdata, struct lp8788_adc *adc) { - struct iio_map *map; + const struct iio_map *map; int ret; map = (!pdata || !pdata->adc_pdata) ? diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c index 996f6cbbed3ce1..2dc5c704426949 100644 --- a/drivers/iio/adc/ltc2497-core.c +++ b/drivers/iio/adc/ltc2497-core.c @@ -168,6 +168,7 @@ static const struct iio_info ltc2497core_info = { int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev) { struct ltc2497core_driverdata *ddata = iio_priv(indio_dev); + struct iio_map *plat_data = dev_get_platdata(dev); int ret; /* @@ -200,16 +201,10 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev) return ret; } - if (dev->platform_data) { - struct iio_map *plat_data; - - plat_data = (struct iio_map *)dev->platform_data; - - ret = iio_map_array_register(indio_dev, plat_data); - if (ret) { - dev_err(&indio_dev->dev, "iio map err: %d\n", ret); - goto err_regulator_disable; - } + ret = iio_map_array_register(indio_dev, plat_data); + if (ret) { + dev_err(&indio_dev->dev, "iio map err: %d\n", ret); + goto err_regulator_disable; } ddata->addr_prev = LTC2497_CONFIG_DEFAULT; @@ -231,7 +226,7 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev) return ret; } -EXPORT_SYMBOL_NS(ltc2497core_probe, LTC2497); +EXPORT_SYMBOL_NS(ltc2497core_probe, "LTC2497"); void ltc2497core_remove(struct iio_dev *indio_dev) { @@ -243,7 +238,7 @@ void ltc2497core_remove(struct iio_dev *indio_dev) regulator_disable(ddata->ref); } -EXPORT_SYMBOL_NS(ltc2497core_remove, LTC2497); +EXPORT_SYMBOL_NS(ltc2497core_remove, "LTC2497"); MODULE_DESCRIPTION("common code for LTC2496/LTC2497 drivers"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h index 781519b5247562..64e81c95a3dd05 100644 --- a/drivers/iio/adc/ltc2497.h +++ b/drivers/iio/adc/ltc2497.h @@ -23,4 +23,4 @@ struct ltc2497core_driverdata { int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev); void ltc2497core_remove(struct iio_dev *indio_dev); -MODULE_IMPORT_NS(LTC2497); +MODULE_IMPORT_NS("LTC2497"); diff --git a/drivers/iio/adc/max11205.c b/drivers/iio/adc/max11205.c index 9d8bc0b154dd35..6c803df220b6e9 100644 --- a/drivers/iio/adc/max11205.c +++ b/drivers/iio/adc/max11205.c @@ -177,4 +177,4 @@ module_spi_driver(max11205_spi_driver); MODULE_AUTHOR("Ramona Bolboaca "); MODULE_DESCRIPTION("MAX11205 ADC driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA); +MODULE_IMPORT_NS("IIO_AD_SIGMA_DELTA"); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index d0c6e94f7204ee..9a0baea08ab616 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -392,7 +393,7 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, if (data < 0) return data; - data = (rxbuf[1] | rxbuf[0] << 8) & + data = get_unaligned_be16(rxbuf) & ((1 << st->chip_info->bits) - 1); } else { /* Get reading */ @@ -943,7 +944,7 @@ static inline int __max1363_check_event_mask(int thismask, int checkmask) static int max1363_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) + enum iio_event_direction dir, bool state) { struct max1363_state *st = iio_priv(indio_dev); diff --git a/drivers/iio/adc/max34408.c b/drivers/iio/adc/max34408.c index ffec22be2d5933..971e6e5dee9b15 100644 --- a/drivers/iio/adc/max34408.c +++ b/drivers/iio/adc/max34408.c @@ -161,7 +161,7 @@ static int max34408_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* - * calcluate current for 8bit ADC with Rsense + * calculate current for 8bit ADC with Rsense * value. * 10 mV * 1000 / Rsense uOhm = max current * (max current * adc val * 1000) / (2^8 - 1) mA diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c index 198c7e68e0cf27..cf8a8c0412ec94 100644 --- a/drivers/iio/adc/men_z188_adc.c +++ b/drivers/iio/adc/men_z188_adc.c @@ -172,4 +172,4 @@ MODULE_AUTHOR("Johannes Thumshirn "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core"); MODULE_ALIAS("mcb:16z188"); -MODULE_IMPORT_NS(MCB); +MODULE_IMPORT_NS("MCB"); diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index e16b0e28974e8f..2d475b43e717ff 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -1483,7 +1483,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops, static struct platform_driver meson_sar_adc_driver = { .probe = meson_sar_adc_probe, - .remove_new = meson_sar_adc_remove, + .remove = meson_sar_adc_remove, .driver = { .name = "meson-saradc", .of_match_table = meson_sar_adc_of_match, diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c index 5fbf9b6abd9c7c..1cb043b1743778 100644 --- a/drivers/iio/adc/mp2629_adc.c +++ b/drivers/iio/adc/mp2629_adc.c @@ -52,7 +52,7 @@ static struct iio_chan_spec mp2629_channels[] = { MP2629_ADC_CHAN(INPUT_CURRENT, IIO_CURRENT) }; -static struct iio_map mp2629_adc_maps[] = { +static const struct iio_map mp2629_adc_maps[] = { MP2629_MAP(BATT_VOLT, "batt-volt"), MP2629_MAP(SYSTEM_VOLT, "system-volt"), MP2629_MAP(INPUT_VOLT, "input-volt"), @@ -195,7 +195,7 @@ static struct platform_driver mp2629_adc_driver = { .of_match_table = mp2629_adc_of_match, }, .probe = mp2629_adc_probe, - .remove_new = mp2629_adc_remove, + .remove = mp2629_adc_remove, }; module_platform_driver(mp2629_adc_driver); diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c index 83161e6d29b901..4eb2455d6ffacb 100644 --- a/drivers/iio/adc/mt6360-adc.c +++ b/drivers/iio/adc/mt6360-adc.c @@ -124,7 +124,7 @@ static int mt6360_adc_read_channel(struct mt6360_adc_data *mad, int channel, int usleep_range(ADC_LOOP_TIME_US / 2, ADC_LOOP_TIME_US); } - *val = rpt[1] << 8 | rpt[2]; + *val = get_unaligned_be16(&rpt[1]); ret = IIO_VAL_INT; out_adc_conv: diff --git a/drivers/iio/adc/mxs-lradc-adc.c b/drivers/iio/adc/mxs-lradc-adc.c index 8c7b64e78dbbc8..152cbe265e1a2e 100644 --- a/drivers/iio/adc/mxs-lradc-adc.c +++ b/drivers/iio/adc/mxs-lradc-adc.c @@ -819,10 +819,10 @@ static void mxs_lradc_adc_remove(struct platform_device *pdev) static struct platform_driver mxs_lradc_adc_driver = { .driver = { - .name = "mxs-lradc-adc", + .name = "mxs-lradc-adc", }, - .probe = mxs_lradc_adc_probe, - .remove_new = mxs_lradc_adc_remove, + .probe = mxs_lradc_adc_probe, + .remove = mxs_lradc_adc_remove, }; module_platform_driver(mxs_lradc_adc_driver); diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index 3a55465951e793..7c1511ee3a4b4a 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -337,7 +337,7 @@ static void npcm_adc_remove(struct platform_device *pdev) static struct platform_driver npcm_adc_driver = { .probe = npcm_adc_probe, - .remove_new = npcm_adc_remove, + .remove = npcm_adc_remove, .driver = { .name = "npcm_adc", .of_match_table = npcm_adc_match, diff --git a/drivers/iio/adc/pac1921.c b/drivers/iio/adc/pac1921.c index 36e813d9c73f1c..b0f6727cfe3835 100644 --- a/drivers/iio/adc/pac1921.c +++ b/drivers/iio/adc/pac1921.c @@ -241,7 +241,7 @@ static inline void pac1921_calc_scale(int dividend, int divisor, int *val, s64 tmp; tmp = div_s64(dividend * (s64)NANO, divisor); - *val = (int)div_s64_rem(tmp, NANO, val2); + *val = div_s64_rem(tmp, NANO, val2); } /* @@ -260,7 +260,7 @@ static void pac1921_calc_current_scales(struct pac1921_priv *priv) int max = (PAC1921_MAX_VSENSE_MV * MICRO) >> i; int vsense_lsb = DIV_ROUND_CLOSEST(max, PAC1921_RES_RESOLUTION); - pac1921_calc_scale(vsense_lsb, (int)priv->rshunt_uohm, + pac1921_calc_scale(vsense_lsb, priv->rshunt_uohm, &priv->current_scales[i][0], &priv->current_scales[i][1]); } @@ -314,7 +314,7 @@ static int pac1921_check_push_overflow(struct iio_dev *indio_dev, s64 timestamp) timestamp); } - priv->prev_ovf_flags = (u8)flags; + priv->prev_ovf_flags = flags; return 0; } @@ -329,8 +329,7 @@ static int pac1921_check_push_overflow(struct iio_dev *indio_dev, s64 timestamp) static int pac1921_read_res(struct pac1921_priv *priv, unsigned long reg, u16 *val) { - int ret = regmap_bulk_read(priv->regmap, (unsigned int)reg, val, - sizeof(*val)); + int ret = regmap_bulk_read(priv->regmap, reg, val, sizeof(*val)); if (ret) return ret; @@ -366,7 +365,7 @@ static int pac1921_read_raw(struct iio_dev *indio_dev, if (ret) return ret; - *val = (int)res_val; + *val = res_val; return IIO_VAL_INT; } @@ -400,10 +399,10 @@ static int pac1921_read_raw(struct iio_dev *indio_dev, s64 tmp = curr_scale[0] * (s64)NANO + curr_scale[1]; /* Multiply by max_vbus (V) / dv_gain */ - tmp *= PAC1921_MAX_VBUS_V >> (int)priv->dv_gain; + tmp *= PAC1921_MAX_VBUS_V >> priv->dv_gain; /* Convert back to INT_PLUS_NANO */ - *val = (int)div_s64_rem(tmp, NANO, val2); + *val = div_s64_rem(tmp, NANO, val2); return IIO_VAL_INT_PLUS_NANO; } @@ -426,7 +425,7 @@ static int pac1921_read_raw(struct iio_dev *indio_dev, * 1/(integr_period_usecs/MICRO) = MICRO/integr_period_usecs */ *val = MICRO; - *val2 = (int)priv->integr_period_usecs; + *val2 = priv->integr_period_usecs; return IIO_VAL_FRACTIONAL; default: @@ -503,7 +502,7 @@ static int pac1921_lookup_scale(const int (*const scales_tbl)[2], size_t size, for (unsigned int i = 0; i < size; i++) if (scales_tbl[i][0] == scale_val && scales_tbl[i][1] == scale_val2) - return (int)i; + return i; return -EINVAL; } @@ -553,7 +552,7 @@ static int pac1921_update_gain_from_scale(struct pac1921_priv *priv, if (ret < 0) return ret; - return pac1921_update_gain(priv, &priv->dv_gain, (u8)ret, + return pac1921_update_gain(priv, &priv->dv_gain, ret, PAC1921_GAIN_DV_GAIN_MASK); case PAC1921_CHAN_VSENSE: ret = pac1921_lookup_scale(pac1921_vsense_scales, @@ -562,7 +561,7 @@ static int pac1921_update_gain_from_scale(struct pac1921_priv *priv, if (ret < 0) return ret; - return pac1921_update_gain(priv, &priv->di_gain, (u8)ret, + return pac1921_update_gain(priv, &priv->di_gain, ret, PAC1921_GAIN_DI_GAIN_MASK); case PAC1921_CHAN_CURRENT: ret = pac1921_lookup_scale(priv->current_scales, @@ -571,7 +570,7 @@ static int pac1921_update_gain_from_scale(struct pac1921_priv *priv, if (ret < 0) return ret; - return pac1921_update_gain(priv, &priv->di_gain, (u8)ret, + return pac1921_update_gain(priv, &priv->di_gain, ret, PAC1921_GAIN_DI_GAIN_MASK); default: return -EINVAL; @@ -586,7 +585,7 @@ static int pac1921_lookup_int_num_samples(int num_samples) { for (unsigned int i = 0; i < ARRAY_SIZE(pac1921_int_num_samples); i++) if (pac1921_int_num_samples[i] == num_samples) - return (int)i; + return i; return -EINVAL; } @@ -607,7 +606,7 @@ static int pac1921_update_int_num_samples(struct pac1921_priv *priv, if (ret < 0) return ret; - n_samples = (u8)ret; + n_samples = ret; if (priv->n_samples == n_samples) return 0; @@ -700,7 +699,8 @@ static int pac1921_read_event_config(struct iio_dev *indio_dev, static int pac1921_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) + enum iio_event_direction dir, + bool state) { struct pac1921_priv *priv = iio_priv(indio_dev); u8 ovf_bit; @@ -770,7 +770,7 @@ static ssize_t pac1921_read_shunt_resistor(struct iio_dev *indio_dev, guard(mutex)(&priv->lock); - vals[0] = (int)priv->rshunt_uohm; + vals[0] = priv->rshunt_uohm; vals[1] = MICRO; return iio_format_value(buf, IIO_VAL_FRACTIONAL, 1, vals); @@ -793,13 +793,13 @@ static ssize_t pac1921_write_shunt_resistor(struct iio_dev *indio_dev, if (ret) return ret; - rshunt_uohm = (u32)val * MICRO + (u32)val_fract; + rshunt_uohm = val * MICRO + val_fract; if (rshunt_uohm == 0 || rshunt_uohm > INT_MAX) return -EINVAL; guard(mutex)(&priv->lock); - priv->rshunt_uohm = (u32)rshunt_uohm; + priv->rshunt_uohm = rshunt_uohm; pac1921_calc_current_scales(priv); @@ -1077,7 +1077,7 @@ static int pac1921_init(struct pac1921_priv *priv) /* * Init control register: * - VPower free run integration mode - * - OUT pin full scale range: 3V (HW detault) + * - OUT pin full scale range: 3V (HW default) * - no timeout, no sleep, no sleep override, no recalc (HW defaults) */ val = FIELD_PREP(PAC1921_CONTROL_MXSL_MASK, @@ -1168,10 +1168,12 @@ static int pac1921_probe(struct i2c_client *client) priv->regmap = devm_regmap_init_i2c(client, &pac1921_regmap_config); if (IS_ERR(priv->regmap)) - return dev_err_probe(dev, (int)PTR_ERR(priv->regmap), + return dev_err_probe(dev, PTR_ERR(priv->regmap), "Cannot initialize register map\n"); - devm_mutex_init(dev, &priv->lock); + ret = devm_mutex_init(dev, &priv->lock); + if (ret) + return ret; priv->dv_gain = PAC1921_DEFAULT_DV_GAIN; priv->di_gain = PAC1921_DEFAULT_DI_GAIN; @@ -1191,7 +1193,7 @@ static int pac1921_probe(struct i2c_client *client) priv->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(priv->vdd)) - return dev_err_probe(dev, (int)PTR_ERR(priv->vdd), + return dev_err_probe(dev, PTR_ERR(priv->vdd), "Cannot get vdd regulator\n"); ret = regulator_enable(priv->vdd); diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index 7ef249d8328661..20802b7f49ea84 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -1507,7 +1507,7 @@ static int pac1934_probe(struct i2c_client *client) indio_dev->name = pac1934_chip_config[ret].name; } - if (acpi_match_device(dev->driver->acpi_match_table, dev)) + if (is_acpi_device_node(dev_fwnode(dev))) ret = pac1934_acpi_parse_channel_config(client, info); else /* diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 203cbbc707198e..d283ee8fb1d2f2 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -456,7 +456,7 @@ static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc, * 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 gain error drift. These parameters vary depending on device and whether * the channel is calibrated (trimmed) or not. */ static int palmas_gpadc_threshold_with_tolerance(int val, const int INL, @@ -676,7 +676,7 @@ 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) + bool state) { struct palmas_gpadc *adc = iio_priv(indio_dev); int adc_chan = chan->channel; diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 9e1112f5acc6a4..31f88cf7f7f182 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -821,7 +821,6 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev, static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc) { - struct fwnode_handle *child; struct pm8xxx_chan_info *ch; int ret; int i; @@ -844,16 +843,15 @@ static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc) return -ENOMEM; i = 0; - device_for_each_child_node(adc->dev, child) { + device_for_each_child_node_scoped(adc->dev, child) { ch = &adc->chans[i]; ret = pm8xxx_xoadc_parse_channel(adc->dev, child, adc->variant->channels, &adc->iio_chans[i], ch); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } + i++; } @@ -1016,7 +1014,7 @@ static struct platform_driver pm8xxx_xoadc_driver = { .of_match_table = pm8xxx_xoadc_id_table, }, .probe = pm8xxx_xoadc_probe, - .remove_new = pm8xxx_xoadc_remove, + .remove = pm8xxx_xoadc_remove, }; module_platform_driver(pm8xxx_xoadc_driver); diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index 9b69f40beed8ea..af3c2f659f5e90 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -830,7 +830,7 @@ static int adc5_get_fw_data(struct adc5_chip *adc) adc->nchannels = device_get_child_node_count(adc->dev); if (!adc->nchannels) - return -EINVAL; + return dev_err_probe(adc->dev, -EINVAL, "no channels defined\n"); adc->iio_chans = devm_kcalloc(adc->dev, adc->nchannels, sizeof(*adc->iio_chans), GFP_KERNEL); @@ -903,7 +903,7 @@ static int adc5_probe(struct platform_device *pdev) ret = adc5_get_fw_data(adc); if (ret) - return dev_err_probe(dev, ret, "adc get dt data failed\n"); + return ret; irq_eoc = platform_get_irq(pdev, 0); if (irq_eoc < 0) { diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index f5c6f1f27b2c7d..00a7f098202543 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -754,7 +754,6 @@ static int vadc_get_fw_data(struct vadc_priv *vadc) const struct vadc_channels *vadc_chan; struct iio_chan_spec *iio_chan; struct vadc_channel_prop prop; - struct fwnode_handle *child; unsigned int index = 0; int ret; @@ -774,12 +773,10 @@ static int vadc_get_fw_data(struct vadc_priv *vadc) iio_chan = vadc->iio_chans; - device_for_each_child_node(vadc->dev, child) { + device_for_each_child_node_scoped(vadc->dev, child) { ret = vadc_get_fw_channel_data(vadc->dev, &prop, child); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } prop.scale_fn_type = vadc_chans[prop.channel].scale_fn_type; vadc->chan_props[index] = prop; diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index 15a21d2860e758..11170b5852d17f 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -592,7 +592,7 @@ static const struct dev_pm_ops rcar_gyroadc_pm_ops = { static struct platform_driver rcar_gyroadc_driver = { .probe = rcar_gyroadc_probe, - .remove_new = rcar_gyroadc_remove, + .remove = rcar_gyroadc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = rcar_gyroadc_match, diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index ce5f3011fe00c4..b33536157adc99 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -185,7 +185,7 @@ static const struct iio_chan_spec rn5t618_adc_iio_channels[] = { RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0") }; -static struct iio_map rn5t618_maps[] = { +static const struct iio_map rn5t618_maps[] = { IIO_MAP("VADP", "rn5t618-power", "vadp"), IIO_MAP("VUSB", "rn5t618-power", "vusb"), { /* sentinel */ } diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c index 654b6a38b650a1..9f7a75168aac31 100644 --- a/drivers/iio/adc/sd_adc_modulator.c +++ b/drivers/iio/adc/sd_adc_modulator.c @@ -159,4 +159,4 @@ module_platform_driver(iio_sd_mod_adc); MODULE_DESCRIPTION("Basic sigma delta modulator"); MODULE_AUTHOR("Arnaud Pouliquen "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_BACKEND); +MODULE_IMPORT_NS("IIO_BACKEND"); diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 616dd729666aa1..2201ee9987ae42 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -906,7 +906,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match); static struct platform_driver stm32_adc_driver = { .probe = stm32_adc_probe, - .remove_new = stm32_adc_remove, + .remove = stm32_adc_remove, .driver = { .name = "stm32-adc-core", .of_match_table = stm32_adc_of_match, diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 32ca26ed59f7af..9d3b23efcc068a 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -2644,7 +2644,7 @@ MODULE_DEVICE_TABLE(of, stm32_adc_of_match); static struct platform_driver stm32_adc_driver = { .probe = stm32_adc_probe, - .remove_new = stm32_adc_remove, + .remove = stm32_adc_remove, .driver = { .name = "stm32-adc", .of_match_table = stm32_adc_of_match, diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 2037f73426d4b3..1f9eca2fb2bf8c 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -1890,11 +1890,11 @@ static struct platform_driver stm32_dfsdm_adc_driver = { .pm = pm_sleep_ptr(&stm32_dfsdm_adc_pm_ops), }, .probe = stm32_dfsdm_adc_probe, - .remove_new = stm32_dfsdm_adc_remove, + .remove = stm32_dfsdm_adc_remove, }; module_platform_driver(stm32_dfsdm_adc_driver); MODULE_DESCRIPTION("STM32 sigma delta ADC"); MODULE_AUTHOR("Arnaud Pouliquen "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_BACKEND); +MODULE_IMPORT_NS("IIO_BACKEND"); diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index bef59fcc0d807c..041dc9ebc04823 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -506,7 +506,7 @@ static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { static struct platform_driver stm32_dfsdm_driver = { .probe = stm32_dfsdm_probe, - .remove_new = stm32_dfsdm_core_remove, + .remove = stm32_dfsdm_core_remove, .driver = { .name = "stm32-dfsdm", .of_match_table = stm32_dfsdm_of_match, diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c index 6a893d484cf703..136b8d9c294f46 100644 --- a/drivers/iio/adc/sun20i-gpadc-iio.c +++ b/drivers/iio/adc/sun20i-gpadc-iio.c @@ -155,7 +155,6 @@ static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev, unsigned int channel; int num_channels, i, ret; struct iio_chan_spec *channels; - struct fwnode_handle *node; num_channels = device_get_child_node_count(dev); if (num_channels == 0) @@ -167,12 +166,10 @@ static int sun20i_gpadc_alloc_channels(struct iio_dev *indio_dev, return -ENOMEM; i = 0; - device_for_each_child_node(dev, node) { + device_for_each_child_node_scoped(dev, node) { ret = fwnode_property_read_u32(node, "reg", &channel); - if (ret) { - fwnode_handle_put(node); + if (ret) return dev_err_probe(dev, ret, "invalid channel number\n"); - } channels[i].type = IIO_VOLTAGE; channels[i].indexed = 1; diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 100ecced5fc11a..8b27458dcd661b 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -114,11 +114,8 @@ struct sun4i_gpadc_iio { .datasheet_name = _name, \ } -static struct iio_map sun4i_gpadc_hwmon_maps[] = { - { - .adc_channel_label = "temp_adc", - .consumer_dev_name = "iio_hwmon.0", - }, +static const struct iio_map sun4i_gpadc_hwmon_maps[] = { + IIO_MAP("temp_adc", "iio_hwmon.0", NULL), { /* sentinel */ }, }; @@ -700,7 +697,7 @@ static struct platform_driver sun4i_gpadc_driver = { }, .id_table = sun4i_gpadc_id, .probe = sun4i_gpadc_probe, - .remove_new = sun4i_gpadc_remove, + .remove = sun4i_gpadc_remove, }; MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_id); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 6d1bc9659946df..47fe8e16aee42d 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -806,7 +806,7 @@ static int ads1015_disable_event_config(struct ads1015_data *data, static int ads1015_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) + enum iio_event_direction dir, bool state) { struct ads1015_data *data = iio_priv(indio_dev); int ret; @@ -1032,8 +1032,7 @@ static int ads1015_probe(struct i2c_client *client) } if (client->irq && chip->has_comparator) { - unsigned long irq_trig = - irqd_get_trigger_type(irq_get_irq_data(client->irq)); + unsigned long irq_trig = irq_get_trigger_type(client->irq); unsigned int cfg_comp_mask = ADS1015_CFG_COMP_QUE_MASK | ADS1015_CFG_COMP_LAT_MASK | ADS1015_CFG_COMP_POL_MASK; unsigned int cfg_comp = diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c index 1c760637514928..e9d9d4d46d3809 100644 --- a/drivers/iio/adc/ti-ads1119.c +++ b/drivers/iio/adc/ti-ads1119.c @@ -804,7 +804,7 @@ static const struct of_device_id __maybe_unused ads1119_of_match[] = { MODULE_DEVICE_TABLE(of, ads1119_of_match); static const struct i2c_device_id ads1119_id[] = { - { "ads1119", 0 }, + { "ads1119" }, { } }; MODULE_DEVICE_TABLE(i2c, ads1119_id); diff --git a/drivers/iio/adc/ti-ads1298.c b/drivers/iio/adc/ti-ads1298.c index 0f9f75baaebbf7..36d43495f603a7 100644 --- a/drivers/iio/adc/ti-ads1298.c +++ b/drivers/iio/adc/ti-ads1298.c @@ -294,7 +294,7 @@ static int ads1298_get_scale(struct ads1298_private *priv, if (ret) return ret; - /* Refererence in millivolts */ + /* Reference in millivolts */ *val = regval & ADS1298_MASK_CONFIG3_VREF_4V ? 4000 : 2400; } diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 426e3c9f88a16e..fe1509d3b1e766 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -494,7 +494,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, /* * We check the complete FIFO. We programmed just one entry but in case * something went wrong we left empty handed (-EAGAIN previously) and - * then the value apeared somehow in the FIFO we would have two entries. + * then the value appeared somehow in the FIFO we would have two entries. * Therefore we read every item and keep only the latest version of the * requested channel. */ @@ -740,12 +740,12 @@ MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); static struct platform_driver tiadc_driver = { .driver = { - .name = "TI-am335x-adc", - .pm = pm_sleep_ptr(&tiadc_pm_ops), + .name = "TI-am335x-adc", + .pm = pm_sleep_ptr(&tiadc_pm_ops), .of_match_table = ti_adc_dt_ids, }, - .probe = tiadc_probe, - .remove_new = tiadc_remove, + .probe = tiadc_probe, + .remove = tiadc_remove, }; module_platform_driver(tiadc_driver); diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 0253064fadec84..0ea51ddeaa0a0a 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -248,7 +248,7 @@ static const struct s16_fract twl4030_divider_ratios[16] = { {15, 100}, /* CHANNEL 11 */ {1, 4}, /* CHANNEL 12 */ {1, 1}, /* CHANNEL 13 Reserved channels */ - {1, 1}, /* CHANNEL 14 Reseved channels */ + {1, 1}, /* CHANNEL 14 Reserved channels */ {5, 11}, /* CHANNEL 15 */ }; @@ -914,7 +914,7 @@ MODULE_DEVICE_TABLE(of, twl_madc_of_match); static struct platform_driver twl4030_madc_driver = { .probe = twl4030_madc_probe, - .remove_new = twl4030_madc_remove, + .remove = twl4030_madc_remove, .driver = { .name = "twl4030_madc", .of_match_table = twl_madc_of_match, diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 6a3db2bce46090..ef7430e6877dcd 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -1003,7 +1003,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend, static struct platform_driver twl6030_gpadc_driver = { .probe = twl6030_gpadc_probe, - .remove_new = twl6030_gpadc_remove, + .remove = twl6030_gpadc_remove, .driver = { .name = DRIVER_NAME, .pm = pm_sleep_ptr(&twl6030_gpadc_pm_ops), diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 5afd2feb8c3ddc..4d83c12975c53a 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -972,7 +972,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend, static struct platform_driver vf610_adc_driver = { .probe = vf610_adc_probe, - .remove_new = vf610_adc_remove, + .remove = vf610_adc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = vf610_adc_match, diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index ebc583b07e0c00..76dd0343f5f76a 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -905,7 +905,7 @@ static int ams_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) + bool state) { struct ams *ams = iio_priv(indio_dev); unsigned int alarm; diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c index 1bd375fb10e085..c188d3dcab48fe 100644 --- a/drivers/iio/adc/xilinx-xadc-events.c +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -121,7 +121,7 @@ int xadc_read_event_config(struct iio_dev *indio_dev, int xadc_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) + enum iio_event_direction dir, bool state) { unsigned int alarm = xadc_get_alarm_mask(chan); struct xadc *xadc = iio_priv(indio_dev); @@ -220,7 +220,7 @@ int xadc_write_event_value(struct iio_dev *indio_dev, /* * Since we store the hysteresis as relative (to the threshold) * value, but the hardware expects an absolute value we need to - * recalcualte this value whenever the hysteresis or the + * recalculate this value whenever the hysteresis or the * threshold changes. */ if (xadc->threshold[offset] < xadc->temp_hysteresis) diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index 3036f4d613ff5d..b4d9d468311723 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -25,7 +25,7 @@ int xadc_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir); int xadc_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); + enum iio_event_direction dir, bool state); int xadc_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, diff --git a/drivers/iio/addac/ad74115.c b/drivers/iio/addac/ad74115.c index 3ee0dd5537c168..a7e480f2472db9 100644 --- a/drivers/iio/addac/ad74115.c +++ b/drivers/iio/addac/ad74115.c @@ -191,7 +191,7 @@ enum ad74115_gpio_mode { }; struct ad74115_channels { - struct iio_chan_spec *channels; + const struct iio_chan_spec *channels; unsigned int num_channels; }; @@ -1295,46 +1295,46 @@ static const struct iio_info ad74115_info = { _AD74115_ADC_CHANNEL(_type, index, BIT(IIO_CHAN_INFO_SCALE) \ | BIT(IIO_CHAN_INFO_OFFSET)) -static struct iio_chan_spec ad74115_voltage_input_channels[] = { +static const struct iio_chan_spec ad74115_voltage_input_channels[] = { AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2), }; -static struct iio_chan_spec ad74115_voltage_output_channels[] = { +static const struct iio_chan_spec ad74115_voltage_output_channels[] = { AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_MAIN), AD74115_ADC_CHANNEL(IIO_CURRENT, AD74115_ADC_CH_CONV1), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2), }; -static struct iio_chan_spec ad74115_current_input_channels[] = { +static const struct iio_chan_spec ad74115_current_input_channels[] = { AD74115_ADC_CHANNEL(IIO_CURRENT, AD74115_ADC_CH_CONV1), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2), }; -static struct iio_chan_spec ad74115_current_output_channels[] = { +static const struct iio_chan_spec ad74115_current_output_channels[] = { AD74115_DAC_CHANNEL(IIO_CURRENT, AD74115_DAC_CH_MAIN), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2), }; -static struct iio_chan_spec ad74115_2_wire_resistance_input_channels[] = { +static const struct iio_chan_spec ad74115_2_wire_resistance_input_channels[] = { _AD74115_ADC_CHANNEL(IIO_RESISTANCE, AD74115_ADC_CH_CONV1, BIT(IIO_CHAN_INFO_PROCESSED)), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2), }; -static struct iio_chan_spec ad74115_3_4_wire_resistance_input_channels[] = { +static const struct iio_chan_spec ad74115_3_4_wire_resistance_input_channels[] = { AD74115_ADC_CHANNEL(IIO_RESISTANCE, AD74115_ADC_CH_CONV1), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2), }; -static struct iio_chan_spec ad74115_digital_input_logic_channels[] = { +static const struct iio_chan_spec ad74115_digital_input_logic_channels[] = { AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_COMPARATOR), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV2), }; -static struct iio_chan_spec ad74115_digital_input_loop_channels[] = { +static const struct iio_chan_spec ad74115_digital_input_loop_channels[] = { AD74115_DAC_CHANNEL(IIO_CURRENT, AD74115_DAC_CH_MAIN), AD74115_DAC_CHANNEL(IIO_VOLTAGE, AD74115_DAC_CH_COMPARATOR), AD74115_ADC_CHANNEL(IIO_VOLTAGE, AD74115_ADC_CH_CONV1), diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index 69c586525d2158..daea2bde7acf95 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -6,9 +6,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -45,8 +47,8 @@ struct ad74413r_channel_config { }; struct ad74413r_channels { - struct iio_chan_spec *channels; - unsigned int num_channels; + const struct iio_chan_spec *channels; + unsigned int num_channels; }; struct ad74413r_state { @@ -59,7 +61,7 @@ struct ad74413r_state { unsigned int num_gpo_gpios; unsigned int num_comparator_gpios; u32 sense_resistor_ohms; - + int refin_reg_uv; /* * Synchronize consecutive operations when doing a one-shot * conversion and when updating the ADC samples SPI message. @@ -68,11 +70,9 @@ struct ad74413r_state { const struct ad74413r_chip_info *chip_info; struct spi_device *spi; - struct regulator *refin_reg; struct regmap *regmap; struct device *dev; struct iio_trigger *trig; - struct gpio_desc *reset_gpio; size_t adc_active_channels; struct spi_message adc_samples_msg; @@ -407,12 +407,16 @@ static int ad74413r_gpio_set_comp_config(struct gpio_chip *chip, static int ad74413r_reset(struct ad74413r_state *st) { + struct gpio_desc *reset_gpio; int ret; - if (st->reset_gpio) { - gpiod_set_value_cansleep(st->reset_gpio, 1); + reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); + + if (reset_gpio) { fsleep(50); - gpiod_set_value_cansleep(st->reset_gpio, 0); + gpiod_set_value_cansleep(reset_gpio, 0); return 0; } @@ -660,7 +664,7 @@ static int ad74413r_get_output_voltage_scale(struct ad74413r_state *st, static int ad74413r_get_output_current_scale(struct ad74413r_state *st, int *val, int *val2) { - *val = regulator_get_voltage(st->refin_reg); + *val = st->refin_reg_uv; *val2 = st->sense_resistor_ohms * AD74413R_DAC_CODE_MAX * 1000; return IIO_VAL_FRACTIONAL; @@ -861,19 +865,12 @@ static int ad74413r_get_single_adc_result(struct iio_dev *indio_dev, unsigned int channel, int *val) { struct ad74413r_state *st = iio_priv(indio_dev); - int ret; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - mutex_lock(&st->lock); - ret = _ad74413r_get_single_adc_result(st, channel, val); - mutex_unlock(&st->lock); - - iio_device_release_direct_mode(indio_dev); - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + guard(mutex)(&st->lock); + return _ad74413r_get_single_adc_result(st, channel, val); + } + unreachable(); } static void ad74413r_adc_to_resistance_result(int adc_result, int *val) @@ -895,7 +892,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, unsigned int channel; int ret = -EINVAL; - mutex_lock(&st->lock); + guard(mutex)(&st->lock); spi_message_init(&st->adc_samples_msg); st->adc_active_channels = 0; @@ -903,11 +900,11 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, for_each_clear_bit(channel, active_scan_mask, AD74413R_CHANNEL_MAX) { ret = ad74413r_set_adc_channel_enable(st, channel, false); if (ret) - goto out; + return ret; } if (*active_scan_mask == 0) - goto out; + return ret; /* * The read select register is used to select which register's value @@ -925,7 +922,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, for_each_set_bit(channel, active_scan_mask, AD74413R_CHANNEL_MAX) { ret = ad74413r_set_adc_channel_enable(st, channel, true); if (ret) - goto out; + return ret; st->adc_active_channels++; @@ -956,11 +953,7 @@ static int ad74413r_update_scan_mode(struct iio_dev *indio_dev, xfer->cs_change = 0; spi_message_add_tail(xfer, &st->adc_samples_msg); - -out: - mutex_unlock(&st->lock); - - return ret; + return 0; } static int ad74413r_buffer_postenable(struct iio_dev *indio_dev) @@ -1138,34 +1131,34 @@ static const struct iio_info ad74413r_info = { AD74413R_ADC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE) \ | BIT(IIO_CHAN_INFO_OFFSET)) -static struct iio_chan_spec ad74413r_voltage_output_channels[] = { +static const struct iio_chan_spec ad74413r_voltage_output_channels[] = { AD74413R_DAC_CHANNEL(IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE)), AD74413R_ADC_CURRENT_CHANNEL, }; -static struct iio_chan_spec ad74413r_current_output_channels[] = { +static const struct iio_chan_spec ad74413r_current_output_channels[] = { AD74413R_DAC_CHANNEL(IIO_CURRENT, BIT(IIO_CHAN_INFO_SCALE)), AD74413R_ADC_VOLTAGE_CHANNEL, }; -static struct iio_chan_spec ad74413r_voltage_input_channels[] = { +static const struct iio_chan_spec ad74413r_voltage_input_channels[] = { AD74413R_ADC_VOLTAGE_CHANNEL, }; -static struct iio_chan_spec ad74413r_current_input_channels[] = { +static const struct iio_chan_spec ad74413r_current_input_channels[] = { AD74413R_ADC_CURRENT_CHANNEL, }; -static struct iio_chan_spec ad74413r_current_input_loop_channels[] = { +static const 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[] = { +static const struct iio_chan_spec ad74413r_resistance_input_channels[] = { AD74413R_ADC_CHANNEL(IIO_RESISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)), }; -static struct iio_chan_spec ad74413r_digital_input_channels[] = { +static const struct iio_chan_spec ad74413r_digital_input_channels[] = { AD74413R_ADC_VOLTAGE_CHANNEL, }; @@ -1270,7 +1263,8 @@ static int ad74413r_setup_channels(struct iio_dev *indio_dev) { struct ad74413r_state *st = iio_priv(indio_dev); struct ad74413r_channel_config *config; - struct iio_chan_spec *channels, *chans; + const struct iio_chan_spec *chans; + struct iio_chan_spec *channels; unsigned int i, num_chans, chan_i; int ret; @@ -1346,11 +1340,6 @@ static int ad74413r_setup_gpios(struct ad74413r_state *st) return 0; } -static void ad74413r_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int ad74413r_probe(struct spi_device *spi) { struct ad74413r_state *st; @@ -1369,7 +1358,10 @@ static int ad74413r_probe(struct spi_device *spi) if (!st->chip_info) return -EINVAL; - mutex_init(&st->lock); + ret = devm_mutex_init(st->dev, &st->lock); + if (ret) + return ret; + init_completion(&st->adc_data_completion); st->regmap = devm_regmap_init(st->dev, NULL, st, @@ -1377,23 +1369,11 @@ static int ad74413r_probe(struct spi_device *spi) if (IS_ERR(st->regmap)) return PTR_ERR(st->regmap); - st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(st->reset_gpio)) - return PTR_ERR(st->reset_gpio); - - st->refin_reg = devm_regulator_get(st->dev, "refin"); - if (IS_ERR(st->refin_reg)) - return dev_err_probe(st->dev, PTR_ERR(st->refin_reg), - "Failed to get refin regulator\n"); - - ret = regulator_enable(st->refin_reg); - if (ret) - return ret; - - ret = devm_add_action_or_reset(st->dev, ad74413r_regulator_disable, - st->refin_reg); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(st->dev, "refin"); + if (ret < 0) + return dev_err_probe(st->dev, ret, + "Failed to get refin regulator voltage\n"); + st->refin_reg_uv = ret; st->sense_resistor_ohms = 100000000; device_property_read_u32(st->dev, "shunt-resistor-micro-ohms", diff --git a/drivers/iio/addac/stx104.c b/drivers/iio/addac/stx104.c index 6946a65512ca29..7bdf2cb9417657 100644 --- a/drivers/iio/addac/stx104.c +++ b/drivers/iio/addac/stx104.c @@ -520,4 +520,4 @@ module_isa_driver(stx104_driver, num_stx104); MODULE_AUTHOR("William Breathitt Gray "); MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(I8254); +MODULE_IMPORT_NS("I8254"); diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index 56e5913ab82d1c..b6a46036d5eadf 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -107,7 +107,7 @@ int rescale_process_scale(struct rescale *rescale, int scale_type, return -EOPNOTSUPP; } } -EXPORT_SYMBOL_NS_GPL(rescale_process_scale, IIO_RESCALE); +EXPORT_SYMBOL_NS_GPL(rescale_process_scale, "IIO_RESCALE"); int rescale_process_offset(struct rescale *rescale, int scale_type, int scale, int scale2, int schan_off, @@ -141,7 +141,7 @@ int rescale_process_offset(struct rescale *rescale, int scale_type, return -EOPNOTSUPP; } } -EXPORT_SYMBOL_NS_GPL(rescale_process_offset, IIO_RESCALE); +EXPORT_SYMBOL_NS_GPL(rescale_process_offset, "IIO_RESCALE"); static int rescale_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index dbde1443d6ede5..7ea784304ffb8d 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -248,7 +248,7 @@ void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block) iio_dma_buffer_queue_wake(queue); dma_fence_end_signalling(cookie); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_block_done, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_block_done, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_block_list_abort() - Indicate that a list block has been @@ -287,7 +287,7 @@ void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue, iio_dma_buffer_queue_wake(queue); dma_fence_end_signalling(cookie); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_block_list_abort, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_block_list_abort, "IIO_DMA_BUFFER"); static bool iio_dma_block_reusable(struct iio_dma_buffer_block *block) { @@ -420,7 +420,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer) return ret; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_request_update, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_request_update, "IIO_DMA_BUFFER"); static void iio_dma_buffer_fileio_free(struct iio_dma_buffer_queue *queue) { @@ -506,7 +506,7 @@ int iio_dma_buffer_enable(struct iio_buffer *buffer, return 0; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_enable, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_enable, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_disable() - Disable DMA buffer @@ -530,7 +530,7 @@ int iio_dma_buffer_disable(struct iio_buffer *buffer, return 0; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_disable, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_disable, "IIO_DMA_BUFFER"); static void iio_dma_buffer_enqueue(struct iio_dma_buffer_queue *queue, struct iio_dma_buffer_block *block) @@ -636,7 +636,7 @@ int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n, { return iio_dma_buffer_io(buffer, n, user_buffer, false); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_read, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_read, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_write() - DMA buffer write callback @@ -653,7 +653,7 @@ int iio_dma_buffer_write(struct iio_buffer *buffer, size_t n, return iio_dma_buffer_io(buffer, n, (__force __user char *)user_buffer, true); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_write, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_write, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_usage() - DMA buffer data_available and @@ -696,7 +696,7 @@ size_t iio_dma_buffer_usage(struct iio_buffer *buf) return data_available; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_usage, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_usage, "IIO_DMA_BUFFER"); struct iio_dma_buffer_block * iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer, @@ -723,7 +723,7 @@ iio_dma_buffer_attach_dmabuf(struct iio_buffer *buffer, return block; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_attach_dmabuf, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_attach_dmabuf, "IIO_DMA_BUFFER"); void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer, struct iio_dma_buffer_block *block) @@ -731,7 +731,7 @@ void iio_dma_buffer_detach_dmabuf(struct iio_buffer *buffer, block->state = IIO_BLOCK_STATE_DEAD; iio_buffer_block_put_atomic(block); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_detach_dmabuf, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_detach_dmabuf, "IIO_DMA_BUFFER"); static int iio_dma_can_enqueue_block(struct iio_dma_buffer_block *block) { @@ -784,7 +784,7 @@ int iio_dma_buffer_enqueue_dmabuf(struct iio_buffer *buffer, return ret; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_enqueue_dmabuf, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_enqueue_dmabuf, "IIO_DMA_BUFFER"); void iio_dma_buffer_lock_queue(struct iio_buffer *buffer) { @@ -792,7 +792,7 @@ void iio_dma_buffer_lock_queue(struct iio_buffer *buffer) mutex_lock(&queue->lock); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_lock_queue, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_lock_queue, "IIO_DMA_BUFFER"); void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer) { @@ -800,7 +800,7 @@ void iio_dma_buffer_unlock_queue(struct iio_buffer *buffer) mutex_unlock(&queue->lock); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_unlock_queue, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_unlock_queue, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback @@ -816,7 +816,7 @@ int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd) return 0; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_set_bytes_per_datum, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_set_bytes_per_datum, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_set_length - DMA buffer set_length callback @@ -836,7 +836,7 @@ int iio_dma_buffer_set_length(struct iio_buffer *buffer, unsigned int length) return 0; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_set_length, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_set_length, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_init() - Initialize DMA buffer queue @@ -864,7 +864,7 @@ int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue, return 0; } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_init, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_init, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_exit() - Cleanup DMA buffer queue @@ -882,7 +882,7 @@ void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue) mutex_unlock(&queue->lock); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_exit, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_exit, "IIO_DMA_BUFFER"); /** * iio_dma_buffer_release() - Release final buffer resources @@ -896,7 +896,7 @@ void iio_dma_buffer_release(struct iio_dma_buffer_queue *queue) { mutex_destroy(&queue->lock); } -EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_release, IIO_DMA_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dma_buffer_release, "IIO_DMA_BUFFER"); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("DMA buffer for the IIO framework"); diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 19af1caf14cd34..d2e1529ad8fd5e 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -286,7 +286,7 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer) iio_buffer_put(buffer); } -EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, IIO_DMAENGINE_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_free, "IIO_DMAENGINE_BUFFER"); struct iio_buffer *iio_dmaengine_buffer_setup_ext(struct device *dev, struct iio_dev *indio_dev, @@ -312,7 +312,7 @@ struct iio_buffer *iio_dmaengine_buffer_setup_ext(struct device *dev, return buffer; } -EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_setup_ext, IIO_DMAENGINE_BUFFER); +EXPORT_SYMBOL_NS_GPL(iio_dmaengine_buffer_setup_ext, "IIO_DMAENGINE_BUFFER"); static void __devm_iio_dmaengine_buffer_free(void *buffer) { @@ -345,9 +345,9 @@ int devm_iio_dmaengine_buffer_setup_ext(struct device *dev, return devm_add_action_or_reset(dev, __devm_iio_dmaengine_buffer_free, buffer); } -EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup_ext, IIO_DMAENGINE_BUFFER); +EXPORT_SYMBOL_NS_GPL(devm_iio_dmaengine_buffer_setup_ext, "IIO_DMAENGINE_BUFFER"); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("DMA buffer for the IIO framework"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_DMA_BUFFER); +MODULE_IMPORT_NS("IIO_DMA_BUFFER"); diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c index 4c03b9e834b88d..e64a41bae32c67 100644 --- a/drivers/iio/cdc/ad7150.c +++ b/drivers/iio/cdc/ad7150.c @@ -232,7 +232,7 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, static int ad7150_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) + enum iio_event_direction dir, bool state) { struct ad7150_chip_info *chip = iio_priv(indio_dev); int ret = 0; diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig index 6c87223f58d903..330fe0af946f75 100644 --- a/drivers/iio/chemical/Kconfig +++ b/drivers/iio/chemical/Kconfig @@ -50,6 +50,8 @@ config BME680 select REGMAP select BME680_I2C if I2C select BME680_SPI if SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for Bosch Sensortec BME680 sensor with temperature, pressure, humidity and gas sensing capability. diff --git a/drivers/iio/chemical/bme680.h b/drivers/iio/chemical/bme680.h index b2c547ac8d3499..00ab89b3138b4f 100644 --- a/drivers/iio/chemical/bme680.h +++ b/drivers/iio/chemical/bme680.h @@ -2,6 +2,8 @@ #ifndef BME680_H_ #define BME680_H_ +#include + #define BME680_REG_CHIP_ID 0xD0 #define BME680_CHIP_ID_VAL 0x61 #define BME680_REG_SOFT_RESET 0xE0 @@ -25,8 +27,6 @@ #define BME680_OSRS_TEMP_MASK GENMASK(7, 5) #define BME680_OSRS_PRESS_MASK GENMASK(4, 2) #define BME680_MODE_MASK GENMASK(1, 0) -#define BME680_MODE_FORCED 1 -#define BME680_MODE_SLEEP 0 #define BME680_REG_CONFIG 0x75 #define BME680_FILTER_MASK GENMASK(4, 2) @@ -42,6 +42,7 @@ #define BME680_RHRANGE_MASK GENMASK(5, 4) #define BME680_REG_RES_HEAT_VAL 0x00 #define BME680_RSERROR_MASK GENMASK(7, 4) +#define BME680_REG_IDAC_HEAT_0 0x50 #define BME680_REG_RES_HEAT_0 0x5A #define BME680_REG_GAS_WAIT_0 0x64 #define BME680_ADC_GAS_RES GENMASK(15, 6) @@ -63,7 +64,11 @@ #define BME680_MEAS_TRIM_MASK GENMASK(24, 4) -#define BME680_STARTUP_TIME_US 5000 +/* Datasheet Section 1.1, Table 1 */ +#define BME680_STARTUP_TIME_US 2000 + +#define BME680_NUM_CHANNELS 4 +#define BME680_NUM_BULK_READ_REGS 15 /* Calibration Parameters */ #define BME680_T2_LSB_REG 0x8A diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index 0b96534c6867a6..d12270409c8ad2 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -16,8 +16,11 @@ #include #include +#include #include #include +#include +#include #include @@ -95,6 +98,19 @@ struct bme680_calib { s8 range_sw_err; }; +/* values of CTRL_MEAS register */ +enum bme680_op_mode { + BME680_MODE_SLEEP = 0, + BME680_MODE_FORCED = 1, +}; + +enum bme680_scan { + BME680_TEMP, + BME680_PRESS, + BME680_HUMID, + BME680_GAS, +}; + struct bme680_data { struct regmap *regmap; struct bme680_calib bme680; @@ -102,11 +118,17 @@ struct bme680_data { u8 oversampling_temp; u8 oversampling_press; u8 oversampling_humid; + u8 preheat_curr_mA; u16 heater_dur; u16 heater_temp; + struct { + s32 chan[4]; + aligned_s64 ts; + } scan; + union { - u8 buf[3]; + u8 buf[BME680_NUM_BULK_READ_REGS]; unsigned int check; __be16 be16; u8 bme680_cal_buf_1[BME680_CALIB_RANGE_1_LEN]; @@ -133,27 +155,71 @@ const struct regmap_config bme680_regmap_config = { .volatile_table = &bme680_volatile_table, .cache_type = REGCACHE_RBTREE, }; -EXPORT_SYMBOL_NS(bme680_regmap_config, IIO_BME680); +EXPORT_SYMBOL_NS(bme680_regmap_config, "IIO_BME680"); static const struct iio_chan_spec bme680_channels[] = { { .type = IIO_TEMP, + /* PROCESSED maintained for ABI backwards compatibility */ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, }, { .type = IIO_PRESSURE, + /* PROCESSED maintained for ABI backwards compatibility */ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_CPU, + }, }, { .type = IIO_HUMIDITYRELATIVE, + /* PROCESSED maintained for ABI backwards compatibility */ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .scan_index = 2, + .scan_type = { + .sign = 'u', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_CPU, + }, }, { .type = IIO_RESISTANCE, .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index = 3, + .scan_type = { + .sign = 'u', + .realbits = 32, + .storagebits = 32, + .endianness = IIO_CPU, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(4), + { + .type = IIO_CURRENT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .output = 1, + .scan_index = -1, }, }; @@ -224,7 +290,7 @@ static int bme680_read_calib(struct bme680_data *data, calib->res_heat_val = data->bme680_cal_buf_3[RES_HEAT_VAL]; calib->res_heat_range = FIELD_GET(BME680_RHRANGE_MASK, - data->bme680_cal_buf_3[RES_HEAT_RANGE]); + data->bme680_cal_buf_3[RES_HEAT_RANGE]); calib->range_sw_err = FIELD_GET(BME680_RSERROR_MASK, data->bme680_cal_buf_3[RANGE_SW_ERR]); @@ -438,19 +504,19 @@ static u32 bme680_compensate_gas(struct bme680_data *data, u16 gas_res_adc, u32 calc_gas_res; /* Look up table for the possible gas range values */ - static const u32 lookupTable[16] = {2147483647u, 2147483647u, - 2147483647u, 2147483647u, 2147483647u, - 2126008810u, 2147483647u, 2130303777u, - 2147483647u, 2147483647u, 2143188679u, - 2136746228u, 2147483647u, 2126008810u, - 2147483647u, 2147483647u}; - - var1 = ((1340 + (5 * (s64) calib->range_sw_err)) * - ((s64) lookupTable[gas_range])) >> 16; + static const u32 lookup_table[16] = { + 2147483647u, 2147483647u, 2147483647u, 2147483647u, + 2147483647u, 2126008810u, 2147483647u, 2130303777u, + 2147483647u, 2147483647u, 2143188679u, 2136746228u, + 2147483647u, 2126008810u, 2147483647u, 2147483647u + }; + + var1 = ((1340LL + (5 * calib->range_sw_err)) * + (lookup_table[gas_range])) >> 16; var2 = ((gas_res_adc << 15) - 16777216) + var1; var3 = ((125000 << (15 - gas_range)) * var1) >> 9; var3 += (var2 >> 1); - calc_gas_res = div64_s64(var3, (s64) var2); + calc_gas_res = div64_s64(var3, (s64)var2); return calc_gas_res; } @@ -468,7 +534,7 @@ static u8 bme680_calc_heater_res(struct bme680_data *data, u16 temp) if (temp > 400) /* Cap temperature */ temp = 400; - var1 = (((s32) BME680_AMB_TEMP * calib->par_gh3) / 1000) * 256; + var1 = (((s32)BME680_AMB_TEMP * calib->par_gh3) / 1000) * 256; var2 = (calib->par_gh1 + 784) * (((((calib->par_gh2 + 154009) * temp * 5) / 100) + 3276800) / 10); @@ -502,23 +568,22 @@ static u8 bme680_calc_heater_dur(u16 dur) return durval; } -static int bme680_set_mode(struct bme680_data *data, bool mode) +/* Taken from datasheet, section 5.3.3 */ +static u8 bme680_calc_heater_preheat_current(u8 curr) +{ + return 8 * curr - 1; +} + +static int bme680_set_mode(struct bme680_data *data, enum bme680_op_mode mode) { struct device *dev = regmap_get_device(data->regmap); int ret; - if (mode) { - ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS, - BME680_MODE_MASK, BME680_MODE_FORCED); - if (ret < 0) - dev_err(dev, "failed to set forced mode\n"); - - } else { - ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS, - BME680_MODE_MASK, BME680_MODE_SLEEP); - if (ret < 0) - dev_err(dev, "failed to set sleep mode\n"); - + ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS, + BME680_MODE_MASK, mode); + if (ret < 0) { + dev_err(dev, "failed to set ctrl_meas register\n"); + return ret; } return ret; @@ -546,7 +611,7 @@ static int bme680_wait_for_eoc(struct bme680_data *data) data->oversampling_humid) * 1936) + (477 * 4) + (477 * 5) + 1000 + (data->heater_dur * 1000); - usleep_range(wait_eoc_us, wait_eoc_us + 100); + fsleep(wait_eoc_us); ret = regmap_read(data->regmap, BME680_REG_MEAS_STAT_0, &data->check); if (ret) { @@ -571,9 +636,8 @@ static int bme680_chip_config(struct bme680_data *data) int ret; u8 osrs; - osrs = FIELD_PREP( - BME680_OSRS_HUMIDITY_MASK, - bme680_oversampling_to_reg(data->oversampling_humid)); + osrs = FIELD_PREP(BME680_OSRS_HUMIDITY_MASK, + bme680_oversampling_to_reg(data->oversampling_humid)); /* * Highly recommended to set oversampling of humidity before * temperature/pressure oversampling. @@ -587,8 +651,7 @@ static int bme680_chip_config(struct bme680_data *data) /* IIR filter settings */ ret = regmap_update_bits(data->regmap, BME680_REG_CONFIG, - BME680_FILTER_MASK, - BME680_FILTER_COEFF_VAL); + BME680_FILTER_MASK, BME680_FILTER_COEFF_VAL); if (ret < 0) { dev_err(dev, "failed to write config register\n"); return ret; @@ -609,14 +672,27 @@ static int bme680_chip_config(struct bme680_data *data) return 0; } +static int bme680_preheat_curr_config(struct bme680_data *data, u8 val) +{ + struct device *dev = regmap_get_device(data->regmap); + u8 heatr_curr; + int ret; + + heatr_curr = bme680_calc_heater_preheat_current(val); + ret = regmap_write(data->regmap, BME680_REG_IDAC_HEAT_0, heatr_curr); + if (ret < 0) + dev_err(dev, "failed to write idac_heat_0 register\n"); + + return ret; +} + static int bme680_gas_config(struct bme680_data *data) { struct device *dev = regmap_get_device(data->regmap); int ret; u8 heatr_res, heatr_dur; - /* Go to sleep */ - ret = bme680_set_mode(data, false); + ret = bme680_set_mode(data, BME680_MODE_SLEEP); if (ret < 0) return ret; @@ -638,6 +714,10 @@ static int bme680_gas_config(struct bme680_data *data) return ret; } + ret = bme680_preheat_curr_config(data, data->preheat_curr_mA); + if (ret) + return ret; + /* Enable the gas sensor and select heater profile set-point 0 */ ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_GAS_1, BME680_RUN_GAS_MASK | BME680_NB_CONV_MASK, @@ -649,23 +729,20 @@ static int bme680_gas_config(struct bme680_data *data) return ret; } -static int bme680_read_temp(struct bme680_data *data, int *val) +static int bme680_read_temp(struct bme680_data *data, s16 *comp_temp) { int ret; u32 adc_temp; - s16 comp_temp; ret = bme680_read_temp_adc(data, &adc_temp); if (ret) return ret; - comp_temp = bme680_compensate_temp(data, adc_temp); - *val = comp_temp * 10; /* Centidegrees to millidegrees */ - return IIO_VAL_INT; + *comp_temp = bme680_compensate_temp(data, adc_temp); + return 0; } -static int bme680_read_press(struct bme680_data *data, - int *val, int *val2) +static int bme680_read_press(struct bme680_data *data, u32 *comp_press) { int ret; u32 adc_press; @@ -679,16 +756,14 @@ static int bme680_read_press(struct bme680_data *data, if (ret) return ret; - *val = bme680_compensate_press(data, adc_press, t_fine); - *val2 = 1000; - return IIO_VAL_FRACTIONAL; + *comp_press = bme680_compensate_press(data, adc_press, t_fine); + return 0; } -static int bme680_read_humid(struct bme680_data *data, - int *val, int *val2) +static int bme680_read_humid(struct bme680_data *data, u32 *comp_humidity) { int ret; - u32 adc_humidity, comp_humidity; + u32 adc_humidity; s32 t_fine; ret = bme680_get_t_fine(data, &t_fine); @@ -699,15 +774,11 @@ static int bme680_read_humid(struct bme680_data *data, if (ret) return ret; - comp_humidity = bme680_compensate_humid(data, adc_humidity, t_fine); - - *val = comp_humidity; - *val2 = 1000; - return IIO_VAL_FRACTIONAL; + *comp_humidity = bme680_compensate_humid(data, adc_humidity, t_fine); + return 0; } -static int bme680_read_gas(struct bme680_data *data, - int *val) +static int bme680_read_gas(struct bme680_data *data, int *comp_gas_res) { struct device *dev = regmap_get_device(data->regmap); int ret; @@ -742,9 +813,8 @@ static int bme680_read_gas(struct bme680_data *data, } gas_range = FIELD_GET(BME680_GAS_RANGE_MASK, gas_regs_val); - - *val = bme680_compensate_gas(data, adc_gas_res, gas_range); - return IIO_VAL_INT; + *comp_gas_res = bme680_compensate_gas(data, adc_gas_res, gas_range); + return 0; } static int bme680_read_raw(struct iio_dev *indio_dev, @@ -752,12 +822,12 @@ static int bme680_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct bme680_data *data = iio_priv(indio_dev); - int ret; + int chan_val, ret; + s16 temp_chan_val; guard(mutex)(&data->lock); - /* set forced mode to trigger measurement */ - ret = bme680_set_mode(data, true); + ret = bme680_set_mode(data, BME680_MODE_FORCED); if (ret < 0) return ret; @@ -769,13 +839,77 @@ static int bme680_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_TEMP: - return bme680_read_temp(data, val); + ret = bme680_read_temp(data, &temp_chan_val); + if (ret) + return ret; + + *val = temp_chan_val * 10; + return IIO_VAL_INT; case IIO_PRESSURE: - return bme680_read_press(data, val, val2); + ret = bme680_read_press(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; case IIO_HUMIDITYRELATIVE: - return bme680_read_humid(data, val, val2); + ret = bme680_read_humid(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; case IIO_RESISTANCE: - return bme680_read_gas(data, val); + ret = bme680_read_gas(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + ret = bme680_read_temp(data, (s16 *)&chan_val); + if (ret) + return ret; + + *val = chan_val; + return IIO_VAL_INT; + case IIO_PRESSURE: + ret = bme680_read_press(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + return IIO_VAL_INT; + case IIO_HUMIDITYRELATIVE: + ret = bme680_read_humid(data, &chan_val); + if (ret) + return ret; + + *val = chan_val; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + *val = 10; + return IIO_VAL_INT; + case IIO_PRESSURE: + *val = 1; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; + case IIO_HUMIDITYRELATIVE: + *val = 1; + *val2 = 1000; + return IIO_VAL_FRACTIONAL; default: return -EINVAL; } @@ -836,6 +970,15 @@ static int bme680_write_raw(struct iio_dev *indio_dev, return bme680_chip_config(data); } + case IIO_CHAN_INFO_PROCESSED: + { + switch (chan->type) { + case IIO_CURRENT: + return bme680_preheat_curr_config(data, (u8)val); + default: + return -EINVAL; + } + } default: return -EINVAL; } @@ -861,6 +1004,86 @@ static const struct iio_info bme680_info = { .attrs = &bme680_attribute_group, }; +static const unsigned long bme680_avail_scan_masks[] = { + BIT(BME680_GAS) | BIT(BME680_HUMID) | BIT(BME680_PRESS) | BIT(BME680_TEMP), + 0 +}; + +static irqreturn_t bme680_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bme680_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + u32 adc_temp, adc_press, adc_humid; + u16 adc_gas_res, gas_regs_val; + u8 gas_range; + s32 t_fine; + int ret; + + guard(mutex)(&data->lock); + + ret = bme680_set_mode(data, BME680_MODE_FORCED); + if (ret < 0) + goto out; + + ret = bme680_wait_for_eoc(data); + if (ret) + goto out; + + ret = regmap_bulk_read(data->regmap, BME680_REG_MEAS_STAT_0, + data->buf, sizeof(data->buf)); + if (ret) { + dev_err(dev, "failed to burst read sensor data\n"); + goto out; + } + if (data->buf[0] & BME680_GAS_MEAS_BIT) { + dev_err(dev, "gas measurement incomplete\n"); + goto out; + } + + /* Temperature calculations */ + adc_temp = FIELD_GET(BME680_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[5])); + if (adc_temp == BME680_MEAS_SKIPPED) { + dev_err(dev, "reading temperature skipped\n"); + goto out; + } + data->scan.chan[0] = bme680_compensate_temp(data, adc_temp); + t_fine = bme680_calc_t_fine(data, adc_temp); + + /* Pressure calculations */ + adc_press = FIELD_GET(BME680_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[2])); + if (adc_press == BME680_MEAS_SKIPPED) { + dev_err(dev, "reading pressure skipped\n"); + goto out; + } + data->scan.chan[1] = bme680_compensate_press(data, adc_press, t_fine); + + /* Humidity calculations */ + adc_humid = get_unaligned_be16(&data->buf[8]); + if (adc_humid == BME680_MEAS_SKIPPED) { + dev_err(dev, "reading humidity skipped\n"); + goto out; + } + data->scan.chan[2] = bme680_compensate_humid(data, adc_humid, t_fine); + + /* Gas calculations */ + gas_regs_val = get_unaligned_be16(&data->buf[13]); + adc_gas_res = FIELD_GET(BME680_ADC_GAS_RES, gas_regs_val); + if ((gas_regs_val & BME680_GAS_STAB_BIT) == 0) { + dev_err(dev, "heater failed to reach the target temperature\n"); + goto out; + } + gas_range = FIELD_GET(BME680_GAS_RANGE_MASK, gas_regs_val); + data->scan.chan[3] = bme680_compensate_gas(data, adc_gas_res, gas_range); + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + iio_get_time_ns(indio_dev)); +out: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + int bme680_core_probe(struct device *dev, struct regmap *regmap, const char *name) { @@ -879,6 +1102,7 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, indio_dev->name = name; indio_dev->channels = bme680_channels; indio_dev->num_channels = ARRAY_SIZE(bme680_channels); + indio_dev->available_scan_masks = bme680_avail_scan_masks; indio_dev->info = &bme680_info; indio_dev->modes = INDIO_DIRECT_MODE; @@ -888,13 +1112,13 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, data->oversampling_temp = 8; /* 8X oversampling rate */ data->heater_temp = 320; /* degree Celsius */ data->heater_dur = 150; /* milliseconds */ + data->preheat_curr_mA = 0; - ret = regmap_write(regmap, BME680_REG_SOFT_RESET, - BME680_CMD_SOFTRESET); + ret = regmap_write(regmap, BME680_REG_SOFT_RESET, BME680_CMD_SOFTRESET); if (ret < 0) return dev_err_probe(dev, ret, "Failed to reset chip\n"); - usleep_range(BME680_STARTUP_TIME_US, BME680_STARTUP_TIME_US + 1000); + fsleep(BME680_STARTUP_TIME_US); ret = regmap_read(regmap, BME680_REG_CHIP_ID, &data->check); if (ret < 0) @@ -922,9 +1146,17 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap, return dev_err_probe(dev, ret, "failed to set gas config data\n"); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + bme680_trigger_handler, + NULL); + if (ret) + return dev_err_probe(dev, ret, + "iio triggered buffer setup failed\n"); + return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(bme680_core_probe, IIO_BME680); +EXPORT_SYMBOL_NS_GPL(bme680_core_probe, "IIO_BME680"); MODULE_AUTHOR("Himanshu Jha "); MODULE_DESCRIPTION("Bosch BME680 Driver"); diff --git a/drivers/iio/chemical/bme680_i2c.c b/drivers/iio/chemical/bme680_i2c.c index 7c4224d75955f7..7a949228b4a614 100644 --- a/drivers/iio/chemical/bme680_i2c.c +++ b/drivers/iio/chemical/bme680_i2c.c @@ -60,4 +60,4 @@ module_i2c_driver(bme680_i2c_driver); MODULE_AUTHOR("Himanshu Jha "); MODULE_DESCRIPTION("BME680 I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_BME680); +MODULE_IMPORT_NS("IIO_BME680"); diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index 7c54bd17d4b06d..3916a51ba68e17 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -163,4 +163,4 @@ module_spi_driver(bme680_spi_driver); MODULE_AUTHOR("Himanshu Jha "); MODULE_DESCRIPTION("Bosch BME680 SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_BME680); +MODULE_IMPORT_NS("IIO_BME680"); diff --git a/drivers/iio/chemical/ens160_core.c b/drivers/iio/chemical/ens160_core.c index c1aa3b498d3b88..4a89cd5894d9f1 100644 --- a/drivers/iio/chemical/ens160_core.c +++ b/drivers/iio/chemical/ens160_core.c @@ -360,7 +360,7 @@ int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160); +EXPORT_SYMBOL_NS(devm_ens160_core_probe, "IIO_ENS160"); MODULE_AUTHOR("Gustavo Silva "); MODULE_DESCRIPTION("ScioSense ENS160 driver"); diff --git a/drivers/iio/chemical/ens160_i2c.c b/drivers/iio/chemical/ens160_i2c.c index 57a189a4c257c4..aa0dfe63924501 100644 --- a/drivers/iio/chemical/ens160_i2c.c +++ b/drivers/iio/chemical/ens160_i2c.c @@ -59,4 +59,4 @@ module_i2c_driver(ens160_i2c_driver); MODULE_AUTHOR("Gustavo Silva "); MODULE_DESCRIPTION("ScioSense ENS160 I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ENS160); +MODULE_IMPORT_NS("IIO_ENS160"); diff --git a/drivers/iio/chemical/ens160_spi.c b/drivers/iio/chemical/ens160_spi.c index 10e4f5fd0f45cb..a674c0e1bf4b49 100644 --- a/drivers/iio/chemical/ens160_spi.c +++ b/drivers/iio/chemical/ens160_spi.c @@ -58,4 +58,4 @@ module_spi_driver(ens160_spi_driver); MODULE_AUTHOR("Gustavo Silva "); MODULE_DESCRIPTION("ScioSense ENS160 SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ENS160); +MODULE_IMPORT_NS("IIO_ENS160"); diff --git a/drivers/iio/chemical/scd30_core.c b/drivers/iio/chemical/scd30_core.c index 7be5a45cf71ae8..ac3080929f0b1c 100644 --- a/drivers/iio/chemical/scd30_core.c +++ b/drivers/iio/chemical/scd30_core.c @@ -747,7 +747,7 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS(scd30_probe, IIO_SCD30); +EXPORT_SYMBOL_NS(scd30_probe, "IIO_SCD30"); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor core driver"); diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c index b31dfaf52df9c5..436df9c61a719f 100644 --- a/drivers/iio/chemical/scd30_i2c.c +++ b/drivers/iio/chemical/scd30_i2c.c @@ -137,4 +137,4 @@ module_i2c_driver(scd30_i2c_driver); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_SCD30); +MODULE_IMPORT_NS("IIO_SCD30"); diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c index 55044f07d5a371..e8b453aae859ee 100644 --- a/drivers/iio/chemical/scd30_serial.c +++ b/drivers/iio/chemical/scd30_serial.c @@ -261,4 +261,4 @@ module_serdev_device_driver(scd30_serdev_driver); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor serial driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_SCD30); +MODULE_IMPORT_NS("IIO_SCD30"); diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index 814ce0aad1cccd..6f4f2ba2c09d5e 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -372,7 +372,7 @@ int sps30_probe(struct device *dev, const char *name, void *priv, const struct s return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(sps30_probe, IIO_SPS30); +EXPORT_SYMBOL_NS_GPL(sps30_probe, "IIO_SPS30"); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor driver"); diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c index 1b21b6bcd0e7a4..f692c089d17b40 100644 --- a/drivers/iio/chemical/sps30_i2c.c +++ b/drivers/iio/chemical/sps30_i2c.c @@ -256,4 +256,4 @@ module_i2c_driver(sps30_i2c_driver); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_SPS30); +MODULE_IMPORT_NS("IIO_SPS30"); diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c index a6dfbe28c914c7..008bc88590f370 100644 --- a/drivers/iio/chemical/sps30_serial.c +++ b/drivers/iio/chemical/sps30_serial.c @@ -429,4 +429,4 @@ module_serdev_device_driver(sps30_serial_driver); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("Sensirion SPS30 particulate matter sensor serial driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_SPS30); +MODULE_IMPORT_NS("IIO_SPS30"); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 9b279937a24e0d..ad1882f608c0a2 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -169,7 +169,7 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st) return value; } -EXPORT_SYMBOL_NS(hid_sensor_read_poll_value, IIO_HID_ATTRIBUTES); +EXPORT_SYMBOL_NS(hid_sensor_read_poll_value, "IIO_HID_ATTRIBUTES"); int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, int *val1, int *val2) @@ -196,7 +196,7 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, return IIO_VAL_INT_PLUS_MICRO; } -EXPORT_SYMBOL_NS(hid_sensor_read_samp_freq_value, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_read_samp_freq_value, "IIO_HID"); int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, int val1, int val2) @@ -231,7 +231,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, return 0; } -EXPORT_SYMBOL_NS(hid_sensor_write_samp_freq_value, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_write_samp_freq_value, "IIO_HID"); int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, int *val1, int *val2) @@ -254,7 +254,7 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st, return IIO_VAL_INT_PLUS_MICRO; } -EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_value, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_value, "IIO_HID"); int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, int *val2) @@ -276,7 +276,7 @@ int hid_sensor_read_raw_hyst_rel_value(struct hid_sensor_common *st, int *val1, return IIO_VAL_INT_PLUS_MICRO; } -EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_rel_value, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_read_raw_hyst_rel_value, "IIO_HID"); int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, @@ -308,7 +308,7 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, return 0; } -EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_value, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_value, "IIO_HID"); int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, int val1, int val2) @@ -339,7 +339,7 @@ int hid_sensor_write_raw_hyst_rel_value(struct hid_sensor_common *st, return 0; } -EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_write_raw_hyst_rel_value, "IIO_HID"); /* * This fuction applies the unit exponent to the scale. @@ -423,14 +423,14 @@ int hid_sensor_format_scale(u32 usage_id, return IIO_VAL_INT_PLUS_NANO; } -EXPORT_SYMBOL_NS(hid_sensor_format_scale, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_format_scale, "IIO_HID"); int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st, int64_t raw_value) { return st->timestamp_ns_scale * raw_value; } -EXPORT_SYMBOL_NS(hid_sensor_convert_timestamp, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_convert_timestamp, "IIO_HID"); static int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, @@ -477,7 +477,7 @@ int hid_sensor_get_report_latency(struct hid_sensor_common *st) return value; } -EXPORT_SYMBOL_NS(hid_sensor_get_report_latency, IIO_HID_ATTRIBUTES); +EXPORT_SYMBOL_NS(hid_sensor_get_report_latency, "IIO_HID_ATTRIBUTES"); int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms) { @@ -485,13 +485,13 @@ int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms) st->report_latency.index, sizeof(latency_ms), &latency_ms); } -EXPORT_SYMBOL_NS(hid_sensor_set_report_latency, IIO_HID_ATTRIBUTES); +EXPORT_SYMBOL_NS(hid_sensor_set_report_latency, "IIO_HID_ATTRIBUTES"); bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st) { return st->report_latency.index > 0 && st->report_latency.report_id > 0; } -EXPORT_SYMBOL_NS(hid_sensor_batch_mode_supported, IIO_HID_ATTRIBUTES); +EXPORT_SYMBOL_NS(hid_sensor_batch_mode_supported, "IIO_HID_ATTRIBUTES"); int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 usage_id, @@ -583,7 +583,7 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, return 0; } -EXPORT_SYMBOL_NS(hid_sensor_parse_common_attributes, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_parse_common_attributes, "IIO_HID"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_DESCRIPTION("HID Sensor common attribute processing"); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index abb09fefc792c5..48193937275b30 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -147,7 +147,7 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state) return 0; } -EXPORT_SYMBOL_NS(hid_sensor_power_state, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_power_state, "IIO_HID"); int hid_sensor_power_state(struct hid_sensor_common *st, bool state) { @@ -222,7 +222,7 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev, iio_trigger_free(attrb->trigger); iio_triggered_buffer_cleanup(indio_dev); } -EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, "IIO_HID"); static const struct iio_trigger_ops hid_sensor_trigger_ops = { .set_trigger_state = &hid_sensor_data_rdy_trigger_set_state, @@ -289,7 +289,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, iio_triggered_buffer_cleanup(indio_dev); return ret; } -EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, "IIO_HID"); static int __maybe_unused hid_sensor_suspend(struct device *dev) { @@ -319,9 +319,9 @@ const struct dev_pm_ops hid_sensor_pm_ops = { SET_RUNTIME_PM_OPS(hid_sensor_suspend, hid_sensor_runtime_resume, NULL) }; -EXPORT_SYMBOL_NS(hid_sensor_pm_ops, IIO_HID); +EXPORT_SYMBOL_NS(hid_sensor_pm_ops, "IIO_HID"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_DESCRIPTION("HID Sensor trigger processing"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID_ATTRIBUTES); +MODULE_IMPORT_NS("IIO_HID_ATTRIBUTES"); diff --git a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c index f44458c380d928..c081b5caa475f3 100644 --- a/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c +++ b/drivers/iio/common/inv_sensors/inv_sensors_timestamp.c @@ -55,7 +55,7 @@ void inv_sensors_timestamp_init(struct inv_sensors_timestamp *ts, /* use theoretical value for chip period */ inv_update_acc(&ts->chip_period, chip->clock_period); } -EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_init, IIO_INV_SENSORS_TIMESTAMP); +EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_init, "IIO_INV_SENSORS_TIMESTAMP"); int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, uint32_t period, bool fifo) @@ -70,9 +70,13 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts, if (mult != ts->mult) ts->new_mult = mult; + /* When FIFO is off, directly apply the new ODR */ + if (!fifo) + inv_sensors_timestamp_apply_odr(ts, 0, 0, 0); + return 0; } -EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, IIO_INV_SENSORS_TIMESTAMP); +EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, "IIO_INV_SENSORS_TIMESTAMP"); static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period) { @@ -162,7 +166,7 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, if (valid) inv_align_timestamp_it(ts); } -EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_interrupt, IIO_INV_SENSORS_TIMESTAMP); +EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_interrupt, "IIO_INV_SENSORS_TIMESTAMP"); void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts, uint32_t fifo_period, size_t fifo_nb, @@ -194,7 +198,7 @@ void inv_sensors_timestamp_apply_odr(struct inv_sensors_timestamp *ts, ts->timestamp = ts->it.up - interval; } } -EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_apply_odr, IIO_INV_SENSORS_TIMESTAMP); +EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_apply_odr, "IIO_INV_SENSORS_TIMESTAMP"); MODULE_AUTHOR("InvenSense, Inc."); MODULE_DESCRIPTION("InvenSense sensors timestamp module"); diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c index 9c9bc77003c7ff..58847086368183 100644 --- a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c +++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c @@ -58,7 +58,7 @@ int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay) return 0; } -EXPORT_SYMBOL_NS(ms_sensors_reset, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_reset, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_read_prom_word() - PROM word read function @@ -84,7 +84,7 @@ int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word) return 0; } -EXPORT_SYMBOL_NS(ms_sensors_read_prom_word, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_read_prom_word, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_convert_and_read() - ADC conversion & read function @@ -130,7 +130,7 @@ int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd, dev_err(&client->dev, "Unable to make sensor adc conversion\n"); return ret; } -EXPORT_SYMBOL_NS(ms_sensors_convert_and_read, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_convert_and_read, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_crc_valid() - CRC check function @@ -248,7 +248,7 @@ int ms_sensors_read_serial(struct i2c_client *client, u64 *sn) return 0; } -EXPORT_SYMBOL_NS(ms_sensors_read_serial, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_read_serial, "IIO_MEAS_SPEC_SENSORS"); static int ms_sensors_read_config_reg(struct i2c_client *client, u8 *config_reg) @@ -299,7 +299,7 @@ ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data, MS_SENSORS_CONFIG_REG_WRITE, config_reg); } -EXPORT_SYMBOL_NS(ms_sensors_write_resolution, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_write_resolution, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_show_battery_low() - Show device battery low indicator @@ -326,7 +326,7 @@ ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, return sysfs_emit(buf, "%d\n", (config_reg & 0x40) >> 6); } -EXPORT_SYMBOL_NS(ms_sensors_show_battery_low, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_show_battery_low, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_show_heater() - Show device heater @@ -353,7 +353,7 @@ ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, return sysfs_emit(buf, "%d\n", (config_reg & 0x4) >> 2); } -EXPORT_SYMBOL_NS(ms_sensors_show_heater, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_show_heater, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_write_heater() - Write device heater @@ -401,7 +401,7 @@ ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data, return len; } -EXPORT_SYMBOL_NS(ms_sensors_write_heater, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_write_heater, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_ht_read_temperature() - Read temperature @@ -442,7 +442,7 @@ int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data, return 0; } -EXPORT_SYMBOL_NS(ms_sensors_ht_read_temperature, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_ht_read_temperature, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_ht_read_humidity() - Read humidity @@ -485,7 +485,7 @@ int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data, return 0; } -EXPORT_SYMBOL_NS(ms_sensors_ht_read_humidity, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_ht_read_humidity, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_tp_crc4() - Calculate PROM CRC for @@ -602,7 +602,7 @@ int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data) return 0; } -EXPORT_SYMBOL_NS(ms_sensors_tp_read_prom, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_tp_read_prom, "IIO_MEAS_SPEC_SENSORS"); /** * ms_sensors_read_temp_and_pressure() - read temp and pressure @@ -688,7 +688,7 @@ int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data, return 0; } -EXPORT_SYMBOL_NS(ms_sensors_read_temp_and_pressure, IIO_MEAS_SPEC_SENSORS); +EXPORT_SYMBOL_NS(ms_sensors_read_temp_and_pressure, "IIO_MEAS_SPEC_SENSORS"); MODULE_DESCRIPTION("Measurement-Specialties common i2c driver"); MODULE_AUTHOR("William Markezana "); diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index e64d242145e04c..65f8a2b13cfd2a 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -205,7 +205,7 @@ u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type type) { return data->delay_buf[type]; } -EXPORT_SYMBOL_NS(ssp_get_sensor_delay, IIO_SSP_SENSORS); +EXPORT_SYMBOL_NS(ssp_get_sensor_delay, "IIO_SSP_SENSORS"); /** * ssp_enable_sensor() - enables data acquisition for sensor @@ -267,7 +267,7 @@ int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type, derror: return ret; } -EXPORT_SYMBOL_NS(ssp_enable_sensor, IIO_SSP_SENSORS); +EXPORT_SYMBOL_NS(ssp_enable_sensor, "IIO_SSP_SENSORS"); /** * ssp_change_delay() - changes data acquisition for sensor @@ -298,7 +298,7 @@ int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type, return 0; } -EXPORT_SYMBOL_NS(ssp_change_delay, IIO_SSP_SENSORS); +EXPORT_SYMBOL_NS(ssp_change_delay, "IIO_SSP_SENSORS"); /** * ssp_disable_sensor() - disables sensor @@ -335,7 +335,7 @@ int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type) return 0; } -EXPORT_SYMBOL_NS(ssp_disable_sensor, IIO_SSP_SENSORS); +EXPORT_SYMBOL_NS(ssp_disable_sensor, "IIO_SSP_SENSORS"); static irqreturn_t ssp_irq_thread_fn(int irq, void *dev_id) { @@ -478,7 +478,7 @@ void ssp_register_consumer(struct iio_dev *indio_dev, enum ssp_sensor_type type) data->sensor_devs[type] = indio_dev; } -EXPORT_SYMBOL_NS(ssp_register_consumer, IIO_SSP_SENSORS); +EXPORT_SYMBOL_NS(ssp_register_consumer, "IIO_SSP_SENSORS"); static int ssp_probe(struct spi_device *spi) { diff --git a/drivers/iio/common/ssp_sensors/ssp_iio.c b/drivers/iio/common/ssp_sensors/ssp_iio.c index 88b8b56bfa51b6..caa404edd9d045 100644 --- a/drivers/iio/common/ssp_sensors/ssp_iio.c +++ b/drivers/iio/common/ssp_sensors/ssp_iio.c @@ -32,7 +32,7 @@ int ssp_common_buffer_postenable(struct iio_dev *indio_dev) return ssp_enable_sensor(data, spd->type, ssp_get_sensor_delay(data, spd->type)); } -EXPORT_SYMBOL_NS(ssp_common_buffer_postenable, IIO_SSP_SENSORS); +EXPORT_SYMBOL_NS(ssp_common_buffer_postenable, "IIO_SSP_SENSORS"); /** * ssp_common_buffer_postdisable() - generic postdisable callback for ssp buffer @@ -55,7 +55,7 @@ int ssp_common_buffer_postdisable(struct iio_dev *indio_dev) return ret; } -EXPORT_SYMBOL_NS(ssp_common_buffer_postdisable, IIO_SSP_SENSORS); +EXPORT_SYMBOL_NS(ssp_common_buffer_postdisable, "IIO_SSP_SENSORS"); /** * ssp_common_process_data() - Common process data callback for ssp sensors @@ -91,9 +91,9 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf, return iio_push_to_buffers_with_timestamp(indio_dev, spd->buffer, calculated_time); } -EXPORT_SYMBOL_NS(ssp_common_process_data, IIO_SSP_SENSORS); +EXPORT_SYMBOL_NS(ssp_common_process_data, "IIO_SSP_SENSORS"); MODULE_AUTHOR("Karol Wrona "); MODULE_DESCRIPTION("Samsung sensorhub commons"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_SSP_SENSORS); +MODULE_IMPORT_NS("IIO_SSP_SENSORS"); diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index e2f108ca949ccd..57f087c2216f92 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -76,4 +76,4 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(st_sensors_trigger_handler, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_trigger_handler, "IIO_ST_SENSORS"); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 1b4287991d00ae..e4f5a7ff7e74c9 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -46,7 +46,7 @@ int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_NS(st_sensors_debugfs_reg_access, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_debugfs_reg_access, "IIO_ST_SENSORS"); static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings, unsigned int odr, struct st_sensor_odr_avl *odr_out) @@ -110,7 +110,7 @@ int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr) return err; } -EXPORT_SYMBOL_NS(st_sensors_set_odr, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_set_odr, "IIO_ST_SENSORS"); static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings, unsigned int fs, int *index_fs_avl) @@ -203,7 +203,7 @@ int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable) set_enable_error: return err; } -EXPORT_SYMBOL_NS(st_sensors_set_enable, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_set_enable, "IIO_ST_SENSORS"); int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) { @@ -217,7 +217,7 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) axis_enable); return err; } -EXPORT_SYMBOL_NS(st_sensors_set_axis_enable, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_set_axis_enable, "IIO_ST_SENSORS"); int st_sensors_power_enable(struct iio_dev *indio_dev) @@ -236,7 +236,7 @@ int st_sensors_power_enable(struct iio_dev *indio_dev) return 0; } -EXPORT_SYMBOL_NS(st_sensors_power_enable, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_power_enable, "IIO_ST_SENSORS"); static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) @@ -331,7 +331,7 @@ void st_sensors_dev_name_probe(struct device *dev, char *name, int len) /* The name from the match takes precedence if present */ strscpy(name, match, len); } -EXPORT_SYMBOL_NS(st_sensors_dev_name_probe, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_dev_name_probe, "IIO_ST_SENSORS"); int st_sensors_init_sensor(struct iio_dev *indio_dev, struct st_sensors_platform_data *pdata) @@ -418,7 +418,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, return err; } -EXPORT_SYMBOL_NS(st_sensors_init_sensor, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_init_sensor, "IIO_ST_SENSORS"); int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) { @@ -467,7 +467,7 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) st_accel_set_dataready_irq_error: return err; } -EXPORT_SYMBOL_NS(st_sensors_set_dataready_irq, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_set_dataready_irq, "IIO_ST_SENSORS"); int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale) { @@ -490,7 +490,7 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale) st_sensors_match_scale_error: return err; } -EXPORT_SYMBOL_NS(st_sensors_set_fullscale_by_gain, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_set_fullscale_by_gain, "IIO_ST_SENSORS"); static int st_sensors_read_axis_data(struct iio_dev *indio_dev, struct iio_chan_spec const *ch, int *data) @@ -555,7 +555,7 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev, return err; } -EXPORT_SYMBOL_NS(st_sensors_read_info_raw, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_read_info_raw, "IIO_ST_SENSORS"); /* * st_sensors_get_settings_index() - get index of the sensor settings for a @@ -582,7 +582,7 @@ int st_sensors_get_settings_index(const char *name, return -ENODEV; } -EXPORT_SYMBOL_NS(st_sensors_get_settings_index, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_get_settings_index, "IIO_ST_SENSORS"); /* * st_sensors_verify_id() - verify sensor ID (WhoAmI) is matching with the @@ -614,7 +614,7 @@ int st_sensors_verify_id(struct iio_dev *indio_dev) return 0; } -EXPORT_SYMBOL_NS(st_sensors_verify_id, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_verify_id, "IIO_ST_SENSORS"); ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, struct device_attribute *attr, char *buf) @@ -634,7 +634,7 @@ ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, return len; } -EXPORT_SYMBOL_NS(st_sensors_sysfs_sampling_frequency_avail, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_sysfs_sampling_frequency_avail, "IIO_ST_SENSORS"); ssize_t st_sensors_sysfs_scale_avail(struct device *dev, struct device_attribute *attr, char *buf) @@ -656,7 +656,7 @@ ssize_t st_sensors_sysfs_scale_avail(struct device *dev, return len; } -EXPORT_SYMBOL_NS(st_sensors_sysfs_scale_avail, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_sysfs_scale_avail, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics ST-sensors core"); diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c index ee95082c741062..7156302fe99772 100644 --- a/drivers/iio/common/st_sensors/st_sensors_i2c.c +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c @@ -61,7 +61,7 @@ int st_sensors_i2c_configure(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_NS(st_sensors_i2c_configure, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_i2c_configure, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver"); diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c index 63e302c3fbaa1b..0da27013943d9f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_spi.c +++ b/drivers/iio/common/st_sensors/st_sensors_spi.c @@ -113,7 +113,7 @@ int st_sensors_spi_configure(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_NS(st_sensors_spi_configure, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_spi_configure, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver"); diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index a0df9250a69ff6..9d4bf822a15dfc 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -134,11 +134,11 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, iio_trigger_set_drvdata(sdata->trig, indio_dev); sdata->trig->ops = trigger_ops; - irq_trig = irqd_get_trigger_type(irq_get_irq_data(sdata->irq)); /* * If the IRQ is triggered on falling edge, we need to mark the * interrupt as active low, if the hardware supports this. */ + irq_trig = irq_get_trigger_type(sdata->irq); switch(irq_trig) { case IRQF_TRIGGER_FALLING: case IRQF_TRIGGER_LOW: @@ -227,7 +227,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_NS(st_sensors_allocate_trigger, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_allocate_trigger, "IIO_ST_SENSORS"); int st_sensors_validate_device(struct iio_trigger *trig, struct iio_dev *indio_dev) @@ -239,4 +239,4 @@ int st_sensors_validate_device(struct iio_trigger *trig, return 0; } -EXPORT_SYMBOL_NS(st_sensors_validate_device, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_sensors_validate_device, "IIO_ST_SENSORS"); diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 9f5d5ebb865374..5d01ba4edbf30c 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -6,9 +6,28 @@ menu "Digital to analog converters" +config AD3552R_HS + tristate "Analog Devices AD3552R DAC High Speed driver" + select AD3552R_LIB + select IIO_BACKEND + help + Say yes here to build support for Analog Devices AD3552R + Digital to Analog Converter High Speed driver. + + The driver requires the assistance of an IP core to operate, + since data is streamed into target device via DMA, sent over a + QSPI + DDR (Double Data Rate) bus. + + To compile this driver as a module, choose M here: the + module will be called ad3552r-hs. + +config AD3552R_LIB + tristate + config AD3552R tristate "Analog Devices AD3552R DAC driver" depends on SPI_MASTER + select AD3552R_LIB select IIO_BUFFER select IIO_TRIGGERED_BUFFER help @@ -306,6 +325,19 @@ config AD7303 To compile this driver as module choose M here: the module will be called ad7303. +config AD8460 + tristate "Analog Devices AD8460 DAC driver" + depends on SPI + select REGMAP_SPI + select IIO_BUFFER + select IIO_BUFFER_DMAENGINE + help + Say yes here to build support for Analog Devices AD8460 Digital to + Analog Converters (DAC). + + To compile this driver as a module choose M here: the module will be called + ad8460. + config AD8801 tristate "Analog Devices AD8801/AD8803 DAC driver" depends on SPI_MASTER diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 2cf148f16306db..414c152be779d8 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -4,6 +4,8 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD3552R_HS) += ad3552r-hs.o +obj-$(CONFIG_AD3552R_LIB) += ad3552r-common.o obj-$(CONFIG_AD3552R) += ad3552r.o obj-$(CONFIG_AD5360) += ad5360.o obj-$(CONFIG_AD5380) += ad5380.o @@ -28,6 +30,7 @@ obj-$(CONFIG_AD5686_SPI) += ad5686-spi.o obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o obj-$(CONFIG_AD7293) += ad7293.o obj-$(CONFIG_AD7303) += ad7303.o +obj-$(CONFIG_AD8460) += ad8460.o obj-$(CONFIG_AD8801) += ad8801.o obj-$(CONFIG_AD9739A) += ad9739a.o obj-$(CONFIG_ADI_AXI_DAC) += adi-axi-dac.o diff --git a/drivers/iio/dac/ad3552r-common.c b/drivers/iio/dac/ad3552r-common.c new file mode 100644 index 00000000000000..0f495df2e5ce77 --- /dev/null +++ b/drivers/iio/dac/ad3552r-common.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2010-2024 Analog Devices Inc. +// Copyright (c) 2024 Baylibre, SAS + +#include +#include +#include +#include +#include + +#include "ad3552r.h" + +const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2] = { + [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 }, + [AD3552R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 }, + [AD3552R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 }, + [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 }, + [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = { -10000, 10000 } +}; +EXPORT_SYMBOL_NS_GPL(ad3552r_ch_ranges, "IIO_AD3552R"); + +const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2] = { + [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = { 0, 2500 }, + [AD3542R_CH_OUTPUT_RANGE_0__3V] = { 0, 3000 }, + [AD3542R_CH_OUTPUT_RANGE_0__5V] = { 0, 5000 }, + [AD3542R_CH_OUTPUT_RANGE_0__10V] = { 0, 10000 }, + [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = { -2500, 7500 }, + [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = { -5000, 5000 } +}; +EXPORT_SYMBOL_NS_GPL(ad3542r_ch_ranges, "IIO_AD3552R"); + +/* Gain * AD3552R_GAIN_SCALE */ +static const s32 gains_scaling_table[] = { + [AD3552R_CH_GAIN_SCALING_1] = 1000, + [AD3552R_CH_GAIN_SCALING_0_5] = 500, + [AD3552R_CH_GAIN_SCALING_0_25] = 250, + [AD3552R_CH_GAIN_SCALING_0_125] = 125 +}; + +u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs) +{ + return FIELD_PREP(AD3552R_MASK_CH_RANGE_OVERRIDE, 1) | + FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_P, p) | + FIELD_PREP(AD3552R_MASK_CH_GAIN_SCALING_N, n) | + FIELD_PREP(AD3552R_MASK_CH_OFFSET_BIT_8, abs(goffs)) | + FIELD_PREP(AD3552R_MASK_CH_OFFSET_POLARITY, goffs < 0); +} +EXPORT_SYMBOL_NS_GPL(ad3552r_calc_custom_gain, "IIO_AD3552R"); + +static void ad3552r_get_custom_range(struct ad3552r_ch_data *ch_data, + s32 *v_min, s32 *v_max) +{ + s64 vref, tmp, common, offset, gn, gp; + /* + * From datasheet formula (In Volts): + * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03] + * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03] + * Calculus are converted to milivolts + */ + vref = 2500; + /* 2.5 * 1.03 * 1000 (To mV) */ + common = 2575 * ch_data->rfb; + offset = ch_data->gain_offset; + + gn = gains_scaling_table[ch_data->n]; + tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common; + tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); + *v_max = vref + tmp; + + gp = gains_scaling_table[ch_data->p]; + tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common; + tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); + *v_min = vref - tmp; +} + +void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data, + const struct ad3552r_model_data *model_data) +{ + s32 idx, v_max, v_min, span, rem; + s64 tmp; + + if (ch_data->range_override) { + ad3552r_get_custom_range(ch_data, &v_min, &v_max); + } else { + /* Normal range */ + idx = ch_data->range; + v_min = model_data->ranges_table[idx][0]; + v_max = model_data->ranges_table[idx][1]; + } + + /* + * From datasheet formula: + * Vout = Span * (D / 65536) + Vmin + * Converted to scale and offset: + * Scale = Span / 65536 + * Offset = 65536 * Vmin / Span + * + * Reminders are in micros in order to be printed as + * IIO_VAL_INT_PLUS_MICRO + */ + span = v_max - v_min; + ch_data->scale_int = div_s64_rem(span, 65536, &rem); + /* Do operations in microvolts */ + ch_data->scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, 65536); + + ch_data->offset_int = div_s64_rem(v_min * 65536, span, &rem); + tmp = (s64)rem * 1000000; + ch_data->offset_dec = div_s64(tmp, span); +} +EXPORT_SYMBOL_NS_GPL(ad3552r_calc_gain_and_offset, "IIO_AD3552R"); + +int ad3552r_get_ref_voltage(struct device *dev, u32 *val) +{ + int voltage; + int delta = 100000; + + voltage = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (voltage < 0 && voltage != -ENODEV) + return dev_err_probe(dev, voltage, + "Error getting vref voltage\n"); + + if (voltage == -ENODEV) { + if (device_property_read_bool(dev, "adi,vref-out-en")) + *val = AD3552R_INTERNAL_VREF_PIN_2P5V; + else + *val = AD3552R_INTERNAL_VREF_PIN_FLOATING; + + return 0; + } + + if (voltage > 2500000 + delta || voltage < 2500000 - delta) { + dev_warn(dev, "vref-supply must be 2.5V"); + return -EINVAL; + } + + *val = AD3552R_EXTERNAL_VREF_PIN_INPUT; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_ref_voltage, "IIO_AD3552R"); + +int ad3552r_get_drive_strength(struct device *dev, u32 *val) +{ + int err; + u32 drive_strength; + + err = device_property_read_u32(dev, "adi,sdo-drive-strength", + &drive_strength); + if (err) + return err; + + if (drive_strength > 3) { + dev_err_probe(dev, -EINVAL, + "adi,sdo-drive-strength must be less than 4\n"); + return -EINVAL; + } + + *val = drive_strength; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_drive_strength, "IIO_AD3552R"); + +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child, + u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs) +{ + int err; + u32 val; + struct fwnode_handle *gain_child __free(fwnode_handle) = + fwnode_get_named_child_node(child, + "custom-output-range-config"); + + if (!gain_child) + return dev_err_probe(dev, -EINVAL, + "custom-output-range-config mandatory\n"); + + err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-scaling-p mandatory\n"); + *gs_p = val; + + err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-scaling-n property mandatory\n"); + *gs_n = val; + + err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); + if (err) + return dev_err_probe(dev, err, + "adi,rfb-ohms mandatory\n"); + *rfb = val; + + err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); + if (err) + return dev_err_probe(dev, err, + "adi,gain-offset mandatory\n"); + *goffs = val; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_custom_gain, "IIO_AD3552R"); + +static int ad3552r_find_range(const struct ad3552r_model_data *model_info, + s32 *vals) +{ + int i; + + for (i = 0; i < model_info->num_ranges; i++) + if (vals[0] == model_info->ranges_table[i][0] * 1000 && + vals[1] == model_info->ranges_table[i][1] * 1000) + return i; + + return -EINVAL; +} + +int ad3552r_get_output_range(struct device *dev, + const struct ad3552r_model_data *model_info, + struct fwnode_handle *child, u32 *val) +{ + int ret; + s32 vals[2]; + + /* This property is optional, so returning -ENOENT if missing */ + if (!fwnode_property_present(child, "adi,output-range-microvolt")) + return -ENOENT; + + ret = fwnode_property_read_u32_array(child, + "adi,output-range-microvolt", + vals, 2); + if (ret) + return dev_err_probe(dev, ret, + "invalid adi,output-range-microvolt\n"); + + ret = ad3552r_find_range(model_info, vals); + if (ret < 0) + return dev_err_probe(dev, ret, + "invalid adi,output-range-microvolt value\n"); + + *val = ret; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ad3552r_get_output_range, "IIO_AD3552R"); + +MODULE_DESCRIPTION("ad3552r common functions"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c new file mode 100644 index 00000000000000..216c634f3eaf72 --- /dev/null +++ b/drivers/iio/dac/ad3552r-hs.c @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD3552R + * Digital to Analog converter driver, High Speed version + * + * Copyright 2024 Analog Devices Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ad3552r.h" +#include "ad3552r-hs.h" + +struct ad3552r_hs_state { + const struct ad3552r_model_data *model_data; + struct gpio_desc *reset_gpio; + struct device *dev; + struct iio_backend *back; + bool single_channel; + struct ad3552r_ch_data ch_data[AD3552R_MAX_CH]; + struct ad3552r_hs_platform_data *data; +}; + +static int ad3552r_qspi_update_reg_bits(struct ad3552r_hs_state *st, + u32 reg, u32 mask, u32 val, + size_t xfer_size) +{ + u32 rval; + int ret; + + ret = st->data->bus_reg_read(st->back, reg, &rval, xfer_size); + if (ret) + return ret; + + rval = (rval & ~mask) | val; + + return st->data->bus_reg_write(st->back, reg, rval, xfer_size); +} + +static int ad3552r_hs_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + int ret; + int ch = chan->channel; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + /* + * Using 4 lanes (QSPI), then using 2 as DDR mode is + * considered always on (considering buffering mode always). + */ + *val = DIV_ROUND_CLOSEST(st->data->bus_sample_data_clock_hz * + 4 * 2, chan->scan_type.realbits); + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_RAW: + ret = st->data->bus_reg_read(st->back, + AD3552R_REG_ADDR_CH_DAC_16B(chan->channel), + val, 2); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = st->ch_data[ch].scale_int; + *val2 = st->ch_data[ch].scale_dec; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = st->ch_data[ch].offset_int; + *val2 = st->ch_data[ch].offset_dec; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int ad3552r_hs_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + return st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_CH_DAC_16B(chan->channel), + val, 2); + } + unreachable(); + default: + return -EINVAL; + } +} + +static int ad3552r_hs_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + struct iio_backend_data_fmt fmt = { + .type = IIO_BACKEND_DATA_UNSIGNED + }; + int loop_len, val, ret; + + switch (*indio_dev->active_scan_mask) { + case AD3552R_CH0_ACTIVE: + st->single_channel = true; + loop_len = 2; + val = AD3552R_REG_ADDR_CH_DAC_16B(0); + break; + case AD3552R_CH1_ACTIVE: + st->single_channel = true; + loop_len = 2; + val = AD3552R_REG_ADDR_CH_DAC_16B(1); + break; + case AD3552R_CH0_ACTIVE | AD3552R_CH1_ACTIVE: + st->single_channel = false; + loop_len = 4; + val = AD3552R_REG_ADDR_CH_DAC_16B(1); + break; + default: + return -EINVAL; + } + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_STREAM_MODE, + loop_len, 1); + if (ret) + return ret; + + /* Inform DAC chip to switch into DDR mode */ + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + AD3552R_MASK_SPI_CONFIG_DDR, 1); + if (ret) + return ret; + + /* Inform DAC IP to go for DDR mode from now on */ + ret = iio_backend_ddr_enable(st->back); + if (ret) { + dev_err(st->dev, "could not set DDR mode, not streaming"); + goto exit_err; + } + + ret = iio_backend_data_transfer_addr(st->back, val); + if (ret) + goto exit_err; + + ret = iio_backend_data_format_set(st->back, 0, &fmt); + if (ret) + goto exit_err; + + ret = iio_backend_data_stream_enable(st->back); + if (ret) + goto exit_err; + + return 0; + +exit_err: + ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + 0, 1); + + iio_backend_ddr_disable(st->back); + + return ret; +} + +static int ad3552r_hs_buffer_predisable(struct iio_dev *indio_dev) +{ + struct ad3552r_hs_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_backend_data_stream_disable(st->back); + if (ret) + return ret; + + /* Inform DAC to set in SDR mode */ + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SPI_CONFIG_DDR, + 0, 1); + if (ret) + return ret; + + ret = iio_backend_ddr_disable(st->back); + if (ret) + return ret; + + return 0; +} + +static inline int ad3552r_hs_set_output_range(struct ad3552r_hs_state *st, + int ch, unsigned int mode) +{ + int val; + + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH0_RANGE, mode); + else + val = FIELD_PREP(AD3552R_MASK_CH1_RANGE, mode); + + return ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, + AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch), + val, 1); +} + +static int ad3552r_hs_reset(struct ad3552r_hs_state *st) +{ + int ret; + + st->reset_gpio = devm_gpiod_get_optional(st->dev, + "reset", GPIOD_OUT_HIGH); + if (IS_ERR(st->reset_gpio)) + return PTR_ERR(st->reset_gpio); + + if (st->reset_gpio) { + fsleep(10); + gpiod_set_value_cansleep(st->reset_gpio, 0); + } else { + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_A, + AD3552R_MASK_SOFTWARE_RESET, + AD3552R_MASK_SOFTWARE_RESET, 1); + if (ret) + return ret; + } + msleep(100); + + return 0; +} + +static int ad3552r_hs_scratch_pad_test(struct ad3552r_hs_state *st) +{ + int ret, val; + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + AD3552R_SCRATCH_PAD_TEST_VAL1, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + &val, 1); + if (ret) + return ret; + + if (val != AD3552R_SCRATCH_PAD_TEST_VAL1) + return dev_err_probe(st->dev, -EIO, + "SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n", + AD3552R_SCRATCH_PAD_TEST_VAL1, val); + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + AD3552R_SCRATCH_PAD_TEST_VAL2, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_SCRATCH_PAD, + &val, 1); + if (ret) + return ret; + + if (val != AD3552R_SCRATCH_PAD_TEST_VAL2) + return dev_err_probe(st->dev, -EIO, + "SCRATCH_PAD_TEST mismatch. Expected 0x%x, Read 0x%x\n", + AD3552R_SCRATCH_PAD_TEST_VAL2, val); + + return 0; +} + +static int ad3552r_hs_setup_custom_gain(struct ad3552r_hs_state *st, + int ch, u16 gain, u16 offset) +{ + int ret; + + ret = st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_OFFSET(ch), + offset, 1); + if (ret) + return ret; + + return st->data->bus_reg_write(st->back, AD3552R_REG_ADDR_CH_GAIN(ch), + gain, 1); +} + +static int ad3552r_hs_setup(struct ad3552r_hs_state *st) +{ + u16 id; + u16 gain = 0, offset = 0; + u32 ch, val, range; + int ret; + + ret = ad3552r_hs_reset(st); + if (ret) + return ret; + + ret = iio_backend_ddr_disable(st->back); + if (ret) + return ret; + + ret = ad3552r_hs_scratch_pad_test(st); + if (ret) + return ret; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_L, + &val, 1); + if (ret) + return ret; + + id = val; + + ret = st->data->bus_reg_read(st->back, AD3552R_REG_ADDR_PRODUCT_ID_H, + &val, 1); + if (ret) + return ret; + + id |= val << 8; + if (id != st->model_data->chip_id) + dev_info(st->dev, "Chip ID error. Expected 0x%x, Read 0x%x\n", + AD3552R_ID, id); + + ret = st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + 0, 1); + if (ret) + return ret; + + ret = st->data->bus_reg_write(st->back, + AD3552R_REG_ADDR_TRANSFER_REGISTER, + FIELD_PREP(AD3552R_MASK_MULTI_IO_MODE, + AD3552R_QUAD_SPI) | + AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE, 1); + if (ret) + return ret; + + ret = iio_backend_data_source_set(st->back, 0, IIO_BACKEND_EXTERNAL); + if (ret) + return ret; + + ret = iio_backend_data_source_set(st->back, 1, IIO_BACKEND_EXTERNAL); + if (ret) + return ret; + + ret = ad3552r_get_ref_voltage(st->dev, &val); + if (ret < 0) + return ret; + + val = ret; + + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + AD3552R_MASK_REFERENCE_VOLTAGE_SEL, + val, 1); + if (ret) + return ret; + + ret = ad3552r_get_drive_strength(st->dev, &val); + if (!ret) { + ret = ad3552r_qspi_update_reg_bits(st, + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SDO_DRIVE_STRENGTH, + val, 1); + if (ret) + return ret; + } + + device_for_each_child_node_scoped(st->dev, child) { + ret = fwnode_property_read_u32(child, "reg", &ch); + if (ret) + return dev_err_probe(st->dev, ret, + "reg property missing\n"); + + ret = ad3552r_get_output_range(st->dev, st->model_data, child, + &range); + if (ret && ret != -ENOENT) + return ret; + if (ret == -ENOENT) { + ret = ad3552r_get_custom_gain(st->dev, child, + &st->ch_data[ch].p, + &st->ch_data[ch].n, + &st->ch_data[ch].rfb, + &st->ch_data[ch].gain_offset); + if (ret) + return ret; + + gain = ad3552r_calc_custom_gain(st->ch_data[ch].p, + st->ch_data[ch].n, + st->ch_data[ch].gain_offset); + offset = abs(st->ch_data[ch].gain_offset); + + st->ch_data[ch].range_override = 1; + + ret = ad3552r_hs_setup_custom_gain(st, ch, gain, + offset); + if (ret) + return ret; + } else { + st->ch_data[ch].range = range; + + ret = ad3552r_hs_set_output_range(st, ch, range); + if (ret) + return ret; + } + + ad3552r_calc_gain_and_offset(&st->ch_data[ch], st->model_data); + } + + return 0; +} + +static const struct iio_buffer_setup_ops ad3552r_hs_buffer_setup_ops = { + .postenable = ad3552r_hs_buffer_postenable, + .predisable = ad3552r_hs_buffer_predisable, +}; + +#define AD3552R_CHANNEL(ch) { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .output = 1, \ + .indexed = 1, \ + .channel = (ch), \ + .scan_index = (ch), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + } \ +} + +static const struct iio_chan_spec ad3552r_hs_channels[] = { + AD3552R_CHANNEL(0), + AD3552R_CHANNEL(1), +}; + +static const struct iio_info ad3552r_hs_info = { + .read_raw = &ad3552r_hs_read_raw, + .write_raw = &ad3552r_hs_write_raw, +}; + +static int ad3552r_hs_probe(struct platform_device *pdev) +{ + struct ad3552r_hs_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->dev = &pdev->dev; + + st->data = dev_get_platdata(st->dev); + if (!st->data) + return dev_err_probe(st->dev, -ENODEV, "No platform data !"); + + st->back = devm_iio_backend_get(&pdev->dev, NULL); + if (IS_ERR(st->back)) + return PTR_ERR(st->back); + + ret = devm_iio_backend_enable(&pdev->dev, st->back); + if (ret) + return ret; + + st->model_data = device_get_match_data(&pdev->dev); + if (!st->model_data) + return -ENODEV; + + indio_dev->name = "ad3552r"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->setup_ops = &ad3552r_hs_buffer_setup_ops; + indio_dev->channels = ad3552r_hs_channels; + indio_dev->num_channels = ARRAY_SIZE(ad3552r_hs_channels); + indio_dev->info = &ad3552r_hs_info; + + ret = devm_iio_backend_request_buffer(&pdev->dev, st->back, indio_dev); + if (ret) + return ret; + + ret = ad3552r_hs_setup(st); + if (ret) + return ret; + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static const struct ad3552r_model_data ad3552r_model_data = { + .model_name = "ad3552r", + .chip_id = AD3552R_ID, + .num_hw_channels = 2, + .ranges_table = ad3552r_ch_ranges, + .num_ranges = ARRAY_SIZE(ad3552r_ch_ranges), +}; + +static const struct of_device_id ad3552r_hs_of_id[] = { + { .compatible = "adi,ad3552r", .data = &ad3552r_model_data }, + { } +}; +MODULE_DEVICE_TABLE(of, ad3552r_hs_of_id); + +static struct platform_driver ad3552r_hs_driver = { + .driver = { + .name = "ad3552r-hs", + .of_match_table = ad3552r_hs_of_id, + }, + .probe = ad3552r_hs_probe, +}; +module_platform_driver(ad3552r_hs_driver); + +MODULE_AUTHOR("Dragos Bogdan "); +MODULE_AUTHOR("Angelo Dureghello "); +MODULE_DESCRIPTION("AD3552R Driver - High Speed version"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_BACKEND"); +MODULE_IMPORT_NS("IIO_AD3552R"); diff --git a/drivers/iio/dac/ad3552r-hs.h b/drivers/iio/dac/ad3552r-hs.h new file mode 100644 index 00000000000000..724261d38dea3f --- /dev/null +++ b/drivers/iio/dac/ad3552r-hs.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2024 Analog Devices Inc. + * Copyright (c) 2024 Baylibre, SAS + */ +#ifndef __LINUX_PLATFORM_DATA_AD3552R_HS_H__ +#define __LINUX_PLATFORM_DATA_AD3552R_HS_H__ + +struct iio_backend; + +struct ad3552r_hs_platform_data { + int (*bus_reg_read)(struct iio_backend *back, u32 reg, u32 *val, + size_t data_size); + int (*bus_reg_write)(struct iio_backend *back, u32 reg, u32 val, + size_t data_size); + u32 bus_sample_data_clock_hz; +}; + +#endif /* __LINUX_PLATFORM_DATA_AD3552R_HS_H__ */ diff --git a/drivers/iio/dac/ad3552r.c b/drivers/iio/dac/ad3552r.c index 7d61b2fe662436..e7206af53af619 100644 --- a/drivers/iio/dac/ad3552r.c +++ b/drivers/iio/dac/ad3552r.c @@ -6,271 +6,15 @@ * Copyright 2021 Analog Devices Inc. */ #include +#include #include #include #include #include #include -#include #include -/* Register addresses */ -/* Primary address space */ -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00 -#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0)) -#define AD3552R_MASK_ADDR_ASCENSION BIT(5) -#define AD3552R_MASK_SDO_ACTIVE BIT(4) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01 -#define AD3552R_MASK_SINGLE_INST BIT(7) -#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3) -#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02 -#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n)) -#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2) -#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0) -#define AD3552R_REG_ADDR_CHIP_TYPE 0x03 -#define AD3552R_MASK_CLASS GENMASK(7, 0) -#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04 -#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05 -#define AD3552R_REG_ADDR_CHIP_GRADE 0x06 -#define AD3552R_MASK_GRADE GENMASK(7, 4) -#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0) -#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A -#define AD3552R_REG_ADDR_SPI_REVISION 0x0B -#define AD3552R_REG_ADDR_VENDOR_L 0x0C -#define AD3552R_REG_ADDR_VENDOR_H 0x0D -#define AD3552R_REG_ADDR_STREAM_MODE 0x0E -#define AD3552R_MASK_LENGTH GENMASK(7, 0) -#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F -#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6) -#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10 -#define AD3552R_MASK_CRC_ENABLE (GENMASK(7, 6) |\ - GENMASK(1, 0)) -#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5) -#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11 -#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7) -#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5) -#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3) -#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2) -#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1) -#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0) -#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14 -#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6) -#define AD3552R_MASK_MEM_CRC_EN BIT(4) -#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2) -#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1) -#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0) -#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15 -#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6) -#define AD3552R_MASK_SAMPLE_HOLD_DIFFERENTIAL_USER_EN BIT(5) -#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3) -#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2) -#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0) -#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16 -#define AD3552R_MASK_REF_RANGE_ALARM BIT(6) -#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5) -#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4) -#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3) -#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2) -#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1) -#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0) -#define AD3552R_REG_ADDR_ERR_STATUS 0x17 -#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6) -#define AD3552R_MASK_DUAL_SPI_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5) -#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4) -#define AD3552R_MASK_RESET_STATUS BIT(0) -#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18 -#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch)) -#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch) -#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19 -#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) ((ch) ? GENMASK(7, 4) :\ - GENMASK(3, 0)) -#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2) -#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0) -#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2) -#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7) -#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5) -#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3) -#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2) -#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(0) -/* - * Secondary region - * For multibyte registers specify the highest address because the access is - * done in descending order - */ -#define AD3552R_SECONDARY_REGION_START 0x28 -#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28 -#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - ch) * 2) -#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E -#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F -#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31 -#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32 -#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - ch) * 2) -/* 3 bytes registers */ -#define AD3552R_REG_START_24B 0x37 -#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37 -#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - ch) * 3) -#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40 -#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41 -#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44 -#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45 -#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - ch) * 3) - -/* Useful defines */ -#define AD3552R_MAX_CH 2 -#define AD3552R_MASK_CH(ch) BIT(ch) -#define AD3552R_MASK_ALL_CH GENMASK(1, 0) -#define AD3552R_MAX_REG_SIZE 3 -#define AD3552R_READ_BIT BIT(7) -#define AD3552R_ADDR_MASK GENMASK(6, 0) -#define AD3552R_MASK_DAC_12B 0xFFF0 -#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8 -#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34 -#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2 -#define AD3552R_GAIN_SCALE 1000 -#define AD3552R_LDAC_PULSE_US 100 - -enum ad3552r_ch_vref_select { - /* Internal source with Vref I/O floating */ - AD3552R_INTERNAL_VREF_PIN_FLOATING, - /* Internal source with Vref I/O at 2.5V */ - AD3552R_INTERNAL_VREF_PIN_2P5V, - /* External source with Vref I/O as input */ - AD3552R_EXTERNAL_VREF_PIN_INPUT -}; - -enum ad3552r_id { - AD3541R_ID = 0x400b, - AD3542R_ID = 0x4009, - AD3551R_ID = 0x400a, - AD3552R_ID = 0x4008, -}; - -enum ad3552r_ch_output_range { - /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ - AD3552R_CH_OUTPUT_RANGE_0__2P5V, - /* Range from 0 V to 5 V. Requires Rfb1x connection */ - AD3552R_CH_OUTPUT_RANGE_0__5V, - /* Range from 0 V to 10 V. Requires Rfb2x connection */ - AD3552R_CH_OUTPUT_RANGE_0__10V, - /* Range from -5 V to 5 V. Requires Rfb2x connection */ - AD3552R_CH_OUTPUT_RANGE_NEG_5__5V, - /* Range from -10 V to 10 V. Requires Rfb4x connection */ - AD3552R_CH_OUTPUT_RANGE_NEG_10__10V, -}; - -static const s32 ad3552r_ch_ranges[][2] = { - [AD3552R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500}, - [AD3552R_CH_OUTPUT_RANGE_0__5V] = {0, 5000}, - [AD3552R_CH_OUTPUT_RANGE_0__10V] = {0, 10000}, - [AD3552R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000}, - [AD3552R_CH_OUTPUT_RANGE_NEG_10__10V] = {-10000, 10000} -}; - -enum ad3542r_ch_output_range { - /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__2P5V, - /* Range from 0 V to 3 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__3V, - /* Range from 0 V to 5 V. Requires Rfb1x connection */ - AD3542R_CH_OUTPUT_RANGE_0__5V, - /* Range from 0 V to 10 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_0__10V, - /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, - /* Range from -5 V to 5 V. Requires Rfb2x connection */ - AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, -}; - -static const s32 ad3542r_ch_ranges[][2] = { - [AD3542R_CH_OUTPUT_RANGE_0__2P5V] = {0, 2500}, - [AD3542R_CH_OUTPUT_RANGE_0__3V] = {0, 3000}, - [AD3542R_CH_OUTPUT_RANGE_0__5V] = {0, 5000}, - [AD3542R_CH_OUTPUT_RANGE_0__10V] = {0, 10000}, - [AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V] = {-2500, 7500}, - [AD3542R_CH_OUTPUT_RANGE_NEG_5__5V] = {-5000, 5000} -}; - -enum ad3552r_ch_gain_scaling { - /* Gain scaling of 1 */ - AD3552R_CH_GAIN_SCALING_1, - /* Gain scaling of 0.5 */ - AD3552R_CH_GAIN_SCALING_0_5, - /* Gain scaling of 0.25 */ - AD3552R_CH_GAIN_SCALING_0_25, - /* Gain scaling of 0.125 */ - AD3552R_CH_GAIN_SCALING_0_125, -}; - -/* Gain * AD3552R_GAIN_SCALE */ -static const s32 gains_scaling_table[] = { - [AD3552R_CH_GAIN_SCALING_1] = 1000, - [AD3552R_CH_GAIN_SCALING_0_5] = 500, - [AD3552R_CH_GAIN_SCALING_0_25] = 250, - [AD3552R_CH_GAIN_SCALING_0_125] = 125 -}; - -enum ad3552r_dev_attributes { - /* - Direct register values */ - /* From 0-3 */ - AD3552R_SDO_DRIVE_STRENGTH, - /* - * 0 -> Internal Vref, vref_io pin floating (default) - * 1 -> Internal Vref, vref_io driven by internal vref - * 2 or 3 -> External Vref - */ - AD3552R_VREF_SELECT, - /* Read registers in ascending order if set. Else descending */ - AD3552R_ADDR_ASCENSION, -}; - -enum ad3552r_ch_attributes { - /* DAC powerdown */ - AD3552R_CH_DAC_POWERDOWN, - /* DAC amplifier powerdown */ - AD3552R_CH_AMPLIFIER_POWERDOWN, - /* Select the output range. Select from enum ad3552r_ch_output_range */ - AD3552R_CH_OUTPUT_RANGE_SEL, - /* - * Over-rider the range selector in order to manually set the output - * voltage range - */ - AD3552R_CH_RANGE_OVERRIDE, - /* Manually set the offset voltage */ - AD3552R_CH_GAIN_OFFSET, - /* Sets the polarity of the offset. */ - AD3552R_CH_GAIN_OFFSET_POLARITY, - /* PDAC gain scaling */ - AD3552R_CH_GAIN_SCALING_P, - /* NDAC gain scaling */ - AD3552R_CH_GAIN_SCALING_N, - /* Rfb value */ - AD3552R_CH_RFB, - /* Channel select. When set allow Input -> DAC and Mask -> DAC */ - AD3552R_CH_SELECT, -}; - -struct ad3552r_ch_data { - s32 scale_int; - s32 scale_dec; - s32 offset_int; - s32 offset_dec; - s16 gain_offset; - u16 rfb; - u8 n; - u8 p; - u8 range; - bool range_override; -}; - -struct ad3552r_model_data { - const char *model_name; - enum ad3552r_id chip_id; - unsigned int num_hw_channels; - const s32 (*ranges_table)[2]; - int num_ranges; - bool requires_output_range; -}; +#include "ad3552r.h" struct ad3552r_desc { const struct ad3552r_model_data *model_data; @@ -285,45 +29,6 @@ struct ad3552r_desc { unsigned int num_ch; }; -static const u16 addr_mask_map[][2] = { - [AD3552R_ADDR_ASCENSION] = { - AD3552R_REG_ADDR_INTERFACE_CONFIG_A, - AD3552R_MASK_ADDR_ASCENSION - }, - [AD3552R_SDO_DRIVE_STRENGTH] = { - AD3552R_REG_ADDR_INTERFACE_CONFIG_D, - AD3552R_MASK_SDO_DRIVE_STRENGTH - }, - [AD3552R_VREF_SELECT] = { - AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, - AD3552R_MASK_REFERENCE_VOLTAGE_SEL - }, -}; - -/* 0 -> reg addr, 1->ch0 mask, 2->ch1 mask */ -static const u16 addr_mask_map_ch[][3] = { - [AD3552R_CH_DAC_POWERDOWN] = { - AD3552R_REG_ADDR_POWERDOWN_CONFIG, - AD3552R_MASK_CH_DAC_POWERDOWN(0), - AD3552R_MASK_CH_DAC_POWERDOWN(1) - }, - [AD3552R_CH_AMPLIFIER_POWERDOWN] = { - AD3552R_REG_ADDR_POWERDOWN_CONFIG, - AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), - AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1) - }, - [AD3552R_CH_OUTPUT_RANGE_SEL] = { - AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, - AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), - AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1) - }, - [AD3552R_CH_SELECT] = { - AD3552R_REG_ADDR_CH_SELECT_16B, - AD3552R_MASK_CH(0), - AD3552R_MASK_CH(1) - } -}; - static u8 _ad3552r_reg_len(u8 addr) { switch (addr) { @@ -399,11 +104,6 @@ static int ad3552r_read_reg(struct ad3552r_desc *dac, u8 addr, u16 *val) return 0; } -static u16 ad3552r_field_prep(u16 val, u16 mask) -{ - return (val << __ffs(mask)) & mask; -} - /* Update field of a register, shift val if needed */ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask, u16 val) @@ -416,21 +116,11 @@ static int ad3552r_update_reg_field(struct ad3552r_desc *dac, u8 addr, u16 mask, return ret; reg &= ~mask; - reg |= ad3552r_field_prep(val, mask); + reg |= val; return ad3552r_write_reg(dac, addr, reg); } -static int ad3552r_set_ch_value(struct ad3552r_desc *dac, - enum ad3552r_ch_attributes attr, - u8 ch, - u16 val) -{ - /* Update register related to attributes in chip */ - return ad3552r_update_reg_field(dac, addr_mask_map_ch[attr][0], - addr_mask_map_ch[attr][ch + 1], val); -} - #define AD3552R_CH_DAC(_idx) ((struct iio_chan_spec) { \ .type = IIO_VOLTAGE, \ .output = true, \ @@ -510,8 +200,14 @@ static int ad3552r_write_raw(struct iio_dev *indio_dev, val); break; case IIO_CHAN_INFO_ENABLE: - err = ad3552r_set_ch_value(dac, AD3552R_CH_DAC_POWERDOWN, - chan->channel, !val); + if (chan->channel == 0) + val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(0), !val); + else + val = FIELD_PREP(AD3552R_MASK_CH_DAC_POWERDOWN(1), !val); + + err = ad3552r_update_reg_field(dac, AD3552R_REG_ADDR_POWERDOWN_CONFIG, + AD3552R_MASK_CH_DAC_POWERDOWN(chan->channel), + val); break; default: err = -EINVAL; @@ -715,83 +411,9 @@ static int ad3552r_reset(struct ad3552r_desc *dac) } return ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_ADDR_ASCENSION][0], - addr_mask_map[AD3552R_ADDR_ASCENSION][1], - val); -} - -static void ad3552r_get_custom_range(struct ad3552r_desc *dac, s32 i, s32 *v_min, - s32 *v_max) -{ - s64 vref, tmp, common, offset, gn, gp; - /* - * From datasheet formula (In Volts): - * Vmin = 2.5 + [(GainN + Offset / 1024) * 2.5 * Rfb * 1.03] - * Vmax = 2.5 - [(GainP + Offset / 1024) * 2.5 * Rfb * 1.03] - * Calculus are converted to milivolts - */ - vref = 2500; - /* 2.5 * 1.03 * 1000 (To mV) */ - common = 2575 * dac->ch_data[i].rfb; - offset = dac->ch_data[i].gain_offset; - - gn = gains_scaling_table[dac->ch_data[i].n]; - tmp = (1024 * gn + AD3552R_GAIN_SCALE * offset) * common; - tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); - *v_max = vref + tmp; - - gp = gains_scaling_table[dac->ch_data[i].p]; - tmp = (1024 * gp - AD3552R_GAIN_SCALE * offset) * common; - tmp = div_s64(tmp, 1024 * AD3552R_GAIN_SCALE); - *v_min = vref - tmp; -} - -static void ad3552r_calc_gain_and_offset(struct ad3552r_desc *dac, s32 ch) -{ - s32 idx, v_max, v_min, span, rem; - s64 tmp; - - if (dac->ch_data[ch].range_override) { - ad3552r_get_custom_range(dac, ch, &v_min, &v_max); - } else { - /* Normal range */ - idx = dac->ch_data[ch].range; - v_min = dac->model_data->ranges_table[idx][0]; - v_max = dac->model_data->ranges_table[idx][1]; - } - - /* - * From datasheet formula: - * Vout = Span * (D / 65536) + Vmin - * Converted to scale and offset: - * Scale = Span / 65536 - * Offset = 65536 * Vmin / Span - * - * Reminders are in micros in order to be printed as - * IIO_VAL_INT_PLUS_MICRO - */ - span = v_max - v_min; - dac->ch_data[ch].scale_int = div_s64_rem(span, 65536, &rem); - /* Do operations in microvolts */ - dac->ch_data[ch].scale_dec = DIV_ROUND_CLOSEST((s64)rem * 1000000, - 65536); - - dac->ch_data[ch].offset_int = div_s64_rem(v_min * 65536, span, &rem); - tmp = (s64)rem * 1000000; - dac->ch_data[ch].offset_dec = div_s64(tmp, span); -} - -static int ad3552r_find_range(const struct ad3552r_model_data *model_data, - s32 *vals) -{ - int i; - - for (i = 0; i < model_data->num_ranges; i++) - if (vals[0] == model_data->ranges_table[i][0] * 1000 && - vals[1] == model_data->ranges_table[i][1] * 1000) - return i; - - return -EINVAL; + AD3552R_REG_ADDR_INTERFACE_CONFIG_A, + AD3552R_MASK_ADDR_ASCENSION, + FIELD_PREP(AD3552R_MASK_ADDR_ASCENSION, val)); } static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, @@ -799,57 +421,30 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, u32 ch) { struct device *dev = &dac->spi->dev; - u32 val; int err; u8 addr; - u16 reg = 0, offset; - - struct fwnode_handle *gain_child __free(fwnode_handle) - = fwnode_get_named_child_node(child, - "custom-output-range-config"); - if (!gain_child) - return dev_err_probe(dev, -EINVAL, - "mandatory custom-output-range-config property missing\n"); - - dac->ch_data[ch].range_override = 1; - reg |= ad3552r_field_prep(1, AD3552R_MASK_CH_RANGE_OVERRIDE); - - err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-p", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-scaling-p property missing\n"); - reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_P); - dac->ch_data[ch].p = val; - - err = fwnode_property_read_u32(gain_child, "adi,gain-scaling-n", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-scaling-n property missing\n"); - reg |= ad3552r_field_prep(val, AD3552R_MASK_CH_GAIN_SCALING_N); - dac->ch_data[ch].n = val; - - err = fwnode_property_read_u32(gain_child, "adi,rfb-ohms", &val); - if (err) - return dev_err_probe(dev, err, - "mandatory adi,rfb-ohms property missing\n"); - dac->ch_data[ch].rfb = val; + u16 reg; - err = fwnode_property_read_u32(gain_child, "adi,gain-offset", &val); + err = ad3552r_get_custom_gain(dev, child, + &dac->ch_data[ch].p, + &dac->ch_data[ch].n, + &dac->ch_data[ch].rfb, + &dac->ch_data[ch].gain_offset); if (err) - return dev_err_probe(dev, err, - "mandatory adi,gain-offset property missing\n"); - dac->ch_data[ch].gain_offset = val; + return err; - offset = abs((s32)val); - reg |= ad3552r_field_prep((offset >> 8), AD3552R_MASK_CH_OFFSET_BIT_8); + dac->ch_data[ch].range_override = 1; - reg |= ad3552r_field_prep((s32)val < 0, AD3552R_MASK_CH_OFFSET_POLARITY); addr = AD3552R_REG_ADDR_CH_GAIN(ch); err = ad3552r_write_reg(dac, addr, - offset & AD3552R_MASK_CH_OFFSET_BITS_0_7); + abs((s32)dac->ch_data[ch].gain_offset) & + AD3552R_MASK_CH_OFFSET_BITS_0_7); if (err) return dev_err_probe(dev, err, "Error writing register\n"); + reg = ad3552r_calc_custom_gain(dac->ch_data[ch].p, dac->ch_data[ch].n, + dac->ch_data[ch].gain_offset); + err = ad3552r_write_reg(dac, addr, reg); if (err) return dev_err_probe(dev, err, "Error writing register\n"); @@ -860,49 +455,31 @@ static int ad3552r_configure_custom_gain(struct ad3552r_desc *dac, static int ad3552r_configure_device(struct ad3552r_desc *dac) { struct device *dev = &dac->spi->dev; - int err, cnt = 0, voltage, delta = 100000; - u32 vals[2], val, ch; + int err, cnt = 0; + u32 val, ch; dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH); if (IS_ERR(dac->gpio_ldac)) return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac), "Error getting gpio ldac"); - voltage = devm_regulator_get_enable_read_voltage(dev, "vref"); - if (voltage < 0 && voltage != -ENODEV) - return dev_err_probe(dev, voltage, "Error getting vref voltage\n"); - - if (voltage == -ENODEV) { - if (device_property_read_bool(dev, "adi,vref-out-en")) - val = AD3552R_INTERNAL_VREF_PIN_2P5V; - else - val = AD3552R_INTERNAL_VREF_PIN_FLOATING; - } else { - if (voltage > 2500000 + delta || voltage < 2500000 - delta) { - dev_warn(dev, "vref-supply must be 2.5V"); - return -EINVAL; - } - val = AD3552R_EXTERNAL_VREF_PIN_INPUT; - } + err = ad3552r_get_ref_voltage(dev, &val); + if (err < 0) + return err; err = ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_VREF_SELECT][0], - addr_mask_map[AD3552R_VREF_SELECT][1], - val); + AD3552R_REG_ADDR_SH_REFERENCE_CONFIG, + AD3552R_MASK_REFERENCE_VOLTAGE_SEL, + FIELD_PREP(AD3552R_MASK_REFERENCE_VOLTAGE_SEL, val)); if (err) return err; - err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val); + err = ad3552r_get_drive_strength(dev, &val); if (!err) { - if (val > 3) { - dev_err(dev, "adi,sdo-drive-strength must be less than 4\n"); - return -EINVAL; - } - err = ad3552r_update_reg_field(dac, - addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0], - addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1], - val); + AD3552R_REG_ADDR_INTERFACE_CONFIG_D, + AD3552R_MASK_SDO_DRIVE_STRENGTH, + FIELD_PREP(AD3552R_MASK_SDO_DRIVE_STRENGTH, val)); if (err) return err; } @@ -923,24 +500,21 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) "reg must be less than %d\n", dac->model_data->num_hw_channels); - if (fwnode_property_present(child, "adi,output-range-microvolt")) { - err = fwnode_property_read_u32_array(child, - "adi,output-range-microvolt", - vals, - 2); - if (err) - return dev_err_probe(dev, err, - "adi,output-range-microvolt property could not be parsed\n"); - - err = ad3552r_find_range(dac->model_data, vals); - if (err < 0) - return dev_err_probe(dev, err, - "Invalid adi,output-range-microvolt value\n"); - - val = err; - err = ad3552r_set_ch_value(dac, - AD3552R_CH_OUTPUT_RANGE_SEL, - ch, val); + err = ad3552r_get_output_range(dev, dac->model_data, + child, &val); + if (err && err != -ENOENT) + return err; + + if (!err) { + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(0), val); + else + val = FIELD_PREP(AD3552R_MASK_CH_OUTPUT_RANGE_SEL(1), val); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE, + AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch), + val); if (err) return err; @@ -955,10 +529,17 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) return err; } - ad3552r_calc_gain_and_offset(dac, ch); + ad3552r_calc_gain_and_offset(&dac->ch_data[ch], dac->model_data); dac->enabled_ch |= BIT(ch); - err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1); + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH(0), 1); + else + val = FIELD_PREP(AD3552R_MASK_CH(1), 1); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_CH_SELECT_16B, + AD3552R_MASK_CH(ch), val); if (err < 0) return err; @@ -970,8 +551,15 @@ static int ad3552r_configure_device(struct ad3552r_desc *dac) /* Disable unused channels */ for_each_clear_bit(ch, &dac->enabled_ch, dac->model_data->num_hw_channels) { - err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN, - ch, 1); + if (ch == 0) + val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(0), 1); + else + val = FIELD_PREP(AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(1), 1); + + err = ad3552r_update_reg_field(dac, + AD3552R_REG_ADDR_POWERDOWN_CONFIG, + AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch), + val); if (err) return err; } @@ -1140,3 +728,4 @@ module_spi_driver(ad3552r_driver); MODULE_AUTHOR("Mihail Chindris "); MODULE_DESCRIPTION("Analog Device AD3552R DAC"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_AD3552R"); diff --git a/drivers/iio/dac/ad3552r.h b/drivers/iio/dac/ad3552r.h new file mode 100644 index 00000000000000..fd5a3dfd1d1cfe --- /dev/null +++ b/drivers/iio/dac/ad3552r.h @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * AD3552R Digital <-> Analog converters common header + * + * Copyright 2021-2024 Analog Devices Inc. + * Author: Angelo Dureghello + */ + +#ifndef __DRIVERS_IIO_DAC_AD3552R_H__ +#define __DRIVERS_IIO_DAC_AD3552R_H__ + +/* Register addresses */ +/* Primary address space */ +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_A 0x00 +#define AD3552R_MASK_SOFTWARE_RESET (BIT(7) | BIT(0)) +#define AD3552R_MASK_ADDR_ASCENSION BIT(5) +#define AD3552R_MASK_SDO_ACTIVE BIT(4) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_B 0x01 +#define AD3552R_MASK_SINGLE_INST BIT(7) +#define AD3552R_MASK_SHORT_INSTRUCTION BIT(3) +#define AD3552R_REG_ADDR_DEVICE_CONFIG 0x02 +#define AD3552R_MASK_DEVICE_STATUS(n) BIT(4 + (n)) +#define AD3552R_MASK_CUSTOM_MODES GENMASK(3, 2) +#define AD3552R_MASK_OPERATING_MODES GENMASK(1, 0) +#define AD3552R_REG_ADDR_CHIP_TYPE 0x03 +#define AD3552R_MASK_CLASS GENMASK(7, 0) +#define AD3552R_REG_ADDR_PRODUCT_ID_L 0x04 +#define AD3552R_REG_ADDR_PRODUCT_ID_H 0x05 +#define AD3552R_REG_ADDR_CHIP_GRADE 0x06 +#define AD3552R_MASK_GRADE GENMASK(7, 4) +#define AD3552R_MASK_DEVICE_REVISION GENMASK(3, 0) +#define AD3552R_REG_ADDR_SCRATCH_PAD 0x0A +#define AD3552R_REG_ADDR_SPI_REVISION 0x0B +#define AD3552R_REG_ADDR_VENDOR_L 0x0C +#define AD3552R_REG_ADDR_VENDOR_H 0x0D +#define AD3552R_REG_ADDR_STREAM_MODE 0x0E +#define AD3552R_MASK_LENGTH GENMASK(7, 0) +#define AD3552R_REG_ADDR_TRANSFER_REGISTER 0x0F +#define AD3552R_MASK_MULTI_IO_MODE GENMASK(7, 6) +#define AD3552R_MASK_STREAM_LENGTH_KEEP_VALUE BIT(2) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_C 0x10 +#define AD3552R_MASK_CRC_ENABLE \ + (GENMASK(7, 6) | GENMASK(1, 0)) +#define AD3552R_MASK_STRICT_REGISTER_ACCESS BIT(5) +#define AD3552R_REG_ADDR_INTERFACE_STATUS_A 0x11 +#define AD3552R_MASK_INTERFACE_NOT_READY BIT(7) +#define AD3552R_MASK_CLOCK_COUNTING_ERROR BIT(5) +#define AD3552R_MASK_INVALID_OR_NO_CRC BIT(3) +#define AD3552R_MASK_WRITE_TO_READ_ONLY_REGISTER BIT(2) +#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS BIT(1) +#define AD3552R_MASK_REGISTER_ADDRESS_INVALID BIT(0) +#define AD3552R_REG_ADDR_INTERFACE_CONFIG_D 0x14 +#define AD3552R_MASK_ALERT_ENABLE_PULLUP BIT(6) +#define AD3552R_MASK_MEM_CRC_EN BIT(4) +#define AD3552R_MASK_SDO_DRIVE_STRENGTH GENMASK(3, 2) +#define AD3552R_MASK_DUAL_SPI_SYNCHROUNOUS_EN BIT(1) +#define AD3552R_MASK_SPI_CONFIG_DDR BIT(0) +#define AD3552R_REG_ADDR_SH_REFERENCE_CONFIG 0x15 +#define AD3552R_MASK_IDUMP_FAST_MODE BIT(6) +#define AD3552R_MASK_SAMPLE_HOLD_DIFF_USER_EN BIT(5) +#define AD3552R_MASK_SAMPLE_HOLD_USER_TRIM GENMASK(4, 3) +#define AD3552R_MASK_SAMPLE_HOLD_USER_ENABLE BIT(2) +#define AD3552R_MASK_REFERENCE_VOLTAGE_SEL GENMASK(1, 0) +#define AD3552R_REG_ADDR_ERR_ALARM_MASK 0x16 +#define AD3552R_MASK_REF_RANGE_ALARM BIT(6) +#define AD3552R_MASK_CLOCK_COUNT_ERR_ALARM BIT(5) +#define AD3552R_MASK_MEM_CRC_ERR_ALARM BIT(4) +#define AD3552R_MASK_SPI_CRC_ERR_ALARM BIT(3) +#define AD3552R_MASK_WRITE_TO_READ_ONLY_ALARM BIT(2) +#define AD3552R_MASK_PARTIAL_REGISTER_ACCESS_ALARM BIT(1) +#define AD3552R_MASK_REGISTER_ADDRESS_INVALID_ALARM BIT(0) +#define AD3552R_REG_ADDR_ERR_STATUS 0x17 +#define AD3552R_MASK_REF_RANGE_ERR_STATUS BIT(6) +#define AD3552R_MASK_STREAM_EXCEEDS_DAC_ERR_STATUS BIT(5) +#define AD3552R_MASK_MEM_CRC_ERR_STATUS BIT(4) +#define AD3552R_MASK_RESET_STATUS BIT(0) +#define AD3552R_REG_ADDR_POWERDOWN_CONFIG 0x18 +#define AD3552R_MASK_CH_DAC_POWERDOWN(ch) BIT(4 + (ch)) +#define AD3552R_MASK_CH_AMPLIFIER_POWERDOWN(ch) BIT(ch) +#define AD3552R_REG_ADDR_CH0_CH1_OUTPUT_RANGE 0x19 +#define AD3552R_MASK_CH0_RANGE GENMASK(2, 0) +#define AD3552R_MASK_CH1_RANGE GENMASK(6, 4) +#define AD3552R_MASK_CH_OUTPUT_RANGE GENMASK(7, 0) +#define AD3552R_MASK_CH_OUTPUT_RANGE_SEL(ch) \ + ((ch) ? GENMASK(7, 4) : GENMASK(3, 0)) +#define AD3552R_REG_ADDR_CH_OFFSET(ch) (0x1B + (ch) * 2) +#define AD3552R_MASK_CH_OFFSET_BITS_0_7 GENMASK(7, 0) +#define AD3552R_REG_ADDR_CH_GAIN(ch) (0x1C + (ch) * 2) +#define AD3552R_MASK_CH_RANGE_OVERRIDE BIT(7) +#define AD3552R_MASK_CH_GAIN_SCALING_N GENMASK(6, 5) +#define AD3552R_MASK_CH_GAIN_SCALING_P GENMASK(4, 3) +#define AD3552R_MASK_CH_OFFSET_POLARITY BIT(2) +#define AD3552R_MASK_CH_OFFSET_BIT_8 BIT(8) +/* + * Secondary region + * For multibyte registers specify the highest address because the access is + * done in descending order + */ +#define AD3552R_SECONDARY_REGION_START 0x28 +#define AD3552R_REG_ADDR_HW_LDAC_16B 0x28 +#define AD3552R_REG_ADDR_CH_DAC_16B(ch) (0x2C - (1 - (ch)) * 2) +#define AD3552R_REG_ADDR_DAC_PAGE_MASK_16B 0x2E +#define AD3552R_REG_ADDR_CH_SELECT_16B 0x2F +#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_16B 0x31 +#define AD3552R_REG_ADDR_SW_LDAC_16B 0x32 +#define AD3552R_REG_ADDR_CH_INPUT_16B(ch) (0x36 - (1 - (ch)) * 2) +/* 3 bytes registers */ +#define AD3552R_REG_START_24B 0x37 +#define AD3552R_REG_ADDR_HW_LDAC_24B 0x37 +#define AD3552R_REG_ADDR_CH_DAC_24B(ch) (0x3D - (1 - (ch)) * 3) +#define AD3552R_REG_ADDR_DAC_PAGE_MASK_24B 0x40 +#define AD3552R_REG_ADDR_CH_SELECT_24B 0x41 +#define AD3552R_REG_ADDR_INPUT_PAGE_MASK_24B 0x44 +#define AD3552R_REG_ADDR_SW_LDAC_24B 0x45 +#define AD3552R_REG_ADDR_CH_INPUT_24B(ch) (0x4B - (1 - (ch)) * 3) + +#define AD3552R_MAX_CH 2 +#define AD3552R_MASK_CH(ch) BIT(ch) +#define AD3552R_MASK_ALL_CH GENMASK(1, 0) +#define AD3552R_MAX_REG_SIZE 3 +#define AD3552R_READ_BIT BIT(7) +#define AD3552R_ADDR_MASK GENMASK(6, 0) +#define AD3552R_MASK_DAC_12B GENMASK(15, 4) +#define AD3552R_DEFAULT_CONFIG_B_VALUE 0x8 +#define AD3552R_SCRATCH_PAD_TEST_VAL1 0x34 +#define AD3552R_SCRATCH_PAD_TEST_VAL2 0xB2 +#define AD3552R_GAIN_SCALE 1000 +#define AD3552R_LDAC_PULSE_US 100 + +#define AD3552R_CH0_ACTIVE BIT(0) +#define AD3552R_CH1_ACTIVE BIT(1) + +#define AD3552R_MAX_RANGES 5 +#define AD3542R_MAX_RANGES 6 +#define AD3552R_QUAD_SPI 2 + +extern const s32 ad3552r_ch_ranges[AD3552R_MAX_RANGES][2]; +extern const s32 ad3542r_ch_ranges[AD3542R_MAX_RANGES][2]; + +enum ad3552r_id { + AD3541R_ID = 0x400b, + AD3542R_ID = 0x4009, + AD3551R_ID = 0x400a, + AD3552R_ID = 0x4008, +}; + +struct ad3552r_model_data { + const char *model_name; + enum ad3552r_id chip_id; + unsigned int num_hw_channels; + const s32 (*ranges_table)[2]; + int num_ranges; + bool requires_output_range; +}; + +struct ad3552r_ch_data { + s32 scale_int; + s32 scale_dec; + s32 offset_int; + s32 offset_dec; + s16 gain_offset; + u16 rfb; + u8 n; + u8 p; + u8 range; + bool range_override; +}; + +enum ad3552r_ch_gain_scaling { + /* Gain scaling of 1 */ + AD3552R_CH_GAIN_SCALING_1, + /* Gain scaling of 0.5 */ + AD3552R_CH_GAIN_SCALING_0_5, + /* Gain scaling of 0.25 */ + AD3552R_CH_GAIN_SCALING_0_25, + /* Gain scaling of 0.125 */ + AD3552R_CH_GAIN_SCALING_0_125, +}; + +enum ad3552r_ch_vref_select { + /* Internal source with Vref I/O floating */ + AD3552R_INTERNAL_VREF_PIN_FLOATING, + /* Internal source with Vref I/O at 2.5V */ + AD3552R_INTERNAL_VREF_PIN_2P5V, + /* External source with Vref I/O as input */ + AD3552R_EXTERNAL_VREF_PIN_INPUT +}; + +enum ad3542r_ch_output_range { + /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__2P5V, + /* Range from 0 V to 3 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__3V, + /* Range from 0 V to 5 V. Requires Rfb1x connection */ + AD3542R_CH_OUTPUT_RANGE_0__5V, + /* Range from 0 V to 10 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_0__10V, + /* Range from -2.5 V to 7.5 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_NEG_2P5__7P5V, + /* Range from -5 V to 5 V. Requires Rfb2x connection */ + AD3542R_CH_OUTPUT_RANGE_NEG_5__5V, +}; + +enum ad3552r_ch_output_range { + /* Range from 0 V to 2.5 V. Requires Rfb1x connection */ + AD3552R_CH_OUTPUT_RANGE_0__2P5V, + /* Range from 0 V to 5 V. Requires Rfb1x connection */ + AD3552R_CH_OUTPUT_RANGE_0__5V, + /* Range from 0 V to 10 V. Requires Rfb2x connection */ + AD3552R_CH_OUTPUT_RANGE_0__10V, + /* Range from -5 V to 5 V. Requires Rfb2x connection */ + AD3552R_CH_OUTPUT_RANGE_NEG_5__5V, + /* Range from -10 V to 10 V. Requires Rfb4x connection */ + AD3552R_CH_OUTPUT_RANGE_NEG_10__10V, +}; + +int ad3552r_get_output_range(struct device *dev, + const struct ad3552r_model_data *model_info, + struct fwnode_handle *child, u32 *val); +int ad3552r_get_custom_gain(struct device *dev, struct fwnode_handle *child, + u8 *gs_p, u8 *gs_n, u16 *rfb, s16 *goffs); +u16 ad3552r_calc_custom_gain(u8 p, u8 n, s16 goffs); +int ad3552r_get_ref_voltage(struct device *dev, u32 *val); +int ad3552r_get_drive_strength(struct device *dev, u32 *val); +void ad3552r_calc_gain_and_offset(struct ad3552r_ch_data *ch_data, + const struct ad3552r_model_data *model_data); + +#endif /* __DRIVERS_IIO_DAC_AD3552R_H__ */ diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 2e3e33f92bc0af..392a1c7aee03b5 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -47,7 +47,6 @@ struct ad5380_chip_info { * struct ad5380_state - driver instance specific data * @regmap: regmap instance used by the device * @chip_info: chip model specific constants, available modes etc - * @vref_reg: vref supply regulator * @vref: actual reference voltage used in uA * @pwr_down: whether the chip is currently in power down mode * @lock: lock to protect the data buffer during regmap ops @@ -55,7 +54,6 @@ struct ad5380_chip_info { struct ad5380_state { struct regmap *regmap; const struct ad5380_chip_info *chip_info; - struct regulator *vref_reg; int vref; bool pwr_down; struct mutex lock; @@ -341,14 +339,14 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = { }, }; -static int ad5380_alloc_channels(struct iio_dev *indio_dev) +static int ad5380_alloc_channels(struct device *dev, struct iio_dev *indio_dev) { struct ad5380_state *st = iio_priv(indio_dev); struct iio_chan_spec *channels; unsigned int i; - channels = kcalloc(st->chip_info->num_channels, - sizeof(struct iio_chan_spec), GFP_KERNEL); + channels = devm_kcalloc(dev, st->chip_info->num_channels, + sizeof(struct iio_chan_spec), GFP_KERNEL); if (!channels) return -ENOMEM; @@ -379,7 +377,6 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, } st = iio_priv(indio_dev); - dev_set_drvdata(dev, indio_dev); st->chip_info = &ad5380_chip_info_tbl[type]; st->regmap = regmap; @@ -391,68 +388,32 @@ static int ad5380_probe(struct device *dev, struct regmap *regmap, mutex_init(&st->lock); - ret = ad5380_alloc_channels(indio_dev); - if (ret) { - dev_err(dev, "Failed to allocate channel spec: %d\n", ret); - return ret; - } + ret = ad5380_alloc_channels(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to allocate channel spec\n"); if (st->chip_info->int_vref == 2500) ctrl |= AD5380_CTRL_INT_VREF_2V5; - st->vref_reg = devm_regulator_get(dev, "vref"); - if (!IS_ERR(st->vref_reg)) { - ret = regulator_enable(st->vref_reg); - if (ret) { - dev_err(dev, "Failed to enable vref regulators: %d\n", - ret); - goto error_free_reg; - } - - ret = regulator_get_voltage(st->vref_reg); - if (ret < 0) - goto error_disable_reg; - - st->vref = ret / 1000; - } else { + ret = devm_regulator_get_enable_read_voltage(dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "Failed to get vref voltage\n"); + if (ret == -ENODEV) { st->vref = st->chip_info->int_vref; ctrl |= AD5380_CTRL_INT_VREF_EN; + } else { + st->vref = ret / 1000; } ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl); - if (ret) { - dev_err(dev, "Failed to write to device: %d\n", ret); - goto error_disable_reg; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to write to device\n"); - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(dev, "Failed to register iio device: %d\n", ret); - goto error_disable_reg; - } + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to register iio device\n"); return 0; - -error_disable_reg: - if (!IS_ERR(st->vref_reg)) - regulator_disable(st->vref_reg); -error_free_reg: - kfree(indio_dev->channels); - - return ret; -} - -static void ad5380_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5380_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - kfree(indio_dev->channels); - - if (!IS_ERR(st->vref_reg)) - regulator_disable(st->vref_reg); } static bool ad5380_reg_false(struct device *dev, unsigned int reg) @@ -486,11 +447,6 @@ static int ad5380_spi_probe(struct spi_device *spi) return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name); } -static void ad5380_spi_remove(struct spi_device *spi) -{ - ad5380_remove(&spi->dev); -} - static const struct spi_device_id ad5380_spi_ids[] = { { "ad5380-3", ID_AD5380_3 }, { "ad5380-5", ID_AD5380_5 }, @@ -517,7 +473,6 @@ static struct spi_driver ad5380_spi_driver = { .name = "ad5380", }, .probe = ad5380_spi_probe, - .remove = ad5380_spi_remove, .id_table = ad5380_spi_ids, }; @@ -559,11 +514,6 @@ static int ad5380_i2c_probe(struct i2c_client *i2c) return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name); } -static void ad5380_i2c_remove(struct i2c_client *i2c) -{ - ad5380_remove(&i2c->dev); -} - static const struct i2c_device_id ad5380_i2c_ids[] = { { "ad5380-3", ID_AD5380_3 }, { "ad5380-5", ID_AD5380_5 }, @@ -590,7 +540,6 @@ static struct i2c_driver ad5380_i2c_driver = { .name = "ad5380", }, .probe = ad5380_i2c_probe, - .remove = ad5380_i2c_remove, .id_table = ad5380_i2c_ids, }; diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 7644acfd879e04..1462ee640b1686 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -384,7 +384,7 @@ static int ad5421_write_raw(struct iio_dev *indio_dev, static int ad5421_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) + enum iio_event_direction dir, bool state) { struct ad5421_state *st = iio_priv(indio_dev); unsigned int mask; diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 708629efc15734..6ad99f97eed55f 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -32,7 +32,6 @@ * struct ad5446_state - driver instance specific data * @dev: this device * @chip_info: chip model specific constants, available modes etc - * @reg: supply regulator * @vref_mv: actual reference voltage used * @cached_val: store/retrieve values during power down * @pwr_down_mode: power down mode (1k, 100k or tristate) @@ -43,7 +42,6 @@ struct ad5446_state { struct device *dev; const struct ad5446_chip_info *chip_info; - struct regulator *reg; unsigned short vref_mv; unsigned cached_val; unsigned pwr_down_mode; @@ -226,32 +224,15 @@ static int ad5446_probe(struct device *dev, const char *name, { struct ad5446_state *st; struct iio_dev *indio_dev; - struct regulator *reg; - int ret, voltage_uv = 0; - - reg = devm_regulator_get(dev, "vcc"); - if (!IS_ERR(reg)) { - ret = regulator_enable(reg); - if (ret) - return ret; - - ret = regulator_get_voltage(reg); - if (ret < 0) - goto error_disable_reg; - - voltage_uv = ret; - } + int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_disable_reg; - } + if (!indio_dev) + return -ENOMEM; + st = iio_priv(indio_dev); st->chip_info = chip_info; - dev_set_drvdata(dev, indio_dev); - st->reg = reg; st->dev = dev; indio_dev->name = name; @@ -264,33 +245,19 @@ static int ad5446_probe(struct device *dev, const char *name, st->pwr_down_mode = MODE_PWRDWN_1k; - if (st->chip_info->int_vref_mv) - st->vref_mv = st->chip_info->int_vref_mv; - else if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else - dev_warn(dev, "reference voltage unspecified\n"); - - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg; - - return 0; - -error_disable_reg: - if (!IS_ERR(reg)) - regulator_disable(reg); - return ret; -} - -static void ad5446_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(indio_dev); + ret = devm_regulator_get_enable_read_voltage(dev, "vcc"); + if (ret < 0 && ret != -ENODEV) + return ret; + if (ret == -ENODEV) { + if (chip_info->int_vref_mv) + st->vref_mv = chip_info->int_vref_mv; + else + dev_warn(dev, "reference voltage unspecified\n"); + } else { + st->vref_mv = ret / 1000; + } - iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + return devm_iio_device_register(dev, indio_dev); } #if IS_ENABLED(CONFIG_SPI_MASTER) @@ -491,18 +458,12 @@ static int ad5446_spi_probe(struct spi_device *spi) &ad5446_spi_chip_info[id->driver_data]); } -static void ad5446_spi_remove(struct spi_device *spi) -{ - ad5446_remove(&spi->dev); -} - static struct spi_driver ad5446_spi_driver = { .driver = { .name = "ad5446", .of_match_table = ad5446_of_ids, }, .probe = ad5446_spi_probe, - .remove = ad5446_spi_remove, .id_table = ad5446_spi_ids, }; @@ -575,11 +536,6 @@ static int ad5446_i2c_probe(struct i2c_client *i2c) &ad5446_i2c_chip_info[id->driver_data]); } -static void ad5446_i2c_remove(struct i2c_client *i2c) -{ - ad5446_remove(&i2c->dev); -} - static const struct i2c_device_id ad5446_i2c_ids[] = { {"ad5301", ID_AD5602}, {"ad5311", ID_AD5612}, @@ -596,7 +552,6 @@ static struct i2c_driver ad5446_i2c_driver = { .name = "ad5446", }, .probe = ad5446_i2c_probe, - .remove = ad5446_i2c_remove, .id_table = ad5446_i2c_ids, }; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index e6c5be728bb211..ff0765c8af47f8 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -270,38 +270,29 @@ static const struct iio_chan_spec ad5504_channels[] = { static int ad5504_probe(struct spi_device *spi) { - struct ad5504_platform_data *pdata = spi->dev.platform_data; + const struct ad5504_platform_data *pdata = dev_get_platdata(&spi->dev); struct iio_dev *indio_dev; struct ad5504_state *st; - struct regulator *reg; - int ret, voltage_uv = 0; + int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; - reg = devm_regulator_get(&spi->dev, "vcc"); - if (!IS_ERR(reg)) { - ret = regulator_enable(reg); - if (ret) - return ret; - ret = regulator_get_voltage(reg); - if (ret < 0) - goto error_disable_reg; + st = iio_priv(indio_dev); - voltage_uv = ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc"); + if (ret < 0 && ret != -ENODEV) + return ret; + if (ret == -ENODEV) { + if (pdata->vref_mv) + st->vref_mv = pdata->vref_mv; + else + dev_warn(&spi->dev, "reference voltage unspecified\n"); + } else { + st->vref_mv = ret / 1000; } - spi_set_drvdata(spi, indio_dev); - st = iio_priv(indio_dev); - if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else if (pdata) - st->vref_mv = pdata->vref_mv; - else - dev_warn(&spi->dev, "reference voltage unspecified\n"); - - st->reg = reg; st->spi = spi; indio_dev->name = spi_get_device_id(st->spi)->name; indio_dev->info = &ad5504_info; @@ -320,31 +311,10 @@ static int ad5504_probe(struct spi_device *spi) spi_get_device_id(st->spi)->name, indio_dev); if (ret) - goto error_disable_reg; + return ret; } - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg; - - return 0; - -error_disable_reg: - if (!IS_ERR(reg)) - regulator_disable(reg); - - return ret; -} - -static void ad5504_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad5504_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad5504_id[] = { @@ -359,7 +329,6 @@ static struct spi_driver ad5504_driver = { .name = "ad5504", }, .probe = ad5504_probe, - .remove = ad5504_remove, .id_table = ad5504_id, }; module_spi_driver(ad5504_driver); diff --git a/drivers/iio/dac/ad5592r-base.c b/drivers/iio/dac/ad5592r-base.c index 4763402dbcd66d..50d19304bacbc6 100644 --- a/drivers/iio/dac/ad5592r-base.c +++ b/drivers/iio/dac/ad5592r-base.c @@ -665,7 +665,7 @@ int ad5592r_probe(struct device *dev, const char *name, return ret; } -EXPORT_SYMBOL_NS_GPL(ad5592r_probe, IIO_AD5592R); +EXPORT_SYMBOL_NS_GPL(ad5592r_probe, "IIO_AD5592R"); void ad5592r_remove(struct device *dev) { @@ -679,7 +679,7 @@ void ad5592r_remove(struct device *dev) if (st->reg) regulator_disable(st->reg); } -EXPORT_SYMBOL_NS_GPL(ad5592r_remove, IIO_AD5592R); +EXPORT_SYMBOL_NS_GPL(ad5592r_remove, "IIO_AD5592R"); MODULE_AUTHOR("Paul Cercueil "); MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters"); diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c index 32d950bbb1ca0b..fd82d8701322c4 100644 --- a/drivers/iio/dac/ad5592r.c +++ b/drivers/iio/dac/ad5592r.c @@ -168,4 +168,4 @@ module_spi_driver(ad5592r_spi_driver); MODULE_AUTHOR("Paul Cercueil "); MODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD5592R); +MODULE_IMPORT_NS("IIO_AD5592R"); diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c index 62e1fbb9e9101e..ddd13ad821a794 100644 --- a/drivers/iio/dac/ad5593r.c +++ b/drivers/iio/dac/ad5593r.c @@ -147,4 +147,4 @@ module_i2c_driver(ad5593r_driver); MODULE_AUTHOR("Paul Cercueil "); MODULE_DESCRIPTION("Analog Devices AD5593R multi-channel converters"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD5592R); +MODULE_IMPORT_NS("IIO_AD5592R"); diff --git a/drivers/iio/dac/ad5624r.h b/drivers/iio/dac/ad5624r.h index 13964f3a22a46a..14a439b06eb6a2 100644 --- a/drivers/iio/dac/ad5624r.h +++ b/drivers/iio/dac/ad5624r.h @@ -54,7 +54,6 @@ struct ad5624r_chip_info { struct ad5624r_state { struct spi_device *us; const struct ad5624r_chip_info *chip_info; - struct regulator *reg; unsigned short vref_mv; unsigned pwr_down_mask; unsigned pwr_down_mode; diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 9304d0499bae82..2fd38ac8f69885 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -223,50 +223,26 @@ static int ad5624r_probe(struct spi_device *spi) { struct ad5624r_state *st; struct iio_dev *indio_dev; - int ret, voltage_uv = 0; + bool external_vref; + int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) - goto error_disable_reg; - - voltage_uv = ret; - } else { - if (PTR_ERR(st->reg) != -ENODEV) - return PTR_ERR(st->reg); + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret == -ENODEV) /* Backwards compatibility. This naming is not correct */ - st->reg = devm_regulator_get_optional(&spi->dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg); - if (ret < 0) - goto error_disable_reg; - - voltage_uv = ret; - } - } + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vcc"); + if (ret < 0 && ret != -ENODEV) + return ret; + + external_vref = ret != -ENODEV; + st->vref_mv = external_vref ? ret / 1000 : st->chip_info->int_vref_mv; - spi_set_drvdata(spi, indio_dev); st->chip_info = &ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - if (voltage_uv) - st->vref_mv = voltage_uv / 1000; - else - st->vref_mv = st->chip_info->int_vref_mv; - st->us = spi; indio_dev->name = spi_get_device_id(spi)->name; @@ -276,31 +252,11 @@ static int ad5624r_probe(struct spi_device *spi) indio_dev->num_channels = AD5624R_DAC_CHANNELS; ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, - !!voltage_uv, 16); - if (ret) - goto error_disable_reg; - - ret = iio_device_register(indio_dev); + external_vref, 16); if (ret) - goto error_disable_reg; - - return 0; - -error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - - return ret; -} - -static void ad5624r_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad5624r_state *st = iio_priv(indio_dev); + return ret; - iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad5624r_id[] = { @@ -319,7 +275,6 @@ static struct spi_driver ad5624r_driver = { .name = "ad5624r", }, .probe = ad5624r_probe, - .remove = ad5624r_remove, .id_table = ad5624r_id, }; module_spi_driver(ad5624r_driver); diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 8ba2ea70451a95..39b5dad0d6a5ee 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -135,4 +135,4 @@ module_spi_driver(ad5686_spi_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD5686); +MODULE_IMPORT_NS("IIO_AD5686"); diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 57cc0f0eedc6c6..8dc578b087845a 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -543,7 +543,7 @@ int ad5686_probe(struct device *dev, regulator_disable(st->reg); return ret; } -EXPORT_SYMBOL_NS_GPL(ad5686_probe, IIO_AD5686); +EXPORT_SYMBOL_NS_GPL(ad5686_probe, "IIO_AD5686"); void ad5686_remove(struct device *dev) { @@ -554,7 +554,7 @@ void ad5686_remove(struct device *dev) if (!IS_ERR(st->reg)) regulator_disable(st->reg); } -EXPORT_SYMBOL_NS_GPL(ad5686_remove, IIO_AD5686); +EXPORT_SYMBOL_NS_GPL(ad5686_remove, "IIO_AD5686"); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index 81541f755a3e1b..bbcda246c54705 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -125,4 +125,4 @@ module_i2c_driver(ad5686_i2c_driver); MODULE_AUTHOR("Stefan Popa "); MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_AD5686); +MODULE_IMPORT_NS("IIO_AD5686"); diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 0b24cb19ac9d1c..05e80b6ae2cc3f 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -699,7 +699,6 @@ static const struct ad5755_platform_data ad5755_default_pdata = { static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev) { - struct fwnode_handle *pp; struct ad5755_platform_data *pdata; unsigned int tmp; unsigned int tmparray[3]; @@ -746,11 +745,12 @@ static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev) } devnr = 0; - device_for_each_child_node(dev, pp) { + device_for_each_child_node_scoped(dev, pp) { if (devnr >= AD5755_NUM_CHANNELS) { dev_err(dev, "There are too many channels defined in DT\n"); - goto error_out; + devm_kfree(dev, pdata); + return NULL; } pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA; @@ -800,11 +800,6 @@ static struct ad5755_platform_data *ad5755_parse_fw(struct device *dev) } return pdata; - - error_out: - fwnode_handle_put(pp); - devm_kfree(dev, pdata); - return NULL; } static int ad5755_probe(struct spi_device *spi) diff --git a/drivers/iio/dac/ad5761.c b/drivers/iio/dac/ad5761.c index 6aa1a068adb061..0aa5ba7f465482 100644 --- a/drivers/iio/dac/ad5761.c +++ b/drivers/iio/dac/ad5761.c @@ -53,7 +53,6 @@ enum ad5761_supported_device_ids { /** * struct ad5761_state - driver instance specific data * @spi: spi_device - * @vref_reg: reference voltage regulator * @use_intref: true when the internal voltage reference is used * @vref: actual voltage reference in mVolts * @range: output range mode used @@ -62,7 +61,6 @@ enum ad5761_supported_device_ids { */ struct ad5761_state { struct spi_device *spi; - struct regulator *vref_reg; struct mutex lock; bool use_intref; @@ -287,63 +285,6 @@ static const struct ad5761_chip_info ad5761_chip_infos[] = { }, }; -static int ad5761_get_vref(struct ad5761_state *st, - const struct ad5761_chip_info *chip_info) -{ - int ret; - - st->vref_reg = devm_regulator_get_optional(&st->spi->dev, "vref"); - if (PTR_ERR(st->vref_reg) == -ENODEV) { - /* Use Internal regulator */ - if (!chip_info->int_vref) { - dev_err(&st->spi->dev, - "Voltage reference not found\n"); - return -EIO; - } - - st->use_intref = true; - st->vref = chip_info->int_vref; - return 0; - } - - if (IS_ERR(st->vref_reg)) { - dev_err(&st->spi->dev, - "Error getting voltage reference regulator\n"); - return PTR_ERR(st->vref_reg); - } - - ret = regulator_enable(st->vref_reg); - if (ret) { - dev_err(&st->spi->dev, - "Failed to enable voltage reference\n"); - return ret; - } - - ret = regulator_get_voltage(st->vref_reg); - if (ret < 0) { - dev_err(&st->spi->dev, - "Failed to get voltage reference value\n"); - goto disable_regulator_vref; - } - - if (ret < 2000000 || ret > 3000000) { - dev_warn(&st->spi->dev, - "Invalid external voltage ref. value %d uV\n", ret); - ret = -EIO; - goto disable_regulator_vref; - } - - st->vref = ret / 1000; - st->use_intref = false; - - return 0; - -disable_regulator_vref: - regulator_disable(st->vref_reg); - st->vref_reg = NULL; - return ret; -} - static int ad5761_probe(struct spi_device *spi) { struct iio_dev *iio_dev; @@ -361,11 +302,28 @@ static int ad5761_probe(struct spi_device *spi) st = iio_priv(iio_dev); st->spi = spi; - spi_set_drvdata(spi, iio_dev); - ret = ad5761_get_vref(st, chip_info); - if (ret) - return ret; + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(&spi->dev, ret, + "Failed to get voltage reference value\n"); + if (ret == -ENODEV) { + /* Use Internal regulator */ + if (!chip_info->int_vref) + return dev_err_probe(&spi->dev, -EIO, + "Voltage reference not found\n"); + + st->use_intref = true; + st->vref = chip_info->int_vref; + } else { + if (ret < 2000000 || ret > 3000000) + return dev_err_probe(&spi->dev, -EIO, + "Invalid external voltage ref. value %d uV\n", + ret); + + st->use_intref = false; + st->vref = ret / 1000; + } if (pdata) voltage_range = pdata->voltage_range; @@ -374,35 +332,15 @@ static int ad5761_probe(struct spi_device *spi) ret = ad5761_spi_set_range(st, voltage_range); if (ret) - goto disable_regulator_err; + return ret; iio_dev->info = &ad5761_info; iio_dev->modes = INDIO_DIRECT_MODE; iio_dev->channels = &chip_info->channel; iio_dev->num_channels = 1; iio_dev->name = spi_get_device_id(st->spi)->name; - ret = iio_device_register(iio_dev); - if (ret) - goto disable_regulator_err; - - return 0; - -disable_regulator_err: - if (!IS_ERR_OR_NULL(st->vref_reg)) - regulator_disable(st->vref_reg); - - return ret; -} - -static void ad5761_remove(struct spi_device *spi) -{ - struct iio_dev *iio_dev = spi_get_drvdata(spi); - struct ad5761_state *st = iio_priv(iio_dev); - - iio_device_unregister(iio_dev); - if (!IS_ERR_OR_NULL(st->vref_reg)) - regulator_disable(st->vref_reg); + return devm_iio_device_register(&spi->dev, iio_dev); } static const struct spi_device_id ad5761_id[] = { @@ -419,7 +357,6 @@ static struct spi_driver ad5761_driver = { .name = "ad5761", }, .probe = ad5761_probe, - .remove = ad5761_remove, .id_table = ad5761_id, }; module_spi_driver(ad5761_driver); diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c index c360ebf5297ab9..25cf11d0471b60 100644 --- a/drivers/iio/dac/ad5770r.c +++ b/drivers/iio/dac/ad5770r.c @@ -17,6 +17,7 @@ #include #include #include +#include #define ADI_SPI_IF_CONFIG_A 0x00 #define ADI_SPI_IF_CONFIG_B 0x01 @@ -121,7 +122,6 @@ struct ad5770r_out_range { * struct ad5770r_state - driver instance specific data * @spi: spi_device * @regmap: regmap - * @vref_reg: fixed regulator for reference configuration * @gpio_reset: gpio descriptor * @output_mode: array contains channels output ranges * @vref: reference value @@ -133,7 +133,6 @@ struct ad5770r_out_range { struct ad5770r_state { struct spi_device *spi; struct regmap *regmap; - struct regulator *vref_reg; struct gpio_desc *gpio_reset; struct ad5770r_out_range output_mode[AD5770R_MAX_CHANNELS]; int vref; @@ -325,7 +324,7 @@ static int ad5770r_read_raw(struct iio_dev *indio_dev, if (ret) return 0; - buf16 = st->transf_buf[0] + (st->transf_buf[1] << 8); + buf16 = get_unaligned_le16(st->transf_buf); *val = buf16 >> 2; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -590,13 +589,6 @@ static int ad5770r_init(struct ad5770r_state *st) return ret; } -static void ad5770r_disable_regulator(void *data) -{ - struct ad5770r_state *st = data; - - regulator_disable(st->vref_reg); -} - static int ad5770r_probe(struct spi_device *spi) { struct ad5770r_state *st; @@ -621,34 +613,12 @@ static int ad5770r_probe(struct spi_device *spi) } st->regmap = regmap; - st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref"); - if (!IS_ERR(st->vref_reg)) { - ret = regulator_enable(st->vref_reg); - if (ret) { - dev_err(&spi->dev, - "Failed to enable vref regulators: %d\n", ret); - return ret; - } + ret = devm_regulator_get_enable_read_voltage(&spi->dev, "vref"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(&spi->dev, ret, "Failed to get vref voltage\n"); - ret = devm_add_action_or_reset(&spi->dev, - ad5770r_disable_regulator, - st); - if (ret < 0) - return ret; - - ret = regulator_get_voltage(st->vref_reg); - if (ret < 0) - return ret; - - st->vref = ret / 1000; - } else { - if (PTR_ERR(st->vref_reg) == -ENODEV) { - st->vref = AD5770R_LOW_VREF_mV; - st->internal_ref = true; - } else { - return PTR_ERR(st->vref_reg); - } - } + st->internal_ref = ret == -ENODEV; + st->vref = st->internal_ref ? AD5770R_LOW_VREF_mV : ret / 1000; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->info = &ad5770r_info; diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 75b549827e15a5..57374f78f6b885 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -61,11 +62,14 @@ /** * struct ad5791_chip_info - chip specific information + * @name: name of the dac chip + * @channel: channel specification * @get_lin_comp: function pointer to the device specific function */ - struct ad5791_chip_info { - int (*get_lin_comp) (unsigned int span); + const char *name; + const struct iio_chan_spec channel; + int (*get_lin_comp)(unsigned int span); }; /** @@ -73,6 +77,9 @@ struct ad5791_chip_info { * @spi: spi_device * @reg_vdd: positive supply regulator * @reg_vss: negative supply regulator + * @gpio_reset: reset gpio + * @gpio_clear: clear gpio + * @gpio_ldac: load dac gpio * @chip_info: chip model specific constants * @vref_mv: actual reference voltage used * @vref_neg_mv: voltage of the negative supply @@ -85,6 +92,9 @@ struct ad5791_state { struct spi_device *spi; struct regulator *reg_vdd; struct regulator *reg_vss; + struct gpio_desc *gpio_reset; + struct gpio_desc *gpio_clear; + struct gpio_desc *gpio_ldac; const struct ad5791_chip_info *chip_info; unsigned short vref_mv; unsigned int vref_neg_mv; @@ -98,13 +108,6 @@ struct ad5791_state { } data[3] __aligned(IIO_DMA_MINALIGN); }; -enum ad5791_supported_device_ids { - ID_AD5760, - ID_AD5780, - ID_AD5781, - ID_AD5791, -}; - static int ad5791_spi_write(struct ad5791_state *st, u8 addr, u32 val) { st->data[0].d32 = cpu_to_be32(AD5791_CMD_WRITE | @@ -228,20 +231,6 @@ static int ad5780_get_lin_comp(unsigned int span) else return AD5780_LINCOMP_10_20; } -static const struct ad5791_chip_info ad5791_chip_info_tbl[] = { - [ID_AD5760] = { - .get_lin_comp = ad5780_get_lin_comp, - }, - [ID_AD5780] = { - .get_lin_comp = ad5780_get_lin_comp, - }, - [ID_AD5781] = { - .get_lin_comp = ad5791_get_lin_comp, - }, - [ID_AD5791] = { - .get_lin_comp = ad5791_get_lin_comp, - }, -}; static int ad5791_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -289,30 +278,34 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { { }, }; -#define AD5791_CHAN(bits, _shift) { \ - .type = IIO_VOLTAGE, \ - .output = 1, \ - .indexed = 1, \ - .address = AD5791_ADDR_DAC0, \ - .channel = 0, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ - .scan_type = { \ - .sign = 'u', \ - .realbits = (bits), \ - .storagebits = 24, \ - .shift = (_shift), \ - }, \ - .ext_info = ad5791_ext_info, \ +#define AD5791_DEFINE_CHIP_INFO(_name, bits, _shift, _lin_comp) \ +static const struct ad5791_chip_info _name##_chip_info = { \ + .name = #_name, \ + .get_lin_comp = &(_lin_comp), \ + .channel = { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .address = AD5791_ADDR_DAC0, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 24, \ + .shift = (_shift), \ + }, \ + .ext_info = ad5791_ext_info, \ + }, \ } -static const struct iio_chan_spec ad5791_channels[] = { - [ID_AD5760] = AD5791_CHAN(16, 4), - [ID_AD5780] = AD5791_CHAN(18, 2), - [ID_AD5781] = AD5791_CHAN(18, 2), - [ID_AD5791] = AD5791_CHAN(20, 0) -}; +AD5791_DEFINE_CHIP_INFO(ad5760, 16, 4, ad5780_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5780, 18, 2, ad5780_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5781, 18, 2, ad5791_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5790, 20, 0, ad5791_get_lin_comp); +AD5791_DEFINE_CHIP_INFO(ad5791, 20, 0, ad5791_get_lin_comp); static int ad5791_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -341,7 +334,7 @@ static const struct iio_info ad5791_info = { static int ad5791_probe(struct spi_device *spi) { - struct ad5791_platform_data *pdata = spi->dev.platform_data; + const struct ad5791_platform_data *pdata = dev_get_platdata(&spi->dev); struct iio_dev *indio_dev; struct ad5791_state *st; int ret, pos_voltage_uv = 0, neg_voltage_uv = 0; @@ -351,31 +344,21 @@ static int ad5791_probe(struct spi_device *spi) if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->reg_vdd = devm_regulator_get(&spi->dev, "vdd"); - if (!IS_ERR(st->reg_vdd)) { - ret = regulator_enable(st->reg_vdd); - if (ret) - return ret; - - ret = regulator_get_voltage(st->reg_vdd); - if (ret < 0) - goto error_disable_reg_pos; - - pos_voltage_uv = ret; - } - st->reg_vss = devm_regulator_get(&spi->dev, "vss"); - if (!IS_ERR(st->reg_vss)) { - ret = regulator_enable(st->reg_vss); - if (ret) - goto error_disable_reg_pos; + st->gpio_reset = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); - ret = regulator_get_voltage(st->reg_vss); - if (ret < 0) - goto error_disable_reg_neg; + st->gpio_clear = devm_gpiod_get_optional(&spi->dev, "clear", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_clear)) + return PTR_ERR(st->gpio_clear); - neg_voltage_uv = ret; - } + st->gpio_ldac = devm_gpiod_get_optional(&spi->dev, "ldac", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_ldac)) + return PTR_ERR(st->gpio_ldac); st->pwr_down = true; st->spi = spi; @@ -386,7 +369,17 @@ static int ad5791_probe(struct spi_device *spi) use_rbuf_gain2 = device_property_read_bool(&spi->dev, "adi,rbuf-gain2-en"); - if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) { + pos_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vdd"); + if (pos_voltage_uv < 0 && pos_voltage_uv != -ENODEV) + return dev_err_probe(&spi->dev, pos_voltage_uv, + "failed to get vdd voltage\n"); + + neg_voltage_uv = devm_regulator_get_enable_read_voltage(&spi->dev, "vss"); + if (neg_voltage_uv < 0 && neg_voltage_uv != -ENODEV) + return dev_err_probe(&spi->dev, neg_voltage_uv, + "failed to get vss voltage\n"); + + if (neg_voltage_uv >= 0 && pos_voltage_uv >= 0) { st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000; st->vref_neg_mv = neg_voltage_uv / 1000; } else if (pdata) { @@ -396,13 +389,18 @@ static int ad5791_probe(struct spi_device *spi) dev_warn(&spi->dev, "reference voltage unspecified\n"); } - ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); - if (ret) - goto error_disable_reg_neg; - - st->chip_info = &ad5791_chip_info_tbl[spi_get_device_id(spi) - ->driver_data]; + if (st->gpio_reset) { + fsleep(20); + gpiod_set_value_cansleep(st->gpio_reset, 0); + } else { + ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); + if (ret) + return dev_err_probe(&spi->dev, ret, "fail to reset\n"); + } + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return dev_err_probe(&spi->dev, -EINVAL, "no chip info\n"); st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv)) | (use_rbuf_gain2 ? 0 : AD5791_CTRL_RBUF) | @@ -411,59 +409,42 @@ static int ad5791_probe(struct spi_device *spi) ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl | AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); if (ret) - goto error_disable_reg_neg; + return dev_err_probe(&spi->dev, ret, "fail to write ctrl register\n"); - spi_set_drvdata(spi, indio_dev); indio_dev->info = &ad5791_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels - = &ad5791_channels[spi_get_device_id(spi)->driver_data]; + indio_dev->channels = &st->chip_info->channel; indio_dev->num_channels = 1; - indio_dev->name = spi_get_device_id(st->spi)->name; - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg_neg; - - return 0; - -error_disable_reg_neg: - if (!IS_ERR(st->reg_vss)) - regulator_disable(st->reg_vss); -error_disable_reg_pos: - if (!IS_ERR(st->reg_vdd)) - regulator_disable(st->reg_vdd); - return ret; + indio_dev->name = st->chip_info->name; + return devm_iio_device_register(&spi->dev, indio_dev); } -static void ad5791_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad5791_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg_vdd)) - regulator_disable(st->reg_vdd); - - if (!IS_ERR(st->reg_vss)) - regulator_disable(st->reg_vss); -} +static const struct of_device_id ad5791_of_match[] = { + { .compatible = "adi,ad5760", .data = &ad5760_chip_info }, + { .compatible = "adi,ad5780", .data = &ad5780_chip_info }, + { .compatible = "adi,ad5781", .data = &ad5781_chip_info }, + { .compatible = "adi,ad5790", .data = &ad5790_chip_info }, + { .compatible = "adi,ad5791", .data = &ad5791_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5791_of_match); static const struct spi_device_id ad5791_id[] = { - {"ad5760", ID_AD5760}, - {"ad5780", ID_AD5780}, - {"ad5781", ID_AD5781}, - {"ad5790", ID_AD5791}, - {"ad5791", ID_AD5791}, - {} + { "ad5760", (kernel_ulong_t)&ad5760_chip_info }, + { "ad5780", (kernel_ulong_t)&ad5780_chip_info }, + { "ad5781", (kernel_ulong_t)&ad5781_chip_info }, + { "ad5790", (kernel_ulong_t)&ad5790_chip_info }, + { "ad5791", (kernel_ulong_t)&ad5791_chip_info }, + { } }; MODULE_DEVICE_TABLE(spi, ad5791_id); static struct spi_driver ad5791_driver = { .driver = { .name = "ad5791", + .of_match_table = ad5791_of_match, }, .probe = ad5791_probe, - .remove = ad5791_remove, .id_table = ad5791_id, }; module_spi_driver(ad5791_driver); diff --git a/drivers/iio/dac/ad8460.c b/drivers/iio/dac/ad8460.c new file mode 100644 index 00000000000000..535ee3105af6b1 --- /dev/null +++ b/drivers/iio/dac/ad8460.c @@ -0,0 +1,951 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AD8460 Waveform generator DAC Driver + * + * Copyright (C) 2024 Analog Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define AD8460_CTRL_REG(x) (x) +#define AD8460_HVDAC_DATA_WORD(x) (0x60 + (2 * (x))) + +#define AD8460_HV_RESET_MSK BIT(7) +#define AD8460_HV_SLEEP_MSK BIT(4) +#define AD8460_WAVE_GEN_MODE_MSK BIT(0) + +#define AD8460_HVDAC_SLEEP_MSK BIT(3) + +#define AD8460_FAULT_ARM_MSK BIT(7) +#define AD8460_FAULT_LIMIT_MSK GENMASK(6, 0) + +#define AD8460_APG_MODE_ENABLE_MSK BIT(5) +#define AD8460_PATTERN_DEPTH_MSK GENMASK(3, 0) + +#define AD8460_QUIESCENT_CURRENT_MSK GENMASK(7, 0) + +#define AD8460_SHUTDOWN_FLAG_MSK BIT(7) + +#define AD8460_DATA_BYTE_LOW_MSK GENMASK(7, 0) +#define AD8460_DATA_BYTE_HIGH_MSK GENMASK(5, 0) +#define AD8460_DATA_BYTE_FULL_MSK GENMASK(13, 0) + +#define AD8460_DEFAULT_FAULT_PROTECT 0x00 +#define AD8460_DATA_BYTE_WORD_LENGTH 2 +#define AD8460_NUM_DATA_WORDS 16 +#define AD8460_NOMINAL_VOLTAGE_SPAN 80 +#define AD8460_MIN_EXT_RESISTOR_OHMS 2000 +#define AD8460_MAX_EXT_RESISTOR_OHMS 20000 +#define AD8460_MIN_VREFIO_UV 120000 +#define AD8460_MAX_VREFIO_UV 1200000 +#define AD8460_ABS_MAX_OVERVOLTAGE_UV 55000000 +#define AD8460_ABS_MAX_OVERCURRENT_UA 1000000 +#define AD8460_MAX_OVERTEMPERATURE_MC 150000 +#define AD8460_MIN_OVERTEMPERATURE_MC 20000 +#define AD8460_CURRENT_LIMIT_CONV(x) ((x) / 15625) +#define AD8460_VOLTAGE_LIMIT_CONV(x) ((x) / 1953000) +#define AD8460_TEMP_LIMIT_CONV(x) (((x) + 266640) / 6510) + +enum ad8460_fault_type { + AD8460_OVERCURRENT_SRC, + AD8460_OVERCURRENT_SNK, + AD8460_OVERVOLTAGE_POS, + AD8460_OVERVOLTAGE_NEG, + AD8460_OVERTEMPERATURE, +}; + +struct ad8460_state { + struct spi_device *spi; + struct regmap *regmap; + struct iio_channel *tmp_adc_channel; + struct clk *sync_clk; + /* lock to protect against multiple access to the device and shared data */ + struct mutex lock; + int refio_1p2v_mv; + u32 ext_resistor_ohms; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + __le16 spi_tx_buf __aligned(IIO_DMA_MINALIGN); +}; + +static int ad8460_hv_reset(struct ad8460_state *state) +{ + int ret; + + ret = regmap_set_bits(state->regmap, AD8460_CTRL_REG(0x00), + AD8460_HV_RESET_MSK); + if (ret) + return ret; + + fsleep(20); + + return regmap_clear_bits(state->regmap, AD8460_CTRL_REG(0x00), + AD8460_HV_RESET_MSK); +} + +static int ad8460_reset(const struct ad8460_state *state) +{ + struct device *dev = &state->spi->dev; + struct gpio_desc *reset; + + reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset)) + return dev_err_probe(dev, PTR_ERR(reset), + "Failed to get reset gpio"); + if (reset) { + /* minimum duration of 10ns */ + ndelay(10); + gpiod_set_value_cansleep(reset, 1); + return 0; + } + + /* bring all registers to their default state */ + return regmap_write(state->regmap, AD8460_CTRL_REG(0x03), 1); +} + +static int ad8460_enable_apg_mode(struct ad8460_state *state, int val) +{ + int ret; + + ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02), + AD8460_APG_MODE_ENABLE_MSK, + FIELD_PREP(AD8460_APG_MODE_ENABLE_MSK, val)); + if (ret) + return ret; + + return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x00), + AD8460_WAVE_GEN_MODE_MSK, + FIELD_PREP(AD8460_WAVE_GEN_MODE_MSK, val)); +} + +static int ad8460_read_shutdown_flag(struct ad8460_state *state, u64 *flag) +{ + int ret, val; + + ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x0E), &val); + if (ret) + return ret; + + *flag = FIELD_GET(AD8460_SHUTDOWN_FLAG_MSK, val); + return 0; +} + +static int ad8460_get_hvdac_word(struct ad8460_state *state, int index, int *val) +{ + int ret; + + ret = regmap_bulk_read(state->regmap, AD8460_HVDAC_DATA_WORD(index), + &state->spi_tx_buf, AD8460_DATA_BYTE_WORD_LENGTH); + if (ret) + return ret; + + *val = le16_to_cpu(state->spi_tx_buf); + + return ret; +} + +static int ad8460_set_hvdac_word(struct ad8460_state *state, int index, int val) +{ + state->spi_tx_buf = cpu_to_le16(FIELD_PREP(AD8460_DATA_BYTE_FULL_MSK, val)); + + return regmap_bulk_write(state->regmap, AD8460_HVDAC_DATA_WORD(index), + &state->spi_tx_buf, AD8460_DATA_BYTE_WORD_LENGTH); +} + +static ssize_t ad8460_dac_input_read(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct ad8460_state *state = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = ad8460_get_hvdac_word(state, private, ®); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", reg); +} + +static ssize_t ad8460_dac_input_write(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad8460_state *state = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = kstrtou32(buf, 10, ®); + if (ret) + return ret; + + guard(mutex)(&state->lock); + + return ad8460_set_hvdac_word(state, private, reg); +} + +static ssize_t ad8460_read_symbol(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct ad8460_state *state = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x02), ®); + if (ret) + return ret; + + return sysfs_emit(buf, "%lu\n", FIELD_GET(AD8460_PATTERN_DEPTH_MSK, reg)); +} + +static ssize_t ad8460_write_symbol(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad8460_state *state = iio_priv(indio_dev); + uint16_t sym; + int ret; + + ret = kstrtou16(buf, 10, &sym); + if (ret) + return ret; + + guard(mutex)(&state->lock); + + return regmap_update_bits(state->regmap, + AD8460_CTRL_REG(0x02), + AD8460_PATTERN_DEPTH_MSK, + FIELD_PREP(AD8460_PATTERN_DEPTH_MSK, sym)); +} + +static ssize_t ad8460_read_toggle_en(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct ad8460_state *state = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x02), ®); + if (ret) + return ret; + + return sysfs_emit(buf, "%ld\n", FIELD_GET(AD8460_APG_MODE_ENABLE_MSK, reg)); +} + +static ssize_t ad8460_write_toggle_en(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad8460_state *state = iio_priv(indio_dev); + bool toggle_en; + int ret; + + ret = kstrtobool(buf, &toggle_en); + if (ret) + return ret; + + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return ad8460_enable_apg_mode(state, toggle_en); + unreachable(); +} + +static ssize_t ad8460_read_powerdown(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + struct ad8460_state *state = iio_priv(indio_dev); + unsigned int reg; + int ret; + + ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x01), ®); + if (ret) + return ret; + + return sysfs_emit(buf, "%ld\n", FIELD_GET(AD8460_HVDAC_SLEEP_MSK, reg)); +} + +static ssize_t ad8460_write_powerdown(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad8460_state *state = iio_priv(indio_dev); + bool pwr_down; + u64 sdn_flag; + int ret; + + ret = kstrtobool(buf, &pwr_down); + if (ret) + return ret; + + guard(mutex)(&state->lock); + + /* + * If powerdown is set, HVDAC is enabled and the HV driver is + * enabled via HV_RESET in case it is in shutdown mode, + * If powerdown is cleared, HVDAC is set to shutdown state + * as well as the HV driver. Quiescent current decreases and ouput is + * floating (high impedance). + */ + + ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x01), + AD8460_HVDAC_SLEEP_MSK, + FIELD_PREP(AD8460_HVDAC_SLEEP_MSK, pwr_down)); + if (ret) + return ret; + + if (!pwr_down) { + ret = ad8460_read_shutdown_flag(state, &sdn_flag); + if (ret) + return ret; + + if (sdn_flag) { + ret = ad8460_hv_reset(state); + if (ret) + return ret; + } + } + + ret = regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x00), + AD8460_HV_SLEEP_MSK, + FIELD_PREP(AD8460_HV_SLEEP_MSK, !pwr_down)); + if (ret) + return ret; + + return len; +} + +static const char * const ad8460_powerdown_modes[] = { + "three_state", +}; + +static int ad8460_get_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + return 0; +} + +static int ad8460_set_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int type) +{ + return 0; +} + +static int ad8460_set_sample(struct ad8460_state *state, int val) +{ + int ret; + + ret = ad8460_enable_apg_mode(state, 1); + if (ret) + return ret; + + guard(mutex)(&state->lock); + ret = ad8460_set_hvdac_word(state, 0, val); + if (ret) + return ret; + + return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x02), + AD8460_PATTERN_DEPTH_MSK, + FIELD_PREP(AD8460_PATTERN_DEPTH_MSK, 0)); +} + +static int ad8460_set_fault_threshold(struct ad8460_state *state, + enum ad8460_fault_type fault, + unsigned int threshold) +{ + return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x08 + fault), + AD8460_FAULT_LIMIT_MSK, + FIELD_PREP(AD8460_FAULT_LIMIT_MSK, threshold)); +} + +static int ad8460_get_fault_threshold(struct ad8460_state *state, + enum ad8460_fault_type fault, + unsigned int *threshold) +{ + unsigned int val; + int ret; + + ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x08 + fault), &val); + if (ret) + return ret; + + *threshold = FIELD_GET(AD8460_FAULT_LIMIT_MSK, val); + + return ret; +} + +static int ad8460_set_fault_threshold_en(struct ad8460_state *state, + enum ad8460_fault_type fault, bool en) +{ + return regmap_update_bits(state->regmap, AD8460_CTRL_REG(0x08 + fault), + AD8460_FAULT_ARM_MSK, + FIELD_PREP(AD8460_FAULT_ARM_MSK, en)); +} + +static int ad8460_get_fault_threshold_en(struct ad8460_state *state, + enum ad8460_fault_type fault, bool *en) +{ + unsigned int val; + int ret; + + ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x08 + fault), &val); + if (ret) + return ret; + + *en = FIELD_GET(AD8460_FAULT_ARM_MSK, val); + + return 0; +} + +static int ad8460_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct ad8460_state *state = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_VOLTAGE: + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) + return ad8460_set_sample(state, val); + unreachable(); + case IIO_CURRENT: + return regmap_write(state->regmap, AD8460_CTRL_REG(0x04), + FIELD_PREP(AD8460_QUIESCENT_CURRENT_MSK, val)); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ad8460_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad8460_state *state = iio_priv(indio_dev); + int data, ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_VOLTAGE: + scoped_guard(mutex, &state->lock) { + ret = ad8460_get_hvdac_word(state, 0, &data); + if (ret) + return ret; + } + *val = data; + return IIO_VAL_INT; + case IIO_CURRENT: + ret = regmap_read(state->regmap, AD8460_CTRL_REG(0x04), + &data); + if (ret) + return ret; + *val = data; + return IIO_VAL_INT; + case IIO_TEMP: + ret = iio_read_channel_raw(state->tmp_adc_channel, &data); + if (ret) + return ret; + *val = data; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + *val = clk_get_rate(state->sync_clk); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* + * vCONV = vNOMINAL_SPAN * (DAC_CODE / 2**14) - 40V + * vMAX = vNOMINAL_SPAN * (2**14 / 2**14) - 40V + * vMIN = vNOMINAL_SPAN * (0 / 2**14) - 40V + * vADJ = vCONV * (2000 / rSET) * (vREF / 1.2) + * vSPAN = vADJ_MAX - vADJ_MIN + * See datasheet page 49, section FULL-SCALE REDUCTION + */ + *val = AD8460_NOMINAL_VOLTAGE_SPAN * 2000 * state->refio_1p2v_mv; + *val2 = state->ext_resistor_ohms * 1200; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } +} + +static int ad8460_select_fault_type(int chan_type, enum iio_event_direction dir) +{ + switch (chan_type) { + case IIO_VOLTAGE: + switch (dir) { + case IIO_EV_DIR_RISING: + return AD8460_OVERVOLTAGE_POS; + case IIO_EV_DIR_FALLING: + return AD8460_OVERVOLTAGE_NEG; + default: + return -EINVAL; + } + case IIO_CURRENT: + switch (dir) { + case IIO_EV_DIR_RISING: + return AD8460_OVERCURRENT_SRC; + case IIO_EV_DIR_FALLING: + return AD8460_OVERCURRENT_SNK; + default: + return -EINVAL; + } + case IIO_TEMP: + switch (dir) { + case IIO_EV_DIR_RISING: + return AD8460_OVERTEMPERATURE; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int ad8460_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 ad8460_state *state = iio_priv(indio_dev); + int fault; + + if (type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + if (info != IIO_EV_INFO_VALUE) + return -EINVAL; + + fault = ad8460_select_fault_type(chan->type, dir); + if (fault < 0) + return fault; + + return ad8460_set_fault_threshold(state, fault, val); +} + +static int ad8460_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 ad8460_state *state = iio_priv(indio_dev); + int fault; + + if (type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + if (info != IIO_EV_INFO_VALUE) + return -EINVAL; + + fault = ad8460_select_fault_type(chan->type, dir); + if (fault < 0) + return fault; + + return ad8460_get_fault_threshold(state, fault, val); +} + +static int ad8460_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, bool val) +{ + struct ad8460_state *state = iio_priv(indio_dev); + int fault; + + if (type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + fault = ad8460_select_fault_type(chan->type, dir); + if (fault < 0) + return fault; + + return ad8460_set_fault_threshold_en(state, fault, val); +} + +static int ad8460_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 ad8460_state *state = iio_priv(indio_dev); + int fault, ret; + bool en; + + if (type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + fault = ad8460_select_fault_type(chan->type, dir); + if (fault < 0) + return fault; + + ret = ad8460_get_fault_threshold_en(state, fault, &en); + if (ret) + return ret; + + return en; +} + +static int ad8460_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ad8460_state *state = iio_priv(indio_dev); + + if (readval) + return regmap_read(state->regmap, reg, readval); + + return regmap_write(state->regmap, reg, writeval); +} + +static int ad8460_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad8460_state *state = iio_priv(indio_dev); + + return ad8460_enable_apg_mode(state, 0); +} + +static int ad8460_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad8460_state *state = iio_priv(indio_dev); + + return ad8460_enable_apg_mode(state, 1); +} + +static const struct iio_buffer_setup_ops ad8460_buffer_setup_ops = { + .preenable = &ad8460_buffer_preenable, + .postdisable = &ad8460_buffer_postdisable, +}; + +static const struct iio_info ad8460_info = { + .read_raw = &ad8460_read_raw, + .write_raw = &ad8460_write_raw, + .write_event_value = &ad8460_write_event_value, + .read_event_value = &ad8460_read_event_value, + .write_event_config = &ad8460_write_event_config, + .read_event_config = &ad8460_read_event_config, + .debugfs_reg_access = &ad8460_reg_access, +}; + +static const struct iio_enum ad8460_powerdown_mode_enum = { + .items = ad8460_powerdown_modes, + .num_items = ARRAY_SIZE(ad8460_powerdown_modes), + .get = ad8460_get_powerdown_mode, + .set = ad8460_set_powerdown_mode, +}; + +#define AD8460_CHAN_EXT_INFO(_name, _what, _read, _write) { \ + .name = (_name), \ + .read = (_read), \ + .write = (_write), \ + .private = (_what), \ + .shared = IIO_SEPARATE, \ +} + +static const struct iio_chan_spec_ext_info ad8460_ext_info[] = { + AD8460_CHAN_EXT_INFO("raw0", 0, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw1", 1, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw2", 2, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw3", 3, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw4", 4, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw5", 5, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw6", 6, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw7", 7, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw8", 8, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw9", 9, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw10", 10, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw11", 11, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw12", 12, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw13", 13, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw14", 14, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("raw15", 15, ad8460_dac_input_read, + ad8460_dac_input_write), + AD8460_CHAN_EXT_INFO("toggle_en", 0, ad8460_read_toggle_en, + ad8460_write_toggle_en), + AD8460_CHAN_EXT_INFO("symbol", 0, ad8460_read_symbol, + ad8460_write_symbol), + AD8460_CHAN_EXT_INFO("powerdown", 0, ad8460_read_powerdown, + ad8460_write_powerdown), + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &ad8460_powerdown_mode_enum), + IIO_ENUM_AVAILABLE("powerdown_mode", IIO_SHARED_BY_TYPE, + &ad8460_powerdown_mode_enum), + { } +}; + +static const struct iio_event_spec ad8460_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 AD8460_VOLTAGE_CHAN { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .output = 1, \ + .indexed = 1, \ + .channel = 0, \ + .scan_index = 0, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 14, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ + .ext_info = ad8460_ext_info, \ + .event_spec = ad8460_events, \ + .num_event_specs = ARRAY_SIZE(ad8460_events), \ +} + +#define AD8460_CURRENT_CHAN { \ + .type = IIO_CURRENT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .output = 1, \ + .indexed = 1, \ + .channel = 0, \ + .scan_index = -1, \ + .event_spec = ad8460_events, \ + .num_event_specs = ARRAY_SIZE(ad8460_events), \ +} + +#define AD8460_TEMP_CHAN { \ + .type = IIO_TEMP, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .indexed = 1, \ + .channel = 0, \ + .scan_index = -1, \ + .event_spec = ad8460_events, \ + .num_event_specs = 1, \ +} + +static const struct iio_chan_spec ad8460_channels[] = { + AD8460_VOLTAGE_CHAN, + AD8460_CURRENT_CHAN, +}; + +static const struct iio_chan_spec ad8460_channels_with_tmp_adc[] = { + AD8460_VOLTAGE_CHAN, + AD8460_CURRENT_CHAN, + AD8460_TEMP_CHAN, +}; + +static const struct regmap_config ad8460_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x7F, +}; + +static const char * const ad8460_supplies[] = { + "avdd_3p3v", "dvdd_3p3v", "vcc_5v", "hvcc", "hvee", "vref_5v" +}; + +static int ad8460_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct ad8460_state *state; + struct iio_dev *indio_dev; + u32 tmp[2], temp; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state)); + if (!indio_dev) + return -ENOMEM; + + state = iio_priv(indio_dev); + + indio_dev->name = "ad8460"; + indio_dev->info = &ad8460_info; + + state->spi = spi; + + state->regmap = devm_regmap_init_spi(spi, &ad8460_regmap_config); + if (IS_ERR(state->regmap)) + return dev_err_probe(dev, PTR_ERR(state->regmap), + "Failed to initialize regmap"); + + ret = devm_mutex_init(dev, &state->lock); + if (ret) + return ret; + + state->sync_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(state->sync_clk)) + return dev_err_probe(dev, PTR_ERR(state->sync_clk), + "Failed to get sync clk\n"); + + state->tmp_adc_channel = devm_iio_channel_get(dev, "ad8460-tmp"); + if (IS_ERR(state->tmp_adc_channel)) { + if (PTR_ERR(state->tmp_adc_channel) == -EPROBE_DEFER) + return -EPROBE_DEFER; + indio_dev->channels = ad8460_channels; + indio_dev->num_channels = ARRAY_SIZE(ad8460_channels); + } else { + indio_dev->channels = ad8460_channels_with_tmp_adc; + indio_dev->num_channels = ARRAY_SIZE(ad8460_channels_with_tmp_adc); + } + + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad8460_supplies), + ad8460_supplies); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable power supplies\n"); + + ret = devm_regulator_get_enable_read_voltage(dev, "refio_1p2v"); + if (ret < 0 && ret != -ENODEV) + return dev_err_probe(dev, ret, "Failed to get reference voltage\n"); + + state->refio_1p2v_mv = ret == -ENODEV ? 1200 : ret / 1000; + + if (!in_range(state->refio_1p2v_mv, AD8460_MIN_VREFIO_UV / 1000, + AD8460_MAX_VREFIO_UV / 1000)) + return dev_err_probe(dev, -EINVAL, + "Invalid ref voltage range(%u mV) [%u mV, %u mV]\n", + state->refio_1p2v_mv, + AD8460_MIN_VREFIO_UV / 1000, + AD8460_MAX_VREFIO_UV / 1000); + + ret = device_property_read_u32(dev, "adi,external-resistor-ohms", + &state->ext_resistor_ohms); + if (ret) + state->ext_resistor_ohms = 2000; + else if (!in_range(state->ext_resistor_ohms, AD8460_MIN_EXT_RESISTOR_OHMS, + AD8460_MAX_EXT_RESISTOR_OHMS)) + return dev_err_probe(dev, -EINVAL, + "Invalid resistor set range(%u) [%u, %u]\n", + state->ext_resistor_ohms, + AD8460_MIN_EXT_RESISTOR_OHMS, + AD8460_MAX_EXT_RESISTOR_OHMS); + + ret = device_property_read_u32_array(dev, "adi,range-microamp", + tmp, ARRAY_SIZE(tmp)); + if (!ret) { + if (in_range(tmp[1], 0, AD8460_ABS_MAX_OVERCURRENT_UA)) + regmap_write(state->regmap, AD8460_CTRL_REG(0x08), + FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | + AD8460_CURRENT_LIMIT_CONV(tmp[1])); + + if (in_range(tmp[0], -AD8460_ABS_MAX_OVERCURRENT_UA, 0)) + regmap_write(state->regmap, AD8460_CTRL_REG(0x09), + FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | + AD8460_CURRENT_LIMIT_CONV(abs(tmp[0]))); + } + + ret = device_property_read_u32_array(dev, "adi,range-microvolt", + tmp, ARRAY_SIZE(tmp)); + if (!ret) { + if (in_range(tmp[1], 0, AD8460_ABS_MAX_OVERVOLTAGE_UV)) + regmap_write(state->regmap, AD8460_CTRL_REG(0x0A), + FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | + AD8460_VOLTAGE_LIMIT_CONV(tmp[1])); + + if (in_range(tmp[0], -AD8460_ABS_MAX_OVERVOLTAGE_UV, 0)) + regmap_write(state->regmap, AD8460_CTRL_REG(0x0B), + FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | + AD8460_VOLTAGE_LIMIT_CONV(abs(tmp[0]))); + } + + ret = device_property_read_u32(dev, "adi,max-millicelsius", &temp); + if (!ret) { + if (in_range(temp, AD8460_MIN_OVERTEMPERATURE_MC, + AD8460_MAX_OVERTEMPERATURE_MC)) + regmap_write(state->regmap, AD8460_CTRL_REG(0x0C), + FIELD_PREP(AD8460_FAULT_ARM_MSK, 1) | + AD8460_TEMP_LIMIT_CONV(abs(temp))); + } + + ret = ad8460_reset(state); + if (ret) + return ret; + + /* Enables DAC by default */ + ret = regmap_clear_bits(state->regmap, AD8460_CTRL_REG(0x01), + AD8460_HVDAC_SLEEP_MSK); + if (ret) + return ret; + + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->setup_ops = &ad8460_buffer_setup_ops; + + ret = devm_iio_dmaengine_buffer_setup_ext(dev, indio_dev, "tx", + IIO_BUFFER_DIRECTION_OUT); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get DMA buffer\n"); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id ad8460_of_match[] = { + { .compatible = "adi,ad8460" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad8460_of_match); + +static const struct spi_device_id ad8460_spi_match[] = { + { .name = "ad8460" }, + { } +}; +MODULE_DEVICE_TABLE(spi, ad8460_spi_match); + +static struct spi_driver ad8460_driver = { + .driver = { + .name = "ad8460", + .of_match_table = ad8460_of_match, + }, + .probe = ad8460_probe, + .id_table = ad8460_spi_match, +}; +module_spi_driver(ad8460_driver); + +MODULE_AUTHOR("Mariel Tinaco "); MODULE_AUTHOR("Nuno Sa "); MODULE_DESCRIPTION("Analog Devices AD9739 DAC"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_BACKEND); +MODULE_IMPORT_NS("IIO_BACKEND"); diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 0cb00f3bec0453..b143f7ed684727 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -29,44 +29,77 @@ #include #include +#include "ad3552r-hs.h" + /* * Register definitions: * https://wiki.analog.com/resources/fpga/docs/axi_dac_ip#register_map */ /* Base controls */ -#define AXI_DAC_REG_CONFIG 0x0c -#define AXI_DDS_DISABLE BIT(6) +#define AXI_DAC_CONFIG_REG 0x0c +#define AXI_DAC_CONFIG_DDS_DISABLE BIT(6) /* DAC controls */ -#define AXI_DAC_REG_RSTN 0x0040 -#define AXI_DAC_RSTN_CE_N BIT(2) -#define AXI_DAC_RSTN_MMCM_RSTN BIT(1) -#define AXI_DAC_RSTN_RSTN BIT(0) -#define AXI_DAC_REG_CNTRL_1 0x0044 -#define AXI_DAC_SYNC BIT(0) -#define AXI_DAC_REG_CNTRL_2 0x0048 -#define ADI_DAC_R1_MODE BIT(4) -#define AXI_DAC_DRP_STATUS 0x0074 -#define AXI_DAC_DRP_LOCKED BIT(17) +#define AXI_DAC_RSTN_REG 0x0040 +#define AXI_DAC_RSTN_CE_N BIT(2) +#define AXI_DAC_RSTN_MMCM_RSTN BIT(1) +#define AXI_DAC_RSTN_RSTN BIT(0) +#define AXI_DAC_CNTRL_1_REG 0x0044 +#define AXI_DAC_CNTRL_1_SYNC BIT(0) +#define AXI_DAC_CNTRL_2_REG 0x0048 +#define AXI_DAC_CNTRL_2_SDR_DDR_N BIT(16) +#define AXI_DAC_CNTRL_2_SYMB_8B BIT(14) +#define ADI_DAC_CNTRL_2_R1_MODE BIT(5) +#define AXI_DAC_CNTRL_2_UNSIGNED_DATA BIT(4) +#define AXI_DAC_STATUS_1_REG 0x0054 +#define AXI_DAC_STATUS_2_REG 0x0058 +#define AXI_DAC_DRP_STATUS_REG 0x0074 +#define AXI_DAC_DRP_STATUS_DRP_LOCKED BIT(17) +#define AXI_DAC_CUSTOM_RD_REG 0x0080 +#define AXI_DAC_CUSTOM_WR_REG 0x0084 +#define AXI_DAC_CUSTOM_WR_DATA_8 GENMASK(23, 16) +#define AXI_DAC_CUSTOM_WR_DATA_16 GENMASK(23, 8) +#define AXI_DAC_UI_STATUS_REG 0x0088 +#define AXI_DAC_UI_STATUS_IF_BUSY BIT(4) +#define AXI_DAC_CUSTOM_CTRL_REG 0x008C +#define AXI_DAC_CUSTOM_CTRL_ADDRESS GENMASK(31, 24) +#define AXI_DAC_CUSTOM_CTRL_SYNCED_TRANSFER BIT(2) +#define AXI_DAC_CUSTOM_CTRL_STREAM BIT(1) +#define AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA BIT(0) + +#define AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE (AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA | \ + AXI_DAC_CUSTOM_CTRL_STREAM) + /* DAC Channel controls */ -#define AXI_DAC_REG_CHAN_CNTRL_1(c) (0x0400 + (c) * 0x40) -#define AXI_DAC_REG_CHAN_CNTRL_3(c) (0x0408 + (c) * 0x40) -#define AXI_DAC_SCALE_SIGN BIT(15) -#define AXI_DAC_SCALE_INT BIT(14) -#define AXI_DAC_SCALE GENMASK(14, 0) -#define AXI_DAC_REG_CHAN_CNTRL_2(c) (0x0404 + (c) * 0x40) -#define AXI_DAC_REG_CHAN_CNTRL_4(c) (0x040c + (c) * 0x40) -#define AXI_DAC_PHASE GENMASK(31, 16) -#define AXI_DAC_FREQUENCY GENMASK(15, 0) -#define AXI_DAC_REG_CHAN_CNTRL_7(c) (0x0418 + (c) * 0x40) -#define AXI_DAC_DATA_SEL GENMASK(3, 0) +#define AXI_DAC_CHAN_CNTRL_1_REG(c) (0x0400 + (c) * 0x40) +#define AXI_DAC_CHAN_CNTRL_3_REG(c) (0x0408 + (c) * 0x40) +#define AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN BIT(15) +#define AXI_DAC_CHAN_CNTRL_3_SCALE_INT BIT(14) +#define AXI_DAC_CHAN_CNTRL_3_SCALE GENMASK(14, 0) +#define AXI_DAC_CHAN_CNTRL_2_REG(c) (0x0404 + (c) * 0x40) +#define AXI_DAC_CHAN_CNTRL_2_PHASE GENMASK(31, 16) +#define AXI_DAC_CHAN_CNTRL_2_FREQUENCY GENMASK(15, 0) +#define AXI_DAC_CHAN_CNTRL_4_REG(c) (0x040c + (c) * 0x40) +#define AXI_DAC_CHAN_CNTRL_7_REG(c) (0x0418 + (c) * 0x40) +#define AXI_DAC_CHAN_CNTRL_7_DATA_SEL GENMASK(3, 0) + +#define AXI_DAC_RD_ADDR(x) (BIT(7) | (x)) /* 360 degrees in rad */ -#define AXI_DAC_2_PI_MEGA 6283190 +#define AXI_DAC_2_PI_MEGA 6283190 + enum { AXI_DAC_DATA_INTERNAL_TONE, AXI_DAC_DATA_DMA = 2, + AXI_DAC_DATA_INTERNAL_RAMP_16BIT = 11, +}; + +struct axi_dac_info { + unsigned int version; + const struct iio_backend_info *backend_info; + bool has_dac_clk; + bool has_child_nodes; }; struct axi_dac_state { @@ -77,9 +110,11 @@ struct axi_dac_state { * data/variables. */ struct mutex lock; + const struct axi_dac_info *info; u64 dac_clk; u32 reg_config; bool int_tone; + int dac_clk_rate; }; static int axi_dac_enable(struct iio_backend *back) @@ -89,7 +124,7 @@ static int axi_dac_enable(struct iio_backend *back) int ret; guard(mutex)(&st->lock); - ret = regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN, + ret = regmap_set_bits(st->regmap, AXI_DAC_RSTN_REG, AXI_DAC_RSTN_MMCM_RSTN); if (ret) return ret; @@ -98,12 +133,14 @@ static int axi_dac_enable(struct iio_backend *back) * designs really use it but if they don't we still get the lock bit * set. So let's do it all the time so the code is generic. */ - ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_DRP_STATUS, __val, - __val & AXI_DAC_DRP_LOCKED, 100, 1000); + ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_DRP_STATUS_REG, + __val, + __val & AXI_DAC_DRP_STATUS_DRP_LOCKED, + 100, 1000); if (ret) return ret; - return regmap_set_bits(st->regmap, AXI_DAC_REG_RSTN, + return regmap_set_bits(st->regmap, AXI_DAC_RSTN_REG, AXI_DAC_RSTN_RSTN | AXI_DAC_RSTN_MMCM_RSTN); } @@ -112,7 +149,7 @@ static void axi_dac_disable(struct iio_backend *back) struct axi_dac_state *st = iio_backend_get_priv(back); guard(mutex)(&st->lock); - regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0); + regmap_write(st->regmap, AXI_DAC_RSTN_REG, 0); } static struct iio_buffer *axi_dac_request_buffer(struct iio_backend *back, @@ -155,15 +192,15 @@ static int __axi_dac_frequency_get(struct axi_dac_state *st, unsigned int chan, } if (tone_2) - reg = AXI_DAC_REG_CHAN_CNTRL_4(chan); + reg = AXI_DAC_CHAN_CNTRL_4_REG(chan); else - reg = AXI_DAC_REG_CHAN_CNTRL_2(chan); + reg = AXI_DAC_CHAN_CNTRL_2_REG(chan); ret = regmap_read(st->regmap, reg, &raw); if (ret) return ret; - raw = FIELD_GET(AXI_DAC_FREQUENCY, raw); + raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_2_FREQUENCY, raw); *freq = DIV_ROUND_CLOSEST_ULL(raw * st->dac_clk, BIT(16)); return 0; @@ -194,17 +231,18 @@ static int axi_dac_scale_get(struct axi_dac_state *st, u32 reg, raw; if (tone_2) - reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel); + reg = AXI_DAC_CHAN_CNTRL_3_REG(chan->channel); else - reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel); + reg = AXI_DAC_CHAN_CNTRL_1_REG(chan->channel); ret = regmap_read(st->regmap, reg, &raw); if (ret) return ret; - sign = FIELD_GET(AXI_DAC_SCALE_SIGN, raw); - raw = FIELD_GET(AXI_DAC_SCALE, raw); - scale = DIV_ROUND_CLOSEST_ULL((u64)raw * MEGA, AXI_DAC_SCALE_INT); + sign = FIELD_GET(AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN, raw); + raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_3_SCALE, raw); + scale = DIV_ROUND_CLOSEST_ULL((u64)raw * MEGA, + AXI_DAC_CHAN_CNTRL_3_SCALE_INT); vals[0] = scale / MEGA; vals[1] = scale % MEGA; @@ -227,15 +265,15 @@ static int axi_dac_phase_get(struct axi_dac_state *st, int ret, vals[2]; if (tone_2) - reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + reg = AXI_DAC_CHAN_CNTRL_4_REG(chan->channel); else - reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + reg = AXI_DAC_CHAN_CNTRL_2_REG(chan->channel); ret = regmap_read(st->regmap, reg, &raw); if (ret) return ret; - raw = FIELD_GET(AXI_DAC_PHASE, raw); + raw = FIELD_GET(AXI_DAC_CHAN_CNTRL_2_PHASE, raw); phase = DIV_ROUND_CLOSEST_ULL((u64)raw * AXI_DAC_2_PI_MEGA, U16_MAX); vals[0] = phase / MEGA; @@ -260,18 +298,20 @@ static int __axi_dac_frequency_set(struct axi_dac_state *st, unsigned int chan, } if (tone_2) - reg = AXI_DAC_REG_CHAN_CNTRL_4(chan); + reg = AXI_DAC_CHAN_CNTRL_4_REG(chan); else - reg = AXI_DAC_REG_CHAN_CNTRL_2(chan); + reg = AXI_DAC_CHAN_CNTRL_2_REG(chan); raw = DIV64_U64_ROUND_CLOSEST((u64)freq * BIT(16), sample_rate); - ret = regmap_update_bits(st->regmap, reg, AXI_DAC_FREQUENCY, raw); + ret = regmap_update_bits(st->regmap, reg, + AXI_DAC_CHAN_CNTRL_2_FREQUENCY, raw); if (ret) return ret; /* synchronize channels */ - return regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); + return regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG, + AXI_DAC_CNTRL_1_SYNC); } static int axi_dac_frequency_set(struct axi_dac_state *st, @@ -312,16 +352,16 @@ static int axi_dac_scale_set(struct axi_dac_state *st, /* format is 1.1.14 (sign, integer and fractional bits) */ if (scale < 0) { - raw = FIELD_PREP(AXI_DAC_SCALE_SIGN, 1); + raw = FIELD_PREP(AXI_DAC_CHAN_CNTRL_3_SCALE_SIGN, 1); scale *= -1; } - raw |= div_u64((u64)scale * AXI_DAC_SCALE_INT, MEGA); + raw |= div_u64((u64)scale * AXI_DAC_CHAN_CNTRL_3_SCALE_INT, MEGA); if (tone_2) - reg = AXI_DAC_REG_CHAN_CNTRL_3(chan->channel); + reg = AXI_DAC_CHAN_CNTRL_3_REG(chan->channel); else - reg = AXI_DAC_REG_CHAN_CNTRL_1(chan->channel); + reg = AXI_DAC_CHAN_CNTRL_1_REG(chan->channel); guard(mutex)(&st->lock); ret = regmap_write(st->regmap, reg, raw); @@ -329,7 +369,8 @@ static int axi_dac_scale_set(struct axi_dac_state *st, return ret; /* synchronize channels */ - ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); + ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG, + AXI_DAC_CNTRL_1_SYNC); if (ret) return ret; @@ -355,18 +396,19 @@ static int axi_dac_phase_set(struct axi_dac_state *st, raw = DIV_ROUND_CLOSEST_ULL((u64)phase * U16_MAX, AXI_DAC_2_PI_MEGA); if (tone_2) - reg = AXI_DAC_REG_CHAN_CNTRL_4(chan->channel); + reg = AXI_DAC_CHAN_CNTRL_4_REG(chan->channel); else - reg = AXI_DAC_REG_CHAN_CNTRL_2(chan->channel); + reg = AXI_DAC_CHAN_CNTRL_2_REG(chan->channel); guard(mutex)(&st->lock); - ret = regmap_update_bits(st->regmap, reg, AXI_DAC_PHASE, - FIELD_PREP(AXI_DAC_PHASE, raw)); + ret = regmap_update_bits(st->regmap, reg, AXI_DAC_CHAN_CNTRL_2_PHASE, + FIELD_PREP(AXI_DAC_CHAN_CNTRL_2_PHASE, raw)); if (ret) return ret; /* synchronize channels */ - ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_1, AXI_DAC_SYNC); + ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_1_REG, + AXI_DAC_CNTRL_1_SYNC); if (ret) return ret; @@ -437,7 +479,7 @@ static int axi_dac_extend_chan(struct iio_backend *back, if (chan->type != IIO_ALTVOLTAGE) return -EINVAL; - if (st->reg_config & AXI_DDS_DISABLE) + if (st->reg_config & AXI_DAC_CONFIG_DDS_DISABLE) /* nothing to extend */ return 0; @@ -454,13 +496,19 @@ static int axi_dac_data_source_set(struct iio_backend *back, unsigned int chan, switch (data) { case IIO_BACKEND_INTERNAL_CONTINUOUS_WAVE: return regmap_update_bits(st->regmap, - AXI_DAC_REG_CHAN_CNTRL_7(chan), - AXI_DAC_DATA_SEL, + AXI_DAC_CHAN_CNTRL_7_REG(chan), + AXI_DAC_CHAN_CNTRL_7_DATA_SEL, AXI_DAC_DATA_INTERNAL_TONE); case IIO_BACKEND_EXTERNAL: return regmap_update_bits(st->regmap, - AXI_DAC_REG_CHAN_CNTRL_7(chan), - AXI_DAC_DATA_SEL, AXI_DAC_DATA_DMA); + AXI_DAC_CHAN_CNTRL_7_REG(chan), + AXI_DAC_CHAN_CNTRL_7_DATA_SEL, + AXI_DAC_DATA_DMA); + case IIO_BACKEND_INTERNAL_RAMP_16BIT: + return regmap_update_bits(st->regmap, + AXI_DAC_CHAN_CNTRL_7_REG(chan), + AXI_DAC_CHAN_CNTRL_7_DATA_SEL, + AXI_DAC_DATA_INTERNAL_RAMP_16BIT); default: return -EINVAL; } @@ -475,7 +523,7 @@ static int axi_dac_set_sample_rate(struct iio_backend *back, unsigned int chan, if (!sample_rate) return -EINVAL; - if (st->reg_config & AXI_DDS_DISABLE) + if (st->reg_config & AXI_DAC_CONFIG_DDS_DISABLE) /* sample_rate has no meaning if DDS is disabled */ return 0; @@ -518,6 +566,184 @@ static int axi_dac_reg_access(struct iio_backend *back, unsigned int reg, return regmap_write(st->regmap, reg, writeval); } +static int axi_dac_ddr_enable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SDR_DDR_N); +} + +static int axi_dac_ddr_disable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SDR_DDR_N); +} + +static int axi_dac_data_stream_enable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_set_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE); +} + +static int axi_dac_data_stream_disable(struct iio_backend *back) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_STREAM_ENABLE); +} + +static int axi_dac_data_transfer_addr(struct iio_backend *back, u32 address) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + if (address > FIELD_MAX(AXI_DAC_CUSTOM_CTRL_ADDRESS)) + return -EINVAL; + + /* + * Sample register address, when the DAC is configured, or stream + * start address when the FSM is in stream state. + */ + return regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_ADDRESS, + FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS, + address)); +} + +static int axi_dac_data_format_set(struct iio_backend *back, unsigned int ch, + const struct iio_backend_data_fmt *data) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + switch (data->type) { + case IIO_BACKEND_DATA_UNSIGNED: + return regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_UNSIGNED_DATA); + default: + return -EINVAL; + } +} + +static int __axi_dac_bus_reg_write(struct iio_backend *back, u32 reg, + u32 val, size_t data_size) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + int ret; + u32 ival; + + /* + * Both AXI_DAC_CNTRL_2_REG and AXI_DAC_CUSTOM_WR_REG need to know + * the data size. So keeping data size control here only, + * since data size is mandatory for the current transfer. + * DDR state handled separately by specific backend calls, + * generally all raw register writes are SDR. + */ + if (data_size == sizeof(u16)) + ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_16, val); + else + ival = FIELD_PREP(AXI_DAC_CUSTOM_WR_DATA_8, val); + + ret = regmap_write(st->regmap, AXI_DAC_CUSTOM_WR_REG, ival); + if (ret) + return ret; + + if (data_size == sizeof(u8)) + ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SYMB_8B); + else + ret = regmap_clear_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + AXI_DAC_CNTRL_2_SYMB_8B); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_ADDRESS, + FIELD_PREP(AXI_DAC_CUSTOM_CTRL_ADDRESS, reg)); + if (ret) + return ret; + + ret = regmap_update_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA); + if (ret) + return ret; + + ret = regmap_read_poll_timeout(st->regmap, + AXI_DAC_UI_STATUS_REG, ival, + FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0, + 10, 100 * KILO); + if (ret == -ETIMEDOUT) + dev_err(st->dev, "AXI read timeout\n"); + + /* Cleaning always AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA */ + return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG, + AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA); +} + +static int axi_dac_bus_reg_write(struct iio_backend *back, u32 reg, + u32 val, size_t data_size) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + + guard(mutex)(&st->lock); + return __axi_dac_bus_reg_write(back, reg, val, data_size); +} + +static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val, + size_t data_size) +{ + struct axi_dac_state *st = iio_backend_get_priv(back); + int ret; + + guard(mutex)(&st->lock); + + /* + * SPI, we write with read flag, then we read just at the AXI + * io address space to get data read. + */ + ret = __axi_dac_bus_reg_write(back, AXI_DAC_RD_ADDR(reg), 0, + data_size); + if (ret) + return ret; + + return regmap_read(st->regmap, AXI_DAC_CUSTOM_RD_REG, val); +} + +static void axi_dac_child_remove(void *data) +{ + platform_device_unregister(data); +} + +static int axi_dac_create_platform_device(struct axi_dac_state *st, + struct fwnode_handle *child) +{ + struct ad3552r_hs_platform_data pdata = { + .bus_reg_read = axi_dac_bus_reg_read, + .bus_reg_write = axi_dac_bus_reg_write, + .bus_sample_data_clock_hz = st->dac_clk_rate, + }; + struct platform_device_info pi = { + .parent = st->dev, + .name = fwnode_get_name(child), + .id = PLATFORM_DEVID_AUTO, + .fwnode = child, + .data = &pdata, + .size_data = sizeof(pdata), + }; + struct platform_device *pdev; + + pdev = platform_device_register_full(&pi); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return devm_add_action_or_reset(st->dev, axi_dac_child_remove, pdev); +} + static const struct iio_backend_ops axi_dac_generic_ops = { .enable = axi_dac_enable, .disable = axi_dac_disable, @@ -531,11 +757,30 @@ static const struct iio_backend_ops axi_dac_generic_ops = { .debugfs_reg_access = iio_backend_debugfs_ptr(axi_dac_reg_access), }; +static const struct iio_backend_ops axi_ad3552r_ops = { + .enable = axi_dac_enable, + .disable = axi_dac_disable, + .request_buffer = axi_dac_request_buffer, + .free_buffer = axi_dac_free_buffer, + .data_source_set = axi_dac_data_source_set, + .ddr_enable = axi_dac_ddr_enable, + .ddr_disable = axi_dac_ddr_disable, + .data_stream_enable = axi_dac_data_stream_enable, + .data_stream_disable = axi_dac_data_stream_disable, + .data_format_set = axi_dac_data_format_set, + .data_transfer_addr = axi_dac_data_transfer_addr, +}; + static const struct iio_backend_info axi_dac_generic = { .name = "axi-dac", .ops = &axi_dac_generic_ops, }; +static const struct iio_backend_info axi_ad3552r = { + .name = "axi-ad3552r", + .ops = &axi_ad3552r_ops, +}; + static const struct regmap_config axi_dac_regmap_config = { .val_bits = 32, .reg_bits = 32, @@ -545,7 +790,6 @@ static const struct regmap_config axi_dac_regmap_config = { static int axi_dac_probe(struct platform_device *pdev) { - const unsigned int *expected_ver; struct axi_dac_state *st; void __iomem *base; unsigned int ver; @@ -556,14 +800,29 @@ static int axi_dac_probe(struct platform_device *pdev) if (!st) return -ENOMEM; - expected_ver = device_get_match_data(&pdev->dev); - if (!expected_ver) + st->info = device_get_match_data(&pdev->dev); + if (!st->info) return -ENODEV; + clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk"); + if (IS_ERR(clk)) { + /* Backward compat., old fdt versions without clock-names. */ + clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk), + "failed to get clock\n"); + } - clk = devm_clk_get_enabled(&pdev->dev, NULL); - if (IS_ERR(clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(clk), - "failed to get clock\n"); + if (st->info->has_dac_clk) { + struct clk *dac_clk; + + dac_clk = devm_clk_get_enabled(&pdev->dev, "dac_clk"); + if (IS_ERR(dac_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dac_clk), + "failed to get dac_clk clock\n"); + + /* We only care about the streaming mode rate */ + st->dac_clk_rate = clk_get_rate(dac_clk) / 2; + } base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) @@ -580,7 +839,7 @@ static int axi_dac_probe(struct platform_device *pdev) * Force disable the core. Up to the frontend to enable us. And we can * still read/write registers... */ - ret = regmap_write(st->regmap, AXI_DAC_REG_RSTN, 0); + ret = regmap_write(st->regmap, AXI_DAC_RSTN_REG, 0); if (ret) return ret; @@ -588,12 +847,13 @@ static int axi_dac_probe(struct platform_device *pdev) if (ret) return ret; - if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(*expected_ver)) { + if (ADI_AXI_PCORE_VER_MAJOR(ver) != + ADI_AXI_PCORE_VER_MAJOR(st->info->version)) { dev_err(&pdev->dev, "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", - ADI_AXI_PCORE_VER_MAJOR(*expected_ver), - ADI_AXI_PCORE_VER_MINOR(*expected_ver), - ADI_AXI_PCORE_VER_PATCH(*expected_ver), + ADI_AXI_PCORE_VER_MAJOR(st->info->version), + ADI_AXI_PCORE_VER_MINOR(st->info->version), + ADI_AXI_PCORE_VER_PATCH(st->info->version), ADI_AXI_PCORE_VER_MAJOR(ver), ADI_AXI_PCORE_VER_MINOR(ver), ADI_AXI_PCORE_VER_PATCH(ver)); @@ -601,7 +861,7 @@ static int axi_dac_probe(struct platform_device *pdev) } /* Let's get the core read only configuration */ - ret = regmap_read(st->regmap, AXI_DAC_REG_CONFIG, &st->reg_config); + ret = regmap_read(st->regmap, AXI_DAC_CONFIG_REG, &st->reg_config); if (ret) return ret; @@ -613,16 +873,40 @@ static int axi_dac_probe(struct platform_device *pdev) * want independent channels let's override the core's default value and * set the R1_MODE bit. */ - ret = regmap_set_bits(st->regmap, AXI_DAC_REG_CNTRL_2, ADI_DAC_R1_MODE); + ret = regmap_set_bits(st->regmap, AXI_DAC_CNTRL_2_REG, + ADI_DAC_CNTRL_2_R1_MODE); if (ret) return ret; mutex_init(&st->lock); - ret = devm_iio_backend_register(&pdev->dev, &axi_dac_generic, st); + + ret = devm_iio_backend_register(&pdev->dev, st->info->backend_info, st); if (ret) return dev_err_probe(&pdev->dev, ret, "failed to register iio backend\n"); + device_for_each_child_node_scoped(&pdev->dev, child) { + int val; + + if (!st->info->has_child_nodes) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid fdt axi-dac compatible."); + + /* Processing only reg 0 node */ + ret = fwnode_property_read_u32(child, "reg", &val); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "invalid reg property."); + if (val != 0) + return dev_err_probe(&pdev->dev, -EINVAL, + "invalid node address."); + + ret = axi_dac_create_platform_device(st, child); + if (ret) + return dev_err_probe(&pdev->dev, -EINVAL, + "cannot create device."); + } + dev_info(&pdev->dev, "AXI DAC IP core (%d.%.2d.%c) probed\n", ADI_AXI_PCORE_VER_MAJOR(ver), ADI_AXI_PCORE_VER_MINOR(ver), @@ -631,10 +915,21 @@ static int axi_dac_probe(struct platform_device *pdev) return 0; } -static unsigned int axi_dac_9_1_b_info = ADI_AXI_PCORE_VER(9, 1, 'b'); +static const struct axi_dac_info dac_generic = { + .version = ADI_AXI_PCORE_VER(9, 1, 'b'), + .backend_info = &axi_dac_generic, +}; + +static const struct axi_dac_info dac_ad3552r = { + .version = ADI_AXI_PCORE_VER(9, 1, 'b'), + .backend_info = &axi_ad3552r, + .has_dac_clk = true, + .has_child_nodes = true, +}; static const struct of_device_id axi_dac_of_match[] = { - { .compatible = "adi,axi-dac-9.1.b", .data = &axi_dac_9_1_b_info }, + { .compatible = "adi,axi-dac-9.1.b", .data = &dac_generic }, + { .compatible = "adi,axi-ad3552r", .data = &dac_ad3552r }, {} }; MODULE_DEVICE_TABLE(of, axi_dac_of_match); @@ -651,5 +946,5 @@ module_platform_driver(axi_dac_driver); MODULE_AUTHOR("Nuno Sa "); MODULE_DESCRIPTION("Analog Devices Generic AXI DAC IP core driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_DMAENGINE_BUFFER); -MODULE_IMPORT_NS(IIO_BACKEND); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER"); +MODULE_IMPORT_NS("IIO_BACKEND"); diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c index 7332064d0852d9..f36f10bfb6be78 100644 --- a/drivers/iio/dac/dpot-dac.c +++ b/drivers/iio/dac/dpot-dac.c @@ -243,7 +243,7 @@ MODULE_DEVICE_TABLE(of, dpot_dac_match); static struct platform_driver dpot_dac_driver = { .probe = dpot_dac_probe, - .remove_new = dpot_dac_remove, + .remove = dpot_dac_remove, .driver = { .name = "iio-dpot-dac", .of_match_table = dpot_dac_match, diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c index b3aa4443a6a484..2332b0c2269152 100644 --- a/drivers/iio/dac/lpc18xx_dac.c +++ b/drivers/iio/dac/lpc18xx_dac.c @@ -184,9 +184,9 @@ static const struct of_device_id lpc18xx_dac_match[] = { MODULE_DEVICE_TABLE(of, lpc18xx_dac_match); static struct platform_driver lpc18xx_dac_driver = { - .probe = lpc18xx_dac_probe, - .remove_new = lpc18xx_dac_remove, - .driver = { + .probe = lpc18xx_dac_probe, + .remove = lpc18xx_dac_remove, + .driver = { .name = "lpc18xx-dac", .of_match_table = lpc18xx_dac_match, }, diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c index ae53baccec9149..3497513854d7d2 100644 --- a/drivers/iio/dac/m62332.c +++ b/drivers/iio/dac/m62332.c @@ -201,7 +201,7 @@ static int m62332_probe(struct i2c_client *client) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &m62332_info; - ret = iio_map_array_register(indio_dev, client->dev.platform_data); + ret = iio_map_array_register(indio_dev, dev_get_platdata(&client->dev)); if (ret < 0) return ret; diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index 685980184d3c82..84336736a47bdd 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -143,10 +143,10 @@ static const struct iio_chan_spec max517_channels[] = { static int max517_probe(struct i2c_client *client) { + const struct max517_platform_data *platform_data = dev_get_platdata(&client->dev); const struct i2c_device_id *id = i2c_client_get_device_id(client); struct max517_data *data; struct iio_dev *indio_dev; - struct max517_platform_data *platform_data = client->dev.platform_data; int chan; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index 2d567073996b79..95ed5197d16f56 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -245,7 +245,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); static struct platform_driver stm32_dac_driver = { .probe = stm32_dac_probe, - .remove_new = stm32_dac_remove, + .remove = stm32_dac_remove, .driver = { .name = "stm32-dac-core", .of_match_table = stm32_dac_of_match, diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index 5a722f307e7e30..3bfb368b3a2340 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -398,7 +398,7 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); static struct platform_driver stm32_dac_driver = { .probe = stm32_dac_probe, - .remove_new = stm32_dac_remove, + .remove = stm32_dac_remove, .driver = { .name = "stm32-dac", .of_match_table = stm32_dac_of_match, diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c index de73bc5a1c93c9..82a078fa98ad9a 100644 --- a/drivers/iio/dac/vf610_dac.c +++ b/drivers/iio/dac/vf610_dac.c @@ -272,7 +272,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_dac_pm_ops, vf610_dac_suspend, static struct platform_driver vf610_dac_driver = { .probe = vf610_dac_probe, - .remove_new = vf610_dac_remove, + .remove = vf610_dac_remove, .driver = { .name = "vf610-dac", .of_match_table = vf610_dac_match, diff --git a/drivers/iio/dummy/iio_simple_dummy.h b/drivers/iio/dummy/iio_simple_dummy.h index a91622ac54e06e..8246f25dbad04f 100644 --- a/drivers/iio/dummy/iio_simple_dummy.h +++ b/drivers/iio/dummy/iio_simple_dummy.h @@ -60,7 +60,7 @@ int iio_simple_dummy_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); + bool state); int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, diff --git a/drivers/iio/dummy/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c index 63a2b844be5083..b51ec21b6309a2 100644 --- a/drivers/iio/dummy/iio_simple_dummy_events.c +++ b/drivers/iio/dummy/iio_simple_dummy_events.c @@ -53,7 +53,7 @@ int iio_simple_dummy_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) + bool state) { struct iio_dummy_state *st = iio_priv(indio_dev); @@ -183,36 +183,34 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private) switch (st->regs->reg_data) { case 0: iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, 0, 0, 0), + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), st->event_timestamp); break; case 1: if (st->activity_running > st->event_val) iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_ACTIVITY, 0, - IIO_MOD_RUNNING, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, - 0, 0, 0), + IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0, + IIO_MOD_RUNNING, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), st->event_timestamp); break; case 2: if (st->activity_walking < st->event_val) iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_ACTIVITY, 0, - IIO_MOD_WALKING, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, - 0, 0, 0), + IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0, + IIO_MOD_WALKING, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), st->event_timestamp); break; case 3: iio_push_event(indio_dev, - IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD, - IIO_EV_DIR_NONE, - IIO_EV_TYPE_CHANGE, 0, 0, 0), + IIO_UNMOD_EVENT_CODE(IIO_STEPS, 0, + IIO_EV_TYPE_CHANGE, + IIO_EV_DIR_NONE), st->event_timestamp); break; default: diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index b391c6e27ab0dc..b1554ced7a26b8 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -970,7 +970,7 @@ static int ad9523_setup(struct iio_dev *indio_dev) static int ad9523_probe(struct spi_device *spi) { - struct ad9523_platform_data *pdata = spi->dev.platform_data; + struct ad9523_platform_data *pdata = dev_get_platdata(&spi->dev); struct iio_dev *indio_dev; struct ad9523_state *st; int ret; diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index e13e64a5164c14..61828e61e27589 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -603,7 +603,7 @@ static int adf4350_probe(struct spi_device *spi) if (pdata == NULL) return -EINVAL; } else { - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); } if (!pdata) { diff --git a/drivers/iio/frequency/adf4371.c b/drivers/iio/frequency/adf4371.c index b270884648265a..d752507e0c9862 100644 --- a/drivers/iio/frequency/adf4371.c +++ b/drivers/iio/frequency/adf4371.c @@ -4,6 +4,7 @@ * * Copyright 2019 Analog Devices Inc. */ +#include "linux/dev_printk.h" #include #include #include @@ -150,6 +151,7 @@ static const struct regmap_config adf4371_regmap_config = { }; struct adf4371_chip_info { + const char *name; unsigned int num_channels; const struct iio_chan_spec *channels; }; @@ -157,7 +159,6 @@ struct adf4371_chip_info { struct adf4371_state { struct spi_device *spi; struct regmap *regmap; - struct clk *clkin; /* * Lock for accessing device registers. Some operations require * multiple consecutive R/W operations, during which the device @@ -444,15 +445,16 @@ static const struct iio_chan_spec adf4371_chan[] = { ADF4371_CHANNEL(ADF4371_CH_RF32), }; -static const struct adf4371_chip_info adf4371_chip_info[] = { - [ADF4371] = { - .channels = adf4371_chan, - .num_channels = 4, - }, - [ADF4372] = { - .channels = adf4371_chan, - .num_channels = 3, - } +static const struct adf4371_chip_info adf4371_chip_info = { + .name = "adf4371", + .channels = adf4371_chan, + .num_channels = 4, +}; + +static const struct adf4371_chip_info adf4372_chip_info = { + .name = "adf4372", + .channels = adf4371_chan, + .num_channels = 3, }; static int adf4371_reg_access(struct iio_dev *indio_dev, @@ -542,10 +544,10 @@ static int adf4371_setup(struct adf4371_state *st) static int adf4371_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); struct iio_dev *indio_dev; struct adf4371_state *st; struct regmap *regmap; + struct clk *clkin; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); @@ -553,50 +555,49 @@ static int adf4371_probe(struct spi_device *spi) return -ENOMEM; regmap = devm_regmap_init_spi(spi, &adf4371_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Error initializing spi regmap: %ld\n", - PTR_ERR(regmap)); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(regmap), + "Error initializing spi regmap\n"); st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); st->spi = spi; st->regmap = regmap; mutex_init(&st->lock); - st->chip_info = &adf4371_chip_info[id->driver_data]; - indio_dev->name = id->name; + st->chip_info = spi_get_device_match_data(spi); + if (!st->chip_info) + return -ENODEV; + + indio_dev->name = st->chip_info->name; indio_dev->info = &adf4371_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; - st->clkin = devm_clk_get_enabled(&spi->dev, "clkin"); - if (IS_ERR(st->clkin)) - return PTR_ERR(st->clkin); + clkin = devm_clk_get_enabled(&spi->dev, "clkin"); + if (IS_ERR(clkin)) + return dev_err_probe(&spi->dev, PTR_ERR(clkin), + "Failed to get clkin\n"); - st->clkin_freq = clk_get_rate(st->clkin); + st->clkin_freq = clk_get_rate(clkin); ret = adf4371_setup(st); - if (ret < 0) { - dev_err(&spi->dev, "ADF4371 setup failed\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(&spi->dev, ret, "ADF4371 setup failed\n"); return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id adf4371_id_table[] = { - { "adf4371", ADF4371 }, - { "adf4372", ADF4372 }, + { "adf4371", (kernel_ulong_t)&adf4371_chip_info }, + { "adf4372", (kernel_ulong_t)&adf4372_chip_info }, {} }; MODULE_DEVICE_TABLE(spi, adf4371_id_table); static const struct of_device_id adf4371_of_match[] = { - { .compatible = "adi,adf4371" }, - { .compatible = "adi,adf4372" }, + { .compatible = "adi,adf4371", .data = &adf4371_chip_info }, + { .compatible = "adi,adf4372", .data = &adf4372_chip_info}, { }, }; MODULE_DEVICE_TABLE(of, adf4371_of_match); diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 97b86c4a53a619..3e193ee0fb6144 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -27,7 +27,7 @@ config ADIS16136 select IIO_ADIS_LIB_BUFFER if IIO_BUFFER help Say yes here to build support for the Analog Devices ADIS16133, ADIS16135, - ADIS16136 gyroscope devices. + ADIS16136, ADIS16137 gyroscope devices. config ADIS16260 tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index da83adc684d0b6..369c7428e1efed 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -583,4 +583,4 @@ module_spi_driver(adis16136_driver); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 495b64a2706172..c151fbb59ffe88 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -430,4 +430,4 @@ module_spi_driver(adis16260_driver); MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16260/5 Digital Gyroscope Sensor"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/gyro/bmg160_core.c b/drivers/iio/gyro/bmg160_core.c index 10728d5ccae398..ba877d067afb7a 100644 --- a/drivers/iio/gyro/bmg160_core.c +++ b/drivers/iio/gyro/bmg160_core.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -444,7 +443,7 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data, static int bmg160_get_bw(struct bmg160_data *data, int *val) { - struct device *dev = regmap_get_device(data->regmap); + struct device *dev = regmap_get_device(data->regmap); int i; unsigned int bw_bits; int ret; @@ -749,7 +748,7 @@ static int bmg160_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) + bool state) { struct bmg160_data *data = iio_priv(indio_dev); int ret; @@ -1055,17 +1054,6 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = { .postdisable = bmg160_buffer_postdisable, }; -static const char *bmg160_match_acpi_device(struct device *dev) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - - return dev_name(dev); -} - int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { @@ -1098,9 +1086,6 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, mutex_init(&data->mutex); - if (ACPI_HANDLE(dev)) - name = bmg160_match_acpi_device(dev); - indio_dev->channels = bmg160_channels; indio_dev->num_channels = ARRAY_SIZE(bmg160_channels); indio_dev->name = name; diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 672d0b720f610a..9c5d7e8ee99cc6 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -17,7 +17,7 @@ static int bmg160_i2c_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); struct regmap *regmap; - const char *name = NULL; + const char *name; regmap = devm_regmap_init_i2c(client, &bmg160_regmap_i2c_conf); if (IS_ERR(regmap)) { @@ -28,6 +28,8 @@ static int bmg160_i2c_probe(struct i2c_client *client) if (id) name = id->name; + else + name = iio_get_acpi_device_name(&client->dev); return bmg160_core_probe(&client->dev, regmap, client->irq, name); } @@ -39,8 +41,6 @@ static void bmg160_i2c_remove(struct i2c_client *client) static const struct acpi_device_id bmg160_acpi_match[] = { {"BMG0160", 0}, - {"BMI055B", 0}, - {"BMI088B", 0}, {}, }; diff --git a/drivers/iio/gyro/fxas21002c_core.c b/drivers/iio/gyro/fxas21002c_core.c index c28d17ca6f5ee0..0391c78c2f186f 100644 --- a/drivers/iio/gyro/fxas21002c_core.c +++ b/drivers/iio/gyro/fxas21002c_core.c @@ -849,8 +849,7 @@ static int fxas21002c_trigger_probe(struct fxas21002c_data *data) if (!data->dready_trig) return -ENOMEM; - irq_trig = irqd_get_trigger_type(irq_get_irq_data(data->irq)); - + irq_trig = irq_get_trigger_type(data->irq); if (irq_trig == IRQF_TRIGGER_RISING) { ret = regmap_field_write(data->regmap_fields[F_IPOL], 1); if (ret < 0) @@ -998,7 +997,7 @@ int fxas21002c_core_probe(struct device *dev, struct regmap *regmap, int irq, return ret; } -EXPORT_SYMBOL_NS_GPL(fxas21002c_core_probe, IIO_FXAS21002C); +EXPORT_SYMBOL_NS_GPL(fxas21002c_core_probe, "IIO_FXAS21002C"); void fxas21002c_core_remove(struct device *dev) { @@ -1009,7 +1008,7 @@ void fxas21002c_core_remove(struct device *dev) pm_runtime_disable(dev); pm_runtime_set_suspended(dev); } -EXPORT_SYMBOL_NS_GPL(fxas21002c_core_remove, IIO_FXAS21002C); +EXPORT_SYMBOL_NS_GPL(fxas21002c_core_remove, "IIO_FXAS21002C"); static int fxas21002c_suspend(struct device *dev) { diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c index b1318a1ea41bfc..43c6b30794873d 100644 --- a/drivers/iio/gyro/fxas21002c_i2c.c +++ b/drivers/iio/gyro/fxas21002c_i2c.c @@ -65,4 +65,4 @@ module_i2c_driver(fxas21002c_i2c_driver); MODULE_AUTHOR("Rui Miguel Silva "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("FXAS21002C I2C Gyro driver"); -MODULE_IMPORT_NS(IIO_FXAS21002C); +MODULE_IMPORT_NS("IIO_FXAS21002C"); diff --git a/drivers/iio/gyro/fxas21002c_spi.c b/drivers/iio/gyro/fxas21002c_spi.c index 4f633826547c20..d62efe50b69763 100644 --- a/drivers/iio/gyro/fxas21002c_spi.c +++ b/drivers/iio/gyro/fxas21002c_spi.c @@ -66,4 +66,4 @@ module_spi_driver(fxas21002c_spi_driver); MODULE_AUTHOR("Rui Miguel Silva "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("FXAS21002C SPI Gyro driver"); -MODULE_IMPORT_NS(IIO_FXAS21002C); +MODULE_IMPORT_NS("IIO_FXAS21002C"); diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index 59a38bf9459bd0..54b6f6fbdcaa12 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -27,7 +27,7 @@ struct gyro_3d_state { struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX]; struct { u32 gyro_val[GYRO_3D_CHANNEL_MAX]; - u64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -279,11 +279,11 @@ static int gyro_3d_parse_report(struct platform_device *pdev, /* Function to initialize the processing for usage id */ static int hid_gyro_3d_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret = 0; static const char *name = "gyro_3d"; struct iio_dev *indio_dev; struct gyro_3d_state *gyro_state; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state)); if (!indio_dev) @@ -361,7 +361,7 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_gyro_3d_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); @@ -386,11 +386,11 @@ static struct platform_driver hid_gyro_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_gyro_3d_probe, - .remove_new = hid_gyro_3d_remove, + .remove = hid_gyro_3d_remove, }; module_platform_driver(hid_gyro_3d_platform_driver); MODULE_DESCRIPTION("HID Sensor Gyroscope 3D"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index 35af68b41408fd..b6883e8b2a8b56 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -1059,12 +1059,12 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq) /* Check if IRQ is open drain */ mpu3050->irq_opendrain = device_property_read_bool(dev, "drive-open-drain"); - irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); /* * Configure the interrupt generator hardware to supply whatever * the interrupt is configured for, edges low/high level low/high, * we can provide it all. */ + irq_trig = irq_get_trigger_type(irq); switch (irq_trig) { case IRQF_TRIGGER_RISING: dev_info(&indio_dev->dev, diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c index d332474bc48433..d9b41cf8d79941 100644 --- a/drivers/iio/gyro/ssp_gyro_sensor.c +++ b/drivers/iio/gyro/ssp_gyro_sensor.c @@ -141,4 +141,4 @@ module_platform_driver(ssp_gyro_driver); MODULE_AUTHOR("Karol Wrona "); MODULE_DESCRIPTION("Samsung sensorhub gyroscopes driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_SSP_SENSORS); +MODULE_IMPORT_NS("IIO_SSP_SENSORS"); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index eaa35da42b332b..7fd82cd707c765 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -465,7 +465,7 @@ const struct st_sensor_settings *st_gyro_get_settings(const char *name) return &st_gyro_sensors_settings[index]; } -EXPORT_SYMBOL_NS(st_gyro_get_settings, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_gyro_get_settings, "IIO_ST_SENSORS"); int st_gyro_common_probe(struct iio_dev *indio_dev) { @@ -511,9 +511,9 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL_NS(st_gyro_common_probe, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_gyro_common_probe, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics gyroscopes driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index 5a10a3556ab054..d4b11bdba66693 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -119,4 +119,4 @@ module_i2c_driver(st_gyro_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics gyroscopes i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 22aaabe48e4a16..811f712711f5ef 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -124,4 +124,4 @@ module_spi_driver(st_gyro_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics gyroscopes spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index bf6d2636a85e7c..a40e1eb6e98c26 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -18,7 +18,7 @@ struct hid_humidity_state { struct hid_sensor_hub_attribute_info humidity_attr; struct { s32 humidity_data; - u64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -287,11 +287,11 @@ static struct platform_driver hid_humidity_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_humidity_probe, - .remove_new = hid_humidity_remove, + .remove = hid_humidity_remove, }; module_platform_driver(hid_humidity_platform_driver); MODULE_DESCRIPTION("HID Environmental humidity sensor"); MODULE_AUTHOR("Song Hongyan "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c index 11ef38994a955b..4d03db19063eae 100644 --- a/drivers/iio/humidity/hts221_buffer.c +++ b/drivers/iio/humidity/hts221_buffer.c @@ -81,8 +81,7 @@ int hts221_allocate_trigger(struct iio_dev *iio_dev) unsigned long irq_type; int err; - irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); - + irq_type = irq_get_trigger_type(hw->irq); switch (irq_type) { case IRQF_TRIGGER_HIGH: case IRQF_TRIGGER_RISING: diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c index 87627d116eff05..0be11470730c6c 100644 --- a/drivers/iio/humidity/hts221_core.c +++ b/drivers/iio/humidity/hts221_core.c @@ -649,7 +649,7 @@ int hts221_probe(struct device *dev, int irq, const char *name, return devm_iio_device_register(hw->dev, iio_dev); } -EXPORT_SYMBOL_NS(hts221_probe, IIO_HTS221); +EXPORT_SYMBOL_NS(hts221_probe, "IIO_HTS221"); static int hts221_suspend(struct device *dev) { diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index 5cb263e0ef5ac8..87a8e3c8d27727 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -73,4 +73,4 @@ module_i2c_driver(hts221_driver); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("STMicroelectronics hts221 i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_HTS221); +MODULE_IMPORT_NS("IIO_HTS221"); diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c index fc4adb68faf6cf..00154b9d66b5d5 100644 --- a/drivers/iio/humidity/hts221_spi.c +++ b/drivers/iio/humidity/hts221_spi.c @@ -66,4 +66,4 @@ module_spi_driver(hts221_driver); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("STMicroelectronics hts221 spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_HTS221); +MODULE_IMPORT_NS("IIO_HTS221"); diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c index 39e886075299ea..6402e393edb875 100644 --- a/drivers/iio/humidity/htu21.c +++ b/drivers/iio/humidity/htu21.c @@ -258,4 +258,4 @@ MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity drive MODULE_AUTHOR("William Markezana "); MODULE_AUTHOR("Ludovic Tancerel "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); +MODULE_IMPORT_NS("IIO_MEAS_SPEC_SENSORS"); diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 782fb80e44c234..ca0efecb5b5c1b 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -53,6 +53,7 @@ config ADIS16480 ADIS16485, ADIS16488 inertial sensors. source "drivers/iio/imu/bmi160/Kconfig" +source "drivers/iio/imu/bmi270/Kconfig" source "drivers/iio/imu/bmi323/Kconfig" source "drivers/iio/imu/bno055/Kconfig" @@ -96,6 +97,20 @@ config KMX61 source "drivers/iio/imu/inv_icm42600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" + +config SMI240 + tristate "Bosch Sensor SMI240 Inertial Measurement Unit" + depends on SPI + select REGMAP_SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for SMI240 IMU on SPI with + accelerometer and gyroscope. + + This driver can also be built as a module. If so, the module will be + called smi240. + source "drivers/iio/imu/st_lsm6dsx/Kconfig" source "drivers/iio/imu/st_lsm9ds0/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 7e2d7d5c3b7bc7..04c77c2c4df8c2 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -15,6 +15,7 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o obj-y += bmi160/ +obj-y += bmi270/ obj-y += bmi323/ obj-y += bno055/ @@ -27,5 +28,7 @@ obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o +obj-$(CONFIG_SMI240) += smi240.o + obj-y += st_lsm6dsx/ obj-y += st_lsm9ds0/ diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index 99410733c1ca74..49417184481276 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -115,7 +115,7 @@ int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value, return ret; } -EXPORT_SYMBOL_NS_GPL(__adis_write_reg, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(__adis_write_reg, "IIO_ADISLIB"); /** * __adis_read_reg() - read N bytes from register (unlocked version) @@ -206,7 +206,7 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val, return ret; } -EXPORT_SYMBOL_NS_GPL(__adis_read_reg, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(__adis_read_reg, "IIO_ADISLIB"); /** * __adis_update_bits_base() - ADIS Update bits function - Unlocked version * @adis: The adis device @@ -231,7 +231,7 @@ int __adis_update_bits_base(struct adis *adis, unsigned int reg, const u32 mask, return __adis_write_reg(adis, reg, __val, size); } -EXPORT_SYMBOL_NS_GPL(__adis_update_bits_base, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(__adis_update_bits_base, "IIO_ADISLIB"); #ifdef CONFIG_DEBUG_FS @@ -253,7 +253,7 @@ int adis_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg, return adis_write_reg_16(adis, reg, writeval); } -EXPORT_SYMBOL_NS(adis_debugfs_reg_access, IIO_ADISLIB); +EXPORT_SYMBOL_NS(adis_debugfs_reg_access, "IIO_ADISLIB"); #endif @@ -294,7 +294,7 @@ int __adis_enable_irq(struct adis *adis, bool enable) return __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc); } -EXPORT_SYMBOL_NS(__adis_enable_irq, IIO_ADISLIB); +EXPORT_SYMBOL_NS(__adis_enable_irq, "IIO_ADISLIB"); /** * __adis_check_status() - Check the device for error conditions (unlocked) @@ -326,7 +326,7 @@ int __adis_check_status(struct adis *adis) return -EIO; } -EXPORT_SYMBOL_NS_GPL(__adis_check_status, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(__adis_check_status, "IIO_ADISLIB"); /** * __adis_reset() - Reset the device (unlocked version) @@ -350,7 +350,7 @@ int __adis_reset(struct adis *adis) return 0; } -EXPORT_SYMBOL_NS_GPL(__adis_reset, IIO_ADIS_LIB); +EXPORT_SYMBOL_NS_GPL(__adis_reset, "IIO_ADIS_LIB"); static int adis_self_test(struct adis *adis) { @@ -441,7 +441,7 @@ int __adis_initial_startup(struct adis *adis) return 0; } -EXPORT_SYMBOL_NS_GPL(__adis_initial_startup, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(__adis_initial_startup, "IIO_ADISLIB"); /** * adis_single_conversion() - Performs a single sample conversion @@ -486,7 +486,7 @@ int adis_single_conversion(struct iio_dev *indio_dev, return IIO_VAL_INT; } -EXPORT_SYMBOL_NS_GPL(adis_single_conversion, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(adis_single_conversion, "IIO_ADISLIB"); /** * adis_init() - Initialize adis device structure @@ -529,7 +529,7 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_NS_GPL(adis_init, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(adis_init, "IIO_ADISLIB"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Lars-Peter Clausen "); diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 6484ab8aff5519..3086dd53620382 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -1228,4 +1228,4 @@ module_spi_driver(adis16400_driver); MODULE_AUTHOR("Manuel Stahl "); MODULE_DESCRIPTION("Analog Devices ADIS16400/5 IMU SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index eaa38dd6201fdb..ecf74046fde1f8 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -418,4 +418,4 @@ module_spi_driver(adis16460_driver); MODULE_AUTHOR("Dragos Bogdan "); MODULE_DESCRIPTION("Analog Devices ADIS16460 IMU driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index 88efe728b61bfe..df8c6cd911694a 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -2107,4 +2107,4 @@ module_spi_driver(adis16475_driver); MODULE_AUTHOR("Nuno Sa "); MODULE_DESCRIPTION("Analog Devices ADIS16475 IMU driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 294181f2fcb314..0a5d13d2240eee 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -1794,4 +1794,4 @@ module_spi_driver(adis16480_driver); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index b7c1cc04492a8e..fdfc0538734c5e 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -124,7 +124,7 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, "IIO_ADISLIB"); static int adis_paging_trigger_handler(struct adis *adis) { @@ -222,4 +222,4 @@ devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis, struct iio_dev return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup, adis); } -EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger_with_attrs, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger_with_attrs, "IIO_ADISLIB"); diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index a8740b043cfe55..d76e13cbac6803 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -102,5 +102,5 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) return devm_iio_trigger_register(&adis->spi->dev, adis->trig); } -EXPORT_SYMBOL_NS_GPL(devm_adis_probe_trigger, IIO_ADISLIB); +EXPORT_SYMBOL_NS_GPL(devm_adis_probe_trigger, "IIO_ADISLIB"); diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 495e8a74ac676e..0423ef6f9571e5 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -149,7 +149,7 @@ const struct regmap_config bmi160_regmap_config = { .reg_bits = 8, .val_bits = 8, }; -EXPORT_SYMBOL_NS(bmi160_regmap_config, IIO_BMI160); +EXPORT_SYMBOL_NS(bmi160_regmap_config, "IIO_BMI160"); struct bmi160_regs { u8 data; /* LSB byte register for X-axis */ @@ -638,7 +638,7 @@ int bmi160_enable_irq(struct regmap *regmap, bool enable) BMI160_DRDY_INT_EN, enable_bit, BMI160_NORMAL_WRITE_USLEEP); } -EXPORT_SYMBOL_NS(bmi160_enable_irq, IIO_BMI160); +EXPORT_SYMBOL_NS(bmi160_enable_irq, "IIO_BMI160"); static int bmi160_get_irq(struct fwnode_handle *fwnode, enum bmi160_int_pin *pin) { @@ -690,18 +690,9 @@ static int bmi160_config_device_irq(struct iio_dev *indio_dev, int irq_type, static int bmi160_setup_irq(struct iio_dev *indio_dev, int irq, enum bmi160_int_pin pin) { - struct irq_data *desc; - u32 irq_type; + u32 irq_type = irq_get_trigger_type(irq); int ret; - desc = irq_get_irq_data(irq); - if (!desc) { - dev_err(&indio_dev->dev, "Could not find IRQ %d\n", irq); - return -EINVAL; - } - - irq_type = irqd_get_trigger_type(desc); - ret = bmi160_config_device_irq(indio_dev, irq_type, pin); if (ret) return ret; @@ -897,7 +888,7 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(bmi160_core_probe, IIO_BMI160); +EXPORT_SYMBOL_NS_GPL(bmi160_core_probe, "IIO_BMI160"); MODULE_AUTHOR("Daniel Baluta "); MODULE_DESCRIPTION("Bosch BMI160 driver"); diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 3aa5d748f9b682..214503fa4af56e 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -80,4 +80,4 @@ module_i2c_driver(bmi160_i2c_driver); MODULE_AUTHOR("Daniel Baluta "); MODULE_DESCRIPTION("BMI160 I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_BMI160); +MODULE_IMPORT_NS("IIO_BMI160"); diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index 9f40500132f7be..8fbaab22db8123 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -68,4 +68,4 @@ module_spi_driver(bmi160_spi_driver); MODULE_AUTHOR("Daniel Baluta +#include + +struct device; +struct bmi270_data { + struct device *dev; + struct regmap *regmap; + const struct bmi270_chip_info *chip_info; + + /* + * Where IIO_DMA_MINALIGN may be larger than 8 bytes, align to + * that to ensure a DMA safe buffer. + */ + struct { + __le16 channels[6]; + aligned_s64 timestamp; + } data __aligned(IIO_DMA_MINALIGN); +}; + +struct bmi270_chip_info { + const char *name; + int chip_id; + const char *fw_name; +}; + +extern const struct regmap_config bmi270_regmap_config; +extern const struct bmi270_chip_info bmi260_chip_info; +extern const struct bmi270_chip_info bmi270_chip_info; + +int bmi270_core_probe(struct device *dev, struct regmap *regmap, + const struct bmi270_chip_info *chip_info); + +#endif /* BMI270_H_ */ diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c new file mode 100644 index 00000000000000..7fec52e0b48624 --- /dev/null +++ b/drivers/iio/imu/bmi270/bmi270_core.c @@ -0,0 +1,734 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "bmi270.h" + +#define BMI270_CHIP_ID_REG 0x00 + +/* Checked to prevent sending incompatible firmware to BMI160 devices */ +#define BMI160_CHIP_ID_VAL 0xD1 + +#define BMI260_CHIP_ID_VAL 0x27 +#define BMI270_CHIP_ID_VAL 0x24 +#define BMI270_CHIP_ID_MSK GENMASK(7, 0) + +#define BMI270_ACCEL_X_REG 0x0c +#define BMI270_ANG_VEL_X_REG 0x12 + +#define BMI270_INTERNAL_STATUS_REG 0x21 +#define BMI270_INTERNAL_STATUS_MSG_MSK GENMASK(3, 0) +#define BMI270_INTERNAL_STATUS_MSG_INIT_OK 0x01 + +#define BMI270_INTERNAL_STATUS_AXES_REMAP_ERR_MSK BIT(5) +#define BMI270_INTERNAL_STATUS_ODR_50HZ_ERR_MSK BIT(6) + +#define BMI270_ACC_CONF_REG 0x40 +#define BMI270_ACC_CONF_ODR_MSK GENMASK(3, 0) +#define BMI270_ACC_CONF_ODR_100HZ 0x08 +#define BMI270_ACC_CONF_BWP_MSK GENMASK(6, 4) +#define BMI270_ACC_CONF_BWP_NORMAL_MODE 0x02 +#define BMI270_ACC_CONF_FILTER_PERF_MSK BIT(7) + +#define BMI270_ACC_CONF_RANGE_REG 0x41 +#define BMI270_ACC_CONF_RANGE_MSK GENMASK(1, 0) + +#define BMI270_GYR_CONF_REG 0x42 +#define BMI270_GYR_CONF_ODR_MSK GENMASK(3, 0) +#define BMI270_GYR_CONF_ODR_200HZ 0x09 +#define BMI270_GYR_CONF_BWP_MSK GENMASK(5, 4) +#define BMI270_GYR_CONF_BWP_NORMAL_MODE 0x02 +#define BMI270_GYR_CONF_NOISE_PERF_MSK BIT(6) +#define BMI270_GYR_CONF_FILTER_PERF_MSK BIT(7) + +#define BMI270_GYR_CONF_RANGE_REG 0x43 +#define BMI270_GYR_CONF_RANGE_MSK GENMASK(2, 0) + +#define BMI270_INIT_CTRL_REG 0x59 +#define BMI270_INIT_CTRL_LOAD_DONE_MSK BIT(0) + +#define BMI270_INIT_DATA_REG 0x5e + +#define BMI270_PWR_CONF_REG 0x7c +#define BMI270_PWR_CONF_ADV_PWR_SAVE_MSK BIT(0) +#define BMI270_PWR_CONF_FIFO_WKUP_MSK BIT(1) +#define BMI270_PWR_CONF_FUP_EN_MSK BIT(2) + +#define BMI270_PWR_CTRL_REG 0x7d +#define BMI270_PWR_CTRL_AUX_EN_MSK BIT(0) +#define BMI270_PWR_CTRL_GYR_EN_MSK BIT(1) +#define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2) +#define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3) + +#define BMI260_INIT_DATA_FILE "bmi260-init-data.fw" +#define BMI270_INIT_DATA_FILE "bmi270-init-data.fw" + +enum bmi270_scan { + BMI270_SCAN_ACCEL_X, + BMI270_SCAN_ACCEL_Y, + BMI270_SCAN_ACCEL_Z, + BMI270_SCAN_GYRO_X, + BMI270_SCAN_GYRO_Y, + BMI270_SCAN_GYRO_Z, + BMI270_SCAN_TIMESTAMP, +}; + +static const unsigned long bmi270_avail_scan_masks[] = { + (BIT(BMI270_SCAN_ACCEL_X) | + BIT(BMI270_SCAN_ACCEL_Y) | + BIT(BMI270_SCAN_ACCEL_Z) | + BIT(BMI270_SCAN_GYRO_X) | + BIT(BMI270_SCAN_GYRO_Y) | + BIT(BMI270_SCAN_GYRO_Z)), + 0 +}; + +const struct bmi270_chip_info bmi260_chip_info = { + .name = "bmi260", + .chip_id = BMI260_CHIP_ID_VAL, + .fw_name = BMI260_INIT_DATA_FILE, +}; +EXPORT_SYMBOL_NS_GPL(bmi260_chip_info, "IIO_BMI270"); + +const struct bmi270_chip_info bmi270_chip_info = { + .name = "bmi270", + .chip_id = BMI270_CHIP_ID_VAL, + .fw_name = BMI270_INIT_DATA_FILE, +}; +EXPORT_SYMBOL_NS_GPL(bmi270_chip_info, "IIO_BMI270"); + +enum bmi270_sensor_type { + BMI270_ACCEL = 0, + BMI270_GYRO, +}; + +struct bmi270_scale { + int scale; + int uscale; +}; + +struct bmi270_odr { + int odr; + int uodr; +}; + +static const struct bmi270_scale bmi270_accel_scale[] = { + { 0, 598 }, + { 0, 1197 }, + { 0, 2394 }, + { 0, 4788 }, +}; + +static const struct bmi270_scale bmi270_gyro_scale[] = { + { 0, 1065 }, + { 0, 532 }, + { 0, 266 }, + { 0, 133 }, + { 0, 66 }, +}; + +struct bmi270_scale_item { + const struct bmi270_scale *tbl; + int num; +}; + +static const struct bmi270_scale_item bmi270_scale_table[] = { + [BMI270_ACCEL] = { + .tbl = bmi270_accel_scale, + .num = ARRAY_SIZE(bmi270_accel_scale), + }, + [BMI270_GYRO] = { + .tbl = bmi270_gyro_scale, + .num = ARRAY_SIZE(bmi270_gyro_scale), + }, +}; + +static const struct bmi270_odr bmi270_accel_odr[] = { + { 0, 781250 }, + { 1, 562500 }, + { 3, 125000 }, + { 6, 250000 }, + { 12, 500000 }, + { 25, 0 }, + { 50, 0 }, + { 100, 0 }, + { 200, 0 }, + { 400, 0 }, + { 800, 0 }, + { 1600, 0 }, +}; + +static const u8 bmi270_accel_odr_vals[] = { + 0x01, + 0x02, + 0x03, + 0x04, + 0x05, + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, +}; + +static const struct bmi270_odr bmi270_gyro_odr[] = { + { 25, 0 }, + { 50, 0 }, + { 100, 0 }, + { 200, 0 }, + { 400, 0 }, + { 800, 0 }, + { 1600, 0 }, + { 3200, 0 }, +}; + +static const u8 bmi270_gyro_odr_vals[] = { + 0x06, + 0x07, + 0x08, + 0x09, + 0x0A, + 0x0B, + 0x0C, + 0x0D, +}; + +struct bmi270_odr_item { + const struct bmi270_odr *tbl; + const u8 *vals; + int num; +}; + +static const struct bmi270_odr_item bmi270_odr_table[] = { + [BMI270_ACCEL] = { + .tbl = bmi270_accel_odr, + .vals = bmi270_accel_odr_vals, + .num = ARRAY_SIZE(bmi270_accel_odr), + }, + [BMI270_GYRO] = { + .tbl = bmi270_gyro_odr, + .vals = bmi270_gyro_odr_vals, + .num = ARRAY_SIZE(bmi270_gyro_odr), + }, +}; + +static int bmi270_set_scale(struct bmi270_data *data, int chan_type, int uscale) +{ + int i; + int reg, mask; + struct bmi270_scale_item bmi270_scale_item; + + switch (chan_type) { + case IIO_ACCEL: + reg = BMI270_ACC_CONF_RANGE_REG; + mask = BMI270_ACC_CONF_RANGE_MSK; + bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL]; + break; + case IIO_ANGL_VEL: + reg = BMI270_GYR_CONF_RANGE_REG; + mask = BMI270_GYR_CONF_RANGE_MSK; + bmi270_scale_item = bmi270_scale_table[BMI270_GYRO]; + break; + default: + return -EINVAL; + } + + for (i = 0; i < bmi270_scale_item.num; i++) { + if (bmi270_scale_item.tbl[i].uscale != uscale) + continue; + + return regmap_update_bits(data->regmap, reg, mask, i); + } + + return -EINVAL; +} + +static int bmi270_get_scale(struct bmi270_data *bmi270_device, int chan_type, + int *uscale) +{ + int ret; + unsigned int val; + struct bmi270_scale_item bmi270_scale_item; + + switch (chan_type) { + case IIO_ACCEL: + ret = regmap_read(bmi270_device->regmap, + BMI270_ACC_CONF_RANGE_REG, &val); + if (ret) + return ret; + + val = FIELD_GET(BMI270_ACC_CONF_RANGE_MSK, val); + bmi270_scale_item = bmi270_scale_table[BMI270_ACCEL]; + break; + case IIO_ANGL_VEL: + ret = regmap_read(bmi270_device->regmap, + BMI270_GYR_CONF_RANGE_REG, &val); + if (ret) + return ret; + + val = FIELD_GET(BMI270_GYR_CONF_RANGE_MSK, val); + bmi270_scale_item = bmi270_scale_table[BMI270_GYRO]; + break; + default: + return -EINVAL; + } + + if (val >= bmi270_scale_item.num) + return -EINVAL; + + *uscale = bmi270_scale_item.tbl[val].uscale; + return 0; +} + +static int bmi270_set_odr(struct bmi270_data *data, int chan_type, int odr, + int uodr) +{ + int i; + int reg, mask; + struct bmi270_odr_item bmi270_odr_item; + + switch (chan_type) { + case IIO_ACCEL: + reg = BMI270_ACC_CONF_REG; + mask = BMI270_ACC_CONF_ODR_MSK; + bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL]; + break; + case IIO_ANGL_VEL: + reg = BMI270_GYR_CONF_REG; + mask = BMI270_GYR_CONF_ODR_MSK; + bmi270_odr_item = bmi270_odr_table[BMI270_GYRO]; + break; + default: + return -EINVAL; + } + + for (i = 0; i < bmi270_odr_item.num; i++) { + if (bmi270_odr_item.tbl[i].odr != odr || + bmi270_odr_item.tbl[i].uodr != uodr) + continue; + + return regmap_update_bits(data->regmap, reg, mask, + bmi270_odr_item.vals[i]); + } + + return -EINVAL; +} + +static int bmi270_get_odr(struct bmi270_data *data, int chan_type, int *odr, + int *uodr) +{ + int i, val, ret; + struct bmi270_odr_item bmi270_odr_item; + + switch (chan_type) { + case IIO_ACCEL: + ret = regmap_read(data->regmap, BMI270_ACC_CONF_REG, &val); + if (ret) + return ret; + + val = FIELD_GET(BMI270_ACC_CONF_ODR_MSK, val); + bmi270_odr_item = bmi270_odr_table[BMI270_ACCEL]; + break; + case IIO_ANGL_VEL: + ret = regmap_read(data->regmap, BMI270_GYR_CONF_REG, &val); + if (ret) + return ret; + + val = FIELD_GET(BMI270_GYR_CONF_ODR_MSK, val); + bmi270_odr_item = bmi270_odr_table[BMI270_GYRO]; + break; + default: + return -EINVAL; + } + + for (i = 0; i < bmi270_odr_item.num; i++) { + if (val != bmi270_odr_item.vals[i]) + continue; + + *odr = bmi270_odr_item.tbl[i].odr; + *uodr = bmi270_odr_item.tbl[i].uodr; + return 0; + } + + return -EINVAL; +} + +static irqreturn_t bmi270_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bmi270_data *bmi270_device = iio_priv(indio_dev); + int ret; + + ret = regmap_bulk_read(bmi270_device->regmap, BMI270_ACCEL_X_REG, + &bmi270_device->data.channels, + sizeof(bmi270_device->data.channels)); + + if (ret) + goto done; + + iio_push_to_buffers_with_timestamp(indio_dev, &bmi270_device->data, + pf->timestamp); +done: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int bmi270_get_data(struct bmi270_data *bmi270_device, + int chan_type, int axis, int *val) +{ + __le16 sample; + int reg; + int ret; + + switch (chan_type) { + case IIO_ACCEL: + reg = BMI270_ACCEL_X_REG + (axis - IIO_MOD_X) * 2; + break; + case IIO_ANGL_VEL: + reg = BMI270_ANG_VEL_X_REG + (axis - IIO_MOD_X) * 2; + break; + default: + return -EINVAL; + } + + ret = regmap_bulk_read(bmi270_device->regmap, reg, &sample, sizeof(sample)); + if (ret) + return ret; + + *val = sign_extend32(le16_to_cpu(sample), 15); + + return 0; +} + +static int bmi270_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + struct bmi270_data *bmi270_device = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = bmi270_get_data(bmi270_device, chan->type, chan->channel2, val); + if (ret) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + ret = bmi270_get_scale(bmi270_device, chan->type, val2); + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = bmi270_get_odr(bmi270_device, chan->type, val, val2); + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int bmi270_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bmi270_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return bmi270_set_scale(data, chan->type, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return bmi270_set_odr(data, chan->type, val, val2); + default: + return -EINVAL; + } +} + +static int bmi270_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT_PLUS_MICRO; + switch (chan->type) { + case IIO_ANGL_VEL: + *vals = (const int *)bmi270_gyro_scale; + *length = ARRAY_SIZE(bmi270_gyro_scale) * 2; + return IIO_AVAIL_LIST; + case IIO_ACCEL: + *vals = (const int *)bmi270_accel_scale; + *length = ARRAY_SIZE(bmi270_accel_scale) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + *type = IIO_VAL_INT_PLUS_MICRO; + switch (chan->type) { + case IIO_ANGL_VEL: + *vals = (const int *)bmi270_gyro_odr; + *length = ARRAY_SIZE(bmi270_gyro_odr) * 2; + return IIO_AVAIL_LIST; + case IIO_ACCEL: + *vals = (const int *)bmi270_accel_odr; + *length = ARRAY_SIZE(bmi270_accel_odr) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static const struct iio_info bmi270_info = { + .read_raw = bmi270_read_raw, + .write_raw = bmi270_write_raw, + .read_avail = bmi270_read_avail, +}; + +#define BMI270_ACCEL_CHANNEL(_axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = BMI270_SCAN_ACCEL_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ +} + +#define BMI270_ANG_VEL_CHANNEL(_axis) { \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = BMI270_SCAN_GYRO_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ +} + +static const struct iio_chan_spec bmi270_channels[] = { + BMI270_ACCEL_CHANNEL(X), + BMI270_ACCEL_CHANNEL(Y), + BMI270_ACCEL_CHANNEL(Z), + BMI270_ANG_VEL_CHANNEL(X), + BMI270_ANG_VEL_CHANNEL(Y), + BMI270_ANG_VEL_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(BMI270_SCAN_TIMESTAMP), +}; + +static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device) +{ + int chip_id; + int ret; + struct device *dev = bmi270_device->dev; + struct regmap *regmap = bmi270_device->regmap; + + ret = regmap_read(regmap, BMI270_CHIP_ID_REG, &chip_id); + if (ret) + return dev_err_probe(dev, ret, "Failed to read chip id"); + + /* + * Some manufacturers use "BMI0160" for both the BMI160 and + * BMI260. If the device is actually a BMI160, the bmi160 + * driver should handle it and this driver should not. + */ + if (chip_id == BMI160_CHIP_ID_VAL) + return -ENODEV; + + if (chip_id != bmi270_device->chip_info->chip_id) + dev_info(dev, "Unexpected chip id 0x%x", chip_id); + + if (chip_id == bmi260_chip_info.chip_id) + bmi270_device->chip_info = &bmi260_chip_info; + else if (chip_id == bmi270_chip_info.chip_id) + bmi270_device->chip_info = &bmi270_chip_info; + + return 0; +} + +static int bmi270_write_calibration_data(struct bmi270_data *bmi270_device) +{ + int ret; + int status = 0; + const struct firmware *init_data; + struct device *dev = bmi270_device->dev; + struct regmap *regmap = bmi270_device->regmap; + + ret = regmap_clear_bits(regmap, BMI270_PWR_CONF_REG, + BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); + if (ret) + return dev_err_probe(dev, ret, + "Failed to write power configuration"); + + /* + * After disabling advanced power save, all registers are accessible + * after a 450us delay. This delay is specified in table A of the + * datasheet. + */ + usleep_range(450, 1000); + + ret = regmap_clear_bits(regmap, BMI270_INIT_CTRL_REG, + BMI270_INIT_CTRL_LOAD_DONE_MSK); + if (ret) + return dev_err_probe(dev, ret, + "Failed to prepare device to load init data"); + + ret = request_firmware(&init_data, + bmi270_device->chip_info->fw_name, dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to load init data file"); + + ret = regmap_bulk_write(regmap, BMI270_INIT_DATA_REG, + init_data->data, init_data->size); + release_firmware(init_data); + if (ret) + return dev_err_probe(dev, ret, "Failed to write init data"); + + ret = regmap_set_bits(regmap, BMI270_INIT_CTRL_REG, + BMI270_INIT_CTRL_LOAD_DONE_MSK); + if (ret) + return dev_err_probe(dev, ret, + "Failed to stop device initialization"); + + /* + * Wait at least 140ms for the device to complete configuration. + * This delay is specified in table C of the datasheet. + */ + usleep_range(140000, 160000); + + ret = regmap_read(regmap, BMI270_INTERNAL_STATUS_REG, &status); + if (ret) + return dev_err_probe(dev, ret, "Failed to read internal status"); + + if (status != BMI270_INTERNAL_STATUS_MSG_INIT_OK) + return dev_err_probe(dev, -ENODEV, "Device failed to initialize"); + + return 0; +} + +static int bmi270_configure_imu(struct bmi270_data *bmi270_device) +{ + int ret; + struct device *dev = bmi270_device->dev; + struct regmap *regmap = bmi270_device->regmap; + + ret = regmap_set_bits(regmap, BMI270_PWR_CTRL_REG, + BMI270_PWR_CTRL_AUX_EN_MSK | + BMI270_PWR_CTRL_GYR_EN_MSK | + BMI270_PWR_CTRL_ACCEL_EN_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable accelerometer and gyroscope"); + + ret = regmap_set_bits(regmap, BMI270_ACC_CONF_REG, + FIELD_PREP(BMI270_ACC_CONF_ODR_MSK, + BMI270_ACC_CONF_ODR_100HZ) | + FIELD_PREP(BMI270_ACC_CONF_BWP_MSK, + BMI270_ACC_CONF_BWP_NORMAL_MODE) | + BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to configure accelerometer"); + + ret = regmap_set_bits(regmap, BMI270_GYR_CONF_REG, + FIELD_PREP(BMI270_GYR_CONF_ODR_MSK, + BMI270_GYR_CONF_ODR_200HZ) | + FIELD_PREP(BMI270_GYR_CONF_BWP_MSK, + BMI270_GYR_CONF_BWP_NORMAL_MODE) | + BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to configure gyroscope"); + + /* Enable FIFO_WKUP, Disable ADV_PWR_SAVE and FUP_EN */ + ret = regmap_write(regmap, BMI270_PWR_CONF_REG, + BMI270_PWR_CONF_FIFO_WKUP_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to set power configuration"); + + return 0; +} + +static int bmi270_chip_init(struct bmi270_data *bmi270_device) +{ + int ret; + + ret = bmi270_validate_chip_id(bmi270_device); + if (ret) + return ret; + + ret = bmi270_write_calibration_data(bmi270_device); + if (ret) + return ret; + + return bmi270_configure_imu(bmi270_device); +} + +int bmi270_core_probe(struct device *dev, struct regmap *regmap, + const struct bmi270_chip_info *chip_info) +{ + int ret; + struct bmi270_data *bmi270_device; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*bmi270_device)); + if (!indio_dev) + return -ENOMEM; + + bmi270_device = iio_priv(indio_dev); + bmi270_device->dev = dev; + bmi270_device->regmap = regmap; + bmi270_device->chip_info = chip_info; + + ret = bmi270_chip_init(bmi270_device); + if (ret) + return ret; + + indio_dev->channels = bmi270_channels; + indio_dev->num_channels = ARRAY_SIZE(bmi270_channels); + indio_dev->name = chip_info->name; + indio_dev->available_scan_masks = bmi270_avail_scan_masks; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &bmi270_info; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + bmi270_trigger_handler, NULL); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(bmi270_core_probe, "IIO_BMI270"); + +MODULE_AUTHOR("Alex Lanzano"); +MODULE_DESCRIPTION("BMI270 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c new file mode 100644 index 00000000000000..44699ab589097e --- /dev/null +++ b/drivers/iio/imu/bmi270/bmi270_i2c.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +#include +#include +#include +#include +#include + +#include "bmi270.h" + +static const struct regmap_config bmi270_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int bmi270_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + struct device *dev = &client->dev; + const struct bmi270_chip_info *chip_info; + + chip_info = i2c_get_match_data(client); + if (!chip_info) + return -ENODEV; + + regmap = devm_regmap_init_i2c(client, &bmi270_i2c_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to init i2c regmap"); + + return bmi270_core_probe(dev, regmap, chip_info); +} + +static const struct i2c_device_id bmi270_i2c_id[] = { + { "bmi260", (kernel_ulong_t)&bmi260_chip_info }, + { "bmi270", (kernel_ulong_t)&bmi270_chip_info }, + { } +}; + +static const struct acpi_device_id bmi270_acpi_match[] = { + /* GPD Win Mini, Aya Neo AIR Pro, OXP Mini Pro, etc. */ + { "BMI0160", (kernel_ulong_t)&bmi260_chip_info }, + { } +}; + +static const struct of_device_id bmi270_of_match[] = { + { .compatible = "bosch,bmi260", .data = &bmi260_chip_info }, + { .compatible = "bosch,bmi270", .data = &bmi270_chip_info }, + { } +}; + +static struct i2c_driver bmi270_i2c_driver = { + .driver = { + .name = "bmi270_i2c", + .acpi_match_table = bmi270_acpi_match, + .of_match_table = bmi270_of_match, + }, + .probe = bmi270_i2c_probe, + .id_table = bmi270_i2c_id, +}; +module_i2c_driver(bmi270_i2c_driver); + +MODULE_AUTHOR("Alex Lanzano"); +MODULE_DESCRIPTION("BMI270 driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_BMI270"); diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c new file mode 100644 index 00000000000000..88a77aba5e4f7d --- /dev/null +++ b/drivers/iio/imu/bmi270/bmi270_spi.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +#include +#include +#include +#include +#include + +#include "bmi270.h" + +/* + * The following two functions are taken from the BMI323 spi driver code. + * In section 6.4 of the BMI270 data it specifies that after a read + * operation the first data byte from the device is a dummy byte + */ +static int bmi270_regmap_spi_read(void *spi, const void *reg_buf, + size_t reg_size, void *val_buf, + size_t val_size) +{ + return spi_write_then_read(spi, reg_buf, reg_size, val_buf, val_size); +} + +static int bmi270_regmap_spi_write(void *spi, const void *data, + size_t count) +{ + u8 *data_buff = (u8 *)data; + + /* + * Remove the extra pad byte since its only needed for the read + * operation + */ + data_buff[1] = data_buff[0]; + return spi_write_then_read(spi, data_buff + 1, count - 1, NULL, 0); +} + +static const struct regmap_bus bmi270_regmap_bus = { + .read = bmi270_regmap_spi_read, + .write = bmi270_regmap_spi_write, +}; + +static const struct regmap_config bmi270_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .pad_bits = 8, + .read_flag_mask = BIT(7), +}; + +static int bmi270_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + struct device *dev = &spi->dev; + const struct bmi270_chip_info *chip_info; + + chip_info = spi_get_device_match_data(spi); + if (!chip_info) + return -ENODEV; + + regmap = devm_regmap_init(dev, &bmi270_regmap_bus, dev, + &bmi270_spi_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to init i2c regmap"); + + return bmi270_core_probe(dev, regmap, chip_info); +} + +static const struct spi_device_id bmi270_spi_id[] = { + { "bmi260", (kernel_ulong_t)&bmi260_chip_info }, + { "bmi270", (kernel_ulong_t)&bmi270_chip_info }, + { } +}; + +static const struct of_device_id bmi270_of_match[] = { + { .compatible = "bosch,bmi260", .data = &bmi260_chip_info }, + { .compatible = "bosch,bmi270", .data = &bmi270_chip_info }, + { } +}; + +static struct spi_driver bmi270_spi_driver = { + .driver = { + .name = "bmi270", + .of_match_table = bmi270_of_match, + }, + .probe = bmi270_spi_probe, + .id_table = bmi270_spi_id, +}; +module_spi_driver(bmi270_spi_driver); + +MODULE_AUTHOR("Alex Lanzano"); +MODULE_DESCRIPTION("BMI270 driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_BMI270"); diff --git a/drivers/iio/imu/bmi323/bmi323.h b/drivers/iio/imu/bmi323/bmi323.h index 209bccb1f335cf..b4cfe92600a4fe 100644 --- a/drivers/iio/imu/bmi323/bmi323.h +++ b/drivers/iio/imu/bmi323/bmi323.h @@ -141,7 +141,6 @@ #define BMI323_STEP_SC1_REG 0x10 #define BMI323_STEP_SC1_WTRMRK_MSK GENMASK(9, 0) #define BMI323_STEP_SC1_RST_CNT_MSK BIT(10) -#define BMI323_STEP_SC1_REG 0x10 #define BMI323_STEP_LEN 2 /* Tap gesture config registers */ diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c index e1f3b0d778be03..f7d7f4442e65f5 100644 --- a/drivers/iio/imu/bmi323/bmi323_core.c +++ b/drivers/iio/imu/bmi323/bmi323_core.c @@ -467,7 +467,7 @@ static int bmi323_feature_engine_events(struct bmi323_data *data, BMI323_FEAT_IO_STATUS_MSK); } -static int bmi323_step_wtrmrk_en(struct bmi323_data *data, int state) +static int bmi323_step_wtrmrk_en(struct bmi323_data *data, bool state) { enum bmi323_irq_pin step_irq; int ret; @@ -484,7 +484,7 @@ static int bmi323_step_wtrmrk_en(struct bmi323_data *data, int state) ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, BMI323_STEP_SC1_WTRMRK_MSK, FIELD_PREP(BMI323_STEP_SC1_WTRMRK_MSK, - state ? 1 : 0)); + state)); if (ret) return ret; @@ -506,7 +506,7 @@ static int bmi323_motion_config_reg(enum iio_event_direction dir) } static int bmi323_motion_event_en(struct bmi323_data *data, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { unsigned int state_value = state ? BMI323_FEAT_XYZ_MSK : 0; int config, ret, msk, raw, field_value; @@ -570,7 +570,7 @@ static int bmi323_motion_event_en(struct bmi323_data *data, } static int bmi323_tap_event_en(struct bmi323_data *data, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { enum bmi323_irq_pin tap_irq; int ret, tap_enabled; @@ -785,7 +785,7 @@ static const struct attribute_group bmi323_event_attribute_group = { static int bmi323_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) + enum iio_event_direction dir, bool state) { struct bmi323_data *data = iio_priv(indio_dev); @@ -1881,7 +1881,6 @@ static int bmi323_trigger_probe(struct bmi323_data *data, struct fwnode_handle *fwnode; enum bmi323_irq_pin irq_pin; int ret, irq, irq_type; - struct irq_data *desc; fwnode = dev_fwnode(data->dev); if (!fwnode) @@ -1898,12 +1897,7 @@ static int bmi323_trigger_probe(struct bmi323_data *data, irq_pin = BMI323_IRQ_INT2; } - desc = irq_get_irq_data(irq); - if (!desc) - return dev_err_probe(data->dev, -EINVAL, - "Could not find IRQ %d\n", irq); - - irq_type = irqd_get_trigger_type(desc); + irq_type = irq_get_trigger_type(irq); switch (irq_type) { case IRQF_TRIGGER_RISING: latch = false; @@ -2170,7 +2164,7 @@ int bmi323_core_probe(struct device *dev) return bmi323_fifo_disable(data); } -EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, IIO_BMI323); +EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, "IIO_BMI323"); static int bmi323_core_runtime_suspend(struct device *dev) { @@ -2298,7 +2292,7 @@ const struct dev_pm_ops bmi323_core_pm_ops = { RUNTIME_PM_OPS(bmi323_core_runtime_suspend, bmi323_core_runtime_resume, NULL) }; -EXPORT_SYMBOL_NS_GPL(bmi323_core_pm_ops, IIO_BMI323); +EXPORT_SYMBOL_NS_GPL(bmi323_core_pm_ops, "IIO_BMI323"); MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); MODULE_AUTHOR("Jagath Jog J "); diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c index 0ba5d69d8329ae..8457fe304db849 100644 --- a/drivers/iio/imu/bmi323/bmi323_i2c.c +++ b/drivers/iio/imu/bmi323/bmi323_i2c.c @@ -140,4 +140,4 @@ module_i2c_driver(bmi323_i2c_driver); MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); MODULE_AUTHOR("Jagath Jog J "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_BMI323); +MODULE_IMPORT_NS("IIO_BMI323"); diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c index 9de3ade78d714d..fd56ab6207500d 100644 --- a/drivers/iio/imu/bmi323/bmi323_spi.c +++ b/drivers/iio/imu/bmi323/bmi323_spi.c @@ -90,4 +90,4 @@ module_spi_driver(bmi323_spi_driver); MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); MODULE_AUTHOR("Jagath Jog J "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_BMI323); +MODULE_IMPORT_NS("IIO_BMI323"); diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c index ea6519b22b2f34..0728d38260a1c9 100644 --- a/drivers/iio/imu/bno055/bno055.c +++ b/drivers/iio/imu/bno055/bno055.c @@ -292,7 +292,7 @@ const struct regmap_config bno055_regmap_config = { .readable_reg = bno055_regmap_readable, .cache_type = REGCACHE_RBTREE, }; -EXPORT_SYMBOL_NS_GPL(bno055_regmap_config, IIO_BNO055); +EXPORT_SYMBOL_NS_GPL(bno055_regmap_config, "IIO_BNO055"); /* must be called in configuration mode */ static int bno055_calibration_load(struct bno055_priv *priv, const u8 *data, int len) @@ -1678,7 +1678,7 @@ int bno055_probe(struct device *dev, struct regmap *regmap, return 0; } -EXPORT_SYMBOL_NS_GPL(bno055_probe, IIO_BNO055); +EXPORT_SYMBOL_NS_GPL(bno055_probe, "IIO_BNO055"); MODULE_AUTHOR("Andrea Merello "); MODULE_DESCRIPTION("Bosch BNO055 driver"); diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c index cf3dd62a83ba8a..f49d0905ee3384 100644 --- a/drivers/iio/imu/bno055/bno055_i2c.c +++ b/drivers/iio/imu/bno055/bno055_i2c.c @@ -53,5 +53,5 @@ module_i2c_driver(bno055_driver); MODULE_AUTHOR("Andrea Merello"); MODULE_DESCRIPTION("Bosch BNO055 I2C interface"); -MODULE_IMPORT_NS(IIO_BNO055); +MODULE_IMPORT_NS("IIO_BNO055"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/bno055/bno055_ser_core.c b/drivers/iio/imu/bno055/bno055_ser_core.c index da7873bfd34875..48669dabb37ba8 100644 --- a/drivers/iio/imu/bno055/bno055_ser_core.c +++ b/drivers/iio/imu/bno055/bno055_ser_core.c @@ -556,5 +556,5 @@ module_serdev_device_driver(bno055_ser_driver); MODULE_AUTHOR("Andrea Merello "); MODULE_DESCRIPTION("Bosch BNO055 serdev interface"); -MODULE_IMPORT_NS(IIO_BNO055); +MODULE_IMPORT_NS("IIO_BNO055"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/fxos8700_core.c b/drivers/iio/imu/fxos8700_core.c index 6d189c4b9ff962..281ebfd9c15a85 100644 --- a/drivers/iio/imu/fxos8700_core.c +++ b/drivers/iio/imu/fxos8700_core.c @@ -8,7 +8,6 @@ */ #include #include -#include #include #include diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 56ac198142500a..7968aa27f9fd79 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -200,7 +200,6 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); - struct inv_sensors_timestamp *ts = &accel_st->ts; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int fifo_en = 0; unsigned int sleep_temp = 0; @@ -229,7 +228,6 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, } /* update data FIFO write */ - inv_sensors_timestamp_apply_odr(ts, 0, 0, 0); ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en); out_unlock: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index c3924cc6190ee4..561d245c1d6446 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -85,7 +85,7 @@ const struct regmap_config inv_icm42600_regmap_config = { .rd_noinc_table = inv_icm42600_regmap_rd_noinc_accesses, .cache_type = REGCACHE_RBTREE, }; -EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, IIO_ICM42600); +EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, "IIO_ICM42600"); struct inv_icm42600_hw { uint8_t whoami; @@ -673,7 +673,6 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, { struct device *dev = regmap_get_device(regmap); struct inv_icm42600_state *st; - struct irq_data *irq_desc; int irq_type; bool open_drain; int ret; @@ -683,14 +682,7 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, return -ENODEV; } - /* get irq properties, set trigger falling by default */ - irq_desc = irq_get_irq_data(irq); - if (!irq_desc) { - dev_err(dev, "could not find IRQ %d\n", irq); - return -EINVAL; - } - - irq_type = irqd_get_trigger_type(irq_desc); + irq_type = irq_get_trigger_type(irq); if (!irq_type) irq_type = IRQF_TRIGGER_FALLING; @@ -773,7 +765,7 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev); } -EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, IIO_ICM42600); +EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, "IIO_ICM42600"); /* * Suspend saves sensors state and turns everything off. @@ -896,4 +888,4 @@ EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42600_pm_ops, IIO_ICM42600) = { MODULE_AUTHOR("InvenSense, Inc."); MODULE_DESCRIPTION("InvenSense ICM-426xx device driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_INV_SENSORS_TIMESTAMP); +MODULE_IMPORT_NS("IIO_INV_SENSORS_TIMESTAMP"); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 938af5b640b00f..c6bb68bf5e1449 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -99,8 +99,6 @@ static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); - struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev); - struct inv_sensors_timestamp *ts = &gyro_st->ts; struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int fifo_en = 0; unsigned int sleep_gyro = 0; @@ -128,7 +126,6 @@ static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev, } /* update data FIFO write */ - inv_sensors_timestamp_apply_odr(ts, 0, 0, 0); ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en); out_unlock: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index ebb31b385881e1..04e440fe023aa3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -71,6 +71,22 @@ static int inv_icm42600_probe(struct i2c_client *client) inv_icm42600_i2c_bus_setup); } +/* + * device id table is used to identify what device can be + * supported by this driver + */ +static const struct i2c_device_id inv_icm42600_id[] = { + { "icm42600", INV_CHIP_ICM42600 }, + { "icm42602", INV_CHIP_ICM42602 }, + { "icm42605", INV_CHIP_ICM42605 }, + { "icm42686", INV_CHIP_ICM42686 }, + { "icm42622", INV_CHIP_ICM42622 }, + { "icm42688", INV_CHIP_ICM42688 }, + { "icm42631", INV_CHIP_ICM42631 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, inv_icm42600_id); + static const struct of_device_id inv_icm42600_of_matches[] = { { .compatible = "invensense,icm42600", @@ -104,6 +120,7 @@ static struct i2c_driver inv_icm42600_driver = { .of_match_table = inv_icm42600_of_matches, .pm = pm_ptr(&inv_icm42600_pm_ops), }, + .id_table = inv_icm42600_id, .probe = inv_icm42600_probe, }; module_i2c_driver(inv_icm42600_driver); @@ -111,4 +128,4 @@ module_i2c_driver(inv_icm42600_driver); MODULE_AUTHOR("InvenSense, Inc."); MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ICM42600); +MODULE_IMPORT_NS("IIO_ICM42600"); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index eae5ff7a3cc102..c55d8e672183dd 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -67,6 +67,22 @@ static int inv_icm42600_probe(struct spi_device *spi) inv_icm42600_spi_bus_setup); } +/* + * device id table is used to identify what device can be + * supported by this driver + */ +static const struct spi_device_id inv_icm42600_id[] = { + { "icm42600", INV_CHIP_ICM42600 }, + { "icm42602", INV_CHIP_ICM42602 }, + { "icm42605", INV_CHIP_ICM42605 }, + { "icm42686", INV_CHIP_ICM42686 }, + { "icm42622", INV_CHIP_ICM42622 }, + { "icm42688", INV_CHIP_ICM42688 }, + { "icm42631", INV_CHIP_ICM42631 }, + { } +}; +MODULE_DEVICE_TABLE(spi, inv_icm42600_id); + static const struct of_device_id inv_icm42600_of_matches[] = { { .compatible = "invensense,icm42600", @@ -100,6 +116,7 @@ static struct spi_driver inv_icm42600_driver = { .of_match_table = inv_icm42600_of_matches, .pm = pm_ptr(&inv_icm42600_pm_ops), }, + .id_table = inv_icm42600_id, .probe = inv_icm42600_probe, }; module_spi_driver(inv_icm42600_driver); @@ -107,4 +124,4 @@ module_spi_driver(inv_icm42600_driver); MODULE_AUTHOR("InvenSense, Inc."); MODULE_DESCRIPTION("InvenSense ICM-426xx SPI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_ICM42600); +MODULE_IMPORT_NS("IIO_ICM42600"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c index f7bce428d9eb45..373e59f6d91a5b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -10,6 +10,8 @@ #include #include #include +#include + #include "inv_mpu_iio.h" enum inv_mpu_product_name { @@ -102,14 +104,11 @@ static int inv_mpu_process_acpi_config(struct i2c_client *client, unsigned short *secondary_addr) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); - const struct acpi_device_id *id; u32 i2c_addr = 0; LIST_HEAD(resources); int ret; - id = acpi_match_device(client->dev.driver->acpi_match_table, - &client->dev); - if (!id) + if (!is_acpi_device_node(dev_fwnode(&client->dev))) return -ENODEV; ret = acpi_dev_get_resources(adev, &resources, @@ -118,8 +117,8 @@ static int inv_mpu_process_acpi_config(struct i2c_client *client, return ret; acpi_dev_free_resource_list(&resources); - *primary_addr = i2c_addr & 0x0000ffff; - *secondary_addr = (i2c_addr & 0xffff0000) >> 16; + *primary_addr = lower_16_bits(i2c_addr); + *secondary_addr = upper_16_bits(i2c_addr); return 0; } diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 14d95f34e981c8..844b611b825a96 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -286,6 +286,24 @@ static const struct inv_mpu6050_hw hw_info[] = { .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, }, + { + .whoami = INV_IAM20680HP_WHOAMI_VALUE, + .name = "IAM20680HP", + .reg = ®_set_6500, + .config = &chip_config_6500, + .fifo_size = 4 * 1024, + .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, + }, + { + .whoami = INV_IAM20680HT_WHOAMI_VALUE, + .name = "IAM20680HT", + .reg = ®_set_6500, + .config = &chip_config_6500, + .fifo_size = 4 * 1024, + .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, + .startup_time = {INV_MPU6500_GYRO_STARTUP_TIME, INV_MPU6500_ACCEL_STARTUP_TIME}, + }, }; static int inv_mpu6050_pwr_mgmt_1_write(struct inv_mpu6050_state *st, bool sleep, @@ -510,6 +528,8 @@ static int inv_mpu6050_set_accel_lpf_regs(struct inv_mpu6050_state *st, return 0; case INV_ICM20689: case INV_ICM20690: + case INV_IAM20680HT: + case INV_IAM20680HP: /* set FIFO size to maximum value */ val |= INV_ICM20689_BITS_FIFO_SIZE_MAX; break; @@ -1153,24 +1173,21 @@ static int inv_mpu6050_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) + bool state) { struct inv_mpu6050_state *st = iio_priv(indio_dev); - int enable; /* support only WoM (accel roc rising) event */ if (chan->type != IIO_ACCEL || type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) return -EINVAL; - enable = !!state; - guard(mutex)(&st->lock); - if (st->chip_config.wom_en == enable) + if (st->chip_config.wom_en == state) return 0; - return inv_mpu6050_enable_wom(st, enable); + return inv_mpu6050_enable_wom(st, state); } static int inv_mpu6050_read_event_value(struct iio_dev *indio_dev, @@ -1859,7 +1876,6 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, struct inv_mpu6050_platform_data *pdata; struct device *dev = regmap_get_device(regmap); int result; - struct irq_data *desc; int irq_type; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); @@ -1893,13 +1909,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, } if (irq > 0) { - desc = irq_get_irq_data(irq); - if (!desc) { - dev_err(dev, "Could not find IRQ %d\n", irq); - return -EINVAL; - } - - irq_type = irqd_get_trigger_type(desc); + irq_type = irq_get_trigger_type(irq); if (!irq_type) irq_type = IRQF_TRIGGER_RISING; } else { @@ -2082,7 +2092,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, inv_mpu6050_set_power_itg(st, false); return result; } -EXPORT_SYMBOL_NS_GPL(inv_mpu_core_probe, IIO_MPU6050); +EXPORT_SYMBOL_NS_GPL(inv_mpu_core_probe, "IIO_MPU6050"); static int inv_mpu_resume(struct device *dev) { @@ -2233,4 +2243,4 @@ EXPORT_NS_GPL_DEV_PM_OPS(inv_mpu_pmops, IIO_MPU6050) = { MODULE_AUTHOR("Invensense Corporation"); MODULE_DESCRIPTION("Invensense device MPU6050 driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_INV_SENSORS_TIMESTAMP); +MODULE_IMPORT_NS("IIO_INV_SENSORS_TIMESTAMP"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 0e03137fb3d40d..307a06f4df2e2f 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -188,6 +188,8 @@ static const struct i2c_device_id inv_mpu_id[] = { {"icm20602", INV_ICM20602}, {"icm20690", INV_ICM20690}, {"iam20680", INV_IAM20680}, + {"iam20680hp", INV_IAM20680HP}, + {"iam20680ht", INV_IAM20680HT}, {} }; @@ -254,6 +256,14 @@ static const struct of_device_id inv_of_match[] = { .compatible = "invensense,iam20680", .data = (void *)INV_IAM20680 }, + { + .compatible = "invensense,iam20680hp", + .data = (void *)INV_IAM20680HP + }, + { + .compatible = "invensense,iam20680ht", + .data = (void *)INV_IAM20680HT + }, { } }; MODULE_DEVICE_TABLE(of, inv_of_match); @@ -281,4 +291,4 @@ module_i2c_driver(inv_mpu_driver); MODULE_AUTHOR("Invensense Corporation"); MODULE_DESCRIPTION("Invensense device MPU6050 driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_MPU6050); +MODULE_IMPORT_NS("IIO_MPU6050"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index e1c0c51468761a..a6862cf426396c 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -85,6 +85,8 @@ enum inv_devices { INV_ICM20602, INV_ICM20690, INV_IAM20680, + INV_IAM20680HP, + INV_IAM20680HT, INV_NUM_PARTS }; @@ -424,6 +426,8 @@ struct inv_mpu6050_state { #define INV_ICM20602_WHOAMI_VALUE 0x12 #define INV_ICM20690_WHOAMI_VALUE 0x20 #define INV_IAM20680_WHOAMI_VALUE 0xA9 +#define INV_IAM20680HP_WHOAMI_VALUE 0xF8 +#define INV_IAM20680HT_WHOAMI_VALUE 0xFA /* scan element definition for generic MPU6xxx devices */ enum inv_mpu6050_scan { diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 05451ca1580b63..ab415874d69948 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -80,6 +80,8 @@ static const struct spi_device_id inv_mpu_id[] = { {"icm20602", INV_ICM20602}, {"icm20690", INV_ICM20690}, {"iam20680", INV_IAM20680}, + {"iam20680hp", INV_IAM20680HP}, + {"iam20680ht", INV_IAM20680HT}, {} }; @@ -142,6 +144,14 @@ static const struct of_device_id inv_of_match[] = { .compatible = "invensense,iam20680", .data = (void *)INV_IAM20680 }, + { + .compatible = "invensense,iam20680hp", + .data = (void *)INV_IAM20680HP + }, + { + .compatible = "invensense,iam20680ht", + .data = (void *)INV_IAM20680HT + }, { } }; MODULE_DEVICE_TABLE(of, inv_of_match); @@ -168,4 +178,4 @@ module_spi_driver(inv_mpu_driver); MODULE_AUTHOR("Adriana Reus "); MODULE_DESCRIPTION("Invensense device MPU6000 driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_MPU6050); +MODULE_IMPORT_NS("IIO_MPU6050"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index 3bfeabab0ec4f6..5b1088cc3704f1 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -112,7 +112,6 @@ int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable) if (enable) { /* reset timestamping */ inv_sensors_timestamp_reset(&st->timestamp); - inv_sensors_timestamp_apply_odr(&st->timestamp, 0, 0, 0); /* reset FIFO */ d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_RST; ret = regmap_write(st->map, st->reg->user_ctrl, d); diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index c61c012e25bbaa..324c38764656ad 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -7,12 +7,13 @@ * IIO driver for KMX61 (7-bit I2C slave address 0x0E or 0x0F). */ -#include #include -#include #include +#include +#include #include #include + #include #include #include @@ -941,7 +942,7 @@ static int kmx61_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) + bool state) { struct kmx61_data *data = kmx61_get_data(indio_dev); int ret = 0; @@ -1217,16 +1218,6 @@ static irqreturn_t kmx61_trigger_handler(int irq, void *p) return IRQ_HANDLED; } -static const char *kmx61_match_acpi_device(struct device *dev) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - return dev_name(dev); -} - static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data, const struct iio_info *info, const struct iio_chan_spec *chan, @@ -1293,8 +1284,6 @@ static int kmx61_probe(struct i2c_client *client) if (id) name = id->name; - else if (ACPI_HANDLE(&client->dev)) - name = kmx61_match_acpi_device(&client->dev); else return -ENODEV; @@ -1496,13 +1485,6 @@ static const struct dev_pm_ops kmx61_pm_ops = { RUNTIME_PM_OPS(kmx61_runtime_suspend, kmx61_runtime_resume, NULL) }; -static const struct acpi_device_id kmx61_acpi_match[] = { - {"KMX61021", 0}, - {} -}; - -MODULE_DEVICE_TABLE(acpi, kmx61_acpi_match); - static const struct i2c_device_id kmx61_id[] = { { "kmx611021" }, {} @@ -1513,7 +1495,6 @@ MODULE_DEVICE_TABLE(i2c, kmx61_id); static struct i2c_driver kmx61_driver = { .driver = { .name = KMX61_DRV_NAME, - .acpi_match_table = kmx61_acpi_match, .pm = pm_ptr(&kmx61_pm_ops), }, .probe = kmx61_probe, diff --git a/drivers/iio/imu/smi240.c b/drivers/iio/imu/smi240.c new file mode 100644 index 00000000000000..4492c4d013bd6a --- /dev/null +++ b/drivers/iio/imu/smi240.c @@ -0,0 +1,621 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* + * Copyright (c) 2024 Robert Bosch GmbH. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define SMI240_CHIP_ID 0x0024 + +#define SMI240_SOFT_CONFIG_EOC_MASK BIT(0) +#define SMI240_SOFT_CONFIG_GYR_BW_MASK BIT(1) +#define SMI240_SOFT_CONFIG_ACC_BW_MASK BIT(2) +#define SMI240_SOFT_CONFIG_BITE_AUTO_MASK BIT(3) +#define SMI240_SOFT_CONFIG_BITE_REP_MASK GENMASK(6, 4) + +#define SMI240_CHIP_ID_REG 0x00 +#define SMI240_SOFT_CONFIG_REG 0x0A +#define SMI240_TEMP_CUR_REG 0x10 +#define SMI240_ACCEL_X_CUR_REG 0x11 +#define SMI240_GYRO_X_CUR_REG 0x14 +#define SMI240_DATA_CAP_FIRST_REG 0x17 +#define SMI240_CMD_REG 0x2F + +#define SMI240_SOFT_RESET_CMD 0xB6 + +#define SMI240_BITE_SEQUENCE_DELAY_US 140000 +#define SMI240_FILTER_FLUSH_DELAY_US 60000 +#define SMI240_DIGITAL_STARTUP_DELAY_US 120000 +#define SMI240_MECH_STARTUP_DELAY_US 100000 + +#define SMI240_BUS_ID 0x00 +#define SMI240_CRC_INIT 0x05 +#define SMI240_CRC_POLY 0x0B +#define SMI240_CRC_MASK GENMASK(2, 0) + +#define SMI240_READ_SD_BIT_MASK BIT(31) +#define SMI240_READ_DATA_MASK GENMASK(19, 4) +#define SMI240_READ_CS_BIT_MASK BIT(3) + +#define SMI240_WRITE_BUS_ID_MASK GENMASK(31, 30) +#define SMI240_WRITE_ADDR_MASK GENMASK(29, 22) +#define SMI240_WRITE_BIT_MASK BIT(21) +#define SMI240_WRITE_CAP_BIT_MASK BIT(20) +#define SMI240_WRITE_DATA_MASK GENMASK(18, 3) + +/* T°C = (temp / 256) + 25 */ +#define SMI240_TEMP_OFFSET 6400 /* 25 * 256 */ +#define SMI240_TEMP_SCALE 3906250 /* (1 / 256) * 1e9 */ + +#define SMI240_ACCEL_SCALE 500 /* (1 / 2000) * 1e6 */ +#define SMI240_GYRO_SCALE 10000 /* (1 / 100) * 1e6 */ + +#define SMI240_LOW_BANDWIDTH_HZ 50 +#define SMI240_HIGH_BANDWIDTH_HZ 400 + +#define SMI240_BUILT_IN_SELF_TEST_COUNT 3 + +#define SMI240_DATA_CHANNEL(_type, _axis, _index) { \ + .type = _type, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +#define SMI240_TEMP_CHANNEL(_index) { \ + .type = IIO_TEMP, \ + .modified = 1, \ + .channel2 = IIO_MOD_TEMP_OBJECT, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ +} + +enum capture_mode { SMI240_CAPTURE_OFF = 0, SMI240_CAPTURE_ON = 1 }; + +struct smi240_data { + struct regmap *regmap; + u16 accel_filter_freq; + u16 anglvel_filter_freq; + u8 built_in_self_test_count; + enum capture_mode capture; + /* + * Ensure natural alignment for timestamp if present. + * Channel size: 2 bytes. + * Max length needed: 2 * 3 channels + temp channel + 2 bytes padding + 8 byte ts. + * If fewer channels are enabled, less space may be needed, as + * long as the timestamp is still aligned to 8 bytes. + */ + s16 buf[12] __aligned(8); + + __be32 spi_buf __aligned(IIO_DMA_MINALIGN); +}; + +enum { + SMI240_TEMP_OBJECT, + SMI240_SCAN_ACCEL_X, + SMI240_SCAN_ACCEL_Y, + SMI240_SCAN_ACCEL_Z, + SMI240_SCAN_GYRO_X, + SMI240_SCAN_GYRO_Y, + SMI240_SCAN_GYRO_Z, + SMI240_SCAN_TIMESTAMP, +}; + +static const struct iio_chan_spec smi240_channels[] = { + SMI240_TEMP_CHANNEL(SMI240_TEMP_OBJECT), + SMI240_DATA_CHANNEL(IIO_ACCEL, X, SMI240_SCAN_ACCEL_X), + SMI240_DATA_CHANNEL(IIO_ACCEL, Y, SMI240_SCAN_ACCEL_Y), + SMI240_DATA_CHANNEL(IIO_ACCEL, Z, SMI240_SCAN_ACCEL_Z), + SMI240_DATA_CHANNEL(IIO_ANGL_VEL, X, SMI240_SCAN_GYRO_X), + SMI240_DATA_CHANNEL(IIO_ANGL_VEL, Y, SMI240_SCAN_GYRO_Y), + SMI240_DATA_CHANNEL(IIO_ANGL_VEL, Z, SMI240_SCAN_GYRO_Z), + IIO_CHAN_SOFT_TIMESTAMP(SMI240_SCAN_TIMESTAMP), +}; + +static const int smi240_low_pass_freqs[] = { SMI240_LOW_BANDWIDTH_HZ, + SMI240_HIGH_BANDWIDTH_HZ }; + +static u8 smi240_crc3(u32 data, u8 init, u8 poly) +{ + u8 crc = init; + u8 do_xor; + s8 i = 31; + + do { + do_xor = crc & 0x04; + crc <<= 1; + crc |= 0x01 & (data >> i); + if (do_xor) + crc ^= poly; + + crc &= SMI240_CRC_MASK; + } while (--i >= 0); + + return crc; +} + +static bool smi240_sensor_data_is_valid(u32 data) +{ + if (smi240_crc3(data, SMI240_CRC_INIT, SMI240_CRC_POLY) != 0) + return false; + + if (FIELD_GET(SMI240_READ_SD_BIT_MASK, data) & + FIELD_GET(SMI240_READ_CS_BIT_MASK, data)) + return false; + + return true; +} + +static int smi240_regmap_spi_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, + size_t val_size) +{ + int ret; + u32 request, response; + u16 *val = val_buf; + struct spi_device *spi = context; + struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); + struct smi240_data *iio_priv_data = iio_priv(indio_dev); + + if (reg_size != 1 || val_size != 2) + return -EINVAL; + + request = FIELD_PREP(SMI240_WRITE_BUS_ID_MASK, SMI240_BUS_ID); + request |= FIELD_PREP(SMI240_WRITE_CAP_BIT_MASK, iio_priv_data->capture); + request |= FIELD_PREP(SMI240_WRITE_ADDR_MASK, *(u8 *)reg_buf); + request |= smi240_crc3(request, SMI240_CRC_INIT, SMI240_CRC_POLY); + + iio_priv_data->spi_buf = cpu_to_be32(request); + + /* + * SMI240 module consists of a 32Bit Out Of Frame (OOF) + * SPI protocol, where the slave interface responds to + * the Master request in the next frame. + * CS signal must toggle (> 700 ns) between the frames. + */ + ret = spi_write(spi, &iio_priv_data->spi_buf, sizeof(request)); + if (ret) + return ret; + + ret = spi_read(spi, &iio_priv_data->spi_buf, sizeof(response)); + if (ret) + return ret; + + response = be32_to_cpu(iio_priv_data->spi_buf); + + if (!smi240_sensor_data_is_valid(response)) + return -EIO; + + *val = FIELD_GET(SMI240_READ_DATA_MASK, response); + + return 0; +} + +static int smi240_regmap_spi_write(void *context, const void *data, + size_t count) +{ + u8 reg_addr; + u16 reg_data; + u32 request; + const u8 *data_ptr = data; + struct spi_device *spi = context; + struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); + struct smi240_data *iio_priv_data = iio_priv(indio_dev); + + if (count < 2) + return -EINVAL; + + reg_addr = data_ptr[0]; + memcpy(®_data, &data_ptr[1], sizeof(reg_data)); + + request = FIELD_PREP(SMI240_WRITE_BUS_ID_MASK, SMI240_BUS_ID); + request |= FIELD_PREP(SMI240_WRITE_BIT_MASK, 1); + request |= FIELD_PREP(SMI240_WRITE_ADDR_MASK, reg_addr); + request |= FIELD_PREP(SMI240_WRITE_DATA_MASK, reg_data); + request |= smi240_crc3(request, SMI240_CRC_INIT, SMI240_CRC_POLY); + + iio_priv_data->spi_buf = cpu_to_be32(request); + + return spi_write(spi, &iio_priv_data->spi_buf, sizeof(request)); +} + +static const struct regmap_bus smi240_regmap_bus = { + .read = smi240_regmap_spi_read, + .write = smi240_regmap_spi_write, +}; + +static const struct regmap_config smi240_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .val_format_endian = REGMAP_ENDIAN_NATIVE, +}; + +static int smi240_soft_reset(struct smi240_data *data) +{ + int ret; + + ret = regmap_write(data->regmap, SMI240_CMD_REG, SMI240_SOFT_RESET_CMD); + if (ret) + return ret; + fsleep(SMI240_DIGITAL_STARTUP_DELAY_US); + + return 0; +} + +static int smi240_soft_config(struct smi240_data *data) +{ + int ret; + u8 acc_bw, gyr_bw; + u16 request; + + switch (data->accel_filter_freq) { + case SMI240_LOW_BANDWIDTH_HZ: + acc_bw = 0x1; + break; + case SMI240_HIGH_BANDWIDTH_HZ: + acc_bw = 0x0; + break; + default: + return -EINVAL; + } + + switch (data->anglvel_filter_freq) { + case SMI240_LOW_BANDWIDTH_HZ: + gyr_bw = 0x1; + break; + case SMI240_HIGH_BANDWIDTH_HZ: + gyr_bw = 0x0; + break; + default: + return -EINVAL; + } + + request = FIELD_PREP(SMI240_SOFT_CONFIG_EOC_MASK, 1); + request |= FIELD_PREP(SMI240_SOFT_CONFIG_GYR_BW_MASK, gyr_bw); + request |= FIELD_PREP(SMI240_SOFT_CONFIG_ACC_BW_MASK, acc_bw); + request |= FIELD_PREP(SMI240_SOFT_CONFIG_BITE_AUTO_MASK, 1); + request |= FIELD_PREP(SMI240_SOFT_CONFIG_BITE_REP_MASK, + data->built_in_self_test_count - 1); + + ret = regmap_write(data->regmap, SMI240_SOFT_CONFIG_REG, request); + if (ret) + return ret; + + fsleep(SMI240_MECH_STARTUP_DELAY_US + + data->built_in_self_test_count * SMI240_BITE_SEQUENCE_DELAY_US + + SMI240_FILTER_FLUSH_DELAY_US); + + return 0; +} + +static int smi240_get_low_pass_filter_freq(struct smi240_data *data, + int chan_type, int *val) +{ + switch (chan_type) { + case IIO_ACCEL: + *val = data->accel_filter_freq; + return 0; + case IIO_ANGL_VEL: + *val = data->anglvel_filter_freq; + return 0; + default: + return -EINVAL; + } +} + +static int smi240_get_data(struct smi240_data *data, int chan_type, int axis, + int *val) +{ + u8 reg; + int ret, sample; + + switch (chan_type) { + case IIO_TEMP: + reg = SMI240_TEMP_CUR_REG; + break; + case IIO_ACCEL: + reg = SMI240_ACCEL_X_CUR_REG + (axis - IIO_MOD_X); + break; + case IIO_ANGL_VEL: + reg = SMI240_GYRO_X_CUR_REG + (axis - IIO_MOD_X); + break; + default: + return -EINVAL; + } + + ret = regmap_read(data->regmap, reg, &sample); + if (ret) + return ret; + + *val = sign_extend32(sample, 15); + + return 0; +} + +static irqreturn_t smi240_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct smi240_data *data = iio_priv(indio_dev); + int base = SMI240_DATA_CAP_FIRST_REG, i = 0; + int ret, chan, sample; + + data->capture = SMI240_CAPTURE_ON; + + iio_for_each_active_channel(indio_dev, chan) { + ret = regmap_read(data->regmap, base + chan, &sample); + data->capture = SMI240_CAPTURE_OFF; + if (ret) + goto out; + data->buf[i++] = sample; + } + + iio_push_to_buffers_with_timestamp(indio_dev, data->buf, pf->timestamp); + +out: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int smi240_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, const int **vals, + int *type, int *length, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + *vals = smi240_low_pass_freqs; + *length = ARRAY_SIZE(smi240_low_pass_freqs); + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int smi240_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + int ret; + struct smi240_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + ret = smi240_get_data(data, chan->type, chan->channel2, val); + iio_device_release_direct_mode(indio_dev); + if (ret) + return ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + ret = smi240_get_low_pass_filter_freq(data, chan->type, val); + if (ret) + return ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + *val = SMI240_TEMP_SCALE / GIGA; + *val2 = SMI240_TEMP_SCALE % GIGA; + return IIO_VAL_INT_PLUS_NANO; + case IIO_ACCEL: + *val = 0; + *val2 = SMI240_ACCEL_SCALE; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ANGL_VEL: + *val = 0; + *val2 = SMI240_GYRO_SCALE; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) { + *val = SMI240_TEMP_OFFSET; + return IIO_VAL_INT; + } else { + return -EINVAL; + } + + default: + return -EINVAL; + } +} + +static int smi240_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + int ret, i; + struct smi240_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + for (i = 0; i < ARRAY_SIZE(smi240_low_pass_freqs); i++) { + if (val == smi240_low_pass_freqs[i]) + break; + } + + if (i == ARRAY_SIZE(smi240_low_pass_freqs)) + return -EINVAL; + + switch (chan->type) { + case IIO_ACCEL: + data->accel_filter_freq = val; + break; + case IIO_ANGL_VEL: + data->anglvel_filter_freq = val; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + /* Write access to soft config is locked until hard/soft reset */ + ret = smi240_soft_reset(data); + if (ret) + return ret; + + return smi240_soft_config(data); +} + +static int smi240_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, long info) +{ + switch (info) { + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT_PLUS_MICRO; + } + default: + return IIO_VAL_INT_PLUS_MICRO; + } +} + +static int smi240_init(struct smi240_data *data) +{ + int ret; + + data->accel_filter_freq = SMI240_HIGH_BANDWIDTH_HZ; + data->anglvel_filter_freq = SMI240_HIGH_BANDWIDTH_HZ; + data->built_in_self_test_count = SMI240_BUILT_IN_SELF_TEST_COUNT; + + ret = smi240_soft_reset(data); + if (ret) + return ret; + + return smi240_soft_config(data); +} + +static const struct iio_info smi240_info = { + .read_avail = smi240_read_avail, + .read_raw = smi240_read_raw, + .write_raw = smi240_write_raw, + .write_raw_get_fmt = smi240_write_raw_get_fmt, +}; + +static int smi240_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct regmap *regmap; + struct smi240_data *data; + int ret, response; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init(dev, &smi240_regmap_bus, dev, + &smi240_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to initialize SPI Regmap\n"); + + data = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + data->regmap = regmap; + data->capture = SMI240_CAPTURE_OFF; + + ret = regmap_read(data->regmap, SMI240_CHIP_ID_REG, &response); + if (ret) + return dev_err_probe(dev, ret, "Read chip id failed\n"); + + if (response != SMI240_CHIP_ID) + dev_info(dev, "Unknown chip id: 0x%04x\n", response); + + ret = smi240_init(data); + if (ret) + return dev_err_probe(dev, ret, + "Device initialization failed\n"); + + indio_dev->channels = smi240_channels; + indio_dev->num_channels = ARRAY_SIZE(smi240_channels); + indio_dev->name = "smi240"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &smi240_info; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + smi240_trigger_handler, NULL); + if (ret) + return dev_err_probe(dev, ret, + "Setup triggered buffer failed\n"); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "Register IIO device failed\n"); + + return 0; +} + +static const struct spi_device_id smi240_spi_id[] = { + { "smi240" }, + { } +}; +MODULE_DEVICE_TABLE(spi, smi240_spi_id); + +static const struct of_device_id smi240_of_match[] = { + { .compatible = "bosch,smi240" }, + { } +}; +MODULE_DEVICE_TABLE(of, smi240_of_match); + +static struct spi_driver smi240_spi_driver = { + .probe = smi240_probe, + .id_table = smi240_spi_id, + .driver = { + .of_match_table = smi240_of_match, + .name = "smi240", + }, +}; +module_spi_driver(smi240_spi_driver); + +MODULE_AUTHOR("Markus Lochmann "); +MODULE_AUTHOR("Stefan Gutmann "); +MODULE_DESCRIPTION("Bosch SMI240 SPI driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index a3b93566533bc0..c225b246c8a552 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -447,7 +447,7 @@ struct st_lsm6dsx_hw { /* Ensure natural alignment of buffer elements */ struct { __le16 channels[3]; - s64 ts __aligned(8); + aligned_s64 ts; } scan[ST_LSM6DSX_ID_MAX]; }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index ed02679297252a..4fdcc2acc94ed0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -1865,7 +1865,7 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, return err; } -static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) +static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, bool state) { const struct st_lsm6dsx_reg *reg; unsigned int data; @@ -1959,7 +1959,7 @@ static int st_lsm6dsx_write_event_config(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); struct st_lsm6dsx_hw *hw = sensor->hw; @@ -2132,14 +2132,11 @@ st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, const struct st_lsm6dsx_reg **drdy_reg) { struct device *dev = hw->dev; + const struct st_sensors_platform_data *pdata = dev_get_platdata(dev); int err = 0, drdy_pin; - if (device_property_read_u32(dev, "st,drdy-int-pin", &drdy_pin) < 0) { - struct st_sensors_platform_data *pdata; - - pdata = (struct st_sensors_platform_data *)dev->platform_data; + if (device_property_read_u32(dev, "st,drdy-int-pin", &drdy_pin) < 0) drdy_pin = pdata ? pdata->drdy_int_pin : 1; - } switch (drdy_pin) { case 1: @@ -2162,14 +2159,13 @@ st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw) { const struct st_lsm6dsx_shub_settings *hub_settings; - struct st_sensors_platform_data *pdata; struct device *dev = hw->dev; + const struct st_sensors_platform_data *pdata = dev_get_platdata(dev); unsigned int data; int err = 0; hub_settings = &hw->settings->shub_settings; - pdata = (struct st_sensors_platform_data *)dev->platform_data; if (device_property_read_bool(dev, "st,pullups") || (pdata && pdata->pullups)) { if (hub_settings->pullup_en.sec_page) { @@ -2524,15 +2520,14 @@ static irqreturn_t st_lsm6dsx_sw_trigger_handler_thread(int irq, static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) { - struct st_sensors_platform_data *pdata; const struct st_lsm6dsx_reg *reg; struct device *dev = hw->dev; + const struct st_sensors_platform_data *pdata = dev_get_platdata(dev); unsigned long irq_type; bool irq_active_low; int err; - irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); - + irq_type = irq_get_trigger_type(hw->irq); switch (irq_type) { case IRQF_TRIGGER_HIGH: case IRQF_TRIGGER_RISING: @@ -2554,7 +2549,6 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) if (err < 0) return err; - pdata = (struct st_sensors_platform_data *)dev->platform_data; if (device_property_read_bool(dev, "drive-open-drain") || (pdata && pdata->open_drain)) { reg = &hw->settings->irq_config.od; @@ -2639,7 +2633,7 @@ static int st_lsm6dsx_init_regulators(struct device *dev) int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, struct regmap *regmap) { - struct st_sensors_platform_data *pdata = dev->platform_data; + const struct st_sensors_platform_data *pdata = dev_get_platdata(dev); const struct st_lsm6dsx_shub_settings *hub_settings; struct st_lsm6dsx_hw *hw; const char *name = NULL; @@ -2730,7 +2724,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return 0; } -EXPORT_SYMBOL_NS(st_lsm6dsx_probe, IIO_LSM6DSX); +EXPORT_SYMBOL_NS(st_lsm6dsx_probe, "IIO_LSM6DSX"); static int st_lsm6dsx_suspend(struct device *dev) { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index cddf41cc0ca97f..25e1de89b6e49f 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -193,4 +193,4 @@ MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_LSM6DSX); +MODULE_IMPORT_NS("IIO_LSM6DSX"); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c index 3b0c8b19c44816..6952d901316fce 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -54,4 +54,4 @@ module_i3c_driver(st_lsm6dsx_driver); MODULE_AUTHOR("Vitor Soares "); MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_LSM6DSX); +MODULE_IMPORT_NS("IIO_LSM6DSX"); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index c122c8831365a4..4b4b6d45524fb8 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -181,4 +181,4 @@ MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_LSM6DSX); +MODULE_IMPORT_NS("IIO_LSM6DSX"); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c index 10c1b2ba7a3d93..8f4a67edb335b2 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_core.c @@ -88,9 +88,9 @@ int st_lsm9ds0_probe(struct st_lsm9ds0 *lsm9ds0, struct regmap *regmap) /* Setup magnetometer device */ return st_lsm9ds0_probe_magn(lsm9ds0, regmap); } -EXPORT_SYMBOL_NS_GPL(st_lsm9ds0_probe, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS_GPL(st_lsm9ds0_probe, "IIO_ST_SENSORS"); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU core driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index d03cec3b24fed0..0732cfa258c4a7 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -91,4 +91,4 @@ module_i2c_driver(st_lsm9ds0_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU I2C driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index 69e9135795a379..43ec57c1e604b1 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -83,4 +83,4 @@ module_spi_driver(st_lsm9ds0_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("STMicroelectronics LSM9DS0 IMU SPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/industrialio-acpi.c b/drivers/iio/industrialio-acpi.c index 981b75d4078020..d67a4384379988 100644 --- a/drivers/iio/industrialio-acpi.c +++ b/drivers/iio/industrialio-acpi.c @@ -2,7 +2,8 @@ /* IIO ACPI helper functions */ #include -#include +#include +#include #include #include @@ -28,17 +29,21 @@ bool iio_read_acpi_mount_matrix(struct device *dev, char *acpi_method) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_device *adev = ACPI_COMPANION(dev); char *str; union acpi_object *obj, *elements; + acpi_handle handle; acpi_status status; int i, j, val[3]; bool ret = false; - if (!adev || !acpi_has_method(adev->handle, acpi_method)) + handle = ACPI_HANDLE(dev); + if (!handle) return false; - status = acpi_evaluate_object(adev->handle, acpi_method, NULL, &buffer); + if (!acpi_has_method(handle, acpi_method)) + return false; + + status = acpi_evaluate_object(handle, acpi_method, NULL, &buffer); if (ACPI_FAILURE(status)) { dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status); return false; @@ -83,3 +88,38 @@ bool iio_read_acpi_mount_matrix(struct device *dev, return ret; } EXPORT_SYMBOL_GPL(iio_read_acpi_mount_matrix); + +/** + * iio_get_acpi_device_name_and_data() - Return ACPI device instance name and driver data + * @dev: Device structure + * @data: Optional pointer to return driver data + * + * When device was enumerated by ACPI ID matching, the user might + * want to set description for the physical chip. In such cases + * the ACPI device instance name might be used. This call may be + * performed to retrieve this information. + * + * NOTE: This helper function exists only for backward compatibility, + * do not use in a new code! + * + * Returns: ACPI device instance name or %NULL. + */ +const char *iio_get_acpi_device_name_and_data(struct device *dev, const void **data) +{ + const struct acpi_device_id *id; + acpi_handle handle; + + handle = ACPI_HANDLE(dev); + if (!handle) + return NULL; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return NULL; + + if (data) + *data = (const void *)id->driver_data; + + return dev_name(dev); +} +EXPORT_SYMBOL_GPL(iio_get_acpi_device_name_and_data); diff --git a/drivers/iio/industrialio-backend.c b/drivers/iio/industrialio-backend.c index 20b3b5212da76a..36328127203520 100644 --- a/drivers/iio/industrialio-backend.c +++ b/drivers/iio/industrialio-backend.c @@ -230,7 +230,7 @@ void iio_backend_debugfs_add(struct iio_backend *back, debugfs_create_file("name", 0400, back_d, back, &iio_backend_debugfs_name_fops); } -EXPORT_SYMBOL_NS_GPL(iio_backend_debugfs_add, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_debugfs_add, "IIO_BACKEND"); /** * iio_backend_debugfs_print_chan_status - Print channel status @@ -256,7 +256,7 @@ ssize_t iio_backend_debugfs_print_chan_status(struct iio_backend *back, return iio_backend_op_call(back, debugfs_print_chan_status, chan, buf, len); } -EXPORT_SYMBOL_NS_GPL(iio_backend_debugfs_print_chan_status, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_debugfs_print_chan_status, "IIO_BACKEND"); /** * iio_backend_chan_enable - Enable a backend channel @@ -270,7 +270,7 @@ int iio_backend_chan_enable(struct iio_backend *back, unsigned int chan) { return iio_backend_op_call(back, chan_enable, chan); } -EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_chan_enable, "IIO_BACKEND"); /** * iio_backend_chan_disable - Disable a backend channel @@ -284,7 +284,7 @@ int iio_backend_chan_disable(struct iio_backend *back, unsigned int chan) { return iio_backend_op_call(back, chan_disable, chan); } -EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_chan_disable, "IIO_BACKEND"); static void __iio_backend_disable(void *back) { @@ -299,7 +299,7 @@ void iio_backend_disable(struct iio_backend *back) { __iio_backend_disable(back); } -EXPORT_SYMBOL_NS_GPL(iio_backend_disable, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_disable, "IIO_BACKEND"); /** * iio_backend_enable - Backend enable @@ -312,7 +312,7 @@ int iio_backend_enable(struct iio_backend *back) { return iio_backend_op_call(back, enable); } -EXPORT_SYMBOL_NS_GPL(iio_backend_enable, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_enable, "IIO_BACKEND"); /** * devm_iio_backend_enable - Device managed backend enable @@ -332,7 +332,7 @@ int devm_iio_backend_enable(struct device *dev, struct iio_backend *back) return devm_add_action_or_reset(dev, __iio_backend_disable, back); } -EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_enable, "IIO_BACKEND"); /** * iio_backend_data_format_set - Configure the channel data format @@ -354,7 +354,7 @@ int iio_backend_data_format_set(struct iio_backend *back, unsigned int chan, return iio_backend_op_call(back, data_format_set, chan, data); } -EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_data_format_set, "IIO_BACKEND"); /** * iio_backend_data_source_set - Select data source @@ -376,7 +376,7 @@ int iio_backend_data_source_set(struct iio_backend *back, unsigned int chan, return iio_backend_op_call(back, data_source_set, chan, data); } -EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_data_source_set, "IIO_BACKEND"); /** * iio_backend_set_sampling_freq - Set channel sampling rate @@ -392,7 +392,7 @@ int iio_backend_set_sampling_freq(struct iio_backend *back, unsigned int chan, { return iio_backend_op_call(back, set_sample_rate, chan, sample_rate_hz); } -EXPORT_SYMBOL_NS_GPL(iio_backend_set_sampling_freq, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_set_sampling_freq, "IIO_BACKEND"); /** * iio_backend_test_pattern_set - Configure a test pattern @@ -415,7 +415,7 @@ int iio_backend_test_pattern_set(struct iio_backend *back, return iio_backend_op_call(back, test_pattern_set, chan, pattern); } -EXPORT_SYMBOL_NS_GPL(iio_backend_test_pattern_set, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_test_pattern_set, "IIO_BACKEND"); /** * iio_backend_chan_status - Get the channel status @@ -434,7 +434,7 @@ int iio_backend_chan_status(struct iio_backend *back, unsigned int chan, { return iio_backend_op_call(back, chan_status, chan, error); } -EXPORT_SYMBOL_NS_GPL(iio_backend_chan_status, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_chan_status, "IIO_BACKEND"); /** * iio_backend_iodelay_set - Set digital I/O delay @@ -457,7 +457,7 @@ int iio_backend_iodelay_set(struct iio_backend *back, unsigned int lane, { return iio_backend_op_call(back, iodelay_set, lane, taps); } -EXPORT_SYMBOL_NS_GPL(iio_backend_iodelay_set, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_iodelay_set, "IIO_BACKEND"); /** * iio_backend_data_sample_trigger - Control when to sample data @@ -478,7 +478,7 @@ int iio_backend_data_sample_trigger(struct iio_backend *back, return iio_backend_op_call(back, data_sample_trigger, trigger); } -EXPORT_SYMBOL_NS_GPL(iio_backend_data_sample_trigger, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_data_sample_trigger, "IIO_BACKEND"); static void iio_backend_free_buffer(void *arg) { @@ -523,7 +523,7 @@ int devm_iio_backend_request_buffer(struct device *dev, return devm_add_action_or_reset(dev, iio_backend_free_buffer, pair); } -EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_request_buffer, "IIO_BACKEND"); /** * iio_backend_read_raw - Read a channel attribute from a backend device. @@ -542,7 +542,7 @@ int iio_backend_read_raw(struct iio_backend *back, { return iio_backend_op_call(back, read_raw, chan, val, val2, mask); } -EXPORT_SYMBOL_NS_GPL(iio_backend_read_raw, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_read_raw, "IIO_BACKEND"); static struct iio_backend *iio_backend_from_indio_dev_parent(const struct device *dev) { @@ -604,7 +604,7 @@ ssize_t iio_backend_ext_info_get(struct iio_dev *indio_dev, uintptr_t private, return iio_backend_op_call(back, ext_info_get, private, chan, buf); } -EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_get, "IIO_BACKEND"); /** * iio_backend_ext_info_set - IIO ext_info write callback @@ -634,7 +634,7 @@ ssize_t iio_backend_ext_info_set(struct iio_dev *indio_dev, uintptr_t private, return iio_backend_op_call(back, ext_info_set, private, chan, buf, len); } -EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_set, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_ext_info_set, "IIO_BACKEND"); /** * iio_backend_extend_chan_spec - Extend an IIO channel @@ -677,7 +677,7 @@ int iio_backend_extend_chan_spec(struct iio_backend *back, return 0; } -EXPORT_SYMBOL_NS_GPL(iio_backend_extend_chan_spec, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_extend_chan_spec, "IIO_BACKEND"); static void iio_backend_release(void *arg) { @@ -718,6 +718,84 @@ static int __devm_iio_backend_get(struct device *dev, struct iio_backend *back) return 0; } +/** + * iio_backend_ddr_enable - Enable interface DDR (Double Data Rate) mode + * @back: Backend device + * + * Enable DDR, data is generated by the IP at each front (raising and falling) + * of the bus clock signal. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_ddr_enable(struct iio_backend *back) +{ + return iio_backend_op_call(back, ddr_enable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_enable, "IIO_BACKEND"); + +/** + * iio_backend_ddr_disable - Disable interface DDR (Double Data Rate) mode + * @back: Backend device + * + * Disable DDR, setting into SDR mode (Single Data Rate). + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_ddr_disable(struct iio_backend *back) +{ + return iio_backend_op_call(back, ddr_disable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_ddr_disable, "IIO_BACKEND"); + +/** + * iio_backend_data_stream_enable - Enable data stream + * @back: Backend device + * + * Enable data stream over the bus interface. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_stream_enable(struct iio_backend *back) +{ + return iio_backend_op_call(back, data_stream_enable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_stream_enable, "IIO_BACKEND"); + +/** + * iio_backend_data_stream_disable - Disable data stream + * @back: Backend device + * + * Disable data stream over the bus interface. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_stream_disable(struct iio_backend *back) +{ + return iio_backend_op_call(back, data_stream_disable); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_stream_disable, "IIO_BACKEND"); + +/** + * iio_backend_data_transfer_addr - Set data address. + * @back: Backend device + * @address: Data register address + * + * Some devices may need to inform the backend about an address + * where to read or write the data. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int iio_backend_data_transfer_addr(struct iio_backend *back, u32 address) +{ + return iio_backend_op_call(back, data_transfer_addr, address); +} +EXPORT_SYMBOL_NS_GPL(iio_backend_data_transfer_addr, "IIO_BACKEND"); + static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, const char *name, struct fwnode_handle *fwnode) { @@ -737,8 +815,8 @@ static struct iio_backend *__devm_iio_backend_fwnode_get(struct device *dev, con } fwnode_back = fwnode_find_reference(fwnode, "io-backends", index); - if (IS_ERR(fwnode)) - return dev_err_cast_probe(dev, fwnode, + if (IS_ERR(fwnode_back)) + return dev_err_cast_probe(dev, fwnode_back, "Cannot get Firmware reference\n"); guard(mutex)(&iio_back_lock); @@ -775,7 +853,7 @@ struct iio_backend *devm_iio_backend_get(struct device *dev, const char *name) { return __devm_iio_backend_fwnode_get(dev, name, dev_fwnode(dev)); } -EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_get, "IIO_BACKEND"); /** * devm_iio_backend_fwnode_get - Device managed backend firmware node get @@ -794,7 +872,7 @@ struct iio_backend *devm_iio_backend_fwnode_get(struct device *dev, { return __devm_iio_backend_fwnode_get(dev, name, fwnode); } -EXPORT_SYMBOL_NS_GPL(devm_iio_backend_fwnode_get, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_fwnode_get, "IIO_BACKEND"); /** * __devm_iio_backend_get_from_fwnode_lookup - Device managed fwnode backend device get @@ -829,7 +907,7 @@ __devm_iio_backend_get_from_fwnode_lookup(struct device *dev, return ERR_PTR(-EPROBE_DEFER); } -EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(__devm_iio_backend_get_from_fwnode_lookup, "IIO_BACKEND"); /** * iio_backend_get_priv - Get driver private data @@ -839,7 +917,7 @@ void *iio_backend_get_priv(const struct iio_backend *back) { return back->priv; } -EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(iio_backend_get_priv, "IIO_BACKEND"); static void iio_backend_unregister(void *arg) { @@ -888,7 +966,7 @@ int devm_iio_backend_register(struct device *dev, return devm_add_action_or_reset(dev, iio_backend_unregister, back); } -EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, IIO_BACKEND); +EXPORT_SYMBOL_NS_GPL(devm_iio_backend_register, "IIO_BACKEND"); MODULE_AUTHOR("Nuno Sa "); MODULE_DESCRIPTION("Framework to handle complex IIO aggregate devices"); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 8104696cd47509..2708f87df7198f 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -36,7 +36,7 @@ #define DMABUF_ENQUEUE_TIMEOUT_MS 5000 -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); struct iio_dmabuf_priv { struct list_head entry; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 6a6568d4a2cb3a..a2117ad1337d55 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -95,6 +95,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_DELTA_VELOCITY] = "deltavelocity", [IIO_COLORTEMP] = "colortemp", [IIO_CHROMATICITY] = "chromaticity", + [IIO_ATTENTION] = "attention", }; static const char * const iio_modifier_names[] = { @@ -1665,7 +1666,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) indio_dev = &iio_dev_opaque->indio_dev; if (sizeof_priv) - indio_dev->priv = (char *)iio_dev_opaque + + ACCESS_PRIVATE(indio_dev, priv) = (char *)iio_dev_opaque + ALIGN(sizeof(*iio_dev_opaque), IIO_DMA_MINALIGN); indio_dev->dev.parent = parent; diff --git a/drivers/iio/industrialio-gts-helper.c b/drivers/iio/industrialio-gts-helper.c index 5f131bc1a01e97..3b5a998150623b 100644 --- a/drivers/iio/industrialio-gts-helper.c +++ b/drivers/iio/industrialio-gts-helper.c @@ -134,7 +134,7 @@ int iio_gts_total_gain_to_scale(struct iio_gts *gts, int 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); +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 @@ -167,7 +167,7 @@ static int iio_gts_gain_cmp(const void *a, const void *b) static int gain_to_scaletables(struct iio_gts *gts, int **gains, int **scales) { - int ret, i, j, new_idx, time_idx; + int i, j, new_idx, time_idx, ret = 0; int *all_gains; size_t gain_bytes; @@ -205,7 +205,7 @@ static int gain_to_scaletables(struct iio_gts *gts, int **gains, int **scales) memcpy(all_gains, gains[time_idx], gain_bytes); new_idx = gts->num_hwgain; - while (time_idx--) { + while (time_idx-- > 0) { for (j = 0; j < gts->num_hwgain; j++) { int candidate = gains[time_idx][j]; int chk; @@ -622,7 +622,7 @@ int devm_iio_init_iio_gts(struct device *dev, int max_scale_int, int max_scale_n return devm_iio_gts_build_avail_tables(dev, gts); } -EXPORT_SYMBOL_NS_GPL(devm_iio_init_iio_gts, IIO_GTS_HELPER); +EXPORT_SYMBOL_NS_GPL(devm_iio_init_iio_gts, "IIO_GTS_HELPER"); /** * iio_gts_all_avail_scales - helper for listing all available scales @@ -645,7 +645,7 @@ int iio_gts_all_avail_scales(struct iio_gts *gts, const int **vals, int *type, return IIO_AVAIL_LIST; } -EXPORT_SYMBOL_NS_GPL(iio_gts_all_avail_scales, IIO_GTS_HELPER); +EXPORT_SYMBOL_NS_GPL(iio_gts_all_avail_scales, "IIO_GTS_HELPER"); /** * iio_gts_avail_scales_for_time - list scales for integration time @@ -679,7 +679,7 @@ int iio_gts_avail_scales_for_time(struct iio_gts *gts, int time, return IIO_AVAIL_LIST; } -EXPORT_SYMBOL_NS_GPL(iio_gts_avail_scales_for_time, IIO_GTS_HELPER); +EXPORT_SYMBOL_NS_GPL(iio_gts_avail_scales_for_time, "IIO_GTS_HELPER"); /** * iio_gts_avail_times - helper for listing available integration times @@ -702,7 +702,7 @@ int iio_gts_avail_times(struct iio_gts *gts, const int **vals, int *type, return IIO_AVAIL_LIST; } -EXPORT_SYMBOL_NS_GPL(iio_gts_avail_times, IIO_GTS_HELPER); +EXPORT_SYMBOL_NS_GPL(iio_gts_avail_times, "IIO_GTS_HELPER"); /** * iio_gts_find_sel_by_gain - find selector corresponding to a HW-gain @@ -722,7 +722,7 @@ int iio_gts_find_sel_by_gain(struct iio_gts *gts, int gain) return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(iio_gts_find_sel_by_gain, IIO_GTS_HELPER); +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 @@ -742,7 +742,7 @@ int iio_gts_find_gain_by_sel(struct iio_gts *gts, int sel) return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(iio_gts_find_gain_by_sel, IIO_GTS_HELPER); +EXPORT_SYMBOL_NS_GPL(iio_gts_find_gain_by_sel, "IIO_GTS_HELPER"); /** * iio_gts_get_min_gain - find smallest valid HW-gain @@ -765,7 +765,7 @@ int iio_gts_get_min_gain(struct iio_gts *gts) return min; } -EXPORT_SYMBOL_NS_GPL(iio_gts_get_min_gain, IIO_GTS_HELPER); +EXPORT_SYMBOL_NS_GPL(iio_gts_get_min_gain, "IIO_GTS_HELPER"); /** * iio_find_closest_gain_low - Find the closest lower matching gain @@ -826,7 +826,7 @@ int iio_find_closest_gain_low(struct iio_gts *gts, int gain, bool *in_range) return gts->hwgain_table[best].gain; } -EXPORT_SYMBOL_NS_GPL(iio_find_closest_gain_low, IIO_GTS_HELPER); +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) @@ -913,7 +913,7 @@ int iio_gts_find_gain_sel_for_scale_using_time(struct iio_gts *gts, int time_sel return 0; } -EXPORT_SYMBOL_NS_GPL(iio_gts_find_gain_sel_for_scale_using_time, IIO_GTS_HELPER); +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) { @@ -975,7 +975,7 @@ int iio_gts_get_scale(struct iio_gts *gts, int gain, int time, int *scale_int, return iio_gts_delinearize(lin_scale, NANO, scale_int, scale_nano); } -EXPORT_SYMBOL_NS_GPL(iio_gts_get_scale, IIO_GTS_HELPER); +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 @@ -1032,7 +1032,7 @@ int iio_gts_find_new_gain_sel_by_old_gain_time(struct iio_gts *gts, return 0; } -EXPORT_SYMBOL_NS_GPL(iio_gts_find_new_gain_sel_by_old_gain_time, IIO_GTS_HELPER); +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 @@ -1084,7 +1084,7 @@ int iio_gts_find_new_gain_by_old_gain_time(struct iio_gts *gts, int old_gain, return 0; } -EXPORT_SYMBOL_NS_GPL(iio_gts_find_new_gain_by_old_gain_time, IIO_GTS_HELPER); +EXPORT_SYMBOL_NS_GPL(iio_gts_find_new_gain_by_old_gain_time, "IIO_GTS_HELPER"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Matti Vaittinen "); diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 151099be2863c6..136b225b6bc8a1 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -20,7 +20,7 @@ struct iio_map_internal { struct iio_dev *indio_dev; - struct iio_map *map; + const struct iio_map *map; struct list_head l; }; @@ -42,7 +42,7 @@ static int iio_map_array_unregister_locked(struct iio_dev *indio_dev) return ret; } -int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps) +int iio_map_array_register(struct iio_dev *indio_dev, const struct iio_map *maps) { struct iio_map_internal *mapi; int i = 0; @@ -86,7 +86,8 @@ static void iio_map_array_unregister_cb(void *indio_dev) iio_map_array_unregister(indio_dev); } -int devm_iio_map_array_register(struct device *dev, struct iio_dev *indio_dev, struct iio_map *maps) +int devm_iio_map_array_register(struct device *dev, struct iio_dev *indio_dev, + const struct iio_map *maps) { int ret; @@ -269,7 +270,7 @@ struct iio_channel *fwnode_iio_channel_get_by_name(struct fwnode_handle *fwnode, return ERR_PTR(-ENODEV); } - chan = __fwnode_iio_channel_get_by_name(fwnode, name); + chan = __fwnode_iio_channel_get_by_name(parent, name); if (!IS_ERR(chan) || PTR_ERR(chan) != -ENODEV) { fwnode_handle_put(parent); return chan; diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index f2f3e414849ab1..29ffa84919273d 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -248,7 +248,6 @@ config SENSORS_ISL29018 tristate "Intersil 29018 light and proximity sensor" depends on I2C select REGMAP_I2C - default n help If you say yes here you get support for ambient light sensing and proximity infrared sensing from Intersil ISL29018. @@ -476,7 +475,7 @@ config OPT3001 depends on I2C help If you say Y or M here, you get support for Texas Instruments - OPT3001 Ambient Light Sensor. + OPT3001 Ambient Light Sensor, OPT3002 Light-to-Digital Sensor. If built as a dynamically linked module, it will be called opt3001. @@ -670,13 +669,24 @@ config VCNL4035 To compile this driver as a module, choose M here: the module will be called vcnl4035. +config VEML3235 + tristate "VEML3235 ambient light sensor" + select REGMAP_I2C + depends on I2C + help + Say Y here if you want to build a driver for the Vishay VEML3235 + ambient light sensor. + + To compile this driver as a module, choose M here: the + module will be called veml3235. + config VEML6030 - tristate "VEML6030 ambient light sensor" + tristate "VEML6030 and VEML6035 ambient light sensors" select REGMAP_I2C depends on I2C help Say Y here if you want to build a driver for the Vishay VEML6030 - ambient light sensor (ALS). + and VEML6035 ambient light sensors (ALS). To compile this driver as a module, choose M here: the module will be called veml6030. diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 321010fc0b938a..f14a3744271242 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_TSL4531) += tsl4531.o obj-$(CONFIG_US5182D) += us5182d.o obj-$(CONFIG_VCNL4000) += vcnl4000.o obj-$(CONFIG_VCNL4035) += vcnl4035.o +obj-$(CONFIG_VEML3235) += veml3235.o obj-$(CONFIG_VEML6030) += veml6030.o obj-$(CONFIG_VEML6040) += veml6040.o obj-$(CONFIG_VEML6070) += veml6070.o diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c index 2e0170be077aef..593d614b1689b2 100644 --- a/drivers/iio/light/adux1020.c +++ b/drivers/iio/light/adux1020.c @@ -502,7 +502,8 @@ static int adux1020_write_raw(struct iio_dev *indio_dev, static int adux1020_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) + enum iio_event_direction dir, + bool state) { struct adux1020_data *data = iio_priv(indio_dev); int ret, mask; @@ -526,12 +527,11 @@ static int adux1020_write_event_config(struct iio_dev *indio_dev, mask = ADUX1020_PROX_OFF1_INT; if (state) - state = 0; + ret = regmap_clear_bits(data->regmap, + ADUX1020_REG_INT_MASK, mask); else - state = mask; - - ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK, - mask, state); + ret = regmap_set_bits(data->regmap, + ADUX1020_REG_INT_MASK, mask); if (ret < 0) goto fail; diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c index 53569587ccb7ba..7cbb8b20330090 100644 --- a/drivers/iio/light/al3010.c +++ b/drivers/iio/light/al3010.c @@ -87,7 +87,12 @@ static int al3010_init(struct al3010_data *data) int ret; ret = al3010_set_pwr(data->client, true); + if (ret < 0) + return ret; + ret = devm_add_action_or_reset(&data->client->dev, + al3010_set_pwr_off, + data); if (ret < 0) return ret; @@ -190,12 +195,6 @@ static int al3010_probe(struct i2c_client *client) return ret; } - ret = devm_add_action_or_reset(&client->dev, - al3010_set_pwr_off, - data); - if (ret < 0) - return ret; - return devm_iio_device_register(&client->dev, indio_dev); } diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 11f2ab4ca26181..938d76f7e3129c 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -46,10 +46,10 @@ struct apds9300_data { struct i2c_client *client; struct mutex mutex; - int power_state; + bool power_state; int thresh_low; int thresh_hi; - int intr_en; + bool intr_en; }; /* Lux calculation */ @@ -148,7 +148,7 @@ static int apds9300_set_thresh_hi(struct apds9300_data *data, int value) return 0; } -static int apds9300_set_intr_state(struct apds9300_data *data, int state) +static int apds9300_set_intr_state(struct apds9300_data *data, bool state) { int ret; u8 cmd; @@ -169,7 +169,7 @@ static int apds9300_set_intr_state(struct apds9300_data *data, int state) return 0; } -static int apds9300_set_power_state(struct apds9300_data *data, int state) +static int apds9300_set_power_state(struct apds9300_data *data, bool state) { int ret; u8 cmd; @@ -221,7 +221,7 @@ static int apds9300_chip_init(struct apds9300_data *data) * Disable interrupt to ensure thai it is doesn't enable * i.e. after device soft reset */ - ret = apds9300_set_intr_state(data, 0); + ret = apds9300_set_intr_state(data, false); if (ret < 0) goto err; @@ -321,7 +321,7 @@ static int apds9300_read_interrupt_config(struct iio_dev *indio_dev, static int apds9300_write_interrupt_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { struct apds9300_data *data = iio_priv(indio_dev); int ret; @@ -459,8 +459,8 @@ static void apds9300_remove(struct i2c_client *client) iio_device_unregister(indio_dev); /* Ensure that power off and interrupts are disabled */ - apds9300_set_intr_state(data, 0); - apds9300_set_power_state(data, 0); + apds9300_set_intr_state(data, false); + apds9300_set_power_state(data, false); } static int apds9300_suspend(struct device *dev) @@ -470,7 +470,7 @@ static int apds9300_suspend(struct device *dev) int ret; mutex_lock(&data->mutex); - ret = apds9300_set_power_state(data, 0); + ret = apds9300_set_power_state(data, false); mutex_unlock(&data->mutex); return ret; @@ -483,7 +483,7 @@ static int apds9300_resume(struct device *dev) int ret; mutex_lock(&data->mutex); - ret = apds9300_set_power_state(data, 1); + ret = apds9300_set_power_state(data, true); mutex_unlock(&data->mutex); return ret; diff --git a/drivers/iio/light/apds9306.c b/drivers/iio/light/apds9306.c index 079e02be100521..69a0d609cffc91 100644 --- a/drivers/iio/light/apds9306.c +++ b/drivers/iio/light/apds9306.c @@ -1071,7 +1071,7 @@ static int apds9306_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) + bool state) { struct apds9306_data *data = iio_priv(indio_dev); struct apds9306_regfields *rf = &data->rf; @@ -1125,10 +1125,7 @@ static int apds9306_write_event_config(struct iio_dev *indio_dev, } } case IIO_EV_TYPE_THRESH_ADAPTIVE: - if (state) - return regmap_field_write(rf->int_thresh_var_en, 1); - else - return regmap_field_write(rf->int_thresh_var_en, 0); + return regmap_field_write(rf->int_thresh_var_en, state); default: return -EINVAL; } @@ -1358,4 +1355,4 @@ module_i2c_driver(apds9306_driver); MODULE_AUTHOR("Subhajit Ghosh "); MODULE_DESCRIPTION("APDS9306 Ambient Light Sensor driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_GTS_HELPER); +MODULE_IMPORT_NS("IIO_GTS_HELPER"); diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 3c14e4c30805e1..d30441d3370309 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -133,8 +133,8 @@ struct apds9960_data { struct regmap_field *reg_enable_pxs; /* state */ - int als_int; - int pxs_int; + bool als_int; + bool pxs_int; int gesture_mode_running; /* gain values */ @@ -749,21 +749,17 @@ static int apds9960_read_event_config(struct iio_dev *indio_dev, default: return -EINVAL; } - - return 0; } static int apds9960_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) + bool state) { struct apds9960_data *data = iio_priv(indio_dev); int ret; - state = !!state; - switch (chan->type) { case IIO_PROXIMITY: if (data->pxs_int == state) diff --git a/drivers/iio/light/bh1745.c b/drivers/iio/light/bh1745.c index 2e458e9d5d8530..56e32689bb97a8 100644 --- a/drivers/iio/light/bh1745.c +++ b/drivers/iio/light/bh1745.c @@ -638,46 +638,42 @@ static int bh1745_read_event_config(struct iio_dev *indio_dev, static int bh1745_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) + enum iio_event_direction dir, bool state) { struct bh1745_data *data = iio_priv(indio_dev); int value; - if (state == 0) + if (!state) return regmap_clear_bits(data->regmap, BH1745_INTR, BH1745_INTR_ENABLE); - if (state == 1) { - /* Latch is always enabled when enabling interrupt */ - value = BH1745_INTR_ENABLE; + /* Latch is always enabled when enabling interrupt */ + value = BH1745_INTR_ENABLE; - switch (chan->channel2) { - case IIO_MOD_LIGHT_RED: - return regmap_write(data->regmap, BH1745_INTR, - value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, - BH1745_INTR_SOURCE_RED)); + switch (chan->channel2) { + case IIO_MOD_LIGHT_RED: + return regmap_write(data->regmap, BH1745_INTR, + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, + BH1745_INTR_SOURCE_RED)); - case IIO_MOD_LIGHT_GREEN: - return regmap_write(data->regmap, BH1745_INTR, - value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, - BH1745_INTR_SOURCE_GREEN)); + case IIO_MOD_LIGHT_GREEN: + return regmap_write(data->regmap, BH1745_INTR, + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, + BH1745_INTR_SOURCE_GREEN)); - case IIO_MOD_LIGHT_BLUE: - return regmap_write(data->regmap, BH1745_INTR, - value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, - BH1745_INTR_SOURCE_BLUE)); + case IIO_MOD_LIGHT_BLUE: + return regmap_write(data->regmap, BH1745_INTR, + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, + BH1745_INTR_SOURCE_BLUE)); - case IIO_MOD_LIGHT_CLEAR: - return regmap_write(data->regmap, BH1745_INTR, - value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, - BH1745_INTR_SOURCE_CLEAR)); + case IIO_MOD_LIGHT_CLEAR: + return regmap_write(data->regmap, BH1745_INTR, + value | FIELD_PREP(BH1745_INTR_SOURCE_MASK, + BH1745_INTR_SOURCE_CLEAR)); - default: - return -EINVAL; - } + default: + return -EINVAL; } - - return -EINVAL; } static int bh1745_read_avail(struct iio_dev *indio_dev, @@ -903,4 +899,4 @@ module_i2c_driver(bh1745_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mudit Sharma "); MODULE_DESCRIPTION("BH1745 colour sensor driver"); -MODULE_IMPORT_NS(IIO_GTS_HELPER); +MODULE_IMPORT_NS("IIO_GTS_HELPER"); diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index 9df85b3999fa88..aeae0566ec12a5 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -217,8 +217,7 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181) cm32181->lux_per_bit = CM32181_LUX_PER_BIT; cm32181->lux_per_bit_base_it = CM32181_LUX_PER_BIT_BASE_IT; - if (ACPI_HANDLE(cm32181->dev)) - cm32181_acpi_parse_cpm_tables(cm32181); + cm32181_acpi_parse_cpm_tables(cm32181); /* Initialize registers*/ for_each_set_bit(i, &cm32181->init_regs_bitmap, CM32181_CONF_REG_NUM) { diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c index 22a63a89f289a2..675c0fd44db45a 100644 --- a/drivers/iio/light/cm3605.c +++ b/drivers/iio/light/cm3605.c @@ -318,7 +318,7 @@ static struct platform_driver cm3605_driver = { .pm = pm_sleep_ptr(&cm3605_dev_pm_ops), }, .probe = cm3605_probe, - .remove_new = cm3605_remove, + .remove = cm3605_remove, }; module_platform_driver(cm3605_driver); diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index a4a1505534c015..ae3fc3299eec6c 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -529,7 +529,7 @@ static int cm36651_write_prox_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) + bool state) { struct cm36651_data *cm36651 = iio_priv(indio_dev); int cmd, ret; diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c index f8b1d7dd6f5fc6..d56ee217fe538c 100644 --- a/drivers/iio/light/gp2ap002.c +++ b/drivers/iio/light/gp2ap002.c @@ -340,7 +340,7 @@ static int gp2ap002_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) + bool state) { struct gp2ap002 *gp2ap002 = iio_priv(indio_dev); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 81e718cdeae32d..1a352c88598e5d 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1159,7 +1159,7 @@ static int gp2ap020a00f_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) + bool state) { struct gp2ap020a00f_data *data = iio_priv(indio_dev); enum gp2ap020a00f_cmd cmd; diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 260281194f6132..aa4c72d4849e13 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -31,7 +31,7 @@ struct als_state { struct iio_chan_spec channels[CHANNEL_SCAN_INDEX_MAX + 1]; struct { u32 illum[CHANNEL_SCAN_INDEX_MAX]; - u64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -356,11 +356,11 @@ static int als_parse_report(struct platform_device *pdev, /* Function to initialize the processing for usage id */ static int hid_als_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret = 0; static const char *name = "als"; struct iio_dev *indio_dev; struct als_state *als_state; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct als_state)); if (!indio_dev) @@ -438,7 +438,7 @@ static int hid_als_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_als_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct als_state *als_state = iio_priv(indio_dev); @@ -467,11 +467,11 @@ static struct platform_driver hid_als_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_als_probe, - .remove_new = hid_als_remove, + .remove = hid_als_remove, }; module_platform_driver(hid_als_platform_driver); MODULE_DESCRIPTION("HID Sensor ALS"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 26c481d2998c1f..c83acbd7827592 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -13,16 +13,32 @@ #include #include "../common/hid-sensors/hid-sensor-trigger.h" -#define CHANNEL_SCAN_INDEX_PRESENCE 0 +static const u32 prox_usage_ids[] = { + HID_USAGE_SENSOR_HUMAN_PRESENCE, + HID_USAGE_SENSOR_HUMAN_PROXIMITY, + HID_USAGE_SENSOR_HUMAN_ATTENTION, +}; + +#define MAX_CHANNELS ARRAY_SIZE(prox_usage_ids) + +enum { + HID_HUMAN_PRESENCE, + HID_HUMAN_PROXIMITY, + HID_HUMAN_ATTENTION, +}; struct prox_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; - struct hid_sensor_hub_attribute_info prox_attr; - u32 human_presence; + struct hid_sensor_hub_attribute_info prox_attr[MAX_CHANNELS]; + struct iio_chan_spec channels[MAX_CHANNELS]; + u32 channel2usage[MAX_CHANNELS]; + u32 human_presence[MAX_CHANNELS]; int scale_pre_decml; int scale_post_decml; int scale_precision; + unsigned long scan_mask[2]; /* One entry plus one terminator. */ + int num_channels; }; static const u32 prox_sensitivity_addresses[] = { @@ -30,17 +46,24 @@ static const u32 prox_sensitivity_addresses[] = { HID_USAGE_SENSOR_DATA_PRESENCE, }; -/* Channel definitions */ -static const struct iio_chan_spec prox_channels[] = { - { - .type = IIO_PROXIMITY, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | - BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_PRESENCE, +#define PROX_CHANNEL(_is_proximity, _channel) \ + {\ + .type = _is_proximity ? IIO_PROXIMITY : IIO_ATTENTION,\ + .info_mask_separate = _is_proximity ? BIT(IIO_CHAN_INFO_RAW) :\ + BIT(IIO_CHAN_INFO_PROCESSED),\ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |\ + BIT(IIO_CHAN_INFO_SCALE) |\ + BIT(IIO_CHAN_INFO_SAMP_FREQ) |\ + BIT(IIO_CHAN_INFO_HYSTERESIS),\ + .indexed = _is_proximity,\ + .channel = _channel,\ } + +/* Channel definitions (same order as prox_usage_ids) */ +static const struct iio_chan_spec prox_channels[] = { + PROX_CHANNEL(true, HID_HUMAN_PRESENCE), + PROX_CHANNEL(true, HID_HUMAN_PROXIMITY), + PROX_CHANNEL(false, 0), }; /* Adjust channel real bits based on report descriptor */ @@ -62,7 +85,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, { struct prox_state *prox_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev; - int report_id = -1; + int report_id; u32 address; int ret_type; s32 min; @@ -71,29 +94,23 @@ static int prox_read_raw(struct iio_dev *indio_dev, *val2 = 0; switch (mask) { case IIO_CHAN_INFO_RAW: - switch (chan->scan_index) { - case CHANNEL_SCAN_INDEX_PRESENCE: - report_id = prox_state->prox_attr.report_id; - min = prox_state->prox_attr.logical_minimum; - address = HID_USAGE_SENSOR_HUMAN_PRESENCE; - hsdev = prox_state->common_attributes.hsdev; - break; - default: - report_id = -1; - break; - } - if (report_id >= 0) { - hid_sensor_power_state(&prox_state->common_attributes, - true); - *val = sensor_hub_input_attr_get_raw_value( - hsdev, hsdev->usage, address, report_id, - SENSOR_HUB_SYNC, min < 0); - hid_sensor_power_state(&prox_state->common_attributes, - false); - } else { - *val = 0; + if (chan->scan_index >= prox_state->num_channels) return -EINVAL; - } + address = prox_state->channel2usage[chan->scan_index]; + report_id = prox_state->prox_attr[chan->scan_index].report_id; + hsdev = prox_state->common_attributes.hsdev; + min = prox_state->prox_attr[chan->scan_index].logical_minimum; + hid_sensor_power_state(&prox_state->common_attributes, true); + *val = sensor_hub_input_attr_get_raw_value(hsdev, + hsdev->usage, + address, + report_id, + SENSOR_HUB_SYNC, + min < 0); + if (prox_state->channel2usage[chan->scan_index] == + HID_USAGE_SENSOR_HUMAN_ATTENTION) + *val *= 100; + hid_sensor_power_state(&prox_state->common_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: @@ -103,7 +120,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_OFFSET: *val = hid_sensor_convert_exponent( - prox_state->prox_attr.unit_expo); + prox_state->prox_attr[chan->scan_index].unit_expo); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: @@ -153,14 +170,6 @@ static const struct iio_info prox_info = { .write_raw = &prox_write_raw, }; -/* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, - int len) -{ - dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, data); -} - /* Callback handler to send event after all samples are received and captured */ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, unsigned usage_id, @@ -170,10 +179,10 @@ static int prox_proc_event(struct hid_sensor_hub_device *hsdev, struct prox_state *prox_state = iio_priv(indio_dev); dev_dbg(&indio_dev->dev, "prox_proc_event\n"); - if (atomic_read(&prox_state->common_attributes.data_ready)) - hid_sensor_push_data(indio_dev, - &prox_state->human_presence, - sizeof(prox_state->human_presence)); + if (atomic_read(&prox_state->common_attributes.data_ready)) { + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + iio_push_to_buffers(indio_dev, &prox_state->human_presence); + } return 0; } @@ -186,58 +195,77 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, { struct iio_dev *indio_dev = platform_get_drvdata(priv); struct prox_state *prox_state = iio_priv(indio_dev); - int ret = -EINVAL; - - switch (usage_id) { - case HID_USAGE_SENSOR_HUMAN_PRESENCE: - switch (raw_len) { - case 1: - prox_state->human_presence = *(u8 *)raw_data; - return 0; - case 4: - prox_state->human_presence = *(u32 *)raw_data; - return 0; - default: + int multiplier = 1; + int chan; + + for (chan = 0; chan < prox_state->num_channels; chan++) + if (prox_state->channel2usage[chan] == usage_id) break; - } - break; + if (chan == prox_state->num_channels) + return -EINVAL; + + if (usage_id == HID_USAGE_SENSOR_HUMAN_ATTENTION) + multiplier = 100; + + switch (raw_len) { + case 1: + prox_state->human_presence[chan] = *(u8 *)raw_data * multiplier; + return 0; + case 4: + prox_state->human_presence[chan] = *(u32 *)raw_data * multiplier; + return 0; } - return ret; + return -EINVAL; } /* Parse report which is specific to an usage id*/ static int prox_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, - unsigned usage_id, struct prox_state *st) { + struct iio_chan_spec *channels = st->channels; + int index = 0; int ret; + int i; + + for (i = 0; i < MAX_CHANNELS; i++) { + u32 usage_id = prox_usage_ids[i]; + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + hsdev->usage, + usage_id, + &st->prox_attr[index]); + if (ret < 0) + continue; + st->channel2usage[index] = usage_id; + st->scan_mask[0] |= BIT(index); + channels[index] = prox_channels[i]; + channels[index].scan_index = index; + prox_adjust_channel_bit_mask(channels, index, + st->prox_attr[index].size); + dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr[index].index, + st->prox_attr[index].report_id); + index++; + } - ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, - usage_id, - HID_USAGE_SENSOR_HUMAN_PRESENCE, - &st->prox_attr); - if (ret < 0) + if (!index) return ret; - prox_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESENCE, - st->prox_attr.size); - dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index, - st->prox_attr.report_id); + st->num_channels = index; - return ret; + return 0; } /* Function to initialize the processing for usage id */ static int hid_prox_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret = 0; static const char *name = "prox"; struct iio_dev *indio_dev; struct prox_state *prox_state; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct prox_state)); @@ -258,22 +286,15 @@ static int hid_prox_probe(struct platform_device *pdev) return ret; } - indio_dev->channels = devm_kmemdup(&pdev->dev, prox_channels, - sizeof(prox_channels), GFP_KERNEL); - if (!indio_dev->channels) { - dev_err(&pdev->dev, "failed to duplicate channels\n"); - return -ENOMEM; - } - - ret = prox_parse_report(pdev, hsdev, - (struct iio_chan_spec *)indio_dev->channels, - hsdev->usage, prox_state); + ret = prox_parse_report(pdev, hsdev, prox_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; } - indio_dev->num_channels = ARRAY_SIZE(prox_channels); + indio_dev->num_channels = prox_state->num_channels; + indio_dev->channels = prox_state->channels; + indio_dev->available_scan_masks = prox_state->scan_mask; indio_dev->info = &prox_info; indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; @@ -315,7 +336,7 @@ static int hid_prox_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_prox_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct prox_state *prox_state = iio_priv(indio_dev); @@ -344,11 +365,11 @@ static struct platform_driver hid_prox_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_prox_probe, - .remove_new = hid_prox_remove, + .remove = hid_prox_remove, }; module_platform_driver(hid_prox_platform_driver); MODULE_DESCRIPTION("HID Sensor Proximity"); MODULE_AUTHOR("Archana Patni "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c index 6de33feada3a36..b9f230210f0731 100644 --- a/drivers/iio/light/iqs621-als.c +++ b/drivers/iio/light/iqs621-als.c @@ -271,7 +271,7 @@ static int iqs621_als_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) + bool state) { struct iqs621_als_private *iqs621_als = iio_priv(indio_dev); struct iqs62x_core *iqs62x = iqs621_als->iqs62x; diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 8dfc750e68c02f..201eae1c45892b 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -8,17 +8,18 @@ * Copyright (c) 2010, NVIDIA Corporation. */ -#include #include #include +#include +#include #include #include #include #include #include + #include #include -#include #define ISL29018_CONV_TIME_MS 100 @@ -687,20 +688,6 @@ static const struct isl29018_chip_info isl29018_chip_info_tbl[] = { }, }; -static const char *isl29018_match_acpi_device(struct device *dev, int *data) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - - if (!id) - return NULL; - - *data = (int)id->driver_data; - - return dev_name(dev); -} - static void isl29018_disable_regulator_action(void *_data) { struct isl29018_chip *chip = _data; @@ -716,9 +703,10 @@ static int isl29018_probe(struct i2c_client *client) const struct i2c_device_id *id = i2c_client_get_device_id(client); struct isl29018_chip *chip; struct iio_dev *indio_dev; + const void *ddata = NULL; + const char *name; + int dev_id; int err; - const char *name = NULL; - int dev_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); if (!indio_dev) @@ -731,11 +719,11 @@ static int isl29018_probe(struct i2c_client *client) if (id) { name = id->name; dev_id = id->driver_data; + } else { + name = iio_get_acpi_device_name_and_data(&client->dev, &ddata); + dev_id = (intptr_t)ddata; } - if (ACPI_HANDLE(&client->dev)) - name = isl29018_match_acpi_device(&client->dev, &dev_id); - mutex_init(&chip->lock); chip->type = dev_id; @@ -832,15 +820,13 @@ static int isl29018_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); -#ifdef CONFIG_ACPI static const struct acpi_device_id isl29018_acpi_match[] = { {"ISL29018", isl29018}, {"ISL29023", isl29023}, {"ISL29035", isl29035}, - {}, + {} }; MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); -#endif static const struct i2c_device_id isl29018_id[] = { {"isl29018", isl29018}, @@ -854,14 +840,14 @@ static const struct of_device_id isl29018_of_match[] = { { .compatible = "isil,isl29018", }, { .compatible = "isil,isl29023", }, { .compatible = "isil,isl29035", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, isl29018_of_match); static struct i2c_driver isl29018_driver = { .driver = { .name = "isl29018", - .acpi_match_table = ACPI_PTR(isl29018_acpi_match), + .acpi_match_table = isl29018_acpi_match, .pm = pm_sleep_ptr(&isl29018_pm_ops), .of_match_table = isl29018_of_match, }, diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index 7800f7fa51b76f..99f0b903018cf8 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -754,7 +754,7 @@ static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val) } static int lm3533_als_setup(struct lm3533_als *als, - struct lm3533_als_platform_data *pdata) + const struct lm3533_als_platform_data *pdata) { int ret; @@ -828,8 +828,8 @@ static const struct iio_info lm3533_als_info = { static int lm3533_als_probe(struct platform_device *pdev) { + const struct lm3533_als_platform_data *pdata; struct lm3533 *lm3533; - struct lm3533_als_platform_data *pdata; struct lm3533_als *als; struct iio_dev *indio_dev; int ret; @@ -838,7 +838,7 @@ static int lm3533_als_probe(struct platform_device *pdev) if (!lm3533) return -EINVAL; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(&pdev->dev, "no platform data\n"); return -EINVAL; @@ -912,7 +912,7 @@ static struct platform_driver lm3533_als_driver = { .name = "lm3533-als", }, .probe = lm3533_als_probe, - .remove_new = lm3533_als_remove, + .remove = lm3533_als_remove, }; module_platform_driver(lm3533_als_driver); diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c index 4f6975e63a8fe1..df664f36090301 100644 --- a/drivers/iio/light/ltr390.c +++ b/drivers/iio/light/ltr390.c @@ -18,14 +18,18 @@ * - Interrupt support */ +#include +#include #include +#include +#include #include #include #include #include -#include #include +#include #include @@ -33,18 +37,27 @@ #define LTR390_ALS_UVS_MEAS_RATE 0x04 #define LTR390_ALS_UVS_GAIN 0x05 #define LTR390_PART_ID 0x06 +#define LTR390_MAIN_STATUS 0x07 #define LTR390_ALS_DATA 0x0D #define LTR390_UVS_DATA 0x10 #define LTR390_INT_CFG 0x19 +#define LTR390_INT_PST 0x1A +#define LTR390_THRESH_UP 0x21 +#define LTR390_THRESH_LOW 0x24 #define LTR390_PART_NUMBER_ID 0xb -#define LTR390_ALS_UVS_GAIN_MASK 0x07 -#define LTR390_ALS_UVS_INT_TIME_MASK 0x70 +#define LTR390_ALS_UVS_GAIN_MASK GENMASK(2, 0) +#define LTR390_ALS_UVS_MEAS_RATE_MASK GENMASK(2, 0) +#define LTR390_ALS_UVS_INT_TIME_MASK GENMASK(6, 4) #define LTR390_ALS_UVS_INT_TIME(x) FIELD_PREP(LTR390_ALS_UVS_INT_TIME_MASK, (x)) +#define LTR390_INT_PST_MASK GENMASK(7, 4) +#define LTR390_INT_PST_VAL(x) FIELD_PREP(LTR390_INT_PST_MASK, (x)) #define LTR390_SW_RESET BIT(4) #define LTR390_UVS_MODE BIT(3) #define LTR390_SENSOR_ENABLE BIT(1) +#define LTR390_LS_INT_EN BIT(2) +#define LTR390_LS_INT_SEL_UVS BIT(5) #define LTR390_FRACTIONAL_PRECISION 100 @@ -70,6 +83,11 @@ enum ltr390_mode { LTR390_SET_UVS_MODE, }; +enum ltr390_meas_rate { + LTR390_GET_FREQ, + LTR390_GET_PERIOD, +}; + struct ltr390_data { struct regmap *regmap; struct i2c_client *client; @@ -87,6 +105,18 @@ static const struct regmap_config ltr390_regmap_config = { .val_bits = 8, }; +/* Sampling frequency is in mili Hz and mili Seconds */ +static const int ltr390_samp_freq_table[][2] = { + [0] = { 40000, 25 }, + [1] = { 20000, 50 }, + [2] = { 10000, 100 }, + [3] = { 5000, 200 }, + [4] = { 2000, 500 }, + [5] = { 1000, 1000 }, + [6] = { 500, 2000 }, + [7] = { 500, 2000 }, +}; + static int ltr390_register_read(struct ltr390_data *data, u8 register_address) { struct device *dev = &data->client->dev; @@ -135,6 +165,19 @@ static int ltr390_counts_per_uvi(struct ltr390_data *data) return DIV_ROUND_CLOSEST(23 * data->gain * data->int_time_us, 10 * orig_gain * orig_int_time); } +static int ltr390_get_samp_freq_or_period(struct ltr390_data *data, + enum ltr390_meas_rate option) +{ + int ret, value; + + ret = regmap_read(data->regmap, LTR390_ALS_UVS_MEAS_RATE, &value); + if (ret < 0) + return ret; + value = FIELD_GET(LTR390_ALS_UVS_MEAS_RATE_MASK, value); + + return ltr390_samp_freq_table[value][option]; +} + static int ltr390_read_raw(struct iio_dev *iio_device, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -191,6 +234,10 @@ static int ltr390_read_raw(struct iio_dev *iio_device, *val = data->int_time_us; return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = ltr390_get_samp_freq_or_period(data, LTR390_GET_FREQ); + return IIO_VAL_INT; + default: return -EINVAL; } @@ -199,6 +246,24 @@ static int ltr390_read_raw(struct iio_dev *iio_device, /* integration time in us */ static const int ltr390_int_time_map_us[] = { 400000, 200000, 100000, 50000, 25000, 12500 }; static const int ltr390_gain_map[] = { 1, 3, 6, 9, 18 }; +static const int ltr390_freq_map[] = { 40000, 20000, 10000, 5000, 2000, 1000, 500, 500 }; + +static const struct iio_event_spec ltr390_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD), + } +}; static const struct iio_chan_spec ltr390_channels[] = { /* UV sensor */ @@ -206,16 +271,24 @@ static const struct iio_chan_spec ltr390_channels[] = { .type = IIO_UVINDEX, .scan_index = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 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) | BIT(IIO_CHAN_INFO_SCALE) + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .event_spec = ltr390_event_spec, + .num_event_specs = ARRAY_SIZE(ltr390_event_spec), }, /* ALS sensor */ { .type = IIO_LIGHT, .scan_index = 1, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 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) | BIT(IIO_CHAN_INFO_SCALE) + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SAMP_FREQ), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .event_spec = ltr390_event_spec, + .num_event_specs = ARRAY_SIZE(ltr390_event_spec), }, }; @@ -264,6 +337,23 @@ static int ltr390_set_int_time(struct ltr390_data *data, int val) return -EINVAL; } +static int ltr390_set_samp_freq(struct ltr390_data *data, int val) +{ + int idx; + + for (idx = 0; idx < ARRAY_SIZE(ltr390_samp_freq_table); idx++) { + if (ltr390_samp_freq_table[idx][0] != val) + continue; + + guard(mutex)(&data->lock); + return regmap_update_bits(data->regmap, + LTR390_ALS_UVS_MEAS_RATE, + LTR390_ALS_UVS_MEAS_RATE_MASK, idx); + } + + return -EINVAL; +} + static int ltr390_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, const int **vals, int *type, int *length, long mask) { @@ -278,6 +368,11 @@ static int ltr390_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec con *type = IIO_VAL_INT; *vals = ltr390_int_time_map_us; return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *length = ARRAY_SIZE(ltr390_freq_map); + *type = IIO_VAL_INT; + *vals = ltr390_freq_map; + return IIO_AVAIL_LIST; default: return -EINVAL; } @@ -301,6 +396,191 @@ static int ltr390_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons return ltr390_set_int_time(data, val); + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2 != 0) + return -EINVAL; + + return ltr390_set_samp_freq(data, val); + + default: + return -EINVAL; + } +} + +static int ltr390_read_intr_prst(struct ltr390_data *data, int *val) +{ + int ret, prst, samp_period; + + samp_period = ltr390_get_samp_freq_or_period(data, LTR390_GET_PERIOD); + ret = regmap_read(data->regmap, LTR390_INT_PST, &prst); + if (ret < 0) + return ret; + *val = prst * samp_period; + + return IIO_VAL_INT; +} + +static int ltr390_write_intr_prst(struct ltr390_data *data, int val) +{ + int ret, samp_period, new_val; + + samp_period = ltr390_get_samp_freq_or_period(data, LTR390_GET_PERIOD); + + /* persist period should be greater than or equal to samp period */ + if (val < samp_period) + return -EINVAL; + + new_val = DIV_ROUND_UP(val, samp_period); + if (new_val < 0 || new_val > 0x0f) + return -EINVAL; + + guard(mutex)(&data->lock); + ret = regmap_update_bits(data->regmap, + LTR390_INT_PST, + LTR390_INT_PST_MASK, + LTR390_INT_PST_VAL(new_val)); + if (ret) + return ret; + + return 0; +} + +static int ltr390_read_threshold(struct iio_dev *indio_dev, + enum iio_event_direction dir, + int *val, int *val2) +{ + struct ltr390_data *data = iio_priv(indio_dev); + int ret; + + switch (dir) { + case IIO_EV_DIR_RISING: + ret = ltr390_register_read(data, LTR390_THRESH_UP); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + + case IIO_EV_DIR_FALLING: + ret = ltr390_register_read(data, LTR390_THRESH_LOW); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ltr390_write_threshold(struct iio_dev *indio_dev, + enum iio_event_direction dir, + int val, int val2) +{ + struct ltr390_data *data = iio_priv(indio_dev); + + guard(mutex)(&data->lock); + switch (dir) { + case IIO_EV_DIR_RISING: + return regmap_bulk_write(data->regmap, LTR390_THRESH_UP, &val, 3); + + case IIO_EV_DIR_FALLING: + return regmap_bulk_write(data->regmap, LTR390_THRESH_LOW, &val, 3); + + default: + return -EINVAL; + } +} + +static int ltr390_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) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + return ltr390_read_threshold(indio_dev, dir, val, val2); + + case IIO_EV_INFO_PERIOD: + return ltr390_read_intr_prst(iio_priv(indio_dev), val); + + default: + return -EINVAL; + } +} + +static int ltr390_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) +{ + switch (info) { + case IIO_EV_INFO_VALUE: + if (val2 != 0) + return -EINVAL; + + return ltr390_write_threshold(indio_dev, dir, val, val2); + + case IIO_EV_INFO_PERIOD: + if (val2 != 0) + return -EINVAL; + + return ltr390_write_intr_prst(iio_priv(indio_dev), val); + + default: + return -EINVAL; + } +} + +static int ltr390_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 ltr390_data *data = iio_priv(indio_dev); + int ret, status; + + ret = regmap_read(data->regmap, LTR390_INT_CFG, &status); + if (ret < 0) + return ret; + + return FIELD_GET(LTR390_LS_INT_EN, status); +} + +static int ltr390_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct ltr390_data *data = iio_priv(indio_dev); + int ret; + + if (!state) + return regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); + + guard(mutex)(&data->lock); + ret = regmap_set_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_EN); + if (ret < 0) + return ret; + + switch (chan->type) { + case IIO_LIGHT: + ret = ltr390_set_mode(data, LTR390_SET_ALS_MODE); + if (ret < 0) + return ret; + + return regmap_clear_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_SEL_UVS); + + case IIO_UVINDEX: + ret = ltr390_set_mode(data, LTR390_SET_UVS_MODE); + if (ret < 0) + return ret; + + return regmap_set_bits(data->regmap, LTR390_INT_CFG, LTR390_LS_INT_SEL_UVS); + default: return -EINVAL; } @@ -310,8 +590,44 @@ static const struct iio_info ltr390_info = { .read_raw = ltr390_read_raw, .write_raw = ltr390_write_raw, .read_avail = ltr390_read_avail, + .read_event_value = ltr390_read_event_value, + .read_event_config = ltr390_read_event_config, + .write_event_value = ltr390_write_event_value, + .write_event_config = ltr390_write_event_config, }; +static irqreturn_t ltr390_interrupt_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct ltr390_data *data = iio_priv(indio_dev); + int ret, status; + + /* Reading the status register to clear the interrupt flag, Datasheet pg: 17*/ + ret = regmap_read(data->regmap, LTR390_MAIN_STATUS, &status); + if (ret < 0) + return ret; + + switch (data->mode) { + case LTR390_SET_ALS_MODE: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + iio_get_time_ns(indio_dev)); + break; + + case LTR390_SET_UVS_MODE: + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_UVINDEX, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + iio_get_time_ns(indio_dev)); + break; + } + + return IRQ_HANDLED; +} + static int ltr390_probe(struct i2c_client *client) { struct ltr390_data *data; @@ -365,9 +681,40 @@ static int ltr390_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "failed to enable the sensor\n"); + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, + NULL, ltr390_interrupt_handler, + IRQF_ONESHOT, + "ltr390_thresh_event", + indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "request irq (%d) failed\n", client->irq); + } + return devm_iio_device_register(dev, indio_dev); } +static int ltr390_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ltr390_data *data = iio_priv(indio_dev); + + return regmap_clear_bits(data->regmap, LTR390_MAIN_CTRL, + LTR390_SENSOR_ENABLE); +} + +static int ltr390_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ltr390_data *data = iio_priv(indio_dev); + + return regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, + LTR390_SENSOR_ENABLE); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ltr390_pm_ops, ltr390_suspend, ltr390_resume); + static const struct i2c_device_id ltr390_id[] = { { "ltr390" }, { /* Sentinel */ } @@ -384,6 +731,7 @@ static struct i2c_driver ltr390_driver = { .driver = { .name = "ltr390", .of_match_table = ltr390_of_table, + .pm = pm_sleep_ptr(<r390_pm_ops), }, .probe = ltr390_probe, .id_table = ltr390_id, diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 8c516ede911619..604f5f900a2ecb 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -1078,15 +1077,11 @@ static int ltr501_read_event_config(struct iio_dev *indio_dev, static int ltr501_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) + enum iio_event_direction dir, bool state) { struct ltr501_data *data = iio_priv(indio_dev); int ret; - /* only 1 and 0 are valid inputs */ - if (state != 1 && state != 0) - return -EINVAL; - switch (chan->type) { case IIO_INTENSITY: mutex_lock(&data->lock_als); @@ -1422,17 +1417,6 @@ static int ltr501_powerdown(struct ltr501_data *data) data->ps_contr & ~LTR501_CONTR_ACTIVE); } -static const char *ltr501_match_acpi_device(struct device *dev, int *chip_idx) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - *chip_idx = id->driver_data; - return dev_name(dev); -} - static int ltr501_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -1440,8 +1424,10 @@ static int ltr501_probe(struct i2c_client *client) struct ltr501_data *data; struct iio_dev *indio_dev; struct regmap *regmap; - int ret, partid, chip_idx = 0; - const char *name = NULL; + const void *ddata = NULL; + int partid, chip_idx; + const char *name; + int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1523,11 +1509,12 @@ static int ltr501_probe(struct i2c_client *client) if (id) { name = id->name; chip_idx = id->driver_data; - } else if (ACPI_HANDLE(&client->dev)) { - name = ltr501_match_acpi_device(&client->dev, &chip_idx); } else { - return -ENODEV; + name = iio_get_acpi_device_name_and_data(&client->dev, &ddata); + chip_idx = (intptr_t)ddata; } + if (!name) + return -ENODEV; data->chip_info = <r501_chip_info_tbl[chip_idx]; @@ -1610,9 +1597,9 @@ static int ltr501_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume); static const struct acpi_device_id ltr_acpi_match[] = { - { "LTER0501", ltr501 }, - { "LTER0559", ltr559 }, { "LTER0301", ltr301 }, + /* https://www.catalog.update.microsoft.com/Search.aspx?q=lter0303 */ + { "LTER0303", ltr303 }, { }, }; MODULE_DEVICE_TABLE(acpi, ltr_acpi_match); diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c index 37eecff571b96b..dbec1e7cfeb863 100644 --- a/drivers/iio/light/ltrf216a.c +++ b/drivers/iio/light/ltrf216a.c @@ -561,6 +561,7 @@ MODULE_DEVICE_TABLE(i2c, ltrf216a_id); static const struct of_device_id ltrf216a_of_match[] = { { .compatible = "liteon,ltr308", .data = <r308_chip_info }, { .compatible = "liteon,ltrf216a", .data = <rf216a_chip_info }, + /* For Valve's Steamdeck device, an ACPI platform using PRP0001 */ { .compatible = "ltr,ltrf216a", .data = <rf216a_chip_info }, {} }; diff --git a/drivers/iio/light/max44009.c b/drivers/iio/light/max44009.c index 3b92362675dc96..8cd7f5664e5b1a 100644 --- a/drivers/iio/light/max44009.c +++ b/drivers/iio/light/max44009.c @@ -422,7 +422,7 @@ static int max44009_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) + bool state) { struct max44009_data *data = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index 176e54bb48c33b..65b295877b4158 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -70,6 +70,35 @@ #define OPT3001_RESULT_READY_SHORT 150 #define OPT3001_RESULT_READY_LONG 1000 +struct opt3001_scale { + int val; + int val2; +}; + +struct opt3001_chip_info { + const struct iio_chan_spec (*channels)[2]; + enum iio_chan_type chan_type; + int num_channels; + + const struct opt3001_scale (*scales)[12]; + /* + * Factor as specified by conversion equation in datasheet. + * eg. 0.01 (scaled to integer 10) for opt3001. + */ + int factor_whole; + /* + * Factor to compensate for potentially scaled factor_whole. + */ + int factor_integer; + /* + * Factor used to align decimal part of proccessed value to six decimal + * places. + */ + int factor_decimal; + + bool has_id; +}; + struct opt3001 { struct i2c_client *client; struct device *dev; @@ -79,6 +108,7 @@ struct opt3001 { bool result_ready; wait_queue_head_t result_ready_queue; u16 result; + const struct opt3001_chip_info *chip_info; u32 int_time; u32 mode; @@ -92,11 +122,6 @@ struct opt3001 { bool use_irq; }; -struct opt3001_scale { - int val; - int val2; -}; - static const struct opt3001_scale opt3001_scales[] = { { .val = 40, @@ -148,21 +173,68 @@ static const struct opt3001_scale opt3001_scales[] = { }, }; +static const struct opt3001_scale opt3002_scales[] = { + { + .val = 4914, + .val2 = 0, + }, + { + .val = 9828, + .val2 = 0, + }, + { + .val = 19656, + .val2 = 0, + }, + { + .val = 39312, + .val2 = 0, + }, + { + .val = 78624, + .val2 = 0, + }, + { + .val = 157248, + .val2 = 0, + }, + { + .val = 314496, + .val2 = 0, + }, + { + .val = 628992, + .val2 = 0, + }, + { + .val = 1257984, + .val2 = 0, + }, + { + .val = 2515968, + .val2 = 0, + }, + { + .val = 5031936, + .val2 = 0, + }, + { + .val = 10063872, + .val2 = 0, + }, +}; + static int opt3001_find_scale(const struct opt3001 *opt, int val, int val2, u8 *exponent) { int i; - - for (i = 0; i < ARRAY_SIZE(opt3001_scales); i++) { - const struct opt3001_scale *scale = &opt3001_scales[i]; - + for (i = 0; i < ARRAY_SIZE(*opt->chip_info->scales); i++) { + const struct opt3001_scale *scale = &(*opt->chip_info->scales)[i]; /* - * Combine the integer and micro parts for comparison - * purposes. Use milli lux precision to avoid 32-bit integer - * overflows. + * Compare the integer and micro parts to determine value scale. */ - if ((val * 1000 + val2 / 1000) <= - (scale->val * 1000 + scale->val2 / 1000)) { + if (val < scale->val || + (val == scale->val && val2 <= scale->val2)) { *exponent = i; return 0; } @@ -174,11 +246,14 @@ static int opt3001_find_scale(const struct opt3001 *opt, int val, static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, u16 mantissa, int *val, int *val2) { - int lux; + int ret; + int whole = opt->chip_info->factor_whole; + int integer = opt->chip_info->factor_integer; + int decimal = opt->chip_info->factor_decimal; - lux = 10 * (mantissa << exponent); - *val = lux / 1000; - *val2 = (lux - (*val * 1000)) * 1000; + ret = whole * (mantissa << exponent); + *val = ret / integer; + *val2 = (ret - (*val * integer)) * decimal; } static void opt3001_set_mode(struct opt3001 *opt, u16 *reg, u16 mode) @@ -225,7 +300,18 @@ static const struct iio_chan_spec opt3001_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1), }; -static int opt3001_get_lux(struct opt3001 *opt, int *val, int *val2) +static const struct iio_chan_spec opt3002_channels[] = { + { + .type = IIO_INTENSITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME), + .event_spec = opt3001_event_spec, + .num_event_specs = ARRAY_SIZE(opt3001_event_spec), + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static int opt3001_get_processed(struct opt3001 *opt, int *val, int *val2) { int ret; u16 mantissa; @@ -397,14 +483,15 @@ static int opt3001_read_raw(struct iio_dev *iio, if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY; - if (chan->type != IIO_LIGHT) + if (chan->type != opt->chip_info->chan_type) return -EINVAL; mutex_lock(&opt->lock); switch (mask) { + case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: - ret = opt3001_get_lux(opt, val, val2); + ret = opt3001_get_processed(opt, val, val2); break; case IIO_CHAN_INFO_INT_TIME: ret = opt3001_get_int_time(opt, val, val2); @@ -428,7 +515,7 @@ static int opt3001_write_raw(struct iio_dev *iio, if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) return -EBUSY; - if (chan->type != IIO_LIGHT) + if (chan->type != opt->chip_info->chan_type) return -EINVAL; if (mask != IIO_CHAN_INFO_INT_TIME) @@ -479,6 +566,9 @@ static int opt3001_write_event_value(struct iio_dev *iio, { struct opt3001 *opt = iio_priv(iio); int ret; + int whole; + int integer; + int decimal; u16 mantissa; u16 value; @@ -497,7 +587,12 @@ static int opt3001_write_event_value(struct iio_dev *iio, goto err; } - mantissa = (((val * 1000) + (val2 / 1000)) / 10) >> exponent; + whole = opt->chip_info->factor_whole; + integer = opt->chip_info->factor_integer; + decimal = opt->chip_info->factor_decimal; + + mantissa = (((val * integer) + (val2 / decimal)) / whole) >> exponent; + value = (exponent << 12) | mantissa; switch (dir) { @@ -539,7 +634,7 @@ static int opt3001_read_event_config(struct iio_dev *iio, static int opt3001_write_event_config(struct iio_dev *iio, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { struct opt3001 *opt = iio_priv(iio); int ret; @@ -610,7 +705,7 @@ static int opt3001_read_id(struct opt3001 *opt) ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID); if (ret < 0) { dev_err(opt->dev, "failed to read register %02x\n", - OPT3001_DEVICE_ID); + OPT3001_DEVICE_ID); return ret; } @@ -692,6 +787,7 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) struct opt3001 *opt = iio_priv(iio); int ret; bool wake_result_ready_queue = false; + enum iio_chan_type chan_type = opt->chip_info->chan_type; if (!opt->ok_to_ignore_lock) mutex_lock(&opt->lock); @@ -707,13 +803,13 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) OPT3001_CONFIGURATION_M_CONTINUOUS) { if (ret & OPT3001_CONFIGURATION_FH) iio_push_event(iio, - IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_UNMOD_EVENT_CODE(chan_type, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), iio_get_time_ns(iio)); if (ret & OPT3001_CONFIGURATION_FL) iio_push_event(iio, - IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_UNMOD_EVENT_CODE(chan_type, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), iio_get_time_ns(iio)); @@ -755,22 +851,25 @@ static int opt3001_probe(struct i2c_client *client) opt = iio_priv(iio); opt->client = client; opt->dev = dev; + opt->chip_info = i2c_get_match_data(client); mutex_init(&opt->lock); init_waitqueue_head(&opt->result_ready_queue); i2c_set_clientdata(client, iio); - ret = opt3001_read_id(opt); - if (ret) - return ret; + if (opt->chip_info->has_id) { + ret = opt3001_read_id(opt); + if (ret) + return ret; + } ret = opt3001_configure(opt); if (ret) return ret; iio->name = client->name; - iio->channels = opt3001_channels; - iio->num_channels = ARRAY_SIZE(opt3001_channels); + iio->channels = *opt->chip_info->channels; + iio->num_channels = opt->chip_info->num_channels; iio->modes = INDIO_DIRECT_MODE; iio->info = &opt3001_info; @@ -825,14 +924,38 @@ static void opt3001_remove(struct i2c_client *client) } } +static const struct opt3001_chip_info opt3001_chip_information = { + .channels = &opt3001_channels, + .chan_type = IIO_LIGHT, + .num_channels = ARRAY_SIZE(opt3001_channels), + .scales = &opt3001_scales, + .factor_whole = 10, + .factor_integer = 1000, + .factor_decimal = 1000, + .has_id = true, +}; + +static const struct opt3001_chip_info opt3002_chip_information = { + .channels = &opt3002_channels, + .chan_type = IIO_INTENSITY, + .num_channels = ARRAY_SIZE(opt3002_channels), + .scales = &opt3002_scales, + .factor_whole = 12, + .factor_integer = 10, + .factor_decimal = 100000, + .has_id = false, +}; + static const struct i2c_device_id opt3001_id[] = { - { "opt3001" }, + { "opt3001", (kernel_ulong_t)&opt3001_chip_information }, + { "opt3002", (kernel_ulong_t)&opt3002_chip_information }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(i2c, opt3001_id); static const struct of_device_id opt3001_of_match[] = { - { .compatible = "ti,opt3001" }, + { .compatible = "ti,opt3001", .data = &opt3001_chip_information }, + { .compatible = "ti,opt3002", .data = &opt3002_chip_information }, { } }; MODULE_DEVICE_TABLE(of, opt3001_of_match); diff --git a/drivers/iio/light/rohm-bu27008.c b/drivers/iio/light/rohm-bu27008.c index 0f010eff1981fb..fa35dd32700ce3 100644 --- a/drivers/iio/light/rohm-bu27008.c +++ b/drivers/iio/light/rohm-bu27008.c @@ -1632,4 +1632,4 @@ module_i2c_driver(bu27008_i2c_driver); MODULE_DESCRIPTION("ROHM BU27008 and BU27010 colour sensor driver"); MODULE_AUTHOR("Matti Vaittinen "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_GTS_HELPER); +MODULE_IMPORT_NS("IIO_GTS_HELPER"); diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c index 76711c3cdf7c02..4f591c2278f21f 100644 --- a/drivers/iio/light/rohm-bu27034.c +++ b/drivers/iio/light/rohm-bu27034.c @@ -1350,4 +1350,4 @@ 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); +MODULE_IMPORT_NS("IIO_GTS_HELPER"); diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 78c08e0bd0776a..56f5fbbf79ac70 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -438,18 +438,6 @@ static irqreturn_t rpr0521_drdy_irq_thread(int irq, void *private) return IRQ_NONE; } -static irqreturn_t rpr0521_trigger_consumer_store_time(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - - /* Other trigger polls store time here. */ - if (!iio_trigger_using_own(indio_dev)) - pf->timestamp = iio_get_time_ns(indio_dev); - - return IRQ_WAKE_THREAD; -} - static irqreturn_t rpr0521_trigger_consumer_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -1016,7 +1004,7 @@ static int rpr0521_probe(struct i2c_client *client) /* Trigger consumer setup */ ret = devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, - rpr0521_trigger_consumer_store_time, + iio_pollfunc_store_time, rpr0521_trigger_consumer_handler, &rpr0521_buffer_setup_ops); if (ret < 0) { diff --git a/drivers/iio/light/st_uvis25_core.c b/drivers/iio/light/st_uvis25_core.c index fba3997574bbf4..40a810000df066 100644 --- a/drivers/iio/light/st_uvis25_core.c +++ b/drivers/iio/light/st_uvis25_core.c @@ -174,8 +174,7 @@ static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev) unsigned long irq_type; int err; - irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); - + irq_type = irq_get_trigger_type(hw->irq); switch (irq_type) { case IRQF_TRIGGER_HIGH: case IRQF_TRIGGER_RISING: @@ -323,7 +322,7 @@ int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap) return devm_iio_device_register(dev, iio_dev); } -EXPORT_SYMBOL_NS(st_uvis25_probe, IIO_UVIS25); +EXPORT_SYMBOL_NS(st_uvis25_probe, "IIO_UVIS25"); static int st_uvis25_suspend(struct device *dev) { diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index 6bc2ddfb77ca63..f54282476d11d6 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -65,4 +65,4 @@ module_i2c_driver(st_uvis25_driver); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("STMicroelectronics uvis25 i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_UVIS25); +MODULE_IMPORT_NS("IIO_UVIS25"); diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c index 86a232320d7d71..18edc6a5a4a4fe 100644 --- a/drivers/iio/light/st_uvis25_spi.c +++ b/drivers/iio/light/st_uvis25_spi.c @@ -66,4 +66,4 @@ module_spi_driver(st_uvis25_driver); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("STMicroelectronics uvis25 spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_UVIS25); +MODULE_IMPORT_NS("IIO_UVIS25"); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index ed20b67145463d..b81cc44db43c37 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -324,15 +324,12 @@ static int stk3310_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) + bool state) { int ret; struct stk3310_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; - if (state < 0 || state > 7) - return -EINVAL; - /* Set INT_PS value */ mutex_lock(&data->lock); ret = regmap_field_write(data->reg_int_ps, state); diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 04452b4664f306..4186aac04902e6 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -327,7 +327,7 @@ static int tcs3472_read_event_config(struct iio_dev *indio_dev, static int tcs3472_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) + enum iio_event_direction dir, bool state) { struct tcs3472_data *data = iio_priv(indio_dev); int ret = 0; diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 1a6f514bced6e0..f1fe7640fce63b 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -630,7 +630,7 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private) static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { struct tsl2563_chip *chip = iio_priv(indio_dev); int ret = 0; diff --git a/drivers/iio/light/tsl2591.c b/drivers/iio/light/tsl2591.c index 850c2465992fa0..b81ca6f73f9273 100644 --- a/drivers/iio/light/tsl2591.c +++ b/drivers/iio/light/tsl2591.c @@ -985,7 +985,7 @@ static int tsl2591_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) + bool state) { struct tsl2591_chip *chip = iio_priv(indio_dev); struct i2c_client *client = chip->client; diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index cab468a82b616a..349afdcbe30dd0 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -1081,14 +1081,14 @@ static int tsl2772_write_interrupt_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - int val) + bool val) { struct tsl2772_chip *chip = iio_priv(indio_dev); if (chan->type == IIO_INTENSITY) - chip->settings.als_interrupt_en = val ? true : false; + chip->settings.als_interrupt_en = val; else - chip->settings.prox_interrupt_en = val ? true : false; + chip->settings.prox_interrupt_en = val; return tsl2772_invoke_change(indio_dev); } diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index de6967ac3b0b3b..c83114aed6b23f 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -627,7 +627,7 @@ static int us5182d_read_event_config(struct iio_dev *indio_dev, static int us5182d_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) + enum iio_event_direction dir, bool state) { struct us5182d_data *data = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 4e3641ff2ed446..e19199b17f2ef7 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -1456,7 +1456,7 @@ static int vcnl4010_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) + bool state) { switch (chan->type) { case IIO_PROXIMITY: @@ -1501,7 +1501,8 @@ static int vcnl4040_read_event_config(struct iio_dev *indio_dev, static int vcnl4040_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) + enum iio_event_direction dir, + bool state) { int ret = -EINVAL; u16 val, mask; diff --git a/drivers/iio/light/veml3235.c b/drivers/iio/light/veml3235.c new file mode 100644 index 00000000000000..66361c3012a3d9 --- /dev/null +++ b/drivers/iio/light/veml3235.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * VEML3235 Ambient Light Sensor + * + * Copyright (c) 2024, Javier Carrasco + * + * Datasheet: https://www.vishay.com/docs/80131/veml3235.pdf + * Appnote-80222: https://www.vishay.com/docs/80222/designingveml3235.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +#define VEML3235_REG_CONF 0x00 +#define VEML3235_REG_WH_DATA 0x04 +#define VEML3235_REG_ALS_DATA 0x05 +#define VEML3235_REG_ID 0x09 + +#define VEML3235_CONF_SD BIT(0) +#define VEML3235_CONF_SD0 BIT(15) + +struct veml3235_rf { + struct regmap_field *it; + struct regmap_field *gain; + struct regmap_field *id; +}; + +struct veml3235_data { + struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + struct veml3235_rf rf; +}; + +static const int veml3235_it_times[][2] = { + { 0, 50000 }, + { 0, 100000 }, + { 0, 200000 }, + { 0, 400000 }, + { 0, 800000 }, +}; + +static const int veml3235_scale_vals[] = { 1, 2, 4, 8 }; + +static int veml3235_power_on(struct veml3235_data *data) +{ + int ret; + + ret = regmap_clear_bits(data->regmap, VEML3235_REG_CONF, + VEML3235_CONF_SD | VEML3235_CONF_SD0); + if (ret) + return ret; + + /* Wait 4 ms to let processor & oscillator start correctly */ + fsleep(4000); + + return 0; +} + +static int veml3235_shut_down(struct veml3235_data *data) +{ + return regmap_set_bits(data->regmap, VEML3235_REG_CONF, + VEML3235_CONF_SD | VEML3235_CONF_SD0); +} + +static void veml3235_shut_down_action(void *data) +{ + veml3235_shut_down(data); +} + +enum veml3235_chan { + CH_ALS, + CH_WHITE, +}; + +static const struct iio_chan_spec veml3235_channels[] = { + { + .type = IIO_LIGHT, + .channel = CH_ALS, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_INTENSITY, + .channel = CH_WHITE, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static const struct regmap_config veml3235_regmap_config = { + .name = "veml3235_regmap", + .reg_bits = 8, + .val_bits = 16, + .max_register = VEML3235_REG_ID, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +static int veml3235_get_it(struct veml3235_data *data, int *val, int *val2) +{ + int ret, reg; + + ret = regmap_field_read(data->rf.it, ®); + if (ret) + return ret; + + switch (reg) { + case 0: + *val2 = 50000; + break; + case 1: + *val2 = 100000; + break; + case 2: + *val2 = 200000; + break; + case 3: + *val2 = 400000; + break; + case 4: + *val2 = 800000; + break; + default: + return -EINVAL; + } + + *val = 0; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml3235_set_it(struct iio_dev *indio_dev, int val, int val2) +{ + struct veml3235_data *data = iio_priv(indio_dev); + int ret, new_it; + + if (val) + return -EINVAL; + + switch (val2) { + case 50000: + new_it = 0x00; + break; + case 100000: + new_it = 0x01; + break; + case 200000: + new_it = 0x02; + break; + case 400000: + new_it = 0x03; + break; + case 800000: + new_it = 0x04; + break; + default: + return -EINVAL; + } + + ret = regmap_field_write(data->rf.it, new_it); + if (ret) { + dev_err(data->dev, + "failed to update integration time: %d\n", ret); + return ret; + } + + return 0; +} + +static int veml3235_set_gain(struct iio_dev *indio_dev, int val, int val2) +{ + struct veml3235_data *data = iio_priv(indio_dev); + int ret, new_gain; + + if (val2 != 0) + return -EINVAL; + + switch (val) { + case 1: + new_gain = 0x00; + break; + case 2: + new_gain = 0x01; + break; + case 4: + new_gain = 0x03; + break; + case 8: + new_gain = 0x07; + break; + default: + return -EINVAL; + } + + ret = regmap_field_write(data->rf.gain, new_gain); + if (ret) { + dev_err(data->dev, "failed to set gain: %d\n", ret); + return ret; + } + + return 0; +} + +static int veml3235_get_gain(struct veml3235_data *data, int *val) +{ + int ret, reg; + + ret = regmap_field_read(data->rf.gain, ®); + if (ret) { + dev_err(data->dev, "failed to read gain %d\n", ret); + return ret; + } + + switch (reg & 0x03) { + case 0: + *val = 1; + break; + case 1: + *val = 2; + break; + case 3: + *val = 4; + break; + default: + return -EINVAL; + } + + /* Double gain */ + if (reg & 0x04) + *val *= 2; + + return IIO_VAL_INT; +} + +static int veml3235_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct veml3235_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + int ret, reg; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_LIGHT: + ret = regmap_read(regmap, VEML3235_REG_ALS_DATA, ®); + if (ret < 0) + return ret; + + *val = reg; + return IIO_VAL_INT; + case IIO_INTENSITY: + ret = regmap_read(regmap, VEML3235_REG_WH_DATA, ®); + if (ret < 0) + return ret; + + *val = reg; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_INT_TIME: + return veml3235_get_it(data, val, val2); + case IIO_CHAN_INFO_SCALE: + return veml3235_get_gain(data, val); + default: + return -EINVAL; + } +} + +static int veml3235_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *vals = (int *)&veml3235_it_times; + *length = 2 * ARRAY_SIZE(veml3235_it_times); + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (int *)&veml3235_scale_vals; + *length = ARRAY_SIZE(veml3235_scale_vals); + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int veml3235_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return veml3235_set_it(indio_dev, val, val2); + case IIO_CHAN_INFO_SCALE: + return veml3235_set_gain(indio_dev, val, val2); + } + + return -EINVAL; +} + +static void veml3235_read_id(struct veml3235_data *data) +{ + int ret, reg; + + ret = regmap_field_read(data->rf.id, ®); + if (ret) { + dev_info(data->dev, "failed to read ID\n"); + return; + } + + if (reg != 0x35) + dev_info(data->dev, "Unknown ID %d\n", reg); +} + +static const struct reg_field veml3235_rf_it = + REG_FIELD(VEML3235_REG_CONF, 4, 6); + +static const struct reg_field veml3235_rf_gain = + REG_FIELD(VEML3235_REG_CONF, 11, 13); + +static const struct reg_field veml3235_rf_id = + REG_FIELD(VEML3235_REG_ID, 0, 7); + +static int veml3235_regfield_init(struct veml3235_data *data) +{ + struct regmap *regmap = data->regmap; + struct device *dev = data->dev; + struct regmap_field *rm_field; + struct veml3235_rf *rf = &data->rf; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_it); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->it = rm_field; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_gain); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->gain = rm_field; + + rm_field = devm_regmap_field_alloc(dev, regmap, veml3235_rf_id); + if (IS_ERR(rm_field)) + return PTR_ERR(rm_field); + rf->id = rm_field; + + return 0; +} + +static int veml3235_hw_init(struct iio_dev *indio_dev) +{ + struct veml3235_data *data = iio_priv(indio_dev); + struct device *dev = data->dev; + int ret; + + /* Set gain to 1 and integration time to 100 ms */ + ret = regmap_field_write(data->rf.gain, 0x00); + if (ret) + return dev_err_probe(data->dev, ret, "failed to set gain\n"); + + ret = regmap_field_write(data->rf.it, 0x01); + if (ret) + return dev_err_probe(data->dev, ret, + "failed to set integration time\n"); + + ret = veml3235_power_on(data); + if (ret) + return dev_err_probe(dev, ret, "failed to power on\n"); + + return devm_add_action_or_reset(dev, veml3235_shut_down_action, data); +} + +static const struct iio_info veml3235_info = { + .read_raw = veml3235_read_raw, + .read_avail = veml3235_read_avail, + .write_raw = veml3235_write_raw, +}; + +static int veml3235_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct veml3235_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_i2c(client, &veml3235_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "failed to setup regmap\n"); + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + data->dev = dev; + data->regmap = regmap; + + ret = veml3235_regfield_init(data); + if (ret) + return dev_err_probe(dev, ret, "failed to init regfield\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable regulator\n"); + + indio_dev->name = "veml3235"; + indio_dev->channels = veml3235_channels; + indio_dev->num_channels = ARRAY_SIZE(veml3235_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &veml3235_info; + + veml3235_read_id(data); + + ret = veml3235_hw_init(indio_dev); + if (ret < 0) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static int veml3235_runtime_suspend(struct device *dev) +{ + struct veml3235_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = veml3235_shut_down(data); + if (ret < 0) + dev_err(data->dev, "failed to suspend: %d\n", ret); + + return ret; +} + +static int veml3235_runtime_resume(struct device *dev) +{ + struct veml3235_data *data = iio_priv(dev_get_drvdata(dev)); + int ret; + + ret = veml3235_power_on(data); + if (ret < 0) + dev_err(data->dev, "failed to resume: %d\n", ret); + + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(veml3235_pm_ops, veml3235_runtime_suspend, + veml3235_runtime_resume, NULL); + +static const struct of_device_id veml3235_of_match[] = { + { .compatible = "vishay,veml3235" }, + { } +}; +MODULE_DEVICE_TABLE(of, veml3235_of_match); + +static const struct i2c_device_id veml3235_id[] = { + { "veml3235" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, veml3235_id); + +static struct i2c_driver veml3235_driver = { + .driver = { + .name = "veml3235", + .of_match_table = veml3235_of_match, + .pm = pm_ptr(&veml3235_pm_ops), + }, + .probe = veml3235_probe, + .id_table = veml3235_id, +}; +module_i2c_driver(veml3235_driver); + +MODULE_AUTHOR("Javier Carrasco "); +MODULE_DESCRIPTION("VEML3235 Ambient Light Sensor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/veml6030.c b/drivers/iio/light/veml6030.c index 621428885455c0..ccb43dfd5cf782 100644 --- a/drivers/iio/light/veml6030.c +++ b/drivers/iio/light/veml6030.c @@ -1,19 +1,30 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * VEML6030 Ambient Light Sensor + * VEML6030, VMEL6035 and VEML7700 Ambient Light Sensors * * Copyright (c) 2019, Rishi Gupta * + * VEML6030: * Datasheet: https://www.vishay.com/docs/84366/veml6030.pdf * Appnote-84367: https://www.vishay.com/docs/84367/designingveml6030.pdf + * + * VEML6035: + * Datasheet: https://www.vishay.com/docs/84889/veml6035.pdf + * Appnote-84944: https://www.vishay.com/docs/84944/designingveml6035.pdf + * + * VEML7700: + * Datasheet: https://www.vishay.com/docs/84286/veml7700.pdf + * Appnote-84323: https://www.vishay.com/docs/84323/designingveml7700.pdf */ +#include #include #include #include #include #include #include +#include #include #include #include @@ -38,16 +49,35 @@ #define VEML6030_ALS_INT_EN BIT(1) #define VEML6030_ALS_SD BIT(0) +#define VEML6035_GAIN_M GENMASK(12, 10) +#define VEML6035_GAIN BIT(10) +#define VEML6035_DG BIT(11) +#define VEML6035_SENS BIT(12) +#define VEML6035_INT_CHAN BIT(3) +#define VEML6035_CHAN_EN BIT(2) + +struct veml603x_chip { + const char *name; + const int(*scale_vals)[][2]; + const int num_scale_vals; + const struct iio_chan_spec *channels; + const int num_channels; + int (*hw_init)(struct iio_dev *indio_dev, struct device *dev); + int (*set_info)(struct iio_dev *indio_dev); + int (*set_als_gain)(struct iio_dev *indio_dev, int val, int val2); + int (*get_als_gain)(struct iio_dev *indio_dev, int *val, int *val2); +}; + /* * The resolution depends on both gain and integration time. The * cur_resolution stores one of the resolution mentioned in the * table during startup and gets updated whenever integration time * or gain is changed. * - * Table 'resolution and maximum detection range' in appnote 84367 + * Table 'resolution and maximum detection range' in the appnotes * is visualized as a 2D array. The cur_gain stores index of gain - * in this table (0-3) while the cur_integration_time holds index - * of integration time (0-5). + * in this table (0-3 for VEML6030, 0-5 for VEML6035) while the + * cur_integration_time holds index of integration time (0-5). */ struct veml6030_data { struct i2c_client *client; @@ -55,27 +85,37 @@ struct veml6030_data { int cur_resolution; int cur_gain; int cur_integration_time; + const struct veml603x_chip *chip; }; -/* Integration time available in seconds */ -static IIO_CONST_ATTR(in_illuminance_integration_time_available, - "0.025 0.05 0.1 0.2 0.4 0.8"); +static const int veml6030_it_times[][2] = { + { 0, 25000 }, + { 0, 50000 }, + { 0, 100000 }, + { 0, 200000 }, + { 0, 400000 }, + { 0, 800000 }, +}; /* * Scale is 1/gain. Value 0.125 is ALS gain x (1/8), 0.25 is - * ALS gain x (1/4), 1.0 = ALS gain x 1 and 2.0 is ALS gain x 2. + * ALS gain x (1/4), 0.5 is ALS gain x (1/2), 1.0 is ALS gain x 1, + * 2.0 is ALS gain x2, and 4.0 is ALS gain x 4. */ -static IIO_CONST_ATTR(in_illuminance_scale_available, - "0.125 0.25 1.0 2.0"); - -static struct attribute *veml6030_attributes[] = { - &iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr, - &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, - NULL +static const int veml6030_scale_vals[][2] = { + { 0, 125000 }, + { 0, 250000 }, + { 1, 0 }, + { 2, 0 }, }; -static const struct attribute_group veml6030_attr_group = { - .attrs = veml6030_attributes, +static const int veml6035_scale_vals[][2] = { + { 0, 125000 }, + { 0, 250000 }, + { 0, 500000 }, + { 1, 0 }, + { 2, 0 }, + { 4, 0 }, }; /* @@ -143,14 +183,23 @@ static const struct attribute_group veml6030_event_attr_group = { static int veml6030_als_pwr_on(struct veml6030_data *data) { - return regmap_clear_bits(data->regmap, VEML6030_REG_ALS_CONF, - VEML6030_ALS_SD); + int ret; + + ret = regmap_clear_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_SD); + if (ret) + return ret; + + /* Wait 4 ms to let processor & oscillator start correctly */ + fsleep(4000); + + return 0; } static int veml6030_als_shut_down(struct veml6030_data *data) { - return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, - VEML6030_ALS_SD, 1); + return regmap_set_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6030_ALS_SD); } static void veml6030_als_shut_down_action(void *data) @@ -189,6 +238,8 @@ static const struct iio_chan_spec veml6030_channels[] = { BIT(IIO_CHAN_INFO_PROCESSED) | BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), .event_spec = veml6030_event_spec, .num_event_specs = ARRAY_SIZE(veml6030_event_spec), }, @@ -198,7 +249,34 @@ static const struct iio_chan_spec veml6030_channels[] = { .modified = 1, .channel2 = IIO_MOD_LIGHT_BOTH, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_PROCESSED), + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static const struct iio_chan_spec veml7700_channels[] = { + { + .type = IIO_LIGHT, + .channel = CH_ALS, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_INTENSITY, + .channel = CH_WHITE, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_SCALE), }, }; @@ -371,6 +449,21 @@ static int veml6030_write_persistence(struct iio_dev *indio_dev, return ret; } +/* + * Cache currently set gain & update resolution. For every + * increase in the gain to next level, resolution is halved + * and vice-versa. + */ +static void veml6030_update_gain_res(struct veml6030_data *data, int gain_idx) +{ + if (data->cur_gain < gain_idx) + data->cur_resolution <<= gain_idx - data->cur_gain; + else if (data->cur_gain > gain_idx) + data->cur_resolution >>= data->cur_gain - gain_idx; + + data->cur_gain = gain_idx; +} + static int veml6030_set_als_gain(struct iio_dev *indio_dev, int val, int val2) { @@ -401,19 +494,49 @@ static int veml6030_set_als_gain(struct iio_dev *indio_dev, return ret; } - /* - * Cache currently set gain & update resolution. For every - * increase in the gain to next level, resolution is halved - * and vice-versa. - */ - if (data->cur_gain < gain_idx) - data->cur_resolution <<= gain_idx - data->cur_gain; - else if (data->cur_gain > gain_idx) - data->cur_resolution >>= data->cur_gain - gain_idx; + veml6030_update_gain_res(data, gain_idx); - data->cur_gain = gain_idx; + return 0; +} - return ret; +static int veml6035_set_als_gain(struct iio_dev *indio_dev, int val, int val2) +{ + int ret, new_gain, gain_idx; + struct veml6030_data *data = iio_priv(indio_dev); + + if (val == 0 && val2 == 125000) { + new_gain = VEML6035_SENS; + gain_idx = 5; + } else if (val == 0 && val2 == 250000) { + new_gain = VEML6035_SENS | VEML6035_GAIN; + gain_idx = 4; + } else if (val == 0 && val2 == 500000) { + new_gain = VEML6035_SENS | VEML6035_GAIN | + VEML6035_DG; + gain_idx = 3; + } else if (val == 1 && val2 == 0) { + new_gain = 0x0000; + gain_idx = 2; + } else if (val == 2 && val2 == 0) { + new_gain = VEML6035_GAIN; + gain_idx = 1; + } else if (val == 4 && val2 == 0) { + new_gain = VEML6035_GAIN | VEML6035_DG; + gain_idx = 0; + } else { + return -EINVAL; + } + + ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF, + VEML6035_GAIN_M, new_gain); + if (ret) { + dev_err(&data->client->dev, "can't set als gain %d\n", ret); + return ret; + } + + veml6030_update_gain_res(data, gain_idx); + + return 0; } static int veml6030_get_als_gain(struct iio_dev *indio_dev, @@ -453,6 +576,52 @@ static int veml6030_get_als_gain(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_MICRO; } +static int veml6035_get_als_gain(struct iio_dev *indio_dev, int *val, int *val2) +{ + int ret, reg; + struct veml6030_data *data = iio_priv(indio_dev); + + ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, ®); + if (ret) { + dev_err(&data->client->dev, + "can't read als conf register %d\n", ret); + return ret; + } + + switch (FIELD_GET(VEML6035_GAIN_M, reg)) { + case 0: + *val = 1; + *val2 = 0; + break; + case 1: + case 2: + *val = 2; + *val2 = 0; + break; + case 3: + *val = 4; + *val2 = 0; + break; + case 4: + *val = 0; + *val2 = 125000; + break; + case 5: + case 6: + *val = 0; + *val2 = 250000; + break; + case 7: + *val = 0; + *val2 = 500000; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT_PLUS_MICRO; +} + static int veml6030_read_thresh(struct iio_dev *indio_dev, int *val, int *val2, int dir) { @@ -533,48 +702,54 @@ static int veml6030_read_raw(struct iio_dev *indio_dev, dev_err(dev, "can't read white data %d\n", ret); return ret; } - if (mask == IIO_CHAN_INFO_PROCESSED) { - *val = (reg * data->cur_resolution) / 10000; - *val2 = (reg * data->cur_resolution) % 10000; - return IIO_VAL_INT_PLUS_MICRO; - } *val = reg; return IIO_VAL_INT; default: return -EINVAL; } case IIO_CHAN_INFO_INT_TIME: - if (chan->type == IIO_LIGHT) - return veml6030_get_intgrn_tm(indio_dev, val, val2); - return -EINVAL; + return veml6030_get_intgrn_tm(indio_dev, val, val2); case IIO_CHAN_INFO_SCALE: - if (chan->type == IIO_LIGHT) - return veml6030_get_als_gain(indio_dev, val, val2); - return -EINVAL; + return data->chip->get_als_gain(indio_dev, val, val2); default: return -EINVAL; } } +static int veml6030_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct veml6030_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *vals = (int *)&veml6030_it_times; + *length = 2 * ARRAY_SIZE(veml6030_it_times); + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (int *)*data->chip->scale_vals; + *length = 2 * data->chip->num_scale_vals; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + } + + return -EINVAL; +} + static int veml6030_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { + struct veml6030_data *data = iio_priv(indio_dev); + switch (mask) { case IIO_CHAN_INFO_INT_TIME: - switch (chan->type) { - case IIO_LIGHT: - return veml6030_set_intgrn_tm(indio_dev, val, val2); - default: - return -EINVAL; - } + return veml6030_set_intgrn_tm(indio_dev, val, val2); case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_LIGHT: - return veml6030_set_als_gain(indio_dev, val, val2); - default: - return -EINVAL; - } + return data->chip->set_als_gain(indio_dev, val, val2); default: return -EINVAL; } @@ -646,14 +821,11 @@ static int veml6030_read_interrupt_config(struct iio_dev *indio_dev, */ static int veml6030_write_interrupt_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir, int state) + enum iio_event_direction dir, bool state) { int ret; struct veml6030_data *data = iio_priv(indio_dev); - if (state < 0 || state > 1) - return -EINVAL; - ret = veml6030_als_shut_down(data); if (ret < 0) { dev_err(&data->client->dev, @@ -673,19 +845,19 @@ static int veml6030_write_interrupt_config(struct iio_dev *indio_dev, static const struct iio_info veml6030_info = { .read_raw = veml6030_read_raw, + .read_avail = veml6030_read_avail, .write_raw = veml6030_write_raw, .read_event_value = veml6030_read_event_val, .write_event_value = veml6030_write_event_val, .read_event_config = veml6030_read_interrupt_config, .write_event_config = veml6030_write_interrupt_config, - .attrs = &veml6030_attr_group, .event_attrs = &veml6030_event_attr_group, }; static const struct iio_info veml6030_info_no_irq = { .read_raw = veml6030_read_raw, + .read_avail = veml6030_read_avail, .write_raw = veml6030_write_raw, - .attrs = &veml6030_attr_group, }; static irqreturn_t veml6030_event_handler(int irq, void *private) @@ -717,65 +889,82 @@ static irqreturn_t veml6030_event_handler(int irq, void *private) return IRQ_HANDLED; } +static int veml6030_set_info(struct iio_dev *indio_dev) +{ + struct veml6030_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + int ret; + + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, veml6030_event_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "irq %d request failed\n", + client->irq); + + indio_dev->info = &veml6030_info; + } else { + indio_dev->info = &veml6030_info_no_irq; + } + + return 0; +} + +static int veml7700_set_info(struct iio_dev *indio_dev) +{ + indio_dev->info = &veml6030_info_no_irq; + + return 0; +} + /* * Set ALS gain to 1/8, integration time to 100 ms, PSM to mode 2, * persistence to 1 x integration time and the threshold * interrupt disabled by default. First shutdown the sensor, * update registers and then power on the sensor. */ -static int veml6030_hw_init(struct iio_dev *indio_dev) +static int veml6030_hw_init(struct iio_dev *indio_dev, struct device *dev) { int ret, val; struct veml6030_data *data = iio_priv(indio_dev); - struct i2c_client *client = data->client; ret = veml6030_als_shut_down(data); - if (ret) { - dev_err(&client->dev, "can't shutdown als %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "can't shutdown als\n"); ret = regmap_write(data->regmap, VEML6030_REG_ALS_CONF, 0x1001); - if (ret) { - dev_err(&client->dev, "can't setup als configs %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "can't setup als configs\n"); ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_PSM, VEML6030_PSM | VEML6030_PSM_EN, 0x03); - if (ret) { - dev_err(&client->dev, "can't setup default PSM %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "can't setup default PSM\n"); ret = regmap_write(data->regmap, VEML6030_REG_ALS_WH, 0xFFFF); - if (ret) { - dev_err(&client->dev, "can't setup high threshold %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "can't setup high threshold\n"); ret = regmap_write(data->regmap, VEML6030_REG_ALS_WL, 0x0000); - if (ret) { - dev_err(&client->dev, "can't setup low threshold %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "can't setup low threshold\n"); ret = veml6030_als_pwr_on(data); - if (ret) { - dev_err(&client->dev, "can't poweron als %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "can't poweron als\n"); - /* Wait 4 ms to let processor & oscillator start correctly */ - usleep_range(4000, 4002); + ret = devm_add_action_or_reset(dev, veml6030_als_shut_down_action, data); + if (ret < 0) + return ret; /* Clear stale interrupt status bits if any during start */ ret = regmap_read(data->regmap, VEML6030_REG_ALS_INT, &val); - if (ret < 0) { - dev_err(&client->dev, - "can't clear als interrupt status %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, + "can't clear als interrupt status\n"); /* Cache currently active measurement parameters */ data->cur_gain = 3; @@ -785,6 +974,62 @@ static int veml6030_hw_init(struct iio_dev *indio_dev) return ret; } +/* + * Set ALS gain to 1/8, integration time to 100 ms, ALS and WHITE + * channel enabled, ALS channel interrupt, PSM enabled, + * PSM_WAIT = 0.8 s, persistence to 1 x integration time and the + * threshold interrupt disabled by default. First shutdown the sensor, + * update registers and then power on the sensor. + */ +static int veml6035_hw_init(struct iio_dev *indio_dev, struct device *dev) +{ + int ret, val; + struct veml6030_data *data = iio_priv(indio_dev); + + ret = veml6030_als_shut_down(data); + if (ret) + return dev_err_probe(dev, ret, "can't shutdown als\n"); + + ret = regmap_write(data->regmap, VEML6030_REG_ALS_CONF, + VEML6035_SENS | VEML6035_CHAN_EN | VEML6030_ALS_SD); + if (ret) + return dev_err_probe(dev, ret, "can't setup als configs\n"); + + ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_PSM, + VEML6030_PSM | VEML6030_PSM_EN, 0x03); + if (ret) + return dev_err_probe(dev, ret, "can't setup default PSM\n"); + + ret = regmap_write(data->regmap, VEML6030_REG_ALS_WH, 0xFFFF); + if (ret) + return dev_err_probe(dev, ret, "can't setup high threshold\n"); + + ret = regmap_write(data->regmap, VEML6030_REG_ALS_WL, 0x0000); + if (ret) + return dev_err_probe(dev, ret, "can't setup low threshold\n"); + + ret = veml6030_als_pwr_on(data); + if (ret) + return dev_err_probe(dev, ret, "can't poweron als\n"); + + ret = devm_add_action_or_reset(dev, veml6030_als_shut_down_action, data); + if (ret < 0) + return ret; + + /* Clear stale interrupt status bits if any during start */ + ret = regmap_read(data->regmap, VEML6030_REG_ALS_INT, &val); + if (ret < 0) + return dev_err_probe(dev, ret, + "can't clear als interrupt status\n"); + + /* Cache currently active measurement parameters */ + data->cur_gain = 5; + data->cur_resolution = 1024; + data->cur_integration_time = 3; + + return 0; +} + static int veml6030_probe(struct i2c_client *client) { int ret; @@ -792,16 +1037,14 @@ static int veml6030_probe(struct i2c_client *client) struct iio_dev *indio_dev; struct regmap *regmap; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "i2c adapter doesn't support plain i2c\n"); - return -EOPNOTSUPP; - } + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return dev_err_probe(&client->dev, -EOPNOTSUPP, + "i2c adapter doesn't support plain i2c\n"); regmap = devm_regmap_init_i2c(client, &veml6030_regmap_config); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "can't setup regmap\n"); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&client->dev, PTR_ERR(regmap), + "can't setup regmap\n"); indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -812,32 +1055,25 @@ static int veml6030_probe(struct i2c_client *client) data->client = client; data->regmap = regmap; - indio_dev->name = "veml6030"; - indio_dev->channels = veml6030_channels; - indio_dev->num_channels = ARRAY_SIZE(veml6030_channels); - indio_dev->modes = INDIO_DIRECT_MODE; + ret = devm_regulator_get_enable(&client->dev, "vdd"); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to enable regulator\n"); - if (client->irq) { - ret = devm_request_threaded_irq(&client->dev, client->irq, - NULL, veml6030_event_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "veml6030", indio_dev); - if (ret < 0) { - dev_err(&client->dev, - "irq %d request failed\n", client->irq); - return ret; - } - indio_dev->info = &veml6030_info; - } else { - indio_dev->info = &veml6030_info_no_irq; - } + data->chip = i2c_get_match_data(client); + if (!data->chip) + return -EINVAL; + + indio_dev->name = data->chip->name; + indio_dev->channels = data->chip->channels; + indio_dev->num_channels = data->chip->num_channels; + indio_dev->modes = INDIO_DIRECT_MODE; - ret = veml6030_hw_init(indio_dev); + ret = data->chip->set_info(indio_dev); if (ret < 0) return ret; - ret = devm_add_action_or_reset(&client->dev, - veml6030_als_shut_down_action, data); + ret = data->chip->hw_init(indio_dev, &client->dev); if (ret < 0) return ret; @@ -873,14 +1109,63 @@ static int veml6030_runtime_resume(struct device *dev) static DEFINE_RUNTIME_DEV_PM_OPS(veml6030_pm_ops, veml6030_runtime_suspend, veml6030_runtime_resume, NULL); +static const struct veml603x_chip veml6030_chip = { + .name = "veml6030", + .scale_vals = &veml6030_scale_vals, + .num_scale_vals = ARRAY_SIZE(veml6030_scale_vals), + .channels = veml6030_channels, + .num_channels = ARRAY_SIZE(veml6030_channels), + .hw_init = veml6030_hw_init, + .set_info = veml6030_set_info, + .set_als_gain = veml6030_set_als_gain, + .get_als_gain = veml6030_get_als_gain, +}; + +static const struct veml603x_chip veml6035_chip = { + .name = "veml6035", + .scale_vals = &veml6035_scale_vals, + .num_scale_vals = ARRAY_SIZE(veml6035_scale_vals), + .channels = veml6030_channels, + .num_channels = ARRAY_SIZE(veml6030_channels), + .hw_init = veml6035_hw_init, + .set_info = veml6030_set_info, + .set_als_gain = veml6035_set_als_gain, + .get_als_gain = veml6035_get_als_gain, +}; + +static const struct veml603x_chip veml7700_chip = { + .name = "veml7700", + .scale_vals = &veml6030_scale_vals, + .num_scale_vals = ARRAY_SIZE(veml6030_scale_vals), + .channels = veml7700_channels, + .num_channels = ARRAY_SIZE(veml7700_channels), + .hw_init = veml6030_hw_init, + .set_info = veml7700_set_info, + .set_als_gain = veml6030_set_als_gain, + .get_als_gain = veml6030_get_als_gain, +}; + static const struct of_device_id veml6030_of_match[] = { - { .compatible = "vishay,veml6030" }, + { + .compatible = "vishay,veml6030", + .data = &veml6030_chip, + }, + { + .compatible = "vishay,veml6035", + .data = &veml6035_chip, + }, + { + .compatible = "vishay,veml7700", + .data = &veml7700_chip, + }, { } }; MODULE_DEVICE_TABLE(of, veml6030_of_match); static const struct i2c_device_id veml6030_id[] = { - { "veml6030" }, + { "veml6030", (kernel_ulong_t)&veml6030_chip}, + { "veml6035", (kernel_ulong_t)&veml6035_chip}, + { "veml7700", (kernel_ulong_t)&veml7700_chip}, { } }; MODULE_DEVICE_TABLE(i2c, veml6030_id); diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index f8321d346d7757..6d4483c85f30cf 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -6,14 +6,16 @@ * * IIO driver for VEML6070 (7-bit I2C slave addresses 0x38 and 0x39) * - * TODO: integration time, ACK signal + * TODO: ACK signal */ +#include #include #include #include #include #include +#include #include #include @@ -28,50 +30,113 @@ #define VEML6070_COMMAND_RSRVD BIT(1) /* reserved, set to 1 */ #define VEML6070_COMMAND_SD BIT(0) /* shutdown mode when set */ -#define VEML6070_IT_10 0x04 /* integration time 1x */ +#define VEML6070_IT_05 0x00 +#define VEML6070_IT_10 0x01 +#define VEML6070_IT_20 0x02 +#define VEML6070_IT_40 0x03 + +#define VEML6070_MIN_RSET_KOHM 75 +#define VEML6070_MIN_IT_US 15625 /* Rset = 75 kohm, IT = 1/2 */ struct veml6070_data { struct i2c_client *client1; struct i2c_client *client2; u8 config; struct mutex lock; + u32 rset; + int it[4][2]; }; +static int veml6070_calc_it(struct device *dev, struct veml6070_data *data) +{ + int i, tmp_it; + + data->rset = 270000; + device_property_read_u32(dev, "vishay,rset-ohms", &data->rset); + + if (data->rset < 75000 || data->rset > 1200000) + return dev_err_probe(dev, -EINVAL, "Rset out of range\n"); + + /* + * convert to kohm to avoid overflows and work with the same units as + * in the datasheet and simplify UVI operations. + */ + data->rset /= KILO; + + tmp_it = VEML6070_MIN_IT_US * data->rset / VEML6070_MIN_RSET_KOHM; + for (i = 0; i < ARRAY_SIZE(data->it); i++) { + data->it[i][0] = (tmp_it << i) / MICRO; + data->it[i][1] = (tmp_it << i) % MICRO; + } + + return 0; +} + +static int veml6070_get_it(struct veml6070_data *data, int *val, int *val2) +{ + int it_idx = FIELD_GET(VEML6070_COMMAND_IT, data->config); + + *val = data->it[it_idx][0]; + *val2 = data->it[it_idx][1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int veml6070_set_it(struct veml6070_data *data, int val, int val2) +{ + int it_idx; + + for (it_idx = 0; it_idx < ARRAY_SIZE(data->it); it_idx++) { + if (data->it[it_idx][0] == val && data->it[it_idx][1] == val2) + break; + } + + if (it_idx >= ARRAY_SIZE(data->it)) + return -EINVAL; + + data->config = (data->config & ~VEML6070_COMMAND_IT) | + FIELD_PREP(VEML6070_COMMAND_IT, it_idx); + + return i2c_smbus_write_byte(data->client1, data->config); +} + static int veml6070_read(struct veml6070_data *data) { - int ret; + int ret, it_ms, val, val2; u8 msb, lsb; - mutex_lock(&data->lock); + guard(mutex)(&data->lock); /* disable shutdown */ ret = i2c_smbus_write_byte(data->client1, data->config & ~VEML6070_COMMAND_SD); if (ret < 0) - goto out; + return ret; - msleep(125 + 10); /* measurement takes up to 125 ms for IT 1x */ + veml6070_get_it(data, &val, &val2); + it_ms = val * MILLI + val2 / (MICRO / MILLI); + msleep(it_ms + 10); ret = i2c_smbus_read_byte(data->client2); /* read MSB, address 0x39 */ if (ret < 0) - goto out; + return ret; + msb = ret; ret = i2c_smbus_read_byte(data->client1); /* read LSB, address 0x38 */ if (ret < 0) - goto out; + return ret; + lsb = ret; /* shutdown again */ ret = i2c_smbus_write_byte(data->client1, data->config); if (ret < 0) - goto out; + return ret; ret = (msb << 8) | lsb; -out: - mutex_unlock(&data->lock); - return ret; + return 0; } static const struct iio_chan_spec veml6070_channels[] = { @@ -80,26 +145,37 @@ static const struct iio_chan_spec veml6070_channels[] = { .modified = 1, .channel2 = IIO_MOD_LIGHT_UV, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), }, { .type = IIO_UVINDEX, .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME), } }; -static int veml6070_to_uv_index(unsigned val) +static int veml6070_to_uv_index(struct veml6070_data *data, unsigned int val) { /* * conversion of raw UV intensity values to UV index depends on * integration time (IT) and value of the resistor connected to - * the RSET pin (default: 270 KOhm) + * the RSET pin. */ - unsigned uvi[11] = { + unsigned int uvi[11] = { 187, 373, 560, /* low */ 746, 933, 1120, /* moderate */ 1308, 1494, /* high */ 1681, 1868, 2054}; /* very high */ - int i; + int i, it_idx; + + it_idx = FIELD_GET(VEML6070_COMMAND_IT, data->config); + + if (!it_idx) + val = (val * 270 / data->rset) << 1; + else + val = (val * 270 / data->rset) >> (it_idx - 1); for (i = 0; i < ARRAY_SIZE(uvi); i++) if (val <= uvi[i]) @@ -122,10 +198,44 @@ static int veml6070_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; if (mask == IIO_CHAN_INFO_PROCESSED) - *val = veml6070_to_uv_index(ret); + *val = veml6070_to_uv_index(data, ret); else *val = ret; return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + return veml6070_get_it(data, val, val2); + default: + return -EINVAL; + } +} + +static int veml6070_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct veml6070_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + *vals = (int *)data->it; + *length = 2 * ARRAY_SIZE(data->it); + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int veml6070_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct veml6070_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + return veml6070_set_it(data, val, val2); default: return -EINVAL; } @@ -133,8 +243,17 @@ static int veml6070_read_raw(struct iio_dev *indio_dev, static const struct iio_info veml6070_info = { .read_raw = veml6070_read_raw, + .read_avail = veml6070_read_avail, + .write_raw = veml6070_write_raw, }; +static void veml6070_i2c_unreg(void *p) +{ + struct veml6070_data *data = p; + + i2c_unregister_device(data->client2); +} + static int veml6070_probe(struct i2c_client *client) { struct veml6070_data *data; @@ -156,36 +275,30 @@ static int veml6070_probe(struct i2c_client *client) indio_dev->name = VEML6070_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB); - if (IS_ERR(data->client2)) { - dev_err(&client->dev, "i2c device for second chip address failed\n"); - return PTR_ERR(data->client2); - } - - data->config = VEML6070_IT_10 | VEML6070_COMMAND_RSRVD | - VEML6070_COMMAND_SD; - ret = i2c_smbus_write_byte(data->client1, data->config); + ret = veml6070_calc_it(&client->dev, data); if (ret < 0) - goto fail; + return ret; - ret = iio_device_register(indio_dev); + ret = devm_regulator_get_enable(&client->dev, "vdd"); if (ret < 0) - goto fail; + return ret; - return ret; + data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB); + if (IS_ERR(data->client2)) + return dev_err_probe(&client->dev, PTR_ERR(data->client2), + "i2c device for second chip address failed\n"); -fail: - i2c_unregister_device(data->client2); - return ret; -} + data->config = FIELD_PREP(VEML6070_COMMAND_IT, VEML6070_IT_10) | + VEML6070_COMMAND_RSRVD | VEML6070_COMMAND_SD; + ret = i2c_smbus_write_byte(data->client1, data->config); + if (ret < 0) + return ret; -static void veml6070_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct veml6070_data *data = iio_priv(indio_dev); + ret = devm_add_action_or_reset(&client->dev, veml6070_i2c_unreg, data); + if (ret < 0) + return ret; - iio_device_unregister(indio_dev); - i2c_unregister_device(data->client2); + return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id veml6070_id[] = { @@ -194,12 +307,18 @@ static const struct i2c_device_id veml6070_id[] = { }; MODULE_DEVICE_TABLE(i2c, veml6070_id); +static const struct of_device_id veml6070_of_match[] = { + { .compatible = "vishay,veml6070" }, + { } +}; +MODULE_DEVICE_TABLE(of, veml6070_of_match); + static struct i2c_driver veml6070_driver = { .driver = { .name = VEML6070_DRV_NAME, + .of_match_table = veml6070_of_match, }, .probe = veml6070_probe, - .remove = veml6070_remove, .id_table = veml6070_id, }; diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index a1b2b3c0b4c889..6e2183a4243e55 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -25,6 +25,10 @@ #include #include +#include +#include +#include +#include #define VL6180_DRV_NAME "vl6180" @@ -38,7 +42,9 @@ #define VL6180_OUT_OF_RESET 0x016 #define VL6180_HOLD 0x017 #define VL6180_RANGE_START 0x018 +#define VL6180_RANGE_INTER_MEAS_TIME 0x01b #define VL6180_ALS_START 0x038 +#define VL6180_ALS_INTER_MEAS_TIME 0x03e #define VL6180_ALS_GAIN 0x03f #define VL6180_ALS_IT 0x040 @@ -84,8 +90,17 @@ struct vl6180_data { struct i2c_client *client; struct mutex lock; + struct completion completion; + struct iio_trigger *trig; unsigned int als_gain_milli; unsigned int als_it_ms; + unsigned int als_meas_rate; + unsigned int range_meas_rate; + + struct { + u16 chan[2]; + aligned_s64 timestamp; + } scan; }; enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX }; @@ -207,29 +222,40 @@ static int vl6180_write_word(struct i2c_client *client, u16 cmd, u16 val) static int vl6180_measure(struct vl6180_data *data, int addr) { struct i2c_client *client = data->client; + unsigned long time_left; int tries = 20, ret; u16 value; mutex_lock(&data->lock); + reinit_completion(&data->completion); + /* Start single shot measurement */ ret = vl6180_write_byte(client, vl6180_chan_regs_table[addr].start_reg, VL6180_STARTSTOP); if (ret < 0) goto fail; - while (tries--) { - ret = vl6180_read_byte(client, VL6180_INTR_STATUS); - if (ret < 0) + if (client->irq) { + time_left = wait_for_completion_timeout(&data->completion, HZ / 10); + if (time_left == 0) { + ret = -ETIMEDOUT; goto fail; + } + } else { + while (tries--) { + ret = vl6180_read_byte(client, VL6180_INTR_STATUS); + if (ret < 0) + goto fail; + + if (ret & vl6180_chan_regs_table[addr].drdy_mask) + break; + msleep(20); + } - if (ret & vl6180_chan_regs_table[addr].drdy_mask) - break; - msleep(20); - } - - if (tries < 0) { - ret = -EIO; - goto fail; + if (tries < 0) { + ret = -EIO; + goto fail; + } } /* Read result value from appropriate registers */ @@ -258,20 +284,41 @@ static const struct iio_chan_spec vl6180_channels[] = { { .type = IIO_LIGHT, .address = VL6180_ALS, + .scan_index = VL6180_ALS, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_HARDWAREGAIN), + BIT(IIO_CHAN_INFO_HARDWAREGAIN) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_DISTANCE, .address = VL6180_RANGE, + .scan_index = VL6180_RANGE, + .scan_type = { + .sign = 'u', + .realbits = 8, + .storagebits = 8, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_PROXIMITY, .address = VL6180_PROX, + .scan_index = VL6180_PROX, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + }, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - } + }, + IIO_CHAN_SOFT_TIMESTAMP(3), }; /* @@ -333,6 +380,18 @@ static int vl6180_read_raw(struct iio_dev *indio_dev, return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_SAMP_FREQ: + switch (chan->type) { + case IIO_DISTANCE: + *val = data->range_meas_rate; + return IIO_VAL_INT; + case IIO_LIGHT: + *val = data->als_meas_rate; + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: return -EINVAL; } @@ -412,11 +471,23 @@ static int vl6180_set_it(struct vl6180_data *data, int val, int val2) return ret; } +static int vl6180_meas_reg_val_from_mhz(unsigned int mhz) +{ + unsigned int period = DIV_ROUND_CLOSEST(1000 * 1000, mhz); + unsigned int reg_val = 0; + + if (period > 10) + reg_val = period < 2550 ? (DIV_ROUND_CLOSEST(period, 10) - 1) : 254; + + return reg_val; +} + static int vl6180_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { struct vl6180_data *data = iio_priv(indio_dev); + unsigned int reg_val; switch (mask) { case IIO_CHAN_INFO_INT_TIME: @@ -427,18 +498,126 @@ static int vl6180_write_raw(struct iio_dev *indio_dev, return -EINVAL; return vl6180_set_als_gain(data, val, val2); + + case IIO_CHAN_INFO_SAMP_FREQ: + { + guard(mutex)(&data->lock); + switch (chan->type) { + case IIO_DISTANCE: + data->range_meas_rate = val; + reg_val = vl6180_meas_reg_val_from_mhz(val); + return vl6180_write_byte(data->client, + VL6180_RANGE_INTER_MEAS_TIME, reg_val); + + case IIO_LIGHT: + data->als_meas_rate = val; + reg_val = vl6180_meas_reg_val_from_mhz(val); + return vl6180_write_byte(data->client, + VL6180_ALS_INTER_MEAS_TIME, reg_val); + + default: + return -EINVAL; + } + } + default: return -EINVAL; } } +static irqreturn_t vl6180_threaded_irq(int irq, void *priv) +{ + struct iio_dev *indio_dev = priv; + struct vl6180_data *data = iio_priv(indio_dev); + + if (iio_buffer_enabled(indio_dev)) + iio_trigger_poll_nested(indio_dev->trig); + else + complete(&data->completion); + + return IRQ_HANDLED; +} + +static irqreturn_t vl6180_trigger_handler(int irq, void *priv) +{ + struct iio_poll_func *pf = priv; + struct iio_dev *indio_dev = pf->indio_dev; + struct vl6180_data *data = iio_priv(indio_dev); + s64 time_ns = iio_get_time_ns(indio_dev); + int ret, bit, i = 0; + + iio_for_each_active_channel(indio_dev, bit) { + if (vl6180_chan_regs_table[bit].word) + ret = vl6180_read_word(data->client, + vl6180_chan_regs_table[bit].value_reg); + else + ret = vl6180_read_byte(data->client, + vl6180_chan_regs_table[bit].value_reg); + + if (ret < 0) { + dev_err(&data->client->dev, + "failed to read from value regs: %d\n", ret); + return IRQ_HANDLED; + } + + data->scan.chan[i++] = ret; + } + + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns); + iio_trigger_notify_done(indio_dev->trig); + + /* Clear the interrupt flag after data read */ + ret = vl6180_write_byte(data->client, VL6180_INTR_CLEAR, + VL6180_CLEAR_ERROR | VL6180_CLEAR_ALS | VL6180_CLEAR_RANGE); + if (ret < 0) + dev_err(&data->client->dev, "failed to clear irq: %d\n", ret); + + return IRQ_HANDLED; +} + static const struct iio_info vl6180_info = { .read_raw = vl6180_read_raw, .write_raw = vl6180_write_raw, .attrs = &vl6180_attribute_group, + .validate_trigger = iio_validate_own_trigger, +}; + +static int vl6180_buffer_postenable(struct iio_dev *indio_dev) +{ + struct vl6180_data *data = iio_priv(indio_dev); + int bit; + + iio_for_each_active_channel(indio_dev, bit) + return vl6180_write_byte(data->client, + vl6180_chan_regs_table[bit].start_reg, + VL6180_MODE_CONT | VL6180_STARTSTOP); + + return -EINVAL; +} + +static int vl6180_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct vl6180_data *data = iio_priv(indio_dev); + int bit; + + iio_for_each_active_channel(indio_dev, bit) + return vl6180_write_byte(data->client, + vl6180_chan_regs_table[bit].start_reg, + VL6180_STARTSTOP); + + return -EINVAL; +} + +static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { + .postenable = &vl6180_buffer_postenable, + .postdisable = &vl6180_buffer_postdisable, +}; + +static const struct iio_trigger_ops vl6180_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, }; -static int vl6180_init(struct vl6180_data *data) +static int vl6180_init(struct vl6180_data *data, struct iio_dev *indio_dev) { struct i2c_client *client = data->client; int ret; @@ -473,6 +652,26 @@ static int vl6180_init(struct vl6180_data *data) if (ret < 0) return ret; + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, + &vl6180_trigger_handler, + &iio_triggered_buffer_setup_ops); + if (ret) + return ret; + + /* Default Range inter-measurement time: 50ms or 20000 mHz */ + ret = vl6180_write_byte(client, VL6180_RANGE_INTER_MEAS_TIME, + vl6180_meas_reg_val_from_mhz(20000)); + if (ret < 0) + return ret; + data->range_meas_rate = 20000; + + /* Default ALS inter-measurement time: 10ms or 100000 mHz */ + ret = vl6180_write_byte(client, VL6180_ALS_INTER_MEAS_TIME, + vl6180_meas_reg_val_from_mhz(100000)); + if (ret < 0) + return ret; + data->als_meas_rate = 100000; + /* ALS integration time: 100ms */ data->als_it_ms = 100; ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100); @@ -513,10 +712,34 @@ static int vl6180_probe(struct i2c_client *client) indio_dev->name = VL6180_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; - ret = vl6180_init(data); + ret = vl6180_init(data, indio_dev); if (ret < 0) return ret; + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, vl6180_threaded_irq, + IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return dev_err_probe(&client->dev, ret, "devm_request_irq error \n"); + + init_completion(&data->completion); + + data->trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", + indio_dev->name, iio_device_id(indio_dev)); + if (!data->trig) + return -ENOMEM; + + data->trig->ops = &vl6180_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + ret = devm_iio_trigger_register(&client->dev, data->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(data->trig); + } + return devm_iio_device_register(&client->dev, indio_dev); } diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index f69ac75500f994..7177cd1d67cb2e 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -54,6 +54,19 @@ config AK09911 help Deprecated: AK09911 is now supported by AK8975 driver. +config ALS31300 + tristate "Allegro MicroSystems ALS31300 3-D Linear Hall Effect Sensor" + depends on I2C + select REGMAP_I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Allegro MicroSystems + ALS31300 Hall Effect Sensor through its I2C interface. + + To compile this driver as a module, choose M here: the + module will be called als31300. + config BMC150_MAGN tristate select IIO_BUFFER diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index ec5c46fbf999b6..3e4c2ecd9adf86 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_AF8133J) += af8133j.o obj-$(CONFIG_AK8974) += ak8974.o obj-$(CONFIG_AK8975) += ak8975.o +obj-$(CONFIG_ALS31300) += als31300.o obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o obj-$(CONFIG_BMC150_MAGN_I2C) += bmc150_magn_i2c.o obj-$(CONFIG_BMC150_MAGN_SPI) += bmc150_magn_spi.o diff --git a/drivers/iio/magnetometer/af8133j.c b/drivers/iio/magnetometer/af8133j.c index d81d89af6283b7..acd291f3e7924c 100644 --- a/drivers/iio/magnetometer/af8133j.c +++ b/drivers/iio/magnetometer/af8133j.c @@ -312,10 +312,11 @@ static int af8133j_set_scale(struct af8133j_data *data, * When suspended, just store the new range to data->range to be * applied later during power up. */ - if (!pm_runtime_status_suspended(dev)) + if (!pm_runtime_status_suspended(dev)) { scoped_guard(mutex, &data->mutex) ret = regmap_write(data->regmap, AF8133J_REG_RANGE, range); + } pm_runtime_enable(dev); diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 961b1e0bfb138d..8306a18706accf 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -910,7 +910,7 @@ static int ak8974_probe(struct i2c_client *i2c) /* If we have a valid DRDY IRQ, make use of it */ if (irq > 0) { - irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); + irq_trig = irq_get_trigger_type(irq); if (irq_trig == IRQF_TRIGGER_RISING) { dev_info(&i2c->dev, "enable rising edge DRDY IRQ\n"); } else if (irq_trig == IRQF_TRIGGER_FALLING) { diff --git a/drivers/iio/magnetometer/als31300.c b/drivers/iio/magnetometer/als31300.c new file mode 100644 index 00000000000000..87b60c4e81fa1c --- /dev/null +++ b/drivers/iio/magnetometer/als31300.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the Allegro MicroSystems ALS31300 3-D Linear Hall Effect Sensor + * + * Copyright (c) 2024 Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * The Allegro MicroSystems ALS31300 has an EEPROM space to configure how + * the device works and how the interrupt line behaves. + * Only the default setup with external trigger is supported. + * + * While the bindings supports declaring an interrupt line, those + * events are not supported. + * + * It should be possible to adapt the driver to the current + * device EEPROM setup at runtime. + */ + +#define ALS31300_EEPROM_CONFIG 0x02 +#define ALS31300_EEPROM_INTERRUPT 0x03 +#define ALS31300_EEPROM_CUSTOMER_1 0x0d +#define ALS31300_EEPROM_CUSTOMER_2 0x0e +#define ALS31300_EEPROM_CUSTOMER_3 0x0f +#define ALS31300_VOL_MODE 0x27 +#define ALS31300_VOL_MODE_LPDCM GENMASK(6, 4) +#define ALS31300_LPDCM_INACTIVE_0_5_MS 0 +#define ALS31300_LPDCM_INACTIVE_1_0_MS 1 +#define ALS31300_LPDCM_INACTIVE_5_0_MS 2 +#define ALS31300_LPDCM_INACTIVE_10_0_MS 3 +#define ALS31300_LPDCM_INACTIVE_50_0_MS 4 +#define ALS31300_LPDCM_INACTIVE_100_0_MS 5 +#define ALS31300_LPDCM_INACTIVE_500_0_MS 6 +#define ALS31300_LPDCM_INACTIVE_1000_0_MS 7 +#define ALS31300_VOL_MODE_SLEEP GENMASK(1, 0) +#define ALS31300_VOL_MODE_ACTIVE_MODE 0 +#define ALS31300_VOL_MODE_SLEEP_MODE 1 +#define ALS31300_VOL_MODE_LPDCM_MODE 2 +#define ALS31300_VOL_MSB 0x28 +#define ALS31300_VOL_MSB_TEMPERATURE GENMASK(5, 0) +#define ALS31300_VOL_MSB_INTERRUPT BIT(6) +#define ALS31300_VOL_MSB_NEW_DATA BIT(7) +#define ALS31300_VOL_MSB_Z_AXIS GENMASK(15, 8) +#define ALS31300_VOL_MSB_Y_AXIS GENMASK(23, 16) +#define ALS31300_VOL_MSB_X_AXIS GENMASK(31, 24) +#define ALS31300_VOL_LSB 0x29 +#define ALS31300_VOL_LSB_TEMPERATURE GENMASK(5, 0) +#define ALS31300_VOL_LSB_HALL_STATUS GENMASK(7, 7) +#define ALS31300_VOL_LSB_Z_AXIS GENMASK(11, 8) +#define ALS31300_VOL_LSB_Y_AXIS GENMASK(15, 12) +#define ALS31300_VOL_LSB_X_AXIS GENMASK(19, 16) +#define ALS31300_VOL_LSB_INTERRUPT_WRITE BIT(20) +#define ALS31300_CUSTOMER_ACCESS 0x35 + +#define ALS31300_DATA_X_GET(b) \ + sign_extend32(FIELD_GET(ALS31300_VOL_MSB_X_AXIS, b[0]) << 4 | \ + FIELD_GET(ALS31300_VOL_LSB_X_AXIS, b[1]), 11) +#define ALS31300_DATA_Y_GET(b) \ + sign_extend32(FIELD_GET(ALS31300_VOL_MSB_Y_AXIS, b[0]) << 4 | \ + FIELD_GET(ALS31300_VOL_LSB_Y_AXIS, b[1]), 11) +#define ALS31300_DATA_Z_GET(b) \ + sign_extend32(FIELD_GET(ALS31300_VOL_MSB_Z_AXIS, b[0]) << 4 | \ + FIELD_GET(ALS31300_VOL_LSB_Z_AXIS, b[1]), 11) +#define ALS31300_TEMPERATURE_GET(b) \ + (FIELD_GET(ALS31300_VOL_MSB_TEMPERATURE, b[0]) << 6 | \ + FIELD_GET(ALS31300_VOL_LSB_TEMPERATURE, b[1])) + +enum als31300_channels { + TEMPERATURE = 0, + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +struct als31300_variant_info { + u8 sensitivity; +}; + +struct als31300_data { + struct device *dev; + /* protects power on/off the device and access HW */ + struct mutex mutex; + const struct als31300_variant_info *variant_info; + struct regmap *map; +}; + +/* The whole measure is split into 2x32-bit registers, we need to read them both at once */ +static int als31300_get_measure(struct als31300_data *data, + u16 *t, s16 *x, s16 *y, s16 *z) +{ + u32 buf[2]; + int ret, err; + + guard(mutex)(&data->mutex); + + ret = pm_runtime_resume_and_get(data->dev); + if (ret) + return ret; + + /* + * Loop until data is valid, new data should have the + * ALS31300_VOL_MSB_NEW_DATA bit set to 1. + * Max update rate is 2KHz, wait up to 1ms. + */ + ret = read_poll_timeout(regmap_bulk_read, err, + err || FIELD_GET(ALS31300_VOL_MSB_NEW_DATA, buf[0]), + 20, USEC_PER_MSEC, false, + data->map, ALS31300_VOL_MSB, buf, ARRAY_SIZE(buf)); + /* Bail out on read_poll_timeout() error */ + if (ret) + goto out; + + /* Bail out on regmap_bulk_read() error */ + if (err) { + dev_err(data->dev, "read data failed, error %d\n", ret); + ret = err; + goto out; + } + + *t = ALS31300_TEMPERATURE_GET(buf); + *x = ALS31300_DATA_X_GET(buf); + *y = ALS31300_DATA_Y_GET(buf); + *z = ALS31300_DATA_Z_GET(buf); + +out: + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + + return ret; +} + +static int als31300_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, + int *val2, long mask) +{ + struct als31300_data *data = iio_priv(indio_dev); + s16 x, y, z; + u16 t; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + case IIO_CHAN_INFO_RAW: + ret = als31300_get_measure(data, &t, &x, &y, &z); + if (ret) + return ret; + + switch (chan->address) { + case TEMPERATURE: + *val = t; + return IIO_VAL_INT; + case AXIS_X: + *val = x; + return IIO_VAL_INT; + case AXIS_Y: + *val = y; + return IIO_VAL_INT; + case AXIS_Z: + *val = z; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + /* + * Fractional part of: + * 1000 * 302 * (value - 1708) + * temp = ---------------------------- + * 4096 + * to convert temperature in millicelcius. + */ + *val = MILLI * 302; + *val2 = 4096; + return IIO_VAL_FRACTIONAL; + case IIO_MAGN: + /* + * Devices are configured in factory + * with different sensitivities: + * - 500 GAUSS <-> 4 LSB/Gauss + * - 1000 GAUSS <-> 2 LSB/Gauss + * - 2000 GAUSS <-> 1 LSB/Gauss + * with translates by a division of the returned + * value to get Gauss value. + * The sensitivity cannot be read at runtime + * so the value depends on the model compatible + * or device id. + */ + *val = 1; + *val2 = data->variant_info->sensitivity; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + *val = -1708; + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static irqreturn_t als31300_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct als31300_data *data = iio_priv(indio_dev); + struct { + u16 temperature; + s16 channels[3]; + aligned_s64 timestamp; + } scan; + s16 x, y, z; + int ret; + u16 t; + + ret = als31300_get_measure(data, &t, &x, &y, &z); + if (ret) + goto trigger_out; + + scan.temperature = t; + scan.channels[0] = x; + scan.channels[1] = y; + scan.channels[2] = z; + iio_push_to_buffers_with_timestamp(indio_dev, &scan, + pf->timestamp); + +trigger_out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +#define ALS31300_AXIS_CHANNEL(axis, index) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ + } + +static const struct iio_chan_spec als31300_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .address = TEMPERATURE, + .scan_index = TEMPERATURE, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, + }, + ALS31300_AXIS_CHANNEL(X, AXIS_X), + ALS31300_AXIS_CHANNEL(Y, AXIS_Y), + ALS31300_AXIS_CHANNEL(Z, AXIS_Z), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const struct iio_info als31300_info = { + .read_raw = als31300_read_raw, +}; + +static int als31300_set_operating_mode(struct als31300_data *data, + unsigned int val) +{ + int ret; + + ret = regmap_update_bits(data->map, ALS31300_VOL_MODE, + ALS31300_VOL_MODE_SLEEP, val); + if (ret) { + dev_err(data->dev, "failed to set operating mode (%pe)\n", ERR_PTR(ret)); + return ret; + } + + /* The time it takes to exit sleep mode is equivalent to Power-On Delay Time */ + if (val == ALS31300_VOL_MODE_ACTIVE_MODE) + fsleep(600); + + return 0; +} + +static void als31300_power_down(void *data) +{ + als31300_set_operating_mode(data, ALS31300_VOL_MODE_SLEEP_MODE); +} + +static const struct iio_buffer_setup_ops als31300_setup_ops = {}; + +static const unsigned long als31300_scan_masks[] = { GENMASK(3, 0), 0 }; + +static bool als31300_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == ALS31300_VOL_MSB || reg == ALS31300_VOL_LSB; +} + +static const struct regmap_config als31300_regmap_config = { + .reg_bits = 8, + .val_bits = 32, + .max_register = ALS31300_CUSTOMER_ACCESS, + .volatile_reg = als31300_volatile_reg, +}; + +static int als31300_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct als31300_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->dev = dev; + i2c_set_clientdata(i2c, indio_dev); + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + data->variant_info = i2c_get_match_data(i2c); + if (!data->variant_info) + return -EINVAL; + + data->map = devm_regmap_init_i2c(i2c, &als31300_regmap_config); + if (IS_ERR(data->map)) + return dev_err_probe(dev, PTR_ERR(data->map), + "failed to allocate register map\n"); + + ret = devm_regulator_get_enable(dev, "vcc"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable regulator\n"); + + ret = als31300_set_operating_mode(data, ALS31300_VOL_MODE_ACTIVE_MODE); + if (ret) + return dev_err_probe(dev, ret, "failed to power on device\n"); + + ret = devm_add_action_or_reset(dev, als31300_power_down, data); + if (ret) + return dev_err_probe(dev, ret, "failed to add powerdown action\n"); + + indio_dev->info = &als31300_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = i2c->name; + indio_dev->channels = als31300_channels; + indio_dev->num_channels = ARRAY_SIZE(als31300_channels); + indio_dev->available_scan_masks = als31300_scan_masks; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + als31300_trigger_handler, + &als31300_setup_ops); + if (ret < 0) + return dev_err_probe(dev, ret, "iio triggered buffer setup failed\n"); + + ret = pm_runtime_set_active(dev); + if (ret < 0) + return ret; + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + pm_runtime_get_noresume(dev); + pm_runtime_set_autosuspend_delay(dev, 200); + pm_runtime_use_autosuspend(dev); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "device register failed\n"); + + return 0; +} + +static int als31300_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct als31300_data *data = iio_priv(indio_dev); + + return als31300_set_operating_mode(data, ALS31300_VOL_MODE_SLEEP_MODE); +} + +static int als31300_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct als31300_data *data = iio_priv(indio_dev); + + return als31300_set_operating_mode(data, ALS31300_VOL_MODE_ACTIVE_MODE); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(als31300_pm_ops, + als31300_runtime_suspend, als31300_runtime_resume, + NULL); + +static const struct als31300_variant_info al31300_variant_500 = { + .sensitivity = 4, +}; + +static const struct als31300_variant_info al31300_variant_1000 = { + .sensitivity = 2, +}; + +static const struct als31300_variant_info al31300_variant_2000 = { + .sensitivity = 1, +}; + +static const struct i2c_device_id als31300_id[] = { + { + .name = "als31300-500", + .driver_data = (kernel_ulong_t)&al31300_variant_500, + }, + { + .name = "als31300-1000", + .driver_data = (kernel_ulong_t)&al31300_variant_1000, + }, + { + .name = "als31300-2000", + .driver_data = (kernel_ulong_t)&al31300_variant_2000, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, als31300_id); + +static const struct of_device_id als31300_of_match[] = { + { + .compatible = "allegromicro,als31300-500", + .data = &al31300_variant_500, + }, + { + .compatible = "allegromicro,als31300-1000", + .data = &al31300_variant_1000, + }, + { + .compatible = "allegromicro,als31300-2000", + .data = &al31300_variant_2000, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, als31300_of_match); + +static struct i2c_driver als31300_driver = { + .driver = { + .name = "als31300", + .of_match_table = als31300_of_match, + .pm = pm_ptr(&als31300_pm_ops), + }, + .probe = als31300_probe, + .id_table = als31300_id, +}; +module_i2c_driver(als31300_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ALS31300 3-D Linear Hall Effect Driver"); +MODULE_AUTHOR("Neil Armstrong "); diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 06d5a1ef1fbdf2..7f545740178edf 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -226,7 +225,7 @@ const struct regmap_config bmc150_magn_regmap_config = { .writeable_reg = bmc150_magn_is_writeable_reg, .volatile_reg = bmc150_magn_is_volatile_reg, }; -EXPORT_SYMBOL_NS(bmc150_magn_regmap_config, IIO_BMC150_MAGN); +EXPORT_SYMBOL_NS(bmc150_magn_regmap_config, "IIO_BMC150_MAGN"); static int bmc150_magn_set_power_mode(struct bmc150_magn_data *data, enum bmc150_magn_power_modes mode, @@ -855,17 +854,6 @@ static const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = { .postdisable = bmc150_magn_buffer_postdisable, }; -static const char *bmc150_magn_match_acpi_device(struct device *dev) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return NULL; - - return dev_name(dev); -} - int bmc150_magn_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { @@ -894,9 +882,6 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, if (ret) return ret; - if (!name && ACPI_HANDLE(dev)) - name = bmc150_magn_match_acpi_device(dev); - mutex_init(&data->mutex); ret = bmc150_magn_init(data); @@ -983,7 +968,7 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); return ret; } -EXPORT_SYMBOL_NS(bmc150_magn_probe, IIO_BMC150_MAGN); +EXPORT_SYMBOL_NS(bmc150_magn_probe, "IIO_BMC150_MAGN"); void bmc150_magn_remove(struct device *dev) { @@ -1009,7 +994,7 @@ void bmc150_magn_remove(struct device *dev) regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); } -EXPORT_SYMBOL_NS(bmc150_magn_remove, IIO_BMC150_MAGN); +EXPORT_SYMBOL_NS(bmc150_magn_remove, "IIO_BMC150_MAGN"); #ifdef CONFIG_PM static int bmc150_magn_runtime_suspend(struct device *dev) @@ -1077,7 +1062,7 @@ const struct dev_pm_ops bmc150_magn_pm_ops = { SET_RUNTIME_PM_OPS(bmc150_magn_runtime_suspend, bmc150_magn_runtime_resume, NULL) }; -EXPORT_SYMBOL_NS(bmc150_magn_pm_ops, IIO_BMC150_MAGN); +EXPORT_SYMBOL_NS(bmc150_magn_pm_ops, "IIO_BMC150_MAGN"); MODULE_AUTHOR("Irina Tirdea "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index a28d46d59875fa..8cbeda924bdaa3 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -38,14 +38,6 @@ static void bmc150_magn_i2c_remove(struct i2c_client *client) bmc150_magn_remove(&client->dev); } -static const struct acpi_device_id bmc150_magn_acpi_match[] = { - {"BMC150B", 0}, - {"BMC156B", 0}, - {"BMM150B", 0}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); - static const struct i2c_device_id bmc150_magn_i2c_id[] = { { "bmc150_magn" }, { "bmc156_magn" }, @@ -67,7 +59,6 @@ static struct i2c_driver bmc150_magn_driver = { .driver = { .name = "bmc150_magn_i2c", .of_match_table = bmc150_magn_of_match, - .acpi_match_table = bmc150_magn_acpi_match, .pm = &bmc150_magn_pm_ops, }, .probe = bmc150_magn_i2c_probe, @@ -79,4 +70,4 @@ module_i2c_driver(bmc150_magn_driver); MODULE_AUTHOR("Daniel Baluta dev); int ret = 0; static char *name = "magn_3d"; struct iio_dev *indio_dev; struct magn_3d_state *magn_state; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_chan_spec *channels; int chan_count = 0; @@ -549,7 +549,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_magn_3d_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct magn_3d_state *magn_state = iio_priv(indio_dev); @@ -574,11 +574,11 @@ static struct platform_driver hid_magn_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_magn_3d_probe, - .remove_new = hid_magn_3d_remove, + .remove = hid_magn_3d_remove, }; module_platform_driver(hid_magn_3d_platform_driver); MODULE_DESCRIPTION("HID Sensor Magnetometer 3D"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/magnetometer/hmc5843_core.c b/drivers/iio/magnetometer/hmc5843_core.c index c5521d61da2958..2fc84310e2ccb2 100644 --- a/drivers/iio/magnetometer/hmc5843_core.c +++ b/drivers/iio/magnetometer/hmc5843_core.c @@ -669,7 +669,7 @@ int hmc5843_common_probe(struct device *dev, struct regmap *regmap, hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP); return ret; } -EXPORT_SYMBOL_NS(hmc5843_common_probe, IIO_HMC5843); +EXPORT_SYMBOL_NS(hmc5843_common_probe, "IIO_HMC5843"); void hmc5843_common_remove(struct device *dev) { @@ -681,7 +681,7 @@ void hmc5843_common_remove(struct device *dev) /* sleep mode to save power */ hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP); } -EXPORT_SYMBOL_NS(hmc5843_common_remove, IIO_HMC5843); +EXPORT_SYMBOL_NS(hmc5843_common_remove, "IIO_HMC5843"); MODULE_AUTHOR("Shubhrajyoti Datta "); MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 core driver"); diff --git a/drivers/iio/magnetometer/hmc5843_i2c.c b/drivers/iio/magnetometer/hmc5843_i2c.c index bdd2784a9f863b..657a309e2bd578 100644 --- a/drivers/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/iio/magnetometer/hmc5843_i2c.c @@ -103,4 +103,4 @@ module_i2c_driver(hmc5843_driver); MODULE_AUTHOR("Josef Gajdusek "); MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 i2c driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HMC5843); +MODULE_IMPORT_NS("IIO_HMC5843"); diff --git a/drivers/iio/magnetometer/hmc5843_spi.c b/drivers/iio/magnetometer/hmc5843_spi.c index c42d2e2a6a6ce1..b7fde331069d6a 100644 --- a/drivers/iio/magnetometer/hmc5843_spi.c +++ b/drivers/iio/magnetometer/hmc5843_spi.c @@ -100,4 +100,4 @@ module_spi_driver(hmc5843_driver); MODULE_AUTHOR("Josef Gajdusek "); MODULE_DESCRIPTION("HMC5983 SPI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HMC5843); +MODULE_IMPORT_NS("IIO_HMC5843"); diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c index baab918b38254b..c99694a77a1418 100644 --- a/drivers/iio/magnetometer/rm3100-core.c +++ b/drivers/iio/magnetometer/rm3100-core.c @@ -100,7 +100,7 @@ const struct regmap_access_table rm3100_readable_table = { .yes_ranges = rm3100_readable_ranges, .n_yes_ranges = ARRAY_SIZE(rm3100_readable_ranges), }; -EXPORT_SYMBOL_NS_GPL(rm3100_readable_table, IIO_RM3100); +EXPORT_SYMBOL_NS_GPL(rm3100_readable_table, "IIO_RM3100"); static const struct regmap_range rm3100_writable_ranges[] = { regmap_reg_range(RM3100_W_REG_START, RM3100_W_REG_END), @@ -110,7 +110,7 @@ const struct regmap_access_table rm3100_writable_table = { .yes_ranges = rm3100_writable_ranges, .n_yes_ranges = ARRAY_SIZE(rm3100_writable_ranges), }; -EXPORT_SYMBOL_NS_GPL(rm3100_writable_table, IIO_RM3100); +EXPORT_SYMBOL_NS_GPL(rm3100_writable_table, "IIO_RM3100"); static const struct regmap_range rm3100_volatile_ranges[] = { regmap_reg_range(RM3100_V_REG_START, RM3100_V_REG_END), @@ -120,7 +120,7 @@ const struct regmap_access_table rm3100_volatile_table = { .yes_ranges = rm3100_volatile_ranges, .n_yes_ranges = ARRAY_SIZE(rm3100_volatile_ranges), }; -EXPORT_SYMBOL_NS_GPL(rm3100_volatile_table, IIO_RM3100); +EXPORT_SYMBOL_NS_GPL(rm3100_volatile_table, "IIO_RM3100"); static irqreturn_t rm3100_thread_fn(int irq, void *d) { @@ -604,7 +604,7 @@ int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq) return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(rm3100_common_probe, IIO_RM3100); +EXPORT_SYMBOL_NS_GPL(rm3100_common_probe, "IIO_RM3100"); MODULE_AUTHOR("Song Qiang "); MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver"); diff --git a/drivers/iio/magnetometer/rm3100-i2c.c b/drivers/iio/magnetometer/rm3100-i2c.c index ac7276b3798c07..a09a271b62c5d2 100644 --- a/drivers/iio/magnetometer/rm3100-i2c.c +++ b/drivers/iio/magnetometer/rm3100-i2c.c @@ -52,4 +52,4 @@ module_i2c_driver(rm3100_driver); MODULE_AUTHOR("Song Qiang "); MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_RM3100); +MODULE_IMPORT_NS("IIO_RM3100"); diff --git a/drivers/iio/magnetometer/rm3100-spi.c b/drivers/iio/magnetometer/rm3100-spi.c index 76dc9b66cd3c52..dd6d48043740c1 100644 --- a/drivers/iio/magnetometer/rm3100-spi.c +++ b/drivers/iio/magnetometer/rm3100-spi.c @@ -62,4 +62,4 @@ module_spi_driver(rm3100_driver); MODULE_AUTHOR("Song Qiang "); MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_RM3100); +MODULE_IMPORT_NS("IIO_RM3100"); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 6cc0dfd31821b0..ef348d316c001e 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -601,7 +601,7 @@ const struct st_sensor_settings *st_magn_get_settings(const char *name) return &st_magn_sensors_settings[index]; } -EXPORT_SYMBOL_NS(st_magn_get_settings, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_magn_get_settings, "IIO_ST_SENSORS"); int st_magn_common_probe(struct iio_dev *indio_dev) { @@ -648,9 +648,9 @@ int st_magn_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL_NS(st_magn_common_probe, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_magn_common_probe, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics magnetometers driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 950826dd20bf5f..1672b274768d4d 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -119,4 +119,4 @@ module_i2c_driver(st_magn_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics magnetometers i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index f203e1f87eecba..fe4d0e63133c03 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -111,4 +111,4 @@ module_spi_driver(st_magn_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics magnetometers spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index 65011a8598d332..c55a38650c0d47 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -372,6 +372,7 @@ static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y u8 data[8]; u16 xy1y2[3]; s32 h[3], s[3]; + int half_range = BIT(13); int i, ret; mutex_lock(&yas5xx->lock); @@ -406,13 +407,13 @@ static int yas537_measure(struct yas5xx *yas5xx, u16 *t, u16 *x, u16 *y1, u16 *y /* The second version of YAS537 needs to include calibration coefficients */ if (yas5xx->version == YAS537_VERSION_1) { for (i = 0; i < 3; i++) - s[i] = xy1y2[i] - BIT(13); - h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / BIT(13); - h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / BIT(13); - h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / BIT(13); + s[i] = xy1y2[i] - half_range; + h[0] = (c->k * (128 * s[0] + c->a2 * s[1] + c->a3 * s[2])) / half_range; + h[1] = (c->k * (c->a4 * s[0] + c->a5 * s[1] + c->a6 * s[2])) / half_range; + h[2] = (c->k * (c->a7 * s[0] + c->a8 * s[1] + c->a9 * s[2])) / half_range; for (i = 0; i < 3; i++) { - clamp_val(h[i], -BIT(13), BIT(13) - 1); - xy1y2[i] = h[i] + BIT(13); + h[i] = clamp(h[i], -half_range, half_range - 1); + xy1y2[i] = h[i] + half_range; } } diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 8943d5c78bc073..429035b65c657a 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -29,7 +29,7 @@ struct incl_3d_state { struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX]; struct { u32 incl_val[INCLI_3D_CHANNEL_MAX]; - u64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -299,11 +299,11 @@ static int incl_3d_parse_report(struct platform_device *pdev, /* Function to initialize the processing for usage id */ static int hid_incl_3d_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret; static char *name = "incli_3d"; struct iio_dev *indio_dev; struct incl_3d_state *incl_state; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct incl_3d_state)); @@ -385,7 +385,7 @@ static int hid_incl_3d_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_incl_3d_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct incl_3d_state *incl_state = iio_priv(indio_dev); @@ -410,11 +410,11 @@ static struct platform_driver hid_incl_3d_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_incl_3d_probe, - .remove_new = hid_incl_3d_remove, + .remove = hid_incl_3d_remove, }; module_platform_driver(hid_incl_3d_platform_driver); MODULE_DESCRIPTION("HID Sensor Inclinometer 3D"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index 5e8cadd5177ae7..96f03988640c31 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -20,7 +20,7 @@ struct dev_rot_state { struct hid_sensor_hub_attribute_info quaternion; struct { s32 sampled_vals[4] __aligned(16); - u64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -230,11 +230,11 @@ static int dev_rot_parse_report(struct platform_device *pdev, /* Function to initialize the processing for usage id */ static int hid_dev_rot_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret; char *name; struct iio_dev *indio_dev; struct dev_rot_state *rot_state; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct dev_rot_state)); @@ -329,7 +329,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_dev_rot_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct dev_rot_state *rot_state = iio_priv(indio_dev); @@ -362,11 +362,11 @@ static struct platform_driver hid_dev_rot_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_dev_rot_probe, - .remove_new = hid_dev_rot_remove, + .remove = hid_dev_rot_remove, }; module_platform_driver(hid_dev_rot_platform_driver); MODULE_DESCRIPTION("HID Sensor Device Rotation"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index 76e173850a3549..423bbb8a3b38f2 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -39,7 +39,7 @@ struct hinge_state { const char *labels[CHANNEL_SCAN_INDEX_MAX]; struct { u32 hinge_val[3]; - u64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; @@ -263,9 +263,9 @@ static int hinge_parse_report(struct platform_device *pdev, /* Function to initialize the processing for usage id */ static int hid_hinge_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct hinge_state *st; struct iio_dev *indio_dev; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; int ret; int i; @@ -344,7 +344,7 @@ static int hid_hinge_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_hinge_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct hinge_state *st = iio_priv(indio_dev); @@ -369,11 +369,11 @@ static struct platform_driver hid_hinge_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_hinge_probe, - .remove_new = hid_hinge_remove, + .remove = hid_hinge_remove, }; module_platform_driver(hid_hinge_platform_driver); MODULE_DESCRIPTION("HID Sensor INTEL Hinge"); MODULE_AUTHOR("Ye Xiang "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/position/iqs624-pos.c b/drivers/iio/position/iqs624-pos.c index 4d7452314209fe..8239239c6ee272 100644 --- a/drivers/iio/position/iqs624-pos.c +++ b/drivers/iio/position/iqs624-pos.c @@ -181,7 +181,7 @@ static int iqs624_pos_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) + bool state) { struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev); struct iqs62x_core *iqs62x = iqs624_pos->iqs62x; diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index a8b97b9b046182..5376605b69b43a 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -16,6 +16,11 @@ * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf * + * Sensor API: + * https://github.com/boschsensortec/BME280_SensorAPI + * https://github.com/boschsensortec/BMP3_SensorAPI + * https://github.com/boschsensortec/BMP5_SensorAPI + * * Notice: * The link to the bmp180 datasheet points to an outdated version missing these changes: * - Changed document referral from ANP015 to BST-MPS-AN004-00 on page 26 @@ -37,12 +42,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -340,10 +347,19 @@ static int bmp280_read_calib(struct bmp280_data *data) return 0; } +/* + * These enums are used for indexing into the array of humidity parameters + * for BME280. Due to some weird indexing, unaligned BE/LE accesses co-exist in + * order to prepare the FIELD_{GET/PREP}() fields. Table 16 in Section 4.2.2 of + * the datasheet. + */ +enum { H2 = 0, H3 = 2, H4 = 3, H5 = 4, H6 = 6 }; + static int bme280_read_calib(struct bmp280_data *data) { struct bmp280_calib *calib = &data->calib.bmp280; struct device *dev = data->dev; + s16 h4_upper, h4_lower, tmp_1, tmp_2, tmp_3; unsigned int tmp; int ret; @@ -352,14 +368,6 @@ static int bme280_read_calib(struct bmp280_data *data) if (ret) return ret; - /* - * Read humidity calibration values. - * Due to some odd register addressing we cannot just - * do a big bulk read. Instead, we have to read each Hx - * value separately and sometimes do some bit shifting... - * Humidity data is only available on BME280. - */ - ret = regmap_read(data->regmap, BME280_REG_COMP_H1, &tmp); if (ret) { dev_err(dev, "failed to read H1 comp value\n"); @@ -368,43 +376,23 @@ static int bme280_read_calib(struct bmp280_data *data) calib->H1 = tmp; ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H2, - &data->le16, sizeof(data->le16)); + data->bme280_humid_cal_buf, + sizeof(data->bme280_humid_cal_buf)); if (ret) { - dev_err(dev, "failed to read H2 comp value\n"); + dev_err(dev, "failed to read humidity calibration values\n"); return ret; } - calib->H2 = sign_extend32(le16_to_cpu(data->le16), 15); - ret = regmap_read(data->regmap, BME280_REG_COMP_H3, &tmp); - if (ret) { - dev_err(dev, "failed to read H3 comp value\n"); - return ret; - } - calib->H3 = tmp; - - ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H4, - &data->be16, sizeof(data->be16)); - if (ret) { - dev_err(dev, "failed to read H4 comp value\n"); - return ret; - } - calib->H4 = sign_extend32(((be16_to_cpu(data->be16) >> 4) & 0xff0) | - (be16_to_cpu(data->be16) & 0xf), 11); - - ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H5, - &data->le16, sizeof(data->le16)); - if (ret) { - dev_err(dev, "failed to read H5 comp value\n"); - return ret; - } - calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, le16_to_cpu(data->le16)), 11); - - ret = regmap_read(data->regmap, BME280_REG_COMP_H6, &tmp); - if (ret) { - dev_err(dev, "failed to read H6 comp value\n"); - return ret; - } - calib->H6 = sign_extend32(tmp, 7); + calib->H2 = get_unaligned_le16(&data->bme280_humid_cal_buf[H2]); + calib->H3 = data->bme280_humid_cal_buf[H3]; + tmp_1 = get_unaligned_be16(&data->bme280_humid_cal_buf[H4]); + tmp_2 = FIELD_GET(BME280_COMP_H4_GET_MASK_UP, tmp_1); + h4_upper = FIELD_PREP(BME280_COMP_H4_PREP_MASK_UP, tmp_2); + h4_lower = FIELD_GET(BME280_COMP_H4_MASK_LOW, tmp_1); + calib->H4 = sign_extend32(h4_upper | h4_lower, 11); + tmp_3 = get_unaligned_le16(&data->bme280_humid_cal_buf[H5]); + calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, tmp_3), 11); + calib->H6 = data->bme280_humid_cal_buf[H6]; return 0; } @@ -635,6 +623,14 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_PROCESSED: + ret = data->chip_info->set_mode(data, BMP280_FORCED); + if (ret) + return ret; + + ret = data->chip_info->wait_conv(data); + if (ret) + return ret; + switch (chan->type) { case IIO_HUMIDITYRELATIVE: ret = data->chip_info->read_humid(data, &chan_value); @@ -664,6 +660,14 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_RAW: + ret = data->chip_info->set_mode(data, BMP280_FORCED); + if (ret) + return ret; + + ret = data->chip_info->wait_conv(data); + if (ret) + return ret; + switch (chan->type) { case IIO_HUMIDITYRELATIVE: ret = data->chip_info->read_humid(data, &chan_value); @@ -983,6 +987,92 @@ static const unsigned long bme280_avail_scan_masks[] = { 0 }; +static int bmp280_preinit(struct bmp280_data *data) +{ + struct device *dev = data->dev; + unsigned int reg; + int ret; + + ret = regmap_write(data->regmap, BMP280_REG_RESET, BMP280_RST_SOFT_CMD); + if (ret) + return dev_err_probe(dev, ret, "Failed to reset device.\n"); + + /* + * According to the datasheet in Chapter 1: Specification, Table 2, + * after resetting, the device uses the complete power-on sequence so + * it needs to wait for the defined start-up time. + */ + fsleep(data->start_up_time); + + ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®); + if (ret) + return dev_err_probe(dev, ret, "Failed to read status register.\n"); + + if (reg & BMP280_REG_STATUS_IM_UPDATE) + return dev_err_probe(dev, -EIO, "Failed to copy NVM contents.\n"); + + return 0; +} + +static const u8 bmp280_operation_mode[] = { + [BMP280_SLEEP] = BMP280_MODE_SLEEP, + [BMP280_FORCED] = BMP280_MODE_FORCED, + [BMP280_NORMAL] = BMP280_MODE_NORMAL, +}; + +static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode) +{ + int ret; + + ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS, + BMP280_MODE_MASK, bmp280_operation_mode[mode]); + if (ret) { + dev_err(data->dev, "failed to write ctrl_meas register.\n"); + return ret; + } + + data->op_mode = mode; + + return 0; +} + +static int bmp280_wait_conv(struct bmp280_data *data) +{ + unsigned int reg, meas_time_us; + int ret; + + /* Check if we are using a BME280 device */ + if (data->oversampling_humid) + meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET + + BIT(data->oversampling_humid) * BMP280_MEAS_DUR; + + else + meas_time_us = 0; + + /* Pressure measurement time */ + meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET + + BIT(data->oversampling_press) * BMP280_MEAS_DUR; + + /* Temperature measurement time */ + meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR; + + /* Waiting time according to the BM(P/E)2 Sensor API */ + fsleep(meas_time_us); + + ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®); + if (ret) { + dev_err(data->dev, "failed to read status register.\n"); + return ret; + } + + if (reg & BMP280_REG_STATUS_MEAS_BIT) { + dev_err(data->dev, "Measurement cycle didn't complete.\n"); + return -EBUSY; + } + + return 0; +} + static int bmp280_chip_config(struct bmp280_data *data) { u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) | @@ -993,7 +1083,7 @@ static int bmp280_chip_config(struct bmp280_data *data) BMP280_OSRS_TEMP_MASK | BMP280_OSRS_PRESS_MASK | BMP280_MODE_MASK, - osrs | BMP280_MODE_NORMAL); + osrs | BMP280_MODE_SLEEP); if (ret) { dev_err(data->dev, "failed to write ctrl_meas register\n"); return ret; @@ -1015,7 +1105,9 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - s32 adc_temp, adc_press, t_fine; + u32 adc_temp, adc_press, comp_press; + s32 t_fine, comp_temp; + s32 *chans = (s32 *)data->sensor_data; int ret; guard(mutex)(&data->lock); @@ -1035,7 +1127,7 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p) goto out; } - data->sensor_data[1] = bmp280_compensate_temp(data, adc_temp); + comp_temp = bmp280_compensate_temp(data, adc_temp); /* Pressure calculations */ adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[0])); @@ -1045,10 +1137,12 @@ static irqreturn_t bmp280_trigger_handler(int irq, void *p) } t_fine = bmp280_calc_t_fine(data, adc_temp); + comp_press = bmp280_compensate_press(data, adc_press, t_fine); - data->sensor_data[0] = bmp280_compensate_press(data, adc_press, t_fine); + chans[0] = comp_press; + chans[1] = comp_temp; - iio_push_to_buffers_with_timestamp(indio_dev, &data->sensor_data, + iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, iio_get_time_ns(indio_dev)); out: @@ -1099,10 +1193,13 @@ const struct bmp280_chip_info bmp280_chip_info = { .read_temp = bmp280_read_temp, .read_press = bmp280_read_press, .read_calib = bmp280_read_calib, + .set_mode = bmp280_set_mode, + .wait_conv = bmp280_wait_conv, + .preinit = bmp280_preinit, .trigger_handler = bmp280_trigger_handler, }; -EXPORT_SYMBOL_NS(bmp280_chip_info, IIO_BMP280); +EXPORT_SYMBOL_NS(bmp280_chip_info, "IIO_BMP280"); static int bme280_chip_config(struct bmp280_data *data) { @@ -1128,7 +1225,9 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - s32 adc_temp, adc_press, adc_humidity, t_fine; + u32 adc_temp, adc_press, adc_humidity, comp_press, comp_humidity; + s32 t_fine, comp_temp; + s32 *chans = (s32 *)data->sensor_data; int ret; guard(mutex)(&data->lock); @@ -1148,7 +1247,7 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) goto out; } - data->sensor_data[1] = bmp280_compensate_temp(data, adc_temp); + comp_temp = bmp280_compensate_temp(data, adc_temp); /* Pressure calculations */ adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[0])); @@ -1158,8 +1257,7 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) } t_fine = bmp280_calc_t_fine(data, adc_temp); - - data->sensor_data[0] = bmp280_compensate_press(data, adc_press, t_fine); + comp_press = bmp280_compensate_press(data, adc_press, t_fine); /* Humidity calculations */ adc_humidity = get_unaligned_be16(&data->buf[6]); @@ -1168,9 +1266,14 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) dev_err(data->dev, "reading humidity skipped\n"); goto out; } - data->sensor_data[2] = bme280_compensate_humidity(data, adc_humidity, t_fine); - iio_push_to_buffers_with_timestamp(indio_dev, &data->sensor_data, + comp_humidity = bme280_compensate_humidity(data, adc_humidity, t_fine); + + chans[0] = comp_press; + chans[1] = comp_temp; + chans[2] = comp_humidity; + + iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, iio_get_time_ns(indio_dev)); out: @@ -1179,6 +1282,63 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p) return IRQ_HANDLED; } +static int __bmp280_trigger_probe(struct iio_dev *indio_dev, + const struct iio_trigger_ops *trigger_ops, + int (*int_pin_config)(struct bmp280_data *data), + irq_handler_t irq_thread_handler) +{ + struct bmp280_data *data = iio_priv(indio_dev); + struct device *dev = data->dev; + u32 irq_type; + int ret, irq; + + irq = fwnode_irq_get(dev_fwnode(dev), 0); + if (irq < 0) + return dev_err_probe(dev, irq, "No interrupt found.\n"); + + irq_type = irq_get_trigger_type(irq); + switch (irq_type) { + case IRQF_TRIGGER_RISING: + data->trig_active_high = true; + break; + case IRQF_TRIGGER_FALLING: + data->trig_active_high = false; + break; + default: + return dev_err_probe(dev, -EINVAL, "Invalid interrupt type specified.\n"); + } + + data->trig_open_drain = + fwnode_property_read_bool(dev_fwnode(dev), "int-open-drain"); + + ret = int_pin_config(data); + if (ret) + return ret; + + data->trig = devm_iio_trigger_alloc(data->dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!data->trig) + return -ENOMEM; + + data->trig->ops = trigger_ops; + iio_trigger_set_drvdata(data->trig, data); + + ret = devm_request_threaded_irq(data->dev, irq, NULL, + irq_thread_handler, IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return dev_err_probe(dev, ret, "request IRQ failed.\n"); + + ret = devm_iio_trigger_register(data->dev, data->trig); + if (ret) + return dev_err_probe(dev, ret, "iio trigger register failed.\n"); + + indio_dev->trig = iio_trigger_get(data->trig); + + return 0; +} + static const u8 bme280_chip_ids[] = { BME280_CHIP_ID }; static const int bme280_humid_coeffs[] = { 1000, 1024 }; @@ -1216,10 +1376,13 @@ const struct bmp280_chip_info bme280_chip_info = { .read_press = bmp280_read_press, .read_humid = bme280_read_humid, .read_calib = bme280_read_calib, + .set_mode = bmp280_set_mode, + .wait_conv = bmp280_wait_conv, + .preinit = bmp280_preinit, .trigger_handler = bme280_trigger_handler, }; -EXPORT_SYMBOL_NS(bme280_chip_info, IIO_BMP280); +EXPORT_SYMBOL_NS(bme280_chip_info, "IIO_BMP280"); /* * Helper function to send a command to BMP3XX sensors. @@ -1502,6 +1665,64 @@ static int bmp380_preinit(struct bmp280_data *data) return bmp380_cmd(data, BMP380_CMD_SOFT_RESET); } +static const u8 bmp380_operation_mode[] = { + [BMP280_SLEEP] = BMP380_MODE_SLEEP, + [BMP280_FORCED] = BMP380_MODE_FORCED, + [BMP280_NORMAL] = BMP380_MODE_NORMAL, +}; + +static int bmp380_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode) +{ + int ret; + + ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, + BMP380_MODE_MASK, + FIELD_PREP(BMP380_MODE_MASK, + bmp380_operation_mode[mode])); + if (ret) { + dev_err(data->dev, "failed to write power control register.\n"); + return ret; + } + + data->op_mode = mode; + + return 0; +} + +static int bmp380_wait_conv(struct bmp280_data *data) +{ + unsigned int reg; + int ret, meas_time_us; + + /* Offset measurement time */ + meas_time_us = BMP380_MEAS_OFFSET; + + /* Pressure measurement time */ + meas_time_us += BMP380_PRESS_MEAS_OFFSET + + BIT(data->oversampling_press) * BMP380_MEAS_DUR; + + /* Temperature measurement time */ + meas_time_us += BMP380_TEMP_MEAS_OFFSET + + BIT(data->oversampling_temp) * BMP380_MEAS_DUR; + + /* Measurement time defined in Datasheet Section 3.9.2 */ + fsleep(meas_time_us); + + ret = regmap_read(data->regmap, BMP380_REG_STATUS, ®); + if (ret) { + dev_err(data->dev, "failed to read status register.\n"); + return ret; + } + + if (!((reg & BMP380_STATUS_DRDY_PRESS_MASK) && + (reg & BMP380_STATUS_DRDY_TEMP_MASK))) { + dev_err(data->dev, "Measurement cycle didn't complete.\n"); + return -EBUSY; + } + + return 0; +} + static int bmp380_chip_config(struct bmp280_data *data) { bool change = false, aux; @@ -1545,14 +1766,12 @@ static int bmp380_chip_config(struct bmp280_data *data) change = change || aux; /* Set filter data */ - ret = regmap_update_bits_check(data->regmap, BMP380_REG_CONFIG, BMP380_FILTER_MASK, - FIELD_PREP(BMP380_FILTER_MASK, data->iir_filter_coeff), - &aux); + ret = regmap_update_bits(data->regmap, BMP380_REG_CONFIG, BMP380_FILTER_MASK, + FIELD_PREP(BMP380_FILTER_MASK, data->iir_filter_coeff)); if (ret) { dev_err(data->dev, "failed to write config register\n"); return ret; } - change = change || aux; if (change) { /* @@ -1564,17 +1783,19 @@ static int bmp380_chip_config(struct bmp280_data *data) * Resets sensor measurement loop toggling between sleep and * normal operating modes. */ - ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, - BMP380_MODE_MASK, - FIELD_PREP(BMP380_MODE_MASK, BMP380_MODE_SLEEP)); + ret = bmp380_set_mode(data, BMP280_SLEEP); if (ret) { dev_err(data->dev, "failed to set sleep mode\n"); return ret; } - usleep_range(2000, 2500); - ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, - BMP380_MODE_MASK, - FIELD_PREP(BMP380_MODE_MASK, BMP380_MODE_NORMAL)); + + /* + * According to the BMP3 Sensor API, the sensor needs 5ms + * in order to go to the sleep mode. + */ + fsleep(5 * USEC_PER_MSEC); + + ret = bmp380_set_mode(data, BMP280_NORMAL); if (ret) { dev_err(data->dev, "failed to set normal mode\n"); return ret; @@ -1600,7 +1821,77 @@ static int bmp380_chip_config(struct bmp280_data *data) } } - return 0; + /* Dummy read to empty data registers. */ + ret = bmp380_read_press(data, &tmp); + if (ret) + return ret; + + ret = bmp380_set_mode(data, BMP280_SLEEP); + if (ret) + dev_err(data->dev, "failed to set sleep mode.\n"); + + return ret; +} + +static int bmp380_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct bmp280_data *data = iio_trigger_get_drvdata(trig); + int ret; + + guard(mutex)(&data->lock); + + ret = regmap_update_bits(data->regmap, BMP380_REG_INT_CONTROL, + BMP380_INT_CTRL_DRDY_EN, + FIELD_PREP(BMP380_INT_CTRL_DRDY_EN, !!state)); + if (ret) + dev_err(data->dev, + "Could not %s interrupt.\n", str_enable_disable(state)); + return ret; +} + +static const struct iio_trigger_ops bmp380_trigger_ops = { + .set_trigger_state = &bmp380_data_rdy_trigger_set_state, +}; + +static int bmp380_int_pin_config(struct bmp280_data *data) +{ + int pin_drive_cfg = FIELD_PREP(BMP380_INT_CTRL_OPEN_DRAIN, + data->trig_open_drain); + int pin_level_cfg = FIELD_PREP(BMP380_INT_CTRL_LEVEL, + data->trig_active_high); + int ret, int_pin_cfg = pin_drive_cfg | pin_level_cfg; + + ret = regmap_update_bits(data->regmap, BMP380_REG_INT_CONTROL, + BMP380_INT_CTRL_SETTINGS_MASK, int_pin_cfg); + if (ret) + dev_err(data->dev, "Could not set interrupt settings.\n"); + + return ret; +} + +static irqreturn_t bmp380_irq_thread_handler(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct bmp280_data *data = iio_priv(indio_dev); + unsigned int int_ctrl; + int ret; + + ret = regmap_read(data->regmap, BMP380_REG_INT_STATUS, &int_ctrl); + if (ret) + return IRQ_NONE; + + if (FIELD_GET(BMP380_INT_STATUS_DRDY, int_ctrl)) + iio_trigger_poll_nested(data->trig); + + return IRQ_HANDLED; +} + +static int bmp380_trigger_probe(struct iio_dev *indio_dev) +{ + return __bmp280_trigger_probe(indio_dev, &bmp380_trigger_ops, + bmp380_int_pin_config, + bmp380_irq_thread_handler); } static irqreturn_t bmp380_trigger_handler(int irq, void *p) @@ -1608,7 +1899,9 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - s32 adc_temp, adc_press, t_fine; + u32 adc_temp, adc_press, comp_press; + s32 t_fine, comp_temp; + s32 *chans = (s32 *)data->sensor_data; int ret; guard(mutex)(&data->lock); @@ -1628,7 +1921,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p) goto out; } - data->sensor_data[1] = bmp380_compensate_temp(data, adc_temp); + comp_temp = bmp380_compensate_temp(data, adc_temp); /* Pressure calculations */ adc_press = get_unaligned_le24(&data->buf[0]); @@ -1638,10 +1931,12 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p) } t_fine = bmp380_calc_t_fine(data, adc_temp); + comp_press = bmp380_compensate_press(data, adc_press, t_fine); - data->sensor_data[0] = bmp380_compensate_press(data, adc_press, t_fine); + chans[0] = comp_press; + chans[1] = comp_temp; - iio_push_to_buffers_with_timestamp(indio_dev, &data->sensor_data, + iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, iio_get_time_ns(indio_dev)); out: @@ -1692,11 +1987,14 @@ const struct bmp280_chip_info bmp380_chip_info = { .read_temp = bmp380_read_temp, .read_press = bmp380_read_press, .read_calib = bmp380_read_calib, + .set_mode = bmp380_set_mode, + .wait_conv = bmp380_wait_conv, .preinit = bmp380_preinit, + .trigger_probe = bmp380_trigger_probe, .trigger_handler = bmp380_trigger_handler, }; -EXPORT_SYMBOL_NS(bmp380_chip_info, IIO_BMP280); +EXPORT_SYMBOL_NS(bmp380_chip_info, "IIO_BMP280"); static int bmp580_soft_reset(struct bmp280_data *data) { @@ -2079,6 +2377,70 @@ static int bmp580_preinit(struct bmp280_data *data) return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); } +static const u8 bmp580_operation_mode[] = { + [BMP280_SLEEP] = BMP580_MODE_SLEEP, + [BMP280_FORCED] = BMP580_MODE_FORCED, + [BMP280_NORMAL] = BMP580_MODE_NORMAL, +}; + +static int bmp580_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode) +{ + struct device *dev = data->dev; + int ret; + + if (mode == BMP280_FORCED) { + ret = regmap_set_bits(data->regmap, BMP580_REG_DSP_CONFIG, + BMP580_DSP_IIR_FORCED_FLUSH); + if (ret) { + dev_err(dev, "Could not flush IIR filter constants.\n"); + return ret; + } + } + + ret = regmap_write_bits(data->regmap, BMP580_REG_ODR_CONFIG, + BMP580_MODE_MASK, + FIELD_PREP(BMP580_MODE_MASK, + bmp580_operation_mode[mode])); + if (ret) { + dev_err(dev, "failed to write power control register.\n"); + return ret; + } + + data->op_mode = mode; + + return 0; +} + +static int bmp580_wait_conv(struct bmp280_data *data) +{ + /* + * Taken from datasheet, Section 2 "Specification, Table 3 "Electrical + * characteristics. + */ + static const int time_conv_press[] = { + 0, 1050, 1785, 3045, 5670, 10920, 21420, 42420, + 84420, + }; + static const int time_conv_temp[] = { + 0, 1050, 1105, 1575, 2205, 3465, 6090, 11340, + 21840, + }; + int meas_time_us; + + meas_time_us = 4 * USEC_PER_MSEC + + time_conv_temp[data->oversampling_temp] + + time_conv_press[data->oversampling_press]; + + /* + * Measurement time mentioned in Chapter 2, Table 4 of the datasheet. + * The extra 4ms is the required mode change to start of measurement + * time. + */ + fsleep(meas_time_us); + + return 0; +} + static int bmp580_chip_config(struct bmp280_data *data) { bool change = false, aux; @@ -2141,26 +2503,13 @@ static int bmp580_chip_config(struct bmp280_data *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); + ret = regmap_update_bits(data->regmap, BMP580_REG_DSP_IIR, + BMP580_DSP_IIR_PRESS_MASK | BMP580_DSP_IIR_TEMP_MASK, + reg_val); 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) { /* @@ -2185,12 +2534,80 @@ static int bmp580_chip_config(struct bmp280_data *data) return 0; } +static int bmp580_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct bmp280_data *data = iio_trigger_get_drvdata(trig); + int ret; + + guard(mutex)(&data->lock); + + ret = regmap_update_bits(data->regmap, BMP580_REG_INT_CONFIG, + BMP580_INT_CONFIG_INT_EN, + FIELD_PREP(BMP580_INT_CONFIG_INT_EN, !!state)); + if (ret) + dev_err(data->dev, + "Could not %s interrupt.\n", str_enable_disable(state)); + return ret; +} + +static const struct iio_trigger_ops bmp580_trigger_ops = { + .set_trigger_state = &bmp580_data_rdy_trigger_set_state, +}; + +static int bmp580_int_pin_config(struct bmp280_data *data) +{ + int pin_drive_cfg = FIELD_PREP(BMP580_INT_CONFIG_OPEN_DRAIN, + data->trig_open_drain); + int pin_level_cfg = FIELD_PREP(BMP580_INT_CONFIG_LEVEL, + data->trig_active_high); + int ret, int_pin_cfg = pin_drive_cfg | pin_level_cfg; + + ret = regmap_update_bits(data->regmap, BMP580_REG_INT_CONFIG, + BMP580_INT_CONFIG_MASK, int_pin_cfg); + if (ret) { + dev_err(data->dev, "Could not set interrupt settings.\n"); + return ret; + } + + ret = regmap_set_bits(data->regmap, BMP580_REG_INT_SOURCE, + BMP580_INT_SOURCE_DRDY); + if (ret) + dev_err(data->dev, "Could not set interrupt source.\n"); + + return ret; +} + +static irqreturn_t bmp580_irq_thread_handler(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct bmp280_data *data = iio_priv(indio_dev); + unsigned int int_ctrl; + int ret; + + ret = regmap_read(data->regmap, BMP580_REG_INT_STATUS, &int_ctrl); + if (ret) + return IRQ_NONE; + + if (FIELD_GET(BMP580_INT_STATUS_DRDY_MASK, int_ctrl)) + iio_trigger_poll_nested(data->trig); + + return IRQ_HANDLED; +} + +static int bmp580_trigger_probe(struct iio_dev *indio_dev) +{ + return __bmp280_trigger_probe(indio_dev, &bmp580_trigger_ops, + bmp580_int_pin_config, + bmp580_irq_thread_handler); +} + static irqreturn_t bmp580_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - int ret; + int ret, offset; guard(mutex)(&data->lock); @@ -2202,13 +2619,17 @@ static irqreturn_t bmp580_trigger_handler(int irq, void *p) goto out; } - /* Temperature calculations */ - memcpy(&data->sensor_data[1], &data->buf[0], 3); + offset = 0; /* Pressure calculations */ - memcpy(&data->sensor_data[0], &data->buf[3], 3); + memcpy(&data->sensor_data[offset], &data->buf[3], 3); + + offset += sizeof(s32); - iio_push_to_buffers_with_timestamp(indio_dev, &data->sensor_data, + /* Temperature calculations */ + memcpy(&data->sensor_data[offset], &data->buf[0], 3); + + iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, iio_get_time_ns(indio_dev)); out: @@ -2257,11 +2678,14 @@ const struct bmp280_chip_info bmp580_chip_info = { .chip_config = bmp580_chip_config, .read_temp = bmp580_read_temp, .read_press = bmp580_read_press, + .set_mode = bmp580_set_mode, + .wait_conv = bmp580_wait_conv, .preinit = bmp580_preinit, + .trigger_probe = bmp580_trigger_probe, .trigger_handler = bmp580_trigger_handler, }; -EXPORT_SYMBOL_NS(bmp580_chip_info, IIO_BMP280); +EXPORT_SYMBOL_NS(bmp580_chip_info, "IIO_BMP280"); static int bmp180_wait_for_eoc(struct bmp280_data *data, u8 ctrl_meas) { @@ -2504,6 +2928,19 @@ static int bmp180_read_press(struct bmp280_data *data, u32 *comp_press) return 0; } +/* Keep compatibility with newer generations of the sensor */ +static int bmp180_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode) +{ + return 0; +} + +/* Keep compatibility with newer generations of the sensor */ +static int bmp180_wait_conv(struct bmp280_data *data) +{ + return 0; +} + +/* Keep compatibility with newer generations of the sensor */ static int bmp180_chip_config(struct bmp280_data *data) { return 0; @@ -2514,23 +2951,24 @@ static irqreturn_t bmp180_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmp280_data *data = iio_priv(indio_dev); - int ret, chan_value; + int ret, comp_temp, comp_press; + s32 *chans = (s32 *)data->sensor_data; guard(mutex)(&data->lock); - ret = bmp180_read_temp(data, &chan_value); + ret = bmp180_read_temp(data, &comp_temp); if (ret) goto out; - data->sensor_data[1] = chan_value; - ret = bmp180_read_press(data, &chan_value); + ret = bmp180_read_press(data, &comp_press); if (ret) goto out; - data->sensor_data[0] = chan_value; + chans[0] = comp_press; + chans[1] = comp_temp; - iio_push_to_buffers_with_timestamp(indio_dev, &data->sensor_data, + iio_push_to_buffers_with_timestamp(indio_dev, data->sensor_data, iio_get_time_ns(indio_dev)); out: @@ -2574,10 +3012,12 @@ const struct bmp280_chip_info bmp180_chip_info = { .read_temp = bmp180_read_temp, .read_press = bmp180_read_press, .read_calib = bmp180_read_calib, + .set_mode = bmp180_set_mode, + .wait_conv = bmp180_wait_conv, .trigger_handler = bmp180_trigger_handler, }; -EXPORT_SYMBOL_NS(bmp180_chip_info, IIO_BMP280); +EXPORT_SYMBOL_NS(bmp180_chip_info, "IIO_BMP280"); static irqreturn_t bmp085_eoc_irq(int irq, void *d) { @@ -2588,15 +3028,18 @@ static irqreturn_t bmp085_eoc_irq(int irq, void *d) return IRQ_HANDLED; } -static int bmp085_fetch_eoc_irq(struct device *dev, - const char *name, - int irq, - struct bmp280_data *data) +static int bmp085_trigger_probe(struct iio_dev *indio_dev) { + struct bmp280_data *data = iio_priv(indio_dev); + struct device *dev = data->dev; unsigned long irq_trig; - int ret; + int ret, irq; - irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); + irq = fwnode_irq_get(dev_fwnode(dev), 0); + if (irq < 0) + return dev_err_probe(dev, irq, "No interrupt found.\n"); + + irq_trig = irq_get_trigger_type(irq); if (irq_trig != IRQF_TRIGGER_RISING) { dev_err(dev, "non-rising trigger given for EOC interrupt, trying to enforce it\n"); irq_trig = IRQF_TRIGGER_RISING; @@ -2604,13 +3047,8 @@ static int bmp085_fetch_eoc_irq(struct device *dev, init_completion(&data->done); - ret = devm_request_threaded_irq(dev, - irq, - bmp085_eoc_irq, - NULL, - irq_trig, - name, - data); + ret = devm_request_irq(dev, irq, bmp085_eoc_irq, irq_trig, + indio_dev->name, data); if (ret) { /* Bail out without IRQ but keep the driver in place */ dev_err(dev, "unable to request DRDY IRQ\n"); @@ -2618,14 +3056,54 @@ static int bmp085_fetch_eoc_irq(struct device *dev, } data->use_eoc = true; + return 0; } +/* Identical to bmp180_chip_info + bmp085_trigger_probe */ +const struct bmp280_chip_info bmp085_chip_info = { + .id_reg = BMP280_REG_ID, + .chip_id = bmp180_chip_ids, + .num_chip_id = ARRAY_SIZE(bmp180_chip_ids), + .regmap_config = &bmp180_regmap_config, + .start_up_time = 2000, + .channels = bmp280_channels, + .num_channels = ARRAY_SIZE(bmp280_channels), + .avail_scan_masks = bmp280_avail_scan_masks, + + .oversampling_temp_avail = bmp180_oversampling_temp_avail, + .num_oversampling_temp_avail = + ARRAY_SIZE(bmp180_oversampling_temp_avail), + .oversampling_temp_default = 0, + + .oversampling_press_avail = bmp180_oversampling_press_avail, + .num_oversampling_press_avail = + ARRAY_SIZE(bmp180_oversampling_press_avail), + .oversampling_press_default = BMP180_MEAS_PRESS_8X, + + .temp_coeffs = bmp180_temp_coeffs, + .temp_coeffs_type = IIO_VAL_FRACTIONAL, + .press_coeffs = bmp180_press_coeffs, + .press_coeffs_type = IIO_VAL_FRACTIONAL, + + .chip_config = bmp180_chip_config, + .read_temp = bmp180_read_temp, + .read_press = bmp180_read_press, + .read_calib = bmp180_read_calib, + .set_mode = bmp180_set_mode, + .wait_conv = bmp180_wait_conv, + + .trigger_probe = bmp085_trigger_probe, + .trigger_handler = bmp180_trigger_handler, +}; +EXPORT_SYMBOL_NS(bmp085_chip_info, "IIO_BMP280"); + static int bmp280_buffer_preenable(struct iio_dev *indio_dev) { struct bmp280_data *data = iio_priv(indio_dev); pm_runtime_get_sync(data->dev); + data->chip_info->set_mode(data, BMP280_NORMAL); return 0; } @@ -2790,12 +3268,17 @@ int bmp280_common_probe(struct device *dev, * however as it happens, the BMP085 shares the chip ID of BMP180 * so we look for an IRQ if we have that. */ - if (irq > 0 && (chip_id == BMP180_CHIP_ID)) { - ret = bmp085_fetch_eoc_irq(dev, name, irq, data); + if (irq > 0) { + if (data->chip_info->trigger_probe) + ret = data->chip_info->trigger_probe(indio_dev); if (ret) return ret; } + ret = data->chip_info->set_mode(data, BMP280_SLEEP); + if (ret) + return dev_err_probe(dev, ret, "Failed to set sleep mode\n"); + /* Enable runtime PM */ pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); @@ -2814,13 +3297,16 @@ int bmp280_common_probe(struct device *dev, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS(bmp280_common_probe, IIO_BMP280); +EXPORT_SYMBOL_NS(bmp280_common_probe, "IIO_BMP280"); static int bmp280_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmp280_data *data = iio_priv(indio_dev); + data->chip_info->set_mode(data, BMP280_SLEEP); + + fsleep(data->start_up_time); return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies); } @@ -2835,7 +3321,12 @@ static int bmp280_runtime_resume(struct device *dev) return ret; usleep_range(data->start_up_time, data->start_up_time + 100); - return data->chip_info->chip_config(data); + + ret = data->chip_info->chip_config(data); + if (ret) + return ret; + + return data->chip_info->set_mode(data, data->op_mode); } EXPORT_RUNTIME_DEV_PM_OPS(bmp280_dev_pm_ops, bmp280_runtime_suspend, diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 5c3a63b4327c80..868e1b2ec7112a 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -27,7 +27,7 @@ static int bmp280_i2c_probe(struct i2c_client *client) } static const struct of_device_id bmp280_of_i2c_match[] = { - { .compatible = "bosch,bmp085", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp085", .data = &bmp085_chip_info }, { .compatible = "bosch,bmp180", .data = &bmp180_chip_info }, { .compatible = "bosch,bmp280", .data = &bmp280_chip_info }, { .compatible = "bosch,bme280", .data = &bme280_chip_info }, @@ -38,7 +38,7 @@ static const struct of_device_id bmp280_of_i2c_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match); static const struct i2c_device_id bmp280_i2c_id[] = { - {"bmp085", (kernel_ulong_t)&bmp180_chip_info }, + {"bmp085", (kernel_ulong_t)&bmp085_chip_info }, {"bmp180", (kernel_ulong_t)&bmp180_chip_info }, {"bmp280", (kernel_ulong_t)&bmp280_chip_info }, {"bme280", (kernel_ulong_t)&bme280_chip_info }, @@ -62,4 +62,4 @@ module_i2c_driver(bmp280_i2c_driver); MODULE_AUTHOR("Vlad Dogaru "); MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_BMP280); +MODULE_IMPORT_NS("IIO_BMP280"); diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c index d27d68edd90656..b6a7b417c8cf73 100644 --- a/drivers/iio/pressure/bmp280-regmap.c +++ b/drivers/iio/pressure/bmp280-regmap.c @@ -39,7 +39,7 @@ const struct regmap_config bmp180_regmap_config = { .writeable_reg = bmp180_is_writeable_reg, .volatile_reg = bmp180_is_volatile_reg, }; -EXPORT_SYMBOL_NS(bmp180_regmap_config, IIO_BMP280); +EXPORT_SYMBOL_NS(bmp180_regmap_config, "IIO_BMP280"); static bool bme280_is_writeable_reg(struct device *dev, unsigned int reg) { @@ -200,7 +200,7 @@ const struct regmap_config bmp280_regmap_config = { .writeable_reg = bmp280_is_writeable_reg, .volatile_reg = bmp280_is_volatile_reg, }; -EXPORT_SYMBOL_NS(bmp280_regmap_config, IIO_BMP280); +EXPORT_SYMBOL_NS(bmp280_regmap_config, "IIO_BMP280"); const struct regmap_config bme280_regmap_config = { .reg_bits = 8, @@ -212,7 +212,7 @@ const struct regmap_config bme280_regmap_config = { .writeable_reg = bme280_is_writeable_reg, .volatile_reg = bme280_is_volatile_reg, }; -EXPORT_SYMBOL_NS(bme280_regmap_config, IIO_BMP280); +EXPORT_SYMBOL_NS(bme280_regmap_config, "IIO_BMP280"); const struct regmap_config bmp380_regmap_config = { .reg_bits = 8, @@ -224,7 +224,7 @@ const struct regmap_config bmp380_regmap_config = { .writeable_reg = bmp380_is_writeable_reg, .volatile_reg = bmp380_is_volatile_reg, }; -EXPORT_SYMBOL_NS(bmp380_regmap_config, IIO_BMP280); +EXPORT_SYMBOL_NS(bmp380_regmap_config, "IIO_BMP280"); const struct regmap_config bmp580_regmap_config = { .reg_bits = 8, @@ -236,4 +236,4 @@ const struct regmap_config bmp580_regmap_config = { .writeable_reg = bmp580_is_writeable_reg, .volatile_reg = bmp580_is_volatile_reg, }; -EXPORT_SYMBOL_NS(bmp580_regmap_config, IIO_BMP280); +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 d18549d9bb647d..0e6e27892f99a8 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -114,7 +114,7 @@ static int bmp280_spi_probe(struct spi_device *spi) } static const struct of_device_id bmp280_of_spi_match[] = { - { .compatible = "bosch,bmp085", .data = &bmp180_chip_info }, + { .compatible = "bosch,bmp085", .data = &bmp085_chip_info }, { .compatible = "bosch,bmp180", .data = &bmp180_chip_info }, { .compatible = "bosch,bmp181", .data = &bmp180_chip_info }, { .compatible = "bosch,bmp280", .data = &bmp280_chip_info }, @@ -126,7 +126,7 @@ static const struct of_device_id bmp280_of_spi_match[] = { MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); static const struct spi_device_id bmp280_spi_id[] = { - { "bmp085", (kernel_ulong_t)&bmp180_chip_info }, + { "bmp085", (kernel_ulong_t)&bmp085_chip_info }, { "bmp180", (kernel_ulong_t)&bmp180_chip_info }, { "bmp181", (kernel_ulong_t)&bmp180_chip_info }, { "bmp280", (kernel_ulong_t)&bmp280_chip_info }, @@ -150,4 +150,4 @@ module_spi_driver(bmp280_spi_driver); MODULE_DESCRIPTION("BMP280 SPI bus driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_BMP280); +MODULE_IMPORT_NS("IIO_BMP280"); diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index ccacc67c147311..2df1175b6b8539 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -55,8 +55,17 @@ #define BMP580_CMD_NVM_WRITE_SEQ_1 0xA0 #define BMP580_CMD_SOFT_RESET 0xB6 +#define BMP580_INT_STATUS_DRDY_MASK BIT(0) #define BMP580_INT_STATUS_POR_MASK BIT(4) +#define BMP580_INT_SOURCE_DRDY BIT(0) + +#define BMP580_INT_CONFIG_MASK GENMASK(3, 0) +#define BMP580_INT_CONFIG_LATCH BIT(0) +#define BMP580_INT_CONFIG_LEVEL BIT(1) +#define BMP580_INT_CONFIG_OPEN_DRAIN BIT(2) +#define BMP580_INT_CONFIG_INT_EN BIT(3) + #define BMP580_STATUS_CORE_RDY_MASK BIT(0) #define BMP580_STATUS_NVM_RDY_MASK BIT(1) #define BMP580_STATUS_NVM_ERR_MASK BIT(2) @@ -170,6 +179,19 @@ #define BMP380_MODE_FORCED 1 #define BMP380_MODE_NORMAL 3 +#define BMP380_MEAS_OFFSET 234 +#define BMP380_MEAS_DUR 2020 +#define BMP380_TEMP_MEAS_OFFSET 163 +#define BMP380_PRESS_MEAS_OFFSET 392 + +#define BMP380_INT_STATUS_DRDY BIT(3) + +#define BMP380_INT_CTRL_SETTINGS_MASK GENMASK(2, 0) +#define BMP380_INT_CTRL_OPEN_DRAIN BIT(0) +#define BMP380_INT_CTRL_LEVEL BIT(1) +#define BMP380_INT_CTRL_LATCH BIT(2) +#define BMP380_INT_CTRL_DRDY_EN BIT(6) + #define BMP380_MIN_TEMP -4000 #define BMP380_MAX_TEMP 8500 #define BMP380_MIN_PRES 3000000 @@ -205,6 +227,10 @@ #define BMP280_REG_CONFIG 0xF5 #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_STATUS 0xF3 +#define BMP280_REG_STATUS_IM_UPDATE BIT(0) +#define BMP280_REG_STATUS_MEAS_BIT BIT(3) +#define BMP280_REG_RESET 0xE0 +#define BMP280_RST_SOFT_CMD 0xB6 #define BMP280_REG_COMP_TEMP_START 0x88 #define BMP280_COMP_TEMP_REG_COUNT 6 @@ -243,6 +269,10 @@ #define BMP280_MODE_FORCED 1 #define BMP280_MODE_NORMAL 3 +#define BMP280_MEAS_OFFSET 1250 +#define BMP280_MEAS_DUR 2300 +#define BMP280_PRESS_HUMID_MEAS_OFFSET 575 + /* BME280 specific registers */ #define BME280_REG_HUMIDITY_LSB 0xFE #define BME280_REG_HUMIDITY_MSB 0xFD @@ -257,8 +287,13 @@ #define BME280_REG_COMP_H5 0xE5 #define BME280_REG_COMP_H6 0xE7 +#define BME280_COMP_H4_GET_MASK_UP GENMASK(15, 8) +#define BME280_COMP_H4_PREP_MASK_UP GENMASK(11, 4) +#define BME280_COMP_H4_MASK_LOW GENMASK(3, 0) #define BME280_COMP_H5_MASK GENMASK(15, 4) +#define BME280_CONTIGUOUS_CALIB_REGS 7 + #define BME280_OSRS_HUMIDITY_MASK GENMASK(2, 0) #define BME280_OSRS_HUMIDITY_SKIP 0 #define BME280_OSRS_HUMIDITY_1X 1 @@ -314,6 +349,7 @@ BMP280_NUM_TEMP_BYTES + \ BME280_NUM_HUMIDITY_BYTES) +#define BME280_NUM_MAX_CHANNELS 3 /* Core exported structs */ static const char *const bmp280_supply_names[] = { @@ -376,12 +412,21 @@ struct bmp380_calib { s8 P11; }; +enum bmp280_op_mode { + BMP280_SLEEP, + BMP280_FORCED, + BMP280_NORMAL, +}; + struct bmp280_data { struct device *dev; struct mutex lock; struct regmap *regmap; struct completion done; bool use_eoc; + bool trig_open_drain; + bool trig_active_high; + struct iio_trigger *trig; const struct bmp280_chip_info *chip_info; union { struct bmp180_calib bmp180; @@ -411,7 +456,11 @@ struct bmp280_data { * Data to push to userspace triggered buffer. Up to 3 channels and * s64 timestamp, aligned. */ - s32 sensor_data[6] __aligned(8); + u8 sensor_data[ALIGN(sizeof(s32) * BME280_NUM_MAX_CHANNELS, sizeof(s64)) + + sizeof(s64)] __aligned(sizeof(s64)); + + /* Value to hold the current operation mode of the device */ + enum bmp280_op_mode op_mode; /* * DMA (thus cache coherency maintenance) may require the @@ -423,6 +472,7 @@ struct bmp280_data { /* Calibration data buffers */ __le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2]; __be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2]; + u8 bme280_humid_cal_buf[BME280_CONTIGUOUS_CALIB_REGS]; u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT]; /* Miscellaneous, endianness-aware data buffers */ __le16 le16; @@ -476,11 +526,15 @@ struct bmp280_chip_info { int (*read_humid)(struct bmp280_data *data, u32 *adc_humidity); int (*read_calib)(struct bmp280_data *data); int (*preinit)(struct bmp280_data *data); + int (*set_mode)(struct bmp280_data *data, enum bmp280_op_mode mode); + int (*wait_conv)(struct bmp280_data *data); + int (*trigger_probe)(struct iio_dev *indio_dev); irqreturn_t (*trigger_handler)(int irq, void *p); }; /* Chip infos for each variant */ +extern const struct bmp280_chip_info bmp085_chip_info; 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; diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 956045e2db293c..f7273d30c5f085 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -24,7 +24,7 @@ struct press_state { struct hid_sensor_hub_attribute_info press_attr; struct { u32 press_data; - u64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -241,11 +241,11 @@ static int press_parse_report(struct platform_device *pdev, /* Function to initialize the processing for usage id */ static int hid_press_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret = 0; static const char *name = "press"; struct iio_dev *indio_dev; struct press_state *press_state; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct press_state)); @@ -325,7 +325,7 @@ static int hid_press_probe(struct platform_device *pdev) /* Function to deinitialize the processing for usage id */ static void hid_press_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct press_state *press_state = iio_priv(indio_dev); @@ -350,11 +350,11 @@ static struct platform_driver hid_press_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_press_probe, - .remove_new = hid_press_remove, + .remove = hid_press_remove, }; module_platform_driver(hid_press_platform_driver); MODULE_DESCRIPTION("HID Sensor Pressure"); MODULE_AUTHOR("Archana Patni "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c index 4e6f10eeabc301..168245818cfe36 100644 --- a/drivers/iio/pressure/hsc030pa.c +++ b/drivers/iio/pressure/hsc030pa.c @@ -534,7 +534,7 @@ int hsc_common_probe(struct device *dev, hsc_recv_fn recv) return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS(hsc_common_probe, IIO_HONEYWELL_HSC030PA); +EXPORT_SYMBOL_NS(hsc_common_probe, "IIO_HONEYWELL_HSC030PA"); MODULE_AUTHOR("Petre Rodan "); MODULE_DESCRIPTION("Honeywell HSC and SSC pressure sensor core driver"); diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c index b3fd230e71da12..7f2398aa815525 100644 --- a/drivers/iio/pressure/hsc030pa_i2c.c +++ b/drivers/iio/pressure/hsc030pa_i2c.c @@ -71,4 +71,4 @@ module_i2c_driver(hsc_i2c_driver); MODULE_AUTHOR("Petre Rodan "); MODULE_DESCRIPTION("Honeywell HSC and SSC pressure sensor i2c driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HONEYWELL_HSC030PA); +MODULE_IMPORT_NS("IIO_HONEYWELL_HSC030PA"); diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c index 337eecc577d2a2..60768726e9ad82 100644 --- a/drivers/iio/pressure/hsc030pa_spi.c +++ b/drivers/iio/pressure/hsc030pa_spi.c @@ -58,4 +58,4 @@ module_spi_driver(hsc_spi_driver); MODULE_AUTHOR("Petre Rodan "); MODULE_DESCRIPTION("Honeywell HSC and SSC pressure sensor spi driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HONEYWELL_HSC030PA); +MODULE_IMPORT_NS("IIO_HONEYWELL_HSC030PA"); diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c index 02ea38c8a3e431..71beb28b7f2ca0 100644 --- a/drivers/iio/pressure/mpl115.c +++ b/drivers/iio/pressure/mpl115.c @@ -225,7 +225,7 @@ int mpl115_probe(struct device *dev, const char *name, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115); +EXPORT_SYMBOL_NS_GPL(mpl115_probe, "IIO_MPL115"); static int mpl115_runtime_suspend(struct device *dev) { diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c index 0c51dc02478e21..3db9ef4e2770f1 100644 --- a/drivers/iio/pressure/mpl115_i2c.c +++ b/drivers/iio/pressure/mpl115_i2c.c @@ -63,4 +63,4 @@ module_i2c_driver(mpl115_i2c_driver); MODULE_AUTHOR("Peter Meerwald "); MODULE_DESCRIPTION("Freescale MPL115A2 pressure/temperature driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_MPL115); +MODULE_IMPORT_NS("IIO_MPL115"); diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c index 58d218fd90dcb9..888cfa6662381e 100644 --- a/drivers/iio/pressure/mpl115_spi.c +++ b/drivers/iio/pressure/mpl115_spi.c @@ -102,4 +102,4 @@ module_spi_driver(mpl115_spi_driver); MODULE_AUTHOR("Akinobu Mita "); MODULE_DESCRIPTION("Freescale MPL115A1 pressure/temperature driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_MPL115); +MODULE_IMPORT_NS("IIO_MPL115"); diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c index 3b6145348c2e3b..2336f2760eaeb7 100644 --- a/drivers/iio/pressure/mprls0025pa.c +++ b/drivers/iio/pressure/mprls0025pa.c @@ -448,7 +448,7 @@ int mpr_common_probe(struct device *dev, const struct mpr_ops *ops, int irq) return 0; } -EXPORT_SYMBOL_NS(mpr_common_probe, IIO_HONEYWELL_MPRLS0025PA); +EXPORT_SYMBOL_NS(mpr_common_probe, "IIO_HONEYWELL_MPRLS0025PA"); MODULE_AUTHOR("Andreas Klinger "); MODULE_DESCRIPTION("Honeywell MPR pressure sensor core driver"); diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c index 7a5c5aa2b456b9..48b23a4256ced0 100644 --- a/drivers/iio/pressure/mprls0025pa_i2c.c +++ b/drivers/iio/pressure/mprls0025pa_i2c.c @@ -97,4 +97,4 @@ module_i2c_driver(mpr_i2c_driver); MODULE_AUTHOR("Andreas Klinger "); MODULE_DESCRIPTION("Honeywell MPR pressure sensor i2c driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA); +MODULE_IMPORT_NS("IIO_HONEYWELL_MPRLS0025PA"); diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c index 3aed14cd95c5ab..09f724c76d706e 100644 --- a/drivers/iio/pressure/mprls0025pa_spi.c +++ b/drivers/iio/pressure/mprls0025pa_spi.c @@ -89,4 +89,4 @@ module_spi_driver(mpr_spi_driver); MODULE_AUTHOR("Petre Rodan "); MODULE_DESCRIPTION("Honeywell MPR pressure sensor spi driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HONEYWELL_MPRLS0025PA); +MODULE_IMPORT_NS("IIO_HONEYWELL_MPRLS0025PA"); diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index 2fc706f9d8ae7d..056c8271c49d93 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -449,7 +449,7 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, return 0; } -EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611); +EXPORT_SYMBOL_NS(ms5611_probe, "IIO_MS5611"); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("MS5611 core driver"); diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index 7e2cb8b6afa223..1c041b9085fb01 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -132,4 +132,4 @@ module_i2c_driver(ms5611_driver); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("MS5611 i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MS5611); +MODULE_IMPORT_NS("IIO_MS5611"); diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index 87181963a3e3db..b5a91e88579354 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -134,4 +134,4 @@ module_spi_driver(ms5611_driver); MODULE_AUTHOR("Tomasz Duszynski "); MODULE_DESCRIPTION("MS5611 spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MS5611); +MODULE_IMPORT_NS("IIO_MS5611"); diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index ac30d76285d1c2..a1767a17fdce91 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -248,4 +248,4 @@ MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver MODULE_AUTHOR("William Markezana "); MODULE_AUTHOR("Ludovic Tancerel "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); +MODULE_IMPORT_NS("IIO_MEAS_SPEC_SENSORS"); diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c index ccaa07a569c9a8..f24d9f92768123 100644 --- a/drivers/iio/pressure/rohm-bm1390.c +++ b/drivers/iio/pressure/rohm-bm1390.c @@ -417,9 +417,6 @@ static int __bm1390_fifo_flush(struct iio_dev *idev, unsigned int samples, return ret; } - if (ret) - return ret; - for (i = 0; i < smp_lvl; i++) { buffer[i].temp = temp; iio_push_to_buffers(idev, &buffer[i]); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 597bf268ea5172..b70d1cee82f324 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -738,7 +738,7 @@ const struct st_sensor_settings *st_press_get_settings(const char *name) return &st_press_sensors_settings[index]; } -EXPORT_SYMBOL_NS(st_press_get_settings, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_press_get_settings, "IIO_ST_SENSORS"); int st_press_common_probe(struct iio_dev *indio_dev) { @@ -790,9 +790,9 @@ int st_press_common_probe(struct iio_dev *indio_dev) return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL_NS(st_press_common_probe, IIO_ST_SENSORS); +EXPORT_SYMBOL_NS(st_press_common_probe, "IIO_ST_SENSORS"); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics pressures driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 389523d6ae3210..b7b66ddc3a7307 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -121,4 +121,4 @@ module_i2c_driver(st_press_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index 25cca5ad7c5599..1a4bd1a0f78745 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -123,4 +123,4 @@ module_spi_driver(st_press_driver); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics pressures spi driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ST_SENSORS); +MODULE_IMPORT_NS("IIO_ST_SENSORS"); diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 950f8dee2b26b7..2adea84f5b4d08 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -162,7 +162,7 @@ bool zpa2326_isreg_writeable(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_writeable, IIO_ZPA2326); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_writeable, "IIO_ZPA2326"); bool zpa2326_isreg_readable(struct device *dev, unsigned int reg) { @@ -191,7 +191,7 @@ bool zpa2326_isreg_readable(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_readable, IIO_ZPA2326); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_readable, "IIO_ZPA2326"); bool zpa2326_isreg_precious(struct device *dev, unsigned int reg) { @@ -204,7 +204,7 @@ bool zpa2326_isreg_precious(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_precious, IIO_ZPA2326); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_precious, "IIO_ZPA2326"); /** * zpa2326_enable_device() - Enable device, i.e. get out of low power mode. @@ -649,7 +649,7 @@ const struct dev_pm_ops zpa2326_pm_ops = { SET_RUNTIME_PM_OPS(zpa2326_runtime_suspend, zpa2326_runtime_resume, NULL) }; -EXPORT_SYMBOL_NS_GPL(zpa2326_pm_ops, IIO_ZPA2326); +EXPORT_SYMBOL_NS_GPL(zpa2326_pm_ops, "IIO_ZPA2326"); /** * zpa2326_resume() - Request the PM layer to power supply the device. @@ -1698,7 +1698,7 @@ int zpa2326_probe(struct device *parent, return err; } -EXPORT_SYMBOL_NS_GPL(zpa2326_probe, IIO_ZPA2326); +EXPORT_SYMBOL_NS_GPL(zpa2326_probe, "IIO_ZPA2326"); void zpa2326_remove(const struct device *parent) { @@ -1709,7 +1709,7 @@ void zpa2326_remove(const struct device *parent) zpa2326_sleep(indio_dev); zpa2326_power_off(indio_dev, iio_priv(indio_dev)); } -EXPORT_SYMBOL_NS_GPL(zpa2326_remove, IIO_ZPA2326); +EXPORT_SYMBOL_NS_GPL(zpa2326_remove, "IIO_ZPA2326"); MODULE_AUTHOR("Gregor Boirie "); MODULE_DESCRIPTION("Core driver for Murata ZPA2326 pressure sensor"); diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c index 4833e525c39357..49a239ebdabff5 100644 --- a/drivers/iio/pressure/zpa2326_i2c.c +++ b/drivers/iio/pressure/zpa2326_i2c.c @@ -85,4 +85,4 @@ module_i2c_driver(zpa2326_i2c_driver); MODULE_AUTHOR("Gregor Boirie "); MODULE_DESCRIPTION("I2C driver for Murata ZPA2326 pressure sensor"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ZPA2326); +MODULE_IMPORT_NS("IIO_ZPA2326"); diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c index 9c1bcb82d3604e..317270fa1c4351 100644 --- a/drivers/iio/pressure/zpa2326_spi.c +++ b/drivers/iio/pressure/zpa2326_spi.c @@ -89,4 +89,4 @@ module_spi_driver(zpa2326_spi_driver); MODULE_AUTHOR("Gregor Boirie "); MODULE_DESCRIPTION("SPI driver for Murata ZPA2326 pressure sensor"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_ZPA2326); +MODULE_IMPORT_NS("IIO_ZPA2326"); diff --git a/drivers/iio/proximity/aw96103.c b/drivers/iio/proximity/aw96103.c index 707ba0a510aa5f..cdd254da9e5035 100644 --- a/drivers/iio/proximity/aw96103.c +++ b/drivers/iio/proximity/aw96103.c @@ -422,7 +422,7 @@ static int aw96103_read_event_config(struct iio_dev *indio_dev, static int aw96103_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) + enum iio_event_direction dir, bool state) { struct aw96103 *aw96103 = iio_priv(indio_dev); diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c index c25472b14d4be0..667369be05553e 100644 --- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c +++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c @@ -167,7 +167,7 @@ static int cros_ec_mkbp_proximity_read_event_config(struct iio_dev *indio_dev, static int cros_ec_mkbp_proximity_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) + enum iio_event_direction dir, bool state) { struct cros_ec_mkbp_proximity_data *data = iio_priv(indio_dev); @@ -261,7 +261,7 @@ static struct platform_driver cros_ec_mkbp_proximity_driver = { .pm = pm_sleep_ptr(&cros_ec_mkbp_proximity_pm_ops), }, .probe = cros_ec_mkbp_proximity_probe, - .remove_new = cros_ec_mkbp_proximity_remove, + .remove = cros_ec_mkbp_proximity_remove, }; module_platform_driver(cros_ec_mkbp_proximity_driver); diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c index d8fb34060d3db8..4021feb7a7ac70 100644 --- a/drivers/iio/proximity/hx9023s.c +++ b/drivers/iio/proximity/hx9023s.c @@ -874,12 +874,12 @@ static int hx9023s_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) + bool state) { struct hx9023s_data *data = iio_priv(indio_dev); if (test_bit(chan->channel, &data->chan_in_use)) { - hx9023s_ch_en(data, chan->channel, !!state); + hx9023s_ch_en(data, chan->channel, state); __assign_bit(chan->channel, &data->chan_event, data->ch_data[chan->channel].enable); } diff --git a/drivers/iio/proximity/irsd200.c b/drivers/iio/proximity/irsd200.c index 6e96b764fed8b5..b09d15230111e6 100644 --- a/drivers/iio/proximity/irsd200.c +++ b/drivers/iio/proximity/irsd200.c @@ -648,7 +648,8 @@ static int irsd200_read_event_config(struct iio_dev *indio_dev, static int irsd200_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) + enum iio_event_direction dir, + bool state) { struct irsd200_data *data = iio_priv(indio_dev); unsigned int tmp; @@ -662,7 +663,7 @@ static int irsd200_write_event_config(struct iio_dev *indio_dev, return ret; return regmap_field_write( - data->regfields[IRS_REGF_INTR_COUNT_THR_OR], !!state); + data->regfields[IRS_REGF_INTR_COUNT_THR_OR], state); default: return -EINVAL; } diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index 86c57672fc7e36..71ad29e441b237 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -389,7 +389,7 @@ static const struct dev_pm_ops srf04_pm_ops = { static struct platform_driver srf04_driver = { .probe = srf04_probe, - .remove_new = srf04_remove, + .remove = srf04_remove, .driver = { .name = "srf04-gpio", .of_match_table = of_srf04_match, diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 427c9343d6d163..0d7f0518d4fb95 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -1029,4 +1029,4 @@ MODULE_AUTHOR("Gwendal Grignou "); MODULE_AUTHOR("Daniel Campello "); MODULE_DESCRIPTION("Driver for Semtech SX9310/SX9311 proximity sensor"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SEMTECH_PROX); +MODULE_IMPORT_NS("SEMTECH_PROX"); diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index 629f83c37d595b..f7819dd2775cd0 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -868,6 +868,26 @@ static u8 sx9324_parse_phase_prop(struct device *dev, return raw; } +static 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 +} + static const struct sx_common_reg_default * sx9324_get_default_reg(struct device *dev, int idx, struct sx_common_reg_default *reg_def) @@ -1135,4 +1155,4 @@ module_i2c_driver(sx9324_driver); MODULE_AUTHOR("Gwendal Grignou "); MODULE_DESCRIPTION("Driver for Semtech SX9324 proximity sensor"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SEMTECH_PROX); +MODULE_IMPORT_NS("SEMTECH_PROX"); diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 2b90bf45a20121..a6ff16e33c1e20 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -7,7 +7,6 @@ * https://edit.wpgdadawant.com/uploads/news_file/program/2019/30184/tech_files/program_30184_suggest_other_file.pdf */ -#include #include #include #include @@ -866,4 +865,4 @@ module_i2c_driver(sx9360_driver); MODULE_AUTHOR("Gwendal Grignou "); MODULE_DESCRIPTION("Driver for Semtech SX9360 proximity sensor"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SEMTECH_PROX); +MODULE_IMPORT_NS("SEMTECH_PROX"); diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 3f4eace05cfc6a..c4e94d0fb16374 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -540,7 +540,7 @@ static int sx9500_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) + bool state) { struct sx9500_data *data = iio_priv(indio_dev); int ret; @@ -551,7 +551,7 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, mutex_lock(&data->mutex); - if (state == 1) { + if (state) { ret = sx9500_inc_chan_users(data, chan->channel); if (ret < 0) goto out_unlock; @@ -571,7 +571,7 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, goto out_unlock; out_undo_chan: - if (state == 1) + if (state) sx9500_dec_chan_users(data, chan->channel); else sx9500_inc_chan_users(data, chan->channel); diff --git a/drivers/iio/proximity/sx_common.c b/drivers/iio/proximity/sx_common.c index 71aa6dced7d342..f70198a1f0d145 100644 --- a/drivers/iio/proximity/sx_common.c +++ b/drivers/iio/proximity/sx_common.c @@ -53,7 +53,7 @@ const struct iio_event_spec sx_common_events[3] = { BIT(IIO_EV_INFO_VALUE), }, }; -EXPORT_SYMBOL_NS_GPL(sx_common_events, SEMTECH_PROX); +EXPORT_SYMBOL_NS_GPL(sx_common_events, "SEMTECH_PROX"); static irqreturn_t sx_common_irq_handler(int irq, void *private) { @@ -233,7 +233,7 @@ int sx_common_read_proximity(struct sx_common_data *data, return ret; } -EXPORT_SYMBOL_NS_GPL(sx_common_read_proximity, SEMTECH_PROX); +EXPORT_SYMBOL_NS_GPL(sx_common_read_proximity, "SEMTECH_PROX"); /** * sx_common_read_event_config() - Configure event setting. @@ -253,7 +253,7 @@ int sx_common_read_event_config(struct iio_dev *indio_dev, return !!(data->chan_event & BIT(chan->channel)); } -EXPORT_SYMBOL_NS_GPL(sx_common_read_event_config, SEMTECH_PROX); +EXPORT_SYMBOL_NS_GPL(sx_common_read_event_config, "SEMTECH_PROX"); /** * sx_common_write_event_config() - Configure event setting. @@ -268,7 +268,7 @@ EXPORT_SYMBOL_NS_GPL(sx_common_read_event_config, SEMTECH_PROX); int sx_common_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) + enum iio_event_direction dir, bool state) { struct sx_common_data *data = iio_priv(indio_dev); unsigned int eventirq = SX_COMMON_FAR_IRQ | SX_COMMON_CLOSE_IRQ; @@ -303,7 +303,7 @@ int sx_common_write_event_config(struct iio_dev *indio_dev, mutex_unlock(&data->mutex); return ret; } -EXPORT_SYMBOL_NS_GPL(sx_common_write_event_config, SEMTECH_PROX); +EXPORT_SYMBOL_NS_GPL(sx_common_write_event_config, "SEMTECH_PROX"); static int sx_common_set_trigger_state(struct iio_trigger *trig, bool state) { @@ -421,27 +421,6 @@ 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) @@ -563,7 +542,7 @@ int sx_common_probe(struct i2c_client *client, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_NS_GPL(sx_common_probe, SEMTECH_PROX); +EXPORT_SYMBOL_NS_GPL(sx_common_probe, "SEMTECH_PROX"); MODULE_AUTHOR("Gwendal Grignou "); MODULE_DESCRIPTION("Common functions and structures for Semtech sensor"); diff --git a/drivers/iio/proximity/sx_common.h b/drivers/iio/proximity/sx_common.h index 101b90e52ff268..fb14e6f06a6de3 100644 --- a/drivers/iio/proximity/sx_common.h +++ b/drivers/iio/proximity/sx_common.h @@ -8,7 +8,6 @@ #ifndef IIO_SX_COMMON_H #define IIO_SX_COMMON_H -#include #include #include #include @@ -144,15 +143,12 @@ int sx_common_read_event_config(struct iio_dev *indio_dev, int sx_common_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); + enum iio_event_direction dir, bool state); 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/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c index d1ddf85f53836e..bb6c9cc88b358d 100644 --- a/drivers/iio/proximity/vcnl3020.c +++ b/drivers/iio/proximity/vcnl3020.c @@ -449,7 +449,7 @@ static int vcnl3020_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) + bool state) { switch (chan->type) { case IIO_PROXIMITY: diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index 8d4f3f849fe246..87d10faaff9b11 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -20,8 +20,13 @@ #include #include #include +#include #include +#include +#include +#include +#include #define VL_REG_SYSRANGE_START 0x00 @@ -39,21 +44,74 @@ #define VL_REG_RESULT_INT_STATUS 0x13 #define VL_REG_RESULT_RANGE_STATUS 0x14 +#define VL_REG_IDENTIFICATION_MODEL_ID 0xC0 #define VL_REG_RESULT_RANGE_STATUS_COMPLETE BIT(0) +#define VL53L0X_MODEL_ID_VAL 0xEE +#define VL53L0X_CONTINUOUS_MODE 0x02 +#define VL53L0X_SINGLE_MODE 0x01 + struct vl53l0x_data { struct i2c_client *client; struct completion completion; struct regulator *vdd_supply; struct gpio_desc *reset_gpio; + struct iio_trigger *trig; + + struct { + u16 chan; + aligned_s64 timestamp; + } scan; }; -static irqreturn_t vl53l0x_handle_irq(int irq, void *priv) +static int vl53l0x_clear_irq(struct vl53l0x_data *data) +{ int ret; + + ret = i2c_smbus_write_byte_data(data->client, + VL_REG_SYSTEM_INTERRUPT_CLEAR, 1); + if (ret < 0) { + dev_err(&data->client->dev, "failed to clear irq: %d\n", ret); + return -EINVAL; + } + + return 0; +} + +static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv) +{ + struct iio_poll_func *pf = priv; + struct iio_dev *indio_dev = pf->indio_dev; + struct vl53l0x_data *data = iio_priv(indio_dev); + u8 buffer[12]; + int ret; + + ret = i2c_smbus_read_i2c_block_data(data->client, + VL_REG_RESULT_RANGE_STATUS, + sizeof(buffer), buffer); + if (ret < 0) + return ret; + else if (ret != 12) + return -EREMOTEIO; + + data->scan.chan = get_unaligned_be16(&buffer[10]); + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, + iio_get_time_ns(indio_dev)); + + iio_trigger_notify_done(indio_dev->trig); + vl53l0x_clear_irq(data); + + return IRQ_HANDLED; +} + +static irqreturn_t vl53l0x_threaded_irq(int irq, void *priv) { struct iio_dev *indio_dev = priv; struct vl53l0x_data *data = iio_priv(indio_dev); - complete(&data->completion); + if (iio_buffer_enabled(indio_dev)) + iio_trigger_poll_nested(indio_dev->trig); + else + complete(&data->completion); return IRQ_HANDLED; } @@ -68,8 +126,9 @@ static int vl53l0x_configure_irq(struct i2c_client *client, if (!irq_flags) irq_flags = IRQF_TRIGGER_FALLING; - ret = devm_request_irq(&client->dev, client->irq, vl53l0x_handle_irq, - irq_flags, indio_dev->name, indio_dev); + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, vl53l0x_threaded_irq, + irq_flags | IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret) { dev_err(&client->dev, "devm_request_irq error: %d\n", ret); return ret; @@ -84,26 +143,6 @@ static int vl53l0x_configure_irq(struct i2c_client *client, return ret; } -static void vl53l0x_clear_irq(struct vl53l0x_data *data) -{ - struct device *dev = &data->client->dev; - int ret; - - ret = i2c_smbus_write_byte_data(data->client, - VL_REG_SYSTEM_INTERRUPT_CLEAR, 1); - if (ret < 0) - dev_err(dev, "failed to clear error irq: %d\n", ret); - - ret = i2c_smbus_write_byte_data(data->client, - VL_REG_SYSTEM_INTERRUPT_CLEAR, 0); - if (ret < 0) - dev_err(dev, "failed to clear range irq: %d\n", ret); - - ret = i2c_smbus_read_byte_data(data->client, VL_REG_RESULT_INT_STATUS); - if (ret < 0 || ret & 0x07) - dev_err(dev, "failed to clear irq: %d\n", ret); -} - static int vl53l0x_read_proximity(struct vl53l0x_data *data, const struct iio_chan_spec *chan, int *val) @@ -125,7 +164,9 @@ static int vl53l0x_read_proximity(struct vl53l0x_data *data, if (time_left == 0) return -ETIMEDOUT; - vl53l0x_clear_irq(data); + ret = vl53l0x_clear_irq(data); + if (ret < 0) + return ret; } else { do { ret = i2c_smbus_read_byte_data(client, @@ -150,7 +191,7 @@ static int vl53l0x_read_proximity(struct vl53l0x_data *data, return -EREMOTEIO; /* Values should be between 30~1200 in millimeters. */ - *val = (buffer[10] << 8) + buffer[11]; + *val = get_unaligned_be16(&buffer[10]); return 0; } @@ -160,7 +201,14 @@ static const struct iio_chan_spec vl53l0x_channels[] = { .type = IIO_DISTANCE, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, }, + IIO_CHAN_SOFT_TIMESTAMP(1), }; static int vl53l0x_read_raw(struct iio_dev *indio_dev, @@ -190,8 +238,16 @@ static int vl53l0x_read_raw(struct iio_dev *indio_dev, } } +static int vl53l0x_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig) +{ + struct vl53l0x_data *data = iio_priv(indio_dev); + + return data->trig == trig ? 0 : -EINVAL; +} + static const struct iio_info vl53l0x_info = { .read_raw = vl53l0x_read_raw, + .validate_trigger = vl53l0x_validate_trigger, }; static void vl53l0x_power_off(void *_data) @@ -218,11 +274,46 @@ static int vl53l0x_power_on(struct vl53l0x_data *data) return 0; } +static int vl53l0x_buffer_postenable(struct iio_dev *indio_dev) +{ + struct vl53l0x_data *data = iio_priv(indio_dev); + + return i2c_smbus_write_byte_data(data->client, VL_REG_SYSRANGE_START, + VL53L0X_CONTINUOUS_MODE); +} + +static int vl53l0x_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct vl53l0x_data *data = iio_priv(indio_dev); + int ret; + + ret = i2c_smbus_write_byte_data(data->client, VL_REG_SYSRANGE_START, + VL53L0X_SINGLE_MODE); + if (ret < 0) + return ret; + + /* Let the ongoing reading finish */ + reinit_completion(&data->completion); + wait_for_completion_timeout(&data->completion, HZ / 10); + + return vl53l0x_clear_irq(data); +} + +static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { + .postenable = &vl53l0x_buffer_postenable, + .postdisable = &vl53l0x_buffer_postdisable, +}; + +static const struct iio_trigger_ops vl53l0x_trigger_ops = { + .validate_device = iio_trigger_validate_own_device, +}; + static int vl53l0x_probe(struct i2c_client *client) { struct vl53l0x_data *data; struct iio_dev *indio_dev; int error; + int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -237,6 +328,13 @@ static int vl53l0x_probe(struct i2c_client *client) I2C_FUNC_SMBUS_BYTE_DATA)) return -EOPNOTSUPP; + ret = i2c_smbus_read_byte_data(data->client, VL_REG_IDENTIFICATION_MODEL_ID); + if (ret < 0) + return -EINVAL; + + if (ret != VL53L0X_MODEL_ID_VAL) + dev_info(&client->dev, "Unknown model id: 0x%x", ret); + data->vdd_supply = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_supply)) return dev_err_probe(&client->dev, PTR_ERR(data->vdd_supply), @@ -265,13 +363,33 @@ static int vl53l0x_probe(struct i2c_client *client) /* usage of interrupt is optional */ if (client->irq) { - int ret; - init_completion(&data->completion); + data->trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!data->trig) + return -ENOMEM; + + data->trig->ops = &vl53l0x_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + ret = devm_iio_trigger_register(&client->dev, data->trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(data->trig); + ret = vl53l0x_configure_irq(client, indio_dev); if (ret) return ret; + + ret = devm_iio_triggered_buffer_setup(&client->dev, + indio_dev, + NULL, + &vl53l0x_trigger_handler, + &iio_triggered_buffer_setup_ops); + if (ret) + return ret; } return devm_iio_device_register(&client->dev, indio_dev); diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index ed0e4963362f96..1244d8e17d504a 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -91,6 +91,8 @@ config MLX90635 config TMP006 tristate "TMP006 infrared thermopile sensor" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help If you say yes here you get support for the Texas Instruments TMP006 infrared thermopile sensor. diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index 0143fd478933cc..692520e1c497bb 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -18,7 +18,7 @@ struct temperature_state { struct hid_sensor_hub_attribute_info temperature_attr; struct { s32 temperature_data; - u64 timestamp __aligned(8); + aligned_s64 timestamp; } scan; int scale_pre_decml; int scale_post_decml; @@ -283,11 +283,11 @@ static struct platform_driver hid_temperature_platform_driver = { .pm = &hid_sensor_pm_ops, }, .probe = hid_temperature_probe, - .remove_new = hid_temperature_remove, + .remove = hid_temperature_remove, }; module_platform_driver(hid_temperature_platform_driver); MODULE_DESCRIPTION("HID Environmental temperature sensor"); MODULE_AUTHOR("Song Hongyan "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index f1bb0976273d37..c2447860adfd6f 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -200,7 +200,7 @@ static int mcp9600_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) + bool state) { struct mcp9600_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index 6d8d661f0c82aa..0c844137d7aa90 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -7,8 +7,6 @@ * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor * * (7-bit I2C slave address 0x40, changeable via ADR pins) - * - * TODO: data ready irq */ #include @@ -21,6 +19,9 @@ #include #include +#include +#include +#include #define TMP006_VOBJECT 0x00 #define TMP006_TAMBIENT 0x01 @@ -45,6 +46,7 @@ struct tmp006_data { struct i2c_client *client; u16 config; + struct iio_trigger *drdy_trig; }; static int tmp006_read_measurement(struct tmp006_data *data, u8 reg) @@ -83,15 +85,19 @@ static int tmp006_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: if (channel->type == IIO_VOLTAGE) { /* LSB is 156.25 nV */ - ret = tmp006_read_measurement(data, TMP006_VOBJECT); - if (ret < 0) - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + ret = tmp006_read_measurement(data, TMP006_VOBJECT); + if (ret < 0) + return ret; + } *val = sign_extend32(ret, 15); } else if (channel->type == IIO_TEMP) { /* LSB is 0.03125 degrees Celsius */ - ret = tmp006_read_measurement(data, TMP006_TAMBIENT); - if (ret < 0) - return ret; + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { + ret = tmp006_read_measurement(data, TMP006_TAMBIENT); + if (ret < 0) + return ret; + } *val = sign_extend32(ret, 15) >> TMP006_TAMBIENT_SHIFT; } else { break; @@ -128,7 +134,7 @@ static int tmp006_write_raw(struct iio_dev *indio_dev, long mask) { struct tmp006_data *data = iio_priv(indio_dev); - int i; + int ret, i; if (mask != IIO_CHAN_INFO_SAMP_FREQ) return -EINVAL; @@ -136,13 +142,19 @@ static int tmp006_write_raw(struct iio_dev *indio_dev, for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++) if ((val == tmp006_freqs[i][0]) && (val2 == tmp006_freqs[i][1])) { + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + data->config &= ~TMP006_CONFIG_CR_MASK; data->config |= i << TMP006_CONFIG_CR_SHIFT; - return i2c_smbus_write_word_swapped(data->client, - TMP006_CONFIG, - data->config); + ret = i2c_smbus_write_word_swapped(data->client, + TMP006_CONFIG, + data->config); + iio_device_release_direct_mode(indio_dev); + return ret; } return -EINVAL; } @@ -164,13 +176,29 @@ static const struct iio_chan_spec tmp006_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + } }, { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), - } + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 14, + .storagebits = 16, + .shift = TMP006_TAMBIENT_SHIFT, + .endianness = IIO_BE, + } + }, + IIO_CHAN_SOFT_TIMESTAMP(2), }; static const struct iio_info tmp006_info = { @@ -213,6 +241,54 @@ static void tmp006_powerdown_cleanup(void *dev) tmp006_power(dev, false); } +static irqreturn_t tmp006_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct tmp006_data *data = iio_priv(indio_dev); + struct { + s16 channels[2]; + s64 ts __aligned(8); + } scan; + s32 ret; + + ret = i2c_smbus_read_word_data(data->client, TMP006_VOBJECT); + if (ret < 0) + goto err; + scan.channels[0] = ret; + + ret = i2c_smbus_read_word_data(data->client, TMP006_TAMBIENT); + if (ret < 0) + goto err; + scan.channels[1] = ret; + + iio_push_to_buffers_with_timestamp(indio_dev, &scan, + iio_get_time_ns(indio_dev)); +err: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int tmp006_set_trigger_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct tmp006_data *data = iio_priv(indio_dev); + + if (state) + data->config |= TMP006_CONFIG_DRDY_EN; + else + data->config &= ~TMP006_CONFIG_DRDY_EN; + + return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, + data->config); +} + +static const struct iio_trigger_ops tmp006_trigger_ops = { + .set_trigger_state = tmp006_set_trigger_state, +}; + +static const unsigned long tmp006_scan_masks[] = { 0x3, 0 }; + static int tmp006_probe(struct i2c_client *client) { struct iio_dev *indio_dev; @@ -241,6 +317,7 @@ static int tmp006_probe(struct i2c_client *client) indio_dev->channels = tmp006_channels; indio_dev->num_channels = ARRAY_SIZE(tmp006_channels); + indio_dev->available_scan_masks = tmp006_scan_masks; ret = i2c_smbus_read_word_swapped(data->client, TMP006_CONFIG); if (ret < 0) @@ -258,6 +335,37 @@ static int tmp006_probe(struct i2c_client *client) if (ret < 0) return ret; + if (client->irq > 0) { + data->drdy_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + iio_device_id(indio_dev)); + if (!data->drdy_trig) + return -ENOMEM; + + data->drdy_trig->ops = &tmp006_trigger_ops; + iio_trigger_set_drvdata(data->drdy_trig, indio_dev); + ret = iio_trigger_register(data->drdy_trig); + if (ret) + return ret; + + indio_dev->trig = iio_trigger_get(data->drdy_trig); + + ret = devm_request_threaded_irq(&client->dev, client->irq, + iio_trigger_generic_data_rdy_poll, + NULL, + IRQF_ONESHOT, + "tmp006_irq", + data->drdy_trig); + if (ret < 0) + return ret; + } + + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, + tmp006_trigger_handler, NULL); + if (ret < 0) + return ret; + return devm_iio_device_register(&client->dev, indio_dev); } diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index 9bdfa94234929c..fd4d389ce1dfec 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -216,7 +216,7 @@ static irqreturn_t tmp007_interrupt_handler(int irq, void *private) static int tmp007_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) + enum iio_event_direction dir, bool state) { struct tmp007_data *data = iio_priv(indio_dev); unsigned int status_mask; diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c index 9213761c5d18a4..cfaa16f46a3fde 100644 --- a/drivers/iio/temperature/tsys01.c +++ b/drivers/iio/temperature/tsys01.c @@ -232,4 +232,4 @@ MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver"); MODULE_AUTHOR("William Markezana "); MODULE_AUTHOR("Ludovic Tancerel "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); +MODULE_IMPORT_NS("IIO_MEAS_SPEC_SENSORS"); diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c index 2b4959d6e46761..ef34b3c58f262b 100644 --- a/drivers/iio/temperature/tsys02d.c +++ b/drivers/iio/temperature/tsys02d.c @@ -187,4 +187,4 @@ MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver"); MODULE_AUTHOR("William Markezana "); MODULE_AUTHOR("Ludovic Tancerel "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); +MODULE_IMPORT_NS("IIO_MEAS_SPEC_SENSORS"); diff --git a/drivers/iio/test/iio-test-gts.c b/drivers/iio/test/iio-test-gts.c index 5f16a7b5e6d411..1eceec9d477f4c 100644 --- a/drivers/iio/test/iio-test-gts.c +++ b/drivers/iio/test/iio-test-gts.c @@ -512,4 +512,4 @@ kunit_test_suite(iio_gts_test_suite); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Matti Vaittinen "); MODULE_DESCRIPTION("Test IIO light sensor gain-time-scale helpers"); -MODULE_IMPORT_NS(IIO_GTS_HELPER); +MODULE_IMPORT_NS("IIO_GTS_HELPER"); diff --git a/drivers/iio/test/iio-test-rescale.c b/drivers/iio/test/iio-test-rescale.c index 31ee55a6faed92..cbf13337ed1ff4 100644 --- a/drivers/iio/test/iio-test-rescale.c +++ b/drivers/iio/test/iio-test-rescale.c @@ -712,4 +712,4 @@ kunit_test_suite(iio_rescale_test_suite); MODULE_AUTHOR("Liam Beguin "); MODULE_DESCRIPTION("Test IIO rescale conversion functions"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(IIO_RESCALE); +MODULE_IMPORT_NS("IIO_RESCALE"); diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index dec256bfbd73e1..21c6b6292a721a 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -96,7 +96,7 @@ static void iio_interrupt_trigger_remove(struct platform_device *pdev) static struct platform_driver iio_interrupt_trigger_driver = { .probe = iio_interrupt_trigger_probe, - .remove_new = iio_interrupt_trigger_remove, + .remove = iio_interrupt_trigger_remove, .driver = { .name = "iio_interrupt_trigger", }, diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 0684329956d956..bb60b2d7b2eca5 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -900,7 +900,7 @@ MODULE_DEVICE_TABLE(of, stm32_trig_of_match); static struct platform_driver stm32_timer_trigger_driver = { .probe = stm32_timer_trigger_probe, - .remove_new = stm32_timer_trigger_remove, + .remove = stm32_timer_trigger_remove, .driver = { .name = "stm32-timer-trigger", .of_match_table = stm32_trig_of_match, diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 07fb8d3c037f00..142170473e7536 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -35,6 +35,8 @@ MODULE_DESCRIPTION("InfiniBand CM"); MODULE_LICENSE("Dual BSD/GPL"); #define CM_DESTROY_ID_WAIT_TIMEOUT 10000 /* msecs */ +#define CM_DIRECT_RETRY_CTX ((void *) 1UL) + static const char * const ibcm_rej_reason_strs[] = { [IB_CM_REJ_NO_QP] = "no QP", [IB_CM_REJ_NO_EEC] = "no EEC", @@ -93,8 +95,7 @@ static void cm_process_work(struct cm_id_private *cm_id_priv, struct cm_work *work); static int cm_send_sidr_rep_locked(struct cm_id_private *cm_id_priv, struct ib_cm_sidr_rep_param *param); -static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv, - const void *private_data, u8 private_data_len); +static void cm_issue_dreq(struct cm_id_private *cm_id_priv); static int cm_send_drep_locked(struct cm_id_private *cm_id_priv, void *private_data, u8 private_data_len); static int cm_send_rej_locked(struct cm_id_private *cm_id_priv, @@ -307,12 +308,7 @@ static struct ib_mad_send_buf *cm_alloc_msg(struct cm_id_private *cm_id_priv) goto out; } - /* Timeout set by caller if response is expected. */ m->ah = ah; - m->retries = cm_id_priv->max_cm_retries; - - refcount_inc(&cm_id_priv->refcount); - m->context[0] = cm_id_priv; out: spin_unlock(&cm_id_priv->av.port->cm_dev->mad_agent_lock); @@ -321,16 +317,13 @@ static struct ib_mad_send_buf *cm_alloc_msg(struct cm_id_private *cm_id_priv) static void cm_free_msg(struct ib_mad_send_buf *msg) { - struct cm_id_private *cm_id_priv = msg->context[0]; - if (msg->ah) rdma_destroy_ah(msg->ah, 0); - cm_deref_id(cm_id_priv); ib_free_send_mad(msg); } static struct ib_mad_send_buf * -cm_alloc_priv_msg(struct cm_id_private *cm_id_priv) +cm_alloc_priv_msg(struct cm_id_private *cm_id_priv, enum ib_cm_state state) { struct ib_mad_send_buf *msg; @@ -339,7 +332,15 @@ cm_alloc_priv_msg(struct cm_id_private *cm_id_priv) msg = cm_alloc_msg(cm_id_priv); if (IS_ERR(msg)) return msg; + cm_id_priv->msg = msg; + refcount_inc(&cm_id_priv->refcount); + msg->context[0] = cm_id_priv; + msg->context[1] = (void *) (unsigned long) state; + + msg->retries = cm_id_priv->max_cm_retries; + msg->timeout_ms = cm_id_priv->timeout_ms; + return msg; } @@ -358,13 +359,20 @@ static void cm_free_priv_msg(struct ib_mad_send_buf *msg) ib_free_send_mad(msg); } -static struct ib_mad_send_buf *cm_alloc_response_msg_no_ah(struct cm_port *port, - struct ib_mad_recv_wc *mad_recv_wc) +static struct ib_mad_send_buf * +cm_alloc_response_msg_no_ah(struct cm_port *port, + struct ib_mad_recv_wc *mad_recv_wc, + bool direct_retry) { - return ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, - 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, - GFP_ATOMIC, - IB_MGMT_BASE_VERSION); + struct ib_mad_send_buf *m; + + m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, + 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, + GFP_ATOMIC, IB_MGMT_BASE_VERSION); + if (!IS_ERR(m)) + m->context[0] = direct_retry ? CM_DIRECT_RETRY_CTX : NULL; + + return m; } static int cm_create_response_msg_ah(struct cm_port *port, @@ -384,12 +392,13 @@ static int cm_create_response_msg_ah(struct cm_port *port, static int cm_alloc_response_msg(struct cm_port *port, struct ib_mad_recv_wc *mad_recv_wc, + bool direct_retry, struct ib_mad_send_buf **msg) { struct ib_mad_send_buf *m; int ret; - m = cm_alloc_response_msg_no_ah(port, mad_recv_wc); + m = cm_alloc_response_msg_no_ah(port, mad_recv_wc, direct_retry); if (IS_ERR(m)) return PTR_ERR(m); @@ -403,13 +412,6 @@ static int cm_alloc_response_msg(struct cm_port *port, return 0; } -static void cm_free_response_msg(struct ib_mad_send_buf *msg) -{ - if (msg->ah) - rdma_destroy_ah(msg->ah, 0); - ib_free_send_mad(msg); -} - static void *cm_copy_private_data(const void *private_data, u8 private_data_len) { void *data; @@ -1109,7 +1111,8 @@ static void cm_destroy_id(struct ib_cm_id *cm_id, int err) cm_id->state = IB_CM_IDLE; break; } - cm_send_dreq_locked(cm_id_priv, NULL, 0); + cm_issue_dreq(cm_id_priv); + cm_enter_timewait(cm_id_priv); goto retest; case IB_CM_DREQ_SENT: ib_cancel_mad(cm_id_priv->msg); @@ -1557,7 +1560,7 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, if (param->alternate_path) cm_move_av_from_path(&cm_id_priv->alt_av, &alt_av); - msg = cm_alloc_priv_msg(cm_id_priv); + msg = cm_alloc_priv_msg(cm_id_priv, IB_CM_REQ_SENT); if (IS_ERR(msg)) { ret = PTR_ERR(msg); goto out_unlock; @@ -1566,8 +1569,6 @@ int ib_send_cm_req(struct ib_cm_id *cm_id, req_msg = (struct cm_req_msg *)msg->mad; cm_format_req(req_msg, cm_id_priv, param); cm_id_priv->tid = req_msg->hdr.tid; - msg->timeout_ms = cm_id_priv->timeout_ms; - msg->context[1] = (void *)(unsigned long)IB_CM_REQ_SENT; cm_id_priv->local_qpn = cpu_to_be32(IBA_GET(CM_REQ_LOCAL_QPN, req_msg)); cm_id_priv->rq_psn = cpu_to_be32(IBA_GET(CM_REQ_STARTING_PSN, req_msg)); @@ -1598,7 +1599,7 @@ static int cm_issue_rej(struct cm_port *port, struct cm_rej_msg *rej_msg, *rcv_msg; int ret; - ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); + ret = cm_alloc_response_msg(port, mad_recv_wc, false, &msg); if (ret) return ret; @@ -1624,7 +1625,7 @@ static int cm_issue_rej(struct cm_port *port, IBA_GET(CM_REJ_REMOTE_COMM_ID, rcv_msg)); ret = ib_post_send_mad(msg, NULL); if (ret) - cm_free_response_msg(msg); + cm_free_msg(msg); return ret; } @@ -1951,7 +1952,7 @@ static void cm_dup_req_handler(struct cm_work *work, } spin_unlock_irq(&cm_id_priv->lock); - ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); + ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, true, &msg); if (ret) return; @@ -1980,7 +1981,7 @@ static void cm_dup_req_handler(struct cm_work *work, return; unlock: spin_unlock_irq(&cm_id_priv->lock); -free: cm_free_response_msg(msg); +free: cm_free_msg(msg); } static struct cm_id_private *cm_match_req(struct cm_work *work, @@ -2294,7 +2295,7 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id, goto out; } - msg = cm_alloc_priv_msg(cm_id_priv); + msg = cm_alloc_priv_msg(cm_id_priv, IB_CM_REP_SENT); if (IS_ERR(msg)) { ret = PTR_ERR(msg); goto out; @@ -2302,8 +2303,6 @@ int ib_send_cm_rep(struct ib_cm_id *cm_id, rep_msg = (struct cm_rep_msg *) msg->mad; cm_format_rep(rep_msg, cm_id_priv, param); - msg->timeout_ms = cm_id_priv->timeout_ms; - msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT; trace_icm_send_rep(cm_id); ret = ib_post_send_mad(msg, NULL); @@ -2444,7 +2443,7 @@ static void cm_dup_rep_handler(struct cm_work *work) atomic_long_inc( &work->port->counters[CM_RECV_DUPLICATES][CM_REP_COUNTER]); - ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); + ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, true, &msg); if (ret) goto deref; @@ -2469,7 +2468,7 @@ static void cm_dup_rep_handler(struct cm_work *work) goto deref; unlock: spin_unlock_irq(&cm_id_priv->lock); -free: cm_free_response_msg(msg); +free: cm_free_msg(msg); deref: cm_deref_id(cm_id_priv); } @@ -2653,59 +2652,68 @@ static void cm_format_dreq(struct cm_dreq_msg *dreq_msg, private_data_len); } -static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv, - const void *private_data, u8 private_data_len) +static void cm_issue_dreq(struct cm_id_private *cm_id_priv) { struct ib_mad_send_buf *msg; int ret; lockdep_assert_held(&cm_id_priv->lock); + msg = cm_alloc_msg(cm_id_priv); + if (IS_ERR(msg)) + return; + + cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv, NULL, 0); + + trace_icm_send_dreq(&cm_id_priv->id); + ret = ib_post_send_mad(msg, NULL); + if (ret) + cm_free_msg(msg); +} + +int ib_send_cm_dreq(struct ib_cm_id *cm_id, const void *private_data, + u8 private_data_len) +{ + struct cm_id_private *cm_id_priv = + container_of(cm_id, struct cm_id_private, id); + struct ib_mad_send_buf *msg; + unsigned long flags; + int ret; + if (private_data && private_data_len > IB_CM_DREQ_PRIVATE_DATA_SIZE) return -EINVAL; + spin_lock_irqsave(&cm_id_priv->lock, flags); if (cm_id_priv->id.state != IB_CM_ESTABLISHED) { trace_icm_dreq_skipped(&cm_id_priv->id); - return -EINVAL; + ret = -EINVAL; + goto unlock; } if (cm_id_priv->id.lap_state == IB_CM_LAP_SENT || cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) ib_cancel_mad(cm_id_priv->msg); - msg = cm_alloc_priv_msg(cm_id_priv); + msg = cm_alloc_priv_msg(cm_id_priv, IB_CM_DREQ_SENT); if (IS_ERR(msg)) { cm_enter_timewait(cm_id_priv); - return PTR_ERR(msg); + ret = PTR_ERR(msg); + goto unlock; } cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv, private_data, private_data_len); - msg->timeout_ms = cm_id_priv->timeout_ms; - msg->context[1] = (void *) (unsigned long) IB_CM_DREQ_SENT; trace_icm_send_dreq(&cm_id_priv->id); ret = ib_post_send_mad(msg, NULL); if (ret) { cm_enter_timewait(cm_id_priv); cm_free_priv_msg(msg); - return ret; + goto unlock; } cm_id_priv->id.state = IB_CM_DREQ_SENT; - return 0; -} - -int ib_send_cm_dreq(struct ib_cm_id *cm_id, const void *private_data, - u8 private_data_len) -{ - struct cm_id_private *cm_id_priv = - container_of(cm_id, struct cm_id_private, id); - unsigned long flags; - int ret; - - spin_lock_irqsave(&cm_id_priv->lock, flags); - ret = cm_send_dreq_locked(cm_id_priv, private_data, private_data_len); +unlock: spin_unlock_irqrestore(&cm_id_priv->lock, flags); return ret; } @@ -2791,7 +2799,7 @@ static int cm_issue_drep(struct cm_port *port, struct cm_drep_msg *drep_msg; int ret; - ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); + ret = cm_alloc_response_msg(port, mad_recv_wc, true, &msg); if (ret) return ret; @@ -2809,7 +2817,7 @@ static int cm_issue_drep(struct cm_port *port, IBA_GET(CM_DREQ_REMOTE_COMM_ID, dreq_msg)); ret = ib_post_send_mad(msg, NULL); if (ret) - cm_free_response_msg(msg); + cm_free_msg(msg); return ret; } @@ -2856,7 +2864,8 @@ static int cm_dreq_handler(struct cm_work *work) case IB_CM_TIMEWAIT: atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] [CM_DREQ_COUNTER]); - msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc); + msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc, + true); if (IS_ERR(msg)) goto unlock; @@ -2867,7 +2876,7 @@ static int cm_dreq_handler(struct cm_work *work) if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) || ib_post_send_mad(msg, NULL)) - cm_free_response_msg(msg); + cm_free_msg(msg); goto deref; case IB_CM_DREQ_RCVD: atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] @@ -3361,7 +3370,8 @@ static int cm_lap_handler(struct cm_work *work) case IB_CM_MRA_LAP_SENT: atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] [CM_LAP_COUNTER]); - msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc); + msg = cm_alloc_response_msg_no_ah(work->port, work->mad_recv_wc, + true); if (IS_ERR(msg)) goto unlock; @@ -3374,7 +3384,7 @@ static int cm_lap_handler(struct cm_work *work) if (cm_create_response_msg_ah(work->port, work->mad_recv_wc, msg) || ib_post_send_mad(msg, NULL)) - cm_free_response_msg(msg); + cm_free_msg(msg); goto deref; case IB_CM_LAP_RCVD: atomic_long_inc(&work->port->counters[CM_RECV_DUPLICATES] @@ -3513,7 +3523,7 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id, goto out_unlock; } - msg = cm_alloc_priv_msg(cm_id_priv); + msg = cm_alloc_priv_msg(cm_id_priv, IB_CM_SIDR_REQ_SENT); if (IS_ERR(msg)) { ret = PTR_ERR(msg); goto out_unlock; @@ -3521,8 +3531,6 @@ int ib_send_cm_sidr_req(struct ib_cm_id *cm_id, cm_format_sidr_req((struct cm_sidr_req_msg *)msg->mad, cm_id_priv, param); - msg->timeout_ms = cm_id_priv->timeout_ms; - msg->context[1] = (void *)(unsigned long)IB_CM_SIDR_REQ_SENT; trace_icm_send_sidr_req(&cm_id_priv->id); ret = ib_post_send_mad(msg, NULL); @@ -3768,17 +3776,17 @@ static int cm_sidr_rep_handler(struct cm_work *work) static void cm_process_send_error(struct cm_id_private *cm_id_priv, struct ib_mad_send_buf *msg, - enum ib_cm_state state, enum ib_wc_status wc_status) { + enum ib_cm_state state = (unsigned long) msg->context[1]; struct ib_cm_event cm_event = {}; int ret; - /* Discard old sends or ones without a response. */ + /* Discard old sends. */ spin_lock_irq(&cm_id_priv->lock); if (msg != cm_id_priv->msg) { spin_unlock_irq(&cm_id_priv->lock); - cm_free_msg(msg); + cm_free_priv_msg(msg); return; } cm_free_priv_msg(msg); @@ -3826,9 +3834,7 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_wc *mad_send_wc) { struct ib_mad_send_buf *msg = mad_send_wc->send_buf; - struct cm_id_private *cm_id_priv = msg->context[0]; - enum ib_cm_state state = - (enum ib_cm_state)(unsigned long)msg->context[1]; + struct cm_id_private *cm_id_priv; struct cm_port *port; u16 attr_index; @@ -3836,13 +3842,12 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent, attr_index = be16_to_cpu(((struct ib_mad_hdr *) msg->mad)->attr_id) - CM_ATTR_ID_OFFSET; - /* - * If the send was in response to a received message (context[0] is not - * set to a cm_id), and is not a REJ, then it is a send that was - * manually retried. - */ - if (!cm_id_priv && (attr_index != CM_REJ_COUNTER)) + if (msg->context[0] == CM_DIRECT_RETRY_CTX) { msg->retries = 1; + cm_id_priv = NULL; + } else { + cm_id_priv = msg->context[0]; + } atomic_long_add(1 + msg->retries, &port->counters[CM_XMIT][attr_index]); if (msg->retries) @@ -3850,10 +3855,9 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent, &port->counters[CM_XMIT_RETRIES][attr_index]); if (cm_id_priv) - cm_process_send_error(cm_id_priv, msg, state, - mad_send_wc->status); + cm_process_send_error(cm_id_priv, msg, mad_send_wc->status); else - cm_free_response_msg(msg); + cm_free_msg(msg); } static void cm_work_handler(struct work_struct *_work) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index e029401b56805f..ca9b956c034d37 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -437,6 +437,7 @@ int ib_device_rename(struct ib_device *ibdev, const char *name) client->rename(ibdev, client_data); } up_read(&ibdev->client_data_rwsem); + rdma_nl_notify_event(ibdev, 0, RDMA_RENAME_EVENT); up_read(&devices_rwsem); return 0; } @@ -2759,6 +2760,7 @@ void ib_set_device_ops(struct ib_device *dev, const struct ib_device_ops *ops) SET_DEVICE_OP(dev_ops, resize_cq); SET_DEVICE_OP(dev_ops, set_vf_guid); SET_DEVICE_OP(dev_ops, set_vf_link_state); + SET_DEVICE_OP(dev_ops, ufile_hw_cleanup); SET_OBJ_SIZE(dev_ops, ib_ah); SET_OBJ_SIZE(dev_ops, ib_counters); @@ -2852,6 +2854,40 @@ static const struct rdma_nl_cbs ibnl_ls_cb_table[RDMA_NL_LS_NUM_OPS] = { }, }; +static int ib_netdevice_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + struct net_device *ib_ndev; + struct ib_device *ibdev; + u32 port; + + switch (event) { + case NETDEV_CHANGENAME: + ibdev = ib_device_get_by_netdev(ndev, RDMA_DRIVER_UNKNOWN); + if (!ibdev) + return NOTIFY_DONE; + + rdma_for_each_port(ibdev, port) { + ib_ndev = ib_device_get_netdev(ibdev, port); + if (ndev == ib_ndev) + rdma_nl_notify_event(ibdev, port, + RDMA_NETDEV_RENAME_EVENT); + dev_put(ib_ndev); + } + ib_device_put(ibdev); + break; + default: + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block nb_netdevice = { + .notifier_call = ib_netdevice_event, +}; + static int __init ib_core_init(void) { int ret = -ENOMEM; @@ -2923,6 +2959,8 @@ static int __init ib_core_init(void) goto err_parent; } + register_netdevice_notifier(&nb_netdevice); + return 0; err_parent: @@ -2952,6 +2990,7 @@ static int __init ib_core_init(void) static void __exit ib_core_cleanup(void) { + unregister_netdevice_notifier(&nb_netdevice); roce_gid_mgmt_cleanup(); rdma_nl_unregister(RDMA_NL_LS); nldev_exit(); diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c index 7dc8e2ec62cc8b..ff121e59b9c0e2 100644 --- a/drivers/infiniband/core/nldev.c +++ b/drivers/infiniband/core/nldev.c @@ -2729,6 +2729,25 @@ static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = { }, }; +static int fill_mon_netdev_rename(struct sk_buff *msg, + struct ib_device *device, u32 port, + const struct net *net) +{ + struct net_device *netdev = ib_device_get_netdev(device, port); + int ret = 0; + + if (!netdev || !net_eq(dev_net(netdev), net)) + goto out; + + ret = nla_put_u32(msg, RDMA_NLDEV_ATTR_NDEV_INDEX, netdev->ifindex); + if (ret) + goto out; + ret = nla_put_string(msg, RDMA_NLDEV_ATTR_NDEV_NAME, netdev->name); +out: + dev_put(netdev); + return ret; +} + static int fill_mon_netdev_association(struct sk_buff *msg, struct ib_device *device, u32 port, const struct net *net) @@ -2793,6 +2812,18 @@ static void rdma_nl_notify_err_msg(struct ib_device *device, u32 port_num, "Failed to send RDMA monitor netdev detach event: port %d\n", port_num); break; + case RDMA_RENAME_EVENT: + dev_warn_ratelimited(&device->dev, + "Failed to send RDMA monitor rename device event\n"); + break; + + case RDMA_NETDEV_RENAME_EVENT: + netdev = ib_device_get_netdev(device, port_num); + dev_warn_ratelimited(&device->dev, + "Failed to send RDMA monitor netdev rename event: port %d netdev %d\n", + port_num, netdev->ifindex); + dev_put(netdev); + break; default: break; } @@ -2822,14 +2853,19 @@ int rdma_nl_notify_event(struct ib_device *device, u32 port_num, switch (type) { case RDMA_REGISTER_EVENT: case RDMA_UNREGISTER_EVENT: + case RDMA_RENAME_EVENT: ret = fill_nldev_handle(skb, device); if (ret) goto err_free; break; case RDMA_NETDEV_ATTACH_EVENT: case RDMA_NETDEV_DETACH_EVENT: - ret = fill_mon_netdev_association(skb, device, - port_num, net); + ret = fill_mon_netdev_association(skb, device, port_num, net); + if (ret) + goto err_free; + break; + case RDMA_NETDEV_RENAME_EVENT: + ret = fill_mon_netdev_rename(skb, device, port_num, net); if (ret) goto err_free; break; diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index 29b1ab1d5f9338..90c177edf9b0d7 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -58,8 +58,8 @@ void uverbs_uobject_put(struct ib_uobject *uobject) } EXPORT_SYMBOL(uverbs_uobject_put); -static int uverbs_try_lock_object(struct ib_uobject *uobj, - enum rdma_lookup_mode mode) +int uverbs_try_lock_object(struct ib_uobject *uobj, + enum rdma_lookup_mode mode) { /* * When a shared access is required, we use a positive counter. Each @@ -84,6 +84,7 @@ static int uverbs_try_lock_object(struct ib_uobject *uobj, } return 0; } +EXPORT_SYMBOL(uverbs_try_lock_object); static void assert_uverbs_usecnt(struct ib_uobject *uobj, enum rdma_lookup_mode mode) @@ -880,9 +881,14 @@ static void ufile_destroy_ucontext(struct ib_uverbs_file *ufile, static int __uverbs_cleanup_ufile(struct ib_uverbs_file *ufile, enum rdma_remove_reason reason) { + struct uverbs_attr_bundle attrs = { .ufile = ufile }; + struct ib_ucontext *ucontext = ufile->ucontext; + struct ib_device *ib_dev = ucontext->device; struct ib_uobject *obj, *next_obj; int ret = -EINVAL; - struct uverbs_attr_bundle attrs = { .ufile = ufile }; + + if (ib_dev->ops.ufile_hw_cleanup) + ib_dev->ops.ufile_hw_cleanup(ufile); /* * This shouldn't run while executing other commands on this diff --git a/drivers/infiniband/core/roce_gid_mgmt.c b/drivers/infiniband/core/roce_gid_mgmt.c index d5131b3ba8ab04..a9f2c6b1b29ed2 100644 --- a/drivers/infiniband/core/roce_gid_mgmt.c +++ b/drivers/infiniband/core/roce_gid_mgmt.c @@ -515,6 +515,27 @@ void rdma_roce_rescan_device(struct ib_device *ib_dev) } EXPORT_SYMBOL(rdma_roce_rescan_device); +/** + * rdma_roce_rescan_port - Rescan all of the network devices in the system + * and add their gids if relevant to the port of the RoCE device. + * + * @ib_dev: IB device + * @port: Port number + */ +void rdma_roce_rescan_port(struct ib_device *ib_dev, u32 port) +{ + struct net_device *ndev = NULL; + + if (rdma_protocol_roce(ib_dev, port)) { + ndev = ib_device_get_netdev(ib_dev, port); + if (!ndev) + return; + enum_all_gids_of_dev_cb(ib_dev, port, ndev, ndev); + dev_put(ndev); + } +} +EXPORT_SYMBOL(rdma_roce_rescan_port); + static void callback_for_addr_gid_device_scan(struct ib_device *device, u32 port, struct net_device *rdma_ndev, @@ -575,16 +596,17 @@ static void handle_netdev_upper(struct ib_device *ib_dev, u32 port, } } -static void _roce_del_all_netdev_gids(struct ib_device *ib_dev, u32 port, - struct net_device *event_ndev) +void roce_del_all_netdev_gids(struct ib_device *ib_dev, + u32 port, struct net_device *ndev) { - ib_cache_gid_del_all_netdev_gids(ib_dev, port, event_ndev); + ib_cache_gid_del_all_netdev_gids(ib_dev, port, ndev); } +EXPORT_SYMBOL(roce_del_all_netdev_gids); static void del_netdev_upper_ips(struct ib_device *ib_dev, u32 port, struct net_device *rdma_ndev, void *cookie) { - handle_netdev_upper(ib_dev, port, cookie, _roce_del_all_netdev_gids); + handle_netdev_upper(ib_dev, port, cookie, roce_del_all_netdev_gids); } static void add_netdev_upper_ips(struct ib_device *ib_dev, u32 port, diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 5dbb248e96259c..02f1666f3cbab4 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1615,7 +1615,6 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file, struct ucma_event *uevent, *tmp; struct ucma_context *ctx; LIST_HEAD(event_list); - struct fd f; struct ucma_file *cur_file; int ret = 0; @@ -1623,21 +1622,17 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file, return -EFAULT; /* Get current fd to protect against it being closed */ - f = fdget(cmd.fd); - if (!fd_file(f)) + CLASS(fd, f)(cmd.fd); + if (fd_empty(f)) return -ENOENT; - if (fd_file(f)->f_op != &ucma_fops) { - ret = -EINVAL; - goto file_put; - } + if (fd_file(f)->f_op != &ucma_fops) + return -EINVAL; cur_file = fd_file(f)->private_data; /* Validate current fd and prevent destruction of id. */ ctx = ucma_get_ctx(cur_file, cmd.id); - if (IS_ERR(ctx)) { - ret = PTR_ERR(ctx); - goto file_put; - } + if (IS_ERR(ctx)) + return PTR_ERR(ctx); rdma_lock_handler(ctx->cm_id); /* @@ -1678,8 +1673,6 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file, err_unlock: rdma_unlock_handler(ctx->cm_id); ucma_put_ctx(ctx); -file_put: - fdput(f); return ret; } diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c index 9fcd37761264a4..0ec2e4120cc94b 100644 --- a/drivers/infiniband/core/umem_dmabuf.c +++ b/drivers/infiniband/core/umem_dmabuf.c @@ -10,7 +10,7 @@ #include "uverbs.h" -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf) { diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 821d93c8f7123c..797e2fcc8072e5 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -133,35 +133,6 @@ struct ib_uverbs_completion_event_file { struct ib_uverbs_event_queue ev_queue; }; -struct ib_uverbs_file { - struct kref ref; - struct ib_uverbs_device *device; - struct mutex ucontext_lock; - /* - * ucontext must be accessed via ib_uverbs_get_ucontext() or with - * ucontext_lock held - */ - struct ib_ucontext *ucontext; - struct ib_uverbs_async_event_file *default_async_file; - struct list_head list; - - /* - * To access the uobjects list hw_destroy_rwsem must be held for write - * OR hw_destroy_rwsem held for read AND uobjects_lock held. - * hw_destroy_rwsem should be called across any destruction of the HW - * object of an associated uobject. - */ - struct rw_semaphore hw_destroy_rwsem; - spinlock_t uobjects_lock; - struct list_head uobjects; - - struct mutex umap_lock; - struct list_head umaps; - struct page *disassociate_page; - - struct xarray idr; -}; - struct ib_uverbs_event { union { struct ib_uverbs_async_event_desc async; diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index a4cce360df2178..66b02fbf077ac5 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -584,7 +584,7 @@ static int ib_uverbs_open_xrcd(struct uverbs_attr_bundle *attrs) if (cmd.fd != -1) { /* search for file descriptor */ f = fdget(cmd.fd); - if (!fd_file(f)) { + if (fd_empty(f)) { ret = -EBADF; goto err_tree_mutex_unlock; } @@ -632,8 +632,7 @@ static int ib_uverbs_open_xrcd(struct uverbs_attr_bundle *attrs) atomic_inc(&xrcd->usecnt); } - if (fd_file(f)) - fdput(f); + fdput(f); mutex_unlock(&ibudev->xrcd_tree_mutex); uobj_finalize_uobj_create(&obj->uobject, attrs); @@ -648,8 +647,7 @@ static int ib_uverbs_open_xrcd(struct uverbs_attr_bundle *attrs) uobj_alloc_abort(&obj->uobject, attrs); err_tree_mutex_unlock: - if (fd_file(f)) - fdput(f); + fdput(f); mutex_unlock(&ibudev->xrcd_tree_mutex); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 94454186ed81d5..85cfc790a7bb36 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -76,6 +76,7 @@ static dev_t dynamic_uverbs_dev; static DEFINE_IDA(uverbs_ida); static int ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device, void *client_data); +static struct ib_client uverbs_client; static char *uverbs_devnode(const struct device *dev, umode_t *mode) { @@ -217,6 +218,7 @@ void ib_uverbs_release_file(struct kref *ref) if (file->disassociate_page) __free_pages(file->disassociate_page, 0); + mutex_destroy(&file->disassociation_lock); mutex_destroy(&file->umap_lock); mutex_destroy(&file->ucontext_lock); kfree(file); @@ -698,8 +700,13 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) ret = PTR_ERR(ucontext); goto out; } + + mutex_lock(&file->disassociation_lock); + vma->vm_ops = &rdma_umap_ops; ret = ucontext->device->ops.mmap(ucontext, vma); + + mutex_unlock(&file->disassociation_lock); out: srcu_read_unlock(&file->device->disassociate_srcu, srcu_key); return ret; @@ -721,6 +728,8 @@ static void rdma_umap_open(struct vm_area_struct *vma) /* We are racing with disassociation */ if (!down_read_trylock(&ufile->hw_destroy_rwsem)) goto out_zap; + mutex_lock(&ufile->disassociation_lock); + /* * Disassociation already completed, the VMA should already be zapped. */ @@ -732,10 +741,12 @@ static void rdma_umap_open(struct vm_area_struct *vma) goto out_unlock; rdma_umap_priv_init(priv, vma, opriv->entry); + mutex_unlock(&ufile->disassociation_lock); up_read(&ufile->hw_destroy_rwsem); return; out_unlock: + mutex_unlock(&ufile->disassociation_lock); up_read(&ufile->hw_destroy_rwsem); out_zap: /* @@ -819,7 +830,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile) { struct rdma_umap_priv *priv, *next_priv; - lockdep_assert_held(&ufile->hw_destroy_rwsem); + mutex_lock(&ufile->disassociation_lock); while (1) { struct mm_struct *mm = NULL; @@ -845,8 +856,10 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile) break; } mutex_unlock(&ufile->umap_lock); - if (!mm) + if (!mm) { + mutex_unlock(&ufile->disassociation_lock); return; + } /* * The umap_lock is nested under mmap_lock since it used within @@ -876,7 +889,31 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile) mmap_read_unlock(mm); mmput(mm); } + + mutex_unlock(&ufile->disassociation_lock); +} + +/** + * rdma_user_mmap_disassociate() - Revoke mmaps for a device + * @device: device to revoke + * + * This function should be called by drivers that need to disable mmaps for the + * device, for instance because it is going to be reset. + */ +void rdma_user_mmap_disassociate(struct ib_device *device) +{ + struct ib_uverbs_device *uverbs_dev = + ib_get_client_data(device, &uverbs_client); + struct ib_uverbs_file *ufile; + + mutex_lock(&uverbs_dev->lists_mutex); + list_for_each_entry(ufile, &uverbs_dev->uverbs_file_list, list) { + if (ufile->ucontext) + uverbs_user_mmap_disassociate(ufile); + } + mutex_unlock(&uverbs_dev->lists_mutex); } +EXPORT_SYMBOL(rdma_user_mmap_disassociate); /* * ib_uverbs_open() does not need the BKL: @@ -947,6 +984,8 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) mutex_init(&file->umap_lock); INIT_LIST_HEAD(&file->umaps); + mutex_init(&file->disassociation_lock); + filp->private_data = file; list_add_tail(&file->list, &dev->uverbs_file_list); mutex_unlock(&dev->lists_mutex); diff --git a/drivers/infiniband/hw/bnxt_re/Makefile b/drivers/infiniband/hw/bnxt_re/Makefile index ee9bb1be61ea13..f63417d2ccc644 100644 --- a/drivers/infiniband/hw/bnxt_re/Makefile +++ b/drivers/infiniband/hw/bnxt_re/Makefile @@ -4,4 +4,5 @@ ccflags-y := -I $(srctree)/drivers/net/ethernet/broadcom/bnxt obj-$(CONFIG_INFINIBAND_BNXT_RE) += bnxt_re.o bnxt_re-y := main.o ib_verbs.o \ qplib_res.o qplib_rcfw.o \ - qplib_sp.o qplib_fp.o hw_counters.o + qplib_sp.o qplib_fp.o hw_counters.o \ + debugfs.o diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index e94518b12f86ee..2975b11b79bf77 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -154,8 +154,25 @@ struct bnxt_re_pacing { #define BNXT_RE_GRC_FIFO_REG_BASE 0x2000 +#define BNXT_RE_MIN_MSIX 2 +#define BNXT_RE_MAX_MSIX BNXT_MAX_ROCE_MSIX +struct bnxt_re_nq_record { + struct bnxt_msix_entry msix_entries[BNXT_RE_MAX_MSIX]; + struct bnxt_qplib_nq nq[BNXT_RE_MAX_MSIX]; + int num_msix; + /* serialize NQ access */ + struct mutex load_lock; +}; + #define MAX_CQ_HASH_BITS (16) #define MAX_SRQ_HASH_BITS (16) + +static inline bool bnxt_re_chip_gen_p7(u16 chip_num) +{ + return (chip_num == CHIP_NUM_58818 || + chip_num == CHIP_NUM_57608); +} + struct bnxt_re_dev { struct ib_device ibdev; struct list_head list; @@ -174,27 +191,24 @@ struct bnxt_re_dev { unsigned int version, major, minor; struct bnxt_qplib_chip_ctx *chip_ctx; struct bnxt_en_dev *en_dev; - int num_msix; int id; struct delayed_work worker; u8 cur_prio_map; - /* FP Notification Queue (CQ & SRQ) */ - struct tasklet_struct nq_task; - /* RCFW Channel */ struct bnxt_qplib_rcfw rcfw; - /* NQ */ - struct bnxt_qplib_nq nq[BNXT_MAX_ROCE_MSIX]; + /* NQ record */ + struct bnxt_re_nq_record *nqr; /* Device Resources */ struct bnxt_qplib_dev_attr dev_attr; struct bnxt_qplib_ctx qplib_ctx; struct bnxt_qplib_res qplib_res; struct bnxt_qplib_dpi dpi_privileged; + struct bnxt_qplib_cq_coal_param cq_coalescing; struct mutex qp_lock; /* protect qp list */ struct list_head qp_list; @@ -213,6 +227,8 @@ struct bnxt_re_dev { struct delayed_work dbq_pacing_work; DECLARE_HASHTABLE(cq_hash, MAX_CQ_HASH_BITS); DECLARE_HASHTABLE(srq_hash, MAX_SRQ_HASH_BITS); + struct dentry *dbg_root; + struct dentry *qp_debugfs; }; #define to_bnxt_re_dev(ptr, member) \ @@ -239,4 +255,23 @@ static inline void bnxt_re_set_pacing_dev_state(struct bnxt_re_dev *rdev) rdev->qplib_res.pacing_data->dev_err_state = test_bit(BNXT_RE_FLAG_ERR_DEVICE_DETACHED, &rdev->flags); } + +static inline int bnxt_re_read_context_allowed(struct bnxt_re_dev *rdev) +{ + if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) || + rdev->rcfw.res->cctx->hwrm_intf_ver < HWRM_VERSION_READ_CTX) + return -EOPNOTSUPP; + return 0; +} + +#define BNXT_RE_CONTEXT_TYPE_QPC_SIZE_P5 1088 +#define BNXT_RE_CONTEXT_TYPE_CQ_SIZE_P5 128 +#define BNXT_RE_CONTEXT_TYPE_MRW_SIZE_P5 128 +#define BNXT_RE_CONTEXT_TYPE_SRQ_SIZE_P5 192 + +#define BNXT_RE_CONTEXT_TYPE_QPC_SIZE_P7 1088 +#define BNXT_RE_CONTEXT_TYPE_CQ_SIZE_P7 192 +#define BNXT_RE_CONTEXT_TYPE_MRW_SIZE_P7 192 +#define BNXT_RE_CONTEXT_TYPE_SRQ_SIZE_P7 192 + #endif diff --git a/drivers/infiniband/hw/bnxt_re/debugfs.c b/drivers/infiniband/hw/bnxt_re/debugfs.c new file mode 100644 index 00000000000000..7c47039044ef0e --- /dev/null +++ b/drivers/infiniband/hw/bnxt_re/debugfs.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Copyright (c) 2024, Broadcom. All rights reserved. The term + * Broadcom refers to Broadcom Limited and/or its subsidiaries. + * + * Description: Debugfs component of the bnxt_re driver + */ + +#include +#include +#include + +#include "bnxt_ulp.h" +#include "roce_hsi.h" +#include "qplib_res.h" +#include "qplib_sp.h" +#include "qplib_fp.h" +#include "qplib_rcfw.h" +#include "bnxt_re.h" +#include "ib_verbs.h" +#include "debugfs.h" + +static struct dentry *bnxt_re_debugfs_root; + +static inline const char *bnxt_re_qp_state_str(u8 state) +{ + switch (state) { + case CMDQ_MODIFY_QP_NEW_STATE_RESET: + return "RST"; + case CMDQ_MODIFY_QP_NEW_STATE_INIT: + return "INIT"; + case CMDQ_MODIFY_QP_NEW_STATE_RTR: + return "RTR"; + case CMDQ_MODIFY_QP_NEW_STATE_RTS: + return "RTS"; + case CMDQ_MODIFY_QP_NEW_STATE_SQE: + return "SQER"; + case CMDQ_MODIFY_QP_NEW_STATE_SQD: + return "SQD"; + case CMDQ_MODIFY_QP_NEW_STATE_ERR: + return "ERR"; + default: + return "Invalid QP state"; + } +} + +static inline const char *bnxt_re_qp_type_str(u8 type) +{ + switch (type) { + case CMDQ_CREATE_QP1_TYPE_GSI: return "QP1"; + case CMDQ_CREATE_QP_TYPE_GSI: return "QP1"; + case CMDQ_CREATE_QP_TYPE_RC: return "RC"; + case CMDQ_CREATE_QP_TYPE_UD: return "UD"; + case CMDQ_CREATE_QP_TYPE_RAW_ETHERTYPE: return "RAW_ETHERTYPE"; + default: return "Invalid transport type"; + } +} + +static ssize_t qp_info_read(struct file *filep, + char __user *buffer, + size_t count, loff_t *ppos) +{ + struct bnxt_re_qp *qp = filep->private_data; + char *buf; + int len; + + if (*ppos) + return 0; + + buf = kasprintf(GFP_KERNEL, + "QPN\t\t: %d\n" + "transport\t: %s\n" + "state\t\t: %s\n" + "mtu\t\t: %d\n" + "timeout\t\t: %d\n" + "remote QPN\t: %d\n", + qp->qplib_qp.id, + bnxt_re_qp_type_str(qp->qplib_qp.type), + bnxt_re_qp_state_str(qp->qplib_qp.state), + qp->qplib_qp.mtu, + qp->qplib_qp.timeout, + qp->qplib_qp.dest_qpn); + if (!buf) + return -ENOMEM; + if (count < strlen(buf)) { + kfree(buf); + return -ENOSPC; + } + len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); + kfree(buf); + return len; +} + +static const struct file_operations debugfs_qp_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = qp_info_read, +}; + +void bnxt_re_debug_add_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp) +{ + char resn[32]; + + sprintf(resn, "0x%x", qp->qplib_qp.id); + qp->dentry = debugfs_create_file(resn, 0400, rdev->qp_debugfs, qp, &debugfs_qp_fops); +} + +void bnxt_re_debug_rem_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp) +{ + debugfs_remove(qp->dentry); +} + +void bnxt_re_debugfs_add_pdev(struct bnxt_re_dev *rdev) +{ + struct pci_dev *pdev = rdev->en_dev->pdev; + + rdev->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), bnxt_re_debugfs_root); + + rdev->qp_debugfs = debugfs_create_dir("QPs", rdev->dbg_root); +} + +void bnxt_re_debugfs_rem_pdev(struct bnxt_re_dev *rdev) +{ + debugfs_remove_recursive(rdev->qp_debugfs); + + debugfs_remove_recursive(rdev->dbg_root); + rdev->dbg_root = NULL; +} + +void bnxt_re_register_debugfs(void) +{ + bnxt_re_debugfs_root = debugfs_create_dir("bnxt_re", NULL); +} + +void bnxt_re_unregister_debugfs(void) +{ + debugfs_remove(bnxt_re_debugfs_root); +} diff --git a/drivers/infiniband/hw/bnxt_re/debugfs.h b/drivers/infiniband/hw/bnxt_re/debugfs.h new file mode 100644 index 00000000000000..cd3be0a9ec7ee1 --- /dev/null +++ b/drivers/infiniband/hw/bnxt_re/debugfs.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Copyright (c) 2024, Broadcom. All rights reserved. The term + * Broadcom refers to Broadcom Limited and/or its subsidiaries. + * + * Description: Debugfs header + */ + +#ifndef __BNXT_RE_DEBUGFS__ +#define __BNXT_RE_DEBUGFS__ + +void bnxt_re_debug_add_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp); +void bnxt_re_debug_rem_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp); + +void bnxt_re_debugfs_add_pdev(struct bnxt_re_dev *rdev); +void bnxt_re_debugfs_rem_pdev(struct bnxt_re_dev *rdev); + +void bnxt_re_register_debugfs(void); +void bnxt_re_unregister_debugfs(void); + +#endif diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index e66ae9f22c710c..82023394e3300e 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -62,6 +62,7 @@ #include "bnxt_re.h" #include "ib_verbs.h" +#include "debugfs.h" #include #include @@ -94,9 +95,9 @@ static int __from_ib_access_flags(int iflags) return qflags; }; -static enum ib_access_flags __to_ib_access_flags(int qflags) +static int __to_ib_access_flags(int qflags) { - enum ib_access_flags iflags = 0; + int iflags = 0; if (qflags & BNXT_QPLIB_ACCESS_LOCAL_WRITE) iflags |= IB_ACCESS_LOCAL_WRITE; @@ -113,7 +114,49 @@ static enum ib_access_flags __to_ib_access_flags(int qflags) if (qflags & BNXT_QPLIB_ACCESS_ON_DEMAND) iflags |= IB_ACCESS_ON_DEMAND; return iflags; -}; +} + +static u8 __qp_access_flags_from_ib(struct bnxt_qplib_chip_ctx *cctx, int iflags) +{ + u8 qflags = 0; + + if (!bnxt_qplib_is_chip_gen_p5_p7(cctx)) + /* For Wh+ */ + return (u8)__from_ib_access_flags(iflags); + + /* For P5, P7 and later chips */ + if (iflags & IB_ACCESS_LOCAL_WRITE) + qflags |= CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE; + if (iflags & IB_ACCESS_REMOTE_WRITE) + qflags |= CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE; + if (iflags & IB_ACCESS_REMOTE_READ) + qflags |= CMDQ_MODIFY_QP_ACCESS_REMOTE_READ; + if (iflags & IB_ACCESS_REMOTE_ATOMIC) + qflags |= CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC; + + return qflags; +} + +static int __qp_access_flags_to_ib(struct bnxt_qplib_chip_ctx *cctx, u8 qflags) +{ + int iflags = 0; + + if (!bnxt_qplib_is_chip_gen_p5_p7(cctx)) + /* For Wh+ */ + return __to_ib_access_flags(qflags); + + /* For P5, P7 and later chips */ + if (qflags & CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE) + iflags |= IB_ACCESS_LOCAL_WRITE; + if (qflags & CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE) + iflags |= IB_ACCESS_REMOTE_WRITE; + if (qflags & CMDQ_MODIFY_QP_ACCESS_REMOTE_READ) + iflags |= IB_ACCESS_REMOTE_READ; + if (qflags & CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC) + iflags |= IB_ACCESS_REMOTE_ATOMIC; + + return iflags; +} static void bnxt_re_check_and_set_relaxed_ordering(struct bnxt_re_dev *rdev, struct bnxt_qplib_mrw *qplib_mr) @@ -211,6 +254,22 @@ int bnxt_re_query_device(struct ib_device *ibdev, return 0; } +int bnxt_re_modify_device(struct ib_device *ibdev, + int device_modify_mask, + struct ib_device_modify *device_modify) +{ + ibdev_dbg(ibdev, "Modify device with mask 0x%x", device_modify_mask); + + if (device_modify_mask & ~IB_DEVICE_MODIFY_NODE_DESC) + return -EOPNOTSUPP; + + if (!(device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC)) + return 0; + + memcpy(ibdev->node_desc, device_modify->node_desc, IB_DEVICE_NODE_DESC_MAX); + return 0; +} + /* Port */ int bnxt_re_query_port(struct ib_device *ibdev, u32 port_num, struct ib_port_attr *port_attr) @@ -939,6 +998,8 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp, struct ib_udata *udata) else if (qp->qplib_qp.type == CMDQ_CREATE_QP_TYPE_UD) atomic_dec(&rdev->stats.res.ud_qp_count); + bnxt_re_debug_rem_qpinfo(rdev, qp); + ib_umem_release(qp->rumem); ib_umem_release(qp->sumem); @@ -1622,6 +1683,7 @@ int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr, if (active_qps > rdev->stats.res.ud_qp_watermark) rdev->stats.res.ud_qp_watermark = active_qps; } + bnxt_re_debug_add_qpinfo(rdev, qp); return 0; qp_destroy: @@ -1814,8 +1876,8 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, srq->qplib_srq.wqe_size = bnxt_re_get_rwqe_size(dev_attr->max_srq_sges); srq->qplib_srq.threshold = srq_init_attr->attr.srq_limit; srq->srq_limit = srq_init_attr->attr.srq_limit; - srq->qplib_srq.eventq_hw_ring_id = rdev->nq[0].ring_id; - nq = &rdev->nq[0]; + srq->qplib_srq.eventq_hw_ring_id = rdev->nqr->nq[0].ring_id; + nq = &rdev->nqr->nq[0]; if (udata) { rc = bnxt_re_init_user_srq(rdev, pd, srq, udata); @@ -2041,12 +2103,10 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, if (qp_attr_mask & IB_QP_ACCESS_FLAGS) { qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_ACCESS; qp->qplib_qp.access = - __from_ib_access_flags(qp_attr->qp_access_flags); + __qp_access_flags_from_ib(qp->qplib_qp.cctx, + qp_attr->qp_access_flags); /* LOCAL_WRITE access must be set to allow RC receive */ - qp->qplib_qp.access |= BNXT_QPLIB_ACCESS_LOCAL_WRITE; - /* Temp: Set all params on QP as of now */ - qp->qplib_qp.access |= CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE; - qp->qplib_qp.access |= CMDQ_MODIFY_QP_ACCESS_REMOTE_READ; + qp->qplib_qp.access |= CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE; } if (qp_attr_mask & IB_QP_PKEY_INDEX) { qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_PKEY; @@ -2080,7 +2140,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, qp->qplib_qp.ah.sgid_index = ctx->idx; qp->qplib_qp.ah.host_sgid_index = grh->sgid_index; qp->qplib_qp.ah.hop_limit = grh->hop_limit; - qp->qplib_qp.ah.traffic_class = grh->traffic_class; + qp->qplib_qp.ah.traffic_class = grh->traffic_class >> 2; qp->qplib_qp.ah.sl = rdma_ah_get_sl(&qp_attr->ah_attr); ether_addr_copy(qp->qplib_qp.ah.dmac, qp_attr->ah_attr.roce.dmac); @@ -2251,7 +2311,8 @@ int bnxt_re_query_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr, qp_attr->qp_state = __to_ib_qp_state(qplib_qp->state); qp_attr->cur_qp_state = __to_ib_qp_state(qplib_qp->cur_qp_state); qp_attr->en_sqd_async_notify = qplib_qp->en_sqd_async_notify ? 1 : 0; - qp_attr->qp_access_flags = __to_ib_access_flags(qplib_qp->access); + qp_attr->qp_access_flags = __qp_access_flags_to_ib(qp->qplib_qp.cctx, + qplib_qp->access); qp_attr->pkey_index = qplib_qp->pkey_index; qp_attr->qkey = qplib_qp->qkey; qp_attr->ah_attr.type = RDMA_AH_ATTR_TYPE_ROCE; @@ -2972,6 +3033,28 @@ int bnxt_re_post_recv(struct ib_qp *ib_qp, const struct ib_recv_wr *wr, return rc; } +static struct bnxt_qplib_nq *bnxt_re_get_nq(struct bnxt_re_dev *rdev) +{ + int min, indx; + + mutex_lock(&rdev->nqr->load_lock); + for (indx = 0, min = 0; indx < (rdev->nqr->num_msix - 1); indx++) { + if (rdev->nqr->nq[min].load > rdev->nqr->nq[indx].load) + min = indx; + } + rdev->nqr->nq[min].load++; + mutex_unlock(&rdev->nqr->load_lock); + + return &rdev->nqr->nq[min]; +} + +static void bnxt_re_put_nq(struct bnxt_re_dev *rdev, struct bnxt_qplib_nq *nq) +{ + mutex_lock(&rdev->nqr->load_lock); + nq->load--; + mutex_unlock(&rdev->nqr->load_lock); +} + /* Completion Queues */ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) { @@ -2990,6 +3073,8 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata) hash_del(&cq->hash_entry); } bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq); + + bnxt_re_put_nq(rdev, nq); ib_umem_release(cq->umem); atomic_dec(&rdev->stats.res.cq_count); @@ -3008,8 +3093,6 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx); struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr; struct bnxt_qplib_chip_ctx *cctx; - struct bnxt_qplib_nq *nq = NULL; - unsigned int nq_alloc_cnt; int cqe = attr->cqe; int rc, entries; u32 active_cqs; @@ -3060,15 +3143,10 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, cq->qplib_cq.dpi = &rdev->dpi_privileged; } - /* - * Allocating the NQ in a round robin fashion. nq_alloc_cnt is a - * used for getting the NQ index. - */ - nq_alloc_cnt = atomic_inc_return(&rdev->nq_alloc_cnt); - nq = &rdev->nq[nq_alloc_cnt % (rdev->num_msix - 1)]; cq->qplib_cq.max_wqe = entries; - cq->qplib_cq.cnq_hw_ring_id = nq->ring_id; - cq->qplib_cq.nq = nq; + cq->qplib_cq.coalescing = &rdev->cq_coalescing; + cq->qplib_cq.nq = bnxt_re_get_nq(rdev); + cq->qplib_cq.cnq_hw_ring_id = cq->qplib_cq.nq->ring_id; rc = bnxt_qplib_create_cq(&rdev->qplib_res, &cq->qplib_cq); if (rc) { @@ -3078,7 +3156,6 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, cq->ib_cq.cqe = entries; cq->cq_period = cq->qplib_cq.period; - nq->budget++; active_cqs = atomic_inc_return(&rdev->stats.res.cq_count); if (active_cqs > rdev->stats.res.cq_watermark) @@ -3633,7 +3710,7 @@ static void bnxt_re_process_res_shadow_qp_wc(struct bnxt_re_qp *gsi_sqp, wc->byte_len = orig_cqe->length; wc->qp = &gsi_qp->ib_qp; - wc->ex.imm_data = cpu_to_be32(le32_to_cpu(orig_cqe->immdata)); + wc->ex.imm_data = cpu_to_be32(orig_cqe->immdata); wc->src_qp = orig_cqe->src_qp; memcpy(wc->smac, orig_cqe->smac, ETH_ALEN); if (bnxt_re_is_vlan_pkt(orig_cqe, &vlan_id, &sl)) { @@ -3778,7 +3855,10 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc) (unsigned long)(cqe->qp_handle), struct bnxt_re_qp, qplib_qp); wc->qp = &qp->ib_qp; - wc->ex.imm_data = cpu_to_be32(le32_to_cpu(cqe->immdata)); + if (cqe->flags & CQ_RES_RC_FLAGS_IMM) + wc->ex.imm_data = cpu_to_be32(cqe->immdata); + else + wc->ex.invalidate_rkey = cqe->invrkey; wc->src_qp = cqe->src_qp; memcpy(wc->smac, cqe->smac, ETH_ALEN); wc->port_num = 1; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h index b789e47ec97a85..ac59f1d73b152b 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h @@ -95,6 +95,7 @@ struct bnxt_re_qp { struct ib_ud_header qp1_hdr; struct bnxt_re_cq *scq; struct bnxt_re_cq *rcq; + struct dentry *dentry; }; struct bnxt_re_cq { @@ -196,6 +197,9 @@ static inline bool bnxt_re_is_var_size_supported(struct bnxt_re_dev *rdev, int bnxt_re_query_device(struct ib_device *ibdev, struct ib_device_attr *ib_attr, struct ib_udata *udata); +int bnxt_re_modify_device(struct ib_device *ibdev, + int device_modify_mask, + struct ib_device_modify *device_modify); int bnxt_re_query_port(struct ib_device *ibdev, u32 port_num, struct ib_port_attr *port_attr); int bnxt_re_get_port_immutable(struct ib_device *ibdev, u32 port_num, diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index 9eb290ec71a85d..b7af0d5ff3b642 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -67,6 +67,7 @@ #include #include "bnxt.h" #include "hw_counters.h" +#include "debugfs.h" static char version[] = BNXT_RE_DESC "\n"; @@ -183,6 +184,7 @@ static int bnxt_re_setup_chip_ctx(struct bnxt_re_dev *rdev) rdev->rcfw.res = &rdev->qplib_res; rdev->qplib_res.dattr = &rdev->dev_attr; rdev->qplib_res.is_vf = BNXT_EN_VF(en_dev); + rdev->qplib_res.en_dev = en_dev; bnxt_re_set_drv_mode(rdev); @@ -287,12 +289,17 @@ static void bnxt_re_set_resource_limits(struct bnxt_re_dev *rdev) static void bnxt_re_vf_res_config(struct bnxt_re_dev *rdev) { + /* + * Use the total VF count since the actual VF count may not be + * available at this point. + */ rdev->num_vfs = pci_sriov_get_totalvfs(rdev->en_dev->pdev); - if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) { - bnxt_re_set_resource_limits(rdev); - bnxt_qplib_set_func_resources(&rdev->qplib_res, &rdev->rcfw, - &rdev->qplib_ctx); - } + if (!rdev->num_vfs) + return; + + bnxt_re_set_resource_limits(rdev); + bnxt_qplib_set_func_resources(&rdev->qplib_res, &rdev->rcfw, + &rdev->qplib_ctx); } static void bnxt_re_shutdown(struct auxiliary_device *adev) @@ -316,8 +323,8 @@ static void bnxt_re_stop_irq(void *handle) rdev = en_info->rdev; rcfw = &rdev->rcfw; - for (indx = BNXT_RE_NQ_IDX; indx < rdev->num_msix; indx++) { - nq = &rdev->nq[indx - 1]; + for (indx = BNXT_RE_NQ_IDX; indx < rdev->nqr->num_msix; indx++) { + nq = &rdev->nqr->nq[indx - 1]; bnxt_qplib_nq_stop_irq(nq, false); } @@ -334,7 +341,7 @@ static void bnxt_re_start_irq(void *handle, struct bnxt_msix_entry *ent) int indx, rc; rdev = en_info->rdev; - msix_ent = rdev->en_dev->msix_entries; + msix_ent = rdev->nqr->msix_entries; rcfw = &rdev->rcfw; if (!ent) { /* Not setting the f/w timeout bit in rcfw. @@ -349,8 +356,8 @@ static void bnxt_re_start_irq(void *handle, struct bnxt_msix_entry *ent) /* Vectors may change after restart, so update with new vectors * in device sctructure. */ - for (indx = 0; indx < rdev->num_msix; indx++) - rdev->en_dev->msix_entries[indx].vector = ent[indx].vector; + for (indx = 0; indx < rdev->nqr->num_msix; indx++) + rdev->nqr->msix_entries[indx].vector = ent[indx].vector; rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_ent[BNXT_RE_AEQ_IDX].vector, false); @@ -358,8 +365,8 @@ static void bnxt_re_start_irq(void *handle, struct bnxt_msix_entry *ent) ibdev_warn(&rdev->ibdev, "Failed to reinit CREQ\n"); return; } - for (indx = BNXT_RE_NQ_IDX ; indx < rdev->num_msix; indx++) { - nq = &rdev->nq[indx - 1]; + for (indx = BNXT_RE_NQ_IDX ; indx < rdev->nqr->num_msix; indx++) { + nq = &rdev->nqr->nq[indx - 1]; rc = bnxt_qplib_nq_start_irq(nq, indx - 1, msix_ent[indx].vector, false); if (rc) { @@ -873,6 +880,253 @@ static const struct attribute_group bnxt_re_dev_attr_group = { .attrs = bnxt_re_attributes, }; +static int bnxt_re_fill_res_mr_entry(struct sk_buff *msg, struct ib_mr *ib_mr) +{ + struct bnxt_qplib_hwq *mr_hwq; + struct nlattr *table_attr; + struct bnxt_re_mr *mr; + + table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_DRIVER); + if (!table_attr) + return -EMSGSIZE; + + mr = container_of(ib_mr, struct bnxt_re_mr, ib_mr); + mr_hwq = &mr->qplib_mr.hwq; + + if (rdma_nl_put_driver_u32(msg, "page_size", + mr_hwq->qe_ppg * mr_hwq->element_size)) + goto err; + if (rdma_nl_put_driver_u32(msg, "max_elements", mr_hwq->max_elements)) + goto err; + if (rdma_nl_put_driver_u32(msg, "element_size", mr_hwq->element_size)) + goto err; + if (rdma_nl_put_driver_u64_hex(msg, "hwq", (unsigned long)mr_hwq)) + goto err; + if (rdma_nl_put_driver_u64_hex(msg, "va", mr->qplib_mr.va)) + goto err; + + nla_nest_end(msg, table_attr); + return 0; + +err: + nla_nest_cancel(msg, table_attr); + return -EMSGSIZE; +} + +static int bnxt_re_fill_res_mr_entry_raw(struct sk_buff *msg, struct ib_mr *ib_mr) +{ + struct bnxt_re_dev *rdev; + struct bnxt_re_mr *mr; + int err, len; + void *data; + + mr = container_of(ib_mr, struct bnxt_re_mr, ib_mr); + rdev = mr->rdev; + + err = bnxt_re_read_context_allowed(rdev); + if (err) + return err; + + len = bnxt_qplib_is_chip_gen_p7(rdev->chip_ctx) ? BNXT_RE_CONTEXT_TYPE_MRW_SIZE_P7 : + BNXT_RE_CONTEXT_TYPE_MRW_SIZE_P5; + data = kzalloc(len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + err = bnxt_qplib_read_context(&rdev->rcfw, CMDQ_READ_CONTEXT_TYPE_MRW, + mr->qplib_mr.lkey, len, data); + if (!err) + err = nla_put(msg, RDMA_NLDEV_ATTR_RES_RAW, len, data); + + kfree(data); + return err; +} + +static int bnxt_re_fill_res_cq_entry(struct sk_buff *msg, struct ib_cq *ib_cq) +{ + struct bnxt_qplib_hwq *cq_hwq; + struct nlattr *table_attr; + struct bnxt_re_cq *cq; + + cq = container_of(ib_cq, struct bnxt_re_cq, ib_cq); + cq_hwq = &cq->qplib_cq.hwq; + + table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_DRIVER); + if (!table_attr) + return -EMSGSIZE; + + if (rdma_nl_put_driver_u32(msg, "cq_depth", cq_hwq->depth)) + goto err; + if (rdma_nl_put_driver_u32(msg, "max_elements", cq_hwq->max_elements)) + goto err; + if (rdma_nl_put_driver_u32(msg, "element_size", cq_hwq->element_size)) + goto err; + if (rdma_nl_put_driver_u32(msg, "max_wqe", cq->qplib_cq.max_wqe)) + goto err; + + nla_nest_end(msg, table_attr); + return 0; + +err: + nla_nest_cancel(msg, table_attr); + return -EMSGSIZE; +} + +static int bnxt_re_fill_res_cq_entry_raw(struct sk_buff *msg, struct ib_cq *ib_cq) +{ + struct bnxt_re_dev *rdev; + struct bnxt_re_cq *cq; + int err, len; + void *data; + + cq = container_of(ib_cq, struct bnxt_re_cq, ib_cq); + rdev = cq->rdev; + + err = bnxt_re_read_context_allowed(rdev); + if (err) + return err; + + len = bnxt_qplib_is_chip_gen_p7(rdev->chip_ctx) ? BNXT_RE_CONTEXT_TYPE_CQ_SIZE_P7 : + BNXT_RE_CONTEXT_TYPE_CQ_SIZE_P5; + data = kzalloc(len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + err = bnxt_qplib_read_context(&rdev->rcfw, + CMDQ_READ_CONTEXT_TYPE_CQ, + cq->qplib_cq.id, len, data); + if (!err) + err = nla_put(msg, RDMA_NLDEV_ATTR_RES_RAW, len, data); + + kfree(data); + return err; +} + +static int bnxt_re_fill_res_qp_entry(struct sk_buff *msg, struct ib_qp *ib_qp) +{ + struct bnxt_qplib_qp *qplib_qp; + struct nlattr *table_attr; + struct bnxt_re_qp *qp; + + table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_DRIVER); + if (!table_attr) + return -EMSGSIZE; + + qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp); + qplib_qp = &qp->qplib_qp; + + if (rdma_nl_put_driver_u32(msg, "sq_max_wqe", qplib_qp->sq.max_wqe)) + goto err; + if (rdma_nl_put_driver_u32(msg, "sq_max_sge", qplib_qp->sq.max_sge)) + goto err; + if (rdma_nl_put_driver_u32(msg, "sq_wqe_size", qplib_qp->sq.wqe_size)) + goto err; + if (rdma_nl_put_driver_u32(msg, "sq_swq_start", qplib_qp->sq.swq_start)) + goto err; + if (rdma_nl_put_driver_u32(msg, "sq_swq_last", qplib_qp->sq.swq_last)) + goto err; + if (rdma_nl_put_driver_u32(msg, "rq_max_wqe", qplib_qp->rq.max_wqe)) + goto err; + if (rdma_nl_put_driver_u32(msg, "rq_max_sge", qplib_qp->rq.max_sge)) + goto err; + if (rdma_nl_put_driver_u32(msg, "rq_wqe_size", qplib_qp->rq.wqe_size)) + goto err; + if (rdma_nl_put_driver_u32(msg, "rq_swq_start", qplib_qp->rq.swq_start)) + goto err; + if (rdma_nl_put_driver_u32(msg, "rq_swq_last", qplib_qp->rq.swq_last)) + goto err; + if (rdma_nl_put_driver_u32(msg, "timeout", qplib_qp->timeout)) + goto err; + + nla_nest_end(msg, table_attr); + return 0; + +err: + nla_nest_cancel(msg, table_attr); + return -EMSGSIZE; +} + +static int bnxt_re_fill_res_qp_entry_raw(struct sk_buff *msg, struct ib_qp *ibqp) +{ + struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibqp->device, ibdev); + int err, len; + void *data; + + err = bnxt_re_read_context_allowed(rdev); + if (err) + return err; + + len = bnxt_qplib_is_chip_gen_p7(rdev->chip_ctx) ? BNXT_RE_CONTEXT_TYPE_QPC_SIZE_P7 : + BNXT_RE_CONTEXT_TYPE_QPC_SIZE_P5; + data = kzalloc(len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + err = bnxt_qplib_read_context(&rdev->rcfw, CMDQ_READ_CONTEXT_TYPE_QPC, + ibqp->qp_num, len, data); + if (!err) + err = nla_put(msg, RDMA_NLDEV_ATTR_RES_RAW, len, data); + + kfree(data); + return err; +} + +static int bnxt_re_fill_res_srq_entry(struct sk_buff *msg, struct ib_srq *ib_srq) +{ + struct nlattr *table_attr; + struct bnxt_re_srq *srq; + + table_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_DRIVER); + if (!table_attr) + return -EMSGSIZE; + + srq = container_of(ib_srq, struct bnxt_re_srq, ib_srq); + + if (rdma_nl_put_driver_u32_hex(msg, "wqe_size", srq->qplib_srq.wqe_size)) + goto err; + if (rdma_nl_put_driver_u32_hex(msg, "max_wqe", srq->qplib_srq.max_wqe)) + goto err; + if (rdma_nl_put_driver_u32_hex(msg, "max_sge", srq->qplib_srq.max_sge)) + goto err; + + nla_nest_end(msg, table_attr); + return 0; + +err: + nla_nest_cancel(msg, table_attr); + return -EMSGSIZE; +} + +static int bnxt_re_fill_res_srq_entry_raw(struct sk_buff *msg, struct ib_srq *ib_srq) +{ + struct bnxt_re_dev *rdev; + struct bnxt_re_srq *srq; + int err, len; + void *data; + + srq = container_of(ib_srq, struct bnxt_re_srq, ib_srq); + rdev = srq->rdev; + + err = bnxt_re_read_context_allowed(rdev); + if (err) + return err; + + len = bnxt_qplib_is_chip_gen_p7(rdev->chip_ctx) ? BNXT_RE_CONTEXT_TYPE_SRQ_SIZE_P7 : + BNXT_RE_CONTEXT_TYPE_SRQ_SIZE_P5; + + data = kzalloc(len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + err = bnxt_qplib_read_context(&rdev->rcfw, CMDQ_READ_CONTEXT_TYPE_SRQ, + srq->qplib_srq.id, len, data); + if (!err) + err = nla_put(msg, RDMA_NLDEV_ATTR_RES_RAW, len, data); + + kfree(data); + return err; +} + static const struct ib_device_ops bnxt_re_dev_ops = { .owner = THIS_MODULE, .driver_id = RDMA_DRIVER_BNXT_RE, @@ -914,6 +1168,7 @@ static const struct ib_device_ops bnxt_re_dev_ops = { .post_srq_recv = bnxt_re_post_srq_recv, .query_ah = bnxt_re_query_ah, .query_device = bnxt_re_query_device, + .modify_device = bnxt_re_modify_device, .query_pkey = bnxt_re_query_pkey, .query_port = bnxt_re_query_port, .query_qp = bnxt_re_query_qp, @@ -930,6 +1185,17 @@ static const struct ib_device_ops bnxt_re_dev_ops = { INIT_RDMA_OBJ_SIZE(ib_ucontext, bnxt_re_ucontext, ib_uctx), }; +static const struct ib_device_ops restrack_ops = { + .fill_res_cq_entry = bnxt_re_fill_res_cq_entry, + .fill_res_cq_entry_raw = bnxt_re_fill_res_cq_entry_raw, + .fill_res_qp_entry = bnxt_re_fill_res_qp_entry, + .fill_res_qp_entry_raw = bnxt_re_fill_res_qp_entry_raw, + .fill_res_mr_entry = bnxt_re_fill_res_mr_entry, + .fill_res_mr_entry_raw = bnxt_re_fill_res_mr_entry_raw, + .fill_res_srq_entry = bnxt_re_fill_res_srq_entry, + .fill_res_srq_entry_raw = bnxt_re_fill_res_srq_entry_raw, +}; + static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) { struct ib_device *ibdev = &rdev->ibdev; @@ -943,7 +1209,7 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) addrconf_addr_eui48((u8 *)&ibdev->node_guid, rdev->netdev->dev_addr); - ibdev->num_comp_vectors = rdev->num_msix - 1; + ibdev->num_comp_vectors = rdev->nqr->num_msix - 1; ibdev->dev.parent = &rdev->en_dev->pdev->dev; ibdev->local_dma_lkey = BNXT_QPLIB_RSVD_LKEY; @@ -951,6 +1217,7 @@ static int bnxt_re_register_ib(struct bnxt_re_dev *rdev) ibdev->driver_def = bnxt_re_uapi_defs; ib_set_device_ops(ibdev, &bnxt_re_dev_ops); + ib_set_device_ops(ibdev, &restrack_ops); ret = ib_device_set_netdev(&rdev->ibdev, rdev->netdev, 1); if (ret) return ret; @@ -990,6 +1257,15 @@ static struct bnxt_re_dev *bnxt_re_dev_add(struct auxiliary_device *adev, atomic_set(&rdev->stats.res.pd_count, 0); rdev->cosq[0] = 0xFFFF; rdev->cosq[1] = 0xFFFF; + rdev->cq_coalescing.buf_maxtime = BNXT_QPLIB_CQ_COAL_DEF_BUF_MAXTIME; + if (bnxt_re_chip_gen_p7(en_dev->chip_num)) { + rdev->cq_coalescing.normal_maxbuf = BNXT_QPLIB_CQ_COAL_DEF_NORMAL_MAXBUF_P7; + rdev->cq_coalescing.during_maxbuf = BNXT_QPLIB_CQ_COAL_DEF_DURING_MAXBUF_P7; + } else { + rdev->cq_coalescing.normal_maxbuf = BNXT_QPLIB_CQ_COAL_DEF_NORMAL_MAXBUF_P5; + rdev->cq_coalescing.during_maxbuf = BNXT_QPLIB_CQ_COAL_DEF_DURING_MAXBUF_P5; + } + rdev->cq_coalescing.en_ring_idle_mode = BNXT_QPLIB_CQ_COAL_DEF_EN_RING_IDLE_MODE; return rdev; } @@ -1276,8 +1552,8 @@ static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev) { int i; - for (i = 1; i < rdev->num_msix; i++) - bnxt_qplib_disable_nq(&rdev->nq[i - 1]); + for (i = 1; i < rdev->nqr->num_msix; i++) + bnxt_qplib_disable_nq(&rdev->nqr->nq[i - 1]); if (rdev->qplib_res.rcfw) bnxt_qplib_cleanup_res(&rdev->qplib_res); @@ -1291,10 +1567,12 @@ static int bnxt_re_init_res(struct bnxt_re_dev *rdev) bnxt_qplib_init_res(&rdev->qplib_res); - for (i = 1; i < rdev->num_msix ; i++) { - db_offt = rdev->en_dev->msix_entries[i].db_offset; - rc = bnxt_qplib_enable_nq(rdev->en_dev->pdev, &rdev->nq[i - 1], - i - 1, rdev->en_dev->msix_entries[i].vector, + mutex_init(&rdev->nqr->load_lock); + + for (i = 1; i < rdev->nqr->num_msix ; i++) { + db_offt = rdev->nqr->msix_entries[i].db_offset; + rc = bnxt_qplib_enable_nq(rdev->en_dev->pdev, &rdev->nqr->nq[i - 1], + i - 1, rdev->nqr->msix_entries[i].vector, db_offt, &bnxt_re_cqn_handler, &bnxt_re_srqn_handler); if (rc) { @@ -1307,20 +1585,22 @@ static int bnxt_re_init_res(struct bnxt_re_dev *rdev) return 0; fail: for (i = num_vec_enabled; i >= 0; i--) - bnxt_qplib_disable_nq(&rdev->nq[i]); + bnxt_qplib_disable_nq(&rdev->nqr->nq[i]); return rc; } static void bnxt_re_free_nq_res(struct bnxt_re_dev *rdev) { + struct bnxt_qplib_nq *nq; u8 type; int i; - for (i = 0; i < rdev->num_msix - 1; i++) { + for (i = 0; i < rdev->nqr->num_msix - 1; i++) { type = bnxt_qplib_get_ring_type(rdev->chip_ctx); - bnxt_re_net_ring_free(rdev, rdev->nq[i].ring_id, type); - bnxt_qplib_free_nq(&rdev->nq[i]); - rdev->nq[i].res = NULL; + nq = &rdev->nqr->nq[i]; + bnxt_re_net_ring_free(rdev, nq->ring_id, type); + bnxt_qplib_free_nq(nq); + nq->res = NULL; } } @@ -1362,12 +1642,12 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) if (rc) goto dealloc_res; - for (i = 0; i < rdev->num_msix - 1; i++) { + for (i = 0; i < rdev->nqr->num_msix - 1; i++) { struct bnxt_qplib_nq *nq; - nq = &rdev->nq[i]; + nq = &rdev->nqr->nq[i]; nq->hwq.max_elements = BNXT_QPLIB_NQE_MAX_CNT; - rc = bnxt_qplib_alloc_nq(&rdev->qplib_res, &rdev->nq[i]); + rc = bnxt_qplib_alloc_nq(&rdev->qplib_res, nq); if (rc) { ibdev_err(&rdev->ibdev, "Alloc Failed NQ%d rc:%#x", i, rc); @@ -1375,17 +1655,17 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) } type = bnxt_qplib_get_ring_type(rdev->chip_ctx); rattr.dma_arr = nq->hwq.pbl[PBL_LVL_0].pg_map_arr; - rattr.pages = nq->hwq.pbl[rdev->nq[i].hwq.level].pg_count; + rattr.pages = nq->hwq.pbl[rdev->nqr->nq[i].hwq.level].pg_count; rattr.type = type; rattr.mode = RING_ALLOC_REQ_INT_MODE_MSIX; rattr.depth = BNXT_QPLIB_NQE_MAX_CNT - 1; - rattr.lrid = rdev->en_dev->msix_entries[i + 1].ring_idx; + rattr.lrid = rdev->nqr->msix_entries[i + 1].ring_idx; rc = bnxt_re_net_ring_alloc(rdev, &rattr, &nq->ring_id); if (rc) { ibdev_err(&rdev->ibdev, "Failed to allocate NQ fw id with rc = 0x%x", rc); - bnxt_qplib_free_nq(&rdev->nq[i]); + bnxt_qplib_free_nq(nq); goto free_nq; } num_vec_created++; @@ -1394,8 +1674,8 @@ static int bnxt_re_alloc_res(struct bnxt_re_dev *rdev) free_nq: for (i = num_vec_created - 1; i >= 0; i--) { type = bnxt_qplib_get_ring_type(rdev->chip_ctx); - bnxt_re_net_ring_free(rdev, rdev->nq[i].ring_id, type); - bnxt_qplib_free_nq(&rdev->nq[i]); + bnxt_re_net_ring_free(rdev, rdev->nqr->nq[i].ring_id, type); + bnxt_qplib_free_nq(&rdev->nqr->nq[i]); } bnxt_qplib_dealloc_dpi(&rdev->qplib_res, &rdev->dpi_privileged); @@ -1590,11 +1870,28 @@ static int bnxt_re_ib_init(struct bnxt_re_dev *rdev) return rc; } +static int bnxt_re_alloc_nqr_mem(struct bnxt_re_dev *rdev) +{ + rdev->nqr = kzalloc(sizeof(*rdev->nqr), GFP_KERNEL); + if (!rdev->nqr) + return -ENOMEM; + + return 0; +} + +static void bnxt_re_free_nqr_mem(struct bnxt_re_dev *rdev) +{ + kfree(rdev->nqr); + rdev->nqr = NULL; +} + static void bnxt_re_dev_uninit(struct bnxt_re_dev *rdev, u8 op_type) { u8 type; int rc; + bnxt_re_debugfs_rem_pdev(rdev); + if (test_and_clear_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags)) cancel_delayed_work_sync(&rdev->worker); @@ -1617,11 +1914,12 @@ static void bnxt_re_dev_uninit(struct bnxt_re_dev *rdev, u8 op_type) bnxt_qplib_free_rcfw_channel(&rdev->rcfw); } - rdev->num_msix = 0; + rdev->nqr->num_msix = 0; if (rdev->pacing.dbr_pacing) bnxt_re_deinitialize_dbr_pacing(rdev); + bnxt_re_free_nqr_mem(rdev); bnxt_re_destroy_chip_ctx(rdev); if (op_type == BNXT_RE_COMPLETE_REMOVE) { if (test_and_clear_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags)) @@ -1659,6 +1957,17 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type) } set_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags); + if (rdev->en_dev->ulp_tbl->msix_requested < BNXT_RE_MIN_MSIX) { + ibdev_err(&rdev->ibdev, + "RoCE requires minimum 2 MSI-X vectors, but only %d reserved\n", + rdev->en_dev->ulp_tbl->msix_requested); + bnxt_unregister_dev(rdev->en_dev); + clear_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags); + return -EINVAL; + } + ibdev_dbg(&rdev->ibdev, "Got %d MSI-X vectors\n", + rdev->en_dev->ulp_tbl->msix_requested); + rc = bnxt_re_setup_chip_ctx(rdev); if (rc) { bnxt_unregister_dev(rdev->en_dev); @@ -1667,19 +1976,20 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type) return -EINVAL; } + rc = bnxt_re_alloc_nqr_mem(rdev); + if (rc) { + bnxt_re_destroy_chip_ctx(rdev); + bnxt_unregister_dev(rdev->en_dev); + clear_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags); + return rc; + } + rdev->nqr->num_msix = rdev->en_dev->ulp_tbl->msix_requested; + memcpy(rdev->nqr->msix_entries, rdev->en_dev->msix_entries, + sizeof(struct bnxt_msix_entry) * rdev->nqr->num_msix); + /* Check whether VF or PF */ bnxt_re_get_sriov_func_type(rdev); - if (!rdev->en_dev->ulp_tbl->msix_requested) { - ibdev_err(&rdev->ibdev, - "Failed to get MSI-X vectors: %#x\n", rc); - rc = -EINVAL; - goto fail; - } - ibdev_dbg(&rdev->ibdev, "Got %d MSI-X vectors\n", - rdev->en_dev->ulp_tbl->msix_requested); - rdev->num_msix = rdev->en_dev->ulp_tbl->msix_requested; - bnxt_re_query_hwrm_intf_version(rdev); /* Establish RCFW Communication Channel to initialize the context @@ -1701,14 +2011,14 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type) rattr.type = type; rattr.mode = RING_ALLOC_REQ_INT_MODE_MSIX; rattr.depth = BNXT_QPLIB_CREQE_MAX_CNT - 1; - rattr.lrid = rdev->en_dev->msix_entries[BNXT_RE_AEQ_IDX].ring_idx; + rattr.lrid = rdev->nqr->msix_entries[BNXT_RE_AEQ_IDX].ring_idx; rc = bnxt_re_net_ring_alloc(rdev, &rattr, &creq->ring_id); if (rc) { ibdev_err(&rdev->ibdev, "Failed to allocate CREQ: %#x\n", rc); goto free_rcfw; } - db_offt = rdev->en_dev->msix_entries[BNXT_RE_AEQ_IDX].db_offset; - vid = rdev->en_dev->msix_entries[BNXT_RE_AEQ_IDX].vector; + db_offt = rdev->nqr->msix_entries[BNXT_RE_AEQ_IDX].db_offset; + vid = rdev->nqr->msix_entries[BNXT_RE_AEQ_IDX].vector; rc = bnxt_qplib_enable_rcfw_channel(&rdev->rcfw, vid, db_offt, &bnxt_re_aeq_handler); @@ -1785,16 +2095,16 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type) INIT_DELAYED_WORK(&rdev->worker, bnxt_re_worker); set_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags); schedule_delayed_work(&rdev->worker, msecs_to_jiffies(30000)); - /* - * Use the total VF count since the actual VF count may not be - * available at this point. - */ - bnxt_re_vf_res_config(rdev); + + if (!(rdev->qplib_res.en_dev->flags & BNXT_EN_FLAG_ROCE_VF_RES_MGMT)) + bnxt_re_vf_res_config(rdev); } hash_init(rdev->cq_hash); if (rdev->chip_ctx->modes.toggle_bits & BNXT_QPLIB_SRQ_TOGGLE_BIT) hash_init(rdev->srq_hash); + bnxt_re_debugfs_add_pdev(rdev); + return 0; free_sctx: bnxt_re_net_stats_ctx_free(rdev, rdev->qplib_ctx.stats.fw_id); @@ -1896,11 +2206,10 @@ static void bnxt_re_setup_cc(struct bnxt_re_dev *rdev, bool enable) if (enable) { cc_param.enable = 1; - cc_param.cc_mode = CMDQ_MODIFY_ROCE_CC_CC_MODE_PROBABILISTIC_CC_MODE; + cc_param.tos_ecn = 1; } - cc_param.mask = (CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE | - CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC | + cc_param.mask = (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)) @@ -2033,12 +2342,6 @@ static int bnxt_re_suspend(struct auxiliary_device *adev, pm_message_t state) rdev = en_info->rdev; en_dev = en_info->en_dev; mutex_lock(&bnxt_re_mutex); - /* L2 driver may invoke this callback during device error/crash or device - * reset. Current RoCE driver doesn't recover the device in case of - * error. Handle the error by dispatching fatal events to all qps - * ie. by calling bnxt_re_dev_stop and release the MSIx vectors as - * L2 driver want to modify the MSIx table. - */ ibdev_info(&rdev->ibdev, "Handle device suspend call"); /* Check the current device state from bnxt_en_dev and move the @@ -2046,17 +2349,12 @@ static int bnxt_re_suspend(struct auxiliary_device *adev, pm_message_t state) * This prevents more commands to HW during clean-up, * in case the device is already in error. */ - if (test_bit(BNXT_STATE_FW_FATAL_COND, &rdev->en_dev->en_state)) + if (test_bit(BNXT_STATE_FW_FATAL_COND, &rdev->en_dev->en_state)) { set_bit(ERR_DEVICE_DETACHED, &rdev->rcfw.cmdq.flags); - - bnxt_re_dev_stop(rdev); - bnxt_re_stop_irq(adev); - /* Move the device states to detached and avoid sending any more - * commands to HW - */ - set_bit(BNXT_RE_FLAG_ERR_DEVICE_DETACHED, &rdev->flags); - set_bit(ERR_DEVICE_DETACHED, &rdev->rcfw.cmdq.flags); - wake_up_all(&rdev->rcfw.cmdq.waitq); + set_bit(BNXT_RE_FLAG_ERR_DEVICE_DETACHED, &rdev->flags); + wake_up_all(&rdev->rcfw.cmdq.waitq); + bnxt_re_dev_stop(rdev); + } if (rdev->pacing.dbr_pacing) bnxt_re_set_pacing_dev_state(rdev); @@ -2075,13 +2373,6 @@ static int bnxt_re_resume(struct auxiliary_device *adev) struct bnxt_re_dev *rdev; mutex_lock(&bnxt_re_mutex); - /* L2 driver may invoke this callback during device recovery, resume. - * reset. Current RoCE driver doesn't recover the device in case of - * error. Handle the error by dispatching fatal events to all qps - * ie. by calling bnxt_re_dev_stop and release the MSIx vectors as - * L2 driver want to modify the MSIx table. - */ - bnxt_re_add_device(adev, BNXT_RE_POST_RECOVERY_INIT); rdev = en_info->rdev; ibdev_info(&rdev->ibdev, "Device resume completed"); @@ -2112,18 +2403,24 @@ static int __init bnxt_re_mod_init(void) int rc; pr_info("%s: %s", ROCE_DRV_MODULE_NAME, version); + bnxt_re_register_debugfs(); + rc = auxiliary_driver_register(&bnxt_re_driver); if (rc) { pr_err("%s: Failed to register auxiliary driver\n", ROCE_DRV_MODULE_NAME); - return rc; + goto err_debug; } return 0; +err_debug: + bnxt_re_unregister_debugfs(); + return rc; } static void __exit bnxt_re_mod_exit(void) { auxiliary_driver_unregister(&bnxt_re_driver); + bnxt_re_unregister_debugfs(); } module_init(bnxt_re_mod_init); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 7ad83566ab0f41..e42abf5be6c0f5 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -556,6 +556,7 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq, nq->pdev = pdev; nq->cqn_handler = cqn_handler; nq->srqn_handler = srqn_handler; + nq->load = 0; /* Have a task to schedule CQ notifiers in post send case */ nq->cqn_wq = create_singlethread_workqueue("bnxt_qplib_nq"); @@ -1282,12 +1283,47 @@ static void __filter_modify_flags(struct bnxt_qplib_qp *qp) } } +static void bnxt_set_mandatory_attributes(struct bnxt_qplib_qp *qp, + struct cmdq_modify_qp *req) +{ + u32 mandatory_flags = 0; + + if (qp->type == CMDQ_MODIFY_QP_QP_TYPE_RC) + mandatory_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_ACCESS; + + if (qp->cur_qp_state == CMDQ_MODIFY_QP_NEW_STATE_INIT && + qp->state == CMDQ_MODIFY_QP_NEW_STATE_RTR) { + if (qp->type == CMDQ_MODIFY_QP_QP_TYPE_RC && qp->srq) + req->flags = cpu_to_le16(CMDQ_MODIFY_QP_FLAGS_SRQ_USED); + mandatory_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_PKEY; + } + + if (qp->type == CMDQ_MODIFY_QP_QP_TYPE_UD || + qp->type == CMDQ_MODIFY_QP_QP_TYPE_GSI) + mandatory_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_QKEY; + + qp->modify_flags |= mandatory_flags; + req->qp_type = qp->type; +} + +static bool is_optimized_state_transition(struct bnxt_qplib_qp *qp) +{ + if ((qp->cur_qp_state == CMDQ_MODIFY_QP_NEW_STATE_INIT && + qp->state == CMDQ_MODIFY_QP_NEW_STATE_RTR) || + (qp->cur_qp_state == CMDQ_MODIFY_QP_NEW_STATE_RTR && + qp->state == CMDQ_MODIFY_QP_NEW_STATE_RTS)) + return true; + + return false; +} + int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) { struct bnxt_qplib_rcfw *rcfw = res->rcfw; struct creq_modify_qp_resp resp = {}; struct bnxt_qplib_cmdqmsg msg = {}; struct cmdq_modify_qp req = {}; + u16 vlan_pcp_vlan_dei_vlan_id; u32 temp32[4]; u32 bmask; int rc; @@ -1298,6 +1334,12 @@ int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) /* Filter out the qp_attr_mask based on the state->new transition */ __filter_modify_flags(qp); + if (qp->modify_flags & CMDQ_MODIFY_QP_MODIFY_MASK_STATE) { + /* Set mandatory attributes for INIT -> RTR and RTR -> RTS transition */ + if (_is_optimize_modify_qp_supported(res->dattr->dev_cap_flags2) && + is_optimized_state_transition(qp)) + bnxt_set_mandatory_attributes(qp, &req); + } bmask = qp->modify_flags; req.modify_mask = cpu_to_le32(qp->modify_flags); req.qp_cid = cpu_to_le32(qp->id); @@ -1378,7 +1420,16 @@ int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) if (bmask & CMDQ_MODIFY_QP_MODIFY_MASK_DEST_QP_ID) req.dest_qp_id = cpu_to_le32(qp->dest_qpn); - req.vlan_pcp_vlan_dei_vlan_id = cpu_to_le16(qp->vlan_id); + if (bmask & CMDQ_MODIFY_QP_MODIFY_MASK_VLAN_ID) { + vlan_pcp_vlan_dei_vlan_id = + ((res->sgid_tbl.tbl[qp->ah.sgid_index].vlan_id << + CMDQ_MODIFY_QP_VLAN_ID_SFT) & + CMDQ_MODIFY_QP_VLAN_ID_MASK); + vlan_pcp_vlan_dei_vlan_id |= + ((qp->ah.sl << CMDQ_MODIFY_QP_VLAN_PCP_SFT) & + CMDQ_MODIFY_QP_VLAN_PCP_MASK); + req.vlan_pcp_vlan_dei_vlan_id = cpu_to_le16(vlan_pcp_vlan_dei_vlan_id); + } bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); @@ -2151,6 +2202,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) struct bnxt_qplib_cmdqmsg msg = {}; struct cmdq_create_cq req = {}; struct bnxt_qplib_pbl *pbl; + u32 coalescing = 0; u32 pg_sz_lvl; int rc; @@ -2177,6 +2229,25 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq) req.dpi = cpu_to_le32(cq->dpi->dpi); req.cq_handle = cpu_to_le64(cq->cq_handle); req.cq_size = cpu_to_le32(cq->max_wqe); + + if (_is_cq_coalescing_supported(res->dattr->dev_cap_flags2)) { + req.flags |= cpu_to_le16(CMDQ_CREATE_CQ_FLAGS_COALESCING_VALID); + coalescing |= ((cq->coalescing->buf_maxtime << + CMDQ_CREATE_CQ_BUF_MAXTIME_SFT) & + CMDQ_CREATE_CQ_BUF_MAXTIME_MASK); + coalescing |= ((cq->coalescing->normal_maxbuf << + CMDQ_CREATE_CQ_NORMAL_MAXBUF_SFT) & + CMDQ_CREATE_CQ_NORMAL_MAXBUF_MASK); + coalescing |= ((cq->coalescing->during_maxbuf << + CMDQ_CREATE_CQ_DURING_MAXBUF_SFT) & + CMDQ_CREATE_CQ_DURING_MAXBUF_MASK); + if (cq->coalescing->en_ring_idle_mode) + coalescing |= CMDQ_CREATE_CQ_ENABLE_RING_IDLE_MODE; + else + coalescing &= ~CMDQ_CREATE_CQ_ENABLE_RING_IDLE_MODE; + req.coalescing = cpu_to_le32(coalescing); + } + pbl = &cq->hwq.pbl[PBL_LVL_0]; pg_sz_lvl = (bnxt_qplib_base_pg_size(&cq->hwq) << CMDQ_CREATE_CQ_PG_SIZE_SFT); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index 820611a239433a..ef3424c8134561 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -383,6 +383,25 @@ static inline bool bnxt_qplib_queue_full(struct bnxt_qplib_q *que, return avail <= slots; } +/* CQ coalescing parameters */ +struct bnxt_qplib_cq_coal_param { + u16 buf_maxtime; + u8 normal_maxbuf; + u8 during_maxbuf; + u8 en_ring_idle_mode; +}; + +#define BNXT_QPLIB_CQ_COAL_DEF_BUF_MAXTIME 0x1 +#define BNXT_QPLIB_CQ_COAL_DEF_NORMAL_MAXBUF_P7 0x8 +#define BNXT_QPLIB_CQ_COAL_DEF_DURING_MAXBUF_P7 0x8 +#define BNXT_QPLIB_CQ_COAL_DEF_NORMAL_MAXBUF_P5 0x1 +#define BNXT_QPLIB_CQ_COAL_DEF_DURING_MAXBUF_P5 0x1 +#define BNXT_QPLIB_CQ_COAL_DEF_EN_RING_IDLE_MODE 0x1 +#define BNXT_QPLIB_CQ_COAL_MAX_BUF_MAXTIME 0x1bf +#define BNXT_QPLIB_CQ_COAL_MAX_NORMAL_MAXBUF 0x1f +#define BNXT_QPLIB_CQ_COAL_MAX_DURING_MAXBUF 0x1f +#define BNXT_QPLIB_CQ_COAL_MAX_EN_RING_IDLE_MODE 0x1 + struct bnxt_qplib_cqe { u8 status; u8 type; @@ -391,7 +410,7 @@ struct bnxt_qplib_cqe { u16 cfa_meta; u64 wr_id; union { - __le32 immdata; + u32 immdata; u32 invrkey; }; u64 qp_handle; @@ -445,6 +464,7 @@ struct bnxt_qplib_cq { */ spinlock_t flush_lock; /* QP flush management */ u16 cnq_events; + struct bnxt_qplib_cq_coal_param *coalescing; }; #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq) @@ -499,6 +519,7 @@ struct bnxt_qplib_nq { struct tasklet_struct nq_tasklet; bool requested; int budget; + u32 load; cqn_handler_t cqn_handler; srqn_handler_t srqn_handler; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index e82bd37158ad6c..5e90ea232de802 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -831,6 +831,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, struct creq_initialize_fw_resp resp = {}; struct cmdq_initialize_fw req = {}; struct bnxt_qplib_cmdqmsg msg = {}; + u16 flags = 0; u8 pgsz, lvl; int rc; @@ -849,10 +850,8 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, * shall setup this area for VF. Skipping the * HW programming */ - if (is_virtfn) + if (is_virtfn || bnxt_qplib_is_chip_gen_p5_p7(rcfw->res->cctx)) goto skip_ctx_setup; - if (bnxt_qplib_is_chip_gen_p5_p7(rcfw->res->cctx)) - goto config_vf_res; lvl = ctx->qpc_tbl.level; pgsz = bnxt_qplib_base_pg_size(&ctx->qpc_tbl); @@ -896,16 +895,14 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, req.number_of_srq = cpu_to_le32(ctx->srqc_tbl.max_elements); req.number_of_cq = cpu_to_le32(ctx->cq_tbl.max_elements); -config_vf_res: - req.max_qp_per_vf = cpu_to_le32(ctx->vf_res.max_qp_per_vf); - req.max_mrw_per_vf = cpu_to_le32(ctx->vf_res.max_mrw_per_vf); - req.max_srq_per_vf = cpu_to_le32(ctx->vf_res.max_srq_per_vf); - 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); - skip_ctx_setup: if (BNXT_RE_HW_RETX(rcfw->res->dattr->dev_cap_flags)) - req.flags |= cpu_to_le16(CMDQ_INITIALIZE_FW_FLAGS_HW_REQUESTER_RETX_SUPPORTED); + flags |= CMDQ_INITIALIZE_FW_FLAGS_HW_REQUESTER_RETX_SUPPORTED; + if (_is_optimize_modify_qp_supported(rcfw->res->dattr->dev_cap_flags2)) + flags |= CMDQ_INITIALIZE_FW_FLAGS_OPTIMIZE_MODIFY_QP_SUPPORTED; + if (rcfw->res->en_dev->flags & BNXT_EN_FLAG_ROCE_VF_RES_MGMT) + flags |= CMDQ_INITIALIZE_FW_FLAGS_L2_VF_RESOURCE_MGMT; + req.flags |= cpu_to_le16(flags); req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id); bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h index 07779aeb75759d..88814cb3aa7413 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h @@ -131,6 +131,8 @@ static inline u32 bnxt_qplib_set_cmd_slots(struct cmdq_base *req) #define RCFW_CMD_IS_BLOCKING 0x8000 #define HWRM_VERSION_DEV_ATTR_MAX_DPI 0x1000A0000000DULL +/* HWRM version 1.10.3.18 */ +#define HWRM_VERSION_READ_CTX 0x1000A00030012 /* Crsq buf is 1024-Byte */ struct bnxt_qplib_crsbe { diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h index c2f710364e0ffe..21fb148713a6f9 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h @@ -39,6 +39,8 @@ #ifndef __BNXT_QPLIB_RES_H__ #define __BNXT_QPLIB_RES_H__ +#include "bnxt_ulp.h" + extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero; #define CHIP_NUM_57508 0x1750 @@ -302,6 +304,7 @@ struct bnxt_qplib_res { struct bnxt_qplib_chip_ctx *cctx; struct bnxt_qplib_dev_attr *dattr; struct net_device *netdev; + struct bnxt_en_dev *en_dev; struct bnxt_qplib_rcfw *rcfw; struct bnxt_qplib_pd_tbl pd_tbl; /* To protect the pd table bit map */ @@ -576,4 +579,14 @@ static inline bool _is_relaxed_ordering_supported(u16 dev_cap_ext_flags2) return dev_cap_ext_flags2 & CREQ_QUERY_FUNC_RESP_SB_MEMORY_REGION_RO_SUPPORTED; } +static inline bool _is_optimize_modify_qp_supported(u16 dev_cap_ext_flags2) +{ + return dev_cap_ext_flags2 & CREQ_QUERY_FUNC_RESP_SB_OPTIMIZE_MODIFY_QP_SUPPORTED; +} + +static inline bool _is_cq_coalescing_supported(u16 dev_cap_ext_flags2) +{ + return dev_cap_ext_flags2 & CREQ_QUERY_FUNC_RESP_SB_CQ_COALESCING_SUPPORTED; +} + #endif /* __BNXT_QPLIB_RES_H__ */ diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index e29fbbdab9fd68..7e20ae3d2c4fe1 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -981,3 +981,38 @@ int bnxt_qplib_modify_cc(struct bnxt_qplib_res *res, rc = bnxt_qplib_rcfw_send_message(res->rcfw, &msg); return rc; } + +int bnxt_qplib_read_context(struct bnxt_qplib_rcfw *rcfw, u8 res_type, + u32 xid, u32 resp_size, void *resp_va) +{ + struct creq_read_context resp = {}; + struct bnxt_qplib_cmdqmsg msg = {}; + struct cmdq_read_context req = {}; + struct bnxt_qplib_rcfw_sbuf sbuf; + int rc; + + sbuf.size = resp_size; + sbuf.sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf.size, + &sbuf.dma_addr, GFP_KERNEL); + if (!sbuf.sb) + return -ENOMEM; + + bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, + CMDQ_BASE_OPCODE_READ_CONTEXT, sizeof(req)); + req.resp_addr = cpu_to_le64(sbuf.dma_addr); + req.resp_size = resp_size / BNXT_QPLIB_CMDQE_UNITS; + + req.xid = cpu_to_le32(xid); + req.type = res_type; + + bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req), + sizeof(resp), 0); + rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); + if (rc) + goto free_mem; + + memcpy(resp_va, sbuf.sb, resp_size); +free_mem: + dma_free_coherent(&rcfw->pdev->dev, sbuf.size, sbuf.sb, sbuf.dma_addr); + return rc; +} diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h index ecf3f45fea74fe..e6beeb514b7dd8 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h @@ -353,6 +353,8 @@ 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); +int bnxt_qplib_read_context(struct bnxt_qplib_rcfw *rcfw, u8 type, u32 xid, + u32 resp_size, void *resp_va); #define BNXT_VAR_MAX_WQE 4352 #define BNXT_VAR_MAX_SLOT_ALIGN 256 diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h index 3ec895284e4931..a98fc9c2313e7e 100644 --- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h +++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h @@ -216,6 +216,8 @@ struct cmdq_initialize_fw { __le16 flags; #define CMDQ_INITIALIZE_FW_FLAGS_MRAV_RESERVATION_SPLIT 0x1UL #define CMDQ_INITIALIZE_FW_FLAGS_HW_REQUESTER_RETX_SUPPORTED 0x2UL + #define CMDQ_INITIALIZE_FW_FLAGS_OPTIMIZE_MODIFY_QP_SUPPORTED 0x8UL + #define CMDQ_INITIALIZE_FW_FLAGS_L2_VF_RESOURCE_MGMT 0x10UL __le16 cookie; u8 resp_size; u8 reserved8; @@ -559,6 +561,7 @@ struct cmdq_modify_qp { #define CMDQ_MODIFY_QP_OPCODE_LAST CMDQ_MODIFY_QP_OPCODE_MODIFY_QP u8 cmd_size; __le16 flags; + #define CMDQ_MODIFY_QP_FLAGS_SRQ_USED 0x1UL __le16 cookie; u8 resp_size; u8 qp_type; @@ -1137,6 +1140,7 @@ struct cmdq_create_cq { #define CMDQ_CREATE_CQ_FLAGS_DISABLE_CQ_OVERFLOW_DETECTION 0x1UL #define CMDQ_CREATE_CQ_FLAGS_STEERING_TAG_VALID 0x2UL #define CMDQ_CREATE_CQ_FLAGS_INFINITE_CQ_MODE 0x4UL + #define CMDQ_CREATE_CQ_FLAGS_COALESCING_VALID 0x8UL __le16 cookie; u8 resp_size; u8 reserved8; @@ -1169,7 +1173,18 @@ struct cmdq_create_cq { __le32 cq_size; __le64 pbl; __le16 steering_tag; - u8 reserved48[6]; + u8 reserved48[2]; + __le32 coalescing; + #define CMDQ_CREATE_CQ_BUF_MAXTIME_MASK 0x1ffUL + #define CMDQ_CREATE_CQ_BUF_MAXTIME_SFT 0 + #define CMDQ_CREATE_CQ_NORMAL_MAXBUF_MASK 0x3e00UL + #define CMDQ_CREATE_CQ_NORMAL_MAXBUF_SFT 9 + #define CMDQ_CREATE_CQ_DURING_MAXBUF_MASK 0x7c000UL + #define CMDQ_CREATE_CQ_DURING_MAXBUF_SFT 14 + #define CMDQ_CREATE_CQ_ENABLE_RING_IDLE_MODE 0x80000UL + #define CMDQ_CREATE_CQ_UNUSED12_MASK 0xfff00000UL + #define CMDQ_CREATE_CQ_UNUSED12_SFT 20 + __le64 reserved64; }; /* creq_create_cq_resp (size:128b/16B) */ @@ -2251,6 +2266,46 @@ struct creq_set_func_resources_resp { u8 reserved48[6]; }; +/* cmdq_read_context (size:192b/24B) */ +struct cmdq_read_context { + u8 opcode; + #define CMDQ_READ_CONTEXT_OPCODE_READ_CONTEXT 0x85UL + #define CMDQ_READ_CONTEXT_OPCODE_LAST CMDQ_READ_CONTEXT_OPCODE_READ_CONTEXT + u8 cmd_size; + __le16 flags; + __le16 cookie; + u8 resp_size; + u8 reserved8; + __le64 resp_addr; + __le32 xid; + u8 type; + #define CMDQ_READ_CONTEXT_TYPE_QPC 0x0UL + #define CMDQ_READ_CONTEXT_TYPE_CQ 0x1UL + #define CMDQ_READ_CONTEXT_TYPE_MRW 0x2UL + #define CMDQ_READ_CONTEXT_TYPE_SRQ 0x3UL + #define CMDQ_READ_CONTEXT_TYPE_LAST CMDQ_READ_CONTEXT_TYPE_SRQ + u8 unused_0[3]; +}; + +/* creq_read_context (size:128b/16B) */ +struct creq_read_context { + u8 type; + #define CREQ_READ_CONTEXT_TYPE_MASK 0x3fUL + #define CREQ_READ_CONTEXT_TYPE_SFT 0 + #define CREQ_READ_CONTEXT_TYPE_QP_EVENT 0x38UL + #define CREQ_READ_CONTEXT_TYPE_LAST CREQ_READ_CONTEXT_TYPE_QP_EVENT + u8 status; + __le16 cookie; + __le32 reserved32; + u8 v; + #define CREQ_READ_CONTEXT_V 0x1UL + u8 event; + #define CREQ_READ_CONTEXT_EVENT_READ_CONTEXT 0x85UL + #define CREQ_READ_CONTEXT_EVENT_LAST CREQ_READ_CONTEXT_EVENT_READ_CONTEXT + __le16 reserved16; + __le32 reserved_32; +}; + /* cmdq_map_tc_to_cos (size:192b/24B) */ struct cmdq_map_tc_to_cos { u8 opcode; diff --git a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h index cd03a5429beb52..fe0b6aec78397b 100644 --- a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h +++ b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h @@ -30,7 +30,8 @@ enum efa_admin_aq_opcode { EFA_ADMIN_DEALLOC_UAR = 17, EFA_ADMIN_CREATE_EQ = 18, EFA_ADMIN_DESTROY_EQ = 19, - EFA_ADMIN_MAX_OPCODE = 19, + EFA_ADMIN_ALLOC_MR = 20, + EFA_ADMIN_MAX_OPCODE = 20, }; enum efa_admin_aq_feature_id { @@ -150,8 +151,11 @@ struct efa_admin_create_qp_cmd { /* UAR number */ u16 uar; + /* Requested service level for the QP, 0 is the default SL */ + u8 sl; + /* MBZ */ - u16 reserved; + u8 reserved; /* MBZ */ u32 reserved2; @@ -459,6 +463,41 @@ struct efa_admin_dereg_mr_resp { struct efa_admin_acq_common_desc acq_common_desc; }; +/* + * Allocation of MemoryRegion, required for QP working with Virtual + * Addresses in kernel verbs semantics, ready for fast registration use. + */ +struct efa_admin_alloc_mr_cmd { + /* Common Admin Queue descriptor */ + struct efa_admin_aq_common_desc aq_common_desc; + + /* Protection Domain */ + u16 pd; + + /* MBZ */ + u16 reserved1; + + /* Maximum number of pages this MR supports. */ + u32 max_pages; +}; + +struct efa_admin_alloc_mr_resp { + /* Common Admin Queue completion descriptor */ + struct efa_admin_acq_common_desc acq_common_desc; + + /* + * L_Key, to be used in conjunction with local buffer references in + * SQ and RQ WQE, or with virtual RQ/CQ rings + */ + u32 l_key; + + /* + * R_Key, to be used in RDMA messages to refer to remotely accessed + * memory region + */ + u32 r_key; +}; + struct efa_admin_create_cq_cmd { struct efa_admin_aq_common_desc aq_common_desc; @@ -483,8 +522,8 @@ struct efa_admin_create_cq_cmd { */ u8 cq_caps_2; - /* completion queue depth in # of entries. must be power of 2 */ - u16 cq_depth; + /* Sub completion queue depth in # of entries. must be power of 2 */ + u16 sub_cq_depth; /* EQ number assigned to this cq */ u16 eqn; @@ -519,8 +558,8 @@ struct efa_admin_create_cq_resp { u16 cq_idx; - /* actual cq depth in number of entries */ - u16 cq_actual_depth; + /* actual sub cq depth in number of entries */ + u16 sub_cq_actual_depth; /* CQ doorbell address, as offset to PCIe DB BAR */ u32 db_offset; @@ -578,6 +617,8 @@ struct efa_admin_basic_stats { u64 rx_pkts; u64 rx_drops; + + u64 qkey_viol; }; struct efa_admin_messages_stats { @@ -677,6 +718,15 @@ struct efa_admin_feature_device_attr_desc { /* Unique global ID for an EFA device */ u64 guid; + + /* The device maximum link speed in Gbit/sec */ + u16 max_link_speed_gbps; + + /* MBZ */ + u16 reserved0; + + /* MBZ */ + u32 reserved1; }; struct efa_admin_feature_queue_attr_desc { @@ -1057,7 +1107,6 @@ struct efa_admin_host_info { /* create_eq_cmd */ #define EFA_ADMIN_CREATE_EQ_CMD_ENTRY_SIZE_WORDS_MASK GENMASK(4, 0) -#define EFA_ADMIN_CREATE_EQ_CMD_VIRT_MASK BIT(6) #define EFA_ADMIN_CREATE_EQ_CMD_COMPLETION_EVENTS_MASK BIT(0) /* host_info */ diff --git a/drivers/infiniband/hw/efa/efa_admin_defs.h b/drivers/infiniband/hw/efa/efa_admin_defs.h index 83f20c38a84008..35700c93e639e4 100644 --- a/drivers/infiniband/hw/efa/efa_admin_defs.h +++ b/drivers/infiniband/hw/efa/efa_admin_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-2024 Amazon.com, Inc. or its affiliates. All rights reserved. */ #ifndef _EFA_ADMIN_H_ @@ -96,7 +96,7 @@ struct efa_admin_acq_entry { struct efa_admin_aenq_common_desc { u16 group; - u16 syndrom; + u16 syndrome; /* * 0 : phase diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.c b/drivers/infiniband/hw/efa/efa_com_cmd.c index 5a774925cdea95..c6b89c45fdc9dc 100644 --- a/drivers/infiniband/hw/efa/efa_com_cmd.c +++ b/drivers/infiniband/hw/efa/efa_com_cmd.c @@ -31,6 +31,7 @@ int efa_com_create_qp(struct efa_com_dev *edev, create_qp_cmd.qp_alloc_size.recv_queue_depth = params->rq_depth; create_qp_cmd.uar = params->uarn; + create_qp_cmd.sl = params->sl; if (params->unsolicited_write_recv) EFA_SET(&create_qp_cmd.flags, EFA_ADMIN_CREATE_QP_CMD_UNSOLICITED_WRITE_RECV, 1); @@ -163,7 +164,7 @@ int efa_com_create_cq(struct efa_com_dev *edev, EFA_SET(&create_cmd.cq_caps_2, EFA_ADMIN_CREATE_CQ_CMD_CQ_ENTRY_SIZE_WORDS, params->entry_size_in_bytes / 4); - create_cmd.cq_depth = params->cq_depth; + create_cmd.sub_cq_depth = params->sub_cq_depth; create_cmd.num_sub_cqs = params->num_sub_cqs; create_cmd.uar = params->uarn; if (params->interrupt_mode_enabled) { @@ -191,7 +192,7 @@ int efa_com_create_cq(struct efa_com_dev *edev, } result->cq_idx = cmd_completion.cq_idx; - result->actual_depth = params->cq_depth; + result->actual_depth = params->sub_cq_depth; result->db_off = cmd_completion.db_offset; result->db_valid = EFA_GET(&cmd_completion.flags, EFA_ADMIN_CREATE_CQ_RESP_DB_VALID); @@ -466,6 +467,7 @@ int efa_com_get_device_attr(struct efa_com_dev *edev, result->max_rdma_size = resp.u.device_attr.max_rdma_size; result->device_caps = resp.u.device_attr.device_caps; result->guid = resp.u.device_attr.guid; + result->max_link_speed_gbps = resp.u.device_attr.max_link_speed_gbps; if (result->admin_api_version < 1) { ibdev_err_ratelimited( diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.h b/drivers/infiniband/hw/efa/efa_com_cmd.h index 668d033f747762..5511355b700d45 100644 --- a/drivers/infiniband/hw/efa/efa_com_cmd.h +++ b/drivers/infiniband/hw/efa/efa_com_cmd.h @@ -27,6 +27,7 @@ struct efa_com_create_qp_params { u16 pd; u16 uarn; u8 qp_type; + u8 sl; u8 unsolicited_write_recv : 1; }; @@ -71,7 +72,7 @@ struct efa_com_create_cq_params { /* cq physical base address in OS memory */ dma_addr_t dma_addr; /* completion queue depth in # of entries */ - u16 cq_depth; + u16 sub_cq_depth; u16 num_sub_cqs; u16 uarn; u16 eqn; @@ -141,6 +142,7 @@ struct efa_com_get_device_attr_result { u16 max_wr_rdma_sge; u16 max_tx_batch; u16 min_sq_depth; + u16 max_link_speed_gbps; u8 db_bar; }; diff --git a/drivers/infiniband/hw/efa/efa_io_defs.h b/drivers/infiniband/hw/efa/efa_io_defs.h index 2d8eb96eaa81be..a4c9fd33da386d 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-2023 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved. */ #ifndef _EFA_IO_H_ @@ -10,6 +10,7 @@ #define EFA_IO_TX_DESC_NUM_RDMA_BUFS 1 #define EFA_IO_TX_DESC_INLINE_MAX_SIZE 32 #define EFA_IO_TX_DESC_IMM_DATA_SIZE 4 +#define EFA_IO_TX_DESC_INLINE_PBL_SIZE 1 enum efa_io_queue_type { /* send queue (of a QP) */ @@ -25,6 +26,10 @@ enum efa_io_send_op_type { EFA_IO_RDMA_READ = 1, /* RDMA write */ EFA_IO_RDMA_WRITE = 2, + /* Fast MR registration */ + EFA_IO_FAST_REG = 3, + /* Fast MR invalidation */ + EFA_IO_FAST_INV = 4, }; enum efa_io_comp_status { @@ -34,15 +39,15 @@ enum efa_io_comp_status { EFA_IO_COMP_STATUS_FLUSHED = 1, /* Internal QP error */ EFA_IO_COMP_STATUS_LOCAL_ERROR_QP_INTERNAL_ERROR = 2, - /* Bad operation type */ - EFA_IO_COMP_STATUS_LOCAL_ERROR_INVALID_OP_TYPE = 3, + /* Unsupported operation */ + EFA_IO_COMP_STATUS_LOCAL_ERROR_UNSUPPORTED_OP = 3, /* Bad AH */ EFA_IO_COMP_STATUS_LOCAL_ERROR_INVALID_AH = 4, /* LKEY not registered or does not match IOVA */ EFA_IO_COMP_STATUS_LOCAL_ERROR_INVALID_LKEY = 5, /* Message too long */ EFA_IO_COMP_STATUS_LOCAL_ERROR_BAD_LENGTH = 6, - /* Destination ENI is down or does not run EFA */ + /* RKEY not registered or does not match remote IOVA */ EFA_IO_COMP_STATUS_REMOTE_ERROR_BAD_ADDRESS = 7, /* Connection was reset by remote side */ EFA_IO_COMP_STATUS_REMOTE_ERROR_ABORT = 8, @@ -54,8 +59,17 @@ enum efa_io_comp_status { EFA_IO_COMP_STATUS_REMOTE_ERROR_BAD_LENGTH = 11, /* Unexpected status returned by responder */ EFA_IO_COMP_STATUS_REMOTE_ERROR_BAD_STATUS = 12, - /* Unresponsive remote - detected locally */ + /* Unresponsive remote - was previously responsive */ EFA_IO_COMP_STATUS_LOCAL_ERROR_UNRESP_REMOTE = 13, + /* No valid AH at remote side (required for RDMA operations) */ + EFA_IO_COMP_STATUS_REMOTE_ERROR_UNKNOWN_PEER = 14, + /* Unreachable remote - never received a response */ + EFA_IO_COMP_STATUS_LOCAL_ERROR_UNREACH_REMOTE = 15, +}; + +enum efa_io_frwr_pbl_mode { + EFA_IO_FRWR_INLINE_PBL = 0, + EFA_IO_FRWR_DIRECT_PBL = 1, }; struct efa_io_tx_meta_desc { @@ -95,13 +109,13 @@ struct efa_io_tx_meta_desc { /* * If inline_msg bit is set, length of inline message in bytes, - * otherwise length of SGL (number of buffers). + * otherwise length of SGL (number of buffers). */ u16 length; /* - * immediate data: if has_imm is set, then this field is included - * within Tx message and reported in remote Rx completion. + * immediate data: if has_imm is set, then this field is included within + * Tx message and reported in remote Rx completion. */ u32 immediate_data; @@ -158,6 +172,63 @@ struct efa_io_rdma_req { struct efa_io_tx_buf_desc local_mem[1]; }; +struct efa_io_fast_mr_reg_req { + /* Updated local key of the MR after lkey/rkey increment */ + u32 lkey; + + /* + * permissions + * 0 : local_write_enable - Local write permissions: + * must be set for RQ buffers and buffers posted for + * RDMA Read requests + * 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 + */ + u8 permissions; + + /* + * control flags + * 4:0 : phys_page_size_shift - page size is (1 << + * phys_page_size_shift) + * 6:5 : pbl_mode - enum efa_io_frwr_pbl_mode + * 7 : reserved - MBZ + */ + u8 flags; + + /* MBZ */ + u8 reserved[2]; + + /* IO Virtual Address associated with this MR */ + u64 iova; + + /* Memory region length, in bytes */ + u64 mr_length; + + /* Physical Buffer List, each element is page-aligned. */ + union { + /* + * Inline array of physical page addresses (optimization + * for short region activation). + */ + u64 inline_array[1]; + + /* points to PBL (Currently only direct) */ + u64 dma_addr; + } pbl; +}; + +struct efa_io_fast_mr_inv_req { + /* Local key of the MR to invalidate */ + u32 lkey; + + /* MBZ */ + u8 reserved[28]; +}; + /* * Tx WQE, composed of tx meta descriptors followed by either tx buffer * descriptors or inline data @@ -174,6 +245,12 @@ struct efa_io_tx_wqe { /* RDMA local and remote memory addresses */ struct efa_io_rdma_req rdma_req; + + /* Fast registration */ + struct efa_io_fast_mr_reg_req reg_mr_req; + + /* Fast invalidation */ + struct efa_io_fast_mr_inv_req inv_mr_req; } data; }; @@ -208,7 +285,7 @@ struct efa_io_rx_desc { struct efa_io_cdesc_common { /* * verbs-generated request ID, as provided in the completed tx or rx - * descriptor. + * descriptor. */ u16 req_id; @@ -221,7 +298,8 @@ struct efa_io_cdesc_common { * 3 : has_imm - indicates that immediate data is * present - for RX completions only * 6:4 : op_type - enum efa_io_send_op_type - * 7 : reserved31 - MBZ + * 7 : unsolicited - indicates that there is no + * matching request - for RDMA with imm. RX only */ u8 flags; @@ -291,6 +369,13 @@ struct efa_io_rx_cdesc_ex { /* tx_buf_desc */ #define EFA_IO_TX_BUF_DESC_LKEY_MASK GENMASK(23, 0) +/* fast_mr_reg_req */ +#define EFA_IO_FAST_MR_REG_REQ_LOCAL_WRITE_ENABLE_MASK BIT(0) +#define EFA_IO_FAST_MR_REG_REQ_REMOTE_WRITE_ENABLE_MASK BIT(1) +#define EFA_IO_FAST_MR_REG_REQ_REMOTE_READ_ENABLE_MASK BIT(2) +#define EFA_IO_FAST_MR_REG_REQ_PHYS_PAGE_SIZE_SHIFT_MASK GENMASK(4, 0) +#define EFA_IO_FAST_MR_REG_REQ_PBL_MODE_MASK GENMASK(6, 5) + /* rx_desc */ #define EFA_IO_RX_DESC_LKEY_MASK GENMASK(23, 0) #define EFA_IO_RX_DESC_FIRST_MASK BIT(30) @@ -301,5 +386,6 @@ struct efa_io_rx_cdesc_ex { #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) +#define EFA_IO_CDESC_COMMON_UNSOLICITED_MASK BIT(7) #endif /* _EFA_IO_H_ */ diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c index cc13415ff7e70c..a8645a40730f31 100644 --- a/drivers/infiniband/hw/efa/efa_verbs.c +++ b/drivers/infiniband/hw/efa/efa_verbs.c @@ -85,6 +85,8 @@ static const struct rdma_stat_desc efa_port_stats_descs[] = { EFA_DEFINE_PORT_STATS(EFA_STATS_STR) }; +#define EFA_DEFAULT_LINK_SPEED_GBPS 100 + #define EFA_CHUNK_PAYLOAD_SHIFT 12 #define EFA_CHUNK_PAYLOAD_SIZE BIT(EFA_CHUNK_PAYLOAD_SHIFT) #define EFA_CHUNK_PAYLOAD_PTR_SIZE 8 @@ -277,10 +279,47 @@ int efa_query_device(struct ib_device *ibdev, return 0; } +static void efa_link_gbps_to_speed_and_width(u16 gbps, + enum ib_port_speed *speed, + enum ib_port_width *width) +{ + if (gbps >= 400) { + *width = IB_WIDTH_8X; + *speed = IB_SPEED_HDR; + } else if (gbps >= 200) { + *width = IB_WIDTH_4X; + *speed = IB_SPEED_HDR; + } else if (gbps >= 120) { + *width = IB_WIDTH_12X; + *speed = IB_SPEED_FDR10; + } else if (gbps >= 100) { + *width = IB_WIDTH_4X; + *speed = IB_SPEED_EDR; + } else if (gbps >= 60) { + *width = IB_WIDTH_12X; + *speed = IB_SPEED_DDR; + } else if (gbps >= 50) { + *width = IB_WIDTH_1X; + *speed = IB_SPEED_HDR; + } else if (gbps >= 40) { + *width = IB_WIDTH_4X; + *speed = IB_SPEED_FDR10; + } else if (gbps >= 30) { + *width = IB_WIDTH_12X; + *speed = IB_SPEED_SDR; + } else { + *width = IB_WIDTH_1X; + *speed = IB_SPEED_EDR; + } +} + int efa_query_port(struct ib_device *ibdev, u32 port, struct ib_port_attr *props) { struct efa_dev *dev = to_edev(ibdev); + enum ib_port_speed link_speed; + enum ib_port_width link_width; + u16 link_gbps; props->lmc = 1; @@ -288,8 +327,10 @@ int efa_query_port(struct ib_device *ibdev, u32 port, props->phys_state = IB_PORT_PHYS_STATE_LINK_UP; props->gid_tbl_len = 1; props->pkey_tbl_len = 1; - props->active_speed = IB_SPEED_EDR; - props->active_width = IB_WIDTH_4X; + link_gbps = dev->dev_attr.max_link_speed_gbps ?: EFA_DEFAULT_LINK_SPEED_GBPS; + efa_link_gbps_to_speed_and_width(link_gbps, &link_speed, &link_width); + props->active_speed = link_speed; + props->active_width = link_width; props->max_mtu = ib_mtu_int_to_enum(dev->dev_attr.mtu); props->active_mtu = ib_mtu_int_to_enum(dev->dev_attr.mtu); props->max_msg_sz = dev->dev_attr.mtu; @@ -676,7 +717,7 @@ int efa_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr, goto err_out; } - if (cmd.comp_mask || !is_reserved_cleared(cmd.reserved_90)) { + if (cmd.comp_mask || !is_reserved_cleared(cmd.reserved_98)) { ibdev_dbg(&dev->ibdev, "Incompatible ABI params, unknown fields in udata\n"); err = -EINVAL; @@ -732,6 +773,8 @@ int efa_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr, create_qp_params.rq_base_addr = qp->rq_dma_addr; } + create_qp_params.sl = cmd.sl; + if (cmd.flags & EFA_CREATE_QP_WITH_UNSOLICITED_WRITE_RECV) create_qp_params.unsolicited_write_recv = true; @@ -1167,7 +1210,7 @@ int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, } params.uarn = cq->ucontext->uarn; - params.cq_depth = entries; + params.sub_cq_depth = entries; params.dma_addr = cq->dma_addr; params.entry_size_in_bytes = cmd.cq_entry_size; params.num_sub_cqs = cmd.num_sub_cqs; diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index c52e6b2c9914d3..a442eca498b8de 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -13235,7 +13235,7 @@ int set_intr_bits(struct hfi1_devdata *dd, u16 first, u16 last, bool set) /* * Clear all interrupt sources on the chip. */ -void clear_all_interrupts(struct hfi1_devdata *dd) +static void clear_all_interrupts(struct hfi1_devdata *dd) { int i; diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h index d861aa8fc64044..8841db16bde7e7 100644 --- a/drivers/infiniband/hw/hfi1/chip.h +++ b/drivers/infiniband/hw/hfi1/chip.h @@ -1404,7 +1404,6 @@ irqreturn_t receive_context_interrupt_napi(int irq, void *data); int set_intr_bits(struct hfi1_devdata *dd, u16 first, u16 last, bool set); void init_qsfp_int(struct hfi1_devdata *dd); -void clear_all_interrupts(struct hfi1_devdata *dd); void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr); void remap_sdma_interrupts(struct hfi1_devdata *dd, int engine, int msix_intr); void reset_interrupts(struct hfi1_devdata *dd); diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 4ec66611a14340..4106423a1b399d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -179,8 +179,8 @@ static void free_cqc(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_CQC, hr_cq->cqn); if (ret) - dev_err(dev, "DESTROY_CQ failed (%d) for CQN %06lx\n", ret, - hr_cq->cqn); + dev_err_ratelimited(dev, "DESTROY_CQ failed (%d) for CQN %06lx\n", + ret, hr_cq->cqn); xa_erase_irq(&cq_table->array, hr_cq->cqn); diff --git a/drivers/infiniband/hw/hns/hns_roce_debugfs.c b/drivers/infiniband/hw/hns/hns_roce_debugfs.c index e8febb40f6450c..b869cdc5411893 100644 --- a/drivers/infiniband/hw/hns/hns_roce_debugfs.c +++ b/drivers/infiniband/hw/hns/hns_roce_debugfs.c @@ -5,6 +5,7 @@ #include #include +#include #include "hns_roce_device.h" @@ -86,7 +87,7 @@ void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev) { struct hns_roce_dev_debugfs *dbgfs = &hr_dev->dbgfs; - dbgfs->root = debugfs_create_dir(dev_name(&hr_dev->ib_dev.dev), + dbgfs->root = debugfs_create_dir(pci_name(hr_dev->pci_dev), hns_roce_dbgfs_root); create_sw_stat_debugfs(hr_dev, dbgfs->root); diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 0b1e21cb6d2d38..560a1d9de408ff 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -489,12 +489,6 @@ struct hns_roce_bank { u32 next; /* Next ID to allocate. */ }; -struct hns_roce_idx_table { - u32 *spare_idx; - u32 head; - u32 tail; -}; - struct hns_roce_qp_table { struct hns_roce_hem_table qp_table; struct hns_roce_hem_table irrl_table; @@ -503,7 +497,7 @@ struct hns_roce_qp_table { struct mutex scc_mutex; struct hns_roce_bank bank[HNS_ROCE_QP_BANK_NUM]; struct mutex bank_mutex; - struct hns_roce_idx_table idx_table; + struct xarray dip_xa; }; struct hns_roce_cq_table { @@ -593,6 +587,7 @@ struct hns_roce_dev; enum { HNS_ROCE_FLUSH_FLAG = 0, + HNS_ROCE_STOP_FLUSH_FLAG = 1, }; struct hns_roce_work { @@ -656,6 +651,8 @@ struct hns_roce_qp { enum hns_roce_cong_type cong_type; u8 tc_mode; u8 priority; + spinlock_t flush_lock; + struct hns_roce_dip *dip; }; struct hns_roce_ib_iboe { @@ -982,8 +979,6 @@ struct hns_roce_dev { enum hns_roce_device_state state; struct list_head qp_list; /* list of all qps on this dev */ spinlock_t qp_list_lock; /* protect qp_list */ - struct list_head dip_list; /* list of all dest ips on this dev */ - spinlock_t dip_list_lock; /* protect dip_list */ struct list_head pgdir_list; struct mutex pgdir_mutex; @@ -1289,6 +1284,7 @@ void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn); void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type); void flush_cqe(struct hns_roce_dev *dev, struct hns_roce_qp *qp); void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type); +void hns_roce_flush_cqe(struct hns_roce_dev *hr_dev, u32 qpn); void hns_roce_srq_event(struct hns_roce_dev *hr_dev, u32 srqn, int event_type); void hns_roce_handle_device_err(struct hns_roce_dev *hr_dev); int hns_roce_init(struct hns_roce_dev *hr_dev); diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c index c7c167e2a04513..f84521be3bea4a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hem.c +++ b/drivers/infiniband/hw/hns/hns_roce_hem.c @@ -300,7 +300,7 @@ static int calc_hem_config(struct hns_roce_dev *hr_dev, struct hns_roce_hem_mhop *mhop, struct hns_roce_hem_index *index) { - struct ib_device *ibdev = &hr_dev->ib_dev; + struct device *dev = hr_dev->dev; unsigned long mhop_obj = obj; u32 l0_idx, l1_idx, l2_idx; u32 chunk_ba_num; @@ -331,14 +331,14 @@ static int calc_hem_config(struct hns_roce_dev *hr_dev, index->buf = l0_idx; break; default: - ibdev_err(ibdev, "table %u not support mhop.hop_num = %u!\n", - table->type, mhop->hop_num); + dev_err(dev, "table %u not support mhop.hop_num = %u!\n", + table->type, mhop->hop_num); return -EINVAL; } if (unlikely(index->buf >= table->num_hem)) { - ibdev_err(ibdev, "table %u exceed hem limt idx %llu, max %lu!\n", - table->type, index->buf, table->num_hem); + dev_err(dev, "table %u exceed hem limt idx %llu, max %lu!\n", + table->type, index->buf, table->num_hem); return -EINVAL; } @@ -448,14 +448,14 @@ static int set_mhop_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem_mhop *mhop, struct hns_roce_hem_index *index) { - struct ib_device *ibdev = &hr_dev->ib_dev; + struct device *dev = hr_dev->dev; u32 step_idx; int ret = 0; if (index->inited & HEM_INDEX_L0) { ret = hr_dev->hw->set_hem(hr_dev, table, obj, 0); if (ret) { - ibdev_err(ibdev, "set HEM step 0 failed!\n"); + dev_err(dev, "set HEM step 0 failed!\n"); goto out; } } @@ -463,7 +463,7 @@ static int set_mhop_hem(struct hns_roce_dev *hr_dev, if (index->inited & HEM_INDEX_L1) { ret = hr_dev->hw->set_hem(hr_dev, table, obj, 1); if (ret) { - ibdev_err(ibdev, "set HEM step 1 failed!\n"); + dev_err(dev, "set HEM step 1 failed!\n"); goto out; } } @@ -475,7 +475,7 @@ static int set_mhop_hem(struct hns_roce_dev *hr_dev, step_idx = mhop->hop_num; ret = hr_dev->hw->set_hem(hr_dev, table, obj, step_idx); if (ret) - ibdev_err(ibdev, "set HEM step last failed!\n"); + dev_err(dev, "set HEM step last failed!\n"); } out: return ret; @@ -485,14 +485,14 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev, struct hns_roce_hem_table *table, unsigned long obj) { - struct ib_device *ibdev = &hr_dev->ib_dev; struct hns_roce_hem_index index = {}; struct hns_roce_hem_mhop mhop = {}; + struct device *dev = hr_dev->dev; int ret; ret = calc_hem_config(hr_dev, table, obj, &mhop, &index); if (ret) { - ibdev_err(ibdev, "calc hem config failed!\n"); + dev_err(dev, "calc hem config failed!\n"); return ret; } @@ -504,7 +504,7 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev, ret = alloc_mhop_hem(hr_dev, table, &mhop, &index); if (ret) { - ibdev_err(ibdev, "alloc mhop hem failed!\n"); + dev_err(dev, "alloc mhop hem failed!\n"); goto out; } @@ -512,7 +512,7 @@ static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev, if (table->type < HEM_TYPE_MTT) { ret = set_mhop_hem(hr_dev, table, obj, &mhop, &index); if (ret) { - ibdev_err(ibdev, "set HEM address to HW failed!\n"); + dev_err(dev, "set HEM address to HW failed!\n"); goto err_alloc; } } @@ -575,7 +575,7 @@ static void clear_mhop_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem_mhop *mhop, struct hns_roce_hem_index *index) { - struct ib_device *ibdev = &hr_dev->ib_dev; + struct device *dev = hr_dev->dev; u32 hop_num = mhop->hop_num; u32 chunk_ba_num; u32 step_idx; @@ -605,21 +605,21 @@ static void clear_mhop_hem(struct hns_roce_dev *hr_dev, ret = hr_dev->hw->clear_hem(hr_dev, table, obj, step_idx); if (ret) - ibdev_warn(ibdev, "failed to clear hop%u HEM, ret = %d.\n", - hop_num, ret); + dev_warn(dev, "failed to clear hop%u HEM, ret = %d.\n", + hop_num, ret); if (index->inited & HEM_INDEX_L1) { ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 1); if (ret) - ibdev_warn(ibdev, "failed to clear HEM step 1, ret = %d.\n", - ret); + dev_warn(dev, "failed to clear HEM step 1, ret = %d.\n", + ret); } if (index->inited & HEM_INDEX_L0) { ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 0); if (ret) - ibdev_warn(ibdev, "failed to clear HEM step 0, ret = %d.\n", - ret); + dev_warn(dev, "failed to clear HEM step 0, ret = %d.\n", + ret); } } } @@ -629,14 +629,14 @@ static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev, unsigned long obj, int check_refcount) { - struct ib_device *ibdev = &hr_dev->ib_dev; struct hns_roce_hem_index index = {}; struct hns_roce_hem_mhop mhop = {}; + struct device *dev = hr_dev->dev; int ret; ret = calc_hem_config(hr_dev, table, obj, &mhop, &index); if (ret) { - ibdev_err(ibdev, "calc hem config failed!\n"); + dev_err(dev, "calc hem config failed!\n"); return; } @@ -672,8 +672,8 @@ void hns_roce_table_put(struct hns_roce_dev *hr_dev, ret = hr_dev->hw->clear_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT); if (ret) - dev_warn(dev, "failed to clear HEM base address, ret = %d.\n", - ret); + dev_warn_ratelimited(dev, "failed to clear HEM base address, ret = %d.\n", + ret); hns_roce_free_hem(hr_dev, table->hem[i]); table->hem[i] = NULL; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c index 24e906b9d3ae13..697b17cca02e71 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c @@ -373,19 +373,12 @@ static int set_rwqe_data_seg(struct ib_qp *ibqp, const struct ib_send_wr *wr, static int check_send_valid(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) { - struct ib_device *ibdev = &hr_dev->ib_dev; - if (unlikely(hr_qp->state == IB_QPS_RESET || hr_qp->state == IB_QPS_INIT || - hr_qp->state == IB_QPS_RTR)) { - ibdev_err(ibdev, "failed to post WQE, QP state %u!\n", - hr_qp->state); + hr_qp->state == IB_QPS_RTR)) return -EINVAL; - } else if (unlikely(hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN)) { - ibdev_err(ibdev, "failed to post WQE, dev state %d!\n", - hr_dev->state); + else if (unlikely(hr_dev->state >= HNS_ROCE_DEVICE_STATE_RST_DOWN)) return -EIO; - } return 0; } @@ -582,7 +575,7 @@ static inline int set_rc_wqe(struct hns_roce_qp *qp, if (WARN_ON(ret)) return ret; - hr_reg_write(rc_sq_wqe, RC_SEND_WQE_FENCE, + hr_reg_write(rc_sq_wqe, RC_SEND_WQE_SO, (wr->send_flags & IB_SEND_FENCE) ? 1 : 0); hr_reg_write(rc_sq_wqe, RC_SEND_WQE_SE, @@ -2560,20 +2553,19 @@ static void hns_roce_free_link_table(struct hns_roce_dev *hr_dev) free_link_table_buf(hr_dev, &priv->ext_llm); } -static void free_dip_list(struct hns_roce_dev *hr_dev) +static void free_dip_entry(struct hns_roce_dev *hr_dev) { struct hns_roce_dip *hr_dip; - struct hns_roce_dip *tmp; - unsigned long flags; + unsigned long idx; - spin_lock_irqsave(&hr_dev->dip_list_lock, flags); + xa_lock(&hr_dev->qp_table.dip_xa); - list_for_each_entry_safe(hr_dip, tmp, &hr_dev->dip_list, node) { - list_del(&hr_dip->node); + xa_for_each(&hr_dev->qp_table.dip_xa, idx, hr_dip) { + __xa_erase(&hr_dev->qp_table.dip_xa, hr_dip->dip_idx); kfree(hr_dip); } - spin_unlock_irqrestore(&hr_dev->dip_list_lock, flags); + xa_unlock(&hr_dev->qp_table.dip_xa); } static struct ib_pd *free_mr_init_pd(struct hns_roce_dev *hr_dev) @@ -2775,8 +2767,8 @@ static int free_mr_modify_rsv_qp(struct hns_roce_dev *hr_dev, ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, attr, mask, IB_QPS_INIT, IB_QPS_INIT, NULL); if (ret) { - ibdev_err(ibdev, "failed to modify qp to init, ret = %d.\n", - ret); + ibdev_err_ratelimited(ibdev, "failed to modify qp to init, ret = %d.\n", + ret); return ret; } @@ -2981,7 +2973,7 @@ static void hns_roce_v2_exit(struct hns_roce_dev *hr_dev) hns_roce_free_link_table(hr_dev); if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP09) - free_dip_list(hr_dev); + free_dip_entry(hr_dev); } static int hns_roce_mbox_post(struct hns_roce_dev *hr_dev, @@ -3421,8 +3413,8 @@ static int free_mr_post_send_lp_wqe(struct hns_roce_qp *hr_qp) ret = hns_roce_v2_post_send(&hr_qp->ibqp, send_wr, &bad_wr); if (ret) { - ibdev_err(ibdev, "failed to post wqe for free mr, ret = %d.\n", - ret); + ibdev_err_ratelimited(ibdev, "failed to post wqe for free mr, ret = %d.\n", + ret); return ret; } @@ -3461,9 +3453,9 @@ static void free_mr_send_cmd_to_hw(struct hns_roce_dev *hr_dev) ret = free_mr_post_send_lp_wqe(hr_qp); if (ret) { - ibdev_err(ibdev, - "failed to send wqe (qp:0x%lx) for free mr, ret = %d.\n", - hr_qp->qpn, ret); + ibdev_err_ratelimited(ibdev, + "failed to send wqe (qp:0x%lx) for free mr, ret = %d.\n", + hr_qp->qpn, ret); break; } @@ -3474,16 +3466,16 @@ static void free_mr_send_cmd_to_hw(struct hns_roce_dev *hr_dev) while (cqe_cnt) { npolled = hns_roce_v2_poll_cq(&free_mr->rsv_cq->ib_cq, cqe_cnt, wc); if (npolled < 0) { - ibdev_err(ibdev, - "failed to poll cqe for free mr, remain %d cqe.\n", - cqe_cnt); + ibdev_err_ratelimited(ibdev, + "failed to poll cqe for free mr, remain %d cqe.\n", + cqe_cnt); goto out; } if (time_after(jiffies, end)) { - ibdev_err(ibdev, - "failed to poll cqe for free mr and timeout, remain %d cqe.\n", - cqe_cnt); + ibdev_err_ratelimited(ibdev, + "failed to poll cqe for free mr and timeout, remain %d cqe.\n", + cqe_cnt); goto out; } cqe_cnt -= npolled; @@ -4701,26 +4693,49 @@ static int modify_qp_rtr_to_rts(struct ib_qp *ibqp, int attr_mask, return 0; } +static int alloc_dip_entry(struct xarray *dip_xa, u32 qpn) +{ + struct hns_roce_dip *hr_dip; + int ret; + + hr_dip = xa_load(dip_xa, qpn); + if (hr_dip) + return 0; + + hr_dip = kzalloc(sizeof(*hr_dip), GFP_KERNEL); + if (!hr_dip) + return -ENOMEM; + + ret = xa_err(xa_store(dip_xa, qpn, hr_dip, GFP_KERNEL)); + if (ret) + kfree(hr_dip); + + return ret; +} + static int get_dip_ctx_idx(struct ib_qp *ibqp, const struct ib_qp_attr *attr, u32 *dip_idx) { const struct ib_global_route *grh = rdma_ah_read_grh(&attr->ah_attr); struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); - u32 *spare_idx = hr_dev->qp_table.idx_table.spare_idx; - u32 *head = &hr_dev->qp_table.idx_table.head; - u32 *tail = &hr_dev->qp_table.idx_table.tail; + struct xarray *dip_xa = &hr_dev->qp_table.dip_xa; + struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); struct hns_roce_dip *hr_dip; - unsigned long flags; + unsigned long idx; int ret = 0; - spin_lock_irqsave(&hr_dev->dip_list_lock, flags); + ret = alloc_dip_entry(dip_xa, ibqp->qp_num); + if (ret) + return ret; - spare_idx[*tail] = ibqp->qp_num; - *tail = (*tail == hr_dev->caps.num_qps - 1) ? 0 : (*tail + 1); + xa_lock(dip_xa); - list_for_each_entry(hr_dip, &hr_dev->dip_list, node) { - if (!memcmp(grh->dgid.raw, hr_dip->dgid, GID_LEN_V2)) { + xa_for_each(dip_xa, idx, hr_dip) { + if (hr_dip->qp_cnt && + !memcmp(grh->dgid.raw, hr_dip->dgid, GID_LEN_V2)) { *dip_idx = hr_dip->dip_idx; + hr_dip->qp_cnt++; + hr_qp->dip = hr_dip; goto out; } } @@ -4728,19 +4743,24 @@ static int get_dip_ctx_idx(struct ib_qp *ibqp, const struct ib_qp_attr *attr, /* If no dgid is found, a new dip and a mapping between dgid and * dip_idx will be created. */ - hr_dip = kzalloc(sizeof(*hr_dip), GFP_ATOMIC); - if (!hr_dip) { - ret = -ENOMEM; - goto out; + xa_for_each(dip_xa, idx, hr_dip) { + if (hr_dip->qp_cnt) + continue; + + *dip_idx = idx; + memcpy(hr_dip->dgid, grh->dgid.raw, sizeof(grh->dgid.raw)); + hr_dip->dip_idx = idx; + hr_dip->qp_cnt++; + hr_qp->dip = hr_dip; + break; } - memcpy(hr_dip->dgid, grh->dgid.raw, sizeof(grh->dgid.raw)); - hr_dip->dip_idx = *dip_idx = spare_idx[*head]; - *head = (*head == hr_dev->caps.num_qps - 1) ? 0 : (*head + 1); - list_add_tail(&hr_dip->node, &hr_dev->dip_list); + /* This should never happen. */ + if (WARN_ON_ONCE(!hr_qp->dip)) + ret = -ENOSPC; out: - spin_unlock_irqrestore(&hr_dev->dip_list_lock, flags); + xa_unlock(dip_xa); return ret; } @@ -5061,10 +5081,8 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp, struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); int ret = 0; - if (!check_qp_state(cur_state, new_state)) { - ibdev_err(&hr_dev->ib_dev, "Illegal state for QP!\n"); + if (!check_qp_state(cur_state, new_state)) return -EINVAL; - } if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { memset(qpc_mask, 0, hr_dev->caps.qpc_sz); @@ -5325,7 +5343,7 @@ static int hns_roce_v2_modify_qp(struct ib_qp *ibqp, /* SW pass context to HW */ ret = hns_roce_v2_qp_modify(hr_dev, context, qpc_mask, hr_qp); if (ret) { - ibdev_err(ibdev, "failed to modify QP, ret = %d.\n", ret); + ibdev_err_ratelimited(ibdev, "failed to modify QP, ret = %d.\n", ret); goto out; } @@ -5463,7 +5481,9 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, ret = hns_roce_v2_query_qpc(hr_dev, hr_qp->qpn, &context); if (ret) { - ibdev_err(ibdev, "failed to query QPC, ret = %d.\n", ret); + ibdev_err_ratelimited(ibdev, + "failed to query QPC, ret = %d.\n", + ret); ret = -EINVAL; goto out; } @@ -5471,7 +5491,7 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, state = hr_reg_read(&context, QPC_QP_ST); tmp_qp_state = to_ib_qp_st((enum hns_roce_v2_qp_state)state); if (tmp_qp_state == -1) { - ibdev_err(ibdev, "Illegal ib_qp_state\n"); + ibdev_err_ratelimited(ibdev, "Illegal ib_qp_state\n"); ret = -EINVAL; goto out; } @@ -5564,9 +5584,9 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev, ret = hns_roce_v2_modify_qp(&hr_qp->ibqp, NULL, 0, hr_qp->state, IB_QPS_RESET, udata); if (ret) - ibdev_err(ibdev, - "failed to modify QP to RST, ret = %d.\n", - ret); + ibdev_err_ratelimited(ibdev, + "failed to modify QP to RST, ret = %d.\n", + ret); } send_cq = hr_qp->ibqp.send_cq ? to_hr_cq(hr_qp->ibqp.send_cq) : NULL; @@ -5594,17 +5614,41 @@ static int hns_roce_v2_destroy_qp_common(struct hns_roce_dev *hr_dev, return ret; } +static void put_dip_ctx_idx(struct hns_roce_dev *hr_dev, + struct hns_roce_qp *hr_qp) +{ + struct hns_roce_dip *hr_dip = hr_qp->dip; + + xa_lock(&hr_dev->qp_table.dip_xa); + + hr_dip->qp_cnt--; + if (!hr_dip->qp_cnt) + memset(hr_dip->dgid, 0, GID_LEN_V2); + + xa_unlock(&hr_dev->qp_table.dip_xa); +} + int hns_roce_v2_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) { struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); + unsigned long flags; int ret; + /* Make sure flush_cqe() is completed */ + spin_lock_irqsave(&hr_qp->flush_lock, flags); + set_bit(HNS_ROCE_STOP_FLUSH_FLAG, &hr_qp->flush_flag); + spin_unlock_irqrestore(&hr_qp->flush_lock, flags); + flush_work(&hr_qp->flush_work.work); + + if (hr_qp->cong_type == CONG_TYPE_DIP) + put_dip_ctx_idx(hr_dev, hr_qp); + ret = hns_roce_v2_destroy_qp_common(hr_dev, hr_qp, udata); if (ret) - ibdev_err(&hr_dev->ib_dev, - "failed to destroy QP, QPN = 0x%06lx, ret = %d.\n", - hr_qp->qpn, ret); + ibdev_err_ratelimited(&hr_dev->ib_dev, + "failed to destroy QP, QPN = 0x%06lx, ret = %d.\n", + hr_qp->qpn, ret); hns_roce_qp_destroy(hr_dev, hr_qp, udata); @@ -5898,9 +5942,9 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) HNS_ROCE_CMD_MODIFY_CQC, hr_cq->cqn); hns_roce_free_cmd_mailbox(hr_dev, mailbox); if (ret) - ibdev_err(&hr_dev->ib_dev, - "failed to process cmd when modifying CQ, ret = %d.\n", - ret); + ibdev_err_ratelimited(&hr_dev->ib_dev, + "failed to process cmd when modifying CQ, ret = %d.\n", + ret); err_out: if (ret) @@ -5924,9 +5968,9 @@ static int hns_roce_v2_query_cqc(struct hns_roce_dev *hr_dev, u32 cqn, ret = hns_roce_cmd_mbox(hr_dev, 0, mailbox->dma, HNS_ROCE_CMD_QUERY_CQC, cqn); if (ret) { - ibdev_err(&hr_dev->ib_dev, - "failed to process cmd when querying CQ, ret = %d.\n", - ret); + ibdev_err_ratelimited(&hr_dev->ib_dev, + "failed to process cmd when querying CQ, ret = %d.\n", + ret); goto err_mailbox; } @@ -5967,11 +6011,10 @@ static int hns_roce_v2_query_mpt(struct hns_roce_dev *hr_dev, u32 key, return ret; } -static void hns_roce_irq_work_handle(struct work_struct *work) +static void dump_aeqe_log(struct hns_roce_work *irq_work) { - struct hns_roce_work *irq_work = - container_of(work, struct hns_roce_work, work); - struct ib_device *ibdev = &irq_work->hr_dev->ib_dev; + struct hns_roce_dev *hr_dev = irq_work->hr_dev; + struct ib_device *ibdev = &hr_dev->ib_dev; switch (irq_work->event_type) { case HNS_ROCE_EVENT_TYPE_PATH_MIG: @@ -6015,6 +6058,8 @@ static void hns_roce_irq_work_handle(struct work_struct *work) case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW: ibdev_warn(ibdev, "DB overflow.\n"); break; + case HNS_ROCE_EVENT_TYPE_MB: + break; case HNS_ROCE_EVENT_TYPE_FLR: ibdev_warn(ibdev, "function level reset.\n"); break; @@ -6025,8 +6070,46 @@ static void hns_roce_irq_work_handle(struct work_struct *work) ibdev_err(ibdev, "invalid xrceth error.\n"); break; default: + ibdev_info(ibdev, "Undefined event %d.\n", + irq_work->event_type); break; } +} + +static void hns_roce_irq_work_handle(struct work_struct *work) +{ + struct hns_roce_work *irq_work = + container_of(work, struct hns_roce_work, work); + struct hns_roce_dev *hr_dev = irq_work->hr_dev; + int event_type = irq_work->event_type; + u32 queue_num = irq_work->queue_num; + + switch (event_type) { + case HNS_ROCE_EVENT_TYPE_PATH_MIG: + case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED: + case HNS_ROCE_EVENT_TYPE_COMM_EST: + case HNS_ROCE_EVENT_TYPE_SQ_DRAINED: + case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: + case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH: + case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: + case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: + case HNS_ROCE_EVENT_TYPE_XRCD_VIOLATION: + case HNS_ROCE_EVENT_TYPE_INVALID_XRCETH: + hns_roce_qp_event(hr_dev, queue_num, event_type); + break; + case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH: + case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR: + hns_roce_srq_event(hr_dev, queue_num, event_type); + break; + case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: + case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: + hns_roce_cq_event(hr_dev, queue_num, event_type); + break; + default: + break; + } + + dump_aeqe_log(irq_work); kfree(irq_work); } @@ -6087,14 +6170,14 @@ static struct hns_roce_aeqe *next_aeqe_sw_v2(struct hns_roce_eq *eq) static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, struct hns_roce_eq *eq) { - struct device *dev = hr_dev->dev; struct hns_roce_aeqe *aeqe = next_aeqe_sw_v2(eq); irqreturn_t aeqe_found = IRQ_NONE; + int num_aeqes = 0; int event_type; u32 queue_num; int sub_type; - while (aeqe) { + while (aeqe && num_aeqes < HNS_AEQ_POLLING_BUDGET) { /* Make sure we read AEQ entry after we have checked the * ownership bit */ @@ -6105,25 +6188,12 @@ static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, queue_num = hr_reg_read(aeqe, AEQE_EVENT_QUEUE_NUM); switch (event_type) { - case HNS_ROCE_EVENT_TYPE_PATH_MIG: - case HNS_ROCE_EVENT_TYPE_PATH_MIG_FAILED: - case HNS_ROCE_EVENT_TYPE_COMM_EST: - case HNS_ROCE_EVENT_TYPE_SQ_DRAINED: case HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR: - case HNS_ROCE_EVENT_TYPE_SRQ_LAST_WQE_REACH: case HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR: case HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR: case HNS_ROCE_EVENT_TYPE_XRCD_VIOLATION: case HNS_ROCE_EVENT_TYPE_INVALID_XRCETH: - hns_roce_qp_event(hr_dev, queue_num, event_type); - break; - case HNS_ROCE_EVENT_TYPE_SRQ_LIMIT_REACH: - case HNS_ROCE_EVENT_TYPE_SRQ_CATAS_ERROR: - hns_roce_srq_event(hr_dev, queue_num, event_type); - break; - case HNS_ROCE_EVENT_TYPE_CQ_ACCESS_ERROR: - case HNS_ROCE_EVENT_TYPE_CQ_OVERFLOW: - hns_roce_cq_event(hr_dev, queue_num, event_type); + hns_roce_flush_cqe(hr_dev, queue_num); break; case HNS_ROCE_EVENT_TYPE_MB: hns_roce_cmd_event(hr_dev, @@ -6131,12 +6201,7 @@ static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, aeqe->event.cmd.status, le64_to_cpu(aeqe->event.cmd.out_param)); break; - case HNS_ROCE_EVENT_TYPE_DB_OVERFLOW: - case HNS_ROCE_EVENT_TYPE_FLR: - break; default: - dev_err(dev, "unhandled event %d on EQ %d at idx %u.\n", - event_type, eq->eqn, eq->cons_index); break; } @@ -6150,6 +6215,7 @@ static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev, hns_roce_v2_init_irq_work(hr_dev, eq, queue_num); aeqe = next_aeqe_sw_v2(eq); + ++num_aeqes; } update_eq_db(eq); @@ -6699,6 +6765,9 @@ static int hns_roce_v2_init_eq_table(struct hns_roce_dev *hr_dev) int ret; int i; + if (hr_dev->caps.aeqe_depth < HNS_AEQ_POLLING_BUDGET) + return -EINVAL; + other_num = hr_dev->caps.num_other_vectors; comp_num = hr_dev->caps.num_comp_vectors; aeq_num = hr_dev->caps.num_aeq_vectors; @@ -7017,6 +7086,7 @@ static void hns_roce_hw_v2_uninit_instance(struct hnae3_handle *handle, handle->rinfo.instance_state = HNS_ROCE_STATE_NON_INIT; } + static int hns_roce_hw_v2_reset_notify_down(struct hnae3_handle *handle) { struct hns_roce_dev *hr_dev; @@ -7035,6 +7105,9 @@ static int hns_roce_hw_v2_reset_notify_down(struct hnae3_handle *handle) hr_dev->active = false; hr_dev->dis_db = true; + + rdma_user_mmap_disassociate(&hr_dev->ib_dev); + hr_dev->state = HNS_ROCE_DEVICE_STATE_RST_DOWN; return 0; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h index c65f68a14a2608..cbdbc9edbce6ec 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h @@ -85,6 +85,11 @@ #define HNS_ROCE_V2_TABLE_CHUNK_SIZE (1 << 18) +/* budget must be smaller than aeqe_depth to guarantee that we update + * the ci before we polled all the entries in the EQ. + */ +#define HNS_AEQ_POLLING_BUDGET 64 + enum { HNS_ROCE_CMD_FLAG_IN = BIT(0), HNS_ROCE_CMD_FLAG_OUT = BIT(1), @@ -919,6 +924,7 @@ struct hns_roce_v2_rc_send_wqe { #define RC_SEND_WQE_OWNER RC_SEND_WQE_FIELD_LOC(7, 7) #define RC_SEND_WQE_CQE RC_SEND_WQE_FIELD_LOC(8, 8) #define RC_SEND_WQE_FENCE RC_SEND_WQE_FIELD_LOC(9, 9) +#define RC_SEND_WQE_SO RC_SEND_WQE_FIELD_LOC(10, 10) #define RC_SEND_WQE_SE RC_SEND_WQE_FIELD_LOC(11, 11) #define RC_SEND_WQE_INLINE RC_SEND_WQE_FIELD_LOC(12, 12) #define RC_SEND_WQE_WQE_INDEX RC_SEND_WQE_FIELD_LOC(30, 15) @@ -1342,7 +1348,7 @@ struct hns_roce_v2_priv { struct hns_roce_dip { u8 dgid[GID_LEN_V2]; u32 dip_idx; - struct list_head node; /* all dips are on a list */ + u32 qp_cnt; }; struct fmea_ram_ecc { diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 4cb0af73358708..ae24c81c9812d9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -466,6 +466,11 @@ static int hns_roce_mmap(struct ib_ucontext *uctx, struct vm_area_struct *vma) pgprot_t prot; int ret; + if (hr_dev->dis_db) { + atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MMAP_ERR_CNT]); + return -EPERM; + } + rdma_entry = rdma_user_mmap_entry_get_pgoff(uctx, vma->vm_pgoff); if (!rdma_entry) { atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MMAP_ERR_CNT]); @@ -1130,8 +1135,6 @@ int hns_roce_init(struct hns_roce_dev *hr_dev) INIT_LIST_HEAD(&hr_dev->qp_list); spin_lock_init(&hr_dev->qp_list_lock); - INIT_LIST_HEAD(&hr_dev->dip_list); - spin_lock_init(&hr_dev->dip_list_lock); ret = hns_roce_register_device(hr_dev); if (ret) diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index 846da8c78b8b72..bf30b3a65a9ba9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -138,8 +138,8 @@ static void hns_roce_mr_free(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr key_to_hw_index(mr->key) & (hr_dev->caps.num_mtpts - 1)); if (ret) - ibdev_warn(ibdev, "failed to destroy mpt, ret = %d.\n", - ret); + ibdev_warn_ratelimited(ibdev, "failed to destroy mpt, ret = %d.\n", + ret); } free_mr_pbl(hr_dev, mr); @@ -435,15 +435,16 @@ static int hns_roce_set_page(struct ib_mr *ibmr, u64 addr) } int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, - unsigned int *sg_offset) + unsigned int *sg_offset_p) { + unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0; struct hns_roce_dev *hr_dev = to_hr_dev(ibmr->device); struct ib_device *ibdev = &hr_dev->ib_dev; struct hns_roce_mr *mr = to_hr_mr(ibmr); struct hns_roce_mtr *mtr = &mr->pbl_mtr; int ret, sg_num = 0; - if (!IS_ALIGNED(*sg_offset, HNS_ROCE_FRMR_ALIGN_SIZE) || + if (!IS_ALIGNED(sg_offset, HNS_ROCE_FRMR_ALIGN_SIZE) || ibmr->page_size < HNS_HW_PAGE_SIZE || ibmr->page_size > HNS_HW_MAX_PAGE_SIZE) return sg_num; @@ -454,7 +455,7 @@ int hns_roce_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, if (!mr->page_list) return sg_num; - sg_num = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, hns_roce_set_page); + sg_num = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset_p, hns_roce_set_page); if (sg_num < 1) { ibdev_err(ibdev, "failed to store sg pages %u %u, cnt = %d.\n", mr->npages, mr->pbl_mtr.hem_cfg.buf_pg_count, sg_num); diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 6b03ba671ff8f3..9e2e76c5940636 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -39,6 +39,25 @@ #include "hns_roce_device.h" #include "hns_roce_hem.h" +static struct hns_roce_qp *hns_roce_qp_lookup(struct hns_roce_dev *hr_dev, + u32 qpn) +{ + struct device *dev = hr_dev->dev; + struct hns_roce_qp *qp; + unsigned long flags; + + xa_lock_irqsave(&hr_dev->qp_table_xa, flags); + qp = __hns_roce_qp_lookup(hr_dev, qpn); + if (qp) + refcount_inc(&qp->refcount); + xa_unlock_irqrestore(&hr_dev->qp_table_xa, flags); + + if (!qp) + dev_warn(dev, "async event for bogus QP %08x\n", qpn); + + return qp; +} + static void flush_work_handle(struct work_struct *work) { struct hns_roce_work *flush_work = container_of(work, @@ -71,11 +90,18 @@ static void flush_work_handle(struct work_struct *work) void init_flush_work(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) { struct hns_roce_work *flush_work = &hr_qp->flush_work; + unsigned long flags; + + spin_lock_irqsave(&hr_qp->flush_lock, flags); + /* Exit directly after destroy_qp() */ + if (test_bit(HNS_ROCE_STOP_FLUSH_FLAG, &hr_qp->flush_flag)) { + spin_unlock_irqrestore(&hr_qp->flush_lock, flags); + return; + } - flush_work->hr_dev = hr_dev; - INIT_WORK(&flush_work->work, flush_work_handle); refcount_inc(&hr_qp->refcount); queue_work(hr_dev->irq_workq, &flush_work->work); + spin_unlock_irqrestore(&hr_qp->flush_lock, flags); } void flush_cqe(struct hns_roce_dev *dev, struct hns_roce_qp *qp) @@ -95,31 +121,28 @@ void flush_cqe(struct hns_roce_dev *dev, struct hns_roce_qp *qp) void hns_roce_qp_event(struct hns_roce_dev *hr_dev, u32 qpn, int event_type) { - struct device *dev = hr_dev->dev; struct hns_roce_qp *qp; - xa_lock(&hr_dev->qp_table_xa); - qp = __hns_roce_qp_lookup(hr_dev, qpn); - if (qp) - refcount_inc(&qp->refcount); - xa_unlock(&hr_dev->qp_table_xa); - - if (!qp) { - dev_warn(dev, "async event for bogus QP %08x\n", qpn); + qp = hns_roce_qp_lookup(hr_dev, qpn); + if (!qp) return; - } - if (event_type == HNS_ROCE_EVENT_TYPE_WQ_CATAS_ERROR || - event_type == HNS_ROCE_EVENT_TYPE_INV_REQ_LOCAL_WQ_ERROR || - event_type == HNS_ROCE_EVENT_TYPE_LOCAL_WQ_ACCESS_ERROR || - event_type == HNS_ROCE_EVENT_TYPE_XRCD_VIOLATION || - event_type == HNS_ROCE_EVENT_TYPE_INVALID_XRCETH) { - qp->state = IB_QPS_ERR; + qp->event(qp, (enum hns_roce_event)event_type); - flush_cqe(hr_dev, qp); - } + if (refcount_dec_and_test(&qp->refcount)) + complete(&qp->free); +} - qp->event(qp, (enum hns_roce_event)event_type); +void hns_roce_flush_cqe(struct hns_roce_dev *hr_dev, u32 qpn) +{ + struct hns_roce_qp *qp; + + qp = hns_roce_qp_lookup(hr_dev, qpn); + if (!qp) + return; + + qp->state = IB_QPS_ERR; + flush_cqe(hr_dev, qp); if (refcount_dec_and_test(&qp->refcount)) complete(&qp->free); @@ -1124,6 +1147,7 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, struct ib_udata *udata, struct hns_roce_qp *hr_qp) { + struct hns_roce_work *flush_work = &hr_qp->flush_work; struct hns_roce_ib_create_qp_resp resp = {}; struct ib_device *ibdev = &hr_dev->ib_dev; struct hns_roce_ib_create_qp ucmd = {}; @@ -1132,9 +1156,12 @@ static int hns_roce_create_qp_common(struct hns_roce_dev *hr_dev, mutex_init(&hr_qp->mutex); spin_lock_init(&hr_qp->sq.lock); spin_lock_init(&hr_qp->rq.lock); + spin_lock_init(&hr_qp->flush_lock); hr_qp->state = IB_QPS_RESET; hr_qp->flush_flag = 0; + flush_work->hr_dev = hr_dev; + INIT_WORK(&flush_work->work, flush_work_handle); if (init_attr->create_flags) return -EOPNOTSUPP; @@ -1546,14 +1573,10 @@ int hns_roce_init_qp_table(struct hns_roce_dev *hr_dev) unsigned int reserved_from_bot; unsigned int i; - qp_table->idx_table.spare_idx = kcalloc(hr_dev->caps.num_qps, - sizeof(u32), GFP_KERNEL); - if (!qp_table->idx_table.spare_idx) - return -ENOMEM; - mutex_init(&qp_table->scc_mutex); mutex_init(&qp_table->bank_mutex); xa_init(&hr_dev->qp_table_xa); + xa_init(&qp_table->dip_xa); reserved_from_bot = hr_dev->caps.reserved_qps; @@ -1578,7 +1601,7 @@ void hns_roce_cleanup_qp_table(struct hns_roce_dev *hr_dev) for (i = 0; i < HNS_ROCE_QP_BANK_NUM; i++) ida_destroy(&hr_dev->qp_table.bank[i].ida); + xa_destroy(&hr_dev->qp_table.dip_xa); mutex_destroy(&hr_dev->qp_table.bank_mutex); mutex_destroy(&hr_dev->qp_table.scc_mutex); - kfree(hr_dev->qp_table.idx_table.spare_idx); } diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c index c9b8233f4b0577..70c06ef65603d8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_srq.c +++ b/drivers/infiniband/hw/hns/hns_roce_srq.c @@ -151,8 +151,8 @@ static void free_srqc(struct hns_roce_dev *hr_dev, struct hns_roce_srq *srq) ret = hns_roce_destroy_hw_ctx(hr_dev, HNS_ROCE_CMD_DESTROY_SRQ, srq->srqn); if (ret) - dev_err(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n", - ret, srq->srqn); + dev_err_ratelimited(hr_dev->dev, "DESTROY_SRQ failed (%d) for SRQN %06lx\n", + ret, srq->srqn); xa_erase_irq(&srq_table->xa, srq->srqn); diff --git a/drivers/infiniband/hw/mana/device.c b/drivers/infiniband/hw/mana/device.c index 7ac01918ef7c0d..3416a85f873825 100644 --- a/drivers/infiniband/hw/mana/device.c +++ b/drivers/infiniband/hw/mana/device.c @@ -9,7 +9,7 @@ MODULE_DESCRIPTION("Microsoft Azure Network Adapter IB driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(NET_MANA); +MODULE_IMPORT_NS("NET_MANA"); static const struct ib_device_ops mana_ib_dev_ops = { .owner = THIS_MODULE, diff --git a/drivers/infiniband/hw/mlx5/devx.c b/drivers/infiniband/hw/mlx5/devx.c index 69999d8d24f379..4186884c66e10b 100644 --- a/drivers/infiniband/hw/mlx5/devx.c +++ b/drivers/infiniband/hw/mlx5/devx.c @@ -27,6 +27,19 @@ enum devx_obj_flags { DEVX_OBJ_FLAGS_INDIRECT_MKEY = 1 << 0, DEVX_OBJ_FLAGS_DCT = 1 << 1, DEVX_OBJ_FLAGS_CQ = 1 << 2, + DEVX_OBJ_FLAGS_HW_FREED = 1 << 3, +}; + +#define MAX_ASYNC_CMDS 8 + +struct mlx5_async_cmd { + struct ib_uobject *uobject; + void *in; + int in_size; + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; + int err; + struct mlx5_async_work cb_work; + struct completion comp; }; struct devx_async_data { @@ -1405,7 +1418,9 @@ static int devx_obj_cleanup(struct ib_uobject *uobject, */ mlx5r_deref_wait_odp_mkey(&obj->mkey); - if (obj->flags & DEVX_OBJ_FLAGS_DCT) + if (obj->flags & DEVX_OBJ_FLAGS_HW_FREED) + ret = 0; + else if (obj->flags & DEVX_OBJ_FLAGS_DCT) ret = mlx5_core_destroy_dct(obj->ib_dev, &obj->core_dct); else if (obj->flags & DEVX_OBJ_FLAGS_CQ) ret = mlx5_core_destroy_cq(obj->ib_dev->mdev, &obj->core_cq); @@ -2595,6 +2610,82 @@ void mlx5_ib_devx_cleanup(struct mlx5_ib_dev *dev) } } +static void devx_async_destroy_cb(int status, struct mlx5_async_work *context) +{ + struct mlx5_async_cmd *devx_out = container_of(context, + struct mlx5_async_cmd, cb_work); + struct devx_obj *obj = devx_out->uobject->object; + + if (!status) + obj->flags |= DEVX_OBJ_FLAGS_HW_FREED; + + complete(&devx_out->comp); +} + +static void devx_async_destroy(struct mlx5_ib_dev *dev, + struct mlx5_async_cmd *cmd) +{ + init_completion(&cmd->comp); + cmd->err = mlx5_cmd_exec_cb(&dev->async_ctx, cmd->in, cmd->in_size, + &cmd->out, sizeof(cmd->out), + devx_async_destroy_cb, &cmd->cb_work); +} + +static void devx_wait_async_destroy(struct mlx5_async_cmd *cmd) +{ + if (!cmd->err) + wait_for_completion(&cmd->comp); + atomic_set(&cmd->uobject->usecnt, 0); +} + +void mlx5_ib_ufile_hw_cleanup(struct ib_uverbs_file *ufile) +{ + struct mlx5_async_cmd async_cmd[MAX_ASYNC_CMDS]; + struct ib_ucontext *ucontext = ufile->ucontext; + struct ib_device *device = ucontext->device; + struct mlx5_ib_dev *dev = to_mdev(device); + struct ib_uobject *uobject; + struct devx_obj *obj; + int head = 0; + int tail = 0; + + list_for_each_entry(uobject, &ufile->uobjects, list) { + WARN_ON(uverbs_try_lock_object(uobject, UVERBS_LOOKUP_WRITE)); + + /* + * Currently we only support QP destruction, if other objects + * are to be destroyed need to add type synchronization to the + * cleanup algorithm and handle pre/post FW cleanup for the + * new types if needed. + */ + if (uobj_get_object_id(uobject) != MLX5_IB_OBJECT_DEVX_OBJ || + (get_dec_obj_type(uobject->object, MLX5_EVENT_TYPE_MAX) != + MLX5_OBJ_TYPE_QP)) { + atomic_set(&uobject->usecnt, 0); + continue; + } + + obj = uobject->object; + + async_cmd[tail % MAX_ASYNC_CMDS].in = obj->dinbox; + async_cmd[tail % MAX_ASYNC_CMDS].in_size = obj->dinlen; + async_cmd[tail % MAX_ASYNC_CMDS].uobject = uobject; + + devx_async_destroy(dev, &async_cmd[tail % MAX_ASYNC_CMDS]); + tail++; + + if (tail - head == MAX_ASYNC_CMDS) { + devx_wait_async_destroy(&async_cmd[head % MAX_ASYNC_CMDS]); + head++; + } + } + + while (head != tail) { + devx_wait_async_destroy(&async_cmd[head % MAX_ASYNC_CMDS]); + head++; + } +} + static ssize_t devx_async_cmd_event_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { diff --git a/drivers/infiniband/hw/mlx5/devx.h b/drivers/infiniband/hw/mlx5/devx.h index ee2213275fd6fd..1344bf4c9d21fe 100644 --- a/drivers/infiniband/hw/mlx5/devx.h +++ b/drivers/infiniband/hw/mlx5/devx.h @@ -28,6 +28,7 @@ int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, bool is_user); void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid); int mlx5_ib_devx_init(struct mlx5_ib_dev *dev); void mlx5_ib_devx_cleanup(struct mlx5_ib_dev *dev); +void mlx5_ib_ufile_hw_cleanup(struct ib_uverbs_file *ufile); #else static inline int mlx5_ib_devx_create(struct mlx5_ib_dev *dev, bool is_user) { @@ -41,5 +42,8 @@ static inline int mlx5_ib_devx_init(struct mlx5_ib_dev *dev) static inline void mlx5_ib_devx_cleanup(struct mlx5_ib_dev *dev) { } +static inline void mlx5_ib_ufile_hw_cleanup(struct ib_uverbs_file *ufile) +{ +} #endif #endif /* _MLX5_IB_DEVX_H */ diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c index 1b6c5e37d1697d..2453ae4384a718 100644 --- a/drivers/infiniband/hw/mlx5/mad.c +++ b/drivers/infiniband/hw/mlx5/mad.c @@ -278,7 +278,13 @@ static int process_pma_cmd(struct mlx5_ib_dev *dev, u32 port_num, goto done; } - err = query_ib_ppcnt(mdev, mdev_port_num, 0, out_cnt, sz, 0); + if (dev->ib_dev.type == RDMA_DEVICE_TYPE_SMI) + err = query_ib_ppcnt(mdev, mdev_port_num, port_num, + out_cnt, sz, 0); + else + err = query_ib_ppcnt(mdev, mdev_port_num, 0, + out_cnt, sz, 0); + if (!err) pma_cnt_assign(pma_cnt, out_cnt); } diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 4999239c8f4137..bc7930d0c5647d 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1182,6 +1182,14 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, MLX5_IB_QUERY_DEV_RESP_PACKET_BASED_CREDIT_MODE; resp.flags |= MLX5_IB_QUERY_DEV_RESP_FLAGS_SCAT2CQE_DCT; + + if (MLX5_CAP_GEN_2(mdev, dp_ordering_force) && + (MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_xrc) || + MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_dc) || + MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_rc) || + MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_ud) || + MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_uc))) + resp.flags |= MLX5_IB_QUERY_DEV_RESP_FLAGS_OOO_DP; } if (offsetofend(typeof(resp), sw_parsing_caps) <= uhw_outlen) { @@ -2997,7 +3005,6 @@ int mlx5_ib_dev_res_srq_init(struct mlx5_ib_dev *dev) static int mlx5_ib_dev_res_init(struct mlx5_ib_dev *dev) { struct mlx5_ib_resources *devr = &dev->devr; - int port; int ret; if (!MLX5_CAP_GEN(dev->mdev, xrc)) @@ -3013,10 +3020,6 @@ static int mlx5_ib_dev_res_init(struct mlx5_ib_dev *dev) return ret; } - for (port = 0; port < ARRAY_SIZE(devr->ports); ++port) - INIT_WORK(&devr->ports[port].pkey_change_work, - pkey_change_handler); - mutex_init(&devr->cq_lock); mutex_init(&devr->srq_lock); @@ -3026,16 +3029,6 @@ static int mlx5_ib_dev_res_init(struct mlx5_ib_dev *dev) static void mlx5_ib_dev_res_cleanup(struct mlx5_ib_dev *dev) { struct mlx5_ib_resources *devr = &dev->devr; - int port; - - /* - * Make sure no change P_Key work items are still executing. - * - * At this stage, the mlx5_ib_event should be unregistered - * and it ensures that no new works are added. - */ - for (port = 0; port < ARRAY_SIZE(devr->ports); ++port) - cancel_work_sync(&devr->ports[port].pkey_change_work); /* After s0/s1 init, they are not unset during the device lifetime. */ if (devr->s1) { @@ -3211,12 +3204,14 @@ static int lag_event(struct notifier_block *nb, unsigned long event, void *data) struct mlx5_ib_dev *dev = container_of(nb, struct mlx5_ib_dev, lag_events); struct mlx5_core_dev *mdev = dev->mdev; + struct ib_device *ibdev = &dev->ib_dev; + struct net_device *old_ndev = NULL; struct mlx5_ib_port *port; struct net_device *ndev; - int i, err; - int portnum; + u32 portnum = 0; + int ret = 0; + int i; - portnum = 0; switch (event) { case MLX5_DRIVER_EVENT_ACTIVE_BACKUP_LAG_CHANGE_LOWERSTATE: ndev = data; @@ -3232,19 +3227,24 @@ static int lag_event(struct notifier_block *nb, unsigned long event, void *data) } } } - err = ib_device_set_netdev(&dev->ib_dev, ndev, - portnum + 1); - dev_put(ndev); - if (err) - return err; - /* Rescan gids after new netdev assignment */ - rdma_roce_rescan_device(&dev->ib_dev); + old_ndev = ib_device_get_netdev(ibdev, portnum + 1); + ret = ib_device_set_netdev(ibdev, ndev, portnum + 1); + if (ret) + goto out; + + if (old_ndev) + roce_del_all_netdev_gids(ibdev, portnum + 1, + old_ndev); + rdma_roce_rescan_port(ibdev, portnum + 1); } break; default: return NOTIFY_DONE; } - return NOTIFY_OK; + +out: + dev_put(old_ndev); + return notifier_from_errno(ret); } static void mlx5e_lag_event_register(struct mlx5_ib_dev *dev) @@ -4134,6 +4134,7 @@ static const struct ib_device_ops mlx5_ib_dev_ops = { .req_notify_cq = mlx5_ib_arm_cq, .rereg_user_mr = mlx5_ib_rereg_user_mr, .resize_cq = mlx5_ib_resize_cq, + .ufile_hw_cleanup = mlx5_ib_ufile_hw_cleanup, INIT_RDMA_OBJ_SIZE(ib_ah, mlx5_ib_ah, ibah), INIT_RDMA_OBJ_SIZE(ib_counters, mlx5_ib_mcounters, ibcntrs), @@ -4464,6 +4465,13 @@ static void mlx5_ib_stage_delay_drop_cleanup(struct mlx5_ib_dev *dev) static int mlx5_ib_stage_dev_notifier_init(struct mlx5_ib_dev *dev) { + struct mlx5_ib_resources *devr = &dev->devr; + int port; + + for (port = 0; port < ARRAY_SIZE(devr->ports); ++port) + INIT_WORK(&devr->ports[port].pkey_change_work, + pkey_change_handler); + dev->mdev_events.notifier_call = mlx5_ib_event; mlx5_notifier_register(dev->mdev, &dev->mdev_events); @@ -4474,8 +4482,14 @@ static int mlx5_ib_stage_dev_notifier_init(struct mlx5_ib_dev *dev) static void mlx5_ib_stage_dev_notifier_cleanup(struct mlx5_ib_dev *dev) { + struct mlx5_ib_resources *devr = &dev->devr; + int port; + mlx5r_macsec_event_unregister(dev); mlx5_notifier_unregister(dev->mdev, &dev->mdev_events); + + for (port = 0; port < ARRAY_SIZE(devr->ports); ++port) + cancel_work_sync(&devr->ports[port].pkey_change_work); } void mlx5_ib_data_direct_bind(struct mlx5_ib_dev *ibdev, @@ -4565,9 +4579,6 @@ static const struct mlx5_ib_profile pf_profile = { STAGE_CREATE(MLX5_IB_STAGE_DEVICE_RESOURCES, mlx5_ib_dev_res_init, mlx5_ib_dev_res_cleanup), - STAGE_CREATE(MLX5_IB_STAGE_DEVICE_NOTIFIER, - mlx5_ib_stage_dev_notifier_init, - mlx5_ib_stage_dev_notifier_cleanup), STAGE_CREATE(MLX5_IB_STAGE_ODP, mlx5_ib_odp_init_one, mlx5_ib_odp_cleanup_one), @@ -4592,6 +4603,9 @@ static const struct mlx5_ib_profile pf_profile = { STAGE_CREATE(MLX5_IB_STAGE_IB_REG, mlx5_ib_stage_ib_reg_init, mlx5_ib_stage_ib_reg_cleanup), + STAGE_CREATE(MLX5_IB_STAGE_DEVICE_NOTIFIER, + mlx5_ib_stage_dev_notifier_init, + mlx5_ib_stage_dev_notifier_cleanup), STAGE_CREATE(MLX5_IB_STAGE_POST_IB_REG_UMR, mlx5_ib_stage_post_ib_reg_umr_init, NULL), @@ -4628,9 +4642,6 @@ const struct mlx5_ib_profile raw_eth_profile = { STAGE_CREATE(MLX5_IB_STAGE_DEVICE_RESOURCES, mlx5_ib_dev_res_init, mlx5_ib_dev_res_cleanup), - STAGE_CREATE(MLX5_IB_STAGE_DEVICE_NOTIFIER, - mlx5_ib_stage_dev_notifier_init, - mlx5_ib_stage_dev_notifier_cleanup), STAGE_CREATE(MLX5_IB_STAGE_COUNTERS, mlx5_ib_counters_init, mlx5_ib_counters_cleanup), @@ -4652,6 +4663,9 @@ const struct mlx5_ib_profile raw_eth_profile = { STAGE_CREATE(MLX5_IB_STAGE_IB_REG, mlx5_ib_stage_ib_reg_init, mlx5_ib_stage_ib_reg_cleanup), + STAGE_CREATE(MLX5_IB_STAGE_DEVICE_NOTIFIER, + mlx5_ib_stage_dev_notifier_init, + mlx5_ib_stage_dev_notifier_cleanup), STAGE_CREATE(MLX5_IB_STAGE_POST_IB_REG_UMR, mlx5_ib_stage_post_ib_reg_umr_init, NULL), diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 23fd72f7f63df9..a01b592aa7168d 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -521,6 +521,7 @@ struct mlx5_ib_qp { struct mlx5_bf bf; u8 has_rq:1; u8 is_rss:1; + u8 is_ooo_rq:1; /* only for user space QPs. For kernel * we have it from the bf object @@ -972,7 +973,6 @@ enum mlx5_ib_stages { MLX5_IB_STAGE_QP, MLX5_IB_STAGE_SRQ, MLX5_IB_STAGE_DEVICE_RESOURCES, - MLX5_IB_STAGE_DEVICE_NOTIFIER, MLX5_IB_STAGE_ODP, MLX5_IB_STAGE_COUNTERS, MLX5_IB_STAGE_CONG_DEBUGFS, @@ -981,6 +981,7 @@ enum mlx5_ib_stages { MLX5_IB_STAGE_PRE_IB_REG_UMR, MLX5_IB_STAGE_WHITELIST_UID, MLX5_IB_STAGE_IB_REG, + MLX5_IB_STAGE_DEVICE_NOTIFIER, MLX5_IB_STAGE_POST_IB_REG_UMR, MLX5_IB_STAGE_DELAY_DROP, MLX5_IB_STAGE_RESTRACK, diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 10ce3b44f645f4..a43eba9d3572ce 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1960,7 +1960,7 @@ static int atomic_size_to_mode(int size_mask) } static int get_atomic_mode(struct mlx5_ib_dev *dev, - enum ib_qp_type qp_type) + struct mlx5_ib_qp *qp) { u8 atomic_operations = MLX5_CAP_ATOMIC(dev->mdev, atomic_operations); u8 atomic = MLX5_CAP_GEN(dev->mdev, atomic); @@ -1970,7 +1970,7 @@ static int get_atomic_mode(struct mlx5_ib_dev *dev, if (!atomic) return -EOPNOTSUPP; - if (qp_type == MLX5_IB_QPT_DCT) + if (qp->type == MLX5_IB_QPT_DCT) atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_dc); else atomic_size_mask = MLX5_CAP_ATOMIC(dev->mdev, atomic_size_qp); @@ -1984,6 +1984,10 @@ static int get_atomic_mode(struct mlx5_ib_dev *dev, atomic_operations & MLX5_ATOMIC_OPS_FETCH_ADD)) atomic_mode = MLX5_ATOMIC_MODE_IB_COMP; + /* OOO DP QPs do not support larger than 8-Bytes atomic operations */ + if (atomic_mode > MLX5_ATOMIC_MODE_8B && qp->is_ooo_rq) + atomic_mode = MLX5_ATOMIC_MODE_8B; + return atomic_mode; } @@ -2839,6 +2843,29 @@ static int check_valid_flow(struct mlx5_ib_dev *dev, struct ib_pd *pd, return 0; } +static bool get_dp_ooo_cap(struct mlx5_core_dev *mdev, enum ib_qp_type qp_type) +{ + if (!MLX5_CAP_GEN_2(mdev, dp_ordering_force)) + return false; + + switch (qp_type) { + case IB_QPT_RC: + return MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_rc); + case IB_QPT_XRC_INI: + case IB_QPT_XRC_TGT: + return MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_xrc); + case IB_QPT_UC: + return MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_uc); + case IB_QPT_UD: + return MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_ud); + case MLX5_IB_QPT_DCI: + case MLX5_IB_QPT_DCT: + return MLX5_CAP_GEN(mdev, dp_ordering_ooo_all_dc); + default: + return false; + } +} + static void process_vendor_flag(struct mlx5_ib_dev *dev, int *flags, int flag, bool cond, struct mlx5_ib_qp *qp) { @@ -3365,7 +3392,7 @@ static int set_qpc_atomic_flags(struct mlx5_ib_qp *qp, if (access_flags & IB_ACCESS_REMOTE_ATOMIC) { int atomic_mode; - atomic_mode = get_atomic_mode(dev, qp->type); + atomic_mode = get_atomic_mode(dev, qp); if (atomic_mode < 0) return -EOPNOTSUPP; @@ -4316,6 +4343,11 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, if (qp->flags & MLX5_IB_QP_CREATE_SQPN_QP1) MLX5_SET(qpc, qpc, deth_sqpn, 1); + if (qp->is_ooo_rq && cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) { + MLX5_SET(qpc, qpc, dp_ordering_1, 1); + MLX5_SET(qpc, qpc, dp_ordering_force, 1); + } + mlx5_cur = to_mlx5_state(cur_state); mlx5_new = to_mlx5_state(new_state); @@ -4531,7 +4563,7 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC) { int atomic_mode; - atomic_mode = get_atomic_mode(dev, MLX5_IB_QPT_DCT); + atomic_mode = get_atomic_mode(dev, qp); if (atomic_mode < 0) return -EOPNOTSUPP; @@ -4573,6 +4605,10 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr, MLX5_SET(dctc, dctc, hop_limit, attr->ah_attr.grh.hop_limit); if (attr->ah_attr.type == RDMA_AH_ATTR_TYPE_ROCE) MLX5_SET(dctc, dctc, eth_prio, attr->ah_attr.sl & 0x7); + if (qp->is_ooo_rq) { + MLX5_SET(dctc, dctc, dp_ordering_1, 1); + MLX5_SET(dctc, dctc, dp_ordering_force, 1); + } err = mlx5_core_create_dct(dev, &qp->dct.mdct, qp->dct.in, MLX5_ST_SZ_BYTES(create_dct_in), out, @@ -4676,11 +4712,16 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, min(udata->inlen, sizeof(ucmd)))) return -EFAULT; - if (ucmd.comp_mask || + if (ucmd.comp_mask & ~MLX5_IB_MODIFY_QP_OOO_DP || memchr_inv(&ucmd.burst_info.reserved, 0, sizeof(ucmd.burst_info.reserved))) return -EOPNOTSUPP; + if (ucmd.comp_mask & MLX5_IB_MODIFY_QP_OOO_DP) { + if (!get_dp_ooo_cap(dev->mdev, qp->type)) + return -EOPNOTSUPP; + qp->is_ooo_rq = 1; + } } if (qp->type == IB_QPT_GSI) diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c index 53ec7510e4ebfb..ba2cd68b53e6c2 100644 --- a/drivers/infiniband/hw/qib/qib_sysfs.c +++ b/drivers/infiniband/hw/qib/qib_sysfs.c @@ -283,7 +283,7 @@ static struct bin_attribute *port_ccmgta_attributes[] = { }; static umode_t qib_ccmgta_is_bin_visible(struct kobject *kobj, - struct bin_attribute *attr, int n) + const struct bin_attribute *attr, int n) { struct qib_pportdata *ppd = qib_get_pportdata_kobj(kobj); diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index d2f7b5195c19dd..91d329e903083c 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -775,6 +775,7 @@ int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask) * Yield the processor */ spin_lock_irqsave(&qp->state_lock, flags); + attr->cur_qp_state = qp_state(qp); if (qp->attr.sq_draining) { spin_unlock_irqrestore(&qp->state_lock, flags); cond_resched(); diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 479c07e6e4ed3e..87a02f0deb0001 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -663,10 +663,12 @@ int rxe_requester(struct rxe_qp *qp) if (unlikely(qp_state(qp) == IB_QPS_ERR)) { wqe = __req_next_wqe(qp); spin_unlock_irqrestore(&qp->state_lock, flags); - if (wqe) + if (wqe) { + wqe->status = IB_WC_WR_FLUSH_ERR; goto err; - else + } else { goto exit; + } } if (unlikely(qp_state(qp) == IB_QPS_RESET)) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c index 7da94fb8d7fa23..4feb7170535cb0 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -128,16 +128,13 @@ static void ipoib_get_ethtool_stats(struct net_device *dev, static void ipoib_get_strings(struct net_device __always_unused *dev, u32 stringset, u8 *data) { - u8 *p = data; int i; switch (stringset) { case ETH_SS_STATS: - for (i = 0; i < IPOIB_GLOBAL_STATS_LEN; i++) { - memcpy(p, ipoib_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } + for (i = 0; i < IPOIB_GLOBAL_STATS_LEN; i++) + ethtool_puts(&data, + ipoib_gstrings_stats[i].stat_string); break; default: break; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 4e31bb0b6466d9..3b463db8ce39d9 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -2145,7 +2146,7 @@ void ipoib_setup_common(struct net_device *dev) dev->hard_header_len = IPOIB_HARD_LEN; dev->addr_len = INFINIBAND_ALEN; dev->type = ARPHRD_INFINIBAND; - dev->tx_queue_len = ipoib_sendq_size * 2; + dev->tx_queue_len = DEFAULT_TX_QUEUE_LEN; dev->features = (NETIF_F_VLAN_CHALLENGED | NETIF_F_HIGHDMA); netif_keep_dst(dev); diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c index 29b3d8fce3f5f3..316959940d2fcb 100644 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c +++ b/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c @@ -164,9 +164,7 @@ static void vnic_get_strings(struct net_device *netdev, u32 stringset, u8 *data) return; for (i = 0; i < VNIC_STATS_LEN; i++) - memcpy(data + i * ETH_GSTRING_LEN, - vnic_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + ethtool_puts(&data, vnic_gstrings_stats[i].stat_string); } /* ethtool ops */ diff --git a/drivers/input/input.c b/drivers/input/input.c index c51858f1cdc556..7f0477e04ad218 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -605,6 +605,9 @@ int input_open_device(struct input_handle *handle) handle->open++; + if (handle->handler->passive_observer) + goto out; + if (dev->users++ || dev->inhibited) { /* * Device is already opened and/or inhibited, @@ -668,11 +671,13 @@ void input_close_device(struct input_handle *handle) __input_release_device(handle); - if (!--dev->users && !dev->inhibited) { - if (dev->poller) - input_dev_poller_stop(dev->poller); - if (dev->close) - dev->close(dev); + if (!handle->handler->passive_observer) { + if (!--dev->users && !dev->inhibited) { + if (dev->poller) + input_dev_poller_stop(dev->poller); + if (dev->close) + dev->close(dev); + } } if (!--handle->open) { diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index 6373d7aa739a88..a9f1946cf0d6f8 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -505,24 +505,22 @@ static int db9_open(struct input_dev *dev) { struct db9 *db9 = input_get_drvdata(dev); struct parport *port = db9->pd->port; - int err; - err = mutex_lock_interruptible(&db9->mutex); - if (err) - return err; - - if (!db9->used++) { - parport_claim(db9->pd); - parport_write_data(port, 0xff); - if (db9_modes[db9->mode].reverse) { - parport_data_reverse(port); - parport_write_control(port, DB9_NORMAL); + scoped_guard(mutex_intr, &db9->mutex) { + if (!db9->used++) { + parport_claim(db9->pd); + parport_write_data(port, 0xff); + if (db9_modes[db9->mode].reverse) { + parport_data_reverse(port); + parport_write_control(port, DB9_NORMAL); + } + mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); } - mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); + + return 0; } - mutex_unlock(&db9->mutex); - return 0; + return -EINTR; } static void db9_close(struct input_dev *dev) @@ -530,14 +528,14 @@ static void db9_close(struct input_dev *dev) struct db9 *db9 = input_get_drvdata(dev); struct parport *port = db9->pd->port; - mutex_lock(&db9->mutex); + guard(mutex)(&db9->mutex); + if (!--db9->used) { del_timer_sync(&db9->timer); parport_write_control(port, 0x00); parport_data_forward(port); parport_release(db9->pd); } - mutex_unlock(&db9->mutex); } static void db9_attach(struct parport *pp) diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 2b553e2d838f27..b53cafd7a5ee12 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -765,33 +765,31 @@ static void gc_timer(struct timer_list *t) static int gc_open(struct input_dev *dev) { struct gc *gc = input_get_drvdata(dev); - int err; - err = mutex_lock_interruptible(&gc->mutex); - if (err) - return err; + scoped_guard(mutex_intr, &gc->mutex) { + if (!gc->used++) { + parport_claim(gc->pd); + parport_write_control(gc->pd->port, 0x04); + mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); + } - if (!gc->used++) { - parport_claim(gc->pd); - parport_write_control(gc->pd->port, 0x04); - mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); + return 0; } - mutex_unlock(&gc->mutex); - return 0; + return -EINTR; } static void gc_close(struct input_dev *dev) { struct gc *gc = input_get_drvdata(dev); - mutex_lock(&gc->mutex); + guard(mutex)(&gc->mutex); + if (!--gc->used) { del_timer_sync(&gc->timer); parport_write_control(gc->pd->port, 0x00); parport_release(gc->pd); } - mutex_unlock(&gc->mutex); } static int gc_setup_pad(struct gc *gc, int idx, int pad_type) diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 95c0348843e6b4..8c78cbe553c8cc 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c @@ -21,14 +21,13 @@ static int make_magnitude_modifier(struct iforce* iforce, unsigned char data[3]; if (!no_alloc) { - mutex_lock(&iforce->mem_mutex); - if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - mutex_unlock(&iforce->mem_mutex); + guard(mutex)(&iforce->mem_mutex); + + if (allocate_resource(&iforce->device_memory, mod_chunk, 2, + iforce->device_memory.start, + iforce->device_memory.end, + 2L, NULL, NULL)) return -ENOSPC; - } - mutex_unlock(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); @@ -54,14 +53,13 @@ static int make_period_modifier(struct iforce* iforce, period = TIME_SCALE(period); if (!no_alloc) { - mutex_lock(&iforce->mem_mutex); - if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - mutex_unlock(&iforce->mem_mutex); + guard(mutex)(&iforce->mem_mutex); + + if (allocate_resource(&iforce->device_memory, mod_chunk, 0x0c, + iforce->device_memory.start, + iforce->device_memory.end, + 2L, NULL, NULL)) return -ENOSPC; - } - mutex_unlock(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); @@ -94,14 +92,13 @@ static int make_envelope_modifier(struct iforce* iforce, fade_duration = TIME_SCALE(fade_duration); if (!no_alloc) { - mutex_lock(&iforce->mem_mutex); + guard(mutex)(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - mutex_unlock(&iforce->mem_mutex); + iforce->device_memory.start, + iforce->device_memory.end, + 2L, NULL, NULL)) return -ENOSPC; - } - mutex_unlock(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); @@ -131,14 +128,13 @@ static int make_condition_modifier(struct iforce* iforce, unsigned char data[10]; if (!no_alloc) { - mutex_lock(&iforce->mem_mutex); + guard(mutex)(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, - iforce->device_memory.start, iforce->device_memory.end, 2L, - NULL, NULL)) { - mutex_unlock(&iforce->mem_mutex); + iforce->device_memory.start, + iforce->device_memory.end, + 2L, NULL, NULL)) return -ENOSPC; - } - mutex_unlock(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 08c889a72f6c67..74181d5123cd04 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -31,49 +31,42 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) int c; int empty; int head, tail; - unsigned long flags; /* * Update head and tail of xmit buffer */ - spin_lock_irqsave(&iforce->xmit_lock, flags); - - head = iforce->xmit.head; - tail = iforce->xmit.tail; - - - if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { - dev_warn(&iforce->dev->dev, - "not enough space in xmit buffer to send new packet\n"); - spin_unlock_irqrestore(&iforce->xmit_lock, flags); - return -1; - } + scoped_guard(spinlock_irqsave, &iforce->xmit_lock) { + head = iforce->xmit.head; + tail = iforce->xmit.tail; + + if (CIRC_SPACE(head, tail, XMIT_SIZE) < n + 2) { + dev_warn(&iforce->dev->dev, + "not enough space in xmit buffer to send new packet\n"); + return -1; + } - empty = head == tail; - XMIT_INC(iforce->xmit.head, n+2); + empty = head == tail; + XMIT_INC(iforce->xmit.head, n + 2); /* * Store packet in xmit buffer */ - iforce->xmit.buf[head] = HI(cmd); - XMIT_INC(head, 1); - iforce->xmit.buf[head] = LO(cmd); - XMIT_INC(head, 1); - - c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); - if (n < c) c=n; - - memcpy(&iforce->xmit.buf[head], - data, - c); - if (n != c) { - memcpy(&iforce->xmit.buf[0], - data + c, - n - c); + iforce->xmit.buf[head] = HI(cmd); + XMIT_INC(head, 1); + iforce->xmit.buf[head] = LO(cmd); + XMIT_INC(head, 1); + + c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); + if (n < c) + c = n; + + memcpy(&iforce->xmit.buf[head], data, c); + if (n != c) + memcpy(&iforce->xmit.buf[0], data + c, n - c); + + XMIT_INC(head, n); } - XMIT_INC(head, n); - spin_unlock_irqrestore(&iforce->xmit_lock, flags); /* * If necessary, start the transmission */ diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 2380546d79782d..75b85c46dfa419 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -28,45 +28,39 @@ static void iforce_serio_xmit(struct iforce *iforce) iforce); unsigned char cs; int i; - unsigned long flags; if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); return; } - spin_lock_irqsave(&iforce->xmit_lock, flags); + guard(spinlock_irqsave)(&iforce->xmit_lock); -again: - if (iforce->xmit.head == iforce->xmit.tail) { - iforce_clear_xmit_and_wake(iforce); - spin_unlock_irqrestore(&iforce->xmit_lock, flags); - return; - } + do { + if (iforce->xmit.head == iforce->xmit.tail) + break; - cs = 0x2b; + cs = 0x2b; - serio_write(iforce_serio->serio, 0x2b); + serio_write(iforce_serio->serio, 0x2b); - serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]); - cs ^= iforce->xmit.buf[iforce->xmit.tail]; - XMIT_INC(iforce->xmit.tail, 1); - - for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]); cs ^= iforce->xmit.buf[iforce->xmit.tail]; XMIT_INC(iforce->xmit.tail, 1); - } - serio_write(iforce_serio->serio, cs); + for (i = iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { + serio_write(iforce_serio->serio, + iforce->xmit.buf[iforce->xmit.tail]); + cs ^= iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + } - if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) - goto again; + serio_write(iforce_serio->serio, cs); - iforce_clear_xmit_and_wake(iforce); + } while (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)); - spin_unlock_irqrestore(&iforce->xmit_lock, flags); + iforce_clear_xmit_and_wake(iforce); } static int iforce_serio_get_id(struct iforce *iforce, u8 id, diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index cba92bd590a8d8..1f00f76b01745d 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -25,13 +25,11 @@ static void __iforce_usb_xmit(struct iforce *iforce) struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb, iforce); int n, c; - unsigned long flags; - spin_lock_irqsave(&iforce->xmit_lock, flags); + guard(spinlock_irqsave)(&iforce->xmit_lock); if (iforce->xmit.head == iforce->xmit.tail) { iforce_clear_xmit_and_wake(iforce); - spin_unlock_irqrestore(&iforce->xmit_lock, flags); return; } @@ -45,7 +43,8 @@ static void __iforce_usb_xmit(struct iforce *iforce) /* Copy rest of data then */ c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); - if (n < c) c=n; + if (n < c) + c = n; memcpy(iforce_usb->out->transfer_buffer + 1, &iforce->xmit.buf[iforce->xmit.tail], @@ -53,11 +52,12 @@ static void __iforce_usb_xmit(struct iforce *iforce) if (n != c) { memcpy(iforce_usb->out->transfer_buffer + 1 + c, &iforce->xmit.buf[0], - n-c); + n - c); } XMIT_INC(iforce->xmit.tail, n); - if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) { + n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC); + if (n) { dev_warn(&iforce_usb->intf->dev, "usb_submit_urb failed %d\n", n); iforce_clear_xmit_and_wake(iforce); @@ -66,7 +66,6 @@ static void __iforce_usb_xmit(struct iforce *iforce) /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. * As long as the urb completion handler is not called, the transmiting * is considered to be running */ - spin_unlock_irqrestore(&iforce->xmit_lock, flags); } static void iforce_usb_xmit(struct iforce *iforce) diff --git a/drivers/input/joystick/n64joy.c b/drivers/input/joystick/n64joy.c index b0986d2195d689..c344dbc0c493e8 100644 --- a/drivers/input/joystick/n64joy.c +++ b/drivers/input/joystick/n64joy.c @@ -191,35 +191,32 @@ static void n64joy_poll(struct timer_list *t) static int n64joy_open(struct input_dev *dev) { struct n64joy_priv *priv = input_get_drvdata(dev); - int err; - - err = mutex_lock_interruptible(&priv->n64joy_mutex); - if (err) - return err; - - if (!priv->n64joy_opened) { - /* - * We could use the vblank irq, but it's not important if - * the poll point slightly changes. - */ - timer_setup(&priv->timer, n64joy_poll, 0); - mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16)); - } - priv->n64joy_opened++; + scoped_guard(mutex_intr, &priv->n64joy_mutex) { + if (!priv->n64joy_opened) { + /* + * We could use the vblank irq, but it's not important + * if the poll point slightly changes. + */ + timer_setup(&priv->timer, n64joy_poll, 0); + mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16)); + } - mutex_unlock(&priv->n64joy_mutex); - return err; + priv->n64joy_opened++; + return 0; + } + + return -EINTR; } static void n64joy_close(struct input_dev *dev) { struct n64joy_priv *priv = input_get_drvdata(dev); - mutex_lock(&priv->n64joy_mutex); + guard(mutex)(&priv->n64joy_mutex); + if (!--priv->n64joy_opened) del_timer_sync(&priv->timer); - mutex_unlock(&priv->n64joy_mutex); } static const u64 __initconst scandata[] ____cacheline_aligned = { diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 0a78dda3e0ea8e..db696ba61a3bff 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -103,33 +103,31 @@ static void tgfx_timer(struct timer_list *t) static int tgfx_open(struct input_dev *dev) { struct tgfx *tgfx = input_get_drvdata(dev); - int err; - err = mutex_lock_interruptible(&tgfx->sem); - if (err) - return err; + scoped_guard(mutex_intr, &tgfx->sem) { + if (!tgfx->used++) { + parport_claim(tgfx->pd); + parport_write_control(tgfx->pd->port, 0x04); + mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); + } - if (!tgfx->used++) { - parport_claim(tgfx->pd); - parport_write_control(tgfx->pd->port, 0x04); - mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); + return 0; } - mutex_unlock(&tgfx->sem); - return 0; + return -EINTR; } static void tgfx_close(struct input_dev *dev) { struct tgfx *tgfx = input_get_drvdata(dev); - mutex_lock(&tgfx->sem); + guard(mutex)(&tgfx->sem); + if (!--tgfx->used) { del_timer_sync(&tgfx->timer); parport_write_control(tgfx->pd->port, 0x00); parport_release(tgfx->pd); } - mutex_unlock(&tgfx->sem); } diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 22ea58bf76cb5c..ff9bc87f2f7092 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1292,9 +1292,8 @@ static void xpad_irq_out(struct urb *urb) struct device *dev = &xpad->intf->dev; int status = urb->status; int error; - unsigned long flags; - spin_lock_irqsave(&xpad->odata_lock, flags); + guard(spinlock_irqsave)(&xpad->odata_lock); switch (status) { case 0: @@ -1328,8 +1327,6 @@ static void xpad_irq_out(struct urb *urb) xpad->irq_out_active = false; } } - - spin_unlock_irqrestore(&xpad->odata_lock, flags); } static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad, @@ -1394,10 +1391,8 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) { struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_CMD_IDX]; - unsigned long flags; - int retval; - spin_lock_irqsave(&xpad->odata_lock, flags); + guard(spinlock_irqsave)(&xpad->odata_lock); packet->data[0] = 0x08; packet->data[1] = 0x00; @@ -1416,17 +1411,12 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) /* Reset the sequence so we send out presence first */ xpad->last_out_packet = -1; - retval = xpad_try_sending_next_out_packet(xpad); - - spin_unlock_irqrestore(&xpad->odata_lock, flags); - - return retval; + return xpad_try_sending_next_out_packet(xpad); } static int xpad_start_xbox_one(struct usb_xpad *xpad) { - unsigned long flags; - int retval; + int error; if (usb_ifnum_to_if(xpad->udev, GIP_WIRED_INTF_AUDIO)) { /* @@ -1435,15 +1425,15 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad) * 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) + error = usb_set_interface(xpad->udev, + GIP_WIRED_INTF_AUDIO, 0); + if (error) dev_warn(&xpad->dev->dev, "unable to disable audio interface: %d\n", - retval); + error); } - spin_lock_irqsave(&xpad->odata_lock, flags); + guard(spinlock_irqsave)(&xpad->odata_lock); /* * Begin the init sequence by attempting to send a packet. @@ -1451,16 +1441,11 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad) * sending any packets from the output ring. */ xpad->init_seq = 0; - retval = xpad_try_sending_next_out_packet(xpad); - - spin_unlock_irqrestore(&xpad->odata_lock, flags); - - return retval; + return xpad_try_sending_next_out_packet(xpad); } static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) { - unsigned long flags; struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_CMD_IDX]; static const u8 mode_report_ack[] = { @@ -1468,7 +1453,7 @@ static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) 0x00, GIP_CMD_VIRTUAL_KEY, GIP_OPT_INTERNAL, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; - spin_lock_irqsave(&xpad->odata_lock, flags); + guard(spinlock_irqsave)(&xpad->odata_lock); packet->len = sizeof(mode_report_ack); memcpy(packet->data, mode_report_ack, packet->len); @@ -1478,8 +1463,6 @@ static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num) /* Reset the sequence so we send out the ack now */ xpad->last_out_packet = -1; xpad_try_sending_next_out_packet(xpad); - - spin_unlock_irqrestore(&xpad->odata_lock, flags); } #ifdef CONFIG_JOYSTICK_XPAD_FF @@ -1489,8 +1472,6 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX]; __u16 strong; __u16 weak; - int retval; - unsigned long flags; if (effect->type != FF_RUMBLE) return 0; @@ -1498,7 +1479,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect strong = effect->u.rumble.strong_magnitude; weak = effect->u.rumble.weak_magnitude; - spin_lock_irqsave(&xpad->odata_lock, flags); + guard(spinlock_irqsave)(&xpad->odata_lock); switch (xpad->xtype) { case XTYPE_XBOX: @@ -1564,15 +1545,10 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect dev_dbg(&xpad->dev->dev, "%s - rumble command sent to unsupported xpad type: %d\n", __func__, xpad->xtype); - retval = -EINVAL; - goto out; + return -EINVAL; } - retval = xpad_try_sending_next_out_packet(xpad); - -out: - spin_unlock_irqrestore(&xpad->odata_lock, flags); - return retval; + return xpad_try_sending_next_out_packet(xpad); } static int xpad_init_ff(struct usb_xpad *xpad) @@ -1625,11 +1601,10 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command) { struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_LED_IDX]; - unsigned long flags; command %= 16; - spin_lock_irqsave(&xpad->odata_lock, flags); + guard(spinlock_irqsave)(&xpad->odata_lock); switch (xpad->xtype) { case XTYPE_XBOX360: @@ -1659,8 +1634,6 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command) } xpad_try_sending_next_out_packet(xpad); - - spin_unlock_irqrestore(&xpad->odata_lock, flags); } /* @@ -1785,11 +1758,10 @@ static void xpad_stop_input(struct usb_xpad *xpad) static void xpad360w_poweroff_controller(struct usb_xpad *xpad) { - unsigned long flags; struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_CMD_IDX]; - spin_lock_irqsave(&xpad->odata_lock, flags); + guard(spinlock_irqsave)(&xpad->odata_lock); packet->data[0] = 0x00; packet->data[1] = 0x00; @@ -1809,8 +1781,6 @@ static void xpad360w_poweroff_controller(struct usb_xpad *xpad) /* Reset the sequence so we send out poweroff now */ xpad->last_out_packet = -1; xpad_try_sending_next_out_packet(xpad); - - spin_unlock_irqrestore(&xpad->odata_lock, flags); } static int xpad360w_start_input(struct usb_xpad *xpad) @@ -2234,10 +2204,10 @@ static int xpad_suspend(struct usb_interface *intf, pm_message_t message) if (auto_poweroff && xpad->pad_present) xpad360w_poweroff_controller(xpad); } else { - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); + if (input_device_enabled(input)) xpad_stop_input(xpad); - mutex_unlock(&input->mutex); } xpad_stop_output(xpad); @@ -2249,26 +2219,25 @@ static int xpad_resume(struct usb_interface *intf) { struct usb_xpad *xpad = usb_get_intfdata(intf); struct input_dev *input = xpad->dev; - int retval = 0; - if (xpad->xtype == XTYPE_XBOX360W) { - retval = xpad360w_start_input(xpad); - } else { - mutex_lock(&input->mutex); - if (input_device_enabled(input)) { - retval = xpad_start_input(xpad); - } else if (xpad->xtype == XTYPE_XBOXONE) { - /* - * Even if there are no users, we'll send Xbox One pads - * the startup sequence so they don't sit there and - * blink until somebody opens the input device again. - */ - retval = xpad_start_xbox_one(xpad); - } - mutex_unlock(&input->mutex); + if (xpad->xtype == XTYPE_XBOX360W) + return xpad360w_start_input(xpad); + + guard(mutex)(&input->mutex); + + if (input_device_enabled(input)) + return xpad_start_input(xpad); + + if (xpad->xtype == XTYPE_XBOXONE) { + /* + * Even if there are no users, we'll send Xbox One pads + * the startup sequence so they don't sit there and + * blink until somebody opens the input device again. + */ + return xpad_start_xbox_one(xpad); } - return retval; + return 0; } static struct usb_driver xpad_driver = { diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c index 10c248f0c1fcda..980d739e45b87e 100644 --- a/drivers/input/keyboard/adp5520-keys.c +++ b/drivers/input/keyboard/adp5520-keys.c @@ -181,7 +181,7 @@ static struct platform_driver adp5520_keys_driver = { .name = "adp5520-keys", }, .probe = adp5520_keys_probe, - .remove_new = adp5520_keys_remove, + .remove = adp5520_keys_remove, }; module_platform_driver(adp5520_keys_driver); diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 922d3ab998f3a5..81d0876ee358ef 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -411,7 +411,7 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - mutex_lock(&kpad->gpio_lock); + guard(mutex)(&kpad->gpio_lock); if (val) kpad->dat_out[bank] |= bit; @@ -420,8 +420,6 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + bank, kpad->dat_out[bank]); - - mutex_unlock(&kpad->gpio_lock); } static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off) @@ -429,18 +427,13 @@ static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off) struct adp5589_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - int ret; - mutex_lock(&kpad->gpio_lock); + guard(mutex)(&kpad->gpio_lock); kpad->dir[bank] &= ~bit; - ret = adp5589_write(kpad->client, - kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, - kpad->dir[bank]); - - mutex_unlock(&kpad->gpio_lock); - - return ret; + return adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, + kpad->dir[bank]); } static int adp5589_gpio_direction_output(struct gpio_chip *chip, @@ -449,9 +442,9 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, struct adp5589_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - int ret; + int error; - mutex_lock(&kpad->gpio_lock); + guard(mutex)(&kpad->gpio_lock); kpad->dir[bank] |= bit; @@ -460,15 +453,19 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, else kpad->dat_out[bank] &= ~bit; - ret = adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) - + bank, kpad->dat_out[bank]); - ret |= adp5589_write(kpad->client, - kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, - kpad->dir[bank]); + error = adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + bank, + kpad->dat_out[bank]); + if (error) + return error; - mutex_unlock(&kpad->gpio_lock); + error = adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, + kpad->dir[bank]); + if (error) + return error; - return ret; + return 0; } static int adp5589_build_gpiomap(struct adp5589_kpad *kpad, diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c index 2c993fa8306a08..b5ff71cd5a7018 100644 --- a/drivers/input/keyboard/applespi.c +++ b/drivers/input/keyboard/applespi.c @@ -717,9 +717,7 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi); static void applespi_msg_complete(struct applespi_data *applespi, bool is_write_msg, bool is_read_compl) { - unsigned long flags; - - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); + guard(spinlock_irqsave)(&applespi->cmd_msg_lock); if (is_read_compl) applespi->read_active = false; @@ -733,8 +731,6 @@ static void applespi_msg_complete(struct applespi_data *applespi, applespi->cmd_msg_queued = 0; applespi_send_cmd_msg(applespi); } - - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); } static void applespi_async_write_complete(void *context) @@ -888,33 +884,22 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi) static void applespi_init(struct applespi_data *applespi, bool is_resume) { - unsigned long flags; - - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); + guard(spinlock_irqsave)(&applespi->cmd_msg_lock); if (is_resume) applespi->want_mt_init_cmd = true; else applespi->want_tp_info_cmd = true; applespi_send_cmd_msg(applespi); - - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); } static int applespi_set_capsl_led(struct applespi_data *applespi, bool capslock_on) { - unsigned long flags; - int sts; - - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); + guard(spinlock_irqsave)(&applespi->cmd_msg_lock); applespi->want_cl_led_on = capslock_on; - sts = applespi_send_cmd_msg(applespi); - - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); - - return sts; + return applespi_send_cmd_msg(applespi); } static void applespi_set_bl_level(struct led_classdev *led_cdev, @@ -922,9 +907,8 @@ static void applespi_set_bl_level(struct led_classdev *led_cdev, { struct applespi_data *applespi = container_of(led_cdev, struct applespi_data, backlight_info); - unsigned long flags; - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); + guard(spinlock_irqsave)(&applespi->cmd_msg_lock); if (value == 0) { applespi->want_bl_level = value; @@ -940,8 +924,6 @@ static void applespi_set_bl_level(struct led_classdev *led_cdev, } applespi_send_cmd_msg(applespi); - - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); } static int applespi_event(struct input_dev *dev, unsigned int type, @@ -1427,9 +1409,7 @@ static void applespi_got_data(struct applespi_data *applespi) /* process packet header */ if (!applespi_verify_crc(applespi, applespi->rx_buffer, APPLESPI_PACKET_SIZE)) { - unsigned long flags; - - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); + guard(spinlock_irqsave)(&applespi->cmd_msg_lock); if (applespi->drain) { applespi->read_active = false; @@ -1438,8 +1418,6 @@ static void applespi_got_data(struct applespi_data *applespi) wake_up_all(&applespi->drain_complete); } - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); - return; } @@ -1572,11 +1550,10 @@ static u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context) { struct applespi_data *applespi = context; int sts; - unsigned long flags; trace_applespi_irq_received(ET_RD_IRQ, PT_READ); - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); + guard(spinlock_irqsave)(&applespi->cmd_msg_lock); if (!applespi->suspended) { sts = applespi_async(applespi, &applespi->rd_m, @@ -1589,8 +1566,6 @@ static u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context) applespi->read_active = true; } - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); - return ACPI_INTERRUPT_HANDLED; } @@ -1818,29 +1793,21 @@ static int applespi_probe(struct spi_device *spi) static void applespi_drain_writes(struct applespi_data *applespi) { - unsigned long flags; - - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); + guard(spinlock_irqsave)(&applespi->cmd_msg_lock); applespi->drain = true; wait_event_lock_irq(applespi->drain_complete, !applespi->write_active, applespi->cmd_msg_lock); - - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); } static void applespi_drain_reads(struct applespi_data *applespi) { - unsigned long flags; - - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); + guard(spinlock_irqsave)(&applespi->cmd_msg_lock); wait_event_lock_irq(applespi->drain_complete, !applespi->read_active, applespi->cmd_msg_lock); applespi->suspended = true; - - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); } static void applespi_remove(struct spi_device *spi) @@ -1907,21 +1874,18 @@ static int applespi_resume(struct device *dev) struct spi_device *spi = to_spi_device(dev); struct applespi_data *applespi = spi_get_drvdata(spi); acpi_status acpi_sts; - unsigned long flags; /* ensure our flags and state reflect a newly resumed device */ - spin_lock_irqsave(&applespi->cmd_msg_lock, flags); - - applespi->drain = false; - applespi->have_cl_led_on = false; - applespi->have_bl_level = 0; - applespi->cmd_msg_queued = 0; - applespi->read_active = false; - applespi->write_active = false; - - applespi->suspended = false; + scoped_guard(spinlock_irqsave, &applespi->cmd_msg_lock) { + applespi->drain = false; + applespi->have_cl_led_on = false; + applespi->have_bl_level = 0; + applespi->cmd_msg_queued = 0; + applespi->read_active = false; + applespi->write_active = false; - spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); + applespi->suspended = false; + } /* switch on the SPI interface */ applespi_enable_spi(applespi); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 5855d4fc6e6a4d..ec94fcfa4cdebe 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -713,9 +713,9 @@ static int atkbd_event(struct input_dev *dev, static inline void atkbd_enable(struct atkbd *atkbd) { - serio_pause_rx(atkbd->ps2dev.serio); + guard(serio_pause_rx)(atkbd->ps2dev.serio); + atkbd->enabled = true; - serio_continue_rx(atkbd->ps2dev.serio); } /* @@ -725,9 +725,9 @@ static inline void atkbd_enable(struct atkbd *atkbd) static inline void atkbd_disable(struct atkbd *atkbd) { - serio_pause_rx(atkbd->ps2dev.serio); + guard(serio_pause_rx)(atkbd->ps2dev.serio); + atkbd->enabled = false; - serio_continue_rx(atkbd->ps2dev.serio); } static int atkbd_activate(struct atkbd *atkbd) diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index b21ef9d6ff9d66..0c17cbaa3d27aa 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -416,7 +416,7 @@ static int cap11xx_led_set(struct led_classdev *cdev, static int cap11xx_init_leds(struct device *dev, struct cap11xx_priv *priv, int num_leds) { - struct device_node *node = dev->of_node, *child; + struct device_node *node = dev->of_node; struct cap11xx_led *led; int cnt = of_get_child_count(node); int error; @@ -445,7 +445,7 @@ static int cap11xx_init_leds(struct device *dev, if (error) return error; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { u32 reg; led->cdev.name = @@ -458,19 +458,15 @@ static int cap11xx_init_leds(struct device *dev, led->cdev.brightness = LED_OFF; error = of_property_read_u32(child, "reg", ®); - if (error != 0 || reg >= num_leds) { - of_node_put(child); + if (error != 0 || reg >= num_leds) return -EINVAL; - } led->reg = reg; led->priv = priv; error = devm_led_classdev_register(dev, &led->cdev); - if (error) { - of_node_put(child); + if (error) return error; - } priv->num_leds++; led++; diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 4c81b20ff6af94..c1e53d87c8a759 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -770,7 +770,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); static struct platform_driver cros_ec_keyb_driver = { .probe = cros_ec_keyb_probe, - .remove_new = cros_ec_keyb_remove, + .remove = cros_ec_keyb_remove, .driver = { .name = "cros-ec-keyb", .dev_groups = cros_ec_keyb_groups, diff --git a/drivers/input/keyboard/cypress-sf.c b/drivers/input/keyboard/cypress-sf.c index eb1d0720784d97..335b72efc5aa1b 100644 --- a/drivers/input/keyboard/cypress-sf.c +++ b/drivers/input/keyboard/cypress-sf.c @@ -208,7 +208,7 @@ static int cypress_sf_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops, cypress_sf_suspend, cypress_sf_resume); -static struct i2c_device_id cypress_sf_id_table[] = { +static const struct i2c_device_id cypress_sf_id_table[] = { { CYPRESS_SF_DEV_NAME }, { } }; diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index dcbc50304a5a46..817c23438f6e51 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -168,15 +168,13 @@ static int ep93xx_keypad_suspend(struct device *dev) struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (keypad->enabled) { clk_disable(keypad->clk); keypad->enabled = false; } - mutex_unlock(&input_dev->mutex); - return 0; } @@ -186,7 +184,7 @@ static int ep93xx_keypad_resume(struct device *dev) struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) { if (!keypad->enabled) { @@ -196,8 +194,6 @@ static int ep93xx_keypad_resume(struct device *dev) } } - mutex_unlock(&input_dev->mutex); - return 0; } @@ -289,7 +285,7 @@ static struct platform_driver ep93xx_keypad_driver = { .of_match_table = ep93xx_keypad_of_ids, }, .probe = ep93xx_keypad_probe, - .remove_new = ep93xx_keypad_remove, + .remove = ep93xx_keypad_remove, }; module_platform_driver(ep93xx_keypad_driver); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 380fe8dab3b063..5eef66516e379a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -531,12 +531,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, * Legacy GPIO number, so request the GPIO here and * convert it to descriptor. */ - unsigned flags = GPIOF_IN; - - if (button->active_low) - flags |= GPIOF_ACTIVE_LOW; - - error = devm_gpio_request_one(dev, button->gpio, flags, desc); + error = devm_gpio_request_one(dev, button->gpio, GPIOF_IN, desc); if (error < 0) { dev_err(dev, "Failed to request GPIO %d, error %d\n", button->gpio, error); @@ -546,6 +541,9 @@ static int gpio_keys_setup_key(struct platform_device *pdev, bdata->gpiod = gpio_to_desc(button->gpio); if (!bdata->gpiod) return -EINVAL; + + if (button->active_low ^ gpiod_is_active_low(bdata->gpiod)) + gpiod_toggle_active_low(bdata->gpiod); } if (bdata->gpiod) { diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 41ca0d3c909856..e6707d72210e3c 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -306,13 +306,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) * Legacy GPIO number so request the GPIO here and * convert it to descriptor. */ - unsigned flags = GPIOF_IN; - - if (button->active_low) - flags |= GPIOF_ACTIVE_LOW; - - error = devm_gpio_request_one(dev, button->gpio, - flags, button->desc ? : DRV_NAME); + error = devm_gpio_request_one(dev, button->gpio, GPIOF_IN, + button->desc ? : DRV_NAME); if (error) return dev_err_probe(dev, error, "unable to claim gpio %u\n", @@ -325,6 +320,9 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) button->gpio); return -EINVAL; } + + if (button->active_low ^ gpiod_is_active_low(bdata->gpiod)) + gpiod_toggle_active_low(bdata->gpiod); } bdata->last_state = -1; diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index c1a4d5055de633..c8d8d0ea35b0cd 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -180,9 +180,8 @@ static irqreturn_t hil_interrupt(int irq, void *handle) /* send a command to the HIL */ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) { - unsigned long flags; + guard(spinlock_irqsave)(&hil_dev.lock); - spin_lock_irqsave(&hil_dev.lock, flags); while (hil_busy()) /* wait */; hil_command(cmd); @@ -191,7 +190,6 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) /* wait */; hil_write_data(*(data++)); } - spin_unlock_irqrestore(&hil_dev.lock, flags); } diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index e15a93619e827f..b92268ddfd8421 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -521,13 +521,11 @@ static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev) struct input_dev *input_dev = kbd->input_dev; unsigned short reg_val = readw(kbd->mmio_base + KPSR); - /* imx kbd can wake up system even clock is disabled */ - mutex_lock(&input_dev->mutex); - - if (input_device_enabled(input_dev)) - clk_disable_unprepare(kbd->clk); - - mutex_unlock(&input_dev->mutex); + scoped_guard(mutex, &input_dev->mutex) { + /* imx kbd can wake up system even clock is disabled */ + if (input_device_enabled(input_dev)) + clk_disable_unprepare(kbd->clk); + } if (device_may_wakeup(&pdev->dev)) { if (reg_val & KBD_STAT_KPKD) @@ -547,23 +545,20 @@ static int __maybe_unused imx_kbd_noirq_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct imx_keypad *kbd = platform_get_drvdata(pdev); struct input_dev *input_dev = kbd->input_dev; - int ret = 0; + int error; if (device_may_wakeup(&pdev->dev)) disable_irq_wake(kbd->irq); - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) { - ret = clk_prepare_enable(kbd->clk); - if (ret) - goto err_clk; + error = clk_prepare_enable(kbd->clk); + if (error) + return error; } -err_clk: - mutex_unlock(&input_dev->mutex); - - return ret; + return 0; } static const struct dev_pm_ops imx_kbd_pm_ops = { diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c index 1d71dd79ffd289..58631bf7ce5564 100644 --- a/drivers/input/keyboard/ipaq-micro-keys.c +++ b/drivers/input/keyboard/ipaq-micro-keys.c @@ -54,18 +54,18 @@ static void micro_key_receive(void *data, int len, unsigned char *msg) static void micro_key_start(struct ipaq_micro_keys *keys) { - spin_lock(&keys->micro->lock); + guard(spinlock)(&keys->micro->lock); + keys->micro->key = micro_key_receive; keys->micro->key_data = keys; - spin_unlock(&keys->micro->lock); } static void micro_key_stop(struct ipaq_micro_keys *keys) { - spin_lock(&keys->micro->lock); + guard(spinlock)(&keys->micro->lock); + keys->micro->key = NULL; keys->micro->key_data = NULL; - spin_unlock(&keys->micro->lock); } static int micro_key_open(struct input_dev *input) @@ -141,13 +141,11 @@ static int micro_key_resume(struct device *dev) struct ipaq_micro_keys *keys = dev_get_drvdata(dev); struct input_dev *input = keys->input; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (input_device_enabled(input)) micro_key_start(keys); - mutex_unlock(&input->mutex); - return 0; } diff --git a/drivers/input/keyboard/iqs62x-keys.c b/drivers/input/keyboard/iqs62x-keys.c index 1315b0f0862fc0..b086c7b28d5c10 100644 --- a/drivers/input/keyboard/iqs62x-keys.c +++ b/drivers/input/keyboard/iqs62x-keys.c @@ -323,7 +323,7 @@ static struct platform_driver iqs62x_keys_platform_driver = { .name = "iqs62x-keys", }, .probe = iqs62x_keys_probe, - .remove_new = iqs62x_keys_remove, + .remove = iqs62x_keys_remove, }; module_platform_driver(iqs62x_keys_platform_driver); diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index cf67ba13477a41..e26bf295634467 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -350,11 +350,11 @@ static int lm8323_configure(struct lm8323_chip *lm) static void pwm_done(struct lm8323_pwm *pwm) { - mutex_lock(&pwm->lock); + guard(mutex)(&pwm->lock); + pwm->running = false; if (pwm->desired_brightness != pwm->brightness) schedule_work(&pwm->work); - mutex_unlock(&pwm->lock); } /* @@ -367,7 +367,7 @@ static irqreturn_t lm8323_irq(int irq, void *_lm) u8 ints; int i; - mutex_lock(&lm->lock); + guard(mutex)(&lm->lock); while ((lm8323_read(lm, LM8323_CMD_READ_INT, &ints, 1) == 1) && ints) { if (likely(ints & INT_KEYPAD)) @@ -394,8 +394,6 @@ static irqreturn_t lm8323_irq(int irq, void *_lm) } } - mutex_unlock(&lm->lock); - return IRQ_HANDLED; } @@ -445,7 +443,7 @@ static void lm8323_pwm_work(struct work_struct *work) u16 pwm_cmds[3]; int num_cmds = 0; - mutex_lock(&pwm->lock); + guard(mutex)(&pwm->lock); /* * Do nothing if we're already at the requested level, @@ -454,7 +452,7 @@ static void lm8323_pwm_work(struct work_struct *work) * finishes. */ if (pwm->running || pwm->desired_brightness == pwm->brightness) - goto out; + return; kill = (pwm->desired_brightness == 0); up = (pwm->desired_brightness > pwm->brightness); @@ -489,9 +487,6 @@ static void lm8323_pwm_work(struct work_struct *work) lm8323_write_pwm(pwm, kill, num_cmds, pwm_cmds); pwm->brightness = pwm->desired_brightness; - - out: - mutex_unlock(&pwm->lock); } static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev, @@ -500,9 +495,9 @@ static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev, struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev); struct lm8323_chip *lm = pwm->chip; - mutex_lock(&pwm->lock); - pwm->desired_brightness = brightness; - mutex_unlock(&pwm->lock); + scoped_guard(mutex, &pwm->lock) { + pwm->desired_brightness = brightness; + } if (in_interrupt()) { schedule_work(&pwm->work); @@ -510,12 +505,12 @@ static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev, /* * Schedule PWM work as usual unless we are going into suspend */ - mutex_lock(&lm->lock); - if (likely(!lm->pm_suspend)) - schedule_work(&pwm->work); - else - lm8323_pwm_work(&pwm->work); - mutex_unlock(&lm->lock); + scoped_guard(mutex, &lm->lock) { + if (likely(!lm->pm_suspend)) + schedule_work(&pwm->work); + else + lm8323_pwm_work(&pwm->work); + } } } @@ -608,9 +603,9 @@ static ssize_t lm8323_set_disable(struct device *dev, if (ret) return ret; - mutex_lock(&lm->lock); + guard(mutex)(&lm->lock); + lm->kp_enabled = !i; - mutex_unlock(&lm->lock); return count; } @@ -758,9 +753,9 @@ static int lm8323_suspend(struct device *dev) irq_set_irq_wake(client->irq, 0); disable_irq(client->irq); - mutex_lock(&lm->lock); - lm->pm_suspend = true; - mutex_unlock(&lm->lock); + scoped_guard(mutex, &lm->lock) { + lm->pm_suspend = true; + } for (i = 0; i < 3; i++) if (lm->pwm[i].enabled) @@ -775,9 +770,9 @@ static int lm8323_resume(struct device *dev) struct lm8323_chip *lm = i2c_get_clientdata(client); int i; - mutex_lock(&lm->lock); - lm->pm_suspend = false; - mutex_unlock(&lm->lock); + scoped_guard(mutex, &lm->lock) { + lm->pm_suspend = false; + } for (i = 0; i < 3; i++) if (lm->pwm[i].enabled) diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index 4b0f8323c4922f..c501a93a441786 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -112,11 +112,10 @@ static inline void locomokbd_reset_col(unsigned long membase, int col) static void locomokbd_scankeyboard(struct locomokbd *locomokbd) { unsigned int row, col, rowd; - unsigned long flags; unsigned int num_pressed; unsigned long membase = locomokbd->base; - spin_lock_irqsave(&locomokbd->lock, flags); + guard(spinlock_irqsave)(&locomokbd->lock); locomokbd_charge_all(membase); @@ -167,8 +166,6 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd) mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL); else locomokbd->count_cancel = 0; - - spin_unlock_irqrestore(&locomokbd->lock, flags); } /* diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 423035be86fb83..2392e7ec3b1911 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -262,7 +262,7 @@ static int lpc32xx_kscan_suspend(struct device *dev) struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); struct input_dev *input = kscandat->input; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (input_device_enabled(input)) { /* Clear IRQ and disable clock */ @@ -270,7 +270,6 @@ static int lpc32xx_kscan_suspend(struct device *dev) clk_disable_unprepare(kscandat->clk); } - mutex_unlock(&input->mutex); return 0; } @@ -279,19 +278,20 @@ static int lpc32xx_kscan_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); struct input_dev *input = kscandat->input; - int retval = 0; + int error; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (input_device_enabled(input)) { /* Enable clock and clear IRQ */ - retval = clk_prepare_enable(kscandat->clk); - if (retval == 0) - writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + error = clk_prepare_enable(kscandat->clk); + if (error) + return error; + + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); } - mutex_unlock(&input->mutex); - return retval; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(lpc32xx_kscan_pm_ops, lpc32xx_kscan_suspend, diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index 91a1d295810943..1a8f1fa53fbb4e 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -132,14 +132,11 @@ static void dc_kbd_callback(struct mapleq *mq) * We should always get the lock because the only * time it may be locked is if the driver is in the cleanup phase. */ - if (likely(mutex_trylock(&maple_keyb_mutex))) { - + scoped_guard(mutex_try, &maple_keyb_mutex) { if (buf[1] == mapledev->function) { memcpy(kbd->new, buf + 2, 8); dc_scan_kbd(kbd); } - - mutex_unlock(&maple_keyb_mutex); } } @@ -211,14 +208,12 @@ static int remove_maple_kbd(struct device *dev) struct maple_device *mdev = to_maple_dev(dev); struct dc_kbd *kbd = maple_get_drvdata(mdev); - mutex_lock(&maple_keyb_mutex); + guard(mutex)(&maple_keyb_mutex); input_unregister_device(kbd->dev); kfree(kbd); maple_set_drvdata(mdev, NULL); - - mutex_unlock(&maple_keyb_mutex); return 0; } diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 3c38bae576edd6..2a3b3bfc2878ba 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -158,18 +157,17 @@ static void matrix_keypad_scan(struct work_struct *work) activate_all_cols(keypad, true); /* Enable IRQs again */ - spin_lock_irq(&keypad->lock); - keypad->scan_pending = false; - enable_row_irqs(keypad); - spin_unlock_irq(&keypad->lock); + scoped_guard(spinlock_irq, &keypad->lock) { + keypad->scan_pending = false; + enable_row_irqs(keypad); + } } static irqreturn_t matrix_keypad_interrupt(int irq, void *id) { struct matrix_keypad *keypad = id; - unsigned long flags; - spin_lock_irqsave(&keypad->lock, flags); + guard(spinlock_irqsave)(&keypad->lock); /* * See if another IRQ beaten us to it and scheduled the @@ -185,7 +183,6 @@ static irqreturn_t matrix_keypad_interrupt(int irq, void *id) msecs_to_jiffies(keypad->debounce_ms)); out: - spin_unlock_irqrestore(&keypad->lock, flags); return IRQ_HANDLED; } @@ -209,9 +206,9 @@ static void matrix_keypad_stop(struct input_dev *dev) { struct matrix_keypad *keypad = input_get_drvdata(dev); - spin_lock_irq(&keypad->lock); - keypad->stopped = true; - spin_unlock_irq(&keypad->lock); + scoped_guard(spinlock_irq, &keypad->lock) { + keypad->stopped = true; + } flush_delayed_work(&keypad->work); /* diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 21827d2497fa7c..bd1a944ded46fd 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -82,42 +82,6 @@ static const struct mpr121_init_register init_reg_table[] = { { AUTO_CONFIG_CTRL_ADDR, 0x0b }, }; -static void mpr121_vdd_supply_disable(void *data) -{ - struct regulator *vdd_supply = data; - - regulator_disable(vdd_supply); -} - -static struct regulator *mpr121_vdd_supply_init(struct device *dev) -{ - struct regulator *vdd_supply; - int err; - - vdd_supply = devm_regulator_get(dev, "vdd"); - if (IS_ERR(vdd_supply)) { - dev_err(dev, "failed to get vdd regulator: %ld\n", - PTR_ERR(vdd_supply)); - return vdd_supply; - } - - err = regulator_enable(vdd_supply); - if (err) { - dev_err(dev, "failed to enable vdd regulator: %d\n", err); - return ERR_PTR(err); - } - - err = devm_add_action_or_reset(dev, mpr121_vdd_supply_disable, - vdd_supply); - if (err) { - dev_err(dev, "failed to add disable regulator action: %d\n", - err); - return ERR_PTR(err); - } - - return vdd_supply; -} - static void mpr_touchkey_report(struct input_dev *dev) { struct mpr121_touchkey *mpr121 = input_get_drvdata(dev); @@ -233,7 +197,6 @@ static int mpr121_phys_init(struct mpr121_touchkey *mpr121, static int mpr_touchkey_probe(struct i2c_client *client) { struct device *dev = &client->dev; - struct regulator *vdd_supply; int vdd_uv; struct mpr121_touchkey *mpr121; struct input_dev *input_dev; @@ -241,11 +204,9 @@ static int mpr_touchkey_probe(struct i2c_client *client) int error; int i; - vdd_supply = mpr121_vdd_supply_init(dev); - if (IS_ERR(vdd_supply)) - return PTR_ERR(vdd_supply); - - vdd_uv = regulator_get_voltage(vdd_supply); + vdd_uv = devm_regulator_get_enable_read_voltage(dev, "vdd"); + if (vdd_uv < 0) + return dev_err_probe(dev, vdd_uv, "failed to get vdd voltage\n"); mpr121 = devm_kzalloc(dev, sizeof(*mpr121), GFP_KERNEL); if (!mpr121) diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c index 4364c3401ff1c6..5ad6be9141603a 100644 --- a/drivers/input/keyboard/mtk-pmic-keys.c +++ b/drivers/input/keyboard/mtk-pmic-keys.c @@ -307,7 +307,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) int error, index = 0; unsigned int keycount; struct mt6397_chip *pmic_chip = dev_get_drvdata(pdev->dev.parent); - struct device_node *node = pdev->dev.of_node, *child; + struct device_node *node = pdev->dev.of_node; static const char *const irqnames[] = { "powerkey", "homekey" }; static const char *const irqnames_r[] = { "powerkey_r", "homekey_r" }; struct mtk_pmic_keys *keys; @@ -343,24 +343,20 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) return -EINVAL; } - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index]; keys->keys[index].irq = platform_get_irq_byname(pdev, irqnames[index]); - if (keys->keys[index].irq < 0) { - of_node_put(child); + if (keys->keys[index].irq < 0) return keys->keys[index].irq; - } if (of_device_is_compatible(node, "mediatek,mt6358-keys")) { keys->keys[index].irq_r = platform_get_irq_byname(pdev, irqnames_r[index]); - if (keys->keys[index].irq_r < 0) { - of_node_put(child); + if (keys->keys[index].irq_r < 0) return keys->keys[index].irq_r; - } } error = of_property_read_u32(child, @@ -369,7 +365,6 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) dev_err(keys->dev, "failed to read key:%d linux,keycode property: %d\n", index, error); - of_node_put(child); return error; } @@ -377,10 +372,8 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) keys->keys[index].wakeup = true; error = mtk_pmic_key_setup(keys, &keys->keys[index]); - if (error) { - of_node_put(child); + if (error) return error; - } index++; } diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 57587541110b63..9e13f3f70a81c6 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -156,15 +156,15 @@ static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute if ((state != 1) && (state != 0)) return -EINVAL; - mutex_lock(&kp_enable_mutex); - if (state != kp_enable) { - if (state) - enable_irq(omap_kp->irq); - else - disable_irq(omap_kp->irq); - kp_enable = state; + scoped_guard(mutex, &kp_enable_mutex) { + if (state != kp_enable) { + if (state) + enable_irq(omap_kp->irq); + else + disable_irq(omap_kp->irq); + kp_enable = state; + } } - mutex_unlock(&kp_enable_mutex); return strnlen(buf, count); } @@ -290,7 +290,7 @@ static void omap_kp_remove(struct platform_device *pdev) static struct platform_driver omap_kp_driver = { .probe = omap_kp_probe, - .remove_new = omap_kp_remove, + .remove = omap_kp_remove, .driver = { .name = "omap-keypad", .dev_groups = omap_kp_groups, diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 040b340995d89d..bffe89c0717adf 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -144,7 +144,7 @@ static void omap4_keypad_scan_keys(struct omap4_keypad *keypad_data, u64 keys) { u64 changed; - mutex_lock(&keypad_data->lock); + guard(mutex)(&keypad_data->lock); changed = keys ^ keypad_data->keys; @@ -158,8 +158,6 @@ static void omap4_keypad_scan_keys(struct omap4_keypad *keypad_data, u64 keys) omap4_keypad_report_keys(keypad_data, changed & keys, true); keypad_data->keys = keys; - - mutex_unlock(&keypad_data->lock); } /* Interrupt handlers */ @@ -487,7 +485,7 @@ MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); static struct platform_driver omap4_keypad_driver = { .probe = omap4_keypad_probe, - .remove_new = omap4_keypad_remove, + .remove = omap4_keypad_remove, .driver = { .name = "omap4-keypad", .of_match_table = omap_keypad_dt_match, diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 26a005f9ace3b5..35d1aa2a22a55f 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -630,12 +630,10 @@ static int pmic8xxx_kp_suspend(struct device *dev) if (device_may_wakeup(dev)) { enable_irq_wake(kp->key_sense_irq); } else { - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) pmic8xxx_kp_disable(kp); - - mutex_unlock(&input_dev->mutex); } return 0; @@ -650,12 +648,10 @@ static int pmic8xxx_kp_resume(struct device *dev) if (device_may_wakeup(dev)) { disable_irq_wake(kp->key_sense_irq); } else { - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) pmic8xxx_kp_enable(kp); - - mutex_unlock(&input_dev->mutex); } return 0; diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 3724363d140e5f..38ec619aa35906 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -682,7 +682,7 @@ static int pxa27x_keypad_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; - int ret = 0; + int error; /* * If the keypad is used as wake up source, the clock is not turned @@ -691,19 +691,19 @@ static int pxa27x_keypad_resume(struct device *dev) if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(keypad->irq); } else { - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) { /* Enable unit clock */ - ret = clk_prepare_enable(keypad->clk); - if (!ret) - pxa27x_keypad_config(keypad); - } + error = clk_prepare_enable(keypad->clk); + if (error) + return error; - mutex_unlock(&input_dev->mutex); + pxa27x_keypad_config(keypad); + } } - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops, diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index e212eff7687c01..9f1049aa3048c8 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -587,7 +587,7 @@ MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); static struct platform_driver samsung_keypad_driver = { .probe = samsung_keypad_probe, - .remove_new = samsung_keypad_remove, + .remove = samsung_keypad_remove, .driver = { .name = "samsung-keypad", .of_match_table = of_match_ptr(samsung_keypad_dt_match), diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 4ea4fd25c5d20e..159f41eedd410d 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -319,7 +319,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops, static struct platform_driver sh_keysc_device_driver = { .probe = sh_keysc_probe, - .remove_new = sh_keysc_remove, + .remove = sh_keysc_remove, .driver = { .name = "sh_keysc", .pm = pm_sleep_ptr(&sh_keysc_dev_pm_ops), diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 1df4feb8ba0178..2fae337562a23d 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -274,7 +273,7 @@ static int spear_kbd_suspend(struct device *dev) struct input_dev *input_dev = kbd->input; unsigned int rate = 0, mode_ctl_reg, val; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); /* explicitly enable clock as we may program device */ clk_enable(kbd->clk); @@ -315,8 +314,6 @@ static int spear_kbd_suspend(struct device *dev) /* restore previous clk state */ clk_disable(kbd->clk); - mutex_unlock(&input_dev->mutex); - return 0; } @@ -326,7 +323,7 @@ static int spear_kbd_resume(struct device *dev) struct spear_kbd *kbd = platform_get_drvdata(pdev); struct input_dev *input_dev = kbd->input; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (device_may_wakeup(&pdev->dev)) { if (kbd->irq_wake_enabled) { @@ -342,8 +339,6 @@ static int spear_kbd_resume(struct device *dev) if (input_device_enabled(input_dev)) writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG); - mutex_unlock(&input_dev->mutex); - return 0; } diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c index 0d27324af809b2..e53ef4c670e4b8 100644 --- a/drivers/input/keyboard/st-keyscan.c +++ b/drivers/input/keyboard/st-keyscan.c @@ -216,14 +216,13 @@ static int keyscan_suspend(struct device *dev) struct st_keyscan *keypad = platform_get_drvdata(pdev); struct input_dev *input = keypad->input_dev; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (device_may_wakeup(dev)) enable_irq_wake(keypad->irq); else if (input_device_enabled(input)) keyscan_stop(keypad); - mutex_unlock(&input->mutex); return 0; } @@ -232,17 +231,19 @@ static int keyscan_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct st_keyscan *keypad = platform_get_drvdata(pdev); struct input_dev *input = keypad->input_dev; - int retval = 0; + int error; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); - if (device_may_wakeup(dev)) + if (device_may_wakeup(dev)) { disable_irq_wake(keypad->irq); - else if (input_device_enabled(input)) - retval = keyscan_start(keypad); + } else if (input_device_enabled(input)) { + error = keyscan_start(keypad); + if (error) + return error; + } - mutex_unlock(&input->mutex); - return retval; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index ef2f440278943a..0acded4fb9c9c0 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -414,7 +414,7 @@ static void stmpe_keypad_remove(struct platform_device *pdev) static struct platform_driver stmpe_keypad_driver = { .driver.name = "stmpe-keypad", .probe = stmpe_keypad_probe, - .remove_new = stmpe_keypad_remove, + .remove = stmpe_keypad_remove, }; module_platform_driver(stmpe_keypad_driver); diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c index f304cab0ebdb83..5730f08f82d79a 100644 --- a/drivers/input/keyboard/sun4i-lradc-keys.c +++ b/drivers/input/keyboard/sun4i-lradc-keys.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -202,7 +201,7 @@ static void sun4i_lradc_close(struct input_dev *dev) static int sun4i_lradc_load_dt_keymap(struct device *dev, struct sun4i_lradc_data *lradc) { - struct device_node *np, *pp; + struct device_node *np; int i; int error; @@ -223,28 +222,25 @@ static int sun4i_lradc_load_dt_keymap(struct device *dev, return -ENOMEM; i = 0; - for_each_child_of_node(np, pp) { + for_each_child_of_node_scoped(np, pp) { struct sun4i_lradc_keymap *map = &lradc->chan0_map[i]; u32 channel; error = of_property_read_u32(pp, "channel", &channel); if (error || channel != 0) { dev_err(dev, "%pOFn: Inval channel prop\n", pp); - of_node_put(pp); return -EINVAL; } error = of_property_read_u32(pp, "voltage", &map->voltage); if (error) { dev_err(dev, "%pOFn: Inval voltage prop\n", pp); - of_node_put(pp); return -EINVAL; } error = of_property_read_u32(pp, "linux,code", &map->keycode); if (error) { dev_err(dev, "%pOFn: Inval linux,code prop\n", pp); - of_node_put(pp); return -EINVAL; } diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 72fb46029710db..3299e1919b370b 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -241,9 +241,8 @@ static void sunkbd_reinit(struct work_struct *work) static void sunkbd_enable(struct sunkbd *sunkbd, bool enable) { - serio_pause_rx(sunkbd->serio); - sunkbd->enabled = enable; - serio_continue_rx(sunkbd->serio); + scoped_guard(serio_pause_rx, sunkbd->serio) + sunkbd->enabled = enable; if (!enable) { wake_up_interruptible(&sunkbd->wait); diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c index 6477a41c4bac3e..9159b5fec129c2 100644 --- a/drivers/input/misc/88pm80x_onkey.c +++ b/drivers/input/misc/88pm80x_onkey.c @@ -141,7 +141,7 @@ static struct platform_driver pm80x_onkey_driver = { .pm = &pm80x_onkey_pm_ops, }, .probe = pm80x_onkey_probe, - .remove_new = pm80x_onkey_remove, + .remove = pm80x_onkey_remove, }; module_platform_driver(pm80x_onkey_driver); diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index 1acd8429c56c97..d106f37df6bcbe 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c @@ -941,7 +941,7 @@ static irqreturn_t ad714x_interrupt_thread(int irq, void *data) struct ad714x_chip *ad714x = data; int i; - mutex_lock(&ad714x->mutex); + guard(mutex)(&ad714x->mutex); ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3); @@ -954,8 +954,6 @@ static irqreturn_t ad714x_interrupt_thread(int irq, void *data) for (i = 0; i < ad714x->hw->touchpad_num; i++) ad714x_touchpad_state_machine(ad714x, i); - mutex_unlock(&ad714x->mutex); - return IRQ_HANDLED; } @@ -1169,13 +1167,11 @@ static int ad714x_suspend(struct device *dev) dev_dbg(ad714x->dev, "%s enter\n", __func__); - mutex_lock(&ad714x->mutex); + guard(mutex)(&ad714x->mutex); data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3; ad714x->write(ad714x, AD714X_PWR_CTRL, data); - mutex_unlock(&ad714x->mutex); - return 0; } @@ -1184,7 +1180,7 @@ static int ad714x_resume(struct device *dev) struct ad714x_chip *ad714x = dev_get_drvdata(dev); dev_dbg(ad714x->dev, "%s enter\n", __func__); - mutex_lock(&ad714x->mutex); + guard(mutex)(&ad714x->mutex); /* resume to non-shutdown mode */ @@ -1197,8 +1193,6 @@ static int ad714x_resume(struct device *dev) ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3); - mutex_unlock(&ad714x->mutex); - return 0; } diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 795f69edb4b27e..e84649af801ddd 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -244,29 +244,21 @@ static int ati_remote2_open(struct input_dev *idev) if (r) { dev_err(&ar2->intf[0]->dev, "%s(): usb_autopm_get_interface() = %d\n", __func__, r); - goto fail1; + return r; } - mutex_lock(&ati_remote2_mutex); + scoped_guard(mutex, &ati_remote2_mutex) { + if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) { + r = ati_remote2_submit_urbs(ar2); + if (r) + break; + } - if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) { - r = ati_remote2_submit_urbs(ar2); - if (r) - goto fail2; + ar2->flags |= ATI_REMOTE2_OPENED; } - ar2->flags |= ATI_REMOTE2_OPENED; - - mutex_unlock(&ati_remote2_mutex); - usb_autopm_put_interface(ar2->intf[0]); - return 0; - - fail2: - mutex_unlock(&ati_remote2_mutex); - usb_autopm_put_interface(ar2->intf[0]); - fail1: return r; } @@ -276,14 +268,12 @@ static void ati_remote2_close(struct input_dev *idev) dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); - mutex_lock(&ati_remote2_mutex); + guard(mutex)(&ati_remote2_mutex); if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) ati_remote2_kill_urbs(ar2); ar2->flags &= ~ATI_REMOTE2_OPENED; - - mutex_unlock(&ati_remote2_mutex); } static void ati_remote2_input_mouse(struct ati_remote2 *ar2) @@ -713,16 +703,14 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev, return r; } - mutex_lock(&ati_remote2_mutex); - - if (mask != ar2->channel_mask) { - r = ati_remote2_setup(ar2, mask); - if (!r) - ar2->channel_mask = mask; + scoped_guard(mutex, &ati_remote2_mutex) { + if (mask != ar2->channel_mask) { + r = ati_remote2_setup(ar2, mask); + if (!r) + ar2->channel_mask = mask; + } } - mutex_unlock(&ati_remote2_mutex); - usb_autopm_put_interface(ar2->intf[0]); return r ? r : count; @@ -892,15 +880,13 @@ static int ati_remote2_suspend(struct usb_interface *interface, dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); - mutex_lock(&ati_remote2_mutex); + guard(mutex)(&ati_remote2_mutex); if (ar2->flags & ATI_REMOTE2_OPENED) ati_remote2_kill_urbs(ar2); ar2->flags |= ATI_REMOTE2_SUSPENDED; - mutex_unlock(&ati_remote2_mutex); - return 0; } @@ -917,7 +903,7 @@ static int ati_remote2_resume(struct usb_interface *interface) dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); - mutex_lock(&ati_remote2_mutex); + guard(mutex)(&ati_remote2_mutex); if (ar2->flags & ATI_REMOTE2_OPENED) r = ati_remote2_submit_urbs(ar2); @@ -925,8 +911,6 @@ static int ati_remote2_resume(struct usb_interface *interface) if (!r) ar2->flags &= ~ATI_REMOTE2_SUSPENDED; - mutex_unlock(&ati_remote2_mutex); - return r; } @@ -943,11 +927,11 @@ static int ati_remote2_reset_resume(struct usb_interface *interface) dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); - mutex_lock(&ati_remote2_mutex); + guard(mutex)(&ati_remote2_mutex); r = ati_remote2_setup(ar2, ar2->channel_mask); if (r) - goto out; + return r; if (ar2->flags & ATI_REMOTE2_OPENED) r = ati_remote2_submit_urbs(ar2); @@ -955,9 +939,6 @@ static int ati_remote2_reset_resume(struct usb_interface *interface) if (!r) ar2->flags &= ~ATI_REMOTE2_SUSPENDED; - out: - mutex_unlock(&ati_remote2_mutex); - return r; } diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c index 728325a2d574ac..0cfe5d4a573c61 100644 --- a/drivers/input/misc/cm109.c +++ b/drivers/input/misc/cm109.c @@ -355,6 +355,35 @@ static void cm109_submit_buzz_toggle(struct cm109_dev *dev) __func__, error); } +static void cm109_submit_ctl(struct cm109_dev *dev) +{ + int error; + + guard(spinlock_irqsave)(&dev->ctl_submit_lock); + + dev->irq_urb_pending = 0; + + if (unlikely(dev->shutdown)) + return; + + if (dev->buzzer_state) + dev->ctl_data->byte[HID_OR0] |= BUZZER_ON; + else + dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON; + + dev->ctl_data->byte[HID_OR1] = dev->keybit; + dev->ctl_data->byte[HID_OR2] = dev->keybit; + + dev->buzzer_pending = 0; + dev->ctl_urb_pending = 1; + + error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC); + if (error) + dev_err(&dev->intf->dev, + "%s: usb_submit_urb (urb_ctl) failed %d\n", + __func__, error); +} + /* * IRQ handler */ @@ -362,8 +391,6 @@ static void cm109_urb_irq_callback(struct urb *urb) { struct cm109_dev *dev = urb->context; const int status = urb->status; - int error; - unsigned long flags; dev_dbg(&dev->intf->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n", dev->irq_data->byte[0], @@ -401,32 +428,7 @@ static void cm109_urb_irq_callback(struct urb *urb) } out: - - spin_lock_irqsave(&dev->ctl_submit_lock, flags); - - dev->irq_urb_pending = 0; - - if (likely(!dev->shutdown)) { - - if (dev->buzzer_state) - dev->ctl_data->byte[HID_OR0] |= BUZZER_ON; - else - dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON; - - dev->ctl_data->byte[HID_OR1] = dev->keybit; - dev->ctl_data->byte[HID_OR2] = dev->keybit; - - dev->buzzer_pending = 0; - dev->ctl_urb_pending = 1; - - error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC); - if (error) - dev_err(&dev->intf->dev, - "%s: usb_submit_urb (urb_ctl) failed %d\n", - __func__, error); - } - - spin_unlock_irqrestore(&dev->ctl_submit_lock, flags); + cm109_submit_ctl(dev); } static void cm109_urb_ctl_callback(struct urb *urb) @@ -434,7 +436,6 @@ static void cm109_urb_ctl_callback(struct urb *urb) struct cm109_dev *dev = urb->context; const int status = urb->status; int error; - unsigned long flags; dev_dbg(&dev->intf->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n", dev->ctl_data->byte[0], @@ -449,35 +450,31 @@ static void cm109_urb_ctl_callback(struct urb *urb) __func__, status); } - spin_lock_irqsave(&dev->ctl_submit_lock, flags); + guard(spinlock_irqsave)(&dev->ctl_submit_lock); dev->ctl_urb_pending = 0; - if (likely(!dev->shutdown)) { - - if (dev->buzzer_pending || status) { - dev->buzzer_pending = 0; - dev->ctl_urb_pending = 1; - cm109_submit_buzz_toggle(dev); - } else if (likely(!dev->irq_urb_pending)) { - /* ask for key data */ - dev->irq_urb_pending = 1; - error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC); - if (error) - dev_err(&dev->intf->dev, - "%s: usb_submit_urb (urb_irq) failed %d\n", - __func__, error); - } - } + if (unlikely(dev->shutdown)) + return; - spin_unlock_irqrestore(&dev->ctl_submit_lock, flags); + if (dev->buzzer_pending || status) { + dev->buzzer_pending = 0; + dev->ctl_urb_pending = 1; + cm109_submit_buzz_toggle(dev); + } else if (likely(!dev->irq_urb_pending)) { + /* ask for key data */ + dev->irq_urb_pending = 1; + error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC); + if (error) + dev_err(&dev->intf->dev, + "%s: usb_submit_urb (urb_irq) failed %d\n", + __func__, error); + } } static void cm109_toggle_buzzer_async(struct cm109_dev *dev) { - unsigned long flags; - - spin_lock_irqsave(&dev->ctl_submit_lock, flags); + guard(spinlock_irqsave)(&dev->ctl_submit_lock); if (dev->ctl_urb_pending) { /* URB completion will resubmit */ @@ -486,8 +483,6 @@ static void cm109_toggle_buzzer_async(struct cm109_dev *dev) dev->ctl_urb_pending = 1; cm109_submit_buzz_toggle(dev); } - - spin_unlock_irqrestore(&dev->ctl_submit_lock, flags); } static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on) @@ -556,32 +551,30 @@ static int cm109_input_open(struct input_dev *idev) return error; } - mutex_lock(&dev->pm_mutex); - - dev->buzzer_state = 0; - dev->key_code = -1; /* no keys pressed */ - dev->keybit = 0xf; + scoped_guard(mutex, &dev->pm_mutex) { + dev->buzzer_state = 0; + dev->key_code = -1; /* no keys pressed */ + dev->keybit = 0xf; - /* issue INIT */ - dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF; - dev->ctl_data->byte[HID_OR1] = dev->keybit; - dev->ctl_data->byte[HID_OR2] = dev->keybit; - dev->ctl_data->byte[HID_OR3] = 0x00; + /* issue INIT */ + dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF; + dev->ctl_data->byte[HID_OR1] = dev->keybit; + dev->ctl_data->byte[HID_OR2] = dev->keybit; + dev->ctl_data->byte[HID_OR3] = 0x00; - dev->ctl_urb_pending = 1; - error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL); - if (error) { - dev->ctl_urb_pending = 0; - dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n", - __func__, error); - } else { - dev->open = 1; + dev->ctl_urb_pending = 1; + error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL); + if (!error) { + dev->open = 1; + return 0; + } } - mutex_unlock(&dev->pm_mutex); + dev->ctl_urb_pending = 0; + usb_autopm_put_interface(dev->intf); - if (error) - usb_autopm_put_interface(dev->intf); + dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n", + __func__, error); return error; } @@ -590,17 +583,15 @@ static void cm109_input_close(struct input_dev *idev) { struct cm109_dev *dev = input_get_drvdata(idev); - mutex_lock(&dev->pm_mutex); - - /* - * Once we are here event delivery is stopped so we - * don't need to worry about someone starting buzzer - * again - */ - cm109_stop_traffic(dev); - dev->open = 0; - - mutex_unlock(&dev->pm_mutex); + scoped_guard(mutex, &dev->pm_mutex) { + /* + * Once we are here event delivery is stopped so we + * don't need to worry about someone starting buzzer + * again + */ + cm109_stop_traffic(dev); + dev->open = 0; + } usb_autopm_put_interface(dev->intf); } @@ -823,9 +814,9 @@ static int cm109_usb_suspend(struct usb_interface *intf, pm_message_t message) dev_info(&intf->dev, "cm109: usb_suspend (event=%d)\n", message.event); - mutex_lock(&dev->pm_mutex); + guard(mutex)(&dev->pm_mutex); + cm109_stop_traffic(dev); - mutex_unlock(&dev->pm_mutex); return 0; } @@ -836,9 +827,9 @@ static int cm109_usb_resume(struct usb_interface *intf) dev_info(&intf->dev, "cm109: usb_resume\n"); - mutex_lock(&dev->pm_mutex); + guard(mutex)(&dev->pm_mutex); + cm109_restore_state(dev); - mutex_unlock(&dev->pm_mutex); return 0; } diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index 0c68e924a1ccdc..cfc12332bee149 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -217,15 +217,13 @@ static int cma3000_open(struct input_dev *input_dev) { struct cma3000_accl_data *data = input_get_drvdata(input_dev); - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); if (!data->suspended) cma3000_poweron(data); data->opened = true; - mutex_unlock(&data->mutex); - return 0; } @@ -233,40 +231,34 @@ static void cma3000_close(struct input_dev *input_dev) { struct cma3000_accl_data *data = input_get_drvdata(input_dev); - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); if (!data->suspended) cma3000_poweroff(data); data->opened = false; - - mutex_unlock(&data->mutex); } void cma3000_suspend(struct cma3000_accl_data *data) { - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); if (!data->suspended && data->opened) cma3000_poweroff(data); data->suspended = true; - - mutex_unlock(&data->mutex); } EXPORT_SYMBOL(cma3000_suspend); void cma3000_resume(struct cma3000_accl_data *data) { - mutex_lock(&data->mutex); + guard(mutex)(&data->mutex); if (data->suspended && data->opened) cma3000_poweron(data); data->suspended = false; - - mutex_unlock(&data->mutex); } EXPORT_SYMBOL(cma3000_resume); diff --git a/drivers/input/misc/cs40l50-vibra.c b/drivers/input/misc/cs40l50-vibra.c index 03bdb7c26ec09f..dce3b0ec8cf368 100644 --- a/drivers/input/misc/cs40l50-vibra.c +++ b/drivers/input/misc/cs40l50-vibra.c @@ -334,11 +334,12 @@ static int cs40l50_add(struct input_dev *dev, struct ff_effect *effect, work_data.custom_len = effect->u.periodic.custom_len; work_data.vib = vib; work_data.effect = effect; - INIT_WORK(&work_data.work, cs40l50_add_worker); + INIT_WORK_ONSTACK(&work_data.work, cs40l50_add_worker); /* Push to the workqueue to serialize with playbacks */ queue_work(vib->vib_wq, &work_data.work); flush_work(&work_data.work); + destroy_work_on_stack(&work_data.work); kfree(work_data.custom_data); @@ -467,11 +468,12 @@ static int cs40l50_erase(struct input_dev *dev, int effect_id) work_data.vib = vib; work_data.effect = &dev->ff->effects[effect_id]; - INIT_WORK(&work_data.work, cs40l50_erase_worker); + INIT_WORK_ONSTACK(&work_data.work, cs40l50_erase_worker); /* Push to workqueue to serialize with playbacks */ queue_work(vib->vib_wq, &work_data.work); flush_work(&work_data.work); + destroy_work_on_stack(&work_data.work); return work_data.error; } diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c index 1629b7ea4cbd4a..e4a605c6af1508 100644 --- a/drivers/input/misc/da7280.c +++ b/drivers/input/misc/da7280.c @@ -1263,39 +1263,37 @@ static int da7280_suspend(struct device *dev) { struct da7280_haptic *haptics = dev_get_drvdata(dev); - mutex_lock(&haptics->input_dev->mutex); + guard(mutex)(&haptics->input_dev->mutex); /* * Make sure no new requests will be submitted while device is * suspended. */ - spin_lock_irq(&haptics->input_dev->event_lock); - haptics->suspended = true; - spin_unlock_irq(&haptics->input_dev->event_lock); + scoped_guard(spinlock_irq, &haptics->input_dev->event_lock) { + haptics->suspended = true; + } da7280_haptic_stop(haptics); - mutex_unlock(&haptics->input_dev->mutex); - return 0; } static int da7280_resume(struct device *dev) { struct da7280_haptic *haptics = dev_get_drvdata(dev); - int retval; + int error; - mutex_lock(&haptics->input_dev->mutex); + guard(mutex)(&haptics->input_dev->mutex); - retval = da7280_haptic_start(haptics); - if (!retval) { - spin_lock_irq(&haptics->input_dev->event_lock); + error = da7280_haptic_start(haptics); + if (error) + return error; + + scoped_guard(spinlock_irq, &haptics->input_dev->event_lock) { haptics->suspended = false; - spin_unlock_irq(&haptics->input_dev->event_lock); } - mutex_unlock(&haptics->input_dev->mutex); - return retval; + return 0; } #ifdef CONFIG_OF diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index 7a1122e1efb9cc..cc23625019e34d 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c @@ -140,8 +140,8 @@ static void da9052_onkey_remove(struct platform_device *pdev) static struct platform_driver da9052_onkey_driver = { .probe = da9052_onkey_probe, - .remove_new = da9052_onkey_remove, - .driver = { + .remove = da9052_onkey_remove, + .driver = { .name = "da9052-onkey", }, }; diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c index 871812f1b398e8..3e4fc2f010119e 100644 --- a/drivers/input/misc/da9055_onkey.c +++ b/drivers/input/misc/da9055_onkey.c @@ -145,8 +145,8 @@ static void da9055_onkey_remove(struct platform_device *pdev) static struct platform_driver da9055_onkey_driver = { .probe = da9055_onkey_probe, - .remove_new = da9055_onkey_remove, - .driver = { + .remove = da9055_onkey_remove, + .driver = { .name = "da9055-onkey", }, }; diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 61b503835aa6d1..96cd6a078c8abf 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -537,64 +537,62 @@ static int drv260x_probe(struct i2c_client *client) static int drv260x_suspend(struct device *dev) { struct drv260x_data *haptics = dev_get_drvdata(dev); - int ret = 0; + int error; - mutex_lock(&haptics->input_dev->mutex); + guard(mutex)(&haptics->input_dev->mutex); if (input_device_enabled(haptics->input_dev)) { - ret = regmap_update_bits(haptics->regmap, - DRV260X_MODE, - DRV260X_STANDBY_MASK, - DRV260X_STANDBY); - if (ret) { + error = regmap_update_bits(haptics->regmap, + DRV260X_MODE, + DRV260X_STANDBY_MASK, + DRV260X_STANDBY); + if (error) { dev_err(dev, "Failed to set standby mode\n"); - goto out; + return error; } gpiod_set_value(haptics->enable_gpio, 0); - ret = regulator_disable(haptics->regulator); - if (ret) { + error = regulator_disable(haptics->regulator); + if (error) { dev_err(dev, "Failed to disable regulator\n"); regmap_update_bits(haptics->regmap, DRV260X_MODE, DRV260X_STANDBY_MASK, 0); + return error; } } -out: - mutex_unlock(&haptics->input_dev->mutex); - return ret; + + return 0; } static int drv260x_resume(struct device *dev) { struct drv260x_data *haptics = dev_get_drvdata(dev); - int ret = 0; + int error; - mutex_lock(&haptics->input_dev->mutex); + guard(mutex)(&haptics->input_dev->mutex); if (input_device_enabled(haptics->input_dev)) { - ret = regulator_enable(haptics->regulator); - if (ret) { + error = regulator_enable(haptics->regulator); + if (error) { dev_err(dev, "Failed to enable regulator\n"); - goto out; + return error; } - ret = regmap_update_bits(haptics->regmap, - DRV260X_MODE, - DRV260X_STANDBY_MASK, 0); - if (ret) { + error = regmap_update_bits(haptics->regmap, + DRV260X_MODE, + DRV260X_STANDBY_MASK, 0); + if (error) { dev_err(dev, "Failed to unset standby mode\n"); regulator_disable(haptics->regulator); - goto out; + return error; } gpiod_set_value(haptics->enable_gpio, 1); } -out: - mutex_unlock(&haptics->input_dev->mutex); - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume); diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index f98e4d76530774..46842cb8ddd788 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -15,7 +15,7 @@ #include #include -/* Contol registers */ +/* Control registers */ #define DRV2665_STATUS 0x00 #define DRV2665_CTRL_1 0x01 #define DRV2665_CTRL_2 0x02 @@ -225,59 +225,57 @@ static int drv2665_probe(struct i2c_client *client) static int drv2665_suspend(struct device *dev) { struct drv2665_data *haptics = dev_get_drvdata(dev); - int ret = 0; + int error; - mutex_lock(&haptics->input_dev->mutex); + guard(mutex)(&haptics->input_dev->mutex); if (input_device_enabled(haptics->input_dev)) { - ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, - DRV2665_STANDBY, DRV2665_STANDBY); - if (ret) { + error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, + DRV2665_STANDBY, DRV2665_STANDBY); + if (error) { dev_err(dev, "Failed to set standby mode\n"); regulator_disable(haptics->regulator); - goto out; + return error; } - ret = regulator_disable(haptics->regulator); - if (ret) { + error = regulator_disable(haptics->regulator); + if (error) { dev_err(dev, "Failed to disable regulator\n"); regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, DRV2665_STANDBY, 0); + return error; } } -out: - mutex_unlock(&haptics->input_dev->mutex); - return ret; + + return 0; } static int drv2665_resume(struct device *dev) { struct drv2665_data *haptics = dev_get_drvdata(dev); - int ret = 0; + int error; - mutex_lock(&haptics->input_dev->mutex); + guard(mutex)(&haptics->input_dev->mutex); if (input_device_enabled(haptics->input_dev)) { - ret = regulator_enable(haptics->regulator); - if (ret) { + error = regulator_enable(haptics->regulator); + if (error) { dev_err(dev, "Failed to enable regulator\n"); - goto out; + return error; } - ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, - DRV2665_STANDBY, 0); - if (ret) { + error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, + DRV2665_STANDBY, 0); + if (error) { dev_err(dev, "Failed to unset standby mode\n"); regulator_disable(haptics->regulator); - goto out; + return error; } } -out: - mutex_unlock(&haptics->input_dev->mutex); - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume); diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index ad49845374b9bf..f952a24ec595be 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -16,7 +16,7 @@ #include #include -/* Contol registers */ +/* Control registers */ #define DRV2667_STATUS 0x00 #define DRV2667_CTRL_1 0x01 #define DRV2667_CTRL_2 0x02 @@ -402,59 +402,57 @@ static int drv2667_probe(struct i2c_client *client) static int drv2667_suspend(struct device *dev) { struct drv2667_data *haptics = dev_get_drvdata(dev); - int ret = 0; + int error; - mutex_lock(&haptics->input_dev->mutex); + guard(mutex)(&haptics->input_dev->mutex); if (input_device_enabled(haptics->input_dev)) { - ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, - DRV2667_STANDBY, DRV2667_STANDBY); - if (ret) { + error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, + DRV2667_STANDBY, DRV2667_STANDBY); + if (error) { dev_err(dev, "Failed to set standby mode\n"); regulator_disable(haptics->regulator); - goto out; + return error; } - ret = regulator_disable(haptics->regulator); - if (ret) { + error = regulator_disable(haptics->regulator); + if (error) { dev_err(dev, "Failed to disable regulator\n"); regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, DRV2667_STANDBY, 0); + return error; } } -out: - mutex_unlock(&haptics->input_dev->mutex); - return ret; + + return 0; } static int drv2667_resume(struct device *dev) { struct drv2667_data *haptics = dev_get_drvdata(dev); - int ret = 0; + int error; - mutex_lock(&haptics->input_dev->mutex); + guard(mutex)(&haptics->input_dev->mutex); if (input_device_enabled(haptics->input_dev)) { - ret = regulator_enable(haptics->regulator); - if (ret) { + error = regulator_enable(haptics->regulator); + if (error) { dev_err(dev, "Failed to enable regulator\n"); - goto out; + return error; } - ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, - DRV2667_STANDBY, 0); - if (ret) { + error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, + DRV2667_STANDBY, 0); + if (error) { dev_err(dev, "Failed to unset standby mode\n"); regulator_disable(haptics->regulator); - goto out; + return error; } } -out: - mutex_unlock(&haptics->input_dev->mutex); - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume); diff --git a/drivers/input/misc/ibm-panel.c b/drivers/input/misc/ibm-panel.c index 867ac7aa10d2c1..aa48f62d7ea054 100644 --- a/drivers/input/misc/ibm-panel.c +++ b/drivers/input/misc/ibm-panel.c @@ -77,12 +77,11 @@ static void ibm_panel_process_command(struct ibm_panel *panel) static int ibm_panel_i2c_slave_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) { - unsigned long flags; struct ibm_panel *panel = i2c_get_clientdata(client); dev_dbg(&panel->input->dev, "event: %u data: %02x\n", event, *val); - spin_lock_irqsave(&panel->lock, flags); + guard(spinlock_irqsave)(&panel->lock); switch (event) { case I2C_SLAVE_STOP: @@ -114,8 +113,6 @@ static int ibm_panel_i2c_slave_cb(struct i2c_client *client, break; } - spin_unlock_irqrestore(&panel->lock, flags); - return 0; } diff --git a/drivers/input/misc/ideapad_slidebar.c b/drivers/input/misc/ideapad_slidebar.c index fa4e7f67d71367..f6e5fc807b4dfc 100644 --- a/drivers/input/misc/ideapad_slidebar.c +++ b/drivers/input/misc/ideapad_slidebar.c @@ -23,7 +23,7 @@ * * The value is in byte range, however, I only figured out * how bits 0b10011001 work. Some other bits, probably, - * are meaningfull too. + * are meaningful too. * * Possible states: * @@ -95,41 +95,29 @@ static struct platform_device *slidebar_platform_dev; static u8 slidebar_pos_get(void) { - u8 res; - unsigned long flags; + guard(spinlock_irqsave)(&io_lock); - spin_lock_irqsave(&io_lock, flags); outb(0xf4, 0xff29); outb(0xbf, 0xff2a); - res = inb(0xff2b); - spin_unlock_irqrestore(&io_lock, flags); - - return res; + return inb(0xff2b); } static u8 slidebar_mode_get(void) { - u8 res; - unsigned long flags; + guard(spinlock_irqsave)(&io_lock); - spin_lock_irqsave(&io_lock, flags); outb(0xf7, 0xff29); outb(0x8b, 0xff2a); - res = inb(0xff2b); - spin_unlock_irqrestore(&io_lock, flags); - - return res; + return inb(0xff2b); } static void slidebar_mode_set(u8 mode) { - unsigned long flags; + guard(spinlock_irqsave)(&io_lock); - spin_lock_irqsave(&io_lock, flags); outb(0xf7, 0xff29); outb(0x8b, 0xff2a); outb(mode, 0xff2b); - spin_unlock_irqrestore(&io_lock, flags); } static bool slidebar_i8042_filter(unsigned char data, unsigned char str, @@ -267,7 +255,7 @@ static struct platform_driver slidebar_drv = { .driver = { .name = "ideapad_slidebar", }, - .remove_new = ideapad_remove, + .remove = ideapad_remove, }; static int __init ideapad_dmi_check(const struct dmi_system_id *id) diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index 4215f9b9c2b07a..d9ee14b1f45184 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -739,7 +739,7 @@ static int ims_pcu_switch_to_bootloader(struct ims_pcu *pcu) { int error; - /* Execute jump to the bootoloader */ + /* Execute jump to the bootloader */ error = ims_pcu_execute_command(pcu, JUMP_TO_BTLDR, NULL, 0); if (error) { dev_err(pcu->dev, diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c index 843f8a3f3410d4..1851848e2cd38f 100644 --- a/drivers/input/misc/iqs269a.c +++ b/drivers/input/misc/iqs269a.c @@ -365,7 +365,7 @@ static int iqs269_ati_mode_set(struct iqs269_private *iqs269, if (mode > IQS269_CHx_ENG_A_ATI_MODE_MAX) return -EINVAL; - mutex_lock(&iqs269->lock); + guard(mutex)(&iqs269->lock); engine_a = be16_to_cpu(ch_reg[ch_num].engine_a); @@ -375,8 +375,6 @@ static int iqs269_ati_mode_set(struct iqs269_private *iqs269, ch_reg[ch_num].engine_a = cpu_to_be16(engine_a); iqs269->ati_current = false; - mutex_unlock(&iqs269->lock); - return 0; } @@ -389,9 +387,9 @@ static int iqs269_ati_mode_get(struct iqs269_private *iqs269, if (ch_num >= IQS269_NUM_CH) return -EINVAL; - mutex_lock(&iqs269->lock); + guard(mutex)(&iqs269->lock); + engine_a = be16_to_cpu(ch_reg[ch_num].engine_a); - mutex_unlock(&iqs269->lock); engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK; *mode = (engine_a >> IQS269_CHx_ENG_A_ATI_MODE_SHIFT); @@ -429,7 +427,7 @@ static int iqs269_ati_base_set(struct iqs269_private *iqs269, return -EINVAL; } - mutex_lock(&iqs269->lock); + guard(mutex)(&iqs269->lock); engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); @@ -439,8 +437,6 @@ static int iqs269_ati_base_set(struct iqs269_private *iqs269, ch_reg[ch_num].engine_b = cpu_to_be16(engine_b); iqs269->ati_current = false; - mutex_unlock(&iqs269->lock); - return 0; } @@ -453,9 +449,9 @@ static int iqs269_ati_base_get(struct iqs269_private *iqs269, if (ch_num >= IQS269_NUM_CH) return -EINVAL; - mutex_lock(&iqs269->lock); + guard(mutex)(&iqs269->lock); + engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); - mutex_unlock(&iqs269->lock); switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) { case IQS269_CHx_ENG_B_ATI_BASE_75: @@ -491,7 +487,7 @@ static int iqs269_ati_target_set(struct iqs269_private *iqs269, if (target > IQS269_CHx_ENG_B_ATI_TARGET_MAX) return -EINVAL; - mutex_lock(&iqs269->lock); + guard(mutex)(&iqs269->lock); engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); @@ -501,8 +497,6 @@ static int iqs269_ati_target_set(struct iqs269_private *iqs269, ch_reg[ch_num].engine_b = cpu_to_be16(engine_b); iqs269->ati_current = false; - mutex_unlock(&iqs269->lock); - return 0; } @@ -515,10 +509,9 @@ static int iqs269_ati_target_get(struct iqs269_private *iqs269, if (ch_num >= IQS269_NUM_CH) return -EINVAL; - mutex_lock(&iqs269->lock); - engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); - mutex_unlock(&iqs269->lock); + guard(mutex)(&iqs269->lock); + engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); *target = (engine_b & IQS269_CHx_ENG_B_ATI_TARGET_MASK) * 32; return 0; @@ -557,7 +550,6 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269, const struct fwnode_handle *ch_node) { struct i2c_client *client = iqs269->client; - struct fwnode_handle *ev_node; struct iqs269_ch_reg *ch_reg; u16 engine_a, engine_b; unsigned int reg, val; @@ -734,8 +726,9 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269, } for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { - ev_node = fwnode_get_named_child_node(ch_node, - iqs269_events[i].name); + struct fwnode_handle *ev_node __free(fwnode_handle) = + fwnode_get_named_child_node(ch_node, + iqs269_events[i].name); if (!ev_node) continue; @@ -744,7 +737,6 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269, dev_err(&client->dev, "Invalid channel %u threshold: %u\n", reg, val); - fwnode_handle_put(ev_node); return -EINVAL; } @@ -758,7 +750,6 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269, dev_err(&client->dev, "Invalid channel %u hysteresis: %u\n", reg, val); - fwnode_handle_put(ev_node); return -EINVAL; } @@ -774,7 +765,6 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269, } error = fwnode_property_read_u32(ev_node, "linux,code", &val); - fwnode_handle_put(ev_node); if (error == -EINVAL) { continue; } else if (error) { @@ -1199,7 +1189,7 @@ static int iqs269_dev_init(struct iqs269_private *iqs269) { int error; - mutex_lock(&iqs269->lock); + guard(mutex)(&iqs269->lock); /* * Early revisions of silicon require the following workaround in order @@ -1210,19 +1200,19 @@ static int iqs269_dev_init(struct iqs269_private *iqs269) error = regmap_multi_reg_write(iqs269->regmap, iqs269_tws_init, ARRAY_SIZE(iqs269_tws_init)); if (error) - goto err_mutex; + return error; } error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI, IQS269_HALL_UI_ENABLE, iqs269->hall_enable ? ~0 : 0); if (error) - goto err_mutex; + return error; error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS, &iqs269->sys_reg, sizeof(iqs269->sys_reg)); if (error) - goto err_mutex; + return error; /* * The following delay gives the device time to deassert its RDY output @@ -1232,10 +1222,7 @@ static int iqs269_dev_init(struct iqs269_private *iqs269) iqs269->ati_current = true; -err_mutex: - mutex_unlock(&iqs269->lock); - - return error; + return 0; } static int iqs269_input_init(struct iqs269_private *iqs269) @@ -1580,13 +1567,11 @@ static ssize_t hall_enable_store(struct device *dev, if (error) return error; - mutex_lock(&iqs269->lock); + guard(mutex)(&iqs269->lock); iqs269->hall_enable = val; iqs269->ati_current = false; - mutex_unlock(&iqs269->lock); - return count; } @@ -1643,13 +1628,11 @@ static ssize_t rx_enable_store(struct device *dev, if (val > 0xFF) return -EINVAL; - mutex_lock(&iqs269->lock); + guard(mutex)(&iqs269->lock); ch_reg[iqs269->ch_num].rx_enable = val; iqs269->ati_current = false; - mutex_unlock(&iqs269->lock); - return count; } diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c index 0dab54d3a0603b..7a6e6927f33125 100644 --- a/drivers/input/misc/iqs626a.c +++ b/drivers/input/misc/iqs626a.c @@ -462,7 +462,6 @@ iqs626_parse_events(struct iqs626_private *iqs626, { struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg; struct i2c_client *client = iqs626->client; - struct fwnode_handle *ev_node; const char *ev_name; u8 *thresh, *hyst; unsigned int val; @@ -501,6 +500,7 @@ iqs626_parse_events(struct iqs626_private *iqs626, if (!iqs626_channels[ch_id].events[i]) continue; + struct fwnode_handle *ev_node __free(fwnode_handle) = NULL; if (ch_id == IQS626_CH_TP_2 || ch_id == IQS626_CH_TP_3) { /* * Trackpad touch events are simply described under the @@ -530,7 +530,6 @@ iqs626_parse_events(struct iqs626_private *iqs626, dev_err(&client->dev, "Invalid input type: %u\n", val); - fwnode_handle_put(ev_node); return -EINVAL; } @@ -545,7 +544,6 @@ iqs626_parse_events(struct iqs626_private *iqs626, dev_err(&client->dev, "Invalid %s channel hysteresis: %u\n", fwnode_get_name(ch_node), val); - fwnode_handle_put(ev_node); return -EINVAL; } @@ -566,7 +564,6 @@ iqs626_parse_events(struct iqs626_private *iqs626, dev_err(&client->dev, "Invalid %s channel threshold: %u\n", fwnode_get_name(ch_node), val); - fwnode_handle_put(ev_node); return -EINVAL; } @@ -575,8 +572,6 @@ iqs626_parse_events(struct iqs626_private *iqs626, else *(thresh + iqs626_events[i].th_offs) = val; } - - fwnode_handle_put(ev_node); } return 0; @@ -774,12 +769,12 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626, for (i = 0; i < iqs626_channels[ch_id].num_ch; i++) { u8 *ati_base = &sys_reg->tp_grp_reg.ch_reg_tp[i].ati_base; u8 *thresh = &sys_reg->tp_grp_reg.ch_reg_tp[i].thresh; - struct fwnode_handle *tc_node; char tc_name[10]; snprintf(tc_name, sizeof(tc_name), "channel-%d", i); - tc_node = fwnode_get_named_child_node(ch_node, tc_name); + struct fwnode_handle *tc_node __free(fwnode_handle) = + fwnode_get_named_child_node(ch_node, tc_name); if (!tc_node) continue; @@ -790,7 +785,6 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626, dev_err(&client->dev, "Invalid %s %s ATI base: %u\n", fwnode_get_name(ch_node), tc_name, val); - fwnode_handle_put(tc_node); return -EINVAL; } @@ -803,14 +797,11 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626, dev_err(&client->dev, "Invalid %s %s threshold: %u\n", fwnode_get_name(ch_node), tc_name, val); - fwnode_handle_put(tc_node); return -EINVAL; } *thresh = val; } - - fwnode_handle_put(tc_node); } if (!fwnode_property_present(ch_node, "linux,keycodes")) @@ -1233,7 +1224,6 @@ static int iqs626_parse_prop(struct iqs626_private *iqs626) { struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg; struct i2c_client *client = iqs626->client; - struct fwnode_handle *ch_node; unsigned int val; int error, i; u16 general; @@ -1375,13 +1365,13 @@ static int iqs626_parse_prop(struct iqs626_private *iqs626) sys_reg->active = 0; for (i = 0; i < ARRAY_SIZE(iqs626_channels); i++) { - ch_node = device_get_named_child_node(&client->dev, - iqs626_channels[i].name); + struct fwnode_handle *ch_node __free(fwnode_handle) = + device_get_named_child_node(&client->dev, + iqs626_channels[i].name); if (!ch_node) continue; error = iqs626_parse_channel(iqs626, ch_node, i); - fwnode_handle_put(ch_node); if (error) return error; diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c index be80a31de9f8f4..22022d11470dbe 100644 --- a/drivers/input/misc/iqs7222.c +++ b/drivers/input/misc/iqs7222.c @@ -2385,9 +2385,9 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) { const char *event_name = iqs7222_kp_events[i].name; u16 event_enable = iqs7222_kp_events[i].enable; - struct fwnode_handle *event_node; - event_node = fwnode_get_named_child_node(chan_node, event_name); + struct fwnode_handle *event_node __free(fwnode_handle) = + fwnode_get_named_child_node(chan_node, event_name); if (!event_node) continue; @@ -2408,7 +2408,6 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, dev_err(&client->dev, "Invalid %s press timeout: %u\n", fwnode_get_name(event_node), val); - fwnode_handle_put(event_node); return -EINVAL; } @@ -2418,7 +2417,6 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, dev_err(&client->dev, "Failed to read %s press timeout: %d\n", fwnode_get_name(event_node), error); - fwnode_handle_put(event_node); return error; } @@ -2429,7 +2427,6 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, dev_desc->touch_link - (i ? 0 : 2), &iqs7222->kp_type[chan_index][i], &iqs7222->kp_code[chan_index][i]); - fwnode_handle_put(event_node); if (error) return error; @@ -2604,10 +2601,10 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) { const char *event_name = iqs7222_sl_events[i].name; - struct fwnode_handle *event_node; enum iqs7222_reg_key_id reg_key; - event_node = fwnode_get_named_child_node(sldr_node, event_name); + struct fwnode_handle *event_node __free(fwnode_handle) = + fwnode_get_named_child_node(sldr_node, event_name); if (!event_node) continue; @@ -2639,7 +2636,6 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, : sldr_setup[4 + reg_offset], NULL, &iqs7222->sl_code[sldr_index][i]); - fwnode_handle_put(event_node); if (error) return error; @@ -2742,9 +2738,9 @@ static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222, for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) { const char *event_name = iqs7222_tp_events[i].name; - struct fwnode_handle *event_node; - event_node = fwnode_get_named_child_node(tpad_node, event_name); + struct fwnode_handle *event_node __free(fwnode_handle) = + fwnode_get_named_child_node(tpad_node, event_name); if (!event_node) continue; @@ -2760,7 +2756,6 @@ static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222, iqs7222_tp_events[i].link, 1566, NULL, &iqs7222->tp_code[i]); - fwnode_handle_put(event_node); if (error) return error; @@ -2818,9 +2813,9 @@ static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222, int reg_grp_index) { struct i2c_client *client = iqs7222->client; - struct fwnode_handle *reg_grp_node; int error; + struct fwnode_handle *reg_grp_node __free(fwnode_handle) = NULL; if (iqs7222_reg_grp_names[reg_grp]) { char reg_grp_name[16]; @@ -2838,14 +2833,17 @@ static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222, error = iqs7222_parse_props(iqs7222, reg_grp_node, reg_grp_index, reg_grp, IQS7222_REG_KEY_NONE); + if (error) + return error; - if (!error && iqs7222_parse_extra[reg_grp]) + if (iqs7222_parse_extra[reg_grp]) { error = iqs7222_parse_extra[reg_grp](iqs7222, reg_grp_node, reg_grp_index); + if (error) + return error; + } - fwnode_handle_put(reg_grp_node); - - return error; + return 0; } static int iqs7222_parse_all(struct iqs7222_private *iqs7222) diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index 837682cb2a7d39..eb9788ea521556 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -25,7 +25,7 @@ /* CONTROL REGISTER 1 BITS */ #define PC1_OFF 0x7F #define PC1_ON (1 << 7) -/* Data ready funtion enable bit: set during probe if using irq mode */ +/* Data ready function enable bit: set during probe if using irq mode */ #define DRDYE (1 << 5) /* DATA CONTROL REGISTER BITS */ #define ODR12_5F 0 @@ -314,9 +314,8 @@ static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr, return error; /* Lock the device to prevent races with open/close (and itself) */ - mutex_lock(&input_dev->mutex); - - disable_irq(client->irq); + guard(mutex)(&input_dev->mutex); + guard(disable_irq)(&client->irq); /* * Set current interval to the greater of the minimum interval or @@ -326,9 +325,6 @@ static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr, kxtj9_update_odr(tj9, tj9->last_poll_interval); - enable_irq(client->irq); - mutex_unlock(&input_dev->mutex); - return count; } @@ -504,12 +500,11 @@ static int kxtj9_suspend(struct device *dev) struct kxtj9_data *tj9 = i2c_get_clientdata(client); struct input_dev *input_dev = tj9->input_dev; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) kxtj9_disable(tj9); - mutex_unlock(&input_dev->mutex); return 0; } @@ -519,12 +514,11 @@ static int kxtj9_resume(struct device *dev) struct kxtj9_data *tj9 = i2c_get_clientdata(client); struct input_dev *input_dev = tj9->input_dev; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) kxtj9_enable(tj9); - mutex_unlock(&input_dev->mutex); return 0; } diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c index 3fe0a85c45e00a..0542334df62463 100644 --- a/drivers/input/misc/m68kspkr.c +++ b/drivers/input/misc/m68kspkr.c @@ -95,7 +95,7 @@ static struct platform_driver m68kspkr_platform_driver = { .name = "m68kspkr", }, .probe = m68kspkr_probe, - .remove_new = m68kspkr_remove, + .remove = m68kspkr_remove, .shutdown = m68kspkr_shutdown, }; diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index 11cac4b7dddc08..f97f341ee0bb2e 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -153,19 +153,19 @@ static void max8997_haptic_enable(struct max8997_haptic *chip) { int error; - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); error = max8997_haptic_set_duty_cycle(chip); if (error) { dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error); - goto out; + return; } if (!chip->enabled) { error = regulator_enable(chip->regulator); if (error) { dev_err(chip->dev, "Failed to enable regulator\n"); - goto out; + return; } max8997_haptic_configure(chip); if (chip->mode == MAX8997_EXTERNAL_MODE) { @@ -173,19 +173,16 @@ static void max8997_haptic_enable(struct max8997_haptic *chip) if (error) { dev_err(chip->dev, "Failed to enable PWM\n"); regulator_disable(chip->regulator); - goto out; + return; } } chip->enabled = true; } - -out: - mutex_unlock(&chip->mutex); } static void max8997_haptic_disable(struct max8997_haptic *chip) { - mutex_lock(&chip->mutex); + guard(mutex)(&chip->mutex); if (chip->enabled) { chip->enabled = false; @@ -194,8 +191,6 @@ static void max8997_haptic_disable(struct max8997_haptic *chip) pwm_disable(chip->pwm); regulator_disable(chip->regulator); } - - mutex_unlock(&chip->mutex); } static void max8997_haptic_play_effect_work(struct work_struct *work) @@ -389,7 +384,7 @@ static struct platform_driver max8997_haptic_driver = { .pm = pm_sleep_ptr(&max8997_haptic_pm_ops), }, .probe = max8997_haptic_probe, - .remove_new = max8997_haptic_remove, + .remove = max8997_haptic_remove, .id_table = max8997_haptic_id, }; module_platform_driver(max8997_haptic_driver); diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index 1c8c939638f6cd..1c7faa9b7afe04 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c @@ -253,7 +253,7 @@ static void mc13783_pwrbutton_remove(struct platform_device *pdev) static struct platform_driver mc13783_pwrbutton_driver = { .probe = mc13783_pwrbutton_probe, - .remove_new = mc13783_pwrbutton_remove, + .remove = mc13783_pwrbutton_remove, .driver = { .name = "mc13783-pwrbutton", }, diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c index 06d5972e8e84dc..39fc451c56e924 100644 --- a/drivers/input/misc/palmas-pwrbutton.c +++ b/drivers/input/misc/palmas-pwrbutton.c @@ -310,7 +310,7 @@ MODULE_DEVICE_TABLE(of, of_palmas_pwr_match); static struct platform_driver palmas_pwron_driver = { .probe = palmas_pwron_probe, - .remove_new = palmas_pwron_remove, + .remove = palmas_pwron_remove, .driver = { .name = "palmas_pwrbutton", .of_match_table = of_match_ptr(of_palmas_pwr_match), diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c index f8954a2cab24d1..fe43fd72ba7b0e 100644 --- a/drivers/input/misc/pcap_keys.c +++ b/drivers/input/misc/pcap_keys.c @@ -112,7 +112,7 @@ static void pcap_keys_remove(struct platform_device *pdev) static struct platform_driver pcap_keys_device_driver = { .probe = pcap_keys_probe, - .remove_new = pcap_keys_remove, + .remove = pcap_keys_remove, .driver = { .name = "pcap-keys", } diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c index c5c5fe236c182c..6d046e236ba690 100644 --- a/drivers/input/misc/pcf50633-input.c +++ b/drivers/input/misc/pcf50633-input.c @@ -103,7 +103,7 @@ static struct platform_driver pcf50633_input_driver = { .name = "pcf50633-input", }, .probe = pcf50633_input_probe, - .remove_new = pcf50633_input_remove, + .remove = pcf50633_input_remove, }; module_platform_driver(pcf50633_input_driver); diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 897854fd245f18..0467808402f241 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -127,7 +127,7 @@ static struct platform_driver pcspkr_platform_driver = { .pm = &pcspkr_pm_ops, }, .probe = pcspkr_probe, - .remove_new = pcspkr_remove, + .remove = pcspkr_remove, .shutdown = pcspkr_shutdown, }; module_platform_driver(pcspkr_platform_driver); diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c index bab710023d8f1c..d0c46665e52703 100644 --- a/drivers/input/misc/pm8941-pwrkey.c +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -465,7 +465,7 @@ MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table); static struct platform_driver pm8941_pwrkey_driver = { .probe = pm8941_pwrkey_probe, - .remove_new = pm8941_pwrkey_remove, + .remove = pm8941_pwrkey_remove, .driver = { .name = "pm8941-pwrkey", .pm = pm_sleep_ptr(&pm8941_pwr_key_pm_ops), diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index 4b039abffc4b85..ecb92ee5ebbc0c 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -194,22 +194,18 @@ static void powermate_sync_state(struct powermate_device *pm) static void powermate_config_complete(struct urb *urb) { struct powermate_device *pm = urb->context; - unsigned long flags; if (urb->status) printk(KERN_ERR "powermate: config urb returned %d\n", urb->status); - spin_lock_irqsave(&pm->lock, flags); + guard(spinlock_irqsave)(&pm->lock); powermate_sync_state(pm); - spin_unlock_irqrestore(&pm->lock, flags); } /* Set the LED up as described and begin the sync with the hardware if required */ static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, int pulse_table, int pulse_asleep, int pulse_awake) { - unsigned long flags; - if (pulse_speed < 0) pulse_speed = 0; if (pulse_table < 0) @@ -222,8 +218,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne pulse_asleep = !!pulse_asleep; pulse_awake = !!pulse_awake; - - spin_lock_irqsave(&pm->lock, flags); + guard(spinlock_irqsave)(&pm->lock); /* mark state updates which are required */ if (static_brightness != pm->static_brightness) { @@ -245,8 +240,6 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne } powermate_sync_state(pm); - - spin_unlock_irqrestore(&pm->lock, flags); } /* Callback from the Input layer when an event arrives from userspace to configure the LED */ diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index 5b9aedf4362f49..0e19e97d98ec27 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -203,9 +203,9 @@ static int pwm_beeper_suspend(struct device *dev) * beeper->suspended, but to ensure that pwm_beeper_event * does not re-submit work once flag is set. */ - spin_lock_irq(&beeper->input->event_lock); - beeper->suspended = true; - spin_unlock_irq(&beeper->input->event_lock); + scoped_guard(spinlock_irq, &beeper->input->event_lock) { + beeper->suspended = true; + } pwm_beeper_stop(beeper); @@ -216,9 +216,9 @@ static int pwm_beeper_resume(struct device *dev) { struct pwm_beeper *beeper = dev_get_drvdata(dev); - spin_lock_irq(&beeper->input->event_lock); - beeper->suspended = false; - spin_unlock_irq(&beeper->input->event_lock); + scoped_guard(spinlock_irq, &beeper->input->event_lock) { + beeper->suspended = false; + } /* Let worker figure out if we should resume beeping */ schedule_work(&beeper->work); diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c index 02f73b7c046283..3666ba6d1f307f 100644 --- a/drivers/input/misc/regulator-haptic.c +++ b/drivers/input/misc/regulator-haptic.c @@ -83,12 +83,10 @@ static void regulator_haptic_work(struct work_struct *work) struct regulator_haptic *haptic = container_of(work, struct regulator_haptic, work); - mutex_lock(&haptic->mutex); + guard(mutex)(&haptic->mutex); if (!haptic->suspended) regulator_haptic_set_voltage(haptic, haptic->magnitude); - - mutex_unlock(&haptic->mutex); } static int regulator_haptic_play_effect(struct input_dev *input, void *data, @@ -205,19 +203,15 @@ static int regulator_haptic_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct regulator_haptic *haptic = platform_get_drvdata(pdev); - int error; - error = mutex_lock_interruptible(&haptic->mutex); - if (error) - return error; - - regulator_haptic_set_voltage(haptic, 0); + scoped_guard(mutex_intr, &haptic->mutex) { + regulator_haptic_set_voltage(haptic, 0); + haptic->suspended = true; - haptic->suspended = true; - - mutex_unlock(&haptic->mutex); + return 0; + } - return 0; + return -EINTR; } static int regulator_haptic_resume(struct device *dev) @@ -226,7 +220,7 @@ static int regulator_haptic_resume(struct device *dev) struct regulator_haptic *haptic = platform_get_drvdata(pdev); unsigned int magnitude; - mutex_lock(&haptic->mutex); + guard(mutex)(&haptic->mutex); haptic->suspended = false; @@ -234,8 +228,6 @@ static int regulator_haptic_resume(struct device *dev) if (magnitude) regulator_haptic_set_voltage(haptic, magnitude); - mutex_unlock(&haptic->mutex); - return 0; } diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index e94cab8133becb..f706e199741719 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -106,7 +106,7 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) struct rotary_encoder *encoder = dev_id; unsigned int state; - mutex_lock(&encoder->access_mutex); + guard(mutex)(&encoder->access_mutex); state = rotary_encoder_get_state(encoder); @@ -129,8 +129,6 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) break; } - mutex_unlock(&encoder->access_mutex); - return IRQ_HANDLED; } @@ -139,7 +137,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) struct rotary_encoder *encoder = dev_id; unsigned int state; - mutex_lock(&encoder->access_mutex); + guard(mutex)(&encoder->access_mutex); state = rotary_encoder_get_state(encoder); @@ -152,8 +150,6 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id) } } - mutex_unlock(&encoder->access_mutex); - return IRQ_HANDLED; } @@ -162,22 +158,19 @@ static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id) struct rotary_encoder *encoder = dev_id; unsigned int state; - mutex_lock(&encoder->access_mutex); + guard(mutex)(&encoder->access_mutex); state = rotary_encoder_get_state(encoder); - if ((encoder->last_stable + 1) % 4 == state) + if ((encoder->last_stable + 1) % 4 == state) { encoder->dir = 1; - else if (encoder->last_stable == (state + 1) % 4) + rotary_encoder_report_event(encoder); + } else if (encoder->last_stable == (state + 1) % 4) { encoder->dir = -1; - else - goto out; - - rotary_encoder_report_event(encoder); + rotary_encoder_report_event(encoder); + } -out: encoder->last_stable = state; - mutex_unlock(&encoder->access_mutex); return IRQ_HANDLED; } diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index 5c5d407fe96501..b8cad415c62ca2 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -515,7 +515,7 @@ static const struct soc_device_data soc_device_INT33D3 = { }; /* - * Button info for Microsoft Surface 3 (non pro), this is indentical to + * Button info for Microsoft Surface 3 (non pro), this is identical to * the PNP0C40 info except that the home button is active-high. * * The Surface 3 Pro also has a MSHW0028 ACPI device, but that uses a custom @@ -612,7 +612,7 @@ MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match); static struct platform_driver soc_button_driver = { .probe = soc_button_probe, - .remove_new = soc_button_remove, + .remove = soc_button_remove, .driver = { .name = KBUILD_MODNAME, .acpi_match_table = ACPI_PTR(soc_button_acpi_match), diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 20020cbc0752be..8d7303fc13bce3 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -69,7 +69,6 @@ static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); struct bbc_beep_info *info = &state->u.bbc; unsigned int count = 0; - unsigned long flags; if (type != EV_SND) return -1; @@ -85,7 +84,7 @@ static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int count = bbc_count_to_reg(info, count); - spin_lock_irqsave(&state->lock, flags); + guard(spinlock_irqsave)(&state->lock); if (count) { sbus_writeb(0x01, info->regs + 0); @@ -97,8 +96,6 @@ static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int sbus_writeb(0x00, info->regs + 0); } - spin_unlock_irqrestore(&state->lock, flags); - return 0; } @@ -107,7 +104,6 @@ static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent); struct grover_beep_info *info = &state->u.grover; unsigned int count = 0; - unsigned long flags; if (type != EV_SND) return -1; @@ -121,7 +117,7 @@ static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned if (value > 20 && value < 32767) count = 1193182 / value; - spin_lock_irqsave(&state->lock, flags); + guard(spinlock_irqsave)(&state->lock); if (count) { /* enable counter 2 */ @@ -136,8 +132,6 @@ static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned sbus_writeb(sbus_readb(info->enable_reg) & 0xFC, info->enable_reg); } - spin_unlock_irqrestore(&state->lock, flags); - return 0; } @@ -188,47 +182,38 @@ static int bbc_beep_probe(struct platform_device *op) { struct sparcspkr_state *state; struct bbc_beep_info *info; - struct device_node *dp; - int err = -ENOMEM; + int err; - state = kzalloc(sizeof(*state), GFP_KERNEL); + state = devm_kzalloc(&op->dev, sizeof(*state), GFP_KERNEL); if (!state) - goto out_err; + return -ENOMEM; state->name = "Sparc BBC Speaker"; state->event = bbc_spkr_event; spin_lock_init(&state->lock); - dp = of_find_node_by_path("/"); - err = -ENODEV; + struct device_node *dp __free(device_node) = of_find_node_by_path("/"); if (!dp) - goto out_free; + return -ENODEV; info = &state->u.bbc; info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0); - of_node_put(dp); if (!info->clock_freq) - goto out_free; + return -ENODEV; info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep"); if (!info->regs) - goto out_free; + return -ENODEV; platform_set_drvdata(op, state); err = sparcspkr_probe(&op->dev); - if (err) - goto out_clear_drvdata; + if (err) { + of_iounmap(&op->resource[0], info->regs, 6); + return err; + } return 0; - -out_clear_drvdata: - of_iounmap(&op->resource[0], info->regs, 6); - -out_free: - kfree(state); -out_err: - return err; } static void bbc_remove(struct platform_device *op) @@ -243,8 +228,6 @@ static void bbc_remove(struct platform_device *op) input_unregister_device(input_dev); of_iounmap(&op->resource[0], info->regs, 6); - - kfree(state); } static const struct of_device_id bbc_beep_match[] = { @@ -262,7 +245,7 @@ static struct platform_driver bbc_beep_driver = { .of_match_table = bbc_beep_match, }, .probe = bbc_beep_probe, - .remove_new = bbc_remove, + .remove = bbc_remove, .shutdown = sparcspkr_shutdown, }; @@ -272,9 +255,9 @@ static int grover_beep_probe(struct platform_device *op) struct grover_beep_info *info; int err = -ENOMEM; - state = kzalloc(sizeof(*state), GFP_KERNEL); + state = devm_kzalloc(&op->dev, sizeof(*state), GFP_KERNEL); if (!state) - goto out_err; + return err; state->name = "Sparc Grover Speaker"; state->event = grover_spkr_event; @@ -283,7 +266,7 @@ static int grover_beep_probe(struct platform_device *op) info = &state->u.grover; info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq"); if (!info->freq_regs) - goto out_free; + return err; info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable"); if (!info->enable_reg) @@ -302,9 +285,7 @@ static int grover_beep_probe(struct platform_device *op) out_unmap_freq_regs: of_iounmap(&op->resource[2], info->freq_regs, 2); -out_free: - kfree(state); -out_err: + return err; } @@ -321,8 +302,6 @@ static void grover_remove(struct platform_device *op) of_iounmap(&op->resource[3], info->enable_reg, 1); of_iounmap(&op->resource[2], info->freq_regs, 2); - - kfree(state); } static const struct of_device_id grover_beep_match[] = { @@ -340,7 +319,7 @@ static struct platform_driver grover_beep_driver = { .of_match_table = grover_beep_match, }, .probe = grover_beep_probe, - .remove_new = grover_remove, + .remove = grover_remove, .shutdown = sparcspkr_shutdown, }; diff --git a/drivers/input/misc/tps65219-pwrbutton.c b/drivers/input/misc/tps65219-pwrbutton.c index eeb9f2334ab461..7a58bae4f1a038 100644 --- a/drivers/input/misc/tps65219-pwrbutton.c +++ b/drivers/input/misc/tps65219-pwrbutton.c @@ -137,7 +137,7 @@ MODULE_DEVICE_TABLE(platform, tps65219_pwrbtn_id_table); static struct platform_driver tps65219_pb_driver = { .probe = tps65219_pb_probe, - .remove_new = tps65219_pb_remove, + .remove = tps65219_pb_remove, .driver = { .name = "tps65219_pwrbutton", }, diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 101548b35ee313..5fa7d4a7da363f 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -165,15 +165,10 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, static bool twl4030_vibra_check_coexist(struct device_node *parent) { - struct device_node *node; + struct device_node *node __free(device_node) = + of_get_child_by_name(parent, "codec"); - node = of_get_child_by_name(parent, "codec"); - if (node) { - of_node_put(node); - return true; - } - - return false; + return node != NULL; } static int twl4030_vibra_probe(struct platform_device *pdev) diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c index 78f0b63e5c2008..afed9af65bf928 100644 --- a/drivers/input/misc/twl6040-vibra.c +++ b/drivers/input/misc/twl6040-vibra.c @@ -229,14 +229,13 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, static int twl6040_vibra_probe(struct platform_device *pdev) { struct device *twl6040_core_dev = pdev->dev.parent; - struct device_node *twl6040_core_node; struct vibra_info *info; int vddvibl_uV = 0; int vddvibr_uV = 0; int error; - twl6040_core_node = of_get_child_by_name(twl6040_core_dev->of_node, - "vibra"); + struct device_node *twl6040_core_node __free(device_node) = + of_get_child_by_name(twl6040_core_dev->of_node, "vibra"); if (!twl6040_core_node) { dev_err(&pdev->dev, "parent of node is missing?\n"); return -EINVAL; @@ -244,7 +243,6 @@ static int twl6040_vibra_probe(struct platform_device *pdev) info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) { - of_node_put(twl6040_core_node); dev_err(&pdev->dev, "couldn't allocate memory\n"); return -ENOMEM; } @@ -264,8 +262,6 @@ static int twl6040_vibra_probe(struct platform_device *pdev) of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV", &vddvibl_uV); of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV", &vddvibr_uV); - of_node_put(twl6040_core_node); - if ((!info->vibldrv_res && !info->viblmotor_res) || (!info->vibrdrv_res && !info->vibrmotor_res)) { dev_err(info->dev, "invalid vibra driver/motor resistance\n"); diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 5a64557920fa59..1b2bd2139aaac5 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -271,7 +271,7 @@ static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = { { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ - { KE_WIFI, 0x78 }, /* satelite dish button */ + { KE_WIFI, 0x78 }, /* satellite dish button */ { KE_END, FE_WIFI_LED } }; @@ -1334,7 +1334,7 @@ static struct platform_driver wistron_driver = { .pm = pm_sleep_ptr(&wistron_pm_ops), }, .probe = wistron_probe, - .remove_new = wistron_remove, + .remove = wistron_remove, }; static int __init wb_module_init(void) diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c index e4a06c73b72d9d..18eb319bc6f750 100644 --- a/drivers/input/misc/wm831x-on.c +++ b/drivers/input/misc/wm831x-on.c @@ -134,7 +134,7 @@ static void wm831x_on_remove(struct platform_device *pdev) static struct platform_driver wm831x_on_driver = { .probe = wm831x_on_probe, - .remove_new = wm831x_on_remove, + .remove = wm831x_on_remove, .driver = { .name = "wm831x-on", }, diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c index 8866bf65d347b8..08dc53ae1b3c9f 100644 --- a/drivers/input/misc/yealink.c +++ b/drivers/input/misc/yealink.c @@ -377,7 +377,7 @@ static int yealink_do_idle_tasks(struct yealink_dev *yld) if (len > sizeof(yld->ctl_data->data)) len = sizeof(yld->ctl_data->data); - /* Combine up to consecutive LCD bytes in a singe request + /* Combine up to consecutive LCD bytes in a single request */ yld->ctl_data->cmd = CMD_LCD; yld->ctl_data->offset = cpu_to_be16(ix); @@ -614,7 +614,7 @@ static ssize_t show_line3(struct device *dev, struct device_attribute *attr, return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET); } -/* Writing to /sys/../lineX will set the coresponding LCD line. +/* Writing to /sys/../lineX will set the corresponding LCD line. * - Excess characters are ignored. * - If less characters are written than allowed, the remaining digits are * unchanged. diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 4e37fc3f1a9e97..0728b5c08f0216 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1585,7 +1585,7 @@ static void alps_flush_packet(struct timer_list *t) struct alps_data *priv = from_timer(priv, t, timer); struct psmouse *psmouse = priv->psmouse; - serio_pause_rx(psmouse->ps2dev.serio); + guard(serio_pause_rx)(psmouse->ps2dev.serio); if (psmouse->pktcnt == psmouse->pktsize) { @@ -1605,8 +1605,6 @@ static void alps_flush_packet(struct timer_list *t) } psmouse->pktcnt = 0; } - - serio_continue_rx(psmouse->ps2dev.serio); } static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index 2fbbaeb76d7082..d203c2a6c438bf 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c @@ -139,7 +139,7 @@ static void __exit amimouse_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver amimouse_driver __refdata = { - .remove_new = __exit_p(amimouse_remove), + .remove = __exit_p(amimouse_remove), .driver = { .name = "amiga-mouse", }, diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c index 221a553f45cd88..654b38d249f322 100644 --- a/drivers/input/mouse/byd.c +++ b/drivers/input/mouse/byd.c @@ -254,13 +254,12 @@ static void byd_clear_touch(struct timer_list *t) struct byd_data *priv = from_timer(priv, t, timer); struct psmouse *psmouse = priv->psmouse; - serio_pause_rx(psmouse->ps2dev.serio); + guard(serio_pause_rx)(psmouse->ps2dev.serio); + priv->touch = false; byd_report_input(psmouse); - serio_continue_rx(psmouse->ps2dev.serio); - /* * Move cursor back to center of pad when we lose touch - this * specifically improves user experience when moving cursor with one diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 7521981274bd8c..a841883660fb82 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -541,7 +541,8 @@ static int elan_update_firmware(struct elan_tp_data *data, dev_dbg(&client->dev, "Starting firmware update....\n"); - disable_irq(client->irq); + guard(disable_irq)(&client->irq); + data->in_fw_update = true; retval = __elan_update_firmware(data, fw); @@ -555,7 +556,6 @@ static int elan_update_firmware(struct elan_tp_data *data, } data->in_fw_update = false; - enable_irq(client->irq); return retval; } @@ -621,8 +621,6 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, const char *buf, size_t count) { struct elan_tp_data *data = dev_get_drvdata(dev); - const struct firmware *fw; - char *fw_name; int error; const u8 *fw_signature; static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF}; @@ -631,15 +629,16 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, return -EINVAL; /* Look for a firmware with the product id appended. */ - fw_name = kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id); + const char *fw_name __free(kfree) = + kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id); if (!fw_name) { dev_err(dev, "failed to allocate memory for firmware name\n"); return -ENOMEM; } dev_info(dev, "requesting fw '%s'\n", fw_name); + const struct firmware *fw __free(firmware) = NULL; error = request_firmware(&fw, fw_name, dev); - kfree(fw_name); if (error) { dev_err(dev, "failed to request firmware: %d\n", error); return error; @@ -651,46 +650,36 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n", (int)sizeof(signature), signature, (int)sizeof(signature), fw_signature); - error = -EBADF; - goto out_release_fw; + return -EBADF; } - error = mutex_lock_interruptible(&data->sysfs_mutex); - if (error) - goto out_release_fw; - - error = elan_update_firmware(data, fw); - - mutex_unlock(&data->sysfs_mutex); + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + error = elan_update_firmware(data, fw); + if (error) + return error; + } -out_release_fw: - release_firmware(fw); - return error ?: count; + return count; } -static ssize_t calibrate_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int elan_calibrate(struct elan_tp_data *data) { - struct i2c_client *client = to_i2c_client(dev); - struct elan_tp_data *data = i2c_get_clientdata(client); + struct i2c_client *client = data->client; + struct device *dev = &client->dev; int tries = 20; int retval; int error; u8 val[ETP_CALIBRATE_MAX_LEN]; - retval = mutex_lock_interruptible(&data->sysfs_mutex); - if (retval) - return retval; - - disable_irq(client->irq); + guard(disable_irq)(&client->irq); data->mode |= ETP_ENABLE_CALIBRATE; retval = data->ops->set_mode(client, data->mode); if (retval) { + data->mode &= ~ETP_ENABLE_CALIBRATE; dev_err(dev, "failed to enable calibration mode: %d\n", retval); - goto out; + return retval; } retval = data->ops->calibrate(client); @@ -728,10 +717,24 @@ static ssize_t calibrate_store(struct device *dev, if (!retval) retval = error; } -out: - enable_irq(client->irq); - mutex_unlock(&data->sysfs_mutex); - return retval ?: count; + return retval; +} + +static ssize_t calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int error; + + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + error = elan_calibrate(data); + if (error) + return error; + } + + return count; } static ssize_t elan_sysfs_read_mode(struct device *dev, @@ -743,16 +746,11 @@ static ssize_t elan_sysfs_read_mode(struct device *dev, int error; enum tp_mode mode; - error = mutex_lock_interruptible(&data->sysfs_mutex); - if (error) - return error; - - error = data->ops->iap_get_mode(data->client, &mode); - - mutex_unlock(&data->sysfs_mutex); - - if (error) - return error; + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + error = data->ops->iap_get_mode(data->client, &mode); + if (error) + return error; + } return sysfs_emit(buf, "%d\n", (int)mode); } @@ -783,44 +781,40 @@ static const struct attribute_group elan_sysfs_group = { .attrs = elan_sysfs_entries, }; -static ssize_t acquire_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static int elan_acquire_baseline(struct elan_tp_data *data) { - struct i2c_client *client = to_i2c_client(dev); - struct elan_tp_data *data = i2c_get_clientdata(client); - int error; + struct i2c_client *client = data->client; + struct device *dev = &client->dev; int retval; + int error; - retval = mutex_lock_interruptible(&data->sysfs_mutex); - if (retval) - return retval; - - disable_irq(client->irq); + guard(disable_irq)(&client->irq); data->baseline_ready = false; data->mode |= ETP_ENABLE_CALIBRATE; - retval = data->ops->set_mode(data->client, data->mode); + retval = data->ops->set_mode(client, data->mode); if (retval) { + data->mode &= ~ETP_ENABLE_CALIBRATE; dev_err(dev, "Failed to enable calibration mode to get baseline: %d\n", retval); - goto out; + return retval; } msleep(250); - retval = data->ops->get_baseline_data(data->client, true, + retval = data->ops->get_baseline_data(client, true, &data->max_baseline); if (retval) { - dev_err(dev, "Failed to read max baseline form device: %d\n", + dev_err(dev, "Failed to read max baseline from device: %d\n", retval); goto out_disable_calibrate; } - retval = data->ops->get_baseline_data(data->client, false, + retval = data->ops->get_baseline_data(client, false, &data->min_baseline); if (retval) { - dev_err(dev, "Failed to read min baseline form device: %d\n", + dev_err(dev, "Failed to read min baseline from device: %d\n", retval); goto out_disable_calibrate; } @@ -829,17 +823,31 @@ static ssize_t acquire_store(struct device *dev, struct device_attribute *attr, out_disable_calibrate: data->mode &= ~ETP_ENABLE_CALIBRATE; - error = data->ops->set_mode(data->client, data->mode); + error = data->ops->set_mode(client, data->mode); if (error) { dev_err(dev, "Failed to disable calibration mode after acquiring baseline: %d\n", error); if (!retval) retval = error; } -out: - enable_irq(client->irq); - mutex_unlock(&data->sysfs_mutex); - return retval ?: count; + + return retval; +} + +static ssize_t acquire_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elan_tp_data *data = i2c_get_clientdata(client); + int error; + + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + error = elan_acquire_baseline(data); + if (error) + return error; + } + + return count; } static ssize_t min_show(struct device *dev, @@ -847,22 +855,15 @@ static ssize_t min_show(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct elan_tp_data *data = i2c_get_clientdata(client); - int retval; - retval = mutex_lock_interruptible(&data->sysfs_mutex); - if (retval) - return retval; + scoped_guard(mutex_intr, &data->sysfs_mutex) { + if (!data->baseline_ready) + return -ENODATA; - if (!data->baseline_ready) { - retval = -ENODATA; - goto out; + return sysfs_emit(buf, "%d", data->min_baseline); } - retval = sysfs_emit(buf, "%d", data->min_baseline); - -out: - mutex_unlock(&data->sysfs_mutex); - return retval; + return -EINTR; } static ssize_t max_show(struct device *dev, @@ -870,25 +871,17 @@ static ssize_t max_show(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct elan_tp_data *data = i2c_get_clientdata(client); - int retval; - retval = mutex_lock_interruptible(&data->sysfs_mutex); - if (retval) - return retval; + scoped_guard(mutex_intr, &data->sysfs_mutex) { + if (!data->baseline_ready) + return -ENODATA; - if (!data->baseline_ready) { - retval = -ENODATA; - goto out; + return sysfs_emit(buf, "%d", data->max_baseline); } - retval = sysfs_emit(buf, "%d", data->max_baseline); - -out: - mutex_unlock(&data->sysfs_mutex); - return retval; + return -EINTR; } - static DEVICE_ATTR_WO(acquire); static DEVICE_ATTR_RO(min); static DEVICE_ATTR_RO(max); @@ -1323,43 +1316,54 @@ static int elan_probe(struct i2c_client *client) return 0; } +static int __elan_suspend(struct elan_tp_data *data) +{ + struct i2c_client *client = data->client; + int error; + + if (device_may_wakeup(&client->dev)) + return elan_sleep(data); + + /* Touchpad is not a wakeup source */ + error = elan_set_power(data, false); + if (error) + return error; + + error = regulator_disable(data->vcc); + if (error) { + dev_err(&client->dev, + "failed to disable regulator when suspending: %d\n", + error); + /* Attempt to power the chip back up */ + elan_set_power(data, true); + return error; + } + + return 0; +} + static int elan_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct elan_tp_data *data = i2c_get_clientdata(client); - int ret; + int error; /* * We are taking the mutex to make sure sysfs operations are * complete before we attempt to bring the device into low[er] * power mode. */ - ret = mutex_lock_interruptible(&data->sysfs_mutex); - if (ret) - return ret; - - disable_irq(client->irq); + scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) { + disable_irq(client->irq); - if (device_may_wakeup(dev)) { - ret = elan_sleep(data); - } else { - ret = elan_set_power(data, false); - if (ret) - goto err; - - ret = regulator_disable(data->vcc); - if (ret) { - dev_err(dev, "error %d disabling regulator\n", ret); - /* Attempt to power the chip back up */ - elan_set_power(data, true); + error = __elan_suspend(data); + if (error) { + enable_irq(client->irq); + return error; } } -err: - if (ret) - enable_irq(client->irq); - mutex_unlock(&data->sysfs_mutex); - return ret; + return 0; } static int elan_resume(struct device *dev) diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 15cf4463b64ea4..a9057d124a8881 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -628,12 +628,11 @@ static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size, const u8 *page, u16 checksum, int idx) { struct device *dev = &client->dev; - u8 *page_store; u8 val[3]; u16 result; int ret, error; - page_store = kmalloc(fw_page_size + 4, GFP_KERNEL); + u8 *page_store __free(kfree) = kmalloc(fw_page_size + 4, GFP_KERNEL); if (!page_store) return -ENOMEM; @@ -647,7 +646,7 @@ static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size, if (ret != fw_page_size + 4) { error = ret < 0 ? ret : -EIO; dev_err(dev, "Failed to write page %d: %d\n", idx, error); - goto exit; + return error; } /* Wait for F/W to update one page ROM data. */ @@ -656,20 +655,17 @@ static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size, error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val); if (error) { dev_err(dev, "Failed to read IAP write result: %d\n", error); - goto exit; + return error; } result = le16_to_cpup((__le16 *)val); if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { dev_err(dev, "IAP reports failed write: %04hx\n", result); - error = -EIO; - goto exit; + return -EIO; } -exit: - kfree(page_store); - return error; + return 0; } static int elan_i2c_finish_fw_update(struct i2c_client *client, diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index 2a2459b1b4f2cb..93420f07b7d07e 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -35,7 +35,7 @@ static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter) if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY)) return; - mutex_lock(&psmouse_smbus_mutex); + guard(mutex)(&psmouse_smbus_mutex); list_for_each_entry(smbdev, &psmouse_smbus_list, node) { if (smbdev->dead) @@ -55,15 +55,13 @@ static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter) "SMBus candidate adapter appeared, triggering rescan\n"); serio_rescan(smbdev->psmouse->ps2dev.serio); } - - mutex_unlock(&psmouse_smbus_mutex); } static void psmouse_smbus_detach_i2c_client(struct i2c_client *client) { struct psmouse_smbus_dev *smbdev, *tmp; - mutex_lock(&psmouse_smbus_mutex); + guard(mutex)(&psmouse_smbus_mutex); list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) { if (smbdev->client != client) @@ -85,8 +83,6 @@ static void psmouse_smbus_detach_i2c_client(struct i2c_client *client) kfree(smbdev); } } - - mutex_unlock(&psmouse_smbus_mutex); } static int psmouse_smbus_notifier_call(struct notifier_block *nb, @@ -171,7 +167,7 @@ static void psmouse_smbus_disconnect(struct psmouse *psmouse) { struct psmouse_smbus_dev *smbdev = psmouse->private; - mutex_lock(&psmouse_smbus_mutex); + guard(mutex)(&psmouse_smbus_mutex); if (smbdev->dead) { list_del(&smbdev->node); @@ -186,8 +182,6 @@ static void psmouse_smbus_disconnect(struct psmouse *psmouse) psmouse_smbus_schedule_remove(smbdev->client); } - mutex_unlock(&psmouse_smbus_mutex); - psmouse->private = NULL; } @@ -219,7 +213,7 @@ void psmouse_smbus_cleanup(struct psmouse *psmouse) { struct psmouse_smbus_dev *smbdev, *tmp; - mutex_lock(&psmouse_smbus_mutex); + guard(mutex)(&psmouse_smbus_mutex); list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) { if (psmouse == smbdev->psmouse) { @@ -227,8 +221,6 @@ void psmouse_smbus_cleanup(struct psmouse *psmouse) kfree(smbdev); } } - - mutex_unlock(&psmouse_smbus_mutex); } int psmouse_smbus_init(struct psmouse *psmouse, @@ -267,9 +259,9 @@ int psmouse_smbus_init(struct psmouse *psmouse, psmouse->disconnect = psmouse_smbus_disconnect; psmouse->resync_time = 0; - mutex_lock(&psmouse_smbus_mutex); - list_add_tail(&smbdev->node, &psmouse_smbus_list); - mutex_unlock(&psmouse_smbus_mutex); + scoped_guard(mutex, &psmouse_smbus_mutex) { + list_add_tail(&smbdev->node, &psmouse_smbus_list); + } /* Bind to already existing adapters right away */ error = i2c_for_each_dev(smbdev, psmouse_smbus_create_companion); @@ -293,9 +285,9 @@ int psmouse_smbus_init(struct psmouse *psmouse, smbdev->board.platform_data = NULL; if (error < 0 || !leave_breadcrumbs) { - mutex_lock(&psmouse_smbus_mutex); - list_del(&smbdev->node); - mutex_unlock(&psmouse_smbus_mutex); + scoped_guard(mutex, &psmouse_smbus_mutex) { + list_del(&smbdev->node); + } kfree(smbdev); } diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 380aa1614442f4..2735f86c23cc89 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -650,9 +650,8 @@ static int synaptics_pt_start(struct serio *serio) struct psmouse *parent = psmouse_from_serio(serio->parent); struct synaptics_data *priv = parent->private; - serio_pause_rx(parent->ps2dev.serio); + guard(serio_pause_rx)(parent->ps2dev.serio); priv->pt_port = serio; - serio_continue_rx(parent->ps2dev.serio); return 0; } @@ -662,9 +661,8 @@ static void synaptics_pt_stop(struct serio *serio) struct psmouse *parent = psmouse_from_serio(serio->parent); struct synaptics_data *priv = parent->private; - serio_pause_rx(parent->ps2dev.serio); + guard(serio_pause_rx)(parent->ps2dev.serio); priv->pt_port = NULL; - serio_continue_rx(parent->ps2dev.serio); } static int synaptics_is_pt_packet(u8 *buf) diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 08533d1b1b16fc..899aee598632b9 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -21,7 +21,7 @@ #define SYN_QUE_EXT_MIN_COORDS 0x0f #define SYN_QUE_MEXT_CAPAB_10 0x10 -/* synatics modes */ +/* synaptics modes */ #define SYN_BIT_ABSOLUTE_MODE BIT(7) #define SYN_BIT_HIGH_RATE BIT(6) #define SYN_BIT_SLEEP_MODE BIT(3) diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c index 1e11ea30d7bdb8..e1157ff0f00af2 100644 --- a/drivers/input/rmi4/rmi_f03.c +++ b/drivers/input/rmi4/rmi_f03.c @@ -61,14 +61,14 @@ void rmi_f03_commit_buttons(struct rmi_function *fn) struct f03_data *f03 = dev_get_drvdata(&fn->dev); struct serio *serio = f03->serio; - serio_pause_rx(serio); + guard(serio_pause_rx)(serio); + if (serio->drv) { serio->drv->interrupt(serio, PSMOUSE_OOB_EXTRA_BTNS, SERIO_OOB_DATA); serio->drv->interrupt(serio, f03->overwrite_buttons, SERIO_OOB_DATA); } - serio_continue_rx(serio); } static int rmi_f03_pt_write(struct serio *id, unsigned char val) diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index e2468bc04a5cb3..d760af4cc12efb 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c @@ -246,7 +246,6 @@ static int rmi_f34_update_firmware(struct f34_data *f34, (const struct rmi_f34_firmware *)fw->data; u32 image_size = le32_to_cpu(syn_fw->image_size); u32 config_size = le32_to_cpu(syn_fw->config_size); - int ret; BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) != F34_FW_IMAGE_OFFSET); @@ -267,8 +266,7 @@ static int rmi_f34_update_firmware(struct f34_data *f34, dev_err(&f34->fn->dev, "Bad firmware image: fw size %d, expected %d\n", image_size, f34->v5.fw_blocks * f34->v5.block_size); - ret = -EILSEQ; - goto out; + return -EILSEQ; } if (config_size && @@ -277,25 +275,18 @@ static int rmi_f34_update_firmware(struct f34_data *f34, "Bad firmware image: config size %d, expected %d\n", config_size, f34->v5.config_blocks * f34->v5.block_size); - ret = -EILSEQ; - goto out; + return -EILSEQ; } if (image_size && !config_size) { dev_err(&f34->fn->dev, "Bad firmware image: no config data\n"); - ret = -EILSEQ; - goto out; + return -EILSEQ; } dev_info(&f34->fn->dev, "Firmware image OK\n"); - mutex_lock(&f34->v5.flash_mutex); - - ret = rmi_f34_flash_firmware(f34, syn_fw); - mutex_unlock(&f34->v5.flash_mutex); - -out: - return ret; + guard(mutex)(&f34->v5.flash_mutex); + return rmi_f34_flash_firmware(f34, syn_fw); } static int rmi_f34_status(struct rmi_function *fn) @@ -461,9 +452,8 @@ static ssize_t rmi_driver_update_fw_store(struct device *dev, { struct rmi_driver_data *data = dev_get_drvdata(dev); char fw_name[NAME_MAX]; - const struct firmware *fw; size_t copy_count = count; - int ret; + int error; if (count == 0 || count >= NAME_MAX) return -EINVAL; @@ -474,17 +464,18 @@ static ssize_t rmi_driver_update_fw_store(struct device *dev, memcpy(fw_name, buf, copy_count); fw_name[copy_count] = '\0'; - ret = request_firmware(&fw, fw_name, dev); - if (ret) - return ret; + const struct firmware *fw __free(firmware) = NULL; + error = request_firmware(&fw, fw_name, dev); + if (error) + return error; dev_info(dev, "Flashing %s\n", fw_name); - ret = rmi_firmware_update(data, fw); - - release_firmware(fw); + error = rmi_firmware_update(data, fw); + if (error) + return error; - return ret ?: count; + return count; } static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store); diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index 611eb9fe2d0471..aa445b1941e934 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c @@ -146,7 +146,7 @@ MODULE_DEVICE_TABLE(of, altera_ps2_match); */ static struct platform_driver altera_ps2_driver = { .probe = altera_ps2_probe, - .remove_new = altera_ps2_remove, + .remove = altera_ps2_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(altera_ps2_match), diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index 0bd6ae1068099a..81b3a053df8103 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -182,7 +182,7 @@ static void ams_delta_serio_exit(struct platform_device *pdev) static struct platform_driver ams_delta_serio_driver = { .probe = ams_delta_serio_init, - .remove_new = ams_delta_serio_exit, + .remove = ams_delta_serio_exit, .driver = { .name = DRIVER_NAME }, diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c index 4015e75fcb903d..b815337be2f432 100644 --- a/drivers/input/serio/apbps2.c +++ b/drivers/input/serio/apbps2.c @@ -208,7 +208,7 @@ static struct platform_driver apbps2_of_driver = { .of_match_table = apbps2_of_match, }, .probe = apbps2_of_probe, - .remove_new = apbps2_of_remove, + .remove = apbps2_of_remove, }; module_platform_driver(apbps2_of_driver); diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index a9180a00587208..e991c72296c93f 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c @@ -260,7 +260,7 @@ static struct platform_driver arc_ps2_driver = { .of_match_table = of_match_ptr(arc_ps2_match), }, .probe = arc_ps2_probe, - .remove_new = arc_ps2_remove, + .remove = arc_ps2_remove, }; module_platform_driver(arc_ps2_driver); diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 6834440b37f661..053a15988c4543 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -190,7 +190,7 @@ static struct platform_driver ct82c710_driver = { .name = "ct82c710", }, .probe = ct82c710_probe, - .remove_new = ct82c710_remove, + .remove = ct82c710_remove, }; diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index d94c01eb3fc973..4fada5bc2a3828 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -145,7 +145,6 @@ static void gscps2_flush(struct gscps2port *ps2port) static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data) { - unsigned long flags; char __iomem *addr = ps2port->addr; if (!wait_TBE(addr)) { @@ -156,9 +155,8 @@ static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data) while (gscps2_readb_status(addr) & GSC_STAT_RBNE) /* wait */; - spin_lock_irqsave(&ps2port->lock, flags); - writeb(data, addr+GSC_XMTDATA); - spin_unlock_irqrestore(&ps2port->lock, flags); + scoped_guard(spinlock_irqsave, &ps2port->lock) + writeb(data, addr+GSC_XMTDATA); /* this is ugly, but due to timing of the port it seems to be necessary. */ mdelay(6); @@ -177,19 +175,19 @@ static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data) static void gscps2_enable(struct gscps2port *ps2port, int enable) { - unsigned long flags; u8 data; /* now enable/disable the port */ - spin_lock_irqsave(&ps2port->lock, flags); - gscps2_flush(ps2port); - data = gscps2_readb_control(ps2port->addr); - if (enable) - data |= GSC_CTRL_ENBL; - else - data &= ~GSC_CTRL_ENBL; - gscps2_writeb_control(data, ps2port->addr); - spin_unlock_irqrestore(&ps2port->lock, flags); + scoped_guard(spinlock_irqsave, &ps2port->lock) { + gscps2_flush(ps2port); + data = gscps2_readb_control(ps2port->addr); + if (enable) + data |= GSC_CTRL_ENBL; + else + data &= ~GSC_CTRL_ENBL; + gscps2_writeb_control(data, ps2port->addr); + } + wait_TBE(ps2port->addr); gscps2_flush(ps2port); } @@ -200,18 +198,57 @@ static void gscps2_enable(struct gscps2port *ps2port, int enable) static void gscps2_reset(struct gscps2port *ps2port) { - unsigned long flags; - /* reset the interface */ - spin_lock_irqsave(&ps2port->lock, flags); + guard(spinlock_irqsave)(&ps2port->lock); gscps2_flush(ps2port); writeb(0xff, ps2port->addr + GSC_RESET); gscps2_flush(ps2port); - spin_unlock_irqrestore(&ps2port->lock, flags); } static LIST_HEAD(ps2port_list); +static void gscps2_read_data(struct gscps2port *ps2port) +{ + u8 status; + + do { + status = gscps2_readb_status(ps2port->addr); + if (!(status & GSC_STAT_RBNE)) + break; + + ps2port->buffer[ps2port->append].str = status; + ps2port->buffer[ps2port->append].data = + gscps2_readb_input(ps2port->addr); + } while (true); +} + +static bool gscps2_report_data(struct gscps2port *ps2port) +{ + unsigned int rxflags; + u8 data, status; + + while (ps2port->act != ps2port->append) { + /* + * Did new data arrived while we read existing data ? + * If yes, exit now and let the new irq handler start + * over again. + */ + if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR) + return true; + + status = ps2port->buffer[ps2port->act].str; + data = ps2port->buffer[ps2port->act].data; + + ps2port->act = (ps2port->act + 1) & BUFFER_SIZE; + rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | + ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); + + serio_interrupt(ps2port->port, data, rxflags); + } + + return false; +} + /** * gscps2_interrupt() - Interruption service routine * @@ -229,47 +266,18 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev) struct gscps2port *ps2port; list_for_each_entry(ps2port, &ps2port_list, node) { + guard(spinlock_irqsave)(&ps2port->lock); - unsigned long flags; - spin_lock_irqsave(&ps2port->lock, flags); - - while ( (ps2port->buffer[ps2port->append].str = - gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) { - ps2port->buffer[ps2port->append].data = - gscps2_readb_input(ps2port->addr); - ps2port->append = ((ps2port->append+1) & BUFFER_SIZE); - } - - spin_unlock_irqrestore(&ps2port->lock, flags); - + gscps2_read_data(ps2port); } /* list_for_each_entry */ /* all data was read from the ports - now report the data to upper layer */ - list_for_each_entry(ps2port, &ps2port_list, node) { - - while (ps2port->act != ps2port->append) { - - unsigned int rxflags; - u8 data, status; - - /* Did new data arrived while we read existing data ? - If yes, exit now and let the new irq handler start over again */ - if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR) - return IRQ_HANDLED; - - status = ps2port->buffer[ps2port->act].str; - data = ps2port->buffer[ps2port->act].data; - - ps2port->act = ((ps2port->act+1) & BUFFER_SIZE); - rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | - ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); - - serio_interrupt(ps2port->port, data, rxflags); - - } /* while() */ - - } /* list_for_each_entry */ + if (gscps2_report_data(ps2port)) { + /* More data ready - break early to restart interrupt */ + break; + } + } return IRQ_HANDLED; } diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c index 31d9dacd2fd189..0ee7505427aced 100644 --- a/drivers/input/serio/hyperv-keyboard.c +++ b/drivers/input/serio/hyperv-keyboard.c @@ -102,7 +102,6 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev, { struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev); struct synth_kbd_keystroke *ks_msg; - unsigned long flags; u32 msg_type = __le32_to_cpu(msg->header.type); u32 info; u16 scan_code; @@ -147,21 +146,22 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev, /* * Inject the information through the serio interrupt. */ - spin_lock_irqsave(&kbd_dev->lock, flags); - if (kbd_dev->started) { - if (info & IS_E0) - serio_interrupt(kbd_dev->hv_serio, - XTKBD_EMUL0, 0); - if (info & IS_E1) - serio_interrupt(kbd_dev->hv_serio, - XTKBD_EMUL1, 0); - scan_code = __le16_to_cpu(ks_msg->make_code); - if (info & IS_BREAK) - scan_code |= XTKBD_RELEASE; + scoped_guard(spinlock_irqsave, &kbd_dev->lock) { + if (kbd_dev->started) { + if (info & IS_E0) + serio_interrupt(kbd_dev->hv_serio, + XTKBD_EMUL0, 0); + if (info & IS_E1) + serio_interrupt(kbd_dev->hv_serio, + XTKBD_EMUL1, 0); + scan_code = __le16_to_cpu(ks_msg->make_code); + if (info & IS_BREAK) + scan_code |= XTKBD_RELEASE; - serio_interrupt(kbd_dev->hv_serio, scan_code, 0); + serio_interrupt(kbd_dev->hv_serio, + scan_code, 0); + } } - spin_unlock_irqrestore(&kbd_dev->lock, flags); /* * Only trigger a wakeup on key down, otherwise @@ -292,11 +292,10 @@ static int hv_kbd_connect_to_vsp(struct hv_device *hv_dev) static int hv_kbd_start(struct serio *serio) { struct hv_kbd_dev *kbd_dev = serio->port_data; - unsigned long flags; - spin_lock_irqsave(&kbd_dev->lock, flags); + guard(spinlock_irqsave)(&kbd_dev->lock); + kbd_dev->started = true; - spin_unlock_irqrestore(&kbd_dev->lock, flags); return 0; } @@ -304,11 +303,10 @@ static int hv_kbd_start(struct serio *serio) static void hv_kbd_stop(struct serio *serio) { struct hv_kbd_dev *kbd_dev = serio->port_data; - unsigned long flags; - spin_lock_irqsave(&kbd_dev->lock, flags); + guard(spinlock_irqsave)(&kbd_dev->lock); + kbd_dev->started = false; - spin_unlock_irqrestore(&kbd_dev->lock, flags); } static int hv_kbd_probe(struct hv_device *hv_dev, diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index 34d1f07ea4c304..127cfdc8668a09 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -90,7 +90,7 @@ static inline void i8042_write_command(int val) * ORDERING IS IMPORTANT! The first match will be apllied and the rest ignored. * This allows entries to overwrite vendor wide quirks on a per device basis. * Where this is irrelevant, entries are sorted case sensitive by DMI_SYS_VENDOR - * and/or DMI_BOARD_VENDOR to make it easier to avoid dublicate entries. + * and/or DMI_BOARD_VENDOR to make it easier to avoid duplicate entries. */ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { { diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index c2fda54dc384fe..0f97158fd14e61 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -101,23 +101,15 @@ static struct platform_driver sparc_i8042_driver = { .of_match_table = sparc_i8042_match, }, .probe = sparc_i8042_probe, - .remove_new = sparc_i8042_remove, + .remove = sparc_i8042_remove, }; static bool i8042_is_mr_coffee(void) { - struct device_node *root; - const char *name; - bool is_mr_coffee; + struct device_node *root __free(device_node) = of_find_node_by_path("/"); + const char *name = of_get_property(root, "name", NULL); - root = of_find_node_by_path("/"); - - name = of_get_property(root, "name", NULL); - is_mr_coffee = name && !strcmp(name, "SUNW,JavaStation-1"); - - of_node_put(root); - - return is_mr_coffee; + return name && !strcmp(name, "SUNW,JavaStation-1"); } static int __init i8042_platform_init(void) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 8ec4872b447145..509330a2788027 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -178,7 +178,7 @@ static unsigned char i8042_suppress_kbd_ack; static struct platform_device *i8042_platform_device; static struct notifier_block i8042_kbd_bind_notifier_block; -static irqreturn_t i8042_interrupt(int irq, void *dev_id); +static bool i8042_handle_data(int irq); static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, struct serio *serio); @@ -197,42 +197,26 @@ EXPORT_SYMBOL(i8042_unlock_chip); int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, struct serio *serio)) { - unsigned long flags; - int ret = 0; + guard(spinlock_irqsave)(&i8042_lock); - spin_lock_irqsave(&i8042_lock, flags); - - if (i8042_platform_filter) { - ret = -EBUSY; - goto out; - } + if (i8042_platform_filter) + return -EBUSY; i8042_platform_filter = filter; - -out: - spin_unlock_irqrestore(&i8042_lock, flags); - return ret; + return 0; } EXPORT_SYMBOL(i8042_install_filter); int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, struct serio *port)) { - unsigned long flags; - int ret = 0; + guard(spinlock_irqsave)(&i8042_lock); - spin_lock_irqsave(&i8042_lock, flags); - - if (i8042_platform_filter != filter) { - ret = -EINVAL; - goto out; - } + if (i8042_platform_filter != filter) + return -EINVAL; i8042_platform_filter = NULL; - -out: - spin_unlock_irqrestore(&i8042_lock, flags); - return ret; + return 0; } EXPORT_SYMBOL(i8042_remove_filter); @@ -271,28 +255,22 @@ static int i8042_wait_write(void) static int i8042_flush(void) { - unsigned long flags; unsigned char data, str; int count = 0; - int retval = 0; - spin_lock_irqsave(&i8042_lock, flags); + guard(spinlock_irqsave)(&i8042_lock); while ((str = i8042_read_status()) & I8042_STR_OBF) { - if (count++ < I8042_BUFFER_SIZE) { - udelay(50); - data = i8042_read_data(); - dbg("%02x <- i8042 (flush, %s)\n", - data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); - } else { - retval = -EIO; - break; - } - } + if (count++ >= I8042_BUFFER_SIZE) + return -EIO; - spin_unlock_irqrestore(&i8042_lock, flags); + udelay(50); + data = i8042_read_data(); + dbg("%02x <- i8042 (flush, %s)\n", + data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); + } - return retval; + return 0; } /* @@ -349,17 +327,12 @@ static int __i8042_command(unsigned char *param, int command) int i8042_command(unsigned char *param, int command) { - unsigned long flags; - int retval; - if (!i8042_present) return -1; - spin_lock_irqsave(&i8042_lock, flags); - retval = __i8042_command(param, command); - spin_unlock_irqrestore(&i8042_lock, flags); + guard(spinlock_irqsave)(&i8042_lock); - return retval; + return __i8042_command(param, command); } EXPORT_SYMBOL(i8042_command); @@ -369,19 +342,18 @@ EXPORT_SYMBOL(i8042_command); static int i8042_kbd_write(struct serio *port, unsigned char c) { - unsigned long flags; - int retval = 0; + int error; - spin_lock_irqsave(&i8042_lock, flags); + guard(spinlock_irqsave)(&i8042_lock); - if (!(retval = i8042_wait_write())) { - dbg("%02x -> i8042 (kbd-data)\n", c); - i8042_write_data(c); - } + error = i8042_wait_write(); + if (error) + return error; - spin_unlock_irqrestore(&i8042_lock, flags); + dbg("%02x -> i8042 (kbd-data)\n", c); + i8042_write_data(c); - return retval; + return 0; } /* @@ -434,7 +406,7 @@ static void i8042_port_close(struct serio *serio) * See if there is any data appeared while we were messing with * port state. */ - i8042_interrupt(0, NULL); + i8042_handle_data(0); } /* @@ -460,9 +432,8 @@ static int i8042_start(struct serio *serio) device_set_wakeup_enable(&serio->dev, true); } - spin_lock_irq(&i8042_lock); + guard(spinlock_irq)(&i8042_lock); port->exists = true; - spin_unlock_irq(&i8042_lock); return 0; } @@ -476,10 +447,10 @@ static void i8042_stop(struct serio *serio) { struct i8042_port *port = serio->port_data; - spin_lock_irq(&i8042_lock); - port->exists = false; - port->serio = NULL; - spin_unlock_irq(&i8042_lock); + scoped_guard(spinlock_irq, &i8042_lock) { + port->exists = false; + port->serio = NULL; + } /* * We need to make sure that interrupt handler finishes using @@ -518,44 +489,10 @@ static bool i8042_filter(unsigned char data, unsigned char str, } /* - * i8042_interrupt() is the most important function in this driver - - * it handles the interrupts from the i8042, and sends incoming bytes - * to the upper layers. - */ - -static irqreturn_t i8042_interrupt(int irq, void *dev_id) -{ - struct i8042_port *port; - struct serio *serio; - unsigned long flags; - unsigned char str, data; - unsigned int dfl; - unsigned int port_no; - bool filtered; - int ret = 1; - - spin_lock_irqsave(&i8042_lock, flags); - - str = i8042_read_status(); - if (unlikely(~str & I8042_STR_OBF)) { - spin_unlock_irqrestore(&i8042_lock, flags); - if (irq) - dbg("Interrupt %d, without any data\n", irq); - ret = 0; - goto out; - } - - data = i8042_read_data(); - - if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { - static unsigned long last_transmit; - static unsigned char last_str; - - dfl = 0; - if (str & I8042_STR_MUXERR) { - dbg("MUX error, status is %02x, data is %02x\n", - str, data); -/* + * i8042_handle_mux() handles case when data is coming from one of + * the multiplexed ports. It would be simple if not for quirks with + * handling errors: + * * When MUXERR condition is signalled the data register can only contain * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately * it is not always the case. Some KBCs also report 0xfc when there is @@ -567,50 +504,106 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) * rest assume that the data came from the same serio last byte * was transmitted (if transmission happened not too long ago). */ - - switch (data) { - default: - if (time_before(jiffies, last_transmit + HZ/10)) { - str = last_str; - break; - } - fallthrough; /* report timeout */ - case 0xfc: - case 0xfd: - case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; - case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; +static int i8042_handle_mux(u8 str, u8 *data, unsigned int *dfl) +{ + static unsigned long last_transmit; + static unsigned long last_port; + unsigned int mux_port; + + mux_port = (str >> 6) & 3; + *dfl = 0; + + if (str & I8042_STR_MUXERR) { + dbg("MUX error, status is %02x, data is %02x\n", + str, *data); + + switch (*data) { + default: + if (time_before(jiffies, last_transmit + HZ/10)) { + mux_port = last_port; + break; } + fallthrough; /* report timeout */ + case 0xfc: + case 0xfd: + case 0xfe: + *dfl = SERIO_TIMEOUT; + *data = 0xfe; + break; + case 0xff: + *dfl = SERIO_PARITY; + *data = 0xfe; + break; } + } - port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3); - last_str = str; - last_transmit = jiffies; - } else { + last_port = mux_port; + last_transmit = jiffies; - dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | - ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0); + return I8042_MUX_PORT_NO + mux_port; +} - port_no = (str & I8042_STR_AUXDATA) ? - I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; - } +/* + * i8042_handle_data() is the most important function in this driver - + * it reads the data from the i8042, determines its destination serio + * port, and sends received byte to the upper layers. + * + * Returns true if there was data waiting, false otherwise. + */ +static bool i8042_handle_data(int irq) +{ + struct i8042_port *port; + struct serio *serio; + unsigned char str, data; + unsigned int dfl; + unsigned int port_no; + bool filtered; + + scoped_guard(spinlock_irqsave, &i8042_lock) { + str = i8042_read_status(); + if (unlikely(~str & I8042_STR_OBF)) + return false; + + data = i8042_read_data(); + + if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { + port_no = i8042_handle_mux(str, &data, &dfl); + } else { + + dfl = (str & I8042_STR_PARITY) ? SERIO_PARITY : 0; + if ((str & I8042_STR_TIMEOUT) && !i8042_notimeout) + dfl |= SERIO_TIMEOUT; - port = &i8042_ports[port_no]; - serio = port->exists ? port->serio : NULL; + port_no = (str & I8042_STR_AUXDATA) ? + I8042_AUX_PORT_NO : I8042_KBD_PORT_NO; + } - filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n", - port_no, irq, - dfl & SERIO_PARITY ? ", bad parity" : "", - dfl & SERIO_TIMEOUT ? ", timeout" : ""); + port = &i8042_ports[port_no]; + serio = port->exists ? port->serio : NULL; - filtered = i8042_filter(data, str, serio); + filter_dbg(port->driver_bound, + data, "<- i8042 (interrupt, %d, %d%s%s)\n", + port_no, irq, + dfl & SERIO_PARITY ? ", bad parity" : "", + dfl & SERIO_TIMEOUT ? ", timeout" : ""); - spin_unlock_irqrestore(&i8042_lock, flags); + filtered = i8042_filter(data, str, serio); + } if (likely(serio && !filtered)) serio_interrupt(serio, data, dfl); - out: - return IRQ_RETVAL(ret); + return true; +} + +static irqreturn_t i8042_interrupt(int irq, void *dev_id) +{ + if (unlikely(!i8042_handle_data(irq))) { + dbg("Interrupt %d, without any data\n", irq); + return IRQ_NONE; + } + + return IRQ_HANDLED; } /* @@ -753,24 +746,22 @@ static bool i8042_irq_being_tested; static irqreturn_t i8042_aux_test_irq(int irq, void *dev_id) { - unsigned long flags; unsigned char str, data; - int ret = 0; - spin_lock_irqsave(&i8042_lock, flags); + guard(spinlock_irqsave)(&i8042_lock); + str = i8042_read_status(); - if (str & I8042_STR_OBF) { - data = i8042_read_data(); - dbg("%02x <- i8042 (aux_test_irq, %s)\n", - data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); - if (i8042_irq_being_tested && - data == 0xa5 && (str & I8042_STR_AUXDATA)) - complete(&i8042_aux_irq_delivered); - ret = 1; - } - spin_unlock_irqrestore(&i8042_lock, flags); + if (!(str & I8042_STR_OBF)) + return IRQ_NONE; + + data = i8042_read_data(); + dbg("%02x <- i8042 (aux_test_irq, %s)\n", + data, str & I8042_STR_AUXDATA ? "aux" : "kbd"); + + if (i8042_irq_being_tested && data == 0xa5 && (str & I8042_STR_AUXDATA)) + complete(&i8042_aux_irq_delivered); - return IRQ_RETVAL(ret); + return IRQ_HANDLED; } /* @@ -811,7 +802,6 @@ static int i8042_check_aux(void) int retval = -1; bool irq_registered = false; bool aux_loop_broken = false; - unsigned long flags; unsigned char param; /* @@ -895,18 +885,15 @@ static int i8042_check_aux(void) if (i8042_enable_aux_port()) goto out; - spin_lock_irqsave(&i8042_lock, flags); - - init_completion(&i8042_aux_irq_delivered); - i8042_irq_being_tested = true; + scoped_guard(spinlock_irqsave, &i8042_lock) { + init_completion(&i8042_aux_irq_delivered); + i8042_irq_being_tested = true; - param = 0xa5; - retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); - - spin_unlock_irqrestore(&i8042_lock, flags); - - if (retval) - goto out; + param = 0xa5; + retval = __i8042_command(¶m, I8042_CMD_AUX_LOOP & 0xf0ff); + if (retval) + goto out; + } if (wait_for_completion_timeout(&i8042_aux_irq_delivered, msecs_to_jiffies(250)) == 0) { @@ -994,7 +981,6 @@ static int i8042_controller_selftest(void) static int i8042_controller_init(void) { - unsigned long flags; int n = 0; unsigned char ctr[2]; @@ -1031,14 +1017,14 @@ static int i8042_controller_init(void) * Handle keylock. */ - spin_lock_irqsave(&i8042_lock, flags); - if (~i8042_read_status() & I8042_STR_KEYLOCK) { - if (i8042_unlock) - i8042_ctr |= I8042_CTR_IGNKEYLOCK; - else - pr_warn("Warning: Keylock active\n"); + scoped_guard(spinlock_irqsave, &i8042_lock) { + if (~i8042_read_status() & I8042_STR_KEYLOCK) { + if (i8042_unlock) + i8042_ctr |= I8042_CTR_IGNKEYLOCK; + else + pr_warn("Warning: Keylock active\n"); + } } - spin_unlock_irqrestore(&i8042_lock, flags); /* * If the chip is configured into nontranslated mode by the BIOS, don't @@ -1216,13 +1202,14 @@ static int i8042_controller_resume(bool s2r_wants_reset) if (i8042_mux_present) { if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports()) pr_warn("failed to resume active multiplexor, mouse won't work\n"); - } else if (i8042_ports[I8042_AUX_PORT_NO].serio) + } else if (i8042_ports[I8042_AUX_PORT_NO].serio) { i8042_enable_aux_port(); + } if (i8042_ports[I8042_KBD_PORT_NO].serio) i8042_enable_kbd_port(); - i8042_interrupt(0, NULL); + i8042_handle_data(0); return 0; } @@ -1253,7 +1240,7 @@ static int i8042_pm_suspend(struct device *dev) static int i8042_pm_resume_noirq(struct device *dev) { if (i8042_forcenorestore || !pm_resume_via_firmware()) - i8042_interrupt(0, NULL); + i8042_handle_data(0); return 0; } @@ -1290,7 +1277,7 @@ static int i8042_pm_resume(struct device *dev) static int i8042_pm_thaw(struct device *dev) { - i8042_interrupt(0, NULL); + i8042_handle_data(0); return 0; } @@ -1603,7 +1590,7 @@ static struct platform_driver i8042_driver = { #endif }, .probe = i8042_probe, - .remove_new = i8042_remove, + .remove = i8042_remove, .shutdown = i8042_shutdown, }; diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c index 676b0bda3d720c..d2c7ffb9a946b7 100644 --- a/drivers/input/serio/ioc3kbd.c +++ b/drivers/input/serio/ioc3kbd.c @@ -208,7 +208,7 @@ MODULE_DEVICE_TABLE(platform, ioc3kbd_id_table); static struct platform_driver ioc3kbd_driver = { .probe = ioc3kbd_probe, - .remove_new = ioc3kbd_remove, + .remove = ioc3kbd_remove, .id_table = ioc3kbd_id_table, .driver = { .name = "ioc3-kbd", diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 6d78a1fe00c1bf..c22ea532276eb9 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -108,13 +108,11 @@ int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout) { int retval; - serio_pause_rx(ps2dev->serio); + guard(serio_pause_rx)(ps2dev->serio); retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1); dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak); - serio_continue_rx(ps2dev->serio); - return retval; } EXPORT_SYMBOL(ps2_sendbyte); @@ -162,10 +160,10 @@ void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout) ps2_begin_command(ps2dev); - serio_pause_rx(ps2dev->serio); - ps2dev->flags = PS2_FLAG_CMD; - ps2dev->cmdcnt = maxbytes; - serio_continue_rx(ps2dev->serio); + scoped_guard(serio_pause_rx, ps2dev->serio) { + ps2dev->flags = PS2_FLAG_CMD; + ps2dev->cmdcnt = maxbytes; + } wait_event_timeout(ps2dev->wait, !(ps2dev->flags & PS2_FLAG_CMD), @@ -224,9 +222,9 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, * use alternative probe to detect it. */ if (ps2dev->cmdbuf[1] == 0xaa) { - serio_pause_rx(ps2dev->serio); - ps2dev->flags = 0; - serio_continue_rx(ps2dev->serio); + scoped_guard(serio_pause_rx, ps2dev->serio) + ps2dev->flags = 0; + timeout = 0; } @@ -235,9 +233,9 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, * won't be 2nd byte of ID response. */ if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) { - serio_pause_rx(ps2dev->serio); - ps2dev->flags = ps2dev->cmdcnt = 0; - serio_continue_rx(ps2dev->serio); + scoped_guard(serio_pause_rx, ps2dev->serio) + ps2dev->flags = ps2dev->cmdcnt = 0; + timeout = 0; } break; @@ -283,6 +281,10 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) memcpy(send_param, param, send); + /* + * Not using guard notation because we need to break critical + * section below while waiting for the response. + */ serio_pause_rx(ps2dev->serio); ps2dev->cmdcnt = receive; diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 42ac1eb948662d..3d28a5cddd6111 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -159,7 +159,7 @@ static struct platform_driver maceps2_driver = { .name = "maceps2", }, .probe = maceps2_probe, - .remove_new = maceps2_remove, + .remove = maceps2_remove, }; static int __init maceps2_init(void) diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c index 0ad95e880cc20d..a2432483002162 100644 --- a/drivers/input/serio/olpc_apsp.c +++ b/drivers/input/serio/olpc_apsp.c @@ -256,7 +256,7 @@ MODULE_DEVICE_TABLE(of, olpc_apsp_dt_ids); static struct platform_driver olpc_apsp_driver = { .probe = olpc_apsp_probe, - .remove_new = olpc_apsp_remove, + .remove = olpc_apsp_remove, .driver = { .name = "olpc-apsp", .of_match_table = olpc_apsp_dt_ids, diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c index 3a431395c4646f..93769910ce24ea 100644 --- a/drivers/input/serio/ps2-gpio.c +++ b/drivers/input/serio/ps2-gpio.c @@ -133,12 +133,12 @@ static int ps2_gpio_write(struct serio *serio, unsigned char val) int ret = 0; if (in_task()) { - mutex_lock(&drvdata->tx.mutex); + guard(mutex)(&drvdata->tx.mutex); + __ps2_gpio_write(serio, val); if (!wait_for_completion_timeout(&drvdata->tx.complete, msecs_to_jiffies(10000))) ret = SERIO_TIMEOUT; - mutex_unlock(&drvdata->tx.mutex); } else { __ps2_gpio_write(serio, val); } @@ -491,7 +491,7 @@ MODULE_DEVICE_TABLE(of, ps2_gpio_match); static struct platform_driver ps2_gpio_driver = { .probe = ps2_gpio_probe, - .remove_new = ps2_gpio_remove, + .remove = ps2_gpio_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ps2_gpio_match), diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c index 937ecdea491d17..b96cee52fc52e1 100644 --- a/drivers/input/serio/ps2mult.c +++ b/drivers/input/serio/ps2mult.c @@ -76,9 +76,8 @@ static int ps2mult_serio_write(struct serio *serio, unsigned char data) struct ps2mult *psm = serio_get_drvdata(mx_port); struct ps2mult_port *port = serio->port_data; bool need_escape; - unsigned long flags; - spin_lock_irqsave(&psm->lock, flags); + guard(spinlock_irqsave)(&psm->lock); if (psm->out_port != port) ps2mult_select_port(psm, port); @@ -93,8 +92,6 @@ static int ps2mult_serio_write(struct serio *serio, unsigned char data) serio_write(mx_port, data); - spin_unlock_irqrestore(&psm->lock, flags); - return 0; } @@ -102,11 +99,10 @@ static int ps2mult_serio_start(struct serio *serio) { struct ps2mult *psm = serio_get_drvdata(serio->parent); struct ps2mult_port *port = serio->port_data; - unsigned long flags; - spin_lock_irqsave(&psm->lock, flags); + guard(spinlock_irqsave)(&psm->lock); + port->registered = true; - spin_unlock_irqrestore(&psm->lock, flags); return 0; } @@ -115,11 +111,10 @@ static void ps2mult_serio_stop(struct serio *serio) { struct ps2mult *psm = serio_get_drvdata(serio->parent); struct ps2mult_port *port = serio->port_data; - unsigned long flags; - spin_lock_irqsave(&psm->lock, flags); + guard(spinlock_irqsave)(&psm->lock); + port->registered = false; - spin_unlock_irqrestore(&psm->lock, flags); } static int ps2mult_create_port(struct ps2mult *psm, int i) @@ -148,16 +143,12 @@ static int ps2mult_create_port(struct ps2mult *psm, int i) static void ps2mult_reset(struct ps2mult *psm) { - unsigned long flags; - - spin_lock_irqsave(&psm->lock, flags); + guard(spinlock_irqsave)(&psm->lock); serio_write(psm->mx_serio, PS2MULT_SESSION_END); serio_write(psm->mx_serio, PS2MULT_SESSION_START); ps2mult_select_port(psm, &psm->ports[PS2MULT_KBD_PORT]); - - spin_unlock_irqrestore(&psm->lock, flags); } static int ps2mult_connect(struct serio *serio, struct serio_driver *drv) @@ -234,11 +225,10 @@ static irqreturn_t ps2mult_interrupt(struct serio *serio, { struct ps2mult *psm = serio_get_drvdata(serio); struct ps2mult_port *in_port; - unsigned long flags; dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, dfl); - spin_lock_irqsave(&psm->lock, flags); + guard(spinlock_irqsave)(&psm->lock); if (psm->escape) { psm->escape = false; @@ -285,7 +275,6 @@ static irqreturn_t ps2mult_interrupt(struct serio *serio, } out: - spin_unlock_irqrestore(&psm->lock, flags); return IRQ_HANDLED; } diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index cd4d5be946a361..ae55c4de092f95 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -39,17 +39,14 @@ struct q40kbd { static irqreturn_t q40kbd_interrupt(int irq, void *dev_id) { struct q40kbd *q40kbd = dev_id; - unsigned long flags; - spin_lock_irqsave(&q40kbd->lock, flags); + guard(spinlock_irqsave)(&q40kbd->lock); if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) serio_interrupt(q40kbd->port, master_inb(KEYCODE_REG), 0); master_outb(-1, KEYBOARD_UNLOCK_REG); - spin_unlock_irqrestore(&q40kbd->lock, flags); - return IRQ_HANDLED; } @@ -60,14 +57,11 @@ static irqreturn_t q40kbd_interrupt(int irq, void *dev_id) static void q40kbd_flush(struct q40kbd *q40kbd) { int maxread = 100; - unsigned long flags; - spin_lock_irqsave(&q40kbd->lock, flags); + guard(spinlock_irqsave)(&q40kbd->lock); while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) master_inb(KEYCODE_REG); - - spin_unlock_irqrestore(&q40kbd->lock, flags); } static void q40kbd_stop(void) @@ -166,7 +160,7 @@ static struct platform_driver q40kbd_driver = { .driver = { .name = "q40kbd", }, - .remove_new = q40kbd_remove, + .remove = q40kbd_remove, }; module_platform_driver_probe(q40kbd_driver, q40kbd_probe); diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index e236bb7e101442..c65c552b0c45b0 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -144,7 +144,7 @@ static void rpckbd_remove(struct platform_device *dev) static struct platform_driver rpckbd_driver = { .probe = rpckbd_probe, - .remove_new = rpckbd_remove, + .remove = rpckbd_remove, .driver = { .name = "kart", }, diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 1311caf7dba4f2..375c6f5f905c36 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -92,7 +92,8 @@ static irqreturn_t ps2_txint(int irq, void *dev_id) struct ps2if *ps2if = dev_id; unsigned int status; - spin_lock(&ps2if->lock); + guard(spinlock)(&ps2if->lock); + status = readl_relaxed(ps2if->base + PS2STAT); if (ps2if->head == ps2if->tail) { disable_irq_nosync(irq); @@ -101,7 +102,6 @@ static irqreturn_t ps2_txint(int irq, void *dev_id) writel_relaxed(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA); ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1); } - spin_unlock(&ps2if->lock); return IRQ_HANDLED; } @@ -113,10 +113,9 @@ static irqreturn_t ps2_txint(int irq, void *dev_id) static int ps2_write(struct serio *io, unsigned char val) { struct ps2if *ps2if = io->port_data; - unsigned long flags; unsigned int head; - spin_lock_irqsave(&ps2if->lock, flags); + guard(spinlock_irqsave)(&ps2if->lock); /* * If the TX register is empty, we can go straight out. @@ -133,7 +132,6 @@ static int ps2_write(struct serio *io, unsigned char val) } } - spin_unlock_irqrestore(&ps2if->lock, flags); return 0; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 97d8eacb911276..4468018cef6640 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -38,33 +38,27 @@ static void serio_attach_driver(struct serio_driver *drv); static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) { - int retval; - - mutex_lock(&serio->drv_mutex); - retval = drv->connect(serio, drv); - mutex_unlock(&serio->drv_mutex); + guard(mutex)(&serio->drv_mutex); - return retval; + return drv->connect(serio, drv); } static int serio_reconnect_driver(struct serio *serio) { - int retval = -1; + guard(mutex)(&serio->drv_mutex); - mutex_lock(&serio->drv_mutex); if (serio->drv && serio->drv->reconnect) - retval = serio->drv->reconnect(serio); - mutex_unlock(&serio->drv_mutex); + return serio->drv->reconnect(serio); - return retval; + return -1; } static void serio_disconnect_driver(struct serio *serio) { - mutex_lock(&serio->drv_mutex); + guard(mutex)(&serio->drv_mutex); + if (serio->drv) serio->drv->disconnect(serio); - mutex_unlock(&serio->drv_mutex); } static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) @@ -147,9 +141,8 @@ static LIST_HEAD(serio_event_list); static struct serio_event *serio_get_event(void) { struct serio_event *event = NULL; - unsigned long flags; - spin_lock_irqsave(&serio_event_lock, flags); + guard(spinlock_irqsave)(&serio_event_lock); if (!list_empty(&serio_event_list)) { event = list_first_entry(&serio_event_list, @@ -157,7 +150,6 @@ static struct serio_event *serio_get_event(void) list_del_init(&event->node); } - spin_unlock_irqrestore(&serio_event_lock, flags); return event; } @@ -171,9 +163,8 @@ static void serio_remove_duplicate_events(void *object, enum serio_event_type type) { struct serio_event *e, *next; - unsigned long flags; - spin_lock_irqsave(&serio_event_lock, flags); + guard(spinlock_irqsave)(&serio_event_lock); list_for_each_entry_safe(e, next, &serio_event_list, node) { if (object == e->object) { @@ -189,15 +180,13 @@ static void serio_remove_duplicate_events(void *object, serio_free_event(e); } } - - spin_unlock_irqrestore(&serio_event_lock, flags); } static void serio_handle_event(struct work_struct *work) { struct serio_event *event; - mutex_lock(&serio_mutex); + guard(mutex)(&serio_mutex); while ((event = serio_get_event())) { @@ -228,8 +217,6 @@ static void serio_handle_event(struct work_struct *work) serio_remove_duplicate_events(event->object, event->type); serio_free_event(event); } - - mutex_unlock(&serio_mutex); } static DECLARE_WORK(serio_event_work, serio_handle_event); @@ -237,11 +224,9 @@ static DECLARE_WORK(serio_event_work, serio_handle_event); static int serio_queue_event(void *object, struct module *owner, enum serio_event_type event_type) { - unsigned long flags; struct serio_event *event; - int retval = 0; - spin_lock_irqsave(&serio_event_lock, flags); + guard(spinlock_irqsave)(&serio_event_lock); /* * Scan event list for the other events for the same serio port, @@ -253,7 +238,7 @@ static int serio_queue_event(void *object, struct module *owner, list_for_each_entry_reverse(event, &serio_event_list, node) { if (event->object == object) { if (event->type == event_type) - goto out; + return 0; break; } } @@ -261,16 +246,14 @@ static int serio_queue_event(void *object, struct module *owner, event = kmalloc(sizeof(*event), GFP_ATOMIC); if (!event) { pr_err("Not enough memory to queue event %d\n", event_type); - retval = -ENOMEM; - goto out; + return -ENOMEM; } if (!try_module_get(owner)) { pr_warn("Can't get module reference, dropping event %d\n", event_type); kfree(event); - retval = -EINVAL; - goto out; + return -EINVAL; } event->type = event_type; @@ -280,9 +263,7 @@ static int serio_queue_event(void *object, struct module *owner, list_add_tail(&event->node, &serio_event_list); queue_work(system_long_wq, &serio_event_work); -out: - spin_unlock_irqrestore(&serio_event_lock, flags); - return retval; + return 0; } /* @@ -292,9 +273,8 @@ static int serio_queue_event(void *object, struct module *owner, static void serio_remove_pending_events(void *object) { struct serio_event *event, *next; - unsigned long flags; - spin_lock_irqsave(&serio_event_lock, flags); + guard(spinlock_irqsave)(&serio_event_lock); list_for_each_entry_safe(event, next, &serio_event_list, node) { if (event->object == object) { @@ -302,8 +282,6 @@ static void serio_remove_pending_events(void *object) serio_free_event(event); } } - - spin_unlock_irqrestore(&serio_event_lock, flags); } /* @@ -315,23 +293,19 @@ static void serio_remove_pending_events(void *object) static struct serio *serio_get_pending_child(struct serio *parent) { struct serio_event *event; - struct serio *serio, *child = NULL; - unsigned long flags; + struct serio *serio; - spin_lock_irqsave(&serio_event_lock, flags); + guard(spinlock_irqsave)(&serio_event_lock); list_for_each_entry(event, &serio_event_list, node) { if (event->type == SERIO_REGISTER_PORT) { serio = event->object; - if (serio->parent == parent) { - child = serio; - break; - } + if (serio->parent == parent) + return serio; } } - spin_unlock_irqrestore(&serio_event_lock, flags); - return child; + return NULL; } /* @@ -382,29 +356,27 @@ static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, c struct device_driver *drv; int error; - error = mutex_lock_interruptible(&serio_mutex); - if (error) - return error; - - if (!strncmp(buf, "none", count)) { - serio_disconnect_port(serio); - } else if (!strncmp(buf, "reconnect", count)) { - serio_reconnect_subtree(serio); - } else if (!strncmp(buf, "rescan", count)) { - serio_disconnect_port(serio); - serio_find_driver(serio); - serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); - } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { - serio_disconnect_port(serio); - error = serio_bind_driver(serio, to_serio_driver(drv)); - serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); - } else { - error = -EINVAL; + scoped_cond_guard(mutex_intr, return -EINTR, &serio_mutex) { + if (!strncmp(buf, "none", count)) { + serio_disconnect_port(serio); + } else if (!strncmp(buf, "reconnect", count)) { + serio_reconnect_subtree(serio); + } else if (!strncmp(buf, "rescan", count)) { + serio_disconnect_port(serio); + serio_find_driver(serio); + serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); + } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { + serio_disconnect_port(serio); + error = serio_bind_driver(serio, to_serio_driver(drv)); + serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); + if (error) + return error; + } else { + return -EINVAL; + } } - mutex_unlock(&serio_mutex); - - return error ? error : count; + return count; } static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf) @@ -526,9 +498,9 @@ static void serio_add_port(struct serio *serio) int error; if (parent) { - serio_pause_rx(parent); + guard(serio_pause_rx)(parent); + list_add_tail(&serio->child_node, &parent->children); - serio_continue_rx(parent); } list_add_tail(&serio->node, &serio_list); @@ -560,9 +532,9 @@ static void serio_destroy_port(struct serio *serio) serio->stop(serio); if (serio->parent) { - serio_pause_rx(serio->parent); + guard(serio_pause_rx)(serio->parent); + list_del_init(&serio->child_node); - serio_continue_rx(serio->parent); serio->parent = NULL; } @@ -701,10 +673,10 @@ EXPORT_SYMBOL(__serio_register_port); */ void serio_unregister_port(struct serio *serio) { - mutex_lock(&serio_mutex); + guard(mutex)(&serio_mutex); + serio_disconnect_port(serio); serio_destroy_port(serio); - mutex_unlock(&serio_mutex); } EXPORT_SYMBOL(serio_unregister_port); @@ -715,12 +687,12 @@ void serio_unregister_child_port(struct serio *serio) { struct serio *s, *next; - mutex_lock(&serio_mutex); + guard(mutex)(&serio_mutex); + list_for_each_entry_safe(s, next, &serio->children, child_node) { serio_disconnect_port(s); serio_destroy_port(s); } - mutex_unlock(&serio_mutex); } EXPORT_SYMBOL(serio_unregister_child_port); @@ -784,10 +756,10 @@ static void serio_driver_remove(struct device *dev) static void serio_cleanup(struct serio *serio) { - mutex_lock(&serio->drv_mutex); + guard(mutex)(&serio->drv_mutex); + if (serio->drv && serio->drv->cleanup) serio->drv->cleanup(serio); - mutex_unlock(&serio->drv_mutex); } static void serio_shutdown(struct device *dev) @@ -850,7 +822,7 @@ void serio_unregister_driver(struct serio_driver *drv) { struct serio *serio; - mutex_lock(&serio_mutex); + guard(mutex)(&serio_mutex); drv->manual_bind = true; /* so serio_find_driver ignores it */ serio_remove_pending_events(drv); @@ -866,15 +838,14 @@ void serio_unregister_driver(struct serio_driver *drv) } driver_unregister(&drv->driver); - mutex_unlock(&serio_mutex); } EXPORT_SYMBOL(serio_unregister_driver); static void serio_set_drv(struct serio *serio, struct serio_driver *drv) { - serio_pause_rx(serio); + guard(serio_pause_rx)(serio); + serio->drv = drv; - serio_continue_rx(serio); } static int serio_bus_match(struct device *dev, const struct device_driver *drv) @@ -935,14 +906,14 @@ static int serio_resume(struct device *dev) struct serio *serio = to_serio_port(dev); int error = -ENOENT; - mutex_lock(&serio->drv_mutex); - if (serio->drv && serio->drv->fast_reconnect) { - error = serio->drv->fast_reconnect(serio); - if (error && error != -ENOENT) - dev_warn(dev, "fast reconnect failed with error %d\n", - error); + scoped_guard(mutex, &serio->drv_mutex) { + if (serio->drv && serio->drv->fast_reconnect) { + error = serio->drv->fast_reconnect(serio); + if (error && error != -ENOENT) + dev_warn(dev, "fast reconnect failed with error %d\n", + error); + } } - mutex_unlock(&serio->drv_mutex); if (error) { /* @@ -989,21 +960,17 @@ EXPORT_SYMBOL(serio_close); irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int dfl) { - unsigned long flags; - irqreturn_t ret = IRQ_NONE; + guard(spinlock_irqsave)(&serio->lock); - spin_lock_irqsave(&serio->lock, flags); + if (likely(serio->drv)) + return serio->drv->interrupt(serio, data, dfl); - if (likely(serio->drv)) { - ret = serio->drv->interrupt(serio, data, dfl); - } else if (!dfl && device_is_registered(&serio->dev)) { + if (!dfl && device_is_registered(&serio->dev)) { serio_rescan(serio); - ret = IRQ_HANDLED; + return IRQ_HANDLED; } - spin_unlock_irqrestore(&serio->lock, flags); - - return ret; + return IRQ_NONE; } EXPORT_SYMBOL(serio_interrupt); diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 0186d1b38f49f8..4d63950889860e 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -29,7 +29,7 @@ struct serio_raw { unsigned char queue[SERIO_RAW_QUEUE_LEN]; unsigned int tail, head; - char name[16]; + char name[20]; struct kref kref; struct serio *serio; struct miscdevice dev; @@ -75,41 +75,31 @@ static int serio_raw_open(struct inode *inode, struct file *file) { struct serio_raw *serio_raw; struct serio_raw_client *client; - int retval; - retval = mutex_lock_interruptible(&serio_raw_mutex); - if (retval) - return retval; + scoped_guard(mutex_intr, &serio_raw_mutex) { + serio_raw = serio_raw_locate(iminor(inode)); + if (!serio_raw) + return -ENODEV; - serio_raw = serio_raw_locate(iminor(inode)); - if (!serio_raw) { - retval = -ENODEV; - goto out; - } + if (serio_raw->dead) + return -ENODEV; - if (serio_raw->dead) { - retval = -ENODEV; - goto out; - } + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; - client = kzalloc(sizeof(*client), GFP_KERNEL); - if (!client) { - retval = -ENOMEM; - goto out; - } + client->serio_raw = serio_raw; + file->private_data = client; - client->serio_raw = serio_raw; - file->private_data = client; + kref_get(&serio_raw->kref); - kref_get(&serio_raw->kref); + scoped_guard(serio_pause_rx, serio_raw->serio) + list_add_tail(&client->node, &serio_raw->client_list); - serio_pause_rx(serio_raw->serio); - list_add_tail(&client->node, &serio_raw->client_list); - serio_continue_rx(serio_raw->serio); + return 0; + } -out: - mutex_unlock(&serio_raw_mutex); - return retval; + return -EINTR; } static void serio_raw_free(struct kref *kref) @@ -126,9 +116,8 @@ static int serio_raw_release(struct inode *inode, struct file *file) struct serio_raw_client *client = file->private_data; struct serio_raw *serio_raw = client->serio_raw; - serio_pause_rx(serio_raw->serio); - list_del(&client->node); - serio_continue_rx(serio_raw->serio); + scoped_guard(serio_pause_rx, serio_raw->serio) + list_del(&client->node); kfree(client); @@ -139,19 +128,15 @@ static int serio_raw_release(struct inode *inode, struct file *file) static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) { - bool empty; + guard(serio_pause_rx)(serio_raw->serio); - serio_pause_rx(serio_raw->serio); - - empty = serio_raw->head == serio_raw->tail; - if (!empty) { - *c = serio_raw->queue[serio_raw->tail]; - serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; - } + if (serio_raw->head == serio_raw->tail) + return false; /* queue is empty */ - serio_continue_rx(serio_raw->serio); + *c = serio_raw->queue[serio_raw->tail]; + serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; - return !empty; + return true; } static ssize_t serio_raw_read(struct file *file, char __user *buffer, @@ -200,40 +185,32 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, { struct serio_raw_client *client = file->private_data; struct serio_raw *serio_raw = client->serio_raw; - int retval = 0; + int written = 0; unsigned char c; - retval = mutex_lock_interruptible(&serio_raw_mutex); - if (retval) - return retval; + scoped_guard(mutex_intr, &serio_raw_mutex) { + if (serio_raw->dead) + return -ENODEV; - if (serio_raw->dead) { - retval = -ENODEV; - goto out; - } + if (count > 32) + count = 32; - if (count > 32) - count = 32; + while (count--) { + if (get_user(c, buffer++)) + return -EFAULT; - while (count--) { - if (get_user(c, buffer++)) { - retval = -EFAULT; - goto out; - } + if (serio_write(serio_raw->serio, c)) { + /* Either signal error or partial write */ + return written ?: -EIO; + } - if (serio_write(serio_raw->serio, c)) { - /* Either signal error or partial write */ - if (retval == 0) - retval = -EIO; - goto out; + written++; } - retval++; + return written; } -out: - mutex_unlock(&serio_raw_mutex); - return retval; + return -EINTR; } static __poll_t serio_raw_poll(struct file *file, poll_table *wait) @@ -300,7 +277,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) } snprintf(serio_raw->name, sizeof(serio_raw->name), - "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no)); + "serio_raw%u", atomic_inc_return(&serio_raw_no)); kref_init(&serio_raw->kref); INIT_LIST_HEAD(&serio_raw->client_list); init_waitqueue_head(&serio_raw->wait); @@ -379,10 +356,10 @@ static void serio_raw_hangup(struct serio_raw *serio_raw) { struct serio_raw_client *client; - serio_pause_rx(serio_raw->serio); - list_for_each_entry(client, &serio_raw->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); - serio_continue_rx(serio_raw->serio); + scoped_guard(serio_pause_rx, serio_raw->serio) { + list_for_each_entry(client, &serio_raw->client_list, node) + kill_fasync(&client->fasync, SIGIO, POLL_HUP); + } wake_up_interruptible(&serio_raw->wait); } @@ -394,10 +371,10 @@ static void serio_raw_disconnect(struct serio *serio) misc_deregister(&serio_raw->dev); - mutex_lock(&serio_raw_mutex); - serio_raw->dead = true; - list_del_init(&serio_raw->node); - mutex_unlock(&serio_raw_mutex); + scoped_guard(mutex, &serio_raw_mutex) { + serio_raw->dead = true; + list_del_init(&serio_raw->node); + } serio_raw_hangup(serio_raw); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 5a2b5404ffc21e..74ac8879618739 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -50,11 +50,9 @@ static int serport_serio_write(struct serio *serio, unsigned char data) static int serport_serio_open(struct serio *serio) { struct serport *serport = serio->port_data; - unsigned long flags; - spin_lock_irqsave(&serport->lock, flags); + guard(spinlock_irqsave)(&serport->lock); set_bit(SERPORT_ACTIVE, &serport->flags); - spin_unlock_irqrestore(&serport->lock, flags); return 0; } @@ -63,11 +61,9 @@ static int serport_serio_open(struct serio *serio) static void serport_serio_close(struct serio *serio) { struct serport *serport = serio->port_data; - unsigned long flags; - spin_lock_irqsave(&serport->lock, flags); + guard(spinlock_irqsave)(&serport->lock); clear_bit(SERPORT_ACTIVE, &serport->flags); - spin_unlock_irqrestore(&serport->lock, flags); } /* @@ -118,14 +114,13 @@ static void serport_ldisc_receive(struct tty_struct *tty, const u8 *cp, const u8 *fp, size_t count) { struct serport *serport = tty->disc_data; - unsigned long flags; unsigned int ch_flags = 0; int i; - spin_lock_irqsave(&serport->lock, flags); + guard(spinlock_irqsave)(&serport->lock); if (!test_bit(SERPORT_ACTIVE, &serport->flags)) - goto out; + return; for (i = 0; i < count; i++) { if (fp) { @@ -146,9 +141,6 @@ static void serport_ldisc_receive(struct tty_struct *tty, const u8 *cp, serio_interrupt(serport->serio, cp[i], ch_flags); } - -out: - spin_unlock_irqrestore(&serport->lock, flags); } /* @@ -246,11 +238,9 @@ static int serport_ldisc_compat_ioctl(struct tty_struct *tty, static void serport_ldisc_hangup(struct tty_struct *tty) { struct serport *serport = tty->disc_data; - unsigned long flags; - spin_lock_irqsave(&serport->lock, flags); - set_bit(SERPORT_DEAD, &serport->flags); - spin_unlock_irqrestore(&serport->lock, flags); + scoped_guard(spinlock_irqsave, &serport->lock) + set_bit(SERPORT_DEAD, &serport->flags); wake_up_interruptible(&serport->wait); } @@ -258,12 +248,11 @@ static void serport_ldisc_hangup(struct tty_struct *tty) static void serport_ldisc_write_wakeup(struct tty_struct * tty) { struct serport *serport = tty->disc_data; - unsigned long flags; - spin_lock_irqsave(&serport->lock, flags); + guard(spinlock_irqsave)(&serport->lock); + if (test_bit(SERPORT_ACTIVE, &serport->flags)) serio_drv_write_wakeup(serport->serio); - spin_unlock_irqrestore(&serport->lock, flags); } /* diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c index 95cd8aaee65da2..524929ce1cae1c 100644 --- a/drivers/input/serio/sun4i-ps2.c +++ b/drivers/input/serio/sun4i-ps2.c @@ -101,7 +101,7 @@ static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id) unsigned int rxflags = 0; u32 rval; - spin_lock(&drvdata->lock); + guard(spinlock)(&drvdata->lock); /* Get the PS/2 interrupts and clear them */ intr_status = readl(drvdata->reg_base + PS2_REG_LSTS); @@ -134,8 +134,6 @@ static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id) writel(intr_status, drvdata->reg_base + PS2_REG_LSTS); writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS); - spin_unlock(&drvdata->lock); - return IRQ_HANDLED; } @@ -146,7 +144,6 @@ static int sun4i_ps2_open(struct serio *serio) u32 clk_scdf; u32 clk_pcdf; u32 rval; - unsigned long flags; /* Set line control and enable interrupt */ rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN @@ -171,9 +168,8 @@ static int sun4i_ps2_open(struct serio *serio) rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER | PS2_GCTL_BUSEN; - spin_lock_irqsave(&drvdata->lock, flags); + guard(spinlock_irqsave)(&drvdata->lock); writel(rval, drvdata->reg_base + PS2_REG_GCTL); - spin_unlock_irqrestore(&drvdata->lock, flags); return 0; } @@ -322,7 +318,7 @@ MODULE_DEVICE_TABLE(of, sun4i_ps2_match); static struct platform_driver sun4i_ps2_driver = { .probe = sun4i_ps2_probe, - .remove_new = sun4i_ps2_remove, + .remove = sun4i_ps2_remove, .driver = { .name = DRIVER_NAME, .of_match_table = sun4i_ps2_match, diff --git a/drivers/input/serio/userio.c b/drivers/input/serio/userio.c index 1ab12b247f9878..7f627b08055e94 100644 --- a/drivers/input/serio/userio.c +++ b/drivers/input/serio/userio.c @@ -55,18 +55,15 @@ struct userio_device { static int userio_device_write(struct serio *id, unsigned char val) { struct userio_device *userio = id->port_data; - unsigned long flags; - spin_lock_irqsave(&userio->buf_lock, flags); + scoped_guard(spinlock_irqsave, &userio->buf_lock) { + userio->buf[userio->head] = val; + userio->head = (userio->head + 1) % USERIO_BUFSIZE; - userio->buf[userio->head] = val; - userio->head = (userio->head + 1) % USERIO_BUFSIZE; - - if (userio->head == userio->tail) - dev_warn(userio_misc.this_device, - "Buffer overflowed, userio client isn't keeping up"); - - spin_unlock_irqrestore(&userio->buf_lock, flags); + if (userio->head == userio->tail) + dev_warn(userio_misc.this_device, + "Buffer overflowed, userio client isn't keeping up"); + } wake_up_interruptible(&userio->waitq); @@ -75,9 +72,8 @@ static int userio_device_write(struct serio *id, unsigned char val) static int userio_char_open(struct inode *inode, struct file *file) { - struct userio_device *userio; - - userio = kzalloc(sizeof(*userio), GFP_KERNEL); + struct userio_device *userio __free(kfree) = + kzalloc(sizeof(*userio), GFP_KERNEL); if (!userio) return -ENOMEM; @@ -86,15 +82,13 @@ static int userio_char_open(struct inode *inode, struct file *file) init_waitqueue_head(&userio->waitq); userio->serio = kzalloc(sizeof(*userio->serio), GFP_KERNEL); - if (!userio->serio) { - kfree(userio); + if (!userio->serio) return -ENOMEM; - } userio->serio->write = userio_device_write; userio->serio->port_data = userio; - file->private_data = userio; + file->private_data = no_free_ptr(userio); return 0; } @@ -118,14 +112,32 @@ static int userio_char_release(struct inode *inode, struct file *file) return 0; } +static size_t userio_fetch_data(struct userio_device *userio, u8 *buf, + size_t count, size_t *copylen) +{ + size_t available, len; + + guard(spinlock_irqsave)(&userio->buf_lock); + + available = CIRC_CNT_TO_END(userio->head, userio->tail, + USERIO_BUFSIZE); + len = min(available, count); + if (len) { + memcpy(buf, &userio->buf[userio->tail], len); + userio->tail = (userio->tail + len) % USERIO_BUFSIZE; + } + + *copylen = len; + return available; +} + static ssize_t userio_char_read(struct file *file, char __user *user_buffer, size_t count, loff_t *ppos) { struct userio_device *userio = file->private_data; int error; - size_t nonwrap_len, copylen; - unsigned char buf[USERIO_BUFSIZE]; - unsigned long flags; + size_t available, copylen; + u8 buf[USERIO_BUFSIZE]; /* * By the time we get here, the data that was waiting might have @@ -135,21 +147,8 @@ static ssize_t userio_char_read(struct file *file, char __user *user_buffer, * of course). */ for (;;) { - spin_lock_irqsave(&userio->buf_lock, flags); - - nonwrap_len = CIRC_CNT_TO_END(userio->head, - userio->tail, - USERIO_BUFSIZE); - copylen = min(nonwrap_len, count); - if (copylen) { - memcpy(buf, &userio->buf[userio->tail], copylen); - userio->tail = (userio->tail + copylen) % - USERIO_BUFSIZE; - } - - spin_unlock_irqrestore(&userio->buf_lock, flags); - - if (nonwrap_len) + available = userio_fetch_data(userio, buf, count, ©len); + if (available) break; /* buffer was/is empty */ @@ -176,40 +175,21 @@ static ssize_t userio_char_read(struct file *file, char __user *user_buffer, return copylen; } -static ssize_t userio_char_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) +static int userio_execute_cmd(struct userio_device *userio, + const struct userio_cmd *cmd) { - struct userio_device *userio = file->private_data; - struct userio_cmd cmd; - int error; - - if (count != sizeof(cmd)) { - dev_warn(userio_misc.this_device, "Invalid payload size\n"); - return -EINVAL; - } - - if (copy_from_user(&cmd, buffer, sizeof(cmd))) - return -EFAULT; - - error = mutex_lock_interruptible(&userio->mutex); - if (error) - return error; - - switch (cmd.type) { + switch (cmd->type) { case USERIO_CMD_REGISTER: if (!userio->serio->id.type) { dev_warn(userio_misc.this_device, "No port type given on /dev/userio\n"); - - error = -EINVAL; - goto out; + return -EINVAL; } if (userio->running) { dev_warn(userio_misc.this_device, "Begin command sent, but we're already running\n"); - error = -EBUSY; - goto out; + return -EBUSY; } userio->running = true; @@ -220,32 +200,51 @@ static ssize_t userio_char_write(struct file *file, const char __user *buffer, if (userio->running) { dev_warn(userio_misc.this_device, "Can't change port type on an already running userio instance\n"); - error = -EBUSY; - goto out; + return -EBUSY; } - userio->serio->id.type = cmd.data; + userio->serio->id.type = cmd->data; break; case USERIO_CMD_SEND_INTERRUPT: if (!userio->running) { dev_warn(userio_misc.this_device, "The device must be registered before sending interrupts\n"); - error = -ENODEV; - goto out; + return -ENODEV; } - serio_interrupt(userio->serio, cmd.data, 0); + serio_interrupt(userio->serio, cmd->data, 0); break; default: - error = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; + } + + return 0; +} + +static ssize_t userio_char_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct userio_device *userio = file->private_data; + struct userio_cmd cmd; + int error; + + if (count != sizeof(cmd)) { + dev_warn(userio_misc.this_device, "Invalid payload size\n"); + return -EINVAL; + } + + if (copy_from_user(&cmd, buffer, sizeof(cmd))) + return -EFAULT; + + scoped_cond_guard(mutex_intr, return -EINTR, &userio->mutex) { + error = userio_execute_cmd(userio, &cmd); + if (error) + return error; } -out: - mutex_unlock(&userio->mutex); - return error ?: count; + return count; } static __poll_t userio_char_poll(struct file *file, poll_table *wait) diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 1543267d02acd8..01433f0b48f161 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -155,22 +155,17 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id) static int sxps2_write(struct serio *pserio, unsigned char c) { struct xps2data *drvdata = pserio->port_data; - unsigned long flags; u32 sr; - int status = -1; - spin_lock_irqsave(&drvdata->lock, flags); + guard(spinlock_irqsave)(&drvdata->lock); /* If the PS/2 transmitter is empty send a byte of data */ sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET); - if (!(sr & XPS2_STATUS_TX_FULL)) { - out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, c); - status = 0; - } + if (sr & XPS2_STATUS_TX_FULL) + return -EAGAIN; - spin_unlock_irqrestore(&drvdata->lock, flags); - - return status; + out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, c); + return 0; } /** @@ -358,7 +353,7 @@ static struct platform_driver xps2_of_driver = { .of_match_table = xps2_of_match, }, .probe = xps2_of_probe, - .remove_new = xps2_of_remove, + .remove = xps2_of_remove, }; module_platform_driver(xps2_of_driver); diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c index a68da2988f9cd8..8d6b71d5979316 100644 --- a/drivers/input/tablet/pegasus_notetaker.c +++ b/drivers/input/tablet/pegasus_notetaker.c @@ -214,6 +214,28 @@ static void pegasus_init(struct work_struct *work) error); } +static int __pegasus_open(struct pegasus *pegasus) +{ + int error; + + guard(mutex)(&pegasus->pm_mutex); + + pegasus->irq->dev = pegasus->usbdev; + if (usb_submit_urb(pegasus->irq, GFP_KERNEL)) + return -EIO; + + error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE); + if (error) { + usb_kill_urb(pegasus->irq); + cancel_work_sync(&pegasus->init); + return error; + } + + pegasus->is_open = true; + + return 0; +} + static int pegasus_open(struct input_dev *dev) { struct pegasus *pegasus = input_get_drvdata(dev); @@ -223,39 +245,25 @@ static int pegasus_open(struct input_dev *dev) if (error) return error; - mutex_lock(&pegasus->pm_mutex); - pegasus->irq->dev = pegasus->usbdev; - if (usb_submit_urb(pegasus->irq, GFP_KERNEL)) { - error = -EIO; - goto err_autopm_put; + error = __pegasus_open(pegasus); + if (error) { + usb_autopm_put_interface(pegasus->intf); + return error; } - error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE); - if (error) - goto err_kill_urb; - - pegasus->is_open = true; - mutex_unlock(&pegasus->pm_mutex); return 0; - -err_kill_urb: - usb_kill_urb(pegasus->irq); - cancel_work_sync(&pegasus->init); -err_autopm_put: - mutex_unlock(&pegasus->pm_mutex); - usb_autopm_put_interface(pegasus->intf); - return error; } static void pegasus_close(struct input_dev *dev) { struct pegasus *pegasus = input_get_drvdata(dev); - mutex_lock(&pegasus->pm_mutex); - usb_kill_urb(pegasus->irq); - cancel_work_sync(&pegasus->init); - pegasus->is_open = false; - mutex_unlock(&pegasus->pm_mutex); + scoped_guard(mutex, &pegasus->pm_mutex) { + usb_kill_urb(pegasus->irq); + cancel_work_sync(&pegasus->init); + + pegasus->is_open = false; + } usb_autopm_put_interface(pegasus->intf); } @@ -411,10 +419,10 @@ static int pegasus_suspend(struct usb_interface *intf, pm_message_t message) { struct pegasus *pegasus = usb_get_intfdata(intf); - mutex_lock(&pegasus->pm_mutex); + guard(mutex)(&pegasus->pm_mutex); + usb_kill_urb(pegasus->irq); cancel_work_sync(&pegasus->init); - mutex_unlock(&pegasus->pm_mutex); return 0; } @@ -422,31 +430,33 @@ static int pegasus_suspend(struct usb_interface *intf, pm_message_t message) static int pegasus_resume(struct usb_interface *intf) { struct pegasus *pegasus = usb_get_intfdata(intf); - int retval = 0; - mutex_lock(&pegasus->pm_mutex); + guard(mutex)(&pegasus->pm_mutex); + if (pegasus->is_open && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0) - retval = -EIO; - mutex_unlock(&pegasus->pm_mutex); + return -EIO; - return retval; + return 0; } static int pegasus_reset_resume(struct usb_interface *intf) { struct pegasus *pegasus = usb_get_intfdata(intf); - int retval = 0; + int error; + + guard(mutex)(&pegasus->pm_mutex); - mutex_lock(&pegasus->pm_mutex); if (pegasus->is_open) { - retval = pegasus_set_mode(pegasus, PEN_MODE_XY, + error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE); - if (!retval && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0) - retval = -EIO; + if (error) + return error; + + if (usb_submit_urb(pegasus->irq, GFP_NOIO) < 0) + return -EIO; } - mutex_unlock(&pegasus->pm_mutex); - return retval; + return 0; } static const struct usb_device_id pegasus_ids[] = { diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 81a3ea4b9a3dd1..0468ce2b216f63 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -117,13 +117,14 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, struct pm860x_chip *chip, int *res_x) { - struct device_node *np = pdev->dev.parent->of_node; struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ : chip->companion; int data, n, ret; - if (!np) + if (!pdev->dev.parent->of_node) return -ENODEV; - np = of_get_child_by_name(np, "touch"); + + struct device_node *np __free(device_node) = + of_get_child_by_name(pdev->dev.parent->of_node, "touch"); if (!np) { dev_err(&pdev->dev, "Can't find touch node\n"); return -EINVAL; @@ -141,13 +142,13 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, if (data) { ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); if (ret < 0) - goto err_put_node; + return -EINVAL; } /* set tsi prebias time */ if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) { ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); if (ret < 0) - goto err_put_node; + return -EINVAL; } /* set prebias & prechg time of pen detect */ data = 0; @@ -158,18 +159,11 @@ static int pm860x_touch_dt_init(struct platform_device *pdev, if (data) { ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); if (ret < 0) - goto err_put_node; + return -EINVAL; } of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x); - of_node_put(np); - return 0; - -err_put_node: - of_node_put(np); - - return -EINVAL; } #else #define pm860x_touch_dt_init(x, y, z) (-1) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1ac26fc2e3eb94..1a03de7fcfa66c 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -420,6 +420,7 @@ config TOUCHSCREEN_GOODIX_BERLIN_SPI config TOUCHSCREEN_HIDEEP tristate "HiDeep Touch IC" depends on I2C + select REGMAP_I2C help Say Y here if you have a touchscreen using HiDeep. @@ -431,6 +432,7 @@ config TOUCHSCREEN_HIDEEP config TOUCHSCREEN_HYCON_HY46XX tristate "Hycon hy46xx touchscreen support" depends on I2C + select REGMAP_I2C help Say Y here if you have a touchscreen using Hycon hy46xx diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 607f18af70104d..066dc04003fa83 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -331,7 +331,7 @@ struct ser_req { u8 ref_off; u16 scratch; struct spi_message msg; - struct spi_transfer xfer[6]; + struct spi_transfer xfer[8]; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. @@ -405,9 +405,19 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) req->xfer[5].rx_buf = &req->scratch; req->xfer[5].len = 2; - CS_CHANGE(req->xfer[5]); spi_message_add_tail(&req->xfer[5], &req->msg); + /* clear the command register */ + req->scratch = 0; + req->xfer[6].tx_buf = &req->scratch; + req->xfer[6].len = 1; + spi_message_add_tail(&req->xfer[6], &req->msg); + + req->xfer[7].rx_buf = &req->scratch; + req->xfer[7].len = 2; + CS_CHANGE(req->xfer[7]); + spi_message_add_tail(&req->xfer[7], &req->msg); + mutex_lock(&ts->lock); ads7846_stop(ts); status = spi_sync(spi, &req->msg); diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 8db2a112a47673..363a4a1f1560e9 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -72,7 +72,7 @@ /* * Interrupt modes: - * periodical: interrupt is asserted periodicaly + * periodical: interrupt is asserted periodically * compare coordinates: interrupt is asserted when coordinates change * indicate touch: interrupt is asserted during touch */ diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c index 9c84235327bfb7..e49bde50d77a22 100644 --- a/drivers/input/touchscreen/bcm_iproc_tsc.c +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c @@ -217,7 +217,7 @@ static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data) "pen up-down (%d)\n", priv->pen_status); } - /* coordinates in FIFO exceed the theshold */ + /* coordinates in FIFO exceed the threshold */ if (intr_status & TS_FIFO_INTR_MASK) { for (i = 0; i < priv->cfg_params.fifo_threshold; i++) { regmap_read(priv->regmap, FIFO_DATA, &raw_coordinate); diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index 52e0e834e76fba..c2d3252f84668c 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c @@ -326,7 +326,7 @@ static void da9052_ts_remove(struct platform_device *pdev) static struct platform_driver da9052_tsi_driver = { .probe = da9052_ts_probe, - .remove_new = da9052_ts_remove, + .remove = da9052_ts_remove, .driver = { .name = "da9052-tsi", }, diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 85c6d8ce003f3a..0d7bf18e25087c 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1237,7 +1237,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) } /* - * Check which sleep modes we can support. Power-off requieres the + * Check which sleep modes we can support. Power-off requires the * reset-pin to ensure correct power-down/power-up behaviour. Start with * the EDT_PMODE_POWEROFF test since this is the deepest possible sleep * mode. diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index eb883db5542057..ad209e6e82a64d 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -225,10 +225,10 @@ static int elo_command_10(struct elo *elo, unsigned char *packet) mutex_lock(&elo->cmd_mutex); - serio_pause_rx(elo->serio); - elo->expected_packet = toupper(packet[0]); - init_completion(&elo->cmd_done); - serio_continue_rx(elo->serio); + scoped_guard(serio_pause_rx, elo->serio) { + elo->expected_packet = toupper(packet[0]); + init_completion(&elo->cmd_done); + } if (serio_write(elo->serio, ELO10_LEAD_BYTE)) goto out; diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 260c83dc23a2e2..fa38d70aded7b6 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -898,7 +898,7 @@ static umode_t ili210x_attributes_visible(struct kobject *kobj, if (attr == &dev_attr_calibrate.attr) return priv->chip->has_calibrate_reg ? attr->mode : 0; - /* Firmware/Kernel/Protocol/BootMode is implememted only for ILI251x */ + /* Firmware/Kernel/Protocol/BootMode is implemented only for ILI251x */ if (!priv->chip->has_firmware_proto) return 0; diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c index aeabf8d057ded6..abeae9102323c0 100644 --- a/drivers/input/touchscreen/imagis.c +++ b/drivers/input/touchscreen/imagis.c @@ -395,6 +395,7 @@ static int imagis_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume); +#ifdef CONFIG_OF static const struct imagis_properties imagis_3032c_data = { .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE, .touch_coord_cmd = IST3038C_REG_TOUCH_COORD, @@ -427,7 +428,6 @@ static const struct imagis_properties imagis_3038c_data = { .protocol_b = true, }; -#ifdef CONFIG_OF static const struct of_device_id imagis_of_match[] = { { .compatible = "imagis,ist3032c", .data = &imagis_3032c_data }, { .compatible = "imagis,ist3038", .data = &imagis_3038_data }, diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index bfbebe245040c1..5abf164ae14c18 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -261,7 +261,7 @@ static void mainstone_wm97xx_remove(struct platform_device *pdev) static struct platform_driver mainstone_wm97xx_driver = { .probe = mainstone_wm97xx_probe, - .remove_new = mainstone_wm97xx_remove, + .remove = mainstone_wm97xx_remove, .driver = { .name = "wm97xx-touch", }, diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index cbcd6e34efb7d1..33635da8507999 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -226,7 +226,7 @@ static void mc13783_ts_remove(struct platform_device *pdev) } static struct platform_driver mc13783_ts_driver = { - .remove_new = mc13783_ts_remove, + .remove = mc13783_ts_remove, .driver = { .name = MC13783_TS_NAME, }, diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c index 0afee41ac9de0e..44b58e0dc1ada1 100644 --- a/drivers/input/touchscreen/novatek-nvt-ts.c +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -31,9 +31,6 @@ #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 @@ -51,10 +48,16 @@ static const int nvt_ts_irq_type[4] = { IRQF_TRIGGER_HIGH }; +struct nvt_ts_i2c_chip_data { + u8 wake_type; + u8 chip_id; +}; + struct nvt_ts_data { struct i2c_client *client; struct input_dev *input; struct gpio_desc *reset_gpio; + struct regulator_bulk_data regulators[2]; struct touchscreen_properties prop; int max_touches; u8 buf[NVT_TS_TOUCH_SIZE * NVT_TS_MAX_TOUCHES]; @@ -142,6 +145,13 @@ static irqreturn_t nvt_ts_irq(int irq, void *dev_id) static int nvt_ts_start(struct input_dev *dev) { struct nvt_ts_data *data = input_get_drvdata(dev); + int error; + + error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), data->regulators); + if (error) { + dev_err(&data->client->dev, "failed to enable regulators\n"); + return error; + } enable_irq(data->client->irq); gpiod_set_value_cansleep(data->reset_gpio, 0); @@ -155,6 +165,7 @@ static void nvt_ts_stop(struct input_dev *dev) disable_irq(data->client->irq); gpiod_set_value_cansleep(data->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); } static int nvt_ts_suspend(struct device *dev) @@ -188,6 +199,7 @@ 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; + const struct nvt_ts_i2c_chip_data *chip; struct input_dev *input; if (!client->irq) { @@ -199,12 +211,35 @@ static int nvt_ts_probe(struct i2c_client *client) if (!data) return -ENOMEM; + chip = device_get_match_data(&client->dev); + if (!chip) + return -EINVAL; + data->client = client; i2c_set_clientdata(client, data); + /* + * VCC is the analog voltage supply + * IOVCC is the digital voltage supply + */ + data->regulators[0].supply = "vcc"; + data->regulators[1].supply = "iovcc"; + error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators), data->regulators); + if (error) { + dev_err(dev, "cannot get regulators: %d\n", error); + return error; + } + + error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), data->regulators); + if (error) { + dev_err(dev, "failed to enable regulators: %d\n", error); + return error; + } + data->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); error = PTR_ERR_OR_ZERO(data->reset_gpio); if (error) { + regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); dev_err(dev, "failed to request reset GPIO: %d\n", error); return error; } @@ -214,6 +249,7 @@ static int nvt_ts_probe(struct i2c_client *client) 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 */ + regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); if (error) return error; @@ -225,8 +261,8 @@ static int nvt_ts_probe(struct i2c_client *client) 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) { + data->buf[NVT_TS_PARAMS_WAKE_TYPE] != chip->wake_type || + data->buf[NVT_TS_PARAMS_CHIP_ID] != chip->chip_id) { dev_err(dev, "Unsupported touchscreen parameters: %*ph\n", NVT_TS_PARAMS_SIZE, data->buf); return -EIO; @@ -277,8 +313,26 @@ static int nvt_ts_probe(struct i2c_client *client) return 0; } +static const struct nvt_ts_i2c_chip_data nvt_nt11205_ts_data = { + .wake_type = 0x05, + .chip_id = 0x05, +}; + +static const struct nvt_ts_i2c_chip_data nvt_nt36672a_ts_data = { + .wake_type = 0x01, + .chip_id = 0x08, +}; + +static const struct of_device_id nvt_ts_of_match[] = { + { .compatible = "novatek,nt11205-ts", .data = &nvt_nt11205_ts_data }, + { .compatible = "novatek,nt36672a-ts", .data = &nvt_nt36672a_ts_data }, + { } +}; +MODULE_DEVICE_TABLE(of, nvt_ts_of_match); + static const struct i2c_device_id nvt_ts_i2c_id[] = { - { "NVT-ts" }, + { "nt11205-ts", (unsigned long) &nvt_nt11205_ts_data }, + { "nt36672a-ts", (unsigned long) &nvt_nt36672a_ts_data }, { } }; MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id); @@ -287,6 +341,7 @@ static struct i2c_driver nvt_ts_driver = { .driver = { .name = "novatek-nvt-ts", .pm = pm_sleep_ptr(&nvt_ts_pm_ops), + .of_match_table = nvt_ts_of_match, }, .probe = nvt_ts_probe, .id_table = nvt_ts_i2c_id, diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index 821245019feaae..083206a3457b8d 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -238,7 +238,7 @@ static const struct dev_pm_ops pcap_ts_pm_ops = { static struct platform_driver pcap_ts_driver = { .probe = pcap_ts_probe, - .remove_new = pcap_ts_remove, + .remove = pcap_ts_remove, .driver = { .name = "pcap-ts", .pm = PCAP_TS_PM_OPS, diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 83bf27085ebc09..dad5786e82a46d 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -44,7 +44,7 @@ enum pixcir_power_mode { /* * Interrupt modes: - * periodical: interrupt is asserted periodicaly + * periodical: interrupt is asserted periodically * diff coordinates: interrupt is asserted when coordinates change * level on touch: interrupt level asserted during touch * pulse on touch: interrupt pulse asserted during touch diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index 45c575df994e01..841d39a449b373 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -122,20 +122,18 @@ static int rpi_ts_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct input_dev *input; - struct device_node *fw_node; struct rpi_firmware *fw; struct rpi_ts *ts; u32 touchbuf; int error; - fw_node = of_get_parent(np); + struct device_node *fw_node __free(device_node) = of_get_parent(np); if (!fw_node) { dev_err(dev, "Missing firmware node\n"); return -ENOENT; } fw = devm_rpi_firmware_get(&pdev->dev, fw_node); - of_node_put(fw_node); if (!fw) return -EPROBE_DEFER; diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index 0e5cc9fbad1777..295d8d75ba3224 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -388,13 +388,13 @@ static int rohm_ts_manual_calibration(struct rohm_ts_data *ts) err_y = (int)READ_CALIB_BUF(PRM1_Y_H) << 2 | READ_CALIB_BUF(PRM1_Y_L); - /* X axis ajust */ + /* X axis adjust */ if (err_x <= 4) calib_x -= AXIS_ADJUST; else if (err_x >= 60) calib_x += AXIS_ADJUST; - /* Y axis ajust */ + /* Y axis adjust */ if (err_y <= 4) calib_y -= AXIS_ADJUST; else if (err_y >= 60) diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index b204fdb2d22c61..a94a1997f96b7d 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -107,7 +107,7 @@ static void stmpe_work(struct work_struct *work) /* * touch_det sometimes get desasserted or just get stuck. This appears - * to be a silicon bug, We still have to clearify this with the + * to be a silicon bug, We still have to clarify this with the * manufacture. As a workaround We release the key anyway if the * touch_det keeps coming in after 4ms, while the FIFO contains no value * during the whole time. @@ -140,7 +140,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data) /* * The FIFO sometimes just crashes and stops generating interrupts. This - * appears to be a silicon bug. We still have to clearify this with + * appears to be a silicon bug. We still have to clarify this with * the manufacture. As a workaround we disable the TSC while we are * collecting data and flush the FIFO after reading */ @@ -362,7 +362,7 @@ static struct platform_driver stmpe_ts_driver = { .name = STMPE_TS_NAME, }, .probe = stmpe_input_probe, - .remove_new = stmpe_ts_remove, + .remove = stmpe_ts_remove, }; module_platform_driver(stmpe_ts_driver); diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 92b2b840b4b7b7..e8286060043aeb 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -396,12 +396,12 @@ static const struct of_device_id sun4i_ts_of_match[] = { MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); static struct platform_driver sun4i_ts_driver = { - .driver = { + .driver = { .name = "sun4i-ts", .of_match_table = sun4i_ts_of_match, }, .probe = sun4i_ts_probe, - .remove_new = sun4i_ts_remove, + .remove = sun4i_ts_remove, }; module_platform_driver(sun4i_ts_driver); diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 294b7ceded2728..93d659ff90aa94 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -550,9 +550,9 @@ MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids); static struct platform_driver ti_tsc_driver = { .probe = titsc_probe, - .remove_new = titsc_remove, + .remove = titsc_remove, .driver = { - .name = "TI-am335x-tsc", + .name = "TI-am335x-tsc", .pm = pm_sleep_ptr(&titsc_pm_ops), .of_match_table = ti_tsc_dt_ids, }, diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c index 6cf66aadc10edd..98422d1e80d6d4 100644 --- a/drivers/input/touchscreen/ts4800-ts.c +++ b/drivers/input/touchscreen/ts4800-ts.c @@ -110,18 +110,17 @@ static int ts4800_parse_dt(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *syscon_np; u32 reg, bit; int error; - syscon_np = of_parse_phandle(np, "syscon", 0); + struct device_node *syscon_np __free(device_node) = + of_parse_phandle(np, "syscon", 0); if (!syscon_np) { dev_err(dev, "no syscon property\n"); return -ENODEV; } ts->regmap = syscon_node_to_regmap(syscon_np); - of_node_put(syscon_np); if (IS_ERR(ts->regmap)) { dev_err(dev, "cannot get parent's regmap\n"); return PTR_ERR(ts->regmap); diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 9cee26b63341df..98f8ec408cad60 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -387,7 +387,7 @@ static struct platform_driver wm831x_ts_driver = { .name = "wm831x-touch", }, .probe = wm831x_ts_probe, - .remove_new = wm831x_ts_remove, + .remove = wm831x_ts_remove, }; module_platform_driver(wm831x_ts_driver); diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index f01f6cc9b59fa8..b25771a8df2b3d 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -222,7 +222,7 @@ EXPORT_SYMBOL_GPL(wm97xx_set_gpio); /* * Codec GPIO pin configuration, this sets pin direction, polarity, - * stickyness and wake up. + * stickiness and wake up. */ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir, enum wm97xx_gpio_pol pol, enum wm97xx_gpio_sticky sticky, @@ -403,7 +403,7 @@ static int wm97xx_read_samples(struct wm97xx *wm) * is actively working with the touchscreen we * don't want to lose the quick response. So we * will slowly increase sleep time after the - * pen is up and quicky restore it to ~one task + * pen is up and quickly restore it to ~one task * switch when pen is down again. */ if (wm->ts_reader_interval < HZ / 10) @@ -876,7 +876,7 @@ static struct platform_driver wm97xx_mfd_driver = { .pm = pm_sleep_ptr(&wm97xx_pm_ops), }, .probe = wm97xx_mfd_probe, - .remove_new = wm97xx_mfd_remove, + .remove = wm97xx_mfd_remove, }; static int __init wm97xx_init(void) diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index 7e9b996b47c833..9d5404a07e8aa5 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -808,7 +808,7 @@ void icc_put(struct icc_path *path) mutex_unlock(&icc_bw_lock); mutex_unlock(&icc_lock); - kfree_const(path->name); + kfree(path->name); kfree(path); } EXPORT_SYMBOL_GPL(icc_put); @@ -1081,7 +1081,7 @@ static int of_count_icc_providers(struct device_node *np) int count = 0; for_each_available_child_of_node(np, child) { - if (of_property_read_bool(child, "#interconnect-cells") && + if (of_property_present(child, "#interconnect-cells") && likely(!of_match_node(ignore_list, child))) count++; count += of_count_icc_providers(child); diff --git a/drivers/interconnect/imx/imx8mm.c b/drivers/interconnect/imx/imx8mm.c index a36aaaf106aeed..efed12d635c1d8 100644 --- a/drivers/interconnect/imx/imx8mm.c +++ b/drivers/interconnect/imx/imx8mm.c @@ -88,7 +88,7 @@ static int imx8mm_icc_probe(struct platform_device *pdev) static struct platform_driver imx8mm_icc_driver = { .probe = imx8mm_icc_probe, - .remove_new = imx_icc_unregister, + .remove = imx_icc_unregister, .driver = { .name = "imx8mm-interconnect", }, diff --git a/drivers/interconnect/imx/imx8mn.c b/drivers/interconnect/imx/imx8mn.c index 2a97c74e875b96..535fae791f2e90 100644 --- a/drivers/interconnect/imx/imx8mn.c +++ b/drivers/interconnect/imx/imx8mn.c @@ -77,7 +77,7 @@ static int imx8mn_icc_probe(struct platform_device *pdev) static struct platform_driver imx8mn_icc_driver = { .probe = imx8mn_icc_probe, - .remove_new = imx_icc_unregister, + .remove = imx_icc_unregister, .driver = { .name = "imx8mn-interconnect", }, diff --git a/drivers/interconnect/imx/imx8mp.c b/drivers/interconnect/imx/imx8mp.c index 86d4c1517b263f..c5751ed18d5193 100644 --- a/drivers/interconnect/imx/imx8mp.c +++ b/drivers/interconnect/imx/imx8mp.c @@ -241,7 +241,7 @@ static int imx8mp_icc_probe(struct platform_device *pdev) static struct platform_driver imx8mp_icc_driver = { .probe = imx8mp_icc_probe, - .remove_new = imx_icc_unregister, + .remove = imx_icc_unregister, .driver = { .name = "imx8mp-interconnect", }, diff --git a/drivers/interconnect/imx/imx8mq.c b/drivers/interconnect/imx/imx8mq.c index f817d24aeefb67..6aa4f06b467645 100644 --- a/drivers/interconnect/imx/imx8mq.c +++ b/drivers/interconnect/imx/imx8mq.c @@ -87,7 +87,7 @@ static int imx8mq_icc_probe(struct platform_device *pdev) static struct platform_driver imx8mq_icc_driver = { .probe = imx8mq_icc_probe, - .remove_new = imx_icc_unregister, + .remove = imx_icc_unregister, .driver = { .name = "imx8mq-interconnect", .sync_state = icc_sync_state, diff --git a/drivers/interconnect/mediatek/mt8183.c b/drivers/interconnect/mediatek/mt8183.c index 24245085c7a944..c212e79334cf5b 100644 --- a/drivers/interconnect/mediatek/mt8183.c +++ b/drivers/interconnect/mediatek/mt8183.c @@ -133,7 +133,7 @@ static struct platform_driver mtk_emi_icc_mt8183_driver = { .sync_state = icc_sync_state, }, .probe = mtk_emi_icc_probe, - .remove_new = mtk_emi_icc_remove, + .remove = mtk_emi_icc_remove, }; module_platform_driver(mtk_emi_icc_mt8183_driver); diff --git a/drivers/interconnect/mediatek/mt8195.c b/drivers/interconnect/mediatek/mt8195.c index 710e14c5447ccf..3ca23469ab18d1 100644 --- a/drivers/interconnect/mediatek/mt8195.c +++ b/drivers/interconnect/mediatek/mt8195.c @@ -329,7 +329,7 @@ static struct platform_driver mtk_emi_icc_mt8195_driver = { .sync_state = icc_sync_state, }, .probe = mtk_emi_icc_probe, - .remove_new = mtk_emi_icc_remove, + .remove = mtk_emi_icc_remove, }; module_platform_driver(mtk_emi_icc_mt8195_driver); diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index de96d466134066..362fb9b0a198a9 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -105,6 +105,26 @@ config INTERCONNECT_QCOM_QCS404 This is a driver for the Qualcomm Network-on-Chip on qcs404-based platforms. +config INTERCONNECT_QCOM_QCS615 + tristate "Qualcomm QCS615 interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on qcs615-based + platforms. + +config INTERCONNECT_QCOM_QCS8300 + tristate "Qualcomm QCS8300 interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip + on QCS8300-based platforms. The interconnect provider collects and + aggreagates the cosumer bandwidth requests to satisfy constraints + placed on Network-on-Chip performance states. + config INTERCONNECT_QCOM_QDU1000 tristate "Qualcomm QDU1000/QRU1000 interconnect driver" depends on INTERCONNECT_QCOM_RPMH_POSSIBLE @@ -137,6 +157,15 @@ config INTERCONNECT_QCOM_SA8775P This is a driver for the Qualcomm Network-on-Chip on sa8775p-based platforms. +config INTERCONNECT_QCOM_SAR2130P + tristate "Qualcomm SAR2130P interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on SAR2130P-based + platforms. + config INTERCONNECT_QCOM_SC7180 tristate "Qualcomm SC7180 interconnect driver" depends on INTERCONNECT_QCOM_RPMH_POSSIBLE diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index bfeea8416fcf9e..9997728c02bf19 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -15,9 +15,12 @@ qnoc-msm8996-objs := msm8996.o icc-osm-l3-objs := osm-l3.o qnoc-qcm2290-objs := qcm2290.o qnoc-qcs404-objs := qcs404.o +qnoc-qcs615-objs := qcs615.o +qnoc-qcs8300-objs := qcs8300.o qnoc-qdu1000-objs := qdu1000.o icc-rpmh-obj := icc-rpmh.o qnoc-sa8775p-objs := sa8775p.o +qnoc-sar2130p-objs := sar2130p.o qnoc-sc7180-objs := sc7180.o qnoc-sc7280-objs := sc7280.o qnoc-sc8180x-objs := sc8180x.o @@ -52,9 +55,12 @@ obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += qnoc-msm8996.o obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o obj-$(CONFIG_INTERCONNECT_QCOM_QCM2290) += qnoc-qcm2290.o obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o +obj-$(CONFIG_INTERCONNECT_QCOM_QCS615) += qnoc-qcs615.o +obj-$(CONFIG_INTERCONNECT_QCOM_QCS8300) += qnoc-qcs8300.o obj-$(CONFIG_INTERCONNECT_QCOM_QDU1000) += qnoc-qdu1000.o obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o obj-$(CONFIG_INTERCONNECT_QCOM_SA8775P) += qnoc-sa8775p.o +obj-$(CONFIG_INTERCONNECT_QCOM_SAR2130P) += qnoc-sar2130p.o obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o obj-$(CONFIG_INTERCONNECT_QCOM_SC8180X) += qnoc-sc8180x.o diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index f49a8e0cb03c06..f2d63745be54c4 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -311,7 +311,10 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev) } qp->num_clks = devm_clk_bulk_get_all(qp->dev, &qp->clks); - if (qp->num_clks < 0 || (!qp->num_clks && desc->qos_clks_required)) { + if (qp->num_clks == -EPROBE_DEFER) + return dev_err_probe(dev, qp->num_clks, "Failed to get QoS clocks\n"); + + if (qp->num_clks < 0 || (!qp->num_clks && desc->qos_requires_clocks)) { dev_info(dev, "Skipping QoS, failed to get clk: %d\n", qp->num_clks); goto skip_qos_config; } diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index 14db89850fb3d9..82344c734091ea 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -153,7 +153,7 @@ struct qcom_icc_desc { size_t num_nodes; struct qcom_icc_bcm * const *bcms; size_t num_bcms; - bool qos_clks_required; + bool qos_requires_clocks; }; int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, diff --git a/drivers/interconnect/qcom/msm8909.c b/drivers/interconnect/qcom/msm8909.c index 0d0cd7282f5b70..dd656ce7b64d1a 100644 --- a/drivers/interconnect/qcom/msm8909.c +++ b/drivers/interconnect/qcom/msm8909.c @@ -1316,7 +1316,7 @@ MODULE_DEVICE_TABLE(of, msm8909_noc_of_match); static struct platform_driver msm8909_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-msm8909", .of_match_table = msm8909_noc_of_match, diff --git a/drivers/interconnect/qcom/msm8916.c b/drivers/interconnect/qcom/msm8916.c index 499b1a9ac413bf..35148880b3e87d 100644 --- a/drivers/interconnect/qcom/msm8916.c +++ b/drivers/interconnect/qcom/msm8916.c @@ -1344,7 +1344,7 @@ MODULE_DEVICE_TABLE(of, msm8916_noc_of_match); static struct platform_driver msm8916_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-msm8916", .of_match_table = msm8916_noc_of_match, diff --git a/drivers/interconnect/qcom/msm8937.c b/drivers/interconnect/qcom/msm8937.c index 052b14c28ef8bc..58533d00266b4a 100644 --- a/drivers/interconnect/qcom/msm8937.c +++ b/drivers/interconnect/qcom/msm8937.c @@ -1175,7 +1175,7 @@ static struct qcom_icc_node slv_lpass = { .qos.qos_mode = NOC_QOS_MODE_INVALID, }; -static struct qcom_icc_node *msm8937_bimc_nodes[] = { +static struct qcom_icc_node * const msm8937_bimc_nodes[] = { [MAS_APPS_PROC] = &mas_apps_proc, [MAS_OXILI] = &mas_oxili, [MAS_SNOC_BIMC_0] = &mas_snoc_bimc_0, @@ -1204,7 +1204,7 @@ static const struct qcom_icc_desc msm8937_bimc = { .ab_coeff = 154, }; -static struct qcom_icc_node *msm8937_pcnoc_nodes[] = { +static struct qcom_icc_node * const msm8937_pcnoc_nodes[] = { [MAS_SPDM] = &mas_spdm, [MAS_BLSP_1] = &mas_blsp_1, [MAS_BLSP_2] = &mas_blsp_2, @@ -1268,7 +1268,7 @@ static const struct qcom_icc_desc msm8937_pcnoc = { .regmap_cfg = &msm8937_pcnoc_regmap_config, }; -static struct qcom_icc_node *msm8937_snoc_nodes[] = { +static struct qcom_icc_node * const msm8937_snoc_nodes[] = { [MAS_QDSS_BAM] = &mas_qdss_bam, [MAS_BIMC_SNOC] = &mas_bimc_snoc, [MAS_PCNOC_SNOC] = &mas_pcnoc_snoc, @@ -1304,7 +1304,7 @@ static const struct qcom_icc_desc msm8937_snoc = { .qos_offset = 0x7000, }; -static struct qcom_icc_node *msm8937_snoc_mm_nodes[] = { +static struct qcom_icc_node * const msm8937_snoc_mm_nodes[] = { [MAS_JPEG] = &mas_jpeg, [MAS_MDP] = &mas_mdp, [MAS_VENUS] = &mas_venus, @@ -1337,7 +1337,7 @@ MODULE_DEVICE_TABLE(of, msm8937_noc_of_match); static struct platform_driver msm8937_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-msm8937", .of_match_table = msm8937_noc_of_match, diff --git a/drivers/interconnect/qcom/msm8939.c b/drivers/interconnect/qcom/msm8939.c index 8ff2c23b1ca0dd..b52c5ac1175c3f 100644 --- a/drivers/interconnect/qcom/msm8939.c +++ b/drivers/interconnect/qcom/msm8939.c @@ -1421,7 +1421,7 @@ MODULE_DEVICE_TABLE(of, msm8939_noc_of_match); static struct platform_driver msm8939_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-msm8939", .of_match_table = msm8939_noc_of_match, diff --git a/drivers/interconnect/qcom/msm8953.c b/drivers/interconnect/qcom/msm8953.c index 62f8c0774b3ecc..be2b1a606612cc 100644 --- a/drivers/interconnect/qcom/msm8953.c +++ b/drivers/interconnect/qcom/msm8953.c @@ -1310,7 +1310,7 @@ static const struct of_device_id msm8953_noc_of_match[] = { static struct platform_driver msm8953_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-msm8953", .of_match_table = msm8953_noc_of_match, diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c index 241076b5f36b46..469fc48ebfe94d 100644 --- a/drivers/interconnect/qcom/msm8974.c +++ b/drivers/interconnect/qcom/msm8974.c @@ -762,7 +762,7 @@ MODULE_DEVICE_TABLE(of, msm8974_noc_of_match); static struct platform_driver msm8974_noc_driver = { .probe = msm8974_icc_probe, - .remove_new = msm8974_icc_remove, + .remove = msm8974_icc_remove, .driver = { .name = "qnoc-msm8974", .of_match_table = msm8974_noc_of_match, diff --git a/drivers/interconnect/qcom/msm8976.c b/drivers/interconnect/qcom/msm8976.c index ab963def77c3ae..4e2ac7ebe7429f 100644 --- a/drivers/interconnect/qcom/msm8976.c +++ b/drivers/interconnect/qcom/msm8976.c @@ -1427,7 +1427,7 @@ MODULE_DEVICE_TABLE(of, msm8976_noc_of_match); static struct platform_driver msm8976_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-msm8976", .of_match_table = msm8976_noc_of_match, diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c index 788131400cd132..b73566c9b21f9d 100644 --- a/drivers/interconnect/qcom/msm8996.c +++ b/drivers/interconnect/qcom/msm8996.c @@ -2108,7 +2108,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-msm8996", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c index 61a8695a9adc73..6a656ed44d49ba 100644 --- a/drivers/interconnect/qcom/osm-l3.c +++ b/drivers/interconnect/qcom/osm-l3.c @@ -290,7 +290,7 @@ MODULE_DEVICE_TABLE(of, osm_l3_of_match); static struct platform_driver osm_l3_driver = { .probe = qcom_osm_l3_probe, - .remove_new = qcom_osm_l3_remove, + .remove = qcom_osm_l3_remove, .driver = { .name = "osm-l3", .of_match_table = osm_l3_of_match, diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c index ccbdc6202c07a6..e120bc1395f35c 100644 --- a/drivers/interconnect/qcom/qcm2290.c +++ b/drivers/interconnect/qcom/qcm2290.c @@ -1367,7 +1367,7 @@ MODULE_DEVICE_TABLE(of, qcm2290_noc_of_match); static struct platform_driver qcm2290_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-qcm2290", .of_match_table = qcm2290_noc_of_match, diff --git a/drivers/interconnect/qcom/qcs404.c b/drivers/interconnect/qcom/qcs404.c index 63e9ff223ac491..ceac7a69876951 100644 --- a/drivers/interconnect/qcom/qcs404.c +++ b/drivers/interconnect/qcom/qcs404.c @@ -1204,7 +1204,7 @@ MODULE_DEVICE_TABLE(of, qcs404_noc_of_match); static struct platform_driver qcs404_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-qcs404", .of_match_table = qcs404_noc_of_match, diff --git a/drivers/interconnect/qcom/qcs615.c b/drivers/interconnect/qcom/qcs615.c new file mode 100644 index 00000000000000..7e59e91ce886d6 --- /dev/null +++ b/drivers/interconnect/qcom/qcs615.c @@ -0,0 +1,1563 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "bcm-voter.h" +#include "icc-rpmh.h" +#include "qcs615.h" + +static struct qcom_icc_node qhm_a1noc_cfg = { + .name = "qhm_a1noc_cfg", + .id = QCS615_MASTER_A1NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_SERVICE_A2NOC }, +}; + +static struct qcom_icc_node qhm_qdss_bam = { + .name = "qhm_qdss_bam", + .id = QCS615_MASTER_QDSS_BAM, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qspi = { + .name = "qhm_qspi", + .id = QCS615_MASTER_QSPI, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qup0 = { + .name = "qhm_qup0", + .id = QCS615_MASTER_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qup1 = { + .name = "qhm_qup1", + .id = QCS615_MASTER_BLSP_1, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qnm_cnoc = { + .name = "qnm_cnoc", + .id = QCS615_MASTER_CNOC_A2NOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_crypto = { + .name = "qxm_crypto", + .id = QCS615_MASTER_CRYPTO, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_ipa = { + .name = "qxm_ipa", + .id = QCS615_MASTER_IPA, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_LPASS_SNOC }, +}; + +static struct qcom_icc_node xm_emac_avb = { + .name = "xm_emac_avb", + .id = QCS615_MASTER_EMAC_EVB, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_pcie = { + .name = "xm_pcie", + .id = QCS615_MASTER_PCIE, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_ANOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node xm_qdss_etr = { + .name = "xm_qdss_etr", + .id = QCS615_MASTER_QDSS_ETR, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_sdc1 = { + .name = "xm_sdc1", + .id = QCS615_MASTER_SDCC_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_sdc2 = { + .name = "xm_sdc2", + .id = QCS615_MASTER_SDCC_2, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_ufs_mem = { + .name = "xm_ufs_mem", + .id = QCS615_MASTER_UFS_MEM, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_usb2 = { + .name = "xm_usb2", + .id = QCS615_MASTER_USB2, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_usb3_0 = { + .name = "xm_usb3_0", + .id = QCS615_MASTER_USB3_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_camnoc_hf0_uncomp = { + .name = "qxm_camnoc_hf0_uncomp", + .id = QCS615_MASTER_CAMNOC_HF0_UNCOMP, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_CAMNOC_UNCOMP }, +}; + +static struct qcom_icc_node qxm_camnoc_hf1_uncomp = { + .name = "qxm_camnoc_hf1_uncomp", + .id = QCS615_MASTER_CAMNOC_HF1_UNCOMP, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_CAMNOC_UNCOMP }, +}; + +static struct qcom_icc_node qxm_camnoc_sf_uncomp = { + .name = "qxm_camnoc_sf_uncomp", + .id = QCS615_MASTER_CAMNOC_SF_UNCOMP, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_CAMNOC_UNCOMP }, +}; + +static struct qcom_icc_node qhm_spdm = { + .name = "qhm_spdm", + .id = QCS615_MASTER_SPDM, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_CNOC_A2NOC }, +}; + +static struct qcom_icc_node qnm_snoc = { + .name = "qnm_snoc", + .id = QCS615_MASTER_SNOC_CNOC, + .channels = 1, + .buswidth = 8, + .num_links = 39, + .links = { QCS615_SLAVE_A1NOC_CFG, QCS615_SLAVE_AHB2PHY_EAST, + QCS615_SLAVE_AHB2PHY_WEST, QCS615_SLAVE_AOP, + QCS615_SLAVE_AOSS, QCS615_SLAVE_CAMERA_CFG, + QCS615_SLAVE_CLK_CTL, QCS615_SLAVE_RBCPR_CX_CFG, + QCS615_SLAVE_RBCPR_MX_CFG, QCS615_SLAVE_CRYPTO_0_CFG, + QCS615_SLAVE_CNOC_DDRSS, QCS615_SLAVE_DISPLAY_CFG, + QCS615_SLAVE_EMAC_AVB_CFG, QCS615_SLAVE_GLM, + QCS615_SLAVE_GFX3D_CFG, QCS615_SLAVE_IMEM_CFG, + QCS615_SLAVE_IPA_CFG, QCS615_SLAVE_CNOC_MNOC_CFG, + QCS615_SLAVE_PCIE_CFG, QCS615_SLAVE_PIMEM_CFG, + QCS615_SLAVE_PRNG, QCS615_SLAVE_QDSS_CFG, + QCS615_SLAVE_QSPI, QCS615_SLAVE_QUP_0, + QCS615_SLAVE_QUP_1, QCS615_SLAVE_SDCC_1, + QCS615_SLAVE_SDCC_2, QCS615_SLAVE_SNOC_CFG, + QCS615_SLAVE_SPDM_WRAPPER, QCS615_SLAVE_TCSR, + QCS615_SLAVE_TLMM_EAST, QCS615_SLAVE_TLMM_SOUTH, + QCS615_SLAVE_TLMM_WEST, QCS615_SLAVE_UFS_MEM_CFG, + QCS615_SLAVE_USB2, QCS615_SLAVE_USB3, + QCS615_SLAVE_VENUS_CFG, QCS615_SLAVE_VSENSE_CTRL_CFG, + QCS615_SLAVE_SERVICE_CNOC }, +}; + +static struct qcom_icc_node xm_qdss_dap = { + .name = "xm_qdss_dap", + .id = QCS615_MASTER_QDSS_DAP, + .channels = 1, + .buswidth = 8, + .num_links = 40, + .links = { QCS615_SLAVE_A1NOC_CFG, QCS615_SLAVE_AHB2PHY_EAST, + QCS615_SLAVE_AHB2PHY_WEST, QCS615_SLAVE_AOP, + QCS615_SLAVE_AOSS, QCS615_SLAVE_CAMERA_CFG, + QCS615_SLAVE_CLK_CTL, QCS615_SLAVE_RBCPR_CX_CFG, + QCS615_SLAVE_RBCPR_MX_CFG, QCS615_SLAVE_CRYPTO_0_CFG, + QCS615_SLAVE_CNOC_DDRSS, QCS615_SLAVE_DISPLAY_CFG, + QCS615_SLAVE_EMAC_AVB_CFG, QCS615_SLAVE_GLM, + QCS615_SLAVE_GFX3D_CFG, QCS615_SLAVE_IMEM_CFG, + QCS615_SLAVE_IPA_CFG, QCS615_SLAVE_CNOC_MNOC_CFG, + QCS615_SLAVE_PCIE_CFG, QCS615_SLAVE_PIMEM_CFG, + QCS615_SLAVE_PRNG, QCS615_SLAVE_QDSS_CFG, + QCS615_SLAVE_QSPI, QCS615_SLAVE_QUP_0, + QCS615_SLAVE_QUP_1, QCS615_SLAVE_SDCC_1, + QCS615_SLAVE_SDCC_2, QCS615_SLAVE_SNOC_CFG, + QCS615_SLAVE_SPDM_WRAPPER, QCS615_SLAVE_TCSR, + QCS615_SLAVE_TLMM_EAST, QCS615_SLAVE_TLMM_SOUTH, + QCS615_SLAVE_TLMM_WEST, QCS615_SLAVE_UFS_MEM_CFG, + QCS615_SLAVE_USB2, QCS615_SLAVE_USB3, + QCS615_SLAVE_VENUS_CFG, QCS615_SLAVE_VSENSE_CTRL_CFG, + QCS615_SLAVE_CNOC_A2NOC, QCS615_SLAVE_SERVICE_CNOC }, +}; + +static struct qcom_icc_node qhm_cnoc = { + .name = "qhm_cnoc", + .id = QCS615_MASTER_CNOC_DC_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 2, + .links = { QCS615_SLAVE_DC_NOC_GEMNOC, QCS615_SLAVE_LLCC_CFG }, +}; + +static struct qcom_icc_node acm_apps = { + .name = "acm_apps", + .id = QCS615_MASTER_APPSS_PROC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { QCS615_SLAVE_GEM_NOC_SNOC, QCS615_SLAVE_LLCC, + QCS615_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node acm_gpu_tcu = { + .name = "acm_gpu_tcu", + .id = QCS615_MASTER_GPU_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QCS615_SLAVE_GEM_NOC_SNOC, QCS615_SLAVE_LLCC }, +}; + +static struct qcom_icc_node acm_sys_tcu = { + .name = "acm_sys_tcu", + .id = QCS615_MASTER_SYS_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QCS615_SLAVE_GEM_NOC_SNOC, QCS615_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qhm_gemnoc_cfg = { + .name = "qhm_gemnoc_cfg", + .id = QCS615_MASTER_GEM_NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 2, + .links = { QCS615_SLAVE_MSS_PROC_MS_MPU_CFG, QCS615_SLAVE_SERVICE_GEM_NOC }, +}; + +static struct qcom_icc_node qnm_gpu = { + .name = "qnm_gpu", + .id = QCS615_MASTER_GFX3D, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { QCS615_SLAVE_GEM_NOC_SNOC, QCS615_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_mnoc_hf = { + .name = "qnm_mnoc_hf", + .id = QCS615_MASTER_MNOC_HF_MEM_NOC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_mnoc_sf = { + .name = "qnm_mnoc_sf", + .id = QCS615_MASTER_MNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 32, + .num_links = 2, + .links = { QCS615_SLAVE_GEM_NOC_SNOC, QCS615_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_snoc_gc = { + .name = "qnm_snoc_gc", + .id = QCS615_MASTER_SNOC_GC_MEM_NOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_snoc_sf = { + .name = "qnm_snoc_sf", + .id = QCS615_MASTER_SNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS615_SLAVE_LLCC }, +}; + +static struct qcom_icc_node ipa_core_master = { + .name = "ipa_core_master", + .id = QCS615_MASTER_IPA_CORE, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_IPA_CORE }, +}; + +static struct qcom_icc_node llcc_mc = { + .name = "llcc_mc", + .id = QCS615_MASTER_LLCC, + .channels = 2, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_EBI1 }, +}; + +static struct qcom_icc_node qhm_mnoc_cfg = { + .name = "qhm_mnoc_cfg", + .id = QCS615_MASTER_CNOC_MNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_SERVICE_MNOC }, +}; + +static struct qcom_icc_node qxm_camnoc_hf0 = { + .name = "qxm_camnoc_hf0", + .id = QCS615_MASTER_CAMNOC_HF0, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qxm_camnoc_hf1 = { + .name = "qxm_camnoc_hf1", + .id = QCS615_MASTER_CAMNOC_HF1, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qxm_camnoc_sf = { + .name = "qxm_camnoc_sf", + .id = QCS615_MASTER_CAMNOC_SF, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qxm_mdp0 = { + .name = "qxm_mdp0", + .id = QCS615_MASTER_MDP0, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qxm_rot = { + .name = "qxm_rot", + .id = QCS615_MASTER_ROTATOR, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qxm_venus0 = { + .name = "qxm_venus0", + .id = QCS615_MASTER_VIDEO_P0, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qxm_venus_arm9 = { + .name = "qxm_venus_arm9", + .id = QCS615_MASTER_VIDEO_PROC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qhm_snoc_cfg = { + .name = "qhm_snoc_cfg", + .id = QCS615_MASTER_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_SLAVE_SERVICE_SNOC }, +}; + +static struct qcom_icc_node qnm_aggre1_noc = { + .name = "qnm_aggre1_noc", + .id = QCS615_MASTER_A1NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 8, + .links = { QCS615_SLAVE_APPSS, QCS615_SLAVE_SNOC_CNOC, + QCS615_SLAVE_SNOC_GEM_NOC_SF, QCS615_SLAVE_IMEM, + QCS615_SLAVE_PIMEM, QCS615_SLAVE_PCIE_0, + QCS615_SLAVE_QDSS_STM, QCS615_SLAVE_TCU }, +}; + +static struct qcom_icc_node qnm_gemnoc = { + .name = "qnm_gemnoc", + .id = QCS615_MASTER_GEM_NOC_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 6, + .links = { QCS615_SLAVE_APPSS, QCS615_SLAVE_SNOC_CNOC, + QCS615_SLAVE_IMEM, QCS615_SLAVE_PIMEM, + QCS615_SLAVE_QDSS_STM, QCS615_SLAVE_TCU }, +}; + +static struct qcom_icc_node qnm_gemnoc_pcie = { + .name = "qnm_gemnoc_pcie", + .id = QCS615_MASTER_GEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_SLAVE_PCIE_0 }, +}; + +static struct qcom_icc_node qnm_lpass_anoc = { + .name = "qnm_lpass_anoc", + .id = QCS615_MASTER_LPASS_ANOC, + .channels = 1, + .buswidth = 8, + .num_links = 7, + .links = { QCS615_SLAVE_APPSS, QCS615_SLAVE_SNOC_CNOC, + QCS615_SLAVE_SNOC_GEM_NOC_SF, QCS615_SLAVE_IMEM, + QCS615_SLAVE_PIMEM, QCS615_SLAVE_PCIE_0, + QCS615_SLAVE_QDSS_STM }, +}; + +static struct qcom_icc_node qnm_pcie_anoc = { + .name = "qnm_pcie_anoc", + .id = QCS615_MASTER_ANOC_PCIE_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 5, + .links = { QCS615_SLAVE_APPSS, QCS615_SLAVE_SNOC_CNOC, + QCS615_SLAVE_SNOC_GEM_NOC_SF, QCS615_SLAVE_IMEM, + QCS615_SLAVE_QDSS_STM }, +}; + +static struct qcom_icc_node qxm_pimem = { + .name = "qxm_pimem", + .id = QCS615_MASTER_PIMEM, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QCS615_SLAVE_SNOC_MEM_NOC_GC, QCS615_SLAVE_IMEM }, +}; + +static struct qcom_icc_node xm_gic = { + .name = "xm_gic", + .id = QCS615_MASTER_GIC, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QCS615_SLAVE_SNOC_MEM_NOC_GC, QCS615_SLAVE_IMEM }, +}; + +static struct qcom_icc_node qns_a1noc_snoc = { + .name = "qns_a1noc_snoc", + .id = QCS615_SLAVE_A1NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS615_MASTER_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qns_lpass_snoc = { + .name = "qns_lpass_snoc", + .id = QCS615_SLAVE_LPASS_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_MASTER_LPASS_ANOC }, +}; + +static struct qcom_icc_node qns_pcie_snoc = { + .name = "qns_pcie_snoc", + .id = QCS615_SLAVE_ANOC_PCIE_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_MASTER_ANOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node srvc_aggre2_noc = { + .name = "srvc_aggre2_noc", + .id = QCS615_SLAVE_SERVICE_A2NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_camnoc_uncomp = { + .name = "qns_camnoc_uncomp", + .id = QCS615_SLAVE_CAMNOC_UNCOMP, + .channels = 1, + .buswidth = 32, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_a1_noc_cfg = { + .name = "qhs_a1_noc_cfg", + .id = QCS615_SLAVE_A1NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_MASTER_A1NOC_CFG }, +}; + +static struct qcom_icc_node qhs_ahb2phy_east = { + .name = "qhs_ahb2phy_east", + .id = QCS615_SLAVE_AHB2PHY_EAST, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy_west = { + .name = "qhs_ahb2phy_west", + .id = QCS615_SLAVE_AHB2PHY_WEST, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_aop = { + .name = "qhs_aop", + .id = QCS615_SLAVE_AOP, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_aoss = { + .name = "qhs_aoss", + .id = QCS615_SLAVE_AOSS, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_camera_cfg = { + .name = "qhs_camera_cfg", + .id = QCS615_SLAVE_CAMERA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_clk_ctl = { + .name = "qhs_clk_ctl", + .id = QCS615_SLAVE_CLK_CTL, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_cx = { + .name = "qhs_cpr_cx", + .id = QCS615_SLAVE_RBCPR_CX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mx = { + .name = "qhs_cpr_mx", + .id = QCS615_SLAVE_RBCPR_MX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_crypto0_cfg = { + .name = "qhs_crypto0_cfg", + .id = QCS615_SLAVE_CRYPTO_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ddrss_cfg = { + .name = "qhs_ddrss_cfg", + .id = QCS615_SLAVE_CNOC_DDRSS, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_MASTER_CNOC_DC_NOC }, +}; + +static struct qcom_icc_node qhs_display_cfg = { + .name = "qhs_display_cfg", + .id = QCS615_SLAVE_DISPLAY_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_emac_avb_cfg = { + .name = "qhs_emac_avb_cfg", + .id = QCS615_SLAVE_EMAC_AVB_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_glm = { + .name = "qhs_glm", + .id = QCS615_SLAVE_GLM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_gpuss_cfg = { + .name = "qhs_gpuss_cfg", + .id = QCS615_SLAVE_GFX3D_CFG, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_imem_cfg = { + .name = "qhs_imem_cfg", + .id = QCS615_SLAVE_IMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipa = { + .name = "qhs_ipa", + .id = QCS615_SLAVE_IPA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mnoc_cfg = { + .name = "qhs_mnoc_cfg", + .id = QCS615_SLAVE_CNOC_MNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_MASTER_CNOC_MNOC_CFG }, +}; + +static struct qcom_icc_node qhs_pcie_config = { + .name = "qhs_pcie_config", + .id = QCS615_SLAVE_PCIE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pimem_cfg = { + .name = "qhs_pimem_cfg", + .id = QCS615_SLAVE_PIMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_prng = { + .name = "qhs_prng", + .id = QCS615_SLAVE_PRNG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qdss_cfg = { + .name = "qhs_qdss_cfg", + .id = QCS615_SLAVE_QDSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qspi = { + .name = "qhs_qspi", + .id = QCS615_SLAVE_QSPI, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup0 = { + .name = "qhs_qup0", + .id = QCS615_SLAVE_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup1 = { + .name = "qhs_qup1", + .id = QCS615_SLAVE_QUP_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc1 = { + .name = "qhs_sdc1", + .id = QCS615_SLAVE_SDCC_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc2 = { + .name = "qhs_sdc2", + .id = QCS615_SLAVE_SDCC_2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_snoc_cfg = { + .name = "qhs_snoc_cfg", + .id = QCS615_SLAVE_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_MASTER_SNOC_CFG }, +}; + +static struct qcom_icc_node qhs_spdm = { + .name = "qhs_spdm", + .id = QCS615_SLAVE_SPDM_WRAPPER, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tcsr = { + .name = "qhs_tcsr", + .id = QCS615_SLAVE_TCSR, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tlmm_east = { + .name = "qhs_tlmm_east", + .id = QCS615_SLAVE_TLMM_EAST, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tlmm_south = { + .name = "qhs_tlmm_south", + .id = QCS615_SLAVE_TLMM_SOUTH, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tlmm_west = { + .name = "qhs_tlmm_west", + .id = QCS615_SLAVE_TLMM_WEST, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ufs_mem_cfg = { + .name = "qhs_ufs_mem_cfg", + .id = QCS615_SLAVE_UFS_MEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb2 = { + .name = "qhs_usb2", + .id = QCS615_SLAVE_USB2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb3 = { + .name = "qhs_usb3", + .id = QCS615_SLAVE_USB3, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_venus_cfg = { + .name = "qhs_venus_cfg", + .id = QCS615_SLAVE_VENUS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_vsense_ctrl_cfg = { + .name = "qhs_vsense_ctrl_cfg", + .id = QCS615_SLAVE_VSENSE_CTRL_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_cnoc_a2noc = { + .name = "qns_cnoc_a2noc", + .id = QCS615_SLAVE_CNOC_A2NOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_MASTER_CNOC_A2NOC }, +}; + +static struct qcom_icc_node srvc_cnoc = { + .name = "srvc_cnoc", + .id = QCS615_SLAVE_SERVICE_CNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_dc_noc_gemnoc = { + .name = "qhs_dc_noc_gemnoc", + .id = QCS615_SLAVE_DC_NOC_GEMNOC, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS615_MASTER_GEM_NOC_CFG }, +}; + +static struct qcom_icc_node qhs_llcc = { + .name = "qhs_llcc", + .id = QCS615_SLAVE_LLCC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mdsp_ms_mpu_cfg = { + .name = "qhs_mdsp_ms_mpu_cfg", + .id = QCS615_SLAVE_MSS_PROC_MS_MPU_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gem_noc_snoc = { + .name = "qns_gem_noc_snoc", + .id = QCS615_SLAVE_GEM_NOC_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_MASTER_GEM_NOC_SNOC }, +}; + +static struct qcom_icc_node qns_llcc = { + .name = "qns_llcc", + .id = QCS615_SLAVE_LLCC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS615_MASTER_LLCC }, +}; + +static struct qcom_icc_node qns_sys_pcie = { + .name = "qns_sys_pcie", + .id = QCS615_SLAVE_MEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_MASTER_GEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node srvc_gemnoc = { + .name = "srvc_gemnoc", + .id = QCS615_SLAVE_SERVICE_GEM_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node ipa_core_slave = { + .name = "ipa_core_slave", + .id = QCS615_SLAVE_IPA_CORE, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node ebi = { + .name = "ebi", + .id = QCS615_SLAVE_EBI1, + .channels = 2, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns2_mem_noc = { + .name = "qns2_mem_noc", + .id = QCS615_SLAVE_MNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_MASTER_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qns_mem_noc_hf = { + .name = "qns_mem_noc_hf", + .id = QCS615_SLAVE_MNOC_HF_MEM_NOC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS615_MASTER_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node srvc_mnoc = { + .name = "srvc_mnoc", + .id = QCS615_SLAVE_SERVICE_MNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_apss = { + .name = "qhs_apss", + .id = QCS615_SLAVE_APPSS, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qns_cnoc = { + .name = "qns_cnoc", + .id = QCS615_SLAVE_SNOC_CNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_MASTER_SNOC_CNOC }, +}; + +static struct qcom_icc_node qns_gemnoc_sf = { + .name = "qns_gemnoc_sf", + .id = QCS615_SLAVE_SNOC_GEM_NOC_SF, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS615_MASTER_SNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qns_memnoc_gc = { + .name = "qns_memnoc_gc", + .id = QCS615_SLAVE_SNOC_MEM_NOC_GC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS615_MASTER_SNOC_GC_MEM_NOC }, +}; + +static struct qcom_icc_node qxs_imem = { + .name = "qxs_imem", + .id = QCS615_SLAVE_IMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qxs_pimem = { + .name = "qxs_pimem", + .id = QCS615_SLAVE_PIMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_snoc = { + .name = "srvc_snoc", + .id = QCS615_SLAVE_SERVICE_SNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie = { + .name = "xs_pcie", + .id = QCS615_SLAVE_PCIE_0, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_qdss_stm = { + .name = "xs_qdss_stm", + .id = QCS615_SLAVE_QDSS_STM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_sys_tcu_cfg = { + .name = "xs_sys_tcu_cfg", + .id = QCS615_SLAVE_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_bcm bcm_acv = { + .name = "ACV", + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_ce0 = { + .name = "CE0", + .num_nodes = 1, + .nodes = { &qxm_crypto }, +}; + +static struct qcom_icc_bcm bcm_cn0 = { + .name = "CN0", + .keepalive = true, + .num_nodes = 37, + .nodes = { &qhm_spdm, &qnm_snoc, + &qhs_a1_noc_cfg, &qhs_aop, + &qhs_aoss, &qhs_camera_cfg, + &qhs_clk_ctl, &qhs_cpr_cx, + &qhs_cpr_mx, &qhs_crypto0_cfg, + &qhs_ddrss_cfg, &qhs_display_cfg, + &qhs_emac_avb_cfg, &qhs_glm, + &qhs_gpuss_cfg, &qhs_imem_cfg, + &qhs_ipa, &qhs_mnoc_cfg, + &qhs_pcie_config, &qhs_pimem_cfg, + &qhs_prng, &qhs_qdss_cfg, + &qhs_qup0, &qhs_qup1, + &qhs_snoc_cfg, &qhs_spdm, + &qhs_tcsr, &qhs_tlmm_east, + &qhs_tlmm_south, &qhs_tlmm_west, + &qhs_ufs_mem_cfg, &qhs_usb2, + &qhs_usb3, &qhs_venus_cfg, + &qhs_vsense_ctrl_cfg, &qns_cnoc_a2noc, + &srvc_cnoc }, +}; + +static struct qcom_icc_bcm bcm_cn1 = { + .name = "CN1", + .num_nodes = 8, + .nodes = { &qhm_qspi, &xm_sdc1, + &xm_sdc2, &qhs_ahb2phy_east, + &qhs_ahb2phy_west, &qhs_qspi, + &qhs_sdc1, &qhs_sdc2 }, +}; + +static struct qcom_icc_bcm bcm_ip0 = { + .name = "IP0", + .num_nodes = 1, + .nodes = { &ipa_core_slave }, +}; + +static struct qcom_icc_bcm bcm_mc0 = { + .name = "MC0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_mm0 = { + .name = "MM0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_bcm bcm_mm1 = { + .name = "MM1", + .num_nodes = 7, + .nodes = { &qxm_camnoc_hf0_uncomp, &qxm_camnoc_hf1_uncomp, + &qxm_camnoc_sf_uncomp, &qxm_camnoc_hf0, + &qxm_camnoc_hf1, &qxm_mdp0, + &qxm_rot }, +}; + +static struct qcom_icc_bcm bcm_mm2 = { + .name = "MM2", + .num_nodes = 2, + .nodes = { &qxm_camnoc_sf, &qns2_mem_noc }, +}; + +static struct qcom_icc_bcm bcm_mm3 = { + .name = "MM3", + .num_nodes = 2, + .nodes = { &qxm_venus0, &qxm_venus_arm9 }, +}; + +static struct qcom_icc_bcm bcm_qup0 = { + .name = "QUP0", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 2, + .nodes = { &qhm_qup0, &qhm_qup1 }, +}; + +static struct qcom_icc_bcm bcm_sh0 = { + .name = "SH0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_llcc }, +}; + +static struct qcom_icc_bcm bcm_sh2 = { + .name = "SH2", + .num_nodes = 1, + .nodes = { &acm_apps }, +}; + +static struct qcom_icc_bcm bcm_sh3 = { + .name = "SH3", + .num_nodes = 1, + .nodes = { &qns_gem_noc_snoc }, +}; + +static struct qcom_icc_bcm bcm_sn0 = { + .name = "SN0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_bcm bcm_sn1 = { + .name = "SN1", + .num_nodes = 1, + .nodes = { &qxs_imem }, +}; + +static struct qcom_icc_bcm bcm_sn2 = { + .name = "SN2", + .num_nodes = 1, + .nodes = { &qns_memnoc_gc }, +}; + +static struct qcom_icc_bcm bcm_sn3 = { + .name = "SN3", + .num_nodes = 2, + .nodes = { &srvc_aggre2_noc, &qns_cnoc }, +}; + +static struct qcom_icc_bcm bcm_sn4 = { + .name = "SN4", + .num_nodes = 1, + .nodes = { &qxs_pimem }, +}; + +static struct qcom_icc_bcm bcm_sn5 = { + .name = "SN5", + .num_nodes = 1, + .nodes = { &xs_qdss_stm }, +}; + +static struct qcom_icc_bcm bcm_sn8 = { + .name = "SN8", + .num_nodes = 2, + .nodes = { &qnm_gemnoc_pcie, &xs_pcie }, +}; + +static struct qcom_icc_bcm bcm_sn9 = { + .name = "SN9", + .num_nodes = 1, + .nodes = { &qnm_aggre1_noc }, +}; + +static struct qcom_icc_bcm bcm_sn12 = { + .name = "SN12", + .num_nodes = 2, + .nodes = { &qxm_pimem, &xm_gic }, +}; + +static struct qcom_icc_bcm bcm_sn13 = { + .name = "SN13", + .num_nodes = 1, + .nodes = { &qnm_lpass_anoc }, +}; + +static struct qcom_icc_bcm bcm_sn14 = { + .name = "SN14", + .num_nodes = 1, + .nodes = { &qns_pcie_snoc }, +}; + +static struct qcom_icc_bcm bcm_sn15 = { + .name = "SN15", + .num_nodes = 1, + .nodes = { &qnm_gemnoc }, +}; + +static struct qcom_icc_bcm * const aggre1_noc_bcms[] = { + &bcm_ce0, + &bcm_cn1, + &bcm_qup0, + &bcm_sn3, + &bcm_sn14, + &bcm_ip0, +}; + +static struct qcom_icc_node * const aggre1_noc_nodes[] = { + [MASTER_A1NOC_CFG] = &qhm_a1noc_cfg, + [MASTER_QDSS_BAM] = &qhm_qdss_bam, + [MASTER_QSPI] = &qhm_qspi, + [MASTER_QUP_0] = &qhm_qup0, + [MASTER_BLSP_1] = &qhm_qup1, + [MASTER_CNOC_A2NOC] = &qnm_cnoc, + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_IPA] = &qxm_ipa, + [MASTER_EMAC_EVB] = &xm_emac_avb, + [MASTER_PCIE] = &xm_pcie, + [MASTER_QDSS_ETR] = &xm_qdss_etr, + [MASTER_SDCC_1] = &xm_sdc1, + [MASTER_SDCC_2] = &xm_sdc2, + [MASTER_UFS_MEM] = &xm_ufs_mem, + [MASTER_USB2] = &xm_usb2, + [MASTER_USB3_0] = &xm_usb3_0, + [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc, + [SLAVE_LPASS_SNOC] = &qns_lpass_snoc, + [SLAVE_ANOC_PCIE_SNOC] = &qns_pcie_snoc, + [SLAVE_SERVICE_A2NOC] = &srvc_aggre2_noc, +}; + +static const struct qcom_icc_desc qcs615_aggre1_noc = { + .nodes = aggre1_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), + .bcms = aggre1_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), +}; + +static struct qcom_icc_bcm * const camnoc_virt_bcms[] = { + &bcm_mm1, +}; + +static struct qcom_icc_node * const camnoc_virt_nodes[] = { + [MASTER_CAMNOC_HF0_UNCOMP] = &qxm_camnoc_hf0_uncomp, + [MASTER_CAMNOC_HF1_UNCOMP] = &qxm_camnoc_hf1_uncomp, + [MASTER_CAMNOC_SF_UNCOMP] = &qxm_camnoc_sf_uncomp, + [SLAVE_CAMNOC_UNCOMP] = &qns_camnoc_uncomp, +}; + +static const struct qcom_icc_desc qcs615_camnoc_virt = { + .nodes = camnoc_virt_nodes, + .num_nodes = ARRAY_SIZE(camnoc_virt_nodes), + .bcms = camnoc_virt_bcms, + .num_bcms = ARRAY_SIZE(camnoc_virt_bcms), +}; + +static struct qcom_icc_bcm * const config_noc_bcms[] = { + &bcm_cn0, + &bcm_cn1, +}; + +static struct qcom_icc_node * const config_noc_nodes[] = { + [MASTER_SPDM] = &qhm_spdm, + [MASTER_SNOC_CNOC] = &qnm_snoc, + [MASTER_QDSS_DAP] = &xm_qdss_dap, + [SLAVE_A1NOC_CFG] = &qhs_a1_noc_cfg, + [SLAVE_AHB2PHY_EAST] = &qhs_ahb2phy_east, + [SLAVE_AHB2PHY_WEST] = &qhs_ahb2phy_west, + [SLAVE_AOP] = &qhs_aop, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_CAMERA_CFG] = &qhs_camera_cfg, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx, + [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg, + [SLAVE_CNOC_DDRSS] = &qhs_ddrss_cfg, + [SLAVE_DISPLAY_CFG] = &qhs_display_cfg, + [SLAVE_EMAC_AVB_CFG] = &qhs_emac_avb_cfg, + [SLAVE_GLM] = &qhs_glm, + [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_IPA_CFG] = &qhs_ipa, + [SLAVE_CNOC_MNOC_CFG] = &qhs_mnoc_cfg, + [SLAVE_PCIE_CFG] = &qhs_pcie_config, + [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg, + [SLAVE_PRNG] = &qhs_prng, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QSPI] = &qhs_qspi, + [SLAVE_QUP_0] = &qhs_qup0, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_SDCC_1] = &qhs_sdc1, + [SLAVE_SDCC_2] = &qhs_sdc2, + [SLAVE_SNOC_CFG] = &qhs_snoc_cfg, + [SLAVE_SPDM_WRAPPER] = &qhs_spdm, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM_EAST] = &qhs_tlmm_east, + [SLAVE_TLMM_SOUTH] = &qhs_tlmm_south, + [SLAVE_TLMM_WEST] = &qhs_tlmm_west, + [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg, + [SLAVE_USB2] = &qhs_usb2, + [SLAVE_USB3] = &qhs_usb3, + [SLAVE_VENUS_CFG] = &qhs_venus_cfg, + [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg, + [SLAVE_CNOC_A2NOC] = &qns_cnoc_a2noc, + [SLAVE_SERVICE_CNOC] = &srvc_cnoc, +}; + +static const struct qcom_icc_desc qcs615_config_noc = { + .nodes = config_noc_nodes, + .num_nodes = ARRAY_SIZE(config_noc_nodes), + .bcms = config_noc_bcms, + .num_bcms = ARRAY_SIZE(config_noc_bcms), +}; + +static struct qcom_icc_node * const dc_noc_nodes[] = { + [MASTER_CNOC_DC_NOC] = &qhm_cnoc, + [SLAVE_DC_NOC_GEMNOC] = &qhs_dc_noc_gemnoc, + [SLAVE_LLCC_CFG] = &qhs_llcc, +}; + +static const struct qcom_icc_desc qcs615_dc_noc = { + .nodes = dc_noc_nodes, + .num_nodes = ARRAY_SIZE(dc_noc_nodes), +}; + +static struct qcom_icc_bcm * const gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh2, + &bcm_sh3, + &bcm_mm1, +}; + +static struct qcom_icc_node * const gem_noc_nodes[] = { + [MASTER_APPSS_PROC] = &acm_apps, + [MASTER_GPU_TCU] = &acm_gpu_tcu, + [MASTER_SYS_TCU] = &acm_sys_tcu, + [MASTER_GEM_NOC_CFG] = &qhm_gemnoc_cfg, + [MASTER_GFX3D] = &qnm_gpu, + [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf, + [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf, + [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [SLAVE_MSS_PROC_MS_MPU_CFG] = &qhs_mdsp_ms_mpu_cfg, + [SLAVE_GEM_NOC_SNOC] = &qns_gem_noc_snoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_sys_pcie, + [SLAVE_SERVICE_GEM_NOC] = &srvc_gemnoc, +}; + +static const struct qcom_icc_desc qcs615_gem_noc = { + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), +}; + +static struct qcom_icc_bcm * const ipa_virt_bcms[] = { + &bcm_ip0, +}; + +static struct qcom_icc_node * const ipa_virt_nodes[] = { + [MASTER_IPA_CORE] = &ipa_core_master, + [SLAVE_IPA_CORE] = &ipa_core_slave, +}; + +static const struct qcom_icc_desc qcs615_ipa_virt = { + .nodes = ipa_virt_nodes, + .num_nodes = ARRAY_SIZE(ipa_virt_nodes), + .bcms = ipa_virt_bcms, + .num_bcms = ARRAY_SIZE(ipa_virt_bcms), +}; + +static struct qcom_icc_bcm * const mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, +}; + +static struct qcom_icc_node * const mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, +}; + +static const struct qcom_icc_desc qcs615_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), +}; + +static struct qcom_icc_bcm * const mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, + &bcm_mm2, + &bcm_mm3, +}; + +static struct qcom_icc_node * const mmss_noc_nodes[] = { + [MASTER_CNOC_MNOC_CFG] = &qhm_mnoc_cfg, + [MASTER_CAMNOC_HF0] = &qxm_camnoc_hf0, + [MASTER_CAMNOC_HF1] = &qxm_camnoc_hf1, + [MASTER_CAMNOC_SF] = &qxm_camnoc_sf, + [MASTER_MDP0] = &qxm_mdp0, + [MASTER_ROTATOR] = &qxm_rot, + [MASTER_VIDEO_P0] = &qxm_venus0, + [MASTER_VIDEO_PROC] = &qxm_venus_arm9, + [SLAVE_MNOC_SF_MEM_NOC] = &qns2_mem_noc, + [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SLAVE_SERVICE_MNOC] = &srvc_mnoc, +}; + +static const struct qcom_icc_desc qcs615_mmss_noc = { + .nodes = mmss_noc_nodes, + .num_nodes = ARRAY_SIZE(mmss_noc_nodes), + .bcms = mmss_noc_bcms, + .num_bcms = ARRAY_SIZE(mmss_noc_bcms), +}; + +static struct qcom_icc_bcm * const system_noc_bcms[] = { + &bcm_sn0, + &bcm_sn1, + &bcm_sn2, + &bcm_sn3, + &bcm_sn4, + &bcm_sn5, + &bcm_sn8, + &bcm_sn9, + &bcm_sn12, + &bcm_sn13, + &bcm_sn15, +}; + +static struct qcom_icc_node * const system_noc_nodes[] = { + [MASTER_SNOC_CFG] = &qhm_snoc_cfg, + [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc, + [MASTER_GEM_NOC_SNOC] = &qnm_gemnoc, + [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie, + [MASTER_LPASS_ANOC] = &qnm_lpass_anoc, + [MASTER_ANOC_PCIE_SNOC] = &qnm_pcie_anoc, + [MASTER_PIMEM] = &qxm_pimem, + [MASTER_GIC] = &xm_gic, + [SLAVE_APPSS] = &qhs_apss, + [SLAVE_SNOC_CNOC] = &qns_cnoc, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, + [SLAVE_SNOC_MEM_NOC_GC] = &qns_memnoc_gc, + [SLAVE_IMEM] = &qxs_imem, + [SLAVE_PIMEM] = &qxs_pimem, + [SLAVE_SERVICE_SNOC] = &srvc_snoc, + [SLAVE_PCIE_0] = &xs_pcie, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static const struct qcom_icc_desc qcs615_system_noc = { + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), +}; + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,qcs615-aggre1-noc", + .data = &qcs615_aggre1_noc}, + { .compatible = "qcom,qcs615-camnoc-virt", + .data = &qcs615_camnoc_virt}, + { .compatible = "qcom,qcs615-config-noc", + .data = &qcs615_config_noc}, + { .compatible = "qcom,qcs615-dc-noc", + .data = &qcs615_dc_noc}, + { .compatible = "qcom,qcs615-gem-noc", + .data = &qcs615_gem_noc}, + { .compatible = "qcom,qcs615-ipa-virt", + .data = &qcs615_ipa_virt}, + { .compatible = "qcom,qcs615-mc-virt", + .data = &qcs615_mc_virt}, + { .compatible = "qcom,qcs615-mmss-noc", + .data = &qcs615_mmss_noc}, + { .compatible = "qcom,qcs615-system-noc", + .data = &qcs615_system_noc}, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, + .driver = { + .name = "qnoc-qcs615", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; + +static int __init qnoc_driver_init(void) +{ + return platform_driver_register(&qnoc_driver); +} +core_initcall(qnoc_driver_init); + +static void __exit qnoc_driver_exit(void) +{ + platform_driver_unregister(&qnoc_driver); +} +module_exit(qnoc_driver_exit); + +MODULE_DESCRIPTION("qcs615 NoC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/qcom/qcs615.h b/drivers/interconnect/qcom/qcs615.h new file mode 100644 index 00000000000000..66e66c7e23d4ec --- /dev/null +++ b/drivers/interconnect/qcom/qcs615.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_QCS615_H +#define __DRIVERS_INTERCONNECT_QCOM_QCS615_H + +#define QCS615_MASTER_A1NOC_CFG 1 +#define QCS615_MASTER_A1NOC_SNOC 2 +#define QCS615_MASTER_ANOC_PCIE_SNOC 3 +#define QCS615_MASTER_APPSS_PROC 4 +#define QCS615_MASTER_BLSP_1 5 +#define QCS615_MASTER_CAMNOC_HF0 6 +#define QCS615_MASTER_CAMNOC_HF0_UNCOMP 7 +#define QCS615_MASTER_CAMNOC_HF1 8 +#define QCS615_MASTER_CAMNOC_HF1_UNCOMP 9 +#define QCS615_MASTER_CAMNOC_SF 10 +#define QCS615_MASTER_CAMNOC_SF_UNCOMP 11 +#define QCS615_MASTER_CNOC_A2NOC 12 +#define QCS615_MASTER_CNOC_DC_NOC 13 +#define QCS615_MASTER_CNOC_MNOC_CFG 14 +#define QCS615_MASTER_CRYPTO 15 +#define QCS615_MASTER_EMAC_EVB 16 +#define QCS615_MASTER_GEM_NOC_CFG 17 +#define QCS615_MASTER_GEM_NOC_PCIE_SNOC 18 +#define QCS615_MASTER_GEM_NOC_SNOC 19 +#define QCS615_MASTER_GFX3D 20 +#define QCS615_MASTER_GIC 21 +#define QCS615_MASTER_GPU_TCU 22 +#define QCS615_MASTER_IPA 23 +#define QCS615_MASTER_IPA_CORE 24 +#define QCS615_MASTER_LLCC 25 +#define QCS615_MASTER_LPASS_ANOC 26 +#define QCS615_MASTER_MDP0 27 +#define QCS615_MASTER_MNOC_HF_MEM_NOC 28 +#define QCS615_MASTER_MNOC_SF_MEM_NOC 29 +#define QCS615_MASTER_PCIE 30 +#define QCS615_MASTER_PIMEM 31 +#define QCS615_MASTER_QDSS_BAM 32 +#define QCS615_MASTER_QDSS_DAP 33 +#define QCS615_MASTER_QDSS_ETR 34 +#define QCS615_MASTER_QSPI 35 +#define QCS615_MASTER_QUP_0 36 +#define QCS615_MASTER_ROTATOR 37 +#define QCS615_MASTER_SDCC_1 38 +#define QCS615_MASTER_SDCC_2 39 +#define QCS615_MASTER_SNOC_CFG 40 +#define QCS615_MASTER_SNOC_CNOC 41 +#define QCS615_MASTER_SNOC_GC_MEM_NOC 42 +#define QCS615_MASTER_SNOC_SF_MEM_NOC 43 +#define QCS615_MASTER_SPDM 44 +#define QCS615_MASTER_SYS_TCU 45 +#define QCS615_MASTER_UFS_MEM 46 +#define QCS615_MASTER_USB2 47 +#define QCS615_MASTER_USB3_0 48 +#define QCS615_MASTER_VIDEO_P0 49 +#define QCS615_MASTER_VIDEO_PROC 50 +#define QCS615_SLAVE_A1NOC_CFG 51 +#define QCS615_SLAVE_A1NOC_SNOC 52 +#define QCS615_SLAVE_AHB2PHY_EAST 53 +#define QCS615_SLAVE_AHB2PHY_WEST 54 +#define QCS615_SLAVE_ANOC_PCIE_SNOC 55 +#define QCS615_SLAVE_AOP 56 +#define QCS615_SLAVE_AOSS 57 +#define QCS615_SLAVE_APPSS 58 +#define QCS615_SLAVE_CAMERA_CFG 59 +#define QCS615_SLAVE_CAMNOC_UNCOMP 60 +#define QCS615_SLAVE_CLK_CTL 61 +#define QCS615_SLAVE_CNOC_A2NOC 62 +#define QCS615_SLAVE_CNOC_DDRSS 63 +#define QCS615_SLAVE_CNOC_MNOC_CFG 64 +#define QCS615_SLAVE_CRYPTO_0_CFG 65 +#define QCS615_SLAVE_DC_NOC_GEMNOC 66 +#define QCS615_SLAVE_DISPLAY_CFG 67 +#define QCS615_SLAVE_EBI1 68 +#define QCS615_SLAVE_EMAC_AVB_CFG 69 +#define QCS615_SLAVE_GEM_NOC_SNOC 70 +#define QCS615_SLAVE_GFX3D_CFG 71 +#define QCS615_SLAVE_GLM 72 +#define QCS615_SLAVE_IMEM 73 +#define QCS615_SLAVE_IMEM_CFG 74 +#define QCS615_SLAVE_IPA_CFG 75 +#define QCS615_SLAVE_IPA_CORE 76 +#define QCS615_SLAVE_LLCC 77 +#define QCS615_SLAVE_LLCC_CFG 78 +#define QCS615_SLAVE_LPASS_SNOC 79 +#define QCS615_SLAVE_MEM_NOC_PCIE_SNOC 80 +#define QCS615_SLAVE_MNOC_HF_MEM_NOC 81 +#define QCS615_SLAVE_MNOC_SF_MEM_NOC 82 +#define QCS615_SLAVE_MSS_PROC_MS_MPU_CFG 83 +#define QCS615_SLAVE_PCIE_0 84 +#define QCS615_SLAVE_PCIE_CFG 85 +#define QCS615_SLAVE_PIMEM 86 +#define QCS615_SLAVE_PIMEM_CFG 87 +#define QCS615_SLAVE_PRNG 88 +#define QCS615_SLAVE_QDSS_CFG 89 +#define QCS615_SLAVE_QDSS_STM 90 +#define QCS615_SLAVE_QSPI 91 +#define QCS615_SLAVE_QUP_0 92 +#define QCS615_SLAVE_QUP_1 93 +#define QCS615_SLAVE_RBCPR_CX_CFG 94 +#define QCS615_SLAVE_RBCPR_MX_CFG 95 +#define QCS615_SLAVE_SDCC_1 96 +#define QCS615_SLAVE_SDCC_2 97 +#define QCS615_SLAVE_SERVICE_A2NOC 98 +#define QCS615_SLAVE_SERVICE_CNOC 99 +#define QCS615_SLAVE_SERVICE_GEM_NOC 100 +#define QCS615_SLAVE_SERVICE_MNOC 101 +#define QCS615_SLAVE_SERVICE_SNOC 102 +#define QCS615_SLAVE_SNOC_CFG 103 +#define QCS615_SLAVE_SNOC_CNOC 104 +#define QCS615_SLAVE_SNOC_GEM_NOC_SF 105 +#define QCS615_SLAVE_SNOC_MEM_NOC_GC 106 +#define QCS615_SLAVE_SPDM_WRAPPER 107 +#define QCS615_SLAVE_TCSR 108 +#define QCS615_SLAVE_TCU 109 +#define QCS615_SLAVE_TLMM_EAST 110 +#define QCS615_SLAVE_TLMM_SOUTH 111 +#define QCS615_SLAVE_TLMM_WEST 112 +#define QCS615_SLAVE_UFS_MEM_CFG 113 +#define QCS615_SLAVE_USB2 114 +#define QCS615_SLAVE_USB3 115 +#define QCS615_SLAVE_VENUS_CFG 116 +#define QCS615_SLAVE_VSENSE_CTRL_CFG 117 + +#endif + diff --git a/drivers/interconnect/qcom/qcs8300.c b/drivers/interconnect/qcom/qcs8300.c new file mode 100644 index 00000000000000..e7a1b2fc69babe --- /dev/null +++ b/drivers/interconnect/qcom/qcs8300.c @@ -0,0 +1,2088 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "bcm-voter.h" +#include "icc-rpmh.h" +#include "qcs8300.h" + +static struct qcom_icc_node qxm_qup3 = { + .name = "qxm_qup3", + .id = QCS8300_MASTER_QUP_3, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_emac_0 = { + .name = "xm_emac_0", + .id = QCS8300_MASTER_EMAC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_sdc1 = { + .name = "xm_sdc1", + .id = QCS8300_MASTER_SDC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_ufs_mem = { + .name = "xm_ufs_mem", + .id = QCS8300_MASTER_UFS_MEM, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_usb2_2 = { + .name = "xm_usb2_2", + .id = QCS8300_MASTER_USB2, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node xm_usb3_0 = { + .name = "xm_usb3_0", + .id = QCS8300_MASTER_USB3_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qdss_bam = { + .name = "qhm_qdss_bam", + .id = QCS8300_MASTER_QDSS_BAM, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qup0 = { + .name = "qhm_qup0", + .id = QCS8300_MASTER_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qhm_qup1 = { + .name = "qhm_qup1", + .id = QCS8300_MASTER_QUP_1, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qnm_cnoc_datapath = { + .name = "qnm_cnoc_datapath", + .id = QCS8300_MASTER_CNOC_A2NOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_crypto_0 = { + .name = "qxm_crypto_0", + .id = QCS8300_MASTER_CRYPTO_CORE0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_crypto_1 = { + .name = "qxm_crypto_1", + .id = QCS8300_MASTER_CRYPTO_CORE1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qxm_ipa = { + .name = "qxm_ipa", + .id = QCS8300_MASTER_IPA, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node xm_qdss_etr_0 = { + .name = "xm_qdss_etr_0", + .id = QCS8300_MASTER_QDSS_ETR_0, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node xm_qdss_etr_1 = { + .name = "xm_qdss_etr_1", + .id = QCS8300_MASTER_QDSS_ETR_1, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qup0_core_master = { + .name = "qup0_core_master", + .id = QCS8300_MASTER_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_QUP_CORE_0 }, +}; + +static struct qcom_icc_node qup1_core_master = { + .name = "qup1_core_master", + .id = QCS8300_MASTER_QUP_CORE_1, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_QUP_CORE_1 }, +}; + +static struct qcom_icc_node qup3_core_master = { + .name = "qup3_core_master", + .id = QCS8300_MASTER_QUP_CORE_3, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_QUP_CORE_3 }, +}; + +static struct qcom_icc_node qnm_gemnoc_cnoc = { + .name = "qnm_gemnoc_cnoc", + .id = QCS8300_MASTER_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 71, + .links = { QCS8300_SLAVE_AHB2PHY_2, QCS8300_SLAVE_AHB2PHY_3, + QCS8300_SLAVE_ANOC_THROTTLE_CFG, QCS8300_SLAVE_AOSS, + QCS8300_SLAVE_APPSS, QCS8300_SLAVE_BOOT_ROM, + QCS8300_SLAVE_CAMERA_CFG, QCS8300_SLAVE_CAMERA_NRT_THROTTLE_CFG, + QCS8300_SLAVE_CAMERA_RT_THROTTLE_CFG, QCS8300_SLAVE_CLK_CTL, + QCS8300_SLAVE_CDSP_CFG, QCS8300_SLAVE_RBCPR_CX_CFG, + QCS8300_SLAVE_RBCPR_MMCX_CFG, QCS8300_SLAVE_RBCPR_MX_CFG, + QCS8300_SLAVE_CPR_NSPCX, QCS8300_SLAVE_CPR_NSPHMX, + QCS8300_SLAVE_CRYPTO_0_CFG, QCS8300_SLAVE_CX_RDPM, + QCS8300_SLAVE_DISPLAY_CFG, QCS8300_SLAVE_DISPLAY_RT_THROTTLE_CFG, + QCS8300_SLAVE_EMAC_CFG, QCS8300_SLAVE_GP_DSP0_CFG, + QCS8300_SLAVE_GPDSP0_THROTTLE_CFG, QCS8300_SLAVE_GPU_TCU_THROTTLE_CFG, + QCS8300_SLAVE_GFX3D_CFG, QCS8300_SLAVE_HWKM, + QCS8300_SLAVE_IMEM_CFG, QCS8300_SLAVE_IPA_CFG, + QCS8300_SLAVE_IPC_ROUTER_CFG, QCS8300_SLAVE_LPASS, + QCS8300_SLAVE_LPASS_THROTTLE_CFG, QCS8300_SLAVE_MX_RDPM, + QCS8300_SLAVE_MXC_RDPM, QCS8300_SLAVE_PCIE_0_CFG, + QCS8300_SLAVE_PCIE_1_CFG, QCS8300_SLAVE_PCIE_TCU_THROTTLE_CFG, + QCS8300_SLAVE_PCIE_THROTTLE_CFG, QCS8300_SLAVE_PDM, + QCS8300_SLAVE_PIMEM_CFG, QCS8300_SLAVE_PKA_WRAPPER_CFG, + QCS8300_SLAVE_QDSS_CFG, QCS8300_SLAVE_QM_CFG, + QCS8300_SLAVE_QM_MPU_CFG, QCS8300_SLAVE_QUP_0, + QCS8300_SLAVE_QUP_1, QCS8300_SLAVE_QUP_3, + QCS8300_SLAVE_SAIL_THROTTLE_CFG, QCS8300_SLAVE_SDC1, + QCS8300_SLAVE_SECURITY, QCS8300_SLAVE_SNOC_THROTTLE_CFG, + QCS8300_SLAVE_TCSR, QCS8300_SLAVE_TLMM, + QCS8300_SLAVE_TSC_CFG, QCS8300_SLAVE_UFS_MEM_CFG, + QCS8300_SLAVE_USB2, QCS8300_SLAVE_USB3_0, + QCS8300_SLAVE_VENUS_CFG, QCS8300_SLAVE_VENUS_CVP_THROTTLE_CFG, + QCS8300_SLAVE_VENUS_V_CPU_THROTTLE_CFG, + QCS8300_SLAVE_VENUS_VCODEC_THROTTLE_CFG, + QCS8300_SLAVE_DDRSS_CFG, QCS8300_SLAVE_GPDSP_NOC_CFG, + QCS8300_SLAVE_CNOC_MNOC_HF_CFG, QCS8300_SLAVE_CNOC_MNOC_SF_CFG, + QCS8300_SLAVE_PCIE_ANOC_CFG, QCS8300_SLAVE_SNOC_CFG, + QCS8300_SLAVE_BOOT_IMEM, QCS8300_SLAVE_IMEM, + QCS8300_SLAVE_PIMEM, QCS8300_SLAVE_QDSS_STM, + QCS8300_SLAVE_TCU }, +}; + +static struct qcom_icc_node qnm_gemnoc_pcie = { + .name = "qnm_gemnoc_pcie", + .id = QCS8300_MASTER_GEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 2, + .links = { QCS8300_SLAVE_PCIE_0, QCS8300_SLAVE_PCIE_1 }, +}; + +static struct qcom_icc_node qnm_cnoc_dc_noc = { + .name = "qnm_cnoc_dc_noc", + .id = QCS8300_MASTER_CNOC_DC_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 2, + .links = { QCS8300_SLAVE_LLCC_CFG, QCS8300_SLAVE_GEM_NOC_CFG }, +}; + +static struct qcom_icc_node alm_gpu_tcu = { + .name = "alm_gpu_tcu", + .id = QCS8300_MASTER_GPU_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC }, +}; + +static struct qcom_icc_node alm_pcie_tcu = { + .name = "alm_pcie_tcu", + .id = QCS8300_MASTER_PCIE_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC }, +}; + +static struct qcom_icc_node alm_sys_tcu = { + .name = "alm_sys_tcu", + .id = QCS8300_MASTER_SYS_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC }, +}; + +static struct qcom_icc_node chm_apps = { + .name = "chm_apps", + .id = QCS8300_MASTER_APPSS_PROC, + .channels = 4, + .buswidth = 32, + .num_links = 3, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC, + QCS8300_SLAVE_GEM_NOC_PCIE_CNOC }, +}; + +static struct qcom_icc_node qnm_cmpnoc0 = { + .name = "qnm_cmpnoc0", + .id = QCS8300_MASTER_COMPUTE_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_gemnoc_cfg = { + .name = "qnm_gemnoc_cfg", + .id = QCS8300_MASTER_GEM_NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 4, + .links = { QCS8300_SLAVE_SERVICE_GEM_NOC_1, QCS8300_SLAVE_SERVICE_GEM_NOC_2, + QCS8300_SLAVE_SERVICE_GEM_NOC, QCS8300_SLAVE_SERVICE_GEM_NOC2 }, +}; + +static struct qcom_icc_node qnm_gpdsp_sail = { + .name = "qnm_gpdsp_sail", + .id = QCS8300_MASTER_GPDSP_SAIL, + .channels = 1, + .buswidth = 16, + .num_links = 2, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_gpu = { + .name = "qnm_gpu", + .id = QCS8300_MASTER_GFX3D, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_mnoc_hf = { + .name = "qnm_mnoc_hf", + .id = QCS8300_MASTER_MNOC_HF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { QCS8300_SLAVE_LLCC, QCS8300_SLAVE_GEM_NOC_PCIE_CNOC }, +}; + +static struct qcom_icc_node qnm_mnoc_sf = { + .name = "qnm_mnoc_sf", + .id = QCS8300_MASTER_MNOC_SF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 3, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC, + QCS8300_SLAVE_GEM_NOC_PCIE_CNOC }, +}; + +static struct qcom_icc_node qnm_pcie = { + .name = "qnm_pcie", + .id = QCS8300_MASTER_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 32, + .num_links = 2, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_snoc_gc = { + .name = "qnm_snoc_gc", + .id = QCS8300_MASTER_SNOC_GC_MEM_NOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_LLCC }, +}; + +static struct qcom_icc_node qnm_snoc_sf = { + .name = "qnm_snoc_sf", + .id = QCS8300_MASTER_SNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 3, + .links = { QCS8300_SLAVE_GEM_NOC_CNOC, QCS8300_SLAVE_LLCC, + QCS8300_SLAVE_GEM_NOC_PCIE_CNOC }, +}; + +static struct qcom_icc_node qnm_sailss_md0 = { + .name = "qnm_sailss_md0", + .id = QCS8300_MASTER_SAILSS_MD0, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_SLAVE_GP_DSP_SAIL_NOC }, +}; + +static struct qcom_icc_node qxm_dsp0 = { + .name = "qxm_dsp0", + .id = QCS8300_MASTER_DSP0, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_SLAVE_GP_DSP_SAIL_NOC }, +}; + +static struct qcom_icc_node qhm_config_noc = { + .name = "qhm_config_noc", + .id = QCS8300_MASTER_CNOC_LPASS_AG_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 6, + .links = { QCS8300_SLAVE_LPASS_CORE_CFG, QCS8300_SLAVE_LPASS_LPI_CFG, + QCS8300_SLAVE_LPASS_MPU_CFG, QCS8300_SLAVE_LPASS_TOP_CFG, + QCS8300_SLAVE_SERVICES_LPASS_AML_NOC, QCS8300_SLAVE_SERVICE_LPASS_AG_NOC }, +}; + +static struct qcom_icc_node qxm_lpass_dsp = { + .name = "qxm_lpass_dsp", + .id = QCS8300_MASTER_LPASS_PROC, + .channels = 1, + .buswidth = 8, + .num_links = 4, + .links = { QCS8300_SLAVE_LPASS_TOP_CFG, QCS8300_SLAVE_LPASS_SNOC, + QCS8300_SLAVE_SERVICES_LPASS_AML_NOC, QCS8300_SLAVE_SERVICE_LPASS_AG_NOC }, +}; + +static struct qcom_icc_node llcc_mc = { + .name = "llcc_mc", + .id = QCS8300_MASTER_LLCC, + .channels = 8, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_EBI1 }, +}; + +static struct qcom_icc_node qnm_camnoc_hf = { + .name = "qnm_camnoc_hf", + .id = QCS8300_MASTER_CAMNOC_HF, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_camnoc_icp = { + .name = "qnm_camnoc_icp", + .id = QCS8300_MASTER_CAMNOC_ICP, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_camnoc_sf = { + .name = "qnm_camnoc_sf", + .id = QCS8300_MASTER_CAMNOC_SF, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_mdp0_0 = { + .name = "qnm_mdp0_0", + .id = QCS8300_MASTER_MDP0, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_mdp0_1 = { + .name = "qnm_mdp0_1", + .id = QCS8300_MASTER_MDP1, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_mnoc_hf_cfg = { + .name = "qnm_mnoc_hf_cfg", + .id = QCS8300_MASTER_CNOC_MNOC_HF_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_SERVICE_MNOC_HF }, +}; + +static struct qcom_icc_node qnm_mnoc_sf_cfg = { + .name = "qnm_mnoc_sf_cfg", + .id = QCS8300_MASTER_CNOC_MNOC_SF_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_SERVICE_MNOC_SF }, +}; + +static struct qcom_icc_node qnm_video0 = { + .name = "qnm_video0", + .id = QCS8300_MASTER_VIDEO_P0, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_video_cvp = { + .name = "qnm_video_cvp", + .id = QCS8300_MASTER_VIDEO_PROC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_video_v_cpu = { + .name = "qnm_video_v_cpu", + .id = QCS8300_MASTER_VIDEO_V_PROC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qhm_nsp_noc_config = { + .name = "qhm_nsp_noc_config", + .id = QCS8300_MASTER_CDSP_NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_SERVICE_NSP_NOC }, +}; + +static struct qcom_icc_node qxm_nsp = { + .name = "qxm_nsp", + .id = QCS8300_MASTER_CDSP_PROC, + .channels = 2, + .buswidth = 32, + .num_links = 2, + .links = { QCS8300_SLAVE_HCP_A, QCS8300_SLAVE_CDSP_MEM_NOC }, +}; + +static struct qcom_icc_node xm_pcie3_0 = { + .name = "xm_pcie3_0", + .id = QCS8300_MASTER_PCIE_0, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node xm_pcie3_1 = { + .name = "xm_pcie3_1", + .id = QCS8300_MASTER_PCIE_1, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node qhm_gic = { + .name = "qhm_gic", + .id = QCS8300_MASTER_GIC_AHB, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_aggre1_noc = { + .name = "qnm_aggre1_noc", + .id = QCS8300_MASTER_A1NOC_SNOC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_aggre2_noc = { + .name = "qnm_aggre2_noc", + .id = QCS8300_MASTER_A2NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_lpass_noc = { + .name = "qnm_lpass_noc", + .id = QCS8300_MASTER_LPASS_ANOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_snoc_cfg = { + .name = "qnm_snoc_cfg", + .id = QCS8300_MASTER_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_SLAVE_SERVICE_SNOC }, +}; + +static struct qcom_icc_node qxm_pimem = { + .name = "qxm_pimem", + .id = QCS8300_MASTER_PIMEM, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_SNOC_GEM_NOC_GC }, +}; + +static struct qcom_icc_node xm_gic = { + .name = "xm_gic", + .id = QCS8300_MASTER_GIC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_SLAVE_SNOC_GEM_NOC_GC }, +}; + +static struct qcom_icc_node qns_a1noc_snoc = { + .name = "qns_a1noc_snoc", + .id = QCS8300_SLAVE_A1NOC_SNOC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_MASTER_A1NOC_SNOC }, +}; + +static struct qcom_icc_node qns_a2noc_snoc = { + .name = "qns_a2noc_snoc", + .id = QCS8300_SLAVE_A2NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_MASTER_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qup0_core_slave = { + .name = "qup0_core_slave", + .id = QCS8300_SLAVE_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qup1_core_slave = { + .name = "qup1_core_slave", + .id = QCS8300_SLAVE_QUP_CORE_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qup3_core_slave = { + .name = "qup3_core_slave", + .id = QCS8300_SLAVE_QUP_CORE_3, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy2 = { + .name = "qhs_ahb2phy2", + .id = QCS8300_SLAVE_AHB2PHY_2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy3 = { + .name = "qhs_ahb2phy3", + .id = QCS8300_SLAVE_AHB2PHY_3, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_anoc_throttle_cfg = { + .name = "qhs_anoc_throttle_cfg", + .id = QCS8300_SLAVE_ANOC_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_aoss = { + .name = "qhs_aoss", + .id = QCS8300_SLAVE_AOSS, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_apss = { + .name = "qhs_apss", + .id = QCS8300_SLAVE_APPSS, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_boot_rom = { + .name = "qhs_boot_rom", + .id = QCS8300_SLAVE_BOOT_ROM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_camera_cfg = { + .name = "qhs_camera_cfg", + .id = QCS8300_SLAVE_CAMERA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_camera_nrt_throttle_cfg = { + .name = "qhs_camera_nrt_throttle_cfg", + .id = QCS8300_SLAVE_CAMERA_NRT_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_camera_rt_throttle_cfg = { + .name = "qhs_camera_rt_throttle_cfg", + .id = QCS8300_SLAVE_CAMERA_RT_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_clk_ctl = { + .name = "qhs_clk_ctl", + .id = QCS8300_SLAVE_CLK_CTL, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_compute0_cfg = { + .name = "qhs_compute0_cfg", + .id = QCS8300_SLAVE_CDSP_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_MASTER_CDSP_NOC_CFG }, +}; + +static struct qcom_icc_node qhs_cpr_cx = { + .name = "qhs_cpr_cx", + .id = QCS8300_SLAVE_RBCPR_CX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mmcx = { + .name = "qhs_cpr_mmcx", + .id = QCS8300_SLAVE_RBCPR_MMCX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mx = { + .name = "qhs_cpr_mx", + .id = QCS8300_SLAVE_RBCPR_MX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_nspcx = { + .name = "qhs_cpr_nspcx", + .id = QCS8300_SLAVE_CPR_NSPCX, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_nsphmx = { + .name = "qhs_cpr_nsphmx", + .id = QCS8300_SLAVE_CPR_NSPHMX, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_crypto0_cfg = { + .name = "qhs_crypto0_cfg", + .id = QCS8300_SLAVE_CRYPTO_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cx_rdpm = { + .name = "qhs_cx_rdpm", + .id = QCS8300_SLAVE_CX_RDPM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_display0_cfg = { + .name = "qhs_display0_cfg", + .id = QCS8300_SLAVE_DISPLAY_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_display0_rt_throttle_cfg = { + .name = "qhs_display0_rt_throttle_cfg", + .id = QCS8300_SLAVE_DISPLAY_RT_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_emac0_cfg = { + .name = "qhs_emac0_cfg", + .id = QCS8300_SLAVE_EMAC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_gp_dsp0_cfg = { + .name = "qhs_gp_dsp0_cfg", + .id = QCS8300_SLAVE_GP_DSP0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_gpdsp0_throttle_cfg = { + .name = "qhs_gpdsp0_throttle_cfg", + .id = QCS8300_SLAVE_GPDSP0_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_gpu_tcu_throttle_cfg = { + .name = "qhs_gpu_tcu_throttle_cfg", + .id = QCS8300_SLAVE_GPU_TCU_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_gpuss_cfg = { + .name = "qhs_gpuss_cfg", + .id = QCS8300_SLAVE_GFX3D_CFG, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_hwkm = { + .name = "qhs_hwkm", + .id = QCS8300_SLAVE_HWKM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_imem_cfg = { + .name = "qhs_imem_cfg", + .id = QCS8300_SLAVE_IMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipa = { + .name = "qhs_ipa", + .id = QCS8300_SLAVE_IPA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipc_router = { + .name = "qhs_ipc_router", + .id = QCS8300_SLAVE_IPC_ROUTER_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lpass_cfg = { + .name = "qhs_lpass_cfg", + .id = QCS8300_SLAVE_LPASS, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_MASTER_CNOC_LPASS_AG_NOC }, +}; + +static struct qcom_icc_node qhs_lpass_throttle_cfg = { + .name = "qhs_lpass_throttle_cfg", + .id = QCS8300_SLAVE_LPASS_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mx_rdpm = { + .name = "qhs_mx_rdpm", + .id = QCS8300_SLAVE_MX_RDPM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_mxc_rdpm = { + .name = "qhs_mxc_rdpm", + .id = QCS8300_SLAVE_MXC_RDPM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie0_cfg = { + .name = "qhs_pcie0_cfg", + .id = QCS8300_SLAVE_PCIE_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie1_cfg = { + .name = "qhs_pcie1_cfg", + .id = QCS8300_SLAVE_PCIE_1_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie_tcu_throttle_cfg = { + .name = "qhs_pcie_tcu_throttle_cfg", + .id = QCS8300_SLAVE_PCIE_TCU_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie_throttle_cfg = { + .name = "qhs_pcie_throttle_cfg", + .id = QCS8300_SLAVE_PCIE_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pdm = { + .name = "qhs_pdm", + .id = QCS8300_SLAVE_PDM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pimem_cfg = { + .name = "qhs_pimem_cfg", + .id = QCS8300_SLAVE_PIMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pke_wrapper_cfg = { + .name = "qhs_pke_wrapper_cfg", + .id = QCS8300_SLAVE_PKA_WRAPPER_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qdss_cfg = { + .name = "qhs_qdss_cfg", + .id = QCS8300_SLAVE_QDSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qm_cfg = { + .name = "qhs_qm_cfg", + .id = QCS8300_SLAVE_QM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qm_mpu_cfg = { + .name = "qhs_qm_mpu_cfg", + .id = QCS8300_SLAVE_QM_MPU_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup0 = { + .name = "qhs_qup0", + .id = QCS8300_SLAVE_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup1 = { + .name = "qhs_qup1", + .id = QCS8300_SLAVE_QUP_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup3 = { + .name = "qhs_qup3", + .id = QCS8300_SLAVE_QUP_3, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sail_throttle_cfg = { + .name = "qhs_sail_throttle_cfg", + .id = QCS8300_SLAVE_SAIL_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc1 = { + .name = "qhs_sdc1", + .id = QCS8300_SLAVE_SDC1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_security = { + .name = "qhs_security", + .id = QCS8300_SLAVE_SECURITY, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_snoc_throttle_cfg = { + .name = "qhs_snoc_throttle_cfg", + .id = QCS8300_SLAVE_SNOC_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tcsr = { + .name = "qhs_tcsr", + .id = QCS8300_SLAVE_TCSR, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tlmm = { + .name = "qhs_tlmm", + .id = QCS8300_SLAVE_TLMM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tsc_cfg = { + .name = "qhs_tsc_cfg", + .id = QCS8300_SLAVE_TSC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ufs_mem_cfg = { + .name = "qhs_ufs_mem_cfg", + .id = QCS8300_SLAVE_UFS_MEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb2_0 = { + .name = "qhs_usb2_0", + .id = QCS8300_SLAVE_USB2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb3_0 = { + .name = "qhs_usb3_0", + .id = QCS8300_SLAVE_USB3_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_venus_cfg = { + .name = "qhs_venus_cfg", + .id = QCS8300_SLAVE_VENUS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_venus_cvp_throttle_cfg = { + .name = "qhs_venus_cvp_throttle_cfg", + .id = QCS8300_SLAVE_VENUS_CVP_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_venus_v_cpu_throttle_cfg = { + .name = "qhs_venus_v_cpu_throttle_cfg", + .id = QCS8300_SLAVE_VENUS_V_CPU_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_venus_vcodec_throttle_cfg = { + .name = "qhs_venus_vcodec_throttle_cfg", + .id = QCS8300_SLAVE_VENUS_VCODEC_THROTTLE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_ddrss_cfg = { + .name = "qns_ddrss_cfg", + .id = QCS8300_SLAVE_DDRSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_MASTER_CNOC_DC_NOC }, +}; + +static struct qcom_icc_node qns_gpdsp_noc_cfg = { + .name = "qns_gpdsp_noc_cfg", + .id = QCS8300_SLAVE_GPDSP_NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mnoc_hf_cfg = { + .name = "qns_mnoc_hf_cfg", + .id = QCS8300_SLAVE_CNOC_MNOC_HF_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_MASTER_CNOC_MNOC_HF_CFG }, +}; + +static struct qcom_icc_node qns_mnoc_sf_cfg = { + .name = "qns_mnoc_sf_cfg", + .id = QCS8300_SLAVE_CNOC_MNOC_SF_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_MASTER_CNOC_MNOC_SF_CFG }, +}; + +static struct qcom_icc_node qns_pcie_anoc_cfg = { + .name = "qns_pcie_anoc_cfg", + .id = QCS8300_SLAVE_PCIE_ANOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_snoc_cfg = { + .name = "qns_snoc_cfg", + .id = QCS8300_SLAVE_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_MASTER_SNOC_CFG }, +}; + +static struct qcom_icc_node qxs_boot_imem = { + .name = "qxs_boot_imem", + .id = QCS8300_SLAVE_BOOT_IMEM, + .channels = 1, + .buswidth = 16, + .num_links = 0, +}; + +static struct qcom_icc_node qxs_imem = { + .name = "qxs_imem", + .id = QCS8300_SLAVE_IMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qxs_pimem = { + .name = "qxs_pimem", + .id = QCS8300_SLAVE_PIMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_0 = { + .name = "xs_pcie_0", + .id = QCS8300_SLAVE_PCIE_0, + .channels = 1, + .buswidth = 16, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_1 = { + .name = "xs_pcie_1", + .id = QCS8300_SLAVE_PCIE_1, + .channels = 1, + .buswidth = 32, + .num_links = 0, +}; + +static struct qcom_icc_node xs_qdss_stm = { + .name = "xs_qdss_stm", + .id = QCS8300_SLAVE_QDSS_STM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_sys_tcu_cfg = { + .name = "xs_sys_tcu_cfg", + .id = QCS8300_SLAVE_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_llcc = { + .name = "qhs_llcc", + .id = QCS8300_SLAVE_LLCC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gemnoc = { + .name = "qns_gemnoc", + .id = QCS8300_SLAVE_GEM_NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { QCS8300_MASTER_GEM_NOC_CFG }, +}; + +static struct qcom_icc_node qns_gem_noc_cnoc = { + .name = "qns_gem_noc_cnoc", + .id = QCS8300_SLAVE_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_MASTER_GEM_NOC_CNOC }, +}; + +static struct qcom_icc_node qns_llcc = { + .name = "qns_llcc", + .id = QCS8300_SLAVE_LLCC, + .channels = 4, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_MASTER_LLCC }, +}; + +static struct qcom_icc_node qns_pcie = { + .name = "qns_pcie", + .id = QCS8300_SLAVE_GEM_NOC_PCIE_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_MASTER_GEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node srvc_even_gemnoc = { + .name = "srvc_even_gemnoc", + .id = QCS8300_SLAVE_SERVICE_GEM_NOC_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_odd_gemnoc = { + .name = "srvc_odd_gemnoc", + .id = QCS8300_SLAVE_SERVICE_GEM_NOC_2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_sys_gemnoc = { + .name = "srvc_sys_gemnoc", + .id = QCS8300_SLAVE_SERVICE_GEM_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_sys_gemnoc_2 = { + .name = "srvc_sys_gemnoc_2", + .id = QCS8300_SLAVE_SERVICE_GEM_NOC2, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gp_dsp_sail_noc = { + .name = "qns_gp_dsp_sail_noc", + .id = QCS8300_SLAVE_GP_DSP_SAIL_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_MASTER_GPDSP_SAIL }, +}; + +static struct qcom_icc_node qhs_lpass_core = { + .name = "qhs_lpass_core", + .id = QCS8300_SLAVE_LPASS_CORE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lpass_lpi = { + .name = "qhs_lpass_lpi", + .id = QCS8300_SLAVE_LPASS_LPI_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lpass_mpu = { + .name = "qhs_lpass_mpu", + .id = QCS8300_SLAVE_LPASS_MPU_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lpass_top = { + .name = "qhs_lpass_top", + .id = QCS8300_SLAVE_LPASS_TOP_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_sysnoc = { + .name = "qns_sysnoc", + .id = QCS8300_SLAVE_LPASS_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_MASTER_LPASS_ANOC }, +}; + +static struct qcom_icc_node srvc_niu_aml_noc = { + .name = "srvc_niu_aml_noc", + .id = QCS8300_SLAVE_SERVICES_LPASS_AML_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_niu_lpass_agnoc = { + .name = "srvc_niu_lpass_agnoc", + .id = QCS8300_SLAVE_SERVICE_LPASS_AG_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node ebi = { + .name = "ebi", + .id = QCS8300_SLAVE_EBI1, + .channels = 8, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mem_noc_hf = { + .name = "qns_mem_noc_hf", + .id = QCS8300_SLAVE_MNOC_HF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_MASTER_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qns_mem_noc_sf = { + .name = "qns_mem_noc_sf", + .id = QCS8300_SLAVE_MNOC_SF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_MASTER_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node srvc_mnoc_hf = { + .name = "srvc_mnoc_hf", + .id = QCS8300_SLAVE_SERVICE_MNOC_HF, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_mnoc_sf = { + .name = "srvc_mnoc_sf", + .id = QCS8300_SLAVE_SERVICE_MNOC_SF, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_hcp = { + .name = "qns_hcp", + .id = QCS8300_SLAVE_HCP_A, + .channels = 2, + .buswidth = 32, + .num_links = 0, +}; + +static struct qcom_icc_node qns_nsp_gemnoc = { + .name = "qns_nsp_gemnoc", + .id = QCS8300_SLAVE_CDSP_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_MASTER_COMPUTE_NOC }, +}; + +static struct qcom_icc_node service_nsp_noc = { + .name = "service_nsp_noc", + .id = QCS8300_SLAVE_SERVICE_NSP_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_pcie_mem_noc = { + .name = "qns_pcie_mem_noc", + .id = QCS8300_SLAVE_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { QCS8300_MASTER_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node qns_gemnoc_gc = { + .name = "qns_gemnoc_gc", + .id = QCS8300_SLAVE_SNOC_GEM_NOC_GC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { QCS8300_MASTER_SNOC_GC_MEM_NOC }, +}; + +static struct qcom_icc_node qns_gemnoc_sf = { + .name = "qns_gemnoc_sf", + .id = QCS8300_SLAVE_SNOC_GEM_NOC_SF, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { QCS8300_MASTER_SNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node srvc_snoc = { + .name = "srvc_snoc", + .id = QCS8300_SLAVE_SERVICE_SNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_bcm bcm_acv = { + .name = "ACV", + .enable_mask = BIT(3), + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_ce0 = { + .name = "CE0", + .num_nodes = 2, + .nodes = { &qxm_crypto_0, &qxm_crypto_1 }, +}; + +static struct qcom_icc_bcm bcm_cn0 = { + .name = "CN0", + .keepalive = true, + .num_nodes = 2, + .nodes = { &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie }, +}; + +static struct qcom_icc_bcm bcm_cn1 = { + .name = "CN1", + .num_nodes = 66, + .nodes = { &qhs_ahb2phy2, &qhs_ahb2phy3, + &qhs_anoc_throttle_cfg, &qhs_aoss, + &qhs_apss, &qhs_boot_rom, + &qhs_camera_cfg, &qhs_camera_nrt_throttle_cfg, + &qhs_camera_rt_throttle_cfg, &qhs_clk_ctl, + &qhs_compute0_cfg, &qhs_cpr_cx, + &qhs_cpr_mmcx, &qhs_cpr_mx, + &qhs_cpr_nspcx, &qhs_cpr_nsphmx, + &qhs_crypto0_cfg, &qhs_cx_rdpm, + &qhs_display0_cfg, &qhs_display0_rt_throttle_cfg, + &qhs_emac0_cfg, &qhs_gp_dsp0_cfg, + &qhs_gpdsp0_throttle_cfg, &qhs_gpu_tcu_throttle_cfg, + &qhs_gpuss_cfg, &qhs_hwkm, + &qhs_imem_cfg, &qhs_ipa, + &qhs_ipc_router, &qhs_lpass_cfg, + &qhs_lpass_throttle_cfg, &qhs_mx_rdpm, + &qhs_mxc_rdpm, &qhs_pcie0_cfg, + &qhs_pcie1_cfg, &qhs_pcie_tcu_throttle_cfg, + &qhs_pcie_throttle_cfg, &qhs_pdm, + &qhs_pimem_cfg, &qhs_pke_wrapper_cfg, + &qhs_qdss_cfg, &qhs_qm_cfg, + &qhs_qm_mpu_cfg, &qhs_sail_throttle_cfg, + &qhs_sdc1, &qhs_security, + &qhs_snoc_throttle_cfg, &qhs_tcsr, + &qhs_tlmm, &qhs_tsc_cfg, + &qhs_ufs_mem_cfg, &qhs_usb2_0, + &qhs_usb3_0, &qhs_venus_cfg, + &qhs_venus_cvp_throttle_cfg, &qhs_venus_v_cpu_throttle_cfg, + &qhs_venus_vcodec_throttle_cfg, &qns_ddrss_cfg, + &qns_gpdsp_noc_cfg, &qns_mnoc_hf_cfg, + &qns_mnoc_sf_cfg, &qns_pcie_anoc_cfg, + &qns_snoc_cfg, &qxs_boot_imem, + &qxs_imem, &xs_sys_tcu_cfg }, +}; + +static struct qcom_icc_bcm bcm_cn2 = { + .name = "CN2", + .num_nodes = 3, + .nodes = { &qhs_qup0, &qhs_qup1, + &qhs_qup3 }, +}; + +static struct qcom_icc_bcm bcm_cn3 = { + .name = "CN3", + .num_nodes = 2, + .nodes = { &xs_pcie_0, &xs_pcie_1 }, +}; + +static struct qcom_icc_bcm bcm_gna0 = { + .name = "GNA0", + .num_nodes = 1, + .nodes = { &qxm_dsp0 }, +}; + +static struct qcom_icc_bcm bcm_mc0 = { + .name = "MC0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_mm0 = { + .name = "MM0", + .keepalive = true, + .num_nodes = 4, + .nodes = { &qnm_camnoc_hf, &qnm_mdp0_0, + &qnm_mdp0_1, &qns_mem_noc_hf }, +}; + +static struct qcom_icc_bcm bcm_mm1 = { + .name = "MM1", + .num_nodes = 6, + .nodes = { &qnm_camnoc_icp, &qnm_camnoc_sf, + &qnm_video0, &qnm_video_cvp, + &qnm_video_v_cpu, &qns_mem_noc_sf }, +}; + +static struct qcom_icc_bcm bcm_nsa0 = { + .name = "NSA0", + .num_nodes = 2, + .nodes = { &qns_hcp, &qns_nsp_gemnoc }, +}; + +static struct qcom_icc_bcm bcm_nsa1 = { + .name = "NSA1", + .num_nodes = 1, + .nodes = { &qxm_nsp }, +}; + +static struct qcom_icc_bcm bcm_pci0 = { + .name = "PCI0", + .num_nodes = 1, + .nodes = { &qns_pcie_mem_noc }, +}; + +static struct qcom_icc_bcm bcm_qup0 = { + .name = "QUP0", + .vote_scale = 1, + .keepalive = true, + .num_nodes = 1, + .nodes = { &qup0_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup1 = { + .name = "QUP1", + .vote_scale = 1, + .keepalive = true, + .num_nodes = 1, + .nodes = { &qup1_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup2 = { + .name = "QUP2", + .vote_scale = 1, + .keepalive = true, + .num_nodes = 1, + .nodes = { &qup3_core_slave }, +}; + +static struct qcom_icc_bcm bcm_sh0 = { + .name = "SH0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_llcc }, +}; + +static struct qcom_icc_bcm bcm_sh2 = { + .name = "SH2", + .num_nodes = 1, + .nodes = { &chm_apps }, +}; + +static struct qcom_icc_bcm bcm_sn0 = { + .name = "SN0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_bcm bcm_sn1 = { + .name = "SN1", + .num_nodes = 1, + .nodes = { &qns_gemnoc_gc }, +}; + +static struct qcom_icc_bcm bcm_sn2 = { + .name = "SN2", + .num_nodes = 1, + .nodes = { &qxs_pimem }, +}; + +static struct qcom_icc_bcm bcm_sn3 = { + .name = "SN3", + .num_nodes = 2, + .nodes = { &qns_a1noc_snoc, &qnm_aggre1_noc }, +}; + +static struct qcom_icc_bcm bcm_sn4 = { + .name = "SN4", + .num_nodes = 2, + .nodes = { &qns_a2noc_snoc, &qnm_aggre2_noc }, +}; + +static struct qcom_icc_bcm bcm_sn9 = { + .name = "SN9", + .num_nodes = 2, + .nodes = { &qns_sysnoc, &qnm_lpass_noc }, +}; + +static struct qcom_icc_bcm bcm_sn10 = { + .name = "SN10", + .num_nodes = 1, + .nodes = { &xs_qdss_stm }, +}; + +static struct qcom_icc_bcm * const aggre1_noc_bcms[] = { + &bcm_sn3, +}; + +static struct qcom_icc_node * const aggre1_noc_nodes[] = { + [MASTER_QUP_3] = &qxm_qup3, + [MASTER_EMAC] = &xm_emac_0, + [MASTER_SDC] = &xm_sdc1, + [MASTER_UFS_MEM] = &xm_ufs_mem, + [MASTER_USB2] = &xm_usb2_2, + [MASTER_USB3_0] = &xm_usb3_0, + [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc, +}; + +static const struct qcom_icc_desc qcs8300_aggre1_noc = { + .nodes = aggre1_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), + .bcms = aggre1_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), +}; + +static struct qcom_icc_bcm * const aggre2_noc_bcms[] = { + &bcm_ce0, + &bcm_sn4, +}; + +static struct qcom_icc_node * const aggre2_noc_nodes[] = { + [MASTER_QDSS_BAM] = &qhm_qdss_bam, + [MASTER_QUP_0] = &qhm_qup0, + [MASTER_QUP_1] = &qhm_qup1, + [MASTER_CNOC_A2NOC] = &qnm_cnoc_datapath, + [MASTER_CRYPTO_CORE0] = &qxm_crypto_0, + [MASTER_CRYPTO_CORE1] = &qxm_crypto_1, + [MASTER_IPA] = &qxm_ipa, + [MASTER_QDSS_ETR_0] = &xm_qdss_etr_0, + [MASTER_QDSS_ETR_1] = &xm_qdss_etr_1, + [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, +}; + +static const struct qcom_icc_desc qcs8300_aggre2_noc = { + .nodes = aggre2_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), + .bcms = aggre2_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre2_noc_bcms), +}; + +static struct qcom_icc_bcm * const clk_virt_bcms[] = { + &bcm_qup0, + &bcm_qup1, + &bcm_qup2, +}; + +static struct qcom_icc_node * const clk_virt_nodes[] = { + [MASTER_QUP_CORE_0] = &qup0_core_master, + [MASTER_QUP_CORE_1] = &qup1_core_master, + [MASTER_QUP_CORE_3] = &qup3_core_master, + [SLAVE_QUP_CORE_0] = &qup0_core_slave, + [SLAVE_QUP_CORE_1] = &qup1_core_slave, + [SLAVE_QUP_CORE_3] = &qup3_core_slave, +}; + +static const struct qcom_icc_desc qcs8300_clk_virt = { + .nodes = clk_virt_nodes, + .num_nodes = ARRAY_SIZE(clk_virt_nodes), + .bcms = clk_virt_bcms, + .num_bcms = ARRAY_SIZE(clk_virt_bcms), +}; + +static struct qcom_icc_bcm * const config_noc_bcms[] = { + &bcm_cn0, + &bcm_cn1, + &bcm_cn2, + &bcm_cn3, + &bcm_sn2, + &bcm_sn10, +}; + +static struct qcom_icc_node * const config_noc_nodes[] = { + [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc, + [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie, + [SLAVE_AHB2PHY_2] = &qhs_ahb2phy2, + [SLAVE_AHB2PHY_3] = &qhs_ahb2phy3, + [SLAVE_ANOC_THROTTLE_CFG] = &qhs_anoc_throttle_cfg, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_APPSS] = &qhs_apss, + [SLAVE_BOOT_ROM] = &qhs_boot_rom, + [SLAVE_CAMERA_CFG] = &qhs_camera_cfg, + [SLAVE_CAMERA_NRT_THROTTLE_CFG] = &qhs_camera_nrt_throttle_cfg, + [SLAVE_CAMERA_RT_THROTTLE_CFG] = &qhs_camera_rt_throttle_cfg, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_CDSP_CFG] = &qhs_compute0_cfg, + [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx, + [SLAVE_RBCPR_MMCX_CFG] = &qhs_cpr_mmcx, + [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx, + [SLAVE_CPR_NSPCX] = &qhs_cpr_nspcx, + [SLAVE_CPR_NSPHMX] = &qhs_cpr_nsphmx, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg, + [SLAVE_CX_RDPM] = &qhs_cx_rdpm, + [SLAVE_DISPLAY_CFG] = &qhs_display0_cfg, + [SLAVE_DISPLAY_RT_THROTTLE_CFG] = &qhs_display0_rt_throttle_cfg, + [SLAVE_EMAC_CFG] = &qhs_emac0_cfg, + [SLAVE_GP_DSP0_CFG] = &qhs_gp_dsp0_cfg, + [SLAVE_GPDSP0_THROTTLE_CFG] = &qhs_gpdsp0_throttle_cfg, + [SLAVE_GPU_TCU_THROTTLE_CFG] = &qhs_gpu_tcu_throttle_cfg, + [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg, + [SLAVE_HWKM] = &qhs_hwkm, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_IPA_CFG] = &qhs_ipa, + [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router, + [SLAVE_LPASS] = &qhs_lpass_cfg, + [SLAVE_LPASS_THROTTLE_CFG] = &qhs_lpass_throttle_cfg, + [SLAVE_MX_RDPM] = &qhs_mx_rdpm, + [SLAVE_MXC_RDPM] = &qhs_mxc_rdpm, + [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg, + [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg, + [SLAVE_PCIE_TCU_THROTTLE_CFG] = &qhs_pcie_tcu_throttle_cfg, + [SLAVE_PCIE_THROTTLE_CFG] = &qhs_pcie_throttle_cfg, + [SLAVE_PDM] = &qhs_pdm, + [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg, + [SLAVE_PKA_WRAPPER_CFG] = &qhs_pke_wrapper_cfg, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QM_CFG] = &qhs_qm_cfg, + [SLAVE_QM_MPU_CFG] = &qhs_qm_mpu_cfg, + [SLAVE_QUP_0] = &qhs_qup0, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_QUP_3] = &qhs_qup3, + [SLAVE_SAIL_THROTTLE_CFG] = &qhs_sail_throttle_cfg, + [SLAVE_SDC1] = &qhs_sdc1, + [SLAVE_SECURITY] = &qhs_security, + [SLAVE_SNOC_THROTTLE_CFG] = &qhs_snoc_throttle_cfg, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_TSC_CFG] = &qhs_tsc_cfg, + [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg, + [SLAVE_USB2] = &qhs_usb2_0, + [SLAVE_USB3_0] = &qhs_usb3_0, + [SLAVE_VENUS_CFG] = &qhs_venus_cfg, + [SLAVE_VENUS_CVP_THROTTLE_CFG] = &qhs_venus_cvp_throttle_cfg, + [SLAVE_VENUS_V_CPU_THROTTLE_CFG] = &qhs_venus_v_cpu_throttle_cfg, + [SLAVE_VENUS_VCODEC_THROTTLE_CFG] = &qhs_venus_vcodec_throttle_cfg, + [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg, + [SLAVE_GPDSP_NOC_CFG] = &qns_gpdsp_noc_cfg, + [SLAVE_CNOC_MNOC_HF_CFG] = &qns_mnoc_hf_cfg, + [SLAVE_CNOC_MNOC_SF_CFG] = &qns_mnoc_sf_cfg, + [SLAVE_PCIE_ANOC_CFG] = &qns_pcie_anoc_cfg, + [SLAVE_SNOC_CFG] = &qns_snoc_cfg, + [SLAVE_BOOT_IMEM] = &qxs_boot_imem, + [SLAVE_IMEM] = &qxs_imem, + [SLAVE_PIMEM] = &qxs_pimem, + [SLAVE_PCIE_0] = &xs_pcie_0, + [SLAVE_PCIE_1] = &xs_pcie_1, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static const struct qcom_icc_desc qcs8300_config_noc = { + .nodes = config_noc_nodes, + .num_nodes = ARRAY_SIZE(config_noc_nodes), + .bcms = config_noc_bcms, + .num_bcms = ARRAY_SIZE(config_noc_bcms), +}; + +static struct qcom_icc_node * const dc_noc_nodes[] = { + [MASTER_CNOC_DC_NOC] = &qnm_cnoc_dc_noc, + [SLAVE_LLCC_CFG] = &qhs_llcc, + [SLAVE_GEM_NOC_CFG] = &qns_gemnoc, +}; + +static const struct qcom_icc_desc qcs8300_dc_noc = { + .nodes = dc_noc_nodes, + .num_nodes = ARRAY_SIZE(dc_noc_nodes), +}; + +static struct qcom_icc_bcm * const gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh2, +}; + +static struct qcom_icc_node * const gem_noc_nodes[] = { + [MASTER_GPU_TCU] = &alm_gpu_tcu, + [MASTER_PCIE_TCU] = &alm_pcie_tcu, + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_COMPUTE_NOC] = &qnm_cmpnoc0, + [MASTER_GEM_NOC_CFG] = &qnm_gemnoc_cfg, + [MASTER_GPDSP_SAIL] = &qnm_gpdsp_sail, + [MASTER_GFX3D] = &qnm_gpu, + [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf, + [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf, + [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie, + [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_GEM_NOC_PCIE_CNOC] = &qns_pcie, + [SLAVE_SERVICE_GEM_NOC_1] = &srvc_even_gemnoc, + [SLAVE_SERVICE_GEM_NOC_2] = &srvc_odd_gemnoc, + [SLAVE_SERVICE_GEM_NOC] = &srvc_sys_gemnoc, + [SLAVE_SERVICE_GEM_NOC2] = &srvc_sys_gemnoc_2, +}; + +static const struct qcom_icc_desc qcs8300_gem_noc = { + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), +}; + +static struct qcom_icc_bcm * const gpdsp_anoc_bcms[] = { + &bcm_gna0, +}; + +static struct qcom_icc_node * const gpdsp_anoc_nodes[] = { + [MASTER_SAILSS_MD0] = &qnm_sailss_md0, + [MASTER_DSP0] = &qxm_dsp0, + [SLAVE_GP_DSP_SAIL_NOC] = &qns_gp_dsp_sail_noc, +}; + +static const struct qcom_icc_desc qcs8300_gpdsp_anoc = { + .nodes = gpdsp_anoc_nodes, + .num_nodes = ARRAY_SIZE(gpdsp_anoc_nodes), + .bcms = gpdsp_anoc_bcms, + .num_bcms = ARRAY_SIZE(gpdsp_anoc_bcms), +}; + +static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = { + &bcm_sn9, +}; + +static struct qcom_icc_node * const lpass_ag_noc_nodes[] = { + [MASTER_CNOC_LPASS_AG_NOC] = &qhm_config_noc, + [MASTER_LPASS_PROC] = &qxm_lpass_dsp, + [SLAVE_LPASS_CORE_CFG] = &qhs_lpass_core, + [SLAVE_LPASS_LPI_CFG] = &qhs_lpass_lpi, + [SLAVE_LPASS_MPU_CFG] = &qhs_lpass_mpu, + [SLAVE_LPASS_TOP_CFG] = &qhs_lpass_top, + [SLAVE_LPASS_SNOC] = &qns_sysnoc, + [SLAVE_SERVICES_LPASS_AML_NOC] = &srvc_niu_aml_noc, + [SLAVE_SERVICE_LPASS_AG_NOC] = &srvc_niu_lpass_agnoc, +}; + +static const struct qcom_icc_desc qcs8300_lpass_ag_noc = { + .nodes = lpass_ag_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), + .bcms = lpass_ag_noc_bcms, + .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms), +}; + +static struct qcom_icc_bcm * const mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, +}; + +static struct qcom_icc_node * const mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, +}; + +static const struct qcom_icc_desc qcs8300_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), +}; + +static struct qcom_icc_bcm * const mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, +}; + +static struct qcom_icc_node * const mmss_noc_nodes[] = { + [MASTER_CAMNOC_HF] = &qnm_camnoc_hf, + [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp, + [MASTER_CAMNOC_SF] = &qnm_camnoc_sf, + [MASTER_MDP0] = &qnm_mdp0_0, + [MASTER_MDP1] = &qnm_mdp0_1, + [MASTER_CNOC_MNOC_HF_CFG] = &qnm_mnoc_hf_cfg, + [MASTER_CNOC_MNOC_SF_CFG] = &qnm_mnoc_sf_cfg, + [MASTER_VIDEO_P0] = &qnm_video0, + [MASTER_VIDEO_PROC] = &qnm_video_cvp, + [MASTER_VIDEO_V_PROC] = &qnm_video_v_cpu, + [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, + [SLAVE_SERVICE_MNOC_HF] = &srvc_mnoc_hf, + [SLAVE_SERVICE_MNOC_SF] = &srvc_mnoc_sf, +}; + +static const struct qcom_icc_desc qcs8300_mmss_noc = { + .nodes = mmss_noc_nodes, + .num_nodes = ARRAY_SIZE(mmss_noc_nodes), + .bcms = mmss_noc_bcms, + .num_bcms = ARRAY_SIZE(mmss_noc_bcms), +}; + +static struct qcom_icc_bcm * const nspa_noc_bcms[] = { + &bcm_nsa0, + &bcm_nsa1, +}; + +static struct qcom_icc_node * const nspa_noc_nodes[] = { + [MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config, + [MASTER_CDSP_PROC] = &qxm_nsp, + [SLAVE_HCP_A] = &qns_hcp, + [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc, + [SLAVE_SERVICE_NSP_NOC] = &service_nsp_noc, +}; + +static const struct qcom_icc_desc qcs8300_nspa_noc = { + .nodes = nspa_noc_nodes, + .num_nodes = ARRAY_SIZE(nspa_noc_nodes), + .bcms = nspa_noc_bcms, + .num_bcms = ARRAY_SIZE(nspa_noc_bcms), +}; + +static struct qcom_icc_bcm * const pcie_anoc_bcms[] = { + &bcm_pci0, +}; + +static struct qcom_icc_node * const pcie_anoc_nodes[] = { + [MASTER_PCIE_0] = &xm_pcie3_0, + [MASTER_PCIE_1] = &xm_pcie3_1, + [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc, +}; + +static const struct qcom_icc_desc qcs8300_pcie_anoc = { + .nodes = pcie_anoc_nodes, + .num_nodes = ARRAY_SIZE(pcie_anoc_nodes), + .bcms = pcie_anoc_bcms, + .num_bcms = ARRAY_SIZE(pcie_anoc_bcms), +}; + +static struct qcom_icc_bcm * const system_noc_bcms[] = { + &bcm_sn0, + &bcm_sn1, + &bcm_sn3, + &bcm_sn4, + &bcm_sn9, +}; + +static struct qcom_icc_node * const system_noc_nodes[] = { + [MASTER_GIC_AHB] = &qhm_gic, + [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc, + [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc, + [MASTER_LPASS_ANOC] = &qnm_lpass_noc, + [MASTER_SNOC_CFG] = &qnm_snoc_cfg, + [MASTER_PIMEM] = &qxm_pimem, + [MASTER_GIC] = &xm_gic, + [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, + [SLAVE_SERVICE_SNOC] = &srvc_snoc, +}; + +static const struct qcom_icc_desc qcs8300_system_noc = { + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), +}; + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,qcs8300-aggre1-noc", + .data = &qcs8300_aggre1_noc}, + { .compatible = "qcom,qcs8300-aggre2-noc", + .data = &qcs8300_aggre2_noc}, + { .compatible = "qcom,qcs8300-clk-virt", + .data = &qcs8300_clk_virt}, + { .compatible = "qcom,qcs8300-config-noc", + .data = &qcs8300_config_noc}, + { .compatible = "qcom,qcs8300-dc-noc", + .data = &qcs8300_dc_noc}, + { .compatible = "qcom,qcs8300-gem-noc", + .data = &qcs8300_gem_noc}, + { .compatible = "qcom,qcs8300-gpdsp-anoc", + .data = &qcs8300_gpdsp_anoc}, + { .compatible = "qcom,qcs8300-lpass-ag-noc", + .data = &qcs8300_lpass_ag_noc}, + { .compatible = "qcom,qcs8300-mc-virt", + .data = &qcs8300_mc_virt}, + { .compatible = "qcom,qcs8300-mmss-noc", + .data = &qcs8300_mmss_noc}, + { .compatible = "qcom,qcs8300-nspa-noc", + .data = &qcs8300_nspa_noc}, + { .compatible = "qcom,qcs8300-pcie-anoc", + .data = &qcs8300_pcie_anoc}, + { .compatible = "qcom,qcs8300-system-noc", + .data = &qcs8300_system_noc}, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, + .driver = { + .name = "qnoc-qcs8300", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; + +static int __init qnoc_driver_init(void) +{ + return platform_driver_register(&qnoc_driver); +} +core_initcall(qnoc_driver_init); + +static void __exit qnoc_driver_exit(void) +{ + platform_driver_unregister(&qnoc_driver); +} +module_exit(qnoc_driver_exit); + +MODULE_DESCRIPTION("QCS8300 NoC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/qcom/qcs8300.h b/drivers/interconnect/qcom/qcs8300.h new file mode 100644 index 00000000000000..6b9e2b424c2ad0 --- /dev/null +++ b/drivers/interconnect/qcom/qcs8300.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_QCS8300_H +#define __DRIVERS_INTERCONNECT_QCOM_QCS8300_H + +#define QCS8300_MASTER_GPU_TCU 0 +#define QCS8300_MASTER_PCIE_TCU 1 +#define QCS8300_MASTER_SYS_TCU 2 +#define QCS8300_MASTER_APPSS_PROC 3 +#define QCS8300_MASTER_LLCC 4 +#define QCS8300_MASTER_CNOC_LPASS_AG_NOC 5 +#define QCS8300_MASTER_GIC_AHB 6 +#define QCS8300_MASTER_CDSP_NOC_CFG 7 +#define QCS8300_MASTER_QDSS_BAM 8 +#define QCS8300_MASTER_QUP_0 9 +#define QCS8300_MASTER_QUP_1 10 +#define QCS8300_MASTER_A1NOC_SNOC 11 +#define QCS8300_MASTER_A2NOC_SNOC 12 +#define QCS8300_MASTER_CAMNOC_HF 13 +#define QCS8300_MASTER_CAMNOC_ICP 14 +#define QCS8300_MASTER_CAMNOC_SF 15 +#define QCS8300_MASTER_COMPUTE_NOC 16 +#define QCS8300_MASTER_CNOC_A2NOC 17 +#define QCS8300_MASTER_CNOC_DC_NOC 18 +#define QCS8300_MASTER_GEM_NOC_CFG 19 +#define QCS8300_MASTER_GEM_NOC_CNOC 20 +#define QCS8300_MASTER_GEM_NOC_PCIE_SNOC 21 +#define QCS8300_MASTER_GPDSP_SAIL 22 +#define QCS8300_MASTER_GFX3D 23 +#define QCS8300_MASTER_LPASS_ANOC 24 +#define QCS8300_MASTER_MDP0 25 +#define QCS8300_MASTER_MDP1 26 +#define QCS8300_MASTER_MNOC_HF_MEM_NOC 27 +#define QCS8300_MASTER_CNOC_MNOC_HF_CFG 28 +#define QCS8300_MASTER_MNOC_SF_MEM_NOC 29 +#define QCS8300_MASTER_CNOC_MNOC_SF_CFG 30 +#define QCS8300_MASTER_ANOC_PCIE_GEM_NOC 31 +#define QCS8300_MASTER_SAILSS_MD0 32 +#define QCS8300_MASTER_SNOC_CFG 33 +#define QCS8300_MASTER_SNOC_GC_MEM_NOC 34 +#define QCS8300_MASTER_SNOC_SF_MEM_NOC 35 +#define QCS8300_MASTER_VIDEO_P0 36 +#define QCS8300_MASTER_VIDEO_PROC 37 +#define QCS8300_MASTER_VIDEO_V_PROC 38 +#define QCS8300_MASTER_QUP_CORE_0 39 +#define QCS8300_MASTER_QUP_CORE_1 40 +#define QCS8300_MASTER_QUP_CORE_3 41 +#define QCS8300_MASTER_CRYPTO_CORE0 42 +#define QCS8300_MASTER_CRYPTO_CORE1 43 +#define QCS8300_MASTER_DSP0 44 +#define QCS8300_MASTER_IPA 45 +#define QCS8300_MASTER_LPASS_PROC 46 +#define QCS8300_MASTER_CDSP_PROC 47 +#define QCS8300_MASTER_PIMEM 48 +#define QCS8300_MASTER_QUP_3 49 +#define QCS8300_MASTER_EMAC 50 +#define QCS8300_MASTER_GIC 51 +#define QCS8300_MASTER_PCIE_0 52 +#define QCS8300_MASTER_PCIE_1 53 +#define QCS8300_MASTER_QDSS_ETR_0 54 +#define QCS8300_MASTER_QDSS_ETR_1 55 +#define QCS8300_MASTER_SDC 56 +#define QCS8300_MASTER_UFS_MEM 57 +#define QCS8300_MASTER_USB2 58 +#define QCS8300_MASTER_USB3_0 59 +#define QCS8300_SLAVE_EBI1 60 +#define QCS8300_SLAVE_AHB2PHY_2 61 +#define QCS8300_SLAVE_AHB2PHY_3 62 +#define QCS8300_SLAVE_ANOC_THROTTLE_CFG 63 +#define QCS8300_SLAVE_AOSS 64 +#define QCS8300_SLAVE_APPSS 65 +#define QCS8300_SLAVE_BOOT_ROM 66 +#define QCS8300_SLAVE_CAMERA_CFG 67 +#define QCS8300_SLAVE_CAMERA_NRT_THROTTLE_CFG 68 +#define QCS8300_SLAVE_CAMERA_RT_THROTTLE_CFG 69 +#define QCS8300_SLAVE_CLK_CTL 70 +#define QCS8300_SLAVE_CDSP_CFG 71 +#define QCS8300_SLAVE_RBCPR_CX_CFG 72 +#define QCS8300_SLAVE_RBCPR_MMCX_CFG 73 +#define QCS8300_SLAVE_RBCPR_MX_CFG 74 +#define QCS8300_SLAVE_CPR_NSPCX 75 +#define QCS8300_SLAVE_CPR_NSPHMX 76 +#define QCS8300_SLAVE_CRYPTO_0_CFG 77 +#define QCS8300_SLAVE_CX_RDPM 78 +#define QCS8300_SLAVE_DISPLAY_CFG 79 +#define QCS8300_SLAVE_DISPLAY_RT_THROTTLE_CFG 80 +#define QCS8300_SLAVE_EMAC_CFG 81 +#define QCS8300_SLAVE_GP_DSP0_CFG 82 +#define QCS8300_SLAVE_GPDSP0_THROTTLE_CFG 83 +#define QCS8300_SLAVE_GPU_TCU_THROTTLE_CFG 84 +#define QCS8300_SLAVE_GFX3D_CFG 85 +#define QCS8300_SLAVE_HWKM 86 +#define QCS8300_SLAVE_IMEM_CFG 87 +#define QCS8300_SLAVE_IPA_CFG 88 +#define QCS8300_SLAVE_IPC_ROUTER_CFG 89 +#define QCS8300_SLAVE_LLCC_CFG 90 +#define QCS8300_SLAVE_LPASS 91 +#define QCS8300_SLAVE_LPASS_CORE_CFG 92 +#define QCS8300_SLAVE_LPASS_LPI_CFG 93 +#define QCS8300_SLAVE_LPASS_MPU_CFG 94 +#define QCS8300_SLAVE_LPASS_THROTTLE_CFG 95 +#define QCS8300_SLAVE_LPASS_TOP_CFG 96 +#define QCS8300_SLAVE_MX_RDPM 97 +#define QCS8300_SLAVE_MXC_RDPM 98 +#define QCS8300_SLAVE_PCIE_0_CFG 99 +#define QCS8300_SLAVE_PCIE_1_CFG 100 +#define QCS8300_SLAVE_PCIE_TCU_THROTTLE_CFG 101 +#define QCS8300_SLAVE_PCIE_THROTTLE_CFG 102 +#define QCS8300_SLAVE_PDM 103 +#define QCS8300_SLAVE_PIMEM_CFG 104 +#define QCS8300_SLAVE_PKA_WRAPPER_CFG 105 +#define QCS8300_SLAVE_QDSS_CFG 106 +#define QCS8300_SLAVE_QM_CFG 107 +#define QCS8300_SLAVE_QM_MPU_CFG 108 +#define QCS8300_SLAVE_QUP_0 109 +#define QCS8300_SLAVE_QUP_1 110 +#define QCS8300_SLAVE_QUP_3 111 +#define QCS8300_SLAVE_SAIL_THROTTLE_CFG 112 +#define QCS8300_SLAVE_SDC1 113 +#define QCS8300_SLAVE_SECURITY 114 +#define QCS8300_SLAVE_SNOC_THROTTLE_CFG 115 +#define QCS8300_SLAVE_TCSR 116 +#define QCS8300_SLAVE_TLMM 117 +#define QCS8300_SLAVE_TSC_CFG 118 +#define QCS8300_SLAVE_UFS_MEM_CFG 119 +#define QCS8300_SLAVE_USB2 120 +#define QCS8300_SLAVE_USB3_0 121 +#define QCS8300_SLAVE_VENUS_CFG 122 +#define QCS8300_SLAVE_VENUS_CVP_THROTTLE_CFG 123 +#define QCS8300_SLAVE_VENUS_V_CPU_THROTTLE_CFG 124 +#define QCS8300_SLAVE_VENUS_VCODEC_THROTTLE_CFG 125 +#define QCS8300_SLAVE_A1NOC_SNOC 126 +#define QCS8300_SLAVE_A2NOC_SNOC 127 +#define QCS8300_SLAVE_DDRSS_CFG 128 +#define QCS8300_SLAVE_GEM_NOC_CNOC 129 +#define QCS8300_SLAVE_GEM_NOC_CFG 130 +#define QCS8300_SLAVE_SNOC_GEM_NOC_GC 131 +#define QCS8300_SLAVE_SNOC_GEM_NOC_SF 132 +#define QCS8300_SLAVE_GP_DSP_SAIL_NOC 133 +#define QCS8300_SLAVE_GPDSP_NOC_CFG 134 +#define QCS8300_SLAVE_HCP_A 135 +#define QCS8300_SLAVE_LLCC 136 +#define QCS8300_SLAVE_MNOC_HF_MEM_NOC 137 +#define QCS8300_SLAVE_MNOC_SF_MEM_NOC 138 +#define QCS8300_SLAVE_CNOC_MNOC_HF_CFG 139 +#define QCS8300_SLAVE_CNOC_MNOC_SF_CFG 140 +#define QCS8300_SLAVE_CDSP_MEM_NOC 141 +#define QCS8300_SLAVE_GEM_NOC_PCIE_CNOC 142 +#define QCS8300_SLAVE_PCIE_ANOC_CFG 143 +#define QCS8300_SLAVE_ANOC_PCIE_GEM_NOC 144 +#define QCS8300_SLAVE_SNOC_CFG 145 +#define QCS8300_SLAVE_LPASS_SNOC 146 +#define QCS8300_SLAVE_QUP_CORE_0 147 +#define QCS8300_SLAVE_QUP_CORE_1 148 +#define QCS8300_SLAVE_QUP_CORE_3 149 +#define QCS8300_SLAVE_BOOT_IMEM 150 +#define QCS8300_SLAVE_IMEM 151 +#define QCS8300_SLAVE_PIMEM 152 +#define QCS8300_SLAVE_SERVICE_NSP_NOC 153 +#define QCS8300_SLAVE_SERVICE_GEM_NOC_1 154 +#define QCS8300_SLAVE_SERVICE_MNOC_HF 155 +#define QCS8300_SLAVE_SERVICE_MNOC_SF 156 +#define QCS8300_SLAVE_SERVICES_LPASS_AML_NOC 157 +#define QCS8300_SLAVE_SERVICE_LPASS_AG_NOC 158 +#define QCS8300_SLAVE_SERVICE_GEM_NOC_2 159 +#define QCS8300_SLAVE_SERVICE_SNOC 160 +#define QCS8300_SLAVE_SERVICE_GEM_NOC 161 +#define QCS8300_SLAVE_SERVICE_GEM_NOC2 162 +#define QCS8300_SLAVE_PCIE_0 163 +#define QCS8300_SLAVE_PCIE_1 164 +#define QCS8300_SLAVE_QDSS_STM 165 +#define QCS8300_SLAVE_TCU 166 + +#endif diff --git a/drivers/interconnect/qcom/qdu1000.c b/drivers/interconnect/qcom/qdu1000.c index 9cb477d2bdfe2b..a7392eb73d4a99 100644 --- a/drivers/interconnect/qcom/qdu1000.c +++ b/drivers/interconnect/qcom/qdu1000.c @@ -1046,7 +1046,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qnoc_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-qdu1000", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c index a729775c2aa45e..e2826af3ea2e1e 100644 --- a/drivers/interconnect/qcom/sa8775p.c +++ b/drivers/interconnect/qcom/sa8775p.c @@ -2519,7 +2519,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sa8775p", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sar2130p.c b/drivers/interconnect/qcom/sar2130p.c new file mode 100644 index 00000000000000..9eac0ac7681273 --- /dev/null +++ b/drivers/interconnect/qcom/sar2130p.c @@ -0,0 +1,1930 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2024, Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bcm-voter.h" +#include "icc-common.h" +#include "icc-rpmh.h" + +enum { + SAR2130P_MASTER_QUP_CORE_0, + SAR2130P_MASTER_QUP_CORE_1, + SAR2130P_MASTER_GEM_NOC_CNOC, + SAR2130P_MASTER_GEM_NOC_PCIE_SNOC, + SAR2130P_MASTER_QDSS_DAP, + SAR2130P_MASTER_GPU_TCU, + SAR2130P_MASTER_SYS_TCU, + SAR2130P_MASTER_APPSS_PROC, + SAR2130P_MASTER_GFX3D, + SAR2130P_MASTER_MNOC_HF_MEM_NOC, + SAR2130P_MASTER_MNOC_SF_MEM_NOC, + SAR2130P_MASTER_COMPUTE_NOC, + SAR2130P_MASTER_ANOC_PCIE_GEM_NOC, + SAR2130P_MASTER_SNOC_GC_MEM_NOC, + SAR2130P_MASTER_SNOC_SF_MEM_NOC, + SAR2130P_MASTER_WLAN_Q6, + SAR2130P_MASTER_CNOC_LPASS_AG_NOC, + SAR2130P_MASTER_LPASS_PROC, + SAR2130P_MASTER_LLCC, + SAR2130P_MASTER_CAMNOC_HF, + SAR2130P_MASTER_CAMNOC_ICP, + SAR2130P_MASTER_CAMNOC_SF, + SAR2130P_MASTER_LSR, + SAR2130P_MASTER_MDP, + SAR2130P_MASTER_CNOC_MNOC_CFG, + SAR2130P_MASTER_VIDEO, + SAR2130P_MASTER_VIDEO_CV_PROC, + SAR2130P_MASTER_VIDEO_PROC, + SAR2130P_MASTER_VIDEO_V_PROC, + SAR2130P_MASTER_CDSP_NOC_CFG, + SAR2130P_MASTER_CDSP_PROC, + SAR2130P_MASTER_PCIE_0, + SAR2130P_MASTER_PCIE_1, + SAR2130P_MASTER_GIC_AHB, + SAR2130P_MASTER_QDSS_BAM, + SAR2130P_MASTER_QSPI_0, + SAR2130P_MASTER_QUP_0, + SAR2130P_MASTER_QUP_1, + SAR2130P_MASTER_A2NOC_SNOC, + SAR2130P_MASTER_CNOC_DATAPATH, + SAR2130P_MASTER_LPASS_ANOC, + SAR2130P_MASTER_SNOC_CFG, + SAR2130P_MASTER_CRYPTO, + SAR2130P_MASTER_PIMEM, + SAR2130P_MASTER_GIC, + SAR2130P_MASTER_QDSS_ETR, + SAR2130P_MASTER_QDSS_ETR_1, + SAR2130P_MASTER_SDCC_1, + SAR2130P_MASTER_USB3_0, + SAR2130P_SLAVE_QUP_CORE_0, + SAR2130P_SLAVE_QUP_CORE_1, + SAR2130P_SLAVE_AHB2PHY_SOUTH, + SAR2130P_SLAVE_AOSS, + SAR2130P_SLAVE_CAMERA_CFG, + SAR2130P_SLAVE_CLK_CTL, + SAR2130P_SLAVE_CDSP_CFG, + SAR2130P_SLAVE_RBCPR_CX_CFG, + SAR2130P_SLAVE_RBCPR_MMCX_CFG, + SAR2130P_SLAVE_RBCPR_MXA_CFG, + SAR2130P_SLAVE_RBCPR_MXC_CFG, + SAR2130P_SLAVE_CPR_NSPCX, + SAR2130P_SLAVE_CRYPTO_0_CFG, + SAR2130P_SLAVE_CX_RDPM, + SAR2130P_SLAVE_DISPLAY_CFG, + SAR2130P_SLAVE_GFX3D_CFG, + SAR2130P_SLAVE_IMEM_CFG, + SAR2130P_SLAVE_IPC_ROUTER_CFG, + SAR2130P_SLAVE_LPASS, + SAR2130P_SLAVE_MX_RDPM, + SAR2130P_SLAVE_PCIE_0_CFG, + SAR2130P_SLAVE_PCIE_1_CFG, + SAR2130P_SLAVE_PDM, + SAR2130P_SLAVE_PIMEM_CFG, + SAR2130P_SLAVE_PRNG, + SAR2130P_SLAVE_QDSS_CFG, + SAR2130P_SLAVE_QSPI_0, + SAR2130P_SLAVE_QUP_0, + SAR2130P_SLAVE_QUP_1, + SAR2130P_SLAVE_SDCC_1, + SAR2130P_SLAVE_TCSR, + SAR2130P_SLAVE_TLMM, + SAR2130P_SLAVE_TME_CFG, + SAR2130P_SLAVE_USB3_0, + SAR2130P_SLAVE_VENUS_CFG, + SAR2130P_SLAVE_VSENSE_CTRL_CFG, + SAR2130P_SLAVE_WLAN_Q6_CFG, + SAR2130P_SLAVE_DDRSS_CFG, + SAR2130P_SLAVE_CNOC_MNOC_CFG, + SAR2130P_SLAVE_SNOC_CFG, + SAR2130P_SLAVE_IMEM, + SAR2130P_SLAVE_PIMEM, + SAR2130P_SLAVE_SERVICE_CNOC, + SAR2130P_SLAVE_PCIE_0, + SAR2130P_SLAVE_PCIE_1, + SAR2130P_SLAVE_QDSS_STM, + SAR2130P_SLAVE_TCU, + SAR2130P_SLAVE_GEM_NOC_CNOC, + SAR2130P_SLAVE_LLCC, + SAR2130P_SLAVE_MEM_NOC_PCIE_SNOC, + SAR2130P_SLAVE_LPASS_CORE_CFG, + SAR2130P_SLAVE_LPASS_LPI_CFG, + SAR2130P_SLAVE_LPASS_MPU_CFG, + SAR2130P_SLAVE_LPASS_TOP_CFG, + SAR2130P_SLAVE_LPASS_SNOC, + SAR2130P_SLAVE_SERVICES_LPASS_AML_NOC, + SAR2130P_SLAVE_SERVICE_LPASS_AG_NOC, + SAR2130P_SLAVE_EBI1, + SAR2130P_SLAVE_MNOC_HF_MEM_NOC, + SAR2130P_SLAVE_MNOC_SF_MEM_NOC, + SAR2130P_SLAVE_SERVICE_MNOC, + SAR2130P_SLAVE_CDSP_MEM_NOC, + SAR2130P_SLAVE_SERVICE_NSP_NOC, + SAR2130P_SLAVE_ANOC_PCIE_GEM_NOC, + SAR2130P_SLAVE_A2NOC_SNOC, + SAR2130P_SLAVE_SNOC_GEM_NOC_GC, + SAR2130P_SLAVE_SNOC_GEM_NOC_SF, + SAR2130P_SLAVE_SERVICE_SNOC, +}; + +static const struct regmap_config icc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, +}; + +static struct qcom_icc_node qup0_core_master = { + .name = "qup0_core_master", + .id = SAR2130P_MASTER_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_SLAVE_QUP_CORE_0 }, +}; + +static struct qcom_icc_node qup1_core_master = { + .name = "qup1_core_master", + .id = SAR2130P_MASTER_QUP_CORE_1, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_SLAVE_QUP_CORE_1 }, +}; + +static struct qcom_icc_node qnm_gemnoc_cnoc = { + .name = "qnm_gemnoc_cnoc", + .id = SAR2130P_MASTER_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 43, + .links = { SAR2130P_SLAVE_AHB2PHY_SOUTH, SAR2130P_SLAVE_AOSS, + SAR2130P_SLAVE_CAMERA_CFG, SAR2130P_SLAVE_CLK_CTL, + SAR2130P_SLAVE_CDSP_CFG, SAR2130P_SLAVE_RBCPR_CX_CFG, + SAR2130P_SLAVE_RBCPR_MMCX_CFG, SAR2130P_SLAVE_RBCPR_MXA_CFG, + SAR2130P_SLAVE_RBCPR_MXC_CFG, SAR2130P_SLAVE_CPR_NSPCX, + SAR2130P_SLAVE_CRYPTO_0_CFG, SAR2130P_SLAVE_CX_RDPM, + SAR2130P_SLAVE_DISPLAY_CFG, SAR2130P_SLAVE_GFX3D_CFG, + SAR2130P_SLAVE_IMEM_CFG, SAR2130P_SLAVE_IPC_ROUTER_CFG, + SAR2130P_SLAVE_LPASS, SAR2130P_SLAVE_MX_RDPM, + SAR2130P_SLAVE_PCIE_0_CFG, SAR2130P_SLAVE_PCIE_1_CFG, + SAR2130P_SLAVE_PDM, SAR2130P_SLAVE_PIMEM_CFG, + SAR2130P_SLAVE_PRNG, SAR2130P_SLAVE_QDSS_CFG, + SAR2130P_SLAVE_QSPI_0, SAR2130P_SLAVE_QUP_0, + SAR2130P_SLAVE_QUP_1, SAR2130P_SLAVE_SDCC_1, + SAR2130P_SLAVE_TCSR, SAR2130P_SLAVE_TLMM, + SAR2130P_SLAVE_TME_CFG, SAR2130P_SLAVE_USB3_0, + SAR2130P_SLAVE_VENUS_CFG, SAR2130P_SLAVE_VSENSE_CTRL_CFG, + SAR2130P_SLAVE_WLAN_Q6_CFG, SAR2130P_SLAVE_DDRSS_CFG, + SAR2130P_SLAVE_CNOC_MNOC_CFG, SAR2130P_SLAVE_SNOC_CFG, + SAR2130P_SLAVE_IMEM, SAR2130P_SLAVE_PIMEM, + SAR2130P_SLAVE_SERVICE_CNOC, SAR2130P_SLAVE_QDSS_STM, + SAR2130P_SLAVE_TCU }, +}; + +static struct qcom_icc_node qnm_gemnoc_pcie = { + .name = "qnm_gemnoc_pcie", + .id = SAR2130P_MASTER_GEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 2, + .links = { SAR2130P_SLAVE_PCIE_0, SAR2130P_SLAVE_PCIE_1 }, +}; + +static struct qcom_icc_node xm_qdss_dap = { + .name = "xm_qdss_dap", + .id = SAR2130P_MASTER_QDSS_DAP, + .channels = 1, + .buswidth = 8, + .num_links = 43, + .links = { SAR2130P_SLAVE_AHB2PHY_SOUTH, SAR2130P_SLAVE_AOSS, + SAR2130P_SLAVE_CAMERA_CFG, SAR2130P_SLAVE_CLK_CTL, + SAR2130P_SLAVE_CDSP_CFG, SAR2130P_SLAVE_RBCPR_CX_CFG, + SAR2130P_SLAVE_RBCPR_MMCX_CFG, SAR2130P_SLAVE_RBCPR_MXA_CFG, + SAR2130P_SLAVE_RBCPR_MXC_CFG, SAR2130P_SLAVE_CPR_NSPCX, + SAR2130P_SLAVE_CRYPTO_0_CFG, SAR2130P_SLAVE_CX_RDPM, + SAR2130P_SLAVE_DISPLAY_CFG, SAR2130P_SLAVE_GFX3D_CFG, + SAR2130P_SLAVE_IMEM_CFG, SAR2130P_SLAVE_IPC_ROUTER_CFG, + SAR2130P_SLAVE_LPASS, SAR2130P_SLAVE_MX_RDPM, + SAR2130P_SLAVE_PCIE_0_CFG, SAR2130P_SLAVE_PCIE_1_CFG, + SAR2130P_SLAVE_PDM, SAR2130P_SLAVE_PIMEM_CFG, + SAR2130P_SLAVE_PRNG, SAR2130P_SLAVE_QDSS_CFG, + SAR2130P_SLAVE_QSPI_0, SAR2130P_SLAVE_QUP_0, + SAR2130P_SLAVE_QUP_1, SAR2130P_SLAVE_SDCC_1, + SAR2130P_SLAVE_TCSR, SAR2130P_SLAVE_TLMM, + SAR2130P_SLAVE_TME_CFG, SAR2130P_SLAVE_USB3_0, + SAR2130P_SLAVE_VENUS_CFG, SAR2130P_SLAVE_VSENSE_CTRL_CFG, + SAR2130P_SLAVE_WLAN_Q6_CFG, SAR2130P_SLAVE_DDRSS_CFG, + SAR2130P_SLAVE_CNOC_MNOC_CFG, SAR2130P_SLAVE_SNOC_CFG, + SAR2130P_SLAVE_IMEM, SAR2130P_SLAVE_PIMEM, + SAR2130P_SLAVE_SERVICE_CNOC, SAR2130P_SLAVE_QDSS_STM, + SAR2130P_SLAVE_TCU }, +}; + +static const struct qcom_icc_qosbox alm_gpu_tcu_qos = { + .num_ports = 1, + .port_offsets = { 0x9e000 }, + .prio = 1, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node alm_gpu_tcu = { + .name = "alm_gpu_tcu", + .id = SAR2130P_MASTER_GPU_TCU, + .channels = 1, + .buswidth = 8, + .qosbox = &alm_gpu_tcu_qos, + .num_links = 2, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC }, +}; + +static const struct qcom_icc_qosbox alm_sys_tcu_qos = { + .num_ports = 1, + .port_offsets = { 0x9f000 }, + .prio = 6, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node alm_sys_tcu = { + .name = "alm_sys_tcu", + .id = SAR2130P_MASTER_SYS_TCU, + .channels = 1, + .buswidth = 8, + .qosbox = &alm_sys_tcu_qos, + .num_links = 2, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC }, +}; + +static struct qcom_icc_node chm_apps = { + .name = "chm_apps", + .id = SAR2130P_MASTER_APPSS_PROC, + .channels = 1, + .buswidth = 32, + .num_links = 3, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC, + SAR2130P_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static const struct qcom_icc_qosbox qnm_gpu_qos = { + .num_ports = 2, + .port_offsets = { 0xe000, 0x4e000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qnm_gpu = { + .name = "qnm_gpu", + .id = SAR2130P_MASTER_GFX3D, + .channels = 2, + .buswidth = 32, + .qosbox = &qnm_gpu_qos, + .num_links = 2, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC }, +}; + +static const struct qcom_icc_qosbox qnm_mnoc_hf_qos = { + .num_ports = 2, + .port_offsets = { 0xf000, 0x4f000 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_mnoc_hf = { + .name = "qnm_mnoc_hf", + .id = SAR2130P_MASTER_MNOC_HF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .qosbox = &qnm_mnoc_hf_qos, + .num_links = 2, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC }, +}; + +static const struct qcom_icc_qosbox qnm_mnoc_sf_qos = { + .num_ports = 1, + .port_offsets = { 0x9d000 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_mnoc_sf = { + .name = "qnm_mnoc_sf", + .id = SAR2130P_MASTER_MNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 32, + .qosbox = &qnm_mnoc_sf_qos, + .num_links = 2, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC }, +}; + +static const struct qcom_icc_qosbox qnm_nsp_gemnoc_qos = { + .num_ports = 2, + .port_offsets = { 0x10000, 0x50000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qnm_nsp_gemnoc = { + .name = "qnm_nsp_gemnoc", + .id = SAR2130P_MASTER_COMPUTE_NOC, + .channels = 2, + .buswidth = 32, + .qosbox = &qnm_nsp_gemnoc_qos, + .num_links = 2, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC }, +}; + +static const struct qcom_icc_qosbox qnm_pcie_qos = { + .num_ports = 1, + .port_offsets = { 0xa2000 }, + .prio = 2, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_pcie = { + .name = "qnm_pcie", + .id = SAR2130P_MASTER_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 16, + .qosbox = &qnm_pcie_qos, + .num_links = 2, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC }, +}; + +static const struct qcom_icc_qosbox qnm_snoc_gc_qos = { + .num_ports = 1, + .port_offsets = { 0xa0000 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_snoc_gc = { + .name = "qnm_snoc_gc", + .id = SAR2130P_MASTER_SNOC_GC_MEM_NOC, + .channels = 1, + .buswidth = 8, + .qosbox = &qnm_snoc_gc_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_LLCC }, +}; + +static const struct qcom_icc_qosbox qnm_snoc_sf_qos = { + .num_ports = 1, + .port_offsets = { 0xa1000 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_snoc_sf = { + .name = "qnm_snoc_sf", + .id = SAR2130P_MASTER_SNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 16, + .qosbox = &qnm_snoc_sf_qos, + .num_links = 3, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC, + SAR2130P_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qxm_wlan_q6 = { + .name = "qxm_wlan_q6", + .id = SAR2130P_MASTER_WLAN_Q6, + .channels = 1, + .buswidth = 8, + .num_links = 3, + .links = { SAR2130P_SLAVE_GEM_NOC_CNOC, SAR2130P_SLAVE_LLCC, + SAR2130P_SLAVE_MEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qhm_config_noc = { + .name = "qhm_config_noc", + .id = SAR2130P_MASTER_CNOC_LPASS_AG_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 6, + .links = { SAR2130P_SLAVE_LPASS_CORE_CFG, SAR2130P_SLAVE_LPASS_LPI_CFG, + SAR2130P_SLAVE_LPASS_MPU_CFG, SAR2130P_SLAVE_LPASS_TOP_CFG, + SAR2130P_SLAVE_SERVICES_LPASS_AML_NOC, SAR2130P_SLAVE_SERVICE_LPASS_AG_NOC }, +}; + +static struct qcom_icc_node qxm_lpass_dsp = { + .name = "qxm_lpass_dsp", + .id = SAR2130P_MASTER_LPASS_PROC, + .channels = 1, + .buswidth = 8, + .num_links = 4, + .links = { SAR2130P_SLAVE_LPASS_TOP_CFG, SAR2130P_SLAVE_LPASS_SNOC, + SAR2130P_SLAVE_SERVICES_LPASS_AML_NOC, SAR2130P_SLAVE_SERVICE_LPASS_AG_NOC }, +}; + +static struct qcom_icc_node llcc_mc = { + .name = "llcc_mc", + .id = SAR2130P_MASTER_LLCC, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_SLAVE_EBI1 }, +}; + +static const struct qcom_icc_qosbox qnm_camnoc_hf_qos = { + .num_ports = 1, + .port_offsets = { 0x1c000 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_camnoc_hf = { + .name = "qnm_camnoc_hf", + .id = SAR2130P_MASTER_CAMNOC_HF, + .channels = 1, + .buswidth = 32, + .qosbox = &qnm_camnoc_hf_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static const struct qcom_icc_qosbox qnm_camnoc_icp_qos = { + .num_ports = 1, + .port_offsets = { 0x1c080 }, + .prio = 4, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_camnoc_icp = { + .name = "qnm_camnoc_icp", + .id = SAR2130P_MASTER_CAMNOC_ICP, + .channels = 1, + .buswidth = 8, + .qosbox = &qnm_camnoc_icp_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static const struct qcom_icc_qosbox qnm_camnoc_sf_qos = { + .num_ports = 1, + .port_offsets = { 0x1c100 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_camnoc_sf = { + .name = "qnm_camnoc_sf", + .id = SAR2130P_MASTER_CAMNOC_SF, + .channels = 1, + .buswidth = 32, + .qosbox = &qnm_camnoc_sf_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static const struct qcom_icc_qosbox qnm_lsr_qos = { + .num_ports = 2, + .port_offsets = { 0x1f000, 0x1f080 }, + .prio = 3, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_lsr = { + .name = "qnm_lsr", + .id = SAR2130P_MASTER_LSR, + .channels = 2, + .buswidth = 32, + .qosbox = &qnm_lsr_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static const struct qcom_icc_qosbox qnm_mdp_qos = { + .num_ports = 2, + .port_offsets = { 0x1d000, 0x1d080 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_mdp = { + .name = "qnm_mdp", + .id = SAR2130P_MASTER_MDP, + .channels = 2, + .buswidth = 32, + .qosbox = &qnm_mdp_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qnm_mnoc_cfg = { + .name = "qnm_mnoc_cfg", + .id = SAR2130P_MASTER_CNOC_MNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_SLAVE_SERVICE_MNOC }, +}; + +static const struct qcom_icc_qosbox qnm_video_qos = { + .num_ports = 2, + .port_offsets = { 0x1e000, 0x1e080 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_video = { + .name = "qnm_video", + .id = SAR2130P_MASTER_VIDEO, + .channels = 2, + .buswidth = 32, + .qosbox = &qnm_video_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static const struct qcom_icc_qosbox qnm_video_cv_cpu_qos = { + .num_ports = 1, + .port_offsets = { 0x1e100 }, + .prio = 4, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_video_cv_cpu = { + .name = "qnm_video_cv_cpu", + .id = SAR2130P_MASTER_VIDEO_CV_PROC, + .channels = 1, + .buswidth = 8, + .qosbox = &qnm_video_cv_cpu_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static const struct qcom_icc_qosbox qnm_video_cvp_qos = { + .num_ports = 1, + .port_offsets = { 0x1e180 }, + .prio = 0, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_video_cvp = { + .name = "qnm_video_cvp", + .id = SAR2130P_MASTER_VIDEO_PROC, + .channels = 1, + .buswidth = 32, + .qosbox = &qnm_video_cvp_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static const struct qcom_icc_qosbox qnm_video_v_cpu_qos = { + .num_ports = 1, + .port_offsets = { 0x1e200 }, + .prio = 4, + .urg_fwd = 1, +}; + +static struct qcom_icc_node qnm_video_v_cpu = { + .name = "qnm_video_v_cpu", + .id = SAR2130P_MASTER_VIDEO_V_PROC, + .channels = 1, + .buswidth = 8, + .qosbox = &qnm_video_v_cpu_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node qhm_nsp_noc_config = { + .name = "qhm_nsp_noc_config", + .id = SAR2130P_MASTER_CDSP_NOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_SLAVE_SERVICE_NSP_NOC }, +}; + +static struct qcom_icc_node qxm_nsp = { + .name = "qxm_nsp", + .id = SAR2130P_MASTER_CDSP_PROC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SAR2130P_SLAVE_CDSP_MEM_NOC }, +}; + +static const struct qcom_icc_qosbox xm_pcie3_0_qos = { + .num_ports = 1, + .port_offsets = { 0x9000 }, + .prio = 3, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node xm_pcie3_0 = { + .name = "xm_pcie3_0", + .id = SAR2130P_MASTER_PCIE_0, + .channels = 1, + .buswidth = 8, + .qosbox = &xm_pcie3_0_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static const struct qcom_icc_qosbox xm_pcie3_1_qos = { + .num_ports = 1, + .port_offsets = { 0xa000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node xm_pcie3_1 = { + .name = "xm_pcie3_1", + .id = SAR2130P_MASTER_PCIE_1, + .channels = 1, + .buswidth = 8, + .qosbox = &xm_pcie3_1_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_ANOC_PCIE_GEM_NOC }, +}; + +static const struct qcom_icc_qosbox qhm_gic_qos = { + .num_ports = 1, + .port_offsets = { 0x1d000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qhm_gic = { + .name = "qhm_gic", + .id = SAR2130P_MASTER_GIC_AHB, + .channels = 1, + .buswidth = 4, + .qosbox = &qhm_gic_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static const struct qcom_icc_qosbox qhm_qdss_bam_qos = { + .num_ports = 1, + .port_offsets = { 0x22000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qhm_qdss_bam = { + .name = "qhm_qdss_bam", + .id = SAR2130P_MASTER_QDSS_BAM, + .channels = 1, + .buswidth = 4, + .qosbox = &qhm_qdss_bam_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static const struct qcom_icc_qosbox qhm_qspi_qos = { + .num_ports = 1, + .port_offsets = { 0x23000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qhm_qspi = { + .name = "qhm_qspi", + .id = SAR2130P_MASTER_QSPI_0, + .channels = 1, + .buswidth = 4, + .qosbox = &qhm_qspi_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static const struct qcom_icc_qosbox qhm_qup0_qos = { + .num_ports = 1, + .port_offsets = { 0x24000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qhm_qup0 = { + .name = "qhm_qup0", + .id = SAR2130P_MASTER_QUP_0, + .channels = 1, + .buswidth = 4, + .qosbox = &qhm_qup0_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static const struct qcom_icc_qosbox qhm_qup1_qos = { + .num_ports = 1, + .port_offsets = { 0x25000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qhm_qup1 = { + .name = "qhm_qup1", + .id = SAR2130P_MASTER_QUP_1, + .channels = 1, + .buswidth = 4, + .qosbox = &qhm_qup1_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qnm_aggre2_noc = { + .name = "qnm_aggre2_noc", + .id = SAR2130P_MASTER_A2NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SAR2130P_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static const struct qcom_icc_qosbox qnm_cnoc_datapath_qos = { + .num_ports = 1, + .port_offsets = { 0x26000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qnm_cnoc_datapath = { + .name = "qnm_cnoc_datapath", + .id = SAR2130P_MASTER_CNOC_DATAPATH, + .channels = 1, + .buswidth = 8, + .qosbox = &qnm_cnoc_datapath_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static const struct qcom_icc_qosbox qnm_lpass_noc_qos = { + .num_ports = 1, + .port_offsets = { 0x1e000 }, + .prio = 0, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qnm_lpass_noc = { + .name = "qnm_lpass_noc", + .id = SAR2130P_MASTER_LPASS_ANOC, + .channels = 1, + .buswidth = 16, + .qosbox = &qnm_lpass_noc_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_SNOC_GEM_NOC_SF }, +}; + +static struct qcom_icc_node qnm_snoc_cfg = { + .name = "qnm_snoc_cfg", + .id = SAR2130P_MASTER_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_SLAVE_SERVICE_SNOC }, +}; + +static const struct qcom_icc_qosbox qxm_crypto_qos = { + .num_ports = 1, + .port_offsets = { 0x27000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qxm_crypto = { + .name = "qxm_crypto", + .id = SAR2130P_MASTER_CRYPTO, + .channels = 1, + .buswidth = 8, + .qosbox = &qxm_crypto_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static const struct qcom_icc_qosbox qxm_pimem_qos = { + .num_ports = 1, + .port_offsets = { 0x1f000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node qxm_pimem = { + .name = "qxm_pimem", + .id = SAR2130P_MASTER_PIMEM, + .channels = 1, + .buswidth = 8, + .qosbox = &qxm_pimem_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_SNOC_GEM_NOC_GC }, +}; + +static const struct qcom_icc_qosbox xm_gic_qos = { + .num_ports = 1, + .port_offsets = { 0x21000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node xm_gic = { + .name = "xm_gic", + .id = SAR2130P_MASTER_GIC, + .channels = 1, + .buswidth = 8, + .qosbox = &xm_gic_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_SNOC_GEM_NOC_GC }, +}; + +static const struct qcom_icc_qosbox xm_qdss_etr_0_qos = { + .num_ports = 1, + .port_offsets = { 0x1b000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node xm_qdss_etr_0 = { + .name = "xm_qdss_etr_0", + .id = SAR2130P_MASTER_QDSS_ETR, + .channels = 1, + .buswidth = 8, + .qosbox = &xm_qdss_etr_0_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static const struct qcom_icc_qosbox xm_qdss_etr_1_qos = { + .num_ports = 1, + .port_offsets = { 0x1c000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node xm_qdss_etr_1 = { + .name = "xm_qdss_etr_1", + .id = SAR2130P_MASTER_QDSS_ETR_1, + .channels = 1, + .buswidth = 8, + .qosbox = &xm_qdss_etr_1_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static const struct qcom_icc_qosbox xm_sdc1_qos = { + .num_ports = 1, + .port_offsets = { 0x29000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node xm_sdc1 = { + .name = "xm_sdc1", + .id = SAR2130P_MASTER_SDCC_1, + .channels = 1, + .buswidth = 8, + .qosbox = &xm_sdc1_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static const struct qcom_icc_qosbox xm_usb3_0_qos = { + .num_ports = 1, + .port_offsets = { 0x28000 }, + .prio = 2, + .urg_fwd = 0, + .prio_fwd_disable = 1, +}; + +static struct qcom_icc_node xm_usb3_0 = { + .name = "xm_usb3_0", + .id = SAR2130P_MASTER_USB3_0, + .channels = 1, + .buswidth = 8, + .qosbox = &xm_usb3_0_qos, + .num_links = 1, + .links = { SAR2130P_SLAVE_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qup0_core_slave = { + .name = "qup0_core_slave", + .id = SAR2130P_SLAVE_QUP_CORE_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qup1_core_slave = { + .name = "qup1_core_slave", + .id = SAR2130P_SLAVE_QUP_CORE_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ahb2phy0 = { + .name = "qhs_ahb2phy0", + .id = SAR2130P_SLAVE_AHB2PHY_SOUTH, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_aoss = { + .name = "qhs_aoss", + .id = SAR2130P_SLAVE_AOSS, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_camera_cfg = { + .name = "qhs_camera_cfg", + .id = SAR2130P_SLAVE_CAMERA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_clk_ctl = { + .name = "qhs_clk_ctl", + .id = SAR2130P_SLAVE_CLK_CTL, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_compute_cfg = { + .name = "qhs_compute_cfg", + .id = SAR2130P_SLAVE_CDSP_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_MASTER_CDSP_NOC_CFG }, +}; + +static struct qcom_icc_node qhs_cpr_cx = { + .name = "qhs_cpr_cx", + .id = SAR2130P_SLAVE_RBCPR_CX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mmcx = { + .name = "qhs_cpr_mmcx", + .id = SAR2130P_SLAVE_RBCPR_MMCX_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mxa = { + .name = "qhs_cpr_mxa", + .id = SAR2130P_SLAVE_RBCPR_MXA_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_mxc = { + .name = "qhs_cpr_mxc", + .id = SAR2130P_SLAVE_RBCPR_MXC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cpr_nspcx = { + .name = "qhs_cpr_nspcx", + .id = SAR2130P_SLAVE_CPR_NSPCX, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_crypto0_cfg = { + .name = "qhs_crypto0_cfg", + .id = SAR2130P_SLAVE_CRYPTO_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_cx_rdpm = { + .name = "qhs_cx_rdpm", + .id = SAR2130P_SLAVE_CX_RDPM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_display_cfg = { + .name = "qhs_display_cfg", + .id = SAR2130P_SLAVE_DISPLAY_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_gpuss_cfg = { + .name = "qhs_gpuss_cfg", + .id = SAR2130P_SLAVE_GFX3D_CFG, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_imem_cfg = { + .name = "qhs_imem_cfg", + .id = SAR2130P_SLAVE_IMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_ipc_router = { + .name = "qhs_ipc_router", + .id = SAR2130P_SLAVE_IPC_ROUTER_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lpass_cfg = { + .name = "qhs_lpass_cfg", + .id = SAR2130P_SLAVE_LPASS, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_MASTER_CNOC_LPASS_AG_NOC }, +}; + +static struct qcom_icc_node qhs_mx_rdpm = { + .name = "qhs_mx_rdpm", + .id = SAR2130P_SLAVE_MX_RDPM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie0_cfg = { + .name = "qhs_pcie0_cfg", + .id = SAR2130P_SLAVE_PCIE_0_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pcie1_cfg = { + .name = "qhs_pcie1_cfg", + .id = SAR2130P_SLAVE_PCIE_1_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pdm = { + .name = "qhs_pdm", + .id = SAR2130P_SLAVE_PDM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_pimem_cfg = { + .name = "qhs_pimem_cfg", + .id = SAR2130P_SLAVE_PIMEM_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_prng = { + .name = "qhs_prng", + .id = SAR2130P_SLAVE_PRNG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qdss_cfg = { + .name = "qhs_qdss_cfg", + .id = SAR2130P_SLAVE_QDSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qspi = { + .name = "qhs_qspi", + .id = SAR2130P_SLAVE_QSPI_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup0 = { + .name = "qhs_qup0", + .id = SAR2130P_SLAVE_QUP_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_qup1 = { + .name = "qhs_qup1", + .id = SAR2130P_SLAVE_QUP_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_sdc1 = { + .name = "qhs_sdc1", + .id = SAR2130P_SLAVE_SDCC_1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tcsr = { + .name = "qhs_tcsr", + .id = SAR2130P_SLAVE_TCSR, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tlmm = { + .name = "qhs_tlmm", + .id = SAR2130P_SLAVE_TLMM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_tme_cfg = { + .name = "qhs_tme_cfg", + .id = SAR2130P_SLAVE_TME_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_usb3_0 = { + .name = "qhs_usb3_0", + .id = SAR2130P_SLAVE_USB3_0, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_venus_cfg = { + .name = "qhs_venus_cfg", + .id = SAR2130P_SLAVE_VENUS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_vsense_ctrl_cfg = { + .name = "qhs_vsense_ctrl_cfg", + .id = SAR2130P_SLAVE_VSENSE_CTRL_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_wlan_q6 = { + .name = "qhs_wlan_q6", + .id = SAR2130P_SLAVE_WLAN_Q6_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_ddrss_cfg = { + .name = "qns_ddrss_cfg", + .id = SAR2130P_SLAVE_DDRSS_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mnoc_cfg = { + .name = "qns_mnoc_cfg", + .id = SAR2130P_SLAVE_CNOC_MNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_MASTER_CNOC_MNOC_CFG }, +}; + +static struct qcom_icc_node qns_snoc_cfg = { + .name = "qns_snoc_cfg", + .id = SAR2130P_SLAVE_SNOC_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 1, + .links = { SAR2130P_MASTER_SNOC_CFG }, +}; + +static struct qcom_icc_node qxs_imem = { + .name = "qxs_imem", + .id = SAR2130P_SLAVE_IMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qxs_pimem = { + .name = "qxs_pimem", + .id = SAR2130P_SLAVE_PIMEM, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_cnoc = { + .name = "srvc_cnoc", + .id = SAR2130P_SLAVE_SERVICE_CNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_0 = { + .name = "xs_pcie_0", + .id = SAR2130P_SLAVE_PCIE_0, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_pcie_1 = { + .name = "xs_pcie_1", + .id = SAR2130P_SLAVE_PCIE_1, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node xs_qdss_stm = { + .name = "xs_qdss_stm", + .id = SAR2130P_SLAVE_QDSS_STM, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node xs_sys_tcu_cfg = { + .name = "xs_sys_tcu_cfg", + .id = SAR2130P_SLAVE_TCU, + .channels = 1, + .buswidth = 8, + .num_links = 0, +}; + +static struct qcom_icc_node qns_gem_noc_cnoc = { + .name = "qns_gem_noc_cnoc", + .id = SAR2130P_SLAVE_GEM_NOC_CNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SAR2130P_MASTER_GEM_NOC_CNOC }, +}; + +static struct qcom_icc_node qns_llcc = { + .name = "qns_llcc", + .id = SAR2130P_SLAVE_LLCC, + .channels = 2, + .buswidth = 16, + .num_links = 1, + .links = { SAR2130P_MASTER_LLCC }, +}; + +static struct qcom_icc_node qns_pcie = { + .name = "qns_pcie", + .id = SAR2130P_SLAVE_MEM_NOC_PCIE_SNOC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SAR2130P_MASTER_GEM_NOC_PCIE_SNOC }, +}; + +static struct qcom_icc_node qhs_lpass_core = { + .name = "qhs_lpass_core", + .id = SAR2130P_SLAVE_LPASS_CORE_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lpass_lpi = { + .name = "qhs_lpass_lpi", + .id = SAR2130P_SLAVE_LPASS_LPI_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lpass_mpu = { + .name = "qhs_lpass_mpu", + .id = SAR2130P_SLAVE_LPASS_MPU_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qhs_lpass_top = { + .name = "qhs_lpass_top", + .id = SAR2130P_SLAVE_LPASS_TOP_CFG, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_sysnoc = { + .name = "qns_sysnoc", + .id = SAR2130P_SLAVE_LPASS_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SAR2130P_MASTER_LPASS_ANOC }, +}; + +static struct qcom_icc_node srvc_niu_aml_noc = { + .name = "srvc_niu_aml_noc", + .id = SAR2130P_SLAVE_SERVICES_LPASS_AML_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node srvc_niu_lpass_agnoc = { + .name = "srvc_niu_lpass_agnoc", + .id = SAR2130P_SLAVE_SERVICE_LPASS_AG_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node ebi = { + .name = "ebi", + .id = SAR2130P_SLAVE_EBI1, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_mem_noc_hf = { + .name = "qns_mem_noc_hf", + .id = SAR2130P_SLAVE_MNOC_HF_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SAR2130P_MASTER_MNOC_HF_MEM_NOC }, +}; + +static struct qcom_icc_node qns_mem_noc_sf = { + .name = "qns_mem_noc_sf", + .id = SAR2130P_SLAVE_MNOC_SF_MEM_NOC, + .channels = 1, + .buswidth = 32, + .num_links = 1, + .links = { SAR2130P_MASTER_MNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node srvc_mnoc = { + .name = "srvc_mnoc", + .id = SAR2130P_SLAVE_SERVICE_MNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_nsp_gemnoc = { + .name = "qns_nsp_gemnoc", + .id = SAR2130P_SLAVE_CDSP_MEM_NOC, + .channels = 2, + .buswidth = 32, + .num_links = 1, + .links = { SAR2130P_MASTER_COMPUTE_NOC }, +}; + +static struct qcom_icc_node service_nsp_noc = { + .name = "service_nsp_noc", + .id = SAR2130P_SLAVE_SERVICE_NSP_NOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_node qns_pcie_mem_noc = { + .name = "qns_pcie_mem_noc", + .id = SAR2130P_SLAVE_ANOC_PCIE_GEM_NOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SAR2130P_MASTER_ANOC_PCIE_GEM_NOC }, +}; + +static struct qcom_icc_node qns_a2noc_snoc = { + .name = "qns_a2noc_snoc", + .id = SAR2130P_SLAVE_A2NOC_SNOC, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SAR2130P_MASTER_A2NOC_SNOC }, +}; + +static struct qcom_icc_node qns_gemnoc_gc = { + .name = "qns_gemnoc_gc", + .id = SAR2130P_SLAVE_SNOC_GEM_NOC_GC, + .channels = 1, + .buswidth = 8, + .num_links = 1, + .links = { SAR2130P_MASTER_SNOC_GC_MEM_NOC }, +}; + +static struct qcom_icc_node qns_gemnoc_sf = { + .name = "qns_gemnoc_sf", + .id = SAR2130P_SLAVE_SNOC_GEM_NOC_SF, + .channels = 1, + .buswidth = 16, + .num_links = 1, + .links = { SAR2130P_MASTER_SNOC_SF_MEM_NOC }, +}; + +static struct qcom_icc_node srvc_snoc = { + .name = "srvc_snoc", + .id = SAR2130P_SLAVE_SERVICE_SNOC, + .channels = 1, + .buswidth = 4, + .num_links = 0, +}; + +static struct qcom_icc_bcm bcm_acv = { + .name = "ACV", + .enable_mask = BIT(3), + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_ce0 = { + .name = "CE0", + .num_nodes = 1, + .nodes = { &qxm_crypto }, +}; + +static struct qcom_icc_bcm bcm_cn0 = { + .name = "CN0", + .enable_mask = BIT(0), + .keepalive = true, + .num_nodes = 48, + .nodes = { &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie, + &xm_qdss_dap, &qhs_ahb2phy0, + &qhs_aoss, &qhs_camera_cfg, + &qhs_clk_ctl, &qhs_compute_cfg, + &qhs_cpr_cx, &qhs_cpr_mmcx, + &qhs_cpr_mxa, &qhs_cpr_mxc, + &qhs_cpr_nspcx, &qhs_crypto0_cfg, + &qhs_cx_rdpm, &qhs_display_cfg, + &qhs_gpuss_cfg, &qhs_imem_cfg, + &qhs_ipc_router, &qhs_lpass_cfg, + &qhs_mx_rdpm, &qhs_pcie0_cfg, + &qhs_pcie1_cfg, &qhs_pdm, + &qhs_pimem_cfg, &qhs_prng, + &qhs_qdss_cfg, &qhs_qspi, + &qhs_qup0, &qhs_qup1, + &qhs_sdc1, &qhs_tcsr, + &qhs_tlmm, &qhs_tme_cfg, + &qhs_usb3_0, &qhs_venus_cfg, + &qhs_vsense_ctrl_cfg, &qhs_wlan_q6, + &qns_ddrss_cfg, &qns_mnoc_cfg, + &qns_snoc_cfg, &qxs_imem, + &qxs_pimem, &srvc_cnoc, + &xs_pcie_0, &xs_pcie_1, + &xs_qdss_stm, &xs_sys_tcu_cfg }, +}; + +static struct qcom_icc_bcm bcm_co0 = { + .name = "CO0", + .enable_mask = BIT(0), + .num_nodes = 2, + .nodes = { &qxm_nsp, &qns_nsp_gemnoc }, +}; + +static struct qcom_icc_bcm bcm_mc0 = { + .name = "MC0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &ebi }, +}; + +static struct qcom_icc_bcm bcm_mm0 = { + .name = "MM0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_mem_noc_hf }, +}; + +static struct qcom_icc_bcm bcm_mm1 = { + .name = "MM1", + .enable_mask = BIT(0), + .num_nodes = 11, + .nodes = { &qnm_camnoc_hf, &qnm_camnoc_icp, + &qnm_camnoc_sf, &qnm_lsr, + &qnm_mdp, &qnm_mnoc_cfg, + &qnm_video, &qnm_video_cv_cpu, + &qnm_video_cvp, &qnm_video_v_cpu, + &qns_mem_noc_sf }, +}; + +static struct qcom_icc_bcm bcm_qup0 = { + .name = "QUP0", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup0_core_slave }, +}; + +static struct qcom_icc_bcm bcm_qup1 = { + .name = "QUP1", + .keepalive = true, + .vote_scale = 1, + .num_nodes = 1, + .nodes = { &qup1_core_slave }, +}; + +static struct qcom_icc_bcm bcm_sh0 = { + .name = "SH0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_llcc }, +}; + +static struct qcom_icc_bcm bcm_sh1 = { + .name = "SH1", + .enable_mask = BIT(0), + .num_nodes = 13, + .nodes = { &alm_gpu_tcu, &alm_sys_tcu, + &chm_apps, &qnm_gpu, + &qnm_mnoc_hf, &qnm_mnoc_sf, + &qnm_nsp_gemnoc, &qnm_pcie, + &qnm_snoc_gc, &qnm_snoc_sf, + &qxm_wlan_q6, &qns_gem_noc_cnoc, + &qns_pcie }, +}; + +static struct qcom_icc_bcm bcm_sn0 = { + .name = "SN0", + .keepalive = true, + .num_nodes = 1, + .nodes = { &qns_gemnoc_sf }, +}; + +static struct qcom_icc_bcm bcm_sn1 = { + .name = "SN1", + .enable_mask = BIT(0), + .num_nodes = 4, + .nodes = { &qhm_gic, &qxm_pimem, + &xm_gic, &qns_gemnoc_gc }, +}; + +static struct qcom_icc_bcm bcm_sn3 = { + .name = "SN3", + .num_nodes = 1, + .nodes = { &qnm_aggre2_noc }, +}; + +static struct qcom_icc_bcm bcm_sn4 = { + .name = "SN4", + .num_nodes = 1, + .nodes = { &qnm_lpass_noc }, +}; + +static struct qcom_icc_bcm bcm_sn7 = { + .name = "SN7", + .num_nodes = 1, + .nodes = { &qns_pcie_mem_noc }, +}; + +static struct qcom_icc_bcm * const clk_virt_bcms[] = { + &bcm_qup0, + &bcm_qup1, +}; + +static struct qcom_icc_node * const clk_virt_nodes[] = { + [MASTER_QUP_CORE_0] = &qup0_core_master, + [MASTER_QUP_CORE_1] = &qup1_core_master, + [SLAVE_QUP_CORE_0] = &qup0_core_slave, + [SLAVE_QUP_CORE_1] = &qup1_core_slave, +}; + +static const struct qcom_icc_desc sar2130p_clk_virt = { + .nodes = clk_virt_nodes, + .num_nodes = ARRAY_SIZE(clk_virt_nodes), + .bcms = clk_virt_bcms, + .num_bcms = ARRAY_SIZE(clk_virt_bcms), +}; + +static struct qcom_icc_bcm * const config_noc_bcms[] = { + &bcm_cn0, +}; + +static struct qcom_icc_node * const config_noc_nodes[] = { + [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc, + [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie, + [MASTER_QDSS_DAP] = &xm_qdss_dap, + [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0, + [SLAVE_AOSS] = &qhs_aoss, + [SLAVE_CAMERA_CFG] = &qhs_camera_cfg, + [SLAVE_CLK_CTL] = &qhs_clk_ctl, + [SLAVE_CDSP_CFG] = &qhs_compute_cfg, + [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx, + [SLAVE_RBCPR_MMCX_CFG] = &qhs_cpr_mmcx, + [SLAVE_RBCPR_MXA_CFG] = &qhs_cpr_mxa, + [SLAVE_RBCPR_MXC_CFG] = &qhs_cpr_mxc, + [SLAVE_CPR_NSPCX] = &qhs_cpr_nspcx, + [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg, + [SLAVE_CX_RDPM] = &qhs_cx_rdpm, + [SLAVE_DISPLAY_CFG] = &qhs_display_cfg, + [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg, + [SLAVE_IMEM_CFG] = &qhs_imem_cfg, + [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router, + [SLAVE_LPASS] = &qhs_lpass_cfg, + [SLAVE_MX_RDPM] = &qhs_mx_rdpm, + [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg, + [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg, + [SLAVE_PDM] = &qhs_pdm, + [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg, + [SLAVE_PRNG] = &qhs_prng, + [SLAVE_QDSS_CFG] = &qhs_qdss_cfg, + [SLAVE_QSPI_0] = &qhs_qspi, + [SLAVE_QUP_0] = &qhs_qup0, + [SLAVE_QUP_1] = &qhs_qup1, + [SLAVE_SDCC_1] = &qhs_sdc1, + [SLAVE_TCSR] = &qhs_tcsr, + [SLAVE_TLMM] = &qhs_tlmm, + [SLAVE_TME_CFG] = &qhs_tme_cfg, + [SLAVE_USB3_0] = &qhs_usb3_0, + [SLAVE_VENUS_CFG] = &qhs_venus_cfg, + [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg, + [SLAVE_WLAN_Q6_CFG] = &qhs_wlan_q6, + [SLAVE_DDRSS_CFG] = &qns_ddrss_cfg, + [SLAVE_CNOC_MNOC_CFG] = &qns_mnoc_cfg, + [SLAVE_SNOC_CFG] = &qns_snoc_cfg, + [SLAVE_IMEM] = &qxs_imem, + [SLAVE_PIMEM] = &qxs_pimem, + [SLAVE_SERVICE_CNOC] = &srvc_cnoc, + [SLAVE_PCIE_0] = &xs_pcie_0, + [SLAVE_PCIE_1] = &xs_pcie_1, + [SLAVE_QDSS_STM] = &xs_qdss_stm, + [SLAVE_TCU] = &xs_sys_tcu_cfg, +}; + +static const struct qcom_icc_desc sar2130p_config_noc = { + .config = &icc_regmap_config, + .nodes = config_noc_nodes, + .num_nodes = ARRAY_SIZE(config_noc_nodes), + .bcms = config_noc_bcms, + .num_bcms = ARRAY_SIZE(config_noc_bcms), +}; + +static struct qcom_icc_bcm * const gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh1, +}; + +static struct qcom_icc_node * const gem_noc_nodes[] = { + [MASTER_GPU_TCU] = &alm_gpu_tcu, + [MASTER_SYS_TCU] = &alm_sys_tcu, + [MASTER_APPSS_PROC] = &chm_apps, + [MASTER_GFX3D] = &qnm_gpu, + [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf, + [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf, + [MASTER_COMPUTE_NOC] = &qnm_nsp_gemnoc, + [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie, + [MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc, + [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf, + [MASTER_WLAN_Q6] = &qxm_wlan_q6, + [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc, + [SLAVE_LLCC] = &qns_llcc, + [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie, +}; + +static const struct qcom_icc_desc sar2130p_gem_noc = { + .config = &icc_regmap_config, + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), +}; + +static struct qcom_icc_bcm * const lpass_ag_noc_bcms[] = { +}; + +static struct qcom_icc_node * const lpass_ag_noc_nodes[] = { + [MASTER_CNOC_LPASS_AG_NOC] = &qhm_config_noc, + [MASTER_LPASS_PROC] = &qxm_lpass_dsp, + [SLAVE_LPASS_CORE_CFG] = &qhs_lpass_core, + [SLAVE_LPASS_LPI_CFG] = &qhs_lpass_lpi, + [SLAVE_LPASS_MPU_CFG] = &qhs_lpass_mpu, + [SLAVE_LPASS_TOP_CFG] = &qhs_lpass_top, + [SLAVE_LPASS_SNOC] = &qns_sysnoc, + [SLAVE_SERVICES_LPASS_AML_NOC] = &srvc_niu_aml_noc, + [SLAVE_SERVICE_LPASS_AG_NOC] = &srvc_niu_lpass_agnoc, +}; + +static const struct qcom_icc_desc sar2130p_lpass_ag_noc = { + .config = &icc_regmap_config, + .nodes = lpass_ag_noc_nodes, + .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes), + .bcms = lpass_ag_noc_bcms, + .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms), +}; + +static struct qcom_icc_bcm * const mc_virt_bcms[] = { + &bcm_acv, + &bcm_mc0, +}; + +static struct qcom_icc_node * const mc_virt_nodes[] = { + [MASTER_LLCC] = &llcc_mc, + [SLAVE_EBI1] = &ebi, +}; + +static const struct qcom_icc_desc sar2130p_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), +}; + +static struct qcom_icc_bcm * const mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, +}; + +static struct qcom_icc_node * const mmss_noc_nodes[] = { + [MASTER_CAMNOC_HF] = &qnm_camnoc_hf, + [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp, + [MASTER_CAMNOC_SF] = &qnm_camnoc_sf, + [MASTER_LSR] = &qnm_lsr, + [MASTER_MDP] = &qnm_mdp, + [MASTER_CNOC_MNOC_CFG] = &qnm_mnoc_cfg, + [MASTER_VIDEO] = &qnm_video, + [MASTER_VIDEO_CV_PROC] = &qnm_video_cv_cpu, + [MASTER_VIDEO_PROC] = &qnm_video_cvp, + [MASTER_VIDEO_V_PROC] = &qnm_video_v_cpu, + [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf, + [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf, + [SLAVE_SERVICE_MNOC] = &srvc_mnoc, +}; + +static const struct qcom_icc_desc sar2130p_mmss_noc = { + .config = &icc_regmap_config, + .nodes = mmss_noc_nodes, + .num_nodes = ARRAY_SIZE(mmss_noc_nodes), + .bcms = mmss_noc_bcms, + .num_bcms = ARRAY_SIZE(mmss_noc_bcms), +}; + +static struct qcom_icc_bcm * const nsp_noc_bcms[] = { + &bcm_co0, +}; + +static struct qcom_icc_node * const nsp_noc_nodes[] = { + [MASTER_CDSP_NOC_CFG] = &qhm_nsp_noc_config, + [MASTER_CDSP_PROC] = &qxm_nsp, + [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc, + [SLAVE_SERVICE_NSP_NOC] = &service_nsp_noc, +}; + +static const struct qcom_icc_desc sar2130p_nsp_noc = { + .config = &icc_regmap_config, + .nodes = nsp_noc_nodes, + .num_nodes = ARRAY_SIZE(nsp_noc_nodes), + .bcms = nsp_noc_bcms, + .num_bcms = ARRAY_SIZE(nsp_noc_bcms), +}; + +static struct qcom_icc_bcm * const pcie_anoc_bcms[] = { + &bcm_sn7, +}; + +static struct qcom_icc_node * const pcie_anoc_nodes[] = { + [MASTER_PCIE_0] = &xm_pcie3_0, + [MASTER_PCIE_1] = &xm_pcie3_1, + [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc, +}; + +static const struct qcom_icc_desc sar2130p_pcie_anoc = { + .config = &icc_regmap_config, + .nodes = pcie_anoc_nodes, + .num_nodes = ARRAY_SIZE(pcie_anoc_nodes), + .bcms = pcie_anoc_bcms, + .num_bcms = ARRAY_SIZE(pcie_anoc_bcms), +}; + +static struct qcom_icc_bcm * const system_noc_bcms[] = { + &bcm_ce0, + &bcm_sn0, + &bcm_sn1, + &bcm_sn3, + &bcm_sn4, +}; + +static struct qcom_icc_node * const system_noc_nodes[] = { + [MASTER_GIC_AHB] = &qhm_gic, + [MASTER_QDSS_BAM] = &qhm_qdss_bam, + [MASTER_QSPI_0] = &qhm_qspi, + [MASTER_QUP_0] = &qhm_qup0, + [MASTER_QUP_1] = &qhm_qup1, + [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc, + [MASTER_CNOC_DATAPATH] = &qnm_cnoc_datapath, + [MASTER_LPASS_ANOC] = &qnm_lpass_noc, + [MASTER_SNOC_CFG] = &qnm_snoc_cfg, + [MASTER_CRYPTO] = &qxm_crypto, + [MASTER_PIMEM] = &qxm_pimem, + [MASTER_GIC] = &xm_gic, + [MASTER_QDSS_ETR] = &xm_qdss_etr_0, + [MASTER_QDSS_ETR_1] = &xm_qdss_etr_1, + [MASTER_SDCC_1] = &xm_sdc1, + [MASTER_USB3_0] = &xm_usb3_0, + [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc, + [SLAVE_SNOC_GEM_NOC_GC] = &qns_gemnoc_gc, + [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf, + [SLAVE_SERVICE_SNOC] = &srvc_snoc, +}; + +static const struct qcom_icc_desc sar2130p_system_noc = { + .config = &icc_regmap_config, + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), +}; + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,sar2130p-clk-virt", .data = &sar2130p_clk_virt}, + { .compatible = "qcom,sar2130p-config-noc", .data = &sar2130p_config_noc}, + { .compatible = "qcom,sar2130p-gem-noc", .data = &sar2130p_gem_noc}, + { .compatible = "qcom,sar2130p-lpass-ag-noc", .data = &sar2130p_lpass_ag_noc}, + { .compatible = "qcom,sar2130p-mc-virt", .data = &sar2130p_mc_virt}, + { .compatible = "qcom,sar2130p-mmss-noc", .data = &sar2130p_mmss_noc}, + { .compatible = "qcom,sar2130p-nsp-noc", .data = &sar2130p_nsp_noc}, + { .compatible = "qcom,sar2130p-pcie-anoc", .data = &sar2130p_pcie_anoc}, + { .compatible = "qcom,sar2130p-system-noc", .data = &sar2130p_system_noc}, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, + .driver = { + .name = "qnoc-sar2130p", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; + +static int __init qnoc_driver_init(void) +{ + return platform_driver_register(&qnoc_driver); +} +core_initcall(qnoc_driver_init); + +static void __exit qnoc_driver_exit(void) +{ + platform_driver_unregister(&qnoc_driver); +} + +module_exit(qnoc_driver_exit); +MODULE_DESCRIPTION("Qualcomm SAR2130P NoC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/interconnect/qcom/sc7180.c b/drivers/interconnect/qcom/sc7180.c index 34a1d163d6e164..af2be15438403e 100644 --- a/drivers/interconnect/qcom/sc7180.c +++ b/drivers/interconnect/qcom/sc7180.c @@ -1807,7 +1807,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc7180", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c index 167971f8e8bec3..346f18d70e9e5e 100644 --- a/drivers/interconnect/qcom/sc7280.c +++ b/drivers/interconnect/qcom/sc7280.c @@ -1691,7 +1691,7 @@ static const struct qcom_icc_desc sc7280_aggre1_noc = { .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), .bcms = aggre1_noc_bcms, .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), - .qos_clks_required = true, + .qos_requires_clocks = true, }; static struct qcom_icc_bcm * const aggre2_noc_bcms[] = { @@ -1723,7 +1723,7 @@ static const struct qcom_icc_desc sc7280_aggre2_noc = { .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), .bcms = aggre2_noc_bcms, .num_bcms = ARRAY_SIZE(aggre2_noc_bcms), - .qos_clks_required = true, + .qos_requires_clocks = true, }; static struct qcom_icc_bcm * const clk_virt_bcms[] = { @@ -2111,7 +2111,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc7280", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c index 03d626776ba17a..a741badaa966e0 100644 --- a/drivers/interconnect/qcom/sc8180x.c +++ b/drivers/interconnect/qcom/sc8180x.c @@ -1889,7 +1889,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc8180x", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sc8280xp.c b/drivers/interconnect/qcom/sc8280xp.c index 7acd152bf0dd8d..0270f6c64481a9 100644 --- a/drivers/interconnect/qcom/sc8280xp.c +++ b/drivers/interconnect/qcom/sc8280xp.c @@ -2391,7 +2391,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc8280xp", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c index ab91de446da881..7392bebba3344f 100644 --- a/drivers/interconnect/qcom/sdm660.c +++ b/drivers/interconnect/qcom/sdm660.c @@ -1714,7 +1714,7 @@ MODULE_DEVICE_TABLE(of, sdm660_noc_of_match); static struct platform_driver sdm660_noc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-sdm660", .of_match_table = sdm660_noc_of_match, diff --git a/drivers/interconnect/qcom/sdm670.c b/drivers/interconnect/qcom/sdm670.c index e5ee7fbaa641c9..907e1ff4ff8179 100644 --- a/drivers/interconnect/qcom/sdm670.c +++ b/drivers/interconnect/qcom/sdm670.c @@ -1533,7 +1533,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdm670", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c index 584800ac871a8d..855802be93fea1 100644 --- a/drivers/interconnect/qcom/sdm845.c +++ b/drivers/interconnect/qcom/sdm845.c @@ -1802,7 +1802,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdm845", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdx55.c b/drivers/interconnect/qcom/sdx55.c index e97f28b8d2b25d..4117db046fa00c 100644 --- a/drivers/interconnect/qcom/sdx55.c +++ b/drivers/interconnect/qcom/sdx55.c @@ -913,7 +913,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdx55", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdx65.c b/drivers/interconnect/qcom/sdx65.c index 2f3f5479d8a513..d3a6c6c148e5de 100644 --- a/drivers/interconnect/qcom/sdx65.c +++ b/drivers/interconnect/qcom/sdx65.c @@ -897,7 +897,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdx65", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdx75.c b/drivers/interconnect/qcom/sdx75.c index 7f422c27488d33..7ef1f17f3292e1 100644 --- a/drivers/interconnect/qcom/sdx75.c +++ b/drivers/interconnect/qcom/sdx75.c @@ -1083,7 +1083,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdx75", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm6115.c b/drivers/interconnect/qcom/sm6115.c index 271b07c74862d2..3ee12c8a4d56b3 100644 --- a/drivers/interconnect/qcom/sm6115.c +++ b/drivers/interconnect/qcom/sm6115.c @@ -1402,7 +1402,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qnoc_probe, - .remove_new = qnoc_remove, + .remove = qnoc_remove, .driver = { .name = "qnoc-sm6115", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm6350.c b/drivers/interconnect/qcom/sm6350.c index 20923e8e611020..f41d7e19ba269c 100644 --- a/drivers/interconnect/qcom/sm6350.c +++ b/drivers/interconnect/qcom/sm6350.c @@ -1702,7 +1702,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm6350", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm7150.c b/drivers/interconnect/qcom/sm7150.c index dc0d1343f5100b..c8c77407cd508d 100644 --- a/drivers/interconnect/qcom/sm7150.c +++ b/drivers/interconnect/qcom/sm7150.c @@ -1730,7 +1730,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm7150", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8150.c b/drivers/interconnect/qcom/sm8150.c index f29b77556a7998..edfe824cad3533 100644 --- a/drivers/interconnect/qcom/sm8150.c +++ b/drivers/interconnect/qcom/sm8150.c @@ -1864,7 +1864,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8150", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8250.c b/drivers/interconnect/qcom/sm8250.c index 1879fa15761f5e..cc1b14c1352910 100644 --- a/drivers/interconnect/qcom/sm8250.c +++ b/drivers/interconnect/qcom/sm8250.c @@ -1991,7 +1991,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8250", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c index 4236a43dc256f9..38105ead4f2954 100644 --- a/drivers/interconnect/qcom/sm8350.c +++ b/drivers/interconnect/qcom/sm8350.c @@ -1807,7 +1807,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8350", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8450.c b/drivers/interconnect/qcom/sm8450.c index b3cd0087377ca7..eb7e17df32ba65 100644 --- a/drivers/interconnect/qcom/sm8450.c +++ b/drivers/interconnect/qcom/sm8450.c @@ -1884,7 +1884,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8450", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c index 4d0e6fa9e003bd..fdb97d1f1d074d 100644 --- a/drivers/interconnect/qcom/sm8550.c +++ b/drivers/interconnect/qcom/sm8550.c @@ -1645,7 +1645,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8550", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8650.c b/drivers/interconnect/qcom/sm8650.c index b962e6c233ef78..20ac5bc5e1fbaf 100644 --- a/drivers/interconnect/qcom/sm8650.c +++ b/drivers/interconnect/qcom/sm8650.c @@ -1650,7 +1650,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8650", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/smd-rpm.c b/drivers/interconnect/qcom/smd-rpm.c index 3816bfb4e2f39e..8316c87a2c60f5 100644 --- a/drivers/interconnect/qcom/smd-rpm.c +++ b/drivers/interconnect/qcom/smd-rpm.c @@ -85,7 +85,7 @@ static struct platform_driver qcom_interconnect_rpm_smd_driver = { .name = "icc_smd_rpm", }, .probe = qcom_icc_rpm_smd_probe, - .remove_new = qcom_icc_rpm_smd_remove, + .remove = qcom_icc_rpm_smd_remove, }; module_platform_driver(qcom_interconnect_rpm_smd_driver); MODULE_AUTHOR("Georgi Djakov "); diff --git a/drivers/interconnect/qcom/x1e80100.c b/drivers/interconnect/qcom/x1e80100.c index 654abb9ce08eed..2c46fdb4a0543f 100644 --- a/drivers/interconnect/qcom/x1e80100.c +++ b/drivers/interconnect/qcom/x1e80100.c @@ -1964,7 +1964,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { .probe = qcom_icc_rpmh_probe, - .remove_new = qcom_icc_rpmh_remove, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-x1e80100", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/samsung/exynos.c b/drivers/interconnect/samsung/exynos.c index c9e5361e17c5b0..9e041365d9091b 100644 --- a/drivers/interconnect/samsung/exynos.c +++ b/drivers/interconnect/samsung/exynos.c @@ -180,7 +180,7 @@ static struct platform_driver exynos_generic_icc_driver = { .sync_state = icc_sync_state, }, .probe = exynos_generic_icc_probe, - .remove_new = exynos_generic_icc_remove, + .remove = exynos_generic_icc_remove, }; module_platform_driver(exynos_generic_icc_driver); diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index b3aa1f5d53218b..47c46e4b739ef3 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -195,6 +195,7 @@ config MSM_IOMMU source "drivers/iommu/amd/Kconfig" source "drivers/iommu/intel/Kconfig" source "drivers/iommu/iommufd/Kconfig" +source "drivers/iommu/riscv/Kconfig" config IRQ_REMAP bool "Support for Interrupt Remapping" @@ -415,6 +416,15 @@ config ARM_SMMU_V3_SVA Say Y here if your system supports SVA extensions such as PCIe PASID and PRI. +config ARM_SMMU_V3_IOMMUFD + bool "Enable IOMMUFD features for ARM SMMUv3 (EXPERIMENTAL)" + depends on IOMMUFD + help + Support for IOMMUFD features intended to support virtual machines + with accelerated virtual IOMMUs. + + Say Y here if you are doing development and testing on this feature. + config ARM_SMMU_V3_KUNIT_TEST tristate "KUnit tests for arm-smmu-v3 driver" if !KUNIT_ALL_TESTS depends on KUNIT diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 542760d963ec7c..5e5a83c6c2aae2 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y += amd/ intel/ arm/ iommufd/ +obj-y += amd/ intel/ arm/ iommufd/ riscv/ obj-$(CONFIG_IOMMU_API) += iommu.o obj-$(CONFIG_IOMMU_API) += iommu-traces.o obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index 6386fa4556d9b8..1bef5d55b2f9dd 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -46,13 +46,15 @@ extern int amd_iommu_gpt_level; extern unsigned long amd_iommu_pgsize_bitmap; /* Protection domain ops */ +void amd_iommu_init_identity_domain(void); struct protection_domain *protection_domain_alloc(unsigned int type, int nid); void protection_domain_free(struct protection_domain *domain); struct iommu_domain *amd_iommu_domain_alloc_sva(struct device *dev, struct mm_struct *mm); void amd_iommu_domain_free(struct iommu_domain *dom); int iommu_sva_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid); + struct device *dev, ioasid_t pasid, + struct iommu_domain *old); void amd_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, struct iommu_domain *domain); @@ -118,9 +120,14 @@ static inline bool check_feature2(u64 mask) return (amd_iommu_efr2 & mask); } +static inline bool amd_iommu_v2_pgtbl_supported(void) +{ + return (check_feature(FEATURE_GIOSUP) && check_feature(FEATURE_GT)); +} + static inline bool amd_iommu_gt_ppr_supported(void) { - return (check_feature(FEATURE_GT) && + return (amd_iommu_v2_pgtbl_supported() && check_feature(FEATURE_PPR) && check_feature(FEATURE_EPHSUP)); } diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 601fb4ee69009e..fdb0357e0bb91a 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -565,6 +565,12 @@ struct pdom_dev_data { struct list_head list; }; +/* Keeps track of the IOMMUs attached to protection domain */ +struct pdom_iommu_info { + struct amd_iommu *iommu; /* IOMMUs attach to protection domain */ + u32 refcnt; /* Count of attached dev/pasid per domain/IOMMU */ +}; + /* * This structure contains generic data for IOMMU protection domains * independent of their use. @@ -578,8 +584,7 @@ struct protection_domain { u16 id; /* the domain id written to the device table */ enum protection_domain_mode pd_mode; /* Track page table type */ bool dirty_tracking; /* dirty tracking is enabled in the domain */ - unsigned dev_cnt; /* devices assigned to this domain */ - unsigned dev_iommu[MAX_IOMMUS]; /* per-IOMMU reference count */ + struct xarray iommu_array; /* per-IOMMU reference count */ struct mmu_notifier mn; /* mmu notifier for the SVA domain */ struct list_head dev_data_list; /* List of pdom_dev_data */ @@ -831,7 +836,7 @@ struct devid_map { */ struct iommu_dev_data { /*Protect against attach/detach races */ - spinlock_t lock; + struct mutex mutex; struct list_head list; /* For domain->dev_list */ struct llist_node dev_data_list; /* For global dev_data_list */ @@ -872,12 +877,6 @@ extern struct list_head amd_iommu_pci_seg_list; */ extern struct list_head amd_iommu_list; -/* - * Array with pointers to each IOMMU struct - * The indices are referenced in the protection domains - */ -extern struct amd_iommu *amd_iommus[MAX_IOMMUS]; - /* * Structure defining one entry in the device table */ @@ -912,14 +911,14 @@ struct unity_map_entry { /* size of the dma_ops aperture as power of 2 */ extern unsigned amd_iommu_aperture_order; -/* allocation bitmap for domain ids */ -extern unsigned long *amd_iommu_pd_alloc_bitmap; - extern bool amd_iommu_force_isolation; /* Max levels of glxval supported */ extern int amd_iommu_max_glx_val; +/* IDA to track protection domain IDs */ +extern struct ida pdom_ids; + /* Global EFR and EFR2 registers */ extern u64 amd_iommu_efr; extern u64 amd_iommu_efr2; diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 43131c3a21726f..0e0a531042acb3 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -177,9 +177,6 @@ LIST_HEAD(amd_iommu_pci_seg_list); /* list of all PCI segments */ LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the system */ -/* Array to assign indices to IOMMUs*/ -struct amd_iommu *amd_iommus[MAX_IOMMUS]; - /* Number of IOMMUs present in the system */ static int amd_iommus_present; @@ -194,12 +191,6 @@ bool amd_iommu_force_isolation __read_mostly; unsigned long amd_iommu_pgsize_bitmap __ro_after_init = AMD_IOMMU_PGSIZES; -/* - * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap - * to know which ones are already in use. - */ -unsigned long *amd_iommu_pd_alloc_bitmap; - enum iommu_init_state { IOMMU_START_STATE, IOMMU_IVRS_DETECTED, @@ -1082,7 +1073,12 @@ static bool __copy_device_table(struct amd_iommu *iommu) if (dte_v && dom_id) { pci_seg->old_dev_tbl_cpy[devid].data[0] = old_devtb[devid].data[0]; pci_seg->old_dev_tbl_cpy[devid].data[1] = old_devtb[devid].data[1]; - __set_bit(dom_id, amd_iommu_pd_alloc_bitmap); + /* Reserve the Domain IDs used by previous kernel */ + if (ida_alloc_range(&pdom_ids, dom_id, dom_id, GFP_ATOMIC) != dom_id) { + pr_err("Failed to reserve domain ID 0x%x\n", dom_id); + memunmap(old_devtb); + return false; + } /* If gcr3 table existed, mask it out */ if (old_devtb[devid].data[0] & DTE_FLAG_GV) { tmp = DTE_GCR3_VAL_B(~0ULL) << DTE_GCR3_SHIFT_B; @@ -1744,9 +1740,6 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h, return -ENOSYS; } - /* Index is fine - add IOMMU to the array */ - amd_iommus[iommu->index] = iommu; - /* * Copy data from ACPI table entry to the iommu struct */ @@ -2070,14 +2063,6 @@ static int __init iommu_init_pci(struct amd_iommu *iommu) init_iommu_perf_ctr(iommu); - if (amd_iommu_pgtable == AMD_IOMMU_V2) { - if (!check_feature(FEATURE_GIOSUP) || - !check_feature(FEATURE_GT)) { - pr_warn("Cannot enable v2 page table for DMA-API. Fallback to v1.\n"); - amd_iommu_pgtable = AMD_IOMMU_V1; - } - } - if (is_rd890_iommu(iommu->dev)) { int i, j; @@ -2172,6 +2157,9 @@ static int __init amd_iommu_init_pci(void) struct amd_iommu_pci_seg *pci_seg; int ret; + /* Init global identity domain before registering IOMMU */ + amd_iommu_init_identity_domain(); + for_each_iommu(iommu) { ret = iommu_init_pci(iommu); if (ret) { @@ -2882,11 +2870,6 @@ static void enable_iommus_vapic(void) #endif } -static void enable_iommus(void) -{ - early_enable_iommus(); -} - static void disable_iommus(void) { struct amd_iommu *iommu; @@ -2913,7 +2896,8 @@ static void amd_iommu_resume(void) iommu_apply_resume_quirks(iommu); /* re-load the hardware */ - enable_iommus(); + for_each_iommu(iommu) + early_enable_iommu(iommu); amd_iommu_enable_interrupts(); } @@ -2994,9 +2978,7 @@ static bool __init check_ioapic_information(void) static void __init free_dma_resources(void) { - iommu_free_pages(amd_iommu_pd_alloc_bitmap, - get_order(MAX_DOMAIN_ID / 8)); - amd_iommu_pd_alloc_bitmap = NULL; + ida_destroy(&pdom_ids); free_unity_maps(); } @@ -3064,20 +3046,6 @@ static int __init early_amd_iommu_init(void) amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base); DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type); - /* Device table - directly used by all IOMMUs */ - ret = -ENOMEM; - - amd_iommu_pd_alloc_bitmap = iommu_alloc_pages(GFP_KERNEL, - get_order(MAX_DOMAIN_ID / 8)); - if (amd_iommu_pd_alloc_bitmap == NULL) - goto out; - - /* - * never allocate domain 0 because its used as the non-allocated and - * error value placeholder - */ - __set_bit(0, amd_iommu_pd_alloc_bitmap); - /* * now the data structures are allocated and basically initialized * start the real acpi table scan @@ -3091,6 +3059,13 @@ static int __init early_amd_iommu_init(void) FIELD_GET(FEATURE_GATS, amd_iommu_efr) == GUEST_PGTABLE_5_LEVEL) amd_iommu_gpt_level = PAGE_MODE_5_LEVEL; + if (amd_iommu_pgtable == AMD_IOMMU_V2) { + if (!amd_iommu_v2_pgtbl_supported()) { + pr_warn("Cannot enable v2 page table for DMA-API. Fallback to v1.\n"); + amd_iommu_pgtable = AMD_IOMMU_V1; + } + } + /* Disable any previously enabled IOMMUs */ if (!is_kdump_kernel() || amd_iommu_disabled) disable_iommus(); diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c index 804b788f3f167d..f3399087859fd1 100644 --- a/drivers/iommu/amd/io_pgtable.c +++ b/drivers/iommu/amd/io_pgtable.c @@ -118,6 +118,7 @@ static void free_sub_pt(u64 *root, int mode, struct list_head *freelist) */ static bool increase_address_space(struct amd_io_pgtable *pgtable, unsigned long address, + unsigned int page_size_level, gfp_t gfp) { struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg; @@ -133,7 +134,8 @@ static bool increase_address_space(struct amd_io_pgtable *pgtable, spin_lock_irqsave(&domain->lock, flags); - if (address <= PM_LEVEL_SIZE(pgtable->mode)) + if (address <= PM_LEVEL_SIZE(pgtable->mode) && + pgtable->mode - 1 >= page_size_level) goto out; ret = false; @@ -163,18 +165,21 @@ static u64 *alloc_pte(struct amd_io_pgtable *pgtable, gfp_t gfp, bool *updated) { + unsigned long last_addr = address + (page_size - 1); struct io_pgtable_cfg *cfg = &pgtable->pgtbl.cfg; int level, end_lvl; u64 *pte, *page; BUG_ON(!is_power_of_2(page_size)); - while (address > PM_LEVEL_SIZE(pgtable->mode)) { + while (last_addr > PM_LEVEL_SIZE(pgtable->mode) || + pgtable->mode - 1 < PAGE_SIZE_LEVEL(page_size)) { /* * Return an error if there is no memory to update the * page-table. */ - if (!increase_address_space(pgtable, address, gfp)) + if (!increase_address_space(pgtable, last_addr, + PAGE_SIZE_LEVEL(page_size), gfp)) return NULL; } diff --git a/drivers/iommu/amd/io_pgtable_v2.c b/drivers/iommu/amd/io_pgtable_v2.c index 25b9042fa45307..c616de2c5926ec 100644 --- a/drivers/iommu/amd/io_pgtable_v2.c +++ b/drivers/iommu/amd/io_pgtable_v2.c @@ -268,8 +268,11 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova, out: if (updated) { struct protection_domain *pdom = io_pgtable_ops_to_domain(ops); + unsigned long flags; + spin_lock_irqsave(&pdom->lock, flags); amd_iommu_domain_flush_pages(pdom, o_iova, size); + spin_unlock_irqrestore(&pdom->lock, flags); } if (mapped) diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 8364cd6fa47d01..16f40b8000d798 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -52,8 +53,6 @@ #define HT_RANGE_START (0xfd00000000ULL) #define HT_RANGE_END (0xffffffffffULL) -static DEFINE_SPINLOCK(pd_bitmap_lock); - LIST_HEAD(ioapic_map); LIST_HEAD(hpet_map); LIST_HEAD(acpihid_map); @@ -70,9 +69,16 @@ struct iommu_cmd { u32 data[4]; }; +/* + * AMD IOMMU allows up to 2^16 different protection domains. This is a bitmap + * to know which ones are already in use. + */ +DEFINE_IDA(pdom_ids); + struct kmem_cache *amd_iommu_irq_cache; -static void detach_device(struct device *dev); +static int amd_iommu_attach_device(struct iommu_domain *dom, + struct device *dev); static void set_dte_entry(struct amd_iommu *iommu, struct iommu_dev_data *dev_data); @@ -202,7 +208,7 @@ static struct iommu_dev_data *alloc_dev_data(struct amd_iommu *iommu, u16 devid) if (!dev_data) return NULL; - spin_lock_init(&dev_data->lock); + mutex_init(&dev_data->mutex); dev_data->devid = devid; ratelimit_default_init(&dev_data->rs); @@ -555,22 +561,6 @@ static void iommu_ignore_device(struct amd_iommu *iommu, struct device *dev) setup_aliases(iommu, dev); } -static void amd_iommu_uninit_device(struct device *dev) -{ - struct iommu_dev_data *dev_data; - - dev_data = dev_iommu_priv_get(dev); - if (!dev_data) - return; - - if (dev_data->domain) - detach_device(dev); - - /* - * We keep dev_data around for unplugged devices and reuse it when the - * device is re-plugged - not doing so would introduce a ton of races. - */ -} /**************************************************************************** * @@ -1230,7 +1220,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu) if (!iommu->need_sync) return 0; - data = atomic64_add_return(1, &iommu->cmd_sem_val); + data = atomic64_inc_return(&iommu->cmd_sem_val); build_completion_wait(&cmd, iommu, data); raw_spin_lock_irqsave(&iommu->lock, flags); @@ -1249,18 +1239,17 @@ static int iommu_completion_wait(struct amd_iommu *iommu) static void domain_flush_complete(struct protection_domain *domain) { - int i; + struct pdom_iommu_info *pdom_iommu_info; + unsigned long i; - for (i = 0; i < amd_iommu_get_num_iommus(); ++i) { - if (domain && !domain->dev_iommu[i]) - continue; + lockdep_assert_held(&domain->lock); - /* - * Devices of this domain are behind this IOMMU - * We need to wait for completion of all commands. - */ - iommu_completion_wait(amd_iommus[i]); - } + /* + * Devices of this domain are behind this IOMMU + * We need to wait for completion of all commands. + */ + xa_for_each(&domain->iommu_array, i, pdom_iommu_info) + iommu_completion_wait(pdom_iommu_info->iommu); } static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid) @@ -1426,6 +1415,7 @@ static int domain_flush_pages_v2(struct protection_domain *pdom, struct iommu_cmd cmd; int ret = 0; + lockdep_assert_held(&pdom->lock); list_for_each_entry(dev_data, &pdom->dev_list, list) { struct amd_iommu *iommu = get_amd_iommu_from_dev(dev_data->dev); u16 domid = dev_data->gcr3_info.domid; @@ -1442,21 +1432,22 @@ static int domain_flush_pages_v2(struct protection_domain *pdom, static int domain_flush_pages_v1(struct protection_domain *pdom, u64 address, size_t size) { + struct pdom_iommu_info *pdom_iommu_info; struct iommu_cmd cmd; - int ret = 0, i; + int ret = 0; + unsigned long i; + + lockdep_assert_held(&pdom->lock); build_inv_iommu_pages(&cmd, address, size, pdom->id, IOMMU_NO_PASID, false); - for (i = 0; i < amd_iommu_get_num_iommus(); ++i) { - if (!pdom->dev_iommu[i]) - continue; - + xa_for_each(&pdom->iommu_array, i, pdom_iommu_info) { /* * Devices of this domain are behind this IOMMU * We need a TLB flush */ - ret |= iommu_queue_command(amd_iommus[i], &cmd); + ret |= iommu_queue_command(pdom_iommu_info->iommu, &cmd); } return ret; @@ -1474,6 +1465,8 @@ static void __domain_flush_pages(struct protection_domain *domain, ioasid_t pasid = IOMMU_NO_PASID; bool gn = false; + lockdep_assert_held(&domain->lock); + if (pdom_is_v2_pgtbl_mode(domain)) { gn = true; ret = domain_flush_pages_v2(domain, address, size); @@ -1495,6 +1488,8 @@ static void __domain_flush_pages(struct protection_domain *domain, void amd_iommu_domain_flush_pages(struct protection_domain *domain, u64 address, size_t size) { + lockdep_assert_held(&domain->lock); + if (likely(!amd_iommu_np_cache)) { __domain_flush_pages(domain, address, size); @@ -1593,6 +1588,8 @@ void amd_iommu_update_and_flush_device_table(struct protection_domain *domain) { struct iommu_dev_data *dev_data; + lockdep_assert_held(&domain->lock); + list_for_each_entry(dev_data, &domain->dev_list, list) { struct amd_iommu *iommu = rlookup_amd_iommu(dev_data->dev); @@ -1640,31 +1637,14 @@ int amd_iommu_complete_ppr(struct device *dev, u32 pasid, int status, int tag) * ****************************************************************************/ -static u16 domain_id_alloc(void) +static int pdom_id_alloc(void) { - unsigned long flags; - int id; - - spin_lock_irqsave(&pd_bitmap_lock, flags); - id = find_first_zero_bit(amd_iommu_pd_alloc_bitmap, MAX_DOMAIN_ID); - BUG_ON(id == 0); - if (id > 0 && id < MAX_DOMAIN_ID) - __set_bit(id, amd_iommu_pd_alloc_bitmap); - else - id = 0; - spin_unlock_irqrestore(&pd_bitmap_lock, flags); - - return id; + return ida_alloc_range(&pdom_ids, 1, MAX_DOMAIN_ID - 1, GFP_ATOMIC); } -static void domain_id_free(int id) +static void pdom_id_free(int id) { - unsigned long flags; - - spin_lock_irqsave(&pd_bitmap_lock, flags); - if (id > 0 && id < MAX_DOMAIN_ID) - __clear_bit(id, amd_iommu_pd_alloc_bitmap); - spin_unlock_irqrestore(&pd_bitmap_lock, flags); + ida_free(&pdom_ids, id); } static void free_gcr3_tbl_level1(u64 *tbl) @@ -1709,7 +1689,7 @@ static void free_gcr3_table(struct gcr3_tbl_info *gcr3_info) gcr3_info->glx = 0; /* Free per device domain ID */ - domain_id_free(gcr3_info->domid); + pdom_id_free(gcr3_info->domid); iommu_free_page(gcr3_info->gcr3_tbl); gcr3_info->gcr3_tbl = NULL; @@ -1736,6 +1716,7 @@ static int setup_gcr3_table(struct gcr3_tbl_info *gcr3_info, { int levels = get_gcr3_levels(pasids); int nid = iommu ? dev_to_node(&iommu->dev->dev) : NUMA_NO_NODE; + int domid; if (levels > amd_iommu_max_glx_val) return -EINVAL; @@ -1744,11 +1725,14 @@ static int setup_gcr3_table(struct gcr3_tbl_info *gcr3_info, return -EBUSY; /* Allocate per device domain ID */ - gcr3_info->domid = domain_id_alloc(); + domid = pdom_id_alloc(); + if (domid <= 0) + return -ENOSPC; + gcr3_info->domid = domid; gcr3_info->gcr3_tbl = iommu_alloc_page_node(nid, GFP_ATOMIC); if (gcr3_info->gcr3_tbl == NULL) { - domain_id_free(gcr3_info->domid); + pdom_id_free(domid); return -ENOMEM; } @@ -2019,57 +2003,69 @@ static void destroy_gcr3_table(struct iommu_dev_data *dev_data, free_gcr3_table(gcr3_info); } -static int do_attach(struct iommu_dev_data *dev_data, - struct protection_domain *domain) +static int pdom_attach_iommu(struct amd_iommu *iommu, + struct protection_domain *pdom) { - struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); - struct io_pgtable_cfg *cfg = &domain->iop.pgtbl.cfg; + struct pdom_iommu_info *pdom_iommu_info, *curr; + struct io_pgtable_cfg *cfg = &pdom->iop.pgtbl.cfg; + unsigned long flags; int ret = 0; - /* Update data structures */ - dev_data->domain = domain; - list_add(&dev_data->list, &domain->dev_list); + spin_lock_irqsave(&pdom->lock, flags); - /* Update NUMA Node ID */ - if (cfg->amd.nid == NUMA_NO_NODE) - cfg->amd.nid = dev_to_node(dev_data->dev); + pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index); + if (pdom_iommu_info) { + pdom_iommu_info->refcnt++; + goto out_unlock; + } - /* Do reference counting */ - domain->dev_iommu[iommu->index] += 1; - domain->dev_cnt += 1; + pdom_iommu_info = kzalloc(sizeof(*pdom_iommu_info), GFP_ATOMIC); + if (!pdom_iommu_info) { + ret = -ENOMEM; + goto out_unlock; + } - /* Setup GCR3 table */ - if (pdom_is_sva_capable(domain)) { - ret = init_gcr3_table(dev_data, domain); - if (ret) - return ret; + pdom_iommu_info->iommu = iommu; + pdom_iommu_info->refcnt = 1; + + curr = xa_cmpxchg(&pdom->iommu_array, iommu->index, + NULL, pdom_iommu_info, GFP_ATOMIC); + if (curr) { + kfree(pdom_iommu_info); + ret = -ENOSPC; + goto out_unlock; } + /* Update NUMA Node ID */ + if (cfg->amd.nid == NUMA_NO_NODE) + cfg->amd.nid = dev_to_node(&iommu->dev->dev); + +out_unlock: + spin_unlock_irqrestore(&pdom->lock, flags); return ret; } -static void do_detach(struct iommu_dev_data *dev_data) +static void pdom_detach_iommu(struct amd_iommu *iommu, + struct protection_domain *pdom) { - struct protection_domain *domain = dev_data->domain; - struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); + struct pdom_iommu_info *pdom_iommu_info; + unsigned long flags; - /* Clear DTE and flush the entry */ - dev_update_dte(dev_data, false); + spin_lock_irqsave(&pdom->lock, flags); - /* Flush IOTLB and wait for the flushes to finish */ - amd_iommu_domain_flush_all(domain); - - /* Clear GCR3 table */ - if (pdom_is_sva_capable(domain)) - destroy_gcr3_table(dev_data, domain); + pdom_iommu_info = xa_load(&pdom->iommu_array, iommu->index); + if (!pdom_iommu_info) { + spin_unlock_irqrestore(&pdom->lock, flags); + return; + } - /* Update data structures */ - dev_data->domain = NULL; - list_del(&dev_data->list); + pdom_iommu_info->refcnt--; + if (pdom_iommu_info->refcnt == 0) { + xa_erase(&pdom->iommu_array, iommu->index); + kfree(pdom_iommu_info); + } - /* decrease reference counters - needs to happen after the flushes */ - domain->dev_iommu[iommu->index] -= 1; - domain->dev_cnt -= 1; + spin_unlock_irqrestore(&pdom->lock, flags); } /* @@ -2079,28 +2075,60 @@ static void do_detach(struct iommu_dev_data *dev_data) static int attach_device(struct device *dev, struct protection_domain *domain) { - struct iommu_dev_data *dev_data; + struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); + struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); + struct pci_dev *pdev; unsigned long flags; int ret = 0; - spin_lock_irqsave(&domain->lock, flags); - - dev_data = dev_iommu_priv_get(dev); - - spin_lock(&dev_data->lock); + mutex_lock(&dev_data->mutex); if (dev_data->domain != NULL) { ret = -EBUSY; goto out; } - ret = do_attach(dev_data, domain); + /* Do reference counting */ + ret = pdom_attach_iommu(iommu, domain); + if (ret) + goto out; -out: - spin_unlock(&dev_data->lock); + /* Setup GCR3 table */ + if (pdom_is_sva_capable(domain)) { + ret = init_gcr3_table(dev_data, domain); + if (ret) { + pdom_detach_iommu(iommu, domain); + goto out; + } + } + + pdev = dev_is_pci(dev_data->dev) ? to_pci_dev(dev_data->dev) : NULL; + if (pdev && pdom_is_sva_capable(domain)) { + pdev_enable_caps(pdev); + + /* + * Device can continue to function even if IOPF + * enablement failed. Hence in error path just + * disable device PRI support. + */ + if (amd_iommu_iopf_add_device(iommu, dev_data)) + pdev_disable_cap_pri(pdev); + } else if (pdev) { + pdev_enable_cap_ats(pdev); + } + /* Update data structures */ + dev_data->domain = domain; + spin_lock_irqsave(&domain->lock, flags); + list_add(&dev_data->list, &domain->dev_list); spin_unlock_irqrestore(&domain->lock, flags); + /* Update device table */ + dev_update_dte(dev_data, true); + +out: + mutex_unlock(&dev_data->mutex); + return ret; } @@ -2110,14 +2138,11 @@ static int attach_device(struct device *dev, static void detach_device(struct device *dev) { struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); - struct protection_domain *domain = dev_data->domain; struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data); + struct protection_domain *domain = dev_data->domain; unsigned long flags; - bool ppr = dev_data->ppr; - - spin_lock_irqsave(&domain->lock, flags); - spin_lock(&dev_data->lock); + mutex_lock(&dev_data->mutex); /* * First check if the device is still attached. It might already @@ -2128,27 +2153,36 @@ static void detach_device(struct device *dev) if (WARN_ON(!dev_data->domain)) goto out; - if (ppr) { + /* Remove IOPF handler */ + if (dev_data->ppr) { iopf_queue_flush_dev(dev); - - /* Updated here so that it gets reflected in DTE */ - dev_data->ppr = false; + amd_iommu_iopf_remove_device(iommu, dev_data); } - do_detach(dev_data); + if (dev_is_pci(dev)) + pdev_disable_caps(to_pci_dev(dev)); -out: - spin_unlock(&dev_data->lock); + /* Clear DTE and flush the entry */ + dev_update_dte(dev_data, false); + /* Flush IOTLB and wait for the flushes to finish */ + spin_lock_irqsave(&domain->lock, flags); + amd_iommu_domain_flush_all(domain); + list_del(&dev_data->list); spin_unlock_irqrestore(&domain->lock, flags); - /* Remove IOPF handler */ - if (ppr) - amd_iommu_iopf_remove_device(iommu, dev_data); + /* Clear GCR3 table */ + if (pdom_is_sva_capable(domain)) + destroy_gcr3_table(dev_data, domain); - if (dev_is_pci(dev)) - pdev_disable_caps(to_pci_dev(dev)); + /* Update data structures */ + dev_data->domain = NULL; + /* decrease reference counters - needs to happen after the flushes */ + pdom_detach_iommu(iommu, domain); + +out: + mutex_unlock(&dev_data->mutex); } static struct iommu_device *amd_iommu_probe_device(struct device *dev) @@ -2205,17 +2239,14 @@ static struct iommu_device *amd_iommu_probe_device(struct device *dev) static void amd_iommu_release_device(struct device *dev) { - struct amd_iommu *iommu; - - if (!check_device(dev)) - return; + struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); - iommu = rlookup_amd_iommu(dev); - if (!iommu) - return; + WARN_ON(dev_data->domain); - amd_iommu_uninit_device(dev); - iommu_completion_wait(iommu); + /* + * We keep dev_data around for unplugged devices and reuse it when the + * device is re-plugged - not doing so would introduce a ton of races. + */ } static struct iommu_group *amd_iommu_device_group(struct device *dev) @@ -2236,70 +2267,53 @@ static struct iommu_group *amd_iommu_device_group(struct device *dev) * *****************************************************************************/ -static void cleanup_domain(struct protection_domain *domain) -{ - struct iommu_dev_data *entry; - - lockdep_assert_held(&domain->lock); - - if (!domain->dev_cnt) - return; - - while (!list_empty(&domain->dev_list)) { - entry = list_first_entry(&domain->dev_list, - struct iommu_dev_data, list); - BUG_ON(!entry->domain); - do_detach(entry); - } - WARN_ON(domain->dev_cnt != 0); -} - void protection_domain_free(struct protection_domain *domain) { WARN_ON(!list_empty(&domain->dev_list)); if (domain->domain.type & __IOMMU_DOMAIN_PAGING) free_io_pgtable_ops(&domain->iop.pgtbl.ops); - domain_id_free(domain->id); + pdom_id_free(domain->id); kfree(domain); } +static void protection_domain_init(struct protection_domain *domain, int nid) +{ + spin_lock_init(&domain->lock); + INIT_LIST_HEAD(&domain->dev_list); + INIT_LIST_HEAD(&domain->dev_data_list); + xa_init(&domain->iommu_array); + domain->iop.pgtbl.cfg.amd.nid = nid; +} + struct protection_domain *protection_domain_alloc(unsigned int type, int nid) { - struct io_pgtable_ops *pgtbl_ops; struct protection_domain *domain; - int pgtable; + int domid; domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; - domain->id = domain_id_alloc(); - if (!domain->id) - goto err_free; + domid = pdom_id_alloc(); + if (domid <= 0) { + kfree(domain); + return NULL; + } + domain->id = domid; - spin_lock_init(&domain->lock); - INIT_LIST_HEAD(&domain->dev_list); - INIT_LIST_HEAD(&domain->dev_data_list); - domain->iop.pgtbl.cfg.amd.nid = nid; + protection_domain_init(domain, nid); + + return domain; +} + +static int pdom_setup_pgtable(struct protection_domain *domain, + unsigned int type, int pgtable) +{ + struct io_pgtable_ops *pgtbl_ops; - switch (type) { /* No need to allocate io pgtable ops in passthrough mode */ - case IOMMU_DOMAIN_IDENTITY: - case IOMMU_DOMAIN_SVA: - return domain; - case IOMMU_DOMAIN_DMA: - pgtable = amd_iommu_pgtable; - break; - /* - * Force IOMMU v1 page table when allocating - * domain for pass-through devices. - */ - case IOMMU_DOMAIN_UNMANAGED: - pgtable = AMD_IOMMU_V1; - break; - default: - goto err_id; - } + if (!(type & __IOMMU_DOMAIN_PAGING)) + return 0; switch (pgtable) { case AMD_IOMMU_V1: @@ -2309,25 +2323,20 @@ struct protection_domain *protection_domain_alloc(unsigned int type, int nid) domain->pd_mode = PD_MODE_V2; break; default: - goto err_id; + return -EINVAL; } pgtbl_ops = alloc_io_pgtable_ops(pgtable, &domain->iop.pgtbl.cfg, domain); if (!pgtbl_ops) - goto err_id; + return -ENOMEM; - return domain; -err_id: - domain_id_free(domain->id); -err_free: - kfree(domain); - return NULL; + return 0; } -static inline u64 dma_max_address(void) +static inline u64 dma_max_address(int pgtable) { - if (amd_iommu_pgtable == AMD_IOMMU_V1) + if (pgtable == AMD_IOMMU_V1) return ~0ULL; /* V2 with 4/5 level page table */ @@ -2340,11 +2349,13 @@ static bool amd_iommu_hd_support(struct amd_iommu *iommu) } static struct iommu_domain *do_iommu_domain_alloc(unsigned int type, - struct device *dev, u32 flags) + struct device *dev, + u32 flags, int pgtable) { bool dirty_tracking = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING; struct protection_domain *domain; struct amd_iommu *iommu = NULL; + int ret; if (dev) iommu = get_amd_iommu_from_dev(dev); @@ -2356,16 +2367,20 @@ static struct iommu_domain *do_iommu_domain_alloc(unsigned int type, if (amd_iommu_snp_en && (type == IOMMU_DOMAIN_IDENTITY)) return ERR_PTR(-EINVAL); - if (dirty_tracking && !amd_iommu_hd_support(iommu)) - return ERR_PTR(-EOPNOTSUPP); - domain = protection_domain_alloc(type, dev ? dev_to_node(dev) : NUMA_NO_NODE); if (!domain) return ERR_PTR(-ENOMEM); + ret = pdom_setup_pgtable(domain, type, pgtable); + if (ret) { + pdom_id_free(domain->id); + kfree(domain); + return ERR_PTR(ret); + } + domain->domain.geometry.aperture_start = 0; - domain->domain.geometry.aperture_end = dma_max_address(); + domain->domain.geometry.aperture_end = dma_max_address(pgtable); domain->domain.geometry.force_aperture = true; domain->domain.pgsize_bitmap = domain->iop.pgtbl.cfg.pgsize_bitmap; @@ -2383,8 +2398,16 @@ static struct iommu_domain *do_iommu_domain_alloc(unsigned int type, static struct iommu_domain *amd_iommu_domain_alloc(unsigned int type) { struct iommu_domain *domain; + int pgtable = amd_iommu_pgtable; - domain = do_iommu_domain_alloc(type, NULL, 0); + /* + * Force IOMMU v1 page table when allocating + * domain for pass-through devices. + */ + if (type == IOMMU_DOMAIN_UNMANAGED) + pgtable = AMD_IOMMU_V1; + + domain = do_iommu_domain_alloc(type, NULL, 0, pgtable); if (IS_ERR(domain)) return NULL; @@ -2392,31 +2415,46 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned int type) } static struct iommu_domain * -amd_iommu_domain_alloc_user(struct device *dev, u32 flags, - struct iommu_domain *parent, - const struct iommu_user_data *user_data) +amd_iommu_domain_alloc_paging_flags(struct device *dev, u32 flags, + const struct iommu_user_data *user_data) { unsigned int type = IOMMU_DOMAIN_UNMANAGED; + struct amd_iommu *iommu = NULL; + const u32 supported_flags = IOMMU_HWPT_ALLOC_DIRTY_TRACKING | + IOMMU_HWPT_ALLOC_PASID; - if ((flags & ~IOMMU_HWPT_ALLOC_DIRTY_TRACKING) || parent || user_data) + if (dev) + iommu = get_amd_iommu_from_dev(dev); + + if ((flags & ~supported_flags) || user_data) return ERR_PTR(-EOPNOTSUPP); - return do_iommu_domain_alloc(type, dev, flags); -} + /* Allocate domain with v2 page table if IOMMU supports PASID. */ + if (flags & IOMMU_HWPT_ALLOC_PASID) { + if (!amd_iommu_pasid_supported()) + return ERR_PTR(-EOPNOTSUPP); -void amd_iommu_domain_free(struct iommu_domain *dom) -{ - struct protection_domain *domain; - unsigned long flags; + return do_iommu_domain_alloc(type, dev, flags, AMD_IOMMU_V2); + } - domain = to_pdomain(dom); + /* Allocate domain with v1 page table for dirty tracking */ + if (flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING) { + if (iommu && amd_iommu_hd_support(iommu)) { + return do_iommu_domain_alloc(type, dev, + flags, AMD_IOMMU_V1); + } - spin_lock_irqsave(&domain->lock, flags); + return ERR_PTR(-EOPNOTSUPP); + } - cleanup_domain(domain); + /* If nothing specific is required use the kernel commandline default */ + return do_iommu_domain_alloc(type, dev, 0, amd_iommu_pgtable); +} - spin_unlock_irqrestore(&domain->lock, flags); +void amd_iommu_domain_free(struct iommu_domain *dom) +{ + struct protection_domain *domain = to_pdomain(dom); protection_domain_free(domain); } @@ -2430,9 +2468,9 @@ static int blocked_domain_attach_device(struct iommu_domain *domain, detach_device(dev); /* Clear DTE and flush the entry */ - spin_lock(&dev_data->lock); + mutex_lock(&dev_data->mutex); dev_update_dte(dev_data, false); - spin_unlock(&dev_data->lock); + mutex_unlock(&dev_data->mutex); return 0; } @@ -2444,13 +2482,39 @@ static struct iommu_domain blocked_domain = { } }; +static struct protection_domain identity_domain; + +static const struct iommu_domain_ops identity_domain_ops = { + .attach_dev = amd_iommu_attach_device, +}; + +void amd_iommu_init_identity_domain(void) +{ + struct iommu_domain *domain = &identity_domain.domain; + + domain->type = IOMMU_DOMAIN_IDENTITY; + domain->ops = &identity_domain_ops; + domain->owner = &amd_iommu_ops; + + identity_domain.id = pdom_id_alloc(); + + protection_domain_init(&identity_domain, NUMA_NO_NODE); +} + +/* Same as blocked domain except it supports only ops->attach_dev() */ +static struct iommu_domain release_domain = { + .type = IOMMU_DOMAIN_BLOCKED, + .ops = &(const struct iommu_domain_ops) { + .attach_dev = blocked_domain_attach_device, + } +}; + static int amd_iommu_attach_device(struct iommu_domain *dom, struct device *dev) { struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev); struct protection_domain *domain = to_pdomain(dom); struct amd_iommu *iommu = get_amd_iommu_from_dev(dev); - struct pci_dev *pdev; int ret; /* @@ -2483,24 +2547,6 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, } #endif - pdev = dev_is_pci(dev_data->dev) ? to_pci_dev(dev_data->dev) : NULL; - if (pdev && pdom_is_sva_capable(domain)) { - pdev_enable_caps(pdev); - - /* - * Device can continue to function even if IOPF - * enablement failed. Hence in error path just - * disable device PRI support. - */ - if (amd_iommu_iopf_add_device(iommu, dev_data)) - pdev_disable_cap_pri(pdev); - } else if (pdev) { - pdev_enable_cap_ats(pdev); - } - - /* Update device table */ - dev_update_dte(dev_data, true); - return ret; } @@ -2842,8 +2888,10 @@ static int amd_iommu_dev_disable_feature(struct device *dev, const struct iommu_ops amd_iommu_ops = { .capable = amd_iommu_capable, .blocked_domain = &blocked_domain, + .release_domain = &release_domain, + .identity_domain = &identity_domain.domain, .domain_alloc = amd_iommu_domain_alloc, - .domain_alloc_user = amd_iommu_domain_alloc_user, + .domain_alloc_paging_flags = amd_iommu_domain_alloc_paging_flags, .domain_alloc_sva = amd_iommu_domain_alloc_sva, .probe_device = amd_iommu_probe_device, .release_device = amd_iommu_release_device, @@ -2890,7 +2938,7 @@ static void iommu_flush_irt_and_complete(struct amd_iommu *iommu, u16 devid) return; build_inv_irt(&cmd, devid); - data = atomic64_add_return(1, &iommu->cmd_sem_val); + data = atomic64_inc_return(&iommu->cmd_sem_val); build_completion_wait(&cmd2, iommu, data); raw_spin_lock_irqsave(&iommu->lock, flags); diff --git a/drivers/iommu/amd/pasid.c b/drivers/iommu/amd/pasid.c index 0657b9373be547..8c73a30c2800e7 100644 --- a/drivers/iommu/amd/pasid.c +++ b/drivers/iommu/amd/pasid.c @@ -100,7 +100,8 @@ static const struct mmu_notifier_ops sva_mn = { }; int iommu_sva_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid) + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) { struct pdom_dev_data *pdom_dev_data; struct protection_domain *sva_pdom = to_pdomain(domain); @@ -108,6 +109,9 @@ int iommu_sva_set_dev_pasid(struct iommu_domain *domain, unsigned long flags; int ret = -EINVAL; + if (old) + return -EOPNOTSUPP; + /* PASID zero is used for requests from the I/O device without PASID */ if (!is_pasid_valid(dev_data, pasid)) return ret; diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c index eb1e62cd499a58..95ba3caeb40177 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-dart.c @@ -1352,7 +1352,7 @@ static struct platform_driver apple_dart_driver = { .pm = pm_sleep_ptr(&apple_dart_pm_ops), }, .probe = apple_dart_probe, - .remove_new = apple_dart_remove, + .remove = apple_dart_remove, }; module_platform_driver(apple_dart_driver); diff --git a/drivers/iommu/arm/arm-smmu-v3/Makefile b/drivers/iommu/arm/arm-smmu-v3/Makefile index dc98c88b48c827..493a659cc66bb2 100644 --- a/drivers/iommu/arm/arm-smmu-v3/Makefile +++ b/drivers/iommu/arm/arm-smmu-v3/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_ARM_SMMU_V3) += arm_smmu_v3.o arm_smmu_v3-y := arm-smmu-v3.o +arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_IOMMUFD) += arm-smmu-v3-iommufd.o arm_smmu_v3-$(CONFIG_ARM_SMMU_V3_SVA) += arm-smmu-v3-sva.o arm_smmu_v3-$(CONFIG_TEGRA241_CMDQV) += tegra241-cmdqv.o diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c new file mode 100644 index 00000000000000..c7cc613050d933 --- /dev/null +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-iommufd.c @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES + */ + +#include + +#include "arm-smmu-v3.h" + +void *arm_smmu_hw_info(struct device *dev, u32 *length, u32 *type) +{ + struct arm_smmu_master *master = dev_iommu_priv_get(dev); + struct iommu_hw_info_arm_smmuv3 *info; + u32 __iomem *base_idr; + unsigned int i; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + + base_idr = master->smmu->base + ARM_SMMU_IDR0; + for (i = 0; i <= 5; i++) + info->idr[i] = readl_relaxed(base_idr + i); + info->iidr = readl_relaxed(master->smmu->base + ARM_SMMU_IIDR); + info->aidr = readl_relaxed(master->smmu->base + ARM_SMMU_AIDR); + + *length = sizeof(*info); + *type = IOMMU_HW_INFO_TYPE_ARM_SMMUV3; + + return info; +} + +static void arm_smmu_make_nested_cd_table_ste( + struct arm_smmu_ste *target, struct arm_smmu_master *master, + struct arm_smmu_nested_domain *nested_domain, bool ats_enabled) +{ + arm_smmu_make_s2_domain_ste( + target, master, nested_domain->vsmmu->s2_parent, ats_enabled); + + target->data[0] = cpu_to_le64(STRTAB_STE_0_V | + FIELD_PREP(STRTAB_STE_0_CFG, + STRTAB_STE_0_CFG_NESTED)); + target->data[0] |= nested_domain->ste[0] & + ~cpu_to_le64(STRTAB_STE_0_CFG); + target->data[1] |= nested_domain->ste[1]; +} + +/* + * Create a physical STE from the virtual STE that userspace provided when it + * created the nested domain. Using the vSTE userspace can request: + * - Non-valid STE + * - Abort STE + * - Bypass STE (install the S2, no CD table) + * - CD table STE (install the S2 and the userspace CD table) + */ +static void arm_smmu_make_nested_domain_ste( + struct arm_smmu_ste *target, struct arm_smmu_master *master, + struct arm_smmu_nested_domain *nested_domain, bool ats_enabled) +{ + unsigned int cfg = + FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(nested_domain->ste[0])); + + /* + * Userspace can request a non-valid STE through the nesting interface. + * We relay that into an abort physical STE with the intention that + * C_BAD_STE for this SID can be generated to userspace. + */ + if (!(nested_domain->ste[0] & cpu_to_le64(STRTAB_STE_0_V))) + cfg = STRTAB_STE_0_CFG_ABORT; + + switch (cfg) { + case STRTAB_STE_0_CFG_S1_TRANS: + arm_smmu_make_nested_cd_table_ste(target, master, nested_domain, + ats_enabled); + break; + case STRTAB_STE_0_CFG_BYPASS: + arm_smmu_make_s2_domain_ste(target, master, + nested_domain->vsmmu->s2_parent, + ats_enabled); + break; + case STRTAB_STE_0_CFG_ABORT: + default: + arm_smmu_make_abort_ste(target); + break; + } +} + +static int arm_smmu_attach_dev_nested(struct iommu_domain *domain, + struct device *dev) +{ + struct arm_smmu_nested_domain *nested_domain = + to_smmu_nested_domain(domain); + struct arm_smmu_master *master = dev_iommu_priv_get(dev); + struct arm_smmu_attach_state state = { + .master = master, + .old_domain = iommu_get_domain_for_dev(dev), + .ssid = IOMMU_NO_PASID, + }; + struct arm_smmu_ste ste; + int ret; + + if (nested_domain->vsmmu->smmu != master->smmu) + return -EINVAL; + if (arm_smmu_ssids_in_use(&master->cd_table)) + return -EBUSY; + + mutex_lock(&arm_smmu_asid_lock); + /* + * The VM has to control the actual ATS state at the PCI device because + * we forward the invalidations directly from the VM. If the VM doesn't + * think ATS is on it will not generate ATC flushes and the ATC will + * become incoherent. Since we can't access the actual virtual PCI ATS + * config bit here base this off the EATS value in the STE. If the EATS + * is set then the VM must generate ATC flushes. + */ + state.disable_ats = !nested_domain->enable_ats; + ret = arm_smmu_attach_prepare(&state, domain); + if (ret) { + mutex_unlock(&arm_smmu_asid_lock); + return ret; + } + + arm_smmu_make_nested_domain_ste(&ste, master, nested_domain, + state.ats_enabled); + arm_smmu_install_ste_for_dev(master, &ste); + arm_smmu_attach_commit(&state); + mutex_unlock(&arm_smmu_asid_lock); + return 0; +} + +static void arm_smmu_domain_nested_free(struct iommu_domain *domain) +{ + kfree(to_smmu_nested_domain(domain)); +} + +static const struct iommu_domain_ops arm_smmu_nested_ops = { + .attach_dev = arm_smmu_attach_dev_nested, + .free = arm_smmu_domain_nested_free, +}; + +static int arm_smmu_validate_vste(struct iommu_hwpt_arm_smmuv3 *arg, + bool *enable_ats) +{ + unsigned int eats; + unsigned int cfg; + + if (!(arg->ste[0] & cpu_to_le64(STRTAB_STE_0_V))) { + memset(arg->ste, 0, sizeof(arg->ste)); + return 0; + } + + /* EIO is reserved for invalid STE data. */ + if ((arg->ste[0] & ~STRTAB_STE_0_NESTING_ALLOWED) || + (arg->ste[1] & ~STRTAB_STE_1_NESTING_ALLOWED)) + return -EIO; + + cfg = FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(arg->ste[0])); + if (cfg != STRTAB_STE_0_CFG_ABORT && cfg != STRTAB_STE_0_CFG_BYPASS && + cfg != STRTAB_STE_0_CFG_S1_TRANS) + return -EIO; + + /* + * Only Full ATS or ATS UR is supported + * The EATS field will be set by arm_smmu_make_nested_domain_ste() + */ + eats = FIELD_GET(STRTAB_STE_1_EATS, le64_to_cpu(arg->ste[1])); + arg->ste[1] &= ~cpu_to_le64(STRTAB_STE_1_EATS); + if (eats != STRTAB_STE_1_EATS_ABT && eats != STRTAB_STE_1_EATS_TRANS) + return -EIO; + + if (cfg == STRTAB_STE_0_CFG_S1_TRANS) + *enable_ats = (eats == STRTAB_STE_1_EATS_TRANS); + return 0; +} + +static struct iommu_domain * +arm_vsmmu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags, + const struct iommu_user_data *user_data) +{ + struct arm_vsmmu *vsmmu = container_of(viommu, struct arm_vsmmu, core); + const u32 SUPPORTED_FLAGS = IOMMU_HWPT_FAULT_ID_VALID; + struct arm_smmu_nested_domain *nested_domain; + struct iommu_hwpt_arm_smmuv3 arg; + bool enable_ats = false; + int ret; + + /* + * Faults delivered to the nested domain are faults that originated by + * the S1 in the domain. The core code will match all PASIDs when + * delivering the fault due to user_pasid_table + */ + if (flags & ~SUPPORTED_FLAGS) + return ERR_PTR(-EOPNOTSUPP); + + ret = iommu_copy_struct_from_user(&arg, user_data, + IOMMU_HWPT_DATA_ARM_SMMUV3, ste); + if (ret) + return ERR_PTR(ret); + + ret = arm_smmu_validate_vste(&arg, &enable_ats); + if (ret) + return ERR_PTR(ret); + + nested_domain = kzalloc(sizeof(*nested_domain), GFP_KERNEL_ACCOUNT); + if (!nested_domain) + return ERR_PTR(-ENOMEM); + + nested_domain->domain.type = IOMMU_DOMAIN_NESTED; + nested_domain->domain.ops = &arm_smmu_nested_ops; + nested_domain->enable_ats = enable_ats; + nested_domain->vsmmu = vsmmu; + nested_domain->ste[0] = arg.ste[0]; + nested_domain->ste[1] = arg.ste[1] & ~cpu_to_le64(STRTAB_STE_1_EATS); + + return &nested_domain->domain; +} + +static int arm_vsmmu_vsid_to_sid(struct arm_vsmmu *vsmmu, u32 vsid, u32 *sid) +{ + struct arm_smmu_master *master; + struct device *dev; + int ret = 0; + + xa_lock(&vsmmu->core.vdevs); + dev = iommufd_viommu_find_dev(&vsmmu->core, (unsigned long)vsid); + if (!dev) { + ret = -EIO; + goto unlock; + } + master = dev_iommu_priv_get(dev); + + /* At this moment, iommufd only supports PCI device that has one SID */ + if (sid) + *sid = master->streams[0].id; +unlock: + xa_unlock(&vsmmu->core.vdevs); + return ret; +} + +/* This is basically iommu_viommu_arm_smmuv3_invalidate in u64 for conversion */ +struct arm_vsmmu_invalidation_cmd { + union { + u64 cmd[2]; + struct iommu_viommu_arm_smmuv3_invalidate ucmd; + }; +}; + +/* + * Convert, in place, the raw invalidation command into an internal format that + * can be passed to arm_smmu_cmdq_issue_cmdlist(). Internally commands are + * stored in CPU endian. + * + * Enforce the VMID or SID on the command. + */ +static int arm_vsmmu_convert_user_cmd(struct arm_vsmmu *vsmmu, + struct arm_vsmmu_invalidation_cmd *cmd) +{ + /* Commands are le64 stored in u64 */ + cmd->cmd[0] = le64_to_cpu(cmd->ucmd.cmd[0]); + cmd->cmd[1] = le64_to_cpu(cmd->ucmd.cmd[1]); + + switch (cmd->cmd[0] & CMDQ_0_OP) { + case CMDQ_OP_TLBI_NSNH_ALL: + /* Convert to NH_ALL */ + cmd->cmd[0] = CMDQ_OP_TLBI_NH_ALL | + FIELD_PREP(CMDQ_TLBI_0_VMID, vsmmu->vmid); + cmd->cmd[1] = 0; + break; + case CMDQ_OP_TLBI_NH_VA: + case CMDQ_OP_TLBI_NH_VAA: + case CMDQ_OP_TLBI_NH_ALL: + case CMDQ_OP_TLBI_NH_ASID: + cmd->cmd[0] &= ~CMDQ_TLBI_0_VMID; + cmd->cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, vsmmu->vmid); + break; + case CMDQ_OP_ATC_INV: + case CMDQ_OP_CFGI_CD: + case CMDQ_OP_CFGI_CD_ALL: { + u32 sid, vsid = FIELD_GET(CMDQ_CFGI_0_SID, cmd->cmd[0]); + + if (arm_vsmmu_vsid_to_sid(vsmmu, vsid, &sid)) + return -EIO; + cmd->cmd[0] &= ~CMDQ_CFGI_0_SID; + cmd->cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SID, sid); + break; + } + default: + return -EIO; + } + return 0; +} + +static int arm_vsmmu_cache_invalidate(struct iommufd_viommu *viommu, + struct iommu_user_data_array *array) +{ + struct arm_vsmmu *vsmmu = container_of(viommu, struct arm_vsmmu, core); + struct arm_smmu_device *smmu = vsmmu->smmu; + struct arm_vsmmu_invalidation_cmd *last; + struct arm_vsmmu_invalidation_cmd *cmds; + struct arm_vsmmu_invalidation_cmd *cur; + struct arm_vsmmu_invalidation_cmd *end; + int ret; + + cmds = kcalloc(array->entry_num, sizeof(*cmds), GFP_KERNEL); + if (!cmds) + return -ENOMEM; + cur = cmds; + end = cmds + array->entry_num; + + static_assert(sizeof(*cmds) == 2 * sizeof(u64)); + ret = iommu_copy_struct_from_full_user_array( + cmds, sizeof(*cmds), array, + IOMMU_VIOMMU_INVALIDATE_DATA_ARM_SMMUV3); + if (ret) + goto out; + + last = cmds; + while (cur != end) { + ret = arm_vsmmu_convert_user_cmd(vsmmu, cur); + if (ret) + goto out; + + /* FIXME work in blocks of CMDQ_BATCH_ENTRIES and copy each block? */ + cur++; + if (cur != end && (cur - last) != CMDQ_BATCH_ENTRIES - 1) + continue; + + /* FIXME always uses the main cmdq rather than trying to group by type */ + ret = arm_smmu_cmdq_issue_cmdlist(smmu, &smmu->cmdq, last->cmd, + cur - last, true); + if (ret) { + cur--; + goto out; + } + last = cur; + } +out: + array->entry_num = cur - cmds; + kfree(cmds); + return ret; +} + +static const struct iommufd_viommu_ops arm_vsmmu_ops = { + .alloc_domain_nested = arm_vsmmu_alloc_domain_nested, + .cache_invalidate = arm_vsmmu_cache_invalidate, +}; + +struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev, + struct iommu_domain *parent, + struct iommufd_ctx *ictx, + unsigned int viommu_type) +{ + struct arm_smmu_device *smmu = + iommu_get_iommu_dev(dev, struct arm_smmu_device, iommu); + struct arm_smmu_master *master = dev_iommu_priv_get(dev); + struct arm_smmu_domain *s2_parent = to_smmu_domain(parent); + struct arm_vsmmu *vsmmu; + + if (viommu_type != IOMMU_VIOMMU_TYPE_ARM_SMMUV3) + return ERR_PTR(-EOPNOTSUPP); + + if (!(smmu->features & ARM_SMMU_FEAT_NESTING)) + return ERR_PTR(-EOPNOTSUPP); + + if (s2_parent->smmu != master->smmu) + return ERR_PTR(-EINVAL); + + /* + * FORCE_SYNC is not set with FEAT_NESTING. Some study of the exact HW + * defect is needed to determine if arm_vsmmu_cache_invalidate() needs + * any change to remove this. + */ + if (WARN_ON(smmu->options & ARM_SMMU_OPT_CMDQ_FORCE_SYNC)) + return ERR_PTR(-EOPNOTSUPP); + + /* + * Must support some way to prevent the VM from bypassing the cache + * because VFIO currently does not do any cache maintenance. canwbs + * indicates the device is fully coherent and no cache maintenance is + * ever required, even for PCI No-Snoop. S2FWB means the S1 can't make + * things non-coherent using the memattr, but No-Snoop behavior is not + * effected. + */ + if (!arm_smmu_master_canwbs(master) && + !(smmu->features & ARM_SMMU_FEAT_S2FWB)) + return ERR_PTR(-EOPNOTSUPP); + + vsmmu = iommufd_viommu_alloc(ictx, struct arm_vsmmu, core, + &arm_vsmmu_ops); + if (IS_ERR(vsmmu)) + return ERR_CAST(vsmmu); + + vsmmu->smmu = smmu; + vsmmu->s2_parent = s2_parent; + /* FIXME Move VMID allocation from the S2 domain allocation to here */ + vsmmu->vmid = s2_parent->s2_cfg.vmid; + + return &vsmmu->core; +} + +MODULE_IMPORT_NS("IOMMUFD"); diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c index a7c36654dee5a5..1d3e7156977565 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c @@ -332,7 +332,8 @@ void arm_smmu_sva_notifier_synchronize(void) } static int arm_smmu_sva_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t id) + struct device *dev, ioasid_t id, + struct iommu_domain *old) { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_master *master = dev_iommu_priv_get(dev); @@ -348,7 +349,7 @@ static int arm_smmu_sva_set_dev_pasid(struct iommu_domain *domain, * get reassigned */ arm_smmu_make_sva_cd(&target, master, domain->mm, smmu_domain->cd.asid); - ret = arm_smmu_set_pasid(master, smmu_domain, id, &target); + ret = arm_smmu_set_pasid(master, smmu_domain, id, &target, old); mmput(domain->mm); return ret; diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c index 84baa021370a86..d2671bfd37981b 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-test.c @@ -607,6 +607,6 @@ static struct kunit_suite arm_smmu_v3_test_module = { }; kunit_test_suites(&arm_smmu_v3_test_module); -MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); MODULE_DESCRIPTION("KUnit tests for arm-smmu-v3 driver"); MODULE_LICENSE("GPL v2"); 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 353fea58cd318a..a5c7002ff75bb0 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -295,6 +295,7 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent) case CMDQ_OP_TLBI_NH_ASID: cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid); fallthrough; + case CMDQ_OP_TLBI_NH_ALL: case CMDQ_OP_TLBI_S12_VMALL: cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid); break; @@ -765,9 +766,9 @@ static void arm_smmu_cmdq_write_entries(struct arm_smmu_cmdq *cmdq, u64 *cmds, * insert their own list of commands then all of the commands from one * CPU will appear before any of the commands from the other CPU. */ -static int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu, - struct arm_smmu_cmdq *cmdq, - u64 *cmds, int n, bool sync) +int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu, + struct arm_smmu_cmdq *cmdq, u64 *cmds, int n, + bool sync) { u64 cmd_sync[CMDQ_ENT_DWORDS]; u32 prod; @@ -1045,7 +1046,8 @@ void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits) /* S2 translates */ if (cfg & BIT(1)) { used_bits[1] |= - cpu_to_le64(STRTAB_STE_1_EATS | STRTAB_STE_1_SHCFG); + cpu_to_le64(STRTAB_STE_1_S2FWB | STRTAB_STE_1_EATS | + STRTAB_STE_1_SHCFG); used_bits[2] |= cpu_to_le64(STRTAB_STE_2_S2VMID | STRTAB_STE_2_VTCR | STRTAB_STE_2_S2AA64 | STRTAB_STE_2_S2ENDI | @@ -1549,7 +1551,6 @@ static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid, } } -VISIBLE_IF_KUNIT void arm_smmu_make_abort_ste(struct arm_smmu_ste *target) { memset(target, 0, sizeof(*target)); @@ -1632,7 +1633,6 @@ void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target, } EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_cdtable_ste); -VISIBLE_IF_KUNIT void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target, struct arm_smmu_master *master, struct arm_smmu_domain *smmu_domain, @@ -1655,6 +1655,8 @@ void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target, FIELD_PREP(STRTAB_STE_1_EATS, ats_enabled ? STRTAB_STE_1_EATS_TRANS : 0)); + if (pgtbl_cfg->quirks & IO_PGTABLE_QUIRK_ARM_S2FWB) + target->data[1] |= cpu_to_le64(STRTAB_STE_1_S2FWB); if (smmu->features & ARM_SMMU_FEAT_ATTR_TYPES_OVR) target->data[1] |= cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG, STRTAB_STE_1_SHCFG_INCOMING)); @@ -2105,7 +2107,16 @@ int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain, if (!master->ats_enabled) continue; - arm_smmu_atc_inv_to_cmd(master_domain->ssid, iova, size, &cmd); + if (master_domain->nested_ats_flush) { + /* + * If a S2 used as a nesting parent is changed we have + * no option but to completely flush the ATC. + */ + arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd); + } else { + arm_smmu_atc_inv_to_cmd(master_domain->ssid, iova, size, + &cmd); + } for (i = 0; i < master->num_streams; i++) { cmd.atc.sid = master->streams[i].id; @@ -2232,6 +2243,15 @@ static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size, } __arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain); + if (smmu_domain->nest_parent) { + /* + * When the S2 domain changes all the nested S1 ASIDs have to be + * flushed too. + */ + cmd.opcode = CMDQ_OP_TLBI_NH_ALL; + arm_smmu_cmdq_issue_cmd_with_sync(smmu_domain->smmu, &cmd); + } + /* * Unfortunately, this can't be leaf-only since we may have * zapped an entire table. @@ -2293,6 +2313,8 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap) case IOMMU_CAP_CACHE_COHERENCY: /* Assume that a coherent TCU implies coherent TBUs */ return master->smmu->features & ARM_SMMU_FEAT_COHERENCY; + case IOMMU_CAP_ENFORCE_CACHE_COHERENCY: + return arm_smmu_master_canwbs(master); case IOMMU_CAP_NOEXEC: case IOMMU_CAP_DEFERRED_FLUSH: return true; @@ -2303,6 +2325,26 @@ static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap) } } +static bool arm_smmu_enforce_cache_coherency(struct iommu_domain *domain) +{ + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct arm_smmu_master_domain *master_domain; + unsigned long flags; + bool ret = true; + + spin_lock_irqsave(&smmu_domain->devices_lock, flags); + list_for_each_entry(master_domain, &smmu_domain->devices, + devices_elm) { + if (!arm_smmu_master_canwbs(master_domain->master)) { + ret = false; + break; + } + } + smmu_domain->enforce_cache_coherency = ret; + spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); + return ret; +} + struct arm_smmu_domain *arm_smmu_domain_alloc(void) { struct arm_smmu_domain *smmu_domain; @@ -2442,6 +2484,9 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain, pgtbl_cfg.oas = smmu->oas; fmt = ARM_64_LPAE_S2; finalise_stage_fn = arm_smmu_domain_finalise_s2; + if ((smmu->features & ARM_SMMU_FEAT_S2FWB) && + (flags & IOMMU_HWPT_ALLOC_NEST_PARENT)) + pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_ARM_S2FWB; break; default: return -EINVAL; @@ -2483,8 +2528,8 @@ arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid) } } -static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master, - const struct arm_smmu_ste *target) +void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master, + const struct arm_smmu_ste *target) { int i, j; struct arm_smmu_device *smmu = master->smmu; @@ -2595,7 +2640,7 @@ static void arm_smmu_disable_pasid(struct arm_smmu_master *master) static struct arm_smmu_master_domain * arm_smmu_find_master_domain(struct arm_smmu_domain *smmu_domain, struct arm_smmu_master *master, - ioasid_t ssid) + ioasid_t ssid, bool nested_ats_flush) { struct arm_smmu_master_domain *master_domain; @@ -2604,7 +2649,8 @@ arm_smmu_find_master_domain(struct arm_smmu_domain *smmu_domain, list_for_each_entry(master_domain, &smmu_domain->devices, devices_elm) { if (master_domain->master == master && - master_domain->ssid == ssid) + master_domain->ssid == ssid && + master_domain->nested_ats_flush == nested_ats_flush) return master_domain; } return NULL; @@ -2624,6 +2670,8 @@ to_smmu_domain_devices(struct iommu_domain *domain) if ((domain->type & __IOMMU_DOMAIN_PAGING) || domain->type == IOMMU_DOMAIN_SVA) return to_smmu_domain(domain); + if (domain->type == IOMMU_DOMAIN_NESTED) + return to_smmu_nested_domain(domain)->vsmmu->s2_parent; return NULL; } @@ -2633,13 +2681,18 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master, { struct arm_smmu_domain *smmu_domain = to_smmu_domain_devices(domain); struct arm_smmu_master_domain *master_domain; + bool nested_ats_flush = false; unsigned long flags; if (!smmu_domain) return; + if (domain->type == IOMMU_DOMAIN_NESTED) + nested_ats_flush = to_smmu_nested_domain(domain)->enable_ats; + spin_lock_irqsave(&smmu_domain->devices_lock, flags); - master_domain = arm_smmu_find_master_domain(smmu_domain, master, ssid); + master_domain = arm_smmu_find_master_domain(smmu_domain, master, ssid, + nested_ats_flush); if (master_domain) { list_del(&master_domain->devices_elm); kfree(master_domain); @@ -2649,16 +2702,6 @@ static void arm_smmu_remove_master_domain(struct arm_smmu_master *master, spin_unlock_irqrestore(&smmu_domain->devices_lock, flags); } -struct arm_smmu_attach_state { - /* Inputs */ - struct iommu_domain *old_domain; - struct arm_smmu_master *master; - bool cd_needs_ats; - ioasid_t ssid; - /* Resulting state */ - bool ats_enabled; -}; - /* * Start the sequence to attach a domain to a master. The sequence contains three * steps: @@ -2679,8 +2722,8 @@ struct arm_smmu_attach_state { * new_domain can be a non-paging domain. In this case ATS will not be enabled, * and invalidations won't be tracked. */ -static int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state, - struct iommu_domain *new_domain) +int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state, + struct iommu_domain *new_domain) { struct arm_smmu_master *master = state->master; struct arm_smmu_master_domain *master_domain; @@ -2706,7 +2749,8 @@ static int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state, * enabled if we have arm_smmu_domain, those always have page * tables. */ - state->ats_enabled = arm_smmu_ats_supported(master); + state->ats_enabled = !state->disable_ats && + arm_smmu_ats_supported(master); } if (smmu_domain) { @@ -2715,6 +2759,9 @@ static int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state, return -ENOMEM; master_domain->master = master; master_domain->ssid = state->ssid; + if (new_domain->type == IOMMU_DOMAIN_NESTED) + master_domain->nested_ats_flush = + to_smmu_nested_domain(new_domain)->enable_ats; /* * During prepare we want the current smmu_domain and new @@ -2731,6 +2778,14 @@ static int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state, * one of them. */ spin_lock_irqsave(&smmu_domain->devices_lock, flags); + if (smmu_domain->enforce_cache_coherency && + !arm_smmu_master_canwbs(master)) { + spin_unlock_irqrestore(&smmu_domain->devices_lock, + flags); + kfree(master_domain); + return -EINVAL; + } + if (state->ats_enabled) atomic_inc(&smmu_domain->nr_ats_masters); list_add(&master_domain->devices_elm, &smmu_domain->devices); @@ -2754,7 +2809,7 @@ static int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state, * completes synchronizing the PCI device's ATC and finishes manipulating the * smmu_domain->devices list. */ -static void arm_smmu_attach_commit(struct arm_smmu_attach_state *state) +void arm_smmu_attach_commit(struct arm_smmu_attach_state *state) { struct arm_smmu_master *master = state->master; @@ -2856,7 +2911,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) } static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t id) + struct device *dev, ioasid_t id, + struct iommu_domain *old) { struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_master *master = dev_iommu_priv_get(dev); @@ -2882,7 +2938,7 @@ static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain, */ arm_smmu_make_s1_cd(&target_cd, master, smmu_domain); return arm_smmu_set_pasid(master, to_smmu_domain(domain), id, - &target_cd); + &target_cd, old); } static void arm_smmu_update_ste(struct arm_smmu_master *master, @@ -2912,16 +2968,13 @@ static void arm_smmu_update_ste(struct arm_smmu_master *master, int arm_smmu_set_pasid(struct arm_smmu_master *master, struct arm_smmu_domain *smmu_domain, ioasid_t pasid, - struct arm_smmu_cd *cd) + struct arm_smmu_cd *cd, struct iommu_domain *old) { struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev); struct arm_smmu_attach_state state = { .master = master, - /* - * For now the core code prevents calling this when a domain is - * already attached, no need to set old_domain. - */ .ssid = pasid, + .old_domain = old, }; struct arm_smmu_cd *cdptr; int ret; @@ -3079,24 +3132,37 @@ static struct iommu_domain arm_smmu_blocked_domain = { }; static struct iommu_domain * -arm_smmu_domain_alloc_user(struct device *dev, u32 flags, - struct iommu_domain *parent, - const struct iommu_user_data *user_data) +arm_smmu_domain_alloc_paging_flags(struct device *dev, u32 flags, + const struct iommu_user_data *user_data) { struct arm_smmu_master *master = dev_iommu_priv_get(dev); - const u32 PAGING_FLAGS = IOMMU_HWPT_ALLOC_DIRTY_TRACKING; + const u32 PAGING_FLAGS = IOMMU_HWPT_ALLOC_DIRTY_TRACKING | + IOMMU_HWPT_ALLOC_PASID | + IOMMU_HWPT_ALLOC_NEST_PARENT; struct arm_smmu_domain *smmu_domain; int ret; if (flags & ~PAGING_FLAGS) return ERR_PTR(-EOPNOTSUPP); - if (parent || user_data) + if (user_data) return ERR_PTR(-EOPNOTSUPP); + if (flags & IOMMU_HWPT_ALLOC_PASID) + return arm_smmu_domain_alloc_paging(dev); + smmu_domain = arm_smmu_domain_alloc(); if (IS_ERR(smmu_domain)) return ERR_CAST(smmu_domain); + if (flags & IOMMU_HWPT_ALLOC_NEST_PARENT) { + if (!(master->smmu->features & ARM_SMMU_FEAT_NESTING)) { + ret = -EOPNOTSUPP; + goto err_free; + } + smmu_domain->stage = ARM_SMMU_DOMAIN_S2; + smmu_domain->nest_parent = true; + } + smmu_domain->domain.type = IOMMU_DOMAIN_UNMANAGED; smmu_domain->domain.ops = arm_smmu_ops.default_domain_ops; ret = arm_smmu_domain_finalise(smmu_domain, master->smmu, flags); @@ -3378,21 +3444,6 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev) return group; } -static int arm_smmu_enable_nesting(struct iommu_domain *domain) -{ - struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - int ret = 0; - - mutex_lock(&smmu_domain->init_mutex); - if (smmu_domain->smmu) - ret = -EPERM; - else - smmu_domain->stage = ARM_SMMU_DOMAIN_S2; - mutex_unlock(&smmu_domain->init_mutex); - - return ret; -} - static int arm_smmu_of_xlate(struct device *dev, const struct of_phandle_args *args) { @@ -3491,9 +3542,10 @@ static struct iommu_ops arm_smmu_ops = { .identity_domain = &arm_smmu_identity_domain, .blocked_domain = &arm_smmu_blocked_domain, .capable = arm_smmu_capable, + .hw_info = arm_smmu_hw_info, .domain_alloc_paging = arm_smmu_domain_alloc_paging, .domain_alloc_sva = arm_smmu_sva_domain_alloc, - .domain_alloc_user = arm_smmu_domain_alloc_user, + .domain_alloc_paging_flags = arm_smmu_domain_alloc_paging_flags, .probe_device = arm_smmu_probe_device, .release_device = arm_smmu_release_device, .device_group = arm_smmu_device_group, @@ -3504,17 +3556,19 @@ static struct iommu_ops arm_smmu_ops = { .dev_disable_feat = arm_smmu_dev_disable_feature, .page_response = arm_smmu_page_response, .def_domain_type = arm_smmu_def_domain_type, + .viommu_alloc = arm_vsmmu_alloc, + .user_pasid_table = 1, .pgsize_bitmap = -1UL, /* Restricted during device attach */ .owner = THIS_MODULE, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = arm_smmu_attach_dev, + .enforce_cache_coherency = arm_smmu_enforce_cache_coherency, .set_dev_pasid = arm_smmu_s1_set_dev_pasid, .map_pages = arm_smmu_map_pages, .unmap_pages = arm_smmu_unmap_pages, .flush_iotlb_all = arm_smmu_flush_iotlb_all, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, - .enable_nesting = arm_smmu_enable_nesting, .free = arm_smmu_domain_free_paging, } }; @@ -4675,7 +4729,7 @@ static struct platform_driver arm_smmu_driver = { .suppress_bind_attrs = true, }, .probe = arm_smmu_device_probe, - .remove_new = arm_smmu_device_remove, + .remove = 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 1e9952ca989f87..0107d3f333a1cc 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -57,6 +58,7 @@ struct arm_smmu_device; #define IDR1_SIDSIZE GENMASK(5, 0) #define ARM_SMMU_IDR3 0xc +#define IDR3_FWB (1 << 8) #define IDR3_RIL (1 << 10) #define ARM_SMMU_IDR5 0x14 @@ -81,6 +83,8 @@ struct arm_smmu_device; #define IIDR_REVISION GENMASK(15, 12) #define IIDR_IMPLEMENTER GENMASK(11, 0) +#define ARM_SMMU_AIDR 0x1C + #define ARM_SMMU_CR0 0x20 #define CR0_ATSCHK (1 << 4) #define CR0_CMDQEN (1 << 3) @@ -241,6 +245,7 @@ static inline u32 arm_smmu_strtab_l2_idx(u32 sid) #define STRTAB_STE_0_CFG_BYPASS 4 #define STRTAB_STE_0_CFG_S1_TRANS 5 #define STRTAB_STE_0_CFG_S2_TRANS 6 +#define STRTAB_STE_0_CFG_NESTED 7 #define STRTAB_STE_0_S1FMT GENMASK_ULL(5, 4) #define STRTAB_STE_0_S1FMT_LINEAR 0 @@ -261,6 +266,7 @@ static inline u32 arm_smmu_strtab_l2_idx(u32 sid) #define STRTAB_STE_1_S1COR GENMASK_ULL(5, 4) #define STRTAB_STE_1_S1CSH GENMASK_ULL(7, 6) +#define STRTAB_STE_1_S2FWB (1UL << 25) #define STRTAB_STE_1_S1STALLD (1UL << 27) #define STRTAB_STE_1_EATS GENMASK_ULL(29, 28) @@ -292,6 +298,15 @@ static inline u32 arm_smmu_strtab_l2_idx(u32 sid) #define STRTAB_STE_3_S2TTB_MASK GENMASK_ULL(51, 4) +/* These bits can be controlled by userspace for STRTAB_STE_0_CFG_NESTED */ +#define STRTAB_STE_0_NESTING_ALLOWED \ + cpu_to_le64(STRTAB_STE_0_V | STRTAB_STE_0_CFG | STRTAB_STE_0_S1FMT | \ + STRTAB_STE_0_S1CTXPTR_MASK | STRTAB_STE_0_S1CDMAX) +#define STRTAB_STE_1_NESTING_ALLOWED \ + cpu_to_le64(STRTAB_STE_1_S1DSS | STRTAB_STE_1_S1CIR | \ + STRTAB_STE_1_S1COR | STRTAB_STE_1_S1CSH | \ + STRTAB_STE_1_S1STALLD | STRTAB_STE_1_EATS) + /* * Context descriptors. * @@ -511,8 +526,10 @@ struct arm_smmu_cmdq_ent { }; } cfgi; + #define CMDQ_OP_TLBI_NH_ALL 0x10 #define CMDQ_OP_TLBI_NH_ASID 0x11 #define CMDQ_OP_TLBI_NH_VA 0x12 + #define CMDQ_OP_TLBI_NH_VAA 0x13 #define CMDQ_OP_TLBI_EL2_ALL 0x20 #define CMDQ_OP_TLBI_EL2_ASID 0x21 #define CMDQ_OP_TLBI_EL2_VA 0x22 @@ -726,6 +743,7 @@ struct arm_smmu_device { #define ARM_SMMU_FEAT_ATTR_TYPES_OVR (1 << 20) #define ARM_SMMU_FEAT_HA (1 << 21) #define ARM_SMMU_FEAT_HD (1 << 22) +#define ARM_SMMU_FEAT_S2FWB (1 << 23) u32 features; #define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0) @@ -811,10 +829,20 @@ struct arm_smmu_domain { /* List of struct arm_smmu_master_domain */ struct list_head devices; spinlock_t devices_lock; + bool enforce_cache_coherency : 1; + bool nest_parent : 1; struct mmu_notifier mmu_notifier; }; +struct arm_smmu_nested_domain { + struct iommu_domain domain; + struct arm_vsmmu *vsmmu; + bool enable_ats : 1; + + __le64 ste[2]; +}; + /* The following are exposed for testing purposes. */ struct arm_smmu_entry_writer_ops; struct arm_smmu_entry_writer { @@ -827,21 +855,22 @@ struct arm_smmu_entry_writer_ops { void (*sync)(struct arm_smmu_entry_writer *writer); }; +void arm_smmu_make_abort_ste(struct arm_smmu_ste *target); +void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target, + struct arm_smmu_master *master, + struct arm_smmu_domain *smmu_domain, + bool ats_enabled); + #if IS_ENABLED(CONFIG_KUNIT) void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits); void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *cur, const __le64 *target); void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits); -void arm_smmu_make_abort_ste(struct arm_smmu_ste *target); void arm_smmu_make_bypass_ste(struct arm_smmu_device *smmu, struct arm_smmu_ste *target); void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target, struct arm_smmu_master *master, bool ats_enabled, unsigned int s1dss); -void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target, - struct arm_smmu_master *master, - struct arm_smmu_domain *smmu_domain, - bool ats_enabled); void arm_smmu_make_sva_cd(struct arm_smmu_cd *target, struct arm_smmu_master *master, struct mm_struct *mm, u16 asid); @@ -851,6 +880,7 @@ struct arm_smmu_master_domain { struct list_head devices_elm; struct arm_smmu_master *master; ioasid_t ssid; + bool nested_ats_flush : 1; }; static inline struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom) @@ -858,6 +888,12 @@ static inline struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom) return container_of(dom, struct arm_smmu_domain, domain); } +static inline struct arm_smmu_nested_domain * +to_smmu_nested_domain(struct iommu_domain *dom) +{ + return container_of(dom, struct arm_smmu_nested_domain, domain); +} + extern struct xarray arm_smmu_asid_xa; extern struct mutex arm_smmu_asid_lock; @@ -875,7 +911,7 @@ void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid, int arm_smmu_set_pasid(struct arm_smmu_master *master, struct arm_smmu_domain *smmu_domain, ioasid_t pasid, - struct arm_smmu_cd *cd); + struct arm_smmu_cd *cd, struct iommu_domain *old); void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid); void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid, @@ -893,6 +929,33 @@ int arm_smmu_init_one_queue(struct arm_smmu_device *smmu, int arm_smmu_cmdq_init(struct arm_smmu_device *smmu, struct arm_smmu_cmdq *cmdq); +static inline bool arm_smmu_master_canwbs(struct arm_smmu_master *master) +{ + return dev_iommu_fwspec_get(master->dev)->flags & + IOMMU_FWSPEC_PCI_RC_CANWBS; +} + +struct arm_smmu_attach_state { + /* Inputs */ + struct iommu_domain *old_domain; + struct arm_smmu_master *master; + bool cd_needs_ats; + bool disable_ats; + ioasid_t ssid; + /* Resulting state */ + bool ats_enabled; +}; + +int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state, + struct iommu_domain *new_domain); +void arm_smmu_attach_commit(struct arm_smmu_attach_state *state); +void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master, + const struct arm_smmu_ste *target); + +int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu, + struct arm_smmu_cmdq *cmdq, u64 *cmds, int n, + bool sync); + #ifdef CONFIG_ARM_SMMU_V3_SVA bool arm_smmu_sva_supported(struct arm_smmu_device *smmu); bool arm_smmu_master_sva_supported(struct arm_smmu_master *master); @@ -949,4 +1012,23 @@ tegra241_cmdqv_probe(struct arm_smmu_device *smmu) return ERR_PTR(-ENODEV); } #endif /* CONFIG_TEGRA241_CMDQV */ + +struct arm_vsmmu { + struct iommufd_viommu core; + struct arm_smmu_device *smmu; + struct arm_smmu_domain *s2_parent; + u16 vmid; +}; + +#if IS_ENABLED(CONFIG_ARM_SMMU_V3_IOMMUFD) +void *arm_smmu_hw_info(struct device *dev, u32 *length, u32 *type); +struct iommufd_viommu *arm_vsmmu_alloc(struct device *dev, + struct iommu_domain *parent, + struct iommufd_ctx *ictx, + unsigned int viommu_type); +#else +#define arm_smmu_hw_info NULL +#define arm_vsmmu_alloc NULL +#endif /* CONFIG_ARM_SMMU_V3_IOMMUFD */ + #endif /* _ARM_SMMU_V3_H */ diff --git a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c index fcd13d301fff68..6e41ddaa24d636 100644 --- a/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c +++ b/drivers/iommu/arm/arm-smmu-v3/tegra241-cmdqv.c @@ -339,7 +339,7 @@ tegra241_cmdqv_get_cmdq(struct arm_smmu_device *smmu, * one CPU at a time can enter the process, while the others * will be spinning at the same lock. */ - lidx = smp_processor_id() % cmdqv->num_lvcmdqs_per_vintf; + lidx = raw_smp_processor_id() % cmdqv->num_lvcmdqs_per_vintf; vcmdq = vintf->lvcmdqs[lidx]; if (!vcmdq || !READ_ONCE(vcmdq->enabled)) return NULL; @@ -509,7 +509,8 @@ static int tegra241_vcmdq_alloc_smmu_cmdq(struct tegra241_vcmdq *vcmdq) snprintf(name, 16, "vcmdq%u", vcmdq->idx); - q->llq.max_n_shift = VCMDQ_LOG2SIZE_MAX; + /* Queue size, capped to ensure natural alignment */ + q->llq.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT, VCMDQ_LOG2SIZE_MAX); /* Use the common helper to init the VCMDQ, and then... */ ret = arm_smmu_init_one_queue(smmu, q, vcmdq->page0, @@ -800,7 +801,9 @@ static int tegra241_cmdqv_init_structures(struct arm_smmu_device *smmu) return 0; } -struct dentry *cmdqv_debugfs_dir; +#ifdef CONFIG_IOMMU_DEBUGFS +static struct dentry *cmdqv_debugfs_dir; +#endif static struct arm_smmu_device * __tegra241_cmdqv_probe(struct arm_smmu_device *smmu, struct resource *res, diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c index 8321962b37148b..650664e0f6e3ff 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c @@ -1437,6 +1437,17 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev) goto out_free; } else { smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode); + + /* + * Defer probe if the relevant SMMU instance hasn't finished + * probing yet. This is a fragile hack and we'd ideally + * avoid this race in the core code. Until that's ironed + * out, however, this is the most pragmatic option on the + * table. + */ + if (!smmu) + return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER, + "smmu dev has not bound yet\n")); } ret = -EINVAL; @@ -1558,21 +1569,6 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev) return group; } -static int arm_smmu_enable_nesting(struct iommu_domain *domain) -{ - struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); - int ret = 0; - - mutex_lock(&smmu_domain->init_mutex); - if (smmu_domain->smmu) - ret = -EPERM; - else - smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED; - mutex_unlock(&smmu_domain->init_mutex); - - return ret; -} - static int arm_smmu_set_pgtable_quirks(struct iommu_domain *domain, unsigned long quirks) { @@ -1656,7 +1652,6 @@ static struct iommu_ops arm_smmu_ops = { .flush_iotlb_all = arm_smmu_flush_iotlb_all, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, - .enable_nesting = arm_smmu_enable_nesting, .set_pgtable_quirks = arm_smmu_set_pgtable_quirks, .free = arm_smmu_domain_free, } @@ -2372,7 +2367,7 @@ static struct platform_driver arm_smmu_driver = { .suppress_bind_attrs = true, }, .probe = arm_smmu_device_probe, - .remove_new = arm_smmu_device_remove, + .remove = 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 b98a7a598b8973..3907924646a20c 100644 --- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c +++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c @@ -759,7 +759,7 @@ static struct platform_driver qcom_iommu_ctx_driver = { .of_match_table = ctx_of_match, }, .probe = qcom_iommu_ctx_probe, - .remove_new = qcom_iommu_ctx_remove, + .remove = qcom_iommu_ctx_remove, }; static bool qcom_iommu_has_secure_context(struct qcom_iommu_dev *qcom_iommu) @@ -931,7 +931,7 @@ static struct platform_driver qcom_iommu_driver = { .pm = &qcom_iommu_pm_ops, }, .probe = qcom_iommu_device_probe, - .remove_new = qcom_iommu_device_remove, + .remove = qcom_iommu_device_remove, }; static int __init qcom_iommu_init(void) diff --git a/drivers/iommu/intel/Kconfig b/drivers/iommu/intel/Kconfig index 88fd32a9323c5a..f2f538c7065032 100644 --- a/drivers/iommu/intel/Kconfig +++ b/drivers/iommu/intel/Kconfig @@ -14,6 +14,7 @@ config INTEL_IOMMU depends on PCI_MSI && ACPI && X86 select IOMMU_API select IOMMU_IOVA + select IOMMU_IOPF select IOMMUFD_DRIVER if IOMMUFD select NEED_DMA_MAP_STATE select DMAR_TABLE @@ -50,7 +51,6 @@ config INTEL_IOMMU_SVM depends on X86_64 select MMU_NOTIFIER select IOMMU_SVA - select IOMMU_IOPF help Shared Virtual Memory (SVM) provides a facility for devices to access DMA resources through process address space by diff --git a/drivers/iommu/intel/Makefile b/drivers/iommu/intel/Makefile index c8beb0281559fb..d3bb0798092df0 100644 --- a/drivers/iommu/intel/Makefile +++ b/drivers/iommu/intel/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DMAR_TABLE) += dmar.o -obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o nested.o cache.o +obj-$(CONFIG_INTEL_IOMMU) += iommu.o pasid.o nested.o cache.o prq.o obj-$(CONFIG_DMAR_TABLE) += trace.o cap_audit.o obj-$(CONFIG_DMAR_PERF) += perf.o obj-$(CONFIG_INTEL_IOMMU_DEBUGFS) += debugfs.o diff --git a/drivers/iommu/intel/cache.c b/drivers/iommu/intel/cache.c index e5b89f728ad3b2..09694cca8752df 100644 --- a/drivers/iommu/intel/cache.c +++ b/drivers/iommu/intel/cache.c @@ -105,12 +105,35 @@ static void cache_tag_unassign(struct dmar_domain *domain, u16 did, spin_unlock_irqrestore(&domain->cache_lock, flags); } +/* domain->qi_batch will be freed in iommu_free_domain() path. */ +static int domain_qi_batch_alloc(struct dmar_domain *domain) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&domain->cache_lock, flags); + if (domain->qi_batch) + goto out_unlock; + + domain->qi_batch = kzalloc(sizeof(*domain->qi_batch), GFP_ATOMIC); + if (!domain->qi_batch) + ret = -ENOMEM; +out_unlock: + spin_unlock_irqrestore(&domain->cache_lock, flags); + + return ret; +} + static int __cache_tag_assign_domain(struct dmar_domain *domain, u16 did, struct device *dev, ioasid_t pasid) { struct device_domain_info *info = dev_iommu_priv_get(dev); int ret; + ret = domain_qi_batch_alloc(domain); + if (ret) + return ret; + ret = cache_tag_assign(domain, did, dev, pasid, CACHE_TAG_IOTLB); if (ret || !info->ats_enabled) return ret; @@ -139,6 +162,10 @@ static int __cache_tag_assign_parent_domain(struct dmar_domain *domain, u16 did, struct device_domain_info *info = dev_iommu_priv_get(dev); int ret; + ret = domain_qi_batch_alloc(domain); + if (ret) + return ret; + ret = cache_tag_assign(domain, did, dev, pasid, CACHE_TAG_NESTING_IOTLB); if (ret || !info->ats_enabled) return ret; @@ -190,13 +217,6 @@ int cache_tag_assign_domain(struct dmar_domain *domain, u16 did = domain_get_id_for_dev(domain, dev); int ret; - /* domain->qi_bach will be freed in iommu_free_domain() path. */ - if (!domain->qi_batch) { - domain->qi_batch = kzalloc(sizeof(*domain->qi_batch), GFP_KERNEL); - if (!domain->qi_batch) - return -ENOMEM; - } - ret = __cache_tag_assign_domain(domain, did, dev, pasid); if (ret || domain->domain.type != IOMMU_DOMAIN_NESTED) return ret; diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c index eaf862e8dea1a9..9f424acf474e94 100644 --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -1060,7 +1060,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd) err = iommu->seq_id; goto error; } - sprintf(iommu->name, "dmar%d", iommu->seq_id); + snprintf(iommu->name, sizeof(iommu->name), "dmar%d", iommu->seq_id); err = map_iommu(iommu, drhd); if (err) { @@ -1895,19 +1895,6 @@ void dmar_msi_write(int irq, struct msi_msg *msg) raw_spin_unlock_irqrestore(&iommu->register_lock, flag); } -void dmar_msi_read(int irq, struct msi_msg *msg) -{ - struct intel_iommu *iommu = irq_get_handler_data(irq); - int reg = dmar_msi_reg(iommu, irq); - unsigned long flag; - - raw_spin_lock_irqsave(&iommu->register_lock, flag); - msg->data = readl(iommu->reg + reg + 4); - msg->address_lo = readl(iommu->reg + reg + 8); - msg->address_hi = readl(iommu->reg + reg + 12); - raw_spin_unlock_irqrestore(&iommu->register_lock, flag); -} - static int dmar_fault_do_one(struct intel_iommu *iommu, int type, u8 fault_reason, u32 pasid, u16 source_id, unsigned long long addr) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index e860bc9439a283..79e0da9eb626cc 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -352,89 +352,6 @@ static bool iommu_paging_structure_coherency(struct intel_iommu *iommu) ecap_smpwc(iommu->ecap) : ecap_coherent(iommu->ecap); } -static void domain_update_iommu_coherency(struct dmar_domain *domain) -{ - struct iommu_domain_info *info; - struct dmar_drhd_unit *drhd; - struct intel_iommu *iommu; - bool found = false; - unsigned long i; - - domain->iommu_coherency = true; - xa_for_each(&domain->iommu_array, i, info) { - found = true; - if (!iommu_paging_structure_coherency(info->iommu)) { - domain->iommu_coherency = false; - break; - } - } - if (found) - return; - - /* No hardware attached; use lowest common denominator */ - rcu_read_lock(); - for_each_active_iommu(iommu, drhd) { - if (!iommu_paging_structure_coherency(iommu)) { - domain->iommu_coherency = false; - break; - } - } - rcu_read_unlock(); -} - -static int domain_update_iommu_superpage(struct dmar_domain *domain, - struct intel_iommu *skip) -{ - struct dmar_drhd_unit *drhd; - struct intel_iommu *iommu; - int mask = 0x3; - - if (!intel_iommu_superpage) - return 0; - - /* set iommu_superpage to the smallest common denominator */ - rcu_read_lock(); - for_each_active_iommu(iommu, drhd) { - if (iommu != skip) { - if (domain && domain->use_first_level) { - if (!cap_fl1gp_support(iommu->cap)) - mask = 0x1; - } else { - mask &= cap_super_page_val(iommu->cap); - } - - if (!mask) - break; - } - } - rcu_read_unlock(); - - return fls(mask); -} - -static int domain_update_device_node(struct dmar_domain *domain) -{ - struct device_domain_info *info; - int nid = NUMA_NO_NODE; - unsigned long flags; - - spin_lock_irqsave(&domain->lock, flags); - list_for_each_entry(info, &domain->devices, link) { - /* - * There could possibly be multiple device numa nodes as devices - * within the same domain may sit behind different IOMMUs. There - * isn't perfect answer in such situation, so we select first - * come first served policy. - */ - nid = dev_to_node(info->dev); - if (nid != NUMA_NO_NODE) - break; - } - spin_unlock_irqrestore(&domain->lock, flags); - - return nid; -} - /* Return the super pagesize bitmap if supported. */ static unsigned long domain_super_pgsize_bitmap(struct dmar_domain *domain) { @@ -452,34 +369,6 @@ static unsigned long domain_super_pgsize_bitmap(struct dmar_domain *domain) return bitmap; } -/* Some capabilities may be different across iommus */ -void domain_update_iommu_cap(struct dmar_domain *domain) -{ - domain_update_iommu_coherency(domain); - domain->iommu_superpage = domain_update_iommu_superpage(domain, NULL); - - /* - * If RHSA is missing, we should default to the device numa domain - * as fall back. - */ - if (domain->nid == NUMA_NO_NODE) - domain->nid = domain_update_device_node(domain); - - /* - * First-level translation restricts the input-address to a - * canonical address (i.e., address bits 63:N have the same - * value as address bit [N-1], where N is 48-bits with 4-level - * paging and 57-bits with 5-level paging). Hence, skip bit - * [N-1]. - */ - if (domain->use_first_level) - domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1); - else - domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw); - - domain->domain.pgsize_bitmap |= domain_super_pgsize_bitmap(domain); -} - struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus, u8 devfn, int alloc) { @@ -707,14 +596,15 @@ static void pgtable_walk(struct intel_iommu *iommu, unsigned long pfn, while (1) { offset = pfn_level_offset(pfn, level); pte = &parent[offset]; - if (!pte || (dma_pte_superpage(pte) || !dma_pte_present(pte))) { - pr_info("PTE not present at level %d\n", level); - break; - } pr_info("pte level: %d, pte value: 0x%016llx\n", level, pte->val); - if (level == 1) + if (!dma_pte_present(pte)) { + pr_info("page table not present at level %d\n", level - 1); + break; + } + + if (level == 1 || dma_pte_superpage(pte)) break; parent = phys_to_virt(dma_pte_addr(pte)); @@ -737,11 +627,11 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, pr_info("Dump %s table entries for IOVA 0x%llx\n", iommu->name, addr); /* root entry dump */ - rt_entry = &iommu->root_entry[bus]; - if (!rt_entry) { - pr_info("root table entry is not present\n"); + if (!iommu->root_entry) { + pr_info("root table is not present\n"); return; } + rt_entry = &iommu->root_entry[bus]; if (sm_supported(iommu)) pr_info("scalable mode root entry: hi 0x%016llx, low 0x%016llx\n", @@ -752,7 +642,7 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, /* context entry dump */ ctx_entry = iommu_context_addr(iommu, bus, devfn, 0); if (!ctx_entry) { - pr_info("context table entry is not present\n"); + pr_info("context table is not present\n"); return; } @@ -761,17 +651,23 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, /* legacy mode does not require PASID entries */ if (!sm_supported(iommu)) { + if (!context_present(ctx_entry)) { + pr_info("legacy mode page table is not present\n"); + return; + } level = agaw_to_level(ctx_entry->hi & 7); pgtable = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK); goto pgtable_walk; } - /* get the pointer to pasid directory entry */ - dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK); - if (!dir) { - pr_info("pasid directory entry is not present\n"); + if (!context_present(ctx_entry)) { + pr_info("pasid directory table is not present\n"); return; } + + /* get the pointer to pasid directory entry */ + dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK); + /* For request-without-pasid, get the pasid from context entry */ if (intel_iommu_sm && pasid == IOMMU_PASID_INVALID) pasid = IOMMU_NO_PASID; @@ -783,7 +679,7 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, /* get the pointer to the pasid table entry */ entries = get_pasid_table_from_pde(pde); if (!entries) { - pr_info("pasid table entry is not present\n"); + pr_info("pasid table is not present\n"); return; } index = pasid & PASID_PTE_MASK; @@ -791,6 +687,11 @@ void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id, for (i = 0; i < ARRAY_SIZE(pte->val); i++) pr_info("pasid table entry[%d]: 0x%016llx\n", i, pte->val[i]); + if (!pasid_pte_is_present(pte)) { + pr_info("scalable mode page table is not present\n"); + return; + } + if (pasid_pte_get_pgtt(pte) == PASID_ENTRY_PGTT_FL_ONLY) { level = pte->val[2] & BIT_ULL(2) ? 5 : 4; pgtable = phys_to_virt(pte->val[2] & VTD_PAGE_MASK); @@ -1428,51 +1329,25 @@ static void free_dmar_iommu(struct intel_iommu *iommu) /* free context mapping */ free_context_table(iommu); -#ifdef CONFIG_INTEL_IOMMU_SVM - if (pasid_supported(iommu)) { - if (ecap_prs(iommu->ecap)) - intel_svm_finish_prq(iommu); - } -#endif + if (ecap_prs(iommu->ecap)) + intel_iommu_finish_prq(iommu); } /* * Check and return whether first level is used by default for * DMA translation. */ -static bool first_level_by_default(unsigned int type) +static bool first_level_by_default(struct intel_iommu *iommu) { /* Only SL is available in legacy mode */ - if (!scalable_mode_support()) + if (!sm_supported(iommu)) return false; /* Only level (either FL or SL) is available, just use it */ - if (intel_cap_flts_sanity() ^ intel_cap_slts_sanity()) - return intel_cap_flts_sanity(); - - /* Both levels are available, decide it based on domain type */ - return type != IOMMU_DOMAIN_UNMANAGED; -} + if (ecap_flts(iommu->ecap) ^ ecap_slts(iommu->ecap)) + return ecap_flts(iommu->ecap); -static struct dmar_domain *alloc_domain(unsigned int type) -{ - struct dmar_domain *domain; - - domain = kzalloc(sizeof(*domain), GFP_KERNEL); - if (!domain) - return NULL; - - domain->nid = NUMA_NO_NODE; - if (first_level_by_default(type)) - domain->use_first_level = true; - INIT_LIST_HEAD(&domain->devices); - INIT_LIST_HEAD(&domain->dev_pasids); - INIT_LIST_HEAD(&domain->cache_tags); - spin_lock_init(&domain->lock); - spin_lock_init(&domain->cache_lock); - xa_init(&domain->iommu_array); - - return domain; + return true; } int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) @@ -1514,7 +1389,6 @@ int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) ret = xa_err(curr) ? : -EBUSY; goto err_clear; } - domain_update_iommu_cap(domain); spin_unlock(&iommu->lock); return 0; @@ -1540,26 +1414,11 @@ void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) clear_bit(info->did, iommu->domain_ids); xa_erase(&domain->iommu_array, iommu->seq_id); domain->nid = NUMA_NO_NODE; - domain_update_iommu_cap(domain); kfree(info); } spin_unlock(&iommu->lock); } -static int guestwidth_to_adjustwidth(int gaw) -{ - int agaw; - int r = (gaw - 12) % 9; - - if (r == 0) - agaw = gaw; - else - agaw = gaw + 9 - r; - if (agaw > 64) - agaw = 64; - return agaw; -} - static void domain_exit(struct dmar_domain *domain) { if (domain->pgd) { @@ -1601,7 +1460,7 @@ static void copied_context_tear_down(struct intel_iommu *iommu, if (did_old < cap_ndoms(iommu->cap)) { iommu->flush.flush_context(iommu, did_old, - (((u16)bus) << 8) | devfn, + PCI_DEVID(bus, devfn), DMA_CCMD_MASK_NOBIT, DMA_CCMD_DEVICE_INVL); iommu->flush.flush_iotlb(iommu, did_old, 0, 0, @@ -1622,7 +1481,7 @@ static void context_present_cache_flush(struct intel_iommu *iommu, u16 did, { if (cap_caching_mode(iommu->cap)) { iommu->flush.flush_context(iommu, 0, - (((u16)bus) << 8) | devfn, + PCI_DEVID(bus, devfn), DMA_CCMD_MASK_NOBIT, DMA_CCMD_DEVICE_INVL); iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); @@ -1641,7 +1500,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, int translation = CONTEXT_TT_MULTI_LEVEL; struct dma_pte *pgd = domain->pgd; struct context_entry *context; - int agaw, ret; + int ret; pr_debug("Set context mapping for %02x:%02x.%d\n", bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); @@ -1658,27 +1517,15 @@ static int domain_context_mapping_one(struct dmar_domain *domain, copied_context_tear_down(iommu, context, bus, devfn); context_clear_entry(context); - context_set_domain_id(context, did); - /* - * Skip top levels of page tables for iommu which has - * less agaw than default. Unnecessary for PT mode. - */ - for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) { - ret = -ENOMEM; - pgd = phys_to_virt(dma_pte_addr(pgd)); - if (!dma_pte_present(pgd)) - goto out_unlock; - } - if (info && info->ats_supported) translation = CONTEXT_TT_DEV_IOTLB; else translation = CONTEXT_TT_MULTI_LEVEL; context_set_address_root(context, virt_to_phys(pgd)); - context_set_address_width(context, agaw); + context_set_address_width(context, domain->agaw); context_set_translation_type(context, translation); context_set_fault_enable(context); context_set_present(context); @@ -1905,26 +1752,52 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 intel_context_flush_present(info, context, did, true); } +int __domain_setup_first_level(struct intel_iommu *iommu, + struct device *dev, ioasid_t pasid, + u16 did, pgd_t *pgd, int flags, + struct iommu_domain *old) +{ + if (!old) + return intel_pasid_setup_first_level(iommu, dev, pgd, + pasid, did, flags); + return intel_pasid_replace_first_level(iommu, dev, pgd, pasid, did, + iommu_domain_did(old, iommu), + flags); +} + +static int domain_setup_second_level(struct intel_iommu *iommu, + struct dmar_domain *domain, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) +{ + if (!old) + return intel_pasid_setup_second_level(iommu, domain, + dev, pasid); + return intel_pasid_replace_second_level(iommu, domain, dev, + iommu_domain_did(old, iommu), + pasid); +} + +static int domain_setup_passthrough(struct intel_iommu *iommu, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) +{ + if (!old) + return intel_pasid_setup_pass_through(iommu, dev, pasid); + return intel_pasid_replace_pass_through(iommu, dev, + iommu_domain_did(old, iommu), + pasid); +} + static int domain_setup_first_level(struct intel_iommu *iommu, struct dmar_domain *domain, struct device *dev, - u32 pasid) + u32 pasid, struct iommu_domain *old) { struct dma_pte *pgd = domain->pgd; - int agaw, level; - int flags = 0; + int level, flags = 0; - /* - * Skip top levels of page tables for iommu which has - * less agaw than default. Unnecessary for PT mode. - */ - for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) { - pgd = phys_to_virt(dma_pte_addr(pgd)); - if (!dma_pte_present(pgd)) - return -ENOMEM; - } - - level = agaw_to_level(agaw); + level = agaw_to_level(domain->agaw); if (level != 4 && level != 5) return -EINVAL; @@ -1934,15 +1807,9 @@ static int domain_setup_first_level(struct intel_iommu *iommu, if (domain->force_snooping) flags |= PASID_FLAG_PAGE_SNOOP; - return intel_pasid_setup_first_level(iommu, dev, (pgd_t *)pgd, pasid, - domain_id_iommu(domain, iommu), - flags); -} - -static bool dev_is_real_dma_subdevice(struct device *dev) -{ - return dev && dev_is_pci(dev) && - pci_real_dma_dev(to_pci_dev(dev)) != to_pci_dev(dev); + return __domain_setup_first_level(iommu, dev, pasid, + domain_id_iommu(domain, iommu), + (pgd_t *)pgd, flags, old); } static int dmar_domain_attach_device(struct dmar_domain *domain, @@ -1968,9 +1835,11 @@ static int dmar_domain_attach_device(struct dmar_domain *domain, if (!sm_supported(iommu)) ret = domain_context_mapping(domain, dev); else if (domain->use_first_level) - ret = domain_setup_first_level(iommu, domain, dev, IOMMU_NO_PASID); + ret = domain_setup_first_level(iommu, domain, dev, + IOMMU_NO_PASID, NULL); else - ret = intel_pasid_setup_second_level(iommu, domain, dev, IOMMU_NO_PASID); + ret = domain_setup_second_level(iommu, domain, dev, + IOMMU_NO_PASID, NULL); if (ret) goto out_block_translation; @@ -2354,19 +2223,18 @@ static int __init init_dmars(void) iommu_flush_write_buffer(iommu); -#ifdef CONFIG_INTEL_IOMMU_SVM - if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) { + if (ecap_prs(iommu->ecap)) { /* * Call dmar_alloc_hwirq() with dmar_global_lock held, * could cause possible lock race condition. */ up_write(&dmar_global_lock); - ret = intel_svm_enable_prq(iommu); + ret = intel_iommu_enable_prq(iommu); down_write(&dmar_global_lock); if (ret) goto free_iommu; } -#endif + ret = dmar_set_interrupt(iommu); if (ret) goto free_iommu; @@ -2746,20 +2614,13 @@ int dmar_parse_one_satc(struct acpi_dmar_header *hdr, void *arg) static int intel_iommu_add(struct dmar_drhd_unit *dmaru) { - int sp, ret; struct intel_iommu *iommu = dmaru->iommu; + int ret; ret = intel_cap_audit(CAP_AUDIT_HOTPLUG_DMAR, iommu); if (ret) goto out; - sp = domain_update_iommu_superpage(NULL, iommu) - 1; - if (sp >= 0 && !(cap_super_page_val(iommu->cap) & (1 << sp))) { - pr_warn("%s: Doesn't support large page.\n", - iommu->name); - return -ENXIO; - } - /* * Disable translation if already enabled prior to OS handover. */ @@ -2786,13 +2647,12 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru) intel_iommu_init_qi(iommu); iommu_flush_write_buffer(iommu); -#ifdef CONFIG_INTEL_IOMMU_SVM - if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) { - ret = intel_svm_enable_prq(iommu); + if (ecap_prs(iommu->ecap)) { + ret = intel_iommu_enable_prq(iommu); if (ret) goto disable_iommu; } -#endif + ret = dmar_set_interrupt(iommu); if (ret) goto disable_iommu; @@ -3288,7 +3148,7 @@ int __init intel_iommu_init(void) * the virtual and physical IOMMU page-tables. */ if (cap_caching_mode(iommu->cap) && - !first_level_by_default(IOMMU_DOMAIN_DMA)) { + !first_level_by_default(iommu)) { pr_info_once("IOMMU batching disallowed due to virtualization\n"); iommu_set_dma_strict(); } @@ -3360,6 +3220,9 @@ void device_block_translation(struct device *dev) struct intel_iommu *iommu = info->iommu; unsigned long flags; + if (info->domain) + cache_tag_unassign_domain(info->domain, dev, IOMMU_NO_PASID); + iommu_disable_pci_caps(info); if (!dev_is_real_dma_subdevice(dev)) { if (sm_supported(iommu)) @@ -3376,32 +3239,10 @@ void device_block_translation(struct device *dev) list_del(&info->link); spin_unlock_irqrestore(&info->domain->lock, flags); - cache_tag_unassign_domain(info->domain, dev, IOMMU_NO_PASID); domain_detach_iommu(info->domain, iommu); info->domain = NULL; } -static int md_domain_init(struct dmar_domain *domain, int guest_width) -{ - int adjust_width; - - /* calculate AGAW */ - domain->gaw = guest_width; - adjust_width = guestwidth_to_adjustwidth(guest_width); - domain->agaw = width_to_agaw(adjust_width); - - domain->iommu_coherency = false; - domain->iommu_superpage = 0; - domain->max_addr = 0; - - /* always allocate the top pgd */ - domain->pgd = iommu_alloc_page_node(domain->nid, GFP_ATOMIC); - if (!domain->pgd) - return -ENOMEM; - domain_flush_cache(domain, domain->pgd, PAGE_SIZE); - return 0; -} - static int blocking_domain_attach_dev(struct iommu_domain *domain, struct device *dev) { @@ -3488,43 +3329,9 @@ static struct dmar_domain *paging_domain_alloc(struct device *dev, bool first_st return domain; } -static struct iommu_domain *intel_iommu_domain_alloc(unsigned type) -{ - struct dmar_domain *dmar_domain; - struct iommu_domain *domain; - - switch (type) { - case IOMMU_DOMAIN_DMA: - case IOMMU_DOMAIN_UNMANAGED: - dmar_domain = alloc_domain(type); - if (!dmar_domain) { - pr_err("Can't allocate dmar_domain\n"); - return NULL; - } - if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) { - pr_err("Domain initialization failed\n"); - domain_exit(dmar_domain); - return NULL; - } - - domain = &dmar_domain->domain; - domain->geometry.aperture_start = 0; - domain->geometry.aperture_end = - __DOMAIN_MAX_ADDR(dmar_domain->gaw); - domain->geometry.force_aperture = true; - - return domain; - default: - return NULL; - } - - return NULL; -} - static struct iommu_domain * -intel_iommu_domain_alloc_user(struct device *dev, u32 flags, - struct iommu_domain *parent, - const struct iommu_user_data *user_data) +intel_iommu_domain_alloc_paging_flags(struct device *dev, u32 flags, + const struct iommu_user_data *user_data) { struct device_domain_info *info = dev_iommu_priv_get(dev); bool dirty_tracking = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING; @@ -3532,24 +3339,31 @@ intel_iommu_domain_alloc_user(struct device *dev, u32 flags, struct intel_iommu *iommu = info->iommu; struct dmar_domain *dmar_domain; struct iommu_domain *domain; - - /* Must be NESTING domain */ - if (parent) { - if (!nested_supported(iommu) || flags) - return ERR_PTR(-EOPNOTSUPP); - return intel_nested_domain_alloc(parent, user_data); - } + bool first_stage; if (flags & - (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING))) + (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING + | IOMMU_HWPT_FAULT_ID_VALID))) return ERR_PTR(-EOPNOTSUPP); if (nested_parent && !nested_supported(iommu)) return ERR_PTR(-EOPNOTSUPP); if (user_data || (dirty_tracking && !ssads_supported(iommu))) return ERR_PTR(-EOPNOTSUPP); - /* Do not use first stage for user domain translation. */ - dmar_domain = paging_domain_alloc(dev, false); + /* + * Always allocate the guest compatible page table unless + * IOMMU_HWPT_ALLOC_NEST_PARENT or IOMMU_HWPT_ALLOC_DIRTY_TRACKING + * is specified. + */ + if (nested_parent || dirty_tracking) { + if (!sm_supported(iommu) || !ecap_slts(iommu->ecap)) + return ERR_PTR(-EOPNOTSUPP); + first_stage = false; + } else { + first_stage = first_level_by_default(iommu); + } + + dmar_domain = paging_domain_alloc(dev, first_stage); if (IS_ERR(dmar_domain)) return ERR_CAST(dmar_domain); domain = &dmar_domain->domain; @@ -3583,42 +3397,41 @@ static void intel_iommu_domain_free(struct iommu_domain *domain) domain_exit(dmar_domain); } -int prepare_domain_attach_device(struct iommu_domain *domain, - struct device *dev) +int paging_domain_compatible(struct iommu_domain *domain, struct device *dev) { struct device_domain_info *info = dev_iommu_priv_get(dev); struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct intel_iommu *iommu = info->iommu; int addr_width; + if (WARN_ON_ONCE(!(domain->type & __IOMMU_DOMAIN_PAGING))) + return -EPERM; + if (dmar_domain->force_snooping && !ecap_sc_support(iommu->ecap)) return -EINVAL; if (domain->dirty_ops && !ssads_supported(iommu)) return -EINVAL; + if (dmar_domain->iommu_coherency != + iommu_paging_structure_coherency(iommu)) + return -EINVAL; + + if (dmar_domain->iommu_superpage != + iommu_superpage_capability(iommu, dmar_domain->use_first_level)) + return -EINVAL; + + if (dmar_domain->use_first_level && + (!sm_supported(iommu) || !ecap_flts(iommu->ecap))) + return -EINVAL; + /* check if this iommu agaw is sufficient for max mapped address */ addr_width = agaw_to_width(iommu->agaw); if (addr_width > cap_mgaw(iommu->cap)) addr_width = cap_mgaw(iommu->cap); - if (dmar_domain->max_addr > (1LL << addr_width)) + if (dmar_domain->gaw > addr_width || dmar_domain->agaw > iommu->agaw) return -EINVAL; - dmar_domain->gaw = addr_width; - - /* - * Knock out extra levels of page tables if necessary - */ - while (iommu->agaw < dmar_domain->agaw) { - struct dma_pte *pte; - - pte = dmar_domain->pgd; - if (dma_pte_present(pte)) { - dmar_domain->pgd = phys_to_virt(dma_pte_addr(pte)); - iommu_free_page(pte); - } - dmar_domain->agaw--; - } if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev) && context_copied(iommu, info->bus, info->devfn)) @@ -3634,7 +3447,7 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, device_block_translation(dev); - ret = prepare_domain_attach_device(domain, dev); + ret = paging_domain_compatible(domain, dev); if (ret) return ret; @@ -4252,8 +4065,8 @@ static int intel_iommu_iotlb_sync_map(struct iommu_domain *domain, return 0; } -static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, - struct iommu_domain *domain) +void domain_remove_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) { struct device_domain_info *info = dev_iommu_priv_get(dev); struct dev_pasid_info *curr, *dev_pasid = NULL; @@ -4261,10 +4074,12 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, struct dmar_domain *dmar_domain; unsigned long flags; - if (domain->type == IOMMU_DOMAIN_IDENTITY) { - intel_pasid_tear_down_entry(iommu, dev, pasid, false); + if (!domain) + return; + + /* Identity domain has no meta data for pasid. */ + if (domain->type == IOMMU_DOMAIN_IDENTITY) return; - } dmar_domain = to_dmar_domain(domain); spin_lock_irqsave(&dmar_domain->lock, flags); @@ -4282,12 +4097,20 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, domain_detach_iommu(dmar_domain, iommu); intel_iommu_debugfs_remove_dev_pasid(dev_pasid); kfree(dev_pasid); - intel_pasid_tear_down_entry(iommu, dev, pasid, false); - intel_drain_pasid_prq(dev, pasid); } -static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid) +static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, + struct iommu_domain *domain) +{ + struct device_domain_info *info = dev_iommu_priv_get(dev); + + intel_pasid_tear_down_entry(info->iommu, dev, pasid, false); + domain_remove_dev_pasid(domain, dev, pasid); +} + +struct dev_pasid_info * +domain_add_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) { struct device_domain_info *info = dev_iommu_priv_get(dev); struct dmar_domain *dmar_domain = to_dmar_domain(domain); @@ -4296,22 +4119,9 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, unsigned long flags; int ret; - if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev)) - return -EOPNOTSUPP; - - if (domain->dirty_ops) - return -EINVAL; - - if (context_copied(iommu, info->bus, info->devfn)) - return -EBUSY; - - ret = prepare_domain_attach_device(domain, dev); - if (ret) - return ret; - dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL); if (!dev_pasid) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ret = domain_attach_iommu(dmar_domain, iommu); if (ret) @@ -4321,31 +4131,67 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, if (ret) goto out_detach_iommu; - if (dmar_domain->use_first_level) - ret = domain_setup_first_level(iommu, dmar_domain, - dev, pasid); - else - ret = intel_pasid_setup_second_level(iommu, dmar_domain, - dev, pasid); - if (ret) - goto out_unassign_tag; - dev_pasid->dev = dev; dev_pasid->pasid = pasid; spin_lock_irqsave(&dmar_domain->lock, flags); list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids); spin_unlock_irqrestore(&dmar_domain->lock, flags); - if (domain->type & __IOMMU_DOMAIN_PAGING) - intel_iommu_debugfs_create_dev_pasid(dev_pasid); - - return 0; -out_unassign_tag: - cache_tag_unassign_domain(dmar_domain, dev, pasid); + return dev_pasid; out_detach_iommu: domain_detach_iommu(dmar_domain, iommu); out_free: kfree(dev_pasid); + return ERR_PTR(ret); +} + +static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) +{ + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + struct intel_iommu *iommu = info->iommu; + struct dev_pasid_info *dev_pasid; + int ret; + + if (WARN_ON_ONCE(!(domain->type & __IOMMU_DOMAIN_PAGING))) + return -EINVAL; + + if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev)) + return -EOPNOTSUPP; + + if (domain->dirty_ops) + return -EINVAL; + + if (context_copied(iommu, info->bus, info->devfn)) + return -EBUSY; + + ret = paging_domain_compatible(domain, dev); + if (ret) + return ret; + + dev_pasid = domain_add_dev_pasid(domain, dev, pasid); + if (IS_ERR(dev_pasid)) + return PTR_ERR(dev_pasid); + + if (dmar_domain->use_first_level) + ret = domain_setup_first_level(iommu, dmar_domain, + dev, pasid, old); + else + ret = domain_setup_second_level(iommu, dmar_domain, + dev, pasid, old); + if (ret) + goto out_remove_dev_pasid; + + domain_remove_dev_pasid(old, dev, pasid); + + intel_iommu_debugfs_create_dev_pasid(dev_pasid); + + return 0; + +out_remove_dev_pasid: + domain_remove_dev_pasid(domain, dev, pasid); return ret; } @@ -4573,15 +4419,22 @@ static int identity_domain_attach_dev(struct iommu_domain *domain, struct device } static int identity_domain_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid) + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) { struct device_domain_info *info = dev_iommu_priv_get(dev); struct intel_iommu *iommu = info->iommu; + int ret; if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev)) return -EOPNOTSUPP; - return intel_pasid_setup_pass_through(iommu, dev, pasid); + ret = domain_setup_passthrough(iommu, dev, pasid, old); + if (ret) + return ret; + + domain_remove_dev_pasid(old, dev, pasid); + return 0; } static struct iommu_domain identity_domain = { @@ -4592,15 +4445,31 @@ static struct iommu_domain identity_domain = { }, }; +static struct iommu_domain *intel_iommu_domain_alloc_paging(struct device *dev) +{ + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct intel_iommu *iommu = info->iommu; + struct dmar_domain *dmar_domain; + bool first_stage; + + first_stage = first_level_by_default(iommu); + dmar_domain = paging_domain_alloc(dev, first_stage); + if (IS_ERR(dmar_domain)) + return ERR_CAST(dmar_domain); + + return &dmar_domain->domain; +} + const struct iommu_ops intel_iommu_ops = { .blocked_domain = &blocking_domain, .release_domain = &blocking_domain, .identity_domain = &identity_domain, .capable = intel_iommu_capable, .hw_info = intel_iommu_hw_info, - .domain_alloc = intel_iommu_domain_alloc, - .domain_alloc_user = intel_iommu_domain_alloc_user, + .domain_alloc_paging_flags = intel_iommu_domain_alloc_paging_flags, .domain_alloc_sva = intel_svm_domain_alloc, + .domain_alloc_paging = intel_iommu_domain_alloc_paging, + .domain_alloc_nested = intel_iommu_domain_alloc_nested, .probe_device = intel_iommu_probe_device, .release_device = intel_iommu_release_device, .get_resv_regions = intel_iommu_get_resv_regions, @@ -4611,9 +4480,7 @@ const struct iommu_ops intel_iommu_ops = { .def_domain_type = device_def_domain_type, .remove_dev_pasid = intel_iommu_remove_dev_pasid, .pgsize_bitmap = SZ_4K, -#ifdef CONFIG_INTEL_IOMMU_SVM - .page_response = intel_svm_page_response, -#endif + .page_response = intel_iommu_page_response, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = intel_iommu_attach_device, .set_dev_pasid = intel_iommu_set_dev_pasid, diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index 1497f3112b12cd..6ea7bbe26b19d5 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -653,8 +654,6 @@ struct dmar_domain { struct { /* parent page table which the user domain is nested on */ struct dmar_domain *s2_domain; - /* user page table pointer (in GPA) */ - unsigned long s1_pgtbl; /* page table attributes */ struct iommu_hwpt_vtd_s1 s1_cfg; /* link to parent domain siblings */ @@ -720,7 +719,7 @@ struct intel_iommu { int msagaw; /* max sagaw of this iommu */ unsigned int irq, pr_irq, perf_irq; u16 segment; /* PCI segment# */ - unsigned char name[13]; /* Device Name */ + unsigned char name[16]; /* Device Name */ #ifdef CONFIG_INTEL_IOMMU unsigned long *domain_ids; /* bitmap of domains */ @@ -730,12 +729,10 @@ struct intel_iommu { struct iommu_flush flush; #endif -#ifdef CONFIG_INTEL_IOMMU_SVM struct page_req_dsc *prq; unsigned char prq_name[16]; /* Name for PRQ interrupt */ unsigned long prq_seq_number; struct completion prq_complete; -#endif struct iopf_queue *iopf_queue; unsigned char iopfq_name[16]; /* Synchronization between fault report and iommu device release. */ @@ -810,6 +807,13 @@ static inline struct dmar_domain *to_dmar_domain(struct iommu_domain *dom) return container_of(dom, struct dmar_domain, domain); } +/* + * Domain ID reserved for pasid entries programmed for first-level + * only and pass-through transfer modes. + */ +#define FLPT_DEFAULT_DID 1 +#define NUM_RESERVED_DID 2 + /* Retrieve the domain ID which has allocated to the domain */ static inline u16 domain_id_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) @@ -820,6 +824,21 @@ domain_id_iommu(struct dmar_domain *domain, struct intel_iommu *iommu) return info->did; } +static inline u16 +iommu_domain_did(struct iommu_domain *domain, struct intel_iommu *iommu) +{ + if (domain->type == IOMMU_DOMAIN_SVA || + domain->type == IOMMU_DOMAIN_IDENTITY) + return FLPT_DEFAULT_DID; + return domain_id_iommu(to_dmar_domain(domain), iommu); +} + +static inline bool dev_is_real_dma_subdevice(struct device *dev) +{ + return dev && dev_is_pci(dev) && + pci_real_dma_dev(to_pci_dev(dev)) != to_pci_dev(dev); +} + /* * 0: readable * 1: writable @@ -1230,15 +1249,26 @@ void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu); void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu); void device_block_translation(struct device *dev); -int prepare_domain_attach_device(struct iommu_domain *domain, - struct device *dev); -void domain_update_iommu_cap(struct dmar_domain *domain); +int paging_domain_compatible(struct iommu_domain *domain, struct device *dev); + +struct dev_pasid_info * +domain_add_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid); +void domain_remove_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid); + +int __domain_setup_first_level(struct intel_iommu *iommu, + struct device *dev, ioasid_t pasid, + u16 did, pgd_t *pgd, int flags, + struct iommu_domain *old); int dmar_ir_support(void); void iommu_flush_write_buffer(struct intel_iommu *iommu); -struct iommu_domain *intel_nested_domain_alloc(struct iommu_domain *parent, - const struct iommu_user_data *user_data); +struct iommu_domain * +intel_iommu_domain_alloc_nested(struct device *dev, struct iommu_domain *parent, + u32 flags, + const struct iommu_user_data *user_data); struct device *device_rbtree_find(struct intel_iommu *iommu, u16 rid); enum cache_tag_type { @@ -1278,18 +1308,18 @@ void intel_context_flush_present(struct device_domain_info *info, struct context_entry *context, u16 did, bool affect_domains); +int intel_iommu_enable_prq(struct intel_iommu *iommu); +int intel_iommu_finish_prq(struct intel_iommu *iommu); +void intel_iommu_page_response(struct device *dev, struct iopf_fault *evt, + struct iommu_page_response *msg); +void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid); + #ifdef CONFIG_INTEL_IOMMU_SVM 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); -void intel_svm_page_response(struct device *dev, struct iopf_fault *evt, - struct iommu_page_response *msg); struct iommu_domain *intel_svm_domain_alloc(struct device *dev, struct mm_struct *mm); -void intel_drain_pasid_prq(struct device *dev, u32 pasid); #else static inline void intel_svm_check(struct intel_iommu *iommu) {} -static inline void intel_drain_pasid_prq(struct device *dev, u32 pasid) {} static inline struct iommu_domain *intel_svm_domain_alloc(struct device *dev, struct mm_struct *mm) { diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c index 7a6d188e3bea09..466c1412dd4567 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -312,7 +312,7 @@ static int set_ioapic_sid(struct irte *irte, int apic) for (i = 0; i < MAX_IO_APICS; i++) { if (ir_ioapic[i].iommu && ir_ioapic[i].id == apic) { - sid = (ir_ioapic[i].bus << 8) | ir_ioapic[i].devfn; + sid = PCI_DEVID(ir_ioapic[i].bus, ir_ioapic[i].devfn); break; } } @@ -337,7 +337,7 @@ static int set_hpet_sid(struct irte *irte, u8 id) for (i = 0; i < MAX_HPET_TBS; i++) { if (ir_hpet[i].iommu && ir_hpet[i].id == id) { - sid = (ir_hpet[i].bus << 8) | ir_hpet[i].devfn; + sid = PCI_DEVID(ir_hpet[i].bus, ir_hpet[i].devfn); break; } } diff --git a/drivers/iommu/intel/nested.c b/drivers/iommu/intel/nested.c index 433c58944401f9..aba92c00b42740 100644 --- a/drivers/iommu/intel/nested.c +++ b/drivers/iommu/intel/nested.c @@ -40,7 +40,7 @@ static int intel_nested_attach_dev(struct iommu_domain *domain, * The s2_domain will be used in nested translation, hence needs * to ensure the s2_domain is compatible with this IOMMU. */ - ret = prepare_domain_attach_device(&dmar_domain->s2_domain->domain, dev); + ret = paging_domain_compatible(&dmar_domain->s2_domain->domain, dev); if (ret) { dev_err_ratelimited(dev, "s2 domain is not compatible\n"); return ret; @@ -130,20 +130,77 @@ static int intel_nested_cache_invalidate_user(struct iommu_domain *domain, return ret; } +static int domain_setup_nested(struct intel_iommu *iommu, + struct dmar_domain *domain, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) +{ + if (!old) + return intel_pasid_setup_nested(iommu, dev, pasid, domain); + return intel_pasid_replace_nested(iommu, dev, pasid, + iommu_domain_did(old, iommu), + domain); +} + +static int intel_nested_set_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) +{ + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + struct intel_iommu *iommu = info->iommu; + struct dev_pasid_info *dev_pasid; + int ret; + + if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev)) + return -EOPNOTSUPP; + + if (context_copied(iommu, info->bus, info->devfn)) + return -EBUSY; + + ret = paging_domain_compatible(&dmar_domain->s2_domain->domain, dev); + if (ret) + return ret; + + dev_pasid = domain_add_dev_pasid(domain, dev, pasid); + if (IS_ERR(dev_pasid)) + return PTR_ERR(dev_pasid); + + ret = domain_setup_nested(iommu, dmar_domain, dev, pasid, old); + if (ret) + goto out_remove_dev_pasid; + + domain_remove_dev_pasid(old, dev, pasid); + + return 0; + +out_remove_dev_pasid: + domain_remove_dev_pasid(domain, dev, pasid); + return ret; +} + static const struct iommu_domain_ops intel_nested_domain_ops = { .attach_dev = intel_nested_attach_dev, + .set_dev_pasid = intel_nested_set_dev_pasid, .free = intel_nested_domain_free, .cache_invalidate_user = intel_nested_cache_invalidate_user, }; -struct iommu_domain *intel_nested_domain_alloc(struct iommu_domain *parent, - const struct iommu_user_data *user_data) +struct iommu_domain * +intel_iommu_domain_alloc_nested(struct device *dev, struct iommu_domain *parent, + u32 flags, + const struct iommu_user_data *user_data) { + struct device_domain_info *info = dev_iommu_priv_get(dev); struct dmar_domain *s2_domain = to_dmar_domain(parent); + struct intel_iommu *iommu = info->iommu; struct iommu_hwpt_vtd_s1 vtd; struct dmar_domain *domain; int ret; + if (!nested_supported(iommu) || flags) + return ERR_PTR(-EOPNOTSUPP); + /* Must be nested domain */ if (user_data->type != IOMMU_HWPT_DATA_VTD_S1) return ERR_PTR(-EOPNOTSUPP); @@ -162,7 +219,6 @@ struct iommu_domain *intel_nested_domain_alloc(struct iommu_domain *parent, domain->use_first_level = true; domain->s2_domain = s2_domain; - domain->s1_pgtbl = vtd.pgtbl_addr; domain->s1_cfg = vtd; domain->domain.ops = &intel_nested_domain_ops; domain->domain.type = IOMMU_DOMAIN_NESTED; diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c index 2e5fa0a232999f..5b7d85f1e143c0 100644 --- a/drivers/iommu/intel/pasid.c +++ b/drivers/iommu/intel/pasid.c @@ -220,7 +220,7 @@ devtlb_invalidation_with_pasid(struct intel_iommu *iommu, if (pci_dev_is_disconnected(to_pci_dev(dev))) return; - sid = info->bus << 8 | info->devfn; + sid = PCI_DEVID(info->bus, info->devfn); qdep = info->ats_qdep; pfsid = info->pfsid; @@ -265,6 +265,8 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); devtlb_invalidation_with_pasid(iommu, dev, pasid); + if (!fault_ignore) + intel_iommu_drain_pasid_prq(dev, pasid); } /* @@ -286,10 +288,69 @@ static void pasid_flush_caches(struct intel_iommu *iommu, } } +/* + * This function is supposed to be used after caller updates the fields + * except for the SSADE and P bit of a pasid table entry. It does the + * below: + * - Flush cacheline if needed + * - Flush the caches per Table 28 ”Guidance to Software for Invalidations“ + * of VT-d spec 5.0. + */ +static void intel_pasid_flush_present(struct intel_iommu *iommu, + struct device *dev, + u32 pasid, u16 did, + struct pasid_entry *pte) +{ + if (!ecap_coherent(iommu->ecap)) + clflush_cache_range(pte, sizeof(*pte)); + + /* + * VT-d spec 5.0 table28 states guides for cache invalidation: + * + * - PASID-selective-within-Domain PASID-cache invalidation + * - PASID-selective PASID-based IOTLB invalidation + * - If (pasid is RID_PASID) + * - Global Device-TLB invalidation to affected functions + * Else + * - PASID-based Device-TLB invalidation (with S=1 and + * Addr[63:12]=0x7FFFFFFF_FFFFF) to affected functions + */ + pasid_cache_invalidation_with_pasid(iommu, did, pasid); + qi_flush_piotlb(iommu, did, pasid, 0, -1, 0); + + devtlb_invalidation_with_pasid(iommu, dev, pasid); +} + /* * Set up the scalable mode pasid table entry for first only * translation type. */ +static void pasid_pte_config_first_level(struct intel_iommu *iommu, + struct pasid_entry *pte, + pgd_t *pgd, u16 did, int flags) +{ + lockdep_assert_held(&iommu->lock); + + pasid_clear_entry(pte); + + /* Setup the first level page table pointer: */ + pasid_set_flptr(pte, (u64)__pa(pgd)); + + if (flags & PASID_FLAG_FL5LP) + pasid_set_flpm(pte, 1); + + if (flags & PASID_FLAG_PAGE_SNOOP) + pasid_set_pgsnp(pte); + + pasid_set_domain_id(pte, did); + pasid_set_address_width(pte, iommu->agaw); + pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); + + /* Setup Present and PASID Granular Transfer Type: */ + pasid_set_translation_type(pte, PASID_ENTRY_PGTT_FL_ONLY); + pasid_set_present(pte); +} + int intel_pasid_setup_first_level(struct intel_iommu *iommu, struct device *dev, pgd_t *pgd, u32 pasid, u16 did, int flags) @@ -320,53 +381,82 @@ int intel_pasid_setup_first_level(struct intel_iommu *iommu, return -EBUSY; } - pasid_clear_entry(pte); + pasid_pte_config_first_level(iommu, pte, pgd, did, flags); - /* Setup the first level page table pointer: */ - pasid_set_flptr(pte, (u64)__pa(pgd)); + spin_unlock(&iommu->lock); - if (flags & PASID_FLAG_FL5LP) - pasid_set_flpm(pte, 1); + pasid_flush_caches(iommu, pte, pasid, did); - if (flags & PASID_FLAG_PAGE_SNOOP) - pasid_set_pgsnp(pte); + return 0; +} - pasid_set_domain_id(pte, did); - pasid_set_address_width(pte, iommu->agaw); - pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); +int intel_pasid_replace_first_level(struct intel_iommu *iommu, + struct device *dev, pgd_t *pgd, + u32 pasid, u16 did, u16 old_did, + int flags) +{ + struct pasid_entry *pte, new_pte; - /* Setup Present and PASID Granular Transfer Type: */ - pasid_set_translation_type(pte, PASID_ENTRY_PGTT_FL_ONLY); - pasid_set_present(pte); + if (!ecap_flts(iommu->ecap)) { + pr_err("No first level translation 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); + return -EINVAL; + } + + pasid_pte_config_first_level(iommu, &new_pte, pgd, did, flags); + + spin_lock(&iommu->lock); + pte = intel_pasid_get_entry(dev, pasid); + if (!pte) { + spin_unlock(&iommu->lock); + return -ENODEV; + } + + if (!pasid_pte_is_present(pte)) { + spin_unlock(&iommu->lock); + return -EINVAL; + } + + WARN_ON(old_did != pasid_get_domain_id(pte)); + + *pte = new_pte; spin_unlock(&iommu->lock); - pasid_flush_caches(iommu, pte, pasid, did); + intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); + intel_iommu_drain_pasid_prq(dev, pasid); return 0; } /* - * Skip top levels of page tables for iommu which has less agaw - * than default. Unnecessary for PT mode. + * Set up the scalable mode pasid entry for second only translation type. */ -static int iommu_skip_agaw(struct dmar_domain *domain, - struct intel_iommu *iommu, - struct dma_pte **pgd) +static void pasid_pte_config_second_level(struct intel_iommu *iommu, + struct pasid_entry *pte, + u64 pgd_val, int agaw, u16 did, + bool dirty_tracking) { - int agaw; + lockdep_assert_held(&iommu->lock); - for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) { - *pgd = phys_to_virt(dma_pte_addr(*pgd)); - if (!dma_pte_present(*pgd)) - return -EINVAL; - } + pasid_clear_entry(pte); + pasid_set_domain_id(pte, did); + pasid_set_slptr(pte, pgd_val); + pasid_set_address_width(pte, agaw); + pasid_set_translation_type(pte, PASID_ENTRY_PGTT_SL_ONLY); + pasid_set_fault_enable(pte); + pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); + if (dirty_tracking) + pasid_set_ssade(pte); - return agaw; + pasid_set_present(pte); } -/* - * Set up the scalable mode pasid entry for second only translation type. - */ int intel_pasid_setup_second_level(struct intel_iommu *iommu, struct dmar_domain *domain, struct device *dev, u32 pasid) @@ -374,7 +464,6 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu, struct pasid_entry *pte; struct dma_pte *pgd; u64 pgd_val; - int agaw; u16 did; /* @@ -388,15 +477,58 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu, } pgd = domain->pgd; - agaw = iommu_skip_agaw(domain, iommu, &pgd); - if (agaw < 0) { - dev_err(dev, "Invalid domain page table\n"); + pgd_val = virt_to_phys(pgd); + did = domain_id_iommu(domain, iommu); + + spin_lock(&iommu->lock); + pte = intel_pasid_get_entry(dev, pasid); + if (!pte) { + spin_unlock(&iommu->lock); + return -ENODEV; + } + + if (pasid_pte_is_present(pte)) { + spin_unlock(&iommu->lock); + return -EBUSY; + } + + pasid_pte_config_second_level(iommu, pte, pgd_val, domain->agaw, + did, domain->dirty_tracking); + spin_unlock(&iommu->lock); + + pasid_flush_caches(iommu, pte, pasid, did); + + return 0; +} + +int intel_pasid_replace_second_level(struct intel_iommu *iommu, + struct dmar_domain *domain, + struct device *dev, u16 old_did, + u32 pasid) +{ + struct pasid_entry *pte, new_pte; + struct dma_pte *pgd; + u64 pgd_val; + u16 did; + + /* + * If hardware advertises no support for second level + * translation, return directly. + */ + if (!ecap_slts(iommu->ecap)) { + pr_err("No second level translation support on %s\n", + iommu->name); return -EINVAL; } + pgd = domain->pgd; pgd_val = virt_to_phys(pgd); did = domain_id_iommu(domain, iommu); + pasid_pte_config_second_level(iommu, &new_pte, pgd_val, + domain->agaw, did, + domain->dirty_tracking); + spin_lock(&iommu->lock); pte = intel_pasid_get_entry(dev, pasid); if (!pte) { @@ -404,25 +536,18 @@ int intel_pasid_setup_second_level(struct intel_iommu *iommu, return -ENODEV; } - if (pasid_pte_is_present(pte)) { + if (!pasid_pte_is_present(pte)) { spin_unlock(&iommu->lock); - return -EBUSY; + return -EINVAL; } - pasid_clear_entry(pte); - pasid_set_domain_id(pte, did); - pasid_set_slptr(pte, pgd_val); - pasid_set_address_width(pte, agaw); - pasid_set_translation_type(pte, PASID_ENTRY_PGTT_SL_ONLY); - pasid_set_fault_enable(pte); - pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); - if (domain->dirty_tracking) - pasid_set_ssade(pte); + WARN_ON(old_did != pasid_get_domain_id(pte)); - pasid_set_present(pte); + *pte = new_pte; spin_unlock(&iommu->lock); - pasid_flush_caches(iommu, pte, pasid, did); + intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); + intel_iommu_drain_pasid_prq(dev, pasid); return 0; } @@ -499,6 +624,20 @@ int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu, /* * Set up the scalable mode pasid entry for passthrough translation type. */ +static void pasid_pte_config_pass_through(struct intel_iommu *iommu, + struct pasid_entry *pte, u16 did) +{ + lockdep_assert_held(&iommu->lock); + + pasid_clear_entry(pte); + pasid_set_domain_id(pte, did); + pasid_set_address_width(pte, iommu->agaw); + pasid_set_translation_type(pte, PASID_ENTRY_PGTT_PT); + pasid_set_fault_enable(pte); + pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); + pasid_set_present(pte); +} + int intel_pasid_setup_pass_through(struct intel_iommu *iommu, struct device *dev, u32 pasid) { @@ -517,13 +656,7 @@ int intel_pasid_setup_pass_through(struct intel_iommu *iommu, return -EBUSY; } - pasid_clear_entry(pte); - pasid_set_domain_id(pte, did); - pasid_set_address_width(pte, iommu->agaw); - pasid_set_translation_type(pte, PASID_ENTRY_PGTT_PT); - pasid_set_fault_enable(pte); - pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); - pasid_set_present(pte); + pasid_pte_config_pass_through(iommu, pte, did); spin_unlock(&iommu->lock); pasid_flush_caches(iommu, pte, pasid, did); @@ -531,6 +664,38 @@ int intel_pasid_setup_pass_through(struct intel_iommu *iommu, return 0; } +int intel_pasid_replace_pass_through(struct intel_iommu *iommu, + struct device *dev, u16 old_did, + u32 pasid) +{ + struct pasid_entry *pte, new_pte; + u16 did = FLPT_DEFAULT_DID; + + pasid_pte_config_pass_through(iommu, &new_pte, did); + + spin_lock(&iommu->lock); + pte = intel_pasid_get_entry(dev, pasid); + if (!pte) { + spin_unlock(&iommu->lock); + return -ENODEV; + } + + if (!pasid_pte_is_present(pte)) { + spin_unlock(&iommu->lock); + return -EINVAL; + } + + WARN_ON(old_did != pasid_get_domain_id(pte)); + + *pte = new_pte; + spin_unlock(&iommu->lock); + + intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); + intel_iommu_drain_pasid_prq(dev, pasid); + + return 0; +} + /* * Set the page snoop control for a pasid entry which has been set up. */ @@ -551,24 +716,47 @@ void intel_pasid_setup_page_snoop_control(struct intel_iommu *iommu, did = pasid_get_domain_id(pte); spin_unlock(&iommu->lock); - if (!ecap_coherent(iommu->ecap)) - clflush_cache_range(pte, sizeof(*pte)); + intel_pasid_flush_present(iommu, dev, pasid, did, pte); +} - /* - * VT-d spec 3.4 table23 states guides for cache invalidation: - * - * - PASID-selective-within-Domain PASID-cache invalidation - * - PASID-selective PASID-based IOTLB invalidation - * - If (pasid is RID_PASID) - * - Global Device-TLB invalidation to affected functions - * Else - * - PASID-based Device-TLB invalidation (with S=1 and - * Addr[63:12]=0x7FFFFFFF_FFFFF) to affected functions - */ - pasid_cache_invalidation_with_pasid(iommu, did, pasid); - qi_flush_piotlb(iommu, did, pasid, 0, -1, 0); +static void pasid_pte_config_nestd(struct intel_iommu *iommu, + struct pasid_entry *pte, + struct iommu_hwpt_vtd_s1 *s1_cfg, + struct dmar_domain *s2_domain, + u16 did) +{ + struct dma_pte *pgd = s2_domain->pgd; - devtlb_invalidation_with_pasid(iommu, dev, pasid); + lockdep_assert_held(&iommu->lock); + + pasid_clear_entry(pte); + + if (s1_cfg->addr_width == ADDR_WIDTH_5LEVEL) + pasid_set_flpm(pte, 1); + + pasid_set_flptr(pte, s1_cfg->pgtbl_addr); + + if (s1_cfg->flags & IOMMU_VTD_S1_SRE) { + pasid_set_sre(pte); + if (s1_cfg->flags & IOMMU_VTD_S1_WPE) + pasid_set_wpe(pte); + } + + if (s1_cfg->flags & IOMMU_VTD_S1_EAFE) + pasid_set_eafe(pte); + + if (s2_domain->force_snooping) + pasid_set_pgsnp(pte); + + pasid_set_slptr(pte, virt_to_phys(pgd)); + pasid_set_fault_enable(pte); + pasid_set_domain_id(pte, did); + pasid_set_address_width(pte, s2_domain->agaw); + pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); + if (s2_domain->dirty_tracking) + pasid_set_ssade(pte); + pasid_set_translation_type(pte, PASID_ENTRY_PGTT_NESTED); + pasid_set_present(pte); } /** @@ -586,10 +774,8 @@ int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev, u32 pasid, struct dmar_domain *domain) { struct iommu_hwpt_vtd_s1 *s1_cfg = &domain->s1_cfg; - pgd_t *s1_gpgd = (pgd_t *)(uintptr_t)domain->s1_pgtbl; struct dmar_domain *s2_domain = domain->s2_domain; u16 did = domain_id_iommu(domain, iommu); - struct dma_pte *pgd = s2_domain->pgd; struct pasid_entry *pte; /* Address width should match the address width supported by hardware */ @@ -632,37 +818,73 @@ int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev, return -EBUSY; } - pasid_clear_entry(pte); + pasid_pte_config_nestd(iommu, pte, s1_cfg, s2_domain, did); + spin_unlock(&iommu->lock); - if (s1_cfg->addr_width == ADDR_WIDTH_5LEVEL) - pasid_set_flpm(pte, 1); + pasid_flush_caches(iommu, pte, pasid, did); - pasid_set_flptr(pte, (uintptr_t)s1_gpgd); + return 0; +} - if (s1_cfg->flags & IOMMU_VTD_S1_SRE) { - pasid_set_sre(pte); - if (s1_cfg->flags & IOMMU_VTD_S1_WPE) - pasid_set_wpe(pte); +int intel_pasid_replace_nested(struct intel_iommu *iommu, + struct device *dev, u32 pasid, + u16 old_did, struct dmar_domain *domain) +{ + struct iommu_hwpt_vtd_s1 *s1_cfg = &domain->s1_cfg; + struct dmar_domain *s2_domain = domain->s2_domain; + u16 did = domain_id_iommu(domain, iommu); + struct pasid_entry *pte, new_pte; + + /* Address width should match the address width supported by hardware */ + switch (s1_cfg->addr_width) { + case ADDR_WIDTH_4LEVEL: + break; + case ADDR_WIDTH_5LEVEL: + if (!cap_fl5lp_support(iommu->cap)) { + dev_err_ratelimited(dev, + "5-level paging not supported\n"); + return -EINVAL; + } + break; + default: + dev_err_ratelimited(dev, "Invalid stage-1 address width %d\n", + s1_cfg->addr_width); + return -EINVAL; } - if (s1_cfg->flags & IOMMU_VTD_S1_EAFE) - pasid_set_eafe(pte); + if ((s1_cfg->flags & IOMMU_VTD_S1_SRE) && !ecap_srs(iommu->ecap)) { + pr_err_ratelimited("No supervisor request support on %s\n", + iommu->name); + return -EINVAL; + } - if (s2_domain->force_snooping) - pasid_set_pgsnp(pte); + if ((s1_cfg->flags & IOMMU_VTD_S1_EAFE) && !ecap_eafs(iommu->ecap)) { + pr_err_ratelimited("No extended access flag support on %s\n", + iommu->name); + return -EINVAL; + } - pasid_set_slptr(pte, virt_to_phys(pgd)); - pasid_set_fault_enable(pte); - pasid_set_domain_id(pte, did); - pasid_set_address_width(pte, s2_domain->agaw); - pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap)); - if (s2_domain->dirty_tracking) - pasid_set_ssade(pte); - pasid_set_translation_type(pte, PASID_ENTRY_PGTT_NESTED); - pasid_set_present(pte); + pasid_pte_config_nestd(iommu, &new_pte, s1_cfg, s2_domain, did); + + spin_lock(&iommu->lock); + pte = intel_pasid_get_entry(dev, pasid); + if (!pte) { + spin_unlock(&iommu->lock); + return -ENODEV; + } + + if (!pasid_pte_is_present(pte)) { + spin_unlock(&iommu->lock); + return -EINVAL; + } + + WARN_ON(old_did != pasid_get_domain_id(pte)); + + *pte = new_pte; spin_unlock(&iommu->lock); - pasid_flush_caches(iommu, pte, pasid, did); + intel_pasid_flush_present(iommu, dev, pasid, old_did, pte); + intel_iommu_drain_pasid_prq(dev, pasid); return 0; } diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h index dde6d3ba5ae0fc..082f4fe20216a7 100644 --- a/drivers/iommu/intel/pasid.h +++ b/drivers/iommu/intel/pasid.h @@ -22,13 +22,6 @@ #define is_pasid_enabled(entry) (((entry)->lo >> 3) & 0x1) #define get_pasid_dir_size(entry) (1 << ((((entry)->lo >> 9) & 0x7) + 7)) -/* - * Domain ID reserved for pasid entries programmed for first-level - * only and pass-through transfer modes. - */ -#define FLPT_DEFAULT_DID 1 -#define NUM_RESERVED_DID 2 - #define PASID_FLAG_NESTED BIT(1) #define PASID_FLAG_PAGE_SNOOP BIT(2) @@ -303,6 +296,21 @@ int intel_pasid_setup_pass_through(struct intel_iommu *iommu, struct device *dev, u32 pasid); int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev, u32 pasid, struct dmar_domain *domain); +int intel_pasid_replace_first_level(struct intel_iommu *iommu, + struct device *dev, pgd_t *pgd, + u32 pasid, u16 did, u16 old_did, + int flags); +int intel_pasid_replace_second_level(struct intel_iommu *iommu, + struct dmar_domain *domain, + struct device *dev, u16 old_did, + u32 pasid); +int intel_pasid_replace_pass_through(struct intel_iommu *iommu, + struct device *dev, u16 old_did, + u32 pasid); +int intel_pasid_replace_nested(struct intel_iommu *iommu, + struct device *dev, u32 pasid, + u16 old_did, struct dmar_domain *domain); + void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, u32 pasid, bool fault_ignore); diff --git a/drivers/iommu/intel/prq.c b/drivers/iommu/intel/prq.c new file mode 100644 index 00000000000000..c2d792db52c3e2 --- /dev/null +++ b/drivers/iommu/intel/prq.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2015 Intel Corporation + * + * Originally split from drivers/iommu/intel/svm.c + */ + +#include +#include + +#include "iommu.h" +#include "pasid.h" +#include "../iommu-pages.h" +#include "trace.h" + +/* Page request queue descriptor */ +struct page_req_dsc { + union { + struct { + u64 type:8; + u64 pasid_present:1; + u64 rsvd:7; + u64 rid:16; + u64 pasid:20; + u64 exe_req:1; + u64 pm_req:1; + u64 rsvd2:10; + }; + u64 qw_0; + }; + union { + struct { + u64 rd_req:1; + u64 wr_req:1; + u64 lpig:1; + u64 prg_index:9; + u64 addr:52; + }; + u64 qw_1; + }; + u64 qw_2; + u64 qw_3; +}; + +/** + * intel_iommu_drain_pasid_prq - Drain page requests and responses for a pasid + * @dev: target device + * @pasid: pasid for draining + * + * Drain all pending page requests and responses related to @pasid in both + * software and hardware. This is supposed to be called after the device + * driver has stopped DMA, the pasid entry has been cleared, and both IOTLB + * and DevTLB have been invalidated. + * + * It waits until all pending page requests for @pasid in the page fault + * queue are completed by the prq handling thread. Then follow the steps + * described in VT-d spec CH7.10 to drain all page requests and page + * responses pending in the hardware. + */ +void intel_iommu_drain_pasid_prq(struct device *dev, u32 pasid) +{ + struct device_domain_info *info; + struct dmar_domain *domain; + struct intel_iommu *iommu; + struct qi_desc desc[3]; + int head, tail; + u16 sid, did; + + info = dev_iommu_priv_get(dev); + if (!info->pri_enabled) + return; + + iommu = info->iommu; + domain = info->domain; + sid = PCI_DEVID(info->bus, info->devfn); + did = domain ? domain_id_iommu(domain, iommu) : FLPT_DEFAULT_DID; + + /* + * Check and wait until all pending page requests in the queue are + * handled by the prq handling thread. + */ +prq_retry: + reinit_completion(&iommu->prq_complete); + tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; + head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; + while (head != tail) { + struct page_req_dsc *req; + + req = &iommu->prq[head / sizeof(*req)]; + if (!req->pasid_present || req->pasid != pasid) { + head = (head + sizeof(*req)) & PRQ_RING_MASK; + continue; + } + + wait_for_completion(&iommu->prq_complete); + goto prq_retry; + } + + iopf_queue_flush_dev(dev); + + /* + * Perform steps described in VT-d spec CH7.10 to drain page + * requests and responses in hardware. + */ + memset(desc, 0, sizeof(desc)); + desc[0].qw0 = QI_IWD_STATUS_DATA(QI_DONE) | + QI_IWD_FENCE | + QI_IWD_TYPE; + if (pasid == IOMMU_NO_PASID) { + qi_desc_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH, &desc[1]); + qi_desc_dev_iotlb(sid, info->pfsid, info->ats_qdep, 0, + MAX_AGAW_PFN_WIDTH, &desc[2]); + } else { + qi_desc_piotlb(did, pasid, 0, -1, 0, &desc[1]); + qi_desc_dev_iotlb_pasid(sid, info->pfsid, pasid, info->ats_qdep, + 0, MAX_AGAW_PFN_WIDTH, &desc[2]); + } +qi_retry: + reinit_completion(&iommu->prq_complete); + qi_submit_sync(iommu, desc, 3, QI_OPT_WAIT_DRAIN); + if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) { + wait_for_completion(&iommu->prq_complete); + goto qi_retry; + } +} + +static bool is_canonical_address(u64 addr) +{ + int shift = 64 - (__VIRTUAL_MASK_SHIFT + 1); + long saddr = (long)addr; + + return (((saddr << shift) >> shift) == saddr); +} + +static void handle_bad_prq_event(struct intel_iommu *iommu, + struct page_req_dsc *req, int result) +{ + struct qi_desc desc = { }; + + pr_err("%s: Invalid page request: %08llx %08llx\n", + iommu->name, ((unsigned long long *)req)[0], + ((unsigned long long *)req)[1]); + + if (!req->lpig) + return; + + desc.qw0 = QI_PGRP_PASID(req->pasid) | + QI_PGRP_DID(req->rid) | + QI_PGRP_PASID_P(req->pasid_present) | + QI_PGRP_RESP_CODE(result) | + QI_PGRP_RESP_TYPE; + desc.qw1 = QI_PGRP_IDX(req->prg_index) | + QI_PGRP_LPIG(req->lpig); + + qi_submit_sync(iommu, &desc, 1, 0); +} + +static int prq_to_iommu_prot(struct page_req_dsc *req) +{ + int prot = 0; + + if (req->rd_req) + prot |= IOMMU_FAULT_PERM_READ; + if (req->wr_req) + prot |= IOMMU_FAULT_PERM_WRITE; + if (req->exe_req) + prot |= IOMMU_FAULT_PERM_EXEC; + if (req->pm_req) + prot |= IOMMU_FAULT_PERM_PRIV; + + return prot; +} + +static void intel_prq_report(struct intel_iommu *iommu, struct device *dev, + struct page_req_dsc *desc) +{ + struct iopf_fault event = { }; + + /* Fill in event data for device specific processing */ + event.fault.type = IOMMU_FAULT_PAGE_REQ; + event.fault.prm.addr = (u64)desc->addr << VTD_PAGE_SHIFT; + event.fault.prm.pasid = desc->pasid; + event.fault.prm.grpid = desc->prg_index; + event.fault.prm.perm = prq_to_iommu_prot(desc); + + if (desc->lpig) + event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; + if (desc->pasid_present) { + event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; + event.fault.prm.flags |= IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID; + } + + iommu_report_device_fault(dev, &event); +} + +static irqreturn_t prq_event_thread(int irq, void *d) +{ + struct intel_iommu *iommu = d; + struct page_req_dsc *req; + int head, tail, handled; + struct device *dev; + u64 address; + + /* + * Clear PPR bit before reading head/tail registers, to ensure that + * we get a new interrupt if needed. + */ + writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG); + + tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; + head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; + handled = (head != tail); + while (head != tail) { + req = &iommu->prq[head / sizeof(*req)]; + address = (u64)req->addr << VTD_PAGE_SHIFT; + + if (unlikely(!is_canonical_address(address))) { + pr_err("IOMMU: %s: Address is not canonical\n", + iommu->name); +bad_req: + handle_bad_prq_event(iommu, req, QI_RESP_INVALID); + goto prq_advance; + } + + if (unlikely(req->pm_req && (req->rd_req | req->wr_req))) { + pr_err("IOMMU: %s: Page request in Privilege Mode\n", + iommu->name); + goto bad_req; + } + + if (unlikely(req->exe_req && req->rd_req)) { + pr_err("IOMMU: %s: Execution request not supported\n", + iommu->name); + goto bad_req; + } + + /* Drop Stop Marker message. No need for a response. */ + if (unlikely(req->lpig && !req->rd_req && !req->wr_req)) + goto prq_advance; + + /* + * If prq is to be handled outside iommu driver via receiver of + * the fault notifiers, we skip the page response here. + */ + mutex_lock(&iommu->iopf_lock); + dev = device_rbtree_find(iommu, req->rid); + if (!dev) { + mutex_unlock(&iommu->iopf_lock); + goto bad_req; + } + + intel_prq_report(iommu, dev, req); + trace_prq_report(iommu, dev, req->qw_0, req->qw_1, + req->qw_2, req->qw_3, + iommu->prq_seq_number++); + mutex_unlock(&iommu->iopf_lock); +prq_advance: + head = (head + sizeof(*req)) & PRQ_RING_MASK; + } + + dmar_writeq(iommu->reg + DMAR_PQH_REG, tail); + + /* + * Clear the page request overflow bit and wake up all threads that + * are waiting for the completion of this handling. + */ + if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) { + pr_info_ratelimited("IOMMU: %s: PRQ overflow detected\n", + iommu->name); + head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; + tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; + if (head == tail) { + iopf_queue_discard_partial(iommu->iopf_queue); + writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG); + pr_info_ratelimited("IOMMU: %s: PRQ overflow cleared", + iommu->name); + } + } + + if (!completion_done(&iommu->prq_complete)) + complete(&iommu->prq_complete); + + return IRQ_RETVAL(handled); +} + +int intel_iommu_enable_prq(struct intel_iommu *iommu) +{ + struct iopf_queue *iopfq; + int irq, ret; + + iommu->prq = iommu_alloc_pages_node(iommu->node, GFP_KERNEL, PRQ_ORDER); + if (!iommu->prq) { + pr_warn("IOMMU: %s: Failed to allocate page request queue\n", + iommu->name); + return -ENOMEM; + } + + irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PRQ + iommu->seq_id, iommu->node, iommu); + if (irq <= 0) { + pr_err("IOMMU: %s: Failed to create IRQ vector for page request queue\n", + iommu->name); + ret = -EINVAL; + goto free_prq; + } + iommu->pr_irq = irq; + + snprintf(iommu->iopfq_name, sizeof(iommu->iopfq_name), + "dmar%d-iopfq", iommu->seq_id); + iopfq = iopf_queue_alloc(iommu->iopfq_name); + if (!iopfq) { + pr_err("IOMMU: %s: Failed to allocate iopf queue\n", iommu->name); + ret = -ENOMEM; + goto free_hwirq; + } + iommu->iopf_queue = iopfq; + + snprintf(iommu->prq_name, sizeof(iommu->prq_name), "dmar%d-prq", iommu->seq_id); + + ret = request_threaded_irq(irq, NULL, prq_event_thread, IRQF_ONESHOT, + iommu->prq_name, iommu); + if (ret) { + pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n", + iommu->name); + goto free_iopfq; + } + dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); + dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); + dmar_writeq(iommu->reg + DMAR_PQA_REG, virt_to_phys(iommu->prq) | PRQ_ORDER); + + init_completion(&iommu->prq_complete); + + return 0; + +free_iopfq: + iopf_queue_free(iommu->iopf_queue); + iommu->iopf_queue = NULL; +free_hwirq: + dmar_free_hwirq(irq); + iommu->pr_irq = 0; +free_prq: + iommu_free_pages(iommu->prq, PRQ_ORDER); + iommu->prq = NULL; + + return ret; +} + +int intel_iommu_finish_prq(struct intel_iommu *iommu) +{ + dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); + dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); + dmar_writeq(iommu->reg + DMAR_PQA_REG, 0ULL); + + if (iommu->pr_irq) { + free_irq(iommu->pr_irq, iommu); + dmar_free_hwirq(iommu->pr_irq); + iommu->pr_irq = 0; + } + + if (iommu->iopf_queue) { + iopf_queue_free(iommu->iopf_queue); + iommu->iopf_queue = NULL; + } + + iommu_free_pages(iommu->prq, PRQ_ORDER); + iommu->prq = NULL; + + return 0; +} + +void intel_iommu_page_response(struct device *dev, struct iopf_fault *evt, + struct iommu_page_response *msg) +{ + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct intel_iommu *iommu = info->iommu; + u8 bus = info->bus, devfn = info->devfn; + struct iommu_fault_page_request *prm; + struct qi_desc desc; + bool pasid_present; + bool last_page; + u16 sid; + + prm = &evt->fault.prm; + sid = PCI_DEVID(bus, devfn); + pasid_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; + last_page = prm->flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; + + desc.qw0 = QI_PGRP_PASID(prm->pasid) | QI_PGRP_DID(sid) | + QI_PGRP_PASID_P(pasid_present) | + QI_PGRP_RESP_CODE(msg->code) | + QI_PGRP_RESP_TYPE; + desc.qw1 = QI_PGRP_IDX(prm->grpid) | QI_PGRP_LPIG(last_page); + desc.qw2 = 0; + desc.qw3 = 0; + + qi_submit_sync(iommu, &desc, 1, 0); +} diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 078d1e32a24eeb..f5569347591f26 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -25,92 +25,6 @@ #include "../iommu-pages.h" #include "trace.h" -static irqreturn_t prq_event_thread(int irq, void *d); - -int intel_svm_enable_prq(struct intel_iommu *iommu) -{ - struct iopf_queue *iopfq; - int irq, ret; - - iommu->prq = iommu_alloc_pages_node(iommu->node, GFP_KERNEL, PRQ_ORDER); - if (!iommu->prq) { - pr_warn("IOMMU: %s: Failed to allocate page request queue\n", - iommu->name); - return -ENOMEM; - } - - irq = dmar_alloc_hwirq(IOMMU_IRQ_ID_OFFSET_PRQ + iommu->seq_id, iommu->node, iommu); - if (irq <= 0) { - pr_err("IOMMU: %s: Failed to create IRQ vector for page request queue\n", - iommu->name); - ret = -EINVAL; - goto free_prq; - } - iommu->pr_irq = irq; - - snprintf(iommu->iopfq_name, sizeof(iommu->iopfq_name), - "dmar%d-iopfq", iommu->seq_id); - iopfq = iopf_queue_alloc(iommu->iopfq_name); - if (!iopfq) { - pr_err("IOMMU: %s: Failed to allocate iopf queue\n", iommu->name); - ret = -ENOMEM; - goto free_hwirq; - } - iommu->iopf_queue = iopfq; - - snprintf(iommu->prq_name, sizeof(iommu->prq_name), "dmar%d-prq", iommu->seq_id); - - ret = request_threaded_irq(irq, NULL, prq_event_thread, IRQF_ONESHOT, - iommu->prq_name, iommu); - if (ret) { - pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n", - iommu->name); - goto free_iopfq; - } - dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); - dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); - dmar_writeq(iommu->reg + DMAR_PQA_REG, virt_to_phys(iommu->prq) | PRQ_ORDER); - - init_completion(&iommu->prq_complete); - - return 0; - -free_iopfq: - iopf_queue_free(iommu->iopf_queue); - iommu->iopf_queue = NULL; -free_hwirq: - dmar_free_hwirq(irq); - iommu->pr_irq = 0; -free_prq: - iommu_free_pages(iommu->prq, PRQ_ORDER); - iommu->prq = NULL; - - return ret; -} - -int intel_svm_finish_prq(struct intel_iommu *iommu) -{ - dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); - dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); - dmar_writeq(iommu->reg + DMAR_PQA_REG, 0ULL); - - if (iommu->pr_irq) { - free_irq(iommu->pr_irq, iommu); - dmar_free_hwirq(iommu->pr_irq); - iommu->pr_irq = 0; - } - - if (iommu->iopf_queue) { - iopf_queue_free(iommu->iopf_queue); - iommu->iopf_queue = NULL; - } - - iommu_free_pages(iommu->prq, PRQ_ORDER); - iommu->prq = NULL; - - return 0; -} - void intel_svm_check(struct intel_iommu *iommu) { if (!pasid_supported(iommu)) @@ -197,360 +111,37 @@ static const struct mmu_notifier_ops intel_mmuops = { }; static int intel_svm_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid) + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) { struct device_domain_info *info = dev_iommu_priv_get(dev); - struct dmar_domain *dmar_domain = to_dmar_domain(domain); struct intel_iommu *iommu = info->iommu; struct mm_struct *mm = domain->mm; struct dev_pasid_info *dev_pasid; unsigned long sflags; - unsigned long flags; int ret = 0; - dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL); - if (!dev_pasid) - return -ENOMEM; - - dev_pasid->dev = dev; - dev_pasid->pasid = pasid; - - ret = cache_tag_assign_domain(to_dmar_domain(domain), dev, pasid); - if (ret) - goto free_dev_pasid; + dev_pasid = domain_add_dev_pasid(domain, dev, pasid); + if (IS_ERR(dev_pasid)) + return PTR_ERR(dev_pasid); /* Setup the pasid table: */ sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0; - ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, pasid, - FLPT_DEFAULT_DID, sflags); + ret = __domain_setup_first_level(iommu, dev, pasid, + FLPT_DEFAULT_DID, mm->pgd, + sflags, old); if (ret) - goto unassign_tag; + goto out_remove_dev_pasid; - spin_lock_irqsave(&dmar_domain->lock, flags); - list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids); - spin_unlock_irqrestore(&dmar_domain->lock, flags); + domain_remove_dev_pasid(old, dev, pasid); return 0; -unassign_tag: - cache_tag_unassign_domain(to_dmar_domain(domain), dev, pasid); -free_dev_pasid: - kfree(dev_pasid); - +out_remove_dev_pasid: + domain_remove_dev_pasid(domain, dev, pasid); return ret; } -/* Page request queue descriptor */ -struct page_req_dsc { - union { - struct { - u64 type:8; - u64 pasid_present:1; - u64 rsvd:7; - u64 rid:16; - u64 pasid:20; - u64 exe_req:1; - u64 pm_req:1; - u64 rsvd2:10; - }; - u64 qw_0; - }; - union { - struct { - u64 rd_req:1; - u64 wr_req:1; - u64 lpig:1; - u64 prg_index:9; - u64 addr:52; - }; - u64 qw_1; - }; - u64 qw_2; - u64 qw_3; -}; - -static bool is_canonical_address(u64 addr) -{ - int shift = 64 - (__VIRTUAL_MASK_SHIFT + 1); - long saddr = (long) addr; - - return (((saddr << shift) >> shift) == saddr); -} - -/** - * intel_drain_pasid_prq - Drain page requests and responses for a pasid - * @dev: target device - * @pasid: pasid for draining - * - * Drain all pending page requests and responses related to @pasid in both - * software and hardware. This is supposed to be called after the device - * driver has stopped DMA, the pasid entry has been cleared, and both IOTLB - * and DevTLB have been invalidated. - * - * It waits until all pending page requests for @pasid in the page fault - * queue are completed by the prq handling thread. Then follow the steps - * described in VT-d spec CH7.10 to drain all page requests and page - * responses pending in the hardware. - */ -void intel_drain_pasid_prq(struct device *dev, u32 pasid) -{ - struct device_domain_info *info; - struct dmar_domain *domain; - struct intel_iommu *iommu; - struct qi_desc desc[3]; - struct pci_dev *pdev; - int head, tail; - u16 sid, did; - int qdep; - - info = dev_iommu_priv_get(dev); - if (WARN_ON(!info || !dev_is_pci(dev))) - return; - - if (!info->pri_enabled) - return; - - iommu = info->iommu; - domain = info->domain; - pdev = to_pci_dev(dev); - sid = PCI_DEVID(info->bus, info->devfn); - did = domain ? domain_id_iommu(domain, iommu) : FLPT_DEFAULT_DID; - qdep = pci_ats_queue_depth(pdev); - - /* - * Check and wait until all pending page requests in the queue are - * handled by the prq handling thread. - */ -prq_retry: - reinit_completion(&iommu->prq_complete); - tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; - head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; - while (head != tail) { - struct page_req_dsc *req; - - req = &iommu->prq[head / sizeof(*req)]; - if (!req->pasid_present || req->pasid != pasid) { - head = (head + sizeof(*req)) & PRQ_RING_MASK; - continue; - } - - wait_for_completion(&iommu->prq_complete); - goto prq_retry; - } - - iopf_queue_flush_dev(dev); - - /* - * Perform steps described in VT-d spec CH7.10 to drain page - * requests and responses in hardware. - */ - memset(desc, 0, sizeof(desc)); - desc[0].qw0 = QI_IWD_STATUS_DATA(QI_DONE) | - QI_IWD_FENCE | - QI_IWD_TYPE; - desc[1].qw0 = QI_EIOTLB_PASID(pasid) | - QI_EIOTLB_DID(did) | - QI_EIOTLB_GRAN(QI_GRAN_NONG_PASID) | - QI_EIOTLB_TYPE; - desc[2].qw0 = QI_DEV_EIOTLB_PASID(pasid) | - QI_DEV_EIOTLB_SID(sid) | - QI_DEV_EIOTLB_QDEP(qdep) | - QI_DEIOTLB_TYPE | - QI_DEV_IOTLB_PFSID(info->pfsid); -qi_retry: - reinit_completion(&iommu->prq_complete); - qi_submit_sync(iommu, desc, 3, QI_OPT_WAIT_DRAIN); - if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) { - wait_for_completion(&iommu->prq_complete); - goto qi_retry; - } -} - -static int prq_to_iommu_prot(struct page_req_dsc *req) -{ - int prot = 0; - - if (req->rd_req) - prot |= IOMMU_FAULT_PERM_READ; - if (req->wr_req) - prot |= IOMMU_FAULT_PERM_WRITE; - if (req->exe_req) - prot |= IOMMU_FAULT_PERM_EXEC; - if (req->pm_req) - prot |= IOMMU_FAULT_PERM_PRIV; - - return prot; -} - -static void intel_svm_prq_report(struct intel_iommu *iommu, struct device *dev, - struct page_req_dsc *desc) -{ - struct iopf_fault event = { }; - - /* Fill in event data for device specific processing */ - event.fault.type = IOMMU_FAULT_PAGE_REQ; - event.fault.prm.addr = (u64)desc->addr << VTD_PAGE_SHIFT; - event.fault.prm.pasid = desc->pasid; - event.fault.prm.grpid = desc->prg_index; - event.fault.prm.perm = prq_to_iommu_prot(desc); - - if (desc->lpig) - event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; - if (desc->pasid_present) { - event.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; - event.fault.prm.flags |= IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID; - } - - iommu_report_device_fault(dev, &event); -} - -static void handle_bad_prq_event(struct intel_iommu *iommu, - struct page_req_dsc *req, int result) -{ - struct qi_desc desc = { }; - - pr_err("%s: Invalid page request: %08llx %08llx\n", - iommu->name, ((unsigned long long *)req)[0], - ((unsigned long long *)req)[1]); - - if (!req->lpig) - return; - - desc.qw0 = QI_PGRP_PASID(req->pasid) | - QI_PGRP_DID(req->rid) | - QI_PGRP_PASID_P(req->pasid_present) | - QI_PGRP_RESP_CODE(result) | - QI_PGRP_RESP_TYPE; - desc.qw1 = QI_PGRP_IDX(req->prg_index) | - QI_PGRP_LPIG(req->lpig); - - qi_submit_sync(iommu, &desc, 1, 0); -} - -static irqreturn_t prq_event_thread(int irq, void *d) -{ - struct intel_iommu *iommu = d; - struct page_req_dsc *req; - int head, tail, handled; - struct device *dev; - u64 address; - - /* - * Clear PPR bit before reading head/tail registers, to ensure that - * we get a new interrupt if needed. - */ - writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG); - - tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; - head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; - handled = (head != tail); - while (head != tail) { - req = &iommu->prq[head / sizeof(*req)]; - address = (u64)req->addr << VTD_PAGE_SHIFT; - - if (unlikely(!req->pasid_present)) { - pr_err("IOMMU: %s: Page request without PASID\n", - iommu->name); -bad_req: - handle_bad_prq_event(iommu, req, QI_RESP_INVALID); - goto prq_advance; - } - - if (unlikely(!is_canonical_address(address))) { - pr_err("IOMMU: %s: Address is not canonical\n", - iommu->name); - goto bad_req; - } - - if (unlikely(req->pm_req && (req->rd_req | req->wr_req))) { - pr_err("IOMMU: %s: Page request in Privilege Mode\n", - iommu->name); - goto bad_req; - } - - if (unlikely(req->exe_req && req->rd_req)) { - pr_err("IOMMU: %s: Execution request not supported\n", - iommu->name); - goto bad_req; - } - - /* Drop Stop Marker message. No need for a response. */ - if (unlikely(req->lpig && !req->rd_req && !req->wr_req)) - goto prq_advance; - - /* - * If prq is to be handled outside iommu driver via receiver of - * the fault notifiers, we skip the page response here. - */ - mutex_lock(&iommu->iopf_lock); - dev = device_rbtree_find(iommu, req->rid); - if (!dev) { - mutex_unlock(&iommu->iopf_lock); - goto bad_req; - } - - intel_svm_prq_report(iommu, dev, req); - trace_prq_report(iommu, dev, req->qw_0, req->qw_1, - req->qw_2, req->qw_3, - iommu->prq_seq_number++); - mutex_unlock(&iommu->iopf_lock); -prq_advance: - head = (head + sizeof(*req)) & PRQ_RING_MASK; - } - - dmar_writeq(iommu->reg + DMAR_PQH_REG, tail); - - /* - * Clear the page request overflow bit and wake up all threads that - * are waiting for the completion of this handling. - */ - if (readl(iommu->reg + DMAR_PRS_REG) & DMA_PRS_PRO) { - pr_info_ratelimited("IOMMU: %s: PRQ overflow detected\n", - iommu->name); - head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; - tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; - if (head == tail) { - iopf_queue_discard_partial(iommu->iopf_queue); - writel(DMA_PRS_PRO, iommu->reg + DMAR_PRS_REG); - pr_info_ratelimited("IOMMU: %s: PRQ overflow cleared", - iommu->name); - } - } - - if (!completion_done(&iommu->prq_complete)) - complete(&iommu->prq_complete); - - return IRQ_RETVAL(handled); -} - -void intel_svm_page_response(struct device *dev, struct iopf_fault *evt, - struct iommu_page_response *msg) -{ - struct device_domain_info *info = dev_iommu_priv_get(dev); - struct intel_iommu *iommu = info->iommu; - u8 bus = info->bus, devfn = info->devfn; - struct iommu_fault_page_request *prm; - struct qi_desc desc; - bool pasid_present; - bool last_page; - u16 sid; - - prm = &evt->fault.prm; - sid = PCI_DEVID(bus, devfn); - pasid_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID; - last_page = prm->flags & IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE; - - desc.qw0 = QI_PGRP_PASID(prm->pasid) | QI_PGRP_DID(sid) | - QI_PGRP_PASID_P(pasid_present) | - QI_PGRP_RESP_CODE(msg->code) | - QI_PGRP_RESP_TYPE; - desc.qw1 = QI_PGRP_IDX(prm->grpid) | QI_PGRP_LPIG(last_page); - desc.qw2 = 0; - desc.qw3 = 0; - - qi_submit_sync(iommu, &desc, 1, 0); -} - static void intel_svm_domain_free(struct iommu_domain *domain) { struct dmar_domain *dmar_domain = to_dmar_domain(domain); diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index 06ffc683b28fee..523355e91a2ca9 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -166,7 +166,6 @@ struct arm_v7s_io_pgtable { arm_v7s_iopte *pgd; struct kmem_cache *l2_tables; - spinlock_t split_lock; }; static bool arm_v7s_pte_is_cont(arm_v7s_iopte pte, int lvl); @@ -363,25 +362,6 @@ static arm_v7s_iopte arm_v7s_prot_to_pte(int prot, int lvl, return pte; } -static int arm_v7s_pte_to_prot(arm_v7s_iopte pte, int lvl) -{ - int prot = IOMMU_READ; - arm_v7s_iopte attr = pte >> ARM_V7S_ATTR_SHIFT(lvl); - - if (!(attr & ARM_V7S_PTE_AP_RDONLY)) - prot |= IOMMU_WRITE; - if (!(attr & ARM_V7S_PTE_AP_UNPRIV)) - prot |= IOMMU_PRIV; - if ((attr & (ARM_V7S_TEX_MASK << ARM_V7S_TEX_SHIFT)) == 0) - prot |= IOMMU_MMIO; - else if (pte & ARM_V7S_ATTR_C) - prot |= IOMMU_CACHE; - if (pte & ARM_V7S_ATTR_XN(lvl)) - prot |= IOMMU_NOEXEC; - - return prot; -} - static arm_v7s_iopte arm_v7s_pte_to_cont(arm_v7s_iopte pte, int lvl) { if (lvl == 1) { @@ -398,23 +378,6 @@ static arm_v7s_iopte arm_v7s_pte_to_cont(arm_v7s_iopte pte, int lvl) return pte; } -static arm_v7s_iopte arm_v7s_cont_to_pte(arm_v7s_iopte pte, int lvl) -{ - if (lvl == 1) { - pte &= ~ARM_V7S_CONT_SECTION; - } else if (lvl == 2) { - arm_v7s_iopte xn = pte & BIT(ARM_V7S_CONT_PAGE_XN_SHIFT); - arm_v7s_iopte tex = pte & (ARM_V7S_CONT_PAGE_TEX_MASK << - ARM_V7S_CONT_PAGE_TEX_SHIFT); - - pte ^= xn | tex | ARM_V7S_PTE_TYPE_CONT_PAGE; - pte |= (xn >> ARM_V7S_CONT_PAGE_XN_SHIFT) | - (tex >> ARM_V7S_CONT_PAGE_TEX_SHIFT) | - ARM_V7S_PTE_TYPE_PAGE; - } - return pte; -} - static bool arm_v7s_pte_is_cont(arm_v7s_iopte pte, int lvl) { if (lvl == 1 && !ARM_V7S_PTE_IS_TABLE(pte, lvl)) @@ -591,77 +554,6 @@ static void arm_v7s_free_pgtable(struct io_pgtable *iop) kfree(data); } -static arm_v7s_iopte arm_v7s_split_cont(struct arm_v7s_io_pgtable *data, - unsigned long iova, int idx, int lvl, - arm_v7s_iopte *ptep) -{ - struct io_pgtable *iop = &data->iop; - arm_v7s_iopte pte; - size_t size = ARM_V7S_BLOCK_SIZE(lvl); - int i; - - /* Check that we didn't lose a race to get the lock */ - pte = *ptep; - if (!arm_v7s_pte_is_cont(pte, lvl)) - return pte; - - ptep -= idx & (ARM_V7S_CONT_PAGES - 1); - pte = arm_v7s_cont_to_pte(pte, lvl); - for (i = 0; i < ARM_V7S_CONT_PAGES; i++) - ptep[i] = pte + i * size; - - __arm_v7s_pte_sync(ptep, ARM_V7S_CONT_PAGES, &iop->cfg); - - size *= ARM_V7S_CONT_PAGES; - io_pgtable_tlb_flush_walk(iop, iova, size, size); - return pte; -} - -static size_t arm_v7s_split_blk_unmap(struct arm_v7s_io_pgtable *data, - struct iommu_iotlb_gather *gather, - unsigned long iova, size_t size, - arm_v7s_iopte blk_pte, - arm_v7s_iopte *ptep) -{ - struct io_pgtable_cfg *cfg = &data->iop.cfg; - arm_v7s_iopte pte, *tablep; - int i, unmap_idx, num_entries, num_ptes; - - tablep = __arm_v7s_alloc_table(2, GFP_ATOMIC, data); - if (!tablep) - return 0; /* Bytes unmapped */ - - num_ptes = ARM_V7S_PTES_PER_LVL(2, cfg); - num_entries = size >> ARM_V7S_LVL_SHIFT(2); - unmap_idx = ARM_V7S_LVL_IDX(iova, 2, cfg); - - pte = arm_v7s_prot_to_pte(arm_v7s_pte_to_prot(blk_pte, 1), 2, cfg); - if (num_entries > 1) - pte = arm_v7s_pte_to_cont(pte, 2); - - for (i = 0; i < num_ptes; i += num_entries, pte += size) { - /* Unmap! */ - if (i == unmap_idx) - continue; - - __arm_v7s_set_pte(&tablep[i], pte, num_entries, cfg); - } - - pte = arm_v7s_install_table(tablep, ptep, blk_pte, cfg); - if (pte != blk_pte) { - __arm_v7s_free_table(tablep, 2, data); - - if (!ARM_V7S_PTE_IS_TABLE(pte, 1)) - return 0; - - tablep = iopte_deref(pte, 1, data); - return __arm_v7s_unmap(data, gather, iova, size, 2, tablep); - } - - io_pgtable_tlb_add_page(&data->iop, gather, iova, size); - return size; -} - static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, struct iommu_iotlb_gather *gather, unsigned long iova, size_t size, int lvl, @@ -694,11 +586,8 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, * case in a lock for the sake of correctness and be done with it. */ if (num_entries <= 1 && arm_v7s_pte_is_cont(pte[0], lvl)) { - unsigned long flags; - - spin_lock_irqsave(&data->split_lock, flags); - pte[0] = arm_v7s_split_cont(data, iova, idx, lvl, ptep); - spin_unlock_irqrestore(&data->split_lock, flags); + WARN_ONCE(true, "Unmap of a partial large IOPTE is not allowed"); + return 0; } /* If the size matches this level, we're in the right place */ @@ -721,12 +610,8 @@ static size_t __arm_v7s_unmap(struct arm_v7s_io_pgtable *data, } return size; } else if (lvl == 1 && !ARM_V7S_PTE_IS_TABLE(pte[0], lvl)) { - /* - * Insert a table at the next level to map the old region, - * minus the part we want to unmap - */ - return arm_v7s_split_blk_unmap(data, gather, iova, size, pte[0], - ptep); + WARN_ONCE(true, "Unmap of a partial large IOPTE is not allowed"); + return 0; } /* Keep on walkin' */ @@ -811,8 +696,6 @@ static struct io_pgtable *arm_v7s_alloc_pgtable(struct io_pgtable_cfg *cfg, if (!data) return NULL; - spin_lock_init(&data->split_lock); - /* * ARM_MTK_TTBR_EXT extend the translation table base support larger * memory address. @@ -936,8 +819,8 @@ static int __init arm_v7s_do_selftests(void) .quirks = IO_PGTABLE_QUIRK_ARM_NS, .pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M, }; - unsigned int iova, size, iova_start; - unsigned int i, loopnr = 0; + unsigned int iova, size; + unsigned int i; size_t mapped; selftest_running = true; @@ -985,26 +868,6 @@ static int __init arm_v7s_do_selftests(void) return __FAIL(ops); iova += SZ_16M; - loopnr++; - } - - /* Partial unmap */ - i = 1; - size = 1UL << __ffs(cfg.pgsize_bitmap); - while (i < loopnr) { - iova_start = i * SZ_16M; - if (ops->unmap_pages(ops, iova_start + size, size, 1, NULL) != size) - return __FAIL(ops); - - /* Remap of partial unmap */ - if (ops->map_pages(ops, iova_start + size, size, size, 1, - IOMMU_READ, GFP_KERNEL, &mapped)) - return __FAIL(ops); - - if (ops->iova_to_phys(ops, iova_start + size + 42) - != (size + 42)) - return __FAIL(ops); - i++; } /* Full unmap */ diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 0e67f1721a3d98..6b9bb58a414fb5 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -106,6 +106,18 @@ #define ARM_LPAE_PTE_HAP_FAULT (((arm_lpae_iopte)0) << 6) #define ARM_LPAE_PTE_HAP_READ (((arm_lpae_iopte)1) << 6) #define ARM_LPAE_PTE_HAP_WRITE (((arm_lpae_iopte)2) << 6) +/* + * For !FWB these code to: + * 1111 = Normal outer write back cachable / Inner Write Back Cachable + * Permit S1 to override + * 0101 = Normal Non-cachable / Inner Non-cachable + * 0001 = Device / Device-nGnRE + * For S2FWB these code: + * 0110 Force Normal Write Back + * 0101 Normal* is forced Normal-NC, Device unchanged + * 0001 Force Device-nGnRE + */ +#define ARM_LPAE_PTE_MEMATTR_FWB_WB (((arm_lpae_iopte)0x6) << 2) #define ARM_LPAE_PTE_MEMATTR_OIWB (((arm_lpae_iopte)0xf) << 2) #define ARM_LPAE_PTE_MEMATTR_NC (((arm_lpae_iopte)0x5) << 2) #define ARM_LPAE_PTE_MEMATTR_DEV (((arm_lpae_iopte)0x1) << 2) @@ -199,6 +211,18 @@ static phys_addr_t iopte_to_paddr(arm_lpae_iopte pte, return (paddr | (paddr << (48 - 12))) & (ARM_LPAE_PTE_ADDR_MASK << 4); } +/* + * Convert an index returned by ARM_LPAE_PGD_IDX(), which can point into + * a concatenated PGD, into the maximum number of entries that can be + * mapped in the same table page. + */ +static inline int arm_lpae_max_entries(int i, struct arm_lpae_io_pgtable *data) +{ + int ptes_per_table = ARM_LPAE_PTES_PER_TABLE(data); + + return ptes_per_table - (i & (ptes_per_table - 1)); +} + static bool selftest_running = false; static dma_addr_t __arm_lpae_dma_addr(void *pages) @@ -390,7 +414,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, /* If we can install a leaf entry at this level, then do so */ if (size == block_size) { - max_entries = ARM_LPAE_PTES_PER_TABLE(data) - map_idx_start; + max_entries = arm_lpae_max_entries(map_idx_start, data); num_entries = min_t(int, pgcount, max_entries); ret = arm_lpae_init_pte(data, iova, paddr, prot, lvl, num_entries, ptep); if (!ret) @@ -458,12 +482,16 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, */ if (data->iop.fmt == ARM_64_LPAE_S2 || data->iop.fmt == ARM_32_LPAE_S2) { - if (prot & IOMMU_MMIO) + if (prot & IOMMU_MMIO) { pte |= ARM_LPAE_PTE_MEMATTR_DEV; - else if (prot & IOMMU_CACHE) - pte |= ARM_LPAE_PTE_MEMATTR_OIWB; - else + } else if (prot & IOMMU_CACHE) { + if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_S2FWB) + pte |= ARM_LPAE_PTE_MEMATTR_FWB_WB; + else + pte |= ARM_LPAE_PTE_MEMATTR_OIWB; + } else { pte |= ARM_LPAE_PTE_MEMATTR_NC; + } } else { if (prot & IOMMU_MMIO) pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV @@ -569,66 +597,6 @@ static void arm_lpae_free_pgtable(struct io_pgtable *iop) kfree(data); } -static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, - struct iommu_iotlb_gather *gather, - unsigned long iova, size_t size, - arm_lpae_iopte blk_pte, int lvl, - arm_lpae_iopte *ptep, size_t pgcount) -{ - struct io_pgtable_cfg *cfg = &data->iop.cfg; - arm_lpae_iopte pte, *tablep; - phys_addr_t blk_paddr; - size_t tablesz = ARM_LPAE_GRANULE(data); - size_t split_sz = ARM_LPAE_BLOCK_SIZE(lvl, data); - int ptes_per_table = ARM_LPAE_PTES_PER_TABLE(data); - int i, unmap_idx_start = -1, num_entries = 0, max_entries; - - if (WARN_ON(lvl == ARM_LPAE_MAX_LEVELS)) - return 0; - - tablep = __arm_lpae_alloc_pages(tablesz, GFP_ATOMIC, cfg, data->iop.cookie); - if (!tablep) - return 0; /* Bytes unmapped */ - - if (size == split_sz) { - unmap_idx_start = ARM_LPAE_LVL_IDX(iova, lvl, data); - max_entries = ptes_per_table - unmap_idx_start; - num_entries = min_t(int, pgcount, max_entries); - } - - blk_paddr = iopte_to_paddr(blk_pte, data); - pte = iopte_prot(blk_pte); - - for (i = 0; i < ptes_per_table; i++, blk_paddr += split_sz) { - /* Unmap! */ - if (i >= unmap_idx_start && i < (unmap_idx_start + num_entries)) - continue; - - __arm_lpae_init_pte(data, blk_paddr, pte, lvl, 1, &tablep[i]); - } - - pte = arm_lpae_install_table(tablep, ptep, blk_pte, data); - if (pte != blk_pte) { - __arm_lpae_free_pages(tablep, tablesz, cfg, data->iop.cookie); - /* - * We may race against someone unmapping another part of this - * block, but anything else is invalid. We can't misinterpret - * a page entry here since we're never at the last level. - */ - if (iopte_type(pte) != ARM_LPAE_PTE_TYPE_TABLE) - return 0; - - tablep = iopte_deref(pte, data); - } else if (unmap_idx_start >= 0) { - for (i = 0; i < num_entries; i++) - io_pgtable_tlb_add_page(&data->iop, gather, iova + i * size, size); - - return num_entries * size; - } - - return __arm_lpae_unmap(data, gather, iova, size, pgcount, lvl, tablep); -} - static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, struct iommu_iotlb_gather *gather, unsigned long iova, size_t size, size_t pgcount, @@ -650,7 +618,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, /* If the size matches this level, we're in the right place */ if (size == ARM_LPAE_BLOCK_SIZE(lvl, data)) { - max_entries = ARM_LPAE_PTES_PER_TABLE(data) - unmap_idx_start; + max_entries = arm_lpae_max_entries(unmap_idx_start, data); num_entries = min_t(int, pgcount, max_entries); /* Find and handle non-leaf entries */ @@ -678,12 +646,8 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, return i * size; } else if (iopte_leaf(pte, lvl, iop->fmt)) { - /* - * Insert a table at the next level to map the old region, - * minus the part we want to unmap - */ - return arm_lpae_split_blk_unmap(data, gather, iova, size, pte, - lvl + 1, ptep, pgcount); + WARN_ONCE(true, "Unmap of a partial large IOPTE is not allowed"); + return 0; } /* Keep on walkin' */ @@ -1035,8 +999,7 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) struct arm_lpae_io_pgtable *data; typeof(&cfg->arm_lpae_s2_cfg.vtcr) vtcr = &cfg->arm_lpae_s2_cfg.vtcr; - /* The NS quirk doesn't apply at stage 2 */ - if (cfg->quirks) + if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_S2FWB)) return NULL; data = arm_lpae_alloc_pgtable(cfg); @@ -1347,19 +1310,6 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) iova += SZ_1G; } - /* Partial unmap */ - size = 1UL << __ffs(cfg->pgsize_bitmap); - if (ops->unmap_pages(ops, SZ_1G + size, size, 1, NULL) != size) - return __FAIL(ops, i); - - /* Remap of partial unmap */ - if (ops->map_pages(ops, SZ_1G + size, size, size, 1, - IOMMU_READ, GFP_KERNEL, &mapped)) - return __FAIL(ops, i); - - if (ops->iova_to_phys(ops, SZ_1G + size + 42) != (size + 42)) - return __FAIL(ops, i); - /* Full unmap */ iova = 0; for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) { @@ -1382,6 +1332,23 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) iova += SZ_1G; } + /* + * Map/unmap the last largest supported page of the IAS, this can + * trigger corner cases in the concatednated page tables. + */ + mapped = 0; + size = 1UL << __fls(cfg->pgsize_bitmap); + iova = (1UL << cfg->ias) - size; + if (ops->map_pages(ops, iova, iova, size, 1, + IOMMU_READ | IOMMU_WRITE | + IOMMU_NOEXEC | IOMMU_CACHE, + GFP_KERNEL, &mapped)) + return __FAIL(ops, i); + if (mapped != size) + return __FAIL(ops, i); + if (ops->unmap_pages(ops, iova, size, 1, NULL) != size) + return __FAIL(ops, i); + free_io_pgtable_ops(ops); } diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c index cbe378c34ba3eb..170022c0953616 100644 --- a/drivers/iommu/iommu-sysfs.c +++ b/drivers/iommu/iommu-sysfs.c @@ -34,7 +34,7 @@ static void release_device(struct device *dev) kfree(dev); } -static struct class iommu_class = { +static const struct class iommu_class = { .name = "iommu", .dev_release = release_device, .dev_groups = dev_groups, diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 83c8e617a2c588..599030e1e890ba 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "dma-iommu.h" #include "iommu-priv.h" @@ -90,15 +91,17 @@ static const char * const iommu_group_resv_type_string[] = { #define IOMMU_CMD_LINE_DMA_API BIT(0) #define IOMMU_CMD_LINE_STRICT BIT(1) +static int bus_iommu_probe(const struct bus_type *bus); static int iommu_bus_notifier(struct notifier_block *nb, unsigned long action, void *data); static void iommu_release_device(struct device *dev); -static struct iommu_domain * -__iommu_group_domain_alloc(struct iommu_group *group, unsigned int type); static int __iommu_attach_device(struct iommu_domain *domain, struct device *dev); static int __iommu_attach_group(struct iommu_domain *domain, struct iommu_group *group); +static struct iommu_domain *__iommu_paging_domain_alloc_flags(struct device *dev, + unsigned int type, + unsigned int flags); enum { IOMMU_SET_DOMAIN_MUST_SUCCEED = 1 << 0, @@ -133,6 +136,8 @@ static struct group_device *iommu_group_alloc_device(struct iommu_group *group, struct device *dev); static void __iommu_group_free_device(struct iommu_group *group, struct group_device *grp_dev); +static void iommu_domain_init(struct iommu_domain *domain, unsigned int type, + const struct iommu_ops *ops); #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ struct iommu_group_attribute iommu_group_attr_##_name = \ @@ -1141,10 +1146,6 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain, } } - - if (!list_empty(&mappings) && iommu_is_dma_domain(domain)) - iommu_flush_iotlb_all(domain); - out: iommu_put_resv_regions(dev, &mappings); @@ -1586,12 +1587,59 @@ struct iommu_group *fsl_mc_device_group(struct device *dev) } EXPORT_SYMBOL_GPL(fsl_mc_device_group); +static struct iommu_domain *__iommu_alloc_identity_domain(struct device *dev) +{ + const struct iommu_ops *ops = dev_iommu_ops(dev); + struct iommu_domain *domain; + + if (ops->identity_domain) + return ops->identity_domain; + + /* Older drivers create the identity domain via ops->domain_alloc() */ + if (!ops->domain_alloc) + return ERR_PTR(-EOPNOTSUPP); + + domain = ops->domain_alloc(IOMMU_DOMAIN_IDENTITY); + if (IS_ERR(domain)) + return domain; + if (!domain) + return ERR_PTR(-ENOMEM); + + iommu_domain_init(domain, IOMMU_DOMAIN_IDENTITY, ops); + return domain; +} + static struct iommu_domain * __iommu_group_alloc_default_domain(struct iommu_group *group, int req_type) { + struct device *dev = iommu_group_first_dev(group); + struct iommu_domain *dom; + if (group->default_domain && group->default_domain->type == req_type) return group->default_domain; - return __iommu_group_domain_alloc(group, req_type); + + /* + * When allocating the DMA API domain assume that the driver is going to + * use PASID and make sure the RID's domain is PASID compatible. + */ + if (req_type & __IOMMU_DOMAIN_PAGING) { + dom = __iommu_paging_domain_alloc_flags(dev, req_type, + dev->iommu->max_pasids ? IOMMU_HWPT_ALLOC_PASID : 0); + + /* + * If driver does not support PASID feature then + * try to allocate non-PASID domain + */ + if (PTR_ERR(dom) == -EOPNOTSUPP) + dom = __iommu_paging_domain_alloc_flags(dev, req_type, 0); + + return dom; + } + + if (req_type == IOMMU_DOMAIN_IDENTITY) + return __iommu_alloc_identity_domain(dev); + + return ERR_PTR(-EINVAL); } /* @@ -1795,7 +1843,7 @@ static void iommu_group_do_probe_finalize(struct device *dev) ops->probe_finalize(dev); } -int bus_iommu_probe(const struct bus_type *bus) +static int bus_iommu_probe(const struct bus_type *bus) { struct iommu_group *group, *next; LIST_HEAD(group_list); @@ -1840,31 +1888,6 @@ int bus_iommu_probe(const struct bus_type *bus) return 0; } -/** - * iommu_present() - make platform-specific assumptions about an IOMMU - * @bus: bus to check - * - * Do not use this function. You want device_iommu_mapped() instead. - * - * Return: true if some IOMMU is present and aware of devices on the given bus; - * in general it may not be the only IOMMU, and it may not have anything to do - * with whatever device you are ultimately interested in. - */ -bool iommu_present(const struct bus_type *bus) -{ - bool ret = false; - - for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) { - if (iommu_buses[i] == bus) { - spin_lock(&iommu_device_lock); - ret = !list_empty(&iommu_device_list); - spin_unlock(&iommu_device_lock); - } - } - return ret; -} -EXPORT_SYMBOL_GPL(iommu_present); - /** * device_iommu_capable() - check for a general IOMMU capability * @dev: device to which the capability would be relevant, if available @@ -1934,117 +1957,67 @@ void iommu_set_fault_handler(struct iommu_domain *domain, } EXPORT_SYMBOL_GPL(iommu_set_fault_handler); -static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops, - struct device *dev, - unsigned int type) +static void iommu_domain_init(struct iommu_domain *domain, unsigned int type, + const struct iommu_ops *ops) { - struct iommu_domain *domain; - unsigned int alloc_type = type & IOMMU_DOMAIN_ALLOC_FLAGS; - - if (alloc_type == IOMMU_DOMAIN_IDENTITY && ops->identity_domain) - return ops->identity_domain; - else if (alloc_type == IOMMU_DOMAIN_BLOCKED && ops->blocked_domain) - return ops->blocked_domain; - else if (type & __IOMMU_DOMAIN_PAGING && ops->domain_alloc_paging) - domain = ops->domain_alloc_paging(dev); - else if (ops->domain_alloc) - domain = ops->domain_alloc(alloc_type); - else - return ERR_PTR(-EOPNOTSUPP); - - /* - * Many domain_alloc ops now return ERR_PTR, make things easier for the - * driver by accepting ERR_PTR from all domain_alloc ops instead of - * having two rules. - */ - if (IS_ERR(domain)) - return domain; - if (!domain) - return ERR_PTR(-ENOMEM); - domain->type = type; domain->owner = ops; + if (!domain->ops) + domain->ops = ops->default_domain_ops; + /* * If not already set, assume all sizes by default; the driver * may override this later */ if (!domain->pgsize_bitmap) domain->pgsize_bitmap = ops->pgsize_bitmap; - - if (!domain->ops) - domain->ops = ops->default_domain_ops; - - if (iommu_is_dma_domain(domain)) { - int rc; - - rc = iommu_get_dma_cookie(domain); - if (rc) { - iommu_domain_free(domain); - return ERR_PTR(rc); - } - } - return domain; } static struct iommu_domain * -__iommu_group_domain_alloc(struct iommu_group *group, unsigned int type) -{ - struct device *dev = iommu_group_first_dev(group); - - return __iommu_domain_alloc(dev_iommu_ops(dev), dev, type); -} - -static int __iommu_domain_alloc_dev(struct device *dev, void *data) +__iommu_paging_domain_alloc_flags(struct device *dev, unsigned int type, + unsigned int flags) { - const struct iommu_ops **ops = data; + const struct iommu_ops *ops; + struct iommu_domain *domain; if (!dev_has_iommu(dev)) - return 0; - - if (WARN_ONCE(*ops && *ops != dev_iommu_ops(dev), - "Multiple IOMMU drivers present for bus %s, which the public IOMMU API can't fully support yet. You will still need to disable one or more for this to work, sorry!\n", - dev_bus_name(dev))) - return -EBUSY; - - *ops = dev_iommu_ops(dev); - return 0; -} + return ERR_PTR(-ENODEV); -/* - * The iommu ops in bus has been retired. Do not use this interface in - * new drivers. - */ -struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus) -{ - const struct iommu_ops *ops = NULL; - int err = bus_for_each_dev(bus, NULL, &ops, __iommu_domain_alloc_dev); - struct iommu_domain *domain; + ops = dev_iommu_ops(dev); - if (err || !ops) - return NULL; + if (ops->domain_alloc_paging && !flags) + domain = ops->domain_alloc_paging(dev); + else if (ops->domain_alloc_paging_flags) + domain = ops->domain_alloc_paging_flags(dev, flags, NULL); + else if (ops->domain_alloc && !flags) + domain = ops->domain_alloc(IOMMU_DOMAIN_UNMANAGED); + else + return ERR_PTR(-EOPNOTSUPP); - domain = __iommu_domain_alloc(ops, NULL, IOMMU_DOMAIN_UNMANAGED); if (IS_ERR(domain)) - return NULL; + return domain; + if (!domain) + return ERR_PTR(-ENOMEM); + + iommu_domain_init(domain, type, ops); return domain; } -EXPORT_SYMBOL_GPL(iommu_domain_alloc); /** - * iommu_paging_domain_alloc() - Allocate a paging domain + * iommu_paging_domain_alloc_flags() - Allocate a paging domain * @dev: device for which the domain is allocated + * @flags: Bitmap of iommufd_hwpt_alloc_flags * * Allocate a paging domain which will be managed by a kernel driver. Return - * allocated domain if successful, or a ERR pointer for failure. + * allocated domain if successful, or an ERR pointer for failure. */ -struct iommu_domain *iommu_paging_domain_alloc(struct device *dev) +struct iommu_domain *iommu_paging_domain_alloc_flags(struct device *dev, + unsigned int flags) { - if (!dev_has_iommu(dev)) - return ERR_PTR(-ENODEV); - - return __iommu_domain_alloc(dev_iommu_ops(dev), dev, IOMMU_DOMAIN_UNMANAGED); + return __iommu_paging_domain_alloc_flags(dev, + IOMMU_DOMAIN_UNMANAGED, flags); } -EXPORT_SYMBOL_GPL(iommu_paging_domain_alloc); +EXPORT_SYMBOL_GPL(iommu_paging_domain_alloc_flags); void iommu_domain_free(struct iommu_domain *domain) { @@ -2216,8 +2189,8 @@ EXPORT_SYMBOL_GPL(iommu_attach_group); /** * iommu_group_replace_domain - replace the domain that a group is attached to - * @new_domain: new IOMMU domain to replace with * @group: IOMMU group that will be attached to the new domain + * @new_domain: new IOMMU domain to replace with * * This API allows the group to switch domains without being forced to go to * the blocking domain in-between. @@ -2238,7 +2211,7 @@ int iommu_group_replace_domain(struct iommu_group *group, mutex_unlock(&group->mutex); return ret; } -EXPORT_SYMBOL_NS_GPL(iommu_group_replace_domain, IOMMUFD_INTERNAL); +EXPORT_SYMBOL_NS_GPL(iommu_group_replace_domain, "IOMMUFD_INTERNAL"); static int __iommu_device_set_domain(struct iommu_group *group, struct device *dev, @@ -2586,6 +2559,20 @@ static size_t __iommu_unmap(struct iommu_domain *domain, return unmapped; } +/** + * iommu_unmap() - Remove mappings from a range of IOVA + * @domain: Domain to manipulate + * @iova: IO virtual address to start + * @size: Length of the range starting from @iova + * + * iommu_unmap() will remove a translation created by iommu_map(). It cannot + * subdivide a mapping created by iommu_map(), so it should be called with IOVA + * ranges that match what was passed to iommu_map(). The range can aggregate + * contiguous iommu_map() calls so long as no individual range is split. + * + * Returns: Number of bytes of IOVA unmapped. iova + res will be the point + * unmapping stopped. + */ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) { @@ -2723,16 +2710,6 @@ static int __init iommu_init(void) } core_initcall(iommu_init); -int iommu_enable_nesting(struct iommu_domain *domain) -{ - if (domain->type != IOMMU_DOMAIN_UNMANAGED) - return -EINVAL; - if (!domain->ops->enable_nesting) - return -EINVAL; - return domain->ops->enable_nesting(domain); -} -EXPORT_SYMBOL_GPL(iommu_enable_nesting); - int iommu_set_pgtable_quirks(struct iommu_domain *domain, unsigned long quirk) { @@ -2965,6 +2942,14 @@ static int iommu_setup_default_domain(struct iommu_group *group, if (group->default_domain == dom) return 0; + if (iommu_is_dma_domain(dom)) { + ret = iommu_get_dma_cookie(dom); + if (ret) { + iommu_domain_free(dom); + return ret; + } + } + /* * IOMMU_RESV_DIRECT and IOMMU_RESV_DIRECT_RELAXABLE regions must be * mapped before their device is attached, in order to guarantee @@ -3152,22 +3137,25 @@ void iommu_device_unuse_default_domain(struct device *dev) static int __iommu_group_alloc_blocking_domain(struct iommu_group *group) { + struct device *dev = iommu_group_first_dev(group); + const struct iommu_ops *ops = dev_iommu_ops(dev); struct iommu_domain *domain; if (group->blocking_domain) return 0; - domain = __iommu_group_domain_alloc(group, IOMMU_DOMAIN_BLOCKED); - if (IS_ERR(domain)) { - /* - * For drivers that do not yet understand IOMMU_DOMAIN_BLOCKED - * create an empty domain instead. - */ - domain = __iommu_group_domain_alloc(group, - IOMMU_DOMAIN_UNMANAGED); - if (IS_ERR(domain)) - return PTR_ERR(domain); + if (ops->blocked_domain) { + group->blocking_domain = ops->blocked_domain; + return 0; } + + /* + * For drivers that do not yet understand IOMMU_DOMAIN_BLOCKED create an + * empty PAGING domain instead. + */ + domain = iommu_paging_domain_alloc(dev); + if (IS_ERR(domain)) + return PTR_ERR(domain); group->blocking_domain = domain; return 0; } @@ -3331,7 +3319,8 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain, int ret; for_each_group_device(group, device) { - ret = domain->ops->set_dev_pasid(domain, device->dev, pasid); + ret = domain->ops->set_dev_pasid(domain, device->dev, + pasid, NULL); if (ret) goto err_revert; } @@ -3493,7 +3482,7 @@ iommu_attach_handle_get(struct iommu_group *group, ioasid_t pasid, unsigned int return handle; } -EXPORT_SYMBOL_NS_GPL(iommu_attach_handle_get, IOMMUFD_INTERNAL); +EXPORT_SYMBOL_NS_GPL(iommu_attach_handle_get, "IOMMUFD_INTERNAL"); /** * iommu_attach_group_handle - Attach an IOMMU domain to an IOMMU group @@ -3533,7 +3522,7 @@ int iommu_attach_group_handle(struct iommu_domain *domain, mutex_unlock(&group->mutex); return ret; } -EXPORT_SYMBOL_NS_GPL(iommu_attach_group_handle, IOMMUFD_INTERNAL); +EXPORT_SYMBOL_NS_GPL(iommu_attach_group_handle, "IOMMUFD_INTERNAL"); /** * iommu_detach_group_handle - Detach an IOMMU domain from an IOMMU group @@ -3551,7 +3540,7 @@ void iommu_detach_group_handle(struct iommu_domain *domain, xa_erase(&group->pasid_array, IOMMU_NO_PASID); mutex_unlock(&group->mutex); } -EXPORT_SYMBOL_NS_GPL(iommu_detach_group_handle, IOMMUFD_INTERNAL); +EXPORT_SYMBOL_NS_GPL(iommu_detach_group_handle, "IOMMUFD_INTERNAL"); /** * iommu_replace_group_handle - replace the domain that a group is attached to @@ -3597,4 +3586,4 @@ int iommu_replace_group_handle(struct iommu_group *group, mutex_unlock(&group->mutex); return ret; } -EXPORT_SYMBOL_NS_GPL(iommu_replace_group_handle, IOMMUFD_INTERNAL); +EXPORT_SYMBOL_NS_GPL(iommu_replace_group_handle, "IOMMUFD_INTERNAL"); diff --git a/drivers/iommu/iommufd/Kconfig b/drivers/iommu/iommufd/Kconfig index 76656fe0470d7d..0a07f9449fd9c2 100644 --- a/drivers/iommu/iommufd/Kconfig +++ b/drivers/iommu/iommufd/Kconfig @@ -1,4 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only +config IOMMUFD_DRIVER_CORE + tristate + default (IOMMUFD_DRIVER || IOMMUFD) if IOMMUFD!=n + config IOMMUFD tristate "IOMMU Userspace API" select INTERVAL_TREE diff --git a/drivers/iommu/iommufd/Makefile b/drivers/iommu/iommufd/Makefile index cf4605962bea6a..cb784da6cddca2 100644 --- a/drivers/iommu/iommufd/Makefile +++ b/drivers/iommu/iommufd/Makefile @@ -7,9 +7,13 @@ iommufd-y := \ ioas.o \ main.o \ pages.o \ - vfio_compat.o + vfio_compat.o \ + viommu.o iommufd-$(CONFIG_IOMMUFD_TEST) += selftest.o obj-$(CONFIG_IOMMUFD) += iommufd.o obj-$(CONFIG_IOMMUFD_DRIVER) += iova_bitmap.o + +iommufd_driver-y := driver.o +obj-$(CONFIG_IOMMUFD_DRIVER_CORE) += iommufd_driver.o diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c index 5fd3dd42029015..dfd0898fb6c157 100644 --- a/drivers/iommu/iommufd/device.c +++ b/drivers/iommu/iommufd/device.c @@ -233,7 +233,7 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx, iommufd_put_group(igroup); return ERR_PTR(rc); } -EXPORT_SYMBOL_NS_GPL(iommufd_device_bind, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_device_bind, "IOMMUFD"); /** * iommufd_ctx_has_group - True if any device within the group is bound @@ -264,7 +264,7 @@ bool iommufd_ctx_has_group(struct iommufd_ctx *ictx, struct iommu_group *group) xa_unlock(&ictx->objects); return false; } -EXPORT_SYMBOL_NS_GPL(iommufd_ctx_has_group, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_ctx_has_group, "IOMMUFD"); /** * iommufd_device_unbind - Undo iommufd_device_bind() @@ -279,19 +279,19 @@ void iommufd_device_unbind(struct iommufd_device *idev) { iommufd_object_destroy_user(idev->ictx, &idev->obj); } -EXPORT_SYMBOL_NS_GPL(iommufd_device_unbind, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_device_unbind, "IOMMUFD"); struct iommufd_ctx *iommufd_device_to_ictx(struct iommufd_device *idev) { return idev->ictx; } -EXPORT_SYMBOL_NS_GPL(iommufd_device_to_ictx, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_device_to_ictx, "IOMMUFD"); u32 iommufd_device_to_id(struct iommufd_device *idev) { return idev->obj.id; } -EXPORT_SYMBOL_NS_GPL(iommufd_device_to_id, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_device_to_id, "IOMMUFD"); static int iommufd_group_setup_msi(struct iommufd_group *igroup, struct iommufd_hwpt_paging *hwpt_paging) @@ -692,7 +692,7 @@ int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id) refcount_inc(&idev->obj.users); return 0; } -EXPORT_SYMBOL_NS_GPL(iommufd_device_attach, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_device_attach, "IOMMUFD"); /** * iommufd_device_replace - Change the device's iommu_domain @@ -714,7 +714,7 @@ int iommufd_device_replace(struct iommufd_device *idev, u32 *pt_id) return iommufd_device_change_pt(idev, pt_id, &iommufd_device_do_replace); } -EXPORT_SYMBOL_NS_GPL(iommufd_device_replace, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_device_replace, "IOMMUFD"); /** * iommufd_device_detach - Disconnect a device to an iommu_domain @@ -731,7 +731,7 @@ void iommufd_device_detach(struct iommufd_device *idev) iommufd_hw_pagetable_put(idev->ictx, hwpt); refcount_dec(&idev->obj.users); } -EXPORT_SYMBOL_NS_GPL(iommufd_device_detach, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_device_detach, "IOMMUFD"); /* * On success, it will refcount_inc() at a valid new_ioas and refcount_dec() at @@ -853,7 +853,7 @@ iommufd_access_create(struct iommufd_ctx *ictx, mutex_init(&access->ioas_lock); return access; } -EXPORT_SYMBOL_NS_GPL(iommufd_access_create, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_access_create, "IOMMUFD"); /** * iommufd_access_destroy - Destroy an iommufd_access @@ -865,7 +865,7 @@ void iommufd_access_destroy(struct iommufd_access *access) { iommufd_object_destroy_user(access->ictx, &access->obj); } -EXPORT_SYMBOL_NS_GPL(iommufd_access_destroy, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_access_destroy, "IOMMUFD"); void iommufd_access_detach(struct iommufd_access *access) { @@ -877,7 +877,7 @@ void iommufd_access_detach(struct iommufd_access *access) WARN_ON(iommufd_access_change_ioas(access, NULL)); mutex_unlock(&access->ioas_lock); } -EXPORT_SYMBOL_NS_GPL(iommufd_access_detach, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_access_detach, "IOMMUFD"); int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id) { @@ -893,7 +893,7 @@ int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id) mutex_unlock(&access->ioas_lock); return rc; } -EXPORT_SYMBOL_NS_GPL(iommufd_access_attach, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_access_attach, "IOMMUFD"); int iommufd_access_replace(struct iommufd_access *access, u32 ioas_id) { @@ -908,7 +908,7 @@ int iommufd_access_replace(struct iommufd_access *access, u32 ioas_id) mutex_unlock(&access->ioas_lock); return rc; } -EXPORT_SYMBOL_NS_GPL(iommufd_access_replace, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_access_replace, "IOMMUFD"); /** * iommufd_access_notify_unmap - Notify users of an iopt to stop using it @@ -991,7 +991,7 @@ void iommufd_access_unpin_pages(struct iommufd_access *access, up_read(&iopt->iova_rwsem); mutex_unlock(&access->ioas_lock); } -EXPORT_SYMBOL_NS_GPL(iommufd_access_unpin_pages, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_access_unpin_pages, "IOMMUFD"); static bool iopt_area_contig_is_aligned(struct iopt_area_contig_iter *iter) { @@ -1106,7 +1106,7 @@ int iommufd_access_pin_pages(struct iommufd_access *access, unsigned long iova, mutex_unlock(&access->ioas_lock); return rc; } -EXPORT_SYMBOL_NS_GPL(iommufd_access_pin_pages, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_access_pin_pages, "IOMMUFD"); /** * iommufd_access_rw - Read or write data under the iova @@ -1170,7 +1170,7 @@ int iommufd_access_rw(struct iommufd_access *access, unsigned long iova, mutex_unlock(&access->ioas_lock); return rc; } -EXPORT_SYMBOL_NS_GPL(iommufd_access_rw, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_access_rw, "IOMMUFD"); int iommufd_get_hw_info(struct iommufd_ucmd *ucmd) { diff --git a/drivers/iommu/iommufd/driver.c b/drivers/iommu/iommufd/driver.c new file mode 100644 index 00000000000000..2d98b04ff1cb7e --- /dev/null +++ b/drivers/iommu/iommufd/driver.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES + */ +#include "iommufd_private.h" + +struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx, + size_t size, + enum iommufd_object_type type) +{ + struct iommufd_object *obj; + int rc; + + obj = kzalloc(size, GFP_KERNEL_ACCOUNT); + if (!obj) + return ERR_PTR(-ENOMEM); + obj->type = type; + /* Starts out bias'd by 1 until it is removed from the xarray */ + refcount_set(&obj->shortterm_users, 1); + refcount_set(&obj->users, 1); + + /* + * Reserve an ID in the xarray but do not publish the pointer yet since + * the caller hasn't initialized it yet. Once the pointer is published + * in the xarray and visible to other threads we can't reliably destroy + * it anymore, so the caller must complete all errorable operations + * before calling iommufd_object_finalize(). + */ + rc = xa_alloc(&ictx->objects, &obj->id, XA_ZERO_ENTRY, xa_limit_31b, + GFP_KERNEL_ACCOUNT); + if (rc) + goto out_free; + return obj; +out_free: + kfree(obj); + return ERR_PTR(rc); +} +EXPORT_SYMBOL_NS_GPL(_iommufd_object_alloc, "IOMMUFD"); + +/* Caller should xa_lock(&viommu->vdevs) to protect the return value */ +struct device *iommufd_viommu_find_dev(struct iommufd_viommu *viommu, + unsigned long vdev_id) +{ + struct iommufd_vdevice *vdev; + + lockdep_assert_held(&viommu->vdevs.xa_lock); + + vdev = xa_load(&viommu->vdevs, vdev_id); + return vdev ? vdev->dev : NULL; +} +EXPORT_SYMBOL_NS_GPL(iommufd_viommu_find_dev, "IOMMUFD"); + +MODULE_DESCRIPTION("iommufd code shared with builtin modules"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iommu/iommufd/fault.c b/drivers/iommu/iommufd/fault.c index e590973ce5cfa2..1fe804e28a8663 100644 --- a/drivers/iommu/iommufd/fault.c +++ b/drivers/iommu/iommufd/fault.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -27,8 +28,12 @@ static int iommufd_fault_iopf_enable(struct iommufd_device *idev) * resource between PF and VFs. There is no coordination for this * shared capability. This waits for a vPRI reset to recover. */ - if (dev_is_pci(dev) && to_pci_dev(dev)->is_virtfn) - return -EINVAL; + if (dev_is_pci(dev)) { + struct pci_dev *pdev = to_pci_dev(dev); + + if (pdev->is_virtfn && pci_pri_supported(pdev)) + return -EINVAL; + } mutex_lock(&idev->iopf_lock); /* Device iopf has already been on. */ @@ -415,8 +420,6 @@ int iommufd_fault_alloc(struct iommufd_ucmd *ucmd) put_unused_fd(fdno); out_fput: fput(filep); - refcount_dec(&fault->obj.users); - iommufd_ctx_put(fault->ictx); out_abort: iommufd_object_abort_and_destroy(ucmd->ictx, &fault->obj); diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c index d06bf6e6c19fd2..ce03c380465154 100644 --- a/drivers/iommu/iommufd/hw_pagetable.c +++ b/drivers/iommu/iommufd/hw_pagetable.c @@ -57,7 +57,10 @@ void iommufd_hwpt_nested_destroy(struct iommufd_object *obj) container_of(obj, struct iommufd_hwpt_nested, common.obj); __iommufd_hwpt_destroy(&hwpt_nested->common); - refcount_dec(&hwpt_nested->parent->common.obj.users); + if (hwpt_nested->viommu) + refcount_dec(&hwpt_nested->viommu->obj.users); + else + refcount_dec(&hwpt_nested->parent->common.obj.users); } void iommufd_hwpt_nested_abort(struct iommufd_object *obj) @@ -107,7 +110,8 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas, const struct iommu_user_data *user_data) { const u32 valid_flags = IOMMU_HWPT_ALLOC_NEST_PARENT | - IOMMU_HWPT_ALLOC_DIRTY_TRACKING; + IOMMU_HWPT_ALLOC_DIRTY_TRACKING | + IOMMU_HWPT_FAULT_ID_VALID; const struct iommu_ops *ops = dev_iommu_ops(idev->dev); struct iommufd_hwpt_paging *hwpt_paging; struct iommufd_hw_pagetable *hwpt; @@ -115,7 +119,7 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas, lockdep_assert_held(&ioas->mutex); - if ((flags || user_data) && !ops->domain_alloc_user) + if ((flags || user_data) && !ops->domain_alloc_paging_flags) return ERR_PTR(-EOPNOTSUPP); if (flags & ~valid_flags) return ERR_PTR(-EOPNOTSUPP); @@ -135,9 +139,9 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas, hwpt_paging->ioas = ioas; hwpt_paging->nest_parent = flags & IOMMU_HWPT_ALLOC_NEST_PARENT; - if (ops->domain_alloc_user) { - hwpt->domain = ops->domain_alloc_user(idev->dev, flags, NULL, - user_data); + if (ops->domain_alloc_paging_flags) { + hwpt->domain = ops->domain_alloc_paging_flags(idev->dev, flags, + user_data); if (IS_ERR(hwpt->domain)) { rc = PTR_ERR(hwpt->domain); hwpt->domain = NULL; @@ -223,7 +227,7 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx, int rc; if ((flags & ~IOMMU_HWPT_FAULT_ID_VALID) || - !user_data->len || !ops->domain_alloc_user) + !user_data->len || !ops->domain_alloc_nested) return ERR_PTR(-EOPNOTSUPP); if (parent->auto_domain || !parent->nest_parent || parent->common.domain->owner != ops) @@ -238,9 +242,9 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx, refcount_inc(&parent->common.obj.users); hwpt_nested->parent = parent; - hwpt->domain = ops->domain_alloc_user(idev->dev, - flags & ~IOMMU_HWPT_FAULT_ID_VALID, - parent->common.domain, user_data); + hwpt->domain = ops->domain_alloc_nested( + idev->dev, parent->common.domain, + flags & ~IOMMU_HWPT_FAULT_ID_VALID, user_data); if (IS_ERR(hwpt->domain)) { rc = PTR_ERR(hwpt->domain); hwpt->domain = NULL; @@ -248,8 +252,7 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx, } hwpt->domain->owner = ops; - if (WARN_ON_ONCE(hwpt->domain->type != IOMMU_DOMAIN_NESTED || - !hwpt->domain->ops->cache_invalidate_user)) { + if (WARN_ON_ONCE(hwpt->domain->type != IOMMU_DOMAIN_NESTED)) { rc = -EINVAL; goto out_abort; } @@ -260,6 +263,58 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx, return ERR_PTR(rc); } +/** + * iommufd_viommu_alloc_hwpt_nested() - Get a hwpt_nested for a vIOMMU + * @viommu: vIOMMU ojbect to associate the hwpt_nested/domain with + * @flags: Flags from userspace + * @user_data: user_data pointer. Must be valid + * + * Allocate a new IOMMU_DOMAIN_NESTED for a vIOMMU and return it as a NESTED + * hw_pagetable. + */ +static struct iommufd_hwpt_nested * +iommufd_viommu_alloc_hwpt_nested(struct iommufd_viommu *viommu, u32 flags, + const struct iommu_user_data *user_data) +{ + struct iommufd_hwpt_nested *hwpt_nested; + struct iommufd_hw_pagetable *hwpt; + int rc; + + if (!user_data->len) + return ERR_PTR(-EOPNOTSUPP); + if (!viommu->ops || !viommu->ops->alloc_domain_nested) + return ERR_PTR(-EOPNOTSUPP); + + hwpt_nested = __iommufd_object_alloc( + viommu->ictx, hwpt_nested, IOMMUFD_OBJ_HWPT_NESTED, common.obj); + if (IS_ERR(hwpt_nested)) + return ERR_CAST(hwpt_nested); + hwpt = &hwpt_nested->common; + + hwpt_nested->viommu = viommu; + refcount_inc(&viommu->obj.users); + hwpt_nested->parent = viommu->hwpt; + + hwpt->domain = + viommu->ops->alloc_domain_nested(viommu, flags, user_data); + if (IS_ERR(hwpt->domain)) { + rc = PTR_ERR(hwpt->domain); + hwpt->domain = NULL; + goto out_abort; + } + hwpt->domain->owner = viommu->iommu_dev->ops; + + if (WARN_ON_ONCE(hwpt->domain->type != IOMMU_DOMAIN_NESTED)) { + rc = -EINVAL; + goto out_abort; + } + return hwpt_nested; + +out_abort: + iommufd_object_abort_and_destroy(viommu->ictx, &hwpt->obj); + return ERR_PTR(rc); +} + int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd) { struct iommu_hwpt_alloc *cmd = ucmd->cmd; @@ -316,6 +371,22 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd) goto out_unlock; } hwpt = &hwpt_nested->common; + } else if (pt_obj->type == IOMMUFD_OBJ_VIOMMU) { + struct iommufd_hwpt_nested *hwpt_nested; + struct iommufd_viommu *viommu; + + viommu = container_of(pt_obj, struct iommufd_viommu, obj); + if (viommu->iommu_dev != __iommu_get_iommu_dev(idev->dev)) { + rc = -EINVAL; + goto out_unlock; + } + hwpt_nested = iommufd_viommu_alloc_hwpt_nested( + viommu, cmd->flags, &user_data); + if (IS_ERR(hwpt_nested)) { + rc = PTR_ERR(hwpt_nested); + goto out_unlock; + } + hwpt = &hwpt_nested->common; } else { rc = -EINVAL; goto out_put_pt; @@ -412,7 +483,7 @@ int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd) .entry_len = cmd->entry_len, .entry_num = cmd->entry_num, }; - struct iommufd_hw_pagetable *hwpt; + struct iommufd_object *pt_obj; u32 done_num = 0; int rc; @@ -426,17 +497,40 @@ int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd) goto out; } - hwpt = iommufd_get_hwpt_nested(ucmd, cmd->hwpt_id); - if (IS_ERR(hwpt)) { - rc = PTR_ERR(hwpt); + pt_obj = iommufd_get_object(ucmd->ictx, cmd->hwpt_id, IOMMUFD_OBJ_ANY); + if (IS_ERR(pt_obj)) { + rc = PTR_ERR(pt_obj); goto out; } + if (pt_obj->type == IOMMUFD_OBJ_HWPT_NESTED) { + struct iommufd_hw_pagetable *hwpt = + container_of(pt_obj, struct iommufd_hw_pagetable, obj); + + if (!hwpt->domain->ops || + !hwpt->domain->ops->cache_invalidate_user) { + rc = -EOPNOTSUPP; + goto out_put_pt; + } + rc = hwpt->domain->ops->cache_invalidate_user(hwpt->domain, + &data_array); + } else if (pt_obj->type == IOMMUFD_OBJ_VIOMMU) { + struct iommufd_viommu *viommu = + container_of(pt_obj, struct iommufd_viommu, obj); + + if (!viommu->ops || !viommu->ops->cache_invalidate) { + rc = -EOPNOTSUPP; + goto out_put_pt; + } + rc = viommu->ops->cache_invalidate(viommu, &data_array); + } else { + rc = -EINVAL; + goto out_put_pt; + } - rc = hwpt->domain->ops->cache_invalidate_user(hwpt->domain, - &data_array); done_num = data_array.entry_num; - iommufd_put_object(ucmd->ictx, &hwpt->obj); +out_put_pt: + iommufd_put_object(ucmd->ictx, pt_obj); out: cmd->entry_num = done_num; if (iommufd_ucmd_respond(ucmd, sizeof(*cmd))) diff --git a/drivers/iommu/iommufd/io_pagetable.c b/drivers/iommu/iommufd/io_pagetable.c index 4bf7ccd39d465c..8a790e597e1253 100644 --- a/drivers/iommu/iommufd/io_pagetable.c +++ b/drivers/iommu/iommufd/io_pagetable.c @@ -107,9 +107,9 @@ static bool __alloc_iova_check_used(struct interval_tree_span_iter *span, * Does not return a 0 IOVA even if it is valid. */ static int iopt_alloc_iova(struct io_pagetable *iopt, unsigned long *iova, - unsigned long uptr, unsigned long length) + unsigned long addr, unsigned long length) { - unsigned long page_offset = uptr % PAGE_SIZE; + unsigned long page_offset = addr % PAGE_SIZE; struct interval_tree_double_span_iter used_span; struct interval_tree_span_iter allowed_span; unsigned long max_alignment = PAGE_SIZE; @@ -122,15 +122,15 @@ static int iopt_alloc_iova(struct io_pagetable *iopt, unsigned long *iova, return -EOVERFLOW; /* - * Keep alignment present in the uptr when building the IOVA, this + * Keep alignment present in addr when building the IOVA, which * increases the chance we can map a THP. */ - if (!uptr) + if (!addr) iova_alignment = roundup_pow_of_two(length); else iova_alignment = min_t(unsigned long, roundup_pow_of_two(length), - 1UL << __ffs64(uptr)); + 1UL << __ffs64(addr)); #ifdef CONFIG_TRANSPARENT_HUGEPAGE max_alignment = HPAGE_SIZE; @@ -248,6 +248,7 @@ static int iopt_alloc_area_pages(struct io_pagetable *iopt, int iommu_prot, unsigned int flags) { struct iopt_pages_list *elm; + unsigned long start; unsigned long iova; int rc = 0; @@ -267,9 +268,15 @@ static int iopt_alloc_area_pages(struct io_pagetable *iopt, /* Use the first entry to guess the ideal IOVA alignment */ elm = list_first_entry(pages_list, struct iopt_pages_list, next); - rc = iopt_alloc_iova( - iopt, dst_iova, - (uintptr_t)elm->pages->uptr + elm->start_byte, length); + switch (elm->pages->type) { + case IOPT_ADDRESS_USER: + start = elm->start_byte + (uintptr_t)elm->pages->uptr; + break; + case IOPT_ADDRESS_FILE: + start = elm->start_byte + elm->pages->start; + break; + } + rc = iopt_alloc_iova(iopt, dst_iova, start, length); if (rc) goto out_unlock; if (IS_ENABLED(CONFIG_IOMMUFD_TEST) && @@ -384,6 +391,34 @@ int iopt_map_pages(struct io_pagetable *iopt, struct list_head *pages_list, return rc; } +static int iopt_map_common(struct iommufd_ctx *ictx, struct io_pagetable *iopt, + struct iopt_pages *pages, unsigned long *iova, + unsigned long length, unsigned long start_byte, + int iommu_prot, unsigned int flags) +{ + struct iopt_pages_list elm = {}; + LIST_HEAD(pages_list); + int rc; + + elm.pages = pages; + elm.start_byte = start_byte; + if (ictx->account_mode == IOPT_PAGES_ACCOUNT_MM && + elm.pages->account_mode == IOPT_PAGES_ACCOUNT_USER) + elm.pages->account_mode = IOPT_PAGES_ACCOUNT_MM; + elm.length = length; + list_add(&elm.next, &pages_list); + + rc = iopt_map_pages(iopt, &pages_list, length, iova, iommu_prot, flags); + if (rc) { + if (elm.area) + iopt_abort_area(elm.area); + if (elm.pages) + iopt_put_pages(elm.pages); + return rc; + } + return 0; +} + /** * iopt_map_user_pages() - Map a user VA to an iova in the io page table * @ictx: iommufd_ctx the iopt is part of @@ -408,29 +443,41 @@ int iopt_map_user_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt, unsigned long length, int iommu_prot, unsigned int flags) { - struct iopt_pages_list elm = {}; - LIST_HEAD(pages_list); - int rc; + struct iopt_pages *pages; - elm.pages = iopt_alloc_pages(uptr, length, iommu_prot & IOMMU_WRITE); - if (IS_ERR(elm.pages)) - return PTR_ERR(elm.pages); - if (ictx->account_mode == IOPT_PAGES_ACCOUNT_MM && - elm.pages->account_mode == IOPT_PAGES_ACCOUNT_USER) - elm.pages->account_mode = IOPT_PAGES_ACCOUNT_MM; - elm.start_byte = uptr - elm.pages->uptr; - elm.length = length; - list_add(&elm.next, &pages_list); + pages = iopt_alloc_user_pages(uptr, length, iommu_prot & IOMMU_WRITE); + if (IS_ERR(pages)) + return PTR_ERR(pages); - rc = iopt_map_pages(iopt, &pages_list, length, iova, iommu_prot, flags); - if (rc) { - if (elm.area) - iopt_abort_area(elm.area); - if (elm.pages) - iopt_put_pages(elm.pages); - return rc; - } - return 0; + return iopt_map_common(ictx, iopt, pages, iova, length, + uptr - pages->uptr, iommu_prot, flags); +} + +/** + * iopt_map_file_pages() - Like iopt_map_user_pages, but map a file. + * @ictx: iommufd_ctx the iopt is part of + * @iopt: io_pagetable to act on + * @iova: If IOPT_ALLOC_IOVA is set this is unused on input and contains + * the chosen iova on output. Otherwise is the iova to map to on input + * @file: file to map + * @start: map file starting at this byte offset + * @length: Number of bytes to map + * @iommu_prot: Combination of IOMMU_READ/WRITE/etc bits for the mapping + * @flags: IOPT_ALLOC_IOVA or zero + */ +int iopt_map_file_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt, + unsigned long *iova, struct file *file, + unsigned long start, unsigned long length, + int iommu_prot, unsigned int flags) +{ + struct iopt_pages *pages; + + pages = iopt_alloc_file_pages(file, start, length, + iommu_prot & IOMMU_WRITE); + if (IS_ERR(pages)) + return PTR_ERR(pages); + return iopt_map_common(ictx, iopt, pages, iova, length, + start - pages->start, iommu_prot, flags); } struct iova_bitmap_fn_arg { diff --git a/drivers/iommu/iommufd/io_pagetable.h b/drivers/iommu/iommufd/io_pagetable.h index c61d74471684ee..10c928a9a46332 100644 --- a/drivers/iommu/iommufd/io_pagetable.h +++ b/drivers/iommu/iommufd/io_pagetable.h @@ -173,6 +173,12 @@ enum { IOPT_PAGES_ACCOUNT_NONE = 0, IOPT_PAGES_ACCOUNT_USER = 1, IOPT_PAGES_ACCOUNT_MM = 2, + IOPT_PAGES_ACCOUNT_MODE_NUM = 3, +}; + +enum iopt_address_type { + IOPT_ADDRESS_USER = 0, + IOPT_ADDRESS_FILE = 1, }; /* @@ -195,7 +201,14 @@ struct iopt_pages { struct task_struct *source_task; struct mm_struct *source_mm; struct user_struct *source_user; - void __user *uptr; + enum iopt_address_type type; + union { + void __user *uptr; /* IOPT_ADDRESS_USER */ + struct { /* IOPT_ADDRESS_FILE */ + struct file *file; + unsigned long start; + }; + }; bool writable:1; u8 account_mode; @@ -206,8 +219,10 @@ struct iopt_pages { struct rb_root_cached domains_itree; }; -struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length, - bool writable); +struct iopt_pages *iopt_alloc_user_pages(void __user *uptr, + unsigned long length, bool writable); +struct iopt_pages *iopt_alloc_file_pages(struct file *file, unsigned long start, + unsigned long length, bool writable); void iopt_release_pages(struct kref *kref); static inline void iopt_put_pages(struct iopt_pages *pages) { @@ -238,4 +253,9 @@ struct iopt_pages_access { unsigned int users; }; +struct pfn_reader_user; + +int iopt_pages_update_pinned(struct iopt_pages *pages, unsigned long npages, + bool inc, struct pfn_reader_user *user); + #endif diff --git a/drivers/iommu/iommufd/ioas.c b/drivers/iommu/iommufd/ioas.c index 2c4b2bb11e78ce..1542c5fd10a85c 100644 --- a/drivers/iommu/iommufd/ioas.c +++ b/drivers/iommu/iommufd/ioas.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES */ +#include #include #include #include @@ -51,7 +52,10 @@ int iommufd_ioas_alloc_ioctl(struct iommufd_ucmd *ucmd) rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); if (rc) goto out_table; + + down_read(&ucmd->ictx->ioas_creation_lock); iommufd_object_finalize(ucmd->ictx, &ioas->obj); + up_read(&ucmd->ictx->ioas_creation_lock); return 0; out_table: @@ -197,6 +201,52 @@ static int conv_iommu_prot(u32 map_flags) return iommu_prot; } +int iommufd_ioas_map_file(struct iommufd_ucmd *ucmd) +{ + struct iommu_ioas_map_file *cmd = ucmd->cmd; + unsigned long iova = cmd->iova; + struct iommufd_ioas *ioas; + unsigned int flags = 0; + struct file *file; + int rc; + + if (cmd->flags & + ~(IOMMU_IOAS_MAP_FIXED_IOVA | IOMMU_IOAS_MAP_WRITEABLE | + IOMMU_IOAS_MAP_READABLE)) + return -EOPNOTSUPP; + + if (cmd->iova >= ULONG_MAX || cmd->length >= ULONG_MAX) + return -EOVERFLOW; + + if (!(cmd->flags & + (IOMMU_IOAS_MAP_WRITEABLE | IOMMU_IOAS_MAP_READABLE))) + return -EINVAL; + + ioas = iommufd_get_ioas(ucmd->ictx, cmd->ioas_id); + if (IS_ERR(ioas)) + return PTR_ERR(ioas); + + if (!(cmd->flags & IOMMU_IOAS_MAP_FIXED_IOVA)) + flags = IOPT_ALLOC_IOVA; + + file = fget(cmd->fd); + if (!file) + return -EBADF; + + rc = iopt_map_file_pages(ucmd->ictx, &ioas->iopt, &iova, file, + cmd->start, cmd->length, + conv_iommu_prot(cmd->flags), flags); + if (rc) + goto out_put; + + cmd->iova = iova; + rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); +out_put: + iommufd_put_object(ucmd->ictx, &ioas->obj); + fput(file); + return rc; +} + int iommufd_ioas_map(struct iommufd_ucmd *ucmd) { struct iommu_ioas_map *cmd = ucmd->cmd; @@ -327,6 +377,215 @@ int iommufd_ioas_unmap(struct iommufd_ucmd *ucmd) return rc; } +static void iommufd_release_all_iova_rwsem(struct iommufd_ctx *ictx, + struct xarray *ioas_list) +{ + struct iommufd_ioas *ioas; + unsigned long index; + + xa_for_each(ioas_list, index, ioas) { + up_write(&ioas->iopt.iova_rwsem); + refcount_dec(&ioas->obj.users); + } + up_write(&ictx->ioas_creation_lock); + xa_destroy(ioas_list); +} + +static int iommufd_take_all_iova_rwsem(struct iommufd_ctx *ictx, + struct xarray *ioas_list) +{ + struct iommufd_object *obj; + unsigned long index; + int rc; + + /* + * This is very ugly, it is done instead of adding a lock around + * pages->source_mm, which is a performance path for mdev, we just + * obtain the write side of all the iova_rwsems which also protects the + * pages->source_*. Due to copies we can't know which IOAS could read + * from the pages, so we just lock everything. This is the only place + * locks are nested and they are uniformly taken in ID order. + * + * ioas_creation_lock prevents new IOAS from being installed in the + * xarray while we do this, and also prevents more than one thread from + * holding nested locks. + */ + down_write(&ictx->ioas_creation_lock); + xa_lock(&ictx->objects); + xa_for_each(&ictx->objects, index, obj) { + struct iommufd_ioas *ioas; + + if (!obj || obj->type != IOMMUFD_OBJ_IOAS) + continue; + + if (!refcount_inc_not_zero(&obj->users)) + continue; + + xa_unlock(&ictx->objects); + + ioas = container_of(obj, struct iommufd_ioas, obj); + down_write_nest_lock(&ioas->iopt.iova_rwsem, + &ictx->ioas_creation_lock); + + rc = xa_err(xa_store(ioas_list, index, ioas, GFP_KERNEL)); + if (rc) { + iommufd_release_all_iova_rwsem(ictx, ioas_list); + return rc; + } + + xa_lock(&ictx->objects); + } + xa_unlock(&ictx->objects); + return 0; +} + +static bool need_charge_update(struct iopt_pages *pages) +{ + switch (pages->account_mode) { + case IOPT_PAGES_ACCOUNT_NONE: + return false; + case IOPT_PAGES_ACCOUNT_MM: + return pages->source_mm != current->mm; + case IOPT_PAGES_ACCOUNT_USER: + /* + * Update when mm changes because it also accounts + * in mm->pinned_vm. + */ + return (pages->source_user != current_user()) || + (pages->source_mm != current->mm); + } + return true; +} + +static int charge_current(unsigned long *npinned) +{ + struct iopt_pages tmp = { + .source_mm = current->mm, + .source_task = current->group_leader, + .source_user = current_user(), + }; + unsigned int account_mode; + int rc; + + for (account_mode = 0; account_mode != IOPT_PAGES_ACCOUNT_MODE_NUM; + account_mode++) { + if (!npinned[account_mode]) + continue; + + tmp.account_mode = account_mode; + rc = iopt_pages_update_pinned(&tmp, npinned[account_mode], true, + NULL); + if (rc) + goto err_undo; + } + return 0; + +err_undo: + while (account_mode != 0) { + account_mode--; + if (!npinned[account_mode]) + continue; + tmp.account_mode = account_mode; + iopt_pages_update_pinned(&tmp, npinned[account_mode], false, + NULL); + } + return rc; +} + +static void change_mm(struct iopt_pages *pages) +{ + struct task_struct *old_task = pages->source_task; + struct user_struct *old_user = pages->source_user; + struct mm_struct *old_mm = pages->source_mm; + + pages->source_mm = current->mm; + mmgrab(pages->source_mm); + mmdrop(old_mm); + + pages->source_task = current->group_leader; + get_task_struct(pages->source_task); + put_task_struct(old_task); + + pages->source_user = get_uid(current_user()); + free_uid(old_user); +} + +#define for_each_ioas_area(_xa, _index, _ioas, _area) \ + xa_for_each((_xa), (_index), (_ioas)) \ + for (_area = iopt_area_iter_first(&_ioas->iopt, 0, ULONG_MAX); \ + _area; \ + _area = iopt_area_iter_next(_area, 0, ULONG_MAX)) + +int iommufd_ioas_change_process(struct iommufd_ucmd *ucmd) +{ + struct iommu_ioas_change_process *cmd = ucmd->cmd; + struct iommufd_ctx *ictx = ucmd->ictx; + unsigned long all_npinned[IOPT_PAGES_ACCOUNT_MODE_NUM] = {}; + struct iommufd_ioas *ioas; + struct iopt_area *area; + struct iopt_pages *pages; + struct xarray ioas_list; + unsigned long index; + int rc; + + if (cmd->__reserved) + return -EOPNOTSUPP; + + xa_init(&ioas_list); + rc = iommufd_take_all_iova_rwsem(ictx, &ioas_list); + if (rc) + return rc; + + for_each_ioas_area(&ioas_list, index, ioas, area) { + if (area->pages->type != IOPT_ADDRESS_FILE) { + rc = -EINVAL; + goto out; + } + } + + /* + * Count last_pinned pages, then clear it to avoid double counting + * if the same iopt_pages is visited multiple times in this loop. + * Since we are under all the locks, npinned == last_npinned, so we + * can easily restore last_npinned before we return. + */ + for_each_ioas_area(&ioas_list, index, ioas, area) { + pages = area->pages; + + if (need_charge_update(pages)) { + all_npinned[pages->account_mode] += pages->last_npinned; + pages->last_npinned = 0; + } + } + + rc = charge_current(all_npinned); + + if (rc) { + /* Charge failed. Fix last_npinned and bail. */ + for_each_ioas_area(&ioas_list, index, ioas, area) + area->pages->last_npinned = area->pages->npinned; + goto out; + } + + for_each_ioas_area(&ioas_list, index, ioas, area) { + pages = area->pages; + + /* Uncharge the old one (which also restores last_npinned) */ + if (need_charge_update(pages)) { + int r = iopt_pages_update_pinned(pages, pages->npinned, + false, NULL); + + if (WARN_ON(r)) + rc = r; + } + change_mm(pages); + } + +out: + iommufd_release_all_iova_rwsem(ictx, &ioas_list); + return rc; +} + int iommufd_option_rlimit_mode(struct iommu_option *cmd, struct iommufd_ctx *ictx) { diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h index f1d865e6fab66a..b6d706cf2c66fb 100644 --- a/drivers/iommu/iommufd/iommufd_private.h +++ b/drivers/iommu/iommufd/iommufd_private.h @@ -5,8 +5,8 @@ #define __IOMMUFD_PRIVATE_H #include +#include #include -#include #include #include #include @@ -24,6 +24,7 @@ struct iommufd_ctx { struct xarray objects; struct xarray groups; wait_queue_head_t destroy_wait; + struct rw_semaphore ioas_creation_lock; u8 account_mode; /* Compatibility with VFIO no iommu */ @@ -69,6 +70,10 @@ int iopt_map_user_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt, unsigned long *iova, void __user *uptr, unsigned long length, int iommu_prot, unsigned int flags); +int iopt_map_file_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt, + unsigned long *iova, struct file *file, + unsigned long start, unsigned long length, + int iommu_prot, unsigned int flags); int iopt_map_pages(struct io_pagetable *iopt, struct list_head *pages_list, unsigned long length, unsigned long *dst_iova, int iommu_prot, unsigned int flags); @@ -122,29 +127,6 @@ static inline int iommufd_ucmd_respond(struct iommufd_ucmd *ucmd, return 0; } -enum iommufd_object_type { - IOMMUFD_OBJ_NONE, - IOMMUFD_OBJ_ANY = IOMMUFD_OBJ_NONE, - IOMMUFD_OBJ_DEVICE, - IOMMUFD_OBJ_HWPT_PAGING, - IOMMUFD_OBJ_HWPT_NESTED, - IOMMUFD_OBJ_IOAS, - IOMMUFD_OBJ_ACCESS, - IOMMUFD_OBJ_FAULT, -#ifdef CONFIG_IOMMUFD_TEST - IOMMUFD_OBJ_SELFTEST, -#endif - IOMMUFD_OBJ_MAX, -}; - -/* Base struct for all objects with a userspace ID handle. */ -struct iommufd_object { - refcount_t shortterm_users; - refcount_t users; - enum iommufd_object_type type; - unsigned int id; -}; - static inline bool iommufd_lock_obj(struct iommufd_object *obj) { if (!refcount_inc_not_zero(&obj->users)) @@ -225,10 +207,6 @@ iommufd_object_put_and_try_destroy(struct iommufd_ctx *ictx, iommufd_object_remove(ictx, obj, obj->id, 0); } -struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx, - size_t size, - enum iommufd_object_type type); - #define __iommufd_object_alloc(ictx, ptr, type, obj) \ container_of(_iommufd_object_alloc( \ ictx, \ @@ -276,6 +254,8 @@ void iommufd_ioas_destroy(struct iommufd_object *obj); int iommufd_ioas_iova_ranges(struct iommufd_ucmd *ucmd); int iommufd_ioas_allow_iovas(struct iommufd_ucmd *ucmd); int iommufd_ioas_map(struct iommufd_ucmd *ucmd); +int iommufd_ioas_map_file(struct iommufd_ucmd *ucmd); +int iommufd_ioas_change_process(struct iommufd_ucmd *ucmd); int iommufd_ioas_copy(struct iommufd_ucmd *ucmd); int iommufd_ioas_unmap(struct iommufd_ucmd *ucmd); int iommufd_ioas_option(struct iommufd_ucmd *ucmd); @@ -312,6 +292,7 @@ struct iommufd_hwpt_paging { struct iommufd_hwpt_nested { struct iommufd_hw_pagetable common; struct iommufd_hwpt_paging *parent; + struct iommufd_viommu *viommu; }; static inline bool hwpt_is_paging(struct iommufd_hw_pagetable *hwpt) @@ -528,6 +509,27 @@ static inline int iommufd_hwpt_replace_device(struct iommufd_device *idev, return iommu_group_replace_domain(idev->igroup->group, hwpt->domain); } +static inline struct iommufd_viommu * +iommufd_get_viommu(struct iommufd_ucmd *ucmd, u32 id) +{ + return container_of(iommufd_get_object(ucmd->ictx, id, + IOMMUFD_OBJ_VIOMMU), + struct iommufd_viommu, obj); +} + +int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd); +void iommufd_viommu_destroy(struct iommufd_object *obj); +int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd); +void iommufd_vdevice_destroy(struct iommufd_object *obj); + +struct iommufd_vdevice { + struct iommufd_object obj; + struct iommufd_ctx *ictx; + struct iommufd_viommu *viommu; + struct device *dev; + u64 id; /* per-vIOMMU virtual ID */ +}; + #ifdef CONFIG_IOMMUFD_TEST int iommufd_test(struct iommufd_ucmd *ucmd); void iommufd_selftest_destroy(struct iommufd_object *obj); diff --git a/drivers/iommu/iommufd/iommufd_test.h b/drivers/iommu/iommufd/iommufd_test.h index f4bc23a92f9a2e..a6b7a163f6364c 100644 --- a/drivers/iommu/iommufd/iommufd_test.h +++ b/drivers/iommu/iommufd/iommufd_test.h @@ -23,6 +23,7 @@ enum { IOMMU_TEST_OP_DIRTY, IOMMU_TEST_OP_MD_CHECK_IOTLB, IOMMU_TEST_OP_TRIGGER_IOPF, + IOMMU_TEST_OP_DEV_CHECK_CACHE, }; enum { @@ -54,6 +55,11 @@ enum { MOCK_NESTED_DOMAIN_IOTLB_NUM = 4, }; +enum { + MOCK_DEV_CACHE_ID_MAX = 3, + MOCK_DEV_CACHE_NUM = 4, +}; + struct iommu_test_cmd { __u32 size; __u32 op; @@ -135,6 +141,10 @@ struct iommu_test_cmd { __u32 perm; __u64 addr; } trigger_iopf; + struct { + __u32 id; + __u32 cache; + } check_dev_cache; }; __u32 last; }; @@ -152,6 +162,7 @@ struct iommu_test_hw_info { /* Should not be equal to any defined value in enum iommu_hwpt_data_type */ #define IOMMU_HWPT_DATA_SELFTEST 0xdead #define IOMMU_TEST_IOTLB_DEFAULT 0xbadbeef +#define IOMMU_TEST_DEV_CACHE_DEFAULT 0xbaddad /** * struct iommu_hwpt_selftest @@ -180,4 +191,25 @@ struct iommu_hwpt_invalidate_selftest { __u32 iotlb_id; }; +#define IOMMU_VIOMMU_TYPE_SELFTEST 0xdeadbeef + +/* Should not be equal to any defined value in enum iommu_viommu_invalidate_data_type */ +#define IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST 0xdeadbeef +#define IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST_INVALID 0xdadbeef + +/** + * struct iommu_viommu_invalidate_selftest - Invalidation data for Mock VIOMMU + * (IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST) + * @flags: Invalidate flags + * @cache_id: Invalidate cache entry index + * + * If IOMMU_TEST_INVALIDATE_ALL is set in @flags, @cache_id will be ignored + */ +struct iommu_viommu_invalidate_selftest { +#define IOMMU_TEST_INVALIDATE_FLAG_ALL (1 << 0) + __u32 flags; + __u32 vdev_id; + __u32 cache_id; +}; + #endif diff --git a/drivers/iommu/iommufd/iova_bitmap.c b/drivers/iommu/iommufd/iova_bitmap.c index d90b9e253412ff..ab665cf38ef4a9 100644 --- a/drivers/iommu/iommufd/iova_bitmap.c +++ b/drivers/iommu/iommufd/iova_bitmap.c @@ -272,7 +272,7 @@ struct iova_bitmap *iova_bitmap_alloc(unsigned long iova, size_t length, iova_bitmap_free(bitmap); return ERR_PTR(rc); } -EXPORT_SYMBOL_NS_GPL(iova_bitmap_alloc, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iova_bitmap_alloc, "IOMMUFD"); /** * iova_bitmap_free() - Frees an IOVA bitmap object @@ -294,7 +294,7 @@ void iova_bitmap_free(struct iova_bitmap *bitmap) kfree(bitmap); } -EXPORT_SYMBOL_NS_GPL(iova_bitmap_free, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iova_bitmap_free, "IOMMUFD"); /* * Returns the remaining bitmap indexes from mapped_total_index to process for @@ -387,7 +387,7 @@ int iova_bitmap_for_each(struct iova_bitmap *bitmap, void *opaque, { return fn(bitmap, bitmap->iova, bitmap->length, opaque); } -EXPORT_SYMBOL_NS_GPL(iova_bitmap_for_each, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iova_bitmap_for_each, "IOMMUFD"); /** * iova_bitmap_set() - Records an IOVA range in bitmap @@ -445,4 +445,4 @@ void iova_bitmap_set(struct iova_bitmap *bitmap, cur_bit += nbits; } while (cur_bit <= last_bit); } -EXPORT_SYMBOL_NS_GPL(iova_bitmap_set, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iova_bitmap_set, "IOMMUFD"); diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c index b5f5d27ee9634e..97c5e3567d33e4 100644 --- a/drivers/iommu/iommufd/main.c +++ b/drivers/iommu/iommufd/main.c @@ -29,38 +29,6 @@ struct iommufd_object_ops { static const struct iommufd_object_ops iommufd_object_ops[]; static struct miscdevice vfio_misc_dev; -struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx, - size_t size, - enum iommufd_object_type type) -{ - struct iommufd_object *obj; - int rc; - - obj = kzalloc(size, GFP_KERNEL_ACCOUNT); - if (!obj) - return ERR_PTR(-ENOMEM); - obj->type = type; - /* Starts out bias'd by 1 until it is removed from the xarray */ - refcount_set(&obj->shortterm_users, 1); - refcount_set(&obj->users, 1); - - /* - * Reserve an ID in the xarray but do not publish the pointer yet since - * the caller hasn't initialized it yet. Once the pointer is published - * in the xarray and visible to other threads we can't reliably destroy - * it anymore, so the caller must complete all errorable operations - * before calling iommufd_object_finalize(). - */ - rc = xa_alloc(&ictx->objects, &obj->id, XA_ZERO_ENTRY, - xa_limit_31b, GFP_KERNEL_ACCOUNT); - if (rc) - goto out_free; - return obj; -out_free: - kfree(obj); - return ERR_PTR(rc); -} - /* * Allow concurrent access to the object. * @@ -73,20 +41,26 @@ struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx, void iommufd_object_finalize(struct iommufd_ctx *ictx, struct iommufd_object *obj) { + XA_STATE(xas, &ictx->objects, obj->id); void *old; - old = xa_store(&ictx->objects, obj->id, obj, GFP_KERNEL); - /* obj->id was returned from xa_alloc() so the xa_store() cannot fail */ - WARN_ON(old); + xa_lock(&ictx->objects); + old = xas_store(&xas, obj); + xa_unlock(&ictx->objects); + /* obj->id was returned from xa_alloc() so the xas_store() cannot fail */ + WARN_ON(old != XA_ZERO_ENTRY); } /* Undo _iommufd_object_alloc() if iommufd_object_finalize() was not called */ void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj) { + XA_STATE(xas, &ictx->objects, obj->id); void *old; - old = xa_erase(&ictx->objects, obj->id); - WARN_ON(old); + xa_lock(&ictx->objects); + old = xas_store(&xas, NULL); + xa_unlock(&ictx->objects); + WARN_ON(old != XA_ZERO_ENTRY); kfree(obj); } @@ -248,6 +222,7 @@ static int iommufd_fops_open(struct inode *inode, struct file *filp) pr_info_once("IOMMUFD is providing /dev/vfio/vfio, not VFIO.\n"); } + init_rwsem(&ictx->ioas_creation_lock); xa_init_flags(&ictx->objects, XA_FLAGS_ALLOC1 | XA_FLAGS_ACCOUNT); xa_init(&ictx->groups); ictx->file = filp; @@ -333,6 +308,8 @@ union ucmd_buffer { struct iommu_ioas_unmap unmap; struct iommu_option option; struct iommu_vfio_ioas vfio_ioas; + struct iommu_viommu_alloc viommu; + struct iommu_vdevice_alloc vdev; #ifdef CONFIG_IOMMUFD_TEST struct iommu_test_cmd test; #endif @@ -372,18 +349,26 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = { struct iommu_ioas_alloc, out_ioas_id), IOCTL_OP(IOMMU_IOAS_ALLOW_IOVAS, iommufd_ioas_allow_iovas, struct iommu_ioas_allow_iovas, allowed_iovas), + IOCTL_OP(IOMMU_IOAS_CHANGE_PROCESS, iommufd_ioas_change_process, + struct iommu_ioas_change_process, __reserved), IOCTL_OP(IOMMU_IOAS_COPY, iommufd_ioas_copy, struct iommu_ioas_copy, src_iova), IOCTL_OP(IOMMU_IOAS_IOVA_RANGES, iommufd_ioas_iova_ranges, struct iommu_ioas_iova_ranges, out_iova_alignment), IOCTL_OP(IOMMU_IOAS_MAP, iommufd_ioas_map, struct iommu_ioas_map, iova), + IOCTL_OP(IOMMU_IOAS_MAP_FILE, iommufd_ioas_map_file, + struct iommu_ioas_map_file, iova), IOCTL_OP(IOMMU_IOAS_UNMAP, iommufd_ioas_unmap, struct iommu_ioas_unmap, length), IOCTL_OP(IOMMU_OPTION, iommufd_option, struct iommu_option, val64), IOCTL_OP(IOMMU_VFIO_IOAS, iommufd_vfio_ioas, struct iommu_vfio_ioas, __reserved), + IOCTL_OP(IOMMU_VIOMMU_ALLOC, iommufd_viommu_alloc_ioctl, + struct iommu_viommu_alloc, out_viommu_id), + IOCTL_OP(IOMMU_VDEVICE_ALLOC, iommufd_vdevice_alloc_ioctl, + struct iommu_vdevice_alloc, virt_id), #ifdef CONFIG_IOMMUFD_TEST IOCTL_OP(IOMMU_TEST_CMD, iommufd_test, struct iommu_test_cmd, last), #endif @@ -442,7 +427,7 @@ void iommufd_ctx_get(struct iommufd_ctx *ictx) { get_file(ictx->file); } -EXPORT_SYMBOL_NS_GPL(iommufd_ctx_get, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_ctx_get, "IOMMUFD"); /** * iommufd_ctx_from_file - Acquires a reference to the iommufd context @@ -462,7 +447,7 @@ struct iommufd_ctx *iommufd_ctx_from_file(struct file *file) iommufd_ctx_get(ictx); return ictx; } -EXPORT_SYMBOL_NS_GPL(iommufd_ctx_from_file, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_ctx_from_file, "IOMMUFD"); /** * iommufd_ctx_from_fd - Acquires a reference to the iommufd context @@ -486,7 +471,7 @@ struct iommufd_ctx *iommufd_ctx_from_fd(int fd) /* fget is the same as iommufd_ctx_get() */ return file->private_data; } -EXPORT_SYMBOL_NS_GPL(iommufd_ctx_from_fd, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_ctx_from_fd, "IOMMUFD"); /** * iommufd_ctx_put - Put back a reference @@ -496,7 +481,7 @@ void iommufd_ctx_put(struct iommufd_ctx *ictx) { fput(ictx->file); } -EXPORT_SYMBOL_NS_GPL(iommufd_ctx_put, IOMMUFD); +EXPORT_SYMBOL_NS_GPL(iommufd_ctx_put, "IOMMUFD"); static const struct iommufd_object_ops iommufd_object_ops[] = { [IOMMUFD_OBJ_ACCESS] = { @@ -519,6 +504,12 @@ static const struct iommufd_object_ops iommufd_object_ops[] = { [IOMMUFD_OBJ_FAULT] = { .destroy = iommufd_fault_destroy, }, + [IOMMUFD_OBJ_VIOMMU] = { + .destroy = iommufd_viommu_destroy, + }, + [IOMMUFD_OBJ_VDEVICE] = { + .destroy = iommufd_vdevice_destroy, + }, #ifdef CONFIG_IOMMUFD_TEST [IOMMUFD_OBJ_SELFTEST] = { .destroy = iommufd_selftest_destroy, @@ -584,7 +575,7 @@ module_exit(iommufd_exit); MODULE_ALIAS_MISCDEV(VFIO_MINOR); MODULE_ALIAS("devname:vfio/vfio"); #endif -MODULE_IMPORT_NS(IOMMUFD_INTERNAL); -MODULE_IMPORT_NS(IOMMUFD); +MODULE_IMPORT_NS("IOMMUFD_INTERNAL"); +MODULE_IMPORT_NS("IOMMUFD"); MODULE_DESCRIPTION("I/O Address Space Management for passthrough devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/iommu/iommufd/pages.c b/drivers/iommu/iommufd/pages.c index 93d806c9c07318..3427749bc5ce1b 100644 --- a/drivers/iommu/iommufd/pages.c +++ b/drivers/iommu/iommufd/pages.c @@ -45,6 +45,7 @@ * last_iova + 1 can overflow. An iopt_pages index will always be much less than * ULONG_MAX so last_index + 1 cannot overflow. */ +#include #include #include #include @@ -346,27 +347,41 @@ static void batch_destroy(struct pfn_batch *batch, void *backup) kfree(batch->pfns); } -/* true if the pfn was added, false otherwise */ -static bool batch_add_pfn(struct pfn_batch *batch, unsigned long pfn) +static bool batch_add_pfn_num(struct pfn_batch *batch, unsigned long pfn, + u32 nr) { const unsigned int MAX_NPFNS = type_max(typeof(*batch->npfns)); - - if (batch->end && - pfn == batch->pfns[batch->end - 1] + batch->npfns[batch->end - 1] && - batch->npfns[batch->end - 1] != MAX_NPFNS) { - batch->npfns[batch->end - 1]++; - batch->total_pfns++; - return true; - } - if (batch->end == batch->array_size) + unsigned int end = batch->end; + + if (end && pfn == batch->pfns[end - 1] + batch->npfns[end - 1] && + nr <= MAX_NPFNS - batch->npfns[end - 1]) { + batch->npfns[end - 1] += nr; + } else if (end < batch->array_size) { + batch->pfns[end] = pfn; + batch->npfns[end] = nr; + batch->end++; + } else { return false; - batch->total_pfns++; - batch->pfns[batch->end] = pfn; - batch->npfns[batch->end] = 1; - batch->end++; + } + + batch->total_pfns += nr; return true; } +static void batch_remove_pfn_num(struct pfn_batch *batch, unsigned long nr) +{ + batch->npfns[batch->end - 1] -= nr; + if (batch->npfns[batch->end - 1] == 0) + batch->end--; + batch->total_pfns -= nr; +} + +/* true if the pfn was added, false otherwise */ +static bool batch_add_pfn(struct pfn_batch *batch, unsigned long pfn) +{ + return batch_add_pfn_num(batch, pfn, 1); +} + /* * Fill the batch with pfns from the domain. When the batch is full, or it * reaches last_index, the function will return. The caller should use @@ -622,6 +637,41 @@ static void batch_from_pages(struct pfn_batch *batch, struct page **pages, break; } +static int batch_from_folios(struct pfn_batch *batch, struct folio ***folios_p, + unsigned long *offset_p, unsigned long npages) +{ + int rc = 0; + struct folio **folios = *folios_p; + unsigned long offset = *offset_p; + + while (npages) { + struct folio *folio = *folios; + unsigned long nr = folio_nr_pages(folio) - offset; + unsigned long pfn = page_to_pfn(folio_page(folio, offset)); + + nr = min(nr, npages); + npages -= nr; + + if (!batch_add_pfn_num(batch, pfn, nr)) + break; + if (nr > 1) { + rc = folio_add_pins(folio, nr - 1); + if (rc) { + batch_remove_pfn_num(batch, nr); + goto out; + } + } + + folios++; + offset = 0; + } + +out: + *folios_p = folios; + *offset_p = offset; + return rc; +} + static void batch_unpin(struct pfn_batch *batch, struct iopt_pages *pages, unsigned int first_page_off, size_t npages) { @@ -703,19 +753,32 @@ struct pfn_reader_user { * neither */ int locked; + + /* The following are only valid if file != NULL. */ + struct file *file; + struct folio **ufolios; + size_t ufolios_len; + unsigned long ufolios_offset; + struct folio **ufolios_next; }; static void pfn_reader_user_init(struct pfn_reader_user *user, struct iopt_pages *pages) { user->upages = NULL; + user->upages_len = 0; user->upages_start = 0; user->upages_end = 0; user->locked = -1; - user->gup_flags = FOLL_LONGTERM; if (pages->writable) user->gup_flags |= FOLL_WRITE; + + user->file = (pages->type == IOPT_ADDRESS_FILE) ? pages->file : NULL; + user->ufolios = NULL; + user->ufolios_len = 0; + user->ufolios_next = NULL; + user->ufolios_offset = 0; } static void pfn_reader_user_destroy(struct pfn_reader_user *user, @@ -724,13 +787,67 @@ static void pfn_reader_user_destroy(struct pfn_reader_user *user, if (user->locked != -1) { if (user->locked) mmap_read_unlock(pages->source_mm); - if (pages->source_mm != current->mm) + if (!user->file && pages->source_mm != current->mm) mmput(pages->source_mm); user->locked = -1; } kfree(user->upages); user->upages = NULL; + kfree(user->ufolios); + user->ufolios = NULL; +} + +static long pin_memfd_pages(struct pfn_reader_user *user, unsigned long start, + unsigned long npages) +{ + unsigned long i; + unsigned long offset; + unsigned long npages_out = 0; + struct page **upages = user->upages; + unsigned long end = start + (npages << PAGE_SHIFT) - 1; + long nfolios = user->ufolios_len / sizeof(*user->ufolios); + + /* + * todo: memfd_pin_folios should return the last pinned offset so + * we can compute npages pinned, and avoid looping over folios here + * if upages == NULL. + */ + nfolios = memfd_pin_folios(user->file, start, end, user->ufolios, + nfolios, &offset); + if (nfolios <= 0) + return nfolios; + + offset >>= PAGE_SHIFT; + user->ufolios_next = user->ufolios; + user->ufolios_offset = offset; + + for (i = 0; i < nfolios; i++) { + struct folio *folio = user->ufolios[i]; + unsigned long nr = folio_nr_pages(folio); + unsigned long npin = min(nr - offset, npages); + + npages -= npin; + npages_out += npin; + + if (upages) { + if (npin == 1) { + *upages++ = folio_page(folio, offset); + } else { + int rc = folio_add_pins(folio, npin - 1); + + if (rc) + return rc; + + while (npin--) + *upages++ = folio_page(folio, offset++); + } + } + + offset = 0; + } + + return npages_out; } static int pfn_reader_user_pin(struct pfn_reader_user *user, @@ -739,7 +856,9 @@ static int pfn_reader_user_pin(struct pfn_reader_user *user, unsigned long last_index) { bool remote_mm = pages->source_mm != current->mm; - unsigned long npages; + unsigned long npages = last_index - start_index + 1; + unsigned long start; + unsigned long unum; uintptr_t uptr; long rc; @@ -747,40 +866,50 @@ static int pfn_reader_user_pin(struct pfn_reader_user *user, WARN_ON(last_index < start_index)) return -EINVAL; - if (!user->upages) { + if (!user->file && !user->upages) { /* All undone in pfn_reader_destroy() */ - user->upages_len = - (last_index - start_index + 1) * sizeof(*user->upages); + user->upages_len = npages * sizeof(*user->upages); user->upages = temp_kmalloc(&user->upages_len, NULL, 0); if (!user->upages) return -ENOMEM; } + if (user->file && !user->ufolios) { + user->ufolios_len = npages * sizeof(*user->ufolios); + user->ufolios = temp_kmalloc(&user->ufolios_len, NULL, 0); + if (!user->ufolios) + return -ENOMEM; + } + if (user->locked == -1) { /* * The majority of usages will run the map task within the mm * providing the pages, so we can optimize into * get_user_pages_fast() */ - if (remote_mm) { + if (!user->file && remote_mm) { if (!mmget_not_zero(pages->source_mm)) return -EFAULT; } user->locked = 0; } - npages = min_t(unsigned long, last_index - start_index + 1, - user->upages_len / sizeof(*user->upages)); - + unum = user->file ? user->ufolios_len / sizeof(*user->ufolios) : + user->upages_len / sizeof(*user->upages); + npages = min_t(unsigned long, npages, unum); if (iommufd_should_fail()) return -EFAULT; - uptr = (uintptr_t)(pages->uptr + start_index * PAGE_SIZE); - if (!remote_mm) + if (user->file) { + start = pages->start + (start_index * PAGE_SIZE); + rc = pin_memfd_pages(user, start, npages); + } else if (!remote_mm) { + uptr = (uintptr_t)(pages->uptr + start_index * PAGE_SIZE); rc = pin_user_pages_fast(uptr, npages, user->gup_flags, user->upages); - else { + } else { + uptr = (uintptr_t)(pages->uptr + start_index * PAGE_SIZE); if (!user->locked) { mmap_read_lock(pages->source_mm); user->locked = 1; @@ -838,7 +967,8 @@ static int update_mm_locked_vm(struct iopt_pages *pages, unsigned long npages, mmap_read_unlock(pages->source_mm); user->locked = 0; /* If we had the lock then we also have a get */ - } else if ((!user || !user->upages) && + + } else if ((!user || (!user->upages && !user->ufolios)) && pages->source_mm != current->mm) { if (!mmget_not_zero(pages->source_mm)) return -EINVAL; @@ -855,8 +985,8 @@ static int update_mm_locked_vm(struct iopt_pages *pages, unsigned long npages, return rc; } -static int do_update_pinned(struct iopt_pages *pages, unsigned long npages, - bool inc, struct pfn_reader_user *user) +int iopt_pages_update_pinned(struct iopt_pages *pages, unsigned long npages, + bool inc, struct pfn_reader_user *user) { int rc = 0; @@ -890,8 +1020,8 @@ static void update_unpinned(struct iopt_pages *pages) return; if (pages->npinned == pages->last_npinned) return; - do_update_pinned(pages, pages->last_npinned - pages->npinned, false, - NULL); + iopt_pages_update_pinned(pages, pages->last_npinned - pages->npinned, + false, NULL); } /* @@ -921,7 +1051,7 @@ static int pfn_reader_user_update_pinned(struct pfn_reader_user *user, npages = pages->npinned - pages->last_npinned; inc = true; } - return do_update_pinned(pages, npages, inc, user); + return iopt_pages_update_pinned(pages, npages, inc, user); } /* @@ -978,6 +1108,8 @@ static int pfn_reader_fill_span(struct pfn_reader *pfns) { struct interval_tree_double_span_iter *span = &pfns->span; unsigned long start_index = pfns->batch_end_index; + struct pfn_reader_user *user = &pfns->user; + unsigned long npages; struct iopt_area *area; int rc; @@ -1015,11 +1147,17 @@ static int pfn_reader_fill_span(struct pfn_reader *pfns) return rc; } - batch_from_pages(&pfns->batch, - pfns->user.upages + - (start_index - pfns->user.upages_start), - pfns->user.upages_end - start_index); - return 0; + npages = user->upages_end - start_index; + start_index -= user->upages_start; + rc = 0; + + if (!user->file) + batch_from_pages(&pfns->batch, user->upages + start_index, + npages); + else + rc = batch_from_folios(&pfns->batch, &user->ufolios_next, + &user->ufolios_offset, npages); + return rc; } static bool pfn_reader_done(struct pfn_reader *pfns) @@ -1092,16 +1230,25 @@ static int pfn_reader_init(struct pfn_reader *pfns, struct iopt_pages *pages, static void pfn_reader_release_pins(struct pfn_reader *pfns) { struct iopt_pages *pages = pfns->pages; + struct pfn_reader_user *user = &pfns->user; - if (pfns->user.upages_end > pfns->batch_end_index) { - size_t npages = pfns->user.upages_end - pfns->batch_end_index; - + if (user->upages_end > pfns->batch_end_index) { /* Any pages not transferred to the batch are just unpinned */ - unpin_user_pages(pfns->user.upages + (pfns->batch_end_index - - pfns->user.upages_start), - npages); + + unsigned long npages = user->upages_end - pfns->batch_end_index; + unsigned long start_index = pfns->batch_end_index - + user->upages_start; + + if (!user->file) { + unpin_user_pages(user->upages + start_index, npages); + } else { + long n = user->ufolios_len / sizeof(*user->ufolios); + + unpin_folios(user->ufolios_next, + user->ufolios + n - user->ufolios_next); + } iopt_pages_sub_npinned(pages, npages); - pfns->user.upages_end = pfns->batch_end_index; + user->upages_end = pfns->batch_end_index; } if (pfns->batch_start_index != pfns->batch_end_index) { pfn_reader_unpin(pfns); @@ -1139,11 +1286,11 @@ static int pfn_reader_first(struct pfn_reader *pfns, struct iopt_pages *pages, return 0; } -struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length, - bool writable) +static struct iopt_pages *iopt_alloc_pages(unsigned long start_byte, + unsigned long length, + bool writable) { struct iopt_pages *pages; - unsigned long end; /* * The iommu API uses size_t as the length, and protect the DIV_ROUND_UP @@ -1152,9 +1299,6 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length, if (length > SIZE_MAX - PAGE_SIZE || length == 0) return ERR_PTR(-EINVAL); - if (check_add_overflow((unsigned long)uptr, length, &end)) - return ERR_PTR(-EOVERFLOW); - pages = kzalloc(sizeof(*pages), GFP_KERNEL_ACCOUNT); if (!pages) return ERR_PTR(-ENOMEM); @@ -1164,8 +1308,7 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length, mutex_init(&pages->mutex); pages->source_mm = current->mm; mmgrab(pages->source_mm); - pages->uptr = (void __user *)ALIGN_DOWN((uintptr_t)uptr, PAGE_SIZE); - pages->npages = DIV_ROUND_UP(length + (uptr - pages->uptr), PAGE_SIZE); + pages->npages = DIV_ROUND_UP(length + start_byte, PAGE_SIZE); pages->access_itree = RB_ROOT_CACHED; pages->domains_itree = RB_ROOT_CACHED; pages->writable = writable; @@ -1179,6 +1322,45 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length, return pages; } +struct iopt_pages *iopt_alloc_user_pages(void __user *uptr, + unsigned long length, bool writable) +{ + struct iopt_pages *pages; + unsigned long end; + void __user *uptr_down = + (void __user *) ALIGN_DOWN((uintptr_t)uptr, PAGE_SIZE); + + if (check_add_overflow((unsigned long)uptr, length, &end)) + return ERR_PTR(-EOVERFLOW); + + pages = iopt_alloc_pages(uptr - uptr_down, length, writable); + if (IS_ERR(pages)) + return pages; + pages->uptr = uptr_down; + pages->type = IOPT_ADDRESS_USER; + return pages; +} + +struct iopt_pages *iopt_alloc_file_pages(struct file *file, unsigned long start, + unsigned long length, bool writable) + +{ + struct iopt_pages *pages; + unsigned long start_down = ALIGN_DOWN(start, PAGE_SIZE); + unsigned long end; + + if (length && check_add_overflow(start, length - 1, &end)) + return ERR_PTR(-EOVERFLOW); + + pages = iopt_alloc_pages(start - start_down, length, writable); + if (IS_ERR(pages)) + return pages; + pages->file = get_file(file); + pages->start = start_down; + pages->type = IOPT_ADDRESS_FILE; + return pages; +} + void iopt_release_pages(struct kref *kref) { struct iopt_pages *pages = container_of(kref, struct iopt_pages, kref); @@ -1191,6 +1373,8 @@ void iopt_release_pages(struct kref *kref) mutex_destroy(&pages->mutex); put_task_struct(pages->source_task); free_uid(pages->source_user); + if (pages->type == IOPT_ADDRESS_FILE) + fput(pages->file); kfree(pages); } @@ -1630,11 +1814,11 @@ static int iopt_pages_fill_from_domain(struct iopt_pages *pages, return 0; } -static int iopt_pages_fill_from_mm(struct iopt_pages *pages, - struct pfn_reader_user *user, - unsigned long start_index, - unsigned long last_index, - struct page **out_pages) +static int iopt_pages_fill(struct iopt_pages *pages, + struct pfn_reader_user *user, + unsigned long start_index, + unsigned long last_index, + struct page **out_pages) { unsigned long cur_index = start_index; int rc; @@ -1708,8 +1892,8 @@ int iopt_pages_fill_xarray(struct iopt_pages *pages, unsigned long start_index, /* hole */ cur_pages = out_pages + (span.start_hole - start_index); - rc = iopt_pages_fill_from_mm(pages, &user, span.start_hole, - span.last_hole, cur_pages); + rc = iopt_pages_fill(pages, &user, span.start_hole, + span.last_hole, cur_pages); if (rc) goto out_clean_xa; rc = pages_to_xarray(&pages->pinned_pfns, span.start_hole, @@ -1789,6 +1973,10 @@ static int iopt_pages_rw_page(struct iopt_pages *pages, unsigned long index, struct page *page = NULL; int rc; + if (IS_ENABLED(CONFIG_IOMMUFD_TEST) && + WARN_ON(pages->type != IOPT_ADDRESS_USER)) + return -EINVAL; + if (!mmget_not_zero(pages->source_mm)) return iopt_pages_rw_slow(pages, index, index, offset, data, length, flags); @@ -1844,6 +2032,15 @@ int iopt_pages_rw_access(struct iopt_pages *pages, unsigned long start_byte, if ((flags & IOMMUFD_ACCESS_RW_WRITE) && !pages->writable) return -EPERM; + if (pages->type == IOPT_ADDRESS_FILE) + return iopt_pages_rw_slow(pages, start_index, last_index, + start_byte % PAGE_SIZE, data, length, + flags); + + if (IS_ENABLED(CONFIG_IOMMUFD_TEST) && + WARN_ON(pages->type != IOPT_ADDRESS_USER)) + return -EINVAL; + if (!(flags & IOMMUFD_ACCESS_RW_KTHREAD) && change_mm) { if (start_index == last_index) return iopt_pages_rw_page(pages, start_index, diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c index 540437be168a0d..a0de6d6d4e689c 100644 --- a/drivers/iommu/iommufd/selftest.c +++ b/drivers/iommu/iommufd/selftest.c @@ -126,12 +126,35 @@ struct mock_iommu_domain { struct xarray pfns; }; +static inline struct mock_iommu_domain * +to_mock_domain(struct iommu_domain *domain) +{ + return container_of(domain, struct mock_iommu_domain, domain); +} + struct mock_iommu_domain_nested { struct iommu_domain domain; + struct mock_viommu *mock_viommu; struct mock_iommu_domain *parent; u32 iotlb[MOCK_NESTED_DOMAIN_IOTLB_NUM]; }; +static inline struct mock_iommu_domain_nested * +to_mock_nested(struct iommu_domain *domain) +{ + return container_of(domain, struct mock_iommu_domain_nested, domain); +} + +struct mock_viommu { + struct iommufd_viommu core; + struct mock_iommu_domain *s2_parent; +}; + +static inline struct mock_viommu *to_mock_viommu(struct iommufd_viommu *viommu) +{ + return container_of(viommu, struct mock_viommu, core); +} + enum selftest_obj_type { TYPE_IDEV, }; @@ -140,8 +163,14 @@ struct mock_dev { struct device dev; unsigned long flags; int id; + u32 cache[MOCK_DEV_CACHE_NUM]; }; +static inline struct mock_dev *to_mock_dev(struct device *dev) +{ + return container_of(dev, struct mock_dev, dev); +} + struct selftest_obj { struct iommufd_object obj; enum selftest_obj_type type; @@ -155,10 +184,15 @@ struct selftest_obj { }; }; +static inline struct selftest_obj *to_selftest_obj(struct iommufd_object *obj) +{ + return container_of(obj, struct selftest_obj, obj); +} + static int mock_domain_nop_attach(struct iommu_domain *domain, struct device *dev) { - struct mock_dev *mdev = container_of(dev, struct mock_dev, dev); + struct mock_dev *mdev = to_mock_dev(dev); if (domain->dirty_ops && (mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY)) return -EINVAL; @@ -193,8 +227,7 @@ static void *mock_domain_hw_info(struct device *dev, u32 *length, u32 *type) static int mock_domain_set_dirty_tracking(struct iommu_domain *domain, bool enable) { - struct mock_iommu_domain *mock = - container_of(domain, struct mock_iommu_domain, domain); + struct mock_iommu_domain *mock = to_mock_domain(domain); unsigned long flags = mock->flags; if (enable && !domain->dirty_ops) @@ -243,8 +276,7 @@ static int mock_domain_read_and_clear_dirty(struct iommu_domain *domain, unsigned long flags, struct iommu_dirty_bitmap *dirty) { - struct mock_iommu_domain *mock = - container_of(domain, struct mock_iommu_domain, domain); + struct mock_iommu_domain *mock = to_mock_domain(domain); unsigned long end = iova + size; void *ent; @@ -281,7 +313,7 @@ static const struct iommu_dirty_ops dirty_ops = { static struct iommu_domain *mock_domain_alloc_paging(struct device *dev) { - struct mock_dev *mdev = container_of(dev, struct mock_dev, dev); + struct mock_dev *mdev = to_mock_dev(dev); struct mock_iommu_domain *mock; mock = kzalloc(sizeof(*mock), GFP_KERNEL); @@ -298,76 +330,81 @@ static struct iommu_domain *mock_domain_alloc_paging(struct device *dev) return &mock->domain; } -static struct iommu_domain * -__mock_domain_alloc_nested(struct mock_iommu_domain *mock_parent, - const struct iommu_hwpt_selftest *user_cfg) +static struct mock_iommu_domain_nested * +__mock_domain_alloc_nested(const struct iommu_user_data *user_data) { struct mock_iommu_domain_nested *mock_nested; - int i; + struct iommu_hwpt_selftest user_cfg; + int rc, i; + + if (user_data->type != IOMMU_HWPT_DATA_SELFTEST) + return ERR_PTR(-EOPNOTSUPP); + + rc = iommu_copy_struct_from_user(&user_cfg, user_data, + IOMMU_HWPT_DATA_SELFTEST, iotlb); + if (rc) + return ERR_PTR(rc); mock_nested = kzalloc(sizeof(*mock_nested), GFP_KERNEL); if (!mock_nested) return ERR_PTR(-ENOMEM); - mock_nested->parent = mock_parent; mock_nested->domain.ops = &domain_nested_ops; mock_nested->domain.type = IOMMU_DOMAIN_NESTED; for (i = 0; i < MOCK_NESTED_DOMAIN_IOTLB_NUM; i++) - mock_nested->iotlb[i] = user_cfg->iotlb; - return &mock_nested->domain; + mock_nested->iotlb[i] = user_cfg.iotlb; + return mock_nested; } static struct iommu_domain * -mock_domain_alloc_user(struct device *dev, u32 flags, - struct iommu_domain *parent, - const struct iommu_user_data *user_data) +mock_domain_alloc_nested(struct device *dev, struct iommu_domain *parent, + u32 flags, const struct iommu_user_data *user_data) { + struct mock_iommu_domain_nested *mock_nested; struct mock_iommu_domain *mock_parent; - struct iommu_hwpt_selftest user_cfg; - int rc; - /* must be mock_domain */ - if (!parent) { - struct mock_dev *mdev = container_of(dev, struct mock_dev, dev); - bool has_dirty_flag = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING; - bool no_dirty_ops = mdev->flags & MOCK_FLAGS_DEVICE_NO_DIRTY; - struct iommu_domain *domain; - - if (flags & (~(IOMMU_HWPT_ALLOC_NEST_PARENT | - IOMMU_HWPT_ALLOC_DIRTY_TRACKING))) - return ERR_PTR(-EOPNOTSUPP); - if (user_data || (has_dirty_flag && no_dirty_ops)) - return ERR_PTR(-EOPNOTSUPP); - domain = mock_domain_alloc_paging(dev); - if (!domain) - return ERR_PTR(-ENOMEM); - if (has_dirty_flag) - container_of(domain, struct mock_iommu_domain, domain) - ->domain.dirty_ops = &dirty_ops; - return domain; - } - - /* must be mock_domain_nested */ - if (user_data->type != IOMMU_HWPT_DATA_SELFTEST || flags) + if (flags) return ERR_PTR(-EOPNOTSUPP); if (!parent || parent->ops != mock_ops.default_domain_ops) return ERR_PTR(-EINVAL); - mock_parent = container_of(parent, struct mock_iommu_domain, domain); + mock_parent = to_mock_domain(parent); if (!mock_parent) return ERR_PTR(-EINVAL); - rc = iommu_copy_struct_from_user(&user_cfg, user_data, - IOMMU_HWPT_DATA_SELFTEST, iotlb); - if (rc) - return ERR_PTR(rc); + mock_nested = __mock_domain_alloc_nested(user_data); + if (IS_ERR(mock_nested)) + return ERR_CAST(mock_nested); + mock_nested->parent = mock_parent; + return &mock_nested->domain; +} - return __mock_domain_alloc_nested(mock_parent, &user_cfg); +static struct iommu_domain * +mock_domain_alloc_paging_flags(struct device *dev, u32 flags, + const struct iommu_user_data *user_data) +{ + bool has_dirty_flag = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING; + const u32 PAGING_FLAGS = IOMMU_HWPT_ALLOC_DIRTY_TRACKING | + IOMMU_HWPT_ALLOC_NEST_PARENT; + bool no_dirty_ops = to_mock_dev(dev)->flags & + MOCK_FLAGS_DEVICE_NO_DIRTY; + struct iommu_domain *domain; + + if (user_data) + return ERR_PTR(-EOPNOTSUPP); + if ((flags & ~PAGING_FLAGS) || (has_dirty_flag && no_dirty_ops)) + return ERR_PTR(-EOPNOTSUPP); + + domain = mock_domain_alloc_paging(dev); + if (!domain) + return ERR_PTR(-ENOMEM); + if (has_dirty_flag) + domain->dirty_ops = &dirty_ops; + return domain; } static void mock_domain_free(struct iommu_domain *domain) { - struct mock_iommu_domain *mock = - container_of(domain, struct mock_iommu_domain, domain); + struct mock_iommu_domain *mock = to_mock_domain(domain); WARN_ON(!xa_empty(&mock->pfns)); kfree(mock); @@ -378,8 +415,7 @@ static int mock_domain_map_pages(struct iommu_domain *domain, size_t pgsize, size_t pgcount, int prot, gfp_t gfp, size_t *mapped) { - struct mock_iommu_domain *mock = - container_of(domain, struct mock_iommu_domain, domain); + struct mock_iommu_domain *mock = to_mock_domain(domain); unsigned long flags = MOCK_PFN_START_IOVA; unsigned long start_iova = iova; @@ -430,8 +466,7 @@ static size_t mock_domain_unmap_pages(struct iommu_domain *domain, size_t pgcount, struct iommu_iotlb_gather *iotlb_gather) { - struct mock_iommu_domain *mock = - container_of(domain, struct mock_iommu_domain, domain); + struct mock_iommu_domain *mock = to_mock_domain(domain); bool first = true; size_t ret = 0; void *ent; @@ -479,8 +514,7 @@ static size_t mock_domain_unmap_pages(struct iommu_domain *domain, static phys_addr_t mock_domain_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) { - struct mock_iommu_domain *mock = - container_of(domain, struct mock_iommu_domain, domain); + struct mock_iommu_domain *mock = to_mock_domain(domain); void *ent; WARN_ON(iova % MOCK_IO_PAGE_SIZE); @@ -491,7 +525,7 @@ static phys_addr_t mock_domain_iova_to_phys(struct iommu_domain *domain, static bool mock_domain_capable(struct device *dev, enum iommu_cap cap) { - struct mock_dev *mdev = container_of(dev, struct mock_dev, dev); + struct mock_dev *mdev = to_mock_dev(dev); switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: @@ -507,14 +541,17 @@ static bool mock_domain_capable(struct device *dev, enum iommu_cap cap) static struct iopf_queue *mock_iommu_iopf_queue; -static struct iommu_device mock_iommu_device = { -}; +static struct mock_iommu_device { + struct iommu_device iommu_dev; + struct completion complete; + refcount_t users; +} mock_iommu; static struct iommu_device *mock_probe_device(struct device *dev) { if (dev->bus != &iommufd_mock_bus_type.bus) return ERR_PTR(-ENODEV); - return &mock_iommu_device; + return &mock_iommu.iommu_dev; } static void mock_domain_page_response(struct device *dev, struct iopf_fault *evt, @@ -540,6 +577,132 @@ static int mock_dev_disable_feat(struct device *dev, enum iommu_dev_features fea return 0; } +static void mock_viommu_destroy(struct iommufd_viommu *viommu) +{ + struct mock_iommu_device *mock_iommu = container_of( + viommu->iommu_dev, struct mock_iommu_device, iommu_dev); + + if (refcount_dec_and_test(&mock_iommu->users)) + complete(&mock_iommu->complete); + + /* iommufd core frees mock_viommu and viommu */ +} + +static struct iommu_domain * +mock_viommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags, + const struct iommu_user_data *user_data) +{ + struct mock_viommu *mock_viommu = to_mock_viommu(viommu); + struct mock_iommu_domain_nested *mock_nested; + + if (flags & ~IOMMU_HWPT_FAULT_ID_VALID) + return ERR_PTR(-EOPNOTSUPP); + + mock_nested = __mock_domain_alloc_nested(user_data); + if (IS_ERR(mock_nested)) + return ERR_CAST(mock_nested); + mock_nested->mock_viommu = mock_viommu; + mock_nested->parent = mock_viommu->s2_parent; + return &mock_nested->domain; +} + +static int mock_viommu_cache_invalidate(struct iommufd_viommu *viommu, + struct iommu_user_data_array *array) +{ + struct iommu_viommu_invalidate_selftest *cmds; + struct iommu_viommu_invalidate_selftest *cur; + struct iommu_viommu_invalidate_selftest *end; + int rc; + + /* A zero-length array is allowed to validate the array type */ + if (array->entry_num == 0 && + array->type == IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST) { + array->entry_num = 0; + return 0; + } + + cmds = kcalloc(array->entry_num, sizeof(*cmds), GFP_KERNEL); + if (!cmds) + return -ENOMEM; + cur = cmds; + end = cmds + array->entry_num; + + static_assert(sizeof(*cmds) == 3 * sizeof(u32)); + rc = iommu_copy_struct_from_full_user_array( + cmds, sizeof(*cmds), array, + IOMMU_VIOMMU_INVALIDATE_DATA_SELFTEST); + if (rc) + goto out; + + while (cur != end) { + struct mock_dev *mdev; + struct device *dev; + int i; + + if (cur->flags & ~IOMMU_TEST_INVALIDATE_FLAG_ALL) { + rc = -EOPNOTSUPP; + goto out; + } + + if (cur->cache_id > MOCK_DEV_CACHE_ID_MAX) { + rc = -EINVAL; + goto out; + } + + xa_lock(&viommu->vdevs); + dev = iommufd_viommu_find_dev(viommu, + (unsigned long)cur->vdev_id); + if (!dev) { + xa_unlock(&viommu->vdevs); + rc = -EINVAL; + goto out; + } + mdev = container_of(dev, struct mock_dev, dev); + + if (cur->flags & IOMMU_TEST_INVALIDATE_FLAG_ALL) { + /* Invalidate all cache entries and ignore cache_id */ + for (i = 0; i < MOCK_DEV_CACHE_NUM; i++) + mdev->cache[i] = 0; + } else { + mdev->cache[cur->cache_id] = 0; + } + xa_unlock(&viommu->vdevs); + + cur++; + } +out: + array->entry_num = cur - cmds; + kfree(cmds); + return rc; +} + +static struct iommufd_viommu_ops mock_viommu_ops = { + .destroy = mock_viommu_destroy, + .alloc_domain_nested = mock_viommu_alloc_domain_nested, + .cache_invalidate = mock_viommu_cache_invalidate, +}; + +static struct iommufd_viommu *mock_viommu_alloc(struct device *dev, + struct iommu_domain *domain, + struct iommufd_ctx *ictx, + unsigned int viommu_type) +{ + struct mock_iommu_device *mock_iommu = + iommu_get_iommu_dev(dev, struct mock_iommu_device, iommu_dev); + struct mock_viommu *mock_viommu; + + if (viommu_type != IOMMU_VIOMMU_TYPE_SELFTEST) + return ERR_PTR(-EOPNOTSUPP); + + mock_viommu = iommufd_viommu_alloc(ictx, struct mock_viommu, core, + &mock_viommu_ops); + if (IS_ERR(mock_viommu)) + return ERR_CAST(mock_viommu); + + refcount_inc(&mock_iommu->users); + return &mock_viommu->core; +} + static const struct iommu_ops mock_ops = { /* * IOMMU_DOMAIN_BLOCKED cannot be returned from def_domain_type() @@ -551,7 +714,8 @@ static const struct iommu_ops mock_ops = { .pgsize_bitmap = MOCK_IO_PAGE_SIZE, .hw_info = mock_domain_hw_info, .domain_alloc_paging = mock_domain_alloc_paging, - .domain_alloc_user = mock_domain_alloc_user, + .domain_alloc_paging_flags = mock_domain_alloc_paging_flags, + .domain_alloc_nested = mock_domain_alloc_nested, .capable = mock_domain_capable, .device_group = generic_device_group, .probe_device = mock_probe_device, @@ -559,6 +723,7 @@ static const struct iommu_ops mock_ops = { .dev_enable_feat = mock_dev_enable_feat, .dev_disable_feat = mock_dev_disable_feat, .user_pasid_table = true, + .viommu_alloc = mock_viommu_alloc, .default_domain_ops = &(struct iommu_domain_ops){ .free = mock_domain_free, @@ -571,18 +736,14 @@ static const struct iommu_ops mock_ops = { static void mock_domain_free_nested(struct iommu_domain *domain) { - struct mock_iommu_domain_nested *mock_nested = - container_of(domain, struct mock_iommu_domain_nested, domain); - - kfree(mock_nested); + kfree(to_mock_nested(domain)); } static int mock_domain_cache_invalidate_user(struct iommu_domain *domain, struct iommu_user_data_array *array) { - struct mock_iommu_domain_nested *mock_nested = - container_of(domain, struct mock_iommu_domain_nested, domain); + struct mock_iommu_domain_nested *mock_nested = to_mock_nested(domain); struct iommu_hwpt_invalidate_selftest inv; u32 processed = 0; int i = 0, j; @@ -657,7 +818,7 @@ get_md_pagetable(struct iommufd_ucmd *ucmd, u32 mockpt_id, iommufd_put_object(ucmd->ictx, &hwpt->obj); return ERR_PTR(-EINVAL); } - *mock = container_of(hwpt->domain, struct mock_iommu_domain, domain); + *mock = to_mock_domain(hwpt->domain); return hwpt; } @@ -675,14 +836,13 @@ get_md_pagetable_nested(struct iommufd_ucmd *ucmd, u32 mockpt_id, iommufd_put_object(ucmd->ictx, &hwpt->obj); return ERR_PTR(-EINVAL); } - *mock_nested = container_of(hwpt->domain, - struct mock_iommu_domain_nested, domain); + *mock_nested = to_mock_nested(hwpt->domain); return hwpt; } static void mock_dev_release(struct device *dev) { - struct mock_dev *mdev = container_of(dev, struct mock_dev, dev); + struct mock_dev *mdev = to_mock_dev(dev); ida_free(&mock_dev_ida, mdev->id); kfree(mdev); @@ -691,7 +851,7 @@ static void mock_dev_release(struct device *dev) static struct mock_dev *mock_dev_create(unsigned long dev_flags) { struct mock_dev *mdev; - int rc; + int rc, i; if (dev_flags & ~(MOCK_FLAGS_DEVICE_NO_DIRTY | MOCK_FLAGS_DEVICE_HUGE_IOVA)) @@ -705,6 +865,8 @@ static struct mock_dev *mock_dev_create(unsigned long dev_flags) mdev->flags = dev_flags; mdev->dev.release = mock_dev_release; mdev->dev.bus = &iommufd_mock_bus_type.bus; + for (i = 0; i < MOCK_DEV_CACHE_NUM; i++) + mdev->cache[i] = IOMMU_TEST_DEV_CACHE_DEFAULT; rc = ida_alloc(&mock_dev_ida, GFP_KERNEL); if (rc < 0) @@ -813,7 +975,7 @@ static int iommufd_test_mock_domain_replace(struct iommufd_ucmd *ucmd, if (IS_ERR(dev_obj)) return PTR_ERR(dev_obj); - sobj = container_of(dev_obj, struct selftest_obj, obj); + sobj = to_selftest_obj(dev_obj); if (sobj->type != TYPE_IDEV) { rc = -EINVAL; goto out_dev_obj; @@ -951,8 +1113,7 @@ static int iommufd_test_md_check_iotlb(struct iommufd_ucmd *ucmd, if (IS_ERR(hwpt)) return PTR_ERR(hwpt); - mock_nested = container_of(hwpt->domain, - struct mock_iommu_domain_nested, domain); + mock_nested = to_mock_nested(hwpt->domain); if (iotlb_id > MOCK_NESTED_DOMAIN_IOTLB_ID_MAX || mock_nested->iotlb[iotlb_id] != iotlb) @@ -961,6 +1122,24 @@ static int iommufd_test_md_check_iotlb(struct iommufd_ucmd *ucmd, return rc; } +static int iommufd_test_dev_check_cache(struct iommufd_ucmd *ucmd, u32 idev_id, + unsigned int cache_id, u32 cache) +{ + struct iommufd_device *idev; + struct mock_dev *mdev; + int rc = 0; + + idev = iommufd_get_device(ucmd, idev_id); + if (IS_ERR(idev)) + return PTR_ERR(idev); + mdev = container_of(idev->dev, struct mock_dev, dev); + + if (cache_id > MOCK_DEV_CACHE_ID_MAX || mdev->cache[cache_id] != cache) + rc = -EINVAL; + iommufd_put_object(ucmd->ictx, &idev->obj); + return rc; +} + struct selftest_access { struct iommufd_access *access; struct file *file; @@ -1431,7 +1610,7 @@ static int iommufd_test_trigger_iopf(struct iommufd_ucmd *ucmd, void iommufd_selftest_destroy(struct iommufd_object *obj) { - struct selftest_obj *sobj = container_of(obj, struct selftest_obj, obj); + struct selftest_obj *sobj = to_selftest_obj(obj); switch (sobj->type) { case TYPE_IDEV: @@ -1470,6 +1649,10 @@ int iommufd_test(struct iommufd_ucmd *ucmd) return iommufd_test_md_check_iotlb(ucmd, cmd->id, cmd->check_iotlb.id, cmd->check_iotlb.iotlb); + case IOMMU_TEST_OP_DEV_CHECK_CACHE: + return iommufd_test_dev_check_cache(ucmd, cmd->id, + cmd->check_dev_cache.id, + cmd->check_dev_cache.cache); case IOMMU_TEST_OP_CREATE_ACCESS: return iommufd_test_create_access(ucmd, cmd->id, cmd->create_access.flags); @@ -1536,24 +1719,27 @@ int __init iommufd_test_init(void) if (rc) goto err_platform; - rc = iommu_device_sysfs_add(&mock_iommu_device, + rc = iommu_device_sysfs_add(&mock_iommu.iommu_dev, &selftest_iommu_dev->dev, NULL, "%s", dev_name(&selftest_iommu_dev->dev)); if (rc) goto err_bus; - rc = iommu_device_register_bus(&mock_iommu_device, &mock_ops, + rc = iommu_device_register_bus(&mock_iommu.iommu_dev, &mock_ops, &iommufd_mock_bus_type.bus, &iommufd_mock_bus_type.nb); if (rc) goto err_sysfs; + refcount_set(&mock_iommu.users, 1); + init_completion(&mock_iommu.complete); + mock_iommu_iopf_queue = iopf_queue_alloc("mock-iopfq"); return 0; err_sysfs: - iommu_device_sysfs_remove(&mock_iommu_device); + iommu_device_sysfs_remove(&mock_iommu.iommu_dev); err_bus: bus_unregister(&iommufd_mock_bus_type.bus); err_platform: @@ -1563,6 +1749,22 @@ int __init iommufd_test_init(void) return rc; } +static void iommufd_test_wait_for_users(void) +{ + if (refcount_dec_and_test(&mock_iommu.users)) + return; + /* + * Time out waiting for iommu device user count to become 0. + * + * Note that this is just making an example here, since the selftest is + * built into the iommufd module, i.e. it only unplugs the iommu device + * when unloading the module. So, it is expected that this WARN_ON will + * not trigger, as long as any iommufd FDs are open. + */ + WARN_ON(!wait_for_completion_timeout(&mock_iommu.complete, + msecs_to_jiffies(10000))); +} + void iommufd_test_exit(void) { if (mock_iommu_iopf_queue) { @@ -1570,8 +1772,9 @@ void iommufd_test_exit(void) mock_iommu_iopf_queue = NULL; } - iommu_device_sysfs_remove(&mock_iommu_device); - iommu_device_unregister_bus(&mock_iommu_device, + iommufd_test_wait_for_users(); + iommu_device_sysfs_remove(&mock_iommu.iommu_dev); + iommu_device_unregister_bus(&mock_iommu.iommu_dev, &iommufd_mock_bus_type.bus, &iommufd_mock_bus_type.nb); bus_unregister(&iommufd_mock_bus_type.bus); diff --git a/drivers/iommu/iommufd/vfio_compat.c b/drivers/iommu/iommufd/vfio_compat.c index a3ad5f0b6c59dd..a258ee2f4579f5 100644 --- a/drivers/iommu/iommufd/vfio_compat.c +++ b/drivers/iommu/iommufd/vfio_compat.c @@ -44,7 +44,7 @@ int iommufd_vfio_compat_ioas_get_id(struct iommufd_ctx *ictx, u32 *out_ioas_id) iommufd_put_object(ictx, &ioas->obj); return 0; } -EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_ioas_get_id, IOMMUFD_VFIO); +EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_ioas_get_id, "IOMMUFD_VFIO"); /** * iommufd_vfio_compat_set_no_iommu - Called when a no-iommu device is attached @@ -66,7 +66,7 @@ int iommufd_vfio_compat_set_no_iommu(struct iommufd_ctx *ictx) xa_unlock(&ictx->objects); return ret; } -EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_set_no_iommu, IOMMUFD_VFIO); +EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_set_no_iommu, "IOMMUFD_VFIO"); /** * iommufd_vfio_compat_ioas_create - Ensure the compat IOAS is created @@ -118,7 +118,7 @@ int iommufd_vfio_compat_ioas_create(struct iommufd_ctx *ictx) iommufd_object_abort(ictx, &ioas->obj); return ret; } -EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_ioas_create, IOMMUFD_VFIO); +EXPORT_SYMBOL_NS_GPL(iommufd_vfio_compat_ioas_create, "IOMMUFD_VFIO"); int iommufd_vfio_ioas(struct iommufd_ucmd *ucmd) { @@ -291,12 +291,7 @@ static int iommufd_vfio_check_extension(struct iommufd_ctx *ictx, case VFIO_DMA_CC_IOMMU: return iommufd_vfio_cc_iommu(ictx); - /* - * This is obsolete, and to be removed from VFIO. It was an incomplete - * idea that got merged. - * https://lore.kernel.org/kvm/0-v1-0093c9b0e345+19-vfio_no_nesting_jgg@nvidia.com/ - */ - case VFIO_TYPE1_NESTING_IOMMU: + case __VFIO_RESERVED_TYPE1_NESTING_IOMMU: return 0; /* diff --git a/drivers/iommu/iommufd/viommu.c b/drivers/iommu/iommufd/viommu.c new file mode 100644 index 00000000000000..69b88e8c7c2656 --- /dev/null +++ b/drivers/iommu/iommufd/viommu.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES + */ +#include "iommufd_private.h" + +void iommufd_viommu_destroy(struct iommufd_object *obj) +{ + struct iommufd_viommu *viommu = + container_of(obj, struct iommufd_viommu, obj); + + if (viommu->ops && viommu->ops->destroy) + viommu->ops->destroy(viommu); + refcount_dec(&viommu->hwpt->common.obj.users); + xa_destroy(&viommu->vdevs); +} + +int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd) +{ + struct iommu_viommu_alloc *cmd = ucmd->cmd; + struct iommufd_hwpt_paging *hwpt_paging; + struct iommufd_viommu *viommu; + struct iommufd_device *idev; + const struct iommu_ops *ops; + int rc; + + if (cmd->flags || cmd->type == IOMMU_VIOMMU_TYPE_DEFAULT) + return -EOPNOTSUPP; + + idev = iommufd_get_device(ucmd, cmd->dev_id); + if (IS_ERR(idev)) + return PTR_ERR(idev); + + ops = dev_iommu_ops(idev->dev); + if (!ops->viommu_alloc) { + rc = -EOPNOTSUPP; + goto out_put_idev; + } + + hwpt_paging = iommufd_get_hwpt_paging(ucmd, cmd->hwpt_id); + if (IS_ERR(hwpt_paging)) { + rc = PTR_ERR(hwpt_paging); + goto out_put_idev; + } + + if (!hwpt_paging->nest_parent) { + rc = -EINVAL; + goto out_put_hwpt; + } + + viommu = ops->viommu_alloc(idev->dev, hwpt_paging->common.domain, + ucmd->ictx, cmd->type); + if (IS_ERR(viommu)) { + rc = PTR_ERR(viommu); + goto out_put_hwpt; + } + + xa_init(&viommu->vdevs); + viommu->type = cmd->type; + viommu->ictx = ucmd->ictx; + viommu->hwpt = hwpt_paging; + refcount_inc(&viommu->hwpt->common.obj.users); + /* + * It is the most likely case that a physical IOMMU is unpluggable. A + * pluggable IOMMU instance (if exists) is responsible for refcounting + * on its own. + */ + viommu->iommu_dev = __iommu_get_iommu_dev(idev->dev); + + cmd->out_viommu_id = viommu->obj.id; + rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); + if (rc) + goto out_abort; + iommufd_object_finalize(ucmd->ictx, &viommu->obj); + goto out_put_hwpt; + +out_abort: + iommufd_object_abort_and_destroy(ucmd->ictx, &viommu->obj); +out_put_hwpt: + iommufd_put_object(ucmd->ictx, &hwpt_paging->common.obj); +out_put_idev: + iommufd_put_object(ucmd->ictx, &idev->obj); + return rc; +} + +void iommufd_vdevice_destroy(struct iommufd_object *obj) +{ + struct iommufd_vdevice *vdev = + container_of(obj, struct iommufd_vdevice, obj); + struct iommufd_viommu *viommu = vdev->viommu; + + /* xa_cmpxchg is okay to fail if alloc failed xa_cmpxchg previously */ + xa_cmpxchg(&viommu->vdevs, vdev->id, vdev, NULL, GFP_KERNEL); + refcount_dec(&viommu->obj.users); + put_device(vdev->dev); +} + +int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd) +{ + struct iommu_vdevice_alloc *cmd = ucmd->cmd; + struct iommufd_vdevice *vdev, *curr; + struct iommufd_viommu *viommu; + struct iommufd_device *idev; + u64 virt_id = cmd->virt_id; + int rc = 0; + + /* virt_id indexes an xarray */ + if (virt_id > ULONG_MAX) + return -EINVAL; + + viommu = iommufd_get_viommu(ucmd, cmd->viommu_id); + if (IS_ERR(viommu)) + return PTR_ERR(viommu); + + idev = iommufd_get_device(ucmd, cmd->dev_id); + if (IS_ERR(idev)) { + rc = PTR_ERR(idev); + goto out_put_viommu; + } + + if (viommu->iommu_dev != __iommu_get_iommu_dev(idev->dev)) { + rc = -EINVAL; + goto out_put_idev; + } + + vdev = iommufd_object_alloc(ucmd->ictx, vdev, IOMMUFD_OBJ_VDEVICE); + if (IS_ERR(vdev)) { + rc = PTR_ERR(vdev); + goto out_put_idev; + } + + vdev->id = virt_id; + vdev->dev = idev->dev; + get_device(idev->dev); + vdev->viommu = viommu; + refcount_inc(&viommu->obj.users); + + curr = xa_cmpxchg(&viommu->vdevs, virt_id, NULL, vdev, GFP_KERNEL); + if (curr) { + rc = xa_err(curr) ?: -EEXIST; + goto out_abort; + } + + cmd->out_vdevice_id = vdev->obj.id; + rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd)); + if (rc) + goto out_abort; + iommufd_object_finalize(ucmd->ictx, &vdev->obj); + goto out_put_idev; + +out_abort: + iommufd_object_abort_and_destroy(ucmd->ictx, &vdev->obj); +out_put_idev: + iommufd_put_object(ucmd->ictx, &idev->obj); +out_put_viommu: + iommufd_put_object(ucmd->ictx, &viommu->obj); + return rc; +} diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 16c6adff3eb7bf..18f83972181362 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -506,7 +507,7 @@ __adjust_overlap_range(struct iova *iova, * reserve_iova - reserves an iova in the given range * @iovad: - iova domain pointer * @pfn_lo: - lower page frame address - * @pfn_hi:- higher pfn adderss + * @pfn_hi:- higher pfn address * This function allocates reserves the address range from pfn_lo to pfn_hi so * that this address is not dished out as part of alloc_iova. */ @@ -673,6 +674,11 @@ static struct iova_magazine *iova_depot_pop(struct iova_rcache *rcache) { struct iova_magazine *mag = rcache->depot; + /* + * As the mag->next pointer is moved to rcache->depot and reset via + * the mag->size assignment, mark it as a transient false positive. + */ + kmemleak_transient_leak(mag->next); rcache->depot = mag->next; mag->size = IOVA_MAG_SIZE; rcache->depot_size--; diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index ff55b8c3071269..074daf1aac4e4c 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -1159,6 +1159,6 @@ static struct platform_driver ipmmu_driver = { .pm = pm_sleep_ptr(&ipmmu_pm), }, .probe = ipmmu_probe, - .remove_new = ipmmu_remove, + .remove = ipmmu_remove, }; builtin_platform_driver(ipmmu_driver); diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 989e0869d80554..ce40f0a419ea09 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -838,6 +838,6 @@ static struct platform_driver msm_iommu_driver = { .of_match_table = msm_iommu_dt_match, }, .probe = msm_iommu_probe, - .remove_new = msm_iommu_remove, + .remove = msm_iommu_remove, }; builtin_platform_driver(msm_iommu_driver); diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 6a2707fe7a78c0..ab60901f8f9288 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -1599,7 +1599,7 @@ static const unsigned int mt8186_larb_region_msk[MT8192_MULTI_REGION_NR_MAX][MTK 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 | - WR_THROT_EN | IOVA_34_EN | MTK_IOMMU_TYPE_MM, + WR_THROT_EN | IOVA_34_EN | MTK_IOMMU_TYPE_MM | PGTABLE_PA_35_EN, .larbid_remap = {{0}, {1, MTK_INVALID_LARBID, 8}, {4}, {7}, {2}, {9, 11, 19, 20}, {MTK_INVALID_LARBID, 14, 16}, {MTK_INVALID_LARBID, 13, MTK_INVALID_LARBID, 17}}, @@ -1794,7 +1794,7 @@ MODULE_DEVICE_TABLE(of, mtk_iommu_of_ids); static struct platform_driver mtk_iommu_driver = { .probe = mtk_iommu_probe, - .remove_new = mtk_iommu_remove, + .remove = 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 ee4e55b6b19003..b6de1ca00cefa3 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -745,7 +745,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_new = mtk_iommu_v1_remove, + .remove = 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 c9528065a59afa..3c62337f43c677 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1230,25 +1230,24 @@ static int omap_iommu_probe(struct platform_device *pdev) if (err) return err; - err = iommu_device_register(&obj->iommu, &omap_iommu_ops, &pdev->dev); - if (err) - goto out_sysfs; obj->has_iommu_driver = true; } + err = iommu_device_register(&obj->iommu, &omap_iommu_ops, &pdev->dev); + if (err) + goto out_sysfs; + pm_runtime_enable(obj->dev); omap_iommu_debugfs_add(obj); dev_info(&pdev->dev, "%s registered\n", obj->name); - /* Re-probe bus to probe device attached to this IOMMU */ - bus_iommu_probe(&platform_bus_type); - return 0; out_sysfs: - iommu_device_sysfs_remove(&obj->iommu); + if (obj->has_iommu_driver) + iommu_device_sysfs_remove(&obj->iommu); return err; } @@ -1256,10 +1255,10 @@ static void omap_iommu_remove(struct platform_device *pdev) { struct omap_iommu *obj = platform_get_drvdata(pdev); - if (obj->has_iommu_driver) { + if (obj->has_iommu_driver) iommu_device_sysfs_remove(&obj->iommu); - iommu_device_unregister(&obj->iommu); - } + + iommu_device_unregister(&obj->iommu); omap_iommu_debugfs_remove(obj); @@ -1286,7 +1285,7 @@ static const struct of_device_id omap_iommu_of_match[] = { static struct platform_driver omap_iommu_driver = { .probe = omap_iommu_probe, - .remove_new = omap_iommu_remove, + .remove = omap_iommu_remove, .driver = { .name = "omap-iommu", .pm = &omap_iommu_pm_ops, @@ -1723,12 +1722,19 @@ static void omap_iommu_release_device(struct device *dev) } +static int omap_iommu_of_xlate(struct device *dev, const struct of_phandle_args *args) +{ + /* TODO: collect args->np to save re-parsing in probe above */ + return 0; +} + static const struct iommu_ops omap_iommu_ops = { .identity_domain = &omap_iommu_identity_domain, .domain_alloc_paging = omap_iommu_domain_alloc_paging, .probe_device = omap_iommu_probe_device, .release_device = omap_iommu_release_device, .device_group = generic_single_device_group, + .of_xlate = omap_iommu_of_xlate, .pgsize_bitmap = OMAP_IOMMU_PGSIZES, .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = omap_iommu_attach_dev, diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig new file mode 100644 index 00000000000000..c071816f59a67b --- /dev/null +++ b/drivers/iommu/riscv/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +# RISC-V IOMMU support + +config RISCV_IOMMU + bool "RISC-V IOMMU Support" + depends on RISCV && 64BIT + default y + select IOMMU_API + help + Support for implementations of the RISC-V IOMMU architecture that + complements the RISC-V MMU capabilities, providing similar address + translation and protection functions for accesses from I/O devices. + + Say Y here if your SoC includes an IOMMU device implementing + the RISC-V IOMMU architecture. + +config RISCV_IOMMU_PCI + def_bool y if RISCV_IOMMU && PCI_MSI + help + Support for the PCIe implementation of RISC-V IOMMU architecture. diff --git a/drivers/iommu/riscv/Makefile b/drivers/iommu/riscv/Makefile new file mode 100644 index 00000000000000..f54c9ed17d41d9 --- /dev/null +++ b/drivers/iommu/riscv/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_RISCV_IOMMU) += iommu.o iommu-platform.o +obj-$(CONFIG_RISCV_IOMMU_PCI) += iommu-pci.o diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h new file mode 100644 index 00000000000000..98daf0e1a30690 --- /dev/null +++ b/drivers/iommu/riscv/iommu-bits.h @@ -0,0 +1,784 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright © 2022-2024 Rivos Inc. + * Copyright © 2023 FORTH-ICS/CARV + * Copyright © 2023 RISC-V IOMMU Task Group + * + * RISC-V IOMMU - Register Layout and Data Structures. + * + * Based on the 'RISC-V IOMMU Architecture Specification', Version 1.0 + * Published at https://github.com/riscv-non-isa/riscv-iommu + * + */ + +#ifndef _RISCV_IOMMU_BITS_H_ +#define _RISCV_IOMMU_BITS_H_ + +#include +#include +#include + +/* + * Chapter 5: Memory Mapped register interface + */ + +/* Common field positions */ +#define RISCV_IOMMU_PPN_FIELD GENMASK_ULL(53, 10) +#define RISCV_IOMMU_QUEUE_LOG2SZ_FIELD GENMASK_ULL(4, 0) +#define RISCV_IOMMU_QUEUE_INDEX_FIELD GENMASK_ULL(31, 0) +#define RISCV_IOMMU_QUEUE_ENABLE BIT(0) +#define RISCV_IOMMU_QUEUE_INTR_ENABLE BIT(1) +#define RISCV_IOMMU_QUEUE_MEM_FAULT BIT(8) +#define RISCV_IOMMU_QUEUE_OVERFLOW BIT(9) +#define RISCV_IOMMU_QUEUE_ACTIVE BIT(16) +#define RISCV_IOMMU_QUEUE_BUSY BIT(17) + +#define RISCV_IOMMU_ATP_PPN_FIELD GENMASK_ULL(43, 0) +#define RISCV_IOMMU_ATP_MODE_FIELD GENMASK_ULL(63, 60) + +/* 5.3 IOMMU Capabilities (64bits) */ +#define RISCV_IOMMU_REG_CAPABILITIES 0x0000 +#define RISCV_IOMMU_CAPABILITIES_VERSION GENMASK_ULL(7, 0) +#define RISCV_IOMMU_CAPABILITIES_SV32 BIT_ULL(8) +#define RISCV_IOMMU_CAPABILITIES_SV39 BIT_ULL(9) +#define RISCV_IOMMU_CAPABILITIES_SV48 BIT_ULL(10) +#define RISCV_IOMMU_CAPABILITIES_SV57 BIT_ULL(11) +#define RISCV_IOMMU_CAPABILITIES_SVPBMT BIT_ULL(15) +#define RISCV_IOMMU_CAPABILITIES_SV32X4 BIT_ULL(16) +#define RISCV_IOMMU_CAPABILITIES_SV39X4 BIT_ULL(17) +#define RISCV_IOMMU_CAPABILITIES_SV48X4 BIT_ULL(18) +#define RISCV_IOMMU_CAPABILITIES_SV57X4 BIT_ULL(19) +#define RISCV_IOMMU_CAPABILITIES_AMO_MRIF BIT_ULL(21) +#define RISCV_IOMMU_CAPABILITIES_MSI_FLAT BIT_ULL(22) +#define RISCV_IOMMU_CAPABILITIES_MSI_MRIF BIT_ULL(23) +#define RISCV_IOMMU_CAPABILITIES_AMO_HWAD BIT_ULL(24) +#define RISCV_IOMMU_CAPABILITIES_ATS BIT_ULL(25) +#define RISCV_IOMMU_CAPABILITIES_T2GPA BIT_ULL(26) +#define RISCV_IOMMU_CAPABILITIES_END BIT_ULL(27) +#define RISCV_IOMMU_CAPABILITIES_IGS GENMASK_ULL(29, 28) +#define RISCV_IOMMU_CAPABILITIES_HPM BIT_ULL(30) +#define RISCV_IOMMU_CAPABILITIES_DBG BIT_ULL(31) +#define RISCV_IOMMU_CAPABILITIES_PAS GENMASK_ULL(37, 32) +#define RISCV_IOMMU_CAPABILITIES_PD8 BIT_ULL(38) +#define RISCV_IOMMU_CAPABILITIES_PD17 BIT_ULL(39) +#define RISCV_IOMMU_CAPABILITIES_PD20 BIT_ULL(40) + +/** + * enum riscv_iommu_igs_settings - Interrupt Generation Support Settings + * @RISCV_IOMMU_CAPABILITIES_IGS_MSI: IOMMU supports only MSI generation + * @RISCV_IOMMU_CAPABILITIES_IGS_WSI: IOMMU supports only Wired-Signaled interrupt + * @RISCV_IOMMU_CAPABILITIES_IGS_BOTH: IOMMU supports both MSI and WSI generation + * @RISCV_IOMMU_CAPABILITIES_IGS_RSRV: Reserved for standard use + */ +enum riscv_iommu_igs_settings { + RISCV_IOMMU_CAPABILITIES_IGS_MSI = 0, + RISCV_IOMMU_CAPABILITIES_IGS_WSI = 1, + RISCV_IOMMU_CAPABILITIES_IGS_BOTH = 2, + RISCV_IOMMU_CAPABILITIES_IGS_RSRV = 3 +}; + +/* 5.4 Features control register (32bits) */ +#define RISCV_IOMMU_REG_FCTL 0x0008 +#define RISCV_IOMMU_FCTL_BE BIT(0) +#define RISCV_IOMMU_FCTL_WSI BIT(1) +#define RISCV_IOMMU_FCTL_GXL BIT(2) + +/* 5.5 Device-directory-table pointer (64bits) */ +#define RISCV_IOMMU_REG_DDTP 0x0010 +#define RISCV_IOMMU_DDTP_IOMMU_MODE GENMASK_ULL(3, 0) +#define RISCV_IOMMU_DDTP_BUSY BIT_ULL(4) +#define RISCV_IOMMU_DDTP_PPN RISCV_IOMMU_PPN_FIELD + +/** + * enum riscv_iommu_ddtp_modes - IOMMU translation modes + * @RISCV_IOMMU_DDTP_IOMMU_MODE_OFF: No inbound transactions allowed + * @RISCV_IOMMU_DDTP_IOMMU_MODE_BARE: Pass-through mode + * @RISCV_IOMMU_DDTP_IOMMU_MODE_1LVL: One-level DDT + * @RISCV_IOMMU_DDTP_IOMMU_MODE_2LVL: Two-level DDT + * @RISCV_IOMMU_DDTP_IOMMU_MODE_3LVL: Three-level DDT + * @RISCV_IOMMU_DDTP_IOMMU_MODE_MAX: Max value allowed by specification + */ +enum riscv_iommu_ddtp_modes { + RISCV_IOMMU_DDTP_IOMMU_MODE_OFF = 0, + RISCV_IOMMU_DDTP_IOMMU_MODE_BARE = 1, + RISCV_IOMMU_DDTP_IOMMU_MODE_1LVL = 2, + RISCV_IOMMU_DDTP_IOMMU_MODE_2LVL = 3, + RISCV_IOMMU_DDTP_IOMMU_MODE_3LVL = 4, + RISCV_IOMMU_DDTP_IOMMU_MODE_MAX = 4 +}; + +/* 5.6 Command Queue Base (64bits) */ +#define RISCV_IOMMU_REG_CQB 0x0018 +#define RISCV_IOMMU_CQB_ENTRIES RISCV_IOMMU_QUEUE_LOG2SZ_FIELD +#define RISCV_IOMMU_CQB_PPN RISCV_IOMMU_PPN_FIELD + +/* 5.7 Command Queue head (32bits) */ +#define RISCV_IOMMU_REG_CQH 0x0020 +#define RISCV_IOMMU_CQH_INDEX RISCV_IOMMU_QUEUE_INDEX_FIELD + +/* 5.8 Command Queue tail (32bits) */ +#define RISCV_IOMMU_REG_CQT 0x0024 +#define RISCV_IOMMU_CQT_INDEX RISCV_IOMMU_QUEUE_INDEX_FIELD + +/* 5.9 Fault Queue Base (64bits) */ +#define RISCV_IOMMU_REG_FQB 0x0028 +#define RISCV_IOMMU_FQB_ENTRIES RISCV_IOMMU_QUEUE_LOG2SZ_FIELD +#define RISCV_IOMMU_FQB_PPN RISCV_IOMMU_PPN_FIELD + +/* 5.10 Fault Queue Head (32bits) */ +#define RISCV_IOMMU_REG_FQH 0x0030 +#define RISCV_IOMMU_FQH_INDEX RISCV_IOMMU_QUEUE_INDEX_FIELD + +/* 5.11 Fault Queue tail (32bits) */ +#define RISCV_IOMMU_REG_FQT 0x0034 +#define RISCV_IOMMU_FQT_INDEX RISCV_IOMMU_QUEUE_INDEX_FIELD + +/* 5.12 Page Request Queue base (64bits) */ +#define RISCV_IOMMU_REG_PQB 0x0038 +#define RISCV_IOMMU_PQB_ENTRIES RISCV_IOMMU_QUEUE_LOG2SZ_FIELD +#define RISCV_IOMMU_PQB_PPN RISCV_IOMMU_PPN_FIELD + +/* 5.13 Page Request Queue head (32bits) */ +#define RISCV_IOMMU_REG_PQH 0x0040 +#define RISCV_IOMMU_PQH_INDEX RISCV_IOMMU_QUEUE_INDEX_FIELD + +/* 5.14 Page Request Queue tail (32bits) */ +#define RISCV_IOMMU_REG_PQT 0x0044 +#define RISCV_IOMMU_PQT_INDEX_MASK RISCV_IOMMU_QUEUE_INDEX_FIELD + +/* 5.15 Command Queue CSR (32bits) */ +#define RISCV_IOMMU_REG_CQCSR 0x0048 +#define RISCV_IOMMU_CQCSR_CQEN RISCV_IOMMU_QUEUE_ENABLE +#define RISCV_IOMMU_CQCSR_CIE RISCV_IOMMU_QUEUE_INTR_ENABLE +#define RISCV_IOMMU_CQCSR_CQMF RISCV_IOMMU_QUEUE_MEM_FAULT +#define RISCV_IOMMU_CQCSR_CMD_TO BIT(9) +#define RISCV_IOMMU_CQCSR_CMD_ILL BIT(10) +#define RISCV_IOMMU_CQCSR_FENCE_W_IP BIT(11) +#define RISCV_IOMMU_CQCSR_CQON RISCV_IOMMU_QUEUE_ACTIVE +#define RISCV_IOMMU_CQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY + +/* 5.16 Fault Queue CSR (32bits) */ +#define RISCV_IOMMU_REG_FQCSR 0x004C +#define RISCV_IOMMU_FQCSR_FQEN RISCV_IOMMU_QUEUE_ENABLE +#define RISCV_IOMMU_FQCSR_FIE RISCV_IOMMU_QUEUE_INTR_ENABLE +#define RISCV_IOMMU_FQCSR_FQMF RISCV_IOMMU_QUEUE_MEM_FAULT +#define RISCV_IOMMU_FQCSR_FQOF RISCV_IOMMU_QUEUE_OVERFLOW +#define RISCV_IOMMU_FQCSR_FQON RISCV_IOMMU_QUEUE_ACTIVE +#define RISCV_IOMMU_FQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY + +/* 5.17 Page Request Queue CSR (32bits) */ +#define RISCV_IOMMU_REG_PQCSR 0x0050 +#define RISCV_IOMMU_PQCSR_PQEN RISCV_IOMMU_QUEUE_ENABLE +#define RISCV_IOMMU_PQCSR_PIE RISCV_IOMMU_QUEUE_INTR_ENABLE +#define RISCV_IOMMU_PQCSR_PQMF RISCV_IOMMU_QUEUE_MEM_FAULT +#define RISCV_IOMMU_PQCSR_PQOF RISCV_IOMMU_QUEUE_OVERFLOW +#define RISCV_IOMMU_PQCSR_PQON RISCV_IOMMU_QUEUE_ACTIVE +#define RISCV_IOMMU_PQCSR_BUSY RISCV_IOMMU_QUEUE_BUSY + +/* 5.18 Interrupt Pending Status (32bits) */ +#define RISCV_IOMMU_REG_IPSR 0x0054 + +#define RISCV_IOMMU_INTR_CQ 0 +#define RISCV_IOMMU_INTR_FQ 1 +#define RISCV_IOMMU_INTR_PM 2 +#define RISCV_IOMMU_INTR_PQ 3 +#define RISCV_IOMMU_INTR_COUNT 4 + +#define RISCV_IOMMU_IPSR_CIP BIT(RISCV_IOMMU_INTR_CQ) +#define RISCV_IOMMU_IPSR_FIP BIT(RISCV_IOMMU_INTR_FQ) +#define RISCV_IOMMU_IPSR_PMIP BIT(RISCV_IOMMU_INTR_PM) +#define RISCV_IOMMU_IPSR_PIP BIT(RISCV_IOMMU_INTR_PQ) + +/* 5.19 Performance monitoring counter overflow status (32bits) */ +#define RISCV_IOMMU_REG_IOCOUNTOVF 0x0058 +#define RISCV_IOMMU_IOCOUNTOVF_CY BIT(0) +#define RISCV_IOMMU_IOCOUNTOVF_HPM GENMASK_ULL(31, 1) + +/* 5.20 Performance monitoring counter inhibits (32bits) */ +#define RISCV_IOMMU_REG_IOCOUNTINH 0x005C +#define RISCV_IOMMU_IOCOUNTINH_CY BIT(0) +#define RISCV_IOMMU_IOCOUNTINH_HPM GENMASK(31, 1) + +/* 5.21 Performance monitoring cycles counter (64bits) */ +#define RISCV_IOMMU_REG_IOHPMCYCLES 0x0060 +#define RISCV_IOMMU_IOHPMCYCLES_COUNTER GENMASK_ULL(62, 0) +#define RISCV_IOMMU_IOHPMCYCLES_OF BIT_ULL(63) + +/* 5.22 Performance monitoring event counters (31 * 64bits) */ +#define RISCV_IOMMU_REG_IOHPMCTR_BASE 0x0068 +#define RISCV_IOMMU_REG_IOHPMCTR(_n) (RISCV_IOMMU_REG_IOHPMCTR_BASE + ((_n) * 0x8)) + +/* 5.23 Performance monitoring event selectors (31 * 64bits) */ +#define RISCV_IOMMU_REG_IOHPMEVT_BASE 0x0160 +#define RISCV_IOMMU_REG_IOHPMEVT(_n) (RISCV_IOMMU_REG_IOHPMEVT_BASE + ((_n) * 0x8)) +#define RISCV_IOMMU_IOHPMEVT_EVENTID GENMASK_ULL(14, 0) +#define RISCV_IOMMU_IOHPMEVT_DMASK BIT_ULL(15) +#define RISCV_IOMMU_IOHPMEVT_PID_PSCID GENMASK_ULL(35, 16) +#define RISCV_IOMMU_IOHPMEVT_DID_GSCID GENMASK_ULL(59, 36) +#define RISCV_IOMMU_IOHPMEVT_PV_PSCV BIT_ULL(60) +#define RISCV_IOMMU_IOHPMEVT_DV_GSCV BIT_ULL(61) +#define RISCV_IOMMU_IOHPMEVT_IDT BIT_ULL(62) +#define RISCV_IOMMU_IOHPMEVT_OF BIT_ULL(63) + +/* Number of defined performance-monitoring event selectors */ +#define RISCV_IOMMU_IOHPMEVT_CNT 31 + +/** + * enum riscv_iommu_hpmevent_id - Performance-monitoring event identifier + * + * @RISCV_IOMMU_HPMEVENT_INVALID: Invalid event, do not count + * @RISCV_IOMMU_HPMEVENT_URQ: Untranslated requests + * @RISCV_IOMMU_HPMEVENT_TRQ: Translated requests + * @RISCV_IOMMU_HPMEVENT_ATS_RQ: ATS translation requests + * @RISCV_IOMMU_HPMEVENT_TLB_MISS: TLB misses + * @RISCV_IOMMU_HPMEVENT_DD_WALK: Device directory walks + * @RISCV_IOMMU_HPMEVENT_PD_WALK: Process directory walks + * @RISCV_IOMMU_HPMEVENT_S_VS_WALKS: First-stage page table walks + * @RISCV_IOMMU_HPMEVENT_G_WALKS: Second-stage page table walks + * @RISCV_IOMMU_HPMEVENT_MAX: Value to denote maximum Event IDs + */ +enum riscv_iommu_hpmevent_id { + RISCV_IOMMU_HPMEVENT_INVALID = 0, + RISCV_IOMMU_HPMEVENT_URQ = 1, + RISCV_IOMMU_HPMEVENT_TRQ = 2, + RISCV_IOMMU_HPMEVENT_ATS_RQ = 3, + RISCV_IOMMU_HPMEVENT_TLB_MISS = 4, + RISCV_IOMMU_HPMEVENT_DD_WALK = 5, + RISCV_IOMMU_HPMEVENT_PD_WALK = 6, + RISCV_IOMMU_HPMEVENT_S_VS_WALKS = 7, + RISCV_IOMMU_HPMEVENT_G_WALKS = 8, + RISCV_IOMMU_HPMEVENT_MAX = 9 +}; + +/* 5.24 Translation request IOVA (64bits) */ +#define RISCV_IOMMU_REG_TR_REQ_IOVA 0x0258 +#define RISCV_IOMMU_TR_REQ_IOVA_VPN GENMASK_ULL(63, 12) + +/* 5.25 Translation request control (64bits) */ +#define RISCV_IOMMU_REG_TR_REQ_CTL 0x0260 +#define RISCV_IOMMU_TR_REQ_CTL_GO_BUSY BIT_ULL(0) +#define RISCV_IOMMU_TR_REQ_CTL_PRIV BIT_ULL(1) +#define RISCV_IOMMU_TR_REQ_CTL_EXE BIT_ULL(2) +#define RISCV_IOMMU_TR_REQ_CTL_NW BIT_ULL(3) +#define RISCV_IOMMU_TR_REQ_CTL_PID GENMASK_ULL(31, 12) +#define RISCV_IOMMU_TR_REQ_CTL_PV BIT_ULL(32) +#define RISCV_IOMMU_TR_REQ_CTL_DID GENMASK_ULL(63, 40) + +/* 5.26 Translation request response (64bits) */ +#define RISCV_IOMMU_REG_TR_RESPONSE 0x0268 +#define RISCV_IOMMU_TR_RESPONSE_FAULT BIT_ULL(0) +#define RISCV_IOMMU_TR_RESPONSE_PBMT GENMASK_ULL(8, 7) +#define RISCV_IOMMU_TR_RESPONSE_SZ BIT_ULL(9) +#define RISCV_IOMMU_TR_RESPONSE_PPN RISCV_IOMMU_PPN_FIELD + +/* 5.27 Interrupt cause to vector (64bits) */ +#define RISCV_IOMMU_REG_ICVEC 0x02F8 +#define RISCV_IOMMU_ICVEC_CIV GENMASK_ULL(3, 0) +#define RISCV_IOMMU_ICVEC_FIV GENMASK_ULL(7, 4) +#define RISCV_IOMMU_ICVEC_PMIV GENMASK_ULL(11, 8) +#define RISCV_IOMMU_ICVEC_PIV GENMASK_ULL(15, 12) + +/* 5.28 MSI Configuration table (32 * 64bits) */ +#define RISCV_IOMMU_REG_MSI_CFG_TBL 0x0300 +#define RISCV_IOMMU_REG_MSI_CFG_TBL_ADDR(_n) \ + (RISCV_IOMMU_REG_MSI_CFG_TBL + ((_n) * 0x10)) +#define RISCV_IOMMU_MSI_CFG_TBL_ADDR GENMASK_ULL(55, 2) +#define RISCV_IOMMU_REG_MSI_CFG_TBL_DATA(_n) \ + (RISCV_IOMMU_REG_MSI_CFG_TBL + ((_n) * 0x10) + 0x08) +#define RISCV_IOMMU_MSI_CFG_TBL_DATA GENMASK_ULL(31, 0) +#define RISCV_IOMMU_REG_MSI_CFG_TBL_CTRL(_n) \ + (RISCV_IOMMU_REG_MSI_CFG_TBL + ((_n) * 0x10) + 0x0C) +#define RISCV_IOMMU_MSI_CFG_TBL_CTRL_M BIT_ULL(0) + +#define RISCV_IOMMU_REG_SIZE 0x1000 + +/* + * Chapter 2: Data structures + */ + +/* + * Device Directory Table macros for non-leaf nodes + */ +#define RISCV_IOMMU_DDTE_V BIT_ULL(0) +#define RISCV_IOMMU_DDTE_PPN RISCV_IOMMU_PPN_FIELD + +/** + * struct riscv_iommu_dc - Device Context + * @tc: Translation Control + * @iohgatp: I/O Hypervisor guest address translation and protection + * (Second stage context) + * @ta: Translation Attributes + * @fsc: First stage context + * @msiptp: MSI page table pointer + * @msi_addr_mask: MSI address mask + * @msi_addr_pattern: MSI address pattern + * @_reserved: Reserved for future use, padding + * + * This structure is used for leaf nodes on the Device Directory Table, + * in case RISCV_IOMMU_CAPABILITIES_MSI_FLAT is not set, the bottom 4 fields + * are not present and are skipped with pointer arithmetic to avoid + * casting, check out riscv_iommu_get_dc(). + * See section 2.1 for more details + */ +struct riscv_iommu_dc { + u64 tc; + u64 iohgatp; + u64 ta; + u64 fsc; + u64 msiptp; + u64 msi_addr_mask; + u64 msi_addr_pattern; + u64 _reserved; +}; + +/* Translation control fields */ +#define RISCV_IOMMU_DC_TC_V BIT_ULL(0) +#define RISCV_IOMMU_DC_TC_EN_ATS BIT_ULL(1) +#define RISCV_IOMMU_DC_TC_EN_PRI BIT_ULL(2) +#define RISCV_IOMMU_DC_TC_T2GPA BIT_ULL(3) +#define RISCV_IOMMU_DC_TC_DTF BIT_ULL(4) +#define RISCV_IOMMU_DC_TC_PDTV BIT_ULL(5) +#define RISCV_IOMMU_DC_TC_PRPR BIT_ULL(6) +#define RISCV_IOMMU_DC_TC_GADE BIT_ULL(7) +#define RISCV_IOMMU_DC_TC_SADE BIT_ULL(8) +#define RISCV_IOMMU_DC_TC_DPE BIT_ULL(9) +#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10) +#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11) + +/* Second-stage (aka G-stage) context fields */ +#define RISCV_IOMMU_DC_IOHGATP_PPN RISCV_IOMMU_ATP_PPN_FIELD +#define RISCV_IOMMU_DC_IOHGATP_GSCID GENMASK_ULL(59, 44) +#define RISCV_IOMMU_DC_IOHGATP_MODE RISCV_IOMMU_ATP_MODE_FIELD + +/** + * enum riscv_iommu_dc_iohgatp_modes - Guest address translation/protection modes + * @RISCV_IOMMU_DC_IOHGATP_MODE_BARE: No translation/protection + * @RISCV_IOMMU_DC_IOHGATP_MODE_SV32X4: Sv32x4 (2-bit extension of Sv32), when fctl.GXL == 1 + * @RISCV_IOMMU_DC_IOHGATP_MODE_SV39X4: Sv39x4 (2-bit extension of Sv39), when fctl.GXL == 0 + * @RISCV_IOMMU_DC_IOHGATP_MODE_SV48X4: Sv48x4 (2-bit extension of Sv48), when fctl.GXL == 0 + * @RISCV_IOMMU_DC_IOHGATP_MODE_SV57X4: Sv57x4 (2-bit extension of Sv57), when fctl.GXL == 0 + */ +enum riscv_iommu_dc_iohgatp_modes { + RISCV_IOMMU_DC_IOHGATP_MODE_BARE = 0, + RISCV_IOMMU_DC_IOHGATP_MODE_SV32X4 = 8, + RISCV_IOMMU_DC_IOHGATP_MODE_SV39X4 = 8, + RISCV_IOMMU_DC_IOHGATP_MODE_SV48X4 = 9, + RISCV_IOMMU_DC_IOHGATP_MODE_SV57X4 = 10 +}; + +/* Translation attributes fields */ +#define RISCV_IOMMU_DC_TA_PSCID GENMASK_ULL(31, 12) + +/* First-stage context fields */ +#define RISCV_IOMMU_DC_FSC_PPN RISCV_IOMMU_ATP_PPN_FIELD +#define RISCV_IOMMU_DC_FSC_MODE RISCV_IOMMU_ATP_MODE_FIELD + +/** + * enum riscv_iommu_dc_fsc_atp_modes - First stage address translation/protection modes + * @RISCV_IOMMU_DC_FSC_MODE_BARE: No translation/protection + * @RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV32: Sv32, when dc.tc.SXL == 1 + * @RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39: Sv39, when dc.tc.SXL == 0 + * @RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48: Sv48, when dc.tc.SXL == 0 + * @RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57: Sv57, when dc.tc.SXL == 0 + * @RISCV_IOMMU_DC_FSC_PDTP_MODE_PD8: 1lvl PDT, 8bit process ids + * @RISCV_IOMMU_DC_FSC_PDTP_MODE_PD17: 2lvl PDT, 17bit process ids + * @RISCV_IOMMU_DC_FSC_PDTP_MODE_PD20: 3lvl PDT, 20bit process ids + * + * FSC holds IOSATP when RISCV_IOMMU_DC_TC_PDTV is 0 and PDTP otherwise. + * IOSATP controls the first stage address translation (same as the satp register on + * the RISC-V MMU), and PDTP holds the process directory table, used to select a + * first stage page table based on a process id (for devices that support multiple + * process ids). + */ +enum riscv_iommu_dc_fsc_atp_modes { + RISCV_IOMMU_DC_FSC_MODE_BARE = 0, + RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV32 = 8, + RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39 = 8, + RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48 = 9, + RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57 = 10, + RISCV_IOMMU_DC_FSC_PDTP_MODE_PD8 = 1, + RISCV_IOMMU_DC_FSC_PDTP_MODE_PD17 = 2, + RISCV_IOMMU_DC_FSC_PDTP_MODE_PD20 = 3 +}; + +/* MSI page table pointer */ +#define RISCV_IOMMU_DC_MSIPTP_PPN RISCV_IOMMU_ATP_PPN_FIELD +#define RISCV_IOMMU_DC_MSIPTP_MODE RISCV_IOMMU_ATP_MODE_FIELD +#define RISCV_IOMMU_DC_MSIPTP_MODE_OFF 0 +#define RISCV_IOMMU_DC_MSIPTP_MODE_FLAT 1 + +/* MSI address mask */ +#define RISCV_IOMMU_DC_MSI_ADDR_MASK GENMASK_ULL(51, 0) + +/* MSI address pattern */ +#define RISCV_IOMMU_DC_MSI_PATTERN GENMASK_ULL(51, 0) + +/** + * struct riscv_iommu_pc - Process Context + * @ta: Translation Attributes + * @fsc: First stage context + * + * This structure is used for leaf nodes on the Process Directory Table + * See section 2.3 for more details + */ +struct riscv_iommu_pc { + u64 ta; + u64 fsc; +}; + +/* Translation attributes fields */ +#define RISCV_IOMMU_PC_TA_V BIT_ULL(0) +#define RISCV_IOMMU_PC_TA_ENS BIT_ULL(1) +#define RISCV_IOMMU_PC_TA_SUM BIT_ULL(2) +#define RISCV_IOMMU_PC_TA_PSCID GENMASK_ULL(31, 12) + +/* First stage context fields */ +#define RISCV_IOMMU_PC_FSC_PPN RISCV_IOMMU_ATP_PPN_FIELD +#define RISCV_IOMMU_PC_FSC_MODE RISCV_IOMMU_ATP_MODE_FIELD + +/* + * Chapter 3: In-memory queue interface + */ + +/** + * struct riscv_iommu_command - Generic IOMMU command structure + * @dword0: Includes the opcode and the function identifier + * @dword1: Opcode specific data + * + * The commands are interpreted as two 64bit fields, where the first + * 7bits of the first field are the opcode which also defines the + * command's format, followed by a 3bit field that specifies the + * function invoked by that command, and the rest is opcode-specific. + * This is a generic struct which will be populated differently + * according to each command. For more infos on the commands and + * the command queue check section 3.1. + */ +struct riscv_iommu_command { + u64 dword0; + u64 dword1; +}; + +/* Fields on dword0, common for all commands */ +#define RISCV_IOMMU_CMD_OPCODE GENMASK_ULL(6, 0) +#define RISCV_IOMMU_CMD_FUNC GENMASK_ULL(9, 7) + +/* 3.1.1 IOMMU Page-table cache invalidation */ +/* Fields on dword0 */ +#define RISCV_IOMMU_CMD_IOTINVAL_OPCODE 1 +#define RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA 0 +#define RISCV_IOMMU_CMD_IOTINVAL_FUNC_GVMA 1 +#define RISCV_IOMMU_CMD_IOTINVAL_AV BIT_ULL(10) +#define RISCV_IOMMU_CMD_IOTINVAL_PSCID GENMASK_ULL(31, 12) +#define RISCV_IOMMU_CMD_IOTINVAL_PSCV BIT_ULL(32) +#define RISCV_IOMMU_CMD_IOTINVAL_GV BIT_ULL(33) +#define RISCV_IOMMU_CMD_IOTINVAL_GSCID GENMASK_ULL(59, 44) +/* dword1[61:10] is the 4K-aligned page address */ +#define RISCV_IOMMU_CMD_IOTINVAL_ADDR GENMASK_ULL(61, 10) + +/* 3.1.2 IOMMU Command Queue Fences */ +/* Fields on dword0 */ +#define RISCV_IOMMU_CMD_IOFENCE_OPCODE 2 +#define RISCV_IOMMU_CMD_IOFENCE_FUNC_C 0 +#define RISCV_IOMMU_CMD_IOFENCE_AV BIT_ULL(10) +#define RISCV_IOMMU_CMD_IOFENCE_WSI BIT_ULL(11) +#define RISCV_IOMMU_CMD_IOFENCE_PR BIT_ULL(12) +#define RISCV_IOMMU_CMD_IOFENCE_PW BIT_ULL(13) +#define RISCV_IOMMU_CMD_IOFENCE_DATA GENMASK_ULL(63, 32) +/* dword1 is the address, word-size aligned and shifted to the right by two bits. */ + +/* 3.1.3 IOMMU Directory cache invalidation */ +/* Fields on dword0 */ +#define RISCV_IOMMU_CMD_IODIR_OPCODE 3 +#define RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_DDT 0 +#define RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_PDT 1 +#define RISCV_IOMMU_CMD_IODIR_PID GENMASK_ULL(31, 12) +#define RISCV_IOMMU_CMD_IODIR_DV BIT_ULL(33) +#define RISCV_IOMMU_CMD_IODIR_DID GENMASK_ULL(63, 40) +/* dword1 is reserved for standard use */ + +/* 3.1.4 IOMMU PCIe ATS */ +/* Fields on dword0 */ +#define RISCV_IOMMU_CMD_ATS_OPCODE 4 +#define RISCV_IOMMU_CMD_ATS_FUNC_INVAL 0 +#define RISCV_IOMMU_CMD_ATS_FUNC_PRGR 1 +#define RISCV_IOMMU_CMD_ATS_PID GENMASK_ULL(31, 12) +#define RISCV_IOMMU_CMD_ATS_PV BIT_ULL(32) +#define RISCV_IOMMU_CMD_ATS_DSV BIT_ULL(33) +#define RISCV_IOMMU_CMD_ATS_RID GENMASK_ULL(55, 40) +#define RISCV_IOMMU_CMD_ATS_DSEG GENMASK_ULL(63, 56) +/* dword1 is the ATS payload, two different payload types for INVAL and PRGR */ + +/* ATS.INVAL payload*/ +#define RISCV_IOMMU_CMD_ATS_INVAL_G BIT_ULL(0) +/* Bits 1 - 10 are zeroed */ +#define RISCV_IOMMU_CMD_ATS_INVAL_S BIT_ULL(11) +#define RISCV_IOMMU_CMD_ATS_INVAL_UADDR GENMASK_ULL(63, 12) + +/* ATS.PRGR payload */ +/* Bits 0 - 31 are zeroed */ +#define RISCV_IOMMU_CMD_ATS_PRGR_PRG_INDEX GENMASK_ULL(40, 32) +/* Bits 41 - 43 are zeroed */ +#define RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE GENMASK_ULL(47, 44) +#define RISCV_IOMMU_CMD_ATS_PRGR_DST_ID GENMASK_ULL(63, 48) + +/** + * struct riscv_iommu_fq_record - Fault/Event Queue Record + * @hdr: Header, includes fault/event cause, PID/DID, transaction type etc + * @_reserved: Low 32bits for custom use, high 32bits for standard use + * @iotval: Transaction-type/cause specific format + * @iotval2: Cause specific format + * + * The fault/event queue reports events and failures raised when + * processing transactions. Each record is a 32byte structure where + * the first dword has a fixed format for providing generic infos + * regarding the fault/event, and two more dwords are there for + * fault/event-specific information. For more details see section + * 3.2. + */ +struct riscv_iommu_fq_record { + u64 hdr; + u64 _reserved; + u64 iotval; + u64 iotval2; +}; + +/* Fields on header */ +#define RISCV_IOMMU_FQ_HDR_CAUSE GENMASK_ULL(11, 0) +#define RISCV_IOMMU_FQ_HDR_PID GENMASK_ULL(31, 12) +#define RISCV_IOMMU_FQ_HDR_PV BIT_ULL(32) +#define RISCV_IOMMU_FQ_HDR_PRIV BIT_ULL(33) +#define RISCV_IOMMU_FQ_HDR_TTYP GENMASK_ULL(39, 34) +#define RISCV_IOMMU_FQ_HDR_DID GENMASK_ULL(63, 40) + +/** + * enum riscv_iommu_fq_causes - Fault/event cause values + * @RISCV_IOMMU_FQ_CAUSE_INST_FAULT: Instruction access fault + * @RISCV_IOMMU_FQ_CAUSE_RD_ADDR_MISALIGNED: Read address misaligned + * @RISCV_IOMMU_FQ_CAUSE_RD_FAULT: Read load fault + * @RISCV_IOMMU_FQ_CAUSE_WR_ADDR_MISALIGNED: Write/AMO address misaligned + * @RISCV_IOMMU_FQ_CAUSE_WR_FAULT: Write/AMO access fault + * @RISCV_IOMMU_FQ_CAUSE_INST_FAULT_S: Instruction page fault + * @RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S: Read page fault + * @RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S: Write/AMO page fault + * @RISCV_IOMMU_FQ_CAUSE_INST_FAULT_VS: Instruction guest page fault + * @RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS: Read guest page fault + * @RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS: Write/AMO guest page fault + * @RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED: All inbound transactions disallowed + * @RISCV_IOMMU_FQ_CAUSE_DDT_LOAD_FAULT: DDT entry load access fault + * @RISCV_IOMMU_FQ_CAUSE_DDT_INVALID: DDT entry invalid + * @RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED: DDT entry misconfigured + * @RISCV_IOMMU_FQ_CAUSE_TTYP_BLOCKED: Transaction type disallowed + * @RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT: MSI PTE load access fault + * @RISCV_IOMMU_FQ_CAUSE_MSI_INVALID: MSI PTE invalid + * @RISCV_IOMMU_FQ_CAUSE_MSI_MISCONFIGURED: MSI PTE misconfigured + * @RISCV_IOMMU_FQ_CAUSE_MRIF_FAULT: MRIF access fault + * @RISCV_IOMMU_FQ_CAUSE_PDT_LOAD_FAULT: PDT entry load access fault + * @RISCV_IOMMU_FQ_CAUSE_PDT_INVALID: PDT entry invalid + * @RISCV_IOMMU_FQ_CAUSE_PDT_MISCONFIGURED: PDT entry misconfigured + * @RISCV_IOMMU_FQ_CAUSE_DDT_CORRUPTED: DDT data corruption + * @RISCV_IOMMU_FQ_CAUSE_PDT_CORRUPTED: PDT data corruption + * @RISCV_IOMMU_FQ_CAUSE_MSI_PT_CORRUPTED: MSI page table data corruption + * @RISCV_IOMMU_FQ_CAUSE_MRIF_CORRUIPTED: MRIF data corruption + * @RISCV_IOMMU_FQ_CAUSE_INTERNAL_DP_ERROR: Internal data path error + * @RISCV_IOMMU_FQ_CAUSE_MSI_WR_FAULT: IOMMU MSI write access fault + * @RISCV_IOMMU_FQ_CAUSE_PT_CORRUPTED: First/second stage page table data corruption + * + * Values are on table 11 of the spec, encodings 275 - 2047 are reserved for standard + * use, and 2048 - 4095 for custom use. + */ +enum riscv_iommu_fq_causes { + RISCV_IOMMU_FQ_CAUSE_INST_FAULT = 1, + RISCV_IOMMU_FQ_CAUSE_RD_ADDR_MISALIGNED = 4, + RISCV_IOMMU_FQ_CAUSE_RD_FAULT = 5, + RISCV_IOMMU_FQ_CAUSE_WR_ADDR_MISALIGNED = 6, + RISCV_IOMMU_FQ_CAUSE_WR_FAULT = 7, + RISCV_IOMMU_FQ_CAUSE_INST_FAULT_S = 12, + RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S = 13, + RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S = 15, + RISCV_IOMMU_FQ_CAUSE_INST_FAULT_VS = 20, + RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS = 21, + RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS = 23, + RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED = 256, + RISCV_IOMMU_FQ_CAUSE_DDT_LOAD_FAULT = 257, + RISCV_IOMMU_FQ_CAUSE_DDT_INVALID = 258, + RISCV_IOMMU_FQ_CAUSE_DDT_MISCONFIGURED = 259, + RISCV_IOMMU_FQ_CAUSE_TTYP_BLOCKED = 260, + RISCV_IOMMU_FQ_CAUSE_MSI_LOAD_FAULT = 261, + RISCV_IOMMU_FQ_CAUSE_MSI_INVALID = 262, + RISCV_IOMMU_FQ_CAUSE_MSI_MISCONFIGURED = 263, + RISCV_IOMMU_FQ_CAUSE_MRIF_FAULT = 264, + RISCV_IOMMU_FQ_CAUSE_PDT_LOAD_FAULT = 265, + RISCV_IOMMU_FQ_CAUSE_PDT_INVALID = 266, + RISCV_IOMMU_FQ_CAUSE_PDT_MISCONFIGURED = 267, + RISCV_IOMMU_FQ_CAUSE_DDT_CORRUPTED = 268, + RISCV_IOMMU_FQ_CAUSE_PDT_CORRUPTED = 269, + RISCV_IOMMU_FQ_CAUSE_MSI_PT_CORRUPTED = 270, + RISCV_IOMMU_FQ_CAUSE_MRIF_CORRUIPTED = 271, + RISCV_IOMMU_FQ_CAUSE_INTERNAL_DP_ERROR = 272, + RISCV_IOMMU_FQ_CAUSE_MSI_WR_FAULT = 273, + RISCV_IOMMU_FQ_CAUSE_PT_CORRUPTED = 274 +}; + +/** + * enum riscv_iommu_fq_ttypes: Fault/event transaction types + * @RISCV_IOMMU_FQ_TTYP_NONE: None. Fault not caused by an inbound transaction. + * @RISCV_IOMMU_FQ_TTYP_UADDR_INST_FETCH: Instruction fetch from untranslated address + * @RISCV_IOMMU_FQ_TTYP_UADDR_RD: Read from untranslated address + * @RISCV_IOMMU_FQ_TTYP_UADDR_WR: Write/AMO to untranslated address + * @RISCV_IOMMU_FQ_TTYP_TADDR_INST_FETCH: Instruction fetch from translated address + * @RISCV_IOMMU_FQ_TTYP_TADDR_RD: Read from translated address + * @RISCV_IOMMU_FQ_TTYP_TADDR_WR: Write/AMO to translated address + * @RISCV_IOMMU_FQ_TTYP_PCIE_ATS_REQ: PCIe ATS translation request + * @RISCV_IOMMU_FQ_TTYP_PCIE_MSG_REQ: PCIe message request + * + * Values are on table 12 of the spec, type 4 and 10 - 31 are reserved for standard use + * and 31 - 63 for custom use. + */ +enum riscv_iommu_fq_ttypes { + RISCV_IOMMU_FQ_TTYP_NONE = 0, + RISCV_IOMMU_FQ_TTYP_UADDR_INST_FETCH = 1, + RISCV_IOMMU_FQ_TTYP_UADDR_RD = 2, + RISCV_IOMMU_FQ_TTYP_UADDR_WR = 3, + RISCV_IOMMU_FQ_TTYP_TADDR_INST_FETCH = 5, + RISCV_IOMMU_FQ_TTYP_TADDR_RD = 6, + RISCV_IOMMU_FQ_TTYP_TADDR_WR = 7, + RISCV_IOMMU_FQ_TTYP_PCIE_ATS_REQ = 8, + RISCV_IOMMU_FQ_TTYP_PCIE_MSG_REQ = 9, +}; + +/** + * struct riscv_iommu_pq_record - PCIe Page Request record + * @hdr: Header, includes PID, DID etc + * @payload: Holds the page address, request group and permission bits + * + * For more infos on the PCIe Page Request queue see chapter 3.3. + */ +struct riscv_iommu_pq_record { + u64 hdr; + u64 payload; +}; + +/* Header fields */ +#define RISCV_IOMMU_PQ_HDR_PID GENMASK_ULL(31, 12) +#define RISCV_IOMMU_PQ_HDR_PV BIT_ULL(32) +#define RISCV_IOMMU_PQ_HDR_PRIV BIT_ULL(33) +#define RISCV_IOMMU_PQ_HDR_EXEC BIT_ULL(34) +#define RISCV_IOMMU_PQ_HDR_DID GENMASK_ULL(63, 40) + +/* Payload fields */ +#define RISCV_IOMMU_PQ_PAYLOAD_R BIT_ULL(0) +#define RISCV_IOMMU_PQ_PAYLOAD_W BIT_ULL(1) +#define RISCV_IOMMU_PQ_PAYLOAD_L BIT_ULL(2) +#define RISCV_IOMMU_PQ_PAYLOAD_RWL_MASK GENMASK_ULL(2, 0) +#define RISCV_IOMMU_PQ_PAYLOAD_PRGI GENMASK_ULL(11, 3) /* Page Request Group Index */ +#define RISCV_IOMMU_PQ_PAYLOAD_ADDR GENMASK_ULL(63, 12) + +/** + * struct riscv_iommu_msipte - MSI Page Table Entry + * @pte: MSI PTE + * @mrif_info: Memory-resident interrupt file info + * + * The MSI Page Table is used for virtualizing MSIs, so that when + * a device sends an MSI to a guest, the IOMMU can reroute it + * by translating the MSI address, either to a guest interrupt file + * or a memory resident interrupt file (MRIF). Note that this page table + * is an array of MSI PTEs, not a multi-level pt, each entry + * is a leaf entry. For more infos check out the AIA spec, chapter 9.5. + * + * Also in basic mode the mrif_info field is ignored by the IOMMU and can + * be used by software, any other reserved fields on pte must be zeroed-out + * by software. + */ +struct riscv_iommu_msipte { + u64 pte; + u64 mrif_info; +}; + +/* Fields on pte */ +#define RISCV_IOMMU_MSIPTE_V BIT_ULL(0) +#define RISCV_IOMMU_MSIPTE_M GENMASK_ULL(2, 1) +#define RISCV_IOMMU_MSIPTE_MRIF_ADDR GENMASK_ULL(53, 7) /* When M == 1 (MRIF mode) */ +#define RISCV_IOMMU_MSIPTE_PPN RISCV_IOMMU_PPN_FIELD /* When M == 3 (basic mode) */ +#define RISCV_IOMMU_MSIPTE_C BIT_ULL(63) + +/* Fields on mrif_info */ +#define RISCV_IOMMU_MSIPTE_MRIF_NID GENMASK_ULL(9, 0) +#define RISCV_IOMMU_MSIPTE_MRIF_NPPN RISCV_IOMMU_PPN_FIELD +#define RISCV_IOMMU_MSIPTE_MRIF_NID_MSB BIT_ULL(60) + +/* Helper functions: command structure builders. */ + +static inline void riscv_iommu_cmd_inval_vma(struct riscv_iommu_command *cmd) +{ + cmd->dword0 = FIELD_PREP(RISCV_IOMMU_CMD_OPCODE, RISCV_IOMMU_CMD_IOTINVAL_OPCODE) | + FIELD_PREP(RISCV_IOMMU_CMD_FUNC, RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA); + cmd->dword1 = 0; +} + +static inline void riscv_iommu_cmd_inval_set_addr(struct riscv_iommu_command *cmd, + u64 addr) +{ + cmd->dword1 = FIELD_PREP(RISCV_IOMMU_CMD_IOTINVAL_ADDR, phys_to_pfn(addr)); + cmd->dword0 |= RISCV_IOMMU_CMD_IOTINVAL_AV; +} + +static inline void riscv_iommu_cmd_inval_set_pscid(struct riscv_iommu_command *cmd, + int pscid) +{ + cmd->dword0 |= FIELD_PREP(RISCV_IOMMU_CMD_IOTINVAL_PSCID, pscid) | + RISCV_IOMMU_CMD_IOTINVAL_PSCV; +} + +static inline void riscv_iommu_cmd_inval_set_gscid(struct riscv_iommu_command *cmd, + int gscid) +{ + cmd->dword0 |= FIELD_PREP(RISCV_IOMMU_CMD_IOTINVAL_GSCID, gscid) | + RISCV_IOMMU_CMD_IOTINVAL_GV; +} + +static inline void riscv_iommu_cmd_iofence(struct riscv_iommu_command *cmd) +{ + cmd->dword0 = FIELD_PREP(RISCV_IOMMU_CMD_OPCODE, RISCV_IOMMU_CMD_IOFENCE_OPCODE) | + FIELD_PREP(RISCV_IOMMU_CMD_FUNC, RISCV_IOMMU_CMD_IOFENCE_FUNC_C) | + RISCV_IOMMU_CMD_IOFENCE_PR | RISCV_IOMMU_CMD_IOFENCE_PW; + cmd->dword1 = 0; +} + +static inline void riscv_iommu_cmd_iofence_set_av(struct riscv_iommu_command *cmd, + u64 addr, u32 data) +{ + cmd->dword0 = FIELD_PREP(RISCV_IOMMU_CMD_OPCODE, RISCV_IOMMU_CMD_IOFENCE_OPCODE) | + FIELD_PREP(RISCV_IOMMU_CMD_FUNC, RISCV_IOMMU_CMD_IOFENCE_FUNC_C) | + FIELD_PREP(RISCV_IOMMU_CMD_IOFENCE_DATA, data) | + RISCV_IOMMU_CMD_IOFENCE_AV; + cmd->dword1 = addr >> 2; +} + +static inline void riscv_iommu_cmd_iodir_inval_ddt(struct riscv_iommu_command *cmd) +{ + cmd->dword0 = FIELD_PREP(RISCV_IOMMU_CMD_OPCODE, RISCV_IOMMU_CMD_IODIR_OPCODE) | + FIELD_PREP(RISCV_IOMMU_CMD_FUNC, RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_DDT); + cmd->dword1 = 0; +} + +static inline void riscv_iommu_cmd_iodir_inval_pdt(struct riscv_iommu_command *cmd) +{ + cmd->dword0 = FIELD_PREP(RISCV_IOMMU_CMD_OPCODE, RISCV_IOMMU_CMD_IODIR_OPCODE) | + FIELD_PREP(RISCV_IOMMU_CMD_FUNC, RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_PDT); + cmd->dword1 = 0; +} + +static inline void riscv_iommu_cmd_iodir_set_did(struct riscv_iommu_command *cmd, + unsigned int devid) +{ + cmd->dword0 |= FIELD_PREP(RISCV_IOMMU_CMD_IODIR_DID, devid) | + RISCV_IOMMU_CMD_IODIR_DV; +} + +static inline void riscv_iommu_cmd_iodir_set_pid(struct riscv_iommu_command *cmd, + unsigned int pasid) +{ + cmd->dword0 |= FIELD_PREP(RISCV_IOMMU_CMD_IODIR_PID, pasid); +} + +#endif /* _RISCV_IOMMU_BITS_H_ */ diff --git a/drivers/iommu/riscv/iommu-pci.c b/drivers/iommu/riscv/iommu-pci.c new file mode 100644 index 00000000000000..c7a89143014c58 --- /dev/null +++ b/drivers/iommu/riscv/iommu-pci.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright © 2022-2024 Rivos Inc. + * Copyright © 2023 FORTH-ICS/CARV + * + * RISCV IOMMU as a PCIe device + * + * Authors + * Tomasz Jeznach + * Nick Kossifidis + */ + +#include +#include +#include +#include +#include + +#include "iommu-bits.h" +#include "iommu.h" + +/* QEMU RISC-V IOMMU implementation */ +#define PCI_DEVICE_ID_REDHAT_RISCV_IOMMU 0x0014 + +/* Rivos Inc. assigned PCI Vendor and Device IDs */ +#ifndef PCI_VENDOR_ID_RIVOS +#define PCI_VENDOR_ID_RIVOS 0x1efd +#endif + +#define PCI_DEVICE_ID_RIVOS_RISCV_IOMMU_GA 0x0008 + +static int riscv_iommu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct riscv_iommu_device *iommu; + int rc, vec; + + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) + return -ENODEV; + + if (pci_resource_len(pdev, 0) < RISCV_IOMMU_REG_SIZE) + return -ENODEV; + + rc = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (rc) + return dev_err_probe(dev, rc, "pcim_iomap_regions failed\n"); + + iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL); + if (!iommu) + return -ENOMEM; + + iommu->dev = dev; + iommu->reg = pcim_iomap_table(pdev)[0]; + + pci_set_master(pdev); + dev_set_drvdata(dev, iommu); + + /* Check device reported capabilities / features. */ + iommu->caps = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_CAPABILITIES); + iommu->fctl = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_FCTL); + + /* The PCI driver only uses MSIs, make sure the IOMMU supports this */ + switch (FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS, iommu->caps)) { + case RISCV_IOMMU_CAPABILITIES_IGS_MSI: + case RISCV_IOMMU_CAPABILITIES_IGS_BOTH: + break; + default: + return dev_err_probe(dev, -ENODEV, + "unable to use message-signaled interrupts\n"); + } + + /* Allocate and assign IRQ vectors for the various events */ + rc = pci_alloc_irq_vectors(pdev, 1, RISCV_IOMMU_INTR_COUNT, + PCI_IRQ_MSIX | PCI_IRQ_MSI); + if (rc <= 0) + return dev_err_probe(dev, -ENODEV, + "unable to allocate irq vectors\n"); + + iommu->irqs_count = rc; + for (vec = 0; vec < iommu->irqs_count; vec++) + iommu->irqs[vec] = msi_get_virq(dev, vec); + + /* Enable message-signaled interrupts, fctl.WSI */ + if (iommu->fctl & RISCV_IOMMU_FCTL_WSI) { + iommu->fctl ^= RISCV_IOMMU_FCTL_WSI; + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_FCTL, iommu->fctl); + } + + return riscv_iommu_init(iommu); +} + +static void riscv_iommu_pci_remove(struct pci_dev *pdev) +{ + struct riscv_iommu_device *iommu = dev_get_drvdata(&pdev->dev); + + riscv_iommu_remove(iommu); +} + +static const struct pci_device_id riscv_iommu_pci_tbl[] = { + {PCI_VDEVICE(REDHAT, PCI_DEVICE_ID_REDHAT_RISCV_IOMMU), 0}, + {PCI_VDEVICE(RIVOS, PCI_DEVICE_ID_RIVOS_RISCV_IOMMU_GA), 0}, + {0,} +}; + +static struct pci_driver riscv_iommu_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = riscv_iommu_pci_tbl, + .probe = riscv_iommu_pci_probe, + .remove = riscv_iommu_pci_remove, + .driver = { + .suppress_bind_attrs = true, + }, +}; + +builtin_pci_driver(riscv_iommu_pci_driver); diff --git a/drivers/iommu/riscv/iommu-platform.c b/drivers/iommu/riscv/iommu-platform.c new file mode 100644 index 00000000000000..382ba28418498e --- /dev/null +++ b/drivers/iommu/riscv/iommu-platform.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RISC-V IOMMU as a platform device + * + * Copyright © 2023 FORTH-ICS/CARV + * Copyright © 2023-2024 Rivos Inc. + * + * Authors + * Nick Kossifidis + * Tomasz Jeznach + */ + +#include +#include +#include + +#include "iommu-bits.h" +#include "iommu.h" + +static int riscv_iommu_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct riscv_iommu_device *iommu = NULL; + struct resource *res = NULL; + int vec; + + iommu = devm_kzalloc(dev, sizeof(*iommu), GFP_KERNEL); + if (!iommu) + return -ENOMEM; + + iommu->dev = dev; + iommu->reg = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(iommu->reg)) + return dev_err_probe(dev, PTR_ERR(iommu->reg), + "could not map register region\n"); + + dev_set_drvdata(dev, iommu); + + /* Check device reported capabilities / features. */ + iommu->caps = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_CAPABILITIES); + iommu->fctl = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_FCTL); + + /* For now we only support WSI */ + switch (FIELD_GET(RISCV_IOMMU_CAPABILITIES_IGS, iommu->caps)) { + case RISCV_IOMMU_CAPABILITIES_IGS_WSI: + case RISCV_IOMMU_CAPABILITIES_IGS_BOTH: + break; + default: + return dev_err_probe(dev, -ENODEV, + "unable to use wire-signaled interrupts\n"); + } + + iommu->irqs_count = platform_irq_count(pdev); + if (iommu->irqs_count <= 0) + return dev_err_probe(dev, -ENODEV, + "no IRQ resources provided\n"); + if (iommu->irqs_count > RISCV_IOMMU_INTR_COUNT) + iommu->irqs_count = RISCV_IOMMU_INTR_COUNT; + + for (vec = 0; vec < iommu->irqs_count; vec++) + iommu->irqs[vec] = platform_get_irq(pdev, vec); + + /* Enable wire-signaled interrupts, fctl.WSI */ + if (!(iommu->fctl & RISCV_IOMMU_FCTL_WSI)) { + iommu->fctl |= RISCV_IOMMU_FCTL_WSI; + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_FCTL, iommu->fctl); + } + + return riscv_iommu_init(iommu); +}; + +static void riscv_iommu_platform_remove(struct platform_device *pdev) +{ + riscv_iommu_remove(dev_get_drvdata(&pdev->dev)); +}; + +static const struct of_device_id riscv_iommu_of_match[] = { + {.compatible = "riscv,iommu",}, + {}, +}; + +static struct platform_driver riscv_iommu_platform_driver = { + .probe = riscv_iommu_platform_probe, + .remove = riscv_iommu_platform_remove, + .driver = { + .name = "riscv,iommu", + .of_match_table = riscv_iommu_of_match, + .suppress_bind_attrs = true, + }, +}; + +builtin_platform_driver(riscv_iommu_platform_driver); diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c new file mode 100644 index 00000000000000..8a05def774bdb5 --- /dev/null +++ b/drivers/iommu/riscv/iommu.c @@ -0,0 +1,1661 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * IOMMU API for RISC-V IOMMU implementations. + * + * Copyright © 2022-2024 Rivos Inc. + * Copyright © 2023 FORTH-ICS/CARV + * + * Authors + * Tomasz Jeznach + * Nick Kossifidis + */ + +#define pr_fmt(fmt) "riscv-iommu: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "../iommu-pages.h" +#include "iommu-bits.h" +#include "iommu.h" + +/* Timeouts in [us] */ +#define RISCV_IOMMU_QCSR_TIMEOUT 150000 +#define RISCV_IOMMU_QUEUE_TIMEOUT 150000 +#define RISCV_IOMMU_DDTP_TIMEOUT 10000000 +#define RISCV_IOMMU_IOTINVAL_TIMEOUT 90000000 + +/* Number of entries per CMD/FLT queue, should be <= INT_MAX */ +#define RISCV_IOMMU_DEF_CQ_COUNT 8192 +#define RISCV_IOMMU_DEF_FQ_COUNT 4096 + +/* RISC-V IOMMU PPN <> PHYS address conversions, PHYS <=> PPN[53:10] */ +#define phys_to_ppn(pa) (((pa) >> 2) & (((1ULL << 44) - 1) << 10)) +#define ppn_to_phys(pn) (((pn) << 2) & (((1ULL << 44) - 1) << 12)) + +#define dev_to_iommu(dev) \ + iommu_get_iommu_dev(dev, struct riscv_iommu_device, iommu) + +/* IOMMU PSCID allocation namespace. */ +static DEFINE_IDA(riscv_iommu_pscids); +#define RISCV_IOMMU_MAX_PSCID (BIT(20) - 1) + +/* Device resource-managed allocations */ +struct riscv_iommu_devres { + void *addr; + int order; +}; + +static void riscv_iommu_devres_pages_release(struct device *dev, void *res) +{ + struct riscv_iommu_devres *devres = res; + + iommu_free_pages(devres->addr, devres->order); +} + +static int riscv_iommu_devres_pages_match(struct device *dev, void *res, void *p) +{ + struct riscv_iommu_devres *devres = res; + struct riscv_iommu_devres *target = p; + + return devres->addr == target->addr; +} + +static void *riscv_iommu_get_pages(struct riscv_iommu_device *iommu, int order) +{ + struct riscv_iommu_devres *devres; + void *addr; + + addr = iommu_alloc_pages_node(dev_to_node(iommu->dev), + GFP_KERNEL_ACCOUNT, order); + if (unlikely(!addr)) + return NULL; + + devres = devres_alloc(riscv_iommu_devres_pages_release, + sizeof(struct riscv_iommu_devres), GFP_KERNEL); + + if (unlikely(!devres)) { + iommu_free_pages(addr, order); + return NULL; + } + + devres->addr = addr; + devres->order = order; + + devres_add(iommu->dev, devres); + + return addr; +} + +static void riscv_iommu_free_pages(struct riscv_iommu_device *iommu, void *addr) +{ + struct riscv_iommu_devres devres = { .addr = addr }; + + devres_release(iommu->dev, riscv_iommu_devres_pages_release, + riscv_iommu_devres_pages_match, &devres); +} + +/* + * Hardware queue allocation and management. + */ + +/* Setup queue base, control registers and default queue length */ +#define RISCV_IOMMU_QUEUE_INIT(q, name) do { \ + struct riscv_iommu_queue *_q = q; \ + _q->qid = RISCV_IOMMU_INTR_ ## name; \ + _q->qbr = RISCV_IOMMU_REG_ ## name ## B; \ + _q->qcr = RISCV_IOMMU_REG_ ## name ## CSR; \ + _q->mask = _q->mask ?: (RISCV_IOMMU_DEF_ ## name ## _COUNT) - 1;\ +} while (0) + +/* Note: offsets are the same for all queues */ +#define Q_HEAD(q) ((q)->qbr + (RISCV_IOMMU_REG_CQH - RISCV_IOMMU_REG_CQB)) +#define Q_TAIL(q) ((q)->qbr + (RISCV_IOMMU_REG_CQT - RISCV_IOMMU_REG_CQB)) +#define Q_ITEM(q, index) ((q)->mask & (index)) +#define Q_IPSR(q) BIT((q)->qid) + +/* + * Discover queue ring buffer hardware configuration, allocate in-memory + * ring buffer or use fixed I/O memory location, configure queue base register. + * Must be called before hardware queue is enabled. + * + * @queue - data structure, configured with RISCV_IOMMU_QUEUE_INIT() + * @entry_size - queue single element size in bytes. + */ +static int riscv_iommu_queue_alloc(struct riscv_iommu_device *iommu, + struct riscv_iommu_queue *queue, + size_t entry_size) +{ + unsigned int logsz; + u64 qb, rb; + + /* + * Use WARL base register property to discover maximum allowed + * number of entries and optional fixed IO address for queue location. + */ + riscv_iommu_writeq(iommu, queue->qbr, RISCV_IOMMU_QUEUE_LOG2SZ_FIELD); + qb = riscv_iommu_readq(iommu, queue->qbr); + + /* + * Calculate and verify hardware supported queue length, as reported + * by the field LOG2SZ, where max queue length is equal to 2^(LOG2SZ + 1). + * Update queue size based on hardware supported value. + */ + logsz = ilog2(queue->mask); + if (logsz > FIELD_GET(RISCV_IOMMU_QUEUE_LOG2SZ_FIELD, qb)) + logsz = FIELD_GET(RISCV_IOMMU_QUEUE_LOG2SZ_FIELD, qb); + + /* + * Use WARL base register property to discover an optional fixed IO + * address for queue ring buffer location. Otherwise allocate contiguous + * system memory. + */ + if (FIELD_GET(RISCV_IOMMU_PPN_FIELD, qb)) { + const size_t queue_size = entry_size << (logsz + 1); + + queue->phys = pfn_to_phys(FIELD_GET(RISCV_IOMMU_PPN_FIELD, qb)); + queue->base = devm_ioremap(iommu->dev, queue->phys, queue_size); + } else { + do { + const size_t queue_size = entry_size << (logsz + 1); + const int order = get_order(queue_size); + + queue->base = riscv_iommu_get_pages(iommu, order); + queue->phys = __pa(queue->base); + } while (!queue->base && logsz-- > 0); + } + + if (!queue->base) + return -ENOMEM; + + qb = phys_to_ppn(queue->phys) | + FIELD_PREP(RISCV_IOMMU_QUEUE_LOG2SZ_FIELD, logsz); + + /* Update base register and read back to verify hw accepted our write */ + riscv_iommu_writeq(iommu, queue->qbr, qb); + rb = riscv_iommu_readq(iommu, queue->qbr); + if (rb != qb) { + dev_err(iommu->dev, "queue #%u allocation failed\n", queue->qid); + return -ENODEV; + } + + /* Update actual queue mask */ + queue->mask = (2U << logsz) - 1; + + dev_dbg(iommu->dev, "queue #%u allocated 2^%u entries", + queue->qid, logsz + 1); + + return 0; +} + +/* Check interrupt queue status, IPSR */ +static irqreturn_t riscv_iommu_queue_ipsr(int irq, void *data) +{ + struct riscv_iommu_queue *queue = (struct riscv_iommu_queue *)data; + + if (riscv_iommu_readl(queue->iommu, RISCV_IOMMU_REG_IPSR) & Q_IPSR(queue)) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +static int riscv_iommu_queue_vec(struct riscv_iommu_device *iommu, int n) +{ + /* Reuse ICVEC.CIV mask for all interrupt vectors mapping. */ + return (iommu->icvec >> (n * 4)) & RISCV_IOMMU_ICVEC_CIV; +} + +/* + * Enable queue processing in the hardware, register interrupt handler. + * + * @queue - data structure, already allocated with riscv_iommu_queue_alloc() + * @irq_handler - threaded interrupt handler. + */ +static int riscv_iommu_queue_enable(struct riscv_iommu_device *iommu, + struct riscv_iommu_queue *queue, + irq_handler_t irq_handler) +{ + const unsigned int irq = iommu->irqs[riscv_iommu_queue_vec(iommu, queue->qid)]; + u32 csr; + int rc; + + if (queue->iommu) + return -EBUSY; + + /* Polling not implemented */ + if (!irq) + return -ENODEV; + + queue->iommu = iommu; + rc = request_threaded_irq(irq, riscv_iommu_queue_ipsr, irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(iommu->dev), queue); + if (rc) { + queue->iommu = NULL; + return rc; + } + + /* + * Enable queue with interrupts, clear any memory fault if any. + * Wait for the hardware to acknowledge request and activate queue + * processing. + * Note: All CSR bitfields are in the same offsets for all queues. + */ + riscv_iommu_writel(iommu, queue->qcr, + RISCV_IOMMU_QUEUE_ENABLE | + RISCV_IOMMU_QUEUE_INTR_ENABLE | + RISCV_IOMMU_QUEUE_MEM_FAULT); + + riscv_iommu_readl_timeout(iommu, queue->qcr, + csr, !(csr & RISCV_IOMMU_QUEUE_BUSY), + 10, RISCV_IOMMU_QCSR_TIMEOUT); + + if (RISCV_IOMMU_QUEUE_ACTIVE != (csr & (RISCV_IOMMU_QUEUE_ACTIVE | + RISCV_IOMMU_QUEUE_BUSY | + RISCV_IOMMU_QUEUE_MEM_FAULT))) { + /* Best effort to stop and disable failing hardware queue. */ + riscv_iommu_writel(iommu, queue->qcr, 0); + free_irq(irq, queue); + queue->iommu = NULL; + dev_err(iommu->dev, "queue #%u failed to start\n", queue->qid); + return -EBUSY; + } + + /* Clear any pending interrupt flag. */ + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_IPSR, Q_IPSR(queue)); + + return 0; +} + +/* + * Disable queue. Wait for the hardware to acknowledge request and + * stop processing enqueued requests. Report errors but continue. + */ +static void riscv_iommu_queue_disable(struct riscv_iommu_queue *queue) +{ + struct riscv_iommu_device *iommu = queue->iommu; + u32 csr; + + if (!iommu) + return; + + free_irq(iommu->irqs[riscv_iommu_queue_vec(iommu, queue->qid)], queue); + riscv_iommu_writel(iommu, queue->qcr, 0); + riscv_iommu_readl_timeout(iommu, queue->qcr, + csr, !(csr & RISCV_IOMMU_QUEUE_BUSY), + 10, RISCV_IOMMU_QCSR_TIMEOUT); + + if (csr & (RISCV_IOMMU_QUEUE_ACTIVE | RISCV_IOMMU_QUEUE_BUSY)) + dev_err(iommu->dev, "fail to disable hardware queue #%u, csr 0x%x\n", + queue->qid, csr); + + queue->iommu = NULL; +} + +/* + * Returns number of available valid queue entries and the first item index. + * Update shadow producer index if necessary. + */ +static int riscv_iommu_queue_consume(struct riscv_iommu_queue *queue, + unsigned int *index) +{ + unsigned int head = atomic_read(&queue->head); + unsigned int tail = atomic_read(&queue->tail); + unsigned int last = Q_ITEM(queue, tail); + int available = (int)(tail - head); + + *index = head; + + if (available > 0) + return available; + + /* read hardware producer index, check reserved register bits are not set. */ + if (riscv_iommu_readl_timeout(queue->iommu, Q_TAIL(queue), + tail, (tail & ~queue->mask) == 0, + 0, RISCV_IOMMU_QUEUE_TIMEOUT)) { + dev_err_once(queue->iommu->dev, + "Hardware error: queue access timeout\n"); + return 0; + } + + if (tail == last) + return 0; + + /* update shadow producer index */ + return (int)(atomic_add_return((tail - last) & queue->mask, &queue->tail) - head); +} + +/* + * Release processed queue entries, should match riscv_iommu_queue_consume() calls. + */ +static void riscv_iommu_queue_release(struct riscv_iommu_queue *queue, int count) +{ + const unsigned int head = atomic_add_return(count, &queue->head); + + riscv_iommu_writel(queue->iommu, Q_HEAD(queue), Q_ITEM(queue, head)); +} + +/* Return actual consumer index based on hardware reported queue head index. */ +static unsigned int riscv_iommu_queue_cons(struct riscv_iommu_queue *queue) +{ + const unsigned int cons = atomic_read(&queue->head); + const unsigned int last = Q_ITEM(queue, cons); + unsigned int head; + + if (riscv_iommu_readl_timeout(queue->iommu, Q_HEAD(queue), head, + !(head & ~queue->mask), + 0, RISCV_IOMMU_QUEUE_TIMEOUT)) + return cons; + + return cons + ((head - last) & queue->mask); +} + +/* Wait for submitted item to be processed. */ +static int riscv_iommu_queue_wait(struct riscv_iommu_queue *queue, + unsigned int index, + unsigned int timeout_us) +{ + unsigned int cons = atomic_read(&queue->head); + + /* Already processed by the consumer */ + if ((int)(cons - index) > 0) + return 0; + + /* Monitor consumer index */ + return readx_poll_timeout(riscv_iommu_queue_cons, queue, cons, + (int)(cons - index) > 0, 0, timeout_us); +} + +/* Enqueue an entry and wait to be processed if timeout_us > 0 + * + * Error handling for IOMMU hardware not responding in reasonable time + * will be added as separate patch series along with other RAS features. + * For now, only report hardware failure and continue. + */ +static unsigned int riscv_iommu_queue_send(struct riscv_iommu_queue *queue, + void *entry, size_t entry_size) +{ + unsigned int prod; + unsigned int head; + unsigned int tail; + unsigned long flags; + + /* Do not preempt submission flow. */ + local_irq_save(flags); + + /* 1. Allocate some space in the queue */ + prod = atomic_inc_return(&queue->prod) - 1; + head = atomic_read(&queue->head); + + /* 2. Wait for space availability. */ + if ((prod - head) > queue->mask) { + if (readx_poll_timeout(atomic_read, &queue->head, + head, (prod - head) < queue->mask, + 0, RISCV_IOMMU_QUEUE_TIMEOUT)) + goto err_busy; + } else if ((prod - head) == queue->mask) { + const unsigned int last = Q_ITEM(queue, head); + + if (riscv_iommu_readl_timeout(queue->iommu, Q_HEAD(queue), head, + !(head & ~queue->mask) && head != last, + 0, RISCV_IOMMU_QUEUE_TIMEOUT)) + goto err_busy; + atomic_add((head - last) & queue->mask, &queue->head); + } + + /* 3. Store entry in the ring buffer */ + memcpy(queue->base + Q_ITEM(queue, prod) * entry_size, entry, entry_size); + + /* 4. Wait for all previous entries to be ready */ + if (readx_poll_timeout(atomic_read, &queue->tail, tail, prod == tail, + 0, RISCV_IOMMU_QUEUE_TIMEOUT)) + goto err_busy; + + /* + * 5. Make sure the ring buffer update (whether in normal or I/O memory) is + * completed and visible before signaling the tail doorbell to fetch + * the next command. 'fence ow, ow' + */ + dma_wmb(); + riscv_iommu_writel(queue->iommu, Q_TAIL(queue), Q_ITEM(queue, prod + 1)); + + /* + * 6. Make sure the doorbell write to the device has finished before updating + * the shadow tail index in normal memory. 'fence o, w' + */ + mmiowb(); + atomic_inc(&queue->tail); + + /* 7. Complete submission and restore local interrupts */ + local_irq_restore(flags); + + return prod; + +err_busy: + local_irq_restore(flags); + dev_err_once(queue->iommu->dev, "Hardware error: command enqueue failed\n"); + + return prod; +} + +/* + * IOMMU Command queue chapter 3.1 + */ + +/* Command queue interrupt handler thread function */ +static irqreturn_t riscv_iommu_cmdq_process(int irq, void *data) +{ + const struct riscv_iommu_queue *queue = (struct riscv_iommu_queue *)data; + unsigned int ctrl; + + /* Clear MF/CQ errors, complete error recovery to be implemented. */ + ctrl = riscv_iommu_readl(queue->iommu, queue->qcr); + if (ctrl & (RISCV_IOMMU_CQCSR_CQMF | RISCV_IOMMU_CQCSR_CMD_TO | + RISCV_IOMMU_CQCSR_CMD_ILL | RISCV_IOMMU_CQCSR_FENCE_W_IP)) { + riscv_iommu_writel(queue->iommu, queue->qcr, ctrl); + dev_warn(queue->iommu->dev, + "Queue #%u error; fault:%d timeout:%d illegal:%d fence_w_ip:%d\n", + queue->qid, + !!(ctrl & RISCV_IOMMU_CQCSR_CQMF), + !!(ctrl & RISCV_IOMMU_CQCSR_CMD_TO), + !!(ctrl & RISCV_IOMMU_CQCSR_CMD_ILL), + !!(ctrl & RISCV_IOMMU_CQCSR_FENCE_W_IP)); + } + + /* Placeholder for command queue interrupt notifiers */ + + /* Clear command interrupt pending. */ + riscv_iommu_writel(queue->iommu, RISCV_IOMMU_REG_IPSR, Q_IPSR(queue)); + + return IRQ_HANDLED; +} + +/* Send command to the IOMMU command queue */ +static void riscv_iommu_cmd_send(struct riscv_iommu_device *iommu, + struct riscv_iommu_command *cmd) +{ + riscv_iommu_queue_send(&iommu->cmdq, cmd, sizeof(*cmd)); +} + +/* Send IOFENCE.C command and wait for all scheduled commands to complete. */ +static void riscv_iommu_cmd_sync(struct riscv_iommu_device *iommu, + unsigned int timeout_us) +{ + struct riscv_iommu_command cmd; + unsigned int prod; + + riscv_iommu_cmd_iofence(&cmd); + prod = riscv_iommu_queue_send(&iommu->cmdq, &cmd, sizeof(cmd)); + + if (!timeout_us) + return; + + if (riscv_iommu_queue_wait(&iommu->cmdq, prod, timeout_us)) + dev_err_once(iommu->dev, + "Hardware error: command execution timeout\n"); +} + +/* + * IOMMU Fault/Event queue chapter 3.2 + */ + +static void riscv_iommu_fault(struct riscv_iommu_device *iommu, + struct riscv_iommu_fq_record *event) +{ + unsigned int err = FIELD_GET(RISCV_IOMMU_FQ_HDR_CAUSE, event->hdr); + unsigned int devid = FIELD_GET(RISCV_IOMMU_FQ_HDR_DID, event->hdr); + + /* Placeholder for future fault handling implementation, report only. */ + if (err) + dev_warn_ratelimited(iommu->dev, + "Fault %d devid: 0x%x iotval: %llx iotval2: %llx\n", + err, devid, event->iotval, event->iotval2); +} + +/* Fault queue interrupt handler thread function */ +static irqreturn_t riscv_iommu_fltq_process(int irq, void *data) +{ + struct riscv_iommu_queue *queue = (struct riscv_iommu_queue *)data; + struct riscv_iommu_device *iommu = queue->iommu; + struct riscv_iommu_fq_record *events; + unsigned int ctrl, idx; + int cnt, len; + + events = (struct riscv_iommu_fq_record *)queue->base; + + /* Clear fault interrupt pending and process all received fault events. */ + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_IPSR, Q_IPSR(queue)); + + do { + cnt = riscv_iommu_queue_consume(queue, &idx); + for (len = 0; len < cnt; idx++, len++) + riscv_iommu_fault(iommu, &events[Q_ITEM(queue, idx)]); + riscv_iommu_queue_release(queue, cnt); + } while (cnt > 0); + + /* Clear MF/OF errors, complete error recovery to be implemented. */ + ctrl = riscv_iommu_readl(iommu, queue->qcr); + if (ctrl & (RISCV_IOMMU_FQCSR_FQMF | RISCV_IOMMU_FQCSR_FQOF)) { + riscv_iommu_writel(iommu, queue->qcr, ctrl); + dev_warn(iommu->dev, + "Queue #%u error; memory fault:%d overflow:%d\n", + queue->qid, + !!(ctrl & RISCV_IOMMU_FQCSR_FQMF), + !!(ctrl & RISCV_IOMMU_FQCSR_FQOF)); + } + + return IRQ_HANDLED; +} + +/* Lookup and initialize device context info structure. */ +static struct riscv_iommu_dc *riscv_iommu_get_dc(struct riscv_iommu_device *iommu, + unsigned int devid) +{ + const bool base_format = !(iommu->caps & RISCV_IOMMU_CAPABILITIES_MSI_FLAT); + unsigned int depth; + unsigned long ddt, old, new; + void *ptr; + u8 ddi_bits[3] = { 0 }; + u64 *ddtp = NULL; + + /* Make sure the mode is valid */ + if (iommu->ddt_mode < RISCV_IOMMU_DDTP_IOMMU_MODE_1LVL || + iommu->ddt_mode > RISCV_IOMMU_DDTP_IOMMU_MODE_3LVL) + return NULL; + + /* + * Device id partitioning for base format: + * DDI[0]: bits 0 - 6 (1st level) (7 bits) + * DDI[1]: bits 7 - 15 (2nd level) (9 bits) + * DDI[2]: bits 16 - 23 (3rd level) (8 bits) + * + * For extended format: + * DDI[0]: bits 0 - 5 (1st level) (6 bits) + * DDI[1]: bits 6 - 14 (2nd level) (9 bits) + * DDI[2]: bits 15 - 23 (3rd level) (9 bits) + */ + if (base_format) { + ddi_bits[0] = 7; + ddi_bits[1] = 7 + 9; + ddi_bits[2] = 7 + 9 + 8; + } else { + ddi_bits[0] = 6; + ddi_bits[1] = 6 + 9; + ddi_bits[2] = 6 + 9 + 9; + } + + /* Make sure device id is within range */ + depth = iommu->ddt_mode - RISCV_IOMMU_DDTP_IOMMU_MODE_1LVL; + if (devid >= (1 << ddi_bits[depth])) + return NULL; + + /* Get to the level of the non-leaf node that holds the device context */ + for (ddtp = iommu->ddt_root; depth-- > 0;) { + const int split = ddi_bits[depth]; + /* + * Each non-leaf node is 64bits wide and on each level + * nodes are indexed by DDI[depth]. + */ + ddtp += (devid >> split) & 0x1FF; + + /* + * Check if this node has been populated and if not + * allocate a new level and populate it. + */ + do { + ddt = READ_ONCE(*(unsigned long *)ddtp); + if (ddt & RISCV_IOMMU_DDTE_V) { + ddtp = __va(ppn_to_phys(ddt)); + break; + } + + ptr = riscv_iommu_get_pages(iommu, 0); + if (!ptr) + return NULL; + + new = phys_to_ppn(__pa(ptr)) | RISCV_IOMMU_DDTE_V; + old = cmpxchg_relaxed((unsigned long *)ddtp, ddt, new); + + if (old == ddt) { + ddtp = (u64 *)ptr; + break; + } + + /* Race setting DDT detected, re-read and retry. */ + riscv_iommu_free_pages(iommu, ptr); + } while (1); + } + + /* + * Grab the node that matches DDI[depth], note that when using base + * format the device context is 4 * 64bits, and the extended format + * is 8 * 64bits, hence the (3 - base_format) below. + */ + ddtp += (devid & ((64 << base_format) - 1)) << (3 - base_format); + + return (struct riscv_iommu_dc *)ddtp; +} + +/* + * This is best effort IOMMU translation shutdown flow. + * Disable IOMMU without waiting for hardware response. + */ +static void riscv_iommu_disable(struct riscv_iommu_device *iommu) +{ + riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_DDTP, 0); + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_CQCSR, 0); + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_FQCSR, 0); + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_PQCSR, 0); +} + +#define riscv_iommu_read_ddtp(iommu) ({ \ + u64 ddtp; \ + riscv_iommu_readq_timeout((iommu), RISCV_IOMMU_REG_DDTP, ddtp, \ + !(ddtp & RISCV_IOMMU_DDTP_BUSY), 10, \ + RISCV_IOMMU_DDTP_TIMEOUT); \ + ddtp; }) + +static int riscv_iommu_iodir_alloc(struct riscv_iommu_device *iommu) +{ + u64 ddtp; + unsigned int mode; + + ddtp = riscv_iommu_read_ddtp(iommu); + if (ddtp & RISCV_IOMMU_DDTP_BUSY) + return -EBUSY; + + /* + * It is optional for the hardware to report a fixed address for device + * directory root page when DDT.MODE is OFF or BARE. + */ + mode = FIELD_GET(RISCV_IOMMU_DDTP_IOMMU_MODE, ddtp); + if (mode == RISCV_IOMMU_DDTP_IOMMU_MODE_BARE || + mode == RISCV_IOMMU_DDTP_IOMMU_MODE_OFF) { + /* Use WARL to discover hardware fixed DDT PPN */ + riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_DDTP, + FIELD_PREP(RISCV_IOMMU_DDTP_IOMMU_MODE, mode)); + ddtp = riscv_iommu_read_ddtp(iommu); + if (ddtp & RISCV_IOMMU_DDTP_BUSY) + return -EBUSY; + + iommu->ddt_phys = ppn_to_phys(ddtp); + if (iommu->ddt_phys) + iommu->ddt_root = devm_ioremap(iommu->dev, + iommu->ddt_phys, PAGE_SIZE); + if (iommu->ddt_root) + memset(iommu->ddt_root, 0, PAGE_SIZE); + } + + if (!iommu->ddt_root) { + iommu->ddt_root = riscv_iommu_get_pages(iommu, 0); + iommu->ddt_phys = __pa(iommu->ddt_root); + } + + if (!iommu->ddt_root) + return -ENOMEM; + + return 0; +} + +/* + * Discover supported DDT modes starting from requested value, + * configure DDTP register with accepted mode and root DDT address. + * Accepted iommu->ddt_mode is updated on success. + */ +static int riscv_iommu_iodir_set_mode(struct riscv_iommu_device *iommu, + unsigned int ddtp_mode) +{ + struct device *dev = iommu->dev; + u64 ddtp, rq_ddtp; + unsigned int mode, rq_mode = ddtp_mode; + struct riscv_iommu_command cmd; + + ddtp = riscv_iommu_read_ddtp(iommu); + if (ddtp & RISCV_IOMMU_DDTP_BUSY) + return -EBUSY; + + /* Disallow state transition from xLVL to xLVL. */ + mode = FIELD_GET(RISCV_IOMMU_DDTP_IOMMU_MODE, ddtp); + if (mode != RISCV_IOMMU_DDTP_IOMMU_MODE_BARE && + mode != RISCV_IOMMU_DDTP_IOMMU_MODE_OFF && + rq_mode != RISCV_IOMMU_DDTP_IOMMU_MODE_BARE && + rq_mode != RISCV_IOMMU_DDTP_IOMMU_MODE_OFF) + return -EINVAL; + + do { + rq_ddtp = FIELD_PREP(RISCV_IOMMU_DDTP_IOMMU_MODE, rq_mode); + if (rq_mode > RISCV_IOMMU_DDTP_IOMMU_MODE_BARE) + rq_ddtp |= phys_to_ppn(iommu->ddt_phys); + + riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_DDTP, rq_ddtp); + ddtp = riscv_iommu_read_ddtp(iommu); + if (ddtp & RISCV_IOMMU_DDTP_BUSY) { + dev_err(dev, "timeout when setting ddtp (ddt mode: %u, read: %llx)\n", + rq_mode, ddtp); + return -EBUSY; + } + + /* Verify IOMMU hardware accepts new DDTP config. */ + mode = FIELD_GET(RISCV_IOMMU_DDTP_IOMMU_MODE, ddtp); + + if (rq_mode == mode) + break; + + /* Hardware mandatory DDTP mode has not been accepted. */ + if (rq_mode < RISCV_IOMMU_DDTP_IOMMU_MODE_1LVL && rq_ddtp != ddtp) { + dev_err(dev, "DDTP update failed hw: %llx vs %llx\n", + ddtp, rq_ddtp); + return -EINVAL; + } + + /* + * Mode field is WARL, an IOMMU may support a subset of + * directory table levels in which case if we tried to set + * an unsupported number of levels we'll readback either + * a valid xLVL or off/bare. If we got off/bare, try again + * with a smaller xLVL. + */ + if (mode < RISCV_IOMMU_DDTP_IOMMU_MODE_1LVL && + rq_mode > RISCV_IOMMU_DDTP_IOMMU_MODE_1LVL) { + dev_dbg(dev, "DDTP hw mode %u vs %u\n", mode, rq_mode); + rq_mode--; + continue; + } + + /* + * We tried all supported modes and IOMMU hardware failed to + * accept new settings, something went very wrong since off/bare + * and at least one xLVL must be supported. + */ + dev_err(dev, "DDTP hw mode %u, failed to set %u\n", + mode, ddtp_mode); + return -EINVAL; + } while (1); + + iommu->ddt_mode = mode; + if (mode != ddtp_mode) + dev_dbg(dev, "DDTP hw mode %u, requested %u\n", mode, ddtp_mode); + + /* Invalidate device context cache */ + riscv_iommu_cmd_iodir_inval_ddt(&cmd); + riscv_iommu_cmd_send(iommu, &cmd); + + /* Invalidate address translation cache */ + riscv_iommu_cmd_inval_vma(&cmd); + riscv_iommu_cmd_send(iommu, &cmd); + + /* IOFENCE.C */ + riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT); + + return 0; +} + +/* This struct contains protection domain specific IOMMU driver data. */ +struct riscv_iommu_domain { + struct iommu_domain domain; + struct list_head bonds; + spinlock_t lock; /* protect bonds list updates. */ + int pscid; + bool amo_enabled; + int numa_node; + unsigned int pgd_mode; + unsigned long *pgd_root; +}; + +#define iommu_domain_to_riscv(iommu_domain) \ + container_of(iommu_domain, struct riscv_iommu_domain, domain) + +/* Private IOMMU data for managed devices, dev_iommu_priv_* */ +struct riscv_iommu_info { + struct riscv_iommu_domain *domain; +}; + +/* + * Linkage between an iommu_domain and attached devices. + * + * Protection domain requiring IOATC and DevATC translation cache invalidations, + * should be linked to attached devices using a riscv_iommu_bond structure. + * Devices should be linked to the domain before first use and unlinked after + * the translations from the referenced protection domain can no longer be used. + * Blocking and identity domains are not tracked here, as the IOMMU hardware + * does not cache negative and/or identity (BARE mode) translations, and DevATC + * is disabled for those protection domains. + * + * The device pointer and IOMMU data remain stable in the bond struct after + * _probe_device() where it's attached to the managed IOMMU, up to the + * completion of the _release_device() call. The release of the bond structure + * is synchronized with the device release. + */ +struct riscv_iommu_bond { + struct list_head list; + struct rcu_head rcu; + struct device *dev; +}; + +static int riscv_iommu_bond_link(struct riscv_iommu_domain *domain, + struct device *dev) +{ + struct riscv_iommu_device *iommu = dev_to_iommu(dev); + struct riscv_iommu_bond *bond; + struct list_head *bonds; + + bond = kzalloc(sizeof(*bond), GFP_KERNEL); + if (!bond) + return -ENOMEM; + bond->dev = dev; + + /* + * List of devices attached to the domain is arranged based on + * managed IOMMU device. + */ + + spin_lock(&domain->lock); + list_for_each(bonds, &domain->bonds) + if (dev_to_iommu(list_entry(bonds, struct riscv_iommu_bond, list)->dev) == iommu) + break; + list_add_rcu(&bond->list, bonds); + spin_unlock(&domain->lock); + + /* Synchronize with riscv_iommu_iotlb_inval() sequence. See comment below. */ + smp_mb(); + + return 0; +} + +static void riscv_iommu_bond_unlink(struct riscv_iommu_domain *domain, + struct device *dev) +{ + struct riscv_iommu_device *iommu = dev_to_iommu(dev); + struct riscv_iommu_bond *bond, *found = NULL; + struct riscv_iommu_command cmd; + int count = 0; + + if (!domain) + return; + + spin_lock(&domain->lock); + list_for_each_entry(bond, &domain->bonds, list) { + if (found && count) + break; + else if (bond->dev == dev) + found = bond; + else if (dev_to_iommu(bond->dev) == iommu) + count++; + } + if (found) + list_del_rcu(&found->list); + spin_unlock(&domain->lock); + kfree_rcu(found, rcu); + + /* + * If this was the last bond between this domain and the IOMMU + * invalidate all cached entries for domain's PSCID. + */ + if (!count) { + riscv_iommu_cmd_inval_vma(&cmd); + riscv_iommu_cmd_inval_set_pscid(&cmd, domain->pscid); + riscv_iommu_cmd_send(iommu, &cmd); + + riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT); + } +} + +/* + * Send IOTLB.INVAL for whole address space for ranges larger than 2MB. + * This limit will be replaced with range invalidations, if supported by + * the hardware, when RISC-V IOMMU architecture specification update for + * range invalidations update will be available. + */ +#define RISCV_IOMMU_IOTLB_INVAL_LIMIT (2 << 20) + +static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain, + unsigned long start, unsigned long end) +{ + struct riscv_iommu_bond *bond; + struct riscv_iommu_device *iommu, *prev; + struct riscv_iommu_command cmd; + unsigned long len = end - start + 1; + unsigned long iova; + + /* + * For each IOMMU linked with this protection domain (via bonds->dev), + * an IOTLB invaliation command will be submitted and executed. + * + * Possbile race with domain attach flow is handled by sequencing + * bond creation - riscv_iommu_bond_link(), and device directory + * update - riscv_iommu_iodir_update(). + * + * PTE Update / IOTLB Inval Device attach & directory update + * -------------------------- -------------------------- + * update page table entries add dev to the bond list + * FENCE RW,RW FENCE RW,RW + * For all IOMMUs: (can be empty) Update FSC/PSCID + * FENCE IOW,IOW FENCE IOW,IOW + * IOTLB.INVAL IODIR.INVAL + * IOFENCE.C + * + * If bond list is not updated with new device, directory context will + * be configured with already valid page table content. If an IOMMU is + * linked to the protection domain it will receive invalidation + * requests for updated page table entries. + */ + smp_mb(); + + rcu_read_lock(); + + prev = NULL; + list_for_each_entry_rcu(bond, &domain->bonds, list) { + iommu = dev_to_iommu(bond->dev); + + /* + * IOTLB invalidation request can be safely omitted if already sent + * to the IOMMU for the same PSCID, and with domain->bonds list + * arranged based on the device's IOMMU, it's sufficient to check + * last device the invalidation was sent to. + */ + if (iommu == prev) + continue; + + riscv_iommu_cmd_inval_vma(&cmd); + riscv_iommu_cmd_inval_set_pscid(&cmd, domain->pscid); + if (len && len < RISCV_IOMMU_IOTLB_INVAL_LIMIT) { + for (iova = start; iova < end; iova += PAGE_SIZE) { + riscv_iommu_cmd_inval_set_addr(&cmd, iova); + riscv_iommu_cmd_send(iommu, &cmd); + } + } else { + riscv_iommu_cmd_send(iommu, &cmd); + } + prev = iommu; + } + + prev = NULL; + list_for_each_entry_rcu(bond, &domain->bonds, list) { + iommu = dev_to_iommu(bond->dev); + if (iommu == prev) + continue; + + riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT); + prev = iommu; + } + rcu_read_unlock(); +} + +#define RISCV_IOMMU_FSC_BARE 0 + +/* + * Update IODIR for the device. + * + * During the execution of riscv_iommu_probe_device(), IODIR entries are + * allocated for the device's identifiers. Device context invalidation + * becomes necessary only if one of the updated entries was previously + * marked as valid, given that invalid device context entries are not + * cached by the IOMMU hardware. + * In this implementation, updating a valid device context while the + * device is not quiesced might be disruptive, potentially causing + * interim translation faults. + */ +static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu, + struct device *dev, u64 fsc, u64 ta) +{ + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct riscv_iommu_dc *dc; + struct riscv_iommu_command cmd; + bool sync_required = false; + u64 tc; + int i; + + for (i = 0; i < fwspec->num_ids; i++) { + dc = riscv_iommu_get_dc(iommu, fwspec->ids[i]); + tc = READ_ONCE(dc->tc); + if (!(tc & RISCV_IOMMU_DC_TC_V)) + continue; + + WRITE_ONCE(dc->tc, tc & ~RISCV_IOMMU_DC_TC_V); + + /* Invalidate device context cached values */ + riscv_iommu_cmd_iodir_inval_ddt(&cmd); + riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]); + riscv_iommu_cmd_send(iommu, &cmd); + sync_required = true; + } + + if (sync_required) + riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT); + + /* + * For device context with DC_TC_PDTV = 0, translation attributes valid bit + * is stored as DC_TC_V bit (both sharing the same location at BIT(0)). + */ + for (i = 0; i < fwspec->num_ids; i++) { + dc = riscv_iommu_get_dc(iommu, fwspec->ids[i]); + tc = READ_ONCE(dc->tc); + tc |= ta & RISCV_IOMMU_DC_TC_V; + + WRITE_ONCE(dc->fsc, fsc); + WRITE_ONCE(dc->ta, ta & RISCV_IOMMU_PC_TA_PSCID); + /* Update device context, write TC.V as the last step. */ + dma_wmb(); + WRITE_ONCE(dc->tc, tc); + + /* Invalidate device context after update */ + riscv_iommu_cmd_iodir_inval_ddt(&cmd); + riscv_iommu_cmd_iodir_set_did(&cmd, fwspec->ids[i]); + riscv_iommu_cmd_send(iommu, &cmd); + } + + riscv_iommu_cmd_sync(iommu, RISCV_IOMMU_IOTINVAL_TIMEOUT); +} + +/* + * IOVA page translation tree management. + */ + +static void riscv_iommu_iotlb_flush_all(struct iommu_domain *iommu_domain) +{ + struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); + + riscv_iommu_iotlb_inval(domain, 0, ULONG_MAX); +} + +static void riscv_iommu_iotlb_sync(struct iommu_domain *iommu_domain, + struct iommu_iotlb_gather *gather) +{ + struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); + + riscv_iommu_iotlb_inval(domain, gather->start, gather->end); +} + +#define PT_SHIFT (PAGE_SHIFT - ilog2(sizeof(pte_t))) + +#define _io_pte_present(pte) ((pte) & (_PAGE_PRESENT | _PAGE_PROT_NONE)) +#define _io_pte_leaf(pte) ((pte) & _PAGE_LEAF) +#define _io_pte_none(pte) ((pte) == 0) +#define _io_pte_entry(pn, prot) ((_PAGE_PFN_MASK & ((pn) << _PAGE_PFN_SHIFT)) | (prot)) + +static void riscv_iommu_pte_free(struct riscv_iommu_domain *domain, + unsigned long pte, struct list_head *freelist) +{ + unsigned long *ptr; + int i; + + if (!_io_pte_present(pte) || _io_pte_leaf(pte)) + return; + + ptr = (unsigned long *)pfn_to_virt(__page_val_to_pfn(pte)); + + /* Recursively free all sub page table pages */ + for (i = 0; i < PTRS_PER_PTE; i++) { + pte = READ_ONCE(ptr[i]); + if (!_io_pte_none(pte) && cmpxchg_relaxed(ptr + i, pte, 0) == pte) + riscv_iommu_pte_free(domain, pte, freelist); + } + + if (freelist) + list_add_tail(&virt_to_page(ptr)->lru, freelist); + else + iommu_free_page(ptr); +} + +static unsigned long *riscv_iommu_pte_alloc(struct riscv_iommu_domain *domain, + unsigned long iova, size_t pgsize, + gfp_t gfp) +{ + unsigned long *ptr = domain->pgd_root; + unsigned long pte, old; + int level = domain->pgd_mode - RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39 + 2; + void *addr; + + do { + const int shift = PAGE_SHIFT + PT_SHIFT * level; + + ptr += ((iova >> shift) & (PTRS_PER_PTE - 1)); + /* + * Note: returned entry might be a non-leaf if there was + * existing mapping with smaller granularity. Up to the caller + * to replace and invalidate. + */ + if (((size_t)1 << shift) == pgsize) + return ptr; +pte_retry: + pte = READ_ONCE(*ptr); + /* + * This is very likely incorrect as we should not be adding + * new mapping with smaller granularity on top + * of existing 2M/1G mapping. Fail. + */ + if (_io_pte_present(pte) && _io_pte_leaf(pte)) + return NULL; + /* + * Non-leaf entry is missing, allocate and try to add to the + * page table. This might race with other mappings, retry. + */ + if (_io_pte_none(pte)) { + addr = iommu_alloc_page_node(domain->numa_node, gfp); + if (!addr) + return NULL; + old = pte; + pte = _io_pte_entry(virt_to_pfn(addr), _PAGE_TABLE); + if (cmpxchg_relaxed(ptr, old, pte) != old) { + iommu_free_page(addr); + goto pte_retry; + } + } + ptr = (unsigned long *)pfn_to_virt(__page_val_to_pfn(pte)); + } while (level-- > 0); + + return NULL; +} + +static unsigned long *riscv_iommu_pte_fetch(struct riscv_iommu_domain *domain, + unsigned long iova, size_t *pte_pgsize) +{ + unsigned long *ptr = domain->pgd_root; + unsigned long pte; + int level = domain->pgd_mode - RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39 + 2; + + do { + const int shift = PAGE_SHIFT + PT_SHIFT * level; + + ptr += ((iova >> shift) & (PTRS_PER_PTE - 1)); + pte = READ_ONCE(*ptr); + if (_io_pte_present(pte) && _io_pte_leaf(pte)) { + *pte_pgsize = (size_t)1 << shift; + return ptr; + } + if (_io_pte_none(pte)) + return NULL; + ptr = (unsigned long *)pfn_to_virt(__page_val_to_pfn(pte)); + } while (level-- > 0); + + return NULL; +} + +static int riscv_iommu_map_pages(struct iommu_domain *iommu_domain, + unsigned long iova, phys_addr_t phys, + size_t pgsize, size_t pgcount, int prot, + gfp_t gfp, size_t *mapped) +{ + struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); + size_t size = 0; + unsigned long *ptr; + unsigned long pte, old, pte_prot; + int rc = 0; + LIST_HEAD(freelist); + + if (!(prot & IOMMU_WRITE)) + pte_prot = _PAGE_BASE | _PAGE_READ; + else if (domain->amo_enabled) + pte_prot = _PAGE_BASE | _PAGE_READ | _PAGE_WRITE; + else + pte_prot = _PAGE_BASE | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY; + + while (pgcount) { + ptr = riscv_iommu_pte_alloc(domain, iova, pgsize, gfp); + if (!ptr) { + rc = -ENOMEM; + break; + } + + old = READ_ONCE(*ptr); + pte = _io_pte_entry(phys_to_pfn(phys), pte_prot); + if (cmpxchg_relaxed(ptr, old, pte) != old) + continue; + + riscv_iommu_pte_free(domain, old, &freelist); + + size += pgsize; + iova += pgsize; + phys += pgsize; + --pgcount; + } + + *mapped = size; + + if (!list_empty(&freelist)) { + /* + * In 1.0 spec version, the smallest scope we can use to + * invalidate all levels of page table (i.e. leaf and non-leaf) + * is an invalidate-all-PSCID IOTINVAL.VMA with AV=0. + * This will be updated with hardware support for + * capability.NL (non-leaf) IOTINVAL command. + */ + riscv_iommu_iotlb_inval(domain, 0, ULONG_MAX); + iommu_put_pages_list(&freelist); + } + + return rc; +} + +static size_t riscv_iommu_unmap_pages(struct iommu_domain *iommu_domain, + unsigned long iova, size_t pgsize, + size_t pgcount, + struct iommu_iotlb_gather *gather) +{ + struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); + size_t size = pgcount << __ffs(pgsize); + unsigned long *ptr, old; + size_t unmapped = 0; + size_t pte_size; + + while (unmapped < size) { + ptr = riscv_iommu_pte_fetch(domain, iova, &pte_size); + if (!ptr) + return unmapped; + + /* partial unmap is not allowed, fail. */ + if (iova & (pte_size - 1)) + return unmapped; + + old = READ_ONCE(*ptr); + if (cmpxchg_relaxed(ptr, old, 0) != old) + continue; + + iommu_iotlb_gather_add_page(&domain->domain, gather, iova, + pte_size); + + iova += pte_size; + unmapped += pte_size; + } + + return unmapped; +} + +static phys_addr_t riscv_iommu_iova_to_phys(struct iommu_domain *iommu_domain, + dma_addr_t iova) +{ + struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); + unsigned long pte_size; + unsigned long *ptr; + + ptr = riscv_iommu_pte_fetch(domain, iova, &pte_size); + if (_io_pte_none(*ptr) || !_io_pte_present(*ptr)) + return 0; + + return pfn_to_phys(__page_val_to_pfn(*ptr)) | (iova & (pte_size - 1)); +} + +static void riscv_iommu_free_paging_domain(struct iommu_domain *iommu_domain) +{ + struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); + const unsigned long pfn = virt_to_pfn(domain->pgd_root); + + WARN_ON(!list_empty(&domain->bonds)); + + if ((int)domain->pscid > 0) + ida_free(&riscv_iommu_pscids, domain->pscid); + + riscv_iommu_pte_free(domain, _io_pte_entry(pfn, _PAGE_TABLE), NULL); + kfree(domain); +} + +static bool riscv_iommu_pt_supported(struct riscv_iommu_device *iommu, int pgd_mode) +{ + switch (pgd_mode) { + case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39: + return iommu->caps & RISCV_IOMMU_CAPABILITIES_SV39; + + case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48: + return iommu->caps & RISCV_IOMMU_CAPABILITIES_SV48; + + case RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57: + return iommu->caps & RISCV_IOMMU_CAPABILITIES_SV57; + } + return false; +} + +static int riscv_iommu_attach_paging_domain(struct iommu_domain *iommu_domain, + struct device *dev) +{ + struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); + struct riscv_iommu_device *iommu = dev_to_iommu(dev); + struct riscv_iommu_info *info = dev_iommu_priv_get(dev); + u64 fsc, ta; + + if (!riscv_iommu_pt_supported(iommu, domain->pgd_mode)) + return -ENODEV; + + fsc = FIELD_PREP(RISCV_IOMMU_PC_FSC_MODE, domain->pgd_mode) | + FIELD_PREP(RISCV_IOMMU_PC_FSC_PPN, virt_to_pfn(domain->pgd_root)); + ta = FIELD_PREP(RISCV_IOMMU_PC_TA_PSCID, domain->pscid) | + RISCV_IOMMU_PC_TA_V; + + if (riscv_iommu_bond_link(domain, dev)) + return -ENOMEM; + + riscv_iommu_iodir_update(iommu, dev, fsc, ta); + riscv_iommu_bond_unlink(info->domain, dev); + info->domain = domain; + + return 0; +} + +static const struct iommu_domain_ops riscv_iommu_paging_domain_ops = { + .attach_dev = riscv_iommu_attach_paging_domain, + .free = riscv_iommu_free_paging_domain, + .map_pages = riscv_iommu_map_pages, + .unmap_pages = riscv_iommu_unmap_pages, + .iova_to_phys = riscv_iommu_iova_to_phys, + .iotlb_sync = riscv_iommu_iotlb_sync, + .flush_iotlb_all = riscv_iommu_iotlb_flush_all, +}; + +static struct iommu_domain *riscv_iommu_alloc_paging_domain(struct device *dev) +{ + struct riscv_iommu_domain *domain; + struct riscv_iommu_device *iommu; + unsigned int pgd_mode; + dma_addr_t va_mask; + int va_bits; + + iommu = dev_to_iommu(dev); + if (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV57) { + pgd_mode = RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV57; + va_bits = 57; + } else if (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV48) { + pgd_mode = RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV48; + va_bits = 48; + } else if (iommu->caps & RISCV_IOMMU_CAPABILITIES_SV39) { + pgd_mode = RISCV_IOMMU_DC_FSC_IOSATP_MODE_SV39; + va_bits = 39; + } else { + dev_err(dev, "cannot find supported page table mode\n"); + return ERR_PTR(-ENODEV); + } + + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (!domain) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD_RCU(&domain->bonds); + spin_lock_init(&domain->lock); + domain->numa_node = dev_to_node(iommu->dev); + domain->amo_enabled = !!(iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD); + domain->pgd_mode = pgd_mode; + domain->pgd_root = iommu_alloc_page_node(domain->numa_node, + GFP_KERNEL_ACCOUNT); + if (!domain->pgd_root) { + kfree(domain); + return ERR_PTR(-ENOMEM); + } + + domain->pscid = ida_alloc_range(&riscv_iommu_pscids, 1, + RISCV_IOMMU_MAX_PSCID, GFP_KERNEL); + if (domain->pscid < 0) { + iommu_free_page(domain->pgd_root); + kfree(domain); + return ERR_PTR(-ENOMEM); + } + + /* + * Note: RISC-V Privilege spec mandates that virtual addresses + * need to be sign-extended, so if (VA_BITS - 1) is set, all + * bits >= VA_BITS need to also be set or else we'll get a + * page fault. However the code that creates the mappings + * above us (e.g. iommu_dma_alloc_iova()) won't do that for us + * for now, so we'll end up with invalid virtual addresses + * to map. As a workaround until we get this sorted out + * limit the available virtual addresses to VA_BITS - 1. + */ + va_mask = DMA_BIT_MASK(va_bits - 1); + + domain->domain.geometry.aperture_start = 0; + domain->domain.geometry.aperture_end = va_mask; + domain->domain.geometry.force_aperture = true; + domain->domain.pgsize_bitmap = va_mask & (SZ_4K | SZ_2M | SZ_1G | SZ_512G); + + domain->domain.ops = &riscv_iommu_paging_domain_ops; + + return &domain->domain; +} + +static int riscv_iommu_attach_blocking_domain(struct iommu_domain *iommu_domain, + struct device *dev) +{ + struct riscv_iommu_device *iommu = dev_to_iommu(dev); + struct riscv_iommu_info *info = dev_iommu_priv_get(dev); + + /* Make device context invalid, translation requests will fault w/ #258 */ + riscv_iommu_iodir_update(iommu, dev, RISCV_IOMMU_FSC_BARE, 0); + riscv_iommu_bond_unlink(info->domain, dev); + info->domain = NULL; + + return 0; +} + +static struct iommu_domain riscv_iommu_blocking_domain = { + .type = IOMMU_DOMAIN_BLOCKED, + .ops = &(const struct iommu_domain_ops) { + .attach_dev = riscv_iommu_attach_blocking_domain, + } +}; + +static int riscv_iommu_attach_identity_domain(struct iommu_domain *iommu_domain, + struct device *dev) +{ + struct riscv_iommu_device *iommu = dev_to_iommu(dev); + struct riscv_iommu_info *info = dev_iommu_priv_get(dev); + + riscv_iommu_iodir_update(iommu, dev, RISCV_IOMMU_FSC_BARE, RISCV_IOMMU_PC_TA_V); + riscv_iommu_bond_unlink(info->domain, dev); + info->domain = NULL; + + return 0; +} + +static struct iommu_domain riscv_iommu_identity_domain = { + .type = IOMMU_DOMAIN_IDENTITY, + .ops = &(const struct iommu_domain_ops) { + .attach_dev = riscv_iommu_attach_identity_domain, + } +}; + +static struct iommu_group *riscv_iommu_device_group(struct device *dev) +{ + if (dev_is_pci(dev)) + return pci_device_group(dev); + return generic_device_group(dev); +} + +static int riscv_iommu_of_xlate(struct device *dev, const struct of_phandle_args *args) +{ + return iommu_fwspec_add_ids(dev, args->args, 1); +} + +static struct iommu_device *riscv_iommu_probe_device(struct device *dev) +{ + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + struct riscv_iommu_device *iommu; + struct riscv_iommu_info *info; + struct riscv_iommu_dc *dc; + u64 tc; + int i; + + if (!fwspec || !fwspec->iommu_fwnode->dev || !fwspec->num_ids) + return ERR_PTR(-ENODEV); + + iommu = dev_get_drvdata(fwspec->iommu_fwnode->dev); + if (!iommu) + return ERR_PTR(-ENODEV); + + /* + * IOMMU hardware operating in fail-over BARE mode will provide + * identity translation for all connected devices anyway... + */ + if (iommu->ddt_mode <= RISCV_IOMMU_DDTP_IOMMU_MODE_BARE) + return ERR_PTR(-ENODEV); + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + /* + * Allocate and pre-configure device context entries in + * the device directory. Do not mark the context valid yet. + */ + tc = 0; + if (iommu->caps & RISCV_IOMMU_CAPABILITIES_AMO_HWAD) + tc |= RISCV_IOMMU_DC_TC_SADE; + for (i = 0; i < fwspec->num_ids; i++) { + dc = riscv_iommu_get_dc(iommu, fwspec->ids[i]); + if (!dc) { + kfree(info); + return ERR_PTR(-ENODEV); + } + if (READ_ONCE(dc->tc) & RISCV_IOMMU_DC_TC_V) + dev_warn(dev, "already attached to IOMMU device directory\n"); + WRITE_ONCE(dc->tc, tc); + } + + dev_iommu_priv_set(dev, info); + + return &iommu->iommu; +} + +static void riscv_iommu_release_device(struct device *dev) +{ + struct riscv_iommu_info *info = dev_iommu_priv_get(dev); + + kfree_rcu_mightsleep(info); +} + +static const struct iommu_ops riscv_iommu_ops = { + .pgsize_bitmap = SZ_4K, + .of_xlate = riscv_iommu_of_xlate, + .identity_domain = &riscv_iommu_identity_domain, + .blocked_domain = &riscv_iommu_blocking_domain, + .release_domain = &riscv_iommu_blocking_domain, + .domain_alloc_paging = riscv_iommu_alloc_paging_domain, + .device_group = riscv_iommu_device_group, + .probe_device = riscv_iommu_probe_device, + .release_device = riscv_iommu_release_device, +}; + +static int riscv_iommu_init_check(struct riscv_iommu_device *iommu) +{ + u64 ddtp; + + /* + * Make sure the IOMMU is switched off or in pass-through mode during + * regular boot flow and disable translation when we boot into a kexec + * kernel and the previous kernel left them enabled. + */ + ddtp = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_DDTP); + if (ddtp & RISCV_IOMMU_DDTP_BUSY) + return -EBUSY; + + if (FIELD_GET(RISCV_IOMMU_DDTP_IOMMU_MODE, ddtp) > + RISCV_IOMMU_DDTP_IOMMU_MODE_BARE) { + if (!is_kdump_kernel()) + return -EBUSY; + riscv_iommu_disable(iommu); + } + + /* Configure accesses to in-memory data structures for CPU-native byte order. */ + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) != + !!(iommu->fctl & RISCV_IOMMU_FCTL_BE)) { + if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_END)) + return -EINVAL; + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_FCTL, + iommu->fctl ^ RISCV_IOMMU_FCTL_BE); + iommu->fctl = riscv_iommu_readl(iommu, RISCV_IOMMU_REG_FCTL); + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) != + !!(iommu->fctl & RISCV_IOMMU_FCTL_BE)) + return -EINVAL; + } + + /* + * Distribute interrupt vectors, always use first vector for CIV. + * At least one interrupt is required. Read back and verify. + */ + if (!iommu->irqs_count) + return -EINVAL; + + iommu->icvec = FIELD_PREP(RISCV_IOMMU_ICVEC_FIV, 1 % iommu->irqs_count) | + FIELD_PREP(RISCV_IOMMU_ICVEC_PIV, 2 % iommu->irqs_count) | + FIELD_PREP(RISCV_IOMMU_ICVEC_PMIV, 3 % iommu->irqs_count); + riscv_iommu_writeq(iommu, RISCV_IOMMU_REG_ICVEC, iommu->icvec); + iommu->icvec = riscv_iommu_readq(iommu, RISCV_IOMMU_REG_ICVEC); + if (max(max(FIELD_GET(RISCV_IOMMU_ICVEC_CIV, iommu->icvec), + FIELD_GET(RISCV_IOMMU_ICVEC_FIV, iommu->icvec)), + max(FIELD_GET(RISCV_IOMMU_ICVEC_PIV, iommu->icvec), + FIELD_GET(RISCV_IOMMU_ICVEC_PMIV, iommu->icvec))) >= iommu->irqs_count) + return -EINVAL; + + return 0; +} + +void riscv_iommu_remove(struct riscv_iommu_device *iommu) +{ + iommu_device_unregister(&iommu->iommu); + iommu_device_sysfs_remove(&iommu->iommu); + riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF); + riscv_iommu_queue_disable(&iommu->cmdq); + riscv_iommu_queue_disable(&iommu->fltq); +} + +int riscv_iommu_init(struct riscv_iommu_device *iommu) +{ + int rc; + + RISCV_IOMMU_QUEUE_INIT(&iommu->cmdq, CQ); + RISCV_IOMMU_QUEUE_INIT(&iommu->fltq, FQ); + + rc = riscv_iommu_init_check(iommu); + if (rc) + return dev_err_probe(iommu->dev, rc, "unexpected device state\n"); + + rc = riscv_iommu_iodir_alloc(iommu); + if (rc) + return rc; + + rc = riscv_iommu_queue_alloc(iommu, &iommu->cmdq, + sizeof(struct riscv_iommu_command)); + if (rc) + return rc; + + rc = riscv_iommu_queue_alloc(iommu, &iommu->fltq, + sizeof(struct riscv_iommu_fq_record)); + if (rc) + return rc; + + rc = riscv_iommu_queue_enable(iommu, &iommu->cmdq, riscv_iommu_cmdq_process); + if (rc) + return rc; + + rc = riscv_iommu_queue_enable(iommu, &iommu->fltq, riscv_iommu_fltq_process); + if (rc) + goto err_queue_disable; + + rc = riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_MAX); + if (rc) + goto err_queue_disable; + + rc = iommu_device_sysfs_add(&iommu->iommu, NULL, NULL, "riscv-iommu@%s", + dev_name(iommu->dev)); + if (rc) { + dev_err_probe(iommu->dev, rc, "cannot register sysfs interface\n"); + goto err_iodir_off; + } + + rc = iommu_device_register(&iommu->iommu, &riscv_iommu_ops, iommu->dev); + if (rc) { + dev_err_probe(iommu->dev, rc, "cannot register iommu interface\n"); + goto err_remove_sysfs; + } + + return 0; + +err_remove_sysfs: + iommu_device_sysfs_remove(&iommu->iommu); +err_iodir_off: + riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF); +err_queue_disable: + riscv_iommu_queue_disable(&iommu->fltq); + riscv_iommu_queue_disable(&iommu->cmdq); + return rc; +} diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h new file mode 100644 index 00000000000000..b1c4664542b48b --- /dev/null +++ b/drivers/iommu/riscv/iommu.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright © 2022-2024 Rivos Inc. + * Copyright © 2023 FORTH-ICS/CARV + * + * Authors + * Tomasz Jeznach + * Nick Kossifidis + */ + +#ifndef _RISCV_IOMMU_H_ +#define _RISCV_IOMMU_H_ + +#include +#include +#include + +#include "iommu-bits.h" + +struct riscv_iommu_device; + +struct riscv_iommu_queue { + atomic_t prod; /* unbounded producer allocation index */ + atomic_t head; /* unbounded shadow ring buffer consumer index */ + atomic_t tail; /* unbounded shadow ring buffer producer index */ + unsigned int mask; /* index mask, queue length - 1 */ + unsigned int irq; /* allocated interrupt number */ + struct riscv_iommu_device *iommu; /* iommu device handling the queue when active */ + void *base; /* ring buffer kernel pointer */ + dma_addr_t phys; /* ring buffer physical address */ + u16 qbr; /* base register offset, head and tail reference */ + u16 qcr; /* control and status register offset */ + u8 qid; /* queue identifier, same as RISCV_IOMMU_INTR_XX */ +}; + +struct riscv_iommu_device { + /* iommu core interface */ + struct iommu_device iommu; + + /* iommu hardware */ + struct device *dev; + + /* hardware control register space */ + void __iomem *reg; + + /* supported and enabled hardware capabilities */ + u64 caps; + u32 fctl; + + /* available interrupt numbers, MSI or WSI */ + unsigned int irqs[RISCV_IOMMU_INTR_COUNT]; + unsigned int irqs_count; + unsigned int icvec; + + /* hardware queues */ + struct riscv_iommu_queue cmdq; + struct riscv_iommu_queue fltq; + + /* device directory */ + unsigned int ddt_mode; + dma_addr_t ddt_phys; + u64 *ddt_root; +}; + +int riscv_iommu_init(struct riscv_iommu_device *iommu); +void riscv_iommu_remove(struct riscv_iommu_device *iommu); + +#define riscv_iommu_readl(iommu, addr) \ + readl_relaxed((iommu)->reg + (addr)) + +#define riscv_iommu_readq(iommu, addr) \ + readq_relaxed((iommu)->reg + (addr)) + +#define riscv_iommu_writel(iommu, addr, val) \ + writel_relaxed((val), (iommu)->reg + (addr)) + +#define riscv_iommu_writeq(iommu, addr, val) \ + writeq_relaxed((val), (iommu)->reg + (addr)) + +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \ + readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \ + delay_us, timeout_us) + +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \ + readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \ + delay_us, timeout_us) + +#endif diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index d8eaa7ea380bb0..fbdeded3d48b59 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -33,6 +33,8 @@ struct s390_domain { struct rcu_head rcu; }; +static struct iommu_domain blocking_domain; + static inline unsigned int calc_rtx(dma_addr_t ptr) { return ((unsigned long)ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK; @@ -369,20 +371,36 @@ static void s390_domain_free(struct iommu_domain *domain) call_rcu(&s390_domain->rcu, s390_iommu_rcu_free_domain); } -static void s390_iommu_detach_device(struct iommu_domain *domain, - struct device *dev) +static void zdev_s390_domain_update(struct zpci_dev *zdev, + struct iommu_domain *domain) +{ + unsigned long flags; + + spin_lock_irqsave(&zdev->dom_lock, flags); + zdev->s390_domain = domain; + spin_unlock_irqrestore(&zdev->dom_lock, flags); +} + +static int blocking_domain_attach_device(struct iommu_domain *domain, + struct device *dev) { - struct s390_domain *s390_domain = to_s390_domain(domain); struct zpci_dev *zdev = to_zpci_dev(dev); + struct s390_domain *s390_domain; unsigned long flags; + if (zdev->s390_domain->type == IOMMU_DOMAIN_BLOCKED) + return 0; + + s390_domain = to_s390_domain(zdev->s390_domain); spin_lock_irqsave(&s390_domain->list_lock, flags); list_del_rcu(&zdev->iommu_list); spin_unlock_irqrestore(&s390_domain->list_lock, flags); zpci_unregister_ioat(zdev, 0); - zdev->s390_domain = NULL; zdev->dma_table = NULL; + zdev_s390_domain_update(zdev, domain); + + return 0; } static int s390_iommu_attach_device(struct iommu_domain *domain, @@ -401,20 +419,15 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, domain->geometry.aperture_end < zdev->start_dma)) return -EINVAL; - if (zdev->s390_domain) - s390_iommu_detach_device(&zdev->s390_domain->domain, dev); + blocking_domain_attach_device(&blocking_domain, dev); + /* If we fail now DMA remains blocked via blocking domain */ cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, virt_to_phys(s390_domain->dma_table), &status); - /* - * If the device is undergoing error recovery the reset code - * will re-establish the new domain. - */ if (cc && status != ZPCI_PCI_ST_FUNC_NOT_AVAIL) return -EIO; - zdev->dma_table = s390_domain->dma_table; - zdev->s390_domain = s390_domain; + zdev_s390_domain_update(zdev, domain); spin_lock_irqsave(&s390_domain->list_lock, flags); list_add_rcu(&zdev->iommu_list, &s390_domain->devices); @@ -466,19 +479,11 @@ static struct iommu_device *s390_iommu_probe_device(struct device *dev) if (zdev->tlb_refresh) dev->iommu->shadow_on_flush = 1; - return &zdev->iommu_dev; -} + /* Start with DMA blocked */ + spin_lock_init(&zdev->dom_lock); + zdev_s390_domain_update(zdev, &blocking_domain); -static void s390_iommu_release_device(struct device *dev) -{ - struct zpci_dev *zdev = to_zpci_dev(dev); - - /* - * release_device is expected to detach any domain currently attached - * to the device, but keep it attached to other devices in the group. - */ - if (zdev) - s390_iommu_detach_device(&zdev->s390_domain->domain, dev); + return &zdev->iommu_dev; } static int zpci_refresh_all(struct zpci_dev *zdev) @@ -697,9 +702,15 @@ static size_t s390_iommu_unmap_pages(struct iommu_domain *domain, struct zpci_iommu_ctrs *zpci_get_iommu_ctrs(struct zpci_dev *zdev) { - if (!zdev || !zdev->s390_domain) + struct s390_domain *s390_domain; + + lockdep_assert_held(&zdev->dom_lock); + + if (zdev->s390_domain->type == IOMMU_DOMAIN_BLOCKED) return NULL; - return &zdev->s390_domain->ctrs; + + s390_domain = to_s390_domain(zdev->s390_domain); + return &s390_domain->ctrs; } int zpci_init_iommu(struct zpci_dev *zdev) @@ -776,11 +787,19 @@ static int __init s390_iommu_init(void) } subsys_initcall(s390_iommu_init); +static struct iommu_domain blocking_domain = { + .type = IOMMU_DOMAIN_BLOCKED, + .ops = &(const struct iommu_domain_ops) { + .attach_dev = blocking_domain_attach_device, + } +}; + static const struct iommu_ops s390_iommu_ops = { + .blocked_domain = &blocking_domain, + .release_domain = &blocking_domain, .capable = s390_iommu_capable, .domain_alloc_paging = s390_domain_alloc_paging, .probe_device = s390_iommu_probe_device, - .release_device = s390_iommu_release_device, .device_group = generic_device_group, .pgsize_bitmap = SZ_4K, .get_resv_regions = s390_iommu_get_resv_regions, diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c index a2f4ffe6d9491c..941d1f361c8cda 100644 --- a/drivers/iommu/sprd-iommu.c +++ b/drivers/iommu/sprd-iommu.c @@ -531,7 +531,7 @@ static struct platform_driver sprd_iommu_driver = { .suppress_bind_attrs = true, }, .probe = sprd_iommu_probe, - .remove_new = sprd_iommu_remove, + .remove = sprd_iommu_remove, }; module_platform_driver(sprd_iommu_driver); diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index d82bcab233a1b0..9bee02db164391 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -258,6 +258,13 @@ config RENESAS_RZG2L_IRQC Enable support for the Renesas RZ/G2L (and alike SoC) Interrupt Controller for external devices. +config RENESAS_RZV2H_ICU + bool "Renesas RZ/V2H(P) ICU support" if COMPILE_TEST + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN_HIERARCHY + help + Enable support for the Renesas RZ/V2H(P) Interrupt Control Unit (ICU) + config SL28CPLD_INTC bool "Kontron sl28cpld IRQ controller" depends on MFD_SL28CPLD=y || COMPILE_TEST @@ -338,6 +345,7 @@ config KEYSTONE_IRQ config MIPS_GIC bool + select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP select GENERIC_IRQ_IPI if SMP select IRQ_DOMAIN_HIERARCHY select MIPS_CM @@ -407,7 +415,7 @@ config PARTITION_PERCPU config STM32MP_EXTI tristate "STM32MP extended interrupts and event controller" depends on (ARCH_STM32 && !ARM_SINGLE_ARMV7M) || COMPILE_TEST - default y + default ARCH_STM32 && !ARM_SINGLE_ARMV7M select IRQ_DOMAIN_HIERARCHY select GENERIC_IRQ_CHIP help @@ -604,6 +612,18 @@ config STARFIVE_JH8100_INTC If you don't know what to do here, say Y. +config THEAD_C900_ACLINT_SSWI + bool "THEAD C9XX ACLINT S-mode IPI Interrupt Controller" + depends on RISCV + depends on SMP + select IRQ_DOMAIN_HIERARCHY + select GENERIC_IRQ_IPI_MUX + help + This enables support for T-HEAD specific ACLINT SSWI device + support. + + If you don't know what to do here, say Y. + config EXYNOS_IRQ_COMBINER bool "Samsung Exynos IRQ combiner support" if COMPILE_TEST depends on (ARCH_EXYNOS && ARM) || COMPILE_TEST diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index e3679ec2b9f76e..25e9ad29b8c4a5 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o obj-$(CONFIG_RENESAS_RZA1_IRQC) += irq-renesas-rza1.o obj-$(CONFIG_RENESAS_RZG2L_IRQC) += irq-renesas-rzg2l.o +obj-$(CONFIG_RENESAS_RZV2H_ICU) += irq-renesas-rzv2h.o obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o @@ -84,6 +85,7 @@ obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o +obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-intc.o obj-$(CONFIG_STM32MP_EXTI) += irq-stm32mp-exti.o obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o @@ -101,6 +103,7 @@ obj-$(CONFIG_RISCV_APLIC_MSI) += irq-riscv-aplic-msi.o obj-$(CONFIG_RISCV_IMSIC) += irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o obj-$(CONFIG_STARFIVE_JH8100_INTC) += irq-starfive-jh8100-intc.o +obj-$(CONFIG_THEAD_C900_ACLINT_SSWI) += irq-thead-c900-aclint-sswi.o obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o diff --git a/drivers/irqchip/irq-aspeed-intc.c b/drivers/irqchip/irq-aspeed-intc.c new file mode 100644 index 00000000000000..bd3b759b4b2c18 --- /dev/null +++ b/drivers/irqchip/irq-aspeed-intc.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Aspeed Interrupt Controller. + * + * Copyright (C) 2023 ASPEED Technology Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INTC_INT_ENABLE_REG 0x00 +#define INTC_INT_STATUS_REG 0x04 +#define INTC_IRQS_PER_WORD 32 + +struct aspeed_intc_ic { + void __iomem *base; + raw_spinlock_t gic_lock; + raw_spinlock_t intc_lock; + struct irq_domain *irq_domain; +}; + +static void aspeed_intc_ic_irq_handler(struct irq_desc *desc) +{ + struct aspeed_intc_ic *intc_ic = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + + scoped_guard(raw_spinlock, &intc_ic->gic_lock) { + unsigned long bit, status; + + status = readl(intc_ic->base + INTC_INT_STATUS_REG); + for_each_set_bit(bit, &status, INTC_IRQS_PER_WORD) { + generic_handle_domain_irq(intc_ic->irq_domain, bit); + writel(BIT(bit), intc_ic->base + INTC_INT_STATUS_REG); + } + } + + chained_irq_exit(chip, desc); +} + +static void aspeed_intc_irq_mask(struct irq_data *data) +{ + struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); + unsigned int mask = readl(intc_ic->base + INTC_INT_ENABLE_REG) & ~BIT(data->hwirq); + + guard(raw_spinlock)(&intc_ic->intc_lock); + writel(mask, intc_ic->base + INTC_INT_ENABLE_REG); +} + +static void aspeed_intc_irq_unmask(struct irq_data *data) +{ + struct aspeed_intc_ic *intc_ic = irq_data_get_irq_chip_data(data); + unsigned int unmask = readl(intc_ic->base + INTC_INT_ENABLE_REG) | BIT(data->hwirq); + + guard(raw_spinlock)(&intc_ic->intc_lock); + writel(unmask, intc_ic->base + INTC_INT_ENABLE_REG); +} + +static struct irq_chip aspeed_intc_chip = { + .name = "ASPEED INTC", + .irq_mask = aspeed_intc_irq_mask, + .irq_unmask = aspeed_intc_irq_unmask, +}; + +static int aspeed_intc_ic_map_irq_domain(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &aspeed_intc_chip, handle_level_irq); + irq_set_chip_data(irq, domain->host_data); + + return 0; +} + +static const struct irq_domain_ops aspeed_intc_ic_irq_domain_ops = { + .map = aspeed_intc_ic_map_irq_domain, +}; + +static int __init aspeed_intc_ic_of_init(struct device_node *node, + struct device_node *parent) +{ + struct aspeed_intc_ic *intc_ic; + int irq, i, ret = 0; + + intc_ic = kzalloc(sizeof(*intc_ic), GFP_KERNEL); + if (!intc_ic) + return -ENOMEM; + + intc_ic->base = of_iomap(node, 0); + if (!intc_ic->base) { + pr_err("Failed to iomap intc_ic base\n"); + ret = -ENOMEM; + goto err_free_ic; + } + writel(0xffffffff, intc_ic->base + INTC_INT_STATUS_REG); + writel(0x0, intc_ic->base + INTC_INT_ENABLE_REG); + + intc_ic->irq_domain = irq_domain_add_linear(node, INTC_IRQS_PER_WORD, + &aspeed_intc_ic_irq_domain_ops, intc_ic); + if (!intc_ic->irq_domain) { + ret = -ENOMEM; + goto err_iounmap; + } + + raw_spin_lock_init(&intc_ic->gic_lock); + raw_spin_lock_init(&intc_ic->intc_lock); + + /* Check all the irq numbers valid. If not, unmaps all the base and frees the data. */ + for (i = 0; i < of_irq_count(node); i++) { + irq = irq_of_parse_and_map(node, i); + if (!irq) { + pr_err("Failed to get irq number\n"); + ret = -EINVAL; + goto err_iounmap; + } + } + + for (i = 0; i < of_irq_count(node); i++) { + irq = irq_of_parse_and_map(node, i); + irq_set_chained_handler_and_data(irq, aspeed_intc_ic_irq_handler, intc_ic); + } + + return 0; + +err_iounmap: + iounmap(intc_ic->base); +err_free_ic: + kfree(intc_ic); + return ret; +} + +IRQCHIP_DECLARE(ast2700_intc_ic, "aspeed,ast2700-intc-ic", aspeed_intc_ic_of_init); diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index c0f55dc7b050df..e98c2875af9ee8 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -319,6 +319,7 @@ static const struct of_device_id aic5_irq_fixups[] __initconst = { { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, { .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup }, { .compatible = "microchip,sam9x60", .data = sam9x60_aic_irq_fixup }, + { .compatible = "microchip,sam9x7", .data = sam9x60_aic_irq_fixup }, { /* sentinel */ }, }; @@ -405,3 +406,11 @@ static int __init sam9x60_aic5_of_init(struct device_node *node, return aic5_of_init(node, parent, NR_SAM9X60_IRQS); } IRQCHIP_DECLARE(sam9x60_aic5, "microchip,sam9x60-aic", sam9x60_aic5_of_init); + +#define NR_SAM9X7_IRQS 70 + +static int __init sam9x7_aic5_of_init(struct device_node *node, struct device_node *parent) +{ + return aic5_of_init(node, parent, NR_SAM9X7_IRQS); +} +IRQCHIP_DECLARE(sam9x7_aic5, "microchip,sam9x7-aic", sam9x7_aic5_of_init); diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index e5f1059b989fe1..e366257684b58d 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -58,6 +58,7 @@ static struct irq_chip bcm2836_arm_irqchip_timer = { .name = "bcm2836-timer", .irq_mask = bcm2836_arm_irqchip_mask_timer_irq, .irq_unmask = bcm2836_arm_irqchip_unmask_timer_irq, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, }; static void bcm2836_arm_irqchip_mask_pmu_irq(struct irq_data *d) @@ -74,6 +75,7 @@ static struct irq_chip bcm2836_arm_irqchip_pmu = { .name = "bcm2836-pmu", .irq_mask = bcm2836_arm_irqchip_mask_pmu_irq, .irq_unmask = bcm2836_arm_irqchip_unmask_pmu_irq, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, }; static void bcm2836_arm_irqchip_mask_gpu_irq(struct irq_data *d) @@ -88,6 +90,7 @@ static struct irq_chip bcm2836_arm_irqchip_gpu = { .name = "bcm2836-gpu", .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, }; static void bcm2836_arm_irqchip_dummy_op(struct irq_data *d) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 52f625e07658cb..92244cfa04647b 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -12,12 +12,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -27,6 +29,7 @@ #include #include #include +#include #include #include @@ -44,6 +47,7 @@ #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) #define ITS_FLAGS_FORCE_NON_SHAREABLE (1ULL << 3) +#define ITS_FLAGS_WORKAROUND_HISILICON_162100801 (1ULL << 4) #define RD_LOCAL_LPI_ENABLED BIT(0) #define RD_LOCAL_PENDTABLE_PREALLOCATED BIT(1) @@ -61,6 +65,7 @@ static u32 lpi_id_bits; #define LPI_PENDBASE_SZ ALIGN(BIT(LPI_NRBITS) / 8, SZ_64K) static u8 __ro_after_init lpi_prop_prio; +static struct its_node *find_4_1_its(void); /* * Collection structure - just an ID, and a redistributor address to @@ -164,6 +169,7 @@ struct its_device { struct its_node *its; struct event_lpi_map event_map; void *itt; + u32 itt_sz; u32 nr_ites; u32 device_id; bool shared; @@ -199,6 +205,87 @@ static DEFINE_IDA(its_vpeid_ida); #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K) +static struct page *its_alloc_pages_node(int node, gfp_t gfp, + unsigned int order) +{ + struct page *page; + int ret = 0; + + page = alloc_pages_node(node, gfp, order); + + if (!page) + return NULL; + + ret = set_memory_decrypted((unsigned long)page_address(page), + 1 << order); + /* + * If set_memory_decrypted() fails then we don't know what state the + * page is in, so we can't free it. Instead we leak it. + * set_memory_decrypted() will already have WARNed. + */ + if (ret) + return NULL; + + return page; +} + +static struct page *its_alloc_pages(gfp_t gfp, unsigned int order) +{ + return its_alloc_pages_node(NUMA_NO_NODE, gfp, order); +} + +static void its_free_pages(void *addr, unsigned int order) +{ + /* + * If the memory cannot be encrypted again then we must leak the pages. + * set_memory_encrypted() will already have WARNed. + */ + if (set_memory_encrypted((unsigned long)addr, 1 << order)) + return; + free_pages((unsigned long)addr, order); +} + +static struct gen_pool *itt_pool; + +static void *itt_alloc_pool(int node, int size) +{ + unsigned long addr; + struct page *page; + + if (size >= PAGE_SIZE) { + page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, get_order(size)); + + return page ? page_address(page) : NULL; + } + + do { + addr = gen_pool_alloc(itt_pool, size); + if (addr) + break; + + page = its_alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); + if (!page) + break; + + gen_pool_add(itt_pool, (unsigned long)page_address(page), PAGE_SIZE, node); + } while (!addr); + + return (void *)addr; +} + +static void itt_free_pool(void *addr, int size) +{ + if (!addr) + return; + + if (size >= PAGE_SIZE) { + its_free_pages(addr, get_order(size)); + return; + } + + gen_pool_free(itt_pool, (unsigned long)addr, size); +} + /* * Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we * always have vSGIs mapped. @@ -621,7 +708,6 @@ static struct its_collection *its_build_mapd_cmd(struct its_node *its, u8 size = ilog2(desc->its_mapd_cmd.dev->nr_ites); itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt); - itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN); its_encode_cmd(cmd, GITS_CMD_MAPD); its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id); @@ -2181,7 +2267,8 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) { struct page *prop_page; - prop_page = alloc_pages(gfp_flags, get_order(LPI_PROPBASE_SZ)); + prop_page = its_alloc_pages(gfp_flags, + get_order(LPI_PROPBASE_SZ)); if (!prop_page) return NULL; @@ -2192,8 +2279,7 @@ static struct page *its_allocate_prop_table(gfp_t gfp_flags) static void its_free_prop_table(struct page *prop_page) { - free_pages((unsigned long)page_address(prop_page), - get_order(LPI_PROPBASE_SZ)); + its_free_pages(page_address(prop_page), get_order(LPI_PROPBASE_SZ)); } static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size) @@ -2315,7 +2401,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, order = get_order(GITS_BASER_PAGES_MAX * psz); } - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order); + page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, order); if (!page) return -ENOMEM; @@ -2328,7 +2414,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, /* 52bit PA is supported only when PageSize=64K */ if (psz != SZ_64K) { pr_err("ITS: no 52bit PA support when psz=%d\n", psz); - free_pages((unsigned long)base, order); + its_free_pages(base, order); return -ENXIO; } @@ -2384,7 +2470,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n", &its->phys_base, its_base_type_string[type], val, tmp); - free_pages((unsigned long)base, order); + its_free_pages(base, order); return -ENXIO; } @@ -2523,8 +2609,7 @@ static void its_free_tables(struct its_node *its) for (i = 0; i < GITS_BASER_NR_REGS; i++) { if (its->tables[i].base) { - free_pages((unsigned long)its->tables[i].base, - its->tables[i].order); + its_free_pages(its->tables[i].base, its->tables[i].order); its->tables[i].base = NULL; } } @@ -2790,7 +2875,7 @@ static bool allocate_vpe_l2_table(int cpu, u32 id) /* Allocate memory for 2nd level table */ if (!table[idx]) { - page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz)); + page = its_alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(psz)); if (!page) return false; @@ -2909,7 +2994,7 @@ static int allocate_vpe_l1_table(void) pr_debug("np = %d, npg = %lld, psz = %d, epp = %d, esz = %d\n", np, npg, psz, epp, esz); - page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE)); + page = its_alloc_pages(GFP_ATOMIC | __GFP_ZERO, get_order(np * PAGE_SIZE)); if (!page) return -ENOMEM; @@ -2955,8 +3040,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags) { struct page *pend_page; - pend_page = alloc_pages(gfp_flags | __GFP_ZERO, - get_order(LPI_PENDBASE_SZ)); + pend_page = its_alloc_pages(gfp_flags | __GFP_ZERO, get_order(LPI_PENDBASE_SZ)); if (!pend_page) return NULL; @@ -2968,7 +3052,7 @@ static struct page *its_allocate_pending_table(gfp_t gfp_flags) static void its_free_pending_table(struct page *pt) { - free_pages((unsigned long)page_address(pt), get_order(LPI_PENDBASE_SZ)); + its_free_pages(page_address(pt), get_order(LPI_PENDBASE_SZ)); } /* @@ -3303,8 +3387,8 @@ static bool its_alloc_table_entry(struct its_node *its, /* Allocate memory for 2nd level table */ if (!table[idx]) { - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, - get_order(baser->psz)); + page = its_alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, + get_order(baser->psz)); if (!page) return false; @@ -3399,15 +3483,18 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, if (WARN_ON(!is_power_of_2(nvecs))) nvecs = roundup_pow_of_two(nvecs); - dev = kzalloc(sizeof(*dev), GFP_KERNEL); /* * Even if the device wants a single LPI, the ITT must be * sized as a power of two (and you need at least one bit...). */ nr_ites = max(2, nvecs); sz = nr_ites * (FIELD_GET(GITS_TYPER_ITT_ENTRY_SIZE, its->typer) + 1); - sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; - itt = kzalloc_node(sz, GFP_KERNEL, its->numa_node); + sz = max(sz, ITS_ITT_ALIGN); + + itt = itt_alloc_pool(its->numa_node, sz); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (alloc_lpis) { lpi_map = its_lpi_alloc(nvecs, &lpi_base, &nr_lpis); if (lpi_map) @@ -3419,9 +3506,9 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, lpi_base = 0; } - if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) { + if (!dev || !itt || !col_map || (!lpi_map && alloc_lpis)) { kfree(dev); - kfree(itt); + itt_free_pool(itt, sz); bitmap_free(lpi_map); kfree(col_map); return NULL; @@ -3431,6 +3518,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, dev->its = its; dev->itt = itt; + dev->itt_sz = sz; dev->nr_ites = nr_ites; dev->event_map.lpi_map = lpi_map; dev->event_map.col_map = col_map; @@ -3458,7 +3546,7 @@ static void its_free_device(struct its_device *its_dev) list_del(&its_dev->entry); raw_spin_unlock_irqrestore(&its_dev->its->lock, flags); kfree(its_dev->event_map.col_map); - kfree(its_dev->itt); + itt_free_pool(its_dev->itt, its_dev->itt_sz); kfree(its_dev); } @@ -3797,6 +3885,20 @@ static void its_vpe_db_proxy_move(struct its_vpe *vpe, int from, int to) raw_spin_unlock_irqrestore(&vpe_proxy.lock, flags); } +static void its_vpe_4_1_invall_locked(int cpu, struct its_vpe *vpe) +{ + void __iomem *rdbase; + u64 val; + + val = GICR_INVALLR_V; + val |= FIELD_PREP(GICR_INVALLR_VPEID, vpe->vpe_id); + + guard(raw_spinlock)(&gic_data_rdist_cpu(cpu)->rd_lock); + rdbase = per_cpu_ptr(gic_rdists->rdist, cpu)->rd_base; + gic_write_lpir(val, rdbase + GICR_INVALLR); + wait_for_syncr(rdbase); +} + static int its_vpe_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) @@ -3804,6 +3906,7 @@ static int its_vpe_set_affinity(struct irq_data *d, struct its_vpe *vpe = irq_data_get_irq_chip_data(d); unsigned int from, cpu = nr_cpu_ids; struct cpumask *table_mask; + struct its_node *its; unsigned long flags; /* @@ -3866,6 +3969,11 @@ static int its_vpe_set_affinity(struct irq_data *d, vpe->col_idx = cpu; its_send_vmovp(vpe); + + its = find_4_1_its(); + if (its && its->flags & ITS_FLAGS_WORKAROUND_HISILICON_162100801) + its_vpe_4_1_invall_locked(cpu, vpe); + its_vpe_db_proxy_move(vpe, from, cpu); out: @@ -4173,22 +4281,12 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, static void its_vpe_4_1_invall(struct its_vpe *vpe) { - void __iomem *rdbase; unsigned long flags; - u64 val; int cpu; - val = GICR_INVALLR_V; - val |= FIELD_PREP(GICR_INVALLR_VPEID, vpe->vpe_id); - /* Target the redistributor this vPE is currently known on */ cpu = vpe_to_cpuid_lock(vpe, &flags); - raw_spin_lock(&gic_data_rdist_cpu(cpu)->rd_lock); - rdbase = per_cpu_ptr(gic_rdists->rdist, cpu)->rd_base; - gic_write_lpir(val, rdbase + GICR_INVALLR); - - wait_for_syncr(rdbase); - raw_spin_unlock(&gic_data_rdist_cpu(cpu)->rd_lock); + its_vpe_4_1_invall_locked(cpu, vpe); vpe_to_cpuid_unlock(vpe, flags); } @@ -4781,6 +4879,14 @@ static bool its_set_non_coherent(void *data) return true; } +static bool __maybe_unused its_enable_quirk_hip09_162100801(void *data) +{ + struct its_node *its = data; + + its->flags |= ITS_FLAGS_WORKAROUND_HISILICON_162100801; + return true; +} + static const struct gic_quirk its_quirks[] = { #ifdef CONFIG_CAVIUM_ERRATUM_22375 { @@ -4827,6 +4933,14 @@ static const struct gic_quirk its_quirks[] = { .init = its_enable_quirk_hip07_161600802, }, #endif +#ifdef CONFIG_HISILICON_ERRATUM_162100801 + { + .desc = "ITS: Hip09 erratum 162100801", + .iidr = 0x00051736, + .mask = 0xffffffff, + .init = its_enable_quirk_hip09_162100801, + }, +#endif #ifdef CONFIG_ROCKCHIP_ERRATUM_3588001 { .desc = "ITS: Rockchip erratum RK3588001", @@ -5132,8 +5246,9 @@ static int __init its_probe_one(struct its_node *its) } } - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, - get_order(ITS_CMD_QUEUE_SZ)); + page = its_alloc_pages_node(its->numa_node, + GFP_KERNEL | __GFP_ZERO, + get_order(ITS_CMD_QUEUE_SZ)); if (!page) { err = -ENOMEM; goto out_unmap_sgir; @@ -5197,7 +5312,7 @@ static int __init its_probe_one(struct its_node *its) out_free_tables: its_free_tables(its); out_free_cmd: - free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ)); + its_free_pages(its->cmd_base, get_order(ITS_CMD_QUEUE_SZ)); out_unmap_sgir: if (its->sgir_base) iounmap(its->sgir_base); @@ -5683,6 +5798,10 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists, bool has_v4_1 = false; int err; + itt_pool = gen_pool_create(get_order(ITS_ITT_ALIGN), -1); + if (!itt_pool) + return -ENOMEM; + gic_rdists = rdists; lpi_prop_prio = irq_prio; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 8b6159f4cdafa4..79d8cc80693c31 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -161,7 +161,22 @@ static bool cpus_have_group0 __ro_after_init; static void __init gic_prio_init(void) { - cpus_have_security_disabled = gic_dist_security_disabled(); + bool ds; + + ds = gic_dist_security_disabled(); + if (!ds) { + u32 val; + + val = readl_relaxed(gic_data.dist_base + GICD_CTLR); + val |= GICD_CTLR_DS; + writel_relaxed(val, gic_data.dist_base + GICD_CTLR); + + ds = gic_dist_security_disabled(); + if (ds) + pr_warn("Broken GIC integration, security disabled"); + } + + cpus_have_security_disabled = ds; cpus_have_group0 = gic_has_group0(); /* @@ -817,7 +832,7 @@ static void gic_deactivate_unhandled(u32 irqnr) * register state is not stale, as these may have been indirectly written * *after* exception entry. * - * (2) Deactivate the interrupt when EOI mode 1 is in use. + * (2) Execute an interrupt priority drop when EOI mode 1 is in use. */ static inline void gic_complete_ack(u32 irqnr) { diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 3be7bd8cd8cdeb..6503573557fdf2 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -64,7 +64,7 @@ static void gic_check_cpu_features(void) union gic_base { void __iomem *common_base; - void __percpu * __iomem *percpu_base; + void __iomem * __percpu *percpu_base; }; struct gic_chip_data { @@ -400,7 +400,7 @@ static void gic_irq_print_chip(struct irq_data *d, struct seq_file *p) struct gic_chip_data *gic = irq_data_get_irq_chip_data(d); if (gic->domain->pm_dev) - seq_printf(p, gic->domain->pm_dev->of_node->name); + seq_puts(p, gic->domain->pm_dev->of_node->name); else seq_printf(p, "GIC-%d", (int)(gic - &gic_data[0])); } diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index b42ed68acfa667..85f80bac096159 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -479,7 +479,7 @@ static struct platform_driver pdc_intc_driver = { .of_match_table = pdc_intc_match, }, .probe = pdc_intc_probe, - .remove_new = pdc_intc_remove, + .remove = pdc_intc_remove, }; static int __init pdc_intc_init(void) diff --git a/drivers/irqchip/irq-imx-intmux.c b/drivers/irqchip/irq-imx-intmux.c index 511adfaeec8227..787543d07565be 100644 --- a/drivers/irqchip/irq-imx-intmux.c +++ b/drivers/irqchip/irq-imx-intmux.c @@ -361,6 +361,6 @@ static struct platform_driver imx_intmux_driver = { .pm = &imx_intmux_pm_ops, }, .probe = imx_intmux_probe, - .remove_new = imx_intmux_remove, + .remove = imx_intmux_remove, }; builtin_platform_driver(imx_intmux_driver); diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c index 75a0e980ff3524..b0e9788c004548 100644 --- a/drivers/irqchip/irq-imx-irqsteer.c +++ b/drivers/irqchip/irq-imx-irqsteer.c @@ -328,6 +328,6 @@ static struct platform_driver imx_irqsteer_driver = { .pm = &imx_irqsteer_pm_ops, }, .probe = imx_irqsteer_probe, - .remove_new = imx_irqsteer_remove, + .remove = imx_irqsteer_remove, }; builtin_platform_driver(imx_irqsteer_driver); diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index 30f1979fa1240a..808c781e254835 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -211,7 +211,7 @@ MODULE_DEVICE_TABLE(of, keystone_irq_dt_ids); static struct platform_driver keystone_irq_device_driver = { .probe = keystone_irq_probe, - .remove_new = keystone_irq_remove, + .remove = keystone_irq_remove, .driver = { .name = "keystone_irq", .of_match_table = of_match_ptr(keystone_irq_dt_ids), diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index e24db71a8783cb..bb79e19dfb5900 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -26,15 +27,37 @@ #define EIOINTC_REG_ISR 0x1800 #define EIOINTC_REG_ROUTE 0x1c00 +#define EXTIOI_VIRT_FEATURES 0x40000000 +#define EXTIOI_HAS_VIRT_EXTENSION BIT(0) +#define EXTIOI_HAS_ENABLE_OPTION BIT(1) +#define EXTIOI_HAS_INT_ENCODE BIT(2) +#define EXTIOI_HAS_CPU_ENCODE BIT(3) +#define EXTIOI_VIRT_CONFIG 0x40000004 +#define EXTIOI_ENABLE BIT(1) +#define EXTIOI_ENABLE_INT_ENCODE BIT(2) +#define EXTIOI_ENABLE_CPU_ENCODE BIT(3) + #define VEC_REG_COUNT 4 #define VEC_COUNT_PER_REG 64 #define VEC_COUNT (VEC_REG_COUNT * VEC_COUNT_PER_REG) #define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG) #define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG) #define EIOINTC_ALL_ENABLE 0xffffffff +#define EIOINTC_ALL_ENABLE_VEC_MASK(vector) (EIOINTC_ALL_ENABLE & ~BIT(vector & 0x1f)) +#define EIOINTC_REG_ENABLE_VEC(vector) (EIOINTC_REG_ENABLE + ((vector >> 5) << 2)) +#define EIOINTC_USE_CPU_ENCODE BIT(0) #define MAX_EIO_NODES (NR_CPUS / CORES_PER_EIO_NODE) +/* + * Routing registers are 32bit, and there is 8-bit route setting for every + * interrupt vector. So one Route register contains four vectors routing + * information. + */ +#define EIOINTC_REG_ROUTE_VEC(vector) (EIOINTC_REG_ROUTE + (vector & ~0x03)) +#define EIOINTC_REG_ROUTE_VEC_SHIFT(vector) ((vector & 0x03) << 3) +#define EIOINTC_REG_ROUTE_VEC_MASK(vector) (0xff << EIOINTC_REG_ROUTE_VEC_SHIFT(vector)) + static int nr_pics; struct eiointc_priv { @@ -44,6 +67,7 @@ struct eiointc_priv { cpumask_t cpuspan_map; struct fwnode_handle *domain_handle; struct irq_domain *eiointc_domain; + int flags; }; static struct eiointc_priv *eiointc_priv[MAX_IO_PICS]; @@ -59,7 +83,10 @@ static void eiointc_enable(void) static int cpu_to_eio_node(int cpu) { - return cpu_logical_map(cpu) / CORES_PER_EIO_NODE; + if (!kvm_para_has_feature(KVM_FEATURE_VIRT_EXTIOI)) + return cpu_logical_map(cpu) / CORES_PER_EIO_NODE; + else + return cpu_logical_map(cpu) / CORES_PER_VEIO_NODE; } #ifdef CONFIG_SMP @@ -89,6 +116,17 @@ static void eiointc_set_irq_route(int pos, unsigned int cpu, unsigned int mnode, } } +static void veiointc_set_irq_route(unsigned int vector, unsigned int cpu) +{ + unsigned long reg = EIOINTC_REG_ROUTE_VEC(vector); + unsigned int data; + + data = iocsr_read32(reg); + data &= ~EIOINTC_REG_ROUTE_VEC_MASK(vector); + data |= cpu_logical_map(cpu) << EIOINTC_REG_ROUTE_VEC_SHIFT(vector); + iocsr_write32(data, reg); +} + static DEFINE_RAW_SPINLOCK(affinity_lock); static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, bool force) @@ -107,18 +145,24 @@ static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *af } vector = d->hwirq; - regaddr = EIOINTC_REG_ENABLE + ((vector >> 5) << 2); - - /* Mask target vector */ - csr_any_send(regaddr, EIOINTC_ALL_ENABLE & (~BIT(vector & 0x1F)), - 0x0, priv->node * CORES_PER_EIO_NODE); - - /* Set route for target vector */ - eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map); - - /* Unmask target vector */ - csr_any_send(regaddr, EIOINTC_ALL_ENABLE, - 0x0, priv->node * CORES_PER_EIO_NODE); + regaddr = EIOINTC_REG_ENABLE_VEC(vector); + + if (priv->flags & EIOINTC_USE_CPU_ENCODE) { + iocsr_write32(EIOINTC_ALL_ENABLE_VEC_MASK(vector), regaddr); + veiointc_set_irq_route(vector, cpu); + iocsr_write32(EIOINTC_ALL_ENABLE, regaddr); + } else { + /* Mask target vector */ + csr_any_send(regaddr, EIOINTC_ALL_ENABLE_VEC_MASK(vector), + 0x0, priv->node * CORES_PER_EIO_NODE); + + /* Set route for target vector */ + eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map); + + /* Unmask target vector */ + csr_any_send(regaddr, EIOINTC_ALL_ENABLE, + 0x0, priv->node * CORES_PER_EIO_NODE); + } irq_data_update_effective_affinity(d, cpumask_of(cpu)); @@ -142,17 +186,23 @@ static int eiointc_index(int node) static int eiointc_router_init(unsigned int cpu) { - int i, bit; - uint32_t data; - uint32_t node = cpu_to_eio_node(cpu); - int index = eiointc_index(node); + int i, bit, cores, index, node; + unsigned int data; + + node = cpu_to_eio_node(cpu); + index = eiointc_index(node); if (index < 0) { pr_err("Error: invalid nodemap!\n"); - return -1; + return -EINVAL; } - if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) == 0) { + if (!(eiointc_priv[index]->flags & EIOINTC_USE_CPU_ENCODE)) + cores = CORES_PER_EIO_NODE; + else + cores = CORES_PER_VEIO_NODE; + + if ((cpu_logical_map(cpu) % cores) == 0) { eiointc_enable(); for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) { @@ -168,7 +218,9 @@ static int eiointc_router_init(unsigned int cpu) for (i = 0; i < eiointc_priv[0]->vec_count / 4; i++) { /* Route to Node-0 Core-0 */ - if (index == 0) + if (eiointc_priv[index]->flags & EIOINTC_USE_CPU_ENCODE) + bit = cpu_logical_map(0); + else if (index == 0) bit = BIT(cpu_logical_map(0)); else bit = (eiointc_priv[index]->node << 4) | 1; @@ -375,7 +427,7 @@ static int __init acpi_cascade_irqdomain_init(void) static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq, u64 node_map) { - int i; + int i, val; node_map = node_map ? node_map : -1ULL; for_each_possible_cpu(i) { @@ -395,6 +447,20 @@ static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq, return -ENOMEM; } + if (kvm_para_has_feature(KVM_FEATURE_VIRT_EXTIOI)) { + val = iocsr_read32(EXTIOI_VIRT_FEATURES); + /* + * With EXTIOI_ENABLE_CPU_ENCODE set + * interrupts can route to 256 vCPUs. + */ + if (val & EXTIOI_HAS_CPU_ENCODE) { + val = iocsr_read32(EXTIOI_VIRT_CONFIG); + val |= EXTIOI_ENABLE_CPU_ENCODE; + iocsr_write32(val, EXTIOI_VIRT_CONFIG); + priv->flags = EIOINTC_USE_CPU_ENCODE; + } + } + eiointc_priv[nr_pics++] = priv; eiointc_router_init(0); irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv); diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 1aef5c4d27c631..c0e1aafe468c32 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -418,7 +418,7 @@ static struct platform_driver ls_scfg_msi_driver = { .of_match_table = ls_scfg_msi_id, }, .probe = ls_scfg_msi_probe, - .remove_new = ls_scfg_msi_remove, + .remove = ls_scfg_msi_remove, }; module_platform_driver(ls_scfg_msi_driver); diff --git a/drivers/irqchip/irq-madera.c b/drivers/irqchip/irq-madera.c index acceb6e7fa95f5..b32982c11515ff 100644 --- a/drivers/irqchip/irq-madera.c +++ b/drivers/irqchip/irq-madera.c @@ -236,7 +236,7 @@ static void madera_irq_remove(struct platform_device *pdev) static struct platform_driver madera_irq_driver = { .probe = madera_irq_probe, - .remove_new = madera_irq_remove, + .remove = madera_irq_remove, .driver = { .name = "madera-irq", .pm = &madera_irq_pm_ops, diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 76253e864f2304..bca8053864b2ce 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -66,6 +66,87 @@ static struct gic_all_vpes_chip_data { bool mask; } gic_all_vpes_chip_data[GIC_NUM_LOCAL_INTRS]; +static int __gic_with_next_online_cpu(int prev) +{ + unsigned int cpu; + + /* Discover the next online CPU */ + cpu = cpumask_next(prev, cpu_online_mask); + + /* If there isn't one, we're done */ + if (cpu >= nr_cpu_ids) + return cpu; + + /* + * Move the access lock to the next CPU's GIC local register block. + * + * Set GIC_VL_OTHER. Since the caller holds gic_lock nothing can + * clobber the written value. + */ + write_gic_vl_other(mips_cm_vp_id(cpu)); + + return cpu; +} + +static inline void gic_unlock_cluster(void) +{ + if (mips_cps_multicluster_cpus()) + mips_cm_unlock_other(); +} + +/** + * for_each_online_cpu_gic() - Iterate over online CPUs, access local registers + * @cpu: An integer variable to hold the current CPU number + * @gic_lock: A pointer to raw spin lock used as a guard + * + * Iterate over online CPUs & configure the other/redirect register region to + * access each CPUs GIC local register block, which can be accessed from the + * loop body using read_gic_vo_*() or write_gic_vo_*() accessor functions or + * their derivatives. + */ +#define for_each_online_cpu_gic(cpu, gic_lock) \ + guard(raw_spinlock_irqsave)(gic_lock); \ + for ((cpu) = __gic_with_next_online_cpu(-1); \ + (cpu) < nr_cpu_ids; \ + gic_unlock_cluster(), \ + (cpu) = __gic_with_next_online_cpu(cpu)) + +/** + * gic_irq_lock_cluster() - Lock redirect block access to IRQ's cluster + * @d: struct irq_data corresponding to the interrupt we're interested in + * + * Locks redirect register block access to the global register block of the GIC + * within the remote cluster that the IRQ corresponding to @d is affine to, + * returning true when this redirect block setup & locking has been performed. + * + * If @d is affine to the local cluster then no locking is performed and this + * function will return false, indicating to the caller that it should access + * the local clusters registers without the overhead of indirection through the + * redirect block. + * + * In summary, if this function returns true then the caller should access GIC + * registers using redirect register block accessors & then call + * mips_cm_unlock_other() when done. If this function returns false then the + * caller should trivially access GIC registers in the local cluster. + * + * Returns true if locking performed, else false. + */ +static bool gic_irq_lock_cluster(struct irq_data *d) +{ + unsigned int cpu, cl; + + cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); + BUG_ON(cpu >= NR_CPUS); + + cl = cpu_cluster(&cpu_data[cpu]); + if (cl == cpu_cluster(¤t_cpu_data)) + return false; + if (mips_cps_numcores(cl) == 0) + return false; + mips_cm_lock_other(cl, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL); + return true; +} + static void gic_clear_pcpu_masks(unsigned int intr) { unsigned int i; @@ -112,7 +193,12 @@ static void gic_send_ipi(struct irq_data *d, unsigned int cpu) { irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d)); - write_gic_wedge(GIC_WEDGE_RW | hwirq); + if (gic_irq_lock_cluster(d)) { + write_gic_redir_wedge(GIC_WEDGE_RW | hwirq); + mips_cm_unlock_other(); + } else { + write_gic_wedge(GIC_WEDGE_RW | hwirq); + } } int gic_get_c0_compare_int(void) @@ -180,7 +266,13 @@ static void gic_mask_irq(struct irq_data *d) { unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq); - write_gic_rmask(intr); + if (gic_irq_lock_cluster(d)) { + write_gic_redir_rmask(intr); + mips_cm_unlock_other(); + } else { + write_gic_rmask(intr); + } + gic_clear_pcpu_masks(intr); } @@ -189,7 +281,12 @@ static void gic_unmask_irq(struct irq_data *d) unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq); unsigned int cpu; - write_gic_smask(intr); + if (gic_irq_lock_cluster(d)) { + write_gic_redir_smask(intr); + mips_cm_unlock_other(); + } else { + write_gic_smask(intr); + } gic_clear_pcpu_masks(intr); cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); @@ -200,7 +297,12 @@ static void gic_ack_irq(struct irq_data *d) { unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); - write_gic_wedge(irq); + if (gic_irq_lock_cluster(d)) { + write_gic_redir_wedge(irq); + mips_cm_unlock_other(); + } else { + write_gic_wedge(irq); + } } static int gic_set_type(struct irq_data *d, unsigned int type) @@ -240,9 +342,16 @@ static int gic_set_type(struct irq_data *d, unsigned int type) break; } - change_gic_pol(irq, pol); - change_gic_trig(irq, trig); - change_gic_dual(irq, dual); + if (gic_irq_lock_cluster(d)) { + change_gic_redir_pol(irq, pol); + change_gic_redir_trig(irq, trig); + change_gic_redir_dual(irq, dual); + mips_cm_unlock_other(); + } else { + change_gic_pol(irq, pol); + change_gic_trig(irq, trig); + change_gic_dual(irq, dual); + } if (trig == GIC_TRIG_EDGE) irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller, @@ -260,25 +369,72 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force) { unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); + unsigned int cpu, cl, old_cpu, old_cl; unsigned long flags; - unsigned int cpu; + /* + * The GIC specifies that we can only route an interrupt to one VP(E), + * ie. CPU in Linux parlance, at a time. Therefore we always route to + * the first online CPU in the mask. + */ cpu = cpumask_first_and(cpumask, cpu_online_mask); if (cpu >= NR_CPUS) return -EINVAL; - /* Assumption : cpumask refers to a single CPU */ - raw_spin_lock_irqsave(&gic_lock, flags); + old_cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); + old_cl = cpu_cluster(&cpu_data[old_cpu]); + cl = cpu_cluster(&cpu_data[cpu]); - /* Re-route this IRQ */ - write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu))); + raw_spin_lock_irqsave(&gic_lock, flags); - /* Update the pcpu_masks */ - gic_clear_pcpu_masks(irq); - if (read_gic_mask(irq)) - set_bit(irq, per_cpu_ptr(pcpu_masks, cpu)); + /* + * If we're moving affinity between clusters, stop routing the + * interrupt to any VP(E) in the old cluster. + */ + if (cl != old_cl) { + if (gic_irq_lock_cluster(d)) { + write_gic_redir_map_vp(irq, 0); + mips_cm_unlock_other(); + } else { + write_gic_map_vp(irq, 0); + } + } + /* + * Update effective affinity - after this gic_irq_lock_cluster() will + * begin operating on the new cluster. + */ irq_data_update_effective_affinity(d, cpumask_of(cpu)); + + /* + * If we're moving affinity between clusters, configure the interrupt + * trigger type in the new cluster. + */ + if (cl != old_cl) + gic_set_type(d, irqd_get_trigger_type(d)); + + /* Route the interrupt to its new VP(E) */ + if (gic_irq_lock_cluster(d)) { + write_gic_redir_map_pin(irq, + GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); + write_gic_redir_map_vp(irq, BIT(mips_cm_vp_id(cpu))); + + /* Update the pcpu_masks */ + gic_clear_pcpu_masks(irq); + if (read_gic_redir_mask(irq)) + set_bit(irq, per_cpu_ptr(pcpu_masks, cpu)); + + mips_cm_unlock_other(); + } else { + write_gic_map_pin(irq, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); + write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu))); + + /* Update the pcpu_masks */ + gic_clear_pcpu_masks(irq); + if (read_gic_mask(irq)) + set_bit(irq, per_cpu_ptr(pcpu_masks, cpu)); + } + raw_spin_unlock_irqrestore(&gic_lock, flags); return IRQ_SET_MASK_OK; @@ -350,37 +506,33 @@ static struct irq_chip gic_local_irq_controller = { static void gic_mask_local_irq_all_vpes(struct irq_data *d) { struct gic_all_vpes_chip_data *cd; - unsigned long flags; int intr, cpu; + if (!mips_cps_multicluster_cpus()) + return; + intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); cd = irq_data_get_irq_chip_data(d); cd->mask = false; - raw_spin_lock_irqsave(&gic_lock, flags); - for_each_online_cpu(cpu) { - write_gic_vl_other(mips_cm_vp_id(cpu)); + for_each_online_cpu_gic(cpu, &gic_lock) write_gic_vo_rmask(BIT(intr)); - } - raw_spin_unlock_irqrestore(&gic_lock, flags); } static void gic_unmask_local_irq_all_vpes(struct irq_data *d) { struct gic_all_vpes_chip_data *cd; - unsigned long flags; int intr, cpu; + if (!mips_cps_multicluster_cpus()) + return; + intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); cd = irq_data_get_irq_chip_data(d); cd->mask = true; - raw_spin_lock_irqsave(&gic_lock, flags); - for_each_online_cpu(cpu) { - write_gic_vl_other(mips_cm_vp_id(cpu)); + for_each_online_cpu_gic(cpu, &gic_lock) write_gic_vo_smask(BIT(intr)); - } - raw_spin_unlock_irqrestore(&gic_lock, flags); } static void gic_all_vpes_irq_cpu_online(void) @@ -436,11 +588,21 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, unsigned long flags; data = irq_get_irq_data(virq); + irq_data_update_effective_affinity(data, cpumask_of(cpu)); 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)); + + /* Route the interrupt to its VP(E) */ + if (gic_irq_lock_cluster(data)) { + write_gic_redir_map_pin(intr, + GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); + write_gic_redir_map_vp(intr, BIT(mips_cm_vp_id(cpu))); + mips_cm_unlock_other(); + } else { + 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))); + } + raw_spin_unlock_irqrestore(&gic_lock, flags); return 0; @@ -469,7 +631,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { struct gic_all_vpes_chip_data *cd; - unsigned long flags; unsigned int intr; int err, cpu; u32 map; @@ -533,12 +694,10 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, if (!gic_local_irq_is_routable(intr)) return -EPERM; - 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); + if (mips_cps_multicluster_cpus()) { + for_each_online_cpu_gic(cpu, &gic_lock) + write_gic_vo_map(mips_gic_vx_map_reg(intr), map); } - raw_spin_unlock_irqrestore(&gic_lock, flags); return 0; } @@ -621,6 +780,9 @@ static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq, if (ret) goto error; + /* Set affinity to cpu. */ + irq_data_update_effective_affinity(irq_get_irq_data(virq + i), + cpumask_of(cpu)); ret = irq_set_irq_type(virq + i, IRQ_TYPE_EDGE_RISING); if (ret) goto error; @@ -734,7 +896,7 @@ static int gic_cpu_startup(unsigned int cpu) static int __init gic_of_init(struct device_node *node, struct device_node *parent) { - unsigned int cpu_vec, i, gicconfig; + unsigned int cpu_vec, i, gicconfig, cl, nclusters; unsigned long reserved; phys_addr_t gic_base; struct resource res; @@ -815,11 +977,32 @@ static int __init gic_of_init(struct device_node *node, board_bind_eic_interrupt = &gic_bind_eic_interrupt; - /* Setup defaults */ - for (i = 0; i < gic_shared_intrs; i++) { - change_gic_pol(i, GIC_POL_ACTIVE_HIGH); - change_gic_trig(i, GIC_TRIG_LEVEL); - write_gic_rmask(i); + /* + * Initialise each cluster's GIC shared registers to sane default + * values. + * Otherwise, the IPI set up will be erased if we move code + * to gic_cpu_startup for each cpu. + */ + nclusters = mips_cps_numclusters(); + for (cl = 0; cl < nclusters; cl++) { + if (cl == cpu_cluster(¤t_cpu_data)) { + for (i = 0; i < gic_shared_intrs; i++) { + change_gic_pol(i, GIC_POL_ACTIVE_HIGH); + change_gic_trig(i, GIC_TRIG_LEVEL); + write_gic_rmask(i); + } + } else if (mips_cps_numcores(cl) != 0) { + mips_cm_lock_other(cl, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL); + for (i = 0; i < gic_shared_intrs; i++) { + change_gic_redir_pol(i, GIC_POL_ACTIVE_HIGH); + change_gic_redir_trig(i, GIC_TRIG_LEVEL); + write_gic_redir_rmask(i); + } + mips_cm_unlock_other(); + + } else { + pr_warn("No CPU cores on the cluster %d skip it\n", cl); + } } return cpuhp_setup_state(CPUHP_AP_IRQ_MIPS_GIC_STARTING, diff --git a/drivers/irqchip/irq-mvebu-pic.c b/drivers/irqchip/irq-mvebu-pic.c index 08b0cc862adf03..3888b758598146 100644 --- a/drivers/irqchip/irq-mvebu-pic.c +++ b/drivers/irqchip/irq-mvebu-pic.c @@ -71,7 +71,7 @@ static void mvebu_pic_print_chip(struct irq_data *d, struct seq_file *p) { struct mvebu_pic *pic = irq_data_get_irq_chip_data(d); - seq_printf(p, dev_name(&pic->pdev->dev)); + seq_puts(p, dev_name(&pic->pdev->dev)); } static const struct irq_chip mvebu_pic_chip = { @@ -183,7 +183,7 @@ MODULE_DEVICE_TABLE(of, mvebu_pic_of_match); static struct platform_driver mvebu_pic_driver = { .probe = mvebu_pic_probe, - .remove_new = mvebu_pic_remove, + .remove = mvebu_pic_remove, .driver = { .name = "mvebu-pic", .of_match_table = mvebu_pic_of_match, diff --git a/drivers/irqchip/irq-mvebu-sei.c b/drivers/irqchip/irq-mvebu-sei.c index f8c70f2d100a11..065166ab5dbc04 100644 --- a/drivers/irqchip/irq-mvebu-sei.c +++ b/drivers/irqchip/irq-mvebu-sei.c @@ -192,7 +192,6 @@ static void mvebu_sei_domain_free(struct irq_domain *domain, unsigned int virq, } static const struct irq_domain_ops mvebu_sei_domain_ops = { - .select = msi_lib_irq_domain_select, .alloc = mvebu_sei_domain_alloc, .free = mvebu_sei_domain_free, }; @@ -306,6 +305,7 @@ static void mvebu_sei_cp_domain_free(struct irq_domain *domain, } static const struct irq_domain_ops mvebu_sei_cp_domain_ops = { + .select = msi_lib_irq_domain_select, .alloc = mvebu_sei_cp_domain_alloc, .free = mvebu_sei_cp_domain_free, }; diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c index 060eb000e9d359..bee01980b4630c 100644 --- a/drivers/irqchip/irq-pruss-intc.c +++ b/drivers/irqchip/irq-pruss-intc.c @@ -648,7 +648,7 @@ static struct platform_driver pruss_intc_driver = { .suppress_bind_attrs = true, }, .probe = pruss_intc_probe, - .remove_new = pruss_intc_remove, + .remove = pruss_intc_remove, }; module_platform_driver(pruss_intc_driver); diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 9ad37237ba9547..954419f2460d11 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -584,7 +584,7 @@ static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); static struct platform_driver intc_irqpin_device_driver = { .probe = intc_irqpin_probe, - .remove_new = intc_irqpin_remove, + .remove = intc_irqpin_remove, .driver = { .name = "renesas_intc_irqpin", .of_match_table = intc_irqpin_dt_ids, diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 76026e0b8e2010..cbce8ffc7de4aa 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -247,7 +247,7 @@ MODULE_DEVICE_TABLE(of, irqc_dt_ids); static struct platform_driver irqc_device_driver = { .probe = irqc_probe, - .remove_new = irqc_remove, + .remove = irqc_remove, .driver = { .name = "renesas_irqc", .of_match_table = irqc_dt_ids, diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c index f05afe82db4d1d..d4e6a68889ec1c 100644 --- a/drivers/irqchip/irq-renesas-rza1.c +++ b/drivers/irqchip/irq-renesas-rza1.c @@ -259,7 +259,7 @@ MODULE_DEVICE_TABLE(of, rza1_irqc_dt_ids); static struct platform_driver rza1_irqc_device_driver = { .probe = rza1_irqc_probe, - .remove_new = rza1_irqc_remove, + .remove = rza1_irqc_remove, .driver = { .name = "renesas_rza1_irqc", .of_match_table = rza1_irqc_dt_ids, diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c new file mode 100644 index 00000000000000..fe2d29e910261b --- /dev/null +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -0,0 +1,513 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/V2H(P) ICU Driver + * + * Based on irq-renesas-rzg2l.c + * + * Copyright (C) 2024 Renesas Electronics Corporation. + * + * Author: Fabrizio Castro + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* DT "interrupts" indexes */ +#define ICU_IRQ_START 1 +#define ICU_IRQ_COUNT 16 +#define ICU_TINT_START (ICU_IRQ_START + ICU_IRQ_COUNT) +#define ICU_TINT_COUNT 32 +#define ICU_NUM_IRQ (ICU_TINT_START + ICU_TINT_COUNT) + +/* Registers */ +#define ICU_NSCNT 0x00 +#define ICU_NSCLR 0x04 +#define ICU_NITSR 0x08 +#define ICU_ISCTR 0x10 +#define ICU_ISCLR 0x14 +#define ICU_IITSR 0x18 +#define ICU_TSCTR 0x20 +#define ICU_TSCLR 0x24 +#define ICU_TITSR(k) (0x28 + (k) * 4) +#define ICU_TSSR(k) (0x30 + (k) * 4) + +/* NMI */ +#define ICU_NMI_EDGE_FALLING 0 +#define ICU_NMI_EDGE_RISING 1 + +#define ICU_NSCLR_NCLR BIT(0) + +/* IRQ */ +#define ICU_IRQ_LEVEL_LOW 0 +#define ICU_IRQ_EDGE_FALLING 1 +#define ICU_IRQ_EDGE_RISING 2 +#define ICU_IRQ_EDGE_BOTH 3 + +#define ICU_IITSR_IITSEL_PREP(iitsel, n) ((iitsel) << ((n) * 2)) +#define ICU_IITSR_IITSEL_GET(iitsr, n) (((iitsr) >> ((n) * 2)) & 0x03) +#define ICU_IITSR_IITSEL_MASK(n) ICU_IITSR_IITSEL_PREP(0x03, n) + +/* TINT */ +#define ICU_TINT_EDGE_RISING 0 +#define ICU_TINT_EDGE_FALLING 1 +#define ICU_TINT_LEVEL_HIGH 2 +#define ICU_TINT_LEVEL_LOW 3 + +#define ICU_TSSR_K(tint_nr) ((tint_nr) / 4) +#define ICU_TSSR_TSSEL_N(tint_nr) ((tint_nr) % 4) +#define ICU_TSSR_TSSEL_PREP(tssel, n) ((tssel) << ((n) * 8)) +#define ICU_TSSR_TSSEL_MASK(n) ICU_TSSR_TSSEL_PREP(0x7F, n) +#define ICU_TSSR_TIEN(n) (BIT(7) << ((n) * 8)) + +#define ICU_TITSR_K(tint_nr) ((tint_nr) / 16) +#define ICU_TITSR_TITSEL_N(tint_nr) ((tint_nr) % 16) +#define ICU_TITSR_TITSEL_PREP(titsel, n) ICU_IITSR_IITSEL_PREP(titsel, n) +#define ICU_TITSR_TITSEL_MASK(n) ICU_IITSR_IITSEL_MASK(n) +#define ICU_TITSR_TITSEL_GET(titsr, n) ICU_IITSR_IITSEL_GET(titsr, n) + +#define ICU_TINT_EXTRACT_HWIRQ(x) FIELD_GET(GENMASK(15, 0), (x)) +#define ICU_TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x)) +#define ICU_PB5_TINT 0x55 + +/** + * struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure. + * @base: Controller's base address + * @irqchip: Pointer to struct irq_chip + * @fwspec: IRQ firmware specific data + * @lock: Lock to serialize access to hardware registers + */ +struct rzv2h_icu_priv { + void __iomem *base; + const struct irq_chip *irqchip; + struct irq_fwspec fwspec[ICU_NUM_IRQ]; + raw_spinlock_t lock; +}; + +static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data) +{ + return data->domain->host_data; +} + +static void rzv2h_icu_eoi(struct irq_data *d) +{ + struct rzv2h_icu_priv *priv = irq_data_to_priv(d); + unsigned int hw_irq = irqd_to_hwirq(d); + unsigned int tintirq_nr; + u32 bit; + + scoped_guard(raw_spinlock, &priv->lock) { + if (hw_irq >= ICU_TINT_START) { + tintirq_nr = hw_irq - ICU_TINT_START; + bit = BIT(tintirq_nr); + if (!irqd_is_level_type(d)) + writel_relaxed(bit, priv->base + ICU_TSCLR); + } else if (hw_irq >= ICU_IRQ_START) { + tintirq_nr = hw_irq - ICU_IRQ_START; + bit = BIT(tintirq_nr); + if (!irqd_is_level_type(d)) + writel_relaxed(bit, priv->base + ICU_ISCLR); + } else { + writel_relaxed(ICU_NSCLR_NCLR, priv->base + ICU_NSCLR); + } + } + + irq_chip_eoi_parent(d); +} + +static void rzv2h_tint_irq_endisable(struct irq_data *d, bool enable) +{ + struct rzv2h_icu_priv *priv = irq_data_to_priv(d); + unsigned int hw_irq = irqd_to_hwirq(d); + u32 tint_nr, tssel_n, k, tssr; + + if (hw_irq < ICU_TINT_START) + return; + + tint_nr = hw_irq - ICU_TINT_START; + k = ICU_TSSR_K(tint_nr); + tssel_n = ICU_TSSR_TSSEL_N(tint_nr); + + guard(raw_spinlock)(&priv->lock); + tssr = readl_relaxed(priv->base + ICU_TSSR(k)); + if (enable) + tssr |= ICU_TSSR_TIEN(tssel_n); + else + tssr &= ~ICU_TSSR_TIEN(tssel_n); + writel_relaxed(tssr, priv->base + ICU_TSSR(k)); +} + +static void rzv2h_icu_irq_disable(struct irq_data *d) +{ + irq_chip_disable_parent(d); + rzv2h_tint_irq_endisable(d, false); +} + +static void rzv2h_icu_irq_enable(struct irq_data *d) +{ + rzv2h_tint_irq_endisable(d, true); + irq_chip_enable_parent(d); +} + +static int rzv2h_nmi_set_type(struct irq_data *d, unsigned int type) +{ + struct rzv2h_icu_priv *priv = irq_data_to_priv(d); + u32 sense; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_FALLING: + sense = ICU_NMI_EDGE_FALLING; + break; + + case IRQ_TYPE_EDGE_RISING: + sense = ICU_NMI_EDGE_RISING; + break; + + default: + return -EINVAL; + } + + writel_relaxed(sense, priv->base + ICU_NITSR); + + return 0; +} + +static void rzv2h_clear_irq_int(struct rzv2h_icu_priv *priv, unsigned int hwirq) +{ + unsigned int irq_nr = hwirq - ICU_IRQ_START; + u32 isctr, iitsr, iitsel; + u32 bit = BIT(irq_nr); + + isctr = readl_relaxed(priv->base + ICU_ISCTR); + iitsr = readl_relaxed(priv->base + ICU_IITSR); + iitsel = ICU_IITSR_IITSEL_GET(iitsr, irq_nr); + + /* + * When level sensing is used, the interrupt flag gets automatically cleared when the + * interrupt signal is de-asserted by the source of the interrupt request, therefore clear + * the interrupt only for edge triggered interrupts. + */ + if ((isctr & bit) && (iitsel != ICU_IRQ_LEVEL_LOW)) + writel_relaxed(bit, priv->base + ICU_ISCLR); +} + +static int rzv2h_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct rzv2h_icu_priv *priv = irq_data_to_priv(d); + unsigned int hwirq = irqd_to_hwirq(d); + u32 irq_nr = hwirq - ICU_IRQ_START; + u32 iitsr, sense; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_LEVEL_LOW: + sense = ICU_IRQ_LEVEL_LOW; + break; + + case IRQ_TYPE_EDGE_FALLING: + sense = ICU_IRQ_EDGE_FALLING; + break; + + case IRQ_TYPE_EDGE_RISING: + sense = ICU_IRQ_EDGE_RISING; + break; + + case IRQ_TYPE_EDGE_BOTH: + sense = ICU_IRQ_EDGE_BOTH; + break; + + default: + return -EINVAL; + } + + guard(raw_spinlock)(&priv->lock); + iitsr = readl_relaxed(priv->base + ICU_IITSR); + iitsr &= ~ICU_IITSR_IITSEL_MASK(irq_nr); + iitsr |= ICU_IITSR_IITSEL_PREP(sense, irq_nr); + rzv2h_clear_irq_int(priv, hwirq); + writel_relaxed(iitsr, priv->base + ICU_IITSR); + + return 0; +} + +static void rzv2h_clear_tint_int(struct rzv2h_icu_priv *priv, unsigned int hwirq) +{ + unsigned int tint_nr = hwirq - ICU_TINT_START; + int titsel_n = ICU_TITSR_TITSEL_N(tint_nr); + u32 tsctr, titsr, titsel; + u32 bit = BIT(tint_nr); + int k = tint_nr / 16; + + tsctr = readl_relaxed(priv->base + ICU_TSCTR); + titsr = readl_relaxed(priv->base + ICU_TITSR(k)); + titsel = ICU_TITSR_TITSEL_GET(titsr, titsel_n); + + /* + * Writing 1 to the corresponding flag from register ICU_TSCTR only has effect if + * TSTATn = 1b and if it's a rising edge or a falling edge interrupt. + */ + if ((tsctr & bit) && ((titsel == ICU_TINT_EDGE_RISING) || + (titsel == ICU_TINT_EDGE_FALLING))) + writel_relaxed(bit, priv->base + ICU_TSCLR); +} + +static int rzv2h_tint_set_type(struct irq_data *d, unsigned int type) +{ + u32 titsr, titsr_k, titsel_n, tien; + struct rzv2h_icu_priv *priv; + u32 tssr, tssr_k, tssel_n; + unsigned int hwirq; + u32 tint, sense; + int tint_nr; + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_LEVEL_LOW: + sense = ICU_TINT_LEVEL_LOW; + break; + + case IRQ_TYPE_LEVEL_HIGH: + sense = ICU_TINT_LEVEL_HIGH; + break; + + case IRQ_TYPE_EDGE_RISING: + sense = ICU_TINT_EDGE_RISING; + break; + + case IRQ_TYPE_EDGE_FALLING: + sense = ICU_TINT_EDGE_FALLING; + break; + + default: + return -EINVAL; + } + + tint = (u32)(uintptr_t)irq_data_get_irq_chip_data(d); + if (tint > ICU_PB5_TINT) + return -EINVAL; + + priv = irq_data_to_priv(d); + hwirq = irqd_to_hwirq(d); + + tint_nr = hwirq - ICU_TINT_START; + + tssr_k = ICU_TSSR_K(tint_nr); + tssel_n = ICU_TSSR_TSSEL_N(tint_nr); + + titsr_k = ICU_TITSR_K(tint_nr); + titsel_n = ICU_TITSR_TITSEL_N(tint_nr); + tien = ICU_TSSR_TIEN(titsel_n); + + guard(raw_spinlock)(&priv->lock); + + tssr = readl_relaxed(priv->base + ICU_TSSR(tssr_k)); + tssr &= ~(ICU_TSSR_TSSEL_MASK(tssel_n) | tien); + tssr |= ICU_TSSR_TSSEL_PREP(tint, tssel_n); + + writel_relaxed(tssr, priv->base + ICU_TSSR(tssr_k)); + + titsr = readl_relaxed(priv->base + ICU_TITSR(titsr_k)); + titsr &= ~ICU_TITSR_TITSEL_MASK(titsel_n); + titsr |= ICU_TITSR_TITSEL_PREP(sense, titsel_n); + + writel_relaxed(titsr, priv->base + ICU_TITSR(titsr_k)); + + rzv2h_clear_tint_int(priv, hwirq); + + writel_relaxed(tssr | tien, priv->base + ICU_TSSR(tssr_k)); + + return 0; +} + +static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type) +{ + unsigned int hw_irq = irqd_to_hwirq(d); + int ret; + + if (hw_irq >= ICU_TINT_START) + ret = rzv2h_tint_set_type(d, type); + else if (hw_irq >= ICU_IRQ_START) + ret = rzv2h_irq_set_type(d, type); + else + ret = rzv2h_nmi_set_type(d, type); + + if (ret) + return ret; + + return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH); +} + +static const struct irq_chip rzv2h_icu_chip = { + .name = "rzv2h-icu", + .irq_eoi = rzv2h_icu_eoi, + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_disable = rzv2h_icu_irq_disable, + .irq_enable = rzv2h_icu_irq_enable, + .irq_get_irqchip_state = irq_chip_get_parent_state, + .irq_set_irqchip_state = irq_chip_set_parent_state, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_type = rzv2h_icu_set_type, + .irq_set_affinity = irq_chip_set_affinity_parent, + .flags = IRQCHIP_SET_TYPE_MASKED, +}; + +static int rzv2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, + void *arg) +{ + struct rzv2h_icu_priv *priv = domain->host_data; + unsigned long tint = 0; + irq_hw_number_t hwirq; + unsigned int type; + int ret; + + ret = irq_domain_translate_twocell(domain, arg, &hwirq, &type); + if (ret) + return ret; + + /* + * For TINT interrupts the hwirq and TINT are encoded in + * fwspec->param[0]. + * hwirq is embedded in bits 0-15. + * TINT is embedded in bits 16-31. + */ + if (hwirq >= ICU_TINT_START) { + tint = ICU_TINT_EXTRACT_GPIOINT(hwirq); + hwirq = ICU_TINT_EXTRACT_HWIRQ(hwirq); + + if (hwirq < ICU_TINT_START) + return -EINVAL; + } + + if (hwirq > (ICU_NUM_IRQ - 1)) + return -EINVAL; + + ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, priv->irqchip, + (void *)(uintptr_t)tint); + if (ret) + return ret; + + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &priv->fwspec[hwirq]); +} + +static const struct irq_domain_ops rzv2h_icu_domain_ops = { + .alloc = rzv2h_icu_alloc, + .free = irq_domain_free_irqs_common, + .translate = irq_domain_translate_twocell, +}; + +static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device_node *np) +{ + struct of_phandle_args map; + unsigned int i; + int ret; + + for (i = 0; i < ICU_NUM_IRQ; i++) { + ret = of_irq_parse_one(np, i, &map); + if (ret) + return ret; + + of_phandle_args_to_fwspec(np, map.args, map.args_count, &priv->fwspec[i]); + } + + return 0; +} + +static int rzv2h_icu_init(struct device_node *node, struct device_node *parent) +{ + struct irq_domain *irq_domain, *parent_domain; + struct rzv2h_icu_priv *rzv2h_icu_data; + struct platform_device *pdev; + struct reset_control *resetn; + int ret; + + pdev = of_find_device_by_node(node); + if (!pdev) + return -ENODEV; + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + dev_err(&pdev->dev, "cannot find parent domain\n"); + ret = -ENODEV; + goto put_dev; + } + + rzv2h_icu_data = devm_kzalloc(&pdev->dev, sizeof(*rzv2h_icu_data), GFP_KERNEL); + if (!rzv2h_icu_data) { + ret = -ENOMEM; + goto put_dev; + } + + rzv2h_icu_data->irqchip = &rzv2h_icu_chip; + + rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL); + if (IS_ERR(rzv2h_icu_data->base)) { + ret = PTR_ERR(rzv2h_icu_data->base); + goto put_dev; + } + + ret = rzv2h_icu_parse_interrupts(rzv2h_icu_data, node); + if (ret) { + dev_err(&pdev->dev, "cannot parse interrupts: %d\n", ret); + goto put_dev; + } + + resetn = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(resetn)) { + ret = PTR_ERR(resetn); + goto put_dev; + } + + ret = reset_control_deassert(resetn); + if (ret) { + dev_err(&pdev->dev, "failed to deassert resetn pin, %d\n", ret); + goto put_dev; + } + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "pm_runtime_resume_and_get failed: %d\n", ret); + goto pm_disable; + } + + raw_spin_lock_init(&rzv2h_icu_data->lock); + + irq_domain = irq_domain_add_hierarchy(parent_domain, 0, ICU_NUM_IRQ, node, + &rzv2h_icu_domain_ops, rzv2h_icu_data); + if (!irq_domain) { + dev_err(&pdev->dev, "failed to add irq domain\n"); + ret = -ENOMEM; + goto pm_put; + } + + /* + * coccicheck complains about a missing put_device call before returning, but it's a false + * positive. We still need &pdev->dev after successfully returning from this function. + */ + return 0; + +pm_put: + pm_runtime_put(&pdev->dev); +pm_disable: + pm_runtime_disable(&pdev->dev); + reset_control_assert(resetn); +put_dev: + put_device(&pdev->dev); + + return ret; +} + +IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu) +IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_init) +IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu) +MODULE_AUTHOR("Fabrizio Castro "); +MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver"); diff --git a/drivers/irqchip/irq-riscv-aplic-main.c b/drivers/irqchip/irq-riscv-aplic-main.c index 900e72541db9e5..93e7c51f944abe 100644 --- a/drivers/irqchip/irq-riscv-aplic-main.c +++ b/drivers/irqchip/irq-riscv-aplic-main.c @@ -207,7 +207,8 @@ static int aplic_probe(struct platform_device *pdev) else rc = aplic_direct_setup(dev, regs); if (rc) - dev_err(dev, "failed to setup APLIC in %s mode\n", msi_mode ? "MSI" : "direct"); + dev_err_probe(dev, rc, "failed to setup APLIC in %s mode\n", + msi_mode ? "MSI" : "direct"); #ifdef CONFIG_ACPI if (!acpi_disabled) diff --git a/drivers/irqchip/irq-riscv-aplic-msi.c b/drivers/irqchip/irq-riscv-aplic-msi.c index 945bff28265cdc..fb8d1838609fb5 100644 --- a/drivers/irqchip/irq-riscv-aplic-msi.c +++ b/drivers/irqchip/irq-riscv-aplic-msi.c @@ -266,6 +266,9 @@ int aplic_msi_setup(struct device *dev, void __iomem *regs) if (msi_domain) dev_set_msi_domain(dev, msi_domain); } + + if (!dev_get_msi_domain(dev)) + return -EPROBE_DEFER; } if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN, &aplic_msi_template, diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index 36dbcf2d728a54..bf69a4802b71e7 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -252,11 +252,10 @@ static int plic_irq_suspend(void) priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; - for (i = 0; i < priv->nr_irqs; i++) - if (readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)) - __set_bit(i, priv->prio_save); - else - __clear_bit(i, priv->prio_save); + for (i = 0; i < priv->nr_irqs; i++) { + __assign_bit(i, priv->prio_save, + readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)); + } for_each_cpu(cpu, cpu_present_mask) { struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); diff --git a/drivers/irqchip/irq-stm32mp-exti.c b/drivers/irqchip/irq-stm32mp-exti.c index 33e0cfdea65452..cb83d6cc6113ae 100644 --- a/drivers/irqchip/irq-stm32mp-exti.c +++ b/drivers/irqchip/irq-stm32mp-exti.c @@ -696,8 +696,7 @@ static int stm32mp_exti_probe(struct platform_device *pdev) if (ret) return ret; - if (of_property_read_bool(np, "interrupts-extended")) - host_data->dt_has_irqs_desc = true; + host_data->dt_has_irqs_desc = of_property_present(np, "interrupts-extended"); return 0; } diff --git a/drivers/irqchip/irq-thead-c900-aclint-sswi.c b/drivers/irqchip/irq-thead-c900-aclint-sswi.c new file mode 100644 index 00000000000000..b0e366ade4271e --- /dev/null +++ b/drivers/irqchip/irq-thead-c900-aclint-sswi.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Inochi Amaoto + */ + +#define pr_fmt(fmt) "thead-c900-aclint-sswi: " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define THEAD_ACLINT_xSWI_REGISTER_SIZE 4 + +#define THEAD_C9XX_CSR_SXSTATUS 0x5c0 +#define THEAD_C9XX_SXSTATUS_CLINTEE BIT(17) + +static int sswi_ipi_virq __ro_after_init; +static DEFINE_PER_CPU(void __iomem *, sswi_cpu_regs); + +static void thead_aclint_sswi_ipi_send(unsigned int cpu) +{ + writel_relaxed(0x1, per_cpu(sswi_cpu_regs, cpu)); +} + +static void thead_aclint_sswi_ipi_clear(void) +{ + writel_relaxed(0x0, this_cpu_read(sswi_cpu_regs)); +} + +static void thead_aclint_sswi_ipi_handle(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + + csr_clear(CSR_IP, IE_SIE); + thead_aclint_sswi_ipi_clear(); + + ipi_mux_process(); + + chained_irq_exit(chip, desc); +} + +static int thead_aclint_sswi_starting_cpu(unsigned int cpu) +{ + enable_percpu_irq(sswi_ipi_virq, irq_get_trigger_type(sswi_ipi_virq)); + + return 0; +} + +static int thead_aclint_sswi_dying_cpu(unsigned int cpu) +{ + thead_aclint_sswi_ipi_clear(); + + disable_percpu_irq(sswi_ipi_virq); + + return 0; +} + +static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, + void __iomem *reg) +{ + struct of_phandle_args parent; + unsigned long hartid; + u32 contexts, i; + int rc, cpu; + + contexts = of_irq_count(to_of_node(fwnode)); + if (!(contexts)) { + pr_err("%pfwP: no ACLINT SSWI context available\n", fwnode); + return -EINVAL; + } + + for (i = 0; i < contexts; i++) { + rc = of_irq_parse_one(to_of_node(fwnode), i, &parent); + if (rc) + return rc; + + rc = riscv_of_parent_hartid(parent.np, &hartid); + if (rc) + return rc; + + if (parent.args[0] != RV_IRQ_SOFT) + return -ENOTSUPP; + + cpu = riscv_hartid_to_cpuid(hartid); + + per_cpu(sswi_cpu_regs, cpu) = reg + i * THEAD_ACLINT_xSWI_REGISTER_SIZE; + } + + pr_info("%pfwP: register %u CPU%s\n", fwnode, contexts, str_plural(contexts)); + + return 0; +} + +static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) +{ + struct irq_domain *domain; + void __iomem *reg; + int virq, rc; + + /* If it is T-HEAD CPU, check whether SSWI is enabled */ + if (riscv_cached_mvendorid(0) == THEAD_VENDOR_ID && + !(csr_read(THEAD_C9XX_CSR_SXSTATUS) & THEAD_C9XX_SXSTATUS_CLINTEE)) + return -ENOTSUPP; + + if (!is_of_node(fwnode)) + return -EINVAL; + + reg = of_iomap(to_of_node(fwnode), 0); + if (!reg) + return -ENOMEM; + + /* Parse SSWI setting */ + rc = thead_aclint_sswi_parse_irq(fwnode, reg); + if (rc < 0) + return rc; + + /* If mulitple SSWI devices are present, do not register irq again */ + if (sswi_ipi_virq) + return 0; + + /* Find riscv intc domain and create IPI irq mapping */ + domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY); + if (!domain) { + pr_err("%pfwP: Failed to find INTC domain\n", fwnode); + return -ENOENT; + } + + sswi_ipi_virq = irq_create_mapping(domain, RV_IRQ_SOFT); + if (!sswi_ipi_virq) { + pr_err("unable to create ACLINT SSWI IRQ mapping\n"); + return -ENOMEM; + } + + /* Register SSWI irq and handler */ + virq = ipi_mux_create(BITS_PER_BYTE, thead_aclint_sswi_ipi_send); + if (virq <= 0) { + pr_err("unable to create muxed IPIs\n"); + irq_dispose_mapping(sswi_ipi_virq); + return virq < 0 ? virq : -ENOMEM; + } + + irq_set_chained_handler(sswi_ipi_virq, thead_aclint_sswi_ipi_handle); + + cpuhp_setup_state(CPUHP_AP_IRQ_THEAD_ACLINT_SSWI_STARTING, + "irqchip/thead-aclint-sswi:starting", + thead_aclint_sswi_starting_cpu, + thead_aclint_sswi_dying_cpu); + + riscv_ipi_set_virq_range(virq, BITS_PER_BYTE); + + /* Announce that SSWI is providing IPIs */ + pr_info("providing IPIs using THEAD ACLINT SSWI\n"); + + return 0; +} + +static int __init thead_aclint_sswi_early_probe(struct device_node *node, + struct device_node *parent) +{ + return thead_aclint_sswi_probe(&node->fwnode); +} +IRQCHIP_DECLARE(thead_aclint_sswi, "thead,c900-aclint-sswi", thead_aclint_sswi_early_probe); diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c index b5dddb3c1568ea..cc219f28d317fe 100644 --- a/drivers/irqchip/irq-ts4800.c +++ b/drivers/irqchip/irq-ts4800.c @@ -154,7 +154,7 @@ MODULE_DEVICE_TABLE(of, ts4800_ic_of_match); static struct platform_driver ts4800_ic_driver = { .probe = ts4800_ic_probe, - .remove_new = ts4800_ic_remove, + .remove = ts4800_ic_remove, .driver = { .name = "ts4800-irqc", .of_match_table = ts4800_ic_of_match, diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index ca471c6fee998b..0abc8934c2ee00 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -69,7 +69,7 @@ static void fpga_irq_print_chip(struct irq_data *d, struct seq_file *p) { struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); - seq_printf(p, irq_domain_get_of_node(f->domain)->name); + seq_puts(p, irq_domain_get_of_node(f->domain)->name); } static const struct irq_chip fpga_chip = { diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index e5a483fd9ad86f..45ff0e198f8f50 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -25,8 +25,8 @@ * Bit 8 = 0x00100 = uLaw (instead of aLaw) * Bit 9 = 0x00200 = Disable DTMF detect on all B-channels via hardware * Bit 10 = spare - * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwhise auto) - * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwhise auto) + * Bit 11 = 0x00800 = Force PCM bus into slave mode. (otherwise auto) + * or Bit 12 = 0x01000 = Force PCM bus into master mode. (otherwise auto) * Bit 13 = spare * Bit 14 = 0x04000 = Use external ram (128K) * Bit 15 = 0x08000 = Use external ram (512K) @@ -41,7 +41,7 @@ * port: (optional or required for all ports on all installed cards) * HFC-4S/HFC-8S only bits: * Bit 0 = 0x001 = Use master clock for this S/T interface - * (ony once per chip). + * (only once per chip). * Bit 1 = 0x002 = transmitter line setup (non capacitive mode) * Don't use this unless you know what you are doing! * Bit 2 = 0x004 = Disable E-channel. (No E-channel processing) @@ -82,7 +82,7 @@ * By default (0), the PCM bus id is 100 for the card that is PCM master. * If multiple cards are PCM master (because they are not interconnected), * each card with PCM master will have increasing PCM id. - * All PCM busses with the same ID are expected to be connected and have + * All PCM buses with the same ID are expected to be connected and have * common time slots slots. * Only one chip of the PCM bus must be master, the others slave. * -1 means no support of PCM bus not even. @@ -930,7 +930,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) if (newmaster) { hc = newmaster; if (debug & DEBUG_HFCMULTI_PLXSD) - printk(KERN_DEBUG "id=%d (0x%p) = syncronized with " + printk(KERN_DEBUG "id=%d (0x%p) = synchronized with " "interface.\n", hc->id, hc); /* Enable new sync master */ plx_acc_32 = hc->plx_membase + PLX_GPIOC; @@ -949,7 +949,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) hc = pcmmaster; if (debug & DEBUG_HFCMULTI_PLXSD) printk(KERN_DEBUG - "id=%d (0x%p) = PCM master syncronized " + "id=%d (0x%p) = PCM master synchronized " "with QUARTZ\n", hc->id, hc); if (hc->ctype == HFC_TYPE_E1) { /* Use the crystal clock for the PCM @@ -2001,7 +2001,7 @@ hfcmulti_tx(struct hfc_multi *hc, int ch) if (Zspace <= 0) Zspace += hc->Zlen; Zspace -= 4; /* keep not too full, so pointers will not overrun */ - /* fill transparent data only to maxinum transparent load (minus 4) */ + /* fill transparent data only to maximum transparent load (minus 4) */ if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) Zspace = Zspace - hc->Zlen + hc->max_trans; if (Zspace <= 0) /* no space of 4 bytes */ @@ -4672,7 +4672,7 @@ init_e1_port_hw(struct hfc_multi *hc, struct hm_map *m) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: PORT set optical " - "interfacs: card(%d) " + "interface: card(%d) " "port(%d)\n", __func__, HFC_cnt + 1, 1); diff --git a/drivers/leds/blink/leds-bcm63138.c b/drivers/leds/blink/leds-bcm63138.c index 3a5e0b98bfbcf3..ef2e511438ccbf 100644 --- a/drivers/leds/blink/leds-bcm63138.c +++ b/drivers/leds/blink/leds-bcm63138.c @@ -2,6 +2,8 @@ /* * Copyright (C) 2021 Rafał Miłecki */ +#include +#include #include #include #include @@ -19,8 +21,10 @@ #define BCM63138_LEDS_PER_REG (32 / BCM63138_LED_BITS) /* 8 */ #define BCM63138_GLB_CTRL 0x00 -#define BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL 0x00000002 -#define BCM63138_GLB_CTRL_SERIAL_LED_EN_POL 0x00000008 +#define BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL BIT(1) +#define BCM63138_GLB_CTRL_SERIAL_LED_CLK_POL BIT(2) +#define BCM63138_GLB_CTRL_SERIAL_LED_EN_POL BIT(3) +#define BCM63138_GLB_CTRL_SERIAL_LED_MSB_FIRST BIT(4) #define BCM63138_MASK 0x04 #define BCM63138_HW_LED_EN 0x08 #define BCM63138_SERIAL_LED_SHIFT_SEL 0x0c @@ -33,6 +37,7 @@ #define BCM63138_BRIGHT_CTRL3 0x28 #define BCM63138_BRIGHT_CTRL4 0x2c #define BCM63138_POWER_LED_CFG 0x30 +#define BCM63138_POWER_LUT_BASE0 0x34 /* -> b0 */ #define BCM63138_HW_POLARITY 0xb4 #define BCM63138_SW_DATA 0xb8 #define BCM63138_SW_POLARITY 0xbc @@ -125,17 +130,14 @@ static void bcm63138_leds_brightness_set(struct led_classdev *led_cdev, { struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev); struct bcm63138_leds *leds = led->leds; - unsigned long flags; - spin_lock_irqsave(&leds->lock, flags); + guard(spinlock_irqsave)(&leds->lock); bcm63138_leds_enable_led(leds, led, value); if (!value) bcm63138_leds_set_flash_rate(leds, led, 0); else bcm63138_leds_set_bright(leds, led, value); - - spin_unlock_irqrestore(&leds->lock, flags); } static int bcm63138_leds_blink_set(struct led_classdev *led_cdev, @@ -144,7 +146,6 @@ static int bcm63138_leds_blink_set(struct led_classdev *led_cdev, { struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev); struct bcm63138_leds *leds = led->leds; - unsigned long flags; u8 value; if (!*delay_on && !*delay_off) { @@ -179,13 +180,11 @@ static int bcm63138_leds_blink_set(struct led_classdev *led_cdev, return -EINVAL; } - spin_lock_irqsave(&leds->lock, flags); + guard(spinlock_irqsave)(&leds->lock); bcm63138_leds_enable_led(leds, led, BCM63138_MAX_BRIGHTNESS); bcm63138_leds_set_flash_rate(leds, led, value); - spin_unlock_irqrestore(&leds->lock, flags); - return 0; } @@ -259,7 +258,7 @@ static int bcm63138_leds_probe(struct platform_device *pdev) struct device_node *np = dev_of_node(&pdev->dev); struct device *dev = &pdev->dev; struct bcm63138_leds *leds; - struct device_node *child; + u32 shift_bits; leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); if (!leds) @@ -273,6 +272,12 @@ static int bcm63138_leds_probe(struct platform_device *pdev) spin_lock_init(&leds->lock); + /* If this property is not present, we use boot defaults */ + if (!of_property_read_u32(np, "brcm,serial-shift-bits", &shift_bits)) { + bcm63138_leds_write(leds, BCM63138_SERIAL_LED_SHIFT_SEL, + GENMASK(shift_bits - 1, 0)); + } + bcm63138_leds_write(leds, BCM63138_GLB_CTRL, BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL | BCM63138_GLB_CTRL_SERIAL_LED_EN_POL); @@ -280,7 +285,7 @@ static int bcm63138_leds_probe(struct platform_device *pdev) bcm63138_leds_write(leds, BCM63138_SERIAL_LED_POLARITY, 0); bcm63138_leds_write(leds, BCM63138_PARALLEL_LED_POLARITY, 0); - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { bcm63138_leds_create_led(leds, child); } diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c index 7b04ea14626058..effaaaf302b588 100644 --- a/drivers/leds/blink/leds-lgm-sso.c +++ b/drivers/leds/blink/leds-lgm-sso.c @@ -861,7 +861,7 @@ MODULE_DEVICE_TABLE(of, of_sso_led_match); static struct platform_driver intel_sso_led_driver = { .probe = intel_sso_led_probe, - .remove_new = intel_sso_led_remove, + .remove = intel_sso_led_remove, .driver = { .name = "lgm-ssoled", .of_match_table = of_sso_led_match, diff --git a/drivers/leds/flash/leds-aat1290.c b/drivers/leds/flash/leds-aat1290.c index c7b6a1f0128828..49251cfd33509e 100644 --- a/drivers/leds/flash/leds-aat1290.c +++ b/drivers/leds/flash/leds-aat1290.c @@ -536,7 +536,7 @@ MODULE_DEVICE_TABLE(of, aat1290_led_dt_match); static struct platform_driver aat1290_led_driver = { .probe = aat1290_led_probe, - .remove_new = aat1290_led_remove, + .remove = aat1290_led_remove, .driver = { .name = "aat1290", .of_match_table = aat1290_led_dt_match, diff --git a/drivers/leds/flash/leds-ktd2692.c b/drivers/leds/flash/leds-ktd2692.c index 16a01a200c0b75..0f16eefcfe4cd3 100644 --- a/drivers/leds/flash/leds-ktd2692.c +++ b/drivers/leds/flash/leds-ktd2692.c @@ -292,6 +292,7 @@ static int ktd2692_probe(struct platform_device *pdev) fled_cdev = &led->fled_cdev; led_cdev = &fled_cdev->led_cdev; + led->props.timing = ktd2692_timing; ret = ktd2692_parse_dt(led, &pdev->dev, &led_cfg); if (ret) @@ -343,12 +344,12 @@ static struct platform_driver ktd2692_driver = { .of_match_table = ktd2692_match, }, .probe = ktd2692_probe, - .remove_new = ktd2692_remove, + .remove = ktd2692_remove, }; module_platform_driver(ktd2692_driver); -MODULE_IMPORT_NS(EXPRESSWIRE); +MODULE_IMPORT_NS("EXPRESSWIRE"); MODULE_AUTHOR("Ingi Kim "); MODULE_DESCRIPTION("Kinetic KTD2692 LED driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/leds/flash/leds-max77693.c b/drivers/leds/flash/leds-max77693.c index 90d78b3d22f882..daee109861086b 100644 --- a/drivers/leds/flash/leds-max77693.c +++ b/drivers/leds/flash/leds-max77693.c @@ -1042,7 +1042,7 @@ MODULE_DEVICE_TABLE(of, max77693_led_dt_match); static struct platform_driver max77693_led_driver = { .probe = max77693_led_probe, - .remove_new = max77693_led_remove, + .remove = max77693_led_remove, .driver = { .name = "max77693-led", .of_match_table = max77693_led_dt_match, diff --git a/drivers/leds/flash/leds-mt6360.c b/drivers/leds/flash/leds-mt6360.c index 4c74f1cf01f00d..462a902f54e04c 100644 --- a/drivers/leds/flash/leds-mt6360.c +++ b/drivers/leds/flash/leds-mt6360.c @@ -784,7 +784,6 @@ static void mt6360_v4l2_flash_release(struct mt6360_priv *priv) static int mt6360_led_probe(struct platform_device *pdev) { struct mt6360_priv *priv; - struct fwnode_handle *child; size_t count; int i = 0, ret; @@ -811,7 +810,7 @@ static int mt6360_led_probe(struct platform_device *pdev) return -ENODEV; } - device_for_each_child_node(&pdev->dev, child) { + device_for_each_child_node_scoped(&pdev->dev, child) { struct mt6360_led *led = priv->leds + i; struct led_init_data init_data = { .fwnode = child, }; u32 reg, led_color; @@ -887,7 +886,7 @@ static struct platform_driver mt6360_led_driver = { .of_match_table = mt6360_led_of_id, }, .probe = mt6360_led_probe, - .remove_new = mt6360_led_remove, + .remove = mt6360_led_remove, }; module_platform_driver(mt6360_led_driver); diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c index 912d9d6223207f..dbdbe92309db96 100644 --- a/drivers/leds/flash/leds-mt6370-flash.c +++ b/drivers/leds/flash/leds-mt6370-flash.c @@ -509,7 +509,6 @@ 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; @@ -529,22 +528,18 @@ static int mt6370_led_probe(struct platform_device *pdev) if (!priv->regmap) return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n"); - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(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); + if (ret) return ret; - } ret = mt6370_led_register(dev, led, child); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } i++; } diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c index 41ce034f700ee5..b4c19be51c4da7 100644 --- a/drivers/leds/flash/leds-qcom-flash.c +++ b/drivers/leds/flash/leds-qcom-flash.c @@ -812,7 +812,6 @@ 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; @@ -896,7 +895,7 @@ static int qcom_flash_led_probe(struct platform_device *pdev) if (!flash_data->v4l2_flash) return -ENOMEM; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) { rc = -ENOMEM; @@ -914,7 +913,6 @@ static int qcom_flash_led_probe(struct platform_device *pdev) return 0; release: - fwnode_handle_put(child); 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; @@ -942,7 +940,7 @@ static struct platform_driver qcom_flash_led_driver = { .of_match_table = qcom_flash_led_match_table, }, .probe = qcom_flash_led_probe, - .remove_new = qcom_flash_led_remove, + .remove = qcom_flash_led_remove, }; module_platform_driver(qcom_flash_led_driver); diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c index eef426924eafb4..6b051f182b72dd 100644 --- a/drivers/leds/flash/leds-rt8515.c +++ b/drivers/leds/flash/leds-rt8515.c @@ -388,7 +388,7 @@ static struct platform_driver rt8515_driver = { .of_match_table = rt8515_match, }, .probe = rt8515_probe, - .remove_new = rt8515_remove, + .remove = rt8515_remove, }; module_platform_driver(rt8515_driver); diff --git a/drivers/leds/flash/leds-sgm3140.c b/drivers/leds/flash/leds-sgm3140.c index db0ac6641954e9..3c01739c0b4641 100644 --- a/drivers/leds/flash/leds-sgm3140.c +++ b/drivers/leds/flash/leds-sgm3140.c @@ -300,7 +300,7 @@ MODULE_DEVICE_TABLE(of, sgm3140_dt_match); static struct platform_driver sgm3140_driver = { .probe = sgm3140_probe, - .remove_new = sgm3140_remove, + .remove = sgm3140_remove, .driver = { .name = "sgm3140", .of_match_table = sgm3140_dt_match, diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c index 6fe9d700dfef6e..f4e26ce84862c0 100644 --- a/drivers/leds/led-class-flash.c +++ b/drivers/leds/led-class-flash.c @@ -12,7 +12,6 @@ #include #include #include -#include "leds.h" #define has_flash_op(fled_cdev, op) \ (fled_cdev && fled_cdev->ops->op) diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c index 30c1ecb5f361ee..b2a87c9948165e 100644 --- a/drivers/leds/led-class-multicolor.c +++ b/drivers/leds/led-class-multicolor.c @@ -11,8 +11,6 @@ #include #include -#include "leds.h" - int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, enum led_brightness brightness) { diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 06b97fd49ad9a2..2a04ac61574d5f 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -25,15 +25,20 @@ static DEFINE_MUTEX(leds_lookup_lock); static LIST_HEAD(leds_lookup_list); +static struct workqueue_struct *leds_wq; + static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); + unsigned int brightness; - /* no lock needed for this */ + mutex_lock(&led_cdev->led_access); led_update_brightness(led_cdev); + brightness = led_cdev->brightness; + mutex_unlock(&led_cdev->led_access); - return sprintf(buf, "%u\n", led_cdev->brightness); + return sprintf(buf, "%u\n", brightness); } static ssize_t brightness_store(struct device *dev, @@ -57,7 +62,6 @@ static ssize_t brightness_store(struct device *dev, if (state == LED_OFF) led_trigger_remove(led_cdev); led_set_brightness(led_cdev, state); - flush_work(&led_cdev->set_brightness_work); ret = size; unlock: @@ -70,8 +74,13 @@ static ssize_t max_brightness_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); + unsigned int max_brightness; - return sprintf(buf, "%u\n", led_cdev->max_brightness); + mutex_lock(&led_cdev->led_access); + max_brightness = led_cdev->max_brightness; + mutex_unlock(&led_cdev->led_access); + + return sprintf(buf, "%u\n", max_brightness); } static DEVICE_ATTR_RO(max_brightness); @@ -549,6 +558,8 @@ int led_classdev_register_ext(struct device *parent, led_update_brightness(led_cdev); + led_cdev->wq = leds_wq; + led_init_core(led_cdev); #ifdef CONFIG_LEDS_TRIGGERS @@ -667,12 +678,19 @@ EXPORT_SYMBOL_GPL(devm_led_classdev_unregister); static int __init leds_init(void) { + leds_wq = alloc_ordered_workqueue("leds", 0); + if (!leds_wq) { + pr_err("Failed to create LEDs ordered workqueue\n"); + return -ENOMEM; + } + return class_register(&leds_class); } static void __exit leds_exit(void) { class_unregister(&leds_class); + destroy_workqueue(leds_wq); } subsys_initcall(leds_init); diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 001c290bc07b7d..f6c46d2e5276b5 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -273,7 +273,7 @@ void led_blink_set_nosleep(struct led_classdev *led_cdev, unsigned long delay_on led_cdev->delayed_delay_on = delay_on; led_cdev->delayed_delay_off = delay_off; set_bit(LED_SET_BLINK, &led_cdev->work_flags); - schedule_work(&led_cdev->set_brightness_work); + queue_work(led_cdev->wq, &led_cdev->set_brightness_work); return; } @@ -304,7 +304,7 @@ void led_set_brightness(struct led_classdev *led_cdev, unsigned int brightness) */ if (!brightness) { set_bit(LED_BLINK_DISABLE, &led_cdev->work_flags); - schedule_work(&led_cdev->set_brightness_work); + queue_work(led_cdev->wq, &led_cdev->set_brightness_work); } else { set_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags); @@ -340,7 +340,7 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev, unsigned int value) set_bit(LED_SET_BRIGHTNESS_OFF, &led_cdev->work_flags); } - schedule_work(&led_cdev->set_brightness_work); + queue_work(led_cdev->wq, &led_cdev->set_brightness_work); } EXPORT_SYMBOL_GPL(led_set_brightness_nopm); diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 81238376484beb..ef5c6c4667ab18 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -226,7 +226,7 @@ static struct platform_driver pm860x_led_driver = { .name = "88pm860x-led", }, .probe = pm860x_led_probe, - .remove_new = pm860x_led_remove, + .remove = pm860x_led_remove, }; module_platform_driver(pm860x_led_driver); diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c index d89a4dca50ae4a..13e5bc80e56e0e 100644 --- a/drivers/leds/leds-adp5520.c +++ b/drivers/leds/leds-adp5520.c @@ -184,7 +184,7 @@ static struct platform_driver adp5520_led_driver = { .name = "adp5520-led", }, .probe = adp5520_led_probe, - .remove_new = adp5520_led_remove, + .remove = adp5520_led_remove, }; module_platform_driver(adp5520_led_driver); diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c index f9d9844e027380..08cca128458c17 100644 --- a/drivers/leds/leds-aw200xx.c +++ b/drivers/leds/leds-aw200xx.c @@ -409,7 +409,6 @@ static int aw200xx_probe_get_display_rows(struct device *dev, static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip) { - struct fwnode_handle *child; u32 current_min, current_max, min_uA; int ret; int i; @@ -424,7 +423,7 @@ static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip) min_uA = UINT_MAX; i = 0; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct led_init_data init_data = {}; struct aw200xx_led *led; u32 source, imax; @@ -468,10 +467,8 @@ static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip) ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); - if (ret) { - fwnode_handle_put(child); + if (ret) break; - } i++; } diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c index 29f5bad6179654..592bbf4b7e3579 100644 --- a/drivers/leds/leds-bcm6328.c +++ b/drivers/leds/leds-bcm6328.c @@ -113,7 +113,7 @@ static void bcm6328_led_mode(struct bcm6328_led *led, unsigned long value) unsigned long val, shift; shift = bcm6328_pin2shift(led->pin); - if (shift / 16) + if (shift >= 16) mode = led->mem + BCM6328_REG_MODE_HI; else mode = led->mem + BCM6328_REG_MODE_LO; @@ -357,7 +357,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg, break; case LEDS_DEFSTATE_KEEP: shift = bcm6328_pin2shift(led->pin); - if (shift / 16) + if (shift >= 16) mode = mem + BCM6328_REG_MODE_HI; else mode = mem + BCM6328_REG_MODE_LO; diff --git a/drivers/leds/leds-cht-wcove.c b/drivers/leds/leds-cht-wcove.c index b4998402b8c6f0..8246f048edcb4b 100644 --- a/drivers/leds/leds-cht-wcove.c +++ b/drivers/leds/leds-cht-wcove.c @@ -461,7 +461,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cht_wc_leds_pm, cht_wc_leds_suspend, cht_wc_leds static struct platform_driver cht_wc_leds_driver = { .probe = cht_wc_leds_probe, - .remove_new = cht_wc_leds_remove, + .remove = cht_wc_leds_remove, .shutdown = cht_wc_leds_disable, .driver = { .name = "cht_wcove_leds", diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c index 82da0fe688ade9..f00b16ac158635 100644 --- a/drivers/leds/leds-clevo-mail.c +++ b/drivers/leds/leds-clevo-mail.c @@ -165,7 +165,7 @@ static void clevo_mail_led_remove(struct platform_device *pdev) } static struct platform_driver clevo_mail_led_driver = { - .remove_new = clevo_mail_led_remove, + .remove = clevo_mail_led_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c index c9914fc51f2023..7e51c374edd4e2 100644 --- a/drivers/leds/leds-cr0014114.c +++ b/drivers/leds/leds-cr0014114.c @@ -181,11 +181,10 @@ static int cr0014114_probe_dt(struct cr0014114 *priv) { size_t i = 0; struct cr0014114_led *led; - struct fwnode_handle *child; struct led_init_data init_data = {}; int ret; - device_for_each_child_node(priv->dev, child) { + device_for_each_child_node_scoped(priv->dev, child) { led = &priv->leds[i]; led->priv = priv; @@ -201,7 +200,6 @@ static int cr0014114_probe_dt(struct cr0014114 *priv) if (ret) { dev_err(priv->dev, "failed to register LED device, err %d", ret); - fwnode_handle_put(child); return ret; } diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c index f067a5f4d3c492..71209b3c8f1e69 100644 --- a/drivers/leds/leds-da903x.c +++ b/drivers/leds/leds-da903x.c @@ -133,7 +133,7 @@ static struct platform_driver da903x_led_driver = { .name = "da903x-led", }, .probe = da903x_led_probe, - .remove_new = da903x_led_remove, + .remove = da903x_led_remove, }; module_platform_driver(da903x_led_driver); diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c index 64679d62076bbb..7c9051184a5989 100644 --- a/drivers/leds/leds-da9052.c +++ b/drivers/leds/leds-da9052.c @@ -179,7 +179,7 @@ static struct platform_driver da9052_led_driver = { .name = "da9052-leds", }, .probe = da9052_led_probe, - .remove_new = da9052_led_remove, + .remove = da9052_led_remove, }; module_platform_driver(da9052_led_driver); diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c index d40194a3029f57..e26d1654bd0d35 100644 --- a/drivers/leds/leds-el15203000.c +++ b/drivers/leds/leds-el15203000.c @@ -237,22 +237,20 @@ static int el15203000_pattern_clear(struct led_classdev *ldev) static int el15203000_probe_dt(struct el15203000 *priv) { struct el15203000_led *led = priv->leds; - struct fwnode_handle *child; int ret; - device_for_each_child_node(priv->dev, child) { + device_for_each_child_node_scoped(priv->dev, child) { struct led_init_data init_data = {}; ret = fwnode_property_read_u32(child, "reg", &led->reg); if (ret) { dev_err(priv->dev, "LED without ID number"); - goto err_child_out; + return ret; } if (led->reg > U8_MAX) { dev_err(priv->dev, "LED value %d is invalid", led->reg); - ret = -EINVAL; - goto err_child_out; + return -EINVAL; } led->priv = priv; @@ -274,17 +272,13 @@ static int el15203000_probe_dt(struct el15203000 *priv) dev_err(priv->dev, "failed to register LED device %s, err %d", led->ldev.name, ret); - goto err_child_out; + return ret; } led++; } return 0; - -err_child_out: - fwnode_handle_put(child); - return ret; } static int el15203000_probe(struct spi_device *spi) diff --git a/drivers/leds/leds-expresswire.c b/drivers/leds/leds-expresswire.c index e4937a8e0f4417..bb69be228a6d3c 100644 --- a/drivers/leds/leds-expresswire.c +++ b/drivers/leds/leds-expresswire.c @@ -18,7 +18,7 @@ void expresswire_power_off(struct expresswire_common_props *props) gpiod_set_value_cansleep(props->ctrl_gpio, 0); usleep_range(props->timing.poweroff_us, props->timing.poweroff_us * 2); } -EXPORT_SYMBOL_NS_GPL(expresswire_power_off, EXPRESSWIRE); +EXPORT_SYMBOL_NS_GPL(expresswire_power_off, "EXPRESSWIRE"); void expresswire_enable(struct expresswire_common_props *props) { @@ -28,14 +28,14 @@ void expresswire_enable(struct expresswire_common_props *props) udelay(props->timing.detect_us); gpiod_set_value(props->ctrl_gpio, 1); } -EXPORT_SYMBOL_NS_GPL(expresswire_enable, EXPRESSWIRE); +EXPORT_SYMBOL_NS_GPL(expresswire_enable, "EXPRESSWIRE"); void expresswire_start(struct expresswire_common_props *props) { gpiod_set_value(props->ctrl_gpio, 1); udelay(props->timing.data_start_us); } -EXPORT_SYMBOL_NS_GPL(expresswire_start, EXPRESSWIRE); +EXPORT_SYMBOL_NS_GPL(expresswire_start, "EXPRESSWIRE"); void expresswire_end(struct expresswire_common_props *props) { @@ -44,7 +44,7 @@ void expresswire_end(struct expresswire_common_props *props) gpiod_set_value(props->ctrl_gpio, 1); udelay(props->timing.end_of_data_high_us); } -EXPORT_SYMBOL_NS_GPL(expresswire_end, EXPRESSWIRE); +EXPORT_SYMBOL_NS_GPL(expresswire_end, "EXPRESSWIRE"); void expresswire_set_bit(struct expresswire_common_props *props, bool bit) { @@ -60,7 +60,7 @@ void expresswire_set_bit(struct expresswire_common_props *props, bool bit) udelay(props->timing.short_bitset_us); } } -EXPORT_SYMBOL_NS_GPL(expresswire_set_bit, EXPRESSWIRE); +EXPORT_SYMBOL_NS_GPL(expresswire_set_bit, "EXPRESSWIRE"); void expresswire_write_u8(struct expresswire_common_props *props, u8 val) { @@ -69,4 +69,4 @@ void expresswire_write_u8(struct expresswire_common_props *props, u8 val) expresswire_set_bit(props, val & BIT(i)); expresswire_end(props); } -EXPORT_SYMBOL_NS_GPL(expresswire_write_u8, EXPRESSWIRE); +EXPORT_SYMBOL_NS_GPL(expresswire_write_u8, "EXPRESSWIRE"); diff --git a/drivers/leds/leds-gpio-register.c b/drivers/leds/leds-gpio-register.c index de3f12c2b80d7e..ccc01fa72e6f35 100644 --- a/drivers/leds/leds-gpio-register.c +++ b/drivers/leds/leds-gpio-register.c @@ -10,8 +10,8 @@ /** * gpio_led_register_device - register a gpio-led device - * @pdata: the platform data used for the new device * @id: platform ID + * @pdata: the platform data used for the new device * * Makes a copy of pdata and pdata->leds and registers a new leds-gpio device * with the result. This allows to have pdata and pdata-leds in .init.rodata diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 4d1612d557c841..a3428b22de3a19 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -21,8 +21,6 @@ #include #include -#include "leds.h" - struct gpio_led_data { struct led_classdev cdev; struct gpio_desc *gpiod; @@ -148,7 +146,6 @@ struct gpio_leds_priv { static struct gpio_leds_priv *gpio_leds_create(struct device *dev) { - struct fwnode_handle *child; struct gpio_leds_priv *priv; int count, used, ret; @@ -162,7 +159,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct device *dev) priv->num_leds = count; used = 0; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct gpio_led_data *led_dat = &priv->leds[used]; struct gpio_led led = {}; @@ -176,7 +173,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct device *dev) if (IS_ERR(led.gpiod)) { dev_err_probe(dev, PTR_ERR(led.gpiod), "Failed to get GPIO '%pfw'\n", child); - fwnode_handle_put(child); return ERR_CAST(led.gpiod); } @@ -192,10 +188,9 @@ static struct gpio_leds_priv *gpio_leds_create(struct device *dev) led.panic_indicator = 1; ret = create_gpio_led(&led, led_dat, dev, child, NULL); - if (ret < 0) { - fwnode_handle_put(child); + if (ret < 0) return ERR_PTR(ret); - } + /* Set gpiod label to match the corresponding LED name. */ gpiod_set_consumer_name(led_dat->gpiod, led_dat->cdev.dev->kobj.name); @@ -217,7 +212,6 @@ static struct gpio_desc *gpio_led_get_gpiod(struct device *dev, int idx, const struct gpio_led *template) { struct gpio_desc *gpiod; - unsigned long flags = GPIOF_OUT_INIT_LOW; int ret; /* @@ -244,10 +238,7 @@ static struct gpio_desc *gpio_led_get_gpiod(struct device *dev, int idx, if (!gpio_is_valid(template->gpio)) return ERR_PTR(-ENOENT); - if (template->active_low) - flags |= GPIOF_ACTIVE_LOW; - - ret = devm_gpio_request_one(dev, template->gpio, flags, + ret = devm_gpio_request_one(dev, template->gpio, GPIOF_OUT_INIT_LOW, template->name); if (ret < 0) return ERR_PTR(ret); @@ -256,6 +247,9 @@ static struct gpio_desc *gpio_led_get_gpiod(struct device *dev, int idx, if (!gpiod) return ERR_PTR(-EINVAL); + if (template->active_low ^ gpiod_is_active_low(gpiod)) + gpiod_toggle_active_low(gpiod); + return gpiod; } diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c index 54b5650877f700..24dc8ad27bb3c0 100644 --- a/drivers/leds/leds-lm3532.c +++ b/drivers/leds/leds-lm3532.c @@ -551,7 +551,6 @@ static void gpio_set_low_action(void *data) static int lm3532_parse_node(struct lm3532_data *priv) { - struct fwnode_handle *child = NULL; struct lm3532_led *led; int control_bank; u32 ramp_time; @@ -587,7 +586,7 @@ static int lm3532_parse_node(struct lm3532_data *priv) else priv->runtime_ramp_down = lm3532_get_ramp_index(ramp_time); - device_for_each_child_node(priv->dev, child) { + device_for_each_child_node_scoped(priv->dev, child) { struct led_init_data idata = { .fwnode = child, .default_label = ":", @@ -599,7 +598,7 @@ static int lm3532_parse_node(struct lm3532_data *priv) ret = fwnode_property_read_u32(child, "reg", &control_bank); if (ret) { dev_err(&priv->client->dev, "reg property missing\n"); - goto child_out; + return ret; } if (control_bank > LM3532_CONTROL_C) { @@ -613,7 +612,7 @@ static int lm3532_parse_node(struct lm3532_data *priv) &led->mode); if (ret) { dev_err(&priv->client->dev, "ti,led-mode property missing\n"); - goto child_out; + return ret; } if (fwnode_property_present(child, "led-max-microamp") && @@ -647,7 +646,7 @@ static int lm3532_parse_node(struct lm3532_data *priv) led->num_leds); if (ret) { dev_err(&priv->client->dev, "led-sources property missing\n"); - goto child_out; + return ret; } led->priv = priv; @@ -657,23 +656,20 @@ static int lm3532_parse_node(struct lm3532_data *priv) if (ret) { dev_err(&priv->client->dev, "led register err: %d\n", ret); - goto child_out; + return ret; } ret = lm3532_init_registers(led); if (ret) { dev_err(&priv->client->dev, "register init err: %d\n", ret); - goto child_out; + return ret; } i++; } - return 0; -child_out: - fwnode_handle_put(child); - return ret; + return 0; } static int lm3532_probe(struct i2c_client *client) diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index a3d33165d262bf..45795f2a10426a 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c @@ -744,7 +744,7 @@ static struct platform_driver lm3533_led_driver = { .name = "lm3533-leds", }, .probe = lm3533_led_probe, - .remove_new = lm3533_led_remove, + .remove = lm3533_led_remove, .shutdown = lm3533_led_shutdown, }; module_platform_driver(lm3533_led_driver); diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c index 99de2a3317271a..7ad232780a3100 100644 --- a/drivers/leds/leds-lm3697.c +++ b/drivers/leds/leds-lm3697.c @@ -202,7 +202,6 @@ static int lm3697_init(struct lm3697 *priv) static int lm3697_probe_dt(struct lm3697 *priv) { - struct fwnode_handle *child = NULL; struct device *dev = priv->dev; struct lm3697_led *led; int ret = -EINVAL; @@ -220,19 +219,18 @@ static int lm3697_probe_dt(struct lm3697 *priv) if (IS_ERR(priv->regulator)) priv->regulator = NULL; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct led_init_data init_data = {}; ret = fwnode_property_read_u32(child, "reg", &control_bank); if (ret) { dev_err(dev, "reg property missing\n"); - goto child_out; + return ret; } if (control_bank > LM3697_CONTROL_B) { dev_err(dev, "reg property is invalid\n"); - ret = -EINVAL; - goto child_out; + return -EINVAL; } led = &priv->leds[i]; @@ -262,7 +260,7 @@ static int lm3697_probe_dt(struct lm3697 *priv) led->num_leds); if (ret) { dev_err(dev, "led-sources property missing\n"); - goto child_out; + return ret; } for (j = 0; j < led->num_leds; j++) @@ -286,17 +284,13 @@ static int lm3697_probe_dt(struct lm3697 *priv) &init_data); if (ret) { dev_err(dev, "led register err: %d\n", ret); - goto child_out; + return ret; } i++; } - return ret; - -child_out: - fwnode_handle_put(child); - return ret; + return 0; } static int lm3697_probe(struct i2c_client *client) diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c index 175d4b06659bbb..02cb1565a9fb62 100644 --- a/drivers/leds/leds-lp50xx.c +++ b/drivers/leds/leds-lp50xx.c @@ -16,8 +16,6 @@ #include -#include "leds.h" - #define LP50XX_DEV_CFG0 0x00 #define LP50XX_DEV_CFG1 0x01 #define LP50XX_LED_CFG0 0x02 @@ -434,7 +432,6 @@ static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv, static int lp50xx_probe_dt(struct lp50xx *priv) { - struct fwnode_handle *child = NULL; struct fwnode_handle *led_node = NULL; struct led_init_data init_data = {}; struct led_classdev *led_cdev; @@ -454,17 +451,17 @@ static int lp50xx_probe_dt(struct lp50xx *priv) if (IS_ERR(priv->regulator)) priv->regulator = NULL; - device_for_each_child_node(priv->dev, child) { + device_for_each_child_node_scoped(priv->dev, child) { led = &priv->leds[i]; ret = fwnode_property_count_u32(child, "reg"); if (ret < 0) { dev_err(priv->dev, "reg property is invalid\n"); - goto child_out; + return ret; } ret = lp50xx_probe_leds(child, priv, led, ret); if (ret) - goto child_out; + return ret; init_data.fwnode = child; num_colors = 0; @@ -475,10 +472,8 @@ static int lp50xx_probe_dt(struct lp50xx *priv) */ mc_led_info = devm_kcalloc(priv->dev, LP50XX_LEDS_PER_MODULE, sizeof(*mc_led_info), GFP_KERNEL); - if (!mc_led_info) { - ret = -ENOMEM; - goto child_out; - } + if (!mc_led_info) + return -ENOMEM; fwnode_for_each_child_node(child, led_node) { ret = fwnode_property_read_u32(led_node, "color", @@ -486,7 +481,7 @@ static int lp50xx_probe_dt(struct lp50xx *priv) if (ret) { fwnode_handle_put(led_node); dev_err(priv->dev, "Cannot read color\n"); - goto child_out; + return ret; } mc_led_info[num_colors].color_index = color_id; @@ -504,16 +499,12 @@ static int lp50xx_probe_dt(struct lp50xx *priv) &init_data); if (ret) { dev_err(priv->dev, "led register err: %d\n", ret); - goto child_out; + return ret; } i++; } return 0; - -child_out: - fwnode_handle_put(child); - return ret; } static int lp50xx_probe(struct i2c_client *client) diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index b26bcc81d07979..14a4af361b2676 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -161,6 +161,30 @@ static int lp5562_post_init_device(struct lp55xx_chip *chip) return 0; } +static int lp5562_multicolor_brightness(struct lp55xx_led *led) +{ + struct lp55xx_chip *chip = led->chip; + static const u8 addr[] = { + LP5562_REG_R_PWM, + LP5562_REG_G_PWM, + LP5562_REG_B_PWM, + LP5562_REG_W_PWM, + }; + int ret; + int i; + + guard(mutex)(&chip->lock); + for (i = 0; i < led->mc_cdev.num_colors; i++) { + ret = lp55xx_write(chip, + addr[led->mc_cdev.subled_info[i].channel], + led->mc_cdev.subled_info[i].brightness); + if (ret) + break; + } + + return ret; +} + static int lp5562_led_brightness(struct lp55xx_led *led) { struct lp55xx_chip *chip = led->chip; @@ -364,6 +388,7 @@ static struct lp55xx_device_config lp5562_cfg = { .post_init_device = lp5562_post_init_device, .set_led_current = lp5562_set_led_current, .brightness_fn = lp5562_led_brightness, + .multicolor_brightness_fn = lp5562_multicolor_brightness, .run_engine = lp5562_run_engine, .firmware_cb = lp55xx_firmware_loaded_cb, .dev_attr_group = &lp5562_group, diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 5a2e259679cfdf..e71456a56ab8da 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -1132,9 +1132,6 @@ static int lp55xx_parse_common_child(struct device_node *np, if (ret) return ret; - if (*chan_nr < 0 || *chan_nr > cfg->max_channel) - return -EINVAL; - return 0; } diff --git a/drivers/leds/leds-max5970.c b/drivers/leds/leds-max5970.c index 56a584311581af..285074c53b2344 100644 --- a/drivers/leds/leds-max5970.c +++ b/drivers/leds/leds-max5970.c @@ -45,7 +45,7 @@ static int max5970_led_set_brightness(struct led_classdev *cdev, static int max5970_led_probe(struct platform_device *pdev) { - struct fwnode_handle *led_node, *child; + struct fwnode_handle *child; struct device *dev = &pdev->dev; struct regmap *regmap; struct max5970_led *ddata; @@ -55,7 +55,8 @@ static int max5970_led_probe(struct platform_device *pdev) if (!regmap) return -ENODEV; - led_node = device_get_named_child_node(dev->parent, "leds"); + struct fwnode_handle *led_node __free(fwnode_handle) = + device_get_named_child_node(dev->parent, "leds"); if (!led_node) return -ENODEV; diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c index 1eeac56b00146d..f8c47078a3bbf7 100644 --- a/drivers/leds/leds-max77650.c +++ b/drivers/leds/leds-max77650.c @@ -62,7 +62,6 @@ static int max77650_led_brightness_set(struct led_classdev *cdev, static int max77650_led_probe(struct platform_device *pdev) { - struct fwnode_handle *child; struct max77650_led *leds, *led; struct device *dev; struct regmap *map; @@ -84,14 +83,12 @@ static int max77650_led_probe(struct platform_device *pdev) if (!num_leds || num_leds > MAX77650_LED_NUM_LEDS) return -ENODEV; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct led_init_data init_data = {}; rv = fwnode_property_read_u32(child, "reg", ®); - if (rv || reg >= MAX77650_LED_NUM_LEDS) { - rv = -EINVAL; - goto err_node_put; - } + if (rv || reg >= MAX77650_LED_NUM_LEDS) + return -EINVAL; led = &leds[reg]; led->map = map; @@ -108,23 +105,20 @@ static int max77650_led_probe(struct platform_device *pdev) rv = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); if (rv) - goto err_node_put; + return rv; rv = regmap_write(map, led->regA, MAX77650_LED_A_DEFAULT); if (rv) - goto err_node_put; + return rv; rv = regmap_write(map, led->regB, MAX77650_LED_B_DEFAULT); if (rv) - goto err_node_put; + return rv; } return regmap_write(map, MAX77650_REG_CNFG_LED_TOP, MAX77650_LED_TOP_DEFAULT); -err_node_put: - fwnode_handle_put(child); - return rv; } static const struct of_device_id max77650_led_of_match[] = { diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index da99d114bfb212..e22f09d1379839 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -301,7 +301,7 @@ static struct platform_driver mc13xxx_led_driver = { .driver = { .name = "mc13xxx-led", }, - .remove_new = mc13xxx_led_remove, + .remove = mc13xxx_led_remove, .id_table = mc13xxx_led_id_table, }; module_platform_driver_probe(mc13xxx_led_driver, mc13xxx_led_probe); diff --git a/drivers/leds/leds-mt6323.c b/drivers/leds/leds-mt6323.c index a19e8e0b6d1b1d..dbdc221c382834 100644 --- a/drivers/leds/leds-mt6323.c +++ b/drivers/leds/leds-mt6323.c @@ -713,7 +713,7 @@ MODULE_DEVICE_TABLE(of, mt6323_led_dt_match); static struct platform_driver mt6323_led_driver = { .probe = mt6323_led_probe, - .remove_new = mt6323_led_remove, + .remove = mt6323_led_remove, .driver = { .name = "mt6323-led", .of_match_table = mt6323_led_dt_match, diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index f3010c472bbd4f..4c6f04a5bd87e2 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -238,7 +238,6 @@ static int ns2_led_register(struct device *dev, struct fwnode_handle *node, static int ns2_led_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct fwnode_handle *child; struct ns2_led *leds; int count; int ret; @@ -251,12 +250,10 @@ static int ns2_led_probe(struct platform_device *pdev) if (!leds) return -ENOMEM; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { ret = ns2_led_register(dev, child, leds++); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } } return 0; diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index b53905da359201..050e93b0488421 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -306,7 +306,6 @@ static int pca963x_register_leds(struct i2c_client *client, struct pca963x_chipdef *chipdef = chip->chipdef; struct pca963x_led *led = chip->leds; struct device *dev = &client->dev; - struct fwnode_handle *child; bool hw_blink; s32 mode2; u32 reg; @@ -338,7 +337,7 @@ static int pca963x_register_leds(struct i2c_client *client, if (ret < 0) return ret; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct led_init_data init_data = {}; char default_label[32]; @@ -346,8 +345,7 @@ static int pca963x_register_leds(struct i2c_client *client, if (ret || reg >= chipdef->n_leds) { dev_err(dev, "Invalid 'reg' property for node %pfw\n", child); - ret = -EINVAL; - goto err; + return -EINVAL; } led->led_num = reg; @@ -369,16 +367,13 @@ static int pca963x_register_leds(struct i2c_client *client, if (ret) { dev_err(dev, "Failed to register LED for node %pfw\n", child); - goto err; + return ret; } ++led; } return 0; -err: - fwnode_handle_put(child); - return ret; } static int pca963x_suspend(struct device *dev) diff --git a/drivers/leds/leds-powernv.c b/drivers/leds/leds-powernv.c index 49ab8c9a3f29fc..3a38578ce8e4a0 100644 --- a/drivers/leds/leds-powernv.c +++ b/drivers/leds/leds-powernv.c @@ -323,8 +323,8 @@ static const struct of_device_id powernv_led_match[] = { MODULE_DEVICE_TABLE(of, powernv_led_match); static struct platform_driver powernv_led_driver = { - .probe = powernv_led_probe, - .remove_new = powernv_led_remove, + .probe = powernv_led_probe, + .remove = powernv_led_remove, .driver = { .name = "powernv-led-driver", .of_match_table = powernv_led_match, diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index e1b414b4035347..c73134e7b95141 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -17,7 +17,6 @@ #include #include #include -#include "leds.h" struct led_pwm { const char *name; @@ -63,6 +62,20 @@ static int led_pwm_set(struct led_classdev *led_cdev, return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate); } +static int led_pwm_default_brightness_get(struct fwnode_handle *fwnode, + int max_brightness) +{ + unsigned int default_brightness; + int ret; + + ret = fwnode_property_read_u32(fwnode, "default-brightness", + &default_brightness); + if (ret < 0 || default_brightness > max_brightness) + default_brightness = max_brightness; + + return default_brightness; +} + __attribute__((nonnull)) static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, struct led_pwm *led, struct fwnode_handle *fwnode) @@ -104,7 +117,8 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, /* set brightness */ switch (led->default_state) { case LEDS_DEFSTATE_ON: - led_data->cdev.brightness = led->max_brightness; + led_data->cdev.brightness = + led_pwm_default_brightness_get(fwnode, led->max_brightness); break; case LEDS_DEFSTATE_KEEP: { @@ -140,21 +154,18 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) { - struct fwnode_handle *fwnode; struct led_pwm led; int ret; - device_for_each_child_node(dev, fwnode) { + device_for_each_child_node_scoped(dev, fwnode) { memset(&led, 0, sizeof(led)); ret = fwnode_property_read_string(fwnode, "label", &led.name); if (ret && is_of_node(fwnode)) led.name = to_of_node(fwnode)->name; - if (!led.name) { - ret = -EINVAL; - goto err_child_out; - } + if (!led.name) + return -EINVAL; led.active_low = fwnode_property_read_bool(fwnode, "active-low"); @@ -165,14 +176,10 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) ret = led_pwm_add(dev, priv, &led, fwnode); if (ret) - goto err_child_out; + return ret; } return 0; - -err_child_out: - fwnode_handle_put(fwnode); - return ret; } static int led_pwm_probe(struct platform_device *pdev) diff --git a/drivers/leds/leds-rb532.c b/drivers/leds/leds-rb532.c index e66f73879c8e39..782e1c11ee442a 100644 --- a/drivers/leds/leds-rb532.c +++ b/drivers/leds/leds-rb532.c @@ -49,7 +49,7 @@ static void rb532_led_remove(struct platform_device *pdev) static struct platform_driver rb532_led_driver = { .probe = rb532_led_probe, - .remove_new = rb532_led_remove, + .remove = rb532_led_remove, .driver = { .name = "rb532-led", }, diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c index 848e929c4a61c8..ade64629431a49 100644 --- a/drivers/leds/leds-regulator.c +++ b/drivers/leds/leds-regulator.c @@ -193,7 +193,7 @@ static struct platform_driver regulator_led_driver = { .of_match_table = regulator_led_of_match, }, .probe = regulator_led_probe, - .remove_new = regulator_led_remove, + .remove = regulator_led_remove, }; module_platform_driver(regulator_led_driver); diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c index cca98c644aa65e..0c5169773949a2 100644 --- a/drivers/leds/leds-sc27xx-bltc.c +++ b/drivers/leds/leds-sc27xx-bltc.c @@ -344,7 +344,7 @@ static struct platform_driver sc27xx_led_driver = { .of_match_table = sc27xx_led_of_match, }, .probe = sc27xx_led_probe, - .remove_new = sc27xx_led_remove, + .remove = sc27xx_led_remove, }; module_platform_driver(sc27xx_led_driver); diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c index 2ef9fc7371bd1f..f24ca75c7cb183 100644 --- a/drivers/leds/leds-ss4200.c +++ b/drivers/leds/leds-ss4200.c @@ -451,7 +451,7 @@ static ssize_t blink_show(struct device *dev, int blinking = 0; if (nasgpio_led_get_attr(led, GPO_BLINK)) blinking = 1; - return sprintf(buf, "%u\n", blinking); + return sprintf(buf, "%d\n", blinking); } static ssize_t blink_store(struct device *dev, diff --git a/drivers/leds/leds-sun50i-a100.c b/drivers/leds/leds-sun50i-a100.c index 4c468d48748648..2c9bd360ab818b 100644 --- a/drivers/leds/leds-sun50i-a100.c +++ b/drivers/leds/leds-sun50i-a100.c @@ -392,7 +392,6 @@ static int sun50i_a100_ledc_probe(struct platform_device *pdev) struct sun50i_a100_ledc_led *led; struct device *dev = &pdev->dev; struct sun50i_a100_ledc *priv; - struct fwnode_handle *child; struct resource *mem; u32 max_addr = 0; u32 num_leds = 0; @@ -402,21 +401,17 @@ static int sun50i_a100_ledc_probe(struct platform_device *pdev) * The maximum LED address must be known in sun50i_a100_ledc_resume() before * class device registration, so parse and validate the subnodes up front. */ - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { u32 addr, color; ret = fwnode_property_read_u32(child, "reg", &addr); - if (ret || addr >= LEDC_MAX_LEDS) { - fwnode_handle_put(child); + if (ret || addr >= LEDC_MAX_LEDS) return dev_err_probe(dev, -EINVAL, "'reg' must be between 0 and %d\n", LEDC_MAX_LEDS - 1); - } ret = fwnode_property_read_u32(child, "color", &color); - if (ret || color != LED_COLOR_ID_RGB) { - fwnode_handle_put(child); + if (ret || color != LED_COLOR_ID_RGB) return dev_err_probe(dev, -EINVAL, "'color' must be LED_COLOR_ID_RGB\n"); - } max_addr = max(max_addr, addr); num_leds++; @@ -502,7 +497,7 @@ static int sun50i_a100_ledc_probe(struct platform_device *pdev) return ret; led = priv->leds; - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct led_classdev *cdev; /* The node was already validated above. */ @@ -527,7 +522,11 @@ static int sun50i_a100_ledc_probe(struct platform_device *pdev) ret = led_classdev_multicolor_register_ext(dev, &led->mc_cdev, &init_data); if (ret) { dev_err_probe(dev, ret, "Failed to register multicolor LED %u", led->addr); - goto err_put_child; + while (led-- > priv->leds) + led_classdev_multicolor_unregister(&led->mc_cdev); + sun50i_a100_ledc_suspend(&pdev->dev); + + return ret; } led++; @@ -536,14 +535,6 @@ static int sun50i_a100_ledc_probe(struct platform_device *pdev) dev_info(dev, "Registered %u LEDs\n", num_leds); return 0; - -err_put_child: - fwnode_handle_put(child); - while (led-- > priv->leds) - led_classdev_multicolor_unregister(&led->mc_cdev); - sun50i_a100_ledc_suspend(&pdev->dev); - - return ret; } static void sun50i_a100_ledc_remove(struct platform_device *pdev) @@ -567,7 +558,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sun50i_a100_ledc_pm, static struct platform_driver sun50i_a100_ledc_driver = { .probe = sun50i_a100_ledc_probe, - .remove_new = sun50i_a100_ledc_remove, + .remove = sun50i_a100_ledc_remove, .shutdown = sun50i_a100_ledc_remove, .driver = { .name = "sun50i-a100-ledc", diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c index a621e5e5c75c5f..bd24e7f5947ab4 100644 --- a/drivers/leds/leds-sunfire.c +++ b/drivers/leds/leds-sunfire.c @@ -219,7 +219,7 @@ MODULE_ALIAS("platform:sunfire-fhc-leds"); static struct platform_driver sunfire_clockboard_led_driver = { .probe = sunfire_clockboard_led_probe, - .remove_new = sunfire_led_generic_remove, + .remove = sunfire_led_generic_remove, .driver = { .name = "sunfire-clockboard-leds", }, @@ -227,7 +227,7 @@ static struct platform_driver sunfire_clockboard_led_driver = { static struct platform_driver sunfire_fhc_led_driver = { .probe = sunfire_fhc_led_probe, - .remove_new = sunfire_led_generic_remove, + .remove = sunfire_led_generic_remove, .driver = { .name = "sunfire-fhc-leds", }, diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 4f22f42249467d..acbd8169723c07 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -658,7 +658,6 @@ static struct tca6507_platform_data * tca6507_led_dt_init(struct device *dev) { struct tca6507_platform_data *pdata; - struct fwnode_handle *child; struct led_info *tca_leds; int count; @@ -671,7 +670,7 @@ tca6507_led_dt_init(struct device *dev) if (!tca_leds) return ERR_PTR(-ENOMEM); - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct led_info led; u32 reg; int ret; @@ -688,10 +687,8 @@ tca6507_led_dt_init(struct device *dev) led.flags |= TCA6507_MAKE_GPIO; ret = fwnode_property_read_u32(child, "reg", ®); - if (ret || reg >= NUM_LEDS) { - fwnode_handle_put(child); + if (ret || reg >= NUM_LEDS) return ERR_PTR(ret ? : -EINVAL); - } tca_leds[reg] = led; } diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c index 4cff8c4b020ca1..2de825ac08b3d7 100644 --- a/drivers/leds/leds-turris-omnia.c +++ b/drivers/leds/leds-turris-omnia.c @@ -10,7 +10,6 @@ #include #include #include -#include "leds.h" #define OMNIA_BOARD_LEDS 12 #define OMNIA_LED_NUM_CHANNELS 3 diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c index 70b32d80f9602b..05930e9e88878e 100644 --- a/drivers/leds/leds-wm831x-status.c +++ b/drivers/leds/leds-wm831x-status.c @@ -292,7 +292,7 @@ static struct platform_driver wm831x_status_driver = { .name = "wm831x-status", }, .probe = wm831x_status_probe, - .remove_new = wm831x_status_remove, + .remove = wm831x_status_remove, }; module_platform_driver(wm831x_status_driver); diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c index 61cbefa05710e8..87e60ea927b9bb 100644 --- a/drivers/leds/leds-wm8350.c +++ b/drivers/leds/leds-wm8350.c @@ -255,7 +255,7 @@ static struct platform_driver wm8350_led_driver = { .name = "wm8350-led", }, .probe = wm8350_led_probe, - .remove_new = wm8350_led_remove, + .remove = wm8350_led_remove, .shutdown = wm8350_led_shutdown, }; diff --git a/drivers/leds/rgb/leds-group-multicolor.c b/drivers/leds/rgb/leds-group-multicolor.c index b6c7679015fdf5..548c7dd63ba1e9 100644 --- a/drivers/leds/rgb/leds-group-multicolor.c +++ b/drivers/leds/rgb/leds-group-multicolor.c @@ -55,7 +55,7 @@ static void restore_sysfs_write_access(void *data) { struct led_classdev *led_cdev = data; - /* Restore the write acccess to the LED */ + /* Restore the write access to the LED */ mutex_lock(&led_cdev->led_access); led_sysfs_enable(led_cdev); mutex_unlock(&led_cdev->led_access); diff --git a/drivers/leds/rgb/leds-ktd202x.c b/drivers/leds/rgb/leds-ktd202x.c index d5c442163c464e..04e62faa3a00ed 100644 --- a/drivers/leds/rgb/leds-ktd202x.c +++ b/drivers/leds/rgb/leds-ktd202x.c @@ -495,7 +495,6 @@ static int ktd202x_add_led(struct ktd202x *chip, struct fwnode_handle *fwnode, u static int ktd202x_probe_fw(struct ktd202x *chip) { - struct fwnode_handle *child; struct device *dev = chip->dev; int count; int i = 0; @@ -509,13 +508,12 @@ static int ktd202x_probe_fw(struct ktd202x *chip) /* Allow the device to execute the complete reset */ usleep_range(200, 300); - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { int ret = ktd202x_add_led(chip, child, i); - if (ret) { - fwnode_handle_put(child); + if (ret) return ret; - } + i++; } diff --git a/drivers/leds/rgb/leds-mt6370-rgb.c b/drivers/leds/rgb/leds-mt6370-rgb.c index 10a0b5b45227ba..ebd3ba878dd562 100644 --- a/drivers/leds/rgb/leds-mt6370-rgb.c +++ b/drivers/leds/rgb/leds-mt6370-rgb.c @@ -587,7 +587,7 @@ static inline int mt6370_mc_pattern_clear(struct led_classdev *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; + int i, ret = 0; mutex_lock(&led->priv->lock); @@ -905,7 +905,6 @@ 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; @@ -936,37 +935,27 @@ static int mt6370_leds_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to allocate regmap field\n"); - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(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 (ret) + dev_err_probe(dev, ret, "Failed to parse reg property\n"); - if (reg >= MT6370_MAX_LEDS) { - ret = -EINVAL; - dev_err(dev, "Error reg property number\n"); - goto fwnode_release; - } + if (reg >= MT6370_MAX_LEDS) + return dev_err_probe(dev, -EINVAL, "Error reg property number\n"); ret = fwnode_property_read_u32(child, "color", &color); - if (ret) { - dev_err(dev, "Failed to parse color property\n"); - goto fwnode_release; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to parse color property\n"); 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; - } + if (priv->leds_active & BIT(reg)) + return dev_err_probe(dev, -EINVAL, "Duplicate reg property\n"); priv->leds_active |= BIT(reg); @@ -975,18 +964,14 @@ static int mt6370_leds_probe(struct platform_device *pdev) ret = mt6370_init_led_properties(dev, led, &init_data); if (ret) - goto fwnode_release; + return ret; ret = mt6370_led_register(dev, led, &init_data); if (ret) - goto fwnode_release; + return ret; } return 0; - -fwnode_release: - fwnode_handle_put(child); - return ret; } static const struct of_device_id mt6370_rgbled_device_table[] = { diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c b/drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c index 726c186391afdb..c98c370687c22d 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c @@ -53,7 +53,7 @@ static void simatic_ipc_leds_gpio_apollolake_remove(struct platform_device *pdev static struct platform_driver simatic_ipc_led_gpio_apollolake_driver = { .probe = simatic_ipc_leds_gpio_apollolake_probe, - .remove_new = simatic_ipc_leds_gpio_apollolake_remove, + .remove = simatic_ipc_leds_gpio_apollolake_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c b/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c index 3fec96c549c14f..7f7cff2754480e 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c @@ -43,7 +43,7 @@ static void simatic_ipc_leds_gpio_elkhartlake_remove(struct platform_device *pde static struct platform_driver simatic_ipc_led_gpio_elkhartlake_driver = { .probe = simatic_ipc_leds_gpio_elkhartlake_probe, - .remove_new = simatic_ipc_leds_gpio_elkhartlake_remove, + .remove = simatic_ipc_leds_gpio_elkhartlake_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c b/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c index a1f10952513c65..bc23d701bcb79c 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c @@ -93,7 +93,7 @@ static void simatic_ipc_leds_gpio_f7188x_remove(struct platform_device *pdev) static struct platform_driver simatic_ipc_led_gpio_driver = { .probe = simatic_ipc_leds_gpio_f7188x_probe, - .remove_new = simatic_ipc_leds_gpio_f7188x_remove, + .remove = simatic_ipc_leds_gpio_f7188x_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index fb38f684444f2c..d00e713c10920c 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -120,6 +120,7 @@ config PMAC_MEDIABAY config PMAC_BACKLIGHT bool "Backlight control for LCD screens" depends on PPC_PMAC && ADB_PMU && FB = y && (BROKEN || !PPC64) + depends on BACKLIGHT_CLASS_DEVICE=y select FB_BACKLIGHT help Say Y here to enable Macintosh specific extensions of the generic diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 2576a53f247eaa..0b2e08a1bee076 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -499,7 +499,7 @@ static struct platform_driver therm_of_driver = { .of_match_table = therm_of_match, }, .probe = therm_of_probe, - .remove_new = therm_of_remove, + .remove = therm_of_remove, }; struct apple_thermal_info { diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c index a4fb16d7db3c11..fc1af74b659672 100644 --- a/drivers/macintosh/via-pmu-led.c +++ b/drivers/macintosh/via-pmu-led.c @@ -92,18 +92,15 @@ static int __init via_pmu_led_init(void) if (dt == NULL) return -ENODEV; model = of_get_property(dt, "model", NULL); - if (model == NULL) { - of_node_put(dt); - return -ENODEV; - } + if (!model) + goto put_node; + if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 && strncmp(model, "iBook", strlen("iBook")) != 0 && strcmp(model, "PowerMac7,2") != 0 && - strcmp(model, "PowerMac7,3") != 0) { - of_node_put(dt); - /* ignore */ - return -ENODEV; - } + strcmp(model, "PowerMac7,3") != 0) + goto put_node; + of_node_put(dt); spin_lock_init(&pmu_blink_lock); @@ -112,6 +109,10 @@ static int __init via_pmu_led_init(void) pmu_blink_req.done = pmu_req_done; return led_classdev_register(NULL, &pmu_led); + +put_node: + of_node_put(dt); + return -ENODEV; } late_initcall(via_pmu_led_init); diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c index 876b4d8cbe378a..5bd6d1ccf2460d 100644 --- a/drivers/macintosh/windfarm_pm112.c +++ b/drivers/macintosh/windfarm_pm112.c @@ -669,7 +669,7 @@ static void wf_pm112_remove(struct platform_device *dev) static struct platform_driver wf_pm112_driver = { .probe = wf_pm112_probe, - .remove_new = wf_pm112_remove, + .remove = wf_pm112_remove, .driver = { .name = "windfarm", }, diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c index cd45fbc4fe1cec..660180c843a3d7 100644 --- a/drivers/macintosh/windfarm_pm121.c +++ b/drivers/macintosh/windfarm_pm121.c @@ -999,7 +999,7 @@ static void pm121_remove(struct platform_device *ddev) static struct platform_driver pm121_driver = { .probe = pm121_probe, - .remove_new = pm121_remove, + .remove = pm121_remove, .driver = { .name = "windfarm", .bus = &platform_bus_type, diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c index 14fa1e9ac3e004..10aa14074c3937 100644 --- a/drivers/macintosh/windfarm_pm72.c +++ b/drivers/macintosh/windfarm_pm72.c @@ -782,7 +782,7 @@ static void wf_pm72_remove(struct platform_device *dev) static struct platform_driver wf_pm72_driver = { .probe = wf_pm72_probe, - .remove_new = wf_pm72_remove, + .remove = wf_pm72_remove, .driver = { .name = "windfarm", }, diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c index 404d2454e33de6..ada97377e19ed4 100644 --- a/drivers/macintosh/windfarm_pm81.c +++ b/drivers/macintosh/windfarm_pm81.c @@ -765,7 +765,7 @@ static void wf_smu_remove(struct platform_device *ddev) static struct platform_driver wf_smu_driver = { .probe = wf_smu_probe, - .remove_new = wf_smu_remove, + .remove = wf_smu_remove, .driver = { .name = "windfarm", }, diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c index fba02a375435e4..108d7938e714b2 100644 --- a/drivers/macintosh/windfarm_pm91.c +++ b/drivers/macintosh/windfarm_pm91.c @@ -695,7 +695,7 @@ static void wf_smu_remove(struct platform_device *ddev) static struct platform_driver wf_smu_driver = { .probe = wf_smu_probe, - .remove_new = wf_smu_remove, + .remove = wf_smu_remove, .driver = { .name = "windfarm", }, diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c index dc8f2c7ef10315..44d86a4102380d 100644 --- a/drivers/macintosh/windfarm_rm31.c +++ b/drivers/macintosh/windfarm_rm31.c @@ -675,7 +675,7 @@ static void wf_rm31_remove(struct platform_device *dev) static struct platform_driver wf_rm31_driver = { .probe = wf_rm31_probe, - .remove_new = wf_rm31_remove, + .remove = wf_rm31_remove, .driver = { .name = "windfarm", }, diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 6fb995778636a3..8ecba7fb999e9d 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -127,7 +127,7 @@ config STI_MBOX config TI_MESSAGE_MANAGER tristate "Texas Instruments Message Manager Driver" - depends on ARCH_KEYSTONE || ARCH_K3 + depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST default ARCH_K3 help An implementation of Message Manager slave driver for Keystone @@ -168,6 +168,7 @@ config MAILBOX_TEST config POLARFIRE_SOC_MAILBOX tristate "PolarFire SoC (MPFS) Mailbox" depends on HAS_IOMEM + depends on MFD_SYSCON depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST help This driver adds support for the PolarFire SoC (MPFS) mailbox controller. @@ -295,4 +296,14 @@ config QCOM_IPCC acts as an interrupt controller for receiving interrupts from clients. Say Y here if you want to build this driver. +config THEAD_TH1520_MBOX + tristate "T-head TH1520 Mailbox" + depends on ARCH_THEAD || COMPILE_TEST + help + Mailbox driver implementation for the Thead TH-1520 platform. Enables + two cores within the SoC to communicate and coordinate by passing + messages. Could be used to communicate between E910 core, on which the + kernel is running, and E902 core used for power management among other + things. + endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 3c3c27d54c13de..5f4f5b0ce2ccf2 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -64,3 +64,5 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o obj-$(CONFIG_QCOM_CPUCP_MBOX) += qcom-cpucp-mbox.o obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o + +obj-$(CONFIG_THEAD_TH1520_MBOX) += mailbox-th1520.o diff --git a/drivers/mailbox/arm_mhuv2.c b/drivers/mailbox/arm_mhuv2.c index 0ec21dcdbde723..cff7c343ee082a 100644 --- a/drivers/mailbox/arm_mhuv2.c +++ b/drivers/mailbox/arm_mhuv2.c @@ -500,7 +500,7 @@ static const struct mhuv2_protocol_ops mhuv2_data_transfer_ops = { static struct mbox_chan *get_irq_chan_comb(struct mhuv2 *mhu, u32 __iomem *reg) { struct mbox_chan *chans = mhu->mbox.chans; - int channel = 0, i, offset = 0, windows, protocol, ch_wn; + int channel = 0, i, j, offset = 0, windows, protocol, ch_wn; u32 stat; for (i = 0; i < MHUV2_CMB_INT_ST_REG_CNT; i++) { @@ -510,9 +510,9 @@ static struct mbox_chan *get_irq_chan_comb(struct mhuv2 *mhu, u32 __iomem *reg) ch_wn = i * MHUV2_STAT_BITS + __builtin_ctz(stat); - for (i = 0; i < mhu->length; i += 2) { - protocol = mhu->protocols[i]; - windows = mhu->protocols[i + 1]; + for (j = 0; j < mhu->length; j += 2) { + protocol = mhu->protocols[j]; + windows = mhu->protocols[j + 1]; if (ch_wn >= offset + windows) { if (protocol == DOORBELL) diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c index b1abc2a0c971a5..41f79e51d9e5a9 100644 --- a/drivers/mailbox/bcm-flexrm-mailbox.c +++ b/drivers/mailbox/bcm-flexrm-mailbox.c @@ -1675,7 +1675,7 @@ static struct platform_driver flexrm_mbox_driver = { .of_match_table = flexrm_mbox_of_match, }, .probe = flexrm_mbox_probe, - .remove_new = flexrm_mbox_remove, + .remove = flexrm_mbox_remove, }; module_platform_driver(flexrm_mbox_driver); diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index a873672a9082d2..406bc41cba6044 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -1618,7 +1618,7 @@ static void pdc_remove(struct platform_device *pdev) static struct platform_driver pdc_mbox_driver = { .probe = pdc_probe, - .remove_new = pdc_remove, + .remove = pdc_remove, .driver = { .name = "brcm-iproc-pdc-mbox", .of_match_table = pdc_mbox_of_match, diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index f815dab3be50cd..6ef8338add0d61 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -782,7 +782,7 @@ static int imx_mu_init_generic(struct imx_mu_priv *priv) cp->chan = &priv->mbox_chans[i]; priv->mbox_chans[i].con_priv = cp; snprintf(cp->irq_desc, sizeof(cp->irq_desc), - "%s[%i-%i]", dev_name(priv->dev), cp->type, cp->idx); + "%s[%i-%u]", dev_name(priv->dev), cp->type, cp->idx); } priv->mbox.num_chans = IMX_MU_CHANS; @@ -819,7 +819,7 @@ static int imx_mu_init_specific(struct imx_mu_priv *priv) cp->chan = &priv->mbox_chans[i]; priv->mbox_chans[i].con_priv = cp; snprintf(cp->irq_desc, sizeof(cp->irq_desc), - "%s[%i-%i]", dev_name(priv->dev), cp->type, cp->idx); + "%s[%i-%u]", dev_name(priv->dev), cp->type, cp->idx); } priv->mbox.num_chans = num_chans; @@ -1120,7 +1120,7 @@ static const struct dev_pm_ops imx_mu_pm_ops = { static struct platform_driver imx_mu_driver = { .probe = imx_mu_probe, - .remove_new = imx_mu_remove, + .remove = imx_mu_remove, .driver = { .name = "imx_mu", .of_match_table = imx_mu_dt_ids, diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c index 20ee283a04cc6a..4df546e3b7eaeb 100644 --- a/drivers/mailbox/mailbox-mpfs.c +++ b/drivers/mailbox/mailbox-mpfs.c @@ -13,12 +13,15 @@ #include #include #include +#include #include +#include #include #include #include #include +#define MESSAGE_INT_OFFSET 0x18cu #define SERVICES_CR_OFFSET 0x50u #define SERVICES_SR_OFFSET 0x54u #define MAILBOX_REG_OFFSET 0x800u @@ -68,6 +71,7 @@ struct mpfs_mbox { void __iomem *int_reg; struct mbox_chan chans[1]; struct mpfs_mss_response *response; + struct regmap *sysreg_scb, *control_scb; u16 resp_offset; }; @@ -75,7 +79,10 @@ static bool mpfs_mbox_busy(struct mpfs_mbox *mbox) { u32 status; - status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET); + if (mbox->control_scb) + regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &status); + else + status = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET); return status & SCB_STATUS_BUSY_MASK; } @@ -95,7 +102,11 @@ static bool mpfs_mbox_last_tx_done(struct mbox_chan *chan) * Failed services are intended to generated interrupts, but in reality * this does not happen, so the status must be checked here. */ - val = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET); + if (mbox->control_scb) + regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &val); + else + val = readl_relaxed(mbox->ctrl_base + SERVICES_SR_OFFSET); + response->resp_status = (val & SCB_STATUS_MASK) >> SCB_STATUS_POS; return true; @@ -143,7 +154,12 @@ static int mpfs_mbox_send_data(struct mbox_chan *chan, void *data) tx_trigger = (opt_sel << SCB_CTRL_POS) & SCB_CTRL_MASK; tx_trigger |= SCB_CTRL_REQ_MASK | SCB_STATUS_NOTIFY_MASK; - writel_relaxed(tx_trigger, mbox->ctrl_base + SERVICES_CR_OFFSET); + + if (mbox->control_scb) + regmap_write(mbox->control_scb, SERVICES_CR_OFFSET, tx_trigger); + else + writel_relaxed(tx_trigger, mbox->ctrl_base + SERVICES_CR_OFFSET); + return 0; } @@ -185,7 +201,10 @@ static irqreturn_t mpfs_mbox_inbox_isr(int irq, void *data) struct mbox_chan *chan = data; struct mpfs_mbox *mbox = (struct mpfs_mbox *)chan->con_priv; - writel_relaxed(0, mbox->int_reg); + if (mbox->control_scb) + regmap_write(mbox->sysreg_scb, MESSAGE_INT_OFFSET, 0); + else + writel_relaxed(0, mbox->int_reg); mpfs_mbox_rx_data(chan); @@ -221,28 +240,62 @@ static const struct mbox_chan_ops mpfs_mbox_ops = { .last_tx_done = mpfs_mbox_last_tx_done, }; -static int mpfs_mbox_probe(struct platform_device *pdev) +static inline int mpfs_mbox_syscon_probe(struct mpfs_mbox *mbox, struct platform_device *pdev) { - struct mpfs_mbox *mbox; - struct resource *regs; - int ret; + mbox->control_scb = syscon_regmap_lookup_by_compatible("microchip,mpfs-control-scb"); + if (IS_ERR(mbox->control_scb)) + return PTR_ERR(mbox->control_scb); - mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL); - if (!mbox) - return -ENOMEM; + mbox->sysreg_scb = syscon_regmap_lookup_by_compatible("microchip,mpfs-sysreg-scb"); + if (IS_ERR(mbox->sysreg_scb)) + return PTR_ERR(mbox->sysreg_scb); + + mbox->mbox_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mbox->ctrl_base)) + return PTR_ERR(mbox->mbox_base); + + return 0; +} + +static inline int mpfs_mbox_old_format_probe(struct mpfs_mbox *mbox, struct platform_device *pdev) +{ + dev_warn(&pdev->dev, "falling back to old devicetree format"); - mbox->ctrl_base = devm_platform_get_and_ioremap_resource(pdev, 0, ®s); + mbox->ctrl_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mbox->ctrl_base)) return PTR_ERR(mbox->ctrl_base); - mbox->int_reg = devm_platform_get_and_ioremap_resource(pdev, 1, ®s); + mbox->int_reg = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(mbox->int_reg)) return PTR_ERR(mbox->int_reg); - mbox->mbox_base = devm_platform_get_and_ioremap_resource(pdev, 2, ®s); + mbox->mbox_base = devm_platform_ioremap_resource(pdev, 2); if (IS_ERR(mbox->mbox_base)) // account for the old dt-binding w/ 2 regs mbox->mbox_base = mbox->ctrl_base + MAILBOX_REG_OFFSET; + return 0; +} + +static int mpfs_mbox_probe(struct platform_device *pdev) +{ + struct mpfs_mbox *mbox; + int ret; + + mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL); + if (!mbox) + return -ENOMEM; + + ret = mpfs_mbox_syscon_probe(mbox, pdev); + if (ret) { + /* + * set this to null, so it can be used as the decision for to + * regmap or not to regmap + */ + mbox->control_scb = NULL; + ret = mpfs_mbox_old_format_probe(mbox, pdev); + if (ret) + return ret; + } mbox->irq = platform_get_irq(pdev, 0); if (mbox->irq < 0) return mbox->irq; diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 3386b4e72551c7..c9dd8c42c0cdf9 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -441,8 +441,8 @@ static struct platform_driver mbox_test_driver = { .name = "mailbox_test", .of_match_table = mbox_test_match, }, - .probe = mbox_test_probe, - .remove_new = mbox_test_remove, + .probe = mbox_test_probe, + .remove = mbox_test_remove, }; module_platform_driver(mbox_test_driver); diff --git a/drivers/mailbox/mailbox-th1520.c b/drivers/mailbox/mailbox-th1520.c new file mode 100644 index 00000000000000..4e84640ac3b876 --- /dev/null +++ b/drivers/mailbox/mailbox-th1520.c @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Alibaba Group Holding Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Status Register */ +#define TH_1520_MBOX_STA 0x0 +#define TH_1520_MBOX_CLR 0x4 +#define TH_1520_MBOX_MASK 0xc + +/* Transmit/receive data register: + * INFO0 ~ INFO6 + */ +#define TH_1520_MBOX_INFO_NUM 8 +#define TH_1520_MBOX_DATA_INFO_NUM 7 +#define TH_1520_MBOX_INFO0 0x14 +/* Transmit ack register: INFO7 */ +#define TH_1520_MBOX_INFO7 0x30 + +/* Generate remote icu IRQ Register */ +#define TH_1520_MBOX_GEN 0x10 +#define TH_1520_MBOX_GEN_RX_DATA BIT(6) +#define TH_1520_MBOX_GEN_TX_ACK BIT(7) + +#define TH_1520_MBOX_CHAN_RES_SIZE 0x1000 +#define TH_1520_MBOX_CHANS 4 +#define TH_1520_MBOX_CHAN_NAME_SIZE 20 + +#define TH_1520_MBOX_ACK_MAGIC 0xdeadbeaf + +#ifdef CONFIG_PM_SLEEP +/* store MBOX context across system-wide suspend/resume transitions */ +struct th1520_mbox_context { + u32 intr_mask[TH_1520_MBOX_CHANS - 1]; +}; +#endif + +enum th1520_mbox_icu_cpu_id { + TH_1520_MBOX_ICU_KERNEL_CPU0, /* 910T */ + TH_1520_MBOX_ICU_CPU1, /* 902 */ + TH_1520_MBOX_ICU_CPU2, /* 906 */ + TH_1520_MBOX_ICU_CPU3, /* 910R */ +}; + +struct th1520_mbox_con_priv { + enum th1520_mbox_icu_cpu_id idx; + void __iomem *comm_local_base; + void __iomem *comm_remote_base; + char irq_desc[TH_1520_MBOX_CHAN_NAME_SIZE]; + struct mbox_chan *chan; +}; + +struct th1520_mbox_priv { + struct device *dev; + void __iomem *local_icu[TH_1520_MBOX_CHANS]; + void __iomem *remote_icu[TH_1520_MBOX_CHANS - 1]; + void __iomem *cur_cpu_ch_base; + spinlock_t mbox_lock; /* control register lock */ + + struct mbox_controller mbox; + struct mbox_chan mbox_chans[TH_1520_MBOX_CHANS]; + struct clk_bulk_data clocks[TH_1520_MBOX_CHANS]; + struct th1520_mbox_con_priv con_priv[TH_1520_MBOX_CHANS]; + int irq; +#ifdef CONFIG_PM_SLEEP + struct th1520_mbox_context *ctx; +#endif +}; + +static struct th1520_mbox_priv * +to_th1520_mbox_priv(struct mbox_controller *mbox) +{ + return container_of(mbox, struct th1520_mbox_priv, mbox); +} + +static void th1520_mbox_write(struct th1520_mbox_priv *priv, u32 val, u32 offs) +{ + iowrite32(val, priv->cur_cpu_ch_base + offs); +} + +static u32 th1520_mbox_read(struct th1520_mbox_priv *priv, u32 offs) +{ + return ioread32(priv->cur_cpu_ch_base + offs); +} + +static u32 th1520_mbox_rmw(struct th1520_mbox_priv *priv, u32 off, u32 set, + u32 clr) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->mbox_lock, flags); + val = th1520_mbox_read(priv, off); + val &= ~clr; + val |= set; + th1520_mbox_write(priv, val, off); + spin_unlock_irqrestore(&priv->mbox_lock, flags); + + return val; +} + +static void th1520_mbox_chan_write(struct th1520_mbox_con_priv *cp, u32 val, + u32 offs, bool is_remote) +{ + if (is_remote) + iowrite32(val, cp->comm_remote_base + offs); + else + iowrite32(val, cp->comm_local_base + offs); +} + +static u32 th1520_mbox_chan_read(struct th1520_mbox_con_priv *cp, u32 offs, + bool is_remote) +{ + if (is_remote) + return ioread32(cp->comm_remote_base + offs); + else + return ioread32(cp->comm_local_base + offs); +} + +static void th1520_mbox_chan_rmw(struct th1520_mbox_con_priv *cp, u32 off, + u32 set, u32 clr, bool is_remote) +{ + struct th1520_mbox_priv *priv = to_th1520_mbox_priv(cp->chan->mbox); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->mbox_lock, flags); + val = th1520_mbox_chan_read(cp, off, is_remote); + val &= ~clr; + val |= set; + th1520_mbox_chan_write(cp, val, off, is_remote); + spin_unlock_irqrestore(&priv->mbox_lock, flags); +} + +static void th1520_mbox_chan_rd_data(struct th1520_mbox_con_priv *cp, + void *data, bool is_remote) +{ + u32 off = TH_1520_MBOX_INFO0; + u32 *arg = data; + u32 i; + + /* read info0 ~ info6, totally 28 bytes + * requires data memory size is 28 bytes + */ + for (i = 0; i < TH_1520_MBOX_DATA_INFO_NUM; i++) { + *arg = th1520_mbox_chan_read(cp, off, is_remote); + off += 4; + arg++; + } +} + +static void th1520_mbox_chan_wr_data(struct th1520_mbox_con_priv *cp, + void *data, bool is_remote) +{ + u32 off = TH_1520_MBOX_INFO0; + u32 *arg = data; + u32 i; + + /* write info0 ~ info6, totally 28 bytes + * requires data memory is 28 bytes valid data + */ + for (i = 0; i < TH_1520_MBOX_DATA_INFO_NUM; i++) { + th1520_mbox_chan_write(cp, *arg, off, is_remote); + off += 4; + arg++; + } +} + +static void th1520_mbox_chan_wr_ack(struct th1520_mbox_con_priv *cp, void *data, + bool is_remote) +{ + u32 off = TH_1520_MBOX_INFO7; + u32 *arg = data; + + th1520_mbox_chan_write(cp, *arg, off, is_remote); +} + +static int th1520_mbox_chan_id_to_mapbit(struct th1520_mbox_con_priv *cp) +{ + int mapbit = 0; + int i; + + for (i = 0; i < TH_1520_MBOX_CHANS; i++) { + if (i == cp->idx) + return mapbit; + + if (i != TH_1520_MBOX_ICU_KERNEL_CPU0) + mapbit++; + } + + if (i == TH_1520_MBOX_CHANS) + dev_err(cp->chan->mbox->dev, "convert to mapbit failed\n"); + + return 0; +} + +static irqreturn_t th1520_mbox_isr(int irq, void *p) +{ + struct mbox_chan *chan = p; + struct th1520_mbox_priv *priv = to_th1520_mbox_priv(chan->mbox); + struct th1520_mbox_con_priv *cp = chan->con_priv; + int mapbit = th1520_mbox_chan_id_to_mapbit(cp); + u32 sta, dat[TH_1520_MBOX_DATA_INFO_NUM]; + u32 ack_magic = TH_1520_MBOX_ACK_MAGIC; + u32 info0_data, info7_data; + + sta = th1520_mbox_read(priv, TH_1520_MBOX_STA); + if (!(sta & BIT(mapbit))) + return IRQ_NONE; + + /* clear chan irq bit in STA register */ + th1520_mbox_rmw(priv, TH_1520_MBOX_CLR, BIT(mapbit), 0); + + /* info0 is the protocol word, should not be zero! */ + info0_data = th1520_mbox_chan_read(cp, TH_1520_MBOX_INFO0, false); + if (info0_data) { + /* read info0~info6 data */ + th1520_mbox_chan_rd_data(cp, dat, false); + + /* clear local info0 */ + th1520_mbox_chan_write(cp, 0x0, TH_1520_MBOX_INFO0, false); + + /* notify remote cpu */ + th1520_mbox_chan_wr_ack(cp, &ack_magic, true); + /* CPU1 902/906 use polling mode to monitor info7 */ + if (cp->idx != TH_1520_MBOX_ICU_CPU1 && + cp->idx != TH_1520_MBOX_ICU_CPU2) + th1520_mbox_chan_rmw(cp, TH_1520_MBOX_GEN, + TH_1520_MBOX_GEN_TX_ACK, 0, true); + + /* transfer the data to client */ + mbox_chan_received_data(chan, (void *)dat); + } + + /* info7 magic value mean the real ack signal, not generate bit7 */ + info7_data = th1520_mbox_chan_read(cp, TH_1520_MBOX_INFO7, false); + if (info7_data == TH_1520_MBOX_ACK_MAGIC) { + /* clear local info7 */ + th1520_mbox_chan_write(cp, 0x0, TH_1520_MBOX_INFO7, false); + + /* notify framework the last TX has completed */ + mbox_chan_txdone(chan, 0); + } + + if (!info0_data && !info7_data) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static int th1520_mbox_send_data(struct mbox_chan *chan, void *data) +{ + struct th1520_mbox_con_priv *cp = chan->con_priv; + + th1520_mbox_chan_wr_data(cp, data, true); + th1520_mbox_chan_rmw(cp, TH_1520_MBOX_GEN, TH_1520_MBOX_GEN_RX_DATA, 0, + true); + return 0; +} + +static int th1520_mbox_startup(struct mbox_chan *chan) +{ + struct th1520_mbox_priv *priv = to_th1520_mbox_priv(chan->mbox); + struct th1520_mbox_con_priv *cp = chan->con_priv; + u32 data[8] = {}; + int mask_bit; + int ret; + + /* clear local and remote generate and info0~info7 */ + th1520_mbox_chan_rmw(cp, TH_1520_MBOX_GEN, 0x0, 0xff, true); + th1520_mbox_chan_rmw(cp, TH_1520_MBOX_GEN, 0x0, 0xff, false); + th1520_mbox_chan_wr_ack(cp, &data[7], true); + th1520_mbox_chan_wr_ack(cp, &data[7], false); + th1520_mbox_chan_wr_data(cp, &data[0], true); + th1520_mbox_chan_wr_data(cp, &data[0], false); + + /* enable the chan mask */ + mask_bit = th1520_mbox_chan_id_to_mapbit(cp); + th1520_mbox_rmw(priv, TH_1520_MBOX_MASK, BIT(mask_bit), 0); + + /* + * Mixing devm_ managed resources with manual IRQ handling is generally + * discouraged due to potential complexities with resource management, + * especially when dealing with shared interrupts. However, in this case, + * the approach is safe and effective because: + * + * 1. Each mailbox channel requests its IRQ within the .startup() callback + * and frees it within the .shutdown() callback. + * 2. During device unbinding, the devm_ managed mailbox controller first + * iterates through all channels, ensuring that their IRQs are freed before + * any other devm_ resources are released. + * + * This ordering guarantees that no interrupts can be triggered from the device + * while it is being unbound, preventing race conditions and ensuring system + * stability. + */ + ret = request_irq(priv->irq, th1520_mbox_isr, + IRQF_SHARED | IRQF_NO_SUSPEND, cp->irq_desc, chan); + if (ret) { + dev_err(priv->dev, "Unable to acquire IRQ %d\n", priv->irq); + return ret; + } + + return 0; +} + +static void th1520_mbox_shutdown(struct mbox_chan *chan) +{ + struct th1520_mbox_priv *priv = to_th1520_mbox_priv(chan->mbox); + struct th1520_mbox_con_priv *cp = chan->con_priv; + int mask_bit; + + free_irq(priv->irq, chan); + + /* clear the chan mask */ + mask_bit = th1520_mbox_chan_id_to_mapbit(cp); + th1520_mbox_rmw(priv, TH_1520_MBOX_MASK, 0, BIT(mask_bit)); +} + +static const struct mbox_chan_ops th1520_mbox_ops = { + .send_data = th1520_mbox_send_data, + .startup = th1520_mbox_startup, + .shutdown = th1520_mbox_shutdown, +}; + +static int th1520_mbox_init_generic(struct th1520_mbox_priv *priv) +{ +#ifdef CONFIG_PM_SLEEP + priv->ctx = devm_kzalloc(priv->dev, sizeof(*priv->ctx), GFP_KERNEL); + if (!priv->ctx) + return -ENOMEM; +#endif + /* Set default configuration */ + th1520_mbox_write(priv, 0xff, TH_1520_MBOX_CLR); + th1520_mbox_write(priv, 0x0, TH_1520_MBOX_MASK); + return 0; +} + +static struct mbox_chan *th1520_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *sp) +{ + u32 chan; + + if (sp->args_count != 1) { + dev_err(mbox->dev, "Invalid argument count %d\n", + sp->args_count); + return ERR_PTR(-EINVAL); + } + + chan = sp->args[0]; /* comm remote channel */ + + if (chan >= mbox->num_chans) { + dev_err(mbox->dev, "Not supported channel number: %d\n", chan); + return ERR_PTR(-EINVAL); + } + + if (chan == TH_1520_MBOX_ICU_KERNEL_CPU0) { + dev_err(mbox->dev, "Cannot communicate with yourself\n"); + return ERR_PTR(-EINVAL); + } + + return &mbox->chans[chan]; +} + +static void __iomem *th1520_map_mmio(struct platform_device *pdev, + char *res_name, size_t offset) +{ + void __iomem *mapped; + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); + + if (!res) { + dev_err(&pdev->dev, "Failed to get resource: %s\n", res_name); + return ERR_PTR(-EINVAL); + } + + mapped = devm_ioremap(&pdev->dev, res->start + offset, + resource_size(res) - offset); + if (IS_ERR(mapped)) + dev_err(&pdev->dev, "Failed to map resource: %s\n", res_name); + + return mapped; +} + +static void th1520_disable_clk(void *data) +{ + struct th1520_mbox_priv *priv = data; + + clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clocks), priv->clocks); +} + +static int th1520_mbox_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct th1520_mbox_priv *priv; + unsigned int remote_idx = 0; + unsigned int i; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + priv->clocks[0].id = "clk-local"; + priv->clocks[1].id = "clk-remote-icu0"; + priv->clocks[2].id = "clk-remote-icu1"; + priv->clocks[3].id = "clk-remote-icu2"; + + ret = devm_clk_bulk_get(dev, ARRAY_SIZE(priv->clocks), + priv->clocks); + if (ret) { + dev_err(dev, "Failed to get clocks\n"); + return ret; + } + + ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clocks), priv->clocks); + if (ret) { + dev_err(dev, "Failed to enable clocks\n"); + return ret; + } + + ret = devm_add_action_or_reset(dev, th1520_disable_clk, priv); + if (ret) { + clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clocks), priv->clocks); + return ret; + } + + /* + * The address mappings in the device tree align precisely with those + * outlined in the manual. However, register offsets within these + * mapped regions are irregular, particularly for remote-icu0. + * Consequently, th1520_map_mmio() requires an additional parameter to + * handle this quirk. + */ + priv->local_icu[TH_1520_MBOX_ICU_KERNEL_CPU0] = + th1520_map_mmio(pdev, "local", 0x0); + if (IS_ERR(priv->local_icu[TH_1520_MBOX_ICU_KERNEL_CPU0])) + return PTR_ERR(priv->local_icu[TH_1520_MBOX_ICU_KERNEL_CPU0]); + + priv->remote_icu[0] = th1520_map_mmio(pdev, "remote-icu0", 0x4000); + if (IS_ERR(priv->remote_icu[0])) + return PTR_ERR(priv->remote_icu[0]); + + priv->remote_icu[1] = th1520_map_mmio(pdev, "remote-icu1", 0x0); + if (IS_ERR(priv->remote_icu[1])) + return PTR_ERR(priv->remote_icu[1]); + + priv->remote_icu[2] = th1520_map_mmio(pdev, "remote-icu2", 0x0); + if (IS_ERR(priv->remote_icu[2])) + return PTR_ERR(priv->remote_icu[2]); + + priv->local_icu[TH_1520_MBOX_ICU_CPU1] = + priv->local_icu[TH_1520_MBOX_ICU_KERNEL_CPU0] + + TH_1520_MBOX_CHAN_RES_SIZE; + priv->local_icu[TH_1520_MBOX_ICU_CPU2] = + priv->local_icu[TH_1520_MBOX_ICU_CPU1] + + TH_1520_MBOX_CHAN_RES_SIZE; + priv->local_icu[TH_1520_MBOX_ICU_CPU3] = + priv->local_icu[TH_1520_MBOX_ICU_CPU2] + + TH_1520_MBOX_CHAN_RES_SIZE; + + priv->cur_cpu_ch_base = priv->local_icu[TH_1520_MBOX_ICU_KERNEL_CPU0]; + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) + return priv->irq; + + /* init the chans */ + for (i = 0; i < TH_1520_MBOX_CHANS; i++) { + struct th1520_mbox_con_priv *cp = &priv->con_priv[i]; + + cp->idx = i; + cp->chan = &priv->mbox_chans[i]; + priv->mbox_chans[i].con_priv = cp; + snprintf(cp->irq_desc, sizeof(cp->irq_desc), + "th1520_mbox_chan[%i]", cp->idx); + + cp->comm_local_base = priv->local_icu[i]; + if (i != TH_1520_MBOX_ICU_KERNEL_CPU0) { + cp->comm_remote_base = priv->remote_icu[remote_idx]; + remote_idx++; + } + } + + spin_lock_init(&priv->mbox_lock); + + priv->mbox.dev = dev; + priv->mbox.ops = &th1520_mbox_ops; + priv->mbox.chans = priv->mbox_chans; + priv->mbox.num_chans = TH_1520_MBOX_CHANS; + priv->mbox.of_xlate = th1520_mbox_xlate; + priv->mbox.txdone_irq = true; + + platform_set_drvdata(pdev, priv); + + ret = th1520_mbox_init_generic(priv); + if (ret) { + dev_err(dev, "Failed to init mailbox context\n"); + return ret; + } + + return devm_mbox_controller_register(dev, &priv->mbox); +} + +static const struct of_device_id th1520_mbox_dt_ids[] = { + { .compatible = "thead,th1520-mbox" }, + {} +}; +MODULE_DEVICE_TABLE(of, th1520_mbox_dt_ids); + +#ifdef CONFIG_PM_SLEEP +static int __maybe_unused th1520_mbox_suspend_noirq(struct device *dev) +{ + struct th1520_mbox_priv *priv = dev_get_drvdata(dev); + struct th1520_mbox_context *ctx = priv->ctx; + u32 i; + /* + * ONLY interrupt mask bit should be stored and restores. + * INFO data all assumed to be lost. + */ + for (i = 0; i < TH_1520_MBOX_CHANS; i++) { + ctx->intr_mask[i] = + ioread32(priv->local_icu[i] + TH_1520_MBOX_MASK); + } + return 0; +} + +static int __maybe_unused th1520_mbox_resume_noirq(struct device *dev) +{ + struct th1520_mbox_priv *priv = dev_get_drvdata(dev); + struct th1520_mbox_context *ctx = priv->ctx; + u32 i; + + for (i = 0; i < TH_1520_MBOX_CHANS; i++) { + iowrite32(ctx->intr_mask[i], + priv->local_icu[i] + TH_1520_MBOX_MASK); + } + + return 0; +} +#endif + +static int __maybe_unused th1520_mbox_runtime_suspend(struct device *dev) +{ + struct th1520_mbox_priv *priv = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(ARRAY_SIZE(priv->clocks), priv->clocks); + + return 0; +} + +static int __maybe_unused th1520_mbox_runtime_resume(struct device *dev) +{ + struct th1520_mbox_priv *priv = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_prepare_enable(ARRAY_SIZE(priv->clocks), priv->clocks); + if (ret) + dev_err(dev, "Failed to enable clocks in runtime resume\n"); + + return ret; +} + +static const struct dev_pm_ops th1520_mbox_pm_ops = { +#ifdef CONFIG_PM_SLEEP + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(th1520_mbox_suspend_noirq, + th1520_mbox_resume_noirq) +#endif + SET_RUNTIME_PM_OPS(th1520_mbox_runtime_suspend, + th1520_mbox_runtime_resume, NULL) +}; + +static struct platform_driver th1520_mbox_driver = { + .probe = th1520_mbox_probe, + .driver = { + .name = "th1520-mbox", + .of_match_table = th1520_mbox_dt_ids, + .pm = &th1520_mbox_pm_ops, + }, +}; +module_platform_driver(th1520_mbox_driver); + +MODULE_DESCRIPTION("Thead TH-1520 mailbox IPC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c index 4bff73532085bd..d186865b8dce64 100644 --- a/drivers/mailbox/mtk-cmdq-mailbox.c +++ b/drivers/mailbox/mtk-cmdq-mailbox.c @@ -397,7 +397,7 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data) task = kzalloc(sizeof(*task), GFP_ATOMIC); if (!task) { - pm_runtime_put_autosuspend(cmdq->mbox.dev); + __pm_runtime_put_autosuspend(cmdq->mbox.dev); return -ENOMEM; } @@ -447,7 +447,7 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data) list_move_tail(&task->list_entry, &thread->task_busy_list); pm_runtime_mark_last_busy(cmdq->mbox.dev); - pm_runtime_put_autosuspend(cmdq->mbox.dev); + __pm_runtime_put_autosuspend(cmdq->mbox.dev); return 0; } @@ -495,7 +495,7 @@ static void cmdq_mbox_shutdown(struct mbox_chan *chan) spin_unlock_irqrestore(&thread->chan->lock, flags); pm_runtime_mark_last_busy(cmdq->mbox.dev); - pm_runtime_put_autosuspend(cmdq->mbox.dev); + __pm_runtime_put_autosuspend(cmdq->mbox.dev); } static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout) @@ -535,7 +535,7 @@ static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout) out: spin_unlock_irqrestore(&thread->chan->lock, flags); pm_runtime_mark_last_busy(cmdq->mbox.dev); - pm_runtime_put_autosuspend(cmdq->mbox.dev); + __pm_runtime_put_autosuspend(cmdq->mbox.dev); return 0; @@ -550,7 +550,7 @@ static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout) return -EFAULT; } pm_runtime_mark_last_busy(cmdq->mbox.dev); - pm_runtime_put_autosuspend(cmdq->mbox.dev); + __pm_runtime_put_autosuspend(cmdq->mbox.dev); return 0; } @@ -584,7 +584,7 @@ static int cmdq_get_clocks(struct device *dev, struct cmdq *cmdq) struct clk_bulk_data *clks; cmdq->clocks = devm_kcalloc(dev, cmdq->pdata->gce_num, - sizeof(cmdq->clocks), GFP_KERNEL); + sizeof(*cmdq->clocks), GFP_KERNEL); if (!cmdq->clocks) return -ENOMEM; @@ -796,7 +796,7 @@ MODULE_DEVICE_TABLE(of, cmdq_of_ids); static struct platform_driver cmdq_drv = { .probe = cmdq_probe, - .remove_new = cmdq_remove, + .remove = cmdq_remove, .driver = { .name = "mtk_cmdq", .pm = &cmdq_pm_ops, diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c index 6797770474a55d..680243751d625f 100644 --- a/drivers/mailbox/omap-mailbox.c +++ b/drivers/mailbox/omap-mailbox.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 94885e411085ad..82102a4c5d6883 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -269,6 +269,35 @@ static bool pcc_mbox_cmd_complete_check(struct pcc_chan_info *pchan) return !!val; } +static void check_and_ack(struct pcc_chan_info *pchan, struct mbox_chan *chan) +{ + struct acpi_pcct_ext_pcc_shared_memory pcc_hdr; + + if (pchan->type != ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) + return; + /* If the memory region has not been mapped, we cannot + * determine if we need to send the message, but we still + * need to set the cmd_update flag before returning. + */ + if (pchan->chan.shmem == NULL) { + pcc_chan_reg_read_modify_write(&pchan->cmd_update); + return; + } + memcpy_fromio(&pcc_hdr, pchan->chan.shmem, + sizeof(struct acpi_pcct_ext_pcc_shared_memory)); + /* + * The PCC slave subspace channel needs to set the command complete bit + * after processing message. If the PCC_ACK_FLAG is set, it should also + * ring the doorbell. + * + * The PCC master subspace channel clears chan_in_use to free channel. + */ + if (le32_to_cpup(&pcc_hdr.flags) & PCC_ACK_FLAG_MASK) + pcc_send_data(chan, NULL); + else + pcc_chan_reg_read_modify_write(&pchan->cmd_update); +} + /** * pcc_mbox_irq - PCC mailbox interrupt handler * @irq: interrupt number @@ -306,14 +335,7 @@ static irqreturn_t pcc_mbox_irq(int irq, void *p) mbox_chan_received_data(chan, NULL); - /* - * The PCC slave subspace channel needs to set the command complete bit - * and ring doorbell after processing message. - * - * The PCC master subspace channel clears chan_in_use to free channel. - */ - if (pchan->type == ACPI_PCCT_TYPE_EXT_PCC_SLAVE_SUBSPACE) - pcc_send_data(chan, NULL); + check_and_ack(pchan, chan); pchan->chan_in_use = false; return IRQ_HANDLED; @@ -365,14 +387,37 @@ EXPORT_SYMBOL_GPL(pcc_mbox_request_channel); void pcc_mbox_free_channel(struct pcc_mbox_chan *pchan) { struct mbox_chan *chan = pchan->mchan; + struct pcc_chan_info *pchan_info; + struct pcc_mbox_chan *pcc_mbox_chan; if (!chan || !chan->cl) return; + pchan_info = chan->con_priv; + pcc_mbox_chan = &pchan_info->chan; + if (pcc_mbox_chan->shmem) { + iounmap(pcc_mbox_chan->shmem); + pcc_mbox_chan->shmem = NULL; + } mbox_free_channel(chan); } EXPORT_SYMBOL_GPL(pcc_mbox_free_channel); +int pcc_mbox_ioremap(struct mbox_chan *chan) +{ + struct pcc_chan_info *pchan_info; + struct pcc_mbox_chan *pcc_mbox_chan; + + if (!chan || !chan->cl) + return -1; + pchan_info = chan->con_priv; + pcc_mbox_chan = &pchan_info->chan; + pcc_mbox_chan->shmem = ioremap(pcc_mbox_chan->shmem_base_addr, + pcc_mbox_chan->shmem_size); + return 0; +} +EXPORT_SYMBOL_GPL(pcc_mbox_ioremap); + /** * pcc_send_data - Called from Mailbox Controller code. Used * here only to ring the channel doorbell. The PCC client diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index 7d91e7c016ba73..f0d1fc0fb9ffc9 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -167,7 +167,7 @@ MODULE_DEVICE_TABLE(of, qcom_apcs_ipc_of_match); static struct platform_driver qcom_apcs_ipc_driver = { .probe = qcom_apcs_ipc_probe, - .remove_new = qcom_apcs_ipc_remove, + .remove = qcom_apcs_ipc_remove, .driver = { .name = "qcom_apcs_ipc", .of_match_table = qcom_apcs_ipc_of_match, diff --git a/drivers/mailbox/qcom-ipcc.c b/drivers/mailbox/qcom-ipcc.c index d537cc9c4d4be0..14c7907c66326f 100644 --- a/drivers/mailbox/qcom-ipcc.c +++ b/drivers/mailbox/qcom-ipcc.c @@ -346,7 +346,7 @@ static const struct dev_pm_ops qcom_ipcc_dev_pm_ops = { static struct platform_driver qcom_ipcc_driver = { .probe = qcom_ipcc_probe, - .remove_new = qcom_ipcc_remove, + .remove = qcom_ipcc_remove, .driver = { .name = "qcom-ipcc", .of_match_table = qcom_ipcc_of_match, diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c index 1442f275782bd5..4f63f1a14ca652 100644 --- a/drivers/mailbox/stm32-ipcc.c +++ b/drivers/mailbox/stm32-ipcc.c @@ -379,7 +379,7 @@ static struct platform_driver stm32_ipcc_driver = { .of_match_table = stm32_ipcc_of_match, }, .probe = stm32_ipcc_probe, - .remove_new = stm32_ipcc_remove, + .remove = stm32_ipcc_remove, }; module_platform_driver(stm32_ipcc_driver); diff --git a/drivers/mailbox/sun6i-msgbox.c b/drivers/mailbox/sun6i-msgbox.c index 3dcc54dc83b2df..6ba6920f4645e7 100644 --- a/drivers/mailbox/sun6i-msgbox.c +++ b/drivers/mailbox/sun6i-msgbox.c @@ -307,8 +307,8 @@ static struct platform_driver sun6i_msgbox_driver = { .name = "sun6i-msgbox", .of_match_table = sun6i_msgbox_of_match, }, - .probe = sun6i_msgbox_probe, - .remove_new = sun6i_msgbox_remove, + .probe = sun6i_msgbox_probe, + .remove = sun6i_msgbox_remove, }; module_platform_driver(sun6i_msgbox_driver); diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 19ef56cbcfd39d..8d5e2d7dc03b2f 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -951,7 +951,7 @@ static struct platform_driver tegra_hsp_driver = { .pm = &tegra_hsp_pm_ops, }, .probe = tegra_hsp_probe, - .remove_new = tegra_hsp_remove, + .remove = tegra_hsp_remove, }; static int __init tegra_hsp_init(void) diff --git a/drivers/mailbox/ti-msgmgr.c b/drivers/mailbox/ti-msgmgr.c index 9d2d4ff6cda403..8eb8df8d95a4cf 100644 --- a/drivers/mailbox/ti-msgmgr.c +++ b/drivers/mailbox/ti-msgmgr.c @@ -920,7 +920,7 @@ static struct platform_driver ti_msgmgr_driver = { .probe = ti_msgmgr_probe, .driver = { .name = "ti-msgmgr", - .of_match_table = of_match_ptr(ti_msgmgr_of_match), + .of_match_table = ti_msgmgr_of_match, .pm = &ti_msgmgr_pm_ops, }, }; diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c index 521d08b9ab47e3..aa5249da59b2f5 100644 --- a/drivers/mailbox/zynqmp-ipi-mailbox.c +++ b/drivers/mailbox/zynqmp-ipi-mailbox.c @@ -940,10 +940,10 @@ static int zynqmp_ipi_probe(struct platform_device *pdev) pdata->num_mboxes = num_mboxes; mbox = pdata->ipi_mboxes; - mbox->setup_ipi_fn = ipi_fn; - for_each_available_child_of_node(np, nc) { mbox->pdata = pdata; + mbox->setup_ipi_fn = ipi_fn; + ret = zynqmp_ipi_mbox_probe(mbox, nc); if (ret) { of_node_put(nc); @@ -1015,7 +1015,7 @@ MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match); static struct platform_driver zynqmp_ipi_driver = { .probe = zynqmp_ipi_probe, - .remove_new = zynqmp_ipi_remove, + .remove = zynqmp_ipi_remove, .driver = { .name = "zynqmp-ipi", .of_match_table = of_match_ptr(zynqmp_ipi_of_match), diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c index 91bbd948ee9318..9b8c40a6459a70 100644 --- a/drivers/mcb/mcb-core.c +++ b/drivers/mcb/mcb-core.c @@ -191,7 +191,7 @@ int __mcb_register_driver(struct mcb_driver *drv, struct module *owner, return driver_register(&drv->driver); } -EXPORT_SYMBOL_NS_GPL(__mcb_register_driver, MCB); +EXPORT_SYMBOL_NS_GPL(__mcb_register_driver, "MCB"); /** * mcb_unregister_driver() - Unregister a @mcb_driver from the system @@ -203,7 +203,7 @@ void mcb_unregister_driver(struct mcb_driver *drv) { driver_unregister(&drv->driver); } -EXPORT_SYMBOL_NS_GPL(mcb_unregister_driver, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_unregister_driver, "MCB"); static void mcb_release_dev(struct device *dev) { @@ -250,7 +250,7 @@ int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev) return ret; } -EXPORT_SYMBOL_NS_GPL(mcb_device_register, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_device_register, "MCB"); static void mcb_free_bus(struct device *dev) { @@ -303,7 +303,7 @@ struct mcb_bus *mcb_alloc_bus(struct device *carrier) put_device(&bus->dev); return ERR_PTR(rc); } -EXPORT_SYMBOL_NS_GPL(mcb_alloc_bus, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_alloc_bus, "MCB"); static int __mcb_devices_unregister(struct device *dev, void *data) { @@ -325,7 +325,7 @@ void mcb_release_bus(struct mcb_bus *bus) { mcb_devices_unregister(bus); } -EXPORT_SYMBOL_NS_GPL(mcb_release_bus, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_release_bus, "MCB"); /** * mcb_bus_get() - Increment refcnt @@ -340,7 +340,7 @@ struct mcb_bus *mcb_bus_get(struct mcb_bus *bus) return bus; } -EXPORT_SYMBOL_NS_GPL(mcb_bus_get, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_bus_get, "MCB"); /** * mcb_bus_put() - Decrement refcnt @@ -353,7 +353,7 @@ void mcb_bus_put(struct mcb_bus *bus) if (bus) put_device(&bus->dev); } -EXPORT_SYMBOL_NS_GPL(mcb_bus_put, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_bus_put, "MCB"); /** * mcb_alloc_dev() - Allocate a device @@ -373,7 +373,7 @@ struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus) return dev; } -EXPORT_SYMBOL_NS_GPL(mcb_alloc_dev, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_alloc_dev, "MCB"); /** * mcb_free_dev() - Free @mcb_device @@ -385,7 +385,7 @@ void mcb_free_dev(struct mcb_device *dev) { kfree(dev); } -EXPORT_SYMBOL_NS_GPL(mcb_free_dev, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_free_dev, "MCB"); static int __mcb_bus_add_devices(struct device *dev, void *data) { @@ -410,7 +410,7 @@ void mcb_bus_add_devices(const struct mcb_bus *bus) { bus_for_each_dev(bus->dev.bus, NULL, NULL, __mcb_bus_add_devices); } -EXPORT_SYMBOL_NS_GPL(mcb_bus_add_devices, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_bus_add_devices, "MCB"); /** * mcb_get_resource() - get a resource for a mcb device @@ -426,7 +426,7 @@ struct resource *mcb_get_resource(struct mcb_device *dev, unsigned int type) else return NULL; } -EXPORT_SYMBOL_NS_GPL(mcb_get_resource, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_get_resource, "MCB"); /** * mcb_request_mem() - Request memory @@ -452,7 +452,7 @@ struct resource *mcb_request_mem(struct mcb_device *dev, const char *name) return mem; } -EXPORT_SYMBOL_NS_GPL(mcb_request_mem, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_request_mem, "MCB"); /** * mcb_release_mem() - Release memory requested by device @@ -467,7 +467,7 @@ void mcb_release_mem(struct resource *mem) size = resource_size(mem); release_mem_region(mem->start, size); } -EXPORT_SYMBOL_NS_GPL(mcb_release_mem, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_release_mem, "MCB"); static int __mcb_get_irq(struct mcb_device *dev) { @@ -493,7 +493,7 @@ int mcb_get_irq(struct mcb_device *dev) return __mcb_get_irq(dev); } -EXPORT_SYMBOL_NS_GPL(mcb_get_irq, MCB); +EXPORT_SYMBOL_NS_GPL(mcb_get_irq, "MCB"); static int mcb_init(void) { diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c index 2bec2086ee1719..070aa787abc606 100644 --- a/drivers/mcb/mcb-lpc.c +++ b/drivers/mcb/mcb-lpc.c @@ -138,7 +138,7 @@ static struct platform_driver mcb_lpc_driver = { .name = "mcb-lpc", }, .probe = mcb_lpc_probe, - .remove_new = mcb_lpc_remove, + .remove = mcb_lpc_remove, }; static const struct dmi_system_id mcb_lpc_dmi_table[] = { @@ -184,4 +184,4 @@ module_exit(mcb_lpc_exit); MODULE_AUTHOR("Andreas Werner "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MCB over LPC support"); -MODULE_IMPORT_NS(MCB); +MODULE_IMPORT_NS("MCB"); diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c index a5f8ab9a09103d..02a680c73979b9 100644 --- a/drivers/mcb/mcb-parse.c +++ b/drivers/mcb/mcb-parse.c @@ -251,4 +251,4 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, return ret; } -EXPORT_SYMBOL_NS_GPL(chameleon_parse_cells, MCB); +EXPORT_SYMBOL_NS_GPL(chameleon_parse_cells, "MCB"); diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c index 3b634ea318c741..f1353da6ef4fc4 100644 --- a/drivers/mcb/mcb-pci.c +++ b/drivers/mcb/mcb-pci.c @@ -154,4 +154,4 @@ module_pci_driver(mcb_pci_driver); MODULE_AUTHOR("Johannes Thumshirn "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MCB over PCI support"); -MODULE_IMPORT_NS(MCB); +MODULE_IMPORT_NS("MCB"); diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig index b2d10063d35fb4..d4697e79d5a391 100644 --- a/drivers/md/bcache/Kconfig +++ b/drivers/md/bcache/Kconfig @@ -5,6 +5,7 @@ config BCACHE select BLOCK_HOLDER_DEPRECATED if SYSFS select CRC64 select CLOSURES + select MIN_HEAP help Allows a block device to be used as cache for other devices; uses a btree for indexing and the layout is optimized for SSDs. diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index da50f6661bae46..8998e61efa406f 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -189,23 +189,16 @@ static inline bool new_bucket_min_cmp(const void *l, const void *r, void *args) return new_bucket_prio(ca, *lhs) < new_bucket_prio(ca, *rhs); } -static inline void new_bucket_swap(void *l, void *r, void __always_unused *args) -{ - struct bucket **lhs = l, **rhs = r; - - swap(*lhs, *rhs); -} - static void invalidate_buckets_lru(struct cache *ca) { struct bucket *b; const struct min_heap_callbacks bucket_max_cmp_callback = { .less = new_bucket_max_cmp, - .swp = new_bucket_swap, + .swp = NULL, }; const struct min_heap_callbacks bucket_min_cmp_callback = { .less = new_bucket_min_cmp, - .swp = new_bucket_swap, + .swp = NULL, }; ca->heap.nr = 0; diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c index bd97d862688744..68258a16e125cf 100644 --- a/drivers/md/bcache/bset.c +++ b/drivers/md/bcache/bset.c @@ -1093,14 +1093,6 @@ static inline bool new_btree_iter_cmp(const void *l, const void *r, void __alway return bkey_cmp(_l->k, _r->k) <= 0; } -static inline void new_btree_iter_swap(void *iter1, void *iter2, void __always_unused *args) -{ - struct btree_iter_set *_iter1 = iter1; - struct btree_iter_set *_iter2 = iter2; - - swap(*_iter1, *_iter2); -} - static inline bool btree_iter_end(struct btree_iter *iter) { return !iter->heap.nr; @@ -1111,7 +1103,7 @@ void bch_btree_iter_push(struct btree_iter *iter, struct bkey *k, { const struct min_heap_callbacks callbacks = { .less = new_btree_iter_cmp, - .swp = new_btree_iter_swap, + .swp = NULL, }; if (k != end) @@ -1157,7 +1149,7 @@ static inline struct bkey *__bch_btree_iter_next(struct btree_iter *iter, struct bkey *ret = NULL; const struct min_heap_callbacks callbacks = { .less = cmp, - .swp = new_btree_iter_swap, + .swp = NULL, }; if (!btree_iter_end(iter)) { @@ -1231,7 +1223,7 @@ static void btree_mergesort(struct btree_keys *b, struct bset *out, : bch_ptr_invalid; const struct min_heap_callbacks callbacks = { .less = b->ops->sort_cmp, - .swp = new_btree_iter_swap, + .swp = NULL, }; /* Heapify the iterator, using our comparison function */ diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c index a7221e5dbe8175..4b84fda1530a79 100644 --- a/drivers/md/bcache/extents.c +++ b/drivers/md/bcache/extents.c @@ -266,20 +266,12 @@ static bool new_bch_extent_sort_cmp(const void *l, const void *r, void __always_ return !(c ? c > 0 : _l->k < _r->k); } -static inline void new_btree_iter_swap(void *iter1, void *iter2, void __always_unused *args) -{ - struct btree_iter_set *_iter1 = iter1; - struct btree_iter_set *_iter2 = iter2; - - swap(*_iter1, *_iter2); -} - static struct bkey *bch_extent_sort_fixup(struct btree_iter *iter, struct bkey *tmp) { const struct min_heap_callbacks callbacks = { .less = new_bch_extent_sort_cmp, - .swp = new_btree_iter_swap, + .swp = NULL, }; while (iter->heap.nr > 1) { struct btree_iter_set *top = iter->heap.data, *i = top + 1; diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c index 7f482729c56de6..ef6abf33f9260d 100644 --- a/drivers/md/bcache/movinggc.c +++ b/drivers/md/bcache/movinggc.c @@ -190,14 +190,6 @@ static bool new_bucket_cmp(const void *l, const void *r, void __always_unused *a return GC_SECTORS_USED(*_l) >= GC_SECTORS_USED(*_r); } -static void new_bucket_swap(void *l, void *r, void __always_unused *args) -{ - struct bucket **_l = l; - struct bucket **_r = r; - - swap(*_l, *_r); -} - static unsigned int bucket_heap_top(struct cache *ca) { struct bucket *b; @@ -212,7 +204,7 @@ void bch_moving_gc(struct cache_set *c) unsigned long sectors_to_move, reserve_sectors; const struct min_heap_callbacks callbacks = { .less = new_bucket_cmp, - .swp = new_bucket_swap, + .swp = NULL, }; if (!c->copy_gc_enabled) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index e7abfdd77c3b66..e42f1400cea9d7 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1718,7 +1718,7 @@ static CLOSURE_CALLBACK(cache_set_flush) if (!IS_ERR_OR_NULL(c->gc_thread)) kthread_stop(c->gc_thread); - if (!IS_ERR(c->root)) + if (!IS_ERR_OR_NULL(c->root)) list_add(&c->root->list, &c->btree_cache); /* diff --git a/drivers/md/dm-bio-prison-v1.c b/drivers/md/dm-bio-prison-v1.c index bca0f39e15b87a..b4d1c4329df34e 100644 --- a/drivers/md/dm-bio-prison-v1.c +++ b/drivers/md/dm-bio-prison-v1.c @@ -198,15 +198,6 @@ int dm_bio_detain(struct dm_bio_prison *prison, } EXPORT_SYMBOL_GPL(dm_bio_detain); -int dm_get_cell(struct dm_bio_prison *prison, - struct dm_cell_key *key, - struct dm_bio_prison_cell *cell_prealloc, - struct dm_bio_prison_cell **cell_result) -{ - return bio_detain(prison, key, NULL, cell_prealloc, cell_result); -} -EXPORT_SYMBOL_GPL(dm_get_cell); - /* * @inmates must have been initialised prior to this call */ @@ -288,32 +279,6 @@ void dm_cell_visit_release(struct dm_bio_prison *prison, } EXPORT_SYMBOL_GPL(dm_cell_visit_release); -static int __promote_or_release(struct rb_root *root, - struct dm_bio_prison_cell *cell) -{ - if (bio_list_empty(&cell->bios)) { - rb_erase(&cell->node, root); - return 1; - } - - cell->holder = bio_list_pop(&cell->bios); - return 0; -} - -int dm_cell_promote_or_release(struct dm_bio_prison *prison, - struct dm_bio_prison_cell *cell) -{ - int r; - unsigned l = lock_nr(&cell->key, prison->num_locks); - - spin_lock_irq(&prison->regions[l].lock); - r = __promote_or_release(&prison->regions[l].cell, cell); - spin_unlock_irq(&prison->regions[l].lock); - - return r; -} -EXPORT_SYMBOL_GPL(dm_cell_promote_or_release); - /*----------------------------------------------------------------*/ #define DEFERRED_SET_SIZE 64 diff --git a/drivers/md/dm-bio-prison-v1.h b/drivers/md/dm-bio-prison-v1.h index 2a097ed0d85e9b..d39706c484476a 100644 --- a/drivers/md/dm-bio-prison-v1.h +++ b/drivers/md/dm-bio-prison-v1.h @@ -72,17 +72,6 @@ struct dm_bio_prison_cell *dm_bio_prison_alloc_cell(struct dm_bio_prison *prison void dm_bio_prison_free_cell(struct dm_bio_prison *prison, struct dm_bio_prison_cell *cell); -/* - * Creates, or retrieves a cell that overlaps the given key. - * - * Returns 1 if pre-existing cell returned, zero if new cell created using - * @cell_prealloc. - */ -int dm_get_cell(struct dm_bio_prison *prison, - struct dm_cell_key *key, - struct dm_bio_prison_cell *cell_prealloc, - struct dm_bio_prison_cell **cell_result); - /* * Returns false if key is beyond BIO_PRISON_MAX_RANGE or spans a boundary. */ @@ -117,19 +106,6 @@ void dm_cell_visit_release(struct dm_bio_prison *prison, void (*visit_fn)(void *, struct dm_bio_prison_cell *), void *context, struct dm_bio_prison_cell *cell); -/* - * Rather than always releasing the prisoners in a cell, the client may - * want to promote one of them to be the new holder. There is a race here - * though between releasing an empty cell, and other threads adding new - * inmates. So this function makes the decision with its lock held. - * - * This function can have two outcomes: - * i) An inmate is promoted to be the holder of the cell (return value of 0). - * ii) The cell has no inmate for promotion and is released (return value of 1). - */ -int dm_cell_promote_or_release(struct dm_bio_prison *prison, - struct dm_bio_prison_cell *cell); - /*----------------------------------------------------------------*/ /* diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 23e0b71b991e75..aab8240429b0ba 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -318,9 +318,10 @@ static struct lru_entry *lru_evict(struct lru *lru, le_predicate pred, void *con */ enum data_mode { DATA_MODE_SLAB = 0, - DATA_MODE_GET_FREE_PAGES = 1, - DATA_MODE_VMALLOC = 2, - DATA_MODE_LIMIT = 3 + DATA_MODE_KMALLOC = 1, + DATA_MODE_GET_FREE_PAGES = 2, + DATA_MODE_VMALLOC = 3, + DATA_MODE_LIMIT = 4 }; struct dm_buffer { @@ -1062,6 +1063,7 @@ static unsigned long dm_bufio_retain_bytes = DM_BUFIO_DEFAULT_RETAIN_BYTES; static unsigned long dm_bufio_peak_allocated; static unsigned long dm_bufio_allocated_kmem_cache; +static unsigned long dm_bufio_allocated_kmalloc; static unsigned long dm_bufio_allocated_get_free_pages; static unsigned long dm_bufio_allocated_vmalloc; static unsigned long dm_bufio_current_allocated; @@ -1104,6 +1106,7 @@ static void adjust_total_allocated(struct dm_buffer *b, bool unlink) static unsigned long * const class_ptr[DATA_MODE_LIMIT] = { &dm_bufio_allocated_kmem_cache, + &dm_bufio_allocated_kmalloc, &dm_bufio_allocated_get_free_pages, &dm_bufio_allocated_vmalloc, }; @@ -1181,6 +1184,11 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, return kmem_cache_alloc(c->slab_cache, gfp_mask); } + if (unlikely(c->block_size < PAGE_SIZE)) { + *data_mode = DATA_MODE_KMALLOC; + return kmalloc(c->block_size, gfp_mask | __GFP_RECLAIMABLE); + } + if (c->block_size <= KMALLOC_MAX_SIZE && gfp_mask & __GFP_NORETRY) { *data_mode = DATA_MODE_GET_FREE_PAGES; @@ -1204,6 +1212,10 @@ static void free_buffer_data(struct dm_bufio_client *c, kmem_cache_free(c->slab_cache, data); break; + case DATA_MODE_KMALLOC: + kfree(data); + break; + case DATA_MODE_GET_FREE_PAGES: free_pages((unsigned long)data, c->sectors_per_block_bits - (PAGE_SHIFT - SECTOR_SHIFT)); @@ -2519,8 +2531,7 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign goto bad_dm_io; } - if (block_size <= KMALLOC_MAX_SIZE && - (block_size < PAGE_SIZE || !is_power_of_2(block_size))) { + if (block_size <= KMALLOC_MAX_SIZE && !is_power_of_2(block_size)) { unsigned int align = min(1U << __ffs(block_size), (unsigned int)PAGE_SIZE); snprintf(slab_name, sizeof(slab_name), "dm_bufio_cache-%u-%u", @@ -2902,6 +2913,7 @@ static int __init dm_bufio_init(void) __u64 mem; dm_bufio_allocated_kmem_cache = 0; + dm_bufio_allocated_kmalloc = 0; dm_bufio_allocated_get_free_pages = 0; dm_bufio_allocated_vmalloc = 0; dm_bufio_current_allocated = 0; @@ -2990,6 +3002,9 @@ MODULE_PARM_DESC(peak_allocated_bytes, "Tracks the maximum allocated memory"); module_param_named(allocated_kmem_cache_bytes, dm_bufio_allocated_kmem_cache, ulong, 0444); MODULE_PARM_DESC(allocated_kmem_cache_bytes, "Memory allocated with kmem_cache_alloc"); +module_param_named(allocated_kmalloc_bytes, dm_bufio_allocated_kmalloc, ulong, 0444); +MODULE_PARM_DESC(allocated_kmalloc_bytes, "Memory allocated with kmalloc_alloc"); + module_param_named(allocated_get_free_pages_bytes, dm_bufio_allocated_get_free_pages, ulong, 0444); MODULE_PARM_DESC(allocated_get_free_pages_bytes, "Memory allocated with get_free_pages"); diff --git a/drivers/md/dm-cache-background-tracker.c b/drivers/md/dm-cache-background-tracker.c index f3051bd7d2df07..b4165f172d62f5 100644 --- a/drivers/md/dm-cache-background-tracker.c +++ b/drivers/md/dm-cache-background-tracker.c @@ -143,12 +143,6 @@ static void update_stats(struct background_tracker *b, struct policy_work *w, in } } -unsigned int btracker_nr_writebacks_queued(struct background_tracker *b) -{ - return atomic_read(&b->pending_writebacks); -} -EXPORT_SYMBOL_GPL(btracker_nr_writebacks_queued); - unsigned int btracker_nr_demotions_queued(struct background_tracker *b) { return atomic_read(&b->pending_demotes); diff --git a/drivers/md/dm-cache-background-tracker.h b/drivers/md/dm-cache-background-tracker.h index 09c8fc59f7bb7b..47156c14a44abf 100644 --- a/drivers/md/dm-cache-background-tracker.h +++ b/drivers/md/dm-cache-background-tracker.h @@ -50,7 +50,6 @@ struct background_tracker *btracker_create(unsigned int max_work); */ void btracker_destroy(struct background_tracker *b); -unsigned int btracker_nr_writebacks_queued(struct background_tracker *b); unsigned int btracker_nr_demotions_queued(struct background_tracker *b); /* diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index 24cd87fddf752b..a9a1ab284076a9 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -1218,15 +1218,6 @@ int dm_cache_load_discards(struct dm_cache_metadata *cmd, return r; } -int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result) -{ - READ_LOCK(cmd); - *result = cmd->cache_blocks; - READ_UNLOCK(cmd); - - return 0; -} - static int __remove(struct dm_cache_metadata *cmd, dm_cblock_t cblock) { int r; @@ -1507,30 +1498,6 @@ int dm_cache_load_mappings(struct dm_cache_metadata *cmd, return r; } -static int __dump_mapping(void *context, uint64_t cblock, void *leaf) -{ - __le64 value; - dm_oblock_t oblock; - unsigned int flags; - - memcpy(&value, leaf, sizeof(value)); - unpack_value(value, &oblock, &flags); - - return 0; -} - -static int __dump_mappings(struct dm_cache_metadata *cmd) -{ - return dm_array_walk(&cmd->info, cmd->root, __dump_mapping, NULL); -} - -void dm_cache_dump(struct dm_cache_metadata *cmd) -{ - READ_LOCK_VOID(cmd); - __dump_mappings(cmd); - READ_UNLOCK(cmd); -} - int dm_cache_changed_this_transaction(struct dm_cache_metadata *cmd) { int r; diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h index 57afc704794728..5f77890207fede 100644 --- a/drivers/md/dm-cache-metadata.h +++ b/drivers/md/dm-cache-metadata.h @@ -71,7 +71,6 @@ void dm_cache_metadata_close(struct dm_cache_metadata *cmd); * origin blocks to map to. */ int dm_cache_resize(struct dm_cache_metadata *cmd, dm_cblock_t new_cache_size); -int dm_cache_size(struct dm_cache_metadata *cmd, dm_cblock_t *result); int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd, sector_t discard_block_size, @@ -123,8 +122,6 @@ int dm_cache_get_free_metadata_block_count(struct dm_cache_metadata *cmd, int dm_cache_get_metadata_dev_size(struct dm_cache_metadata *cmd, dm_block_t *result); -void dm_cache_dump(struct dm_cache_metadata *cmd); - /* * The policy is invited to save a 32bit hint value for every cblock (eg, * for a hit count). These are stored against the policy name. If diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 849eb6333e980f..9cb797a561d6e3 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -3362,7 +3362,7 @@ static int cache_iterate_devices(struct dm_target *ti, static void disable_passdown_if_not_supported(struct cache *cache) { struct block_device *origin_bdev = cache->origin_dev->bdev; - struct queue_limits *origin_limits = &bdev_get_queue(origin_bdev)->limits; + struct queue_limits *origin_limits = bdev_limits(origin_bdev); const char *reason = NULL; if (!cache->features.discard_passdown) @@ -3384,7 +3384,7 @@ static void disable_passdown_if_not_supported(struct cache *cache) static void set_discard_limits(struct cache *cache, struct queue_limits *limits) { struct block_device *origin_bdev = cache->origin_dev->bdev; - struct queue_limits *origin_limits = &bdev_get_queue(origin_bdev)->limits; + struct queue_limits *origin_limits = bdev_limits(origin_bdev); if (!cache->features.discard_passdown) { /* No passdown is done so setting own virtual limits */ diff --git a/drivers/md/dm-clone-target.c b/drivers/md/dm-clone-target.c index 12bbe487a4c895..e956d980672c80 100644 --- a/drivers/md/dm-clone-target.c +++ b/drivers/md/dm-clone-target.c @@ -2020,7 +2020,7 @@ static void clone_resume(struct dm_target *ti) static void disable_passdown_if_not_supported(struct clone *clone) { struct block_device *dest_dev = clone->dest_dev->bdev; - struct queue_limits *dest_limits = &bdev_get_queue(dest_dev)->limits; + struct queue_limits *dest_limits = bdev_limits(dest_dev); const char *reason = NULL; if (!test_bit(DM_CLONE_DISCARD_PASSDOWN, &clone->flags)) @@ -2041,7 +2041,7 @@ static void disable_passdown_if_not_supported(struct clone *clone) static void set_discard_limits(struct clone *clone, struct queue_limits *limits) { struct block_device *dest_bdev = clone->dest_dev->bdev; - struct queue_limits *dest_limits = &bdev_get_queue(dest_bdev)->limits; + struct queue_limits *dest_limits = bdev_limits(dest_bdev); if (!test_bit(DM_CLONE_DISCARD_PASSDOWN, &clone->flags)) { /* No passdown is done so we set our own virtual limits */ diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index f299ff393a6a2c..d42eac944eb54b 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1912,7 +1912,7 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user, if ((kernel_params->version[0] != DM_VERSION_MAJOR) || (kernel_params->version[1] > DM_VERSION_MINOR)) { - DMERR("ioctl interface mismatch: kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", + DMERR_LIMIT("ioctl interface mismatch: kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)", DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, kernel_params->version[0], @@ -1961,7 +1961,7 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern if (unlikely(param_kernel->data_size < minimum_data_size) || unlikely(param_kernel->data_size > DM_MAX_TARGETS * DM_MAX_TARGET_PARAMS)) { - DMERR("Invalid data size in the ioctl structure: %u", + DMERR_LIMIT("Invalid data size in the ioctl structure: %u", param_kernel->data_size); return -EINVAL; } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index dbd39b9722b912..bd8b796ae683bb 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1033,11 +1033,6 @@ struct dm_target *dm_table_get_wildcard_target(struct dm_table *t) return NULL; } -bool dm_table_bio_based(struct dm_table *t) -{ - return __table_type_bio_based(dm_table_get_type(t)); -} - bool dm_table_request_based(struct dm_table *t) { return __table_type_request_based(dm_table_get_type(t)); diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 89632ce9776056..bf0f9dddd146ab 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -2484,6 +2484,7 @@ static void pool_work_wait(struct pool_work *pw, struct pool *pool, init_completion(&pw->complete); queue_work(pool->wq, &pw->worker); wait_for_completion(&pw->complete); + destroy_work_on_stack(&pw->worker); } /*----------------------------------------------------------------*/ @@ -2842,7 +2843,7 @@ static void disable_discard_passdown_if_not_supported(struct pool_c *pt) { struct pool *pool = pt->pool; struct block_device *data_bdev = pt->data_dev->bdev; - struct queue_limits *data_limits = &bdev_get_queue(data_bdev)->limits; + struct queue_limits *data_limits = bdev_limits(data_bdev); const char *reason = NULL; if (!pt->adjusted_pf.discard_passdown) diff --git a/drivers/md/dm-vdo/Kconfig b/drivers/md/dm-vdo/Kconfig index 111ecd2c2a2495..2400b2bc4bc729 100644 --- a/drivers/md/dm-vdo/Kconfig +++ b/drivers/md/dm-vdo/Kconfig @@ -7,6 +7,7 @@ config DM_VDO select DM_BUFIO select LZ4_COMPRESS select LZ4_DECOMPRESS + select MIN_HEAP help This device mapper target presents a block device with deduplication, compression and thin-provisioning. diff --git a/drivers/md/dm-vdo/block-map.c b/drivers/md/dm-vdo/block-map.c index a0a7c1bd634e8a..89cb7942ec5cc9 100644 --- a/drivers/md/dm-vdo/block-map.c +++ b/drivers/md/dm-vdo/block-map.c @@ -209,8 +209,6 @@ static int initialize_info(struct vdo_page_cache *cache) /** * allocate_cache_components() - Allocate components of the cache which require their own * allocation. - * @maximum_age: The number of journal blocks before a dirtied page is considered old and must be - * written out. * * The caller is responsible for all clean up on errors. * diff --git a/drivers/md/dm-vdo/data-vio.c b/drivers/md/dm-vdo/data-vio.c index 0d502f6a86ad02..810002747091f3 100644 --- a/drivers/md/dm-vdo/data-vio.c +++ b/drivers/md/dm-vdo/data-vio.c @@ -327,8 +327,9 @@ static u32 __must_check pack_status(struct data_vio_compression_status status) /** * set_data_vio_compression_status() - Set the compression status of a data_vio. - * @state: The expected current status of the data_vio. - * @new_state: The status to set. + * @data_vio: The data_vio to change. + * @status: The expected current status of the data_vio. + * @new_status: The status to set. * * Return: true if the new status was set, false if the data_vio's compression status did not * match the expected state, and so was left unchanged. @@ -836,7 +837,7 @@ static void destroy_data_vio(struct data_vio *data_vio) * @vdo: The vdo to which the pool will belong. * @pool_size: The number of data_vios in the pool. * @discard_limit: The maximum number of data_vios which may be used for discards. - * @pool: A pointer to hold the newly allocated pool. + * @pool_ptr: A pointer to hold the newly allocated pool. */ int make_data_vio_pool(struct vdo *vdo, data_vio_count_t pool_size, data_vio_count_t discard_limit, struct data_vio_pool **pool_ptr) @@ -1074,35 +1075,6 @@ void dump_data_vio_pool(struct data_vio_pool *pool, bool dump_vios) spin_unlock(&pool->lock); } -data_vio_count_t get_data_vio_pool_active_discards(struct data_vio_pool *pool) -{ - return READ_ONCE(pool->discard_limiter.busy); -} - -data_vio_count_t get_data_vio_pool_discard_limit(struct data_vio_pool *pool) -{ - return READ_ONCE(pool->discard_limiter.limit); -} - -data_vio_count_t get_data_vio_pool_maximum_discards(struct data_vio_pool *pool) -{ - return READ_ONCE(pool->discard_limiter.max_busy); -} - -int set_data_vio_pool_discard_limit(struct data_vio_pool *pool, data_vio_count_t limit) -{ - if (get_data_vio_pool_request_limit(pool) < limit) { - // The discard limit may not be higher than the data_vio limit. - return -EINVAL; - } - - spin_lock(&pool->lock); - pool->discard_limiter.limit = limit; - spin_unlock(&pool->lock); - - return VDO_SUCCESS; -} - data_vio_count_t get_data_vio_pool_active_requests(struct data_vio_pool *pool) { return READ_ONCE(pool->limiter.busy); diff --git a/drivers/md/dm-vdo/data-vio.h b/drivers/md/dm-vdo/data-vio.h index 25926b6cd98bb7..067b983bb291db 100644 --- a/drivers/md/dm-vdo/data-vio.h +++ b/drivers/md/dm-vdo/data-vio.h @@ -336,11 +336,6 @@ void drain_data_vio_pool(struct data_vio_pool *pool, struct vdo_completion *comp void resume_data_vio_pool(struct data_vio_pool *pool, struct vdo_completion *completion); void dump_data_vio_pool(struct data_vio_pool *pool, bool dump_vios); -data_vio_count_t get_data_vio_pool_active_discards(struct data_vio_pool *pool); -data_vio_count_t get_data_vio_pool_discard_limit(struct data_vio_pool *pool); -data_vio_count_t get_data_vio_pool_maximum_discards(struct data_vio_pool *pool); -int __must_check set_data_vio_pool_discard_limit(struct data_vio_pool *pool, - data_vio_count_t limit); data_vio_count_t get_data_vio_pool_active_requests(struct data_vio_pool *pool); data_vio_count_t get_data_vio_pool_request_limit(struct data_vio_pool *pool); data_vio_count_t get_data_vio_pool_maximum_requests(struct data_vio_pool *pool); diff --git a/drivers/md/dm-vdo/dedupe.c b/drivers/md/dm-vdo/dedupe.c index 80628ae93fbacc..b6f8e2dc7729fb 100644 --- a/drivers/md/dm-vdo/dedupe.c +++ b/drivers/md/dm-vdo/dedupe.c @@ -565,7 +565,7 @@ static void wait_on_hash_lock(struct hash_lock *lock, struct data_vio *data_vio) * @waiter: The data_vio's waiter link. * @context: Not used. */ -static void abort_waiter(struct vdo_waiter *waiter, void *context __always_unused) +static void abort_waiter(struct vdo_waiter *waiter, void __always_unused *context) { write_data_vio(vdo_waiter_as_data_vio(waiter)); } @@ -1727,7 +1727,7 @@ static void report_bogus_lock_state(struct hash_lock *lock, struct data_vio *dat /** * vdo_continue_hash_lock() - Continue the processing state after writing, compressing, or * deduplicating. - * @data_vio: The data_vio to continue processing in its hash lock. + * @completion: The data_vio completion to continue processing in its hash lock. * * Asynchronously continue processing a data_vio in its hash lock after it has finished writing, * compressing, or deduplicating, so it can share the result with any data_vios waiting in the hash @@ -1825,7 +1825,7 @@ static inline int assert_hash_lock_preconditions(const struct data_vio *data_vio /** * vdo_acquire_hash_lock() - Acquire or share a lock on a record name. - * @data_vio: The data_vio acquiring a lock on its record name. + * @completion: The data_vio completion acquiring a lock on its record name. * * Acquire or share a lock on the hash (record name) of the data in a data_vio, updating the * data_vio to reference the lock. This must only be called in the correct thread for the zone. In @@ -2679,7 +2679,8 @@ static void get_index_statistics(struct hash_zones *zones, /** * vdo_get_dedupe_statistics() - Tally the statistics from all the hash zones and the UDS index. - * @hash_zones: The hash zones to query + * @zones: The hash zones to query + * @stats: A structure to store the statistics * * Return: The sum of the hash lock statistics from all hash zones plus the statistics from the UDS * index diff --git a/drivers/md/dm-vdo/encodings.c b/drivers/md/dm-vdo/encodings.c index a34ea0229d5366..100e92f8f866c8 100644 --- a/drivers/md/dm-vdo/encodings.c +++ b/drivers/md/dm-vdo/encodings.c @@ -858,7 +858,7 @@ static int __must_check make_partition(struct layout *layout, enum partition_id /** * vdo_initialize_layout() - Lay out the partitions of a vdo. * @size: The entire size of the vdo. - * @origin: The start of the layout on the underlying storage in blocks. + * @offset: The start of the layout on the underlying storage in blocks. * @block_map_blocks: The size of the block map partition. * @journal_blocks: The size of the journal partition. * @summary_blocks: The size of the slab summary partition. diff --git a/drivers/md/dm-vdo/indexer/index-layout.c b/drivers/md/dm-vdo/indexer/index-layout.c index 627adc24af3b76..af8fab83b0f3ec 100644 --- a/drivers/md/dm-vdo/indexer/index-layout.c +++ b/drivers/md/dm-vdo/indexer/index-layout.c @@ -248,32 +248,6 @@ static int __must_check compute_sizes(const struct uds_configuration *config, return UDS_SUCCESS; } -int uds_compute_index_size(const struct uds_parameters *parameters, u64 *index_size) -{ - int result; - struct uds_configuration *index_config; - struct save_layout_sizes sizes; - - if (index_size == NULL) { - vdo_log_error("Missing output size pointer"); - return -EINVAL; - } - - result = uds_make_configuration(parameters, &index_config); - if (result != UDS_SUCCESS) { - vdo_log_error_strerror(result, "cannot compute index size"); - return uds_status_to_errno(result); - } - - result = compute_sizes(index_config, &sizes); - uds_free_configuration(index_config); - if (result != UDS_SUCCESS) - return uds_status_to_errno(result); - - *index_size = sizes.total_size; - return UDS_SUCCESS; -} - /* Create unique data using the current time and a pseudorandom number. */ static void create_unique_nonce_data(u8 *buffer) { diff --git a/drivers/md/dm-vdo/indexer/indexer.h b/drivers/md/dm-vdo/indexer/indexer.h index 3744aaf625b051..183a94eb7e923f 100644 --- a/drivers/md/dm-vdo/indexer/indexer.h +++ b/drivers/md/dm-vdo/indexer/indexer.h @@ -283,10 +283,6 @@ struct uds_request { enum uds_index_region location; }; -/* Compute the number of bytes needed to store an index. */ -int __must_check uds_compute_index_size(const struct uds_parameters *parameters, - u64 *index_size); - /* A session is required for most index operations. */ int __must_check uds_create_index_session(struct uds_index_session **session); diff --git a/drivers/md/dm-vdo/int-map.c b/drivers/md/dm-vdo/int-map.c index f6fe58e437b3a2..aeb690415dbd18 100644 --- a/drivers/md/dm-vdo/int-map.c +++ b/drivers/md/dm-vdo/int-map.c @@ -70,7 +70,7 @@ * it's crucial to keep the hop fields near the buckets that they use them so they'll tend to share * cache lines. */ -struct __packed bucket { +struct bucket { /** * @first_hop: The biased offset of the first entry in the hop list of the neighborhood * that hashes to this bucket. @@ -82,7 +82,7 @@ struct __packed bucket { u64 key; /** @value: The value stored in this bucket (NULL if empty). */ void *value; -}; +} __packed; /** * struct int_map - The concrete definition of the opaque int_map type. @@ -310,7 +310,6 @@ static struct bucket *select_bucket(const struct int_map *map, u64 key) /** * search_hop_list() - Search the hop list associated with given hash bucket for a given search * key. - * @map: The map being searched. * @bucket: The map bucket to search for the key. * @key: The mapping key. * @previous_ptr: Output. if not NULL, a pointer in which to store the bucket in the list preceding @@ -321,9 +320,7 @@ static struct bucket *select_bucket(const struct int_map *map, u64 key) * * Return: An entry that matches the key, or NULL if not found. */ -static struct bucket *search_hop_list(struct int_map *map __always_unused, - struct bucket *bucket, - u64 key, +static struct bucket *search_hop_list(struct bucket *bucket, u64 key, struct bucket **previous_ptr) { struct bucket *previous = NULL; @@ -357,7 +354,7 @@ static struct bucket *search_hop_list(struct int_map *map __always_unused, */ void *vdo_int_map_get(struct int_map *map, u64 key) { - struct bucket *match = search_hop_list(map, select_bucket(map, key), key, NULL); + struct bucket *match = search_hop_list(select_bucket(map, key), key, NULL); return ((match != NULL) ? match->value : NULL); } @@ -443,7 +440,6 @@ find_empty_bucket(struct int_map *map, struct bucket *bucket, unsigned int max_p /** * move_empty_bucket() - Move an empty bucket closer to the start of the bucket array. - * @map: The map containing the bucket. * @hole: The empty bucket to fill with an entry that precedes it in one of its enclosing * neighborhoods. * @@ -454,8 +450,7 @@ find_empty_bucket(struct int_map *map, struct bucket *bucket, unsigned int max_p * Return: The bucket that was vacated by moving its entry to the provided hole, or NULL if no * entry could be moved. */ -static struct bucket *move_empty_bucket(struct int_map *map __always_unused, - struct bucket *hole) +static struct bucket *move_empty_bucket(struct bucket *hole) { /* * Examine every neighborhood that the empty bucket is part of, starting with the one in @@ -516,7 +511,6 @@ static struct bucket *move_empty_bucket(struct int_map *map __always_unused, /** * update_mapping() - Find and update any existing mapping for a given key, returning the value * associated with the key in the provided pointer. - * @map: The int_map to attempt to modify. * @neighborhood: The first bucket in the neighborhood that would contain the search key * @key: The key with which to associate the new value. * @new_value: The value to be associated with the key. @@ -525,10 +519,10 @@ static struct bucket *move_empty_bucket(struct int_map *map __always_unused, * * Return: true if the map contains a mapping for the key, false if it does not. */ -static bool update_mapping(struct int_map *map, struct bucket *neighborhood, - u64 key, void *new_value, bool update, void **old_value_ptr) +static bool update_mapping(struct bucket *neighborhood, u64 key, void *new_value, + bool update, void **old_value_ptr) { - struct bucket *bucket = search_hop_list(map, neighborhood, key, NULL); + struct bucket *bucket = search_hop_list(neighborhood, key, NULL); if (bucket == NULL) { /* There is no bucket containing the key in the neighborhood. */ @@ -584,7 +578,7 @@ static struct bucket *find_or_make_vacancy(struct int_map *map, * The nearest empty bucket isn't within the neighborhood that must contain the new * entry, so try to swap it with bucket that is closer. */ - hole = move_empty_bucket(map, hole); + hole = move_empty_bucket(hole); } return NULL; @@ -625,7 +619,7 @@ int vdo_int_map_put(struct int_map *map, u64 key, void *new_value, bool update, * Check whether the neighborhood already contains an entry for the key, in which case we * optionally update it, returning the old value. */ - if (update_mapping(map, neighborhood, key, new_value, update, old_value_ptr)) + if (update_mapping(neighborhood, key, new_value, update, old_value_ptr)) return VDO_SUCCESS; /* @@ -679,7 +673,7 @@ void *vdo_int_map_remove(struct int_map *map, u64 key) /* Select the bucket to search and search it for an existing entry. */ struct bucket *bucket = select_bucket(map, key); struct bucket *previous; - struct bucket *victim = search_hop_list(map, bucket, key, &previous); + struct bucket *victim = search_hop_list(bucket, key, &previous); if (victim == NULL) { /* There is no matching entry to remove. */ diff --git a/drivers/md/dm-vdo/io-submitter.c b/drivers/md/dm-vdo/io-submitter.c index ab62abe18827bb..421e5436c32c94 100644 --- a/drivers/md/dm-vdo/io-submitter.c +++ b/drivers/md/dm-vdo/io-submitter.c @@ -367,7 +367,7 @@ void __submit_metadata_vio(struct vio *vio, physical_block_number_t physical, * completions. * @max_requests_active: Number of bios for merge tracking. * @vdo: The vdo which will use this submitter. - * @io_submitter: pointer to the new data structure. + * @io_submitter_ptr: pointer to the new data structure. * * Return: VDO_SUCCESS or an error. */ diff --git a/drivers/md/dm-vdo/murmurhash3.c b/drivers/md/dm-vdo/murmurhash3.c index 13008b0892062e..b0b0587d85f37d 100644 --- a/drivers/md/dm-vdo/murmurhash3.c +++ b/drivers/md/dm-vdo/murmurhash3.c @@ -44,14 +44,11 @@ void murmurhash3_128(const void *key, const int len, const u32 seed, void *out) u64 *hash_out = out; /* body */ - - const u64 *blocks = (const u64 *)(data); - int i; for (i = 0; i < nblocks; i++) { - u64 k1 = get_unaligned_le64(&blocks[i * 2]); - u64 k2 = get_unaligned_le64(&blocks[i * 2 + 1]); + u64 k1 = get_unaligned_le64(&data[i * 16]); + u64 k2 = get_unaligned_le64(&data[i * 16 + 8]); k1 *= c1; k1 = ROTL64(k1, 31); diff --git a/drivers/md/dm-vdo/packer.c b/drivers/md/dm-vdo/packer.c index 16cf29b4c90a54..f70f5edabc1000 100644 --- a/drivers/md/dm-vdo/packer.c +++ b/drivers/md/dm-vdo/packer.c @@ -250,7 +250,6 @@ static void abort_packing(struct data_vio *data_vio) /** * release_compressed_write_waiter() - Update a data_vio for which a successful compressed write * has completed and send it on its way. - * @data_vio: The data_vio to release. * @allocation: The allocation to which the compressed block was written. */ @@ -383,7 +382,7 @@ static void initialize_compressed_block(struct compressed_block *block, u16 size * @compression: The agent's compression_state to pack in to. * @data_vio: The data_vio to pack. * @offset: The offset into the compressed block at which to pack the fragment. - * @compressed_block: The compressed block which will be written out when batch is fully packed. + * @block: The compressed block which will be written out when batch is fully packed. * * Return: The new amount of space used. */ diff --git a/drivers/md/dm-vdo/physical-zone.c b/drivers/md/dm-vdo/physical-zone.c index 2fee3a7c1191b1..a43b5c45fab7c5 100644 --- a/drivers/md/dm-vdo/physical-zone.c +++ b/drivers/md/dm-vdo/physical-zone.c @@ -517,7 +517,7 @@ static int allocate_and_lock_block(struct allocation *allocation) * @waiter: The allocating_vio that was waiting to allocate. * @context: The context (unused). */ -static void retry_allocation(struct vdo_waiter *waiter, void *context __always_unused) +static void retry_allocation(struct vdo_waiter *waiter, void __always_unused *context) { struct data_vio *data_vio = vdo_waiter_as_data_vio(waiter); diff --git a/drivers/md/dm-vdo/recovery-journal.c b/drivers/md/dm-vdo/recovery-journal.c index ee6321a3e5238d..de58184f538f50 100644 --- a/drivers/md/dm-vdo/recovery-journal.c +++ b/drivers/md/dm-vdo/recovery-journal.c @@ -1365,7 +1365,7 @@ static void add_queued_recovery_entries(struct recovery_journal_block *block) * * Implements waiter_callback_fn. */ -static void write_block(struct vdo_waiter *waiter, void *context __always_unused) +static void write_block(struct vdo_waiter *waiter, void __always_unused *context) { struct recovery_journal_block *block = container_of(waiter, struct recovery_journal_block, write_waiter); diff --git a/drivers/md/dm-vdo/repair.c b/drivers/md/dm-vdo/repair.c index ffff2c999518eb..8c006fb3afcf0c 100644 --- a/drivers/md/dm-vdo/repair.c +++ b/drivers/md/dm-vdo/repair.c @@ -166,7 +166,7 @@ static void swap_mappings(void *item1, void *item2, void __always_unused *args) static const struct min_heap_callbacks repair_min_heap = { .less = mapping_is_less_than, - .swp = swap_mappings, + .swp = NULL, }; static struct numbered_block_mapping *sort_next_heap_element(struct repair_completion *repair) diff --git a/drivers/md/dm-vdo/slab-depot.c b/drivers/md/dm-vdo/slab-depot.c index 274f9ccd072f05..8f0a35c63af686 100644 --- a/drivers/md/dm-vdo/slab-depot.c +++ b/drivers/md/dm-vdo/slab-depot.c @@ -1287,7 +1287,7 @@ static struct reference_block * __must_check get_reference_block(struct vdo_slab * slab_block_number_from_pbn() - Determine the index within the slab of a particular physical * block number. * @slab: The slab. - * @physical_block_number: The physical block number. + * @pbn: The physical block number. * @slab_block_number_ptr: A pointer to the slab block number. * * Return: VDO_SUCCESS or an error code. @@ -1459,7 +1459,6 @@ static int increment_for_data(struct vdo_slab *slab, struct reference_block *blo * @block_number: The block to update. * @old_status: The reference status of the data block before this decrement. * @updater: The reference updater doing this operation in case we need to look up the pbn lock. - * @lock: The pbn_lock associated with the block being decremented (may be NULL). * @counter_ptr: A pointer to the count for the data block (in, out). * @adjust_block_count: Whether to update the allocator's free block count. * @@ -3232,8 +3231,7 @@ int vdo_enqueue_clean_slab_waiter(struct block_allocator *allocator, /** * vdo_modify_reference_count() - Modify the reference count of a block by first making a slab * journal entry and then updating the reference counter. - * - * @data_vio: The data_vio for which to add the entry. + * @completion: The data_vio completion for which to add the entry. * @updater: Which of the data_vio's reference updaters is being submitted. */ void vdo_modify_reference_count(struct vdo_completion *completion, @@ -3301,17 +3299,9 @@ static bool slab_status_is_less_than(const void *item1, const void *item2, return info1->slab_number < info2->slab_number; } -static void swap_slab_statuses(void *item1, void *item2, void __always_unused *args) -{ - struct slab_status *info1 = item1; - struct slab_status *info2 = item2; - - swap(*info1, *info2); -} - static const struct min_heap_callbacks slab_status_min_heap = { .less = slab_status_is_less_than, - .swp = swap_slab_statuses, + .swp = NULL, }; /* Inform the slab actor that a action has finished on some slab; used by apply_to_slabs(). */ @@ -4750,8 +4740,7 @@ void vdo_use_new_slabs(struct slab_depot *depot, struct vdo_completion *parent) /** * stop_scrubbing() - Tell the scrubber to stop scrubbing after it finishes the slab it is * currently working on. - * @scrubber: The scrubber to stop. - * @parent: The completion to notify when scrubbing has stopped. + * @allocator: The block allocator owning the scrubber to stop. */ static void stop_scrubbing(struct block_allocator *allocator) { diff --git a/drivers/md/dm-vdo/vdo.c b/drivers/md/dm-vdo/vdo.c index fff847767755a3..a7e32baab4afd3 100644 --- a/drivers/md/dm-vdo/vdo.c +++ b/drivers/md/dm-vdo/vdo.c @@ -643,7 +643,7 @@ static void finish_vdo(struct vdo *vdo) /** * free_listeners() - Free the list of read-only listeners associated with a thread. - * @thread_data: The thread holding the list to free. + * @thread: The thread holding the list to free. */ static void free_listeners(struct vdo_thread *thread) { @@ -852,7 +852,7 @@ int vdo_synchronous_flush(struct vdo *vdo) /** * vdo_get_state() - Get the current state of the vdo. * @vdo: The vdo. - + * * Context: This method may be called from any thread. * * Return: The current state of the vdo. diff --git a/drivers/md/dm-vdo/vio.c b/drivers/md/dm-vdo/vio.c index b291578f726f50..e710f3c5a972dd 100644 --- a/drivers/md/dm-vdo/vio.c +++ b/drivers/md/dm-vdo/vio.c @@ -202,6 +202,7 @@ int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback, if (data == NULL) return VDO_SUCCESS; + bio->bi_ioprio = 0; bio->bi_io_vec = bio->bi_inline_vecs; bio->bi_max_vecs = vio->block_count + 1; len = VDO_BLOCK_SIZE * vio->block_count; diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index c142ec5458b70f..47d595f6a76e57 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -93,7 +93,7 @@ static void dm_bufio_alloc_callback(struct dm_buffer *buf) */ static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector) { - return v->data_start + dm_target_offset(v->ti, bi_sector); + return dm_target_offset(v->ti, bi_sector); } /* @@ -952,7 +952,7 @@ static int verity_prepare_ioctl(struct dm_target *ti, struct block_device **bdev *bdev = v->data_dev->bdev; - if (v->data_start || ti->len != bdev_nr_sectors(v->data_dev->bdev)) + if (ti->len != bdev_nr_sectors(v->data_dev->bdev)) return 1; return 0; } @@ -962,7 +962,7 @@ static int verity_iterate_devices(struct dm_target *ti, { struct dm_verity *v = ti->private; - return fn(ti, v->data_dev, v->data_start, ti->len, data); + return fn(ti, v->data_dev, 0, ti->len, data); } static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits) diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h index c996140bda94db..8cbb57862ae19a 100644 --- a/drivers/md/dm-verity.h +++ b/drivers/md/dm-verity.h @@ -50,7 +50,6 @@ struct dm_verity { unsigned int sig_size; /* root digest signature size */ #endif /* CONFIG_SECURITY */ unsigned int salt_size; - sector_t data_start; /* data offset in 512-byte sectors */ sector_t hash_start; /* hash start in blocks */ sector_t data_blocks; /* the number of data blocks */ sector_t hash_blocks; /* the number of hash blocks */ diff --git a/drivers/md/dm-zone.c b/drivers/md/dm-zone.c index c0d41c36e06ebf..20edd3fabbabfe 100644 --- a/drivers/md/dm-zone.c +++ b/drivers/md/dm-zone.c @@ -344,7 +344,7 @@ int dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q, clear_bit(DMF_EMULATE_ZONE_APPEND, &md->flags); } else { set_bit(DMF_EMULATE_ZONE_APPEND, &md->flags); - lim->max_zone_append_sectors = 0; + lim->max_hw_zone_append_sectors = 0; } /* @@ -379,7 +379,7 @@ int dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q, if (!zlim.mapped_nr_seq_zones) { lim->max_open_zones = 0; lim->max_active_zones = 0; - lim->max_zone_append_sectors = 0; + lim->max_hw_zone_append_sectors = 0; lim->zone_write_granularity = 0; lim->chunk_sectors = 0; lim->features &= ~BLK_FEAT_ZONED; diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c index 8156881a31de93..deff22ecccbb83 100644 --- a/drivers/md/dm-zoned-metadata.c +++ b/drivers/md/dm-zoned-metadata.c @@ -245,11 +245,6 @@ unsigned int dmz_zone_nr_blocks(struct dmz_metadata *zmd) return zmd->zone_nr_blocks; } -unsigned int dmz_zone_nr_blocks_shift(struct dmz_metadata *zmd) -{ - return zmd->zone_nr_blocks_shift; -} - unsigned int dmz_zone_nr_sectors(struct dmz_metadata *zmd) { return zmd->zone_nr_sectors; @@ -3005,48 +3000,3 @@ void dmz_dtr_metadata(struct dmz_metadata *zmd) dmz_cleanup_metadata(zmd); kfree(zmd); } - -/* - * Check zone information on resume. - */ -int dmz_resume_metadata(struct dmz_metadata *zmd) -{ - struct dm_zone *zone; - sector_t wp_block; - unsigned int i; - int ret; - - /* Check zones */ - for (i = 0; i < zmd->nr_zones; i++) { - zone = dmz_get(zmd, i); - if (!zone) { - dmz_zmd_err(zmd, "Unable to get zone %u", i); - return -EIO; - } - wp_block = zone->wp_block; - - ret = dmz_update_zone(zmd, zone); - if (ret) { - dmz_zmd_err(zmd, "Broken zone %u", i); - return ret; - } - - if (dmz_is_offline(zone)) { - dmz_zmd_warn(zmd, "Zone %u is offline", i); - continue; - } - - /* Check write pointer */ - if (!dmz_is_seq(zone)) - zone->wp_block = 0; - else if (zone->wp_block != wp_block) { - dmz_zmd_err(zmd, "Zone %u: Invalid wp (%llu / %llu)", - i, (u64)zone->wp_block, (u64)wp_block); - zone->wp_block = wp_block; - dmz_invalidate_blocks(zmd, zone, zone->wp_block, - zmd->zone_nr_blocks - zone->wp_block); - } - } - - return 0; -} diff --git a/drivers/md/dm-zoned-reclaim.c b/drivers/md/dm-zoned-reclaim.c index d58db9a27e6cfd..76e2c686854871 100644 --- a/drivers/md/dm-zoned-reclaim.c +++ b/drivers/md/dm-zoned-reclaim.c @@ -76,9 +76,9 @@ static int dmz_reclaim_align_wp(struct dmz_reclaim *zrc, struct dm_zone *zone, * pointer and the requested position. */ nr_blocks = block - wp_block; - ret = blkdev_issue_zeroout(dev->bdev, - dmz_start_sect(zmd, zone) + dmz_blk2sect(wp_block), - dmz_blk2sect(nr_blocks), GFP_NOIO, 0); + ret = blk_zone_issue_zeroout(dev->bdev, + dmz_start_sect(zmd, zone) + dmz_blk2sect(wp_block), + dmz_blk2sect(nr_blocks), GFP_NOIO); if (ret) { dmz_dev_err(dev, "Align zone %u wp %llu to %llu (wp+%u) blocks failed %d", diff --git a/drivers/md/dm-zoned.h b/drivers/md/dm-zoned.h index 265494d3f7114b..59ba0aaa953130 100644 --- a/drivers/md/dm-zoned.h +++ b/drivers/md/dm-zoned.h @@ -192,7 +192,6 @@ enum { int dmz_ctr_metadata(struct dmz_dev *dev, int num_dev, struct dmz_metadata **zmd, const char *devname); void dmz_dtr_metadata(struct dmz_metadata *zmd); -int dmz_resume_metadata(struct dmz_metadata *zmd); void dmz_lock_map(struct dmz_metadata *zmd); void dmz_unlock_map(struct dmz_metadata *zmd); @@ -230,7 +229,6 @@ unsigned int dmz_nr_unmap_rnd_zones(struct dmz_metadata *zmd, int idx); unsigned int dmz_nr_seq_zones(struct dmz_metadata *zmd, int idx); unsigned int dmz_nr_unmap_seq_zones(struct dmz_metadata *zmd, int idx); unsigned int dmz_zone_nr_blocks(struct dmz_metadata *zmd); -unsigned int dmz_zone_nr_blocks_shift(struct dmz_metadata *zmd); unsigned int dmz_zone_nr_sectors(struct dmz_metadata *zmd); unsigned int dmz_zone_nr_sectors_shift(struct dmz_metadata *zmd); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 19230404d8c2bd..12ecf07a38410a 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2517,12 +2517,6 @@ void dm_unlock_md_type(struct mapped_device *md) mutex_unlock(&md->type_lock); } -void dm_set_md_type(struct mapped_device *md, enum dm_queue_mode type) -{ - BUG_ON(!mutex_is_locked(&md->type_lock)); - md->type = type; -} - enum dm_queue_mode dm_get_md_type(struct mapped_device *md) { return md->type; @@ -3349,6 +3343,59 @@ void dm_free_md_mempools(struct dm_md_mempools *pools) kfree(pools); } +struct dm_blkdev_id { + u8 *id; + enum blk_unique_id type; +}; + +static int __dm_get_unique_id(struct dm_target *ti, struct dm_dev *dev, + sector_t start, sector_t len, void *data) +{ + struct dm_blkdev_id *dm_id = data; + const struct block_device_operations *fops = dev->bdev->bd_disk->fops; + + if (!fops->get_unique_id) + return 0; + + return fops->get_unique_id(dev->bdev->bd_disk, dm_id->id, dm_id->type); +} + +/* + * Allow access to get_unique_id() for the first device returning a + * non-zero result. Reasonable use expects all devices to have the + * same unique id. + */ +static int dm_blk_get_unique_id(struct gendisk *disk, u8 *id, + enum blk_unique_id type) +{ + struct mapped_device *md = disk->private_data; + struct dm_table *table; + struct dm_target *ti; + int ret = 0, srcu_idx; + + struct dm_blkdev_id dm_id = { + .id = id, + .type = type, + }; + + table = dm_get_live_table(md, &srcu_idx); + if (!table || !dm_table_get_size(table)) + goto out; + + /* We only support devices that have a single target */ + if (table->num_targets != 1) + goto out; + ti = dm_table_get_target(table, 0); + + if (!ti->type->iterate_devices) + goto out; + + ret = ti->type->iterate_devices(ti, __dm_get_unique_id, &dm_id); +out: + dm_put_live_table(md, srcu_idx); + return ret; +} + struct dm_pr { u64 old_key; u64 new_key; @@ -3674,6 +3721,7 @@ static const struct block_device_operations dm_blk_dops = { .ioctl = dm_blk_ioctl, .getgeo = dm_blk_getgeo, .report_zones = dm_blk_report_zones, + .get_unique_id = dm_blk_get_unique_id, .pr_ops = &dm_pr_ops, .owner = THIS_MODULE }; @@ -3683,6 +3731,7 @@ static const struct block_device_operations dm_rq_blk_dops = { .release = dm_blk_close, .ioctl = dm_blk_ioctl, .getgeo = dm_blk_getgeo, + .get_unique_id = dm_blk_get_unique_id, .pr_ops = &dm_pr_ops, .owner = THIS_MODULE }; diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 8ad782249af888..a0a8ff11981580 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -71,12 +71,10 @@ enum dm_queue_mode dm_table_get_type(struct dm_table *t); struct target_type *dm_table_get_immutable_target_type(struct dm_table *t); struct dm_target *dm_table_get_immutable_target(struct dm_table *t); struct dm_target *dm_table_get_wildcard_target(struct dm_table *t); -bool dm_table_bio_based(struct dm_table *t); bool dm_table_request_based(struct dm_table *t); void dm_lock_md_type(struct mapped_device *md); void dm_unlock_md_type(struct mapped_device *md); -void dm_set_md_type(struct mapped_device *md, enum dm_queue_mode type); enum dm_queue_mode dm_get_md_type(struct mapped_device *md); struct target_type *dm_get_immutable_target_type(struct mapped_device *md); diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 29da10e6f703e2..c3a42dd66ce551 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -1285,6 +1285,7 @@ static void bitmap_unplug_async(struct bitmap *bitmap) queue_work(md_bitmap_wq, &unplug_work.work); wait_for_completion(&done); + destroy_work_on_stack(&unplug_work.work); } static void bitmap_unplug(struct mddev *mddev, bool sync) diff --git a/drivers/md/md.c b/drivers/md/md.c index 67108c397c5a86..aebe12b0ee279f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -9784,9 +9784,7 @@ EXPORT_SYMBOL(md_reap_sync_thread); void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev) { sysfs_notify_dirent_safe(rdev->sysfs_state); - wait_event_timeout(rdev->blocked_wait, - !test_bit(Blocked, &rdev->flags) && - !test_bit(BlockedBadBlocks, &rdev->flags), + wait_event_timeout(rdev->blocked_wait, !rdev_blocked(rdev), msecs_to_jiffies(5000)); rdev_dec_pending(rdev, mddev); } @@ -9815,6 +9813,17 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors, { struct mddev *mddev = rdev->mddev; int rv; + + /* + * Recording new badblocks for faulty rdev will force unnecessary + * super block updating. This is fragile for external management because + * userspace daemon may trying to remove this device and deadlock may + * occur. This will be probably solved in the mdadm, but it is safer to + * avoid it. + */ + if (test_bit(Faulty, &rdev->flags)) + return 1; + if (is_new) s += rdev->new_data_offset; else diff --git a/drivers/md/md.h b/drivers/md/md.h index 5d2e6bd58e4da2..4ba93af36126dd 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -1002,6 +1002,30 @@ static inline void mddev_trace_remap(struct mddev *mddev, struct bio *bio, trace_block_bio_remap(bio, disk_devt(mddev->gendisk), sector); } +static inline bool rdev_blocked(struct md_rdev *rdev) +{ + /* + * Blocked will be set by error handler and cleared by daemon after + * updating superblock, meanwhile write IO should be blocked to prevent + * reading old data after power failure. + */ + if (test_bit(Blocked, &rdev->flags)) + return true; + + /* + * Faulty device should not be accessed anymore, there is no need to + * wait for bad block to be acknowledged. + */ + if (test_bit(Faulty, &rdev->flags)) + return false; + + /* rdev is blocked by badblocks. */ + if (test_bit(BlockedBadBlocks, &rdev->flags)) + return true; + + return false; +} + #define mddev_add_trace_msg(mddev, fmt, args...) \ do { \ if (!mddev_is_dm(mddev)) \ diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c index 3a19124ee27932..22a551c407da49 100644 --- a/drivers/md/persistent-data/dm-space-map-common.c +++ b/drivers/md/persistent-data/dm-space-map-common.c @@ -51,7 +51,7 @@ static int index_check(const struct dm_block_validator *v, block_size - sizeof(__le32), INDEX_CSUM_XOR)); if (csum_disk != mi_le->csum) { - DMERR_LIMIT("i%s failed: csum %u != wanted %u", __func__, + DMERR_LIMIT("%s failed: csum %u != wanted %u", __func__, le32_to_cpu(csum_disk), le32_to_cpu(mi_le->csum)); return -EILSEQ; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 32d58752477847..7049ec7fb8eb44 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -384,6 +384,7 @@ static int raid0_set_limits(struct mddev *mddev) lim.max_write_zeroes_sectors = mddev->chunk_sectors; lim.io_min = mddev->chunk_sectors << 9; lim.io_opt = lim.io_min * mddev->raid_disks; + lim.features |= BLK_FEAT_ATOMIC_WRITES_STACKED; err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY); if (err) { queue_limits_cancel_update(mddev->gendisk->queue); @@ -466,6 +467,12 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) struct bio *split = bio_split(bio, zone->zone_end - bio->bi_iter.bi_sector, GFP_NOIO, &mddev->bio_set); + + if (IS_ERR(split)) { + bio->bi_status = errno_to_blk_status(PTR_ERR(split)); + bio_endio(bio); + return; + } bio_chain(split, bio); submit_bio_noacct(bio); bio = split; @@ -608,6 +615,12 @@ static bool raid0_make_request(struct mddev *mddev, struct bio *bio) if (sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, sectors, GFP_NOIO, &mddev->bio_set); + + if (IS_ERR(split)) { + bio->bi_status = errno_to_blk_status(PTR_ERR(split)); + bio_endio(bio); + return true; + } bio_chain(split, bio); raid0_map_submit_bio(mddev, bio); bio = split; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 6c9d24203f39f0..519c56f0ee3d40 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1322,7 +1322,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, const enum req_op op = bio_op(bio); const blk_opf_t do_sync = bio->bi_opf & REQ_SYNC; int max_sectors; - int rdisk; + int rdisk, error; bool r1bio_existed = !!r1_bio; /* @@ -1383,6 +1383,11 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, if (max_sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, max_sectors, gfp, &conf->bio_split); + + if (IS_ERR(split)) { + error = PTR_ERR(split); + goto err_handle; + } bio_chain(split, bio); submit_bio_noacct(bio); bio = split; @@ -1410,6 +1415,47 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio, read_bio->bi_private = r1_bio; mddev_trace_remap(mddev, read_bio, r1_bio->sector); submit_bio_noacct(read_bio); + return; + +err_handle: + atomic_dec(&mirror->rdev->nr_pending); + bio->bi_status = errno_to_blk_status(error); + set_bit(R1BIO_Uptodate, &r1_bio->state); + raid_end_bio_io(r1_bio); +} + +static bool wait_blocked_rdev(struct mddev *mddev, struct bio *bio) +{ + struct r1conf *conf = mddev->private; + int disks = conf->raid_disks * 2; + int i; + +retry: + for (i = 0; i < disks; i++) { + struct md_rdev *rdev = conf->mirrors[i].rdev; + + if (!rdev) + continue; + + /* don't write here until the bad block is acknowledged */ + if (test_bit(WriteErrorSeen, &rdev->flags) && + rdev_has_badblock(rdev, bio->bi_iter.bi_sector, + bio_sectors(bio)) < 0) + set_bit(BlockedBadBlocks, &rdev->flags); + + if (rdev_blocked(rdev)) { + if (bio->bi_opf & REQ_NOWAIT) + return false; + + mddev_add_trace_msg(rdev->mddev, "raid1 wait rdev %d blocked", + rdev->raid_disk); + atomic_inc(&rdev->nr_pending); + md_wait_for_blocked_rdev(rdev, rdev->mddev); + goto retry; + } + } + + return true; } static void raid1_write_request(struct mddev *mddev, struct bio *bio, @@ -1417,9 +1463,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, { struct r1conf *conf = mddev->private; struct r1bio *r1_bio; - int i, disks; + int i, disks, k, error; unsigned long flags; - struct md_rdev *blocked_rdev; int first_clone; int max_sectors; bool write_behind = false; @@ -1457,7 +1502,11 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, return; } - retry_write: + if (!wait_blocked_rdev(mddev, bio)) { + bio_wouldblock_error(bio); + return; + } + r1_bio = alloc_r1bio(mddev, bio); r1_bio->sectors = max_write_sectors; @@ -1473,7 +1522,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, */ disks = conf->raid_disks * 2; - blocked_rdev = NULL; max_sectors = r1_bio->sectors; for (i = 0; i < disks; i++) { struct md_rdev *rdev = conf->mirrors[i].rdev; @@ -1486,11 +1534,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, if (!is_discard && rdev && test_bit(WriteMostly, &rdev->flags)) write_behind = true; - if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { - atomic_inc(&rdev->nr_pending); - blocked_rdev = rdev; - break; - } r1_bio->bios[i] = NULL; if (!rdev || test_bit(Faulty, &rdev->flags)) { if (i < conf->raid_disks) @@ -1506,13 +1549,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, is_bad = is_badblock(rdev, r1_bio->sector, max_sectors, &first_bad, &bad_sectors); - if (is_bad < 0) { - /* mustn't write here until the bad block is - * acknowledged*/ - set_bit(BlockedBadBlocks, &rdev->flags); - blocked_rdev = rdev; - break; - } if (is_bad && first_bad <= r1_bio->sector) { /* Cannot write here at all */ bad_sectors -= (r1_bio->sector - first_bad); @@ -1535,7 +1571,21 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, continue; } if (is_bad) { - int good_sectors = first_bad - r1_bio->sector; + int good_sectors; + + /* + * We cannot atomically write this, so just + * error in that case. It could be possible to + * atomically write other mirrors, but the + * complexity of supporting that is not worth + * the benefit. + */ + if (bio->bi_opf & REQ_ATOMIC) { + error = -EIO; + goto err_handle; + } + + good_sectors = first_bad - r1_bio->sector; if (good_sectors < max_sectors) max_sectors = good_sectors; } @@ -1543,27 +1593,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, r1_bio->bios[i] = bio; } - if (unlikely(blocked_rdev)) { - /* Wait for this device to become unblocked */ - int j; - - for (j = 0; j < i; j++) - if (r1_bio->bios[j]) - rdev_dec_pending(conf->mirrors[j].rdev, mddev); - mempool_free(r1_bio, &conf->r1bio_pool); - allow_barrier(conf, bio->bi_iter.bi_sector); - - if (bio->bi_opf & REQ_NOWAIT) { - bio_wouldblock_error(bio); - return; - } - mddev_add_trace_msg(mddev, "raid1 wait rdev %d blocked", - blocked_rdev->raid_disk); - md_wait_for_blocked_rdev(blocked_rdev, mddev); - wait_barrier(conf, bio->bi_iter.bi_sector, false); - goto retry_write; - } - /* * When using a bitmap, we may call alloc_behind_master_bio below. * alloc_behind_master_bio allocates a copy of the data payload a page @@ -1576,6 +1605,11 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, if (max_sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, max_sectors, GFP_NOIO, &conf->bio_split); + + if (IS_ERR(split)) { + error = PTR_ERR(split); + goto err_handle; + } bio_chain(split, bio); submit_bio_noacct(bio); bio = split; @@ -1637,7 +1671,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, mbio->bi_iter.bi_sector = (r1_bio->sector + rdev->data_offset); mbio->bi_end_io = raid1_end_write_request; - mbio->bi_opf = bio_op(bio) | (bio->bi_opf & (REQ_SYNC | REQ_FUA)); + mbio->bi_opf = bio_op(bio) | + (bio->bi_opf & (REQ_SYNC | REQ_FUA | REQ_ATOMIC)); if (test_bit(FailFast, &rdev->flags) && !test_bit(WriteMostly, &rdev->flags) && conf->raid_disks - mddev->degraded > 1) @@ -1660,6 +1695,18 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio, /* In case raid1d snuck in to freeze_array */ wake_up_barrier(conf); + return; +err_handle: + for (k = 0; k < i; k++) { + if (r1_bio->bios[k]) { + rdev_dec_pending(conf->mirrors[k].rdev, mddev); + r1_bio->bios[k] = NULL; + } + } + + bio->bi_status = errno_to_blk_status(error); + set_bit(R1BIO_Uptodate, &r1_bio->state); + raid_end_bio_io(r1_bio); } static bool raid1_make_request(struct mddev *mddev, struct bio *bio) @@ -3192,6 +3239,7 @@ static int raid1_set_limits(struct mddev *mddev) md_init_stacking_limits(&lim); lim.max_write_zeroes_sectors = 0; + lim.features |= BLK_FEAT_ATOMIC_WRITES_STACKED; err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY); if (err) { queue_limits_cancel_update(mddev->gendisk->queue); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 862b1fb71d864b..7d7a8a2524dcab 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1159,6 +1159,7 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, int slot = r10_bio->read_slot; struct md_rdev *err_rdev = NULL; gfp_t gfp = GFP_NOIO; + int error; if (slot >= 0 && r10_bio->devs[slot].rdev) { /* @@ -1206,6 +1207,10 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, if (max_sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, max_sectors, gfp, &conf->bio_split); + if (IS_ERR(split)) { + error = PTR_ERR(split); + goto err_handle; + } bio_chain(split, bio); allow_barrier(conf); submit_bio_noacct(bio); @@ -1236,6 +1241,11 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, mddev_trace_remap(mddev, read_bio, r10_bio->sector); submit_bio_noacct(read_bio); return; +err_handle: + atomic_dec(&rdev->nr_pending); + bio->bi_status = errno_to_blk_status(error); + set_bit(R10BIO_Uptodate, &r10_bio->state); + raid_end_bio_io(r10_bio); } static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, @@ -1245,6 +1255,7 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, const enum req_op op = bio_op(bio); const blk_opf_t do_sync = bio->bi_opf & REQ_SYNC; const blk_opf_t do_fua = bio->bi_opf & REQ_FUA; + const blk_opf_t do_atomic = bio->bi_opf & REQ_ATOMIC; unsigned long flags; struct r10conf *conf = mddev->private; struct md_rdev *rdev; @@ -1263,7 +1274,7 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, mbio->bi_iter.bi_sector = (r10_bio->devs[n_copy].addr + choose_data_offset(r10_bio, rdev)); mbio->bi_end_io = raid10_end_write_request; - mbio->bi_opf = op | do_sync | do_fua; + mbio->bi_opf = op | do_sync | do_fua | do_atomic; if (!replacement && test_bit(FailFast, &conf->mirrors[devnum].rdev->flags) && enough(conf, devnum)) @@ -1285,9 +1296,9 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio, static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio) { - int i; struct r10conf *conf = mddev->private; struct md_rdev *blocked_rdev; + int i; retry_wait: blocked_rdev = NULL; @@ -1295,40 +1306,36 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio) struct md_rdev *rdev, *rrdev; rdev = conf->mirrors[i].rdev; - rrdev = conf->mirrors[i].replacement; - if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { - atomic_inc(&rdev->nr_pending); - blocked_rdev = rdev; - break; - } - if (rrdev && unlikely(test_bit(Blocked, &rrdev->flags))) { - atomic_inc(&rrdev->nr_pending); - blocked_rdev = rrdev; - break; - } - - if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) { + if (rdev) { sector_t dev_sector = r10_bio->devs[i].addr; /* * Discard request doesn't care the write result * so it doesn't need to wait blocked disk here. */ - if (!r10_bio->sectors) - continue; - - if (rdev_has_badblock(rdev, dev_sector, - r10_bio->sectors) < 0) { + if (test_bit(WriteErrorSeen, &rdev->flags) && + r10_bio->sectors && + rdev_has_badblock(rdev, dev_sector, + r10_bio->sectors) < 0) /* - * Mustn't write here until the bad block - * is acknowledged + * Mustn't write here until the bad + * block is acknowledged */ - atomic_inc(&rdev->nr_pending); set_bit(BlockedBadBlocks, &rdev->flags); + + if (rdev_blocked(rdev)) { blocked_rdev = rdev; + atomic_inc(&rdev->nr_pending); break; } } + + rrdev = conf->mirrors[i].replacement; + if (rrdev && rdev_blocked(rrdev)) { + atomic_inc(&rrdev->nr_pending); + blocked_rdev = rrdev; + break; + } } if (unlikely(blocked_rdev)) { @@ -1347,9 +1354,10 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, struct r10bio *r10_bio) { struct r10conf *conf = mddev->private; - int i; + int i, k; sector_t sectors; int max_sectors; + int error; if ((mddev_is_clustered(mddev) && md_cluster_ops->area_resyncing(mddev, WRITE, @@ -1461,7 +1469,21 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, continue; } if (is_bad) { - int good_sectors = first_bad - dev_sector; + int good_sectors; + + /* + * We cannot atomically write this, so just + * error in that case. It could be possible to + * atomically write other mirrors, but the + * complexity of supporting that is not worth + * the benefit. + */ + if (bio->bi_opf & REQ_ATOMIC) { + error = -EIO; + goto err_handle; + } + + good_sectors = first_bad - dev_sector; if (good_sectors < max_sectors) max_sectors = good_sectors; } @@ -1482,6 +1504,10 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, if (r10_bio->sectors < bio_sectors(bio)) { struct bio *split = bio_split(bio, r10_bio->sectors, GFP_NOIO, &conf->bio_split); + if (IS_ERR(split)) { + error = PTR_ERR(split); + goto err_handle; + } bio_chain(split, bio); allow_barrier(conf); submit_bio_noacct(bio); @@ -1503,6 +1529,26 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio, raid10_write_one_disk(mddev, r10_bio, bio, true, i); } one_write_done(r10_bio); + return; +err_handle: + for (k = 0; k < i; k++) { + int d = r10_bio->devs[k].devnum; + struct md_rdev *rdev = conf->mirrors[d].rdev; + struct md_rdev *rrdev = conf->mirrors[d].replacement; + + if (r10_bio->devs[k].bio) { + rdev_dec_pending(rdev, mddev); + r10_bio->devs[k].bio = NULL; + } + if (r10_bio->devs[k].repl_bio) { + rdev_dec_pending(rrdev, mddev); + r10_bio->devs[k].repl_bio = NULL; + } + } + + bio->bi_status = errno_to_blk_status(error); + set_bit(R10BIO_Uptodate, &r10_bio->state); + raid_end_bio_io(r10_bio); } static void __make_request(struct mddev *mddev, struct bio *bio, int sectors) @@ -1644,6 +1690,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) if (remainder) { split_size = stripe_size - remainder; split = bio_split(bio, split_size, GFP_NOIO, &conf->bio_split); + if (IS_ERR(split)) { + bio->bi_status = errno_to_blk_status(PTR_ERR(split)); + bio_endio(bio); + return 0; + } bio_chain(split, bio); allow_barrier(conf); /* Resend the fist split part */ @@ -1654,6 +1705,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) if (remainder) { split_size = bio_sectors(bio) - remainder; split = bio_split(bio, split_size, GFP_NOIO, &conf->bio_split); + if (IS_ERR(split)) { + bio->bi_status = errno_to_blk_status(PTR_ERR(split)); + bio_endio(bio); + return 0; + } bio_chain(split, bio); allow_barrier(conf); /* Resend the second split part */ @@ -3984,6 +4040,7 @@ static int raid10_set_queue_limits(struct mddev *mddev) lim.max_write_zeroes_sectors = 0; lim.io_min = mddev->chunk_sectors << 9; lim.io_opt = lim.io_min * raid10_nr_stripes(conf); + lim.features |= BLK_FEAT_ATOMIC_WRITES_STACKED; err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY); if (err) { queue_limits_cancel_update(mddev->gendisk->queue); diff --git a/drivers/md/raid5-ppl.c b/drivers/md/raid5-ppl.c index a70cbec12ed017..37c4da5311ca71 100644 --- a/drivers/md/raid5-ppl.c +++ b/drivers/md/raid5-ppl.c @@ -258,7 +258,7 @@ static struct ppl_io_unit *ppl_new_iounit(struct ppl_log *log, memset(pplhdr->reserved, 0xff, PPL_HDR_RESERVED); pplhdr->signature = cpu_to_le32(ppl_conf->signature); - io->seq = atomic64_add_return(1, &ppl_conf->seq); + io->seq = atomic64_inc_return(&ppl_conf->seq); pplhdr->generation = cpu_to_le64(io->seq); return io; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index dc2ea636d17342..f09e7677ee9f1b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4724,14 +4724,13 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) if (rdev) { is_bad = rdev_has_badblock(rdev, sh->sector, RAID5_STRIPE_SECTORS(conf)); - if (s->blocked_rdev == NULL - && (test_bit(Blocked, &rdev->flags) - || is_bad < 0)) { + if (s->blocked_rdev == NULL) { if (is_bad < 0) - set_bit(BlockedBadBlocks, - &rdev->flags); - s->blocked_rdev = rdev; - atomic_inc(&rdev->nr_pending); + set_bit(BlockedBadBlocks, &rdev->flags); + if (rdev_blocked(rdev)) { + s->blocked_rdev = rdev; + atomic_inc(&rdev->nr_pending); + } } } clear_bit(R5_Insync, &dev->flags); @@ -7177,6 +7176,8 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) err = mddev_suspend_and_lock(mddev); if (err) return err; + raid5_quiesce(mddev, true); + conf = mddev->private; if (!conf) err = -ENODEV; @@ -7198,6 +7199,8 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) kfree(old_groups); } } + + raid5_quiesce(mddev, false); mddev_unlock_and_resume(mddev); return err ?: len; diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 896ecfc4afa6fa..d174e586698f04 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -633,7 +633,7 @@ struct r5conf { * two caches. */ int active_name; - char cache_name[2][32]; + char cache_name[2][48]; struct kmem_cache *slab_cache; /* for allocating stripes */ struct mutex cache_size_mutex; /* Protect changes to cache size */ diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index 48282d272fe649..ca0db8d457b48a 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -438,6 +438,6 @@ static void __exit cec_devnode_exit(void) subsys_initcall(cec_devnode_init); module_exit(cec_devnode_exit) -MODULE_AUTHOR("Hans Verkuil "); +MODULE_AUTHOR("Hans Verkuil "); MODULE_DESCRIPTION("Device node registration for cec drivers"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/cec/platform/Kconfig b/drivers/media/cec/platform/Kconfig index ede81fe331b0de..e40413609f537f 100644 --- a/drivers/media/cec/platform/Kconfig +++ b/drivers/media/cec/platform/Kconfig @@ -99,7 +99,7 @@ config CEC_TEGRA config CEC_SECO tristate "SECO Boards HDMI CEC driver" - depends on X86 || COMPILE_TEST + depends on X86 || (COMPILE_TEST && HAS_IOPORT) depends on PCI && DMI select CEC_CORE select CEC_NOTIFIER diff --git a/drivers/media/cec/platform/cec-gpio/cec-gpio.c b/drivers/media/cec/platform/cec-gpio/cec-gpio.c index 98dacb0919b673..cf64e8871fe5ba 100644 --- a/drivers/media/cec/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/cec/platform/cec-gpio/cec-gpio.c @@ -279,7 +279,7 @@ MODULE_DEVICE_TABLE(of, cec_gpio_match); static struct platform_driver cec_gpio_pdrv = { .probe = cec_gpio_probe, - .remove_new = cec_gpio_remove, + .remove = cec_gpio_remove, .driver = { .name = "cec-gpio", .of_match_table = cec_gpio_match, @@ -288,6 +288,6 @@ static struct platform_driver cec_gpio_pdrv = { module_platform_driver(cec_gpio_pdrv); -MODULE_AUTHOR("Hans Verkuil "); +MODULE_AUTHOR("Hans Verkuil "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("CEC GPIO driver"); diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 8fbbb4091455f1..12b73ea0f31d47 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -582,7 +582,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_cec_id); static struct platform_driver cros_ec_cec_driver = { .probe = cros_ec_cec_probe, - .remove_new = cros_ec_cec_remove, + .remove = cros_ec_cec_remove, .driver = { .name = DRV_NAME, .pm = &cros_ec_cec_pm_ops, diff --git a/drivers/media/cec/platform/meson/ao-cec-g12a.c b/drivers/media/cec/platform/meson/ao-cec-g12a.c index 51294b9b6cd591..41f5b8669cb01b 100644 --- a/drivers/media/cec/platform/meson/ao-cec-g12a.c +++ b/drivers/media/cec/platform/meson/ao-cec-g12a.c @@ -778,7 +778,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); static struct platform_driver meson_ao_cec_g12a_driver = { .probe = meson_ao_cec_g12a_probe, - .remove_new = meson_ao_cec_g12a_remove, + .remove = meson_ao_cec_g12a_remove, .driver = { .name = "meson-ao-cec-g12a", .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), diff --git a/drivers/media/cec/platform/meson/ao-cec.c b/drivers/media/cec/platform/meson/ao-cec.c index 494738daf09a40..145efd9af6acab 100644 --- a/drivers/media/cec/platform/meson/ao-cec.c +++ b/drivers/media/cec/platform/meson/ao-cec.c @@ -714,7 +714,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_of_match); static struct platform_driver meson_ao_cec_driver = { .probe = meson_ao_cec_probe, - .remove_new = meson_ao_cec_remove, + .remove = meson_ao_cec_remove, .driver = { .name = "meson-ao-cec", .of_match_table = meson_ao_cec_of_match, diff --git a/drivers/media/cec/platform/s5p/s5p_cec.c b/drivers/media/cec/platform/s5p/s5p_cec.c index 51ab4a80aafe63..4a92d3230f661e 100644 --- a/drivers/media/cec/platform/s5p/s5p_cec.c +++ b/drivers/media/cec/platform/s5p/s5p_cec.c @@ -294,7 +294,7 @@ MODULE_DEVICE_TABLE(of, s5p_cec_match); static struct platform_driver s5p_cec_pdrv = { .probe = s5p_cec_probe, - .remove_new = s5p_cec_remove, + .remove = s5p_cec_remove, .driver = { .name = CEC_NAME, .of_match_table = s5p_cec_match, diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c index 5d4c5a2cae097e..b7bb49f0239577 100644 --- a/drivers/media/cec/platform/seco/seco-cec.c +++ b/drivers/media/cec/platform/seco/seco-cec.c @@ -778,7 +778,7 @@ static struct platform_driver secocec_driver = { .pm = SECOCEC_PM_OPS, }, .probe = secocec_probe, - .remove_new = secocec_remove, + .remove = secocec_remove, }; module_platform_driver(secocec_driver); diff --git a/drivers/media/cec/platform/sti/stih-cec.c b/drivers/media/cec/platform/sti/stih-cec.c index 99978a7c8d9b70..49843d576c7ce7 100644 --- a/drivers/media/cec/platform/sti/stih-cec.c +++ b/drivers/media/cec/platform/sti/stih-cec.c @@ -383,7 +383,7 @@ MODULE_DEVICE_TABLE(of, stih_cec_match); static struct platform_driver stih_cec_pdrv = { .probe = stih_cec_probe, - .remove_new = stih_cec_remove, + .remove = stih_cec_remove, .driver = { .name = CEC_NAME, .of_match_table = stih_cec_match, diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c index bda9d254041a6a..fea2d65acffc6e 100644 --- a/drivers/media/cec/platform/stm32/stm32-cec.c +++ b/drivers/media/cec/platform/stm32/stm32-cec.c @@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(of, stm32_cec_of_match); static struct platform_driver stm32_cec_driver = { .probe = stm32_cec_probe, - .remove_new = stm32_cec_remove, + .remove = stm32_cec_remove, .driver = { .name = CEC_NAME, .of_match_table = stm32_cec_of_match, diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c index 7c1022cee1e84f..3ed50097262f64 100644 --- a/drivers/media/cec/platform/tegra/tegra_cec.c +++ b/drivers/media/cec/platform/tegra/tegra_cec.c @@ -465,7 +465,7 @@ static struct platform_driver tegra_cec_driver = { .of_match_table = tegra_cec_of_match, }, .probe = tegra_cec_probe, - .remove_new = tegra_cec_remove, + .remove = tegra_cec_remove, #ifdef CONFIG_PM .suspend = tegra_cec_suspend, diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index bb7d81f7eba624..a1854b3dd004b9 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -407,8 +407,6 @@ const struct vb2_ops vbi_qops = { .buf_cleanup = buf_cleanup, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 040489e15ea0c3..94e1cd4eaedbf1 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -681,8 +681,6 @@ const struct vb2_ops video_qops = { .buf_cleanup = buf_cleanup, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /********************************************************************************/ diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 73990e469df9da..d14ba271db50de 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -398,8 +398,6 @@ void smsdvb_debugfs_release(struct smsdvb_client_t *client) void smsdvb_debugfs_register(void) { - struct dentry *d; - /* * FIXME: This was written to debug Siano USB devices. So, it creates * the debugfs node under /usb. @@ -410,12 +408,7 @@ void smsdvb_debugfs_register(void) * node for sdio-based boards, but this may need some logic at sdio * subsystem. */ - d = debugfs_create_dir("smsdvb", usb_debug_root); - if (IS_ERR_OR_NULL(d)) { - pr_err("Couldn't create sysfs node for smsdvb\n"); - return; - } - smsdvb_debugfs_usb_root = d; + smsdvb_debugfs_usb_root = debugfs_create_dir("smsdvb", usb_debug_root); } void smsdvb_debugfs_unregister(void) diff --git a/drivers/media/common/uvc.c b/drivers/media/common/uvc.c index c54c2268fee618..1ad4604474accd 100644 --- a/drivers/media/common/uvc.c +++ b/drivers/media/common/uvc.c @@ -96,6 +96,10 @@ static const struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_RGBP, .fcc = V4L2_PIX_FMT_RGB565, }, + { + .guid = UVC_GUID_FORMAT_D3DFMT_R5G6B5, + .fcc = V4L2_PIX_FMT_RGB565, + }, { .guid = UVC_GUID_FORMAT_BGR3, .fcc = V4L2_PIX_FMT_BGR24, @@ -120,6 +124,10 @@ static const struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_Y12I, .fcc = V4L2_PIX_FMT_Y12I, }, + { + .guid = UVC_GUID_FORMAT_Y16I, + .fcc = V4L2_PIX_FMT_Y16I, + }, { .guid = UVC_GUID_FORMAT_Z16, .fcc = V4L2_PIX_FMT_Z16, diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index b0523fc23506ac..2df566f409b65e 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -2037,7 +2037,10 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * become ready or for streamoff. Driver's lock is released to * allow streamoff or qbuf to be called while waiting. */ - call_void_qop(q, wait_prepare, q); + if (q->ops->wait_prepare) + call_void_qop(q, wait_prepare, q); + else if (q->lock) + mutex_unlock(q->lock); /* * All locks have been released, it is safe to sleep now. @@ -2047,12 +2050,16 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) !list_empty(&q->done_list) || !q->streaming || q->error); + if (q->ops->wait_finish) + call_void_qop(q, wait_finish, q); + else if (q->lock) + mutex_lock(q->lock); + + q->waiting_in_dqbuf = 0; /* * We need to reevaluate both conditions again after reacquiring * the locks or return an error if one occurred. */ - call_void_qop(q, wait_finish, q); - q->waiting_in_dqbuf = 0; if (ret) { dprintk(q, 1, "sleep was interrupted\n"); return ret; @@ -2324,7 +2331,7 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type) } if (q_num_bufs < q->min_queued_buffers) { - dprintk(q, 1, "need at least %u queued buffers\n", + dprintk(q, 1, "need at least %u allocated buffers\n", q->min_queued_buffers); return -EINVAL; } @@ -2646,6 +2653,14 @@ int vb2_core_queue_init(struct vb2_queue *q) if (WARN_ON(q->min_reqbufs_allocation > q->max_num_buffers)) return -EINVAL; + /* Either both or none are set */ + if (WARN_ON(!q->ops->wait_prepare ^ !q->ops->wait_finish)) + return -EINVAL; + + /* Warn if q->lock is NULL and no custom wait_prepare is provided */ + if (WARN_ON(!q->lock && !q->ops->wait_prepare)) + return -EINVAL; + INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); @@ -3205,10 +3220,17 @@ static int vb2_thread(void *data) continue; prequeue--; } else { - call_void_qop(q, wait_finish, q); - if (!threadio->stop) + if (!threadio->stop) { + if (q->ops->wait_finish) + call_void_qop(q, wait_finish, q); + else if (q->lock) + mutex_lock(q->lock); ret = vb2_core_dqbuf(q, &index, NULL, 0); - call_void_qop(q, wait_prepare, q); + if (q->ops->wait_prepare) + call_void_qop(q, wait_prepare, q); + else if (q->lock) + mutex_unlock(q->lock); + } dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret); if (!ret) vb = vb2_get_buffer(q, index); @@ -3220,12 +3242,19 @@ static int vb2_thread(void *data) if (vb->state != VB2_BUF_STATE_ERROR) if (threadio->fnc(vb, threadio->priv)) break; - call_void_qop(q, wait_finish, q); if (copy_timestamp) vb->timestamp = ktime_get_ns(); - if (!threadio->stop) + if (!threadio->stop) { + if (q->ops->wait_finish) + call_void_qop(q, wait_finish, q); + else if (q->lock) + mutex_lock(q->lock); ret = vb2_core_qbuf(q, vb, NULL, NULL); - call_void_qop(q, wait_prepare, q); + if (q->ops->wait_prepare) + call_void_qop(q, wait_prepare, q); + else if (q->lock) + mutex_unlock(q->lock); + } if (ret || threadio->stop) break; } @@ -3305,4 +3334,4 @@ EXPORT_SYMBOL_GPL(vb2_thread_stop); MODULE_DESCRIPTION("Media buffer core framework"); MODULE_AUTHOR("Pawel Osciak , Marek Szyprowski"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index bb0b7fa67b539a..a13ec569c82f6d 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -862,4 +862,4 @@ EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size); MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 6975a71d740f6d..c6ddf2357c58c1 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -676,4 +676,4 @@ EXPORT_SYMBOL_GPL(vb2_dma_sg_memops); MODULE_DESCRIPTION("dma scatter/gather memory handling routines for videobuf2"); MODULE_AUTHOR("Andrzej Pietrasiewicz"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 293f3d5f1c4e98..9201d854dbcc0c 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -231,7 +231,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b break; } - /* Fill in driver-provided information for OUTPUT types */ + /* Fill in user-provided information for OUTPUT types */ if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* * Will have to go up to b->length when API starts diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 7d953706f3f800..3f777068cd34b7 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -442,4 +442,4 @@ EXPORT_SYMBOL_GPL(vb2_vmalloc_memops); MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2"); MODULE_AUTHOR("Pawel Osciak "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 27f1de21f57175..d935fb10e62081 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -729,7 +729,7 @@ static int bcm3510_init_cold(struct bcm3510_state *st) int ret; bcm3510_register_value v; - /* read Acquisation Processor status register and check it is not in RUN mode */ + /* read Acquisition Processor status register and check it is not in RUN mode */ if ((ret = bcm3510_readB(st,0xa2,&v)) < 0) return ret; if (v.APSTAT1_a2.RUN) { diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index c958bcff026ec5..6cbbb351d545df 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -78,7 +78,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); #define SOC_8090_P1G_11R1 0x86 #define SOC_8090_P1G_21R1 0x8e -/* else use thos ones to check */ +/* else use those ones to check */ #define P1A_B 0x0 #define P1C 0x1 #define P1D_E_F 0x3 @@ -1574,7 +1574,7 @@ static int dib0090_reset(struct dvb_frontend *fe) if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc)) dib0090_set_EFUSE(state); - /* Congigure in function of the crystal */ + /* Configure in function of the crystal */ if (state->config->force_crystal_mode != 0) dib0090_write_reg(state, 0x14, state->config->force_crystal_mode & 3); diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c index c598b2a6332565..63bc7b74bc8b46 100644 --- a/drivers/media/dvb-frontends/dib3000mb.c +++ b/drivers/media/dvb-frontends/dib3000mb.c @@ -51,7 +51,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a static int dib3000_read_reg(struct dib3000_state *state, u16 reg) { u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff }; - u8 rb[2]; + u8 rb[2] = {}; struct i2c_msg msg[] = { { .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 }, { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 }, @@ -640,7 +640,7 @@ static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber) return 0; } -/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */ +/* see dib3000-watch dvb-apps for exact calculations of signal_strength and snr */ static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { struct dib3000_state* state = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 023db6e793f867..05254d8717db85 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -947,8 +947,6 @@ static const struct vb2_ops rtl2832_sdr_vb2_ops = { .buf_queue = rtl2832_sdr_buf_queue, .start_streaming = rtl2832_sdr_start_streaming, .stop_streaming = rtl2832_sdr_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int rtl2832_sdr_g_tuner(struct file *file, void *priv, @@ -1487,7 +1485,7 @@ static struct platform_driver rtl2832_sdr_driver = { .name = "rtl2832_sdr", }, .probe = rtl2832_sdr_probe, - .remove_new = rtl2832_sdr_remove, + .remove = rtl2832_sdr_remove, }; module_platform_driver(rtl2832_sdr_driver); diff --git a/drivers/media/dvb-frontends/stv6111.c b/drivers/media/dvb-frontends/stv6111.c index 2d0adb6fcb0817..0ac15273922da2 100644 --- a/drivers/media/dvb-frontends/stv6111.c +++ b/drivers/media/dvb-frontends/stv6111.c @@ -161,7 +161,7 @@ static const struct slookup gain_rfagc_lookup[] = { }; /* - * This table is 6 dB too low comapred to the others (probably created with + * This table is 6 dB too low compared to the others (probably created with * a different BB_MAG setting) */ static const struct slookup gain_channel_agc_nf_lookup[] = { diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index fd928787207edf..c11563853c07f3 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c @@ -954,7 +954,7 @@ static int RFTrackingFiltersCorrection(struct tda_state *state, Capprox = 255; - /* TODO Temperature compensation. There is defenitely a scale factor */ + /* TODO Temperature compensation. There is definitely a scale factor */ /* missing in the datasheet, so leave it out for now. */ state->m_Regs[EB14] = Capprox; diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index a5baca2449c76d..e25add6cc38e94 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -553,13 +553,19 @@ static void ts2020_regmap_unlock(void *__dev) static int ts2020_probe(struct i2c_client *client) { struct ts2020_config *pdata = client->dev.platform_data; - struct dvb_frontend *fe = pdata->fe; + struct dvb_frontend *fe; struct ts2020_priv *dev; int ret; u8 u8tmp; unsigned int utmp; char *chip_str; + if (!pdata) { + dev_err(&client->dev, "platform data is mandatory\n"); + return -EINVAL; + } + + fe = pdata->fe; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c index 17f6e373c13d89..e8b9e67a871763 100644 --- a/drivers/media/dvb-frontends/zd1301_demod.c +++ b/drivers/media/dvb-frontends/zd1301_demod.c @@ -531,7 +531,7 @@ static struct platform_driver zd1301_demod_driver = { .suppress_bind_attrs = true, }, .probe = zd1301_demod_probe, - .remove_new = zd1301_demod_remove, + .remove = zd1301_demod_remove, }; module_platform_driver(zd1301_demod_driver); diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c index 3df055be66d6cb..5ad987c6861b99 100644 --- a/drivers/media/dvb-frontends/zl10036.c +++ b/drivers/media/dvb-frontends/zl10036.c @@ -89,7 +89,7 @@ static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count) int ret; if (zl10036_debug & 0x02) { - /* every 8bit-value satisifes this! + /* every 8bit-value satisfies this! * so only check for debug log */ if ((buf[0] & 0x80) == 0x00) reg = 2; diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 819ff9f7c90fea..ff7dfa0278a7a0 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1440,7 +1440,8 @@ static int adv7180_probe(struct i2c_client *client) return ret; } - if (of_property_read_bool(np, "adv,force-bt656-4")) + if (of_property_read_bool(np, "adv,force-bt656-4") || + of_property_read_bool(np, "adi,force-bt656-4")) state->force_bt656_4 = true; if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index e9406d552699f8..4036972af3a662 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -116,6 +116,9 @@ struct adv7511_state { unsigned edid_detect_counter; struct workqueue_struct *work_queue; struct delayed_work edid_handler; /* work entry */ + + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; }; static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd); @@ -483,27 +486,25 @@ static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size) return 256 - csum; } -static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri) +static int read_infoframe(struct v4l2_subdev *sd, + const struct adv7511_cfg_read_infoframe *cri, + u8 *buffer) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *dev = &client->dev; - union hdmi_infoframe frame; - u8 buffer[32]; u8 len; int i; if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) { v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc); - return; + return 0; } memcpy(buffer, cri->header, sizeof(cri->header)); len = buffer[2]; - if (len + 4 > sizeof(buffer)) { + if (len + 4 > V4L2_DEBUGFS_IF_MAX_LEN) { v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); - return; + return 0; } if (cri->payload_addr >= 0x100) { @@ -516,21 +517,38 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_ buffer[3] = 0; buffer[3] = hdmi_infoframe_checksum(buffer, len + 4); - if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) { - v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); + return len + 4; +} + +static void log_infoframe(struct v4l2_subdev *sd, + const struct adv7511_cfg_read_infoframe *cri) +{ + union hdmi_infoframe frame; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + int len = read_infoframe(sd, cri, buffer); + + if (len <= 0) + return; + + if (hdmi_infoframe_unpack(&frame, buffer, len) < 0) { + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", + __func__, cri->desc); return; } hdmi_infoframe_log(KERN_INFO, dev, &frame); } +static const struct adv7511_cfg_read_infoframe cri[] = { + { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 }, + { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 }, + { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 }, +}; + static void adv7511_log_infoframes(struct v4l2_subdev *sd) { - static const struct adv7511_cfg_read_infoframe cri[] = { - { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 }, - { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 }, - { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 }, - }; int i; for (i = 0; i < ARRAY_SIZE(cri); i++) @@ -1693,6 +1711,34 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) return false; } +static ssize_t +adv7511_debugfs_if_read(u32 type, void *priv, + struct file *filp, char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int index; + int len; + + switch (type) { + case V4L2_DEBUGFS_IF_AVI: + index = 0; + break; + case V4L2_DEBUGFS_IF_AUDIO: + index = 1; + break; + case V4L2_DEBUGFS_IF_SPD: + index = 2; + break; + default: + return 0; + } + len = read_infoframe(sd, &cri[index], buf); + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static int adv7511_registered(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); @@ -1700,9 +1746,16 @@ static int adv7511_registered(struct v4l2_subdev *sd) int err; err = cec_register_adapter(state->cec_adap, &client->dev); - if (err) + if (err) { cec_delete_adapter(state->cec_adap); - return err; + return err; + } + + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | + V4L2_DEBUGFS_IF_SPD, sd, adv7511_debugfs_if_read); + return 0; } static void adv7511_unregistered(struct v4l2_subdev *sd) @@ -1710,6 +1763,10 @@ static void adv7511_unregistered(struct v4l2_subdev *sd) struct adv7511_state *state = get_adv7511_state(sd); cec_unregister_adapter(state->cec_adap); + v4l2_debugfs_if_free(state->infoframes); + state->infoframes = NULL; + debugfs_remove_recursive(state->debugfs_dir); + state->debugfs_dir = NULL; } static const struct v4l2_subdev_internal_ops adv7511_int_ops = { diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 272945a878b3ce..e271782b7b70bd 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -42,7 +42,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_DESCRIPTION("Analog Devices ADV7604/10/11/12 video decoder driver"); -MODULE_AUTHOR("Hans Verkuil "); +MODULE_AUTHOR("Hans Verkuil "); MODULE_AUTHOR("Mats Randgaard "); MODULE_LICENSE("GPL"); @@ -193,6 +193,9 @@ struct adv76xx_state { struct delayed_work delayed_work_enable_hotplug; bool restart_stdi_once; + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; + /* CEC */ struct cec_adapter *cec_adap; u8 cec_addr[ADV76XX_MAX_ADDRS]; @@ -1405,12 +1408,13 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - false, timings)) + false, adv76xx_get_dv_timings_cap(sd, -1), timings)) return 0; if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - false, state->aspect_ratio, timings)) + false, state->aspect_ratio, + adv76xx_get_dv_timings_cap(sd, -1), timings)) return 0; v4l2_dbg(2, debug, sd, @@ -2458,10 +2462,9 @@ static const struct adv76xx_cfg_read_infoframe adv76xx_cri[] = { { "Vendor", 0x10, 0xec, 0x54 } }; -static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index, - union hdmi_infoframe *frame) +static int adv76xx_read_infoframe_buf(struct v4l2_subdev *sd, int index, + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN]) { - uint8_t buffer[32]; u8 len; int i; @@ -2472,27 +2475,20 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index, } for (i = 0; i < 3; i++) - buffer[i] = infoframe_read(sd, - adv76xx_cri[index].head_addr + i); + buf[i] = infoframe_read(sd, adv76xx_cri[index].head_addr + i); - len = buffer[2] + 1; + len = buf[2] + 1; - if (len + 3 > sizeof(buffer)) { + if (len + 3 > V4L2_DEBUGFS_IF_MAX_LEN) { v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, adv76xx_cri[index].desc, len); return -ENOENT; } for (i = 0; i < len; i++) - buffer[i + 3] = infoframe_read(sd, - adv76xx_cri[index].payload_addr + i); - - if (hdmi_infoframe_unpack(frame, buffer, len + 3) < 0) { - v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, - adv76xx_cri[index].desc); - return -ENOENT; - } - return 0; + buf[i + 3] = infoframe_read(sd, + adv76xx_cri[index].payload_addr + i); + return len + 3; } static void adv76xx_log_infoframes(struct v4l2_subdev *sd) @@ -2505,10 +2501,19 @@ static void adv76xx_log_infoframes(struct v4l2_subdev *sd) } for (i = 0; i < ARRAY_SIZE(adv76xx_cri); i++) { - union hdmi_infoframe frame; struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + union hdmi_infoframe frame; + int len; - if (!adv76xx_read_infoframe(sd, i, &frame)) + len = adv76xx_read_infoframe_buf(sd, i, buffer); + if (len < 0) + continue; + + if (hdmi_infoframe_unpack(&frame, buffer, len) < 0) + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", + __func__, adv76xx_cri[i].desc); + else hdmi_infoframe_log(KERN_INFO, &client->dev, &frame); } } @@ -2694,6 +2699,41 @@ static int adv76xx_subscribe_event(struct v4l2_subdev *sd, } } +static ssize_t +adv76xx_debugfs_if_read(u32 type, void *priv, struct file *filp, + char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int index; + int len; + + if (!is_hdmi(sd)) + return 0; + + switch (type) { + case V4L2_DEBUGFS_IF_AVI: + index = 0; + break; + case V4L2_DEBUGFS_IF_AUDIO: + index = 1; + break; + case V4L2_DEBUGFS_IF_SPD: + index = 2; + break; + case V4L2_DEBUGFS_IF_HDMI: + index = 3; + break; + default: + return 0; + } + + len = adv76xx_read_infoframe_buf(sd, index, buf); + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static int adv76xx_registered(struct v4l2_subdev *sd) { struct adv76xx_state *state = to_state(sd); @@ -2701,9 +2741,16 @@ static int adv76xx_registered(struct v4l2_subdev *sd) int err; err = cec_register_adapter(state->cec_adap, &client->dev); - if (err) + if (err) { cec_delete_adapter(state->cec_adap); - return err; + return err; + } + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | + V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI, sd, + adv76xx_debugfs_if_read); + return 0; } static void adv76xx_unregistered(struct v4l2_subdev *sd) @@ -2711,6 +2758,10 @@ static void adv76xx_unregistered(struct v4l2_subdev *sd) struct adv76xx_state *state = to_state(sd); cec_unregister_adapter(state->cec_adap); + v4l2_debugfs_if_free(state->infoframes); + state->infoframes = NULL; + debugfs_remove_recursive(state->debugfs_dir); + state->debugfs_dir = NULL; } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 014fc913225c4a..5545cd23e113d5 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -38,7 +38,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_DESCRIPTION("Analog Devices ADV7842 video decoder driver"); -MODULE_AUTHOR("Hans Verkuil "); +MODULE_AUTHOR("Hans Verkuil "); MODULE_AUTHOR("Martin Bugge "); MODULE_LICENSE("GPL"); @@ -114,6 +114,9 @@ struct adv7842_state { bool restart_stdi_once; bool hdmi_port_a; + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; + /* i2c clients */ struct i2c_client *i2c_sdp_io; struct i2c_client *i2c_sdp; @@ -1431,14 +1434,15 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, } if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, - (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | - (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - false, timings)) + (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | + (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), + false, adv7842_get_dv_timings_cap(sd), timings)) return 0; if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs, - (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | - (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), - false, state->aspect_ratio, timings)) + (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | + (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), + false, state->aspect_ratio, + adv7842_get_dv_timings_cap(sd), timings)) return 0; v4l2_dbg(2, debug, sd, @@ -2565,58 +2569,65 @@ struct adv7842_cfg_read_infoframe { u8 payload_addr; }; -static void log_infoframe(struct v4l2_subdev *sd, const struct adv7842_cfg_read_infoframe *cri) +static const struct adv7842_cfg_read_infoframe adv7842_cri[] = { + { "AVI", 0x01, 0xe0, 0x00 }, + { "Audio", 0x02, 0xe3, 0x1c }, + { "SDP", 0x04, 0xe6, 0x2a }, + { "Vendor", 0x10, 0xec, 0x54 } +}; + +static int adv7842_read_infoframe_buf(struct v4l2_subdev *sd, int index, + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN]) { - int i; - u8 buffer[32]; - union hdmi_infoframe frame; - u8 len; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *dev = &client->dev; + const struct adv7842_cfg_read_infoframe *cri = &adv7842_cri[index]; + int len, i; if (!(io_read(sd, 0x60) & cri->present_mask)) { - v4l2_info(sd, "%s infoframe not received\n", cri->desc); - return; + v4l2_dbg(1, debug, sd, + "%s infoframe not received\n", cri->desc); + return -ENOENT; } for (i = 0; i < 3; i++) - buffer[i] = infoframe_read(sd, cri->head_addr + i); + buf[i] = infoframe_read(sd, cri->head_addr + i); - len = buffer[2] + 1; + len = buf[2] + 1; - if (len + 3 > sizeof(buffer)) { - v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); - return; + if (len + 3 > V4L2_DEBUGFS_IF_MAX_LEN) { + v4l2_err(sd, "%s: invalid %s infoframe length %d\n", + __func__, cri->desc, len); + return -ENOENT; } for (i = 0; i < len; i++) - buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i); - - if (hdmi_infoframe_unpack(&frame, buffer, len + 3) < 0) { - v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); - return; - } - - hdmi_infoframe_log(KERN_INFO, dev, &frame); + buf[i + 3] = infoframe_read(sd, cri->payload_addr + i); + return len + 3; } static void adv7842_log_infoframes(struct v4l2_subdev *sd) { - int i; - static const struct adv7842_cfg_read_infoframe cri[] = { - { "AVI", 0x01, 0xe0, 0x00 }, - { "Audio", 0x02, 0xe3, 0x1c }, - { "SDP", 0x04, 0xe6, 0x2a }, - { "Vendor", 0x10, 0xec, 0x54 } - }; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + union hdmi_infoframe frame; + u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + int len, i; if (!(hdmi_read(sd, 0x05) & 0x80)) { v4l2_info(sd, "receive DVI-D signal, no infoframes\n"); return; } - for (i = 0; i < ARRAY_SIZE(cri); i++) - log_infoframe(sd, &cri[i]); + for (i = 0; i < ARRAY_SIZE(adv7842_cri); i++) { + len = adv7842_read_infoframe_buf(sd, i, buffer); + if (len < 0) + continue; + + if (hdmi_infoframe_unpack(&frame, buffer, len) < 0) + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", + __func__, adv7842_cri[i].desc); + else + hdmi_infoframe_log(KERN_INFO, dev, &frame); + } } #if 0 @@ -3263,6 +3274,41 @@ static int adv7842_subscribe_event(struct v4l2_subdev *sd, } } +static ssize_t +adv7842_debugfs_if_read(u32 type, void *priv, struct file *filp, + char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int index; + int len; + + if (!is_hdmi(sd)) + return 0; + + switch (type) { + case V4L2_DEBUGFS_IF_AVI: + index = 0; + break; + case V4L2_DEBUGFS_IF_AUDIO: + index = 1; + break; + case V4L2_DEBUGFS_IF_SPD: + index = 2; + break; + case V4L2_DEBUGFS_IF_HDMI: + index = 3; + break; + default: + return 0; + } + + len = adv7842_read_infoframe_buf(sd, index, buf); + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static int adv7842_registered(struct v4l2_subdev *sd) { struct adv7842_state *state = to_state(sd); @@ -3270,8 +3316,15 @@ static int adv7842_registered(struct v4l2_subdev *sd) int err; err = cec_register_adapter(state->cec_adap, &client->dev); - if (err) + if (err) { cec_delete_adapter(state->cec_adap); + } else { + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | + V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI, sd, + adv7842_debugfs_if_read); + } return err; } @@ -3280,6 +3333,10 @@ static void adv7842_unregistered(struct v4l2_subdev *sd) struct adv7842_state *state = to_state(sd); cec_unregister_adapter(state->cec_adap); + v4l2_debugfs_if_free(state->infoframes); + state->infoframes = NULL; + debugfs_remove_recursive(state->debugfs_dir); + state->debugfs_dir = NULL; } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index 5ddfd3dcb18876..05b708bd0a641c 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -2240,8 +2239,6 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) static const struct v4l2_subdev_core_ops alvium_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops alvium_video_ops = { @@ -2289,7 +2286,7 @@ static int alvium_subdev_init(struct alvium_dev *alvium) v4l2_i2c_subdev_init(sd, client, &alvium_subdev_ops); sd->internal_ops = &alvium_internal_ops; - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; alvium->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index 8eed4a200fd89b..79bddfee2e2ec7 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -904,4 +904,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Texas Instruments DS90UB913 FPD-Link III Serializer Driver"); MODULE_AUTHOR("Luca Ceresoli "); MODULE_AUTHOR("Tomi Valkeinen "); -MODULE_IMPORT_NS(I2C_ATR); +MODULE_IMPORT_NS("I2C_ATR"); diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index 16f88db1498162..725589b3e1c58a 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -717,8 +716,6 @@ static const struct v4l2_subdev_pad_ops ub953_pad_ops = { static const struct v4l2_subdev_core_ops ub953_subdev_core_ops = { .log_status = ub953_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_ops ub953_subdev_ops = { @@ -1246,7 +1243,7 @@ static int ub953_subdev_init(struct ub953_data *priv) priv->sd.internal_ops = &ub953_internal_ops; priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; + V4L2_SUBDEV_FL_STREAMS; priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; priv->sd.entity.ops = &ub953_entity_ops; @@ -1428,4 +1425,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Texas Instruments FPD-Link III/IV CSI-2 Serializers Driver"); MODULE_AUTHOR("Luca Ceresoli "); MODULE_AUTHOR("Tomi Valkeinen "); -MODULE_IMPORT_NS(I2C_ATR); +MODULE_IMPORT_NS("I2C_ATR"); diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index ffe5f25f864762..1b1ff7f7505b00 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include @@ -1286,7 +1285,7 @@ static int ub960_rxport_get_strobe_pos(struct ub960_data *priv, clk_delay += v & UB960_IR_RX_ANA_STROBE_SET_CLK_DELAY_MASK; - ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v); + ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v); if (ret) return ret; @@ -3085,8 +3084,6 @@ static int ub960_log_status(struct v4l2_subdev *sd) static const struct v4l2_subdev_core_ops ub960_subdev_core_ops = { .log_status = ub960_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_internal_ops ub960_internal_ops = { @@ -3667,7 +3664,7 @@ static int ub960_create_subdev(struct ub960_data *priv) } priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; + V4L2_SUBDEV_FL_STREAMS; priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; priv->sd.entity.ops = &ub960_entity_ops; @@ -4055,4 +4052,4 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Texas Instruments FPD-Link III/IV Deserializers Driver"); MODULE_AUTHOR("Luca Ceresoli "); MODULE_AUTHOR("Tomi Valkeinen "); -MODULE_IMPORT_NS(I2C_ATR); +MODULE_IMPORT_NS("I2C_ATR"); diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c index 18ef2b35c9aa3d..3a4d100b9199f3 100644 --- a/drivers/media/i2c/dw9768.c +++ b/drivers/media/i2c/dw9768.c @@ -374,7 +374,8 @@ static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - pm_runtime_put(sd->dev); + pm_runtime_mark_last_busy(sd->dev); + pm_runtime_put_autosuspend(sd->dev); return 0; } @@ -471,10 +472,9 @@ static int dw9768_probe(struct i2c_client *client) * to be powered on in an ACPI system. Similarly for power off in * remove. */ - pm_runtime_enable(dev); full_power = (is_acpi_node(dev_fwnode(dev)) && acpi_dev_state_d0(dev)) || - (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev)); + (is_of_node(dev_fwnode(dev)) && !IS_ENABLED(CONFIG_PM)); if (full_power) { ret = dw9768_runtime_resume(dev); if (ret < 0) { @@ -484,23 +484,26 @@ static int dw9768_probe(struct i2c_client *client) pm_runtime_set_active(dev); } + pm_runtime_enable(dev); ret = v4l2_async_register_subdev(&dw9768->sd); if (ret < 0) { dev_err(dev, "failed to register V4L2 subdev: %d", ret); goto err_power_off; } + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); pm_runtime_idle(dev); return 0; err_power_off: + pm_runtime_disable(dev); if (full_power) { dw9768_runtime_suspend(dev); pm_runtime_set_suspended(dev); } err_clean_entity: - pm_runtime_disable(dev); media_entity_cleanup(&dw9768->sd.entity); err_free_handler: v4l2_ctrl_handler_free(&dw9768->ctrls); @@ -517,12 +520,12 @@ static void dw9768_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&dw9768->sd); v4l2_ctrl_handler_free(&dw9768->ctrls); media_entity_cleanup(&dw9768->sd.entity); + pm_runtime_disable(dev); if ((is_acpi_node(dev_fwnode(dev)) && acpi_dev_state_d0(dev)) || - (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev))) { + (is_of_node(dev_fwnode(dev)) && !IS_ENABLED(CONFIG_PM))) { dw9768_runtime_suspend(dev); pm_runtime_set_suspended(dev); } - pm_runtime_disable(dev); } static const struct of_device_id dw9768_of_table[] = { diff --git a/drivers/media/i2c/gc0308.c b/drivers/media/i2c/gc0308.c index fa754a8a39a670..069f42785b3c50 100644 --- a/drivers/media/i2c/gc0308.c +++ b/drivers/media/i2c/gc0308.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -987,8 +986,6 @@ static const struct v4l2_ctrl_ops gc0308_ctrl_ops = { static const struct v4l2_subdev_core_ops gc0308_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = gc0308_g_register, .s_register = gc0308_s_register, @@ -1338,7 +1335,6 @@ static int gc0308_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&gc0308->sd, client, &gc0308_subdev_ops); gc0308->sd.internal_ops = &gc0308_internal_ops; gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS; ret = gc0308_init_controls(gc0308); if (ret) diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c index 0413c557e594bb..3f7f3d5abeebb8 100644 --- a/drivers/media/i2c/gc05a2.c +++ b/drivers/media/i2c/gc05a2.c @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -1059,13 +1058,7 @@ static const struct v4l2_subdev_pad_ops gc05a2_subdev_pad_ops = { .get_selection = gc05a2_get_selection, }; -static const struct v4l2_subdev_core_ops gc05a2_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_ops gc05a2_subdev_ops = { - .core = &gc05a2_core_ops, .video = &gc05a2_video_ops, .pad = &gc05a2_subdev_pad_ops, }; @@ -1271,8 +1264,7 @@ static int gc05a2_probe(struct i2c_client *client) return dev_err_probe(dev, ret, "failed to init controls\n"); - gc05a2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + gc05a2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; gc05a2->pad.flags = MEDIA_PAD_FL_SOURCE; gc05a2->sd.dev = &client->dev; gc05a2->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/gc08a3.c b/drivers/media/i2c/gc08a3.c index 84de5cff958d6c..938709a677b69f 100644 --- a/drivers/media/i2c/gc08a3.c +++ b/drivers/media/i2c/gc08a3.c @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -1001,13 +1000,7 @@ static const struct v4l2_subdev_pad_ops gc08a3_subdev_pad_ops = { .get_selection = gc08a3_get_selection, }; -static const struct v4l2_subdev_core_ops gc08a3_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_ops gc08a3_subdev_ops = { - .core = &gc08a3_core_ops, .video = &gc08a3_video_ops, .pad = &gc08a3_subdev_pad_ops, }; @@ -1247,8 +1240,7 @@ static int gc08a3_probe(struct i2c_client *client) goto err_power_off; } - gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; gc08a3->pad.flags = MEDIA_PAD_FL_SOURCE; gc08a3->sd.dev = &client->dev; gc08a3->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c index 667bb756d05626..ba02161d46e723 100644 --- a/drivers/media/i2c/gc2145.c +++ b/drivers/media/i2c/gc2145.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -899,9 +898,11 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145, return ret; } -static int gc2145_start_streaming(struct gc2145 *gc2145, - struct v4l2_subdev_state *state) +static int gc2145_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct gc2145 *gc2145 = to_gc2145(sd); struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); const struct gc2145_format *gc2145_format; struct v4l2_mbus_framefmt *fmt; @@ -967,8 +968,11 @@ static int gc2145_start_streaming(struct gc2145 *gc2145, return ret; } -static void gc2145_stop_streaming(struct gc2145 *gc2145) +static int gc2145_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct gc2145 *gc2145 = to_gc2145(sd); struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd); int ret = 0; @@ -983,22 +987,6 @@ static void gc2145_stop_streaming(struct gc2145 *gc2145) pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); -} - -static int gc2145_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct gc2145 *gc2145 = to_gc2145(sd); - struct v4l2_subdev_state *state; - int ret = 0; - - state = v4l2_subdev_lock_and_get_active_state(sd); - - if (enable) - ret = gc2145_start_streaming(gc2145, state); - else - gc2145_stop_streaming(gc2145); - - v4l2_subdev_unlock_state(state); return ret; } @@ -1123,13 +1111,8 @@ static const u8 test_pattern_val[] = { GC2145_TEST_UNIFORM | GC2145_TEST_BLACK, }; -static const struct v4l2_subdev_core_ops gc2145_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_video_ops gc2145_video_ops = { - .s_stream = gc2145_set_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops gc2145_pad_ops = { @@ -1138,10 +1121,11 @@ static const struct v4l2_subdev_pad_ops gc2145_pad_ops = { .set_fmt = gc2145_set_pad_format, .get_selection = gc2145_get_selection, .enum_frame_size = gc2145_enum_frame_size, + .enable_streams = gc2145_enable_streams, + .disable_streams = gc2145_disable_streams, }; static const struct v4l2_subdev_ops gc2145_subdev_ops = { - .core = &gc2145_core_ops, .video = &gc2145_video_ops, .pad = &gc2145_pad_ops, }; @@ -1407,8 +1391,7 @@ static int gc2145_probe(struct i2c_client *client) goto error_power_off; /* Initialize subdev */ - gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; gc2145->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; /* Initialize source pad */ diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index f31f9886c924e4..3ac42d1ab8b437 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -644,7 +644,7 @@ struct hi556 { /* Current mode */ const struct hi556_mode *cur_mode; - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; /* True if the device has been identified */ diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index e78a80b2bb2e45..2d54cea113e19f 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -922,11 +921,6 @@ static int imx219_init_state(struct v4l2_subdev *sd, return 0; } -static const struct v4l2_subdev_core_ops imx219_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_video_ops imx219_video_ops = { .s_stream = imx219_set_stream, }; @@ -940,7 +934,6 @@ static const struct v4l2_subdev_pad_ops imx219_pad_ops = { }; static const struct v4l2_subdev_ops imx219_subdev_ops = { - .core = &imx219_core_ops, .video = &imx219_video_ops, .pad = &imx219_pad_ops, }; @@ -1166,8 +1159,7 @@ static int imx219_probe(struct i2c_client *client) goto error_power_off; /* Initialize subdev */ - imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; /* Initialize source pad */ diff --git a/drivers/media/i2c/imx283.c b/drivers/media/i2c/imx283.c index 94276f4f2d8369..f676faf4b301f6 100644 --- a/drivers/media/i2c/imx283.c +++ b/drivers/media/i2c/imx283.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -1284,11 +1283,6 @@ static int imx283_get_selection(struct v4l2_subdev *sd, } } -static const struct v4l2_subdev_core_ops imx283_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_video_ops imx283_video_ops = { .s_stream = v4l2_subdev_s_stream_helper, }; @@ -1308,7 +1302,6 @@ static const struct v4l2_subdev_internal_ops imx283_internal_ops = { }; static const struct v4l2_subdev_ops imx283_subdev_ops = { - .core = &imx283_core_ops, .video = &imx283_video_ops, .pad = &imx283_pad_ops, }; @@ -1548,8 +1541,7 @@ static int imx283_probe(struct i2c_client *client) goto error_pm; /* Initialize subdev */ - imx283->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + imx283->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; imx283->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; imx283->sd.internal_ops = &imx283_internal_ops; diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 458905dfb3e110..f5ee6bd3b52d63 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -78,7 +77,6 @@ #define IMX290_ADBIT2 CCI_REG8(0x317c) #define IMX290_ADBIT2_10BIT 0x12 #define IMX290_ADBIT2_12BIT 0x00 -#define IMX290_CHIP_ID CCI_REG16_LE(0x319a) #define IMX290_ADBIT3 CCI_REG8(0x31ec) #define IMX290_ADBIT3_10BIT 0x37 #define IMX290_ADBIT3_12BIT 0x0e @@ -1211,11 +1209,6 @@ static int imx290_entity_init_state(struct v4l2_subdev *subdev, return 0; } -static const struct v4l2_subdev_core_ops imx290_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_video_ops imx290_video_ops = { .s_stream = imx290_set_stream, }; @@ -1229,7 +1222,6 @@ static const struct v4l2_subdev_pad_ops imx290_pad_ops = { }; static const struct v4l2_subdev_ops imx290_subdev_ops = { - .core = &imx290_core_ops, .video = &imx290_video_ops, .pad = &imx290_pad_ops, }; @@ -1250,11 +1242,20 @@ static int imx290_subdev_init(struct imx290 *imx290) imx290->current_mode = &imx290_modes_ptr(imx290)[0]; + /* + * After linking the subdev with the imx290 instance, we are allowed to + * use the pm_runtime functions. Decrease the PM usage count. The device + * will get suspended after the autosuspend delay, turning the power + * off. However, the communication happening in imx290_ctrl_update() + * will already be prevented even before the delay. + */ v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); - imx290->sd.internal_ops = &imx290_internal_ops; - imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; imx290->sd.dev = imx290->dev; + pm_runtime_mark_last_busy(imx290->dev); + pm_runtime_put_autosuspend(imx290->dev); + + imx290->sd.internal_ops = &imx290_internal_ops; + imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; imx290->sd.entity.ops = &imx290_subdev_entity_ops; imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; @@ -1580,6 +1581,16 @@ static int imx290_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); + /* + * Make sure the sensor is available, in STANDBY and not streaming + * before the V4L2 subdev is initialized. + */ + ret = imx290_stop_streaming(imx290); + if (ret) { + ret = dev_err_probe(dev, ret, "Could not initialize device\n"); + goto err_pm; + } + /* Initialize the V4L2 subdev. */ ret = imx290_subdev_init(imx290); if (ret) @@ -1599,13 +1610,6 @@ static int imx290_probe(struct i2c_client *client) goto err_subdev; } - /* - * Decrease the PM usage count. The device will get suspended after the - * autosuspend delay, turning the power off. - */ - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - return 0; err_subdev: diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index a20b0db330d345..3f7924aa1bd3da 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -1113,8 +1113,7 @@ static int imx415_subdev_init(struct imx415 *sensor) if (ret) return ret; - sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); diff --git a/drivers/media/i2c/max96717.c b/drivers/media/i2c/max96717.c index 4e85b8eb1e7767..9259d58ba734ee 100644 --- a/drivers/media/i2c/max96717.c +++ b/drivers/media/i2c/max96717.c @@ -697,8 +697,10 @@ static int max96717_subdev_init(struct max96717_priv *priv) priv->pads[MAX96717_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&priv->sd.entity, 2, priv->pads); - if (ret) - return dev_err_probe(dev, ret, "Failed to init pads\n"); + if (ret) { + dev_err_probe(dev, ret, "Failed to init pads\n"); + goto err_free_ctrl; + } ret = v4l2_subdev_init_finalize(&priv->sd); if (ret) { diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index d8735c246e5283..4ef5fb06131d5d 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -17,14 +17,12 @@ #include #include #include -#include -#include #include +#include #include #include #include -#include #include #include #include @@ -113,18 +111,25 @@ #define MT9P031_TEST_PATTERN_RED 0xa2 #define MT9P031_TEST_PATTERN_BLUE 0xa3 +struct mt9p031_model_info { + u32 code; +}; + struct mt9p031 { struct v4l2_subdev subdev; struct media_pad pad; struct v4l2_rect crop; /* Sensor window */ struct v4l2_mbus_framefmt format; - struct mt9p031_platform_data *pdata; struct mutex power_lock; /* lock to protect power_count */ int power_count; struct clk *clk; struct regulator_bulk_data regulators[3]; + unsigned int pixclk_pol:1; + int ext_freq; + int target_freq; + u32 code; struct aptina_pll pll; unsigned int clk_div; @@ -225,7 +230,6 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) }; struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); - struct mt9p031_platform_data *pdata = mt9p031->pdata; unsigned long ext_freq; int ret; @@ -233,7 +237,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) if (IS_ERR(mt9p031->clk)) return PTR_ERR(mt9p031->clk); - ret = clk_set_rate(mt9p031->clk, pdata->ext_freq); + ret = clk_set_rate(mt9p031->clk, mt9p031->ext_freq); if (ret < 0) return ret; @@ -245,7 +249,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) if (ext_freq > limits.ext_clock_max) { unsigned int div; - div = DIV_ROUND_UP(ext_freq, pdata->target_freq); + div = DIV_ROUND_UP(ext_freq, mt9p031->target_freq); div = roundup_pow_of_two(div) / 2; mt9p031->clk_div = min_t(unsigned int, div, 64); @@ -255,7 +259,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) } mt9p031->pll.ext_clock = ext_freq; - mt9p031->pll.pix_clock = pdata->target_freq; + mt9p031->pll.pix_clock = mt9p031->target_freq; mt9p031->use_pll = true; return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll); @@ -376,7 +380,7 @@ static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on) } /* Configure the pixel clock polarity */ - if (mt9p031->pdata && mt9p031->pdata->pixclk_pol) { + if (mt9p031->pixclk_pol) { ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL, MT9P031_PIXEL_CLOCK_INVERT); if (ret < 0) @@ -1057,53 +1061,41 @@ static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = { * Driver initialization and probing */ -static struct mt9p031_platform_data * -mt9p031_get_pdata(struct i2c_client *client) +static int mt9p031_parse_properties(struct mt9p031 *mt9p031, struct device *dev) { - struct mt9p031_platform_data *pdata = NULL; - struct device_node *np; struct v4l2_fwnode_endpoint endpoint = { .bus_type = V4L2_MBUS_PARALLEL }; + struct fwnode_handle *np; + int ret; - if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) - return client->dev.platform_data; - - np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); + np = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); if (!np) - return NULL; - - if (v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &endpoint) < 0) - goto done; + return dev_err_probe(dev, -EINVAL, "endpoint node not found\n"); - pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - goto done; + ret = v4l2_fwnode_endpoint_parse(np, &endpoint); + fwnode_handle_put(np); + if (ret) + return dev_err_probe(dev, -EINVAL, "could not parse endpoint\n"); - of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq); - of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq); + fwnode_property_read_u32(np, "input-clock-frequency", + &mt9p031->ext_freq); + fwnode_property_read_u32(np, "pixel-clock-frequency", + &mt9p031->target_freq); - pdata->pixclk_pol = !!(endpoint.bus.parallel.flags & - V4L2_MBUS_PCLK_SAMPLE_RISING); + mt9p031->pixclk_pol = !!(endpoint.bus.parallel.flags & + V4L2_MBUS_PCLK_SAMPLE_RISING); -done: - of_node_put(np); - return pdata; + return 0; } static int mt9p031_probe(struct i2c_client *client) { - struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client); struct i2c_adapter *adapter = client->adapter; struct mt9p031 *mt9p031; unsigned int i; int ret; - if (pdata == NULL) { - dev_err(&client->dev, "No platform data\n"); - return -EINVAL; - } - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { dev_warn(&client->dev, "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); @@ -1114,10 +1106,13 @@ static int mt9p031_probe(struct i2c_client *client) if (mt9p031 == NULL) return -ENOMEM; - mt9p031->pdata = pdata; + ret = mt9p031_parse_properties(mt9p031, &client->dev); + if (ret) + return ret; + mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF; mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC; - mt9p031->code = (uintptr_t)i2c_get_match_data(client); + mt9p031->code = (uintptr_t)device_get_match_data(&client->dev); mt9p031->regulators[0].supply = "vdd"; mt9p031->regulators[1].supply = "vdd_io"; @@ -1145,8 +1140,8 @@ static int mt9p031_probe(struct i2c_client *client) v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, - V4L2_CID_PIXEL_RATE, pdata->target_freq, - pdata->target_freq, 1, pdata->target_freq); + V4L2_CID_PIXEL_RATE, mt9p031->target_freq, + mt9p031->target_freq, 1, mt9p031->target_freq); v4l2_ctrl_new_std_menu_items(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, 0, @@ -1213,18 +1208,18 @@ static void mt9p031_remove(struct i2c_client *client) mutex_destroy(&mt9p031->power_lock); } -static const struct i2c_device_id mt9p031_id[] = { - { "mt9p006", MEDIA_BUS_FMT_SGRBG12_1X12 }, - { "mt9p031", MEDIA_BUS_FMT_SGRBG12_1X12 }, - { "mt9p031m", MEDIA_BUS_FMT_Y12_1X12 }, - { /* sentinel */ } +static const struct mt9p031_model_info mt9p031_models_bayer = { + .code = MEDIA_BUS_FMT_SGRBG12_1X12 +}; + +static const struct mt9p031_model_info mt9p031_models_mono = { + .code = MEDIA_BUS_FMT_Y12_1X12 }; -MODULE_DEVICE_TABLE(i2c, mt9p031_id); static const struct of_device_id mt9p031_of_match[] = { - { .compatible = "aptina,mt9p006", .data = (void *)MEDIA_BUS_FMT_SGRBG12_1X12 }, - { .compatible = "aptina,mt9p031", .data = (void *)MEDIA_BUS_FMT_SGRBG12_1X12 }, - { .compatible = "aptina,mt9p031m", .data = (void *)MEDIA_BUS_FMT_Y12_1X12 }, + { .compatible = "aptina,mt9p006", .data = &mt9p031_models_bayer }, + { .compatible = "aptina,mt9p031", .data = &mt9p031_models_bayer }, + { .compatible = "aptina,mt9p031m", .data = &mt9p031_models_mono }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mt9p031_of_match); @@ -1236,7 +1231,6 @@ static struct i2c_driver mt9p031_i2c_driver = { }, .probe = mt9p031_probe, .remove = mt9p031_remove, - .id_table = mt9p031_id, }; module_i2c_driver(mt9p031_i2c_driver); diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c index 0b9fb1ddbe5970..141cb6f75b5550 100644 --- a/drivers/media/i2c/ov01a10.c +++ b/drivers/media/i2c/ov01a10.c @@ -13,7 +13,6 @@ #include #include -#include #include #define OV01A10_LINK_FREQ_400MHZ 400000000ULL @@ -804,8 +803,6 @@ static int ov01a10_get_selection(struct v4l2_subdev *sd, static const struct v4l2_subdev_core_ops ov01a10_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops ov01a10_video_ops = { @@ -892,8 +889,7 @@ static int ov01a10_probe(struct i2c_client *client) } ov01a10->sd.state_lock = ov01a10->ctrl_handler.lock; - ov01a10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | - V4L2_SUBDEV_FL_HAS_EVENTS; + ov01a10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov01a10->sd.entity.ops = &ov01a10_subdev_entity_ops; ov01a10->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ov01a10->pad.flags = MEDIA_PAD_FL_SOURCE; diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index 7ead3c720e0e11..b9682264e2f53d 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -3,10 +3,13 @@ #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -1215,7 +1218,7 @@ static const char * const ov08x40_test_pattern_menu[] = { /* Configurations for supported link frequencies */ #define OV08X40_LINK_FREQ_400MHZ 400000000ULL #define OV08X40_SCLK_96MHZ 96000000ULL -#define OV08X40_EXT_CLK 19200000 +#define OV08X40_XVCLK 19200000 #define OV08X40_DATA_LANES 4 /* @@ -1279,6 +1282,12 @@ static const struct ov08x40_mode supported_modes[] = { }, }; +static const char * const ov08x40_supply_names[] = { + "dovdd", /* Digital I/O power */ + "avdd", /* Analog power */ + "dvdd", /* Digital core power */ +}; + struct ov08x40 { struct v4l2_subdev sd; struct media_pad pad; @@ -1291,6 +1300,10 @@ struct ov08x40 { struct v4l2_ctrl *hblank; struct v4l2_ctrl *exposure; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(ov08x40_supply_names)]; + /* Current mode */ const struct ov08x40_mode *cur_mode; @@ -1303,6 +1316,61 @@ struct ov08x40 { #define to_ov08x40(_sd) container_of(_sd, struct ov08x40, sd) +static int ov08x40_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov08x40 *ov08x = to_ov08x40(sd); + int ret; + + if (is_acpi_node(dev_fwnode(dev))) + return 0; + + ret = clk_prepare_enable(ov08x->xvclk); + if (ret < 0) { + dev_err(dev, "failed to enable xvclk\n"); + return ret; + } + + if (ov08x->reset_gpio) { + gpiod_set_value_cansleep(ov08x->reset_gpio, 1); + usleep_range(1000, 2000); + } + + ret = regulator_bulk_enable(ARRAY_SIZE(ov08x40_supply_names), + ov08x->supplies); + if (ret < 0) { + dev_err(dev, "failed to enable regulators\n"); + goto disable_clk; + } + + gpiod_set_value_cansleep(ov08x->reset_gpio, 0); + usleep_range(1500, 1800); + + return 0; + +disable_clk: + gpiod_set_value_cansleep(ov08x->reset_gpio, 1); + clk_disable_unprepare(ov08x->xvclk); + + return ret; +} + +static int ov08x40_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov08x40 *ov08x = to_ov08x40(sd); + + if (is_acpi_node(dev_fwnode(dev))) + return 0; + + gpiod_set_value_cansleep(ov08x->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ov08x40_supply_names), + ov08x->supplies); + clk_disable_unprepare(ov08x->xvclk); + + return 0; +} + /* Read registers up to 4 at a time */ static int ov08x40_read_reg(struct ov08x40 *ov08x, u16 reg, u32 len, u32 *val) @@ -1339,15 +1407,13 @@ static int ov08x40_read_reg(struct ov08x40 *ov08x, return 0; } -static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg, - u16 last_reg, u8 val) +static int __ov08x40_burst_fill_regs(struct i2c_client *client, u16 first_reg, + u16 last_reg, size_t num_regs, u8 val) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); struct i2c_msg msgs; - size_t i, num_regs; + size_t i; int ret; - num_regs = last_reg - first_reg + 1; msgs.addr = client->addr; msgs.flags = 0; msgs.len = 2 + num_regs; @@ -1373,6 +1439,31 @@ static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg, return 0; } +static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg, + u16 last_reg, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); + size_t num_regs, num_write_regs; + int ret; + + num_regs = last_reg - first_reg + 1; + num_write_regs = num_regs; + + if (client->adapter->quirks && client->adapter->quirks->max_write_len) + num_write_regs = client->adapter->quirks->max_write_len - 2; + + while (first_reg < last_reg) { + ret = __ov08x40_burst_fill_regs(client, first_reg, last_reg, + num_write_regs, val); + if (ret) + return ret; + + first_reg += num_write_regs; + } + + return 0; +} + /* Write registers up to 4 at a time */ static int ov08x40_write_reg(struct ov08x40 *ov08x, u16 reg, u32 len, u32 __val) @@ -2049,7 +2140,7 @@ static void ov08x40_free_controls(struct ov08x40 *ov08x) mutex_destroy(&ov08x->mutex); } -static int ov08x40_check_hwcfg(struct device *dev) +static int ov08x40_check_hwcfg(struct ov08x40 *ov08x, struct device *dev) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY @@ -2058,21 +2149,46 @@ static int ov08x40_check_hwcfg(struct device *dev) struct fwnode_handle *fwnode = dev_fwnode(dev); unsigned int i, j; int ret; - u32 ext_clk; + u32 xvclk_rate; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - return ret; + if (!is_acpi_node(fwnode)) { + ov08x->xvclk = devm_clk_get(dev, NULL); + if (IS_ERR(ov08x->xvclk)) { + dev_err(dev, "could not get xvclk clock (%pe)\n", + ov08x->xvclk); + return PTR_ERR(ov08x->xvclk); + } + + xvclk_rate = clk_get_rate(ov08x->xvclk); + + ov08x->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov08x->reset_gpio)) + return PTR_ERR(ov08x->reset_gpio); + + for (i = 0; i < ARRAY_SIZE(ov08x40_supply_names); i++) + ov08x->supplies[i].supply = ov08x40_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, + ARRAY_SIZE(ov08x40_supply_names), + ov08x->supplies); + if (ret) + return ret; + } else { + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &xvclk_rate); + if (ret) { + dev_err(dev, "can't get clock frequency"); + return ret; + } } - if (ext_clk != OV08X40_EXT_CLK) { + if (xvclk_rate != OV08X40_XVCLK) { dev_err(dev, "external clock %d is not supported", - ext_clk); + xvclk_rate); return -EINVAL; } @@ -2120,32 +2236,37 @@ static int ov08x40_check_hwcfg(struct device *dev) } static int ov08x40_probe(struct i2c_client *client) -{ - struct ov08x40 *ov08x; +{ struct ov08x40 *ov08x; int ret; bool full_power; + ov08x = devm_kzalloc(&client->dev, sizeof(*ov08x), GFP_KERNEL); + if (!ov08x) + return -ENOMEM; + /* Check HW config */ - ret = ov08x40_check_hwcfg(&client->dev); + ret = ov08x40_check_hwcfg(ov08x, &client->dev); if (ret) { dev_err(&client->dev, "failed to check hwcfg: %d", ret); return ret; } - ov08x = devm_kzalloc(&client->dev, sizeof(*ov08x), GFP_KERNEL); - if (!ov08x) - return -ENOMEM; - /* Initialize subdev */ v4l2_i2c_subdev_init(&ov08x->sd, client, &ov08x40_subdev_ops); full_power = acpi_dev_state_d0(&client->dev); if (full_power) { + ret = ov08x40_power_on(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to power on\n"); + return ret; + } + /* Check module identity */ ret = ov08x40_identify_module(ov08x); if (ret) { dev_err(&client->dev, "failed to find sensor: %d\n", ret); - return ret; + goto probe_power_off; } } @@ -2154,7 +2275,7 @@ static int ov08x40_probe(struct i2c_client *client) ret = ov08x40_init_controls(ov08x); if (ret) - return ret; + goto probe_power_off; /* Initialize subdev */ ov08x->sd.internal_ops = &ov08x40_internal_ops; @@ -2187,6 +2308,9 @@ static int ov08x40_probe(struct i2c_client *client) error_handler_free: ov08x40_free_controls(ov08x); +probe_power_off: + ov08x40_power_off(&client->dev); + return ret; } @@ -2201,6 +2325,8 @@ static void ov08x40_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); pm_runtime_set_suspended(&client->dev); + + ov08x40_power_off(&client->dev); } #ifdef CONFIG_ACPI @@ -2212,10 +2338,17 @@ static const struct acpi_device_id ov08x40_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, ov08x40_acpi_ids); #endif +static const struct of_device_id ov08x40_of_match[] = { + { .compatible = "ovti,ov08x40" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov08x40_of_match); + static struct i2c_driver ov08x40_i2c_driver = { .driver = { .name = "ov08x40", .acpi_match_table = ACPI_PTR(ov08x40_acpi_ids), + .of_match_table = ov08x40_of_match, }, .probe = ov08x40_probe, .remove = ov08x40_remove, diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index bd0b2f0f0d45b9..c484b753a718c3 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -530,7 +530,7 @@ struct ov2740 { /* Current mode */ const struct ov2740_mode *cur_mode; - /* NVM data inforamtion */ + /* NVM data information */ struct nvm_data *nvm; /* Supported modes */ @@ -1132,7 +1132,8 @@ static int ov2740_check_hwcfg(struct device *dev) */ ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) - return -EPROBE_DEFER; + return dev_err_probe(dev, -EPROBE_DEFER, + "waiting for fwnode graph endpoint\n"); ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); if (ret) { @@ -1330,7 +1331,7 @@ static int ov2740_probe(struct i2c_client *client) ret = ov2740_check_hwcfg(dev); if (ret) - return dev_err_probe(dev, ret, "failed to check HW configuration\n"); + return ret; ov2740->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ov2740->reset_gpio)) { diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index c1d3fce4a7d383..da5cb5f45a4ff5 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -377,7 +377,7 @@ struct reg_value { struct ov5640_timings { /* Analog crop rectangle. */ struct v4l2_rect analog_crop; - /* Visibile crop: from analog crop top-left corner. */ + /* Visible crop: from analog crop top-left corner. */ struct v4l2_rect crop; /* Total pixels per line: width + fixed hblank. */ u32 htot; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 0c32bd2940ecf0..004d0ee5c3f576 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -88,7 +88,6 @@ struct ov5645 { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_fwnode_endpoint ep; - struct v4l2_mbus_framefmt fmt; struct v4l2_rect crop; struct clk *xclk; @@ -105,8 +104,6 @@ struct ov5645 { u8 timing_tc_reg20; u8 timing_tc_reg21; - struct mutex power_lock; /* lock to protect power state */ - struct gpio_desc *enable_gpio; struct gpio_desc *rst_gpio; }; @@ -781,11 +778,8 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) struct ov5645, ctrls); int ret; - mutex_lock(&ov5645->power_lock); - if (!pm_runtime_get_if_in_use(ov5645->dev)) { - mutex_unlock(&ov5645->power_lock); + if (!pm_runtime_get_if_in_use(ov5645->dev)) return 0; - } switch (ctrl->id) { case V4L2_CID_SATURATION: @@ -816,7 +810,6 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); - mutex_unlock(&ov5645->power_lock); return ret; } @@ -855,49 +848,6 @@ static int ov5645_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static struct v4l2_mbus_framefmt * -__ov5645_get_pad_format(struct ov5645 *ov5645, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - switch (which) { - case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_state_get_format(sd_state, pad); - case V4L2_SUBDEV_FORMAT_ACTIVE: - return &ov5645->fmt; - default: - return NULL; - } -} - -static int ov5645_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct ov5645 *ov5645 = to_ov5645(sd); - - format->format = *__ov5645_get_pad_format(ov5645, sd_state, - format->pad, - format->which); - return 0; -} - -static struct v4l2_rect * -__ov5645_get_pad_crop(struct ov5645 *ov5645, - struct v4l2_subdev_state *sd_state, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - switch (which) { - case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_state_get_crop(sd_state, pad); - case V4L2_SUBDEV_FORMAT_ACTIVE: - return &ov5645->crop; - default: - return NULL; - } -} - static int ov5645_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) @@ -908,33 +858,30 @@ static int ov5645_set_format(struct v4l2_subdev *sd, const struct ov5645_mode_info *new_mode; int ret; - __crop = __ov5645_get_pad_crop(ov5645, sd_state, format->pad, - format->which); - + __crop = v4l2_subdev_state_get_crop(sd_state, 0); new_mode = v4l2_find_nearest_size(ov5645_mode_info_data, - ARRAY_SIZE(ov5645_mode_info_data), - width, height, - format->format.width, format->format.height); + ARRAY_SIZE(ov5645_mode_info_data), + width, height, format->format.width, + format->format.height); __crop->width = new_mode->width; __crop->height = new_mode->height; if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - ret = v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock, - new_mode->pixel_clock); + ret = __v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock, + new_mode->pixel_clock); if (ret < 0) return ret; - ret = v4l2_ctrl_s_ctrl(ov5645->link_freq, - new_mode->link_freq); + ret = __v4l2_ctrl_s_ctrl(ov5645->link_freq, + new_mode->link_freq); if (ret < 0) return ret; ov5645->current_mode = new_mode; } - __format = __ov5645_get_pad_format(ov5645, sd_state, format->pad, - format->which); + __format = v4l2_subdev_state_get_format(sd_state, 0); __format->width = __crop->width; __format->height = __crop->height; __format->code = MEDIA_BUS_FMT_UYVY8_1X16; @@ -949,11 +896,15 @@ static int ov5645_set_format(struct v4l2_subdev *sd, static int ov5645_init_state(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - struct v4l2_subdev_format fmt = { 0 }; - - fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt.format.width = 1920; - fmt.format.height = 1080; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .pad = 0, + .format = { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .width = ov5645_mode_info_data[1].width, + .height = ov5645_mode_info_data[1].height, + }, + }; ov5645_set_format(subdev, sd_state, &fmt); @@ -964,82 +915,88 @@ static int ov5645_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct ov5645 *ov5645 = to_ov5645(sd); - if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - sel->r = *__ov5645_get_pad_crop(ov5645, sd_state, sel->pad, - sel->which); + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); return 0; } -static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable) +static int ov5645_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { - struct ov5645 *ov5645 = to_ov5645(subdev); + struct ov5645 *ov5645 = to_ov5645(sd); int ret; - if (enable) { - ret = pm_runtime_resume_and_get(ov5645->dev); - if (ret < 0) - return ret; + ret = pm_runtime_resume_and_get(ov5645->dev); + if (ret < 0) + return ret; - ret = ov5645_set_register_array(ov5645, + ret = ov5645_set_register_array(ov5645, ov5645->current_mode->data, ov5645->current_mode->data_size); - if (ret < 0) { - dev_err(ov5645->dev, "could not set mode %dx%d\n", - ov5645->current_mode->width, - ov5645->current_mode->height); - goto err_rpm_put; - } - ret = v4l2_ctrl_handler_setup(&ov5645->ctrls); - if (ret < 0) { - dev_err(ov5645->dev, "could not sync v4l2 controls\n"); - goto err_rpm_put; - } - - ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45); - if (ret < 0) - goto err_rpm_put; - - ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, - OV5645_SYSTEM_CTRL0_START); - if (ret < 0) - goto err_rpm_put; - } else { - ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40); - if (ret < 0) - goto stream_off_rpm_put; + if (ret < 0) { + dev_err(ov5645->dev, "could not set mode %dx%d\n", + ov5645->current_mode->width, + ov5645->current_mode->height); + goto err_rpm_put; + } + ret = __v4l2_ctrl_handler_setup(&ov5645->ctrls); + if (ret < 0) { + dev_err(ov5645->dev, "could not sync v4l2 controls\n"); + goto err_rpm_put; + } - ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, - OV5645_SYSTEM_CTRL0_STOP); + ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45); + if (ret < 0) + goto err_rpm_put; - goto stream_off_rpm_put; - } + ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, + OV5645_SYSTEM_CTRL0_START); + if (ret < 0) + goto err_rpm_put; return 0; err_rpm_put: pm_runtime_put_sync(ov5645->dev); return ret; +} + +static int ov5645_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ov5645 *ov5645 = to_ov5645(sd); + int ret; + + ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40); + if (ret < 0) + goto rpm_put; -stream_off_rpm_put: + ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, + OV5645_SYSTEM_CTRL0_STOP); + +rpm_put: pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); + return ret; } static const struct v4l2_subdev_video_ops ov5645_video_ops = { - .s_stream = ov5645_s_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = { .enum_mbus_code = ov5645_enum_mbus_code, .enum_frame_size = ov5645_enum_frame_size, - .get_fmt = ov5645_get_format, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ov5645_set_format, .get_selection = ov5645_get_selection, + .enable_streams = ov5645_enable_streams, + .disable_streams = ov5645_disable_streams, }; static const struct v4l2_subdev_ops ov5645_subdev_ops = { @@ -1069,51 +1026,44 @@ static int ov5645_probe(struct i2c_client *client) ov5645->dev = dev; endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1); - if (!endpoint) { - dev_err(dev, "endpoint node not found\n"); - return -EINVAL; - } + if (!endpoint) + return dev_err_probe(dev, -EINVAL, + "endpoint node not found\n"); ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint), &ov5645->ep); of_node_put(endpoint); - if (ret < 0) { - dev_err(dev, "parsing endpoint node failed\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, + "parsing endpoint node failed\n"); - if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) { - dev_err(dev, "invalid bus type, must be CSI2\n"); - return -EINVAL; - } + if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) + return dev_err_probe(dev, -EINVAL, + "invalid bus type, must be CSI2\n"); /* get system clock (xclk) */ ov5645->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(ov5645->xclk)) { - dev_err(dev, "could not get xclk"); - return PTR_ERR(ov5645->xclk); - } + if (IS_ERR(ov5645->xclk)) + return dev_err_probe(dev, PTR_ERR(ov5645->xclk), + "could not get xclk"); ret = of_property_read_u32(dev->of_node, "clock-frequency", &xclk_freq); - if (ret) { - dev_err(dev, "could not get xclk frequency\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "could not get xclk frequency\n"); /* external clock must be 24MHz, allow 1% tolerance */ - if (xclk_freq < 23760000 || xclk_freq > 24240000) { - dev_err(dev, "external clock frequency %u is not supported\n", - xclk_freq); - return -EINVAL; - } + if (xclk_freq < 23760000 || xclk_freq > 24240000) + return dev_err_probe(dev, -EINVAL, + "unsupported xclk frequency %u\n", + xclk_freq); ret = clk_set_rate(ov5645->xclk, xclk_freq); - if (ret) { - dev_err(dev, "could not set xclk frequency\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, + "could not set xclk frequency\n"); for (i = 0; i < OV5645_NUM_SUPPLIES; i++) ov5645->supplies[i].supply = ov5645_supply_name[i]; @@ -1124,18 +1074,14 @@ static int ov5645_probe(struct i2c_client *client) return ret; ov5645->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); - if (IS_ERR(ov5645->enable_gpio)) { - dev_err(dev, "cannot get enable gpio\n"); - return PTR_ERR(ov5645->enable_gpio); - } + if (IS_ERR(ov5645->enable_gpio)) + return dev_err_probe(dev, PTR_ERR(ov5645->enable_gpio), + "cannot get enable gpio\n"); ov5645->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(ov5645->rst_gpio)) { - dev_err(dev, "cannot get reset gpio\n"); - return PTR_ERR(ov5645->rst_gpio); - } - - mutex_init(&ov5645->power_lock); + if (IS_ERR(ov5645->rst_gpio)) + return dev_err_probe(dev, PTR_ERR(ov5645->rst_gpio), + "cannot get reset gpio\n"); v4l2_ctrl_handler_init(&ov5645->ctrls, 9); v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, @@ -1170,9 +1116,8 @@ static int ov5645_probe(struct i2c_client *client) ov5645->sd.ctrl_handler = &ov5645->ctrls; if (ov5645->ctrls.error) { - dev_err(dev, "%s: control initialization error %d\n", - __func__, ov5645->ctrls.error); ret = ov5645->ctrls.error; + dev_err_probe(dev, ret, "failed to add controls\n"); goto free_ctrl; } @@ -1180,12 +1125,12 @@ static int ov5645_probe(struct i2c_client *client) ov5645->sd.internal_ops = &ov5645_internal_ops; ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov5645->pad.flags = MEDIA_PAD_FL_SOURCE; - ov5645->sd.dev = &client->dev; + ov5645->sd.dev = dev; ov5645->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&ov5645->sd.entity, 1, &ov5645->pad); if (ret < 0) { - dev_err(dev, "could not register media entity\n"); + dev_err_probe(dev, ret, "could not register media entity\n"); goto free_ctrl; } @@ -1195,14 +1140,14 @@ static int ov5645_probe(struct i2c_client *client) ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH, &chip_id_high); if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH_BYTE) { - dev_err(dev, "could not read ID high\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read ID high\n"); goto power_down; } ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_LOW, &chip_id_low); if (ret < 0 || chip_id_low != OV5645_CHIP_ID_LOW_BYTE) { - dev_err(dev, "could not read ID low\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read ID low\n"); goto power_down; } @@ -1211,24 +1156,31 @@ static int ov5645_probe(struct i2c_client *client) ret = ov5645_read_reg(ov5645, OV5645_AEC_PK_MANUAL, &ov5645->aec_pk_manual); if (ret < 0) { - dev_err(dev, "could not read AEC/AGC mode\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read AEC/AGC mode\n"); goto power_down; } ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG20, &ov5645->timing_tc_reg20); if (ret < 0) { - dev_err(dev, "could not read vflip value\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read vflip value\n"); goto power_down; } ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21, &ov5645->timing_tc_reg21); if (ret < 0) { - dev_err(dev, "could not read hflip value\n"); ret = -ENODEV; + dev_err_probe(dev, ret, "could not read hflip value\n"); + goto power_down; + } + + ov5645->sd.state_lock = ov5645->ctrls.lock; + ret = v4l2_subdev_init_finalize(&ov5645->sd); + if (ret < 0) { + dev_err_probe(dev, ret, "subdev init error\n"); goto power_down; } @@ -1236,11 +1188,9 @@ static int ov5645_probe(struct i2c_client *client) pm_runtime_get_noresume(dev); pm_runtime_enable(dev); - ov5645_init_state(&ov5645->sd, NULL); - - ret = v4l2_async_register_subdev(&ov5645->sd); + ret = v4l2_async_register_subdev_sensor(&ov5645->sd); if (ret < 0) { - dev_err(dev, "could not register v4l2 device\n"); + dev_err_probe(dev, ret, "could not register v4l2 device\n"); goto err_pm_runtime; } @@ -1254,13 +1204,13 @@ static int ov5645_probe(struct i2c_client *client) err_pm_runtime: pm_runtime_disable(dev); pm_runtime_put_noidle(dev); + v4l2_subdev_cleanup(&ov5645->sd); power_down: ov5645_set_power_off(dev); free_entity: media_entity_cleanup(&ov5645->sd.entity); free_ctrl: v4l2_ctrl_handler_free(&ov5645->ctrls); - mutex_destroy(&ov5645->power_lock); return ret; } @@ -1271,13 +1221,13 @@ static void ov5645_remove(struct i2c_client *client) struct ov5645 *ov5645 = to_ov5645(sd); v4l2_async_unregister_subdev(&ov5645->sd); + v4l2_subdev_cleanup(sd); media_entity_cleanup(&ov5645->sd.entity); v4l2_ctrl_handler_free(&ov5645->ctrls); pm_runtime_disable(ov5645->dev); if (!pm_runtime_status_suspended(ov5645->dev)) ov5645_set_power_off(ov5645->dev); pm_runtime_set_suspended(ov5645->dev); - mutex_destroy(&ov5645->power_lock); } static const struct i2c_device_id ov5645_id[] = { diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index f051045d340f23..c54bbc2071899d 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1879,7 +1879,7 @@ struct ov5670 { struct gpio_desc *pwdn_gpio; /* PWDNB pin. */ struct gpio_desc *reset_gpio; /* XSHUTDOWN pin. */ - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; /* True if the device has been identified */ diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index 2833b14ee139dc..c1081deffc2f99 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -510,7 +510,7 @@ struct ov5675 { /* Current mode */ const struct ov5675_mode *cur_mode; - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; /* True if the device has been identified */ @@ -732,7 +732,7 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_EXPOSURE: /* 4 least significant bits of expsoure are fractional part * val = val << 4 - * for ov5675, the unit of exposure is differnt from other + * for ov5675, the unit of exposure is different from other * OmniVision sensors, its exposure value is twice of the * register value, the exposure should be divided by 2 before * set register, e.g. val << 3. diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c index 541bf74581d2ab..a5da4fe47e0b09 100644 --- a/drivers/media/i2c/ov64a40.c +++ b/drivers/media/i2c/ov64a40.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -3200,13 +3199,7 @@ static const struct v4l2_subdev_pad_ops ov64a40_pad_ops = { .get_selection = ov64a40_get_selection, }; -static const struct v4l2_subdev_core_ops ov64a40_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_ops ov64a40_subdev_ops = { - .core = &ov64a40_core_ops, .video = &ov64a40_video_ops, .pad = &ov64a40_pad_ops, }; @@ -3605,8 +3598,7 @@ static int ov64a40_probe(struct i2c_client *client) /* Initialize subdev */ ov64a40->sd.internal_ops = &ov64a40_internal_ops; - ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE - | V4L2_SUBDEV_FL_HAS_EVENTS; + ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ov64a40->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ov64a40->pad.flags = MEDIA_PAD_FL_SOURCE; diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c index 3b0fdb3c70c0b3..062e1023a411ea 100644 --- a/drivers/media/i2c/ov772x.c +++ b/drivers/media/i2c/ov772x.c @@ -269,7 +269,7 @@ #define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */ #define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */ /* AEC max step control */ -#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */ +#define AEC_NO_LIMIT 0x01 /* 0 : AEC increase step has limit */ /* 1 : No limit to AEC increase step */ /* CLKRC */ /* Input clock divider register */ diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 0830676e5d5a40..1f1c0de8e510d2 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -117,7 +117,7 @@ struct ov7740 { struct v4l2_ctrl *brightness; struct v4l2_ctrl *contrast; - struct mutex mutex; /* To serialize asynchronus callbacks */ + struct mutex mutex; /* To serialize asynchronous callbacks */ struct gpio_desc *resetb_gpio; struct gpio_desc *pwdn_gpio; diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 3b94338f55ed39..e6704d01824815 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1435,7 +1435,7 @@ struct ov8856 { /* Application specified mbus format */ u32 cur_mbus_index; - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; /* lanes index */ diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c index 326f50a5ab51ff..95f9ae7948463e 100644 --- a/drivers/media/i2c/ov8858.c +++ b/drivers/media/i2c/ov8858.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -1500,13 +1499,7 @@ static const struct v4l2_subdev_pad_ops ov8858_pad_ops = { .set_fmt = ov8858_set_fmt, }; -static const struct v4l2_subdev_core_ops ov8858_core_ops = { - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - static const struct v4l2_subdev_ops ov8858_subdev_ops = { - .core = &ov8858_core_ops, .video = &ov8858_video_ops, .pad = &ov8858_pad_ops, }; @@ -1917,7 +1910,7 @@ static int ov8858_probe(struct i2c_client *client) return ret; sd = &ov8858->subdev; - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ov8858->pad.flags = MEDIA_PAD_FL_SOURCE; sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad); diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 56df97c9886b51..026ea34d62914c 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -286,7 +286,7 @@ static const struct i2c_rv ov965x_init_regs[] = { { REG_COM5, 0x00 }, /* System clock options */ { REG_COM2, 0x01 }, /* Output drive, soft sleep mode */ { REG_COM10, 0x00 }, /* Slave mode, HREF vs HSYNC, signals negate */ - { REG_EDGE, 0xa6 }, /* Edge enhancement treshhold and factor */ + { REG_EDGE, 0xa6 }, /* Edge enhancement threshold and factor */ { REG_COM16, 0x02 }, /* Color matrix coeff double option */ { REG_COM17, 0x08 }, /* Single frame out, banding filter */ { 0x16, 0x06 }, diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index bf9e2adbff3473..cae3aeefb61630 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -335,7 +335,7 @@ struct ov9734 { /* Current mode */ const struct ov9734_mode *cur_mode; - /* To serialize asynchronus callbacks */ + /* To serialize asynchronous callbacks */ struct mutex mutex; }; diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index b947a55281f0e4..f08db3cfe076b8 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -67,9 +68,6 @@ static const u32 mipid02_supported_fmt_codes[] = { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16, MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR888_1X24, - MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, - MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_JPEG_1X8 }; @@ -100,6 +98,7 @@ struct mipid02_dev { /* remote source */ struct v4l2_async_notifier notifier; struct v4l2_subdev *s_subdev; + u16 s_subdev_pad_id; /* registers */ struct { u8 clk_lane_reg1; @@ -138,12 +137,6 @@ static int bpp_from_code(__u32 code) case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_VYUY8_1X16: case MEDIA_BUS_FMT_RGB565_1X16: - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - case MEDIA_BUS_FMT_RGB565_2X8_BE: return 16; case MEDIA_BUS_FMT_BGR888_1X24: return 24; @@ -175,16 +168,10 @@ static u8 data_type_from_code(__u32 code) case MEDIA_BUS_FMT_YVYU8_1X16: case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_VYUY8_1X16: - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: return MIPI_CSI2_DT_YUV422_8B; case MEDIA_BUS_FMT_BGR888_1X24: return MIPI_CSI2_DT_RGB888; case MEDIA_BUS_FMT_RGB565_1X16: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - case MEDIA_BUS_FMT_RGB565_2X8_BE: return MIPI_CSI2_DT_RGB565; default: return 0; @@ -248,8 +235,10 @@ static void mipid02_apply_reset(struct mipid02_dev *bridge) usleep_range(5000, 10000); } -static int mipid02_set_power_on(struct mipid02_dev *bridge) +static int mipid02_set_power_on(struct device *dev) { + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct mipid02_dev *bridge = to_mipid02_dev(sd); struct i2c_client *client = bridge->i2c_client; int ret; @@ -282,10 +271,15 @@ static int mipid02_set_power_on(struct mipid02_dev *bridge) return ret; } -static void mipid02_set_power_off(struct mipid02_dev *bridge) +static int mipid02_set_power_off(struct device *dev) { + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct mipid02_dev *bridge = to_mipid02_dev(sd); + regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies); clk_disable_unprepare(bridge->xclk); + + return 0; } static int mipid02_detect(struct mipid02_dev *bridge) @@ -447,15 +441,19 @@ static int mipid02_configure_from_code(struct mipid02_dev *bridge, return 0; } -static int mipid02_stream_disable(struct mipid02_dev *bridge) +static int mipid02_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct mipid02_dev *bridge = to_mipid02_dev(sd); struct i2c_client *client = bridge->i2c_client; int ret = -EINVAL; if (!bridge->s_subdev) goto error; - ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 0); + ret = v4l2_subdev_disable_streams(bridge->s_subdev, + bridge->s_subdev_pad_id, BIT(0)); if (ret) goto error; @@ -465,6 +463,10 @@ static int mipid02_stream_disable(struct mipid02_dev *bridge) cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret); if (ret) goto error; + + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + error: if (ret) dev_err(&client->dev, "failed to stream off %d", ret); @@ -472,33 +474,36 @@ static int mipid02_stream_disable(struct mipid02_dev *bridge) return ret; } -static int mipid02_stream_enable(struct mipid02_dev *bridge) +static int mipid02_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct mipid02_dev *bridge = to_mipid02_dev(sd); struct i2c_client *client = bridge->i2c_client; - struct v4l2_subdev_state *state; struct v4l2_mbus_framefmt *fmt; int ret = -EINVAL; if (!bridge->s_subdev) - goto error; + return ret; memset(&bridge->r, 0, sizeof(bridge->r)); - state = v4l2_subdev_lock_and_get_active_state(&bridge->sd); fmt = v4l2_subdev_state_get_format(state, MIPID02_SINK_0); /* build registers content */ ret = mipid02_configure_from_rx(bridge, fmt); if (ret) - goto error; + return ret; ret = mipid02_configure_from_tx(bridge); if (ret) - goto error; + return ret; ret = mipid02_configure_from_code(bridge, fmt); if (ret) - goto error; + return ret; - v4l2_subdev_unlock_state(state); + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) + return ret; /* write mipi registers */ cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, @@ -524,33 +529,20 @@ static int mipid02_stream_enable(struct mipid02_dev *bridge) if (ret) goto error; - ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 1); + ret = v4l2_subdev_enable_streams(bridge->s_subdev, + bridge->s_subdev_pad_id, BIT(0)); if (ret) goto error; return 0; error: - dev_err(&client->dev, "failed to stream on %d", ret); - mipid02_stream_disable(bridge); - - return ret; -} - -static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct mipid02_dev *bridge = to_mipid02_dev(sd); - struct i2c_client *client = bridge->i2c_client; - int ret = 0; - - dev_dbg(&client->dev, "%s : requested %d\n", __func__, enable); - - ret = enable ? mipid02_stream_enable(bridge) : - mipid02_stream_disable(bridge); - if (ret) - dev_err(&client->dev, "failed to stream %s (%d)\n", - enable ? "enable" : "disable", ret); + cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, 0, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1, 0, &ret); + cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret); + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); return ret; } @@ -640,13 +632,15 @@ static int mipid02_set_fmt(struct v4l2_subdev *sd, } static const struct v4l2_subdev_video_ops mipid02_video_ops = { - .s_stream = mipid02_s_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { .enum_mbus_code = mipid02_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mipid02_set_fmt, + .enable_streams = mipid02_enable_streams, + .disable_streams = mipid02_disable_streams, }; static const struct v4l2_subdev_ops mipid02_subdev_ops = { @@ -692,6 +686,7 @@ static int mipid02_async_bound(struct v4l2_async_notifier *notifier, } bridge->s_subdev = s_subdev; + bridge->s_subdev_pad_id = source_pad; return 0; } @@ -875,7 +870,7 @@ static int mipid02_probe(struct i2c_client *client) } /* enable clock, power and reset device if available */ - ret = mipid02_set_power_on(bridge); + ret = mipid02_set_power_on(&client->dev); if (ret) goto entity_cleanup; @@ -897,6 +892,15 @@ static int mipid02_probe(struct i2c_client *client) goto power_off; } + /* Enable runtime PM and turn off the device */ + pm_runtime_set_active(dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(dev); + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + ret = v4l2_async_register_subdev(&bridge->sd); if (ret < 0) { dev_err(&client->dev, "v4l2_async_register_subdev failed %d", @@ -911,8 +915,10 @@ static int mipid02_probe(struct i2c_client *client) unregister_notifier: v4l2_async_nf_unregister(&bridge->notifier); v4l2_async_nf_cleanup(&bridge->notifier); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); power_off: - mipid02_set_power_off(bridge); + mipid02_set_power_off(&client->dev); entity_cleanup: media_entity_cleanup(&bridge->sd.entity); @@ -927,7 +933,11 @@ static void mipid02_remove(struct i2c_client *client) v4l2_async_nf_unregister(&bridge->notifier); v4l2_async_nf_cleanup(&bridge->notifier); v4l2_async_unregister_subdev(&bridge->sd); - mipid02_set_power_off(bridge); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + mipid02_set_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); media_entity_cleanup(&bridge->sd.entity); } @@ -937,10 +947,15 @@ static const struct of_device_id mipid02_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mipid02_dt_ids); +static const struct dev_pm_ops mipid02_pm_ops = { + RUNTIME_PM_OPS(mipid02_set_power_off, mipid02_set_power_on, NULL) +}; + static struct i2c_driver mipid02_i2c_driver = { .driver = { .name = "st-mipid02", .of_match_table = mipid02_dt_ids, + .pm = pm_ptr(&mipid02_pm_ops), }, .probe = mipid02_probe, .remove = mipid02_remove, diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 65d58ddf02870d..c50d4e85dfd144 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -87,6 +87,10 @@ struct tc358743_state { struct timer_list timer; struct work_struct work_i2c_poll; + /* debugfs */ + struct dentry *debugfs_dir; + struct v4l2_debugfs_if *infoframes; + /* edid */ u8 edid_blocks_written; @@ -430,12 +434,35 @@ static void tc358743_erase_bksv(struct v4l2_subdev *sd) /* --------------- AVI infoframe --------------- */ +static ssize_t +tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp, + char __user *ubuf, size_t count, loff_t *ppos) +{ + u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + struct v4l2_subdev *sd = priv; + int len; + + if (!is_hdmi(sd)) + return 0; + + if (type != V4L2_DEBUGFS_IF_AVI) + return 0; + + i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1); + len = buf[2] + 4; + if (len > V4L2_DEBUGFS_IF_MAX_LEN) + len = -ENOENT; + if (len > 0) + len = simple_read_from_buffer(ubuf, count, ppos, buf, len); + return len < 0 ? 0 : len; +} + static void print_avi_infoframe(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct device *dev = &client->dev; union hdmi_infoframe frame; - u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; + u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {}; if (!is_hdmi(sd)) { v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); @@ -2161,6 +2188,11 @@ static int tc358743_probe(struct i2c_client *client) if (err < 0) goto err_work_queues; + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); + state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, + V4L2_DEBUGFS_IF_AVI, sd, + tc358743_debugfs_if_read); + v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); @@ -2168,8 +2200,10 @@ static int tc358743_probe(struct i2c_client *client) err_work_queues: cec_unregister_adapter(state->cec_adap); - if (!state->i2c_client->irq) + if (!state->i2c_client->irq) { + del_timer(&state->timer); flush_work(&state->work_i2c_poll); + } cancel_delayed_work(&state->delayed_work_enable_hotplug); mutex_destroy(&state->confctl_mutex); err_hdl: @@ -2188,6 +2222,8 @@ static void tc358743_remove(struct i2c_client *client) flush_work(&state->work_i2c_poll); } cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); + v4l2_debugfs_if_free(state->infoframes); + debugfs_remove_recursive(state->debugfs_dir); cec_unregister_adapter(state->cec_adap); v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c index c77440ff098cde..8852c56431fe3f 100644 --- a/drivers/media/i2c/thp7312.c +++ b/drivers/media/i2c/thp7312.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -879,8 +878,6 @@ static int thp7312_init_state(struct v4l2_subdev *sd, static const struct v4l2_subdev_core_ops thp7312_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops thp7312_video_ops = { @@ -2127,7 +2124,7 @@ static int thp7312_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&thp7312->sd, client, &thp7312_subdev_ops); thp7312->sd.internal_ops = &thp7312_internal_ops; - thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; thp7312->pad.flags = MEDIA_PAD_FL_SOURCE; thp7312->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index 7526fabc7ee413..b7cedc5b3e8ef4 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -7,7 +7,7 @@ * Author: Chaithrika U S * * Contributors: - * Hans Verkuil + * Hans Verkuil * Lad, Prabhakar * Martin Bugge * diff --git a/drivers/media/i2c/vgxy61.c b/drivers/media/i2c/vgxy61.c index 409d2d4ffb4bb2..d77468c8587bc4 100644 --- a/drivers/media/i2c/vgxy61.c +++ b/drivers/media/i2c/vgxy61.c @@ -1617,7 +1617,7 @@ static int vgxy61_detect(struct vgxy61_dev *sensor) ret = cci_read(sensor->regmap, VGXY61_REG_NVM, &st, NULL); if (ret < 0) - return st; + return ret; if (st != VGXY61_NVM_OK) dev_warn(&client->dev, "Bad nvm state got %u\n", (u8)st); diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 56dbe07a1c9986..036a6375627a95 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -566,8 +566,6 @@ static const struct vb2_ops video_i2c_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int video_i2c_querycap(struct file *file, void *priv, @@ -798,13 +796,13 @@ static int video_i2c_probe(struct i2c_client *client) queue->min_queued_buffers = 1; queue->ops = &video_i2c_video_qops; queue->mem_ops = &vb2_vmalloc_memops; + queue->lock = &data->queue_lock; ret = vb2_queue_init(queue); if (ret < 0) goto error_unregister_device; data->vdev.queue = queue; - data->vdev.queue->lock = &data->queue_lock; snprintf(data->vdev.name, sizeof(data->vdev.name), "I2C %d-%d Transport Video", diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 96dd0f6ccd0d0a..04559090558205 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -768,10 +768,10 @@ static int media_pipeline_populate(struct media_pipeline *pipe, return ret; } -__must_check int __media_pipeline_start(struct media_pad *pad, +__must_check int __media_pipeline_start(struct media_pad *origin, struct media_pipeline *pipe) { - struct media_device *mdev = pad->graph_obj.mdev; + struct media_device *mdev = origin->graph_obj.mdev; struct media_pipeline_pad *err_ppad; struct media_pipeline_pad *ppad; int ret; @@ -782,7 +782,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad, * If the pad is already part of a pipeline, that pipeline must be the * same as the pipe given to media_pipeline_start(). */ - if (WARN_ON(pad->pipe && pad->pipe != pipe)) + if (WARN_ON(origin->pipe && origin->pipe != pipe)) return -EINVAL; /* @@ -799,7 +799,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad, * with media_pipeline_pad instances for each pad found during graph * walk. */ - ret = media_pipeline_populate(pipe, pad); + ret = media_pipeline_populate(pipe, origin); if (ret) return ret; @@ -914,14 +914,14 @@ __must_check int __media_pipeline_start(struct media_pad *pad, } EXPORT_SYMBOL_GPL(__media_pipeline_start); -__must_check int media_pipeline_start(struct media_pad *pad, +__must_check int media_pipeline_start(struct media_pad *origin, struct media_pipeline *pipe) { - struct media_device *mdev = pad->graph_obj.mdev; + struct media_device *mdev = origin->graph_obj.mdev; int ret; mutex_lock(&mdev->graph_mutex); - ret = __media_pipeline_start(pad, pipe); + ret = __media_pipeline_start(origin, pipe); mutex_unlock(&mdev->graph_mutex); return ret; } diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c index e064914c476e7c..5edfc2791ce7c7 100644 --- a/drivers/media/mc/mc-request.c +++ b/drivers/media/mc/mc-request.c @@ -6,7 +6,7 @@ * Copyright (C) 2018 Intel Corporation * Copyright (C) 2018 Google, Inc. * - * Author: Hans Verkuil + * Author: Hans Verkuil * Author: Sakari Ailus */ @@ -246,22 +246,21 @@ static const struct file_operations request_fops = { struct media_request * media_request_get_by_fd(struct media_device *mdev, int request_fd) { - struct fd f; struct media_request *req; if (!mdev || !mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue) return ERR_PTR(-EBADR); - f = fdget(request_fd); - if (!fd_file(f)) - goto err_no_req_fd; + CLASS(fd, f)(request_fd); + if (fd_empty(f)) + goto err; if (fd_file(f)->f_op != &request_fops) - goto err_fput; + goto err; req = fd_file(f)->private_data; if (req->mdev != mdev) - goto err_fput; + goto err; /* * Note: as long as someone has an open filehandle of the request, @@ -272,14 +271,9 @@ media_request_get_by_fd(struct media_device *mdev, int request_fd) * before media_request_get() is called. */ media_request_get(req); - fdput(f); - return req; -err_fput: - fdput(f); - -err_no_req_fd: +err: dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd); return ERR_PTR(-EINVAL); } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 511f013cc33873..2782832f5eb8f2 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1584,8 +1584,6 @@ static const struct vb2_ops bttv_video_qops = { .buf_cleanup = buf_cleanup, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static void radio_enable(struct bttv *btv) diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c index e489a3acb4b98a..a71440611e46ec 100644 --- a/drivers/media/pci/bt8xx/bttv-vbi.c +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -170,8 +170,6 @@ const struct vb2_ops bttv_vbi_qops = { .buf_cleanup = buf_cleanup_vbi, .start_streaming = start_streaming_vbi, .stop_streaming = stop_streaming_vbi, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 6e1a0614e6d069..39e25cc53edb97 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -44,7 +44,7 @@ module_param_named(ignore_err, cobalt_ignore_err, int, 0644); MODULE_PARM_DESC(ignore_err, "If set then ignore missing i2c adapters/receivers. Default: 0\n"); -MODULE_AUTHOR("Hans Verkuil & Morten Hestnes"); +MODULE_AUTHOR("Hans Verkuil & Morten Hestnes"); MODULE_DESCRIPTION("cobalt driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index d4d7b264c965a3..ae82427e3479bb 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -424,8 +424,6 @@ static const struct vb2_ops cobalt_qops = { .buf_queue = cobalt_buf_queue, .start_streaming = cobalt_start_streaming, .stop_streaming = cobalt_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* V4L2 ioctls */ diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index acc6418db4254a..42d6f7b90ede30 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -229,8 +229,6 @@ static const struct vb2_ops cx18_vb2_qops = { .buf_prepare = cx18_buf_prepare, .start_streaming = cx18_start_streaming, .stop_streaming = cx18_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int cx18_stream_init(struct cx18 *cx, int type) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index fdb96f80c03649..219937a153b3ae 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1210,8 +1210,6 @@ static const struct vb2_ops cx23885_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx23885_start_streaming, .stop_streaming = cx23885_stop_streaming, }; diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 3d01cdc4c7f3d7..05a7859cbe5795 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -170,8 +170,6 @@ static const struct vb2_ops dvb_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx23885_start_streaming, .stop_streaming = cx23885_stop_streaming, }; diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 4bdd2bea3713e1..40817cc52fc1ee 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -249,8 +249,6 @@ const struct vb2_ops cx23885_vbi_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx23885_start_streaming, .stop_streaming = cx23885_stop_streaming, }; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 7d4a409c433e2a..35d58328db5639 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -519,8 +519,6 @@ static const struct vb2_ops cx23885_video_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx23885_start_streaming, .stop_streaming = cx23885_stop_streaming, }; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 0bee4b728a6014..84aa1209e7171e 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -295,8 +295,6 @@ static const struct vb2_ops cx25821_video_qops = { .buf_prepare = cx25821_buffer_prepare, .buf_finish = cx25821_buffer_finish, .buf_queue = cx25821_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = cx25821_start_streaming, .stop_streaming = cx25821_stop_streaming, }; diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index d55df8fdb3b604..13b8cc46835b2c 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -781,8 +781,6 @@ static const struct vb2_ops blackbird_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index b33b3a5e32ec64..c9cfceed2f1b42 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -152,8 +152,6 @@ static const struct vb2_ops dvb_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index 469aeaa725ad92..e3e379e6f6207b 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -228,8 +228,6 @@ const struct vb2_ops cx8800_vbi_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index cefb6b25e92172..0c87327689d3f6 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -562,8 +562,6 @@ static const struct vb2_ops cx8800_video_qops = { .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index dff853e73fdc8e..7bddcbba4cf1ba 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -222,8 +222,6 @@ static void dt3155_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops q_ops = { .queue_setup = dt3155_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = dt3155_buf_prepare, .start_streaming = dt3155_start_streaming, .stop_streaming = dt3155_stop_streaming, diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c index a0e9a71580b5dc..1bf249f446a988 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -323,7 +323,7 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor) return 0; } -EXPORT_SYMBOL_NS_GPL(ipu_bridge_parse_ssdb, INTEL_IPU_BRIDGE); +EXPORT_SYMBOL_NS_GPL(ipu_bridge_parse_ssdb, "INTEL_IPU_BRIDGE"); static void ipu_bridge_create_fwnode_properties( struct ipu_sensor *sensor, @@ -631,7 +631,7 @@ int ipu_bridge_instantiate_vcm(struct device *sensor) return 0; } -EXPORT_SYMBOL_NS_GPL(ipu_bridge_instantiate_vcm, INTEL_IPU_BRIDGE); +EXPORT_SYMBOL_NS_GPL(ipu_bridge_instantiate_vcm, "INTEL_IPU_BRIDGE"); static int ipu_bridge_instantiate_ivsc(struct ipu_sensor *sensor) { @@ -882,7 +882,7 @@ int ipu_bridge_init(struct device *dev, return ret; } -EXPORT_SYMBOL_NS_GPL(ipu_bridge_init, INTEL_IPU_BRIDGE); +EXPORT_SYMBOL_NS_GPL(ipu_bridge_init, "INTEL_IPU_BRIDGE"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Intel IPU Sensors Bridge driver"); diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 81ec8630453b7a..dd73d534ac490b 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1045,8 +1045,6 @@ static const struct vb2_ops cio2_vb2_ops = { .queue_setup = cio2_vb2_queue_setup, .start_streaming = cio2_vb2_start_streaming, .stop_streaming = cio2_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /**************** V4L2 interface ****************/ @@ -2002,4 +2000,4 @@ MODULE_AUTHOR("Yuning Pu"); MODULE_AUTHOR("Yong Zhi "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("IPU3 CIO2 driver"); -MODULE_IMPORT_NS(INTEL_IPU_BRIDGE); +MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); diff --git a/drivers/media/pci/intel/ipu6/Kconfig b/drivers/media/pci/intel/ipu6/Kconfig index 49e4fb696573f6..1129e2beb4bec7 100644 --- a/drivers/media/pci/intel/ipu6/Kconfig +++ b/drivers/media/pci/intel/ipu6/Kconfig @@ -2,19 +2,13 @@ config VIDEO_INTEL_IPU6 tristate "Intel IPU6 driver" depends on ACPI || COMPILE_TEST depends on VIDEO_DEV - depends on X86 && X86_64 && HAS_DMA + depends on X86 && HAS_DMA depends on IPU_BRIDGE || !IPU_BRIDGE - # - # This driver incorrectly tries to override the dma_ops. It should - # never have done that, but for now keep it working on architectures - # that use dma ops - # - depends on ARCH_HAS_DMA_OPS select AUXILIARY_BUS select IOMMU_IOVA select VIDEO_V4L2_SUBDEV_API select MEDIA_CONTROLLER - select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG select V4L2_FWNODE help This is the 6th Gen Intel Image Processing Unit, found in Intel SoCs diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.c b/drivers/media/pci/intel/ipu6/ipu6-bus.c index 149ec098cdbfe1..37d88ddb6ee7cd 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-bus.c +++ b/drivers/media/pci/intel/ipu6/ipu6-bus.c @@ -94,8 +94,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent, if (!adev) return ERR_PTR(-ENOMEM); - adev->dma_mask = DMA_BIT_MASK(isp->secure_mode ? IPU6_MMU_ADDR_BITS : - IPU6_MMU_ADDR_BITS_NON_SECURE); adev->isp = isp; adev->ctrl = ctrl; adev->pdata = pdata; @@ -106,10 +104,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent, auxdev->dev.parent = parent; auxdev->dev.release = ipu6_bus_release; - auxdev->dev.dma_ops = &ipu6_dma_ops; - auxdev->dev.dma_mask = &adev->dma_mask; - auxdev->dev.dma_parms = pdev->dev.dma_parms; - auxdev->dev.coherent_dma_mask = adev->dma_mask; ret = auxiliary_device_init(auxdev); if (ret < 0) { diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c index e47f84c30e10d6..e898902e83f371 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c +++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c @@ -24,6 +24,7 @@ #include "ipu6.h" #include "ipu6-bus.h" +#include "ipu6-dma.h" #include "ipu6-buttress.h" #include "ipu6-platform-buttress-regs.h" @@ -214,20 +215,17 @@ static void ipu6_buttress_ipc_recv(struct ipu6_device *isp, } static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp, - enum ipu6_buttress_ipc_domain ipc_domain, struct ipu6_ipc_buttress_bulk_msg *msgs, u32 size) { unsigned long tx_timeout_jiffies, rx_timeout_jiffies; unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY; struct ipu6_buttress *b = &isp->buttress; - struct ipu6_buttress_ipc *ipc; + struct ipu6_buttress_ipc *ipc = &b->cse; u32 val; int ret; int tout; - ipc = ipc_domain == IPU6_BUTTRESS_IPC_CSE ? &b->cse : &b->ish; - mutex_lock(&b->ipc_mutex); ret = ipu6_buttress_ipc_validity_open(isp, ipc); @@ -305,7 +303,6 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp, static int ipu6_buttress_ipc_send(struct ipu6_device *isp, - enum ipu6_buttress_ipc_domain ipc_domain, u32 ipc_msg, u32 size, bool require_resp, u32 expected_resp) { @@ -316,7 +313,7 @@ ipu6_buttress_ipc_send(struct ipu6_device *isp, .expected_resp = expected_resp, }; - return ipu6_buttress_ipc_send_bulk(isp, ipc_domain, &msg, 1); + return ipu6_buttress_ipc_send_bulk(isp, &msg, 1); } static irqreturn_t ipu6_buttress_call_isr(struct ipu6_bus_device *adev) @@ -345,12 +342,16 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr) u32 disable_irqs = 0; u32 irq_status; u32 i, count = 0; + int active; - pm_runtime_get_noresume(&isp->pdev->dev); + active = pm_runtime_get_if_active(&isp->pdev->dev); + if (!active) + return IRQ_NONE; irq_status = readl(isp->base + reg_irq_sts); - if (!irq_status) { - pm_runtime_put_noidle(&isp->pdev->dev); + if (irq_status == 0 || WARN_ON_ONCE(irq_status == 0xffffffffu)) { + if (active > 0) + pm_runtime_put_noidle(&isp->pdev->dev); return IRQ_NONE; } @@ -381,25 +382,12 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr) complete(&b->cse.recv_complete); } - if (irq_status & BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING) { - dev_dbg(&isp->pdev->dev, - "BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING\n"); - ipu6_buttress_ipc_recv(isp, &b->ish, &b->ish.recv_data); - complete(&b->ish.recv_complete); - } - if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) { dev_dbg(&isp->pdev->dev, "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n"); complete(&b->cse.send_complete); } - if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH) { - dev_dbg(&isp->pdev->dev, - "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n"); - complete(&b->ish.send_complete); - } - if (irq_status & BUTTRESS_ISR_SAI_VIOLATION && ipu6_buttress_get_secure_mode(isp)) dev_err(&isp->pdev->dev, @@ -426,7 +414,8 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr) writel(BUTTRESS_IRQS & ~disable_irqs, isp->base + BUTTRESS_REG_ISR_ENABLE); - pm_runtime_put(&isp->pdev->dev); + if (active > 0) + pm_runtime_put(&isp->pdev->dev); return ret; } @@ -517,7 +506,7 @@ bool ipu6_buttress_auth_done(struct ipu6_device *isp) return val == BUTTRESS_SECURITY_CTL_AUTH_DONE; } -EXPORT_SYMBOL_NS_GPL(ipu6_buttress_auth_done, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_buttress_auth_done, "INTEL_IPU6"); int ipu6_buttress_reset_authentication(struct ipu6_device *isp) { @@ -553,6 +542,7 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys, const struct firmware *fw, struct sg_table *sgt) { bool is_vmalloc = is_vmalloc_addr(fw->data); + struct pci_dev *pdev = sys->isp->pdev; struct page **pages; const void *addr; unsigned long n_pages; @@ -562,7 +552,7 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys, if (!is_vmalloc && !virt_addr_valid(fw->data)) return -EDOM; - n_pages = PHYS_PFN(PAGE_ALIGN(fw->size)); + n_pages = PFN_UP(fw->size); pages = kmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL); if (!pages) @@ -588,29 +578,38 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys, goto out; } - ret = dma_map_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0); - if (ret < 0) { - ret = -ENOMEM; + ret = dma_map_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0); + if (ret) { + sg_free_table(sgt); + goto out; + } + + ret = ipu6_dma_map_sgtable(sys, sgt, DMA_TO_DEVICE, 0); + if (ret) { + dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0); sg_free_table(sgt); goto out; } - dma_sync_sgtable_for_device(&sys->auxdev.dev, sgt, DMA_TO_DEVICE); + ipu6_dma_sync_sgtable(sys, sgt); out: kfree(pages); return ret; } -EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, "INTEL_IPU6"); void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys, struct sg_table *sgt) { - dma_unmap_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0); + struct pci_dev *pdev = sys->isp->pdev; + + ipu6_dma_unmap_sgtable(sys, sgt, DMA_TO_DEVICE, 0); + dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0); sg_free_table(sgt); } -EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, "INTEL_IPU6"); int ipu6_buttress_authenticate(struct ipu6_device *isp) { @@ -650,7 +649,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp) */ dev_info(&isp->pdev->dev, "Sending BOOT_LOAD to CSE\n"); - ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE, + ret = ipu6_buttress_ipc_send(isp, BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD, 1, true, BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE); @@ -692,7 +691,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp) * IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as */ dev_info(&isp->pdev->dev, "Sending AUTHENTICATE_RUN to CSE\n"); - ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE, + ret = ipu6_buttress_ipc_send(isp, BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN, 1, true, BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE); @@ -775,7 +774,7 @@ int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp) return -ETIMEDOUT; } -EXPORT_SYMBOL_NS_GPL(ipu6_buttress_start_tsc_sync, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_buttress_start_tsc_sync, "INTEL_IPU6"); void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val) { @@ -797,7 +796,7 @@ void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val) } local_irq_restore(flags); } -EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_read, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_read, "INTEL_IPU6"); u64 ipu6_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu6_device *isp) { @@ -812,7 +811,7 @@ u64 ipu6_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu6_device *isp) */ return div_u64(ns, isp->buttress.ref_clk); } -EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_ticks_to_ns, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_ticks_to_ns, "INTEL_IPU6"); void ipu6_buttress_restore(struct ipu6_device *isp) { @@ -833,9 +832,7 @@ int ipu6_buttress_init(struct ipu6_device *isp) mutex_init(&b->auth_mutex); mutex_init(&b->cons_mutex); mutex_init(&b->ipc_mutex); - init_completion(&b->ish.send_complete); init_completion(&b->cse.send_complete); - init_completion(&b->ish.recv_complete); init_completion(&b->cse.recv_complete); b->cse.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK; @@ -847,8 +844,6 @@ int ipu6_buttress_init(struct ipu6_device *isp) b->cse.data0_in = BUTTRESS_REG_CSE2IUDATA0; b->cse.data0_out = BUTTRESS_REG_IU2CSEDATA0; - /* no ISH on IPU6 */ - memset(&b->ish, 0, sizeof(b->ish)); INIT_LIST_HEAD(&b->constraints); isp->secure_mode = ipu6_buttress_get_secure_mode(isp); diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h index 9b6f56958be7e2..482978c2a09dc7 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h +++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h @@ -46,18 +46,12 @@ struct ipu6_buttress_ipc { struct ipu6_buttress { struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex; struct ipu6_buttress_ipc cse; - struct ipu6_buttress_ipc ish; struct list_head constraints; u32 wdt_cached_value; bool force_suspend; u32 ref_clk; }; -enum ipu6_buttress_ipc_domain { - IPU6_BUTTRESS_IPC_CSE, - IPU6_BUTTRESS_IPC_ISH, -}; - struct ipu6_ipc_buttress_bulk_msg { u32 cmd; u32 expected_resp; diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c index 715b21ab4b8e98..8b8142bcb2d50a 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c +++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c @@ -15,6 +15,7 @@ #include "ipu6.h" #include "ipu6-bus.h" #include "ipu6-cpd.h" +#include "ipu6-dma.h" /* 15 entries + header*/ #define MAX_PKG_DIR_ENT_CNT 16 @@ -43,9 +44,9 @@ * 63:56 55 54:48 47:32 31:24 23:0 * Rsvd Rsvd Type Version Rsvd Size */ -#define PKG_DIR_SIZE_MASK GENMASK(23, 0) -#define PKG_DIR_VERSION_MASK GENMASK(47, 32) -#define PKG_DIR_TYPE_MASK GENMASK(54, 48) +#define PKG_DIR_SIZE_MASK GENMASK_ULL(23, 0) +#define PKG_DIR_VERSION_MASK GENMASK_ULL(47, 32) +#define PKG_DIR_TYPE_MASK GENMASK_ULL(54, 48) static inline const struct ipu6_cpd_ent *ipu6_cpd_get_entry(const void *cpd, u8 idx) @@ -162,7 +163,6 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src) { dma_addr_t dma_addr_src = sg_dma_address(adev->fw_sgt.sgl); const struct ipu6_cpd_ent *ent, *man_ent, *met_ent; - struct device *dev = &adev->auxdev.dev; struct ipu6_device *isp = adev->isp; unsigned int man_sz, met_sz; void *pkg_dir_pos; @@ -175,8 +175,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src) met_sz = met_ent->len; adev->pkg_dir_size = PKG_DIR_SIZE + man_sz + met_sz; - adev->pkg_dir = dma_alloc_attrs(dev, adev->pkg_dir_size, - &adev->pkg_dir_dma_addr, GFP_KERNEL, 0); + adev->pkg_dir = ipu6_dma_alloc(adev, adev->pkg_dir_size, + &adev->pkg_dir_dma_addr, GFP_KERNEL, 0); if (!adev->pkg_dir) return -ENOMEM; @@ -198,8 +198,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src) met_ent->len); if (ret) { dev_err(&isp->pdev->dev, "Failed to parse module data\n"); - dma_free_attrs(dev, adev->pkg_dir_size, - adev->pkg_dir, adev->pkg_dir_dma_addr, 0); + ipu6_dma_free(adev, adev->pkg_dir_size, + adev->pkg_dir, adev->pkg_dir_dma_addr, 0); return ret; } @@ -211,19 +211,19 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src) pkg_dir_pos += man_sz; memcpy(pkg_dir_pos, src + met_ent->offset, met_sz); - dma_sync_single_range_for_device(dev, adev->pkg_dir_dma_addr, - 0, adev->pkg_dir_size, DMA_TO_DEVICE); + ipu6_dma_sync_single(adev, adev->pkg_dir_dma_addr, + adev->pkg_dir_size); return 0; } -EXPORT_SYMBOL_NS_GPL(ipu6_cpd_create_pkg_dir, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_cpd_create_pkg_dir, "INTEL_IPU6"); void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev) { - dma_free_attrs(&adev->auxdev.dev, adev->pkg_dir_size, adev->pkg_dir, - adev->pkg_dir_dma_addr, 0); + ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir, + adev->pkg_dir_dma_addr, 0); } -EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, "INTEL_IPU6"); static int ipu6_cpd_validate_cpd(struct ipu6_device *isp, const void *cpd, unsigned long cpd_size, diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c index 92530a1cc90f51..b34022bad83bf3 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-dma.c +++ b/drivers/media/pci/intel/ipu6/ipu6-dma.c @@ -39,8 +39,7 @@ static struct vm_info *get_vm_info(struct ipu6_mmu *mmu, dma_addr_t iova) return NULL; } -static void __dma_clear_buffer(struct page *page, size_t size, - unsigned long attrs) +static void __clear_buffer(struct page *page, size_t size, unsigned long attrs) { void *ptr; @@ -56,8 +55,7 @@ static void __dma_clear_buffer(struct page *page, size_t size, clflush_cache_range(ptr, size); } -static struct page **__dma_alloc_buffer(struct device *dev, size_t size, - gfp_t gfp, unsigned long attrs) +static struct page **__alloc_buffer(size_t size, gfp_t gfp, unsigned long attrs) { int count = PHYS_PFN(size); int array_size = count * sizeof(struct page *); @@ -86,7 +84,7 @@ static struct page **__dma_alloc_buffer(struct device *dev, size_t size, pages[i + j] = pages[i] + j; } - __dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs); + __clear_buffer(pages[i], PAGE_SIZE << order, attrs); i += 1 << order; count -= 1 << order; } @@ -100,29 +98,26 @@ static struct page **__dma_alloc_buffer(struct device *dev, size_t size, return NULL; } -static void __dma_free_buffer(struct device *dev, struct page **pages, - size_t size, unsigned long attrs) +static void __free_buffer(struct page **pages, size_t size, unsigned long attrs) { int count = PHYS_PFN(size); unsigned int i; for (i = 0; i < count && pages[i]; i++) { - __dma_clear_buffer(pages[i], PAGE_SIZE, attrs); + __clear_buffer(pages[i], PAGE_SIZE, attrs); __free_pages(pages[i], 0); } kvfree(pages); } -static void ipu6_dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction dir) +void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle, + size_t size) { void *vaddr; u32 offset; struct vm_info *info; - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; + struct ipu6_mmu *mmu = sys->mmu; info = get_vm_info(mmu, dma_handle); if (WARN_ON(!info)) @@ -135,25 +130,33 @@ static void ipu6_dma_sync_single_for_cpu(struct device *dev, vaddr = info->vaddr + offset; clflush_cache_range(vaddr, size); } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_single, "INTEL_IPU6"); -static void ipu6_dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sglist, - int nents, enum dma_data_direction dir) +void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents) { struct scatterlist *sg; int i; for_each_sg(sglist, sg, nents, i) - clflush_cache_range(page_to_virt(sg_page(sg)), sg->length); + clflush_cache_range(sg_virt(sg), sg->length); } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_sg, "INTEL_IPU6"); -static void *ipu6_dma_alloc(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - unsigned long attrs) +void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; - struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev; + ipu6_dma_sync_sg(sys, sgt->sgl, sgt->orig_nents); +} +EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_sgtable, "INTEL_IPU6"); + +void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + unsigned long attrs) +{ + struct device *dev = &sys->auxdev.dev; + struct pci_dev *pdev = sys->isp->pdev; dma_addr_t pci_dma_addr, ipu6_iova; + struct ipu6_mmu *mmu = sys->mmu; struct vm_info *info; unsigned long count; struct page **pages; @@ -173,7 +176,7 @@ static void *ipu6_dma_alloc(struct device *dev, size_t size, if (!iova) goto out_kfree; - pages = __dma_alloc_buffer(dev, size, gfp, attrs); + pages = __alloc_buffer(size, gfp, attrs); if (!pages) goto out_free_iova; @@ -227,7 +230,7 @@ static void *ipu6_dma_alloc(struct device *dev, size_t size, ipu6_mmu_unmap(mmu->dmap->mmu_info, ipu6_iova, PAGE_SIZE); } - __dma_free_buffer(dev, pages, size, attrs); + __free_buffer(pages, size, attrs); out_free_iova: __free_iova(&mmu->dmap->iovad, iova); @@ -236,13 +239,13 @@ static void *ipu6_dma_alloc(struct device *dev, size_t size, return NULL; } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_alloc, "INTEL_IPU6"); -static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle, - unsigned long attrs) +void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr, + dma_addr_t dma_handle, unsigned long attrs) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; - struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev; + struct ipu6_mmu *mmu = sys->mmu; + struct pci_dev *pdev = sys->isp->pdev; struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(dma_handle)); dma_addr_t pci_dma_addr, ipu6_iova; struct vm_info *info; @@ -281,7 +284,7 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr, ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo), PFN_PHYS(iova_size(iova))); - __dma_free_buffer(dev, pages, size, attrs); + __free_buffer(pages, size, attrs); mmu->tlb_invalidate(mmu); @@ -289,13 +292,14 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr, kfree(info); } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_free, "INTEL_IPU6"); -static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma, - void *addr, dma_addr_t iova, size_t size, - unsigned long attrs) +int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma, + void *addr, dma_addr_t iova, size_t size, + unsigned long attrs) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; - size_t count = PHYS_PFN(PAGE_ALIGN(size)); + struct ipu6_mmu *mmu = sys->mmu; + size_t count = PFN_UP(size); struct vm_info *info; size_t i; int ret; @@ -323,18 +327,17 @@ static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma, return 0; } -static void ipu6_dma_unmap_sg(struct device *dev, - struct scatterlist *sglist, - int nents, enum dma_data_direction dir, - unsigned long attrs) +void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs) { - struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev; - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; + struct device *dev = &sys->auxdev.dev; + struct ipu6_mmu *mmu = sys->mmu; struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(sg_dma_address(sglist))); - int i, npages, count; struct scatterlist *sg; dma_addr_t pci_dma_addr; + unsigned int i; if (!nents) return; @@ -342,31 +345,15 @@ static void ipu6_dma_unmap_sg(struct device *dev, if (WARN_ON(!iova)) return; - if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) - ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL); - - /* get the nents as orig_nents given by caller */ - count = 0; - npages = iova_size(iova); - for_each_sg(sglist, sg, nents, i) { - if (sg_dma_len(sg) == 0 || - sg_dma_address(sg) == DMA_MAPPING_ERROR) - break; - - npages -= PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg))); - count++; - if (npages <= 0) - break; - } - /* * Before IPU6 mmu unmap, return the pci dma address back to sg * assume the nents is less than orig_nents as the least granule * is 1 SZ_4K page */ - dev_dbg(dev, "trying to unmap concatenated %u ents\n", count); - for_each_sg(sglist, sg, count, i) { - dev_dbg(dev, "ipu unmap sg[%d] %pad\n", i, &sg_dma_address(sg)); + dev_dbg(dev, "trying to unmap concatenated %u ents\n", nents); + for_each_sg(sglist, sg, nents, i) { + dev_dbg(dev, "unmap sg[%d] %pad size %u\n", i, + &sg_dma_address(sg), sg_dma_len(sg)); pci_dma_addr = ipu6_mmu_iova_to_phys(mmu->dmap->mmu_info, sg_dma_address(sg)); dev_dbg(dev, "return pci_dma_addr %pad back to sg[%d]\n", @@ -380,23 +367,21 @@ static void ipu6_dma_unmap_sg(struct device *dev, PFN_PHYS(iova_size(iova))); mmu->tlb_invalidate(mmu); - - dma_unmap_sg_attrs(&pdev->dev, sglist, nents, dir, attrs); - __free_iova(&mmu->dmap->iovad, iova); } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sg, "INTEL_IPU6"); -static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist, - int nents, enum dma_data_direction dir, - unsigned long attrs) +int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; - struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev; + struct device *dev = &sys->auxdev.dev; + struct ipu6_mmu *mmu = sys->mmu; struct scatterlist *sg; struct iova *iova; size_t npages = 0; unsigned long iova_addr; - int i, count; + int i; for_each_sg(sglist, sg, nents, i) { if (sg->offset) { @@ -406,17 +391,11 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist, } } - dev_dbg(dev, "pci_dma_map_sg trying to map %d ents\n", nents); - count = dma_map_sg_attrs(&pdev->dev, sglist, nents, dir, attrs); - if (count <= 0) { - dev_err(dev, "pci_dma_map_sg %d ents failed\n", nents); - return 0; - } - - dev_dbg(dev, "pci_dma_map_sg %d ents mapped\n", count); + for_each_sg(sglist, sg, nents, i) + npages += PFN_UP(sg_dma_len(sg)); - for_each_sg(sglist, sg, count, i) - npages += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg))); + dev_dbg(dev, "dmamap trying to map %d ents %zu pages\n", + nents, npages); iova = alloc_iova(&mmu->dmap->iovad, npages, PHYS_PFN(dma_get_mask(dev)), 0); @@ -427,12 +406,13 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist, iova->pfn_hi); iova_addr = iova->pfn_lo; - for_each_sg(sglist, sg, count, i) { + for_each_sg(sglist, sg, nents, i) { + phys_addr_t iova_pa; int ret; - dev_dbg(dev, "mapping entry %d: iova 0x%llx phy %pad size %d\n", - i, PFN_PHYS(iova_addr), &sg_dma_address(sg), - sg_dma_len(sg)); + iova_pa = PFN_PHYS(iova_addr); + dev_dbg(dev, "mapping entry %d: iova %pap phy %pap size %d\n", + i, &iova_pa, &sg_dma_address(sg), sg_dma_len(sg)); ret = ipu6_mmu_map(mmu->dmap->mmu_info, PFN_PHYS(iova_addr), sg_dma_address(sg), @@ -442,28 +422,51 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist, sg_dma_address(sg) = PFN_PHYS(iova_addr); - iova_addr += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg))); + iova_addr += PFN_UP(sg_dma_len(sg)); } - if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0) - ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL); + dev_dbg(dev, "dmamap %d ents %zu pages mapped\n", nents, npages); - return count; + return nents; out_fail: - ipu6_dma_unmap_sg(dev, sglist, i, dir, attrs); + ipu6_dma_unmap_sg(sys, sglist, i, dir, attrs); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(ipu6_dma_map_sg, "INTEL_IPU6"); + +int ipu6_dma_map_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs) +{ + int nents; + + nents = ipu6_dma_map_sg(sys, sgt->sgl, sgt->nents, dir, attrs); + if (nents < 0) + return nents; + + sgt->nents = nents; return 0; } +EXPORT_SYMBOL_NS_GPL(ipu6_dma_map_sgtable, "INTEL_IPU6"); + +void ipu6_dma_unmap_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs) +{ + ipu6_dma_unmap_sg(sys, sgt->sgl, sgt->nents, dir, attrs); +} +EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sgtable, "INTEL_IPU6"); /* * Create scatter-list for the already allocated DMA buffer */ -static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt, - void *cpu_addr, dma_addr_t handle, size_t size, - unsigned long attrs) +int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size, + unsigned long attrs) { - struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu; + struct device *dev = &sys->auxdev.dev; + struct ipu6_mmu *mmu = sys->mmu; struct vm_info *info; int n_pages; int ret = 0; @@ -478,25 +481,12 @@ static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt, if (WARN_ON(!info->pages)) return -ENOMEM; - n_pages = PHYS_PFN(PAGE_ALIGN(size)); + n_pages = PFN_UP(size); ret = sg_alloc_table_from_pages(sgt, info->pages, n_pages, 0, size, GFP_KERNEL); if (ret) - dev_warn(dev, "IPU6 get sgt table failed\n"); + dev_warn(dev, "get sgt table failed\n"); return ret; } - -const struct dma_map_ops ipu6_dma_ops = { - .alloc = ipu6_dma_alloc, - .free = ipu6_dma_free, - .mmap = ipu6_dma_mmap, - .map_sg = ipu6_dma_map_sg, - .unmap_sg = ipu6_dma_unmap_sg, - .sync_single_for_cpu = ipu6_dma_sync_single_for_cpu, - .sync_single_for_device = ipu6_dma_sync_single_for_cpu, - .sync_sg_for_cpu = ipu6_dma_sync_sg_for_cpu, - .sync_sg_for_device = ipu6_dma_sync_sg_for_cpu, - .get_sgtable = ipu6_dma_get_sgtable, -}; diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.h b/drivers/media/pci/intel/ipu6/ipu6-dma.h index 847ea5b7c925c3..b51244add9e611 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-dma.h +++ b/drivers/media/pci/intel/ipu6/ipu6-dma.h @@ -5,7 +5,13 @@ #define IPU6_DMA_H #include +#include #include +#include +#include +#include + +#include "ipu6-bus.h" struct ipu6_mmu_info; @@ -14,6 +20,30 @@ struct ipu6_dma_mapping { struct iova_domain iovad; }; -extern const struct dma_map_ops ipu6_dma_ops; - +void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle, + size_t size); +void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents); +void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt); +void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + unsigned long attrs); +void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr, + dma_addr_t dma_handle, unsigned long attrs); +int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma, + void *addr, dma_addr_t iova, size_t size, + unsigned long attrs); +int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs); +void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist, + int nents, enum dma_data_direction dir, + unsigned long attrs); +int ipu6_dma_map_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs); +void ipu6_dma_unmap_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs); +int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size, + unsigned long attrs); #endif /* IPU6_DMA_H */ diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-com.c b/drivers/media/pci/intel/ipu6/ipu6-fw-com.c index 0b33fe9e703dcb..40d8ce138a67d2 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-fw-com.c +++ b/drivers/media/pci/intel/ipu6/ipu6-fw-com.c @@ -12,6 +12,7 @@ #include #include "ipu6-bus.h" +#include "ipu6-dma.h" #include "ipu6-fw-com.h" /* @@ -88,7 +89,6 @@ struct ipu6_fw_com_context { void *dma_buffer; dma_addr_t dma_addr; unsigned int dma_size; - unsigned long attrs; struct ipu6_fw_sys_queue *input_queue; /* array of host to SP queues */ struct ipu6_fw_sys_queue *output_queue; /* array of SP to host */ @@ -164,7 +164,6 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, struct ipu6_fw_com_context *ctx; struct device *dev = &adev->auxdev.dev; size_t sizeall, offset; - unsigned long attrs = 0; void *specific_host_addr; unsigned int i; @@ -206,9 +205,8 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, sizeall += sizeinput + sizeoutput; - ctx->dma_buffer = dma_alloc_attrs(dev, sizeall, &ctx->dma_addr, - GFP_KERNEL, attrs); - ctx->attrs = attrs; + ctx->dma_buffer = ipu6_dma_alloc(adev, sizeall, &ctx->dma_addr, + GFP_KERNEL, 0); if (!ctx->dma_buffer) { dev_err(dev, "failed to allocate dma memory\n"); kfree(ctx); @@ -239,10 +237,12 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, memcpy(specific_host_addr, cfg->specific_addr, cfg->specific_size); + ipu6_dma_sync_single(adev, ctx->config_vied_addr, sizeall); + /* initialize input queues */ offset += specific_size; res.reg = SYSCOM_QPR_BASE_REG; - res.host_address = (u64)(ctx->dma_buffer + offset); + res.host_address = (uintptr_t)(ctx->dma_buffer + offset); res.vied_address = ctx->dma_addr + offset; for (i = 0; i < cfg->num_input_queues; i++) ipu6_sys_queue_init(ctx->input_queue + i, @@ -251,7 +251,7 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, /* initialize output queues */ offset += sizeinput; - res.host_address = (u64)(ctx->dma_buffer + offset); + res.host_address = (uintptr_t)(ctx->dma_buffer + offset); res.vied_address = ctx->dma_addr + offset; for (i = 0; i < cfg->num_output_queues; i++) { ipu6_sys_queue_init(ctx->output_queue + i, @@ -261,7 +261,7 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg, return ctx; } -EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_prepare, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_prepare, "INTEL_IPU6"); int ipu6_fw_com_open(struct ipu6_fw_com_context *ctx) { @@ -289,7 +289,7 @@ int ipu6_fw_com_open(struct ipu6_fw_com_context *ctx) return 0; } -EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_open, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_open, "INTEL_IPU6"); int ipu6_fw_com_close(struct ipu6_fw_com_context *ctx) { @@ -307,7 +307,7 @@ int ipu6_fw_com_close(struct ipu6_fw_com_context *ctx) return 0; } -EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_close, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_close, "INTEL_IPU6"); int ipu6_fw_com_release(struct ipu6_fw_com_context *ctx, unsigned int force) { @@ -315,12 +315,12 @@ int ipu6_fw_com_release(struct ipu6_fw_com_context *ctx, unsigned int force) if (!force && !ctx->cell_ready(ctx->adev)) return -EBUSY; - dma_free_attrs(&ctx->adev->auxdev.dev, ctx->dma_size, - ctx->dma_buffer, ctx->dma_addr, ctx->attrs); + ipu6_dma_free(ctx->adev, ctx->dma_size, + ctx->dma_buffer, ctx->dma_addr, 0); kfree(ctx); return 0; } -EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_release, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_release, "INTEL_IPU6"); bool ipu6_fw_com_ready(struct ipu6_fw_com_context *ctx) { @@ -332,7 +332,7 @@ bool ipu6_fw_com_ready(struct ipu6_fw_com_context *ctx) return state == SYSCOM_STATE_READY; } -EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_ready, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_fw_com_ready, "INTEL_IPU6"); void *ipu6_send_get_token(struct ipu6_fw_com_context *ctx, int q_nbr) { @@ -358,9 +358,9 @@ void *ipu6_send_get_token(struct ipu6_fw_com_context *ctx, int q_nbr) index = readl(q_dmem + FW_COM_WR_REG); - return (void *)(q->host_address + index * q->token_size); + return (void *)((uintptr_t)q->host_address + index * q->token_size); } -EXPORT_SYMBOL_NS_GPL(ipu6_send_get_token, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_send_get_token, "INTEL_IPU6"); void ipu6_send_put_token(struct ipu6_fw_com_context *ctx, int q_nbr) { @@ -373,7 +373,7 @@ void ipu6_send_put_token(struct ipu6_fw_com_context *ctx, int q_nbr) writel(wr, q_dmem + FW_COM_WR_REG); } -EXPORT_SYMBOL_NS_GPL(ipu6_send_put_token, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_send_put_token, "INTEL_IPU6"); void *ipu6_recv_get_token(struct ipu6_fw_com_context *ctx, int q_nbr) { @@ -395,9 +395,9 @@ void *ipu6_recv_get_token(struct ipu6_fw_com_context *ctx, int q_nbr) if (!packets) return NULL; - return (void *)(q->host_address + rd * q->token_size); + return (void *)((uintptr_t)q->host_address + rd * q->token_size); } -EXPORT_SYMBOL_NS_GPL(ipu6_recv_get_token, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_recv_get_token, "INTEL_IPU6"); void ipu6_recv_put_token(struct ipu6_fw_com_context *ctx, int q_nbr) { @@ -410,4 +410,4 @@ void ipu6_recv_put_token(struct ipu6_fw_com_context *ctx, int q_nbr) writel(rd, q_dmem + FW_COM_RD_REG); } -EXPORT_SYMBOL_NS_GPL(ipu6_recv_put_token, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_recv_put_token, "INTEL_IPU6"); diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c b/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c index 1715275e6776c7..db28748434530f 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c @@ -67,7 +67,7 @@ static void dwc_dphy_write(struct ipu6_isys *isys, u32 phy_id, u32 addr, void __iomem *isys_base = isys->pdata->base; void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id); - dev_dbg(dev, "write: reg 0x%lx = data 0x%x", base + addr - isys_base, + dev_dbg(dev, "write: reg 0x%zx = data 0x%x", base + addr - isys_base, data); writel(data, base + addr); } @@ -80,7 +80,7 @@ static u32 dwc_dphy_read(struct ipu6_isys *isys, u32 phy_id, u32 addr) u32 data; data = readl(base + addr); - dev_dbg(dev, "read: reg 0x%lx = data 0x%x", base + addr - isys_base, + dev_dbg(dev, "read: reg 0x%zx = data 0x%x", base + addr - isys_base, data); return data; diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c index 03dbb0e0ea7957..bbb66b56ee88c9 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c @@ -13,17 +13,48 @@ #include #include -#include +#include #include #include "ipu6-bus.h" +#include "ipu6-dma.h" #include "ipu6-fw-isys.h" #include "ipu6-isys.h" #include "ipu6-isys-video.h" -static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, - unsigned int *num_planes, unsigned int sizes[], - struct device *alloc_devs[]) +static int ipu6_isys_buf_init(struct vb2_buffer *vb) +{ + struct ipu6_isys *isys = vb2_get_drv_priv(vb->vb2_queue); + struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu6_isys_video_buffer *ivb = + vb2_buffer_to_ipu6_isys_video_buffer(vvb); + int ret; + + ret = ipu6_dma_map_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0); + if (ret) + return ret; + + ivb->dma_addr = sg_dma_address(sg->sgl); + + return 0; +} + +static void ipu6_isys_buf_cleanup(struct vb2_buffer *vb) +{ + struct ipu6_isys *isys = vb2_get_drv_priv(vb->vb2_queue); + struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu6_isys_video_buffer *ivb = + vb2_buffer_to_ipu6_isys_video_buffer(vvb); + + ivb->dma_addr = 0; + ipu6_dma_unmap_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0); +} + +static int ipu6_isys_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) { struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q); struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); @@ -207,9 +238,11 @@ ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb, struct ipu6_fw_isys_frame_buff_set_abi *set) { struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue); + struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb); + struct ipu6_isys_video_buffer *ivb = + vb2_buffer_to_ipu6_isys_video_buffer(vvb); - set->output_pins[aq->fw_output].addr = - vb2_dma_contig_plane_dma_addr(vb, 0); + set->output_pins[aq->fw_output].addr = ivb->dma_addr; set->output_pins[aq->fw_output].out_buf_id = vb->index + 1; } @@ -332,7 +365,7 @@ static void buf_queue(struct vb2_buffer *vb) dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name); - dma = vb2_dma_contig_plane_dma_addr(vb, 0); + dma = ivb->dma_addr; dev_dbg(dev, "iova: iova %pad\n", &dma); spin_lock_irqsave(&aq->lock, flags); @@ -724,10 +757,14 @@ void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream, } list_for_each_entry_reverse(ib, &aq->active, head) { + struct ipu6_isys_video_buffer *ivb; + struct vb2_v4l2_buffer *vvb; dma_addr_t addr; vb = ipu6_isys_buffer_to_vb2_buffer(ib); - addr = vb2_dma_contig_plane_dma_addr(vb, 0); + vvb = to_vb2_v4l2_buffer(vb); + ivb = vb2_buffer_to_ipu6_isys_video_buffer(vvb); + addr = ivb->dma_addr; if (info->pin.addr != addr) { if (first) @@ -766,10 +803,12 @@ void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream, } static const struct vb2_ops ipu6_isys_queue_ops = { - .queue_setup = queue_setup, + .queue_setup = ipu6_isys_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, + .buf_init = ipu6_isys_buf_init, .buf_prepare = ipu6_isys_buf_prepare, + .buf_cleanup = ipu6_isys_buf_cleanup, .start_streaming = start_streaming, .stop_streaming = stop_streaming, .buf_queue = buf_queue, @@ -779,16 +818,17 @@ int ipu6_isys_queue_init(struct ipu6_isys_queue *aq) { struct ipu6_isys *isys = ipu6_isys_queue_to_video(aq)->isys; struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); + struct ipu6_bus_device *adev = isys->adev; int ret; /* no support for userptr */ if (!aq->vbq.io_modes) aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF; - aq->vbq.drv_priv = aq; + aq->vbq.drv_priv = isys; aq->vbq.ops = &ipu6_isys_queue_ops; aq->vbq.lock = &av->mutex; - aq->vbq.mem_ops = &vb2_dma_contig_memops; + aq->vbq.mem_ops = &vb2_dma_sg_memops; aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; aq->vbq.min_queued_buffers = 1; aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; @@ -797,8 +837,8 @@ int ipu6_isys_queue_init(struct ipu6_isys_queue *aq) if (ret) return ret; - aq->dev = &isys->adev->auxdev.dev; - aq->vbq.dev = &isys->adev->auxdev.dev; + aq->dev = &adev->auxdev.dev; + aq->vbq.dev = &adev->isp->pdev->dev; spin_lock_init(&aq->lock); INIT_LIST_HEAD(&aq->active); INIT_LIST_HEAD(&aq->incoming); diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h index 95cfd4869d9356..fe8fc796a58f5d 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h @@ -38,6 +38,7 @@ struct ipu6_isys_buffer { struct ipu6_isys_video_buffer { struct vb2_v4l2_buffer vb_v4l2; struct ipu6_isys_buffer ib; + dma_addr_t dma_addr; }; #define IPU6_ISYS_BUFFER_LIST_FL_INCOMING BIT(0) diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c index b37561352ead38..387963529adb56 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c @@ -543,7 +543,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av, ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg); if (ret < 0) { - ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg); + ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); return ret; } } @@ -560,7 +560,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av, IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN); if (ret < 0) { dev_err(dev, "can't open stream (%d)\n", ret); - ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg); + ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); return ret; } @@ -569,7 +569,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av, tout = wait_for_completion_timeout(&stream->stream_open_completion, IPU6_FW_CALL_TIMEOUT_JIFFIES); - ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg); + ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg); if (!tout) { dev_err(dev, "stream open time out\n"); diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c index c4aff2e2009bab..77f9c73198681b 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c @@ -34,6 +34,7 @@ #include "ipu6-bus.h" #include "ipu6-cpd.h" +#include "ipu6-dma.h" #include "ipu6-isys.h" #include "ipu6-isys-csi2.h" #include "ipu6-mmu.h" @@ -576,7 +577,7 @@ void update_watermark_setting(struct ipu6_isys *isys) } enable_iwake(isys, true); - calc_fill_time_us = max_sram_size / isys_pb_datarate_mbs; + calc_fill_time_us = div64_u64(max_sram_size, isys_pb_datarate_mbs); if (isys->pdata->ipdata->enhanced_iwake) { ltr = isys->pdata->ipdata->ltr; @@ -933,29 +934,27 @@ static const struct dev_pm_ops isys_pm_ops = { static void free_fw_msg_bufs(struct ipu6_isys *isys) { - struct device *dev = &isys->adev->auxdev.dev; struct isys_fw_msgs *fwmsg, *safe; list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist, head) - dma_free_attrs(dev, sizeof(struct isys_fw_msgs), fwmsg, - fwmsg->dma_addr, 0); + ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), fwmsg, + fwmsg->dma_addr, 0); list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist_fw, head) - dma_free_attrs(dev, sizeof(struct isys_fw_msgs), fwmsg, - fwmsg->dma_addr, 0); + ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), fwmsg, + fwmsg->dma_addr, 0); } static int alloc_fw_msg_bufs(struct ipu6_isys *isys, int amount) { - struct device *dev = &isys->adev->auxdev.dev; struct isys_fw_msgs *addr; dma_addr_t dma_addr; unsigned long flags; unsigned int i; for (i = 0; i < amount; i++) { - addr = dma_alloc_attrs(dev, sizeof(struct isys_fw_msgs), - &dma_addr, GFP_KERNEL, 0); + addr = ipu6_dma_alloc(isys->adev, sizeof(*addr), + &dma_addr, GFP_KERNEL, 0); if (!addr) break; addr->dma_addr = dma_addr; @@ -974,8 +973,8 @@ static int alloc_fw_msg_bufs(struct ipu6_isys *isys, int amount) struct isys_fw_msgs, head); list_del(&addr->head); spin_unlock_irqrestore(&isys->listlock, flags); - dma_free_attrs(dev, sizeof(struct isys_fw_msgs), addr, - addr->dma_addr, 0); + ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), addr, + addr->dma_addr, 0); spin_lock_irqsave(&isys->listlock, flags); } spin_unlock_irqrestore(&isys->listlock, flags); @@ -1026,11 +1025,11 @@ void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys) spin_unlock_irqrestore(&isys->listlock, flags); } -void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, u64 data) +void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data) { struct isys_fw_msgs *msg; unsigned long flags; - u64 *ptr = (u64 *)data; + void *ptr = (void *)data; if (!ptr) return; @@ -1378,5 +1377,5 @@ MODULE_AUTHOR("Yunliang Ding "); MODULE_AUTHOR("Hongju Wang "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Intel IPU6 input system driver"); -MODULE_IMPORT_NS(INTEL_IPU6); -MODULE_IMPORT_NS(INTEL_IPU_BRIDGE); +MODULE_IMPORT_NS("INTEL_IPU6"); +MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h index 86dfc2eff5d003..610b60e69152b6 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys.h +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h @@ -180,7 +180,7 @@ struct isys_fw_msgs { }; struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream); -void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, u64 data); +void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data); void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys); extern const struct v4l2_ioctl_ops ipu6_isys_ioctl_ops; diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c index c3a20507d6dbcc..6d1c0b90169d40 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c +++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c @@ -97,13 +97,15 @@ static void page_table_dump(struct ipu6_mmu_info *mmu_info) for (l1_idx = 0; l1_idx < ISP_L1PT_PTES; l1_idx++) { u32 l2_idx; u32 iova = (phys_addr_t)l1_idx << ISP_L1PT_SHIFT; + phys_addr_t l2_phys; if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) continue; + + l2_phys = TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx];) dev_dbg(mmu_info->dev, - "l1 entry %u; iovas 0x%8.8x-0x%8.8x, at %pa\n", - l1_idx, iova, iova + ISP_PAGE_SIZE, - TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx])); + "l1 entry %u; iovas 0x%8.8x-0x%8.8x, at %pap\n", + l1_idx, iova, iova + ISP_PAGE_SIZE, &l2_phys); for (l2_idx = 0; l2_idx < ISP_L2PT_PTES; l2_idx++) { u32 *l2_pt = mmu_info->l2_pts[l1_idx]; @@ -227,7 +229,7 @@ static u32 *alloc_l1_pt(struct ipu6_mmu_info *mmu_info) } mmu_info->l1_pt_dma = dma >> ISP_PADDR_SHIFT; - dev_dbg(mmu_info->dev, "l1 pt %p mapped at %llx\n", pt, dma); + dev_dbg(mmu_info->dev, "l1 pt %p mapped at %pad\n", pt, &dma); return pt; @@ -252,75 +254,142 @@ static u32 *alloc_l2_pt(struct ipu6_mmu_info *mmu_info) return pt; } +static void l2_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, + phys_addr_t dummy, size_t size) +{ + unsigned int l2_entries; + unsigned int l2_idx; + unsigned long flags; + u32 l1_idx; + u32 *l2_pt; + + spin_lock_irqsave(&mmu_info->lock, flags); + for (l1_idx = iova >> ISP_L1PT_SHIFT; + size > 0 && l1_idx < ISP_L1PT_PTES; l1_idx++) { + dev_dbg(mmu_info->dev, + "unmapping l2 pgtable (l1 index %u (iova 0x%8.8lx))\n", + l1_idx, iova); + + if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) { + dev_err(mmu_info->dev, + "unmap not mapped iova 0x%8.8lx l1 index %u\n", + iova, l1_idx); + continue; + } + l2_pt = mmu_info->l2_pts[l1_idx]; + + l2_entries = 0; + for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; + size > 0 && l2_idx < ISP_L2PT_PTES; l2_idx++) { + phys_addr_t pteval = TBL_PHYS_ADDR(l2_pt[l2_idx]); + + dev_dbg(mmu_info->dev, + "unmap l2 index %u with pteval 0x%p\n", + l2_idx, &pteval); + l2_pt[l2_idx] = mmu_info->dummy_page_pteval; + + iova += ISP_PAGE_SIZE; + size -= ISP_PAGE_SIZE; + + l2_entries++; + } + + WARN_ON_ONCE(!l2_entries); + clflush_cache_range(&l2_pt[l2_idx - l2_entries], + sizeof(l2_pt[0]) * l2_entries); + } + + WARN_ON_ONCE(size); + spin_unlock_irqrestore(&mmu_info->lock, flags); +} + static int l2_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, phys_addr_t paddr, size_t size) { - u32 l1_idx = iova >> ISP_L1PT_SHIFT; - u32 iova_start = iova; + struct device *dev = mmu_info->dev; + unsigned int l2_entries; u32 *l2_pt, *l2_virt; unsigned int l2_idx; unsigned long flags; + size_t mapped = 0; dma_addr_t dma; u32 l1_entry; - - dev_dbg(mmu_info->dev, - "mapping l2 page table for l1 index %u (iova %8.8x)\n", - l1_idx, (u32)iova); + u32 l1_idx; + int err = 0; spin_lock_irqsave(&mmu_info->lock, flags); - l1_entry = mmu_info->l1_pt[l1_idx]; - if (l1_entry == mmu_info->dummy_l2_pteval) { - l2_virt = mmu_info->l2_pts[l1_idx]; - if (likely(!l2_virt)) { - l2_virt = alloc_l2_pt(mmu_info); - if (!l2_virt) { - spin_unlock_irqrestore(&mmu_info->lock, flags); - return -ENOMEM; + + paddr = ALIGN(paddr, ISP_PAGE_SIZE); + for (l1_idx = iova >> ISP_L1PT_SHIFT; + size > 0 && l1_idx < ISP_L1PT_PTES; l1_idx++) { + dev_dbg(dev, + "mapping l2 page table for l1 index %u (iova %8.8x)\n", + l1_idx, (u32)iova); + + l1_entry = mmu_info->l1_pt[l1_idx]; + if (l1_entry == mmu_info->dummy_l2_pteval) { + l2_virt = mmu_info->l2_pts[l1_idx]; + if (likely(!l2_virt)) { + l2_virt = alloc_l2_pt(mmu_info); + if (!l2_virt) { + err = -ENOMEM; + goto error; + } } - } - dma = map_single(mmu_info, l2_virt); - if (!dma) { - dev_err(mmu_info->dev, "Failed to map l2pt page\n"); - free_page((unsigned long)l2_virt); - spin_unlock_irqrestore(&mmu_info->lock, flags); - return -EINVAL; - } + dma = map_single(mmu_info, l2_virt); + if (!dma) { + dev_err(dev, "Failed to map l2pt page\n"); + free_page((unsigned long)l2_virt); + err = -EINVAL; + goto error; + } - l1_entry = dma >> ISP_PADDR_SHIFT; + l1_entry = dma >> ISP_PADDR_SHIFT; - dev_dbg(mmu_info->dev, "page for l1_idx %u %p allocated\n", - l1_idx, l2_virt); - mmu_info->l1_pt[l1_idx] = l1_entry; - mmu_info->l2_pts[l1_idx] = l2_virt; - clflush_cache_range((void *)&mmu_info->l1_pt[l1_idx], - sizeof(mmu_info->l1_pt[l1_idx])); - } + dev_dbg(dev, "page for l1_idx %u %p allocated\n", + l1_idx, l2_virt); + mmu_info->l1_pt[l1_idx] = l1_entry; + mmu_info->l2_pts[l1_idx] = l2_virt; - l2_pt = mmu_info->l2_pts[l1_idx]; + clflush_cache_range(&mmu_info->l1_pt[l1_idx], + sizeof(mmu_info->l1_pt[l1_idx])); + } - dev_dbg(mmu_info->dev, "l2_pt at %p with dma 0x%x\n", l2_pt, l1_entry); + l2_pt = mmu_info->l2_pts[l1_idx]; + l2_entries = 0; - paddr = ALIGN(paddr, ISP_PAGE_SIZE); + for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; + size > 0 && l2_idx < ISP_L2PT_PTES; l2_idx++) { + l2_pt[l2_idx] = paddr >> ISP_PADDR_SHIFT; - l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; + dev_dbg(dev, "l2 index %u mapped as 0x%8.8x\n", l2_idx, + l2_pt[l2_idx]); - dev_dbg(mmu_info->dev, "l2_idx %u, phys 0x%8.8x\n", l2_idx, - l2_pt[l2_idx]); - if (l2_pt[l2_idx] != mmu_info->dummy_page_pteval) { - spin_unlock_irqrestore(&mmu_info->lock, flags); - return -EINVAL; - } + iova += ISP_PAGE_SIZE; + paddr += ISP_PAGE_SIZE; + mapped += ISP_PAGE_SIZE; + size -= ISP_PAGE_SIZE; + + l2_entries++; + } - l2_pt[l2_idx] = paddr >> ISP_PADDR_SHIFT; + WARN_ON_ONCE(!l2_entries); + clflush_cache_range(&l2_pt[l2_idx - l2_entries], + sizeof(l2_pt[0]) * l2_entries); + } - clflush_cache_range((void *)&l2_pt[l2_idx], sizeof(l2_pt[l2_idx])); spin_unlock_irqrestore(&mmu_info->lock, flags); - dev_dbg(mmu_info->dev, "l2 index %u mapped as 0x%8.8x\n", l2_idx, - l2_pt[l2_idx]); - return 0; + +error: + spin_unlock_irqrestore(&mmu_info->lock, flags); + /* unroll mapping in case something went wrong */ + if (mapped) + l2_unmap(mmu_info, iova - mapped, paddr - mapped, mapped); + + return err; } static int __ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, @@ -330,61 +399,21 @@ static int __ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, u32 iova_end = ALIGN(iova + size, ISP_PAGE_SIZE); dev_dbg(mmu_info->dev, - "mapping iova 0x%8.8x--0x%8.8x, size %zu at paddr 0x%10.10llx\n", - iova_start, iova_end, size, paddr); + "mapping iova 0x%8.8x--0x%8.8x, size %zu at paddr %pap\n", + iova_start, iova_end, size, &paddr); return l2_map(mmu_info, iova_start, paddr, size); } -static size_t l2_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, - phys_addr_t dummy, size_t size) +static void __ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, + unsigned long iova, size_t size) { - u32 l1_idx = iova >> ISP_L1PT_SHIFT; - u32 iova_start = iova; - unsigned int l2_idx; - size_t unmapped = 0; - unsigned long flags; - u32 *l2_pt; - - dev_dbg(mmu_info->dev, "unmapping l2 page table for l1 index %u (iova 0x%8.8lx)\n", - l1_idx, iova); - - spin_lock_irqsave(&mmu_info->lock, flags); - if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) { - spin_unlock_irqrestore(&mmu_info->lock, flags); - dev_err(mmu_info->dev, - "unmap iova 0x%8.8lx l1 idx %u which was not mapped\n", - iova, l1_idx); - return 0; - } - - for (l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT; - (iova_start & ISP_L1PT_MASK) + (l2_idx << ISP_PAGE_SHIFT) - < iova_start + size && l2_idx < ISP_L2PT_PTES; l2_idx++) { - l2_pt = mmu_info->l2_pts[l1_idx]; - dev_dbg(mmu_info->dev, - "unmap l2 index %u with pteval 0x%10.10llx\n", - l2_idx, TBL_PHYS_ADDR(l2_pt[l2_idx])); - l2_pt[l2_idx] = mmu_info->dummy_page_pteval; - - clflush_cache_range((void *)&l2_pt[l2_idx], - sizeof(l2_pt[l2_idx])); - unmapped++; - } - spin_unlock_irqrestore(&mmu_info->lock, flags); - - return unmapped << ISP_PAGE_SHIFT; -} - -static size_t __ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, - unsigned long iova, size_t size) -{ - return l2_unmap(mmu_info, iova, 0, size); + l2_unmap(mmu_info, iova, 0, size); } static int allocate_trash_buffer(struct ipu6_mmu *mmu) { - unsigned int n_pages = PHYS_PFN(PAGE_ALIGN(IPU6_MMUV2_TRASH_RANGE)); + unsigned int n_pages = PFN_UP(IPU6_MMUV2_TRASH_RANGE); struct iova *iova; unsigned int i; dma_addr_t dma; @@ -513,7 +542,7 @@ int ipu6_mmu_hw_init(struct ipu6_mmu *mmu) return 0; } -EXPORT_SYMBOL_NS_GPL(ipu6_mmu_hw_init, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_mmu_hw_init, "INTEL_IPU6"); static struct ipu6_mmu_info *ipu6_mmu_alloc(struct ipu6_device *isp) { @@ -525,9 +554,10 @@ static struct ipu6_mmu_info *ipu6_mmu_alloc(struct ipu6_device *isp) return NULL; mmu_info->aperture_start = 0; - mmu_info->aperture_end = DMA_BIT_MASK(isp->secure_mode ? - IPU6_MMU_ADDR_BITS : - IPU6_MMU_ADDR_BITS_NON_SECURE); + mmu_info->aperture_end = + (dma_addr_t)DMA_BIT_MASK(isp->secure_mode ? + IPU6_MMU_ADDR_BITS : + IPU6_MMU_ADDR_BITS_NON_SECURE); mmu_info->pgsize_bitmap = SZ_4K; mmu_info->dev = &isp->pdev->dev; @@ -577,7 +607,7 @@ void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu) mmu->ready = false; spin_unlock_irqrestore(&mmu->ready_lock, flags); } -EXPORT_SYMBOL_NS_GPL(ipu6_mmu_hw_cleanup, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_mmu_hw_cleanup, "INTEL_IPU6"); static struct ipu6_dma_mapping *alloc_dma_mapping(struct ipu6_device *isp) { @@ -619,40 +649,13 @@ phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info, return phy_addr; } -static size_t ipu6_mmu_pgsize(unsigned long pgsize_bitmap, - unsigned long addr_merge, size_t size) -{ - unsigned int pgsize_idx; - size_t pgsize; - - /* Max page size that still fits into 'size' */ - pgsize_idx = __fls(size); - - if (likely(addr_merge)) { - /* Max page size allowed by address */ - unsigned int align_pgsize_idx = __ffs(addr_merge); - - pgsize_idx = min(pgsize_idx, align_pgsize_idx); - } - - pgsize = (1UL << (pgsize_idx + 1)) - 1; - pgsize &= pgsize_bitmap; - - WARN_ON(!pgsize); - - /* pick the biggest page */ - pgsize_idx = __fls(pgsize); - pgsize = 1UL << pgsize_idx; - - return pgsize; -} - -size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, - size_t size) +void ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, + size_t size) { - size_t unmapped_page, unmapped = 0; unsigned int min_pagesz; + dev_dbg(mmu_info->dev, "unmapping iova 0x%lx size 0x%zx\n", iova, size); + /* find out the minimum page size supported */ min_pagesz = 1 << __ffs(mmu_info->pgsize_bitmap); @@ -664,38 +667,16 @@ size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, if (!IS_ALIGNED(iova | size, min_pagesz)) { dev_err(NULL, "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n", iova, size, min_pagesz); - return -EINVAL; - } - - /* - * Keep iterating until we either unmap 'size' bytes (or more) - * or we hit an area that isn't mapped. - */ - while (unmapped < size) { - size_t pgsize = ipu6_mmu_pgsize(mmu_info->pgsize_bitmap, - iova, size - unmapped); - - unmapped_page = __ipu6_mmu_unmap(mmu_info, iova, pgsize); - if (!unmapped_page) - break; - - dev_dbg(mmu_info->dev, "unmapped: iova 0x%lx size 0x%zx\n", - iova, unmapped_page); - - iova += unmapped_page; - unmapped += unmapped_page; + return; } - return unmapped; + __ipu6_mmu_unmap(mmu_info, iova, size); } int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, phys_addr_t paddr, size_t size) { - unsigned long orig_iova = iova; unsigned int min_pagesz; - size_t orig_size = size; - int ret = 0; if (mmu_info->pgsize_bitmap == 0UL) return -ENODEV; @@ -718,28 +699,7 @@ int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, dev_dbg(mmu_info->dev, "map: iova 0x%lx pa %pa size 0x%zx\n", iova, &paddr, size); - while (size) { - size_t pgsize = ipu6_mmu_pgsize(mmu_info->pgsize_bitmap, - iova | paddr, size); - - dev_dbg(mmu_info->dev, - "mapping: iova 0x%lx pa %pa pgsize 0x%zx\n", - iova, &paddr, pgsize); - - ret = __ipu6_mmu_map(mmu_info, iova, paddr, pgsize); - if (ret) - break; - - iova += pgsize; - paddr += pgsize; - size -= pgsize; - } - - /* unroll mapping in case something went wrong */ - if (ret) - ipu6_mmu_unmap(mmu_info, orig_iova, orig_size - size); - - return ret; + return __ipu6_mmu_map(mmu_info, iova, paddr, size); } static void ipu6_mmu_destroy(struct ipu6_mmu *mmu) diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h index 21cdb0f146eb51..8e40b4a66d7dd7 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h +++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h @@ -66,8 +66,8 @@ int ipu6_mmu_hw_init(struct ipu6_mmu *mmu); void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu); int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova, phys_addr_t paddr, size_t size); -size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, - size_t size); +void ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova, + size_t size); phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info, dma_addr_t iova); #endif diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h index 20f27011df43ee..efd65e494c1649 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h +++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h @@ -219,8 +219,6 @@ enum { BUTTRESS_ISR_IS_IRQ | BUTTRESS_ISR_PS_IRQ) #define BUTTRESS_EVENT (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \ - BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING | \ BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \ - BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH | \ BUTTRESS_ISR_SAI_VIOLATION) #endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */ diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c index 7fb707d3530967..277af7cda8eec1 100644 --- a/drivers/media/pci/intel/ipu6/ipu6.c +++ b/drivers/media/pci/intel/ipu6/ipu6.c @@ -247,7 +247,8 @@ ipu6_pkg_dir_configure_spc(struct ipu6_device *isp, dma_addr = sg_dma_address(isp->psys->fw_sgt.sgl); pg_offset = server_fw_addr - dma_addr; - prog = (struct ipu6_cell_program *)((u64)isp->cpd_fw->data + pg_offset); + prog = (struct ipu6_cell_program *)((uintptr_t)isp->cpd_fw->data + + pg_offset); spc_base = base + prog->regs_addr; if (spc_base != (base + hw_variant->spc_offset)) dev_warn(&isp->pdev->dev, @@ -280,7 +281,7 @@ void ipu6_configure_spc(struct ipu6_device *isp, ipu6_pkg_dir_configure_spc(isp, hw_variant, pkg_dir_idx, base, pkg_dir, pkg_dir_dma_addr); } -EXPORT_SYMBOL_NS_GPL(ipu6_configure_spc, INTEL_IPU6); +EXPORT_SYMBOL_NS_GPL(ipu6_configure_spc, "INTEL_IPU6"); #define IPU6_ISYS_CSI2_NPORTS 4 #define IPU6SE_ISYS_CSI2_NPORTS 4 @@ -752,6 +753,9 @@ static void ipu6_pci_reset_done(struct pci_dev *pdev) */ static int ipu6_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); + + synchronize_irq(pdev->irq); return 0; } @@ -836,7 +840,7 @@ static struct pci_driver ipu6_pci_driver = { module_pci_driver(ipu6_pci_driver); -MODULE_IMPORT_NS(INTEL_IPU_BRIDGE); +MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); MODULE_AUTHOR("Sakari Ailus "); MODULE_AUTHOR("Tianshu Qiu "); MODULE_AUTHOR("Bingbu Cao "); diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c index 2a9c12c975cac1..6a893c4547b28d 100644 --- a/drivers/media/pci/intel/ivsc/mei_csi.c +++ b/drivers/media/pci/intel/ivsc/mei_csi.c @@ -808,7 +808,7 @@ static struct mei_cl_driver mei_csi_driver = { module_mei_cl_driver(mei_csi_driver); -MODULE_IMPORT_NS(INTEL_IPU_BRIDGE); +MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); MODULE_AUTHOR("Wentong Wu "); MODULE_AUTHOR("Zhifeng Wang "); MODULE_DESCRIPTION("Device driver for IVSC CSI"); diff --git a/drivers/media/pci/mantis/mantis_core.h b/drivers/media/pci/mantis/mantis_core.h deleted file mode 100644 index 93c89a10a2c769..00000000000000 --- a/drivers/media/pci/mantis/mantis_core.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - -*/ - -#ifndef __MANTIS_CORE_H -#define __MANTIS_CORE_H - -#include "mantis_common.h" - - -#define FE_TYPE_SAT 0 -#define FE_TYPE_CAB 1 -#define FE_TYPE_TER 2 - -#define FE_TYPE_TS204 0 -#define FE_TYPE_TS188 1 - - -struct vendorname { - u8 *sub_vendor_name; - u32 sub_vendor_id; -}; - -struct devicetype { - u8 *sub_device_name; - u32 sub_device_id; - u8 device_type; - u32 type_flags; -}; - - -extern int mantis_dma_init(struct mantis_pci *mantis); -extern int mantis_dma_exit(struct mantis_pci *mantis); -extern void mantis_dma_start(struct mantis_pci *mantis); -extern void mantis_dma_stop(struct mantis_pci *mantis); -extern int mantis_i2c_init(struct mantis_pci *mantis); -extern int mantis_i2c_exit(struct mantis_pci *mantis); - -#endif /* __MANTIS_CORE_H */ diff --git a/drivers/media/pci/mgb4/mgb4_core.c b/drivers/media/pci/mgb4/mgb4_core.c index 2819bbdab4842f..bc63dc81bcae0d 100644 --- a/drivers/media/pci/mgb4/mgb4_core.c +++ b/drivers/media/pci/mgb4/mgb4_core.c @@ -582,9 +582,7 @@ static int mgb4_probe(struct pci_dev *pdev, const struct pci_device_id *id) NULL); #endif -#ifdef CONFIG_DEBUG_FS mgbdev->debugfs = debugfs_create_dir(dev_name(&pdev->dev), NULL); -#endif /* Get card serial number. On systems without MTD flash support we may * get an error thus ignore the return value. An invalid serial number @@ -646,6 +644,8 @@ static void mgb4_remove(struct pci_dev *pdev) hwmon_device_unregister(mgbdev->hwmon_dev); #endif + debugfs_remove_recursive(mgbdev->debugfs); + if (mgbdev->indio_dev) mgb4_trigger_free(mgbdev->indio_dev); @@ -656,10 +656,6 @@ static void mgb4_remove(struct pci_dev *pdev) if (mgbdev->vin[i]) mgb4_vin_free(mgbdev->vin[i]); -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(mgbdev->debugfs); -#endif - device_remove_groups(&mgbdev->pdev->dev, mgb4_pci_groups); free_spi(mgbdev); free_i2c(mgbdev); diff --git a/drivers/media/pci/mgb4/mgb4_core.h b/drivers/media/pci/mgb4/mgb4_core.h index b52cd67270b56d..9aec62514c0be9 100644 --- a/drivers/media/pci/mgb4/mgb4_core.h +++ b/drivers/media/pci/mgb4/mgb4_core.h @@ -68,9 +68,7 @@ struct mgb4_dev { u8 module_version; u32 serial_number; -#ifdef CONFIG_DEBUG_FS struct dentry *debugfs; -#endif }; #endif diff --git a/drivers/media/pci/mgb4/mgb4_vin.c b/drivers/media/pci/mgb4/mgb4_vin.c index e9332abb31729e..3f171c624b40df 100644 --- a/drivers/media/pci/mgb4/mgb4_vin.c +++ b/drivers/media/pci/mgb4/mgb4_vin.c @@ -260,6 +260,7 @@ static void buffer_queue(struct vb2_buffer *vb) static void stop_streaming(struct vb2_queue *vq) { struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq); + struct mgb4_regs *video = &vindev->mgbdev->video; const struct mgb4_vin_config *config = vindev->config; int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq); @@ -273,6 +274,9 @@ static void stop_streaming(struct vb2_queue *vq) mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2, 0x0); + mgb4_write_reg(video, vindev->config->regs.padding, 0); + set_loopback_padding(vindev, 0); + cancel_work_sync(&vindev->dma_work); return_all_buffers(vindev, VB2_BUF_STATE_ERROR); } @@ -280,6 +284,7 @@ static void stop_streaming(struct vb2_queue *vq) static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq); + struct mgb4_regs *video = &vindev->mgbdev->video; const struct mgb4_vin_config *config = vindev->config; int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq); @@ -292,6 +297,9 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2, 0x2); + mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding); + set_loopback_padding(vindev, vindev->padding); + xdma_enable_user_irq(vindev->mgbdev->xdev, irq); return 0; @@ -304,8 +312,6 @@ static const struct vb2_ops queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish }; static int fh_open(struct file *file) @@ -324,34 +330,16 @@ static int fh_open(struct file *file) if (get_timings(vindev, &vindev->timings) < 0) vindev->timings = cea1080p60; - set_loopback_padding(vindev, vindev->padding); out: mutex_unlock(&vindev->lock); return rv; } -static int fh_release(struct file *file) -{ - struct mgb4_vin_dev *vindev = video_drvdata(file); - int rv; - - mutex_lock(&vindev->lock); - - if (v4l2_fh_is_singular_file(file)) - set_loopback_padding(vindev, 0); - - rv = _vb2_fop_release(file, NULL); - - mutex_unlock(&vindev->lock); - - return rv; -} - static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, .open = fh_open, - .release = fh_release, + .release = vb2_fop_release, .unlocked_ioctl = video_ioctl2, .read = vb2_fop_read, .mmap = vb2_fop_mmap, @@ -507,8 +495,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) vindev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width * pixelsize)) / pixelsize; - mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding); - set_loopback_padding(vindev, vindev->padding); return 0; } @@ -853,14 +839,16 @@ static void fpga_init(struct mgb4_vin_dev *vindev) mgb4_write_reg(video, regs->config, 1U << 9); } -#ifdef CONFIG_DEBUG_FS -static void debugfs_init(struct mgb4_vin_dev *vindev) +static void create_debugfs(struct mgb4_vin_dev *vindev) { +#ifdef CONFIG_DEBUG_FS struct mgb4_regs *video = &vindev->mgbdev->video; + struct dentry *entry; - vindev->debugfs = debugfs_create_dir(vindev->vdev.name, - vindev->mgbdev->debugfs); - if (!vindev->debugfs) + if (IS_ERR_OR_NULL(vindev->mgbdev->debugfs)) + return; + entry = debugfs_create_dir(vindev->vdev.name, vindev->mgbdev->debugfs); + if (IS_ERR(entry)) return; vindev->regs[0].name = "CONFIG"; @@ -892,10 +880,9 @@ static void debugfs_init(struct mgb4_vin_dev *vindev) vindev->regset.base = video->membase; vindev->regset.regs = vindev->regs; - debugfs_create_regset32("registers", 0444, vindev->debugfs, - &vindev->regset); -} + debugfs_create_regset32("registers", 0444, entry, &vindev->regset); #endif +} struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id) { @@ -1001,9 +988,7 @@ struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id) goto err_video_dev; } -#ifdef CONFIG_DEBUG_FS - debugfs_init(vindev); -#endif + create_debugfs(vindev); return vindev; @@ -1034,10 +1019,6 @@ void mgb4_vin_free(struct mgb4_vin_dev *vindev) free_irq(vin_irq, vindev); free_irq(err_irq, vindev); -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(vindev->debugfs); -#endif - groups = MGB4_IS_GMSL(vindev->mgbdev) ? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups; device_remove_groups(&vindev->vdev.dev, groups); diff --git a/drivers/media/pci/mgb4/mgb4_vin.h b/drivers/media/pci/mgb4/mgb4_vin.h index 9693bd0ce18060..8fd10c0a55546a 100644 --- a/drivers/media/pci/mgb4/mgb4_vin.h +++ b/drivers/media/pci/mgb4/mgb4_vin.h @@ -58,7 +58,6 @@ struct mgb4_vin_dev { const struct mgb4_vin_config *config; #ifdef CONFIG_DEBUG_FS - struct dentry *debugfs; struct debugfs_regset32 regset; struct debugfs_reg32 regs[sizeof(struct mgb4_vin_regs) / 4]; #endif diff --git a/drivers/media/pci/mgb4/mgb4_vout.c b/drivers/media/pci/mgb4/mgb4_vout.c index 998edcbd972387..6b2791e29de15e 100644 --- a/drivers/media/pci/mgb4/mgb4_vout.c +++ b/drivers/media/pci/mgb4/mgb4_vout.c @@ -230,8 +230,6 @@ static const struct vb2_ops queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish }; static int vidioc_querycap(struct file *file, void *priv, @@ -676,14 +674,16 @@ static void fpga_init(struct mgb4_vout_dev *voutdev) (voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4); } -#ifdef CONFIG_DEBUG_FS -static void debugfs_init(struct mgb4_vout_dev *voutdev) +static void create_debugfs(struct mgb4_vout_dev *voutdev) { +#ifdef CONFIG_DEBUG_FS struct mgb4_regs *video = &voutdev->mgbdev->video; + struct dentry *entry; - voutdev->debugfs = debugfs_create_dir(voutdev->vdev.name, - voutdev->mgbdev->debugfs); - if (!voutdev->debugfs) + if (IS_ERR_OR_NULL(voutdev->mgbdev->debugfs)) + return; + entry = debugfs_create_dir(voutdev->vdev.name, voutdev->mgbdev->debugfs); + if (IS_ERR(entry)) return; voutdev->regs[0].name = "CONFIG"; @@ -711,10 +711,9 @@ static void debugfs_init(struct mgb4_vout_dev *voutdev) voutdev->regset.base = video->membase; voutdev->regset.regs = voutdev->regs; - debugfs_create_regset32("registers", 0444, voutdev->debugfs, - &voutdev->regset); -} + debugfs_create_regset32("registers", 0444, entry, &voutdev->regset); #endif +} struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id) { @@ -808,9 +807,7 @@ struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id) goto err_video_dev; } -#ifdef CONFIG_DEBUG_FS - debugfs_init(voutdev); -#endif + create_debugfs(voutdev); return voutdev; @@ -833,10 +830,6 @@ void mgb4_vout_free(struct mgb4_vout_dev *voutdev) free_irq(irq, voutdev); -#ifdef CONFIG_DEBUG_FS - debugfs_remove_recursive(voutdev->debugfs); -#endif - groups = MGB4_IS_GMSL(voutdev->mgbdev) ? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups; device_remove_groups(&voutdev->vdev.dev, groups); diff --git a/drivers/media/pci/mgb4/mgb4_vout.h b/drivers/media/pci/mgb4/mgb4_vout.h index adc8fe1e7ae68b..a07eeabdcf342b 100644 --- a/drivers/media/pci/mgb4/mgb4_vout.h +++ b/drivers/media/pci/mgb4/mgb4_vout.h @@ -54,7 +54,6 @@ struct mgb4_vout_dev { const struct mgb4_vout_config *config; #ifdef CONFIG_DEBUG_FS - struct dentry *debugfs; struct debugfs_regset32 regset; struct debugfs_reg32 regs[sizeof(struct mgb4_vout_regs) / 4]; #endif diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c b/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c index e90aa1c1584c50..34d6d52f1e4e1b 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c @@ -175,11 +175,11 @@ int netup_spi_init(struct netup_unidvb_dev *ndev) struct spi_controller *ctlr; struct netup_spi *nspi; - ctlr = devm_spi_alloc_master(&ndev->pci_dev->dev, - sizeof(struct netup_spi)); + ctlr = devm_spi_alloc_host(&ndev->pci_dev->dev, + sizeof(struct netup_spi)); if (!ctlr) { dev_err(&ndev->pci_dev->dev, - "%s(): unable to alloc SPI master\n", __func__); + "%s(): unable to alloc SPI host\n", __func__); return -EINVAL; } nspi = spi_controller_get_devdata(ctlr); diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index bbf480ab31ca77..8c4f70e4177d18 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -78,8 +78,6 @@ static const struct vb2_ops saa7134_empress_qops = { .buf_init = saa7134_ts_buffer_init, .buf_prepare = saa7134_ts_buffer_prepare, .buf_queue = saa7134_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c index 437dbe5e75e297..ec699ea1479942 100644 --- a/drivers/media/pci/saa7134/saa7134-ts.c +++ b/drivers/media/pci/saa7134/saa7134-ts.c @@ -166,8 +166,6 @@ struct vb2_ops saa7134_ts_qops = { .buf_init = saa7134_ts_buffer_init, .buf_prepare = saa7134_ts_buffer_prepare, .buf_queue = saa7134_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = saa7134_ts_stop_streaming, }; EXPORT_SYMBOL_GPL(saa7134_ts_qops); diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index 3e773690468bdb..efa6e4fa423aa9 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -161,8 +161,6 @@ const struct vb2_ops saa7134_vbi_qops = { .buf_init = buffer_init, .buf_prepare = buffer_prepare, .buf_queue = saa7134_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = saa7134_vb2_start_streaming, .stop_streaming = saa7134_vb2_stop_streaming, }; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 56b4481a40e612..43e7b006eb5967 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -844,8 +844,6 @@ static const struct vb2_ops vb2_qops = { .buf_init = buffer_init, .buf_prepare = buffer_prepare, .buf_queue = saa7134_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = saa7134_vb2_start_streaming, .stop_streaming = saa7134_vb2_stop_streaming, }; diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 0adf3d80f248ed..5ee59b3844cc3d 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -756,8 +756,6 @@ static const struct vb2_ops solo_enc_video_qops = { .buf_finish = solo_enc_buf_finish, .start_streaming = solo_enc_start_streaming, .stop_streaming = solo_enc_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int solo_enc_querycap(struct file *file, void *priv, diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index e18cc41fca83b2..35715b21dbdffc 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -365,8 +365,6 @@ static const struct vb2_ops solo_video_qops = { .buf_queue = solo_buf_queue, .start_streaming = solo_start_streaming, .stop_streaming = solo_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int solo_querycap(struct file *file, void *priv, diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 364ce9e5701827..3049bad20f142d 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -372,8 +372,6 @@ static const struct vb2_ops vip_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index 4f35c159efe5a3..0a08708e52b082 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c @@ -471,8 +471,6 @@ static const struct vb2_ops tw5864_video_qops = { .buf_queue = tw5864_buf_queue, .start_streaming = tw5864_start_streaming, .stop_streaming = tw5864_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int tw5864_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index cdf5d733b863e4..77773dec48b83a 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -524,8 +524,6 @@ static const struct vb2_ops tw68_video_qops = { .buf_finish = tw68_buf_finish, .start_streaming = tw68_start_streaming, .stop_streaming = tw68_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index 63be95fce83d13..785dd797d921b5 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -579,8 +579,6 @@ static const struct vb2_ops tw686x_video_qops = { .buf_prepare = tw686x_buf_prepare, .start_streaming = tw686x_start_streaming, .stop_streaming = tw686x_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 5c05e64c71a905..f42f596d3e6295 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -950,8 +950,6 @@ static const struct vb2_ops zr_video_qops = { .buf_prepare = zr_vb2_prepare, .start_streaming = zr_vb2_start_streaming, .stop_streaming = zr_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 73606cee586ede..e491399afcc984 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -1509,8 +1509,10 @@ static int allocate_buffers_internal(struct allegro_channel *channel, INIT_LIST_HEAD(&buffer->head); err = allegro_alloc_buffer(dev, buffer, size); - if (err) + if (err) { + kfree(buffer); goto err; + } list_add(&buffer->head, list); } @@ -2895,8 +2897,6 @@ static const struct vb2_ops allegro_queue_ops = { .buf_queue = allegro_buf_queue, .start_streaming = allegro_start_streaming, .stop_streaming = allegro_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int allegro_queue_init(void *priv, @@ -4003,7 +4003,7 @@ static const struct dev_pm_ops allegro_pm_ops = { static struct platform_driver allegro_driver = { .probe = allegro_probe, - .remove_new = allegro_remove, + .remove = allegro_remove, .driver = { .name = "allegro", .of_match_table = allegro_dt_ids, diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c index 09409908ba5dfb..0c004bb8ba0505 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c +++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c @@ -391,8 +391,6 @@ static const struct vb2_ops ge2d_qops = { .buf_queue = ge2d_buf_queue, .start_streaming = ge2d_start_streaming, .stop_streaming = ge2d_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int @@ -1045,7 +1043,7 @@ MODULE_DEVICE_TABLE(of, meson_ge2d_match); static struct platform_driver ge2d_drv = { .probe = ge2d_probe, - .remove_new = ge2d_remove, + .remove = ge2d_remove, .driver = { .name = "meson-ge2d", .of_match_table = meson_ge2d_match, diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 351b4edc874271..c5c1f1fbaa8036 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -52,6 +52,7 @@ struct venc_t { u32 ready_count; u32 enable; u32 stopped; + u32 memory_resource_configured; u32 skipped_count; u32 skipped_bytes; @@ -943,10 +944,19 @@ static int venc_start_session(struct vpu_inst *inst, u32 type) ret = vpu_iface_set_encode_params(inst, &venc->params, 0); if (ret) goto error; + + venc->memory_resource_configured = false; ret = vpu_session_configure_codec(inst); if (ret) goto error; + if (!venc->memory_resource_configured) { + vb2_queue_error(v4l2_m2m_get_src_vq(inst->fh.m2m_ctx)); + vb2_queue_error(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx)); + ret = -ENOMEM; + goto error; + } + inst->state = VPU_CODEC_STATE_CONFIGURED; /*vpu_iface_config_memory_resource*/ @@ -985,6 +995,7 @@ static void venc_cleanup_mem_resource(struct vpu_inst *inst) u32 i; venc = inst->priv; + venc->memory_resource_configured = false; for (i = 0; i < ARRAY_SIZE(venc->enc); i++) vpu_free_dma(&venc->enc[i]); @@ -1048,6 +1059,7 @@ static void venc_request_mem_resource(struct vpu_inst *inst, vpu_iface_config_memory_resource(inst, MEM_RES_REF, i, &venc->ref[i]); for (i = 0; i < act_frame_num; i++) vpu_iface_config_memory_resource(inst, MEM_RES_ACT, i, &venc->act[i]); + venc->memory_resource_configured = true; } static void venc_cleanup_frames(struct venc_t *venc) diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index 3a2030d02e45e6..8df85c14ab3fb9 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -864,7 +864,7 @@ MODULE_DEVICE_TABLE(of, vpu_core_dt_match); static struct platform_driver amphion_vpu_core_driver = { .probe = vpu_core_probe, - .remove_new = vpu_core_remove, + .remove = vpu_core_remove, .driver = { .name = "amphion-vpu-core", .of_match_table = vpu_core_dt_match, diff --git a/drivers/media/platform/amphion/vpu_drv.c b/drivers/media/platform/amphion/vpu_drv.c index 2bf70aafd2baab..efbfd2652721f0 100644 --- a/drivers/media/platform/amphion/vpu_drv.c +++ b/drivers/media/platform/amphion/vpu_drv.c @@ -151,8 +151,8 @@ static int vpu_probe(struct platform_device *pdev) media_device_cleanup(&vpu->mdev); v4l2_device_unregister(&vpu->v4l2_dev); err_vpu_deinit: - pm_runtime_set_suspended(dev); pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); return ret; } @@ -227,7 +227,7 @@ MODULE_DEVICE_TABLE(of, vpu_dt_match); static struct platform_driver amphion_vpu_driver = { .probe = vpu_probe, - .remove_new = vpu_remove, + .remove = vpu_remove, .driver = { .name = "amphion-vpu", .of_match_table = vpu_dt_match, diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 83db57bc80b70f..45707931bc4f1f 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -646,8 +646,6 @@ static const struct vb2_ops vpu_vb2_ops = { .start_streaming = vpu_vb2_start_streaming, .stop_streaming = vpu_vb2_stop_streaming, .buf_queue = vpu_vb2_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) @@ -841,6 +839,7 @@ int vpu_add_func(struct vpu_dev *vpu, struct vpu_func *func) vfd->fops = vdec_get_fops(); vfd->ioctl_ops = vdec_get_ioctl_ops(); } + video_set_drvdata(vfd, vpu); ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); if (ret) { @@ -848,7 +847,6 @@ int vpu_add_func(struct vpu_dev *vpu, struct vpu_func *func) v4l2_m2m_release(func->m2m_dev); return ret; } - video_set_drvdata(vfd, vpu); func->vfd = vfd; ret = v4l2_m2m_register_media_controller(func->m2m_dev, func->vfd, func->function); diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c index fc6050e3be0d8e..54cae0da9aca3f 100644 --- a/drivers/media/platform/aspeed/aspeed-video.c +++ b/drivers/media/platform/aspeed/aspeed-video.c @@ -1891,8 +1891,6 @@ static void aspeed_video_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops aspeed_video_vb2_ops = { .queue_setup = aspeed_video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = aspeed_video_buf_prepare, .start_streaming = aspeed_video_start_streaming, .stop_streaming = aspeed_video_stop_streaming, @@ -2226,7 +2224,7 @@ static struct platform_driver aspeed_video_driver = { .of_match_table = aspeed_video_of_match, }, .probe = aspeed_video_probe, - .remove_new = aspeed_video_remove, + .remove = aspeed_video_remove, }; module_platform_driver(aspeed_video_driver); diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 5c823d3f9cc0c9..0d1c3934752972 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -526,8 +526,6 @@ static const struct vb2_ops isi_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int isi_g_fmt_vid_cap(struct file *file, void *priv, @@ -1367,7 +1365,7 @@ static struct platform_driver atmel_isi_driver = { .pm = &atmel_isi_dev_pm_ops, }, .probe = atmel_isi_probe, - .remove_new = atmel_isi_remove, + .remove = atmel_isi_remove, }; module_platform_driver(atmel_isi_driver); diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c index a1d93c14553d80..3aed0e493c81f1 100644 --- a/drivers/media/platform/broadcom/bcm2835-unicam.c +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c @@ -1801,8 +1801,6 @@ static void unicam_buffer_queue(struct vb2_buffer *vb) static const struct vb2_ops unicam_video_qops = { .queue_setup = unicam_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = unicam_buffer_prepare, .start_streaming = unicam_start_streaming, .stop_streaming = unicam_stop_streaming, @@ -2724,7 +2722,7 @@ MODULE_DEVICE_TABLE(of, unicam_of_match); static struct platform_driver unicam_driver = { .probe = unicam_probe, - .remove_new = unicam_remove, + .remove = unicam_remove, .driver = { .name = UNICAM_MODULE_NAME, .pm = pm_ptr(&unicam_pm_ops), diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 6f7d27a48eff04..4d64df829e7585 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -751,7 +751,7 @@ MODULE_DEVICE_TABLE(of, csi2rx_of_table); static struct platform_driver csi2rx_driver = { .probe = csi2rx_probe, - .remove_new = csi2rx_remove, + .remove = csi2rx_remove, .driver = { .name = "cdns-csi2rx", diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 3d98f91f1beed3..e22b133f346dfb 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -644,7 +644,7 @@ static void csi2tx_remove(struct platform_device *pdev) static struct platform_driver csi2tx_driver = { .probe = csi2tx_probe, - .remove_new = csi2tx_remove, + .remove = csi2tx_remove, .driver = { .name = "cdns-csi2tx", diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c index 7da0194ec850f0..289a076c3bcc77 100644 --- a/drivers/media/platform/chips-media/coda/coda-common.c +++ b/drivers/media/platform/chips-media/coda/coda-common.c @@ -2171,8 +2171,6 @@ static const struct vb2_ops coda_qops = { .buf_queue = coda_buf_queue, .start_streaming = coda_start_streaming, .stop_streaming = coda_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int coda_s_ctrl(struct v4l2_ctrl *ctrl) @@ -3346,7 +3344,7 @@ static const struct dev_pm_ops coda_pm_ops = { static struct platform_driver coda_driver = { .probe = coda_probe, - .remove_new = coda_remove, + .remove = coda_remove, .driver = { .name = CODA_NAME, .of_match_table = coda_dt_ids, diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c index d60841c54a8026..2c9d8cbca6e4b7 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -7,6 +7,8 @@ #include "wave5-helper.h" +#define DEFAULT_BS_SIZE(width, height) ((width) * (height) / 8 * 3) + const char *state_to_str(enum vpu_instance_state state) { switch (state) { @@ -58,7 +60,6 @@ int wave5_vpu_release_device(struct file *filp, char *name) { struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data); - struct vpu_device *dev = inst->dev; int ret = 0; v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); @@ -78,18 +79,6 @@ int wave5_vpu_release_device(struct file *filp, } wave5_cleanup_instance(inst); - if (dev->irq < 0) { - ret = mutex_lock_interruptible(&dev->dev_lock); - if (ret) - return ret; - - if (list_empty(&dev->instances)) { - dev_dbg(dev->dev, "Disabling the hrtimer\n"); - hrtimer_cancel(&dev->hrtimer); - } - - mutex_unlock(&dev->dev_lock); - } return ret; } @@ -230,3 +219,25 @@ void wave5_return_bufs(struct vb2_queue *q, u32 state) v4l2_m2m_buf_done(vbuf, state); } } + +void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, + int pix_fmt_type, + unsigned int width, + unsigned int height, + const struct v4l2_frmsize_stepwise *frmsize) +{ + v4l2_apply_frmsize_constraints(&width, &height, frmsize); + + if (pix_fmt_type == VPU_FMT_TYPE_CODEC) { + pix_mp->width = width; + pix_mp->height = height; + pix_mp->num_planes = 1; + pix_mp->plane_fmt[0].bytesperline = 0; + pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_BS_SIZE(width, height), + pix_mp->plane_fmt[0].sizeimage); + } else { + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, width, height); + } + pix_mp->flags = 0; + pix_mp->field = V4L2_FIELD_NONE; +} diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h index 6cee1c14d3ce26..9937fce553fc33 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.h +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h @@ -28,4 +28,9 @@ const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx, const struct vpu_format fmt_list[MAX_FMTS]); enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type); void wave5_return_bufs(struct vb2_queue *q, u32 state); +void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, + int pix_fmt_type, + unsigned int width, + unsigned int height, + const struct v4l2_frmsize_stepwise *frmsize); #endif diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c index c89aafabc74213..c8a90599410980 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-hw.c +++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c @@ -23,6 +23,15 @@ #define W521_FEATURE_AVC_ENCODER BIT(1) #define W521_FEATURE_HEVC_ENCODER BIT(0) +#define ENC_AVC_INTRA_IDR_PARAM_MASK 0x7ff +#define ENC_AVC_INTRA_PERIOD_SHIFT 6 +#define ENC_AVC_IDR_PERIOD_SHIFT 17 +#define ENC_AVC_FORCED_IDR_HEADER_SHIFT 28 + +#define ENC_HEVC_INTRA_QP_SHIFT 3 +#define ENC_HEVC_FORCED_IDR_HEADER_SHIFT 9 +#define ENC_HEVC_INTRA_PERIOD_SHIFT 16 + /* Decoder support fields */ #define W521_FEATURE_AVC_DECODER BIT(3) #define W521_FEATURE_HEVC_DECODER BIT(2) @@ -35,7 +44,7 @@ #define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff) #define REMAP_CTRL_REGISTER_VALUE(index) ( \ - (BIT(31) | (index << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS) \ + (BIT(31) | ((index) << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS)\ ) #define FASTIO_ADDRESS_MASK GENMASK(15, 0) @@ -1219,8 +1228,8 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size) return setup_wave5_properties(dev); } -static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, - size_t size) +int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, + size_t size) { u32 reg_val; struct vpu_buf *common_vb; @@ -1772,12 +1781,19 @@ int wave5_vpu_enc_init_seq(struct vpu_instance *inst) if (inst->std == W_AVC_ENC) vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, p_param->intra_qp | - ((p_param->intra_period & 0x7ff) << 6) | - ((p_param->avc_idr_period & 0x7ff) << 17)); + ((p_param->intra_period & ENC_AVC_INTRA_IDR_PARAM_MASK) + << ENC_AVC_INTRA_PERIOD_SHIFT) | + ((p_param->avc_idr_period & ENC_AVC_INTRA_IDR_PARAM_MASK) + << ENC_AVC_IDR_PERIOD_SHIFT) | + (p_param->forced_idr_header_enable + << ENC_AVC_FORCED_IDR_HEADER_SHIFT)); else if (inst->std == W_HEVC_ENC) vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, - p_param->decoding_refresh_type | (p_param->intra_qp << 3) | - (p_param->intra_period << 16)); + p_param->decoding_refresh_type | + (p_param->intra_qp << ENC_HEVC_INTRA_QP_SHIFT) | + (p_param->forced_idr_header_enable + << ENC_HEVC_FORCED_IDR_HEADER_SHIFT) | + (p_param->intra_period << ENC_HEVC_INTRA_PERIOD_SHIFT)); reg_val = (p_param->rdo_skip << 2) | (p_param->lambda_scaling_enable << 3) | diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index 0c5c9a8de91faa..d3ff420c52ce1c 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -5,116 +5,98 @@ * Copyright (C) 2021-2023 CHIPS&MEDIA INC */ +#include #include "wave5-helper.h" #define VPU_DEC_DEV_NAME "C&M Wave5 VPU decoder" #define VPU_DEC_DRV_NAME "wave5-dec" -#define DEFAULT_SRC_SIZE(width, height) ({ \ - (width) * (height) / 8 * 3; \ -}) +static const struct v4l2_frmsize_stepwise dec_hevc_frmsize = { + .min_width = W5_MIN_DEC_PIC_8_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_8_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_CODEC_STEP_HEIGHT, +}; + +static const struct v4l2_frmsize_stepwise dec_h264_frmsize = { + .min_width = W5_MIN_DEC_PIC_32_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_32_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_CODEC_STEP_HEIGHT, +}; + +static const struct v4l2_frmsize_stepwise dec_raw_frmsize = { + .min_width = W5_MIN_DEC_PIC_8_WIDTH, + .max_width = W5_MAX_DEC_PIC_WIDTH, + .step_width = W5_DEC_RAW_STEP_WIDTH, + .min_height = W5_MIN_DEC_PIC_8_HEIGHT, + .max_height = W5_MAX_DEC_PIC_HEIGHT, + .step_height = W5_DEC_RAW_STEP_HEIGHT, +}; static const struct vpu_format dec_fmt_list[FMT_TYPES][MAX_FMTS] = { [VPU_FMT_TYPE_CODEC] = { { .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_hevc_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_H264, - .max_width = 8192, - .min_width = 32, - .max_height = 4320, - .min_height = 32, + .v4l2_frmsize = &dec_h264_frmsize, }, }, [VPU_FMT_TYPE_RAW] = { { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, - .max_width = 8192, - .min_width = 8, - .max_height = 4320, - .min_height = 8, + .v4l2_frmsize = &dec_raw_frmsize, }, } }; @@ -233,74 +215,6 @@ static void wave5_handle_src_buffer(struct vpu_instance *inst, dma_addr_t rd_ptr inst->remaining_consumed_bytes = consumed_bytes; } -static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width, - unsigned int height) -{ - switch (pix_mp->pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height * 3 / 2; - break; - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height * 2; - break; - case V4L2_PIX_FMT_YUV420M: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[1].sizeimage = width * height / 4; - pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[2].sizeimage = width * height / 4; - break; - case V4L2_PIX_FMT_NV12M: - case V4L2_PIX_FMT_NV21M: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[1].sizeimage = width * height / 2; - break; - case V4L2_PIX_FMT_YUV422M: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[1].sizeimage = width * height / 2; - pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[2].sizeimage = width * height / 2; - break; - case V4L2_PIX_FMT_NV16M: - case V4L2_PIX_FMT_NV61M: - pix_mp->width = round_up(width, 32); - pix_mp->height = round_up(height, 16); - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = width * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[1].sizeimage = width * height; - break; - default: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = 0; - pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_SRC_SIZE(width, height), - pix_mp->plane_fmt[0].sizeimage); - break; - } -} - static int start_decode(struct vpu_instance *inst, u32 *fail_res) { struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; @@ -388,6 +302,8 @@ static int handle_dynamic_resolution_change(struct vpu_instance *inst) } if (p_dec_info->initial_info_obtained) { + const struct vpu_format *vpu_fmt; + inst->conf_win.left = initial_info->pic_crop_rect.left; inst->conf_win.top = initial_info->pic_crop_rect.top; inst->conf_win.width = initial_info->pic_width - @@ -395,10 +311,27 @@ static int handle_dynamic_resolution_change(struct vpu_instance *inst) inst->conf_win.height = initial_info->pic_height - initial_info->pic_crop_rect.top - initial_info->pic_crop_rect.bottom; - wave5_update_pix_fmt(&inst->src_fmt, initial_info->pic_width, - initial_info->pic_height); - wave5_update_pix_fmt(&inst->dst_fmt, initial_info->pic_width, - initial_info->pic_height); + vpu_fmt = wave5_find_vpu_fmt(inst->src_fmt.pixelformat, + dec_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->src_fmt, + VPU_FMT_TYPE_CODEC, + initial_info->pic_width, + initial_info->pic_height, + vpu_fmt->v4l2_frmsize); + + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, + dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, + VPU_FMT_TYPE_RAW, + initial_info->pic_width, + initial_info->pic_height, + vpu_fmt->v4l2_frmsize); } v4l2_event_queue_fh(fh, &vpu_event_src_ch); @@ -518,6 +451,8 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst) if (q_status.report_queue_count == 0 && (q_status.instance_queue_count == 0 || dec_info.sequence_changed)) { dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } } @@ -545,12 +480,12 @@ static int wave5_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_f } fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - fsize->stepwise.min_width = vpu_fmt->min_width; - fsize->stepwise.max_width = vpu_fmt->max_width; - fsize->stepwise.step_width = 1; - fsize->stepwise.min_height = vpu_fmt->min_height; - fsize->stepwise.max_height = vpu_fmt->max_height; - fsize->stepwise.step_height = 1; + fsize->stepwise.min_width = vpu_fmt->v4l2_frmsize->min_width; + fsize->stepwise.max_width = vpu_fmt->v4l2_frmsize->max_width; + fsize->stepwise.step_width = W5_DEC_CODEC_STEP_WIDTH; + fsize->stepwise.min_height = vpu_fmt->v4l2_frmsize->min_height; + fsize->stepwise.max_height = vpu_fmt->v4l2_frmsize->max_height; + fsize->stepwise.step_height = W5_DEC_CODEC_STEP_HEIGHT; return 0; } @@ -573,6 +508,7 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo { struct vpu_instance *inst = wave5_to_vpu_inst(fh); struct dec_info *p_dec_info = &inst->codec_info->dec_info; + const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; int width, height; @@ -586,14 +522,12 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo width = inst->dst_fmt.width; height = inst->dst_fmt.height; f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; - f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; + frmsize = &dec_raw_frmsize; } else { - const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt); - - width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); - height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; - f->fmt.pix_mp.num_planes = info->mem_planes; + frmsize = vpu_fmt->v4l2_frmsize; } if (p_dec_info->initial_info_obtained) { @@ -601,9 +535,8 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo height = inst->dst_fmt.height; } - wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); - f->fmt.pix_mp.flags = 0; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW, + width, height, frmsize); f->fmt.pix_mp.colorspace = inst->colorspace; f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; f->fmt.pix_mp.quantization = inst->quantization; @@ -715,7 +648,9 @@ static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; + int width, height; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n", @@ -724,20 +659,19 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_CODEC]); if (!vpu_fmt) { + width = inst->src_fmt.width; + height = inst->src_fmt.height; f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; - f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; - wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height); + frmsize = &dec_hevc_frmsize; } else { - int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); - int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); - + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; - f->fmt.pix_mp.num_planes = 1; - wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + frmsize = vpu_fmt->v4l2_frmsize; } - f->fmt.pix_mp.flags = 0; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC, + width, height, frmsize); return 0; } @@ -745,6 +679,7 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; int i, ret; dev_dbg(inst->dev->dev, @@ -779,7 +714,13 @@ static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_form inst->quantization = f->fmt.pix_mp.quantization; inst->xfer_func = f->fmt.pix_mp.xfer_func; - wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height); + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, dec_fmt_list[VPU_FMT_TYPE_RAW]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_RAW, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + vpu_fmt->v4l2_frmsize); return 0; } @@ -1002,6 +943,7 @@ static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buff struct vpu_instance *inst = vb2_get_drv_priv(q); struct v4l2_pix_format_mplane inst_format = (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt; + unsigned int i; dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__, *num_buffers, *num_planes, q->type); @@ -1015,31 +957,9 @@ static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buff if (*num_buffers < inst->fbc_buf_count) *num_buffers = inst->fbc_buf_count; - if (*num_planes == 1) { - if (inst->output_format == FORMAT_422) - sizes[0] = inst_format.width * inst_format.height * 2; - else - sizes[0] = inst_format.width * inst_format.height * 3 / 2; - dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]); - } else if (*num_planes == 2) { - sizes[0] = inst_format.width * inst_format.height; - if (inst->output_format == FORMAT_422) - sizes[1] = inst_format.width * inst_format.height; - else - sizes[1] = inst_format.width * inst_format.height / 2; - dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u\n", - __func__, sizes[0], sizes[1]); - } else if (*num_planes == 3) { - sizes[0] = inst_format.width * inst_format.height; - if (inst->output_format == FORMAT_422) { - sizes[1] = inst_format.width * inst_format.height / 2; - sizes[2] = inst_format.width * inst_format.height / 2; - } else { - sizes[1] = inst_format.width * inst_format.height / 4; - sizes[2] = inst_format.width * inst_format.height / 4; - } - dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u | size[2]: %u\n", - __func__, sizes[0], sizes[1], sizes[2]); + for (i = 0; i < *num_planes; i++) { + sizes[i] = inst_format.plane_fmt[i].sizeimage; + dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]); } } @@ -1398,6 +1318,7 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count int ret = 0; dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); v4l2_m2m_update_start_streaming_state(m2m_ctx, q); @@ -1429,13 +1350,15 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count if (ret) goto return_buffers; } - + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); return ret; free_bitstream_vbuf: wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); return_buffers: wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); + pm_runtime_put_autosuspend(inst->dev->dev); return ret; } @@ -1521,6 +1444,7 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) bool check_cmd = TRUE; dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); while (check_cmd) { struct queue_status_info q_status; @@ -1544,12 +1468,13 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) streamoff_output(q); else streamoff_capture(q); + + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); } static const struct vb2_ops wave5_vpu_dec_vb2_ops = { .queue_setup = wave5_vpu_dec_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_queue = wave5_vpu_dec_buf_queue, .start_streaming = wave5_vpu_dec_start_streaming, .stop_streaming = wave5_vpu_dec_stop_streaming, @@ -1558,20 +1483,15 @@ static const struct vb2_ops wave5_vpu_dec_vb2_ops = { static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, struct v4l2_pix_format_mplane *dst_fmt) { - unsigned int dst_pix_fmt = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; - const struct v4l2_format_info *dst_fmt_info = v4l2_format_info(dst_pix_fmt); - src_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; - src_fmt->field = V4L2_FIELD_NONE; - src_fmt->flags = 0; - src_fmt->num_planes = 1; - wave5_update_pix_fmt(src_fmt, 720, 480); - - dst_fmt->pixelformat = dst_pix_fmt; - dst_fmt->field = V4L2_FIELD_NONE; - dst_fmt->flags = 0; - dst_fmt->num_planes = dst_fmt_info->mem_planes; - wave5_update_pix_fmt(dst_fmt, 736, 480); + wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_CODEC, + W5_DEF_DEC_PIC_WIDTH, W5_DEF_DEC_PIC_HEIGHT, + &dec_hevc_frmsize); + + dst_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; + wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_RAW, + W5_DEF_DEC_PIC_WIDTH, W5_DEF_DEC_PIC_HEIGHT, + &dec_raw_frmsize); } static int wave5_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) @@ -1630,7 +1550,7 @@ static void wave5_vpu_dec_device_run(void *priv) int ret = 0; dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__); - + pm_runtime_resume_and_get(inst->dev->dev); ret = fill_ringbuffer(inst); if (ret) { dev_warn(inst->dev->dev, "Filling ring buffer failed\n"); @@ -1713,6 +1633,8 @@ static void wave5_vpu_dec_device_run(void *priv) finish_job_and_return: dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } @@ -1879,9 +1801,8 @@ static int wave5_vpu_open_dec(struct file *filp) if (ret) goto cleanup_inst; - if (dev->irq < 0 && !hrtimer_active(&dev->hrtimer) && list_empty(&dev->instances)) - hrtimer_start(&dev->hrtimer, ns_to_ktime(dev->vpu_poll_interval * NSEC_PER_MSEC), - HRTIMER_MODE_REL_PINNED); + if (list_empty(&dev->instances)) + pm_runtime_use_autosuspend(inst->dev->dev); list_add_tail(&inst->list, &dev->instances); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index 3e35a05c2d8df5..1e5fc5f8b856c5 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -5,70 +5,90 @@ * Copyright (C) 2021-2023 CHIPS&MEDIA INC */ +#include #include "wave5-helper.h" #define VPU_ENC_DEV_NAME "C&M Wave5 VPU encoder" #define VPU_ENC_DRV_NAME "wave5-enc" +static const struct v4l2_frmsize_stepwise enc_frmsize[FMT_TYPES] = { + [VPU_FMT_TYPE_CODEC] = { + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .step_width = W5_ENC_CODEC_STEP_WIDTH, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .step_height = W5_ENC_CODEC_STEP_HEIGHT, + }, + [VPU_FMT_TYPE_RAW] = { + .min_width = W5_MIN_ENC_PIC_WIDTH, + .max_width = W5_MAX_ENC_PIC_WIDTH, + .step_width = W5_ENC_RAW_STEP_WIDTH, + .min_height = W5_MIN_ENC_PIC_HEIGHT, + .max_height = W5_MAX_ENC_PIC_HEIGHT, + .step_height = W5_ENC_RAW_STEP_HEIGHT, + }, +}; + static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = { [VPU_FMT_TYPE_CODEC] = { { .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_H264, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC], }, }, [VPU_FMT_TYPE_RAW] = { { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV12, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV21, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, { .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M, - .max_width = W5_MAX_ENC_PIC_WIDTH, - .min_width = W5_MIN_ENC_PIC_WIDTH, - .max_height = W5_MAX_ENC_PIC_HEIGHT, - .min_height = W5_MIN_ENC_PIC_HEIGHT, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], + }, + { + .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M, + .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW], }, } }; @@ -105,46 +125,6 @@ static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state return -EINVAL; } -static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width, - unsigned int height) -{ - switch (pix_mp->pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height * 3 / 2; - break; - case V4L2_PIX_FMT_YUV420M: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 4; - pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2; - pix_mp->plane_fmt[2].sizeimage = round_up(width, 32) * height / 4; - break; - case V4L2_PIX_FMT_NV12M: - case V4L2_PIX_FMT_NV21M: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height; - pix_mp->plane_fmt[1].bytesperline = round_up(width, 32); - pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 2; - break; - default: - pix_mp->width = width; - pix_mp->height = height; - pix_mp->plane_fmt[0].bytesperline = 0; - pix_mp->plane_fmt[0].sizeimage = width * height / 8 * 3; - break; - } -} - static int start_encode(struct vpu_instance *inst, u32 *fail_res) { struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; @@ -153,13 +133,26 @@ static int start_encode(struct vpu_instance *inst, u32 *fail_res) struct vb2_v4l2_buffer *dst_buf; struct frame_buffer frame_buf; struct enc_param pic_param; - u32 stride = ALIGN(inst->dst_fmt.width, 32); - u32 luma_size = (stride * inst->dst_fmt.height); - u32 chroma_size = ((stride / 2) * (inst->dst_fmt.height / 2)); + const struct v4l2_format_info *info; + u32 stride = inst->src_fmt.plane_fmt[0].bytesperline; + u32 luma_size = 0; + u32 chroma_size = 0; memset(&pic_param, 0, sizeof(struct enc_param)); memset(&frame_buf, 0, sizeof(struct frame_buffer)); + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + if (info->mem_planes == 1) { + luma_size = stride * inst->dst_fmt.height; + chroma_size = luma_size / (info->hdiv * info->vdiv); + } else { + luma_size = inst->src_fmt.plane_fmt[0].sizeimage; + chroma_size = inst->src_fmt.plane_fmt[1].sizeimage; + } + dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx); if (!dst_buf) { dev_dbg(inst->dev->dev, "%s: No destination buffer found\n", __func__); @@ -359,13 +352,8 @@ static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_f return -EINVAL; } - fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - fsize->stepwise.min_width = vpu_fmt->min_width; - fsize->stepwise.max_width = vpu_fmt->max_width; - fsize->stepwise.step_width = 1; - fsize->stepwise.min_height = vpu_fmt->min_height; - fsize->stepwise.max_height = vpu_fmt->max_height; - fsize->stepwise.step_height = 1; + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = enc_frmsize[VPU_FMT_TYPE_CODEC]; return 0; } @@ -390,7 +378,9 @@ static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; + int width, height; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, @@ -398,20 +388,19 @@ static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]); if (!vpu_fmt) { + width = inst->dst_fmt.width; + height = inst->dst_fmt.height; f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat; - f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes; - wave5_update_pix_fmt(&f->fmt.pix_mp, inst->dst_fmt.width, inst->dst_fmt.height); + frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC]; } else { - int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); - int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); - + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; - f->fmt.pix_mp.num_planes = 1; - wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + frmsize = vpu_fmt->v4l2_frmsize; } - f->fmt.pix_mp.flags = 0; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC, + width, height, frmsize); f->fmt.pix_mp.colorspace = inst->colorspace; f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc; f->fmt.pix_mp.quantization = inst->quantization; @@ -498,7 +487,9 @@ static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; + int width, height; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height, @@ -506,28 +497,27 @@ static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_fo vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_RAW]); if (!vpu_fmt) { + width = inst->src_fmt.width; + height = inst->src_fmt.height; f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat; - f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes; - wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height); + frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW]; } else { - int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width); - int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height); - const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt); - + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt; - f->fmt.pix_mp.num_planes = info->mem_planes; - wave5_update_pix_fmt(&f->fmt.pix_mp, width, height); + frmsize = vpu_fmt->v4l2_frmsize; } - f->fmt.pix_mp.flags = 0; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; - + wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW, + width, height, frmsize); return 0; } static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_instance *inst = wave5_to_vpu_inst(fh); + const struct vpu_format *vpu_fmt; + const struct v4l2_format_info *info; int i, ret; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", @@ -549,16 +539,20 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage; } - if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 || - inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M) { - inst->cbcr_interleave = true; - inst->nv21 = false; - } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 || - inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) { - inst->cbcr_interleave = true; + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + inst->cbcr_interleave = (info->comp_planes == 2) ? true : false; + + switch (inst->src_fmt.pixelformat) { + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV61M: inst->nv21 = true; - } else { - inst->cbcr_interleave = false; + break; + default: inst->nv21 = false; } @@ -567,7 +561,15 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form inst->quantization = f->fmt.pix_mp.quantization; inst->xfer_func = f->fmt.pix_mp.xfer_func; - wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height); + vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]); + if (!vpu_fmt) + return -EINVAL; + + wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_CODEC, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + vpu_fmt->v4l2_frmsize); + inst->conf_win.width = inst->dst_fmt.width; + inst->conf_win.height = inst->dst_fmt.height; return 0; } @@ -583,12 +585,17 @@ static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_se switch (s->target) { case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP: s->r.left = 0; s->r.top = 0; s->r.width = inst->dst_fmt.width; s->r.height = inst->dst_fmt.height; break; + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + s->r.width = inst->conf_win.width; + s->r.height = inst->conf_win.height; + break; default: return -EINVAL; } @@ -611,8 +618,10 @@ static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_se s->r.left = 0; s->r.top = 0; - s->r.width = inst->src_fmt.width; - s->r.height = inst->src_fmt.height; + s->r.width = min(s->r.width, inst->dst_fmt.width); + s->r.height = min(s->r.height, inst->dst_fmt.height); + + inst->conf_win = s->r; return 0; } @@ -1061,6 +1070,9 @@ static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: inst->enc_param.entropy_coding_mode = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + inst->enc_param.forced_idr_header_enable = ctrl->val; + break; case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: break; default: @@ -1125,13 +1137,23 @@ static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(m2m_ctx, vbuf); } -static void wave5_set_enc_openparam(struct enc_open_param *open_param, - struct vpu_instance *inst) +static int wave5_set_enc_openparam(struct enc_open_param *open_param, + struct vpu_instance *inst) { struct enc_wave_param input = inst->enc_param; + const struct v4l2_format_info *info; u32 num_ctu_row = ALIGN(inst->dst_fmt.height, 64) / 64; u32 num_mb_row = ALIGN(inst->dst_fmt.height, 16) / 16; + info = v4l2_format_info(inst->src_fmt.pixelformat); + if (!info) + return -EINVAL; + + if (info->hdiv == 2 && info->vdiv == 1) + open_param->src_format = FORMAT_422; + else + open_param->src_format = FORMAT_420; + open_param->wave_param.gop_preset_idx = PRESET_IDX_IPP_SINGLE; open_param->wave_param.hvs_qp_scale = 2; open_param->wave_param.hvs_max_delta_qp = 10; @@ -1147,8 +1169,8 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param, open_param->wave_param.lambda_scaling_enable = 1; open_param->line_buf_int_en = true; - open_param->pic_width = inst->dst_fmt.width; - open_param->pic_height = inst->dst_fmt.height; + open_param->pic_width = inst->conf_win.width; + open_param->pic_height = inst->conf_win.height; open_param->frame_rate_info = inst->frame_rate; open_param->rc_enable = inst->rc_enable; if (inst->rc_enable) { @@ -1219,6 +1241,9 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param, else open_param->wave_param.intra_refresh_arg = num_ctu_row; } + open_param->wave_param.forced_idr_header_enable = input.forced_idr_header_enable; + + return 0; } static int initialize_sequence(struct vpu_instance *inst) @@ -1306,6 +1331,7 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; int ret = 0; + pm_runtime_resume_and_get(inst->dev->dev); v4l2_m2m_update_start_streaming_state(m2m_ctx, q); if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { @@ -1313,7 +1339,12 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count memset(&open_param, 0, sizeof(struct enc_open_param)); - wave5_set_enc_openparam(&open_param, inst); + ret = wave5_set_enc_openparam(&open_param, inst); + if (ret) { + dev_dbg(inst->dev->dev, "%s: wave5_set_enc_openparam, fail: %d\n", + __func__, ret); + goto return_buffers; + } ret = wave5_vpu_enc_open(inst, &open_param); if (ret) { @@ -1360,9 +1391,13 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count if (ret) goto return_buffers; + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); return 0; return_buffers: wave5_return_bufs(q, VB2_BUF_STATE_QUEUED); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); return ret; } @@ -1404,6 +1439,7 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) */ dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); + pm_runtime_resume_and_get(inst->dev->dev); if (wave5_vpu_both_queues_are_streaming(inst)) switch_state(inst, VPU_INST_STATE_STOP); @@ -1428,12 +1464,13 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) streamoff_output(inst, q); else streamoff_capture(inst, q); + + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); } static const struct vb2_ops wave5_vpu_enc_vb2_ops = { .queue_setup = wave5_vpu_enc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_queue = wave5_vpu_enc_buf_queue, .start_streaming = wave5_vpu_enc_start_streaming, .stop_streaming = wave5_vpu_enc_stop_streaming, @@ -1442,20 +1479,15 @@ static const struct vb2_ops wave5_vpu_enc_vb2_ops = { static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, struct v4l2_pix_format_mplane *dst_fmt) { - unsigned int src_pix_fmt = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; - const struct v4l2_format_info *src_fmt_info = v4l2_format_info(src_pix_fmt); - - src_fmt->pixelformat = src_pix_fmt; - src_fmt->field = V4L2_FIELD_NONE; - src_fmt->flags = 0; - src_fmt->num_planes = src_fmt_info->mem_planes; - wave5_update_pix_fmt(src_fmt, 416, 240); + src_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; + wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_RAW, + W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT, + &enc_frmsize[VPU_FMT_TYPE_RAW]); dst_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt; - dst_fmt->field = V4L2_FIELD_NONE; - dst_fmt->flags = 0; - dst_fmt->num_planes = 1; - wave5_update_pix_fmt(dst_fmt, 416, 240); + wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_CODEC, + W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT, + &enc_frmsize[VPU_FMT_TYPE_CODEC]); } static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) @@ -1474,6 +1506,7 @@ static void wave5_vpu_enc_device_run(void *priv) u32 fail_res = 0; int ret = 0; + pm_runtime_resume_and_get(inst->dev->dev); switch (inst->state) { case VPU_INST_STATE_PIC_RUN: ret = start_encode(inst, &fail_res); @@ -1487,6 +1520,8 @@ static void wave5_vpu_enc_device_run(void *priv) break; } dev_dbg(inst->dev->dev, "%s: leave with active job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); return; default: WARN(1, "Execution of a job in state %s is invalid.\n", @@ -1494,6 +1529,8 @@ static void wave5_vpu_enc_device_run(void *priv) break; } dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__); + pm_runtime_mark_last_busy(inst->dev->dev); + pm_runtime_put_autosuspend(inst->dev->dev); v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } @@ -1701,6 +1738,9 @@ static int wave5_vpu_open_enc(struct file *filp) 0, 1, 1, 0); v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1); + v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + 0, 1, 1, 0); if (v4l2_ctrl_hdl->error) { ret = -ENODEV; @@ -1711,6 +1751,8 @@ static int wave5_vpu_open_enc(struct file *filp) v4l2_ctrl_handler_setup(v4l2_ctrl_hdl); wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt); + inst->conf_win.width = inst->dst_fmt.width; + inst->conf_win.height = inst->dst_fmt.height; inst->colorspace = V4L2_COLORSPACE_REC709; inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; inst->quantization = V4L2_QUANTIZATION_DEFAULT; @@ -1732,9 +1774,8 @@ static int wave5_vpu_open_enc(struct file *filp) if (ret) goto cleanup_inst; - if (dev->irq < 0 && !hrtimer_active(&dev->hrtimer) && list_empty(&dev->instances)) - hrtimer_start(&dev->hrtimer, ns_to_ktime(dev->vpu_poll_interval * NSEC_PER_MSEC), - HRTIMER_MODE_REL_PINNED); + if (list_empty(&dev->instances)) + pm_runtime_use_autosuspend(inst->dev->dev); list_add_tail(&inst->list, &dev->instances); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c index 7273254ecb0349..6b294a2d671781 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "wave5-vpu.h" #include "wave5-regdefine.h" @@ -153,6 +154,45 @@ static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name, return 0; } +static __maybe_unused int wave5_pm_suspend(struct device *dev) +{ + struct vpu_device *vpu = dev_get_drvdata(dev); + + if (pm_runtime_suspended(dev)) + return 0; + + if (vpu->irq < 0) + hrtimer_cancel(&vpu->hrtimer); + + wave5_vpu_sleep_wake(dev, true, NULL, 0); + clk_bulk_disable_unprepare(vpu->num_clks, vpu->clks); + + return 0; +} + +static __maybe_unused int wave5_pm_resume(struct device *dev) +{ + struct vpu_device *vpu = dev_get_drvdata(dev); + int ret = 0; + + wave5_vpu_sleep_wake(dev, false, NULL, 0); + ret = clk_bulk_prepare_enable(vpu->num_clks, vpu->clks); + if (ret) { + dev_err(dev, "Enabling clocks, fail: %d\n", ret); + return ret; + } + + if (vpu->irq < 0 && !hrtimer_active(&vpu->hrtimer)) + hrtimer_start(&vpu->hrtimer, ns_to_ktime(vpu->vpu_poll_interval * NSEC_PER_MSEC), + HRTIMER_MODE_REL_PINNED); + + return ret; +} + +static const struct dev_pm_ops wave5_pm_ops = { + SET_RUNTIME_PM_OPS(wave5_pm_suspend, wave5_pm_resume, NULL) +}; + static int wave5_vpu_probe(struct platform_device *pdev) { int ret; @@ -281,6 +321,12 @@ static int wave5_vpu_probe(struct platform_device *pdev) (match_data->flags & WAVE5_IS_DEC) ? "'DECODE'" : ""); dev_info(&pdev->dev, "Product Code: 0x%x\n", dev->product_code); dev_info(&pdev->dev, "Firmware Revision: %u\n", fw_revision); + + pm_runtime_set_autosuspend_delay(&pdev->dev, 100); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + wave5_vpu_sleep_wake(&pdev->dev, true, NULL, 0); + return 0; err_enc_unreg: @@ -310,6 +356,9 @@ static void wave5_vpu_remove(struct platform_device *pdev) hrtimer_cancel(&dev->hrtimer); } + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + mutex_destroy(&dev->dev_lock); mutex_destroy(&dev->hw_lock); reset_control_assert(dev->resets); @@ -337,9 +386,10 @@ static struct platform_driver wave5_vpu_driver = { .driver = { .name = VPU_PLATFORM_DEVICE_NAME, .of_match_table = of_match_ptr(wave5_dt_ids), + .pm = &wave5_pm_ops, }, .probe = wave5_vpu_probe, - .remove_new = wave5_vpu_remove, + .remove = wave5_vpu_remove, }; module_platform_driver(wave5_vpu_driver); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h index 32b7fd3730b5f4..3847332551fc06 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h @@ -38,10 +38,7 @@ enum vpu_fmt_type { struct vpu_format { unsigned int v4l2_pix_fmt; - unsigned int max_width; - unsigned int min_width; - unsigned int max_height; - unsigned int min_height; + const struct v4l2_frmsize_stepwise *v4l2_frmsize; }; static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh) diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c index 1a3efb638dde5a..e16b990041c2e4 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c @@ -6,6 +6,8 @@ */ #include +#include +#include #include "wave5-vpuapi.h" #include "wave5-regdefine.h" #include "wave5.h" @@ -195,14 +197,20 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res) int retry = 0; struct vpu_device *vpu_dev = inst->dev; int i; + int inst_count = 0; + struct vpu_instance *inst_elm; *fail_res = 0; if (!inst->codec_info) return -EINVAL; + pm_runtime_resume_and_get(inst->dev->dev); + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); - if (ret) + if (ret) { + pm_runtime_put_sync(inst->dev->dev); return ret; + } do { ret = wave5_vpu_dec_finish_seq(inst, fail_res); @@ -232,9 +240,14 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res) wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_task); + list_for_each_entry(inst_elm, &vpu_dev->instances, list) + inst_count++; + if (inst_count == 1) + pm_runtime_dont_use_autosuspend(vpu_dev->dev); + unlock_and_return: mutex_unlock(&vpu_dev->hw_lock); - + pm_runtime_put_sync(inst->dev->dev); return ret; } @@ -697,25 +710,33 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) int ret; int retry = 0; struct vpu_device *vpu_dev = inst->dev; + int inst_count = 0; + struct vpu_instance *inst_elm; *fail_res = 0; if (!inst->codec_info) return -EINVAL; + pm_runtime_resume_and_get(inst->dev->dev); + ret = mutex_lock_interruptible(&vpu_dev->hw_lock); - if (ret) + if (ret) { + pm_runtime_resume_and_get(inst->dev->dev); return ret; + } do { ret = wave5_vpu_enc_finish_seq(inst, fail_res); if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) { dev_warn(inst->dev->dev, "enc_finish_seq timed out\n"); + pm_runtime_resume_and_get(inst->dev->dev); mutex_unlock(&vpu_dev->hw_lock); return ret; } if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING && retry++ >= MAX_FIRMWARE_CALL_RETRY) { + pm_runtime_resume_and_get(inst->dev->dev); mutex_unlock(&vpu_dev->hw_lock); return -ETIMEDOUT; } @@ -734,7 +755,13 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res) wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task); + list_for_each_entry(inst_elm, &vpu_dev->instances, list) + inst_count++; + if (inst_count == 1) + pm_runtime_dont_use_autosuspend(vpu_dev->dev); + mutex_unlock(&vpu_dev->hw_lock); + pm_runtime_put_sync(inst->dev->dev); return 0; } diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h index d2370511faf89b..45615c15beca32 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h @@ -568,6 +568,7 @@ struct enc_wave_param { u32 lambda_scaling_enable: 1; /* enable lambda scaling using custom GOP */ u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */ u32 mb_level_rc_enable: 1; /* enable MB-level rate control */ + u32 forced_idr_header_enable: 1; /* enable header encoding before IDR frame */ }; struct enc_open_param { diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h index e4bc2e467cb52f..1ea9f5f314995d 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h @@ -32,10 +32,29 @@ #define MAX_NUM_INSTANCE 32 -#define W5_MIN_ENC_PIC_WIDTH 256 -#define W5_MIN_ENC_PIC_HEIGHT 128 -#define W5_MAX_ENC_PIC_WIDTH 8192 -#define W5_MAX_ENC_PIC_HEIGHT 8192 +#define W5_DEF_DEC_PIC_WIDTH 720U +#define W5_DEF_DEC_PIC_HEIGHT 480U +#define W5_MIN_DEC_PIC_8_WIDTH 8U +#define W5_MIN_DEC_PIC_8_HEIGHT 8U +#define W5_MIN_DEC_PIC_32_WIDTH 32U +#define W5_MIN_DEC_PIC_32_HEIGHT 32U +#define W5_MAX_DEC_PIC_WIDTH 8192U +#define W5_MAX_DEC_PIC_HEIGHT 4320U +#define W5_DEC_CODEC_STEP_WIDTH 1U +#define W5_DEC_CODEC_STEP_HEIGHT 1U +#define W5_DEC_RAW_STEP_WIDTH 32U +#define W5_DEC_RAW_STEP_HEIGHT 16U + +#define W5_DEF_ENC_PIC_WIDTH 416U +#define W5_DEF_ENC_PIC_HEIGHT 240U +#define W5_MIN_ENC_PIC_WIDTH 256U +#define W5_MIN_ENC_PIC_HEIGHT 128U +#define W5_MAX_ENC_PIC_WIDTH 8192U +#define W5_MAX_ENC_PIC_HEIGHT 8192U +#define W5_ENC_CODEC_STEP_WIDTH 8U +#define W5_ENC_CODEC_STEP_HEIGHT 8U +#define W5_ENC_RAW_STEP_WIDTH 32U +#define W5_ENC_RAW_STEP_HEIGHT 16U // application specific configuration #define VPU_ENC_TIMEOUT 60000 diff --git a/drivers/media/platform/chips-media/wave5/wave5.h b/drivers/media/platform/chips-media/wave5/wave5.h index 2a29b9164f9799..2caab356f3e1eb 100644 --- a/drivers/media/platform/chips-media/wave5/wave5.h +++ b/drivers/media/platform/chips-media/wave5/wave5.h @@ -62,6 +62,9 @@ int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision); int wave5_vpu_init(struct device *dev, u8 *fw, size_t size); +int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code, + size_t size); + int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode); int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param); diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c index 187f2d8abfbb5d..c194f830577f9a 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.c +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c @@ -1593,8 +1593,6 @@ static const struct vb2_ops e5010_video_ops = { .buf_finish = e5010_buf_finish, .buf_prepare = e5010_buf_prepare, .buf_out_validate = e5010_buf_out_validate, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = e5010_start_streaming, .stop_streaming = e5010_stop_streaming, }; @@ -1619,7 +1617,7 @@ MODULE_DEVICE_TABLE(of, e5010_of_match); static struct platform_driver e5010_driver = { .probe = e5010_probe, - .remove_new = e5010_remove, + .remove = e5010_remove, .driver = { .name = E5010_MODULE_NAME, .of_match_table = e5010_of_match, diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c index f118aaac0b3893..bef1e7137f23f0 100644 --- a/drivers/media/platform/intel/pxa_camera.c +++ b/drivers/media/platform/intel/pxa_camera.c @@ -1504,8 +1504,6 @@ static const struct vb2_ops pxac_vb2_ops = { .buf_cleanup = pxac_vb2_cleanup, .start_streaming = pxac_vb2_start_streaming, .stop_streaming = pxac_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev) @@ -2460,7 +2458,7 @@ static struct platform_driver pxa_camera_driver = { .of_match_table = pxa_camera_of_match, }, .probe = pxa_camera_probe, - .remove_new = pxa_camera_remove, + .remove = pxa_camera_remove, }; module_platform_driver(pxa_camera_driver); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 5adcef80c69879..5188f318909667 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -784,8 +784,6 @@ static const struct vb2_ops deinterlace_qops = { .queue_setup = deinterlace_queue_setup, .buf_prepare = deinterlace_buf_prepare, .buf_queue = deinterlace_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -993,7 +991,7 @@ static void deinterlace_remove(struct platform_device *pdev) static struct platform_driver deinterlace_pdrv = { .probe = deinterlace_probe, - .remove_new = deinterlace_remove, + .remove = deinterlace_remove, .driver = { .name = MEM2MEM_NAME, }, diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c index c81593c969e057..9ec01228f90731 100644 --- a/drivers/media/platform/marvell/mcam-core.c +++ b/drivers/media/platform/marvell/mcam-core.c @@ -1203,8 +1203,6 @@ static const struct vb2_ops mcam_vb2_ops = { .buf_queue = mcam_vb_buf_queue, .start_streaming = mcam_vb_start_streaming, .stop_streaming = mcam_vb_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; @@ -1267,8 +1265,6 @@ static const struct vb2_ops mcam_vb2_sg_ops = { .buf_cleanup = mcam_vb_sg_buf_cleanup, .start_streaming = mcam_vb_start_streaming, .stop_streaming = mcam_vb_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; #endif /* MCAM_MODE_DMA_SG */ diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c index ff9d151121d5eb..3fd4fc1b9c48f6 100644 --- a/drivers/media/platform/marvell/mmp-driver.c +++ b/drivers/media/platform/marvell/mmp-driver.c @@ -359,7 +359,7 @@ MODULE_DEVICE_TABLE(of, mmpcam_of_match); static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, - .remove_new = mmpcam_remove, + .remove = mmpcam_remove, .driver = { .name = "mmp-camera", .of_match_table = mmpcam_of_match, diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index ac48658e2de403..834d2a354692df 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -884,8 +884,6 @@ static const struct vb2_ops mtk_jpeg_dec_qops = { .queue_setup = mtk_jpeg_queue_setup, .buf_prepare = mtk_jpeg_buf_prepare, .buf_queue = mtk_jpeg_dec_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = mtk_jpeg_dec_stop_streaming, }; @@ -893,8 +891,6 @@ static const struct vb2_ops mtk_jpeg_enc_qops = { .queue_setup = mtk_jpeg_queue_setup, .buf_prepare = mtk_jpeg_buf_prepare, .buf_queue = mtk_jpeg_enc_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = mtk_jpeg_enc_stop_streaming, }; @@ -1293,6 +1289,11 @@ static int mtk_jpeg_single_core_init(struct platform_device *pdev, return 0; } +static void mtk_jpeg_destroy_workqueue(void *data) +{ + destroy_workqueue(data); +} + static int mtk_jpeg_probe(struct platform_device *pdev) { struct mtk_jpeg_dev *jpeg; @@ -1337,6 +1338,11 @@ static int mtk_jpeg_probe(struct platform_device *pdev) | WQ_FREEZABLE); if (!jpeg->workqueue) return -EINVAL; + ret = devm_add_action_or_reset(&pdev->dev, + mtk_jpeg_destroy_workqueue, + jpeg->workqueue); + if (ret) + return ret; } ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); @@ -1950,7 +1956,7 @@ MODULE_DEVICE_TABLE(of, mtk_jpeg_match); static struct platform_driver mtk_jpeg_driver = { .probe = mtk_jpeg_probe, - .remove_new = mtk_jpeg_remove, + .remove = mtk_jpeg_remove, .driver = { .name = MTK_JPEG_NAME, .of_match_table = mtk_jpeg_match, diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c index 4a6ee211e18f97..2c5d74939d0a92 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -578,11 +578,6 @@ static int mtk_jpegdec_hw_init_irq(struct mtk_jpegdec_comp_dev *dev) return 0; } -static void mtk_jpegdec_destroy_workqueue(void *data) -{ - destroy_workqueue(data); -} - static int mtk_jpegdec_hw_probe(struct platform_device *pdev) { struct mtk_jpegdec_clk *jpegdec_clk; @@ -606,12 +601,6 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev) dev->plat_dev = pdev; dev->dev = &pdev->dev; - ret = devm_add_action_or_reset(&pdev->dev, - mtk_jpegdec_destroy_workqueue, - master_dev->workqueue); - if (ret) - return ret; - spin_lock_init(&dev->hw_lock); dev->hw_state = MTK_JPEG_HW_IDLE; diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c index 917cdf38f230e7..80fdc6ff57e0ec 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c @@ -298,7 +298,7 @@ static const struct dev_pm_ops mtk_mdp_pm_ops = { static struct platform_driver mtk_mdp_driver = { .probe = mtk_mdp_probe, - .remove_new = mtk_mdp_remove, + .remove = mtk_mdp_remove, .driver = { .name = MTK_MDP_MODULE_NAME, .pm = &mtk_mdp_pm_ops, diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c index f14779e7596e51..28c998bd3a81c4 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c @@ -584,8 +584,6 @@ static const struct vb2_ops mtk_mdp_m2m_qops = { .buf_queue = mtk_mdp_m2m_buf_queue, .stop_streaming = mtk_mdp_m2m_stop_streaming, .start_streaming = mtk_mdp_m2m_start_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int mtk_mdp_m2m_querycap(struct file *file, void *fh, diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 37e7b985d52cca..5e94ff0d0756fc 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -413,7 +413,7 @@ static const struct dev_pm_ops mdp_pm_ops = { static struct platform_driver mdp_driver = { .probe = mdp_probe, - .remove_new = mdp_remove, + .remove = mdp_remove, .driver = { .name = MDP_MODULE_NAME, .pm = &mdp_pm_ops, diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c index 0e69128a3772c3..59ce5cce069836 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -266,8 +266,6 @@ static void mdp_m2m_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops mdp_m2m_qops = { .queue_setup = mdp_m2m_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = mdp_m2m_buf_prepare, .start_streaming = mdp_m2m_start_streaming, .stop_streaming = mdp_m2m_stop_streaming, diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c index 2073781ccadb15..9247d92d431d85 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c @@ -591,7 +591,7 @@ static void mtk_vcodec_dec_remove(struct platform_device *pdev) static struct platform_driver mtk_vcodec_dec_driver = { .probe = mtk_vcodec_probe, - .remove_new = mtk_vcodec_dec_remove, + .remove = mtk_vcodec_dec_remove, .driver = { .name = MTK_VCODEC_DEC_NAME, .of_match_table = mtk_vcodec_match, diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c index e62c1c18758bb1..aa9bdee7a96ca9 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c @@ -598,8 +598,6 @@ static void mtk_init_vdec_params(struct mtk_vcodec_dec_ctx *ctx) static const struct vb2_ops mtk_vdec_frame_vb2_ops = { .queue_setup = vb2ops_vdec_queue_setup, .buf_prepare = vb2ops_vdec_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vb2ops_vdec_start_streaming, .buf_queue = vb2ops_vdec_stateful_buf_queue, diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index 3307dc15fc1dfe..afa224da0f4165 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -856,8 +856,6 @@ static int vb2ops_vdec_out_buf_validate(struct vb2_buffer *vb) static const struct vb2_ops mtk_vdec_request_vb2_ops = { .queue_setup = vb2ops_vdec_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vb2ops_vdec_start_streaming, .stop_streaming = vb2ops_vdec_stop_streaming, diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c index eea709d9382091..47c302745c1de9 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c @@ -1188,7 +1188,8 @@ static int vdec_vp9_slice_setup_lat(struct vdec_vp9_slice_instance *instance, return ret; } -static +/* clang stack usage explodes if this is inlined */ +static noinline_for_stack void vdec_vp9_slice_map_counts_eob_coef(unsigned int i, unsigned int j, unsigned int k, struct vdec_vp9_slice_frame_counts *counts, struct v4l2_vp9_frame_symbol_counts *counts_helper) diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c index 7eaf0e24c9fc41..a01dc25a769911 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c @@ -1009,8 +1009,6 @@ static const struct vb2_ops mtk_venc_vb2_ops = { .buf_out_validate = vb2ops_venc_buf_out_validate, .buf_prepare = vb2ops_venc_buf_prepare, .buf_queue = vb2ops_venc_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vb2ops_venc_start_streaming, .stop_streaming = vb2ops_venc_stop_streaming, }; diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c index 3cb8a16222220e..a1e4483abcdbde 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c @@ -473,7 +473,7 @@ static void mtk_vcodec_enc_remove(struct platform_device *pdev) static struct platform_driver mtk_vcodec_enc_driver = { .probe = mtk_vcodec_probe, - .remove_new = mtk_vcodec_enc_remove, + .remove = mtk_vcodec_enc_remove, .driver = { .name = MTK_VCODEC_ENC_NAME, .of_match_table = mtk_vcodec_enc_match, diff --git a/drivers/media/platform/mediatek/vpu/mtk_vpu.c b/drivers/media/platform/mediatek/vpu/mtk_vpu.c index 724ae7c2ab3ba2..8d8319f0cd2219 100644 --- a/drivers/media/platform/mediatek/vpu/mtk_vpu.c +++ b/drivers/media/platform/mediatek/vpu/mtk_vpu.c @@ -1041,7 +1041,7 @@ static const struct dev_pm_ops mtk_vpu_pm = { static struct platform_driver mtk_vpu_driver = { .probe = mtk_vpu_probe, - .remove_new = mtk_vpu_remove, + .remove = mtk_vpu_remove, .driver = { .name = "mtk_vpu", .pm = &mtk_vpu_pm, diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c index fee73260bb1e11..70303a0b6919eb 100644 --- a/drivers/media/platform/microchip/microchip-csi2dc.c +++ b/drivers/media/platform/microchip/microchip-csi2dc.c @@ -782,7 +782,7 @@ MODULE_DEVICE_TABLE(of, csi2dc_of_match); static struct platform_driver csi2dc_driver = { .probe = csi2dc_probe, - .remove_new = csi2dc_remove, + .remove = csi2dc_remove, .driver = { .name = "microchip-csi2dc", .pm = &csi2dc_dev_pm_ops, diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c index 28e56f6a695da2..a7cdc743fda71d 100644 --- a/drivers/media/platform/microchip/microchip-isc-base.c +++ b/drivers/media/platform/microchip/microchip-isc-base.c @@ -465,8 +465,6 @@ static void isc_buffer_queue(struct vb2_buffer *vb) static const struct vb2_ops isc_vb2_ops = { .queue_setup = isc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = isc_buffer_prepare, .start_streaming = isc_start_streaming, .stop_streaming = isc_stop_streaming, diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c index 60b6d922d764eb..66d3d7891991e9 100644 --- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c +++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c @@ -658,7 +658,7 @@ MODULE_DEVICE_TABLE(of, microchip_isc_of_match); static struct platform_driver microchip_isc_driver = { .probe = microchip_isc_probe, - .remove_new = microchip_isc_remove, + .remove = microchip_isc_remove, .driver = { .name = "microchip-sama5d2-isc", .pm = µchip_isc_dev_pm_ops, diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c index e97abe3e35af0e..b0302dfc3278d7 100644 --- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c +++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c @@ -621,7 +621,7 @@ MODULE_DEVICE_TABLE(of, microchip_xisc_of_match); static struct platform_driver microchip_xisc_driver = { .probe = microchip_xisc_probe, - .remove_new = microchip_xisc_remove, + .remove = microchip_xisc_remove, .driver = { .name = "microchip-sama7g5-xisc", .pm = µchip_xisc_dev_pm_ops, diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c index 60fbb91400355c..4f5d75645b2bb9 100644 --- a/drivers/media/platform/nuvoton/npcm-video.c +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -1558,8 +1558,6 @@ static const struct regmap_config npcm_video_ece_regmap_cfg = { static const struct vb2_ops npcm_video_vb2_ops = { .queue_setup = npcm_video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = npcm_video_buf_prepare, .buf_finish = npcm_video_buf_finish, .start_streaming = npcm_video_start_streaming, @@ -1814,7 +1812,7 @@ static struct platform_driver npcm_video_driver = { .of_match_table = npcm_video_match, }, .probe = npcm_video_probe, - .remove_new = npcm_video_remove, + .remove = npcm_video_remove, }; module_platform_driver(npcm_video_driver); diff --git a/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c b/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c index 1c5b94989aec07..b34244ea14dd06 100644 --- a/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c +++ b/drivers/media/platform/nvidia/tegra-vde/dmabuf-cache.c @@ -16,7 +16,7 @@ #include "vde.h" -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); struct tegra_vde_cache_entry { enum dma_data_direction dma_dir; diff --git a/drivers/media/platform/nvidia/tegra-vde/iommu.c b/drivers/media/platform/nvidia/tegra-vde/iommu.c index 5521ed3e465fba..b1d9d841d94409 100644 --- a/drivers/media/platform/nvidia/tegra-vde/iommu.c +++ b/drivers/media/platform/nvidia/tegra-vde/iommu.c @@ -78,9 +78,10 @@ int tegra_vde_iommu_init(struct tegra_vde *vde) arm_iommu_release_mapping(mapping); } #endif - vde->domain = iommu_domain_alloc(&platform_bus_type); - if (!vde->domain) { - err = -ENOMEM; + vde->domain = iommu_paging_domain_alloc(dev); + if (IS_ERR(vde->domain)) { + err = PTR_ERR(vde->domain); + vde->domain = NULL; goto put_group; } diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index 0f48ce6f243e8c..e3726cab0c82c9 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -328,8 +328,6 @@ static const struct vb2_ops tegra_qops = { .buf_request_complete = tegra_buf_request_complete, .start_streaming = tegra_start_streaming, .stop_streaming = tegra_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int tegra_queue_init(void *priv, @@ -929,13 +927,13 @@ int tegra_vde_v4l2_init(struct tegra_vde *vde) media_device_init(&vde->mdev); video_set_drvdata(&vde->vdev, vde); - vde->vdev.lock = &vde->v4l2_lock, - vde->vdev.fops = &tegra_v4l2_fops, - vde->vdev.vfl_dir = VFL_DIR_M2M, - vde->vdev.release = video_device_release_empty, + vde->vdev.lock = &vde->v4l2_lock; + vde->vdev.fops = &tegra_v4l2_fops; + vde->vdev.vfl_dir = VFL_DIR_M2M; + vde->vdev.release = video_device_release_empty; vde->vdev.v4l2_dev = &vde->v4l2_dev; - vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops, - vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, + vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops; + vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; vde->v4l2_dev.mdev = &vde->mdev; vde->mdev.ops = &tegra_media_device_ops; diff --git a/drivers/media/platform/nvidia/tegra-vde/vde.c b/drivers/media/platform/nvidia/tegra-vde/vde.c index 81a0d3b76b88fc..3232392c60e208 100644 --- a/drivers/media/platform/nvidia/tegra-vde/vde.c +++ b/drivers/media/platform/nvidia/tegra-vde/vde.c @@ -535,7 +535,7 @@ MODULE_DEVICE_TABLE(of, tegra_vde_of_match); static struct platform_driver tegra_vde_driver = { .probe = tegra_vde_probe, - .remove_new = tegra_vde_remove, + .remove = tegra_vde_remove, .shutdown = tegra_vde_shutdown, .driver = { .name = "tegra-vde", diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c index 0024d6175ad9aa..66582e7f92fc6c 100644 --- a/drivers/media/platform/nxp/dw100/dw100.c +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -558,8 +558,6 @@ static const struct vb2_ops dw100_qops = { .buf_queue = dw100_buf_queue, .start_streaming = dw100_start_streaming, .stop_streaming = dw100_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int dw100_m2m_queue_init(void *priv, struct vb2_queue *src_vq, @@ -1311,7 +1309,7 @@ static void dw100_hw_set_destination(struct dw100_device *dw_dev, } dev_dbg(&dw_dev->pdev->dev, - "Set HW source registers for %ux%u - stride %u, pixfmt: %p4cc, dma:%pad\n", + "Set HW destination registers for %ux%u - stride %u, pixfmt: %p4cc, dma:%pad\n", width, height, stride, &fourcc, &addr_y); /* Pixel Format */ @@ -1688,7 +1686,7 @@ MODULE_DEVICE_TABLE(of, dw100_dt_ids); static struct platform_driver dw100_driver = { .probe = dw100_probe, - .remove_new = dw100_remove, + .remove = dw100_remove, .driver = { .name = DRV_NAME, .pm = &dw100_pm, diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 1d891381303722..7f5fe551179b9e 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1965,8 +1965,6 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) static const struct vb2_ops mxc_jpeg_qops = { .queue_setup = mxc_jpeg_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_out_validate = mxc_jpeg_buf_out_validate, .buf_prepare = mxc_jpeg_buf_prepare, .start_streaming = mxc_jpeg_start_streaming, @@ -2679,6 +2677,8 @@ static void mxc_jpeg_detach_pm_domains(struct mxc_jpeg_dev *jpeg) int i; for (i = 0; i < jpeg->num_domains; i++) { + if (jpeg->pd_dev[i] && !pm_runtime_suspended(jpeg->pd_dev[i])) + pm_runtime_force_suspend(jpeg->pd_dev[i]); if (jpeg->pd_link[i] && !IS_ERR(jpeg->pd_link[i])) device_link_del(jpeg->pd_link[i]); if (jpeg->pd_dev[i] && !IS_ERR(jpeg->pd_dev[i])) @@ -2842,6 +2842,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev) jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M; jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; + video_set_drvdata(jpeg->dec_vdev, jpeg); if (mode == MXC_JPEG_ENCODE) { v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_DECODER_CMD); v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_TRY_DECODER_CMD); @@ -2854,7 +2855,6 @@ static int mxc_jpeg_probe(struct platform_device *pdev) dev_err(dev, "failed to register video device\n"); goto err_vdev_register; } - video_set_drvdata(jpeg->dec_vdev, jpeg); if (mode == MXC_JPEG_ENCODE) v4l2_info(&jpeg->v4l2_dev, "encoder device registered as /dev/video%d (%d,%d)\n", @@ -2888,7 +2888,6 @@ static int mxc_jpeg_probe(struct platform_device *pdev) return ret; } -#ifdef CONFIG_PM static int mxc_jpeg_runtime_resume(struct device *dev) { struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); @@ -2911,9 +2910,7 @@ static int mxc_jpeg_runtime_suspend(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM_SLEEP static int mxc_jpeg_suspend(struct device *dev) { struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); @@ -2934,12 +2931,10 @@ static int mxc_jpeg_resume(struct device *dev) v4l2_m2m_resume(jpeg->m2m_dev); return ret; } -#endif static const struct dev_pm_ops mxc_jpeg_pm_ops = { - SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend, - mxc_jpeg_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume) + RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend, mxc_jpeg_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume) }; static void mxc_jpeg_remove(struct platform_device *pdev) @@ -2959,11 +2954,11 @@ MODULE_DEVICE_TABLE(of, mxc_jpeg_match); static struct platform_driver mxc_jpeg_driver = { .probe = mxc_jpeg_probe, - .remove_new = mxc_jpeg_remove, + .remove = mxc_jpeg_remove, .driver = { .name = "mxc-jpeg", .of_match_table = mxc_jpeg_match, - .pm = &mxc_jpeg_pm_ops, + .pm = pm_ptr(&mxc_jpeg_pm_ops), }, }; module_platform_driver(mxc_jpeg_driver); diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 44e1402e8be198..29523bb84d9563 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1570,7 +1570,7 @@ MODULE_DEVICE_TABLE(of, mipi_csis_of_match); static struct platform_driver mipi_csis_driver = { .probe = mipi_csis_probe, - .remove_new = mipi_csis_remove, + .remove = mipi_csis_remove, .driver = { .of_match_table = mipi_csis_of_match, .name = CSIS_DRIVER_NAME, diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index e4427e6487fba7..7f8ffbac582fcf 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -1606,8 +1606,6 @@ static const struct vb2_ops pxp_qops = { .buf_queue = pxp_buf_queue, .start_streaming = pxp_start_streaming, .stop_streaming = pxp_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -1943,7 +1941,7 @@ MODULE_DEVICE_TABLE(of, pxp_dt_ids); static struct platform_driver pxp_driver = { .probe = pxp_probe, - .remove_new = pxp_remove, + .remove = pxp_remove, .driver = { .name = MEM2MEM_NAME, .of_match_table = pxp_dt_ids, diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 9566ff738818d6..34a92642bbfe7b 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -1507,8 +1507,6 @@ static const struct vb2_ops imx7_csi_video_qops = { .buf_init = imx7_csi_video_buf_init, .buf_prepare = imx7_csi_video_buf_prepare, .buf_queue = imx7_csi_video_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = imx7_csi_video_start_streaming, .stop_streaming = imx7_csi_video_stop_streaming, }; @@ -2281,7 +2279,7 @@ MODULE_DEVICE_TABLE(of, imx7_csi_of_match); static struct platform_driver imx7_csi_driver = { .probe = imx7_csi_probe, - .remove_new = imx7_csi_remove, + .remove = imx7_csi_remove, .driver = { .of_match_table = imx7_csi_of_match, .name = "imx7-csi", 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 c2013995049c60..aaf58063677c5e 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -535,7 +535,7 @@ MODULE_DEVICE_TABLE(of, mxc_isi_of_match); static struct platform_driver mxc_isi_driver = { .probe = mxc_isi_probe, - .remove_new = mxc_isi_remove, + .remove = mxc_isi_remove, .driver = { .of_match_table = mxc_isi_of_match, .name = MXC_ISI_DRIVER_NAME, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c index 9745d6219a1667..794050a6a919b8 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -269,8 +269,6 @@ static const struct vb2_ops mxc_isi_m2m_vb2_qops = { .buf_init = mxc_isi_m2m_vb2_buffer_init, .buf_prepare = mxc_isi_m2m_vb2_buffer_prepare, .buf_queue = mxc_isi_m2m_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = mxc_isi_m2m_vb2_start_streaming, .stop_streaming = mxc_isi_m2m_vb2_stop_streaming, }; diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c index 4091f1c0e78bdc..c0ba34ea82fd79 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c @@ -987,8 +987,6 @@ static const struct vb2_ops mxc_isi_vb2_qops = { .buf_init = mxc_isi_vb2_buffer_init, .buf_prepare = mxc_isi_vb2_buffer_prepare, .buf_queue = mxc_isi_vb2_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = mxc_isi_vb2_start_streaming, .stop_streaming = mxc_isi_vb2_stop_streaming, }; diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c index d4a6c553296990..1f2657cf6e8242 100644 --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c @@ -953,7 +953,7 @@ MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match); static struct platform_driver imx8mq_mipi_csi_driver = { .probe = imx8mq_mipi_csi_probe, - .remove_new = imx8mq_mipi_csi_remove, + .remove = imx8mq_mipi_csi_remove, .driver = { .of_match_table = imx8mq_mipi_csi_of_match, .name = MIPI_CSI2_DRIVER_NAME, diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c index 023ed40c6b0836..0c6cc120fd2a44 100644 --- a/drivers/media/platform/nxp/mx2_emmaprp.c +++ b/drivers/media/platform/nxp/mx2_emmaprp.c @@ -677,8 +677,6 @@ static const struct vb2_ops emmaprp_qops = { .queue_setup = emmaprp_queue_setup, .buf_prepare = emmaprp_buf_prepare, .buf_queue = emmaprp_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -902,7 +900,7 @@ static void emmaprp_remove(struct platform_device *pdev) static struct platform_driver emmaprp_pdrv = { .probe = emmaprp_probe, - .remove_new = emmaprp_remove, + .remove = emmaprp_remove, .driver = { .name = MEM2MEM_NAME, }, diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 2f7361dfd4614c..5af2b382a843c2 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -212,14 +212,25 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on) if (ret < 0) return ret; + ret = regulator_bulk_enable(csiphy->num_supplies, + csiphy->supplies); + if (ret < 0) { + pm_runtime_put_sync(dev); + return ret; + } + ret = csiphy_set_clock_rates(csiphy); if (ret < 0) { + regulator_bulk_disable(csiphy->num_supplies, + csiphy->supplies); pm_runtime_put_sync(dev); return ret; } ret = camss_enable_clocks(csiphy->nclocks, csiphy->clock, dev); if (ret < 0) { + regulator_bulk_disable(csiphy->num_supplies, + csiphy->supplies); pm_runtime_put_sync(dev); return ret; } @@ -234,6 +245,8 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on) camss_disable_clocks(csiphy->nclocks, csiphy->clock); + regulator_bulk_disable(csiphy->num_supplies, csiphy->supplies); + pm_runtime_put_sync(dev); } @@ -583,6 +596,7 @@ int msm_csiphy_subdev_init(struct camss *camss, return PTR_ERR(csiphy->base); if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_8x96) { csiphy->base_clk_mux = devm_platform_ioremap_resource_byname(pdev, res->reg[1]); @@ -676,7 +690,27 @@ int msm_csiphy_subdev_init(struct camss *camss, } } - return 0; + /* CSIPHY supplies */ + for (i = 0; i < ARRAY_SIZE(res->regulators); i++) { + if (res->regulators[i]) + csiphy->num_supplies++; + } + + if (csiphy->num_supplies) { + csiphy->supplies = devm_kmalloc_array(camss->dev, + csiphy->num_supplies, + sizeof(*csiphy->supplies), + GFP_KERNEL); + if (!csiphy->supplies) + return -ENOMEM; + } + + for (i = 0; i < csiphy->num_supplies; i++) + csiphy->supplies[i].supply = res->regulators[i]; + + ret = devm_regulator_bulk_get(camss->dev, csiphy->num_supplies, + csiphy->supplies); + return ret; } /* diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index 47f0b6b09eba4d..eebc1ff1cfabc7 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -91,6 +91,8 @@ struct csiphy_device { bool *rate_set; int nclocks; u32 timer_clk_rate; + struct regulator_bulk_data *supplies; + int num_supplies; struct csiphy_config cfg; struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM]; const struct csiphy_subdev_resources *res; diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index a12dcc7ff438c5..2dc585c6123dd2 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -830,6 +830,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) ispif_select_cid(ispif, intf, cid, vfe, 1); ispif_config_irq(ispif, intf, vfe, 1); if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, @@ -848,6 +849,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&ispif->config_lock); if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, @@ -1111,6 +1113,7 @@ int msm_ispif_subdev_init(struct camss *camss, if (camss->res->version == CAMSS_8x16) ispif->line_num = 2; else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) ispif->line_num = 4; else @@ -1130,6 +1133,7 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x16); } else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) { ispif->line[i].formats = ispif_formats_8x96; ispif->line[i].nformats = @@ -1162,6 +1166,7 @@ int msm_ispif_subdev_init(struct camss *camss, ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); else if (camss->res->version == CAMSS_8x96 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c index 1bd3a6ef1d04d8..9a9007c3ff33b4 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -938,7 +938,10 @@ static irqreturn_t vfe_isr(int irq, void *dev) */ static void vfe_4_1_pm_domain_off(struct vfe_device *vfe) { - /* nop */ + if (!vfe->res->has_pd) + return; + + vfe_pm_domain_off(vfe); } /* @@ -947,7 +950,10 @@ static void vfe_4_1_pm_domain_off(struct vfe_device *vfe) */ static int vfe_4_1_pm_domain_on(struct vfe_device *vfe) { - return 0; + if (!vfe->res->has_pd) + return 0; + + return vfe_pm_domain_on(vfe); } static const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = { diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 83c5a36d071fcc..80a62ba1129504 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -285,6 +285,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, switch (vfe->camss->res->version) { case CAMSS_8x16: + case CAMSS_8x53: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: { diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 3b8fc31d957c77..aa021fd5e1233b 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -310,8 +310,6 @@ static void video_stop_streaming(struct vb2_queue *q) static const struct vb2_ops msm_video_vb2_q_ops = { .queue_setup = video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_init = video_buf_init, .buf_prepare = video_buf_prepare, .buf_queue = video_buf_queue, diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index d64985ca6e884f..9fb31f4c18adee 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -152,6 +152,160 @@ static const struct camss_subdev_resources vfe_res_8x16[] = { } }; +static const struct camss_subdev_resources csid_res_8x53[] = { + /* CSID0 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", + "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .hw_ops = &csid_ops_4_7, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_7 + } + }, + + /* CSID1 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", + "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .hw_ops = &csid_ops_4_7, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_7 + } + }, + + /* CSID2 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", + "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 100000000, 200000000, 310000000, + 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, + .csid = { + .hw_ops = &csid_ops_4_7, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_7 + } + }, +}; + +static const struct camss_subdev_resources ispif_res_8x53 = { + /* ISPIF */ + .clock = { "top_ahb", "ahb", "ispif_ahb", + "csi0", "csi0_pix", "csi0_rdi", + "csi1", "csi1_pix", "csi1_rdi", + "csi2", "csi2_pix", "csi2_rdi" }, + .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" }, + .reg = { "ispif", "csi_clk_mux" }, + .interrupt = { "ispif" }, +}; + +static const struct camss_subdev_resources vfe_res_8x53[] = { + /* VFE0 */ + { + .regulators = {}, + .clock = { "top_ahb", "ahb", "ispif_ahb", + "vfe0", "csi_vfe0", "vfe0_ahb", "vfe0_axi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 50000000, 100000000, 133330000, + 160000000, 200000000, 266670000, + 310000000, 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "vfe0", + .hw_ops = &vfe_ops_4_1, + .formats_rdi = &vfe_formats_rdi_8x16, + .formats_pix = &vfe_formats_pix_8x16 + } + }, + + /* VFE1 */ + { + .regulators = {}, + .clock = { "top_ahb", "ahb", "ispif_ahb", + "vfe1", "csi_vfe1", "vfe1_ahb", "vfe1_axi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 50000000, 100000000, 133330000, + 160000000, 200000000, 266670000, + 310000000, 400000000, 465000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "vfe1", + .hw_ops = &vfe_ops_4_1, + .formats_rdi = &vfe_formats_rdi_8x16, + .formats_pix = &vfe_formats_pix_8x16 + } + } +}; + +static const struct resources_icc icc_res_8x53[] = { + { + .name = "cam_ahb", + .icc_bw_tbl.avg = 38400, + .icc_bw_tbl.peak = 76800, + }, + { + .name = "cam_vfe0_mem", + .icc_bw_tbl.avg = 939524, + .icc_bw_tbl.peak = 1342177, + }, + { + .name = "cam_vfe1_mem", + .icc_bw_tbl.avg = 939524, + .icc_bw_tbl.peak = 1342177, + }, +}; + static const struct camss_subdev_resources csiphy_res_8x96[] = { /* CSIPHY0 */ { @@ -837,7 +991,7 @@ static const struct camss_subdev_resources vfe_res_845[] = { static const struct camss_subdev_resources csiphy_res_8250[] = { /* CSIPHY0 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy0", "csiphy0_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -850,7 +1004,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY1 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy1", "csiphy1_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -863,7 +1017,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY2 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy2", "csiphy2_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -876,7 +1030,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY3 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy3", "csiphy3_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -889,7 +1043,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY4 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy4", "csiphy4_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -902,7 +1056,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { }, /* CSIPHY5 */ { - .regulators = {}, + .regulators = { "vdda-phy", "vdda-pll" }, .clock = { "csiphy5", "csiphy5_timer" }, .clock_rate = { { 400000000 }, { 300000000 } }, @@ -918,7 +1072,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = { static const struct camss_subdev_resources csid_res_8250[] = { /* CSID0 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = {}, .clock = { "vfe0_csid", "vfe0_cphy_rx", "vfe0", "vfe0_areg", "vfe0_ahb" }, .clock_rate = { { 400000000 }, { 400000000 }, @@ -935,7 +1089,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { }, /* CSID1 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = {}, .clock = { "vfe1_csid", "vfe1_cphy_rx", "vfe1", "vfe1_areg", "vfe1_ahb" }, .clock_rate = { { 400000000 }, { 400000000 }, @@ -952,7 +1106,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { }, /* CSID2 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = {}, .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" }, .clock_rate = { { 400000000 }, { 400000000 }, @@ -969,7 +1123,7 @@ static const struct camss_subdev_resources csid_res_8250[] = { }, /* CSID3 */ { - .regulators = { "vdda-phy", "vdda-pll" }, + .regulators = {}, .clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" }, .clock_rate = { { 400000000 }, { 400000000 }, @@ -1780,6 +1934,7 @@ static int camss_of_parse_ports(struct camss *camss) */ static int camss_init_subdevices(struct camss *camss) { + struct platform_device *pdev = to_platform_device(camss->dev); const struct camss_resources *res = camss->res; unsigned int i; int ret; @@ -1806,6 +1961,17 @@ static int camss_init_subdevices(struct camss *camss) } } + /* Get optional CSID wrapper regs shared between CSID devices */ + if (res->csid_wrapper_res) { + char *reg = res->csid_wrapper_res->reg; + void __iomem *base; + + base = devm_platform_ioremap_resource_byname(pdev, reg); + if (IS_ERR(base)) + return PTR_ERR(base); + camss->csid_wrapper_base = base; + } + for (i = 0; i < camss->res->csid_num; i++) { ret = msm_csid_subdev_init(camss, &camss->csid[i], &res->csid_res[i], i); @@ -2130,10 +2296,8 @@ static int camss_configure_pd(struct camss *camss) if (camss->res->pd_name) { camss->genpd = dev_pm_domain_attach_by_name(camss->dev, camss->res->pd_name); - if (IS_ERR(camss->genpd)) { - ret = PTR_ERR(camss->genpd); - goto fail_pm; - } + if (IS_ERR(camss->genpd)) + return PTR_ERR(camss->genpd); } if (!camss->genpd) { @@ -2143,14 +2307,13 @@ static int camss_configure_pd(struct camss *camss) */ camss->genpd = dev_pm_domain_attach_by_id(camss->dev, camss->genpd_num - 1); + if (IS_ERR(camss->genpd)) + return PTR_ERR(camss->genpd); } - if (IS_ERR_OR_NULL(camss->genpd)) { - if (!camss->genpd) - ret = -ENODEV; - else - ret = PTR_ERR(camss->genpd); - goto fail_pm; - } + + if (!camss->genpd) + return -ENODEV; + camss->genpd_link = device_link_add(camss->dev, camss->genpd, DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); @@ -2239,6 +2402,7 @@ static int camss_probe(struct platform_device *pdev) return -ENOMEM; if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_8x96) { camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); if (!camss->ispif) @@ -2380,6 +2544,20 @@ static const struct camss_resources msm8916_resources = { .link_entities = camss_link_entities }; +static const struct camss_resources msm8953_resources = { + .version = CAMSS_8x53, + .icc_res = icc_res_8x53, + .icc_path_num = ARRAY_SIZE(icc_res_8x53), + .csiphy_res = csiphy_res_8x96, + .csid_res = csid_res_8x53, + .ispif_res = &ispif_res_8x53, + .vfe_res = vfe_res_8x53, + .csiphy_num = ARRAY_SIZE(csiphy_res_8x96), + .csid_num = ARRAY_SIZE(csid_res_8x53), + .vfe_num = ARRAY_SIZE(vfe_res_8x53), + .link_entities = camss_link_entities +}; + static const struct camss_resources msm8996_resources = { .version = CAMSS_8x96, .csiphy_res = csiphy_res_8x96, @@ -2446,6 +2624,7 @@ static const struct camss_resources sc8280xp_resources = { static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,msm8916-camss", .data = &msm8916_resources }, + { .compatible = "qcom,msm8953-camss", .data = &msm8953_resources }, { .compatible = "qcom,msm8996-camss", .data = &msm8996_resources }, { .compatible = "qcom,sdm660-camss", .data = &sdm660_resources }, { .compatible = "qcom,sdm845-camss", .data = &sdm845_resources }, @@ -2497,7 +2676,7 @@ static const struct dev_pm_ops camss_pm_ops = { static struct platform_driver qcom_camss_driver = { .probe = camss_probe, - .remove_new = camss_remove, + .remove = camss_remove, .driver = { .name = "qcom-camss", .of_match_table = camss_dt_match, diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 73c47c07fc30c5..9da7f48f5dd762 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -66,6 +66,10 @@ struct resources_icc { struct icc_bw_tbl icc_bw_tbl; }; +struct resources_wrapper { + char *reg; +}; + enum pm_domain { PM_DOMAIN_VFE0 = 0, PM_DOMAIN_VFE1 = 1, @@ -74,6 +78,7 @@ enum pm_domain { enum camss_version { CAMSS_8x16, + CAMSS_8x53, CAMSS_8x96, CAMSS_660, CAMSS_845, @@ -93,6 +98,7 @@ struct camss_resources { const struct camss_subdev_resources *csid_res; const struct camss_subdev_resources *ispif_res; const struct camss_subdev_resources *vfe_res; + const struct resources_wrapper *csid_wrapper_res; const struct resources_icc *icc_res; const unsigned int icc_path_num; const unsigned int csiphy_num; @@ -110,6 +116,7 @@ struct camss { struct csid_device *csid; struct ispif_device *ispif; struct vfe_device *vfe; + void __iomem *csid_wrapper_base; atomic_t ref_count; int genpd_num; struct device *genpd; diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 84e95a46dfc983..2d27c5167246f5 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -412,8 +413,8 @@ static int venus_probe(struct platform_device *pdev) of_platform_depopulate(dev); err_runtime_disable: pm_runtime_put_noidle(dev); - pm_runtime_set_suspended(dev); pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); hfi_destroy(core); err_core_deinit: hfi_core_deinit(core, false); @@ -502,6 +503,30 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) return ret; } +void venus_close_common(struct venus_inst *inst) +{ + /* + * First, remove the inst from the ->instances list, so that + * to_instance() will return NULL. + */ + hfi_session_destroy(inst); + /* + * Second, make sure we don't have IRQ/IRQ-thread currently running + * or pending execution, which would race with the inst destruction. + */ + synchronize_irq(inst->core->irq); + + v4l2_m2m_ctx_release(inst->m2m_ctx); + v4l2_m2m_release(inst->m2m_dev); + v4l2_fh_del(&inst->fh); + v4l2_fh_exit(&inst->fh); + v4l2_ctrl_handler_free(&inst->ctrl_handler); + + mutex_destroy(&inst->lock); + mutex_destroy(&inst->ctx_q_lock); +} +EXPORT_SYMBOL_GPL(venus_close_common); + static __maybe_unused int venus_runtime_resume(struct device *dev) { struct venus_core *core = dev_get_drvdata(dev); @@ -752,7 +777,7 @@ static const struct venus_resources sdm845_res_v2 = { .vcodec_clks_num = 2, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, .vcodec_pmdomains_num = 3, - .opp_pmdomain = (const char *[]) { "cx", NULL }, + .opp_pmdomain = (const char *[]) { "cx" }, .vcodec_num = 2, .max_load = 3110400, /* 4096x2160@90 */ .hfi_version = HFI_VERSION_4XX, @@ -801,7 +826,7 @@ static const struct venus_resources sc7180_res = { .vcodec_clks_num = 2, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, - .opp_pmdomain = (const char *[]) { "cx", NULL }, + .opp_pmdomain = (const char *[]) { "cx" }, .vcodec_num = 1, .hfi_version = HFI_VERSION_4XX, .vpu_version = VPU_VERSION_AR50, @@ -858,7 +883,7 @@ static const struct venus_resources sm8250_res = { .vcodec_clks_num = 1, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, - .opp_pmdomain = (const char *[]) { "mx", NULL }, + .opp_pmdomain = (const char *[]) { "mx" }, .vcodec_num = 1, .max_load = 7833600, .hfi_version = HFI_VERSION_6XX, @@ -917,7 +942,7 @@ static const struct venus_resources sc7280_res = { .vcodec_clks_num = 2, .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, - .opp_pmdomain = (const char *[]) { "cx", NULL }, + .opp_pmdomain = (const char *[]) { "cx" }, .vcodec_num = 1, .hfi_version = HFI_VERSION_6XX, .vpu_version = VPU_VERSION_IRIS2_1, @@ -949,7 +974,7 @@ MODULE_DEVICE_TABLE(of, venus_dt_match); static struct platform_driver qcom_venus_driver = { .probe = venus_probe, - .remove_new = venus_remove, + .remove = venus_remove, .driver = { .name = "qcom-venus", .of_match_table = venus_dt_match, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 55202b89e1b9fc..44f1c3bc418653 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -26,6 +26,7 @@ #define VIDC_CLKS_NUM_MAX 4 #define VIDC_VCODEC_CLKS_NUM_MAX 2 #define VIDC_RESETS_NUM_MAX 2 +#define VIDC_MAX_HIER_CODING_LAYER 6 extern int venus_fw_debug; @@ -132,9 +133,7 @@ struct venus_format { * @vcodec1_clks: an array of vcodec1 struct clk pointers * @video_path: an interconnect handle to video to/from memory path * @cpucfg_path: an interconnect handle to cpu configuration path - * @has_opp_table: does OPP table exist * @pmdomains: a pointer to a list of pmdomains - * @opp_dl_venus: an device-link for device OPP * @opp_pmdomain: an OPP power-domain * @resets: an array of reset signals * @vdev_dec: a reference to video device structure for decoder instances @@ -186,10 +185,8 @@ struct venus_core { struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; struct icc_path *video_path; struct icc_path *cpucfg_path; - bool has_opp_table; struct dev_pm_domain_list *pmdomains; - struct device_link *opp_dl_venus; - struct device *opp_pmdomain; + struct dev_pm_domain_list *opp_pmdomain; struct reset_control *resets[VIDC_RESETS_NUM_MAX]; struct video_device *vdev_dec; struct video_device *vdev_enc; @@ -255,6 +252,7 @@ struct venc_controls { u32 rc_enable; u32 const_quality; u32 frame_skip_mode; + u32 layer_bitrate; u32 h264_i_period; u32 h264_entropy_mode; @@ -273,6 +271,8 @@ struct venc_controls { s32 h264_loop_filter_alpha; s32 h264_loop_filter_beta; u32 h264_8x8_transform; + u32 h264_hier_layers; + u32 h264_hier_layer_bitrate[VIDC_MAX_HIER_CODING_LAYER]; u32 hevc_i_qp; u32 hevc_p_qp; @@ -564,4 +564,6 @@ is_fw_rev_or_older(struct venus_core *core, u32 vmajor, u32 vminor, u32 vrev) (core)->venus_ver.minor == vminor && (core)->venus_ver.rev <= vrev); } + +void venus_close_common(struct venus_inst *inst); #endif diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index ea8a2bd9419e6d..33a5a659c0ada0 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -864,7 +864,6 @@ static int venc_power_v4(struct device *dev, int on) static int vcodec_domains_get(struct venus_core *core) { int ret; - struct device **opp_virt_dev; struct device *dev = core->dev; const struct venus_resources *res = core->res; struct dev_pm_domain_attach_data vcodec_data = { @@ -872,6 +871,11 @@ static int vcodec_domains_get(struct venus_core *core) .num_pd_names = res->vcodec_pmdomains_num, .pd_flags = PD_FLAG_NO_DEV_LINK, }; + struct dev_pm_domain_attach_data opp_pd_data = { + .pd_names = res->opp_pmdomain, + .num_pd_names = 1, + .pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP, + }; if (!res->vcodec_pmdomains_num) goto skip_pmdomains; @@ -881,37 +885,15 @@ static int vcodec_domains_get(struct venus_core *core) return ret; skip_pmdomains: - if (!core->res->opp_pmdomain) + if (!res->opp_pmdomain) return 0; /* Attach the power domain for setting performance state */ - ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev); - if (ret) - goto opp_attach_err; - - core->opp_pmdomain = *opp_virt_dev; - core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain, - DL_FLAG_RPM_ACTIVE | - DL_FLAG_PM_RUNTIME | - DL_FLAG_STATELESS); - if (!core->opp_dl_venus) { - ret = -ENODEV; - goto opp_attach_err; - } + ret = devm_pm_domain_attach_list(dev, &opp_pd_data, &core->opp_pmdomain); + if (ret < 0) + return ret; return 0; - -opp_attach_err: - return ret; -} - -static void vcodec_domains_put(struct venus_core *core) -{ - if (!core->has_opp_table) - return; - - if (core->opp_dl_venus) - device_link_del(core->opp_dl_venus); } static int core_resets_reset(struct venus_core *core) @@ -1000,9 +982,7 @@ static int core_get_v4(struct venus_core *core) if (core->res->opp_pmdomain) { ret = devm_pm_opp_of_add_table(dev); - if (!ret) { - core->has_opp_table = true; - } else if (ret != -ENODEV) { + if (ret && ret != -ENODEV) { dev_err(dev, "invalid OPP table in device tree\n"); return ret; } @@ -1013,10 +993,6 @@ static int core_get_v4(struct venus_core *core) static void core_put_v4(struct venus_core *core) { - if (legacy_binding) - return; - - vcodec_domains_put(core); } static int core_power_v4(struct venus_core *core, int on) diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index d12089370d91e7..98c22b9f937218 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -1735,7 +1735,7 @@ static int vdec_open(struct file *file) err_session_destroy: hfi_session_destroy(inst); err_ctrl_deinit: - vdec_ctrl_deinit(inst); + v4l2_ctrl_handler_free(&inst->ctrl_handler); err_free: kfree(inst); return ret; @@ -1746,18 +1746,9 @@ static int vdec_close(struct file *file) struct venus_inst *inst = to_inst(file); vdec_pm_get(inst); - cancel_work_sync(&inst->delayed_process_work); - v4l2_m2m_ctx_release(inst->m2m_ctx); - v4l2_m2m_release(inst->m2m_dev); - vdec_ctrl_deinit(inst); + venus_close_common(inst); ida_destroy(&inst->dpb_ids); - hfi_session_destroy(inst); - mutex_destroy(&inst->lock); - mutex_destroy(&inst->ctx_q_lock); - v4l2_fh_del(&inst->fh); - v4l2_fh_exit(&inst->fh); - vdec_pm_put(inst, false); kfree(inst); @@ -1875,7 +1866,7 @@ MODULE_DEVICE_TABLE(of, vdec_dt_match); static struct platform_driver qcom_venus_dec_driver = { .probe = vdec_probe, - .remove_new = vdec_remove, + .remove = vdec_remove, .driver = { .name = "qcom-venus-decoder", .of_match_table = vdec_dt_match, diff --git a/drivers/media/platform/qcom/venus/vdec.h b/drivers/media/platform/qcom/venus/vdec.h index 6b262d0bf561b8..0cf981108ff08c 100644 --- a/drivers/media/platform/qcom/venus/vdec.h +++ b/drivers/media/platform/qcom/venus/vdec.h @@ -9,6 +9,5 @@ struct venus_inst; int vdec_ctrl_init(struct venus_inst *inst); -void vdec_ctrl_deinit(struct venus_inst *inst); #endif diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c index 7e0f29bf7fae06..36ed955b041941 100644 --- a/drivers/media/platform/qcom/venus/vdec_ctrls.c +++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c @@ -187,8 +187,3 @@ int vdec_ctrl_init(struct venus_inst *inst) return 0; } - -void vdec_ctrl_deinit(struct venus_inst *inst) -{ - v4l2_ctrl_handler_free(&inst->ctrl_handler); -} diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 3ec2fb8d9fab60..c1c543535aaf5e 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -734,6 +734,29 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; + if (ctr->layer_bitrate) { + unsigned int i; + + ptype = HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER; + ret = hfi_session_set_property(inst, ptype, &ctr->h264_hier_layers); + if (ret) + return ret; + + ptype = HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER; + ret = hfi_session_set_property(inst, ptype, &ctr->layer_bitrate); + if (ret) + return ret; + + for (i = 0; i < ctr->h264_hier_layers; ++i) { + ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + brate.bitrate = ctr->h264_hier_layer_bitrate[i]; + brate.layer_id = i; + + ret = hfi_session_set_property(inst, ptype, &brate); + if (ret) + return ret; + } + } } if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || @@ -823,18 +846,33 @@ static int venc_set_properties(struct venus_inst *inst) return ret; } - if (!ctr->bitrate) - bitrate = 64000; - else - bitrate = ctr->bitrate; + if (!ctr->layer_bitrate) { + if (!ctr->bitrate) + bitrate = 64000; + else + bitrate = ctr->bitrate; - ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; - brate.bitrate = bitrate; - brate.layer_id = 0; + ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + brate.bitrate = bitrate; + brate.layer_id = 0; - ret = hfi_session_set_property(inst, ptype, &brate); - if (ret) - return ret; + ret = hfi_session_set_property(inst, ptype, &brate); + if (ret) + return ret; + + if (!ctr->bitrate_peak) + bitrate *= 2; + else + bitrate = ctr->bitrate_peak; + + ptype = HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE; + brate.bitrate = bitrate; + brate.layer_id = 0; + + ret = hfi_session_set_property(inst, ptype, &brate); + if (ret) + return ret; + } if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { @@ -849,19 +887,6 @@ static int venc_set_properties(struct venus_inst *inst) return ret; } - if (!ctr->bitrate_peak) - bitrate *= 2; - else - bitrate = ctr->bitrate_peak; - - ptype = HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE; - brate.bitrate = bitrate; - brate.layer_id = 0; - - ret = hfi_session_set_property(inst, ptype, &brate); - if (ret) - return ret; - ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP; if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { quant.qp_i = ctr->hevc_i_qp; @@ -1503,7 +1528,7 @@ static int venc_open(struct file *file) err_session_destroy: hfi_session_destroy(inst); err_ctrl_deinit: - venc_ctrl_deinit(inst); + v4l2_ctrl_handler_free(&inst->ctrl_handler); err_free: kfree(inst); return ret; @@ -1514,18 +1539,8 @@ static int venc_close(struct file *file) struct venus_inst *inst = to_inst(file); venc_pm_get(inst); - - v4l2_m2m_ctx_release(inst->m2m_ctx); - v4l2_m2m_release(inst->m2m_dev); - venc_ctrl_deinit(inst); - hfi_session_destroy(inst); - mutex_destroy(&inst->lock); - mutex_destroy(&inst->ctx_q_lock); - v4l2_fh_del(&inst->fh); - v4l2_fh_exit(&inst->fh); - + venus_close_common(inst); inst->enc_state = VENUS_ENC_STATE_DEINIT; - venc_pm_put(inst, false); kfree(inst); @@ -1643,7 +1658,7 @@ MODULE_DEVICE_TABLE(of, venc_dt_match); static struct platform_driver qcom_venus_enc_driver = { .probe = venc_probe, - .remove_new = venc_remove, + .remove = venc_remove, .driver = { .name = "qcom-venus-encoder", .of_match_table = venc_dt_match, diff --git a/drivers/media/platform/qcom/venus/venc.h b/drivers/media/platform/qcom/venus/venc.h index 4ea37fdcd9b8f0..719d0f73b14b80 100644 --- a/drivers/media/platform/qcom/venus/venc.h +++ b/drivers/media/platform/qcom/venus/venc.h @@ -9,6 +9,5 @@ struct venus_inst; int venc_ctrl_init(struct venus_inst *inst); -void venc_ctrl_deinit(struct venus_inst *inst); #endif diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index d9d2a293f3ef3a..51801a962ed2cc 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -67,12 +67,28 @@ static int venc_calc_bpframes(u32 gop_size, u32 conseq_b, u32 *bf, u32 *pf) return 0; } +static int dynamic_bitrate_update(struct venus_inst *inst, u32 bitrate, + u32 layer_id) +{ + int ret = 0; + + mutex_lock(&inst->lock); + if (inst->streamon_out && inst->streamon_cap) { + u32 ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + struct hfi_bitrate brate = { .bitrate = bitrate, .layer_id = layer_id }; + + ret = hfi_session_set_property(inst, ptype, &brate); + } + mutex_unlock(&inst->lock); + + return ret; +} + static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) { struct venus_inst *inst = ctrl_to_inst(ctrl); struct venc_controls *ctr = &inst->controls.enc; struct hfi_enable en = { .enable = 1 }; - struct hfi_bitrate brate; struct hfi_ltr_use ltr_use; struct hfi_ltr_mark ltr_mark; u32 bframes; @@ -85,19 +101,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDEO_BITRATE: ctr->bitrate = ctrl->val; - mutex_lock(&inst->lock); - if (inst->streamon_out && inst->streamon_cap) { - ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; - brate.bitrate = ctr->bitrate; - brate.layer_id = 0; - - ret = hfi_session_set_property(inst, ptype, &brate); - if (ret) { - mutex_unlock(&inst->lock); - return ret; - } - } - mutex_unlock(&inst->lock); + ret = dynamic_bitrate_update(inst, ctr->bitrate, 0); + if (ret) + return ret; break; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: ctr->bitrate_peak = ctrl->val; @@ -340,6 +346,55 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) ctr->h264_8x8_transform = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: + if (ctrl->val != V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P) + return -EINVAL; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: + ctr->layer_bitrate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER: + if (ctrl->val > VIDC_MAX_HIER_CODING_LAYER) + return -EINVAL; + ctr->h264_hier_layers = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: + ctr->h264_hier_layer_bitrate[0] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[0], 0); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: + ctr->h264_hier_layer_bitrate[1] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[1], 1); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: + ctr->h264_hier_layer_bitrate[2] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[2], 2); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: + ctr->h264_hier_layer_bitrate[3] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[3], 3); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: + ctr->h264_hier_layer_bitrate[4] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[4], 4); + if (ret) + return ret; + break; + case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: + ctr->h264_hier_layer_bitrate[5] = ctrl->val; + ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[5], 5); + if (ret) + return ret; + break; + default: return -EINVAL; } @@ -622,6 +677,49 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0, ((4096 * 2304) >> 8), 1, 0); + if (IS_V4(inst->core) || IS_V6(inst->core)) { + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + 1, V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, 0, + VIDC_MAX_HIER_CODING_LAYER, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + BITRATE_MIN, BITRATE_MAX, BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + BITRATE_MIN, BITRATE_MAX, + BITRATE_STEP, BITRATE_DEFAULT); + } + ret = inst->ctrl_handler.error; if (ret) goto err; @@ -635,8 +733,3 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_handler_free(&inst->ctrl_handler); return ret; } - -void venc_ctrl_deinit(struct venus_inst *inst) -{ - v4l2_ctrl_handler_free(&inst->ctrl_handler); -} diff --git a/drivers/media/platform/raspberrypi/Kconfig b/drivers/media/platform/raspberrypi/Kconfig index e928f979019e65..bd5101ffefb5bc 100644 --- a/drivers/media/platform/raspberrypi/Kconfig +++ b/drivers/media/platform/raspberrypi/Kconfig @@ -3,3 +3,4 @@ comment "Raspberry Pi media platform drivers" source "drivers/media/platform/raspberrypi/pisp_be/Kconfig" +source "drivers/media/platform/raspberrypi/rp1-cfe/Kconfig" diff --git a/drivers/media/platform/raspberrypi/Makefile b/drivers/media/platform/raspberrypi/Makefile index c0d1a2dab4860c..af7fde84eefe23 100644 --- a/drivers/media/platform/raspberrypi/Makefile +++ b/drivers/media/platform/raspberrypi/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += pisp_be/ +obj-y += rp1-cfe/ diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c index 65ff2382cffe9e..7596ae1f7de667 100644 --- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c @@ -1781,7 +1781,7 @@ MODULE_DEVICE_TABLE(of, pispbe_of_match); static struct platform_driver pispbe_pdrv = { .probe = pispbe_probe, - .remove_new = pispbe_remove, + .remove = pispbe_remove, .driver = { .name = PISPBE_NAME, .of_match_table = pispbe_of_match, diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig b/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig new file mode 100644 index 00000000000000..327b61f1134bc9 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig @@ -0,0 +1,15 @@ +# RP1 V4L2 camera support + +config VIDEO_RP1_CFE + tristate "Raspberry Pi RP1 Camera Front End (CFE) video capture driver" + depends on VIDEO_DEV + depends on PM + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + Say Y here to enable support for the Raspberry Pi RP1 Camera Front End. + + To compile this driver as a module, choose M here. The module will be + called rp1-cfe. diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/Makefile b/drivers/media/platform/raspberrypi/rp1-cfe/Makefile new file mode 100644 index 00000000000000..3f0d0fc8570ee7 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for RP1 Camera Front End driver +# +rp1-cfe-objs := cfe.o csi2.o pisp-fe.o dphy.o +obj-$(CONFIG_VIDEO_RP1_CFE) += rp1-cfe.o diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h new file mode 100644 index 00000000000000..7aecf7f8373344 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h @@ -0,0 +1,332 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RP1 Camera Front End formats definition + * + * Copyright (C) 2021-2024 - Raspberry Pi Ltd. + */ +#ifndef _CFE_FMTS_H_ +#define _CFE_FMTS_H_ + +#include "cfe.h" +#include + +static const struct cfe_fmt formats[] = { + /* YUV Formats */ + { + .fourcc = V4L2_PIX_FMT_YUYV, + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + }, + { + .fourcc = V4L2_PIX_FMT_YVYU, + .code = MEDIA_BUS_FMT_YVYU8_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + }, + { + .fourcc = V4L2_PIX_FMT_VYUY, + .code = MEDIA_BUS_FMT_VYUY8_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_YUV422_8B, + }, + { + /* RGB Formats */ + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RGB565, + }, + { .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RGB565, + }, + { + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RGB555, + }, + { + .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ + .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RGB555, + }, + { + .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ + .code = MEDIA_BUS_FMT_RGB888_1X24, + .depth = 24, + .csi_dt = MIPI_CSI2_DT_RGB888, + }, + { + .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ + .code = MEDIA_BUS_FMT_BGR888_1X24, + .depth = 24, + .csi_dt = MIPI_CSI2_DT_RGB888, + }, + { + .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ + .code = MEDIA_BUS_FMT_ARGB8888_1X32, + .depth = 32, + .csi_dt = 0x0, + }, + + /* Bayer Formats */ + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10P, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10P, + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10P, + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10P, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12P, + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12P, + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12P, + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12P, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR14P, + .code = MEDIA_BUS_FMT_SBGGR14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG14P, + .code = MEDIA_BUS_FMT_SGBRG14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG14P, + .code = MEDIA_BUS_FMT_SGRBG14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB14P, + .code = MEDIA_BUS_FMT_SRGGB14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .code = MEDIA_BUS_FMT_SBGGR16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .code = MEDIA_BUS_FMT_SGBRG16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .code = MEDIA_BUS_FMT_SGRBG16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB16, + .code = MEDIA_BUS_FMT_SRGGB16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB }, + }, + /* PiSP Compressed Mode 1 */ + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB, + .code = MEDIA_BUS_FMT_SRGGB16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR, + .code = MEDIA_BUS_FMT_SBGGR16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG, + .code = MEDIA_BUS_FMT_SGBRG16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG, + .code = MEDIA_BUS_FMT_SGRBG16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + /* Greyscale format */ + { + .fourcc = V4L2_PIX_FMT_GREY, + .code = MEDIA_BUS_FMT_Y8_1X8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y10P, + .code = MEDIA_BUS_FMT_Y10_1X10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_RAW10, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y12P, + .code = MEDIA_BUS_FMT_Y12_1X12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_RAW12, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y14P, + .code = MEDIA_BUS_FMT_Y14_1X14, + .depth = 14, + .csi_dt = MIPI_CSI2_DT_RAW14, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_Y16, + .code = MEDIA_BUS_FMT_Y16_1X16, + .depth = 16, + .csi_dt = MIPI_CSI2_DT_RAW16, + .flags = CFE_FORMAT_FLAG_FE_OUT, + .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO }, + }, + { + .fourcc = V4L2_PIX_FMT_PISP_COMP1_MONO, + .code = MEDIA_BUS_FMT_Y16_1X16, + .depth = 8, + .flags = CFE_FORMAT_FLAG_FE_OUT, + }, + + /* Embedded data formats */ + { + .fourcc = V4L2_META_FMT_GENERIC_8, + .code = MEDIA_BUS_FMT_META_8, + .depth = 8, + .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, + { + .fourcc = V4L2_META_FMT_GENERIC_CSI2_10, + .code = MEDIA_BUS_FMT_META_10, + .depth = 10, + .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, + { + .fourcc = V4L2_META_FMT_GENERIC_CSI2_12, + .code = MEDIA_BUS_FMT_META_12, + .depth = 12, + .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, + + /* Frontend formats */ + { + .fourcc = V4L2_META_FMT_RPI_FE_CFG, + .code = MEDIA_BUS_FMT_FIXED, + .flags = CFE_FORMAT_FLAG_META_OUT, + }, + { + .fourcc = V4L2_META_FMT_RPI_FE_STATS, + .code = MEDIA_BUS_FMT_FIXED, + .flags = CFE_FORMAT_FLAG_META_CAP, + }, +}; + +#endif /* _CFE_FMTS_H_ */ diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h new file mode 100644 index 00000000000000..1a36259f51b7bd --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Raspberry Pi Ltd. + * Copyright (c) 2024 Ideas on Board Oy + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cfe + +#if !defined(_CFE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _CFE_TRACE_H + +#include +#include + +TRACE_EVENT(cfe_return_buffer, + TP_PROTO(u32 node_id, u32 buf_idx, u32 queue_id), + TP_ARGS(node_id, buf_idx, queue_id), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, buf_idx) + __field(u32, queue_id) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->buf_idx = buf_idx; + __entry->queue_id = queue_id; + ), + TP_printk("node=%u buf=%u, queue=%u", __entry->node_id, + __entry->buf_idx, __entry->queue_id) +); + +DECLARE_EVENT_CLASS(cfe_buffer_template, + TP_PROTO(u32 node_id, struct vb2_buffer *buf), + TP_ARGS(node_id, buf), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, buf_idx) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->buf_idx = buf->index; + ), + TP_printk("node=%u buf=%u", __entry->node_id, __entry->buf_idx) +); + +DEFINE_EVENT(cfe_buffer_template, cfe_buffer_prepare, + TP_PROTO(u32 node_id, struct vb2_buffer *buf), + TP_ARGS(node_id, buf)); + +TRACE_EVENT(cfe_buffer_queue, + TP_PROTO(u32 node_id, struct vb2_buffer *buf, bool schedule_now), + TP_ARGS(node_id, buf, schedule_now), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, buf_idx) + __field(bool, schedule_now) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->buf_idx = buf->index; + __entry->schedule_now = schedule_now; + ), + TP_printk("node=%u buf=%u%s", __entry->node_id, __entry->buf_idx, + __entry->schedule_now ? " schedule immediately" : "") +); + +DEFINE_EVENT(cfe_buffer_template, cfe_csi2_schedule, + TP_PROTO(u32 node_id, struct vb2_buffer *buf), + TP_ARGS(node_id, buf)); + +DEFINE_EVENT(cfe_buffer_template, cfe_fe_schedule, + TP_PROTO(u32 node_id, struct vb2_buffer *buf), + TP_ARGS(node_id, buf)); + +TRACE_EVENT(cfe_buffer_complete, + TP_PROTO(u32 node_id, struct vb2_v4l2_buffer *buf), + TP_ARGS(node_id, buf), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, buf_idx) + __field(u32, seq) + __field(u64, ts) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->buf_idx = buf->vb2_buf.index; + __entry->seq = buf->sequence; + __entry->ts = buf->vb2_buf.timestamp; + ), + TP_printk("node=%u buf=%u seq=%u ts=%llu", __entry->node_id, + __entry->buf_idx, __entry->seq, __entry->ts) +); + +TRACE_EVENT(cfe_frame_start, + TP_PROTO(u32 node_id, u32 fs_count), + TP_ARGS(node_id, fs_count), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, fs_count) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->fs_count = fs_count; + ), + TP_printk("node=%u fs_count=%u", __entry->node_id, __entry->fs_count) +); + +TRACE_EVENT(cfe_frame_end, + TP_PROTO(u32 node_id, u32 fs_count), + TP_ARGS(node_id, fs_count), + TP_STRUCT__entry( + __field(u32, node_id) + __field(u32, fs_count) + ), + TP_fast_assign( + __entry->node_id = node_id; + __entry->fs_count = fs_count; + ), + TP_printk("node=%u fs_count=%u", __entry->node_id, __entry->fs_count) +); + +TRACE_EVENT(cfe_prepare_next_job, + TP_PROTO(bool fe_enabled), + TP_ARGS(fe_enabled), + TP_STRUCT__entry( + __field(bool, fe_enabled) + ), + TP_fast_assign( + __entry->fe_enabled = fe_enabled; + ), + TP_printk("fe_enabled=%u", __entry->fe_enabled) +); + +/* These are copied from csi2.c */ +#define CSI2_STATUS_IRQ_FS(x) (BIT(0) << (x)) +#define CSI2_STATUS_IRQ_FE(x) (BIT(4) << (x)) +#define CSI2_STATUS_IRQ_FE_ACK(x) (BIT(8) << (x)) +#define CSI2_STATUS_IRQ_LE(x) (BIT(12) << (x)) +#define CSI2_STATUS_IRQ_LE_ACK(x) (BIT(16) << (x)) + +TRACE_EVENT(csi2_irq, + TP_PROTO(u32 channel, u32 status, u32 dbg), + TP_ARGS(channel, status, dbg), + TP_STRUCT__entry( + __field(u32, channel) + __field(u32, status) + __field(u32, dbg) + ), + TP_fast_assign( + __entry->channel = channel; + __entry->status = status; + __entry->dbg = dbg; + ), + TP_printk("ch=%u flags=[ %s%s%s%s%s] frame=%u line=%u\n", + __entry->channel, + (__entry->status & CSI2_STATUS_IRQ_FS(__entry->channel)) ? + "FS " : "", + (__entry->status & CSI2_STATUS_IRQ_FE(__entry->channel)) ? + "FE " : "", + (__entry->status & CSI2_STATUS_IRQ_FE_ACK(__entry->channel)) ? + "FE_ACK " : "", + (__entry->status & CSI2_STATUS_IRQ_LE(__entry->channel)) ? + "LE " : "", + (__entry->status & CSI2_STATUS_IRQ_LE_ACK(__entry->channel)) ? + "LE_ACK " : "", + __entry->dbg >> 16, __entry->dbg & 0xffff) +); + +TRACE_EVENT(fe_irq, + TP_PROTO(u32 status, u32 output_status, u32 frame_status, + u32 error_status, u32 int_status), + TP_ARGS(status, output_status, frame_status, error_status, int_status), + TP_STRUCT__entry( + __field(u32, status) + __field(u32, output_status) + __field(u32, frame_status) + __field(u32, error_status) + __field(u32, int_status) + ), + TP_fast_assign( + __entry->status = status; + __entry->output_status = output_status; + __entry->frame_status = frame_status; + __entry->error_status = error_status; + __entry->int_status = int_status; + ), + TP_printk("status 0x%x out_status 0x%x frame_status 0x%x error_status 0x%x int_status 0x%x", + __entry->status, + __entry->output_status, + __entry->frame_status, + __entry->error_status, + __entry->int_status) +); + +#endif /* _CFE_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE ../../drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace +#include diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c new file mode 100644 index 00000000000000..12660087b12f22 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c @@ -0,0 +1,2509 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RP1 Camera Front End Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#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 "cfe-fmts.h" +#include "cfe.h" +#include "csi2.h" +#include "pisp-fe.h" + +#define CREATE_TRACE_POINTS +#include "cfe-trace.h" + +#define CFE_MODULE_NAME "rp1-cfe" +#define CFE_VERSION "1.0" + +#define cfe_dbg(cfe, fmt, arg...) dev_dbg(&(cfe)->pdev->dev, fmt, ##arg) +#define cfe_info(cfe, fmt, arg...) dev_info(&(cfe)->pdev->dev, fmt, ##arg) +#define cfe_err(cfe, fmt, arg...) dev_err(&(cfe)->pdev->dev, fmt, ##arg) + +/* MIPICFG registers */ +#define MIPICFG_CFG 0x004 +#define MIPICFG_INTR 0x028 +#define MIPICFG_INTE 0x02c +#define MIPICFG_INTF 0x030 +#define MIPICFG_INTS 0x034 + +#define MIPICFG_CFG_SEL_CSI BIT(0) + +#define MIPICFG_INT_CSI_DMA BIT(0) +#define MIPICFG_INT_CSI_HOST BIT(2) +#define MIPICFG_INT_PISP_FE BIT(4) + +#define BPL_ALIGNMENT 16 +#define MAX_BYTESPERLINE 0xffffff00 +#define MAX_BUFFER_SIZE 0xffffff00 +/* + * Max width is therefore determined by the max stride divided by the number of + * bits per pixel. + * + * However, to avoid overflow issues let's use a 16k maximum. This lets us + * calculate 16k * 16k * 4 with 32bits. If we need higher maximums, a careful + * review and adjustment of the code is needed so that it will deal with + * overflows correctly. + */ +#define MAX_WIDTH 16384 +#define MAX_HEIGHT MAX_WIDTH +/* Define a nominal minimum image size */ +#define MIN_WIDTH 16 +#define MIN_HEIGHT 16 + +#define MIN_META_WIDTH 4 +#define MIN_META_HEIGHT 1 + +const struct v4l2_mbus_framefmt cfe_default_format = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_RAW, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_XFER_FUNC_NONE, +}; + +enum node_ids { + /* CSI2 HW output nodes first. */ + CSI2_CH0, + CSI2_CH1, + CSI2_CH2, + CSI2_CH3, + /* FE only nodes from here on. */ + FE_OUT0, + FE_OUT1, + FE_STATS, + FE_CONFIG, + NUM_NODES +}; + +struct node_description { + enum node_ids id; + const char *name; + unsigned int caps; + unsigned int pad_flags; + unsigned int link_pad; +}; + +/* Must match the ordering of enum ids */ +static const struct node_description node_desc[NUM_NODES] = { + [CSI2_CH0] = { + .name = "csi2-ch0", + .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_PAD_FIRST_SOURCE + 0 + }, + /* + * At the moment the main userspace component (libcamera) doesn't + * support metadata with video nodes that support both video and + * metadata. So for the time being this node is set to only support + * V4L2_CAP_META_CAPTURE. + */ + [CSI2_CH1] = { + .name = "csi2-ch1", + .caps = V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_PAD_FIRST_SOURCE + 1 + }, + [CSI2_CH2] = { + .name = "csi2-ch2", + .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_PAD_FIRST_SOURCE + 2 + }, + [CSI2_CH3] = { + .name = "csi2-ch3", + .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = CSI2_PAD_FIRST_SOURCE + 3 + }, + [FE_OUT0] = { + .name = "fe-image0", + .caps = V4L2_CAP_VIDEO_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_OUTPUT0_PAD + }, + [FE_OUT1] = { + .name = "fe-image1", + .caps = V4L2_CAP_VIDEO_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_OUTPUT1_PAD + }, + [FE_STATS] = { + .name = "fe-stats", + .caps = V4L2_CAP_META_CAPTURE, + .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_STATS_PAD + }, + [FE_CONFIG] = { + .name = "fe-config", + .caps = V4L2_CAP_META_OUTPUT, + .pad_flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT, + .link_pad = FE_CONFIG_PAD + }, +}; + +#define is_fe_node(node) (((node)->id) >= FE_OUT0) +#define is_csi2_node(node) (!is_fe_node(node)) + +#define node_supports_image_output(node) \ + (node_desc[(node)->id].caps & V4L2_CAP_VIDEO_CAPTURE) +#define node_supports_meta_output(node) \ + (node_desc[(node)->id].caps & V4L2_CAP_META_CAPTURE) +#define node_supports_image_input(node) \ + (node_desc[(node)->id].caps & V4L2_CAP_VIDEO_OUTPUT) +#define node_supports_meta_input(node) \ + (node_desc[(node)->id].caps & V4L2_CAP_META_OUTPUT) +#define node_supports_image(node) \ + (node_supports_image_output(node) || node_supports_image_input(node)) +#define node_supports_meta(node) \ + (node_supports_meta_output(node) || node_supports_meta_input(node)) + +#define is_image_output_node(node) \ + ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) +#define is_image_input_node(node) \ + ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) +#define is_image_node(node) \ + (is_image_output_node(node) || is_image_input_node(node)) +#define is_meta_output_node(node) \ + ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_CAPTURE) +#define is_meta_input_node(node) \ + ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_OUTPUT) +#define is_meta_node(node) \ + (is_meta_output_node(node) || is_meta_input_node(node)) + +/* To track state across all nodes. */ +#define NODE_REGISTERED BIT(0) +#define NODE_ENABLED BIT(1) +#define NODE_STREAMING BIT(2) +#define FS_INT BIT(3) +#define FE_INT BIT(4) +#define NUM_STATES 5 + +struct cfe_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +struct cfe_config_buffer { + struct cfe_buffer buf; + struct pisp_fe_config config; +}; + +static inline struct cfe_buffer *to_cfe_buffer(struct vb2_buffer *vb) +{ + return container_of(vb, struct cfe_buffer, vb.vb2_buf); +} + +static inline +struct cfe_config_buffer *to_cfe_config_buffer(struct cfe_buffer *buf) +{ + return container_of(buf, struct cfe_config_buffer, buf); +} + +struct cfe_node { + /* Node id */ + enum node_ids id; + /* Pointer pointing to current v4l2_buffer */ + struct cfe_buffer *cur_frm; + /* Pointer pointing to next v4l2_buffer */ + struct cfe_buffer *next_frm; + /* Used to store current pixel format */ + struct v4l2_format vid_fmt; + /* Used to store current meta format */ + struct v4l2_format meta_fmt; + /* Buffer queue used in video-buf */ + struct vb2_queue buffer_queue; + /* Queue of filled frames */ + struct list_head dma_queue; + /* lock used to access this structure */ + struct mutex lock; + /* Identifies video device for this channel */ + struct video_device video_dev; + /* Pointer to the parent handle */ + struct cfe_device *cfe; + /* Media pad for this node */ + struct media_pad pad; + /* Frame-start counter */ + unsigned int fs_count; + /* Timestamp of the current buffer */ + u64 ts; +}; + +struct cfe_device { + struct dentry *debugfs; + struct kref kref; + + /* peripheral base address */ + void __iomem *mipi_cfg_base; + + struct clk *clk; + + /* V4l2 device */ + struct v4l2_device v4l2_dev; + struct media_device mdev; + struct media_pipeline pipe; + + /* IRQ lock for node state and DMA queues */ + spinlock_t state_lock; + bool job_ready; + bool job_queued; + + /* parent device */ + struct platform_device *pdev; + /* subdevice async Notifier */ + struct v4l2_async_notifier notifier; + + /* Source sub device */ + struct v4l2_subdev *source_sd; + /* Source subdev's pad */ + u32 source_pad; + + struct cfe_node node[NUM_NODES]; + DECLARE_BITMAP(node_flags, NUM_STATES * NUM_NODES); + + struct csi2_device csi2; + struct pisp_fe_device fe; + + int fe_csi2_channel; + + /* Mask of enabled streams */ + u64 streams_mask; +}; + +static inline bool is_fe_enabled(struct cfe_device *cfe) +{ + return cfe->fe_csi2_channel != -1; +} + +static inline struct cfe_device *to_cfe_device(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cfe_device, v4l2_dev); +} + +static inline u32 cfg_reg_read(struct cfe_device *cfe, u32 offset) +{ + return readl(cfe->mipi_cfg_base + offset); +} + +static inline void cfg_reg_write(struct cfe_device *cfe, u32 offset, u32 val) +{ + writel(val, cfe->mipi_cfg_base + offset); +} + +static bool check_state(struct cfe_device *cfe, unsigned long state, + unsigned int node_id) +{ + unsigned long bit; + + for_each_set_bit(bit, &state, sizeof(state)) { + if (!test_bit(bit + (node_id * NUM_STATES), cfe->node_flags)) + return false; + } + + return true; +} + +static void set_state(struct cfe_device *cfe, unsigned long state, + unsigned int node_id) +{ + unsigned long bit; + + for_each_set_bit(bit, &state, sizeof(state)) + set_bit(bit + (node_id * NUM_STATES), cfe->node_flags); +} + +static void clear_state(struct cfe_device *cfe, unsigned long state, + unsigned int node_id) +{ + unsigned long bit; + + for_each_set_bit(bit, &state, sizeof(state)) + clear_bit(bit + (node_id * NUM_STATES), cfe->node_flags); +} + +static bool test_any_node(struct cfe_device *cfe, unsigned long cond) +{ + for (unsigned int i = 0; i < NUM_NODES; i++) { + if (check_state(cfe, cond, i)) + return true; + } + + return false; +} + +static bool test_all_nodes(struct cfe_device *cfe, unsigned long precond, + unsigned long cond) +{ + for (unsigned int i = 0; i < NUM_NODES; i++) { + if (check_state(cfe, precond, i)) { + if (!check_state(cfe, cond, i)) + return false; + } + } + + return true; +} + +static int mipi_cfg_regs_show(struct seq_file *s, void *data) +{ + struct cfe_device *cfe = s->private; + int ret; + + ret = pm_runtime_resume_and_get(&cfe->pdev->dev); + if (ret) + return ret; + +#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", cfg_reg_read(cfe, reg)) + DUMP(MIPICFG_CFG); + DUMP(MIPICFG_INTR); + DUMP(MIPICFG_INTE); + DUMP(MIPICFG_INTF); + DUMP(MIPICFG_INTS); +#undef DUMP + + pm_runtime_put(&cfe->pdev->dev); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(mipi_cfg_regs); + +/* Format setup functions */ +const struct cfe_fmt *find_format_by_code(u32 code) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].code == code) + return &formats[i]; + } + + return NULL; +} + +const struct cfe_fmt *find_format_by_pix(u32 pixelformat) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].fourcc == pixelformat) + return &formats[i]; + } + + return NULL; +} + +static const struct cfe_fmt *find_format_by_code_and_fourcc(u32 code, + u32 fourcc) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].code == code && formats[i].fourcc == fourcc) + return &formats[i]; + } + + return NULL; +} + +/* + * Given the mbus code, find the 16 bit remapped code. Returns 0 if no remap + * possible. + */ +u32 cfe_find_16bit_code(u32 code) +{ + const struct cfe_fmt *cfe_fmt; + + cfe_fmt = find_format_by_code(code); + + if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_16BIT]) + return 0; + + cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_16BIT]); + if (!cfe_fmt) + return 0; + + return cfe_fmt->code; +} + +/* + * Given the mbus code, find the 8 bit compressed code. Returns 0 if no remap + * possible. + */ +u32 cfe_find_compressed_code(u32 code) +{ + const struct cfe_fmt *cfe_fmt; + + cfe_fmt = find_format_by_code(code); + + if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_COMPRESSED]) + return 0; + + cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_COMPRESSED]); + if (!cfe_fmt) + return 0; + + return cfe_fmt->code; +} + +static void cfe_calc_vid_format_size_bpl(struct cfe_device *cfe, + const struct cfe_fmt *fmt, + struct v4l2_format *f) +{ + unsigned int min_bytesperline; + + v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2, + &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0, 0); + + min_bytesperline = + ALIGN((f->fmt.pix.width * fmt->depth) >> 3, BPL_ALIGNMENT); + + if (f->fmt.pix.bytesperline > min_bytesperline && + f->fmt.pix.bytesperline <= MAX_BYTESPERLINE) + f->fmt.pix.bytesperline = + ALIGN(f->fmt.pix.bytesperline, BPL_ALIGNMENT); + else + f->fmt.pix.bytesperline = min_bytesperline; + + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + cfe_dbg(cfe, "%s: %p4cc size: %ux%u bpl:%u img_size:%u\n", __func__, + &f->fmt.pix.pixelformat, f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); +} + +static void cfe_calc_meta_format_size_bpl(struct cfe_device *cfe, + const struct cfe_fmt *fmt, + struct v4l2_format *f) +{ + v4l_bound_align_image(&f->fmt.meta.width, MIN_META_WIDTH, MAX_WIDTH, 2, + &f->fmt.meta.height, MIN_META_HEIGHT, MAX_HEIGHT, + 0, 0); + + f->fmt.meta.bytesperline = (f->fmt.meta.width * fmt->depth) >> 3; + f->fmt.meta.buffersize = f->fmt.meta.height * f->fmt.pix.bytesperline; + + cfe_dbg(cfe, "%s: %p4cc size: %ux%u bpl:%u buf_size:%u\n", __func__, + &f->fmt.meta.dataformat, f->fmt.meta.width, f->fmt.meta.height, + f->fmt.meta.bytesperline, f->fmt.meta.buffersize); +} + +static void cfe_schedule_next_csi2_job(struct cfe_device *cfe) +{ + struct cfe_buffer *buf; + dma_addr_t addr; + + for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) { + struct cfe_node *node = &cfe->node[i]; + unsigned int stride, size; + + if (!check_state(cfe, NODE_STREAMING, i)) + continue; + + buf = list_first_entry(&node->dma_queue, struct cfe_buffer, + list); + node->next_frm = buf; + list_del(&buf->list); + + trace_cfe_csi2_schedule(node->id, &buf->vb.vb2_buf); + + if (is_meta_node(node)) { + size = node->meta_fmt.fmt.meta.buffersize; + /* We use CSI2_CH_CTRL_PACK_BYTES, so stride == 0 */ + stride = 0; + } else { + size = node->vid_fmt.fmt.pix.sizeimage; + stride = node->vid_fmt.fmt.pix.bytesperline; + } + + addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + csi2_set_buffer(&cfe->csi2, node->id, addr, stride, size); + } +} + +static void cfe_schedule_next_pisp_job(struct cfe_device *cfe) +{ + struct vb2_buffer *vb2_bufs[FE_NUM_PADS] = { 0 }; + struct cfe_config_buffer *config_buf; + struct cfe_buffer *buf; + + for (unsigned int i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (!check_state(cfe, NODE_STREAMING, i)) + continue; + + buf = list_first_entry(&node->dma_queue, struct cfe_buffer, + list); + + trace_cfe_fe_schedule(node->id, &buf->vb.vb2_buf); + + node->next_frm = buf; + vb2_bufs[node_desc[i].link_pad] = &buf->vb.vb2_buf; + list_del(&buf->list); + } + + config_buf = to_cfe_config_buffer(cfe->node[FE_CONFIG].next_frm); + pisp_fe_submit_job(&cfe->fe, vb2_bufs, &config_buf->config); +} + +static bool cfe_check_job_ready(struct cfe_device *cfe) +{ + for (unsigned int i = 0; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (!check_state(cfe, NODE_ENABLED, i)) + continue; + + if (list_empty(&node->dma_queue)) + return false; + } + + return true; +} + +static void cfe_prepare_next_job(struct cfe_device *cfe) +{ + trace_cfe_prepare_next_job(is_fe_enabled(cfe)); + + cfe->job_queued = true; + cfe_schedule_next_csi2_job(cfe); + if (is_fe_enabled(cfe)) + cfe_schedule_next_pisp_job(cfe); + + /* Flag if another job is ready after this. */ + cfe->job_ready = cfe_check_job_ready(cfe); +} + +static void cfe_process_buffer_complete(struct cfe_node *node, + enum vb2_buffer_state state) +{ + trace_cfe_buffer_complete(node->id, &node->cur_frm->vb); + + node->cur_frm->vb.sequence = node->fs_count - 1; + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); +} + +static void cfe_queue_event_sof(struct cfe_node *node) +{ + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, + .u.frame_sync.frame_sequence = node->fs_count - 1, + }; + + v4l2_event_queue(&node->video_dev, &event); +} + +static void cfe_sof_isr(struct cfe_node *node) +{ + struct cfe_device *cfe = node->cfe; + bool matching_fs = true; + + trace_cfe_frame_start(node->id, node->fs_count); + + /* + * If the sensor is producing unexpected frame event ordering over a + * sustained period of time, guard against the possibility of coming + * here and orphaning the cur_frm if it's not been dequeued already. + * Unfortunately, there is not enough hardware state to tell if this + * may have occurred. + */ + if (WARN(node->cur_frm, "%s: [%s] Orphaned frame at seq %u\n", + __func__, node_desc[node->id].name, node->fs_count)) + cfe_process_buffer_complete(node, VB2_BUF_STATE_ERROR); + + node->cur_frm = node->next_frm; + node->next_frm = NULL; + node->fs_count++; + + node->ts = ktime_get_ns(); + for (unsigned int i = 0; i < NUM_NODES; i++) { + if (!check_state(cfe, NODE_STREAMING, i) || i == node->id) + continue; + /* + * This checks if any other node has seen a FS. If yes, use the + * same timestamp, eventually across all node buffers. + */ + if (cfe->node[i].fs_count >= node->fs_count) + node->ts = cfe->node[i].ts; + /* + * This checks if all other node have seen a matching FS. If + * yes, we can flag another job to be queued. + */ + if (matching_fs && cfe->node[i].fs_count != node->fs_count) + matching_fs = false; + } + + if (matching_fs) + cfe->job_queued = false; + + if (node->cur_frm) + node->cur_frm->vb.vb2_buf.timestamp = node->ts; + + set_state(cfe, FS_INT, node->id); + clear_state(cfe, FE_INT, node->id); + + if (is_image_output_node(node)) + cfe_queue_event_sof(node); +} + +static void cfe_eof_isr(struct cfe_node *node) +{ + struct cfe_device *cfe = node->cfe; + + trace_cfe_frame_end(node->id, node->fs_count - 1); + + if (node->cur_frm) + cfe_process_buffer_complete(node, VB2_BUF_STATE_DONE); + + node->cur_frm = NULL; + set_state(cfe, FE_INT, node->id); + clear_state(cfe, FS_INT, node->id); +} + +static irqreturn_t cfe_isr(int irq, void *dev) +{ + struct cfe_device *cfe = dev; + bool sof[NUM_NODES] = { 0 }, eof[NUM_NODES] = { 0 }; + u32 sts; + + sts = cfg_reg_read(cfe, MIPICFG_INTS); + + if (sts & MIPICFG_INT_CSI_DMA) + csi2_isr(&cfe->csi2, sof, eof); + + if (sts & MIPICFG_INT_PISP_FE) + pisp_fe_isr(&cfe->fe, sof + CSI2_NUM_CHANNELS, + eof + CSI2_NUM_CHANNELS); + + spin_lock(&cfe->state_lock); + + for (unsigned int i = 0; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + /* + * The check_state(NODE_STREAMING) is to ensure we do not loop + * over the CSI2_CHx nodes when the FE is active since they + * generate interrupts even though the node is not streaming. + */ + if (!check_state(cfe, NODE_STREAMING, i) || !(sof[i] || eof[i])) + continue; + + /* + * There are 3 cases where we could get FS + FE_ACK at + * the same time: + * 1) FE of the current frame, and FS of the next frame. + * 2) FS + FE of the same frame. + * 3) FE of the current frame, and FS + FE of the next + * frame. To handle this, see the sof handler below. + * + * (1) is handled implicitly by the ordering of the FE and FS + * handlers below. + */ + if (eof[i]) { + /* + * The condition below tests for (2). Run the FS handler + * first before the FE handler, both for the current + * frame. + */ + if (sof[i] && !check_state(cfe, FS_INT, i)) { + cfe_sof_isr(node); + sof[i] = false; + } + + cfe_eof_isr(node); + } + + if (sof[i]) { + /* + * The condition below tests for (3). In such cases, we + * come in here with FS flag set in the node state from + * the previous frame since it only gets cleared in + * cfe_eof_isr(). Handle the FE for the previous + * frame first before the FS handler for the current + * frame. + */ + if (check_state(cfe, FS_INT, node->id) && + !check_state(cfe, FE_INT, node->id)) { + cfe_dbg(cfe, "%s: [%s] Handling missing previous FE interrupt\n", + __func__, node_desc[node->id].name); + cfe_eof_isr(node); + } + + cfe_sof_isr(node); + } + + if (!cfe->job_queued && cfe->job_ready) + cfe_prepare_next_job(cfe); + } + + spin_unlock(&cfe->state_lock); + + return IRQ_HANDLED; +} + +/* + * Stream helpers + */ + +static int cfe_get_vc_dt_fallback(struct cfe_device *cfe, u8 *vc, u8 *dt) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + const struct cfe_fmt *cfe_fmt; + + state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); + + fmt = v4l2_subdev_state_get_format(state, CSI2_PAD_SINK, 0); + if (!fmt) + return -EINVAL; + + cfe_fmt = find_format_by_code(fmt->code); + if (!cfe_fmt) + return -EINVAL; + + *vc = 0; + *dt = cfe_fmt->csi_dt; + + return 0; +} + +static int cfe_get_vc_dt(struct cfe_device *cfe, unsigned int channel, u8 *vc, + u8 *dt) +{ + struct v4l2_mbus_frame_desc remote_desc; + struct v4l2_subdev_state *state; + u32 sink_stream; + unsigned int i; + int ret; + + state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); + + ret = v4l2_subdev_routing_find_opposite_end(&state->routing, + CSI2_PAD_FIRST_SOURCE + channel, 0, NULL, &sink_stream); + if (ret) + return ret; + + ret = v4l2_subdev_call(cfe->source_sd, pad, get_frame_desc, + cfe->source_pad, &remote_desc); + if (ret == -ENOIOCTLCMD) { + cfe_dbg(cfe, "source does not support get_frame_desc, use fallback\n"); + return cfe_get_vc_dt_fallback(cfe, vc, dt); + } else if (ret) { + cfe_err(cfe, "Failed to get frame descriptor\n"); + return ret; + } + + if (remote_desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + cfe_err(cfe, "Frame descriptor does not describe CSI-2 link"); + return -EINVAL; + } + + for (i = 0; i < remote_desc.num_entries; i++) { + if (remote_desc.entry[i].stream == sink_stream) + break; + } + + if (i == remote_desc.num_entries) { + cfe_err(cfe, "Stream %u not found in remote frame desc\n", + sink_stream); + return -EINVAL; + } + + *vc = remote_desc.entry[i].bus.csi2.vc; + *dt = remote_desc.entry[i].bus.csi2.dt; + + return 0; +} + +static int cfe_start_channel(struct cfe_node *node) +{ + struct cfe_device *cfe = node->cfe; + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *source_fmt; + const struct cfe_fmt *fmt; + unsigned long flags; + bool start_fe; + int ret; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + start_fe = is_fe_enabled(cfe) && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); + + state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); + + if (start_fe) { + unsigned int width, height; + u8 vc, dt; + + cfe_dbg(cfe, "%s: %s using csi2 channel %d\n", __func__, + node_desc[FE_OUT0].name, cfe->fe_csi2_channel); + + ret = cfe_get_vc_dt(cfe, cfe->fe_csi2_channel, &vc, &dt); + if (ret) + return ret; + + source_fmt = v4l2_subdev_state_get_format(state, + node_desc[cfe->fe_csi2_channel].link_pad); + fmt = find_format_by_code(source_fmt->code); + + width = source_fmt->width; + height = source_fmt->height; + + /* Must have a valid CSI2 datatype. */ + WARN_ON(!fmt->csi_dt); + + /* + * Start the associated CSI2 Channel as well. + * + * Must write to the ADDR register to latch the ctrl values + * even if we are connected to the front end. Once running, + * this is handled by the CSI2 AUTO_ARM mode. + */ + csi2_start_channel(&cfe->csi2, cfe->fe_csi2_channel, + CSI2_MODE_FE_STREAMING, + true, false, width, height, vc, dt); + csi2_set_buffer(&cfe->csi2, cfe->fe_csi2_channel, 0, 0, -1); + pisp_fe_start(&cfe->fe); + } + + if (is_csi2_node(node)) { + unsigned int width = 0, height = 0; + u8 vc, dt; + + ret = cfe_get_vc_dt(cfe, node->id, &vc, &dt); + if (ret) { + if (start_fe) { + csi2_stop_channel(&cfe->csi2, + cfe->fe_csi2_channel); + pisp_fe_stop(&cfe->fe); + } + + return ret; + } + + u32 mode = CSI2_MODE_NORMAL; + + source_fmt = v4l2_subdev_state_get_format(state, + node_desc[node->id].link_pad); + fmt = find_format_by_code(source_fmt->code); + + /* Must have a valid CSI2 datatype. */ + WARN_ON(!fmt->csi_dt); + + if (is_image_output_node(node)) { + u32 pixfmt; + + width = source_fmt->width; + height = source_fmt->height; + + pixfmt = node->vid_fmt.fmt.pix.pixelformat; + + if (pixfmt == fmt->remap[CFE_REMAP_16BIT]) { + mode = CSI2_MODE_REMAP; + } else if (pixfmt == fmt->remap[CFE_REMAP_COMPRESSED]) { + mode = CSI2_MODE_COMPRESSED; + csi2_set_compression(&cfe->csi2, node->id, + CSI2_COMPRESSION_DELTA, 0, + 0); + } + } + /* Unconditionally start this CSI2 channel. */ + csi2_start_channel(&cfe->csi2, node->id, + mode, + /* Auto arm */ + false, + /* Pack bytes */ + is_meta_node(node) ? true : false, + width, height, vc, dt); + } + + spin_lock_irqsave(&cfe->state_lock, flags); + if (cfe->job_ready && test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) + cfe_prepare_next_job(cfe); + spin_unlock_irqrestore(&cfe->state_lock, flags); + + return 0; +} + +static void cfe_stop_channel(struct cfe_node *node, bool fe_stop) +{ + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s] fe_stop %u\n", __func__, + node_desc[node->id].name, fe_stop); + + if (fe_stop) { + csi2_stop_channel(&cfe->csi2, cfe->fe_csi2_channel); + pisp_fe_stop(&cfe->fe); + } + + if (is_csi2_node(node)) + csi2_stop_channel(&cfe->csi2, node->id); +} + +static void cfe_return_buffers(struct cfe_node *node, + enum vb2_buffer_state state) +{ + struct cfe_device *cfe = node->cfe; + struct cfe_buffer *buf, *tmp; + unsigned long flags; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + spin_lock_irqsave(&cfe->state_lock, flags); + list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) { + list_del(&buf->list); + trace_cfe_return_buffer(node->id, buf->vb.vb2_buf.index, 2); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + + if (node->cur_frm) { + trace_cfe_return_buffer(node->id, + node->cur_frm->vb.vb2_buf.index, 0); + vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state); + } + if (node->next_frm && node->cur_frm != node->next_frm) { + trace_cfe_return_buffer(node->id, + node->next_frm->vb.vb2_buf.index, 1); + vb2_buffer_done(&node->next_frm->vb.vb2_buf, state); + } + + node->cur_frm = NULL; + node->next_frm = NULL; + spin_unlock_irqrestore(&cfe->state_lock, flags); +} + +/* + * vb2 ops + */ + +static int cfe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct cfe_node *node = vb2_get_drv_priv(vq); + struct cfe_device *cfe = node->cfe; + unsigned int size = is_image_node(node) ? + node->vid_fmt.fmt.pix.sizeimage : + node->meta_fmt.fmt.meta.buffersize; + + cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, + node->buffer_queue.type); + + if (vq->max_num_buffers + *nbuffers < 3) + *nbuffers = 3 - vq->max_num_buffers; + + if (*nplanes) { + if (sizes[0] < size) { + cfe_err(cfe, "sizes[0] %i < size %u\n", sizes[0], size); + return -EINVAL; + } + size = sizes[0]; + } + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int cfe_buffer_prepare(struct vb2_buffer *vb) +{ + struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); + struct cfe_device *cfe = node->cfe; + struct cfe_buffer *buf = to_cfe_buffer(vb); + unsigned long size; + + trace_cfe_buffer_prepare(node->id, vb); + + size = is_image_node(node) ? node->vid_fmt.fmt.pix.sizeimage : + node->meta_fmt.fmt.meta.buffersize; + if (vb2_plane_size(vb, 0) < size) { + cfe_err(cfe, "data will not fit into plane (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); + + if (node->id == FE_CONFIG) { + struct cfe_config_buffer *b = to_cfe_config_buffer(buf); + void *addr = vb2_plane_vaddr(vb, 0); + + memcpy(&b->config, addr, sizeof(struct pisp_fe_config)); + return pisp_fe_validate_config(&cfe->fe, &b->config, + &cfe->node[FE_OUT0].vid_fmt, + &cfe->node[FE_OUT1].vid_fmt); + } + + return 0; +} + +static void cfe_buffer_queue(struct vb2_buffer *vb) +{ + struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue); + struct cfe_device *cfe = node->cfe; + struct cfe_buffer *buf = to_cfe_buffer(vb); + unsigned long flags; + bool schedule_now; + + spin_lock_irqsave(&cfe->state_lock, flags); + + list_add_tail(&buf->list, &node->dma_queue); + + if (!cfe->job_ready) + cfe->job_ready = cfe_check_job_ready(cfe); + + schedule_now = !cfe->job_queued && cfe->job_ready && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); + + trace_cfe_buffer_queue(node->id, vb, schedule_now); + + if (schedule_now) + cfe_prepare_next_job(cfe); + + spin_unlock_irqrestore(&cfe->state_lock, flags); +} + +static s64 cfe_get_source_link_freq(struct cfe_device *cfe) +{ + struct v4l2_subdev_state *state; + s64 link_freq; + u32 bpp; + + state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd); + + /* + * v4l2_get_link_freq() uses V4L2_CID_LINK_FREQ first, and falls back + * to V4L2_CID_PIXEL_RATE if V4L2_CID_LINK_FREQ is not available. + * + * With multistream input there is no single pixel rate, and thus we + * cannot use V4L2_CID_PIXEL_RATE, so we pass 0 as the bpp which + * causes v4l2_get_link_freq() to return an error if it falls back to + * V4L2_CID_PIXEL_RATE. + */ + + if (state->routing.num_routes == 1) { + struct v4l2_subdev_route *route = &state->routing.routes[0]; + struct v4l2_mbus_framefmt *source_fmt; + const struct cfe_fmt *fmt; + + source_fmt = v4l2_subdev_state_get_format(state, + route->sink_pad, + route->sink_stream); + + fmt = find_format_by_code(source_fmt->code); + if (!fmt) + return -EINVAL; + + bpp = fmt->depth; + } else { + bpp = 0; + } + + link_freq = v4l2_get_link_freq(cfe->source_sd->ctrl_handler, bpp, + 2 * cfe->csi2.dphy.active_lanes); + if (link_freq < 0) + cfe_err(cfe, "failed to get link freq for subdev '%s'\n", + cfe->source_sd->name); + + return link_freq; +} + +static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct v4l2_mbus_config mbus_config = { 0 }; + struct cfe_node *node = vb2_get_drv_priv(vq); + struct cfe_device *cfe = node->cfe; + struct v4l2_subdev_state *state; + struct v4l2_subdev_route *route; + s64 link_freq; + int ret; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + if (!check_state(cfe, NODE_ENABLED, node->id)) { + cfe_err(cfe, "%s node link is not enabled.\n", + node_desc[node->id].name); + ret = -EINVAL; + goto err_streaming; + } + + ret = pm_runtime_resume_and_get(&cfe->pdev->dev); + if (ret < 0) { + cfe_err(cfe, "pm_runtime_resume_and_get failed\n"); + goto err_streaming; + } + + /* When using the Frontend, we must enable the FE_CONFIG node. */ + if (is_fe_enabled(cfe) && + !check_state(cfe, NODE_ENABLED, cfe->node[FE_CONFIG].id)) { + cfe_err(cfe, "FE enabled, but FE_CONFIG node is not\n"); + ret = -EINVAL; + goto err_pm_put; + } + + ret = media_pipeline_start(&node->pad, &cfe->pipe); + if (ret < 0) { + cfe_err(cfe, "Failed to start media pipeline: %d\n", ret); + goto err_pm_put; + } + + state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); + + clear_state(cfe, FS_INT | FE_INT, node->id); + set_state(cfe, NODE_STREAMING, node->id); + node->fs_count = 0; + + ret = cfe_start_channel(node); + if (ret) + goto err_unlock_state; + + if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) { + cfe_dbg(cfe, "Streaming on hold, as all nodes are not set to streaming yet\n"); + v4l2_subdev_unlock_state(state); + return 0; + } + + cfg_reg_write(cfe, MIPICFG_CFG, MIPICFG_CFG_SEL_CSI); + cfg_reg_write(cfe, MIPICFG_INTE, + MIPICFG_INT_CSI_DMA | MIPICFG_INT_PISP_FE); + + ret = v4l2_subdev_call(cfe->source_sd, pad, get_mbus_config, 0, + &mbus_config); + if (ret < 0 && ret != -ENOIOCTLCMD) { + cfe_err(cfe, "g_mbus_config failed\n"); + goto err_clear_inte; + } + + cfe->csi2.dphy.active_lanes = mbus_config.bus.mipi_csi2.num_data_lanes; + if (!cfe->csi2.dphy.active_lanes) + cfe->csi2.dphy.active_lanes = cfe->csi2.dphy.max_lanes; + if (cfe->csi2.dphy.active_lanes > cfe->csi2.dphy.max_lanes) { + cfe_err(cfe, "Device has requested %u data lanes, which is >%u configured in DT\n", + cfe->csi2.dphy.active_lanes, cfe->csi2.dphy.max_lanes); + ret = -EINVAL; + goto err_clear_inte; + } + + link_freq = cfe_get_source_link_freq(cfe); + if (link_freq < 0) + goto err_clear_inte; + + cfe->csi2.dphy.dphy_rate = div_s64(link_freq * 2, 1000000); + csi2_open_rx(&cfe->csi2); + + cfe->streams_mask = 0; + + for_each_active_route(&state->routing, route) + cfe->streams_mask |= BIT_ULL(route->sink_stream); + + ret = v4l2_subdev_enable_streams(cfe->source_sd, cfe->source_pad, + cfe->streams_mask); + if (ret) { + cfe_err(cfe, "stream on failed in subdev\n"); + goto err_disable_cfe; + } + + cfe_dbg(cfe, "Streaming enabled\n"); + + v4l2_subdev_unlock_state(state); + + return 0; + +err_disable_cfe: + csi2_close_rx(&cfe->csi2); +err_clear_inte: + cfg_reg_write(cfe, MIPICFG_INTE, 0); + + cfe_stop_channel(node, + is_fe_enabled(cfe) && test_all_nodes(cfe, NODE_ENABLED, + NODE_STREAMING)); +err_unlock_state: + v4l2_subdev_unlock_state(state); + media_pipeline_stop(&node->pad); +err_pm_put: + pm_runtime_put(&cfe->pdev->dev); +err_streaming: + cfe_return_buffers(node, VB2_BUF_STATE_QUEUED); + clear_state(cfe, NODE_STREAMING, node->id); + + return ret; +} + +static void cfe_stop_streaming(struct vb2_queue *vq) +{ + struct cfe_node *node = vb2_get_drv_priv(vq); + struct cfe_device *cfe = node->cfe; + unsigned long flags; + bool fe_stop; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + spin_lock_irqsave(&cfe->state_lock, flags); + fe_stop = is_fe_enabled(cfe) && + test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING); + + cfe->job_ready = false; + clear_state(cfe, NODE_STREAMING, node->id); + spin_unlock_irqrestore(&cfe->state_lock, flags); + + cfe_stop_channel(node, fe_stop); + + if (!test_any_node(cfe, NODE_STREAMING)) { + struct v4l2_subdev_state *state; + int ret; + + state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd); + + ret = v4l2_subdev_disable_streams(cfe->source_sd, + cfe->source_pad, + cfe->streams_mask); + if (ret) + cfe_err(cfe, "stream disable failed in subdev\n"); + + v4l2_subdev_unlock_state(state); + + csi2_close_rx(&cfe->csi2); + + cfg_reg_write(cfe, MIPICFG_INTE, 0); + + cfe_dbg(cfe, "%s: Streaming disabled\n", __func__); + } + + media_pipeline_stop(&node->pad); + + /* Clear all queued buffers for the node */ + cfe_return_buffers(node, VB2_BUF_STATE_ERROR); + + pm_runtime_put(&cfe->pdev->dev); +} + +static const struct vb2_ops cfe_video_qops = { + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .queue_setup = cfe_queue_setup, + .buf_prepare = cfe_buffer_prepare, + .buf_queue = cfe_buffer_queue, + .start_streaming = cfe_start_streaming, + .stop_streaming = cfe_stop_streaming, +}; + +/* + * v4l2 ioctl ops + */ + +static int cfe_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, CFE_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, CFE_MODULE_NAME, sizeof(cap->card)); + + cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_META_OUTPUT; + + return 0; +} + +static int cfe_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + unsigned int i, j; + + if (!node_supports_image_output(node)) + return -EINVAL; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) { + if (f->mbus_code && formats[i].code != f->mbus_code) + continue; + + if (formats[i].flags & CFE_FORMAT_FLAG_META_OUT || + formats[i].flags & CFE_FORMAT_FLAG_META_CAP) + continue; + + if (is_fe_node(node) && + !(formats[i].flags & CFE_FORMAT_FLAG_FE_OUT)) + continue; + + if (j == f->index) { + f->pixelformat = formats[i].fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; + } + j++; + } + + return -EINVAL; +} + +static int cfe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + + if (!node_supports_image(node)) + return -EINVAL; + + *f = node->vid_fmt; + + return 0; +} + +static int cfe_validate_fmt_vid_cap(struct cfe_node *node, + struct v4l2_format *f) +{ + struct cfe_device *cfe = node->cfe; + const struct cfe_fmt *fmt; + + cfe_dbg(cfe, "%s: [%s] %ux%u, V4L2 pix %p4cc\n", __func__, + node_desc[node->id].name, f->fmt.pix.width, f->fmt.pix.height, + &f->fmt.pix.pixelformat); + + if (!node_supports_image_output(node)) + return -EINVAL; + + /* + * Default to a format that works for both CSI2 and FE. + */ + fmt = find_format_by_pix(f->fmt.pix.pixelformat); + if (!fmt) + fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10); + + f->fmt.pix.pixelformat = fmt->fourcc; + + if (is_fe_node(node) && fmt->remap[CFE_REMAP_16BIT]) { + f->fmt.pix.pixelformat = fmt->remap[CFE_REMAP_16BIT]; + fmt = find_format_by_pix(f->fmt.pix.pixelformat); + } + + f->fmt.pix.field = V4L2_FIELD_NONE; + + cfe_calc_vid_format_size_bpl(cfe, fmt, f); + + return 0; +} + +static int cfe_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + struct vb2_queue *q = &node->buffer_queue; + int ret; + + if (vb2_is_busy(q)) + return -EBUSY; + + ret = cfe_validate_fmt_vid_cap(node, f); + if (ret) + return ret; + + node->vid_fmt = *f; + + cfe_dbg(cfe, "%s: Set %ux%u, V4L2 pix %p4cc\n", __func__, + node->vid_fmt.fmt.pix.width, node->vid_fmt.fmt.pix.height, + &node->vid_fmt.fmt.pix.pixelformat); + + return 0; +} + +static int cfe_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + return cfe_validate_fmt_vid_cap(node, f); +} + +static int cfe_enum_fmt_meta(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + if (!node_supports_meta(node)) + return -EINVAL; + + switch (node->id) { + case CSI2_CH0...CSI2_CH3: + f->flags = V4L2_FMT_FLAG_META_LINE_BASED; + + switch (f->index) { + case 0: + f->pixelformat = V4L2_META_FMT_GENERIC_8; + return 0; + case 1: + f->pixelformat = V4L2_META_FMT_GENERIC_CSI2_10; + return 0; + case 2: + f->pixelformat = V4L2_META_FMT_GENERIC_CSI2_12; + return 0; + default: + return -EINVAL; + } + default: + break; + } + + if (f->index != 0) + return -EINVAL; + + switch (node->id) { + case FE_STATS: + f->pixelformat = V4L2_META_FMT_RPI_FE_STATS; + return 0; + case FE_CONFIG: + f->pixelformat = V4L2_META_FMT_RPI_FE_CFG; + return 0; + default: + return -EINVAL; + } +} + +static int cfe_validate_fmt_meta(struct cfe_node *node, struct v4l2_format *f) +{ + struct cfe_device *cfe = node->cfe; + const struct cfe_fmt *fmt; + + switch (node->id) { + case CSI2_CH0...CSI2_CH3: + cfe_dbg(cfe, "%s: [%s] %ux%u, V4L2 meta %p4cc\n", __func__, + node_desc[node->id].name, f->fmt.meta.width, + f->fmt.meta.height, &f->fmt.meta.dataformat); + break; + case FE_STATS: + case FE_CONFIG: + cfe_dbg(cfe, "%s: [%s] %u bytes, V4L2 meta %p4cc\n", __func__, + node_desc[node->id].name, f->fmt.meta.buffersize, + &f->fmt.meta.dataformat); + break; + default: + return -EINVAL; + } + + if (!node_supports_meta(node)) + return -EINVAL; + + switch (node->id) { + case CSI2_CH0...CSI2_CH3: + fmt = find_format_by_pix(f->fmt.meta.dataformat); + if (!fmt || !(fmt->flags & CFE_FORMAT_FLAG_META_CAP)) + fmt = find_format_by_pix(V4L2_META_FMT_GENERIC_CSI2_10); + + f->fmt.meta.dataformat = fmt->fourcc; + + cfe_calc_meta_format_size_bpl(cfe, fmt, f); + + return 0; + case FE_STATS: + f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_STATS; + f->fmt.meta.buffersize = sizeof(struct pisp_statistics); + return 0; + case FE_CONFIG: + f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_CFG; + f->fmt.meta.buffersize = sizeof(struct pisp_fe_config); + return 0; + default: + return -EINVAL; + } +} + +static int cfe_g_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + if (!node_supports_meta(node)) + return -EINVAL; + + *f = node->meta_fmt; + + return 0; +} + +static int cfe_s_fmt_meta(struct file *file, void *priv, struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + struct vb2_queue *q = &node->buffer_queue; + int ret; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + + if (vb2_is_busy(q)) + return -EBUSY; + + if (!node_supports_meta(node)) + return -EINVAL; + + ret = cfe_validate_fmt_meta(node, f); + if (ret) + return ret; + + node->meta_fmt = *f; + + cfe_dbg(cfe, "%s: Set %p4cc\n", __func__, + &node->meta_fmt.fmt.meta.dataformat); + + return 0; +} + +static int cfe_try_fmt_meta(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + + cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name); + return cfe_validate_fmt_meta(node, f); +} + +static int cfe_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct cfe_node *node = video_drvdata(file); + struct cfe_device *cfe = node->cfe; + const struct cfe_fmt *fmt; + + cfe_dbg(cfe, "%s [%s]\n", __func__, node_desc[node->id].name); + + if (fsize->index > 0) + return -EINVAL; + + /* check for valid format */ + fmt = find_format_by_pix(fsize->pixel_format); + if (!fmt) { + cfe_dbg(cfe, "Invalid pixel code: %x\n", fsize->pixel_format); + return -EINVAL; + } + + /* TODO: Do we have limits on the step_width? */ + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_WIDTH; + fsize->stepwise.max_width = MAX_WIDTH; + fsize->stepwise.step_width = 2; + fsize->stepwise.min_height = MIN_HEIGHT; + fsize->stepwise.max_height = MAX_HEIGHT; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int cfe_vb2_ioctl_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct video_device *vdev = video_devdata(file); + struct cfe_node *node = video_get_drvdata(vdev); + struct cfe_device *cfe = node->cfe; + int ret; + + cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, + p->type); + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->type != V4L2_BUF_TYPE_META_CAPTURE && + p->type != V4L2_BUF_TYPE_META_OUTPUT) + return -EINVAL; + + ret = vb2_queue_change_type(vdev->queue, p->type); + if (ret) + return ret; + + return vb2_ioctl_reqbufs(file, priv, p); +} + +static int cfe_vb2_ioctl_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *p) +{ + struct video_device *vdev = video_devdata(file); + struct cfe_node *node = video_get_drvdata(vdev); + struct cfe_device *cfe = node->cfe; + int ret; + + cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, + p->format.type); + + if (p->format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + p->format.type != V4L2_BUF_TYPE_META_CAPTURE && + p->format.type != V4L2_BUF_TYPE_META_OUTPUT) + return -EINVAL; + + ret = vb2_queue_change_type(vdev->queue, p->format.type); + if (ret) + return ret; + + return vb2_ioctl_create_bufs(file, priv, p); +} + +static int cfe_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct cfe_node *node = video_get_drvdata(fh->vdev); + + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: + if (!node_supports_image_output(node)) + break; + + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + if (!node_supports_image_output(node) && + !node_supports_meta_output(node)) + break; + + return v4l2_event_subscribe(fh, sub, 4, NULL); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static const struct v4l2_ioctl_ops cfe_ioctl_ops = { + .vidioc_querycap = cfe_querycap, + .vidioc_enum_fmt_vid_cap = cfe_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cfe_g_fmt, + .vidioc_s_fmt_vid_cap = cfe_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cfe_try_fmt_vid_cap, + + .vidioc_enum_fmt_meta_cap = cfe_enum_fmt_meta, + .vidioc_g_fmt_meta_cap = cfe_g_fmt_meta, + .vidioc_s_fmt_meta_cap = cfe_s_fmt_meta, + .vidioc_try_fmt_meta_cap = cfe_try_fmt_meta, + + .vidioc_enum_fmt_meta_out = cfe_enum_fmt_meta, + .vidioc_g_fmt_meta_out = cfe_g_fmt_meta, + .vidioc_s_fmt_meta_out = cfe_s_fmt_meta, + .vidioc_try_fmt_meta_out = cfe_try_fmt_meta, + + .vidioc_enum_framesizes = cfe_enum_framesizes, + + .vidioc_reqbufs = cfe_vb2_ioctl_reqbufs, + .vidioc_create_bufs = cfe_vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_subscribe_event = cfe_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static void cfe_notify(struct v4l2_subdev *sd, unsigned int notification, + void *arg) +{ + struct cfe_device *cfe = to_cfe_device(sd->v4l2_dev); + + switch (notification) { + case V4L2_DEVICE_NOTIFY_EVENT: + for (unsigned int i = 0; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (check_state(cfe, NODE_REGISTERED, i)) + continue; + + v4l2_event_queue(&node->video_dev, arg); + } + break; + default: + break; + } +} + +/* cfe capture driver file operations */ +static const struct v4l2_file_operations cfe_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static int cfe_video_link_validate(struct media_link *link) +{ + struct video_device *vd = container_of(link->sink->entity, + struct video_device, entity); + struct cfe_node *node = container_of(vd, struct cfe_node, video_dev); + struct cfe_device *cfe = node->cfe; + struct v4l2_mbus_framefmt *source_fmt; + struct v4l2_subdev_state *state; + struct v4l2_subdev *source_sd; + int ret = 0; + + cfe_dbg(cfe, "%s: [%s] link \"%s\":%u -> \"%s\":%u\n", __func__, + node_desc[node->id].name, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + if (!media_entity_remote_source_pad_unique(link->sink->entity)) { + cfe_err(cfe, "video node %s pad not connected\n", vd->name); + return -ENOTCONN; + } + + source_sd = media_entity_to_v4l2_subdev(link->source->entity); + + state = v4l2_subdev_lock_and_get_active_state(source_sd); + + source_fmt = v4l2_subdev_state_get_format(state, link->source->index); + if (!source_fmt) { + ret = -EINVAL; + goto out; + } + + if (is_image_output_node(node)) { + struct v4l2_pix_format *pix_fmt = &node->vid_fmt.fmt.pix; + const struct cfe_fmt *fmt; + + if (source_fmt->width != pix_fmt->width || + source_fmt->height != pix_fmt->height) { + cfe_err(cfe, "Wrong width or height %ux%u (remote pad set to %ux%u)\n", + pix_fmt->width, pix_fmt->height, + source_fmt->width, source_fmt->height); + ret = -EINVAL; + goto out; + } + + fmt = find_format_by_code_and_fourcc(source_fmt->code, + pix_fmt->pixelformat); + if (!fmt) { + cfe_err(cfe, "Format mismatch!\n"); + ret = -EINVAL; + goto out; + } + } else if (is_csi2_node(node) && is_meta_output_node(node)) { + struct v4l2_meta_format *meta_fmt = &node->meta_fmt.fmt.meta; + const struct cfe_fmt *fmt; + + if (source_fmt->width != meta_fmt->width || + source_fmt->height != meta_fmt->height) { + cfe_err(cfe, "Wrong width or height %ux%u (remote pad set to %ux%u)\n", + meta_fmt->width, meta_fmt->height, + source_fmt->width, source_fmt->height); + ret = -EINVAL; + goto out; + } + + fmt = find_format_by_code_and_fourcc(source_fmt->code, + meta_fmt->dataformat); + if (!fmt) { + cfe_err(cfe, "Format mismatch!\n"); + ret = -EINVAL; + goto out; + } + } + +out: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static const struct media_entity_operations cfe_media_entity_ops = { + .link_validate = cfe_video_link_validate, +}; + +static int cfe_video_link_notify(struct media_link *link, u32 flags, + unsigned int notification) +{ + struct media_device *mdev = link->graph_obj.mdev; + struct cfe_device *cfe = container_of(mdev, struct cfe_device, mdev); + struct media_entity *fe = &cfe->fe.sd.entity; + struct media_entity *csi2 = &cfe->csi2.sd.entity; + unsigned long lock_flags; + + if (notification != MEDIA_DEV_NOTIFY_POST_LINK_CH) + return 0; + + cfe_dbg(cfe, "%s: %s[%u] -> %s[%u] 0x%x", __func__, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, flags); + + spin_lock_irqsave(&cfe->state_lock, lock_flags); + + for (unsigned int i = 0; i < NUM_NODES; i++) { + if (link->sink->entity != &cfe->node[i].video_dev.entity && + link->source->entity != &cfe->node[i].video_dev.entity) + continue; + + if (link->flags & MEDIA_LNK_FL_ENABLED) + set_state(cfe, NODE_ENABLED, i); + else + clear_state(cfe, NODE_ENABLED, i); + + break; + } + + spin_unlock_irqrestore(&cfe->state_lock, lock_flags); + + if (link->source->entity != csi2) + return 0; + if (link->sink->entity != fe) + return 0; + if (link->sink->index != 0) + return 0; + + cfe->fe_csi2_channel = -1; + if (link->flags & MEDIA_LNK_FL_ENABLED) { + if (link->source->index == node_desc[CSI2_CH0].link_pad) + cfe->fe_csi2_channel = CSI2_CH0; + else if (link->source->index == node_desc[CSI2_CH1].link_pad) + cfe->fe_csi2_channel = CSI2_CH1; + else if (link->source->index == node_desc[CSI2_CH2].link_pad) + cfe->fe_csi2_channel = CSI2_CH2; + else if (link->source->index == node_desc[CSI2_CH3].link_pad) + cfe->fe_csi2_channel = CSI2_CH3; + } + + if (is_fe_enabled(cfe)) + cfe_dbg(cfe, "%s: Found CSI2:%d -> FE:0 link\n", __func__, + cfe->fe_csi2_channel); + else + cfe_dbg(cfe, "%s: Unable to find CSI2:x -> FE:0 link\n", + __func__); + + return 0; +} + +static const struct media_device_ops cfe_media_device_ops = { + .link_notify = cfe_video_link_notify, +}; + +static void cfe_release(struct kref *kref) +{ + struct cfe_device *cfe = container_of(kref, struct cfe_device, kref); + + media_device_cleanup(&cfe->mdev); + + kfree(cfe); +} + +static void cfe_put(struct cfe_device *cfe) +{ + kref_put(&cfe->kref, cfe_release); +} + +static void cfe_get(struct cfe_device *cfe) +{ + kref_get(&cfe->kref); +} + +static void cfe_node_release(struct video_device *vdev) +{ + struct cfe_node *node = video_get_drvdata(vdev); + + cfe_put(node->cfe); +} + +static int cfe_register_node(struct cfe_device *cfe, int id) +{ + struct video_device *vdev; + const struct cfe_fmt *fmt; + struct vb2_queue *q; + struct cfe_node *node = &cfe->node[id]; + int ret; + + node->cfe = cfe; + node->id = id; + + if (node_supports_image(node)) { + if (node_supports_image_output(node)) + node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else + node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + fmt = find_format_by_code(cfe_default_format.code); + if (!fmt) { + cfe_err(cfe, "Failed to find format code\n"); + return -EINVAL; + } + + node->vid_fmt.fmt.pix.pixelformat = fmt->fourcc; + v4l2_fill_pix_format(&node->vid_fmt.fmt.pix, + &cfe_default_format); + + ret = cfe_validate_fmt_vid_cap(node, &node->vid_fmt); + if (ret) + return ret; + } + + if (node_supports_meta(node)) { + if (node_supports_meta_output(node)) + node->meta_fmt.type = V4L2_BUF_TYPE_META_CAPTURE; + else + node->meta_fmt.type = V4L2_BUF_TYPE_META_OUTPUT; + + ret = cfe_validate_fmt_meta(node, &node->meta_fmt); + if (ret) + return ret; + } + + mutex_init(&node->lock); + + q = &node->buffer_queue; + q->type = node_supports_image(node) ? node->vid_fmt.type : + node->meta_fmt.type; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = node; + q->ops = &cfe_video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = id == FE_CONFIG ? sizeof(struct cfe_config_buffer) + : sizeof(struct cfe_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &node->lock; + q->min_queued_buffers = 1; + q->dev = &cfe->pdev->dev; + + ret = vb2_queue_init(q); + if (ret) { + cfe_err(cfe, "vb2_queue_init() failed\n"); + return ret; + } + + INIT_LIST_HEAD(&node->dma_queue); + + vdev = &node->video_dev; + vdev->release = cfe_node_release; + vdev->fops = &cfe_fops; + vdev->ioctl_ops = &cfe_ioctl_ops; + vdev->entity.ops = &cfe_media_entity_ops; + vdev->v4l2_dev = &cfe->v4l2_dev; + vdev->vfl_dir = (node_supports_image_output(node) || + node_supports_meta_output(node)) ? + VFL_DIR_RX : + VFL_DIR_TX; + vdev->queue = q; + vdev->lock = &node->lock; + vdev->device_caps = node_desc[id].caps; + vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; + + /* Define the device names */ + snprintf(vdev->name, sizeof(vdev->name), "%s-%s", CFE_MODULE_NAME, + node_desc[id].name); + + video_set_drvdata(vdev, node); + node->pad.flags = node_desc[id].pad_flags; + media_entity_pads_init(&vdev->entity, 1, &node->pad); + + if (!node_supports_image(node)) { + v4l2_disable_ioctl(&node->video_dev, + VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES); + } + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + cfe_err(cfe, "Unable to register video device %s\n", + vdev->name); + return ret; + } + + cfe_info(cfe, "Registered [%s] node id %d as /dev/video%u\n", + vdev->name, id, vdev->num); + + /* + * Acquire a reference to cfe, which will be released when the video + * device will be unregistered and userspace will have closed all open + * file handles. + */ + cfe_get(cfe); + set_state(cfe, NODE_REGISTERED, id); + + return 0; +} + +static void cfe_unregister_nodes(struct cfe_device *cfe) +{ + for (unsigned int i = 0; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (check_state(cfe, NODE_REGISTERED, i)) { + clear_state(cfe, NODE_REGISTERED, i); + video_unregister_device(&node->video_dev); + } + } +} + +static int cfe_link_node_pads(struct cfe_device *cfe) +{ + struct media_pad *remote_pad; + int ret; + + /* Source -> CSI2 */ + + ret = v4l2_create_fwnode_links_to_pad(cfe->source_sd, + &cfe->csi2.pad[CSI2_PAD_SINK], + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + + if (ret) { + cfe_err(cfe, "Failed to create links to the source: %d\n", ret); + return ret; + } + + remote_pad = media_pad_remote_pad_unique(&cfe->csi2.pad[CSI2_PAD_SINK]); + if (IS_ERR(remote_pad)) { + ret = PTR_ERR(remote_pad); + cfe_err(cfe, "Failed to get unique remote source pad: %d\n", + ret); + return ret; + } + + cfe->source_pad = remote_pad->index; + + for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) { + struct cfe_node *node = &cfe->node[i]; + + if (!check_state(cfe, NODE_REGISTERED, i)) + continue; + + /* CSI2 channel # -> /dev/video# */ + ret = media_create_pad_link(&cfe->csi2.sd.entity, + node_desc[i].link_pad, + &node->video_dev.entity, 0, 0); + if (ret) + return ret; + + if (node_supports_image(node)) { + /* CSI2 channel # -> FE Input */ + ret = media_create_pad_link(&cfe->csi2.sd.entity, + node_desc[i].link_pad, + &cfe->fe.sd.entity, + FE_STREAM_PAD, 0); + if (ret) + return ret; + } + } + + for (unsigned int i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) { + struct cfe_node *node = &cfe->node[i]; + struct media_entity *src, *dst; + unsigned int src_pad, dst_pad; + + if (node_desc[i].pad_flags & MEDIA_PAD_FL_SINK) { + /* FE -> /dev/video# */ + src = &cfe->fe.sd.entity; + src_pad = node_desc[i].link_pad; + dst = &node->video_dev.entity; + dst_pad = 0; + } else { + /* /dev/video# -> FE */ + dst = &cfe->fe.sd.entity; + dst_pad = node_desc[i].link_pad; + src = &node->video_dev.entity; + src_pad = 0; + } + + ret = media_create_pad_link(src, src_pad, dst, dst_pad, 0); + if (ret) + return ret; + } + + return 0; +} + +static int cfe_probe_complete(struct cfe_device *cfe) +{ + int ret; + + cfe->v4l2_dev.notify = cfe_notify; + + for (unsigned int i = 0; i < NUM_NODES; i++) { + ret = cfe_register_node(cfe, i); + if (ret) { + cfe_err(cfe, "Unable to register video node %u.\n", i); + goto unregister; + } + } + + ret = cfe_link_node_pads(cfe); + if (ret) { + cfe_err(cfe, "Unable to link node pads.\n"); + goto unregister; + } + + ret = v4l2_device_register_subdev_nodes(&cfe->v4l2_dev); + if (ret) { + cfe_err(cfe, "Unable to register subdev nodes.\n"); + goto unregister; + } + + return 0; + +unregister: + cfe_unregister_nodes(cfe); + return ret; +} + +static int cfe_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asd) +{ + struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); + + if (cfe->source_sd) { + cfe_err(cfe, "Rejecting subdev %s (Already set!!)", + subdev->name); + return 0; + } + + cfe->source_sd = subdev; + + cfe_dbg(cfe, "Using source %s for capture\n", subdev->name); + + return 0; +} + +static int cfe_async_complete(struct v4l2_async_notifier *notifier) +{ + struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev); + + return cfe_probe_complete(cfe); +} + +static const struct v4l2_async_notifier_operations cfe_async_ops = { + .bound = cfe_async_bound, + .complete = cfe_async_complete, +}; + +static int cfe_register_async_nf(struct cfe_device *cfe) +{ + struct platform_device *pdev = cfe->pdev; + struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct fwnode_handle *local_ep_fwnode; + struct v4l2_async_connection *asd; + int ret; + + local_ep_fwnode = fwnode_graph_get_endpoint_by_id(pdev->dev.fwnode, 0, + 0, 0); + if (!local_ep_fwnode) { + cfe_err(cfe, "Failed to find local endpoint fwnode\n"); + return -ENODEV; + } + + /* Parse the local endpoint and validate its configuration. */ + ret = v4l2_fwnode_endpoint_parse(local_ep_fwnode, &ep); + if (ret) { + cfe_err(cfe, "Failed to find remote endpoint fwnode\n"); + goto err_put_local_fwnode; + } + + for (unsigned int lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes; + lane++) { + if (ep.bus.mipi_csi2.data_lanes[lane] != lane + 1) { + cfe_err(cfe, "Data lanes reordering not supported\n"); + ret = -EINVAL; + goto err_put_local_fwnode; + } + } + + cfe->csi2.dphy.max_lanes = ep.bus.mipi_csi2.num_data_lanes; + cfe->csi2.bus_flags = ep.bus.mipi_csi2.flags; + + /* Initialize and register the async notifier. */ + v4l2_async_nf_init(&cfe->notifier, &cfe->v4l2_dev); + cfe->notifier.ops = &cfe_async_ops; + + asd = v4l2_async_nf_add_fwnode_remote(&cfe->notifier, local_ep_fwnode, + struct v4l2_async_connection); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + cfe_err(cfe, "Error adding subdevice: %d\n", ret); + goto err_put_local_fwnode; + } + + ret = v4l2_async_nf_register(&cfe->notifier); + if (ret) { + cfe_err(cfe, "Error registering async notifier: %d\n", ret); + goto err_nf_cleanup; + } + + fwnode_handle_put(local_ep_fwnode); + + return 0; + +err_nf_cleanup: + v4l2_async_nf_cleanup(&cfe->notifier); +err_put_local_fwnode: + fwnode_handle_put(local_ep_fwnode); + + return ret; +} + +static int cfe_probe(struct platform_device *pdev) +{ + struct cfe_device *cfe; + char debugfs_name[32]; + int ret; + + cfe = kzalloc(sizeof(*cfe), GFP_KERNEL); + if (!cfe) + return -ENOMEM; + + platform_set_drvdata(pdev, cfe); + + kref_init(&cfe->kref); + cfe->pdev = pdev; + cfe->fe_csi2_channel = -1; + spin_lock_init(&cfe->state_lock); + + cfe->csi2.base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(cfe->csi2.base)) { + dev_err(&pdev->dev, "Failed to get dma io block\n"); + ret = PTR_ERR(cfe->csi2.base); + goto err_cfe_put; + } + + cfe->csi2.dphy.base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(cfe->csi2.dphy.base)) { + dev_err(&pdev->dev, "Failed to get host io block\n"); + ret = PTR_ERR(cfe->csi2.dphy.base); + goto err_cfe_put; + } + + cfe->mipi_cfg_base = devm_platform_ioremap_resource(pdev, 2); + if (IS_ERR(cfe->mipi_cfg_base)) { + dev_err(&pdev->dev, "Failed to get mipi cfg io block\n"); + ret = PTR_ERR(cfe->mipi_cfg_base); + goto err_cfe_put; + } + + cfe->fe.base = devm_platform_ioremap_resource(pdev, 3); + if (IS_ERR(cfe->fe.base)) { + dev_err(&pdev->dev, "Failed to get pisp fe io block\n"); + ret = PTR_ERR(cfe->fe.base); + goto err_cfe_put; + } + + ret = platform_get_irq(pdev, 0); + if (ret <= 0) { + ret = -EINVAL; + goto err_cfe_put; + } + + ret = devm_request_irq(&pdev->dev, ret, cfe_isr, 0, "rp1-cfe", cfe); + if (ret) { + dev_err(&pdev->dev, "Unable to request interrupt\n"); + ret = -EINVAL; + goto err_cfe_put; + } + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(&pdev->dev, "DMA enable failed\n"); + goto err_cfe_put; + } + + ret = vb2_dma_contig_set_max_seg_size(&pdev->dev, UINT_MAX); + if (ret) + goto err_cfe_put; + + /* TODO: Enable clock only when running. */ + cfe->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(cfe->clk)) { + ret = dev_err_probe(&pdev->dev, PTR_ERR(cfe->clk), + "clock not found\n"); + goto err_cfe_put; + } + + cfe->mdev.dev = &pdev->dev; + cfe->mdev.ops = &cfe_media_device_ops; + strscpy(cfe->mdev.model, CFE_MODULE_NAME, sizeof(cfe->mdev.model)); + strscpy(cfe->mdev.serial, "", sizeof(cfe->mdev.serial)); + snprintf(cfe->mdev.bus_info, sizeof(cfe->mdev.bus_info), "platform:%s", + dev_name(&pdev->dev)); + + media_device_init(&cfe->mdev); + + cfe->v4l2_dev.mdev = &cfe->mdev; + + ret = v4l2_device_register(&pdev->dev, &cfe->v4l2_dev); + if (ret) { + cfe_err(cfe, "Unable to register v4l2 device.\n"); + goto err_cfe_put; + } + + snprintf(debugfs_name, sizeof(debugfs_name), "rp1-cfe:%s", + dev_name(&pdev->dev)); + cfe->debugfs = debugfs_create_dir(debugfs_name, NULL); + debugfs_create_file("regs", 0440, cfe->debugfs, cfe, + &mipi_cfg_regs_fops); + + /* Enable the block power domain */ + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_resume_and_get(&cfe->pdev->dev); + if (ret) + goto err_runtime_disable; + + cfe->csi2.v4l2_dev = &cfe->v4l2_dev; + ret = csi2_init(&cfe->csi2, cfe->debugfs); + if (ret) { + cfe_err(cfe, "Failed to init csi2 (%d)\n", ret); + goto err_runtime_put; + } + + cfe->fe.v4l2_dev = &cfe->v4l2_dev; + ret = pisp_fe_init(&cfe->fe, cfe->debugfs); + if (ret) { + cfe_err(cfe, "Failed to init pisp fe (%d)\n", ret); + goto err_csi2_uninit; + } + + cfe->mdev.hw_revision = cfe->fe.hw_revision; + ret = media_device_register(&cfe->mdev); + if (ret < 0) { + cfe_err(cfe, "Unable to register media-controller device.\n"); + goto err_pisp_fe_uninit; + } + + ret = cfe_register_async_nf(cfe); + if (ret) { + cfe_err(cfe, "Failed to connect subdevs\n"); + goto err_media_unregister; + } + + pm_runtime_put(&cfe->pdev->dev); + + return 0; + +err_media_unregister: + media_device_unregister(&cfe->mdev); +err_pisp_fe_uninit: + pisp_fe_uninit(&cfe->fe); +err_csi2_uninit: + csi2_uninit(&cfe->csi2); +err_runtime_put: + pm_runtime_put(&cfe->pdev->dev); +err_runtime_disable: + pm_runtime_disable(&pdev->dev); + debugfs_remove(cfe->debugfs); + v4l2_device_unregister(&cfe->v4l2_dev); +err_cfe_put: + cfe_put(cfe); + + return ret; +} + +static void cfe_remove(struct platform_device *pdev) +{ + struct cfe_device *cfe = platform_get_drvdata(pdev); + + debugfs_remove(cfe->debugfs); + + v4l2_async_nf_unregister(&cfe->notifier); + v4l2_async_nf_cleanup(&cfe->notifier); + + media_device_unregister(&cfe->mdev); + cfe_unregister_nodes(cfe); + + pisp_fe_uninit(&cfe->fe); + csi2_uninit(&cfe->csi2); + + pm_runtime_disable(&pdev->dev); + + v4l2_device_unregister(&cfe->v4l2_dev); + + cfe_put(cfe); +} + +static int cfe_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cfe_device *cfe = platform_get_drvdata(pdev); + + clk_disable_unprepare(cfe->clk); + + return 0; +} + +static int cfe_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct cfe_device *cfe = platform_get_drvdata(pdev); + int ret; + + ret = clk_prepare_enable(cfe->clk); + if (ret) { + dev_err(dev, "Unable to enable clock\n"); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops cfe_pm_ops = { + SET_RUNTIME_PM_OPS(cfe_runtime_suspend, cfe_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static const struct of_device_id cfe_of_match[] = { + { .compatible = "raspberrypi,rp1-cfe" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, cfe_of_match); + +static struct platform_driver cfe_driver = { + .probe = cfe_probe, + .remove = cfe_remove, + .driver = { + .name = CFE_MODULE_NAME, + .of_match_table = cfe_of_match, + .pm = &cfe_pm_ops, + }, +}; + +module_platform_driver(cfe_driver); + +MODULE_AUTHOR("Naushir Patuck "); +MODULE_AUTHOR("Tomi Valkeinen "); +MODULE_DESCRIPTION("Raspberry Pi RP1 Camera Front End driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(CFE_VERSION); diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h new file mode 100644 index 00000000000000..c63cc314be3caa --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RP1 CFE Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ +#ifndef _RP1_CFE_ +#define _RP1_CFE_ + +#include +#include +#include + +extern bool cfe_debug_verbose; + +enum cfe_remap_types { + CFE_REMAP_16BIT, + CFE_REMAP_COMPRESSED, + CFE_NUM_REMAP, +}; + +#define CFE_FORMAT_FLAG_META_OUT BIT(0) +#define CFE_FORMAT_FLAG_META_CAP BIT(1) +#define CFE_FORMAT_FLAG_FE_OUT BIT(2) + +struct cfe_fmt { + u32 fourcc; + u32 code; + u8 depth; + u8 csi_dt; + u32 remap[CFE_NUM_REMAP]; + u32 flags; +}; + +extern const struct v4l2_mbus_framefmt cfe_default_format; + +const struct cfe_fmt *find_format_by_code(u32 code); +const struct cfe_fmt *find_format_by_pix(u32 pixelformat); +u32 cfe_find_16bit_code(u32 code); +u32 cfe_find_compressed_code(u32 code); + +#endif diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c new file mode 100644 index 00000000000000..35c2ab1e2cd4d5 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c @@ -0,0 +1,586 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RP1 CSI-2 Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#include +#include +#include +#include + +#include + +#include "cfe.h" +#include "csi2.h" + +#include "cfe-trace.h" + +static bool csi2_track_errors; +module_param_named(track_csi2_errors, csi2_track_errors, bool, 0); +MODULE_PARM_DESC(track_csi2_errors, "track csi-2 errors"); + +#define csi2_dbg(csi2, fmt, arg...) dev_dbg((csi2)->v4l2_dev->dev, fmt, ##arg) +#define csi2_err(csi2, fmt, arg...) dev_err((csi2)->v4l2_dev->dev, fmt, ##arg) + +/* CSI2-DMA registers */ +#define CSI2_STATUS 0x000 +#define CSI2_QOS 0x004 +#define CSI2_DISCARDS_OVERFLOW 0x008 +#define CSI2_DISCARDS_INACTIVE 0x00c +#define CSI2_DISCARDS_UNMATCHED 0x010 +#define CSI2_DISCARDS_LEN_LIMIT 0x014 + +#define CSI2_DISCARDS_AMOUNT_SHIFT 0 +#define CSI2_DISCARDS_AMOUNT_MASK GENMASK(23, 0) +#define CSI2_DISCARDS_DT_SHIFT 24 +#define CSI2_DISCARDS_DT_MASK GENMASK(29, 24) +#define CSI2_DISCARDS_VC_SHIFT 30 +#define CSI2_DISCARDS_VC_MASK GENMASK(31, 30) + +#define CSI2_LLEV_PANICS 0x018 +#define CSI2_ULEV_PANICS 0x01c +#define CSI2_IRQ_MASK 0x020 +#define CSI2_IRQ_MASK_IRQ_OVERFLOW BIT(0) +#define CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW BIT(1) +#define CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT BIT(2) +#define CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED BIT(3) +#define CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE BIT(4) +#define CSI2_IRQ_MASK_IRQ_ALL \ + (CSI2_IRQ_MASK_IRQ_OVERFLOW | CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW | \ + CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT | \ + CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED | \ + CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE) + +#define CSI2_CTRL 0x024 +#define CSI2_CH_CTRL(x) ((x) * 0x40 + 0x28) +#define CSI2_CH_ADDR0(x) ((x) * 0x40 + 0x2c) +#define CSI2_CH_ADDR1(x) ((x) * 0x40 + 0x3c) +#define CSI2_CH_STRIDE(x) ((x) * 0x40 + 0x30) +#define CSI2_CH_LENGTH(x) ((x) * 0x40 + 0x34) +#define CSI2_CH_DEBUG(x) ((x) * 0x40 + 0x38) +#define CSI2_CH_FRAME_SIZE(x) ((x) * 0x40 + 0x40) +#define CSI2_CH_COMP_CTRL(x) ((x) * 0x40 + 0x44) +#define CSI2_CH_FE_FRAME_ID(x) ((x) * 0x40 + 0x48) + +/* CSI2_STATUS */ +#define CSI2_STATUS_IRQ_FS(x) (BIT(0) << (x)) +#define CSI2_STATUS_IRQ_FE(x) (BIT(4) << (x)) +#define CSI2_STATUS_IRQ_FE_ACK(x) (BIT(8) << (x)) +#define CSI2_STATUS_IRQ_LE(x) (BIT(12) << (x)) +#define CSI2_STATUS_IRQ_LE_ACK(x) (BIT(16) << (x)) +#define CSI2_STATUS_IRQ_CH_MASK(x) \ + (CSI2_STATUS_IRQ_FS(x) | CSI2_STATUS_IRQ_FE(x) | \ + CSI2_STATUS_IRQ_FE_ACK(x) | CSI2_STATUS_IRQ_LE(x) | \ + CSI2_STATUS_IRQ_LE_ACK(x)) +#define CSI2_STATUS_IRQ_OVERFLOW BIT(20) +#define CSI2_STATUS_IRQ_DISCARD_OVERFLOW BIT(21) +#define CSI2_STATUS_IRQ_DISCARD_LEN_LIMIT BIT(22) +#define CSI2_STATUS_IRQ_DISCARD_UNMATCHED BIT(23) +#define CSI2_STATUS_IRQ_DISCARD_INACTIVE BIT(24) + +/* CSI2_CTRL */ +#define CSI2_CTRL_EOP_IS_EOL BIT(0) + +/* CSI2_CH_CTRL */ +#define CSI2_CH_CTRL_DMA_EN BIT(0) +#define CSI2_CH_CTRL_FORCE BIT(3) +#define CSI2_CH_CTRL_AUTO_ARM BIT(4) +#define CSI2_CH_CTRL_IRQ_EN_FS BIT(13) +#define CSI2_CH_CTRL_IRQ_EN_FE BIT(14) +#define CSI2_CH_CTRL_IRQ_EN_FE_ACK BIT(15) +#define CSI2_CH_CTRL_IRQ_EN_LE BIT(16) +#define CSI2_CH_CTRL_IRQ_EN_LE_ACK BIT(17) +#define CSI2_CH_CTRL_FLUSH_FE BIT(28) +#define CSI2_CH_CTRL_PACK_LINE BIT(29) +#define CSI2_CH_CTRL_PACK_BYTES BIT(30) +#define CSI2_CH_CTRL_CH_MODE_MASK GENMASK(2, 1) +#define CSI2_CH_CTRL_VC_MASK GENMASK(6, 5) +#define CSI2_CH_CTRL_DT_MASK GENMASK(12, 7) +#define CSI2_CH_CTRL_LC_MASK GENMASK(27, 18) + +/* CHx_COMPRESSION_CONTROL */ +#define CSI2_CH_COMP_CTRL_OFFSET_MASK GENMASK(15, 0) +#define CSI2_CH_COMP_CTRL_SHIFT_MASK GENMASK(19, 16) +#define CSI2_CH_COMP_CTRL_MODE_MASK GENMASK(25, 24) + +static inline u32 csi2_reg_read(struct csi2_device *csi2, u32 offset) +{ + return readl(csi2->base + offset); +} + +static inline void csi2_reg_write(struct csi2_device *csi2, u32 offset, u32 val) +{ + writel(val, csi2->base + offset); +} + +static inline void set_field(u32 *valp, u32 field, u32 mask) +{ + u32 val = *valp; + + val &= ~mask; + val |= (field << __ffs(mask)) & mask; + *valp = val; +} + +static int csi2_regs_show(struct seq_file *s, void *data) +{ + struct csi2_device *csi2 = s->private; + int ret; + + ret = pm_runtime_resume_and_get(csi2->v4l2_dev->dev); + if (ret) + return ret; + +#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", csi2_reg_read(csi2, reg)) +#define DUMP_CH(idx, reg) seq_printf(s, #reg "(%u) \t0x%08x\n", idx, \ + csi2_reg_read(csi2, reg(idx))) + + DUMP(CSI2_STATUS); + DUMP(CSI2_DISCARDS_OVERFLOW); + DUMP(CSI2_DISCARDS_INACTIVE); + DUMP(CSI2_DISCARDS_UNMATCHED); + DUMP(CSI2_DISCARDS_LEN_LIMIT); + DUMP(CSI2_LLEV_PANICS); + DUMP(CSI2_ULEV_PANICS); + DUMP(CSI2_IRQ_MASK); + DUMP(CSI2_CTRL); + + for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; ++i) { + DUMP_CH(i, CSI2_CH_CTRL); + DUMP_CH(i, CSI2_CH_ADDR0); + DUMP_CH(i, CSI2_CH_ADDR1); + DUMP_CH(i, CSI2_CH_STRIDE); + DUMP_CH(i, CSI2_CH_LENGTH); + DUMP_CH(i, CSI2_CH_DEBUG); + DUMP_CH(i, CSI2_CH_FRAME_SIZE); + DUMP_CH(i, CSI2_CH_COMP_CTRL); + DUMP_CH(i, CSI2_CH_FE_FRAME_ID); + } + +#undef DUMP +#undef DUMP_CH + + pm_runtime_put(csi2->v4l2_dev->dev); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(csi2_regs); + +static int csi2_errors_show(struct seq_file *s, void *data) +{ + struct csi2_device *csi2 = s->private; + unsigned long flags; + u32 discards_table[DISCARDS_TABLE_NUM_VCS][DISCARDS_TABLE_NUM_ENTRIES]; + u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES]; + u32 overflows; + + spin_lock_irqsave(&csi2->errors_lock, flags); + + memcpy(discards_table, csi2->discards_table, sizeof(discards_table)); + memcpy(discards_dt_table, csi2->discards_dt_table, + sizeof(discards_dt_table)); + overflows = csi2->overflows; + + csi2->overflows = 0; + memset(csi2->discards_table, 0, sizeof(discards_table)); + memset(csi2->discards_dt_table, 0, sizeof(discards_dt_table)); + + spin_unlock_irqrestore(&csi2->errors_lock, flags); + + seq_printf(s, "Overflows %u\n", overflows); + seq_puts(s, "Discards:\n"); + seq_puts(s, "VC OVLF LEN UNMATCHED INACTIVE\n"); + + for (unsigned int vc = 0; vc < DISCARDS_TABLE_NUM_VCS; ++vc) { + seq_printf(s, "%u %10u %10u %10u %10u\n", vc, + discards_table[vc][DISCARDS_TABLE_OVERFLOW], + discards_table[vc][DISCARDS_TABLE_LENGTH_LIMIT], + discards_table[vc][DISCARDS_TABLE_UNMATCHED], + discards_table[vc][DISCARDS_TABLE_INACTIVE]); + } + + seq_printf(s, "Last DT %10u %10u %10u %10u\n", + discards_dt_table[DISCARDS_TABLE_OVERFLOW], + discards_dt_table[DISCARDS_TABLE_LENGTH_LIMIT], + discards_dt_table[DISCARDS_TABLE_UNMATCHED], + discards_dt_table[DISCARDS_TABLE_INACTIVE]); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(csi2_errors); + +static void csi2_isr_handle_errors(struct csi2_device *csi2, u32 status) +{ + spin_lock(&csi2->errors_lock); + + if (status & CSI2_STATUS_IRQ_OVERFLOW) + csi2->overflows++; + + for (unsigned int i = 0; i < DISCARDS_TABLE_NUM_ENTRIES; ++i) { + static const u32 discard_bits[] = { + CSI2_STATUS_IRQ_DISCARD_OVERFLOW, + CSI2_STATUS_IRQ_DISCARD_LEN_LIMIT, + CSI2_STATUS_IRQ_DISCARD_UNMATCHED, + CSI2_STATUS_IRQ_DISCARD_INACTIVE, + }; + static const u8 discard_regs[] = { + CSI2_DISCARDS_OVERFLOW, + CSI2_DISCARDS_LEN_LIMIT, + CSI2_DISCARDS_UNMATCHED, + CSI2_DISCARDS_INACTIVE, + }; + u32 amount; + u8 dt, vc; + u32 v; + + if (!(status & discard_bits[i])) + continue; + + v = csi2_reg_read(csi2, discard_regs[i]); + csi2_reg_write(csi2, discard_regs[i], 0); + + amount = (v & CSI2_DISCARDS_AMOUNT_MASK) >> + CSI2_DISCARDS_AMOUNT_SHIFT; + dt = (v & CSI2_DISCARDS_DT_MASK) >> CSI2_DISCARDS_DT_SHIFT; + vc = (v & CSI2_DISCARDS_VC_MASK) >> CSI2_DISCARDS_VC_SHIFT; + + csi2->discards_table[vc][i] += amount; + csi2->discards_dt_table[i] = dt; + } + + spin_unlock(&csi2->errors_lock); +} + +void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof) +{ + u32 status; + + status = csi2_reg_read(csi2, CSI2_STATUS); + + /* Write value back to clear the interrupts */ + csi2_reg_write(csi2, CSI2_STATUS, status); + + for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) { + u32 dbg; + + if ((status & CSI2_STATUS_IRQ_CH_MASK(i)) == 0) + continue; + + dbg = csi2_reg_read(csi2, CSI2_CH_DEBUG(i)); + + trace_csi2_irq(i, status, dbg); + + sof[i] = !!(status & CSI2_STATUS_IRQ_FS(i)); + eof[i] = !!(status & CSI2_STATUS_IRQ_FE_ACK(i)); + } + + if (csi2_track_errors) + csi2_isr_handle_errors(csi2, status); +} + +void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, + dma_addr_t dmaaddr, unsigned int stride, unsigned int size) +{ + u64 addr = dmaaddr; + /* + * ADDRESS0 must be written last as it triggers the double buffering + * mechanism for all buffer registers within the hardware. + */ + addr >>= 4; + csi2_reg_write(csi2, CSI2_CH_LENGTH(channel), size >> 4); + csi2_reg_write(csi2, CSI2_CH_STRIDE(channel), stride >> 4); + csi2_reg_write(csi2, CSI2_CH_ADDR1(channel), addr >> 32); + csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), addr & 0xffffffff); +} + +void csi2_set_compression(struct csi2_device *csi2, unsigned int channel, + enum csi2_compression_mode mode, unsigned int shift, + unsigned int offset) +{ + u32 compression = 0; + + set_field(&compression, CSI2_CH_COMP_CTRL_OFFSET_MASK, offset); + set_field(&compression, CSI2_CH_COMP_CTRL_SHIFT_MASK, shift); + set_field(&compression, CSI2_CH_COMP_CTRL_MODE_MASK, mode); + csi2_reg_write(csi2, CSI2_CH_COMP_CTRL(channel), compression); +} + +void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, + enum csi2_mode mode, bool auto_arm, bool pack_bytes, + unsigned int width, unsigned int height, + u8 vc, u8 dt) +{ + u32 ctrl; + + csi2_dbg(csi2, "%s [%u]\n", __func__, channel); + + csi2_reg_write(csi2, CSI2_CH_CTRL(channel), 0); + csi2_reg_write(csi2, CSI2_CH_DEBUG(channel), 0); + csi2_reg_write(csi2, CSI2_STATUS, CSI2_STATUS_IRQ_CH_MASK(channel)); + + /* Enable channel and FS/FE interrupts. */ + ctrl = CSI2_CH_CTRL_DMA_EN | CSI2_CH_CTRL_IRQ_EN_FS | + CSI2_CH_CTRL_IRQ_EN_FE_ACK | CSI2_CH_CTRL_PACK_LINE; + /* PACK_BYTES ensures no striding for embedded data. */ + if (pack_bytes) + ctrl |= CSI2_CH_CTRL_PACK_BYTES; + + if (auto_arm) + ctrl |= CSI2_CH_CTRL_AUTO_ARM; + + if (width && height) { + set_field(&ctrl, mode, CSI2_CH_CTRL_CH_MODE_MASK); + csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), + (height << 16) | width); + } else { + set_field(&ctrl, 0x0, CSI2_CH_CTRL_CH_MODE_MASK); + csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), 0); + } + + set_field(&ctrl, vc, CSI2_CH_CTRL_VC_MASK); + set_field(&ctrl, dt, CSI2_CH_CTRL_DT_MASK); + csi2_reg_write(csi2, CSI2_CH_CTRL(channel), ctrl); + csi2->num_lines[channel] = height; +} + +void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel) +{ + csi2_dbg(csi2, "%s [%u]\n", __func__, channel); + + /* Channel disable. Use FORCE to allow stopping mid-frame. */ + csi2_reg_write(csi2, CSI2_CH_CTRL(channel), CSI2_CH_CTRL_FORCE); + /* Latch the above change by writing to the ADDR0 register. */ + csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); + /* Write this again, the HW needs it! */ + csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0); +} + +void csi2_open_rx(struct csi2_device *csi2) +{ + csi2_reg_write(csi2, CSI2_IRQ_MASK, + csi2_track_errors ? CSI2_IRQ_MASK_IRQ_ALL : 0); + + dphy_start(&csi2->dphy); + + csi2_reg_write(csi2, CSI2_CTRL, CSI2_CTRL_EOP_IS_EOL); +} + +void csi2_close_rx(struct csi2_device *csi2) +{ + dphy_stop(&csi2->dphy); + + csi2_reg_write(csi2, CSI2_IRQ_MASK, 0); +} + +static int csi2_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { { + .sink_pad = CSI2_PAD_SINK, + .sink_stream = 0, + .source_pad = CSI2_PAD_FIRST_SOURCE, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + } }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + int ret; + + ret = v4l2_subdev_set_routing_with_fmt(sd, state, &routing, + &cfe_default_format); + if (ret) + return ret; + + return 0; +} + +static int csi2_pad_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + if (format->pad == CSI2_PAD_SINK) { + /* Store the sink format and propagate it to the source. */ + + const struct cfe_fmt *cfe_fmt; + + cfe_fmt = find_format_by_code(format->format.code); + if (!cfe_fmt) { + cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB10_1X10); + format->format.code = cfe_fmt->code; + } + + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_state_get_format(state, format->pad, + format->stream); + if (!fmt) + return -EINVAL; + + *fmt = format->format; + + fmt = v4l2_subdev_state_get_opposite_stream_format(state, + format->pad, + format->stream); + if (!fmt) + return -EINVAL; + + format->format.field = V4L2_FIELD_NONE; + + *fmt = format->format; + } else { + /* Only allow changing the source pad mbus code. */ + + struct v4l2_mbus_framefmt *sink_fmt, *source_fmt; + u32 sink_code; + u32 code; + + sink_fmt = v4l2_subdev_state_get_opposite_stream_format(state, + format->pad, + format->stream); + if (!sink_fmt) + return -EINVAL; + + source_fmt = v4l2_subdev_state_get_format(state, format->pad, + format->stream); + if (!source_fmt) + return -EINVAL; + + sink_code = sink_fmt->code; + code = format->format.code; + + /* + * Only allow changing the mbus code to: + * - The sink's mbus code + * - The 16-bit version of the sink's mbus code + * - The compressed version of the sink's mbus code + */ + if (code == sink_code || + code == cfe_find_16bit_code(sink_code) || + code == cfe_find_compressed_code(sink_code)) + source_fmt->code = code; + + format->format.code = source_fmt->code; + } + + return 0; +} + +static int csi2_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + ret = v4l2_subdev_routing_validate(sd, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | + V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING); + if (ret) + return ret; + + /* Only stream ID 0 allowed on source pads */ + for (unsigned int i = 0; i < routing->num_routes; ++i) { + const struct v4l2_subdev_route *route = &routing->routes[i]; + + if (route->source_stream != 0) + return -EINVAL; + } + + ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, + &cfe_default_format); + if (ret) + return ret; + + return 0; +} + +static const struct v4l2_subdev_pad_ops csi2_subdev_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = csi2_pad_set_fmt, + .set_routing = csi2_set_routing, + .link_validate = v4l2_subdev_link_validate_default, +}; + +static const struct media_entity_operations csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, + .has_pad_interdep = v4l2_subdev_has_pad_interdep, +}; + +static const struct v4l2_subdev_ops csi2_subdev_ops = { + .pad = &csi2_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops csi2_internal_ops = { + .init_state = csi2_init_state, +}; + +int csi2_init(struct csi2_device *csi2, struct dentry *debugfs) +{ + unsigned int ret; + + spin_lock_init(&csi2->errors_lock); + + csi2->dphy.dev = csi2->v4l2_dev->dev; + dphy_probe(&csi2->dphy); + + debugfs_create_file("csi2_regs", 0440, debugfs, csi2, &csi2_regs_fops); + + if (csi2_track_errors) + debugfs_create_file("csi2_errors", 0440, debugfs, csi2, + &csi2_errors_fops); + + csi2->pad[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + + for (unsigned int i = CSI2_PAD_FIRST_SOURCE; + i < CSI2_PAD_FIRST_SOURCE + CSI2_PAD_NUM_SOURCES; i++) + csi2->pad[i].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&csi2->sd.entity, ARRAY_SIZE(csi2->pad), + csi2->pad); + if (ret) + return ret; + + /* Initialize subdev */ + v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops); + csi2->sd.internal_ops = &csi2_internal_ops; + csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + csi2->sd.entity.ops = &csi2_entity_ops; + csi2->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; + csi2->sd.owner = THIS_MODULE; + snprintf(csi2->sd.name, sizeof(csi2->sd.name), "csi2"); + + ret = v4l2_subdev_init_finalize(&csi2->sd); + if (ret) + goto err_entity_cleanup; + + ret = v4l2_device_register_subdev(csi2->v4l2_dev, &csi2->sd); + if (ret) { + csi2_err(csi2, "Failed register csi2 subdev (%d)\n", ret); + goto err_subdev_cleanup; + } + + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&csi2->sd); +err_entity_cleanup: + media_entity_cleanup(&csi2->sd.entity); + + return ret; +} + +void csi2_uninit(struct csi2_device *csi2) +{ + v4l2_device_unregister_subdev(&csi2->sd); + v4l2_subdev_cleanup(&csi2->sd); + media_entity_cleanup(&csi2->sd.entity); +} diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h new file mode 100644 index 00000000000000..a8ee5de565fbd6 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RP1 CSI-2 Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#ifndef _RP1_CSI2_ +#define _RP1_CSI2_ + +#include +#include +#include +#include +#include + +#include "dphy.h" + +#define CSI2_NUM_CHANNELS 4 + +#define CSI2_PAD_SINK 0 +#define CSI2_PAD_FIRST_SOURCE 1 +#define CSI2_PAD_NUM_SOURCES 4 +#define CSI2_NUM_PADS 5 + +#define DISCARDS_TABLE_NUM_VCS 4 + +enum csi2_mode { + CSI2_MODE_NORMAL = 0, + CSI2_MODE_REMAP = 1, + CSI2_MODE_COMPRESSED = 2, + CSI2_MODE_FE_STREAMING = 3, +}; + +enum csi2_compression_mode { + CSI2_COMPRESSION_DELTA = 1, + CSI2_COMPRESSION_SIMPLE = 2, + CSI2_COMPRESSION_COMBINED = 3, +}; + +enum discards_table_index { + DISCARDS_TABLE_OVERFLOW = 0, + DISCARDS_TABLE_LENGTH_LIMIT, + DISCARDS_TABLE_UNMATCHED, + DISCARDS_TABLE_INACTIVE, + DISCARDS_TABLE_NUM_ENTRIES, +}; + +struct csi2_device { + /* Parent V4l2 device */ + struct v4l2_device *v4l2_dev; + + void __iomem *base; + + struct dphy_data dphy; + + enum v4l2_mbus_type bus_type; + unsigned int bus_flags; + unsigned int num_lines[CSI2_NUM_CHANNELS]; + + struct media_pad pad[CSI2_NUM_PADS]; + struct v4l2_subdev sd; + + /* lock for csi2 errors counters */ + spinlock_t errors_lock; + u32 overflows; + u32 discards_table[DISCARDS_TABLE_NUM_VCS][DISCARDS_TABLE_NUM_ENTRIES]; + u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES]; +}; + +void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof); +void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel, + dma_addr_t dmaaddr, unsigned int stride, + unsigned int size); +void csi2_set_compression(struct csi2_device *csi2, unsigned int channel, + enum csi2_compression_mode mode, unsigned int shift, + unsigned int offset); +void csi2_start_channel(struct csi2_device *csi2, unsigned int channel, + enum csi2_mode mode, bool auto_arm, + bool pack_bytes, unsigned int width, + unsigned int height, u8 vc, u8 dt); +void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel); +void csi2_open_rx(struct csi2_device *csi2); +void csi2_close_rx(struct csi2_device *csi2); +int csi2_init(struct csi2_device *csi2, struct dentry *debugfs); +void csi2_uninit(struct csi2_device *csi2); + +#endif diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c new file mode 100644 index 00000000000000..b443f0f56ddc82 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RP1 CSI-2 Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#include +#include + +#include "dphy.h" + +#define dphy_dbg(dphy, fmt, arg...) dev_dbg((dphy)->dev, fmt, ##arg) +#define dphy_err(dphy, fmt, arg...) dev_err((dphy)->dev, fmt, ##arg) + +/* DW dphy Host registers */ +#define DPHY_VERSION 0x000 +#define DPHY_N_LANES 0x004 +#define DPHY_RESETN 0x008 +#define DPHY_PHY_SHUTDOWNZ 0x040 +#define DPHY_PHY_RSTZ 0x044 +#define DPHY_PHY_RX 0x048 +#define DPHY_PHY_STOPSTATE 0x04c +#define DPHY_PHY_TST_CTRL0 0x050 +#define DPHY_PHY_TST_CTRL1 0x054 +#define DPHY_PHY2_TST_CTRL0 0x058 +#define DPHY_PHY2_TST_CTRL1 0x05c + +/* DW dphy Host Transactions */ +#define DPHY_HS_RX_CTRL_LANE0_OFFSET 0x44 +#define DPHY_PLL_INPUT_DIV_OFFSET 0x17 +#define DPHY_PLL_LOOP_DIV_OFFSET 0x18 +#define DPHY_PLL_DIV_CTRL_OFFSET 0x19 + +static u32 dw_csi2_host_read(struct dphy_data *dphy, u32 offset) +{ + return readl(dphy->base + offset); +} + +static void dw_csi2_host_write(struct dphy_data *dphy, u32 offset, u32 data) +{ + writel(data, dphy->base + offset); +} + +static void set_tstclr(struct dphy_data *dphy, u32 val) +{ + u32 ctrl0 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL0); + + dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL0, (ctrl0 & ~1) | val); +} + +static void set_tstclk(struct dphy_data *dphy, u32 val) +{ + u32 ctrl0 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL0); + + dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL0, (ctrl0 & ~2) | (val << 1)); +} + +static uint8_t get_tstdout(struct dphy_data *dphy) +{ + u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1); + + return ((ctrl1 >> 8) & 0xff); +} + +static void set_testen(struct dphy_data *dphy, u32 val) +{ + u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1); + + dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL1, + (ctrl1 & ~(1 << 16)) | (val << 16)); +} + +static void set_testdin(struct dphy_data *dphy, u32 val) +{ + u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1); + + dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL1, (ctrl1 & ~0xff) | val); +} + +static uint8_t dphy_transaction(struct dphy_data *dphy, u8 test_code, + uint8_t test_data) +{ + /* See page 101 of the MIPI DPHY databook. */ + set_tstclk(dphy, 1); + set_testen(dphy, 0); + set_testdin(dphy, test_code); + set_testen(dphy, 1); + set_tstclk(dphy, 0); + set_testen(dphy, 0); + set_testdin(dphy, test_data); + set_tstclk(dphy, 1); + return get_tstdout(dphy); +} + +static void dphy_set_hsfreqrange(struct dphy_data *dphy, uint32_t mbps) +{ + /* See Table 5-1 on page 65 of dphy databook */ + static const u16 hsfreqrange_table[][2] = { + { 89, 0b000000 }, { 99, 0b010000 }, { 109, 0b100000 }, + { 129, 0b000001 }, { 139, 0b010001 }, { 149, 0b100001 }, + { 169, 0b000010 }, { 179, 0b010010 }, { 199, 0b100010 }, + { 219, 0b000011 }, { 239, 0b010011 }, { 249, 0b100011 }, + { 269, 0b000100 }, { 299, 0b010100 }, { 329, 0b000101 }, + { 359, 0b010101 }, { 399, 0b100101 }, { 449, 0b000110 }, + { 499, 0b010110 }, { 549, 0b000111 }, { 599, 0b010111 }, + { 649, 0b001000 }, { 699, 0b011000 }, { 749, 0b001001 }, + { 799, 0b011001 }, { 849, 0b101001 }, { 899, 0b111001 }, + { 949, 0b001010 }, { 999, 0b011010 }, { 1049, 0b101010 }, + { 1099, 0b111010 }, { 1149, 0b001011 }, { 1199, 0b011011 }, + { 1249, 0b101011 }, { 1299, 0b111011 }, { 1349, 0b001100 }, + { 1399, 0b011100 }, { 1449, 0b101100 }, { 1500, 0b111100 }, + }; + unsigned int i; + + if (mbps < 80 || mbps > 1500) + dphy_err(dphy, "DPHY: Datarate %u Mbps out of range\n", mbps); + + for (i = 0; i < ARRAY_SIZE(hsfreqrange_table) - 1; i++) { + if (mbps <= hsfreqrange_table[i][0]) + break; + } + + dphy_transaction(dphy, DPHY_HS_RX_CTRL_LANE0_OFFSET, + hsfreqrange_table[i][1] << 1); +} + +static void dphy_init(struct dphy_data *dphy) +{ + dw_csi2_host_write(dphy, DPHY_PHY_RSTZ, 0); + dw_csi2_host_write(dphy, DPHY_PHY_SHUTDOWNZ, 0); + set_tstclk(dphy, 1); + set_testen(dphy, 0); + set_tstclr(dphy, 1); + usleep_range(15, 20); + set_tstclr(dphy, 0); + usleep_range(15, 20); + + dphy_set_hsfreqrange(dphy, dphy->dphy_rate); + + usleep_range(5, 10); + dw_csi2_host_write(dphy, DPHY_PHY_SHUTDOWNZ, 1); + usleep_range(5, 10); + dw_csi2_host_write(dphy, DPHY_PHY_RSTZ, 1); +} + +void dphy_start(struct dphy_data *dphy) +{ + dphy_dbg(dphy, "%s: Link rate %u Mbps, %u data lanes\n", __func__, + dphy->dphy_rate, dphy->active_lanes); + + dw_csi2_host_write(dphy, DPHY_N_LANES, (dphy->active_lanes - 1)); + dphy_init(dphy); + dw_csi2_host_write(dphy, DPHY_RESETN, 0xffffffff); + usleep_range(10, 50); +} + +void dphy_stop(struct dphy_data *dphy) +{ + dphy_dbg(dphy, "%s\n", __func__); + + /* Set only one lane (lane 0) as active (ON) */ + dw_csi2_host_write(dphy, DPHY_N_LANES, 0); + dw_csi2_host_write(dphy, DPHY_RESETN, 0); +} + +void dphy_probe(struct dphy_data *dphy) +{ + u32 host_ver; + u8 host_ver_major, host_ver_minor; + + host_ver = dw_csi2_host_read(dphy, DPHY_VERSION); + host_ver_major = (u8)((host_ver >> 24) - '0'); + host_ver_minor = (u8)((host_ver >> 16) - '0'); + host_ver_minor = host_ver_minor * 10; + host_ver_minor += (u8)((host_ver >> 8) - '0'); + + dphy_dbg(dphy, "DW dphy Host HW v%u.%u\n", host_ver_major, + host_ver_minor); +} diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h new file mode 100644 index 00000000000000..84fa370957cc3c --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + * Copyright (c) 2023-2024 Ideas on Board Oy + */ + +#ifndef _RP1_DPHY_ +#define _RP1_DPHY_ + +#include +#include + +struct dphy_data { + struct device *dev; + + void __iomem *base; + + u32 dphy_rate; + u32 max_lanes; + u32 active_lanes; +}; + +void dphy_probe(struct dphy_data *dphy); +void dphy_start(struct dphy_data *dphy); +void dphy_stop(struct dphy_data *dphy); + +#endif diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c new file mode 100644 index 00000000000000..05762b1be2bc75 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PiSP Front End Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + */ + +#include +#include +#include +#include +#include + +#include + +#include "cfe.h" +#include "pisp-fe.h" + +#include "cfe-trace.h" + +#define FE_VERSION 0x000 +#define FE_CONTROL 0x004 +#define FE_STATUS 0x008 +#define FE_FRAME_STATUS 0x00c +#define FE_ERROR_STATUS 0x010 +#define FE_OUTPUT_STATUS 0x014 +#define FE_INT_EN 0x018 +#define FE_INT_STATUS 0x01c + +/* CONTROL */ +#define FE_CONTROL_QUEUE BIT(0) +#define FE_CONTROL_ABORT BIT(1) +#define FE_CONTROL_RESET BIT(2) +#define FE_CONTROL_LATCH_REGS BIT(3) + +/* INT_EN / INT_STATUS */ +#define FE_INT_EOF BIT(0) +#define FE_INT_SOF BIT(1) +#define FE_INT_LINES0 BIT(8) +#define FE_INT_LINES1 BIT(9) +#define FE_INT_STATS BIT(16) +#define FE_INT_QREADY BIT(24) + +/* STATUS */ +#define FE_STATUS_QUEUED BIT(0) +#define FE_STATUS_WAITING BIT(1) +#define FE_STATUS_ACTIVE BIT(2) + +#define PISP_FE_CONFIG_BASE_OFFSET 0x0040 + +#define PISP_FE_ENABLE_STATS_CLUSTER \ + (PISP_FE_ENABLE_STATS_CROP | PISP_FE_ENABLE_DECIMATE | \ + PISP_FE_ENABLE_BLC | PISP_FE_ENABLE_CDAF_STATS | \ + PISP_FE_ENABLE_AWB_STATS | PISP_FE_ENABLE_RGBY | \ + PISP_FE_ENABLE_LSC | PISP_FE_ENABLE_AGC_STATS) + +#define PISP_FE_ENABLE_OUTPUT_CLUSTER(i) \ + ((PISP_FE_ENABLE_CROP0 | PISP_FE_ENABLE_DOWNSCALE0 | \ + PISP_FE_ENABLE_COMPRESS0 | PISP_FE_ENABLE_OUTPUT0) << (4 * (i))) + +struct pisp_fe_config_param { + u32 dirty_flags; + u32 dirty_flags_extra; + size_t offset; + size_t size; +}; + +static const struct pisp_fe_config_param pisp_fe_config_map[] = { + /* *_dirty_flag_extra types */ + { 0, PISP_FE_DIRTY_GLOBAL, + offsetof(struct pisp_fe_config, global), + sizeof(struct pisp_fe_global_config) }, + { 0, PISP_FE_DIRTY_FLOATING, + offsetof(struct pisp_fe_config, floating_stats), + sizeof(struct pisp_fe_floating_stats_config) }, + { 0, PISP_FE_DIRTY_OUTPUT_AXI, + offsetof(struct pisp_fe_config, output_axi), + sizeof(struct pisp_fe_output_axi_config) }, + /* *_dirty_flag types */ + { PISP_FE_ENABLE_INPUT, 0, + offsetof(struct pisp_fe_config, input), + sizeof(struct pisp_fe_input_config) }, + { PISP_FE_ENABLE_DECOMPRESS, 0, + offsetof(struct pisp_fe_config, decompress), + sizeof(struct pisp_decompress_config) }, + { PISP_FE_ENABLE_DECOMPAND, 0, + offsetof(struct pisp_fe_config, decompand), + sizeof(struct pisp_fe_decompand_config) }, + { PISP_FE_ENABLE_BLA, 0, + offsetof(struct pisp_fe_config, bla), + sizeof(struct pisp_bla_config) }, + { PISP_FE_ENABLE_DPC, 0, + offsetof(struct pisp_fe_config, dpc), + sizeof(struct pisp_fe_dpc_config) }, + { PISP_FE_ENABLE_STATS_CROP, 0, + offsetof(struct pisp_fe_config, stats_crop), + sizeof(struct pisp_fe_crop_config) }, + { PISP_FE_ENABLE_BLC, 0, + offsetof(struct pisp_fe_config, blc), + sizeof(struct pisp_bla_config) }, + { PISP_FE_ENABLE_CDAF_STATS, 0, + offsetof(struct pisp_fe_config, cdaf_stats), + sizeof(struct pisp_fe_cdaf_stats_config) }, + { PISP_FE_ENABLE_AWB_STATS, 0, + offsetof(struct pisp_fe_config, awb_stats), + sizeof(struct pisp_fe_awb_stats_config) }, + { PISP_FE_ENABLE_RGBY, 0, + offsetof(struct pisp_fe_config, rgby), + sizeof(struct pisp_fe_rgby_config) }, + { PISP_FE_ENABLE_LSC, 0, + offsetof(struct pisp_fe_config, lsc), + sizeof(struct pisp_fe_lsc_config) }, + { PISP_FE_ENABLE_AGC_STATS, 0, + offsetof(struct pisp_fe_config, agc_stats), + sizeof(struct pisp_agc_statistics) }, + { PISP_FE_ENABLE_CROP0, 0, + offsetof(struct pisp_fe_config, ch[0].crop), + sizeof(struct pisp_fe_crop_config) }, + { PISP_FE_ENABLE_DOWNSCALE0, 0, + offsetof(struct pisp_fe_config, ch[0].downscale), + sizeof(struct pisp_fe_downscale_config) }, + { PISP_FE_ENABLE_COMPRESS0, 0, + offsetof(struct pisp_fe_config, ch[0].compress), + sizeof(struct pisp_compress_config) }, + { PISP_FE_ENABLE_OUTPUT0, 0, + offsetof(struct pisp_fe_config, ch[0].output), + sizeof(struct pisp_fe_output_config) }, + { PISP_FE_ENABLE_CROP1, 0, + offsetof(struct pisp_fe_config, ch[1].crop), + sizeof(struct pisp_fe_crop_config) }, + { PISP_FE_ENABLE_DOWNSCALE1, 0, + offsetof(struct pisp_fe_config, ch[1].downscale), + sizeof(struct pisp_fe_downscale_config) }, + { PISP_FE_ENABLE_COMPRESS1, 0, + offsetof(struct pisp_fe_config, ch[1].compress), + sizeof(struct pisp_compress_config) }, + { PISP_FE_ENABLE_OUTPUT1, 0, + offsetof(struct pisp_fe_config, ch[1].output), + sizeof(struct pisp_fe_output_config) }, +}; + +#define pisp_fe_dbg(fe, fmt, arg...) dev_dbg((fe)->v4l2_dev->dev, fmt, ##arg) +#define pisp_fe_info(fe, fmt, arg...) dev_info((fe)->v4l2_dev->dev, fmt, ##arg) +#define pisp_fe_err(fe, fmt, arg...) dev_err((fe)->v4l2_dev->dev, fmt, ##arg) + +static inline u32 pisp_fe_reg_read(struct pisp_fe_device *fe, u32 offset) +{ + return readl(fe->base + offset); +} + +static inline void pisp_fe_reg_write(struct pisp_fe_device *fe, u32 offset, + u32 val) +{ + writel(val, fe->base + offset); +} + +static inline void pisp_fe_reg_write_relaxed(struct pisp_fe_device *fe, + u32 offset, u32 val) +{ + writel_relaxed(val, fe->base + offset); +} + +static int pisp_fe_regs_show(struct seq_file *s, void *data) +{ + struct pisp_fe_device *fe = s->private; + int ret; + + ret = pm_runtime_resume_and_get(fe->v4l2_dev->dev); + if (ret) + return ret; + + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS); + +#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", pisp_fe_reg_read(fe, reg)) + DUMP(FE_VERSION); + DUMP(FE_CONTROL); + DUMP(FE_STATUS); + DUMP(FE_FRAME_STATUS); + DUMP(FE_ERROR_STATUS); + DUMP(FE_OUTPUT_STATUS); + DUMP(FE_INT_EN); + DUMP(FE_INT_STATUS); +#undef DUMP + + pm_runtime_put(fe->v4l2_dev->dev); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(pisp_fe_regs); + +static void pisp_fe_config_write(struct pisp_fe_device *fe, + struct pisp_fe_config *config, + unsigned int start_offset, unsigned int size) +{ + const unsigned int max_offset = + offsetof(struct pisp_fe_config, ch[PISP_FE_NUM_OUTPUTS]); + unsigned int end_offset; + u32 *cfg = (u32 *)config; + + start_offset = min(start_offset, max_offset); + end_offset = min(start_offset + size, max_offset); + + cfg += start_offset >> 2; + for (unsigned int i = start_offset; i < end_offset; i += 4, cfg++) + pisp_fe_reg_write_relaxed(fe, PISP_FE_CONFIG_BASE_OFFSET + i, + *cfg); +} + +void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof) +{ + u32 status, int_status, out_status, frame_status, error_status; + + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS); + status = pisp_fe_reg_read(fe, FE_STATUS); + out_status = pisp_fe_reg_read(fe, FE_OUTPUT_STATUS); + frame_status = pisp_fe_reg_read(fe, FE_FRAME_STATUS); + error_status = pisp_fe_reg_read(fe, FE_ERROR_STATUS); + + int_status = pisp_fe_reg_read(fe, FE_INT_STATUS); + pisp_fe_reg_write(fe, FE_INT_STATUS, int_status); + + trace_fe_irq(status, out_status, frame_status, error_status, + int_status); + + /* We do not report interrupts for the input/stream pad. */ + for (unsigned int i = 0; i < FE_NUM_PADS - 1; i++) { + sof[i] = !!(int_status & FE_INT_SOF); + eof[i] = !!(int_status & FE_INT_EOF); + } +} + +static bool pisp_fe_validate_output(struct pisp_fe_config const *cfg, + unsigned int c, struct v4l2_format const *f) +{ + unsigned int wbytes; + + wbytes = cfg->ch[c].output.format.width; + if (cfg->ch[c].output.format.format & PISP_IMAGE_FORMAT_BPS_MASK) + wbytes *= 2; + + /* Check output image dimensions are nonzero and not too big */ + if (cfg->ch[c].output.format.width < 2 || + cfg->ch[c].output.format.height < 2 || + cfg->ch[c].output.format.height > f->fmt.pix.height || + cfg->ch[c].output.format.stride > f->fmt.pix.bytesperline || + wbytes > f->fmt.pix.bytesperline) + return false; + + /* Check for zero-sized crops, which could cause lockup */ + if ((cfg->global.enables & PISP_FE_ENABLE_CROP(c)) && + ((cfg->ch[c].crop.offset_x >= (cfg->input.format.width & ~1) || + cfg->ch[c].crop.offset_y >= cfg->input.format.height || + cfg->ch[c].crop.width < 2 || cfg->ch[c].crop.height < 2))) + return false; + + if ((cfg->global.enables & PISP_FE_ENABLE_DOWNSCALE(c)) && + (cfg->ch[c].downscale.output_width < 2 || + cfg->ch[c].downscale.output_height < 2)) + return false; + + return true; +} + +static bool pisp_fe_validate_stats(struct pisp_fe_config const *cfg) +{ + /* Check for zero-sized crop, which could cause lockup */ + return (!(cfg->global.enables & PISP_FE_ENABLE_STATS_CROP) || + (cfg->stats_crop.offset_x < (cfg->input.format.width & ~1) && + cfg->stats_crop.offset_y < cfg->input.format.height && + cfg->stats_crop.width >= 2 && cfg->stats_crop.height >= 2)); +} + +int pisp_fe_validate_config(struct pisp_fe_device *fe, + struct pisp_fe_config *cfg, + struct v4l2_format const *f0, + struct v4l2_format const *f1) +{ + /* + * Check the input is enabled, streaming and has nonzero size; + * to avoid cases where the hardware might lock up or try to + * read inputs from memory (which this driver doesn't support). + */ + if (!(cfg->global.enables & PISP_FE_ENABLE_INPUT) || + cfg->input.streaming != 1 || cfg->input.format.width < 2 || + cfg->input.format.height < 2) { + pisp_fe_err(fe, "%s: Input config not valid", __func__); + return -EINVAL; + } + + for (unsigned int i = 0; i < PISP_FE_NUM_OUTPUTS; i++) { + if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) { + if (cfg->global.enables & + PISP_FE_ENABLE_OUTPUT_CLUSTER(i)) { + pisp_fe_err(fe, "%s: Output %u not valid", + __func__, i); + return -EINVAL; + } + continue; + } + + if (!pisp_fe_validate_output(cfg, i, i ? f1 : f0)) + return -EINVAL; + } + + if ((cfg->global.enables & PISP_FE_ENABLE_STATS_CLUSTER) && + !pisp_fe_validate_stats(cfg)) { + pisp_fe_err(fe, "%s: Stats config not valid", __func__); + return -EINVAL; + } + + return 0; +} + +void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs, + struct pisp_fe_config *cfg) +{ + u64 addr; + u32 status; + + /* + * Check output buffers exist and outputs are correctly configured. + * If valid, set the buffer's DMA address; otherwise disable. + */ + for (unsigned int i = 0; i < PISP_FE_NUM_OUTPUTS; i++) { + struct vb2_buffer *buf = vb2_bufs[FE_OUTPUT0_PAD + i]; + + if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) + continue; + + addr = vb2_dma_contig_plane_dma_addr(buf, 0); + cfg->output_buffer[i].addr_lo = addr & 0xffffffff; + cfg->output_buffer[i].addr_hi = addr >> 32; + } + + if (vb2_bufs[FE_STATS_PAD]) { + addr = vb2_dma_contig_plane_dma_addr(vb2_bufs[FE_STATS_PAD], 0); + cfg->stats_buffer.addr_lo = addr & 0xffffffff; + cfg->stats_buffer.addr_hi = addr >> 32; + } + + /* Set up ILINES interrupts 3/4 of the way down each output */ + cfg->ch[0].output.ilines = + max(0x80u, (3u * cfg->ch[0].output.format.height) >> 2); + cfg->ch[1].output.ilines = + max(0x80u, (3u * cfg->ch[1].output.format.height) >> 2); + + /* + * The hardware must have consumed the previous config by now. + * This read of status also serves as a memory barrier before the + * sequence of relaxed writes which follow. + */ + status = pisp_fe_reg_read(fe, FE_STATUS); + if (WARN_ON(status & FE_STATUS_QUEUED)) + return; + + /* + * Unconditionally write buffers, global and input parameters. + * Write cropping and output parameters whenever they are enabled. + * Selectively write other parameters that have been marked as + * changed through the dirty flags. + */ + pisp_fe_config_write(fe, cfg, 0, + offsetof(struct pisp_fe_config, decompress)); + cfg->dirty_flags_extra &= ~PISP_FE_DIRTY_GLOBAL; + cfg->dirty_flags &= ~PISP_FE_ENABLE_INPUT; + cfg->dirty_flags |= (cfg->global.enables & + (PISP_FE_ENABLE_STATS_CROP | + PISP_FE_ENABLE_OUTPUT_CLUSTER(0) | + PISP_FE_ENABLE_OUTPUT_CLUSTER(1))); + for (unsigned int i = 0; i < ARRAY_SIZE(pisp_fe_config_map); i++) { + const struct pisp_fe_config_param *p = &pisp_fe_config_map[i]; + + if (cfg->dirty_flags & p->dirty_flags || + cfg->dirty_flags_extra & p->dirty_flags_extra) + pisp_fe_config_write(fe, cfg, p->offset, p->size); + } + + /* This final non-relaxed write serves as a memory barrier */ + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_QUEUE); +} + +void pisp_fe_start(struct pisp_fe_device *fe) +{ + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_RESET); + pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); + pisp_fe_reg_write(fe, FE_INT_EN, FE_INT_EOF | FE_INT_SOF | + FE_INT_LINES0 | FE_INT_LINES1); + fe->inframe_count = 0; +} + +void pisp_fe_stop(struct pisp_fe_device *fe) +{ + pisp_fe_reg_write(fe, FE_INT_EN, 0); + pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_ABORT); + usleep_range(1000, 2000); + WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); + pisp_fe_reg_write(fe, FE_INT_STATUS, ~0); +} + +static int pisp_fe_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD); + *fmt = cfe_default_format; + fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + + fmt = v4l2_subdev_state_get_format(state, FE_CONFIG_PAD); + fmt->code = MEDIA_BUS_FMT_FIXED; + fmt->width = sizeof(struct pisp_fe_config); + fmt->height = 1; + + fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT0_PAD); + *fmt = cfe_default_format; + fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + + fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT1_PAD); + *fmt = cfe_default_format; + fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + + fmt = v4l2_subdev_state_get_format(state, FE_STATS_PAD); + fmt->code = MEDIA_BUS_FMT_FIXED; + fmt->width = sizeof(struct pisp_statistics); + fmt->height = 1; + + return 0; +} + +static int pisp_fe_pad_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + const struct cfe_fmt *cfe_fmt; + + /* TODO: format propagation to source pads */ + /* TODO: format validation */ + + switch (format->pad) { + case FE_STREAM_PAD: + cfe_fmt = find_format_by_code(format->format.code); + if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT)) + cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16); + + format->format.code = cfe_fmt->code; + format->format.field = V4L2_FIELD_NONE; + + fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD); + *fmt = format->format; + + fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT0_PAD); + *fmt = format->format; + + fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT1_PAD); + *fmt = format->format; + + return 0; + + case FE_OUTPUT0_PAD: + case FE_OUTPUT1_PAD: { + /* + * TODO: we should allow scaling and cropping by allowing the + * user to set the size here. + */ + struct v4l2_mbus_framefmt *sink_fmt, *source_fmt; + u32 sink_code; + u32 code; + + cfe_fmt = find_format_by_code(format->format.code); + if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT)) + cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16); + + format->format.code = cfe_fmt->code; + + sink_fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD); + if (!sink_fmt) + return -EINVAL; + + source_fmt = v4l2_subdev_state_get_format(state, format->pad); + if (!source_fmt) + return -EINVAL; + + sink_code = sink_fmt->code; + code = format->format.code; + + /* + * If the source code from the user does not match the code in + * the sink pad, check that the source code matches the + * compressed version of the sink code. + */ + + if (code != sink_code && + code == cfe_find_compressed_code(sink_code)) + source_fmt->code = code; + + return 0; + } + + case FE_CONFIG_PAD: + case FE_STATS_PAD: + default: + return v4l2_subdev_get_fmt(sd, state, format); + } +} + +static const struct v4l2_subdev_pad_ops pisp_fe_subdev_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = pisp_fe_pad_set_fmt, + .link_validate = v4l2_subdev_link_validate_default, +}; + +static int pisp_fe_link_validate(struct media_link *link) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(link->sink->entity); + struct pisp_fe_device *fe = container_of(sd, struct pisp_fe_device, sd); + + pisp_fe_dbg(fe, "%s: link \"%s\":%u -> \"%s\":%u\n", __func__, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + if (link->sink->index == FE_STREAM_PAD) + return v4l2_subdev_link_validate(link); + + if (link->sink->index == FE_CONFIG_PAD) + return 0; + + return -EINVAL; +} + +static const struct media_entity_operations pisp_fe_entity_ops = { + .link_validate = pisp_fe_link_validate, +}; + +static const struct v4l2_subdev_ops pisp_fe_subdev_ops = { + .pad = &pisp_fe_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops pisp_fe_internal_ops = { + .init_state = pisp_fe_init_state, +}; + +int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs) +{ + int ret; + + debugfs_create_file("fe_regs", 0440, debugfs, fe, &pisp_fe_regs_fops); + + fe->hw_revision = pisp_fe_reg_read(fe, FE_VERSION); + pisp_fe_info(fe, "PiSP FE HW v%u.%u\n", + (fe->hw_revision >> 24) & 0xff, + (fe->hw_revision >> 20) & 0x0f); + + fe->pad[FE_STREAM_PAD].flags = + MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + fe->pad[FE_CONFIG_PAD].flags = MEDIA_PAD_FL_SINK; + fe->pad[FE_OUTPUT0_PAD].flags = MEDIA_PAD_FL_SOURCE; + fe->pad[FE_OUTPUT1_PAD].flags = MEDIA_PAD_FL_SOURCE; + fe->pad[FE_STATS_PAD].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&fe->sd.entity, ARRAY_SIZE(fe->pad), + fe->pad); + if (ret) + return ret; + + /* Initialize subdev */ + v4l2_subdev_init(&fe->sd, &pisp_fe_subdev_ops); + fe->sd.internal_ops = &pisp_fe_internal_ops; + fe->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; + fe->sd.entity.ops = &pisp_fe_entity_ops; + fe->sd.entity.name = "pisp-fe"; + fe->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + fe->sd.owner = THIS_MODULE; + snprintf(fe->sd.name, sizeof(fe->sd.name), "pisp-fe"); + + ret = v4l2_subdev_init_finalize(&fe->sd); + if (ret) + goto err_entity_cleanup; + + ret = v4l2_device_register_subdev(fe->v4l2_dev, &fe->sd); + if (ret) { + pisp_fe_err(fe, "Failed register pisp fe subdev (%d)\n", ret); + goto err_subdev_cleanup; + } + + /* Must be in IDLE state (STATUS == 0) here. */ + WARN_ON(pisp_fe_reg_read(fe, FE_STATUS)); + + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&fe->sd); +err_entity_cleanup: + media_entity_cleanup(&fe->sd.entity); + + return ret; +} + +void pisp_fe_uninit(struct pisp_fe_device *fe) +{ + v4l2_device_unregister_subdev(&fe->sd); + v4l2_subdev_cleanup(&fe->sd); + media_entity_cleanup(&fe->sd.entity); +} diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h new file mode 100644 index 00000000000000..54d506e19cf214 --- /dev/null +++ b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * PiSP Front End Driver + * + * Copyright (c) 2021-2024 Raspberry Pi Ltd. + */ +#ifndef _PISP_FE_H_ +#define _PISP_FE_H_ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +enum pisp_fe_pads { + FE_STREAM_PAD, + FE_CONFIG_PAD, + FE_OUTPUT0_PAD, + FE_OUTPUT1_PAD, + FE_STATS_PAD, + FE_NUM_PADS +}; + +struct pisp_fe_device { + /* Parent V4l2 device */ + struct v4l2_device *v4l2_dev; + void __iomem *base; + u32 hw_revision; + + u16 inframe_count; + struct media_pad pad[FE_NUM_PADS]; + struct v4l2_subdev sd; +}; + +void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof); +int pisp_fe_validate_config(struct pisp_fe_device *fe, + struct pisp_fe_config *cfg, + struct v4l2_format const *f0, + struct v4l2_format const *f1); +void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs, + struct pisp_fe_config *cfg); +void pisp_fe_start(struct pisp_fe_device *fe); +void pisp_fe_stop(struct pisp_fe_device *fe); +int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs); +void pisp_fe_uninit(struct pisp_fe_device *fe); + +#endif diff --git a/drivers/media/platform/renesas/rcar-csi2.c b/drivers/media/platform/renesas/rcar-csi2.c index c419ddb4c5a2c1..27ffdd28cbf7d3 100644 --- a/drivers/media/platform/renesas/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-csi2.c @@ -135,13 +135,23 @@ struct rcar_csi2; /* V4H BASE registers */ #define V4H_N_LANES_REG 0x0004 #define V4H_CSI2_RESETN_REG 0x0008 + #define V4H_PHY_MODE_REG 0x001c +#define V4H_PHY_MODE_DPHY 0 +#define V4H_PHY_MODE_CPHY 1 + #define V4H_PHY_SHUTDOWNZ_REG 0x0040 #define V4H_DPHY_RSTZ_REG 0x0044 #define V4H_FLDC_REG 0x0804 #define V4H_FLDD_REG 0x0808 #define V4H_IDIC_REG 0x0810 + #define V4H_PHY_EN_REG 0x2000 +#define V4H_PHY_EN_ENABLE_3 BIT(7) +#define V4H_PHY_EN_ENABLE_2 BIT(6) +#define V4H_PHY_EN_ENABLE_1 BIT(5) +#define V4H_PHY_EN_ENABLE_0 BIT(4) +#define V4H_PHY_EN_ENABLE_CLK BIT(0) #define V4H_ST_PHYST_REG 0x2814 #define V4H_ST_PHYST_ST_PHY_READY BIT(31) @@ -237,17 +247,37 @@ static const struct rcsi2_cphy_setting cphy_setting_table_r8a779g0[] = { { /* sentinel */ }, }; +/* V4M registers */ +#define V4M_OVR1_REG 0x0848 +#define V4M_OVR1_FORCERXMODE_3 BIT(12) +#define V4M_OVR1_FORCERXMODE_2 BIT(11) +#define V4M_OVR1_FORCERXMODE_1 BIT(10) +#define V4M_OVR1_FORCERXMODE_0 BIT(9) + +#define V4M_FRXM_REG 0x2004 +#define V4M_FRXM_FORCERXMODE_3 BIT(3) +#define V4M_FRXM_FORCERXMODE_2 BIT(2) +#define V4M_FRXM_FORCERXMODE_1 BIT(1) +#define V4M_FRXM_FORCERXMODE_0 BIT(0) + +#define V4M_PHYPLL_REG 0x02050 +#define V4M_CSI0CLKFCPR_REG 0x02054 +#define V4M_PHTW_REG 0x02060 +#define V4M_PHTR_REG 0x02064 +#define V4M_PHTC_REG 0x02068 + struct phtw_value { - u16 data; - u16 code; + u8 data; + u8 code; }; -struct rcsi2_mbps_reg { +struct rcsi2_mbps_info { u16 mbps; - u16 reg; + u8 reg; + u16 osc_freq; /* V4M */ }; -static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = { +static const struct rcsi2_mbps_info phtw_mbps_v3u[] = { { .mbps = 1500, .reg = 0xcc }, { .mbps = 1550, .reg = 0x1d }, { .mbps = 1600, .reg = 0x27 }, @@ -272,7 +302,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = { { /* sentinel */ }, }; -static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { +static const struct rcsi2_mbps_info phtw_mbps_h3_v3h_m3n[] = { { .mbps = 80, .reg = 0x86 }, { .mbps = 90, .reg = 0x86 }, { .mbps = 100, .reg = 0x87 }, @@ -292,7 +322,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { { /* sentinel */ }, }; -static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { +static const struct rcsi2_mbps_info phtw_mbps_v3m_e3[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x20 }, { .mbps = 100, .reg = 0x40 }, @@ -336,7 +366,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { #define PHYPLL_REG 0x68 #define PHYPLL_HSFREQRANGE(n) ((n) << 16) -static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = { +static const struct rcsi2_mbps_info hsfreqrange_v3u[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x10 }, { .mbps = 100, .reg = 0x20 }, @@ -402,7 +432,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = { { /* sentinel */ }, }; -static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { +static const struct rcsi2_mbps_info hsfreqrange_h3_v3h_m3n[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x10 }, { .mbps = 100, .reg = 0x20 }, @@ -449,7 +479,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { { /* sentinel */ }, }; -static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = { +static const struct rcsi2_mbps_info hsfreqrange_m3w[] = { { .mbps = 80, .reg = 0x00 }, { .mbps = 90, .reg = 0x10 }, { .mbps = 100, .reg = 0x20 }, @@ -496,6 +526,73 @@ static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = { { /* sentinel */ }, }; +static const struct rcsi2_mbps_info hsfreqrange_v4m[] = { + { .mbps = 80, .reg = 0x00, .osc_freq = 0x01a9 }, + { .mbps = 90, .reg = 0x10, .osc_freq = 0x01a9 }, + { .mbps = 100, .reg = 0x20, .osc_freq = 0x01a9 }, + { .mbps = 110, .reg = 0x30, .osc_freq = 0x01a9 }, + { .mbps = 120, .reg = 0x01, .osc_freq = 0x01a9 }, + { .mbps = 130, .reg = 0x11, .osc_freq = 0x01a9 }, + { .mbps = 140, .reg = 0x21, .osc_freq = 0x01a9 }, + { .mbps = 150, .reg = 0x31, .osc_freq = 0x01a9 }, + { .mbps = 160, .reg = 0x02, .osc_freq = 0x01a9 }, + { .mbps = 170, .reg = 0x12, .osc_freq = 0x01a9 }, + { .mbps = 180, .reg = 0x22, .osc_freq = 0x01a9 }, + { .mbps = 190, .reg = 0x32, .osc_freq = 0x01a9 }, + { .mbps = 205, .reg = 0x03, .osc_freq = 0x01a9 }, + { .mbps = 220, .reg = 0x13, .osc_freq = 0x01a9 }, + { .mbps = 235, .reg = 0x23, .osc_freq = 0x01a9 }, + { .mbps = 250, .reg = 0x33, .osc_freq = 0x01a9 }, + { .mbps = 275, .reg = 0x04, .osc_freq = 0x01a9 }, + { .mbps = 300, .reg = 0x14, .osc_freq = 0x01a9 }, + { .mbps = 325, .reg = 0x25, .osc_freq = 0x01a9 }, + { .mbps = 350, .reg = 0x35, .osc_freq = 0x01a9 }, + { .mbps = 400, .reg = 0x05, .osc_freq = 0x01a9 }, + { .mbps = 450, .reg = 0x16, .osc_freq = 0x01a9 }, + { .mbps = 500, .reg = 0x26, .osc_freq = 0x01a9 }, + { .mbps = 550, .reg = 0x37, .osc_freq = 0x01a9 }, + { .mbps = 600, .reg = 0x07, .osc_freq = 0x01a9 }, + { .mbps = 650, .reg = 0x18, .osc_freq = 0x01a9 }, + { .mbps = 700, .reg = 0x28, .osc_freq = 0x01a9 }, + { .mbps = 750, .reg = 0x39, .osc_freq = 0x01a9 }, + { .mbps = 800, .reg = 0x09, .osc_freq = 0x01a9 }, + { .mbps = 850, .reg = 0x19, .osc_freq = 0x01a9 }, + { .mbps = 900, .reg = 0x29, .osc_freq = 0x01a9 }, + { .mbps = 950, .reg = 0x3a, .osc_freq = 0x01a9 }, + { .mbps = 1000, .reg = 0x0a, .osc_freq = 0x01a9 }, + { .mbps = 1050, .reg = 0x1a, .osc_freq = 0x01a9 }, + { .mbps = 1100, .reg = 0x2a, .osc_freq = 0x01a9 }, + { .mbps = 1150, .reg = 0x3b, .osc_freq = 0x01a9 }, + { .mbps = 1200, .reg = 0x0b, .osc_freq = 0x01a9 }, + { .mbps = 1250, .reg = 0x1b, .osc_freq = 0x01a9 }, + { .mbps = 1300, .reg = 0x2b, .osc_freq = 0x01a9 }, + { .mbps = 1350, .reg = 0x3c, .osc_freq = 0x01a9 }, + { .mbps = 1400, .reg = 0x0c, .osc_freq = 0x01a9 }, + { .mbps = 1450, .reg = 0x1c, .osc_freq = 0x01a9 }, + { .mbps = 1500, .reg = 0x2c, .osc_freq = 0x01a9 }, + { .mbps = 1550, .reg = 0x3d, .osc_freq = 0x0108 }, + { .mbps = 1600, .reg = 0x0d, .osc_freq = 0x0110 }, + { .mbps = 1650, .reg = 0x1d, .osc_freq = 0x0119 }, + { .mbps = 1700, .reg = 0x2e, .osc_freq = 0x0121 }, + { .mbps = 1750, .reg = 0x3e, .osc_freq = 0x012a }, + { .mbps = 1800, .reg = 0x0e, .osc_freq = 0x0132 }, + { .mbps = 1850, .reg = 0x1e, .osc_freq = 0x013b }, + { .mbps = 1900, .reg = 0x2f, .osc_freq = 0x0143 }, + { .mbps = 1950, .reg = 0x3f, .osc_freq = 0x014c }, + { .mbps = 2000, .reg = 0x0f, .osc_freq = 0x0154 }, + { .mbps = 2050, .reg = 0x40, .osc_freq = 0x015d }, + { .mbps = 2100, .reg = 0x41, .osc_freq = 0x0165 }, + { .mbps = 2150, .reg = 0x42, .osc_freq = 0x016e }, + { .mbps = 2200, .reg = 0x43, .osc_freq = 0x0176 }, + { .mbps = 2250, .reg = 0x44, .osc_freq = 0x017f }, + { .mbps = 2300, .reg = 0x45, .osc_freq = 0x0187 }, + { .mbps = 2350, .reg = 0x46, .osc_freq = 0x0190 }, + { .mbps = 2400, .reg = 0x47, .osc_freq = 0x0198 }, + { .mbps = 2450, .reg = 0x48, .osc_freq = 0x01a1 }, + { .mbps = 2500, .reg = 0x49, .osc_freq = 0x01a9 }, + { /* sentinel */ }, +}; + /* PHY ESC Error Monitor */ #define PHEERM_REG 0x74 @@ -584,13 +681,19 @@ enum rcar_csi2_pads { NR_OF_RCAR_CSI2_PAD, }; +struct rcsi2_register_layout { + unsigned int phtw; + unsigned int phypll; +}; + struct rcar_csi2_info { + const struct rcsi2_register_layout *regs; int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); int (*phy_post_init)(struct rcar_csi2 *priv); int (*start_receiver)(struct rcar_csi2 *priv, struct v4l2_subdev_state *state); void (*enter_standby)(struct rcar_csi2 *priv); - const struct rcsi2_mbps_reg *hsfreqrange; + const struct rcsi2_mbps_info *hsfreqrange; unsigned int csi0clkfreqrange; unsigned int num_channels; bool clear_ulps; @@ -656,6 +759,70 @@ static void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data) iowrite16(data, priv->base + reg); } +static int rcsi2_phtw_write(struct rcar_csi2 *priv, u8 data, u8 code) +{ + unsigned int timeout; + + rcsi2_write(priv, priv->info->regs->phtw, + PHTW_DWEN | PHTW_TESTDIN_DATA(data) | + PHTW_CWEN | PHTW_TESTDIN_CODE(code)); + + /* Wait for DWEN and CWEN to be cleared by hardware. */ + for (timeout = 0; timeout <= 20; timeout++) { + if (!(rcsi2_read(priv, priv->info->regs->phtw) & (PHTW_DWEN | PHTW_CWEN))) + return 0; + + usleep_range(1000, 2000); + } + + dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n"); + + return -ETIMEDOUT; +} + +static int rcsi2_phtw_write_array(struct rcar_csi2 *priv, + const struct phtw_value *values, + unsigned int size) +{ + int ret; + + for (unsigned int i = 0; i < size; i++) { + ret = rcsi2_phtw_write(priv, values[i].data, values[i].code); + if (ret) + return ret; + } + + return 0; +} + +static const struct rcsi2_mbps_info * +rcsi2_mbps_to_info(struct rcar_csi2 *priv, + const struct rcsi2_mbps_info *infotable, unsigned int mbps) +{ + const struct rcsi2_mbps_info *info; + const struct rcsi2_mbps_info *prev = NULL; + + if (mbps < infotable->mbps) + dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps", + mbps, infotable->mbps); + + for (info = infotable; info->mbps != 0; info++) { + if (info->mbps >= mbps) + break; + prev = info; + } + + if (!info->mbps) { + dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); + return NULL; + } + + if (prev && ((mbps - prev->mbps) <= (info->mbps - mbps))) + info = prev; + + return info; +} + static void rcsi2_enter_standby_gen3(struct rcar_csi2 *priv) { rcsi2_write(priv, PHYCNT_REG, 0); @@ -708,29 +875,13 @@ static int rcsi2_wait_phy_start(struct rcar_csi2 *priv, static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) { - const struct rcsi2_mbps_reg *hsfreq; - const struct rcsi2_mbps_reg *hsfreq_prev = NULL; - - if (mbps < priv->info->hsfreqrange->mbps) - dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps", - mbps, priv->info->hsfreqrange->mbps); - - for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) { - if (hsfreq->mbps >= mbps) - break; - hsfreq_prev = hsfreq; - } + const struct rcsi2_mbps_info *info; - if (!hsfreq->mbps) { - dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); + info = rcsi2_mbps_to_info(priv, priv->info->hsfreqrange, mbps); + if (!info) return -ERANGE; - } - if (hsfreq_prev && - ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps))) - hsfreq = hsfreq_prev; - - rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg)); + rcsi2_write(priv, priv->info->regs->phypll, PHYPLL_HSFREQRANGE(info->reg)); return 0; } @@ -1092,11 +1243,11 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); /* PHY static setting */ - rcsi2_write(priv, V4H_PHY_EN_REG, BIT(0)); + rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK); rcsi2_write(priv, V4H_FLDC_REG, 0); rcsi2_write(priv, V4H_FLDD_REG, 0); rcsi2_write(priv, V4H_IDIC_REG, 0); - rcsi2_write(priv, V4H_PHY_MODE_REG, BIT(0)); + rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_CPHY); rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1); /* Reset CSI2 */ @@ -1131,6 +1282,195 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, return 0; } +static int rcsi2_d_phy_setting_v4m(struct rcar_csi2 *priv, int data_rate) +{ + unsigned int timeout; + int ret; + + static const struct phtw_value step1[] = { + { .data = 0x00, .code = 0x00 }, + { .data = 0x00, .code = 0x1e }, + }; + + /* Shutdown and reset PHY. */ + rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); + rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); + + /* Start internal calibration (POR). */ + ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); + if (ret) + return ret; + + /* Wait for POR to complete. */ + for (timeout = 10; timeout > 0; timeout--) { + if ((rcsi2_read(priv, V4M_PHTR_REG) & 0xf0000) == 0x70000) + break; + usleep_range(1000, 2000); + } + + if (!timeout) { + dev_err(priv->dev, "D-PHY calibration failed\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rcsi2_set_osc_freq(struct rcar_csi2 *priv, unsigned int mbps) +{ + const struct rcsi2_mbps_info *info; + struct phtw_value steps[] = { + { .data = 0x00, .code = 0x00 }, + { .code = 0xe2 }, /* Data filled in below. */ + { .code = 0xe3 }, /* Data filled in below. */ + { .data = 0x01, .code = 0xe4 }, + }; + + info = rcsi2_mbps_to_info(priv, priv->info->hsfreqrange, mbps); + if (!info) + return -ERANGE; + + /* Fill in data for command. */ + steps[1].data = (info->osc_freq & 0x00ff) >> 0; + steps[2].data = (info->osc_freq & 0x0f00) >> 8; + + return rcsi2_phtw_write_array(priv, steps, ARRAY_SIZE(steps)); +} + +static int rcsi2_init_common_v4m(struct rcar_csi2 *priv, unsigned int mbps) +{ + int ret; + + static const struct phtw_value step1[] = { + { .data = 0x00, .code = 0x00 }, + { .data = 0x3c, .code = 0x08 }, + }; + + static const struct phtw_value step2[] = { + { .data = 0x00, .code = 0x00 }, + { .data = 0x80, .code = 0xe0 }, + { .data = 0x01, .code = 0xe1 }, + { .data = 0x06, .code = 0x00 }, + { .data = 0x0f, .code = 0x11 }, + { .data = 0x08, .code = 0x00 }, + { .data = 0x0f, .code = 0x11 }, + { .data = 0x0a, .code = 0x00 }, + { .data = 0x0f, .code = 0x11 }, + { .data = 0x0c, .code = 0x00 }, + { .data = 0x0f, .code = 0x11 }, + { .data = 0x01, .code = 0x00 }, + { .data = 0x31, .code = 0xaa }, + { .data = 0x05, .code = 0x00 }, + { .data = 0x05, .code = 0x09 }, + { .data = 0x07, .code = 0x00 }, + { .data = 0x05, .code = 0x09 }, + { .data = 0x09, .code = 0x00 }, + { .data = 0x05, .code = 0x09 }, + { .data = 0x0b, .code = 0x00 }, + { .data = 0x05, .code = 0x09 }, + }; + + if (priv->info->hsfreqrange) { + ret = rcsi2_set_phypll(priv, mbps); + if (ret) + return ret; + + ret = rcsi2_set_osc_freq(priv, mbps); + if (ret) + return ret; + } + + if (mbps <= 1500) { + ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); + if (ret) + return ret; + } + + if (priv->info->csi0clkfreqrange) + rcsi2_write(priv, V4M_CSI0CLKFCPR_REG, + CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange)); + + rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK | + V4H_PHY_EN_ENABLE_0 | V4H_PHY_EN_ENABLE_1 | + V4H_PHY_EN_ENABLE_2 | V4H_PHY_EN_ENABLE_3); + + if (mbps > 1500) { + ret = rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2)); + if (ret) + return ret; + } + + return ret; +} + +static int rcsi2_start_receiver_v4m(struct rcar_csi2 *priv, + struct v4l2_subdev_state *state) +{ + const struct rcar_csi2_format *format; + const struct v4l2_mbus_framefmt *fmt; + unsigned int lanes; + int mbps; + int ret; + + /* Calculate parameters */ + fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK); + format = rcsi2_code_to_fmt(fmt->code); + if (!format) + return -EINVAL; + + ret = rcsi2_get_active_lanes(priv, &lanes); + if (ret) + return ret; + + mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); + if (mbps < 0) + return mbps; + + /* Reset LINK and PHY */ + rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0); + rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0); + rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); + rcsi2_write(priv, V4M_PHTC_REG, PHTC_TESTCLR); + + /* PHY static setting */ + rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK); + rcsi2_write(priv, V4H_FLDC_REG, 0); + rcsi2_write(priv, V4H_FLDD_REG, 0); + rcsi2_write(priv, V4H_IDIC_REG, 0); + rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_DPHY); + rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1); + + rcsi2_write(priv, V4M_FRXM_REG, + V4M_FRXM_FORCERXMODE_0 | V4M_FRXM_FORCERXMODE_1 | + V4M_FRXM_FORCERXMODE_2 | V4M_FRXM_FORCERXMODE_3); + rcsi2_write(priv, V4M_OVR1_REG, + V4M_OVR1_FORCERXMODE_0 | V4M_OVR1_FORCERXMODE_1 | + V4M_OVR1_FORCERXMODE_2 | V4M_OVR1_FORCERXMODE_3); + + /* Reset CSI2 */ + rcsi2_write(priv, V4M_PHTC_REG, 0); + rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0)); + + /* Common settings */ + ret = rcsi2_init_common_v4m(priv, mbps); + if (ret) + return ret; + + /* D-PHY settings */ + ret = rcsi2_d_phy_setting_v4m(priv, mbps); + if (ret) + return ret; + + rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 | + V4H_ST_PHYST_ST_STOPSTATE_1 | + V4H_ST_PHYST_ST_STOPSTATE_2 | + V4H_ST_PHYST_ST_STOPSTATE_3); + + rcsi2_write(priv, V4M_FRXM_REG, 0); + + return 0; +} + static int rcsi2_start(struct rcar_csi2 *priv, struct v4l2_subdev_state *state) { int ret; @@ -1451,64 +1791,16 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv) * NOTE: Magic values are from the datasheet and lack documentation. */ -static int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code) -{ - unsigned int timeout; - - rcsi2_write(priv, PHTW_REG, - PHTW_DWEN | PHTW_TESTDIN_DATA(data) | - PHTW_CWEN | PHTW_TESTDIN_CODE(code)); - - /* Wait for DWEN and CWEN to be cleared by hardware. */ - for (timeout = 0; timeout <= 20; timeout++) { - if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN))) - return 0; - - usleep_range(1000, 2000); - } - - dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n"); - - return -ETIMEDOUT; -} - -static int rcsi2_phtw_write_array(struct rcar_csi2 *priv, - const struct phtw_value *values) -{ - const struct phtw_value *value; - int ret; - - for (value = values; value->data || value->code; value++) { - ret = rcsi2_phtw_write(priv, value->data, value->code); - if (ret) - return ret; - } - - return 0; -} - static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, - const struct rcsi2_mbps_reg *values, u16 code) + const struct rcsi2_mbps_info *values, u8 code) { - const struct rcsi2_mbps_reg *value; - const struct rcsi2_mbps_reg *prev_value = NULL; - - for (value = values; value->mbps; value++) { - if (value->mbps >= mbps) - break; - prev_value = value; - } + const struct rcsi2_mbps_info *info; - if (prev_value && - ((mbps - prev_value->mbps) <= (value->mbps - mbps))) - value = prev_value; - - if (!value->mbps) { - dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); + info = rcsi2_mbps_to_info(priv, values, mbps); + if (!info) return -ERANGE; - } - return rcsi2_phtw_write(priv, value->reg, code); + return rcsi2_phtw_write(priv, info->reg, code); } static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, @@ -1520,7 +1812,6 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, { .data = 0x11, .code = 0xe4 }, { .data = 0x01, .code = 0xe5 }, { .data = 0x10, .code = 0x04 }, - { /* sentinel */ }, }; static const struct phtw_value step2[] = { @@ -1529,12 +1820,11 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, { .data = 0x4b, .code = 0xac }, { .data = 0x03, .code = 0x00 }, { .data = 0x80, .code = 0x07 }, - { /* sentinel */ }, }; int ret; - ret = rcsi2_phtw_write_array(priv, step1); + ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); if (ret) return ret; @@ -1549,7 +1839,7 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, return ret; } - return rcsi2_phtw_write_array(priv, step2); + return rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2)); } static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) @@ -1575,10 +1865,9 @@ static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) { .data = 0xee, .code = 0x54 }, { .data = 0xee, .code = 0x84 }, { .data = 0xee, .code = 0x94 }, - { /* sentinel */ }, }; - return rcsi2_phtw_write_array(priv, step1); + return rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); } static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, @@ -1587,20 +1876,17 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, /* In case of 1500Mbps or less */ static const struct phtw_value step1[] = { { .data = 0xcc, .code = 0xe2 }, - { /* sentinel */ }, }; static const struct phtw_value step2[] = { { .data = 0x01, .code = 0xe3 }, { .data = 0x11, .code = 0xe4 }, { .data = 0x01, .code = 0xe5 }, - { /* sentinel */ }, }; /* In case of 1500Mbps or less */ static const struct phtw_value step3[] = { { .data = 0x38, .code = 0x08 }, - { /* sentinel */ }, }; static const struct phtw_value step4[] = { @@ -1608,29 +1894,28 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, { .data = 0x4b, .code = 0xac }, { .data = 0x03, .code = 0x00 }, { .data = 0x80, .code = 0x07 }, - { /* sentinel */ }, }; int ret; if (mbps != 0 && mbps <= 1500) - ret = rcsi2_phtw_write_array(priv, step1); + ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1)); else ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2); if (ret) return ret; - ret = rcsi2_phtw_write_array(priv, step2); + ret = rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2)); if (ret) return ret; if (mbps != 0 && mbps <= 1500) { - ret = rcsi2_phtw_write_array(priv, step3); + ret = rcsi2_phtw_write_array(priv, step3, ARRAY_SIZE(step3)); if (ret) return ret; } - ret = rcsi2_phtw_write_array(priv, step4); + ret = rcsi2_phtw_write_array(priv, step4, ARRAY_SIZE(step4)); if (ret) return ret; @@ -1714,7 +1999,13 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv, return PTR_ERR_OR_ZERO(priv->rstc); } +static const struct rcsi2_register_layout rcsi2_registers_gen3 = { + .phtw = PHTW_REG, + .phypll = PHYPLL_REG, +}; + static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1726,6 +2017,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_h3es2, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1737,6 +2029,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { + .regs = &rcsi2_registers_gen3, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, .hsfreqrange = hsfreqrange_m3w, @@ -1745,6 +2038,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = { + .regs = &rcsi2_registers_gen3, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, .hsfreqrange = hsfreqrange_m3w, @@ -1753,6 +2047,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1764,6 +2059,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_v3m_e3, .phy_post_init = rcsi2_phy_post_init_v3m_e3, .start_receiver = rcsi2_start_receiver_gen3, @@ -1773,6 +2069,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1783,6 +2080,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_v3m_e3, .phy_post_init = rcsi2_phy_post_init_v3m_e3, .start_receiver = rcsi2_start_receiver_gen3, @@ -1792,6 +2090,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = { + .regs = &rcsi2_registers_gen3, .init_phtw = rcsi2_init_phtw_v3u, .start_receiver = rcsi2_start_receiver_gen3, .enter_standby = rcsi2_enter_standby_gen3, @@ -1803,11 +2102,26 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = { }; static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = { + .regs = &rcsi2_registers_gen3, .start_receiver = rcsi2_start_receiver_v4h, .use_isp = true, .support_cphy = true, }; +static const struct rcsi2_register_layout rcsi2_registers_v4m = { + .phtw = V4M_PHTW_REG, + .phypll = V4M_PHYPLL_REG, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a779h0 = { + .regs = &rcsi2_registers_v4m, + .start_receiver = rcsi2_start_receiver_v4m, + .hsfreqrange = hsfreqrange_v4m, + .csi0clkfreqrange = 0x0c, + .use_isp = true, + .support_dphy = true, +}; + static const struct of_device_id rcar_csi2_of_table[] = { { .compatible = "renesas,r8a774a1-csi2", @@ -1861,6 +2175,10 @@ static const struct of_device_id rcar_csi2_of_table[] = { .compatible = "renesas,r8a779g0-csi2", .data = &rcar_csi2_info_r8a779g0, }, + { + .compatible = "renesas,r8a779h0-csi2", + .data = &rcar_csi2_info_r8a779h0, + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); @@ -1974,7 +2292,7 @@ static void rcsi2_remove(struct platform_device *pdev) } static struct platform_driver rcar_csi2_pdrv = { - .remove_new = rcsi2_remove, + .remove = rcsi2_remove, .probe = rcsi2_probe, .driver = { .name = "rcar-csi2", diff --git a/drivers/media/platform/renesas/rcar-fcp.c b/drivers/media/platform/renesas/rcar-fcp.c index bcef7b87da7c12..cee9bbce4e3aff 100644 --- a/drivers/media/platform/renesas/rcar-fcp.c +++ b/drivers/media/platform/renesas/rcar-fcp.c @@ -164,7 +164,7 @@ MODULE_DEVICE_TABLE(of, rcar_fcp_of_match); static struct platform_driver rcar_fcp_platform_driver = { .probe = rcar_fcp_probe, - .remove_new = rcar_fcp_remove, + .remove = rcar_fcp_remove, .driver = { .name = "rcar-fcp", .of_match_table = rcar_fcp_of_match, diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c index 4512ac338ca53b..c515278e3be540 100644 --- a/drivers/media/platform/renesas/rcar-isp.c +++ b/drivers/media/platform/renesas/rcar-isp.c @@ -431,7 +431,9 @@ static int risp_probe_resources(struct rcar_isp *isp, static const struct of_device_id risp_of_id_table[] = { { .compatible = "renesas,r8a779a0-isp" }, { .compatible = "renesas,r8a779g0-isp" }, - { /* sentinel */ }, + /* Keep above for compatibility with old DTB files. */ + { .compatible = "renesas,rcar-gen4-isp" }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, risp_of_id_table); @@ -522,7 +524,7 @@ static struct platform_driver rcar_isp_driver = { .of_match_table = risp_of_id_table, }, .probe = risp_probe, - .remove_new = risp_remove, + .remove = risp_remove, }; module_platform_driver(rcar_isp_driver); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index 695d884a22d1b9..ddfb18e6e7a400 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -1279,6 +1279,7 @@ static const struct rvin_info rcar_info_gen4 = { .use_mc = true, .use_isp = true, .nv12 = true, + .raw10 = true, .max_width = 4096, .max_height = 4096, }; @@ -1443,7 +1444,7 @@ static struct platform_driver rcar_vin_driver = { .of_match_table = rvin_of_id_table, }, .probe = rcar_vin_probe, - .remove_new = rcar_vin_remove, + .remove = rcar_vin_remove, }; module_platform_driver(rcar_vin_driver); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 21d5b2815e86a6..8773998101ffb5 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -123,7 +123,9 @@ /* Video n Data Mode Register bits */ #define VNDMR_A8BIT(n) (((n) & 0xff) << 24) #define VNDMR_A8BIT_MASK (0xff << 24) +#define VNDMR_RMODE_RAW10 (2 << 19) #define VNDMR_YMODE_Y8 (1 << 12) +#define VNDMR_YC_THR (1 << 11) #define VNDMR_EXRGB (1 << 8) #define VNDMR_BPSM (1 << 4) #define VNDMR_ABIT (1 << 2) @@ -790,6 +792,12 @@ static int rvin_setup(struct rvin_dev *vin) case MEDIA_BUS_FMT_Y8_1X8: vnmc |= VNMC_INF_RAW8; break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + vnmc |= VNMC_INF_RGB666; + break; default: break; } @@ -898,6 +906,12 @@ static int rvin_setup(struct rvin_dev *vin) dmr = 0; } break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + dmr = VNDMR_RMODE_RAW10 | VNDMR_YC_THR; + break; default: vin_err(vin, "Invalid pixelformat (0x%x)\n", vin->format.pixelformat); @@ -1280,6 +1294,22 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, if (vin->format.pixelformat != V4L2_PIX_FMT_GREY) return -EPIPE; break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR10) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SGBRG10_1X10: + if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG10) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SGRBG10_1X10: + if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG10) + return -EPIPE; + break; + case MEDIA_BUS_FMT_SRGGB10_1X10: + if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB10) + return -EPIPE; + break; default: return -EPIPE; } @@ -1529,8 +1559,6 @@ static const struct vb2_ops rvin_qops = { .buf_queue = rvin_buffer_queue, .start_streaming = rvin_start_streaming_vq, .stop_streaming = rvin_stop_streaming_vq, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; void rvin_dma_unregister(struct rvin_dev *vin) diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index bb4b07bed28dd3..756fdfdbce616c 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -86,6 +86,22 @@ static const struct rvin_video_format rvin_formats[] = { .fourcc = V4L2_PIX_FMT_GREY, .bpp = 1, }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .bpp = 4, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .bpp = 4, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .bpp = 4, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .bpp = 4, + }, }; const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, @@ -106,6 +122,13 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333)) return NULL; break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + if (!vin->info->raw10) + return NULL; + break; default: break; } @@ -407,6 +430,26 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; f->pixelformat = V4L2_PIX_FMT_SRGGB8; return 0; + case MEDIA_BUS_FMT_SBGGR10_1X10: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SBGGR10; + return 0; + case MEDIA_BUS_FMT_SGBRG10_1X10: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SGBRG10; + return 0; + case MEDIA_BUS_FMT_SGRBG10_1X10: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SGRBG10; + return 0; + case MEDIA_BUS_FMT_SRGGB10_1X10: + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_SRGGB10; + return 0; default: return -EINVAL; } diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h index 997a66318a2931..f87d4bc9e53ed3 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h @@ -151,7 +151,8 @@ struct rvin_group_route { * @model: VIN model * @use_mc: use media controller instead of controlling subdevice * @use_isp: the VIN is connected to the ISP and not to the CSI-2 - * @nv12: support outputing NV12 pixel format + * @nv12: support outputting NV12 pixel format + * @raw10: support outputting RAW10 pixel format * @max_width: max input width the VIN supports * @max_height: max input height the VIN supports * @routes: list of possible routes from the CSI-2 recivers to @@ -163,6 +164,7 @@ struct rvin_info { bool use_mc; bool use_isp; bool nv12; + bool raw10; unsigned int max_width; unsigned int max_height; diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index f21d0505434194..fc8b6bbef793c6 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -861,8 +861,6 @@ static const struct vb2_ops rcar_drif_vb2_ops = { .buf_queue = rcar_drif_buf_queue, .start_streaming = rcar_drif_start_streaming, .stop_streaming = rcar_drif_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int rcar_drif_querycap(struct file *file, void *fh, @@ -1071,7 +1069,6 @@ static int rcar_drif_sdr_register(struct rcar_drif_sdr *sdr) sdr->vdev->release = video_device_release; sdr->vdev->lock = &sdr->v4l2_mutex; sdr->vdev->queue = &sdr->vb_queue; - sdr->vdev->queue->lock = &sdr->vb_queue_mutex; sdr->vdev->ctrl_handler = &sdr->ctrl_hdl; sdr->vdev->v4l2_dev = &sdr->v4l2_dev; sdr->vdev->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER | @@ -1316,6 +1313,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr) sdr->vb_queue.ops = &rcar_drif_vb2_ops; sdr->vb_queue.mem_ops = &vb2_vmalloc_memops; sdr->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + sdr->vb_queue.lock = &sdr->vb_queue_mutex; /* Init videobuf2 queue */ ret = vb2_queue_init(&sdr->vb_queue); @@ -1475,7 +1473,7 @@ static struct platform_driver rcar_drif_driver = { .pm = &rcar_drif_pm_ops, }, .probe = rcar_drif_probe, - .remove_new = rcar_drif_remove, + .remove = rcar_drif_remove, }; module_platform_driver(rcar_drif_driver); diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c index a2565b269f3bd6..5d453a7a89889f 100644 --- a/drivers/media/platform/renesas/rcar_fdp1.c +++ b/drivers/media/platform/renesas/rcar_fdp1.c @@ -2032,8 +2032,6 @@ static const struct vb2_ops fdp1_qops = { .buf_queue = fdp1_buf_queue, .start_streaming = fdp1_start_streaming, .stop_streaming = fdp1_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -2444,7 +2442,7 @@ MODULE_DEVICE_TABLE(of, fdp1_dt_ids); static struct platform_driver fdp1_pdrv = { .probe = fdp1_probe, - .remove_new = fdp1_remove, + .remove = fdp1_remove, .driver = { .name = DRIVER_NAME, .of_match_table = fdp1_dt_ids, diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index e50fe7525a732b..81038df71bb5d9 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -1171,8 +1171,6 @@ static const struct vb2_ops jpu_qops = { .buf_finish = jpu_buf_finish, .start_streaming = jpu_start_streaming, .stop_streaming = jpu_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int jpu_queue_init(void *priv, struct vb2_queue *src_vq, @@ -1736,7 +1734,7 @@ static const struct dev_pm_ops jpu_pm_ops = { static struct platform_driver jpu_driver = { .probe = jpu_probe, - .remove_new = jpu_remove, + .remove = jpu_remove, .driver = { .of_match_table = jpu_dt_ids, .name = DRV_NAME, diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c index 16776027679653..8cceafe491b1be 100644 --- a/drivers/media/platform/renesas/renesas-ceu.c +++ b/drivers/media/platform/renesas/renesas-ceu.c @@ -761,8 +761,6 @@ static const struct vb2_ops ceu_vb2_ops = { .queue_setup = ceu_vb2_setup, .buf_queue = ceu_vb2_queue, .buf_prepare = ceu_vb2_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = ceu_start_streaming, .stop_streaming = ceu_stop_streaming, }; @@ -1723,7 +1721,7 @@ static struct platform_driver ceu_driver = { .of_match_table = of_match_ptr(ceu_of_match), }, .probe = ceu_probe, - .remove_new = ceu_remove, + .remove = ceu_remove, }; module_platform_driver(ceu_driver); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c index 280efd2a818559..89be584a498852 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c @@ -72,7 +72,6 @@ static int rzg2l_cru_group_notify_complete(struct v4l2_async_notifier *notifier) source->name, sink->name); return ret; } - cru->csi.channel = 0; cru->ip.remote = cru->csi.subdev; /* Create media device link between CRU IP <-> CRU OUTPUT */ @@ -209,7 +208,7 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru) const struct of_device_id *match; int ret; - cru->pad.flags = MEDIA_PAD_FL_SINK; + cru->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; ret = media_entity_pads_init(&cru->vdev.entity, 1, &cru->pad); if (ret) return ret; @@ -242,7 +241,7 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru) static int rzg2l_cru_probe(struct platform_device *pdev) { struct rzg2l_cru_dev *cru; - int ret; + int irq, ret; cru = devm_kzalloc(&pdev->dev, sizeof(*cru), GFP_KERNEL); if (!cru) @@ -270,9 +269,14 @@ static int rzg2l_cru_probe(struct platform_device *pdev) cru->dev = &pdev->dev; cru->info = of_device_get_match_data(&pdev->dev); - cru->image_conv_irq = platform_get_irq(pdev, 0); - if (cru->image_conv_irq < 0) - return cru->image_conv_irq; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, rzg2l_cru_irq, 0, + KBUILD_MODNAME, cru); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to request irq\n"); platform_set_drvdata(pdev, cru); @@ -325,7 +329,7 @@ static struct platform_driver rzg2l_cru_driver = { .of_match_table = rzg2l_cru_of_id_table, }, .probe = rzg2l_cru_probe, - .remove_new = rzg2l_cru_remove, + .remove = rzg2l_cru_remove, }; module_platform_driver(rzg2l_cru_driver); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h new file mode 100644 index 00000000000000..1c9f22118a5d90 --- /dev/null +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * rzg2l-cru-regs.h--RZ/G2L (and alike SoCs) CRU Registers Definitions + * + * Copyright (C) 2024 Renesas Electronics Corp. + */ + +#ifndef __RZG2L_CRU_REGS_H__ +#define __RZG2L_CRU_REGS_H__ + +/* HW CRU Registers Definition */ + +/* CRU Control Register */ +#define CRUnCTRL 0x0 +#define CRUnCTRL_VINSEL(x) ((x) << 0) + +/* CRU Interrupt Enable Register */ +#define CRUnIE 0x4 +#define CRUnIE_EFE BIT(17) + +/* CRU Interrupt Status Register */ +#define CRUnINTS 0x8 +#define CRUnINTS_SFS BIT(16) + +/* CRU Reset Register */ +#define CRUnRST 0xc +#define CRUnRST_VRESETN BIT(0) + +/* Memory Bank Base Address (Lower) Register for CRU Image Data */ +#define AMnMBxADDRL(x) (0x100 + ((x) * 8)) + +/* Memory Bank Base Address (Higher) Register for CRU Image Data */ +#define AMnMBxADDRH(x) (0x104 + ((x) * 8)) + +/* Memory Bank Enable Register for CRU Image Data */ +#define AMnMBVALID 0x148 +#define AMnMBVALID_MBVALID(x) GENMASK(x, 0) + +/* Memory Bank Status Register for CRU Image Data */ +#define AMnMBS 0x14c +#define AMnMBS_MBSTS 0x7 + +/* AXI Master Transfer Setting Register for CRU Image Data */ +#define AMnAXIATTR 0x158 +#define AMnAXIATTR_AXILEN_MASK GENMASK(3, 0) +#define AMnAXIATTR_AXILEN (0xf) + +/* AXI Master FIFO Pointer Register for CRU Image Data */ +#define AMnFIFOPNTR 0x168 +#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0) +#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16) + +/* AXI Master Transfer Stop Register for CRU Image Data */ +#define AMnAXISTP 0x174 +#define AMnAXISTP_AXI_STOP BIT(0) + +/* AXI Master Transfer Stop Status Register for CRU Image Data */ +#define AMnAXISTPACK 0x178 +#define AMnAXISTPACK_AXI_STOP_ACK BIT(0) + +/* CRU Image Processing Enable Register */ +#define ICnEN 0x200 +#define ICnEN_ICEN BIT(0) + +/* CRU Image Processing Main Control Register */ +#define ICnMC 0x208 +#define ICnMC_CSCTHR BIT(5) +#define ICnMC_INF(x) ((x) << 16) +#define ICnMC_VCSEL(x) ((x) << 22) +#define ICnMC_INF_MASK GENMASK(21, 16) + +/* CRU Module Status Register */ +#define ICnMS 0x254 +#define ICnMS_IA BIT(2) + +/* CRU Data Output Mode Register */ +#define ICnDMR 0x26c +#define ICnDMR_YCMODE_UYVY (1 << 4) + +#endif /* __RZG2L_CRU_REGS_H__ */ diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h index a5a99b004322bc..8b898ce05b8476 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h @@ -8,6 +8,7 @@ #ifndef __RZG2L_CRU__ #define __RZG2L_CRU__ +#include #include #include @@ -30,6 +31,11 @@ #define RZG2L_CRU_MIN_INPUT_HEIGHT 240 #define RZG2L_CRU_MAX_INPUT_HEIGHT 4095 +enum rzg2l_csi2_pads { + RZG2L_CRU_IP_SINK = 0, + RZG2L_CRU_IP_SOURCE, +}; + /** * enum rzg2l_cru_dma_state - DMA states * @RZG2L_CRU_DMA_STOPPED: No operation in progress @@ -47,7 +53,6 @@ enum rzg2l_cru_dma_state { struct rzg2l_cru_csi { struct v4l2_async_connection *asd; struct v4l2_subdev *subdev; - u32 channel; }; struct rzg2l_cru_ip { @@ -57,6 +62,24 @@ struct rzg2l_cru_ip { struct v4l2_subdev *remote; }; +/** + * struct rzg2l_cru_ip_format - CRU IP format + * @code: Media bus code + * @datatype: MIPI CSI2 data type + * @format: 4CC format identifier (V4L2_PIX_FMT_*) + * @icndmr: ICnDMR register value + * @bpp: bytes per pixel + * @yuv: Flag to indicate whether the format is YUV-based. + */ +struct rzg2l_cru_ip_format { + u32 code; + u32 datatype; + u32 format; + u32 icndmr; + u8 bpp; + bool yuv; +}; + /** * struct rzg2l_cru_dev - Renesas CRU device structure * @dev: (OF) device @@ -68,8 +91,6 @@ struct rzg2l_cru_ip { * * @vclk: CRU Main clock * - * @image_conv_irq: Holds image conversion interrupt number - * * @vdev: V4L2 video device associated with CRU * @v4l2_dev: V4L2 device * @num_buf: Holds the current number of buffers enabled @@ -105,8 +126,6 @@ struct rzg2l_cru_dev { struct clk *vclk; - int image_conv_irq; - struct video_device vdev; struct v4l2_device v4l2_dev; u8 num_buf; @@ -141,6 +160,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru); int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru); void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru); +irqreturn_t rzg2l_cru_irq(int irq, void *data); const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format); @@ -148,4 +168,8 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru); void rzg2l_cru_ip_subdev_unregister(struct rzg2l_cru_dev *cru); struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru); +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code); +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format); +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index); + #endif diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c index c7fdee347ac8ae..881e910dce0234 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c @@ -183,12 +183,15 @@ static const struct rzg2l_csi2_timings rzg2l_csi2_global_timings[] = { struct rzg2l_csi2_format { u32 code; - unsigned int datatype; unsigned int bpp; }; static const struct rzg2l_csi2_format rzg2l_csi2_formats[] = { - { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 }, + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16 }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, }; static inline struct rzg2l_csi2 *sd_to_csi2(struct v4l2_subdev *sd) @@ -574,6 +577,9 @@ static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd, if (fse->index != 0) return -EINVAL; + if (!rzg2l_csi2_code_to_fmt(fse->code)) + return -EINVAL; + fse->min_width = RZG2L_CSI2_MIN_WIDTH; fse->min_height = RZG2L_CSI2_MIN_HEIGHT; fse->max_width = RZG2L_CSI2_MAX_WIDTH; @@ -582,6 +588,25 @@ static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd, return 0; } +static int rzg2l_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct rzg2l_csi2 *csi2 = sd_to_csi2(sd); + struct media_pad *remote_pad; + + if (!csi2->remote_source) + return -ENODEV; + + remote_pad = media_pad_remote_pad_unique(&csi2->pads[RZG2L_CSI2_SINK]); + if (IS_ERR(remote_pad)) { + dev_err(csi2->dev, "can't get source pad of %s (%ld)\n", + csi2->remote_source->name, PTR_ERR(remote_pad)); + return PTR_ERR(remote_pad); + } + return v4l2_subdev_call(csi2->remote_source, pad, get_frame_desc, + remote_pad->index, fd); +} + static const struct v4l2_subdev_video_ops rzg2l_csi2_video_ops = { .s_stream = rzg2l_csi2_s_stream, .pre_streamon = rzg2l_csi2_pre_streamon, @@ -593,6 +618,7 @@ static const struct v4l2_subdev_pad_ops rzg2l_csi2_pad_ops = { .enum_frame_size = rzg2l_csi2_enum_frame_size, .set_fmt = rzg2l_csi2_set_format, .get_fmt = v4l2_subdev_get_fmt, + .get_frame_desc = rzg2l_csi2_get_frame_desc, }; static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = { @@ -795,14 +821,17 @@ static int rzg2l_csi2_probe(struct platform_device *pdev) csi2->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; csi2->subdev.entity.ops = &rzg2l_csi2_entity_ops; - csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; + csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; /* * TODO: RZ/G2L CSI2 supports 4 virtual channels, as virtual * channels should be implemented by streams API which is under * development lets hardcode to VC0 for now. */ - csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&csi2->subdev.entity, 2, csi2->pads); + csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; + ret = media_entity_pads_init(&csi2->subdev.entity, ARRAY_SIZE(csi2->pads), + csi2->pads); if (ret) goto error_pm; @@ -868,7 +897,7 @@ static const struct of_device_id rzg2l_csi2_of_table[] = { MODULE_DEVICE_TABLE(of, rzg2l_csi2_of_table); static struct platform_driver rzg2l_csi2_pdrv = { - .remove_new = rzg2l_csi2_remove, + .remove = rzg2l_csi2_remove, .probe = rzg2l_csi2_probe, .driver = { .name = "rzg2l-csi2", diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c index ac8ebae4ed079b..76a2b451f1daf0 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c @@ -6,24 +6,55 @@ */ #include -#include "rzg2l-cru.h" +#include -struct rzg2l_cru_ip_format { - u32 code; - unsigned int datatype; - unsigned int bpp; -}; +#include "rzg2l-cru.h" +#include "rzg2l-cru-regs.h" static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = { - { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 }, -}; - -enum rzg2l_csi2_pads { - RZG2L_CRU_IP_SINK = 0, - RZG2L_CRU_IP_SOURCE, + { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .format = V4L2_PIX_FMT_UYVY, + .bpp = 2, + .icndmr = ICnDMR_YCMODE_UYVY, + .yuv = true, + }, + { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .format = V4L2_PIX_FMT_SBGGR8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 1, + .icndmr = 0, + .yuv = false, + }, + { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .format = V4L2_PIX_FMT_SGBRG8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 1, + .icndmr = 0, + .yuv = false, + }, + { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .format = V4L2_PIX_FMT_SGRBG8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 1, + .icndmr = 0, + .yuv = false, + }, + { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .format = V4L2_PIX_FMT_SRGGB8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 1, + .icndmr = 0, + .yuv = false, + }, }; -static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code) +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code) { unsigned int i; @@ -34,6 +65,26 @@ static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int c return NULL; } +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) { + if (rzg2l_cru_ip_formats[i].format == format) + return &rzg2l_cru_ip_formats[i]; + } + + return NULL; +} + +const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index) +{ + if (index >= ARRAY_SIZE(rzg2l_cru_ip_formats)) + return NULL; + + return &rzg2l_cru_ip_formats[index]; +} + struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru) { struct v4l2_subdev_state *state; @@ -149,7 +200,7 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd, if (fse->index != 0) return -EINVAL; - if (fse->code != MEDIA_BUS_FMT_UYVY8_1X16) + if (!rzg2l_cru_ip_code_to_fmt(fse->code)) return -EINVAL; fse->min_width = RZG2L_CRU_MIN_INPUT_WIDTH; @@ -217,8 +268,10 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru) ip->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; ip->subdev.entity.ops = &rzg2l_cru_ip_entity_ops; - ip->pads[0].flags = MEDIA_PAD_FL_SINK; - ip->pads[1].flags = MEDIA_PAD_FL_SOURCE; + ip->pads[RZG2L_CRU_IP_SINK].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + ip->pads[RZG2L_CRU_IP_SOURCE].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; ret = media_entity_pads_init(&ip->subdev.entity, 2, ip->pads); if (ret) diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index b16b8af6e8f8cb..17a1af507a2708 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -15,75 +15,12 @@ #include #include +#include #include #include #include "rzg2l-cru.h" - -/* HW CRU Registers Definition */ - -/* CRU Control Register */ -#define CRUnCTRL 0x0 -#define CRUnCTRL_VINSEL(x) ((x) << 0) - -/* CRU Interrupt Enable Register */ -#define CRUnIE 0x4 -#define CRUnIE_EFE BIT(17) - -/* CRU Interrupt Status Register */ -#define CRUnINTS 0x8 -#define CRUnINTS_SFS BIT(16) - -/* CRU Reset Register */ -#define CRUnRST 0xc -#define CRUnRST_VRESETN BIT(0) - -/* Memory Bank Base Address (Lower) Register for CRU Image Data */ -#define AMnMBxADDRL(x) (0x100 + ((x) * 8)) - -/* Memory Bank Base Address (Higher) Register for CRU Image Data */ -#define AMnMBxADDRH(x) (0x104 + ((x) * 8)) - -/* Memory Bank Enable Register for CRU Image Data */ -#define AMnMBVALID 0x148 -#define AMnMBVALID_MBVALID(x) GENMASK(x, 0) - -/* Memory Bank Status Register for CRU Image Data */ -#define AMnMBS 0x14c -#define AMnMBS_MBSTS 0x7 - -/* AXI Master FIFO Pointer Register for CRU Image Data */ -#define AMnFIFOPNTR 0x168 -#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0) -#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16) - -/* AXI Master Transfer Stop Register for CRU Image Data */ -#define AMnAXISTP 0x174 -#define AMnAXISTP_AXI_STOP BIT(0) - -/* AXI Master Transfer Stop Status Register for CRU Image Data */ -#define AMnAXISTPACK 0x178 -#define AMnAXISTPACK_AXI_STOP_ACK BIT(0) - -/* CRU Image Processing Enable Register */ -#define ICnEN 0x200 -#define ICnEN_ICEN BIT(0) - -/* CRU Image Processing Main Control Register */ -#define ICnMC 0x208 -#define ICnMC_CSCTHR BIT(5) -#define ICnMC_INF_YUV8_422 (0x1e << 16) -#define ICnMC_INF_USER (0x30 << 16) -#define ICnMC_VCSEL(x) ((x) << 22) -#define ICnMC_INF_MASK GENMASK(21, 16) - -/* CRU Module Status Register */ -#define ICnMS 0x254 -#define ICnMS_IA BIT(2) - -/* CRU Data Output Mode Register */ -#define ICnDMR 0x26c -#define ICnDMR_YCMODE_UYVY (1 << 4) +#include "rzg2l-cru-regs.h" #define RZG2L_TIMEOUT_MS 100 #define RZG2L_RETRIES 10 @@ -184,46 +121,6 @@ static void rzg2l_cru_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&cru->qlock, flags); } -static int rzg2l_cru_mc_validate_format(struct rzg2l_cru_dev *cru, - struct v4l2_subdev *sd, - struct media_pad *pad) -{ - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - - fmt.pad = pad->index; - if (v4l2_subdev_call_state_active(sd, pad, get_fmt, &fmt)) - return -EPIPE; - - switch (fmt.format.code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - break; - default: - return -EPIPE; - } - - switch (fmt.format.field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_NONE: - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_SEQ_TB: - case V4L2_FIELD_SEQ_BT: - break; - default: - return -EPIPE; - } - - if (fmt.format.width != cru->format.width || - fmt.format.height != cru->format.height) - return -EPIPE; - - return 0; -} - static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru, int slot, dma_addr_t addr) { @@ -278,6 +175,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot) static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru) { unsigned int slot; + u32 amnaxiattr; /* * Set image data memory banks. @@ -287,55 +185,47 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru) for (slot = 0; slot < cru->num_buf; slot++) rzg2l_cru_fill_hw_slot(cru, slot); + + /* Set AXI burst max length to recommended setting */ + amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK; + amnaxiattr |= AMnAXIATTR_AXILEN; + rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr); } -static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, bool *input_is_yuv, - struct v4l2_mbus_framefmt *ip_sd_fmt) +static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, + const struct rzg2l_cru_ip_format *ip_fmt, + u8 csi_vc) { - u32 icnmc; - - switch (ip_sd_fmt->code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - icnmc = ICnMC_INF_YUV8_422; - *input_is_yuv = true; - break; - default: - *input_is_yuv = false; - icnmc = ICnMC_INF_USER; - break; - } + u32 icnmc = ICnMC_INF(ip_fmt->datatype); icnmc |= (rzg2l_cru_read(cru, ICnMC) & ~ICnMC_INF_MASK); /* Set virtual channel CSI2 */ - icnmc |= ICnMC_VCSEL(cru->csi.channel); + icnmc |= ICnMC_VCSEL(csi_vc); rzg2l_cru_write(cru, ICnMC, icnmc); } static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru, - struct v4l2_mbus_framefmt *ip_sd_fmt) + struct v4l2_mbus_framefmt *ip_sd_fmt, + u8 csi_vc) { - bool output_is_yuv = false; - bool input_is_yuv = false; - u32 icndmr; + const struct rzg2l_cru_ip_format *cru_video_fmt; + const struct rzg2l_cru_ip_format *cru_ip_fmt; - rzg2l_cru_csi2_setup(cru, &input_is_yuv, ip_sd_fmt); + cru_ip_fmt = rzg2l_cru_ip_code_to_fmt(ip_sd_fmt->code); + rzg2l_cru_csi2_setup(cru, cru_ip_fmt, csi_vc); /* Output format */ - switch (cru->format.pixelformat) { - case V4L2_PIX_FMT_UYVY: - icndmr = ICnDMR_YCMODE_UYVY; - output_is_yuv = true; - break; - default: + cru_video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat); + if (!cru_video_fmt) { dev_err(cru->dev, "Invalid pixelformat (0x%x)\n", cru->format.pixelformat); return -EINVAL; } /* If input and output use same colorspace, do bypass mode */ - if (output_is_yuv == input_is_yuv) + if (cru_ip_fmt->yuv == cru_video_fmt->yuv) rzg2l_cru_write(cru, ICnMC, rzg2l_cru_read(cru, ICnMC) | ICnMC_CSCTHR); else @@ -343,7 +233,7 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru, rzg2l_cru_read(cru, ICnMC) & (~ICnMC_CSCTHR)); /* Set output data format */ - rzg2l_cru_write(cru, ICnDMR, icndmr); + rzg2l_cru_write(cru, ICnDMR, cru_video_fmt->icndmr); return 0; } @@ -422,12 +312,47 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru) spin_unlock_irqrestore(&cru->qlock, flags); } +static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru) +{ + struct v4l2_mbus_frame_desc fd = { }; + struct media_pad *remote_pad; + int ret; + + remote_pad = media_pad_remote_pad_unique(&cru->ip.pads[RZG2L_CRU_IP_SINK]); + ret = v4l2_subdev_call(cru->ip.remote, pad, get_frame_desc, remote_pad->index, &fd); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_err(cru->dev, "get_frame_desc failed on IP remote subdev\n"); + return ret; + } + /* If remote subdev does not implement .get_frame_desc default to VC0. */ + if (ret == -ENOIOCTLCMD) + return 0; + + if (fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_err(cru->dev, "get_frame_desc returned invalid bus type %d\n", fd.type); + return -EINVAL; + } + + if (!fd.num_entries) { + dev_err(cru->dev, "get_frame_desc returned zero entries\n"); + return -EINVAL; + } + + return fd.entry[0].bus.csi2.vc; +} + int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru) { struct v4l2_mbus_framefmt *fmt = rzg2l_cru_ip_get_src_fmt(cru); unsigned long flags; + u8 csi_vc; int ret; + ret = rzg2l_cru_get_virtual_channel(cru); + if (ret < 0) + return ret; + csi_vc = ret; + spin_lock_irqsave(&cru->qlock, flags); /* Select a video input */ @@ -444,7 +369,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru) rzg2l_cru_initialize_axi(cru); /* Initialize image convert */ - ret = rzg2l_cru_initialize_image_conv(cru, fmt); + ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc); if (ret) { spin_unlock_irqrestore(&cru->qlock, flags); return ret; @@ -492,10 +417,6 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on) return stream_off_ret; } - ret = rzg2l_cru_mc_validate_format(cru, sd, pad); - if (ret) - return ret; - pipe = media_entity_pipeline(&sd->entity) ? : &cru->vdev.pipe; ret = video_device_pipeline_start(&cru->vdev, pipe); if (ret) @@ -527,7 +448,7 @@ static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru) rzg2l_cru_set_stream(cru, 0); } -static irqreturn_t rzg2l_cru_irq(int irq, void *data) +irqreturn_t rzg2l_cru_irq(int irq, void *data) { struct rzg2l_cru_dev *cru = data; unsigned int handled = 0; @@ -637,13 +558,6 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count goto assert_aresetn; } - ret = request_irq(cru->image_conv_irq, rzg2l_cru_irq, - IRQF_SHARED, KBUILD_MODNAME, cru); - if (ret) { - dev_err(cru->dev, "failed to request irq\n"); - goto assert_presetn; - } - /* Allocate scratch buffer. */ cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage, &cru->scratch_phys, GFP_KERNEL); @@ -651,7 +565,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count return_unused_buffers(cru, VB2_BUF_STATE_QUEUED); dev_err(cru->dev, "Failed to allocate scratch buffer\n"); ret = -ENOMEM; - goto free_image_conv_irq; + goto assert_presetn; } cru->sequence = 0; @@ -670,9 +584,6 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count if (ret) dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch, cru->scratch_phys); -free_image_conv_irq: - free_irq(cru->image_conv_irq, cru); - assert_presetn: reset_control_assert(cru->presetn); @@ -698,7 +609,6 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq) dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch, cru->scratch_phys); - free_irq(cru->image_conv_irq, cru); return_unused_buffers(cru, VB2_BUF_STATE_ERROR); reset_control_assert(cru->presetn); @@ -712,8 +622,6 @@ static const struct vb2_ops rzg2l_cru_qops = { .buf_queue = rzg2l_cru_buffer_queue, .start_streaming = rzg2l_cru_start_streaming_vq, .stop_streaming = rzg2l_cru_stop_streaming_vq, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru) @@ -775,46 +683,16 @@ int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru) * V4L2 stuff */ -static const struct v4l2_format_info rzg2l_cru_formats[] = { - { - .format = V4L2_PIX_FMT_UYVY, - .bpp[0] = 2, - }, -}; - -const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rzg2l_cru_formats); i++) - if (rzg2l_cru_formats[i].format == format) - return rzg2l_cru_formats + i; - - return NULL; -} - -static u32 rzg2l_cru_format_bytesperline(struct v4l2_pix_format *pix) -{ - const struct v4l2_format_info *fmt; - - fmt = rzg2l_cru_format_from_pixel(pix->pixelformat); - - if (WARN_ON(!fmt)) - return -EINVAL; - - return pix->width * fmt->bpp[0]; -} - -static u32 rzg2l_cru_format_sizeimage(struct v4l2_pix_format *pix) -{ - return pix->bytesperline * pix->height; -} - static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru, struct v4l2_pix_format *pix) { - if (!rzg2l_cru_format_from_pixel(pix->pixelformat)) + const struct rzg2l_cru_ip_format *fmt; + + fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat); + if (!fmt) { pix->pixelformat = RZG2L_CRU_DEFAULT_FORMAT; + fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat); + } switch (pix->field) { case V4L2_FIELD_TOP: @@ -833,8 +711,8 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru, v4l_bound_align_image(&pix->width, 320, RZG2L_CRU_MAX_INPUT_WIDTH, 1, &pix->height, 240, RZG2L_CRU_MAX_INPUT_HEIGHT, 2, 0); - pix->bytesperline = rzg2l_cru_format_bytesperline(pix); - pix->sizeimage = rzg2l_cru_format_sizeimage(pix); + pix->bytesperline = pix->width * fmt->bpp; + pix->sizeimage = pix->bytesperline * pix->height; dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n", pix->width, pix->height, pix->bytesperline, pix->sizeimage); @@ -905,10 +783,13 @@ static int rzg2l_cru_g_fmt_vid_cap(struct file *file, void *priv, static int rzg2l_cru_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index >= ARRAY_SIZE(rzg2l_cru_formats)) + const struct rzg2l_cru_ip_format *fmt; + + fmt = rzg2l_cru_ip_index_to_fmt(f->index); + if (!fmt) return -EINVAL; - f->pixelformat = rzg2l_cru_formats[f->index].format; + f->pixelformat = fmt->format; return 0; } @@ -984,6 +865,43 @@ static const struct v4l2_file_operations rzg2l_cru_fops = { .read = vb2_fop_read, }; +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +static int rzg2l_cru_video_link_validate(struct media_link *link) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + const struct rzg2l_cru_ip_format *video_fmt; + struct v4l2_subdev *subdev; + struct rzg2l_cru_dev *cru; + int ret; + + subdev = media_entity_to_v4l2_subdev(link->source->entity); + fmt.pad = link->source->index; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret < 0) + return ret == -ENOIOCTLCMD ? -EINVAL : ret; + + cru = container_of(media_entity_to_video_device(link->sink->entity), + struct rzg2l_cru_dev, vdev); + video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat); + + if (fmt.format.width != cru->format.width || + fmt.format.height != cru->format.height || + fmt.format.field != cru->format.field || + video_fmt->code != fmt.format.code) + return -EPIPE; + + return 0; +} + +static const struct media_entity_operations rzg2l_cru_video_media_ops = { + .link_validate = rzg2l_cru_video_link_validate, +}; + static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru) { struct video_device *vdev = &cru->vdev; @@ -995,6 +913,7 @@ static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru) vdev->lock = &cru->lock; vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; vdev->device_caps |= V4L2_CAP_IO_MC; + vdev->entity.ops = &rzg2l_cru_video_media_ops; vdev->fops = &rzg2l_cru_fops; vdev->ioctl_ops = &rzg2l_cru_ioctl_ops; diff --git a/drivers/media/platform/renesas/sh_vou.c b/drivers/media/platform/renesas/sh_vou.c index 1e74dd601c2b72..4ad7ae188d5b25 100644 --- a/drivers/media/platform/renesas/sh_vou.c +++ b/drivers/media/platform/renesas/sh_vou.c @@ -360,8 +360,6 @@ static const struct vb2_ops sh_vou_qops = { .buf_queue = sh_vou_buf_queue, .start_streaming = sh_vou_start_streaming, .stop_streaming = sh_vou_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* Video IOCTLs */ @@ -1359,7 +1357,7 @@ static void sh_vou_remove(struct platform_device *pdev) } static struct platform_driver sh_vou = { - .remove_new = sh_vou_remove, + .remove = sh_vou_remove, .driver = { .name = "sh-vou", }, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c index 1aac44d687316f..9fc6bf624a520a 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c @@ -1005,7 +1005,7 @@ MODULE_DEVICE_TABLE(of, vsp1_of_match); static struct platform_driver vsp1_platform_driver = { .probe = vsp1_probe, - .remove_new = vsp1_remove, + .remove = vsp1_remove, .driver = { .name = "vsp1", .pm = &vsp1_pm_ops, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c index 9c2d4c91bfadb8..c762202877babd 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c @@ -155,8 +155,6 @@ static const struct vb2_ops histo_video_queue_qops = { .queue_setup = histo_queue_setup, .buf_prepare = histo_buffer_prepare, .buf_queue = histo_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = histo_start_streaming, .stop_streaming = histo_stop_streaming, }; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index e728f9f5160e42..03f4efd6b82bd7 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -873,8 +873,6 @@ static const struct vb2_ops vsp1_video_queue_qops = { .queue_setup = vsp1_video_queue_setup, .buf_prepare = vsp1_video_buffer_prepare, .buf_queue = vsp1_video_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vsp1_video_start_streaming, .stop_streaming = vsp1_video_stop_streaming, }; diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index 70808049d2e810..8a48e9d91f96f1 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -218,8 +218,6 @@ const struct vb2_ops rga_qops = { .buf_prepare = rga_buf_prepare, .buf_queue = rga_buf_queue, .buf_cleanup = rga_buf_cleanup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = rga_buf_start_streaming, .stop_streaming = rga_buf_stop_streaming, }; diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 0e768f3e9edab4..1739ac0c8e9269 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -102,7 +102,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) src_vq->drv_priv = ctx; src_vq->ops = &rga_qops; src_vq->mem_ops = &vb2_dma_sg_memops; - dst_vq->gfp_flags = __GFP_DMA32; + src_vq->gfp_flags = __GFP_DMA32; src_vq->buf_struct_size = sizeof(struct rga_vb_buffer); src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->rga->mutex; @@ -972,7 +972,7 @@ MODULE_DEVICE_TABLE(of, rockchip_rga_match); static struct platform_driver rga_pdrv = { .probe = rga_probe, - .remove_new = rga_remove, + .remove = rga_remove, .driver = { .name = RGA_NAME, .pm = &rga_pm, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 2bddb4fa8a5cd1..02339cd94486ab 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -1203,8 +1203,6 @@ static const struct vb2_ops rkisp1_vb2_ops = { .buf_init = rkisp1_vb2_buf_init, .buf_queue = rkisp1_vb2_buf_queue, .buf_prepare = rkisp1_vb2_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = rkisp1_vb2_stop_streaming, .start_streaming = rkisp1_vb2_start_streaming, }; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index dd114ab77800f8..0100b9c3edbefb 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -752,7 +752,7 @@ static struct platform_driver rkisp1_drv = { .pm = &rkisp1_pm_ops, }, .probe = rkisp1_probe, - .remove_new = rkisp1_remove, + .remove = rkisp1_remove, }; module_platform_driver(rkisp1_drv); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 320581a9f866e9..b28f4140c8a309 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -2704,8 +2704,6 @@ static const struct vb2_ops rkisp1_params_vb2_ops = { .queue_setup = rkisp1_params_vb2_queue_setup, .buf_init = rkisp1_params_vb2_buf_init, .buf_cleanup = rkisp1_params_vb2_buf_cleanup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_queue = rkisp1_params_vb2_buf_queue, .buf_prepare = rkisp1_params_vb2_buf_prepare, .stop_streaming = rkisp1_params_vb2_stop_streaming, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index a502719e916a92..d5fdb8f82dc78b 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -150,8 +150,6 @@ static const struct vb2_ops rkisp1_stats_vb2_ops = { .queue_setup = rkisp1_stats_vb2_queue_setup, .buf_queue = rkisp1_stats_vb2_buf_queue, .buf_prepare = rkisp1_stats_vb2_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = rkisp1_stats_vb2_stop_streaming, }; diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c index f45f5c8612a6b3..a06d7cace92f48 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c @@ -1309,7 +1309,7 @@ static const struct dev_pm_ops gsc_pm_ops = { static struct platform_driver gsc_driver = { .probe = gsc_probe, - .remove_new = gsc_remove, + .remove = gsc_remove, .driver = { .name = GSC_MODULE_NAME, .pm = &gsc_pm_ops, diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index b7854ce5fb8e34..4bda1c369c44c4 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -276,8 +276,6 @@ static const struct vb2_ops gsc_m2m_qops = { .queue_setup = gsc_m2m_queue_setup, .buf_prepare = gsc_m2m_buf_prepare, .buf_queue = gsc_m2m_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = gsc_m2m_stop_streaming, .start_streaming = gsc_m2m_start_streaming, }; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index ffa4ea21387da3..c3c2e474a18a72 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -455,8 +455,6 @@ static const struct vb2_ops fimc_capture_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.c b/drivers/media/platform/samsung/exynos4-is/fimc-core.c index adfc2d73d04b7f..2c9edd0a559b85 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-core.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.c @@ -1157,7 +1157,7 @@ static const struct dev_pm_ops fimc_pm_ops = { static struct platform_driver fimc_driver = { .probe = fimc_probe, - .remove_new = fimc_remove, + .remove = fimc_remove, .driver = { .of_match_table = fimc_of_match, .name = FIMC_DRIVER_NAME, diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c index 44363c4241d536..b243cbb1d01003 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c @@ -137,7 +137,7 @@ static const struct of_device_id fimc_is_i2c_of_match[] = { static struct platform_driver fimc_is_i2c_driver = { .probe = fimc_is_i2c_probe, - .remove_new = fimc_is_i2c_remove, + .remove = fimc_is_i2c_remove, .driver = { .of_match_table = fimc_is_i2c_of_match, .name = "fimc-isp-i2c", diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index 0a4b58daf9249f..2e8fe9e497350b 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -963,7 +963,7 @@ static const struct dev_pm_ops fimc_is_pm_ops = { static struct platform_driver fimc_is_driver = { .probe = fimc_is_probe, - .remove_new = fimc_is_remove, + .remove = fimc_is_remove, .driver = { .of_match_table = fimc_is_of_match, .name = FIMC_IS_DRV_NAME, diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c index 06c4352562b38f..ad219ac1b95137 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c @@ -255,8 +255,6 @@ static const struct vb2_ops isp_video_capture_qops = { .queue_setup = isp_video_capture_queue_setup, .buf_prepare = isp_video_capture_buffer_prepare, .buf_queue = isp_video_capture_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = isp_video_capture_start_streaming, .stop_streaming = isp_video_capture_stop_streaming, }; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 1a4d754432154c..f23e51e3da2fe5 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -441,8 +441,6 @@ static const struct vb2_ops fimc_lite_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; @@ -1654,7 +1652,7 @@ MODULE_DEVICE_TABLE(of, flite_of_match); static struct platform_driver fimc_lite_driver = { .probe = fimc_lite_probe, - .remove_new = fimc_lite_remove, + .remove = fimc_lite_remove, .driver = { .of_match_table = flite_of_match, .name = FIMC_LITE_DRV_NAME, diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c index 199997eec1cc25..951433c8e92a5b 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c @@ -216,8 +216,6 @@ static const struct vb2_ops fimc_qops = { .queue_setup = fimc_queue_setup, .buf_prepare = fimc_buf_prepare, .buf_queue = fimc_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = stop_streaming, .start_streaming = start_streaming, }; diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c index 5f10bb4eb4f7c9..b5ee3c54778938 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.c +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c @@ -1564,7 +1564,7 @@ MODULE_DEVICE_TABLE(of, fimc_md_of_match); static struct platform_driver fimc_md_driver = { .probe = fimc_md_probe, - .remove_new = fimc_md_remove, + .remove = fimc_md_remove, .driver = { .of_match_table = of_match_ptr(fimc_md_of_match), .name = "s5p-fimc-md", diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.h b/drivers/media/platform/samsung/exynos4-is/media-dev.h index 786264cf79dc14..a50e58ab7ef773 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.h +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.h @@ -178,8 +178,9 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); #ifdef CONFIG_OF static inline bool fimc_md_is_isp_available(struct device_node *node) { - node = of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME); - return node ? of_device_is_available(node) : false; + struct device_node *child __free(device_node) = + of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME); + return child ? of_device_is_available(child) : false; } #else #define fimc_md_is_isp_available(node) (false) diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c index 4b9b20ba35041c..63f3eecdd7e699 100644 --- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c @@ -1020,7 +1020,7 @@ MODULE_DEVICE_TABLE(of, s5pcsis_of_match); static struct platform_driver s5pcsis_driver = { .probe = s5pcsis_probe, - .remove_new = s5pcsis_remove, + .remove = s5pcsis_remove, .driver = { .of_match_table = s5pcsis_of_match, .name = CSIS_DRIVER_NAME, diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index be58260ea67e79..bd1149e8abc2d2 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -525,8 +525,6 @@ static const struct vb2_ops s3c_camif_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; diff --git a/drivers/media/platform/samsung/s3c-camif/camif-core.c b/drivers/media/platform/samsung/s3c-camif/camif-core.c index e4529f666e2060..de6e8f1518496a 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-core.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-core.c @@ -622,7 +622,7 @@ static const struct dev_pm_ops s3c_camif_pm_ops = { static struct platform_driver s3c_camif_driver = { .probe = s3c_camif_probe, - .remove_new = s3c_camif_remove, + .remove = s3c_camif_remove, .id_table = s3c_camif_driver_ids, .driver = { .name = S3C_CAMIF_DRIVER_NAME, diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c index 89aeba47ed079e..ffed16a34493be 100644 --- a/drivers/media/platform/samsung/s5p-g2d/g2d.c +++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c @@ -133,8 +133,6 @@ static const struct vb2_ops g2d_qops = { .queue_setup = g2d_queue_setup, .buf_prepare = g2d_buf_prepare, .buf_queue = g2d_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -777,7 +775,7 @@ MODULE_DEVICE_TABLE(of, exynos_g2d_match); static struct platform_driver g2d_pdrv = { .probe = g2d_probe, - .remove_new = g2d_remove, + .remove = g2d_remove, .driver = { .name = G2D_NAME, .of_match_table = exynos_g2d_match, diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index 1db4609b35574f..ac4cf269456a93 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -2595,8 +2595,6 @@ static const struct vb2_ops s5p_jpeg_qops = { .queue_setup = s5p_jpeg_queue_setup, .buf_prepare = s5p_jpeg_buf_prepare, .buf_queue = s5p_jpeg_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = s5p_jpeg_start_streaming, .stop_streaming = s5p_jpeg_stop_streaming, }; @@ -3165,7 +3163,7 @@ static void *jpeg_get_drv_data(struct device *dev) static struct platform_driver s5p_jpeg_driver = { .probe = s5p_jpeg_probe, - .remove_new = s5p_jpeg_remove, + .remove = s5p_jpeg_remove, .driver = { .of_match_table = samsung_jpeg_match, .name = S5P_JPEG_M2M_NAME, diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c index 637a5104d94897..6657d294c10aa5 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c @@ -427,11 +427,6 @@ void exynos3250_jpeg_clear_int_status(void __iomem *regs, writel(value, regs + EXYNOS3250_JPGINTST); } -unsigned int exynos3250_jpeg_operating(void __iomem *regs) -{ - return readl(regs + S5P_JPGOPR) & EXYNOS3250_JPGOPR_MASK; -} - unsigned int exynos3250_jpeg_compressed_size(void __iomem *regs) { return readl(regs + EXYNOS3250_JPGCNT) & EXYNOS3250_JPGCNT_MASK; diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h index 15af928fad764c..709c61ae322ca9 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h @@ -45,7 +45,6 @@ void exynos3250_jpeg_rstart(void __iomem *regs); unsigned int exynos3250_jpeg_get_int_status(void __iomem *regs); void exynos3250_jpeg_clear_int_status(void __iomem *regs, unsigned int value); -unsigned int exynos3250_jpeg_operating(void __iomem *regs); unsigned int exynos3250_jpeg_compressed_size(void __iomem *regs); void exynos3250_jpeg_dec_stream_size(void __iomem *regs, unsigned int size); void exynos3250_jpeg_dec_scaling_ratio(void __iomem *regs, unsigned int sratio); diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c index 0828cfa783feda..479288fc8c776f 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c @@ -185,11 +185,6 @@ unsigned int exynos4_jpeg_get_int_status(void __iomem *base) return readl(base + EXYNOS4_INT_STATUS_REG); } -unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base) -{ - return readl(base + EXYNOS4_FIFO_STATUS_REG); -} - void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value) { unsigned int reg; @@ -300,22 +295,8 @@ void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size) writel(size, base + EXYNOS4_BITSTREAM_SIZE_REG); } -void exynos4_jpeg_get_frame_size(void __iomem *base, - unsigned int *width, unsigned int *height) -{ - *width = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) & - EXYNOS4_DECODED_SIZE_MASK); - *height = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) >> 16) & - EXYNOS4_DECODED_SIZE_MASK; -} - unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base) { return readl(base + EXYNOS4_DECODE_IMG_FMT_REG) & EXYNOS4_JPEG_DECODED_IMG_FMT_MASK; } - -void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size) -{ - writel(size, base + EXYNOS4_INT_TIMER_COUNT_REG); -} diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h index 3e28875269605b..b941cc89e4ba16 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h @@ -35,10 +35,6 @@ void exynos4_jpeg_select_dec_h_tbl(void __iomem *base, char c, char x); void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt); void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size); unsigned int exynos4_jpeg_get_stream_size(void __iomem *base); -void exynos4_jpeg_get_frame_size(void __iomem *base, - unsigned int *width, unsigned int *height); unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base); -unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base); -void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size); #endif /* JPEG_HW_EXYNOS4_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index 50451984d59f75..2fe3c9228ac54c 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -1721,7 +1721,7 @@ MODULE_DEVICE_TABLE(of, exynos_mfc_match); static struct platform_driver s5p_mfc_driver = { .probe = s5p_mfc_probe, - .remove_new = s5p_mfc_remove, + .remove = s5p_mfc_remove, .driver = { .name = S5P_MFC_NAME, .pm = &s5p_mfc_pm_ops, diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c index 91e102d4ec4e2a..3efbc336790629 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -1161,8 +1161,6 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops s5p_mfc_dec_qops = { .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_init = s5p_mfc_buf_init, .start_streaming = s5p_mfc_start_streaming, .stop_streaming = s5p_mfc_stop_streaming, diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index 81cbb36fb382c0..6c603dcd56649f 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -2652,8 +2652,6 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) static const struct vb2_ops s5p_mfc_enc_qops = { .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_init = s5p_mfc_buf_init, .buf_prepare = s5p_mfc_buf_prepare, .start_streaming = s5p_mfc_start_streaming, diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index c7ee6e1a445146..73ad66ed20f2e3 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -531,8 +531,6 @@ static const struct vb2_ops bdisp_qops = { .queue_setup = bdisp_queue_setup, .buf_prepare = bdisp_buf_prepare, .buf_queue = bdisp_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = bdisp_stop_streaming, .start_streaming = bdisp_start_streaming, }; @@ -1411,7 +1409,7 @@ MODULE_DEVICE_TABLE(of, bdisp_match_types); static struct platform_driver bdisp_driver = { .probe = bdisp_probe, - .remove_new = bdisp_remove, + .remove = bdisp_remove, .driver = { .name = BDISP_NAME, .of_match_table = bdisp_match_types, diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c index 67d3d6e50d2e2b..7b3a37957e3ae8 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c @@ -1158,7 +1158,7 @@ static struct platform_driver c8sectpfe_driver = { .of_match_table = c8sectpfe_match, }, .probe = c8sectpfe_probe, - .remove_new = c8sectpfe_remove, + .remove = c8sectpfe_remove, }; module_platform_driver(c8sectpfe_driver); diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index da402d1e9171a0..196e6a40335d14 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -1559,8 +1559,6 @@ static const struct vb2_ops delta_vb2_au_ops = { .queue_setup = delta_vb2_au_queue_setup, .buf_prepare = delta_vb2_au_prepare, .buf_queue = delta_vb2_au_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = delta_vb2_au_start_streaming, .stop_streaming = delta_vb2_au_stop_streaming, }; @@ -1570,8 +1568,6 @@ static const struct vb2_ops delta_vb2_frame_ops = { .buf_prepare = delta_vb2_frame_prepare, .buf_finish = delta_vb2_frame_finish, .buf_queue = delta_vb2_frame_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = delta_vb2_frame_stop_streaming, }; @@ -1954,7 +1950,7 @@ MODULE_DEVICE_TABLE(of, delta_match_types); static struct platform_driver delta_driver = { .probe = delta_probe, - .remove_new = delta_remove, + .remove = delta_remove, .driver = { .name = DELTA_NAME, .of_match_table = delta_match_types, diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c index 161a5c0fbc4e34..5366c0f92549bb 100644 --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c @@ -1114,8 +1114,6 @@ static const struct vb2_ops hva_qops = { .buf_queue = hva_buf_queue, .start_streaming = hva_start_streaming, .stop_streaming = hva_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* @@ -1456,7 +1454,7 @@ MODULE_DEVICE_TABLE(of, hva_match_types); static struct platform_driver hva_driver = { .probe = hva_probe, - .remove_new = hva_remove, + .remove = hva_remove, .driver = { .name = HVA_NAME, .of_match_table = hva_match_types, diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c index 92f1edee58f899..b6c8400fb92da9 100644 --- a/drivers/media/platform/st/stm32/dma2d/dma2d.c +++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c @@ -186,8 +186,6 @@ static const struct vb2_ops dma2d_qops = { .buf_queue = dma2d_buf_queue, .start_streaming = dma2d_start_streaming, .stop_streaming = dma2d_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -717,7 +715,7 @@ MODULE_DEVICE_TABLE(of, stm32_dma2d_match); static struct platform_driver dma2d_pdrv = { .probe = dma2d_probe, - .remove_new = dma2d_remove, + .remove = dma2d_remove, .driver = { .name = DMA2D_NAME, .of_match_table = stm32_dma2d_match, diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index ff3331af940689..9b699ee2b1e061 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -898,8 +898,6 @@ static const struct vb2_ops dcmi_video_qops = { .buf_queue = dcmi_buf_queue, .start_streaming = dcmi_start_streaming, .stop_streaming = dcmi_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int dcmi_g_fmt_vid_cap(struct file *file, void *priv, @@ -2149,7 +2147,7 @@ static const struct dev_pm_ops dcmi_pm_ops = { static struct platform_driver stm32_dcmi_driver = { .probe = dcmi_probe, - .remove_new = dcmi_remove, + .remove = dcmi_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(stm32_dcmi_of_match), diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c index 9f768f011fa25a..7edd49bfe7e5b8 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c @@ -625,12 +625,6 @@ static const struct vb2_ops dcmipp_bytecap_qops = { .buf_prepare = dcmipp_bytecap_buf_prepare, .buf_queue = dcmipp_bytecap_buf_queue, .queue_setup = dcmipp_bytecap_queue_setup, - /* - * Since q->lock is set we can use the standard - * vb2_ops_wait_prepare/finish helper functions. - */ - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static void dcmipp_bytecap_release(struct video_device *vdev) diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c index 7f771ea49b7848..3806f7c6e2fe22 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c @@ -583,7 +583,7 @@ static const struct dev_pm_ops dcmipp_pm_ops = { static struct platform_driver dcmipp_pdrv = { .probe = dcmipp_probe, - .remove_new = dcmipp_remove, + .remove = dcmipp_remove, .driver = { .name = DCMIPP_PDEV_NAME, .of_match_table = dcmipp_of_match, diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index d07e980aba61c8..e53a07b770b7e8 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -340,7 +340,7 @@ static const struct dev_pm_ops sun4i_csi_pm_ops = { static struct platform_driver sun4i_csi_driver = { .probe = sun4i_csi_probe, - .remove_new = sun4i_csi_remove, + .remove = sun4i_csi_remove, .driver = { .name = "sun4i-csi", .of_match_table = sun4i_csi_of_match, diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index d1371e13011374..e911c7f7acc524 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -371,8 +371,6 @@ static const struct vb2_ops sun4i_csi_qops = { .buf_queue = sun4i_csi_buffer_queue, .start_streaming = sun4i_csi_start_streaming, .stop_streaming = sun4i_csi_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static irqreturn_t sun4i_csi_irq(int irq, void *data) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index c6ba385c0c8615..af2a32c226a55c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -423,7 +423,7 @@ MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); static struct platform_driver sun6i_csi_platform_driver = { .probe = sun6i_csi_probe, - .remove_new = sun6i_csi_remove, + .remove = sun6i_csi_remove, .driver = { .name = SUN6I_CSI_NAME, .of_match_table = sun6i_csi_of_match, diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 14c0dc827c5200..76356bc7f10e39 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -657,8 +657,6 @@ static const struct vb2_ops sun6i_csi_capture_queue_ops = { .buf_queue = sun6i_csi_capture_buffer_queue, .start_streaming = sun6i_csi_capture_start_streaming, .stop_streaming = sun6i_csi_capture_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* V4L2 Device */ diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c index f9d4dc45b49077..b06cb73015cdd1 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -757,7 +757,7 @@ MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match); static struct platform_driver sun6i_mipi_csi2_platform_driver = { .probe = sun6i_mipi_csi2_probe, - .remove_new = sun6i_mipi_csi2_remove, + .remove = sun6i_mipi_csi2_remove, .driver = { .name = SUN6I_MIPI_CSI2_NAME, .of_match_table = sun6i_mipi_csi2_of_match, diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c index 4a5698eb12b77c..dbc51daa4fe378 100644 --- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -824,7 +824,7 @@ MODULE_DEVICE_TABLE(of, sun8i_a83t_mipi_csi2_of_match); static struct platform_driver sun8i_a83t_mipi_csi2_platform_driver = { .probe = sun8i_a83t_mipi_csi2_probe, - .remove_new = sun8i_a83t_mipi_csi2_remove, + .remove = sun8i_a83t_mipi_csi2_remove, .driver = { .name = SUN8I_A83T_MIPI_CSI2_NAME, .of_match_table = sun8i_a83t_mipi_csi2_of_match, diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index a1c35a2b68ed90..3e7f2df70408b8 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -659,8 +659,6 @@ static const struct vb2_ops deinterlace_qops = { .buf_queue = deinterlace_buf_queue, .start_streaming = deinterlace_start_streaming, .stop_streaming = deinterlace_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int deinterlace_queue_init(void *priv, struct vb2_queue *src_vq, @@ -1001,7 +999,7 @@ static const struct dev_pm_ops deinterlace_pm_ops = { static struct platform_driver deinterlace_driver = { .probe = deinterlace_probe, - .remove_new = deinterlace_remove, + .remove = deinterlace_remove, .driver = { .name = DEINTERLACE_NAME, .of_match_table = deinterlace_dt_match, diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index a12323ca89faeb..abd10b218aa1dc 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -522,8 +522,6 @@ static const struct vb2_ops rotate_qops = { .buf_queue = rotate_buf_queue, .start_streaming = rotate_start_streaming, .stop_streaming = rotate_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int rotate_queue_init(void *priv, struct vb2_queue *src_vq, @@ -905,7 +903,7 @@ static const struct dev_pm_ops rotate_pm_ops = { static struct platform_driver rotate_driver = { .probe = rotate_probe, - .remove_new = rotate_remove, + .remove = rotate_remove, .driver = { .name = ROTATE_NAME, .of_match_table = rotate_dt_match, diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c index 009ff68a2b43ca..44cdccb8937752 100644 --- a/drivers/media/platform/ti/am437x/am437x-vpfe.c +++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c @@ -2079,8 +2079,6 @@ static long vpfe_ioctl_default(struct file *file, void *priv, } static const struct vb2_ops vpfe_video_qops = { - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .queue_setup = vpfe_queue_setup, .buf_prepare = vpfe_buffer_prepare, .buf_queue = vpfe_buffer_queue, @@ -2617,7 +2615,7 @@ MODULE_DEVICE_TABLE(of, vpfe_of_match); static struct platform_driver vpfe_driver = { .probe = vpfe_probe, - .remove_new = vpfe_remove, + .remove = vpfe_remove, .driver = { .name = VPFE_MODULE_NAME, .pm = &vpfe_pm_ops, diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index e1ba5dfc217e3a..e29743ae61e27e 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -808,8 +808,6 @@ static const struct vb2_ops cal_video_qops = { .buf_queue = cal_buffer_queue, .start_streaming = cal_start_streaming, .stop_streaming = cal_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c index 5c2c04142aeed2..4bd2092e0255f7 100644 --- a/drivers/media/platform/ti/cal/cal.c +++ b/drivers/media/platform/ti/cal/cal.c @@ -1332,7 +1332,7 @@ static const struct dev_pm_ops cal_pm_ops = { static struct platform_driver cal_pdrv = { .probe = cal_probe, - .remove_new = cal_remove, + .remove = cal_remove, .driver = { .name = CAL_MODULE_NAME, .pm = &cal_pm_ops, diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c index f4e1fa76bf3724..a81719702a22d1 100644 --- a/drivers/media/platform/ti/davinci/vpif.c +++ b/drivers/media/platform/ti/davinci/vpif.c @@ -589,7 +589,7 @@ static struct platform_driver vpif_driver = { .name = VPIF_DRIVER_NAME, .pm = vpif_pm_ops, }, - .remove_new = vpif_remove, + .remove = vpif_remove, .probe = vpif_probe, }; diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index 16326437767f80..d053972888d1b4 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -310,8 +310,6 @@ static const struct vb2_ops video_qops = { .start_streaming = vpif_start_streaming, .stop_streaming = vpif_stop_streaming, .buf_queue = vpif_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /** @@ -1815,7 +1813,7 @@ static __refdata struct platform_driver vpif_driver = { .pm = &vpif_pm_ops, }, .probe = vpif_probe, - .remove_new = vpif_remove, + .remove = vpif_remove, }; module_platform_driver(vpif_driver); diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index 76d8fa8ad088a1..70c89549f4b61d 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -293,8 +293,6 @@ static void vpif_stop_streaming(struct vb2_queue *vq) static const struct vb2_ops video_qops = { .queue_setup = vpif_buffer_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = vpif_buffer_prepare, .start_streaming = vpif_start_streaming, .stop_streaming = vpif_stop_streaming, @@ -1398,7 +1396,7 @@ static __refdata struct platform_driver vpif_driver = { .pm = &vpif_pm_ops, }, .probe = vpif_probe, - .remove_new = vpif_remove, + .remove = vpif_remove, }; module_platform_driver(vpif_driver); diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 22442fce760785..6412a00be8eab8 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -878,8 +878,6 @@ static const struct vb2_ops csi_vb2_qops = { .buf_queue = ti_csi2rx_buffer_queue, .start_streaming = ti_csi2rx_start_streaming, .stop_streaming = ti_csi2rx_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi) @@ -1014,9 +1012,9 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi) pix_fmt->height = 480; pix_fmt->field = V4L2_FIELD_NONE; pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; - pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601, - pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE, - pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB, + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; ti_csi2rx_fill_fmt(fmt, &csi->v_fmt); @@ -1163,7 +1161,7 @@ MODULE_DEVICE_TABLE(of, ti_csi2rx_of_match); static struct platform_driver ti_csi2rx_pdrv = { .probe = ti_csi2rx_probe, - .remove_new = ti_csi2rx_remove, + .remove = ti_csi2rx_remove, .driver = { .name = TI_CSI2RX_MODULE_NAME, .of_match_table = ti_csi2rx_of_match, diff --git a/drivers/media/platform/ti/omap/omap_vout.c b/drivers/media/platform/ti/omap/omap_vout.c index 1c56b6a87ced4e..a87d5030ac35ce 100644 --- a/drivers/media/platform/ti/omap/omap_vout.c +++ b/drivers/media/platform/ti/omap/omap_vout.c @@ -1300,8 +1300,6 @@ static const struct vb2_ops omap_vout_vb2_ops = { .buf_prepare = omap_vout_vb2_prepare, .start_streaming = omap_vout_vb2_start_streaming, .stop_streaming = omap_vout_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* Init functions used during driver initialization */ @@ -1721,7 +1719,7 @@ static struct platform_driver omap_vout_driver = { .driver = { .name = VOUT_NAME, }, - .remove_new = omap_vout_remove, + .remove = omap_vout_remove, }; static int __init omap_vout_init(void) diff --git a/drivers/media/platform/ti/omap/omap_voutdef.h b/drivers/media/platform/ti/omap/omap_voutdef.h index b586193341d2d3..159e5e670d9164 100644 --- a/drivers/media/platform/ti/omap/omap_voutdef.h +++ b/drivers/media/platform/ti/omap/omap_voutdef.h @@ -48,7 +48,7 @@ #define VRFB_TX_TIMEOUT 1000 #define VRFB_NUM_BUFS 4 -/* Max buffer size tobe allocated during init */ +/* Max buffer size to be allocated during init */ #define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4) enum dma_channel_state { diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index 91101ba88ef01f..405ca215179dd3 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -2472,7 +2472,7 @@ MODULE_DEVICE_TABLE(of, omap3isp_of_table); static struct platform_driver omap3isp_driver = { .probe = isp_probe, - .remove_new = isp_remove, + .remove = isp_remove, .id_table = omap3isp_id_table, .driver = { .name = "omap3isp", diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index daca689dc08254..5c9aa80023fd66 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -480,11 +480,29 @@ static int isp_video_start_streaming(struct vb2_queue *queue, return 0; } +static void omap3isp_wait_prepare(struct vb2_queue *vq) +{ + struct isp_video_fh *vfh = vb2_get_drv_priv(vq); + struct isp_video *video = vfh->video; + + mutex_unlock(&video->queue_lock); +} + +static void omap3isp_wait_finish(struct vb2_queue *vq) +{ + struct isp_video_fh *vfh = vb2_get_drv_priv(vq); + struct isp_video *video = vfh->video; + + mutex_lock(&video->queue_lock); +} + static const struct vb2_ops isp_video_queue_ops = { .queue_setup = isp_video_queue_setup, .buf_prepare = isp_video_buffer_prepare, .buf_queue = isp_video_buffer_queue, .start_streaming = isp_video_start_streaming, + .wait_prepare = omap3isp_wait_prepare, + .wait_finish = omap3isp_wait_finish, }; /* diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c index 6848cbc82f5288..636d76ecebcd7e 100644 --- a/drivers/media/platform/ti/vpe/vpe.c +++ b/drivers/media/platform/ti/vpe/vpe.c @@ -2210,8 +2210,6 @@ static const struct vb2_ops vpe_qops = { .queue_setup = vpe_queue_setup, .buf_prepare = vpe_buf_prepare, .buf_queue = vpe_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = vpe_start_streaming, .stop_streaming = vpe_stop_streaming, }; @@ -2649,7 +2647,7 @@ MODULE_DEVICE_TABLE(of, vpe_of_match); static struct platform_driver vpe_pdrv = { .probe = vpe_probe, - .remove_new = vpe_remove, + .remove = vpe_remove, .driver = { .name = VPE_MODULE_NAME, .of_match_table = of_match_ptr(vpe_of_match), diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 05bbac853c4fd7..8542238e0fb1d2 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -1277,7 +1277,7 @@ static const struct dev_pm_ops hantro_pm_ops = { static struct platform_driver hantro_driver = { .probe = hantro_probe, - .remove_new = hantro_remove, + .remove = hantro_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_hantro_match, diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 62d3962c18d992..2513adfbd82595 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -201,7 +201,15 @@ static int vidioc_enum_fmt(struct file *file, void *priv, struct hantro_ctx *ctx = fh_to_ctx(priv); const struct hantro_fmt *fmt, *formats; unsigned int num_fmts, i, j = 0; - bool skip_mode_none; + bool skip_mode_none, enum_all_formats; + u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL; + + /* + * If the V4L2_FMTDESC_FLAG_ENUM_ALL flag is set, we want to enumerate all + * hardware supported pixel formats + */ + enum_all_formats = !!(f->index & V4L2_FMTDESC_FLAG_ENUM_ALL); + f->index = index; /* * When dealing with an encoder: @@ -222,9 +230,9 @@ static int vidioc_enum_fmt(struct file *file, void *priv, if (skip_mode_none == mode_none) continue; - if (!hantro_check_depth_match(fmt, ctx->bit_depth)) + if (!hantro_check_depth_match(fmt, ctx->bit_depth) && !enum_all_formats) continue; - if (j == f->index) { + if (j == index) { f->pixelformat = fmt->fourcc; return 0; } @@ -242,9 +250,9 @@ static int vidioc_enum_fmt(struct file *file, void *priv, for (i = 0; i < num_fmts; i++) { fmt = &formats[i]; - if (!hantro_check_depth_match(fmt, ctx->bit_depth)) + if (!hantro_check_depth_match(fmt, ctx->bit_depth) && !enum_all_formats) continue; - if (j == f->index) { + if (j == index) { f->pixelformat = fmt->fourcc; return 0; } @@ -996,6 +1004,4 @@ const struct vb2_ops hantro_queue_ops = { .buf_request_complete = hantro_buf_request_complete, .start_streaming = hantro_start_streaming, .stop_streaming = hantro_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c index 65e8f2d074005c..e54f5fac325bd6 100644 --- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c @@ -161,8 +161,7 @@ static int rockchip_vpu981_av1_dec_frame_ref(struct hantro_ctx *ctx, av1_dec->frame_refs[i].timestamp = timestamp; av1_dec->frame_refs[i].frame_type = frame->frame_type; av1_dec->frame_refs[i].order_hint = frame->order_hint; - if (!av1_dec->frame_refs[i].vb2_ref) - av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx); + av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx); for (j = 0; j < V4L2_AV1_TOTAL_REFS_PER_FRAME; j++) av1_dec->frame_refs[i].order_hints[j] = frame->order_hints[j]; diff --git a/drivers/media/platform/via/via-camera.c b/drivers/media/platform/via/via-camera.c index 4cb8f29e2f14aa..5702eff664d4ef 100644 --- a/drivers/media/platform/via/via-camera.c +++ b/drivers/media/platform/via/via-camera.c @@ -666,8 +666,6 @@ static const struct vb2_ops viacam_vb2_ops = { .buf_prepare = viacam_vb2_prepare, .start_streaming = viacam_vb2_start_streaming, .stop_streaming = viacam_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* --------------------------------------------------------------------------*/ @@ -1307,7 +1305,7 @@ static struct platform_driver viacam_driver = { .name = "viafb-camera", }, .probe = viacam_probe, - .remove_new = viacam_remove, + .remove = viacam_remove, }; module_platform_driver(viacam_driver); diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index 31e9e92e723eb1..cba34893258a85 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -52,6 +52,7 @@ static int video_mux_link_setup(struct media_entity *entity, const struct media_pad *remote, u32 flags) { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct v4l2_subdev_state *sd_state; struct video_mux *vmux = v4l2_subdev_to_video_mux(sd); u16 source_pad = entity->num_pads - 1; int ret = 0; @@ -67,10 +68,10 @@ static int video_mux_link_setup(struct media_entity *entity, remote->entity->name, remote->index, local->entity->name, local->index, flags & MEDIA_LNK_FL_ENABLED); + sd_state = v4l2_subdev_lock_and_get_active_state(sd); mutex_lock(&vmux->lock); if (flags & MEDIA_LNK_FL_ENABLED) { - struct v4l2_subdev_state *sd_state; struct v4l2_mbus_framefmt *source_mbusformat; if (vmux->active == local->index) @@ -88,12 +89,10 @@ static int video_mux_link_setup(struct media_entity *entity, vmux->active = local->index; /* Propagate the active format to the source */ - sd_state = v4l2_subdev_lock_and_get_active_state(sd); source_mbusformat = v4l2_subdev_state_get_format(sd_state, source_pad); *source_mbusformat = *v4l2_subdev_state_get_format(sd_state, vmux->active); - v4l2_subdev_unlock_state(sd_state); } else { if (vmux->active != local->index) goto out; @@ -105,6 +104,7 @@ static int video_mux_link_setup(struct media_entity *entity, out: mutex_unlock(&vmux->lock); + v4l2_subdev_unlock_state(sd_state); return ret; } @@ -486,7 +486,7 @@ MODULE_DEVICE_TABLE(of, video_mux_dt_ids); static struct platform_driver video_mux_driver = { .probe = video_mux_probe, - .remove_new = video_mux_remove, + .remove = video_mux_remove, .driver = { .of_match_table = video_mux_dt_ids, .name = "video-mux", diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c index f953d5474ae00a..146131b8f37e5a 100644 --- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c +++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c @@ -1028,7 +1028,7 @@ static struct platform_driver xcsi2rxss_driver = { .of_match_table = xcsi2rxss_of_id_table, }, .probe = xcsi2rxss_probe, - .remove_new = xcsi2rxss_remove, + .remove = xcsi2rxss_remove, }; module_platform_driver(xcsi2rxss_driver); diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index a1687b868a4452..18bfa6001909df 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -458,8 +458,6 @@ static const struct vb2_ops xvip_dma_queue_qops = { .queue_setup = xvip_dma_queue_setup, .buf_prepare = xvip_dma_buffer_prepare, .buf_queue = xvip_dma_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = xvip_dma_start_streaming, .stop_streaming = xvip_dma_stop_streaming, }; diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c index e05e528ffc6f72..cb93711ea3e356 100644 --- a/drivers/media/platform/xilinx/xilinx-tpg.c +++ b/drivers/media/platform/xilinx/xilinx-tpg.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -711,22 +712,13 @@ static int xtpg_parse_of(struct xtpg_device *xtpg) { struct device *dev = xtpg->xvip.dev; struct device_node *node = xtpg->xvip.dev->of_node; - struct device_node *ports; - struct device_node *port; unsigned int nports = 0; bool has_endpoint = false; - ports = of_get_child_by_name(node, "ports"); - if (ports == NULL) - ports = node; - - for_each_child_of_node(ports, port) { + for_each_of_graph_port(node, port) { const struct xvip_video_format *format; struct device_node *endpoint; - if (!of_node_name_eq(port, "port")) - continue; - format = xvip_of_get_format(port); if (IS_ERR(format)) { dev_err(dev, "invalid format in DT"); @@ -744,7 +736,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg) } if (nports == 0) { - endpoint = of_get_next_child(port, NULL); + endpoint = of_graph_get_next_port_endpoint(port, NULL); if (endpoint) has_endpoint = true; of_node_put(endpoint); @@ -920,7 +912,7 @@ static struct platform_driver xtpg_driver = { .of_match_table = xtpg_of_id_table, }, .probe = xtpg_probe, - .remove_new = xtpg_remove, + .remove = xtpg_remove, }; module_platform_driver(xtpg_driver); diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index bfe48cc0ab5254..024b439feec92c 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -618,7 +618,7 @@ static struct platform_driver xvip_composite_driver = { .of_match_table = xvip_composite_of_id_table, }, .probe = xvip_composite_probe, - .remove_new = xvip_composite_remove, + .remove = xvip_composite_remove, }; module_platform_driver(xvip_composite_driver); diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c index dda70719f0045a..92fec7bb47dae8 100644 --- a/drivers/media/platform/xilinx/xilinx-vtc.c +++ b/drivers/media/platform/xilinx/xilinx-vtc.c @@ -365,7 +365,7 @@ static struct platform_driver xvtc_driver = { .of_match_table = xvtc_of_id_table, }, .probe = xvtc_probe, - .remove_new = xvtc_remove, + .remove = xvtc_remove, }; module_platform_driver(xvtc_driver); diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 0e9a3787724c8a..3c8c17d64821c7 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -4,7 +4,7 @@ * * Copyright 1997 M. Kirkwood * - * Converted to the radio-isa framework by Hans Verkuil + * Converted to the radio-isa framework by Hans Verkuil * Converted to V4L2 API by Mauro Carvalho Chehab * Converted to new API by Alan Cox * Various bugfixes and enhancements by Russell Kroll diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index a532f63aa9d967..5ca6274c45bd3c 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -15,7 +15,7 @@ * Converted to new API by Alan Cox * Various bugfixes and enhancements by Russell Kroll * - * Converted to the radio-isa framework by Hans Verkuil + * Converted to the radio-isa framework by Hans Verkuil * Converted to V4L2 API by Mauro Carvalho Chehab * * Note: this card seems to swap the left and right audio channels! diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index ad49151f5ff094..4f87c76a2a96d9 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -4,7 +4,7 @@ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers * to concentrate on the actual hardware operation. * - * Copyright (C) 2012 Hans Verkuil + * Copyright (C) 2012 Hans Verkuil */ #include diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h index c9159958203e95..0f3db473da5e51 100644 --- a/drivers/media/radio/radio-isa.h +++ b/drivers/media/radio/radio-isa.h @@ -4,7 +4,7 @@ * This takes care of all the V4L2 scaffolding, allowing the ISA drivers * to concentrate on the actual hardware operation. * - * Copyright (C) 2012 Hans Verkuil + * Copyright (C) 2012 Hans Verkuil */ #ifndef _RADIO_ISA_H_ diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 08be77b8f3b71c..27f058c5e67787 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -23,7 +23,7 @@ * This code has been reintroduced and converted to use * the new V4L2 RDS API by: * - * Hans Verkuil + * Hans Verkuil */ #include diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 73d2c187f1227f..16b13a63bfed7f 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -7,7 +7,7 @@ * Converted to new API by Alan Cox * Various bugfixes and enhancements by Russell Kroll * - * Converted to the radio-isa framework by Hans Verkuil + * Converted to the radio-isa framework by Hans Verkuil * Converted to V4L2 API by Mauro Carvalho Chehab * * Fully tested with actual hardware and the v4l2-compliance tool. diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index b2c5809a8bc71f..9980346cb5ea38 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -1513,7 +1513,7 @@ static struct platform_driver si476x_radio_driver = { .name = DRIVER_NAME, }, .probe = si476x_radio_probe, - .remove_new = si476x_radio_remove, + .remove = si476x_radio_remove, }; module_platform_driver(si476x_radio_driver); diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 621bb85232711a..72008063445456 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -17,7 +17,7 @@ * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); * Volume Control is done digitally * - * Converted to the radio-isa framework by Hans Verkuil + * Converted to the radio-isa framework by Hans Verkuil * Converted to V4L2 API by Mauro Carvalho Chehab */ diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 04daa9c358c27f..a6069b106fd304 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -164,7 +164,7 @@ static struct platform_driver timbradio_platform_driver = { .name = DRIVER_NAME, }, .probe = timbradio_probe, - .remove_new = timbradio_remove, + .remove = timbradio_remove, }; module_platform_driver(timbradio_platform_driver); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index f6b98c304b72c9..511a8ede05ecdc 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -2145,7 +2145,7 @@ static int wl1273_fm_radio_probe(struct platform_device *pdev) static struct platform_driver wl1273_fm_radio_driver = { .probe = wl1273_fm_radio_probe, - .remove_new = wl1273_fm_radio_remove, + .remove = wl1273_fm_radio_remove, .driver = { .name = "wl1273_fm_radio", }, diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index f3dc57c751314b..099b7af6a410bd 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -30,7 +30,7 @@ * 2006-07-24 - Converted to V4L2 API * by Mauro Carvalho Chehab * - * Converted to the radio-isa framework by Hans Verkuil + * Converted to the radio-isa framework by Hans Verkuil * * Note that this is the driver for the Zoltrix Radio Plus. * This driver does not work for the Zoltrix Radio Plus 108 or the diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c index 9fdaed68a962ef..67b4afadc95a3e 100644 --- a/drivers/media/radio/si4713/radio-platform-si4713.c +++ b/drivers/media/radio/si4713/radio-platform-si4713.c @@ -205,7 +205,7 @@ static struct platform_driver radio_si4713_pdriver = { .name = "radio-si4713", }, .probe = radio_si4713_pdriver_probe, - .remove_new = radio_si4713_pdriver_remove, + .remove = radio_si4713_pdriver_remove, }; module_platform_driver(radio_si4713_pdriver); diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 3d36f323a8f8f7..4d032436691c1b 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -466,11 +466,12 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); return -ETIMEDOUT; } + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); if (!fmdev->resp_skb) { + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); fmerr("Response SKB is missing\n"); return -EFAULT; } - spin_lock_irqsave(&fmdev->resp_skb_lock, flags); skb = fmdev->resp_skb; fmdev->resp_skb = NULL; spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 74d69ce22a33e8..0a8aeafdb7e07a 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -184,6 +184,7 @@ config IR_GPIO_TX tristate "GPIO IR Bit Banging Transmitter" depends on LIRC depends on (OF && GPIOLIB) || COMPILE_TEST + depends on !PREEMPT_RT help Say Y if you want to a GPIO based IR transmitter. This is a bit banging driver. diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index d7721e60776edd..a733914a257424 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -311,9 +311,9 @@ static void ati_remote_dump(struct device *dev, unsigned char *data, if (data[0] != (unsigned char)0xff && data[0] != 0x00) dev_warn(dev, "Weird byte 0x%02x\n", data[0]); } else if (len == 4) - dev_warn(dev, "Weird key %*ph\n", 4, data); + dev_warn(dev, "Weird key %4ph\n", data); else - dev_warn(dev, "Weird data, len=%d %*ph ...\n", len, 6, data); + dev_warn(dev, "Weird data, len=%d %6ph ...\n", len, data); } /* @@ -502,7 +502,7 @@ static void ati_remote_input_report(struct urb *urb) if (data[1] != ((data[2] + data[3] + 0xd5) & 0xff)) { dbginfo(&ati_remote->interface->dev, - "wrong checksum in input: %*ph\n", 4, data); + "wrong checksum in input: %4ph\n", data); return; } diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index b29a1a9f381da3..bf6d8fa983bfb4 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -201,7 +201,7 @@ MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match); static struct platform_driver gpio_ir_recv_driver = { .probe = gpio_ir_recv_probe, - .remove_new = gpio_ir_recv_remove, + .remove = gpio_ir_recv_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = gpio_ir_recv_of_match, diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c index 1a8fea357f14c0..e185ead4046447 100644 --- a/drivers/media/rc/gpio-ir-tx.c +++ b/drivers/media/rc/gpio-ir-tx.c @@ -78,8 +78,6 @@ static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf, ktime_t edge; int i; - local_irq_disable(); - edge = ktime_get(); for (i = 0; i < count; i++) { @@ -110,8 +108,6 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf, space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) * (NSEC_PER_SEC / 100), gpio_ir->carrier); - local_irq_disable(); - edge = ktime_get(); for (i = 0; i < count; i++) { diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c index d87d8e14c55681..067f4bc7fcc326 100644 --- a/drivers/media/rc/img-ir/img-ir-core.c +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -181,7 +181,7 @@ static struct platform_driver img_ir_driver = { .pm = &img_ir_pmops, }, .probe = img_ir_probe, - .remove_new = img_ir_remove, + .remove = img_ir_remove, }; module_platform_driver(img_ir_driver); diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index de5bb9a08ea4c0..afd80d2350c6d3 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -394,7 +394,7 @@ static struct platform_driver hix5hd2_ir_driver = { .pm = &hix5hd2_ir_pm_ops, }, .probe = hix5hd2_ir_probe, - .remove_new = hix5hd2_ir_remove, + .remove = hix5hd2_ir_remove, }; module_platform_driver(hix5hd2_ir_driver); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index f042f3f14afa9d..a2257dc2f25d6b 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -815,28 +815,23 @@ void __exit lirc_dev_exit(void) struct rc_dev *rc_dev_get_from_fd(int fd, bool write) { - struct fd f = fdget(fd); + CLASS(fd, f)(fd); struct lirc_fh *fh; struct rc_dev *dev; - if (!fd_file(f)) + if (fd_empty(f)) return ERR_PTR(-EBADF); - if (fd_file(f)->f_op != &lirc_fops) { - fdput(f); + if (fd_file(f)->f_op != &lirc_fops) return ERR_PTR(-EINVAL); - } - if (write && !(fd_file(f)->f_mode & FMODE_WRITE)) { - fdput(f); + if (write && !(fd_file(f)->f_mode & FMODE_WRITE)) return ERR_PTR(-EPERM); - } fh = fd_file(f)->private_data; dev = fh->rc; get_device(&dev->dev); - fdput(f); return dev; } diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 9cdb45821eccd6..272ebb0d97c811 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -628,7 +628,7 @@ MODULE_DEVICE_TABLE(of, meson_ir_match); static struct platform_driver meson_ir_driver = { .probe = meson_ir_probe, - .remove_new = meson_ir_remove, + .remove = meson_ir_remove, .shutdown = meson_ir_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c index b2f82b2d1c8d40..85c9436b0a2004 100644 --- a/drivers/media/rc/mtk-cir.c +++ b/drivers/media/rc/mtk-cir.c @@ -440,7 +440,7 @@ static void mtk_ir_remove(struct platform_device *pdev) static struct platform_driver mtk_ir_driver = { .probe = mtk_ir_probe, - .remove_new = mtk_ir_remove, + .remove = mtk_ir_remove, .driver = { .name = MTK_IR_DEV, .of_match_table = mtk_ir_match, diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 988b09191c4c74..6539fa0a6e7905 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -408,7 +408,7 @@ static struct platform_driver st_rc_driver = { .pm = &st_rc_pm_ops, }, .probe = st_rc_probe, - .remove_new = st_rc_remove, + .remove = st_rc_remove, }; module_platform_driver(st_rc_driver); diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index b49df8355e6b39..92ef4e7c6f69fc 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -413,7 +413,7 @@ MODULE_DEVICE_TABLE(of, sunxi_ir_match); static struct platform_driver sunxi_ir_driver = { .probe = sunxi_ir_probe, - .remove_new = sunxi_ir_remove, + .remove = sunxi_ir_remove, .shutdown = sunxi_ir_shutdown, .driver = { .name = SUNXI_IR_DEV, diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 846e90c062910e..c45f5cf12ded3c 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -26,7 +26,7 @@ #include "codec-v4l2-fwht.h" MODULE_DESCRIPTION("Virtual codec device"); -MODULE_AUTHOR("Hans Verkuil "); +MODULE_AUTHOR("Hans Verkuil "); MODULE_LICENSE("GPL v2"); static bool multiplanar; @@ -43,6 +43,8 @@ MODULE_PARM_DESC(debug, " activates debug info"); #define MIN_WIDTH 640U #define MAX_HEIGHT 2160U #define MIN_HEIGHT 360U +/* Recommended number of buffers for the stateful codecs */ +#define VICODEC_REC_BUFS 2 #define dprintk(dev, fmt, arg...) \ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) @@ -1688,8 +1690,6 @@ static const struct vb2_ops vicodec_qops = { .buf_request_complete = vicodec_buf_request_complete, .start_streaming = vicodec_start_streaming, .stop_streaming = vicodec_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int queue_init(void *priv, struct vb2_queue *src_vq, @@ -1707,12 +1707,14 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &vicodec_qops; src_vq->mem_ops = &vb2_vmalloc_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - if (ctx->is_enc) + if (ctx->is_enc) { src_vq->lock = &ctx->dev->stateful_enc.mutex; - else if (ctx->is_stateless) + src_vq->min_reqbufs_allocation = VICODEC_REC_BUFS; + } else if (ctx->is_stateless) { src_vq->lock = &ctx->dev->stateless_dec.mutex; - else + } else { src_vq->lock = &ctx->dev->stateful_dec.mutex; + } src_vq->supports_requests = ctx->is_stateless; src_vq->requires_requests = ctx->is_stateless; ret = vb2_queue_init(src_vq); @@ -1730,6 +1732,8 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->mem_ops = &vb2_vmalloc_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = src_vq->lock; + if (!ctx->is_stateless && !ctx->is_enc) + dst_vq->min_reqbufs_allocation = VICODEC_REC_BUFS; return vb2_queue_init(dst_vq); } @@ -1854,11 +1858,16 @@ static int vicodec_open(struct file *file) 1, 31, 1, 20); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP, 1, 31, 1, 20); - if (ctx->is_enc) - v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1); + if (ctx->is_stateless) v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); + else + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, ctx->is_enc ? + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT : + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + VICODEC_REC_BUFS, VICODEC_REC_BUFS, 1, + VICODEC_REC_BUFS); + if (hdl->error) { rc = hdl->error; v4l2_ctrl_handler_free(hdl); @@ -2207,7 +2216,7 @@ static void vicodec_remove(struct platform_device *pdev) static struct platform_driver vicodec_pdrv = { .probe = vicodec_probe, - .remove_new = vicodec_remove, + .remove = vicodec_remove, .driver = { .name = VICODEC_NAME, }, diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c index 613949df897d34..e1dd8adeba469f 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c @@ -572,7 +572,7 @@ static struct platform_driver vidtv_bridge_driver = { .name = VIDTV_PDEV_NAME, }, .probe = vidtv_bridge_probe, - .remove_new = vidtv_bridge_remove, + .remove = vidtv_bridge_remove, }; static void __exit vidtv_bridge_exit(void) diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 3e3b424b486058..6c24dcf27eb078 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -1100,8 +1100,6 @@ static const struct vb2_ops vim2m_qops = { .buf_queue = vim2m_buf_queue, .start_streaming = vim2m_start_streaming, .stop_streaming = vim2m_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_request_complete = vim2m_buf_request_complete, }; @@ -1394,7 +1392,7 @@ static void vim2m_remove(struct platform_device *pdev) static struct platform_driver vim2m_pdrv = { .probe = vim2m_probe, - .remove_new = vim2m_remove, + .remove = vim2m_remove, .driver = { .name = MEM2MEM_NAME, }, diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index 89506ae0090167..10df039278e701 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -326,12 +326,6 @@ static const struct vb2_ops vimc_capture_qops = { .buf_queue = vimc_capture_buf_queue, .queue_setup = vimc_capture_queue_setup, .buf_prepare = vimc_capture_buffer_prepare, - /* - * Since q->lock is set we can use the standard - * vb2_ops_wait_prepare/finish helper functions. - */ - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct media_entity_operations vimc_capture_mops = { diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c index 2083c60e34d6a6..c812fa9f0650b7 100644 --- a/drivers/media/test-drivers/vimc/vimc-core.c +++ b/drivers/media/test-drivers/vimc/vimc-core.c @@ -410,7 +410,7 @@ static struct platform_device vimc_pdev = { static struct platform_driver vimc_pdrv = { .probe = vimc_probe, - .remove_new = vimc_remove, + .remove = vimc_remove, .driver = { .name = VIMC_PDEV_NAME, }, diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c index c46464bcaf2e13..01c964ea6f7675 100644 --- a/drivers/media/test-drivers/visl/visl-core.c +++ b/drivers/media/test-drivers/visl/visl-core.c @@ -523,7 +523,7 @@ static void visl_remove(struct platform_device *pdev) static struct platform_driver visl_pdrv = { .probe = visl_probe, - .remove_new = visl_remove, + .remove = visl_remove, .driver = { .name = VISL_NAME, }, diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c index f8d970319764f6..8be505d8908c98 100644 --- a/drivers/media/test-drivers/visl/visl-video.c +++ b/drivers/media/test-drivers/visl/visl-video.c @@ -136,6 +136,12 @@ static const u32 visl_decoded_fmts[] = { V4L2_PIX_FMT_YUV420, }; +static const u32 visl_extended_decoded_fmts[] = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_P010, +}; + const struct visl_coded_format_desc visl_coded_fmts[] = { { .pixelformat = V4L2_PIX_FMT_FWHT_STATELESS, @@ -341,11 +347,21 @@ static int visl_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct visl_ctx *ctx = visl_file_to_ctx(file); + u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL; + int max_fmts = ctx->coded_format_desc->num_decoded_fmts; + const u32 *decoded_fmts = ctx->coded_format_desc->decoded_fmts; + + if (f->index & V4L2_FMTDESC_FLAG_ENUM_ALL) { + max_fmts = ARRAY_SIZE(visl_extended_decoded_fmts); + decoded_fmts = visl_extended_decoded_fmts; + } + + f->index = index; - if (f->index >= ctx->coded_format_desc->num_decoded_fmts) + if (index >= max_fmts) return -EINVAL; - f->pixelformat = ctx->coded_format_desc->decoded_fmts[f->index]; + f->pixelformat = decoded_fmts[index]; return 0; } @@ -716,8 +732,6 @@ static const struct vb2_ops visl_qops = { .buf_queue = visl_buf_queue, .start_streaming = visl_start_streaming, .stop_streaming = visl_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_request_complete = visl_buf_request_complete, }; diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 4f330f4fc6be9e..7477ac8cb95564 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -2239,7 +2239,7 @@ static struct platform_device vivid_pdev = { static struct platform_driver vivid_pdrv = { .probe = vivid_probe, - .remove_new = vivid_remove, + .remove = vivid_remove, .driver = { .name = "vivid", }, diff --git a/drivers/media/test-drivers/vivid/vivid-meta-cap.c b/drivers/media/test-drivers/vivid/vivid-meta-cap.c index 0a718d037e5944..c7aaecc0b5a247 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-cap.c @@ -122,8 +122,6 @@ const struct vb2_ops vivid_meta_cap_qops = { .start_streaming = meta_cap_start_streaming, .stop_streaming = meta_cap_stop_streaming, .buf_request_complete = meta_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c index 82ab3b26914e6d..55e5e5dec2f2ab 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-out.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c @@ -122,8 +122,6 @@ const struct vb2_ops vivid_meta_out_qops = { .start_streaming = meta_out_start_streaming, .stop_streaming = meta_out_stop_streaming, .buf_request_complete = meta_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vidioc_enum_fmt_meta_out(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c index 38cda33dffb2ab..74a91d28c8be93 100644 --- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c @@ -337,8 +337,6 @@ const struct vb2_ops vivid_sdr_cap_qops = { .start_streaming = sdr_cap_start_streaming, .stop_streaming = sdr_cap_stop_streaming, .buf_request_complete = sdr_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vivid_sdr_enum_freq_bands(struct file *file, void *fh, diff --git a/drivers/media/test-drivers/vivid/vivid-touch-cap.c b/drivers/media/test-drivers/vivid/vivid-touch-cap.c index 3600b084bca53e..36a781fa17bc3d 100644 --- a/drivers/media/test-drivers/vivid/vivid-touch-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-touch-cap.c @@ -110,8 +110,6 @@ const struct vb2_ops vivid_touch_cap_qops = { .start_streaming = touch_cap_start_streaming, .stop_streaming = touch_cap_stop_streaming, .buf_request_complete = touch_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f) diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c index 99138f63585c71..a09f62c66c33d1 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c @@ -230,8 +230,6 @@ const struct vb2_ops vivid_vbi_cap_qops = { .start_streaming = vbi_cap_start_streaming, .stop_streaming = vbi_cap_stop_streaming, .buf_request_complete = vbi_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.c b/drivers/media/test-drivers/vivid/vivid-vbi-out.c index 871a56d934254a..b7a09d2f394e43 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.c @@ -128,8 +128,6 @@ const struct vb2_ops vivid_vbi_out_qops = { .start_streaming = vbi_out_start_streaming, .stop_streaming = vbi_out_stop_streaming, .buf_request_complete = vbi_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int vidioc_g_fmt_vbi_out(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c index 6a790ac8cbe689..b166d90177c641 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -257,8 +258,6 @@ const struct vb2_ops vivid_vid_cap_qops = { .start_streaming = vid_cap_start_streaming, .stop_streaming = vid_cap_stop_streaming, .buf_request_complete = vid_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* @@ -1459,12 +1458,19 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) h_freq = (u32)bt->pixelclock / total_h_pixel; if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { + struct v4l2_dv_timings cvt = {}; + if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width, - bt->polarities, bt->interlaced, timings)) + bt->polarities, bt->interlaced, + &vivid_dv_timings_cap, &cvt) && + cvt.bt.width == bt->width && cvt.bt.height == bt->height) { + *timings = cvt; return true; + } } if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) { + struct v4l2_dv_timings gtf = {}; struct v4l2_fract aspect_ratio; find_aspect_ratio(bt->width, bt->height, @@ -1472,8 +1478,12 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) &aspect_ratio.denominator); if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync, bt->polarities, bt->interlaced, - aspect_ratio, timings)) + aspect_ratio, &vivid_dv_timings_cap, + >f) && + gtf.bt.width == bt->width && gtf.bt.height == bt->height) { + *timings = gtf; return true; + } } return false; } diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c index 60327f3612af40..5ec84db934d6b0 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c @@ -201,8 +201,6 @@ const struct vb2_ops vivid_vid_out_qops = { .start_streaming = vid_out_start_streaming, .stop_streaming = vid_out_stop_streaming, .buf_request_complete = vid_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 4d5b1c878028d2..9186174a46fd2b 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -444,7 +444,7 @@ static struct platform_driver it913x_driver = { .suppress_bind_attrs = true, }, .probe = it913x_probe, - .remove_new = it913x_remove, + .remove = it913x_remove, .id_table = it913x_id_table, }; diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 6afef11a49cb1a..2c8ce74ddca4d2 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -1476,7 +1476,7 @@ static u32 MT2063_CalcLO2Mult(u32 *Div, } /* - * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be + * FindClearTuneFilter() - Calculate the correct ClearTune filter to be * used for a given input frequency. * * @state: ptr to tuner data structure diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c index 7c03d4132763f7..3b61c3afed18d2 100644 --- a/drivers/media/tuners/mxl301rf.c +++ b/drivers/media/tuners/mxl301rf.c @@ -64,7 +64,7 @@ static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val) /* tuner_ops */ -/* get RSSI and update propery cache, set to *out in % */ +/* get RSSI and update property cache, set to *out in % */ static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out) { struct mxl301rf_state *state; diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c index d9bfa257a00542..0e811c5eae6cb7 100644 --- a/drivers/media/tuners/mxl5005s.c +++ b/drivers/media/tuners/mxl5005s.c @@ -2639,7 +2639,7 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ; status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A); - /* Euqation E5B CHCAL_EN_INIT_RF */ + /* Equation E5B CHCAL_EN_INIT_RF */ status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0)); /*if (E5 == 0) * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1); diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index a7e721baaa997f..3a3309bc01518e 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -279,7 +279,9 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, if (approx > 255) approx = 255; - tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); + ret = tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); + if (tda_fail(ret)) + goto fail; /* calculate temperature compensation */ rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000; diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c index d78a2bdb3e36d7..425e9fd3f3d467 100644 --- a/drivers/media/tuners/tea5761.c +++ b/drivers/media/tuners/tea5761.c @@ -46,7 +46,7 @@ struct tea5761_priv { /* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ /* First byte */ -#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ +#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from bottom to up */ #define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ /* Bits 0-5 for divider MSB */ @@ -132,7 +132,7 @@ static void tea5761_status_dump(unsigned char *buffer) frq / 1000, frq % 1000, div); } -/* Freq should be specifyed at 62.5 Hz */ +/* Freq should be specified at 62.5 Hz */ static int __set_radio_freq(struct dvb_frontend *fe, unsigned int freq, bool mono) diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c index 016d0d5ec50b83..ef4acb1f1bfa77 100644 --- a/drivers/media/tuners/tea5767.c +++ b/drivers/media/tuners/tea5767.c @@ -44,7 +44,7 @@ struct tea5767_priv { /* Third register */ -/* Station search from botton to up */ +/* Station search from bottom to up */ #define TEA5767_SEARCH_UP 0x80 /* Searches with ADC output = 10 */ @@ -183,7 +183,7 @@ static void tea5767_status_dump(struct tea5767_priv *priv, (buffer[4] & TEA5767_RESERVED_MASK)); } -/* Freq should be specifyed at 62.5 Hz */ +/* Freq should be specified at 62.5 Hz */ static int set_radio_freq(struct dvb_frontend *fe, struct analog_parameters *params) { diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index e24e655fb1dbfb..08f0920cf6ca2f 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -603,8 +603,6 @@ static const struct vb2_ops airspy_vb2_ops = { .buf_queue = airspy_buf_queue, .start_streaming = airspy_start_streaming, .stop_streaming = airspy_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int airspy_querycap(struct file *file, void *fh, @@ -1017,6 +1015,7 @@ static int airspy_probe(struct usb_interface *intf, s->vb_queue.ops = &airspy_vb2_ops; s->vb_queue.mem_ops = &vb2_vmalloc_memops; s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + s->vb_queue.lock = &s->vb_queue_lock; ret = vb2_queue_init(&s->vb_queue); if (ret) { dev_err(s->dev, "Could not initialize vb2 queue\n"); @@ -1026,7 +1025,6 @@ static int airspy_probe(struct usb_interface *intf, /* Init video_device structure */ s->vdev = airspy_template; s->vdev.queue = &s->vb_queue; - s->vdev.queue->lock = &s->vb_queue_lock; video_set_drvdata(&s->vdev, s); /* Register the v4l2_device structure */ diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index b0333637b747d7..11203adf47ea04 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -74,6 +74,4 @@ const struct vb2_ops au0828_vbi_qops = { .prepare_streaming = v4l_vb2q_enable_media_source, .start_streaming = au0828_start_analog_streaming, .stop_streaming = au0828_stop_vbi_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 2ec49ea479d56e..e9cd2a335f7faf 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -915,8 +915,6 @@ static const struct vb2_ops au0828_video_qops = { .prepare_streaming = v4l_vb2q_enable_media_source, .start_streaming = au0828_start_analog_streaming, .stop_streaming = au0828_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index abb967c8bd352c..a4a9781328c50a 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1458,8 +1458,6 @@ static const struct vb2_ops cx231xx_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 3d3c881c8e587a..6139ef5d891d6b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -623,7 +623,7 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input) } int cx231xx_set_decoder_video_input(struct cx231xx *dev, - u8 pin_type, u8 input) + u8 pin_type, u32 input) { int status = 0; u32 value = 0; @@ -1338,39 +1338,6 @@ void update_HH_register_after_set_DIF(struct cx231xx *dev) */ } -void cx231xx_dump_HH_reg(struct cx231xx *dev) -{ - u32 value = 0; - u16 i = 0; - - value = 0x45005390; - vid_blk_write_word(dev, 0x104, value); - - for (i = 0x100; i < 0x140; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - for (i = 0x300; i < 0x400; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - for (i = 0x400; i < 0x440; i++) { - vid_blk_read_word(dev, i, &value); - dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value); - i = i+3; - } - - vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); - vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390); - vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value); - dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value); -} - #if 0 static void cx231xx_dump_SC_reg(struct cx231xx *dev) { @@ -2460,30 +2427,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode) return status; } -int cx231xx_power_suspend(struct cx231xx *dev) -{ - u8 value[4] = { 0, 0, 0, 0 }; - u32 tmp = 0; - int status = 0; - - status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, - value, 4); - if (status > 0) - return status; - - tmp = le32_to_cpu(*((__le32 *) value)); - tmp &= (~PWR_MODE_MASK); - - value[0] = (u8) tmp; - value[1] = (u8) (tmp >> 8); - value[2] = (u8) (tmp >> 16); - value[3] = (u8) (tmp >> 24); - status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN, - value, 4); - - return status; -} - /****************************************************************************** * S T R E A M C O N T R O L functions * ******************************************************************************/ diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 92efe6c1f47bae..691f073892b36c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -679,8 +679,7 @@ struct cx231xx_board cx231xx_boards[] = { }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | - (CX231XX_VIN_1_2 << 8) | - CX25840_SVIDEO_ON, + (CX231XX_VIN_3_2 << 8), .amux = CX231XX_AMUX_LINE_IN, .gpio = NULL, } @@ -990,10 +989,11 @@ struct cx231xx_board cx231xx_boards[] = { } }, }, }; -const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); /* table of devices that work with this driver */ struct usb_device_id cx231xx_id_table[] = { + {USB_DEVICE(0x1D19, 0x6108), + .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, {USB_DEVICE(0x1D19, 0x6109), .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, {USB_DEVICE(0x0572, 0x5A3C), diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 33431d9f54c2cf..338e101484653a 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -243,8 +243,6 @@ struct vb2_ops cx231xx_vbi_qops = { .buf_queue = vbi_buf_queue, .start_streaming = vbi_start_streaming, .stop_streaming = vbi_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 435eb0b32cb15c..2cd4e333bc4b01 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -800,8 +800,6 @@ static const struct vb2_ops cx231xx_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /********************* v4l2 interface **************************************/ diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 74339a6a2f7184..19f5036a78d7f4 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -790,7 +790,6 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq, u8 spectral_invert, u32 mode); void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev); void reset_s5h1432_demod(struct cx231xx *dev); -void cx231xx_dump_HH_reg(struct cx231xx *dev); void update_HH_register_after_set_DIF(struct cx231xx *dev); @@ -905,7 +904,6 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type); /* Power control functions */ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode); -int cx231xx_power_suspend(struct cx231xx *dev); /* chip specific control functions */ int cx231xx_init_ctrl_pin_status(struct cx231xx *dev); @@ -916,7 +914,7 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3); /* video audio decoder related functions */ void video_mux(struct cx231xx *dev, int index); int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input); -int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input); +int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u32 input); int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev); int cx231xx_set_audio_input(struct cx231xx *dev, u8 input); @@ -949,7 +947,6 @@ extern void cx231xx_pre_card_setup(struct cx231xx *dev); extern void cx231xx_card_setup(struct cx231xx *dev); extern struct cx231xx_board cx231xx_boards[]; extern struct usb_device_id cx231xx_id_table[]; -extern const unsigned int cx231xx_bcount; int cx231xx_tuner_callback(void *ptr, int component, int command, int arg); /* cx23885-417.c */ diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 8699846eb4162c..bea12cdc85e8ba 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -46,24 +46,15 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, state->buf); - /* We need receive one message more after dvb_usb_generic_rw due - to weird transaction flow, which is 1 x send + 2 x receive. */ + /* + * We need receive one message more after dvb_usbv2_generic_rw_locked() + * due to weird transaction flow, which is 1 x send + 2 x receive. + */ ret = dvb_usbv2_generic_rw_locked(d, state->buf, sizeof(state->buf), state->buf, sizeof(state->buf)); if (ret) goto error_unlock; - /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32 - * (EPIPE, Broken pipe). Function supports currently msleep() as a - * parameter but I would not like to use it, since according to - * Documentation/timers/timers-howto.rst it should not be used such - * short, under < 20ms, sleeps. Repeating failed message would be - * better choice as not to add unwanted delays... - * Fixing that correctly is one of those or both; - * 1) use repeat if possible - * 2) add suitable delay - */ - /* get answer, retry few times if error returned */ for (i = 0; i < 3; i++) { /* receive 2nd answer */ diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c index b5d8c6b75ae133..8253046cd6e601 100644 --- a/drivers/media/usb/dvb-usb/cxusb-analog.c +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -956,8 +956,6 @@ static const struct vb2_ops cxdev_video_qops = { .start_streaming = cxusb_medion_v_start_streaming, .stop_streaming = cxusb_medion_v_stop_streaming, .buf_queue = cxusub_medion_v_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish }; static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index b253c44c9724ff..8c5d9518122330 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -84,6 +84,4 @@ const struct vb2_ops em28xx_vbi_qops = { .buf_queue = vbi_buffer_queue, .start_streaming = em28xx_start_analog_streaming, .stop_streaming = em28xx_stop_vbi_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 4aef584e21da5d..66c09bc6d59ed2 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1229,8 +1229,6 @@ static const struct vb2_ops em28xx_video_qops = { .buf_queue = buffer_queue, .start_streaming = em28xx_start_analog_streaming, .stop_streaming = em28xx_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int em28xx_vb2_setup(struct em28xx *dev) diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index 13256565b03430..2087ffcb85a5a6 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -452,8 +452,6 @@ static const struct vb2_ops go7007_video_qops = { .buf_finish = go7007_buf_finish, .start_streaming = go7007_start_streaming, .stop_streaming = go7007_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int vidioc_g_parm(struct file *filp, void *priv, diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index e8c8bdb9c40baa..25edd218965402 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1380,8 +1380,6 @@ static const struct vb2_ops gspca_qops = { .buf_queue = gspca_buffer_queue, .start_streaming = gspca_start_streaming, .stop_streaming = gspca_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct v4l2_file_operations dev_fops = { diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 8b6a57f170d0dd..bdff64a29a33a2 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -847,7 +847,7 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) r = rate_1; i = ARRAY_SIZE(rate_1); } - while (--i > 0) { + while (--i >= 0) { if (sd->frame_rate >= r->fps) break; r++; diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 9c0ecd5f056c08..0b50de8775a38d 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -888,8 +888,6 @@ static const struct vb2_ops hackrf_vb2_ops = { .buf_queue = hackrf_buf_queue, .start_streaming = hackrf_start_streaming, .stop_streaming = hackrf_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int hackrf_querycap(struct file *file, void *fh, @@ -1398,6 +1396,7 @@ static int hackrf_probe(struct usb_interface *intf, dev->rx_vb2_queue.drv_priv = dev; dev->rx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer); dev->rx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->rx_vb2_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->rx_vb2_queue); if (ret) { dev_err(dev->dev, "Could not initialize rx vb2 queue\n"); @@ -1413,6 +1412,7 @@ static int hackrf_probe(struct usb_interface *intf, dev->tx_vb2_queue.drv_priv = dev; dev->tx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer); dev->tx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->tx_vb2_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->tx_vb2_queue); if (ret) { dev_err(dev->dev, "Could not initialize tx vb2 queue\n"); @@ -1474,7 +1474,6 @@ static int hackrf_probe(struct usb_interface *intf, /* Init video_device structure for receiver */ dev->rx_vdev = hackrf_template; dev->rx_vdev.queue = &dev->rx_vb2_queue; - dev->rx_vdev.queue->lock = &dev->vb_queue_lock; dev->rx_vdev.v4l2_dev = &dev->v4l2_dev; dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler; dev->rx_vdev.lock = &dev->v4l2_lock; @@ -1494,7 +1493,6 @@ static int hackrf_probe(struct usb_interface *intf, /* Init video_device structure for transmitter */ dev->tx_vdev = hackrf_template; dev->tx_vdev.queue = &dev->tx_vb2_queue; - dev->tx_vdev.queue->lock = &dev->vb_queue_lock; dev->tx_vdev.v4l2_dev = &dev->v4l2_dev; dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler; dev->tx_vdev.lock = &dev->v4l2_lock; diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 5138486abfa0d8..33099f39146afd 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -883,8 +883,6 @@ static const struct vb2_ops msi2500_vb2_ops = { .buf_queue = msi2500_buf_queue, .start_streaming = msi2500_start_streaming, .stop_streaming = msi2500_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv, @@ -1199,6 +1197,7 @@ static int msi2500_probe(struct usb_interface *intf, dev->vb_queue.ops = &msi2500_vb2_ops; dev->vb_queue.mem_ops = &vb2_vmalloc_memops; dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + dev->vb_queue.lock = &dev->vb_queue_lock; ret = vb2_queue_init(&dev->vb_queue); if (ret) { dev_err(dev->dev, "Could not initialize vb2 queue\n"); @@ -1208,7 +1207,6 @@ static int msi2500_probe(struct usb_interface *intf, /* Init video_device structure */ dev->vdev = msi2500_template; dev->vdev.queue = &dev->vb_queue; - dev->vdev.queue->lock = &dev->vb_queue_lock; video_set_drvdata(&dev->vdev, dev); /* Register the v4l2_device structure */ @@ -1219,8 +1217,8 @@ static int msi2500_probe(struct usb_interface *intf, goto err_free_mem; } - /* SPI master adapter */ - ctlr = spi_alloc_master(dev->dev, 0); + /* SPI host adapter */ + ctlr = spi_alloc_host(dev->dev, 0); if (ctlr == NULL) { ret = -ENOMEM; goto err_unregister_v4l2_dev; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c index 675dc7153e2bec..28ffe7981f8cc8 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -335,8 +335,8 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp, unsigned int cnt) if (scnt < sp->buffer_slot_count) { struct pvr2_buffer **nb = NULL; if (scnt) { - nb = kmemdup(sp->buffers, scnt * sizeof(*nb), - GFP_KERNEL); + nb = kmemdup_array(sp->buffers, scnt, sizeof(*nb), + GFP_KERNEL); if (!nb) return -ENOMEM; } kfree(sp->buffers); diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index e342199711d397..3ec9eb5956edd0 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -760,8 +760,6 @@ static const struct vb2_ops pwc_vb_queue_ops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /***************************************************************************/ @@ -1054,6 +1052,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vb_queue.ops = &pwc_vb_queue_ops; pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + pdev->vb_queue.lock = &pdev->vb_queue_lock; rc = vb2_queue_init(&pdev->vb_queue); if (rc < 0) { PWC_ERROR("Oops, could not initialize vb2 queue.\n"); @@ -1064,7 +1063,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vdev = pwc_template; strscpy(pdev->vdev.name, name, sizeof(pdev->vdev.name)); pdev->vdev.queue = &pdev->vb_queue; - pdev->vdev.queue->lock = &pdev->vb_queue_lock; video_set_drvdata(&pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index a6e450181fd014..899a7a67e2baf1 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -704,8 +704,6 @@ static const struct vb2_ops s2255_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int vidioc_querycap(struct file *file, void *priv, diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index a1f785a5ffd892..5ba3d9c4b3fb03 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -734,8 +734,6 @@ static const struct vb2_ops stk1160_video_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct video_device v4l_template = { diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 702f1c8bd2ab3d..be22a9697197c6 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -780,8 +780,6 @@ static const struct vb2_ops usbtv_vb2_ops = { .buf_queue = usbtv_buf_queue, .start_streaming = usbtv_start_streaming, .stop_streaming = usbtv_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 0fac689c6350b2..b3c8411dc05c9e 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -371,7 +371,7 @@ static int uvc_parse_format(struct uvc_device *dev, * Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ - while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && + while (ftype && buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == ftype) { unsigned int maxIntervalIndex; @@ -775,14 +775,27 @@ static const u8 uvc_media_transport_input_guid[16] = UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT; static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; -static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, - unsigned int num_pads, unsigned int extra_size) +static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type, + u16 id, unsigned int num_pads, + unsigned int extra_size) { struct uvc_entity *entity; unsigned int num_inputs; unsigned int size; unsigned int i; + /* Per UVC 1.1+ spec 3.7.2, the ID should be non-zero. */ + if (id == 0) { + dev_err(&dev->udev->dev, "Found Unit with invalid ID 0.\n"); + return ERR_PTR(-EINVAL); + } + + /* Per UVC 1.1+ spec 3.7.2, the ID is unique. */ + if (uvc_entity_by_id(dev, id)) { + dev_err(&dev->udev->dev, "Found multiple Units with ID %u\n", id); + return ERR_PTR(-EINVAL); + } + extra_size = roundup(extra_size, sizeof(*entity->pads)); if (num_pads) num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1; @@ -792,7 +805,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, + num_inputs; entity = kzalloc(size, GFP_KERNEL); if (entity == NULL) - return NULL; + return ERR_PTR(-ENOMEM); entity->id = id; entity->type = type; @@ -904,10 +917,10 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, break; } - unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3], - p + 1, 2*n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, UVC_VC_EXTENSION_UNIT, + buffer[3], p + 1, 2 * n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; @@ -1016,10 +1029,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3], - 1, n + p); - if (term == NULL) - return -ENOMEM; + term = uvc_alloc_new_entity(dev, type | UVC_TERM_INPUT, + buffer[3], 1, n + p); + if (IS_ERR(term)) + return PTR_ERR(term); if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) { term->camera.bControlSize = n; @@ -1075,10 +1088,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return 0; } - term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3], - 1, 0); - if (term == NULL) - return -ENOMEM; + term = uvc_alloc_new_entity(dev, type | UVC_TERM_OUTPUT, + buffer[3], 1, 0); + if (IS_ERR(term)) + return PTR_ERR(term); memcpy(term->baSourceID, &buffer[7], 1); @@ -1097,9 +1110,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], + p + 1, 0); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->baSourceID, &buffer[5], p); @@ -1119,9 +1133,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], 2, n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->baSourceID, &buffer[4], 1); unit->processing.wMaxMultiplier = @@ -1148,9 +1162,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n); - if (unit == NULL) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], + p + 1, n); + if (IS_ERR(unit)) + return PTR_ERR(unit); memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; @@ -1290,9 +1305,10 @@ static int uvc_gpio_parse(struct uvc_device *dev) return dev_err_probe(&dev->udev->dev, irq, "No IRQ for privacy GPIO\n"); - unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1); - if (!unit) - return -ENOMEM; + unit = uvc_alloc_new_entity(dev, UVC_EXT_GPIO_UNIT, + UVC_EXT_GPIO_UNIT_ID, 0, 1); + if (IS_ERR(unit)) + return PTR_ERR(unit); unit->gpio.gpio_privacy = gpio_privacy; unit->gpio.irq = irq; @@ -1919,11 +1935,41 @@ static void uvc_unregister_video(struct uvc_device *dev) struct uvc_streaming *stream; list_for_each_entry(stream, &dev->streams, list) { + /* Nothing to do here, continue. */ if (!video_is_registered(&stream->vdev)) continue; + /* + * For stream->vdev we follow the same logic as: + * vb2_video_unregister_device(). + */ + + /* 1. Take a reference to vdev */ + get_device(&stream->vdev.dev); + + /* 2. Ensure that no new ioctls can be called. */ video_unregister_device(&stream->vdev); - video_unregister_device(&stream->meta.vdev); + + /* 3. Wait for old ioctls to finish. */ + mutex_lock(&stream->mutex); + + /* 4. Stop streaming. */ + uvc_queue_release(&stream->queue); + + mutex_unlock(&stream->mutex); + + put_device(&stream->vdev.dev); + + /* + * For stream->meta.vdev we can directly call: + * vb2_video_unregister_device(). + */ + vb2_video_unregister_device(&stream->meta.vdev); + + /* + * Now both vdevs are not streaming and all the ioctls will + * return -ENODEV. + */ uvc_debugfs_cleanup_stream(stream); } @@ -2116,7 +2162,6 @@ static int uvc_probe(struct usb_interface *intf, INIT_LIST_HEAD(&dev->streams); kref_init(&dev->ref); atomic_set(&dev->nmappings, 0); - mutex_init(&dev->lock); dev->udev = usb_get_dev(udev); dev->intf = usb_get_intf(intf); @@ -2288,10 +2333,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message) /* Controls are cached on the fly so they don't need to be saved. */ if (intf->cur_altsetting->desc.bInterfaceSubClass == UVC_SC_VIDEOCONTROL) { - mutex_lock(&dev->lock); - if (dev->users) - uvc_status_stop(dev); - mutex_unlock(&dev->lock); + uvc_status_suspend(dev); return 0; } @@ -2322,12 +2364,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset) return ret; } - mutex_lock(&dev->lock); - if (dev->users) - ret = uvc_status_start(dev, GFP_NOIO); - mutex_unlock(&dev->lock); - - return ret; + return uvc_status_resume(dev); } list_for_each_entry(stream, &dev->streams, list) { @@ -2428,9 +2465,22 @@ static const struct uvc_device_info uvc_quirk_force_y8 = { * The Logitech cameras listed below have their interface class set to * VENDOR_SPEC because they don't announce themselves as UVC devices, even * though they are compliant. + * + * Sort these by vendor/product ID. */ static const struct usb_device_id uvc_ids[] = { /* Quanta ACER HD User Facing */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0408, + .idProduct = 0x4033, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = UVC_PC_PROTOCOL_15, + .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){ + .uvc_version = 0x010a, + } }, + /* Quanta ACER HD User Facing */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0408, @@ -2964,6 +3014,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX | UVC_QUIRK_IGNORE_SELECTOR_UNIT) }, + /* NXP Semiconductors IR VIDEO */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1fc9, + .idProduct = 0x009b, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, /* Oculus VR Positional Tracker DK2 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -3072,6 +3131,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, + /* Intel D421 Depth Module */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x8086, + .idProduct = 0x1155, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) }, { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 16fa17bbd15eaa..26ee85657fc89d 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -197,8 +197,6 @@ static const struct vb2_ops uvc_queue_qops = { .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, .buf_finish = uvc_buffer_finish, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = uvc_start_streaming, .stop_streaming = uvc_stop_streaming, }; @@ -207,8 +205,6 @@ static const struct vb2_ops uvc_meta_queue_qops = { .queue_setup = uvc_queue_setup, .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .stop_streaming = uvc_stop_streaming, }; diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index a78a88c710e24a..06c867510c8fe6 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -257,6 +257,8 @@ int uvc_status_init(struct uvc_device *dev) unsigned int pipe; int interval; + mutex_init(&dev->status_lock); + if (ep == NULL) return 0; @@ -292,7 +294,7 @@ int uvc_status_init(struct uvc_device *dev) void uvc_status_unregister(struct uvc_device *dev) { - usb_kill_urb(dev->int_urb); + uvc_status_suspend(dev); uvc_input_unregister(dev); } @@ -302,18 +304,25 @@ void uvc_status_cleanup(struct uvc_device *dev) kfree(dev->status); } -int uvc_status_start(struct uvc_device *dev, gfp_t flags) +static int uvc_status_start(struct uvc_device *dev, gfp_t flags) { - if (dev->int_urb == NULL) + lockdep_assert_held(&dev->status_lock); + + if (!dev->int_urb) return 0; return usb_submit_urb(dev->int_urb, flags); } -void uvc_status_stop(struct uvc_device *dev) +static void uvc_status_stop(struct uvc_device *dev) { struct uvc_ctrl_work *w = &dev->async_ctrl; + lockdep_assert_held(&dev->status_lock); + + if (!dev->int_urb) + return; + /* * Prevent the asynchronous control handler from requeing the URB. The * barrier is needed so the flush_status change is visible to other @@ -350,3 +359,49 @@ void uvc_status_stop(struct uvc_device *dev) */ smp_store_release(&dev->flush_status, false); } + +int uvc_status_resume(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users) + return uvc_status_start(dev, GFP_NOIO); + + return 0; +} + +void uvc_status_suspend(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users) + uvc_status_stop(dev); +} + +int uvc_status_get(struct uvc_device *dev) +{ + int ret; + + guard(mutex)(&dev->status_lock); + + if (!dev->status_users) { + ret = uvc_status_start(dev, GFP_KERNEL); + if (ret) + return ret; + } + + dev->status_users++; + + return 0; +} + +void uvc_status_put(struct uvc_device *dev) +{ + guard(mutex)(&dev->status_lock); + + if (dev->status_users == 1) + uvc_status_stop(dev); + WARN_ON(!dev->status_users); + if (dev->status_users) + dev->status_users--; +} diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index f4988f03640aec..97c5407f66032a 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -628,20 +628,13 @@ static int uvc_v4l2_open(struct file *file) return -ENOMEM; } - mutex_lock(&stream->dev->lock); - if (stream->dev->users == 0) { - ret = uvc_status_start(stream->dev, GFP_KERNEL); - if (ret < 0) { - mutex_unlock(&stream->dev->lock); - usb_autopm_put_interface(stream->dev->intf); - kfree(handle); - return ret; - } + ret = uvc_status_get(stream->dev); + if (ret) { + usb_autopm_put_interface(stream->dev->intf); + kfree(handle); + return ret; } - stream->dev->users++; - mutex_unlock(&stream->dev->lock); - v4l2_fh_init(&handle->vfh, &stream->vdev); v4l2_fh_add(&handle->vfh); handle->chain = stream->chain; @@ -670,10 +663,7 @@ static int uvc_v4l2_release(struct file *file) kfree(handle); file->private_data = NULL; - mutex_lock(&stream->dev->lock); - if (--stream->dev->users == 0) - uvc_status_stop(stream->dev); - mutex_unlock(&stream->dev->lock); + uvc_status_put(stream->dev); usb_autopm_put_interface(stream->dev->intf); return 0; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index b7d24a853ce4f1..07f9921d83f2d5 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -563,8 +563,6 @@ struct uvc_device { const struct uvc_device_info *info; - struct mutex lock; /* Protects users */ - unsigned int users; atomic_t nmappings; /* Video control interface */ @@ -586,6 +584,8 @@ struct uvc_device { struct usb_host_endpoint *int_ep; struct urb *int_urb; struct uvc_status *status; + struct mutex status_lock; /* Protects status_users */ + unsigned int status_users; bool flush_status; struct input_dev *input; @@ -752,8 +752,10 @@ int uvc_register_video_device(struct uvc_device *dev, int uvc_status_init(struct uvc_device *dev); void uvc_status_unregister(struct uvc_device *dev); void uvc_status_cleanup(struct uvc_device *dev); -int uvc_status_start(struct uvc_device *dev, gfp_t flags); -void uvc_status_stop(struct uvc_device *dev); +int uvc_status_resume(struct uvc_device *dev); +void uvc_status_suspend(struct uvc_device *dev); +int uvc_status_get(struct uvc_device *dev); +void uvc_status_put(struct uvc_device *dev); /* Controls */ extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops; diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 3d7711cc42bc58..5bcaeeba4d09f3 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -93,6 +93,8 @@ static struct attribute *video_device_attrs[] = { }; ATTRIBUTE_GROUPS(video_device); +static struct dentry *v4l2_debugfs_root_dir; + /* * Active devices */ @@ -227,7 +229,7 @@ static void v4l2_device_release(struct device *cd) v4l2_device_put(v4l2_dev); } -static struct class video_class = { +static const struct class video_class = { .name = VIDEO_NAME, .dev_groups = video_device_groups, }; @@ -1118,6 +1120,16 @@ void video_unregister_device(struct video_device *vdev) } EXPORT_SYMBOL(video_unregister_device); +#ifdef CONFIG_DEBUG_FS +struct dentry *v4l2_debugfs_root(void) +{ + if (!v4l2_debugfs_root_dir) + v4l2_debugfs_root_dir = debugfs_create_dir("v4l2", NULL); + return v4l2_debugfs_root_dir; +} +EXPORT_SYMBOL_GPL(v4l2_debugfs_root); +#endif + #if defined(CONFIG_MEDIA_CONTROLLER) __must_check int video_device_pipeline_start(struct video_device *vdev, @@ -1222,6 +1234,8 @@ static void __exit videodev_exit(void) class_unregister(&video_class); unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); + debugfs_remove_recursive(v4l2_debugfs_root_dir); + v4l2_debugfs_root_dir = NULL; } subsys_initcall(videodev_init); diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 942d0005c55e82..d26edf157e6400 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -481,25 +481,28 @@ EXPORT_SYMBOL_GPL(v4l2_calc_timeperframe); * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). * @interlaced - if this flag is true, it indicates interlaced format - * @fmt - the resulting timings. + * @cap - the v4l2_dv_timings_cap capabilities. + * @timings - the resulting timings. * * This function will attempt to detect if the given values correspond to a * valid CVT format. If so, then it will return true, and fmt will be filled * in with the found CVT timings. */ -bool v4l2_detect_cvt(unsigned frame_height, - unsigned hfreq, - unsigned vsync, - unsigned active_width, +bool v4l2_detect_cvt(unsigned int frame_height, + unsigned int hfreq, + unsigned int vsync, + unsigned int active_width, u32 polarities, bool interlaced, - struct v4l2_dv_timings *fmt) + const struct v4l2_dv_timings_cap *cap, + struct v4l2_dv_timings *timings) { - int v_fp, v_bp, h_fp, h_bp, hsync; - int frame_width, image_height, image_width; + struct v4l2_dv_timings t = {}; + int v_fp, v_bp, h_fp, h_bp, hsync; + int frame_width, image_height, image_width; bool reduced_blanking; bool rb_v2 = false; - unsigned pix_clk; + unsigned int pix_clk; if (vsync < 4 || vsync > 8) return false; @@ -625,36 +628,39 @@ bool v4l2_detect_cvt(unsigned frame_height, h_fp = h_blank - hsync - h_bp; } - fmt->type = V4L2_DV_BT_656_1120; - fmt->bt.polarities = polarities; - fmt->bt.width = image_width; - fmt->bt.height = image_height; - fmt->bt.hfrontporch = h_fp; - fmt->bt.vfrontporch = v_fp; - fmt->bt.hsync = hsync; - fmt->bt.vsync = vsync; - fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync; + t.type = V4L2_DV_BT_656_1120; + t.bt.polarities = polarities; + t.bt.width = image_width; + t.bt.height = image_height; + t.bt.hfrontporch = h_fp; + t.bt.vfrontporch = v_fp; + t.bt.hsync = hsync; + t.bt.vsync = vsync; + t.bt.hbackporch = frame_width - image_width - h_fp - hsync; if (!interlaced) { - fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync; - fmt->bt.interlaced = V4L2_DV_PROGRESSIVE; + t.bt.vbackporch = frame_height - image_height - v_fp - vsync; + t.bt.interlaced = V4L2_DV_PROGRESSIVE; } else { - fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp - + t.bt.vbackporch = (frame_height - image_height - 2 * v_fp - 2 * vsync) / 2; - fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp - - 2 * vsync - fmt->bt.vbackporch; - fmt->bt.il_vfrontporch = v_fp; - fmt->bt.il_vsync = vsync; - fmt->bt.flags |= V4L2_DV_FL_HALF_LINE; - fmt->bt.interlaced = V4L2_DV_INTERLACED; + t.bt.il_vbackporch = frame_height - image_height - 2 * v_fp - + 2 * vsync - t.bt.vbackporch; + t.bt.il_vfrontporch = v_fp; + t.bt.il_vsync = vsync; + t.bt.flags |= V4L2_DV_FL_HALF_LINE; + t.bt.interlaced = V4L2_DV_INTERLACED; } - fmt->bt.pixelclock = pix_clk; - fmt->bt.standards = V4L2_DV_BT_STD_CVT; + t.bt.pixelclock = pix_clk; + t.bt.standards = V4L2_DV_BT_STD_CVT; if (reduced_blanking) - fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + t.bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + if (!v4l2_valid_dv_timings(&t, cap, NULL, NULL)) + return false; + *timings = t; return true; } EXPORT_SYMBOL_GPL(v4l2_detect_cvt); @@ -699,22 +705,25 @@ EXPORT_SYMBOL_GPL(v4l2_detect_cvt); * image height, so it has to be passed explicitly. Usually * the native screen aspect ratio is used for this. If it * is not filled in correctly, then 16:9 will be assumed. - * @fmt - the resulting timings. + * @cap - the v4l2_dv_timings_cap capabilities. + * @timings - the resulting timings. * * This function will attempt to detect if the given values correspond to a * valid GTF format. If so, then it will return true, and fmt will be filled * in with the found GTF timings. */ -bool v4l2_detect_gtf(unsigned frame_height, - unsigned hfreq, - unsigned vsync, - u32 polarities, - bool interlaced, - struct v4l2_fract aspect, - struct v4l2_dv_timings *fmt) +bool v4l2_detect_gtf(unsigned int frame_height, + unsigned int hfreq, + unsigned int vsync, + u32 polarities, + bool interlaced, + struct v4l2_fract aspect, + const struct v4l2_dv_timings_cap *cap, + struct v4l2_dv_timings *timings) { + struct v4l2_dv_timings t = {}; int pix_clk; - int v_fp, v_bp, h_fp, hsync; + int v_fp, v_bp, h_fp, hsync; int frame_width, image_height, image_width; bool default_gtf; int h_blank; @@ -783,36 +792,39 @@ bool v4l2_detect_gtf(unsigned frame_height, h_fp = h_blank / 2 - hsync; - fmt->type = V4L2_DV_BT_656_1120; - fmt->bt.polarities = polarities; - fmt->bt.width = image_width; - fmt->bt.height = image_height; - fmt->bt.hfrontporch = h_fp; - fmt->bt.vfrontporch = v_fp; - fmt->bt.hsync = hsync; - fmt->bt.vsync = vsync; - fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync; + t.type = V4L2_DV_BT_656_1120; + t.bt.polarities = polarities; + t.bt.width = image_width; + t.bt.height = image_height; + t.bt.hfrontporch = h_fp; + t.bt.vfrontporch = v_fp; + t.bt.hsync = hsync; + t.bt.vsync = vsync; + t.bt.hbackporch = frame_width - image_width - h_fp - hsync; if (!interlaced) { - fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync; - fmt->bt.interlaced = V4L2_DV_PROGRESSIVE; + t.bt.vbackporch = frame_height - image_height - v_fp - vsync; + t.bt.interlaced = V4L2_DV_PROGRESSIVE; } else { - fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp - + t.bt.vbackporch = (frame_height - image_height - 2 * v_fp - 2 * vsync) / 2; - fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp - - 2 * vsync - fmt->bt.vbackporch; - fmt->bt.il_vfrontporch = v_fp; - fmt->bt.il_vsync = vsync; - fmt->bt.flags |= V4L2_DV_FL_HALF_LINE; - fmt->bt.interlaced = V4L2_DV_INTERLACED; + t.bt.il_vbackporch = frame_height - image_height - 2 * v_fp - + 2 * vsync - t.bt.vbackporch; + t.bt.il_vfrontporch = v_fp; + t.bt.il_vsync = vsync; + t.bt.flags |= V4L2_DV_FL_HALF_LINE; + t.bt.interlaced = V4L2_DV_INTERLACED; } - fmt->bt.pixelclock = pix_clk; - fmt->bt.standards = V4L2_DV_BT_STD_GTF; + t.bt.pixelclock = pix_clk; + t.bt.standards = V4L2_DV_BT_STD_GTF; if (!default_gtf) - fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + t.bt.flags |= V4L2_DV_FL_REDUCED_BLANKING; + if (!v4l2_valid_dv_timings(&t, cap, NULL, NULL)) + return false; + *timings = t; return true; } EXPORT_SYMBOL_GPL(v4l2_detect_gtf); @@ -1154,3 +1166,70 @@ int v4l2_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port) return 0; } EXPORT_SYMBOL_GPL(v4l2_phys_addr_validate); + +#ifdef CONFIG_DEBUG_FS + +#define DEBUGFS_FOPS(type, flag) \ +static ssize_t \ +infoframe_read_##type(struct file *filp, \ + char __user *ubuf, size_t count, loff_t *ppos) \ +{ \ + struct v4l2_debugfs_if *infoframes = filp->private_data; \ + \ + return infoframes->if_read((flag), infoframes->priv, filp, \ + ubuf, count, ppos); \ +} \ + \ +static const struct file_operations infoframe_##type##_fops = { \ + .owner = THIS_MODULE, \ + .open = simple_open, \ + .read = infoframe_read_##type, \ +} + +DEBUGFS_FOPS(avi, V4L2_DEBUGFS_IF_AVI); +DEBUGFS_FOPS(audio, V4L2_DEBUGFS_IF_AUDIO); +DEBUGFS_FOPS(spd, V4L2_DEBUGFS_IF_SPD); +DEBUGFS_FOPS(hdmi, V4L2_DEBUGFS_IF_HDMI); + +struct v4l2_debugfs_if *v4l2_debugfs_if_alloc(struct dentry *root, u32 if_types, + void *priv, + v4l2_debugfs_if_read_t if_read) +{ + struct v4l2_debugfs_if *infoframes; + + if (IS_ERR_OR_NULL(root) || !if_types || !if_read) + return NULL; + + infoframes = kzalloc(sizeof(*infoframes), GFP_KERNEL); + if (!infoframes) + return NULL; + + infoframes->if_dir = debugfs_create_dir("infoframes", root); + infoframes->priv = priv; + infoframes->if_read = if_read; + if (if_types & V4L2_DEBUGFS_IF_AVI) + debugfs_create_file("avi", 0400, infoframes->if_dir, + infoframes, &infoframe_avi_fops); + if (if_types & V4L2_DEBUGFS_IF_AUDIO) + debugfs_create_file("audio", 0400, infoframes->if_dir, + infoframes, &infoframe_audio_fops); + if (if_types & V4L2_DEBUGFS_IF_SPD) + debugfs_create_file("spd", 0400, infoframes->if_dir, + infoframes, &infoframe_spd_fops); + if (if_types & V4L2_DEBUGFS_IF_HDMI) + debugfs_create_file("hdmi", 0400, infoframes->if_dir, + infoframes, &infoframe_hdmi_fops); + return infoframes; +} +EXPORT_SYMBOL_GPL(v4l2_debugfs_if_alloc); + +void v4l2_debugfs_if_free(struct v4l2_debugfs_if *infoframes) +{ + if (infoframes) { + debugfs_remove_recursive(infoframes->if_dir); + kfree(infoframes); + } +} +EXPORT_SYMBOL_GPL(v4l2_debugfs_if_free); + +#endif diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index e14db67be97c50..0304daa8471d1e 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1327,6 +1327,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_Y14P: descr = "14-bit Greyscale (MIPI Packed)"; break; case V4L2_PIX_FMT_Y8I: descr = "Interleaved 8-bit Greyscale"; break; case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break; + case V4L2_PIX_FMT_Y16I: descr = "Interleaved 16-bit Greyscale"; break; case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break; case V4L2_PIX_FMT_INZI: descr = "Planar 10:16 Greyscale Depth"; break; case V4L2_PIX_FMT_CNF4: descr = "4-bit Depth Confidence (Packed)"; break; @@ -1467,6 +1468,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_Y212: descr = "12-bit YUYV Packed"; break; case V4L2_PIX_FMT_Y216: descr = "16-bit YUYV Packed"; break; case V4L2_META_FMT_RPI_BE_CFG: descr = "RPi PiSP BE Config format"; break; + case V4L2_META_FMT_RPI_FE_CFG: descr = "RPi PiSP FE Config format"; break; + case V4L2_META_FMT_RPI_FE_STATS: descr = "RPi PiSP FE Statistics format"; break; case V4L2_META_FMT_GENERIC_8: descr = "8-bit Generic Metadata"; break; case V4L2_META_FMT_GENERIC_CSI2_10: descr = "8-bit Generic Meta, 10b CSI-2"; break; case V4L2_META_FMT_GENERIC_CSI2_12: descr = "8-bit Generic Meta, 12b CSI-2"; break; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 3a4ba08810d249..cde1774c9098dd 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -334,6 +334,11 @@ static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, unsigned int i; int ret; +#if defined(CONFIG_MEDIA_CONTROLLER) + if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) + return -EOPNOTSUPP; +#endif + memset(fd, 0, sizeof(*fd)); ret = sd->ops->pad->get_frame_desc(sd, pad, fd); @@ -691,10 +696,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); + if (v4l2_subdev_has_op(sd, core, subscribe_event)) + return v4l2_subdev_call(sd, core, subscribe_event, + vfh, arg); + + if ((sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) && + vfh->ctrl_handler) + return v4l2_ctrl_subdev_subscribe_event(sd, vfh, arg); + + return -ENOIOCTLCMD; case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); + if (v4l2_subdev_has_op(sd, core, unsubscribe_event)) + return v4l2_subdev_call(sd, core, unsubscribe_event, + vfh, arg); + + if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) + return v4l2_event_subdev_unsubscribe(sd, vfh, arg); + + return -ENOIOCTLCMD; #ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER: @@ -1641,6 +1661,9 @@ int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name, } } + if (sd->ctrl_handler) + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + state = __v4l2_subdev_state_alloc(sd, name, key); if (IS_ERR(state)) return PTR_ERR(state); diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 5028467b2dc97b..08d9e05b1b3383 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -934,7 +934,7 @@ static struct platform_driver brcmstb_dpfe_driver = { .of_match_table = brcmstb_dpfe_of_match, }, .probe = brcmstb_dpfe_probe, - .remove_new = brcmstb_dpfe_remove, + .remove = brcmstb_dpfe_remove, .resume = brcmstb_dpfe_resume, }; diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c index 4f17a93aa02848..c87b37e2c1f07c 100644 --- a/drivers/memory/brcmstb_memc.c +++ b/drivers/memory/brcmstb_memc.c @@ -283,7 +283,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_memc_pm_ops, brcmstb_memc_suspend, static struct platform_driver brcmstb_memc_driver = { .probe = brcmstb_memc_probe, - .remove_new = brcmstb_memc_remove, + .remove = brcmstb_memc_remove, .driver = { .name = "brcmstb_memc", .of_match_table = brcmstb_memc_of_match, diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index 99eb7d1baa5ff6..2e1ecae9e95973 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -1159,7 +1159,7 @@ MODULE_DEVICE_TABLE(of, emif_of_match); static struct platform_driver emif_driver = { .probe = emif_probe, - .remove_new = emif_remove, + .remove = emif_remove, .shutdown = emif_shutdown, .driver = { .name = "emif", diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c index f47d05f7c5c50a..ecd6c19551532c 100644 --- a/drivers/memory/fsl-corenet-cf.c +++ b/drivers/memory/fsl-corenet-cf.c @@ -249,7 +249,7 @@ static struct platform_driver ccf_driver = { .of_match_table = ccf_matches, }, .probe = ccf_probe, - .remove_new = ccf_remove, + .remove = ccf_remove, }; module_platform_driver(ccf_driver); diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c index 15e919c24f817b..e89e0c6cc4bccc 100644 --- a/drivers/memory/fsl_ifc.c +++ b/drivers/memory/fsl_ifc.c @@ -316,7 +316,7 @@ static struct platform_driver fsl_ifc_ctrl_driver = { .of_match_table = fsl_ifc_match, }, .probe = fsl_ifc_ctrl_probe, - .remove_new = fsl_ifc_ctrl_remove, + .remove = fsl_ifc_ctrl_remove, }; static int __init fsl_ifc_init(void) diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c index fb6db2ffe71b1b..1a8161514d03e4 100644 --- a/drivers/memory/jz4780-nemc.c +++ b/drivers/memory/jz4780-nemc.c @@ -407,7 +407,7 @@ static const struct of_device_id jz4780_nemc_dt_match[] = { static struct platform_driver jz4780_nemc_driver = { .probe = jz4780_nemc_probe, - .remove_new = jz4780_nemc_remove, + .remove = jz4780_nemc_remove, .driver = { .name = "jz4780-nemc", .of_match_table = of_match_ptr(jz4780_nemc_dt_match), diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c index 2bc034dff691bf..5710348f72f6ff 100644 --- a/drivers/memory/mtk-smi.c +++ b/drivers/memory/mtk-smi.c @@ -616,7 +616,7 @@ static const struct dev_pm_ops smi_larb_pm_ops = { static struct platform_driver mtk_smi_larb_driver = { .probe = mtk_smi_larb_probe, - .remove_new = mtk_smi_larb_remove, + .remove = mtk_smi_larb_remove, .driver = { .name = "mtk-smi-larb", .of_match_table = mtk_smi_larb_of_ids, @@ -838,7 +838,7 @@ static const struct dev_pm_ops smi_common_pm_ops = { static struct platform_driver mtk_smi_common_driver = { .probe = mtk_smi_common_probe, - .remove_new = mtk_smi_common_remove, + .remove = mtk_smi_common_remove, .driver = { .name = "mtk-smi-common", .of_match_table = mtk_smi_common_of_ids, diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index c8a0d82f9c27df..50eb9f49512b44 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -2743,7 +2743,7 @@ MODULE_DEVICE_TABLE(of, gpmc_dt_ids); static struct platform_driver gpmc_driver = { .probe = gpmc_probe, - .remove_new = gpmc_remove, + .remove = gpmc_remove, .driver = { .name = DEVICE_NAME, .of_match_table = of_match_ptr(gpmc_dt_ids), diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 7fbd36fa1a1b46..15b4706aafee9f 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -795,7 +795,7 @@ MODULE_DEVICE_TABLE(of, rpcif_of_match); static struct platform_driver rpcif_driver = { .probe = rpcif_probe, - .remove_new = rpcif_remove, + .remove = rpcif_remove, .driver = { .name = "rpc-if", .of_match_table = rpcif_of_match, diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c index 7d80322754fada..788d49c688b1d9 100644 --- a/drivers/memory/samsung/exynos5422-dmc.c +++ b/drivers/memory/samsung/exynos5422-dmc.c @@ -1571,7 +1571,7 @@ MODULE_DEVICE_TABLE(of, exynos5_dmc_of_match); static struct platform_driver exynos5_dmc_platdrv = { .probe = exynos5_dmc_probe, - .remove_new = exynos5_dmc_remove, + .remove = exynos5_dmc_remove, .driver = { .name = "exynos5-dmc", .of_match_table = exynos5_dmc_of_match, diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c index 566c225f71c06e..6e386ab5409159 100644 --- a/drivers/memory/stm32-fmc2-ebi.c +++ b/drivers/memory/stm32-fmc2-ebi.c @@ -1815,7 +1815,7 @@ MODULE_DEVICE_TABLE(of, stm32_fmc2_ebi_match); static struct platform_driver stm32_fmc2_ebi_driver = { .probe = stm32_fmc2_ebi_probe, - .remove_new = stm32_fmc2_ebi_remove, + .remove = stm32_fmc2_ebi_remove, .driver = { .name = "stm32_fmc2_ebi", .of_match_table = stm32_fmc2_ebi_match, diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c index 33d67d25171940..bc807d7fcd4e56 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -406,7 +406,7 @@ static struct platform_driver tegra186_emc_driver = { .sync_state = icc_sync_state, }, .probe = tegra186_emc_probe, - .remove_new = tegra186_emc_remove, + .remove = tegra186_emc_remove, }; module_platform_driver(tegra186_emc_driver); diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c index 78ca1d6c097740..2d5d8245a1d3b3 100644 --- a/drivers/memory/tegra/tegra210-emc-core.c +++ b/drivers/memory/tegra/tegra210-emc-core.c @@ -2051,7 +2051,7 @@ static struct platform_driver tegra210_emc_driver = { .pm = &tegra210_emc_pm_ops, }, .probe = tegra210_emc_probe, - .remove_new = tegra210_emc_remove, + .remove = tegra210_emc_remove, }; module_platform_driver(tegra210_emc_driver); diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c index 592f70e9c8e5bb..df362ecc59e910 100644 --- a/drivers/memory/ti-emif-pm.c +++ b/drivers/memory/ti-emif-pm.c @@ -330,7 +330,7 @@ static const struct dev_pm_ops ti_emif_pm_ops = { static struct platform_driver ti_emif_driver = { .probe = ti_emif_probe, - .remove_new = ti_emif_remove, + .remove = ti_emif_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = ti_emif_of_match, diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index 9a3a784054cc6c..ae4e8b8e6eb7d7 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -26,7 +26,7 @@ static DEFINE_IDR(memstick_host_idr); static DEFINE_SPINLOCK(memstick_host_lock); static int memstick_dev_match(struct memstick_dev *card, - struct memstick_device_id *id) + const struct memstick_device_id *id) { if (id->match_flags & MEMSTICK_MATCH_ALL) { if ((id->type == card->id.type) @@ -44,7 +44,7 @@ static int memstick_bus_match(struct device *dev, const struct device_driver *dr dev); const struct memstick_driver *ms_drv = container_of_const(drv, struct memstick_driver, driver); - struct memstick_device_id *ids = ms_drv->id_table; + const struct memstick_device_id *ids = ms_drv->id_table; if (ids) { while (ids->match_flags) { diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index 47a314a4eb6faf..20a2466bec2375 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -996,7 +996,7 @@ static int msb_verify_block(struct msb_data *msb, u16 pba, return 0; } -/* Writes exectly one block + oob */ +/* Writes exactly one block + oob */ static int msb_write_block(struct msb_data *msb, u16 pba, u32 lba, struct scatterlist *sg, int offset) { @@ -1684,7 +1684,7 @@ static int msb_cache_read(struct msb_data *msb, int lba, */ static const struct chs_entry chs_table[] = { -/* size sectors cylynders heads */ +/* size sectors cylinders heads */ { 4, 16, 247, 2 }, { 8, 16, 495, 2 }, { 16, 16, 495, 4 }, @@ -1729,7 +1729,7 @@ static int msb_init_card(struct memstick_dev *card) boot_block = &msb->boot_page[0]; - /* Save intersting attributes from boot page */ + /* Save interesting attributes from boot page */ msb->block_count = boot_block->attr.number_of_blocks; msb->page_size = boot_block->attr.page_size; @@ -2279,7 +2279,7 @@ static int msb_resume(struct memstick_dev *card) #endif /* CONFIG_PM */ -static struct memstick_device_id msb_id_tbl[] = { +static const struct memstick_device_id msb_id_tbl[] = { {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE, MEMSTICK_CLASS_FLASH}, diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 49accfdc89d616..13b317c5606996 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -1349,7 +1349,7 @@ static int mspro_block_resume(struct memstick_dev *card) #endif /* CONFIG_PM */ -static struct memstick_device_id mspro_block_id_tbl[] = { +static const struct memstick_device_id mspro_block_id_tbl[] = { {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO, MEMSTICK_CLASS_DUO}, {} diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 461f5ffd02bc12..544a31ff46e5cd 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -675,7 +675,7 @@ static irqreturn_t r592_irq(int irq, void *data) return ret; } -/* External inteface: set settings */ +/* External interface: set settings */ static int r592_set_param(struct memstick_host *host, enum memstick_param param, int value) { diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c index ffdd8de9ec5d79..6eb892fd4d3432 100644 --- a/drivers/memstick/host/rtsx_usb_ms.c +++ b/drivers/memstick/host/rtsx_usb_ms.c @@ -853,7 +853,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_usb_ms_ids); static struct platform_driver rtsx_usb_ms_driver = { .probe = rtsx_usb_ms_drv_probe, - .remove_new = rtsx_usb_ms_drv_remove, + .remove = rtsx_usb_ms_drv_remove, .id_table = rtsx_usb_ms_ids, .driver = { .name = "rtsx_usb_ms", diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 91242f26defb00..ee61b70aa677e9 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -137,7 +137,7 @@ static const struct scsi_host_template mptfc_driver_template = { * Supported hardware */ -static struct pci_device_id mptfc_pci_table[] = { +static const struct pci_device_id mptfc_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919, diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index a1ec7e84d6fe4f..40b34f670065cb 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -51,10 +51,7 @@ #define LINUX_MPTLAN_H_INCLUDED /*****************************************************************************/ -#if !defined(__GENKSYMS__) #include -#endif - #include #include // #include diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index a0bcb0864ecd2c..d0549a4daf76a4 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -4231,10 +4231,8 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num, static void mptsas_reprobe_lun(struct scsi_device *sdev, void *data) { - int rc; - sdev->no_uld_attach = data ? 1 : 0; - rc = scsi_device_reprobe(sdev); + WARN_ON(scsi_device_reprobe(sdev)); } static void @@ -5379,7 +5377,7 @@ static void mptsas_remove(struct pci_dev *pdev) mptscsih_remove(pdev); } -static struct pci_device_id mptsas_pci_table[] = { +static const struct pci_device_id mptsas_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068, diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 574b882c9a8540..4184d0c70ac31d 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -1238,7 +1238,7 @@ static struct spi_function_template mptspi_transport_functions = { * Supported hardware */ -static struct pci_device_id mptspi_pci_table[] = { +static const struct pci_device_id mptspi_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030, diff --git a/drivers/mfd/88pm886.c b/drivers/mfd/88pm886.c index dbe9efc027d20a..891fdce5d8c124 100644 --- a/drivers/mfd/88pm886.c +++ b/drivers/mfd/88pm886.c @@ -37,6 +37,7 @@ static struct resource pm886_onkey_resources[] = { static struct mfd_cell pm886_devs[] = { MFD_CELL_RES("88pm886-onkey", pm886_onkey_resources), MFD_CELL_NAME("88pm886-regulator"), + MFD_CELL_NAME("88pm886-rtc"), }; static int pm886_power_off_handler(struct sys_off_data *sys_off_data) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f9325bcce1b94e..ae23b317a64e49 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -25,7 +25,7 @@ config MFD_ADP5585 select MFD_CORE select REGMAP_I2C depends on I2C - depends on OF || COMPILE_TEST + depends on OF help Say yes here to add support for the Analog Devices ADP5585 GPIO expander, PWM and keypad controller. This includes the I2C driver and @@ -236,6 +236,18 @@ config MFD_AXP20X_RSB components like regulators or the PEK (Power Enable Key) under the corresponding menus. +config MFD_CGBC + tristate "Congatec Board Controller" + select MFD_CORE + depends on X86 + help + This is the core driver of the Board Controller found on some Congatec + SMARC modules. The Board Controller provides functions like watchdog, + I2C busses, and GPIO controller. + + To compile this driver as a module, choose M here: the module will be + called cgbc-core. + config MFD_CROS_EC_DEV tristate "ChromeOS Embedded Controller multifunction device" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2a9f91e81af836..e057d6d6faef5c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o +obj-$(CONFIG_MFD_CGBC) += cgbc-core.o obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o obj-$(CONFIG_MFD_CS42L43) += cs42l43.o obj-$(CONFIG_MFD_CS42L43_I2C) += cs42l43-i2c.o diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index 8f3ebe651eeaaf..b6b44e2e319809 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -159,7 +159,7 @@ static struct platform_driver ab8500_sysctrl_driver = { .of_match_table = ab8500_sysctrl_match, }, .probe = ab8500_sysctrl_probe, - .remove_new = ab8500_sysctrl_remove, + .remove = ab8500_sysctrl_remove, }; static int __init ab8500_sysctrl_init(void) diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index b52f7ffdad352a..d5df5466eaf5ad 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -95,7 +95,7 @@ static int __maybe_unused atmel_flexcom_resume_noirq(struct device *dev) if (err) return err; - val = FLEX_MR_OPMODE(ddata->opmode), + val = FLEX_MR_OPMODE(ddata->opmode); writel(val, ddata->base + FLEX_MR); clk_disable_unprepare(ddata->clk); diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index e560066e588523..4628ca14e76682 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -255,8 +255,8 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply); /** * atmel_hsmc_cs_conf_apply - apply an SMC CS conf * @regmap: the HSMC regmap - * @cs: the CS id * @layout: the layout of registers + * @cs: the CS id * @conf: the SMC CS conf to apply * * Applies an SMC CS configuration. @@ -296,8 +296,8 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get); /** * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf * @regmap: the HSMC regmap - * @cs: the CS id * @layout: the layout of registers + * @cs: the CS id * @conf: the SMC CS conf object to store the current conf * * Retrieve the SMC CS configuration. diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index 791a0b4cb64bb7..5c93136f977e72 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,axp221", .data = (void *)AXP221_ID }, { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, { .compatible = "x-powers,axp313a", .data = (void *)AXP313A_ID }, + { .compatible = "x-powers,axp323", .data = (void *)AXP323_ID }, { .compatible = "x-powers,axp717", .data = (void *)AXP717_ID }, { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID }, { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 4051551757f2dc..251465a656d092 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -34,20 +34,21 @@ #define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4) static const char * const axp20x_model_names[] = { - "AXP152", - "AXP192", - "AXP202", - "AXP209", - "AXP221", - "AXP223", - "AXP288", - "AXP313a", - "AXP717", - "AXP803", - "AXP806", - "AXP809", - "AXP813", - "AXP15060", + [AXP152_ID] = "AXP152", + [AXP192_ID] = "AXP192", + [AXP202_ID] = "AXP202", + [AXP209_ID] = "AXP209", + [AXP221_ID] = "AXP221", + [AXP223_ID] = "AXP223", + [AXP288_ID] = "AXP288", + [AXP313A_ID] = "AXP313a", + [AXP323_ID] = "AXP323", + [AXP717_ID] = "AXP717", + [AXP803_ID] = "AXP803", + [AXP806_ID] = "AXP806", + [AXP809_ID] = "AXP809", + [AXP813_ID] = "AXP813", + [AXP15060_ID] = "AXP15060", }; static const struct regmap_range axp152_writeable_ranges[] = { @@ -193,6 +194,10 @@ static const struct regmap_range axp313a_writeable_ranges[] = { regmap_reg_range(AXP313A_ON_INDICATE, AXP313A_IRQ_STATE), }; +static const struct regmap_range axp323_writeable_ranges[] = { + regmap_reg_range(AXP313A_ON_INDICATE, AXP323_DCDC_MODE_CTRL2), +}; + static const struct regmap_range axp313a_volatile_ranges[] = { regmap_reg_range(AXP313A_SHUTDOWN_CTRL, AXP313A_SHUTDOWN_CTRL), regmap_reg_range(AXP313A_IRQ_STATE, AXP313A_IRQ_STATE), @@ -203,6 +208,11 @@ static const struct regmap_access_table axp313a_writeable_table = { .n_yes_ranges = ARRAY_SIZE(axp313a_writeable_ranges), }; +static const struct regmap_access_table axp323_writeable_table = { + .yes_ranges = axp323_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(axp323_writeable_ranges), +}; + static const struct regmap_access_table axp313a_volatile_table = { .yes_ranges = axp313a_volatile_ranges, .n_yes_ranges = ARRAY_SIZE(axp313a_volatile_ranges), @@ -433,6 +443,15 @@ static const struct regmap_config axp313a_regmap_config = { .cache_type = REGCACHE_MAPLE, }; +static const struct regmap_config axp323_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &axp323_writeable_table, + .volatile_table = &axp313a_volatile_table, + .max_register = AXP323_DCDC_MODE_CTRL2, + .cache_type = REGCACHE_MAPLE, +}; + static const struct regmap_config axp717_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -1221,6 +1240,7 @@ static int axp20x_power_off(struct sys_off_data *data) unsigned int shutdown_reg; switch (axp20x->variant) { + case AXP323_ID: case AXP313A_ID: shutdown_reg = AXP313A_SHUTDOWN_CTRL; break; @@ -1289,6 +1309,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_cfg = &axp313a_regmap_config; axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip; break; + case AXP323_ID: + axp20x->nr_cells = ARRAY_SIZE(axp313a_cells); + axp20x->cells = axp313a_cells; + axp20x->regmap_cfg = &axp323_regmap_config; + axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip; + break; case AXP717_ID: axp20x->nr_cells = ARRAY_SIZE(axp717_cells); axp20x->cells = axp717_cells; @@ -1345,7 +1371,7 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_irq_chip = &axp15060_regmap_irq_chip; break; default: - dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); + dev_err(dev, "unsupported AXP20X ID %u\n", axp20x->variant); return -EINVAL; } @@ -1419,7 +1445,7 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) } } - ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells, + ret = mfd_add_devices(axp20x->dev, PLATFORM_DEVID_AUTO, axp20x->cells, axp20x->nr_cells, NULL, 0, NULL); if (ret) { diff --git a/drivers/mfd/cgbc-core.c b/drivers/mfd/cgbc-core.c new file mode 100644 index 00000000000000..85283c8dde253c --- /dev/null +++ b/drivers/mfd/cgbc-core.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Congatec Board Controller core driver. + * + * The x86 Congatec modules have an embedded micro controller named Board + * Controller. This Board Controller has a Watchdog timer, some GPIOs, and two + * I2C busses. + * + * Copyright (C) 2024 Bootlin + * + * Author: Thomas Richard + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CGBC_IO_SESSION_BASE 0x0E20 +#define CGBC_IO_SESSION_END 0x0E30 +#define CGBC_IO_CMD_BASE 0x0E00 +#define CGBC_IO_CMD_END 0x0E10 + +#define CGBC_MASK_STATUS (BIT(6) | BIT(7)) +#define CGBC_MASK_DATA_COUNT 0x1F +#define CGBC_MASK_ERROR_CODE 0x1F + +#define CGBC_STATUS_DATA_READY 0x00 +#define CGBC_STATUS_CMD_READY BIT(6) +#define CGBC_STATUS_ERROR (BIT(6) | BIT(7)) + +#define CGBC_SESSION_CMD 0x00 +#define CGBC_SESSION_CMD_IDLE 0x00 +#define CGBC_SESSION_CMD_REQUEST 0x01 +#define CGBC_SESSION_DATA 0x01 +#define CGBC_SESSION_STATUS 0x02 +#define CGBC_SESSION_STATUS_FREE 0x03 +#define CGBC_SESSION_ACCESS 0x04 +#define CGBC_SESSION_ACCESS_GAINED 0x00 + +#define CGBC_SESSION_VALID_MIN 0x02 +#define CGBC_SESSION_VALID_MAX 0xFE + +#define CGBC_CMD_STROBE 0x00 +#define CGBC_CMD_INDEX 0x02 +#define CGBC_CMD_INDEX_CBM_MAN8 0x00 +#define CGBC_CMD_INDEX_CBM_AUTO32 0x03 +#define CGBC_CMD_DATA 0x04 +#define CGBC_CMD_ACCESS 0x0C + +#define CGBC_CMD_GET_FW_REV 0x21 + +static struct platform_device *cgbc_pdev; + +/* Wait the Board Controller is ready to receive some session commands */ +static int cgbc_wait_device(struct cgbc_device_data *cgbc) +{ + u16 status; + int ret; + + ret = readx_poll_timeout(ioread16, cgbc->io_session + CGBC_SESSION_STATUS, status, + status == CGBC_SESSION_STATUS_FREE, 0, 500000); + + if (ret || ioread32(cgbc->io_session + CGBC_SESSION_ACCESS)) + ret = -ENODEV; + + return ret; +} + +static int cgbc_session_command(struct cgbc_device_data *cgbc, u8 cmd) +{ + int ret; + u8 val; + + ret = readx_poll_timeout(ioread8, cgbc->io_session + CGBC_SESSION_CMD, val, + val == CGBC_SESSION_CMD_IDLE, 0, 100000); + if (ret) + return ret; + + iowrite8(cmd, cgbc->io_session + CGBC_SESSION_CMD); + + ret = readx_poll_timeout(ioread8, cgbc->io_session + CGBC_SESSION_CMD, val, + val == CGBC_SESSION_CMD_IDLE, 0, 100000); + if (ret) + return ret; + + ret = (int)ioread8(cgbc->io_session + CGBC_SESSION_DATA); + + iowrite8(CGBC_SESSION_STATUS_FREE, cgbc->io_session + CGBC_SESSION_STATUS); + + return ret; +} + +static int cgbc_session_request(struct cgbc_device_data *cgbc) +{ + unsigned int ret; + + ret = cgbc_wait_device(cgbc); + + if (ret) + return dev_err_probe(cgbc->dev, ret, "device not found or not ready\n"); + + cgbc->session = cgbc_session_command(cgbc, CGBC_SESSION_CMD_REQUEST); + + /* The Board Controller sent us a wrong session handle, we cannot communicate with it */ + if (cgbc->session < CGBC_SESSION_VALID_MIN || cgbc->session > CGBC_SESSION_VALID_MAX) + return dev_err_probe(cgbc->dev, -ECONNREFUSED, + "failed to get a valid session handle\n"); + + return 0; +} + +static void cgbc_session_release(struct cgbc_device_data *cgbc) +{ + if (cgbc_session_command(cgbc, cgbc->session) != cgbc->session) + dev_warn(cgbc->dev, "failed to release session\n"); +} + +static bool cgbc_command_lock(struct cgbc_device_data *cgbc) +{ + iowrite8(cgbc->session, cgbc->io_cmd + CGBC_CMD_ACCESS); + + return ioread8(cgbc->io_cmd + CGBC_CMD_ACCESS) == cgbc->session; +} + +static void cgbc_command_unlock(struct cgbc_device_data *cgbc) +{ + iowrite8(cgbc->session, cgbc->io_cmd + CGBC_CMD_ACCESS); +} + +int cgbc_command(struct cgbc_device_data *cgbc, void *cmd, unsigned int cmd_size, void *data, + unsigned int data_size, u8 *status) +{ + u8 checksum = 0, data_checksum = 0, istatus = 0, val; + u8 *_data = (u8 *)data; + u8 *_cmd = (u8 *)cmd; + int mode_change = -1; + bool lock; + int ret, i; + + mutex_lock(&cgbc->lock); + + /* Request access */ + ret = readx_poll_timeout(cgbc_command_lock, cgbc, lock, lock, 0, 100000); + if (ret) + goto out; + + /* Wait board controller is ready */ + ret = readx_poll_timeout(ioread8, cgbc->io_cmd + CGBC_CMD_STROBE, val, + val == CGBC_CMD_STROBE, 0, 100000); + if (ret) + goto release; + + /* Write command packet */ + if (cmd_size <= 2) { + iowrite8(CGBC_CMD_INDEX_CBM_MAN8, cgbc->io_cmd + CGBC_CMD_INDEX); + } else { + iowrite8(CGBC_CMD_INDEX_CBM_AUTO32, cgbc->io_cmd + CGBC_CMD_INDEX); + if ((cmd_size % 4) != 0x03) + mode_change = (cmd_size & 0xFFFC) - 1; + } + + for (i = 0; i < cmd_size; i++) { + iowrite8(_cmd[i], cgbc->io_cmd + CGBC_CMD_DATA + (i % 4)); + checksum ^= _cmd[i]; + if (mode_change == i) + iowrite8((i + 1) | CGBC_CMD_INDEX_CBM_MAN8, cgbc->io_cmd + CGBC_CMD_INDEX); + } + + /* Append checksum byte */ + iowrite8(checksum, cgbc->io_cmd + CGBC_CMD_DATA + (i % 4)); + + /* Perform command strobe */ + iowrite8(cgbc->session, cgbc->io_cmd + CGBC_CMD_STROBE); + + /* Rewind cmd buffer index */ + iowrite8(CGBC_CMD_INDEX_CBM_AUTO32, cgbc->io_cmd + CGBC_CMD_INDEX); + + /* Wait command completion */ + ret = read_poll_timeout(ioread8, val, val == CGBC_CMD_STROBE, 0, 100000, false, + cgbc->io_cmd + CGBC_CMD_STROBE); + if (ret) + goto release; + + istatus = ioread8(cgbc->io_cmd + CGBC_CMD_DATA); + checksum = istatus; + + /* Check command status */ + switch (istatus & CGBC_MASK_STATUS) { + case CGBC_STATUS_DATA_READY: + if (istatus > data_size) + istatus = data_size; + for (i = 0; i < istatus; i++) { + _data[i] = ioread8(cgbc->io_cmd + CGBC_CMD_DATA + ((i + 1) % 4)); + checksum ^= _data[i]; + } + data_checksum = ioread8(cgbc->io_cmd + CGBC_CMD_DATA + ((i + 1) % 4)); + istatus &= CGBC_MASK_DATA_COUNT; + break; + case CGBC_STATUS_ERROR: + case CGBC_STATUS_CMD_READY: + data_checksum = ioread8(cgbc->io_cmd + CGBC_CMD_DATA + 1); + if ((istatus & CGBC_MASK_STATUS) == CGBC_STATUS_ERROR) + ret = -EIO; + istatus = istatus & CGBC_MASK_ERROR_CODE; + break; + default: + data_checksum = ioread8(cgbc->io_cmd + CGBC_CMD_DATA + 1); + istatus &= CGBC_MASK_ERROR_CODE; + ret = -EIO; + break; + } + + /* Checksum verification */ + if (ret == 0 && data_checksum != checksum) + ret = -EIO; + +release: + cgbc_command_unlock(cgbc); + +out: + mutex_unlock(&cgbc->lock); + + if (status) + *status = istatus; + + return ret; +} +EXPORT_SYMBOL_GPL(cgbc_command); + +static struct mfd_cell cgbc_devs[] = { + { .name = "cgbc-wdt" }, + { .name = "cgbc-gpio" }, + { .name = "cgbc-i2c", .id = 1 }, + { .name = "cgbc-i2c", .id = 2 }, +}; + +static int cgbc_map(struct cgbc_device_data *cgbc) +{ + struct device *dev = cgbc->dev; + struct platform_device *pdev = to_platform_device(dev); + struct resource *ioport; + + ioport = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!ioport) + return -EINVAL; + + cgbc->io_session = devm_ioport_map(dev, ioport->start, resource_size(ioport)); + if (!cgbc->io_session) + return -ENOMEM; + + ioport = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (!ioport) + return -EINVAL; + + cgbc->io_cmd = devm_ioport_map(dev, ioport->start, resource_size(ioport)); + if (!cgbc->io_cmd) + return -ENOMEM; + + return 0; +} + +static const struct resource cgbc_resources[] = { + { + .start = CGBC_IO_SESSION_BASE, + .end = CGBC_IO_SESSION_END, + .flags = IORESOURCE_IO, + }, + { + .start = CGBC_IO_CMD_BASE, + .end = CGBC_IO_CMD_END, + .flags = IORESOURCE_IO, + }, +}; + +static ssize_t cgbc_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cgbc_device_data *cgbc = dev_get_drvdata(dev); + + return sysfs_emit(buf, "CGBCP%c%c%c\n", cgbc->version.feature, cgbc->version.major, + cgbc->version.minor); +} + +static DEVICE_ATTR_RO(cgbc_version); + +static struct attribute *cgbc_attrs[] = { + &dev_attr_cgbc_version.attr, + NULL +}; + +ATTRIBUTE_GROUPS(cgbc); + +static int cgbc_get_version(struct cgbc_device_data *cgbc) +{ + u8 cmd = CGBC_CMD_GET_FW_REV; + u8 data[4]; + int ret; + + ret = cgbc_command(cgbc, &cmd, 1, &data, sizeof(data), NULL); + if (ret) + return ret; + + cgbc->version.feature = data[0]; + cgbc->version.major = data[1]; + cgbc->version.minor = data[2]; + + return 0; +} + +static int cgbc_init_device(struct cgbc_device_data *cgbc) +{ + int ret; + + ret = cgbc_session_request(cgbc); + if (ret) + return ret; + + ret = cgbc_get_version(cgbc); + if (ret) + goto release_session; + + ret = mfd_add_devices(cgbc->dev, -1, cgbc_devs, ARRAY_SIZE(cgbc_devs), + NULL, 0, NULL); + if (ret) + goto release_session; + + return 0; + +release_session: + cgbc_session_release(cgbc); + return ret; +} + +static int cgbc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cgbc_device_data *cgbc; + int ret; + + cgbc = devm_kzalloc(dev, sizeof(*cgbc), GFP_KERNEL); + if (!cgbc) + return -ENOMEM; + + cgbc->dev = dev; + + ret = cgbc_map(cgbc); + if (ret) + return ret; + + mutex_init(&cgbc->lock); + + platform_set_drvdata(pdev, cgbc); + + return cgbc_init_device(cgbc); +} + +static void cgbc_remove(struct platform_device *pdev) +{ + struct cgbc_device_data *cgbc = platform_get_drvdata(pdev); + + cgbc_session_release(cgbc); + + mfd_remove_devices(&pdev->dev); +} + +static struct platform_driver cgbc_driver = { + .driver = { + .name = "cgbc", + .dev_groups = cgbc_groups, + }, + .probe = cgbc_probe, + .remove = cgbc_remove, +}; + +static const struct dmi_system_id cgbc_dmi_table[] __initconst = { + { + .ident = "SA7", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "congatec"), + DMI_MATCH(DMI_BOARD_NAME, "conga-SA7"), + }, + }, + {} +}; +MODULE_DEVICE_TABLE(dmi, cgbc_dmi_table); + +static int __init cgbc_init(void) +{ + const struct dmi_system_id *id; + int ret = -ENODEV; + + id = dmi_first_match(cgbc_dmi_table); + if (IS_ERR_OR_NULL(id)) + return ret; + + cgbc_pdev = platform_device_register_simple("cgbc", PLATFORM_DEVID_NONE, cgbc_resources, + ARRAY_SIZE(cgbc_resources)); + if (IS_ERR(cgbc_pdev)) + return PTR_ERR(cgbc_pdev); + + return platform_driver_register(&cgbc_driver); +} + +static void __exit cgbc_exit(void) +{ + platform_device_unregister(cgbc_pdev); + platform_driver_unregister(&cgbc_driver); +} + +module_init(cgbc_init); +module_exit(cgbc_exit); + +MODULE_DESCRIPTION("Congatec Board Controller Core Driver"); +MODULE_AUTHOR("Thomas Richard "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cgbc-core"); diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index f3dc812b359f34..9f84a52b48d6a8 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -108,6 +108,10 @@ static const struct mfd_cell cros_ec_keyboard_leds_cells[] = { { .name = "cros-keyboard-leds", }, }; +static const struct mfd_cell cros_ec_ucsi_cells[] = { + { .name = "cros_ec_ucsi", }, +}; + static const struct cros_feature_to_cells cros_subdevices[] = { { .id = EC_FEATURE_CEC, @@ -125,9 +129,9 @@ static const struct cros_feature_to_cells cros_subdevices[] = { .num_cells = ARRAY_SIZE(cros_ec_rtc_cells), }, { - .id = EC_FEATURE_USB_PD, - .mfd_cells = cros_usbpd_charger_cells, - .num_cells = ARRAY_SIZE(cros_usbpd_charger_cells), + .id = EC_FEATURE_UCSI_PPM, + .mfd_cells = cros_ec_ucsi_cells, + .num_cells = ARRAY_SIZE(cros_ec_ucsi_cells), }, { .id = EC_FEATURE_HANG_DETECT, @@ -252,6 +256,21 @@ static int ec_device_probe(struct platform_device *pdev) } } + /* + * UCSI provides power supply information so we don't need to separately + * load the cros_usbpd_charger driver. + */ + if (cros_ec_check_features(ec, EC_FEATURE_USB_PD) && + !cros_ec_check_features(ec, EC_FEATURE_UCSI_PPM)) { + retval = mfd_add_hotplug_devices(ec->dev, + cros_usbpd_charger_cells, + ARRAY_SIZE(cros_usbpd_charger_cells)); + + if (retval) + dev_warn(ec->dev, "failed to add usbpd-charger: %d\n", + retval); + } + /* * Lightbar is a special case. Newer devices support autodetection, * but older ones do not. @@ -346,7 +365,7 @@ static struct platform_driver cros_ec_dev_driver = { }, .id_table = cros_ec_id, .probe = ec_device_probe, - .remove_new = ec_device_remove, + .remove = ec_device_remove, }; static int __init cros_ec_dev_init(void) diff --git a/drivers/mfd/cs40l50-core.c b/drivers/mfd/cs40l50-core.c index 26e7a769eb1427..4859a33777a04c 100644 --- a/drivers/mfd/cs40l50-core.c +++ b/drivers/mfd/cs40l50-core.c @@ -567,4 +567,4 @@ EXPORT_GPL_DEV_PM_OPS(cs40l50_pm_ops) = { MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver"); MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(FW_CS_DSP); +MODULE_IMPORT_NS("FW_CS_DSP"); diff --git a/drivers/mfd/cs42l43-i2c.c b/drivers/mfd/cs42l43-i2c.c index c9e4ea76149a88..f0ad4002652dc4 100644 --- a/drivers/mfd/cs42l43-i2c.c +++ b/drivers/mfd/cs42l43-i2c.c @@ -92,7 +92,7 @@ static struct i2c_driver cs42l43_i2c_driver = { }; module_i2c_driver(cs42l43_i2c_driver); -MODULE_IMPORT_NS(MFD_CS42L43); +MODULE_IMPORT_NS("MFD_CS42L43"); MODULE_DESCRIPTION("CS42L43 I2C Driver"); MODULE_AUTHOR("Charles Keepax "); diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c index 65f7b1d7824861..3938d48039c485 100644 --- a/drivers/mfd/cs42l43-sdw.c +++ b/drivers/mfd/cs42l43-sdw.c @@ -215,7 +215,7 @@ static struct sdw_driver cs42l43_sdw_driver = { }; module_sdw_driver(cs42l43_sdw_driver); -MODULE_IMPORT_NS(MFD_CS42L43); +MODULE_IMPORT_NS("MFD_CS42L43"); MODULE_DESCRIPTION("CS42L43 SoundWire Driver"); MODULE_AUTHOR("Lucas Tanure "); diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c index ae8fd37afb7548..b5ab5e613db79c 100644 --- a/drivers/mfd/cs42l43.c +++ b/drivers/mfd/cs42l43.c @@ -264,7 +264,7 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { { CS42L43_ASRC_MASK, 0x0000000F }, { CS42L43_HPOUT_MASK, 0x00000003 }, }; -EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, "MFD_CS42L43"); bool cs42l43_readable_register(struct device *dev, unsigned int reg) { @@ -392,7 +392,7 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, "MFD_CS42L43"); bool cs42l43_precious_register(struct device *dev, unsigned int reg) { @@ -407,7 +407,7 @@ bool cs42l43_precious_register(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, "MFD_CS42L43"); bool cs42l43_volatile_register(struct device *dev, unsigned int reg) { @@ -435,7 +435,7 @@ bool cs42l43_volatile_register(struct device *dev, unsigned int reg) return cs42l43_precious_register(dev, reg); } } -EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, "MFD_CS42L43"); #define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT) @@ -967,7 +967,6 @@ static void cs42l43_boot_work(struct work_struct *work) err: pm_runtime_put_sync(cs42l43->dev); - cs42l43_dev_remove(cs42l43); } static int cs42l43_power_up(struct cs42l43 *cs42l43) @@ -1097,27 +1096,52 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) return 0; } -EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, "MFD_CS42L43"); void cs42l43_dev_remove(struct cs42l43 *cs42l43) { + cancel_work_sync(&cs42l43->boot_work); + cs42l43_power_down(cs42l43); } -EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, "MFD_CS42L43"); static int cs42l43_suspend(struct device *dev) { struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + static const struct reg_sequence mask_all[] = { + { CS42L43_DECIM_MASK, 0xFFFFFFFF, }, + { CS42L43_EQ_MIX_MASK, 0xFFFFFFFF, }, + { CS42L43_ASP_MASK, 0xFFFFFFFF, }, + { CS42L43_PLL_MASK, 0xFFFFFFFF, }, + { CS42L43_SOFT_MASK, 0xFFFFFFFF, }, + { CS42L43_SWIRE_MASK, 0xFFFFFFFF, }, + { CS42L43_MSM_MASK, 0xFFFFFFFF, }, + { CS42L43_ACC_DET_MASK, 0xFFFFFFFF, }, + { CS42L43_I2C_TGT_MASK, 0xFFFFFFFF, }, + { CS42L43_SPI_MSTR_MASK, 0xFFFFFFFF, }, + { CS42L43_SW_TO_SPI_BRIDGE_MASK, 0xFFFFFFFF, }, + { CS42L43_OTP_MASK, 0xFFFFFFFF, }, + { CS42L43_CLASS_D_AMP_MASK, 0xFFFFFFFF, }, + { CS42L43_GPIO_INT_MASK, 0xFFFFFFFF, }, + { CS42L43_ASRC_MASK, 0xFFFFFFFF, }, + { CS42L43_HPOUT_MASK, 0xFFFFFFFF, }, + }; int ret; - /* - * Don't care about being resumed here, but the driver does want - * force_resume to always trigger an actual resume, so that register - * state for the MCU/GPIOs is returned as soon as possible after system - * resume. force_resume will resume if the reference count is resumed on - * suspend hence the get_noresume. - */ - pm_runtime_get_noresume(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(cs42l43->dev, "Failed to resume for suspend: %d\n", ret); + return ret; + } + + /* The IRQs will be re-enabled on resume by the cache sync */ + ret = regmap_multi_reg_write_bypassed(cs42l43->regmap, + mask_all, ARRAY_SIZE(mask_all)); + if (ret) { + dev_err(cs42l43->dev, "Failed to mask IRQs: %d\n", ret); + return ret; + } ret = pm_runtime_force_suspend(dev); if (ret) { @@ -1132,6 +1156,26 @@ static int cs42l43_suspend(struct device *dev) if (ret) return ret; + disable_irq(cs42l43->irq); + + return 0; +} + +static int cs42l43_suspend_noirq(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + enable_irq(cs42l43->irq); + + return 0; +} + +static int cs42l43_resume_noirq(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + disable_irq(cs42l43->irq); + return 0; } @@ -1144,6 +1188,8 @@ static int cs42l43_resume(struct device *dev) if (ret) return ret; + enable_irq(cs42l43->irq); + ret = pm_runtime_force_resume(dev); if (ret) { dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret); @@ -1211,6 +1257,7 @@ static int cs42l43_runtime_resume(struct device *dev) EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = { SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend_noirq, cs42l43_resume_noirq) RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL) }; diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index be5f2b34e18aeb..80fc5c0cac2fb0 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -37,7 +37,7 @@ static int da9052_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, da9052); config = da9052_regmap_config; - config.read_flag_mask = 1; + config.write_flag_mask = 1; config.reg_bits = 7; config.pad_bits = 1; config.val_bits = 8; diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c index e58990c85ed878..6a585173230b13 100644 --- a/drivers/mfd/exynos-lpass.c +++ b/drivers/mfd/exynos-lpass.c @@ -179,13 +179,13 @@ static const struct of_device_id exynos_lpass_of_match[] = { MODULE_DEVICE_TABLE(of, exynos_lpass_of_match); static struct platform_driver exynos_lpass_driver = { - .driver = { + .driver = { .name = "exynos-lpass", .pm = &lpass_pm_ops, .of_match_table = exynos_lpass_of_match, }, .probe = exynos_lpass_probe, - .remove_new = exynos_lpass_remove, + .remove = exynos_lpass_remove, }; module_platform_driver(exynos_lpass_driver); diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index 2e4ab24041547c..6fe388da6fb6e8 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -211,7 +211,7 @@ static struct platform_driver mx25_tsadc_driver = { .of_match_table = mx25_tsadc_ids, }, .probe = mx25_tsadc_probe, - .remove_new = mx25_tsadc_remove, + .remove = mx25_tsadc_remove, }; module_platform_driver(mx25_tsadc_driver); diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index 5f61909c85e926..3b4ffcbbee204a 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -159,12 +159,12 @@ static const struct of_device_id hi655x_pmic_match[] = { MODULE_DEVICE_TABLE(of, hi655x_pmic_match); static struct platform_driver hi655x_pmic_driver = { - .driver = { - .name = "hi655x-pmic", + .driver = { + .name = "hi655x-pmic", .of_match_table = hi655x_pmic_match, }, - .probe = hi655x_pmic_probe, - .remove_new = hi655x_pmic_remove, + .probe = hi655x_pmic_probe, + .remove = hi655x_pmic_remove, }; module_platform_driver(hi655x_pmic_driver); diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index 2a83f8678f1d92..63406026d80966 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -208,7 +208,7 @@ static void intel_lpss_acpi_remove(struct platform_device *pdev) static struct platform_driver intel_lpss_acpi_driver = { .probe = intel_lpss_acpi_probe, - .remove_new = intel_lpss_acpi_remove, + .remove = intel_lpss_acpi_remove, .driver = { .name = "intel-lpss", .acpi_match_table = intel_lpss_acpi_ids, @@ -222,4 +222,4 @@ MODULE_AUTHOR("Andy Shevchenko "); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel LPSS ACPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(INTEL_LPSS); +MODULE_IMPORT_NS("INTEL_LPSS"); diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 1d8cdc4d5819b6..1a5b8b13f8d0b2 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -653,4 +653,4 @@ MODULE_AUTHOR("Andy Shevchenko "); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel LPSS PCI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(INTEL_LPSS); +MODULE_IMPORT_NS("INTEL_LPSS"); diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 2a9018112dfc86..3ba05ebb90359f 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -464,7 +464,7 @@ int intel_lpss_probe(struct device *dev, return ret; } -EXPORT_SYMBOL_NS_GPL(intel_lpss_probe, INTEL_LPSS); +EXPORT_SYMBOL_NS_GPL(intel_lpss_probe, "INTEL_LPSS"); void intel_lpss_remove(struct device *dev) { @@ -476,7 +476,7 @@ void intel_lpss_remove(struct device *dev) intel_lpss_unregister_clock(lpss); ida_free(&intel_lpss_devid_ida, lpss->devid); } -EXPORT_SYMBOL_NS_GPL(intel_lpss_remove, INTEL_LPSS); +EXPORT_SYMBOL_NS_GPL(intel_lpss_remove, "INTEL_LPSS"); static int resume_lpss_device(struct device *dev, void *data) { diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c index 8ad5b382158419..e930161bf65eac 100644 --- a/drivers/mfd/intel-m10-bmc-core.c +++ b/drivers/mfd/intel-m10-bmc-core.c @@ -22,7 +22,7 @@ void m10bmc_fw_state_set(struct intel_m10bmc *m10bmc, enum m10bmc_fw_state new_s m10bmc->bmcfw_state = new_state; up_write(&m10bmc->bmcfw_lock); } -EXPORT_SYMBOL_NS_GPL(m10bmc_fw_state_set, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_fw_state_set, "INTEL_M10_BMC_CORE"); /* * For some Intel FPGA devices, the BMC firmware is not available to service @@ -75,7 +75,7 @@ int m10bmc_sys_read(struct intel_m10bmc *m10bmc, unsigned int offset, unsigned i return ret; } -EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, "INTEL_M10_BMC_CORE"); int m10bmc_sys_update_bits(struct intel_m10bmc *m10bmc, unsigned int offset, unsigned int msk, unsigned int val) @@ -95,7 +95,7 @@ int m10bmc_sys_update_bits(struct intel_m10bmc *m10bmc, unsigned int offset, return ret; } -EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, "INTEL_M10_BMC_CORE"); static ssize_t bmc_version_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -183,7 +183,7 @@ const struct attribute_group *m10bmc_dev_groups[] = { &m10bmc_group, NULL, }; -EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, "INTEL_M10_BMC_CORE"); int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info) { @@ -201,7 +201,7 @@ int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platf return ret; } -EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, "INTEL_M10_BMC_CORE"); MODULE_DESCRIPTION("Intel MAX 10 BMC core driver"); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c index 4fa9d380c62b5f..d213c6ec04bad0 100644 --- a/drivers/mfd/intel-m10-bmc-pmci.c +++ b/drivers/mfd/intel-m10-bmc-pmci.c @@ -454,4 +454,4 @@ module_dfl_driver(m10bmc_pmci_driver); MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface"); MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); +MODULE_IMPORT_NS("INTEL_M10_BMC_CORE"); diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c index 36f631ef7a6774..cfa620f0c70e19 100644 --- a/drivers/mfd/intel-m10-bmc-spi.c +++ b/drivers/mfd/intel-m10-bmc-spi.c @@ -181,4 +181,4 @@ MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface"); MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:intel-m10-bmc"); -MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); +MODULE_IMPORT_NS("INTEL_M10_BMC_CORE"); diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index ccd76800d8e49b..9d89171d83f9a5 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -6,16 +6,27 @@ */ #include +#include #include #include +#include #include +#include +#include #include -#include +#include +#include #include #include #include +#include #include #include +#include +#include +#include +#include +#include /* PMIC device registers */ #define REG_ADDR_MASK GENMASK(15, 8) @@ -148,6 +159,7 @@ static const struct regmap_irq_chip bxtwc_regmap_irq_chip = { static const struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = { .name = "bxtwc_irq_chip_pwrbtn", + .domain_suffix = "PWRBTN", .status_base = BXTWC_PWRBTNIRQ, .mask_base = BXTWC_MPWRBTNIRQ, .irqs = bxtwc_regmap_irqs_pwrbtn, @@ -157,6 +169,7 @@ static const struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = { static const struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { .name = "bxtwc_irq_chip_tmu", + .domain_suffix = "TMU", .status_base = BXTWC_TMUIRQ, .mask_base = BXTWC_MTMUIRQ, .irqs = bxtwc_regmap_irqs_tmu, @@ -166,6 +179,7 @@ static const struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { static const struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { .name = "bxtwc_irq_chip_bcu", + .domain_suffix = "BCU", .status_base = BXTWC_BCUIRQ, .mask_base = BXTWC_MBCUIRQ, .irqs = bxtwc_regmap_irqs_bcu, @@ -175,6 +189,7 @@ static const struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { static const struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { .name = "bxtwc_irq_chip_adc", + .domain_suffix = "ADC", .status_base = BXTWC_ADCIRQ, .mask_base = BXTWC_MADCIRQ, .irqs = bxtwc_regmap_irqs_adc, @@ -184,6 +199,7 @@ static const struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { static const struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { .name = "bxtwc_irq_chip_chgr", + .domain_suffix = "CHGR", .status_base = BXTWC_CHGR0IRQ, .mask_base = BXTWC_MCHGR0IRQ, .irqs = bxtwc_regmap_irqs_chgr, @@ -193,6 +209,7 @@ static const struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { static const struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = { .name = "bxtwc_irq_chip_crit", + .domain_suffix = "CRIT", .status_base = BXTWC_CRITIRQ, .mask_base = BXTWC_MCRITIRQ, .irqs = bxtwc_regmap_irqs_crit, @@ -230,44 +247,55 @@ static const struct resource tmu_resources[] = { }; static struct mfd_cell bxt_wc_dev[] = { - { - .name = "bxt_wcove_gpadc", - .num_resources = ARRAY_SIZE(adc_resources), - .resources = adc_resources, - }, { .name = "bxt_wcove_thermal", .num_resources = ARRAY_SIZE(thermal_resources), .resources = thermal_resources, }, { - .name = "bxt_wcove_usbc", - .num_resources = ARRAY_SIZE(usbc_resources), - .resources = usbc_resources, + .name = "bxt_wcove_gpio", + .num_resources = ARRAY_SIZE(gpio_resources), + .resources = gpio_resources, }, { - .name = "bxt_wcove_ext_charger", - .num_resources = ARRAY_SIZE(charger_resources), - .resources = charger_resources, + .name = "bxt_wcove_region", }, +}; + +static const struct mfd_cell bxt_wc_tmu_dev[] = { + { + .name = "bxt_wcove_tmu", + .num_resources = ARRAY_SIZE(tmu_resources), + .resources = tmu_resources, + }, +}; + +static const struct mfd_cell bxt_wc_bcu_dev[] = { { .name = "bxt_wcove_bcu", .num_resources = ARRAY_SIZE(bcu_resources), .resources = bcu_resources, }, +}; + +static const struct mfd_cell bxt_wc_adc_dev[] = { { - .name = "bxt_wcove_tmu", - .num_resources = ARRAY_SIZE(tmu_resources), - .resources = tmu_resources, + .name = "bxt_wcove_gpadc", + .num_resources = ARRAY_SIZE(adc_resources), + .resources = adc_resources, }, +}; +static struct mfd_cell bxt_wc_chgr_dev[] = { { - .name = "bxt_wcove_gpio", - .num_resources = ARRAY_SIZE(gpio_resources), - .resources = gpio_resources, + .name = "bxt_wcove_usbc", + .num_resources = ARRAY_SIZE(usbc_resources), + .resources = usbc_resources, }, { - .name = "bxt_wcove_region", + .name = "bxt_wcove_ext_charger", + .num_resources = ARRAY_SIZE(charger_resources), + .resources = charger_resources, }, }; @@ -347,6 +375,7 @@ static ssize_t addr_store(struct device *dev, return count; } +static DEVICE_ATTR_ADMIN_RW(addr); static ssize_t val_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -383,23 +412,14 @@ static ssize_t val_store(struct device *dev, } return count; } - -static DEVICE_ATTR_ADMIN_RW(addr); static DEVICE_ATTR_ADMIN_RW(val); + static struct attribute *bxtwc_attrs[] = { &dev_attr_addr.attr, &dev_attr_val.attr, NULL }; - -static const struct attribute_group bxtwc_group = { - .attrs = bxtwc_attrs, -}; - -static const struct attribute_group *bxtwc_groups[] = { - &bxtwc_group, - NULL -}; +ATTRIBUTE_GROUPS(bxtwc); static const struct regmap_config bxtwc_regmap_config = { .reg_bits = 16, @@ -414,15 +434,39 @@ static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data) { - int irq; + struct device *dev = pmic->dev; + int irq, ret; irq = regmap_irq_get_virq(pdata, pirq); if (irq < 0) - return dev_err_probe(pmic->dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", + return dev_err_probe(dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", pirq, chip->name); - return devm_regmap_add_irq_chip(pmic->dev, pmic->regmap, irq, irq_flags, - 0, chip, data); + ret = devm_regmap_add_irq_chip(dev, pmic->regmap, irq, irq_flags, 0, chip, data); + if (ret) + return dev_err_probe(dev, ret, "Failed to add %s IRQ chip\n", chip->name); + + return 0; +} + +static int bxtwc_add_chained_devices(struct intel_soc_pmic *pmic, + const struct mfd_cell *cells, int n_devs, + struct regmap_irq_chip_data *pdata, + int pirq, int irq_flags, + const struct regmap_irq_chip *chip, + struct regmap_irq_chip_data **data) +{ + struct device *dev = pmic->dev; + struct irq_domain *domain; + int ret; + + ret = bxtwc_add_chained_irq_chip(pmic, pdata, pirq, irq_flags, chip, data); + if (ret) + return ret; + + domain = regmap_irq_get_domain(*data); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, cells, n_devs, NULL, 0, domain); } static int bxtwc_probe(struct platform_device *pdev) @@ -466,48 +510,49 @@ static int bxtwc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_tmu_dev, ARRAY_SIZE(bxt_wc_tmu_dev), + pmic->irq_chip_data, + BXTWC_TMU_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_tmu, + &pmic->irq_chip_data_tmu); + if (ret) + return ret; + ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, BXTWC_PWRBTN_LVL1_IRQ, IRQF_ONESHOT, &bxtwc_regmap_irq_chip_pwrbtn, &pmic->irq_chip_data_pwrbtn); if (ret) - return dev_err_probe(dev, ret, "Failed to add PWRBTN IRQ chip\n"); - - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_TMU_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_tmu, - &pmic->irq_chip_data_tmu); - if (ret) - return dev_err_probe(dev, ret, "Failed to add TMU IRQ chip\n"); + return ret; - /* Add chained IRQ handler for BCU IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_BCU_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_bcu, - &pmic->irq_chip_data_bcu); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_bcu_dev, ARRAY_SIZE(bxt_wc_bcu_dev), + pmic->irq_chip_data, + BXTWC_BCU_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_bcu, + &pmic->irq_chip_data_bcu); if (ret) - return dev_err_probe(dev, ret, "Failed to add BUC IRQ chip\n"); + return ret; - /* Add chained IRQ handler for ADC IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_ADC_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_adc, - &pmic->irq_chip_data_adc); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_adc_dev, ARRAY_SIZE(bxt_wc_adc_dev), + pmic->irq_chip_data, + BXTWC_ADC_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_adc, + &pmic->irq_chip_data_adc); if (ret) - return dev_err_probe(dev, ret, "Failed to add ADC IRQ chip\n"); + return ret; - /* Add chained IRQ handler for CHGR IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_CHGR_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_chgr, - &pmic->irq_chip_data_chgr); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_chgr_dev, ARRAY_SIZE(bxt_wc_chgr_dev), + pmic->irq_chip_data, + BXTWC_CHGR_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_chgr, + &pmic->irq_chip_data_chgr); if (ret) - return dev_err_probe(dev, ret, "Failed to add CHGR IRQ chip\n"); + return ret; /* Add chained IRQ handler for CRIT IRQs */ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, @@ -516,7 +561,7 @@ static int bxtwc_probe(struct platform_device *pdev) &bxtwc_regmap_irq_chip_crit, &pmic->irq_chip_data_crit); if (ret) - return dev_err_probe(dev, ret, "Failed to add CRIT IRQ chip\n"); + return ret; ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, bxt_wc_dev, ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL); @@ -571,7 +616,7 @@ static struct platform_driver bxtwc_driver = { .probe = bxtwc_probe, .shutdown = bxtwc_shutdown, .driver = { - .name = "BXTWC PMIC", + .name = "intel_soc_pmic_bxtwc", .pm = pm_sleep_ptr(&bxtwc_pm_ops), .acpi_match_table = bxtwc_acpi_ids, .dev_groups = bxtwc_groups, diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c index 2a83f540d4c9d8..aa71a7d83fcd17 100644 --- a/drivers/mfd/intel_soc_pmic_chtwc.c +++ b/drivers/mfd/intel_soc_pmic_chtwc.c @@ -267,7 +267,7 @@ static const struct acpi_device_id cht_wc_acpi_ids[] = { static struct i2c_driver cht_wc_driver = { .driver = { - .name = "CHT Whiskey Cove PMIC", + .name = "intel_soc_pmic_chtwc", .pm = pm_sleep_ptr(&cht_wc_pm_ops), .acpi_match_table = cht_wc_acpi_ids, }, diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 876d017f74feea..879fbf5cd1622b 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -259,12 +259,19 @@ static const struct acpi_device_id crystal_cove_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, crystal_cove_acpi_match); +static const struct i2c_device_id crystal_cove_i2c_match[] = { + { "intel_soc_pmic_crc" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, crystal_cove_i2c_match); + static struct i2c_driver crystal_cove_i2c_driver = { .driver = { - .name = "crystal_cove_i2c", + .name = "intel_soc_pmic_crc", .pm = pm_sleep_ptr(&crystal_cove_pm_ops), .acpi_match_table = crystal_cove_acpi_match, }, + .id_table = crystal_cove_i2c_match, .probe = crystal_cove_i2c_probe, .remove = crystal_cove_i2c_remove, .shutdown = crystal_cove_shutdown, diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index c964ea6539aa67..2370b44e221448 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -130,6 +130,7 @@ static void micro_rx_msg(struct ipaq_micro *micro, u8 id, int len, u8 *data) default: dev_err(micro->dev, "unknown msg %d [%d] %*ph\n", id, len, len, data); + break; } spin_unlock(µ->lock); } diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 8a332852bf97d0..c5bfb6440a930f 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -486,7 +486,7 @@ static struct platform_driver kempld_driver = { .dev_groups = pld_groups, }, .probe = kempld_probe, - .remove_new = kempld_remove, + .remove = kempld_remove, }; static const struct dmi_system_id kempld_dmi_table[] __initconst = { diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 3883e472b739de..228c4a2f4c1fa2 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -286,7 +286,7 @@ static const struct dev_pm_ops mcp_sa11x0_pm_ops = { static struct platform_driver mcp_sa11x0_driver = { .probe = mcp_sa11x0_probe, - .remove_new = mcp_sa11x0_remove, + .remove = mcp_sa11x0_remove, .driver = { .name = DRIVER_NAME, .pm = pm_sleep_ptr(&mcp_sa11x0_pm_ops), diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index c2939e785818fc..0e5d59ae064a69 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -13,12 +13,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -87,6 +89,13 @@ static const struct resource mt6323_keys_resources[] = { DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_FCHRKEY, "homekey"), }; +static const struct resource mt6328_keys_resources[] = { + DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_PWRKEY, "powerkey"), + DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_HOMEKEY, "homekey"), + DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_PWRKEY_R, "powerkey_r"), + DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_HOMEKEY_R, "homekey_r"), +}; + static const struct resource mt6357_keys_resources[] = { DEFINE_RES_IRQ_NAMED(MT6357_IRQ_PWRKEY, "powerkey"), DEFINE_RES_IRQ_NAMED(MT6357_IRQ_HOMEKEY, "homekey"), @@ -133,6 +142,18 @@ static const struct mfd_cell mt6323_devs[] = { }, }; +static const struct mfd_cell mt6328_devs[] = { + { + .name = "mt6328-regulator", + .of_compatible = "mediatek,mt6328-regulator" + }, { + .name = "mtk-pmic-keys", + .num_resources = ARRAY_SIZE(mt6328_keys_resources), + .resources = mt6328_keys_resources, + .of_compatible = "mediatek,mt6328-keys" + }, +}; + static const struct mfd_cell mt6357_devs[] = { { .name = "mt6359-auxadc", @@ -262,6 +283,14 @@ static const struct chip_data mt6323_core = { .irq_init = mt6397_irq_init, }; +static const struct chip_data mt6328_core = { + .cid_addr = MT6328_HWCID, + .cid_shift = 0, + .cells = mt6328_devs, + .cell_size = ARRAY_SIZE(mt6328_devs), + .irq_init = mt6397_irq_init, +}; + static const struct chip_data mt6357_core = { .cid_addr = MT6357_SWCID, .cid_shift = 8, @@ -360,6 +389,9 @@ static const struct of_device_id mt6397_of_match[] = { { .compatible = "mediatek,mt6323", .data = &mt6323_core, + }, { + .compatible = "mediatek,mt6328", + .data = &mt6328_core, }, { .compatible = "mediatek,mt6331", .data = &mt6331_mt6332_core, diff --git a/drivers/mfd/mt6397-irq.c b/drivers/mfd/mt6397-irq.c index 886745b5b607c3..1310665200ede4 100644 --- a/drivers/mfd/mt6397-irq.c +++ b/drivers/mfd/mt6397-irq.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -31,6 +33,9 @@ static void mt6397_irq_sync_unlock(struct irq_data *data) mt6397->irq_masks_cur[0]); regmap_write(mt6397->regmap, mt6397->int_con[1], mt6397->irq_masks_cur[1]); + if (mt6397->int_con[2]) + regmap_write(mt6397->regmap, mt6397->int_con[2], + mt6397->irq_masks_cur[2]); mutex_unlock(&mt6397->irqlock); } @@ -105,6 +110,8 @@ static irqreturn_t mt6397_irq_thread(int irq, void *data) mt6397_irq_handle_reg(mt6397, mt6397->int_status[0], 0); mt6397_irq_handle_reg(mt6397, mt6397->int_status[1], 16); + if (mt6397->int_status[2]) + mt6397_irq_handle_reg(mt6397, mt6397->int_status[2], 32); return IRQ_HANDLED; } @@ -138,6 +145,9 @@ static int mt6397_irq_pm_notifier(struct notifier_block *notifier, chip->int_con[0], chip->wake_mask[0]); regmap_write(chip->regmap, chip->int_con[1], chip->wake_mask[1]); + if (chip->int_con[2]) + regmap_write(chip->regmap, + chip->int_con[2], chip->wake_mask[2]); enable_irq_wake(chip->irq); break; @@ -146,6 +156,9 @@ static int mt6397_irq_pm_notifier(struct notifier_block *notifier, chip->int_con[0], chip->irq_masks_cur[0]); regmap_write(chip->regmap, chip->int_con[1], chip->irq_masks_cur[1]); + if (chip->int_con[2]) + regmap_write(chip->regmap, + chip->int_con[2], chip->irq_masks_cur[2]); disable_irq_wake(chip->irq); break; @@ -169,6 +182,14 @@ int mt6397_irq_init(struct mt6397_chip *chip) chip->int_status[0] = MT6323_INT_STATUS0; chip->int_status[1] = MT6323_INT_STATUS1; break; + case MT6328_CHIP_ID: + chip->int_con[0] = MT6328_INT_CON0; + chip->int_con[1] = MT6328_INT_CON1; + chip->int_con[2] = MT6328_INT_CON2; + chip->int_status[0] = MT6328_INT_STATUS0; + chip->int_status[1] = MT6328_INT_STATUS1; + chip->int_status[2] = MT6328_INT_STATUS2; + break; case MT6331_CHIP_ID: chip->int_con[0] = MT6331_INT_CON0; chip->int_con[1] = MT6331_INT_CON1; @@ -191,6 +212,8 @@ int mt6397_irq_init(struct mt6397_chip *chip) /* Mask all interrupt sources */ regmap_write(chip->regmap, chip->int_con[0], 0x0); regmap_write(chip->regmap, chip->int_con[1], 0x0); + if (chip->int_con[2]) + regmap_write(chip->regmap, chip->int_con[2], 0x0); chip->pm_nb.notifier_call = mt6397_irq_pm_notifier; chip->irq_domain = irq_domain_add_linear(chip->dev->of_node, diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c index b2ebb54331216b..64afc76317904b 100644 --- a/drivers/mfd/mxs-lradc.c +++ b/drivers/mfd/mxs-lradc.c @@ -243,7 +243,7 @@ static struct platform_driver mxs_lradc_driver = { .of_match_table = mxs_lradc_dt_ids, }, .probe = mxs_lradc_probe, - .remove_new = mxs_lradc_remove, + .remove = mxs_lradc_remove, }; module_platform_driver(mxs_lradc_driver); diff --git a/drivers/mfd/ocelot-core.c b/drivers/mfd/ocelot-core.c index 9cccf54fc9c885..41aff270885488 100644 --- a/drivers/mfd/ocelot-core.c +++ b/drivers/mfd/ocelot-core.c @@ -113,7 +113,7 @@ int ocelot_chip_reset(struct device *dev) return readx_poll_timeout(ocelot_gcb_chip_rst_status, ddata, val, !val, VSC7512_GCB_RST_SLEEP_US, VSC7512_GCB_RST_TIMEOUT_US); } -EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT); +EXPORT_SYMBOL_NS(ocelot_chip_reset, "MFD_OCELOT"); static const struct resource vsc7512_miim0_resources[] = { DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"), @@ -226,9 +226,9 @@ int ocelot_core_init(struct device *dev) return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL); } -EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT); +EXPORT_SYMBOL_NS(ocelot_core_init, "MFD_OCELOT"); MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver"); MODULE_AUTHOR("Colin Foster "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(MFD_OCELOT_SPI); +MODULE_IMPORT_NS("MFD_OCELOT_SPI"); diff --git a/drivers/mfd/ocelot-spi.c b/drivers/mfd/ocelot-spi.c index b015c8683f1bcf..1fed9878c32319 100644 --- a/drivers/mfd/ocelot-spi.c +++ b/drivers/mfd/ocelot-spi.c @@ -193,7 +193,7 @@ struct regmap *ocelot_spi_init_regmap(struct device *dev, const struct resource return devm_regmap_init(dev, &ocelot_spi_regmap_bus, dev, ®map_config); } -EXPORT_SYMBOL_NS(ocelot_spi_init_regmap, MFD_OCELOT_SPI); +EXPORT_SYMBOL_NS(ocelot_spi_init_regmap, "MFD_OCELOT_SPI"); static int ocelot_spi_probe(struct spi_device *spi) { @@ -295,4 +295,4 @@ module_spi_driver(ocelot_spi_driver); MODULE_DESCRIPTION("SPI Controlled Ocelot Chip Driver"); MODULE_AUTHOR("Colin Foster "); MODULE_LICENSE("Dual MIT/GPL"); -MODULE_IMPORT_NS(MFD_OCELOT); +MODULE_IMPORT_NS("MFD_OCELOT"); diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 6de7ba75234552..a77b6fc790f2e0 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -843,7 +843,7 @@ static struct platform_driver usbhs_omap_driver = { .of_match_table = usbhs_omap_dt_ids, }, .probe = usbhs_omap_probe, - .remove_new = usbhs_omap_remove, + .remove = usbhs_omap_remove, }; MODULE_AUTHOR("Keshava Munegowda "); diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 5f25ac514ff2b5..0f7fdb99c809bb 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -301,7 +301,7 @@ static struct platform_driver usbtll_omap_driver = { .of_match_table = usbtll_omap_dt_ids, }, .probe = usbtll_omap_probe, - .remove_new = usbtll_omap_remove, + .remove = usbtll_omap_remove, }; int omap_tll_init(struct usbhs_omap_platform_data *pdata) diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index ab55906f91f98a..1fbba0e666d51f 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -243,7 +243,7 @@ static struct platform_driver pcf50633_adc_driver = { .name = "pcf50633-adc", }, .probe = pcf50633_adc_probe, - .remove_new = pcf50633_adc_remove, + .remove = pcf50633_adc_remove, }; module_platform_driver(pcf50633_adc_driver); diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index 8b6285f687da55..f9ebdf5845b857 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c @@ -595,7 +595,7 @@ static void pm8xxx_remove(struct platform_device *pdev) static struct platform_driver pm8xxx_driver = { .probe = pm8xxx_probe, - .remove_new = pm8xxx_remove, + .remove = pm8xxx_remove, .driver = { .name = "pm8xxx-core", .of_match_table = pm8xxx_id_table, diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c index 39ab114ea669d1..71c2b80a4678d6 100644 --- a/drivers/mfd/rk8xx-core.c +++ b/drivers/mfd/rk8xx-core.c @@ -618,7 +618,7 @@ static int rk808_power_off(struct sys_off_data *data) bit = DEV_OFF; break; case RK808_ID: - reg = RK808_DEVCTRL_REG, + reg = RK808_DEVCTRL_REG; bit = DEV_OFF_RST; break; case RK809_ID: @@ -785,8 +785,8 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap if (ret) return dev_err_probe(dev, ret, "failed to add MFD devices\n"); - if (device_property_read_bool(dev, "rockchip,system-power-controller") || - device_property_read_bool(dev, "system-power-controller")) { + if (device_property_read_bool(dev, "system-power-controller") || + device_property_read_bool(dev, "rockchip,system-power-controller")) { ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF_PREPARE, SYS_OFF_PRIO_HIGH, &rk808_power_off, rk808); diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c index 39f7514aa3d875..738d8b3b9ffedb 100644 --- a/drivers/mfd/rohm-bd71828.c +++ b/drivers/mfd/rohm-bd71828.c @@ -32,15 +32,15 @@ static struct gpio_keys_platform_data bd71828_powerkey_data = { }; static const struct resource bd71815_rtc_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0"), - DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1"), - DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd70528-rtc-alm-0"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd70528-rtc-alm-1"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd70528-rtc-alm-2"), }; static const struct resource bd71828_rtc_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"), - DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"), - DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"), + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd70528-rtc-alm-0"), + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd70528-rtc-alm-1"), + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd70528-rtc-alm-2"), }; static struct resource bd71815_power_irqs[] = { diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c index 714f08ed544b50..60ec8db790a7b7 100644 --- a/drivers/mfd/rohm-bd96801.c +++ b/drivers/mfd/rohm-bd96801.c @@ -5,13 +5,9 @@ * ROHM BD96801 PMIC driver * * This version of the "BD86801 scalable PMIC"'s driver supports only very - * basic set of the PMIC features. Most notably, there is no support for - * the ERRB interrupt and the configurations which should be done when the - * PMIC is in STBY mode. - * - * Supporting the ERRB interrupt would require dropping the regmap-IRQ - * usage or working around (or accepting a presense of) a naming conflict - * in debugFS IRQs. + * basic set of the PMIC features. + * Most notably, there is no support for the configurations which should + * be done when the PMIC is in STBY mode. * * Being able to reliably do the configurations like changing the * regulator safety limits (like limits for the over/under -voltages, over @@ -23,16 +19,14 @@ * be the need to configure these safety limits. Hence it's not simple to * come up with a generic solution. * - * Users who require the ERRB handling and STBY state configurations can - * have a look at the original RFC: + * Users who require the STBY state configurations can have a look at the + * original RFC: * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ - * which implements a workaround to debugFS naming conflict and some of - * the safety limit configurations - but leaves the state change handling - * and synchronization to be implemented. + * which implements some of the safety limit configurations - but leaves the + * state change handling and synchronization to be implemented. * * It would be great to hear (and receive a patch!) if you implement the - * STBY configuration support or a proper fix to the debugFS naming - * conflict in your downstream driver ;) + * STBY configuration support or a proper fix in your downstream driver ;) */ #include @@ -46,6 +40,64 @@ #include #include +static const struct resource regulator_errb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96801_OTP_ERR_STAT, "bd96801-otp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_DBIST_ERR_STAT, "bd96801-dbist-err"), + DEFINE_RES_IRQ_NAMED(BD96801_EEP_ERR_STAT, "bd96801-eep-err"), + DEFINE_RES_IRQ_NAMED(BD96801_ABIST_ERR_STAT, "bd96801-abist-err"), + DEFINE_RES_IRQ_NAMED(BD96801_PRSTB_ERR_STAT, "bd96801-prstb-err"), + DEFINE_RES_IRQ_NAMED(BD96801_DRMOS1_ERR_STAT, "bd96801-drmoserr1"), + DEFINE_RES_IRQ_NAMED(BD96801_DRMOS2_ERR_STAT, "bd96801-drmoserr2"), + DEFINE_RES_IRQ_NAMED(BD96801_SLAVE_ERR_STAT, "bd96801-slave-err"), + DEFINE_RES_IRQ_NAMED(BD96801_VREF_ERR_STAT, "bd96801-vref-err"), + DEFINE_RES_IRQ_NAMED(BD96801_TSD_ERR_STAT, "bd96801-tsd"), + DEFINE_RES_IRQ_NAMED(BD96801_UVLO_ERR_STAT, "bd96801-uvlo-err"), + DEFINE_RES_IRQ_NAMED(BD96801_OVLO_ERR_STAT, "bd96801-ovlo-err"), + DEFINE_RES_IRQ_NAMED(BD96801_OSC_ERR_STAT, "bd96801-osc-err"), + DEFINE_RES_IRQ_NAMED(BD96801_PON_ERR_STAT, "bd96801-pon-err"), + DEFINE_RES_IRQ_NAMED(BD96801_POFF_ERR_STAT, "bd96801-poff-err"), + DEFINE_RES_IRQ_NAMED(BD96801_CMD_SHDN_ERR_STAT, "bd96801-cmd-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_INT_PRSTB_WDT_ERR, "bd96801-prstb-wdt-err"), + DEFINE_RES_IRQ_NAMED(BD96801_INT_CHIP_IF_ERR, "bd96801-chip-if-err"), + DEFINE_RES_IRQ_NAMED(BD96801_INT_SHDN_ERR_STAT, "bd96801-int-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_PVIN_ERR_STAT, "bd96801-buck1-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVP_ERR_STAT, "bd96801-buck1-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVP_ERR_STAT, "bd96801-buck1-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_SHDN_ERR_STAT, "bd96801-buck1-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_PVIN_ERR_STAT, "bd96801-buck2-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVP_ERR_STAT, "bd96801-buck2-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVP_ERR_STAT, "bd96801-buck2-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_SHDN_ERR_STAT, "bd96801-buck2-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_PVIN_ERR_STAT, "bd96801-buck3-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVP_ERR_STAT, "bd96801-buck3-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVP_ERR_STAT, "bd96801-buck3-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_SHDN_ERR_STAT, "bd96801-buck3-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_PVIN_ERR_STAT, "bd96801-buck4-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVP_ERR_STAT, "bd96801-buck4-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVP_ERR_STAT, "bd96801-buck4-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_SHDN_ERR_STAT, "bd96801-buck4-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_PVIN_ERR_STAT, "bd96801-ldo5-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVP_ERR_STAT, "bd96801-ldo5-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVP_ERR_STAT, "bd96801-ldo5-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_SHDN_ERR_STAT, "bd96801-ldo5-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_PVIN_ERR_STAT, "bd96801-ldo6-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVP_ERR_STAT, "bd96801-ldo6-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVP_ERR_STAT, "bd96801-ldo6-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_SHDN_ERR_STAT, "bd96801-ldo6-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_PVIN_ERR_STAT, "bd96801-ldo7-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVP_ERR_STAT, "bd96801-ldo7-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVP_ERR_STAT, "bd96801-ldo7-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "bd96801-ldo7-shdn-err"), +}; + static const struct resource regulator_intb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"), @@ -90,20 +142,14 @@ static const struct resource regulator_intb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"), }; -static const struct resource wdg_intb_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD96801_WDT_ERR_STAT, "bd96801-wdg"), +enum { + WDG_CELL = 0, + REGULATOR_CELL, }; static struct mfd_cell bd96801_cells[] = { - { - .name = "bd96801-wdt", - .resources = wdg_intb_irqs, - .num_resources = ARRAY_SIZE(wdg_intb_irqs), - }, { - .name = "bd96801-regulator", - .resources = regulator_intb_irqs, - .num_resources = ARRAY_SIZE(regulator_intb_irqs), - }, + [WDG_CELL] = { .name = "bd96801-wdt", }, + [REGULATOR_CELL] = { .name = "bd96801-regulator", }, }; static const struct regmap_range bd96801_volatile_ranges[] = { @@ -128,6 +174,91 @@ static const struct regmap_access_table volatile_regs = { .n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges), }; +/* + * For ERRB we need main register bit mapping as bit(0) indicates active IRQ + * in one of the first 3 sub IRQ registers, For INTB we can use default 1 to 1 + * mapping. + */ +static unsigned int bit0_offsets[] = {0, 1, 2}; /* System stat, 3 registers */ +static unsigned int bit1_offsets[] = {3}; /* Buck 1 stat */ +static unsigned int bit2_offsets[] = {4}; /* Buck 2 stat */ +static unsigned int bit3_offsets[] = {5}; /* Buck 3 stat */ +static unsigned int bit4_offsets[] = {6}; /* Buck 4 stat */ +static unsigned int bit5_offsets[] = {7}; /* LDO 5 stat */ +static unsigned int bit6_offsets[] = {8}; /* LDO 6 stat */ +static unsigned int bit7_offsets[] = {9}; /* LDO 7 stat */ + +static const struct regmap_irq_sub_irq_map errb_sub_irq_offsets[] = { + REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), +}; + +static const struct regmap_irq bd96801_errb_irqs[] = { + /* Reg 0x52 Fatal ERRB1 */ + REGMAP_IRQ_REG(BD96801_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DBIST_ERR_STAT, 0, BD96801_DBIST_ERR_MASK), + REGMAP_IRQ_REG(BD96801_EEP_ERR_STAT, 0, BD96801_EEP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_ABIST_ERR_STAT, 0, BD96801_ABIST_ERR_MASK), + REGMAP_IRQ_REG(BD96801_PRSTB_ERR_STAT, 0, BD96801_PRSTB_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DRMOS1_ERR_STAT, 0, BD96801_DRMOS1_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DRMOS2_ERR_STAT, 0, BD96801_DRMOS2_ERR_MASK), + REGMAP_IRQ_REG(BD96801_SLAVE_ERR_STAT, 0, BD96801_SLAVE_ERR_MASK), + /* 0x53 Fatal ERRB2 */ + REGMAP_IRQ_REG(BD96801_VREF_ERR_STAT, 1, BD96801_VREF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_TSD_ERR_STAT, 1, BD96801_TSD_ERR_MASK), + REGMAP_IRQ_REG(BD96801_UVLO_ERR_STAT, 1, BD96801_UVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96801_OVLO_ERR_STAT, 1, BD96801_OVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96801_OSC_ERR_STAT, 1, BD96801_OSC_ERR_MASK), + REGMAP_IRQ_REG(BD96801_PON_ERR_STAT, 1, BD96801_PON_ERR_MASK), + REGMAP_IRQ_REG(BD96801_POFF_ERR_STAT, 1, BD96801_POFF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_CMD_SHDN_ERR_STAT, 1, BD96801_CMD_SHDN_ERR_MASK), + /* 0x54 Fatal INTB shadowed to ERRB */ + REGMAP_IRQ_REG(BD96801_INT_PRSTB_WDT_ERR, 2, BD96801_INT_PRSTB_WDT_ERR_MASK), + REGMAP_IRQ_REG(BD96801_INT_CHIP_IF_ERR, 2, BD96801_INT_CHIP_IF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_INT_SHDN_ERR_STAT, 2, BD96801_INT_SHDN_ERR_MASK), + /* Reg 0x55 BUCK1 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK1_PVIN_ERR_STAT, 3, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OVP_ERR_STAT, 3, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_UVP_ERR_STAT, 3, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_SHDN_ERR_STAT, 3, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x56 BUCK2 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK2_PVIN_ERR_STAT, 4, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OVP_ERR_STAT, 4, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_UVP_ERR_STAT, 4, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_SHDN_ERR_STAT, 4, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x57 BUCK3 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK3_PVIN_ERR_STAT, 5, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OVP_ERR_STAT, 5, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_UVP_ERR_STAT, 5, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_SHDN_ERR_STAT, 5, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x58 BUCK4 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK4_PVIN_ERR_STAT, 6, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OVP_ERR_STAT, 6, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_UVP_ERR_STAT, 6, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_SHDN_ERR_STAT, 6, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x59 LDO5 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO5_PVIN_ERR_STAT, 7, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_OVP_ERR_STAT, 7, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_UVP_ERR_STAT, 7, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_SHDN_ERR_STAT, 7, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x5a LDO6 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO6_PVIN_ERR_STAT, 8, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_OVP_ERR_STAT, 8, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_UVP_ERR_STAT, 8, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_SHDN_ERR_STAT, 8, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x5b LDO7 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO7_PVIN_ERR_STAT, 9, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_OVP_ERR_STAT, 9, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_UVP_ERR_STAT, 9, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_SHDN_ERR_STAT, 9, BD96801_OUT_SHDN_ERR_MASK), +}; + static const struct regmap_irq bd96801_intb_irqs[] = { /* STATUS SYSTEM INTB */ REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK), @@ -176,8 +307,25 @@ static const struct regmap_irq bd96801_intb_irqs[] = { REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK), }; -static struct regmap_irq_chip bd96801_irq_chip_intb = { +static const struct regmap_irq_chip bd96801_irq_chip_errb = { + .name = "bd96801-irq-errb", + .domain_suffix = "errb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96801_errb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96801_errb_irqs), + .status_base = BD96801_REG_INT_SYS_ERRB1, + .mask_base = BD96801_REG_MASK_SYS_ERRB, + .ack_base = BD96801_REG_INT_SYS_ERRB1, + .init_ack_masked = true, + .num_regs = 10, + .irq_reg_stride = 1, + .sub_reg_offsets = &errb_sub_irq_offsets[0], +}; + +static const struct regmap_irq_chip bd96801_irq_chip_intb = { .name = "bd96801-irq-intb", + .domain_suffix = "intb", .main_status = BD96801_REG_INT_MAIN, .num_main_regs = 1, .irqs = &bd96801_intb_irqs[0], @@ -194,16 +342,20 @@ static const struct regmap_config bd96801_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_table = &volatile_regs, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int bd96801_i2c_probe(struct i2c_client *i2c) { - struct regmap_irq_chip_data *intb_irq_data; + struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data; + struct irq_domain *intb_domain, *errb_domain; const struct fwnode_handle *fwnode; - struct irq_domain *intb_domain; + struct resource *regulator_res; + struct resource wdg_irq; struct regmap *regmap; - int ret, intb_irq; + int intb_irq, errb_irq, num_intb, num_errb = 0; + int num_regu_irqs, wdg_irq_no; + int i, ret; fwnode = dev_fwnode(&i2c->dev); if (!fwnode) @@ -213,6 +365,23 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) if (intb_irq < 0) return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n"); + num_intb = ARRAY_SIZE(regulator_intb_irqs); + + /* ERRB may be omitted if processor is powered by the PMIC */ + errb_irq = fwnode_irq_get_byname(fwnode, "errb"); + if (errb_irq < 0) + errb_irq = 0; + + if (errb_irq) + num_errb = ARRAY_SIZE(regulator_errb_irqs); + + num_regu_irqs = num_intb + num_errb; + + regulator_res = devm_kcalloc(&i2c->dev, num_regu_irqs, + sizeof(*regulator_res), GFP_KERNEL); + if (!regulator_res) + return -ENOMEM; + regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config); if (IS_ERR(regmap)) return dev_err_probe(&i2c->dev, PTR_ERR(regmap), @@ -230,12 +399,50 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) intb_domain = regmap_irq_get_domain(intb_irq_data); - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, - bd96801_cells, - ARRAY_SIZE(bd96801_cells), NULL, 0, - intb_domain); + /* + * MFD core code is built to handle only one IRQ domain. BD96801 + * has two domains so we do IRQ mapping here and provide the + * already mapped IRQ numbers to sub-devices. + */ + for (i = 0; i < num_intb; i++) { + struct resource *res = ®ulator_res[i]; + + *res = regulator_intb_irqs[i]; + res->start = res->end = irq_create_mapping(intb_domain, + res->start); + } + + wdg_irq_no = irq_create_mapping(intb_domain, BD96801_WDT_ERR_STAT); + wdg_irq = DEFINE_RES_IRQ_NAMED(wdg_irq_no, "bd96801-wdg"); + bd96801_cells[WDG_CELL].resources = &wdg_irq; + bd96801_cells[WDG_CELL].num_resources = 1; + + if (!num_errb) + goto skip_errb; + + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, errb_irq, IRQF_ONESHOT, + 0, &bd96801_irq_chip_errb, &errb_irq_data); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to add ERRB IRQ chip\n"); + + errb_domain = regmap_irq_get_domain(errb_irq_data); + + for (i = 0; i < num_errb; i++) { + struct resource *res = ®ulator_res[num_intb + i]; + + *res = regulator_errb_irqs[i]; + res->start = res->end = irq_create_mapping(errb_domain, res->start); + } + +skip_errb: + bd96801_cells[REGULATOR_CELL].resources = regulator_res; + bd96801_cells[REGULATOR_CELL].num_resources = num_regu_irqs; + + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, bd96801_cells, + ARRAY_SIZE(bd96801_cells), NULL, 0, NULL); if (ret) - dev_err(&i2c->dev, "Failed to create subdevices\n"); + dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); return ret; } diff --git a/drivers/mfd/rt5033.c b/drivers/mfd/rt5033.c index 7e23ab3d5842c8..84ebc96f58e48d 100644 --- a/drivers/mfd/rt5033.c +++ b/drivers/mfd/rt5033.c @@ -81,8 +81,8 @@ static int rt5033_i2c_probe(struct i2c_client *i2c) chip_rev = dev_id & RT5033_CHIP_REV_MASK; dev_info(&i2c->dev, "Device found (rev. %d)\n", chip_rev); - ret = regmap_add_irq_chip(rt5033->regmap, rt5033->irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ret = devm_regmap_add_irq_chip(rt5033->dev, rt5033->regmap, + rt5033->irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, &rt5033_irq_chip, &rt5033->irq_data); if (ret) { dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index a6b0d7300b2d38..cdfe738e1d76e6 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -34,6 +34,10 @@ static const struct mfd_cell s5m8767_devs[] = { }, }; +static const struct mfd_cell s2dos05_devs[] = { + { .name = "s2dos05-regulator", }, +}; + static const struct mfd_cell s2mps11_devs[] = { { .name = "s2mps11-regulator", }, { .name = "s2mps14-rtc", }, @@ -83,6 +87,9 @@ static const struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s5m8767-pmic", .data = (void *)S5M8767X, + }, { + .compatible = "samsung,s2dos05", + .data = (void *)S2DOS05, }, { .compatible = "samsung,s2mps11-pmic", .data = (void *)S2MPS11X, @@ -339,6 +346,10 @@ static int sec_pmic_probe(struct i2c_client *i2c) sec_devs = s5m8767_devs; num_sec_devs = ARRAY_SIZE(s5m8767_devs); break; + case S2DOS05: + sec_devs = s2dos05_devs; + num_sec_devs = ARRAY_SIZE(s2dos05_devs); + break; case S2MPA01: sec_devs = s2mpa01_devs; num_sec_devs = ARRAY_SIZE(s2mpa01_devs); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index b3592982a83b55..0469e85d72cff3 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1705,7 +1705,7 @@ static struct platform_driver sm501_plat_driver = { .of_match_table = of_sm501_match_tbl, }, .probe = sm501_plat_probe, - .remove_new = sm501_plat_remove, + .remove = sm501_plat_remove, .suspend = pm_sleep_ptr(sm501_plat_suspend), .resume = pm_sleep_ptr(sm501_plat_resume), }; diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c index 9fd13d88950c67..650724e19b8862 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -326,7 +326,7 @@ MODULE_DEVICE_TABLE(of, stm32_timers_of_match); static struct platform_driver stm32_timers_driver = { .probe = stm32_timers_probe, - .remove_new = stm32_timers_remove, + .remove = stm32_timers_remove, .driver = { .name = "stm32-timers", .of_match_table = stm32_timers_of_match, diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 2ce15f60eb1071..3e1d699ba9340f 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -108,6 +108,8 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) syscon_config.reg_stride = reg_io_width; syscon_config.val_bits = reg_io_width * 8; syscon_config.max_register = resource_size(&res) - reg_io_width; + if (!syscon_config.max_register) + syscon_config.max_register_is_0 = true; regmap = regmap_init_mmio(NULL, base, &syscon_config); kfree(syscon_config.name); @@ -357,6 +359,9 @@ static int syscon_probe(struct platform_device *pdev) return -ENOMEM; syscon_config.max_register = resource_size(res) - 4; + if (!syscon_config.max_register) + syscon_config.max_register_is_0 = true; + if (pdata) syscon_config.name = pdata->label; syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_config); diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 0c1364d88469f5..068c25401c6cda 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -377,7 +377,7 @@ static struct platform_driver ti_tscadc_driver = { .of_match_table = ti_tscadc_dt_ids, }, .probe = ti_tscadc_probe, - .remove_new = ti_tscadc_remove, + .remove = ti_tscadc_remove, }; diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 2b9105295f3012..710364435b6b9e 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -544,17 +544,13 @@ static int tps65010_probe(struct i2c_client *client) */ if (client->irq > 0) { status = request_irq(client->irq, tps65010_irq, - IRQF_TRIGGER_FALLING, DRIVER_NAME, tps); + IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN, + DRIVER_NAME, tps); if (status < 0) { dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", client->irq, status); return status; } - /* annoying race here, ideally we'd have an option - * to claim the irq now and enable it later. - * FIXME genirq IRQF_NOAUTOEN now solves that ... - */ - disable_irq(client->irq); set_bit(FLAG_IRQ_ENABLE, &tps->flags); } else dev_warn(&client->dev, "IRQ not configured!\n"); diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c index f206a9c50e9d84..7098712ea00899 100644 --- a/drivers/mfd/tps65911-comparator.c +++ b/drivers/mfd/tps65911-comparator.c @@ -154,7 +154,7 @@ static struct platform_driver tps65911_comparator_driver = { .name = "tps65911-comparator", }, .probe = tps65911_comparator_probe, - .remove_new = tps65911_comparator_remove, + .remove = tps65911_comparator_remove, }; static int __init tps65911_comparator_init(void) diff --git a/drivers/mfd/tqmx86.c b/drivers/mfd/tqmx86.c index fac02875fe7d9f..1cba3b67b0fb9a 100644 --- a/drivers/mfd/tqmx86.c +++ b/drivers/mfd/tqmx86.c @@ -35,11 +35,14 @@ #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_120UC 10 #define TQMX86_REG_BOARD_ID_110EB 11 #define TQMX86_REG_BOARD_ID_E40M 12 #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_ID_130UC 16 +#define TQMX86_REG_BOARD_ID_E41S 19 #define TQMX86_REG_BOARD_REV 0x01 #define TQMX86_REG_IO_EXT_INT 0x06 #define TQMX86_REG_IO_EXT_INT_NONE 0 @@ -47,6 +50,7 @@ #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_I2C1_SHIFT 0 #define TQMX86_REG_IO_EXT_INT_GPIO_SHIFT 4 #define TQMX86_REG_SAUC 0x17 @@ -55,23 +59,36 @@ static uint gpio_irq; module_param(gpio_irq, uint, 0); -MODULE_PARM_DESC(gpio_irq, "GPIO IRQ number (7, 9, 12)"); +MODULE_PARM_DESC(gpio_irq, "GPIO IRQ number (valid parameters: 7, 9, 12)"); -static const struct resource tqmx_i2c_soft_resources[] = { - DEFINE_RES_IO(TQMX86_IOBASE_I2C, TQMX86_IOSIZE_I2C), +static uint i2c1_irq; +module_param(i2c1_irq, uint, 0); +MODULE_PARM_DESC(i2c1_irq, "I2C1 IRQ number (valid parameters: 7, 9, 12)"); + +enum tqmx86_i2c1_resource_type { + TQMX86_I2C1_IO, + TQMX86_I2C1_IRQ, +}; + +static struct resource tqmx_i2c_soft_resources[] = { + [TQMX86_I2C1_IO] = DEFINE_RES_IO(TQMX86_IOBASE_I2C, TQMX86_IOSIZE_I2C), + /* Placeholder for IRQ resource */ + [TQMX86_I2C1_IRQ] = {}, }; static const struct resource tqmx_watchdog_resources[] = { DEFINE_RES_IO(TQMX86_IOBASE_WATCHDOG, TQMX86_IOSIZE_WATCHDOG), }; -/* - * The IRQ resource must be first, since it is updated with the - * configured IRQ in the probe function. - */ +enum tqmx86_gpio_resource_type { + TQMX86_GPIO_IO, + TQMX86_GPIO_IRQ, +}; + static struct resource tqmx_gpio_resources[] = { - DEFINE_RES_IRQ(0), - DEFINE_RES_IO(TQMX86_IOBASE_GPIO, TQMX86_IOSIZE_GPIO), + [TQMX86_GPIO_IO] = DEFINE_RES_IO(TQMX86_IOBASE_GPIO, TQMX86_IOSIZE_GPIO), + /* Placeholder for IRQ resource */ + [TQMX86_GPIO_IRQ] = {}, }; static struct i2c_board_info tqmx86_i2c_devices[] = { @@ -132,6 +149,8 @@ static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc) return "TQMx70EB"; case TQMX86_REG_BOARD_ID_80UC: return "TQMx80UC"; + case TQMX86_REG_BOARD_ID_120UC: + return "TQMx120UC"; case TQMX86_REG_BOARD_ID_110EB: return "TQMx110EB"; case TQMX86_REG_BOARD_ID_E40M: @@ -142,6 +161,10 @@ static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc) return "TQMxE40C1"; case TQMX86_REG_BOARD_ID_E40C2: return "TQMxE40C2"; + case TQMX86_REG_BOARD_ID_130UC: + return "TQMx130UC"; + case TQMX86_REG_BOARD_ID_E41S: + return "TQMxE41S"; default: return "Unknown"; } @@ -154,11 +177,14 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) case TQMX86_REG_BOARD_ID_60EB: case TQMX86_REG_BOARD_ID_70EB: case TQMX86_REG_BOARD_ID_80UC: + case TQMX86_REG_BOARD_ID_120UC: case TQMX86_REG_BOARD_ID_110EB: case TQMX86_REG_BOARD_ID_E40M: case TQMX86_REG_BOARD_ID_E40S: case TQMX86_REG_BOARD_ID_E40C1: case TQMX86_REG_BOARD_ID_E40C2: + case TQMX86_REG_BOARD_ID_130UC: + case TQMX86_REG_BOARD_ID_E41S: return 24000; case TQMX86_REG_BOARD_ID_E39MS: case TQMX86_REG_BOARD_ID_E39C1: @@ -174,33 +200,52 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) } } -static int tqmx86_probe(struct platform_device *pdev) +static int tqmx86_setup_irq(struct device *dev, const char *label, u8 irq, + void __iomem *io_base, u8 reg_shift) { - 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; - void __iomem *io_base; - int err; + u8 val, readback; + int irq_cfg; - switch (gpio_irq) { + switch (irq) { case 0: - gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_NONE; + irq_cfg = TQMX86_REG_IO_EXT_INT_NONE; break; case 7: - gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_7; + irq_cfg = TQMX86_REG_IO_EXT_INT_7; break; case 9: - gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_9; + irq_cfg = TQMX86_REG_IO_EXT_INT_9; break; case 12: - gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_12; + irq_cfg = TQMX86_REG_IO_EXT_INT_12; break; default: - pr_err("tqmx86: Invalid GPIO IRQ (%d)\n", gpio_irq); + dev_err(dev, "invalid %s IRQ (%d)\n", label, irq); return -EINVAL; } + val = ioread8(io_base + TQMX86_REG_IO_EXT_INT); + val &= ~(TQMX86_REG_IO_EXT_INT_MASK << reg_shift); + val |= (irq_cfg & TQMX86_REG_IO_EXT_INT_MASK) << reg_shift; + + iowrite8(val, io_base + TQMX86_REG_IO_EXT_INT); + readback = ioread8(io_base + TQMX86_REG_IO_EXT_INT); + if (readback != val) { + dev_warn(dev, "%s interrupts not supported\n", label); + return -EINVAL; + } + + return 0; +} + +static int tqmx86_probe(struct platform_device *pdev) +{ + u8 board_id, sauc, rev, i2c_det; + struct device *dev = &pdev->dev; + const char *board_name; + void __iomem *io_base; + int err; + io_base = devm_ioport_map(dev, TQMX86_IOBASE, TQMX86_IOSIZE); if (!io_base) return -ENOMEM; @@ -221,25 +266,23 @@ static int tqmx86_probe(struct platform_device *pdev) */ i2c_det = inb(TQMX86_REG_I2C_DETECT); - if (gpio_irq_cfg) { - io_ext_int_val = - gpio_irq_cfg << TQMX86_REG_IO_EXT_INT_GPIO_SHIFT; - iowrite8(io_ext_int_val, io_base + TQMX86_REG_IO_EXT_INT); - readback = ioread8(io_base + TQMX86_REG_IO_EXT_INT); - if (readback != io_ext_int_val) { - dev_warn(dev, "GPIO interrupts not supported.\n"); - return -EINVAL; - } - - /* Assumes the IRQ resource is first. */ - tqmx_gpio_resources[0].start = gpio_irq; - } else { - tqmx_gpio_resources[0].flags = 0; + if (gpio_irq) { + err = tqmx86_setup_irq(dev, "GPIO", gpio_irq, io_base, + TQMX86_REG_IO_EXT_INT_GPIO_SHIFT); + if (!err) + tqmx_gpio_resources[TQMX86_GPIO_IRQ] = DEFINE_RES_IRQ(gpio_irq); } ocores_platform_data.clock_khz = tqmx86_board_id_to_clk_rate(dev, board_id); if (i2c_det == TQMX86_REG_I2C_DETECT_SOFT) { + if (i2c1_irq) { + err = tqmx86_setup_irq(dev, "I2C1", i2c1_irq, io_base, + TQMX86_REG_IO_EXT_INT_I2C1_SHIFT); + if (!err) + tqmx_i2c_soft_resources[TQMX86_I2C1_IRQ] = DEFINE_RES_IRQ(i2c1_irq); + } + err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, tqmx86_i2c_soft_dev, ARRAY_SIZE(tqmx86_i2c_soft_dev), diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index c130ffef182f19..f89eda4a17fe43 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -711,6 +711,10 @@ static struct of_dev_auxdata twl_auxdata_lookup[] = { { /* sentinel */ }, }; +static const struct mfd_cell twl6030_cells[] = { + { .name = "twl6030-clk" }, +}; + static const struct mfd_cell twl6032_cells[] = { { .name = "twl6032-clk" }, }; @@ -861,17 +865,23 @@ twl_probe(struct i2c_client *client) TWL4030_DCDC_GLOBAL_CFG); } - if (id->driver_data == (TWL6030_CLASS | TWL6032_SUBCLASS)) { - status = devm_mfd_add_devices(&client->dev, - PLATFORM_DEVID_NONE, - twl6032_cells, - ARRAY_SIZE(twl6032_cells), - NULL, 0, NULL); + if (twl_class_is_6030()) { + const struct mfd_cell *cells; + int num_cells; + + if (id->driver_data & TWL6032_SUBCLASS) { + cells = twl6032_cells; + num_cells = ARRAY_SIZE(twl6032_cells); + } else { + cells = twl6030_cells; + num_cells = ARRAY_SIZE(twl6030_cells); + } + + status = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE, + cells, num_cells, NULL, 0, NULL); if (status < 0) goto free; - } - if (twl_class_is_6030()) { if (of_device_is_system_power_controller(node)) { if (!pm_power_off) pm_power_off = twl6030_power_off; diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index d436ddf661dab8..a4a550bafb3cc1 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -276,7 +276,7 @@ static struct platform_driver twl4030_audio_driver = { .of_match_table = twl4030_audio_of_match, }, .probe = twl4030_audio_probe, - .remove_new = twl4030_audio_remove, + .remove = twl4030_audio_remove, }; module_platform_driver(twl4030_audio_driver); diff --git a/drivers/mfd/wcd934x.c b/drivers/mfd/wcd934x.c index fcd182d519811a..3c3080e8c8cf7e 100644 --- a/drivers/mfd/wcd934x.c +++ b/drivers/mfd/wcd934x.c @@ -284,6 +284,7 @@ static const struct slim_device_id wcd934x_slim_id[] = { SLIM_DEV_IDX_WCD9340, SLIM_DEV_INSTANCE_ID_WCD9340 }, {} }; +MODULE_DEVICE_TABLE(slim, wcd934x_slim_id); static struct slim_driver wcd934x_slim_driver = { .driver = { @@ -298,5 +299,4 @@ static struct slim_driver wcd934x_slim_driver = { module_slim_driver(wcd934x_slim_driver); MODULE_DESCRIPTION("WCD934X slim driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("slim:217:250:*"); MODULE_AUTHOR("Srinivas Kandagatla "); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3fe7e2a9bd294d..09cbe3f0ab1e56 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -610,10 +610,33 @@ config MARVELL_CN10K_DPI To compile this driver as a module, choose M here: the module will be called mrvl_cn10k_dpi. +config MCHP_LAN966X_PCI + tristate "Microchip LAN966x PCIe Support" + depends on PCI + select OF + select OF_OVERLAY + select IRQ_DOMAIN + help + This enables the support for the LAN966x PCIe device. + + This is used to drive the LAN966x PCIe device from the host system + to which it is connected. The driver uses a device tree overlay to + load other drivers to support for LAN966x internal components. + + Even if this driver does not depend on those other drivers, in order + to have a fully functional board, the following drivers are needed: + - fixed-clock (COMMON_CLK) + - lan966x-oic (LAN966X_OIC) + - lan966x-cpu-syscon (MFD_SYSCON) + - lan966x-switch-reset (RESET_MCHP_SPARX5) + - lan966x-pinctrl (PINCTRL_OCELOT) + - lan966x-serdes (PHY_LAN966X_SERDES) + - lan966x-miim (MDIO_MSCC_MIIM) + - lan966x-switch (LAN966X_SWITCH) + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" -source "drivers/misc/ti-st/Kconfig" source "drivers/misc/lis3lv02d/Kconfig" source "drivers/misc/altera-stapl/Kconfig" source "drivers/misc/mei/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a9f94525e1819d..40bf953185c773 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -40,7 +40,6 @@ obj-y += eeprom/ obj-y += cb710/ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o obj-$(CONFIG_PCH_PHUB) += pch_phub.o -obj-y += ti-st/ obj-y += lis3lv02d/ obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_INTEL_MEI) += mei/ @@ -71,4 +70,7 @@ obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o obj-$(CONFIG_NSM) += nsm.o obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o +lan966x-pci-objs := lan966x_pci.o +lan966x-pci-objs += lan966x_pci.dtbo.o +obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o obj-y += keba/ diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index 6d4edd69db126a..e7d73c972f65dc 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1147,7 +1147,7 @@ static int apds990x_probe(struct i2c_client *client) err = chip->pdata->setup_resources(); if (err) { err = -EINVAL; - goto fail3; + goto fail4; } } @@ -1155,7 +1155,7 @@ static int apds990x_probe(struct i2c_client *client) apds990x_attribute_group); if (err < 0) { dev_err(&chip->client->dev, "Sysfs registration failed\n"); - goto fail4; + goto fail5; } err = request_threaded_irq(client->irq, NULL, @@ -1166,15 +1166,17 @@ static int apds990x_probe(struct i2c_client *client) if (err) { dev_err(&client->dev, "could not get IRQ %d\n", client->irq); - goto fail5; + goto fail6; } return err; -fail5: +fail6: sysfs_remove_group(&chip->client->dev.kobj, &apds990x_attribute_group[0]); -fail4: +fail5: if (chip->pdata && chip->pdata->release_resources) chip->pdata->release_resources(); +fail4: + pm_runtime_disable(&client->dev); fail3: regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); fail2: diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 6eac0f33591524..35a1963415346a 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -153,7 +153,7 @@ static int ssc_sound_dai_probe(struct ssc_device *ssc) ssc->sound_dai = false; - if (!of_property_read_bool(np, "#sound-dai-cells")) + if (!of_property_present(np, "#sound-dai-cells")) return 0; id = of_alias_get_id(np, "ssc"); @@ -176,7 +176,7 @@ static void ssc_sound_dai_remove(struct ssc_device *ssc) #else static inline int ssc_sound_dai_probe(struct ssc_device *ssc) { - if (of_property_read_bool(ssc->pdev->dev.of_node, "#sound-dai-cells")) + if (of_property_present(ssc->pdev->dev.of_node, "#sound-dai-cells")) return -ENOTSUPP; return 0; @@ -269,7 +269,7 @@ static struct platform_driver ssc_driver = { }, .id_table = atmel_ssc_devtypes, .probe = ssc_probe, - .remove_new = ssc_remove, + .remove = ssc_remove, }; module_platform_driver(ssc_driver); diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c index 0142c4bf4f42d4..a5549eaf52d089 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -17,8 +17,6 @@ #include -#define DRV_NAME_ALCOR_PCI "alcor_pci" - static DEFINE_IDA(alcor_pci_idr); static struct mfd_cell alcor_pci_cells[] = { diff --git a/drivers/misc/cardreader/rtsx_usb.c b/drivers/misc/cardreader/rtsx_usb.c index f150d8769f1986..77b0490a1b38d7 100644 --- a/drivers/misc/cardreader/rtsx_usb.c +++ b/drivers/misc/cardreader/rtsx_usb.c @@ -20,11 +20,11 @@ MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)"); static const struct mfd_cell rtsx_usb_cells[] = { [RTSX_USB_SD_CARD] = { - .name = "rtsx_usb_sdmmc", + .name = DRV_NAME_RTSX_USB_SDMMC, .pdata_size = 0, }, [RTSX_USB_MS_CARD] = { - .name = "rtsx_usb_ms", + .name = DRV_NAME_RTSX_USB_MS, .pdata_size = 0, }, }; @@ -780,7 +780,7 @@ static const struct usb_device_id rtsx_usb_usb_ids[] = { MODULE_DEVICE_TABLE(usb, rtsx_usb_usb_ids); static struct usb_driver rtsx_usb_driver = { - .name = "rtsx_usb", + .name = DRV_NAME_RTSX_USB, .probe = rtsx_usb_probe, .disconnect = rtsx_usb_disconnect, .suspend = rtsx_usb_suspend, diff --git a/drivers/misc/cxl/of.c b/drivers/misc/cxl/of.c index 03633cccd04389..cf6bd8a43056e7 100644 --- a/drivers/misc/cxl/of.c +++ b/drivers/misc/cxl/of.c @@ -339,6 +339,6 @@ struct platform_driver cxl_of_driver = { .owner = THIS_MODULE }, .probe = cxl_of_probe, - .remove_new = cxl_of_remove, + .remove = cxl_of_remove, .shutdown = cxl_of_shutdown, }; diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 9df12399bda37c..cb1c4b8e7fd37a 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -97,11 +97,11 @@ config EEPROM_DIGSY_MTC_CFG If unsure, say N. config EEPROM_IDT_89HPESX - tristate "IDT 89HPESx PCIe-swtiches EEPROM / CSR support" + tristate "IDT 89HPESx PCIe-switches EEPROM / CSR support" depends on I2C && SYSFS help Enable this driver to get read/write access to EEPROM / CSRs - over IDT PCIe-swtich i2c-slave interface. + over IDT PCIe-switch i2c-slave interface. This driver can also be built as a module. If so, the module will be called idt_89hpesx. diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index ca872e3465ed9b..0a7c7f29406c79 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -207,6 +207,8 @@ AT24_CHIP_DATA(at24_data_24cs64, 16, AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY); AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16); AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16); +/* M24256E Additional Write lockable page (M24256E-F order codes) */ +AT24_CHIP_DATA(at24_data_24256e_wlp, 64, AT24_FLAG_ADDR16); AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16); AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16); AT24_CHIP_DATA_BS(at24_data_24c1025, 1048576 / 8, AT24_FLAG_ADDR16, 2); @@ -240,6 +242,7 @@ static const struct i2c_device_id at24_ids[] = { { "24cs64", (kernel_ulong_t)&at24_data_24cs64 }, { "24c128", (kernel_ulong_t)&at24_data_24c128 }, { "24c256", (kernel_ulong_t)&at24_data_24c256 }, + { "24256e-wl", (kernel_ulong_t)&at24_data_24256e_wlp }, { "24c512", (kernel_ulong_t)&at24_data_24c512 }, { "24c1024", (kernel_ulong_t)&at24_data_24c1024 }, { "24c1025", (kernel_ulong_t)&at24_data_24c1025 }, @@ -278,6 +281,7 @@ static const struct of_device_id __maybe_unused at24_of_match[] = { { .compatible = "atmel,24c2048", .data = &at24_data_24c2048 }, { .compatible = "microchip,24aa025e48", .data = &at24_data_24aa025e48 }, { .compatible = "microchip,24aa025e64", .data = &at24_data_24aa025e64 }, + { .compatible = "st,24256e-wl", .data = &at24_data_24256e_wlp }, { /* END OF LIST */ }, }; MODULE_DEVICE_TABLE(of, at24_of_match); diff --git a/drivers/misc/eeprom/eeprom_93cx6.c b/drivers/misc/eeprom/eeprom_93cx6.c index 9627294fe3e951..e6f0e0fc1ca204 100644 --- a/drivers/misc/eeprom/eeprom_93cx6.c +++ b/drivers/misc/eeprom/eeprom_93cx6.c @@ -8,6 +8,7 @@ * Supported chipsets: 93c46 & 93c66. */ +#include #include #include #include @@ -102,7 +103,7 @@ static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom, /* * Check if this bit needs to be set. */ - eeprom->reg_data_in = !!(data & (1 << (i - 1))); + eeprom->reg_data_in = !!(data & BIT(i - 1)); /* * Write the bit to the eeprom register. @@ -152,7 +153,7 @@ static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom, * Read if the bit has been set. */ if (eeprom->reg_data_out) - buf |= (1 << (i - 1)); + buf |= BIT(i - 1); eeprom_93cx6_pulse_low(eeprom); } @@ -186,6 +187,11 @@ void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word, eeprom_93cx6_write_bits(eeprom, command, PCI_EEPROM_WIDTH_OPCODE + eeprom->width); + if (has_quirk_extra_read_cycle(eeprom)) { + eeprom_93cx6_pulse_high(eeprom); + eeprom_93cx6_pulse_low(eeprom); + } + /* * Read the requested 16 bits. */ @@ -252,6 +258,11 @@ void eeprom_93cx6_readb(struct eeprom_93cx6 *eeprom, const u8 byte, eeprom_93cx6_write_bits(eeprom, command, PCI_EEPROM_WIDTH_OPCODE + eeprom->width + 1); + if (has_quirk_extra_read_cycle(eeprom)) { + eeprom_93cx6_pulse_high(eeprom); + eeprom_93cx6_pulse_low(eeprom); + } + /* * Read the requested 8 bits. */ diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index e2221be884458f..9cae6f530679b3 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -229,7 +229,7 @@ static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on) static ssize_t eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev, - const char *buf, unsigned off) + const char *buf, unsigned int off) { struct spi_message m; struct spi_transfer t[2] = {}; diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 74181b8c386b78..48d08eeb2d20b5 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -2215,7 +2215,7 @@ static const struct of_device_id fastrpc_match_table[] = { static struct platform_driver fastrpc_cb_driver = { .probe = fastrpc_cb_probe, - .remove_new = fastrpc_cb_remove, + .remove = fastrpc_cb_remove, .driver = { .name = "qcom,fastrpc-cb", .of_match_table = fastrpc_match_table, @@ -2505,4 +2505,4 @@ module_exit(fastrpc_exit); MODULE_DESCRIPTION("Qualcomm FastRPC"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); diff --git a/drivers/misc/hisi_hikey_usb.c b/drivers/misc/hisi_hikey_usb.c index fb9be37057a8dd..ffe7b945a29857 100644 --- a/drivers/misc/hisi_hikey_usb.c +++ b/drivers/misc/hisi_hikey_usb.c @@ -260,7 +260,7 @@ MODULE_DEVICE_TABLE(of, id_table_hisi_hikey_usb); static struct platform_driver hisi_hikey_usb_driver = { .probe = hisi_hikey_usb_probe, - .remove_new = hisi_hikey_usb_remove, + .remove = hisi_hikey_usb_remove, .driver = { .name = DEVICE_DRIVER_NAME, .of_match_table = id_table_hisi_hikey_usb, diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c index 1643ba2ff9644d..c288aeec16c095 100644 --- a/drivers/misc/isl29020.c +++ b/drivers/misc/isl29020.c @@ -68,7 +68,7 @@ static ssize_t als_lux_input_data_show(struct device *dev, if (val < 0) return val; lux = ((((1 << (2 * (val & 3))))*1000) * ret_val) / 65536; - return sprintf(buf, "%ld\n", lux); + return sprintf(buf, "%lu\n", lux); } static ssize_t als_sensing_range_store(struct device *dev, diff --git a/drivers/misc/keba/Kconfig b/drivers/misc/keba/Kconfig index 5fbcbc2252ac1e..d6d47197a963bd 100644 --- a/drivers/misc/keba/Kconfig +++ b/drivers/misc/keba/Kconfig @@ -1,7 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 config KEBA_CP500 tristate "KEBA CP500 system FPGA support" + depends on X86_64 || ARM64 || COMPILE_TEST depends on PCI + depends on I2C select AUXILIARY_BUS help This driver supports the KEBA CP500 system FPGA, which is used in @@ -11,3 +13,14 @@ config KEBA_CP500 This driver can also be built as a module. If so, the module will be called cp500. + +config KEBA_LAN9252 + tristate "KEBA CP500 LAN9252 configuration" + depends on SPI + depends on KEBA_CP500 || COMPILE_TEST + help + This driver is used for updating the configuration of the LAN9252 + controller on KEBA CP500 devices. + + This driver can also be built as a module. If so, the module will be + called lan9252. diff --git a/drivers/misc/keba/Makefile b/drivers/misc/keba/Makefile index 0a8b846cda7dcb..05e9efcad54f2e 100644 --- a/drivers/misc/keba/Makefile +++ b/drivers/misc/keba/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_KEBA_CP500) += cp500.o +obj-$(CONFIG_KEBA_LAN9252) += lan9252.o diff --git a/drivers/misc/keba/cp500.c b/drivers/misc/keba/cp500.c index ae09228178810c..255d3022dae8fe 100644 --- a/drivers/misc/keba/cp500.c +++ b/drivers/misc/keba/cp500.c @@ -12,7 +12,12 @@ #include #include #include +#include +#include +#include #include +#include +#include #define CP500 "cp500" @@ -27,6 +32,7 @@ /* BAR 0 registers */ #define CP500_VERSION_REG 0x00 #define CP500_RECONFIG_REG 0x11 /* upper 8-bits of STARTUP register */ +#define CP500_PRESENT_REG 0x20 #define CP500_AXI_REG 0x40 /* Bits in BUILD_REG */ @@ -35,14 +41,35 @@ /* Bits in RECONFIG_REG */ #define CP500_RECFG_REQ 0x01 /* reconfigure FPGA on next reset */ +/* Bits in PRESENT_REG */ +#define CP500_PRESENT_FAN0 0x01 + /* MSIX */ #define CP500_AXI_MSIX 3 +#define CP500_RFB_UART_MSIX 4 +#define CP500_DEBUG_UART_MSIX 5 +#define CP500_SI1_UART_MSIX 6 #define CP500_NUM_MSIX 8 #define CP500_NUM_MSIX_NO_MMI 2 #define CP500_NUM_MSIX_NO_AXI 3 /* EEPROM */ -#define CP500_HW_CPU_EEPROM_NAME "cp500_cpu_eeprom" +#define CP500_EEPROM_DA_OFFSET 0x016F +#define CP500_EEPROM_DA_ESC_TYPE_MASK 0x01 +#define CP500_EEPROM_ESC_LAN9252 0x00 +#define CP500_EEPROM_ESC_ET1100 0x01 +#define CP500_EEPROM_CPU_NAME "cpu_eeprom" +#define CP500_EEPROM_CPU_OFFSET 0 +#define CP500_EEPROM_CPU_SIZE 3072 +#define CP500_EEPROM_USER_NAME "user_eeprom" +#define CP500_EEPROM_USER_OFFSET 3072 +#define CP500_EEPROM_USER_SIZE 1024 + +/* SPI flash running at full speed */ +#define CP500_FLASH_HZ (33 * 1000 * 1000) + +/* LAN9252 */ +#define CP500_LAN9252_HZ (10 * 1000 * 1000) #define CP500_IS_CP035(dev) ((dev)->pci_dev->device == PCI_DEVICE_ID_KEBA_CP035) #define CP500_IS_CP505(dev) ((dev)->pci_dev->device == PCI_DEVICE_ID_KEBA_CP505) @@ -51,29 +78,56 @@ struct cp500_dev_info { off_t offset; size_t size; + unsigned int msix; }; struct cp500_devs { struct cp500_dev_info startup; + struct cp500_dev_info spi; struct cp500_dev_info i2c; + struct cp500_dev_info fan; + struct cp500_dev_info batt; + struct cp500_dev_info uart0_rfb; + struct cp500_dev_info uart1_dbg; + struct cp500_dev_info uart2_si1; }; /* list of devices within FPGA of CP035 family (CP035, CP056, CP057) */ static struct cp500_devs cp035_devices = { .startup = { 0x0000, SZ_4K }, + .spi = { 0x1000, SZ_4K }, .i2c = { 0x4000, SZ_4K }, + .fan = { 0x9000, SZ_4K }, + .batt = { 0xA000, SZ_4K }, + .uart0_rfb = { 0xB000, SZ_4K, CP500_RFB_UART_MSIX }, + .uart2_si1 = { 0xD000, SZ_4K, CP500_SI1_UART_MSIX }, }; /* list of devices within FPGA of CP505 family (CP503, CP505, CP507) */ static struct cp500_devs cp505_devices = { .startup = { 0x0000, SZ_4K }, + .spi = { 0x4000, SZ_4K }, .i2c = { 0x5000, SZ_4K }, + .fan = { 0x9000, SZ_4K }, + .batt = { 0xA000, SZ_4K }, + .uart0_rfb = { 0xB000, SZ_4K, CP500_RFB_UART_MSIX }, + .uart2_si1 = { 0xD000, SZ_4K, CP500_SI1_UART_MSIX }, }; /* list of devices within FPGA of CP520 family (CP520, CP530) */ static struct cp500_devs cp520_devices = { - .startup = { 0x0000, SZ_4K }, - .i2c = { 0x5000, SZ_4K }, + .startup = { 0x0000, SZ_4K }, + .spi = { 0x4000, SZ_4K }, + .i2c = { 0x5000, SZ_4K }, + .fan = { 0x8000, SZ_4K }, + .batt = { 0x9000, SZ_4K }, + .uart0_rfb = { 0xC000, SZ_4K, CP500_RFB_UART_MSIX }, + .uart1_dbg = { 0xD000, SZ_4K, CP500_DEBUG_UART_MSIX }, +}; + +struct cp500_nvmem { + struct nvmem_device *nvmem; + unsigned int offset; }; struct cp500 { @@ -85,18 +139,31 @@ struct cp500 { int minor; int build; } version; + struct notifier_block nvmem_notifier; + atomic_t nvmem_notified; /* system FPGA BAR */ resource_size_t sys_hwbase; + struct keba_spi_auxdev *spi; struct keba_i2c_auxdev *i2c; + struct keba_fan_auxdev *fan; + struct keba_batt_auxdev *batt; + struct keba_uart_auxdev *uart0_rfb; + struct keba_uart_auxdev *uart1_dbg; + struct keba_uart_auxdev *uart2_si1; /* ECM EtherCAT BAR */ resource_size_t ecm_hwbase; + /* NVMEM devices */ + struct cp500_nvmem nvmem_cpu; + struct cp500_nvmem nvmem_user; + void __iomem *system_startup_addr; }; /* I2C devices */ +#define CP500_EEPROM_ADDR 0x50 static struct i2c_board_info cp500_i2c_info[] = { { /* temperature sensor */ I2C_BOARD_INFO("emc1403", 0x4c), @@ -107,30 +174,66 @@ static struct i2c_board_info cp500_i2c_info[] = { * CP505 family: bridge board * CP520 family: carrier board */ - I2C_BOARD_INFO("24c32", 0x50), - .dev_name = CP500_HW_CPU_EEPROM_NAME, + I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR), }, { /* interface board EEPROM */ - I2C_BOARD_INFO("24c32", 0x51), + I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 1), }, { /* * EEPROM (optional) * CP505 family: CPU board * CP520 family: MMI board */ - I2C_BOARD_INFO("24c32", 0x52), + I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 2), }, { /* extension module 0 EEPROM (optional) */ - I2C_BOARD_INFO("24c32", 0x53), + I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 3), }, { /* extension module 1 EEPROM (optional) */ - I2C_BOARD_INFO("24c32", 0x54), + I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 4), }, { /* extension module 2 EEPROM (optional) */ - I2C_BOARD_INFO("24c32", 0x55), + I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 5), }, { /* extension module 3 EEPROM (optional) */ - I2C_BOARD_INFO("24c32", 0x56), + I2C_BOARD_INFO("24c32", CP500_EEPROM_ADDR + 6), + } +}; + +/* SPI devices */ +static struct mtd_partition cp500_partitions[] = { + { + .name = "system-flash-parts", + .size = MTDPART_SIZ_FULL, + .offset = 0, + .mask_flags = 0 + } +}; +static const struct flash_platform_data cp500_w25q32 = { + .type = "w25q32", + .name = "system-flash", + .parts = cp500_partitions, + .nr_parts = ARRAY_SIZE(cp500_partitions), +}; +static const struct flash_platform_data cp500_m25p16 = { + .type = "m25p16", + .name = "system-flash", + .parts = cp500_partitions, + .nr_parts = ARRAY_SIZE(cp500_partitions), +}; +static struct spi_board_info cp500_spi_info[] = { + { /* system FPGA configuration bitstream flash */ + .modalias = "m25p80", + .platform_data = &cp500_m25p16, + .max_speed_hz = CP500_FLASH_HZ, + .chip_select = 0, + .mode = SPI_MODE_3, + }, { /* LAN9252 EtherCAT slave controller */ + .modalias = "lan9252", + .platform_data = NULL, + .max_speed_hz = CP500_LAN9252_HZ, + .chip_select = 1, + .mode = SPI_MODE_3, } }; @@ -229,7 +332,7 @@ static void cp500_i2c_release(struct device *dev) static int cp500_register_i2c(struct cp500 *cp500) { - int retval; + int ret; cp500->i2c = kzalloc(sizeof(*cp500->i2c), GFP_KERNEL); if (!cp500->i2c) @@ -251,30 +354,412 @@ static int cp500_register_i2c(struct cp500 *cp500) cp500->i2c->info_size = ARRAY_SIZE(cp500_i2c_info); cp500->i2c->info = cp500_i2c_info; - retval = auxiliary_device_init(&cp500->i2c->auxdev); - if (retval) { + ret = auxiliary_device_init(&cp500->i2c->auxdev); + if (ret) { kfree(cp500->i2c); cp500->i2c = NULL; - return retval; + return ret; } - retval = __auxiliary_device_add(&cp500->i2c->auxdev, "keba"); - if (retval) { + ret = __auxiliary_device_add(&cp500->i2c->auxdev, "keba"); + if (ret) { auxiliary_device_uninit(&cp500->i2c->auxdev); cp500->i2c = NULL; - return retval; + return ret; + } + + return 0; +} + +static void cp500_spi_release(struct device *dev) +{ + struct keba_spi_auxdev *spi = + container_of(dev, struct keba_spi_auxdev, auxdev.dev); + + kfree(spi); +} + +static int cp500_register_spi(struct cp500 *cp500, u8 esc_type) +{ + int info_size; + int ret; + + cp500->spi = kzalloc(sizeof(*cp500->spi), GFP_KERNEL); + if (!cp500->spi) + return -ENOMEM; + + if (CP500_IS_CP035(cp500)) + cp500_spi_info[0].platform_data = &cp500_w25q32; + if (esc_type == CP500_EEPROM_ESC_LAN9252) + info_size = ARRAY_SIZE(cp500_spi_info); + else + info_size = ARRAY_SIZE(cp500_spi_info) - 1; + + cp500->spi->auxdev.name = "spi"; + cp500->spi->auxdev.id = 0; + cp500->spi->auxdev.dev.release = cp500_spi_release; + cp500->spi->auxdev.dev.parent = &cp500->pci_dev->dev; + cp500->spi->io = (struct resource) { + /* SPI register area */ + .start = (resource_size_t) cp500->sys_hwbase + + cp500->devs->spi.offset, + .end = (resource_size_t) cp500->sys_hwbase + + cp500->devs->spi.offset + + cp500->devs->spi.size - 1, + .flags = IORESOURCE_MEM, + }; + cp500->spi->info_size = info_size; + cp500->spi->info = cp500_spi_info; + + ret = auxiliary_device_init(&cp500->spi->auxdev); + if (ret) { + kfree(cp500->spi); + cp500->spi = NULL; + + return ret; + } + ret = __auxiliary_device_add(&cp500->spi->auxdev, "keba"); + if (ret) { + auxiliary_device_uninit(&cp500->spi->auxdev); + cp500->spi = NULL; + + return ret; + } + + return 0; +} + +static void cp500_fan_release(struct device *dev) +{ + struct keba_fan_auxdev *fan = + container_of(dev, struct keba_fan_auxdev, auxdev.dev); + + kfree(fan); +} + +static int cp500_register_fan(struct cp500 *cp500) +{ + int ret; + + cp500->fan = kzalloc(sizeof(*cp500->fan), GFP_KERNEL); + if (!cp500->fan) + return -ENOMEM; + + cp500->fan->auxdev.name = "fan"; + cp500->fan->auxdev.id = 0; + cp500->fan->auxdev.dev.release = cp500_fan_release; + cp500->fan->auxdev.dev.parent = &cp500->pci_dev->dev; + cp500->fan->io = (struct resource) { + /* fan register area */ + .start = (resource_size_t) cp500->sys_hwbase + + cp500->devs->fan.offset, + .end = (resource_size_t) cp500->sys_hwbase + + cp500->devs->fan.offset + + cp500->devs->fan.size - 1, + .flags = IORESOURCE_MEM, + }; + + ret = auxiliary_device_init(&cp500->fan->auxdev); + if (ret) { + kfree(cp500->fan); + cp500->fan = NULL; + + return ret; + } + ret = __auxiliary_device_add(&cp500->fan->auxdev, "keba"); + if (ret) { + auxiliary_device_uninit(&cp500->fan->auxdev); + cp500->fan = NULL; + + return ret; + } + + return 0; +} + +static void cp500_batt_release(struct device *dev) +{ + struct keba_batt_auxdev *fan = + container_of(dev, struct keba_batt_auxdev, auxdev.dev); + + kfree(fan); +} + +static int cp500_register_batt(struct cp500 *cp500) +{ + int ret; + + cp500->batt = kzalloc(sizeof(*cp500->batt), GFP_KERNEL); + if (!cp500->batt) + return -ENOMEM; + + cp500->batt->auxdev.name = "batt"; + cp500->batt->auxdev.id = 0; + cp500->batt->auxdev.dev.release = cp500_batt_release; + cp500->batt->auxdev.dev.parent = &cp500->pci_dev->dev; + cp500->batt->io = (struct resource) { + /* battery register area */ + .start = (resource_size_t) cp500->sys_hwbase + + cp500->devs->batt.offset, + .end = (resource_size_t) cp500->sys_hwbase + + cp500->devs->batt.offset + + cp500->devs->batt.size - 1, + .flags = IORESOURCE_MEM, + }; + + ret = auxiliary_device_init(&cp500->batt->auxdev); + if (ret) { + kfree(cp500->batt); + cp500->batt = NULL; + + return ret; + } + ret = __auxiliary_device_add(&cp500->batt->auxdev, "keba"); + if (ret) { + auxiliary_device_uninit(&cp500->batt->auxdev); + cp500->batt = NULL; + + return ret; } return 0; } +static void cp500_uart_release(struct device *dev) +{ + struct keba_uart_auxdev *uart = + container_of(dev, struct keba_uart_auxdev, auxdev.dev); + + kfree(uart); +} + +static int cp500_register_uart(struct cp500 *cp500, + struct keba_uart_auxdev **uart, const char *name, + struct cp500_dev_info *info, unsigned int irq) +{ + int ret; + + *uart = kzalloc(sizeof(**uart), GFP_KERNEL); + if (!*uart) + return -ENOMEM; + + (*uart)->auxdev.name = name; + (*uart)->auxdev.id = 0; + (*uart)->auxdev.dev.release = cp500_uart_release; + (*uart)->auxdev.dev.parent = &cp500->pci_dev->dev; + (*uart)->io = (struct resource) { + /* UART register area */ + .start = (resource_size_t) cp500->sys_hwbase + info->offset, + .end = (resource_size_t) cp500->sys_hwbase + info->offset + + info->size - 1, + .flags = IORESOURCE_MEM, + }; + (*uart)->irq = irq; + + ret = auxiliary_device_init(&(*uart)->auxdev); + if (ret) { + kfree(*uart); + *uart = NULL; + + return ret; + } + ret = __auxiliary_device_add(&(*uart)->auxdev, "keba"); + if (ret) { + auxiliary_device_uninit(&(*uart)->auxdev); + *uart = NULL; + + return ret; + } + + return 0; +} + +static int cp500_nvmem_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct cp500_nvmem *nvmem = priv; + int ret; + + ret = nvmem_device_read(nvmem->nvmem, nvmem->offset + offset, bytes, + val); + if (ret != bytes) + return ret; + + return 0; +} + +static int cp500_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct cp500_nvmem *nvmem = priv; + int ret; + + ret = nvmem_device_write(nvmem->nvmem, nvmem->offset + offset, bytes, + val); + if (ret != bytes) + return ret; + + return 0; +} + +static int cp500_nvmem_register(struct cp500 *cp500, struct nvmem_device *nvmem) +{ + struct device *dev = &cp500->pci_dev->dev; + struct nvmem_config nvmem_config = {}; + struct nvmem_device *tmp; + + /* + * The main EEPROM of CP500 devices is logically split into two EEPROMs. + * The first logical EEPROM with 3 kB contains the type label which is + * programmed during production of the device. The second logical EEPROM + * with 1 kB is not programmed during production and can be used for + * arbitrary user data. + */ + + nvmem_config.dev = dev; + nvmem_config.owner = THIS_MODULE; + nvmem_config.id = NVMEM_DEVID_NONE; + nvmem_config.type = NVMEM_TYPE_EEPROM; + nvmem_config.root_only = true; + nvmem_config.reg_read = cp500_nvmem_read; + nvmem_config.reg_write = cp500_nvmem_write; + + cp500->nvmem_cpu.nvmem = nvmem; + cp500->nvmem_cpu.offset = CP500_EEPROM_CPU_OFFSET; + nvmem_config.name = CP500_EEPROM_CPU_NAME; + nvmem_config.size = CP500_EEPROM_CPU_SIZE; + nvmem_config.priv = &cp500->nvmem_cpu; + tmp = devm_nvmem_register(dev, &nvmem_config); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + + cp500->nvmem_user.nvmem = nvmem; + cp500->nvmem_user.offset = CP500_EEPROM_USER_OFFSET; + nvmem_config.name = CP500_EEPROM_USER_NAME; + nvmem_config.size = CP500_EEPROM_USER_SIZE; + nvmem_config.priv = &cp500->nvmem_user; + tmp = devm_nvmem_register(dev, &nvmem_config); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + + return 0; +} + +static int cp500_nvmem_match(struct device *dev, const void *data) +{ + const struct cp500 *cp500 = data; + struct i2c_client *client; + + /* match only CPU EEPROM below the cp500 device */ + dev = dev->parent; + client = i2c_verify_client(dev); + if (!client || client->addr != CP500_EEPROM_ADDR) + return 0; + while ((dev = dev->parent)) + if (dev == &cp500->pci_dev->dev) + return 1; + + return 0; +} + +static void cp500_devm_nvmem_put(void *data) +{ + struct nvmem_device *nvmem = data; + + nvmem_device_put(nvmem); +} + +static int cp500_nvmem(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct nvmem_device *nvmem; + struct cp500 *cp500; + struct device *dev; + int notified; + u8 esc_type; + int ret; + + if (action != NVMEM_ADD) + return NOTIFY_DONE; + cp500 = container_of(nb, struct cp500, nvmem_notifier); + dev = &cp500->pci_dev->dev; + + /* process CPU EEPROM content only once */ + notified = atomic_read(&cp500->nvmem_notified); + if (notified) + return NOTIFY_DONE; + nvmem = nvmem_device_find(cp500, cp500_nvmem_match); + if (IS_ERR_OR_NULL(nvmem)) + return NOTIFY_DONE; + if (!atomic_try_cmpxchg_relaxed(&cp500->nvmem_notified, ¬ified, 1)) { + nvmem_device_put(nvmem); + + return NOTIFY_DONE; + } + + ret = devm_add_action_or_reset(dev, cp500_devm_nvmem_put, nvmem); + if (ret) + return ret; + + ret = cp500_nvmem_register(cp500, nvmem); + if (ret) + return ret; + + ret = nvmem_device_read(nvmem, CP500_EEPROM_DA_OFFSET, sizeof(esc_type), + (void *)&esc_type); + if (ret != sizeof(esc_type)) { + dev_warn(dev, "Failed to read device assembly!\n"); + + return NOTIFY_DONE; + } + esc_type &= CP500_EEPROM_DA_ESC_TYPE_MASK; + + if (cp500_register_spi(cp500, esc_type)) + dev_warn(dev, "Failed to register SPI!\n"); + + return NOTIFY_OK; +} + static void cp500_register_auxiliary_devs(struct cp500 *cp500) { struct device *dev = &cp500->pci_dev->dev; + u8 present = ioread8(cp500->system_startup_addr + CP500_PRESENT_REG); if (cp500_register_i2c(cp500)) - dev_warn(dev, "Failed to register i2c!\n"); + dev_warn(dev, "Failed to register I2C!\n"); + if (present & CP500_PRESENT_FAN0) + if (cp500_register_fan(cp500)) + dev_warn(dev, "Failed to register fan!\n"); + if (cp500_register_batt(cp500)) + dev_warn(dev, "Failed to register battery!\n"); + if (cp500->devs->uart0_rfb.size && + cp500->devs->uart0_rfb.msix < cp500->msix_num) { + int irq = pci_irq_vector(cp500->pci_dev, + cp500->devs->uart0_rfb.msix); + + if (cp500_register_uart(cp500, &cp500->uart0_rfb, "rs485-uart", + &cp500->devs->uart0_rfb, irq)) + dev_warn(dev, "Failed to register RFB UART!\n"); + } + if (cp500->devs->uart1_dbg.size && + cp500->devs->uart1_dbg.msix < cp500->msix_num) { + int irq = pci_irq_vector(cp500->pci_dev, + cp500->devs->uart1_dbg.msix); + + if (cp500_register_uart(cp500, &cp500->uart1_dbg, "rs232-uart", + &cp500->devs->uart1_dbg, irq)) + dev_warn(dev, "Failed to register debug UART!\n"); + } + if (cp500->devs->uart2_si1.size && + cp500->devs->uart2_si1.msix < cp500->msix_num) { + int irq = pci_irq_vector(cp500->pci_dev, + cp500->devs->uart2_si1.msix); + + if (cp500_register_uart(cp500, &cp500->uart2_si1, "uart", + &cp500->devs->uart2_si1, irq)) + dev_warn(dev, "Failed to register SI1 UART!\n"); + } } static void cp500_unregister_dev(struct auxiliary_device *auxdev) @@ -285,11 +770,34 @@ static void cp500_unregister_dev(struct auxiliary_device *auxdev) static void cp500_unregister_auxiliary_devs(struct cp500 *cp500) { - + if (cp500->spi) { + cp500_unregister_dev(&cp500->spi->auxdev); + cp500->spi = NULL; + } if (cp500->i2c) { cp500_unregister_dev(&cp500->i2c->auxdev); cp500->i2c = NULL; } + if (cp500->fan) { + cp500_unregister_dev(&cp500->fan->auxdev); + cp500->fan = NULL; + } + if (cp500->batt) { + cp500_unregister_dev(&cp500->batt->auxdev); + cp500->batt = NULL; + } + if (cp500->uart0_rfb) { + cp500_unregister_dev(&cp500->uart0_rfb->auxdev); + cp500->uart0_rfb = NULL; + } + if (cp500->uart1_dbg) { + cp500_unregister_dev(&cp500->uart1_dbg->auxdev); + cp500->uart1_dbg = NULL; + } + if (cp500->uart2_si1) { + cp500_unregister_dev(&cp500->uart2_si1->auxdev); + cp500->uart2_si1 = NULL; + } } static irqreturn_t cp500_axi_handler(int irq, void *dev) @@ -396,15 +904,21 @@ static int cp500_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) pci_set_drvdata(pci_dev, cp500); + cp500->nvmem_notifier.notifier_call = cp500_nvmem; + ret = nvmem_register_notifier(&cp500->nvmem_notifier); + if (ret != 0) + goto out_free_irq; ret = cp500_enable(cp500); if (ret != 0) - goto out_free_irq; + goto out_unregister_nvmem; cp500_register_auxiliary_devs(cp500); return 0; +out_unregister_nvmem: + nvmem_unregister_notifier(&cp500->nvmem_notifier); out_free_irq: pci_free_irq_vectors(pci_dev); out_disable: @@ -422,6 +936,8 @@ static void cp500_remove(struct pci_dev *pci_dev) cp500_disable(cp500); + nvmem_unregister_notifier(&cp500->nvmem_notifier); + pci_set_drvdata(pci_dev, 0); pci_free_irq_vectors(pci_dev); diff --git a/drivers/misc/keba/lan9252.c b/drivers/misc/keba/lan9252.c new file mode 100644 index 00000000000000..fc54afd1d05b8b --- /dev/null +++ b/drivers/misc/keba/lan9252.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) KEBA Industrial Automation Gmbh 2024 + * + * Driver for LAN9252 on KEBA CP500 devices + * + * This driver is used for updating the configuration of the LAN9252 controller + * on KEBA CP500 devices. The LAN9252 is connected over SPI, which is also named + * PDI. + */ + +#include +#include + +/* SPI commands */ +#define LAN9252_SPI_READ 0x3 +#define LAN9252_SPI_WRITE 0x2 + +struct lan9252_read_cmd { + u8 cmd; + u8 addr_0; + u8 addr_1; +} __packed; + +struct lan9252_write_cmd { + u8 cmd; + u8 addr_0; + u8 addr_1; + u32 data; +} __packed; + +/* byte test register */ +#define LAN9252_BYTE_TEST 0x64 +#define LAN9252_BYTE_TEST_VALUE 0x87654321 + +/* hardware configuration register */ +#define LAN9252_HW_CFG 0x74 +#define LAN9252_HW_CFG_READY 0x08000000 + +/* EtherCAT CSR interface data register */ +#define LAN9252_ECAT_CSR_DATA 0x300 + +/* EtherCAT CSR interface command register */ +#define LAN9252_ECAT_CSR_CMD 0x304 +#define LAN9252_ECAT_CSR_BUSY 0x80000000 +#define LAN9252_ECAT_CSR_READ 0x40000000 + +/* EtherCAT slave controller MII register */ +#define LAN9252_ESC_MII 0x510 +#define LAN9252_ESC_MII_BUSY 0x8000 +#define LAN9252_ESC_MII_CMD_ERR 0x4000 +#define LAN9252_ESC_MII_READ_ERR 0x2000 +#define LAN9252_ESC_MII_ERR_MASK (LAN9252_ESC_MII_CMD_ERR | \ + LAN9252_ESC_MII_READ_ERR) +#define LAN9252_ESC_MII_WRITE 0x0200 +#define LAN9252_ESC_MII_READ 0x0100 + +/* EtherCAT slave controller PHY address register */ +#define LAN9252_ESC_PHY_ADDR 0x512 + +/* EtherCAT slave controller PHY register address register */ +#define LAN9252_ESC_PHY_REG_ADDR 0x513 + +/* EtherCAT slave controller PHY data register */ +#define LAN9252_ESC_PHY_DATA 0x514 + +/* EtherCAT slave controller PDI access state register */ +#define LAN9252_ESC_MII_PDI 0x517 +#define LAN9252_ESC_MII_ACCESS_PDI 0x01 +#define LAN9252_ESC_MII_ACCESS_ECAT 0x00 + +/* PHY address */ +#define PHY_ADDRESS 2 + +#define SPI_RETRY_COUNT 10 +#define SPI_WAIT_US 100 +#define SPI_CSR_WAIT_US 500 + +static int lan9252_spi_read(struct spi_device *spi, u16 addr, u32 *data) +{ + struct lan9252_read_cmd cmd; + + cmd.cmd = LAN9252_SPI_READ; + cmd.addr_0 = (addr >> 8) & 0xFF; + cmd.addr_1 = addr & 0xFF; + + return spi_write_then_read(spi, (u8 *)&cmd, + sizeof(struct lan9252_read_cmd), + (u8 *)data, sizeof(u32)); +} + +static int lan9252_spi_write(struct spi_device *spi, u16 addr, u32 data) +{ + struct lan9252_write_cmd cmd; + + cmd.cmd = LAN9252_SPI_WRITE; + cmd.addr_0 = (addr >> 8) & 0xFF; + cmd.addr_1 = addr & 0xFF; + cmd.data = data; + + return spi_write(spi, (u8 *)&cmd, sizeof(struct lan9252_write_cmd)); +} + +static bool lan9252_init(struct spi_device *spi) +{ + u32 data; + int ret; + + ret = lan9252_spi_read(spi, LAN9252_BYTE_TEST, &data); + if (ret || data != LAN9252_BYTE_TEST_VALUE) + return false; + + ret = lan9252_spi_read(spi, LAN9252_HW_CFG, &data); + if (ret || !(data & LAN9252_HW_CFG_READY)) + return false; + + return true; +} + +static u8 lan9252_esc_get_size(u16 addr) +{ + if (addr == LAN9252_ESC_MII || addr == LAN9252_ESC_PHY_DATA) + return 2; + + return 1; +} + +static int lan9252_esc_wait(struct spi_device *spi) +{ + ktime_t timeout = ktime_add_us(ktime_get(), SPI_WAIT_US); + u32 data; + int ret; + + /* wait while CSR command is busy */ + for (;;) { + ret = lan9252_spi_read(spi, LAN9252_ECAT_CSR_CMD, &data); + if (ret) + return ret; + if (!(data & LAN9252_ECAT_CSR_BUSY)) + return 0; + + if (ktime_compare(ktime_get(), timeout) > 0) { + ret = lan9252_spi_read(spi, LAN9252_ECAT_CSR_CMD, &data); + if (ret) + return ret; + break; + } + } + + return (!(data & LAN9252_ECAT_CSR_BUSY)) ? 0 : -ETIMEDOUT; +} + +static int lan9252_esc_read(struct spi_device *spi, u16 addr, u32 *data) +{ + u32 csr_cmd; + u8 size; + int ret; + + size = lan9252_esc_get_size(addr); + csr_cmd = LAN9252_ECAT_CSR_BUSY | LAN9252_ECAT_CSR_READ; + csr_cmd |= (size << 16) | addr; + ret = lan9252_spi_write(spi, LAN9252_ECAT_CSR_CMD, csr_cmd); + if (ret) + return ret; + + ret = lan9252_esc_wait(spi); + if (ret) + return ret; + + ret = lan9252_spi_read(spi, LAN9252_ECAT_CSR_DATA, data); + if (ret) + return ret; + + return 0; +} + +static int lan9252_esc_write(struct spi_device *spi, u16 addr, u32 data) +{ + u32 csr_cmd; + u8 size; + int ret; + + ret = lan9252_spi_write(spi, LAN9252_ECAT_CSR_DATA, data); + if (ret) + return ret; + + size = lan9252_esc_get_size(addr); + csr_cmd = LAN9252_ECAT_CSR_BUSY; + csr_cmd |= (size << 16) | addr; + ret = lan9252_spi_write(spi, LAN9252_ECAT_CSR_CMD, csr_cmd); + if (ret) + return ret; + + ret = lan9252_esc_wait(spi); + if (ret) + return ret; + + return 0; +} + +static int lan9252_access_mii(struct spi_device *spi, bool access) +{ + u32 data; + + if (access) + data = LAN9252_ESC_MII_ACCESS_PDI; + else + data = LAN9252_ESC_MII_ACCESS_ECAT; + + return lan9252_esc_write(spi, LAN9252_ESC_MII_PDI, data); +} + +static int lan9252_mii_wait(struct spi_device *spi) +{ + ktime_t timeout = ktime_add_us(ktime_get(), SPI_CSR_WAIT_US); + u32 data; + int ret; + + /* wait while MII control state machine is busy */ + for (;;) { + ret = lan9252_esc_read(spi, LAN9252_ESC_MII, &data); + if (ret) + return ret; + if (data & LAN9252_ESC_MII_ERR_MASK) + return -EIO; + if (!(data & LAN9252_ESC_MII_BUSY)) + return 0; + + if (ktime_compare(ktime_get(), timeout) > 0) { + ret = lan9252_esc_read(spi, LAN9252_ESC_MII, &data); + if (ret) + return ret; + if (data & LAN9252_ESC_MII_ERR_MASK) + return -EIO; + break; + } + } + + return (!(data & LAN9252_ESC_MII_BUSY)) ? 0 : -ETIMEDOUT; +} + +static int lan9252_mii_read(struct spi_device *spi, u8 phy_addr, u8 reg_addr, + u32 *data) +{ + int ret; + + ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_ADDR, phy_addr); + if (ret) + return ret; + ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_REG_ADDR, reg_addr); + if (ret) + return ret; + + ret = lan9252_esc_write(spi, LAN9252_ESC_MII, LAN9252_ESC_MII_READ); + if (ret) + return ret; + + ret = lan9252_mii_wait(spi); + if (ret) + return ret; + + return lan9252_esc_read(spi, LAN9252_ESC_PHY_DATA, data); +} + +static int lan9252_mii_write(struct spi_device *spi, u8 phy_addr, u8 reg_addr, + u32 data) +{ + int ret; + + ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_ADDR, phy_addr); + if (ret) + return ret; + ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_REG_ADDR, reg_addr); + if (ret) + return ret; + ret = lan9252_esc_write(spi, LAN9252_ESC_PHY_DATA, data); + if (ret) + return ret; + + ret = lan9252_esc_write(spi, LAN9252_ESC_MII, LAN9252_ESC_MII_WRITE); + if (ret) + return ret; + + return lan9252_mii_wait(spi); +} + +static int lan9252_probe(struct spi_device *spi) +{ + u32 data; + int retry = SPI_RETRY_COUNT; + int ret; + + /* execute specified initialization sequence */ + while (retry && !lan9252_init(spi)) + retry--; + if (retry == 0) { + dev_err(&spi->dev, + "Can't initialize LAN9252 SPI communication!"); + return -EIO; + } + + /* enable access to MII management for PDI */ + ret = lan9252_access_mii(spi, true); + if (ret) { + dev_err(&spi->dev, "Can't enable access to MII management!"); + return ret; + } + + /* + * check PHY configuration and configure if necessary + * - full duplex + * - auto negotiation disabled + * - 100 Mbps + */ + ret = lan9252_mii_read(spi, PHY_ADDRESS, MII_BMCR, &data); + if (ret) { + dev_err(&spi->dev, "Can't read LAN9252 configuration!"); + goto out; + } + if (!(data & BMCR_FULLDPLX) || (data & BMCR_ANENABLE) || + !(data & BMCR_SPEED100)) { + /* + */ + data &= ~(BMCR_ANENABLE); + data |= (BMCR_FULLDPLX | BMCR_SPEED100); + ret = lan9252_mii_write(spi, PHY_ADDRESS, MII_BMCR, data); + if (ret) + dev_err(&spi->dev, + "Can't write LAN9252 configuration!"); + } + + dev_info(&spi->dev, "LAN9252 PHY configuration"); + +out: + /* disable access to MII management for PDI */ + lan9252_access_mii(spi, false); + + return ret; +} + +static const struct spi_device_id lan9252_id[] = { + {"lan9252"}, + {} +}; +MODULE_DEVICE_TABLE(spi, lan9252_id); + +static struct spi_driver lan9252_driver = { + .driver = { + .name = "lan9252", + }, + .probe = lan9252_probe, + .id_table = lan9252_id, +}; +module_spi_driver(lan9252_driver); + +MODULE_AUTHOR("Petar Bojanic "); +MODULE_AUTHOR("Gerhard Engleder "); +MODULE_DESCRIPTION("KEBA LAN9252 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/lan966x_pci.c b/drivers/misc/lan966x_pci.c new file mode 100644 index 00000000000000..9c79b58137e52c --- /dev/null +++ b/drivers/misc/lan966x_pci.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip LAN966x PCI driver + * + * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries. + * + * Authors: + * Clément Léger + * Hervé Codina + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */ +extern char __dtbo_lan966x_pci_begin[]; +extern char __dtbo_lan966x_pci_end[]; + +struct pci_dev_intr_ctrl { + struct pci_dev *pci_dev; + struct irq_domain *irq_domain; + int irq; +}; + +static int pci_dev_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); + return 0; +} + +static const struct irq_domain_ops pci_dev_irq_domain_ops = { + .map = pci_dev_irq_domain_map, + .xlate = irq_domain_xlate_onecell, +}; + +static irqreturn_t pci_dev_irq_handler(int irq, void *data) +{ + struct pci_dev_intr_ctrl *intr_ctrl = data; + int ret; + + ret = generic_handle_domain_irq(intr_ctrl->irq_domain, 0); + return ret ? IRQ_NONE : IRQ_HANDLED; +} + +static struct pci_dev_intr_ctrl *pci_dev_create_intr_ctrl(struct pci_dev *pdev) +{ + struct pci_dev_intr_ctrl *intr_ctrl __free(kfree) = NULL; + struct fwnode_handle *fwnode; + int ret; + + fwnode = dev_fwnode(&pdev->dev); + if (!fwnode) + return ERR_PTR(-ENODEV); + + intr_ctrl = kmalloc(sizeof(*intr_ctrl), GFP_KERNEL); + if (!intr_ctrl) + return ERR_PTR(-ENOMEM); + + intr_ctrl->pci_dev = pdev; + + intr_ctrl->irq_domain = irq_domain_create_linear(fwnode, 1, &pci_dev_irq_domain_ops, + intr_ctrl); + if (!intr_ctrl->irq_domain) { + pci_err(pdev, "Failed to create irqdomain\n"); + return ERR_PTR(-ENOMEM); + } + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX); + if (ret < 0) { + pci_err(pdev, "Unable alloc irq vector (%d)\n", ret); + goto err_remove_domain; + } + intr_ctrl->irq = pci_irq_vector(pdev, 0); + ret = request_irq(intr_ctrl->irq, pci_dev_irq_handler, IRQF_SHARED, + pci_name(pdev), intr_ctrl); + if (ret) { + pci_err(pdev, "Unable to request irq %d (%d)\n", intr_ctrl->irq, ret); + goto err_free_irq_vector; + } + + return_ptr(intr_ctrl); + +err_free_irq_vector: + pci_free_irq_vectors(pdev); +err_remove_domain: + irq_domain_remove(intr_ctrl->irq_domain); + return ERR_PTR(ret); +} + +static void pci_dev_remove_intr_ctrl(struct pci_dev_intr_ctrl *intr_ctrl) +{ + free_irq(intr_ctrl->irq, intr_ctrl); + pci_free_irq_vectors(intr_ctrl->pci_dev); + irq_dispose_mapping(irq_find_mapping(intr_ctrl->irq_domain, 0)); + irq_domain_remove(intr_ctrl->irq_domain); + kfree(intr_ctrl); +} + +static void devm_pci_dev_remove_intr_ctrl(void *intr_ctrl) +{ + pci_dev_remove_intr_ctrl(intr_ctrl); +} + +static int devm_pci_dev_create_intr_ctrl(struct pci_dev *pdev) +{ + struct pci_dev_intr_ctrl *intr_ctrl; + + intr_ctrl = pci_dev_create_intr_ctrl(pdev); + if (IS_ERR(intr_ctrl)) + return PTR_ERR(intr_ctrl); + + return devm_add_action_or_reset(&pdev->dev, devm_pci_dev_remove_intr_ctrl, intr_ctrl); +} + +struct lan966x_pci { + struct device *dev; + int ovcs_id; +}; + +static int lan966x_pci_load_overlay(struct lan966x_pci *data) +{ + u32 dtbo_size = __dtbo_lan966x_pci_end - __dtbo_lan966x_pci_begin; + void *dtbo_start = __dtbo_lan966x_pci_begin; + + return of_overlay_fdt_apply(dtbo_start, dtbo_size, &data->ovcs_id, dev_of_node(data->dev)); +} + +static void lan966x_pci_unload_overlay(struct lan966x_pci *data) +{ + of_overlay_remove(&data->ovcs_id); +} + +static int lan966x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *dev = &pdev->dev; + struct lan966x_pci *data; + int ret; + + /* + * On ACPI system, fwnode can point to the ACPI node. + * This driver needs an of_node to be used as the device-tree overlay + * target. This of_node should be set by the PCI core if it succeeds in + * creating it (CONFIG_PCI_DYNAMIC_OF_NODES feature). + * Check here for the validity of this of_node. + */ + if (!dev_of_node(dev)) + return dev_err_probe(dev, -EINVAL, "Missing of_node for device\n"); + + /* Need to be done before devm_pci_dev_create_intr_ctrl. + * It allocates an IRQ and so pdev->irq is updated. + */ + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = devm_pci_dev_create_intr_ctrl(pdev); + if (ret) + return ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + pci_set_drvdata(pdev, data); + data->dev = dev; + + ret = lan966x_pci_load_overlay(data); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = of_platform_default_populate(dev_of_node(dev), NULL, dev); + if (ret) + goto err_unload_overlay; + + return 0; + +err_unload_overlay: + lan966x_pci_unload_overlay(data); + return ret; +} + +static void lan966x_pci_remove(struct pci_dev *pdev) +{ + struct lan966x_pci *data = pci_get_drvdata(pdev); + + of_platform_depopulate(data->dev); + + lan966x_pci_unload_overlay(data); +} + +static struct pci_device_id lan966x_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_EFAR, 0x9660) }, + { } +}; +MODULE_DEVICE_TABLE(pci, lan966x_pci_ids); + +static struct pci_driver lan966x_pci_driver = { + .name = "mchp_lan966x_pci", + .id_table = lan966x_pci_ids, + .probe = lan966x_pci_probe, + .remove = lan966x_pci_remove, +}; +module_pci_driver(lan966x_pci_driver); + +MODULE_AUTHOR("Herve Codina "); +MODULE_DESCRIPTION("Microchip LAN966x PCI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/lan966x_pci.dtso b/drivers/misc/lan966x_pci.dtso new file mode 100644 index 00000000000000..7b196b0a0eb65a --- /dev/null +++ b/drivers/misc/lan966x_pci.dtso @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Microchip UNG + */ + +#include +#include +#include +#include +#include + +/dts-v1/; +/plugin/; + +/ { + fragment@0 { + target-path = ""; + + /* + * These properties allow to avoid a dtc warnings. + * The real interrupt controller is the PCI device itself. It + * is the node on which the device tree overlay will be applied. + * This node has those properties. + */ + #interrupt-cells = <1>; + interrupt-controller; + + __overlay__ { + #address-cells = <3>; + #size-cells = <2>; + + cpu_clk: clock-600000000 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <600000000>; /* CPU clock = 600MHz */ + }; + + ddr_clk: clock-30000000 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <30000000>; /* Fabric clock = 30MHz */ + }; + + sys_clk: clock-15625000 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <15625000>; /* System clock = 15.625MHz */ + }; + + pci-ep-bus@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + /* + * map @0xe2000000 (32MB) to BAR0 (CPU) + * map @0xe0000000 (16MB) to BAR1 (AMBA) + */ + ranges = <0xe2000000 0x00 0x00 0x00 0x2000000 + 0xe0000000 0x01 0x00 0x00 0x1000000>; + + oic: oic@e00c0120 { + compatible = "microchip,lan966x-oic"; + #interrupt-cells = <2>; + interrupt-controller; + interrupts = <0>; /* PCI INTx assigned interrupt */ + reg = <0xe00c0120 0x190>; + }; + + cpu_ctrl: syscon@e00c0000 { + compatible = "microchip,lan966x-cpu-syscon", "syscon"; + reg = <0xe00c0000 0xa8>; + }; + + reset: reset@e200400c { + compatible = "microchip,lan966x-switch-reset"; + reg = <0xe200400c 0x4>, <0xe00c0000 0xa8>; + reg-names = "gcb","cpu"; + #reset-cells = <1>; + cpu-syscon = <&cpu_ctrl>; + }; + + gpio: pinctrl@e2004064 { + compatible = "microchip,lan966x-pinctrl"; + reg = <0xe2004064 0xb4>, + <0xe2010024 0x138>; + resets = <&reset 0>; + reset-names = "switch"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&gpio 0 0 78>; + interrupt-parent = <&oic>; + interrupt-controller; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + #interrupt-cells = <2>; + + tod_pins: tod_pins { + pins = "GPIO_36"; + function = "ptpsync_1"; + }; + + fc0_a_pins: fcb4-i2c-pins { + /* RXD, TXD */ + pins = "GPIO_9", "GPIO_10"; + function = "fc0_a"; + }; + + }; + + serdes: serdes@e202c000 { + compatible = "microchip,lan966x-serdes"; + reg = <0xe202c000 0x9c>, + <0xe2004010 0x4>; + #phy-cells = <2>; + }; + + mdio1: mdio@e200413c { + #address-cells = <1>; + #size-cells = <0>; + compatible = "microchip,lan966x-miim"; + reg = <0xe200413c 0x24>, + <0xe2010020 0x4>; + + resets = <&reset 0>; + reset-names = "switch"; + + lan966x_phy0: ethernet-lan966x_phy@1 { + reg = <1>; + }; + + lan966x_phy1: ethernet-lan966x_phy@2 { + reg = <2>; + }; + }; + + switch: switch@e0000000 { + compatible = "microchip,lan966x-switch"; + reg = <0xe0000000 0x0100000>, + <0xe2000000 0x0800000>; + reg-names = "cpu", "gcb"; + + interrupt-parent = <&oic>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, + <9 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "xtr", "ana"; + + resets = <&reset 0>; + reset-names = "switch"; + + pinctrl-names = "default"; + pinctrl-0 = <&tod_pins>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + port0: port@0 { + phy-handle = <&lan966x_phy0>; + + reg = <0>; + phy-mode = "gmii"; + phys = <&serdes 0 CU(0)>; + }; + + port1: port@1 { + phy-handle = <&lan966x_phy1>; + + reg = <1>; + phy-mode = "gmii"; + phys = <&serdes 1 CU(1)>; + }; + }; + }; + }; + }; + }; +}; diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 62ba0152547975..376047beea3d64 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -445,7 +445,7 @@ static void lkdtm_FAM_BOUNDS(void) pr_err("FAIL: survived access of invalid flexible array member index!\n"); - if (!__has_attribute(__counted_by__)) + if (!IS_ENABLED(CONFIG_CC_HAS_COUNTED_BY)) pr_warn("This is expected since this %s was built with a compiler that does not support __counted_by\n", lkdtm_kernel_info); else if (IS_ENABLED(CONFIG_UBSAN_BOUNDS)) diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 5576146ab13bcb..718ec5d81d940f 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -145,8 +145,8 @@ ssize_t __mei_cl_send_timeout(struct mei_cl *cl, const u8 *buf, size_t length, u * @cl: host client * @buf: buffer to receive * @length: buffer length - * @mode: io mode * @vtag: virtual tag + * @mode: io mode * @timeout: recv timeout, 0 for infinite timeout * * Return: read size in bytes of < 0 on error diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c index 20a11b299bcd00..435760b1e86f7a 100644 --- a/drivers/misc/mei/platform-vsc.c +++ b/drivers/misc/mei/platform-vsc.c @@ -256,8 +256,6 @@ static int mei_vsc_hw_reset(struct mei_device *mei_dev, bool intr_enable) vsc_tp_reset(hw->tp); - vsc_tp_intr_disable(hw->tp); - return vsc_tp_init(hw->tp, mei_dev->dev); } @@ -437,7 +435,7 @@ MODULE_DEVICE_TABLE(platform, mei_vsc_id_table); static struct platform_driver mei_vsc_drv = { .probe = mei_vsc_probe, - .remove_new = mei_vsc_remove, + .remove = mei_vsc_remove, .id_table = mei_vsc_id_table, .driver = { .name = MEI_VSC_DRV_NAME, @@ -451,4 +449,4 @@ MODULE_AUTHOR("Wentong Wu "); MODULE_AUTHOR("Zhifeng Wang "); MODULE_DESCRIPTION("Intel Visual Sensing Controller Interface"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(VSC_TP); +MODULE_IMPORT_NS("VSC_TP"); diff --git a/drivers/misc/mei/vsc-fw-loader.c b/drivers/misc/mei/vsc-fw-loader.c index 9f129bc641f699..43abefa806e115 100644 --- a/drivers/misc/mei/vsc-fw-loader.c +++ b/drivers/misc/mei/vsc-fw-loader.c @@ -317,28 +317,34 @@ static int vsc_identify_silicon(struct vsc_fw_loader *fw_loader) cmd->data.dump_mem.addr = cpu_to_le32(VSC_EFUSE_ADDR); cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32)); ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE); - if (ret) - return ret; - if (ack->token == VSC_TOKEN_ERROR) - return -EINVAL; + if (ret || ack->token == VSC_TOKEN_ERROR) { + dev_err(fw_loader->dev, "CMD_DUMP_MEM error %d token %d\n", ret, ack->token); + return ret ?: -EINVAL; + } cmd->magic = cpu_to_le32(VSC_MAGIC_NUM); cmd->cmd_id = VSC_CMD_GET_CONT; ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE); - if (ret) - return ret; - if (ack->token != VSC_TOKEN_DUMP_RESP) - return -EINVAL; + if (ret || ack->token != VSC_TOKEN_DUMP_RESP) { + dev_err(fw_loader->dev, "CMD_GETCONT error %d token %d\n", ret, ack->token); + return ret ?: -EINVAL; + } version = FIELD_GET(VSC_MAINSTEPPING_VERSION_MASK, ack->payload[0]); sub_version = FIELD_GET(VSC_SUBSTEPPING_VERSION_MASK, ack->payload[0]); - if (version != VSC_MAINSTEPPING_VERSION_A) + if (version != VSC_MAINSTEPPING_VERSION_A) { + dev_err(fw_loader->dev, "mainstepping mismatch expected %d got %d\n", + VSC_MAINSTEPPING_VERSION_A, version); return -EINVAL; + } if (sub_version != VSC_SUBSTEPPING_VERSION_0 && - sub_version != VSC_SUBSTEPPING_VERSION_1) + sub_version != VSC_SUBSTEPPING_VERSION_1) { + dev_err(fw_loader->dev, "substepping %d is out of supported range %d - %d\n", + sub_version, VSC_SUBSTEPPING_VERSION_0, VSC_SUBSTEPPING_VERSION_1); return -EINVAL; + } dev_info(fw_loader->dev, "silicon stepping version is %u:%u\n", version, sub_version); @@ -767,4 +773,4 @@ int vsc_tp_init(struct vsc_tp *tp, struct device *dev) return ret; } -EXPORT_SYMBOL_NS_GPL(vsc_tp_init, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_init, "VSC_TP"); diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c index 1618cca9a7317f..35d349fee76989 100644 --- a/drivers/misc/mei/vsc-tp.c +++ b/drivers/misc/mei/vsc-tp.c @@ -299,7 +299,7 @@ int vsc_tp_xfer(struct vsc_tp *tp, u8 cmd, const void *obuf, size_t olen, return ret; } -EXPORT_SYMBOL_NS_GPL(vsc_tp_xfer, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_xfer, "VSC_TP"); /** * vsc_tp_rom_xfer - transfer data to rom code @@ -364,10 +364,8 @@ void vsc_tp_reset(struct vsc_tp *tp) gpiod_set_value_cansleep(tp->wakeupfw, 1); atomic_set(&tp->assert_cnt, 0); - - enable_irq(tp->spi->irq); } -EXPORT_SYMBOL_NS_GPL(vsc_tp_reset, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_reset, "VSC_TP"); /** * vsc_tp_need_read - check if device has data to sent @@ -385,7 +383,7 @@ bool vsc_tp_need_read(struct vsc_tp *tp) return true; } -EXPORT_SYMBOL_NS_GPL(vsc_tp_need_read, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_need_read, "VSC_TP"); /** * vsc_tp_register_event_cb - register a callback function to receive event @@ -402,7 +400,7 @@ int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb, return 0; } -EXPORT_SYMBOL_NS_GPL(vsc_tp_register_event_cb, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_register_event_cb, "VSC_TP"); /** * vsc_tp_request_irq - request irq for vsc_tp device @@ -423,7 +421,7 @@ int vsc_tp_request_irq(struct vsc_tp *tp) return 0; } -EXPORT_SYMBOL_NS_GPL(vsc_tp_request_irq, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_request_irq, "VSC_TP"); /** * vsc_tp_free_irq - free irq for vsc_tp device @@ -433,7 +431,7 @@ void vsc_tp_free_irq(struct vsc_tp *tp) { free_irq(tp->spi->irq, tp); } -EXPORT_SYMBOL_NS_GPL(vsc_tp_free_irq, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_free_irq, "VSC_TP"); /** * vsc_tp_intr_synchronize - synchronize vsc_tp interrupt @@ -443,7 +441,7 @@ void vsc_tp_intr_synchronize(struct vsc_tp *tp) { synchronize_irq(tp->spi->irq); } -EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_synchronize, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_synchronize, "VSC_TP"); /** * vsc_tp_intr_enable - enable vsc_tp interrupt @@ -453,7 +451,7 @@ void vsc_tp_intr_enable(struct vsc_tp *tp) { enable_irq(tp->spi->irq); } -EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_enable, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_enable, "VSC_TP"); /** * vsc_tp_intr_disable - disable vsc_tp interrupt @@ -463,7 +461,7 @@ void vsc_tp_intr_disable(struct vsc_tp *tp) { disable_irq(tp->spi->irq); } -EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_disable, VSC_TP); +EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_disable, "VSC_TP"); static int vsc_tp_match_any(struct acpi_device *adev, void *data) { diff --git a/drivers/misc/ocxl/sysfs.c b/drivers/misc/ocxl/sysfs.c index 405180d47d9bff..07520d6e6dc557 100644 --- a/drivers/misc/ocxl/sysfs.c +++ b/drivers/misc/ocxl/sysfs.c @@ -125,7 +125,7 @@ static const struct vm_operations_struct global_mmio_vmops = { }; static int global_mmio_mmap(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, + const struct bin_attribute *bin_attr, struct vm_area_struct *vma) { struct ocxl_afu *afu = to_afu(kobj_to_dev(kobj)); diff --git a/drivers/misc/open-dice.c b/drivers/misc/open-dice.c index e6a61e6d9427fa..24c29e0f00ef16 100644 --- a/drivers/misc/open-dice.c +++ b/drivers/misc/open-dice.c @@ -178,7 +178,7 @@ static const struct of_device_id open_dice_of_match[] = { }; static struct platform_driver open_dice_driver = { - .remove_new = open_dice_remove, + .remove = open_dice_remove, .driver = { .name = DRIVER_NAME, .of_match_table = open_dice_of_match, diff --git a/drivers/misc/rpmb-core.c b/drivers/misc/rpmb-core.c index bc68cde1a8bfd8..2d653926cdbbb0 100644 --- a/drivers/misc/rpmb-core.c +++ b/drivers/misc/rpmb-core.c @@ -13,7 +13,6 @@ #include static DEFINE_IDA(rpmb_ida); -static DEFINE_MUTEX(rpmb_mutex); /** * rpmb_dev_get() - increase rpmb device ref counter @@ -63,9 +62,7 @@ static void rpmb_dev_release(struct device *dev) { struct rpmb_dev *rdev = to_rpmb_dev(dev); - mutex_lock(&rpmb_mutex); - ida_simple_remove(&rpmb_ida, rdev->id); - mutex_unlock(&rpmb_mutex); + ida_free(&rpmb_ida, rdev->id); kfree(rdev->descr.dev_id); kfree(rdev); } @@ -175,9 +172,7 @@ struct rpmb_dev *rpmb_dev_register(struct device *dev, goto err_free_rdev; } - mutex_lock(&rpmb_mutex); - ret = ida_simple_get(&rpmb_ida, 0, 0, GFP_KERNEL); - mutex_unlock(&rpmb_mutex); + ret = ida_alloc(&rpmb_ida, GFP_KERNEL); if (ret < 0) goto err_free_dev_id; rdev->id = ret; diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index 546eb06a40d045..e40b027a88e252 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -451,7 +451,7 @@ static struct platform_driver sram_driver = { .of_match_table = sram_dt_ids, }, .probe = sram_probe, - .remove_new = sram_remove, + .remove = sram_remove, }; static int __init sram_init(void) diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig deleted file mode 100644 index 1503a6496f6327..00000000000000 --- a/drivers/misc/ti-st/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# TI's shared transport line discipline and the protocol -# drivers (BT, FM and GPS) -# -menu "Texas Instruments shared transport line discipline" -config TI_ST - tristate "Shared transport core driver" - depends on NET && TTY - depends on GPIOLIB || COMPILE_TEST - select FW_LOADER - help - This enables the shared transport core driver for TI - BT / FM and GPS combo chips. This enables protocol drivers - to register themselves with core and send data, the responses - are returned to relevant protocol drivers based on their - packet types. - -endmenu diff --git a/drivers/misc/ti-st/Makefile b/drivers/misc/ti-st/Makefile deleted file mode 100644 index 93393100952edf..00000000000000 --- a/drivers/misc/ti-st/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for TI's shared transport line discipline -# and its protocol drivers (BT, FM, GPS) -# -obj-$(CONFIG_TI_ST) += st_drv.o -st_drv-objs := st_core.o st_kim.o st_ll.o diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c deleted file mode 100644 index b878431553abce..00000000000000 --- a/drivers/misc/ti-st/st_core.c +++ /dev/null @@ -1,918 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Shared Transport Line discipline driver Core - * This hooks up ST KIM driver and ST LL driver - * Copyright (C) 2009-2010 Texas Instruments - * Author: Pavan Savoy - */ - -#define pr_fmt(fmt) "(stc): " fmt -#include -#include -#include - -#include -#include - -#include -#include - -/* - * function pointer pointing to either, - * st_kim_recv during registration to receive fw download responses - * st_int_recv after registration to receive proto stack responses - */ -static void (*st_recv)(void *disc_data, const u8 *ptr, size_t count); - -/********************************************************************/ -static void add_channel_to_table(struct st_data_s *st_gdata, - struct st_proto_s *new_proto) -{ - pr_info("%s: id %d\n", __func__, new_proto->chnl_id); - /* list now has the channel id as index itself */ - st_gdata->list[new_proto->chnl_id] = new_proto; - st_gdata->is_registered[new_proto->chnl_id] = true; -} - -static void remove_channel_from_table(struct st_data_s *st_gdata, - struct st_proto_s *proto) -{ - pr_info("%s: id %d\n", __func__, proto->chnl_id); -/* st_gdata->list[proto->chnl_id] = NULL; */ - st_gdata->is_registered[proto->chnl_id] = false; -} - -/* - * called from KIM during firmware download. - * - * This is a wrapper function to tty->ops->write_room. - * It returns number of free space available in - * uart tx buffer. - */ -int st_get_uart_wr_room(struct st_data_s *st_gdata) -{ - if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { - pr_err("tty unavailable to perform write"); - return -1; - } - - return tty_write_room(st_gdata->tty); -} - -/* - * can be called in from - * -- KIM (during fw download) - * -- ST Core (during st_write) - * - * This is the internal write function - a wrapper - * to tty->ops->write - */ -int st_int_write(struct st_data_s *st_gdata, - const unsigned char *data, int count) -{ - struct tty_struct *tty; - if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { - pr_err("tty unavailable to perform write"); - return -EINVAL; - } - tty = st_gdata->tty; -#ifdef VERBOSE - print_hex_dump(KERN_DEBUG, "ops->write(tty, data, count); - -} - -/* - * push the skb received to relevant - * protocol stacks - */ -static void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) -{ - pr_debug(" %s(prot:%d) ", __func__, chnl_id); - - if (unlikely - (st_gdata == NULL || st_gdata->rx_skb == NULL - || st_gdata->is_registered[chnl_id] == false)) { - pr_err("chnl_id %d not registered, no data to send?", - chnl_id); - kfree_skb(st_gdata->rx_skb); - return; - } - /* - * this cannot fail - * this shouldn't take long - * - should be just skb_queue_tail for the - * protocol stack driver - */ - if (likely(st_gdata->list[chnl_id]->recv != NULL)) { - if (unlikely - (st_gdata->list[chnl_id]->recv - (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb) - != 0)) { - pr_err(" proto stack %d's ->recv failed", chnl_id); - kfree_skb(st_gdata->rx_skb); - return; - } - } else { - pr_err(" proto stack %d's ->recv null", chnl_id); - kfree_skb(st_gdata->rx_skb); - } - return; -} - -/* - * st_reg_complete - to call registration complete callbacks - * of all protocol stack drivers - * This function is being called with spin lock held, protocol drivers are - * only expected to complete their waits and do nothing more than that. - */ -static void st_reg_complete(struct st_data_s *st_gdata, int err) -{ - unsigned char i = 0; - pr_info(" %s ", __func__); - for (i = 0; i < ST_MAX_CHANNELS; i++) { - if (likely(st_gdata != NULL && - st_gdata->is_registered[i] == true && - st_gdata->list[i]->reg_complete_cb != NULL)) { - st_gdata->list[i]->reg_complete_cb - (st_gdata->list[i]->priv_data, err); - pr_info("protocol %d's cb sent %d\n", i, err); - if (err) { /* cleanup registered protocol */ - st_gdata->is_registered[i] = false; - if (st_gdata->protos_registered) - st_gdata->protos_registered--; - } - } - } -} - -static inline int st_check_data_len(struct st_data_s *st_gdata, - unsigned char chnl_id, int len) -{ - int room = skb_tailroom(st_gdata->rx_skb); - - pr_debug("len %d room %d", len, room); - - if (!len) { - /* - * Received packet has only packet header and - * has zero length payload. So, ask ST CORE to - * forward the packet to protocol driver (BT/FM/GPS) - */ - st_send_frame(chnl_id, st_gdata); - - } else if (len > room) { - /* - * Received packet's payload length is larger. - * We can't accommodate it in created skb. - */ - pr_err("Data length is too large len %d room %d", len, - room); - kfree_skb(st_gdata->rx_skb); - } else { - /* - * Packet header has non-zero payload length and - * we have enough space in created skb. Lets read - * payload data */ - st_gdata->rx_state = ST_W4_DATA; - st_gdata->rx_count = len; - return len; - } - - /* Change ST state to continue to process next packet */ - st_gdata->rx_state = ST_W4_PACKET_TYPE; - st_gdata->rx_skb = NULL; - st_gdata->rx_count = 0; - st_gdata->rx_chnl = 0; - - return 0; -} - -/* - * st_wakeup_ack - internal function for action when wake-up ack - * received - */ -static inline void st_wakeup_ack(struct st_data_s *st_gdata, - unsigned char cmd) -{ - struct sk_buff *waiting_skb; - unsigned long flags = 0; - - spin_lock_irqsave(&st_gdata->lock, flags); - /* - * de-Q from waitQ and Q in txQ now that the - * chip is awake - */ - while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq))) - skb_queue_tail(&st_gdata->txq, waiting_skb); - - /* state forwarded to ST LL */ - st_ll_sleep_state(st_gdata, (unsigned long)cmd); - spin_unlock_irqrestore(&st_gdata->lock, flags); - - /* wake up to send the recently copied skbs from waitQ */ - st_tx_wakeup(st_gdata); -} - -/* - * st_int_recv - ST's internal receive function. - * Decodes received RAW data and forwards to corresponding - * client drivers (Bluetooth,FM,GPS..etc). - * This can receive various types of packets, - * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets - * CH-8 packets from FM, CH-9 packets from GPS cores. - */ -static void st_int_recv(void *disc_data, const u8 *ptr, size_t count) -{ - struct st_proto_s *proto; - unsigned short payload_len = 0; - int len = 0; - unsigned char type = 0; - unsigned char *plen; - struct st_data_s *st_gdata = (struct st_data_s *)disc_data; - unsigned long flags; - - if (st_gdata == NULL) { - pr_err(" received null from TTY "); - return; - } - - pr_debug("count %zu rx_state %ld" - "rx_count %ld", count, st_gdata->rx_state, - st_gdata->rx_count); - - spin_lock_irqsave(&st_gdata->lock, flags); - /* Decode received bytes here */ - while (count) { - if (st_gdata->rx_count) { - len = min_t(unsigned int, st_gdata->rx_count, count); - skb_put_data(st_gdata->rx_skb, ptr, len); - st_gdata->rx_count -= len; - count -= len; - ptr += len; - - if (st_gdata->rx_count) - continue; - - /* Check ST RX state machine , where are we? */ - switch (st_gdata->rx_state) { - /* Waiting for complete packet ? */ - case ST_W4_DATA: - pr_debug("Complete pkt received"); - /* - * Ask ST CORE to forward - * the packet to protocol driver - */ - st_send_frame(st_gdata->rx_chnl, st_gdata); - - st_gdata->rx_state = ST_W4_PACKET_TYPE; - st_gdata->rx_skb = NULL; - continue; - /* parse the header to know details */ - case ST_W4_HEADER: - proto = st_gdata->list[st_gdata->rx_chnl]; - plen = - &st_gdata->rx_skb->data - [proto->offset_len_in_hdr]; - pr_debug("plen pointing to %x\n", *plen); - if (proto->len_size == 1) /* 1 byte len field */ - payload_len = *(unsigned char *)plen; - else if (proto->len_size == 2) - payload_len = - __le16_to_cpu(*(unsigned short *)plen); - else - pr_info("%s: invalid length " - "for id %d\n", - __func__, proto->chnl_id); - st_check_data_len(st_gdata, proto->chnl_id, - payload_len); - pr_debug("off %d, pay len %d\n", - proto->offset_len_in_hdr, payload_len); - continue; - } /* end of switch rx_state */ - } - - /* end of if rx_count */ - - /* - * Check first byte of packet and identify module - * owner (BT/FM/GPS) - */ - switch (*ptr) { - case LL_SLEEP_IND: - case LL_SLEEP_ACK: - case LL_WAKE_UP_IND: - pr_debug("PM packet"); - /* - * this takes appropriate action based on - * sleep state received -- - */ - st_ll_sleep_state(st_gdata, *ptr); - /* - * if WAKEUP_IND collides copy from waitq to txq - * and assume chip awake - */ - spin_unlock_irqrestore(&st_gdata->lock, flags); - if (st_ll_getstate(st_gdata) == ST_LL_AWAKE) - st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK); - spin_lock_irqsave(&st_gdata->lock, flags); - - ptr++; - count--; - continue; - case LL_WAKE_UP_ACK: - pr_debug("PM packet"); - - spin_unlock_irqrestore(&st_gdata->lock, flags); - /* wake up ack received */ - st_wakeup_ack(st_gdata, *ptr); - spin_lock_irqsave(&st_gdata->lock, flags); - - ptr++; - count--; - continue; - /* Unknown packet? */ - default: - type = *ptr; - - /* - * Default case means non-HCILL packets, - * possibilities are packets for: - * (a) valid protocol - Supported Protocols within - * the ST_MAX_CHANNELS. - * (b) registered protocol - Checked by - * "st_gdata->list[type] == NULL)" are supported - * protocols only. - * Rules out any invalid protocol and - * unregistered protocols with channel ID < 16. - */ - - if ((type >= ST_MAX_CHANNELS) || - (st_gdata->list[type] == NULL)) { - pr_err("chip/interface misbehavior: " - "dropping frame starting " - "with 0x%02x\n", type); - goto done; - } - - st_gdata->rx_skb = alloc_skb( - st_gdata->list[type]->max_frame_size, - GFP_ATOMIC); - if (st_gdata->rx_skb == NULL) { - pr_err("out of memory: dropping\n"); - goto done; - } - - skb_reserve(st_gdata->rx_skb, - st_gdata->list[type]->reserve); - /* next 2 required for BT only */ - st_gdata->rx_skb->cb[0] = type; /*pkt_type*/ - st_gdata->rx_skb->cb[1] = 0; /*incoming*/ - st_gdata->rx_chnl = *ptr; - st_gdata->rx_state = ST_W4_HEADER; - st_gdata->rx_count = st_gdata->list[type]->hdr_len; - pr_debug("rx_count %ld\n", st_gdata->rx_count); - } - ptr++; - count--; - } -done: - spin_unlock_irqrestore(&st_gdata->lock, flags); - pr_debug("done %s", __func__); - return; -} - -/* - * st_int_dequeue - internal de-Q function. - * If the previous data set was not written - * completely, return that skb which has the pending data. - * In normal cases, return top of txq. - */ -static struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) -{ - struct sk_buff *returning_skb; - - pr_debug("%s", __func__); - if (st_gdata->tx_skb != NULL) { - returning_skb = st_gdata->tx_skb; - st_gdata->tx_skb = NULL; - return returning_skb; - } - return skb_dequeue(&st_gdata->txq); -} - -/* - * st_int_enqueue - internal Q-ing function. - * Will either Q the skb to txq or the tx_waitq - * depending on the ST LL state. - * If the chip is asleep, then Q it onto waitq and - * wakeup the chip. - * txq and waitq needs protection since the other contexts - * may be sending data, waking up chip. - */ -static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) -{ - unsigned long flags = 0; - - pr_debug("%s", __func__); - spin_lock_irqsave(&st_gdata->lock, flags); - - switch (st_ll_getstate(st_gdata)) { - case ST_LL_AWAKE: - pr_debug("ST LL is AWAKE, sending normally"); - skb_queue_tail(&st_gdata->txq, skb); - break; - case ST_LL_ASLEEP_TO_AWAKE: - skb_queue_tail(&st_gdata->tx_waitq, skb); - break; - case ST_LL_AWAKE_TO_ASLEEP: - pr_err("ST LL is illegal state(%ld)," - "purging received skb.", st_ll_getstate(st_gdata)); - dev_kfree_skb_irq(skb); - break; - case ST_LL_ASLEEP: - skb_queue_tail(&st_gdata->tx_waitq, skb); - st_ll_wakeup(st_gdata); - break; - default: - pr_err("ST LL is illegal state(%ld)," - "purging received skb.", st_ll_getstate(st_gdata)); - dev_kfree_skb_irq(skb); - break; - } - - spin_unlock_irqrestore(&st_gdata->lock, flags); - pr_debug("done %s", __func__); - return; -} - -/* - * internal wakeup function - * called from either - * - TTY layer when write's finished - * - st_write (in context of the protocol stack) - */ -static void work_fn_write_wakeup(struct work_struct *work) -{ - struct st_data_s *st_gdata = container_of(work, struct st_data_s, - work_write_wakeup); - - st_tx_wakeup((void *)st_gdata); -} -void st_tx_wakeup(struct st_data_s *st_data) -{ - struct sk_buff *skb; - unsigned long flags; /* for irq save flags */ - pr_debug("%s", __func__); - /* check for sending & set flag sending here */ - if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) { - pr_debug("ST already sending"); - /* keep sending */ - set_bit(ST_TX_WAKEUP, &st_data->tx_state); - return; - /* TX_WAKEUP will be checked in another - * context - */ - } - do { /* come back if st_tx_wakeup is set */ - /* woke-up to write */ - clear_bit(ST_TX_WAKEUP, &st_data->tx_state); - while ((skb = st_int_dequeue(st_data))) { - int len; - spin_lock_irqsave(&st_data->lock, flags); - /* enable wake-up from TTY */ - set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags); - len = st_int_write(st_data, skb->data, skb->len); - skb_pull(skb, len); - /* if skb->len = len as expected, skb->len=0 */ - if (skb->len) { - /* would be the next skb to be sent */ - st_data->tx_skb = skb; - spin_unlock_irqrestore(&st_data->lock, flags); - break; - } - dev_kfree_skb_irq(skb); - spin_unlock_irqrestore(&st_data->lock, flags); - } - /* if wake-up is set in another context- restart sending */ - } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state)); - - /* clear flag sending */ - clear_bit(ST_TX_SENDING, &st_data->tx_state); -} - -/********************************************************************/ -/* functions called from ST KIM -*/ -void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) -{ - seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", - st_gdata->protos_registered, - st_gdata->is_registered[0x04] == true ? 'R' : 'U', - st_gdata->is_registered[0x08] == true ? 'R' : 'U', - st_gdata->is_registered[0x09] == true ? 'R' : 'U'); -} - -/********************************************************************/ -/* - * functions called from protocol stack drivers - * to be EXPORT-ed - */ -long st_register(struct st_proto_s *new_proto) -{ - struct st_data_s *st_gdata; - long err = 0; - unsigned long flags = 0; - - st_kim_ref(&st_gdata, 0); - if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL - || new_proto->reg_complete_cb == NULL) { - pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); - return -EINVAL; - } - - if (new_proto->chnl_id >= ST_MAX_CHANNELS) { - pr_err("chnl_id %d not supported", new_proto->chnl_id); - return -EPROTONOSUPPORT; - } - - if (st_gdata->is_registered[new_proto->chnl_id] == true) { - pr_err("chnl_id %d already registered", new_proto->chnl_id); - return -EALREADY; - } - - /* can be from process context only */ - spin_lock_irqsave(&st_gdata->lock, flags); - - if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { - pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id); - /* fw download in progress */ - - add_channel_to_table(st_gdata, new_proto); - st_gdata->protos_registered++; - new_proto->write = st_write; - - set_bit(ST_REG_PENDING, &st_gdata->st_state); - spin_unlock_irqrestore(&st_gdata->lock, flags); - return -EINPROGRESS; - } else if (st_gdata->protos_registered == ST_EMPTY) { - pr_info(" chnl_id list empty :%d ", new_proto->chnl_id); - set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); - st_recv = st_kim_recv; - - /* enable the ST LL - to set default chip state */ - st_ll_enable(st_gdata); - - /* release lock previously held - re-locked below */ - spin_unlock_irqrestore(&st_gdata->lock, flags); - - /* - * this may take a while to complete - * since it involves BT fw download - */ - err = st_kim_start(st_gdata->kim_data); - if (err != 0) { - clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); - if ((st_gdata->protos_registered != ST_EMPTY) && - (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { - pr_err(" KIM failure complete callback "); - spin_lock_irqsave(&st_gdata->lock, flags); - st_reg_complete(st_gdata, err); - spin_unlock_irqrestore(&st_gdata->lock, flags); - clear_bit(ST_REG_PENDING, &st_gdata->st_state); - } - return -EINVAL; - } - - spin_lock_irqsave(&st_gdata->lock, flags); - - clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); - st_recv = st_int_recv; - - /* - * this is where all pending registration - * are signalled to be complete by calling callback functions - */ - if ((st_gdata->protos_registered != ST_EMPTY) && - (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { - pr_debug(" call reg complete callback "); - st_reg_complete(st_gdata, 0); - } - clear_bit(ST_REG_PENDING, &st_gdata->st_state); - - /* - * check for already registered once more, - * since the above check is old - */ - if (st_gdata->is_registered[new_proto->chnl_id] == true) { - pr_err(" proto %d already registered ", - new_proto->chnl_id); - spin_unlock_irqrestore(&st_gdata->lock, flags); - return -EALREADY; - } - - add_channel_to_table(st_gdata, new_proto); - st_gdata->protos_registered++; - new_proto->write = st_write; - spin_unlock_irqrestore(&st_gdata->lock, flags); - return err; - } - /* if fw is already downloaded & new stack registers protocol */ - else { - add_channel_to_table(st_gdata, new_proto); - st_gdata->protos_registered++; - new_proto->write = st_write; - - /* lock already held before entering else */ - spin_unlock_irqrestore(&st_gdata->lock, flags); - return err; - } -} -EXPORT_SYMBOL_GPL(st_register); - -/* - * to unregister a protocol - - * to be called from protocol stack driver - */ -long st_unregister(struct st_proto_s *proto) -{ - long err = 0; - unsigned long flags = 0; - struct st_data_s *st_gdata; - - pr_debug("%s: %d ", __func__, proto->chnl_id); - - st_kim_ref(&st_gdata, 0); - if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) { - pr_err(" chnl_id %d not supported", proto->chnl_id); - return -EPROTONOSUPPORT; - } - - spin_lock_irqsave(&st_gdata->lock, flags); - - if (st_gdata->is_registered[proto->chnl_id] == false) { - pr_err(" chnl_id %d not registered", proto->chnl_id); - spin_unlock_irqrestore(&st_gdata->lock, flags); - return -EPROTONOSUPPORT; - } - - if (st_gdata->protos_registered) - st_gdata->protos_registered--; - - remove_channel_from_table(st_gdata, proto); - spin_unlock_irqrestore(&st_gdata->lock, flags); - - if ((st_gdata->protos_registered == ST_EMPTY) && - (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { - pr_info(" all chnl_ids unregistered "); - - /* stop traffic on tty */ - if (st_gdata->tty) { - tty_ldisc_flush(st_gdata->tty); - stop_tty(st_gdata->tty); - } - - /* all chnl_ids now unregistered */ - st_kim_stop(st_gdata->kim_data); - /* disable ST LL */ - st_ll_disable(st_gdata); - } - return err; -} - -/* - * called in protocol stack drivers - * via the write function pointer - */ -long st_write(struct sk_buff *skb) -{ - struct st_data_s *st_gdata; - long len; - - st_kim_ref(&st_gdata, 0); - if (unlikely(skb == NULL || st_gdata == NULL - || st_gdata->tty == NULL)) { - pr_err("data/tty unavailable to perform write"); - return -EINVAL; - } - - pr_debug("%d to be written", skb->len); - len = skb->len; - - /* st_ll to decide where to enqueue the skb */ - st_int_enqueue(st_gdata, skb); - /* wake up */ - st_tx_wakeup(st_gdata); - - /* return number of bytes written */ - return len; -} - -/* for protocols making use of shared transport */ -EXPORT_SYMBOL_GPL(st_unregister); - -/********************************************************************/ -/* - * functions called from TTY layer - */ -static int st_tty_open(struct tty_struct *tty) -{ - struct st_data_s *st_gdata; - pr_info("%s ", __func__); - - st_kim_ref(&st_gdata, 0); - st_gdata->tty = tty; - tty->disc_data = st_gdata; - - /* don't do an wakeup for now */ - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - - /* mem already allocated - */ - tty->receive_room = 65536; - /* Flush any pending characters in the driver and discipline. */ - tty_ldisc_flush(tty); - tty_driver_flush_buffer(tty); - /* - * signal to UIM via KIM that - - * installation of N_TI_WL ldisc is complete - */ - st_kim_complete(st_gdata->kim_data); - pr_debug("done %s", __func__); - - return 0; -} - -static void st_tty_close(struct tty_struct *tty) -{ - unsigned char i; - unsigned long flags; - struct st_data_s *st_gdata = tty->disc_data; - - pr_info("%s ", __func__); - - /* - * TODO: - * if a protocol has been registered & line discipline - * un-installed for some reason - what should be done ? - */ - spin_lock_irqsave(&st_gdata->lock, flags); - for (i = ST_BT; i < ST_MAX_CHANNELS; i++) { - if (st_gdata->is_registered[i] == true) - pr_err("%d not un-registered", i); - st_gdata->list[i] = NULL; - st_gdata->is_registered[i] = false; - } - st_gdata->protos_registered = 0; - spin_unlock_irqrestore(&st_gdata->lock, flags); - /* - * signal to UIM via KIM that - - * N_TI_WL ldisc is un-installed - */ - st_kim_complete(st_gdata->kim_data); - st_gdata->tty = NULL; - /* Flush any pending characters in the driver and discipline. */ - tty_ldisc_flush(tty); - tty_driver_flush_buffer(tty); - - spin_lock_irqsave(&st_gdata->lock, flags); - /* empty out txq and tx_waitq */ - skb_queue_purge(&st_gdata->txq); - skb_queue_purge(&st_gdata->tx_waitq); - /* reset the TTY Rx states of ST */ - st_gdata->rx_count = 0; - st_gdata->rx_state = ST_W4_PACKET_TYPE; - kfree_skb(st_gdata->rx_skb); - st_gdata->rx_skb = NULL; - spin_unlock_irqrestore(&st_gdata->lock, flags); - - pr_debug("%s: done ", __func__); -} - -static void st_tty_receive(struct tty_struct *tty, const u8 *data, - const u8 *tty_flags, size_t count) -{ -#ifdef VERBOSE - print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, - 16, 1, data, count, 0); -#endif - - /* - * if fw download is in progress then route incoming data - * to KIM for validation - */ - st_recv(tty->disc_data, data, count); - pr_debug("done %s", __func__); -} - -/* - * wake-up function called in from the TTY layer - * inside the internal wakeup function will be called - */ -static void st_tty_wakeup(struct tty_struct *tty) -{ - struct st_data_s *st_gdata = tty->disc_data; - pr_debug("%s ", __func__); - /* don't do an wakeup for now */ - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - - /* - * schedule the internal wakeup instead of calling directly to - * avoid lockup (port->lock needed in tty->ops->write is - * already taken here - */ - schedule_work(&st_gdata->work_write_wakeup); -} - -static void st_tty_flush_buffer(struct tty_struct *tty) -{ - struct st_data_s *st_gdata = tty->disc_data; - pr_debug("%s ", __func__); - - kfree_skb(st_gdata->tx_skb); - st_gdata->tx_skb = NULL; - - tty_driver_flush_buffer(tty); - return; -} - -static struct tty_ldisc_ops st_ldisc_ops = { - .num = N_TI_WL, - .name = "n_st", - .open = st_tty_open, - .close = st_tty_close, - .receive_buf = st_tty_receive, - .write_wakeup = st_tty_wakeup, - .flush_buffer = st_tty_flush_buffer, - .owner = THIS_MODULE -}; - -/********************************************************************/ -int st_core_init(struct st_data_s **core_data) -{ - struct st_data_s *st_gdata; - long err; - - err = tty_register_ldisc(&st_ldisc_ops); - if (err) { - pr_err("error registering %d line discipline %ld", - N_TI_WL, err); - return err; - } - pr_debug("registered n_shared line discipline"); - - st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL); - if (!st_gdata) { - pr_err("memory allocation failed"); - err = -ENOMEM; - goto err_unreg_ldisc; - } - - /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's - * will be pushed in this queue for actual transmission. - */ - skb_queue_head_init(&st_gdata->txq); - skb_queue_head_init(&st_gdata->tx_waitq); - - /* Locking used in st_int_enqueue() to avoid multiple execution */ - spin_lock_init(&st_gdata->lock); - - err = st_ll_init(st_gdata); - if (err) { - pr_err("error during st_ll initialization(%ld)", err); - goto err_free_gdata; - } - - INIT_WORK(&st_gdata->work_write_wakeup, work_fn_write_wakeup); - - *core_data = st_gdata; - return 0; -err_free_gdata: - kfree(st_gdata); -err_unreg_ldisc: - tty_unregister_ldisc(&st_ldisc_ops); - return err; -} - -void st_core_exit(struct st_data_s *st_gdata) -{ - long err; - /* internal module cleanup */ - err = st_ll_deinit(st_gdata); - if (err) - pr_err("error during deinit of ST LL %ld", err); - - if (st_gdata != NULL) { - /* Free ST Tx Qs and skbs */ - skb_queue_purge(&st_gdata->txq); - skb_queue_purge(&st_gdata->tx_waitq); - kfree_skb(st_gdata->rx_skb); - kfree_skb(st_gdata->tx_skb); - /* TTY ldisc cleanup */ - tty_unregister_ldisc(&st_ldisc_ops); - /* free the global data pointer */ - kfree(st_gdata); - } -} diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c deleted file mode 100644 index ff172cf4614d6b..00000000000000 --- a/drivers/misc/ti-st/st_kim.c +++ /dev/null @@ -1,839 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Shared Transport Line discipline driver Core - * Init Manager module responsible for GPIO control - * and firmware download - * Copyright (C) 2009-2010 Texas Instruments - * Author: Pavan Savoy - */ - -#define pr_fmt(fmt) "(stk) :" fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ -static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; - -/**********************************************************************/ -/* internal functions */ - -/* - * st_get_plat_device - - * function which returns the reference to the platform device - * requested by id. As of now only 1 such device exists (id=0) - * the context requesting for reference can get the id to be - * requested by a. The protocol driver which is registering or - * b. the tty device which is opened. - */ -static struct platform_device *st_get_plat_device(int id) -{ - return st_kim_devices[id]; -} - -/* - * validate_firmware_response - - * function to return whether the firmware response was proper - * in case of error don't complete so that waiting for proper - * response times out - */ -static void validate_firmware_response(struct kim_data_s *kim_gdata) -{ - struct sk_buff *skb = kim_gdata->rx_skb; - if (!skb) - return; - - /* - * these magic numbers are the position in the response buffer which - * allows us to distinguish whether the response is for the read - * version info. command - */ - if (skb->data[2] == 0x01 && skb->data[3] == 0x01 && - skb->data[4] == 0x10 && skb->data[5] == 0x00) { - /* fw version response */ - memcpy(kim_gdata->resp_buffer, - kim_gdata->rx_skb->data, - kim_gdata->rx_skb->len); - kim_gdata->rx_state = ST_W4_PACKET_TYPE; - kim_gdata->rx_skb = NULL; - kim_gdata->rx_count = 0; - } else if (unlikely(skb->data[5] != 0)) { - pr_err("no proper response during fw download"); - pr_err("data6 %x", skb->data[5]); - kfree_skb(skb); - return; /* keep waiting for the proper response */ - } - /* becos of all the script being downloaded */ - complete_all(&kim_gdata->kim_rcvd); - kfree_skb(skb); -} - -/* - * check for data len received inside kim_int_recv - * most often hit the last case to update state to waiting for data - */ -static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len) -{ - register int room = skb_tailroom(kim_gdata->rx_skb); - - pr_debug("len %d room %d", len, room); - - if (!len) { - validate_firmware_response(kim_gdata); - } else if (len > room) { - /* - * Received packet's payload length is larger. - * We can't accommodate it in created skb. - */ - pr_err("Data length is too large len %d room %d", len, - room); - kfree_skb(kim_gdata->rx_skb); - } else { - /* - * Packet header has non-zero payload length and - * we have enough space in created skb. Lets read - * payload data */ - kim_gdata->rx_state = ST_W4_DATA; - kim_gdata->rx_count = len; - return len; - } - - /* - * Change ST LL state to continue to process next - * packet - */ - kim_gdata->rx_state = ST_W4_PACKET_TYPE; - kim_gdata->rx_skb = NULL; - kim_gdata->rx_count = 0; - - return 0; -} - -/* - * kim_int_recv - receive function called during firmware download - * firmware download responses on different UART drivers - * have been observed to come in bursts of different - * tty_receive and hence the logic - */ -static void kim_int_recv(struct kim_data_s *kim_gdata, const u8 *ptr, - size_t count) -{ - int len = 0; - unsigned char *plen; - - pr_debug("%s", __func__); - /* Decode received bytes here */ - while (count) { - if (kim_gdata->rx_count) { - len = min_t(unsigned int, kim_gdata->rx_count, count); - skb_put_data(kim_gdata->rx_skb, ptr, len); - kim_gdata->rx_count -= len; - count -= len; - ptr += len; - - if (kim_gdata->rx_count) - continue; - - /* Check ST RX state machine , where are we? */ - switch (kim_gdata->rx_state) { - /* Waiting for complete packet ? */ - case ST_W4_DATA: - pr_debug("Complete pkt received"); - validate_firmware_response(kim_gdata); - kim_gdata->rx_state = ST_W4_PACKET_TYPE; - kim_gdata->rx_skb = NULL; - continue; - /* Waiting for Bluetooth event header ? */ - case ST_W4_HEADER: - plen = - (unsigned char *)&kim_gdata->rx_skb->data[1]; - pr_debug("event hdr: plen 0x%02x\n", *plen); - kim_check_data_len(kim_gdata, *plen); - continue; - } /* end of switch */ - } /* end of if rx_state */ - switch (*ptr) { - /* Bluetooth event packet? */ - case 0x04: - kim_gdata->rx_state = ST_W4_HEADER; - kim_gdata->rx_count = 2; - break; - default: - pr_info("unknown packet"); - ptr++; - count--; - continue; - } - ptr++; - count--; - kim_gdata->rx_skb = - alloc_skb(1024+8, GFP_ATOMIC); - if (!kim_gdata->rx_skb) { - pr_err("can't allocate mem for new packet"); - kim_gdata->rx_state = ST_W4_PACKET_TYPE; - kim_gdata->rx_count = 0; - return; - } - skb_reserve(kim_gdata->rx_skb, 8); - kim_gdata->rx_skb->cb[0] = 4; - kim_gdata->rx_skb->cb[1] = 0; - - } - return; -} - -static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) -{ - unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0; - static const char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 }; - long time_left; - - pr_debug("%s", __func__); - - reinit_completion(&kim_gdata->kim_rcvd); - if (4 != st_int_write(kim_gdata->core_data, read_ver_cmd, 4)) { - pr_err("kim: couldn't write 4 bytes"); - return -EIO; - } - - time_left = wait_for_completion_interruptible_timeout( - &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME)); - if (time_left <= 0) { - pr_err(" waiting for ver info- timed out or received signal"); - return time_left ? -ERESTARTSYS : -ETIMEDOUT; - } - reinit_completion(&kim_gdata->kim_rcvd); - /* - * the positions 12 & 13 in the response buffer provide with the - * chip, major & minor numbers - */ - - version = - MAKEWORD(kim_gdata->resp_buffer[12], - kim_gdata->resp_buffer[13]); - chip = (version & 0x7C00) >> 10; - min_ver = (version & 0x007F); - maj_ver = (version & 0x0380) >> 7; - - if (version & 0x8000) - maj_ver |= 0x0008; - - sprintf(bts_scr_name, "ti-connectivity/TIInit_%d.%d.%d.bts", - chip, maj_ver, min_ver); - - /* to be accessed later via sysfs entry */ - kim_gdata->version.full = version; - kim_gdata->version.chip = chip; - kim_gdata->version.maj_ver = maj_ver; - kim_gdata->version.min_ver = min_ver; - - pr_info("%s", bts_scr_name); - return 0; -} - -static void skip_change_remote_baud(unsigned char **ptr, long *len) -{ - unsigned char *nxt_action, *cur_action; - cur_action = *ptr; - - nxt_action = cur_action + sizeof(struct bts_action) + - ((struct bts_action *) cur_action)->size; - - if (((struct bts_action *) nxt_action)->type != ACTION_WAIT_EVENT) { - pr_err("invalid action after change remote baud command"); - } else { - *ptr = *ptr + sizeof(struct bts_action) + - ((struct bts_action *)cur_action)->size; - *len = *len - (sizeof(struct bts_action) + - ((struct bts_action *)cur_action)->size); - /* warn user on not commenting these in firmware */ - pr_warn("skipping the wait event of change remote baud"); - } -} - -/* - * download_firmware - - * internal function which parses through the .bts firmware - * script file intreprets SEND, DELAY actions only as of now - */ -static long download_firmware(struct kim_data_s *kim_gdata) -{ - long err = 0; - long len = 0; - unsigned char *ptr = NULL; - unsigned char *action_ptr = NULL; - unsigned char bts_scr_name[40] = { 0 }; /* 40 char long bts scr name? */ - int wr_room_space; - int cmd_size; - unsigned long timeout; - - err = read_local_version(kim_gdata, bts_scr_name); - if (err != 0) { - pr_err("kim: failed to read local ver"); - return err; - } - err = - request_firmware(&kim_gdata->fw_entry, bts_scr_name, - &kim_gdata->kim_pdev->dev); - if (unlikely((err != 0) || (kim_gdata->fw_entry->data == NULL) || - (kim_gdata->fw_entry->size == 0))) { - pr_err(" request_firmware failed(errno %ld) for %s", err, - bts_scr_name); - return -EINVAL; - } - ptr = (void *)kim_gdata->fw_entry->data; - len = kim_gdata->fw_entry->size; - /* - * bts_header to remove out magic number and - * version - */ - ptr += sizeof(struct bts_header); - len -= sizeof(struct bts_header); - - while (len > 0 && ptr) { - pr_debug(" action size %d, type %d ", - ((struct bts_action *)ptr)->size, - ((struct bts_action *)ptr)->type); - - switch (((struct bts_action *)ptr)->type) { - case ACTION_SEND_COMMAND: /* action send */ - pr_debug("S"); - action_ptr = &(((struct bts_action *)ptr)->data[0]); - if (unlikely - (((struct hci_command *)action_ptr)->opcode == - 0xFF36)) { - /* - * ignore remote change - * baud rate HCI VS command - */ - pr_warn("change remote baud" - " rate command in firmware"); - skip_change_remote_baud(&ptr, &len); - break; - } - /* - * Make sure we have enough free space in uart - * tx buffer to write current firmware command - */ - cmd_size = ((struct bts_action *)ptr)->size; - timeout = jiffies + msecs_to_jiffies(CMD_WR_TIME); - do { - wr_room_space = - st_get_uart_wr_room(kim_gdata->core_data); - if (wr_room_space < 0) { - pr_err("Unable to get free " - "space info from uart tx buffer"); - release_firmware(kim_gdata->fw_entry); - return wr_room_space; - } - mdelay(1); /* wait 1ms before checking room */ - } while ((wr_room_space < cmd_size) && - time_before(jiffies, timeout)); - - /* Timeout happened ? */ - if (time_after_eq(jiffies, timeout)) { - pr_err("Timeout while waiting for free " - "free space in uart tx buffer"); - release_firmware(kim_gdata->fw_entry); - return -ETIMEDOUT; - } - /* - * reinit completion before sending for the - * relevant wait - */ - reinit_completion(&kim_gdata->kim_rcvd); - - /* - * Free space found in uart buffer, call st_int_write - * to send current firmware command to the uart tx - * buffer. - */ - err = st_int_write(kim_gdata->core_data, - ((struct bts_action_send *)action_ptr)->data, - ((struct bts_action *)ptr)->size); - if (unlikely(err < 0)) { - release_firmware(kim_gdata->fw_entry); - return err; - } - /* - * Check number of bytes written to the uart tx buffer - * and requested command write size - */ - if (err != cmd_size) { - pr_err("Number of bytes written to uart " - "tx buffer are not matching with " - "requested cmd write size"); - release_firmware(kim_gdata->fw_entry); - return -EIO; - } - break; - case ACTION_WAIT_EVENT: /* wait */ - pr_debug("W"); - err = wait_for_completion_interruptible_timeout( - &kim_gdata->kim_rcvd, - msecs_to_jiffies(CMD_RESP_TIME)); - if (err <= 0) { - pr_err("response timeout/signaled during fw download "); - /* timed out */ - release_firmware(kim_gdata->fw_entry); - return err ? -ERESTARTSYS : -ETIMEDOUT; - } - reinit_completion(&kim_gdata->kim_rcvd); - break; - case ACTION_DELAY: /* sleep */ - pr_info("sleep command in scr"); - action_ptr = &(((struct bts_action *)ptr)->data[0]); - mdelay(((struct bts_action_delay *)action_ptr)->msec); - break; - } - len = - len - (sizeof(struct bts_action) + - ((struct bts_action *)ptr)->size); - ptr = - ptr + sizeof(struct bts_action) + - ((struct bts_action *)ptr)->size; - } - /* fw download complete */ - release_firmware(kim_gdata->fw_entry); - return 0; -} - -/**********************************************************************/ -/* functions called from ST core */ -/* called from ST Core, when REG_IN_PROGRESS (registration in progress) - * can be because of - * 1. response to read local version - * 2. during send/recv's of firmware download - */ -void st_kim_recv(void *disc_data, const u8 *data, size_t count) -{ - struct st_data_s *st_gdata = (struct st_data_s *)disc_data; - struct kim_data_s *kim_gdata = st_gdata->kim_data; - - /* - * proceed to gather all data and distinguish read fw version response - * from other fw responses when data gathering is complete - */ - kim_int_recv(kim_gdata, data, count); - return; -} - -/* - * to signal completion of line discipline installation - * called from ST Core, upon tty_open - */ -void st_kim_complete(void *kim_data) -{ - struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; - complete(&kim_gdata->ldisc_installed); -} - -/* - * st_kim_start - called from ST Core upon 1st registration - * This involves toggling the chip enable gpio, reading - * the firmware version from chip, forming the fw file name - * based on the chip version, requesting the fw, parsing it - * and perform download(send/recv). - */ -long st_kim_start(void *kim_data) -{ - long err = 0; - long retry = POR_RETRY_COUNT; - struct ti_st_plat_data *pdata; - struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; - - pr_info(" %s", __func__); - pdata = kim_gdata->kim_pdev->dev.platform_data; - - do { - /* platform specific enabling code here */ - if (pdata->chip_enable) - pdata->chip_enable(kim_gdata); - - /* Configure BT nShutdown to HIGH state */ - gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_LOW); - mdelay(5); /* FIXME: a proper toggle */ - gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_HIGH); - mdelay(100); - /* re-initialize the completion */ - reinit_completion(&kim_gdata->ldisc_installed); - /* send notification to UIM */ - kim_gdata->ldisc_install = 1; - pr_info("ldisc_install = 1"); - sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, - NULL, "install"); - /* wait for ldisc to be installed */ - err = wait_for_completion_interruptible_timeout( - &kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME)); - if (!err) { - /* - * ldisc installation timeout, - * flush uart, power cycle BT_EN - */ - pr_err("ldisc installation timeout"); - err = st_kim_stop(kim_gdata); - continue; - } else { - /* ldisc installed now */ - pr_info("line discipline installed"); - err = download_firmware(kim_gdata); - if (err != 0) { - /* - * ldisc installed but fw download failed, - * flush uart & power cycle BT_EN - */ - pr_err("download firmware failed"); - err = st_kim_stop(kim_gdata); - continue; - } else { /* on success don't retry */ - break; - } - } - } while (retry--); - return err; -} - -/* - * st_kim_stop - stop communication with chip. - * This can be called from ST Core/KIM, on the- - * (a) last un-register when chip need not be powered there-after, - * (b) upon failure to either install ldisc or download firmware. - * The function is responsible to (a) notify UIM about un-installation, - * (b) flush UART if the ldisc was installed. - * (c) reset BT_EN - pull down nshutdown at the end. - * (d) invoke platform's chip disabling routine. - */ -long st_kim_stop(void *kim_data) -{ - long err = 0; - struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; - struct ti_st_plat_data *pdata = - kim_gdata->kim_pdev->dev.platform_data; - struct tty_struct *tty = kim_gdata->core_data->tty; - - reinit_completion(&kim_gdata->ldisc_installed); - - if (tty) { /* can be called before ldisc is installed */ - /* Flush any pending characters in the driver and discipline. */ - tty_ldisc_flush(tty); - tty_driver_flush_buffer(tty); - } - - /* send uninstall notification to UIM */ - pr_info("ldisc_install = 0"); - kim_gdata->ldisc_install = 0; - sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install"); - - /* wait for ldisc to be un-installed */ - err = wait_for_completion_interruptible_timeout( - &kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME)); - if (!err) { /* timeout */ - pr_err(" timed out waiting for ldisc to be un-installed"); - err = -ETIMEDOUT; - } - - /* By default configure BT nShutdown to LOW state */ - gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_LOW); - mdelay(1); - gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_HIGH); - mdelay(1); - gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_LOW); - - /* platform specific disable */ - if (pdata->chip_disable) - pdata->chip_disable(kim_gdata); - return err; -} - -/**********************************************************************/ -/* functions called from subsystems */ -/* called when debugfs entry is read from */ - -static int version_show(struct seq_file *s, void *unused) -{ - struct kim_data_s *kim_gdata = s->private; - seq_printf(s, "%04X %d.%d.%d\n", kim_gdata->version.full, - kim_gdata->version.chip, kim_gdata->version.maj_ver, - kim_gdata->version.min_ver); - return 0; -} - -static int list_show(struct seq_file *s, void *unused) -{ - struct kim_data_s *kim_gdata = s->private; - kim_st_list_protocols(kim_gdata->core_data, s); - return 0; -} - -static ssize_t show_install(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct kim_data_s *kim_data = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", kim_data->ldisc_install); -} - -#ifdef DEBUG -static ssize_t store_dev_name(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct kim_data_s *kim_data = dev_get_drvdata(dev); - pr_debug("storing dev name >%s<", buf); - strscpy(kim_data->dev_name, buf, sizeof(kim_data->dev_name)); - pr_debug("stored dev name >%s<", kim_data->dev_name); - return count; -} - -static ssize_t store_baud_rate(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct kim_data_s *kim_data = dev_get_drvdata(dev); - pr_debug("storing baud rate >%s<", buf); - sscanf(buf, "%ld", &kim_data->baud_rate); - pr_debug("stored baud rate >%ld<", kim_data->baud_rate); - return count; -} -#endif /* if DEBUG */ - -static ssize_t show_dev_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct kim_data_s *kim_data = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", kim_data->dev_name); -} - -static ssize_t show_baud_rate(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct kim_data_s *kim_data = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", kim_data->baud_rate); -} - -static ssize_t show_flow_cntrl(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct kim_data_s *kim_data = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", kim_data->flow_cntrl); -} - -/* structures specific for sysfs entries */ -static struct kobj_attribute ldisc_install = -__ATTR(install, 0444, (void *)show_install, NULL); - -static struct kobj_attribute uart_dev_name = -#ifdef DEBUG /* TODO: move this to debug-fs if possible */ -__ATTR(dev_name, 0644, (void *)show_dev_name, (void *)store_dev_name); -#else -__ATTR(dev_name, 0444, (void *)show_dev_name, NULL); -#endif - -static struct kobj_attribute uart_baud_rate = -#ifdef DEBUG /* TODO: move to debugfs */ -__ATTR(baud_rate, 0644, (void *)show_baud_rate, (void *)store_baud_rate); -#else -__ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL); -#endif - -static struct kobj_attribute uart_flow_cntrl = -__ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL); - -static struct attribute *uim_attrs[] = { - &ldisc_install.attr, - &uart_dev_name.attr, - &uart_baud_rate.attr, - &uart_flow_cntrl.attr, - NULL, -}; - -static const struct attribute_group uim_attr_grp = { - .attrs = uim_attrs, -}; - -/* - * st_kim_ref - reference the core's data - * This references the per-ST platform device in the arch/xx/ - * board-xx.c file. - * This would enable multiple such platform devices to exist - * on a given platform - */ -void st_kim_ref(struct st_data_s **core_data, int id) -{ - struct platform_device *pdev; - struct kim_data_s *kim_gdata; - /* get kim_gdata reference from platform device */ - pdev = st_get_plat_device(id); - if (!pdev) - goto err; - kim_gdata = platform_get_drvdata(pdev); - if (!kim_gdata) - goto err; - - *core_data = kim_gdata->core_data; - return; -err: - *core_data = NULL; -} - -DEFINE_SHOW_ATTRIBUTE(version); -DEFINE_SHOW_ATTRIBUTE(list); - -/**********************************************************************/ -/* functions called from platform device driver subsystem - * need to have a relevant platform device entry in the platform's - * board-*.c file - */ - -static struct dentry *kim_debugfs_dir; -static int kim_probe(struct platform_device *pdev) -{ - struct kim_data_s *kim_gdata; - struct ti_st_plat_data *pdata = pdev->dev.platform_data; - int err; - - if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { - /* multiple devices could exist */ - st_kim_devices[pdev->id] = pdev; - } else { - /* platform's sure about existence of 1 device */ - st_kim_devices[0] = pdev; - } - - kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_KERNEL); - if (!kim_gdata) { - pr_err("no mem to allocate"); - return -ENOMEM; - } - platform_set_drvdata(pdev, kim_gdata); - - err = st_core_init(&kim_gdata->core_data); - if (err != 0) { - pr_err(" ST core init failed"); - err = -EIO; - goto err_core_init; - } - /* refer to itself */ - kim_gdata->core_data->kim_data = kim_gdata; - - /* Claim the chip enable nShutdown gpio from the system */ - kim_gdata->nshutdown = pdata->nshutdown_gpio; - err = gpio_request(kim_gdata->nshutdown, "kim"); - if (unlikely(err)) { - pr_err(" gpio %d request failed ", kim_gdata->nshutdown); - goto err_sysfs_group; - } - - /* Configure nShutdown GPIO as output=0 */ - err = gpio_direction_output(kim_gdata->nshutdown, 0); - if (unlikely(err)) { - pr_err(" unable to configure gpio %d", kim_gdata->nshutdown); - goto err_sysfs_group; - } - /* get reference of pdev for request_firmware */ - kim_gdata->kim_pdev = pdev; - init_completion(&kim_gdata->kim_rcvd); - init_completion(&kim_gdata->ldisc_installed); - - err = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); - if (err) { - pr_err("failed to create sysfs entries"); - goto err_sysfs_group; - } - - /* copying platform data */ - strscpy(kim_gdata->dev_name, pdata->dev_name, - sizeof(kim_gdata->dev_name)); - kim_gdata->flow_cntrl = pdata->flow_cntrl; - kim_gdata->baud_rate = pdata->baud_rate; - pr_info("sysfs entries created\n"); - - kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); - - debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, - kim_gdata, &version_fops); - debugfs_create_file("protocols", S_IRUGO, kim_debugfs_dir, - kim_gdata, &list_fops); - return 0; - -err_sysfs_group: - st_core_exit(kim_gdata->core_data); - -err_core_init: - kfree(kim_gdata); - - return err; -} - -static void kim_remove(struct platform_device *pdev) -{ - /* free the GPIOs requested */ - struct ti_st_plat_data *pdata = pdev->dev.platform_data; - struct kim_data_s *kim_gdata; - - kim_gdata = platform_get_drvdata(pdev); - - /* - * Free the Bluetooth/FM/GPIO - * nShutdown gpio from the system - */ - gpio_free(pdata->nshutdown_gpio); - pr_info("nshutdown GPIO Freed"); - - debugfs_remove_recursive(kim_debugfs_dir); - sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); - pr_info("sysfs entries removed"); - - kim_gdata->kim_pdev = NULL; - st_core_exit(kim_gdata->core_data); - - kfree(kim_gdata); - kim_gdata = NULL; -} - -static int kim_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct ti_st_plat_data *pdata = pdev->dev.platform_data; - - if (pdata->suspend) - return pdata->suspend(pdev, state); - - return 0; -} - -static int kim_resume(struct platform_device *pdev) -{ - struct ti_st_plat_data *pdata = pdev->dev.platform_data; - - if (pdata->resume) - return pdata->resume(pdev); - - return 0; -} - -/**********************************************************************/ -/* entry point for ST KIM module, called in from ST Core */ -static struct platform_driver kim_platform_driver = { - .probe = kim_probe, - .remove_new = kim_remove, - .suspend = kim_suspend, - .resume = kim_resume, - .driver = { - .name = "kim", - }, -}; - -module_platform_driver(kim_platform_driver); - -MODULE_AUTHOR("Pavan Savoy "); -MODULE_DESCRIPTION("Shared Transport Driver for TI BT/FM/GPS combo chips "); -MODULE_LICENSE("GPL"); diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c deleted file mode 100644 index 07406140d2770e..00000000000000 --- a/drivers/misc/ti-st/st_ll.c +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Shared Transport driver - * HCI-LL module responsible for TI proprietary HCI_LL protocol - * Copyright (C) 2009-2010 Texas Instruments - * Author: Pavan Savoy - */ - -#define pr_fmt(fmt) "(stll) :" fmt -#include -#include -#include -#include - -/**********************************************************************/ -/* internal functions */ -static void send_ll_cmd(struct st_data_s *st_data, - unsigned char cmd) -{ - - pr_debug("%s: writing %x", __func__, cmd); - st_int_write(st_data, &cmd, 1); - return; -} - -static void ll_device_want_to_sleep(struct st_data_s *st_data) -{ - struct kim_data_s *kim_data; - struct ti_st_plat_data *pdata; - - pr_debug("%s", __func__); - /* sanity check */ - if (st_data->ll_state != ST_LL_AWAKE) - pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND" - "in state %ld", st_data->ll_state); - - send_ll_cmd(st_data, LL_SLEEP_ACK); - /* update state */ - st_data->ll_state = ST_LL_ASLEEP; - - /* communicate to platform about chip asleep */ - kim_data = st_data->kim_data; - pdata = kim_data->kim_pdev->dev.platform_data; - if (pdata->chip_asleep) - pdata->chip_asleep(NULL); -} - -static void ll_device_want_to_wakeup(struct st_data_s *st_data) -{ - struct kim_data_s *kim_data; - struct ti_st_plat_data *pdata; - - /* diff actions in diff states */ - switch (st_data->ll_state) { - case ST_LL_ASLEEP: - send_ll_cmd(st_data, LL_WAKE_UP_ACK); /* send wake_ack */ - break; - case ST_LL_ASLEEP_TO_AWAKE: - /* duplicate wake_ind */ - pr_err("duplicate wake_ind while waiting for Wake ack"); - break; - case ST_LL_AWAKE: - /* duplicate wake_ind */ - pr_err("duplicate wake_ind already AWAKE"); - break; - case ST_LL_AWAKE_TO_ASLEEP: - /* duplicate wake_ind */ - pr_err("duplicate wake_ind"); - break; - } - /* update state */ - st_data->ll_state = ST_LL_AWAKE; - - /* communicate to platform about chip wakeup */ - kim_data = st_data->kim_data; - pdata = kim_data->kim_pdev->dev.platform_data; - if (pdata->chip_awake) - pdata->chip_awake(NULL); -} - -/**********************************************************************/ -/* functions invoked by ST Core */ - -/* called when ST Core wants to - * enable ST LL */ -void st_ll_enable(struct st_data_s *ll) -{ - ll->ll_state = ST_LL_AWAKE; -} - -/* called when ST Core /local module wants to - * disable ST LL */ -void st_ll_disable(struct st_data_s *ll) -{ - ll->ll_state = ST_LL_INVALID; -} - -/* called when ST Core wants to update the state */ -void st_ll_wakeup(struct st_data_s *ll) -{ - if (likely(ll->ll_state != ST_LL_AWAKE)) { - send_ll_cmd(ll, LL_WAKE_UP_IND); /* WAKE_IND */ - ll->ll_state = ST_LL_ASLEEP_TO_AWAKE; - } else { - /* don't send the duplicate wake_indication */ - pr_err(" Chip already AWAKE "); - } -} - -/* called when ST Core wants the state */ -unsigned long st_ll_getstate(struct st_data_s *ll) -{ - pr_debug(" returning state %ld", ll->ll_state); - return ll->ll_state; -} - -/* called from ST Core, when a PM related packet arrives */ -unsigned long st_ll_sleep_state(struct st_data_s *st_data, - unsigned char cmd) -{ - switch (cmd) { - case LL_SLEEP_IND: /* sleep ind */ - pr_debug("sleep indication recvd"); - ll_device_want_to_sleep(st_data); - break; - case LL_SLEEP_ACK: /* sleep ack */ - pr_err("sleep ack rcvd: host shouldn't"); - break; - case LL_WAKE_UP_IND: /* wake ind */ - pr_debug("wake indication recvd"); - ll_device_want_to_wakeup(st_data); - break; - case LL_WAKE_UP_ACK: /* wake ack */ - pr_debug("wake ack rcvd"); - st_data->ll_state = ST_LL_AWAKE; - break; - default: - pr_err(" unknown input/state "); - return -EINVAL; - } - return 0; -} - -/* Called from ST CORE to initialize ST LL */ -long st_ll_init(struct st_data_s *ll) -{ - /* set state to invalid */ - ll->ll_state = ST_LL_INVALID; - return 0; -} - -/* Called from ST CORE to de-initialize ST LL */ -long st_ll_deinit(struct st_data_s *ll) -{ - return 0; -} diff --git a/drivers/misc/tps6594-esm.c b/drivers/misc/tps6594-esm.c index b4d67a1a24e44e..2fbd3fbdf713a2 100644 --- a/drivers/misc/tps6594-esm.c +++ b/drivers/misc/tps6594-esm.c @@ -135,7 +135,7 @@ static struct platform_driver tps6594_esm_driver = { .pm = pm_sleep_ptr(&tps6594_esm_pm_ops), }, .probe = tps6594_esm_probe, - .remove_new = tps6594_esm_remove, + .remove = tps6594_esm_remove, }; module_platform_driver(tps6594_esm_driver); diff --git a/drivers/misc/tps6594-pfsm.c b/drivers/misc/tps6594-pfsm.c index 9bcca1856bfeea..0a24ce44cc37c4 100644 --- a/drivers/misc/tps6594-pfsm.c +++ b/drivers/misc/tps6594-pfsm.c @@ -314,7 +314,7 @@ static struct platform_driver tps6594_pfsm_driver = { .name = "tps6594-pfsm", }, .probe = tps6594_pfsm_probe, - .remove_new = tps6594_pfsm_remove, + .remove = tps6594_pfsm_remove, }; module_platform_driver(tps6594_pfsm_driver); diff --git a/drivers/misc/vcpu_stall_detector.c b/drivers/misc/vcpu_stall_detector.c index 41b8c2119e20e5..f0b1fc87490ec6 100644 --- a/drivers/misc/vcpu_stall_detector.c +++ b/drivers/misc/vcpu_stall_detector.c @@ -233,7 +233,7 @@ MODULE_DEVICE_TABLE(of, vcpu_stall_detect_of_match); static struct platform_driver vcpu_stall_detect_driver = { .probe = vcpu_stall_detect_probe, - .remove_new = vcpu_stall_detect_remove, + .remove = vcpu_stall_detect_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = vcpu_stall_detect_of_match, diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c index ea433695f4c470..3135ba3a58ee04 100644 --- a/drivers/misc/xilinx_sdfec.c +++ b/drivers/misc/xilinx_sdfec.c @@ -1444,7 +1444,7 @@ static struct platform_driver xsdfec_driver = { .of_match_table = xsdfec_of_match, }, .probe = xsdfec_probe, - .remove_new = xsdfec_remove, + .remove = xsdfec_remove, }; module_platform_driver(xsdfec_driver); diff --git a/drivers/misc/xilinx_tmr_inject.c b/drivers/misc/xilinx_tmr_inject.c index 734fdfac19ef3c..6284606ffb9ff6 100644 --- a/drivers/misc/xilinx_tmr_inject.c +++ b/drivers/misc/xilinx_tmr_inject.c @@ -164,7 +164,7 @@ static struct platform_driver xtmr_inject_driver = { .of_match_table = xtmr_inject_of_match, }, .probe = xtmr_inject_probe, - .remove_new = xtmr_inject_remove, + .remove = xtmr_inject_remove, }; module_platform_driver(xtmr_inject_driver); MODULE_AUTHOR("Advanced Micro Devices, Inc"); diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 6a907736cd7a51..15b067e8b0d16c 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ - sdio_cis.o sdio_io.o sdio_irq.o \ + sdio_cis.o sdio_io.o sdio_irq.o sd_uhs2.o\ slot-gpio.o regulator.o mmc_core-$(CONFIG_OF) += pwrseq.o obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index ef06a4d5d65bb2..4830628510e6e2 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -50,6 +50,7 @@ #include #include +#include #include "queue.h" #include "block.h" @@ -993,11 +994,12 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks) int err; u32 result; __be32 *blocks; + u8 resp_sz = mmc_card_ult_capacity(card) ? 8 : 4; + unsigned int noio_flag; struct mmc_request mrq = {}; struct mmc_command cmd = {}; struct mmc_data data = {}; - struct scatterlist sg; err = mmc_app_cmd(card->host, card); @@ -1008,7 +1010,7 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks) cmd.arg = 0; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; - data.blksz = 4; + data.blksz = resp_sz; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; @@ -1018,15 +1020,29 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks) mrq.cmd = &cmd; mrq.data = &data; - blocks = kmalloc(4, GFP_KERNEL); + noio_flag = memalloc_noio_save(); + blocks = kmalloc(resp_sz, GFP_KERNEL); + memalloc_noio_restore(noio_flag); if (!blocks) return -ENOMEM; - sg_init_one(&sg, blocks, 4); + sg_init_one(&sg, blocks, resp_sz); mmc_wait_for_req(card->host, &mrq); - result = ntohl(*blocks); + if (mmc_card_ult_capacity(card)) { + /* + * Normally, ACMD22 returns the number of written sectors as + * u32. SDUC, however, returns it as u64. This is not a + * superfluous requirement, because SDUC writes may exceed 2TB. + * For Linux mmc however, the previously write operation could + * not be more than the block layer limits, thus just make room + * for a u64 and cast the response back to u32. + */ + result = clamp_val(get_unaligned_be64(blocks), 0, UINT_MAX); + } else { + result = ntohl(*blocks); + } kfree(blocks); if (cmd.error || data.error) @@ -1199,7 +1215,8 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req, { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; - unsigned int from, nr; + unsigned int nr; + sector_t from; int err = 0; blk_status_t status = BLK_STS_OK; @@ -1254,7 +1271,8 @@ static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, { struct mmc_blk_data *md = mq->blkdata; struct mmc_card *card = md->queue.card; - unsigned int from, nr, arg; + unsigned int nr, arg; + sector_t from; int err = 0, type = MMC_BLK_SECDISCARD; blk_status_t status = BLK_STS_OK; @@ -1759,6 +1777,11 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC; brq->mrq.sbc = &brq->sbc; } + + if (mmc_card_ult_capacity(card)) { + brq->cmd.ext_addr = blk_rq_pos(req) >> 32; + brq->cmd.has_ext_addr = true; + } } #define MMC_MAX_RETRIES 5 @@ -2501,6 +2524,56 @@ static inline int mmc_blk_readonly(struct mmc_card *card) !(card->csd.cmdclass & CCC_BLOCK_WRITE); } +/* + * Search for a declared partitions node for the disk in mmc-card related node. + * + * This is to permit support for partition table defined in DT in special case + * where a partition table is not written in the disk and is expected to be + * passed from the running system. + * + * For the user disk, "partitions" node is searched. + * For the special HW disk, "partitions-" node with the appended name is used + * following this conversion table (to adhere to JEDEC naming) + * - boot0 -> partitions-boot1 + * - boot1 -> partitions-boot2 + * - gp0 -> partitions-gp1 + * - gp1 -> partitions-gp2 + * - gp2 -> partitions-gp3 + * - gp3 -> partitions-gp4 + */ +static struct fwnode_handle *mmc_blk_get_partitions_node(struct device *mmc_dev, + const char *subname) +{ + const char *node_name = "partitions"; + + if (subname) { + mmc_dev = mmc_dev->parent; + + /* + * Check if we are allocating a BOOT disk boot0/1 disk. + * In DT we use the JEDEC naming boot1/2. + */ + if (!strcmp(subname, "boot0")) + node_name = "partitions-boot1"; + if (!strcmp(subname, "boot1")) + node_name = "partitions-boot2"; + /* + * Check if we are allocating a GP disk gp0/1/2/3 disk. + * In DT we use the JEDEC naming gp1/2/3/4. + */ + if (!strcmp(subname, "gp0")) + node_name = "partitions-gp1"; + if (!strcmp(subname, "gp1")) + node_name = "partitions-gp2"; + if (!strcmp(subname, "gp2")) + node_name = "partitions-gp3"; + if (!strcmp(subname, "gp3")) + node_name = "partitions-gp4"; + } + + return device_get_named_child_node(mmc_dev, node_name); +} + static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct device *parent, sector_t size, @@ -2509,6 +2582,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, int area_type, unsigned int part_type) { + struct fwnode_handle *disk_fwnode; struct mmc_blk_data *md; int devidx, ret; char cap_str[10]; @@ -2547,7 +2621,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, if (mmc_host_cmd23(card->host)) { if ((mmc_card_mmc(card) && card->csd.mmca_vsn >= CSD_SPEC_VER_3) || - (mmc_card_sd(card) && + (mmc_card_sd(card) && !mmc_card_ult_capacity(card) && card->scr.cmds & SD_SCR_CMD23_SUPPORT)) md->flags |= MMC_BLK_CMD23; } @@ -2610,7 +2684,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, /* used in ->open, must be set before add_disk: */ if (area_type == MMC_BLK_DATA_AREA_MAIN) dev_set_drvdata(&card->dev, md); - ret = device_add_disk(md->parent, md->disk, mmc_disk_attr_groups); + disk_fwnode = mmc_blk_get_partitions_node(parent, subname); + ret = add_disk_fwnode(md->parent, md->disk, mmc_disk_attr_groups, + disk_fwnode); if (ret) goto err_put_disk; return md; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 0ddaee0eae54f0..1cf64e0952fbe2 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -149,6 +149,8 @@ static void mmc_bus_shutdown(struct device *dev) if (dev->driver && drv->shutdown) drv->shutdown(card); + __mmc_stop_host(host); + if (host->bus_ops->shutdown) { ret = host->bus_ops->shutdown(host); if (ret) @@ -299,6 +301,7 @@ int mmc_add_card(struct mmc_card *card) { int ret; const char *type; + const char *speed_mode = ""; const char *uhs_bus_speed_mode = ""; static const char *const uhs_speeds[] = { [UHS_SDR12_BUS_SPEED] = "SDR12 ", @@ -321,7 +324,9 @@ int mmc_add_card(struct mmc_card *card) case MMC_TYPE_SD: type = "SD"; if (mmc_card_blockaddr(card)) { - if (mmc_card_ext_capacity(card)) + if (mmc_card_ult_capacity(card)) + type = "SDUC"; + else if (mmc_card_ext_capacity(card)) type = "SDXC"; else type = "SDHC"; @@ -340,27 +345,32 @@ int mmc_add_card(struct mmc_card *card) break; } + if (mmc_card_hs(card)) + speed_mode = "high speed "; + else if (mmc_card_uhs(card)) + speed_mode = "UHS-I speed "; + else if (mmc_card_uhs2(card->host)) + speed_mode = "UHS-II speed "; + else if (mmc_card_ddr52(card)) + speed_mode = "high speed DDR "; + else if (mmc_card_hs200(card)) + speed_mode = "HS200 "; + else if (mmc_card_hs400es(card)) + speed_mode = "HS400 Enhanced strobe "; + else if (mmc_card_hs400(card)) + speed_mode = "HS400 "; + if (mmc_card_uhs(card) && (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; - if (mmc_host_is_spi(card->host)) { - pr_info("%s: new %s%s%s card on SPI\n", - mmc_hostname(card->host), - mmc_card_hs(card) ? "high speed " : "", - mmc_card_ddr52(card) ? "DDR " : "", - type); - } else { - pr_info("%s: new %s%s%s%s%s%s card at address %04x\n", - mmc_hostname(card->host), - mmc_card_uhs(card) ? "ultra high speed " : - (mmc_card_hs(card) ? "high speed " : ""), - mmc_card_hs400(card) ? "HS400 " : - (mmc_card_hs200(card) ? "HS200 " : ""), - mmc_card_hs400es(card) ? "Enhanced strobe " : "", - mmc_card_ddr52(card) ? "DDR " : "", + if (mmc_host_is_spi(card->host)) + pr_info("%s: new %s%s card on SPI\n", + mmc_hostname(card->host), speed_mode, type); + else + pr_info("%s: new %s%s%s card at address %04x\n", + mmc_hostname(card->host), speed_mode, uhs_bus_speed_mode, type, card->rca); - } mmc_add_card_debugfs(card); card->dev.of_node = mmc_of_find_child_device(card->host, 0); diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h index b7754a1b8d9788..3205feb1e8ff6a 100644 --- a/drivers/mmc/core/card.h +++ b/drivers/mmc/core/card.h @@ -23,6 +23,7 @@ #define MMC_CARD_SDXC (1<<3) /* card is SDXC */ #define MMC_CARD_REMOVED (1<<4) /* card has been removed */ #define MMC_STATE_SUSPENDED (1<<5) /* card is suspended */ +#define MMC_CARD_SDUC (1<<6) /* card is SDUC */ #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) @@ -30,11 +31,13 @@ #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) #define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED) +#define mmc_card_ult_capacity(c) ((c)->state & MMC_CARD_SDUC) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) +#define mmc_card_set_ult_capacity(c) ((c)->state |= MMC_CARD_SDUC) #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED) #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED) @@ -82,6 +85,7 @@ struct mmc_fixup { #define CID_MANFID_SANDISK_SD 0x3 #define CID_MANFID_ATP 0x9 #define CID_MANFID_TOSHIBA 0x11 +#define CID_MANFID_GIGASTONE 0x12 #define CID_MANFID_MICRON 0x13 #define CID_MANFID_SAMSUNG 0x15 #define CID_MANFID_APACER 0x27 @@ -284,4 +288,10 @@ static inline int mmc_card_broken_cache_flush(const struct mmc_card *c) { return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH; } + +static inline int mmc_card_broken_sd_poweroff_notify(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY; +} + #endif diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d6c819dd68ed47..d996d39c0d6fa1 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -336,6 +336,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { int err; + if (mrq->cmd && mrq->cmd->has_ext_addr) + mmc_send_ext_addr(host, mrq->cmd->ext_addr); + init_completion(&mrq->cmd_completion); mmc_retune_hold(host); @@ -351,6 +354,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) if (err) return err; + if (host->uhs2_sd_tran) + mmc_uhs2_prepare_cmd(host, mrq); + led_trigger_event(host->led, LED_FULL); __mmc_start_request(host, mrq); @@ -450,6 +456,9 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq) if (err) goto out_err; + if (host->uhs2_sd_tran) + mmc_uhs2_prepare_cmd(host, mrq); + err = host->cqe_ops->cqe_request(host, mrq); if (err) goto out_err; @@ -1132,7 +1141,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) return 0; } - if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) { + if (!mmc_card_uhs2(host) && host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) { bit = ffs(ocr) - 1; ocr &= 3 << bit; mmc_power_cycle(host, ocr); @@ -1598,8 +1607,8 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card, return mmc_mmc_erase_timeout(card, arg, qty); } -static int mmc_do_erase(struct mmc_card *card, unsigned int from, - unsigned int to, unsigned int arg) +static int mmc_do_erase(struct mmc_card *card, sector_t from, + sector_t to, unsigned int arg) { struct mmc_command cmd = {}; unsigned int qty = 0, busy_timeout = 0; @@ -1630,8 +1639,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, else if (mmc_card_sd(card)) qty += to - from + 1; else - qty += ((to / card->erase_size) - - (from / card->erase_size)) + 1; + qty += (mmc_sector_div(to, card->erase_size) - + mmc_sector_div(from, card->erase_size)) + 1; if (!mmc_card_blockaddr(card)) { from <<= 9; @@ -1644,6 +1653,12 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.opcode = MMC_ERASE_GROUP_START; cmd.arg = from; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + + if (mmc_card_ult_capacity(card)) { + cmd.ext_addr = from >> 32; + cmd.has_ext_addr = true; + } + err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_err("mmc_erase: group start error %d, " @@ -1659,6 +1674,12 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.opcode = MMC_ERASE_GROUP_END; cmd.arg = to; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + + if (mmc_card_ult_capacity(card)) { + cmd.ext_addr = to >> 32; + cmd.has_ext_addr = true; + } + err = mmc_wait_for_cmd(card->host, &cmd, 0); if (err) { pr_err("mmc_erase: group end error %d, status %#x\n", @@ -1700,18 +1721,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, } static unsigned int mmc_align_erase_size(struct mmc_card *card, - unsigned int *from, - unsigned int *to, + sector_t *from, + sector_t *to, unsigned int nr) { - unsigned int from_new = *from, nr_new = nr, rem; + sector_t from_new = *from; + unsigned int nr_new = nr, rem; /* * When the 'card->erase_size' is power of 2, we can use round_up/down() * to align the erase size efficiently. */ if (is_power_of_2(card->erase_size)) { - unsigned int temp = from_new; + sector_t temp = from_new; from_new = round_up(temp, card->erase_size); rem = from_new - temp; @@ -1723,7 +1745,7 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card, nr_new = round_down(nr_new, card->erase_size); } else { - rem = from_new % card->erase_size; + rem = mmc_sector_mod(from_new, card->erase_size); if (rem) { rem = card->erase_size - rem; from_new += rem; @@ -1756,10 +1778,12 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card, * * Caller must claim host before calling this function. */ -int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, +int mmc_erase(struct mmc_card *card, sector_t from, unsigned int nr, unsigned int arg) { - unsigned int rem, to = from + nr; + unsigned int rem; + sector_t to = from + nr; + int err; if (!(card->csd.cmdclass & CCC_ERASE)) @@ -1780,7 +1804,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, return -EOPNOTSUPP; if (arg == MMC_SECURE_ERASE_ARG) { - if (from % card->erase_size || nr % card->erase_size) + if (mmc_sector_mod(from, card->erase_size) || nr % card->erase_size) return -EINVAL; } @@ -1804,7 +1828,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, * and call mmc_do_erase() twice if necessary. This special case is * identified by the card->eg_boundary flag. */ - rem = card->erase_size - (from % card->erase_size); + rem = card->erase_size - mmc_sector_mod(from, card->erase_size); if ((arg & MMC_TRIM_OR_DISCARD_ARGS) && card->eg_boundary && nr > rem) { err = mmc_do_erase(card, from, from + rem - 1, arg); from += rem; @@ -1863,12 +1887,12 @@ int mmc_can_secure_erase_trim(struct mmc_card *card) } EXPORT_SYMBOL(mmc_can_secure_erase_trim); -int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, +int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr) { if (!card->erase_size) return 0; - if (from % card->erase_size || nr % card->erase_size) + if (mmc_sector_mod(from, card->erase_size) || nr % card->erase_size) return 0; return 1; } @@ -2249,6 +2273,18 @@ void mmc_rescan(struct work_struct *work) goto out; } + /* + * Ideally we should favor initialization of legacy SD cards and defer + * UHS-II enumeration. However, it seems like cards doesn't reliably + * announce their support for UHS-II in the response to the ACMD41, + * while initializing the legacy SD interface. Therefore, let's start + * with UHS-II for now. + */ + if (!mmc_attach_sd_uhs2(host)) { + mmc_release_host(host); + goto out; + } + for (i = 0; i < ARRAY_SIZE(freqs); i++) { unsigned int freq = freqs[i]; if (freq > host->f_max) { @@ -2281,10 +2317,13 @@ void mmc_rescan(struct work_struct *work) void mmc_start_host(struct mmc_host *host) { + bool power_up = !(host->caps2 & + (MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_SD_UHS2)); + host->f_init = max(min(freqs[0], host->f_max), host->f_min); host->rescan_disable = 0; - if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) { + if (power_up) { mmc_claim_host(host); mmc_power_up(host, host->ocr_avail); mmc_release_host(host); @@ -2296,6 +2335,9 @@ void mmc_start_host(struct mmc_host *host) void __mmc_stop_host(struct mmc_host *host) { + if (host->rescan_disable) + return; + if (host->slot.cd_irq >= 0) { mmc_gpio_set_cd_wake(host, false); disable_irq(host->slot.cd_irq); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 37091a6589edb5..fc9c066e6468f8 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -81,6 +81,7 @@ int mmc_detect_card_removed(struct mmc_host *host); int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); int mmc_attach_sdio(struct mmc_host *host); +int mmc_attach_sd_uhs2(struct mmc_host *host); /* Module parameters */ extern bool use_spi_crc; @@ -116,15 +117,13 @@ bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq); int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq); -int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, - unsigned int arg); +int mmc_erase(struct mmc_card *card, sector_t from, unsigned int nr, unsigned int arg); int mmc_can_erase(struct mmc_card *card); int mmc_can_trim(struct mmc_card *card); int mmc_can_discard(struct mmc_card *card); int mmc_can_sanitize(struct mmc_card *card); int mmc_can_secure_erase_trim(struct mmc_card *card); -int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, - unsigned int nr); +int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr); unsigned int mmc_calc_max_discard(struct mmc_card *card); int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); @@ -199,4 +198,14 @@ static inline int mmc_flush_cache(struct mmc_host *host) return 0; } +static inline unsigned int mmc_sector_div(sector_t dividend, u32 divisor) +{ + return div_u64(dividend, divisor); +} + +static inline unsigned int mmc_sector_mod(sector_t dividend, u32 divisor) +{ + return sector_div(dividend, divisor); +} + #endif diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 3b3adbddf6641e..5c8e62e8f3318c 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -144,10 +144,24 @@ int mmc_set_dsr(struct mmc_host *host) return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); } +int __mmc_go_idle(struct mmc_host *host) +{ + struct mmc_command cmd = {}; + int err; + + cmd.opcode = MMC_GO_IDLE_STATE; + cmd.arg = 0; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; + + err = mmc_wait_for_cmd(host, &cmd, 0); + mmc_delay(1); + + return err; +} + int mmc_go_idle(struct mmc_host *host) { int err; - struct mmc_command cmd = {}; /* * Non-SPI hosts need to prevent chipselect going active during @@ -163,13 +177,7 @@ int mmc_go_idle(struct mmc_host *host) mmc_delay(1); } - cmd.opcode = MMC_GO_IDLE_STATE; - cmd.arg = 0; - cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC; - - err = mmc_wait_for_cmd(host, &cmd, 0); - - mmc_delay(1); + err = __mmc_go_idle(host); if (!mmc_host_is_spi(host)) { mmc_set_chip_select(host, MMC_CS_DONTCARE); diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 06017110e1b00d..0df3ebd900d1fa 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -25,6 +25,7 @@ struct mmc_command; int mmc_select_card(struct mmc_card *card); int mmc_deselect_cards(struct mmc_host *host); int mmc_set_dsr(struct mmc_host *host); +int __mmc_go_idle(struct mmc_host *host); int mmc_go_idle(struct mmc_host *host); int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_set_relative_addr(struct mmc_card *card); diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c index b7f627a9fdeab9..4f4286b8e0f201 100644 --- a/drivers/mmc/core/mmc_test.c +++ b/drivers/mmc/core/mmc_test.c @@ -3241,6 +3241,12 @@ static int mmc_test_probe(struct mmc_card *card) if (!mmc_card_mmc(card) && !mmc_card_sd(card)) return -ENODEV; + if (mmc_card_ult_capacity(card)) { + pr_info("%s: mmc-test currently UNSUPPORTED for SDUC\n", + mmc_hostname(card->host)); + return -EOPNOTSUPP; + } + ret = mmc_test_register_dbgfs_file(card); if (ret) return ret; diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index 96fa4c50890085..35af67e2694513 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -107,7 +107,7 @@ MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match); static struct platform_driver mmc_pwrseq_emmc_driver = { .probe = mmc_pwrseq_emmc_probe, - .remove_new = mmc_pwrseq_emmc_remove, + .remove = mmc_pwrseq_emmc_remove, .driver = { .name = "pwrseq_emmc", .of_match_table = mmc_pwrseq_emmc_of_match, diff --git a/drivers/mmc/core/pwrseq_sd8787.c b/drivers/mmc/core/pwrseq_sd8787.c index f24bbd68e25130..30282155a0e11e 100644 --- a/drivers/mmc/core/pwrseq_sd8787.c +++ b/drivers/mmc/core/pwrseq_sd8787.c @@ -122,7 +122,7 @@ static void mmc_pwrseq_sd8787_remove(struct platform_device *pdev) static struct platform_driver mmc_pwrseq_sd8787_driver = { .probe = mmc_pwrseq_sd8787_probe, - .remove_new = mmc_pwrseq_sd8787_remove, + .remove = mmc_pwrseq_sd8787_remove, .driver = { .name = "pwrseq_sd8787", .of_match_table = mmc_pwrseq_sd8787_of_match, diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index 154a8921ae7598..37cd858df0f4d7 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include @@ -29,6 +31,7 @@ struct mmc_pwrseq_simple { u32 power_off_delay_us; struct clk *ext_clk; struct gpio_descs *reset_gpios; + struct reset_control *reset_ctrl; }; #define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq) @@ -67,14 +70,21 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host) pwrseq->clk_enabled = true; } - mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); + if (pwrseq->reset_ctrl) { + reset_control_deassert(pwrseq->reset_ctrl); + reset_control_assert(pwrseq->reset_ctrl); + } else + mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); } static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host) { struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); - mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); + if (pwrseq->reset_ctrl) + reset_control_deassert(pwrseq->reset_ctrl); + else + mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); if (pwrseq->post_power_on_delay_ms) msleep(pwrseq->post_power_on_delay_ms); @@ -84,7 +94,10 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host) { struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); - mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); + if (pwrseq->reset_ctrl) + reset_control_assert(pwrseq->reset_ctrl); + else + mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); if (pwrseq->power_off_delay_us) usleep_range(pwrseq->power_off_delay_us, @@ -112,6 +125,7 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev) { struct mmc_pwrseq_simple *pwrseq; struct device *dev = &pdev->dev; + int ngpio; pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); if (!pwrseq) @@ -121,12 +135,26 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev) if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT) return dev_err_probe(dev, PTR_ERR(pwrseq->ext_clk), "external clock not ready\n"); - pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", - GPIOD_OUT_HIGH); - if (IS_ERR(pwrseq->reset_gpios) && - PTR_ERR(pwrseq->reset_gpios) != -ENOENT && - PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) { - return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios), "reset GPIOs not ready\n"); + ngpio = of_count_phandle_with_args(dev->of_node, "reset-gpios", "#gpio-cells"); + if (ngpio == 1) { + pwrseq->reset_ctrl = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(pwrseq->reset_ctrl)) + return dev_err_probe(dev, PTR_ERR(pwrseq->reset_ctrl), + "reset control not ready\n"); + } + + /* + * Fallback to GPIO based reset control in case of multiple reset lines + * are specified or the platform doesn't have support for RESET at all. + */ + if (!pwrseq->reset_ctrl) { + pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(pwrseq->reset_gpios) && + PTR_ERR(pwrseq->reset_gpios) != -ENOENT && + PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) { + return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios), + "reset GPIOs not ready\n"); + } } device_property_read_u32(dev, "post-power-on-delay-ms", @@ -151,7 +179,7 @@ static void mmc_pwrseq_simple_remove(struct platform_device *pdev) static struct platform_driver mmc_pwrseq_simple_driver = { .probe = mmc_pwrseq_simple_probe, - .remove_new = mmc_pwrseq_simple_remove, + .remove = mmc_pwrseq_simple_remove, .driver = { .name = "pwrseq_simple", .of_match_table = mmc_pwrseq_simple_of_match, diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 92905fc46436dd..89b512905be140 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -25,6 +25,15 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = { 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), + /* + * GIGASTONE Gaming Plus microSD cards manufactured on 02/2022 never + * clear Flush Cache bit and set Poweroff Notification Ready bit. + */ + _FIXUP_EXT("ASTC", CID_MANFID_GIGASTONE, 0x3456, 2022, 2, + 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd, + MMC_QUIRK_BROKEN_SD_CACHE | MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY, + EXT_CSD_REV_ANY), + END_FIXUP }; diff --git a/drivers/mmc/core/regulator.c b/drivers/mmc/core/regulator.c index 01747ab1024ec1..3dae2e9b797813 100644 --- a/drivers/mmc/core/regulator.c +++ b/drivers/mmc/core/regulator.c @@ -226,6 +226,33 @@ int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios) } EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc); +/** + * mmc_regulator_set_vqmmc2 - Set vqmmc2 as per the ios->vqmmc2_voltage + * @mmc: The mmc host to regulate + * @ios: The io bus settings + * + * Sets a new voltage level for the vqmmc2 regulator, which may correspond to + * the vdd2 regulator for an SD UHS-II interface. This function is expected to + * be called by mmc host drivers. + * + * Returns a negative error code on failure, zero if the voltage level was + * changed successfully or a positive value if the level didn't need to change. + */ +int mmc_regulator_set_vqmmc2(struct mmc_host *mmc, struct mmc_ios *ios) +{ + if (IS_ERR(mmc->supply.vqmmc2)) + return -EINVAL; + + switch (ios->vqmmc2_voltage) { + case MMC_VQMMC2_VOLTAGE_180: + return mmc_regulator_set_voltage_if_supported( + mmc->supply.vqmmc2, 1700000, 1800000, 1950000); + default: + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc2); + #else static inline int mmc_regulator_get_ocrmask(struct regulator *supply) @@ -252,6 +279,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc"); mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc"); + mmc->supply.vqmmc2 = devm_regulator_get_optional(dev, "vqmmc2"); if (IS_ERR(mmc->supply.vmmc)) { if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) @@ -275,6 +303,12 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) dev_dbg(dev, "No vqmmc regulator found\n"); } + if (IS_ERR(mmc->supply.vqmmc2)) { + if (PTR_ERR(mmc->supply.vqmmc2) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_dbg(dev, "No vqmmc2 regulator found\n"); + } + return 0; } EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 12fe282bea77ef..cc757b850e798b 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -100,7 +100,7 @@ void mmc_decode_cid(struct mmc_card *card) /* * Given a 128-bit response, decode to our card CSD structure. */ -static int mmc_decode_csd(struct mmc_card *card) +static int mmc_decode_csd(struct mmc_card *card, bool is_sduc) { struct mmc_csd *csd = &card->csd; unsigned int e, m, csd_struct; @@ -144,9 +144,10 @@ static int mmc_decode_csd(struct mmc_card *card) mmc_card_set_readonly(card); break; case 1: + case 2: /* - * This is a block-addressed SDHC or SDXC card. Most - * interesting fields are unused and have fixed + * This is a block-addressed SDHC, SDXC or SDUC card. + * Most interesting fields are unused and have fixed * values. To avoid getting tripped by buggy cards, * we assume those fixed values ourselves. */ @@ -159,14 +160,19 @@ static int mmc_decode_csd(struct mmc_card *card) e = unstuff_bits(resp, 96, 3); csd->max_dtr = tran_exp[e] * tran_mant[m]; csd->cmdclass = unstuff_bits(resp, 84, 12); - csd->c_size = unstuff_bits(resp, 48, 22); - /* SDXC cards have a minimum C_SIZE of 0x00FFFF */ - if (csd->c_size >= 0xFFFF) + if (csd_struct == 1) + m = unstuff_bits(resp, 48, 22); + else + m = unstuff_bits(resp, 48, 28); + csd->c_size = m; + + if (csd->c_size >= 0x400000 && is_sduc) + mmc_card_set_ult_capacity(card); + else if (csd->c_size >= 0xFFFF) mmc_card_set_ext_capacity(card); - m = unstuff_bits(resp, 48, 22); - csd->capacity = (1 + m) << 10; + csd->capacity = (1 + (typeof(sector_t))m) << 10; csd->read_blkbits = 9; csd->read_partial = 0; @@ -194,7 +200,7 @@ static int mmc_decode_csd(struct mmc_card *card) /* * Given a 64-bit response, decode to our card SCR structure. */ -static int mmc_decode_scr(struct mmc_card *card) +int mmc_decode_scr(struct mmc_card *card) { struct sd_scr *scr = &card->scr; unsigned int scr_struct; @@ -830,8 +836,11 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) * block-addressed SDHC cards. */ err = mmc_send_if_cond(host, ocr); - if (!err) + if (!err) { ocr |= SD_OCR_CCS; + /* Set HO2T as well - SDUC card won't respond otherwise */ + ocr |= SD_OCR_2T; + } /* * If the host supports one of UHS-I modes, request the card @@ -876,7 +885,7 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) return err; } -int mmc_sd_get_csd(struct mmc_card *card) +int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc) { int err; @@ -887,14 +896,14 @@ int mmc_sd_get_csd(struct mmc_card *card) if (err) return err; - err = mmc_decode_csd(card); + err = mmc_decode_csd(card, is_sduc); if (err) return err; return 0; } -static int mmc_sd_get_ro(struct mmc_host *host) +int mmc_sd_get_ro(struct mmc_host *host) { int ro; @@ -1107,7 +1116,7 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page, card->ext_power.rev = reg_buf[0] & 0xf; /* Power Off Notification support at bit 4. */ - if (reg_buf[1] & BIT(4)) + if ((reg_buf[1] & BIT(4)) && !mmc_card_broken_sd_poweroff_notify(card)) card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY; /* Power Sustenance support at bit 5. */ @@ -1442,7 +1451,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, } if (!oldcard) { - err = mmc_sd_get_csd(card); + u32 sduc_arg = SD_OCR_CCS | SD_OCR_2T; + bool is_sduc = (rocr & sduc_arg) == sduc_arg; + + err = mmc_sd_get_csd(card, is_sduc); if (err) goto free_card; @@ -1552,7 +1564,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, goto free_card; } - if (host->cqe_ops && !host->cqe_enabled) { + if (!mmc_card_ult_capacity(card) && host->cqe_ops && !host->cqe_enabled) { err = host->cqe_ops->cqe_enable(host, card); if (!err) { host->cqe_enabled = true; diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h index fe6dd46927a423..301dc34b8b637a 100644 --- a/drivers/mmc/core/sd.h +++ b/drivers/mmc/core/sd.h @@ -10,7 +10,9 @@ struct mmc_host; struct mmc_card; int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr); -int mmc_sd_get_csd(struct mmc_card *card); +int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc); +int mmc_decode_scr(struct mmc_card *card); +int mmc_sd_get_ro(struct mmc_host *host); void mmc_decode_cid(struct mmc_card *card); int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, bool reinit); diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index f93c392040ae7a..cd86463dd306ce 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -16,6 +16,7 @@ #include #include "core.h" +#include "card.h" #include "sd_ops.h" #include "mmc_ops.h" @@ -41,6 +42,15 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) if (WARN_ON(card && card->host != host)) return -EINVAL; + /* + * UHS2 packet has APP bit so only set APP_CMD flag here. + * Will set the APP bit when assembling UHS2 packet. + */ + if (host->uhs2_sd_tran) { + host->uhs2_app_cmd = true; + return 0; + } + cmd.opcode = MMC_APP_CMD; if (card) { @@ -188,6 +198,20 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) return 0; } +int mmc_send_ext_addr(struct mmc_host *host, u32 addr) +{ + struct mmc_command cmd = { + .opcode = SD_ADDR_EXT, + .arg = addr, + .flags = MMC_RSP_R1 | MMC_CMD_AC, + }; + + if (!mmc_card_ult_capacity(host->card)) + return 0; + + return mmc_wait_for_cmd(host, &cmd, 0); +} + static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits, u32 *resp) { diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h index 7667fc223b7484..8fffc1b29757b3 100644 --- a/drivers/mmc/core/sd_ops.h +++ b/drivers/mmc/core/sd_ops.h @@ -12,6 +12,7 @@ struct mmc_card; struct mmc_host; +struct mmc_request; int mmc_app_set_bus_width(struct mmc_card *card, int width); int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); @@ -21,6 +22,8 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca); int mmc_app_send_scr(struct mmc_card *card); int mmc_app_sd_status(struct mmc_card *card, void *ssr); int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card); +int mmc_send_ext_addr(struct mmc_host *host, u32 addr); +void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq); #endif diff --git a/drivers/mmc/core/sd_uhs2.c b/drivers/mmc/core/sd_uhs2.c new file mode 100644 index 00000000000000..1c31d0dfa96152 --- /dev/null +++ b/drivers/mmc/core/sd_uhs2.c @@ -0,0 +1,1304 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 Linaro Ltd + * Author: Ulf Hansson + * + * Copyright (C) 2014 Intel Corp, All Rights Reserved. + * Author: Yi Sun + * + * Copyright (C) 2020 Genesys Logic, Inc. + * Authors: Ben Chuang + * + * Copyright (C) 2020 Linaro Limited + * Author: AKASHI Takahiro + * + * Copyright (C) 2022 Genesys Logic, Inc. + * Authors: Jason Lai + * + * Copyright (C) 2023 Genesys Logic, Inc. + * Authors: Victor Shih + * + * Support for SD UHS-II cards + */ +#include +#include + +#include +#include +#include +#include +#include + +#include "card.h" +#include "core.h" +#include "bus.h" +#include "sd.h" +#include "sd_ops.h" +#include "mmc_ops.h" + +#define UHS2_WAIT_CFG_COMPLETE_PERIOD_US (1 * 1000) +#define UHS2_WAIT_CFG_COMPLETE_TIMEOUT_MS 100 + +static const unsigned int sd_uhs2_freqs[] = { 52000000, 26000000 }; + +struct sd_uhs2_wait_active_state_data { + struct mmc_host *host; + struct mmc_command *cmd; +}; + +static int sd_uhs2_power_up(struct mmc_host *host) +{ + if (host->ios.power_mode == MMC_POWER_ON) + return 0; + + host->ios.vdd = fls(host->ocr_avail) - 1; + host->ios.clock = host->f_init; + host->ios.timing = MMC_TIMING_UHS2_SPEED_A; + host->ios.power_mode = MMC_POWER_ON; + + return host->ops->uhs2_control(host, UHS2_SET_IOS); +} + +static int sd_uhs2_power_off(struct mmc_host *host) +{ + int err; + + if (host->ios.power_mode == MMC_POWER_OFF) + return 0; + + host->ios.vdd = 0; + host->ios.clock = 0; + host->ios.power_mode = MMC_POWER_OFF; + host->uhs2_sd_tran = false; + + err = host->ops->uhs2_control(host, UHS2_SET_IOS); + if (err) + return err; + + /* For consistency, let's restore the initial timing. */ + host->ios.timing = MMC_TIMING_LEGACY; + return 0; +} + +/* + * Run the phy initialization sequence, which mainly relies on the UHS-II host + * to check that we reach the expected electrical state, between the host and + * the card. + */ +static int sd_uhs2_phy_init(struct mmc_host *host) +{ + int err; + + err = host->ops->uhs2_control(host, UHS2_PHY_INIT); + if (err) { + pr_err("%s: failed to initial phy for UHS-II!\n", + mmc_hostname(host)); + } + + return err; +} + +/* + * sd_uhs2_cmd_assemble() - build up UHS-II command packet which is embedded in + * mmc_command structure + * @cmd: MMC command to executed + * @uhs2_cmd: UHS2 command corresponded to MMC command + * @header: Header field of UHS-II command cxpacket + * @arg: Argument field of UHS-II command packet + * @payload: Payload field of UHS-II command packet + * @plen: Payload length + * @resp: Response buffer is allocated by caller and it is used to keep + * the response of CM-TRAN command. For SD-TRAN command, uhs2_resp + * should be null and SD-TRAN command response should be stored in + * resp of mmc_command. + * @resp_len: Response buffer length + * + * The uhs2_command structure contains message packets which are transmited/ + * received on UHS-II bus. This function fills in the contents of uhs2_command + * structure and embededs UHS2 command into mmc_command structure, which is used + * in legacy SD operation functions. + * + */ +static void sd_uhs2_cmd_assemble(struct mmc_command *cmd, + struct uhs2_command *uhs2_cmd, + u8 plen, u8 resp_len) +{ + uhs2_cmd->payload_len = plen * sizeof(u32); + uhs2_cmd->packet_len = uhs2_cmd->payload_len + 4; + + cmd->uhs2_cmd = uhs2_cmd; + cmd->uhs2_cmd->uhs2_resp_len = resp_len; +} + +/* + * Do the early initialization of the card, by sending the device init broadcast + * command and wait for the process to be completed. + */ +static int sd_uhs2_dev_init(struct mmc_host *host) +{ + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u32 cnt; + u32 dap, gap, resp_gap; + u32 payload0; + u8 gd = 0; + int err; + + dap = host->uhs2_caps.dap; + gap = host->uhs2_caps.gap; + + /* + * Refer to UHS-II Addendum Version 1.02 Figure 6-21 to see DEVICE_INIT CCMD format. + * Head: + * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b). + * - IOADR = CMD_BASE + 002h + * Payload: + * - bit [3:0] : GAP(Group Allocated Power) + * - bit [7:4] : GD(Group Descriptor) + * - bit [11] : Complete Flag + * - bit [15:12]: DAP(Device Allocated Power) + */ + uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD; + uhs2_cmd.arg = ((UHS2_DEV_CMD_DEVICE_INIT & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_4B | + (UHS2_DEV_CMD_DEVICE_INIT >> 8); + + /* + * Refer to UHS-II Addendum Version 1.02 section 6.3.1. + * Max. time from DEVICE_INIT CCMD EOP reception on Device + * Rx to its SOP transmission on Device Tx(Tfwd_init_cmd) is + * 1 second. + */ + cmd.busy_timeout = 1000; + + /* + * Refer to UHS-II Addendum Version 1.02 section 6.2.6.3. + * Let's retry the DEVICE_INIT command no more than 30 times. + */ + for (cnt = 0; cnt < 30; cnt++) { + payload0 = ((dap & 0xF) << 12) | + UHS2_DEV_INIT_COMPLETE_FLAG | + ((gd & 0xF) << 4) | + (gap & 0xF); + uhs2_cmd.payload[0] = (__force __be32)payload0; + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_DEV_INIT_PAYLOAD_LEN, + UHS2_DEV_INIT_RESP_LEN); + + err = mmc_wait_for_cmd(host, &cmd, 0); + + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + continue; + } + + if (uhs2_cmd.uhs2_resp[3] != (UHS2_DEV_CMD_DEVICE_INIT & 0xFF)) { + pr_err("%s: DEVICE_INIT response is wrong!\n", + mmc_hostname(host)); + return -EIO; + } + + if (uhs2_cmd.uhs2_resp[5] & 0x8) { + host->uhs2_caps.group_desc = gd; + return 0; + } + resp_gap = uhs2_cmd.uhs2_resp[4] & 0x0F; + if (gap == resp_gap) + gd++; + } + + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + return 0; +} + +/* + * Run the enumeration process by sending the enumerate command to the card. + * Note that, we currently support only the point to point connection, which + * means only one card can be attached per host/slot. + */ +static int sd_uhs2_enum(struct mmc_host *host, u32 *node_id) +{ + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u32 payload0; + u8 id_f = 0xF, id_l = 0x0; + int err; + + /* + * Refer to UHS-II Addendum Version 1.02 Figure 6-28 to see ENUMERATE CCMD format. + * Header: + * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b). + * - IOADR = CMD_BASE + 003h + * Payload: + * - bit [3:0]: ID_L(Last Node ID) + * - bit [7:4]: ID_F(First Node ID) + */ + uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD; + uhs2_cmd.arg = ((UHS2_DEV_CMD_ENUMERATE & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_4B | + (UHS2_DEV_CMD_ENUMERATE >> 8); + + payload0 = (id_f << 4) | id_l; + uhs2_cmd.payload[0] = cpu_to_be32(payload0); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_DEV_ENUM_PAYLOAD_LEN, UHS2_DEV_ENUM_RESP_LEN); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + if (uhs2_cmd.uhs2_resp[3] != (UHS2_DEV_CMD_ENUMERATE & 0xFF)) { + pr_err("%s: ENUMERATE response is wrong!\n", + mmc_hostname(host)); + return -EIO; + } + + id_f = (uhs2_cmd.uhs2_resp[4] >> 4) & 0xF; + id_l = uhs2_cmd.uhs2_resp[4] & 0xF; + *node_id = id_f; + + return 0; +} + +/* + * Read the UHS-II configuration registers (CFG_REG) of the card, by sending it + * commands and by parsing the responses. Store a copy of the relevant data in + * card->uhs2_config. + */ +static int sd_uhs2_config_read(struct mmc_host *host, struct mmc_card *card) +{ + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u32 cap; + int err; + + /* + * Use Control Read CCMD to read Generic Capability from Configuration Register. + * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b). + * - IOADR = Generic Capability Register(CFG_BASE + 000h) + */ + uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | card->uhs2_config.node_id; + uhs2_cmd.arg = ((UHS2_DEV_CONFIG_GEN_CAPS & 0xFF) << 8) | + UHS2_NATIVE_CMD_READ | + UHS2_NATIVE_CMD_PLEN_4B | + (UHS2_DEV_CONFIG_GEN_CAPS >> 8); + + /* + * There is no payload because per spec, there should be + * no payload field for read CCMD. + * Plen is set in arg. Per spec, plen for read CCMD + * represents the len of read data which is assigned in payload + * of following RES (p136). + */ + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, 0, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + /* + * Generic Capability Register: + * bit [7:0] : Reserved + * bit [13:8] : Device-Specific Number of Lanes and Functionality + * bit 8: 2L-HD + * bit 9: 2D-1U FD + * bit 10: 1D-2U FD + * bit 11: 2D-2U FD + * Others: Reserved + * bit [14] : DADR Length + * 0: 4 bytes + * 1: Reserved + * bit [23:16]: Application Type + * bit 16: 0=Non-SD memory, 1=SD memory + * bit 17: 0=Non-SDIO, 1=SDIO + * bit 18: 0=Card, 1=Embedded + * bit [63:24]: Reserved + */ + cap = cmd.resp[0]; + card->uhs2_config.n_lanes = + (cap >> UHS2_DEV_CONFIG_N_LANES_POS) & + UHS2_DEV_CONFIG_N_LANES_MASK; + card->uhs2_config.dadr_len = + (cap >> UHS2_DEV_CONFIG_DADR_POS) & + UHS2_DEV_CONFIG_DADR_MASK; + card->uhs2_config.app_type = + (cap >> UHS2_DEV_CONFIG_APP_POS) & + UHS2_DEV_CONFIG_APP_MASK; + + /* + * Use Control Read CCMD to read PHY Capability from Configuration Register. + * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b). + * - IOADR = PHY Capability Register(CFG_BASE + 002h) + */ + uhs2_cmd.arg = ((UHS2_DEV_CONFIG_PHY_CAPS & 0xFF) << 8) | + UHS2_NATIVE_CMD_READ | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_PHY_CAPS >> 8); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, 0, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + /* + * PHY Capability Register: + * bit [3:0] : PHY Minor Revision + * bit [5:4] : PHY Major Revision + * bit [15] : Support Hibernate Mode + * 0: Not support Hibernate Mode + * 1: Support Hibernate Mode + * bit [31:16]: Reserved + * bit [35:32]: Device-Specific N_LSS_SYN + * bit [39:36]: Device-Specific N_LSS_DIR + * bit [63:40]: Reserved + */ + cap = cmd.resp[0]; + card->uhs2_config.phy_minor_rev = + cap & UHS2_DEV_CONFIG_PHY_MINOR_MASK; + card->uhs2_config.phy_major_rev = + (cap >> UHS2_DEV_CONFIG_PHY_MAJOR_POS) & + UHS2_DEV_CONFIG_PHY_MAJOR_MASK; + card->uhs2_config.can_hibernate = + (cap >> UHS2_DEV_CONFIG_CAN_HIBER_POS) & + UHS2_DEV_CONFIG_CAN_HIBER_MASK; + + cap = cmd.resp[1]; + card->uhs2_config.n_lss_sync = + cap & UHS2_DEV_CONFIG_N_LSS_SYN_MASK; + card->uhs2_config.n_lss_dir = + (cap >> UHS2_DEV_CONFIG_N_LSS_DIR_POS) & + UHS2_DEV_CONFIG_N_LSS_DIR_MASK; + if (card->uhs2_config.n_lss_sync == 0) + card->uhs2_config.n_lss_sync = 16 << 2; + else + card->uhs2_config.n_lss_sync <<= 2; + + if (card->uhs2_config.n_lss_dir == 0) + card->uhs2_config.n_lss_dir = 16 << 3; + else + card->uhs2_config.n_lss_dir <<= 3; + + /* + * Use Control Read CCMD to read LINK/TRAN Capability from Configuration Register. + * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b). + * - IOADR = LINK/TRAN Capability Register(CFG_BASE + 004h) + */ + uhs2_cmd.arg = ((UHS2_DEV_CONFIG_LINK_TRAN_CAPS & 0xFF) << 8) | + UHS2_NATIVE_CMD_READ | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_LINK_TRAN_CAPS >> 8); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, 0, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + /* + * LINK/TRAN Capability Register: + * bit [3:0] : LINK_TRAN Minor Revision + * bit [5:4] : LINK/TRAN Major Revision + * bit [7:6] : Reserved + * bit [15:8] : Device-Specific N_FCU + * bit [18:16]: Device Type + * 001b=Host + * 010b=Device + * 011b=Reserved for CMD issuable Device + * bit [19] : Reserved + * bit [31:20]: Device-Specific MAX_BLKLEN + * bit [39:32]: Device-Specific N_DATA_GAP + * bit [63:40]: Reserved + */ + cap = cmd.resp[0]; + card->uhs2_config.link_minor_rev = + cap & UHS2_DEV_CONFIG_LT_MINOR_MASK; + card->uhs2_config.link_major_rev = + (cap >> UHS2_DEV_CONFIG_LT_MAJOR_POS) & + UHS2_DEV_CONFIG_LT_MAJOR_MASK; + card->uhs2_config.n_fcu = + (cap >> UHS2_DEV_CONFIG_N_FCU_POS) & + UHS2_DEV_CONFIG_N_FCU_MASK; + card->uhs2_config.dev_type = + (cap >> UHS2_DEV_CONFIG_DEV_TYPE_POS) & + UHS2_DEV_CONFIG_DEV_TYPE_MASK; + card->uhs2_config.maxblk_len = + (cap >> UHS2_DEV_CONFIG_MAX_BLK_LEN_POS) & + UHS2_DEV_CONFIG_MAX_BLK_LEN_MASK; + + cap = cmd.resp[1]; + card->uhs2_config.n_data_gap = + cap & UHS2_DEV_CONFIG_N_DATA_GAP_MASK; + if (card->uhs2_config.n_fcu == 0) + card->uhs2_config.n_fcu = 256; + + return 0; +} + +/* + * Based on the card's and host's UHS-II capabilities, let's update the + * configuration of the card and the host. This may also include to move to a + * greater speed range/mode. Depending on the updated configuration, we may need + * to do a soft reset of the card via sending it a GO_DORMANT_STATE command. + * + * In the final step, let's check if the card signals "config completion", which + * indicates that the card has moved from config state into active state. + */ +static int sd_uhs2_config_write(struct mmc_host *host, struct mmc_card *card) +{ + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + u32 payload0, payload1; + u8 nMinDataGap; + int err; + + /* + * Use Control Write CCMD to set Generic Setting in Configuration Register. + * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b). + * - IOADR = Generic Setting Register(CFG_BASE + 008h) + * - Payload = New contents to be written to Generic Setting Register + */ + uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | card->uhs2_config.node_id; + uhs2_cmd.arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_GEN_SET >> 8); + + /* + * Most UHS-II cards only support FD and 2L-HD mode. Other lane numbers + * defined in UHS-II addendem Ver1.01 are optional. + */ + host->uhs2_caps.n_lanes_set = UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD; + card->uhs2_config.n_lanes_set = UHS2_DEV_CONFIG_GEN_SET_2L_FD_HD; + + payload0 = card->uhs2_config.n_lanes_set << UHS2_DEV_CONFIG_N_LANES_POS; + payload1 = 0; + uhs2_cmd.payload[0] = cpu_to_be32(payload0); + uhs2_cmd.payload[1] = cpu_to_be32(payload1); + + /* + * There is no payload because per spec, there should be + * no payload field for read CCMD. + * Plen is set in arg. Per spec, plen for read CCMD + * represents the len of read data which is assigned in payload + * of following RES (p136). + */ + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_CFG_WRITE_PAYLOAD_LEN, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + /* + * Use Control Write CCMD to set PHY Setting in Configuration Register. + * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b). + * - IOADR = PHY Setting Register(CFG_BASE + 00Ah) + * - Payload = New contents to be written to PHY Setting Register + */ + uhs2_cmd.arg = ((UHS2_DEV_CONFIG_PHY_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_PHY_SET >> 8); + + if (host->uhs2_caps.speed_range == UHS2_DEV_CONFIG_PHY_SET_SPEED_B) { + if (card->uhs2_config.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD && + host->uhs2_caps.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD) { + /* Support HD */ + host->ios.timing = MMC_TIMING_UHS2_SPEED_B_HD; + nMinDataGap = 1; + } else { + /* Only support 2L-FD so far */ + host->ios.timing = MMC_TIMING_UHS2_SPEED_B; + nMinDataGap = 3; + } + card->uhs2_config.speed_range_set = UHS2_DEV_CONFIG_PHY_SET_SPEED_B; + } else { + if (card->uhs2_config.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD && + host->uhs2_caps.n_lanes == UHS2_DEV_CONFIG_2L_HD_FD) { + /* Support HD */ + host->ios.timing = MMC_TIMING_UHS2_SPEED_A_HD; + nMinDataGap = 1; + } else { + /* Only support 2L-FD so far */ + host->ios.timing = MMC_TIMING_UHS2_SPEED_A; + nMinDataGap = 3; + } + card->uhs2_config.speed_range_set = UHS2_DEV_CONFIG_PHY_SET_SPEED_A; + } + + payload0 = card->uhs2_config.speed_range_set << UHS2_DEV_CONFIG_PHY_SET_SPEED_POS; + + card->uhs2_config.n_lss_sync_set = (max(card->uhs2_config.n_lss_sync, + host->uhs2_caps.n_lss_sync) >> 2) & + UHS2_DEV_CONFIG_N_LSS_SYN_MASK; + host->uhs2_caps.n_lss_sync_set = card->uhs2_config.n_lss_sync_set; + + card->uhs2_config.n_lss_dir_set = (max(card->uhs2_config.n_lss_dir, + host->uhs2_caps.n_lss_dir) >> 3) & + UHS2_DEV_CONFIG_N_LSS_DIR_MASK; + host->uhs2_caps.n_lss_dir_set = card->uhs2_config.n_lss_dir_set; + + payload1 = (card->uhs2_config.n_lss_dir_set << UHS2_DEV_CONFIG_N_LSS_DIR_POS) | + card->uhs2_config.n_lss_sync_set; + uhs2_cmd.payload[0] = cpu_to_be32(payload0); + uhs2_cmd.payload[1] = cpu_to_be32(payload1); + + memset(uhs2_cmd.uhs2_resp, 0, sizeof(uhs2_cmd.uhs2_resp)); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_CFG_WRITE_PAYLOAD_LEN, + UHS2_CFG_WRITE_PHY_SET_RESP_LEN); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + if ((uhs2_cmd.uhs2_resp[2] & 0x80)) { + pr_err("%s: %s: UHS2 CMD not accepted, resp= 0x%x!\n", + mmc_hostname(host), __func__, uhs2_cmd.uhs2_resp[2]); + return -EIO; + } + + /* + * Use Control Write CCMD to set LINK/TRAN Setting in Configuration Register. + * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b). + * - IOADR = LINK/TRAN Setting Register(CFG_BASE + 00Ch) + * - Payload = New contents to be written to LINK/TRAN Setting Register + */ + uhs2_cmd.arg = ((UHS2_DEV_CONFIG_LINK_TRAN_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_LINK_TRAN_SET >> 8); + + if (card->uhs2_config.app_type == UHS2_DEV_CONFIG_APP_SD_MEM) + card->uhs2_config.maxblk_len_set = UHS2_DEV_CONFIG_LT_SET_MAX_BLK_LEN; + else + card->uhs2_config.maxblk_len_set = min(card->uhs2_config.maxblk_len, + host->uhs2_caps.maxblk_len); + host->uhs2_caps.maxblk_len_set = card->uhs2_config.maxblk_len_set; + + card->uhs2_config.n_fcu_set = min(card->uhs2_config.n_fcu, host->uhs2_caps.n_fcu); + host->uhs2_caps.n_fcu_set = card->uhs2_config.n_fcu_set; + + card->uhs2_config.n_data_gap_set = max(nMinDataGap, card->uhs2_config.n_data_gap); + host->uhs2_caps.n_data_gap_set = card->uhs2_config.n_data_gap_set; + + host->uhs2_caps.max_retry_set = 3; + card->uhs2_config.max_retry_set = host->uhs2_caps.max_retry_set; + + payload0 = (card->uhs2_config.maxblk_len_set << UHS2_DEV_CONFIG_MAX_BLK_LEN_POS) | + (card->uhs2_config.max_retry_set << UHS2_DEV_CONFIG_LT_SET_MAX_RETRY_POS) | + (card->uhs2_config.n_fcu_set << UHS2_DEV_CONFIG_N_FCU_POS); + payload1 = card->uhs2_config.n_data_gap_set; + uhs2_cmd.payload[0] = cpu_to_be32(payload0); + uhs2_cmd.payload[1] = cpu_to_be32(payload1); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_CFG_WRITE_PAYLOAD_LEN, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + /* + * Use Control Write CCMD to set Config Completion(payload bit 63) in Generic Setting + * Register. + * Header: + * - Control Write(R/W=1) with 8-Byte payload(PLEN=10b). + * - IOADR = PGeneric Setting Register(CFG_BASE + 008h) + * Payload: + * - bit [63]: Config Completion + * + * DLSM transits to Active state immediately when Config Completion is set to 1. + */ + uhs2_cmd.arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_GEN_SET >> 8); + + payload0 = 0; + payload1 = UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE; + uhs2_cmd.payload[0] = cpu_to_be32(payload0); + uhs2_cmd.payload[1] = cpu_to_be32(payload1); + + memset(uhs2_cmd.uhs2_resp, 0, sizeof(uhs2_cmd.uhs2_resp)); + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_CFG_WRITE_PAYLOAD_LEN, + UHS2_CFG_WRITE_GENERIC_SET_RESP_LEN); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + /* Set host Config Setting registers */ + err = host->ops->uhs2_control(host, UHS2_SET_CONFIG); + if (err) { + pr_err("%s: %s: UHS2 SET_CONFIG fail!\n", mmc_hostname(host), __func__); + return err; + } + + return 0; +} + +static int sd_uhs2_go_dormant(struct mmc_host *host, u32 node_id) +{ + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + int err; + + /* Disable Normal INT */ + err = host->ops->uhs2_control(host, UHS2_DISABLE_INT); + if (err) { + pr_err("%s: %s: UHS2 DISABLE_INT fail!\n", + mmc_hostname(host), __func__); + return err; + } + + /* + * Refer to UHS-II Addendum Version 1.02 Figure 6-17 to see GO_DORMANT_STATE CCMD format. + * Header: + * - Control Write(R/W=1) with 4-Byte payload(PLEN=01b). + * - IOADR = CMD_BASE + 001h + * Payload: + * - bit [7]: HBR(Entry to Hibernate Mode) + * 1: Host intends to enter Hibernate mode during Dormant state. + * The default setting is 0 because hibernate is currently not supported. + */ + uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | node_id; + uhs2_cmd.arg = ((UHS2_DEV_CMD_GO_DORMANT_STATE & 0xFF) << 8) | + UHS2_NATIVE_CMD_WRITE | + UHS2_NATIVE_CMD_PLEN_4B | + (UHS2_DEV_CMD_GO_DORMANT_STATE >> 8); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, UHS2_GO_DORMANT_PAYLOAD_LEN, 0); + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) { + pr_err("%s: %s: UHS2 CMD send fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + /* Check Dormant State in Present */ + err = host->ops->uhs2_control(host, UHS2_CHECK_DORMANT); + if (err) + return err; + + /* Disable UHS2 card clock */ + err = host->ops->uhs2_control(host, UHS2_DISABLE_CLK); + if (err) + return err; + + /* Restore sd clock */ + mmc_delay(5); + err = host->ops->uhs2_control(host, UHS2_ENABLE_CLK); + if (err) + return err; + + /* Enable Normal INT */ + err = host->ops->uhs2_control(host, UHS2_ENABLE_INT); + if (err) + return err; + + /* Detect UHS2 */ + err = host->ops->uhs2_control(host, UHS2_PHY_INIT); + if (err) + return err; + + return 0; +} + +static int sd_uhs2_wait_active_state_cb(void *cb_data, bool *busy) +{ + struct sd_uhs2_wait_active_state_data *data = cb_data; + struct mmc_host *host = data->host; + struct mmc_command *cmd = data->cmd; + int err; + + err = mmc_wait_for_cmd(host, cmd, 0); + if (err) + return err; + + if (cmd->resp[1] & UHS2_DEV_CONFIG_GEN_SET_CFG_COMPLETE) + *busy = false; + else + *busy = true; + + return 0; +} + +static int sd_uhs2_go_dormant_state(struct mmc_host *host, u32 node_id) +{ + struct mmc_command cmd = {0}; + struct uhs2_command uhs2_cmd = {}; + int err; + struct sd_uhs2_wait_active_state_data cb_data = { + .host = host, + .cmd = &cmd + }; + + err = sd_uhs2_go_dormant(host, node_id); + if (err) { + pr_err("%s: %s: UHS2 GO_DORMANT_STATE fail, err= 0x%x!\n", + mmc_hostname(host), __func__, err); + return err; + } + + /* + * Use Control Read CCMD to check Config Completion(bit 63) in Generic Setting Register. + * - Control Read(R/W=0) with 8-Byte payload(PLEN=10b). + * - IOADR = Generic Setting Register(CFG_BASE + 008h) + * + * When UHS-II card been switched to new speed mode, it will set Config Completion to 1. + */ + uhs2_cmd.header = UHS2_NATIVE_PACKET | UHS2_PACKET_TYPE_CCMD | node_id; + uhs2_cmd.arg = ((UHS2_DEV_CONFIG_GEN_SET & 0xFF) << 8) | + UHS2_NATIVE_CMD_READ | + UHS2_NATIVE_CMD_PLEN_8B | + (UHS2_DEV_CONFIG_GEN_SET >> 8); + + sd_uhs2_cmd_assemble(&cmd, &uhs2_cmd, 0, 0); + err = __mmc_poll_for_busy(host, UHS2_WAIT_CFG_COMPLETE_PERIOD_US, + UHS2_WAIT_CFG_COMPLETE_TIMEOUT_MS, + &sd_uhs2_wait_active_state_cb, &cb_data); + if (err) { + pr_err("%s: %s: Not switch to Active in 100 ms\n", mmc_hostname(host), __func__); + return err; + } + + return 0; +} + +/* + * Allocate the data structure for the mmc_card and run the UHS-II specific + * initialization sequence. + */ +static int sd_uhs2_init_card(struct mmc_host *host, struct mmc_card *oldcard) +{ + struct mmc_card *card; + u32 node_id = 0; + int err; + + err = sd_uhs2_dev_init(host); + if (err) + return err; + + err = sd_uhs2_enum(host, &node_id); + if (err) + return err; + + if (oldcard) { + card = oldcard; + } else { + card = mmc_alloc_card(host, &sd_type); + if (IS_ERR(card)) + return PTR_ERR(card); + } + + card->uhs2_config.node_id = node_id; + card->type = MMC_TYPE_SD; + + err = sd_uhs2_config_read(host, card); + if (err) + goto err; + + err = sd_uhs2_config_write(host, card); + if (err) + goto err; + + /* If change speed to Range B, need to GO_DORMANT_STATE */ + if (host->ios.timing == MMC_TIMING_UHS2_SPEED_B || + host->ios.timing == MMC_TIMING_UHS2_SPEED_B_HD) { + err = sd_uhs2_go_dormant_state(host, node_id); + if (err) + goto err; + } + + host->uhs2_sd_tran = true; + host->card = card; + return 0; + +err: + if (!oldcard) + mmc_remove_card(card); + return err; +} + +/* + * Initialize the UHS-II card through the SD-TRAN transport layer. This enables + * commands/requests to be backwards compatible through the legacy SD protocol. + * UHS-II cards has a specific power limit specified for VDD1/VDD2, that should + * be set through a legacy CMD6. Note that, the power limit that becomes set, + * survives a soft reset through the GO_DORMANT_STATE command. + */ +static int sd_uhs2_legacy_init(struct mmc_host *host, struct mmc_card *card, + bool reinit) +{ + int err; + u32 cid[4]; + u32 ocr; + u32 rocr; + u8 *status; + int ro; + + /* Send CMD0 to reset SD card */ + err = __mmc_go_idle(host); + if (err) + return err; + + mmc_delay(1); + + /* Send CMD8 to communicate SD interface operation condition */ + err = mmc_send_if_cond(host, host->ocr_avail); + if (err) + return err; + + /* + * Probe SD card working voltage. + */ + err = mmc_send_app_op_cond(host, 0, &ocr); + if (err) + return err; + + card->ocr = ocr; + + /* + * Some SD cards claims an out of spec VDD voltage range. Let's treat + * these bits as being in-valid and especially also bit7. + */ + ocr &= ~0x7FFF; + rocr = mmc_select_voltage(host, ocr); + /* + * Some cards have zero value of rocr in UHS-II mode. Assign host's + * ocr value to rocr. + */ + if (!rocr) + rocr = host->ocr_avail; + + rocr |= (SD_OCR_CCS | SD_OCR_XPC); + + /* Wait SD power on ready */ + ocr = rocr; + + err = mmc_send_app_op_cond(host, ocr, &rocr); + if (err) + return err; + + err = mmc_send_cid(host, cid); + if (err) + return err; + + if (reinit) { + if (memcmp(cid, card->raw_cid, sizeof(cid)) != 0) { + pr_debug("%s: Perhaps the card was replaced\n", + mmc_hostname(host)); + return -ENOENT; + } + } else { + memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); + mmc_decode_cid(card); + } + + /* + * For native busses: get card RCA and quit open drain mode. + */ + err = mmc_send_relative_addr(host, &card->rca); + if (err) + return err; + + err = mmc_sd_get_csd(card, false); + if (err) + return err; + + /* + * Select card, as all following commands rely on that. + */ + err = mmc_select_card(card); + if (err) + return err; + + /* + * Fetch SCR from card. + */ + err = mmc_app_send_scr(card); + if (err) + return err; + + err = mmc_decode_scr(card); + if (err) + return err; + + /* + * Switch to high power consumption mode. + * Even switch failed, sd card can still work at lower power consumption mode, but + * performance will be lower than high power consumption mode. + */ + status = kmalloc(64, GFP_KERNEL); + if (!status) + return -ENOMEM; + + if (!(card->csd.cmdclass & CCC_SWITCH)) { + pr_warn("%s: card lacks mandatory switch function, performance might suffer\n", + mmc_hostname(card->host)); + } else { + /* + * Send CMD6 to set Maximum Power Consumption to get better + * performance. Ignore errors and continue. + */ + err = mmc_sd_switch(card, 0, 3, SD4_SET_POWER_LIMIT_1_80W, status); + if (!err) + mmc_sd_switch(card, 1, 3, SD4_SET_POWER_LIMIT_1_80W, status); + } + + /* + * Check if read-only switch is active. + */ + ro = mmc_sd_get_ro(host); + if (ro < 0) + pr_warn("%s: host does not support read-only switch, assuming write-enable\n", + mmc_hostname(host)); + else if (ro > 0) + mmc_card_set_readonly(card); + + kfree(status); + return 0; +} + +static int sd_uhs2_reinit(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + int err; + + err = sd_uhs2_power_up(host); + if (err) + return err; + + err = sd_uhs2_phy_init(host); + if (err) + return err; + + err = sd_uhs2_init_card(host, card); + if (err) + return err; + + return sd_uhs2_legacy_init(host, card, true); +} + +static void sd_uhs2_remove(struct mmc_host *host) +{ + mmc_remove_card(host->card); + host->card = NULL; +} + +static int sd_uhs2_alive(struct mmc_host *host) +{ + return mmc_send_status(host->card, NULL); +} + +static void sd_uhs2_detect(struct mmc_host *host) +{ + int err; + + mmc_get_card(host->card, NULL); + err = _mmc_detect_card_removed(host); + mmc_put_card(host->card, NULL); + + if (err) { + sd_uhs2_remove(host); + + mmc_claim_host(host); + mmc_detach_bus(host); + sd_uhs2_power_off(host); + mmc_release_host(host); + } +} + +static int _sd_uhs2_suspend(struct mmc_host *host) +{ + struct mmc_card *card = host->card; + + mmc_claim_host(host); + + if (mmc_card_suspended(card)) + goto out; + + sd_uhs2_power_off(host); + mmc_card_set_suspended(card); + +out: + mmc_release_host(host); + return 0; +} + +/* + * Callback for suspend + */ +static int sd_uhs2_suspend(struct mmc_host *host) +{ + int err; + + err = _sd_uhs2_suspend(host); + if (!err) { + pm_runtime_disable(&host->card->dev); + pm_runtime_set_suspended(&host->card->dev); + } + + return err; +} + +/* + * This function tries to determine if the same card is still present + * and, if so, restore all state to it. + */ +static int _mmc_sd_uhs2_resume(struct mmc_host *host) +{ + int err = 0; + + mmc_claim_host(host); + + if (!mmc_card_suspended(host->card)) + goto out; + + /* Power up UHS2 SD card and re-initialize it. */ + err = sd_uhs2_reinit(host); + mmc_card_clr_suspended(host->card); + +out: + mmc_release_host(host); + return err; +} + +/* + * Callback for resume + */ +static int sd_uhs2_resume(struct mmc_host *host) +{ + pm_runtime_enable(&host->card->dev); + return 0; +} + +/* + * Callback for runtime_suspend. + */ +static int sd_uhs2_runtime_suspend(struct mmc_host *host) +{ + int err; + + if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) + return 0; + + err = _sd_uhs2_suspend(host); + if (err) + pr_err("%s: error %d doing aggressive suspend\n", mmc_hostname(host), err); + + return err; +} + +static int sd_uhs2_runtime_resume(struct mmc_host *host) +{ + int err; + + err = _mmc_sd_uhs2_resume(host); + if (err && err != -ENOMEDIUM) + pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err); + + return err; +} + +static int sd_uhs2_hw_reset(struct mmc_host *host) +{ + sd_uhs2_power_off(host); + /* Wait at least 1 ms according to SD spec */ + mmc_delay(1); + + return sd_uhs2_reinit(host); +} + +static const struct mmc_bus_ops sd_uhs2_ops = { + .remove = sd_uhs2_remove, + .alive = sd_uhs2_alive, + .detect = sd_uhs2_detect, + .suspend = sd_uhs2_suspend, + .resume = sd_uhs2_resume, + .runtime_suspend = sd_uhs2_runtime_suspend, + .runtime_resume = sd_uhs2_runtime_resume, + .shutdown = sd_uhs2_suspend, + .hw_reset = sd_uhs2_hw_reset, +}; + +static int sd_uhs2_attach(struct mmc_host *host) +{ + int err; + + err = sd_uhs2_power_up(host); + if (err) + goto err; + + err = sd_uhs2_phy_init(host); + if (err) + goto err; + + err = sd_uhs2_init_card(host, NULL); + if (err) + goto err; + + err = sd_uhs2_legacy_init(host, host->card, false); + if (err) + goto remove_card; + + mmc_attach_bus(host, &sd_uhs2_ops); + + mmc_release_host(host); + + err = mmc_add_card(host->card); + if (err) + goto remove_card; + + mmc_claim_host(host); + return 0; + +remove_card: + sd_uhs2_remove(host); + mmc_claim_host(host); +err: + mmc_detach_bus(host); + sd_uhs2_power_off(host); + return err; +} + +/** + * mmc_attach_sd_uhs2 - select UHS2 interface + * @host: MMC host + * + * Try to select UHS2 interface and initialize the bus for a given + * frequency, @freq. + * + * Return: 0 on success, non-zero error on failure + */ +int mmc_attach_sd_uhs2(struct mmc_host *host) +{ + int i, err; + + if (!(host->caps2 & MMC_CAP2_SD_UHS2)) + return -EOPNOTSUPP; + + /* Turn off the legacy SD interface before trying with UHS-II. */ + mmc_power_off(host); + + /* + * Start UHS-II initialization at 52MHz and possibly make a retry at + * 26MHz according to the spec. It's required that the host driver + * validates ios->clock, to set a rate within the correct range. + */ + for (i = 0; i < ARRAY_SIZE(sd_uhs2_freqs); i++) { + host->f_init = sd_uhs2_freqs[i]; + pr_debug("%s: %s: trying to init UHS-II card at %u Hz\n", + mmc_hostname(host), __func__, host->f_init); + err = sd_uhs2_attach(host); + if (!err) + break; + } + + return err; +} + +/* + * mmc_uhs2_prepare_cmd - prepare for SD command packet + * @host: MMC host + * @mrq: MMC request + * + * Initialize and fill in a header and a payload of SD command packet. + * The caller should allocate uhs2_command in host->cmd->uhs2_cmd in + * advance. + * + * Return: 0 on success, non-zero error on failure + */ +void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq) +{ + struct mmc_command *cmd; + struct uhs2_command *uhs2_cmd; + u8 plen; + + cmd = mrq->cmd; + cmd->uhs2_cmd = &mrq->uhs2_cmd; + uhs2_cmd = cmd->uhs2_cmd; + uhs2_cmd->header = host->card->uhs2_config.node_id; + if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) + uhs2_cmd->header |= UHS2_PACKET_TYPE_DCMD; + else + uhs2_cmd->header |= UHS2_PACKET_TYPE_CCMD; + + uhs2_cmd->arg = cmd->opcode << UHS2_SD_CMD_INDEX_POS; + if (host->uhs2_app_cmd) { + uhs2_cmd->arg |= UHS2_SD_CMD_APP; + host->uhs2_app_cmd = false; + } + + /* + * UHS-II Addendum 7.2.1.2 + * Host may set DM to 1 for DCMD which supports multi-block read/write regardless of + * data transfer length (e.g., CMD18, CMD25). Otherwise, it shall not set DM to 1. + * (e.g., CMD6, CMD17, CMD24). These rules are also applied to other multi-block read/write + * commands defined in other Part of SD specifications (for example, Host may set DM to 1 + * for ACMD18 or ACMD25). + */ + if (mmc_op_multi(cmd->opcode)) + cmd->uhs2_cmd->tmode_half_duplex = mmc_card_uhs2_hd_mode(host); + else + cmd->uhs2_cmd->tmode_half_duplex = 0; + + uhs2_cmd = cmd->uhs2_cmd; + plen = 2; /* at the maximum */ + + if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC && + cmd->uhs2_cmd->tmode_half_duplex) { + if (mmc_card_uhs2_hd_mode(host)) + uhs2_cmd->arg |= UHS2_DCMD_2L_HD_MODE; + + uhs2_cmd->arg |= UHS2_DCMD_LM_TLEN_EXIST; + + if (cmd->data->blocks == 1 && + cmd->data->blksz != 512 && + cmd->opcode != MMC_READ_SINGLE_BLOCK && + cmd->opcode != MMC_WRITE_BLOCK) { + uhs2_cmd->arg |= UHS2_DCMD_TLUM_BYTE_MODE; + uhs2_cmd->payload[1] = cpu_to_be32(cmd->data->blksz); + } else { + uhs2_cmd->payload[1] = cpu_to_be32(cmd->data->blocks); + } + } else { + plen = 1; + } + + uhs2_cmd->payload[0] = cpu_to_be32(cmd->arg); + sd_uhs2_cmd_assemble(cmd, uhs2_cmd, plen, 0); +} diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 4fb247fde5c080..9566837c9848e6 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -769,7 +769,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, * Read CSD, before selecting the card */ if (!oldcard && mmc_card_sd_combo(card)) { - err = mmc_sd_get_csd(card); + err = mmc_sd_get_csd(card, false); if (err) goto remove; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 7199cb0bd0b9e7..6824131b69b188 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -98,10 +98,20 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER This is the case for the Nintendo Wii SDHCI. +config MMC_SDHCI_UHS2 + tristate "UHS2 support on SDHCI controller" if COMPILE_TEST + depends on MMC_SDHCI + help + This option is selected by SDHCI controller drivers that want to + support UHS2-capable devices. + + If you have a controller with this feature, say Y or M here. + config MMC_SDHCI_PCI tristate "SDHCI support on PCI bus" depends on MMC_SDHCI && PCI select MMC_CQHCI + select MMC_SDHCI_UHS2 select IOSF_MBI if X86 select MMC_SDHCI_IO_ACCESSORS help @@ -1009,6 +1019,7 @@ config MMC_MTK depends on COMMON_CLK select REGULATOR select MMC_CQHCI + select MMC_HSQ help This selects the MediaTek(R) Secure digital and Multimedia card Interface. If you have a machine with a integrated SD/MMC card reader, say Y or M here. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 3ccffebbe59b91..5147467ec825ff 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o +obj-$(CONFIG_MMC_SDHCI_UHS2) += sdhci-uhs2.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ sdhci-pci-dwc-mshc.o sdhci-pci-gli.o diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c index 42aa43740ba86d..b6b6dd677ae5b8 100644 --- a/drivers/mmc/host/alcor.c +++ b/drivers/mmc/host/alcor.c @@ -1175,7 +1175,7 @@ MODULE_DEVICE_TABLE(platform, alcor_pci_sdmmc_ids); static struct platform_driver alcor_pci_sdmmc_driver = { .probe = alcor_pci_sdmmc_drv_probe, - .remove_new = alcor_pci_sdmmc_drv_remove, + .remove = alcor_pci_sdmmc_drv_remove, .id_table = alcor_pci_sdmmc_ids, .driver = { .name = DRV_NAME_ALCOR_PCI_SDMMC, diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index cdbd2edf4b2e7c..fc360902729db7 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -860,7 +860,7 @@ static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data) } /* - * Configure given PDC buffer taking care of alignement issues. + * Configure given PDC buffer taking care of alignment issues. * Update host->data_size and host->sg. */ static void atmci_pdc_set_single_buf(struct atmel_mci *host, @@ -2653,7 +2653,7 @@ static const struct dev_pm_ops atmci_dev_pm_ops = { static struct platform_driver atmci_driver = { .probe = atmci_probe, - .remove_new = atmci_remove, + .remove = atmci_remove, .driver = { .name = "atmel_mci", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 6e80bcb668ecc4..057d42307832c8 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -543,7 +543,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status) cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24; } } else { - /* Techincally, we should be getting all 48 bits of + /* Technically, we should be getting all 48 bits of * the response (SD_RESP1 + SD_RESP2), but because * our response omits the CRC, our data ends up * being shifted 8 bits to the right. In this case, @@ -1185,7 +1185,7 @@ static int au1xmmc_resume(struct platform_device *pdev) static struct platform_driver au1xmmc_driver = { .probe = au1xmmc_probe, - .remove_new = au1xmmc_remove, + .remove = au1xmmc_remove, .suspend = au1xmmc_suspend, .resume = au1xmmc_resume, .driver = { diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 35d8fdea668b91..7847f0c8b4652a 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -148,9 +148,10 @@ struct bcm2835_host { void __iomem *ioaddr; u32 phys_addr; + struct clk *clk; struct platform_device *pdev; - int clock; /* Current clock speed */ + unsigned int clock; /* Current clock speed */ unsigned int max_clk; /* Max possible freq */ struct work_struct dma_work; struct delayed_work timeout_work; /* Timer for timeouts */ @@ -1345,7 +1346,6 @@ static int bcm2835_add_host(struct bcm2835_host *host) static int bcm2835_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct clk *clk; struct bcm2835_host *host; struct mmc_host *mmc; const __be32 *regaddr_p; @@ -1393,15 +1393,6 @@ static int bcm2835_probe(struct platform_device *pdev) /* Ignore errors to fall back to PIO mode */ } - - clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) { - ret = dev_err_probe(dev, PTR_ERR(clk), "could not get clk\n"); - goto err; - } - - host->max_clk = clk_get_rate(clk); - host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) { ret = host->irq; @@ -1412,16 +1403,30 @@ static int bcm2835_probe(struct platform_device *pdev) if (ret) goto err; - ret = bcm2835_add_host(host); + host->clk = devm_clk_get(dev, NULL); + if (IS_ERR(host->clk)) { + ret = dev_err_probe(dev, PTR_ERR(host->clk), "could not get clk\n"); + goto err; + } + + ret = clk_prepare_enable(host->clk); if (ret) goto err; + host->max_clk = clk_get_rate(host->clk); + + ret = bcm2835_add_host(host); + if (ret) + goto err_clk; + platform_set_drvdata(pdev, host); dev_dbg(dev, "%s -> OK\n", __func__); return 0; +err_clk: + clk_disable_unprepare(host->clk); err: dev_dbg(dev, "%s -> err %d\n", __func__, ret); if (host->dma_chan_rxtx) @@ -1445,6 +1450,8 @@ static void bcm2835_remove(struct platform_device *pdev) cancel_work_sync(&host->dma_work); cancel_delayed_work_sync(&host->timeout_work); + clk_disable_unprepare(host->clk); + if (host->dma_chan_rxtx) dma_release_channel(host->dma_chan_rxtx); @@ -1459,7 +1466,7 @@ MODULE_DEVICE_TABLE(of, bcm2835_match); static struct platform_driver bcm2835_driver = { .probe = bcm2835_probe, - .remove_new = bcm2835_remove, + .remove = bcm2835_remove, .driver = { .name = "sdhost-bcm2835", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/cavium-octeon.c b/drivers/mmc/host/cavium-octeon.c index 060ec4f4800f62..0592f356b1e5af 100644 --- a/drivers/mmc/host/cavium-octeon.c +++ b/drivers/mmc/host/cavium-octeon.c @@ -217,7 +217,7 @@ static int octeon_mmc_probe(struct platform_device *pdev) return PTR_ERR(base); host->dma_base = base; /* - * To keep the register addresses shared we intentionaly use + * To keep the register addresses shared we intentionally use * a negative offset here, first register used on Octeon therefore * starts at 0x20 (MIO_EMM_DMA_CFG). */ @@ -326,7 +326,7 @@ MODULE_DEVICE_TABLE(of, octeon_mmc_match); static struct platform_driver octeon_mmc_driver = { .probe = octeon_mmc_probe, - .remove_new = octeon_mmc_remove, + .remove = octeon_mmc_remove, .driver = { .name = KBUILD_MODNAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index 902f7f20abaa77..d741c1f9cf8786 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -771,7 +771,7 @@ static void cb710_mmc_exit(struct platform_device *pdev) static struct platform_driver cb710_mmc_driver = { .driver.name = "cb710-mmc", .probe = cb710_mmc_init, - .remove_new = cb710_mmc_exit, + .remove = cb710_mmc_exit, #ifdef CONFIG_PM .suspend = cb710_mmc_suspend, .resume = cb710_mmc_resume, diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 9cbde800685d07..cde4c4339ab75a 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -7,24 +7,23 @@ * Copyright (C) 2009 David Brownell */ -#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 /* * Register Definitions @@ -1229,7 +1228,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) host->mmc_input_clk = clk_get_rate(host->clk); - pdev->id_entry = of_device_get_match_data(&pdev->dev); + pdev->id_entry = device_get_match_data(&pdev->dev); if (pdev->id_entry) { ret = mmc_of_parse(mmc); if (ret) { @@ -1400,7 +1399,7 @@ static struct platform_driver davinci_mmcsd_driver = { .of_match_table = davinci_mmc_dt_ids, }, .probe = davinci_mmcsd_probe, - .remove_new = davinci_mmcsd_remove, + .remove = davinci_mmcsd_remove, .id_table = davinci_mmc_devtype, }; diff --git a/drivers/mmc/host/dw_mmc-bluefield.c b/drivers/mmc/host/dw_mmc-bluefield.c index 24e0b604b4052f..3cf526ab0387bd 100644 --- a/drivers/mmc/host/dw_mmc-bluefield.c +++ b/drivers/mmc/host/dw_mmc-bluefield.c @@ -68,7 +68,7 @@ static int dw_mci_bluefield_probe(struct platform_device *pdev) static struct platform_driver dw_mci_bluefield_pltfm_driver = { .probe = dw_mci_bluefield_probe, - .remove_new = dw_mci_pltfm_remove, + .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_bluefield", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 6dc057718d2cb8..53d32d0f2709e0 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -682,7 +682,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = { static struct platform_driver dw_mci_exynos_pltfm_driver = { .probe = dw_mci_exynos_probe, - .remove_new = dw_mci_exynos_remove, + .remove = dw_mci_exynos_remove, .driver = { .name = "dwmmc_exynos", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/dw_mmc-hi3798cv200.c b/drivers/mmc/host/dw_mmc-hi3798cv200.c index 6099756e59b3c9..0ccfae1b2dbe63 100644 --- a/drivers/mmc/host/dw_mmc-hi3798cv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798cv200.c @@ -189,7 +189,7 @@ static const struct of_device_id dw_mci_hi3798cv200_match[] = { MODULE_DEVICE_TABLE(of, dw_mci_hi3798cv200_match); static struct platform_driver dw_mci_hi3798cv200_driver = { .probe = dw_mci_hi3798cv200_probe, - .remove_new = dw_mci_hi3798cv200_remove, + .remove = dw_mci_hi3798cv200_remove, .driver = { .name = "dwmmc_hi3798cv200", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/dw_mmc-hi3798mv200.c b/drivers/mmc/host/dw_mmc-hi3798mv200.c index 96af693e3e37ce..cce174b5249bb4 100644 --- a/drivers/mmc/host/dw_mmc-hi3798mv200.c +++ b/drivers/mmc/host/dw_mmc-hi3798mv200.c @@ -237,7 +237,7 @@ static void dw_mci_hi3798mv200_remove(struct platform_device *pdev) MODULE_DEVICE_TABLE(of, dw_mci_hi3798mv200_match); static struct platform_driver dw_mci_hi3798mv200_driver = { .probe = dw_mci_hi3798mv200_probe, - .remove_new = dw_mci_hi3798mv200_remove, + .remove = dw_mci_hi3798mv200_remove, .driver = { .name = "dwmmc_hi3798mv200", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index e8ee7c43f60b28..0311a37dd4abfa 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -470,7 +470,7 @@ static const struct dev_pm_ops dw_mci_k3_dev_pm_ops = { static struct platform_driver dw_mci_k3_pltfm_driver = { .probe = dw_mci_k3_probe, - .remove_new = dw_mci_pltfm_remove, + .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_k3", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 2353fadceda118..de820ffd21333e 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -131,7 +131,7 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove); static struct platform_driver dw_mci_pltfm_driver = { .probe = dw_mci_pltfm_probe, - .remove_new = dw_mci_pltfm_remove, + .remove = dw_mci_pltfm_remove, .driver = { .name = "dw_mmc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index f96260fd143b4c..baa23b51773127 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -577,7 +577,7 @@ static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = { static struct platform_driver dw_mci_rockchip_pltfm_driver = { .probe = dw_mci_rockchip_probe, - .remove_new = dw_mci_rockchip_remove, + .remove = dw_mci_rockchip_remove, .driver = { .name = "dwmmc_rockchip", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/dw_mmc-starfive.c b/drivers/mmc/host/dw_mmc-starfive.c index b4d81ef0f3af03..34964b0dab21f3 100644 --- a/drivers/mmc/host/dw_mmc-starfive.c +++ b/drivers/mmc/host/dw_mmc-starfive.c @@ -115,7 +115,7 @@ static int dw_mci_starfive_probe(struct platform_device *pdev) static struct platform_driver dw_mci_starfive_driver = { .probe = dw_mci_starfive_probe, - .remove_new = dw_mci_pltfm_remove, + .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_starfive", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index e9f6e4e622901a..3cbda98d08d287 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1182,7 +1182,7 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data) /* * Use the initial fifoth_val for PIO mode. If wm_algined * is set, we set watermark same as data size. - * If next issued data may be transfered by DMA mode, + * If next issued data may be transferred by DMA mode, * prev_blksz should be invalidated. */ if (host->wm_aligned) diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 6a45991ca056fe..596012d5afac8b 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1191,7 +1191,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend, static struct platform_driver jz4740_mmc_driver = { .probe = jz4740_mmc_probe, - .remove_new = jz4740_mmc_remove, + .remove = jz4740_mmc_remove, .driver = { .name = "jz4740-mmc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c index 4ec8072dc60b3d..b338ccfa8f3378 100644 --- a/drivers/mmc/host/litex_mmc.c +++ b/drivers/mmc/host/litex_mmc.c @@ -644,7 +644,7 @@ MODULE_DEVICE_TABLE(of, litex_match); static struct platform_driver litex_mmc_driver = { .probe = litex_mmc_probe, - .remove_new = litex_mmc_remove, + .remove = litex_mmc_remove, .driver = { .name = "litex-mmc", .of_match_table = litex_match, diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index c7c067b9415a41..694bb443d5f3fe 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -879,7 +879,7 @@ static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) /* * The memory at the end of the controller used as bounce buffer for * the dram_access_quirk only accepts 32bit read/write access, - * check the aligment and length of the data before starting the request. + * check the alignment and length of the data before starting the request. */ if (host->dram_access_quirk && mrq->data) { mrq->cmd->error = meson_mmc_validate_dram_access(mmc, mrq->data); @@ -1334,7 +1334,7 @@ MODULE_DEVICE_TABLE(of, meson_mmc_of_match); static struct platform_driver meson_mmc_driver = { .probe = meson_mmc_probe, - .remove_new = meson_mmc_remove, + .remove = meson_mmc_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c index 31f750301dc132..b4e56ccffca2c3 100644 --- a/drivers/mmc/host/meson-mx-sdhc-mmc.c +++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c @@ -904,7 +904,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_sdhc_of_match); static struct platform_driver meson_mx_sdhc_driver = { .probe = meson_mx_sdhc_probe, - .remove_new = meson_mx_sdhc_remove, + .remove = meson_mx_sdhc_remove, .driver = { .name = "meson-mx-sdhc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index a11577f2ee69bd..ad351805eed40a 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -754,7 +754,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_mmc_of_match); static struct platform_driver meson_mx_mmc_driver = { .probe = meson_mx_mmc_probe, - .remove_new = meson_mx_mmc_remove, + .remove = meson_mx_mmc_remove, .driver = { .name = "meson-mx-sdio", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 8fee7052f2ef4f..47443fb5eb3362 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -222,10 +222,6 @@ static int mmc_spi_response_get(struct mmc_spi_host *host, u8 leftover = 0; unsigned short rotator; int i; - char tag[32]; - - snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s", - cmd->opcode, maptype(cmd)); /* Except for data block reads, the whole response will already * be stored in the scratch buffer. It's somewhere after the @@ -378,8 +374,9 @@ static int mmc_spi_response_get(struct mmc_spi_host *host, } if (value < 0) - dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n", - tag, cmd->resp[0], cmd->resp[1]); + dev_dbg(&host->spi->dev, + " ... CMD%d response SPI_%s: resp %04x %08x\n", + cmd->opcode, maptype(cmd), cmd->resp[0], cmd->resp[1]); /* disable chipselect on errors and some success cases */ if (value >= 0 && cs_on) diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index a5eb4ced4d5d2e..4d3647f9ec0679 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -77,7 +77,7 @@ #define MCI_CPSM_INTERRUPT BIT(8) #define MCI_CPSM_PENDING BIT(9) #define MCI_CPSM_ENABLE BIT(10) -/* Command register flag extenstions in the ST Micro versions */ +/* Command register flag extensions in the ST Micro versions */ #define MCI_CPSM_ST_SDIO_SUSP BIT(11) #define MCI_CPSM_ST_ENCMD_COMPL BIT(12) #define MCI_CPSM_ST_NIEN BIT(13) diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index 8ede4ce9327149..a12048e5de63a6 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -719,7 +719,7 @@ MODULE_DEVICE_TABLE(of, moxart_mmc_match); static struct platform_driver moxart_mmc_driver = { .probe = moxart_probe, - .remove_new = moxart_remove, + .remove = moxart_remove, .driver = { .name = "mmc-moxart", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 89018b6c97b9a7..af445d3f8e2ae7 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -33,6 +33,7 @@ #include #include "cqhci.h" +#include "mmc_hsq.h" #define MAX_BD_NUM 1024 #define MSDC_NR_CLOCKS 3 @@ -65,6 +66,7 @@ #define SDC_RESP3 0x4c #define SDC_BLK_NUM 0x50 #define SDC_ADV_CFG0 0x64 +#define MSDC_NEW_RX_CFG 0x68 #define EMMC_IOCON 0x7c #define SDC_ACMD_RESP 0x80 #define DMA_SA_H4BIT 0x8c @@ -91,6 +93,7 @@ #define EMMC_TOP_CONTROL 0x00 #define EMMC_TOP_CMD 0x04 #define EMMC50_PAD_DS_TUNE 0x0c +#define LOOP_TEST_CONTROL 0x30 /*--------------------------------------------------------------------------*/ /* Register Mask */ @@ -202,9 +205,13 @@ #define SDC_STS_CMDBUSY BIT(1) /* RW */ #define SDC_STS_SWR_COMPL BIT(31) /* RW */ -#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */ /* SDC_ADV_CFG0 mask */ +#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */ #define SDC_RX_ENHANCE_EN BIT(20) /* RW */ +#define SDC_NEW_TX_EN BIT(31) /* RW */ + +/* MSDC_NEW_RX_CFG mask */ +#define MSDC_NEW_RX_PATH_SEL BIT(0) /* RW */ /* DMA_SA_H4BIT mask */ #define DMA_ADDR_HIGH_4BIT GENMASK(3, 0) /* RW */ @@ -226,6 +233,7 @@ /* MSDC_PATCH_BIT mask */ #define MSDC_PATCH_BIT_ODDSUPP BIT(1) /* RW */ +#define MSDC_PATCH_BIT_RD_DAT_SEL BIT(3) /* RW */ #define MSDC_INT_DAT_LATCH_CK_SEL GENMASK(9, 7) #define MSDC_CKGEN_MSDC_DLY_SEL GENMASK(14, 10) #define MSDC_PATCH_BIT_IODSSEL BIT(16) /* RW */ @@ -247,6 +255,8 @@ #define MSDC_PB2_SUPPORT_64G BIT(1) /* RW */ #define MSDC_PB2_RESPWAIT GENMASK(3, 2) /* RW */ #define MSDC_PB2_RESPSTSENSEL GENMASK(18, 16) /* RW */ +#define MSDC_PB2_POP_EN_CNT GENMASK(23, 20) /* RW */ +#define MSDC_PB2_CFGCRCSTSEDGE BIT(25) /* RW */ #define MSDC_PB2_CRCSTSENSEL GENMASK(31, 29) /* RW */ #define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* RW */ @@ -311,6 +321,12 @@ #define PAD_DS_DLY1 GENMASK(14, 10) /* RW */ #define PAD_DS_DLY3 GENMASK(4, 0) /* RW */ +/* LOOP_TEST_CONTROL mask */ +#define TEST_LOOP_DSCLK_MUX_SEL BIT(0) /* RW */ +#define TEST_LOOP_LATCH_MUX_SEL BIT(1) /* RW */ +#define LOOP_EN_SEL_CLK BIT(20) /* RW */ +#define TEST_HS400_CMD_LOOP_MUX_SEL BIT(31) /* RW */ + #define REQ_CMD_EIO BIT(0) #define REQ_CMD_TMO BIT(1) #define REQ_DAT_ERR BIT(2) @@ -391,6 +407,7 @@ struct msdc_save_para { u32 emmc_top_control; u32 emmc_top_cmd; u32 emmc50_pad_ds_tune; + u32 loop_test_control; }; struct mtk_mmc_compatible { @@ -402,9 +419,13 @@ struct mtk_mmc_compatible { bool data_tune; bool busy_check; bool stop_clk_fix; + u8 stop_dly_sel; + u8 pop_en_cnt; bool enhance_rx; bool support_64g; bool use_internal_cd; + bool support_new_tx; + bool support_new_rx; }; struct msdc_tune_para { @@ -473,6 +494,7 @@ struct msdc_host { bool hs400_tuning; /* hs400 mode online tuning */ bool internal_cd; /* Use internal card-detect logic */ bool cqhci; /* support eMMC hw cmdq */ + bool hsq_en; /* Host Software Queue is enabled */ struct msdc_save_para save_para; /* used when gate HCLK */ struct msdc_tune_para def_tune_para; /* default tune setting */ struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ @@ -502,6 +524,7 @@ static const struct mtk_mmc_compatible mt2712_compat = { .data_tune = true, .busy_check = true, .stop_clk_fix = true, + .stop_dly_sel = 3, .enhance_rx = true, .support_64g = true, }; @@ -515,6 +538,7 @@ static const struct mtk_mmc_compatible mt6779_compat = { .data_tune = true, .busy_check = true, .stop_clk_fix = true, + .stop_dly_sel = 3, .enhance_rx = true, .support_64g = true, }; @@ -554,6 +578,7 @@ static const struct mtk_mmc_compatible mt7622_compat = { .data_tune = true, .busy_check = true, .stop_clk_fix = true, + .stop_dly_sel = 3, .enhance_rx = true, .support_64g = false, }; @@ -567,6 +592,7 @@ static const struct mtk_mmc_compatible mt7986_compat = { .data_tune = true, .busy_check = true, .stop_clk_fix = true, + .stop_dly_sel = 3, .enhance_rx = true, .support_64g = true, }; @@ -606,6 +632,7 @@ static const struct mtk_mmc_compatible mt8183_compat = { .data_tune = true, .busy_check = true, .stop_clk_fix = true, + .stop_dly_sel = 3, .enhance_rx = true, .support_64g = true, }; @@ -619,6 +646,24 @@ static const struct mtk_mmc_compatible mt8516_compat = { .data_tune = true, .busy_check = true, .stop_clk_fix = true, + .stop_dly_sel = 3, +}; + +static const struct mtk_mmc_compatible mt8196_compat = { + .clk_div_bits = 12, + .recheck_sdio_irq = false, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, + .busy_check = true, + .stop_clk_fix = true, + .stop_dly_sel = 1, + .pop_en_cnt = 2, + .enhance_rx = true, + .support_64g = true, + .support_new_tx = true, + .support_new_rx = true, }; static const struct of_device_id msdc_of_ids[] = { @@ -629,9 +674,11 @@ static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, { .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat}, + { .compatible = "mediatek,mt7988-mmc", .data = &mt7986_compat}, { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat}, + { .compatible = "mediatek,mt8196-mmc", .data = &mt8196_compat}, { .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat}, {} @@ -872,6 +919,41 @@ static int msdc_ungate_clock(struct msdc_host *host) (val & MSDC_CFG_CKSTB), 1, 20000); } +static void msdc_new_tx_setting(struct msdc_host *host) +{ + if (!host->top_base) + return; + + sdr_set_bits(host->top_base + LOOP_TEST_CONTROL, + TEST_LOOP_DSCLK_MUX_SEL); + sdr_set_bits(host->top_base + LOOP_TEST_CONTROL, + TEST_LOOP_LATCH_MUX_SEL); + sdr_clr_bits(host->top_base + LOOP_TEST_CONTROL, + TEST_HS400_CMD_LOOP_MUX_SEL); + + switch (host->timing) { + case MMC_TIMING_LEGACY: + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + case MMC_TIMING_UHS_SDR12: + case MMC_TIMING_UHS_SDR25: + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: + sdr_clr_bits(host->top_base + LOOP_TEST_CONTROL, + LOOP_EN_SEL_CLK); + break; + case MMC_TIMING_UHS_SDR50: + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + case MMC_TIMING_MMC_HS400: + sdr_set_bits(host->top_base + LOOP_TEST_CONTROL, + LOOP_EN_SEL_CLK); + break; + default: + break; + } +} + static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) { struct mmc_host *mmc = mmc_from_priv(host); @@ -881,6 +963,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) u32 sclk; u32 tune_reg = host->dev_comp->pad_tune_reg; u32 val; + bool timing_changed; if (!hz) { dev_dbg(host->dev, "set mclk to 0\n"); @@ -890,6 +973,11 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) return; } + if (host->timing != timing) + timing_changed = true; + else + timing_changed = false; + flags = readl(host->base + MSDC_INTEN); sdr_clr_bits(host->base + MSDC_INTEN, flags); if (host->dev_comp->clk_div_bits == 8) @@ -996,6 +1084,9 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRRDLY, host->hs400_cmd_int_delay); + if (host->dev_comp->support_new_tx && timing_changed) + msdc_new_tx_setting(host); + dev_dbg(host->dev, "sclk: %d, timing: %d\n", mmc->actual_clock, timing); } @@ -1163,7 +1254,9 @@ static void msdc_track_cmd_data(struct msdc_host *host, struct mmc_command *cmd) static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) { + struct mmc_host *mmc = mmc_from_priv(host); unsigned long flags; + bool hsq_req_done; /* * No need check the return value of cancel_delayed_work, as only ONE @@ -1171,6 +1264,27 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) */ cancel_delayed_work(&host->req_timeout); + /* + * If the request was handled from Host Software Queue, there's almost + * nothing to do here, and we also don't need to reset mrq as any race + * condition would not have any room to happen, since HSQ stores the + * "scheduled" mrqs in an internal array of mrq slots anyway. + * However, if the controller experienced an error, we still want to + * reset it as soon as possible. + * + * Note that non-HSQ requests will still be happening at times, even + * though it is enabled, and that's what is going to reset host->mrq. + * Also, msdc_unprepare_data() is going to be called by HSQ when needed + * as HSQ request finalization will eventually call the .post_req() + * callback of this driver which, in turn, unprepares the data. + */ + hsq_req_done = host->hsq_en ? mmc_hsq_finalize_request(mmc, mrq) : false; + if (hsq_req_done) { + if (host->error) + msdc_reset_hw(host); + return; + } + spin_lock_irqsave(&host->lock, flags); host->mrq = NULL; spin_unlock_irqrestore(&host->lock, flags); @@ -1180,7 +1294,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) msdc_unprepare_data(host, mrq->data); if (host->error) msdc_reset_hw(host); - mmc_request_done(mmc_from_priv(host), mrq); + mmc_request_done(mmc, mrq); if (host->dev_comp->recheck_sdio_irq) msdc_recheck_sdio_irq(host); } @@ -1340,7 +1454,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) struct msdc_host *host = mmc_priv(mmc); host->error = 0; - WARN_ON(host->mrq); + WARN_ON(!host->hsq_en && host->mrq); host->mrq = mrq; if (mrq->data) @@ -1704,6 +1818,17 @@ static void msdc_init_hw(struct msdc_host *host) reset_control_deassert(host->reset); } + /* New tx/rx enable bit need to be 0->1 for hardware check */ + if (host->dev_comp->support_new_tx) { + sdr_clr_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN); + sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN); + msdc_new_tx_setting(host); + } + if (host->dev_comp->support_new_rx) { + sdr_clr_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL); + sdr_set_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL); + } + /* Configure to MMC/SD mode, clock free running */ sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN); @@ -1742,8 +1867,16 @@ static void msdc_init_hw(struct msdc_host *host) sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL); if (host->dev_comp->stop_clk_fix) { - sdr_set_field(host->base + MSDC_PATCH_BIT1, - MSDC_PATCH_BIT1_STOP_DLY, 3); + if (host->dev_comp->stop_dly_sel) + sdr_set_field(host->base + MSDC_PATCH_BIT1, + MSDC_PATCH_BIT1_STOP_DLY, + host->dev_comp->stop_dly_sel); + + if (host->dev_comp->pop_en_cnt) + sdr_set_field(host->base + MSDC_PATCH_BIT2, + MSDC_PB2_POP_EN_CNT, + host->dev_comp->pop_en_cnt); + sdr_clr_bits(host->base + SDC_FIFO_CFG, SDC_FIFO_CFG_WRVALIDSEL); sdr_clr_bits(host->base + SDC_FIFO_CFG, @@ -2055,6 +2188,19 @@ static inline void msdc_set_data_delay(struct msdc_host *host, u32 value) } } +static inline void msdc_set_data_sample_edge(struct msdc_host *host, bool rising) +{ + u32 value = rising ? 0 : 1; + + if (host->dev_comp->support_new_rx) { + sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_PATCH_BIT_RD_DAT_SEL, value); + sdr_set_field(host->base + MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTSEDGE, value); + } else { + sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DSPL, value); + sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL, value); + } +} + static int msdc_tune_response(struct mmc_host *mmc, u32 opcode) { struct msdc_host *host = mmc_priv(mmc); @@ -2210,8 +2356,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL, host->latch_ck); - sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); - sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, true); for (i = 0; i < host->tuning_step; i++) { msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); @@ -2224,8 +2369,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4)) goto skip_fall; - sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); - sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, false); for (i = 0; i < host->tuning_step; i++) { msdc_set_data_delay(host, i); ret = mmc_send_tuning(mmc, opcode, NULL); @@ -2237,12 +2381,10 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode) skip_fall: final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); if (final_maxlen == final_rise_delay.maxlen) { - sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); - sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, true); final_delay = final_rise_delay.final_phase; } else { - sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); - sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, false); final_delay = final_fall_delay.final_phase; } msdc_set_data_delay(host, final_delay); @@ -2267,8 +2409,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) host->latch_ck); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - sdr_clr_bits(host->base + MSDC_IOCON, - MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, true); for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); msdc_set_data_delay(host, i); @@ -2283,8 +2424,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) goto skip_fall; sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - sdr_set_bits(host->base + MSDC_IOCON, - MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, false); for (i = 0; i < host->tuning_step; i++) { msdc_set_cmd_delay(host, i); msdc_set_data_delay(host, i); @@ -2298,13 +2438,11 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode) final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); if (final_maxlen == final_rise_delay.maxlen) { sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - sdr_clr_bits(host->base + MSDC_IOCON, - MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, true); final_delay = final_rise_delay.final_phase; } else { sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); - sdr_set_bits(host->base + MSDC_IOCON, - MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, false); final_delay = final_fall_delay.final_phase; } @@ -2324,8 +2462,7 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode) if (host->dev_comp->data_tune && host->dev_comp->async_fifo) { ret = msdc_tune_together(mmc, opcode); if (host->hs400_mode) { - sdr_clr_bits(host->base + MSDC_IOCON, - MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL); + msdc_set_data_sample_edge(host, true); msdc_set_data_delay(host, 0); } goto tune_done; @@ -2727,7 +2864,6 @@ static int msdc_drv_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct msdc_host *host; - struct resource *res; int ret; if (!pdev->dev.of_node) { @@ -2736,77 +2872,64 @@ static int msdc_drv_probe(struct platform_device *pdev) } /* Allocate MMC host for this device */ - mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(struct msdc_host)); if (!mmc) return -ENOMEM; host = mmc_priv(mmc); ret = mmc_of_parse(mmc); if (ret) - goto host_free; + return ret; host->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(host->base)) { - ret = PTR_ERR(host->base); - goto host_free; - } + if (IS_ERR(host->base)) + return PTR_ERR(host->base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res) { - host->top_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(host->top_base)) - host->top_base = NULL; - } + host->top_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(host->top_base)) + host->top_base = NULL; ret = mmc_regulator_get_supply(mmc); if (ret) - goto host_free; + return ret; ret = msdc_of_clock_parse(pdev, host); if (ret) - goto host_free; + return ret; host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev, "hrst"); - if (IS_ERR(host->reset)) { - ret = PTR_ERR(host->reset); - goto host_free; - } + if (IS_ERR(host->reset)) + return PTR_ERR(host->reset); /* only eMMC has crypto property */ if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) { host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto"); if (IS_ERR(host->crypto_clk)) - host->crypto_clk = NULL; - else + return PTR_ERR(host->crypto_clk); + else if (host->crypto_clk) mmc->caps2 |= MMC_CAP2_CRYPTO; } host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) { - ret = host->irq; - goto host_free; - } + if (host->irq < 0) + return host->irq; host->pinctrl = devm_pinctrl_get(&pdev->dev); - if (IS_ERR(host->pinctrl)) { - ret = PTR_ERR(host->pinctrl); - dev_err(&pdev->dev, "Cannot find pinctrl!\n"); - goto host_free; - } + if (IS_ERR(host->pinctrl)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->pinctrl), + "Cannot find pinctrl"); host->pins_default = pinctrl_lookup_state(host->pinctrl, "default"); if (IS_ERR(host->pins_default)) { - ret = PTR_ERR(host->pins_default); dev_err(&pdev->dev, "Cannot find pinctrl default!\n"); - goto host_free; + return PTR_ERR(host->pins_default); } host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs"); if (IS_ERR(host->pins_uhs)) { - ret = PTR_ERR(host->pins_uhs); dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n"); - goto host_free; + return PTR_ERR(host->pins_uhs); } /* Support for SDIO eint irq ? */ @@ -2885,7 +3008,7 @@ static int msdc_drv_probe(struct platform_device *pdev) ret = msdc_ungate_clock(host); if (ret) { dev_err(&pdev->dev, "Cannot ungate clocks!\n"); - goto release_mem; + goto release_clk; } msdc_init_hw(host); @@ -2895,20 +3018,33 @@ static int msdc_drv_probe(struct platform_device *pdev) GFP_KERNEL); if (!host->cq_host) { ret = -ENOMEM; - goto host_free; + goto release; } host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128; host->cq_host->mmio = host->base + 0x800; host->cq_host->ops = &msdc_cmdq_ops; ret = cqhci_init(host->cq_host, mmc, true); if (ret) - goto host_free; + goto release; mmc->max_segs = 128; /* cqhci 16bit length */ /* 0 size, means 65536 so we don't have to -1 here */ mmc->max_seg_size = 64 * 1024; /* Reduce CIT to 0x40 that corresponds to 2.35us */ msdc_cqe_cit_cal(host, 2350); + } else if (mmc->caps2 & MMC_CAP2_NO_SDIO) { + /* Use HSQ on eMMC/SD (but not on SDIO) if HW CQE not supported */ + struct mmc_hsq *hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL); + if (!hsq) { + ret = -ENOMEM; + goto release; + } + + ret = mmc_hsq_init(hsq, mmc); + if (ret) + goto release; + + host->hsq_en = true; } ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq, @@ -2929,21 +3065,20 @@ static int msdc_drv_probe(struct platform_device *pdev) end: pm_runtime_disable(host->dev); release: - platform_set_drvdata(pdev, NULL); msdc_deinit_hw(host); +release_clk: msdc_gate_clock(host); + platform_set_drvdata(pdev, NULL); release_mem: + device_init_wakeup(&pdev->dev, false); if (host->dma.gpd) dma_free_coherent(&pdev->dev, 2 * sizeof(struct mt_gpdma_desc), host->dma.gpd, host->dma.gpd_addr); if (host->dma.bd) dma_free_coherent(&pdev->dev, - MAX_BD_NUM * sizeof(struct mt_bdma_desc), - host->dma.bd, host->dma.bd_addr); -host_free: - mmc_free_host(mmc); - + MAX_BD_NUM * sizeof(struct mt_bdma_desc), + host->dma.bd, host->dma.bd_addr); return ret; } @@ -2968,9 +3103,8 @@ static void msdc_drv_remove(struct platform_device *pdev) 2 * sizeof(struct mt_gpdma_desc), host->dma.gpd, host->dma.gpd_addr); dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc), - host->dma.bd, host->dma.bd_addr); - - mmc_free_host(mmc); + host->dma.bd, host->dma.bd_addr); + device_init_wakeup(&pdev->dev, false); } static void msdc_save_reg(struct msdc_host *host) @@ -2995,6 +3129,8 @@ static void msdc_save_reg(struct msdc_host *host) readl(host->top_base + EMMC_TOP_CMD); host->save_para.emmc50_pad_ds_tune = readl(host->top_base + EMMC50_PAD_DS_TUNE); + host->save_para.loop_test_control = + readl(host->top_base + LOOP_TEST_CONTROL); } else { host->save_para.pad_tune = readl(host->base + tune_reg); } @@ -3005,6 +3141,15 @@ static void msdc_restore_reg(struct msdc_host *host) struct mmc_host *mmc = mmc_from_priv(host); u32 tune_reg = host->dev_comp->pad_tune_reg; + if (host->dev_comp->support_new_tx) { + sdr_clr_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN); + sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN); + } + if (host->dev_comp->support_new_rx) { + sdr_clr_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL); + sdr_set_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL); + } + writel(host->save_para.msdc_cfg, host->base + MSDC_CFG); writel(host->save_para.iocon, host->base + MSDC_IOCON); writel(host->save_para.sdc_cfg, host->base + SDC_CFG); @@ -3023,6 +3168,8 @@ static void msdc_restore_reg(struct msdc_host *host) host->top_base + EMMC_TOP_CMD); writel(host->save_para.emmc50_pad_ds_tune, host->top_base + EMMC50_PAD_DS_TUNE); + writel(host->save_para.loop_test_control, + host->top_base + LOOP_TEST_CONTROL); } else { writel(host->save_para.pad_tune, host->base + tune_reg); } @@ -3036,6 +3183,9 @@ static int __maybe_unused msdc_runtime_suspend(struct device *dev) struct mmc_host *mmc = dev_get_drvdata(dev); struct msdc_host *host = mmc_priv(mmc); + if (host->hsq_en) + mmc_hsq_suspend(mmc); + msdc_save_reg(host); if (sdio_irq_claimed(mmc)) { @@ -3066,6 +3216,10 @@ static int __maybe_unused msdc_runtime_resume(struct device *dev) pinctrl_select_state(host->pinctrl, host->pins_uhs); enable_irq(host->irq); } + + if (host->hsq_en) + mmc_hsq_resume(mmc); + return 0; } @@ -3112,7 +3266,7 @@ static const struct dev_pm_ops msdc_dev_pm_ops = { static struct platform_driver mt_msdc_driver = { .probe = msdc_drv_probe, - .remove_new = msdc_drv_remove, + .remove = msdc_drv_remove, .driver = { .name = "mtk-msdc", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 12df4ff9eeee53..b92f3ba38663b7 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -819,7 +819,7 @@ MODULE_DEVICE_TABLE(of, mvsdio_dt_ids); static struct platform_driver mvsd_driver = { .probe = mvsd_probe, - .remove_new = mvsd_remove, + .remove = mvsd_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 1edf652913541e..e7a286c3216fdb 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1225,7 +1225,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume); static struct platform_driver mxcmci_driver = { .probe = mxcmci_probe, - .remove_new = mxcmci_remove, + .remove = mxcmci_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 6751da9b60f964..80e6f48c83aa05 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -714,7 +714,7 @@ static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume); static struct platform_driver mxs_mmc_driver = { .probe = mxs_mmc_probe, - .remove_new = mxs_mmc_remove, + .remove = mxs_mmc_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 335350a4e99aba..62252ad4e20de1 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1554,7 +1554,7 @@ MODULE_DEVICE_TABLE(of, mmc_omap_match); static struct platform_driver mmc_omap_driver = { .probe = mmc_omap_probe, - .remove_new = mmc_omap_remove, + .remove = mmc_omap_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e120aeb869b892..59e36e0ebbbf74 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2121,7 +2121,7 @@ static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = { static struct platform_driver omap_hsmmc_driver = { .probe = omap_hsmmc_probe, - .remove_new = omap_hsmmc_remove, + .remove = omap_hsmmc_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c index fc08f25c34eb6d..797ef48d9204e4 100644 --- a/drivers/mmc/host/owl-mmc.c +++ b/drivers/mmc/host/owl-mmc.c @@ -692,7 +692,7 @@ static struct platform_driver owl_mmc_driver = { .of_match_table = owl_mmc_of_match, }, .probe = owl_mmc_probe, - .remove_new = owl_mmc_remove, + .remove = owl_mmc_remove, }; module_platform_driver(owl_mmc_driver); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index fae3192c3a142c..2d0ad006913d5b 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -810,7 +810,7 @@ static void pxamci_remove(struct platform_device *pdev) static struct platform_driver pxamci_driver = { .probe = pxamci_probe, - .remove_new = pxamci_remove, + .remove = pxamci_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 1dcaa050f26486..4b389e92399e82 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -613,7 +613,7 @@ static struct platform_driver renesas_internal_dmac_sdhi_driver = { .of_match_table = renesas_sdhi_internal_dmac_of_match, }, .probe = renesas_sdhi_internal_dmac_probe, - .remove_new = renesas_sdhi_remove, + .remove = renesas_sdhi_remove, }; module_platform_driver(renesas_internal_dmac_sdhi_driver); diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 0ba3f62a9b4919..822a310c9bbaed 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -471,7 +471,7 @@ static struct platform_driver renesas_sys_dmac_sdhi_driver = { .of_match_table = renesas_sdhi_sys_dmac_of_match, }, .probe = renesas_sdhi_sys_dmac_probe, - .remove_new = renesas_sdhi_remove, + .remove = renesas_sdhi_remove, }; module_platform_driver(renesas_sys_dmac_sdhi_driver); diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 20e79109be16d6..48d3b0aae5a001 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1591,7 +1591,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_pci_sdmmc_ids); static struct platform_driver rtsx_pci_sdmmc_driver = { .probe = rtsx_pci_sdmmc_drv_probe, - .remove_new = rtsx_pci_sdmmc_drv_remove, + .remove = rtsx_pci_sdmmc_drv_remove, .id_table = rtsx_pci_sdmmc_ids, .driver = { .name = DRV_NAME_RTSX_PCI_SDMMC, diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index 4e86f0a705b60a..107c78df53cf40 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1453,7 +1453,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids); static struct platform_driver rtsx_usb_sdmmc_driver = { .probe = rtsx_usb_sdmmc_drv_probe, - .remove_new = rtsx_usb_sdmmc_drv_remove, + .remove = rtsx_usb_sdmmc_drv_remove, .id_table = rtsx_usb_sdmmc_ids, .driver = { .name = "rtsx_usb_sdmmc", diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index eb8f427f9770d5..d1ce9193ece934 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -1080,7 +1080,7 @@ static struct platform_driver sdhci_acpi_driver = { .pm = &sdhci_acpi_pm_ops, }, .probe = sdhci_acpi_probe, - .remove_new = sdhci_acpi_remove, + .remove = sdhci_acpi_remove, }; module_platform_driver(sdhci_acpi_driver); diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index e067c7f5c53721..fda911fb28e5af 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -328,7 +328,7 @@ static struct platform_driver sdhci_bcm_kona_driver = { .of_match_table = sdhci_bcm_kona_of_match, }, .probe = sdhci_bcm_kona_probe, - .remove_new = sdhci_bcm_kona_remove, + .remove = sdhci_bcm_kona_remove, }; module_platform_driver(sdhci_bcm_kona_driver); diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index 031a4b514d16bd..0ef4d578ade849 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -545,7 +545,7 @@ static struct platform_driver sdhci_brcmstb_driver = { .of_match_table = of_match_ptr(sdhci_brcm_of_match), }, .probe = sdhci_brcmstb_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, .shutdown = sdhci_brcmstb_shutdown, }; diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index be1505e8c536e8..a94b297fcf2a34 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -608,7 +608,7 @@ static struct platform_driver sdhci_cdns_driver = { .of_match_table = sdhci_cdns_match, }, .probe = sdhci_cdns_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, }; module_platform_driver(sdhci_cdns_driver); diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 88ec23417808b2..77034b13fa66ae 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -106,7 +106,7 @@ static struct platform_driver sdhci_dove_driver = { .of_match_table = sdhci_dove_of_match_table, }, .probe = sdhci_dove_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, }; module_platform_driver(sdhci_dove_driver); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 8f0bc6dca2b040..d55d045ef2363b 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -30,7 +30,8 @@ #include "sdhci-esdhc.h" #include "cqhci.h" -#define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f +#define ESDHC_SYS_CTRL_DTOCV_MASK GENMASK(19, 16) +#define ESDHC_SYS_CTRL_IPP_RST_N BIT(23) #define ESDHC_CTRL_D3CD 0x08 #define ESDHC_BURST_LEN_EN_INCR (1 << 27) /* VENDOR SPEC register */ @@ -238,6 +239,7 @@ struct esdhc_platform_data { struct esdhc_soc_data { u32 flags; + u32 quirks; }; static const struct esdhc_soc_data esdhc_imx25_data = { @@ -309,10 +311,12 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = { | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 | ESDHC_FLAG_STATE_LOST_IN_LPMODE, + .quirks = SDHCI_QUIRK_NO_LED, }; static struct esdhc_soc_data usdhc_imxrt1050_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, + .quirks = SDHCI_QUIRK_NO_LED, }; static struct esdhc_soc_data usdhc_imx8qxp_data = { @@ -321,6 +325,7 @@ static struct esdhc_soc_data usdhc_imx8qxp_data = { | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES | ESDHC_FLAG_STATE_LOST_IN_LPMODE | ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME, + .quirks = SDHCI_QUIRK_NO_LED, }; static struct esdhc_soc_data usdhc_imx8mm_data = { @@ -328,6 +333,7 @@ static struct esdhc_soc_data usdhc_imx8mm_data = { | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES | ESDHC_FLAG_STATE_LOST_IN_LPMODE, + .quirks = SDHCI_QUIRK_NO_LED, }; struct pltfm_imx_data { @@ -1385,8 +1391,8 @@ static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) /* use maximum timeout counter */ esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK, - esdhc_is_usdhc(imx_data) ? 0xF : 0xE, - SDHCI_TIMEOUT_CONTROL); + esdhc_is_usdhc(imx_data) ? 0xF0000 : 0xE0000, + ESDHC_SYSTEM_CONTROL); } static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) @@ -1402,6 +1408,17 @@ static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) return 0; } +static void esdhc_hw_reset(struct sdhci_host *host) +{ + esdhc_clrset_le(host, ESDHC_SYS_CTRL_IPP_RST_N, 0, ESDHC_SYSTEM_CONTROL); + /* eMMC spec requires minimum 1us, here delay between 1-10us */ + usleep_range(1, 10); + esdhc_clrset_le(host, ESDHC_SYS_CTRL_IPP_RST_N, + ESDHC_SYS_CTRL_IPP_RST_N, ESDHC_SYSTEM_CONTROL); + /* eMMC spec requires minimum 200us, here delay between 200-300us */ + usleep_range(200, 300); +} + static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl_le, .read_w = esdhc_readw_le, @@ -1420,6 +1437,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .reset = esdhc_reset, .irq = esdhc_cqhci_irq, .dump_vendor_regs = esdhc_dump_debug_regs, + .hw_reset = esdhc_hw_reset, }; static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { @@ -1524,7 +1542,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL); } else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { /* - * ESDHC_STD_TUNING_EN may be configed in bootloader + * ESDHC_STD_TUNING_EN may be configured in bootloader * or ROM code, so clear this bit here to make sure * the manual tuning can work. */ @@ -1626,7 +1644,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, /* * If we have this property, then activate WP check. - * Retrieveing and requesting the actual WP GPIO will happen + * Retrieving and requesting the actual WP GPIO will happen * in the call to mmc_of_parse(). */ if (of_property_read_bool(np, "wp-gpios")) @@ -1687,6 +1705,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->socdata = device_get_match_data(&pdev->dev); + host->quirks |= imx_data->socdata->quirks; if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); @@ -2015,7 +2034,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = { .pm = &sdhci_esdhc_pmops, }, .probe = sdhci_esdhc_imx_probe, - .remove_new = sdhci_esdhc_imx_remove, + .remove = sdhci_esdhc_imx_remove, }; module_platform_driver(sdhci_esdhc_imx_driver); diff --git a/drivers/mmc/host/sdhci-esdhc-mcf.c b/drivers/mmc/host/sdhci-esdhc-mcf.c index 3ad87322f6a553..327662ba5bd930 100644 --- a/drivers/mmc/host/sdhci-esdhc-mcf.c +++ b/drivers/mmc/host/sdhci-esdhc-mcf.c @@ -512,7 +512,7 @@ static struct platform_driver sdhci_esdhc_mcf_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = sdhci_esdhc_mcf_probe, - .remove_new = sdhci_esdhc_mcf_remove, + .remove = sdhci_esdhc_mcf_remove, }; module_platform_driver(sdhci_esdhc_mcf_driver); diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 10235fdff246f6..80b2567a488bff 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -424,7 +424,7 @@ static struct platform_driver sdhci_iproc_driver = { .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_iproc_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, .shutdown = sdhci_iproc_shutdown, }; module_platform_driver(sdhci_iproc_driver); diff --git a/drivers/mmc/host/sdhci-milbeaut.c b/drivers/mmc/host/sdhci-milbeaut.c index 83706edc979689..a4675456f9c783 100644 --- a/drivers/mmc/host/sdhci-milbeaut.c +++ b/drivers/mmc/host/sdhci-milbeaut.c @@ -335,7 +335,7 @@ static struct platform_driver sdhci_milbeaut_driver = { .of_match_table = mlb_dt_ids, }, .probe = sdhci_milbeaut_probe, - .remove_new = sdhci_milbeaut_remove, + .remove = sdhci_milbeaut_remove, }; module_platform_driver(sdhci_milbeaut_driver); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index e113b99a3eab59..e00208535bd1c6 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2601,7 +2601,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) sdhci_msm_handle_pwr_irq(host, 0); /* - * Ensure that above writes are propogated before interrupt enablement + * Ensure that above writes are propagated before interrupt enablement * in GIC. */ mb(); @@ -2753,7 +2753,7 @@ static const struct dev_pm_ops sdhci_msm_pm_ops = { static struct platform_driver sdhci_msm_driver = { .probe = sdhci_msm_probe, - .remove_new = sdhci_msm_remove, + .remove = sdhci_msm_remove, .driver = { .name = "sdhci_msm", .of_match_table = sdhci_msm_dt_match, diff --git a/drivers/mmc/host/sdhci-npcm.c b/drivers/mmc/host/sdhci-npcm.c index 5bf9d18f364e41..bee0585ba5c131 100644 --- a/drivers/mmc/host/sdhci-npcm.c +++ b/drivers/mmc/host/sdhci-npcm.c @@ -85,7 +85,7 @@ static struct platform_driver npcm_sdhci_driver = { .pm = &sdhci_pltfm_pmops, }, .probe = npcm_sdhci_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, }; module_platform_driver(npcm_sdhci_driver); diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 5edd024347bd5d..8c29676ab6628b 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -76,6 +76,8 @@ #define FREQSEL_225M_200M 0x7 #define PHY_DLL_TIMEOUT_MS 100 +#define SDHCI_HW_RST_EN BIT(4) + /* Default settings for ZynqMP Clock Phases */ #define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0} #define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0} @@ -475,6 +477,21 @@ static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) } } +static void sdhci_arasan_hw_reset(struct sdhci_host *host) +{ + u8 reg; + + reg = sdhci_readb(host, SDHCI_POWER_CONTROL); + reg |= SDHCI_HW_RST_EN; + sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); + /* As per eMMC spec, minimum 1us is required but give it 2us for good measure */ + usleep_range(2, 5); + reg &= ~SDHCI_HW_RST_EN; + sdhci_writeb(host, reg, SDHCI_POWER_CONTROL); + /* As per eMMC spec, minimum 200us is required but give it 300us for good measure */ + usleep_range(300, 500); +} + static int sdhci_arasan_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -505,6 +522,7 @@ static const struct sdhci_ops sdhci_arasan_ops = { .reset = sdhci_arasan_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, .set_power = sdhci_set_power_and_bus_voltage, + .hw_reset = sdhci_arasan_hw_reset, }; static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) @@ -2046,7 +2064,7 @@ static struct platform_driver sdhci_arasan_driver = { .pm = &sdhci_arasan_dev_pm_ops, }, .probe = sdhci_arasan_probe, - .remove_new = sdhci_arasan_remove, + .remove = sdhci_arasan_remove, }; module_platform_driver(sdhci_arasan_driver); diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index 37240895ffaafc..d6de010551b934 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -519,7 +519,7 @@ static struct platform_driver aspeed_sdhci_driver = { .of_match_table = aspeed_sdhci_of_match, }, .probe = aspeed_sdhci_probe, - .remove_new = aspeed_sdhci_remove, + .remove = aspeed_sdhci_remove, }; static int aspeed_sdc_probe(struct platform_device *pdev) @@ -596,7 +596,7 @@ static struct platform_driver aspeed_sdc_driver = { .of_match_table = aspeed_sdc_of_match, }, .probe = aspeed_sdc_probe, - .remove_new = aspeed_sdc_remove, + .remove = aspeed_sdc_remove, }; #if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 23a9faad2ff81d..97988ed3746723 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -471,7 +471,7 @@ static struct platform_driver sdhci_at91_driver = { .pm = &sdhci_at91_dev_pm_ops, }, .probe = sdhci_at91_probe, - .remove_new = sdhci_at91_remove, + .remove = sdhci_at91_remove, }; module_platform_driver(sdhci_at91_driver); diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index 8fd80dac11bfdf..7ea3da45db326d 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -1626,7 +1626,7 @@ static struct platform_driver sdhci_dwcmshc_driver = { .pm = &dwcmshc_pmops, }, .probe = dwcmshc_probe, - .remove_new = dwcmshc_remove, + .remove = dwcmshc_remove, }; module_platform_driver(sdhci_dwcmshc_driver); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 3ae9aa25745ae0..002d0d59b9926d 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -1521,7 +1521,7 @@ static struct platform_driver sdhci_esdhc_driver = { .pm = &esdhc_of_dev_pm_ops, }, .probe = sdhci_esdhc_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, }; module_platform_driver(sdhci_esdhc_driver); diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 9c1c0ce610efcd..5bb845d13599c6 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -85,7 +85,7 @@ static struct platform_driver sdhci_hlwd_driver = { .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_hlwd_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, }; module_platform_driver(sdhci_hlwd_driver); diff --git a/drivers/mmc/host/sdhci-of-ma35d1.c b/drivers/mmc/host/sdhci-of-ma35d1.c index b84c2927bd4ade..1e6d180100ad46 100644 --- a/drivers/mmc/host/sdhci-of-ma35d1.c +++ b/drivers/mmc/host/sdhci-of-ma35d1.c @@ -305,7 +305,7 @@ static struct platform_driver sdhci_ma35_driver = { .of_match_table = sdhci_ma35_dt_ids, }, .probe = ma35_probe, - .remove_new = ma35_remove, + .remove = ma35_remove, }; module_platform_driver(sdhci_ma35_driver); diff --git a/drivers/mmc/host/sdhci-of-sparx5.c b/drivers/mmc/host/sdhci-of-sparx5.c index 64b77e7d14cdbd..d2aa684e786f4d 100644 --- a/drivers/mmc/host/sdhci-of-sparx5.c +++ b/drivers/mmc/host/sdhci-of-sparx5.c @@ -255,7 +255,7 @@ static struct platform_driver sdhci_sparx5_driver = { .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_sparx5_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, }; module_platform_driver(sdhci_sparx5_driver); diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 5841a9afeb9f50..54d795205fb443 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1478,7 +1478,7 @@ static const struct dev_pm_ops sdhci_omap_dev_pm_ops = { static struct platform_driver sdhci_omap_driver = { .probe = sdhci_omap_probe, - .remove_new = sdhci_omap_remove, + .remove = sdhci_omap_remove, .driver = { .name = "sdhci-omap", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index ed45ed0bdafd96..1f0bd723f01124 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include "sdhci.h" #include "sdhci-cqhci.h" #include "sdhci-pci.h" +#include "sdhci-uhs2.h" static void sdhci_pci_hw_reset(struct sdhci_host *host); @@ -1235,6 +1237,29 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { .priv_size = sizeof(struct intel_host), }; +/* DMI quirks for devices with missing or broken CD GPIO info */ +static const struct gpiod_lookup_table vexia_edu_atla10_cd_gpios = { + .dev_id = "0000:00:12.0", + .table = { + GPIO_LOOKUP("INT33FC:00", 38, "cd", GPIO_ACTIVE_HIGH), + { } + }, +}; + +static const struct dmi_system_id sdhci_intel_byt_cd_gpio_override[] = { + { + /* Vexia Edu Atla 10 tablet 9V version */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), + }, + .driver_data = (void *)&vexia_edu_atla10_cd_gpios, + }, + { } +}; + static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { #ifdef CONFIG_PM_SLEEP .resume = byt_resume, @@ -1253,6 +1278,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { .add_host = byt_add_host, .remove_slot = byt_remove_slot, .ops = &sdhci_intel_byt_ops, + .cd_gpio_override = sdhci_intel_byt_cd_gpio_override, .priv_size = sizeof(struct intel_host), }; @@ -2054,6 +2080,42 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = { * * \*****************************************************************************/ +static struct gpiod_lookup_table *sdhci_pci_add_gpio_lookup_table( + struct sdhci_pci_chip *chip) +{ + struct gpiod_lookup_table *cd_gpio_lookup_table; + const struct dmi_system_id *dmi_id = NULL; + size_t count; + + if (chip->fixes && chip->fixes->cd_gpio_override) + dmi_id = dmi_first_match(chip->fixes->cd_gpio_override); + + if (!dmi_id) + return NULL; + + cd_gpio_lookup_table = dmi_id->driver_data; + for (count = 0; cd_gpio_lookup_table->table[count].key; count++) + ; + + cd_gpio_lookup_table = kmemdup(dmi_id->driver_data, + /* count + 1 terminating entry */ + struct_size(cd_gpio_lookup_table, table, count + 1), + GFP_KERNEL); + if (!cd_gpio_lookup_table) + return ERR_PTR(-ENOMEM); + + gpiod_add_lookup_table(cd_gpio_lookup_table); + return cd_gpio_lookup_table; +} + +static void sdhci_pci_remove_gpio_lookup_table(struct gpiod_lookup_table *lookup_table) +{ + if (lookup_table) { + gpiod_remove_lookup_table(lookup_table); + kfree(lookup_table); + } +} + static struct sdhci_pci_slot *sdhci_pci_probe_slot( struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, int slotno) @@ -2129,8 +2191,19 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( device_init_wakeup(&pdev->dev, true); if (slot->cd_idx >= 0) { + struct gpiod_lookup_table *cd_gpio_lookup_table; + + cd_gpio_lookup_table = sdhci_pci_add_gpio_lookup_table(chip); + if (IS_ERR(cd_gpio_lookup_table)) { + ret = PTR_ERR(cd_gpio_lookup_table); + goto remove; + } + ret = mmc_gpiod_request_cd(host->mmc, "cd", slot->cd_idx, slot->cd_override_level, 0); + + sdhci_pci_remove_gpio_lookup_table(cd_gpio_lookup_table); + if (ret && ret != -EPROBE_DEFER) ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx, @@ -2181,7 +2254,10 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) if (scratch == (u32)-1) dead = 1; - sdhci_remove_host(slot->host, dead); + if (slot->chip->fixes && slot->chip->fixes->remove_host) + slot->chip->fixes->remove_host(slot, dead); + else + sdhci_remove_host(slot->host, dead); if (slot->chip->fixes && slot->chip->fixes->remove_slot) slot->chip->fixes->remove_slot(slot, dead); @@ -2189,6 +2265,16 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) sdhci_free_host(slot->host); } +int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot) +{ + return sdhci_uhs2_add_host(slot->host); +} + +void sdhci_pci_uhs2_remove_host(struct sdhci_pci_slot *slot, int dead) +{ + sdhci_uhs2_remove_host(slot->host, dead); +} + static void sdhci_pci_runtime_pm_allow(struct device *dev) { pm_suspend_ignore_children(dev, 1); diff --git a/drivers/mmc/host/sdhci-pci-gli.c b/drivers/mmc/host/sdhci-pci-gli.c index 68ce4920e01e35..4c2ae71770f782 100644 --- a/drivers/mmc/host/sdhci-pci-gli.c +++ b/drivers/mmc/host/sdhci-pci-gli.c @@ -18,6 +18,7 @@ #include "sdhci-cqhci.h" #include "sdhci-pci.h" #include "cqhci.h" +#include "sdhci-uhs2.h" /* Genesys Logic extra registers */ #define SDHCI_GLI_9750_WT 0x800 @@ -139,13 +140,49 @@ #define PCI_GLI_9755_PLLSSC 0x68 #define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0) +#define PCI_GLI_9755_PLLSSC_RTL BIT(24) +#define GLI_9755_PLLSSC_RTL_VALUE 0x1 +#define PCI_GLI_9755_PLLSSC_TRANS_PASS BIT(27) +#define GLI_9755_PLLSSC_TRANS_PASS_VALUE 0x1 +#define PCI_GLI_9755_PLLSSC_RECV GENMASK(29, 28) +#define GLI_9755_PLLSSC_RECV_VALUE 0x0 +#define PCI_GLI_9755_PLLSSC_TRAN GENMASK(31, 30) +#define GLI_9755_PLLSSC_TRAN_VALUE 0x3 + +#define PCI_GLI_9755_UHS2_PLL 0x6C +#define PCI_GLI_9755_UHS2_PLL_SSC GENMASK(9, 8) +#define GLI_9755_UHS2_PLL_SSC_VALUE 0x0 +#define PCI_GLI_9755_UHS2_PLL_DELAY BIT(18) +#define GLI_9755_UHS2_PLL_DELAY_VALUE 0x1 +#define PCI_GLI_9755_UHS2_PLL_PDRST BIT(27) +#define GLI_9755_UHS2_PLL_PDRST_VALUE 0x1 #define PCI_GLI_9755_SerDes 0x70 +#define PCI_GLI_9755_UHS2_SERDES_INTR GENMASK(2, 0) +#define GLI_9755_UHS2_SERDES_INTR_VALUE 0x3 +#define PCI_GLI_9755_UHS2_SERDES_ZC1 BIT(3) +#define GLI_9755_UHS2_SERDES_ZC1_VALUE 0x0 +#define PCI_GLI_9755_UHS2_SERDES_ZC2 GENMASK(7, 4) +#define GLI_9755_UHS2_SERDES_ZC2_DEFAULT 0xB +#define GLI_9755_UHS2_SERDES_ZC2_SANDISK 0x0 #define PCI_GLI_9755_SCP_DIS BIT(19) +#define PCI_GLI_9755_UHS2_SERDES_TRAN GENMASK(27, 24) +#define GLI_9755_UHS2_SERDES_TRAN_VALUE 0xC +#define PCI_GLI_9755_UHS2_SERDES_RECV GENMASK(31, 28) +#define GLI_9755_UHS2_SERDES_RECV_VALUE 0xF #define PCI_GLI_9755_MISC 0x78 #define PCI_GLI_9755_MISC_SSC_OFF BIT(26) +#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL 0x508 +#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_CMD_CONFLICT_CHECK BIT(0) +#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE GENMASK(21, 16) +#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_PLUG_IN_VALUE 0x05 +#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_PLUG_OUT_VALUE 0x3F +#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE GENMASK(23, 22) +#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE_1MS 0x2 +#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE_10MS 0x3 + #define SDHCI_GLI_9767_GM_BURST_SIZE 0x510 #define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8) @@ -182,6 +219,13 @@ #define PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF BIT(21) #define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30) +#define PCIE_GLI_9767_RESET_REG 0x8E4 +#define PCIE_GLI_9767_RESET_REG_SD_HOST_SW_RESET BIT(0) + +#define PCIE_GLI_9767_UHS2_PHY_SET_REG1 0x90C +#define PCIE_GLI_9767_UHS2_PHY_SET_REG1_SERDES_INTR GENMASK(31, 29) +#define PCIE_GLI_9767_UHS2_PHY_SET_REG1_SERDES_INTR_VALUE 0x3 + #define PCIE_GLI_9767_SDHC_CAP 0x91C #define PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT BIT(5) @@ -200,9 +244,15 @@ #define PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE BIT(1) #define PCIE_GLI_9767_SD_DATA_MULTI_CTL 0x944 +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_SELECT_UHS2 BIT(5) +#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_UHS2_SWITCH_CTL BIT(8) #define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME GENMASK(23, 16) #define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE 0x64 +#define PCIE_GLI_9767_UHS2_PHY_SET_REG2 0x948 +#define PCIE_GLI_9767_UHS2_PHY_SET_REG2_SSC_PPM_SETTING GENMASK(22, 21) +#define PCIE_GLI_9767_UHS2_PHY_SET_REG2_SSC_PPM_SETTING_VALUE 0x0 + #define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2 0x950 #define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE BIT(0) @@ -212,6 +262,28 @@ #define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2 0x958 #define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN BIT(0) +#define PCIE_GLI_9767_UHS2_CTL1 0x95C +#define PCIE_GLI_9767_UHS2_CTL1_TRANS_PASS BIT(5) +#define PCIE_GLI_9767_UHS2_CTL1_TRANS_PASS_VALUE 0x1 +#define PCIE_GLI_9767_UHS2_CTL1_DECODING_CTL BIT(6) +#define PCIE_GLI_9767_UHS2_CTL1_DECODING_CTL_VALUE 0x1 +#define PCIE_GLI_9767_UHS2_CTL1_SERDES_TRAN GENMASK(10, 7) +#define PCIE_GLI_9767_UHS2_CTL1_SERDES_TRAN_VALUE 0x3 +#define PCIE_GLI_9767_UHS2_CTL1_SERDES_RECV GENMASK(14, 11) +#define PCIE_GLI_9767_UHS2_CTL1_SERDES_RECV_VALUE 0xf +#define PCIE_GLI_9767_UHS2_CTL1_DIR_TRANS GENMASK(16, 15) +#define PCIE_GLI_9767_UHS2_CTL1_DIR_TRANS_VALUE 0x0 +#define PCIE_GLI_9767_UHS2_CTL1_DIR_RECV GENMASK(18, 17) +#define PCIE_GLI_9767_UHS2_CTL1_DIR_RECV_VALUE 0x0 +#define PCIE_GLI_9767_UHS2_CTL1_PDRST BIT(25) +#define PCIE_GLI_9767_UHS2_CTL1_PDRST_VALUE 0x1 + +#define PCIE_GLI_9767_UHS2_CTL2 0x964 +#define PCIE_GLI_9767_UHS2_CTL2_ZC GENMASK(3, 0) +#define PCIE_GLI_9767_UHS2_CTL2_ZC_VALUE 0xb +#define PCIE_GLI_9767_UHS2_CTL2_ZC_CTL BIT(6) +#define PCIE_GLI_9767_UHS2_CTL2_ZC_CTL_VALUE 0x1 + #define GLI_MAX_TUNING_LOOP 40 /* Genesys Logic chipset */ @@ -779,6 +851,203 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot) gl9755_wt_off(pdev); } +static void gl9755_vendor_init(struct sdhci_host *host) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct pci_dev *pdev = slot->chip->pdev; + u32 serdes; + u32 pllssc; + u32 uhs2_pll; + + gl9755_wt_on(pdev); + + pci_read_config_dword(pdev, PCI_GLI_9755_SerDes, &serdes); + serdes &= ~PCI_GLI_9755_UHS2_SERDES_TRAN; + serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_TRAN, + GLI_9755_UHS2_SERDES_TRAN_VALUE); + serdes &= ~PCI_GLI_9755_UHS2_SERDES_RECV; + serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_RECV, + GLI_9755_UHS2_SERDES_RECV_VALUE); + serdes &= ~PCI_GLI_9755_UHS2_SERDES_INTR; + serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_INTR, + GLI_9755_UHS2_SERDES_INTR_VALUE); + serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC1; + serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC1, + GLI_9755_UHS2_SERDES_ZC1_VALUE); + serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC2; + serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC2, + GLI_9755_UHS2_SERDES_ZC2_DEFAULT); + pci_write_config_dword(pdev, PCI_GLI_9755_SerDes, serdes); + + pci_read_config_dword(pdev, PCI_GLI_9755_UHS2_PLL, &uhs2_pll); + uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_SSC; + uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_SSC, + GLI_9755_UHS2_PLL_SSC_VALUE); + uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_DELAY; + uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_DELAY, + GLI_9755_UHS2_PLL_DELAY_VALUE); + uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_PDRST; + uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_PDRST, + GLI_9755_UHS2_PLL_PDRST_VALUE); + pci_write_config_dword(pdev, PCI_GLI_9755_UHS2_PLL, uhs2_pll); + + pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &pllssc); + pllssc &= ~PCI_GLI_9755_PLLSSC_RTL; + pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_RTL, + GLI_9755_PLLSSC_RTL_VALUE); + pllssc &= ~PCI_GLI_9755_PLLSSC_TRANS_PASS; + pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_TRANS_PASS, + GLI_9755_PLLSSC_TRANS_PASS_VALUE); + pllssc &= ~PCI_GLI_9755_PLLSSC_RECV; + pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_RECV, + GLI_9755_PLLSSC_RECV_VALUE); + pllssc &= ~PCI_GLI_9755_PLLSSC_TRAN; + pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_TRAN, + GLI_9755_PLLSSC_TRAN_VALUE); + pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, pllssc); + + gl9755_wt_off(pdev); +} + +static void sdhci_gli_pre_detect_init(struct sdhci_host *host) +{ + /* Need more time on UHS2 detect flow */ + sdhci_writeb(host, 0xA7, SDHCI_UHS2_TIMER_CTRL); +} + +static void sdhci_gli_overcurrent_event_enable(struct sdhci_host *host, bool enable) +{ + u32 mask; + + mask = sdhci_readl(host, SDHCI_SIGNAL_ENABLE); + if (enable) + mask |= SDHCI_INT_BUS_POWER; + else + mask &= ~SDHCI_INT_BUS_POWER; + + sdhci_writel(host, mask, SDHCI_SIGNAL_ENABLE); + + mask = sdhci_readl(host, SDHCI_INT_ENABLE); + if (enable) + mask |= SDHCI_INT_BUS_POWER; + else + mask &= ~SDHCI_INT_BUS_POWER; + + sdhci_writel(host, mask, SDHCI_INT_ENABLE); +} + +static void gl9755_set_power(struct sdhci_host *host, unsigned char mode, + unsigned short vdd) +{ + u8 pwr = 0; + + if (mode != MMC_POWER_OFF) { + pwr = sdhci_get_vdd_value(vdd); + if (!pwr) + WARN(1, "%s: Invalid vdd %#x\n", mmc_hostname(host->mmc), vdd); + pwr |= SDHCI_VDD2_POWER_180; + } + + if (host->pwr == pwr) + return; + + host->pwr = pwr; + + if (pwr == 0) { + sdhci_gli_overcurrent_event_enable(host, false); + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + } else { + sdhci_gli_overcurrent_event_enable(host, false); + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + + pwr |= (SDHCI_POWER_ON | SDHCI_VDD2_POWER_ON); + + sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL); + /* wait stable */ + mdelay(5); + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + /* wait stable */ + mdelay(5); + sdhci_gli_overcurrent_event_enable(host, true); + } +} + +static bool sdhci_wait_clock_stable(struct sdhci_host *host) +{ + u16 clk = 0; + + if (read_poll_timeout_atomic(sdhci_readw, clk, (clk & SDHCI_CLOCK_INT_STABLE), + 10, 20000, false, host, SDHCI_CLOCK_CONTROL)) { + pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return false; + } + return true; +} + +static void sdhci_gli_enable_internal_clock(struct sdhci_host *host) +{ + u16 ctrl2; + + ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + + sdhci_writew(host, SDHCI_CLOCK_INT_EN, SDHCI_CLOCK_CONTROL); + + if (!((ctrl2 & SDHCI_CTRL_V4_MODE) && + (ctrl2 & SDHCI_CTRL_UHS2_ENABLE))) { + sdhci_wait_clock_stable(host); + sdhci_writew(host, SDHCI_CTRL_V4_MODE, SDHCI_HOST_CONTROL2); + } +} + +static int sdhci_gli_wait_software_reset_done(struct sdhci_host *host, u8 mask) +{ + u8 rst; + + /* hw clears the bit when it's done */ + if (read_poll_timeout_atomic(sdhci_readb, rst, !(rst & mask), + 10, 100000, false, host, SDHCI_SOFTWARE_RESET)) { + pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); + sdhci_dumpregs(host); + /* manual clear */ + sdhci_writeb(host, 0, SDHCI_SOFTWARE_RESET); + return -ETIMEDOUT; + } + + return 0; +} + +static void sdhci_gli_uhs2_reset_sd_tran(struct sdhci_host *host) +{ + /* do this on UHS2 mode */ + if (host->mmc->uhs2_sd_tran) { + sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD); + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + sdhci_uhs2_clear_set_irqs(host, + SDHCI_INT_ALL_MASK, + SDHCI_UHS2_INT_ERROR_MASK); + } +} + +static void sdhci_gl9755_reset(struct sdhci_host *host, u8 mask) +{ + /* need internal clock */ + if (mask & SDHCI_RESET_ALL) + sdhci_gli_enable_internal_clock(host); + + sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); + + /* reset sd-tran on UHS2 mode if need to reset cmd/data */ + if ((mask & SDHCI_RESET_CMD) | (mask & SDHCI_RESET_DATA)) + sdhci_gli_uhs2_reset_sd_tran(host); + + if (mask & SDHCI_RESET_ALL) + host->clock = 0; + + sdhci_gli_wait_software_reset_done(host, mask); +} + static inline void gl9767_vhs_read(struct pci_dev *pdev) { u32 vhs_enable; @@ -937,6 +1206,31 @@ static void sdhci_gl9767_set_clock(struct sdhci_host *host, unsigned int clock) gl9767_set_low_power_negotiation(pdev, true); } +static void sdhci_gl9767_set_card_detect_debounce_time(struct sdhci_host *host) +{ + u32 value; + + value = sdhci_readl(host, SDHCI_GLI_9767_SD_HOST_OPERATION_CTL); + value &= ~(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE | + SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE); + if (sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT) + value |= FIELD_PREP(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE, + SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_PLUG_IN_VALUE) | + FIELD_PREP(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE, + SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE_1MS); + else + value |= FIELD_PREP(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE, + SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_PLUG_OUT_VALUE) | + FIELD_PREP(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE, + SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE_10MS); + sdhci_writel(host, value, SDHCI_GLI_9767_SD_HOST_OPERATION_CTL); +} + +static void sdhci_gl9767_card_event(struct sdhci_host *host) +{ + sdhci_gl9767_set_card_detect_debounce_time(host); +} + static void gli_set_9767(struct sdhci_host *host) { u32 value; @@ -944,6 +1238,12 @@ static void gli_set_9767(struct sdhci_host *host) value = sdhci_readl(host, SDHCI_GLI_9767_GM_BURST_SIZE); value &= ~SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET; sdhci_writel(host, value, SDHCI_GLI_9767_GM_BURST_SIZE); + + value = sdhci_readl(host, SDHCI_GLI_9767_SD_HOST_OPERATION_CTL); + value &= ~SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_CMD_CONFLICT_CHECK; + sdhci_writel(host, value, SDHCI_GLI_9767_SD_HOST_OPERATION_CTL); + + sdhci_gl9767_set_card_detect_debounce_time(host); } static void gl9767_hw_setting(struct sdhci_pci_slot *slot) @@ -982,7 +1282,43 @@ static void gl9767_hw_setting(struct sdhci_pci_slot *slot) static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask) { - sdhci_reset(host, mask); + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct pci_dev *pdev = slot->chip->pdev; + u32 value; + + /* need internal clock */ + if (mask & SDHCI_RESET_ALL) { + sdhci_gli_enable_internal_clock(host); + + gl9767_vhs_write(pdev); + + pci_read_config_dword(pdev, PCIE_GLI_9767_RESET_REG, &value); + value &= ~PCIE_GLI_9767_RESET_REG_SD_HOST_SW_RESET; + pci_write_config_dword(pdev, PCIE_GLI_9767_RESET_REG, value); + + if (read_poll_timeout_atomic(pci_read_config_dword, value, + !(value & PCIE_GLI_9767_RESET_REG_SD_HOST_SW_RESET), + 1, 5, true, pdev, PCIE_GLI_9767_RESET_REG, &value)) { + pr_warn("%s: %s: Reset SDHC AHB and TL-AMBA failure.\n", + __func__, mmc_hostname(host->mmc)); + gl9767_vhs_read(pdev); + return; + } + gl9767_vhs_read(pdev); + } + + if (mmc_card_uhs2(host->mmc)) { + if (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) { + sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); + sdhci_gli_uhs2_reset_sd_tran(host); + sdhci_gli_wait_software_reset_done(host, mask); + } else { + sdhci_uhs2_reset(host, mask); + } + } else { + sdhci_reset(host, mask); + } + gli_set_9767(host); } @@ -1076,6 +1412,86 @@ static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios) return 0; } +static void gl9767_vendor_init(struct sdhci_host *host) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct pci_dev *pdev = slot->chip->pdev; + u32 value; + + gl9767_vhs_write(pdev); + + pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_PHY_SET_REG1, &value); + value |= FIELD_PREP(PCIE_GLI_9767_UHS2_PHY_SET_REG1_SERDES_INTR, + PCIE_GLI_9767_UHS2_PHY_SET_REG1_SERDES_INTR_VALUE); + pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_PHY_SET_REG1, value); + + pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_PHY_SET_REG2, &value); + value |= FIELD_PREP(PCIE_GLI_9767_UHS2_PHY_SET_REG2_SSC_PPM_SETTING, + PCIE_GLI_9767_UHS2_PHY_SET_REG2_SSC_PPM_SETTING_VALUE); + pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_PHY_SET_REG2, value); + + pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL1, &value); + value |= FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_TRANS_PASS, + PCIE_GLI_9767_UHS2_CTL1_TRANS_PASS_VALUE) | + FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_DECODING_CTL, + PCIE_GLI_9767_UHS2_CTL1_DECODING_CTL_VALUE) | + FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_SERDES_TRAN, + PCIE_GLI_9767_UHS2_CTL1_SERDES_TRAN_VALUE) | + FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_SERDES_RECV, + PCIE_GLI_9767_UHS2_CTL1_SERDES_RECV_VALUE) | + FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_DIR_TRANS, + PCIE_GLI_9767_UHS2_CTL1_DIR_TRANS_VALUE) | + FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_DIR_RECV, + PCIE_GLI_9767_UHS2_CTL1_DIR_RECV_VALUE) | + FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_PDRST, + PCIE_GLI_9767_UHS2_CTL1_PDRST_VALUE); + pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL1, value); + + pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL2, &value); + value |= FIELD_PREP(PCIE_GLI_9767_UHS2_CTL2_ZC, + PCIE_GLI_9767_UHS2_CTL2_ZC_VALUE) | + FIELD_PREP(PCIE_GLI_9767_UHS2_CTL2_ZC_CTL, + PCIE_GLI_9767_UHS2_CTL2_ZC_CTL_VALUE); + pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL2, value); + + gl9767_vhs_read(pdev); +} + +static void sdhci_gl9767_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) +{ + struct sdhci_pci_slot *slot = sdhci_priv(host); + struct pci_dev *pdev = slot->chip->pdev; + u32 value; + + if (mmc_card_uhs2(host->mmc)) { + gl9767_vhs_write(pdev); + + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value); + value |= PCIE_GLI_9767_SD_DATA_MULTI_CTL_SELECT_UHS2 | + PCIE_GLI_9767_SD_DATA_MULTI_CTL_UHS2_SWITCH_CTL; + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value); + + gl9767_vhs_read(pdev); + + sdhci_gli_overcurrent_event_enable(host, false); + sdhci_uhs2_set_power(host, mode, vdd); + sdhci_gli_overcurrent_event_enable(host, true); + } else { + gl9767_vhs_write(pdev); + + pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value); + value &= ~(PCIE_GLI_9767_SD_DATA_MULTI_CTL_SELECT_UHS2 | + PCIE_GLI_9767_SD_DATA_MULTI_CTL_UHS2_SWITCH_CTL); + pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value); + + gl9767_vhs_read(pdev); + + sdhci_gli_overcurrent_event_enable(host, false); + sdhci_set_power(host, mode, vdd); + sdhci_gli_overcurrent_event_enable(host, true); + } +} + static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot) { struct sdhci_host *host = slot->host; @@ -1096,6 +1512,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot) gli_pcie_enable_msi(slot); slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; sdhci_enable_v4_mode(host); + gl9755_vendor_init(host); return 0; } @@ -1111,6 +1528,7 @@ static int gli_probe_slot_gl9767(struct sdhci_pci_slot *slot) host->mmc->caps2 |= MMC_CAP2_SD_EXP; host->mmc_host_ops.init_sd_express = gl9767_init_sd_express; sdhci_enable_v4_mode(host); + gl9767_vendor_init(host); return 0; } @@ -1534,17 +1952,24 @@ static const struct sdhci_ops sdhci_gl9755_ops = { .read_w = sdhci_gli_readw, .read_b = sdhci_gli_readb, .set_clock = sdhci_gl9755_set_clock, + .set_power = gl9755_set_power, .enable_dma = sdhci_pci_enable_dma, .set_bus_width = sdhci_set_bus_width, - .reset = sdhci_reset, + .reset = sdhci_gl9755_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, .voltage_switch = sdhci_gli_voltage_switch, + .dump_uhs2_regs = sdhci_uhs2_dump_regs, + .set_timeout = sdhci_uhs2_set_timeout, + .irq = sdhci_uhs2_irq, + .uhs2_pre_detect_init = sdhci_gli_pre_detect_init, }; const struct sdhci_pci_fixes sdhci_gl9755 = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, .probe_slot = gli_probe_slot_gl9755, + .add_host = sdhci_pci_uhs2_add_host, + .remove_host = sdhci_pci_uhs2_remove_host, .ops = &sdhci_gl9755_ops, #ifdef CONFIG_PM_SLEEP .resume = sdhci_pci_gli_resume, @@ -1607,12 +2032,20 @@ static const struct sdhci_ops sdhci_gl9767_ops = { .reset = sdhci_gl9767_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, .voltage_switch = sdhci_gl9767_voltage_switch, + .dump_uhs2_regs = sdhci_uhs2_dump_regs, + .set_timeout = sdhci_uhs2_set_timeout, + .irq = sdhci_uhs2_irq, + .set_power = sdhci_gl9767_set_power, + .uhs2_pre_detect_init = sdhci_gli_pre_detect_init, + .card_event = sdhci_gl9767_card_event, }; const struct sdhci_pci_fixes sdhci_gl9767 = { .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, .probe_slot = gli_probe_slot_gl9767, + .add_host = sdhci_pci_uhs2_add_host, + .remove_host = sdhci_pci_uhs2_remove_host, .ops = &sdhci_gl9767_ops, #ifdef CONFIG_PM_SLEEP .resume = sdhci_pci_gli_resume, diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h index 153704f812edc8..f38f0bd4165c35 100644 --- a/drivers/mmc/host/sdhci-pci.h +++ b/drivers/mmc/host/sdhci-pci.h @@ -145,6 +145,7 @@ struct sdhci_pci_fixes { int (*probe_slot) (struct sdhci_pci_slot *); int (*add_host) (struct sdhci_pci_slot *); void (*remove_slot) (struct sdhci_pci_slot *, int); + void (*remove_host) (struct sdhci_pci_slot *, int); #ifdef CONFIG_PM_SLEEP int (*suspend) (struct sdhci_pci_chip *); @@ -156,6 +157,7 @@ struct sdhci_pci_fixes { #endif const struct sdhci_ops *ops; + const struct dmi_system_id *cd_gpio_override; size_t priv_size; }; @@ -189,6 +191,8 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot) return (void *)slot->private; } +int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot); +void sdhci_pci_uhs2_remove_host(struct sdhci_pci_slot *slot, int dead); #ifdef CONFIG_PM_SLEEP int sdhci_pci_resume_host(struct sdhci_pci_chip *chip); #endif diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c index 7a0351a9c74e6b..d6a299f4990065 100644 --- a/drivers/mmc/host/sdhci-pic32.c +++ b/drivers/mmc/host/sdhci-pic32.c @@ -236,7 +236,7 @@ static struct platform_driver pic32_sdhci_driver = { .of_match_table = of_match_ptr(pic32_sdhci_id_table), }, .probe = pic32_sdhci_probe, - .remove_new = pic32_sdhci_remove, + .remove = pic32_sdhci_remove, }; module_platform_driver(pic32_sdhci_driver); diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 7b957f6d55884a..45b6f0891c47e6 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -351,7 +351,7 @@ static struct platform_driver sdhci_pxav2_driver = { .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_pxav2_probe, - .remove_new = sdhci_pltfm_remove, + .remove = sdhci_pltfm_remove, }; module_platform_driver(sdhci_pxav2_driver); diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 3af43ac0582552..990723a008aec5 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -568,7 +568,7 @@ static struct platform_driver sdhci_pxav3_driver = { .pm = &sdhci_pxav3_pmops, }, .probe = sdhci_pxav3_probe, - .remove_new = sdhci_pxav3_remove, + .remove = sdhci_pxav3_remove, }; module_platform_driver(sdhci_pxav3_driver); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index a71d56c7031ffa..bdf4dc0d6b77b8 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -774,7 +774,7 @@ MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match); static struct platform_driver sdhci_s3c_driver = { .probe = sdhci_s3c_probe, - .remove_new = sdhci_s3c_remove, + .remove = sdhci_s3c_remove, .id_table = sdhci_s3c_driver_ids, .driver = { .name = "s3c-sdhci", diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index c81bdfa97b891e..770dc12b9ae92d 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -182,7 +182,7 @@ static struct platform_driver sdhci_driver = { .of_match_table = sdhci_spear_id_table, }, .probe = sdhci_probe, - .remove_new = sdhci_remove, + .remove = sdhci_remove, }; module_platform_driver(sdhci_driver); diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index 8776f42871196b..db5e253b0f7918 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -975,7 +975,7 @@ static const struct dev_pm_ops sdhci_sprd_pm_ops = { static struct platform_driver sdhci_sprd_driver = { .probe = sdhci_sprd_probe, - .remove_new = sdhci_sprd_remove, + .remove = sdhci_sprd_remove, .driver = { .name = "sdhci_sprd_r11", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index d12532b96b5112..4973e08a98f873 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -507,7 +507,7 @@ MODULE_DEVICE_TABLE(of, st_sdhci_match); static struct platform_driver sdhci_st_driver = { .probe = sdhci_st_probe, - .remove_new = sdhci_st_remove, + .remove = sdhci_st_remove, .driver = { .name = "sdhci-st", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 1ad0a6b3a2eb77..b2f5c3f8b83962 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1525,7 +1525,6 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_NO_HISPD_BIT | - SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER, @@ -1930,7 +1929,7 @@ static struct platform_driver sdhci_tegra_driver = { .pm = &sdhci_tegra_dev_pm_ops, }, .probe = sdhci_tegra_probe, - .remove_new = sdhci_tegra_remove, + .remove = sdhci_tegra_remove, }; module_platform_driver(sdhci_tegra_driver); diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c new file mode 100644 index 00000000000000..c53b64d50c0de5 --- /dev/null +++ b/drivers/mmc/host/sdhci-uhs2.c @@ -0,0 +1,1250 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/drivers/mmc/host/sdhci_uhs2.c - Secure Digital Host Controller + * Interface driver + * + * Copyright (C) 2014 Intel Corp, All Rights Reserved. + * Copyright (C) 2020 Genesys Logic, Inc. + * Authors: Ben Chuang + * Copyright (C) 2020 Linaro Limited + * Author: AKASHI Takahiro + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sdhci.h" +#include "sdhci-uhs2.h" + +#define DRIVER_NAME "sdhci_uhs2" +#define DBG(f, x...) \ + pr_debug(DRIVER_NAME " [%s()]: " f, __func__, ## x) +#define SDHCI_UHS2_DUMP(f, x...) \ + pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x) + +#define UHS2_RESET_TIMEOUT_100MS 100000 +#define UHS2_CHECK_DORMANT_TIMEOUT_100MS 100000 +#define UHS2_INTERFACE_DETECT_TIMEOUT_100MS 100000 +#define UHS2_LANE_SYNC_TIMEOUT_150MS 150000 + +#define UHS2_ARG_IOADR_MASK 0xfff + +void sdhci_uhs2_dump_regs(struct sdhci_host *host) +{ + if (!(mmc_card_uhs2(host->mmc))) + return; + + SDHCI_UHS2_DUMP("==================== UHS2 ==================\n"); + SDHCI_UHS2_DUMP("Blk Size: 0x%08x | Blk Cnt: 0x%08x\n", + sdhci_readw(host, SDHCI_UHS2_BLOCK_SIZE), + sdhci_readl(host, SDHCI_UHS2_BLOCK_COUNT)); + SDHCI_UHS2_DUMP("Cmd: 0x%08x | Trn mode: 0x%08x\n", + sdhci_readw(host, SDHCI_UHS2_CMD), + sdhci_readw(host, SDHCI_UHS2_TRANS_MODE)); + SDHCI_UHS2_DUMP("Int Stat: 0x%08x | Dev Sel : 0x%08x\n", + sdhci_readw(host, SDHCI_UHS2_DEV_INT_STATUS), + sdhci_readb(host, SDHCI_UHS2_DEV_SELECT)); + SDHCI_UHS2_DUMP("Dev Int Code: 0x%08x\n", + sdhci_readb(host, SDHCI_UHS2_DEV_INT_CODE)); + SDHCI_UHS2_DUMP("Reset: 0x%08x | Timer: 0x%08x\n", + sdhci_readw(host, SDHCI_UHS2_SW_RESET), + sdhci_readw(host, SDHCI_UHS2_TIMER_CTRL)); + SDHCI_UHS2_DUMP("ErrInt: 0x%08x | ErrIntEn: 0x%08x\n", + sdhci_readl(host, SDHCI_UHS2_INT_STATUS), + sdhci_readl(host, SDHCI_UHS2_INT_STATUS_ENABLE)); + SDHCI_UHS2_DUMP("ErrSigEn: 0x%08x\n", + sdhci_readl(host, SDHCI_UHS2_INT_SIGNAL_ENABLE)); +} +EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs); + +/*****************************************************************************\ + * * + * Low level functions * + * * +\*****************************************************************************/ + +static inline u16 uhs2_dev_cmd(struct mmc_command *cmd) +{ + return be16_to_cpu((__force __be16)cmd->uhs2_cmd->arg) & UHS2_ARG_IOADR_MASK; +} + +static inline int mmc_opt_regulator_set_ocr(struct mmc_host *mmc, + struct regulator *supply, + unsigned short vdd_bit) +{ + return IS_ERR_OR_NULL(supply) ? 0 : mmc_regulator_set_ocr(mmc, supply, vdd_bit); +} + +/** + * sdhci_uhs2_reset - invoke SW reset + * @host: SDHCI host + * @mask: Control mask + * + * Invoke SW reset, depending on a bit in @mask and wait for completion. + */ +void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask) +{ + u32 val; + + sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET); + + if (mask & SDHCI_UHS2_SW_RESET_FULL) + host->clock = 0; + + /* hw clears the bit when it's done */ + if (read_poll_timeout_atomic(sdhci_readw, val, !(val & mask), 10, + UHS2_RESET_TIMEOUT_100MS, true, host, SDHCI_UHS2_SW_RESET)) { + pr_warn("%s: %s: Reset 0x%x never completed. %s: clean reset bit.\n", __func__, + mmc_hostname(host->mmc), (int)mask, mmc_hostname(host->mmc)); + sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET); + return; + } +} +EXPORT_SYMBOL_GPL(sdhci_uhs2_reset); + +static void sdhci_uhs2_reset_cmd_data(struct sdhci_host *host) +{ + sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + + if (host->mmc->uhs2_sd_tran) { + sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD); + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK, SDHCI_UHS2_INT_ERROR_MASK); + } +} + +void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd) +{ + struct mmc_host *mmc = host->mmc; + u8 pwr = 0; + + if (mode != MMC_POWER_OFF) { + pwr = sdhci_get_vdd_value(vdd); + if (!pwr) + WARN(1, "%s: Invalid vdd %#x\n", + mmc_hostname(host->mmc), vdd); + pwr |= SDHCI_VDD2_POWER_180; + } + + if (host->pwr == pwr) + return; + host->pwr = pwr; + + if (pwr == 0) { + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + + mmc_opt_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + mmc_regulator_set_vqmmc2(mmc, &mmc->ios); + } else { + mmc_opt_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + /* support 1.8v only for now */ + mmc_regulator_set_vqmmc2(mmc, &mmc->ios); + + /* Clear the power reg before setting a new value */ + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + + /* vdd first */ + pwr |= SDHCI_POWER_ON; + sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL); + mdelay(5); + + pwr |= SDHCI_VDD2_POWER_ON; + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); + mdelay(5); + } +} +EXPORT_SYMBOL_GPL(sdhci_uhs2_set_power); + +static u8 sdhci_calc_timeout_uhs2(struct sdhci_host *host, u8 *cmd_res, u8 *dead_lock) +{ + /* timeout in us */ + unsigned int dead_lock_timeout = 1 * 1000 * 1000; + unsigned int cmd_res_timeout = 5 * 1000; + unsigned int current_timeout; + u8 count; + + /* + * Figure out needed cycles. + * We do this in steps in order to fit inside a 32 bit int. + * The first step is the minimum timeout, which will have a + * minimum resolution of 6 bits: + * (1) 2^13*1000 > 2^22, + * (2) host->timeout_clk < 2^16 + * => + * (1) / (2) > 2^6 + */ + count = 0; + current_timeout = (1 << 13) * 1000 / host->timeout_clk; + while (current_timeout < cmd_res_timeout) { + count++; + current_timeout <<= 1; + if (count >= 0xF) + break; + } + + if (count >= 0xF) { + DBG("%s: Too large timeout 0x%x requested for CMD_RES!\n", + mmc_hostname(host->mmc), count); + count = 0xE; + } + *cmd_res = count; + + count = 0; + current_timeout = (1 << 13) * 1000 / host->timeout_clk; + while (current_timeout < dead_lock_timeout) { + count++; + current_timeout <<= 1; + if (count >= 0xF) + break; + } + + if (count >= 0xF) { + DBG("%s: Too large timeout 0x%x requested for DEADLOCK!\n", + mmc_hostname(host->mmc), count); + count = 0xE; + } + *dead_lock = count; + + return count; +} + +static void __sdhci_uhs2_set_timeout(struct sdhci_host *host) +{ + u8 cmd_res, dead_lock; + + sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock); + cmd_res |= FIELD_PREP(SDHCI_UHS2_TIMER_CTRL_DEADLOCK_MASK, dead_lock); + sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL); +} + +void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) +{ + __sdhci_set_timeout(host, cmd); + + if (mmc_card_uhs2(host->mmc)) + __sdhci_uhs2_set_timeout(host); +} +EXPORT_SYMBOL_GPL(sdhci_uhs2_set_timeout); + +/** + * sdhci_uhs2_clear_set_irqs - set Error Interrupt Status Enable register + * @host: SDHCI host + * @clear: bit-wise clear mask + * @set: bit-wise set mask + * + * Set/unset bits in UHS-II Error Interrupt Status Enable register + */ +void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set) +{ + u32 ier; + + ier = sdhci_readl(host, SDHCI_UHS2_INT_STATUS_ENABLE); + ier &= ~clear; + ier |= set; + sdhci_writel(host, ier, SDHCI_UHS2_INT_STATUS_ENABLE); + sdhci_writel(host, ier, SDHCI_UHS2_INT_SIGNAL_ENABLE); +} +EXPORT_SYMBOL_GPL(sdhci_uhs2_clear_set_irqs); + +static void __sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + u8 cmd_res, dead_lock; + u16 ctrl_2; + + /* UHS2 Timeout Control */ + sdhci_calc_timeout_uhs2(host, &cmd_res, &dead_lock); + + /* change to use calculate value */ + cmd_res |= FIELD_PREP(SDHCI_UHS2_TIMER_CTRL_DEADLOCK_MASK, dead_lock); + + sdhci_uhs2_clear_set_irqs(host, + SDHCI_UHS2_INT_CMD_TIMEOUT | + SDHCI_UHS2_INT_DEADLOCK_TIMEOUT, + 0); + sdhci_writeb(host, cmd_res, SDHCI_UHS2_TIMER_CTRL); + sdhci_uhs2_clear_set_irqs(host, 0, + SDHCI_UHS2_INT_CMD_TIMEOUT | + SDHCI_UHS2_INT_DEADLOCK_TIMEOUT); + + /* UHS2 timing. Note, UHS2 timing is disabled when powering off */ + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + if (ios->power_mode != MMC_POWER_OFF && + (ios->timing == MMC_TIMING_UHS2_SPEED_A || + ios->timing == MMC_TIMING_UHS2_SPEED_A_HD || + ios->timing == MMC_TIMING_UHS2_SPEED_B || + ios->timing == MMC_TIMING_UHS2_SPEED_B_HD)) + ctrl_2 |= SDHCI_CTRL_UHS2 | SDHCI_CTRL_UHS2_ENABLE; + else + ctrl_2 &= ~(SDHCI_CTRL_UHS2 | SDHCI_CTRL_UHS2_ENABLE); + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); + host->timing = ios->timing; + + if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) + sdhci_enable_preset_value(host, true); + + if (host->ops->set_power) + host->ops->set_power(host, ios->power_mode, ios->vdd); + else + sdhci_uhs2_set_power(host, ios->power_mode, ios->vdd); + + sdhci_set_clock(host, host->clock); +} + +static int sdhci_uhs2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + + pr_debug("%s: clock %uHz powermode %u Vdd %u timing %u\n", + mmc_hostname(mmc), ios->clock, ios->power_mode, ios->vdd, ios->timing); + + if (!mmc_card_uhs2(mmc)) { + sdhci_set_ios(mmc, ios); + return 0; + } + + if (ios->power_mode == MMC_POWER_UNDEFINED) + return 0; + + if (host->flags & SDHCI_DEVICE_DEAD) { + if (ios->power_mode == MMC_POWER_OFF) { + mmc_opt_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + mmc_regulator_set_vqmmc2(mmc, ios); + } + return -1; + } + + sdhci_set_ios_common(mmc, ios); + + __sdhci_uhs2_set_ios(mmc, ios); + + return 0; +} + +static int sdhci_uhs2_interface_detect(struct sdhci_host *host) +{ + u32 val; + + if (read_poll_timeout(sdhci_readl, val, (val & SDHCI_UHS2_IF_DETECT), + 100, UHS2_INTERFACE_DETECT_TIMEOUT_100MS, true, + host, SDHCI_PRESENT_STATE)) { + pr_warn("%s: not detect UHS2 interface in 100ms.\n", mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return -EIO; + } + + /* Enable UHS2 error interrupts */ + sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK, SDHCI_UHS2_INT_ERROR_MASK); + + if (read_poll_timeout(sdhci_readl, val, (val & SDHCI_UHS2_LANE_SYNC), + 100, UHS2_LANE_SYNC_TIMEOUT_150MS, true, host, SDHCI_PRESENT_STATE)) { + pr_warn("%s: UHS2 Lane sync fail in 150ms.\n", mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return -EIO; + } + + DBG("%s: UHS2 Lane synchronized in UHS2 mode, PHY is initialized.\n", + mmc_hostname(host->mmc)); + return 0; +} + +static int sdhci_uhs2_init(struct sdhci_host *host) +{ + u16 caps_ptr = 0; + u32 caps_gen = 0; + u32 caps_phy = 0; + u32 caps_tran[2] = {0, 0}; + struct mmc_host *mmc = host->mmc; + + caps_ptr = sdhci_readw(host, SDHCI_UHS2_CAPS_PTR); + if (caps_ptr < 0x100 || caps_ptr > 0x1FF) { + pr_err("%s: SDHCI_UHS2_CAPS_PTR(%d) is wrong.\n", + mmc_hostname(mmc), caps_ptr); + return -ENODEV; + } + caps_gen = sdhci_readl(host, caps_ptr + SDHCI_UHS2_CAPS_OFFSET); + caps_phy = sdhci_readl(host, caps_ptr + SDHCI_UHS2_CAPS_PHY_OFFSET); + caps_tran[0] = sdhci_readl(host, caps_ptr + SDHCI_UHS2_CAPS_TRAN_OFFSET); + caps_tran[1] = sdhci_readl(host, caps_ptr + SDHCI_UHS2_CAPS_TRAN_1_OFFSET); + + /* General Caps */ + mmc->uhs2_caps.dap = caps_gen & SDHCI_UHS2_CAPS_DAP_MASK; + mmc->uhs2_caps.gap = FIELD_GET(SDHCI_UHS2_CAPS_GAP_MASK, caps_gen); + mmc->uhs2_caps.n_lanes = FIELD_GET(SDHCI_UHS2_CAPS_LANE_MASK, caps_gen); + mmc->uhs2_caps.addr64 = (caps_gen & SDHCI_UHS2_CAPS_ADDR_64) ? 1 : 0; + mmc->uhs2_caps.card_type = FIELD_GET(SDHCI_UHS2_CAPS_DEV_TYPE_MASK, caps_gen); + + /* PHY Caps */ + mmc->uhs2_caps.phy_rev = caps_phy & SDHCI_UHS2_CAPS_PHY_REV_MASK; + mmc->uhs2_caps.speed_range = FIELD_GET(SDHCI_UHS2_CAPS_PHY_RANGE_MASK, caps_phy); + mmc->uhs2_caps.n_lss_sync = FIELD_GET(SDHCI_UHS2_CAPS_PHY_N_LSS_SYN_MASK, caps_phy); + mmc->uhs2_caps.n_lss_dir = FIELD_GET(SDHCI_UHS2_CAPS_PHY_N_LSS_DIR_MASK, caps_phy); + if (mmc->uhs2_caps.n_lss_sync == 0) + mmc->uhs2_caps.n_lss_sync = 16 << 2; + else + mmc->uhs2_caps.n_lss_sync <<= 2; + if (mmc->uhs2_caps.n_lss_dir == 0) + mmc->uhs2_caps.n_lss_dir = 16 << 3; + else + mmc->uhs2_caps.n_lss_dir <<= 3; + + /* LINK/TRAN Caps */ + mmc->uhs2_caps.link_rev = caps_tran[0] & SDHCI_UHS2_CAPS_TRAN_LINK_REV_MASK; + mmc->uhs2_caps.n_fcu = FIELD_GET(SDHCI_UHS2_CAPS_TRAN_N_FCU_MASK, caps_tran[0]); + if (mmc->uhs2_caps.n_fcu == 0) + mmc->uhs2_caps.n_fcu = 256; + mmc->uhs2_caps.host_type = FIELD_GET(SDHCI_UHS2_CAPS_TRAN_HOST_TYPE_MASK, caps_tran[0]); + mmc->uhs2_caps.maxblk_len = FIELD_GET(SDHCI_UHS2_CAPS_TRAN_BLK_LEN_MASK, caps_tran[0]); + mmc->uhs2_caps.n_data_gap = caps_tran[1] & SDHCI_UHS2_CAPS_TRAN_1_N_DATA_GAP_MASK; + + return 0; +} + +static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + DBG("Begin do uhs2 detect init.\n"); + + if (host->ops->uhs2_pre_detect_init) + host->ops->uhs2_pre_detect_init(host); + + if (sdhci_uhs2_interface_detect(host)) { + pr_warn("%s: cannot detect UHS2 interface.\n", mmc_hostname(host->mmc)); + return -EIO; + } + + if (sdhci_uhs2_init(host)) { + pr_warn("%s: UHS2 init fail.\n", mmc_hostname(host->mmc)); + return -EIO; + } + + /* Init complete, do soft reset and enable UHS2 error irqs. */ + sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD); + sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_ALL_MASK, SDHCI_UHS2_INT_ERROR_MASK); + /* + * N.B SDHCI_INT_ENABLE and SDHCI_SIGNAL_ENABLE was cleared + * by SDHCI_UHS2_SW_RESET_SD + */ + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + + return 0; +} + +static int sdhci_uhs2_disable_clk(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + + clk &= ~SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + return 0; +} + +static int sdhci_uhs2_enable_clk(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + int timeout_us = 20000; /* 20ms */ + u32 val; + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + if (read_poll_timeout(sdhci_readw, val, (val & SDHCI_CLOCK_INT_STABLE), + 10, timeout_us, true, host, SDHCI_CLOCK_CONTROL)) { + pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return -EIO; + } + return 0; +} + +static void sdhci_uhs2_set_config(struct sdhci_host *host) +{ + u32 value; + u16 sdhci_uhs2_set_ptr = sdhci_readw(host, SDHCI_UHS2_SETTINGS_PTR); + u16 sdhci_uhs2_gen_set_reg = sdhci_uhs2_set_ptr; + u16 sdhci_uhs2_phy_set_reg = sdhci_uhs2_set_ptr + 4; + u16 sdhci_uhs2_tran_set_reg = sdhci_uhs2_set_ptr + 8; + u16 sdhci_uhs2_tran_set_1_reg = sdhci_uhs2_set_ptr + 12; + + /* Set Gen Settings */ + value = FIELD_PREP(SDHCI_UHS2_GEN_SETTINGS_N_LANES_MASK, host->mmc->uhs2_caps.n_lanes_set); + sdhci_writel(host, value, sdhci_uhs2_gen_set_reg); + + /* Set PHY Settings */ + value = FIELD_PREP(SDHCI_UHS2_PHY_N_LSS_DIR_MASK, host->mmc->uhs2_caps.n_lss_dir_set) | + FIELD_PREP(SDHCI_UHS2_PHY_N_LSS_SYN_MASK, host->mmc->uhs2_caps.n_lss_sync_set); + if (host->mmc->ios.timing == MMC_TIMING_UHS2_SPEED_B || + host->mmc->ios.timing == MMC_TIMING_UHS2_SPEED_B_HD) + value |= SDHCI_UHS2_PHY_SET_SPEED_B; + sdhci_writel(host, value, sdhci_uhs2_phy_set_reg); + + /* Set LINK-TRAN Settings */ + value = FIELD_PREP(SDHCI_UHS2_TRAN_RETRY_CNT_MASK, host->mmc->uhs2_caps.max_retry_set) | + FIELD_PREP(SDHCI_UHS2_TRAN_N_FCU_MASK, host->mmc->uhs2_caps.n_fcu_set); + sdhci_writel(host, value, sdhci_uhs2_tran_set_reg); + sdhci_writel(host, host->mmc->uhs2_caps.n_data_gap_set, sdhci_uhs2_tran_set_1_reg); +} + +static int sdhci_uhs2_check_dormant(struct sdhci_host *host) +{ + u32 val; + + if (read_poll_timeout(sdhci_readl, val, (val & SDHCI_UHS2_IN_DORMANT_STATE), + 100, UHS2_CHECK_DORMANT_TIMEOUT_100MS, true, host, + SDHCI_PRESENT_STATE)) { + pr_warn("%s: UHS2 IN_DORMANT fail in 100ms.\n", mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + return -EIO; + } + return 0; +} + +static int sdhci_uhs2_control(struct mmc_host *mmc, enum sd_uhs2_operation op) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct mmc_ios *ios = &mmc->ios; + int err = 0; + + DBG("Begin uhs2 control, act %d.\n", op); + + switch (op) { + case UHS2_PHY_INIT: + err = sdhci_uhs2_do_detect_init(mmc); + break; + case UHS2_SET_CONFIG: + sdhci_uhs2_set_config(host); + break; + case UHS2_ENABLE_INT: + sdhci_uhs2_clear_set_irqs(host, 0, SDHCI_INT_CARD_INT); + break; + case UHS2_DISABLE_INT: + sdhci_uhs2_clear_set_irqs(host, SDHCI_INT_CARD_INT, 0); + break; + case UHS2_CHECK_DORMANT: + err = sdhci_uhs2_check_dormant(host); + break; + case UHS2_DISABLE_CLK: + err = sdhci_uhs2_disable_clk(mmc); + break; + case UHS2_ENABLE_CLK: + err = sdhci_uhs2_enable_clk(mmc); + break; + case UHS2_SET_IOS: + err = sdhci_uhs2_set_ios(mmc, ios); + break; + default: + pr_err("%s: input sd uhs2 operation %d is wrong!\n", + mmc_hostname(host->mmc), op); + err = -EIO; + break; + } + + return err; +} + +/*****************************************************************************\ + * * + * Core functions * + * * +\*****************************************************************************/ + +static void sdhci_uhs2_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) +{ + struct mmc_data *data = cmd->data; + + sdhci_initialize_data(host, data); + + sdhci_prepare_dma(host, data); + + sdhci_writew(host, data->blksz, SDHCI_UHS2_BLOCK_SIZE); + sdhci_writew(host, data->blocks, SDHCI_UHS2_BLOCK_COUNT); +} + +static void sdhci_uhs2_finish_data(struct sdhci_host *host) +{ + struct mmc_data *data = host->data; + + __sdhci_finish_data_common(host, true); + + __sdhci_finish_mrq(host, data->mrq); +} + +static void sdhci_uhs2_set_transfer_mode(struct sdhci_host *host, struct mmc_command *cmd) +{ + u16 mode; + struct mmc_data *data = cmd->data; + + if (!data) { + /* clear Auto CMD settings for no data CMDs */ + if (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_TRANS_ABORT) { + mode = 0; + } else { + mode = sdhci_readw(host, SDHCI_UHS2_TRANS_MODE); + if (cmd->opcode == MMC_STOP_TRANSMISSION || cmd->opcode == MMC_ERASE) + mode |= SDHCI_UHS2_TRNS_WAIT_EBSY; + else + /* send status mode */ + if (cmd->opcode == MMC_SEND_STATUS) + mode = 0; + } + + DBG("UHS2 no data trans mode is 0x%x.\n", mode); + + sdhci_writew(host, mode, SDHCI_UHS2_TRANS_MODE); + return; + } + + WARN_ON(!host->data); + + mode = SDHCI_UHS2_TRNS_BLK_CNT_EN | SDHCI_UHS2_TRNS_WAIT_EBSY; + if (data->flags & MMC_DATA_WRITE) + mode |= SDHCI_UHS2_TRNS_DATA_TRNS_WRT; + + if (data->blocks == 1 && + data->blksz != 512 && + cmd->opcode != MMC_READ_SINGLE_BLOCK && + cmd->opcode != MMC_WRITE_BLOCK) { + mode &= ~SDHCI_UHS2_TRNS_BLK_CNT_EN; + mode |= SDHCI_UHS2_TRNS_BLK_BYTE_MODE; + } + + if (host->flags & SDHCI_REQ_USE_DMA) + mode |= SDHCI_UHS2_TRNS_DMA; + + if (cmd->uhs2_cmd->tmode_half_duplex) + mode |= SDHCI_UHS2_TRNS_2L_HD; + + sdhci_writew(host, mode, SDHCI_UHS2_TRANS_MODE); + + DBG("UHS2 trans mode is 0x%x.\n", mode); +} + +static void __sdhci_uhs2_send_command(struct sdhci_host *host, struct mmc_command *cmd) +{ + int i, j; + int cmd_reg; + + i = 0; + sdhci_writel(host, + ((u32)cmd->uhs2_cmd->arg << 16) | + (u32)cmd->uhs2_cmd->header, + SDHCI_UHS2_CMD_PACKET + i); + i += 4; + + /* + * Per spec, payload (config) should be MSB before sending out. + * But we don't need convert here because had set payload as + * MSB when preparing config read/write commands. + */ + for (j = 0; j < cmd->uhs2_cmd->payload_len / sizeof(u32); j++) { + sdhci_writel(host, *(__force u32 *)(cmd->uhs2_cmd->payload + j), + SDHCI_UHS2_CMD_PACKET + i); + i += 4; + } + + for ( ; i < SDHCI_UHS2_CMD_PACK_MAX_LEN; i += 4) + sdhci_writel(host, 0, SDHCI_UHS2_CMD_PACKET + i); + + DBG("UHS2 CMD packet_len = %d.\n", cmd->uhs2_cmd->packet_len); + for (i = 0; i < cmd->uhs2_cmd->packet_len; i++) + DBG("UHS2 CMD_PACKET[%d] = 0x%x.\n", i, + sdhci_readb(host, SDHCI_UHS2_CMD_PACKET + i)); + + cmd_reg = FIELD_PREP(SDHCI_UHS2_CMD_PACK_LEN_MASK, cmd->uhs2_cmd->packet_len); + if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) + cmd_reg |= SDHCI_UHS2_CMD_DATA; + if (cmd->opcode == MMC_STOP_TRANSMISSION) + cmd_reg |= SDHCI_UHS2_CMD_CMD12; + + /* UHS2 Native ABORT */ + if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) && + (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_TRANS_ABORT)) + cmd_reg |= SDHCI_UHS2_CMD_TRNS_ABORT; + + /* UHS2 Native DORMANT */ + if ((cmd->uhs2_cmd->header & UHS2_NATIVE_PACKET) && + (uhs2_dev_cmd(cmd) == UHS2_DEV_CMD_GO_DORMANT_STATE)) + cmd_reg |= SDHCI_UHS2_CMD_DORMANT; + + DBG("0x%x is set to UHS2 CMD register.\n", cmd_reg); + + sdhci_writew(host, cmd_reg, SDHCI_UHS2_CMD); +} + +static bool sdhci_uhs2_send_command(struct sdhci_host *host, struct mmc_command *cmd) +{ + u32 mask; + unsigned long timeout; + + WARN_ON(host->cmd); + + /* Initially, a command has no error */ + cmd->error = 0; + + if (cmd->opcode == MMC_STOP_TRANSMISSION) + cmd->flags |= MMC_RSP_BUSY; + + mask = SDHCI_CMD_INHIBIT; + + if (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) + return false; + + host->cmd = cmd; + host->data_timeout = 0; + if (sdhci_data_line_cmd(cmd)) { + WARN_ON(host->data_cmd); + host->data_cmd = cmd; + __sdhci_uhs2_set_timeout(host); + } + + if (cmd->data) + sdhci_uhs2_prepare_data(host, cmd); + + sdhci_uhs2_set_transfer_mode(host, cmd); + + timeout = jiffies; + if (host->data_timeout) + timeout += nsecs_to_jiffies(host->data_timeout); + else if (!cmd->data && cmd->busy_timeout > 9000) + timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ; + else + timeout += 10 * HZ; + sdhci_mod_timer(host, cmd->mrq, timeout); + + __sdhci_uhs2_send_command(host, cmd); + + return true; +} + +static bool sdhci_uhs2_send_command_retry(struct sdhci_host *host, + struct mmc_command *cmd, + unsigned long flags) + __releases(host->lock) + __acquires(host->lock) +{ + struct mmc_command *deferred_cmd = host->deferred_cmd; + int timeout = 10; /* Approx. 10 ms */ + bool present; + + while (!sdhci_uhs2_send_command(host, cmd)) { + if (!timeout--) { + pr_err("%s: Controller never released inhibit bit(s).\n", + mmc_hostname(host->mmc)); + sdhci_dumpregs(host); + cmd->error = -EIO; + return false; + } + + spin_unlock_irqrestore(&host->lock, flags); + + usleep_range(1000, 1250); + + present = host->mmc->ops->get_cd(host->mmc); + + spin_lock_irqsave(&host->lock, flags); + + /* A deferred command might disappear, handle that */ + if (cmd == deferred_cmd && cmd != host->deferred_cmd) + return true; + + if (sdhci_present_error(host, cmd, present)) + return false; + } + + if (cmd == host->deferred_cmd) + host->deferred_cmd = NULL; + + return true; +} + +static void __sdhci_uhs2_finish_command(struct sdhci_host *host) +{ + struct mmc_command *cmd = host->cmd; + u8 resp; + u8 error_code; + bool breada0 = 0; + int i; + + if (host->mmc->uhs2_sd_tran) { + resp = sdhci_readb(host, SDHCI_UHS2_RESPONSE + 2); + if (resp & UHS2_RES_NACK_MASK) { + error_code = (resp >> UHS2_RES_ECODE_POS) & UHS2_RES_ECODE_MASK; + pr_err("%s: NACK response, ECODE=0x%x.\n", + mmc_hostname(host->mmc), error_code); + } + breada0 = 1; + } + + if (cmd->uhs2_cmd->uhs2_resp_len) { + int len = min_t(int, cmd->uhs2_cmd->uhs2_resp_len, UHS2_MAX_RESP_LEN); + + /* Get whole response of some native CCMD, like + * DEVICE_INIT, ENUMERATE. + */ + for (i = 0; i < len; i++) + cmd->uhs2_cmd->uhs2_resp[i] = sdhci_readb(host, SDHCI_UHS2_RESPONSE + i); + } else { + /* Get SD CMD response and Payload for some read + * CCMD, like INQUIRY_CFG. + */ + /* Per spec (p136), payload field is divided into + * a unit of DWORD and transmission order within + * a DWORD is big endian. + */ + if (!breada0) + sdhci_readl(host, SDHCI_UHS2_RESPONSE); + for (i = 4; i < 20; i += 4) { + cmd->resp[i / 4 - 1] = + (sdhci_readb(host, + SDHCI_UHS2_RESPONSE + i) << 24) | + (sdhci_readb(host, + SDHCI_UHS2_RESPONSE + i + 1) + << 16) | + (sdhci_readb(host, + SDHCI_UHS2_RESPONSE + i + 2) + << 8) | + sdhci_readb(host, SDHCI_UHS2_RESPONSE + i + 3); + } + } +} + +static void sdhci_uhs2_finish_command(struct sdhci_host *host) +{ + struct mmc_command *cmd = host->cmd; + + __sdhci_uhs2_finish_command(host); + + host->cmd = NULL; + + if (cmd->mrq->cap_cmd_during_tfr && cmd == cmd->mrq->cmd) + mmc_command_done(host->mmc, cmd->mrq); + + /* + * The host can send and interrupt when the busy state has + * ended, allowing us to wait without wasting CPU cycles. + * The busy signal uses DAT0 so this is similar to waiting + * for data to complete. + * + * Note: The 1.0 specification is a bit ambiguous about this + * feature so there might be some problems with older + * controllers. + */ + if (cmd->flags & MMC_RSP_BUSY) { + if (cmd->data) { + DBG("Cannot wait for busy signal when also doing a data transfer"); + } else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) && + cmd == host->data_cmd) { + /* Command complete before busy is ended */ + return; + } + } + + /* Processed actual command. */ + if (host->data && host->data_early) + sdhci_uhs2_finish_data(host); + + if (!cmd->data) + __sdhci_finish_mrq(host, cmd->mrq); +} + +static void sdhci_uhs2_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct mmc_command *cmd; + unsigned long flags; + bool present; + + if (!(mmc_card_uhs2(mmc))) { + sdhci_request(mmc, mrq); + return; + } + + mrq->stop = NULL; + mrq->sbc = NULL; + if (mrq->data) + mrq->data->stop = NULL; + + /* Firstly check card presence */ + present = mmc->ops->get_cd(mmc); + + spin_lock_irqsave(&host->lock, flags); + + if (sdhci_present_error(host, mrq->cmd, present)) + goto out_finish; + + cmd = mrq->cmd; + + if (!sdhci_uhs2_send_command_retry(host, cmd, flags)) + goto out_finish; + + spin_unlock_irqrestore(&host->lock, flags); + + return; + +out_finish: + sdhci_finish_mrq(host, mrq); + spin_unlock_irqrestore(&host->lock, flags); +} + +/*****************************************************************************\ + * * + * Request done * + * * +\*****************************************************************************/ + +static bool sdhci_uhs2_needs_reset(struct sdhci_host *host, struct mmc_request *mrq) +{ + return sdhci_needs_reset(host, mrq) || + (!(host->flags & SDHCI_DEVICE_DEAD) && mrq->data && mrq->data->error); +} + +static bool sdhci_uhs2_request_done(struct sdhci_host *host) +{ + unsigned long flags; + struct mmc_request *mrq; + int i; + + spin_lock_irqsave(&host->lock, flags); + + for (i = 0; i < SDHCI_MAX_MRQS; i++) { + mrq = host->mrqs_done[i]; + if (mrq) + break; + } + + if (!mrq) { + spin_unlock_irqrestore(&host->lock, flags); + return true; + } + + /* + * Always unmap the data buffers if they were mapped by + * sdhci_prepare_data() whenever we finish with a request. + * This avoids leaking DMA mappings on error. + */ + if (host->flags & SDHCI_REQ_USE_DMA) + sdhci_request_done_dma(host, mrq); + + /* + * The controller needs a reset of internal state machines + * upon error conditions. + */ + if (sdhci_uhs2_needs_reset(host, mrq)) { + /* + * Do not finish until command and data lines are available for + * reset. Note there can only be one other mrq, so it cannot + * also be in mrqs_done, otherwise host->cmd and host->data_cmd + * would both be null. + */ + if (host->cmd || host->data_cmd) { + spin_unlock_irqrestore(&host->lock, flags); + return true; + } + + if (mrq->cmd->error || mrq->data->error) + sdhci_uhs2_reset_cmd_data(host); + else + sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD); + host->pending_reset = false; + } + + host->mrqs_done[i] = NULL; + + spin_unlock_irqrestore(&host->lock, flags); + + if (host->ops->request_done) + host->ops->request_done(host, mrq); + else + mmc_request_done(host->mmc, mrq); + + return false; +} + +static void sdhci_uhs2_complete_work(struct work_struct *work) +{ + struct sdhci_host *host = container_of(work, struct sdhci_host, + complete_work); + + if (!mmc_card_uhs2(host->mmc)) { + sdhci_complete_work(work); + return; + } + + while (!sdhci_uhs2_request_done(host)) + ; +} + +/*****************************************************************************\ + * * + * Interrupt handling * + * * +\*****************************************************************************/ + +static void __sdhci_uhs2_irq(struct sdhci_host *host, u32 uhs2mask) +{ + struct mmc_command *cmd = host->cmd; + + DBG("*** %s got UHS2 error interrupt: 0x%08x\n", + mmc_hostname(host->mmc), uhs2mask); + + if (uhs2mask & SDHCI_UHS2_INT_CMD_ERR_MASK) { + if (!host->cmd) { + pr_err("%s: Got cmd interrupt 0x%08x but no cmd.\n", + mmc_hostname(host->mmc), + (unsigned int)uhs2mask); + sdhci_dumpregs(host); + return; + } + host->cmd->error = -EILSEQ; + if (uhs2mask & SDHCI_UHS2_INT_CMD_TIMEOUT) + host->cmd->error = -ETIMEDOUT; + } + + if (uhs2mask & SDHCI_UHS2_INT_DATA_ERR_MASK) { + if (!host->data) { + pr_err("%s: Got data interrupt 0x%08x but no data.\n", + mmc_hostname(host->mmc), + (unsigned int)uhs2mask); + sdhci_dumpregs(host); + return; + } + + if (uhs2mask & SDHCI_UHS2_INT_DEADLOCK_TIMEOUT) { + pr_err("%s: Got deadlock timeout interrupt 0x%08x\n", + mmc_hostname(host->mmc), + (unsigned int)uhs2mask); + host->data->error = -ETIMEDOUT; + } else if (uhs2mask & SDHCI_UHS2_INT_ADMA_ERROR) { + pr_err("%s: ADMA error = 0x %x\n", + mmc_hostname(host->mmc), + sdhci_readb(host, SDHCI_ADMA_ERROR)); + host->data->error = -EIO; + } else { + host->data->error = -EILSEQ; + } + } + + if (host->data && host->data->error) + sdhci_uhs2_finish_data(host); + else + sdhci_finish_mrq(host, cmd->mrq); + +} + +u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask) +{ + u32 mask = intmask, uhs2mask; + + if (!mmc_card_uhs2(host->mmc)) + goto out; + + if (intmask & SDHCI_INT_ERROR) { + uhs2mask = sdhci_readl(host, SDHCI_UHS2_INT_STATUS); + if (!(uhs2mask & SDHCI_UHS2_INT_ERROR_MASK)) + goto cmd_irq; + + /* Clear error interrupts */ + sdhci_writel(host, uhs2mask & SDHCI_UHS2_INT_ERROR_MASK, + SDHCI_UHS2_INT_STATUS); + + /* Handle error interrupts */ + __sdhci_uhs2_irq(host, uhs2mask); + + /* Caller, sdhci_irq(), doesn't have to care about UHS-2 errors */ + intmask &= ~SDHCI_INT_ERROR; + mask &= SDHCI_INT_ERROR; + } + +cmd_irq: + if (intmask & SDHCI_INT_CMD_MASK) { + /* Clear command interrupt */ + sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS); + + /* Handle command interrupt */ + if (intmask & SDHCI_INT_RESPONSE) + sdhci_uhs2_finish_command(host); + + /* Caller, sdhci_irq(), doesn't have to care about UHS-2 commands */ + intmask &= ~SDHCI_INT_CMD_MASK; + mask &= SDHCI_INT_CMD_MASK; + } + + /* Clear already-handled interrupts. */ + sdhci_writel(host, mask, SDHCI_INT_STATUS); + +out: + return intmask; +} +EXPORT_SYMBOL_GPL(sdhci_uhs2_irq); + +static irqreturn_t sdhci_uhs2_thread_irq(int irq, void *dev_id) +{ + struct sdhci_host *host = dev_id; + struct mmc_command *cmd; + unsigned long flags; + u32 isr; + + if (!mmc_card_uhs2(host->mmc)) + return sdhci_thread_irq(irq, dev_id); + + while (!sdhci_uhs2_request_done(host)) + ; + + spin_lock_irqsave(&host->lock, flags); + + isr = host->thread_isr; + host->thread_isr = 0; + + cmd = host->deferred_cmd; + if (cmd && !sdhci_uhs2_send_command_retry(host, cmd, flags)) + sdhci_finish_mrq(host, cmd->mrq); + + spin_unlock_irqrestore(&host->lock, flags); + + if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { + struct mmc_host *mmc = host->mmc; + + mmc->ops->card_event(mmc); + mmc_detect_change(mmc, msecs_to_jiffies(200)); + } + + return IRQ_HANDLED; +} + +/*****************************************************************************\ + * * + * Driver init/exit * + * * +\*****************************************************************************/ + +static int sdhci_uhs2_host_ops_init(struct sdhci_host *host) +{ + host->mmc_host_ops.uhs2_control = sdhci_uhs2_control; + host->mmc_host_ops.request = sdhci_uhs2_request; + + return 0; +} + +static int __init sdhci_uhs2_mod_init(void) +{ + return 0; +} +module_init(sdhci_uhs2_mod_init); + +static void __exit sdhci_uhs2_mod_exit(void) +{ +} +module_exit(sdhci_uhs2_mod_exit); + +/*****************************************************************************\ + * + * Device allocation/registration * + * * +\*****************************************************************************/ + +static void __sdhci_uhs2_add_host_v4(struct sdhci_host *host, u32 caps1) +{ + struct mmc_host *mmc; + u32 max_current_caps2; + + mmc = host->mmc; + + /* Support UHS2 */ + if (caps1 & SDHCI_SUPPORT_UHS2) + mmc->caps2 |= MMC_CAP2_SD_UHS2; + + max_current_caps2 = sdhci_readl(host, SDHCI_MAX_CURRENT_1); + + if ((caps1 & SDHCI_CAN_VDD2_180) && + !max_current_caps2 && + !IS_ERR(mmc->supply.vqmmc2)) { + /* UHS2 - VDD2 */ + int curr = regulator_get_current_limit(mmc->supply.vqmmc2); + + if (curr > 0) { + /* convert to SDHCI_MAX_CURRENT format */ + curr = curr / 1000; /* convert to mA */ + curr = curr / SDHCI_MAX_CURRENT_MULTIPLIER; + curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT); + max_current_caps2 = curr; + } + } + + if (!(caps1 & SDHCI_CAN_VDD2_180)) + mmc->caps2 &= ~MMC_CAP2_SD_UHS2; +} + +static void __sdhci_uhs2_remove_host(struct sdhci_host *host, int dead) +{ + if (!mmc_card_uhs2(host->mmc)) + return; + + if (!dead) + sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_FULL); +} + +int sdhci_uhs2_add_host(struct sdhci_host *host) +{ + struct mmc_host *mmc = host->mmc; + int ret; + + ret = sdhci_setup_host(host); + if (ret) + return ret; + + if (host->version >= SDHCI_SPEC_400) + __sdhci_uhs2_add_host_v4(host, host->caps1); + + if ((mmc->caps2 & MMC_CAP2_SD_UHS2) && !host->v4_mode) + /* host doesn't want to enable UHS2 support */ + mmc->caps2 &= ~MMC_CAP2_SD_UHS2; + + /* overwrite ops */ + if (mmc->caps2 & MMC_CAP2_SD_UHS2) + sdhci_uhs2_host_ops_init(host); + + host->complete_work_fn = sdhci_uhs2_complete_work; + host->thread_irq_fn = sdhci_uhs2_thread_irq; + + /* LED support not implemented for UHS2 */ + host->quirks |= SDHCI_QUIRK_NO_LED; + + ret = __sdhci_add_host(host); + if (ret) + goto cleanup; + + return 0; + +cleanup: + if (host->version >= SDHCI_SPEC_400) + __sdhci_uhs2_remove_host(host, 0); + + sdhci_cleanup_host(host); + + return ret; +} +EXPORT_SYMBOL_GPL(sdhci_uhs2_add_host); + +void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead) +{ + __sdhci_uhs2_remove_host(host, dead); + + sdhci_remove_host(host, dead); +} +EXPORT_SYMBOL_GPL(sdhci_uhs2_remove_host); + +MODULE_AUTHOR("Intel, Genesys Logic, Linaro"); +MODULE_DESCRIPTION("MMC UHS-II Support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h new file mode 100644 index 00000000000000..da69059196301b --- /dev/null +++ b/drivers/mmc/host/sdhci-uhs2.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Header file for Host Controller UHS2 related registers. + * + * Copyright (C) 2014 Intel Corp, All Rights Reserved. + */ +#ifndef __SDHCI_UHS2_H +#define __SDHCI_UHS2_H + +#include + +/* SDHCI Category C registers : UHS2 usage */ + +#define SDHCI_UHS2_CM_TRAN_RESP 0x10 +#define SDHCI_UHS2_SD_TRAN_RESP 0x18 +#define SDHCI_UHS2_SD_TRAN_RESP_1 0x1C + +/* SDHCI Category B registers : UHS2 only */ + +#define SDHCI_UHS2_BLOCK_SIZE 0x80 +#define SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF)) + +#define SDHCI_UHS2_BLOCK_COUNT 0x84 + +#define SDHCI_UHS2_CMD_PACKET 0x88 +#define SDHCI_UHS2_CMD_PACK_MAX_LEN 20 + +#define SDHCI_UHS2_TRANS_MODE 0x9C +#define SDHCI_UHS2_TRNS_DMA BIT(0) +#define SDHCI_UHS2_TRNS_BLK_CNT_EN BIT(1) +#define SDHCI_UHS2_TRNS_DATA_TRNS_WRT BIT(4) +#define SDHCI_UHS2_TRNS_BLK_BYTE_MODE BIT(5) +#define SDHCI_UHS2_TRNS_RES_R5 BIT(6) +#define SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN BIT(7) +#define SDHCI_UHS2_TRNS_RES_INT_DIS BIT(8) +#define SDHCI_UHS2_TRNS_WAIT_EBSY BIT(14) +#define SDHCI_UHS2_TRNS_2L_HD BIT(15) + +#define SDHCI_UHS2_CMD 0x9E +#define SDHCI_UHS2_CMD_SUB_CMD BIT(2) +#define SDHCI_UHS2_CMD_DATA BIT(5) +#define SDHCI_UHS2_CMD_TRNS_ABORT BIT(6) +#define SDHCI_UHS2_CMD_CMD12 BIT(7) +#define SDHCI_UHS2_CMD_DORMANT GENMASK(7, 6) +#define SDHCI_UHS2_CMD_PACK_LEN_MASK GENMASK(12, 8) + +#define SDHCI_UHS2_RESPONSE 0xA0 +#define SDHCI_UHS2_RESPONSE_MAX_LEN 20 + +#define SDHCI_UHS2_MSG_SELECT 0xB4 +#define SDHCI_UHS2_MSG_SELECT_CURR 0x0 +#define SDHCI_UHS2_MSG_SELECT_ONE 0x1 +#define SDHCI_UHS2_MSG_SELECT_TWO 0x2 +#define SDHCI_UHS2_MSG_SELECT_THREE 0x3 + +#define SDHCI_UHS2_MSG 0xB8 + +#define SDHCI_UHS2_DEV_INT_STATUS 0xBC + +#define SDHCI_UHS2_DEV_SELECT 0xBE +#define SDHCI_UHS2_DEV_SEL_MASK GENMASK(3, 0) +#define SDHCI_UHS2_DEV_SEL_INT_MSG_EN BIT(7) + +#define SDHCI_UHS2_DEV_INT_CODE 0xBF + +#define SDHCI_UHS2_SW_RESET 0xC0 +#define SDHCI_UHS2_SW_RESET_FULL BIT(0) +#define SDHCI_UHS2_SW_RESET_SD BIT(1) + +#define SDHCI_UHS2_TIMER_CTRL 0xC2 +#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_MASK GENMASK(7, 4) + +#define SDHCI_UHS2_INT_STATUS 0xC4 +#define SDHCI_UHS2_INT_STATUS_ENABLE 0xC8 +#define SDHCI_UHS2_INT_SIGNAL_ENABLE 0xCC +#define SDHCI_UHS2_INT_HEADER_ERR BIT(0) +#define SDHCI_UHS2_INT_RES_ERR BIT(1) +#define SDHCI_UHS2_INT_RETRY_EXP BIT(2) +#define SDHCI_UHS2_INT_CRC BIT(3) +#define SDHCI_UHS2_INT_FRAME_ERR BIT(4) +#define SDHCI_UHS2_INT_TID_ERR BIT(5) +#define SDHCI_UHS2_INT_UNRECOVER BIT(7) +#define SDHCI_UHS2_INT_EBUSY_ERR BIT(8) +#define SDHCI_UHS2_INT_ADMA_ERROR BIT(15) +#define SDHCI_UHS2_INT_CMD_TIMEOUT BIT(16) +#define SDHCI_UHS2_INT_DEADLOCK_TIMEOUT BIT(17) +#define SDHCI_UHS2_INT_VENDOR_ERR BIT(27) +#define SDHCI_UHS2_INT_ERROR_MASK ( \ + SDHCI_UHS2_INT_HEADER_ERR | \ + SDHCI_UHS2_INT_RES_ERR | \ + SDHCI_UHS2_INT_RETRY_EXP | \ + SDHCI_UHS2_INT_CRC | \ + SDHCI_UHS2_INT_FRAME_ERR | \ + SDHCI_UHS2_INT_TID_ERR | \ + SDHCI_UHS2_INT_UNRECOVER | \ + SDHCI_UHS2_INT_EBUSY_ERR | \ + SDHCI_UHS2_INT_ADMA_ERROR | \ + SDHCI_UHS2_INT_CMD_TIMEOUT | \ + SDHCI_UHS2_INT_DEADLOCK_TIMEOUT) +#define SDHCI_UHS2_INT_CMD_ERR_MASK ( \ + SDHCI_UHS2_INT_HEADER_ERR | \ + SDHCI_UHS2_INT_RES_ERR | \ + SDHCI_UHS2_INT_FRAME_ERR | \ + SDHCI_UHS2_INT_TID_ERR | \ + SDHCI_UHS2_INT_CMD_TIMEOUT) +/* CRC Error occurs during a packet receiving */ +#define SDHCI_UHS2_INT_DATA_ERR_MASK ( \ + SDHCI_UHS2_INT_RETRY_EXP | \ + SDHCI_UHS2_INT_CRC | \ + SDHCI_UHS2_INT_UNRECOVER | \ + SDHCI_UHS2_INT_EBUSY_ERR | \ + SDHCI_UHS2_INT_ADMA_ERROR | \ + SDHCI_UHS2_INT_DEADLOCK_TIMEOUT) + +#define SDHCI_UHS2_SETTINGS_PTR 0xE0 +#define SDHCI_UHS2_GEN_SETTINGS_POWER_LOW BIT(0) +#define SDHCI_UHS2_GEN_SETTINGS_N_LANES_MASK GENMASK(11, 8) +#define SDHCI_UHS2_FD_OR_2L_HD 0x0 /* 2 lanes */ +#define SDHCI_UHS2_2D1U_FD 0x2 /* 3 lanes, 2 down, 1 up, full duplex */ +#define SDHCI_UHS2_1D2U_FD 0x3 /* 3 lanes, 1 down, 2 up, full duplex */ +#define SDHCI_UHS2_2D2U_FD 0x4 /* 4 lanes, 2 down, 2 up, full duplex */ + +#define SDHCI_UHS2_PHY_SET_SPEED_B BIT(6) +#define SDHCI_UHS2_PHY_HIBERNATE_EN BIT(12) +#define SDHCI_UHS2_PHY_N_LSS_SYN_MASK GENMASK(19, 16) +#define SDHCI_UHS2_PHY_N_LSS_DIR_MASK GENMASK(23, 20) + +#define SDHCI_UHS2_TRAN_N_FCU_MASK GENMASK(15, 8) +#define SDHCI_UHS2_TRAN_RETRY_CNT_MASK GENMASK(17, 16) +#define SDHCI_UHS2_TRAN_1_N_DAT_GAP_MASK GENMASK(7, 0) + +#define SDHCI_UHS2_CAPS_PTR 0xE2 +#define SDHCI_UHS2_CAPS_OFFSET 0 +#define SDHCI_UHS2_CAPS_DAP_MASK GENMASK(3, 0) +#define SDHCI_UHS2_CAPS_GAP_MASK GENMASK(7, 4) +#define SDHCI_UHS2_CAPS_GAP(gap) ((gap) * 360) +#define SDHCI_UHS2_CAPS_LANE_MASK GENMASK(13, 8) +#define SDHCI_UHS2_CAPS_2L_HD_FD 1 +#define SDHCI_UHS2_CAPS_2D1U_FD 2 +#define SDHCI_UHS2_CAPS_1D2U_FD 4 +#define SDHCI_UHS2_CAPS_2D2U_FD 8 +#define SDHCI_UHS2_CAPS_ADDR_64 BIT(14) +#define SDHCI_UHS2_CAPS_BOOT BIT(15) +#define SDHCI_UHS2_CAPS_DEV_TYPE_MASK GENMASK(17, 16) +#define SDHCI_UHS2_CAPS_DEV_TYPE_RMV 0 +#define SDHCI_UHS2_CAPS_DEV_TYPE_EMB 1 +#define SDHCI_UHS2_CAPS_DEV_TYPE_EMB_RMV 2 +#define SDHCI_UHS2_CAPS_NUM_DEV_MASK GENMASK(21, 18) +#define SDHCI_UHS2_CAPS_BUS_TOPO_MASK GENMASK(23, 22) +#define SDHCI_UHS2_CAPS_BUS_TOPO_SHIFT 22 +#define SDHCI_UHS2_CAPS_BUS_TOPO_P2P 0 +#define SDHCI_UHS2_CAPS_BUS_TOPO_RING 1 +#define SDHCI_UHS2_CAPS_BUS_TOPO_HUB 2 +#define SDHCI_UHS2_CAPS_BUS_TOPO_HUB_RING 3 + +#define SDHCI_UHS2_CAPS_PHY_OFFSET 4 +#define SDHCI_UHS2_CAPS_PHY_REV_MASK GENMASK(5, 0) +#define SDHCI_UHS2_CAPS_PHY_RANGE_MASK GENMASK(7, 6) +#define SDHCI_UHS2_CAPS_PHY_RANGE_A 0 +#define SDHCI_UHS2_CAPS_PHY_RANGE_B 1 +#define SDHCI_UHS2_CAPS_PHY_N_LSS_SYN_MASK GENMASK(19, 16) +#define SDHCI_UHS2_CAPS_PHY_N_LSS_DIR_MASK GENMASK(23, 20) +#define SDHCI_UHS2_CAPS_TRAN_OFFSET 8 +#define SDHCI_UHS2_CAPS_TRAN_LINK_REV_MASK GENMASK(5, 0) +#define SDHCI_UHS2_CAPS_TRAN_N_FCU_MASK GENMASK(15, 8) +#define SDHCI_UHS2_CAPS_TRAN_HOST_TYPE_MASK GENMASK(18, 16) +#define SDHCI_UHS2_CAPS_TRAN_BLK_LEN_MASK GENMASK(31, 20) + +#define SDHCI_UHS2_CAPS_TRAN_1_OFFSET 12 +#define SDHCI_UHS2_CAPS_TRAN_1_N_DATA_GAP_MASK GENMASK(7, 0) + +#define SDHCI_UHS2_EMBED_CTRL_PTR 0xE6 +#define SDHCI_UHS2_VENDOR_PTR 0xE8 + +struct sdhci_host; +struct mmc_command; +struct mmc_request; + +void sdhci_uhs2_dump_regs(struct sdhci_host *host); +void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask); +void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd); +void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd); +int sdhci_uhs2_add_host(struct sdhci_host *host); +void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead); +void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set); +u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask); + +#endif /* __SDHCI_UHS2_H */ diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index 0e52867f6e91cf..098f0ea45cbe29 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c @@ -734,7 +734,7 @@ static struct platform_driver sdhci_xenon_driver = { .pm = &sdhci_xenon_dev_pm_ops, }, .probe = xenon_probe, - .remove_new = xenon_remove, + .remove = xenon_remove, }; module_platform_driver(sdhci_xenon_driver); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4b91c9e9663575..f4a7733a8ad22f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include @@ -47,8 +47,6 @@ static unsigned int debug_quirks = 0; static unsigned int debug_quirks2; -static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); - static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd); void sdhci_dumpregs(struct sdhci_host *host) @@ -110,6 +108,9 @@ void sdhci_dumpregs(struct sdhci_host *host) } } + if (host->ops->dump_uhs2_regs) + host->ops->dump_uhs2_regs(host); + if (host->ops->dump_vendor_regs) host->ops->dump_vendor_regs(host); @@ -146,10 +147,11 @@ void sdhci_enable_v4_mode(struct sdhci_host *host) } EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode); -static inline bool sdhci_data_line_cmd(struct mmc_command *cmd) +bool sdhci_data_line_cmd(struct mmc_command *cmd) { return cmd->data || cmd->flags & MMC_RSP_BUSY; } +EXPORT_SYMBOL_GPL(sdhci_data_line_cmd); static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) { @@ -233,7 +235,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) } EXPORT_SYMBOL_GPL(sdhci_reset); -static bool sdhci_do_reset(struct sdhci_host *host, u8 mask) +bool sdhci_do_reset(struct sdhci_host *host, u8 mask) { if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { struct mmc_host *mmc = host->mmc; @@ -246,6 +248,7 @@ static bool sdhci_do_reset(struct sdhci_host *host, u8 mask) return true; } +EXPORT_SYMBOL_GPL(sdhci_do_reset); static void sdhci_reset_for_all(struct sdhci_host *host) { @@ -501,14 +504,15 @@ static inline void sdhci_led_deactivate(struct sdhci_host *host) #endif -static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, - unsigned long timeout) +void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, + unsigned long timeout) { if (sdhci_data_line_cmd(mrq->cmd)) mod_timer(&host->data_timer, timeout); else mod_timer(&host->timer, timeout); } +EXPORT_SYMBOL_GPL(sdhci_mod_timer); static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) { @@ -1075,8 +1079,7 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) __sdhci_set_timeout(host, cmd); } -static void sdhci_initialize_data(struct sdhci_host *host, - struct mmc_data *data) +void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data) { WARN_ON(host->data); @@ -1089,6 +1092,7 @@ static void sdhci_initialize_data(struct sdhci_host *host, host->data_early = 0; host->data->bytes_xfered = 0; } +EXPORT_SYMBOL_GPL(sdhci_initialize_data); static inline void sdhci_set_block_info(struct sdhci_host *host, struct mmc_data *data) @@ -1111,12 +1115,8 @@ static inline void sdhci_set_block_info(struct sdhci_host *host, } } -static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) +void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data) { - struct mmc_data *data = cmd->data; - - sdhci_initialize_data(host, data); - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { struct scatterlist *sg; unsigned int length_mask, offset_mask; @@ -1201,6 +1201,16 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) } sdhci_set_transfer_irqs(host); +} +EXPORT_SYMBOL_GPL(sdhci_prepare_dma); + +static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) +{ + struct mmc_data *data = cmd->data; + + sdhci_initialize_data(host, data); + + sdhci_prepare_dma(host, data); sdhci_set_block_info(host, data); } @@ -1488,7 +1498,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); } -static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq) +bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq) { return (!(host->flags & SDHCI_DEVICE_DEAD) && ((mrq->cmd && mrq->cmd->error) || @@ -1496,6 +1506,7 @@ static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq) (mrq->data && mrq->data->stop && mrq->data->stop->error) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))); } +EXPORT_SYMBOL_GPL(sdhci_needs_reset); static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq) { @@ -1518,7 +1529,7 @@ static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq) WARN_ON(i >= SDHCI_MAX_MRQS); } -static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) +void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) { if (host->cmd && host->cmd->mrq == mrq) host->cmd = NULL; @@ -1542,15 +1553,17 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) if (!sdhci_has_requests(host)) sdhci_led_deactivate(host); } +EXPORT_SYMBOL_GPL(__sdhci_finish_mrq); -static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) +void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq) { __sdhci_finish_mrq(host, mrq); queue_work(host->complete_wq, &host->complete_work); } +EXPORT_SYMBOL_GPL(sdhci_finish_mrq); -static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout) +void __sdhci_finish_data_common(struct sdhci_host *host, bool defer_reset) { struct mmc_command *data_cmd = host->data_cmd; struct mmc_data *data = host->data; @@ -1563,7 +1576,9 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout) * conditions. */ if (data->error) { - if (!host->cmd || host->cmd == data_cmd) + if (defer_reset) + host->pending_reset = true; + else if (!host->cmd || host->cmd == data_cmd) sdhci_reset_for(host, REQUEST_ERROR); else sdhci_reset_for(host, REQUEST_ERROR_DATA_ONLY); @@ -1584,6 +1599,14 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout) data->bytes_xfered = 0; else data->bytes_xfered = data->blksz * data->blocks; +} +EXPORT_SYMBOL_GPL(__sdhci_finish_data_common); + +static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout) +{ + struct mmc_data *data = host->data; + + __sdhci_finish_data_common(host, false); /* * Need to send CMD12 if - @@ -1718,8 +1741,8 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) return true; } -static bool sdhci_present_error(struct sdhci_host *host, - struct mmc_command *cmd, bool present) +bool sdhci_present_error(struct sdhci_host *host, + struct mmc_command *cmd, bool present) { if (!present || host->flags & SDHCI_DEVICE_DEAD) { cmd->error = -ENOMEDIUM; @@ -1728,6 +1751,7 @@ static bool sdhci_present_error(struct sdhci_host *host, return false; } +EXPORT_SYMBOL_GPL(sdhci_present_error); static bool sdhci_send_command_retry(struct sdhci_host *host, struct mmc_command *cmd, @@ -1874,6 +1898,12 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host) case MMC_TIMING_MMC_HS400: preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400); break; + case MMC_TIMING_UHS2_SPEED_A: + case MMC_TIMING_UHS2_SPEED_A_HD: + case MMC_TIMING_UHS2_SPEED_B: + case MMC_TIMING_UHS2_SPEED_B_HD: + preset = sdhci_readw(host, SDHCI_PRESET_FOR_UHS2); + break; default: pr_warn("%s: Invalid UHS-I mode selected\n", mmc_hostname(host->mmc)); @@ -2058,41 +2088,46 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode, sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); } +unsigned short sdhci_get_vdd_value(unsigned short vdd) +{ + switch (1 << vdd) { + case MMC_VDD_165_195: + /* + * Without a regulator, SDHCI does not support 2.0v + * so we only get here if the driver deliberately + * added the 2.0v range to ocr_avail. Map it to 1.8v + * for the purpose of turning on the power. + */ + case MMC_VDD_20_21: + return SDHCI_POWER_180; + case MMC_VDD_29_30: + case MMC_VDD_30_31: + return SDHCI_POWER_300; + case MMC_VDD_32_33: + case MMC_VDD_33_34: + /* + * 3.4V ~ 3.6V are valid only for those platforms where it's + * known that the voltage range is supported by hardware. + */ + case MMC_VDD_34_35: + case MMC_VDD_35_36: + return SDHCI_POWER_330; + default: + return 0; + } +} +EXPORT_SYMBOL_GPL(sdhci_get_vdd_value); + void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, unsigned short vdd) { u8 pwr = 0; if (mode != MMC_POWER_OFF) { - switch (1 << vdd) { - case MMC_VDD_165_195: - /* - * Without a regulator, SDHCI does not support 2.0v - * so we only get here if the driver deliberately - * added the 2.0v range to ocr_avail. Map it to 1.8v - * for the purpose of turning on the power. - */ - case MMC_VDD_20_21: - pwr = SDHCI_POWER_180; - break; - case MMC_VDD_29_30: - case MMC_VDD_30_31: - pwr = SDHCI_POWER_300; - break; - case MMC_VDD_32_33: - case MMC_VDD_33_34: - /* - * 3.4 ~ 3.6V are valid only for those platforms where it's - * known that the voltage range is supported by hardware. - */ - case MMC_VDD_34_35: - case MMC_VDD_35_36: - pwr = SDHCI_POWER_330; - break; - default: + pwr = sdhci_get_vdd_value(vdd); + if (!pwr) { WARN(1, "%s: Invalid vdd %#x\n", mmc_hostname(host->mmc), vdd); - break; } } @@ -2315,24 +2350,9 @@ static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_i (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type); } -void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios) { struct sdhci_host *host = mmc_priv(mmc); - bool reinit_uhs = host->reinit_uhs; - bool turning_on_clk = false; - u8 ctrl; - - host->reinit_uhs = false; - - if (ios->power_mode == MMC_POWER_UNDEFINED) - return; - - if (host->flags & SDHCI_DEVICE_DEAD) { - if (!IS_ERR(mmc->supply.vmmc) && - ios->power_mode == MMC_POWER_OFF) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); - return; - } /* * Reset the chip on each power off. @@ -2349,8 +2369,6 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_enable_preset_value(host, false); if (!ios->clock || ios->clock != host->clock) { - turning_on_clk = ios->clock && !host->clock; - host->ops->set_clock(host, ios->clock); host->clock = ios->clock; @@ -2366,6 +2384,31 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mmc->max_busy_timeout /= host->timeout_clk; } } +} +EXPORT_SYMBOL_GPL(sdhci_set_ios_common); + +void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + bool reinit_uhs = host->reinit_uhs; + bool turning_on_clk; + u8 ctrl; + + host->reinit_uhs = false; + + if (ios->power_mode == MMC_POWER_UNDEFINED) + return; + + if (host->flags & SDHCI_DEVICE_DEAD) { + if (!IS_ERR(mmc->supply.vmmc) && + ios->power_mode == MMC_POWER_OFF) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + return; + } + + turning_on_clk = ios->clock != host->clock && ios->clock && !host->clock; + + sdhci_set_ios_common(mmc, ios); if (host->ops->set_power) host->ops->set_power(host, ios->power_mode, ios->vdd); @@ -2934,7 +2977,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) } EXPORT_SYMBOL_GPL(sdhci_execute_tuning); -static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) +void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) { /* Host Controller v3.00 defines preset value registers */ if (host->version < SDHCI_SPEC_300) @@ -2962,6 +3005,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable) host->preset_enabled = enable; } } +EXPORT_SYMBOL_GPL(sdhci_enable_preset_value); static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err) @@ -3055,6 +3099,53 @@ static const struct mmc_host_ops sdhci_ops = { * * \*****************************************************************************/ +void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq) +{ + struct mmc_data *data = mrq->data; + + if (data && data->host_cookie == COOKIE_MAPPED) { + if (host->bounce_buffer) { + /* + * On reads, copy the bounced data into the + * sglist + */ + if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) { + unsigned int length = data->bytes_xfered; + + if (length > host->bounce_buffer_size) { + pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n", + mmc_hostname(host->mmc), + host->bounce_buffer_size, + data->bytes_xfered); + /* Cap it down and continue */ + length = host->bounce_buffer_size; + } + dma_sync_single_for_cpu(mmc_dev(host->mmc), + host->bounce_addr, + host->bounce_buffer_size, + DMA_FROM_DEVICE); + sg_copy_from_buffer(data->sg, + data->sg_len, + host->bounce_buffer, + length); + } else { + /* No copying, just switch ownership */ + dma_sync_single_for_cpu(mmc_dev(host->mmc), + host->bounce_addr, + host->bounce_buffer_size, + mmc_get_dma_dir(data)); + } + } else { + /* Unmap the raw data */ + dma_unmap_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, + mmc_get_dma_dir(data)); + } + data->host_cookie = COOKIE_UNMAPPED; + } +} +EXPORT_SYMBOL_GPL(sdhci_request_done_dma); + static bool sdhci_request_done(struct sdhci_host *host) { unsigned long flags; @@ -3119,48 +3210,7 @@ static bool sdhci_request_done(struct sdhci_host *host) sdhci_set_mrq_done(host, mrq); } - if (data && data->host_cookie == COOKIE_MAPPED) { - if (host->bounce_buffer) { - /* - * On reads, copy the bounced data into the - * sglist - */ - if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) { - unsigned int length = data->bytes_xfered; - - if (length > host->bounce_buffer_size) { - pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n", - mmc_hostname(host->mmc), - host->bounce_buffer_size, - data->bytes_xfered); - /* Cap it down and continue */ - length = host->bounce_buffer_size; - } - dma_sync_single_for_cpu( - mmc_dev(host->mmc), - host->bounce_addr, - host->bounce_buffer_size, - DMA_FROM_DEVICE); - sg_copy_from_buffer(data->sg, - data->sg_len, - host->bounce_buffer, - length); - } else { - /* No copying, just switch ownership */ - dma_sync_single_for_cpu( - mmc_dev(host->mmc), - host->bounce_addr, - host->bounce_buffer_size, - mmc_get_dma_dir(data)); - } - } else { - /* Unmap the raw data */ - dma_unmap_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, - mmc_get_dma_dir(data)); - } - data->host_cookie = COOKIE_UNMAPPED; - } + sdhci_request_done_dma(host, mrq); } host->mrqs_done[i] = NULL; @@ -3175,7 +3225,7 @@ static bool sdhci_request_done(struct sdhci_host *host) return false; } -static void sdhci_complete_work(struct work_struct *work) +void sdhci_complete_work(struct work_struct *work) { struct sdhci_host *host = container_of(work, struct sdhci_host, complete_work); @@ -3183,6 +3233,7 @@ static void sdhci_complete_work(struct work_struct *work) while (!sdhci_request_done(host)) ; } +EXPORT_SYMBOL_GPL(sdhci_complete_work); static void sdhci_timeout_timer(struct timer_list *t) { @@ -3644,7 +3695,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) return result; } -static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) +irqreturn_t sdhci_thread_irq(int irq, void *dev_id) { struct sdhci_host *host = dev_id; struct mmc_command *cmd; @@ -3674,6 +3725,7 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(sdhci_thread_irq); /*****************************************************************************\ * * @@ -4046,6 +4098,9 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, host->max_timeout_count = 0xE; + host->complete_work_fn = sdhci_complete_work; + host->thread_irq_fn = sdhci_thread_irq; + return host; } @@ -4810,7 +4865,7 @@ int __sdhci_add_host(struct sdhci_host *host) if (!host->complete_wq) return -ENOMEM; - INIT_WORK(&host->complete_work, sdhci_complete_work); + INIT_WORK(&host->complete_work, host->complete_work_fn); timer_setup(&host->timer, sdhci_timeout_timer, 0); timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0); @@ -4819,7 +4874,7 @@ int __sdhci_add_host(struct sdhci_host *host) sdhci_init(host, 0); - ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq, + ret = request_threaded_irq(host->irq, sdhci_irq, host->thread_irq_fn, IRQF_SHARED, mmc_hostname(mmc), host); if (ret) { pr_err("%s: Failed to request IRQ %d: %d\n", diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index f531b617f28d77..cd0e35a805427c 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -43,8 +43,23 @@ #define SDHCI_TRNS_READ 0x10 #define SDHCI_TRNS_MULTI 0x20 +/* + * Defined in Host Version 4.0. + */ +#define SDHCI_TRNS_RES_TYPE 0x40 +#define SDHCI_TRNS_RES_ERR_CHECK 0x80 +#define SDHCI_TRNS_RES_INT_DIS 0x0100 + #define SDHCI_COMMAND 0x0E #define SDHCI_CMD_RESP_MASK 0x03 + +/* + * Host Version 4.10 adds this bit to distinguish a main command or + * sub command. + * For example with SDIO, CMD52 (sub command) issued during CMD53 (main command). + */ +#define SDHCI_CMD_SUB_CMD 0x04 + #define SDHCI_CMD_CRC 0x08 #define SDHCI_CMD_INDEX 0x10 #define SDHCI_CMD_DATA 0x20 @@ -65,6 +80,9 @@ #define SDHCI_PRESENT_STATE 0x24 #define SDHCI_CMD_INHIBIT 0x00000001 #define SDHCI_DATA_INHIBIT 0x00000002 + +#define SDHCI_DAT_4_TO_7_LVL_MASK 0x000000F0 + #define SDHCI_DOING_WRITE 0x00000100 #define SDHCI_DOING_READ 0x00000200 #define SDHCI_SPACE_AVAILABLE 0x00000400 @@ -80,6 +98,15 @@ #define SDHCI_DATA_0_LVL_MASK 0x00100000 #define SDHCI_CMD_LVL 0x01000000 +/* Host Version 4.10 */ + +#define SDHCI_HOST_REGULATOR_STABLE 0x02000000 +#define SDHCI_CMD_NOT_ISSUED_ERR 0x08000000 +#define SDHCI_SUB_CMD_STATUS 0x10000000 +#define SDHCI_UHS2_IN_DORMANT_STATE 0x20000000 +#define SDHCI_UHS2_LANE_SYNC 0x40000000 +#define SDHCI_UHS2_IF_DETECT 0x80000000 + #define SDHCI_HOST_CONTROL 0x28 #define SDHCI_CTRL_LED 0x01 #define SDHCI_CTRL_4BITBUS 0x02 @@ -117,7 +144,7 @@ #define SDHCI_CLOCK_CONTROL 0x2C #define SDHCI_DIVIDER_SHIFT 8 #define SDHCI_DIVIDER_HI_SHIFT 6 -#define SDHCI_DIV_MASK 0xFF +#define SDHCI_DIV_MASK 0xFF #define SDHCI_DIV_MASK_LEN 8 #define SDHCI_DIV_HI_MASK 0x300 #define SDHCI_PROG_CLOCK_MODE 0x0020 @@ -146,6 +173,10 @@ #define SDHCI_INT_CARD_REMOVE 0x00000080 #define SDHCI_INT_CARD_INT 0x00000100 #define SDHCI_INT_RETUNE 0x00001000 + +/* Host Version 4.10 */ +#define SDHCI_INT_FX_EVENT 0x00002000 + #define SDHCI_INT_CQE 0x00004000 #define SDHCI_INT_ERROR 0x00008000 #define SDHCI_INT_TIMEOUT 0x00010000 @@ -160,6 +191,9 @@ #define SDHCI_INT_ADMA_ERROR 0x02000000 #define SDHCI_INT_TUNING_ERROR 0x04000000 +/* Host Version 4.0 */ +#define SDHCI_INT_RESP_ERR 0x08000000 + #define SDHCI_INT_NORMAL_MASK 0x00007FFF #define SDHCI_INT_ERROR_MASK 0xFFFF8000 @@ -186,6 +220,9 @@ #define SDHCI_AUTO_CMD_END_BIT 0x00000008 #define SDHCI_AUTO_CMD_INDEX 0x00000010 +/* Host Version 4.10 */ +#define SDHCI_AUTO_CMD_RESP_ERR 0x0020 + #define SDHCI_HOST_CONTROL2 0x3E #define SDHCI_CTRL_UHS_MASK 0x0007 #define SDHCI_CTRL_UHS_SDR12 0x0000 @@ -194,6 +231,7 @@ #define SDHCI_CTRL_UHS_SDR104 0x0003 #define SDHCI_CTRL_UHS_DDR50 0x0004 #define SDHCI_CTRL_HS400 0x0005 /* Non-standard */ +#define SDHCI_CTRL_UHS2 0x0007 #define SDHCI_CTRL_VDD_180 0x0008 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_B 0x0000 @@ -202,9 +240,12 @@ #define SDHCI_CTRL_DRV_TYPE_D 0x0030 #define SDHCI_CTRL_EXEC_TUNING 0x0040 #define SDHCI_CTRL_TUNED_CLK 0x0080 +#define SDHCI_CTRL_UHS2_ENABLE 0x0100 +#define SDHCI_CTRL_ADMA2_LEN_MODE 0x0400 #define SDHCI_CMD23_ENABLE 0x0800 #define SDHCI_CTRL_V4_MODE 0x1000 #define SDHCI_CTRL_64BIT_ADDR 0x2000 +#define SDHCI_CTRL_ASYNC_INT_ENABLE 0x4000 #define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000 #define SDHCI_CAPABILITIES 0x40 @@ -227,11 +268,13 @@ #define SDHCI_CAN_VDD_180 0x04000000 #define SDHCI_CAN_64BIT_V4 0x08000000 #define SDHCI_CAN_64BIT 0x10000000 +#define SDHCI_CAN_ASYNC_INT 0x20000000 #define SDHCI_CAPABILITIES_1 0x44 #define SDHCI_SUPPORT_SDR50 0x00000001 #define SDHCI_SUPPORT_SDR104 0x00000002 #define SDHCI_SUPPORT_DDR50 0x00000004 +#define SDHCI_SUPPORT_UHS2 0x00000008 #define SDHCI_DRIVER_TYPE_A 0x00000010 #define SDHCI_DRIVER_TYPE_C 0x00000020 #define SDHCI_DRIVER_TYPE_D 0x00000040 @@ -240,6 +283,7 @@ #define SDHCI_RETUNING_MODE_MASK GENMASK(15, 14) #define SDHCI_CLOCK_MUL_MASK GENMASK(23, 16) #define SDHCI_CAN_DO_ADMA3 0x08000000 +#define SDHCI_CAN_VDD2_180 0x10000000 /* UHS-2 1.8V VDD2 */ #define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */ #define SDHCI_MAX_CURRENT 0x48 @@ -247,11 +291,14 @@ #define SDHCI_MAX_CURRENT_330_MASK GENMASK(7, 0) #define SDHCI_MAX_CURRENT_300_MASK GENMASK(15, 8) #define SDHCI_MAX_CURRENT_180_MASK GENMASK(23, 16) +#define SDHCI_MAX_CURRENT_1 0x4C +#define SDHCI_MAX_CURRENT_VDD2_180_MASK GENMASK(7, 0) /* UHS2 */ #define SDHCI_MAX_CURRENT_MULTIPLIER 4 /* 4C-4F reserved for more max current */ #define SDHCI_SET_ACMD12_ERROR 0x50 +/* Host Version 4.10 */ #define SDHCI_SET_INT_ERROR 0x52 #define SDHCI_ADMA_ERROR 0x54 @@ -270,10 +317,15 @@ #define SDHCI_PRESET_FOR_SDR104 0x6C #define SDHCI_PRESET_FOR_DDR50 0x6E #define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */ + +/* UHS2 */ +#define SDHCI_PRESET_FOR_UHS2 0x74 #define SDHCI_PRESET_DRV_MASK GENMASK(15, 14) #define SDHCI_PRESET_CLKGEN_SEL BIT(10) #define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0) +#define SDHCI_ADMA3_ADDRESS 0x78 + #define SDHCI_SLOT_INT_STATUS 0xFC #define SDHCI_HOST_VERSION 0xFE @@ -573,6 +625,9 @@ struct sdhci_host { struct timer_list timer; /* Timer for timeouts */ struct timer_list data_timer; /* Timer for data timeouts */ + void (*complete_work_fn)(struct work_struct *work); + irqreturn_t (*thread_irq_fn)(int irq, void *dev_id); + #if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA) struct dma_chan *rx_chan; struct dma_chan *tx_chan; @@ -667,6 +722,8 @@ struct sdhci_ops { void (*request_done)(struct sdhci_host *host, struct mmc_request *mrq); void (*dump_vendor_regs)(struct sdhci_host *host); + void (*dump_uhs2_regs)(struct sdhci_host *host); + void (*uhs2_pre_detect_init)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS @@ -774,6 +831,15 @@ static inline void sdhci_read_caps(struct sdhci_host *host) __sdhci_read_caps(host, NULL, NULL, NULL); } +bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq); +bool sdhci_data_line_cmd(struct mmc_command *cmd); +void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq, unsigned long timeout); +void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data); +void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data); +void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq); +void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq); +void __sdhci_finish_data_common(struct sdhci_host *host, bool defer_reset); +bool sdhci_present_error(struct sdhci_host *host, struct mmc_command *cmd, bool present); u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, unsigned int *actual_clock); void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); @@ -783,6 +849,7 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode, void sdhci_set_power_and_bus_voltage(struct sdhci_host *host, unsigned char mode, unsigned short vdd); +unsigned short sdhci_get_vdd_value(unsigned short vdd); void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, unsigned short vdd); int sdhci_get_cd_nogpio(struct mmc_host *mmc); @@ -791,13 +858,19 @@ void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq); int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq); void sdhci_set_bus_width(struct sdhci_host *host, int width); void sdhci_reset(struct sdhci_host *host, u8 mask); +bool sdhci_do_reset(struct sdhci_host *host, u8 mask); void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode); +void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); +void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios); void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios); void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable); +void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq); +void sdhci_complete_work(struct work_struct *work); +irqreturn_t sdhci_thread_irq(int irq, void *dev_id); void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, dma_addr_t addr, int len, unsigned int cmd); diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 0aa3c40ea6ed8e..b73f673db92bbc 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -155,6 +155,7 @@ struct sdhci_am654_data { u32 tuning_loop; #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) +#define SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA BIT(1) }; struct window { @@ -356,6 +357,29 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host, sdhci_set_clock(host, clock); } +static int sdhci_am654_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); + int ret; + + if ((sdhci_am654->quirks & SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA) && + ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { + if (!IS_ERR(mmc->supply.vqmmc)) { + ret = mmc_regulator_set_vqmmc(mmc, ios); + if (ret < 0) { + pr_err("%s: Switching to 1.8V signalling voltage failed,\n", + mmc_hostname(mmc)); + return -EIO; + } + } + return 0; + } + + return sdhci_start_signal_voltage_switch(mmc, ios); +} + static u8 sdhci_am654_write_power_on(struct sdhci_host *host, u8 val, int reg) { writeb(val, host->ioaddr + reg); @@ -844,6 +868,11 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev, if (device_property_read_bool(dev, "ti,fails-without-test-cd")) sdhci_am654->quirks |= SDHCI_AM654_QUIRK_FORCE_CDTEST; + /* Suppress v1p8 ena for eMMC and SD with vqmmc supply */ + if (!!of_parse_phandle(dev->of_node, "vmmc-supply", 0) == + !!of_parse_phandle(dev->of_node, "vqmmc-supply", 0)) + sdhci_am654->quirks |= SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA; + sdhci_get_of_property(pdev); return 0; @@ -940,6 +969,7 @@ static int sdhci_am654_probe(struct platform_device *pdev) goto err_pltfm_free; } + host->mmc_host_ops.start_signal_voltage_switch = sdhci_am654_start_signal_voltage_switch; host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; pm_runtime_get_noresume(dev); @@ -1100,7 +1130,7 @@ static struct platform_driver sdhci_am654_driver = { .of_match_table = sdhci_am654_of_match, }, .probe = sdhci_am654_probe, - .remove_new = sdhci_am654_remove, + .remove = sdhci_am654_remove, }; module_platform_driver(sdhci_am654_driver); diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index c58e7cb1e2a79e..ee66e4f3683d27 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -247,7 +247,7 @@ static struct platform_driver sdhci_f_sdh30_driver = { .pm = &sdhci_pltfm_pmops, }, .probe = sdhci_f_sdh30_probe, - .remove_new = sdhci_f_sdh30_remove, + .remove = sdhci_f_sdh30_remove, }; module_platform_driver(sdhci_f_sdh30_driver); diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 08b4312af94ec8..ce60cec26b985d 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -439,14 +439,15 @@ static void sh_mmcif_request_dma(struct sh_mmcif_host *host) if (IS_ERR(host->chan_rx)) host->chan_rx = NULL; } - dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx, - host->chan_rx); if (!host->chan_tx || !host->chan_rx || sh_mmcif_dma_slave_config(host, host->chan_tx, DMA_MEM_TO_DEV) || sh_mmcif_dma_slave_config(host, host->chan_rx, DMA_DEV_TO_MEM)) goto error; + dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx, + host->chan_rx); + return; error: @@ -1596,7 +1597,7 @@ static const struct dev_pm_ops sh_mmcif_dev_pm_ops = { static struct platform_driver sh_mmcif_driver = { .probe = sh_mmcif_probe, - .remove_new = sh_mmcif_remove, + .remove = sh_mmcif_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/sunplus-mmc.c b/drivers/mmc/host/sunplus-mmc.c index 13c7cc0b6180a7..1cddea615a2707 100644 --- a/drivers/mmc/host/sunplus-mmc.c +++ b/drivers/mmc/host/sunplus-mmc.c @@ -982,7 +982,7 @@ MODULE_DEVICE_TABLE(of, spmmc_of_table); static struct platform_driver spmmc_driver = { .probe = spmmc_drv_probe, - .remove_new = spmmc_drv_remove, + .remove = spmmc_drv_remove, .driver = { .name = "spmmc", .pm = pm_ptr(&spmmc_pm_ops), diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index e0ab5fd635e6cd..1508eead5d0178 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1554,7 +1554,7 @@ static struct platform_driver sunxi_mmc_driver = { .pm = &sunxi_mmc_pm_ops, }, .probe = sunxi_mmc_probe, - .remove_new = sunxi_mmc_remove, + .remove = sunxi_mmc_remove, }; module_platform_driver(sunxi_mmc_driver); diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c index 46ee8a0b2b8563..4ad02cfdc23897 100644 --- a/drivers/mmc/host/uniphier-sd.c +++ b/drivers/mmc/host/uniphier-sd.c @@ -754,7 +754,7 @@ MODULE_DEVICE_TABLE(of, uniphier_sd_match); static struct platform_driver uniphier_sd_driver = { .probe = uniphier_sd_probe, - .remove_new = uniphier_sd_remove, + .remove = uniphier_sd_remove, .driver = { .name = "uniphier-sd", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 6e421445d56c94..49efb960a052bb 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1899,7 +1899,7 @@ static void usdhi6_remove(struct platform_device *pdev) static struct platform_driver usdhi6_driver = { .probe = usdhi6_probe, - .remove_new = usdhi6_remove, + .remove = usdhi6_remove, .driver = { .name = "usdhi6rol0", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 6e20405d04300e..8b268e8a0ec9e7 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1896,7 +1896,7 @@ static struct platform_device *wbsd_device; static struct platform_driver wbsd_driver = { .probe = wbsd_probe, - .remove_new = wbsd_remove, + .remove = wbsd_remove, .suspend = wbsd_platform_suspend, .resume = wbsd_platform_resume, .driver = { diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 860380931b6cde..cdb36a9f9e38e0 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -982,7 +982,7 @@ static const struct dev_pm_ops wmt_mci_pm = { static struct platform_driver wmt_mci_driver = { .probe = wmt_mci_probe, - .remove_new = wmt_mci_remove, + .remove = wmt_mci_remove, .driver = { .name = DRIVER_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 9f2223d3e8e119..7c91429a670bbb 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -1779,10 +1779,8 @@ static int __xipram do_write_oneword_retry(struct map_info *map, map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_RETRIES) { - ret = 0; + if (++retry_cnt <= MAX_RETRIES) goto retry; - } } xip_enable(map, chip, adr); diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 74f559bf8dfb0a..2edc4674177451 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -367,7 +367,7 @@ static void bcm47xxsflash_bcma_remove(struct platform_device *pdev) static struct platform_driver bcma_sflash_driver = { .probe = bcm47xxsflash_bcma_probe, - .remove_new = bcm47xxsflash_bcma_remove, + .remove = bcm47xxsflash_bcma_remove, .driver = { .name = "bcma_sflash", }, diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index a2b643af70194c..c93769c233d9a3 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -2075,7 +2075,7 @@ static struct platform_driver g3_driver = { }, .suspend = docg3_suspend, .resume = docg3_resume, - .remove_new = docg3_release, + .remove = docg3_release, }; module_platform_driver_probe(g3_driver, docg3_probe); diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 1bf192f229d712..f756c60a4931d5 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -399,7 +399,7 @@ static void phram_remove(struct platform_device *pdev) static struct platform_driver phram_driver = { .probe = phram_probe, - .remove_new = phram_remove, + .remove = phram_remove, .driver = { .name = "phram", .of_match_table = of_match_ptr(phram_of_match), diff --git a/drivers/mtd/devices/powernv_flash.c b/drivers/mtd/devices/powernv_flash.c index 10cd1d9b48859d..a12427d9e20fa3 100644 --- a/drivers/mtd/devices/powernv_flash.c +++ b/drivers/mtd/devices/powernv_flash.c @@ -286,7 +286,7 @@ static struct platform_driver powernv_flash_driver = { .name = "powernv_flash", .of_match_table = powernv_flash_match, }, - .remove_new = powernv_flash_release, + .remove = powernv_flash_release, .probe = powernv_flash_probe, }; diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index 1574296d47e2f4..f02f96bff45099 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -1093,7 +1093,7 @@ static struct platform_driver spear_smi_driver = { .pm = &spear_smi_pm_ops, }, .probe = spear_smi_probe, - .remove_new = spear_smi_remove, + .remove = spear_smi_remove, }; module_platform_driver(spear_smi_driver); diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 3268de5fc7802c..dba584fa2a530b 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -2132,7 +2132,7 @@ MODULE_DEVICE_TABLE(of, stfsm_match); static struct platform_driver stfsm_driver = { .probe = stfsm_probe, - .remove_new = stfsm_remove, + .remove = stfsm_remove, .driver = { .name = "st-spi-fsm", .of_match_table = stfsm_match, diff --git a/drivers/mtd/hyperbus/hbmc-am654.c b/drivers/mtd/hyperbus/hbmc-am654.c index dbe3eb361cca28..217f4e69233fbf 100644 --- a/drivers/mtd/hyperbus/hbmc-am654.c +++ b/drivers/mtd/hyperbus/hbmc-am654.c @@ -254,7 +254,7 @@ MODULE_DEVICE_TABLE(of, am654_hbmc_dt_ids); static struct platform_driver am654_hbmc_platform_driver = { .probe = am654_hbmc_probe, - .remove_new = am654_hbmc_remove, + .remove = am654_hbmc_remove, .driver = { .name = "hbmc-am654", .of_match_table = am654_hbmc_dt_ids, diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index b22aa57119f238..f448e23f9260f1 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -163,9 +163,16 @@ static void rpcif_hb_remove(struct platform_device *pdev) pm_runtime_disable(hyperbus->rpc.dev); } +static const struct platform_device_id rpc_if_hyperflash_id_table[] = { + { .name = "rpc-if-hyperflash" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, rpc_if_hyperflash_id_table); + static struct platform_driver rpcif_platform_driver = { .probe = rpcif_hb_probe, - .remove_new = rpcif_hb_remove, + .remove = rpcif_hb_remove, + .id_table = rpc_if_hyperflash_id_table, .driver = { .name = "rpc-if-hyperflash", }, diff --git a/drivers/mtd/lpddr/lpddr2_nvm.c b/drivers/mtd/lpddr/lpddr2_nvm.c index 9169e1155dbbd7..565b71f7fdd5bf 100644 --- a/drivers/mtd/lpddr/lpddr2_nvm.c +++ b/drivers/mtd/lpddr/lpddr2_nvm.c @@ -487,7 +487,7 @@ static struct platform_driver lpddr2_nvm_drv = { .name = "lpddr2_nvm", }, .probe = lpddr2_nvm_probe, - .remove_new = lpddr2_nvm_remove, + .remove = lpddr2_nvm_remove, }; module_platform_driver(lpddr2_nvm_drv); diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 124b13c5d74758..80d467eba92a36 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -184,7 +184,7 @@ MODULE_DEVICE_TABLE(of, ltq_mtd_match); static struct platform_driver ltq_mtd_driver = { .probe = ltq_mtd_probe, - .remove_new = ltq_mtd_remove, + .remove = ltq_mtd_remove, .driver = { .name = "ltq-nor", .of_match_table = ltq_mtd_match, diff --git a/drivers/mtd/maps/physmap-core.c b/drivers/mtd/maps/physmap-core.c index 96eb2e782c3826..2bd7a1af898c95 100644 --- a/drivers/mtd/maps/physmap-core.c +++ b/drivers/mtd/maps/physmap-core.c @@ -621,7 +621,7 @@ static void physmap_flash_shutdown(struct platform_device *dev) static struct platform_driver physmap_flash_driver = { .probe = physmap_flash_probe, - .remove_new = physmap_flash_remove, + .remove = physmap_flash_remove, .shutdown = physmap_flash_shutdown, .driver = { .name = "physmap-flash", diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 8b736f029f817f..1c541eaf477a9a 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -205,7 +205,7 @@ MODULE_ALIAS("platform:mtd-ram"); static struct platform_driver platram_driver = { .probe = platram_probe, - .remove_new = platram_remove, + .remove = platram_remove, .driver = { .name = "mtd-ram", }, diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index f2a2d4706f1fb9..f27c25db677898 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -128,7 +128,7 @@ static struct platform_driver pxa2xx_flash_driver = { .name = "pxa2xx-flash", }, .probe = pxa2xx_flash_probe, - .remove_new = pxa2xx_flash_remove, + .remove = pxa2xx_flash_remove, .shutdown = pxa2xx_flash_shutdown, }; diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index ac8a0a19a02169..6a54a84d0d9c92 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -293,7 +293,7 @@ static void sa1100_mtd_remove(struct platform_device *pdev) static struct platform_driver sa1100_mtd_driver = { .probe = sa1100_mtd_probe, - .remove_new = sa1100_mtd_remove, + .remove = sa1100_mtd_remove, .driver = { .name = "sa1100-mtd", }, diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index b69dade3f7ad07..ea3aa026b55b04 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -149,7 +149,7 @@ static struct platform_driver uflash_driver = { .of_match_table = uflash_match, }, .probe = uflash_probe, - .remove_new = uflash_remove, + .remove = uflash_remove, }; module_platform_driver(uflash_driver); diff --git a/drivers/mtd/nand/ecc-mxic.c b/drivers/mtd/nand/ecc-mxic.c index 47e10945b8d271..56b56f726b9983 100644 --- a/drivers/mtd/nand/ecc-mxic.c +++ b/drivers/mtd/nand/ecc-mxic.c @@ -723,21 +723,21 @@ static int mxic_ecc_finish_io_req_pipelined(struct nand_device *nand, return ret; } -static struct nand_ecc_engine_ops mxic_ecc_engine_external_ops = { +static const struct nand_ecc_engine_ops mxic_ecc_engine_external_ops = { .init_ctx = mxic_ecc_init_ctx_external, .cleanup_ctx = mxic_ecc_cleanup_ctx, .prepare_io_req = mxic_ecc_prepare_io_req_external, .finish_io_req = mxic_ecc_finish_io_req_external, }; -static struct nand_ecc_engine_ops mxic_ecc_engine_pipelined_ops = { +static const struct nand_ecc_engine_ops mxic_ecc_engine_pipelined_ops = { .init_ctx = mxic_ecc_init_ctx_pipelined, .cleanup_ctx = mxic_ecc_cleanup_ctx, .prepare_io_req = mxic_ecc_prepare_io_req_pipelined, .finish_io_req = mxic_ecc_finish_io_req_pipelined, }; -struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void) +const struct nand_ecc_engine_ops *mxic_ecc_get_pipelined_ops(void) { return &mxic_ecc_engine_pipelined_ops; } @@ -869,7 +869,7 @@ static struct platform_driver mxic_ecc_driver = { .of_match_table = mxic_ecc_of_ids, }, .probe = mxic_ecc_probe, - .remove_new = mxic_ecc_remove, + .remove = mxic_ecc_remove, }; module_platform_driver(mxic_ecc_driver); diff --git a/drivers/mtd/nand/ecc-sw-bch.c b/drivers/mtd/nand/ecc-sw-bch.c index 405552d014a884..0d9310dd6f521d 100644 --- a/drivers/mtd/nand/ecc-sw-bch.c +++ b/drivers/mtd/nand/ecc-sw-bch.c @@ -384,7 +384,7 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand, return max_bitflips; } -static struct nand_ecc_engine_ops nand_ecc_sw_bch_engine_ops = { +static const struct nand_ecc_engine_ops nand_ecc_sw_bch_engine_ops = { .init_ctx = nand_ecc_sw_bch_init_ctx, .cleanup_ctx = nand_ecc_sw_bch_cleanup_ctx, .prepare_io_req = nand_ecc_sw_bch_prepare_io_req, diff --git a/drivers/mtd/nand/ecc-sw-hamming.c b/drivers/mtd/nand/ecc-sw-hamming.c index 254db2e7f8bb30..f2d0effad9d29f 100644 --- a/drivers/mtd/nand/ecc-sw-hamming.c +++ b/drivers/mtd/nand/ecc-sw-hamming.c @@ -638,7 +638,7 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand, return max_bitflips; } -static struct nand_ecc_engine_ops nand_ecc_sw_hamming_engine_ops = { +static const struct nand_ecc_engine_ops nand_ecc_sw_hamming_engine_ops = { .init_ctx = nand_ecc_sw_hamming_init_ctx, .cleanup_ctx = nand_ecc_sw_hamming_cleanup_ctx, .prepare_io_req = nand_ecc_sw_hamming_prepare_io_req, diff --git a/drivers/mtd/nand/onenand/generic.c b/drivers/mtd/nand/onenand/generic.c index 4e7de48f07a625..4e6fd1c344845d 100644 --- a/drivers/mtd/nand/onenand/generic.c +++ b/drivers/mtd/nand/onenand/generic.c @@ -104,7 +104,7 @@ static struct platform_driver generic_onenand_driver = { .name = DRIVER_NAME, }, .probe = generic_onenand_probe, - .remove_new = generic_onenand_remove, + .remove = generic_onenand_remove, }; module_platform_driver(generic_onenand_driver); diff --git a/drivers/mtd/nand/onenand/onenand_omap2.c b/drivers/mtd/nand/onenand/onenand_omap2.c index a12f8f3efd0781..f9a386b69050a5 100644 --- a/drivers/mtd/nand/onenand/onenand_omap2.c +++ b/drivers/mtd/nand/onenand/onenand_omap2.c @@ -593,7 +593,7 @@ MODULE_DEVICE_TABLE(of, omap2_onenand_id_table); static struct platform_driver omap2_onenand_driver = { .probe = omap2_onenand_probe, - .remove_new = omap2_onenand_remove, + .remove = omap2_onenand_remove, .shutdown = omap2_onenand_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/mtd/nand/onenand/onenand_samsung.c b/drivers/mtd/nand/onenand/onenand_samsung.c index fd6890a03d5571..f37a6138e461f2 100644 --- a/drivers/mtd/nand/onenand/onenand_samsung.c +++ b/drivers/mtd/nand/onenand/onenand_samsung.c @@ -991,7 +991,7 @@ static struct platform_driver s3c_onenand_driver = { }, .id_table = s3c_onenand_driver_ids, .probe = s3c_onenand_probe, - .remove_new = s3c_onenand_remove, + .remove = s3c_onenand_remove, }; module_platform_driver(s3c_onenand_driver); diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index 919816a7aca754..fb2b7db70297fe 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -432,7 +432,7 @@ MODULE_DEVICE_TABLE(platform, gpio_nand_plat_id_table); static struct platform_driver gpio_nand_driver = { .probe = gpio_nand_probe, - .remove_new = gpio_nand_remove, + .remove = gpio_nand_remove, .id_table = gpio_nand_plat_id_table, .driver = { .name = "ams-delta-nand", diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c index 5436ec4a8fde42..db42aa0c7b6b59 100644 --- a/drivers/mtd/nand/raw/arasan-nand-controller.c +++ b/drivers/mtd/nand/raw/arasan-nand-controller.c @@ -1500,7 +1500,7 @@ static struct platform_driver anfc_driver = { .of_match_table = anfc_ids, }, .probe = anfc_probe, - .remove_new = anfc_remove, + .remove = anfc_remove, }; module_platform_driver(anfc_driver); diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index f9ccfd02e80456..dedcca87defc7a 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -2663,7 +2663,7 @@ static struct platform_driver atmel_nand_controller_driver = { .pm = &atmel_nand_controller_pm_ops, }, .probe = atmel_nand_controller_probe, - .remove_new = atmel_nand_controller_remove, + .remove = atmel_nand_controller_remove, }; module_platform_driver(atmel_nand_controller_driver); diff --git a/drivers/mtd/nand/raw/atmel/pmecc.c b/drivers/mtd/nand/raw/atmel/pmecc.c index 4d7dc8a9c37385..a22aab4ed4e8ab 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.c +++ b/drivers/mtd/nand/raw/atmel/pmecc.c @@ -362,7 +362,7 @@ atmel_pmecc_create_user(struct atmel_pmecc *pmecc, size = ALIGN(size, sizeof(s32)); size += (req->ecc.strength + 1) * sizeof(s32) * 3; - user = kzalloc(size, GFP_KERNEL); + user = devm_kzalloc(pmecc->dev, size, GFP_KERNEL); if (!user) return ERR_PTR(-ENOMEM); @@ -408,12 +408,6 @@ atmel_pmecc_create_user(struct atmel_pmecc *pmecc, } EXPORT_SYMBOL_GPL(atmel_pmecc_create_user); -void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user) -{ - kfree(user); -} -EXPORT_SYMBOL_GPL(atmel_pmecc_destroy_user); - static int get_strength(struct atmel_pmecc_user *user) { const int *strengths = user->pmecc->caps->strengths; diff --git a/drivers/mtd/nand/raw/atmel/pmecc.h b/drivers/mtd/nand/raw/atmel/pmecc.h index 7851c05126cf15..cc0c5af1f4f1ab 100644 --- a/drivers/mtd/nand/raw/atmel/pmecc.h +++ b/drivers/mtd/nand/raw/atmel/pmecc.h @@ -55,8 +55,6 @@ struct atmel_pmecc *devm_atmel_pmecc_get(struct device *dev); struct atmel_pmecc_user * atmel_pmecc_create_user(struct atmel_pmecc *pmecc, struct atmel_pmecc_user_req *req); -void atmel_pmecc_destroy_user(struct atmel_pmecc_user *user); - void atmel_pmecc_reset(struct atmel_pmecc *pmecc); int atmel_pmecc_enable(struct atmel_pmecc_user *user, int op); void atmel_pmecc_disable(struct atmel_pmecc_user *user); diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c index 063a5e0b8d4baf..04d64724c4004f 100644 --- a/drivers/mtd/nand/raw/au1550nd.c +++ b/drivers/mtd/nand/raw/au1550nd.c @@ -357,7 +357,7 @@ static struct platform_driver au1550nd_driver = { .name = "au1550-nand", }, .probe = au1550nd_probe, - .remove_new = au1550nd_remove, + .remove = au1550nd_remove, }; module_platform_driver(au1550nd_driver); diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/main.c b/drivers/mtd/nand/raw/bcm47xxnflash/main.c index ebcf508e06060f..4d4e185c22e560 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/main.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/main.c @@ -70,7 +70,7 @@ static void bcm47xxnflash_remove(struct platform_device *pdev) static struct platform_driver bcm47xxnflash_driver = { .probe = bcm47xxnflash_probe, - .remove_new = bcm47xxnflash_remove, + .remove = bcm47xxnflash_remove, .driver = { .name = "bcma_nflash", }, diff --git a/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c index 05b7b653bdf30f..a06cd87f839a60 100644 --- a/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/bcm6368_nand.c @@ -117,7 +117,7 @@ MODULE_DEVICE_TABLE(of, bcm6368_nand_of_match); static struct platform_driver bcm6368_nand_driver = { .probe = bcm6368_nand_probe, - .remove_new = brcmnand_remove, + .remove = brcmnand_remove, .driver = { .name = "bcm6368_nand", .pm = &brcmnand_pm_ops, diff --git a/drivers/mtd/nand/raw/brcmnand/bcma_nand.c b/drivers/mtd/nand/raw/brcmnand/bcma_nand.c index 4e7e435ba33965..dd27977919fbac 100644 --- a/drivers/mtd/nand/raw/brcmnand/bcma_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/bcma_nand.c @@ -119,7 +119,7 @@ static int brcmnand_bcma_nand_probe(struct platform_device *pdev) static struct platform_driver brcmnand_bcma_nand_driver = { .probe = brcmnand_bcma_nand_probe, - .remove_new = brcmnand_remove, + .remove = brcmnand_remove, .driver = { .name = "bcma_brcmnand", .pm = &brcmnand_pm_ops, diff --git a/drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c b/drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c index ea534850b97a30..c31d7f37dc5218 100644 --- a/drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/bcmbca_nand.c @@ -112,7 +112,7 @@ MODULE_DEVICE_TABLE(of, bcmbca_nand_of_match); static struct platform_driver bcmbca_nand_driver = { .probe = bcmbca_nand_probe, - .remove_new = brcmnand_remove, + .remove = brcmnand_remove, .driver = { .name = "bcmbca_nand", .pm = &brcmnand_pm_ops, diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 1b2ec0fec60c7a..9c253a511e45a5 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -1561,7 +1561,7 @@ static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i, (oob[j + 2] << 8) | (oob[j + 3] << 0)); - /* handle the remaing bytes */ + /* handle the remaining bytes */ while (j < tbytes) plast[k++] = oob[j++]; diff --git a/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c index 558f083b92e9bf..950923d977b727 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c @@ -23,7 +23,7 @@ static int brcmstb_nand_probe(struct platform_device *pdev) static struct platform_driver brcmstb_nand_driver = { .probe = brcmstb_nand_probe, - .remove_new = brcmnand_remove, + .remove = brcmnand_remove, .driver = { .name = "brcmstb_nand", .pm = &brcmnand_pm_ops, diff --git a/drivers/mtd/nand/raw/brcmnand/iproc_nand.c b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c index bf46c8b858986f..089c70fc6edfc0 100644 --- a/drivers/mtd/nand/raw/brcmnand/iproc_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/iproc_nand.c @@ -134,7 +134,7 @@ MODULE_DEVICE_TABLE(of, iproc_nand_of_match); static struct platform_driver iproc_nand_driver = { .probe = iproc_nand_probe, - .remove_new = brcmnand_remove, + .remove = brcmnand_remove, .driver = { .name = "iproc_nand", .pm = &brcmnand_pm_ops, diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index 3bc89b3569632d..8d1d710e439dd3 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -1891,7 +1891,7 @@ static int cadence_nand_read_buf(struct cdns_nand_ctrl *cdns_ctrl, int len_in_words = (data_dma_width == 4) ? len >> 2 : len >> 3; - /* read alingment data */ + /* read alignment data */ if (data_dma_width == 4) ioread32_rep(cdns_ctrl->io.virt, buf, len_in_words); #ifdef CONFIG_64BIT @@ -3055,7 +3055,7 @@ static void cadence_nand_dt_remove(struct platform_device *ofdev) static struct platform_driver cadence_nand_dt_driver = { .probe = cadence_nand_dt_probe, - .remove_new = cadence_nand_dt_remove, + .remove = cadence_nand_dt_remove, .driver = { .name = "cadence-nand-controller", .of_match_table = cadence_nand_dt_ids, diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c index f0a15717cf055a..341318024a1931 100644 --- a/drivers/mtd/nand/raw/cs553x_nand.c +++ b/drivers/mtd/nand/raw/cs553x_nand.c @@ -26,7 +26,7 @@ #define NR_CS553X_CONTROLLERS 4 -#define MSR_DIVIL_GLD_CAP 0x51400000 /* DIVIL capabilitiies */ +#define MSR_DIVIL_GLD_CAP 0x51400000 /* DIVIL capabilities */ #define CAP_CS5535 0x2df000ULL #define CAP_CS5536 0x5df500ULL diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 392678143a36b2..1f8354acfb50b2 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -10,15 +10,15 @@ * Dirk Behme */ -#include -#include -#include #include #include -#include +#include +#include #include +#include +#include +#include #include -#include #define NRCSR_OFFSET 0x00 #define NANDFCR_OFFSET 0x60 @@ -487,10 +487,10 @@ static const struct of_device_id davinci_nand_of_match[] = { }; MODULE_DEVICE_TABLE(of, davinci_nand_of_match); -static struct davinci_nand_pdata - *nand_davinci_get_pdata(struct platform_device *pdev) +static struct davinci_nand_pdata * +nand_davinci_get_pdata(struct platform_device *pdev) { - if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) { + if (!dev_get_platdata(&pdev->dev)) { struct davinci_nand_pdata *pdata; const char *mode; u32 prop; @@ -501,23 +501,24 @@ static struct davinci_nand_pdata pdev->dev.platform_data = pdata; if (!pdata) return ERR_PTR(-ENOMEM); - if (!of_property_read_u32(pdev->dev.of_node, - "ti,davinci-chipselect", &prop)) + if (!device_property_read_u32(&pdev->dev, + "ti,davinci-chipselect", &prop)) pdata->core_chipsel = prop; else return ERR_PTR(-EINVAL); - if (!of_property_read_u32(pdev->dev.of_node, - "ti,davinci-mask-ale", &prop)) + if (!device_property_read_u32(&pdev->dev, + "ti,davinci-mask-ale", &prop)) pdata->mask_ale = prop; - if (!of_property_read_u32(pdev->dev.of_node, - "ti,davinci-mask-cle", &prop)) + if (!device_property_read_u32(&pdev->dev, + "ti,davinci-mask-cle", &prop)) pdata->mask_cle = prop; - if (!of_property_read_u32(pdev->dev.of_node, - "ti,davinci-mask-chipsel", &prop)) + if (!device_property_read_u32(&pdev->dev, + "ti,davinci-mask-chipsel", &prop)) pdata->mask_chipsel = prop; - if (!of_property_read_string(pdev->dev.of_node, - "ti,davinci-ecc-mode", &mode)) { + if (!device_property_read_string(&pdev->dev, + "ti,davinci-ecc-mode", + &mode)) { if (!strncmp("none", mode, 4)) pdata->engine_type = NAND_ECC_ENGINE_TYPE_NONE; if (!strncmp("soft", mode, 4)) @@ -525,16 +526,17 @@ static struct davinci_nand_pdata if (!strncmp("hw", mode, 2)) pdata->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; } - if (!of_property_read_u32(pdev->dev.of_node, - "ti,davinci-ecc-bits", &prop)) + if (!device_property_read_u32(&pdev->dev, + "ti,davinci-ecc-bits", &prop)) pdata->ecc_bits = prop; - if (!of_property_read_u32(pdev->dev.of_node, - "ti,davinci-nand-buswidth", &prop) && prop == 16) + if (!device_property_read_u32(&pdev->dev, + "ti,davinci-nand-buswidth", + &prop) && prop == 16) pdata->options |= NAND_BUSWIDTH_16; - if (of_property_read_bool(pdev->dev.of_node, - "ti,davinci-nand-use-bbt")) + if (device_property_read_bool(&pdev->dev, + "ti,davinci-nand-use-bbt")) pdata->bbt_options = NAND_BBT_USE_FLASH; /* @@ -548,17 +550,15 @@ static struct davinci_nand_pdata * then use "ti,davinci-nand" as the compatible in your * device-tree file. */ - if (of_device_is_compatible(pdev->dev.of_node, - "ti,keystone-nand")) { + if (device_is_compatible(&pdev->dev, "ti,keystone-nand")) pdata->options |= NAND_NO_SUBPAGE_WRITE; - } } return dev_get_platdata(&pdev->dev); } #else -static struct davinci_nand_pdata - *nand_davinci_get_pdata(struct platform_device *pdev) +static struct davinci_nand_pdata * +nand_davinci_get_pdata(struct platform_device *pdev) { return dev_get_platdata(&pdev->dev); } @@ -901,7 +901,7 @@ static void nand_davinci_remove(struct platform_device *pdev) static struct platform_driver nand_davinci_driver = { .probe = nand_davinci_probe, - .remove_new = nand_davinci_remove, + .remove = nand_davinci_remove, .driver = { .name = "davinci_nand", .of_match_table = of_match_ptr(davinci_nand_of_match), diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index 2f5666511fda8d..e0dd59bba4bddd 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -225,7 +225,7 @@ static void denali_dt_remove(struct platform_device *pdev) static struct platform_driver denali_dt_driver = { .probe = denali_dt_probe, - .remove_new = denali_dt_remove, + .remove = denali_dt_remove, .driver = { .name = "denali-nand-dt", .of_match_table = denali_nand_dt_ids, diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index df6a0d5c86bb30..03dbe37df02174 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -999,7 +999,7 @@ static struct platform_driver fsl_elbc_nand_driver = { .of_match_table = fsl_elbc_nand_match, }, .probe = fsl_elbc_nand_probe, - .remove_new = fsl_elbc_nand_remove, + .remove = fsl_elbc_nand_remove, }; module_platform_driver(fsl_elbc_nand_driver); diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index f0e2318ce088c0..7be95d0be24827 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -1130,7 +1130,7 @@ static struct platform_driver fsl_ifc_nand_driver = { .of_match_table = fsl_ifc_nand_match, }, .probe = fsl_ifc_nand_probe, - .remove_new = fsl_ifc_nand_remove, + .remove = fsl_ifc_nand_remove, }; module_platform_driver(fsl_ifc_nand_driver); diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 315e9d2b573d33..f4dc990a8da16a 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -259,7 +259,7 @@ static struct platform_driver of_fun_driver = { .of_match_table = of_fun_match, }, .probe = fun_probe, - .remove_new = fun_remove, + .remove = fun_remove, }; module_platform_driver(of_fun_driver); diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 811982da355740..d579d5dd60d66e 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -1221,7 +1221,7 @@ static const struct of_device_id fsmc_nand_id_table[] = { MODULE_DEVICE_TABLE(of, fsmc_nand_id_table); static struct platform_driver fsmc_nand_driver = { - .remove_new = fsmc_nand_remove, + .remove = fsmc_nand_remove, .driver = { .name = "fsmc-nand", .of_match_table = fsmc_nand_id_table, diff --git a/drivers/mtd/nand/raw/gpio.c b/drivers/mtd/nand/raw/gpio.c index d6cc2cb6521470..69e5e43532a448 100644 --- a/drivers/mtd/nand/raw/gpio.c +++ b/drivers/mtd/nand/raw/gpio.c @@ -392,7 +392,7 @@ static int gpio_nand_probe(struct platform_device *pdev) static struct platform_driver gpio_nand_driver = { .probe = gpio_nand_probe, - .remove_new = gpio_nand_remove, + .remove = gpio_nand_remove, .driver = { .name = "gpio-nand", .of_match_table = of_match_ptr(gpio_nand_id_table), diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index e1b515304e3cdd..d7680294445330 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "gpmi-nand.h" #include "gpmi-regs.h" @@ -737,9 +738,8 @@ static int bch_set_geometry(struct gpmi_nand_data *this) if (ret) return ret; - ret = pm_runtime_get_sync(this->dev); + ret = pm_runtime_resume_and_get(this->dev); if (ret < 0) { - pm_runtime_put_autosuspend(this->dev); return ret; } @@ -2761,15 +2761,9 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (ret) goto exit_acquire_resources; - ret = __gpmi_enable_clk(this, true); - if (ret) - goto exit_acquire_resources; - + pm_runtime_enable(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 500); pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); ret = gpmi_init(this); if (ret) @@ -2779,15 +2773,12 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (ret) goto exit_nfc_init; - pm_runtime_mark_last_busy(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); - dev_info(this->dev, "driver registered.\n"); return 0; exit_nfc_init: - pm_runtime_put(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); release_resources(this); exit_acquire_resources: @@ -2801,23 +2792,23 @@ static void gpmi_nand_remove(struct platform_device *pdev) struct nand_chip *chip = &this->nand; int ret; - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - ret = mtd_device_unregister(nand_to_mtd(chip)); WARN_ON(ret); nand_cleanup(chip); gpmi_free_dma_buffer(this); release_resources(this); + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); } -#ifdef CONFIG_PM_SLEEP static int gpmi_pm_suspend(struct device *dev) { - struct gpmi_nand_data *this = dev_get_drvdata(dev); + int ret; - release_dma_channels(this); - return 0; + pinctrl_pm_select_sleep_state(dev); + ret = pm_runtime_force_suspend(dev); + + return ret; } static int gpmi_pm_resume(struct device *dev) @@ -2825,9 +2816,13 @@ static int gpmi_pm_resume(struct device *dev) struct gpmi_nand_data *this = dev_get_drvdata(dev); int ret; - ret = acquire_dma_channels(this); - if (ret < 0) + ret = pm_runtime_force_resume(dev); + if (ret) { + dev_err(this->dev, "Error in resume %d\n", ret); return ret; + } + + pinctrl_pm_select_default_state(dev); /* re-init the GPMI registers */ ret = gpmi_init(this); @@ -2849,35 +2844,45 @@ static int gpmi_pm_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ -static int __maybe_unused gpmi_runtime_suspend(struct device *dev) +#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true) +#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false) + +static int gpmi_runtime_suspend(struct device *dev) { struct gpmi_nand_data *this = dev_get_drvdata(dev); - return __gpmi_enable_clk(this, false); + gpmi_disable_clk(this); + + return 0; } -static int __maybe_unused gpmi_runtime_resume(struct device *dev) +static int gpmi_runtime_resume(struct device *dev) { struct gpmi_nand_data *this = dev_get_drvdata(dev); + int ret; + + ret = gpmi_enable_clk(this); + if (ret) + return ret; + + return 0; - return __gpmi_enable_clk(this, true); } static const struct dev_pm_ops gpmi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume) - SET_RUNTIME_PM_OPS(gpmi_runtime_suspend, gpmi_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume) + RUNTIME_PM_OPS(gpmi_runtime_suspend, gpmi_runtime_resume, NULL) }; static struct platform_driver gpmi_nand_driver = { .driver = { .name = "gpmi-nand", - .pm = &gpmi_pm_ops, + .pm = pm_ptr(&gpmi_pm_ops), .of_match_table = gpmi_nand_id_table, }, - .probe = gpmi_nand_probe, - .remove_new = gpmi_nand_remove, + .probe = gpmi_nand_probe, + .remove = gpmi_nand_remove, }; module_platform_driver(gpmi_nand_driver); diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c index fe291a2e5c77c9..d97270ec118550 100644 --- a/drivers/mtd/nand/raw/hisi504_nand.c +++ b/drivers/mtd/nand/raw/hisi504_nand.c @@ -858,7 +858,7 @@ static struct platform_driver hisi_nfc_driver = { .pm = &hisi_nfc_pm_ops, }, .probe = hisi_nfc_probe, - .remove_new = hisi_nfc_remove, + .remove = hisi_nfc_remove, }; module_platform_driver(hisi_nfc_driver); diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c index 0e7dd9ca4b2bfe..47dc3efcee92e6 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c @@ -549,7 +549,7 @@ MODULE_DEVICE_TABLE(of, ingenic_nand_dt_match); static struct platform_driver ingenic_nand_driver = { .probe = ingenic_nand_probe, - .remove_new = ingenic_nand_remove, + .remove = ingenic_nand_remove, .driver = { .name = DRV_NAME, .of_match_table = ingenic_nand_dt_match, diff --git a/drivers/mtd/nand/raw/intel-nand-controller.c b/drivers/mtd/nand/raw/intel-nand-controller.c index f0f0522b2fa254..01cefdaf115d13 100644 --- a/drivers/mtd/nand/raw/intel-nand-controller.c +++ b/drivers/mtd/nand/raw/intel-nand-controller.c @@ -728,7 +728,7 @@ MODULE_DEVICE_TABLE(of, ebu_nand_match); static struct platform_driver ebu_nand_driver = { .probe = ebu_nand_probe, - .remove_new = ebu_nand_remove, + .remove = ebu_nand_remove, .driver = { .name = "intel-nand-controller", .of_match_table = ebu_nand_match, diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c index b9c3adc54c0102..19b13ae536d48a 100644 --- a/drivers/mtd/nand/raw/lpc32xx_mlc.c +++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c @@ -891,7 +891,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, - .remove_new = lpc32xx_nand_remove, + .remove = lpc32xx_nand_remove, .resume = pm_ptr(lpc32xx_nand_resume), .suspend = pm_ptr(lpc32xx_nand_suspend), .driver = { diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c index ade971e4cc3b29..b54d76547ffb29 100644 --- a/drivers/mtd/nand/raw/lpc32xx_slc.c +++ b/drivers/mtd/nand/raw/lpc32xx_slc.c @@ -1010,7 +1010,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match); static struct platform_driver lpc32xx_nand_driver = { .probe = lpc32xx_nand_probe, - .remove_new = lpc32xx_nand_remove, + .remove = lpc32xx_nand_remove, .resume = pm_ptr(lpc32xx_nand_resume), .suspend = pm_ptr(lpc32xx_nand_suspend), .driver = { diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index aa113a5d88c89e..303b3016a070bd 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -3183,7 +3183,7 @@ static struct platform_driver marvell_nfc_driver = { }, .id_table = marvell_nfc_platform_ids, .probe = marvell_nfc_probe, - .remove_new = marvell_nfc_remove, + .remove = marvell_nfc_remove, }; module_platform_driver(marvell_nfc_driver); diff --git a/drivers/mtd/nand/raw/meson_nand.c b/drivers/mtd/nand/raw/meson_nand.c index fbb06aa305cb5e..b8834aa96e81c4 100644 --- a/drivers/mtd/nand/raw/meson_nand.c +++ b/drivers/mtd/nand/raw/meson_nand.c @@ -1621,7 +1621,7 @@ static void meson_nfc_remove(struct platform_device *pdev) static struct platform_driver meson_nfc_driver = { .probe = meson_nfc_probe, - .remove_new = meson_nfc_remove, + .remove = meson_nfc_remove, .driver = { .name = "meson-nand", .of_match_table = meson_nfc_id_table, diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index 215610f808f169..97b4e7f3e1bb5e 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -835,7 +835,7 @@ MODULE_DEVICE_TABLE(of, mpc5121_nfc_match); static struct platform_driver mpc5121_nfc_driver = { .probe = mpc5121_nfc_probe, - .remove_new = mpc5121_nfc_remove, + .remove = mpc5121_nfc_remove, .driver = { .name = DRV_NAME, .of_match_table = mpc5121_nfc_match, diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index 586868b4139f51..21c7e110274693 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -1640,7 +1640,7 @@ static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume); static struct platform_driver mtk_nfc_driver = { .probe = mtk_nfc_probe, - .remove_new = mtk_nfc_remove, + .remove = mtk_nfc_remove, .driver = { .name = MTK_NAME, .of_match_table = mtk_nfc_id_table, diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 736808150e74aa..8c56b685bf91a4 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1824,7 +1824,7 @@ static struct platform_driver mxcnd_driver = { .of_match_table = mxcnd_dt_ids, }, .probe = mxcnd_probe, - .remove_new = mxcnd_remove, + .remove = mxcnd_remove, }; module_platform_driver(mxcnd_driver); diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c index be8050e84b4f1f..92de26697359cc 100644 --- a/drivers/mtd/nand/raw/mxic_nand.c +++ b/drivers/mtd/nand/raw/mxic_nand.c @@ -574,7 +574,7 @@ MODULE_DEVICE_TABLE(of, mxic_nfc_of_ids); static struct platform_driver mxic_nfc_driver = { .probe = mxic_nfc_probe, - .remove_new = mxic_nfc_remove, + .remove = mxic_nfc_remove, .driver = { .name = "mxic-nfc", .of_match_table = mxic_nfc_of_ids, diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index e229de32ff5000..03237310852cbf 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -113,7 +113,7 @@ static void macronix_nand_onfi_init(struct nand_chip *chip) rand_otp = of_property_read_bool(dn, "mxic,enable-randomizer-otp"); mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor; - /* Subpage write is prohibited in randomizer operatoin */ + /* Subpage write is prohibited in randomizer operation */ if (rand_otp && chip->options & NAND_NO_SUBPAGE_WRITE && mxic->reliability_func & MACRONIX_RANDOMIZER_BIT) { if (p->supports_set_get_features) { diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c index 3bb32a7c6d6798..13365128194d0c 100644 --- a/drivers/mtd/nand/raw/ndfc.c +++ b/drivers/mtd/nand/raw/ndfc.c @@ -266,7 +266,7 @@ static struct platform_driver ndfc_driver = { .of_match_table = ndfc_match, }, .probe = ndfc_probe, - .remove_new = ndfc_remove, + .remove = ndfc_remove, }; module_platform_driver(ndfc_driver); diff --git a/drivers/mtd/nand/raw/omap2.c b/drivers/mtd/nand/raw/omap2.c index cf76afc6c0edc2..d9141f3c0dd167 100644 --- a/drivers/mtd/nand/raw/omap2.c +++ b/drivers/mtd/nand/raw/omap2.c @@ -2291,7 +2291,7 @@ MODULE_DEVICE_TABLE(of, omap_nand_ids); static struct platform_driver omap_nand_driver = { .probe = omap_nand_probe, - .remove_new = omap_nand_remove, + .remove = omap_nand_remove, .driver = { .name = DRIVER_NAME, .of_match_table = omap_nand_ids, diff --git a/drivers/mtd/nand/raw/omap_elm.c b/drivers/mtd/nand/raw/omap_elm.c index 4a97d4a76454a2..c1d19b8e6715a7 100644 --- a/drivers/mtd/nand/raw/omap_elm.c +++ b/drivers/mtd/nand/raw/omap_elm.c @@ -560,7 +560,7 @@ static struct platform_driver elm_driver = { .pm = &elm_pm_ops, }, .probe = elm_probe, - .remove_new = elm_remove, + .remove = elm_remove, }; module_platform_driver(elm_driver); diff --git a/drivers/mtd/nand/raw/orion_nand.c b/drivers/mtd/nand/raw/orion_nand.c index 2951d81614fd07..47e80d5e58c598 100644 --- a/drivers/mtd/nand/raw/orion_nand.c +++ b/drivers/mtd/nand/raw/orion_nand.c @@ -214,7 +214,7 @@ MODULE_DEVICE_TABLE(of, orion_nand_of_match_table); #endif static struct platform_driver orion_nand_driver = { - .remove_new = orion_nand_remove, + .remove = orion_nand_remove, .driver = { .name = "orion_nand", .of_match_table = of_match_ptr(orion_nand_of_match_table), diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c index 19b2c9d25863b1..0b1f7670660e4a 100644 --- a/drivers/mtd/nand/raw/pasemi_nand.c +++ b/drivers/mtd/nand/raw/pasemi_nand.c @@ -237,7 +237,7 @@ static struct platform_driver pasemi_nand_driver = .of_match_table = pasemi_nand_match, }, .probe = pasemi_nand_probe, - .remove_new = pasemi_nand_remove, + .remove = pasemi_nand_remove, }; module_platform_driver(pasemi_nand_driver); diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index 2570fd0beea0d3..09440ed4652e73 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -187,7 +187,7 @@ static const struct mtd_ooblayout_ops pl35x_ecc_ooblayout16_ops = { .free = pl35x_ecc_ooblayout16_free, }; -/* Generic flash bbt decriptors */ +/* Generic flash bbt descriptors */ static u8 bbt_pattern[] = { 'B', 'b', 't', '0' }; static u8 mirror_pattern[] = { '1', 't', 'b', 'B' }; @@ -1184,7 +1184,7 @@ MODULE_DEVICE_TABLE(of, pl35x_nand_of_match); static struct platform_driver pl35x_nandc_driver = { .probe = pl35x_nand_probe, - .remove_new = pl35x_nand_remove, + .remove = pl35x_nand_remove, .driver = { .name = PL35X_NANDC_DRIVER_NAME, .of_match_table = pl35x_nand_of_match, diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c index b5c374b51ecdca..0bcd455328ef0d 100644 --- a/drivers/mtd/nand/raw/plat_nand.c +++ b/drivers/mtd/nand/raw/plat_nand.c @@ -144,7 +144,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match); static struct platform_driver plat_nand_driver = { .probe = plat_nand_probe, - .remove_new = plat_nand_remove, + .remove = plat_nand_remove, .driver = { .name = "gen_nand", .of_match_table = plat_nand_match, diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index b8cff9240b286c..636bba2528bfea 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -3535,8 +3535,8 @@ static struct platform_driver qcom_nandc_driver = { .name = "qcom-nandc", .of_match_table = qcom_nandc_of_match, }, - .probe = qcom_nandc_probe, - .remove_new = qcom_nandc_remove, + .probe = qcom_nandc_probe, + .remove = qcom_nandc_remove, }; module_platform_driver(qcom_nandc_driver); diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c index ed0cf732d20e40..b07c2f8b40350d 100644 --- a/drivers/mtd/nand/raw/r852.c +++ b/drivers/mtd/nand/raw/r852.c @@ -335,7 +335,7 @@ static void r852_cmdctl(struct nand_chip *chip, int dat, unsigned int ctrl) else dev->ctlreg &= ~R852_CTL_WRITE; - /* when write is stareted, enable write access */ + /* when write is started, enable write access */ if (dat == NAND_CMD_ERASE1) dev->ctlreg |= R852_CTL_WRITE; @@ -372,7 +372,7 @@ static int r852_wait(struct nand_chip *chip) nand_status_op(chip, &status); - /* Unfortunelly, no way to send detailed error status... */ + /* Unfortunately, no way to send detailed error status... */ if (dev->dma_error) { status |= NAND_STATUS_FAIL; dev->dma_error = 0; diff --git a/drivers/mtd/nand/raw/renesas-nand-controller.c b/drivers/mtd/nand/raw/renesas-nand-controller.c index 0e92d50c5249b0..44f6603736d19b 100644 --- a/drivers/mtd/nand/raw/renesas-nand-controller.c +++ b/drivers/mtd/nand/raw/renesas-nand-controller.c @@ -1402,7 +1402,7 @@ static struct platform_driver rnandc_driver = { .of_match_table = rnandc_id_table, }, .probe = rnandc_probe, - .remove_new = rnandc_remove, + .remove = rnandc_remove, }; module_platform_driver(rnandc_driver); diff --git a/drivers/mtd/nand/raw/rockchip-nand-controller.c b/drivers/mtd/nand/raw/rockchip-nand-controller.c index 51c9cf9013dc28..63e7b9e39a5ab0 100644 --- a/drivers/mtd/nand/raw/rockchip-nand-controller.c +++ b/drivers/mtd/nand/raw/rockchip-nand-controller.c @@ -1477,7 +1477,7 @@ static const struct dev_pm_ops rk_nfc_pm_ops = { static struct platform_driver rk_nfc_driver = { .probe = rk_nfc_probe, - .remove_new = rk_nfc_remove, + .remove = rk_nfc_remove, .driver = { .name = "rockchip-nfc", .of_match_table = rk_nfc_id_table, diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index 48c1d0eb66ca4c..229f2e87d56eea 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -1213,7 +1213,7 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); static struct platform_driver s3c24xx_nand_driver = { .probe = s3c24xx_nand_probe, - .remove_new = s3c24xx_nand_remove, + .remove = s3c24xx_nand_remove, .suspend = s3c24xx_nand_suspend, .resume = s3c24xx_nand_resume, .id_table = s3c24xx_driver_ids, diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index 2a8164efb273d7..97f733e481ffc2 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -1216,7 +1216,7 @@ static void flctl_remove(struct platform_device *pdev) static struct platform_driver flctl_driver = { .probe = flctl_probe, - .remove_new = flctl_remove, + .remove = flctl_remove, .driver = { .name = "sh_flctl", .of_match_table = of_flctl_match, diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c index 2402dc5465d547..142e93b200a3b0 100644 --- a/drivers/mtd/nand/raw/sharpsl.c +++ b/drivers/mtd/nand/raw/sharpsl.c @@ -234,7 +234,7 @@ static struct platform_driver sharpsl_nand_driver = { .name = "sharpsl-nand", }, .probe = sharpsl_nand_probe, - .remove_new = sharpsl_nand_remove, + .remove = sharpsl_nand_remove, }; module_platform_driver(sharpsl_nand_driver); diff --git a/drivers/mtd/nand/raw/sm_common.c b/drivers/mtd/nand/raw/sm_common.c index 24f52a30fb1304..e238784c8c3eec 100644 --- a/drivers/mtd/nand/raw/sm_common.c +++ b/drivers/mtd/nand/raw/sm_common.c @@ -52,8 +52,8 @@ static const struct mtd_ooblayout_ops oob_sm_ops = { .free = oob_sm_ooblayout_free, }; -/* NOTE: This layout is not compatabable with SmartMedia, */ -/* because the 256 byte devices have page depenent oob layout */ +/* NOTE: This layout is not compatible with SmartMedia, */ +/* because the 256 byte devices have page dependent oob layout */ /* However it does preserve the bad block markers */ /* If you use smftl, it will bypass this and work correctly */ /* If you not, then you break SmartMedia compliance anyway */ diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c index 76d50eb9f1db50..668584683ce502 100644 --- a/drivers/mtd/nand/raw/socrates_nand.c +++ b/drivers/mtd/nand/raw/socrates_nand.c @@ -231,7 +231,7 @@ static struct platform_driver socrates_nand_driver = { .of_match_table = socrates_nand_match, }, .probe = socrates_nand_probe, - .remove_new = socrates_nand_remove, + .remove = socrates_nand_remove, }; module_platform_driver(socrates_nand_driver); diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 0f67e96cc24020..a960403081f110 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -2147,7 +2147,7 @@ MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match); static struct platform_driver stm32_fmc2_nfc_driver = { .probe = stm32_fmc2_nfc_probe, - .remove_new = stm32_fmc2_nfc_remove, + .remove = stm32_fmc2_nfc_remove, .driver = { .name = "stm32_fmc2_nfc", .of_match_table = stm32_fmc2_nfc_match, diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index c28634e20abf8a..fab371e3e9b780 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -2196,7 +2196,7 @@ static struct platform_driver sunxi_nfc_driver = { .of_match_table = sunxi_nfc_ids, }, .probe = sunxi_nfc_probe, - .remove_new = sunxi_nfc_remove, + .remove = sunxi_nfc_remove, }; module_platform_driver(sunxi_nfc_driver); diff --git a/drivers/mtd/nand/raw/technologic-nand-controller.c b/drivers/mtd/nand/raw/technologic-nand-controller.c index 0e45a6fd91dd4b..a3294aaf43bda0 100644 --- a/drivers/mtd/nand/raw/technologic-nand-controller.c +++ b/drivers/mtd/nand/raw/technologic-nand-controller.c @@ -213,7 +213,7 @@ static struct platform_driver ts72xx_nand_driver = { .of_match_table = ts72xx_id_table, }, .probe = ts72xx_nand_probe, - .remove_new = ts72xx_nand_remove, + .remove = ts72xx_nand_remove, }; module_platform_driver(ts72xx_nand_driver); diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index a553e3ac8ff41d..7f9eb5f042a7ee 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -1279,7 +1279,7 @@ static struct platform_driver tegra_nand_driver = { .pm = &tegra_nand_pm, }, .probe = tegra_nand_probe, - .remove_new = tegra_nand_remove, + .remove = tegra_nand_remove, }; module_platform_driver(tegra_nand_driver); diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c index 37f79c019a72f8..907fb5de426983 100644 --- a/drivers/mtd/nand/raw/txx9ndfmc.c +++ b/drivers/mtd/nand/raw/txx9ndfmc.c @@ -405,7 +405,7 @@ static int txx9ndfmc_resume(struct platform_device *dev) static struct platform_driver txx9ndfmc_driver = { .probe = txx9ndfmc_probe, - .remove_new = txx9ndfmc_remove, + .remove = txx9ndfmc_remove, .resume = txx9ndfmc_resume, .driver = { .name = "txx9ndfmc", diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index f31d23219f9148..4b5ba31878535f 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -941,7 +941,7 @@ static struct platform_driver vf610_nfc_driver = { .pm = &vf610_nfc_pm_ops, }, .probe = vf610_nfc_probe, - .remove_new = vf610_nfc_remove, + .remove = vf610_nfc_remove, }; module_platform_driver(vf610_nfc_driver); diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c index 008549011fb91c..af84395dc66ead 100644 --- a/drivers/mtd/nand/raw/xway_nand.c +++ b/drivers/mtd/nand/raw/xway_nand.c @@ -256,7 +256,7 @@ static const struct of_device_id xway_nand_match[] = { static struct platform_driver xway_nand_driver = { .probe = xway_nand_probe, - .remove_new = xway_nand_remove, + .remove = xway_nand_remove, .driver = { .name = "lantiq,nand-xway", .of_match_table = xway_nand_match, diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 4d76f9f71a0e9e..b1df7f6271616b 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -337,7 +337,7 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand, return ret; } -static struct nand_ecc_engine_ops spinand_ondie_ecc_engine_ops = { +static const struct nand_ecc_engine_ops spinand_ondie_ecc_engine_ops = { .init_ctx = spinand_ondie_ecc_init_ctx, .cleanup_ctx = spinand_ondie_ecc_cleanup_ctx, .prepare_io_req = spinand_ondie_ecc_prepare_io_req, diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index f3bb81d7e46045..7180e615ac9752 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -161,17 +161,18 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand, } static const struct spinand_info winbond_spinand_table[] = { - SPINAND_INFO("W25M02GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), + /* 512M-bit densities */ + SPINAND_INFO("W25N512GW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x20), + NAND_MEMORG(1, 2048, 64, 64, 512, 10, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), - SPINAND_SELECT_TARGET(w25m02gv_select_target)), - SPINAND_INFO("W25N01GV", + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + /* 1G-bit densities */ + SPINAND_INFO("W25N01GV", /* 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), @@ -180,52 +181,63 @@ static const struct spinand_info winbond_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), - SPINAND_INFO("W25N01KV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), - NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1), - NAND_ECCREQ(4, 512), + SPINAND_INFO("W25N01GW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&w25n01kv_ooblayout, w25n02kv_ecc_get_status)), - SPINAND_INFO("W25N02KV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), - NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), - NAND_ECCREQ(8, 512), + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + SPINAND_INFO("W25N01JW", /* high-speed 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), - SPINAND_INFO("W25N01JW", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + SPINAND_INFO("W25N01KV", /* 3.3V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), + NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)), - SPINAND_INFO("W25N02JWZEIF", + SPINAND_ECCINFO(&w25n01kv_ooblayout, w25n02kv_ecc_get_status)), + /* 2G-bit densities */ + SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), + SPINAND_SELECT_TARGET(w25m02gv_select_target)), + SPINAND_INFO("W25N02JW", /* high-speed 1.8V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1), - NAND_ECCREQ(4, 512), + NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), - SPINAND_INFO("W25N512GW", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x20), - NAND_MEMORG(1, 2048, 64, 64, 512, 10, 1, 1, 1), - NAND_ECCREQ(4, 512), + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + SPINAND_INFO("W25N02KV", /* 3.3V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), - SPINAND_INFO("W25N02KWZEIR", + SPINAND_INFO("W25N02KW", /* 1.8V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x22), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), @@ -234,18 +246,19 @@ static const struct spinand_info winbond_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), - SPINAND_INFO("W25N01GWZEIG", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x21), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), - NAND_ECCREQ(4, 512), + /* 4G-bit densities */ + SPINAND_INFO("W25N04KV", /* 3.3V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), + NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1), + NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&w25m02gv_ooblayout, w25n02kv_ecc_get_status)), - SPINAND_INFO("W25N04KV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), - NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1), + SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + SPINAND_INFO("W25N04KW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x23), + NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, diff --git a/drivers/mtd/spi-nor/controllers/hisi-sfc.c b/drivers/mtd/spi-nor/controllers/hisi-sfc.c index 89a7f0bbc4b322..db948da2c4c545 100644 --- a/drivers/mtd/spi-nor/controllers/hisi-sfc.c +++ b/drivers/mtd/spi-nor/controllers/hisi-sfc.c @@ -488,7 +488,7 @@ static struct platform_driver hisi_spi_nor_driver = { .of_match_table = hisi_spi_nor_dt_ids, }, .probe = hisi_spi_nor_probe, - .remove_new = hisi_spi_nor_remove, + .remove = hisi_spi_nor_remove, }; module_platform_driver(hisi_spi_nor_driver); diff --git a/drivers/mtd/spi-nor/controllers/nxp-spifi.c b/drivers/mtd/spi-nor/controllers/nxp-spifi.c index 5aee62f51031f1..1a92d71755db93 100644 --- a/drivers/mtd/spi-nor/controllers/nxp-spifi.c +++ b/drivers/mtd/spi-nor/controllers/nxp-spifi.c @@ -446,7 +446,7 @@ MODULE_DEVICE_TABLE(of, nxp_spifi_match); static struct platform_driver nxp_spifi_driver = { .probe = nxp_spifi_probe, - .remove_new = nxp_spifi_remove, + .remove = nxp_spifi_remove, .driver = { .name = "nxp-spifi", .of_match_table = nxp_spifi_match, diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 9d6e85bf227b92..66949d9f0cc5a0 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -89,7 +89,7 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor, op->addr.buswidth = spi_nor_get_protocol_addr_nbits(proto); if (op->dummy.nbytes) - op->dummy.buswidth = spi_nor_get_protocol_addr_nbits(proto); + op->dummy.buswidth = spi_nor_get_protocol_data_nbits(proto); if (op->data.nbytes) op->data.buswidth = spi_nor_get_protocol_data_nbits(proto); @@ -113,6 +113,9 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor, op->cmd.opcode = (op->cmd.opcode << 8) | ext; op->cmd.nbytes = 2; } + + if (proto == SNOR_PROTO_8_8_8_DTR && nor->flags & SNOR_F_SWAP16) + op->data.swap16 = true; } /** diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h index 1516b6d0dc37a3..5c33740ed7f5f4 100644 --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h @@ -140,6 +140,7 @@ enum spi_nor_option_flags { SNOR_F_RWW = BIT(14), SNOR_F_ECC = BIT(15), SNOR_F_NO_WP = BIT(16), + SNOR_F_SWAP16 = BIT(17), }; struct spi_nor_read_command { diff --git a/drivers/mtd/spi-nor/macronix.c b/drivers/mtd/spi-nor/macronix.c index ea6be95e75a526..830da21eea08fe 100644 --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -8,6 +8,23 @@ #include "core.h" +#define MXIC_NOR_OP_RD_CR2 0x71 /* Read configuration register 2 opcode */ +#define MXIC_NOR_OP_WR_CR2 0x72 /* Write configuration register 2 opcode */ +#define MXIC_NOR_ADDR_CR2_MODE 0x00000000 /* CR2 address for setting spi/sopi/dopi mode */ +#define MXIC_NOR_ADDR_CR2_DC 0x00000300 /* CR2 address for setting dummy cycles */ +#define MXIC_NOR_REG_DOPI_EN 0x2 /* Enable Octal DTR */ +#define MXIC_NOR_REG_SPI_EN 0x0 /* Enable SPI */ + +/* Convert dummy cycles to bit pattern */ +#define MXIC_NOR_REG_DC(p) \ + ((20 - (p)) >> 1) + +#define MXIC_NOR_WR_CR2(addr, ndata, buf) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(MXIC_NOR_OP_WR_CR2, 0), \ + SPI_MEM_OP_ADDR(4, addr, 0), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) + static int mx25l25635_post_bfpt_fixups(struct spi_nor *nor, const struct sfdp_parameter_header *bfpt_header, @@ -182,9 +199,88 @@ static const struct flash_info macronix_nor_parts[] = { .name = "mx25l3255e", .size = SZ_4M, .no_sfdp_flags = SECT_4K, - } + }, + /* + * This spares us of adding new flash entries for flashes that can be + * initialized solely based on the SFDP data, but still need the + * manufacturer hooks to set parameters that can't be discovered at SFDP + * parsing time. + */ + { .id = SNOR_ID(0xc2) } }; +static int macronix_nor_octal_dtr_en(struct spi_nor *nor) +{ + struct spi_mem_op op; + u8 *buf = nor->bouncebuf, i; + int ret; + + /* Use dummy cycles which is parse by SFDP and convert to bit pattern. */ + buf[0] = MXIC_NOR_REG_DC(nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].num_wait_states); + op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_DC, 1, buf); + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + /* Set the octal and DTR enable bits. */ + buf[0] = MXIC_NOR_REG_DOPI_EN; + op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_MODE, 1, buf); + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); + if (ret) + return ret; + + /* Read flash ID to make sure the switch was successful. */ + ret = spi_nor_read_id(nor, 4, 4, buf, SNOR_PROTO_8_8_8_DTR); + if (ret) { + dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); + return ret; + } + + /* Macronix SPI-NOR flash 8D-8D-8D read ID would get 6 bytes data A-A-B-B-C-C */ + for (i = 0; i < nor->info->id->len; i++) + if (buf[i * 2] != buf[(i * 2) + 1] || buf[i * 2] != nor->info->id->bytes[i]) + return -EINVAL; + + return 0; +} + +static int macronix_nor_octal_dtr_dis(struct spi_nor *nor) +{ + struct spi_mem_op op; + u8 *buf = nor->bouncebuf; + int ret; + + /* + * The register is 1-byte wide, but 1-byte transactions are not + * allowed in 8D-8D-8D mode. Since there is no register at the + * next location, just initialize the value to 0 and let the + * transaction go on. + */ + buf[0] = MXIC_NOR_REG_SPI_EN; + buf[1] = 0x0; + op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_MODE, 2, buf); + ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); + if (ret) + return ret; + + /* Read flash ID to make sure the switch was successful. */ + ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); + if (ret) { + dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret); + return ret; + } + + if (memcmp(buf, nor->info->id->bytes, nor->info->id->len)) + return -EINVAL; + + return 0; +} + +static int macronix_nor_set_octal_dtr(struct spi_nor *nor, bool enable) +{ + return enable ? macronix_nor_octal_dtr_en(nor) : macronix_nor_octal_dtr_dis(nor); +} + static void macronix_nor_default_init(struct spi_nor *nor) { nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; @@ -194,6 +290,7 @@ static int macronix_nor_late_init(struct spi_nor *nor) { if (!nor->params->set_4byte_addr_mode) nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; + nor->params->set_octal_dtr = macronix_nor_set_octal_dtr; return 0; } diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 5b1117265bd289..21727f9a4ac692 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -671,6 +671,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, return -EOPNOTSUPP; } + /* Byte order in 8D-8D-8D mode */ + if (bfpt.dwords[SFDP_DWORD(18)] & BFPT_DWORD18_BYTE_ORDER_SWAPPED) + nor->flags |= SNOR_F_SWAP16; + return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt); } diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h index da0fe5aa9bb0a1..f74a0eb339ea79 100644 --- a/drivers/mtd/spi-nor/sfdp.h +++ b/drivers/mtd/spi-nor/sfdp.h @@ -130,6 +130,7 @@ struct sfdp_bfpt { #define BFPT_DWORD18_CMD_EXT_INV (0x1UL << 29) /* Invert */ #define BFPT_DWORD18_CMD_EXT_RES (0x2UL << 29) /* Reserved */ #define BFPT_DWORD18_CMD_EXT_16B (0x3UL << 29) /* 16-bit opcode */ +#define BFPT_DWORD18_BYTE_ORDER_SWAPPED BIT(31) /* Byte order swapped in 8D-8D-8D mode */ struct sfdp_parameter_header { u8 id_lsb; diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index d6c92595f6bc9b..5a88a6096ca8c9 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -106,6 +106,7 @@ static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr) int ret; if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) { + op.addr.nbytes = nor->addr_nbytes; op.dummy.nbytes = params->rdsr_dummy; op.data.nbytes = 2; } diff --git a/drivers/mtd/spi-nor/sysfs.c b/drivers/mtd/spi-nor/sysfs.c index 96064e4babf01f..5e9eb268073d18 100644 --- a/drivers/mtd/spi-nor/sysfs.c +++ b/drivers/mtd/spi-nor/sysfs.c @@ -87,7 +87,7 @@ static umode_t spi_nor_sysfs_is_visible(struct kobject *kobj, } static umode_t spi_nor_sysfs_is_bin_visible(struct kobject *kobj, - struct bin_attribute *attr, int n) + const struct bin_attribute *attr, int n) { struct spi_device *spi = to_spi_device(kobj_to_dev(kobj)); struct spi_mem *spimem = spi_get_drvdata(spi); diff --git a/drivers/mtd/spi-nor/winbond.c b/drivers/mtd/spi-nor/winbond.c index 9f7ce5763e7104..8d0a00d69e1233 100644 --- a/drivers/mtd/spi-nor/winbond.c +++ b/drivers/mtd/spi-nor/winbond.c @@ -129,6 +129,7 @@ static const struct flash_info winbond_nor_parts[] = { .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, }, { .id = SNOR_ID(0xef, 0x40, 0x18), + /* Flavors w/ and w/o SFDP. */ .name = "w25q128", .size = SZ_16M, .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 13fed398937e40..e1ee68f8b8f890 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include "mtd_test.h" diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c index 8eb40b6e6dfa93..6878700d2fc04c 100644 --- a/drivers/mtd/tests/pagetest.c +++ b/drivers/mtd/tests/pagetest.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include "mtd_test.h" diff --git a/drivers/mtd/tests/subpagetest.c b/drivers/mtd/tests/subpagetest.c index 05250a080139f1..f34bbf033c4d3a 100644 --- a/drivers/mtd/tests/subpagetest.c +++ b/drivers/mtd/tests/subpagetest.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "mtd_test.h" diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index ae5abe492b52ab..adc47b87b38a5f 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -1447,7 +1447,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai, return err; } -static struct ubi_attach_info *alloc_ai(void) +static struct ubi_attach_info *alloc_ai(const char *slab_name) { struct ubi_attach_info *ai; @@ -1461,7 +1461,7 @@ static struct ubi_attach_info *alloc_ai(void) INIT_LIST_HEAD(&ai->alien); INIT_LIST_HEAD(&ai->fastmap); ai->volumes = RB_ROOT; - ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache", + ai->aeb_slab_cache = kmem_cache_create(slab_name, sizeof(struct ubi_ainf_peb), 0, 0, NULL); if (!ai->aeb_slab_cache) { @@ -1491,7 +1491,7 @@ static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info **ai) err = -ENOMEM; - scan_ai = alloc_ai(); + scan_ai = alloc_ai("ubi_aeb_slab_cache_fastmap"); if (!scan_ai) goto out; @@ -1557,7 +1557,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) int err; struct ubi_attach_info *ai; - ai = alloc_ai(); + ai = alloc_ai("ubi_aeb_slab_cache"); if (!ai) return -ENOMEM; @@ -1575,7 +1575,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) if (err > 0 || mtd_is_eccerr(err)) { if (err != UBI_NO_FASTMAP) { destroy_ai(ai); - ai = alloc_ai(); + ai = alloc_ai("ubi_aeb_slab_cache"); if (!ai) return -ENOMEM; @@ -1614,7 +1614,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan) if (ubi->fm && ubi_dbg_chk_fastmap(ubi)) { struct ubi_attach_info *scan_ai; - scan_ai = alloc_ai(); + scan_ai = alloc_ai("ubi_aeb_slab_cache_dbg_chk_fastmap"); if (!scan_ai) { err = -ENOMEM; goto out_wl; diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 2a9cc9413c427d..9bdb6525f1281f 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -346,14 +346,27 @@ int ubi_wl_get_peb(struct ubi_device *ubi) * WL sub-system. * * @ubi: UBI device description object + * @need_fill: whether to fill wear-leveling pool when no PEBs are found */ -static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi) +static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi, + bool need_fill) { struct ubi_fm_pool *pool = &ubi->fm_wl_pool; int pnum; - if (pool->used == pool->size) + if (pool->used == pool->size) { + if (need_fill && !ubi->fm_work_scheduled) { + /* + * We cannot update the fastmap here because this + * function is called in atomic context. + * Let's fail here and refill/update it as soon as + * possible. + */ + ubi->fm_work_scheduled = 1; + schedule_work(&ubi->fm_work); + } return NULL; + } pnum = pool->pebs[pool->used]; return ubi->lookuptbl[pnum]; @@ -375,7 +388,7 @@ static bool need_wear_leveling(struct ubi_device *ubi) if (!ubi->used.rb_node) return false; - e = next_peb_for_wl(ubi); + e = next_peb_for_wl(ubi, false); if (!e) { if (!ubi->free.rb_node) return false; diff --git a/drivers/mtd/ubi/nvmem.c b/drivers/mtd/ubi/nvmem.c index a94a1a9aaec10e..34f8c1d3cdeed4 100644 --- a/drivers/mtd/ubi/nvmem.c +++ b/drivers/mtd/ubi/nvmem.c @@ -55,7 +55,7 @@ static int ubi_nvmem_reg_read(void *priv, unsigned int from, if (err) return err; - return bytes_left == 0 ? 0 : -EIO; + return 0; } static int ubi_nvmem_add(struct ubi_volume_info *vi) diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 1c9e874e8edeae..26cc53ad34ec77 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -549,6 +549,7 @@ struct ubi_debug_info { * @peb_buf: a buffer of PEB size used for different purposes * @buf_mutex: protects @peb_buf * @ckvol_mutex: serializes static volume checking when opening + * @wl_reboot_notifier: close all wear-leveling work before reboot * * @dbg: debugging information for this UBI device */ @@ -651,6 +652,7 @@ struct ubi_device { void *peb_buf; struct mutex buf_mutex; struct mutex ckvol_mutex; + struct notifier_block wl_reboot_notifier; struct ubi_debug_info dbg; }; @@ -831,7 +833,6 @@ void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av); struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi, struct ubi_attach_info *ai); int ubi_attach(struct ubi_device *ubi, int force_scan); -void ubi_destroy_ai(struct ubi_attach_info *ai); /* vtbl.c */ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 5a3558bbb90356..e5cf3bdca3b012 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -143,8 +143,10 @@ static struct fwnode_handle *find_volume_fwnode(struct ubi_volume *vol) vol->vol_id != volid) continue; + fwnode_handle_put(fw_vols); return fw_vol; } + fwnode_handle_put(fw_vols); return NULL; } diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index a357f3d27f2f3d..4f6f339d8fb8ab 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -89,6 +89,7 @@ #include #include #include +#include #include "ubi.h" #include "wl.h" @@ -127,6 +128,8 @@ static int self_check_in_wl_tree(const struct ubi_device *ubi, struct ubi_wl_entry *e, struct rb_root *root); static int self_check_in_pq(const struct ubi_device *ubi, struct ubi_wl_entry *e); +static int ubi_wl_reboot_notifier(struct notifier_block *n, + unsigned long state, void *cmd); /** * wl_tree_add - add a wear-leveling entry to a WL RB-tree. @@ -683,7 +686,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ubi_assert(!ubi->move_to_put); #ifdef CONFIG_MTD_UBI_FASTMAP - if (!next_peb_for_wl(ubi) || + if (!next_peb_for_wl(ubi, true) || #else if (!ubi->free.rb_node || #endif @@ -846,7 +849,14 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, goto out_not_moved; } if (err == MOVE_RETRY) { - scrubbing = 1; + /* + * For source PEB: + * 1. The scrubbing is set for scrub type PEB, it will + * be put back into ubi->scrub list. + * 2. Non-scrub type PEB will be put back into ubi->used + * list. + */ + keep = 1; dst_leb_clean = 1; goto out_not_moved; } @@ -1943,6 +1953,13 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) if (!ubi->ro_mode && !ubi->fm_disabled) ubi_ensure_anchor_pebs(ubi); #endif + + if (!ubi->wl_reboot_notifier.notifier_call) { + ubi->wl_reboot_notifier.notifier_call = ubi_wl_reboot_notifier; + ubi->wl_reboot_notifier.priority = 1; /* Higher than MTD */ + register_reboot_notifier(&ubi->wl_reboot_notifier); + } + return 0; out_free: @@ -1988,6 +2005,17 @@ void ubi_wl_close(struct ubi_device *ubi) kfree(ubi->lookuptbl); } +static int ubi_wl_reboot_notifier(struct notifier_block *n, + unsigned long state, void *cmd) +{ + struct ubi_device *ubi; + + ubi = container_of(n, struct ubi_device, wl_reboot_notifier); + ubi_wl_close(ubi); + + return NOTIFY_DONE; +} + /** * self_check_ec - make sure that the erase counter of a PEB is correct. * @ubi: UBI device description object diff --git a/drivers/mtd/ubi/wl.h b/drivers/mtd/ubi/wl.h index 7b6715ef6d4a35..a69169c35e310f 100644 --- a/drivers/mtd/ubi/wl.h +++ b/drivers/mtd/ubi/wl.h @@ -5,7 +5,8 @@ static void update_fastmap_work_fn(struct work_struct *wrk); static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root); static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi); -static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi); +static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi, + bool need_fill); static bool need_wear_leveling(struct ubi_device *ubi); static void ubi_fastmap_close(struct ubi_device *ubi); static inline void ubi_fastmap_init(struct ubi_device *ubi, int *count) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9920b3a68ed158..1fd5acdc73c6af 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -641,6 +641,7 @@ config NETDEVSIM depends on PTP_1588_CLOCK_MOCK || PTP_1588_CLOCK_MOCK=n select NET_DEVLINK select PAGE_POOL + select NET_SHAPER help This driver is a developer testing tool and software model that can be used to test various control path networking APIs, especially diff --git a/drivers/net/amt.c b/drivers/net/amt.c index 0433a0f36d1b4e..98c6205ed19f15 100644 --- a/drivers/net/amt.c +++ b/drivers/net/amt.c @@ -3206,15 +3206,11 @@ static int amt_newlink(struct net *net, struct net_device *dev, goto err; } - if (data[IFLA_AMT_RELAY_PORT]) - amt->relay_port = nla_get_be16(data[IFLA_AMT_RELAY_PORT]); - else - amt->relay_port = htons(IANA_AMT_UDP_PORT); + amt->relay_port = nla_get_be16_default(data[IFLA_AMT_RELAY_PORT], + htons(IANA_AMT_UDP_PORT)); - if (data[IFLA_AMT_GATEWAY_PORT]) - amt->gw_port = nla_get_be16(data[IFLA_AMT_GATEWAY_PORT]); - else - amt->gw_port = htons(IANA_AMT_UDP_PORT); + amt->gw_port = nla_get_be16_default(data[IFLA_AMT_GATEWAY_PORT], + htons(IANA_AMT_UDP_PORT)); if (!amt->relay_port) { NL_SET_ERR_MSG_ATTR(extack, tb[IFLA_AMT_DISCOVERY_IP], diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index e057526448d780..a2abfade82dd1c 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -84,7 +84,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (skb_copy_bits(skb, BAREUDP_BASE_HLEN, &ipversion, sizeof(ipversion))) { - DEV_STATS_INC(bareudp->dev, rx_dropped); + dev_core_stats_rx_dropped_inc(bareudp->dev); goto drop; } ipversion >>= 4; @@ -94,7 +94,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) } else if (ipversion == 6 && bareudp->multi_proto_mode) { proto = htons(ETH_P_IPV6); } else { - DEV_STATS_INC(bareudp->dev, rx_dropped); + dev_core_stats_rx_dropped_inc(bareudp->dev); goto drop; } } else if (bareudp->ethertype == htons(ETH_P_MPLS_UC)) { @@ -108,7 +108,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) ipv4_is_multicast(tunnel_hdr->daddr)) { proto = htons(ETH_P_MPLS_MC); } else { - DEV_STATS_INC(bareudp->dev, rx_dropped); + dev_core_stats_rx_dropped_inc(bareudp->dev); goto drop; } } else { @@ -124,7 +124,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) (addr_type & IPV6_ADDR_MULTICAST)) { proto = htons(ETH_P_MPLS_MC); } else { - DEV_STATS_INC(bareudp->dev, rx_dropped); + dev_core_stats_rx_dropped_inc(bareudp->dev); goto drop; } } @@ -136,7 +136,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) proto, !net_eq(bareudp->net, dev_net(bareudp->dev)))) { - DEV_STATS_INC(bareudp->dev, rx_dropped); + dev_core_stats_rx_dropped_inc(bareudp->dev); goto drop; } @@ -144,7 +144,7 @@ static int bareudp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) tun_dst = udp_tun_rx_dst(skb, family, key, 0, 0); if (!tun_dst) { - DEV_STATS_INC(bareudp->dev, rx_dropped); + dev_core_stats_rx_dropped_inc(bareudp->dev); goto drop; } skb_dst_set(skb, &tun_dst->dst); @@ -317,7 +317,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, __be32 saddr; int err; - if (!skb_vlan_inet_prepare(skb, skb->protocol != htons(ETH_P_TEB))) + if (skb_vlan_inet_prepare(skb, skb->protocol != htons(ETH_P_TEB))) return -EINVAL; if (!sock) @@ -387,7 +387,7 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev, __be16 sport; int err; - if (!skb_vlan_inet_prepare(skb, skb->protocol != htons(ETH_P_TEB))) + if (skb_vlan_inet_prepare(skb, skb->protocol != htons(ETH_P_TEB))) return -EINVAL; if (!sock) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 15e0f14d0d49de..7b78c2bada8149 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1480,7 +1480,7 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev) slave_disable_netpoll(slave); } -static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni) +static int bond_netpoll_setup(struct net_device *dev) { struct bonding *bond = netdev_priv(dev); struct list_head *iter; @@ -1520,9 +1520,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, struct slave *slave; mask = features; - - features &= ~NETIF_F_ONE_FOR_ALL; - features |= NETIF_F_ALL_FOR_ALL; + features = netdev_base_features(features); bond_for_each_slave(bond, slave, iter) { features = netdev_increment_features(features, @@ -1536,6 +1534,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev, #define BOND_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \ + NETIF_F_GSO_ENCAP_ALL | \ NETIF_F_HIGHDMA | NETIF_F_LRO) #define BOND_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ @@ -1549,6 +1548,7 @@ static void bond_compute_features(struct bonding *bond) { unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM; + netdev_features_t gso_partial_features = NETIF_F_GSO_ESP; netdev_features_t vlan_features = BOND_VLAN_FEATURES; netdev_features_t enc_features = BOND_ENC_FEATURES; #ifdef CONFIG_XFRM_OFFLOAD @@ -1564,8 +1564,9 @@ static void bond_compute_features(struct bonding *bond) if (!bond_has_slaves(bond)) goto done; - vlan_features &= NETIF_F_ALL_FOR_ALL; - mpls_features &= NETIF_F_ALL_FOR_ALL; + + vlan_features = netdev_base_features(vlan_features); + mpls_features = netdev_base_features(mpls_features); bond_for_each_slave(bond, slave, iter) { vlan_features = netdev_increment_features(vlan_features, @@ -1581,6 +1582,9 @@ static void bond_compute_features(struct bonding *bond) BOND_XFRM_FEATURES); #endif /* CONFIG_XFRM_OFFLOAD */ + if (slave->dev->hw_enc_features & NETIF_F_GSO_PARTIAL) + gso_partial_features &= slave->dev->gso_partial_features; + mpls_features = netdev_increment_features(mpls_features, slave->dev->mpls_features, BOND_MPLS_FEATURES); @@ -1594,6 +1598,11 @@ static void bond_compute_features(struct bonding *bond) } bond_dev->hard_header_len = max_hard_header_len; + if (gso_partial_features & NETIF_F_GSO_ESP) + bond_dev->gso_partial_features |= NETIF_F_GSO_ESP; + else + bond_dev->gso_partial_features &= ~NETIF_F_GSO_ESP; + done: bond_dev->vlan_features = vlan_features; bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL | @@ -5690,8 +5699,11 @@ static int bond_xdp_set(struct net_device *dev, struct bpf_prog *prog, ASSERT_RTNL(); - if (!bond_xdp_check(bond)) + if (!bond_xdp_check(bond)) { + BOND_NL_ERR(dev, extack, + "No native XDP support for the current bonding mode"); return -EOPNOTSUPP; + } old_prog = bond->xdp_prog; bond->xdp_prog = prog; diff --git a/drivers/net/can/c_can/c_can_main.c b/drivers/net/can/c_can/c_can_main.c index 511615dc334196..cc371d0c9f3c76 100644 --- a/drivers/net/can/c_can/c_can_main.c +++ b/drivers/net/can/c_can/c_can_main.c @@ -1014,49 +1014,57 @@ static int c_can_handle_bus_err(struct net_device *dev, /* propagate the error condition to the CAN stack */ skb = alloc_can_err_skb(dev, &cf); - if (unlikely(!skb)) - return 0; /* check for 'last error code' which tells us the * type of the last error to occur on the CAN bus */ - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + if (likely(skb)) + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; switch (lec_type) { case LEC_STUFF_ERROR: netdev_dbg(dev, "stuff error\n"); - cf->data[2] |= CAN_ERR_PROT_STUFF; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_STUFF; stats->rx_errors++; break; case LEC_FORM_ERROR: netdev_dbg(dev, "form error\n"); - cf->data[2] |= CAN_ERR_PROT_FORM; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_FORM; stats->rx_errors++; break; case LEC_ACK_ERROR: netdev_dbg(dev, "ack error\n"); - cf->data[3] = CAN_ERR_PROT_LOC_ACK; + if (likely(skb)) + cf->data[3] = CAN_ERR_PROT_LOC_ACK; stats->tx_errors++; break; case LEC_BIT1_ERROR: netdev_dbg(dev, "bit1 error\n"); - cf->data[2] |= CAN_ERR_PROT_BIT1; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_BIT1; stats->tx_errors++; break; case LEC_BIT0_ERROR: netdev_dbg(dev, "bit0 error\n"); - cf->data[2] |= CAN_ERR_PROT_BIT0; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_BIT0; stats->tx_errors++; break; case LEC_CRC_ERROR: netdev_dbg(dev, "CRC error\n"); - cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + if (likely(skb)) + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; stats->rx_errors++; break; default: break; } + if (unlikely(!skb)) + return 0; + netif_receive_skb(skb); return 1; } diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 6792c14fd7eb00..681643ab37804e 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -468,7 +468,7 @@ static int can_set_termination(struct net_device *ndev, u16 term) else set = 0; - gpiod_set_value(priv->termination_gpio, set); + gpiod_set_value_cansleep(priv->termination_gpio, set); return 0; } diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index d32b10900d2f62..c86b57d47085fd 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -390,36 +390,55 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev) return 0; priv->can.can_stats.bus_error++; - stats->rx_errors++; /* Propagate the error condition to the CAN stack. */ skb = alloc_can_err_skb(ndev, &cf); - if (unlikely(!skb)) - return 0; /* Read the error counter register and check for new errors. */ - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + if (likely(skb)) + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST) - cf->data[2] |= CAN_ERR_PROT_OVERLOAD; + if (errctr & IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST) { + stats->rx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_OVERLOAD; + } - if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST) - cf->data[3] = CAN_ERR_PROT_LOC_ACK; + if (errctr & IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST) { + stats->tx_errors++; + if (likely(skb)) + cf->data[3] = CAN_ERR_PROT_LOC_ACK; + } - if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST) - cf->data[2] |= CAN_ERR_PROT_BIT0; + if (errctr & IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST) { + stats->tx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_BIT0; + } - if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST) - cf->data[2] |= CAN_ERR_PROT_BIT1; + if (errctr & IFI_CANFD_ERROR_CTR_BIT1_ERROR_FIRST) { + stats->tx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_BIT1; + } - if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST) - cf->data[2] |= CAN_ERR_PROT_STUFF; + if (errctr & IFI_CANFD_ERROR_CTR_STUFF_ERROR_FIRST) { + stats->rx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_STUFF; + } - if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST) - cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + if (errctr & IFI_CANFD_ERROR_CTR_CRC_ERROR_FIRST) { + stats->rx_errors++; + if (likely(skb)) + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + } - if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST) - cf->data[2] |= CAN_ERR_PROT_FORM; + if (errctr & IFI_CANFD_ERROR_CTR_FORM_ERROR_FIRST) { + stats->rx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_FORM; + } /* Reset the error counter, ack the IRQ and re-enable the counter. */ writel(IFI_CANFD_ERROR_CTR_ER_RESET, priv->base + IFI_CANFD_ERROR_CTR); @@ -427,6 +446,9 @@ static int ifi_canfd_handle_lec_err(struct net_device *ndev) priv->base + IFI_CANFD_INTERRUPT); writel(IFI_CANFD_ERROR_CTR_ER_ENABLE, priv->base + IFI_CANFD_ERROR_CTR); + if (unlikely(!skb)) + return 0; + netif_receive_skb(skb); return 1; diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 16e9e7d7527d97..97cd8bbf2e32a9 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -695,47 +695,60 @@ static int m_can_handle_lec_err(struct net_device *dev, u32 timestamp = 0; cdev->can.can_stats.bus_error++; - stats->rx_errors++; /* propagate the error condition to the CAN stack */ skb = alloc_can_err_skb(dev, &cf); - if (unlikely(!skb)) - return 0; /* check for 'last error code' which tells us the * type of the last error to occur on the CAN bus */ - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + if (likely(skb)) + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; switch (lec_type) { case LEC_STUFF_ERROR: netdev_dbg(dev, "stuff error\n"); - cf->data[2] |= CAN_ERR_PROT_STUFF; + stats->rx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_STUFF; break; case LEC_FORM_ERROR: netdev_dbg(dev, "form error\n"); - cf->data[2] |= CAN_ERR_PROT_FORM; + stats->rx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_FORM; break; case LEC_ACK_ERROR: netdev_dbg(dev, "ack error\n"); - cf->data[3] = CAN_ERR_PROT_LOC_ACK; + stats->tx_errors++; + if (likely(skb)) + cf->data[3] = CAN_ERR_PROT_LOC_ACK; break; case LEC_BIT1_ERROR: netdev_dbg(dev, "bit1 error\n"); - cf->data[2] |= CAN_ERR_PROT_BIT1; + stats->tx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_BIT1; break; case LEC_BIT0_ERROR: netdev_dbg(dev, "bit0 error\n"); - cf->data[2] |= CAN_ERR_PROT_BIT0; + stats->tx_errors++; + if (likely(skb)) + cf->data[2] |= CAN_ERR_PROT_BIT0; break; case LEC_CRC_ERROR: netdev_dbg(dev, "CRC error\n"); - cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + stats->rx_errors++; + if (likely(skb)) + cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; break; default: break; } + if (unlikely(!skb)) + return 0; + if (cdev->is_peripheral) timestamp = m_can_get_timestamp(cdev); @@ -1207,20 +1220,32 @@ static void m_can_coalescing_update(struct m_can_classdev *cdev, u32 ir) static int m_can_interrupt_handler(struct m_can_classdev *cdev) { struct net_device *dev = cdev->net; - u32 ir; + u32 ir = 0, ir_read; int ret; if (pm_runtime_suspended(cdev->dev)) return IRQ_NONE; - ir = m_can_read(cdev, M_CAN_IR); + /* The m_can controller signals its interrupt status as a level, but + * depending in the integration the CPU may interpret the signal as + * edge-triggered (for example with m_can_pci). For these + * edge-triggered integrations, we must observe that IR is 0 at least + * once to be sure that the next interrupt will generate an edge. + */ + while ((ir_read = m_can_read(cdev, M_CAN_IR)) != 0) { + ir |= ir_read; + + /* ACK all irqs */ + m_can_write(cdev, M_CAN_IR, ir); + + if (!cdev->irq_edge_triggered) + break; + } + m_can_coalescing_update(cdev, ir); if (!ir) return IRQ_NONE; - /* ACK all irqs */ - m_can_write(cdev, M_CAN_IR, ir); - if (cdev->ops->clear_interrupts) cdev->ops->clear_interrupts(cdev); @@ -1682,6 +1707,14 @@ static int m_can_dev_setup(struct m_can_classdev *cdev) return -EINVAL; } + /* Write the INIT bit, in case no hardware reset has happened before + * the probe (for example, it was observed that the Intel Elkhart Lake + * SoCs do not properly reset the CAN controllers on reboot) + */ + err = m_can_cccr_update_bits(cdev, CCCR_INIT, CCCR_INIT); + if (err) + return err; + if (!cdev->is_peripheral) netif_napi_add(dev, &cdev->napi, m_can_poll); @@ -1733,11 +1766,7 @@ static int m_can_dev_setup(struct m_can_classdev *cdev) return -EINVAL; } - /* Forcing standby mode should be redundant, as the chip should be in - * standby after a reset. Write the INIT bit anyways, should the chip - * be configured by previous stage. - */ - return m_can_cccr_update_bits(cdev, CCCR_INIT, CCCR_INIT); + return 0; } static void m_can_stop(struct net_device *dev) diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 92b2bd8628e6b3..ef39e8e527ab67 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -99,6 +99,7 @@ struct m_can_classdev { int pm_clock_support; int pm_wake_source; int is_peripheral; + bool irq_edge_triggered; // Cached M_CAN_IE register content u32 active_interrupts; diff --git a/drivers/net/can/m_can/m_can_pci.c b/drivers/net/can/m_can/m_can_pci.c index d72fe771dfc7aa..9ad7419f88f830 100644 --- a/drivers/net/can/m_can/m_can_pci.c +++ b/drivers/net/can/m_can/m_can_pci.c @@ -127,6 +127,7 @@ static int m_can_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) mcan_class->pm_clock_support = 1; mcan_class->pm_wake_source = 0; mcan_class->can.clock.freq = id->driver_data; + mcan_class->irq_edge_triggered = true; mcan_class->ops = &m_can_pci_ops; pci_set_drvdata(pci, mcan_class); diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index ddb3247948ad2f..4d245857ef1cec 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -416,8 +416,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) int ret = 0; skb = alloc_can_err_skb(dev, &cf); - if (skb == NULL) - return -ENOMEM; txerr = priv->read_reg(priv, SJA1000_TXERR); rxerr = priv->read_reg(priv, SJA1000_RXERR); @@ -425,8 +423,11 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (isrc & IRQ_DOI) { /* data overrun interrupt */ netdev_dbg(dev, "data overrun interrupt\n"); - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + } + stats->rx_over_errors++; stats->rx_errors++; sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */ @@ -452,7 +453,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) else state = CAN_STATE_ERROR_ACTIVE; } - if (state != CAN_STATE_BUS_OFF) { + if (state != CAN_STATE_BUS_OFF && skb) { cf->can_id |= CAN_ERR_CNT; cf->data[6] = txerr; cf->data[7] = rxerr; @@ -460,33 +461,38 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) if (isrc & IRQ_BEI) { /* bus error interrupt */ priv->can.can_stats.bus_error++; - stats->rx_errors++; ecc = priv->read_reg(priv, SJA1000_ECC); + if (skb) { + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - - /* set error type */ - switch (ecc & ECC_MASK) { - case ECC_BIT: - cf->data[2] |= CAN_ERR_PROT_BIT; - break; - case ECC_FORM: - cf->data[2] |= CAN_ERR_PROT_FORM; - break; - case ECC_STUFF: - cf->data[2] |= CAN_ERR_PROT_STUFF; - break; - default: - break; - } + /* set error type */ + switch (ecc & ECC_MASK) { + case ECC_BIT: + cf->data[2] |= CAN_ERR_PROT_BIT; + break; + case ECC_FORM: + cf->data[2] |= CAN_ERR_PROT_FORM; + break; + case ECC_STUFF: + cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + default: + break; + } - /* set error location */ - cf->data[3] = ecc & ECC_SEG; + /* set error location */ + cf->data[3] = ecc & ECC_SEG; + } /* Error occurred during transmission? */ - if ((ecc & ECC_DIR) == 0) - cf->data[2] |= CAN_ERR_PROT_TX; + if ((ecc & ECC_DIR) == 0) { + stats->tx_errors++; + if (skb) + cf->data[2] |= CAN_ERR_PROT_TX; + } else { + stats->rx_errors++; + } } if (isrc & IRQ_EPI) { /* error passive interrupt */ @@ -502,8 +508,10 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) netdev_dbg(dev, "arbitration lost interrupt\n"); alc = priv->read_reg(priv, SJA1000_ALC); priv->can.can_stats.arbitration_lost++; - cf->can_id |= CAN_ERR_LOSTARB; - cf->data[0] = alc & 0x1f; + if (skb) { + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] = alc & 0x1f; + } } if (state != priv->can.state) { @@ -516,6 +524,9 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) can_bus_off(dev); } + if (!skb) + return -ENOMEM; + netif_rx(skb); return ret; diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c index 148d974ebb2107..09ae218315d73d 100644 --- a/drivers/net/can/spi/hi311x.c +++ b/drivers/net/can/spi/hi311x.c @@ -663,27 +663,27 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id) u8 rxerr, txerr; skb = alloc_can_err_skb(net, &cf); - if (!skb) - break; txerr = hi3110_read(spi, HI3110_READ_TEC); rxerr = hi3110_read(spi, HI3110_READ_REC); tx_state = txerr >= rxerr ? new_state : 0; rx_state = txerr <= rxerr ? new_state : 0; can_change_state(net, cf, tx_state, rx_state); - netif_rx(skb); if (new_state == CAN_STATE_BUS_OFF) { + if (skb) + netif_rx(skb); can_bus_off(net); if (priv->can.restart_ms == 0) { priv->force_quit = 1; hi3110_hw_sleep(spi); break; } - } else { + } else if (skb) { cf->can_id |= CAN_ERR_CNT; cf->data[6] = txerr; cf->data[7] = rxerr; + netif_rx(skb); } } @@ -696,27 +696,38 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id) /* Check for protocol errors */ if (eflag & HI3110_ERR_PROTOCOL_MASK) { skb = alloc_can_err_skb(net, &cf); - if (!skb) - break; + if (skb) + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; priv->can.can_stats.bus_error++; - priv->net->stats.rx_errors++; - if (eflag & HI3110_ERR_BITERR) - cf->data[2] |= CAN_ERR_PROT_BIT; - else if (eflag & HI3110_ERR_FRMERR) - cf->data[2] |= CAN_ERR_PROT_FORM; - else if (eflag & HI3110_ERR_STUFERR) - cf->data[2] |= CAN_ERR_PROT_STUFF; - else if (eflag & HI3110_ERR_CRCERR) - cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; - else if (eflag & HI3110_ERR_ACKERR) - cf->data[3] |= CAN_ERR_PROT_LOC_ACK; - - cf->data[6] = hi3110_read(spi, HI3110_READ_TEC); - cf->data[7] = hi3110_read(spi, HI3110_READ_REC); + if (eflag & HI3110_ERR_BITERR) { + priv->net->stats.tx_errors++; + if (skb) + cf->data[2] |= CAN_ERR_PROT_BIT; + } else if (eflag & HI3110_ERR_FRMERR) { + priv->net->stats.rx_errors++; + if (skb) + cf->data[2] |= CAN_ERR_PROT_FORM; + } else if (eflag & HI3110_ERR_STUFERR) { + priv->net->stats.rx_errors++; + if (skb) + cf->data[2] |= CAN_ERR_PROT_STUFF; + } else if (eflag & HI3110_ERR_CRCERR) { + priv->net->stats.rx_errors++; + if (skb) + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; + } else if (eflag & HI3110_ERR_ACKERR) { + priv->net->stats.tx_errors++; + if (skb) + cf->data[3] |= CAN_ERR_PROT_LOC_ACK; + } + netdev_dbg(priv->net, "Bus Error\n"); - netif_rx(skb); + if (skb) { + cf->data[6] = hi3110_read(spi, HI3110_READ_TEC); + cf->data[7] = hi3110_read(spi, HI3110_READ_REC); + netif_rx(skb); + } } } diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c index d3ac865933fdf6..e94321849fd7e6 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c @@ -21,6 +21,11 @@ static inline bool mcp251xfd_tx_fifo_sta_empty(u32 fifo_sta) return fifo_sta & MCP251XFD_REG_FIFOSTA_TFERFFIF; } +static inline bool mcp251xfd_tx_fifo_sta_less_than_half_full(u32 fifo_sta) +{ + return fifo_sta & MCP251XFD_REG_FIFOSTA_TFHRFHIF; +} + static inline int mcp251xfd_tef_tail_get_from_chip(const struct mcp251xfd_priv *priv, u8 *tef_tail) @@ -147,7 +152,29 @@ mcp251xfd_get_tef_len(struct mcp251xfd_priv *priv, u8 *len_p) BUILD_BUG_ON(sizeof(tx_ring->obj_num) != sizeof(len)); len = (chip_tx_tail << shift) - (tail << shift); - *len_p = len >> shift; + len >>= shift; + + /* According to mcp2518fd erratum DS80000789E 6. the FIFOCI + * bits of a FIFOSTA register, here the TX-FIFO tail index + * might be corrupted. + * + * However here it seems the bit indicating that the TX-FIFO + * is empty (MCP251XFD_REG_FIFOSTA_TFERFFIF) is not correct + * while the TX-FIFO tail index is. + * + * We assume the TX-FIFO is empty, i.e. all pending CAN frames + * haven been send, if: + * - Chip's head and tail index are equal (len == 0). + * - The TX-FIFO is less than half full. + * (The TX-FIFO empty case has already been checked at the + * beginning of this function.) + * - No free buffers in the TX ring. + */ + if (len == 0 && mcp251xfd_tx_fifo_sta_less_than_half_full(fifo_sta) && + mcp251xfd_get_tx_free(tx_ring) == 0) + len = tx_ring->obj_num; + + *len_p = len; return 0; } diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index 360158c295d348..4311c1f0eafd8d 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c @@ -579,11 +579,9 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) /* bus error interrupt */ netdev_dbg(dev, "bus error interrupt\n"); priv->can.can_stats.bus_error++; - stats->rx_errors++; + ecc = readl(priv->base + SUN4I_REG_STA_ADDR); if (likely(skb)) { - ecc = readl(priv->base + SUN4I_REG_STA_ADDR); - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; switch (ecc & SUN4I_STA_MASK_ERR) { @@ -601,9 +599,15 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) >> 16; break; } - /* error occurred during transmission? */ - if ((ecc & SUN4I_STA_ERR_DIR) == 0) + } + + /* error occurred during transmission? */ + if ((ecc & SUN4I_STA_ERR_DIR) == 0) { + if (likely(skb)) cf->data[2] |= CAN_ERR_PROT_TX; + stats->tx_errors++; + } else { + stats->rx_errors++; } } if (isrc & SUN4I_INT_ERR_PASSIVE) { @@ -629,10 +633,10 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status) tx_state = txerr >= rxerr ? state : 0; rx_state = txerr <= rxerr ? state : 0; - if (likely(skb)) - can_change_state(dev, cf, tx_state, rx_state); - else - priv->can.state = state; + /* The skb allocation might fail, but can_change_state() + * handles cf == NULL. + */ + can_change_state(dev, cf, tx_state, rx_state); if (state == CAN_STATE_BUS_OFF) can_bus_off(dev); } diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 050c0b49938a42..5355bac4dccbe0 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -335,15 +335,14 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) struct net_device_stats *stats = &dev->netdev->stats; skb = alloc_can_err_skb(dev->netdev, &cf); - if (skb == NULL) - return; if (msg->type == CPC_MSG_TYPE_CAN_STATE) { u8 state = msg->msg.can_state; if (state & SJA1000_SR_BS) { dev->can.state = CAN_STATE_BUS_OFF; - cf->can_id |= CAN_ERR_BUSOFF; + if (skb) + cf->can_id |= CAN_ERR_BUSOFF; dev->can.can_stats.bus_off++; can_bus_off(dev->netdev); @@ -361,44 +360,53 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) /* bus error interrupt */ dev->can.can_stats.bus_error++; - stats->rx_errors++; - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + if (skb) { + cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - switch (ecc & SJA1000_ECC_MASK) { - case SJA1000_ECC_BIT: - cf->data[2] |= CAN_ERR_PROT_BIT; - break; - case SJA1000_ECC_FORM: - cf->data[2] |= CAN_ERR_PROT_FORM; - break; - case SJA1000_ECC_STUFF: - cf->data[2] |= CAN_ERR_PROT_STUFF; - break; - default: - cf->data[3] = ecc & SJA1000_ECC_SEG; - break; + switch (ecc & SJA1000_ECC_MASK) { + case SJA1000_ECC_BIT: + cf->data[2] |= CAN_ERR_PROT_BIT; + break; + case SJA1000_ECC_FORM: + cf->data[2] |= CAN_ERR_PROT_FORM; + break; + case SJA1000_ECC_STUFF: + cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + default: + cf->data[3] = ecc & SJA1000_ECC_SEG; + break; + } } /* Error occurred during transmission? */ - if ((ecc & SJA1000_ECC_DIR) == 0) - cf->data[2] |= CAN_ERR_PROT_TX; + if ((ecc & SJA1000_ECC_DIR) == 0) { + stats->tx_errors++; + if (skb) + cf->data[2] |= CAN_ERR_PROT_TX; + } else { + stats->rx_errors++; + } - if (dev->can.state == CAN_STATE_ERROR_WARNING || - dev->can.state == CAN_STATE_ERROR_PASSIVE) { + if (skb && (dev->can.state == CAN_STATE_ERROR_WARNING || + dev->can.state == CAN_STATE_ERROR_PASSIVE)) { cf->can_id |= CAN_ERR_CRTL; cf->data[1] = (txerr > rxerr) ? CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE; } } else if (msg->type == CPC_MSG_TYPE_OVERRUN) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + } stats->rx_over_errors++; stats->rx_errors++; } - netif_rx(skb); + if (skb) + netif_rx(skb); } /* diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c index bc0c8903fe7794..e0cfa1460b0b83 100644 --- a/drivers/net/can/usb/f81604.c +++ b/drivers/net/can/usb/f81604.c @@ -526,7 +526,6 @@ static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv, netdev_dbg(netdev, "bus error interrupt\n"); priv->can.can_stats.bus_error++; - stats->rx_errors++; if (skb) { cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; @@ -548,10 +547,15 @@ static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv, /* set error location */ cf->data[3] = data->ecc & F81604_SJA1000_ECC_SEG; + } - /* Error occurred during transmission? */ - if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0) + /* Error occurred during transmission? */ + if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0) { + stats->tx_errors++; + if (skb) cf->data[2] |= CAN_ERR_PROT_TX; + } else { + stats->rx_errors++; } set_bit(F81604_CLEAR_ECC, &priv->clear_flags); diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index bc86e9b329fd10..b6f4de375df75d 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -43,9 +43,6 @@ #define USB_XYLANTA_SAINT3_VENDOR_ID 0x16d0 #define USB_XYLANTA_SAINT3_PRODUCT_ID 0x0f30 -#define GS_USB_ENDPOINT_IN 1 -#define GS_USB_ENDPOINT_OUT 2 - /* Timestamp 32 bit timer runs at 1 MHz (1 µs tick). Worker accounts * for timer overflow (will be after ~71 minutes) */ @@ -336,6 +333,9 @@ struct gs_usb { unsigned int hf_size_rx; u8 active_channels; + + unsigned int pipe_in; + unsigned int pipe_out; }; /* 'allocate' a tx context. @@ -687,7 +687,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) resubmit_urb: usb_fill_bulk_urb(urb, parent->udev, - usb_rcvbulkpipe(parent->udev, GS_USB_ENDPOINT_IN), + parent->pipe_in, hf, dev->parent->hf_size_rx, gs_usb_receive_bulk_callback, parent); @@ -819,7 +819,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, } usb_fill_bulk_urb(urb, dev->udev, - usb_sndbulkpipe(dev->udev, GS_USB_ENDPOINT_OUT), + dev->parent->pipe_out, hf, dev->hf_size_tx, gs_usb_xmit_callback, txc); @@ -925,8 +925,7 @@ static int gs_can_open(struct net_device *netdev) /* fill, anchor, and submit rx urb */ usb_fill_bulk_urb(urb, dev->udev, - usb_rcvbulkpipe(dev->udev, - GS_USB_ENDPOINT_IN), + dev->parent->pipe_in, buf, dev->parent->hf_size_rx, gs_usb_receive_bulk_callback, parent); @@ -1413,6 +1412,7 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); + struct usb_endpoint_descriptor *ep_in, *ep_out; struct gs_host_frame *hf; struct gs_usb *parent; struct gs_host_config hconf = { @@ -1422,6 +1422,13 @@ static int gs_usb_probe(struct usb_interface *intf, unsigned int icount, i; int rc; + rc = usb_find_common_endpoints(intf->cur_altsetting, + &ep_in, &ep_out, NULL, NULL); + if (rc) { + dev_err(&intf->dev, "Required endpoints not found\n"); + return rc; + } + /* send host config */ rc = usb_control_msg_send(udev, 0, GS_USB_BREQ_HOST_FORMAT, @@ -1466,6 +1473,10 @@ static int gs_usb_probe(struct usb_interface *intf, usb_set_intfdata(intf, parent); parent->udev = udev; + /* store the detected endpoints */ + parent->pipe_in = usb_rcvbulkpipe(parent->udev, ep_in->bEndpointAddress); + parent->pipe_out = usb_sndbulkpipe(parent->udev, ep_out->bEndpointAddress); + for (i = 0; i < icount; i++) { unsigned int hf_size_rx = 0; diff --git a/drivers/net/can/vxcan.c b/drivers/net/can/vxcan.c index 9e1b7d41005f8d..ca88119410852f 100644 --- a/drivers/net/can/vxcan.c +++ b/drivers/net/can/vxcan.c @@ -172,13 +172,12 @@ static void vxcan_setup(struct net_device *dev) /* forward declaration for rtnl_create_link() */ static struct rtnl_link_ops vxcan_link_ops; -static int vxcan_newlink(struct net *net, struct net_device *dev, +static int vxcan_newlink(struct net *peer_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { struct vxcan_priv *priv; struct net_device *peer; - struct net *peer_net; struct nlattr *peer_tb[IFLA_MAX + 1], **tbp = tb; char ifname[IFNAMSIZ]; @@ -188,14 +187,10 @@ static int vxcan_newlink(struct net *net, struct net_device *dev, /* register peer device */ if (data && data[VXCAN_INFO_PEER]) { - struct nlattr *nla_peer; + struct nlattr *nla_peer = data[VXCAN_INFO_PEER]; - nla_peer = data[VXCAN_INFO_PEER]; ifmp = nla_data(nla_peer); - err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack); - if (err < 0) - return err; - + rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack); tbp = peer_tb; } @@ -207,23 +202,15 @@ static int vxcan_newlink(struct net *net, struct net_device *dev, name_assign_type = NET_NAME_ENUM; } - peer_net = rtnl_link_get_net(net, tbp); - if (IS_ERR(peer_net)) - return PTR_ERR(peer_net); - peer = rtnl_create_link(peer_net, ifname, name_assign_type, &vxcan_link_ops, tbp, extack); - if (IS_ERR(peer)) { - put_net(peer_net); + if (IS_ERR(peer)) return PTR_ERR(peer); - } if (ifmp && dev->ifindex) peer->ifindex = ifmp->ifi_index; err = register_netdevice(peer); - put_net(peer_net); - peer_net = NULL; if (err < 0) { free_netdev(peer); return err; @@ -302,6 +289,7 @@ static struct rtnl_link_ops vxcan_link_ops = { .newlink = vxcan_newlink, .dellink = vxcan_dellink, .policy = vxcan_policy, + .peer_type = VXCAN_INFO_PEER, .maxtype = VXCAN_INFO_MAX, .get_link_net = vxcan_get_link_net, }; diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index c39cb119e760db..285785c942b077 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -989,8 +989,7 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset, if (stringset == ETH_SS_STATS) { for (i = 0; i < mib_size; i++) - strscpy(data + i * ETH_GSTRING_LEN, - mibs[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, mibs[i].name); } else if (stringset == ETH_SS_PHY_STATS) { phydev = b53_get_phy_device(ds, port); if (!phydev) diff --git a/drivers/net/dsa/b53/b53_mmap.c b/drivers/net/dsa/b53/b53_mmap.c index 3a89349dc918d4..c687360a5b7f11 100644 --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c @@ -370,7 +370,7 @@ MODULE_DEVICE_TABLE(of, b53_mmap_of_table); static struct platform_driver b53_mmap_driver = { .probe = b53_mmap_probe, - .remove_new = b53_mmap_remove, + .remove = b53_mmap_remove, .shutdown = b53_mmap_shutdown, .driver = { .name = "b53-switch", diff --git a/drivers/net/dsa/b53/b53_srab.c b/drivers/net/dsa/b53/b53_srab.c index f3f95332ff17ec..b9939bbd2cd517 100644 --- a/drivers/net/dsa/b53/b53_srab.c +++ b/drivers/net/dsa/b53/b53_srab.c @@ -682,7 +682,7 @@ static void b53_srab_shutdown(struct platform_device *pdev) static struct platform_driver b53_srab_driver = { .probe = b53_srab_probe, - .remove_new = b53_srab_remove, + .remove = b53_srab_remove, .shutdown = b53_srab_shutdown, .driver = { .name = "b53-srab-switch", diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 0e663ec0c12a3b..43bde1f583ffdc 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -513,12 +513,12 @@ static void bcm_sf2_crossbar_setup(struct bcm_sf2_priv *priv) u32 reg; int i; - mask = BIT(priv->num_crossbar_int_ports) - 1; + mask = BIT(priv->num_crossbar_ext_bits) - 1; reg = reg_readl(priv, REG_CROSSBAR); switch (priv->type) { case BCM4908_DEVICE_ID: - shift = CROSSBAR_BCM4908_INT_P7 * priv->num_crossbar_int_ports; + shift = CROSSBAR_BCM4908_INT_P7 * priv->num_crossbar_ext_bits; reg &= ~(mask << shift); if (0) /* FIXME */ reg |= CROSSBAR_BCM4908_EXT_SERDES << shift; @@ -536,7 +536,7 @@ static void bcm_sf2_crossbar_setup(struct bcm_sf2_priv *priv) reg = reg_readl(priv, REG_CROSSBAR); for (i = 0; i < priv->num_crossbar_int_ports; i++) { - shift = i * priv->num_crossbar_int_ports; + shift = i * priv->num_crossbar_ext_bits; dev_dbg(dev, "crossbar int port #%d - ext port #%d\n", i, (reg >> shift) & mask); @@ -1183,8 +1183,8 @@ static void bcm_sf2_sw_get_strings(struct dsa_switch *ds, int port, int cnt = b53_get_sset_count(ds, port, stringset); b53_get_strings(ds, port, stringset, data); - bcm_sf2_cfp_get_strings(ds, port, stringset, - data + cnt * ETH_GSTRING_LEN); + data += cnt * ETH_GSTRING_LEN; + bcm_sf2_cfp_get_strings(ds, port, stringset, &data); } static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds, int port, @@ -1260,6 +1260,7 @@ struct bcm_sf2_of_data { unsigned int core_reg_align; unsigned int num_cfp_rules; unsigned int num_crossbar_int_ports; + unsigned int num_crossbar_ext_bits; }; static const u16 bcm_sf2_4908_reg_offsets[] = { @@ -1288,6 +1289,7 @@ static const struct bcm_sf2_of_data bcm_sf2_4908_data = { .reg_offsets = bcm_sf2_4908_reg_offsets, .num_cfp_rules = 256, .num_crossbar_int_ports = 2, + .num_crossbar_ext_bits = 2, }; /* Register offsets for the SWITCH_REG_* block */ @@ -1399,6 +1401,7 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) priv->core_reg_align = data->core_reg_align; priv->num_cfp_rules = data->num_cfp_rules; priv->num_crossbar_int_ports = data->num_crossbar_int_ports; + priv->num_crossbar_ext_bits = data->num_crossbar_ext_bits; priv->rcdev = devm_reset_control_get_optional_exclusive(&pdev->dev, "switch"); @@ -1620,7 +1623,7 @@ static SIMPLE_DEV_PM_OPS(bcm_sf2_pm_ops, static struct platform_driver bcm_sf2_driver = { .probe = bcm_sf2_sw_probe, - .remove_new = bcm_sf2_sw_remove, + .remove = bcm_sf2_sw_remove, .shutdown = bcm_sf2_sw_shutdown, .driver = { .name = "brcm-sf2", diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h index f95f4880b69e17..be9f3b29019f93 100644 --- a/drivers/net/dsa/bcm_sf2.h +++ b/drivers/net/dsa/bcm_sf2.h @@ -75,6 +75,7 @@ struct bcm_sf2_priv { unsigned int core_reg_align; unsigned int num_cfp_rules; unsigned int num_crossbar_int_ports; + unsigned int num_crossbar_ext_bits; /* spinlock protecting access to the indirect registers */ spinlock_t indir_lock; @@ -227,8 +228,8 @@ int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port, int bcm_sf2_cfp_rst(struct bcm_sf2_priv *priv); void bcm_sf2_cfp_exit(struct dsa_switch *ds); int bcm_sf2_cfp_resume(struct dsa_switch *ds); -void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port, - u32 stringset, uint8_t *data); +void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port, u32 stringset, + uint8_t **data); void bcm_sf2_cfp_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); int bcm_sf2_cfp_get_sset_count(struct dsa_switch *ds, int port, int sset); diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index c88ee3dd429978..e22362e6f0cd1d 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -1279,27 +1279,19 @@ static const struct bcm_sf2_cfp_stat { }, }; -void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port, - u32 stringset, uint8_t *data) +void bcm_sf2_cfp_get_strings(struct dsa_switch *ds, int port, u32 stringset, + uint8_t **data) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - unsigned int s = ARRAY_SIZE(bcm_sf2_cfp_stats); - char buf[ETH_GSTRING_LEN]; - unsigned int i, j, iter; + unsigned int i, j; if (stringset != ETH_SS_STATS) return; - for (i = 1; i < priv->num_cfp_rules; i++) { - for (j = 0; j < s; j++) { - snprintf(buf, sizeof(buf), - "CFP%03d_%sCntr", - i, bcm_sf2_cfp_stats[j].name); - iter = (i - 1) * s + j; - strscpy(data + iter * ETH_GSTRING_LEN, - buf, ETH_GSTRING_LEN); - } - } + for (i = 1; i < priv->num_cfp_rules; i++) + for (j = 0; j < ARRAY_SIZE(bcm_sf2_cfp_stats); j++) + ethtool_sprintf(data, "CFP%03d_%sCntr", i, + bcm_sf2_cfp_stats[j].name); } void bcm_sf2_cfp_get_ethtool_stats(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index c70ed67cc18882..adbab544c60ff3 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -121,8 +121,7 @@ static void dsa_loop_get_strings(struct dsa_switch *ds, int port, return; for (i = 0; i < __DSA_LOOP_CNT_MAX; i++) - memcpy(data + i * ETH_GSTRING_LEN, - ps->ports[port].mib[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, ps->ports[port].mib[i].name); } static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c index beda1e9d350fb5..283ec5a6e23c9b 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.c +++ b/drivers/net/dsa/hirschmann/hellcreek.c @@ -294,12 +294,8 @@ static void hellcreek_get_strings(struct dsa_switch *ds, int port, { int i; - for (i = 0; i < ARRAY_SIZE(hellcreek_counter); ++i) { - const struct hellcreek_counter *counter = &hellcreek_counter[i]; - - strscpy(data + i * ETH_GSTRING_LEN, - counter->name, ETH_GSTRING_LEN); - } + for (i = 0; i < ARRAY_SIZE(hellcreek_counter); ++i) + ethtool_puts(&data, hellcreek_counter[i].name); } static int hellcreek_get_sset_count(struct dsa_switch *ds, int port, int sset) @@ -2105,7 +2101,7 @@ MODULE_DEVICE_TABLE(of, hellcreek_of_match); static struct platform_driver hellcreek_driver = { .probe = hellcreek_probe, - .remove_new = hellcreek_remove, + .remove = hellcreek_remove, .shutdown = hellcreek_shutdown, .driver = { .name = "hellcreek", diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index fcd4505f49252f..6eb3140d404449 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -2249,7 +2249,7 @@ MODULE_DEVICE_TABLE(of, gswip_of_match); static struct platform_driver gswip_driver = { .probe = gswip_probe, - .remove_new = gswip_remove, + .remove = gswip_remove, .shutdown = gswip_shutdown, .driver = { .name = "gswip", diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 0ba658a72d8fea..d16817e0476f2f 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1131,6 +1131,10 @@ void ksz9477_config_cpu_port(struct dsa_switch *ds) if (i == dev->cpu_port) continue; ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); + + /* Power down the internal PHY if port is unused. */ + if (dsa_is_unused_port(ds, i) && dev->info->internal_phy[i]) + ksz_pwrite16(dev, i, 0x100, BMCR_PDOWN); } } diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index 7d7560f23a73b5..1c6d7fc1677237 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -2,7 +2,7 @@ /* * Microchip KSZ9477 series register access through I2C * - * Copyright (C) 2018-2019 Microchip Technology Inc. + * Copyright (C) 2018-2024 Microchip Technology Inc. */ #include @@ -16,6 +16,8 @@ KSZ_REGMAP_TABLE(ksz9477, not_used, 16, 0, 0); static int ksz9477_i2c_probe(struct i2c_client *i2c) { + const struct ksz_chip_data *chip; + struct device *ddev = &i2c->dev; struct regmap_config rc; struct ksz_device *dev; int i, ret; @@ -24,6 +26,12 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c) if (!dev) return -ENOMEM; + chip = device_get_match_data(ddev); + if (!chip) + return -EINVAL; + + /* Save chip id to do special initialization when probing. */ + dev->chip_id = chip->chip_id; for (i = 0; i < __KSZ_NUM_REGMAPS; i++) { rc = ksz9477_regmap_config[i]; rc.lock_arg = &dev->regmap_mutex; @@ -111,6 +119,10 @@ static const struct of_device_id ksz9477_dt_ids[] = { .compatible = "microchip,ksz9567", .data = &ksz_switch_chips[KSZ9567] }, + { + .compatible = "microchip,lan9646", + .data = &ksz_switch_chips[LAN9646] + }, {}, }; MODULE_DEVICE_TABLE(of, ksz9477_dt_ids); diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 5290f5ad98f392..8a03baa6aecc72 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -411,6 +411,8 @@ static const struct ksz_dev_ops lan937x_dev_ops = { .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table, .port_setup = lan937x_port_setup, .set_ageing_time = lan937x_set_ageing_time, + .mdio_bus_preinit = lan937x_mdio_bus_preinit, + .create_phy_addr_map = lan937x_create_phy_addr_map, .r_phy = lan937x_r_phy, .w_phy = lan937x_w_phy, .r_mib_cnt = ksz9477_r_mib_cnt, @@ -1098,10 +1100,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { regmap_reg_range(0x1030, 0x1030), regmap_reg_range(0x1100, 0x1115), regmap_reg_range(0x111a, 0x111f), - regmap_reg_range(0x1122, 0x1127), - regmap_reg_range(0x112a, 0x112b), - regmap_reg_range(0x1136, 0x1139), - regmap_reg_range(0x113e, 0x113f), + regmap_reg_range(0x1120, 0x112b), + regmap_reg_range(0x1134, 0x113b), + regmap_reg_range(0x113c, 0x113f), regmap_reg_range(0x1400, 0x1401), regmap_reg_range(0x1403, 0x1403), regmap_reg_range(0x1410, 0x1417), @@ -1128,10 +1129,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { regmap_reg_range(0x2030, 0x2030), regmap_reg_range(0x2100, 0x2115), regmap_reg_range(0x211a, 0x211f), - regmap_reg_range(0x2122, 0x2127), - regmap_reg_range(0x212a, 0x212b), - regmap_reg_range(0x2136, 0x2139), - regmap_reg_range(0x213e, 0x213f), + regmap_reg_range(0x2120, 0x212b), + regmap_reg_range(0x2134, 0x213b), + regmap_reg_range(0x213c, 0x213f), regmap_reg_range(0x2400, 0x2401), regmap_reg_range(0x2403, 0x2403), regmap_reg_range(0x2410, 0x2417), @@ -1158,10 +1158,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { regmap_reg_range(0x3030, 0x3030), regmap_reg_range(0x3100, 0x3115), regmap_reg_range(0x311a, 0x311f), - regmap_reg_range(0x3122, 0x3127), - regmap_reg_range(0x312a, 0x312b), - regmap_reg_range(0x3136, 0x3139), - regmap_reg_range(0x313e, 0x313f), + regmap_reg_range(0x3120, 0x312b), + regmap_reg_range(0x3134, 0x313b), + regmap_reg_range(0x313c, 0x313f), regmap_reg_range(0x3400, 0x3401), regmap_reg_range(0x3403, 0x3403), regmap_reg_range(0x3410, 0x3417), @@ -1188,10 +1187,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { regmap_reg_range(0x4030, 0x4030), regmap_reg_range(0x4100, 0x4115), regmap_reg_range(0x411a, 0x411f), - regmap_reg_range(0x4122, 0x4127), - regmap_reg_range(0x412a, 0x412b), - regmap_reg_range(0x4136, 0x4139), - regmap_reg_range(0x413e, 0x413f), + regmap_reg_range(0x4120, 0x412b), + regmap_reg_range(0x4134, 0x413b), + regmap_reg_range(0x413c, 0x413f), regmap_reg_range(0x4400, 0x4401), regmap_reg_range(0x4403, 0x4403), regmap_reg_range(0x4410, 0x4417), @@ -1218,10 +1216,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { regmap_reg_range(0x5030, 0x5030), regmap_reg_range(0x5100, 0x5115), regmap_reg_range(0x511a, 0x511f), - regmap_reg_range(0x5122, 0x5127), - regmap_reg_range(0x512a, 0x512b), - regmap_reg_range(0x5136, 0x5139), - regmap_reg_range(0x513e, 0x513f), + regmap_reg_range(0x5120, 0x512b), + regmap_reg_range(0x5134, 0x513b), + regmap_reg_range(0x513c, 0x513f), regmap_reg_range(0x5400, 0x5401), regmap_reg_range(0x5403, 0x5403), regmap_reg_range(0x5410, 0x5417), @@ -1248,10 +1245,9 @@ static const struct regmap_range ksz9896_valid_regs[] = { regmap_reg_range(0x6030, 0x6030), regmap_reg_range(0x6100, 0x6115), regmap_reg_range(0x611a, 0x611f), - regmap_reg_range(0x6122, 0x6127), - regmap_reg_range(0x612a, 0x612b), - regmap_reg_range(0x6136, 0x6139), - regmap_reg_range(0x613e, 0x613f), + regmap_reg_range(0x6120, 0x612b), + regmap_reg_range(0x6134, 0x613b), + regmap_reg_range(0x613c, 0x613f), regmap_reg_range(0x6300, 0x6301), regmap_reg_range(0x6400, 0x6401), regmap_reg_range(0x6403, 0x6403), @@ -1762,6 +1758,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_tx_queues = 8, .num_ipms = 8, .tc_cbs_supported = true, + .phy_side_mdio_supported = true, .ops = &lan937x_dev_ops, .phylink_mac_ops = &lan937x_phylink_mac_ops, .mib_names = ksz9477_mib_names, @@ -1790,6 +1787,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_tx_queues = 8, .num_ipms = 8, .tc_cbs_supported = true, + .phy_side_mdio_supported = true, .ops = &lan937x_dev_ops, .phylink_mac_ops = &lan937x_phylink_mac_ops, .mib_names = ksz9477_mib_names, @@ -1818,6 +1816,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_tx_queues = 8, .num_ipms = 8, .tc_cbs_supported = true, + .phy_side_mdio_supported = true, .ops = &lan937x_dev_ops, .phylink_mac_ops = &lan937x_phylink_mac_ops, .mib_names = ksz9477_mib_names, @@ -1850,6 +1849,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_tx_queues = 8, .num_ipms = 8, .tc_cbs_supported = true, + .phy_side_mdio_supported = true, .ops = &lan937x_dev_ops, .phylink_mac_ops = &lan937x_phylink_mac_ops, .mib_names = ksz9477_mib_names, @@ -1882,6 +1882,7 @@ const struct ksz_chip_data ksz_switch_chips[] = { .num_tx_queues = 8, .num_ipms = 8, .tc_cbs_supported = true, + .phy_side_mdio_supported = true, .ops = &lan937x_dev_ops, .phylink_mac_ops = &lan937x_phylink_mac_ops, .mib_names = ksz9477_mib_names, @@ -1901,6 +1902,41 @@ const struct ksz_chip_data ksz_switch_chips[] = { .internal_phy = {true, true, true, true, false, false, true, true}, }, + + [LAN9646] = { + .chip_id = LAN9646_CHIP_ID, + .dev_name = "LAN9646", + .num_vlans = 4096, + .num_alus = 4096, + .num_statics = 16, + .cpu_ports = 0x7F, /* can be configured as cpu port */ + .port_cnt = 7, /* total physical port count */ + .port_nirqs = 4, + .num_tx_queues = 4, + .num_ipms = 8, + .ops = &ksz9477_dev_ops, + .phylink_mac_ops = &ksz9477_phylink_mac_ops, + .phy_errata_9477 = true, + .mib_names = ksz9477_mib_names, + .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), + .reg_mib_cnt = MIB_COUNTER_NUM, + .regs = ksz9477_regs, + .masks = ksz9477_masks, + .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, + .supports_mii = {false, false, false, false, + false, true, true}, + .supports_rmii = {false, false, false, false, + false, true, true}, + .supports_rgmii = {false, false, false, false, + false, true, true}, + .internal_phy = {true, true, true, true, + true, false, false}, + .gbit_capable = {true, true, true, true, true, true, true}, + .wr_table = &ksz9477_register_set, + .rd_table = &ksz9477_register_set, + }, }; EXPORT_SYMBOL_GPL(ksz_switch_chips); @@ -2112,10 +2148,8 @@ static void ksz_get_strings(struct dsa_switch *ds, int port, if (stringset != ETH_SS_STATS) return; - for (i = 0; i < dev->info->mib_cnt; i++) { - memcpy(buf + i * ETH_GSTRING_LEN, - dev->info->mib_names[i].string, ETH_GSTRING_LEN); - } + for (i = 0; i < dev->info->mib_cnt; i++) + ethtool_puts(&buf, dev->info->mib_names[i].string); } /** @@ -2238,16 +2272,100 @@ static int ksz_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, return dev->dev_ops->w_phy(dev, addr, regnum, val); } +/** + * ksz_parent_mdio_read - Read data from a PHY register on the parent MDIO bus. + * @bus: MDIO bus structure. + * @addr: PHY address on the parent MDIO bus. + * @regnum: Register number to read. + * + * This function provides a direct read operation on the parent MDIO bus for + * accessing PHY registers. By bypassing SPI or I2C, it uses the parent MDIO bus + * to retrieve data from the PHY registers at the specified address and register + * number. + * + * Return: Value of the PHY register, or a negative error code on failure. + */ +static int ksz_parent_mdio_read(struct mii_bus *bus, int addr, int regnum) +{ + struct ksz_device *dev = bus->priv; + + return mdiobus_read_nested(dev->parent_mdio_bus, addr, regnum); +} + +/** + * ksz_parent_mdio_write - Write data to a PHY register on the parent MDIO bus. + * @bus: MDIO bus structure. + * @addr: PHY address on the parent MDIO bus. + * @regnum: Register number to write to. + * @val: Value to write to the PHY register. + * + * This function provides a direct write operation on the parent MDIO bus for + * accessing PHY registers. Bypassing SPI or I2C, it uses the parent MDIO bus + * to modify the PHY register values at the specified address. + * + * Return: 0 on success, or a negative error code on failure. + */ +static int ksz_parent_mdio_write(struct mii_bus *bus, int addr, int regnum, + u16 val) +{ + struct ksz_device *dev = bus->priv; + + return mdiobus_write_nested(dev->parent_mdio_bus, addr, regnum, val); +} + +/** + * ksz_phy_addr_to_port - Map a PHY address to the corresponding switch port. + * @dev: Pointer to device structure. + * @addr: PHY address to map to a port. + * + * This function finds the corresponding switch port for a given PHY address by + * iterating over all user ports on the device. It checks if a port's PHY + * address in `phy_addr_map` matches the specified address and if the port + * contains an internal PHY. If a match is found, the index of the port is + * returned. + * + * Return: Port index on success, or -EINVAL if no matching port is found. + */ +static int ksz_phy_addr_to_port(struct ksz_device *dev, int addr) +{ + struct dsa_switch *ds = dev->ds; + struct dsa_port *dp; + + dsa_switch_for_each_user_port(dp, ds) { + if (dev->info->internal_phy[dp->index] && + dev->phy_addr_map[dp->index] == addr) + return dp->index; + } + + return -EINVAL; +} + +/** + * ksz_irq_phy_setup - Configure IRQs for PHYs in the KSZ device. + * @dev: Pointer to the KSZ device structure. + * + * Sets up IRQs for each active PHY connected to the KSZ switch by mapping the + * appropriate IRQs for each PHY and assigning them to the `user_mii_bus` in + * the DSA switch structure. Each IRQ is mapped based on the port's IRQ domain. + * + * Return: 0 on success, or a negative error code on failure. + */ static int ksz_irq_phy_setup(struct ksz_device *dev) { struct dsa_switch *ds = dev->ds; - int phy; + int phy, port; int irq; int ret; - for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) { + for (phy = 0; phy < PHY_MAX_ADDR; phy++) { if (BIT(phy) & ds->phys_mii_mask) { - irq = irq_find_mapping(dev->ports[phy].pirq.domain, + port = ksz_phy_addr_to_port(dev, phy); + if (port < 0) { + ret = port; + goto out; + } + + irq = irq_find_mapping(dev->ports[port].pirq.domain, PORT_SRC_PHY_INT); if (irq < 0) { ret = irq; @@ -2265,49 +2383,183 @@ static int ksz_irq_phy_setup(struct ksz_device *dev) return ret; } +/** + * ksz_irq_phy_free - Release IRQ mappings for PHYs in the KSZ device. + * @dev: Pointer to the KSZ device structure. + * + * Releases any IRQ mappings previously assigned to active PHYs in the KSZ + * switch by disposing of each mapped IRQ in the `user_mii_bus` structure. + */ static void ksz_irq_phy_free(struct ksz_device *dev) { struct dsa_switch *ds = dev->ds; int phy; - for (phy = 0; phy < KSZ_MAX_NUM_PORTS; phy++) + for (phy = 0; phy < PHY_MAX_ADDR; phy++) if (BIT(phy) & ds->phys_mii_mask) irq_dispose_mapping(ds->user_mii_bus->irq[phy]); } +/** + * ksz_parse_dt_phy_config - Parse and validate PHY configuration from DT + * @dev: pointer to the KSZ device structure + * @bus: pointer to the MII bus structure + * @mdio_np: pointer to the MDIO node in the device tree + * + * This function parses and validates PHY configurations for each user port + * defined in the device tree for a KSZ switch device. It verifies that the + * `phy-handle` properties are correctly set and that the internal PHYs match + * expected addresses and parent nodes. Sets up the PHY mask in the MII bus if + * all validations pass. Logs error messages for any mismatches or missing data. + * + * Return: 0 on success, or a negative error code on failure. + */ +static int ksz_parse_dt_phy_config(struct ksz_device *dev, struct mii_bus *bus, + struct device_node *mdio_np) +{ + struct device_node *phy_node, *phy_parent_node; + bool phys_are_valid = true; + struct dsa_port *dp; + u32 phy_addr; + int ret; + + dsa_switch_for_each_user_port(dp, dev->ds) { + if (!dev->info->internal_phy[dp->index]) + continue; + + phy_node = of_parse_phandle(dp->dn, "phy-handle", 0); + if (!phy_node) { + dev_err(dev->dev, "failed to parse phy-handle for port %d.\n", + dp->index); + phys_are_valid = false; + continue; + } + + phy_parent_node = of_get_parent(phy_node); + if (!phy_parent_node) { + dev_err(dev->dev, "failed to get PHY-parent node for port %d\n", + dp->index); + phys_are_valid = false; + } else if (phy_parent_node != mdio_np) { + dev_err(dev->dev, "PHY-parent node mismatch for port %d, expected %pOF, got %pOF\n", + dp->index, mdio_np, phy_parent_node); + phys_are_valid = false; + } else { + ret = of_property_read_u32(phy_node, "reg", &phy_addr); + if (ret < 0) { + dev_err(dev->dev, "failed to read PHY address for port %d. Error %d\n", + dp->index, ret); + phys_are_valid = false; + } else if (phy_addr != dev->phy_addr_map[dp->index]) { + dev_err(dev->dev, "PHY address mismatch for port %d, expected 0x%x, got 0x%x\n", + dp->index, dev->phy_addr_map[dp->index], + phy_addr); + phys_are_valid = false; + } else { + bus->phy_mask |= BIT(phy_addr); + } + } + + of_node_put(phy_node); + of_node_put(phy_parent_node); + } + + if (!phys_are_valid) + return -EINVAL; + + return 0; +} + +/** + * ksz_mdio_register - Register and configure the MDIO bus for the KSZ device. + * @dev: Pointer to the KSZ device structure. + * + * This function sets up and registers an MDIO bus for the KSZ switch device, + * allowing access to its internal PHYs. If the device supports side MDIO, + * the function will configure the external MDIO controller specified by the + * "mdio-parent-bus" device tree property to directly manage internal PHYs. + * Otherwise, SPI or I2C access is set up for PHY access. + * + * Return: 0 on success, or a negative error code on failure. + */ static int ksz_mdio_register(struct ksz_device *dev) { + struct device_node *parent_bus_node; + struct mii_bus *parent_bus = NULL; struct dsa_switch *ds = dev->ds; struct device_node *mdio_np; struct mii_bus *bus; - int ret; + int ret, i; mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio"); if (!mdio_np) return 0; + parent_bus_node = of_parse_phandle(mdio_np, "mdio-parent-bus", 0); + if (parent_bus_node && !dev->info->phy_side_mdio_supported) { + dev_err(dev->dev, "Side MDIO bus is not supported for this HW, ignoring 'mdio-parent-bus' property.\n"); + ret = -EINVAL; + + goto put_mdio_node; + } else if (parent_bus_node) { + parent_bus = of_mdio_find_bus(parent_bus_node); + if (!parent_bus) { + ret = -EPROBE_DEFER; + + goto put_mdio_node; + } + + dev->parent_mdio_bus = parent_bus; + } + bus = devm_mdiobus_alloc(ds->dev); if (!bus) { - of_node_put(mdio_np); - return -ENOMEM; + ret = -ENOMEM; + goto put_mdio_node; + } + + if (dev->dev_ops->mdio_bus_preinit) { + ret = dev->dev_ops->mdio_bus_preinit(dev, !!parent_bus); + if (ret) + goto put_mdio_node; + } + + if (dev->dev_ops->create_phy_addr_map) { + ret = dev->dev_ops->create_phy_addr_map(dev, !!parent_bus); + if (ret) + goto put_mdio_node; + } else { + for (i = 0; i < dev->info->port_cnt; i++) + dev->phy_addr_map[i] = i; } bus->priv = dev; - bus->read = ksz_sw_mdio_read; - bus->write = ksz_sw_mdio_write; - bus->name = "ksz user smi"; - snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); + if (parent_bus) { + bus->read = ksz_parent_mdio_read; + bus->write = ksz_parent_mdio_write; + bus->name = "KSZ side MDIO"; + snprintf(bus->id, MII_BUS_ID_SIZE, "ksz-side-mdio-%d", + ds->index); + } else { + bus->read = ksz_sw_mdio_read; + bus->write = ksz_sw_mdio_write; + bus->name = "ksz user smi"; + snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index); + } + + ret = ksz_parse_dt_phy_config(dev, bus, mdio_np); + if (ret) + goto put_mdio_node; + + ds->phys_mii_mask = bus->phy_mask; bus->parent = ds->dev; - bus->phy_mask = ~ds->phys_mii_mask; ds->user_mii_bus = bus; if (dev->irq > 0) { ret = ksz_irq_phy_setup(dev); - if (ret) { - of_node_put(mdio_np); - return ret; - } + if (ret) + goto put_mdio_node; } ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np); @@ -2318,7 +2570,9 @@ static int ksz_mdio_register(struct ksz_device *dev) ksz_irq_phy_free(dev); } +put_mdio_node: of_node_put(mdio_np); + of_node_put(parent_bus_node); return ret; } @@ -2745,6 +2999,7 @@ static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port) case KSZ9896_CHIP_ID: /* KSZ9896C Errata DS80000757A Module 3 */ case KSZ9897_CHIP_ID: + case LAN9646_CHIP_ID: /* KSZ9897R Errata DS80000758C Module 4 */ /* Energy Efficient Ethernet (EEE) feature select must be manually disabled * The EEE feature is enabled by default, but it is not fully @@ -3005,6 +3260,7 @@ static void ksz_port_teardown(struct dsa_switch *ds, int port) case KSZ9893_CHIP_ID: case KSZ9896_CHIP_ID: case KSZ9897_CHIP_ID: + case LAN9646_CHIP_ID: if (dsa_is_user_port(ds, port)) ksz9477_port_acl_free(dev, port); } @@ -3061,7 +3317,8 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, dev->chip_id == KSZ9477_CHIP_ID || dev->chip_id == KSZ9896_CHIP_ID || dev->chip_id == KSZ9897_CHIP_ID || - dev->chip_id == KSZ9567_CHIP_ID) + dev->chip_id == KSZ9567_CHIP_ID || + dev->chip_id == LAN9646_CHIP_ID) proto = DSA_TAG_PROTO_KSZ9477; if (is_lan937x(dev)) @@ -3180,6 +3437,7 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port) case LAN9372_CHIP_ID: case LAN9373_CHIP_ID: case LAN9374_CHIP_ID: + case LAN9646_CHIP_ID: return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; } @@ -3202,6 +3460,7 @@ static int ksz_validate_eee(struct dsa_switch *ds, int port) case KSZ9893_CHIP_ID: case KSZ9896_CHIP_ID: case KSZ9897_CHIP_ID: + case LAN9646_CHIP_ID: return 0; } @@ -3554,7 +3813,10 @@ static int ksz_switch_detect(struct ksz_device *dev) case LAN9372_CHIP_ID: case LAN9373_CHIP_ID: case LAN9374_CHIP_ID: - dev->chip_id = id32; + + /* LAN9646 does not have its own chip id. */ + if (dev->chip_id != LAN9646_CHIP_ID) + dev->chip_id = id32; break; case KSZ9893_CHIP_ID: ret = ksz_read8(dev, REG_CHIP_ID4, @@ -3593,6 +3855,7 @@ static int ksz_cls_flower_add(struct dsa_switch *ds, int port, case KSZ9893_CHIP_ID: case KSZ9896_CHIP_ID: case KSZ9897_CHIP_ID: + case LAN9646_CHIP_ID: return ksz9477_cls_flower_add(ds, port, cls, ingress); } @@ -3613,6 +3876,7 @@ static int ksz_cls_flower_del(struct dsa_switch *ds, int port, case KSZ9893_CHIP_ID: case KSZ9896_CHIP_ID: case KSZ9897_CHIP_ID: + case LAN9646_CHIP_ID: return ksz9477_cls_flower_del(ds, port, cls, ingress); } @@ -4700,6 +4964,7 @@ static int ksz_parse_drive_strength(struct ksz_device *dev) case KSZ9893_CHIP_ID: case KSZ9896_CHIP_ID: case KSZ9897_CHIP_ID: + case LAN9646_CHIP_ID: return ksz9477_drive_strength_write(dev, of_props, ARRAY_SIZE(of_props)); default: diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index bec846e20682ff..b3bb75ca0796d2 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -65,6 +65,12 @@ struct ksz_chip_data { u8 num_tx_queues; u8 num_ipms; /* number of Internal Priority Maps */ bool tc_cbs_supported; + + /** + * @phy_side_mdio_supported: Indicates if the chip supports an additional + * side MDIO channel for accessing integrated PHYs. + */ + bool phy_side_mdio_supported; const struct ksz_dev_ops *ops; const struct phylink_mac_ops *phylink_mac_ops; bool phy_errata_9477; @@ -191,6 +197,22 @@ struct ksz_device { struct ksz_switch_macaddr *switch_macaddr; struct net_device *hsr_dev; /* HSR */ u8 hsr_ports; + + /** + * @phy_addr_map: Array mapping switch ports to their corresponding PHY + * addresses. + */ + u8 phy_addr_map[KSZ_MAX_NUM_PORTS]; + + /** + * @parent_mdio_bus: Pointer to the external MDIO bus controller. + * + * This points to an external MDIO bus controller that is used to access + * the PHYs integrated within the switch. Unlike an integrated MDIO + * bus, this external controller provides a direct path for managing + * the switch’s internal PHYs, bypassing the main SPI interface. + */ + struct mii_bus *parent_mdio_bus; }; /* List of supported models */ @@ -214,6 +236,7 @@ enum ksz_model { LAN9372, LAN9373, LAN9374, + LAN9646, }; enum ksz_regs { @@ -326,6 +349,43 @@ struct ksz_dev_ops { void (*port_cleanup)(struct ksz_device *dev, int port); void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port); int (*set_ageing_time)(struct ksz_device *dev, unsigned int msecs); + + /** + * @mdio_bus_preinit: Function pointer to pre-initialize the MDIO bus + * for accessing PHYs. + * @dev: Pointer to device structure. + * @side_mdio: Boolean indicating if the PHYs are accessed over a side + * MDIO bus. + * + * This function pointer is used to configure the MDIO bus for PHY + * access before initiating regular PHY operations. It enables either + * SPI/I2C or side MDIO access modes by unlocking necessary registers + * and setting up access permissions for the selected mode. + * + * Return: + * - 0 on success. + * - Negative error code on failure. + */ + int (*mdio_bus_preinit)(struct ksz_device *dev, bool side_mdio); + + /** + * @create_phy_addr_map: Function pointer to create a port-to-PHY + * address map. + * @dev: Pointer to device structure. + * @side_mdio: Boolean indicating if the PHYs are accessed over a side + * MDIO bus. + * + * This function pointer is responsible for mapping switch ports to PHY + * addresses according to the configured access mode (SPI or side MDIO) + * and the device’s strap configuration. The mapping setup may vary + * depending on the chip variant and configuration. Ensures the correct + * address mapping for PHY communication. + * + * Return: + * - 0 on success. + * - Negative error code on failure (e.g., invalid configuration). + */ + int (*create_phy_addr_map)(struct ksz_device *dev, bool side_mdio); int (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val); int (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val); void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr, diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 050f17c43ef60d..22fb9ef4645c18 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -1106,7 +1106,7 @@ static int ksz_ptp_msg_irq_setup(struct ksz_port *port, u8 n) ptpmsg_irq->port = port; ptpmsg_irq->ts_reg = ops->get_port_addr(port->num, ts_reg[n]); - snprintf(ptpmsg_irq->name, sizeof(ptpmsg_irq->name), name[n]); + strscpy(ptpmsg_irq->name, name[n]); ptpmsg_irq->num = irq_find_mapping(port->ptpirq.domain, n); if (ptpmsg_irq->num < 0) diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 1c6652f2b9fee0..108a958dc356f1 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -54,6 +54,8 @@ static int ksz_spi_probe(struct spi_device *spi) if (!chip) return -EINVAL; + /* Save chip id to do special initialization when probing. */ + dev->chip_id = chip->chip_id; if (chip->chip_id == KSZ88X3_CHIP_ID) regmap_config = ksz8863_regmap_config; else if (chip->chip_id == KSZ8795_CHIP_ID || @@ -203,6 +205,10 @@ static const struct of_device_id ksz_dt_ids[] = { .compatible = "microchip,lan9374", .data = &ksz_switch_chips[LAN9374] }, + { + .compatible = "microchip,lan9646", + .data = &ksz_switch_chips[LAN9646] + }, {}, }; MODULE_DEVICE_TABLE(of, ksz_dt_ids); @@ -228,6 +234,7 @@ static const struct spi_device_id ksz_spi_ids[] = { { "lan9372" }, { "lan9373" }, { "lan9374" }, + { "lan9646" }, { }, }; MODULE_DEVICE_TABLE(spi, ksz_spi_ids); diff --git a/drivers/net/dsa/microchip/lan937x.h b/drivers/net/dsa/microchip/lan937x.h index 3388d91dbc44e6..df13ebbd356f9f 100644 --- a/drivers/net/dsa/microchip/lan937x.h +++ b/drivers/net/dsa/microchip/lan937x.h @@ -13,6 +13,8 @@ void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port); void lan937x_config_cpu_port(struct dsa_switch *ds); int lan937x_switch_init(struct ksz_device *dev); void lan937x_switch_exit(struct ksz_device *dev); +int lan937x_mdio_bus_preinit(struct ksz_device *dev, bool side_mdio); +int lan937x_create_phy_addr_map(struct ksz_device *dev, bool side_mdio); int lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data); int lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val); int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu); diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 824d9309a3d35e..b7652efd632ead 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -18,6 +18,87 @@ #include "ksz9477.h" #include "lan937x.h" +/* marker for ports without built-in PHY */ +#define LAN937X_NO_PHY U8_MAX + +/* + * lan9370_phy_addr - Mapping of LAN9370 switch ports to PHY addresses. + * + * Each entry corresponds to a specific port on the LAN9370 switch, + * where ports 1-4 are connected to integrated 100BASE-T1 PHYs, and + * Port 5 is connected to an RGMII interface without a PHY. The values + * are based on the documentation (DS00003108E, section 3.3). + */ +static const u8 lan9370_phy_addr[] = { + [0] = 2, /* Port 1, T1 AFE0 */ + [1] = 3, /* Port 2, T1 AFE1 */ + [2] = 5, /* Port 3, T1 AFE3 */ + [3] = 6, /* Port 4, T1 AFE4 */ + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ +}; + +/* + * lan9371_phy_addr - Mapping of LAN9371 switch ports to PHY addresses. + * + * The values are based on the documentation (DS00003109E, section 3.3). + */ +static const u8 lan9371_phy_addr[] = { + [0] = 2, /* Port 1, T1 AFE0 */ + [1] = 3, /* Port 2, T1 AFE1 */ + [2] = 5, /* Port 3, T1 AFE3 */ + [3] = 8, /* Port 4, TX PHY */ + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ + [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */ +}; + +/* + * lan9372_phy_addr - Mapping of LAN9372 switch ports to PHY addresses. + * + * The values are based on the documentation (DS00003110F, section 3.3). + */ +static const u8 lan9372_phy_addr[] = { + [0] = 2, /* Port 1, T1 AFE0 */ + [1] = 3, /* Port 2, T1 AFE1 */ + [2] = 5, /* Port 3, T1 AFE3 */ + [3] = 8, /* Port 4, TX PHY */ + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ + [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */ + [6] = 6, /* Port 7, T1 AFE4 */ + [7] = 4, /* Port 8, T1 AFE2 */ +}; + +/* + * lan9373_phy_addr - Mapping of LAN9373 switch ports to PHY addresses. + * + * The values are based on the documentation (DS00003110F, section 3.3). + */ +static const u8 lan9373_phy_addr[] = { + [0] = 2, /* Port 1, T1 AFE0 */ + [1] = 3, /* Port 2, T1 AFE1 */ + [2] = 5, /* Port 3, T1 AFE3 */ + [3] = LAN937X_NO_PHY, /* Port 4, SGMII */ + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ + [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */ + [6] = 6, /* Port 7, T1 AFE4 */ + [7] = 4, /* Port 8, T1 AFE2 */ +}; + +/* + * lan9374_phy_addr - Mapping of LAN9374 switch ports to PHY addresses. + * + * The values are based on the documentation (DS00003110F, section 3.3). + */ +static const u8 lan9374_phy_addr[] = { + [0] = 2, /* Port 1, T1 AFE0 */ + [1] = 3, /* Port 2, T1 AFE1 */ + [2] = 5, /* Port 3, T1 AFE3 */ + [3] = 7, /* Port 4, T1 AFE5 */ + [4] = LAN937X_NO_PHY, /* Port 5, RGMII 2 */ + [5] = LAN937X_NO_PHY, /* Port 6, RGMII 1 */ + [6] = 6, /* Port 7, T1 AFE4 */ + [7] = 4, /* Port 8, T1 AFE2 */ +}; + static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { return regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0); @@ -30,24 +111,144 @@ static int lan937x_port_cfg(struct ksz_device *dev, int port, int offset, bits, set ? bits : 0); } -static int lan937x_enable_spi_indirect_access(struct ksz_device *dev) +/** + * lan937x_create_phy_addr_map - Create port-to-PHY address map for MDIO bus. + * @dev: Pointer to device structure. + * @side_mdio: Boolean indicating if the PHYs are accessed over a side MDIO bus. + * + * This function sets up the PHY address mapping for the LAN937x switches, + * which support two access modes for internal PHYs: + * 1. **SPI Access**: A straightforward one-to-one port-to-PHY address + * mapping is applied. + * 2. **MDIO Access**: The PHY address mapping varies based on chip variant + * and strap configuration. An offset is calculated based on strap settings + * to ensure correct PHY addresses are assigned. The offset calculation logic + * is based on Microchip's Article Number 000015828, available at: + * https://microchip.my.site.com/s/article/LAN9374-Virtual-PHY-PHY-Address-Mapping + * + * The function first checks if side MDIO access is disabled, in which case a + * simple direct mapping (port number = PHY address) is applied. If side MDIO + * access is enabled, it reads the strap configuration to determine the correct + * offset for PHY addresses. + * + * The appropriate mapping table is selected based on the chip ID, and the + * `phy_addr_map` is populated with the correct addresses for each port. Any + * port with no PHY is assigned a `LAN937X_NO_PHY` marker. + * + * Return: 0 on success, error code on failure. + */ +int lan937x_create_phy_addr_map(struct ksz_device *dev, bool side_mdio) +{ + static const u8 *phy_addr_map; + u32 strap_val; + u8 offset = 0; + size_t size; + int ret, i; + + if (!side_mdio) { + /* simple direct mapping */ + for (i = 0; i < dev->info->port_cnt; i++) + dev->phy_addr_map[i] = i; + + return 0; + } + + ret = ksz_read32(dev, REG_SW_CFG_STRAP_VAL, &strap_val); + if (ret < 0) + return ret; + + if (!(strap_val & SW_CASCADE_ID_CFG) && !(strap_val & SW_VPHY_ADD_CFG)) + offset = 0; + else if (!(strap_val & SW_CASCADE_ID_CFG) && (strap_val & SW_VPHY_ADD_CFG)) + offset = 7; + else if ((strap_val & SW_CASCADE_ID_CFG) && !(strap_val & SW_VPHY_ADD_CFG)) + offset = 15; + else + offset = 22; + + switch (dev->info->chip_id) { + case LAN9370_CHIP_ID: + phy_addr_map = lan9370_phy_addr; + size = ARRAY_SIZE(lan9370_phy_addr); + break; + case LAN9371_CHIP_ID: + phy_addr_map = lan9371_phy_addr; + size = ARRAY_SIZE(lan9371_phy_addr); + break; + case LAN9372_CHIP_ID: + phy_addr_map = lan9372_phy_addr; + size = ARRAY_SIZE(lan9372_phy_addr); + break; + case LAN9373_CHIP_ID: + phy_addr_map = lan9373_phy_addr; + size = ARRAY_SIZE(lan9373_phy_addr); + break; + case LAN9374_CHIP_ID: + phy_addr_map = lan9374_phy_addr; + size = ARRAY_SIZE(lan9374_phy_addr); + break; + default: + return -EINVAL; + } + + if (size < dev->info->port_cnt) + return -EINVAL; + + for (i = 0; i < dev->info->port_cnt; i++) { + if (phy_addr_map[i] == LAN937X_NO_PHY) + dev->phy_addr_map[i] = phy_addr_map[i]; + else + dev->phy_addr_map[i] = phy_addr_map[i] + offset; + } + + return 0; +} + +/** + * lan937x_mdio_bus_preinit - Pre-initialize MDIO bus for accessing PHYs. + * @dev: Pointer to device structure. + * @side_mdio: Boolean indicating if the PHYs are accessed over a side MDIO bus. + * + * This function configures the LAN937x switch for PHY access either through + * SPI or the side MDIO bus, unlocking the necessary registers for each access + * mode. + * + * Operation Modes: + * 1. **SPI Access**: Enables SPI indirect access to address clock domain + * crossing issues when SPI is used for PHY access. + * 2. **MDIO Access**: Grants access to internal PHYs over the side MDIO bus, + * required when using the MDIO bus for PHY management. + * + * Return: 0 on success, error code on failure. + */ +int lan937x_mdio_bus_preinit(struct ksz_device *dev, bool side_mdio) { u16 data16; int ret; - /* Enable Phy access through SPI */ + /* Unlock access to the PHYs, needed for SPI and side MDIO access */ ret = lan937x_cfg(dev, REG_GLOBAL_CTRL_0, SW_PHY_REG_BLOCK, false); if (ret < 0) - return ret; + goto print_error; - ret = ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, &data16); - if (ret < 0) - return ret; + if (side_mdio) + /* Allow access to internal PHYs over MDIO bus */ + data16 = VPHY_MDIO_INTERNAL_ENABLE; + else + /* Enable SPI indirect access to address clock domain crossing + * issue + */ + data16 = VPHY_SPI_INDIRECT_ENABLE; - /* Allow SPI access */ - data16 |= VPHY_SPI_INDIRECT_ENABLE; + ret = ksz_rmw16(dev, REG_VPHY_SPECIAL_CTRL__2, + VPHY_SPI_INDIRECT_ENABLE | VPHY_MDIO_INTERNAL_ENABLE, + data16); + +print_error: + if (ret < 0) + dev_err(dev->dev, "failed to preinit the MDIO bus\n"); - return ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, data16); + return ret; } static int lan937x_vphy_ind_addr_wr(struct ksz_device *dev, int addr, int reg) @@ -363,13 +564,6 @@ int lan937x_setup(struct dsa_switch *ds) struct ksz_device *dev = ds->priv; int ret; - /* enable Indirect Access from SPI to the VPHY registers */ - ret = lan937x_enable_spi_indirect_access(dev); - if (ret < 0) { - dev_err(dev->dev, "failed to enable spi indirect access"); - return ret; - } - /* The VLAN aware is a global setting. Mixed vlan * filterings are not supported. */ diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h index 2f22a9d01de36b..4ec93e421da451 100644 --- a/drivers/net/dsa/microchip/lan937x_reg.h +++ b/drivers/net/dsa/microchip/lan937x_reg.h @@ -37,6 +37,10 @@ #define SW_CLK125_ENB BIT(1) #define SW_CLK25_ENB BIT(0) +#define REG_SW_CFG_STRAP_VAL 0x0200 +#define SW_CASCADE_ID_CFG BIT(15) +#define SW_VPHY_ADD_CFG BIT(0) + /* 2 - PHY Control */ #define REG_SW_CFG_STRAP_OVR 0x0214 #define SW_VPHY_DISABLE BIT(31) diff --git a/drivers/net/dsa/mt7530-mmio.c b/drivers/net/dsa/mt7530-mmio.c index 10dc49961f15d7..5f2db4317dd3ba 100644 --- a/drivers/net/dsa/mt7530-mmio.c +++ b/drivers/net/dsa/mt7530-mmio.c @@ -86,7 +86,7 @@ static void mt7988_shutdown(struct platform_device *pdev) static struct platform_driver mt7988_platform_driver = { .probe = mt7988_probe, - .remove_new = mt7988_remove, + .remove = mt7988_remove, .shutdown = mt7988_shutdown, .driver = { .name = "mt7530-mmio", diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index d84ee1b419a614..086b8b3d5b40f7 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "mt7530.h" @@ -3146,6 +3147,53 @@ mt753x_conduit_state_change(struct dsa_switch *ds, mt7530_rmw(priv, MT753X_MFC, MT7530_CPU_EN | MT7530_CPU_PORT_MASK, val); } +static int mt753x_tc_setup_qdisc_tbf(struct dsa_switch *ds, int port, + struct tc_tbf_qopt_offload *qopt) +{ + struct tc_tbf_qopt_offload_replace_params *p = &qopt->replace_params; + struct mt7530_priv *priv = ds->priv; + u32 rate = 0; + + switch (qopt->command) { + case TC_TBF_REPLACE: + rate = div_u64(p->rate.rate_bytes_ps, 1000) << 3; /* kbps */ + fallthrough; + case TC_TBF_DESTROY: { + u32 val, tick; + + mt7530_rmw(priv, MT753X_GERLCR, EGR_BC_MASK, + EGR_BC_CRC_IPG_PREAMBLE); + + /* if rate is greater than 10Mbps tick is 1/32 ms, + * 1ms otherwise + */ + tick = rate > 10000 ? 2 : 7; + val = FIELD_PREP(ERLCR_CIR_MASK, (rate >> 5)) | + FIELD_PREP(ERLCR_EN_MASK, !!rate) | + FIELD_PREP(ERLCR_EXP_MASK, tick) | + ERLCR_TBF_MODE_MASK | + FIELD_PREP(ERLCR_MANT_MASK, 0xf); + mt7530_write(priv, MT753X_ERLCR_P(port), val); + break; + } + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int mt753x_setup_tc(struct dsa_switch *ds, int port, + enum tc_setup_type type, void *type_data) +{ + switch (type) { + case TC_SETUP_QDISC_TBF: + return mt753x_tc_setup_qdisc_tbf(ds, port, type_data); + default: + return -EOPNOTSUPP; + } +} + static int mt7988_setup(struct dsa_switch *ds) { struct mt7530_priv *priv = ds->priv; @@ -3193,6 +3241,7 @@ const struct dsa_switch_ops mt7530_switch_ops = { .get_mac_eee = mt753x_get_mac_eee, .set_mac_eee = mt753x_set_mac_eee, .conduit_state_change = mt753x_conduit_state_change, + .port_setup_tc = mt753x_setup_tc, }; EXPORT_SYMBOL_GPL(mt7530_switch_ops); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 6ad33a9f6b1dff..448200689f492d 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -248,6 +248,18 @@ enum mt7530_vlan_egress_attr { #define AGE_UNIT_MAX 0xfff #define AGE_UNIT(x) (AGE_UNIT_MASK & (x)) +#define MT753X_ERLCR_P(x) (0x1040 + ((x) * 0x100)) +#define ERLCR_CIR_MASK GENMASK(31, 16) +#define ERLCR_EN_MASK BIT(15) +#define ERLCR_EXP_MASK GENMASK(11, 8) +#define ERLCR_TBF_MODE_MASK BIT(7) +#define ERLCR_MANT_MASK GENMASK(6, 0) + +#define MT753X_GERLCR 0x10e0 +#define EGR_BC_MASK GENMASK(7, 0) +#define EGR_BC_CRC 0x4 /* crc */ +#define EGR_BC_CRC_IPG_PREAMBLE 0x18 /* crc + ipg + preamble */ + /* Register for port STP state control */ #define MT7530_SSP_P(x) (0x2000 + ((x) * 0x100)) #define FID_PST(fid, state) (((state) & 0x3) << ((fid) * 2)) diff --git a/drivers/net/dsa/mv88e6xxx/Kconfig b/drivers/net/dsa/mv88e6xxx/Kconfig index e3181d5471dfe3..64ae3882d17c72 100644 --- a/drivers/net/dsa/mv88e6xxx/Kconfig +++ b/drivers/net/dsa/mv88e6xxx/Kconfig @@ -17,3 +17,13 @@ config NET_DSA_MV88E6XXX_PTP help Say Y to enable PTP hardware timestamping on Marvell 88E6xxx switch chips that support it. + +config NET_DSA_MV88E6XXX_LEDS + bool "LED support for Marvell 88E6xxx" + default y + depends on NET_DSA_MV88E6XXX + depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_MV88E6XXX + depends on LEDS_TRIGGERS + help + This enabled support for controlling the LEDs attached to the + Marvell 88E6xxx switch chips. diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile index a9a9651187db7e..dd961081d6313d 100644 --- a/drivers/net/dsa/mv88e6xxx/Makefile +++ b/drivers/net/dsa/mv88e6xxx/Makefile @@ -9,6 +9,7 @@ mv88e6xxx-objs += global2.o mv88e6xxx-objs += global2_avb.o mv88e6xxx-objs += global2_scratch.o mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_PTP) += hwtstamp.o +mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_LEDS) += leds.o mv88e6xxx-objs += pcs-6185.o mv88e6xxx-objs += pcs-6352.o mv88e6xxx-objs += pcs-639x.o diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 284270a4ade1c1..3a792f79270d99 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -867,7 +868,7 @@ mv88e6xxx_mac_select_pcs(struct phylink_config *config, { struct dsa_port *dp = dsa_phylink_to_port(config); struct mv88e6xxx_chip *chip = dp->ds->priv; - struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP); + struct phylink_pcs *pcs = NULL; if (chip->info->ops->pcs_ops) pcs = chip->info->ops->pcs_ops->pcs_select(chip, dp->index, @@ -1152,42 +1153,37 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip, return value; } -static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, - uint8_t *data, int types) +static void mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip, + uint8_t **data, int types) { const struct mv88e6xxx_hw_stat *stat; - int i, j; + int i; - for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { + for (i = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) { stat = &mv88e6xxx_hw_stats[i]; - if (stat->type & types) { - memcpy(data + j * ETH_GSTRING_LEN, stat->string, - ETH_GSTRING_LEN); - j++; - } + if (stat->type & types) + ethtool_puts(data, stat->string); } - - return j; } -static int mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, - uint8_t *data) +static void mv88e6095_stats_get_strings(struct mv88e6xxx_chip *chip, + uint8_t **data) { - return mv88e6xxx_stats_get_strings(chip, data, - STATS_TYPE_BANK0 | STATS_TYPE_PORT); + mv88e6xxx_stats_get_strings(chip, data, + STATS_TYPE_BANK0 | STATS_TYPE_PORT); } -static int mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, - uint8_t *data) +static void mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip, + uint8_t **data) { - return mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); + mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0); } -static int mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, - uint8_t *data) +static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip, + uint8_t **data) { - return mv88e6xxx_stats_get_strings(chip, data, - STATS_TYPE_BANK0 | STATS_TYPE_BANK1); + mv88e6xxx_stats_get_strings(chip, data, + STATS_TYPE_BANK0 | STATS_TYPE_BANK1); } static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { @@ -1198,21 +1194,18 @@ static const uint8_t *mv88e6xxx_atu_vtu_stats_strings[] = { "vtu_miss_violation", }; -static void mv88e6xxx_atu_vtu_get_strings(uint8_t *data) +static void mv88e6xxx_atu_vtu_get_strings(uint8_t **data) { unsigned int i; for (i = 0; i < ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings); i++) - strscpy(data + i * ETH_GSTRING_LEN, - mv88e6xxx_atu_vtu_stats_strings[i], - ETH_GSTRING_LEN); + ethtool_puts(data, mv88e6xxx_atu_vtu_stats_strings[i]); } static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) { struct mv88e6xxx_chip *chip = ds->priv; - int count = 0; if (stringset != ETH_SS_STATS) return; @@ -1220,15 +1213,12 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port, mv88e6xxx_reg_lock(chip); if (chip->info->ops->stats_get_strings) - count = chip->info->ops->stats_get_strings(chip, data); + chip->info->ops->stats_get_strings(chip, &data); - if (chip->info->ops->serdes_get_strings) { - data += count * ETH_GSTRING_LEN; - count = chip->info->ops->serdes_get_strings(chip, port, data); - } + if (chip->info->ops->serdes_get_strings) + chip->info->ops->serdes_get_strings(chip, port, &data); - data += count * ETH_GSTRING_LEN; - mv88e6xxx_atu_vtu_get_strings(data); + mv88e6xxx_atu_vtu_get_strings(&data); mv88e6xxx_reg_unlock(chip); } @@ -1929,36 +1919,9 @@ static int mv88e6xxx_vtu_loadpurge(struct mv88e6xxx_chip *chip, return chip->info->ops->vtu_loadpurge(chip, entry); } -static int mv88e6xxx_fid_map_vlan(struct mv88e6xxx_chip *chip, - const struct mv88e6xxx_vtu_entry *entry, - void *_fid_bitmap) -{ - unsigned long *fid_bitmap = _fid_bitmap; - - set_bit(entry->fid, fid_bitmap); - return 0; -} - -int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *fid_bitmap) -{ - bitmap_zero(fid_bitmap, MV88E6XXX_N_FID); - - /* Every FID has an associated VID, so walking the VTU - * will discover the full set of FIDs in use. - */ - return mv88e6xxx_vtu_walk(chip, mv88e6xxx_fid_map_vlan, fid_bitmap); -} - static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) { - DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); - int err; - - err = mv88e6xxx_fid_map(chip, fid_bitmap); - if (err) - return err; - - *fid = find_first_zero_bit(fid_bitmap, MV88E6XXX_N_FID); + *fid = find_first_zero_bit(chip->fid_bitmap, MV88E6XXX_N_FID); if (unlikely(*fid >= mv88e6xxx_num_databases(chip))) return -ENOSPC; @@ -2665,6 +2628,9 @@ static int mv88e6xxx_port_vlan_join(struct mv88e6xxx_chip *chip, int port, port, vid); } + /* Record FID used in SW FID map */ + bitmap_set(chip->fid_bitmap, vlan.fid, 1); + return 0; } @@ -2770,6 +2736,9 @@ static int mv88e6xxx_port_vlan_leave(struct mv88e6xxx_chip *chip, err = mv88e6xxx_mst_put(chip, vlan.sid); if (err) return err; + + /* Record FID freed in SW FID map */ + bitmap_clear(chip->fid_bitmap, vlan.fid, 1); } return mv88e6xxx_g1_atu_remove(chip, vlan.fid, port, false); @@ -3371,14 +3340,44 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) { struct device_node *phy_handle = NULL; + struct fwnode_handle *ports_fwnode; + struct fwnode_handle *port_fwnode; struct dsa_switch *ds = chip->ds; + struct mv88e6xxx_port *p; struct dsa_port *dp; int tx_amp; int err; u16 reg; + u32 val; + + p = &chip->ports[port]; + p->chip = chip; + p->port = port; + + /* Look up corresponding fwnode if any */ + ports_fwnode = device_get_named_child_node(chip->dev, "ethernet-ports"); + if (!ports_fwnode) + ports_fwnode = device_get_named_child_node(chip->dev, "ports"); + if (ports_fwnode) { + fwnode_for_each_child_node(ports_fwnode, port_fwnode) { + if (fwnode_property_read_u32(port_fwnode, "reg", &val)) + continue; + if (val == port) { + p->fwnode = port_fwnode; + p->fiber = fwnode_property_present(port_fwnode, "sfp"); + break; + } + } + fwnode_handle_put(ports_fwnode); + } else { + dev_dbg(chip->dev, "no ethernet ports node defined for the device\n"); + } - chip->ports[port].chip = chip; - chip->ports[port].port = port; + if (chip->info->ops->port_setup_leds) { + err = chip->info->ops->port_setup_leds(chip, port); + if (err && err != -EOPNOTSUPP) + return err; + } err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED, SPEED_UNFORCED, DUPLEX_UNFORCED, @@ -4597,6 +4596,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6352_port_get_cmode, + .port_setup_leds = mv88e6xxx_port_setup_leds, .port_setup_message_port = mv88e6xxx_setup_message_port, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_set_histogram = mv88e6095_g1_stats_set_histogram, @@ -4699,6 +4699,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6352_port_get_cmode, + .port_setup_leds = mv88e6xxx_port_setup_leds, .port_setup_message_port = mv88e6xxx_setup_message_port, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_set_histogram = mv88e6095_g1_stats_set_histogram, @@ -4974,6 +4975,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6352_port_get_cmode, + .port_setup_leds = mv88e6xxx_port_setup_leds, .port_setup_message_port = mv88e6xxx_setup_message_port, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_set_histogram = mv88e6095_g1_stats_set_histogram, @@ -5396,6 +5398,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6352_port_get_cmode, + .port_setup_leds = mv88e6xxx_port_setup_leds, .port_setup_message_port = mv88e6xxx_setup_message_port, .stats_snapshot = mv88e6320_g1_stats_snapshot, .stats_set_histogram = mv88e6095_g1_stats_set_histogram, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index a5468224083962..9fe8e8a7856b27 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -276,6 +278,7 @@ struct mv88e6xxx_vlan { struct mv88e6xxx_port { struct mv88e6xxx_chip *chip; int port; + struct fwnode_handle *fwnode; struct mv88e6xxx_vlan bridge_pvid; u64 serdes_stats[2]; u64 atu_member_violation; @@ -290,6 +293,11 @@ struct mv88e6xxx_port { struct devlink_region *region; void *pcs_private; + /* LED related information */ + bool fiber; + struct led_classdev led0; + struct led_classdev led1; + /* MacAuth Bypass control flag */ bool mab; }; @@ -434,6 +442,9 @@ struct mv88e6xxx_chip { /* Bridge MST to SID mappings */ struct list_head msts; + + /* FID map */ + DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); }; struct mv88e6xxx_bus_ops { @@ -574,6 +585,9 @@ struct mv88e6xxx_ops { phy_interface_t mode); int (*port_get_cmode)(struct mv88e6xxx_chip *chip, int port, u8 *cmode); + /* LED control */ + int (*port_setup_leds)(struct mv88e6xxx_chip *chip, int port); + /* Some devices have a per port register indicating what is * the upstream port this port should forward to. */ @@ -592,7 +606,7 @@ struct mv88e6xxx_ops { /* Return the number of strings describing statistics */ int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip); - int (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data); + void (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t **data); size_t (*stats_get_stat)(struct mv88e6xxx_chip *chip, int port, const struct mv88e6xxx_hw_stat *stat, uint64_t *data); @@ -619,8 +633,8 @@ struct mv88e6xxx_ops { /* Statistics from the SERDES interface */ int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port); - int (*serdes_get_strings)(struct mv88e6xxx_chip *chip, int port, - uint8_t *data); + int (*serdes_get_strings)(struct mv88e6xxx_chip *chip, int port, + uint8_t **data); size_t (*serdes_get_stats)(struct mv88e6xxx_chip *chip, int port, uint64_t *data); @@ -830,6 +844,4 @@ int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip, void *priv), void *priv); -int mv88e6xxx_fid_map(struct mv88e6xxx_chip *chip, unsigned long *bitmap); - #endif /* _MV88E6XXX_CHIP_H */ diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c index a08dab75e0c0c1..795c8df7b6a743 100644 --- a/drivers/net/dsa/mv88e6xxx/devlink.c +++ b/drivers/net/dsa/mv88e6xxx/devlink.c @@ -374,10 +374,9 @@ static int mv88e6xxx_region_atu_snapshot(struct devlink *dl, u8 **data) { struct dsa_switch *ds = dsa_devlink_to_ds(dl); - DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID); struct mv88e6xxx_devlink_atu_entry *table; struct mv88e6xxx_chip *chip = ds->priv; - int fid = -1, count, err; + int fid = -1, err = 0, count; table = kmalloc_array(mv88e6xxx_num_databases(chip), sizeof(struct mv88e6xxx_devlink_atu_entry), @@ -392,14 +391,8 @@ static int mv88e6xxx_region_atu_snapshot(struct devlink *dl, mv88e6xxx_reg_lock(chip); - err = mv88e6xxx_fid_map(chip, fid_bitmap); - if (err) { - kfree(table); - goto out; - } - while (1) { - fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1); + fid = find_next_bit(chip->fid_bitmap, MV88E6XXX_N_FID, fid + 1); if (fid == MV88E6XXX_N_FID) break; diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c index bcfb4a812055cb..b524f27a2f0df0 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c @@ -471,6 +471,9 @@ int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip) { int err; + /* As part of the VTU flush, refresh FID map */ + bitmap_zero(chip->fid_bitmap, MV88E6XXX_N_FID); + err = mv88e6xxx_g1_vtu_op_wait(chip); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/leds.c b/drivers/net/dsa/mv88e6xxx/leds.c new file mode 100644 index 00000000000000..1c88bfaea46ba6 --- /dev/null +++ b/drivers/net/dsa/mv88e6xxx/leds.c @@ -0,0 +1,839 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include + +#include "chip.h" +#include "global2.h" +#include "port.h" + +/* Offset 0x16: LED control */ + +static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg) +{ + reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE; + + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg); +} + +static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port, + u16 ptr, u16 *val) +{ + int err; + + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr); + if (err) + return err; + + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val); + *val &= 0x3ff; + + return err; +} + +static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led, + int brightness) +{ + u16 reg; + int err; + + err = mv88e6xxx_port_led_read(p->chip, p->port, + MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, + ®); + if (err) + return err; + + if (led == 1) + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; + else + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; + + if (brightness) { + /* Selector 0x0f == Force LED ON */ + if (led == 1) + reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELF; + else + reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELF; + } else { + /* Selector 0x0e == Force LED OFF */ + if (led == 1) + reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE; + else + reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE; + } + + reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; + + return mv88e6xxx_port_led_write(p->chip, p->port, reg); +} + +static int mv88e6xxx_led0_brightness_set_blocking(struct led_classdev *ldev, + enum led_brightness brightness) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_brightness_set(p, 0, brightness); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int mv88e6xxx_led1_brightness_set_blocking(struct led_classdev *ldev, + enum led_brightness brightness) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_brightness_set(p, 1, brightness); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +struct mv88e6xxx_led_hwconfig { + int led; + u8 portmask; + unsigned long rules; + bool fiber; + bool blink_activity; + u16 selector; +}; + +/* The following is a lookup table to check what rules we can support on a + * certain LED given restrictions such as that some rules only work with fiber + * (SFP) connections and some blink on activity by default. + */ +#define MV88E6XXX_PORTS_0_3 (BIT(0) | BIT(1) | BIT(2) | BIT(3)) +#define MV88E6XXX_PORTS_4_5 (BIT(4) | BIT(5)) +#define MV88E6XXX_PORT_4 BIT(4) +#define MV88E6XXX_PORT_5 BIT(5) + +/* Entries are listed in selector order. + * + * These configurations vary across different switch families, list + * different tables per-family here. + */ +static const struct mv88e6xxx_led_hwconfig mv88e6352_led_hwconfigs[] = { + { + .led = 0, + .portmask = MV88E6XXX_PORT_4, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORT_5, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_1000), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_4_5, + .rules = BIT(TRIGGER_NETDEV_LINK), + .fiber = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORT_4, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORT_5, + .rules = BIT(TRIGGER_NETDEV_LINK), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORT_4, + .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORT_5, + .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORT_5, + .rules = BIT(TRIGGER_NETDEV_LINK), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_10), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELA, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELA, + }, + { + .led = 0, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), + .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELB, + }, + { + .led = 1, + .portmask = MV88E6XXX_PORTS_0_3, + .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000), + .blink_activity = true, + .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELB, + }, +}; + +/* mv88e6xxx_led_match_selector() - look up the appropriate LED mode selector + * @p: port state container + * @led: LED number, 0 or 1 + * @blink_activity: blink the LED (usually blink on indicated activity) + * @fiber: the link is connected to fiber such as SFP + * @rules: LED status flags from the LED classdev core + * @selector: fill in the selector in this parameter with an OR operation + */ +static int mv88e6xxx_led_match_selector(struct mv88e6xxx_port *p, int led, bool blink_activity, + bool fiber, unsigned long rules, u16 *selector) +{ + const struct mv88e6xxx_led_hwconfig *conf; + int i; + + /* No rules means we turn the LED off */ + if (!rules) { + if (led == 1) + *selector |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE; + else + *selector |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE; + return 0; + } + + /* TODO: these rules are for MV88E6352, when adding other families, + * think about making sure you select the table that match the + * specific switch family. + */ + for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) { + conf = &mv88e6352_led_hwconfigs[i]; + + if (conf->led != led) + continue; + + if (!(conf->portmask & BIT(p->port))) + continue; + + if (conf->blink_activity != blink_activity) + continue; + + if (conf->fiber != fiber) + continue; + + if (conf->rules == rules) { + dev_dbg(p->chip->dev, "port%d LED %d set selector %04x for rules %08lx\n", + p->port, led, conf->selector, rules); + *selector |= conf->selector; + return 0; + } + } + + return -EOPNOTSUPP; +} + +/* mv88e6xxx_led_match_selector() - find Linux netdev rules from a selector value + * @p: port state container + * @selector: the selector value from the LED actity register + * @led: LED number, 0 or 1 + * @rules: Linux netdev activity rules found from selector + */ +static int +mv88e6xxx_led_match_rule(struct mv88e6xxx_port *p, u16 selector, int led, unsigned long *rules) +{ + const struct mv88e6xxx_led_hwconfig *conf; + int i; + + /* Find the selector in the table, we just look for the right selector + * and ignore if the activity has special properties such as blinking + * or is fiber-only. + */ + for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) { + conf = &mv88e6352_led_hwconfigs[i]; + + if (conf->led != led) + continue; + + if (!(conf->portmask & BIT(p->port))) + continue; + + if (conf->selector == selector) { + dev_dbg(p->chip->dev, "port%d LED %d has selector %04x, rules %08lx\n", + p->port, led, selector, conf->rules); + *rules = conf->rules; + return 0; + } + } + + return -EINVAL; +} + +/* mv88e6xxx_led_get_selector() - get the appropriate LED mode selector + * @p: port state container + * @led: LED number, 0 or 1 + * @fiber: the link is connected to fiber such as SFP + * @rules: LED status flags from the LED classdev core + * @selector: fill in the selector in this parameter with an OR operation + */ +static int mv88e6xxx_led_get_selector(struct mv88e6xxx_port *p, int led, + bool fiber, unsigned long rules, u16 *selector) +{ + int err; + + /* What happens here is that we first try to locate a trigger with solid + * indicator (such as LED is on for a 1000 link) else we try a second + * sweep to find something suitable with a trigger that will blink on + * activity. + */ + err = mv88e6xxx_led_match_selector(p, led, false, fiber, rules, selector); + if (err) + return mv88e6xxx_led_match_selector(p, led, true, fiber, rules, selector); + + return 0; +} + +/* Sets up the hardware blinking period */ +static int mv88e6xxx_led_set_blinking_period(struct mv88e6xxx_port *p, int led, + unsigned long delay_on, unsigned long delay_off) +{ + unsigned long period; + u16 reg; + + period = delay_on + delay_off; + + reg = 0; + + switch (period) { + case 21: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS; + break; + case 42: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS; + break; + case 84: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS; + break; + case 168: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS; + break; + case 336: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS; + break; + case 672: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS; + break; + default: + /* Fall back to software blinking */ + return -EINVAL; + } + + /* This is essentially PWM duty cycle: how long time of the period + * will the LED be on. Zero isn't great in most cases. + */ + switch (delay_on) { + case 0: + /* This is usually pretty useless and will make the LED look OFF */ + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE; + break; + case 21: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS; + break; + case 42: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS; + break; + case 84: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS; + break; + case 168: + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS; + break; + default: + /* Just use something non-zero */ + reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS; + break; + } + + /* Set up blink rate */ + reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK; + + return mv88e6xxx_port_led_write(p->chip, p->port, reg); +} + +static int mv88e6xxx_led_blink_set(struct mv88e6xxx_port *p, int led, + unsigned long *delay_on, unsigned long *delay_off) +{ + u16 reg; + int err; + + /* Choose a sensible default 336 ms (~3 Hz) */ + if ((*delay_on == 0) && (*delay_off == 0)) { + *delay_on = 168; + *delay_off = 168; + } + + /* No off delay is just on */ + if (*delay_off == 0) + return mv88e6xxx_led_brightness_set(p, led, 1); + + err = mv88e6xxx_led_set_blinking_period(p, led, *delay_on, *delay_off); + if (err) + return err; + + err = mv88e6xxx_port_led_read(p->chip, p->port, + MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, + ®); + if (err) + return err; + + if (led == 1) + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; + else + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; + + /* This will select the forced blinking status */ + if (led == 1) + reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELD; + else + reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELD; + + reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; + + return mv88e6xxx_port_led_write(p->chip, p->port, reg); +} + +static int mv88e6xxx_led0_blink_set(struct led_classdev *ldev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_blink_set(p, 0, delay_on, delay_off); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int mv88e6xxx_led1_blink_set(struct led_classdev *ldev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_blink_set(p, 1, delay_on, delay_off); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int +mv88e6xxx_led0_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + u16 selector = 0; + + return mv88e6xxx_led_get_selector(p, 0, p->fiber, rules, &selector); +} + +static int +mv88e6xxx_led1_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + u16 selector = 0; + + return mv88e6xxx_led_get_selector(p, 1, p->fiber, rules, &selector); +} + +static int mv88e6xxx_led_hw_control_set(struct mv88e6xxx_port *p, + int led, unsigned long rules) +{ + u16 reg; + int err; + + err = mv88e6xxx_port_led_read(p->chip, p->port, + MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, + ®); + if (err) + return err; + + if (led == 1) + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; + else + reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; + + err = mv88e6xxx_led_get_selector(p, led, p->fiber, rules, ®); + if (err) + return err; + + reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL; + + if (led == 0) + dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n", + p->port, + (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK)); + else + dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n", + p->port, + (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4); + + return mv88e6xxx_port_led_write(p->chip, p->port, reg); +} + +static int +mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules) +{ + u16 val; + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_port_led_read(p->chip, p->port, + MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val); + mv88e6xxx_reg_unlock(p->chip); + if (err) + return err; + + /* Mask out the selector bits for this port */ + if (led == 1) { + val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK; + /* It's forced blinking/OFF/ON */ + if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD || + val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE || + val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) { + *rules = 0; + return 0; + } + } else { + val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK; + /* It's forced blinking/OFF/ON */ + if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD || + val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE || + val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) { + *rules = 0; + return 0; + } + } + + err = mv88e6xxx_led_match_rule(p, val, led, rules); + if (!err) + return 0; + + dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val); + *rules = 0; + return 0; +} + +static int +mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_hw_control_set(p, 0, rules); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int +mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + int err; + + mv88e6xxx_reg_lock(p->chip); + err = mv88e6xxx_led_hw_control_set(p, 1, rules); + mv88e6xxx_reg_unlock(p->chip); + + return err; +} + +static int +mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + + return mv88e6xxx_led_hw_control_get(p, 0, rules); +} + +static int +mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + + return mv88e6xxx_led_hw_control_get(p, 1, rules); +} + +static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p) +{ + struct dsa_port *dp; + + dp = dsa_to_port(p->chip->ds, p->port); + if (!dp) + return NULL; + if (dp->user) + return &dp->user->dev; + return NULL; +} + +static struct device * +mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0); + + return mv88e6xxx_led_hw_control_get_device(p); +} + +static struct device * +mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev) +{ + struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1); + + return mv88e6xxx_led_hw_control_get_device(p); +} + +int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port) +{ + struct fwnode_handle *led = NULL, *leds = NULL; + struct led_init_data init_data = { }; + enum led_default_state state; + struct mv88e6xxx_port *p; + struct led_classdev *l; + struct device *dev; + u32 led_num; + int ret; + + /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */ + if (port > 5) + return -EOPNOTSUPP; + + p = &chip->ports[port]; + if (!p->fwnode) + return 0; + + dev = chip->dev; + + leds = fwnode_get_named_child_node(p->fwnode, "leds"); + if (!leds) { + dev_dbg(dev, "No Leds node specified in device tree for port %d!\n", + port); + return 0; + } + + fwnode_for_each_child_node(leds, led) { + /* Reg represent the led number of the port, max 2 + * LEDs can be connected to each port, in some designs + * only one LED is connected. + */ + if (fwnode_property_read_u32(led, "reg", &led_num)) + continue; + if (led_num > 1) { + dev_err(dev, "invalid LED specified port %d\n", port); + return -EINVAL; + } + + if (led_num == 0) + l = &p->led0; + else + l = &p->led1; + + state = led_init_default_state_get(led); + switch (state) { + case LEDS_DEFSTATE_ON: + l->brightness = 1; + mv88e6xxx_led_brightness_set(p, led_num, 1); + break; + case LEDS_DEFSTATE_KEEP: + break; + default: + l->brightness = 0; + mv88e6xxx_led_brightness_set(p, led_num, 0); + } + + l->max_brightness = 1; + if (led_num == 0) { + l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking; + l->blink_set = mv88e6xxx_led0_blink_set; + l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported; + l->hw_control_set = mv88e6xxx_led0_hw_control_set; + l->hw_control_get = mv88e6xxx_led0_hw_control_get; + l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device; + } else { + l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking; + l->blink_set = mv88e6xxx_led1_blink_set; + l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported; + l->hw_control_set = mv88e6xxx_led1_hw_control_set; + l->hw_control_get = mv88e6xxx_led1_hw_control_get; + l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device; + } + l->hw_control_trigger = "netdev"; + + init_data.default_label = ":port"; + init_data.fwnode = led; + init_data.devname_mandatory = true; + init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name, + port, led_num); + if (!init_data.devicename) + return -ENOMEM; + + ret = devm_led_classdev_register_ext(dev, l, &init_data); + kfree(init_data.devicename); + + if (ret) { + dev_err(dev, "Failed to init LED %d for port %d", led_num, port); + return ret; + } + } + + return 0; +} diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 04053fdc6489af..dc777ddce1f3d9 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "chip.h" #include "global2.h" diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index ddadeb9bfdaeed..c1d2f99efb1c66 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -309,6 +309,130 @@ /* Offset 0x13: OutFiltered Counter */ #define MV88E6XXX_PORT_OUT_FILTERED 0x13 +/* Offset 0x16: LED Control */ +#define MV88E6XXX_PORT_LED_CONTROL 0x16 +#define MV88E6XXX_PORT_LED_CONTROL_UPDATE BIT(15) +#define MV88E6XXX_PORT_LED_CONTROL_POINTER_MASK GENMASK(14, 12) +#define MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL (0x00 << 12) /* Control for LED 0 and 1 */ +#define MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK (0x06 << 12) /* Stetch and Blink Rate */ +#define MV88E6XXX_PORT_LED_CONTROL_POINTER_CNTL_SPECIAL (0x07 << 12) /* Control for the Port's Special LED */ +#define MV88E6XXX_PORT_LED_CONTROL_DATA_MASK GENMASK(10, 0) +/* Selection masks valid for either port 1,2,3,4 or 5 */ +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK GENMASK(3, 0) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK GENMASK(7, 4) +/* Selection control for LED 0 and 1, ports 5 and 6 only has LED 0 + * Bits Function + * 0..3 LED 0 control selector on ports 1-5 + * 4..7 LED 1 control selector on ports 1-4 on port 5 this controls LED 0 of port 6 + * + * Sel Port LED Function for the 6352 family: + * 0 1-4 0 Link/Act/Speed by Blink Rate (off=no link, on=link, blink=activity, blink speed=link speed) + * 1-4 1 Port 2's Special LED + * 5-6 0 Port 5 Link/Act (off=no link, on=link, blink=activity) + * 5-6 1 Port 6 Link/Act (off=no link, on=link 1000, blink=activity) + * 1 1-4 0 100/1000 Link/Act (off=no link, on=100 or 1000 link, blink=activity) + * 1-4 1 10/100 Link Act (off=no link, on=10 or 100 link, blink=activity) + * 5-6 0 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity) + * 5-6 1 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity) + * 2 1-4 0 1000 Link/Act (off=no link, on=link 1000, blink=activity) + * 1-4 1 10/100 Link/Act (off=no link, on=10 or 100 link, blink=activity) + * 5-6 0 Fiber 1000 Link/Act (off=no link, on=link 1000, blink=activity) + * 5-6 1 Fiber 100 Link/Act (off=no link, on=link 100, blink=activity) + * 3 1-4 0 Link/Act (off=no link, on=link, blink=activity) + * 1-4 1 1000 Link (off=no link, on=1000 link) + * 5-6 0 Port 0's Special LED + * 5-6 1 Fiber Link (off=no link, on=link) + * 4 1-4 0 Port 0's Special LED + * 1-4 1 Port 1's Special LED + * 5-6 0 Port 1's Special LED + * 5-6 1 Port 5 Link/Act (off=no link, on=link, blink=activity) + * 5 1-4 0 Reserved + * 1-4 1 Reserved + * 5-6 0 Port 2's Special LED + * 5-6 1 Port 6 Link (off=no link, on=link) + * 6 1-4 0 Duplex/Collision (off=half-duplex,on=full-duplex,blink=collision) + * 1-4 1 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity) + * 5-6 0 Port 5 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col) + * 5-6 1 Port 6 Duplex/Collision (off=half-duplex, on=full-duplex, blink=col) + * 7 1-4 0 10/1000 Link/Act (off=no link, on=10 or 1000 link, blink=activity) + * 1-4 1 10/1000 Link (off=no link, on=10 or 1000 link) + * 5-6 0 Port 5 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed) + * 5-6 1 Port 6 Link/Act/Speed by Blink rate (off=no link, on=link, blink=activity, blink speed=link speed) + * 8 1-4 0 Link (off=no link, on=link) + * 1-4 1 Activity (off=no link, blink on=activity) + * 5-6 0 Port 6 Link/Act (off=no link, on=link, blink=activity) + * 5-6 1 Port 0's Special LED + * 9 1-4 0 10 Link (off=no link, on=10 link) + * 1-4 1 100 Link (off=no link, on=100 link) + * 5-6 0 Reserved + * 5-6 1 Port 1's Special LED + * a 1-4 0 10 Link/Act (off=no link, on=10 link, blink=activity) + * 1-4 1 100 Link/Act (off=no link, on=100 link, blink=activity) + * 5-6 0 Reserved + * 5-6 1 Port 2's Special LED + * b 1-4 0 100/1000 Link (off=no link, on=100 or 1000 link) + * 1-4 1 10/100 Link (off=no link, on=100 link, blink=activity) + * 5-6 0 Reserved + * 5-6 1 Reserved + * c * * PTP Act (blink on=PTP activity) + * d * * Force Blink + * e * * Force Off + * f * * Force On + */ +/* Select LED0 output */ +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0 0x0 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1 0x1 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2 0x2 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3 0x3 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL4 0x4 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL5 0x5 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6 0x6 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7 0x7 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8 0x8 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9 0x9 +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELA 0xa +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELB 0xb +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELC 0xc +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELD 0xd +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELE 0xe +#define MV88E6XXX_PORT_LED_CONTROL_LED0_SELF 0xf +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0 (0x0 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1 (0x1 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2 (0x2 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3 (0x3 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4 (0x4 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5 (0x5 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6 (0x6 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7 (0x7 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8 (0x8 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9 (0x9 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELA (0xa << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELB (0xb << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELC (0xc << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELD (0xd << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELE (0xe << 4) +#define MV88E6XXX_PORT_LED_CONTROL_LED1_SELF (0xf << 4) +/* Stretch and Blink Rate Control (Index 0x06 of LED Control) */ +/* Pulse Stretch Selection for all LED's on this port */ +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE (0 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS (1 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS (2 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS (3 << 4) +#define MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS (4 << 4) +/* Blink Rate Selection for all LEDs on this port */ +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS 0 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS 1 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS 2 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS 3 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS 4 +#define MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS 5 + /* Control for Special LED (Index 0x7 of LED Control on Port0) */ +#define MV88E6XXX_PORT_LED_CONTROL_0x07_P0_LAN_LINKACT_SHIFT 0 /* bits 6:0 LAN Link Activity LED */ +/* Control for Special LED (Index 0x7 of LED Control on Port 1) */ +#define MV88E6XXX_PORT_LED_CONTROL_0x07_P1_WAN_LINKACT_SHIFT 0 /* bits 6:0 WAN Link Activity LED */ +/* Control for Special LED (Index 0x7 of LED Control on Port 2) */ +#define MV88E6XXX_PORT_LED_CONTROL_0x07_P2_PTP_ACT 0 /* bits 6:0 PTP Activity */ + /* Offset 0x18: IEEE Priority Mapping Table */ #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18 #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000 @@ -457,6 +581,15 @@ int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode); int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); +#ifdef CONFIG_NET_DSA_MV88E6XXX_LEDS +int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port); +#else +static inline int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, + int port) +{ + return 0; +} +#endif int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port, bool drop_untagged); int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port, bool map); diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 01ea53940786d0..b3330211edbcaa 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -132,8 +132,8 @@ int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) return ARRAY_SIZE(mv88e6352_serdes_hw_stats); } -int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, - int port, uint8_t *data) +int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, + uint8_t **data) { struct mv88e6352_serdes_hw_stat *stat; int err, i; @@ -144,8 +144,7 @@ int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, for (i = 0; i < ARRAY_SIZE(mv88e6352_serdes_hw_stats); i++) { stat = &mv88e6352_serdes_hw_stats[i]; - memcpy(data + i * ETH_GSTRING_LEN, stat->string, - ETH_GSTRING_LEN); + ethtool_puts(data, stat->string); } return ARRAY_SIZE(mv88e6352_serdes_hw_stats); } @@ -394,8 +393,8 @@ int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) return ARRAY_SIZE(mv88e6390_serdes_hw_stats); } -int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, - int port, uint8_t *data) +int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, + uint8_t **data) { struct mv88e6390_serdes_hw_stat *stat; int i; @@ -405,8 +404,7 @@ int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { stat = &mv88e6390_serdes_hw_stats[i]; - memcpy(data + i * ETH_GSTRING_LEN, stat->string, - ETH_GSTRING_LEN); + ethtool_puts(data, stat->string); } return ARRAY_SIZE(mv88e6390_serdes_hw_stats); } diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index ff5c3ab31e155e..ad887d8601bcbb 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -125,13 +125,13 @@ unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port); int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port); -int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, - int port, uint8_t *data); +int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, + uint8_t **data); size_t mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, uint64_t *data); int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port); -int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, - int port, uint8_t *data); +int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, + uint8_t **data); size_t mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, uint64_t *data); diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 0102a82e88cc61..940f1b71226d64 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -24,7 +24,7 @@ #define VSC9959_NUM_PORTS 6 #define VSC9959_TAS_GCL_ENTRY_MAX 63 -#define VSC9959_TAS_MIN_GATE_LEN_NS 33 +#define VSC9959_TAS_MIN_GATE_LEN_NS 35 #define VSC9959_VCAP_POLICER_BASE 63 #define VSC9959_VCAP_POLICER_MAX 383 #define VSC9959_SWITCH_PCI_BAR 4 @@ -1056,11 +1056,15 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot) mdiobus_free(felix->imdio); } -/* The switch considers any frame (regardless of size) as eligible for - * transmission if the traffic class gate is open for at least 33 ns. +/* The switch considers any frame (regardless of size) as eligible + * for transmission if the traffic class gate is open for at least + * VSC9959_TAS_MIN_GATE_LEN_NS. + * * Overruns are prevented by cropping an interval at the end of the gate time - * slot for which egress scheduling is blocked, but we need to still keep 33 ns - * available for one packet to be transmitted, otherwise the port tc will hang. + * slot for which egress scheduling is blocked, but we need to still keep + * VSC9959_TAS_MIN_GATE_LEN_NS available for one packet to be transmitted, + * otherwise the port tc will hang. + * * This function returns the size of a gate interval that remains available for * setting the guard band, after reserving the space for one egress frame. */ @@ -1303,7 +1307,8 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port) * per-tc static guard band lengths, so it reduces the * useful gate interval length. Therefore, be careful * to calculate a guard band (and therefore max_sdu) - * that still leaves 33 ns available in the time slot. + * that still leaves VSC9959_TAS_MIN_GATE_LEN_NS + * available in the time slot. */ max_sdu = div_u64(remaining_gate_len_ps, picos_per_byte); /* A TC gate may be completely closed, which is a diff --git a/drivers/net/dsa/ocelot/ocelot_ext.c b/drivers/net/dsa/ocelot/ocelot_ext.c index 5632a7248cd417..d5c557a20292ed 100644 --- a/drivers/net/dsa/ocelot/ocelot_ext.c +++ b/drivers/net/dsa/ocelot/ocelot_ext.c @@ -102,11 +102,11 @@ static struct platform_driver ocelot_ext_switch_driver = { .of_match_table = ocelot_ext_switch_of_match, }, .probe = ocelot_ext_probe, - .remove_new = ocelot_ext_remove, + .remove = ocelot_ext_remove, .shutdown = ocelot_ext_shutdown, }; module_platform_driver(ocelot_ext_switch_driver); MODULE_DESCRIPTION("External Ocelot Switch driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(MFD_OCELOT); +MODULE_IMPORT_NS("MFD_OCELOT"); diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 70782649c39576..eb3944ba2a7279 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -1014,7 +1014,7 @@ MODULE_DEVICE_TABLE(of, seville_of_match); static struct platform_driver seville_vsc9953_driver = { .probe = seville_probe, - .remove_new = seville_remove, + .remove = seville_remove, .shutdown = seville_shutdown, .driver = { .name = "mscc_seville", diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index f8d8c70642c4ff..59b4a7240b5832 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -673,7 +673,7 @@ qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, * We therefore need to lock the MDIO bus onto which the switch is * connected. */ - mutex_lock(&priv->bus->mdio_lock); + mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); /* Actually start the request: * 1. Send mdio master packet diff --git a/drivers/net/dsa/realtek/realtek-mdio.c b/drivers/net/dsa/realtek/realtek-mdio.c index 04b758e5a680ac..a5e7dff96e91b5 100644 --- a/drivers/net/dsa/realtek/realtek-mdio.c +++ b/drivers/net/dsa/realtek/realtek-mdio.c @@ -140,13 +140,13 @@ int realtek_mdio_probe(struct mdio_device *mdiodev) return 0; } -EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, "REALTEK_DSA"); /** * realtek_mdio_remove() - Remove the driver of an MDIO-connected switch * @mdiodev: mdio_device to be removed. * - * This function should be used as the .remove_new in an mdio_driver. First + * This function should be used as the .remove in an mdio_driver. First * it unregisters the DSA switch and then it calls the common remove function. * * Context: Can sleep. @@ -163,7 +163,7 @@ void realtek_mdio_remove(struct mdio_device *mdiodev) rtl83xx_remove(priv); } -EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, "REALTEK_DSA"); /** * realtek_mdio_shutdown() - Shutdown the driver of a MDIO-connected switch @@ -184,4 +184,4 @@ void realtek_mdio_shutdown(struct mdio_device *mdiodev) rtl83xx_shutdown(priv); } -EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, "REALTEK_DSA"); diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index 88590ae95a75c5..972e2221841858 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -361,13 +361,13 @@ int realtek_smi_probe(struct platform_device *pdev) return 0; } -EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, "REALTEK_DSA"); /** * realtek_smi_remove() - Remove the driver of a SMI-connected switch * @pdev: platform_device to be removed. * - * This function should be used as the .remove_new in a platform_driver. First + * This function should be used as the .remove in a platform_driver. First * it unregisters the DSA switch and then it calls the common remove function. * * Context: Can sleep. @@ -384,7 +384,7 @@ void realtek_smi_remove(struct platform_device *pdev) rtl83xx_remove(priv); } -EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, "REALTEK_DSA"); /** * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch @@ -405,4 +405,4 @@ void realtek_smi_shutdown(struct platform_device *pdev) rtl83xx_shutdown(priv); } -EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, "REALTEK_DSA"); diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c index ad7044b295ec1a..7e96355c28bd4e 100644 --- a/drivers/net/dsa/realtek/rtl8365mb.c +++ b/drivers/net/dsa/realtek/rtl8365mb.c @@ -2164,7 +2164,7 @@ static struct platform_driver rtl8365mb_smi_driver = { .of_match_table = rtl8365mb_of_match, }, .probe = realtek_smi_probe, - .remove_new = realtek_smi_remove, + .remove = realtek_smi_remove, .shutdown = realtek_smi_shutdown, }; @@ -2206,4 +2206,4 @@ module_exit(rtl8365mb_exit); MODULE_AUTHOR("Alvin Šipraga "); MODULE_DESCRIPTION("Driver for RTL8365MB-VC ethernet switch"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(REALTEK_DSA); +MODULE_IMPORT_NS("REALTEK_DSA"); diff --git a/drivers/net/dsa/realtek/rtl8366-core.c b/drivers/net/dsa/realtek/rtl8366-core.c index 7c6520ba3a26cf..047feeed96a2fd 100644 --- a/drivers/net/dsa/realtek/rtl8366-core.c +++ b/drivers/net/dsa/realtek/rtl8366-core.c @@ -34,7 +34,7 @@ int rtl8366_mc_is_used(struct realtek_priv *priv, int mc_index, int *used) return 0; } -EXPORT_SYMBOL_NS_GPL(rtl8366_mc_is_used, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_mc_is_used, "REALTEK_DSA"); /** * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration @@ -187,7 +187,7 @@ int rtl8366_set_vlan(struct realtek_priv *priv, int vid, u32 member, return ret; } -EXPORT_SYMBOL_NS_GPL(rtl8366_set_vlan, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_set_vlan, "REALTEK_DSA"); int rtl8366_set_pvid(struct realtek_priv *priv, unsigned int port, unsigned int vid) @@ -217,7 +217,7 @@ int rtl8366_set_pvid(struct realtek_priv *priv, unsigned int port, return 0; } -EXPORT_SYMBOL_NS_GPL(rtl8366_set_pvid, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_set_pvid, "REALTEK_DSA"); int rtl8366_enable_vlan4k(struct realtek_priv *priv, bool enable) { @@ -243,7 +243,7 @@ int rtl8366_enable_vlan4k(struct realtek_priv *priv, bool enable) priv->vlan4k_enabled = enable; return 0; } -EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan4k, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan4k, "REALTEK_DSA"); int rtl8366_enable_vlan(struct realtek_priv *priv, bool enable) { @@ -265,7 +265,7 @@ int rtl8366_enable_vlan(struct realtek_priv *priv, bool enable) return ret; } -EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_enable_vlan, "REALTEK_DSA"); int rtl8366_reset_vlan(struct realtek_priv *priv) { @@ -290,7 +290,7 @@ int rtl8366_reset_vlan(struct realtek_priv *priv) return 0; } -EXPORT_SYMBOL_NS_GPL(rtl8366_reset_vlan, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_reset_vlan, "REALTEK_DSA"); int rtl8366_vlan_add(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan, @@ -345,7 +345,7 @@ int rtl8366_vlan_add(struct dsa_switch *ds, int port, return 0; } -EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_add, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_add, "REALTEK_DSA"); int rtl8366_vlan_del(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan) @@ -389,7 +389,7 @@ int rtl8366_vlan_del(struct dsa_switch *ds, int port, return 0; } -EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_del, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_vlan_del, "REALTEK_DSA"); void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) @@ -403,7 +403,7 @@ void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, for (i = 0; i < priv->num_mib_counters; i++) ethtool_puts(&data, priv->mib_counters[i].name); } -EXPORT_SYMBOL_NS_GPL(rtl8366_get_strings, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_get_strings, "REALTEK_DSA"); int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset) { @@ -417,7 +417,7 @@ int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset) return priv->num_mib_counters; } -EXPORT_SYMBOL_NS_GPL(rtl8366_get_sset_count, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_get_sset_count, "REALTEK_DSA"); void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) { @@ -441,4 +441,4 @@ void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) data[i] = mibvalue; } } -EXPORT_SYMBOL_NS_GPL(rtl8366_get_ethtool_stats, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl8366_get_ethtool_stats, "REALTEK_DSA"); diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c index c7a8cd06058781..23374178a17607 100644 --- a/drivers/net/dsa/realtek/rtl8366rb.c +++ b/drivers/net/dsa/realtek/rtl8366rb.c @@ -2102,7 +2102,7 @@ static struct platform_driver rtl8366rb_smi_driver = { .of_match_table = rtl8366rb_of_match, }, .probe = realtek_smi_probe, - .remove_new = realtek_smi_remove, + .remove = realtek_smi_remove, .shutdown = realtek_smi_shutdown, }; @@ -2144,4 +2144,4 @@ module_exit(rtl8366rb_exit); MODULE_AUTHOR("Linus Walleij "); MODULE_DESCRIPTION("Driver for RTL8366RB ethernet switch"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(REALTEK_DSA); +MODULE_IMPORT_NS("REALTEK_DSA"); diff --git a/drivers/net/dsa/realtek/rtl83xx.c b/drivers/net/dsa/realtek/rtl83xx.c index 3c5018d5e1f93b..2b9bd4462714bf 100644 --- a/drivers/net/dsa/realtek/rtl83xx.c +++ b/drivers/net/dsa/realtek/rtl83xx.c @@ -25,7 +25,7 @@ void rtl83xx_lock(void *ctx) mutex_lock(&priv->map_lock); } -EXPORT_SYMBOL_NS_GPL(rtl83xx_lock, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl83xx_lock, "REALTEK_DSA"); /** * rtl83xx_unlock() - Unlocks the mutex used by regmaps @@ -42,7 +42,7 @@ void rtl83xx_unlock(void *ctx) mutex_unlock(&priv->map_lock); } -EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, "REALTEK_DSA"); static int rtl83xx_user_mdio_read(struct mii_bus *bus, int addr, int regnum) { @@ -109,7 +109,7 @@ int rtl83xx_setup_user_mdio(struct dsa_switch *ds) return ret; } -EXPORT_SYMBOL_NS_GPL(rtl83xx_setup_user_mdio, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl83xx_setup_user_mdio, "REALTEK_DSA"); /** * rtl83xx_probe() - probe a Realtek switch @@ -208,7 +208,7 @@ rtl83xx_probe(struct device *dev, return priv; } -EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, "REALTEK_DSA"); /** * rtl83xx_register_switch() - detects and register a switch @@ -245,7 +245,7 @@ int rtl83xx_register_switch(struct realtek_priv *priv) return 0; } -EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, "REALTEK_DSA"); /** * rtl83xx_unregister_switch() - unregister a switch @@ -262,7 +262,7 @@ void rtl83xx_unregister_switch(struct realtek_priv *priv) dsa_unregister_switch(ds); } -EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, "REALTEK_DSA"); /** * rtl83xx_shutdown() - shutdown a switch @@ -283,7 +283,7 @@ void rtl83xx_shutdown(struct realtek_priv *priv) dev_set_drvdata(priv->dev, NULL); } -EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, "REALTEK_DSA"); /** * rtl83xx_remove() - Cleanup a realtek switch driver @@ -297,7 +297,7 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA); void rtl83xx_remove(struct realtek_priv *priv) { } -EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); +EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, "REALTEK_DSA"); void rtl83xx_reset_assert(struct realtek_priv *priv) { diff --git a/drivers/net/dsa/rzn1_a5psw.c b/drivers/net/dsa/rzn1_a5psw.c index 92e032972b34b7..66974379334a46 100644 --- a/drivers/net/dsa/rzn1_a5psw.c +++ b/drivers/net/dsa/rzn1_a5psw.c @@ -802,10 +802,8 @@ static void a5psw_get_strings(struct dsa_switch *ds, int port, u32 stringset, if (stringset != ETH_SS_STATS) return; - for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++) { - memcpy(data + u * ETH_GSTRING_LEN, a5psw_stats[u].name, - ETH_GSTRING_LEN); - } + for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++) + ethtool_puts(&data, a5psw_stats[u].name); } static void a5psw_get_ethtool_stats(struct dsa_switch *ds, int port, @@ -1324,7 +1322,7 @@ static struct platform_driver a5psw_driver = { .of_match_table = a5psw_of_mtable, }, .probe = a5psw_probe, - .remove_new = a5psw_remove, + .remove = a5psw_remove, .shutdown = a5psw_shutdown, }; module_platform_driver(a5psw_driver); diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 8c66d3bf61f028..dceb96ae9c83db 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -278,7 +278,7 @@ struct sja1105_private { struct mii_bus *mdio_base_t1; struct mii_bus *mdio_base_tx; struct mii_bus *mdio_pcs; - struct dw_xpcs *xpcs[SJA1105_MAX_NUM_PORTS]; + struct phylink_pcs *pcs[SJA1105_MAX_NUM_PORTS]; struct sja1105_ptp_data ptp_data; struct sja1105_tas_data tas_data; }; diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c index decc6c931dc100..2ea64b1d026d73 100644 --- a/drivers/net/dsa/sja1105/sja1105_ethtool.c +++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c @@ -586,7 +586,6 @@ void sja1105_get_strings(struct dsa_switch *ds, int port, { struct sja1105_private *priv = ds->priv; enum sja1105_counter_index max_ctr, i; - char *p = data; if (stringset != ETH_SS_STATS) return; @@ -597,10 +596,8 @@ void sja1105_get_strings(struct dsa_switch *ds, int port, else max_ctr = __MAX_SJA1105PQRS_PORT_COUNTER; - for (i = 0; i < max_ctr; i++) { - strscpy(p, sja1105_port_counters[i].name, ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } + for (i = 0; i < max_ctr; i++) + ethtool_puts(&data, sja1105_port_counters[i].name); } int sja1105_get_sset_count(struct dsa_switch *ds, int port, int sset) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index d0563ef59acf64..f8454f3b6f9c5d 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -1257,29 +1256,11 @@ static int sja1105_parse_dt(struct sja1105_private *priv) return rc; } -/* Convert link speed from SJA1105 to ethtool encoding */ -static int sja1105_port_speed_to_ethtool(struct sja1105_private *priv, - u64 speed) -{ - if (speed == priv->info->port_speed[SJA1105_SPEED_10MBPS]) - return SPEED_10; - if (speed == priv->info->port_speed[SJA1105_SPEED_100MBPS]) - return SPEED_100; - if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) - return SPEED_1000; - if (speed == priv->info->port_speed[SJA1105_SPEED_2500MBPS]) - return SPEED_2500; - return SPEED_UNKNOWN; -} - -/* Set link speed in the MAC configuration for a specific port. */ -static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, - int speed_mbps) +static int sja1105_set_port_speed(struct sja1105_private *priv, int port, + int speed_mbps) { struct sja1105_mac_config_entry *mac; - struct device *dev = priv->ds->dev; u64 speed; - int rc; /* On P/Q/R/S, one can read from the device via the MAC reconfiguration * tables. On E/T, MAC reconfig tables are not readable, only writable. @@ -1313,7 +1294,7 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS]; break; default: - dev_err(dev, "Invalid speed %iMbps\n", speed_mbps); + dev_err(priv->ds->dev, "Invalid speed %iMbps\n", speed_mbps); return -EINVAL; } @@ -1325,11 +1306,31 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port, * we need to configure the PCS only (if even that). */ if (priv->phy_mode[port] == PHY_INTERFACE_MODE_SGMII) - mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS]; + speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS]; else if (priv->phy_mode[port] == PHY_INTERFACE_MODE_2500BASEX) - mac[port].speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS]; - else - mac[port].speed = speed; + speed = priv->info->port_speed[SJA1105_SPEED_2500MBPS]; + + mac[port].speed = speed; + + return 0; +} + +/* Write the MAC Configuration Table entry and, if necessary, the CGU settings, + * after a link speedchange for this port. + */ +static int sja1105_set_port_config(struct sja1105_private *priv, int port) +{ + struct sja1105_mac_config_entry *mac; + struct device *dev = priv->ds->dev; + int rc; + + /* On P/Q/R/S, one can read from the device via the MAC reconfiguration + * tables. On E/T, MAC reconfig tables are not readable, only writable. + * We have to *know* what the MAC looks like. For the sake of keeping + * the code common, we'll use the static configuration tables as a + * reasonable approximation for both E/T and P/Q/R/S. + */ + mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; /* Write to the dynamic reconfiguration tables */ rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port, @@ -1356,12 +1357,8 @@ sja1105_mac_select_pcs(struct phylink_config *config, phy_interface_t iface) { struct dsa_port *dp = dsa_phylink_to_port(config); struct sja1105_private *priv = dp->ds->priv; - struct dw_xpcs *xpcs = priv->xpcs[dp->index]; - - if (xpcs) - return &xpcs->pcs; - return NULL; + return priv->pcs[dp->index]; } static void sja1105_mac_config(struct phylink_config *config, @@ -1390,7 +1387,8 @@ static void sja1105_mac_link_up(struct phylink_config *config, struct sja1105_private *priv = dp->ds->priv; int port = dp->index; - sja1105_adjust_port_config(priv, port, speed); + if (!sja1105_set_port_speed(priv, port, speed)) + sja1105_set_port_config(priv, port); sja1105_inhibit_tx(priv, BIT(port), false); } @@ -2293,8 +2291,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv, { struct ptp_system_timestamp ptp_sts_before; struct ptp_system_timestamp ptp_sts_after; - int speed_mbps[SJA1105_MAX_NUM_PORTS]; u16 bmcr[SJA1105_MAX_NUM_PORTS] = {0}; + u64 mac_speed[SJA1105_MAX_NUM_PORTS]; struct sja1105_mac_config_entry *mac; struct dsa_switch *ds = priv->ds; s64 t1, t2, t3, t4; @@ -2307,17 +2305,16 @@ int sja1105_static_config_reload(struct sja1105_private *priv, mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; - /* Back up the dynamic link speed changed by sja1105_adjust_port_config + /* Back up the dynamic link speed changed by sja1105_set_port_speed() * in order to temporarily restore it to SJA1105_SPEED_AUTO - which the * switch wants to see in the static config in order to allow us to * change it through the dynamic interface later. */ for (i = 0; i < ds->num_ports; i++) { - speed_mbps[i] = sja1105_port_speed_to_ethtool(priv, - mac[i].speed); + mac_speed[i] = mac[i].speed; mac[i].speed = priv->info->port_speed[SJA1105_SPEED_AUTO]; - if (priv->xpcs[i]) + if (priv->pcs[i]) bmcr[i] = mdiobus_c45_read(priv->mdio_pcs, i, MDIO_MMD_VEND2, MDIO_CTRL1); } @@ -2374,14 +2371,15 @@ int sja1105_static_config_reload(struct sja1105_private *priv, } for (i = 0; i < ds->num_ports; i++) { - struct dw_xpcs *xpcs = priv->xpcs[i]; + struct phylink_pcs *pcs = priv->pcs[i]; unsigned int neg_mode; - rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]); + mac[i].speed = mac_speed[i]; + rc = sja1105_set_port_config(priv, i); if (rc < 0) goto out; - if (!xpcs) + if (!pcs) continue; if (bmcr[i] & BMCR_ANENABLE) @@ -2389,7 +2387,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv, else neg_mode = PHYLINK_PCS_NEG_OUTBAND; - rc = xpcs_do_config(xpcs, priv->phy_mode[i], NULL, neg_mode); + rc = pcs->ops->pcs_config(pcs, neg_mode, priv->phy_mode[i], + NULL, true); if (rc < 0) goto out; @@ -2405,8 +2404,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv, else speed = SPEED_10; - xpcs_link_up(&xpcs->pcs, neg_mode, priv->phy_mode[i], - speed, DUPLEX_FULL); + pcs->ops->pcs_link_up(pcs, neg_mode, priv->phy_mode[i], + speed, DUPLEX_FULL); } } diff --git a/drivers/net/dsa/sja1105/sja1105_mdio.c b/drivers/net/dsa/sja1105/sja1105_mdio.c index 52ddb4ef259e93..84b7169f297480 100644 --- a/drivers/net/dsa/sja1105/sja1105_mdio.c +++ b/drivers/net/dsa/sja1105/sja1105_mdio.c @@ -400,7 +400,7 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) } for (port = 0; port < ds->num_ports; port++) { - struct dw_xpcs *xpcs; + struct phylink_pcs *pcs; if (dsa_is_unused_port(ds, port)) continue; @@ -409,13 +409,13 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX) continue; - xpcs = xpcs_create_mdiodev(bus, port, priv->phy_mode[port]); - if (IS_ERR(xpcs)) { - rc = PTR_ERR(xpcs); + pcs = xpcs_create_pcs_mdiodev(bus, port); + if (IS_ERR(pcs)) { + rc = PTR_ERR(pcs); goto out_pcs_free; } - priv->xpcs[port] = xpcs; + priv->pcs[port] = pcs; } priv->mdio_pcs = bus; @@ -424,11 +424,10 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) out_pcs_free: for (port = 0; port < ds->num_ports; port++) { - if (!priv->xpcs[port]) - continue; - - xpcs_destroy(priv->xpcs[port]); - priv->xpcs[port] = NULL; + if (priv->pcs[port]) { + xpcs_destroy_pcs(priv->pcs[port]); + priv->pcs[port] = NULL; + } } mdiobus_unregister(bus); @@ -446,11 +445,10 @@ static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv) return; for (port = 0; port < ds->num_ports; port++) { - if (!priv->xpcs[port]) - continue; - - xpcs_destroy(priv->xpcs[port]); - priv->xpcs[port] = NULL; + if (priv->pcs[port]) { + xpcs_destroy_pcs(priv->pcs[port]); + priv->pcs[port] = NULL; + } } mdiobus_unregister(priv->mdio_pcs); diff --git a/drivers/net/dsa/vitesse-vsc73xx-platform.c b/drivers/net/dsa/vitesse-vsc73xx-platform.c index 755b7895a15a9d..7a2e0a619b85ad 100644 --- a/drivers/net/dsa/vitesse-vsc73xx-platform.c +++ b/drivers/net/dsa/vitesse-vsc73xx-platform.c @@ -158,7 +158,7 @@ MODULE_DEVICE_TABLE(of, vsc73xx_of_match); static struct platform_driver vsc73xx_platform_driver = { .probe = vsc73xx_platform_probe, - .remove_new = vsc73xx_platform_remove, + .remove = vsc73xx_platform_remove, .shutdown = vsc73xx_platform_shutdown, .driver = { .name = "vsc73xx-platform", diff --git a/drivers/net/dsa/xrs700x/xrs700x.c b/drivers/net/dsa/xrs700x/xrs700x.c index de3b768f2ff9c0..4dbcc49a9e526f 100644 --- a/drivers/net/dsa/xrs700x/xrs700x.c +++ b/drivers/net/dsa/xrs700x/xrs700x.c @@ -91,10 +91,8 @@ static void xrs700x_get_strings(struct dsa_switch *ds, int port, if (stringset != ETH_SS_STATS) return; - for (i = 0; i < ARRAY_SIZE(xrs700x_mibs); i++) { - strscpy(data, xrs700x_mibs[i].name, ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (i = 0; i < ARRAY_SIZE(xrs700x_mibs); i++) + ethtool_puts(&data, xrs700x_mibs[i].name); } static int xrs700x_get_sset_count(struct dsa_switch *ds, int port, int sset) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index e9c5e1e11fa02d..005d79975f3bd2 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -168,22 +168,21 @@ static int __init dummy_init_module(void) { int i, err = 0; - down_write(&pernet_ops_rwsem); - rtnl_lock(); - err = __rtnl_link_register(&dummy_link_ops); + err = rtnl_link_register(&dummy_link_ops); if (err < 0) - goto out; + return err; + + rtnl_net_lock(&init_net); for (i = 0; i < numdummies && !err; i++) { err = dummy_init_one(); cond_resched(); } - if (err < 0) - __rtnl_link_unregister(&dummy_link_ops); -out: - rtnl_unlock(); - up_write(&pernet_ops_rwsem); + rtnl_net_unlock(&init_net); + + if (err < 0) + rtnl_link_unregister(&dummy_link_ops); return err; } diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 082388bb6169fa..790270912913fb 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -1302,7 +1302,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, if (print_info) pr_cont(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ - if (dev->irq <= 0 || dev->irq >= nr_irqs) + if (dev->irq <= 0 || dev->irq >= irq_get_nr_irqs()) pr_warn(" *** Warning: IRQ %d is unlikely to work! ***\n", dev->irq); diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2874680ef24d0f..e1695d0fbd8bb0 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -1009,7 +1009,7 @@ static struct platform_driver axdrv = { .name = "ax88796", }, .probe = ax_probe, - .remove_new = ax_remove, + .remove = ax_remove, .suspend = ax_suspend, .resume = ax_resume, }; diff --git a/drivers/net/ethernet/8390/mcf8390.c b/drivers/net/ethernet/8390/mcf8390.c index 5a0fa995e643b9..94ff8364cdf085 100644 --- a/drivers/net/ethernet/8390/mcf8390.c +++ b/drivers/net/ethernet/8390/mcf8390.c @@ -457,7 +457,7 @@ static struct platform_driver mcf8390_drv = { .name = "mcf8390", }, .probe = mcf8390_probe, - .remove_new = mcf8390_remove, + .remove = mcf8390_remove, }; module_platform_driver(mcf8390_drv); diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index 350683a09d2eff..961019c3284211 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -894,7 +894,7 @@ static int ne_drv_resume(struct platform_device *pdev) #endif static struct platform_driver ne_driver = { - .remove_new = ne_drv_remove, + .remove = ne_drv_remove, .suspend = ne_drv_suspend, .resume = ne_drv_resume, .driver = { diff --git a/drivers/net/ethernet/actions/owl-emac.c b/drivers/net/ethernet/actions/owl-emac.c index e03193da5874f8..115f48b3342cc5 100644 --- a/drivers/net/ethernet/actions/owl-emac.c +++ b/drivers/net/ethernet/actions/owl-emac.c @@ -1607,7 +1607,7 @@ static struct platform_driver owl_emac_driver = { .pm = &owl_emac_pm_ops, }, .probe = owl_emac_probe, - .remove_new = owl_emac_remove, + .remove = owl_emac_remove, }; module_platform_driver(owl_emac_driver); diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c index adf6f67c5fcbad..a593adc16c78ab 100644 --- a/drivers/net/ethernet/aeroflex/greth.c +++ b/drivers/net/ethernet/aeroflex/greth.c @@ -1565,7 +1565,7 @@ static struct platform_driver greth_of_driver = { .of_match_table = greth_of_match, }, .probe = greth_of_probe, - .remove_new = greth_of_remove, + .remove = greth_of_remove, }; module_platform_driver(greth_of_driver); diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index d761c08fe5c15e..2f516b950f4ea3 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -1142,7 +1142,7 @@ static struct platform_driver emac_driver = { .of_match_table = emac_of_match, }, .probe = emac_probe, - .remove_new = emac_remove, + .remove = emac_remove, .suspend = emac_suspend, .resume = emac_resume, }; diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 3c112c18ae6ae0..3f6204de9e6b80 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1519,7 +1519,7 @@ MODULE_DEVICE_TABLE(of, altera_tse_ids); static struct platform_driver altera_tse_driver = { .probe = altera_tse_probe, - .remove_new = altera_tse_remove, + .remove = altera_tse_remove, .suspend = NULL, .resume = NULL, .driver = { diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index d958cda9e58ba9..66445617fbfbf8 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -763,25 +763,16 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com if (comp_ctx->status == ENA_CMD_COMPLETED) { netdev_err(admin_queue->ena_dev->net_device, - "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n", - comp_ctx->cmd_opcode, admin_queue->auto_polling ? "ON" : "OFF"); - /* Check if fallback to polling is enabled */ - if (admin_queue->auto_polling) - admin_queue->polling = true; + "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d)\n", + comp_ctx->cmd_opcode); } else { netdev_err(admin_queue->ena_dev->net_device, "The ena device didn't send a completion for the admin cmd %d status %d\n", comp_ctx->cmd_opcode, comp_ctx->status); } - /* Check if shifted to polling mode. - * This will happen if there is a completion without an interrupt - * and autopolling mode is enabled. Continuing normal execution in such case - */ - if (!admin_queue->polling) { - admin_queue->running_state = false; - ret = -ETIME; - goto err; - } + admin_queue->running_state = false; + ret = -ETIME; + goto err; } ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status); @@ -1650,12 +1641,6 @@ void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling) ena_dev->admin_queue.polling = polling; } -void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev, - bool polling) -{ - ena_dev->admin_queue.auto_polling = polling; -} - int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) { struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; @@ -2198,21 +2183,6 @@ int ena_com_get_ena_srd_info(struct ena_com_dev *ena_dev, return ret; } -int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev, - struct ena_admin_basic_stats *stats) -{ - struct ena_com_stats_ctx ctx; - int ret; - - memset(&ctx, 0x0, sizeof(ctx)); - ret = ena_get_dev_stats(ena_dev, &ctx, ENA_ADMIN_GET_STATS_TYPE_BASIC); - if (likely(ret == 0)) - memcpy(stats, &ctx.get_resp.u.basic_stats, - sizeof(ctx.get_resp.u.basic_stats)); - - return ret; -} - int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 len) { struct ena_admin_aq_get_stats_cmd *get_cmd; @@ -2289,24 +2259,6 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) return ret; } -int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, - struct ena_admin_feature_offload_desc *offload) -{ - int ret; - struct ena_admin_get_feat_resp resp; - - ret = ena_com_get_feature(ena_dev, &resp, - ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0); - if (unlikely(ret)) { - netdev_err(ena_dev->net_device, "Failed to get offload capabilities %d\n", ret); - return ret; - } - - memcpy(offload, &resp.u.offload, sizeof(resp.u.offload)); - - return 0; -} - int ena_com_set_hash_function(struct ena_com_dev *ena_dev) { struct ena_com_admin_queue *admin_queue = &ena_dev->admin_queue; diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index a372c5e768a74c..9414e93d107b3d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -224,9 +224,6 @@ struct ena_com_admin_queue { /* Indicate if the admin queue should poll for completion */ bool polling; - /* Define if fallback to polling mode should occur */ - bool auto_polling; - u16 curr_cmd_id; /* Indicate that the ena was initialized and can @@ -493,17 +490,6 @@ bool ena_com_get_admin_running_state(struct ena_com_dev *ena_dev); */ void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling); -/* ena_com_set_admin_auto_polling_mode - Enable autoswitch to polling mode - * @ena_dev: ENA communication layer struct - * @polling: Enable/Disable polling mode - * - * Set the autopolling mode. - * If autopolling is on: - * In case of missing interrupt when data is available switch to polling. - */ -void ena_com_set_admin_auto_polling_mode(struct ena_com_dev *ena_dev, - bool polling); - /* ena_com_admin_q_comp_intr_handler - admin queue interrupt handler * @ena_dev: ENA communication layer struct * @@ -591,15 +577,6 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag); int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, struct ena_com_dev_get_features_ctx *get_feat_ctx); -/* ena_com_get_dev_basic_stats - Get device basic statistics - * @ena_dev: ENA communication layer struct - * @stats: stats return value - * - * @return: 0 on Success and negative value otherwise. - */ -int ena_com_get_dev_basic_stats(struct ena_com_dev *ena_dev, - struct ena_admin_basic_stats *stats); - /* ena_com_get_eni_stats - Get extended network interface statistics * @ena_dev: ENA communication layer struct * @stats: stats return value @@ -635,15 +612,6 @@ int ena_com_get_customer_metrics(struct ena_com_dev *ena_dev, char *buffer, u32 */ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu); -/* ena_com_get_offload_settings - Retrieve the device offloads capabilities - * @ena_dev: ENA communication layer struct - * @offlad: offload return value - * - * @return: 0 on Success and negative value otherwise. - */ -int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, - struct ena_admin_feature_offload_desc *offload); - /* ena_com_rss_init - Init RSS * @ena_dev: ENA communication layer struct * @log_size: indirection log size diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 60fb35ec4b15ac..a3c934c3de71d3 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -1129,22 +1129,18 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf) return; } - strings_buf = devm_kcalloc(&adapter->pdev->dev, - ETH_GSTRING_LEN, strings_num, - GFP_ATOMIC); + strings_buf = kcalloc(strings_num, ETH_GSTRING_LEN, GFP_ATOMIC); if (!strings_buf) { netif_err(adapter, drv, netdev, "Failed to allocate strings_buf\n"); return; } - data_buf = devm_kcalloc(&adapter->pdev->dev, - strings_num, sizeof(u64), - GFP_ATOMIC); + data_buf = kcalloc(strings_num, sizeof(u64), GFP_ATOMIC); if (!data_buf) { netif_err(adapter, drv, netdev, "Failed to allocate data buf\n"); - devm_kfree(&adapter->pdev->dev, strings_buf); + kfree(strings_buf); return; } @@ -1166,8 +1162,8 @@ static void ena_dump_stats_ex(struct ena_adapter *adapter, u8 *buf) strings_buf + i * ETH_GSTRING_LEN, data_buf[i]); - devm_kfree(&adapter->pdev->dev, strings_buf); - devm_kfree(&adapter->pdev->dev, data_buf); + kfree(strings_buf); + kfree(data_buf); } void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index c5b50cfa935a38..63c8a2328142d6 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1383,7 +1383,7 @@ static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi) rx_ring->rx_stats.bytes, &dim_sample); - net_dim(&ena_napi->dim, dim_sample); + net_dim(&ena_napi->dim, &dim_sample); rx_ring->per_napi_packets = 0; } @@ -1677,9 +1677,9 @@ static int ena_request_mgmnt_irq(struct ena_adapter *adapter) static int ena_request_io_irq(struct ena_adapter *adapter) { u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues; + int rc = 0, i, k, irq_idx; unsigned long flags = 0; struct ena_irq *irq; - int rc = 0, i, k; if (!test_bit(ENA_FLAG_MSIX_ENABLED, &adapter->flags)) { netif_err(adapter, ifup, adapter->netdev, @@ -1705,6 +1705,16 @@ static int ena_request_io_irq(struct ena_adapter *adapter) irq_set_affinity_hint(irq->vector, &irq->affinity_hint_mask); } + /* Now that IO IRQs have been successfully allocated map them to the + * corresponding IO NAPI instance. Note that the mgmnt IRQ does not + * have a NAPI, so care must be taken to correctly map IRQs to NAPIs. + */ + for (i = 0; i < io_queue_count; i++) { + irq_idx = ENA_IO_IRQ_IDX(i); + irq = &adapter->irq_tbl[irq_idx]; + netif_napi_set_irq(&adapter->ena_napi[i].napi, irq->vector); + } + return rc; err: @@ -1811,20 +1821,40 @@ static void ena_napi_disable_in_range(struct ena_adapter *adapter, int first_index, int count) { + struct napi_struct *napi; int i; - for (i = first_index; i < first_index + count; i++) - napi_disable(&adapter->ena_napi[i].napi); + for (i = first_index; i < first_index + count; i++) { + napi = &adapter->ena_napi[i].napi; + if (!ENA_IS_XDP_INDEX(adapter, i)) { + /* This API is supported for non-XDP queues only */ + netif_queue_set_napi(adapter->netdev, i, + NETDEV_QUEUE_TYPE_TX, NULL); + netif_queue_set_napi(adapter->netdev, i, + NETDEV_QUEUE_TYPE_RX, NULL); + } + napi_disable(napi); + } } static void ena_napi_enable_in_range(struct ena_adapter *adapter, int first_index, int count) { + struct napi_struct *napi; int i; - for (i = first_index; i < first_index + count; i++) - napi_enable(&adapter->ena_napi[i].napi); + for (i = first_index; i < first_index + count; i++) { + napi = &adapter->ena_napi[i].napi; + napi_enable(napi); + if (!ENA_IS_XDP_INDEX(adapter, i)) { + /* This API is supported for non-XDP queues only */ + netif_queue_set_napi(adapter->netdev, i, + NETDEV_QUEUE_TYPE_RX, napi); + netif_queue_set_napi(adapter->netdev, i, + NETDEV_QUEUE_TYPE_TX, napi); + } + } } /* Configure the Rx forwarding */ diff --git a/drivers/net/ethernet/amd/amd8111e.h b/drivers/net/ethernet/amd/amd8111e.h index 305232f5476d06..e4ee4c28800cfb 100644 --- a/drivers/net/ethernet/amd/amd8111e.h +++ b/drivers/net/ethernet/amd/amd8111e.h @@ -550,7 +550,6 @@ typedef enum { /* Driver definitions */ -#define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD8111E_7462 0x7462 #define MAX_UNITS 8 /* Maximum number of devices possible */ diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c index 85c978149bf660..0671a066913bc0 100644 --- a/drivers/net/ethernet/amd/au1000_eth.c +++ b/drivers/net/ethernet/amd/au1000_eth.c @@ -1363,7 +1363,7 @@ static void au1000_remove(struct platform_device *pdev) static struct platform_driver au1000_eth_driver = { .probe = au1000_probe, - .remove_new = au1000_remove, + .remove = au1000_remove, .driver = { .name = "au1000-eth", }, diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c index c78706d21a6afe..0f98b92408eda3 100644 --- a/drivers/net/ethernet/amd/sunlance.c +++ b/drivers/net/ethernet/amd/sunlance.c @@ -1514,7 +1514,7 @@ static struct platform_driver sunlance_sbus_driver = { .of_match_table = sunlance_sbus_match, }, .probe = sunlance_sbus_probe, - .remove_new = sunlance_sbus_remove, + .remove = sunlance_sbus_remove, }; module_platform_driver(sunlance_sbus_driver); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c index 5fc94c2f638e04..4431ab1c18b320 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c @@ -195,23 +195,19 @@ static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: - for (i = 0; i < XGBE_STATS_COUNT; i++) { - memcpy(data, xgbe_gstring_stats[i].stat_string, - ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (i = 0; i < XGBE_STATS_COUNT; i++) + ethtool_puts(&data, xgbe_gstring_stats[i].stat_string); + for (i = 0; i < pdata->tx_ring_count; i++) { - sprintf(data, "txq_%u_packets", i); - data += ETH_GSTRING_LEN; - sprintf(data, "txq_%u_bytes", i); - data += ETH_GSTRING_LEN; + ethtool_sprintf(&data, "txq_%u_packets", i); + ethtool_sprintf(&data, "txq_%u_bytes", i); } + for (i = 0; i < pdata->rx_ring_count; i++) { - sprintf(data, "rxq_%u_packets", i); - data += ETH_GSTRING_LEN; - sprintf(data, "rxq_%u_bytes", i); - data += ETH_GSTRING_LEN; + ethtool_sprintf(&data, "rxq_%u_packets", i); + ethtool_sprintf(&data, "rxq_%u_bytes", i); } + break; } } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-platform.c b/drivers/net/ethernet/amd/xgbe/xgbe-platform.c index 7912b3b45148ab..4365bd62942cf7 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-platform.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-platform.c @@ -565,7 +565,7 @@ static struct platform_driver xgbe_driver = { .pm = &xgbe_platform_pm_ops, }, .probe = xgbe_platform_probe, - .remove_new = xgbe_platform_remove, + .remove = xgbe_platform_remove, }; int xgbe_platform_init(void) diff --git a/drivers/net/ethernet/apm/xgene-v2/main.c b/drivers/net/ethernet/apm/xgene-v2/main.c index 9e90c238149104..2a91c84aebdb04 100644 --- a/drivers/net/ethernet/apm/xgene-v2/main.c +++ b/drivers/net/ethernet/apm/xgene-v2/main.c @@ -734,7 +734,7 @@ static struct platform_driver xge_driver = { .acpi_match_table = ACPI_PTR(xge_acpi_match), }, .probe = xge_probe, - .remove_new = xge_remove, + .remove = xge_remove, .shutdown = xge_shutdown, }; module_platform_driver(xge_driver); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 4af9d89d5f88b1..3b2951030a3891 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -2159,7 +2159,7 @@ static struct platform_driver xgene_enet_driver = { .acpi_match_table = ACPI_PTR(xgene_enet_acpi_match), }, .probe = xgene_enet_probe, - .remove_new = xgene_enet_remove, + .remove = xgene_enet_remove, .shutdown = xgene_enet_shutdown, }; diff --git a/drivers/net/ethernet/apple/macmace.c b/drivers/net/ethernet/apple/macmace.c index 766ab78256feeb..8989506e624826 100644 --- a/drivers/net/ethernet/apple/macmace.c +++ b/drivers/net/ethernet/apple/macmace.c @@ -759,7 +759,7 @@ static void mac_mace_device_remove(struct platform_device *pdev) static struct platform_driver mac_mace_driver = { .probe = mace_probe, - .remove_new = mac_mace_device_remove, + .remove = mac_mace_device_remove, .driver = { .name = mac_mace_string, }, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 440ff4616fec1f..6fef47ba0a59b1 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -15,6 +15,7 @@ #include "aq_macsec.h" #include "aq_main.h" +#include #include #include @@ -977,6 +978,76 @@ static int aq_ethtool_set_phy_tunable(struct net_device *ndev, return err; } +static int aq_ethtool_get_module_info(struct net_device *ndev, + struct ethtool_modinfo *modinfo) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + u8 compliance_val, dom_type; + int err; + + /* Module EEPROM is only supported for controllers with external PHY */ + if (aq_nic->aq_nic_cfg.aq_hw_caps->media_type != AQ_HW_MEDIA_TYPE_FIBRE || + !aq_nic->aq_hw_ops->hw_read_module_eeprom) + return -EOPNOTSUPP; + + err = aq_nic->aq_hw_ops->hw_read_module_eeprom(aq_nic->aq_hw, + SFF_8472_ID_ADDR, SFF_8472_COMP_ADDR, 1, &compliance_val); + if (err) + return err; + + err = aq_nic->aq_hw_ops->hw_read_module_eeprom(aq_nic->aq_hw, + SFF_8472_ID_ADDR, SFF_8472_DOM_TYPE_ADDR, 1, &dom_type); + if (err) + return err; + + if (dom_type & SFF_8472_ADDRESS_CHANGE_REQ_MASK || compliance_val == 0x00) { + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + } else { + modinfo->type = ETH_MODULE_SFF_8472; + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + } + return 0; +} + +static int aq_ethtool_get_module_eeprom(struct net_device *ndev, + struct ethtool_eeprom *ee, unsigned char *data) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + unsigned int first, last, len; + int err; + + if (!aq_nic->aq_hw_ops->hw_read_module_eeprom) + return -EOPNOTSUPP; + + first = ee->offset; + last = ee->offset + ee->len; + + if (first < ETH_MODULE_SFF_8079_LEN) { + len = min(last, ETH_MODULE_SFF_8079_LEN); + len -= first; + + err = aq_nic->aq_hw_ops->hw_read_module_eeprom(aq_nic->aq_hw, + SFF_8472_ID_ADDR, first, len, data); + if (err) + return err; + + first += len; + data += len; + } + if (first < ETH_MODULE_SFF_8472_LEN && last > ETH_MODULE_SFF_8079_LEN) { + len = min(last, ETH_MODULE_SFF_8472_LEN); + len -= first; + first -= ETH_MODULE_SFF_8079_LEN; + + err = aq_nic->aq_hw_ops->hw_read_module_eeprom(aq_nic->aq_hw, + SFF_8472_DIAGNOSTICS_ADDR, first, len, data); + if (err) + return err; + } + return 0; +} + const struct ethtool_ops aq_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES, @@ -1014,4 +1085,6 @@ const struct ethtool_ops aq_ethtool_ops = { .get_ts_info = aq_ethtool_get_ts_info, .get_phy_tunable = aq_ethtool_get_phy_tunable, .set_phy_tunable = aq_ethtool_set_phy_tunable, + .get_module_info = aq_ethtool_get_module_info, + .get_module_eeprom = aq_ethtool_get_module_eeprom, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h index 6d5be5ebeb138c..f26fe1a7553997 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h @@ -14,4 +14,12 @@ extern const struct ethtool_ops aq_ethtool_ops; #define AQ_PRIV_FLAGS_MASK (AQ_HW_LOOPBACK_MASK) +#define SFF_8472_ID_ADDR 0x50 +#define SFF_8472_DIAGNOSTICS_ADDR 0x51 + +#define SFF_8472_COMP_ADDR 0x5e +#define SFF_8472_DOM_TYPE_ADDR 0x5c + +#define SFF_8472_ADDRESS_CHANGE_REQ_MASK 0x4 + #endif /* AQ_ETHTOOL_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index f010bda61c9611..42c0efc1b45581 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -340,6 +340,9 @@ struct aq_hw_ops { int (*hw_set_loopback)(struct aq_hw_s *self, u32 mode, bool enable); int (*hw_get_mac_temp)(struct aq_hw_s *self, u32 *temp); + + int (*hw_read_module_eeprom)(struct aq_hw_s *self, u8 dev_addr, + u8 reg_start_addr, int len, u8 *data); }; struct aq_fw_ops { diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 43c71f6b314f9d..08630ee94251ce 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -162,8 +162,8 @@ int aq_pci_func_alloc_irq(struct aq_nic_s *self, unsigned int i, self->msix_entry_mask |= (1 << i); if (pdev->msix_enabled && affinity_mask) - irq_set_affinity_hint(pci_irq_vector(pdev, i), - affinity_mask); + irq_update_affinity_hint(pci_irq_vector(pdev, i), + affinity_mask); } return err; @@ -187,7 +187,7 @@ void aq_pci_func_free_irqs(struct aq_nic_s *self) continue; if (pdev->msix_enabled) - irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL); + irq_update_affinity_hint(pci_irq_vector(pdev, i), NULL); free_irq(pci_irq_vector(pdev, i), irq_data); self->msix_entry_mask &= ~(1U << i); } diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 56c46266bb0ae5..493432d036b9a2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -1654,6 +1654,137 @@ static int hw_atl_b0_get_mac_temp(struct aq_hw_s *self, u32 *temp) return 0; } +#define START_TRANSMIT 0x5001 +#define START_READ_TRANSMIT 0x5101 +#define STOP_TRANSMIT 0x3001 +#define REPEAT_TRANSMIT 0x1001 +#define REPEAT_NACK_TRANSMIT 0x1011 + +static int hw_atl_b0_smb0_wait_result(struct aq_hw_s *self, bool expect_ack) +{ + int err; + u32 val; + + err = readx_poll_timeout(hw_atl_smb0_byte_transfer_complete_get, + self, val, val == 1, 100U, 10000U); + if (err) + return err; + if (hw_atl_smb0_receive_acknowledged_get(self) != expect_ack) + return -EIO; + return 0; +} + +/* Starts an I2C/SMBUS write to a given address. addr is in 7-bit format, + * the read/write bit is not part of it. + */ +static int hw_atl_b0_smb0_start_write(struct aq_hw_s *self, u32 addr) +{ + hw_atl_smb0_tx_data_set(self, (addr << 1) | 0); + hw_atl_smb0_provisioning2_set(self, START_TRANSMIT); + return hw_atl_b0_smb0_wait_result(self, 0); +} + +/* Writes a single byte as part of an ongoing write started by start_write. */ +static int hw_atl_b0_smb0_write_byte(struct aq_hw_s *self, u32 data) +{ + hw_atl_smb0_tx_data_set(self, data); + hw_atl_smb0_provisioning2_set(self, REPEAT_TRANSMIT); + return hw_atl_b0_smb0_wait_result(self, 0); +} + +/* Starts an I2C/SMBUS read to a given address. addr is in 7-bit format, + * the read/write bit is not part of it. + */ +static int hw_atl_b0_smb0_start_read(struct aq_hw_s *self, u32 addr) +{ + int err; + + hw_atl_smb0_tx_data_set(self, (addr << 1) | 1); + hw_atl_smb0_provisioning2_set(self, START_READ_TRANSMIT); + err = hw_atl_b0_smb0_wait_result(self, 0); + if (err) + return err; + if (hw_atl_smb0_repeated_start_detect_get(self) == 0) + return -EIO; + return 0; +} + +/* Reads a single byte as part of an ongoing read started by start_read. */ +static int hw_atl_b0_smb0_read_byte(struct aq_hw_s *self) +{ + int err; + + hw_atl_smb0_provisioning2_set(self, REPEAT_TRANSMIT); + err = hw_atl_b0_smb0_wait_result(self, 0); + if (err) + return err; + return hw_atl_smb0_rx_data_get(self); +} + +/* Reads the last byte of an ongoing read. */ +static int hw_atl_b0_smb0_read_byte_nack(struct aq_hw_s *self) +{ + int err; + + hw_atl_smb0_provisioning2_set(self, REPEAT_NACK_TRANSMIT); + err = hw_atl_b0_smb0_wait_result(self, 1); + if (err) + return err; + return hw_atl_smb0_rx_data_get(self); +} + +/* Sends a stop condition and ends a transfer. */ +static void hw_atl_b0_smb0_stop(struct aq_hw_s *self) +{ + hw_atl_smb0_provisioning2_set(self, STOP_TRANSMIT); +} + +static int hw_atl_b0_read_module_eeprom(struct aq_hw_s *self, u8 dev_addr, + u8 reg_start_addr, int len, u8 *data) +{ + int i, b; + int err; + u32 val; + + /* Wait for SMBUS0 to be idle */ + err = readx_poll_timeout(hw_atl_smb0_bus_busy_get, self, + val, val == 0, 100U, 10000U); + if (err) + return err; + + err = hw_atl_b0_smb0_start_write(self, dev_addr); + if (err) + goto out; + + err = hw_atl_b0_smb0_write_byte(self, reg_start_addr); + if (err) + goto out; + + err = hw_atl_b0_smb0_start_read(self, dev_addr); + if (err) + goto out; + + for (i = 0; i < len - 1; i++) { + b = hw_atl_b0_smb0_read_byte(self); + if (b < 0) { + err = b; + goto out; + } + data[i] = (u8)b; + } + + b = hw_atl_b0_smb0_read_byte_nack(self); + if (b < 0) { + err = b; + goto out; + } + data[i] = (u8)b; + +out: + hw_atl_b0_smb0_stop(self); + return err; +} + const struct aq_hw_ops hw_atl_ops_b0 = { .hw_soft_reset = hw_atl_utils_soft_reset, .hw_prepare = hw_atl_utils_initfw, @@ -1712,4 +1843,5 @@ const struct aq_hw_ops hw_atl_ops_b0 = { .hw_set_fc = hw_atl_b0_set_fc, .hw_get_mac_temp = hw_atl_b0_get_mac_temp, + .hw_read_module_eeprom = hw_atl_b0_read_module_eeprom, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index 7b67bdd8a258ef..d07af1271d59dd 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -57,6 +57,49 @@ u32 hw_atl_ts_data_get(struct aq_hw_s *aq_hw) HW_ATL_TS_DATA_OUT_SHIFT); } +u32 hw_atl_smb0_bus_busy_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_SMB0_BUS_BUSY_ADR, + HW_ATL_SMB0_BUS_BUSY_MSK, + HW_ATL_SMB0_BUS_BUSY_SHIFT); +} + +u32 hw_atl_smb0_byte_transfer_complete_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_ADR, + HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_MSK, + HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_SHIFT); +} + +u32 hw_atl_smb0_receive_acknowledged_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_SMB0_RX_ACKNOWLEDGED_ADR, + HW_ATL_SMB0_RX_ACKNOWLEDGED_MSK, + HW_ATL_SMB0_RX_ACKNOWLEDGED_SHIFT); +} + +u32 hw_atl_smb0_repeated_start_detect_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_SMB0_REPEATED_START_DETECT_ADR, + HW_ATL_SMB0_REPEATED_START_DETECT_MSK, + HW_ATL_SMB0_REPEATED_START_DETECT_SHIFT); +} + +u32 hw_atl_smb0_rx_data_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_SMB0_RECEIVED_DATA_ADR); +} + +void hw_atl_smb0_tx_data_set(struct aq_hw_s *aq_hw, u32 data) +{ + return aq_hw_write_reg(aq_hw, HW_ATL_SMB0_TRANSMITTED_DATA_ADR, data); +} + +void hw_atl_smb0_provisioning2_set(struct aq_hw_s *aq_hw, u32 data) +{ + return aq_hw_write_reg(aq_hw, HW_ATL_SMB0_PROVISIONING2_ADR, data); +} + /* global */ void hw_atl_reg_glb_cpu_sem_set(struct aq_hw_s *aq_hw, u32 glb_cpu_sem, u32 semaphore) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index 58f5ee0a6214f2..5fd506acacb541 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -34,6 +34,27 @@ u32 hw_atl_ts_ready_latch_high_get(struct aq_hw_s *aq_hw); /* get temperature sense data */ u32 hw_atl_ts_data_get(struct aq_hw_s *aq_hw); +/* SMBUS0 bus busy */ +u32 hw_atl_smb0_bus_busy_get(struct aq_hw_s *aq_hw); + +/* SMBUS0 byte transfer complete */ +u32 hw_atl_smb0_byte_transfer_complete_get(struct aq_hw_s *aq_hw); + +/* SMBUS0 receive acknowledged */ +u32 hw_atl_smb0_receive_acknowledged_get(struct aq_hw_s *aq_hw); + +/* SMBUS0 set transmitted data (only leftmost byte of data valid) */ +void hw_atl_smb0_tx_data_set(struct aq_hw_s *aq_hw, u32 data); + +/* SMBUS0 provisioning2 command register */ +void hw_atl_smb0_provisioning2_set(struct aq_hw_s *aq_hw, u32 data); + +/* SMBUS0 repeated start detect */ +u32 hw_atl_smb0_repeated_start_detect_get(struct aq_hw_s *aq_hw); + +/* SMBUS0 received data register */ +u32 hw_atl_smb0_rx_data_get(struct aq_hw_s *aq_hw); + /* global */ /* set global microprocessor semaphore */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index 4a6467031b9edb..fce30d90b6cbbb 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -42,6 +42,38 @@ #define HW_ATL_TS_DATA_OUT_SHIFT 0 #define HW_ATL_TS_DATA_OUT_WIDTH 12 +/* SMBUS0 Received Data register */ +#define HW_ATL_SMB0_RECEIVED_DATA_ADR 0x00000748 +/* SMBUS0 Transmitted Data register */ +#define HW_ATL_SMB0_TRANSMITTED_DATA_ADR 0x00000608 + +/* SMBUS0 Global Provisioning 2 register */ +#define HW_ATL_SMB0_PROVISIONING2_ADR 0x00000604 + +/* SMBUS0 Bus Busy Bitfield Definitions */ +#define HW_ATL_SMB0_BUS_BUSY_ADR 0x00000744 +#define HW_ATL_SMB0_BUS_BUSY_MSK 0x00000080 +#define HW_ATL_SMB0_BUS_BUSY_SHIFT 7 +#define HW_ATL_SMB0_BUS_BUSY_WIDTH 1 + +/* SMBUS0 Byte Transfer Complete Bitfield Definitions */ +#define HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_ADR 0x00000744 +#define HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_MSK 0x00000002 +#define HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_SHIFT 1 +#define HW_ATL_SMB0_BYTE_TRANSFER_COMPLETE_WIDTH 1 + +/* SMBUS0 Receive Acknowledge Bitfield Definitions */ +#define HW_ATL_SMB0_RX_ACKNOWLEDGED_ADR 0x00000744 +#define HW_ATL_SMB0_RX_ACKNOWLEDGED_MSK 0x00000100 +#define HW_ATL_SMB0_RX_ACKNOWLEDGED_SHIFT 8 +#define HW_ATL_SMB0_RX_ACKNOWLEDGED_WIDTH 1 + +/* SMBUS0 Repeated Start Detect Bitfield Definitions */ +#define HW_ATL_SMB0_REPEATED_START_DETECT_ADR 0x00000744 +#define HW_ATL_SMB0_REPEATED_START_DETECT_MSK 0x00000004 +#define HW_ATL_SMB0_REPEATED_START_DETECT_SHIFT 2 +#define HW_ATL_SMB0_REPEATED_START_DETECT_WIDTH 1 + /* global microprocessor semaphore definitions * base address: 0x000003a0 * parameter: semaphore {s} | stride size 0x4 | range [0, 15] diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c index 493d6356c8caef..780e70ea1c22c1 100644 --- a/drivers/net/ethernet/arc/emac_rockchip.c +++ b/drivers/net/ethernet/arc/emac_rockchip.c @@ -264,7 +264,7 @@ static void emac_rockchip_remove(struct platform_device *pdev) static struct platform_driver emac_rockchip_driver = { .probe = emac_rockchip_probe, - .remove_new = emac_rockchip_remove, + .remove = emac_rockchip_remove, .driver = { .name = DRV_NAME, .of_match_table = emac_rockchip_dt_ids, diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c index 9586b6894f7e7f..3d4c3d8698e2c6 100644 --- a/drivers/net/ethernet/atheros/ag71xx.c +++ b/drivers/net/ethernet/atheros/ag71xx.c @@ -1598,8 +1598,8 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) int ring_mask, ring_size, done = 0; unsigned int pktlen_mask, offset; struct ag71xx_ring *ring; - struct list_head rx_list; struct sk_buff *skb; + LIST_HEAD(rx_list); ring = &ag->rx_ring; pktlen_mask = ag->dcfg->desc_pktlen_mask; @@ -1610,8 +1610,6 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) netif_dbg(ag, rx_status, ndev, "rx packets, limit=%d, curr=%u, dirty=%u\n", limit, ring->curr, ring->dirty); - INIT_LIST_HEAD(&rx_list); - while (done < limit) { unsigned int i = ring->curr & ring_mask; struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i); @@ -1648,6 +1646,7 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) skb->dev = ndev; skb->ip_summed = CHECKSUM_NONE; + skb->protocol = eth_type_trans(skb, ndev); list_add_tail(&skb->list, &rx_list); next: @@ -1659,8 +1658,6 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) ag71xx_ring_rx_refill(ag); - list_for_each_entry(skb, &rx_list, list) - skb->protocol = eth_type_trans(skb, ndev); netif_receive_skb_list(&rx_list); netif_dbg(ag, rx_status, ndev, "rx finish, curr=%u, dirty=%u, done=%d\n", @@ -1822,10 +1819,9 @@ static int ag71xx_probe(struct platform_device *pdev) } clk_eth = devm_clk_get_enabled(&pdev->dev, "eth"); - if (IS_ERR(clk_eth)) { - netif_err(ag, probe, ndev, "Failed to get eth clk.\n"); - return PTR_ERR(clk_eth); - } + if (IS_ERR(clk_eth)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk_eth), + "Failed to get eth clk."); SET_NETDEV_DEV(ndev, &pdev->dev); @@ -1836,14 +1832,13 @@ static int ag71xx_probe(struct platform_device *pdev) memcpy(ag->fifodata, dcfg->fifodata, sizeof(ag->fifodata)); ag->mac_reset = devm_reset_control_get(&pdev->dev, "mac"); - if (IS_ERR(ag->mac_reset)) { - netif_err(ag, probe, ndev, "missing mac reset\n"); - return PTR_ERR(ag->mac_reset); - } + if (IS_ERR(ag->mac_reset)) + return dev_err_probe(&pdev->dev, PTR_ERR(ag->mac_reset), + "missing mac reset"); - ag->mac_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!ag->mac_base) - return -ENOMEM; + ag->mac_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ag->mac_base)) + return PTR_ERR(ag->mac_base); /* ensure that HW is in manual polling mode before interrupts are * activated. Otherwise ag71xx_interrupt might call napi_schedule @@ -1917,18 +1912,14 @@ static int ag71xx_probe(struct platform_device *pdev) if (err) return err; - platform_set_drvdata(pdev, ndev); - err = ag71xx_phylink_setup(ag); - if (err) { - netif_err(ag, probe, ndev, "failed to setup phylink (%d)\n", err); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to setup phylink"); err = devm_register_netdev(&pdev->dev, ndev); if (err) { netif_err(ag, probe, ndev, "unable to register net device\n"); - platform_set_drvdata(pdev, NULL); return err; } diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 75ca3ddda1f5e0..eeec8bf17cf458 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -72,7 +72,6 @@ config BCMGENET tristate "Broadcom GENET internal MAC support" depends on HAS_IOMEM depends on PTP_1588_CLOCK_OPTIONAL || !ARCH_BCM2835 - select MII select PHYLIB select FIXED_PHY select BCM7XXX_PHY @@ -195,7 +194,6 @@ config SYSTEMPORT tristate "Broadcom SYSTEMPORT internal MAC support" depends on HAS_IOMEM depends on NET_DSA || !NET_DSA - select MII select PHYLIB select FIXED_PHY select DIMLIB @@ -260,7 +258,6 @@ config BCMASP depends on ARCH_BRCMSTB || COMPILE_TEST default ARCH_BRCMSTB depends on OF - select MII select PHYLIB select MDIO_BCM_UNIMAC help diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c index 297c2682a9cf97..a68fab1b05f0c6 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c @@ -1500,7 +1500,7 @@ static SIMPLE_DEV_PM_OPS(bcmasp_pm_ops, static struct platform_driver bcmasp_driver = { .probe = bcmasp_probe, - .remove_new = bcmasp_remove, + .remove = bcmasp_remove, .shutdown = bcmasp_shutdown, .driver = { .name = "brcm,asp-v2", diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c index ca163c8e372972..9da5ae29a1050b 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c @@ -101,14 +101,14 @@ static int bcmasp_get_sset_count(struct net_device *dev, int string_set) static void bcmasp_get_strings(struct net_device *dev, u32 stringset, u8 *data) { + const char *str; unsigned int i; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < BCMASP_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, - bcmasp_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + str = bcmasp_gstrings_stats[i].stat_string; + ethtool_puts(&data, str); } break; default: @@ -496,4 +496,5 @@ const struct ethtool_ops bcmasp_ethtool_ops = { .get_strings = bcmasp_get_strings, .get_ethtool_stats = bcmasp_get_ethtool_stats, .get_sset_count = bcmasp_get_sset_count, + .get_ts_info = ethtool_op_get_ts_info, }; diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index 9ea16ef4139d35..cfd50efbdbc0c4 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -365,6 +365,9 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev) intf->tx_spb_index = spb_index; intf->tx_spb_dma_valid = valid; + + skb_tx_timestamp(skb); + bcmasp_intf_tx_write(intf, intf->tx_spb_dma_valid); if (tx_spb_ring_full(intf, MAX_SKB_FRAGS + 1)) diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c index 72df1bb1017288..203e8d0dd04b82 100644 --- a/drivers/net/ethernet/broadcom/bcm4908_enet.c +++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c @@ -789,7 +789,7 @@ static struct platform_driver bcm4908_enet_driver = { .of_match_table = bcm4908_enet_of_match, }, .probe = bcm4908_enet_probe, - .remove_new = bcm4908_enet_remove, + .remove = bcm4908_enet_remove, }; module_platform_driver(bcm4908_enet_driver); diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 3c0e3b9828be9f..65e3a0656a4c56 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -1339,14 +1339,14 @@ static int bcm_enet_get_sset_count(struct net_device *netdev, static void bcm_enet_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { + const char *str; int i; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < BCM_ENET_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, - bcm_enet_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + str = bcm_enet_gstrings_stats[i].stat_string; + ethtool_puts(&data, str); } break; } @@ -1936,7 +1936,7 @@ static void bcm_enet_remove(struct platform_device *pdev) static struct platform_driver bcm63xx_enet_driver = { .probe = bcm_enet_probe, - .remove_new = bcm_enet_remove, + .remove = bcm_enet_remove, .driver = { .name = "bcm63xx_enet", }, @@ -2503,14 +2503,14 @@ static const struct bcm_enet_stats bcm_enetsw_gstrings_stats[] = { static void bcm_enetsw_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { + const char *str; int i; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, - bcm_enetsw_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + str = bcm_enetsw_gstrings_stats[i].stat_string; + ethtool_puts(&data, str); } break; } @@ -2755,7 +2755,7 @@ static void bcm_enetsw_remove(struct platform_device *pdev) static struct platform_driver bcm63xx_enetsw_driver = { .probe = bcm_enetsw_probe, - .remove_new = bcm_enetsw_remove, + .remove = bcm_enetsw_remove, .driver = { .name = "bcm63xx_enetsw", }, diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 0a68b526e4a821..42672c63f10863 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -27,30 +27,6 @@ #include "bcmsysport.h" -/* I/O accessors register helpers */ -#define BCM_SYSPORT_IO_MACRO(name, offset) \ -static inline u32 name##_readl(struct bcm_sysport_priv *priv, u32 off) \ -{ \ - u32 reg = readl_relaxed(priv->base + offset + off); \ - return reg; \ -} \ -static inline void name##_writel(struct bcm_sysport_priv *priv, \ - u32 val, u32 off) \ -{ \ - writel_relaxed(val, priv->base + offset + off); \ -} \ - -BCM_SYSPORT_IO_MACRO(intrl2_0, SYS_PORT_INTRL2_0_OFFSET); -BCM_SYSPORT_IO_MACRO(intrl2_1, SYS_PORT_INTRL2_1_OFFSET); -BCM_SYSPORT_IO_MACRO(umac, SYS_PORT_UMAC_OFFSET); -BCM_SYSPORT_IO_MACRO(gib, SYS_PORT_GIB_OFFSET); -BCM_SYSPORT_IO_MACRO(tdma, SYS_PORT_TDMA_OFFSET); -BCM_SYSPORT_IO_MACRO(rxchk, SYS_PORT_RXCHK_OFFSET); -BCM_SYSPORT_IO_MACRO(txchk, SYS_PORT_TXCHK_OFFSET); -BCM_SYSPORT_IO_MACRO(rbuf, SYS_PORT_RBUF_OFFSET); -BCM_SYSPORT_IO_MACRO(tbuf, SYS_PORT_TBUF_OFFSET); -BCM_SYSPORT_IO_MACRO(topctrl, SYS_PORT_TOPCTRL_OFFSET); - /* On SYSTEMPORT Lite, any register after RDMA_STATUS has the exact * same layout, except it has been moved by 4 bytes up, *sigh* */ @@ -370,32 +346,22 @@ static void bcm_sysport_get_strings(struct net_device *dev, { struct bcm_sysport_priv *priv = netdev_priv(dev); const struct bcm_sysport_stats *s; - char buf[128]; - int i, j; + int i; switch (stringset) { case ETH_SS_STATS: - for (i = 0, j = 0; i < BCM_SYSPORT_STATS_LEN; i++) { + for (i = 0; i < BCM_SYSPORT_STATS_LEN; i++) { s = &bcm_sysport_gstrings_stats[i]; if (priv->is_lite && !bcm_sysport_lite_stat_valid(s->type)) continue; - memcpy(data + j * ETH_GSTRING_LEN, s->stat_string, - ETH_GSTRING_LEN); - j++; + ethtool_puts(&data, s->stat_string); } for (i = 0; i < dev->num_tx_queues; i++) { - snprintf(buf, sizeof(buf), "txq%d_packets", i); - memcpy(data + j * ETH_GSTRING_LEN, buf, - ETH_GSTRING_LEN); - j++; - - snprintf(buf, sizeof(buf), "txq%d_bytes", i); - memcpy(data + j * ETH_GSTRING_LEN, buf, - ETH_GSTRING_LEN); - j++; + ethtool_sprintf(&data, "txq%d_packets", i); + ethtool_sprintf(&data, "txq%d_bytes", i); } break; default: @@ -1053,7 +1019,7 @@ static int bcm_sysport_poll(struct napi_struct *napi, int budget) if (priv->dim.use_dim) { dim_update_sample(priv->dim.event_ctr, priv->dim.packets, priv->dim.bytes, &dim_sample); - net_dim(&priv->dim.dim, dim_sample); + net_dim(&priv->dim.dim, &dim_sample); } return work_done; @@ -2900,7 +2866,7 @@ static SIMPLE_DEV_PM_OPS(bcm_sysport_pm_ops, static struct platform_driver bcm_sysport_driver = { .probe = bcm_sysport_probe, - .remove_new = bcm_sysport_remove, + .remove = bcm_sysport_remove, .driver = { .name = "brcm-systemport", .of_match_table = bcm_sysport_of_match, diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index 335cf6631db592..a34296f989f12a 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -773,4 +773,27 @@ struct bcm_sysport_priv { struct bcm_sysport_tx_ring *ring_map[DSA_MAX_PORTS * 8]; }; + +/* I/O accessors register helpers */ +#define BCM_SYSPORT_IO_MACRO(name, offset) \ +static inline u32 name##_readl(struct bcm_sysport_priv *priv, u32 off) \ +{ \ + u32 reg = readl_relaxed(priv->base + (offset) + off); \ + return reg; \ +} \ +static inline void name##_writel(struct bcm_sysport_priv *priv, \ + u32 val, u32 off) \ +{ \ + writel_relaxed(val, priv->base + (offset) + off); \ +} \ + +BCM_SYSPORT_IO_MACRO(intrl2_0, SYS_PORT_INTRL2_0_OFFSET); +BCM_SYSPORT_IO_MACRO(intrl2_1, SYS_PORT_INTRL2_1_OFFSET); +BCM_SYSPORT_IO_MACRO(umac, SYS_PORT_UMAC_OFFSET); +BCM_SYSPORT_IO_MACRO(gib, SYS_PORT_GIB_OFFSET); +BCM_SYSPORT_IO_MACRO(tdma, SYS_PORT_TDMA_OFFSET); +BCM_SYSPORT_IO_MACRO(rxchk, SYS_PORT_RXCHK_OFFSET); +BCM_SYSPORT_IO_MACRO(rbuf, SYS_PORT_RBUF_OFFSET); +BCM_SYSPORT_IO_MACRO(topctrl, SYS_PORT_TOPCTRL_OFFSET); + #endif /* __BCM_SYSPORT_H */ diff --git a/drivers/net/ethernet/broadcom/bgmac-platform.c b/drivers/net/ethernet/broadcom/bgmac-platform.c index 77425c7a32dbf8..4e266ce41180b3 100644 --- a/drivers/net/ethernet/broadcom/bgmac-platform.c +++ b/drivers/net/ethernet/broadcom/bgmac-platform.c @@ -171,6 +171,7 @@ static int platform_phy_connect(struct bgmac *bgmac) static int bgmac_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + struct device_node *phy_node; struct bgmac *bgmac; struct resource *regs; int ret; @@ -236,7 +237,9 @@ static int bgmac_probe(struct platform_device *pdev) bgmac->cco_ctl_maskset = platform_bgmac_cco_ctl_maskset; bgmac->get_bus_clock = platform_bgmac_get_bus_clock; bgmac->cmn_maskset32 = platform_bgmac_cmn_maskset32; - if (of_parse_phandle(np, "phy-handle", 0)) { + phy_node = of_parse_phandle(np, "phy-handle", 0); + if (phy_node) { + of_node_put(phy_node); bgmac->phy_connect = platform_phy_connect; } else { bgmac->phy_connect = bgmac_phy_connect_direct; @@ -294,7 +297,7 @@ static struct platform_driver bgmac_enet_driver = { .pm = BGMAC_PM_OPS }, .probe = bgmac_probe, - .remove_new = bgmac_remove, + .remove = bgmac_remove, }; module_platform_driver(bgmac_enet_driver); diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 6ffdc42294074f..a461ec612e9523 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1367,8 +1367,7 @@ static void bgmac_get_strings(struct net_device *dev, u32 stringset, return; for (i = 0; i < BGMAC_STATS_LEN; i++) - strscpy(data + i * ETH_GSTRING_LEN, - bgmac_get_strings_stats[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, bgmac_get_strings_stats[i].name); } static void bgmac_get_ethtool_stats(struct net_device *dev, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index adf7b6b94941c2..44199855ebfb96 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -39,34 +39,34 @@ static const struct { int size; char string[ETH_GSTRING_LEN]; } bnx2x_q_stats_arr[] = { -/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%s]: rx_bytes" }, +/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%d]: rx_bytes" }, { Q_STATS_OFFSET32(total_unicast_packets_received_hi), - 8, "[%s]: rx_ucast_packets" }, + 8, "[%d]: rx_ucast_packets" }, { Q_STATS_OFFSET32(total_multicast_packets_received_hi), - 8, "[%s]: rx_mcast_packets" }, + 8, "[%d]: rx_mcast_packets" }, { Q_STATS_OFFSET32(total_broadcast_packets_received_hi), - 8, "[%s]: rx_bcast_packets" }, - { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%s]: rx_discards" }, + 8, "[%d]: rx_bcast_packets" }, + { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%d]: rx_discards" }, { Q_STATS_OFFSET32(rx_err_discard_pkt), - 4, "[%s]: rx_phy_ip_err_discards"}, + 4, "[%d]: rx_phy_ip_err_discards"}, { Q_STATS_OFFSET32(rx_skb_alloc_failed), - 4, "[%s]: rx_skb_alloc_discard" }, - { Q_STATS_OFFSET32(hw_csum_err), 4, "[%s]: rx_csum_offload_errors" }, - { Q_STATS_OFFSET32(driver_xoff), 4, "[%s]: tx_exhaustion_events" }, - { Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%s]: tx_bytes" }, + 4, "[%d]: rx_skb_alloc_discard" }, + { Q_STATS_OFFSET32(hw_csum_err), 4, "[%d]: rx_csum_offload_errors" }, + { Q_STATS_OFFSET32(driver_xoff), 4, "[%d]: tx_exhaustion_events" }, + { Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%d]: tx_bytes" }, /* 10 */{ Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi), - 8, "[%s]: tx_ucast_packets" }, + 8, "[%d]: tx_ucast_packets" }, { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi), - 8, "[%s]: tx_mcast_packets" }, + 8, "[%d]: tx_mcast_packets" }, { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi), - 8, "[%s]: tx_bcast_packets" }, + 8, "[%d]: tx_bcast_packets" }, { Q_STATS_OFFSET32(total_tpa_aggregations_hi), - 8, "[%s]: tpa_aggregations" }, + 8, "[%d]: tpa_aggregations" }, { Q_STATS_OFFSET32(total_tpa_aggregated_frames_hi), - 8, "[%s]: tpa_aggregated_frames"}, - { Q_STATS_OFFSET32(total_tpa_bytes_hi), 8, "[%s]: tpa_bytes"}, + 8, "[%d]: tpa_aggregated_frames"}, + { Q_STATS_OFFSET32(total_tpa_bytes_hi), 8, "[%d]: tpa_bytes"}, { Q_STATS_OFFSET32(driver_filtered_tx_pkt), - 4, "[%s]: driver_filtered_tx_pkt" } + 4, "[%d]: driver_filtered_tx_pkt" } }; #define BNX2X_NUM_Q_STATS ARRAY_SIZE(bnx2x_q_stats_arr) @@ -3184,49 +3184,43 @@ static u32 bnx2x_get_private_flags(struct net_device *dev) static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) { struct bnx2x *bp = netdev_priv(dev); - int i, j, k, start; - char queue_name[MAX_QUEUE_NAME_LEN+1]; + const char *str; + int i, j, start; switch (stringset) { case ETH_SS_STATS: - k = 0; if (is_multi(bp)) { for_each_eth_queue(bp, i) { - memset(queue_name, 0, sizeof(queue_name)); - snprintf(queue_name, sizeof(queue_name), - "%d", i); - for (j = 0; j < BNX2X_NUM_Q_STATS; j++) - snprintf(buf + (k + j)*ETH_GSTRING_LEN, - ETH_GSTRING_LEN, - bnx2x_q_stats_arr[j].string, - queue_name); - k += BNX2X_NUM_Q_STATS; + for (j = 0; j < BNX2X_NUM_Q_STATS; j++) { + str = bnx2x_q_stats_arr[j].string; + ethtool_sprintf(&buf, str, i); + } } } - for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { + for (i = 0; i < BNX2X_NUM_STATS; i++) { if (HIDE_PORT_STAT(bp) && IS_PORT_STAT(i)) continue; - strcpy(buf + (k + j)*ETH_GSTRING_LEN, - bnx2x_stats_arr[i].string); - j++; + ethtool_puts(&buf, bnx2x_stats_arr[i].string); } break; case ETH_SS_TEST: + if (IS_VF(bp)) + break; /* First 4 tests cannot be done in MF mode */ if (!IS_MF(bp)) start = 0; else start = 4; - memcpy(buf, bnx2x_tests_str_arr + start, - ETH_GSTRING_LEN * BNX2X_NUM_TESTS(bp)); + for (i = start; i < BNX2X_NUM_TESTS_SF; i++) + ethtool_puts(&buf, bnx2x_tests_str_arr[i]); break; case ETH_SS_PRIV_FLAGS: - memcpy(buf, bnx2x_private_arr, - ETH_GSTRING_LEN * BNX2X_PRI_FLAG_LEN); + for (i = 0; i < BNX2X_PRI_FLAG_LEN; i++) + ethtool_puts(&buf, bnx2x_private_arr[i]); break; } } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 99d025b69079a8..b86f980fa7ea60 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -245,6 +245,21 @@ static const u16 bnxt_async_events_arr[] = { ASYNC_EVENT_CMPL_EVENT_ID_PPS_TIMESTAMP, ASYNC_EVENT_CMPL_EVENT_ID_ERROR_REPORT, ASYNC_EVENT_CMPL_EVENT_ID_PHC_UPDATE, + ASYNC_EVENT_CMPL_EVENT_ID_DBG_BUF_PRODUCER, +}; + +const u16 bnxt_bstore_to_trace[] = { + [BNXT_CTX_SRT] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT_TRACE, + [BNXT_CTX_SRT2] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT2_TRACE, + [BNXT_CTX_CRT] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT_TRACE, + [BNXT_CTX_CRT2] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT2_TRACE, + [BNXT_CTX_RIGP0] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP0_TRACE, + [BNXT_CTX_L2HWRM] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_L2_HWRM_TRACE, + [BNXT_CTX_REHWRM] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ROCE_HWRM_TRACE, + [BNXT_CTX_CA0] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA0_TRACE, + [BNXT_CTX_CA1] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA1_TRACE, + [BNXT_CTX_CA2] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA2_TRACE, + [BNXT_CTX_RIGP1] = DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP1_TRACE, }; static struct workqueue_struct *bnxt_pf_wq; @@ -864,6 +879,11 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget) bnapi->events &= ~BNXT_TX_CMP_EVENT; } +static bool bnxt_separate_head_pool(void) +{ + return PAGE_SIZE > BNXT_RX_PAGE_SIZE; +} + static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, struct bnxt_rx_ring_info *rxr, unsigned int *offset, @@ -886,27 +906,19 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, } static inline u8 *__bnxt_alloc_rx_frag(struct bnxt *bp, dma_addr_t *mapping, + struct bnxt_rx_ring_info *rxr, gfp_t gfp) { - u8 *data; - struct pci_dev *pdev = bp->pdev; + unsigned int offset; + struct page *page; - if (gfp == GFP_ATOMIC) - data = napi_alloc_frag(bp->rx_buf_size); - else - data = netdev_alloc_frag(bp->rx_buf_size); - if (!data) + page = page_pool_alloc_frag(rxr->head_pool, &offset, + bp->rx_buf_size, gfp); + if (!page) return NULL; - *mapping = dma_map_single_attrs(&pdev->dev, data + bp->rx_dma_offset, - bp->rx_buf_use_size, bp->rx_dir, - DMA_ATTR_WEAK_ORDERING); - - if (dma_mapping_error(&pdev->dev, *mapping)) { - skb_free_frag(data); - data = NULL; - } - return data; + *mapping = page_pool_get_dma_addr(page) + bp->rx_dma_offset + offset; + return page_address(page) + offset; } int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, @@ -928,7 +940,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, rx_buf->data = page; rx_buf->data_ptr = page_address(page) + offset + bp->rx_offset; } else { - u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, gfp); + u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, rxr, gfp); if (!data) return -ENOMEM; @@ -1179,13 +1191,14 @@ static struct sk_buff *bnxt_rx_skb(struct bnxt *bp, } skb = napi_build_skb(data, bp->rx_buf_size); - dma_unmap_single_attrs(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, - bp->rx_dir, DMA_ATTR_WEAK_ORDERING); + dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, + bp->rx_dir); if (!skb) { - skb_free_frag(data); + page_pool_free_va(rxr->head_pool, data, true); return NULL; } + skb_mark_for_recycle(skb); skb_reserve(skb, bp->rx_offset); skb_put(skb, offset_and_len & 0xffff); return skb; @@ -1518,7 +1531,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, if (TPA_START_IS_IPV6(tpa_start1)) tpa_info->gso_type = SKB_GSO_TCPV6; /* RSS profiles 1 and 3 with extract code 0 for inner 4-tuple */ - else if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP && + else if (!BNXT_CHIP_P4_PLUS(bp) && TPA_START_HASH_TYPE(tpa_start) == 3) tpa_info->gso_type = SKB_GSO_TCPV6; tpa_info->rss_hash = @@ -1840,7 +1853,8 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, u8 *new_data; dma_addr_t new_mapping; - new_data = __bnxt_alloc_rx_frag(bp, &new_mapping, GFP_ATOMIC); + new_data = __bnxt_alloc_rx_frag(bp, &new_mapping, rxr, + GFP_ATOMIC); if (!new_data) { bnxt_abort_tpa(cpr, idx, agg_bufs); cpr->sw_stats->rx.rx_oom_discards += 1; @@ -1852,16 +1866,16 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, tpa_info->mapping = new_mapping; skb = napi_build_skb(data, bp->rx_buf_size); - dma_unmap_single_attrs(&bp->pdev->dev, mapping, - bp->rx_buf_use_size, bp->rx_dir, - DMA_ATTR_WEAK_ORDERING); + dma_sync_single_for_cpu(&bp->pdev->dev, mapping, + bp->rx_buf_use_size, bp->rx_dir); if (!skb) { - skb_free_frag(data); + page_pool_free_va(rxr->head_pool, data, true); bnxt_abort_tpa(cpr, idx, agg_bufs); cpr->sw_stats->rx.rx_oom_discards += 1; return NULL; } + skb_mark_for_recycle(skb); skb_reserve(skb, bp->rx_offset); skb_put(skb, len); } @@ -2212,15 +2226,13 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, if (cmp_type == CMP_TYPE_RX_L2_V3_CMP) { type = bnxt_rss_ext_op(bp, rxcmp); } else { - u32 hash_type = RX_CMP_HASH_TYPE(rxcmp); + u32 itypes = RX_CMP_ITYPES(rxcmp); - /* RSS profiles 1 and 3 with extract code 0 for inner - * 4-tuple - */ - if (hash_type != 1 && hash_type != 3) - type = PKT_HASH_TYPE_L3; - else + if (itypes == RX_CMP_FLAGS_ITYPE_TCP || + itypes == RX_CMP_FLAGS_ITYPE_UDP) type = PKT_HASH_TYPE_L4; + else + type = PKT_HASH_TYPE_L3; } skb_set_hash(skb, le32_to_cpu(rxcmp->rx_cmp_rss_hash), type); } @@ -2254,11 +2266,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, if (!bnxt_get_rx_ts_p5(bp, &ts, cmpl_ts)) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; - unsigned long flags; - spin_lock_irqsave(&ptp->ptp_lock, flags); - ns = timecounter_cyc2time(&ptp->tc, ts); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + ns = bnxt_timecounter_cyc2time(ptp, ts); memset(skb_hwtstamps(skb), 0, sizeof(*skb_hwtstamps(skb))); skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns); @@ -2465,6 +2474,59 @@ static bool bnxt_auto_speed_updated(struct bnxt_link_info *link_info) return false; } +bool bnxt_bs_trace_avail(struct bnxt *bp, u16 type) +{ + u32 flags = bp->ctx->ctx_arr[type].flags; + + return (flags & BNXT_CTX_MEM_TYPE_VALID) && + ((flags & BNXT_CTX_MEM_FW_TRACE) || + (flags & BNXT_CTX_MEM_FW_BIN_TRACE)); +} + +static void bnxt_bs_trace_init(struct bnxt *bp, struct bnxt_ctx_mem_type *ctxm) +{ + u32 mem_size, pages, rem_bytes, magic_byte_offset; + u16 trace_type = bnxt_bstore_to_trace[ctxm->type]; + struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info; + struct bnxt_ring_mem_info *rmem, *rmem_pg_tbl; + struct bnxt_bs_trace_info *bs_trace; + int last_pg; + + if (ctxm->instance_bmap && ctxm->instance_bmap > 1) + return; + + mem_size = ctxm->max_entries * ctxm->entry_size; + rem_bytes = mem_size % BNXT_PAGE_SIZE; + pages = DIV_ROUND_UP(mem_size, BNXT_PAGE_SIZE); + + last_pg = (pages - 1) & (MAX_CTX_PAGES - 1); + magic_byte_offset = (rem_bytes ? rem_bytes : BNXT_PAGE_SIZE) - 1; + + rmem = &ctx_pg[0].ring_mem; + bs_trace = &bp->bs_trace[trace_type]; + bs_trace->ctx_type = ctxm->type; + bs_trace->trace_type = trace_type; + if (pages > MAX_CTX_PAGES) { + int last_pg_dir = rmem->nr_pages - 1; + + rmem_pg_tbl = &ctx_pg[0].ctx_pg_tbl[last_pg_dir]->ring_mem; + bs_trace->magic_byte = rmem_pg_tbl->pg_arr[last_pg]; + } else { + bs_trace->magic_byte = rmem->pg_arr[last_pg]; + } + bs_trace->magic_byte += magic_byte_offset; + *bs_trace->magic_byte = BNXT_TRACE_BUF_MAGIC_BYTE; +} + +#define BNXT_EVENT_BUF_PRODUCER_TYPE(data1) \ + (((data1) & ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_MASK) >>\ + ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SFT) + +#define BNXT_EVENT_BUF_PRODUCER_OFFSET(data2) \ + (((data2) & \ + ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_MASK) >>\ + ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_SFT) + #define BNXT_EVENT_THERMAL_CURRENT_TEMP(data2) \ ((data2) & \ ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA2_CURRENT_TEMP_MASK) @@ -2764,12 +2826,12 @@ static int bnxt_async_event_process(struct bnxt *bp, if (!ptp) goto async_event_process_exit; - spin_lock_irqsave(&ptp->ptp_lock, flags); bnxt_ptp_update_current_time(bp); ns = (((u64)BNXT_EVENT_PHC_RTC_UPDATE(data1) << BNXT_PHC_BITS) | ptp->current_time); + write_seqlock_irqsave(&ptp->ptp_lock, flags); bnxt_ptp_rtc_timecounter_init(ptp, ns); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + write_sequnlock_irqrestore(&ptp->ptp_lock, flags); } break; } @@ -2781,6 +2843,13 @@ static int bnxt_async_event_process(struct bnxt *bp, hwrm_update_token(bp, seq_id, BNXT_HWRM_DEFERRED); goto async_event_process_exit; } + case ASYNC_EVENT_CMPL_EVENT_ID_DBG_BUF_PRODUCER: { + u16 type = (u16)BNXT_EVENT_BUF_PRODUCER_TYPE(data1); + u32 offset = BNXT_EVENT_BUF_PRODUCER_OFFSET(data2); + + bnxt_bs_trace_check_wrap(&bp->bs_trace[type], offset); + goto async_event_process_exit; + } default: goto async_event_process_exit; } @@ -3102,7 +3171,7 @@ static int bnxt_poll(struct napi_struct *napi, int budget) cpr->rx_packets, cpr->rx_bytes, &dim_sample); - net_dim(&cpr->dim, dim_sample); + net_dim(&cpr->dim, &dim_sample); } return work_done; } @@ -3233,7 +3302,7 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) cpr_rx->rx_packets, cpr_rx->rx_bytes, &dim_sample); - net_dim(&cpr->dim, dim_sample); + net_dim(&cpr->dim, &dim_sample); } return work_done; } @@ -3311,28 +3380,22 @@ static void bnxt_free_tx_skbs(struct bnxt *bp) static void bnxt_free_one_rx_ring(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) { - struct pci_dev *pdev = bp->pdev; int i, max_idx; max_idx = bp->rx_nr_pages * RX_DESC_CNT; for (i = 0; i < max_idx; i++) { struct bnxt_sw_rx_bd *rx_buf = &rxr->rx_buf_ring[i]; - dma_addr_t mapping = rx_buf->mapping; void *data = rx_buf->data; if (!data) continue; rx_buf->data = NULL; - if (BNXT_RX_PAGE_MODE(bp)) { + if (BNXT_RX_PAGE_MODE(bp)) page_pool_recycle_direct(rxr->page_pool, data); - } else { - dma_unmap_single_attrs(&pdev->dev, mapping, - bp->rx_buf_use_size, bp->rx_dir, - DMA_ATTR_WEAK_ORDERING); - skb_free_frag(data); - } + else + page_pool_free_va(rxr->head_pool, data, true); } } @@ -3356,16 +3419,11 @@ static void bnxt_free_one_rx_agg_ring(struct bnxt *bp, struct bnxt_rx_ring_info } } -static void bnxt_free_one_rx_ring_skbs(struct bnxt *bp, int ring_nr) +static void bnxt_free_one_tpa_info_data(struct bnxt *bp, + struct bnxt_rx_ring_info *rxr) { - struct bnxt_rx_ring_info *rxr = &bp->rx_ring[ring_nr]; - struct pci_dev *pdev = bp->pdev; - struct bnxt_tpa_idx_map *map; int i; - if (!rxr->rx_tpa) - goto skip_rx_tpa_free; - for (i = 0; i < bp->max_tpa; i++) { struct bnxt_tpa_info *tpa_info = &rxr->rx_tpa[i]; u8 *data = tpa_info->data; @@ -3373,14 +3431,20 @@ static void bnxt_free_one_rx_ring_skbs(struct bnxt *bp, int ring_nr) if (!data) continue; - dma_unmap_single_attrs(&pdev->dev, tpa_info->mapping, - bp->rx_buf_use_size, bp->rx_dir, - DMA_ATTR_WEAK_ORDERING); - tpa_info->data = NULL; - - skb_free_frag(data); + page_pool_free_va(rxr->head_pool, data, false); } +} + +static void bnxt_free_one_rx_ring_skbs(struct bnxt *bp, + struct bnxt_rx_ring_info *rxr) +{ + struct bnxt_tpa_idx_map *map; + + if (!rxr->rx_tpa) + goto skip_rx_tpa_free; + + bnxt_free_one_tpa_info_data(bp, rxr); skip_rx_tpa_free: if (!rxr->rx_buf_ring) @@ -3408,7 +3472,7 @@ static void bnxt_free_rx_skbs(struct bnxt *bp) return; for (i = 0; i < bp->rx_nr_rings; i++) - bnxt_free_one_rx_ring_skbs(bp, i); + bnxt_free_one_rx_ring_skbs(bp, &bp->rx_ring[i]); } static void bnxt_free_skbs(struct bnxt *bp) @@ -3434,6 +3498,35 @@ static void bnxt_init_ctx_mem(struct bnxt_ctx_mem_type *ctxm, void *p, int len) *(p2 + i + offset) = init_val; } +static size_t __bnxt_copy_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem, + void *buf, size_t offset, size_t head, + size_t tail) +{ + int i, head_page, start_idx, source_offset; + size_t len, rem_len, total_len, max_bytes; + + head_page = head / rmem->page_size; + source_offset = head % rmem->page_size; + total_len = (tail - head) & MAX_CTX_BYTES_MASK; + if (!total_len) + total_len = MAX_CTX_BYTES; + start_idx = head_page % MAX_CTX_PAGES; + max_bytes = (rmem->nr_pages - start_idx) * rmem->page_size - + source_offset; + total_len = min(total_len, max_bytes); + rem_len = total_len; + + for (i = start_idx; rem_len; i++, source_offset = 0) { + len = min((size_t)(rmem->page_size - source_offset), rem_len); + if (buf) + memcpy(buf + offset, rmem->pg_arr[i] + source_offset, + len); + offset += len; + rem_len -= len; + } + return total_len; +} + static void bnxt_free_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) { struct pci_dev *pdev = bp->pdev; @@ -3520,29 +3613,64 @@ static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) return 0; } +static void bnxt_free_one_tpa_info(struct bnxt *bp, + struct bnxt_rx_ring_info *rxr) +{ + int i; + + kfree(rxr->rx_tpa_idx_map); + rxr->rx_tpa_idx_map = NULL; + if (rxr->rx_tpa) { + for (i = 0; i < bp->max_tpa; i++) { + kfree(rxr->rx_tpa[i].agg_arr); + rxr->rx_tpa[i].agg_arr = NULL; + } + } + kfree(rxr->rx_tpa); + rxr->rx_tpa = NULL; +} + static void bnxt_free_tpa_info(struct bnxt *bp) { - int i, j; + int i; for (i = 0; i < bp->rx_nr_rings; i++) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; - kfree(rxr->rx_tpa_idx_map); - rxr->rx_tpa_idx_map = NULL; - if (rxr->rx_tpa) { - for (j = 0; j < bp->max_tpa; j++) { - kfree(rxr->rx_tpa[j].agg_arr); - rxr->rx_tpa[j].agg_arr = NULL; - } - } - kfree(rxr->rx_tpa); - rxr->rx_tpa = NULL; + bnxt_free_one_tpa_info(bp, rxr); } } +static int bnxt_alloc_one_tpa_info(struct bnxt *bp, + struct bnxt_rx_ring_info *rxr) +{ + struct rx_agg_cmp *agg; + int i; + + rxr->rx_tpa = kcalloc(bp->max_tpa, sizeof(struct bnxt_tpa_info), + GFP_KERNEL); + if (!rxr->rx_tpa) + return -ENOMEM; + + if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) + return 0; + for (i = 0; i < bp->max_tpa; i++) { + agg = kcalloc(MAX_SKB_FRAGS, sizeof(*agg), GFP_KERNEL); + if (!agg) + return -ENOMEM; + rxr->rx_tpa[i].agg_arr = agg; + } + rxr->rx_tpa_idx_map = kzalloc(sizeof(*rxr->rx_tpa_idx_map), + GFP_KERNEL); + if (!rxr->rx_tpa_idx_map) + return -ENOMEM; + + return 0; +} + static int bnxt_alloc_tpa_info(struct bnxt *bp) { - int i, j; + int i, rc; bp->max_tpa = MAX_TPA; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { @@ -3553,25 +3681,10 @@ static int bnxt_alloc_tpa_info(struct bnxt *bp) for (i = 0; i < bp->rx_nr_rings; i++) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i]; - struct rx_agg_cmp *agg; - rxr->rx_tpa = kcalloc(bp->max_tpa, sizeof(struct bnxt_tpa_info), - GFP_KERNEL); - if (!rxr->rx_tpa) - return -ENOMEM; - - if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) - continue; - for (j = 0; j < bp->max_tpa; j++) { - agg = kcalloc(MAX_SKB_FRAGS, sizeof(*agg), GFP_KERNEL); - if (!agg) - return -ENOMEM; - rxr->rx_tpa[j].agg_arr = agg; - } - rxr->rx_tpa_idx_map = kzalloc(sizeof(*rxr->rx_tpa_idx_map), - GFP_KERNEL); - if (!rxr->rx_tpa_idx_map) - return -ENOMEM; + rc = bnxt_alloc_one_tpa_info(bp, rxr); + if (rc) + return rc; } return 0; } @@ -3595,7 +3708,9 @@ static void bnxt_free_rx_rings(struct bnxt *bp) xdp_rxq_info_unreg(&rxr->xdp_rxq); page_pool_destroy(rxr->page_pool); - rxr->page_pool = NULL; + if (bnxt_separate_head_pool()) + page_pool_destroy(rxr->head_pool); + rxr->page_pool = rxr->head_pool = NULL; kfree(rxr->rx_agg_bmap); rxr->rx_agg_bmap = NULL; @@ -3613,6 +3728,7 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp, int numa_node) { struct page_pool_params pp = { 0 }; + struct page_pool *pool; pp.pool_size = bp->rx_agg_ring_size; if (BNXT_RX_PAGE_MODE(bp)) @@ -3625,13 +3741,37 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp, pp.max_len = PAGE_SIZE; pp.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; - rxr->page_pool = page_pool_create(&pp); - if (IS_ERR(rxr->page_pool)) { - int err = PTR_ERR(rxr->page_pool); + pool = page_pool_create(&pp); + if (IS_ERR(pool)) + return PTR_ERR(pool); + rxr->page_pool = pool; - rxr->page_pool = NULL; - return err; + if (bnxt_separate_head_pool()) { + pp.pool_size = max(bp->rx_ring_size, 1024); + pool = page_pool_create(&pp); + if (IS_ERR(pool)) + goto err_destroy_pp; } + rxr->head_pool = pool; + + return 0; + +err_destroy_pp: + page_pool_destroy(rxr->page_pool); + rxr->page_pool = NULL; + return PTR_ERR(pool); +} + +static int bnxt_alloc_rx_agg_bmap(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) +{ + u16 mem_size; + + rxr->rx_agg_bmap_size = bp->rx_agg_ring_mask + 1; + mem_size = rxr->rx_agg_bmap_size / 8; + rxr->rx_agg_bmap = kzalloc(mem_size, GFP_KERNEL); + if (!rxr->rx_agg_bmap) + return -ENOMEM; + return 0; } @@ -3679,19 +3819,15 @@ static int bnxt_alloc_rx_rings(struct bnxt *bp) ring->grp_idx = i; if (agg_rings) { - u16 mem_size; - ring = &rxr->rx_agg_ring_struct; rc = bnxt_alloc_ring(bp, &ring->ring_mem); if (rc) return rc; ring->grp_idx = i; - rxr->rx_agg_bmap_size = bp->rx_agg_ring_mask + 1; - mem_size = rxr->rx_agg_bmap_size / 8; - rxr->rx_agg_bmap = kzalloc(mem_size, GFP_KERNEL); - if (!rxr->rx_agg_bmap) - return -ENOMEM; + rc = bnxt_alloc_rx_agg_bmap(bp, rxr); + if (rc) + return rc; } } if (bp->flags & BNXT_FLAG_TPA) @@ -4166,10 +4302,31 @@ static void bnxt_alloc_one_rx_ring_page(struct bnxt *bp, rxr->rx_agg_prod = prod; } +static int bnxt_alloc_one_tpa_info_data(struct bnxt *bp, + struct bnxt_rx_ring_info *rxr) +{ + dma_addr_t mapping; + u8 *data; + int i; + + for (i = 0; i < bp->max_tpa; i++) { + data = __bnxt_alloc_rx_frag(bp, &mapping, rxr, + GFP_KERNEL); + if (!data) + return -ENOMEM; + + rxr->rx_tpa[i].data = data; + rxr->rx_tpa[i].data_ptr = data + bp->rx_offset; + rxr->rx_tpa[i].mapping = mapping; + } + + return 0; +} + static int bnxt_alloc_one_rx_ring(struct bnxt *bp, int ring_nr) { struct bnxt_rx_ring_info *rxr = &bp->rx_ring[ring_nr]; - int i; + int rc; bnxt_alloc_one_rx_ring_skb(bp, rxr, ring_nr); @@ -4179,18 +4336,9 @@ static int bnxt_alloc_one_rx_ring(struct bnxt *bp, int ring_nr) bnxt_alloc_one_rx_ring_page(bp, rxr, ring_nr); if (rxr->rx_tpa) { - dma_addr_t mapping; - u8 *data; - - for (i = 0; i < bp->max_tpa; i++) { - data = __bnxt_alloc_rx_frag(bp, &mapping, GFP_KERNEL); - if (!data) - return -ENOMEM; - - rxr->rx_tpa[i].data = data; - rxr->rx_tpa[i].data_ptr = data + bp->rx_offset; - rxr->rx_tpa[i].mapping = mapping; - } + rc = bnxt_alloc_one_tpa_info_data(bp, rxr); + if (rc) + return rc; } return 0; } @@ -4558,7 +4706,7 @@ int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode) struct net_device *dev = bp->dev; if (page_mode) { - bp->flags &= ~BNXT_FLAG_AGG_RINGS; + bp->flags &= ~(BNXT_FLAG_AGG_RINGS | BNXT_FLAG_NO_AGG_RINGS); bp->flags |= BNXT_FLAG_RX_PAGE_MODE; if (bp->xdp_prog->aux->xdp_has_frags) @@ -8153,6 +8301,9 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) if (flags & FUNC_QCFG_RESP_FLAGS_RING_MONITOR_ENABLED) bp->fw_cap |= BNXT_FW_CAP_RING_MONITOR; + if (flags & FUNC_QCFG_RESP_FLAGS_ENABLE_RDMA_SRIOV) + bp->fw_cap |= BNXT_FW_CAP_ENABLE_RDMA_SRIOV; + switch (resp->port_partition_type) { case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_0: case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_5: @@ -8214,7 +8365,7 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp, int ctx_max) struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; int n = 1; - if (!ctxm->max_entries) + if (!ctxm->max_entries || ctxm->pg_info) continue; if (ctxm->instance_bmap) @@ -8226,6 +8377,9 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp, int ctx_max) return 0; } +static void bnxt_free_one_ctx_mem(struct bnxt *bp, + struct bnxt_ctx_mem_type *ctxm, bool force); + #define BNXT_CTX_INIT_VALID(flags) \ (!!((flags) & \ FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_ENABLE_CTX_KIND_INIT)) @@ -8234,7 +8388,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) { struct hwrm_func_backing_store_qcaps_v2_output *resp; struct hwrm_func_backing_store_qcaps_v2_input *req; - struct bnxt_ctx_mem_info *ctx; + struct bnxt_ctx_mem_info *ctx = bp->ctx; u16 type; int rc; @@ -8242,16 +8396,20 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) if (rc) return rc; - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - bp->ctx = ctx; + if (!ctx) { + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + bp->ctx = ctx; + } resp = hwrm_req_hold(bp, req); for (type = 0; type < BNXT_CTX_V2_MAX; ) { struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; u8 init_val, init_off, i; + u32 max_entries; + u16 entry_size; __le32 *p; u32 flags; @@ -8261,15 +8419,26 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) goto ctx_done; flags = le32_to_cpu(resp->flags); type = le16_to_cpu(resp->next_valid_type); - if (!(flags & FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID)) + if (!(flags & BNXT_CTX_MEM_TYPE_VALID)) { + bnxt_free_one_ctx_mem(bp, ctxm, true); continue; - + } + entry_size = le16_to_cpu(resp->entry_size); + max_entries = le32_to_cpu(resp->max_num_entries); + if (ctxm->mem_valid) { + if (!(flags & BNXT_CTX_MEM_PERSIST) || + ctxm->entry_size != entry_size || + ctxm->max_entries != max_entries) + bnxt_free_one_ctx_mem(bp, ctxm, true); + else + continue; + } ctxm->type = le16_to_cpu(resp->type); - ctxm->entry_size = le16_to_cpu(resp->entry_size); + ctxm->entry_size = entry_size; ctxm->flags = flags; ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map); ctxm->entry_multiple = resp->entry_multiple; - ctxm->max_entries = le32_to_cpu(resp->max_num_entries); + ctxm->max_entries = max_entries; ctxm->min_entries = le32_to_cpu(resp->min_num_entries); init_val = resp->ctx_init_value; init_off = resp->ctx_init_offset; @@ -8294,7 +8463,8 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) struct hwrm_func_backing_store_qcaps_input *req; int rc; - if (bp->hwrm_spec_code < 0x10902 || BNXT_VF(bp) || bp->ctx) + if (bp->hwrm_spec_code < 0x10902 || BNXT_VF(bp) || + (bp->ctx && bp->ctx->flags & BNXT_CTX_FLAG_INITED)) return 0; if (bp->fw_cap & BNXT_FW_CAP_BACKING_STORE_V2) @@ -8635,6 +8805,36 @@ static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp, return rc; } +static size_t bnxt_copy_ctx_pg_tbls(struct bnxt *bp, + struct bnxt_ctx_pg_info *ctx_pg, + void *buf, size_t offset, size_t head, + size_t tail) +{ + struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem; + size_t nr_pages = ctx_pg->nr_pages; + int page_size = rmem->page_size; + size_t len = 0, total_len = 0; + u16 depth = rmem->depth; + + tail %= nr_pages * page_size; + do { + if (depth > 1) { + int i = head / (page_size * MAX_CTX_PAGES); + struct bnxt_ctx_pg_info *pg_tbl; + + pg_tbl = ctx_pg->ctx_pg_tbl[i]; + rmem = &pg_tbl->ring_mem; + } + len = __bnxt_copy_ring(bp, rmem, buf, offset, head, tail); + head += len; + offset += len; + total_len += len; + if (head >= nr_pages * page_size) + head = 0; + } while (head != tail); + return total_len; +} + static void bnxt_free_ctx_pg_tbls(struct bnxt *bp, struct bnxt_ctx_pg_info *ctx_pg) { @@ -8685,6 +8885,8 @@ static int bnxt_setup_ctxm_pg_tbls(struct bnxt *bp, rc = bnxt_alloc_ctx_pg_tbls(bp, &ctx_pg[i], mem_size, pg_lvl, ctxm->init_value ? ctxm : NULL); } + if (!rc) + ctxm->mem_valid = 1; return rc; } @@ -8711,6 +8913,16 @@ static int bnxt_hwrm_func_backing_store_cfg_v2(struct bnxt *bp, hwrm_req_hold(bp, req); req->type = cpu_to_le16(ctxm->type); req->entry_size = cpu_to_le16(ctxm->entry_size); + if ((ctxm->flags & BNXT_CTX_MEM_PERSIST) && + bnxt_bs_trace_avail(bp, ctxm->type)) { + struct bnxt_bs_trace_info *bs_trace; + u32 enables; + + enables = FUNC_BACKING_STORE_CFG_V2_REQ_ENABLES_NEXT_BS_OFFSET; + req->enables = cpu_to_le32(enables); + bs_trace = &bp->bs_trace[bnxt_bstore_to_trace[ctxm->type]]; + req->next_bs_offset = cpu_to_le32(bs_trace->last_offset); + } req->subtype_valid_cnt = ctxm->split_entry_cnt; for (i = 0, p = &req->split_entry_0; i < ctxm->split_entry_cnt; i++) p[i] = cpu_to_le32(ctxm->split[i]); @@ -8740,21 +8952,42 @@ static int bnxt_backing_store_cfg_v2(struct bnxt *bp, u32 ena) { struct bnxt_ctx_mem_info *ctx = bp->ctx; struct bnxt_ctx_mem_type *ctxm; - u16 last_type; + u16 last_type = BNXT_CTX_INV; int rc = 0; u16 type; - if (!ena) - return 0; - else if (ena & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM) - last_type = BNXT_CTX_MAX - 1; - else - last_type = BNXT_CTX_L2_MAX - 1; + for (type = BNXT_CTX_SRT; type <= BNXT_CTX_RIGP1; type++) { + ctxm = &ctx->ctx_arr[type]; + if (!bnxt_bs_trace_avail(bp, type)) + continue; + if (!ctxm->mem_valid) { + rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, + ctxm->max_entries, 1); + if (rc) { + netdev_warn(bp->dev, "Unable to setup ctx page for type:0x%x.\n", + type); + continue; + } + bnxt_bs_trace_init(bp, ctxm); + } + last_type = type; + } + + if (last_type == BNXT_CTX_INV) { + if (!ena) + return 0; + else if (ena & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM) + last_type = BNXT_CTX_MAX - 1; + else + last_type = BNXT_CTX_L2_MAX - 1; + } ctx->ctx_arr[last_type].last = 1; for (type = 0 ; type < BNXT_CTX_V2_MAX; type++) { ctxm = &ctx->ctx_arr[type]; + if (!ctxm->mem_valid) + continue; rc = bnxt_hwrm_func_backing_store_cfg_v2(bp, ctxm, ctxm->last); if (rc) return rc; @@ -8762,21 +8995,63 @@ static int bnxt_backing_store_cfg_v2(struct bnxt *bp, u32 ena) return 0; } -void bnxt_free_ctx_mem(struct bnxt *bp) +/** + * __bnxt_copy_ctx_mem - copy host context memory + * @bp: The driver context + * @ctxm: The pointer to the context memory type + * @buf: The destination buffer or NULL to just obtain the length + * @offset: The buffer offset to copy the data to + * @head: The head offset of context memory to copy from + * @tail: The tail offset (last byte + 1) of context memory to end the copy + * + * This function is called for debugging purposes to dump the host context + * used by the chip. + * + * Return: Length of memory copied + */ +static size_t __bnxt_copy_ctx_mem(struct bnxt *bp, + struct bnxt_ctx_mem_type *ctxm, void *buf, + size_t offset, size_t head, size_t tail) { - struct bnxt_ctx_mem_info *ctx = bp->ctx; - u16 type; + struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info; + size_t len = 0, total_len = 0; + int i, n = 1; - if (!ctx) - return; + if (!ctx_pg) + return 0; - for (type = 0; type < BNXT_CTX_V2_MAX; type++) { - struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; - struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info; - int i, n = 1; + if (ctxm->instance_bmap) + n = hweight32(ctxm->instance_bmap); + for (i = 0; i < n; i++) { + len = bnxt_copy_ctx_pg_tbls(bp, &ctx_pg[i], buf, offset, head, + tail); + offset += len; + total_len += len; + } + return total_len; +} - if (!ctx_pg) - continue; +size_t bnxt_copy_ctx_mem(struct bnxt *bp, struct bnxt_ctx_mem_type *ctxm, + void *buf, size_t offset) +{ + size_t tail = ctxm->max_entries * ctxm->entry_size; + + return __bnxt_copy_ctx_mem(bp, ctxm, buf, offset, 0, tail); +} + +static void bnxt_free_one_ctx_mem(struct bnxt *bp, + struct bnxt_ctx_mem_type *ctxm, bool force) +{ + struct bnxt_ctx_pg_info *ctx_pg; + int i, n = 1; + + ctxm->last = 0; + + if (ctxm->mem_valid && !force && (ctxm->flags & BNXT_CTX_MEM_PERSIST)) + return; + + ctx_pg = ctxm->pg_info; + if (ctx_pg) { if (ctxm->instance_bmap) n = hweight32(ctxm->instance_bmap); for (i = 0; i < n; i++) @@ -8784,11 +9059,27 @@ void bnxt_free_ctx_mem(struct bnxt *bp) kfree(ctx_pg); ctxm->pg_info = NULL; + ctxm->mem_valid = 0; } + memset(ctxm, 0, sizeof(*ctxm)); +} + +void bnxt_free_ctx_mem(struct bnxt *bp, bool force) +{ + struct bnxt_ctx_mem_info *ctx = bp->ctx; + u16 type; + + if (!ctx) + return; + + for (type = 0; type < BNXT_CTX_V2_MAX; type++) + bnxt_free_one_ctx_mem(bp, &ctx->ctx_arr[type], force); ctx->flags &= ~BNXT_CTX_FLAG_INITED; - kfree(ctx); - bp->ctx = NULL; + if (force) { + kfree(ctx); + bp->ctx = NULL; + } } static int bnxt_alloc_ctx_mem(struct bnxt *bp) @@ -9053,7 +9344,6 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp) struct hwrm_port_mac_ptp_qcfg_output *resp; struct hwrm_port_mac_ptp_qcfg_input *req; struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; - bool phc_cfg; u8 flags; int rc; @@ -9100,8 +9390,9 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp) rc = -ENODEV; goto exit; } - phc_cfg = (flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_RTC_CONFIGURED) != 0; - rc = bnxt_ptp_init(bp, phc_cfg); + ptp->rtc_configured = + (flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_RTC_CONFIGURED) != 0; + rc = bnxt_ptp_init(bp); if (rc) netdev_warn(bp->dev, "PTP initialization failed.\n"); exit: @@ -9179,6 +9470,9 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp) bp->flags |= BNXT_FLAG_UDP_GSO_CAP; if (flags_ext2 & FUNC_QCAPS_RESP_FLAGS_EXT2_TX_PKT_TS_CMPL_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_TX_TS_CMP; + if (BNXT_PF(bp) && + (flags_ext2 & FUNC_QCAPS_RESP_FLAGS_EXT2_ROCE_VF_RESOURCE_MGMT_SUPPORTED)) + bp->fw_cap |= BNXT_FW_CAP_ROCE_VF_RESC_MGMT_SUPPORTED; bp->tx_push_thresh = 0; if ((flags & FUNC_QCAPS_RESP_FLAGS_PUSH_MODE_SUPPORTED) && @@ -10885,7 +11179,7 @@ static void bnxt_free_irq(struct bnxt *bp) irq = &bp->irq_tbl[map_idx]; if (irq->requested) { if (irq->have_cpumask) { - irq_set_affinity_hint(irq->vector, NULL); + irq_update_affinity_hint(irq->vector, NULL); free_cpumask_var(irq->cpu_mask); irq->have_cpumask = 0; } @@ -10940,10 +11234,10 @@ static int bnxt_request_irq(struct bnxt *bp) irq->have_cpumask = 1; cpumask_set_cpu(cpumask_local_spread(i, numa_node), irq->cpu_mask); - rc = irq_set_affinity_hint(irq->vector, irq->cpu_mask); + rc = irq_update_affinity_hint(irq->vector, irq->cpu_mask); if (rc) { netdev_warn(bp->dev, - "Set affinity failed, IRQ = %d\n", + "Update affinity hint failed, IRQ = %d\n", irq->vector); break; } @@ -10988,7 +11282,8 @@ static void bnxt_init_napi(struct bnxt *bp) cp_nr_rings--; for (i = 0; i < cp_nr_rings; i++) { bnapi = bp->bnapi[i]; - netif_napi_add(bp->dev, &bnapi->napi, poll_fn); + netif_napi_add_config(bp->dev, &bnapi->napi, poll_fn, + bnapi->index); } if (BNXT_CHIP_TYPE_NITRO_A0(bp)) { bnapi = bp->bnapi[cp_nr_rings]; @@ -11748,7 +12043,7 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up) set_bit(BNXT_STATE_FW_RESET_DET, &bp->state); if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) bnxt_ulp_irq_stop(bp); - bnxt_free_ctx_mem(bp); + bnxt_free_ctx_mem(bp, false); bnxt_dcb_free(bp); rc = bnxt_fw_init_one(bp); if (rc) { @@ -12882,7 +13177,7 @@ static netdev_features_t bnxt_fix_features(struct net_device *dev, if (features & NETIF_F_GRO_HW) features &= ~NETIF_F_LRO; - /* Both CTAG and STAG VLAN accelaration on the RX side have to be + /* Both CTAG and STAG VLAN acceleration on the RX side have to be * turned on or off together. */ vlan_features = features & BNXT_HW_FEATURE_VLAN_ALL_RX; @@ -13413,7 +13708,7 @@ static void bnxt_rx_ring_reset(struct bnxt *bp) bnxt_reset_task(bp, true); break; } - bnxt_free_one_rx_ring_skbs(bp, i); + bnxt_free_one_rx_ring_skbs(bp, rxr); rxr->rx_prod = 0; rxr->rx_agg_prod = 0; rxr->rx_sw_agg_prod = 0; @@ -13461,7 +13756,7 @@ static void bnxt_fw_reset_close(struct bnxt *bp) bnxt_hwrm_func_drv_unrgtr(bp); if (pci_is_enabled(bp->pdev)) pci_disable_device(bp->pdev); - bnxt_free_ctx_mem(bp); + bnxt_free_ctx_mem(bp, false); } static bool is_bnxt_fw_ok(struct bnxt *bp) @@ -13495,12 +13790,13 @@ static void bnxt_force_fw_reset(struct bnxt *bp) test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) return; + /* we have to serialize with bnxt_refclk_read()*/ if (ptp) { unsigned long flags; - spin_lock_irqsave(&ptp->ptp_lock, flags); + write_seqlock_irqsave(&ptp->ptp_lock, flags); set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + write_sequnlock_irqrestore(&ptp->ptp_lock, flags); } else { set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); } @@ -13564,12 +13860,13 @@ void bnxt_fw_reset(struct bnxt *bp) struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; int n = 0, tmo; + /* we have to serialize with bnxt_refclk_read()*/ if (ptp) { unsigned long flags; - spin_lock_irqsave(&ptp->ptp_lock, flags); + write_seqlock_irqsave(&ptp->ptp_lock, flags); set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + write_sequnlock_irqrestore(&ptp->ptp_lock, flags); } else { set_bit(BNXT_STATE_IN_FW_RESET, &bp->state); } @@ -14494,6 +14791,14 @@ static int bnxt_change_mtu(struct net_device *dev, int new_mtu) bnxt_close_nic(bp, true, false); WRITE_ONCE(dev->mtu, new_mtu); + + /* MTU change may change the AGG ring settings if an XDP multi-buffer + * program is attached. We need to set the AGG rings settings and + * rx_skb_func accordingly. + */ + if (READ_ONCE(bp->xdp_prog)) + bnxt_set_rx_skb_mode(bp, true); + bnxt_set_ring_params(bp); if (netif_running(dev)) @@ -15033,19 +15338,6 @@ static const struct netdev_stat_ops bnxt_stat_ops = { .get_base_stats = bnxt_get_base_stats, }; -static int bnxt_alloc_rx_agg_bmap(struct bnxt *bp, struct bnxt_rx_ring_info *rxr) -{ - u16 mem_size; - - rxr->rx_agg_bmap_size = bp->rx_agg_ring_mask + 1; - mem_size = rxr->rx_agg_bmap_size / 8; - rxr->rx_agg_bmap = kzalloc(mem_size, GFP_KERNEL); - if (!rxr->rx_agg_bmap) - return -ENOMEM; - - return 0; -} - static int bnxt_queue_mem_alloc(struct net_device *dev, void *qmem, int idx) { struct bnxt_rx_ring_info *rxr, *clone; @@ -15094,15 +15386,25 @@ static int bnxt_queue_mem_alloc(struct net_device *dev, void *qmem, int idx) goto err_free_rx_agg_ring; } + if (bp->flags & BNXT_FLAG_TPA) { + rc = bnxt_alloc_one_tpa_info(bp, clone); + if (rc) + goto err_free_tpa_info; + } + bnxt_init_one_rx_ring_rxbd(bp, clone); bnxt_init_one_rx_agg_ring_rxbd(bp, clone); bnxt_alloc_one_rx_ring_skb(bp, clone, idx); if (bp->flags & BNXT_FLAG_AGG_RINGS) bnxt_alloc_one_rx_ring_page(bp, clone, idx); + if (bp->flags & BNXT_FLAG_TPA) + bnxt_alloc_one_tpa_info_data(bp, clone); return 0; +err_free_tpa_info: + bnxt_free_one_tpa_info(bp, clone); err_free_rx_agg_ring: bnxt_free_ring(bp, &clone->rx_agg_ring_struct.ring_mem); err_free_rx_ring: @@ -15110,9 +15412,11 @@ static int bnxt_queue_mem_alloc(struct net_device *dev, void *qmem, int idx) err_rxq_info_unreg: xdp_rxq_info_unreg(&clone->xdp_rxq); err_page_pool_destroy: - clone->page_pool->p.napi = NULL; page_pool_destroy(clone->page_pool); + if (bnxt_separate_head_pool()) + page_pool_destroy(clone->head_pool); clone->page_pool = NULL; + clone->head_pool = NULL; return rc; } @@ -15122,13 +15426,15 @@ static void bnxt_queue_mem_free(struct net_device *dev, void *qmem) struct bnxt *bp = netdev_priv(dev); struct bnxt_ring_struct *ring; - bnxt_free_one_rx_ring(bp, rxr); - bnxt_free_one_rx_agg_ring(bp, rxr); + bnxt_free_one_rx_ring_skbs(bp, rxr); xdp_rxq_info_unreg(&rxr->xdp_rxq); page_pool_destroy(rxr->page_pool); + if (bnxt_separate_head_pool()) + page_pool_destroy(rxr->head_pool); rxr->page_pool = NULL; + rxr->head_pool = NULL; ring = &rxr->rx_ring_struct; bnxt_free_ring(bp, &ring->ring_mem); @@ -15210,7 +15516,10 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx) rxr->rx_agg_prod = clone->rx_agg_prod; rxr->rx_sw_agg_prod = clone->rx_sw_agg_prod; rxr->rx_next_cons = clone->rx_next_cons; + rxr->rx_tpa = clone->rx_tpa; + rxr->rx_tpa_idx_map = clone->rx_tpa_idx_map; rxr->page_pool = clone->page_pool; + rxr->head_pool = clone->head_pool; rxr->xdp_rxq = clone->xdp_rxq; bnxt_copy_rx_ring(bp, rxr, clone); @@ -15231,6 +15540,13 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx) for (i = 0; i <= BNXT_VNIC_NTUPLE; i++) { vnic = &bp->vnic_info[i]; + + rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true); + if (rc) { + netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n", + vnic->vnic_id, rc); + return rc; + } vnic->mru = bp->dev->mtu + ETH_HLEN + VLAN_HLEN; bnxt_hwrm_vnic_update(bp, vnic, VNIC_UPDATE_REQ_ENABLES_MRU_VALID); @@ -15262,6 +15578,8 @@ static int bnxt_queue_stop(struct net_device *dev, void *qmem, int idx) bnxt_hwrm_rx_agg_ring_free(bp, rxr, false); rxr->rx_next_cons = 0; page_pool_disable_direct_recycling(rxr->page_pool); + if (bnxt_separate_head_pool()) + page_pool_disable_direct_recycling(rxr->head_pool); memcpy(qmem, rxr, sizeof(*rxr)); bnxt_init_rx_ring_struct(bp, qmem); @@ -15316,7 +15634,7 @@ static void bnxt_remove_one(struct pci_dev *pdev) kfree(bp->fw_health); bp->fw_health = NULL; bnxt_cleanup_pci(bp); - bnxt_free_ctx_mem(bp); + bnxt_free_ctx_mem(bp, true); bnxt_free_crash_dump_mem(bp); kfree(bp->rss_indir_tbl); bp->rss_indir_tbl = NULL; @@ -15958,7 +16276,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) kfree(bp->fw_health); bp->fw_health = NULL; bnxt_cleanup_pci(bp); - bnxt_free_ctx_mem(bp); + bnxt_free_ctx_mem(bp, true); bnxt_free_crash_dump_mem(bp); kfree(bp->rss_indir_tbl); bp->rss_indir_tbl = NULL; @@ -15984,6 +16302,7 @@ static void bnxt_shutdown(struct pci_dev *pdev) if (netif_running(dev)) dev_close(dev); + bnxt_ptp_clear(bp); bnxt_clear_int_mode(bp); pci_disable_device(pdev); @@ -16011,8 +16330,9 @@ static int bnxt_suspend(struct device *device) rc = bnxt_close(dev); } bnxt_hwrm_func_drv_unrgtr(bp); + bnxt_ptp_clear(bp); pci_disable_device(bp->pdev); - bnxt_free_ctx_mem(bp); + bnxt_free_ctx_mem(bp, false); rtnl_unlock(); return rc; } @@ -16054,6 +16374,10 @@ static int bnxt_resume(struct device *device) if (bp->fw_crash_mem) bnxt_hwrm_crash_dump_mem_cfg(bp); + if (bnxt_ptp_init(bp)) { + kfree(bp->ptp_cfg); + bp->ptp_cfg = NULL; + } bnxt_get_wol_settings(bp); if (netif_running(dev)) { rc = bnxt_open(dev); @@ -16124,7 +16448,7 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev, if (pci_is_enabled(pdev)) pci_disable_device(pdev); - bnxt_free_ctx_mem(bp); + bnxt_free_ctx_mem(bp, false); rtnl_unlock(); /* Request a slot slot reset. */ @@ -16136,7 +16460,7 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev, * @pdev: Pointer to PCI device * * Restart the card from scratch, as if from a cold-boot. - * At this point, the card has exprienced a hard reset, + * At this point, the card has experienced a hard reset, * followed by fixups by BIOS, and has its config space * set up identically to what it was at cold boot. */ @@ -16164,7 +16488,7 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); /* Upon fatal error, our device internal logic that latches to * BAR value is getting reset and will restore only upon - * rewritting the BARs. + * rewriting the BARs. * * As pci_restore_state() does not re-write the BARs if the * value is same as saved value earlier, driver needs to @@ -16232,8 +16556,12 @@ static void bnxt_io_resume(struct pci_dev *pdev) rtnl_lock(); err = bnxt_hwrm_func_qcaps(bp); - if (!err && netif_running(netdev)) - err = bnxt_open(netdev); + if (!err) { + if (netif_running(netdev)) + err = bnxt_open(netdev); + else + err = bnxt_reserve_rings(bp, true); + } if (!err) netif_device_attach(netdev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 69231e85140b2e..7df7a2233307af 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -267,6 +267,9 @@ struct rx_cmp { (((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\ RX_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK) +#define RX_CMP_ITYPES(rxcmp) \ + (le32_to_cpu((rxcmp)->rx_cmp_len_flags_type) & RX_CMP_FLAGS_ITYPES_MASK) + #define RX_CMP_V3_HASH_TYPE_LEGACY(rxcmp) \ ((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_V3_RSS_EXT_OP_LEGACY) >>\ RX_CMP_V3_RSS_EXT_OP_LEGACY_SHIFT) @@ -378,7 +381,7 @@ struct rx_agg_cmp { u32 rx_agg_cmp_opaque; __le32 rx_agg_cmp_v; #define RX_AGG_CMP_V (1 << 0) - #define RX_AGG_CMP_AGG_ID (0xffff << 16) + #define RX_AGG_CMP_AGG_ID (0x0fff << 16) #define RX_AGG_CMP_AGG_ID_SHIFT 16 __le32 rx_agg_cmp_unused; }; @@ -416,7 +419,7 @@ struct rx_tpa_start_cmp { #define RX_TPA_START_CMP_V3_RSS_HASH_TYPE_SHIFT 7 #define RX_TPA_START_CMP_AGG_ID (0x7f << 25) #define RX_TPA_START_CMP_AGG_ID_SHIFT 25 - #define RX_TPA_START_CMP_AGG_ID_P5 (0xffff << 16) + #define RX_TPA_START_CMP_AGG_ID_P5 (0x0fff << 16) #define RX_TPA_START_CMP_AGG_ID_SHIFT_P5 16 #define RX_TPA_START_CMP_METADATA1 (0xf << 28) #define RX_TPA_START_CMP_METADATA1_SHIFT 28 @@ -540,7 +543,7 @@ struct rx_tpa_end_cmp { #define RX_TPA_END_CMP_PAYLOAD_OFFSET_SHIFT 16 #define RX_TPA_END_CMP_AGG_ID (0x7f << 25) #define RX_TPA_END_CMP_AGG_ID_SHIFT 25 - #define RX_TPA_END_CMP_AGG_ID_P5 (0xffff << 16) + #define RX_TPA_END_CMP_AGG_ID_P5 (0x0fff << 16) #define RX_TPA_END_CMP_AGG_ID_SHIFT_P5 16 __le32 rx_tpa_end_cmp_tsdelta; @@ -1105,6 +1108,7 @@ struct bnxt_rx_ring_info { struct bnxt_ring_struct rx_agg_ring_struct; struct xdp_rxq_info xdp_rxq; struct page_pool *page_pool; + struct page_pool *head_pool; }; struct bnxt_rx_sw_stats { @@ -1848,6 +1852,8 @@ struct bnxt_vf_rep { #define MAX_CTX_PAGES (BNXT_PAGE_SIZE / 8) #define MAX_CTX_TOTAL_PAGES (MAX_CTX_PAGES * MAX_CTX_PAGES) +#define MAX_CTX_BYTES ((size_t)MAX_CTX_TOTAL_PAGES * BNXT_PAGE_SIZE) +#define MAX_CTX_BYTES_MASK (MAX_CTX_BYTES - 1) struct bnxt_ctx_pg_info { u32 entries; @@ -1880,6 +1886,13 @@ struct bnxt_ctx_mem_type { u16 entry_size; u32 flags; #define BNXT_CTX_MEM_TYPE_VALID FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID +#define BNXT_CTX_MEM_FW_TRACE \ + FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_DBG_TRACE +#define BNXT_CTX_MEM_FW_BIN_TRACE \ + FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_BIN_DBG_TRACE +#define BNXT_CTX_MEM_PERSIST \ + FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_NEXT_BS_OFFSET + u32 instance_bmap; u8 init_value; u8 entry_multiple; @@ -1888,6 +1901,7 @@ struct bnxt_ctx_mem_type { u32 max_entries; u32 min_entries; u8 last:1; + u8 mem_valid:1; u8 split_entry_cnt; #define BNXT_MAX_SPLIT_ENTRY 4 union { @@ -1919,21 +1933,30 @@ struct bnxt_ctx_mem_type { #define BNXT_CTX_FTQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_FP_TQM_RING #define BNXT_CTX_MRAV FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MRAV #define BNXT_CTX_TIM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TIM -#define BNXT_CTX_TKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TKC -#define BNXT_CTX_RKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RKC +#define BNXT_CTX_TCK FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TX_CK +#define BNXT_CTX_RCK FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RX_CK #define BNXT_CTX_MTQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MP_TQM_RING #define BNXT_CTX_SQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SQ_DB_SHADOW #define BNXT_CTX_RQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RQ_DB_SHADOW #define BNXT_CTX_SRQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRQ_DB_SHADOW #define BNXT_CTX_CQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CQ_DB_SHADOW -#define BNXT_CTX_QTKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QUIC_TKC -#define BNXT_CTX_QRKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QUIC_RKC #define BNXT_CTX_TBLSC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TBL_SCOPE #define BNXT_CTX_XPAR FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_XID_PARTITION +#define BNXT_CTX_SRT FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRT_TRACE +#define BNXT_CTX_SRT2 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRT2_TRACE +#define BNXT_CTX_CRT FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CRT_TRACE +#define BNXT_CTX_CRT2 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CRT2_TRACE +#define BNXT_CTX_RIGP0 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RIGP0_TRACE +#define BNXT_CTX_L2HWRM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_L2_HWRM_TRACE +#define BNXT_CTX_REHWRM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_ROCE_HWRM_TRACE +#define BNXT_CTX_CA0 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA0_TRACE +#define BNXT_CTX_CA1 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA1_TRACE +#define BNXT_CTX_CA2 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA2_TRACE +#define BNXT_CTX_RIGP1 FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RIGP1_TRACE #define BNXT_CTX_MAX (BNXT_CTX_TIM + 1) #define BNXT_CTX_L2_MAX (BNXT_CTX_FTQM + 1) -#define BNXT_CTX_V2_MAX (BNXT_CTX_XPAR + 1) +#define BNXT_CTX_V2_MAX (BNXT_CTX_RIGP1 + 1) #define BNXT_CTX_INV ((u16)-1) struct bnxt_ctx_mem_info { @@ -2094,6 +2117,26 @@ enum board_idx { NETXTREME_E_P7_VF, }; +#define BNXT_TRACE_BUF_MAGIC_BYTE ((u8)0xbc) +#define BNXT_TRACE_MAX 11 + +struct bnxt_bs_trace_info { + u8 *magic_byte; + u32 last_offset; + u8 wrapped:1; + u16 ctx_type; + u16 trace_type; +}; + +static inline void bnxt_bs_trace_check_wrap(struct bnxt_bs_trace_info *bs_trace, + u32 offset) +{ + if (!bs_trace->wrapped && + *bs_trace->magic_byte != BNXT_TRACE_BUF_MAGIC_BYTE) + bs_trace->wrapped = 1; + bs_trace->last_offset = offset; +} + struct bnxt { void __iomem *bar0; void __iomem *bar1; @@ -2406,6 +2449,8 @@ struct bnxt { #define BNXT_FW_CAP_DCBX_AGENT BIT_ULL(2) #define BNXT_FW_CAP_NEW_RM BIT_ULL(3) #define BNXT_FW_CAP_IF_CHANGE BIT_ULL(4) + #define BNXT_FW_CAP_ENABLE_RDMA_SRIOV BIT_ULL(5) + #define BNXT_FW_CAP_ROCE_VF_RESC_MGMT_SUPPORTED BIT_ULL(6) #define BNXT_FW_CAP_KONG_MB_CHNL BIT_ULL(7) #define BNXT_FW_CAP_OVS_64BIT_HANDLE BIT_ULL(10) #define BNXT_FW_CAP_TRUSTED_VF BIT_ULL(11) @@ -2452,6 +2497,10 @@ struct bnxt { #define BNXT_SUPPORTS_QUEUE_API(bp) \ (BNXT_PF(bp) && BNXT_SUPPORTS_NTUPLE_VNIC(bp) && \ ((bp)->fw_cap & BNXT_FW_CAP_VNIC_RE_FLUSH)) +#define BNXT_RDMA_SRIOV_EN(bp) \ + ((bp)->fw_cap & BNXT_FW_CAP_ENABLE_RDMA_SRIOV) +#define BNXT_ROCE_VF_RESC_CAP(bp) \ + ((bp)->fw_cap & BNXT_FW_CAP_ROCE_VF_RESC_MGMT_SUPPORTED) u32 hwrm_spec_code; u16 hwrm_cmd_seq; @@ -2622,6 +2671,7 @@ struct bnxt { u16 dump_flag; #define BNXT_DUMP_LIVE 0 #define BNXT_DUMP_CRASH 1 +#define BNXT_DUMP_DRIVER 2 struct bpf_prog *xdp_prog; @@ -2650,6 +2700,7 @@ struct bnxt { struct bnxt_ctx_pg_info *fw_crash_mem; u32 fw_crash_len; + struct bnxt_bs_trace_info bs_trace[BNXT_TRACE_MAX]; }; #define BNXT_NUM_RX_RING_STATS 8 @@ -2785,12 +2836,14 @@ static inline bool bnxt_sriov_cfg(struct bnxt *bp) #endif } +extern const u16 bnxt_bstore_to_trace[]; extern const u16 bnxt_lhint_arr[]; int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 prod, gfp_t gfp); void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data); u32 bnxt_fw_health_readl(struct bnxt *bp, int reg_idx); +bool bnxt_bs_trace_avail(struct bnxt *bp, u16 type); void bnxt_set_tpa_flags(struct bnxt *bp); void bnxt_set_ring_params(struct bnxt *); int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode); @@ -2822,7 +2875,9 @@ int bnxt_hwrm_vnic_alloc(struct bnxt *bp, struct bnxt_vnic_info *vnic, int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings); int bnxt_nq_rings_in_use(struct bnxt *bp); int bnxt_hwrm_set_coal(struct bnxt *); -void bnxt_free_ctx_mem(struct bnxt *bp); +size_t bnxt_copy_ctx_mem(struct bnxt *bp, struct bnxt_ctx_mem_type *ctxm, + void *buf, size_t offset); +void bnxt_free_ctx_mem(struct bnxt *bp, bool force); int bnxt_num_tx_to_cp(struct bnxt *bp, int tx); unsigned int bnxt_get_max_func_stat_ctxs(struct bnxt *bp); unsigned int bnxt_get_avail_stat_ctxs_for_en(struct bnxt *bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c index 4e2b938ed1f7e0..7236d8e548ab5d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c @@ -15,6 +15,50 @@ #include "bnxt_hwrm.h" #include "bnxt_coredump.h" +static const u16 bnxt_bstore_to_seg_id[] = { + [BNXT_CTX_QP] = BNXT_CTX_MEM_SEG_QP, + [BNXT_CTX_SRQ] = BNXT_CTX_MEM_SEG_SRQ, + [BNXT_CTX_CQ] = BNXT_CTX_MEM_SEG_CQ, + [BNXT_CTX_VNIC] = BNXT_CTX_MEM_SEG_VNIC, + [BNXT_CTX_STAT] = BNXT_CTX_MEM_SEG_STAT, + [BNXT_CTX_STQM] = BNXT_CTX_MEM_SEG_STQM, + [BNXT_CTX_FTQM] = BNXT_CTX_MEM_SEG_FTQM, + [BNXT_CTX_MRAV] = BNXT_CTX_MEM_SEG_MRAV, + [BNXT_CTX_TIM] = BNXT_CTX_MEM_SEG_TIM, + [BNXT_CTX_SRT] = BNXT_CTX_MEM_SEG_SRT, + [BNXT_CTX_SRT2] = BNXT_CTX_MEM_SEG_SRT2, + [BNXT_CTX_CRT] = BNXT_CTX_MEM_SEG_CRT, + [BNXT_CTX_CRT2] = BNXT_CTX_MEM_SEG_CRT2, + [BNXT_CTX_RIGP0] = BNXT_CTX_MEM_SEG_RIGP0, + [BNXT_CTX_L2HWRM] = BNXT_CTX_MEM_SEG_L2HWRM, + [BNXT_CTX_REHWRM] = BNXT_CTX_MEM_SEG_REHWRM, + [BNXT_CTX_CA0] = BNXT_CTX_MEM_SEG_CA0, + [BNXT_CTX_CA1] = BNXT_CTX_MEM_SEG_CA1, + [BNXT_CTX_CA2] = BNXT_CTX_MEM_SEG_CA2, + [BNXT_CTX_RIGP1] = BNXT_CTX_MEM_SEG_RIGP1, +}; + +static int bnxt_dbg_hwrm_log_buffer_flush(struct bnxt *bp, u16 type, u32 flags, + u32 *offset) +{ + struct hwrm_dbg_log_buffer_flush_output *resp; + struct hwrm_dbg_log_buffer_flush_input *req; + int rc; + + rc = hwrm_req_init(bp, req, HWRM_DBG_LOG_BUFFER_FLUSH); + if (rc) + return rc; + + req->flags = cpu_to_le32(flags); + req->type = cpu_to_le16(type); + resp = hwrm_req_hold(bp, req); + rc = hwrm_req_send(bp, req); + if (!rc) + *offset = le32_to_cpu(resp->current_buffer_offset); + hwrm_req_drop(bp, req); + return rc; +} + static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, struct bnxt_hwrm_dbg_dma_info *info) { @@ -165,11 +209,12 @@ static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id, return rc; } -static void +void bnxt_fill_coredump_seg_hdr(struct bnxt *bp, struct bnxt_coredump_segment_hdr *seg_hdr, struct coredump_segment_record *seg_rec, u32 seg_len, - int status, u32 duration, u32 instance) + int status, u32 duration, u32 instance, u32 comp_id, + u32 seg_id) { memset(seg_hdr, 0, sizeof(*seg_hdr)); memcpy(seg_hdr->signature, "sEgM", 4); @@ -180,11 +225,8 @@ bnxt_fill_coredump_seg_hdr(struct bnxt *bp, seg_hdr->high_version = seg_rec->version_hi; seg_hdr->flags = cpu_to_le32(seg_rec->compress_flags); } else { - /* For hwrm_ver_get response Component id = 2 - * and Segment id = 0 - */ - seg_hdr->component_id = cpu_to_le32(2); - seg_hdr->segment_id = 0; + seg_hdr->component_id = cpu_to_le32(comp_id); + seg_hdr->segment_id = cpu_to_le32(seg_id); } seg_hdr->function_id = cpu_to_le16(bp->pdev->devfn); seg_hdr->length = cpu_to_le32(seg_len); @@ -269,7 +311,78 @@ bnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record, record->ioctl_high_version = 0; } -static int __bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) +static void bnxt_fill_drv_seg_record(struct bnxt *bp, + struct bnxt_driver_segment_record *record, + struct bnxt_ctx_mem_type *ctxm, u16 type) +{ + struct bnxt_bs_trace_info *bs_trace = &bp->bs_trace[type]; + u32 offset = 0; + int rc = 0; + + rc = bnxt_dbg_hwrm_log_buffer_flush(bp, type, 0, &offset); + if (rc) + return; + + bnxt_bs_trace_check_wrap(bs_trace, offset); + record->max_entries = cpu_to_le32(ctxm->max_entries); + record->entry_size = cpu_to_le32(ctxm->entry_size); + record->offset = cpu_to_le32(bs_trace->last_offset); + record->wrapped = bs_trace->wrapped; +} + +static u32 bnxt_get_ctx_coredump(struct bnxt *bp, void *buf, u32 offset, + u32 *segs) +{ + struct bnxt_driver_segment_record record = {}; + struct bnxt_coredump_segment_hdr seg_hdr; + struct bnxt_ctx_mem_info *ctx = bp->ctx; + u32 comp_id = BNXT_DRV_COMP_ID; + void *data = NULL; + size_t len = 0; + u16 type; + + *segs = 0; + if (!ctx) + return 0; + + if (buf) + buf += offset; + for (type = 0 ; type <= BNXT_CTX_RIGP1; type++) { + struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; + bool trace = bnxt_bs_trace_avail(bp, type); + u32 seg_id = bnxt_bstore_to_seg_id[type]; + size_t seg_len, extra_hlen = 0; + + if (!ctxm->mem_valid || !seg_id) + continue; + + if (trace) + extra_hlen = BNXT_SEG_RCD_LEN; + if (buf) + data = buf + BNXT_SEG_HDR_LEN + extra_hlen; + seg_len = bnxt_copy_ctx_mem(bp, ctxm, data, 0) + extra_hlen; + if (buf) { + bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, NULL, seg_len, + 0, 0, 0, comp_id, seg_id); + memcpy(buf, &seg_hdr, BNXT_SEG_HDR_LEN); + buf += BNXT_SEG_HDR_LEN; + if (trace) { + u16 trace_type = bnxt_bstore_to_trace[type]; + + bnxt_fill_drv_seg_record(bp, &record, ctxm, + trace_type); + memcpy(buf, &record, BNXT_SEG_RCD_LEN); + } + buf += seg_len; + } + len += BNXT_SEG_HDR_LEN + seg_len; + *segs += 1; + } + return len; +} + +static int __bnxt_get_coredump(struct bnxt *bp, u16 dump_type, void *buf, + u32 *dump_len) { u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output); u32 offset = 0, seg_hdr_len, seg_record_len, buf_len = 0; @@ -287,17 +400,31 @@ static int __bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) start_utc = sys_tz.tz_minuteswest * 60; seg_hdr_len = sizeof(seg_hdr); - /* First segment should be hwrm_ver_get response */ + /* First segment should be hwrm_ver_get response. + * For hwrm_ver_get response Component id = 2 and Segment id = 0. + */ *dump_len = seg_hdr_len + ver_get_resp_len; if (buf) { bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, NULL, ver_get_resp_len, - 0, 0, 0); + 0, 0, 0, BNXT_VER_GET_COMP_ID, 0); memcpy(buf + offset, &seg_hdr, seg_hdr_len); offset += seg_hdr_len; memcpy(buf + offset, &bp->ver_resp, ver_get_resp_len); offset += ver_get_resp_len; } + if (dump_type == BNXT_DUMP_DRIVER) { + u32 drv_len, segs = 0; + + drv_len = bnxt_get_ctx_coredump(bp, buf, offset, &segs); + *dump_len += drv_len; + offset += drv_len; + if (buf) + coredump.total_segs += segs; + goto err; + } + + seg_record_len = sizeof(*seg_record); rc = bnxt_hwrm_dbg_coredump_list(bp, &coredump); if (rc) { netdev_err(bp->dev, "Failed to get coredump segment list\n"); @@ -346,7 +473,7 @@ static int __bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) end = jiffies; duration = jiffies_to_msecs(end - start); bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, seg_record, seg_len, - rc, duration, 0); + rc, duration, 0, 0, 0); if (buf) { /* Write segment header into the buffer */ @@ -442,7 +569,7 @@ int bnxt_get_coredump(struct bnxt *bp, u16 dump_type, void *buf, u32 *dump_len) else return -EOPNOTSUPP; } else { - return __bnxt_get_coredump(bp, buf, dump_len); + return __bnxt_get_coredump(bp, dump_type, buf, dump_len); } } @@ -512,9 +639,12 @@ u32 bnxt_get_coredump_length(struct bnxt *bp, u16 dump_type) return bp->fw_crash_len; } - if (bnxt_hwrm_get_dump_len(bp, dump_type, &len)) { - if (dump_type != BNXT_DUMP_CRASH) - __bnxt_get_coredump(bp, NULL, &len); + if (dump_type != BNXT_DUMP_DRIVER) { + if (!bnxt_hwrm_get_dump_len(bp, dump_type, &len)) + return len; } + if (dump_type != BNXT_DUMP_CRASH) + __bnxt_get_coredump(bp, dump_type, NULL, &len); + return len; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.h index a76d5c281413fd..d1cd6387f3ab4b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.h @@ -68,11 +68,49 @@ struct bnxt_coredump_record { __le16 rsvd3[313]; }; +struct bnxt_driver_segment_record { + __le32 max_entries; + __le32 entry_size; + __le32 offset; + __u8 wrapped:1; + __u8 unused[3]; +}; + +#define BNXT_VER_GET_COMP_ID 2 +#define BNXT_DRV_COMP_ID 0xd + +#define BNXT_CTX_MEM_SEG_ID_START 0x200 + +#define BNXT_CTX_MEM_SEG_QP (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_QP) +#define BNXT_CTX_MEM_SEG_SRQ (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_SRQ) +#define BNXT_CTX_MEM_SEG_CQ (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_CQ) +#define BNXT_CTX_MEM_SEG_VNIC (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_VNIC) +#define BNXT_CTX_MEM_SEG_STAT (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_STAT) +#define BNXT_CTX_MEM_SEG_STQM (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_STQM) +#define BNXT_CTX_MEM_SEG_FTQM (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_FTQM) +#define BNXT_CTX_MEM_SEG_MRAV (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_MRAV) +#define BNXT_CTX_MEM_SEG_TIM (BNXT_CTX_MEM_SEG_ID_START + BNXT_CTX_TIM) + +#define BNXT_CTX_MEM_SEG_SRT 0x1 +#define BNXT_CTX_MEM_SEG_SRT2 0x2 +#define BNXT_CTX_MEM_SEG_CRT 0x3 +#define BNXT_CTX_MEM_SEG_CRT2 0x4 +#define BNXT_CTX_MEM_SEG_RIGP0 0x5 +#define BNXT_CTX_MEM_SEG_L2HWRM 0x6 +#define BNXT_CTX_MEM_SEG_REHWRM 0x7 +#define BNXT_CTX_MEM_SEG_CA0 0x8 +#define BNXT_CTX_MEM_SEG_CA1 0x9 +#define BNXT_CTX_MEM_SEG_CA2 0xa +#define BNXT_CTX_MEM_SEG_RIGP1 0xb + #define BNXT_CRASH_DUMP_LEN (8 << 20) #define COREDUMP_LIST_BUF_LEN 2048 #define COREDUMP_RETRIEVE_BUF_LEN 4096 +#define BNXT_SEG_HDR_LEN sizeof(struct bnxt_coredump_segment_hdr) +#define BNXT_SEG_RCD_LEN sizeof(struct bnxt_driver_segment_record) + struct bnxt_coredump { void *data; int data_size; @@ -118,6 +156,11 @@ struct hwrm_dbg_cmn_output { #define BNXT_DBG_CR_DUMP_MDM_CFG_DDR \ DBG_CRASHDUMP_MEDIUM_CFG_REQ_TYPE_DDR +void bnxt_fill_coredump_seg_hdr(struct bnxt *bp, + struct bnxt_coredump_segment_hdr *seg_hdr, + struct coredump_segment_record *seg_rec, + u32 seg_len, int status, u32 duration, + u32 instance, u32 comp_id, u32 seg_id); int bnxt_get_coredump(struct bnxt *bp, u16 dump_type, void *buf, u32 *dump_len); int bnxt_hwrm_get_dump_len(struct bnxt *bp, u16 dump_type, u32 *dump_len); u32 bnxt_get_coredump_length(struct bnxt *bp, u16 dump_type); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 4cb0fabf977e38..ef8288fd68f4cb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -463,7 +463,7 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change, break; } bnxt_cancel_reservations(bp, false); - bnxt_free_ctx_mem(bp); + bnxt_free_ctx_mem(bp, false); break; } case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index f71cc8188b4e5b..d87681d711067c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -705,112 +705,105 @@ static void bnxt_get_ethtool_stats(struct net_device *dev, static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf) { struct bnxt *bp = netdev_priv(dev); - static const char * const *str; u32 i, j, num_str; + const char *str; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < bp->cp_nr_rings; i++) { - if (is_rx_ring(bp, i)) { - num_str = NUM_RING_RX_HW_STATS; - for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, - bnxt_ring_rx_stats_str[j]); - buf += ETH_GSTRING_LEN; + if (is_rx_ring(bp, i)) + for (j = 0; j < NUM_RING_RX_HW_STATS; j++) { + str = bnxt_ring_rx_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); } - } - if (is_tx_ring(bp, i)) { - num_str = NUM_RING_TX_HW_STATS; - for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, - bnxt_ring_tx_stats_str[j]); - buf += ETH_GSTRING_LEN; + if (is_tx_ring(bp, i)) + for (j = 0; j < NUM_RING_TX_HW_STATS; j++) { + str = bnxt_ring_tx_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); } - } num_str = bnxt_get_num_tpa_ring_stats(bp); if (!num_str || !is_rx_ring(bp, i)) goto skip_tpa_stats; if (bp->max_tpa_v2) - str = bnxt_ring_tpa2_stats_str; + for (j = 0; j < num_str; j++) { + str = bnxt_ring_tpa2_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } else - str = bnxt_ring_tpa_stats_str; - - for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, str[j]); - buf += ETH_GSTRING_LEN; - } -skip_tpa_stats: - if (is_rx_ring(bp, i)) { - num_str = NUM_RING_RX_SW_STATS; for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, - bnxt_rx_sw_stats_str[j]); - buf += ETH_GSTRING_LEN; + str = bnxt_ring_tpa_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); } - } - num_str = NUM_RING_CMN_SW_STATS; - for (j = 0; j < num_str; j++) { - sprintf(buf, "[%d]: %s", i, - bnxt_cmn_sw_stats_str[j]); - buf += ETH_GSTRING_LEN; +skip_tpa_stats: + if (is_rx_ring(bp, i)) + for (j = 0; j < NUM_RING_RX_SW_STATS; j++) { + str = bnxt_rx_sw_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, + str); + } + for (j = 0; j < NUM_RING_CMN_SW_STATS; j++) { + str = bnxt_cmn_sw_stats_str[j]; + ethtool_sprintf(&buf, "[%d]: %s", i, str); } } - for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++) { - strscpy(buf, bnxt_ring_err_stats_arr[i], ETH_GSTRING_LEN); - buf += ETH_GSTRING_LEN; - } + for (i = 0; i < BNXT_NUM_RING_ERR_STATS; i++) + ethtool_puts(&buf, bnxt_ring_err_stats_arr[i]); - if (bp->flags & BNXT_FLAG_PORT_STATS) { + if (bp->flags & BNXT_FLAG_PORT_STATS) for (i = 0; i < BNXT_NUM_PORT_STATS; i++) { - strcpy(buf, bnxt_port_stats_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_port_stats_arr[i].string; + ethtool_puts(&buf, str); } - } + if (bp->flags & BNXT_FLAG_PORT_STATS_EXT) { u32 len; len = min_t(u32, bp->fw_rx_stats_ext_size, ARRAY_SIZE(bnxt_port_stats_ext_arr)); for (i = 0; i < len; i++) { - strcpy(buf, bnxt_port_stats_ext_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_port_stats_ext_arr[i].string; + ethtool_puts(&buf, str); } + len = min_t(u32, bp->fw_tx_stats_ext_size, ARRAY_SIZE(bnxt_tx_port_stats_ext_arr)); for (i = 0; i < len; i++) { - strcpy(buf, - bnxt_tx_port_stats_ext_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_tx_port_stats_ext_arr[i].string; + ethtool_puts(&buf, str); } + if (bp->pri2cos_valid) { for (i = 0; i < 8; i++) { - strcpy(buf, - bnxt_rx_bytes_pri_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_rx_bytes_pri_arr[i].string; + ethtool_puts(&buf, str); } + for (i = 0; i < 8; i++) { - strcpy(buf, - bnxt_rx_pkts_pri_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_rx_pkts_pri_arr[i].string; + ethtool_puts(&buf, str); } + for (i = 0; i < 8; i++) { - strcpy(buf, - bnxt_tx_bytes_pri_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_tx_bytes_pri_arr[i].string; + ethtool_puts(&buf, str); } + for (i = 0; i < 8; i++) { - strcpy(buf, - bnxt_tx_pkts_pri_arr[i].string); - buf += ETH_GSTRING_LEN; + str = bnxt_tx_pkts_pri_arr[i].string; + ethtool_puts(&buf, str); } } } break; case ETH_SS_TEST: if (bp->num_tests) - memcpy(buf, bp->test_info->string, - bp->num_tests * ETH_GSTRING_LEN); + for (i = 0; i < bp->num_tests; i++) + ethtool_puts(&buf, bp->test_info->string[i]); break; default: netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n", @@ -1131,14 +1124,15 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) fkeys = &fltr->fkeys; fmasks = &fltr->fmasks; if (fkeys->basic.n_proto == htons(ETH_P_IP)) { - if (fkeys->basic.ip_proto == IPPROTO_ICMP || - fkeys->basic.ip_proto == IPPROTO_RAW) { + if (fkeys->basic.ip_proto == BNXT_IP_PROTO_WILDCARD) { fs->flow_type = IP_USER_FLOW; fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; - if (fkeys->basic.ip_proto == IPPROTO_ICMP) - fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP; - else - fs->h_u.usr_ip4_spec.proto = IPPROTO_RAW; + fs->h_u.usr_ip4_spec.proto = BNXT_IP_PROTO_WILDCARD; + fs->m_u.usr_ip4_spec.proto = 0; + } else if (fkeys->basic.ip_proto == IPPROTO_ICMP) { + fs->flow_type = IP_USER_FLOW; + fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; + fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP; fs->m_u.usr_ip4_spec.proto = BNXT_IP_PROTO_FULL_MASK; } else if (fkeys->basic.ip_proto == IPPROTO_TCP) { fs->flow_type = TCP_V4_FLOW; @@ -1160,13 +1154,13 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst; } } else { - if (fkeys->basic.ip_proto == IPPROTO_ICMPV6 || - fkeys->basic.ip_proto == IPPROTO_RAW) { + if (fkeys->basic.ip_proto == BNXT_IP_PROTO_WILDCARD) { fs->flow_type = IPV6_USER_FLOW; - if (fkeys->basic.ip_proto == IPPROTO_ICMPV6) - fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6; - else - fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_RAW; + fs->h_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_WILDCARD; + fs->m_u.usr_ip6_spec.l4_proto = 0; + } else if (fkeys->basic.ip_proto == IPPROTO_ICMPV6) { + fs->flow_type = IPV6_USER_FLOW; + fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6; fs->m_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_FULL_MASK; } else if (fkeys->basic.ip_proto == IPPROTO_TCP) { fs->flow_type = TCP_V6_FLOW; @@ -1193,10 +1187,14 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) } } - if (fltr->base.flags & BNXT_ACT_DROP) + if (fltr->base.flags & BNXT_ACT_DROP) { fs->ring_cookie = RX_CLS_FLOW_DISC; - else + } else if (fltr->base.flags & BNXT_ACT_RSS_CTX) { + fs->flow_type |= FLOW_RSS; + cmd->rss_context = fltr->base.fw_vnic_id; + } else { fs->ring_cookie = fltr->base.rxq; + } rc = 0; fltr_err: @@ -1289,10 +1287,12 @@ static int bnxt_add_l2_cls_rule(struct bnxt *bp, static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec, struct ethtool_usrip4_spec *ip_mask) { + u8 mproto = ip_mask->proto; + u8 sproto = ip_spec->proto; + if (ip_mask->l4_4_bytes || ip_mask->tos || ip_spec->ip_ver != ETH_RX_NFC_IP4 || - ip_mask->proto != BNXT_IP_PROTO_FULL_MASK || - (ip_spec->proto != IPPROTO_RAW && ip_spec->proto != IPPROTO_ICMP)) + (mproto && (mproto != BNXT_IP_PROTO_FULL_MASK || sproto != IPPROTO_ICMP))) return false; return true; } @@ -1300,10 +1300,11 @@ static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec, static bool bnxt_verify_ntuple_ip6_flow(struct ethtool_usrip6_spec *ip_spec, struct ethtool_usrip6_spec *ip_mask) { + u8 mproto = ip_mask->l4_proto; + u8 sproto = ip_spec->l4_proto; + if (ip_mask->l4_4_bytes || ip_mask->tclass || - ip_mask->l4_proto != BNXT_IP_PROTO_FULL_MASK || - (ip_spec->l4_proto != IPPROTO_RAW && - ip_spec->l4_proto != IPPROTO_ICMPV6)) + (mproto && (mproto != BNXT_IP_PROTO_FULL_MASK || sproto != IPPROTO_ICMPV6))) return false; return true; } @@ -1357,7 +1358,8 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, struct ethtool_usrip4_spec *ip_spec = &fs->h_u.usr_ip4_spec; struct ethtool_usrip4_spec *ip_mask = &fs->m_u.usr_ip4_spec; - fkeys->basic.ip_proto = ip_spec->proto; + fkeys->basic.ip_proto = ip_mask->proto ? ip_spec->proto + : BNXT_IP_PROTO_WILDCARD; fkeys->basic.n_proto = htons(ETH_P_IP); fkeys->addrs.v4addrs.src = ip_spec->ip4src; fmasks->addrs.v4addrs.src = ip_mask->ip4src; @@ -1388,7 +1390,8 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, struct ethtool_usrip6_spec *ip_spec = &fs->h_u.usr_ip6_spec; struct ethtool_usrip6_spec *ip_mask = &fs->m_u.usr_ip6_spec; - fkeys->basic.ip_proto = ip_spec->l4_proto; + fkeys->basic.ip_proto = ip_mask->l4_proto ? ip_spec->l4_proto + : BNXT_IP_PROTO_WILDCARD; fkeys->basic.n_proto = htons(ETH_P_IPV6); fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src; fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src; @@ -2838,19 +2841,24 @@ static int bnxt_get_link_ksettings(struct net_device *dev, } base->port = PORT_NONE; - if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { + if (media == BNXT_MEDIA_TP) { base->port = PORT_TP; linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, lk_ksettings->link_modes.supported); linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, lk_ksettings->link_modes.advertising); + } else if (media == BNXT_MEDIA_KR) { + linkmode_set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, + lk_ksettings->link_modes.supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, + lk_ksettings->link_modes.advertising); } else { linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, lk_ksettings->link_modes.supported); linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, lk_ksettings->link_modes.advertising); - if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) + if (media == BNXT_MEDIA_CR) base->port = PORT_DA; else base->port = PORT_FIBRE; @@ -4985,8 +4993,8 @@ static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) { struct bnxt *bp = netdev_priv(dev); - if (dump->flag > BNXT_DUMP_CRASH) { - netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); + if (dump->flag > BNXT_DUMP_DRIVER) { + netdev_info(dev, "Supports only Live(0), Crash(1), Driver(2) dumps.\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index e2ee030237d4a8..33b86ede1ce5fb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -44,6 +44,7 @@ struct bnxt_led_cfg { #define BNXT_PXP_REG_LEN 0x3110 #define BNXT_IP_PROTO_FULL_MASK 0xFF +#define BNXT_IP_PROTO_WILDCARD 0x0 extern const struct ethtool_ops bnxt_ethtool_ops; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index f8ef6f1a1964e6..5f8de16343788f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -42,6 +42,10 @@ struct hwrm_resp_hdr { #define TLV_TYPE_MODIFY_ROCE_CC_GEN1 0x5UL #define TLV_TYPE_QUERY_ROCE_CC_GEN2 0x6UL #define TLV_TYPE_MODIFY_ROCE_CC_GEN2 0x7UL +#define TLV_TYPE_QUERY_ROCE_CC_GEN1_EXT 0x8UL +#define TLV_TYPE_MODIFY_ROCE_CC_GEN1_EXT 0x9UL +#define TLV_TYPE_QUERY_ROCE_CC_GEN2_EXT 0xaUL +#define TLV_TYPE_MODIFY_ROCE_CC_GEN2_EXT 0xbUL #define TLV_TYPE_ENGINE_CKV_ALIAS_ECC_PUBLIC_KEY 0x8001UL #define TLV_TYPE_ENGINE_CKV_IV 0x8003UL #define TLV_TYPE_ENGINE_CKV_AUTH_TAG 0x8004UL @@ -509,6 +513,7 @@ struct cmd_nums { #define HWRM_TFC_IF_TBL_GET 0x399UL #define HWRM_TFC_TBL_SCOPE_CONFIG_GET 0x39aUL #define HWRM_TFC_RESC_USAGE_QUERY 0x39bUL + #define HWRM_TFC_GLOBAL_ID_FREE 0x39cUL #define HWRM_SV 0x400UL #define HWRM_DBG_SERDES_TEST 0xff0eUL #define HWRM_DBG_LOG_BUFFER_FLUSH 0xff0fUL @@ -624,8 +629,8 @@ struct hwrm_err_output { #define HWRM_VERSION_MAJOR 1 #define HWRM_VERSION_MINOR 10 #define HWRM_VERSION_UPDATE 3 -#define HWRM_VERSION_RSVD 68 -#define HWRM_VERSION_STR "1.10.3.68" +#define HWRM_VERSION_RSVD 85 +#define HWRM_VERSION_STR "1.10.3.85" /* hwrm_ver_get_input (size:192b/24B) */ struct hwrm_ver_get_input { @@ -1302,6 +1307,43 @@ struct hwrm_async_event_cmpl_error_report { #define ASYNC_EVENT_CMPL_ERROR_REPORT_EVENT_DATA1_ERROR_TYPE_SFT 0 }; +/* hwrm_async_event_cmpl_dbg_buf_producer (size:128b/16B) */ +struct hwrm_async_event_cmpl_dbg_buf_producer { + __le16 type; + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_MASK 0x3fUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_SFT 0 + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_HWRM_ASYNC_EVENT 0x2eUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_TYPE_HWRM_ASYNC_EVENT + __le16 event_id; + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_DBG_BUF_PRODUCER 0x4cUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_ID_DBG_BUF_PRODUCER + __le32 event_data2; + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_MASK 0xffffffffUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_SFT 0 + u8 opaque_v; + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_V 0x1UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_OPAQUE_MASK 0xfeUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_OPAQUE_SFT 1 + u8 timestamp_lo; + __le16 timestamp_hi; + __le32 event_data1; + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_MASK 0xffffUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SFT 0 + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SRT_TRACE 0x0UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_SRT2_TRACE 0x1UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CRT_TRACE 0x2UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CRT2_TRACE 0x3UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_RIGP0_TRACE 0x4UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_L2_HWRM_TRACE 0x5UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_ROCE_HWRM_TRACE 0x6UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA0_TRACE 0x7UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA1_TRACE 0x8UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_CA2_TRACE 0x9UL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_RIGP1_TRACE 0xaUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_AFM_KONG_HWRM_TRACE 0xbUL + #define ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_LAST ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA1_TYPE_AFM_KONG_HWRM_TRACE +}; + /* hwrm_async_event_cmpl_hwrm_error (size:128b/16B) */ struct hwrm_async_event_cmpl_hwrm_error { __le16 type; @@ -1864,7 +1906,10 @@ struct hwrm_func_qcaps_output { __le32 roce_vf_max_gid; __le32 flags_ext3; #define FUNC_QCAPS_RESP_FLAGS_EXT3_RM_RSV_WHILE_ALLOC_CAP 0x1UL - u8 unused_3[7]; + #define FUNC_QCAPS_RESP_FLAGS_EXT3_REQUIRE_L2_FILTER 0x2UL + #define FUNC_QCAPS_RESP_FLAGS_EXT3_MAX_ROCE_VFS_SUPPORTED 0x4UL + __le16 max_roce_vfs; + u8 unused_3[5]; u8 valid; }; @@ -2253,17 +2298,18 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_FLAGS2_KTLS_KEY_CTX_ASSETS_TEST 0x1UL #define FUNC_CFG_REQ_FLAGS2_QUIC_KEY_CTX_ASSETS_TEST 0x2UL __le32 enables2; - #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL - #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL - #define FUNC_CFG_REQ_ENABLES2_QUIC_TX_KEY_CTXS 0x4UL - #define FUNC_CFG_REQ_ENABLES2_QUIC_RX_KEY_CTXS 0x8UL - #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF 0x10UL - #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF 0x20UL - #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF 0x40UL - #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF 0x80UL - #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF 0x100UL - #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL - #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL + #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL + #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL + #define FUNC_CFG_REQ_ENABLES2_QUIC_TX_KEY_CTXS 0x4UL + #define FUNC_CFG_REQ_ENABLES2_QUIC_RX_KEY_CTXS 0x8UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF 0x10UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF 0x20UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF 0x40UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF 0x80UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF 0x100UL + #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL + #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL + #define FUNC_CFG_REQ_ENABLES2_PHYSICAL_SLOT_NUMBER 0x800UL u8 port_kdnet_mode; #define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL #define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL @@ -2281,7 +2327,7 @@ struct hwrm_func_cfg_input { #define FUNC_CFG_REQ_DB_PAGE_SIZE_2MB 0x9UL #define FUNC_CFG_REQ_DB_PAGE_SIZE_4MB 0xaUL #define FUNC_CFG_REQ_DB_PAGE_SIZE_LAST FUNC_CFG_REQ_DB_PAGE_SIZE_4MB - u8 unused_1[2]; + __le16 physical_slot_number; __le32 num_ktls_tx_key_ctxs; __le32 num_ktls_rx_key_ctxs; __le32 num_quic_tx_key_ctxs; @@ -3683,7 +3729,7 @@ struct hwrm_func_ptp_ext_qcfg_output { u8 valid; }; -/* hwrm_func_backing_store_cfg_v2_input (size:448b/56B) */ +/* hwrm_func_backing_store_cfg_v2_input (size:512b/64B) */ struct hwrm_func_backing_store_cfg_v2_input { __le16 req_type; __le16 cmpl_ring; @@ -3721,6 +3767,7 @@ struct hwrm_func_backing_store_cfg_v2_input { #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_CA1_TRACE 0x27UL #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_RIGP1_TRACE 0x29UL + #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_CFG_V2_REQ_TYPE_INVALID __le16 instance; @@ -3752,6 +3799,9 @@ struct hwrm_func_backing_store_cfg_v2_input { __le32 split_entry_1; __le32 split_entry_2; __le32 split_entry_3; + __le32 enables; + #define FUNC_BACKING_STORE_CFG_V2_REQ_ENABLES_NEXT_BS_OFFSET 0x1UL + __le32 next_bs_offset; }; /* hwrm_func_backing_store_cfg_v2_output (size:128b/16B) */ @@ -3802,6 +3852,7 @@ struct hwrm_func_backing_store_qcfg_v2_input { #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CA1_TRACE 0x27UL #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RIGP1_TRACE 0x29UL + #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID __le16 instance; @@ -3963,6 +4014,7 @@ struct hwrm_func_backing_store_qcaps_v2_input { #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA1_TRACE 0x27UL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RIGP1_TRACE 0x29UL + #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_INVALID u8 rsvd[6]; @@ -4005,6 +4057,7 @@ struct hwrm_func_backing_store_qcaps_v2_output { #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_CA1_TRACE 0x27UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_CA2_TRACE 0x28UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_RIGP1_TRACE 0x29UL + #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_AFM_KONG_HWRM_TRACE 0x2aUL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_INVALID 0xffffUL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_LAST FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_INVALID __le16 entry_size; @@ -4014,6 +4067,8 @@ struct hwrm_func_backing_store_qcaps_v2_output { #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_DRIVER_MANAGED_MEMORY 0x4UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_ROCE_QP_PSEUDO_STATIC_ALLOC 0x8UL #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_DBG_TRACE 0x10UL + #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_FW_BIN_DBG_TRACE 0x20UL + #define FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_NEXT_BS_OFFSET 0x40UL __le32 instance_bit_map; u8 ctx_init_value; u8 ctx_init_offset; @@ -4034,7 +4089,8 @@ struct hwrm_func_backing_store_qcaps_v2_output { __le32 split_entry_1; __le32 split_entry_2; __le32 split_entry_3; - u8 rsvd3[3]; + __le16 max_instance_count; + u8 rsvd3; u8 valid; }; @@ -4535,11 +4591,12 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_PHY_TYPE_800G_BASEDR8 0x3dUL #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_800G_BASEDR8 u8 media_type; - #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL - #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL - #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC 0x2UL - #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE 0x3UL - #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_LAST PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE + #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL + #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL + #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC 0x2UL + #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE 0x3UL + #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_BACKPLANE 0x4UL + #define PORT_PHY_QCFG_RESP_MEDIA_TYPE_LAST PORT_PHY_QCFG_RESP_MEDIA_TYPE_BACKPLANE u8 xcvr_pkg_type; #define PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_INTERNAL 0x1UL #define PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_EXTERNAL 0x2UL @@ -4654,7 +4711,8 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_100GB 0x2UL #define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL u8 link_down_reason; - #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL + #define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_OTP_SPEED_VIOLATION 0x2UL __le16 support_speeds2; #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB 0x1UL #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB 0x2UL @@ -9241,20 +9299,22 @@ struct hwrm_fw_set_time_output { /* hwrm_struct_hdr (size:128b/16B) */ struct hwrm_struct_hdr { __le16 struct_id; - #define STRUCT_HDR_STRUCT_ID_LLDP_CFG 0x41bUL - #define STRUCT_HDR_STRUCT_ID_DCBX_ETS 0x41dUL - #define STRUCT_HDR_STRUCT_ID_DCBX_PFC 0x41fUL - #define STRUCT_HDR_STRUCT_ID_DCBX_APP 0x421UL - #define STRUCT_HDR_STRUCT_ID_DCBX_FEATURE_STATE 0x422UL - #define STRUCT_HDR_STRUCT_ID_LLDP_GENERIC 0x424UL - #define STRUCT_HDR_STRUCT_ID_LLDP_DEVICE 0x426UL - #define STRUCT_HDR_STRUCT_ID_POWER_BKUP 0x427UL - #define STRUCT_HDR_STRUCT_ID_PEER_MMAP 0x429UL - #define STRUCT_HDR_STRUCT_ID_AFM_OPAQUE 0x1UL - #define STRUCT_HDR_STRUCT_ID_PORT_DESCRIPTION 0xaUL - #define STRUCT_HDR_STRUCT_ID_RSS_V2 0x64UL - #define STRUCT_HDR_STRUCT_ID_MSIX_PER_VF 0xc8UL - #define STRUCT_HDR_STRUCT_ID_LAST STRUCT_HDR_STRUCT_ID_MSIX_PER_VF + #define STRUCT_HDR_STRUCT_ID_LLDP_CFG 0x41bUL + #define STRUCT_HDR_STRUCT_ID_DCBX_ETS 0x41dUL + #define STRUCT_HDR_STRUCT_ID_DCBX_PFC 0x41fUL + #define STRUCT_HDR_STRUCT_ID_DCBX_APP 0x421UL + #define STRUCT_HDR_STRUCT_ID_DCBX_FEATURE_STATE 0x422UL + #define STRUCT_HDR_STRUCT_ID_LLDP_GENERIC 0x424UL + #define STRUCT_HDR_STRUCT_ID_LLDP_DEVICE 0x426UL + #define STRUCT_HDR_STRUCT_ID_POWER_BKUP 0x427UL + #define STRUCT_HDR_STRUCT_ID_PEER_MMAP 0x429UL + #define STRUCT_HDR_STRUCT_ID_AFM_OPAQUE 0x1UL + #define STRUCT_HDR_STRUCT_ID_PORT_DESCRIPTION 0xaUL + #define STRUCT_HDR_STRUCT_ID_RSS_V2 0x64UL + #define STRUCT_HDR_STRUCT_ID_MSIX_PER_VF 0xc8UL + #define STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_COUNT 0x12cUL + #define STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_BOUND 0x12dUL + #define STRUCT_HDR_STRUCT_ID_LAST STRUCT_HDR_STRUCT_ID_UDCC_RTT_BUCKET_BOUND __le16 len; u8 version; u8 count; @@ -9756,6 +9816,7 @@ struct hwrm_dbg_qcaps_output { #define DBG_QCAPS_RESP_FLAGS_COREDUMP_HOST_DDR 0x10UL #define DBG_QCAPS_RESP_FLAGS_COREDUMP_HOST_CAPTURE 0x20UL #define DBG_QCAPS_RESP_FLAGS_PTRACE 0x40UL + #define DBG_QCAPS_RESP_FLAGS_REG_ACCESS_RESTRICTED 0x80UL u8 unused_1[3]; u8 valid; }; @@ -9996,6 +10057,43 @@ struct hwrm_dbg_ring_info_get_output { u8 valid; }; +/* hwrm_dbg_log_buffer_flush_input (size:192b/24B) */ +struct hwrm_dbg_log_buffer_flush_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + __le16 type; + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT_TRACE 0x0UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_SRT2_TRACE 0x1UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT_TRACE 0x2UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CRT2_TRACE 0x3UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP0_TRACE 0x4UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_L2_HWRM_TRACE 0x5UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_ROCE_HWRM_TRACE 0x6UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA0_TRACE 0x7UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA1_TRACE 0x8UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_CA2_TRACE 0x9UL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_RIGP1_TRACE 0xaUL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_AFM_KONG_HWRM_TRACE 0xbUL + #define DBG_LOG_BUFFER_FLUSH_REQ_TYPE_LAST DBG_LOG_BUFFER_FLUSH_REQ_TYPE_AFM_KONG_HWRM_TRACE + u8 unused_1[2]; + __le32 flags; + #define DBG_LOG_BUFFER_FLUSH_REQ_FLAGS_FLUSH_ALL_BUFFERS 0x1UL +}; + +/* hwrm_dbg_log_buffer_flush_output (size:128b/16B) */ +struct hwrm_dbg_log_buffer_flush_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + __le32 current_buffer_offset; + u8 unused_1[3]; + u8 valid; +}; + /* hwrm_nvm_read_input (size:320b/40B) */ struct hwrm_nvm_read_input { __le16 req_type; @@ -10080,6 +10178,7 @@ struct hwrm_nvm_write_input { #define NVM_WRITE_REQ_FLAGS_KEEP_ORIG_ACTIVE_IMG 0x1UL #define NVM_WRITE_REQ_FLAGS_BATCH_MODE 0x2UL #define NVM_WRITE_REQ_FLAGS_BATCH_LAST 0x4UL + #define NVM_WRITE_REQ_FLAGS_SKIP_CRID_CHECK 0x8UL __le32 dir_item_length; __le32 offset; __le32 len; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c index fa514be8765028..2d4e19b96ee744 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c @@ -67,15 +67,15 @@ static int bnxt_ptp_settime(struct ptp_clock_info *ptp_info, if (BNXT_PTP_USE_RTC(ptp->bp)) return bnxt_ptp_cfg_settime(ptp->bp, ns); - spin_lock_irqsave(&ptp->ptp_lock, flags); + write_seqlock_irqsave(&ptp->ptp_lock, flags); timecounter_init(&ptp->tc, &ptp->cc, ns); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + write_sequnlock_irqrestore(&ptp->ptp_lock, flags); return 0; } /* Caller holds ptp_lock */ -static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts, - u64 *ns) +static int __bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts, + u64 *ns) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; u32 high_before, high_now, low; @@ -98,17 +98,50 @@ static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts, return 0; } -static void bnxt_ptp_get_current_time(struct bnxt *bp) +static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts, + u64 *ns) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; unsigned long flags; + int rc; + + /* We have to serialize reg access and FW reset */ + read_seqlock_excl_irqsave(&ptp->ptp_lock, flags); + rc = __bnxt_refclk_read(bp, sts, ns); + read_sequnlock_excl_irqrestore(&ptp->ptp_lock, flags); + return rc; +} + +static int bnxt_refclk_read_low(struct bnxt *bp, struct ptp_system_timestamp *sts, + u32 *low) +{ + struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; + unsigned long flags; + + /* We have to serialize reg access and FW reset */ + read_seqlock_excl_irqsave(&ptp->ptp_lock, flags); + + if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) { + read_sequnlock_excl_irqrestore(&ptp->ptp_lock, flags); + return -EIO; + } + + ptp_read_system_prets(sts); + *low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]); + ptp_read_system_postts(sts); + + read_sequnlock_excl_irqrestore(&ptp->ptp_lock, flags); + return 0; +} + +static void bnxt_ptp_get_current_time(struct bnxt *bp) +{ + struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; if (!ptp) return; - spin_lock_irqsave(&ptp->ptp_lock, flags); - WRITE_ONCE(ptp->old_time, ptp->current_time); + WRITE_ONCE(ptp->old_time, ptp->current_time >> BNXT_HI_TIMER_SHIFT); bnxt_refclk_read(bp, NULL, &ptp->current_time); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); } static int bnxt_hwrm_port_ts_query(struct bnxt *bp, u32 flags, u64 *ts, @@ -151,36 +184,32 @@ static int bnxt_ptp_gettimex(struct ptp_clock_info *ptp_info, { struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg, ptp_info); - unsigned long flags; u64 ns, cycles; + u32 low; int rc; - spin_lock_irqsave(&ptp->ptp_lock, flags); - rc = bnxt_refclk_read(ptp->bp, sts, &cycles); - if (rc) { - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + rc = bnxt_refclk_read_low(ptp->bp, sts, &low); + if (rc) return rc; - } - ns = timecounter_cyc2time(&ptp->tc, cycles); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + + cycles = bnxt_extend_cycles_32b_to_48b(ptp, low); + ns = bnxt_timecounter_cyc2time(ptp, cycles); *ts = ns_to_timespec64(ns); return 0; } -/* Caller holds ptp_lock */ void bnxt_ptp_update_current_time(struct bnxt *bp) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; bnxt_refclk_read(ptp->bp, NULL, &ptp->current_time); - WRITE_ONCE(ptp->old_time, ptp->current_time); + WRITE_ONCE(ptp->old_time, ptp->current_time >> BNXT_HI_TIMER_SHIFT); } static int bnxt_ptp_adjphc(struct bnxt_ptp_cfg *ptp, s64 delta) { struct hwrm_port_mac_cfg_input *req; - unsigned long flags; int rc; rc = hwrm_req_init(ptp->bp, req, HWRM_PORT_MAC_CFG); @@ -194,9 +223,7 @@ static int bnxt_ptp_adjphc(struct bnxt_ptp_cfg *ptp, s64 delta) if (rc) { netdev_err(ptp->bp->dev, "ptp adjphc failed. rc = %x\n", rc); } else { - spin_lock_irqsave(&ptp->ptp_lock, flags); bnxt_ptp_update_current_time(ptp->bp); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); } return rc; @@ -211,9 +238,9 @@ static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta) if (BNXT_PTP_USE_RTC(ptp->bp)) return bnxt_ptp_adjphc(ptp, delta); - spin_lock_irqsave(&ptp->ptp_lock, flags); + write_seqlock_irqsave(&ptp->ptp_lock, flags); timecounter_adjtime(&ptp->tc, delta); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + write_sequnlock_irqrestore(&ptp->ptp_lock, flags); return 0; } @@ -246,10 +273,10 @@ static int bnxt_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) if (!BNXT_MH(bp)) return bnxt_ptp_adjfine_rtc(bp, scaled_ppm); - spin_lock_irqsave(&ptp->ptp_lock, flags); + write_seqlock_irqsave(&ptp->ptp_lock, flags); timecounter_read(&ptp->tc); ptp->cc.mult = adjust_by_scaled_ppm(ptp->cmult, scaled_ppm); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + write_sequnlock_irqrestore(&ptp->ptp_lock, flags); return 0; } @@ -257,13 +284,10 @@ void bnxt_ptp_pps_event(struct bnxt *bp, u32 data1, u32 data2) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; struct ptp_clock_event event; - unsigned long flags; u64 ns, pps_ts; pps_ts = EVENT_PPS_TS(data2, data1); - spin_lock_irqsave(&ptp->ptp_lock, flags); - ns = timecounter_cyc2time(&ptp->tc, pps_ts); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + ns = bnxt_timecounter_cyc2time(ptp, pps_ts); switch (EVENT_DATA2_PPS_EVENT_TYPE(data2)) { case ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_INTERNAL: @@ -400,17 +424,13 @@ static int bnxt_get_target_cycles(struct bnxt_ptp_cfg *ptp, u64 target_ns, { u64 cycles_now; u64 nsec_now, nsec_delta; - unsigned long flags; int rc; - spin_lock_irqsave(&ptp->ptp_lock, flags); rc = bnxt_refclk_read(ptp->bp, NULL, &cycles_now); - if (rc) { - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + if (rc) return rc; - } - nsec_now = timecounter_cyc2time(&ptp->tc, cycles_now); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + + nsec_now = bnxt_timecounter_cyc2time(ptp, cycles_now); nsec_delta = target_ns - nsec_now; *cycles_delta = div64_u64(nsec_delta << ptp->cc.shift, ptp->cc.mult); @@ -687,7 +707,7 @@ static u64 bnxt_cc_read(const struct cyclecounter *cc) struct bnxt_ptp_cfg *ptp = container_of(cc, struct bnxt_ptp_cfg, cc); u64 ns = 0; - bnxt_refclk_read(ptp->bp, NULL, &ns); + __bnxt_refclk_read(ptp->bp, NULL, &ns); return ns; } @@ -697,7 +717,6 @@ static int bnxt_stamp_tx_skb(struct bnxt *bp, int slot) struct skb_shared_hwtstamps timestamp; struct bnxt_ptp_tx_req *txts_req; unsigned long now = jiffies; - unsigned long flags; u64 ts = 0, ns = 0; u32 tmo = 0; int rc; @@ -711,9 +730,7 @@ static int bnxt_stamp_tx_skb(struct bnxt *bp, int slot) tmo, slot); if (!rc) { memset(×tamp, 0, sizeof(timestamp)); - spin_lock_irqsave(&ptp->ptp_lock, flags); - ns = timecounter_cyc2time(&ptp->tc, ts); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + ns = bnxt_timecounter_cyc2time(ptp, ts); timestamp.hwtstamp = ns_to_ktime(ns); skb_tstamp_tx(txts_req->tx_skb, ×tamp); ptp->stats.ts_pkts++; @@ -767,9 +784,9 @@ static long bnxt_ptp_ts_aux_work(struct ptp_clock_info *ptp_info) bnxt_ptp_get_current_time(bp); ptp->next_period = now + HZ; if (time_after_eq(now, ptp->next_overflow_check)) { - spin_lock_irqsave(&ptp->ptp_lock, flags); + write_seqlock_irqsave(&ptp->ptp_lock, flags); timecounter_read(&ptp->tc); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + write_sequnlock_irqrestore(&ptp->ptp_lock, flags); ptp->next_overflow_check = now + BNXT_PHC_OVERFLOW_PERIOD; } if (rc == -EAGAIN) @@ -808,15 +825,11 @@ void bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb, u16 prod) int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; - u64 time; if (!ptp) return -ENODEV; - BNXT_READ_TIME64(ptp, time, ptp->old_time); - *ts = (time & BNXT_HI_TIMER_MASK) | pkt_ts; - if (pkt_ts < (time & BNXT_LO_TIMER_MASK)) - *ts += BNXT_LO_TIMER_MASK + 1; + *ts = bnxt_extend_cycles_32b_to_48b(ptp, pkt_ts); return 0; } @@ -829,7 +842,6 @@ void bnxt_tx_ts_cmp(struct bnxt *bp, struct bnxt_napi *bnapi, u32 opaque = tscmp->tx_ts_cmp_opaque; struct bnxt_tx_ring_info *txr; struct bnxt_sw_tx_bd *tx_buf; - unsigned long flags; u64 ts, ns; u16 cons; @@ -844,9 +856,7 @@ void bnxt_tx_ts_cmp(struct bnxt *bp, struct bnxt_napi *bnapi, le32_to_cpu(tscmp->tx_ts_cmp_flags_type), le32_to_cpu(tscmp->tx_ts_cmp_errors_v)); } else { - spin_lock_irqsave(&ptp->ptp_lock, flags); - ns = timecounter_cyc2time(&ptp->tc, ts); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + ns = bnxt_timecounter_cyc2time(ptp, ts); timestamp.hwtstamp = ns_to_ktime(ns); skb_tstamp_tx(tx_buf->skb, ×tamp); } @@ -955,6 +965,7 @@ static bool bnxt_pps_config_ok(struct bnxt *bp) static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; + unsigned long flags; if (!ptp->ptp_clock) { memset(&ptp->cc, 0, sizeof(ptp->cc)); @@ -971,8 +982,11 @@ static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc) } ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD; } - if (init_tc) + if (init_tc) { + write_seqlock_irqsave(&ptp->ptp_lock, flags); timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real())); + write_sequnlock_irqrestore(&ptp->ptp_lock, flags); + } } /* Caller holds ptp_lock */ @@ -1005,9 +1019,9 @@ int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg) if (rc) return rc; } - spin_lock_irqsave(&bp->ptp_cfg->ptp_lock, flags); + write_seqlock_irqsave(&bp->ptp_cfg->ptp_lock, flags); bnxt_ptp_rtc_timecounter_init(bp->ptp_cfg, ns); - spin_unlock_irqrestore(&bp->ptp_cfg->ptp_lock, flags); + write_sequnlock_irqrestore(&bp->ptp_cfg->ptp_lock, flags); return 0; } @@ -1024,7 +1038,7 @@ static void bnxt_ptp_free(struct bnxt *bp) } } -int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg) +int bnxt_ptp_init(struct bnxt *bp) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; int rc; @@ -1042,12 +1056,12 @@ int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg) bnxt_ptp_free(bp); WRITE_ONCE(ptp->tx_avail, BNXT_MAX_TX_TS); - spin_lock_init(&ptp->ptp_lock); + seqlock_init(&ptp->ptp_lock); spin_lock_init(&ptp->ptp_tx_lock); if (BNXT_PTP_USE_RTC(bp)) { bnxt_ptp_timecounter_init(bp, false); - rc = bnxt_ptp_init_rtc(bp, phc_cfg); + rc = bnxt_ptp_init_rtc(bp, ptp->rtc_configured); if (rc) goto out; } else { @@ -1075,12 +1089,8 @@ int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg) atomic64_set(&ptp->stats.ts_err, 0); if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) { - unsigned long flags; - - spin_lock_irqsave(&ptp->ptp_lock, flags); bnxt_refclk_read(bp, NULL, &ptp->current_time); - WRITE_ONCE(ptp->old_time, ptp->current_time); - spin_unlock_irqrestore(&ptp->ptp_lock, flags); + WRITE_ONCE(ptp->old_time, ptp->current_time >> BNXT_HI_TIMER_SHIFT); ptp_schedule_worker(ptp->ptp_clock, 0); } ptp->txts_tmo = BNXT_PTP_DFLT_TX_TMO; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h index f322466ecad350..a95f05e9c579b7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h @@ -21,6 +21,7 @@ #define BNXT_DEVCLK_FREQ 1000000 #define BNXT_LO_TIMER_MASK 0x0000ffffffffUL #define BNXT_HI_TIMER_MASK 0xffff00000000UL +#define BNXT_HI_TIMER_SHIFT 24 #define BNXT_PTP_DFLT_TX_TMO 1000 /* ms */ #define BNXT_PTP_QTS_TIMEOUT 1000 @@ -102,14 +103,15 @@ struct bnxt_ptp_cfg { struct timecounter tc; struct bnxt_pps pps_info; /* serialize timecounter access */ - spinlock_t ptp_lock; + seqlock_t ptp_lock; /* serialize ts tx request queuing */ spinlock_t ptp_tx_lock; u64 current_time; - u64 old_time; unsigned long next_period; unsigned long next_overflow_check; u32 cmult; + /* cache of upper 24 bits of cyclecoutner. 8 bits are used to check for roll-over */ + u32 old_time; /* a 23b shift cyclecounter will overflow in ~36 mins. Check overflow every 18 mins. */ #define BNXT_PHC_OVERFLOW_PERIOD (18 * 60 * HZ) @@ -133,6 +135,7 @@ struct bnxt_ptp_cfg { BNXT_PTP_MSG_PDELAY_REQ | \ BNXT_PTP_MSG_PDELAY_RESP) u8 tx_tstamp_en:1; + u8 rtc_configured:1; int rx_filter; u32 tstamp_filters; @@ -145,20 +148,6 @@ struct bnxt_ptp_cfg { struct bnxt_ptp_stats stats; }; -#if BITS_PER_LONG == 32 -#define BNXT_READ_TIME64(ptp, dst, src) \ -do { \ - unsigned long flags; \ - \ - spin_lock_irqsave(&(ptp)->ptp_lock, flags); \ - (dst) = (src); \ - spin_unlock_irqrestore(&(ptp)->ptp_lock, flags); \ -} while (0) -#else -#define BNXT_READ_TIME64(ptp, dst, src) \ - ((dst) = READ_ONCE(src)) -#endif - #define BNXT_PTP_INC_TX_AVAIL(ptp) \ do { \ spin_lock_bh(&(ptp)->ptp_tx_lock); \ @@ -180,6 +169,29 @@ void bnxt_tx_ts_cmp(struct bnxt *bp, struct bnxt_napi *bnapi, struct tx_ts_cmp *tscmp); void bnxt_ptp_rtc_timecounter_init(struct bnxt_ptp_cfg *ptp, u64 ns); int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg); -int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg); +int bnxt_ptp_init(struct bnxt *bp); void bnxt_ptp_clear(struct bnxt *bp); +static inline u64 bnxt_timecounter_cyc2time(struct bnxt_ptp_cfg *ptp, u64 ts) +{ + unsigned int seq; + u64 ns; + + do { + seq = read_seqbegin(&ptp->ptp_lock); + ns = timecounter_cyc2time(&ptp->tc, ts); + } while (read_seqretry(&ptp->ptp_lock, seq)); + + return ns; +} + +static inline u64 bnxt_extend_cycles_32b_to_48b(struct bnxt_ptp_cfg *ptp, u32 ts) +{ + u64 time, cycles; + + time = (u64)READ_ONCE(ptp->old_time) << BNXT_HI_TIMER_SHIFT; + cycles = (time & BNXT_HI_TIMER_MASK) | ts; + if (ts < (time & BNXT_LO_TIMER_MASK)) + cycles += BNXT_LO_TIMER_MASK + 1; + return cycles; +} #endif diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index 7bb8a5d744308a..12b6ed51fd884c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -520,6 +520,56 @@ static int __bnxt_set_vf_params(struct bnxt *bp, int vf_id) return hwrm_req_send(bp, req); } +static void bnxt_hwrm_roce_sriov_cfg(struct bnxt *bp, int num_vfs) +{ + struct hwrm_func_qcaps_output *resp; + struct hwrm_func_cfg_input *cfg_req; + struct hwrm_func_qcaps_input *req; + int rc; + + rc = hwrm_req_init(bp, req, HWRM_FUNC_QCAPS); + if (rc) + return; + + req->fid = cpu_to_le16(0xffff); + resp = hwrm_req_hold(bp, req); + rc = hwrm_req_send(bp, req); + if (rc) + goto err; + + rc = hwrm_req_init(bp, cfg_req, HWRM_FUNC_CFG); + if (rc) + goto err; + + cfg_req->fid = cpu_to_le16(0xffff); + cfg_req->enables2 = + cpu_to_le32(FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF | + FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF | + FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF | + FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF | + FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF | + FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF); + cfg_req->roce_max_av_per_vf = + cpu_to_le32(le32_to_cpu(resp->roce_vf_max_av) / num_vfs); + cfg_req->roce_max_cq_per_vf = + cpu_to_le32(le32_to_cpu(resp->roce_vf_max_cq) / num_vfs); + cfg_req->roce_max_mrw_per_vf = + cpu_to_le32(le32_to_cpu(resp->roce_vf_max_mrw) / num_vfs); + cfg_req->roce_max_qp_per_vf = + cpu_to_le32(le32_to_cpu(resp->roce_vf_max_qp) / num_vfs); + cfg_req->roce_max_srq_per_vf = + cpu_to_le32(le32_to_cpu(resp->roce_vf_max_srq) / num_vfs); + cfg_req->roce_max_gid_per_vf = + cpu_to_le32(le32_to_cpu(resp->roce_vf_max_gid) / num_vfs); + + rc = hwrm_req_send(bp, cfg_req); + +err: + hwrm_req_drop(bp, req); + if (rc) + netdev_err(bp->dev, "RoCE sriov configuration failed\n"); +} + /* Only called by PF to reserve resources for VFs, returns actual number of * VFs configured, or < 0 on error. */ @@ -759,6 +809,9 @@ int bnxt_cfg_hw_sriov(struct bnxt *bp, int *num_vfs, bool reset) *num_vfs = rc; } + if (BNXT_RDMA_SRIOV_EN(bp) && BNXT_ROCE_VF_RESC_CAP(bp)) + bnxt_hwrm_roce_sriov_cfg(bp, *num_vfs); + return 0; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index fdd6356f21efb3..b771c84cdd8951 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -414,6 +414,8 @@ static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp) edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP; if (bp->flags & BNXT_FLAG_VF) edev->flags |= BNXT_EN_FLAG_VF; + if (BNXT_ROCE_VF_RESC_CAP(bp)) + edev->flags |= BNXT_EN_FLAG_ROCE_VF_RES_MGMT; edev->chip_num = bp->chip_num; edev->hw_ring_stats_size = bp->hw_ring_stats_size; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h index 4f4914f5c84c91..5d6aac60f23650 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h @@ -64,6 +64,7 @@ struct bnxt_en_dev { #define BNXT_EN_FLAG_ULP_STOPPED 0x8 #define BNXT_EN_FLAG_VF 0x10 #define BNXT_EN_VF(edev) ((edev)->flags & BNXT_EN_FLAG_VF) + #define BNXT_EN_FLAG_ROCE_VF_RES_MGMT 0x20 struct bnxt_ulp *ulp_tbl; int l2_db_size; /* Doorbell BAR size in diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index f7be886570d887..3e93f957430b2d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1144,14 +1144,14 @@ static int bcmgenet_get_sset_count(struct net_device *dev, int string_set) static void bcmgenet_get_strings(struct net_device *dev, u32 stringset, u8 *data) { + const char *str; int i; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < BCMGENET_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, - bcmgenet_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + str = bcmgenet_gstrings_stats[i].stat_string; + ethtool_puts(&data, str); } break; } @@ -2405,7 +2405,7 @@ static int bcmgenet_rx_poll(struct napi_struct *napi, int budget) if (ring->dim.use_dim) { dim_update_sample(ring->dim.event_ctr, ring->dim.packets, ring->dim.bytes, &dim_sample); - net_dim(&ring->dim.dim, dim_sample); + net_dim(&ring->dim.dim, &dim_sample); } return work_done; @@ -4350,7 +4350,7 @@ MODULE_DEVICE_TABLE(acpi, genet_acpi_match); static struct platform_driver bcmgenet_driver = { .probe = bcmgenet_probe, - .remove_new = bcmgenet_remove, + .remove = bcmgenet_remove, .shutdown = bcmgenet_shutdown, .driver = { .name = "bcmgenet", diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c index fcf8485f344602..30865fe03eeb28 100644 --- a/drivers/net/ethernet/broadcom/sb1250-mac.c +++ b/drivers/net/ethernet/broadcom/sb1250-mac.c @@ -2608,7 +2608,7 @@ static void sbmac_remove(struct platform_device *pldev) static struct platform_driver sbmac_driver = { .probe = sbmac_probe, - .remove_new = sbmac_remove, + .remove = sbmac_remove, .driver = { .name = sbmac_string, }, diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 37881591774175..9cc8db10a8d604 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -3737,7 +3737,7 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, } do { - u32 *fw_data = (u32 *)(fw_hdr + 1); + __be32 *fw_data = (__be32 *)(fw_hdr + 1); for (i = 0; i < tg3_fw_data_len(tp, fw_hdr); i++) write_op(tp, cpu_scratch_base + (be32_to_cpu(fw_hdr->base_addr) & 0xffff) + @@ -7395,27 +7395,60 @@ static int tg3_poll(struct napi_struct *napi, int budget) static void tg3_napi_disable(struct tg3 *tp) { + int txq_idx = tp->txq_cnt - 1; + int rxq_idx = tp->rxq_cnt - 1; + struct tg3_napi *tnapi; int i; - for (i = tp->irq_cnt - 1; i >= 0; i--) - napi_disable(&tp->napi[i].napi); + for (i = tp->irq_cnt - 1; i >= 0; i--) { + tnapi = &tp->napi[i]; + if (tnapi->tx_buffers) { + netif_queue_set_napi(tp->dev, txq_idx, + NETDEV_QUEUE_TYPE_TX, NULL); + txq_idx--; + } + if (tnapi->rx_rcb) { + netif_queue_set_napi(tp->dev, rxq_idx, + NETDEV_QUEUE_TYPE_RX, NULL); + rxq_idx--; + } + napi_disable(&tnapi->napi); + } } static void tg3_napi_enable(struct tg3 *tp) { + int txq_idx = 0, rxq_idx = 0; + struct tg3_napi *tnapi; int i; - for (i = 0; i < tp->irq_cnt; i++) - napi_enable(&tp->napi[i].napi); + for (i = 0; i < tp->irq_cnt; i++) { + tnapi = &tp->napi[i]; + napi_enable(&tnapi->napi); + if (tnapi->tx_buffers) { + netif_queue_set_napi(tp->dev, txq_idx, + NETDEV_QUEUE_TYPE_TX, + &tnapi->napi); + txq_idx++; + } + if (tnapi->rx_rcb) { + netif_queue_set_napi(tp->dev, rxq_idx, + NETDEV_QUEUE_TYPE_RX, + &tnapi->napi); + rxq_idx++; + } + } } static void tg3_napi_init(struct tg3 *tp) { int i; - netif_napi_add(tp->dev, &tp->napi[0].napi, tg3_poll); - for (i = 1; i < tp->irq_cnt; i++) - netif_napi_add(tp->dev, &tp->napi[i].napi, tg3_poll_msix); + for (i = 0; i < tp->irq_cnt; i++) { + netif_napi_add(tp->dev, &tp->napi[i].napi, + i ? tg3_poll_msix : tg3_poll); + netif_napi_set_irq(&tp->napi[i].napi, tp->napi[i].irq_vec); + } } static void tg3_napi_fini(struct tg3 *tp) @@ -11309,18 +11342,17 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num) else { name = &tnapi->irq_lbl[0]; if (tnapi->tx_buffers && tnapi->rx_rcb) - snprintf(name, IFNAMSIZ, + snprintf(name, sizeof(tnapi->irq_lbl), "%s-txrx-%d", tp->dev->name, irq_num); else if (tnapi->tx_buffers) - snprintf(name, IFNAMSIZ, + snprintf(name, sizeof(tnapi->irq_lbl), "%s-tx-%d", tp->dev->name, irq_num); else if (tnapi->rx_rcb) - snprintf(name, IFNAMSIZ, + snprintf(name, sizeof(tnapi->irq_lbl), "%s-rx-%d", tp->dev->name, irq_num); else - snprintf(name, IFNAMSIZ, + snprintf(name, sizeof(tnapi->irq_lbl), "%s-%d", tp->dev->name, irq_num); - name[IFNAMSIZ-1] = 0; } if (tg3_flag(tp, USING_MSI) || tg3_flag(tp, USING_MSIX)) { @@ -13093,12 +13125,16 @@ static int tg3_test_nvram(struct tg3 *tp) /* Bootstrap checksum at offset 0x10 */ csum = calc_crc((unsigned char *) buf, 0x10); - if (csum != le32_to_cpu(buf[0x10/4])) + + /* The type of buf is __be32 *, but this value is __le32 */ + if (csum != le32_to_cpu((__force __le32)buf[0x10 / 4])) goto out; /* Manufacturing block starts at offset 0x74, checksum at 0xfc */ - csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88); - if (csum != le32_to_cpu(buf[0xfc/4])) + csum = calc_crc((unsigned char *)&buf[0x74 / 4], 0x88); + + /* The type of buf is __be32 *, but this value is __le32 */ + if (csum != le32_to_cpu((__force __le32)buf[0xfc / 4])) goto out; kfree(buf); @@ -17065,12 +17101,14 @@ static int tg3_get_device_address(struct tg3 *tp, u8 *addr) addr_ok = is_valid_ether_addr(addr); } if (!addr_ok) { + __be32 be_hi, be_lo; + /* Next, try NVRAM. */ if (!tg3_flag(tp, NO_NVRAM) && - !tg3_nvram_read_be32(tp, mac_offset + 0, &hi) && - !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) { - memcpy(&addr[0], ((char *)&hi) + 2, 2); - memcpy(&addr[2], (char *)&lo, sizeof(lo)); + !tg3_nvram_read_be32(tp, mac_offset + 0, &be_hi) && + !tg3_nvram_read_be32(tp, mac_offset + 4, &be_lo)) { + memcpy(&addr[0], ((char *)&be_hi) + 2, 2); + memcpy(&addr[2], (char *)&be_lo, sizeof(be_lo)); } /* Finally just fetch it out of the MAC control regs. */ else { @@ -17801,6 +17839,9 @@ static int tg3_init_one(struct pci_dev *pdev, } else persist_dma_mask = dma_mask = DMA_BIT_MASK(64); + if (tg3_asic_rev(tp) == ASIC_REV_57766) + persist_dma_mask = DMA_BIT_MASK(31); + /* Configure DMA attributes. */ if (dma_mask > DMA_BIT_MASK(32)) { err = dma_set_mask(&pdev->dev, dma_mask); @@ -18237,7 +18278,7 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, * @pdev: Pointer to PCI device * * Restart the card from scratch, as if from a cold-boot. - * At this point, the card has exprienced a hard reset, + * At this point, the card has experienced a hard reset, * followed by fixups by BIOS, and has its config space * set up identically to what it was at cold boot. */ diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index cf1b2b123c7ee9..b473f8014d9c0d 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -3033,7 +3033,7 @@ struct tg3_napi { dma_addr_t rx_rcb_mapping; dma_addr_t tx_desc_mapping; - char irq_lbl[IFNAMSIZ]; + char irq_lbl[IFNAMSIZ + 6 + 10]; /* name + "-txrx-" + %d */ unsigned int irq_vec; }; diff --git a/drivers/net/ethernet/brocade/bna/bnad.h b/drivers/net/ethernet/brocade/bna/bnad.h index 10b1e534030e62..4396997c59d041 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.h +++ b/drivers/net/ethernet/brocade/bna/bnad.h @@ -351,7 +351,6 @@ struct bnad { /* debugfs specific data */ char *regdata; u32 reglen; - struct dentry *bnad_dentry_files[5]; struct dentry *port_debugfs_root; }; diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c index 97291bfbeea589..8f0972e6737c12 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c +++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c @@ -500,11 +500,6 @@ bnad_debugfs_init(struct bnad *bnad) if (!bna_debugfs_root) { bna_debugfs_root = debugfs_create_dir("bna", NULL); atomic_set(&bna_debugfs_port_count, 0); - if (!bna_debugfs_root) { - netdev_warn(bnad->netdev, - "debugfs root dir creation failed\n"); - return; - } } /* Setup the pci_dev debugfs directory for the port */ @@ -517,18 +512,11 @@ bnad_debugfs_init(struct bnad *bnad) for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { file = &bnad_debugfs_files[i]; - bnad->bnad_dentry_files[i] = - debugfs_create_file(file->name, - file->mode, - bnad->port_debugfs_root, - bnad, - file->fops); - if (!bnad->bnad_dentry_files[i]) { - netdev_warn(bnad->netdev, - "create %s entry failed\n", - file->name); - return; - } + debugfs_create_file(file->name, + file->mode, + bnad->port_debugfs_root, + bnad, + file->fops); } } } @@ -537,15 +525,6 @@ bnad_debugfs_init(struct bnad *bnad) void bnad_debugfs_uninit(struct bnad *bnad) { - int i; - - for (i = 0; i < ARRAY_SIZE(bnad_debugfs_files); i++) { - if (bnad->bnad_dentry_files[i]) { - debugfs_remove(bnad->bnad_dentry_files[i]); - bnad->bnad_dentry_files[i] = NULL; - } - } - /* Remove the pci_dev debugfs directory for the port */ if (bnad->port_debugfs_root) { debugfs_remove(bnad->port_debugfs_root); diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 56901280ba0472..daa416fb1724e9 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -915,20 +915,15 @@ static int macb_mii_probe(struct net_device *dev) return 0; } -static int macb_mdiobus_register(struct macb *bp) +static int macb_mdiobus_register(struct macb *bp, struct device_node *mdio_np) { struct device_node *child, *np = bp->pdev->dev.of_node; /* If we have a child named mdio, probe it instead of looking for PHYs * directly under the MAC node */ - child = of_get_child_by_name(np, "mdio"); - if (child) { - int ret = of_mdiobus_register(bp->mii_bus, child); - - of_node_put(child); - return ret; - } + if (mdio_np) + return of_mdiobus_register(bp->mii_bus, mdio_np); /* Only create the PHY from the device tree if at least one PHY is * described. Otherwise scan the entire MDIO bus. We do this to support @@ -950,17 +945,15 @@ static int macb_mdiobus_register(struct macb *bp) static int macb_mii_init(struct macb *bp) { - struct device_node *child, *np = bp->pdev->dev.of_node; + struct device_node *mdio_np, *np = bp->pdev->dev.of_node; int err = -ENXIO; /* With fixed-link, we don't need to register the MDIO bus, * except if we have a child named "mdio" in the device tree. * In that case, some devices may be attached to the MACB's MDIO bus. */ - child = of_get_child_by_name(np, "mdio"); - if (child) - of_node_put(child); - else if (of_phy_is_fixed_link(np)) + mdio_np = of_get_child_by_name(np, "mdio"); + if (!mdio_np && of_phy_is_fixed_link(np)) return macb_mii_probe(bp->dev); /* Enable management port */ @@ -984,7 +977,7 @@ static int macb_mii_init(struct macb *bp) dev_set_drvdata(&bp->dev->dev, bp->mii_bus); - err = macb_mdiobus_register(bp); + err = macb_mdiobus_register(bp, mdio_np); if (err) goto err_out_free_mdiobus; @@ -999,6 +992,8 @@ static int macb_mii_init(struct macb *bp) err_out_free_mdiobus: mdiobus_free(bp->mii_bus); err_out: + of_node_put(mdio_np); + return err; } @@ -4849,10 +4844,11 @@ static const struct macb_config pc302gem_config = { }; static const struct macb_config sama5d2_config = { - .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII, + .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_JUMBO, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, + .jumbo_max_len = 10240, .usrio = &macb_default_usrio, }; @@ -5490,7 +5486,7 @@ static const struct dev_pm_ops macb_pm_ops = { static struct platform_driver macb_driver = { .probe = macb_probe, - .remove_new = macb_remove, + .remove = macb_remove, .driver = { .name = "macb", .of_match_table = of_match_ptr(macb_dt_ids), diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index a71b320fd0308b..331ac6a3dc382e 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -1919,7 +1919,7 @@ static struct platform_driver xgmac_driver = { .pm = &xgmac_pm_ops, }, .probe = xgmac_probe, - .remove_new = xgmac_remove, + .remove = xgmac_remove, }; module_platform_driver(xgmac_driver); diff --git a/drivers/net/ethernet/cavium/common/cavium_ptp.c b/drivers/net/ethernet/cavium/common/cavium_ptp.c index 9fd717b9cf69ec..984f0dd7b62e19 100644 --- a/drivers/net/ethernet/cavium/common/cavium_ptp.c +++ b/drivers/net/ethernet/cavium/common/cavium_ptp.c @@ -239,12 +239,11 @@ static int cavium_ptp_probe(struct pci_dev *pdev, if (err) goto error_free; - err = pcim_iomap_regions(pdev, 1 << PCI_PTP_BAR_NO, pci_name(pdev)); + clock->reg_base = pcim_iomap_region(pdev, PCI_PTP_BAR_NO, pci_name(pdev)); + err = PTR_ERR_OR_ZERO(clock->reg_base); if (err) goto error_free; - clock->reg_base = pcim_iomap_table(pdev)[PCI_PTP_BAR_NO]; - spin_lock_init(&clock->spin_lock); cc = &clock->cycle_counter; @@ -292,7 +291,7 @@ static int cavium_ptp_probe(struct pci_dev *pdev, clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG); clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN; writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG); - pcim_iounmap_regions(pdev, 1 << PCI_PTP_BAR_NO); + pcim_iounmap_region(pdev, PCI_PTP_BAR_NO); error_free: devm_kfree(dev, clock); diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index b3c81a2e9d4643..9ad49aea2673b6 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -36,175 +36,6 @@ */ #define CN23XX_INPUT_JABBER 64600 -void cn23xx_dump_pf_initialized_regs(struct octeon_device *oct) -{ - int i = 0; - u32 regval = 0; - struct octeon_cn23xx_pf *cn23xx = (struct octeon_cn23xx_pf *)oct->chip; - - /*In cn23xx_soft_reset*/ - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%llx\n", - "CN23XX_WIN_WR_MASK_REG", CVM_CAST64(CN23XX_WIN_WR_MASK_REG), - CVM_CAST64(octeon_read_csr64(oct, CN23XX_WIN_WR_MASK_REG))); - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "CN23XX_SLI_SCRATCH1", CVM_CAST64(CN23XX_SLI_SCRATCH1), - CVM_CAST64(octeon_read_csr64(oct, CN23XX_SLI_SCRATCH1))); - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "CN23XX_RST_SOFT_RST", CN23XX_RST_SOFT_RST, - lio_pci_readq(oct, CN23XX_RST_SOFT_RST)); - - /*In cn23xx_set_dpi_regs*/ - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "CN23XX_DPI_DMA_CONTROL", CN23XX_DPI_DMA_CONTROL, - lio_pci_readq(oct, CN23XX_DPI_DMA_CONTROL)); - - for (i = 0; i < 6; i++) { - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_DPI_DMA_ENG_ENB", i, - CN23XX_DPI_DMA_ENG_ENB(i), - lio_pci_readq(oct, CN23XX_DPI_DMA_ENG_ENB(i))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_DPI_DMA_ENG_BUF", i, - CN23XX_DPI_DMA_ENG_BUF(i), - lio_pci_readq(oct, CN23XX_DPI_DMA_ENG_BUF(i))); - } - - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", "CN23XX_DPI_CTL", - CN23XX_DPI_CTL, lio_pci_readq(oct, CN23XX_DPI_CTL)); - - /*In cn23xx_setup_pcie_mps and cn23xx_setup_pcie_mrrs */ - pci_read_config_dword(oct->pci_dev, CN23XX_CONFIG_PCIE_DEVCTL, ®val); - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "CN23XX_CONFIG_PCIE_DEVCTL", - CVM_CAST64(CN23XX_CONFIG_PCIE_DEVCTL), CVM_CAST64(regval)); - - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_DPI_SLI_PRTX_CFG", oct->pcie_port, - CN23XX_DPI_SLI_PRTX_CFG(oct->pcie_port), - lio_pci_readq(oct, CN23XX_DPI_SLI_PRTX_CFG(oct->pcie_port))); - - /*In cn23xx_specific_regs_setup */ - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_S2M_PORTX_CTL", oct->pcie_port, - CVM_CAST64(CN23XX_SLI_S2M_PORTX_CTL(oct->pcie_port)), - CVM_CAST64(octeon_read_csr64( - oct, CN23XX_SLI_S2M_PORTX_CTL(oct->pcie_port)))); - - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "CN23XX_SLI_RING_RST", CVM_CAST64(CN23XX_SLI_PKT_IOQ_RING_RST), - (u64)octeon_read_csr64(oct, CN23XX_SLI_PKT_IOQ_RING_RST)); - - /*In cn23xx_setup_global_mac_regs*/ - for (i = 0; i < CN23XX_MAX_MACS; i++) { - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_PKT_MAC_RINFO64", i, - CVM_CAST64(CN23XX_SLI_PKT_MAC_RINFO64(i, oct->pf_num)), - CVM_CAST64(octeon_read_csr64 - (oct, CN23XX_SLI_PKT_MAC_RINFO64 - (i, oct->pf_num)))); - } - - /*In cn23xx_setup_global_input_regs*/ - for (i = 0; i < CN23XX_MAX_INPUT_QUEUES; i++) { - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_IQ_PKT_CONTROL64", i, - CVM_CAST64(CN23XX_SLI_IQ_PKT_CONTROL64(i)), - CVM_CAST64(octeon_read_csr64 - (oct, CN23XX_SLI_IQ_PKT_CONTROL64(i)))); - } - - /*In cn23xx_setup_global_output_regs*/ - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "CN23XX_SLI_OQ_WMARK", CVM_CAST64(CN23XX_SLI_OQ_WMARK), - CVM_CAST64(octeon_read_csr64(oct, CN23XX_SLI_OQ_WMARK))); - - for (i = 0; i < CN23XX_MAX_OUTPUT_QUEUES; i++) { - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_OQ_PKT_CONTROL", i, - CVM_CAST64(CN23XX_SLI_OQ_PKT_CONTROL(i)), - CVM_CAST64(octeon_read_csr( - oct, CN23XX_SLI_OQ_PKT_CONTROL(i)))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_OQ_PKT_INT_LEVELS", i, - CVM_CAST64(CN23XX_SLI_OQ_PKT_INT_LEVELS(i)), - CVM_CAST64(octeon_read_csr64( - oct, CN23XX_SLI_OQ_PKT_INT_LEVELS(i)))); - } - - /*In cn23xx_enable_interrupt and cn23xx_disable_interrupt*/ - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "cn23xx->intr_enb_reg64", - CVM_CAST64((long)(cn23xx->intr_enb_reg64)), - CVM_CAST64(readq(cn23xx->intr_enb_reg64))); - - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "cn23xx->intr_sum_reg64", - CVM_CAST64((long)(cn23xx->intr_sum_reg64)), - CVM_CAST64(readq(cn23xx->intr_sum_reg64))); - - /*In cn23xx_setup_iq_regs*/ - for (i = 0; i < CN23XX_MAX_INPUT_QUEUES; i++) { - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_IQ_BASE_ADDR64", i, - CVM_CAST64(CN23XX_SLI_IQ_BASE_ADDR64(i)), - CVM_CAST64(octeon_read_csr64( - oct, CN23XX_SLI_IQ_BASE_ADDR64(i)))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_IQ_SIZE", i, - CVM_CAST64(CN23XX_SLI_IQ_SIZE(i)), - CVM_CAST64(octeon_read_csr - (oct, CN23XX_SLI_IQ_SIZE(i)))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_IQ_DOORBELL", i, - CVM_CAST64(CN23XX_SLI_IQ_DOORBELL(i)), - CVM_CAST64(octeon_read_csr64( - oct, CN23XX_SLI_IQ_DOORBELL(i)))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_IQ_INSTR_COUNT64", i, - CVM_CAST64(CN23XX_SLI_IQ_INSTR_COUNT64(i)), - CVM_CAST64(octeon_read_csr64( - oct, CN23XX_SLI_IQ_INSTR_COUNT64(i)))); - } - - /*In cn23xx_setup_oq_regs*/ - for (i = 0; i < CN23XX_MAX_OUTPUT_QUEUES; i++) { - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_OQ_BASE_ADDR64", i, - CVM_CAST64(CN23XX_SLI_OQ_BASE_ADDR64(i)), - CVM_CAST64(octeon_read_csr64( - oct, CN23XX_SLI_OQ_BASE_ADDR64(i)))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_OQ_SIZE", i, - CVM_CAST64(CN23XX_SLI_OQ_SIZE(i)), - CVM_CAST64(octeon_read_csr - (oct, CN23XX_SLI_OQ_SIZE(i)))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_OQ_BUFF_INFO_SIZE", i, - CVM_CAST64(CN23XX_SLI_OQ_BUFF_INFO_SIZE(i)), - CVM_CAST64(octeon_read_csr( - oct, CN23XX_SLI_OQ_BUFF_INFO_SIZE(i)))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_OQ_PKTS_SENT", i, - CVM_CAST64(CN23XX_SLI_OQ_PKTS_SENT(i)), - CVM_CAST64(octeon_read_csr64( - oct, CN23XX_SLI_OQ_PKTS_SENT(i)))); - dev_dbg(&oct->pci_dev->dev, "%s(%d)[%llx] : 0x%016llx\n", - "CN23XX_SLI_OQ_PKTS_CREDIT", i, - CVM_CAST64(CN23XX_SLI_OQ_PKTS_CREDIT(i)), - CVM_CAST64(octeon_read_csr64( - oct, CN23XX_SLI_OQ_PKTS_CREDIT(i)))); - } - - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "CN23XX_SLI_PKT_TIME_INT", - CVM_CAST64(CN23XX_SLI_PKT_TIME_INT), - CVM_CAST64(octeon_read_csr64(oct, CN23XX_SLI_PKT_TIME_INT))); - dev_dbg(&oct->pci_dev->dev, "%s[%llx] : 0x%016llx\n", - "CN23XX_SLI_PKT_CNT_INT", - CVM_CAST64(CN23XX_SLI_PKT_CNT_INT), - CVM_CAST64(octeon_read_csr64(oct, CN23XX_SLI_PKT_CNT_INT))); -} - static int cn23xx_pf_soft_reset(struct octeon_device *oct) { octeon_write_csr64(oct, CN23XX_WIN_WR_MASK_REG, 0xFF); diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.h b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.h index e6f31d0d5c0b66..234b96b4f48870 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.h +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.h @@ -59,8 +59,6 @@ int validate_cn23xx_pf_config_info(struct octeon_device *oct, u32 cn23xx_pf_get_oq_ticks(struct octeon_device *oct, u32 time_intr_in_us); -void cn23xx_dump_pf_initialized_regs(struct octeon_device *oct); - int cn23xx_sriov_config(struct octeon_device *oct); int cn23xx_fw_loaded(struct octeon_device *oct); diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c index 744f2434f7fa54..393b9951490a18 100644 --- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c @@ -1545,7 +1545,7 @@ static struct platform_driver octeon_mgmt_driver = { .of_match_table = octeon_mgmt_match, }, .probe = octeon_mgmt_probe, - .remove_new = octeon_mgmt_remove, + .remove = octeon_mgmt_remove, }; module_platform_driver(octeon_mgmt_driver); diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c index 89256b86684032..5a9f6925e1fa7f 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c @@ -515,23 +515,6 @@ void *cxgb3_free_atid(struct t3cdev *tdev, int atid) EXPORT_SYMBOL(cxgb3_free_atid); -/* - * Free a server TID and return it to the free pool. - */ -void cxgb3_free_stid(struct t3cdev *tdev, int stid) -{ - struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; - union listen_entry *p = stid2entry(t, stid); - - spin_lock_bh(&t->stid_lock); - p->next = t->sfree; - t->sfree = p; - t->stids_in_use--; - spin_unlock_bh(&t->stid_lock); -} - -EXPORT_SYMBOL(cxgb3_free_stid); - void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client, void *ctx, unsigned int tid) { @@ -671,28 +654,6 @@ int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client, EXPORT_SYMBOL(cxgb3_alloc_atid); -int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client, - void *ctx) -{ - int stid = -1; - struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; - - spin_lock_bh(&t->stid_lock); - if (t->sfree) { - union listen_entry *p = t->sfree; - - stid = (p - t->stid_tab) + t->stid_base; - t->sfree = p->next; - p->t3c_tid.ctx = ctx; - p->t3c_tid.client = client; - t->stids_in_use++; - } - spin_unlock_bh(&t->stid_lock); - return stid; -} - -EXPORT_SYMBOL(cxgb3_alloc_stid); - /* Get the t3cdev associated with a net_device */ struct t3cdev *dev2t3cdev(struct net_device *dev) { diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h index 929c298115ca18..7419824f992620 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.h @@ -95,10 +95,7 @@ struct cxgb3_client { */ int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client, void *ctx); -int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client, - void *ctx); void *cxgb3_free_atid(struct t3cdev *dev, int atid); -void cxgb3_free_stid(struct t3cdev *dev, int stid); void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client, void *ctx, unsigned int tid); void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid); diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c index 163efab27e9b8e..5060d399888903 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c @@ -120,7 +120,7 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) write_unlock_bh(&ctbl->lock); dev_err(adap->pdev_dev, "CLIP FW cmd failed with error %d, " - "Connections using %pI6c wont be " + "Connections using %pI6c won't be " "offloaded", ret, ce->addr6.sin6_addr.s6_addr); return ret; @@ -133,7 +133,7 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) } else { write_unlock_bh(&ctbl->lock); dev_info(adap->pdev_dev, "CLIP table overflow, " - "Connections using %pI6c wont be offloaded", + "Connections using %pI6c won't be offloaded", (void *)lip); return -ENOMEM; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index bbf7641a0fc799..c7c2c15a18155e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1608,7 +1608,6 @@ void t4_os_portmod_changed(struct adapter *adap, int port_id); void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat); void t4_free_sge_resources(struct adapter *adap); -void t4_free_ofld_rxqs(struct adapter *adap, int n, struct sge_ofld_rxq *q); irq_handler_t t4_intr_handler(struct adapter *adap); netdev_tx_t t4_start_xmit(struct sk_buff *skb, struct net_device *dev); int cxgb4_selftest_lb_pkt(struct net_device *netdev); @@ -2077,7 +2076,7 @@ void t4_idma_monitor(struct adapter *adapter, struct sge_idma_monitor_state *idma, int hz, int ticks); int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, - unsigned int naddr, u8 *addr); + u8 start, unsigned int naddr, u8 *addr); void t4_tp_pio_read(struct adapter *adap, u32 *buff, u32 nregs, u32 start_index, bool sleep_ok); void t4_tp_tm_pio_read(struct adapter *adap, u32 *buff, u32 nregs, @@ -2141,28 +2140,6 @@ int cxgb4_free_mac_filt(struct adapter *adap, unsigned int viid, unsigned int naddr, const u8 **addr, bool sleep_ok); int cxgb4_init_mps_ref_entries(struct adapter *adap); void cxgb4_free_mps_ref_entries(struct adapter *adap); -int cxgb4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid, - const u8 *addr, const u8 *mask, - unsigned int vni, unsigned int vni_mask, - u8 dip_hit, u8 lookup_type, bool sleep_ok); -int cxgb4_free_encap_mac_filt(struct adapter *adap, unsigned int viid, - int idx, bool sleep_ok); -int cxgb4_free_raw_mac_filt(struct adapter *adap, - unsigned int viid, - const u8 *addr, - const u8 *mask, - unsigned int idx, - u8 lookup_type, - u8 port_id, - bool sleep_ok); -int cxgb4_alloc_raw_mac_filt(struct adapter *adap, - unsigned int viid, - const u8 *addr, - const u8 *mask, - unsigned int idx, - u8 lookup_type, - u8 port_id, - bool sleep_ok); int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid, int *tcam_idx, const u8 *addr, bool persistent, u8 *smt_idx); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 2418645c882373..bc3af005440643 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2188,18 +2188,6 @@ void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, } EXPORT_SYMBOL(cxgb4_get_tcp_stats); -void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, - const unsigned int *pgsz_order) -{ - struct adapter *adap = netdev2adap(dev); - - t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK_A, tag_mask); - t4_write_reg(adap, ULP_RX_ISCSI_PSZ_A, HPZ0_V(pgsz_order[0]) | - HPZ1_V(pgsz_order[1]) | HPZ2_V(pgsz_order[2]) | - HPZ3_V(pgsz_order[3])); -} -EXPORT_SYMBOL(cxgb4_iscsi_init); - int cxgb4_flush_eq_cache(struct net_device *dev) { struct adapter *adap = netdev2adap(dev); @@ -3246,7 +3234,7 @@ static int cxgb4_mgmt_set_vf_mac(struct net_device *dev, int vf, u8 *mac) dev_info(pi->adapter->pdev_dev, "Setting MAC %pM on VF %d\n", mac, vf); - ret = t4_set_vf_mac_acl(adap, vf + 1, 1, mac); + ret = t4_set_vf_mac_acl(adap, vf + 1, pi->lport, 1, mac); if (!ret) ether_addr_copy(adap->vfinfo[vf].vf_mac_addr, mac); return ret; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c index a020e84906813f..60f4d5b5eb3a41 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_mps.c @@ -28,28 +28,6 @@ static int cxgb4_mps_ref_dec_by_mac(struct adapter *adap, return ret; } -static int cxgb4_mps_ref_dec(struct adapter *adap, u16 idx) -{ - struct mps_entries_ref *mps_entry, *tmp; - int ret = -EINVAL; - - spin_lock(&adap->mps_ref_lock); - list_for_each_entry_safe(mps_entry, tmp, &adap->mps_ref, list) { - if (mps_entry->idx == idx) { - if (!refcount_dec_and_test(&mps_entry->refcnt)) { - spin_unlock(&adap->mps_ref_lock); - return -EBUSY; - } - list_del(&mps_entry->list); - kfree(mps_entry); - ret = 0; - break; - } - } - spin_unlock(&adap->mps_ref_lock); - return ret; -} - static int cxgb4_mps_ref_inc(struct adapter *adap, const u8 *mac_addr, u16 idx, const u8 *mask) { @@ -141,82 +119,6 @@ int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid, return ret; } -int cxgb4_free_raw_mac_filt(struct adapter *adap, - unsigned int viid, - const u8 *addr, - const u8 *mask, - unsigned int idx, - u8 lookup_type, - u8 port_id, - bool sleep_ok) -{ - int ret = 0; - - if (!cxgb4_mps_ref_dec(adap, idx)) - ret = t4_free_raw_mac_filt(adap, viid, addr, - mask, idx, lookup_type, - port_id, sleep_ok); - - return ret; -} - -int cxgb4_alloc_raw_mac_filt(struct adapter *adap, - unsigned int viid, - const u8 *addr, - const u8 *mask, - unsigned int idx, - u8 lookup_type, - u8 port_id, - bool sleep_ok) -{ - int ret; - - ret = t4_alloc_raw_mac_filt(adap, viid, addr, - mask, idx, lookup_type, - port_id, sleep_ok); - if (ret < 0) - return ret; - - if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) { - ret = -ENOMEM; - t4_free_raw_mac_filt(adap, viid, addr, - mask, idx, lookup_type, - port_id, sleep_ok); - } - - return ret; -} - -int cxgb4_free_encap_mac_filt(struct adapter *adap, unsigned int viid, - int idx, bool sleep_ok) -{ - int ret = 0; - - if (!cxgb4_mps_ref_dec(adap, idx)) - ret = t4_free_encap_mac_filt(adap, viid, idx, sleep_ok); - - return ret; -} - -int cxgb4_alloc_encap_mac_filt(struct adapter *adap, unsigned int viid, - const u8 *addr, const u8 *mask, - unsigned int vni, unsigned int vni_mask, - u8 dip_hit, u8 lookup_type, bool sleep_ok) -{ - int ret; - - ret = t4_alloc_encap_mac_filt(adap, viid, addr, mask, vni, vni_mask, - dip_hit, lookup_type, sleep_ok); - if (ret < 0) - return ret; - - if (cxgb4_mps_ref_inc(adap, addr, ret, mask)) { - ret = -ENOMEM; - t4_free_encap_mac_filt(adap, viid, ret, sleep_ok); - } - return ret; -} - int cxgb4_init_mps_ref_entries(struct adapter *adap) { spin_lock_init(&adap->mps_ref_lock); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index d8cafaa7ddb4f8..d7713038386c89 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -518,8 +518,6 @@ unsigned int cxgb4_best_aligned_mtu(const unsigned short *mtus, unsigned int *mtu_idxp); void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4, struct tp_tcp_stats *v6); -void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask, - const unsigned int *pgsz_order); struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl, unsigned int skb_len, unsigned int pull_len); int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, u16 size); diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 1e5f5b1a22a6de..c02b4e9c06b231 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -608,25 +608,6 @@ struct l2t_entry *t4_l2t_alloc_switching(struct adapter *adap, u16 vlan, return e; } -/** - * cxgb4_l2t_alloc_switching - Allocates an L2T entry for switch filters - * @dev: net_device pointer - * @vlan: VLAN Id - * @port: Associated port - * @dmac: Destination MAC address to add to L2T - * Returns pointer to the allocated l2t entry - * - * Allocates an L2T entry for use by switching rule of a filter - */ -struct l2t_entry *cxgb4_l2t_alloc_switching(struct net_device *dev, u16 vlan, - u8 port, u8 *dmac) -{ - struct adapter *adap = netdev2adap(dev); - - return t4_l2t_alloc_switching(adap, vlan, port, dmac); -} -EXPORT_SYMBOL(cxgb4_l2t_alloc_switching); - struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end) { unsigned int l2t_size; diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.h b/drivers/net/ethernet/chelsio/cxgb4/l2t.h index 340fecb28a137b..8aad7e9dee6d52 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.h +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.h @@ -115,8 +115,6 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, unsigned int priority); u64 cxgb4_select_ntuple(struct net_device *dev, const struct l2t_entry *l2t); -struct l2t_entry *cxgb4_l2t_alloc_switching(struct net_device *dev, u16 vlan, - u8 port, u8 *dmac); void t4_l2t_update(struct adapter *adap, struct neighbour *neigh); struct l2t_entry *t4_l2t_alloc_switching(struct adapter *adap, u16 vlan, u8 port, u8 *dmac); diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index de52bcb884c417..a7d76a8ed05020 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -4874,22 +4874,6 @@ void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, } } -/** - * t4_free_ofld_rxqs - free a block of consecutive Rx queues - * @adap: the adapter - * @n: number of queues - * @q: pointer to first queue - * - * Release the resources of a consecutive block of offload Rx queues. - */ -void t4_free_ofld_rxqs(struct adapter *adap, int n, struct sge_ofld_rxq *q) -{ - for ( ; n; n--, q++) - if (q->rspq.desc) - free_rspq_fl(adap, &q->rspq, - q->fl.size ? &q->fl : NULL); -} - void t4_sge_free_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq) { if (txq->q.desc) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/srq.c b/drivers/net/ethernet/chelsio/cxgb4/srq.c index 9a54302bb046dc..a77d6ac1ee8c3f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/srq.c +++ b/drivers/net/ethernet/chelsio/cxgb4/srq.c @@ -51,64 +51,6 @@ struct srq_data *t4_init_srq(int srq_size) return s; } -/* cxgb4_get_srq_entry: read the SRQ table entry - * @dev: Pointer to the net_device - * @idx: Index to the srq - * @entryp: pointer to the srq entry - * - * Sends CPL_SRQ_TABLE_REQ message for the given index. - * Contents will be returned in CPL_SRQ_TABLE_RPL message. - * - * Returns zero if the read is successful, else a error - * number will be returned. Caller should not use the srq - * entry if the return value is non-zero. - * - * - */ -int cxgb4_get_srq_entry(struct net_device *dev, - int srq_idx, struct srq_entry *entryp) -{ - struct cpl_srq_table_req *req; - struct adapter *adap; - struct sk_buff *skb; - struct srq_data *s; - int rc = -ENODEV; - - adap = netdev2adap(dev); - s = adap->srq; - - if (!(adap->flags & CXGB4_FULL_INIT_DONE) || !s) - goto out; - - skb = alloc_skb(sizeof(*req), GFP_KERNEL); - if (!skb) - return -ENOMEM; - req = (struct cpl_srq_table_req *) - __skb_put_zero(skb, sizeof(*req)); - INIT_TP_WR(req, 0); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SRQ_TABLE_REQ, - TID_TID_V(srq_idx) | - TID_QID_V(adap->sge.fw_evtq.abs_id))); - req->idx = srq_idx; - - mutex_lock(&s->lock); - - s->entryp = entryp; - t4_mgmt_tx(adap, skb); - - rc = wait_for_completion_timeout(&s->comp, SRQ_WAIT_TO); - if (rc) - rc = 0; - else /* !rc means we timed out */ - rc = -ETIMEDOUT; - - WARN_ON_ONCE(entryp->idx != srq_idx); - mutex_unlock(&s->lock); -out: - return rc; -} -EXPORT_SYMBOL(cxgb4_get_srq_entry); - void do_srq_table_rpl(struct adapter *adap, const struct cpl_srq_table_rpl *rpl) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/srq.h b/drivers/net/ethernet/chelsio/cxgb4/srq.h index ec85cf93865a80..d9f04bd5ffa338 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/srq.h +++ b/drivers/net/ethernet/chelsio/cxgb4/srq.h @@ -58,8 +58,6 @@ struct srq_data { }; struct srq_data *t4_init_srq(int srq_size); -int cxgb4_get_srq_entry(struct net_device *dev, - int srq_idx, struct srq_entry *entryp); void do_srq_table_rpl(struct adapter *adap, const struct cpl_srq_table_rpl *rpl); #endif /* __CXGB4_SRQ_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 76de55306c4d01..175bf9b1305888 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -10215,11 +10215,12 @@ int t4_load_cfg(struct adapter *adap, const u8 *cfg_data, unsigned int size) * t4_set_vf_mac_acl - Set MAC address for the specified VF * @adapter: The adapter * @vf: one of the VFs instantiated by the specified PF + * @start: The start port id associated with specified VF * @naddr: the number of MAC addresses * @addr: the MAC address(es) to be set to the specified VF */ int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, - unsigned int naddr, u8 *addr) + u8 start, unsigned int naddr, u8 *addr) { struct fw_acl_mac_cmd cmd; @@ -10234,7 +10235,7 @@ int t4_set_vf_mac_acl(struct adapter *adapter, unsigned int vf, cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd)); cmd.nmac = naddr; - switch (adapter->pf) { + switch (start) { case 3: memcpy(cmd.macaddr3, addr, sizeof(cmd.macaddr3)); break; diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h index 7ff82b6778bad1..21e0dfeff1585d 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h @@ -573,7 +573,6 @@ int send_tx_flowc_wr(struct sock *sk, int compl, u32 snd_nxt, u32 rcv_nxt); void chtls_tcp_push(struct sock *sk, int flags); int chtls_push_frames(struct chtls_sock *csk, int comp); -int chtls_set_tcb_tflag(struct sock *sk, unsigned int bit_pos, int val); void chtls_set_tcb_field_rpl_skb(struct sock *sk, u16 word, u64 mask, u64 val, u8 cookie, int through_l2t); diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_hw.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_hw.c index 1e67140b0f8013..fab6df21f01c98 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_hw.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_hw.c @@ -106,15 +106,6 @@ void chtls_set_tcb_field_rpl_skb(struct sock *sk, u16 word, send_or_defer(sk, tcp_sk(sk), skb, through_l2t); } -/* - * Set one of the t_flags bits in the TCB. - */ -int chtls_set_tcb_tflag(struct sock *sk, unsigned int bit_pos, int val) -{ - return chtls_set_tcb_field(sk, 1, 1ULL << bit_pos, - (u64)val << bit_pos); -} - static int chtls_set_tcb_keyid(struct sock *sk, int keyid) { return chtls_set_tcb_field(sk, 31, 0xFFFFFFFFULL, keyid); diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c index 455a54708be440..daa1ebaef51120 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c @@ -342,12 +342,13 @@ static struct sk_buff *copy_gl_to_skb_pkt(const struct pkt_gl *gl, { struct sk_buff *skb; - /* Allocate space for cpl_pass_accpet_req which will be synthesized by - * driver. Once driver synthesizes cpl_pass_accpet_req the skb will go + /* Allocate space for cpl_pass_accept_req which will be synthesized by + * driver. Once driver synthesizes cpl_pass_accept_req the skb will go * through the regular cpl_pass_accept_req processing in TOM. */ - skb = alloc_skb(gl->tot_len + sizeof(struct cpl_pass_accept_req) - - pktshift, GFP_ATOMIC); + skb = alloc_skb(size_add(gl->tot_len, + sizeof(struct cpl_pass_accept_req)) - + pktshift, GFP_ATOMIC); if (unlikely(!skb)) return NULL; __skb_put(skb, gl->tot_len + sizeof(struct cpl_pass_accept_req) diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c index 0a21a10a791c5b..fa5857923db4c2 100644 --- a/drivers/net/ethernet/cirrus/cs89x0.c +++ b/drivers/net/ethernet/cirrus/cs89x0.c @@ -1903,7 +1903,7 @@ static struct platform_driver cs89x0_driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(cs89x0_match), }, - .remove_new = cs89x0_platform_remove, + .remove = cs89x0_platform_remove, }; module_platform_driver_probe(cs89x0_driver, cs89x0_platform_probe); diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c index c2007cd864163b..a4972457edd9d9 100644 --- a/drivers/net/ethernet/cirrus/ep93xx_eth.c +++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c @@ -862,7 +862,7 @@ MODULE_DEVICE_TABLE(of, ep93xx_eth_of_ids); static struct platform_driver ep93xx_eth_driver = { .probe = ep93xx_eth_probe, - .remove_new = ep93xx_eth_remove, + .remove = ep93xx_eth_remove, .driver = { .name = "ep93xx-eth", .of_match_table = ep93xx_eth_of_ids, diff --git a/drivers/net/ethernet/cirrus/mac89x0.c b/drivers/net/ethernet/cirrus/mac89x0.c index 84b300fee2bb52..6723df9b65d9b7 100644 --- a/drivers/net/ethernet/cirrus/mac89x0.c +++ b/drivers/net/ethernet/cirrus/mac89x0.c @@ -568,7 +568,7 @@ static void mac89x0_device_remove(struct platform_device *pdev) static struct platform_driver mac89x0_platform_driver = { .probe = mac89x0_device_probe, - .remove_new = mac89x0_device_remove, + .remove = mac89x0_device_remove, .driver = { .name = "mac89x0", }, diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 0cc3644ee8554f..10b7e02ba4d0ee 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -23,10 +23,8 @@ #define ENIC_BARS_MAX 6 -#define ENIC_WQ_MAX 8 -#define ENIC_RQ_MAX 8 -#define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX) -#define ENIC_INTR_MAX (ENIC_CQ_MAX + 2) +#define ENIC_WQ_MAX 256 +#define ENIC_RQ_MAX 256 #define ENIC_WQ_NAPI_BUDGET 256 @@ -162,6 +160,17 @@ struct enic_rq_stats { u64 desc_skip; /* Rx pkt went into later buffer */ }; +struct enic_wq { + spinlock_t lock; /* spinlock for wq */ + struct vnic_wq vwq; + struct enic_wq_stats stats; +} ____cacheline_aligned; + +struct enic_rq { + struct vnic_rq vrq; + struct enic_rq_stats stats; +} ____cacheline_aligned; + /* Per-instance private data structure */ struct enic { struct net_device *netdev; @@ -173,8 +182,8 @@ struct enic { struct work_struct reset; struct work_struct tx_hang_reset; struct work_struct change_mtu_work; - struct msix_entry msix_entry[ENIC_INTR_MAX]; - struct enic_msix_entry msix[ENIC_INTR_MAX]; + struct msix_entry *msix_entry; + struct enic_msix_entry *msix; u32 msg_enable; spinlock_t devcmd_lock; u8 mac_addr[ETH_ALEN]; @@ -193,28 +202,25 @@ struct enic { bool enic_api_busy; struct enic_port_profile *pp; - /* work queue cache line section */ - ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX]; - spinlock_t wq_lock[ENIC_WQ_MAX]; - struct enic_wq_stats wq_stats[ENIC_WQ_MAX]; + struct enic_wq *wq; + unsigned int wq_avail; unsigned int wq_count; u16 loop_enable; u16 loop_tag; - /* receive queue cache line section */ - ____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX]; - struct enic_rq_stats rq_stats[ENIC_RQ_MAX]; + struct enic_rq *rq; + unsigned int rq_avail; unsigned int rq_count; struct vxlan_offload vxlan; - struct napi_struct napi[ENIC_RQ_MAX + ENIC_WQ_MAX]; + struct napi_struct *napi; - /* interrupt resource cache line section */ - ____cacheline_aligned struct vnic_intr intr[ENIC_INTR_MAX]; + struct vnic_intr *intr; + unsigned int intr_avail; unsigned int intr_count; u32 __iomem *legacy_pba; /* memory-mapped */ - /* completion queue cache line section */ - ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX]; + struct vnic_cq *cq; + unsigned int cq_avail; unsigned int cq_count; struct enic_rfs_flw_tbl rfs_h; u32 rx_copybreak; @@ -272,18 +278,28 @@ static inline unsigned int enic_msix_wq_intr(struct enic *enic, return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset; } -static inline unsigned int enic_msix_err_intr(struct enic *enic) -{ - return enic->rq_count + enic->wq_count; -} +/* MSIX interrupts are organized as the error interrupt, then the notify + * interrupt followed by all the I/O interrupts. The error interrupt needs + * to fit in 7 bits due to hardware constraints + */ +#define ENIC_MSIX_RESERVED_INTR 2 +#define ENIC_MSIX_ERR_INTR 0 +#define ENIC_MSIX_NOTIFY_INTR 1 +#define ENIC_MSIX_IO_INTR_BASE ENIC_MSIX_RESERVED_INTR +#define ENIC_MSIX_MIN_INTR (ENIC_MSIX_RESERVED_INTR + 2) #define ENIC_LEGACY_IO_INTR 0 #define ENIC_LEGACY_ERR_INTR 1 #define ENIC_LEGACY_NOTIFY_INTR 2 +static inline unsigned int enic_msix_err_intr(struct enic *enic) +{ + return ENIC_MSIX_ERR_INTR; +} + static inline unsigned int enic_msix_notify_intr(struct enic *enic) { - return enic->rq_count + enic->wq_count + 1; + return ENIC_MSIX_NOTIFY_INTR; } static inline bool enic_is_err_intr(struct enic *enic, int intr) diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index f7986f2b6a1794..d607b4f0542cea 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -337,7 +337,7 @@ static void enic_get_ethtool_stats(struct net_device *netdev, for (i = 0; i < NUM_ENIC_GEN_STATS; i++) *(data++) = ((u64 *)&enic->gen_stats)[enic_gen_stats[i].index]; for (i = 0; i < enic->rq_count; i++) { - struct enic_rq_stats *rqstats = &enic->rq_stats[i]; + struct enic_rq_stats *rqstats = &enic->rq[i].stats; int index; for (j = 0; j < NUM_ENIC_PER_RQ_STATS; j++) { @@ -346,7 +346,7 @@ static void enic_get_ethtool_stats(struct net_device *netdev, } } for (i = 0; i < enic->wq_count; i++) { - struct enic_wq_stats *wqstats = &enic->wq_stats[i]; + struct enic_wq_stats *wqstats = &enic->wq[i].stats; int index; for (j = 0; j < NUM_ENIC_PER_WQ_STATS; j++) { @@ -695,8 +695,8 @@ static void enic_get_channels(struct net_device *netdev, switch (vnic_dev_get_intr_mode(enic->vdev)) { case VNIC_DEV_INTR_MODE_MSIX: - channels->max_rx = ENIC_RQ_MAX; - channels->max_tx = ENIC_WQ_MAX; + channels->max_rx = min(enic->rq_avail, ENIC_RQ_MAX); + channels->max_tx = min(enic->wq_avail, ENIC_WQ_MAX); channels->rx_count = enic->rq_count; channels->tx_count = enic->wq_count; break; diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index ffed14b63d41d1..9913952ccb42f2 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -342,8 +342,8 @@ static void enic_wq_free_buf(struct vnic_wq *wq, { struct enic *enic = vnic_dev_priv(wq->vdev); - enic->wq_stats[wq->index].cq_work++; - enic->wq_stats[wq->index].cq_bytes += buf->len; + enic->wq[wq->index].stats.cq_work++; + enic->wq[wq->index].stats.cq_bytes += buf->len; enic_free_wq_buf(wq, buf); } @@ -352,20 +352,20 @@ static int enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, { struct enic *enic = vnic_dev_priv(vdev); - spin_lock(&enic->wq_lock[q_number]); + spin_lock(&enic->wq[q_number].lock); - vnic_wq_service(&enic->wq[q_number], cq_desc, + vnic_wq_service(&enic->wq[q_number].vwq, cq_desc, completed_index, enic_wq_free_buf, opaque); if (netif_tx_queue_stopped(netdev_get_tx_queue(enic->netdev, q_number)) && - vnic_wq_desc_avail(&enic->wq[q_number]) >= + vnic_wq_desc_avail(&enic->wq[q_number].vwq) >= (MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS)) { netif_wake_subqueue(enic->netdev, q_number); - enic->wq_stats[q_number].wake++; + enic->wq[q_number].stats.wake++; } - spin_unlock(&enic->wq_lock[q_number]); + spin_unlock(&enic->wq[q_number].lock); return 0; } @@ -377,7 +377,7 @@ static bool enic_log_q_error(struct enic *enic) bool err = false; for (i = 0; i < enic->wq_count; i++) { - error_status = vnic_wq_error_status(&enic->wq[i]); + error_status = vnic_wq_error_status(&enic->wq[i].vwq); err |= error_status; if (error_status) netdev_err(enic->netdev, "WQ[%d] error_status %d\n", @@ -385,7 +385,7 @@ static bool enic_log_q_error(struct enic *enic) } for (i = 0; i < enic->rq_count; i++) { - error_status = vnic_rq_error_status(&enic->rq[i]); + error_status = vnic_rq_error_status(&enic->rq[i].vrq); err |= error_status; if (error_status) netdev_err(enic->netdev, "RQ[%d] error_status %d\n", @@ -598,9 +598,9 @@ static int enic_queue_wq_skb_vlan(struct enic *enic, struct vnic_wq *wq, err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); /* The enic_queue_wq_desc() above does not do HW checksum */ - enic->wq_stats[wq->index].csum_none++; - enic->wq_stats[wq->index].packets++; - enic->wq_stats[wq->index].bytes += skb->len; + enic->wq[wq->index].stats.csum_none++; + enic->wq[wq->index].stats.packets++; + enic->wq[wq->index].stats.bytes += skb->len; return err; } @@ -634,9 +634,9 @@ static int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq, if (!eop) err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); - enic->wq_stats[wq->index].csum_partial++; - enic->wq_stats[wq->index].packets++; - enic->wq_stats[wq->index].bytes += skb->len; + enic->wq[wq->index].stats.csum_partial++; + enic->wq[wq->index].stats.packets++; + enic->wq[wq->index].stats.bytes += skb->len; return err; } @@ -699,11 +699,11 @@ static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq, if (skb->encapsulation) { hdr_len = skb_inner_tcp_all_headers(skb); enic_preload_tcp_csum_encap(skb); - enic->wq_stats[wq->index].encap_tso++; + enic->wq[wq->index].stats.encap_tso++; } else { hdr_len = skb_tcp_all_headers(skb); enic_preload_tcp_csum(skb); - enic->wq_stats[wq->index].tso++; + enic->wq[wq->index].stats.tso++; } /* Queue WQ_ENET_MAX_DESC_LEN length descriptors @@ -757,8 +757,8 @@ static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq, pkts = len / mss; if ((len % mss) > 0) pkts++; - enic->wq_stats[wq->index].packets += pkts; - enic->wq_stats[wq->index].bytes += (len + (pkts * hdr_len)); + enic->wq[wq->index].stats.packets += pkts; + enic->wq[wq->index].stats.bytes += (len + (pkts * hdr_len)); return 0; } @@ -792,9 +792,9 @@ static inline int enic_queue_wq_skb_encap(struct enic *enic, struct vnic_wq *wq, if (!eop) err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback); - enic->wq_stats[wq->index].encap_csum++; - enic->wq_stats[wq->index].packets++; - enic->wq_stats[wq->index].bytes += skb->len; + enic->wq[wq->index].stats.encap_csum++; + enic->wq[wq->index].stats.packets++; + enic->wq[wq->index].stats.bytes += skb->len; return err; } @@ -812,7 +812,7 @@ static inline int enic_queue_wq_skb(struct enic *enic, /* VLAN tag from trunking driver */ vlan_tag_insert = 1; vlan_tag = skb_vlan_tag_get(skb); - enic->wq_stats[wq->index].add_vlan++; + enic->wq[wq->index].stats.add_vlan++; } else if (enic->loop_enable) { vlan_tag = enic->loop_tag; loopback = 1; @@ -859,11 +859,11 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, struct netdev_queue *txq; txq_map = skb_get_queue_mapping(skb) % enic->wq_count; - wq = &enic->wq[txq_map]; + wq = &enic->wq[txq_map].vwq; if (skb->len <= 0) { dev_kfree_skb_any(skb); - enic->wq_stats[wq->index].null_pkt++; + enic->wq[wq->index].stats.null_pkt++; return NETDEV_TX_OK; } @@ -878,19 +878,19 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, skb_shinfo(skb)->nr_frags + 1 > ENIC_NON_TSO_MAX_DESC && skb_linearize(skb)) { dev_kfree_skb_any(skb); - enic->wq_stats[wq->index].skb_linear_fail++; + enic->wq[wq->index].stats.skb_linear_fail++; return NETDEV_TX_OK; } - spin_lock(&enic->wq_lock[txq_map]); + spin_lock(&enic->wq[txq_map].lock); if (vnic_wq_desc_avail(wq) < skb_shinfo(skb)->nr_frags + ENIC_DESC_MAX_SPLITS) { netif_tx_stop_queue(txq); /* This is a hard error, log it */ netdev_err(netdev, "BUG! Tx ring full when queue awake!\n"); - spin_unlock(&enic->wq_lock[txq_map]); - enic->wq_stats[wq->index].desc_full_awake++; + spin_unlock(&enic->wq[txq_map].lock); + enic->wq[wq->index].stats.desc_full_awake++; return NETDEV_TX_BUSY; } @@ -899,14 +899,14 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS) { netif_tx_stop_queue(txq); - enic->wq_stats[wq->index].stopped++; + enic->wq[wq->index].stats.stopped++; } skb_tx_timestamp(skb); if (!netdev_xmit_more() || netif_xmit_stopped(txq)) vnic_wq_doorbell(wq); error: - spin_unlock(&enic->wq_lock[txq_map]); + spin_unlock(&enic->wq[txq_map].lock); return NETDEV_TX_OK; } @@ -940,10 +940,10 @@ static void enic_get_stats(struct net_device *netdev, net_stats->rx_errors = stats->rx.rx_errors; net_stats->multicast = stats->rx.rx_multicast_frames_ok; - for (i = 0; i < ENIC_RQ_MAX; i++) { - struct enic_rq_stats *rqs = &enic->rq_stats[i]; + for (i = 0; i < enic->rq_count; i++) { + struct enic_rq_stats *rqs = &enic->rq[i].stats; - if (!enic->rq->ctrl) + if (!enic->rq[i].vrq.ctrl) break; pkt_truncated += rqs->pkt_truncated; bad_fcs += rqs->bad_fcs; @@ -1313,7 +1313,7 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq) } skb = netdev_alloc_skb_ip_align(netdev, len); if (!skb) { - enic->rq_stats[rq->index].no_skb++; + enic->rq[rq->index].stats.no_skb++; return -ENOMEM; } @@ -1366,7 +1366,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, struct net_device *netdev = enic->netdev; struct sk_buff *skb; struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; - struct enic_rq_stats *rqstats = &enic->rq_stats[rq->index]; + struct enic_rq_stats *rqstats = &enic->rq[rq->index].stats; u8 type, color, eop, sop, ingress_port, vlan_stripped; u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof; @@ -1512,7 +1512,7 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, { struct enic *enic = vnic_dev_priv(vdev); - vnic_rq_service(&enic->rq[q_number], cq_desc, + vnic_rq_service(&enic->rq[q_number].vrq, cq_desc, completed_index, VNIC_RQ_RETURN_DESC, enic_rq_indicate_buf, opaque); @@ -1609,7 +1609,7 @@ static int enic_poll(struct napi_struct *napi, int budget) 0 /* don't unmask intr */, 0 /* don't reset intr timer */); - err = vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); + err = vnic_rq_fill(&enic->rq[0].vrq, enic_rq_alloc_buf); /* Buffer allocation failed. Stay in polling * mode so we can try to fill the ring again. @@ -1621,7 +1621,7 @@ static int enic_poll(struct napi_struct *napi, int budget) /* Call the function which refreshes the intr coalescing timer * value based on the traffic. */ - enic_calc_int_moderation(enic, &enic->rq[0]); + enic_calc_int_moderation(enic, &enic->rq[0].vrq); if ((rq_work_done < budget) && napi_complete_done(napi, rq_work_done)) { @@ -1630,11 +1630,11 @@ static int enic_poll(struct napi_struct *napi, int budget) */ if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) - enic_set_int_moderation(enic, &enic->rq[0]); + enic_set_int_moderation(enic, &enic->rq[0].vrq); vnic_intr_unmask(&enic->intr[intr]); - enic->rq_stats[0].napi_complete++; + enic->rq[0].stats.napi_complete++; } else { - enic->rq_stats[0].napi_repoll++; + enic->rq[0].stats.napi_repoll++; } return rq_work_done; @@ -1683,7 +1683,7 @@ static int enic_poll_msix_wq(struct napi_struct *napi, int budget) struct net_device *netdev = napi->dev; struct enic *enic = netdev_priv(netdev); unsigned int wq_index = (napi - &enic->napi[0]) - enic->rq_count; - struct vnic_wq *wq = &enic->wq[wq_index]; + struct vnic_wq *wq = &enic->wq[wq_index].vwq; unsigned int cq; unsigned int intr; unsigned int wq_work_to_do = ENIC_WQ_NAPI_BUDGET; @@ -1737,7 +1737,7 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) 0 /* don't unmask intr */, 0 /* don't reset intr timer */); - err = vnic_rq_fill(&enic->rq[rq], enic_rq_alloc_buf); + err = vnic_rq_fill(&enic->rq[rq].vrq, enic_rq_alloc_buf); /* Buffer allocation failed. Stay in polling mode * so we can try to fill the ring again. @@ -1749,7 +1749,7 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) /* Call the function which refreshes the intr coalescing timer * value based on the traffic. */ - enic_calc_int_moderation(enic, &enic->rq[rq]); + enic_calc_int_moderation(enic, &enic->rq[rq].vrq); if ((work_done < budget) && napi_complete_done(napi, work_done)) { @@ -1758,11 +1758,11 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) */ if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) - enic_set_int_moderation(enic, &enic->rq[rq]); + enic_set_int_moderation(enic, &enic->rq[rq].vrq); vnic_intr_unmask(&enic->intr[intr]); - enic->rq_stats[rq].napi_complete++; + enic->rq[rq].stats.napi_complete++; } else { - enic->rq_stats[rq].napi_repoll++; + enic->rq[rq].stats.napi_repoll++; } return work_done; @@ -1792,7 +1792,7 @@ static void enic_free_intr(struct enic *enic) free_irq(enic->pdev->irq, enic); break; case VNIC_DEV_INTR_MODE_MSIX: - for (i = 0; i < ARRAY_SIZE(enic->msix); i++) + for (i = 0; i < enic->intr_count; i++) if (enic->msix[i].requested) free_irq(enic->msix_entry[i].vector, enic->msix[i].devid); @@ -1859,7 +1859,7 @@ static int enic_request_intr(struct enic *enic) enic->msix[intr].isr = enic_isr_msix_notify; enic->msix[intr].devid = enic; - for (i = 0; i < ARRAY_SIZE(enic->msix); i++) + for (i = 0; i < enic->intr_count; i++) enic->msix[i].requested = 0; for (i = 0; i < enic->intr_count; i++) { @@ -1989,10 +1989,10 @@ static int enic_open(struct net_device *netdev) for (i = 0; i < enic->rq_count; i++) { /* enable rq before updating rq desc */ - vnic_rq_enable(&enic->rq[i]); - vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf); + vnic_rq_enable(&enic->rq[i].vrq); + vnic_rq_fill(&enic->rq[i].vrq, enic_rq_alloc_buf); /* Need at least one buffer on ring to get going */ - if (vnic_rq_desc_used(&enic->rq[i]) == 0) { + if (vnic_rq_desc_used(&enic->rq[i].vrq) == 0) { netdev_err(netdev, "Unable to alloc receive buffers\n"); err = -ENOMEM; goto err_out_free_rq; @@ -2000,7 +2000,7 @@ static int enic_open(struct net_device *netdev) } for (i = 0; i < enic->wq_count; i++) - vnic_wq_enable(&enic->wq[i]); + vnic_wq_enable(&enic->wq[i].vwq); if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic)) enic_dev_add_station_addr(enic); @@ -2027,9 +2027,9 @@ static int enic_open(struct net_device *netdev) err_out_free_rq: for (i = 0; i < enic->rq_count; i++) { - ret = vnic_rq_disable(&enic->rq[i]); + ret = vnic_rq_disable(&enic->rq[i].vrq); if (!ret) - vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); + vnic_rq_clean(&enic->rq[i].vrq, enic_free_rq_buf); } enic_dev_notify_unset(enic); err_out_free_intr: @@ -2071,12 +2071,12 @@ static int enic_stop(struct net_device *netdev) enic_dev_del_station_addr(enic); for (i = 0; i < enic->wq_count; i++) { - err = vnic_wq_disable(&enic->wq[i]); + err = vnic_wq_disable(&enic->wq[i].vwq); if (err) return err; } for (i = 0; i < enic->rq_count; i++) { - err = vnic_rq_disable(&enic->rq[i]); + err = vnic_rq_disable(&enic->rq[i].vrq); if (err) return err; } @@ -2086,9 +2086,9 @@ static int enic_stop(struct net_device *netdev) enic_free_intr(enic); for (i = 0; i < enic->wq_count; i++) - vnic_wq_clean(&enic->wq[i], enic_free_wq_buf); + vnic_wq_clean(&enic->wq[i].vwq, enic_free_wq_buf); for (i = 0; i < enic->rq_count; i++) - vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); + vnic_rq_clean(&enic->rq[i].vrq, enic_free_rq_buf); for (i = 0; i < enic->cq_count; i++) vnic_cq_clean(&enic->cq[i]); for (i = 0; i < enic->intr_count; i++) @@ -2442,112 +2442,56 @@ static void enic_tx_hang_reset(struct work_struct *work) static int enic_set_intr_mode(struct enic *enic) { - unsigned int n = min_t(unsigned int, enic->rq_count, ENIC_RQ_MAX); - unsigned int m = min_t(unsigned int, enic->wq_count, ENIC_WQ_MAX); unsigned int i; + int num_intr; /* Set interrupt mode (INTx, MSI, MSI-X) depending * on system capabilities. * * Try MSI-X first - * - * We need n RQs, m WQs, n+m CQs, and n+m+2 INTRs - * (the second to last INTR is used for WQ/RQ errors) - * (the last INTR is used for notifications) - */ - - BUG_ON(ARRAY_SIZE(enic->msix_entry) < n + m + 2); - for (i = 0; i < n + m + 2; i++) - enic->msix_entry[i].entry = i; - - /* Use multiple RQs if RSS is enabled */ - if (ENIC_SETTING(enic, RSS) && - enic->config.intr_mode < 1 && - enic->rq_count >= n && - enic->wq_count >= m && - enic->cq_count >= n + m && - enic->intr_count >= n + m + 2) { - - if (pci_enable_msix_range(enic->pdev, enic->msix_entry, - n + m + 2, n + m + 2) > 0) { - - enic->rq_count = n; - enic->wq_count = m; - enic->cq_count = n + m; - enic->intr_count = n + m + 2; - - vnic_dev_set_intr_mode(enic->vdev, - VNIC_DEV_INTR_MODE_MSIX); - - return 0; - } - } - if (enic->config.intr_mode < 1 && - enic->rq_count >= 1 && - enic->wq_count >= m && - enic->cq_count >= 1 + m && - enic->intr_count >= 1 + m + 2) { - if (pci_enable_msix_range(enic->pdev, enic->msix_entry, - 1 + m + 2, 1 + m + 2) > 0) { - - enic->rq_count = 1; - enic->wq_count = m; - enic->cq_count = 1 + m; - enic->intr_count = 1 + m + 2; - + enic->intr_avail >= ENIC_MSIX_MIN_INTR) { + for (i = 0; i < enic->intr_avail; i++) + enic->msix_entry[i].entry = i; + + num_intr = pci_enable_msix_range(enic->pdev, enic->msix_entry, + ENIC_MSIX_MIN_INTR, + enic->intr_avail); + if (num_intr > 0) { vnic_dev_set_intr_mode(enic->vdev, - VNIC_DEV_INTR_MODE_MSIX); - + VNIC_DEV_INTR_MODE_MSIX); + enic->intr_avail = num_intr; return 0; } } /* Next try MSI * - * We need 1 RQ, 1 WQ, 2 CQs, and 1 INTR + * We need 1 INTR */ if (enic->config.intr_mode < 2 && - enic->rq_count >= 1 && - enic->wq_count >= 1 && - enic->cq_count >= 2 && - enic->intr_count >= 1 && + enic->intr_avail >= 1 && !pci_enable_msi(enic->pdev)) { - - enic->rq_count = 1; - enic->wq_count = 1; - enic->cq_count = 2; - enic->intr_count = 1; - + enic->intr_avail = 1; vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_MSI); - return 0; } /* Next try INTx * - * We need 1 RQ, 1 WQ, 2 CQs, and 3 INTRs + * We need 3 INTRs * (the first INTR is used for WQ/RQ) * (the second INTR is used for WQ/RQ errors) * (the last INTR is used for notifications) */ if (enic->config.intr_mode < 3 && - enic->rq_count >= 1 && - enic->wq_count >= 1 && - enic->cq_count >= 2 && - enic->intr_count >= 3) { - - enic->rq_count = 1; - enic->wq_count = 1; - enic->cq_count = 2; - enic->intr_count = 3; - + enic->intr_avail >= 3) { + enic->intr_avail = 3; vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_INTX); - return 0; } @@ -2572,11 +2516,81 @@ static void enic_clear_intr_mode(struct enic *enic) vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); } +static int enic_adjust_resources(struct enic *enic) +{ + unsigned int max_queues; + unsigned int rq_default; + unsigned int rq_avail; + unsigned int wq_avail; + + if (enic->rq_avail < 1 || enic->wq_avail < 1 || enic->cq_avail < 2) { + dev_err(enic_get_dev(enic), + "Not enough resources available rq: %d wq: %d cq: %d\n", + enic->rq_avail, enic->wq_avail, + enic->cq_avail); + return -ENOSPC; + } + + if (is_kdump_kernel()) { + dev_info(enic_get_dev(enic), "Running from within kdump kernel. Using minimal resources\n"); + enic->rq_avail = 1; + enic->wq_avail = 1; + enic->config.rq_desc_count = ENIC_MIN_RQ_DESCS; + enic->config.wq_desc_count = ENIC_MIN_WQ_DESCS; + enic->config.mtu = min_t(u16, 1500, enic->config.mtu); + } + + /* if RSS isn't set, then we can only use one RQ */ + if (!ENIC_SETTING(enic, RSS)) + enic->rq_avail = 1; + + switch (vnic_dev_get_intr_mode(enic->vdev)) { + case VNIC_DEV_INTR_MODE_INTX: + case VNIC_DEV_INTR_MODE_MSI: + enic->rq_count = 1; + enic->wq_count = 1; + enic->cq_count = 2; + enic->intr_count = enic->intr_avail; + break; + case VNIC_DEV_INTR_MODE_MSIX: + /* Adjust the number of wqs/rqs/cqs/interrupts that will be + * used based on which resource is the most constrained + */ + wq_avail = min(enic->wq_avail, ENIC_WQ_MAX); + rq_default = netif_get_num_default_rss_queues(); + rq_avail = min3(enic->rq_avail, ENIC_RQ_MAX, rq_default); + max_queues = min(enic->cq_avail, + enic->intr_avail - ENIC_MSIX_RESERVED_INTR); + if (wq_avail + rq_avail <= max_queues) { + enic->rq_count = rq_avail; + enic->wq_count = wq_avail; + } else { + /* recalculate wq/rq count */ + if (rq_avail < wq_avail) { + enic->rq_count = min(rq_avail, max_queues / 2); + enic->wq_count = max_queues - enic->rq_count; + } else { + enic->wq_count = min(wq_avail, max_queues / 2); + enic->rq_count = max_queues - enic->wq_count; + } + } + enic->cq_count = enic->rq_count + enic->wq_count; + enic->intr_count = enic->cq_count + ENIC_MSIX_RESERVED_INTR; + + break; + default: + dev_err(enic_get_dev(enic), "Unknown interrupt mode\n"); + return -EINVAL; + } + + return 0; +} + static void enic_get_queue_stats_rx(struct net_device *dev, int idx, struct netdev_queue_stats_rx *rxs) { struct enic *enic = netdev_priv(dev); - struct enic_rq_stats *rqstats = &enic->rq_stats[idx]; + struct enic_rq_stats *rqstats = &enic->rq[idx].stats; rxs->bytes = rqstats->bytes; rxs->packets = rqstats->packets; @@ -2590,7 +2604,7 @@ static void enic_get_queue_stats_tx(struct net_device *dev, int idx, struct netdev_queue_stats_tx *txs) { struct enic *enic = netdev_priv(dev); - struct enic_wq_stats *wqstats = &enic->wq_stats[idx]; + struct enic_wq_stats *wqstats = &enic->wq[idx].stats; txs->bytes = wqstats->bytes; txs->packets = wqstats->packets; @@ -2674,6 +2688,71 @@ static const struct netdev_stat_ops enic_netdev_stat_ops = { .get_base_stats = enic_get_base_stats, }; +static void enic_free_enic_resources(struct enic *enic) +{ + kfree(enic->wq); + enic->wq = NULL; + + kfree(enic->rq); + enic->rq = NULL; + + kfree(enic->cq); + enic->cq = NULL; + + kfree(enic->napi); + enic->napi = NULL; + + kfree(enic->msix_entry); + enic->msix_entry = NULL; + + kfree(enic->msix); + enic->msix = NULL; + + kfree(enic->intr); + enic->intr = NULL; +} + +static int enic_alloc_enic_resources(struct enic *enic) +{ + enic->wq = kcalloc(enic->wq_avail, sizeof(struct enic_wq), GFP_KERNEL); + if (!enic->wq) + goto free_queues; + + enic->rq = kcalloc(enic->rq_avail, sizeof(struct enic_rq), GFP_KERNEL); + if (!enic->rq) + goto free_queues; + + enic->cq = kcalloc(enic->cq_avail, sizeof(struct vnic_cq), GFP_KERNEL); + if (!enic->cq) + goto free_queues; + + enic->napi = kcalloc(enic->wq_avail + enic->rq_avail, + sizeof(struct napi_struct), GFP_KERNEL); + if (!enic->napi) + goto free_queues; + + enic->msix_entry = kcalloc(enic->intr_avail, sizeof(struct msix_entry), + GFP_KERNEL); + if (!enic->msix_entry) + goto free_queues; + + enic->msix = kcalloc(enic->intr_avail, sizeof(struct enic_msix_entry), + GFP_KERNEL); + if (!enic->msix) + goto free_queues; + + enic->intr = kcalloc(enic->intr_avail, sizeof(struct vnic_intr), + GFP_KERNEL); + if (!enic->intr) + goto free_queues; + + return 0; + +free_queues: + enic_free_enic_resources(enic); + return -ENOMEM; +} + static void enic_dev_deinit(struct enic *enic) { unsigned int i; @@ -2691,18 +2770,7 @@ static void enic_dev_deinit(struct enic *enic) enic_free_vnic_resources(enic); enic_clear_intr_mode(enic); enic_free_affinity_hint(enic); -} - -static void enic_kdump_kernel_config(struct enic *enic) -{ - if (is_kdump_kernel()) { - dev_info(enic_get_dev(enic), "Running from within kdump kernel. Using minimal resources\n"); - enic->rq_count = 1; - enic->wq_count = 1; - enic->config.rq_desc_count = ENIC_MIN_RQ_DESCS; - enic->config.wq_desc_count = ENIC_MIN_WQ_DESCS; - enic->config.mtu = min_t(u16, 1500, enic->config.mtu); - } + enic_free_enic_resources(enic); } static int enic_dev_init(struct enic *enic) @@ -2734,19 +2802,26 @@ static int enic_dev_init(struct enic *enic) enic_get_res_counts(enic); - /* modify resource count if we are in kdump_kernel - */ - enic_kdump_kernel_config(enic); + err = enic_alloc_enic_resources(enic); + if (err) { + dev_err(dev, "Failed to allocate enic resources\n"); + return err; + } - /* Set interrupt mode based on resource counts and system - * capabilities - */ + /* Set interrupt mode based on system capabilities */ err = enic_set_intr_mode(enic); if (err) { dev_err(dev, "Failed to set intr mode based on resource " "counts and system capabilities, aborting\n"); - return err; + goto err_out_free_vnic_resources; + } + + /* Adjust resource counts based on most constrained resources */ + err = enic_adjust_resources(enic); + if (err) { + dev_err(dev, "Failed to adjust resources\n"); + goto err_out_free_vnic_resources; } /* Allocate and configure vNIC resources @@ -2788,6 +2863,7 @@ static int enic_dev_init(struct enic *enic) enic_free_affinity_hint(enic); enic_clear_intr_mode(enic); enic_free_vnic_resources(enic); + enic_free_enic_resources(enic); return err; } @@ -2993,7 +3069,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work); for (i = 0; i < enic->wq_count; i++) - spin_lock_init(&enic->wq_lock[i]); + spin_lock_init(&enic->wq[i].lock); /* Register net device */ diff --git a/drivers/net/ethernet/cisco/enic/enic_res.c b/drivers/net/ethernet/cisco/enic/enic_res.c index 1c48aebdbab02b..1261251998330c 100644 --- a/drivers/net/ethernet/cisco/enic/enic_res.c +++ b/drivers/net/ethernet/cisco/enic/enic_res.c @@ -176,9 +176,9 @@ void enic_free_vnic_resources(struct enic *enic) unsigned int i; for (i = 0; i < enic->wq_count; i++) - vnic_wq_free(&enic->wq[i]); + vnic_wq_free(&enic->wq[i].vwq); for (i = 0; i < enic->rq_count; i++) - vnic_rq_free(&enic->rq[i]); + vnic_rq_free(&enic->rq[i].vrq); for (i = 0; i < enic->cq_count; i++) vnic_cq_free(&enic->cq[i]); for (i = 0; i < enic->intr_count; i++) @@ -187,16 +187,21 @@ void enic_free_vnic_resources(struct enic *enic) void enic_get_res_counts(struct enic *enic) { - enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ); - enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ); - enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ); - enic->intr_count = vnic_dev_get_res_count(enic->vdev, - RES_TYPE_INTR_CTRL); + enic->wq_avail = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ); + enic->rq_avail = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ); + enic->cq_avail = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ); + enic->intr_avail = vnic_dev_get_res_count(enic->vdev, + RES_TYPE_INTR_CTRL); + + enic->wq_count = enic->wq_avail; + enic->rq_count = enic->rq_avail; + enic->cq_count = enic->cq_avail; + enic->intr_count = enic->intr_avail; dev_info(enic_get_dev(enic), "vNIC resources avail: wq %d rq %d cq %d intr %d\n", - enic->wq_count, enic->rq_count, - enic->cq_count, enic->intr_count); + enic->wq_avail, enic->rq_avail, + enic->cq_avail, enic->intr_avail); } void enic_init_vnic_resources(struct enic *enic) @@ -221,9 +226,12 @@ void enic_init_vnic_resources(struct enic *enic) switch (intr_mode) { case VNIC_DEV_INTR_MODE_INTX: + error_interrupt_enable = 1; + error_interrupt_offset = ENIC_LEGACY_ERR_INTR; + break; case VNIC_DEV_INTR_MODE_MSIX: error_interrupt_enable = 1; - error_interrupt_offset = enic->intr_count - 2; + error_interrupt_offset = enic_msix_err_intr(enic); break; default: error_interrupt_enable = 0; @@ -233,7 +241,7 @@ void enic_init_vnic_resources(struct enic *enic) for (i = 0; i < enic->rq_count; i++) { cq_index = i; - vnic_rq_init(&enic->rq[i], + vnic_rq_init(&enic->rq[i].vrq, cq_index, error_interrupt_enable, error_interrupt_offset); @@ -241,7 +249,7 @@ void enic_init_vnic_resources(struct enic *enic) for (i = 0; i < enic->wq_count; i++) { cq_index = enic->rq_count + i; - vnic_wq_init(&enic->wq[i], + vnic_wq_init(&enic->wq[i].vwq, cq_index, error_interrupt_enable, error_interrupt_offset); @@ -249,15 +257,15 @@ void enic_init_vnic_resources(struct enic *enic) /* Init CQ resources * - * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI - * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X + * All CQs point to INTR[0] for INTx, MSI + * CQ[i] point to INTR[ENIC_MSIX_IO_INTR_BASE + i] for MSI-X */ for (i = 0; i < enic->cq_count; i++) { switch (intr_mode) { case VNIC_DEV_INTR_MODE_MSIX: - interrupt_offset = i; + interrupt_offset = ENIC_MSIX_IO_INTR_BASE + i; break; default: interrupt_offset = 0; @@ -322,7 +330,7 @@ int enic_alloc_vnic_resources(struct enic *enic) */ for (i = 0; i < enic->wq_count; i++) { - err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i, + err = vnic_wq_alloc(enic->vdev, &enic->wq[i].vwq, i, enic->config.wq_desc_count, sizeof(struct wq_enet_desc)); if (err) @@ -330,7 +338,7 @@ int enic_alloc_vnic_resources(struct enic *enic) } for (i = 0; i < enic->rq_count; i++) { - err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i, + err = vnic_rq_alloc(enic->vdev, &enic->rq[i].vrq, i, enic->config.rq_desc_count, sizeof(struct rq_enet_desc)); if (err) diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index 73e1c71c5092e4..991e3839858b52 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -2573,7 +2573,7 @@ static struct platform_driver gemini_ethernet_port_driver = { .of_match_table = gemini_ethernet_port_of_match, }, .probe = gemini_ethernet_port_probe, - .remove_new = gemini_ethernet_port_remove, + .remove = gemini_ethernet_port_remove, }; static int gemini_ethernet_probe(struct platform_device *pdev) @@ -2637,7 +2637,7 @@ static struct platform_driver gemini_ethernet_driver = { .of_match_table = gemini_ethernet_of_match, }, .probe = gemini_ethernet_probe, - .remove_new = gemini_ethernet_remove, + .remove = gemini_ethernet_remove, }; static int __init gemini_ethernet_module_init(void) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 150cc94ae9f884..8735e333034cf4 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -1799,7 +1799,7 @@ static struct platform_driver dm9000_driver = { .of_match_table = of_match_ptr(dm9000_of_matches), }, .probe = dm9000_probe, - .remove_new = dm9000_drv_remove, + .remove = dm9000_drv_remove, }; module_platform_driver(dm9000_driver); diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig index 0d77f84c8e7bbc..e9e13654812c2d 100644 --- a/drivers/net/ethernet/dlink/Kconfig +++ b/drivers/net/ethernet/dlink/Kconfig @@ -32,24 +32,4 @@ config DL2K To compile this driver as a module, choose M here: the module will be called dl2k. -config SUNDANCE - tristate "Sundance Alta support" - depends on PCI - select CRC32 - select MII - help - This driver is for the Sundance "Alta" chip. - More specific information and updates are available from - . - -config SUNDANCE_MMIO - bool "Use MMIO instead of PIO" - depends on SUNDANCE - help - Enable memory-mapped I/O for interaction with Sundance NIC registers. - Do NOT enable this by default, PIO (enabled when MMIO is disabled) - is known to solve bugs on certain chips. - - If unsure, say N. - endif # NET_VENDOR_DLINK diff --git a/drivers/net/ethernet/dlink/Makefile b/drivers/net/ethernet/dlink/Makefile index 3ff503c747db74..38c236eb6007a5 100644 --- a/drivers/net/ethernet/dlink/Makefile +++ b/drivers/net/ethernet/dlink/Makefile @@ -4,4 +4,3 @@ # obj-$(CONFIG_DL2K) += dl2k.o -obj-$(CONFIG_SUNDANCE) += sundance.o diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c deleted file mode 100644 index 8af5ecec7d6147..00000000000000 --- a/drivers/net/ethernet/dlink/sundance.c +++ /dev/null @@ -1,1985 +0,0 @@ -/* sundance.c: A Linux device driver for the Sundance ST201 "Alta". */ -/* - Written 1999-2000 by Donald Becker. - - This software may be used and distributed according to the terms of - the GNU General Public License (GPL), incorporated herein by reference. - Drivers based on or derived from this code fall under the GPL and must - retain the authorship, copyright and license notice. This file is not - a complete program and may only be used when the entire operating - system is licensed under the GPL. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Support and updates available at - http://www.scyld.com/network/sundance.html - [link no longer provides useful info -jgarzik] - Archives of the mailing list are still available at - https://www.beowulf.org/pipermail/netdrivers/ - -*/ - -#define DRV_NAME "sundance" - -/* The user-configurable values. - These may be modified when a driver module is loaded.*/ -static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ -/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). - Typical is a 64 element hash table based on the Ethernet CRC. */ -static const int multicast_filter_limit = 32; - -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1518 effectively disables this feature. - This chip can receive into offset buffers, so the Alpha does not - need a copy-align. */ -static int rx_copybreak; -static int flowctrl=1; - -/* media[] specifies the media type the NIC operates at. - autosense Autosensing active media. - 10mbps_hd 10Mbps half duplex. - 10mbps_fd 10Mbps full duplex. - 100mbps_hd 100Mbps half duplex. - 100mbps_fd 100Mbps full duplex. - 0 Autosensing active media. - 1 10Mbps half duplex. - 2 10Mbps full duplex. - 3 100Mbps half duplex. - 4 100Mbps full duplex. -*/ -#define MAX_UNITS 8 -static char *media[MAX_UNITS]; - - -/* Operational parameters that are set at compile time. */ - -/* Keep the ring sizes a power of two for compile efficiency. - The compiler will convert '%'<2^N> into a bit mask. - Making the Tx ring too large decreases the effectiveness of channel - bonding and packet priority, and more than 128 requires modifying the - Tx error recovery. - Large receive rings merely waste memory. */ -#define TX_RING_SIZE 32 -#define TX_QUEUE_LEN (TX_RING_SIZE - 1) /* Limit ring entries actually used. */ -#define RX_RING_SIZE 64 -#define RX_BUDGET 32 -#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc) -#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc) - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*HZ) -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ - -/* Include files, designed to support most kernel versions 2.0.0 and later. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("Sundance Alta Ethernet driver"); -MODULE_LICENSE("GPL"); - -module_param(debug, int, 0); -module_param(rx_copybreak, int, 0); -module_param_array(media, charp, NULL, 0); -module_param(flowctrl, int, 0); -MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)"); -MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]"); - -/* - Theory of Operation - -I. Board Compatibility - -This driver is designed for the Sundance Technologies "Alta" ST201 chip. - -II. Board-specific settings - -III. Driver operation - -IIIa. Ring buffers - -This driver uses two statically allocated fixed-size descriptor lists -formed into rings by a branch from the final descriptor to the beginning of -the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. -Some chips explicitly use only 2^N sized rings, while others use a -'next descriptor' pointer that the driver forms into rings. - -IIIb/c. Transmit/Receive Structure - -This driver uses a zero-copy receive and transmit scheme. -The driver allocates full frame size skbuffs for the Rx ring buffers at -open() time and passes the skb->data field to the chip as receive data -buffers. When an incoming frame is less than RX_COPYBREAK bytes long, -a fresh skbuff is allocated and the frame is copied to the new skbuff. -When the incoming frame is larger, the skbuff is passed directly up the -protocol stack. Buffers consumed this way are replaced by newly allocated -skbuffs in a later phase of receives. - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. New boards are typically used in generously configured machines -and the underfilled buffers have negligible impact compared to the benefit of -a single allocation size, so the default value of zero results in never -copying packets. When copying is done, the cost is usually mitigated by using -a combined copy/checksum routine. Copying also preloads the cache, which is -most useful with small frames. - -A subtle aspect of the operation is that the IP header at offset 14 in an -ethernet frame isn't longword aligned for further processing. -Unaligned buffers are permitted by the Sundance hardware, so -frames are received into the skbuff at an offset of "+2", 16-byte aligning -the IP header. - -IIId. Synchronization - -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and interrupt handling software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'lp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. After reaping the stats, it marks the Tx queue entry as -empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it -clears both the tx_full and tbusy flags. - -IV. Notes - -IVb. References - -The Sundance ST201 datasheet, preliminary version. -The Kendin KS8723 datasheet, preliminary version. -The ICplus IP100 datasheet, preliminary version. -http://www.scyld.com/expert/100mbps.html -http://www.scyld.com/expert/NWay.html - -IVc. Errata - -*/ - -/* Work-around for Kendin chip bugs. */ -#ifndef CONFIG_SUNDANCE_MMIO -#define USE_IO_OPS 1 -#endif - -static const struct pci_device_id sundance_pci_tbl[] = { - { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 }, - { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 }, - { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 }, - { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 }, - { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, - { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, - { } -}; -MODULE_DEVICE_TABLE(pci, sundance_pci_tbl); - -enum { - netdev_io_size = 128 -}; - -struct pci_id_info { - const char *name; -}; -static const struct pci_id_info pci_id_tbl[] = { - {"D-Link DFE-550TX FAST Ethernet Adapter"}, - {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"}, - {"D-Link DFE-580TX 4 port Server Adapter"}, - {"D-Link DFE-530TXS FAST Ethernet Adapter"}, - {"D-Link DL10050-based FAST Ethernet Adapter"}, - {"Sundance Technology Alta"}, - {"IC Plus Corporation IP100A FAST Ethernet Adapter"}, - { } /* terminate list. */ -}; - -/* This driver was written to use PCI memory space, however x86-oriented - hardware often uses I/O space accesses. */ - -/* Offsets to the device registers. - Unlike software-only systems, device drivers interact with complex hardware. - It's not useful to define symbolic names for every register bit in the - device. The name can only partially document the semantics and make - the driver longer and more difficult to read. - In general, only the important configuration values or bits changed - multiple times should be defined symbolically. -*/ -enum alta_offsets { - DMACtrl = 0x00, - TxListPtr = 0x04, - TxDMABurstThresh = 0x08, - TxDMAUrgentThresh = 0x09, - TxDMAPollPeriod = 0x0a, - RxDMAStatus = 0x0c, - RxListPtr = 0x10, - DebugCtrl0 = 0x1a, - DebugCtrl1 = 0x1c, - RxDMABurstThresh = 0x14, - RxDMAUrgentThresh = 0x15, - RxDMAPollPeriod = 0x16, - LEDCtrl = 0x1a, - ASICCtrl = 0x30, - EEData = 0x34, - EECtrl = 0x36, - FlashAddr = 0x40, - FlashData = 0x44, - WakeEvent = 0x45, - TxStatus = 0x46, - TxFrameId = 0x47, - DownCounter = 0x18, - IntrClear = 0x4a, - IntrEnable = 0x4c, - IntrStatus = 0x4e, - MACCtrl0 = 0x50, - MACCtrl1 = 0x52, - StationAddr = 0x54, - MaxFrameSize = 0x5A, - RxMode = 0x5c, - MIICtrl = 0x5e, - MulticastFilter0 = 0x60, - MulticastFilter1 = 0x64, - RxOctetsLow = 0x68, - RxOctetsHigh = 0x6a, - TxOctetsLow = 0x6c, - TxOctetsHigh = 0x6e, - TxFramesOK = 0x70, - RxFramesOK = 0x72, - StatsCarrierError = 0x74, - StatsLateColl = 0x75, - StatsMultiColl = 0x76, - StatsOneColl = 0x77, - StatsTxDefer = 0x78, - RxMissed = 0x79, - StatsTxXSDefer = 0x7a, - StatsTxAbort = 0x7b, - StatsBcastTx = 0x7c, - StatsBcastRx = 0x7d, - StatsMcastTx = 0x7e, - StatsMcastRx = 0x7f, - /* Aliased and bogus values! */ - RxStatus = 0x0c, -}; - -#define ASIC_HI_WORD(x) ((x) + 2) - -enum ASICCtrl_HiWord_bit { - GlobalReset = 0x0001, - RxReset = 0x0002, - TxReset = 0x0004, - DMAReset = 0x0008, - FIFOReset = 0x0010, - NetworkReset = 0x0020, - HostReset = 0x0040, - ResetBusy = 0x0400, -}; - -/* Bits in the interrupt status/mask registers. */ -enum intr_status_bits { - IntrSummary=0x0001, IntrPCIErr=0x0002, IntrMACCtrl=0x0008, - IntrTxDone=0x0004, IntrRxDone=0x0010, IntrRxStart=0x0020, - IntrDrvRqst=0x0040, - StatsMax=0x0080, LinkChange=0x0100, - IntrTxDMADone=0x0200, IntrRxDMADone=0x0400, -}; - -/* Bits in the RxMode register. */ -enum rx_mode_bits { - AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08, - AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01, -}; -/* Bits in MACCtrl. */ -enum mac_ctrl0_bits { - EnbFullDuplex=0x20, EnbRcvLargeFrame=0x40, - EnbFlowCtrl=0x100, EnbPassRxCRC=0x200, -}; -enum mac_ctrl1_bits { - StatsEnable=0x0020, StatsDisable=0x0040, StatsEnabled=0x0080, - TxEnable=0x0100, TxDisable=0x0200, TxEnabled=0x0400, - RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000, -}; - -/* Bits in WakeEvent register. */ -enum wake_event_bits { - WakePktEnable = 0x01, - MagicPktEnable = 0x02, - LinkEventEnable = 0x04, - WolEnable = 0x80, -}; - -/* The Rx and Tx buffer descriptors. */ -/* Note that using only 32 bit fields simplifies conversion to big-endian - architectures. */ -struct netdev_desc { - __le32 next_desc; - __le32 status; - struct desc_frag { __le32 addr, length; } frag; -}; - -/* Bits in netdev_desc.status */ -enum desc_status_bits { - DescOwn=0x8000, - DescEndPacket=0x4000, - DescEndRing=0x2000, - LastFrag=0x80000000, - DescIntrOnTx=0x8000, - DescIntrOnDMADone=0x80000000, - DisableAlign = 0x00000001, -}; - -#define PRIV_ALIGN 15 /* Required alignment mask */ -/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment - within the structure. */ -#define MII_CNT 4 -struct netdev_private { - /* Descriptor rings first for alignment. */ - struct netdev_desc *rx_ring; - struct netdev_desc *tx_ring; - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - dma_addr_t tx_ring_dma; - dma_addr_t rx_ring_dma; - struct timer_list timer; /* Media monitoring timer. */ - struct net_device *ndev; /* backpointer */ - /* ethtool extra stats */ - struct { - u64 tx_multiple_collisions; - u64 tx_single_collisions; - u64 tx_late_collisions; - u64 tx_deferred; - u64 tx_deferred_excessive; - u64 tx_aborted; - u64 tx_bcasts; - u64 rx_bcasts; - u64 tx_mcasts; - u64 rx_mcasts; - } xstats; - /* Frequently used values: keep some adjacent for cache effect. */ - spinlock_t lock; - int msg_enable; - int chip_id; - unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - struct netdev_desc *last_tx; /* Last Tx descriptor used. */ - unsigned int cur_tx, dirty_tx; - /* These values are keep track of the transceiver/media in use. */ - unsigned int flowctrl:1; - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int an_enable:1; - unsigned int speed; - unsigned int wol_enabled:1; /* Wake on LAN enabled */ - struct tasklet_struct rx_tasklet; - struct tasklet_struct tx_tasklet; - int budget; - int cur_task; - /* Multicast and receive mode. */ - spinlock_t mcastlock; /* SMP lock multicast updates. */ - u16 mcast_filter[4]; - /* MII transceiver section. */ - struct mii_if_info mii_if; - int mii_preamble_required; - unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ - struct pci_dev *pci_dev; - void __iomem *base; - spinlock_t statlock; -}; - -/* The station address location in the EEPROM. */ -#define EEPROM_SA_OFFSET 0x10 -#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \ - IntrDrvRqst | IntrTxDone | StatsMax | \ - LinkChange) - -static int change_mtu(struct net_device *dev, int new_mtu); -static int eeprom_read(void __iomem *ioaddr, int location); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static int mdio_wait_link(struct net_device *dev, int wait); -static int netdev_open(struct net_device *dev); -static void check_duplex(struct net_device *dev); -static void netdev_timer(struct timer_list *t); -static void tx_timeout(struct net_device *dev, unsigned int txqueue); -static void init_ring(struct net_device *dev); -static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev); -static int reset_tx (struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance); -static void rx_poll(struct tasklet_struct *t); -static void tx_poll(struct tasklet_struct *t); -static void refill_rx (struct net_device *dev); -static void netdev_error(struct net_device *dev, int intr_status); -static void netdev_error(struct net_device *dev, int intr_status); -static void set_rx_mode(struct net_device *dev); -static int __set_mac_addr(struct net_device *dev); -static int sundance_set_mac_addr(struct net_device *dev, void *data); -static struct net_device_stats *get_stats(struct net_device *dev); -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static int netdev_close(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; - -static void sundance_reset(struct net_device *dev, unsigned long reset_cmd) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base + ASICCtrl; - int countdown; - - /* ST201 documentation states ASICCtrl is a 32bit register */ - iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr); - /* ST201 documentation states reset can take up to 1 ms */ - countdown = 10 + 1; - while (ioread32 (ioaddr) & (ResetBusy << 16)) { - if (--countdown == 0) { - printk(KERN_WARNING "%s : reset not completed !!\n", dev->name); - break; - } - udelay(100); - } -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void sundance_poll_controller(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - - disable_irq(np->pci_dev->irq); - intr_handler(np->pci_dev->irq, dev); - enable_irq(np->pci_dev->irq); -} -#endif - -static const struct net_device_ops netdev_ops = { - .ndo_open = netdev_open, - .ndo_stop = netdev_close, - .ndo_start_xmit = start_tx, - .ndo_get_stats = get_stats, - .ndo_set_rx_mode = set_rx_mode, - .ndo_eth_ioctl = netdev_ioctl, - .ndo_tx_timeout = tx_timeout, - .ndo_change_mtu = change_mtu, - .ndo_set_mac_address = sundance_set_mac_addr, - .ndo_validate_addr = eth_validate_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = sundance_poll_controller, -#endif -}; - -static int sundance_probe1(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - struct netdev_private *np; - static int card_idx; - int chip_idx = ent->driver_data; - int irq; - int i; - void __iomem *ioaddr; - u16 mii_ctl; - void *ring_space; - dma_addr_t ring_dma; -#ifdef USE_IO_OPS - int bar = 0; -#else - int bar = 1; -#endif - int phy, phy_end, phy_idx = 0; - __le16 addr[ETH_ALEN / 2]; - - if (pci_enable_device(pdev)) - return -EIO; - pci_set_master(pdev); - - irq = pdev->irq; - - dev = alloc_etherdev(sizeof(*np)); - if (!dev) - return -ENOMEM; - SET_NETDEV_DEV(dev, &pdev->dev); - - if (pci_request_regions(pdev, DRV_NAME)) - goto err_out_netdev; - - ioaddr = pci_iomap(pdev, bar, netdev_io_size); - if (!ioaddr) - goto err_out_res; - - for (i = 0; i < 3; i++) - addr[i] = - cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); - eth_hw_addr_set(dev, (u8 *)addr); - - np = netdev_priv(dev); - np->ndev = dev; - np->base = ioaddr; - np->pci_dev = pdev; - np->chip_id = chip_idx; - np->msg_enable = (1 << debug) - 1; - spin_lock_init(&np->lock); - spin_lock_init(&np->statlock); - tasklet_setup(&np->rx_tasklet, rx_poll); - tasklet_setup(&np->tx_tasklet, tx_poll); - - ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, - &ring_dma, GFP_KERNEL); - if (!ring_space) - goto err_out_cleardev; - np->tx_ring = (struct netdev_desc *)ring_space; - np->tx_ring_dma = ring_dma; - - ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, - &ring_dma, GFP_KERNEL); - if (!ring_space) - goto err_out_unmap_tx; - np->rx_ring = (struct netdev_desc *)ring_space; - np->rx_ring_dma = ring_dma; - - np->mii_if.dev = dev; - np->mii_if.mdio_read = mdio_read; - np->mii_if.mdio_write = mdio_write; - np->mii_if.phy_id_mask = 0x1f; - np->mii_if.reg_num_mask = 0x1f; - - /* The chip-specific entries in the device structure. */ - dev->netdev_ops = &netdev_ops; - dev->ethtool_ops = ðtool_ops; - dev->watchdog_timeo = TX_TIMEOUT; - - /* MTU range: 68 - 8191 */ - dev->min_mtu = ETH_MIN_MTU; - dev->max_mtu = 8191; - - pci_set_drvdata(pdev, dev); - - i = register_netdev(dev); - if (i) - goto err_out_unmap_rx; - - printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", - dev->name, pci_id_tbl[chip_idx].name, ioaddr, - dev->dev_addr, irq); - - np->phys[0] = 1; /* Default setting */ - np->mii_preamble_required++; - - /* - * It seems some phys doesn't deal well with address 0 being accessed - * first - */ - if (sundance_pci_tbl[np->chip_id].device == 0x0200) { - phy = 0; - phy_end = 31; - } else { - phy = 1; - phy_end = 32; /* wraps to zero, due to 'phy & 0x1f' */ - } - for (; phy <= phy_end && phy_idx < MII_CNT; phy++) { - int phyx = phy & 0x1f; - int mii_status = mdio_read(dev, phyx, MII_BMSR); - if (mii_status != 0xffff && mii_status != 0x0000) { - np->phys[phy_idx++] = phyx; - np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE); - if ((mii_status & 0x0040) == 0) - np->mii_preamble_required++; - printk(KERN_INFO "%s: MII PHY found at address %d, status " - "0x%4.4x advertising %4.4x.\n", - dev->name, phyx, mii_status, np->mii_if.advertising); - } - } - np->mii_preamble_required--; - - if (phy_idx == 0) { - printk(KERN_INFO "%s: No MII transceiver found, aborting. ASIC status %x\n", - dev->name, ioread32(ioaddr + ASICCtrl)); - goto err_out_unregister; - } - - np->mii_if.phy_id = np->phys[0]; - - /* Parse override configuration */ - np->an_enable = 1; - if (card_idx < MAX_UNITS) { - if (media[card_idx] != NULL) { - np->an_enable = 0; - if (strcmp (media[card_idx], "100mbps_fd") == 0 || - strcmp (media[card_idx], "4") == 0) { - np->speed = 100; - np->mii_if.full_duplex = 1; - } else if (strcmp (media[card_idx], "100mbps_hd") == 0 || - strcmp (media[card_idx], "3") == 0) { - np->speed = 100; - np->mii_if.full_duplex = 0; - } else if (strcmp (media[card_idx], "10mbps_fd") == 0 || - strcmp (media[card_idx], "2") == 0) { - np->speed = 10; - np->mii_if.full_duplex = 1; - } else if (strcmp (media[card_idx], "10mbps_hd") == 0 || - strcmp (media[card_idx], "1") == 0) { - np->speed = 10; - np->mii_if.full_duplex = 0; - } else { - np->an_enable = 1; - } - } - if (flowctrl == 1) - np->flowctrl = 1; - } - - /* Fibre PHY? */ - if (ioread32 (ioaddr + ASICCtrl) & 0x80) { - /* Default 100Mbps Full */ - if (np->an_enable) { - np->speed = 100; - np->mii_if.full_duplex = 1; - np->an_enable = 0; - } - } - /* Reset PHY */ - mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET); - mdelay (300); - /* If flow control enabled, we need to advertise it.*/ - if (np->flowctrl) - mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400); - mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART); - /* Force media type */ - if (!np->an_enable) { - mii_ctl = 0; - mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0; - mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0; - mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl); - printk (KERN_INFO "Override speed=%d, %s duplex\n", - np->speed, np->mii_if.full_duplex ? "Full" : "Half"); - - } - - /* Perhaps move the reset here? */ - /* Reset the chip to erase previous misconfiguration. */ - if (netif_msg_hw(np)) - printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); - sundance_reset(dev, 0x00ff << 16); - if (netif_msg_hw(np)) - printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); - - card_idx++; - return 0; - -err_out_unregister: - unregister_netdev(dev); -err_out_unmap_rx: - dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, - np->rx_ring, np->rx_ring_dma); -err_out_unmap_tx: - dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, - np->tx_ring, np->tx_ring_dma); -err_out_cleardev: - pci_iounmap(pdev, ioaddr); -err_out_res: - pci_release_regions(pdev); -err_out_netdev: - free_netdev (dev); - return -ENODEV; -} - -static int change_mtu(struct net_device *dev, int new_mtu) -{ - if (netif_running(dev)) - return -EBUSY; - WRITE_ONCE(dev->mtu, new_mtu); - return 0; -} - -#define eeprom_delay(ee_addr) ioread32(ee_addr) -/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ -static int eeprom_read(void __iomem *ioaddr, int location) -{ - int boguscnt = 10000; /* Typical 1900 ticks. */ - iowrite16(0x0200 | (location & 0xff), ioaddr + EECtrl); - do { - eeprom_delay(ioaddr + EECtrl); - if (! (ioread16(ioaddr + EECtrl) & 0x8000)) { - return ioread16(ioaddr + EEData); - } - } while (--boguscnt > 0); - return 0; -} - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. - - The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back 33Mhz PCI cycles. */ -#define mdio_delay() ioread8(mdio_addr) - -enum mii_reg_bits { - MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004, -}; -#define MDIO_EnbIn (0) -#define MDIO_WRITE0 (MDIO_EnbOutput) -#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput) - -/* Generate the preamble required for initial synchronization and - a few older transceivers. */ -static void mdio_sync(void __iomem *mdio_addr) -{ - int bits = 32; - - /* Establish sync by sending at least 32 logic ones. */ - while (--bits >= 0) { - iowrite8(MDIO_WRITE1, mdio_addr); - mdio_delay(); - iowrite8(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); - mdio_delay(); - } -} - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *mdio_addr = np->base + MIICtrl; - int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int i, retval = 0; - - if (np->mii_preamble_required) - mdio_sync(mdio_addr); - - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; - - iowrite8(dataval, mdio_addr); - mdio_delay(); - iowrite8(dataval | MDIO_ShiftClk, mdio_addr); - mdio_delay(); - } - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - iowrite8(MDIO_EnbIn, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((ioread8(mdio_addr) & MDIO_Data) ? 1 : 0); - iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); - mdio_delay(); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *mdio_addr = np->base + MIICtrl; - int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - int i; - - if (np->mii_preamble_required) - mdio_sync(mdio_addr); - - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; - - iowrite8(dataval, mdio_addr); - mdio_delay(); - iowrite8(dataval | MDIO_ShiftClk, mdio_addr); - mdio_delay(); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - iowrite8(MDIO_EnbIn, mdio_addr); - mdio_delay(); - iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); - mdio_delay(); - } -} - -static int mdio_wait_link(struct net_device *dev, int wait) -{ - int bmsr; - int phy_id; - struct netdev_private *np; - - np = netdev_priv(dev); - phy_id = np->phys[0]; - - do { - bmsr = mdio_read(dev, phy_id, MII_BMSR); - if (bmsr & 0x0004) - return 0; - mdelay(1); - } while (--wait > 0); - return -1; -} - -static int netdev_open(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - const int irq = np->pci_dev->irq; - unsigned long flags; - int i; - - sundance_reset(dev, 0x00ff << 16); - - i = request_irq(irq, intr_handler, IRQF_SHARED, dev->name, dev); - if (i) - return i; - - if (netif_msg_ifup(np)) - printk(KERN_DEBUG "%s: netdev_open() irq %d\n", dev->name, irq); - - init_ring(dev); - - iowrite32(np->rx_ring_dma, ioaddr + RxListPtr); - /* The Tx list pointer is written as packets are queued. */ - - /* Initialize other registers. */ - __set_mac_addr(dev); -#if IS_ENABLED(CONFIG_VLAN_8021Q) - iowrite16(dev->mtu + 18, ioaddr + MaxFrameSize); -#else - iowrite16(dev->mtu + 14, ioaddr + MaxFrameSize); -#endif - if (dev->mtu > 2047) - iowrite32(ioread32(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl); - - /* Configure the PCI bus bursts and FIFO thresholds. */ - - if (dev->if_port == 0) - dev->if_port = np->default_port; - - spin_lock_init(&np->mcastlock); - - set_rx_mode(dev); - iowrite16(0, ioaddr + IntrEnable); - iowrite16(0, ioaddr + DownCounter); - /* Set the chip to poll every N*320nsec. */ - iowrite8(100, ioaddr + RxDMAPollPeriod); - iowrite8(127, ioaddr + TxDMAPollPeriod); - /* Fix DFE-580TX packet drop issue */ - if (np->pci_dev->revision >= 0x14) - iowrite8(0x01, ioaddr + DebugCtrl1); - netif_start_queue(dev); - - spin_lock_irqsave(&np->lock, flags); - reset_tx(dev); - spin_unlock_irqrestore(&np->lock, flags); - - iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); - - /* Disable Wol */ - iowrite8(ioread8(ioaddr + WakeEvent) | 0x00, ioaddr + WakeEvent); - np->wol_enabled = 0; - - if (netif_msg_ifup(np)) - printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " - "MAC Control %x, %4.4x %4.4x.\n", - dev->name, ioread32(ioaddr + RxStatus), ioread8(ioaddr + TxStatus), - ioread32(ioaddr + MACCtrl0), - ioread16(ioaddr + MACCtrl1), ioread16(ioaddr + MACCtrl0)); - - /* Set the timer to check for link beat. */ - timer_setup(&np->timer, netdev_timer, 0); - np->timer.expires = jiffies + 3*HZ; - add_timer(&np->timer); - - /* Enable interrupts by setting the interrupt mask. */ - iowrite16(DEFAULT_INTR, ioaddr + IntrEnable); - - return 0; -} - -static void check_duplex(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); - int negotiated = mii_lpa & np->mii_if.advertising; - int duplex; - - /* Force media */ - if (!np->an_enable || mii_lpa == 0xffff) { - if (np->mii_if.full_duplex) - iowrite16 (ioread16 (ioaddr + MACCtrl0) | EnbFullDuplex, - ioaddr + MACCtrl0); - return; - } - - /* Autonegotiation */ - duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; - if (np->mii_if.full_duplex != duplex) { - np->mii_if.full_duplex = duplex; - if (netif_msg_link(np)) - printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " - "negotiated capability %4.4x.\n", dev->name, - duplex ? "full" : "half", np->phys[0], negotiated); - iowrite16(ioread16(ioaddr + MACCtrl0) | (duplex ? 0x20 : 0), ioaddr + MACCtrl0); - } -} - -static void netdev_timer(struct timer_list *t) -{ - struct netdev_private *np = from_timer(np, t, timer); - struct net_device *dev = np->mii_if.dev; - void __iomem *ioaddr = np->base; - int next_tick = 10*HZ; - - if (netif_msg_timer(np)) { - printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, " - "Tx %x Rx %x.\n", - dev->name, ioread16(ioaddr + IntrEnable), - ioread8(ioaddr + TxStatus), ioread32(ioaddr + RxStatus)); - } - check_duplex(dev); - np->timer.expires = jiffies + next_tick; - add_timer(&np->timer); -} - -static void tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - unsigned long flag; - - netif_stop_queue(dev); - tasklet_disable_in_atomic(&np->tx_tasklet); - iowrite16(0, ioaddr + IntrEnable); - printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x " - "TxFrameId %2.2x," - " resetting...\n", dev->name, ioread8(ioaddr + TxStatus), - ioread8(ioaddr + TxFrameId)); - - { - int i; - for (i=0; itx_ring_dma + i*sizeof(*np->tx_ring)), - le32_to_cpu(np->tx_ring[i].next_desc), - le32_to_cpu(np->tx_ring[i].status), - (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff, - le32_to_cpu(np->tx_ring[i].frag.addr), - le32_to_cpu(np->tx_ring[i].frag.length)); - } - printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", - ioread32(np->base + TxListPtr), - netif_queue_stopped(dev)); - printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", - np->cur_tx, np->cur_tx % TX_RING_SIZE, - np->dirty_tx, np->dirty_tx % TX_RING_SIZE); - printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx); - printk(KERN_DEBUG "cur_task=%d\n", np->cur_task); - } - spin_lock_irqsave(&np->lock, flag); - - /* Stop and restart the chip's Tx processes . */ - reset_tx(dev); - spin_unlock_irqrestore(&np->lock, flag); - - dev->if_port = 0; - - netif_trans_update(dev); /* prevent tx timeout */ - dev->stats.tx_errors++; - if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { - netif_wake_queue(dev); - } - iowrite16(DEFAULT_INTR, ioaddr + IntrEnable); - tasklet_enable(&np->tx_tasklet); -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void init_ring(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - int i; - - np->cur_rx = np->cur_tx = 0; - np->dirty_rx = np->dirty_tx = 0; - np->cur_task = 0; - - np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16); - - /* Initialize all Rx descriptors. */ - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma + - ((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring)); - np->rx_ring[i].status = 0; - np->rx_ring[i].frag.length = 0; - np->rx_skbuff[i] = NULL; - } - - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = - netdev_alloc_skb(dev, np->rx_buf_sz + 2); - np->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb_reserve(skb, 2); /* 16 byte align the IP header. */ - np->rx_ring[i].frag.addr = cpu_to_le32( - dma_map_single(&np->pci_dev->dev, skb->data, - np->rx_buf_sz, DMA_FROM_DEVICE)); - if (dma_mapping_error(&np->pci_dev->dev, - np->rx_ring[i].frag.addr)) { - dev_kfree_skb(skb); - np->rx_skbuff[i] = NULL; - break; - } - np->rx_ring[i].frag.length = cpu_to_le32(np->rx_buf_sz | LastFrag); - } - np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_skbuff[i] = NULL; - np->tx_ring[i].status = 0; - } -} - -static void tx_poll(struct tasklet_struct *t) -{ - struct netdev_private *np = from_tasklet(np, t, tx_tasklet); - unsigned head = np->cur_task % TX_RING_SIZE; - struct netdev_desc *txdesc = - &np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE]; - - /* Chain the next pointer */ - for (; np->cur_tx - np->cur_task > 0; np->cur_task++) { - int entry = np->cur_task % TX_RING_SIZE; - txdesc = &np->tx_ring[entry]; - if (np->last_tx) { - np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma + - entry*sizeof(struct netdev_desc)); - } - np->last_tx = txdesc; - } - /* Indicate the latest descriptor of tx ring */ - txdesc->status |= cpu_to_le32(DescIntrOnTx); - - if (ioread32 (np->base + TxListPtr) == 0) - iowrite32 (np->tx_ring_dma + head * sizeof(struct netdev_desc), - np->base + TxListPtr); -} - -static netdev_tx_t -start_tx (struct sk_buff *skb, struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - struct netdev_desc *txdesc; - unsigned entry; - - /* Calculate the next Tx descriptor entry. */ - entry = np->cur_tx % TX_RING_SIZE; - np->tx_skbuff[entry] = skb; - txdesc = &np->tx_ring[entry]; - - txdesc->next_desc = 0; - txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign); - txdesc->frag.addr = cpu_to_le32(dma_map_single(&np->pci_dev->dev, - skb->data, skb->len, DMA_TO_DEVICE)); - if (dma_mapping_error(&np->pci_dev->dev, - txdesc->frag.addr)) - goto drop_frame; - txdesc->frag.length = cpu_to_le32 (skb->len | LastFrag); - - /* Increment cur_tx before tasklet_schedule() */ - np->cur_tx++; - mb(); - /* Schedule a tx_poll() task */ - tasklet_schedule(&np->tx_tasklet); - - /* On some architectures: explicitly flush cache lines here. */ - if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1 && - !netif_queue_stopped(dev)) { - /* do nothing */ - } else { - netif_stop_queue (dev); - } - if (netif_msg_tx_queued(np)) { - printk (KERN_DEBUG - "%s: Transmit frame #%d queued in slot %d.\n", - dev->name, np->cur_tx, entry); - } - return NETDEV_TX_OK; - -drop_frame: - dev_kfree_skb_any(skb); - np->tx_skbuff[entry] = NULL; - dev->stats.tx_dropped++; - return NETDEV_TX_OK; -} - -/* Reset hardware tx and free all of tx buffers */ -static int -reset_tx (struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - struct sk_buff *skb; - int i; - - /* Reset tx logic, TxListPtr will be cleaned */ - iowrite16 (TxDisable, ioaddr + MACCtrl1); - sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16); - - /* free all tx skbuff */ - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_ring[i].next_desc = 0; - - skb = np->tx_skbuff[i]; - if (skb) { - dma_unmap_single(&np->pci_dev->dev, - le32_to_cpu(np->tx_ring[i].frag.addr), - skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - np->tx_skbuff[i] = NULL; - dev->stats.tx_dropped++; - } - } - np->cur_tx = np->dirty_tx = 0; - np->cur_task = 0; - - np->last_tx = NULL; - iowrite8(127, ioaddr + TxDMAPollPeriod); - - iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); - return 0; -} - -/* The interrupt handler cleans up after the Tx thread, - and schedule a Rx thread work */ -static irqreturn_t intr_handler(int irq, void *dev_instance) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - int hw_frame_id; - int tx_cnt; - int tx_status; - int handled = 0; - int i; - - do { - int intr_status = ioread16(ioaddr + IntrStatus); - iowrite16(intr_status, ioaddr + IntrStatus); - - if (netif_msg_intr(np)) - printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", - dev->name, intr_status); - - if (!(intr_status & DEFAULT_INTR)) - break; - - handled = 1; - - if (intr_status & (IntrRxDMADone)) { - iowrite16(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone), - ioaddr + IntrEnable); - if (np->budget < 0) - np->budget = RX_BUDGET; - tasklet_schedule(&np->rx_tasklet); - } - if (intr_status & (IntrTxDone | IntrDrvRqst)) { - tx_status = ioread16 (ioaddr + TxStatus); - for (tx_cnt=32; tx_status & 0x80; --tx_cnt) { - if (netif_msg_tx_done(np)) - printk - ("%s: Transmit status is %2.2x.\n", - dev->name, tx_status); - if (tx_status & 0x1e) { - if (netif_msg_tx_err(np)) - printk("%s: Transmit error status %4.4x.\n", - dev->name, tx_status); - dev->stats.tx_errors++; - if (tx_status & 0x10) - dev->stats.tx_fifo_errors++; - if (tx_status & 0x08) - dev->stats.collisions++; - if (tx_status & 0x04) - dev->stats.tx_fifo_errors++; - if (tx_status & 0x02) - dev->stats.tx_window_errors++; - - /* - ** This reset has been verified on - ** DFE-580TX boards ! phdm@macqel.be. - */ - if (tx_status & 0x10) { /* TxUnderrun */ - /* Restart Tx FIFO and transmitter */ - sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); - /* No need to reset the Tx pointer here */ - } - /* Restart the Tx. Need to make sure tx enabled */ - i = 10; - do { - iowrite16(ioread16(ioaddr + MACCtrl1) | TxEnable, ioaddr + MACCtrl1); - if (ioread16(ioaddr + MACCtrl1) & TxEnabled) - break; - mdelay(1); - } while (--i); - } - /* Yup, this is a documentation bug. It cost me *hours*. */ - iowrite16 (0, ioaddr + TxStatus); - if (tx_cnt < 0) { - iowrite32(5000, ioaddr + DownCounter); - break; - } - tx_status = ioread16 (ioaddr + TxStatus); - } - hw_frame_id = (tx_status >> 8) & 0xff; - } else { - hw_frame_id = ioread8(ioaddr + TxFrameId); - } - - if (np->pci_dev->revision >= 0x14) { - spin_lock(&np->lock); - for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { - int entry = np->dirty_tx % TX_RING_SIZE; - struct sk_buff *skb; - int sw_frame_id; - sw_frame_id = (le32_to_cpu( - np->tx_ring[entry].status) >> 2) & 0xff; - if (sw_frame_id == hw_frame_id && - !(le32_to_cpu(np->tx_ring[entry].status) - & 0x00010000)) - break; - if (sw_frame_id == (hw_frame_id + 1) % - TX_RING_SIZE) - break; - skb = np->tx_skbuff[entry]; - /* Free the original skb. */ - dma_unmap_single(&np->pci_dev->dev, - le32_to_cpu(np->tx_ring[entry].frag.addr), - skb->len, DMA_TO_DEVICE); - dev_consume_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = NULL; - np->tx_ring[entry].frag.addr = 0; - np->tx_ring[entry].frag.length = 0; - } - spin_unlock(&np->lock); - } else { - spin_lock(&np->lock); - for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { - int entry = np->dirty_tx % TX_RING_SIZE; - struct sk_buff *skb; - if (!(le32_to_cpu(np->tx_ring[entry].status) - & 0x00010000)) - break; - skb = np->tx_skbuff[entry]; - /* Free the original skb. */ - dma_unmap_single(&np->pci_dev->dev, - le32_to_cpu(np->tx_ring[entry].frag.addr), - skb->len, DMA_TO_DEVICE); - dev_consume_skb_irq(np->tx_skbuff[entry]); - np->tx_skbuff[entry] = NULL; - np->tx_ring[entry].frag.addr = 0; - np->tx_ring[entry].frag.length = 0; - } - spin_unlock(&np->lock); - } - - if (netif_queue_stopped(dev) && - np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { - /* The ring is no longer full, clear busy flag. */ - netif_wake_queue (dev); - } - /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & (IntrPCIErr | LinkChange | StatsMax)) - netdev_error(dev, intr_status); - } while (0); - if (netif_msg_intr(np)) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, ioread16(ioaddr + IntrStatus)); - return IRQ_RETVAL(handled); -} - -static void rx_poll(struct tasklet_struct *t) -{ - struct netdev_private *np = from_tasklet(np, t, rx_tasklet); - struct net_device *dev = np->ndev; - int entry = np->cur_rx % RX_RING_SIZE; - int boguscnt = np->budget; - void __iomem *ioaddr = np->base; - int received = 0; - - /* If EOP is set on the next entry, it's a new packet. Send it up. */ - while (1) { - struct netdev_desc *desc = &(np->rx_ring[entry]); - u32 frame_status = le32_to_cpu(desc->status); - int pkt_len; - - if (--boguscnt < 0) { - goto not_done; - } - if (!(frame_status & DescOwn)) - break; - pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */ - if (netif_msg_rx_status(np)) - printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", - frame_status); - if (frame_status & 0x001f4000) { - /* There was a error. */ - if (netif_msg_rx_err(np)) - printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", - frame_status); - dev->stats.rx_errors++; - if (frame_status & 0x00100000) - dev->stats.rx_length_errors++; - if (frame_status & 0x00010000) - dev->stats.rx_fifo_errors++; - if (frame_status & 0x00060000) - dev->stats.rx_frame_errors++; - if (frame_status & 0x00080000) - dev->stats.rx_crc_errors++; - if (frame_status & 0x00100000) { - printk(KERN_WARNING "%s: Oversized Ethernet frame," - " status %8.8x.\n", - dev->name, frame_status); - } - } else { - struct sk_buff *skb; -#ifndef final_version - if (netif_msg_rx_status(np)) - printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" - ", bogus_cnt %d.\n", - pkt_len, boguscnt); -#endif - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak && - (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { - skb_reserve(skb, 2); /* 16 byte align the IP header */ - dma_sync_single_for_cpu(&np->pci_dev->dev, - le32_to_cpu(desc->frag.addr), - np->rx_buf_sz, DMA_FROM_DEVICE); - skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len); - dma_sync_single_for_device(&np->pci_dev->dev, - le32_to_cpu(desc->frag.addr), - np->rx_buf_sz, DMA_FROM_DEVICE); - skb_put(skb, pkt_len); - } else { - dma_unmap_single(&np->pci_dev->dev, - le32_to_cpu(desc->frag.addr), - np->rx_buf_sz, DMA_FROM_DEVICE); - skb_put(skb = np->rx_skbuff[entry], pkt_len); - np->rx_skbuff[entry] = NULL; - } - skb->protocol = eth_type_trans(skb, dev); - /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */ - netif_rx(skb); - } - entry = (entry + 1) % RX_RING_SIZE; - received++; - } - np->cur_rx = entry; - refill_rx (dev); - np->budget -= received; - iowrite16(DEFAULT_INTR, ioaddr + IntrEnable); - return; - -not_done: - np->cur_rx = entry; - refill_rx (dev); - if (!received) - received = 1; - np->budget -= received; - if (np->budget <= 0) - np->budget = RX_BUDGET; - tasklet_schedule(&np->rx_tasklet); -} - -static void refill_rx (struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - int entry; - - /* Refill the Rx ring buffers. */ - for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0; - np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) { - struct sk_buff *skb; - entry = np->dirty_rx % RX_RING_SIZE; - if (np->rx_skbuff[entry] == NULL) { - skb = netdev_alloc_skb(dev, np->rx_buf_sz + 2); - np->rx_skbuff[entry] = skb; - if (skb == NULL) - break; /* Better luck next round. */ - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - np->rx_ring[entry].frag.addr = cpu_to_le32( - dma_map_single(&np->pci_dev->dev, skb->data, - np->rx_buf_sz, DMA_FROM_DEVICE)); - if (dma_mapping_error(&np->pci_dev->dev, - np->rx_ring[entry].frag.addr)) { - dev_kfree_skb_irq(skb); - np->rx_skbuff[entry] = NULL; - break; - } - } - /* Perhaps we need not reset this field. */ - np->rx_ring[entry].frag.length = - cpu_to_le32(np->rx_buf_sz | LastFrag); - np->rx_ring[entry].status = 0; - } -} -static void netdev_error(struct net_device *dev, int intr_status) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - u16 mii_ctl, mii_advertise, mii_lpa; - int speed; - - if (intr_status & LinkChange) { - if (mdio_wait_link(dev, 10) == 0) { - printk(KERN_INFO "%s: Link up\n", dev->name); - if (np->an_enable) { - mii_advertise = mdio_read(dev, np->phys[0], - MII_ADVERTISE); - mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); - mii_advertise &= mii_lpa; - printk(KERN_INFO "%s: Link changed: ", - dev->name); - if (mii_advertise & ADVERTISE_100FULL) { - np->speed = 100; - printk("100Mbps, full duplex\n"); - } else if (mii_advertise & ADVERTISE_100HALF) { - np->speed = 100; - printk("100Mbps, half duplex\n"); - } else if (mii_advertise & ADVERTISE_10FULL) { - np->speed = 10; - printk("10Mbps, full duplex\n"); - } else if (mii_advertise & ADVERTISE_10HALF) { - np->speed = 10; - printk("10Mbps, half duplex\n"); - } else - printk("\n"); - - } else { - mii_ctl = mdio_read(dev, np->phys[0], MII_BMCR); - speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; - np->speed = speed; - printk(KERN_INFO "%s: Link changed: %dMbps ,", - dev->name, speed); - printk("%s duplex.\n", - (mii_ctl & BMCR_FULLDPLX) ? - "full" : "half"); - } - check_duplex(dev); - if (np->flowctrl && np->mii_if.full_duplex) { - iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200, - ioaddr + MulticastFilter1+2); - iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl, - ioaddr + MACCtrl0); - } - netif_carrier_on(dev); - } else { - printk(KERN_INFO "%s: Link down\n", dev->name); - netif_carrier_off(dev); - } - } - if (intr_status & StatsMax) { - get_stats(dev); - } - if (intr_status & IntrPCIErr) { - printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", - dev->name, intr_status); - /* We must do a global reset of DMA to continue. */ - } -} - -static struct net_device_stats *get_stats(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - unsigned long flags; - u8 late_coll, single_coll, mult_coll; - - spin_lock_irqsave(&np->statlock, flags); - /* The chip only need report frame silently dropped. */ - dev->stats.rx_missed_errors += ioread8(ioaddr + RxMissed); - dev->stats.tx_packets += ioread16(ioaddr + TxFramesOK); - dev->stats.rx_packets += ioread16(ioaddr + RxFramesOK); - dev->stats.tx_carrier_errors += ioread8(ioaddr + StatsCarrierError); - - mult_coll = ioread8(ioaddr + StatsMultiColl); - np->xstats.tx_multiple_collisions += mult_coll; - single_coll = ioread8(ioaddr + StatsOneColl); - np->xstats.tx_single_collisions += single_coll; - late_coll = ioread8(ioaddr + StatsLateColl); - np->xstats.tx_late_collisions += late_coll; - dev->stats.collisions += mult_coll - + single_coll - + late_coll; - - np->xstats.tx_deferred += ioread8(ioaddr + StatsTxDefer); - np->xstats.tx_deferred_excessive += ioread8(ioaddr + StatsTxXSDefer); - np->xstats.tx_aborted += ioread8(ioaddr + StatsTxAbort); - np->xstats.tx_bcasts += ioread8(ioaddr + StatsBcastTx); - np->xstats.rx_bcasts += ioread8(ioaddr + StatsBcastRx); - np->xstats.tx_mcasts += ioread8(ioaddr + StatsMcastTx); - np->xstats.rx_mcasts += ioread8(ioaddr + StatsMcastRx); - - dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsLow); - dev->stats.tx_bytes += ioread16(ioaddr + TxOctetsHigh) << 16; - dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsLow); - dev->stats.rx_bytes += ioread16(ioaddr + RxOctetsHigh) << 16; - - spin_unlock_irqrestore(&np->statlock, flags); - - return &dev->stats; -} - -static void set_rx_mode(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - u16 mc_filter[4]; /* Multicast hash filter */ - u32 rx_mode; - int i; - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - memset(mc_filter, 0xff, sizeof(mc_filter)); - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys; - } else if ((netdev_mc_count(dev) > multicast_filter_limit) || - (dev->flags & IFF_ALLMULTI)) { - /* Too many to match, or accept all multicasts. */ - memset(mc_filter, 0xff, sizeof(mc_filter)); - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - } else if (!netdev_mc_empty(dev)) { - struct netdev_hw_addr *ha; - int bit; - int index; - int crc; - memset (mc_filter, 0, sizeof (mc_filter)); - netdev_for_each_mc_addr(ha, dev) { - crc = ether_crc_le(ETH_ALEN, ha->addr); - for (index=0, bit=0; bit < 6; bit++, crc <<= 1) - if (crc & 0x80000000) index |= 1 << bit; - mc_filter[index/16] |= (1 << (index % 16)); - } - rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys; - } else { - iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode); - return; - } - if (np->mii_if.full_duplex && np->flowctrl) - mc_filter[3] |= 0x0200; - - for (i = 0; i < 4; i++) - iowrite16(mc_filter[i], ioaddr + MulticastFilter0 + i*2); - iowrite8(rx_mode, ioaddr + RxMode); -} - -static int __set_mac_addr(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - u16 addr16; - - addr16 = (dev->dev_addr[0] | (dev->dev_addr[1] << 8)); - iowrite16(addr16, np->base + StationAddr); - addr16 = (dev->dev_addr[2] | (dev->dev_addr[3] << 8)); - iowrite16(addr16, np->base + StationAddr+2); - addr16 = (dev->dev_addr[4] | (dev->dev_addr[5] << 8)); - iowrite16(addr16, np->base + StationAddr+4); - return 0; -} - -/* Invoked with rtnl_lock held */ -static int sundance_set_mac_addr(struct net_device *dev, void *data) -{ - const struct sockaddr *addr = data; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - eth_hw_addr_set(dev, addr->sa_data); - __set_mac_addr(dev); - - return 0; -} - -static const struct { - const char name[ETH_GSTRING_LEN]; -} sundance_stats[] = { - { "tx_multiple_collisions" }, - { "tx_single_collisions" }, - { "tx_late_collisions" }, - { "tx_deferred" }, - { "tx_deferred_excessive" }, - { "tx_aborted" }, - { "tx_bcasts" }, - { "rx_bcasts" }, - { "tx_mcasts" }, - { "rx_mcasts" }, -}; - -static int check_if_running(struct net_device *dev) -{ - if (!netif_running(dev)) - return -EINVAL; - return 0; -} - -static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct netdev_private *np = netdev_priv(dev); - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); -} - -static int get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *cmd) -{ - struct netdev_private *np = netdev_priv(dev); - spin_lock_irq(&np->lock); - mii_ethtool_get_link_ksettings(&np->mii_if, cmd); - spin_unlock_irq(&np->lock); - return 0; -} - -static int set_link_ksettings(struct net_device *dev, - const struct ethtool_link_ksettings *cmd) -{ - struct netdev_private *np = netdev_priv(dev); - int res; - spin_lock_irq(&np->lock); - res = mii_ethtool_set_link_ksettings(&np->mii_if, cmd); - spin_unlock_irq(&np->lock); - return res; -} - -static int nway_reset(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - return mii_nway_restart(&np->mii_if); -} - -static u32 get_link(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - return mii_link_ok(&np->mii_if); -} - -static u32 get_msglevel(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - return np->msg_enable; -} - -static void set_msglevel(struct net_device *dev, u32 val) -{ - struct netdev_private *np = netdev_priv(dev); - np->msg_enable = val; -} - -static void get_strings(struct net_device *dev, u32 stringset, - u8 *data) -{ - if (stringset == ETH_SS_STATS) - memcpy(data, sundance_stats, sizeof(sundance_stats)); -} - -static int get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return ARRAY_SIZE(sundance_stats); - default: - return -EOPNOTSUPP; - } -} - -static void get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct netdev_private *np = netdev_priv(dev); - int i = 0; - - get_stats(dev); - data[i++] = np->xstats.tx_multiple_collisions; - data[i++] = np->xstats.tx_single_collisions; - data[i++] = np->xstats.tx_late_collisions; - data[i++] = np->xstats.tx_deferred; - data[i++] = np->xstats.tx_deferred_excessive; - data[i++] = np->xstats.tx_aborted; - data[i++] = np->xstats.tx_bcasts; - data[i++] = np->xstats.rx_bcasts; - data[i++] = np->xstats.tx_mcasts; - data[i++] = np->xstats.rx_mcasts; -} - -#ifdef CONFIG_PM - -static void sundance_get_wol(struct net_device *dev, - struct ethtool_wolinfo *wol) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - u8 wol_bits; - - wol->wolopts = 0; - - wol->supported = (WAKE_PHY | WAKE_MAGIC); - if (!np->wol_enabled) - return; - - wol_bits = ioread8(ioaddr + WakeEvent); - if (wol_bits & MagicPktEnable) - wol->wolopts |= WAKE_MAGIC; - if (wol_bits & LinkEventEnable) - wol->wolopts |= WAKE_PHY; -} - -static int sundance_set_wol(struct net_device *dev, - struct ethtool_wolinfo *wol) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - u8 wol_bits; - - if (!device_can_wakeup(&np->pci_dev->dev)) - return -EOPNOTSUPP; - - np->wol_enabled = !!(wol->wolopts); - wol_bits = ioread8(ioaddr + WakeEvent); - wol_bits &= ~(WakePktEnable | MagicPktEnable | - LinkEventEnable | WolEnable); - - if (np->wol_enabled) { - if (wol->wolopts & WAKE_MAGIC) - wol_bits |= (MagicPktEnable | WolEnable); - if (wol->wolopts & WAKE_PHY) - wol_bits |= (LinkEventEnable | WolEnable); - } - iowrite8(wol_bits, ioaddr + WakeEvent); - - device_set_wakeup_enable(&np->pci_dev->dev, np->wol_enabled); - - return 0; -} -#else -#define sundance_get_wol NULL -#define sundance_set_wol NULL -#endif /* CONFIG_PM */ - -static const struct ethtool_ops ethtool_ops = { - .begin = check_if_running, - .get_drvinfo = get_drvinfo, - .nway_reset = nway_reset, - .get_link = get_link, - .get_wol = sundance_get_wol, - .set_wol = sundance_set_wol, - .get_msglevel = get_msglevel, - .set_msglevel = set_msglevel, - .get_strings = get_strings, - .get_sset_count = get_sset_count, - .get_ethtool_stats = get_ethtool_stats, - .get_link_ksettings = get_link_ksettings, - .set_link_ksettings = set_link_ksettings, -}; - -static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct netdev_private *np = netdev_priv(dev); - int rc; - - if (!netif_running(dev)) - return -EINVAL; - - spin_lock_irq(&np->lock); - rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL); - spin_unlock_irq(&np->lock); - - return rc; -} - -static int netdev_close(struct net_device *dev) -{ - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - struct sk_buff *skb; - int i; - - /* Wait and kill tasklet */ - tasklet_kill(&np->rx_tasklet); - tasklet_kill(&np->tx_tasklet); - np->cur_tx = 0; - np->dirty_tx = 0; - np->cur_task = 0; - np->last_tx = NULL; - - netif_stop_queue(dev); - - if (netif_msg_ifdown(np)) { - printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x " - "Rx %4.4x Int %2.2x.\n", - dev->name, ioread8(ioaddr + TxStatus), - ioread32(ioaddr + RxStatus), ioread16(ioaddr + IntrStatus)); - printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", - dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); - } - - /* Disable interrupts by clearing the interrupt mask. */ - iowrite16(0x0000, ioaddr + IntrEnable); - - /* Disable Rx and Tx DMA for safely release resource */ - iowrite32(0x500, ioaddr + DMACtrl); - - /* Stop the chip's Tx and Rx processes. */ - iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); - - for (i = 2000; i > 0; i--) { - if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0) - break; - mdelay(1); - } - - iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset, - ioaddr + ASIC_HI_WORD(ASICCtrl)); - - for (i = 2000; i > 0; i--) { - if ((ioread16(ioaddr + ASIC_HI_WORD(ASICCtrl)) & ResetBusy) == 0) - break; - mdelay(1); - } - -#ifdef __i386__ - if (netif_msg_hw(np)) { - printk(KERN_DEBUG " Tx ring at %8.8x:\n", - (int)(np->tx_ring_dma)); - for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_DEBUG " #%d desc. %4.4x %8.8x %8.8x.\n", - i, np->tx_ring[i].status, np->tx_ring[i].frag.addr, - np->tx_ring[i].frag.length); - printk(KERN_DEBUG " Rx ring %8.8x:\n", - (int)(np->rx_ring_dma)); - for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) { - printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n", - i, np->rx_ring[i].status, np->rx_ring[i].frag.addr, - np->rx_ring[i].frag.length); - } - } -#endif /* __i386__ debugging only */ - - free_irq(np->pci_dev->irq, dev); - - del_timer_sync(&np->timer); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - np->rx_ring[i].status = 0; - skb = np->rx_skbuff[i]; - if (skb) { - dma_unmap_single(&np->pci_dev->dev, - le32_to_cpu(np->rx_ring[i].frag.addr), - np->rx_buf_sz, DMA_FROM_DEVICE); - dev_kfree_skb(skb); - np->rx_skbuff[i] = NULL; - } - np->rx_ring[i].frag.addr = cpu_to_le32(0xBADF00D0); /* poison */ - } - for (i = 0; i < TX_RING_SIZE; i++) { - np->tx_ring[i].next_desc = 0; - skb = np->tx_skbuff[i]; - if (skb) { - dma_unmap_single(&np->pci_dev->dev, - le32_to_cpu(np->tx_ring[i].frag.addr), - skb->len, DMA_TO_DEVICE); - dev_kfree_skb(skb); - np->tx_skbuff[i] = NULL; - } - } - - return 0; -} - -static void sundance_remove1(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - if (dev) { - struct netdev_private *np = netdev_priv(dev); - unregister_netdev(dev); - dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, - np->rx_ring, np->rx_ring_dma); - dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, - np->tx_ring, np->tx_ring_dma); - pci_iounmap(pdev, np->base); - pci_release_regions(pdev); - free_netdev(dev); - } -} - -static int __maybe_unused sundance_suspend(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; - - if (!netif_running(dev)) - return 0; - - netdev_close(dev); - netif_device_detach(dev); - - if (np->wol_enabled) { - iowrite8(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode); - iowrite16(RxEnable, ioaddr + MACCtrl1); - } - - device_set_wakeup_enable(dev_d, np->wol_enabled); - - return 0; -} - -static int __maybe_unused sundance_resume(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - int err = 0; - - if (!netif_running(dev)) - return 0; - - err = netdev_open(dev); - if (err) { - printk(KERN_ERR "%s: Can't resume interface!\n", - dev->name); - goto out; - } - - netif_device_attach(dev); - -out: - return err; -} - -static SIMPLE_DEV_PM_OPS(sundance_pm_ops, sundance_suspend, sundance_resume); - -static struct pci_driver sundance_driver = { - .name = DRV_NAME, - .id_table = sundance_pci_tbl, - .probe = sundance_probe1, - .remove = sundance_remove1, - .driver.pm = &sundance_pm_ops, -}; - -module_pci_driver(sundance_driver); diff --git a/drivers/net/ethernet/dnet.c b/drivers/net/ethernet/dnet.c index 2a18df3605f125..0de3cd660ec80f 100644 --- a/drivers/net/ethernet/dnet.c +++ b/drivers/net/ethernet/dnet.c @@ -863,7 +863,7 @@ static void dnet_remove(struct platform_device *pdev) static struct platform_driver dnet_driver = { .probe = dnet_probe, - .remove_new = dnet_remove, + .remove = dnet_remove, .driver = { .name = "dnet", }, diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c index 44da335d66bda2..95a5295d036184 100644 --- a/drivers/net/ethernet/engleder/tsnep_main.c +++ b/drivers/net/ethernet/engleder/tsnep_main.c @@ -2689,7 +2689,7 @@ static struct platform_driver tsnep_driver = { .of_match_table = tsnep_of_match, }, .probe = tsnep_probe, - .remove_new = tsnep_remove, + .remove = tsnep_remove, }; module_platform_driver(tsnep_driver); diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index ad41c90190180c..0c418557264c2b 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1296,7 +1296,7 @@ MODULE_DEVICE_TABLE(of, ethoc_match); static struct platform_driver ethoc_driver = { .probe = ethoc_probe, - .remove_new = ethoc_remove, + .remove = ethoc_remove, .suspend = ethoc_suspend, .resume = ethoc_resume, .driver = { diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 9ebe751c1df075..5cb478e9869776 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -651,7 +651,7 @@ MODULE_DEVICE_TABLE(of, nps_enet_dt_ids); static struct platform_driver nps_enet_driver = { .probe = nps_enet_probe, - .remove_new = nps_enet_remove, + .remove = nps_enet_remove, .driver = { .name = DRV_NAME, .of_match_table = nps_enet_dt_ids, diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 0b61f548fd188f..17ec35e75a6563 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -1913,40 +1913,22 @@ static int ftgmac100_probe(struct platform_device *pdev) goto err_phy_connect; } err = phy_connect_direct(netdev, phydev, ftgmac100_adjust_link, - PHY_INTERFACE_MODE_MII); + PHY_INTERFACE_MODE_RMII); if (err) { dev_err(&pdev->dev, "Connecting PHY failed\n"); goto err_phy_connect; } - } else if (np && of_phy_is_fixed_link(np)) { - struct phy_device *phy; - - err = of_phy_register_fixed_link(np); - if (err) { - dev_err(&pdev->dev, "Failed to register fixed PHY\n"); - goto err_phy_connect; - } - - phy = of_phy_get_and_connect(priv->netdev, np, - &ftgmac100_adjust_link); - if (!phy) { - dev_err(&pdev->dev, "Failed to connect to fixed PHY\n"); - of_phy_deregister_fixed_link(np); - err = -EINVAL; - goto err_phy_connect; - } - - /* Display what we found */ - phy_attached_info(phy); - } else if (np && of_get_property(np, "phy-handle", NULL)) { + } else if (np && (of_phy_is_fixed_link(np) || + of_get_property(np, "phy-handle", NULL))) { struct phy_device *phy; /* Support "mdio"/"phy" child nodes for ast2400/2500 with * an embedded MDIO controller. Automatically scan the DTS for * available PHYs and register them. */ - if (of_device_is_compatible(np, "aspeed,ast2400-mac") || - of_device_is_compatible(np, "aspeed,ast2500-mac")) { + if (of_get_property(np, "phy-handle", NULL) && + (of_device_is_compatible(np, "aspeed,ast2400-mac") || + of_device_is_compatible(np, "aspeed,ast2500-mac"))) { err = ftgmac100_setup_mdio(netdev); if (err) goto err_setup_mdio; @@ -2089,7 +2071,7 @@ MODULE_DEVICE_TABLE(of, ftgmac100_of_match); static struct platform_driver ftgmac100_driver = { .probe = ftgmac100_probe, - .remove_new = ftgmac100_remove, + .remove = ftgmac100_remove, .driver = { .name = DRV_NAME, .of_match_table = ftgmac100_of_match, diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index 1047c805054eae..5803a382f0ba65 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -1243,7 +1243,7 @@ static const struct of_device_id ftmac100_of_ids[] = { static struct platform_driver ftmac100_driver = { .probe = ftmac100_probe, - .remove_new = ftmac100_remove, + .remove = ftmac100_remove, .driver = { .name = DRV_NAME, .of_match_table = ftmac100_of_ids diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index e15dd3d858df21..bf5baef5c3e065 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -463,6 +463,22 @@ static int dpaa_set_mac_address(struct net_device *net_dev, void *addr) return 0; } +static int dpaa_addr_sync(struct net_device *net_dev, const u8 *addr) +{ + const struct dpaa_priv *priv = netdev_priv(net_dev); + + return priv->mac_dev->add_hash_mac_addr(priv->mac_dev->fman_mac, + (enet_addr_t *)addr); +} + +static int dpaa_addr_unsync(struct net_device *net_dev, const u8 *addr) +{ + const struct dpaa_priv *priv = netdev_priv(net_dev); + + return priv->mac_dev->remove_hash_mac_addr(priv->mac_dev->fman_mac, + (enet_addr_t *)addr); +} + static void dpaa_set_rx_mode(struct net_device *net_dev) { const struct dpaa_priv *priv; @@ -490,9 +506,9 @@ static void dpaa_set_rx_mode(struct net_device *net_dev) err); } - err = priv->mac_dev->set_multi(net_dev, priv->mac_dev); + err = __dev_mc_sync(net_dev, dpaa_addr_sync, dpaa_addr_unsync); if (err < 0) - netif_err(priv, drv, net_dev, "mac_dev->set_multi() = %d\n", + netif_err(priv, drv, net_dev, "dpaa_addr_sync() = %d\n", err); } @@ -1804,7 +1820,6 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, struct page *page, *head_page; struct dpaa_bp *dpaa_bp; void *vaddr, *sg_vaddr; - int frag_off, frag_len; struct sk_buff *skb; dma_addr_t sg_addr; int page_offset; @@ -1847,6 +1862,11 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, * on Tx, if extra headers are added. */ WARN_ON(fd_off != priv->rx_headroom); + /* The offset to data start within the buffer holding + * the SGT should always be equal to the offset to data + * start within the first buffer holding the frame. + */ + WARN_ON_ONCE(fd_off != qm_sg_entry_get_off(&sgt[i])); skb_reserve(skb, fd_off); skb_put(skb, qm_sg_entry_get_len(&sgt[i])); } else { @@ -1860,21 +1880,23 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, page = virt_to_page(sg_vaddr); head_page = virt_to_head_page(sg_vaddr); - /* Compute offset in (possibly tail) page */ + /* Compute offset of sg_vaddr in (possibly tail) page */ page_offset = ((unsigned long)sg_vaddr & (PAGE_SIZE - 1)) + (page_address(page) - page_address(head_page)); - /* page_offset only refers to the beginning of sgt[i]; - * but the buffer itself may have an internal offset. + + /* Non-initial SGT entries should not have a buffer + * offset. */ - frag_off = qm_sg_entry_get_off(&sgt[i]) + page_offset; - frag_len = qm_sg_entry_get_len(&sgt[i]); + WARN_ON_ONCE(qm_sg_entry_get_off(&sgt[i])); + /* skb_add_rx_frag() does no checking on the page; if * we pass it a tail page, we'll end up with - * bad page accounting and eventually with segafults. + * bad page accounting and eventually with segfaults. */ - skb_add_rx_frag(skb, i - 1, head_page, frag_off, - frag_len, dpaa_bp->size); + skb_add_rx_frag(skb, i - 1, head_page, page_offset, + qm_sg_entry_get_len(&sgt[i]), + dpaa_bp->size); } /* Update the pool count for the current {cpu x bpool} */ @@ -2750,7 +2772,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal, if (net_dev->features & NETIF_F_RXHASH && priv->keygen_in_use && !fman_port_get_hash_result_offset(priv->mac_dev->port[RX], &hash_offset)) { - hash = be32_to_cpu(*(u32 *)(vaddr + hash_offset)); + hash = be32_to_cpu(*(__be32 *)(vaddr + hash_offset)); hash_valid = true; } @@ -3571,7 +3593,7 @@ static struct platform_driver dpaa_driver = { }, .id_table = dpaa_devtype, .probe = dpaa_eth_probe, - .remove_new = dpaa_remove + .remove = dpaa_remove }; static int __init dpaa_load(void) diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index b0060cf96090e8..9986f6e1f58774 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -243,38 +243,24 @@ static void dpaa_get_ethtool_stats(struct net_device *net_dev, static void dpaa_get_strings(struct net_device *net_dev, u32 stringset, u8 *data) { - unsigned int i, j, num_cpus, size; - char string_cpu[ETH_GSTRING_LEN]; - u8 *strings; + unsigned int i, j, num_cpus; - memset(string_cpu, 0, sizeof(string_cpu)); - strings = data; - num_cpus = num_online_cpus(); - size = DPAA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN; + num_cpus = num_online_cpus(); for (i = 0; i < DPAA_STATS_PERCPU_LEN; i++) { - for (j = 0; j < num_cpus; j++) { - snprintf(string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]", - dpaa_stats_percpu[i], j); - memcpy(strings, string_cpu, ETH_GSTRING_LEN); - strings += ETH_GSTRING_LEN; - } - snprintf(string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]", - dpaa_stats_percpu[i]); - memcpy(strings, string_cpu, ETH_GSTRING_LEN); - strings += ETH_GSTRING_LEN; - } - for (j = 0; j < num_cpus; j++) { - snprintf(string_cpu, ETH_GSTRING_LEN, - "bpool [CPU %d]", j); - memcpy(strings, string_cpu, ETH_GSTRING_LEN); - strings += ETH_GSTRING_LEN; + for (j = 0; j < num_cpus; j++) + ethtool_sprintf(&data, "%s [CPU %d]", + dpaa_stats_percpu[i], j); + + ethtool_sprintf(&data, "%s [TOTAL]", dpaa_stats_percpu[i]); } - snprintf(string_cpu, ETH_GSTRING_LEN, "bpool [TOTAL]"); - memcpy(strings, string_cpu, ETH_GSTRING_LEN); - strings += ETH_GSTRING_LEN; + for (i = 0; i < num_cpus; i++) + ethtool_sprintf(&data, "bpool [CPU %d]", i); + + ethtool_puts(&data, "bpool [TOTAL]"); - memcpy(strings, dpaa_stats_global, size); + for (i = 0; i < DPAA_STATS_GLOBAL_LEN; i++) + ethtool_puts(&data, dpaa_stats_global[i]); } static int dpaa_get_hash_opts(struct net_device *dev, diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c index 7f476519b7adf8..74ef77cb70780c 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -217,20 +217,15 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev, static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { - u8 *p = data; int i; switch (stringset) { case ETH_SS_STATS: - for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) { - strscpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } - for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) { - strscpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } - dpaa2_mac_get_strings(p); + for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) + ethtool_puts(&data, dpaa2_ethtool_stats[i]); + for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) + ethtool_puts(&data, dpaa2_ethtool_extras[i]); + dpaa2_mac_get_strings(&data); break; } } diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index a69bb22c37eaba..422ce13a7c9498 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -558,15 +558,12 @@ int dpaa2_mac_get_sset_count(void) return DPAA2_MAC_NUM_STATS; } -void dpaa2_mac_get_strings(u8 *data) +void dpaa2_mac_get_strings(u8 **data) { - u8 *p = data; int i; - for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) { - strscpy(p, dpaa2_mac_ethtool_stats[i], ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } + for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) + ethtool_puts(data, dpaa2_mac_ethtool_stats[i]); } void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h index c1ec9efd413ac3..53f8d106d11e13 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h @@ -49,7 +49,7 @@ void dpaa2_mac_disconnect(struct dpaa2_mac *mac); int dpaa2_mac_get_sset_count(void); -void dpaa2_mac_get_strings(u8 *data); +void dpaa2_mac_get_strings(u8 **data); void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c index 6bc1988be31122..a888f6e6e9b00b 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch-ethtool.c @@ -170,17 +170,16 @@ dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset) static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { - u8 *p = data; + const char *str; int i; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) { - memcpy(p, dpaa2_switch_ethtool_counters[i].name, - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = dpaa2_switch_ethtool_counters[i].name; + ethtool_puts(&data, str); } - dpaa2_mac_get_strings(p); + dpaa2_mac_get_strings(&data); break; } } diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig index 4d75e6807e9293..6c2779047dcd5f 100644 --- a/drivers/net/ethernet/freescale/enetc/Kconfig +++ b/drivers/net/ethernet/freescale/enetc/Kconfig @@ -7,6 +7,14 @@ config FSL_ENETC_CORE If compiled as module (M), the module name is fsl-enetc-core. +config NXP_ENETC_PF_COMMON + tristate + help + This module supports common functionality between drivers of + different versions of NXP ENETC PF controllers. + + If compiled as module (M), the module name is nxp-enetc-pf-common. + config FSL_ENETC tristate "ENETC PF driver" depends on PCI_MSI @@ -14,6 +22,7 @@ config FSL_ENETC select FSL_ENETC_CORE select FSL_ENETC_IERB select FSL_ENETC_MDIO + select NXP_ENETC_PF_COMMON select PHYLINK select PCS_LYNX select DIMLIB @@ -24,6 +33,23 @@ config FSL_ENETC If compiled as module (M), the module name is fsl-enetc. +config NXP_ENETC4 + tristate "ENETC4 PF driver" + depends on PCI_MSI + select MDIO_DEVRES + select FSL_ENETC_CORE + select FSL_ENETC_MDIO + select NXP_ENETC_PF_COMMON + select PHYLINK + select DIMLIB + help + This driver supports NXP ENETC devices with major revision 4. ENETC is + as the NIC functionality in NETC, it supports virtualization/isolation + based on PCIe Single Root IO Virtualization (SR-IOV) and a full range + of TSN standards and NIC offload capabilities. + + If compiled as module (M), the module name is nxp-enetc4. + config FSL_ENETC_VF tristate "ENETC VF driver" depends on PCI_MSI @@ -75,3 +101,17 @@ config FSL_ENETC_QOS enable/disable from user space via Qos commands(tc). In the kernel side, it can be loaded by Qos driver. Currently, it is only support taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu). + +config NXP_NETC_BLK_CTRL + tristate "NETC blocks control driver" + help + This driver configures Integrated Endpoint Register Block (IERB) and + Privileged Register Block (PRB) of NETC. For i.MX platforms, it also + includes the configuration of NETCMIX block. + The IERB contains registers that are used for pre-boot initialization, + debug, and non-customer configuration. The PRB controls global reset + and global error handling for NETC. The NETCMIX block is mainly used + to set MII protocol and PCS protocol of the links, it also contains + settings for some other functions. + + If compiled as module (M), the module name is nxp-netc-blk-ctrl. diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile index b13cbbabb2ea36..6fd27ee4fcd1d7 100644 --- a/drivers/net/ethernet/freescale/enetc/Makefile +++ b/drivers/net/ethernet/freescale/enetc/Makefile @@ -3,11 +3,17 @@ obj-$(CONFIG_FSL_ENETC_CORE) += fsl-enetc-core.o fsl-enetc-core-y := enetc.o enetc_cbdr.o enetc_ethtool.o +obj-$(CONFIG_NXP_ENETC_PF_COMMON) += nxp-enetc-pf-common.o +nxp-enetc-pf-common-y := enetc_pf_common.o + obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o fsl-enetc-y := enetc_pf.o fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o +obj-$(CONFIG_NXP_ENETC4) += nxp-enetc4.o +nxp-enetc4-y := enetc4_pf.o + obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o fsl-enetc-vf-y := enetc_vf.o @@ -19,3 +25,6 @@ fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o obj-$(CONFIG_FSL_ENETC_PTP_CLOCK) += fsl-enetc-ptp.o fsl-enetc-ptp-y := enetc_ptp.o + +obj-$(CONFIG_NXP_NETC_BLK_CTRL) += nxp-netc-blk-ctrl.o +nxp-netc-blk-ctrl-y := netc_blk_ctrl.o diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index c09370eab319b2..535969fa0fdbef 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -3,6 +3,7 @@ #include "enetc.h" #include +#include #include #include #include @@ -21,13 +22,16 @@ void enetc_port_mac_wr(struct enetc_si *si, u32 reg, u32 val) { enetc_port_wr(&si->hw, reg, val); if (si->hw_features & ENETC_SI_F_QBU) - enetc_port_wr(&si->hw, reg + ENETC_PMAC_OFFSET, val); + enetc_port_wr(&si->hw, reg + si->drvdata->pmac_offset, val); } EXPORT_SYMBOL_GPL(enetc_port_mac_wr); static void enetc_change_preemptible_tcs(struct enetc_ndev_priv *priv, u8 preemptible_tcs) { + if (!(priv->si->hw_features & ENETC_SI_F_QBU)) + return; + priv->preemptible_tcs = preemptible_tcs; enetc_mm_commit_preemptible_tcs(priv); } @@ -700,8 +704,9 @@ static void enetc_rx_dim_work(struct work_struct *w) net_dim_get_rx_moderation(dim->mode, dim->profile_ix); struct enetc_int_vector *v = container_of(dim, struct enetc_int_vector, rx_dim); + struct enetc_ndev_priv *priv = netdev_priv(v->rx_ring.ndev); - v->rx_ictt = enetc_usecs_to_cycles(moder.usec); + v->rx_ictt = enetc_usecs_to_cycles(moder.usec, priv->sysclk_freq); dim->state = DIM_START_MEASURE; } @@ -718,7 +723,7 @@ static void enetc_rx_net_dim(struct enetc_int_vector *v) v->rx_ring.stats.packets, v->rx_ring.stats.bytes, &dim_sample); - net_dim(&v->rx_dim, dim_sample); + net_dim(&v->rx_dim, &dim_sample); } static int enetc_bd_ready_count(struct enetc_bdr *tx_ring, int ci) @@ -1736,9 +1741,15 @@ void enetc_get_si_caps(struct enetc_si *si) si->num_rx_rings = (val >> 16) & 0xff; si->num_tx_rings = val & 0xff; - val = enetc_rd(hw, ENETC_SIRFSCAPR); - si->num_fs_entries = ENETC_SIRFSCAPR_GET_NUM_RFS(val); - si->num_fs_entries = min(si->num_fs_entries, ENETC_MAX_RFS_SIZE); + val = enetc_rd(hw, ENETC_SIPCAPR0); + if (val & ENETC_SIPCAPR0_RFS) { + val = enetc_rd(hw, ENETC_SIRFSCAPR); + si->num_fs_entries = ENETC_SIRFSCAPR_GET_NUM_RFS(val); + si->num_fs_entries = min(si->num_fs_entries, ENETC_MAX_RFS_SIZE); + } else { + /* ENETC which not supports RFS */ + si->num_fs_entries = 0; + } si->num_rss = 0; val = enetc_rd(hw, ENETC_SIPCAPR0); @@ -1748,15 +1759,6 @@ void enetc_get_si_caps(struct enetc_si *si) rss = enetc_rd(hw, ENETC_SIRSSCAPR); si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss); } - - if (val & ENETC_SIPCAPR0_QBV) - si->hw_features |= ENETC_SI_F_QBV; - - if (val & ENETC_SIPCAPR0_QBU) - si->hw_features |= ENETC_SI_F_QBU; - - if (val & ENETC_SIPCAPR0_PSFP) - si->hw_features |= ENETC_SI_F_PSFP; } EXPORT_SYMBOL_GPL(enetc_get_si_caps); @@ -2066,7 +2068,10 @@ int enetc_configure_si(struct enetc_ndev_priv *priv) /* enable SI */ enetc_wr(hw, ENETC_SIMR, ENETC_SIMR_EN); - if (si->num_rss) { + /* TODO: RSS support for i.MX95 will be supported later, and the + * is_enetc_rev1() condition will be removed + */ + if (si->num_rss && is_enetc_rev1(si)) { err = enetc_setup_default_rss_table(si, priv->num_rx_rings); if (err) return err; @@ -2090,9 +2095,9 @@ void enetc_init_si_rings_params(struct enetc_ndev_priv *priv) */ priv->num_rx_rings = min_t(int, cpus, si->num_rx_rings); priv->num_tx_rings = si->num_tx_rings; - priv->bdr_int_num = cpus; + priv->bdr_int_num = priv->num_rx_rings; priv->ic_mode = ENETC_IC_RX_ADAPTIVE | ENETC_IC_TX_MANUAL; - priv->tx_ictt = ENETC_TXIC_TIMETHR; + priv->tx_ictt = enetc_usecs_to_cycles(600, priv->sysclk_freq); } EXPORT_SYMBOL_GPL(enetc_init_si_rings_params); @@ -2501,10 +2506,14 @@ int enetc_open(struct net_device *ndev) extended = !!(priv->active_offloads & ENETC_F_RX_TSTAMP); - err = enetc_setup_irqs(priv); + err = clk_prepare_enable(priv->ref_clk); if (err) return err; + err = enetc_setup_irqs(priv); + if (err) + goto err_setup_irqs; + err = enetc_phylink_connect(ndev); if (err) goto err_phy_connect; @@ -2536,6 +2545,8 @@ int enetc_open(struct net_device *ndev) phylink_disconnect_phy(priv->phylink); err_phy_connect: enetc_free_irqs(priv); +err_setup_irqs: + clk_disable_unprepare(priv->ref_clk); return err; } @@ -2589,6 +2600,7 @@ int enetc_close(struct net_device *ndev) enetc_assign_tx_resources(priv, NULL); enetc_free_irqs(priv); + clk_disable_unprepare(priv->ref_clk); return 0; } @@ -2995,13 +3007,99 @@ int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) } EXPORT_SYMBOL_GPL(enetc_ioctl); +static int enetc_int_vector_init(struct enetc_ndev_priv *priv, int i, + int v_tx_rings) +{ + struct enetc_int_vector *v; + struct enetc_bdr *bdr; + int j, err; + + v = kzalloc(struct_size(v, tx_ring, v_tx_rings), GFP_KERNEL); + if (!v) + return -ENOMEM; + + priv->int_vector[i] = v; + bdr = &v->rx_ring; + bdr->index = i; + bdr->ndev = priv->ndev; + bdr->dev = priv->dev; + bdr->bd_count = priv->rx_bd_count; + bdr->buffer_offset = ENETC_RXB_PAD; + priv->rx_ring[i] = bdr; + + err = xdp_rxq_info_reg(&bdr->xdp.rxq, priv->ndev, i, 0); + if (err) + goto free_vector; + + err = xdp_rxq_info_reg_mem_model(&bdr->xdp.rxq, MEM_TYPE_PAGE_SHARED, + NULL); + if (err) { + xdp_rxq_info_unreg(&bdr->xdp.rxq); + goto free_vector; + } + + /* init defaults for adaptive IC */ + if (priv->ic_mode & ENETC_IC_RX_ADAPTIVE) { + v->rx_ictt = 0x1; + v->rx_dim_en = true; + } + + INIT_WORK(&v->rx_dim.work, enetc_rx_dim_work); + netif_napi_add(priv->ndev, &v->napi, enetc_poll); + v->count_tx_rings = v_tx_rings; + + for (j = 0; j < v_tx_rings; j++) { + int idx; + + /* default tx ring mapping policy */ + idx = priv->bdr_int_num * j + i; + __set_bit(idx, &v->tx_rings_map); + bdr = &v->tx_ring[j]; + bdr->index = idx; + bdr->ndev = priv->ndev; + bdr->dev = priv->dev; + bdr->bd_count = priv->tx_bd_count; + priv->tx_ring[idx] = bdr; + } + + return 0; + +free_vector: + priv->rx_ring[i] = NULL; + priv->int_vector[i] = NULL; + kfree(v); + + return err; +} + +static void enetc_int_vector_destroy(struct enetc_ndev_priv *priv, int i) +{ + struct enetc_int_vector *v = priv->int_vector[i]; + struct enetc_bdr *rx_ring = &v->rx_ring; + int j, tx_ring_index; + + xdp_rxq_info_unreg_mem_model(&rx_ring->xdp.rxq); + xdp_rxq_info_unreg(&rx_ring->xdp.rxq); + netif_napi_del(&v->napi); + cancel_work_sync(&v->rx_dim.work); + + for (j = 0; j < v->count_tx_rings; j++) { + tx_ring_index = priv->bdr_int_num * j + i; + priv->tx_ring[tx_ring_index] = NULL; + } + + priv->rx_ring[i] = NULL; + priv->int_vector[i] = NULL; + kfree(v); +} + int enetc_alloc_msix(struct enetc_ndev_priv *priv) { struct pci_dev *pdev = priv->si->pdev; + int v_tx_rings, v_remainder; int num_stack_tx_queues; int first_xdp_tx_ring; int i, n, err, nvec; - int v_tx_rings; nvec = ENETC_BDR_INT_BASE_IDX + priv->bdr_int_num; /* allocate MSIX for both messaging and Rx/Tx interrupts */ @@ -3015,64 +3113,17 @@ int enetc_alloc_msix(struct enetc_ndev_priv *priv) /* # of tx rings per int vector */ v_tx_rings = priv->num_tx_rings / priv->bdr_int_num; + v_remainder = priv->num_tx_rings % priv->bdr_int_num; for (i = 0; i < priv->bdr_int_num; i++) { - struct enetc_int_vector *v; - struct enetc_bdr *bdr; - int j; - - v = kzalloc(struct_size(v, tx_ring, v_tx_rings), GFP_KERNEL); - if (!v) { - err = -ENOMEM; - goto fail; - } - - priv->int_vector[i] = v; - - bdr = &v->rx_ring; - bdr->index = i; - bdr->ndev = priv->ndev; - bdr->dev = priv->dev; - bdr->bd_count = priv->rx_bd_count; - bdr->buffer_offset = ENETC_RXB_PAD; - priv->rx_ring[i] = bdr; - - err = xdp_rxq_info_reg(&bdr->xdp.rxq, priv->ndev, i, 0); - if (err) { - kfree(v); - goto fail; - } + /* Distribute the remaining TX rings to the first v_remainder + * interrupt vectors + */ + int num_tx_rings = i < v_remainder ? v_tx_rings + 1 : v_tx_rings; - err = xdp_rxq_info_reg_mem_model(&bdr->xdp.rxq, - MEM_TYPE_PAGE_SHARED, NULL); - if (err) { - xdp_rxq_info_unreg(&bdr->xdp.rxq); - kfree(v); + err = enetc_int_vector_init(priv, i, num_tx_rings); + if (err) goto fail; - } - - /* init defaults for adaptive IC */ - if (priv->ic_mode & ENETC_IC_RX_ADAPTIVE) { - v->rx_ictt = 0x1; - v->rx_dim_en = true; - } - INIT_WORK(&v->rx_dim.work, enetc_rx_dim_work); - netif_napi_add(priv->ndev, &v->napi, enetc_poll); - v->count_tx_rings = v_tx_rings; - - for (j = 0; j < v_tx_rings; j++) { - int idx; - - /* default tx ring mapping policy */ - idx = priv->bdr_int_num * j + i; - __set_bit(idx, &v->tx_rings_map); - bdr = &v->tx_ring[j]; - bdr->index = idx; - bdr->ndev = priv->ndev; - bdr->dev = priv->dev; - bdr->bd_count = priv->tx_bd_count; - priv->tx_ring[idx] = bdr; - } } num_stack_tx_queues = enetc_num_stack_tx_queues(priv); @@ -3092,16 +3143,8 @@ int enetc_alloc_msix(struct enetc_ndev_priv *priv) return 0; fail: - while (i--) { - struct enetc_int_vector *v = priv->int_vector[i]; - struct enetc_bdr *rx_ring = &v->rx_ring; - - xdp_rxq_info_unreg_mem_model(&rx_ring->xdp.rxq); - xdp_rxq_info_unreg(&rx_ring->xdp.rxq); - netif_napi_del(&v->napi); - cancel_work_sync(&v->rx_dim.work); - kfree(v); - } + while (i--) + enetc_int_vector_destroy(priv, i); pci_free_irq_vectors(pdev); @@ -3113,26 +3156,8 @@ void enetc_free_msix(struct enetc_ndev_priv *priv) { int i; - for (i = 0; i < priv->bdr_int_num; i++) { - struct enetc_int_vector *v = priv->int_vector[i]; - struct enetc_bdr *rx_ring = &v->rx_ring; - - xdp_rxq_info_unreg_mem_model(&rx_ring->xdp.rxq); - xdp_rxq_info_unreg(&rx_ring->xdp.rxq); - netif_napi_del(&v->napi); - cancel_work_sync(&v->rx_dim.work); - } - - for (i = 0; i < priv->num_rx_rings; i++) - priv->rx_ring[i] = NULL; - - for (i = 0; i < priv->num_tx_rings; i++) - priv->tx_ring[i] = NULL; - - for (i = 0; i < priv->bdr_int_num; i++) { - kfree(priv->int_vector[i]); - priv->int_vector[i] = NULL; - } + for (i = 0; i < priv->bdr_int_num; i++) + enetc_int_vector_destroy(priv, i); /* disable all MSIX for this device */ pci_free_irq_vectors(priv->si->pdev); @@ -3241,5 +3266,55 @@ void enetc_pci_remove(struct pci_dev *pdev) } EXPORT_SYMBOL_GPL(enetc_pci_remove); +static const struct enetc_drvdata enetc_pf_data = { + .sysclk_freq = ENETC_CLK_400M, + .pmac_offset = ENETC_PMAC_OFFSET, + .eth_ops = &enetc_pf_ethtool_ops, +}; + +static const struct enetc_drvdata enetc4_pf_data = { + .sysclk_freq = ENETC_CLK_333M, + .pmac_offset = ENETC4_PMAC_OFFSET, + .eth_ops = &enetc4_pf_ethtool_ops, +}; + +static const struct enetc_drvdata enetc_vf_data = { + .sysclk_freq = ENETC_CLK_400M, + .eth_ops = &enetc_vf_ethtool_ops, +}; + +static const struct enetc_platform_info enetc_info[] = { + { .revision = ENETC_REV_1_0, + .dev_id = ENETC_DEV_ID_PF, + .data = &enetc_pf_data, + }, + { .revision = ENETC_REV_4_1, + .dev_id = NXP_ENETC_PF_DEV_ID, + .data = &enetc4_pf_data, + }, + { .revision = ENETC_REV_1_0, + .dev_id = ENETC_DEV_ID_VF, + .data = &enetc_vf_data, + }, +}; + +int enetc_get_driver_data(struct enetc_si *si) +{ + u16 dev_id = si->pdev->device; + int i; + + for (i = 0; i < ARRAY_SIZE(enetc_info); i++) { + if (si->revision == enetc_info[i].revision && + dev_id == enetc_info[i].dev_id) { + si->drvdata = enetc_info[i].data; + + return 0; + } + } + + return -ERANGE; +} +EXPORT_SYMBOL_GPL(enetc_get_driver_data); + MODULE_DESCRIPTION("NXP ENETC Ethernet driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index fb7d98d5778399..72fa03dbc2ddbb 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -14,6 +14,7 @@ #include #include "enetc_hw.h" +#include "enetc4_hw.h" #define ENETC_MAC_MAXFRM_SIZE 9600 #define ENETC_MAX_MTU (ENETC_MAC_MAXFRM_SIZE - \ @@ -231,6 +232,18 @@ enum enetc_errata { #define ENETC_SI_F_QBV BIT(1) #define ENETC_SI_F_QBU BIT(2) +struct enetc_drvdata { + u32 pmac_offset; /* Only valid for PSI which supports 802.1Qbu */ + u64 sysclk_freq; + const struct ethtool_ops *eth_ops; +}; + +struct enetc_platform_info { + u16 revision; + u16 dev_id; + const struct enetc_drvdata *data; +}; + /* PCI IEP device data */ struct enetc_si { struct pci_dev *pdev; @@ -246,11 +259,18 @@ struct enetc_si { int num_fs_entries; int num_rss; /* number of RSS buckets */ unsigned short pad; + u16 revision; int hw_features; + const struct enetc_drvdata *drvdata; }; #define ENETC_SI_ALIGN 32 +static inline bool is_enetc_rev1(struct enetc_si *si) +{ + return si->pdev->revision == ENETC_REV1; +} + static inline void *enetc_si_priv(const struct enetc_si *si) { return (char *)si + ALIGN(sizeof(struct enetc_si), ENETC_SI_ALIGN); @@ -302,7 +322,7 @@ struct enetc_cls_rule { int used; }; -#define ENETC_MAX_BDR_INT 2 /* fixed to max # of available cpus */ +#define ENETC_MAX_BDR_INT 6 /* fixed to max # of available cpus */ struct psfp_cap { u32 max_streamid; u32 max_psfp_filter; @@ -341,7 +361,6 @@ enum enetc_ic_mode { #define ENETC_RXIC_PKTTHR min_t(u32, 256, ENETC_RX_RING_DEFAULT_SIZE / 2) #define ENETC_TXIC_PKTTHR min_t(u32, 128, ENETC_TX_RING_DEFAULT_SIZE / 2) -#define ENETC_TXIC_TIMETHR enetc_usecs_to_cycles(600) struct enetc_ndev_priv { struct net_device *ndev; @@ -389,6 +408,9 @@ struct enetc_ndev_priv { * and link state updates */ struct mutex mm_lock; + + struct clk *ref_clk; /* RGMII/RMII reference clock */ + u64 sysclk_freq; /* NETC system clock frequency */ }; /* Messaging */ @@ -418,6 +440,7 @@ void enetc_init_si_rings_params(struct enetc_ndev_priv *priv); int enetc_alloc_si_resources(struct enetc_ndev_priv *priv); void enetc_free_si_resources(struct enetc_ndev_priv *priv); int enetc_configure_si(struct enetc_ndev_priv *priv); +int enetc_get_driver_data(struct enetc_si *si); int enetc_open(struct net_device *ndev); int enetc_close(struct net_device *ndev); @@ -434,6 +457,9 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, struct xdp_frame **frames, u32 flags); /* ethtool */ +extern const struct ethtool_ops enetc_pf_ethtool_ops; +extern const struct ethtool_ops enetc4_pf_ethtool_ops; +extern const struct ethtool_ops enetc_vf_ethtool_ops; void enetc_set_ethtool_ops(struct net_device *ndev); void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link); void enetc_mm_commit_preemptible_tcs(struct enetc_ndev_priv *priv); diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h new file mode 100644 index 00000000000000..26b22067744819 --- /dev/null +++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * This header file defines the register offsets and bit fields + * of ENETC4 PF and VFs. Note that the same registers as ENETC + * version 1.0 are defined in the enetc_hw.h file. + * + * Copyright 2024 NXP + */ +#ifndef __ENETC4_HW_H_ +#define __ENETC4_HW_H_ + +#define NXP_ENETC_VENDOR_ID 0x1131 +#define NXP_ENETC_PF_DEV_ID 0xe101 + +/***************************ENETC port registers**************************/ +#define ENETC4_ECAPR0 0x0 +#define ECAPR0_RFS BIT(2) +#define ECAPR0_TSD BIT(5) +#define ECAPR0_RSS BIT(8) +#define ECAPR0_RSC BIT(9) +#define ECAPR0_LSO BIT(10) +#define ECAPR0_WO BIT(13) + +#define ENETC4_ECAPR1 0x4 +#define ECAPR1_NUM_TCS GENMASK(6, 4) +#define ECAPR1_NUM_MCH GENMASK(9, 8) +#define ECAPR1_NUM_UCH GENMASK(11, 10) +#define ECAPR1_NUM_MSIX GENMASK(22, 12) +#define ECAPR1_NUM_VSI GENMASK(27, 24) +#define ECAPR1_NUM_IPV BIT(31) + +#define ENETC4_ECAPR2 0x8 +#define ECAPR2_NUM_TX_BDR GENMASK(9, 0) +#define ECAPR2_NUM_RX_BDR GENMASK(25, 16) + +#define ENETC4_PMR 0x10 +#define PMR_SI_EN(a) BIT((16 + (a))) + +/* Port Pause ON/OFF threshold register */ +#define ENETC4_PPAUONTR 0x108 +#define ENETC4_PPAUOFFTR 0x10c + +/* Port Station interface promiscuous MAC mode register */ +#define ENETC4_PSIPMMR 0x200 +#define PSIPMMR_SI_MAC_UP(a) BIT(a) /* a = SI index */ +#define PSIPMMR_SI_MAC_MP(a) BIT((a) + 16) + +/* Port Station interface promiscuous VLAN mode register */ +#define ENETC4_PSIPVMR 0x204 + +/* Port RSS key register n. n = 0,1,2,...,9 */ +#define ENETC4_PRSSKR(n) ((n) * 0x4 + 0x250) + +/* Port station interface MAC address filtering capability register */ +#define ENETC4_PSIMAFCAPR 0x280 +#define PSIMAFCAPR_NUM_MAC_AFTE GENMASK(11, 0) + +/* Port station interface VLAN filtering capability register */ +#define ENETC4_PSIVLANFCAPR 0x2c0 +#define PSIVLANFCAPR_NUM_VLAN_FTE GENMASK(11, 0) + +/* Port station interface VLAN filtering mode register */ +#define ENETC4_PSIVLANFMR 0x2c4 +#define PSIVLANFMR_VS BIT(0) + +/* Port Station interface a primary MAC address registers */ +#define ENETC4_PSIPMAR0(a) ((a) * 0x80 + 0x2000) +#define ENETC4_PSIPMAR1(a) ((a) * 0x80 + 0x2004) + +/* Port station interface a configuration register 0/2 */ +#define ENETC4_PSICFGR0(a) ((a) * 0x80 + 0x2010) +#define PSICFGR0_VASE BIT(13) +#define PSICFGR0_ASE BIT(15) +#define PSICFGR0_ANTI_SPOOFING (PSICFGR0_VASE | PSICFGR0_ASE) + +#define ENETC4_PSICFGR2(a) ((a) * 0x80 + 0x2018) +#define PSICFGR2_NUM_MSIX GENMASK(5, 0) + +#define ENETC4_PMCAPR 0x4004 +#define PMCAPR_HD BIT(8) +#define PMCAPR_FP GENMASK(10, 9) + +/* Port configuration register */ +#define ENETC4_PCR 0x4010 +#define PCR_HDR_FMT BIT(0) +#define PCR_L2DOSE BIT(4) +#define PCR_TIMER_CS BIT(8) +#define PCR_PSPEED GENMASK(29, 16) +#define PCR_PSPEED_VAL(speed) (((speed) / 10 - 1) << 16) + +/* Port MAC address register 0/1 */ +#define ENETC4_PMAR0 0x4020 +#define ENETC4_PMAR1 0x4024 + +/* Port operational register */ +#define ENETC4_POR 0x4100 + +/* Port traffic class a transmit maximum SDU register */ +#define ENETC4_PTCTMSDUR(a) ((a) * 0x20 + 0x4208) +#define PTCTMSDUR_MAXSDU GENMASK(15, 0) +#define PTCTMSDUR_SDU_TYPE GENMASK(17, 16) +#define SDU_TYPE_PPDU 0 +#define SDU_TYPE_MPDU 1 +#define SDU_TYPE_MSDU 2 + +#define ENETC4_PMAC_OFFSET 0x400 +#define ENETC4_PM_CMD_CFG(mac) (0x5008 + (mac) * 0x400) +#define PM_CMD_CFG_TX_EN BIT(0) +#define PM_CMD_CFG_RX_EN BIT(1) +#define PM_CMD_CFG_PAUSE_FWD BIT(7) +#define PM_CMD_CFG_PAUSE_IGN BIT(8) +#define PM_CMD_CFG_TX_ADDR_INS BIT(9) +#define PM_CMD_CFG_LOOP_EN BIT(10) +#define PM_CMD_CFG_LPBK_MODE GENMASK(12, 11) +#define LPBCK_MODE_EXT_TX_CLK 0 +#define LPBCK_MODE_MAC_LEVEL 1 +#define LPBCK_MODE_INT_TX_CLK 2 +#define PM_CMD_CFG_CNT_FRM_EN BIT(13) +#define PM_CMD_CFG_TXP BIT(15) +#define PM_CMD_CFG_SEND_IDLE BIT(16) +#define PM_CMD_CFG_HD_FCEN BIT(18) +#define PM_CMD_CFG_SFD BIT(21) +#define PM_CMD_CFG_TX_FLUSH BIT(22) +#define PM_CMD_CFG_TX_LOWP_EN BIT(23) +#define PM_CMD_CFG_RX_LOWP_EMPTY BIT(24) +#define PM_CMD_CFG_SWR BIT(26) +#define PM_CMD_CFG_TS_MODE BIT(30) +#define PM_CMD_CFG_MG BIT(31) + +/* Port MAC 0/1 Maximum Frame Length Register */ +#define ENETC4_PM_MAXFRM(mac) (0x5014 + (mac) * 0x400) + +/* Port MAC 0/1 Pause Quanta Register */ +#define ENETC4_PM_PAUSE_QUANTA(mac) (0x5054 + (mac) * 0x400) + +/* Port MAC 0/1 Pause Quanta Threshold Register */ +#define ENETC4_PM_PAUSE_THRESH(mac) (0x5064 + (mac) * 0x400) + +/* Port MAC 0 Interface Mode Control Register */ +#define ENETC4_PM_IF_MODE(mac) (0x5300 + (mac) * 0x400) +#define PM_IF_MODE_IFMODE GENMASK(2, 0) +#define IFMODE_XGMII 0 +#define IFMODE_RMII 3 +#define IFMODE_RGMII 4 +#define IFMODE_SGMII 5 +#define PM_IF_MODE_REVMII BIT(3) +#define PM_IF_MODE_M10 BIT(4) +#define PM_IF_MODE_HD BIT(6) +#define PM_IF_MODE_SSP GENMASK(14, 13) +#define SSP_100M 0 +#define SSP_10M 1 +#define SSP_1G 2 +#define PM_IF_MODE_ENA BIT(15) + +#endif diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c new file mode 100644 index 00000000000000..fc41078c4f5da6 --- /dev/null +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c @@ -0,0 +1,756 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* Copyright 2024 NXP */ + +#include +#include +#include +#include +#include + +#include "enetc_pf_common.h" + +#define ENETC_SI_MAX_RING_NUM 8 + +static void enetc4_get_port_caps(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + u32 val; + + val = enetc_port_rd(hw, ENETC4_ECAPR1); + pf->caps.num_vsi = (val & ECAPR1_NUM_VSI) >> 24; + pf->caps.num_msix = ((val & ECAPR1_NUM_MSIX) >> 12) + 1; + + val = enetc_port_rd(hw, ENETC4_ECAPR2); + pf->caps.num_rx_bdr = (val & ECAPR2_NUM_RX_BDR) >> 16; + pf->caps.num_tx_bdr = val & ECAPR2_NUM_TX_BDR; + + val = enetc_port_rd(hw, ENETC4_PMCAPR); + pf->caps.half_duplex = (val & PMCAPR_HD) ? 1 : 0; +} + +static void enetc4_pf_set_si_primary_mac(struct enetc_hw *hw, int si, + const u8 *addr) +{ + u16 lower = get_unaligned_le16(addr + 4); + u32 upper = get_unaligned_le32(addr); + + if (si != 0) { + __raw_writel(upper, hw->port + ENETC4_PSIPMAR0(si)); + __raw_writew(lower, hw->port + ENETC4_PSIPMAR1(si)); + } else { + __raw_writel(upper, hw->port + ENETC4_PMAR0); + __raw_writew(lower, hw->port + ENETC4_PMAR1); + } +} + +static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si, + u8 *addr) +{ + u32 upper; + u16 lower; + + upper = __raw_readl(hw->port + ENETC4_PSIPMAR0(si)); + lower = __raw_readw(hw->port + ENETC4_PSIPMAR1(si)); + + put_unaligned_le32(upper, addr); + put_unaligned_le16(lower, addr + 4); +} + +static const struct enetc_pf_ops enetc4_pf_ops = { + .set_si_primary_mac = enetc4_pf_set_si_primary_mac, + .get_si_primary_mac = enetc4_pf_get_si_primary_mac, +}; + +static int enetc4_pf_struct_init(struct enetc_si *si) +{ + struct enetc_pf *pf = enetc_si_priv(si); + + pf->si = si; + pf->total_vfs = pci_sriov_get_totalvfs(si->pdev); + pf->ops = &enetc4_pf_ops; + + enetc4_get_port_caps(pf); + + return 0; +} + +static u32 enetc4_psicfgr0_val_construct(bool is_vf, u32 num_tx_bdr, u32 num_rx_bdr) +{ + u32 val; + + val = ENETC_PSICFGR0_SET_TXBDR(num_tx_bdr); + val |= ENETC_PSICFGR0_SET_RXBDR(num_rx_bdr); + val |= ENETC_PSICFGR0_SIVC(ENETC_VLAN_TYPE_C | ENETC_VLAN_TYPE_S); + + if (is_vf) + val |= ENETC_PSICFGR0_VTE | ENETC_PSICFGR0_SIVIE; + + return val; +} + +static void enetc4_default_rings_allocation(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + u32 num_rx_bdr, num_tx_bdr, val; + u32 vf_tx_bdr, vf_rx_bdr; + int i, rx_rem, tx_rem; + + if (pf->caps.num_rx_bdr < ENETC_SI_MAX_RING_NUM + pf->caps.num_vsi) + num_rx_bdr = pf->caps.num_rx_bdr - pf->caps.num_vsi; + else + num_rx_bdr = ENETC_SI_MAX_RING_NUM; + + if (pf->caps.num_tx_bdr < ENETC_SI_MAX_RING_NUM + pf->caps.num_vsi) + num_tx_bdr = pf->caps.num_tx_bdr - pf->caps.num_vsi; + else + num_tx_bdr = ENETC_SI_MAX_RING_NUM; + + val = enetc4_psicfgr0_val_construct(false, num_tx_bdr, num_rx_bdr); + enetc_port_wr(hw, ENETC4_PSICFGR0(0), val); + + num_rx_bdr = pf->caps.num_rx_bdr - num_rx_bdr; + rx_rem = num_rx_bdr % pf->caps.num_vsi; + num_rx_bdr = num_rx_bdr / pf->caps.num_vsi; + + num_tx_bdr = pf->caps.num_tx_bdr - num_tx_bdr; + tx_rem = num_tx_bdr % pf->caps.num_vsi; + num_tx_bdr = num_tx_bdr / pf->caps.num_vsi; + + for (i = 0; i < pf->caps.num_vsi; i++) { + vf_tx_bdr = (i < tx_rem) ? num_tx_bdr + 1 : num_tx_bdr; + vf_rx_bdr = (i < rx_rem) ? num_rx_bdr + 1 : num_rx_bdr; + val = enetc4_psicfgr0_val_construct(true, vf_tx_bdr, vf_rx_bdr); + enetc_port_wr(hw, ENETC4_PSICFGR0(i + 1), val); + } +} + +static void enetc4_allocate_si_rings(struct enetc_pf *pf) +{ + enetc4_default_rings_allocation(pf); +} + +static void enetc4_pf_set_si_vlan_promisc(struct enetc_hw *hw, int si, bool en) +{ + u32 val = enetc_port_rd(hw, ENETC4_PSIPVMR); + + if (en) + val |= BIT(si); + else + val &= ~BIT(si); + + enetc_port_wr(hw, ENETC4_PSIPVMR, val); +} + +static void enetc4_set_default_si_vlan_promisc(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + int num_si = pf->caps.num_vsi + 1; + int i; + + /* enforce VLAN promiscuous mode for all SIs */ + for (i = 0; i < num_si; i++) + enetc4_pf_set_si_vlan_promisc(hw, i, true); +} + +/* Allocate the number of MSI-X vectors for per SI. */ +static void enetc4_set_si_msix_num(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + int i, num_msix, total_si; + u32 val; + + total_si = pf->caps.num_vsi + 1; + + num_msix = pf->caps.num_msix / total_si + + pf->caps.num_msix % total_si - 1; + val = num_msix & PSICFGR2_NUM_MSIX; + enetc_port_wr(hw, ENETC4_PSICFGR2(0), val); + + num_msix = pf->caps.num_msix / total_si - 1; + val = num_msix & PSICFGR2_NUM_MSIX; + for (i = 0; i < pf->caps.num_vsi; i++) + enetc_port_wr(hw, ENETC4_PSICFGR2(i + 1), val); +} + +static void enetc4_enable_all_si(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + int num_si = pf->caps.num_vsi + 1; + u32 si_bitmap = 0; + int i; + + /* Master enable for all SIs */ + for (i = 0; i < num_si; i++) + si_bitmap |= PMR_SI_EN(i); + + enetc_port_wr(hw, ENETC4_PMR, si_bitmap); +} + +static void enetc4_configure_port_si(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + + enetc4_allocate_si_rings(pf); + + /* Outer VLAN tag will be used for VLAN filtering */ + enetc_port_wr(hw, ENETC4_PSIVLANFMR, PSIVLANFMR_VS); + + enetc4_set_default_si_vlan_promisc(pf); + + /* Disable SI MAC multicast & unicast promiscuous */ + enetc_port_wr(hw, ENETC4_PSIPMMR, 0); + + enetc4_set_si_msix_num(pf); + + enetc4_enable_all_si(pf); +} + +static void enetc4_pf_reset_tc_msdu(struct enetc_hw *hw) +{ + u32 val = ENETC_MAC_MAXFRM_SIZE; + int tc; + + val = u32_replace_bits(val, SDU_TYPE_MPDU, PTCTMSDUR_SDU_TYPE); + + for (tc = 0; tc < ENETC_NUM_TC; tc++) + enetc_port_wr(hw, ENETC4_PTCTMSDUR(tc), val); +} + +static void enetc4_set_trx_frame_size(struct enetc_pf *pf) +{ + struct enetc_si *si = pf->si; + + enetc_port_mac_wr(si, ENETC4_PM_MAXFRM(0), + ENETC_SET_MAXFRM(ENETC_MAC_MAXFRM_SIZE)); + + enetc4_pf_reset_tc_msdu(&si->hw); +} + +static void enetc4_set_rss_key(struct enetc_hw *hw, const u8 *bytes) +{ + int i; + + for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++) + enetc_port_wr(hw, ENETC4_PRSSKR(i), ((u32 *)bytes)[i]); +} + +static void enetc4_set_default_rss_key(struct enetc_pf *pf) +{ + u8 hash_key[ENETC_RSSHASH_KEY_SIZE] = {0}; + struct enetc_hw *hw = &pf->si->hw; + + /* set up hash key */ + get_random_bytes(hash_key, ENETC_RSSHASH_KEY_SIZE); + enetc4_set_rss_key(hw, hash_key); +} + +static void enetc4_enable_trx(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + + /* Enable port transmit/receive */ + enetc_port_wr(hw, ENETC4_POR, 0); +} + +static void enetc4_configure_port(struct enetc_pf *pf) +{ + enetc4_configure_port_si(pf); + enetc4_set_trx_frame_size(pf); + enetc4_set_default_rss_key(pf); + enetc4_enable_trx(pf); +} + +static int enetc4_pf_init(struct enetc_pf *pf) +{ + struct device *dev = &pf->si->pdev->dev; + int err; + + /* Initialize the MAC address for PF and VFs */ + err = enetc_setup_mac_addresses(dev->of_node, pf); + if (err) { + dev_err(dev, "Failed to set MAC addresses\n"); + return err; + } + + enetc4_configure_port(pf); + + return 0; +} + +static const struct net_device_ops enetc4_ndev_ops = { + .ndo_open = enetc_open, + .ndo_stop = enetc_close, + .ndo_start_xmit = enetc_xmit, + .ndo_get_stats = enetc_get_stats, + .ndo_set_mac_address = enetc_pf_set_mac_addr, +}; + +static struct phylink_pcs * +enetc4_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t iface) +{ + struct enetc_pf *pf = phylink_to_enetc_pf(config); + + return pf->pcs; +} + +static void enetc4_mac_config(struct enetc_pf *pf, unsigned int mode, + phy_interface_t phy_mode) +{ + struct enetc_ndev_priv *priv = netdev_priv(pf->si->ndev); + struct enetc_si *si = pf->si; + u32 val; + + val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0)); + val &= ~(PM_IF_MODE_IFMODE | PM_IF_MODE_ENA); + + switch (phy_mode) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + val |= IFMODE_RGMII; + /* We need to enable auto-negotiation for the MAC + * if its RGMII interface support In-Band status. + */ + if (phylink_autoneg_inband(mode)) + val |= PM_IF_MODE_ENA; + break; + case PHY_INTERFACE_MODE_RMII: + val |= IFMODE_RMII; + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: + val |= IFMODE_SGMII; + break; + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_XGMII: + case PHY_INTERFACE_MODE_USXGMII: + val |= IFMODE_XGMII; + break; + default: + dev_err(priv->dev, + "Unsupported PHY mode:%d\n", phy_mode); + return; + } + + enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val); +} + +static void enetc4_pl_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ + struct enetc_pf *pf = phylink_to_enetc_pf(config); + + enetc4_mac_config(pf, mode, state->interface); +} + +static void enetc4_set_port_speed(struct enetc_ndev_priv *priv, int speed) +{ + u32 old_speed = priv->speed; + u32 val; + + if (speed == old_speed) + return; + + val = enetc_port_rd(&priv->si->hw, ENETC4_PCR); + val &= ~PCR_PSPEED; + + switch (speed) { + case SPEED_100: + case SPEED_1000: + case SPEED_2500: + case SPEED_10000: + val |= (PCR_PSPEED & PCR_PSPEED_VAL(speed)); + break; + case SPEED_10: + default: + val |= (PCR_PSPEED & PCR_PSPEED_VAL(SPEED_10)); + } + + priv->speed = speed; + enetc_port_wr(&priv->si->hw, ENETC4_PCR, val); +} + +static void enetc4_set_rgmii_mac(struct enetc_pf *pf, int speed, int duplex) +{ + struct enetc_si *si = pf->si; + u32 old_val, val; + + old_val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0)); + val = old_val & ~(PM_IF_MODE_ENA | PM_IF_MODE_M10 | PM_IF_MODE_REVMII); + + switch (speed) { + case SPEED_1000: + val = u32_replace_bits(val, SSP_1G, PM_IF_MODE_SSP); + break; + case SPEED_100: + val = u32_replace_bits(val, SSP_100M, PM_IF_MODE_SSP); + break; + case SPEED_10: + val = u32_replace_bits(val, SSP_10M, PM_IF_MODE_SSP); + } + + val = u32_replace_bits(val, duplex == DUPLEX_FULL ? 0 : 1, + PM_IF_MODE_HD); + + if (val == old_val) + return; + + enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val); +} + +static void enetc4_set_rmii_mac(struct enetc_pf *pf, int speed, int duplex) +{ + struct enetc_si *si = pf->si; + u32 old_val, val; + + old_val = enetc_port_mac_rd(si, ENETC4_PM_IF_MODE(0)); + val = old_val & ~(PM_IF_MODE_ENA | PM_IF_MODE_SSP); + + switch (speed) { + case SPEED_100: + val &= ~PM_IF_MODE_M10; + break; + case SPEED_10: + val |= PM_IF_MODE_M10; + } + + val = u32_replace_bits(val, duplex == DUPLEX_FULL ? 0 : 1, + PM_IF_MODE_HD); + + if (val == old_val) + return; + + enetc_port_mac_wr(si, ENETC4_PM_IF_MODE(0), val); +} + +static void enetc4_set_hd_flow_control(struct enetc_pf *pf, bool enable) +{ + struct enetc_si *si = pf->si; + u32 old_val, val; + + if (!pf->caps.half_duplex) + return; + + old_val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); + val = u32_replace_bits(old_val, enable ? 1 : 0, PM_CMD_CFG_HD_FCEN); + if (val == old_val) + return; + + enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); +} + +static void enetc4_set_rx_pause(struct enetc_pf *pf, bool rx_pause) +{ + struct enetc_si *si = pf->si; + u32 old_val, val; + + old_val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); + val = u32_replace_bits(old_val, rx_pause ? 0 : 1, PM_CMD_CFG_PAUSE_IGN); + if (val == old_val) + return; + + enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); +} + +static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_pause) +{ + u32 pause_off_thresh = 0, pause_on_thresh = 0; + u32 init_quanta = 0, refresh_quanta = 0; + struct enetc_hw *hw = &pf->si->hw; + u32 rbmr, old_rbmr; + int i; + + for (i = 0; i < num_rxbdr; i++) { + old_rbmr = enetc_rxbdr_rd(hw, i, ENETC_RBMR); + rbmr = u32_replace_bits(old_rbmr, tx_pause ? 1 : 0, ENETC_RBMR_CM); + if (rbmr == old_rbmr) + continue; + + enetc_rxbdr_wr(hw, i, ENETC_RBMR, rbmr); + } + + if (tx_pause) { + /* When the port first enters congestion, send a PAUSE request + * with the maximum number of quanta. When the port exits + * congestion, it will automatically send a PAUSE frame with + * zero quanta. + */ + init_quanta = 0xffff; + + /* Also, set up the refresh timer to send follow-up PAUSE + * frames at half the quanta value, in case the congestion + * condition persists. + */ + refresh_quanta = 0xffff / 2; + + /* Start emitting PAUSE frames when 3 large frames (or more + * smaller frames) have accumulated in the FIFO waiting to be + * DMAed to the RX ring. + */ + pause_on_thresh = 3 * ENETC_MAC_MAXFRM_SIZE; + pause_off_thresh = 1 * ENETC_MAC_MAXFRM_SIZE; + } + + enetc_port_mac_wr(pf->si, ENETC4_PM_PAUSE_QUANTA(0), init_quanta); + enetc_port_mac_wr(pf->si, ENETC4_PM_PAUSE_THRESH(0), refresh_quanta); + enetc_port_wr(hw, ENETC4_PPAUONTR, pause_on_thresh); + enetc_port_wr(hw, ENETC4_PPAUOFFTR, pause_off_thresh); +} + +static void enetc4_enable_mac(struct enetc_pf *pf, bool en) +{ + struct enetc_si *si = pf->si; + u32 val; + + val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); + val &= ~(PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN); + val |= en ? (PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN) : 0; + + enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); +} + +static void enetc4_pl_mac_link_up(struct phylink_config *config, + struct phy_device *phy, unsigned int mode, + phy_interface_t interface, int speed, + int duplex, bool tx_pause, bool rx_pause) +{ + struct enetc_pf *pf = phylink_to_enetc_pf(config); + struct enetc_si *si = pf->si; + struct enetc_ndev_priv *priv; + bool hd_fc = false; + + priv = netdev_priv(si->ndev); + enetc4_set_port_speed(priv, speed); + + if (!phylink_autoneg_inband(mode) && + phy_interface_mode_is_rgmii(interface)) + enetc4_set_rgmii_mac(pf, speed, duplex); + + if (interface == PHY_INTERFACE_MODE_RMII) + enetc4_set_rmii_mac(pf, speed, duplex); + + if (duplex == DUPLEX_FULL) { + /* When preemption is enabled, generation of PAUSE frames + * must be disabled, as stated in the IEEE 802.3 standard. + */ + if (priv->active_offloads & ENETC_F_QBU) + tx_pause = false; + } else { /* DUPLEX_HALF */ + if (tx_pause || rx_pause) + hd_fc = true; + + /* As per 802.3 annex 31B, PAUSE frames are only supported + * when the link is configured for full duplex operation. + */ + tx_pause = false; + rx_pause = false; + } + + enetc4_set_hd_flow_control(pf, hd_fc); + enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause); + enetc4_set_rx_pause(pf, rx_pause); + enetc4_enable_mac(pf, true); +} + +static void enetc4_pl_mac_link_down(struct phylink_config *config, + unsigned int mode, + phy_interface_t interface) +{ + struct enetc_pf *pf = phylink_to_enetc_pf(config); + + enetc4_enable_mac(pf, false); +} + +static const struct phylink_mac_ops enetc_pl_mac_ops = { + .mac_select_pcs = enetc4_pl_mac_select_pcs, + .mac_config = enetc4_pl_mac_config, + .mac_link_up = enetc4_pl_mac_link_up, + .mac_link_down = enetc4_pl_mac_link_down, +}; + +static void enetc4_pci_remove(void *data) +{ + struct pci_dev *pdev = data; + + enetc_pci_remove(pdev); +} + +static int enetc4_link_init(struct enetc_ndev_priv *priv, + struct device_node *node) +{ + struct enetc_pf *pf = enetc_si_priv(priv->si); + struct device *dev = priv->dev; + int err; + + err = of_get_phy_mode(node, &pf->if_mode); + if (err) { + dev_err(dev, "Failed to get PHY mode\n"); + return err; + } + + err = enetc_mdiobus_create(pf, node); + if (err) { + dev_err(dev, "Failed to create MDIO bus\n"); + return err; + } + + err = enetc_phylink_create(priv, node, &enetc_pl_mac_ops); + if (err) { + dev_err(dev, "Failed to create phylink\n"); + goto err_phylink_create; + } + + return 0; + +err_phylink_create: + enetc_mdiobus_destroy(pf); + + return err; +} + +static void enetc4_link_deinit(struct enetc_ndev_priv *priv) +{ + struct enetc_pf *pf = enetc_si_priv(priv->si); + + enetc_phylink_destroy(priv); + enetc_mdiobus_destroy(pf); +} + +static int enetc4_pf_netdev_create(struct enetc_si *si) +{ + struct device *dev = &si->pdev->dev; + struct enetc_ndev_priv *priv; + struct net_device *ndev; + int err; + + ndev = alloc_etherdev_mqs(sizeof(struct enetc_ndev_priv), + si->num_tx_rings, si->num_rx_rings); + if (!ndev) + return -ENOMEM; + + priv = netdev_priv(ndev); + priv->ref_clk = devm_clk_get_optional(dev, "ref"); + if (IS_ERR(priv->ref_clk)) { + dev_err(dev, "Get reference clock failed\n"); + err = PTR_ERR(priv->ref_clk); + goto err_clk_get; + } + + enetc_pf_netdev_setup(si, ndev, &enetc4_ndev_ops); + + enetc_init_si_rings_params(priv); + + err = enetc_configure_si(priv); + if (err) { + dev_err(dev, "Failed to configure SI\n"); + goto err_config_si; + } + + err = enetc_alloc_msix(priv); + if (err) { + dev_err(dev, "Failed to alloc MSI-X\n"); + goto err_alloc_msix; + } + + err = enetc4_link_init(priv, dev->of_node); + if (err) + goto err_link_init; + + err = register_netdev(ndev); + if (err) { + dev_err(dev, "Failed to register netdev\n"); + goto err_reg_netdev; + } + + return 0; + +err_reg_netdev: + enetc4_link_deinit(priv); +err_link_init: + enetc_free_msix(priv); +err_alloc_msix: +err_config_si: +err_clk_get: + mutex_destroy(&priv->mm_lock); + free_netdev(ndev); + + return err; +} + +static void enetc4_pf_netdev_destroy(struct enetc_si *si) +{ + struct enetc_ndev_priv *priv = netdev_priv(si->ndev); + struct net_device *ndev = si->ndev; + + unregister_netdev(ndev); + enetc_free_msix(priv); + free_netdev(ndev); +} + +static int enetc4_pf_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct enetc_si *si; + struct enetc_pf *pf; + int err; + + err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf)); + if (err) + return dev_err_probe(dev, err, "PCIe probing failed\n"); + + err = devm_add_action_or_reset(dev, enetc4_pci_remove, pdev); + if (err) + return dev_err_probe(dev, err, + "Add enetc4_pci_remove() action failed\n"); + + /* si is the private data. */ + si = pci_get_drvdata(pdev); + if (!si->hw.port || !si->hw.global) + return dev_err_probe(dev, -ENODEV, + "Couldn't map PF only space\n"); + + si->revision = enetc_get_ip_revision(&si->hw); + err = enetc_get_driver_data(si); + if (err) + return dev_err_probe(dev, err, + "Could not get VF driver data\n"); + + err = enetc4_pf_struct_init(si); + if (err) + return err; + + pf = enetc_si_priv(si); + err = enetc4_pf_init(pf); + if (err) + return err; + + enetc_get_si_caps(si); + + return enetc4_pf_netdev_create(si); +} + +static void enetc4_pf_remove(struct pci_dev *pdev) +{ + struct enetc_si *si = pci_get_drvdata(pdev); + + enetc4_pf_netdev_destroy(si); +} + +static const struct pci_device_id enetc4_pf_id_table[] = { + { PCI_DEVICE(NXP_ENETC_VENDOR_ID, NXP_ENETC_PF_DEV_ID) }, + { 0, } /* End of table. */ +}; +MODULE_DEVICE_TABLE(pci, enetc4_pf_id_table); + +static struct pci_driver enetc4_pf_driver = { + .name = KBUILD_MODNAME, + .id_table = enetc4_pf_id_table, + .probe = enetc4_pf_probe, + .remove = enetc4_pf_remove, +}; +module_pci_driver(enetc4_pf_driver); + +MODULE_DESCRIPTION("ENETC4 PF Driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c index 2563eb8ac7b63a..bf34b5bb1e3581 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -247,38 +247,25 @@ static int enetc_get_sset_count(struct net_device *ndev, int sset) static void enetc_get_strings(struct net_device *ndev, u32 stringset, u8 *data) { struct enetc_ndev_priv *priv = netdev_priv(ndev); - u8 *p = data; int i, j; switch (stringset) { case ETH_SS_STATS: - for (i = 0; i < ARRAY_SIZE(enetc_si_counters); i++) { - strscpy(p, enetc_si_counters[i].name, ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } - for (i = 0; i < priv->num_tx_rings; i++) { - for (j = 0; j < ARRAY_SIZE(tx_ring_stats); j++) { - snprintf(p, ETH_GSTRING_LEN, tx_ring_stats[j], - i); - p += ETH_GSTRING_LEN; - } - } - for (i = 0; i < priv->num_rx_rings; i++) { - for (j = 0; j < ARRAY_SIZE(rx_ring_stats); j++) { - snprintf(p, ETH_GSTRING_LEN, rx_ring_stats[j], - i); - p += ETH_GSTRING_LEN; - } - } + for (i = 0; i < ARRAY_SIZE(enetc_si_counters); i++) + ethtool_puts(&data, enetc_si_counters[i].name); + for (i = 0; i < priv->num_tx_rings; i++) + for (j = 0; j < ARRAY_SIZE(tx_ring_stats); j++) + ethtool_sprintf(&data, tx_ring_stats[j], i); + for (i = 0; i < priv->num_rx_rings; i++) + for (j = 0; j < ARRAY_SIZE(rx_ring_stats); j++) + ethtool_sprintf(&data, rx_ring_stats[j], i); if (!enetc_si_is_pf(priv->si)) break; - for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++) { - strscpy(p, enetc_port_counters[i].name, - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } + for (i = 0; i < ARRAY_SIZE(enetc_port_counters); i++) + ethtool_puts(&data, enetc_port_counters[i].name); + break; } } @@ -775,9 +762,10 @@ static int enetc_get_coalesce(struct net_device *ndev, { struct enetc_ndev_priv *priv = netdev_priv(ndev); struct enetc_int_vector *v = priv->int_vector[0]; + u64 clk_freq = priv->sysclk_freq; - ic->tx_coalesce_usecs = enetc_cycles_to_usecs(priv->tx_ictt); - ic->rx_coalesce_usecs = enetc_cycles_to_usecs(v->rx_ictt); + ic->tx_coalesce_usecs = enetc_cycles_to_usecs(priv->tx_ictt, clk_freq); + ic->rx_coalesce_usecs = enetc_cycles_to_usecs(v->rx_ictt, clk_freq); ic->tx_max_coalesced_frames = ENETC_TXIC_PKTTHR; ic->rx_max_coalesced_frames = ENETC_RXIC_PKTTHR; @@ -793,12 +781,13 @@ static int enetc_set_coalesce(struct net_device *ndev, struct netlink_ext_ack *extack) { struct enetc_ndev_priv *priv = netdev_priv(ndev); + u64 clk_freq = priv->sysclk_freq; u32 rx_ictt, tx_ictt; int i, ic_mode; bool changed; - tx_ictt = enetc_usecs_to_cycles(ic->tx_coalesce_usecs); - rx_ictt = enetc_usecs_to_cycles(ic->rx_coalesce_usecs); + tx_ictt = enetc_usecs_to_cycles(ic->tx_coalesce_usecs, clk_freq); + rx_ictt = enetc_usecs_to_cycles(ic->rx_coalesce_usecs, clk_freq); if (ic->rx_max_coalesced_frames != ENETC_RXIC_PKTTHR) return -EOPNOTSUPP; @@ -1178,7 +1167,7 @@ void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link) } EXPORT_SYMBOL_GPL(enetc_mm_link_state_update); -static const struct ethtool_ops enetc_pf_ethtool_ops = { +const struct ethtool_ops enetc_pf_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES | ETHTOOL_COALESCE_USE_ADAPTIVE_RX, @@ -1213,7 +1202,7 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = { .get_mm_stats = enetc_get_mm_stats, }; -static const struct ethtool_ops enetc_vf_ethtool_ops = { +const struct ethtool_ops enetc_vf_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES | ETHTOOL_COALESCE_USE_ADAPTIVE_RX, @@ -1234,13 +1223,26 @@ static const struct ethtool_ops enetc_vf_ethtool_ops = { .get_ts_info = enetc_get_ts_info, }; +const struct ethtool_ops enetc4_pf_ethtool_ops = { + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | + ETHTOOL_COALESCE_MAX_FRAMES | + ETHTOOL_COALESCE_USE_ADAPTIVE_RX, + .get_ringparam = enetc_get_ringparam, + .get_coalesce = enetc_get_coalesce, + .set_coalesce = enetc_set_coalesce, + .get_link_ksettings = enetc_get_link_ksettings, + .set_link_ksettings = enetc_set_link_ksettings, + .get_link = ethtool_op_get_link, + .get_wol = enetc_get_wol, + .set_wol = enetc_set_wol, + .get_pauseparam = enetc_get_pauseparam, + .set_pauseparam = enetc_set_pauseparam, +}; + void enetc_set_ethtool_ops(struct net_device *ndev) { struct enetc_ndev_priv *priv = netdev_priv(ndev); - if (enetc_si_is_pf(priv->si)) - ndev->ethtool_ops = &enetc_pf_ethtool_ops; - else - ndev->ethtool_ops = &enetc_vf_ethtool_ops; + ndev->ethtool_ops = priv->si->drvdata->eth_ops; } EXPORT_SYMBOL_GPL(enetc_set_ethtool_ops); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h index 1619943fb2637a..55ba949230ffd0 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h @@ -6,6 +6,8 @@ #define ENETC_MM_VERIFY_SLEEP_US USEC_PER_MSEC #define ENETC_MM_VERIFY_RETRIES 3 +#define ENETC_NUM_TC 8 + /* ENETC device IDs */ #define ENETC_DEV_ID_PF 0xe100 #define ENETC_DEV_ID_VF 0xef00 @@ -21,10 +23,8 @@ #define ENETC_SICTR0 0x18 #define ENETC_SICTR1 0x1c #define ENETC_SIPCAPR0 0x20 -#define ENETC_SIPCAPR0_PSFP BIT(9) #define ENETC_SIPCAPR0_RSS BIT(8) -#define ENETC_SIPCAPR0_QBV BIT(4) -#define ENETC_SIPCAPR0_QBU BIT(3) +#define ENETC_SIPCAPR0_RFS BIT(2) #define ENETC_SIPCAPR1 0x24 #define ENETC_SITGTGR 0x30 #define ENETC_SIRBGCR 0x38 @@ -191,6 +191,9 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_PCAPR0 0x0900 #define ENETC_PCAPR0_RXBDR(val) ((val) >> 24) #define ENETC_PCAPR0_TXBDR(val) (((val) >> 16) & 0xff) +#define ENETC_PCAPR0_PSFP BIT(9) +#define ENETC_PCAPR0_QBV BIT(4) +#define ENETC_PCAPR0_QBU BIT(3) #define ENETC_PCAPR1 0x0904 #define ENETC_PSICFGR0(n) (0x0940 + (n) * 0xc) /* n = SI index */ #define ENETC_PSICFGR0_SET_TXBDR(val) ((val) & 0xff) @@ -368,6 +371,10 @@ enum enetc_bdr_type {TX, RX}; /** Global regs, offset: 2_0000h */ #define ENETC_GLOBAL_BASE 0x20000 #define ENETC_G_EIPBRR0 0x0bf8 +#define EIPBRR0_REVISION GENMASK(15, 0) +#define ENETC_REV_1_0 0x0100 +#define ENETC_REV_4_1 0X0401 + #define ENETC_G_EIPBRR1 0x0bfc #define ENETC_G_EPFBLPR(n) (0xd00 + 4 * (n)) #define ENETC_G_EPFBLPR1_XGMII 0x80000000 @@ -396,18 +403,22 @@ struct enetc_hw { */ extern rwlock_t enetc_mdio_lock; +DECLARE_STATIC_KEY_FALSE(enetc_has_err050089); + /* use this locking primitive only on the fast datapath to * group together multiple non-MDIO register accesses to * minimize the overhead of the lock */ static inline void enetc_lock_mdio(void) { - read_lock(&enetc_mdio_lock); + if (static_branch_unlikely(&enetc_has_err050089)) + read_lock(&enetc_mdio_lock); } static inline void enetc_unlock_mdio(void) { - read_unlock(&enetc_mdio_lock); + if (static_branch_unlikely(&enetc_has_err050089)) + read_unlock(&enetc_mdio_lock); } /* use these accessors only on the fast datapath under @@ -416,14 +427,16 @@ static inline void enetc_unlock_mdio(void) */ static inline u32 enetc_rd_reg_hot(void __iomem *reg) { - lockdep_assert_held(&enetc_mdio_lock); + if (static_branch_unlikely(&enetc_has_err050089)) + lockdep_assert_held(&enetc_mdio_lock); return ioread32(reg); } static inline void enetc_wr_reg_hot(void __iomem *reg, u32 val) { - lockdep_assert_held(&enetc_mdio_lock); + if (static_branch_unlikely(&enetc_has_err050089)) + lockdep_assert_held(&enetc_mdio_lock); iowrite32(val, reg); } @@ -452,9 +465,13 @@ static inline u32 _enetc_rd_mdio_reg_wa(void __iomem *reg) unsigned long flags; u32 val; - write_lock_irqsave(&enetc_mdio_lock, flags); - val = ioread32(reg); - write_unlock_irqrestore(&enetc_mdio_lock, flags); + if (static_branch_unlikely(&enetc_has_err050089)) { + write_lock_irqsave(&enetc_mdio_lock, flags); + val = ioread32(reg); + write_unlock_irqrestore(&enetc_mdio_lock, flags); + } else { + val = ioread32(reg); + } return val; } @@ -463,9 +480,13 @@ static inline void _enetc_wr_mdio_reg_wa(void __iomem *reg, u32 val) { unsigned long flags; - write_lock_irqsave(&enetc_mdio_lock, flags); - iowrite32(val, reg); - write_unlock_irqrestore(&enetc_mdio_lock, flags); + if (static_branch_unlikely(&enetc_has_err050089)) { + write_lock_irqsave(&enetc_mdio_lock, flags); + iowrite32(val, reg); + write_unlock_irqrestore(&enetc_mdio_lock, flags); + } else { + iowrite32(val, reg); + } } #ifdef ioread64 @@ -957,15 +978,17 @@ struct enetc_cbd { u8 status_flags; }; -#define ENETC_CLK 400000000ULL -static inline u32 enetc_cycles_to_usecs(u32 cycles) +#define ENETC_CLK_400M 400000000ULL +#define ENETC_CLK_333M 333000000ULL + +static inline u32 enetc_cycles_to_usecs(u32 cycles, u64 clk_freq) { - return (u32)div_u64(cycles * 1000000ULL, ENETC_CLK); + return (u32)div_u64(cycles * 1000000ULL, clk_freq); } -static inline u32 enetc_usecs_to_cycles(u32 usecs) +static inline u32 enetc_usecs_to_cycles(u32 usecs, u64 clk_freq) { - return (u32)div_u64(usecs * ENETC_CLK, 1000000ULL); + return (u32)div_u64(usecs * clk_freq, 1000000ULL); } /* Port traffic class frame preemption register */ diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c index a1b595bd799356..e108cac8288d36 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c @@ -4,11 +4,35 @@ #include #include "enetc_pf.h" +#define NETC_EMDIO_VEN_ID 0x1131 +#define NETC_EMDIO_DEV_ID 0xee00 #define ENETC_MDIO_DEV_ID 0xee01 #define ENETC_MDIO_DEV_NAME "FSL PCIe IE Central MDIO" #define ENETC_MDIO_BUS_NAME ENETC_MDIO_DEV_NAME " Bus" #define ENETC_MDIO_DRV_NAME ENETC_MDIO_DEV_NAME " driver" +DEFINE_STATIC_KEY_FALSE(enetc_has_err050089); +EXPORT_SYMBOL_GPL(enetc_has_err050089); + +static void enetc_emdio_enable_err050089(struct pci_dev *pdev) +{ + if (pdev->vendor == PCI_VENDOR_ID_FREESCALE && + pdev->device == ENETC_MDIO_DEV_ID) { + static_branch_inc(&enetc_has_err050089); + dev_info(&pdev->dev, "Enabled ERR050089 workaround\n"); + } +} + +static void enetc_emdio_disable_err050089(struct pci_dev *pdev) +{ + if (pdev->vendor == PCI_VENDOR_ID_FREESCALE && + pdev->device == ENETC_MDIO_DEV_ID) { + static_branch_dec(&enetc_has_err050089); + if (!static_key_enabled(&enetc_has_err050089.key)) + dev_info(&pdev->dev, "Disabled ERR050089 workaround\n"); + } +} + static int enetc_pci_mdio_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -62,6 +86,8 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev, goto err_pci_mem_reg; } + enetc_emdio_enable_err050089(pdev); + err = of_mdiobus_register(bus, dev->of_node); if (err) goto err_mdiobus_reg; @@ -71,6 +97,7 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev, return 0; err_mdiobus_reg: + enetc_emdio_disable_err050089(pdev); pci_release_region(pdev, 0); err_pci_mem_reg: pci_disable_device(pdev); @@ -88,6 +115,9 @@ static void enetc_pci_mdio_remove(struct pci_dev *pdev) struct enetc_mdio_priv *mdio_priv; mdiobus_unregister(bus); + + enetc_emdio_disable_err050089(pdev); + mdio_priv = bus->priv; iounmap(mdio_priv->hw->port); pci_release_region(pdev, 0); @@ -96,6 +126,7 @@ static void enetc_pci_mdio_remove(struct pci_dev *pdev) static const struct pci_device_id enetc_pci_mdio_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_MDIO_DEV_ID) }, + { PCI_DEVICE(NETC_EMDIO_VEN_ID, NETC_EMDIO_DEV_ID) }, { 0, } /* End of table. */ }; MODULE_DEVICE_TABLE(pci, enetc_pci_mdio_id_table); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index c95a7c083b0f48..203862ec111427 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -2,15 +2,13 @@ /* Copyright 2017-2019 NXP */ #include -#include #include -#include +#include #include -#include #include #include #include "enetc_ierb.h" -#include "enetc_pf.h" +#include "enetc_pf_common.h" #define ENETC_DRV_NAME_STR "ENETC PF driver" @@ -33,18 +31,15 @@ static void enetc_pf_set_primary_mac_addr(struct enetc_hw *hw, int si, __raw_writew(lower, hw->port + ENETC_PSIPMAR1(si)); } -static int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr) +static struct phylink_pcs *enetc_pf_create_pcs(struct enetc_pf *pf, + struct mii_bus *bus) { - struct enetc_ndev_priv *priv = netdev_priv(ndev); - struct sockaddr *saddr = addr; - - if (!is_valid_ether_addr(saddr->sa_data)) - return -EADDRNOTAVAIL; - - eth_hw_addr_set(ndev, saddr->sa_data); - enetc_pf_set_primary_mac_addr(&priv->si->hw, 0, saddr->sa_data); + return lynx_pcs_create_mdiodev(bus, 0); +} - return 0; +static void enetc_pf_destroy_pcs(struct phylink_pcs *pcs) +{ + lynx_pcs_destroy(pcs); } static void enetc_set_vlan_promisc(struct enetc_hw *hw, char si_map) @@ -393,56 +388,6 @@ static int enetc_pf_set_vf_spoofchk(struct net_device *ndev, int vf, bool en) return 0; } -static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf, - int si) -{ - struct device *dev = &pf->si->pdev->dev; - struct enetc_hw *hw = &pf->si->hw; - u8 mac_addr[ETH_ALEN] = { 0 }; - int err; - - /* (1) try to get the MAC address from the device tree */ - if (np) { - err = of_get_mac_address(np, mac_addr); - if (err == -EPROBE_DEFER) - return err; - } - - /* (2) bootloader supplied MAC address */ - if (is_zero_ether_addr(mac_addr)) - enetc_pf_get_primary_mac_addr(hw, si, mac_addr); - - /* (3) choose a random one */ - if (is_zero_ether_addr(mac_addr)) { - eth_random_addr(mac_addr); - dev_info(dev, "no MAC address specified for SI%d, using %pM\n", - si, mac_addr); - } - - enetc_pf_set_primary_mac_addr(hw, si, mac_addr); - - return 0; -} - -static int enetc_setup_mac_addresses(struct device_node *np, - struct enetc_pf *pf) -{ - int err, i; - - /* The PF might take its MAC from the device tree */ - err = enetc_setup_mac_address(np, pf, 0); - if (err) - return err; - - for (i = 0; i < pf->total_vfs; i++) { - err = enetc_setup_mac_address(NULL, pf, i + 1); - if (err) - return err; - } - - return 0; -} - static void enetc_port_assign_rfs_entries(struct enetc_si *si) { struct enetc_pf *pf = enetc_si_priv(si); @@ -464,6 +409,23 @@ static void enetc_port_assign_rfs_entries(struct enetc_si *si) enetc_port_wr(hw, ENETC_PRFSMR, ENETC_PRFSMR_RFSE); } +static void enetc_port_get_caps(struct enetc_si *si) +{ + struct enetc_hw *hw = &si->hw; + u32 val; + + val = enetc_port_rd(hw, ENETC_PCAPR0); + + if (val & ENETC_PCAPR0_QBV) + si->hw_features |= ENETC_SI_F_QBV; + + if (val & ENETC_PCAPR0_QBU) + si->hw_features |= ENETC_SI_F_QBU; + + if (val & ENETC_PCAPR0_PSFP) + si->hw_features |= ENETC_SI_F_PSFP; +} + static void enetc_port_si_configure(struct enetc_si *si) { struct enetc_pf *pf = enetc_si_priv(si); @@ -471,6 +433,8 @@ static void enetc_port_si_configure(struct enetc_si *si) int num_rings, i; u32 val; + enetc_port_get_caps(si); + val = enetc_port_rd(hw, ENETC_PCAPR0); num_rings = min(ENETC_PCAPR0_RXBDR(val), ENETC_PCAPR0_TXBDR(val)); @@ -766,187 +730,6 @@ static const struct net_device_ops enetc_ndev_ops = { .ndo_xdp_xmit = enetc_xdp_xmit, }; -static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, - const struct net_device_ops *ndev_ops) -{ - struct enetc_ndev_priv *priv = netdev_priv(ndev); - - SET_NETDEV_DEV(ndev, &si->pdev->dev); - priv->ndev = ndev; - priv->si = si; - priv->dev = &si->pdev->dev; - si->ndev = ndev; - - priv->msg_enable = (NETIF_MSG_WOL << 1) - 1; - ndev->netdev_ops = ndev_ops; - enetc_set_ethtool_ops(ndev); - ndev->watchdog_timeo = 5 * HZ; - ndev->max_mtu = ENETC_MAX_MTU; - - ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | - NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | - NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK | - NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6; - ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM | - NETIF_F_HW_VLAN_CTAG_TX | - NETIF_F_HW_VLAN_CTAG_RX | - NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6; - ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM | - NETIF_F_TSO | NETIF_F_TSO6; - - if (si->num_rss) - ndev->hw_features |= NETIF_F_RXHASH; - - ndev->priv_flags |= IFF_UNICAST_FLT; - ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | - NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG | - NETDEV_XDP_ACT_NDO_XMIT_SG; - - if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) { - priv->active_offloads |= ENETC_F_QCI; - ndev->features |= NETIF_F_HW_TC; - ndev->hw_features |= NETIF_F_HW_TC; - } - - /* pick up primary MAC address from SI */ - enetc_load_primary_mac_addr(&si->hw, ndev); -} - -static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np) -{ - struct device *dev = &pf->si->pdev->dev; - struct enetc_mdio_priv *mdio_priv; - struct mii_bus *bus; - int err; - - bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); - if (!bus) - return -ENOMEM; - - bus->name = "Freescale ENETC MDIO Bus"; - bus->read = enetc_mdio_read_c22; - bus->write = enetc_mdio_write_c22; - bus->read_c45 = enetc_mdio_read_c45; - bus->write_c45 = enetc_mdio_write_c45; - bus->parent = dev; - mdio_priv = bus->priv; - mdio_priv->hw = &pf->si->hw; - mdio_priv->mdio_base = ENETC_EMDIO_BASE; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); - - err = of_mdiobus_register(bus, np); - if (err) - return dev_err_probe(dev, err, "cannot register MDIO bus\n"); - - pf->mdio = bus; - - return 0; -} - -static void enetc_mdio_remove(struct enetc_pf *pf) -{ - if (pf->mdio) - mdiobus_unregister(pf->mdio); -} - -static int enetc_imdio_create(struct enetc_pf *pf) -{ - struct device *dev = &pf->si->pdev->dev; - struct enetc_mdio_priv *mdio_priv; - struct phylink_pcs *phylink_pcs; - struct mii_bus *bus; - int err; - - bus = mdiobus_alloc_size(sizeof(*mdio_priv)); - if (!bus) - return -ENOMEM; - - bus->name = "Freescale ENETC internal MDIO Bus"; - bus->read = enetc_mdio_read_c22; - bus->write = enetc_mdio_write_c22; - bus->read_c45 = enetc_mdio_read_c45; - bus->write_c45 = enetc_mdio_write_c45; - bus->parent = dev; - bus->phy_mask = ~0; - mdio_priv = bus->priv; - mdio_priv->hw = &pf->si->hw; - mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev)); - - err = mdiobus_register(bus); - if (err) { - dev_err(dev, "cannot register internal MDIO bus (%d)\n", err); - goto free_mdio_bus; - } - - phylink_pcs = lynx_pcs_create_mdiodev(bus, 0); - if (IS_ERR(phylink_pcs)) { - err = PTR_ERR(phylink_pcs); - dev_err(dev, "cannot create lynx pcs (%d)\n", err); - goto unregister_mdiobus; - } - - pf->imdio = bus; - pf->pcs = phylink_pcs; - - return 0; - -unregister_mdiobus: - mdiobus_unregister(bus); -free_mdio_bus: - mdiobus_free(bus); - return err; -} - -static void enetc_imdio_remove(struct enetc_pf *pf) -{ - if (pf->pcs) - lynx_pcs_destroy(pf->pcs); - if (pf->imdio) { - mdiobus_unregister(pf->imdio); - mdiobus_free(pf->imdio); - } -} - -static bool enetc_port_has_pcs(struct enetc_pf *pf) -{ - return (pf->if_mode == PHY_INTERFACE_MODE_SGMII || - pf->if_mode == PHY_INTERFACE_MODE_1000BASEX || - pf->if_mode == PHY_INTERFACE_MODE_2500BASEX || - pf->if_mode == PHY_INTERFACE_MODE_USXGMII); -} - -static int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node) -{ - struct device_node *mdio_np; - int err; - - mdio_np = of_get_child_by_name(node, "mdio"); - if (mdio_np) { - err = enetc_mdio_probe(pf, mdio_np); - - of_node_put(mdio_np); - if (err) - return err; - } - - if (enetc_port_has_pcs(pf)) { - err = enetc_imdio_create(pf); - if (err) { - enetc_mdio_remove(pf); - return err; - } - } - - return 0; -} - -static void enetc_mdiobus_destroy(struct enetc_pf *pf) -{ - enetc_mdio_remove(pf); - enetc_imdio_remove(pf); -} - static struct phylink_pcs * enetc_pl_mac_select_pcs(struct phylink_config *config, phy_interface_t iface) { @@ -1092,47 +875,6 @@ static const struct phylink_mac_ops enetc_mac_phylink_ops = { .mac_link_down = enetc_pl_mac_link_down, }; -static int enetc_phylink_create(struct enetc_ndev_priv *priv, - struct device_node *node) -{ - struct enetc_pf *pf = enetc_si_priv(priv->si); - struct phylink *phylink; - int err; - - pf->phylink_config.dev = &priv->ndev->dev; - pf->phylink_config.type = PHYLINK_NETDEV; - pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; - - __set_bit(PHY_INTERFACE_MODE_INTERNAL, - pf->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_SGMII, - pf->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_1000BASEX, - pf->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_2500BASEX, - pf->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_USXGMII, - pf->phylink_config.supported_interfaces); - phy_interface_set_rgmii(pf->phylink_config.supported_interfaces); - - phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node), - pf->if_mode, &enetc_mac_phylink_ops); - if (IS_ERR(phylink)) { - err = PTR_ERR(phylink); - return err; - } - - priv->phylink = phylink; - - return 0; -} - -static void enetc_phylink_destroy(struct enetc_ndev_priv *priv) -{ - phylink_destroy(priv->phylink); -} - /* Initialize the entire shared memory for the flow steering entries * of this port (PF + VFs) */ @@ -1215,6 +957,13 @@ static struct enetc_si *enetc_psi_create(struct pci_dev *pdev) goto out_pci_remove; } + si->revision = enetc_get_ip_revision(&si->hw); + err = enetc_get_driver_data(si); + if (err) { + dev_err(&pdev->dev, "Could not get PF driver data\n"); + goto out_pci_remove; + } + err = enetc_setup_cbdr(&pdev->dev, &si->hw, ENETC_CBDR_DEFAULT_SIZE, &si->cbd_ring); if (err) @@ -1250,6 +999,14 @@ static void enetc_psi_destroy(struct pci_dev *pdev) enetc_pci_remove(pdev); } +static const struct enetc_pf_ops enetc_pf_ops = { + .set_si_primary_mac = enetc_pf_set_primary_mac_addr, + .get_si_primary_mac = enetc_pf_get_primary_mac_addr, + .create_pcs = enetc_pf_create_pcs, + .destroy_pcs = enetc_pf_destroy_pcs, + .enable_psfp = enetc_psfp_enable, +}; + static int enetc_pf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1276,6 +1033,8 @@ static int enetc_pf_probe(struct pci_dev *pdev, pf = enetc_si_priv(si); pf->si = si; + pf->ops = &enetc_pf_ops; + pf->total_vfs = pci_sriov_get_totalvfs(pdev); if (pf->total_vfs) { pf->vf_state = kcalloc(pf->total_vfs, sizeof(struct enetc_vf_state), @@ -1335,7 +1094,7 @@ static int enetc_pf_probe(struct pci_dev *pdev, if (err) goto err_mdiobus_create; - err = enetc_phylink_create(priv, node); + err = enetc_phylink_create(priv, node, &enetc_mac_phylink_ops); if (err) goto err_phylink_create; diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h index c26bd66e45976a..a26a1286385580 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h @@ -28,6 +28,24 @@ struct enetc_vf_state { enum enetc_vf_flags flags; }; +struct enetc_port_caps { + u32 half_duplex:1; + int num_vsi; + int num_msix; + int num_rx_bdr; + int num_tx_bdr; +}; + +struct enetc_pf; + +struct enetc_pf_ops { + void (*set_si_primary_mac)(struct enetc_hw *hw, int si, const u8 *addr); + void (*get_si_primary_mac)(struct enetc_hw *hw, int si, u8 *addr); + struct phylink_pcs *(*create_pcs)(struct enetc_pf *pf, struct mii_bus *bus); + void (*destroy_pcs)(struct phylink_pcs *pcs); + int (*enable_psfp)(struct enetc_ndev_priv *priv); +}; + struct enetc_pf { struct enetc_si *si; int num_vfs; /* number of active VFs, after sriov_init */ @@ -50,6 +68,9 @@ struct enetc_pf { phy_interface_t if_mode; struct phylink_config phylink_config; + + struct enetc_port_caps caps; + const struct enetc_pf_ops *ops; }; #define phylink_to_enetc_pf(config) \ diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c new file mode 100644 index 00000000000000..0eecfc833164fd --- /dev/null +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* Copyright 2024 NXP */ + +#include +#include +#include + +#include "enetc_pf_common.h" + +static void enetc_set_si_hw_addr(struct enetc_pf *pf, int si, + const u8 *mac_addr) +{ + struct enetc_hw *hw = &pf->si->hw; + + pf->ops->set_si_primary_mac(hw, si, mac_addr); +} + +static void enetc_get_si_hw_addr(struct enetc_pf *pf, int si, u8 *mac_addr) +{ + struct enetc_hw *hw = &pf->si->hw; + + pf->ops->get_si_primary_mac(hw, si, mac_addr); +} + +int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct enetc_pf *pf = enetc_si_priv(priv->si); + struct sockaddr *saddr = addr; + + if (!is_valid_ether_addr(saddr->sa_data)) + return -EADDRNOTAVAIL; + + eth_hw_addr_set(ndev, saddr->sa_data); + enetc_set_si_hw_addr(pf, 0, saddr->sa_data); + + return 0; +} +EXPORT_SYMBOL_GPL(enetc_pf_set_mac_addr); + +static int enetc_setup_mac_address(struct device_node *np, struct enetc_pf *pf, + int si) +{ + struct device *dev = &pf->si->pdev->dev; + u8 mac_addr[ETH_ALEN] = { 0 }; + int err; + + /* (1) try to get the MAC address from the device tree */ + if (np) { + err = of_get_mac_address(np, mac_addr); + if (err == -EPROBE_DEFER) + return err; + } + + /* (2) bootloader supplied MAC address */ + if (is_zero_ether_addr(mac_addr)) + enetc_get_si_hw_addr(pf, si, mac_addr); + + /* (3) choose a random one */ + if (is_zero_ether_addr(mac_addr)) { + eth_random_addr(mac_addr); + dev_info(dev, "no MAC address specified for SI%d, using %pM\n", + si, mac_addr); + } + + enetc_set_si_hw_addr(pf, si, mac_addr); + + return 0; +} + +int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf) +{ + int err, i; + + /* The PF might take its MAC from the device tree */ + err = enetc_setup_mac_address(np, pf, 0); + if (err) + return err; + + for (i = 0; i < pf->total_vfs; i++) { + err = enetc_setup_mac_address(NULL, pf, i + 1); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses); + +void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, + const struct net_device_ops *ndev_ops) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct enetc_pf *pf = enetc_si_priv(si); + + SET_NETDEV_DEV(ndev, &si->pdev->dev); + priv->ndev = ndev; + priv->si = si; + priv->dev = &si->pdev->dev; + si->ndev = ndev; + + priv->msg_enable = (NETIF_MSG_WOL << 1) - 1; + priv->sysclk_freq = si->drvdata->sysclk_freq; + ndev->netdev_ops = ndev_ops; + enetc_set_ethtool_ops(ndev); + ndev->watchdog_timeo = 5 * HZ; + ndev->max_mtu = ENETC_MAX_MTU; + + ndev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK | + NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6; + ndev->features = NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6; + ndev->vlan_features = NETIF_F_SG | NETIF_F_HW_CSUM | + NETIF_F_TSO | NETIF_F_TSO6; + + ndev->priv_flags |= IFF_UNICAST_FLT; + + /* TODO: currently, i.MX95 ENETC driver does not support advanced features */ + if (!is_enetc_rev1(si)) { + ndev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_LOOPBACK); + goto end; + } + + if (si->num_rss) + ndev->hw_features |= NETIF_F_RXHASH; + + ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_NDO_XMIT | NETDEV_XDP_ACT_RX_SG | + NETDEV_XDP_ACT_NDO_XMIT_SG; + + if (si->hw_features & ENETC_SI_F_PSFP && pf->ops->enable_psfp && + !pf->ops->enable_psfp(priv)) { + priv->active_offloads |= ENETC_F_QCI; + ndev->features |= NETIF_F_HW_TC; + ndev->hw_features |= NETIF_F_HW_TC; + } + +end: + /* pick up primary MAC address from SI */ + enetc_load_primary_mac_addr(&si->hw, ndev); +} +EXPORT_SYMBOL_GPL(enetc_pf_netdev_setup); + +static int enetc_mdio_probe(struct enetc_pf *pf, struct device_node *np) +{ + struct device *dev = &pf->si->pdev->dev; + struct enetc_mdio_priv *mdio_priv; + struct mii_bus *bus; + int err; + + bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); + if (!bus) + return -ENOMEM; + + bus->name = "Freescale ENETC MDIO Bus"; + bus->read = enetc_mdio_read_c22; + bus->write = enetc_mdio_write_c22; + bus->read_c45 = enetc_mdio_read_c45; + bus->write_c45 = enetc_mdio_write_c45; + bus->parent = dev; + mdio_priv = bus->priv; + mdio_priv->hw = &pf->si->hw; + mdio_priv->mdio_base = ENETC_EMDIO_BASE; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); + + err = of_mdiobus_register(bus, np); + if (err) + return dev_err_probe(dev, err, "cannot register MDIO bus\n"); + + pf->mdio = bus; + + return 0; +} + +static void enetc_mdio_remove(struct enetc_pf *pf) +{ + if (pf->mdio) + mdiobus_unregister(pf->mdio); +} + +static int enetc_imdio_create(struct enetc_pf *pf) +{ + struct device *dev = &pf->si->pdev->dev; + struct enetc_mdio_priv *mdio_priv; + struct phylink_pcs *phylink_pcs; + struct mii_bus *bus; + int err; + + if (!pf->ops->create_pcs) { + dev_err(dev, "Creating PCS is not supported\n"); + + return -EOPNOTSUPP; + } + + bus = mdiobus_alloc_size(sizeof(*mdio_priv)); + if (!bus) + return -ENOMEM; + + bus->name = "Freescale ENETC internal MDIO Bus"; + bus->read = enetc_mdio_read_c22; + bus->write = enetc_mdio_write_c22; + bus->read_c45 = enetc_mdio_read_c45; + bus->write_c45 = enetc_mdio_write_c45; + bus->parent = dev; + bus->phy_mask = ~0; + mdio_priv = bus->priv; + mdio_priv->hw = &pf->si->hw; + mdio_priv->mdio_base = ENETC_PM_IMDIO_BASE; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev)); + + err = mdiobus_register(bus); + if (err) { + dev_err(dev, "cannot register internal MDIO bus (%d)\n", err); + goto free_mdio_bus; + } + + phylink_pcs = pf->ops->create_pcs(pf, bus); + if (IS_ERR(phylink_pcs)) { + err = PTR_ERR(phylink_pcs); + dev_err(dev, "cannot create lynx pcs (%d)\n", err); + goto unregister_mdiobus; + } + + pf->imdio = bus; + pf->pcs = phylink_pcs; + + return 0; + +unregister_mdiobus: + mdiobus_unregister(bus); +free_mdio_bus: + mdiobus_free(bus); + return err; +} + +static void enetc_imdio_remove(struct enetc_pf *pf) +{ + if (pf->pcs && pf->ops->destroy_pcs) + pf->ops->destroy_pcs(pf->pcs); + + if (pf->imdio) { + mdiobus_unregister(pf->imdio); + mdiobus_free(pf->imdio); + } +} + +static bool enetc_port_has_pcs(struct enetc_pf *pf) +{ + return (pf->if_mode == PHY_INTERFACE_MODE_SGMII || + pf->if_mode == PHY_INTERFACE_MODE_1000BASEX || + pf->if_mode == PHY_INTERFACE_MODE_2500BASEX || + pf->if_mode == PHY_INTERFACE_MODE_USXGMII); +} + +int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node) +{ + struct device_node *mdio_np; + int err; + + mdio_np = of_get_child_by_name(node, "mdio"); + if (mdio_np) { + err = enetc_mdio_probe(pf, mdio_np); + + of_node_put(mdio_np); + if (err) + return err; + } + + if (enetc_port_has_pcs(pf)) { + err = enetc_imdio_create(pf); + if (err) { + enetc_mdio_remove(pf); + return err; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(enetc_mdiobus_create); + +void enetc_mdiobus_destroy(struct enetc_pf *pf) +{ + enetc_mdio_remove(pf); + enetc_imdio_remove(pf); +} +EXPORT_SYMBOL_GPL(enetc_mdiobus_destroy); + +int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node, + const struct phylink_mac_ops *ops) +{ + struct enetc_pf *pf = enetc_si_priv(priv->si); + struct phylink *phylink; + int err; + + pf->phylink_config.dev = &priv->ndev->dev; + pf->phylink_config.type = PHYLINK_NETDEV; + pf->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; + + __set_bit(PHY_INTERFACE_MODE_INTERNAL, + pf->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_SGMII, + pf->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, + pf->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_2500BASEX, + pf->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_USXGMII, + pf->phylink_config.supported_interfaces); + phy_interface_set_rgmii(pf->phylink_config.supported_interfaces); + + phylink = phylink_create(&pf->phylink_config, of_fwnode_handle(node), + pf->if_mode, ops); + if (IS_ERR(phylink)) { + err = PTR_ERR(phylink); + return err; + } + + priv->phylink = phylink; + + return 0; +} +EXPORT_SYMBOL_GPL(enetc_phylink_create); + +void enetc_phylink_destroy(struct enetc_ndev_priv *priv) +{ + phylink_destroy(priv->phylink); +} +EXPORT_SYMBOL_GPL(enetc_phylink_destroy); + +MODULE_DESCRIPTION("NXP ENETC PF common functionality driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h new file mode 100644 index 00000000000000..48f55ee743adce --- /dev/null +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* Copyright 2024 NXP */ + +#include "enetc_pf.h" + +int enetc_pf_set_mac_addr(struct net_device *ndev, void *addr); +int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf); +void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, + const struct net_device_ops *ndev_ops); +int enetc_mdiobus_create(struct enetc_pf *pf, struct device_node *node); +void enetc_mdiobus_destroy(struct enetc_pf *pf); +int enetc_phylink_create(struct enetc_ndev_priv *priv, struct device_node *node, + const struct phylink_mac_ops *ops); +void enetc_phylink_destroy(struct enetc_ndev_priv *priv); + +static inline u16 enetc_get_ip_revision(struct enetc_hw *hw) +{ + return enetc_global_rd(hw, ENETC_G_EIPBRR0) & EIPBRR0_REVISION; +} diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index b65da49dd92617..ccf86651455ca1 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -336,7 +336,7 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) * * (enetClockFrequency / portTransmitRate) * 100 */ - hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit, + hi_credit_reg = (u32)div_u64((priv->sysclk_freq * 100ULL) * hi_credit_bit, port_transmit_rate * 1000000ULL); enetc_port_wr(hw, ENETC_PTCCBSR1(tc), hi_credit_reg); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c index b15db70769e5ee..a5f8ce576b6e80 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c @@ -135,6 +135,7 @@ static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev, si->ndev = ndev; priv->msg_enable = (NETIF_MSG_IFUP << 1) - 1; + priv->sysclk_freq = si->drvdata->sysclk_freq; ndev->netdev_ops = ndev_ops; enetc_set_ethtool_ops(ndev); ndev->watchdog_timeo = 5 * HZ; @@ -171,6 +172,13 @@ static int enetc_vf_probe(struct pci_dev *pdev, return dev_err_probe(&pdev->dev, err, "PCI probing failed\n"); si = pci_get_drvdata(pdev); + si->revision = ENETC_REV_1_0; + err = enetc_get_driver_data(si); + if (err) { + dev_err_probe(&pdev->dev, err, + "Could not get VF driver data\n"); + goto err_alloc_netdev; + } enetc_get_si_caps(si); diff --git a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c new file mode 100644 index 00000000000000..bcb8eefeb93c0c --- /dev/null +++ b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * NXP NETC Blocks Control Driver + * + * Copyright 2024 NXP + * + * This driver is used for pre-initialization of NETC, such as PCS and MII + * protocols, LDID, warm reset, etc. Therefore, all NETC device drivers can + * only be probed after the netc-blk-crtl driver has completed initialization. + * In addition, when the system enters suspend mode, IERB, PRB, and NETCMIX + * will be powered off, except for WOL. Therefore, when the system resumes, + * these blocks need to be reinitialized. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* NETCMIX registers */ +#define IMX95_CFG_LINK_IO_VAR 0x0 +#define IO_VAR_16FF_16G_SERDES 0x1 +#define IO_VAR(port, var) (((var) & 0xf) << ((port) << 2)) + +#define IMX95_CFG_LINK_MII_PROT 0x4 +#define CFG_LINK_MII_PORT_0 GENMASK(3, 0) +#define CFG_LINK_MII_PORT_1 GENMASK(7, 4) +#define MII_PROT_MII 0x0 +#define MII_PROT_RMII 0x1 +#define MII_PROT_RGMII 0x2 +#define MII_PROT_SERIAL 0x3 +#define MII_PROT(port, prot) (((prot) & 0xf) << ((port) << 2)) + +#define IMX95_CFG_LINK_PCS_PROT(a) (0x8 + (a) * 4) +#define PCS_PROT_1G_SGMII BIT(0) +#define PCS_PROT_2500M_SGMII BIT(1) +#define PCS_PROT_XFI BIT(3) +#define PCS_PROT_SFI BIT(4) +#define PCS_PROT_10G_SXGMII BIT(6) + +/* NETC privileged register block register */ +#define PRB_NETCRR 0x100 +#define NETCRR_SR BIT(0) +#define NETCRR_LOCK BIT(1) + +#define PRB_NETCSR 0x104 +#define NETCSR_ERROR BIT(0) +#define NETCSR_STATE BIT(1) + +/* NETC integrated endpoint register block register */ +#define IERB_EMDIOFAUXR 0x344 +#define IERB_T0FAUXR 0x444 +#define IERB_EFAUXR(a) (0x3044 + 0x100 * (a)) +#define IERB_VFAUXR(a) (0x4004 + 0x40 * (a)) +#define FAUXR_LDID GENMASK(3, 0) + +/* Platform information */ +#define IMX95_ENETC0_BUS_DEVFN 0x0 +#define IMX95_ENETC1_BUS_DEVFN 0x40 +#define IMX95_ENETC2_BUS_DEVFN 0x80 + +/* Flags for different platforms */ +#define NETC_HAS_NETCMIX BIT(0) + +struct netc_devinfo { + u32 flags; + int (*netcmix_init)(struct platform_device *pdev); + int (*ierb_init)(struct platform_device *pdev); +}; + +struct netc_blk_ctrl { + void __iomem *prb; + void __iomem *ierb; + void __iomem *netcmix; + + const struct netc_devinfo *devinfo; + struct platform_device *pdev; + struct dentry *debugfs_root; +}; + +static void netc_reg_write(void __iomem *base, u32 offset, u32 val) +{ + netc_write(base + offset, val); +} + +static u32 netc_reg_read(void __iomem *base, u32 offset) +{ + return netc_read(base + offset); +} + +static int netc_of_pci_get_bus_devfn(struct device_node *np) +{ + u32 reg[5]; + int error; + + error = of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg)); + if (error) + return error; + + return (reg[0] >> 8) & 0xffff; +} + +static int netc_get_link_mii_protocol(phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_MII: + return MII_PROT_MII; + case PHY_INTERFACE_MODE_RMII: + return MII_PROT_RMII; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + return MII_PROT_RGMII; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_XGMII: + case PHY_INTERFACE_MODE_USXGMII: + return MII_PROT_SERIAL; + default: + return -EINVAL; + } +} + +static int imx95_netcmix_init(struct platform_device *pdev) +{ + struct netc_blk_ctrl *priv = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; + phy_interface_t interface; + int bus_devfn, mii_proto; + u32 val; + int err; + + /* Default setting of MII protocol */ + val = MII_PROT(0, MII_PROT_RGMII) | MII_PROT(1, MII_PROT_RGMII) | + MII_PROT(2, MII_PROT_SERIAL); + + /* Update the link MII protocol through parsing phy-mode */ + for_each_available_child_of_node_scoped(np, child) { + for_each_available_child_of_node_scoped(child, gchild) { + if (!of_device_is_compatible(gchild, "pci1131,e101")) + continue; + + bus_devfn = netc_of_pci_get_bus_devfn(gchild); + if (bus_devfn < 0) + return -EINVAL; + + if (bus_devfn == IMX95_ENETC2_BUS_DEVFN) + continue; + + err = of_get_phy_mode(gchild, &interface); + if (err) + continue; + + mii_proto = netc_get_link_mii_protocol(interface); + if (mii_proto < 0) + return -EINVAL; + + switch (bus_devfn) { + case IMX95_ENETC0_BUS_DEVFN: + val = u32_replace_bits(val, mii_proto, + CFG_LINK_MII_PORT_0); + break; + case IMX95_ENETC1_BUS_DEVFN: + val = u32_replace_bits(val, mii_proto, + CFG_LINK_MII_PORT_1); + break; + default: + return -EINVAL; + } + } + } + + /* Configure Link I/O variant */ + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_IO_VAR, + IO_VAR(2, IO_VAR_16FF_16G_SERDES)); + /* Configure Link 2 PCS protocol */ + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_PCS_PROT(2), + PCS_PROT_10G_SXGMII); + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_MII_PROT, val); + + return 0; +} + +static bool netc_ierb_is_locked(struct netc_blk_ctrl *priv) +{ + return !!(netc_reg_read(priv->prb, PRB_NETCRR) & NETCRR_LOCK); +} + +static int netc_lock_ierb(struct netc_blk_ctrl *priv) +{ + u32 val; + + netc_reg_write(priv->prb, PRB_NETCRR, NETCRR_LOCK); + + return read_poll_timeout(netc_reg_read, val, !(val & NETCSR_STATE), + 100, 2000, false, priv->prb, PRB_NETCSR); +} + +static int netc_unlock_ierb_with_warm_reset(struct netc_blk_ctrl *priv) +{ + u32 val; + + netc_reg_write(priv->prb, PRB_NETCRR, 0); + + return read_poll_timeout(netc_reg_read, val, !(val & NETCRR_LOCK), + 1000, 100000, true, priv->prb, PRB_NETCRR); +} + +static int imx95_ierb_init(struct platform_device *pdev) +{ + struct netc_blk_ctrl *priv = platform_get_drvdata(pdev); + + /* EMDIO : No MSI-X intterupt */ + netc_reg_write(priv->ierb, IERB_EMDIOFAUXR, 0); + /* ENETC0 PF */ + netc_reg_write(priv->ierb, IERB_EFAUXR(0), 0); + /* ENETC0 VF0 */ + netc_reg_write(priv->ierb, IERB_VFAUXR(0), 1); + /* ENETC0 VF1 */ + netc_reg_write(priv->ierb, IERB_VFAUXR(1), 2); + /* ENETC1 PF */ + netc_reg_write(priv->ierb, IERB_EFAUXR(1), 3); + /* ENETC1 VF0 */ + netc_reg_write(priv->ierb, IERB_VFAUXR(2), 5); + /* ENETC1 VF1 */ + netc_reg_write(priv->ierb, IERB_VFAUXR(3), 6); + /* ENETC2 PF */ + netc_reg_write(priv->ierb, IERB_EFAUXR(2), 4); + /* ENETC2 VF0 */ + netc_reg_write(priv->ierb, IERB_VFAUXR(4), 5); + /* ENETC2 VF1 */ + netc_reg_write(priv->ierb, IERB_VFAUXR(5), 6); + /* NETC TIMER */ + netc_reg_write(priv->ierb, IERB_T0FAUXR, 7); + + return 0; +} + +static int netc_ierb_init(struct platform_device *pdev) +{ + struct netc_blk_ctrl *priv = platform_get_drvdata(pdev); + const struct netc_devinfo *devinfo = priv->devinfo; + int err; + + if (netc_ierb_is_locked(priv)) { + err = netc_unlock_ierb_with_warm_reset(priv); + if (err) { + dev_err(&pdev->dev, "Unlock IERB failed.\n"); + return err; + } + } + + if (devinfo->ierb_init) { + err = devinfo->ierb_init(pdev); + if (err) + return err; + } + + err = netc_lock_ierb(priv); + if (err) { + dev_err(&pdev->dev, "Lock IERB failed.\n"); + return err; + } + + return 0; +} + +#if IS_ENABLED(CONFIG_DEBUG_FS) +static int netc_prb_show(struct seq_file *s, void *data) +{ + struct netc_blk_ctrl *priv = s->private; + u32 val; + + val = netc_reg_read(priv->prb, PRB_NETCRR); + seq_printf(s, "[PRB NETCRR] Lock:%d SR:%d\n", + (val & NETCRR_LOCK) ? 1 : 0, + (val & NETCRR_SR) ? 1 : 0); + + val = netc_reg_read(priv->prb, PRB_NETCSR); + seq_printf(s, "[PRB NETCSR] State:%d Error:%d\n", + (val & NETCSR_STATE) ? 1 : 0, + (val & NETCSR_ERROR) ? 1 : 0); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(netc_prb); + +static void netc_blk_ctrl_create_debugfs(struct netc_blk_ctrl *priv) +{ + struct dentry *root; + + root = debugfs_create_dir("netc_blk_ctrl", NULL); + if (IS_ERR(root)) + return; + + priv->debugfs_root = root; + + debugfs_create_file("prb", 0444, root, priv, &netc_prb_fops); +} + +static void netc_blk_ctrl_remove_debugfs(struct netc_blk_ctrl *priv) +{ + debugfs_remove_recursive(priv->debugfs_root); + priv->debugfs_root = NULL; +} + +#else + +static void netc_blk_ctrl_create_debugfs(struct netc_blk_ctrl *priv) +{ +} + +static void netc_blk_ctrl_remove_debugfs(struct netc_blk_ctrl *priv) +{ +} +#endif + +static int netc_prb_check_error(struct netc_blk_ctrl *priv) +{ + if (netc_reg_read(priv->prb, PRB_NETCSR) & NETCSR_ERROR) + return -1; + + return 0; +} + +static const struct netc_devinfo imx95_devinfo = { + .flags = NETC_HAS_NETCMIX, + .netcmix_init = imx95_netcmix_init, + .ierb_init = imx95_ierb_init, +}; + +static const struct of_device_id netc_blk_ctrl_match[] = { + { .compatible = "nxp,imx95-netc-blk-ctrl", .data = &imx95_devinfo }, + {}, +}; +MODULE_DEVICE_TABLE(of, netc_blk_ctrl_match); + +static int netc_blk_ctrl_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + const struct netc_devinfo *devinfo; + struct device *dev = &pdev->dev; + const struct of_device_id *id; + struct netc_blk_ctrl *priv; + struct clk *ipg_clk; + void __iomem *regs; + int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdev = pdev; + ipg_clk = devm_clk_get_optional_enabled(dev, "ipg"); + if (IS_ERR(ipg_clk)) + return dev_err_probe(dev, PTR_ERR(ipg_clk), + "Set ipg clock failed\n"); + + id = of_match_device(netc_blk_ctrl_match, dev); + if (!id) + return dev_err_probe(dev, -EINVAL, "Cannot match device\n"); + + devinfo = (struct netc_devinfo *)id->data; + if (!devinfo) + return dev_err_probe(dev, -EINVAL, "No device information\n"); + + priv->devinfo = devinfo; + regs = devm_platform_ioremap_resource_byname(pdev, "ierb"); + if (IS_ERR(regs)) + return dev_err_probe(dev, PTR_ERR(regs), + "Missing IERB resource\n"); + + priv->ierb = regs; + regs = devm_platform_ioremap_resource_byname(pdev, "prb"); + if (IS_ERR(regs)) + return dev_err_probe(dev, PTR_ERR(regs), + "Missing PRB resource\n"); + + priv->prb = regs; + if (devinfo->flags & NETC_HAS_NETCMIX) { + regs = devm_platform_ioremap_resource_byname(pdev, "netcmix"); + if (IS_ERR(regs)) + return dev_err_probe(dev, PTR_ERR(regs), + "Missing NETCMIX resource\n"); + priv->netcmix = regs; + } + + platform_set_drvdata(pdev, priv); + if (devinfo->netcmix_init) { + err = devinfo->netcmix_init(pdev); + if (err) + return dev_err_probe(dev, err, + "Initializing NETCMIX failed\n"); + } + + err = netc_ierb_init(pdev); + if (err) + return dev_err_probe(dev, err, "Initializing IERB failed\n"); + + if (netc_prb_check_error(priv) < 0) + dev_warn(dev, "The current IERB configuration is invalid\n"); + + netc_blk_ctrl_create_debugfs(priv); + + err = of_platform_populate(node, NULL, NULL, dev); + if (err) { + netc_blk_ctrl_remove_debugfs(priv); + return dev_err_probe(dev, err, "of_platform_populate failed\n"); + } + + return 0; +} + +static void netc_blk_ctrl_remove(struct platform_device *pdev) +{ + struct netc_blk_ctrl *priv = platform_get_drvdata(pdev); + + of_platform_depopulate(&pdev->dev); + netc_blk_ctrl_remove_debugfs(priv); +} + +static struct platform_driver netc_blk_ctrl_driver = { + .driver = { + .name = "nxp-netc-blk-ctrl", + .of_match_table = netc_blk_ctrl_match, + }, + .probe = netc_blk_ctrl_probe, + .remove = netc_blk_ctrl_remove, +}; + +module_platform_driver(netc_blk_ctrl_driver); + +MODULE_DESCRIPTION("NXP NETC Blocks Control Driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 9d9fcec41488e3..1b55047c0237cb 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -4766,7 +4766,7 @@ static struct platform_driver fec_driver = { }, .id_table = fec_devtype, .probe = fec_probe, - .remove_new = fec_drv_remove, + .remove = fec_drv_remove, }; module_platform_driver(fec_driver); diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c index ebae71ec26c6eb..2bfaf14f65c8df 100644 --- a/drivers/net/ethernet/freescale/fec_mpc52xx.c +++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c @@ -1040,7 +1040,7 @@ static struct platform_driver mpc52xx_fec_driver = { .of_match_table = mpc52xx_fec_match, }, .probe = mpc52xx_fec_probe, - .remove_new = mpc52xx_fec_remove, + .remove = mpc52xx_fec_remove, #ifdef CONFIG_PM .suspend = mpc52xx_fec_of_suspend, .resume = mpc52xx_fec_of_resume, diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c b/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c index 39689826cc8ffc..3d073f0fae6302 100644 --- a/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c +++ b/drivers/net/ethernet/freescale/fec_mpc52xx_phy.c @@ -94,7 +94,7 @@ static int mpc52xx_fec_mdio_probe(struct platform_device *of) goto out_free; } - snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); + snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res.start); bus->priv = priv; bus->parent = dev; @@ -144,7 +144,7 @@ struct platform_driver mpc52xx_fec_mdio_driver = { .of_match_table = mpc52xx_fec_mdio_match, }, .probe = mpc52xx_fec_mdio_probe, - .remove_new = mpc52xx_fec_mdio_remove, + .remove = mpc52xx_fec_mdio_remove, }; /* let fec driver call it, since this has to be registered before it */ diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index a4eb6edb850add..7f6b5743207166 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -84,8 +84,7 @@ #define FEC_CC_MULT (1 << 31) #define FEC_COUNTER_PERIOD (1 << 31) #define PPS_OUPUT_RELOAD_PERIOD NSEC_PER_SEC -#define FEC_CHANNLE_0 0 -#define DEFAULT_PPS_CHANNEL FEC_CHANNLE_0 +#define DEFAULT_PPS_CHANNEL 0 #define FEC_PTP_MAX_NSEC_PERIOD 4000000000ULL #define FEC_PTP_MAX_NSEC_COUNTER 0x80000000ULL @@ -525,7 +524,6 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp, int ret = 0; if (rq->type == PTP_CLK_REQ_PPS) { - fep->pps_channel = DEFAULT_PPS_CHANNEL; fep->reload_period = PPS_OUPUT_RELOAD_PERIOD; ret = fec_ptp_enable_pps(fep, on); @@ -536,10 +534,9 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp, if (rq->perout.flags) return -EOPNOTSUPP; - if (rq->perout.index != DEFAULT_PPS_CHANNEL) + if (rq->perout.index != fep->pps_channel) return -EOPNOTSUPP; - fep->pps_channel = DEFAULT_PPS_CHANNEL; period.tv_sec = rq->perout.period.sec; period.tv_nsec = rq->perout.period.nsec; period_ns = timespec64_to_ns(&period); @@ -707,12 +704,16 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx) { struct net_device *ndev = platform_get_drvdata(pdev); struct fec_enet_private *fep = netdev_priv(ndev); + struct device_node *np = fep->pdev->dev.of_node; int irq; int ret; fep->ptp_caps.owner = THIS_MODULE; strscpy(fep->ptp_caps.name, "fec ptp", sizeof(fep->ptp_caps.name)); + fep->pps_channel = DEFAULT_PPS_CHANNEL; + of_property_read_u32(np, "fsl,pps-channel", &fep->pps_channel); + fep->ptp_caps.max_adj = 250000000; fep->ptp_caps.n_alarm = 0; fep->ptp_caps.n_ext_ts = 0; diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index d96028f01770cf..fb416d60dcd727 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -24,7 +24,6 @@ /* General defines */ #define FMAN_LIODN_TBL 64 /* size of LIODN table */ -#define MAX_NUM_OF_MACS 10 #define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 #define BASE_RX_PORTID 0x08 #define BASE_TX_PORTID 0x28 diff --git a/drivers/net/ethernet/freescale/fman/fman.h b/drivers/net/ethernet/freescale/fman/fman.h index 2ea575a46675b0..74eb62eba0d7ff 100644 --- a/drivers/net/ethernet/freescale/fman/fman.h +++ b/drivers/net/ethernet/freescale/fman/fman.h @@ -74,6 +74,9 @@ #define BM_MAX_NUM_OF_POOLS 64 /* Buffers pools */ #define FMAN_PORT_MAX_EXT_POOLS_NUM 8 /* External BM pools per Rx port */ +/* General defines */ +#define MAX_NUM_OF_MACS 10 + struct fman; /* FMan data */ /* Enum for defining port types */ diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c index 3088da7adf0f84..85617bb94959f3 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@ -1415,7 +1415,6 @@ int dtsec_initialization(struct mac_device *mac_dev, mac_dev->set_exception = dtsec_set_exception; mac_dev->set_allmulti = dtsec_set_allmulti; mac_dev->set_tstamp = dtsec_set_tstamp; - mac_dev->set_multi = fman_set_multi; mac_dev->enable = dtsec_enable; mac_dev->disable = dtsec_disable; diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 796e6f4e583d18..3925441143fac9 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -1087,7 +1087,6 @@ int memac_initialization(struct mac_device *mac_dev, mac_dev->set_exception = memac_set_exception; mac_dev->set_allmulti = memac_set_allmulti; mac_dev->set_tstamp = memac_set_tstamp; - mac_dev->set_multi = fman_set_multi; mac_dev->enable = memac_enable; mac_dev->disable = memac_disable; diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c index f17a4e51151017..e977389f70889f 100644 --- a/drivers/net/ethernet/freescale/fman/fman_port.c +++ b/drivers/net/ethernet/freescale/fman/fman_port.c @@ -987,7 +987,7 @@ static int init_low_level_driver(struct fman_port *port) return -ENODEV; } - /* The code bellow is a trick so the FM will not release the buffer + /* The code below is a trick so the FM will not release the buffer * to BM nor will try to enqueue the frame to QM */ if (port->port_type == FMAN_PORT_TYPE_TX) { diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.c b/drivers/net/ethernet/freescale/fman/fman_tgec.c index c2261d26db5b93..fecfca6eba03e5 100644 --- a/drivers/net/ethernet/freescale/fman/fman_tgec.c +++ b/drivers/net/ethernet/freescale/fman/fman_tgec.c @@ -771,7 +771,6 @@ int tgec_initialization(struct mac_device *mac_dev, mac_dev->set_exception = tgec_set_exception; mac_dev->set_allmulti = tgec_set_allmulti; mac_dev->set_tstamp = tgec_set_tstamp; - mac_dev->set_multi = fman_set_multi; mac_dev->enable = tgec_enable; mac_dev->disable = tgec_disable; diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c index 11da139082e1bf..a39fcea6a77a0f 100644 --- a/drivers/net/ethernet/freescale/fman/mac.c +++ b/drivers/net/ethernet/freescale/fman/mac.c @@ -32,8 +32,6 @@ MODULE_DESCRIPTION("FSL FMan MAC API based driver"); struct mac_priv_s { u8 cell_index; struct fman *fman; - /* List of multicast addresses */ - struct list_head mc_addr_list; struct platform_device *eth_dev; u16 speed; }; @@ -57,44 +55,6 @@ static void mac_exception(struct mac_device *mac_dev, __func__, ex); } -int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev) -{ - struct mac_priv_s *priv; - struct mac_address *old_addr, *tmp; - struct netdev_hw_addr *ha; - int err; - enet_addr_t *addr; - - priv = mac_dev->priv; - - /* Clear previous address list */ - list_for_each_entry_safe(old_addr, tmp, &priv->mc_addr_list, list) { - addr = (enet_addr_t *)old_addr->addr; - err = mac_dev->remove_hash_mac_addr(mac_dev->fman_mac, addr); - if (err < 0) - return err; - - list_del(&old_addr->list); - kfree(old_addr); - } - - /* Add all the addresses from the new list */ - netdev_for_each_mc_addr(ha, net_dev) { - addr = (enet_addr_t *)ha->addr; - err = mac_dev->add_hash_mac_addr(mac_dev->fman_mac, addr); - if (err < 0) - return err; - - tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC); - if (!tmp) - return -ENOMEM; - - ether_addr_copy(tmp->addr, ha->addr); - list_add(&tmp->list, &priv->mc_addr_list); - } - return 0; -} - static DEFINE_MUTEX(eth_lock); static struct platform_device *dpaa_eth_add_device(int fman_id, @@ -181,8 +141,6 @@ static int mac_probe(struct platform_device *_of_dev) mac_dev->priv = priv; mac_dev->dev = dev; - INIT_LIST_HEAD(&priv->mc_addr_list); - /* Get the FM node */ dev_node = of_get_parent(mac_node); if (!dev_node) { @@ -259,6 +217,11 @@ static int mac_probe(struct platform_device *_of_dev) err = -EINVAL; goto _return_dev_put; } + if (val >= MAX_NUM_OF_MACS) { + dev_err(dev, "cell-index value is too big for %pOF\n", mac_node); + err = -EINVAL; + goto _return_dev_put; + } priv->cell_index = (u8)val; /* Get the MAC address */ @@ -379,7 +342,7 @@ static struct platform_driver mac_driver = { .of_match_table = mac_match, }, .probe = mac_probe, - .remove_new = mac_remove, + .remove = mac_remove, }; builtin_platform_driver(mac_driver); diff --git a/drivers/net/ethernet/freescale/fman/mac.h b/drivers/net/ethernet/freescale/fman/mac.h index 8b5b43d50f8efb..955ace338965a7 100644 --- a/drivers/net/ethernet/freescale/fman/mac.h +++ b/drivers/net/ethernet/freescale/fman/mac.h @@ -40,8 +40,6 @@ struct mac_device { int (*change_addr)(struct fman_mac *mac_dev, const enet_addr_t *enet_addr); int (*set_allmulti)(struct fman_mac *mac_dev, bool enable); int (*set_tstamp)(struct fman_mac *mac_dev, bool enable); - int (*set_multi)(struct net_device *net_dev, - struct mac_device *mac_dev); int (*set_exception)(struct fman_mac *mac_dev, enum fman_mac_exceptions exception, bool enable); int (*add_hash_mac_addr)(struct fman_mac *mac_dev, diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index 3425c4a6abcbdb..f563692a4a00c4 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -1052,7 +1052,7 @@ static struct platform_driver fs_enet_driver = { .of_match_table = fs_enet_match, }, .probe = fs_enet_probe, - .remove_new = fs_enet_remove, + .remove = fs_enet_remove, }; #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c index 2e210a00355843..66038e2a4ae3ac 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c +++ b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c @@ -123,7 +123,7 @@ static int fs_mii_bitbang_init(struct mii_bus *bus, struct device_node *np) * we get is an int, and the odds of multiple bitbang mdio buses * is low enough that it's not worth going too crazy. */ - snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); + snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res.start); data = of_get_property(np, "fsl,mdio-pin", &len); if (!data || len != 4) @@ -214,7 +214,7 @@ static struct platform_driver fs_enet_bb_mdio_driver = { .of_match_table = fs_enet_mdio_bb_match, }, .probe = fs_enet_mdio_probe, - .remove_new = fs_enet_mdio_remove, + .remove = fs_enet_mdio_remove, }; module_platform_driver(fs_enet_bb_mdio_driver); diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c index 93d91e8ad0de53..dec31b638941ce 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c @@ -212,7 +212,7 @@ static struct platform_driver fs_enet_fec_mdio_driver = { .of_match_table = fs_enet_mdio_fec_match, }, .probe = fs_enet_mdio_probe, - .remove_new = fs_enet_mdio_remove, + .remove = fs_enet_mdio_remove, }; module_platform_driver(fs_enet_fec_mdio_driver); diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 026f7270a54de8..56d2f79fb7e329 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -526,7 +526,7 @@ static struct platform_driver fsl_pq_mdio_driver = { .of_match_table = fsl_pq_mdio_match, }, .probe = fsl_pq_mdio_probe, - .remove_new = fsl_pq_mdio_remove, + .remove = fsl_pq_mdio_remove, }; module_platform_driver(fsl_pq_mdio_driver); diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index ecb1703ea150fe..435138f4699d2c 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2207,8 +2207,9 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) if (unlikely(do_tstamp)) { struct skb_shared_hwtstamps shhwtstamps; - u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) & - ~0x7UL); + __be64 *ns; + + ns = (__be64 *)(((uintptr_t)skb->data + 0x10) & ~0x7UL); memset(&shhwtstamps, 0, sizeof(shhwtstamps)); shhwtstamps.hwtstamp = ns_to_ktime(be64_to_cpu(*ns)); @@ -2471,7 +2472,7 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) /* Get receive timestamp from the skb */ if (priv->hwts_rx_en) { struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); - u64 *ns = (u64 *) skb->data; + __be64 *ns = (__be64 *)skb->data; memset(shhwtstamps, 0, sizeof(*shhwtstamps)); shhwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(*ns)); @@ -3642,7 +3643,7 @@ static struct platform_driver gfar_driver = { .of_match_table = gfar_match, }, .probe = gfar_probe, - .remove_new = gfar_remove, + .remove = gfar_remove, }; module_platform_driver(gfar_driver); diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index a99b95c4bcfbc5..781d92e703cb3d 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -115,12 +115,14 @@ static const char stat_gstrings[][ETH_GSTRING_LEN] = { static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf) { struct gfar_private *priv = netdev_priv(dev); + int i; if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) - memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN); + for (i = 0; i < GFAR_STATS_LEN; i++) + ethtool_puts(&buf, stat_gstrings[i]); else - memcpy(buf, stat_gstrings, - GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN); + for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) + ethtool_puts(&buf, stat_gstrings[i]); } /* Fill in an array of 64-bit statistics from various sources. diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index ab421243a4192f..6663c176808928 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -3591,22 +3591,23 @@ static int ucc_geth_probe(struct platform_device* ofdev) if ((ucc_num < 0) || (ucc_num > 7)) return -ENODEV; - ug_info = kmemdup(&ugeth_primary_info, sizeof(*ug_info), GFP_KERNEL); - if (ug_info == NULL) + ug_info = devm_kmemdup(&ofdev->dev, &ugeth_primary_info, + sizeof(*ug_info), GFP_KERNEL); + if (!ug_info) return -ENOMEM; ug_info->uf_info.ucc_num = ucc_num; err = ucc_geth_parse_clock(np, "rx", &ug_info->uf_info.rx_clock); if (err) - goto err_free_info; + return err; err = ucc_geth_parse_clock(np, "tx", &ug_info->uf_info.tx_clock); if (err) - goto err_free_info; + return err; err = of_address_to_resource(np, 0, &res); if (err) - goto err_free_info; + return err; ug_info->uf_info.regs = res.start; ug_info->uf_info.irq = irq_of_parse_and_map(np, 0); @@ -3619,7 +3620,7 @@ static int ucc_geth_probe(struct platform_device* ofdev) */ err = of_phy_register_fixed_link(np); if (err) - goto err_free_info; + return err; ug_info->phy_node = of_node_get(np); } @@ -3687,9 +3688,8 @@ static int ucc_geth_probe(struct platform_device* ofdev) ug_info->uf_info.irq); /* Create an ethernet device instance */ - dev = alloc_etherdev(sizeof(*ugeth)); - - if (dev == NULL) { + dev = devm_alloc_etherdev(&ofdev->dev, sizeof(*ugeth)); + if (!dev) { err = -ENOMEM; goto err_deregister_fixed_link; } @@ -3724,15 +3724,17 @@ static int ucc_geth_probe(struct platform_device* ofdev) /* Carrier starts down, phylib will bring it up */ netif_carrier_off(dev); - err = register_netdev(dev); + err = devm_register_netdev(&ofdev->dev, dev); if (err) { if (netif_msg_probe(ugeth)) pr_err("%s: Cannot register net device, aborting\n", dev->name); - goto err_free_netdev; + goto err_deregister_fixed_link; } - of_get_ethdev_address(np, dev); + err = of_get_ethdev_address(np, dev); + if (err == -EPROBE_DEFER) + goto err_deregister_fixed_link; ugeth->ug_info = ug_info; ugeth->dev = device; @@ -3741,16 +3743,11 @@ static int ucc_geth_probe(struct platform_device* ofdev) return 0; -err_free_netdev: - free_netdev(dev); err_deregister_fixed_link: if (of_phy_is_fixed_link(np)) of_phy_deregister_fixed_link(np); of_node_put(ug_info->tbi_node); of_node_put(ug_info->phy_node); -err_free_info: - kfree(ug_info); - return err; } @@ -3760,14 +3757,11 @@ static void ucc_geth_remove(struct platform_device* ofdev) struct ucc_geth_private *ugeth = netdev_priv(dev); struct device_node *np = ofdev->dev.of_node; - unregister_netdev(dev); ucc_geth_memclean(ugeth); if (of_phy_is_fixed_link(np)) of_phy_deregister_fixed_link(np); of_node_put(ugeth->ug_info->tbi_node); of_node_put(ugeth->ug_info->phy_node); - kfree(ugeth->ug_info); - free_netdev(dev); } static const struct of_device_id ucc_geth_match[] = { @@ -3786,7 +3780,7 @@ static struct platform_driver ucc_geth_driver = { .of_match_table = ucc_geth_match, }, .probe = ucc_geth_probe, - .remove_new = ucc_geth_remove, + .remove = ucc_geth_remove, .suspend = ucc_geth_suspend, .resume = ucc_geth_resume, }; diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c index 601beb93d3b3bc..699f346faf5cd7 100644 --- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c +++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c @@ -287,20 +287,17 @@ static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) { struct ucc_geth_private *ugeth = netdev_priv(netdev); u32 stats_mode = ugeth->ug_info->statisticsMode; + int i; - if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) { - memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN * - ETH_GSTRING_LEN); - buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN; - } - if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) { - memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN * - ETH_GSTRING_LEN); - buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN; - } + if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) + for (i = 0; i < UEC_HW_STATS_LEN; i++) + ethtool_puts(&buf, hw_stat_gstrings[i]); + if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) + for (i = 0; i < UEC_TX_FW_STATS_LEN; i++) + ethtool_puts(&buf, tx_fw_stat_gstrings[i]); if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) - memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN * - ETH_GSTRING_LEN); + for (i = 0; i < UEC_RX_FW_STATS_LEN; i++) + ethtool_puts(&buf, rx_fw_stat_gstrings[i]); } static void uec_get_ethtool_stats(struct net_device *netdev, diff --git a/drivers/net/ethernet/fungible/funcore/fun_queue.c b/drivers/net/ethernet/fungible/funcore/fun_queue.c index 8ab9f68434f5ae..d07ee3e4f52ade 100644 --- a/drivers/net/ethernet/fungible/funcore/fun_queue.c +++ b/drivers/net/ethernet/fungible/funcore/fun_queue.c @@ -482,43 +482,6 @@ struct fun_queue *fun_alloc_queue(struct fun_dev *fdev, int qid, return NULL; } -/* Create a funq's CQ on the device. */ -static int fun_create_cq(struct fun_queue *funq) -{ - struct fun_dev *fdev = funq->fdev; - unsigned int rqid; - int rc; - - rqid = funq->cq_flags & FUN_ADMIN_EPCQ_CREATE_FLAG_RQ ? - funq->rqid : FUN_HCI_ID_INVALID; - rc = fun_cq_create(fdev, funq->cq_flags, funq->cqid, rqid, - funq->cqe_size_log2, funq->cq_depth, - funq->cq_dma_addr, 0, 0, funq->cq_intcoal_nentries, - funq->cq_intcoal_usec, funq->cq_vector, 0, 0, - &funq->cqid, &funq->cq_db); - if (!rc) - dev_dbg(fdev->dev, "created CQ %u\n", funq->cqid); - - return rc; -} - -/* Create a funq's SQ on the device. */ -static int fun_create_sq(struct fun_queue *funq) -{ - struct fun_dev *fdev = funq->fdev; - int rc; - - rc = fun_sq_create(fdev, funq->sq_flags, funq->sqid, funq->cqid, - funq->sqe_size_log2, funq->sq_depth, - funq->sq_dma_addr, funq->sq_intcoal_nentries, - funq->sq_intcoal_usec, funq->cq_vector, 0, 0, - 0, &funq->sqid, &funq->sq_db); - if (!rc) - dev_dbg(fdev->dev, "created SQ %u\n", funq->sqid); - - return rc; -} - /* Create a funq's RQ on the device. */ int fun_create_rq(struct fun_queue *funq) { @@ -561,34 +524,6 @@ int fun_request_irq(struct fun_queue *funq, const char *devname, return rc; } -/* Create all component queues of a funq on the device. */ -int fun_create_queue(struct fun_queue *funq) -{ - int rc; - - rc = fun_create_cq(funq); - if (rc) - return rc; - - if (funq->rq_depth) { - rc = fun_create_rq(funq); - if (rc) - goto release_cq; - } - - rc = fun_create_sq(funq); - if (rc) - goto release_rq; - - return 0; - -release_rq: - fun_destroy_sq(funq->fdev, funq->rqid); -release_cq: - fun_destroy_cq(funq->fdev, funq->cqid); - return rc; -} - void fun_free_irq(struct fun_queue *funq) { if (funq->irq_handler) { diff --git a/drivers/net/ethernet/fungible/funcore/fun_queue.h b/drivers/net/ethernet/fungible/funcore/fun_queue.h index 7fb53d0ae8b000..2d966afb187ad7 100644 --- a/drivers/net/ethernet/fungible/funcore/fun_queue.h +++ b/drivers/net/ethernet/fungible/funcore/fun_queue.h @@ -163,7 +163,6 @@ static inline void fun_set_cq_callback(struct fun_queue *funq, cq_callback_t cb, } int fun_create_rq(struct fun_queue *funq); -int fun_create_queue(struct fun_queue *funq); void fun_free_irq(struct fun_queue *funq); int fun_request_irq(struct fun_queue *funq, const char *devname, diff --git a/drivers/net/ethernet/google/Kconfig b/drivers/net/ethernet/google/Kconfig index 8641a00f8e6385..564862a57124e2 100644 --- a/drivers/net/ethernet/google/Kconfig +++ b/drivers/net/ethernet/google/Kconfig @@ -18,6 +18,7 @@ if NET_VENDOR_GOOGLE config GVE tristate "Google Virtual NIC (gVNIC) support" depends on (PCI_MSI && (X86 || CPU_LITTLE_ENDIAN)) + select PAGE_POOL help This driver supports Google Virtual NIC (gVNIC)" diff --git a/drivers/net/ethernet/google/gve/Makefile b/drivers/net/ethernet/google/gve/Makefile index 9ed07080b38a25..4520f1c07a638f 100644 --- a/drivers/net/ethernet/google/gve/Makefile +++ b/drivers/net/ethernet/google/gve/Makefile @@ -1,4 +1,5 @@ # Makefile for the Google virtual Ethernet (gve) driver obj-$(CONFIG_GVE) += gve.o -gve-objs := gve_main.o gve_tx.o gve_tx_dqo.o gve_rx.o gve_rx_dqo.o gve_ethtool.o gve_adminq.o gve_utils.o gve_flow_rule.o +gve-objs := gve_main.o gve_tx.o gve_tx_dqo.o gve_rx.o gve_rx_dqo.o gve_ethtool.o gve_adminq.o gve_utils.o gve_flow_rule.o \ + gve_buffer_mgmt_dqo.o diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index 301fa1ea4f5167..dd92949bb2149a 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "gve_desc.h" @@ -60,6 +61,8 @@ #define GVE_DEFAULT_RX_BUFFER_OFFSET 2048 +#define GVE_PAGE_POOL_SIZE_MULTIPLIER 4 + #define GVE_FLOW_RULES_CACHE_SIZE \ (GVE_ADMINQ_BUFFER_SIZE / sizeof(struct gve_adminq_queried_flow_rule)) #define GVE_FLOW_RULE_IDS_CACHE_SIZE \ @@ -102,6 +105,7 @@ struct gve_rx_slot_page_info { struct page *page; void *page_address; u32 page_offset; /* offset to write to in page */ + unsigned int buf_size; int pagecnt_bias; /* expected pagecnt if only the driver has a ref */ u16 pad; /* adjustment for rx padding */ u8 can_flip; /* tracks if the networking stack is using the page */ @@ -273,6 +277,8 @@ struct gve_rx_ring { /* Address info of the buffers for header-split */ struct gve_header_buf hdr_bufs; + + struct page_pool *page_pool; } dqo; }; @@ -1162,6 +1168,36 @@ void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx); u16 gve_get_pkt_buf_size(const struct gve_priv *priv, bool enable_hplit); bool gve_header_split_supported(const struct gve_priv *priv); int gve_set_hsplit_config(struct gve_priv *priv, u8 tcp_data_split); +/* rx buffer handling */ +int gve_buf_ref_cnt(struct gve_rx_buf_state_dqo *bs); +void gve_free_page_dqo(struct gve_priv *priv, struct gve_rx_buf_state_dqo *bs, + bool free_page); +struct gve_rx_buf_state_dqo *gve_alloc_buf_state(struct gve_rx_ring *rx); +bool gve_buf_state_is_allocated(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state); +void gve_free_buf_state(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state); +struct gve_rx_buf_state_dqo *gve_dequeue_buf_state(struct gve_rx_ring *rx, + struct gve_index_list *list); +void gve_enqueue_buf_state(struct gve_rx_ring *rx, struct gve_index_list *list, + struct gve_rx_buf_state_dqo *buf_state); +struct gve_rx_buf_state_dqo *gve_get_recycled_buf_state(struct gve_rx_ring *rx); +void gve_try_recycle_buf(struct gve_priv *priv, struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state); +void gve_free_to_page_pool(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state, + bool allow_direct); +int gve_alloc_qpl_page_dqo(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state); +void gve_free_qpl_page_dqo(struct gve_rx_buf_state_dqo *buf_state); +void gve_reuse_buffer(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state); +void gve_free_buffer(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state); +int gve_alloc_buffer(struct gve_rx_ring *rx, struct gve_rx_desc_dqo *desc); +struct page_pool *gve_rx_create_page_pool(struct gve_priv *priv, + struct gve_rx_ring *rx); + /* Reset */ void gve_schedule_reset(struct gve_priv *priv); int gve_reset(struct gve_priv *priv, bool attempt_teardown); diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c index e44e8b139633fc..060e0e6749380f 100644 --- a/drivers/net/ethernet/google/gve/gve_adminq.c +++ b/drivers/net/ethernet/google/gve/gve_adminq.c @@ -1248,10 +1248,10 @@ gve_adminq_configure_flow_rule(struct gve_priv *priv, sizeof(struct gve_adminq_configure_flow_rule), flow_rule_cmd); - if (err) { + if (err == -ETIME) { dev_err(&priv->pdev->dev, "Timeout to configure the flow rule, trigger reset"); gve_reset(priv, true); - } else { + } else if (!err) { priv->flow_rules_cache.rules_cache_synced = false; } diff --git a/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c b/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c new file mode 100644 index 00000000000000..403f0f335ba669 --- /dev/null +++ b/drivers/net/ethernet/google/gve/gve_buffer_mgmt_dqo.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* Google virtual Ethernet (gve) driver + * + * Copyright (C) 2015-2024 Google, Inc. + */ + +#include "gve.h" +#include "gve_utils.h" + +int gve_buf_ref_cnt(struct gve_rx_buf_state_dqo *bs) +{ + return page_count(bs->page_info.page) - bs->page_info.pagecnt_bias; +} + +struct gve_rx_buf_state_dqo *gve_alloc_buf_state(struct gve_rx_ring *rx) +{ + struct gve_rx_buf_state_dqo *buf_state; + s16 buffer_id; + + buffer_id = rx->dqo.free_buf_states; + if (unlikely(buffer_id == -1)) + return NULL; + + buf_state = &rx->dqo.buf_states[buffer_id]; + + /* Remove buf_state from free list */ + rx->dqo.free_buf_states = buf_state->next; + + /* Point buf_state to itself to mark it as allocated */ + buf_state->next = buffer_id; + + return buf_state; +} + +bool gve_buf_state_is_allocated(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state) +{ + s16 buffer_id = buf_state - rx->dqo.buf_states; + + return buf_state->next == buffer_id; +} + +void gve_free_buf_state(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state) +{ + s16 buffer_id = buf_state - rx->dqo.buf_states; + + buf_state->next = rx->dqo.free_buf_states; + rx->dqo.free_buf_states = buffer_id; +} + +struct gve_rx_buf_state_dqo *gve_dequeue_buf_state(struct gve_rx_ring *rx, + struct gve_index_list *list) +{ + struct gve_rx_buf_state_dqo *buf_state; + s16 buffer_id; + + buffer_id = list->head; + if (unlikely(buffer_id == -1)) + return NULL; + + buf_state = &rx->dqo.buf_states[buffer_id]; + + /* Remove buf_state from list */ + list->head = buf_state->next; + if (buf_state->next == -1) + list->tail = -1; + + /* Point buf_state to itself to mark it as allocated */ + buf_state->next = buffer_id; + + return buf_state; +} + +void gve_enqueue_buf_state(struct gve_rx_ring *rx, struct gve_index_list *list, + struct gve_rx_buf_state_dqo *buf_state) +{ + s16 buffer_id = buf_state - rx->dqo.buf_states; + + buf_state->next = -1; + + if (list->head == -1) { + list->head = buffer_id; + list->tail = buffer_id; + } else { + int tail = list->tail; + + rx->dqo.buf_states[tail].next = buffer_id; + list->tail = buffer_id; + } +} + +struct gve_rx_buf_state_dqo *gve_get_recycled_buf_state(struct gve_rx_ring *rx) +{ + struct gve_rx_buf_state_dqo *buf_state; + int i; + + /* Recycled buf states are immediately usable. */ + buf_state = gve_dequeue_buf_state(rx, &rx->dqo.recycled_buf_states); + if (likely(buf_state)) + return buf_state; + + if (unlikely(rx->dqo.used_buf_states.head == -1)) + return NULL; + + /* Used buf states are only usable when ref count reaches 0, which means + * no SKBs refer to them. + * + * Search a limited number before giving up. + */ + for (i = 0; i < 5; i++) { + buf_state = gve_dequeue_buf_state(rx, &rx->dqo.used_buf_states); + if (gve_buf_ref_cnt(buf_state) == 0) { + rx->dqo.used_buf_states_cnt--; + return buf_state; + } + + gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state); + } + + return NULL; +} + +int gve_alloc_qpl_page_dqo(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state) +{ + struct gve_priv *priv = rx->gve; + u32 idx; + + idx = rx->dqo.next_qpl_page_idx; + if (idx >= gve_get_rx_pages_per_qpl_dqo(priv->rx_desc_cnt)) { + net_err_ratelimited("%s: Out of QPL pages\n", + priv->dev->name); + return -ENOMEM; + } + buf_state->page_info.page = rx->dqo.qpl->pages[idx]; + buf_state->addr = rx->dqo.qpl->page_buses[idx]; + rx->dqo.next_qpl_page_idx++; + buf_state->page_info.page_offset = 0; + buf_state->page_info.page_address = + page_address(buf_state->page_info.page); + buf_state->page_info.buf_size = priv->data_buffer_size_dqo; + buf_state->last_single_ref_offset = 0; + + /* The page already has 1 ref. */ + page_ref_add(buf_state->page_info.page, INT_MAX - 1); + buf_state->page_info.pagecnt_bias = INT_MAX; + + return 0; +} + +void gve_free_qpl_page_dqo(struct gve_rx_buf_state_dqo *buf_state) +{ + if (!buf_state->page_info.page) + return; + + page_ref_sub(buf_state->page_info.page, + buf_state->page_info.pagecnt_bias - 1); + buf_state->page_info.page = NULL; +} + +void gve_try_recycle_buf(struct gve_priv *priv, struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state) +{ + const u16 data_buffer_size = priv->data_buffer_size_dqo; + int pagecount; + + /* Can't reuse if we only fit one buffer per page */ + if (data_buffer_size * 2 > PAGE_SIZE) + goto mark_used; + + pagecount = gve_buf_ref_cnt(buf_state); + + /* Record the offset when we have a single remaining reference. + * + * When this happens, we know all of the other offsets of the page are + * usable. + */ + if (pagecount == 1) { + buf_state->last_single_ref_offset = + buf_state->page_info.page_offset; + } + + /* Use the next buffer sized chunk in the page. */ + buf_state->page_info.page_offset += data_buffer_size; + buf_state->page_info.page_offset &= (PAGE_SIZE - 1); + + /* If we wrap around to the same offset without ever dropping to 1 + * reference, then we don't know if this offset was ever freed. + */ + if (buf_state->page_info.page_offset == + buf_state->last_single_ref_offset) { + goto mark_used; + } + + gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, buf_state); + return; + +mark_used: + gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state); + rx->dqo.used_buf_states_cnt++; +} + +void gve_free_to_page_pool(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state, + bool allow_direct) +{ + struct page *page = buf_state->page_info.page; + + if (!page) + return; + + page_pool_put_full_page(page->pp, page, allow_direct); + buf_state->page_info.page = NULL; +} + +static int gve_alloc_from_page_pool(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state) +{ + struct gve_priv *priv = rx->gve; + struct page *page; + + buf_state->page_info.buf_size = priv->data_buffer_size_dqo; + page = page_pool_alloc(rx->dqo.page_pool, + &buf_state->page_info.page_offset, + &buf_state->page_info.buf_size, GFP_ATOMIC); + + if (!page) + return -ENOMEM; + + buf_state->page_info.page = page; + buf_state->page_info.page_address = page_address(page); + buf_state->addr = page_pool_get_dma_addr(page); + + return 0; +} + +struct page_pool *gve_rx_create_page_pool(struct gve_priv *priv, + struct gve_rx_ring *rx) +{ + u32 ntfy_id = gve_rx_idx_to_ntfy(priv, rx->q_num); + struct page_pool_params pp = { + .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, + .order = 0, + .pool_size = GVE_PAGE_POOL_SIZE_MULTIPLIER * priv->rx_desc_cnt, + .dev = &priv->pdev->dev, + .netdev = priv->dev, + .napi = &priv->ntfy_blocks[ntfy_id].napi, + .max_len = PAGE_SIZE, + .dma_dir = DMA_FROM_DEVICE, + }; + + return page_pool_create(&pp); +} + +void gve_free_buffer(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state) +{ + if (rx->dqo.page_pool) { + gve_free_to_page_pool(rx, buf_state, true); + gve_free_buf_state(rx, buf_state); + } else { + gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, + buf_state); + } +} + +void gve_reuse_buffer(struct gve_rx_ring *rx, + struct gve_rx_buf_state_dqo *buf_state) +{ + if (rx->dqo.page_pool) { + buf_state->page_info.page = NULL; + gve_free_buf_state(rx, buf_state); + } else { + gve_dec_pagecnt_bias(&buf_state->page_info); + gve_try_recycle_buf(rx->gve, rx, buf_state); + } +} + +int gve_alloc_buffer(struct gve_rx_ring *rx, struct gve_rx_desc_dqo *desc) +{ + struct gve_rx_buf_state_dqo *buf_state; + + if (rx->dqo.page_pool) { + buf_state = gve_alloc_buf_state(rx); + if (WARN_ON_ONCE(!buf_state)) + return -ENOMEM; + + if (gve_alloc_from_page_pool(rx, buf_state)) + goto free_buf_state; + } else { + buf_state = gve_get_recycled_buf_state(rx); + if (unlikely(!buf_state)) { + buf_state = gve_alloc_buf_state(rx); + if (unlikely(!buf_state)) + return -ENOMEM; + + if (unlikely(gve_alloc_qpl_page_dqo(rx, buf_state))) + goto free_buf_state; + } + } + desc->buf_id = cpu_to_le16(buf_state - rx->dqo.buf_states); + desc->buf_addr = cpu_to_le64(buf_state->addr + + buf_state->page_info.page_offset); + + return 0; + +free_buf_state: + gve_free_buf_state(rx, buf_state); + return -ENOMEM; +} diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 661566db68c860..e171ca248f9af6 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -1875,6 +1875,11 @@ static void gve_turndown(struct gve_priv *priv) if (!gve_tx_was_added_to_block(priv, idx)) continue; + + if (idx < priv->tx_cfg.num_queues) + netif_queue_set_napi(priv->dev, idx, + NETDEV_QUEUE_TYPE_TX, NULL); + napi_disable(&block->napi); } for (idx = 0; idx < priv->rx_cfg.num_queues; idx++) { @@ -1883,6 +1888,9 @@ static void gve_turndown(struct gve_priv *priv) if (!gve_rx_was_added_to_block(priv, idx)) continue; + + netif_queue_set_napi(priv->dev, idx, NETDEV_QUEUE_TYPE_RX, + NULL); napi_disable(&block->napi); } @@ -1909,6 +1917,12 @@ static void gve_turnup(struct gve_priv *priv) continue; napi_enable(&block->napi); + + if (idx < priv->tx_cfg.num_queues) + netif_queue_set_napi(priv->dev, idx, + NETDEV_QUEUE_TYPE_TX, + &block->napi); + if (gve_is_gqi(priv)) { iowrite32be(0, gve_irq_doorbell(priv, block)); } else { @@ -1931,6 +1945,9 @@ static void gve_turnup(struct gve_priv *priv) continue; napi_enable(&block->napi); + netif_queue_set_napi(priv->dev, idx, NETDEV_QUEUE_TYPE_RX, + &block->napi); + if (gve_is_gqi(priv)) { iowrite32be(0, gve_irq_doorbell(priv, block)); } else { @@ -2544,6 +2561,54 @@ static const struct netdev_queue_mgmt_ops gve_queue_mgmt_ops = { .ndo_queue_stop = gve_rx_queue_stop, }; +static void gve_get_rx_queue_stats(struct net_device *dev, int idx, + struct netdev_queue_stats_rx *rx_stats) +{ + struct gve_priv *priv = netdev_priv(dev); + struct gve_rx_ring *rx = &priv->rx[idx]; + unsigned int start; + + do { + start = u64_stats_fetch_begin(&rx->statss); + rx_stats->packets = rx->rpackets; + rx_stats->bytes = rx->rbytes; + rx_stats->alloc_fail = rx->rx_skb_alloc_fail + + rx->rx_buf_alloc_fail; + } while (u64_stats_fetch_retry(&rx->statss, start)); +} + +static void gve_get_tx_queue_stats(struct net_device *dev, int idx, + struct netdev_queue_stats_tx *tx_stats) +{ + struct gve_priv *priv = netdev_priv(dev); + struct gve_tx_ring *tx = &priv->tx[idx]; + unsigned int start; + + do { + start = u64_stats_fetch_begin(&tx->statss); + tx_stats->packets = tx->pkt_done; + tx_stats->bytes = tx->bytes_done; + } while (u64_stats_fetch_retry(&tx->statss, start)); +} + +static void gve_get_base_stats(struct net_device *dev, + struct netdev_queue_stats_rx *rx, + struct netdev_queue_stats_tx *tx) +{ + rx->packets = 0; + rx->bytes = 0; + rx->alloc_fail = 0; + + tx->packets = 0; + tx->bytes = 0; +} + +static const struct netdev_stat_ops gve_stat_ops = { + .get_queue_stats_rx = gve_get_rx_queue_stats, + .get_queue_stats_tx = gve_get_tx_queue_stats, + .get_base_stats = gve_get_base_stats, +}; + static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int max_tx_queues, max_rx_queues; @@ -2599,6 +2664,7 @@ static int gve_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->ethtool_ops = &gve_ethtool_ops; dev->netdev_ops = &gve_netdev_ops; dev->queue_mgmt_ops = &gve_queue_mgmt_ops; + dev->stat_ops = &gve_stat_ops; /* Set default and supported features. * diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c index 1154c1d8f66f05..8ac0047f1ada11 100644 --- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c @@ -16,189 +16,6 @@ #include #include -static int gve_buf_ref_cnt(struct gve_rx_buf_state_dqo *bs) -{ - return page_count(bs->page_info.page) - bs->page_info.pagecnt_bias; -} - -static void gve_free_page_dqo(struct gve_priv *priv, - struct gve_rx_buf_state_dqo *bs, - bool free_page) -{ - page_ref_sub(bs->page_info.page, bs->page_info.pagecnt_bias - 1); - if (free_page) - gve_free_page(&priv->pdev->dev, bs->page_info.page, bs->addr, - DMA_FROM_DEVICE); - bs->page_info.page = NULL; -} - -static struct gve_rx_buf_state_dqo *gve_alloc_buf_state(struct gve_rx_ring *rx) -{ - struct gve_rx_buf_state_dqo *buf_state; - s16 buffer_id; - - buffer_id = rx->dqo.free_buf_states; - if (unlikely(buffer_id == -1)) - return NULL; - - buf_state = &rx->dqo.buf_states[buffer_id]; - - /* Remove buf_state from free list */ - rx->dqo.free_buf_states = buf_state->next; - - /* Point buf_state to itself to mark it as allocated */ - buf_state->next = buffer_id; - - return buf_state; -} - -static bool gve_buf_state_is_allocated(struct gve_rx_ring *rx, - struct gve_rx_buf_state_dqo *buf_state) -{ - s16 buffer_id = buf_state - rx->dqo.buf_states; - - return buf_state->next == buffer_id; -} - -static void gve_free_buf_state(struct gve_rx_ring *rx, - struct gve_rx_buf_state_dqo *buf_state) -{ - s16 buffer_id = buf_state - rx->dqo.buf_states; - - buf_state->next = rx->dqo.free_buf_states; - rx->dqo.free_buf_states = buffer_id; -} - -static struct gve_rx_buf_state_dqo * -gve_dequeue_buf_state(struct gve_rx_ring *rx, struct gve_index_list *list) -{ - struct gve_rx_buf_state_dqo *buf_state; - s16 buffer_id; - - buffer_id = list->head; - if (unlikely(buffer_id == -1)) - return NULL; - - buf_state = &rx->dqo.buf_states[buffer_id]; - - /* Remove buf_state from list */ - list->head = buf_state->next; - if (buf_state->next == -1) - list->tail = -1; - - /* Point buf_state to itself to mark it as allocated */ - buf_state->next = buffer_id; - - return buf_state; -} - -static void gve_enqueue_buf_state(struct gve_rx_ring *rx, - struct gve_index_list *list, - struct gve_rx_buf_state_dqo *buf_state) -{ - s16 buffer_id = buf_state - rx->dqo.buf_states; - - buf_state->next = -1; - - if (list->head == -1) { - list->head = buffer_id; - list->tail = buffer_id; - } else { - int tail = list->tail; - - rx->dqo.buf_states[tail].next = buffer_id; - list->tail = buffer_id; - } -} - -static struct gve_rx_buf_state_dqo * -gve_get_recycled_buf_state(struct gve_rx_ring *rx) -{ - struct gve_rx_buf_state_dqo *buf_state; - int i; - - /* Recycled buf states are immediately usable. */ - buf_state = gve_dequeue_buf_state(rx, &rx->dqo.recycled_buf_states); - if (likely(buf_state)) - return buf_state; - - if (unlikely(rx->dqo.used_buf_states.head == -1)) - return NULL; - - /* Used buf states are only usable when ref count reaches 0, which means - * no SKBs refer to them. - * - * Search a limited number before giving up. - */ - for (i = 0; i < 5; i++) { - buf_state = gve_dequeue_buf_state(rx, &rx->dqo.used_buf_states); - if (gve_buf_ref_cnt(buf_state) == 0) { - rx->dqo.used_buf_states_cnt--; - return buf_state; - } - - gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state); - } - - /* For QPL, we cannot allocate any new buffers and must - * wait for the existing ones to be available. - */ - if (rx->dqo.qpl) - return NULL; - - /* If there are no free buf states discard an entry from - * `used_buf_states` so it can be used. - */ - if (unlikely(rx->dqo.free_buf_states == -1)) { - buf_state = gve_dequeue_buf_state(rx, &rx->dqo.used_buf_states); - if (gve_buf_ref_cnt(buf_state) == 0) - return buf_state; - - gve_free_page_dqo(rx->gve, buf_state, true); - gve_free_buf_state(rx, buf_state); - } - - return NULL; -} - -static int gve_alloc_page_dqo(struct gve_rx_ring *rx, - struct gve_rx_buf_state_dqo *buf_state) -{ - struct gve_priv *priv = rx->gve; - u32 idx; - - if (!rx->dqo.qpl) { - int err; - - err = gve_alloc_page(priv, &priv->pdev->dev, - &buf_state->page_info.page, - &buf_state->addr, - DMA_FROM_DEVICE, GFP_ATOMIC); - if (err) - return err; - } else { - idx = rx->dqo.next_qpl_page_idx; - if (idx >= gve_get_rx_pages_per_qpl_dqo(priv->rx_desc_cnt)) { - net_err_ratelimited("%s: Out of QPL pages\n", - priv->dev->name); - return -ENOMEM; - } - buf_state->page_info.page = rx->dqo.qpl->pages[idx]; - buf_state->addr = rx->dqo.qpl->page_buses[idx]; - rx->dqo.next_qpl_page_idx++; - } - buf_state->page_info.page_offset = 0; - buf_state->page_info.page_address = - page_address(buf_state->page_info.page); - buf_state->last_single_ref_offset = 0; - - /* The page already has 1 ref. */ - page_ref_add(buf_state->page_info.page, INT_MAX - 1); - buf_state->page_info.pagecnt_bias = INT_MAX; - - return 0; -} - static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx) { struct device *hdev = &priv->pdev->dev; @@ -278,8 +95,10 @@ static void gve_rx_reset_ring_dqo(struct gve_priv *priv, int idx) for (i = 0; i < rx->dqo.num_buf_states; i++) { struct gve_rx_buf_state_dqo *bs = &rx->dqo.buf_states[i]; - if (bs->page_info.page) - gve_free_page_dqo(priv, bs, !rx->dqo.qpl); + if (rx->dqo.page_pool) + gve_free_to_page_pool(rx, bs, false); + else + gve_free_qpl_page_dqo(bs); } } @@ -321,9 +140,11 @@ void gve_rx_free_ring_dqo(struct gve_priv *priv, struct gve_rx_ring *rx, for (i = 0; i < rx->dqo.num_buf_states; i++) { struct gve_rx_buf_state_dqo *bs = &rx->dqo.buf_states[i]; - /* Only free page for RDA. QPL pages are freed in gve_main. */ - if (bs->page_info.page) - gve_free_page_dqo(priv, bs, !rx->dqo.qpl); + + if (rx->dqo.page_pool) + gve_free_to_page_pool(rx, bs, false); + else + gve_free_qpl_page_dqo(bs); } if (rx->dqo.qpl) { @@ -350,6 +171,11 @@ void gve_rx_free_ring_dqo(struct gve_priv *priv, struct gve_rx_ring *rx, kvfree(rx->dqo.buf_states); rx->dqo.buf_states = NULL; + if (rx->dqo.page_pool) { + page_pool_destroy(rx->dqo.page_pool); + rx->dqo.page_pool = NULL; + } + gve_rx_free_hdr_bufs(priv, rx); netif_dbg(priv, drv, priv->dev, "freed rx ring %d\n", idx); @@ -382,6 +208,7 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) { struct device *hdev = &priv->pdev->dev; + struct page_pool *pool; int qpl_page_cnt; size_t size; u32 qpl_id; @@ -395,8 +222,7 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv, rx->gve = priv; rx->q_num = idx; - rx->dqo.num_buf_states = cfg->raw_addressing ? - min_t(s16, S16_MAX, buffer_queue_slots * 4) : + rx->dqo.num_buf_states = cfg->raw_addressing ? buffer_queue_slots : gve_get_rx_pages_per_qpl_dqo(cfg->ring_size); rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states, sizeof(rx->dqo.buf_states[0]), @@ -424,7 +250,13 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv, if (!rx->dqo.bufq.desc_ring) goto err; - if (!cfg->raw_addressing) { + if (cfg->raw_addressing) { + pool = gve_rx_create_page_pool(priv, rx); + if (IS_ERR(pool)) + goto err; + + rx->dqo.page_pool = pool; + } else { qpl_id = gve_get_rx_qpl_id(cfg->qcfg_tx, rx->q_num); qpl_page_cnt = gve_get_rx_pages_per_qpl_dqo(cfg->ring_size); @@ -521,26 +353,14 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) num_avail_slots = min_t(u32, num_avail_slots, complq->num_free_slots); while (num_posted < num_avail_slots) { struct gve_rx_desc_dqo *desc = &bufq->desc_ring[bufq->tail]; - struct gve_rx_buf_state_dqo *buf_state; - - buf_state = gve_get_recycled_buf_state(rx); - if (unlikely(!buf_state)) { - buf_state = gve_alloc_buf_state(rx); - if (unlikely(!buf_state)) - break; - - if (unlikely(gve_alloc_page_dqo(rx, buf_state))) { - u64_stats_update_begin(&rx->statss); - rx->rx_buf_alloc_fail++; - u64_stats_update_end(&rx->statss); - gve_free_buf_state(rx, buf_state); - break; - } + + if (unlikely(gve_alloc_buffer(rx, desc))) { + u64_stats_update_begin(&rx->statss); + rx->rx_buf_alloc_fail++; + u64_stats_update_end(&rx->statss); + break; } - desc->buf_id = cpu_to_le16(buf_state - rx->dqo.buf_states); - desc->buf_addr = cpu_to_le64(buf_state->addr + - buf_state->page_info.page_offset); if (rx->dqo.hdr_bufs.data) desc->header_buf_addr = cpu_to_le64(rx->dqo.hdr_bufs.addr + @@ -557,48 +377,6 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) rx->fill_cnt += num_posted; } -static void gve_try_recycle_buf(struct gve_priv *priv, struct gve_rx_ring *rx, - struct gve_rx_buf_state_dqo *buf_state) -{ - const u16 data_buffer_size = priv->data_buffer_size_dqo; - int pagecount; - - /* Can't reuse if we only fit one buffer per page */ - if (data_buffer_size * 2 > PAGE_SIZE) - goto mark_used; - - pagecount = gve_buf_ref_cnt(buf_state); - - /* Record the offset when we have a single remaining reference. - * - * When this happens, we know all of the other offsets of the page are - * usable. - */ - if (pagecount == 1) { - buf_state->last_single_ref_offset = - buf_state->page_info.page_offset; - } - - /* Use the next buffer sized chunk in the page. */ - buf_state->page_info.page_offset += data_buffer_size; - buf_state->page_info.page_offset &= (PAGE_SIZE - 1); - - /* If we wrap around to the same offset without ever dropping to 1 - * reference, then we don't know if this offset was ever freed. - */ - if (buf_state->page_info.page_offset == - buf_state->last_single_ref_offset) { - goto mark_used; - } - - gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, buf_state); - return; - -mark_used: - gve_enqueue_buf_state(rx, &rx->dqo.used_buf_states, buf_state); - rx->dqo.used_buf_states_cnt++; -} - static void gve_rx_skb_csum(struct sk_buff *skb, const struct gve_rx_compl_desc_dqo *desc, struct gve_ptype ptype) @@ -713,6 +491,9 @@ static int gve_rx_append_frags(struct napi_struct *napi, if (!skb) return -1; + if (rx->dqo.page_pool) + skb_mark_for_recycle(skb); + if (rx->ctx.skb_tail == rx->ctx.skb_head) skb_shinfo(rx->ctx.skb_head)->frag_list = skb; else @@ -723,7 +504,7 @@ static int gve_rx_append_frags(struct napi_struct *napi, if (rx->ctx.skb_tail != rx->ctx.skb_head) { rx->ctx.skb_head->len += buf_len; rx->ctx.skb_head->data_len += buf_len; - rx->ctx.skb_head->truesize += priv->data_buffer_size_dqo; + rx->ctx.skb_head->truesize += buf_state->page_info.buf_size; } /* Trigger ondemand page allocation if we are running low on buffers */ @@ -733,13 +514,8 @@ static int gve_rx_append_frags(struct napi_struct *napi, skb_add_rx_frag(rx->ctx.skb_tail, num_frags, buf_state->page_info.page, buf_state->page_info.page_offset, - buf_len, priv->data_buffer_size_dqo); - gve_dec_pagecnt_bias(&buf_state->page_info); - - /* Advances buffer page-offset if page is partially used. - * Marks buffer as used if page is full. - */ - gve_try_recycle_buf(priv, rx, buf_state); + buf_len, buf_state->page_info.buf_size); + gve_reuse_buffer(rx, buf_state); return 0; } @@ -773,8 +549,7 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, } if (unlikely(compl_desc->rx_error)) { - gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, - buf_state); + gve_free_buffer(rx, buf_state); return -EINVAL; } @@ -798,6 +573,9 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, if (unlikely(!rx->ctx.skb_head)) goto error; rx->ctx.skb_tail = rx->ctx.skb_head; + + if (rx->dqo.page_pool) + skb_mark_for_recycle(rx->ctx.skb_head); } else { unsplit = 1; } @@ -834,8 +612,7 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, rx->rx_copybreak_pkt++; u64_stats_update_end(&rx->statss); - gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, - buf_state); + gve_free_buffer(rx, buf_state); return 0; } @@ -850,16 +627,17 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, return 0; } + if (rx->dqo.page_pool) + skb_mark_for_recycle(rx->ctx.skb_head); + skb_add_rx_frag(rx->ctx.skb_head, 0, buf_state->page_info.page, buf_state->page_info.page_offset, buf_len, - priv->data_buffer_size_dqo); - gve_dec_pagecnt_bias(&buf_state->page_info); - - gve_try_recycle_buf(priv, rx, buf_state); + buf_state->page_info.buf_size); + gve_reuse_buffer(rx, buf_state); return 0; error: - gve_enqueue_buf_state(rx, &rx->dqo.recycled_buf_states, buf_state); + gve_free_buffer(rx, buf_state); return -ENOMEM; } diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c index 2349750075a54d..30fef100257e6f 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.c +++ b/drivers/net/ethernet/google/gve/gve_utils.c @@ -111,6 +111,7 @@ void gve_add_napi(struct gve_priv *priv, int ntfy_idx, struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; netif_napi_add(priv->dev, &block->napi, gve_poll); + netif_napi_set_irq(&block->napi, block->irq); } void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index 3312e1d93c3b51..65302c41bfb147 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -7,7 +7,6 @@ config NET_VENDOR_HISILICON bool "Hisilicon devices" default y depends on OF || ACPI - depends on ARM || ARM64 || COMPILE_TEST help If you have a network (Ethernet) card belonging to this class, say Y. @@ -18,6 +17,8 @@ config NET_VENDOR_HISILICON if NET_VENDOR_HISILICON +if ARM || ARM64 || COMPILE_TEST + config HIX5HD2_GMAC tristate "Hisilicon HIX5HD2 Family Network Device Support" select PHYLIB @@ -141,4 +142,19 @@ config HNS3_ENET endif #HNS3 +endif # ARM || ARM64 || COMPILE_TEST + +config HIBMCGE + tristate "Hisilicon BMC Gigabit Ethernet Device Support" + depends on PCI && PCI_MSI + select PHYLIB + select MOTORCOMM_PHY + select REALTEK_PHY + help + If you wish to compile a kernel for a BMC with HIBMC-xx_gmac + then you should answer Y to this. This makes this driver suitable for use + on certain boards such as the HIBMC-210. + + If you are unsure, say N. + endif # NET_VENDOR_HISILICON diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile index 7f76d412047ae7..0e2cadfea8ff23 100644 --- a/drivers/net/ethernet/hisilicon/Makefile +++ b/drivers/net/ethernet/hisilicon/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_HNS_MDIO) += hns_mdio.o obj-$(CONFIG_HNS) += hns/ obj-$(CONFIG_HNS3) += hns3/ obj-$(CONFIG_HISI_FEMAC) += hisi_femac.o +obj-$(CONFIG_HIBMCGE) += hibmcge/ diff --git a/drivers/net/ethernet/hisilicon/hibmcge/Makefile b/drivers/net/ethernet/hisilicon/hibmcge/Makefile new file mode 100644 index 00000000000000..ae58ac38c206ef --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Makefile for the HISILICON BMC GE network device drivers. +# + +obj-$(CONFIG_HIBMCGE) += hibmcge.o + +hibmcge-objs = hbg_main.o hbg_hw.o hbg_mdio.o hbg_irq.o hbg_txrx.o hbg_ethtool.o diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h new file mode 100644 index 00000000000000..96daf058d387cd --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_COMMON_H +#define __HBG_COMMON_H + +#include +#include +#include "hbg_reg.h" + +#define HBG_STATUS_DISABLE 0x0 +#define HBG_STATUS_ENABLE 0x1 +#define HBG_RX_SKIP1 0x00 +#define HBG_RX_SKIP2 0x01 +#define HBG_VECTOR_NUM 4 +#define HBG_PCU_CACHE_LINE_SIZE 32 +#define HBG_TX_TIMEOUT_BUF_LEN 1024 +#define HBG_RX_DESCR 0x01 + +#define HBG_PACKET_HEAD_SIZE ((HBG_RX_SKIP1 + HBG_RX_SKIP2 + \ + HBG_RX_DESCR) * HBG_PCU_CACHE_LINE_SIZE) + +enum hbg_dir { + HBG_DIR_TX = 1 << 0, + HBG_DIR_RX = 1 << 1, + HBG_DIR_TX_RX = HBG_DIR_TX | HBG_DIR_RX, +}; + +enum hbg_tx_state { + HBG_TX_STATE_COMPLETE = 0, /* clear state, must fix to 0 */ + HBG_TX_STATE_START, +}; + +enum hbg_nic_state { + HBG_NIC_STATE_EVENT_HANDLING = 0, +}; + +struct hbg_buffer { + u32 state; + dma_addr_t state_dma; + + struct sk_buff *skb; + dma_addr_t skb_dma; + u32 skb_len; + + enum hbg_dir dir; + struct hbg_ring *ring; + struct hbg_priv *priv; +}; + +struct hbg_ring { + struct hbg_buffer *queue; + dma_addr_t queue_dma; + + union { + u32 head; + u32 ntc; + }; + union { + u32 tail; + u32 ntu; + }; + u32 len; + + enum hbg_dir dir; + struct hbg_priv *priv; + struct napi_struct napi; + char *tout_log_buf; /* tx timeout log buffer */ +}; + +enum hbg_hw_event_type { + HBG_HW_EVENT_NONE = 0, + HBG_HW_EVENT_INIT, /* driver is loading */ + HBG_HW_EVENT_RESET, +}; + +struct hbg_dev_specs { + u32 mac_id; + struct sockaddr mac_addr; + u32 phy_addr; + u32 mdio_frequency; + u32 rx_fifo_num; + u32 tx_fifo_num; + u32 vlan_layers; + u32 max_mtu; + u32 min_mtu; + + u32 max_frame_len; + u32 rx_buf_size; +}; + +struct hbg_irq_info { + const char *name; + u32 mask; + bool re_enable; + bool need_print; + u64 count; + + void (*irq_handle)(struct hbg_priv *priv, struct hbg_irq_info *info); +}; + +struct hbg_vector { + char name[HBG_VECTOR_NUM][32]; + struct hbg_irq_info *info_array; + u32 info_array_len; +}; + +struct hbg_mac { + struct mii_bus *mdio_bus; + struct phy_device *phydev; + u8 phy_addr; + + u32 speed; + u32 duplex; + u32 autoneg; + u32 link_status; +}; + +struct hbg_priv { + struct net_device *netdev; + struct pci_dev *pdev; + u8 __iomem *io_base; + struct hbg_dev_specs dev_specs; + unsigned long state; + struct hbg_mac mac; + struct hbg_vector vectors; + struct hbg_ring tx_ring; + struct hbg_ring rx_ring; +}; + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c new file mode 100644 index 00000000000000..c3370114aef326 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include +#include +#include "hbg_ethtool.h" + +static const struct ethtool_ops hbg_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, +}; + +void hbg_ethtool_set_ops(struct net_device *netdev) +{ + netdev->ethtool_ops = &hbg_ethtool_ops; +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.h new file mode 100644 index 00000000000000..628707ec2686d3 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_ETHTOOL_H +#define __HBG_ETHTOOL_H + +#include + +void hbg_ethtool_set_ops(struct net_device *netdev); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c new file mode 100644 index 00000000000000..05295c2ad43923 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include +#include +#include +#include +#include "hbg_common.h" +#include "hbg_hw.h" +#include "hbg_reg.h" + +#define HBG_HW_EVENT_WAIT_TIMEOUT_US (2 * 1000 * 1000) +#define HBG_HW_EVENT_WAIT_INTERVAL_US (10 * 1000) +/* little endian or big endian. + * ctrl means packet description, data means skb packet data + */ +#define HBG_ENDIAN_CTRL_LE_DATA_BE 0x0 +#define HBG_PCU_FRAME_LEN_PLUS 4 + +static bool hbg_hw_spec_is_valid(struct hbg_priv *priv) +{ + return hbg_reg_read(priv, HBG_REG_SPEC_VALID_ADDR) && + !hbg_reg_read(priv, HBG_REG_EVENT_REQ_ADDR); +} + +int hbg_hw_event_notify(struct hbg_priv *priv, + enum hbg_hw_event_type event_type) +{ + bool is_valid; + int ret; + + if (test_and_set_bit(HBG_NIC_STATE_EVENT_HANDLING, &priv->state)) + return -EBUSY; + + /* notify */ + hbg_reg_write(priv, HBG_REG_EVENT_REQ_ADDR, event_type); + + ret = read_poll_timeout(hbg_hw_spec_is_valid, is_valid, is_valid, + HBG_HW_EVENT_WAIT_INTERVAL_US, + HBG_HW_EVENT_WAIT_TIMEOUT_US, + HBG_HW_EVENT_WAIT_INTERVAL_US, priv); + + clear_bit(HBG_NIC_STATE_EVENT_HANDLING, &priv->state); + + if (ret) + dev_err(&priv->pdev->dev, + "event %d wait timeout\n", event_type); + + return ret; +} + +static int hbg_hw_dev_specs_init(struct hbg_priv *priv) +{ + struct hbg_dev_specs *specs = &priv->dev_specs; + u64 mac_addr; + + if (!hbg_hw_spec_is_valid(priv)) { + dev_err(&priv->pdev->dev, "dev_specs not init\n"); + return -EINVAL; + } + + specs->mac_id = hbg_reg_read(priv, HBG_REG_MAC_ID_ADDR); + specs->phy_addr = hbg_reg_read(priv, HBG_REG_PHY_ID_ADDR); + specs->mdio_frequency = hbg_reg_read(priv, HBG_REG_MDIO_FREQ_ADDR); + specs->max_mtu = hbg_reg_read(priv, HBG_REG_MAX_MTU_ADDR); + specs->min_mtu = hbg_reg_read(priv, HBG_REG_MIN_MTU_ADDR); + specs->vlan_layers = hbg_reg_read(priv, HBG_REG_VLAN_LAYERS_ADDR); + specs->rx_fifo_num = hbg_reg_read(priv, HBG_REG_RX_FIFO_NUM_ADDR); + specs->tx_fifo_num = hbg_reg_read(priv, HBG_REG_TX_FIFO_NUM_ADDR); + mac_addr = hbg_reg_read64(priv, HBG_REG_MAC_ADDR_ADDR); + u64_to_ether_addr(mac_addr, (u8 *)specs->mac_addr.sa_data); + + if (!is_valid_ether_addr((u8 *)specs->mac_addr.sa_data)) + return -EADDRNOTAVAIL; + + specs->max_frame_len = HBG_PCU_CACHE_LINE_SIZE + specs->max_mtu; + specs->rx_buf_size = HBG_PACKET_HEAD_SIZE + specs->max_frame_len; + return 0; +} + +u32 hbg_hw_get_irq_status(struct hbg_priv *priv) +{ + u32 status; + + status = hbg_reg_read(priv, HBG_REG_CF_INTRPT_STAT_ADDR); + + hbg_field_modify(status, HBG_INT_MSK_TX_B, + hbg_reg_read(priv, HBG_REG_CF_IND_TXINT_STAT_ADDR)); + hbg_field_modify(status, HBG_INT_MSK_RX_B, + hbg_reg_read(priv, HBG_REG_CF_IND_RXINT_STAT_ADDR)); + + return status; +} + +void hbg_hw_irq_clear(struct hbg_priv *priv, u32 mask) +{ + if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) + return hbg_reg_write(priv, HBG_REG_CF_IND_TXINT_CLR_ADDR, 0x1); + + if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) + return hbg_reg_write(priv, HBG_REG_CF_IND_RXINT_CLR_ADDR, 0x1); + + return hbg_reg_write(priv, HBG_REG_CF_INTRPT_CLR_ADDR, mask); +} + +bool hbg_hw_irq_is_enabled(struct hbg_priv *priv, u32 mask) +{ + if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) + return hbg_reg_read(priv, HBG_REG_CF_IND_TXINT_MSK_ADDR); + + if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) + return hbg_reg_read(priv, HBG_REG_CF_IND_RXINT_MSK_ADDR); + + return hbg_reg_read(priv, HBG_REG_CF_INTRPT_MSK_ADDR) & mask; +} + +void hbg_hw_irq_enable(struct hbg_priv *priv, u32 mask, bool enable) +{ + u32 value; + + if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) + return hbg_reg_write(priv, + HBG_REG_CF_IND_TXINT_MSK_ADDR, enable); + + if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) + return hbg_reg_write(priv, + HBG_REG_CF_IND_RXINT_MSK_ADDR, enable); + + value = hbg_reg_read(priv, HBG_REG_CF_INTRPT_MSK_ADDR); + if (enable) + value |= mask; + else + value &= ~mask; + + hbg_reg_write(priv, HBG_REG_CF_INTRPT_MSK_ADDR, value); +} + +void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr) +{ + hbg_reg_write64(priv, HBG_REG_STATION_ADDR_LOW_2_ADDR, mac_addr); +} + +static void hbg_hw_set_pcu_max_frame_len(struct hbg_priv *priv, + u16 max_frame_len) +{ + max_frame_len = max_t(u32, max_frame_len, ETH_DATA_LEN); + + /* lower two bits of value must be set to 0 */ + max_frame_len = round_up(max_frame_len, HBG_PCU_FRAME_LEN_PLUS); + + hbg_reg_write_field(priv, HBG_REG_MAX_FRAME_LEN_ADDR, + HBG_REG_MAX_FRAME_LEN_M, max_frame_len); +} + +static void hbg_hw_set_mac_max_frame_len(struct hbg_priv *priv, + u16 max_frame_size) +{ + hbg_reg_write_field(priv, HBG_REG_MAX_FRAME_SIZE_ADDR, + HBG_REG_MAX_FRAME_LEN_M, max_frame_size); +} + +void hbg_hw_set_mtu(struct hbg_priv *priv, u16 mtu) +{ + hbg_hw_set_pcu_max_frame_len(priv, mtu); + hbg_hw_set_mac_max_frame_len(priv, mtu); +} + +void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable) +{ + hbg_reg_write_field(priv, HBG_REG_PORT_ENABLE_ADDR, + HBG_REG_PORT_ENABLE_TX_B, enable); + hbg_reg_write_field(priv, HBG_REG_PORT_ENABLE_ADDR, + HBG_REG_PORT_ENABLE_RX_B, enable); +} + +u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir) +{ + if (dir & HBG_DIR_TX) + return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR, + HBG_REG_CF_CFF_DATA_NUM_ADDR_TX_M); + + if (dir & HBG_DIR_RX) + return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR, + HBG_REG_CF_CFF_DATA_NUM_ADDR_RX_M); + + return 0; +} + +void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc) +{ + hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_0_ADDR, tx_desc->word0); + hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_1_ADDR, tx_desc->word1); + hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_2_ADDR, tx_desc->word2); + hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_3_ADDR, tx_desc->word3); +} + +void hbg_hw_fill_buffer(struct hbg_priv *priv, u32 buffer_dma_addr) +{ + hbg_reg_write(priv, HBG_REG_RX_CFF_ADDR_ADDR, buffer_dma_addr); +} + +void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex) +{ + hbg_reg_write_field(priv, HBG_REG_PORT_MODE_ADDR, + HBG_REG_PORT_MODE_M, speed); + hbg_reg_write_field(priv, HBG_REG_DUPLEX_TYPE_ADDR, + HBG_REG_DUPLEX_B, duplex); +} + +static void hbg_hw_init_transmit_ctrl(struct hbg_priv *priv) +{ + u32 ctrl = 0; + + ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_AN_EN_B, HBG_STATUS_ENABLE); + ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_CRC_ADD_B, HBG_STATUS_ENABLE); + ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_PAD_EN_B, HBG_STATUS_ENABLE); + + hbg_reg_write(priv, HBG_REG_TRANSMIT_CTRL_ADDR, ctrl); +} + +static void hbg_hw_init_rx_ctrl(struct hbg_priv *priv) +{ + u32 ctrl = 0; + + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RX_GET_ADDR_MODE_B, + HBG_STATUS_ENABLE); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_TIME_INF_EN_B, HBG_STATUS_DISABLE); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE_M, HBG_RX_SKIP1); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE2_M, + HBG_RX_SKIP2); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RX_ALIGN_NUM_M, NET_IP_ALIGN); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_PORT_NUM, priv->dev_specs.mac_id); + + hbg_reg_write(priv, HBG_REG_RX_CTRL_ADDR, ctrl); +} + +static void hbg_hw_init_rx_control(struct hbg_priv *priv) +{ + hbg_hw_init_rx_ctrl(priv); + + /* parse from L2 layer */ + hbg_reg_write_field(priv, HBG_REG_RX_PKT_MODE_ADDR, + HBG_REG_RX_PKT_MODE_PARSE_MODE_M, 0x1); + + hbg_reg_write_field(priv, HBG_REG_RECV_CTRL_ADDR, + HBG_REG_RECV_CTRL_STRIP_PAD_EN_B, + HBG_STATUS_ENABLE); + hbg_reg_write_field(priv, HBG_REG_RX_BUF_SIZE_ADDR, + HBG_REG_RX_BUF_SIZE_M, priv->dev_specs.rx_buf_size); + hbg_reg_write_field(priv, HBG_REG_CF_CRC_STRIP_ADDR, + HBG_REG_CF_CRC_STRIP_B, HBG_STATUS_DISABLE); +} + +int hbg_hw_init(struct hbg_priv *priv) +{ + int ret; + + ret = hbg_hw_dev_specs_init(priv); + if (ret) + return ret; + + hbg_reg_write_field(priv, HBG_REG_BUS_CTRL_ADDR, + HBG_REG_BUS_CTRL_ENDIAN_M, + HBG_ENDIAN_CTRL_LE_DATA_BE); + hbg_reg_write_field(priv, HBG_REG_MODE_CHANGE_EN_ADDR, + HBG_REG_MODE_CHANGE_EN_B, HBG_STATUS_ENABLE); + + hbg_hw_init_rx_control(priv); + hbg_hw_init_transmit_ctrl(priv); + return 0; +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h new file mode 100644 index 00000000000000..14fb39241c93ff --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_HW_H +#define __HBG_HW_H + +#include +#include + +static inline u32 hbg_reg_read(struct hbg_priv *priv, u32 addr) +{ + return readl(priv->io_base + addr); +} + +static inline void hbg_reg_write(struct hbg_priv *priv, u32 addr, u32 value) +{ + writel(value, priv->io_base + addr); +} + +static inline u64 hbg_reg_read64(struct hbg_priv *priv, u32 addr) +{ + return lo_hi_readq(priv->io_base + addr); +} + +static inline void hbg_reg_write64(struct hbg_priv *priv, u32 addr, u64 value) +{ + lo_hi_writeq(value, priv->io_base + addr); +} + +#define hbg_reg_read_field(priv, addr, mask) \ + FIELD_GET(mask, hbg_reg_read(priv, addr)) + +#define hbg_field_modify(reg_value, mask, value) ({ \ + (reg_value) &= ~(mask); \ + (reg_value) |= FIELD_PREP(mask, value); }) + +#define hbg_reg_write_field(priv, addr, mask, val) ({ \ + typeof(priv) _priv = (priv); \ + typeof(addr) _addr = (addr); \ + u32 _value = hbg_reg_read(_priv, _addr); \ + hbg_field_modify(_value, mask, val); \ + hbg_reg_write(_priv, _addr, _value); }) + +int hbg_hw_event_notify(struct hbg_priv *priv, + enum hbg_hw_event_type event_type); +int hbg_hw_init(struct hbg_priv *priv); +void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex); +u32 hbg_hw_get_irq_status(struct hbg_priv *priv); +void hbg_hw_irq_clear(struct hbg_priv *priv, u32 mask); +bool hbg_hw_irq_is_enabled(struct hbg_priv *priv, u32 mask); +void hbg_hw_irq_enable(struct hbg_priv *priv, u32 mask, bool enable); +void hbg_hw_set_mtu(struct hbg_priv *priv, u16 mtu); +void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable); +void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr); +u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir); +void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc); +void hbg_hw_fill_buffer(struct hbg_priv *priv, u32 buffer_dma_addr); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c new file mode 100644 index 00000000000000..25dd25f096fe0e --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include +#include "hbg_irq.h" +#include "hbg_hw.h" + +static void hbg_irq_handle_err(struct hbg_priv *priv, + struct hbg_irq_info *irq_info) +{ + if (irq_info->need_print) + dev_err(&priv->pdev->dev, + "receive error interrupt: %s\n", irq_info->name); +} + +static void hbg_irq_handle_tx(struct hbg_priv *priv, + struct hbg_irq_info *irq_info) +{ + napi_schedule(&priv->tx_ring.napi); +} + +static void hbg_irq_handle_rx(struct hbg_priv *priv, + struct hbg_irq_info *irq_info) +{ + napi_schedule(&priv->rx_ring.napi); +} + +#define HBG_TXRX_IRQ_I(name, handle) \ + {#name, HBG_INT_MSK_##name##_B, false, false, 0, handle} +#define HBG_ERR_IRQ_I(name, need_print) \ + {#name, HBG_INT_MSK_##name##_B, true, need_print, 0, hbg_irq_handle_err} + +static struct hbg_irq_info hbg_irqs[] = { + HBG_TXRX_IRQ_I(RX, hbg_irq_handle_rx), + HBG_TXRX_IRQ_I(TX, hbg_irq_handle_tx), + HBG_ERR_IRQ_I(MAC_MII_FIFO_ERR, true), + HBG_ERR_IRQ_I(MAC_PCS_RX_FIFO_ERR, true), + HBG_ERR_IRQ_I(MAC_PCS_TX_FIFO_ERR, true), + HBG_ERR_IRQ_I(MAC_APP_RX_FIFO_ERR, true), + HBG_ERR_IRQ_I(MAC_APP_TX_FIFO_ERR, true), + HBG_ERR_IRQ_I(SRAM_PARITY_ERR, true), + HBG_ERR_IRQ_I(TX_AHB_ERR, true), + HBG_ERR_IRQ_I(RX_BUF_AVL, false), + HBG_ERR_IRQ_I(REL_BUF_ERR, true), + HBG_ERR_IRQ_I(TXCFG_AVL, false), + HBG_ERR_IRQ_I(TX_DROP, false), + HBG_ERR_IRQ_I(RX_DROP, false), + HBG_ERR_IRQ_I(RX_AHB_ERR, true), + HBG_ERR_IRQ_I(MAC_FIFO_ERR, false), + HBG_ERR_IRQ_I(RBREQ_ERR, false), + HBG_ERR_IRQ_I(WE_ERR, false), +}; + +static irqreturn_t hbg_irq_handle(int irq_num, void *p) +{ + struct hbg_irq_info *info; + struct hbg_priv *priv = p; + u32 status; + u32 i; + + status = hbg_hw_get_irq_status(priv); + for (i = 0; i < priv->vectors.info_array_len; i++) { + info = &priv->vectors.info_array[i]; + if (status & info->mask) { + if (!hbg_hw_irq_is_enabled(priv, info->mask)) + continue; + + hbg_hw_irq_enable(priv, info->mask, false); + hbg_hw_irq_clear(priv, info->mask); + + info->count++; + if (info->irq_handle) + info->irq_handle(priv, info); + + if (info->re_enable) + hbg_hw_irq_enable(priv, info->mask, true); + } + } + + return IRQ_HANDLED; +} + +static const char *irq_names_map[HBG_VECTOR_NUM] = { "tx", "rx", + "err", "mdio" }; + +int hbg_irq_init(struct hbg_priv *priv) +{ + struct hbg_vector *vectors = &priv->vectors; + struct device *dev = &priv->pdev->dev; + int ret, id; + u32 i; + + /* used pcim_enable_device(), so the vectors become device managed */ + ret = pci_alloc_irq_vectors(priv->pdev, HBG_VECTOR_NUM, HBG_VECTOR_NUM, + PCI_IRQ_MSI | PCI_IRQ_MSIX); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to allocate vectors\n"); + + if (ret != HBG_VECTOR_NUM) + return dev_err_probe(dev, -EINVAL, + "requested %u MSI, but allocated %d MSI\n", + HBG_VECTOR_NUM, ret); + + /* mdio irq not requested, so the number of requested interrupts + * is HBG_VECTOR_NUM - 1. + */ + for (i = 0; i < HBG_VECTOR_NUM - 1; i++) { + id = pci_irq_vector(priv->pdev, i); + if (id < 0) + return dev_err_probe(dev, id, "failed to get irq id\n"); + + snprintf(vectors->name[i], sizeof(vectors->name[i]), "%s-%s-%s", + dev_driver_string(dev), pci_name(priv->pdev), + irq_names_map[i]); + + ret = devm_request_irq(dev, id, hbg_irq_handle, 0, + vectors->name[i], priv); + if (ret) + return dev_err_probe(dev, ret, + "failed to request irq: %s\n", + irq_names_map[i]); + } + + vectors->info_array = hbg_irqs; + vectors->info_array_len = ARRAY_SIZE(hbg_irqs); + return 0; +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.h new file mode 100644 index 00000000000000..5c5323cfc75153 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_IRQ_H +#define __HBG_IRQ_H + +#include "hbg_common.h" + +int hbg_irq_init(struct hbg_priv *priv); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c new file mode 100644 index 00000000000000..75505fb5cc4a57 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include +#include +#include +#include +#include "hbg_common.h" +#include "hbg_ethtool.h" +#include "hbg_hw.h" +#include "hbg_irq.h" +#include "hbg_mdio.h" +#include "hbg_txrx.h" + +static void hbg_change_mtu(struct hbg_priv *priv, int new_mtu); + +static void hbg_all_irq_enable(struct hbg_priv *priv, bool enabled) +{ + struct hbg_irq_info *info; + u32 i; + + for (i = 0; i < priv->vectors.info_array_len; i++) { + info = &priv->vectors.info_array[i]; + hbg_hw_irq_enable(priv, info->mask, enabled); + } +} + +static int hbg_net_open(struct net_device *netdev) +{ + struct hbg_priv *priv = netdev_priv(netdev); + int ret; + + ret = hbg_txrx_init(priv); + if (ret) + return ret; + + hbg_all_irq_enable(priv, true); + hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE); + netif_start_queue(netdev); + hbg_phy_start(priv); + + return 0; +} + +/* This function only can be called after hbg_txrx_uninit() */ +static int hbg_hw_txrx_clear(struct hbg_priv *priv) +{ + int ret; + + /* After ring buffers have been released, + * do a reset to release hw fifo rx ring buffer + */ + ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET); + if (ret) + return ret; + + /* After reset, regs need to be reconfigured */ + hbg_hw_init(priv); + hbg_hw_set_uc_addr(priv, ether_addr_to_u64(priv->netdev->dev_addr)); + hbg_change_mtu(priv, priv->netdev->mtu); + + return 0; +} + +static int hbg_net_stop(struct net_device *netdev) +{ + struct hbg_priv *priv = netdev_priv(netdev); + + hbg_phy_stop(priv); + netif_stop_queue(netdev); + hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE); + hbg_all_irq_enable(priv, false); + hbg_txrx_uninit(priv); + return hbg_hw_txrx_clear(priv); +} + +static int hbg_net_set_mac_address(struct net_device *netdev, void *addr) +{ + struct hbg_priv *priv = netdev_priv(netdev); + u8 *mac_addr; + + mac_addr = ((struct sockaddr *)addr)->sa_data; + + if (!is_valid_ether_addr(mac_addr)) + return -EADDRNOTAVAIL; + + hbg_hw_set_uc_addr(priv, ether_addr_to_u64(mac_addr)); + dev_addr_set(netdev, mac_addr); + + return 0; +} + +static void hbg_change_mtu(struct hbg_priv *priv, int new_mtu) +{ + u32 frame_len; + + frame_len = new_mtu + VLAN_HLEN * priv->dev_specs.vlan_layers + + ETH_HLEN + ETH_FCS_LEN; + hbg_hw_set_mtu(priv, frame_len); +} + +static int hbg_net_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct hbg_priv *priv = netdev_priv(netdev); + + if (netif_running(netdev)) + return -EBUSY; + + hbg_change_mtu(priv, new_mtu); + WRITE_ONCE(netdev->mtu, new_mtu); + + dev_dbg(&priv->pdev->dev, + "change mtu from %u to %u\n", netdev->mtu, new_mtu); + + return 0; +} + +static void hbg_net_tx_timeout(struct net_device *netdev, unsigned int txqueue) +{ + struct hbg_priv *priv = netdev_priv(netdev); + struct hbg_ring *ring = &priv->tx_ring; + char *buf = ring->tout_log_buf; + u32 pos = 0; + + pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos, + "ring used num: %u, fifo used num: %u\n", + hbg_get_queue_used_num(ring), + hbg_hw_get_fifo_used_num(priv, HBG_DIR_TX)); + pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos, + "ntc: %u, ntu: %u, irq enabled: %u\n", + ring->ntc, ring->ntu, + hbg_hw_irq_is_enabled(priv, HBG_INT_MSK_TX_B)); + + netdev_info(netdev, "%s", buf); +} + +static const struct net_device_ops hbg_netdev_ops = { + .ndo_open = hbg_net_open, + .ndo_stop = hbg_net_stop, + .ndo_start_xmit = hbg_net_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = hbg_net_set_mac_address, + .ndo_change_mtu = hbg_net_change_mtu, + .ndo_tx_timeout = hbg_net_tx_timeout, +}; + +static int hbg_init(struct hbg_priv *priv) +{ + int ret; + + ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_INIT); + if (ret) + return ret; + + ret = hbg_hw_init(priv); + if (ret) + return ret; + + ret = hbg_irq_init(priv); + if (ret) + return ret; + + return hbg_mdio_init(priv); +} + +static int hbg_pci_init(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct hbg_priv *priv = netdev_priv(netdev); + struct device *dev = &pdev->dev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return dev_err_probe(dev, ret, "failed to enable PCI device\n"); + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + return dev_err_probe(dev, ret, "failed to set PCI DMA mask\n"); + + ret = pcim_iomap_regions(pdev, BIT(0), dev_driver_string(dev)); + if (ret) + return dev_err_probe(dev, ret, "failed to map PCI bar space\n"); + + priv->io_base = pcim_iomap_table(pdev)[0]; + if (!priv->io_base) + return dev_err_probe(dev, -ENOMEM, "failed to get io base\n"); + + pci_set_master(pdev); + return 0; +} + +static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct net_device *netdev; + struct hbg_priv *priv; + int ret; + + netdev = devm_alloc_etherdev(dev, sizeof(struct hbg_priv)); + if (!netdev) + return -ENOMEM; + + pci_set_drvdata(pdev, netdev); + SET_NETDEV_DEV(netdev, dev); + + priv = netdev_priv(netdev); + priv->netdev = netdev; + priv->pdev = pdev; + + ret = hbg_pci_init(pdev); + if (ret) + return ret; + + ret = hbg_init(priv); + if (ret) + return ret; + + netdev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; + netdev->max_mtu = priv->dev_specs.max_mtu; + netdev->min_mtu = priv->dev_specs.min_mtu; + netdev->netdev_ops = &hbg_netdev_ops; + netdev->watchdog_timeo = 5 * HZ; + + hbg_change_mtu(priv, ETH_DATA_LEN); + hbg_net_set_mac_address(priv->netdev, &priv->dev_specs.mac_addr); + hbg_ethtool_set_ops(netdev); + + ret = devm_register_netdev(dev, netdev); + if (ret) + return dev_err_probe(dev, ret, "failed to register netdev\n"); + + netif_carrier_off(netdev); + return 0; +} + +static const struct pci_device_id hbg_pci_tbl[] = { + {PCI_VDEVICE(HUAWEI, 0x3730), 0}, + { } +}; +MODULE_DEVICE_TABLE(pci, hbg_pci_tbl); + +static struct pci_driver hbg_driver = { + .name = "hibmcge", + .id_table = hbg_pci_tbl, + .probe = hbg_probe, +}; +module_pci_driver(hbg_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huawei Tech. Co., Ltd."); +MODULE_DESCRIPTION("hibmcge driver"); +MODULE_VERSION("1.0"); diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c new file mode 100644 index 00000000000000..a3479fba850164 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include +#include "hbg_common.h" +#include "hbg_hw.h" +#include "hbg_mdio.h" +#include "hbg_reg.h" + +#define HBG_MAC_GET_PRIV(mac) ((struct hbg_priv *)(mac)->mdio_bus->priv) +#define HBG_MII_BUS_GET_MAC(bus) (&((struct hbg_priv *)(bus)->priv)->mac) + +#define HBG_MDIO_C22_MODE 0x1 +#define HBG_MDIO_C22_REG_WRITE 0x1 +#define HBG_MDIO_C22_REG_READ 0x2 + +#define HBG_MDIO_OP_TIMEOUT_US (1 * 1000 * 1000) +#define HBG_MDIO_OP_INTERVAL_US (5 * 1000) + +static void hbg_mdio_set_command(struct hbg_mac *mac, u32 cmd) +{ + hbg_reg_write(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR, cmd); +} + +static void hbg_mdio_get_command(struct hbg_mac *mac, u32 *cmd) +{ + *cmd = hbg_reg_read(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR); +} + +static void hbg_mdio_set_wdata_reg(struct hbg_mac *mac, u16 wdata_value) +{ + hbg_reg_write_field(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_WDATA_ADDR, + HBG_REG_MDIO_WDATA_M, wdata_value); +} + +static u32 hbg_mdio_get_rdata_reg(struct hbg_mac *mac) +{ + return hbg_reg_read_field(HBG_MAC_GET_PRIV(mac), + HBG_REG_MDIO_RDATA_ADDR, + HBG_REG_MDIO_WDATA_M); +} + +static int hbg_mdio_wait_ready(struct hbg_mac *mac) +{ + struct hbg_priv *priv = HBG_MAC_GET_PRIV(mac); + u32 cmd = 0; + int ret; + + ret = readl_poll_timeout(priv->io_base + HBG_REG_MDIO_COMMAND_ADDR, cmd, + !FIELD_GET(HBG_REG_MDIO_COMMAND_START_B, cmd), + HBG_MDIO_OP_INTERVAL_US, + HBG_MDIO_OP_TIMEOUT_US); + + return ret ? -ETIMEDOUT : 0; +} + +static int hbg_mdio_cmd_send(struct hbg_mac *mac, u32 prt_addr, u32 dev_addr, + u32 type, u32 op_code) +{ + u32 cmd = 0; + + hbg_mdio_get_command(mac, &cmd); + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_ST_M, type); + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_OP_M, op_code); + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_PRTAD_M, prt_addr); + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_DEVAD_M, dev_addr); + + /* if auto scan enabled, this value need fix to 0 */ + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_START_B, 0x1); + + hbg_mdio_set_command(mac, cmd); + + /* wait operation complete and check the result */ + return hbg_mdio_wait_ready(mac); +} + +static int hbg_mdio_read22(struct mii_bus *bus, int phy_addr, int regnum) +{ + struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus); + int ret; + + ret = hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE, + HBG_MDIO_C22_REG_READ); + if (ret) + return ret; + + return hbg_mdio_get_rdata_reg(mac); +} + +static int hbg_mdio_write22(struct mii_bus *bus, int phy_addr, int regnum, + u16 val) +{ + struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus); + + hbg_mdio_set_wdata_reg(mac, val); + return hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE, + HBG_MDIO_C22_REG_WRITE); +} + +static void hbg_mdio_init_hw(struct hbg_priv *priv) +{ + u32 freq = priv->dev_specs.mdio_frequency; + struct hbg_mac *mac = &priv->mac; + u32 cmd = 0; + + cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_ST_M, HBG_MDIO_C22_MODE); + cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_AUTO_SCAN_B, HBG_STATUS_DISABLE); + + /* freq use two bits, which are stored in clk_sel and clk_sel_exp */ + cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_CLK_SEL_B, freq & 0x1); + cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_CLK_SEL_EXP_B, + (freq >> 1) & 0x1); + + hbg_mdio_set_command(mac, cmd); +} + +static void hbg_phy_adjust_link(struct net_device *netdev) +{ + struct hbg_priv *priv = netdev_priv(netdev); + struct phy_device *phydev = netdev->phydev; + u32 speed; + + if (phydev->link != priv->mac.link_status) { + if (phydev->link) { + switch (phydev->speed) { + case SPEED_10: + speed = HBG_PORT_MODE_SGMII_10M; + break; + case SPEED_100: + speed = HBG_PORT_MODE_SGMII_100M; + break; + case SPEED_1000: + speed = HBG_PORT_MODE_SGMII_1000M; + break; + default: + return; + } + + priv->mac.speed = speed; + priv->mac.duplex = phydev->duplex; + priv->mac.autoneg = phydev->autoneg; + hbg_hw_adjust_link(priv, speed, phydev->duplex); + } + + priv->mac.link_status = phydev->link; + phy_print_status(phydev); + } +} + +static void hbg_phy_disconnect(void *data) +{ + phy_disconnect((struct phy_device *)data); +} + +static int hbg_phy_connect(struct hbg_priv *priv) +{ + struct phy_device *phydev = priv->mac.phydev; + struct device *dev = &priv->pdev->dev; + int ret; + + ret = phy_connect_direct(priv->netdev, phydev, hbg_phy_adjust_link, + PHY_INTERFACE_MODE_SGMII); + if (ret) + return dev_err_probe(dev, ret, "failed to connect phy\n"); + + ret = devm_add_action_or_reset(dev, hbg_phy_disconnect, phydev); + if (ret) + return ret; + + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + phy_attached_info(phydev); + + return 0; +} + +void hbg_phy_start(struct hbg_priv *priv) +{ + phy_start(priv->mac.phydev); +} + +void hbg_phy_stop(struct hbg_priv *priv) +{ + phy_stop(priv->mac.phydev); +} + +int hbg_mdio_init(struct hbg_priv *priv) +{ + struct device *dev = &priv->pdev->dev; + struct hbg_mac *mac = &priv->mac; + struct phy_device *phydev; + struct mii_bus *mdio_bus; + int ret; + + mac->phy_addr = priv->dev_specs.phy_addr; + mdio_bus = devm_mdiobus_alloc(dev); + if (!mdio_bus) + return dev_err_probe(dev, -ENOMEM, + "failed to alloc MDIO bus\n"); + + mdio_bus->parent = dev; + mdio_bus->priv = priv; + mdio_bus->phy_mask = ~(1 << mac->phy_addr); + mdio_bus->name = "hibmcge mii bus"; + mac->mdio_bus = mdio_bus; + + mdio_bus->read = hbg_mdio_read22; + mdio_bus->write = hbg_mdio_write22; + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii", dev_name(dev)); + + ret = devm_mdiobus_register(dev, mdio_bus); + if (ret) + return dev_err_probe(dev, ret, "failed to register MDIO bus\n"); + + phydev = mdiobus_get_phy(mdio_bus, mac->phy_addr); + if (!phydev) + return dev_err_probe(dev, -ENODEV, + "failed to get phy device\n"); + + mac->phydev = phydev; + hbg_mdio_init_hw(priv); + return hbg_phy_connect(priv); +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h new file mode 100644 index 00000000000000..febd02a309c791 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_MDIO_H +#define __HBG_MDIO_H + +#include "hbg_common.h" + +int hbg_mdio_init(struct hbg_priv *priv); +void hbg_phy_start(struct hbg_priv *priv); +void hbg_phy_stop(struct hbg_priv *priv); +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h new file mode 100644 index 00000000000000..57d81c6d763321 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_REG_H +#define __HBG_REG_H + +/* DEV SPEC */ +#define HBG_REG_SPEC_VALID_ADDR 0x0000 +#define HBG_REG_EVENT_REQ_ADDR 0x0004 +#define HBG_REG_MAC_ID_ADDR 0x0008 +#define HBG_REG_PHY_ID_ADDR 0x000C +#define HBG_REG_MAC_ADDR_ADDR 0x0010 +#define HBG_REG_MDIO_FREQ_ADDR 0x0024 +#define HBG_REG_MAX_MTU_ADDR 0x0028 +#define HBG_REG_MIN_MTU_ADDR 0x002C +#define HBG_REG_TX_FIFO_NUM_ADDR 0x0030 +#define HBG_REG_RX_FIFO_NUM_ADDR 0x0034 +#define HBG_REG_VLAN_LAYERS_ADDR 0x0038 + +/* MDIO */ +#define HBG_REG_MDIO_BASE 0x8000 +#define HBG_REG_MDIO_COMMAND_ADDR (HBG_REG_MDIO_BASE + 0x0000) +#define HBG_REG_MDIO_COMMAND_CLK_SEL_EXP_B BIT(17) +#define HBG_REG_MDIO_COMMAND_AUTO_SCAN_B BIT(16) +#define HBG_REG_MDIO_COMMAND_CLK_SEL_B BIT(15) +#define HBG_REG_MDIO_COMMAND_START_B BIT(14) +#define HBG_REG_MDIO_COMMAND_ST_M GENMASK(13, 12) +#define HBG_REG_MDIO_COMMAND_OP_M GENMASK(11, 10) +#define HBG_REG_MDIO_COMMAND_PRTAD_M GENMASK(9, 5) +#define HBG_REG_MDIO_COMMAND_DEVAD_M GENMASK(4, 0) +#define HBG_REG_MDIO_WDATA_ADDR (HBG_REG_MDIO_BASE + 0x0008) +#define HBG_REG_MDIO_WDATA_M GENMASK(15, 0) +#define HBG_REG_MDIO_RDATA_ADDR (HBG_REG_MDIO_BASE + 0x000C) +#define HBG_REG_MDIO_STA_ADDR (HBG_REG_MDIO_BASE + 0x0010) + +/* GMAC */ +#define HBG_REG_SGMII_BASE 0x10000 +#define HBG_REG_DUPLEX_TYPE_ADDR (HBG_REG_SGMII_BASE + 0x0008) +#define HBG_REG_DUPLEX_B BIT(0) +#define HBG_REG_MAX_FRAME_SIZE_ADDR (HBG_REG_SGMII_BASE + 0x003C) +#define HBG_REG_PORT_MODE_ADDR (HBG_REG_SGMII_BASE + 0x0040) +#define HBG_REG_PORT_MODE_M GENMASK(3, 0) +#define HBG_REG_PORT_ENABLE_ADDR (HBG_REG_SGMII_BASE + 0x0044) +#define HBG_REG_PORT_ENABLE_RX_B BIT(1) +#define HBG_REG_PORT_ENABLE_TX_B BIT(2) +#define HBG_REG_TRANSMIT_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x0060) +#define HBG_REG_TRANSMIT_CTRL_PAD_EN_B BIT(7) +#define HBG_REG_TRANSMIT_CTRL_CRC_ADD_B BIT(6) +#define HBG_REG_TRANSMIT_CTRL_AN_EN_B BIT(5) +#define HBG_REG_CF_CRC_STRIP_ADDR (HBG_REG_SGMII_BASE + 0x01B0) +#define HBG_REG_CF_CRC_STRIP_B BIT(0) +#define HBG_REG_MODE_CHANGE_EN_ADDR (HBG_REG_SGMII_BASE + 0x01B4) +#define HBG_REG_MODE_CHANGE_EN_B BIT(0) +#define HBG_REG_RECV_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x01E0) +#define HBG_REG_RECV_CTRL_STRIP_PAD_EN_B BIT(3) +#define HBG_REG_STATION_ADDR_LOW_2_ADDR (HBG_REG_SGMII_BASE + 0x0210) +#define HBG_REG_STATION_ADDR_HIGH_2_ADDR (HBG_REG_SGMII_BASE + 0x0214) + +/* PCU */ +#define HBG_REG_CF_INTRPT_MSK_ADDR (HBG_REG_SGMII_BASE + 0x042C) +#define HBG_INT_MSK_WE_ERR_B BIT(31) +#define HBG_INT_MSK_RBREQ_ERR_B BIT(30) +#define HBG_INT_MSK_MAC_FIFO_ERR_B BIT(29) +#define HBG_INT_MSK_RX_AHB_ERR_B BIT(28) +#define HBG_INT_MSK_RX_DROP_B BIT(26) +#define HBG_INT_MSK_TX_DROP_B BIT(25) +#define HBG_INT_MSK_TXCFG_AVL_B BIT(24) +#define HBG_INT_MSK_REL_BUF_ERR_B BIT(23) +#define HBG_INT_MSK_RX_BUF_AVL_B BIT(22) +#define HBG_INT_MSK_TX_AHB_ERR_B BIT(21) +#define HBG_INT_MSK_SRAM_PARITY_ERR_B BIT(20) +#define HBG_INT_MSK_MAC_APP_TX_FIFO_ERR_B BIT(19) +#define HBG_INT_MSK_MAC_APP_RX_FIFO_ERR_B BIT(18) +#define HBG_INT_MSK_MAC_PCS_TX_FIFO_ERR_B BIT(17) +#define HBG_INT_MSK_MAC_PCS_RX_FIFO_ERR_B BIT(16) +#define HBG_INT_MSK_MAC_MII_FIFO_ERR_B BIT(15) +#define HBG_INT_MSK_TX_B BIT(1) /* just used in driver */ +#define HBG_INT_MSK_RX_B BIT(0) /* just used in driver */ +#define HBG_REG_CF_INTRPT_STAT_ADDR (HBG_REG_SGMII_BASE + 0x0434) +#define HBG_REG_CF_INTRPT_CLR_ADDR (HBG_REG_SGMII_BASE + 0x0438) +#define HBG_REG_MAX_FRAME_LEN_ADDR (HBG_REG_SGMII_BASE + 0x0444) +#define HBG_REG_MAX_FRAME_LEN_M GENMASK(15, 0) +#define HBG_REG_CF_CFF_DATA_NUM_ADDR (HBG_REG_SGMII_BASE + 0x045C) +#define HBG_REG_CF_CFF_DATA_NUM_ADDR_TX_M GENMASK(8, 0) +#define HBG_REG_CF_CFF_DATA_NUM_ADDR_RX_M GENMASK(24, 16) +#define HBG_REG_TX_CFF_ADDR_0_ADDR (HBG_REG_SGMII_BASE + 0x0488) +#define HBG_REG_TX_CFF_ADDR_1_ADDR (HBG_REG_SGMII_BASE + 0x048C) +#define HBG_REG_TX_CFF_ADDR_2_ADDR (HBG_REG_SGMII_BASE + 0x0490) +#define HBG_REG_TX_CFF_ADDR_3_ADDR (HBG_REG_SGMII_BASE + 0x0494) +#define HBG_REG_RX_CFF_ADDR_ADDR (HBG_REG_SGMII_BASE + 0x04A0) +#define HBG_REG_RX_BUF_SIZE_ADDR (HBG_REG_SGMII_BASE + 0x04E4) +#define HBG_REG_RX_BUF_SIZE_M GENMASK(15, 0) +#define HBG_REG_BUS_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x04E8) +#define HBG_REG_BUS_CTRL_ENDIAN_M GENMASK(2, 1) +#define HBG_REG_RX_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x04F0) +#define HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE_M GENMASK(31, 28) +#define HBG_REG_RX_CTRL_TIME_INF_EN_B BIT(23) +#define HBG_REG_RX_CTRL_RX_ALIGN_NUM_M GENMASK(18, 17) +#define HBG_REG_RX_CTRL_PORT_NUM GENMASK(16, 13) +#define HBG_REG_RX_CTRL_RX_GET_ADDR_MODE_B BIT(12) +#define HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE2_M GENMASK(3, 0) +#define HBG_REG_RX_PKT_MODE_ADDR (HBG_REG_SGMII_BASE + 0x04F4) +#define HBG_REG_RX_PKT_MODE_PARSE_MODE_M GENMASK(22, 21) +#define HBG_REG_CF_IND_TXINT_MSK_ADDR (HBG_REG_SGMII_BASE + 0x0694) +#define HBG_REG_IND_INTR_MASK_B BIT(0) +#define HBG_REG_CF_IND_TXINT_STAT_ADDR (HBG_REG_SGMII_BASE + 0x0698) +#define HBG_REG_CF_IND_TXINT_CLR_ADDR (HBG_REG_SGMII_BASE + 0x069C) +#define HBG_REG_CF_IND_RXINT_MSK_ADDR (HBG_REG_SGMII_BASE + 0x06a0) +#define HBG_REG_CF_IND_RXINT_STAT_ADDR (HBG_REG_SGMII_BASE + 0x06a4) +#define HBG_REG_CF_IND_RXINT_CLR_ADDR (HBG_REG_SGMII_BASE + 0x06a8) + +enum hbg_port_mode { + /* 0x0 ~ 0x5 are reserved */ + HBG_PORT_MODE_SGMII_10M = 0x6, + HBG_PORT_MODE_SGMII_100M = 0x7, + HBG_PORT_MODE_SGMII_1000M = 0x8, +}; + +struct hbg_tx_desc { + u32 word0; + u32 word1; + u32 word2; /* pkt_addr */ + u32 word3; /* clear_addr */ +}; + +#define HBG_TX_DESC_W0_IP_OFF_M GENMASK(30, 26) +#define HBG_TX_DESC_W0_l3_CS_B BIT(2) +#define HBG_TX_DESC_W0_WB_B BIT(1) +#define HBG_TX_DESC_W0_l4_CS_B BIT(0) +#define HBG_TX_DESC_W1_SEND_LEN_M GENMASK(19, 4) + +struct hbg_rx_desc { + u32 word0; + u32 word1; /* tag */ + u32 word2; + u32 word3; + u32 word4; + u32 word5; +}; + +#define HBG_RX_DESC_W2_PKT_LEN_M GENMASK(31, 16) + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c new file mode 100644 index 00000000000000..f4f256a0dfea41 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include +#include "hbg_common.h" +#include "hbg_irq.h" +#include "hbg_reg.h" +#include "hbg_txrx.h" + +#define netdev_get_tx_ring(netdev) \ + (&(((struct hbg_priv *)netdev_priv(netdev))->tx_ring)) + +#define buffer_to_dma_dir(buffer) (((buffer)->dir == HBG_DIR_RX) ? \ + DMA_FROM_DEVICE : DMA_TO_DEVICE) + +#define hbg_queue_used_num(head, tail, ring) ({ \ + typeof(ring) _ring = (ring); \ + ((tail) + _ring->len - (head)) % _ring->len; }) +#define hbg_queue_left_num(head, tail, ring) ({ \ + typeof(ring) _r = (ring); \ + _r->len - hbg_queue_used_num((head), (tail), _r) - 1; }) +#define hbg_queue_is_empty(head, tail, ring) \ + (hbg_queue_used_num((head), (tail), (ring)) == 0) +#define hbg_queue_is_full(head, tail, ring) \ + (hbg_queue_left_num((head), (tail), (ring)) == 0) +#define hbg_queue_next_prt(p, ring) (((p) + 1) % (ring)->len) +#define hbg_queue_move_next(p, ring) ({ \ + typeof(ring) _ring = (ring); \ + _ring->p = hbg_queue_next_prt(_ring->p, _ring); }) + +#define HBG_TX_STOP_THRS 2 +#define HBG_TX_START_THRS (2 * HBG_TX_STOP_THRS) + +static int hbg_dma_map(struct hbg_buffer *buffer) +{ + struct hbg_priv *priv = buffer->priv; + + buffer->skb_dma = dma_map_single(&priv->pdev->dev, + buffer->skb->data, buffer->skb_len, + buffer_to_dma_dir(buffer)); + if (unlikely(dma_mapping_error(&priv->pdev->dev, buffer->skb_dma))) + return -ENOMEM; + + return 0; +} + +static void hbg_dma_unmap(struct hbg_buffer *buffer) +{ + struct hbg_priv *priv = buffer->priv; + + if (unlikely(!buffer->skb_dma)) + return; + + dma_unmap_single(&priv->pdev->dev, buffer->skb_dma, buffer->skb_len, + buffer_to_dma_dir(buffer)); + buffer->skb_dma = 0; +} + +static void hbg_init_tx_desc(struct hbg_buffer *buffer, + struct hbg_tx_desc *tx_desc) +{ + u32 ip_offset = buffer->skb->network_header - buffer->skb->mac_header; + u32 word0 = 0; + + word0 |= FIELD_PREP(HBG_TX_DESC_W0_WB_B, HBG_STATUS_ENABLE); + word0 |= FIELD_PREP(HBG_TX_DESC_W0_IP_OFF_M, ip_offset); + if (likely(buffer->skb->ip_summed == CHECKSUM_PARTIAL)) { + word0 |= FIELD_PREP(HBG_TX_DESC_W0_l3_CS_B, HBG_STATUS_ENABLE); + word0 |= FIELD_PREP(HBG_TX_DESC_W0_l4_CS_B, HBG_STATUS_ENABLE); + } + + tx_desc->word0 = word0; + tx_desc->word1 = FIELD_PREP(HBG_TX_DESC_W1_SEND_LEN_M, + buffer->skb->len); + tx_desc->word2 = buffer->skb_dma; + tx_desc->word3 = buffer->state_dma; +} + +netdev_tx_t hbg_net_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct hbg_ring *ring = netdev_get_tx_ring(netdev); + struct hbg_priv *priv = netdev_priv(netdev); + /* This smp_load_acquire() pairs with smp_store_release() in + * hbg_napi_tx_recycle() called in tx interrupt handle process. + */ + u32 ntc = smp_load_acquire(&ring->ntc); + struct hbg_buffer *buffer; + struct hbg_tx_desc tx_desc; + u32 ntu = ring->ntu; + + if (unlikely(!skb->len || + skb->len > hbg_spec_max_frame_len(priv, HBG_DIR_TX))) { + dev_kfree_skb_any(skb); + netdev->stats.tx_errors++; + return NETDEV_TX_OK; + } + + if (!netif_subqueue_maybe_stop(netdev, 0, + hbg_queue_left_num(ntc, ntu, ring), + HBG_TX_STOP_THRS, HBG_TX_START_THRS)) + return NETDEV_TX_BUSY; + + buffer = &ring->queue[ntu]; + buffer->skb = skb; + buffer->skb_len = skb->len; + if (unlikely(hbg_dma_map(buffer))) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + buffer->state = HBG_TX_STATE_START; + hbg_init_tx_desc(buffer, &tx_desc); + hbg_hw_set_tx_desc(priv, &tx_desc); + + /* This smp_store_release() pairs with smp_load_acquire() in + * hbg_napi_tx_recycle() called in tx interrupt handle process. + */ + smp_store_release(&ring->ntu, hbg_queue_next_prt(ntu, ring)); + dev_sw_netstats_tx_add(netdev, 1, skb->len); + return NETDEV_TX_OK; +} + +static void hbg_buffer_free_skb(struct hbg_buffer *buffer) +{ + if (unlikely(!buffer->skb)) + return; + + dev_kfree_skb_any(buffer->skb); + buffer->skb = NULL; +} + +static int hbg_buffer_alloc_skb(struct hbg_buffer *buffer) +{ + u32 len = hbg_spec_max_frame_len(buffer->priv, buffer->dir); + struct hbg_priv *priv = buffer->priv; + + buffer->skb = netdev_alloc_skb(priv->netdev, len); + if (unlikely(!buffer->skb)) + return -ENOMEM; + + buffer->skb_len = len; + memset(buffer->skb->data, 0, HBG_PACKET_HEAD_SIZE); + return 0; +} + +static void hbg_buffer_free(struct hbg_buffer *buffer) +{ + hbg_dma_unmap(buffer); + hbg_buffer_free_skb(buffer); +} + +static int hbg_napi_tx_recycle(struct napi_struct *napi, int budget) +{ + struct hbg_ring *ring = container_of(napi, struct hbg_ring, napi); + /* This smp_load_acquire() pairs with smp_store_release() in + * hbg_net_start_xmit() called in xmit process. + */ + u32 ntu = smp_load_acquire(&ring->ntu); + struct hbg_priv *priv = ring->priv; + struct hbg_buffer *buffer; + u32 ntc = ring->ntc; + int packet_done = 0; + + /* We need do cleanup even if budget is 0. + * Per NAPI documentation budget is for Rx. + * So We hardcode the amount of work Tx NAPI does to 128. + */ + budget = 128; + while (packet_done < budget) { + if (unlikely(hbg_queue_is_empty(ntc, ntu, ring))) + break; + + /* make sure HW write desc complete */ + dma_rmb(); + + buffer = &ring->queue[ntc]; + if (buffer->state != HBG_TX_STATE_COMPLETE) + break; + + hbg_buffer_free(buffer); + ntc = hbg_queue_next_prt(ntc, ring); + packet_done++; + } + + /* This smp_store_release() pairs with smp_load_acquire() in + * hbg_net_start_xmit() called in xmit process. + */ + smp_store_release(&ring->ntc, ntc); + netif_wake_queue(priv->netdev); + + if (likely(packet_done < budget && + napi_complete_done(napi, packet_done))) + hbg_hw_irq_enable(priv, HBG_INT_MSK_TX_B, true); + + return packet_done; +} + +static int hbg_rx_fill_one_buffer(struct hbg_priv *priv) +{ + struct hbg_ring *ring = &priv->rx_ring; + struct hbg_buffer *buffer; + int ret; + + if (hbg_queue_is_full(ring->ntc, ring->ntu, ring)) + return 0; + + buffer = &ring->queue[ring->ntu]; + ret = hbg_buffer_alloc_skb(buffer); + if (unlikely(ret)) + return ret; + + ret = hbg_dma_map(buffer); + if (unlikely(ret)) { + hbg_buffer_free_skb(buffer); + return ret; + } + + hbg_hw_fill_buffer(priv, buffer->skb_dma); + hbg_queue_move_next(ntu, ring); + return 0; +} + +static bool hbg_sync_data_from_hw(struct hbg_priv *priv, + struct hbg_buffer *buffer) +{ + struct hbg_rx_desc *rx_desc; + + /* make sure HW write desc complete */ + dma_rmb(); + + dma_sync_single_for_cpu(&priv->pdev->dev, buffer->skb_dma, + buffer->skb_len, DMA_FROM_DEVICE); + + rx_desc = (struct hbg_rx_desc *)buffer->skb->data; + return FIELD_GET(HBG_RX_DESC_W2_PKT_LEN_M, rx_desc->word2) != 0; +} + +static int hbg_napi_rx_poll(struct napi_struct *napi, int budget) +{ + struct hbg_ring *ring = container_of(napi, struct hbg_ring, napi); + struct hbg_priv *priv = ring->priv; + struct hbg_rx_desc *rx_desc; + struct hbg_buffer *buffer; + u32 packet_done = 0; + u32 pkt_len; + + while (packet_done < budget) { + if (unlikely(hbg_queue_is_empty(ring->ntc, ring->ntu, ring))) + break; + + buffer = &ring->queue[ring->ntc]; + if (unlikely(!buffer->skb)) + goto next_buffer; + + if (unlikely(!hbg_sync_data_from_hw(priv, buffer))) + break; + rx_desc = (struct hbg_rx_desc *)buffer->skb->data; + pkt_len = FIELD_GET(HBG_RX_DESC_W2_PKT_LEN_M, rx_desc->word2); + + hbg_dma_unmap(buffer); + + skb_reserve(buffer->skb, HBG_PACKET_HEAD_SIZE + NET_IP_ALIGN); + skb_put(buffer->skb, pkt_len); + buffer->skb->protocol = eth_type_trans(buffer->skb, + priv->netdev); + + dev_sw_netstats_rx_add(priv->netdev, pkt_len); + napi_gro_receive(napi, buffer->skb); + buffer->skb = NULL; + +next_buffer: + hbg_rx_fill_one_buffer(priv); + hbg_queue_move_next(ntc, ring); + packet_done++; + } + + if (likely(packet_done < budget && + napi_complete_done(napi, packet_done))) + hbg_hw_irq_enable(priv, HBG_INT_MSK_RX_B, true); + + return packet_done; +} + +static void hbg_ring_uninit(struct hbg_ring *ring) +{ + struct hbg_buffer *buffer; + u32 i; + + if (!ring->queue) + return; + + napi_disable(&ring->napi); + netif_napi_del(&ring->napi); + + for (i = 0; i < ring->len; i++) { + buffer = &ring->queue[i]; + hbg_buffer_free(buffer); + buffer->ring = NULL; + buffer->priv = NULL; + } + + dma_free_coherent(&ring->priv->pdev->dev, + ring->len * sizeof(*ring->queue), + ring->queue, ring->queue_dma); + ring->queue = NULL; + ring->queue_dma = 0; + ring->len = 0; + ring->priv = NULL; +} + +static int hbg_ring_init(struct hbg_priv *priv, struct hbg_ring *ring, + int (*napi_poll)(struct napi_struct *, int), + enum hbg_dir dir) +{ + struct hbg_buffer *buffer; + u32 i, len; + + len = hbg_get_spec_fifo_max_num(priv, dir) + 1; + ring->queue = dma_alloc_coherent(&priv->pdev->dev, + len * sizeof(*ring->queue), + &ring->queue_dma, GFP_KERNEL); + if (!ring->queue) + return -ENOMEM; + + for (i = 0; i < len; i++) { + buffer = &ring->queue[i]; + buffer->skb_len = 0; + buffer->dir = dir; + buffer->ring = ring; + buffer->priv = priv; + buffer->state_dma = ring->queue_dma + (i * sizeof(*buffer)); + } + + ring->dir = dir; + ring->priv = priv; + ring->ntc = 0; + ring->ntu = 0; + ring->len = len; + + if (dir == HBG_DIR_TX) + netif_napi_add_tx(priv->netdev, &ring->napi, napi_poll); + else + netif_napi_add(priv->netdev, &ring->napi, napi_poll); + + napi_enable(&ring->napi); + return 0; +} + +static int hbg_tx_ring_init(struct hbg_priv *priv) +{ + struct hbg_ring *tx_ring = &priv->tx_ring; + + if (!tx_ring->tout_log_buf) + tx_ring->tout_log_buf = devm_kmalloc(&priv->pdev->dev, + HBG_TX_TIMEOUT_BUF_LEN, + GFP_KERNEL); + + if (!tx_ring->tout_log_buf) + return -ENOMEM; + + return hbg_ring_init(priv, tx_ring, hbg_napi_tx_recycle, HBG_DIR_TX); +} + +static int hbg_rx_ring_init(struct hbg_priv *priv) +{ + int ret; + u32 i; + + ret = hbg_ring_init(priv, &priv->rx_ring, hbg_napi_rx_poll, HBG_DIR_RX); + if (ret) + return ret; + + for (i = 0; i < priv->rx_ring.len - 1; i++) { + ret = hbg_rx_fill_one_buffer(priv); + if (ret) { + hbg_ring_uninit(&priv->rx_ring); + return ret; + } + } + + return 0; +} + +int hbg_txrx_init(struct hbg_priv *priv) +{ + int ret; + + ret = hbg_tx_ring_init(priv); + if (ret) { + dev_err(&priv->pdev->dev, + "failed to init tx ring, ret = %d\n", ret); + return ret; + } + + ret = hbg_rx_ring_init(priv); + if (ret) { + dev_err(&priv->pdev->dev, + "failed to init rx ring, ret = %d\n", ret); + hbg_ring_uninit(&priv->tx_ring); + } + + return ret; +} + +void hbg_txrx_uninit(struct hbg_priv *priv) +{ + hbg_ring_uninit(&priv->tx_ring); + hbg_ring_uninit(&priv->rx_ring); +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.h new file mode 100644 index 00000000000000..2883a5899ae29e --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_TXRX_H +#define __HBG_TXRX_H + +#include +#include "hbg_hw.h" + +static inline u32 hbg_spec_max_frame_len(struct hbg_priv *priv, + enum hbg_dir dir) +{ + return (dir == HBG_DIR_TX) ? priv->dev_specs.max_frame_len : + priv->dev_specs.rx_buf_size; +} + +static inline u32 hbg_get_spec_fifo_max_num(struct hbg_priv *priv, + enum hbg_dir dir) +{ + return (dir == HBG_DIR_TX) ? priv->dev_specs.tx_fifo_num : + priv->dev_specs.rx_fifo_num; +} + +static inline bool hbg_fifo_is_full(struct hbg_priv *priv, enum hbg_dir dir) +{ + return hbg_hw_get_fifo_used_num(priv, dir) >= + hbg_get_spec_fifo_max_num(priv, dir); +} + +static inline u32 hbg_get_queue_used_num(struct hbg_ring *ring) +{ + return (ring->ntu + ring->len - ring->ntc) % ring->len; +} + +netdev_tx_t hbg_net_start_xmit(struct sk_buff *skb, struct net_device *netdev); +int hbg_txrx_init(struct hbg_priv *priv); +void hbg_txrx_uninit(struct hbg_priv *priv); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index beb815e5289b12..a376d4bdf2819b 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -1047,7 +1047,7 @@ MODULE_DEVICE_TABLE(of, hip04_mac_match); static struct platform_driver hip04_mac_driver = { .probe = hip04_mac_probe, - .remove_new = hip04_remove, + .remove = hip04_remove, .driver = { .name = DRV_NAME, .of_match_table = hip04_mac_match, diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c index 2406263c9dd3ad..d244a40df43091 100644 --- a/drivers/net/ethernet/hisilicon/hisi_femac.c +++ b/drivers/net/ethernet/hisilicon/hisi_femac.c @@ -959,7 +959,7 @@ static struct platform_driver hisi_femac_driver = { .of_match_table = hisi_femac_match, }, .probe = hisi_femac_drv_probe, - .remove_new = hisi_femac_drv_remove, + .remove = hisi_femac_drv_remove, #ifdef CONFIG_PM .suspend = hisi_femac_drv_suspend, .resume = hisi_femac_drv_resume, diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index 1a972b093a4240..e3e7f2270560cb 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1312,7 +1312,7 @@ static struct platform_driver hix5hd2_dev_driver = { .of_match_table = hix5hd2_of_match, }, .probe = hix5hd2_dev_probe, - .remove_new = hix5hd2_dev_remove, + .remove = hix5hd2_dev_remove, }; module_platform_driver(hix5hd2_dev_driver); diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h index d72657444ef3aa..2ae34d01fd3626 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.h +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h @@ -512,7 +512,7 @@ struct hnae_ae_ops { struct net_device_stats *net_stats); void (*get_stats)(struct hnae_handle *handle, u64 *data); void (*get_strings)(struct hnae_handle *handle, - u32 stringset, u8 *data); + u32 stringset, u8 **data); int (*get_sset_count)(struct hnae_handle *handle, int stringset); void (*update_led_status)(struct hnae_handle *handle); int (*set_led_id)(struct hnae_handle *handle, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c index bc3e406f01390c..8ce910f8d0cccc 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -730,15 +730,14 @@ static void hns_ae_get_stats(struct hnae_handle *handle, u64 *data) hns_dsaf_get_stats(vf_cb->dsaf_dev, p, vf_cb->port_index); } -static void hns_ae_get_strings(struct hnae_handle *handle, - u32 stringset, u8 *data) +static void hns_ae_get_strings(struct hnae_handle *handle, u32 stringset, + u8 **data) { int port; int idx; struct hns_mac_cb *mac_cb; struct hns_ppe_cb *ppe_cb; struct dsaf_device *dsaf_dev = hns_ae_get_dsaf_dev(handle->dev); - u8 *p = data; struct hnae_vf_cb *vf_cb; assert(handle); @@ -748,19 +747,14 @@ static void hns_ae_get_strings(struct hnae_handle *handle, mac_cb = hns_get_mac_cb(handle); ppe_cb = hns_get_ppe_cb(handle); - for (idx = 0; idx < handle->q_num; idx++) { - hns_rcb_get_strings(stringset, p, idx); - p += ETH_GSTRING_LEN * hns_rcb_get_ring_sset_count(stringset); - } - - hns_ppe_get_strings(ppe_cb, stringset, p); - p += ETH_GSTRING_LEN * hns_ppe_get_sset_count(stringset); + for (idx = 0; idx < handle->q_num; idx++) + hns_rcb_get_strings(stringset, data, idx); - hns_mac_get_strings(mac_cb, stringset, p); - p += ETH_GSTRING_LEN * hns_mac_get_sset_count(mac_cb, stringset); + hns_ppe_get_strings(ppe_cb, stringset, data); + hns_mac_get_strings(mac_cb, stringset, data); if (mac_cb->mac_type == HNAE_PORT_SERVICE) - hns_dsaf_get_strings(stringset, p, port, dsaf_dev); + hns_dsaf_get_strings(stringset, data, port, dsaf_dev); } static int hns_ae_get_sset_count(struct hnae_handle *handle, int stringset) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index bdb7afaabdd06a..400933ca1a29b3 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -669,16 +669,15 @@ static void hns_gmac_get_stats(void *mac_drv, u64 *data) } } -static void hns_gmac_get_strings(u32 stringset, u8 *data) +static void hns_gmac_get_strings(u32 stringset, u8 **data) { - u8 *buff = data; u32 i; if (stringset != ETH_SS_STATS) return; for (i = 0; i < ARRAY_SIZE(g_gmac_stats_string); i++) - ethtool_puts(&buff, g_gmac_stats_string[i].desc); + ethtool_puts(data, g_gmac_stats_string[i].desc); } static int hns_gmac_get_sset_count(int stringset) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c index 58baac7103b380..bc6b269be29959 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c @@ -1090,28 +1090,24 @@ int hns_mac_init(struct dsaf_device *dsaf_dev) u32 port_id; int max_port_num = hns_mac_get_max_port_num(dsaf_dev); struct hns_mac_cb *mac_cb; - struct fwnode_handle *child; - device_for_each_child_node(dsaf_dev->dev, child) { + device_for_each_child_node_scoped(dsaf_dev->dev, child) { ret = fwnode_property_read_u32(child, "reg", &port_id); if (ret) { - fwnode_handle_put(child); dev_err(dsaf_dev->dev, "get reg fail, ret=%d!\n", ret); return ret; } if (port_id >= max_port_num) { - fwnode_handle_put(child); dev_err(dsaf_dev->dev, "reg(%u) out of range!\n", port_id); return -EINVAL; } mac_cb = devm_kzalloc(dsaf_dev->dev, sizeof(*mac_cb), GFP_KERNEL); - if (!mac_cb) { - fwnode_handle_put(child); + if (!mac_cb) return -ENOMEM; - } + mac_cb->fw_port = child; mac_cb->mac_id = (u8)port_id; dsaf_dev->mac_cb[port_id] = mac_cb; @@ -1194,8 +1190,7 @@ void hns_mac_get_stats(struct hns_mac_cb *mac_cb, u64 *data) mac_ctrl_drv->get_ethtool_stats(mac_ctrl_drv, data); } -void hns_mac_get_strings(struct hns_mac_cb *mac_cb, - int stringset, u8 *data) +void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 **data) { struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h index edf0bcf76ac9ee..630f01cf7a71c2 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h @@ -378,7 +378,7 @@ struct mac_driver { void (*get_regs)(void *mac_drv, void *data); int (*get_regs_count)(void); /* get strings name for ethtool statistic */ - void (*get_strings)(u32 stringset, u8 *data); + void (*get_strings)(u32 stringset, u8 **data); /* get the number of strings*/ int (*get_sset_count)(int stringset); @@ -445,7 +445,7 @@ int hns_mac_config_mac_loopback(struct hns_mac_cb *mac_cb, enum hnae_loop loop, int en); void hns_mac_update_stats(struct hns_mac_cb *mac_cb); void hns_mac_get_stats(struct hns_mac_cb *mac_cb, u64 *data); -void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 *data); +void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 **data); int hns_mac_get_sset_count(struct hns_mac_cb *mac_cb, int stringset); void hns_mac_get_regs(struct hns_mac_cb *mac_cb, void *data); int hns_mac_get_regs_count(struct hns_mac_cb *mac_cb); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 1b67da1f6fa86e..851490346261ee 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -2590,55 +2590,34 @@ void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data) p[i] = 0xdddddddd; } -static char *hns_dsaf_get_node_stats_strings(char *data, int node, - struct dsaf_device *dsaf_dev) +static void hns_dsaf_get_node_stats_strings(u8 **data, int node, + struct dsaf_device *dsaf_dev) { - char *buff = data; - int i; bool is_ver1 = AE_IS_VER1(dsaf_dev->dsaf_ver); + int i; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_pad_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_manage_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pkt_id", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pause_frame", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_release_buf_num", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_sbm_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_crc_false_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_bp_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_lookup_rslt_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_local_rslt_fail_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_vlan_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_stp_drop_pkts", node); - buff += ETH_GSTRING_LEN; + ethtool_sprintf(data, "innod%d_pad_drop_pkts", node); + ethtool_sprintf(data, "innod%d_manage_pkts", node); + ethtool_sprintf(data, "innod%d_rx_pkts", node); + ethtool_sprintf(data, "innod%d_rx_pkt_id", node); + ethtool_sprintf(data, "innod%d_rx_pause_frame", node); + ethtool_sprintf(data, "innod%d_release_buf_num", node); + ethtool_sprintf(data, "innod%d_sbm_drop_pkts", node); + ethtool_sprintf(data, "innod%d_crc_false_pkts", node); + ethtool_sprintf(data, "innod%d_bp_drop_pkts", node); + ethtool_sprintf(data, "innod%d_lookup_rslt_drop_pkts", node); + ethtool_sprintf(data, "innod%d_local_rslt_fail_pkts", node); + ethtool_sprintf(data, "innod%d_vlan_drop_pkts", node); + ethtool_sprintf(data, "innod%d_stp_drop_pkts", node); if (node < DSAF_SERVICE_NW_NUM && !is_ver1) { for (i = 0; i < DSAF_PRIO_NR; i++) { - snprintf(buff + 0 * ETH_GSTRING_LEN * DSAF_PRIO_NR, - ETH_GSTRING_LEN, "inod%d_pfc_prio%d_pkts", - node, i); - snprintf(buff + 1 * ETH_GSTRING_LEN * DSAF_PRIO_NR, - ETH_GSTRING_LEN, "onod%d_pfc_prio%d_pkts", - node, i); - buff += ETH_GSTRING_LEN; + ethtool_sprintf(data, "inod%d_pfc_prio%d_pkts", node, + i); + ethtool_sprintf(data, "onod%d_pfc_prio%d_pkts", node, + i); } - buff += 1 * DSAF_PRIO_NR * ETH_GSTRING_LEN; } - snprintf(buff, ETH_GSTRING_LEN, "onnod%d_tx_pkts", node); - buff += ETH_GSTRING_LEN; - - return buff; + ethtool_sprintf(data, "onnod%d_tx_pkts", node); } static u64 *hns_dsaf_get_node_stats(struct dsaf_device *ddev, u64 *data, @@ -2720,21 +2699,20 @@ int hns_dsaf_get_sset_count(struct dsaf_device *dsaf_dev, int stringset) *@port:port index *@dsaf_dev: dsaf device */ -void hns_dsaf_get_strings(int stringset, u8 *data, int port, +void hns_dsaf_get_strings(int stringset, u8 **data, int port, struct dsaf_device *dsaf_dev) { - char *buff = (char *)data; int node = port; if (stringset != ETH_SS_STATS) return; /* for ge/xge node info */ - buff = hns_dsaf_get_node_stats_strings(buff, node, dsaf_dev); + hns_dsaf_get_node_stats_strings(data, node, dsaf_dev); /* for ppe node info */ node = port + DSAF_PPE_INODE_BASE; - (void)hns_dsaf_get_node_stats_strings(buff, node, dsaf_dev); + hns_dsaf_get_node_stats_strings(data, node, dsaf_dev); } /** @@ -3031,7 +3009,7 @@ MODULE_DEVICE_TABLE(of, g_dsaf_match); static struct platform_driver g_dsaf_driver = { .probe = hns_dsaf_probe, - .remove_new = hns_dsaf_remove, + .remove = hns_dsaf_remove, .driver = { .name = DSAF_DRV_NAME, .of_match_table = g_dsaf_match, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h index 5526a10caac5a5..0eb03dff1a8bfc 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h @@ -442,7 +442,7 @@ void hns_dsaf_update_stats(struct dsaf_device *dsaf_dev, u32 inode_num); int hns_dsaf_get_sset_count(struct dsaf_device *dsaf_dev, int stringset); void hns_dsaf_get_stats(struct dsaf_device *ddev, u64 *data, int port); -void hns_dsaf_get_strings(int stringset, u8 *data, int port, +void hns_dsaf_get_strings(int stringset, u8 **data, int port, struct dsaf_device *dsaf_dev); void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c index a08d1f0a5a1653..5013beb4d28257 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c @@ -457,24 +457,23 @@ int hns_ppe_get_regs_count(void) * @stringset: string set type * @data: output string */ -void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 *data) +void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 **data) { int index = ppe_cb->index; - u8 *buff = data; - - ethtool_sprintf(&buff, "ppe%d_rx_sw_pkt", index); - ethtool_sprintf(&buff, "ppe%d_rx_pkt_ok", index); - ethtool_sprintf(&buff, "ppe%d_rx_drop_pkt_no_bd", index); - ethtool_sprintf(&buff, "ppe%d_rx_alloc_buf_fail", index); - ethtool_sprintf(&buff, "ppe%d_rx_alloc_buf_wait", index); - ethtool_sprintf(&buff, "ppe%d_rx_pkt_drop_no_buf", index); - ethtool_sprintf(&buff, "ppe%d_rx_pkt_err_fifo_full", index); - - ethtool_sprintf(&buff, "ppe%d_tx_bd", index); - ethtool_sprintf(&buff, "ppe%d_tx_pkt", index); - ethtool_sprintf(&buff, "ppe%d_tx_pkt_ok", index); - ethtool_sprintf(&buff, "ppe%d_tx_pkt_err_fifo_empty", index); - ethtool_sprintf(&buff, "ppe%d_tx_pkt_err_csum_fail", index); + + ethtool_sprintf(data, "ppe%d_rx_sw_pkt", index); + ethtool_sprintf(data, "ppe%d_rx_pkt_ok", index); + ethtool_sprintf(data, "ppe%d_rx_drop_pkt_no_bd", index); + ethtool_sprintf(data, "ppe%d_rx_alloc_buf_fail", index); + ethtool_sprintf(data, "ppe%d_rx_alloc_buf_wait", index); + ethtool_sprintf(data, "ppe%d_rx_pkt_drop_no_buf", index); + ethtool_sprintf(data, "ppe%d_rx_pkt_err_fifo_full", index); + + ethtool_sprintf(data, "ppe%d_tx_bd", index); + ethtool_sprintf(data, "ppe%d_tx_pkt", index); + ethtool_sprintf(data, "ppe%d_tx_pkt_ok", index); + ethtool_sprintf(data, "ppe%d_tx_pkt_err_fifo_empty", index); + ethtool_sprintf(data, "ppe%d_tx_pkt_err_csum_fail", index); } void hns_ppe_get_stats(struct hns_ppe_cb *ppe_cb, u64 *data) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h index 7e00231c1acfac..602c8e971fe462 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h @@ -109,7 +109,7 @@ int hns_ppe_get_sset_count(int stringset); int hns_ppe_get_regs_count(void); void hns_ppe_get_regs(struct hns_ppe_cb *ppe_cb, void *data); -void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 *data); +void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 **data); void hns_ppe_get_stats(struct hns_ppe_cb *ppe_cb, u64 *data); void hns_ppe_set_tso_enable(struct hns_ppe_cb *ppe_cb, u32 value); void hns_ppe_set_rss_key(struct hns_ppe_cb *ppe_cb, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index 93344563a259f3..46af467aa59633 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -923,44 +923,42 @@ int hns_rcb_get_ring_regs_count(void) *@data:strings name value *@index:queue index */ -void hns_rcb_get_strings(int stringset, u8 *data, int index) +void hns_rcb_get_strings(int stringset, u8 **data, int index) { - u8 *buff = data; - if (stringset != ETH_SS_STATS) return; - ethtool_sprintf(&buff, "tx_ring%d_rcb_pkt_num", index); - ethtool_sprintf(&buff, "tx_ring%d_ppe_tx_pkt_num", index); - ethtool_sprintf(&buff, "tx_ring%d_ppe_drop_pkt_num", index); - ethtool_sprintf(&buff, "tx_ring%d_fbd_num", index); - - ethtool_sprintf(&buff, "tx_ring%d_pkt_num", index); - ethtool_sprintf(&buff, "tx_ring%d_bytes", index); - ethtool_sprintf(&buff, "tx_ring%d_err_cnt", index); - ethtool_sprintf(&buff, "tx_ring%d_io_err", index); - ethtool_sprintf(&buff, "tx_ring%d_sw_err", index); - ethtool_sprintf(&buff, "tx_ring%d_seg_pkt", index); - ethtool_sprintf(&buff, "tx_ring%d_restart_queue", index); - ethtool_sprintf(&buff, "tx_ring%d_tx_busy", index); - - ethtool_sprintf(&buff, "rx_ring%d_rcb_pkt_num", index); - ethtool_sprintf(&buff, "rx_ring%d_ppe_pkt_num", index); - ethtool_sprintf(&buff, "rx_ring%d_ppe_drop_pkt_num", index); - ethtool_sprintf(&buff, "rx_ring%d_fbd_num", index); - - ethtool_sprintf(&buff, "rx_ring%d_pkt_num", index); - ethtool_sprintf(&buff, "rx_ring%d_bytes", index); - ethtool_sprintf(&buff, "rx_ring%d_err_cnt", index); - ethtool_sprintf(&buff, "rx_ring%d_io_err", index); - ethtool_sprintf(&buff, "rx_ring%d_sw_err", index); - ethtool_sprintf(&buff, "rx_ring%d_seg_pkt", index); - ethtool_sprintf(&buff, "rx_ring%d_reuse_pg", index); - ethtool_sprintf(&buff, "rx_ring%d_len_err", index); - ethtool_sprintf(&buff, "rx_ring%d_non_vld_desc_err", index); - ethtool_sprintf(&buff, "rx_ring%d_bd_num_err", index); - ethtool_sprintf(&buff, "rx_ring%d_l2_err", index); - ethtool_sprintf(&buff, "rx_ring%d_l3l4csum_err", index); + ethtool_sprintf(data, "tx_ring%d_rcb_pkt_num", index); + ethtool_sprintf(data, "tx_ring%d_ppe_tx_pkt_num", index); + ethtool_sprintf(data, "tx_ring%d_ppe_drop_pkt_num", index); + ethtool_sprintf(data, "tx_ring%d_fbd_num", index); + + ethtool_sprintf(data, "tx_ring%d_pkt_num", index); + ethtool_sprintf(data, "tx_ring%d_bytes", index); + ethtool_sprintf(data, "tx_ring%d_err_cnt", index); + ethtool_sprintf(data, "tx_ring%d_io_err", index); + ethtool_sprintf(data, "tx_ring%d_sw_err", index); + ethtool_sprintf(data, "tx_ring%d_seg_pkt", index); + ethtool_sprintf(data, "tx_ring%d_restart_queue", index); + ethtool_sprintf(data, "tx_ring%d_tx_busy", index); + + ethtool_sprintf(data, "rx_ring%d_rcb_pkt_num", index); + ethtool_sprintf(data, "rx_ring%d_ppe_pkt_num", index); + ethtool_sprintf(data, "rx_ring%d_ppe_drop_pkt_num", index); + ethtool_sprintf(data, "rx_ring%d_fbd_num", index); + + ethtool_sprintf(data, "rx_ring%d_pkt_num", index); + ethtool_sprintf(data, "rx_ring%d_bytes", index); + ethtool_sprintf(data, "rx_ring%d_err_cnt", index); + ethtool_sprintf(data, "rx_ring%d_io_err", index); + ethtool_sprintf(data, "rx_ring%d_sw_err", index); + ethtool_sprintf(data, "rx_ring%d_seg_pkt", index); + ethtool_sprintf(data, "rx_ring%d_reuse_pg", index); + ethtool_sprintf(data, "rx_ring%d_len_err", index); + ethtool_sprintf(data, "rx_ring%d_non_vld_desc_err", index); + ethtool_sprintf(data, "rx_ring%d_bd_num_err", index); + ethtool_sprintf(data, "rx_ring%d_l2_err", index); + ethtool_sprintf(data, "rx_ring%d_l3l4csum_err", index); } void hns_rcb_get_common_regs(struct rcb_common_cb *rcb_com, void *data) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h index c1e9b6997853ff..0f4cc184ef3909 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h @@ -157,7 +157,7 @@ int hns_rcb_get_ring_regs_count(void); void hns_rcb_get_ring_regs(struct hnae_queue *queue, void *data); -void hns_rcb_get_strings(int stringset, u8 *data, int index); +void hns_rcb_get_strings(int stringset, u8 **data, int index); void hns_rcb_set_rx_ring_bs(struct hnae_queue *q, u32 buf_size); void hns_rcb_set_tx_ring_bs(struct hnae_queue *q, u32 buf_size); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c index c58833eb48306b..dbc44c2c26c24f 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c @@ -743,16 +743,15 @@ static void hns_xgmac_get_stats(void *mac_drv, u64 *data) *@stringset: type of values in data *@data:data for value of string name */ -static void hns_xgmac_get_strings(u32 stringset, u8 *data) +static void hns_xgmac_get_strings(u32 stringset, u8 **data) { - u8 *buff = data; u32 i; if (stringset != ETH_SS_STATS) return; for (i = 0; i < ARRAY_SIZE(g_xgmac_stats_string); i++) - ethtool_puts(&buff, g_xgmac_stats_string[i].desc); + ethtool_puts(data, g_xgmac_stats_string[i].desc); } /** diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index fd32e15cadcb41..42bb341fd80b77 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -2439,7 +2439,7 @@ static struct platform_driver hns_nic_dev_driver = { .acpi_match_table = ACPI_PTR(hns_enet_acpi_match), }, .probe = hns_nic_dev_probe, - .remove_new = hns_nic_dev_remove, + .remove = hns_nic_dev_remove, }; module_platform_driver(hns_nic_dev_driver); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index a5bb306b2cf1d5..6c458f037262fd 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -903,7 +903,6 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { struct hns_nic_priv *priv = netdev_priv(netdev); struct hnae_handle *h = priv->ae_handle; - u8 *buff = data; if (!h->dev->ops->get_strings) { netdev_err(netdev, "h->dev->ops->get_strings is null!\n"); @@ -912,43 +911,43 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data) if (stringset == ETH_SS_TEST) { if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII) - ethtool_puts(&buff, + ethtool_puts(&data, hns_nic_test_strs[MAC_INTERNALLOOP_MAC]); - ethtool_puts(&buff, hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]); + ethtool_puts(&data, hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]); if ((netdev->phydev) && (!netdev->phydev->is_c45)) - ethtool_puts(&buff, + ethtool_puts(&data, hns_nic_test_strs[MAC_INTERNALLOOP_PHY]); } else { - ethtool_puts(&buff, "rx_packets"); - ethtool_puts(&buff, "tx_packets"); - ethtool_puts(&buff, "rx_bytes"); - ethtool_puts(&buff, "tx_bytes"); - ethtool_puts(&buff, "rx_errors"); - ethtool_puts(&buff, "tx_errors"); - ethtool_puts(&buff, "rx_dropped"); - ethtool_puts(&buff, "tx_dropped"); - ethtool_puts(&buff, "multicast"); - ethtool_puts(&buff, "collisions"); - ethtool_puts(&buff, "rx_over_errors"); - ethtool_puts(&buff, "rx_crc_errors"); - ethtool_puts(&buff, "rx_frame_errors"); - ethtool_puts(&buff, "rx_fifo_errors"); - ethtool_puts(&buff, "rx_missed_errors"); - ethtool_puts(&buff, "tx_aborted_errors"); - ethtool_puts(&buff, "tx_carrier_errors"); - ethtool_puts(&buff, "tx_fifo_errors"); - ethtool_puts(&buff, "tx_heartbeat_errors"); - ethtool_puts(&buff, "rx_length_errors"); - ethtool_puts(&buff, "tx_window_errors"); - ethtool_puts(&buff, "rx_compressed"); - ethtool_puts(&buff, "tx_compressed"); - ethtool_puts(&buff, "netdev_rx_dropped"); - ethtool_puts(&buff, "netdev_tx_dropped"); - - ethtool_puts(&buff, "netdev_tx_timeout"); - - h->dev->ops->get_strings(h, stringset, buff); + ethtool_puts(&data, "rx_packets"); + ethtool_puts(&data, "tx_packets"); + ethtool_puts(&data, "rx_bytes"); + ethtool_puts(&data, "tx_bytes"); + ethtool_puts(&data, "rx_errors"); + ethtool_puts(&data, "tx_errors"); + ethtool_puts(&data, "rx_dropped"); + ethtool_puts(&data, "tx_dropped"); + ethtool_puts(&data, "multicast"); + ethtool_puts(&data, "collisions"); + ethtool_puts(&data, "rx_over_errors"); + ethtool_puts(&data, "rx_crc_errors"); + ethtool_puts(&data, "rx_frame_errors"); + ethtool_puts(&data, "rx_fifo_errors"); + ethtool_puts(&data, "rx_missed_errors"); + ethtool_puts(&data, "tx_aborted_errors"); + ethtool_puts(&data, "tx_carrier_errors"); + ethtool_puts(&data, "tx_fifo_errors"); + ethtool_puts(&data, "tx_heartbeat_errors"); + ethtool_puts(&data, "rx_length_errors"); + ethtool_puts(&data, "tx_window_errors"); + ethtool_puts(&data, "rx_compressed"); + ethtool_puts(&data, "tx_compressed"); + ethtool_puts(&data, "netdev_rx_dropped"); + ethtool_puts(&data, "netdev_tx_dropped"); + + ethtool_puts(&data, "netdev_tx_timeout"); + + h->dev->ops->get_strings(h, stringset, &data); } } @@ -970,7 +969,7 @@ static int hns_get_sset_count(struct net_device *netdev, int stringset) return -EOPNOTSUPP; } if (stringset == ETH_SS_TEST) { - u32 cnt = (sizeof(hns_nic_test_strs) / ETH_GSTRING_LEN); + u32 cnt = ARRAY_SIZE(hns_nic_test_strs); if (priv->ae_handle->phy_if == PHY_INTERFACE_MODE_XGMII) cnt--; diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 27dbe367f3d355..710a8f9f224843 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -677,7 +677,7 @@ struct hnae3_ae_ops { void (*get_mac_stats)(struct hnae3_handle *handle, struct hns3_mac_stats *mac_stats); void (*get_strings)(struct hnae3_handle *handle, - u32 stringset, u8 *data); + u32 stringset, u8 **data); int (*get_sset_count)(struct hnae3_handle *handle, int stringset); void (*get_regs)(struct hnae3_handle *handle, u32 *version, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c index 2b31188ff55586..f9a3d6fc4416cb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c @@ -36,27 +36,22 @@ int hclge_comm_tqps_get_sset_count(struct hnae3_handle *handle) } EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_sset_count); -u8 *hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 *data) +void hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 **data) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; - u8 *buff = data; u16 i; for (i = 0; i < kinfo->num_tqps; i++) { struct hclge_comm_tqp *tqp = container_of(kinfo->tqp[i], struct hclge_comm_tqp, q); - snprintf(buff, ETH_GSTRING_LEN, "txq%u_pktnum_rcd", tqp->index); - buff += ETH_GSTRING_LEN; + ethtool_sprintf(data, "txq%u_pktnum_rcd", tqp->index); } for (i = 0; i < kinfo->num_tqps; i++) { struct hclge_comm_tqp *tqp = container_of(kinfo->tqp[i], struct hclge_comm_tqp, q); - snprintf(buff, ETH_GSTRING_LEN, "rxq%u_pktnum_rcd", tqp->index); - buff += ETH_GSTRING_LEN; + ethtool_sprintf(data, "rxq%u_pktnum_rcd", tqp->index); } - - return buff; } EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_strings); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h index a46350162ee8db..b9ff424c0bc28f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h @@ -32,7 +32,7 @@ struct hclge_comm_tqp { u64 *hclge_comm_tqps_get_stats(struct hnae3_handle *handle, u64 *data); int hclge_comm_tqps_get_sset_count(struct hnae3_handle *handle); -u8 *hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 *data); +void hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 **data); void hclge_comm_reset_tqp_stats(struct hnae3_handle *handle); int hclge_comm_tqps_update_stats(struct hnae3_handle *handle, struct hclge_comm_hw *hw); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 4cbc4d069a1f36..43377a7b242645 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4448,7 +4448,7 @@ static void hns3_update_rx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector) dim_update_sample(tqp_vector->event_cnt, rx_group->total_packets, rx_group->total_bytes, &sample); - net_dim(&rx_group->dim, sample); + net_dim(&rx_group->dim, &sample); } static void hns3_update_tx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector) @@ -4461,7 +4461,7 @@ static void hns3_update_tx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector) dim_update_sample(tqp_vector->event_cnt, tx_group->total_packets, tx_group->total_bytes, &sample); - net_dim(&tx_group->dim, sample); + net_dim(&tx_group->dim, &sample); } static int hns3_nic_common_poll(struct napi_struct *napi, int budget) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index b1e98834734769..b771a2daba4360 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -509,54 +509,37 @@ static int hns3_get_sset_count(struct net_device *netdev, int stringset) } } -static void *hns3_update_strings(u8 *data, const struct hns3_stats *stats, - u32 stat_count, u32 num_tqps, const char *prefix) +static void hns3_update_strings(u8 **data, const struct hns3_stats *stats, + u32 stat_count, u32 num_tqps, + const char *prefix) { -#define MAX_PREFIX_SIZE (6 + 4) - u32 size_left; u32 i, j; - u32 n1; - for (i = 0; i < num_tqps; i++) { - for (j = 0; j < stat_count; j++) { - data[ETH_GSTRING_LEN - 1] = '\0'; - - /* first, prepend the prefix string */ - n1 = scnprintf(data, MAX_PREFIX_SIZE, "%s%u_", - prefix, i); - size_left = (ETH_GSTRING_LEN - 1) - n1; - - /* now, concatenate the stats string to it */ - strncat(data, stats[j].stats_string, size_left); - data += ETH_GSTRING_LEN; - } - } - - return data; + for (i = 0; i < num_tqps; i++) + for (j = 0; j < stat_count; j++) + ethtool_sprintf(data, "%s%u_%s", prefix, i, + stats[j].stats_string); } -static u8 *hns3_get_strings_tqps(struct hnae3_handle *handle, u8 *data) +static void hns3_get_strings_tqps(struct hnae3_handle *handle, u8 **data) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; const char tx_prefix[] = "txq"; const char rx_prefix[] = "rxq"; /* get strings for Tx */ - data = hns3_update_strings(data, hns3_txq_stats, HNS3_TXQ_STATS_COUNT, - kinfo->num_tqps, tx_prefix); + hns3_update_strings(data, hns3_txq_stats, HNS3_TXQ_STATS_COUNT, + kinfo->num_tqps, tx_prefix); /* get strings for Rx */ - data = hns3_update_strings(data, hns3_rxq_stats, HNS3_RXQ_STATS_COUNT, - kinfo->num_tqps, rx_prefix); - - return data; + hns3_update_strings(data, hns3_rxq_stats, HNS3_RXQ_STATS_COUNT, + kinfo->num_tqps, rx_prefix); } static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { struct hnae3_handle *h = hns3_get_handle(netdev); const struct hnae3_ae_ops *ops = h->ae_algo->ops; - char *buff = (char *)data; int i; if (!ops->get_strings) @@ -564,18 +547,15 @@ static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: - buff = hns3_get_strings_tqps(h, buff); - ops->get_strings(h, stringset, (u8 *)buff); + hns3_get_strings_tqps(h, &data); + ops->get_strings(h, stringset, &data); break; case ETH_SS_TEST: - ops->get_strings(h, stringset, data); + ops->get_strings(h, stringset, &data); break; case ETH_SS_PRIV_FLAGS: - for (i = 0; i < HNS3_PRIV_FLAGS_LEN; i++) { - snprintf(buff, ETH_GSTRING_LEN, "%s", - hns3_priv_flags[i].name); - buff += ETH_GSTRING_LEN; - } + for (i = 0; i < HNS3_PRIV_FLAGS_LEN; i++) + ethtool_puts(&data, hns3_priv_flags[i].name); break; default: break; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index bd86efd92a5a7d..05942fa78b115f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -594,25 +594,21 @@ static u64 *hclge_comm_get_stats(struct hclge_dev *hdev, return buf; } -static u8 *hclge_comm_get_strings(struct hclge_dev *hdev, u32 stringset, - const struct hclge_comm_stats_str strs[], - int size, u8 *data) +static void hclge_comm_get_strings(struct hclge_dev *hdev, u32 stringset, + const struct hclge_comm_stats_str strs[], + int size, u8 **data) { - char *buff = (char *)data; u32 i; if (stringset != ETH_SS_STATS) - return buff; + return; for (i = 0; i < size; i++) { if (strs[i].stats_num > hdev->ae_dev->dev_specs.mac_stats_num) continue; - snprintf(buff, ETH_GSTRING_LEN, "%s", strs[i].desc); - buff = buff + ETH_GSTRING_LEN; + ethtool_puts(data, strs[i].desc); } - - return (u8 *)buff; } static void hclge_update_stats_for_all(struct hclge_dev *hdev) @@ -717,44 +713,38 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) } static void hclge_get_strings(struct hnae3_handle *handle, u32 stringset, - u8 *data) + u8 **data) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; - u8 *p = (char *)data; + const char *str; int size; if (stringset == ETH_SS_STATS) { size = ARRAY_SIZE(g_mac_stats_string); - p = hclge_comm_get_strings(hdev, stringset, g_mac_stats_string, - size, p); - p = hclge_comm_tqps_get_strings(handle, p); + hclge_comm_get_strings(hdev, stringset, g_mac_stats_string, + size, data); + hclge_comm_tqps_get_strings(handle, data); } else if (stringset == ETH_SS_TEST) { if (handle->flags & HNAE3_SUPPORT_EXTERNAL_LOOPBACK) { - memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_EXTERNAL], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_EXTERNAL]; + ethtool_puts(data, str); } if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) { - memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_APP], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_APP]; + ethtool_puts(data, str); } if (handle->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK) { - memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES]; + ethtool_puts(data, str); } if (handle->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK) { - memcpy(p, - hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES]; + ethtool_puts(data, str); } if (handle->flags & HNAE3_SUPPORT_PHY_LOOPBACK) { - memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_PHY], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_PHY]; + ethtool_puts(data, str); } } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 094a7c7b55921f..2f6ffb88e70038 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -130,12 +130,10 @@ static int hclgevf_get_sset_count(struct hnae3_handle *handle, int strset) } static void hclgevf_get_strings(struct hnae3_handle *handle, u32 strset, - u8 *data) + u8 **data) { - u8 *p = (char *)data; - if (strset == ETH_SS_STATS) - p = hclge_comm_tqps_get_strings(handle, p); + hclge_comm_tqps_get_strings(handle, data); } static void hclgevf_get_stats(struct hnae3_handle *handle, u64 *data) diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c index 8a047145f0c50b..a1aa6c1f966ec6 100644 --- a/drivers/net/ethernet/hisilicon/hns_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns_mdio.c @@ -636,7 +636,7 @@ MODULE_DEVICE_TABLE(acpi, hns_mdio_acpi_match); static struct platform_driver hns_mdio_driver = { .probe = hns_mdio_probe, - .remove_new = hns_mdio_remove, + .remove = hns_mdio_remove, .driver = { .name = MDIO_DRV_NAME, .of_match_table = hns_mdio_match, diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c index 890f213da8d180..ae1f523d6841b5 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_main.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c @@ -172,6 +172,7 @@ static int create_txqs(struct hinic_dev *nic_dev) hinic_sq_dbgfs_uninit(nic_dev); devm_kfree(&netdev->dev, nic_dev->txqs); + nic_dev->txqs = NULL; return err; } @@ -268,6 +269,7 @@ static int create_rxqs(struct hinic_dev *nic_dev) hinic_rq_dbgfs_uninit(nic_dev); devm_kfree(&netdev->dev, nic_dev->rxqs); + nic_dev->rxqs = NULL; return err; } diff --git a/drivers/net/ethernet/i825xx/sni_82596.c b/drivers/net/ethernet/i825xx/sni_82596.c index 813403c2628f59..baa598988f47c8 100644 --- a/drivers/net/ethernet/i825xx/sni_82596.c +++ b/drivers/net/ethernet/i825xx/sni_82596.c @@ -168,7 +168,7 @@ static void sni_82596_driver_remove(struct platform_device *pdev) static struct platform_driver sni_82596_driver = { .probe = sni_82596_probe, - .remove_new = sni_82596_driver_remove, + .remove = sni_82596_driver_remove, .driver = { .name = sni_82596_string, }, diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index c41c3f1cc506ff..9b006bc353a1b7 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -121,7 +121,7 @@ static struct platform_driver ehea_driver = { .of_match_table = ehea_device_table, }, .probe = ehea_probe_adapter, - .remove_new = ehea_remove, + .remove = ehea_remove, }; void ehea_dump(void *adr, int len, char *msg) diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index dac570f3c11036..25b8a355600423 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -1727,6 +1727,7 @@ static inline int emac_rx_sg_append(struct emac_instance *dev, int slot) /* NAPI poll context */ static int emac_poll_rx(void *param, int budget) { + LIST_HEAD(rx_list); struct emac_instance *dev = param; int slot = dev->rx_slot, received = 0; @@ -1783,8 +1784,7 @@ static int emac_poll_rx(void *param, int budget) skb->protocol = eth_type_trans(skb, dev->ndev); emac_rx_csum(dev, skb, ctrl); - if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) - ++dev->estats.rx_dropped_stack; + list_add_tail(&skb->list, &rx_list); next: ++dev->stats.rx_packets; skip: @@ -1828,6 +1828,8 @@ static int emac_poll_rx(void *param, int budget) goto next; } + netif_receive_skb_list(&rx_list); + if (received) { DBG2(dev, "rx %d BDs" NL, received); dev->rx_slot = slot; @@ -2935,9 +2937,12 @@ static int emac_init_config(struct emac_instance *dev) /* Read MAC-address */ err = of_get_ethdev_address(np, dev->ndev); - if (err) - return dev_err_probe(&dev->ofdev->dev, err, - "Can't get valid [local-]mac-address from OF !\n"); + if (err == -EPROBE_DEFER) + return err; + if (err) { + dev_warn(&dev->ofdev->dev, "Can't get valid mac-address. Generating random."); + eth_hw_addr_random(dev->ndev); + } /* IAHT and GAHT filter parameterization */ if (emac_has_feature(dev, EMAC_FTR_EMAC4SYNC)) { @@ -3019,8 +3024,14 @@ static int emac_probe(struct platform_device *ofdev) SET_NETDEV_DEV(ndev, &ofdev->dev); /* Initialize some embedded data structures */ - mutex_init(&dev->mdio_lock); - mutex_init(&dev->link_lock); + err = devm_mutex_init(&ofdev->dev, &dev->mdio_lock); + if (err) + goto err_gone; + + err = devm_mutex_init(&ofdev->dev, &dev->link_lock); + if (err) + goto err_gone; + spin_lock_init(&dev->lock); INIT_WORK(&dev->reset_work, emac_reset_work); @@ -3029,15 +3040,8 @@ static int emac_probe(struct platform_device *ofdev) if (err) goto err_gone; - /* Get interrupts. EMAC irq is mandatory */ - dev->emac_irq = irq_of_parse_and_map(np, 0); - if (!dev->emac_irq) { - printk(KERN_ERR "%pOF: Can't map main interrupt\n", np); - err = -ENODEV; - goto err_gone; - } - /* Setup error IRQ handler */ + dev->emac_irq = platform_get_irq(ofdev, 0); err = devm_request_irq(&ofdev->dev, dev->emac_irq, emac_irq, 0, "EMAC", dev); if (err) { @@ -3048,12 +3052,10 @@ static int emac_probe(struct platform_device *ofdev) ndev->irq = dev->emac_irq; - /* Map EMAC regs */ - // TODO : platform_get_resource() and devm_ioremap_resource() - dev->emacp = devm_of_iomap(&ofdev->dev, np, 0, NULL); - if (!dev->emacp) { + dev->emacp = devm_platform_ioremap_resource(ofdev, 0); + if (IS_ERR(dev->emacp)) { dev_err(&ofdev->dev, "can't map device registers"); - err = -ENOMEM; + err = PTR_ERR(dev->emacp); goto err_gone; } @@ -3241,7 +3243,7 @@ static struct platform_driver emac_driver = { .of_match_table = emac_match, }, .probe = emac_probe, - .remove_new = emac_remove, + .remove = emac_remove, }; static void __init emac_make_bootlist(void) diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c index 99d5f83f7c60b5..7d70056e90081c 100644 --- a/drivers/net/ethernet/ibm/emac/mal.c +++ b/drivers/net/ethernet/ibm/emac/mal.c @@ -524,7 +524,8 @@ static int mal_probe(struct platform_device *ofdev) unsigned long irqflags; irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde; - mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL); + mal = devm_kzalloc(&ofdev->dev, sizeof(struct mal_instance), + GFP_KERNEL); if (!mal) return -ENOMEM; @@ -539,8 +540,7 @@ static int mal_probe(struct platform_device *ofdev) printk(KERN_ERR "mal%d: can't find MAL num-tx-chans property!\n", index); - err = -ENODEV; - goto fail; + return -ENODEV; } mal->num_tx_chans = prop[0]; @@ -549,8 +549,7 @@ static int mal_probe(struct platform_device *ofdev) printk(KERN_ERR "mal%d: can't find MAL num-rx-chans property!\n", index); - err = -ENODEV; - goto fail; + return -ENODEV; } mal->num_rx_chans = prop[0]; @@ -558,15 +557,13 @@ static int mal_probe(struct platform_device *ofdev) if (dcr_base == 0) { printk(KERN_ERR "mal%d: can't find DCR resource!\n", index); - err = -ENODEV; - goto fail; + return -ENODEV; } mal->dcr_host = dcr_map(ofdev->dev.of_node, dcr_base, 0x100); if (!DCR_MAP_OK(mal->dcr_host)) { printk(KERN_ERR "mal%d: failed to map DCRs !\n", index); - err = -ENODEV; - goto fail; + return -ENODEV; } if (of_device_is_compatible(ofdev->dev.of_node, "ibm,mcmal-405ez")) { @@ -582,25 +579,6 @@ static int mal_probe(struct platform_device *ofdev) #endif } - mal->txeob_irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); - mal->rxeob_irq = irq_of_parse_and_map(ofdev->dev.of_node, 1); - mal->serr_irq = irq_of_parse_and_map(ofdev->dev.of_node, 2); - - if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { - mal->txde_irq = mal->rxde_irq = mal->serr_irq; - } else { - mal->txde_irq = irq_of_parse_and_map(ofdev->dev.of_node, 3); - mal->rxde_irq = irq_of_parse_and_map(ofdev->dev.of_node, 4); - } - - if (!mal->txeob_irq || !mal->rxeob_irq || !mal->serr_irq || - !mal->txde_irq || !mal->rxde_irq) { - printk(KERN_ERR - "mal%d: failed to map interrupts !\n", index); - err = -ENODEV; - goto fail_unmap; - } - INIT_LIST_HEAD(&mal->poll_list); INIT_LIST_HEAD(&mal->list); spin_lock_init(&mal->lock); @@ -654,31 +632,43 @@ static int mal_probe(struct platform_device *ofdev) sizeof(struct mal_descriptor) * mal_rx_bd_offset(mal, i)); + mal->txeob_irq = platform_get_irq(ofdev, 0); + mal->rxeob_irq = platform_get_irq(ofdev, 1); + mal->serr_irq = platform_get_irq(ofdev, 2); + if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { + mal->txde_irq = mal->rxde_irq = mal->serr_irq; irqflags = IRQF_SHARED; hdlr_serr = hdlr_txde = hdlr_rxde = mal_int; } else { + mal->txde_irq = platform_get_irq(ofdev, 3); + mal->rxde_irq = platform_get_irq(ofdev, 4); irqflags = 0; hdlr_serr = mal_serr; hdlr_txde = mal_txde; hdlr_rxde = mal_rxde; } - err = request_irq(mal->serr_irq, hdlr_serr, irqflags, "MAL SERR", mal); + err = devm_request_irq(&ofdev->dev, mal->serr_irq, hdlr_serr, irqflags, + "MAL SERR", mal); if (err) goto fail2; - err = request_irq(mal->txde_irq, hdlr_txde, irqflags, "MAL TX DE", mal); + err = devm_request_irq(&ofdev->dev, mal->txde_irq, hdlr_txde, irqflags, + "MAL TX DE", mal); if (err) - goto fail3; - err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); + goto fail2; + err = devm_request_irq(&ofdev->dev, mal->txeob_irq, mal_txeob, 0, + "MAL TX EOB", mal); if (err) - goto fail4; - err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, "MAL RX DE", mal); + goto fail2; + err = devm_request_irq(&ofdev->dev, mal->rxde_irq, hdlr_rxde, irqflags, + "MAL RX DE", mal); if (err) - goto fail5; - err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); + goto fail2; + err = devm_request_irq(&ofdev->dev, mal->rxeob_irq, mal_rxeob, 0, + "MAL RX EOB", mal); if (err) - goto fail6; + goto fail2; /* Enable all MAL SERR interrupt sources */ set_mal_dcrn(mal, MAL_IER, MAL_IER_EVENTS); @@ -697,23 +687,12 @@ static int mal_probe(struct platform_device *ofdev) return 0; - fail6: - free_irq(mal->rxde_irq, mal); - fail5: - free_irq(mal->txeob_irq, mal); - fail4: - free_irq(mal->txde_irq, mal); - fail3: - free_irq(mal->serr_irq, mal); fail2: dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); fail_dummy: free_netdev(mal->dummy_dev); fail_unmap: dcr_unmap(mal->dcr_host, 0x100); - fail: - kfree(mal); - return err; } @@ -732,12 +711,6 @@ static void mal_remove(struct platform_device *ofdev) "mal%d: commac list is not empty on remove!\n", mal->index); - free_irq(mal->serr_irq, mal); - free_irq(mal->txde_irq, mal); - free_irq(mal->txeob_irq, mal); - free_irq(mal->rxde_irq, mal); - free_irq(mal->rxeob_irq, mal); - mal_reset(mal); free_netdev(mal->dummy_dev); @@ -746,10 +719,9 @@ static void mal_remove(struct platform_device *ofdev) dma_free_coherent(&ofdev->dev, sizeof(struct mal_descriptor) * - (NUM_TX_BUFF * mal->num_tx_chans + - NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt, - mal->bd_dma); - kfree(mal); + (NUM_TX_BUFF * mal->num_tx_chans + + NUM_RX_BUFF * mal->num_rx_chans), + mal->bd_virt, mal->bd_dma); } static const struct of_device_id mal_platform_match[] = @@ -778,7 +750,7 @@ static struct platform_driver mal_of_driver = { .of_match_table = mal_platform_match, }, .probe = mal_probe, - .remove_new = mal_remove, + .remove = mal_remove, }; int __init mal_init(void) diff --git a/drivers/net/ethernet/ibm/emac/rgmii.c b/drivers/net/ethernet/ibm/emac/rgmii.c index e1712fdc3c3189..b544dd8633b7b7 100644 --- a/drivers/net/ethernet/ibm/emac/rgmii.c +++ b/drivers/net/ethernet/ibm/emac/rgmii.c @@ -216,31 +216,24 @@ void *rgmii_dump_regs(struct platform_device *ofdev, void *buf) static int rgmii_probe(struct platform_device *ofdev) { - struct device_node *np = ofdev->dev.of_node; struct rgmii_instance *dev; - struct resource regs; - int rc; + int err; - rc = -ENOMEM; - dev = kzalloc(sizeof(struct rgmii_instance), GFP_KERNEL); - if (dev == NULL) - goto err_gone; + dev = devm_kzalloc(&ofdev->dev, sizeof(struct rgmii_instance), + GFP_KERNEL); + if (!dev) + return -ENOMEM; - mutex_init(&dev->lock); - dev->ofdev = ofdev; + err = devm_mutex_init(&ofdev->dev, &dev->lock); + if (err) + return err; - rc = -ENXIO; - if (of_address_to_resource(np, 0, ®s)) { - printk(KERN_ERR "%pOF: Can't get registers address\n", np); - goto err_free; - } + dev->ofdev = ofdev; - rc = -ENOMEM; - dev->base = (struct rgmii_regs __iomem *)ioremap(regs.start, - sizeof(struct rgmii_regs)); - if (dev->base == NULL) { - printk(KERN_ERR "%pOF: Can't map device registers!\n", np); - goto err_free; + dev->base = devm_platform_ioremap_resource(ofdev, 0); + if (IS_ERR(dev->base)) { + dev_err(&ofdev->dev, "can't map device registers"); + return PTR_ERR(dev->base); } /* Check for RGMII flags */ @@ -266,21 +259,6 @@ static int rgmii_probe(struct platform_device *ofdev) platform_set_drvdata(ofdev, dev); return 0; - - err_free: - kfree(dev); - err_gone: - return rc; -} - -static void rgmii_remove(struct platform_device *ofdev) -{ - struct rgmii_instance *dev = platform_get_drvdata(ofdev); - - WARN_ON(dev->users != 0); - - iounmap(dev->base); - kfree(dev); } static const struct of_device_id rgmii_match[] = @@ -300,7 +278,6 @@ static struct platform_driver rgmii_driver = { .of_match_table = rgmii_match, }, .probe = rgmii_probe, - .remove_new = rgmii_remove, }; int __init rgmii_init(void) diff --git a/drivers/net/ethernet/ibm/emac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c index fa3488258ca24e..09f6373ed2f90b 100644 --- a/drivers/net/ethernet/ibm/emac/tah.c +++ b/drivers/net/ethernet/ibm/emac/tah.c @@ -87,31 +87,24 @@ void *tah_dump_regs(struct platform_device *ofdev, void *buf) static int tah_probe(struct platform_device *ofdev) { - struct device_node *np = ofdev->dev.of_node; struct tah_instance *dev; - struct resource regs; - int rc; + int err; - rc = -ENOMEM; - dev = kzalloc(sizeof(struct tah_instance), GFP_KERNEL); - if (dev == NULL) - goto err_gone; + dev = devm_kzalloc(&ofdev->dev, sizeof(struct tah_instance), + GFP_KERNEL); + if (!dev) + return -ENOMEM; - mutex_init(&dev->lock); - dev->ofdev = ofdev; + err = devm_mutex_init(&ofdev->dev, &dev->lock); + if (err) + return err; - rc = -ENXIO; - if (of_address_to_resource(np, 0, ®s)) { - printk(KERN_ERR "%pOF: Can't get registers address\n", np); - goto err_free; - } + dev->ofdev = ofdev; - rc = -ENOMEM; - dev->base = (struct tah_regs __iomem *)ioremap(regs.start, - sizeof(struct tah_regs)); - if (dev->base == NULL) { - printk(KERN_ERR "%pOF: Can't map device registers!\n", np); - goto err_free; + dev->base = devm_platform_ioremap_resource(ofdev, 0); + if (IS_ERR(dev->base)) { + dev_err(&ofdev->dev, "can't map device registers"); + return PTR_ERR(dev->base); } platform_set_drvdata(ofdev, dev); @@ -123,21 +116,6 @@ static int tah_probe(struct platform_device *ofdev) wmb(); return 0; - - err_free: - kfree(dev); - err_gone: - return rc; -} - -static void tah_remove(struct platform_device *ofdev) -{ - struct tah_instance *dev = platform_get_drvdata(ofdev); - - WARN_ON(dev->users != 0); - - iounmap(dev->base); - kfree(dev); } static const struct of_device_id tah_match[] = @@ -158,7 +136,6 @@ static struct platform_driver tah_driver = { .of_match_table = tah_match, }, .probe = tah_probe, - .remove_new = tah_remove, }; int __init tah_init(void) diff --git a/drivers/net/ethernet/ibm/emac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c index 26e86cdee2f602..69ca6065de1c79 100644 --- a/drivers/net/ethernet/ibm/emac/zmii.c +++ b/drivers/net/ethernet/ibm/emac/zmii.c @@ -232,32 +232,25 @@ void *zmii_dump_regs(struct platform_device *ofdev, void *buf) static int zmii_probe(struct platform_device *ofdev) { - struct device_node *np = ofdev->dev.of_node; struct zmii_instance *dev; - struct resource regs; - int rc; + int err; - rc = -ENOMEM; - dev = kzalloc(sizeof(struct zmii_instance), GFP_KERNEL); - if (dev == NULL) - goto err_gone; + dev = devm_kzalloc(&ofdev->dev, sizeof(struct zmii_instance), + GFP_KERNEL); + if (!dev) + return -ENOMEM; + + err = devm_mutex_init(&ofdev->dev, &dev->lock); + if (err) + return err; - mutex_init(&dev->lock); dev->ofdev = ofdev; dev->mode = PHY_INTERFACE_MODE_NA; - rc = -ENXIO; - if (of_address_to_resource(np, 0, ®s)) { - printk(KERN_ERR "%pOF: Can't get registers address\n", np); - goto err_free; - } - - rc = -ENOMEM; - dev->base = (struct zmii_regs __iomem *)ioremap(regs.start, - sizeof(struct zmii_regs)); - if (dev->base == NULL) { - printk(KERN_ERR "%pOF: Can't map device registers!\n", np); - goto err_free; + dev->base = devm_platform_ioremap_resource(ofdev, 0); + if (IS_ERR(dev->base)) { + dev_err(&ofdev->dev, "can't map device registers"); + return PTR_ERR(dev->base); } /* We may need FER value for autodetection later */ @@ -271,21 +264,6 @@ static int zmii_probe(struct platform_device *ofdev) platform_set_drvdata(ofdev, dev); return 0; - - err_free: - kfree(dev); - err_gone: - return rc; -} - -static void zmii_remove(struct platform_device *ofdev) -{ - struct zmii_instance *dev = platform_get_drvdata(ofdev); - - WARN_ON(dev->users != 0); - - iounmap(dev->base); - kfree(dev); } static const struct of_device_id zmii_match[] = @@ -306,7 +284,6 @@ static struct platform_driver zmii_driver = { .of_match_table = zmii_match, }, .probe = zmii_probe, - .remove_new = zmii_remove, }; int __init zmii_init(void) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 97425c06e1ed7f..e95ae0d39948c8 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -2310,7 +2310,7 @@ static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter, tx_buff = &tx_pool->tx_buff[index]; adapter->netdev->stats.tx_packets--; adapter->netdev->stats.tx_bytes -= tx_buff->skb->len; - adapter->tx_stats_buffers[queue_num].packets--; + adapter->tx_stats_buffers[queue_num].batched_packets--; adapter->tx_stats_buffers[queue_num].bytes -= tx_buff->skb->len; dev_kfree_skb_any(tx_buff->skb); @@ -2402,7 +2402,8 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int tx_map_failed = 0; union sub_crq indir_arr[16]; unsigned int tx_dropped = 0; - unsigned int tx_packets = 0; + unsigned int tx_dpackets = 0; + unsigned int tx_bpackets = 0; unsigned int tx_bytes = 0; dma_addr_t data_dma_addr; struct netdev_queue *txq; @@ -2575,6 +2576,7 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) if (lpar_rc != H_SUCCESS) goto tx_err; + tx_dpackets++; goto early_exit; } @@ -2603,6 +2605,8 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) goto tx_err; } + tx_bpackets++; + early_exit: if (atomic_add_return(num_entries, &tx_scrq->used) >= adapter->req_tx_entries_per_subcrq) { @@ -2610,7 +2614,6 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) netif_stop_subqueue(netdev, queue_num); } - tx_packets++; tx_bytes += skb->len; txq_trans_cond_update(txq); ret = NETDEV_TX_OK; @@ -2640,10 +2643,11 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev) rcu_read_unlock(); netdev->stats.tx_dropped += tx_dropped; netdev->stats.tx_bytes += tx_bytes; - netdev->stats.tx_packets += tx_packets; + netdev->stats.tx_packets += tx_bpackets + tx_dpackets; adapter->tx_send_failed += tx_send_failed; adapter->tx_map_failed += tx_map_failed; - adapter->tx_stats_buffers[queue_num].packets += tx_packets; + adapter->tx_stats_buffers[queue_num].batched_packets += tx_bpackets; + adapter->tx_stats_buffers[queue_num].direct_packets += tx_dpackets; adapter->tx_stats_buffers[queue_num].bytes += tx_bytes; adapter->tx_stats_buffers[queue_num].dropped_packets += tx_dropped; @@ -3804,29 +3808,20 @@ static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data) if (stringset != ETH_SS_STATS) return; - for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++, data += ETH_GSTRING_LEN) - memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN); + for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++) + ethtool_puts(&data, ibmvnic_stats[i].name); for (i = 0; i < adapter->req_tx_queues; i++) { - snprintf(data, ETH_GSTRING_LEN, "tx%d_packets", i); - data += ETH_GSTRING_LEN; - - snprintf(data, ETH_GSTRING_LEN, "tx%d_bytes", i); - data += ETH_GSTRING_LEN; - - snprintf(data, ETH_GSTRING_LEN, "tx%d_dropped_packets", i); - data += ETH_GSTRING_LEN; + ethtool_sprintf(&data, "tx%d_batched_packets", i); + ethtool_sprintf(&data, "tx%d_direct_packets", i); + ethtool_sprintf(&data, "tx%d_bytes", i); + ethtool_sprintf(&data, "tx%d_dropped_packets", i); } for (i = 0; i < adapter->req_rx_queues; i++) { - snprintf(data, ETH_GSTRING_LEN, "rx%d_packets", i); - data += ETH_GSTRING_LEN; - - snprintf(data, ETH_GSTRING_LEN, "rx%d_bytes", i); - data += ETH_GSTRING_LEN; - - snprintf(data, ETH_GSTRING_LEN, "rx%d_interrupts", i); - data += ETH_GSTRING_LEN; + ethtool_sprintf(&data, "rx%d_packets", i); + ethtool_sprintf(&data, "rx%d_bytes", i); + ethtool_sprintf(&data, "rx%d_interrupts", i); } } @@ -3873,7 +3868,9 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev, (adapter, ibmvnic_stats[i].offset)); for (j = 0; j < adapter->req_tx_queues; j++) { - data[i] = adapter->tx_stats_buffers[j].packets; + data[i] = adapter->tx_stats_buffers[j].batched_packets; + i++; + data[i] = adapter->tx_stats_buffers[j].direct_packets; i++; data[i] = adapter->tx_stats_buffers[j].bytes; i++; diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h index 94ac36b1408be9..a189038d88df03 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.h +++ b/drivers/net/ethernet/ibm/ibmvnic.h @@ -213,7 +213,8 @@ struct ibmvnic_statistics { #define NUM_TX_STATS 3 struct ibmvnic_tx_queue_stats { - u64 packets; + u64 batched_packets; + u64 direct_packets; u64 bytes; u64 dropped_packets; }; diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 0375c7448a5734..20bc40eec487a3 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -258,6 +258,7 @@ config I40E_DCB config IAVF tristate select LIBIE + select NET_SHAPER config I40EVF tristate "Intel(R) Ethernet Adaptive Virtual Function support" diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index ab7ae418d29485..3f089c3d47b23b 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -513,6 +513,8 @@ void e1000_down(struct e1000_adapter *adapter) */ netif_carrier_off(netdev); + netif_queue_set_napi(netdev, 0, NETDEV_QUEUE_TYPE_RX, NULL); + netif_queue_set_napi(netdev, 0, NETDEV_QUEUE_TYPE_TX, NULL); napi_disable(&adapter->napi); e1000_irq_disable(adapter); @@ -1392,7 +1394,10 @@ int e1000_open(struct net_device *netdev) /* From here on the code is the same as e1000_up() */ clear_bit(__E1000_DOWN, &adapter->flags); + netif_napi_set_irq(&adapter->napi, adapter->pdev->irq); napi_enable(&adapter->napi); + netif_queue_set_napi(netdev, 0, NETDEV_QUEUE_TYPE_RX, &adapter->napi); + netif_queue_set_napi(netdev, 0, NETDEV_QUEUE_TYPE_TX, &adapter->napi); e1000_irq_enable(adapter); @@ -3504,7 +3509,9 @@ static void e1000_reset_task(struct work_struct *work) container_of(work, struct e1000_adapter, reset_task); e_err(drv, "Reset adapter\n"); + rtnl_lock(); e1000_reinit_locked(adapter); + rtnl_unlock(); } /** @@ -5069,7 +5076,9 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) usleep_range(10000, 20000); WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags)); + rtnl_lock(); e1000_down(adapter); + rtnl_unlock(); } status = er32(STATUS); @@ -5230,16 +5239,20 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); + rtnl_lock(); netif_device_detach(netdev); - if (state == pci_channel_io_perm_failure) + if (state == pci_channel_io_perm_failure) { + rtnl_unlock(); return PCI_ERS_RESULT_DISCONNECT; + } if (netif_running(netdev)) e1000_down(adapter); if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags)) pci_disable_device(pdev); + rtnl_unlock(); /* Request a slot reset. */ return PCI_ERS_RESULT_NEED_RESET; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 07e90334635824..286155efcedf7a 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -2928,11 +2928,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter) tx_ring->head = adapter->hw.hw_addr + E1000_TDH(0); tx_ring->tail = adapter->hw.hw_addr + E1000_TDT(0); - writel(0, tx_ring->head); if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) e1000e_update_tdt_wa(tx_ring, 0); - else - writel(0, tx_ring->tail); /* Set the Tx Interrupt Delay register */ ew32(TIDV, adapter->tx_int_delay); @@ -3253,11 +3250,8 @@ static void e1000_configure_rx(struct e1000_adapter *adapter) rx_ring->head = adapter->hw.hw_addr + E1000_RDH(0); rx_ring->tail = adapter->hw.hw_addr + E1000_RDT(0); - writel(0, rx_ring->head); if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) e1000e_update_rdt_wa(rx_ring, 0); - else - writel(0, rx_ring->tail); /* Enable Receive Checksum Offload for TCP and UDP */ rxcsum = er32(RXCSUM); @@ -4613,6 +4607,7 @@ int e1000e_open(struct net_device *netdev) struct e1000_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; int err; + int irq; /* disallow open during test */ if (test_bit(__E1000_TESTING, &adapter->state)) @@ -4676,7 +4671,15 @@ int e1000e_open(struct net_device *netdev) /* From here on the code is the same as e1000e_up() */ clear_bit(__E1000_DOWN, &adapter->state); + if (adapter->int_mode == E1000E_INT_MODE_MSIX) + irq = adapter->msix_entries[0].vector; + else + irq = adapter->pdev->irq; + + netif_napi_set_irq(&adapter->napi, irq); napi_enable(&adapter->napi); + netif_queue_set_napi(netdev, 0, NETDEV_QUEUE_TYPE_RX, &adapter->napi); + netif_queue_set_napi(netdev, 0, NETDEV_QUEUE_TYPE_TX, &adapter->napi); e1000_irq_enable(adapter); @@ -4735,6 +4738,8 @@ int e1000e_close(struct net_device *netdev) netdev_info(netdev, "NIC Link is Down\n"); } + netif_queue_set_napi(netdev, 0, NETDEV_QUEUE_TYPE_RX, NULL); + netif_queue_set_napi(netdev, 0, NETDEV_QUEUE_TYPE_TX, NULL); napi_disable(&adapter->napi); e1000e_free_tx_resources(adapter->tx_ring); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f2506511bbfff4..bce5b76f1e7a58 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5299,7 +5299,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) } flags_complete: - bitmap_xor(changed_flags, pf->flags, orig_flags, I40E_PF_FLAGS_NBITS); + bitmap_xor(changed_flags, new_flags, orig_flags, I40E_PF_FLAGS_NBITS); if (test_bit(I40E_FLAG_FW_LLDP_DIS, changed_flags)) reset_needed = I40E_PF_RESET_AND_REBUILD_FLAG; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 55fb362eb50816..0e1d9e2fbf38cc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -99,7 +99,7 @@ module_param(debug, uint, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all), Debug mask (0x8XXXXXXX)"); MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver"); -MODULE_IMPORT_NS(LIBIE); +MODULE_IMPORT_NS("LIBIE"); MODULE_LICENSE("GPL v2"); static struct workqueue_struct *i40e_wq; @@ -13095,12 +13095,13 @@ static int i40e_get_phys_port_id(struct net_device *netdev, * @addr: the MAC address entry being added * @vid: VLAN ID * @flags: instructions from stack about fdb operation + * @notified: whether notification was emitted * @extack: netlink extended ack, unused currently */ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags, + u16 flags, bool *notified, struct netlink_ext_ack *extack) { struct i40e_netdev_priv *np = netdev_priv(dev); diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index 48cd1d06761c86..532a0a595fe8e6 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "iavf_type.h" #include @@ -250,6 +251,9 @@ struct iavf_cloud_filter { #define IAVF_RESET_WAIT_DETECTED_COUNT 500 #define IAVF_RESET_WAIT_COMPLETE_COUNT 2000 +#define IAVF_MAX_QOS_TC_NUM 8 +#define IAVF_DEFAULT_QUANTA_SIZE 1024 + /* board specific private data structure */ struct iavf_adapter { struct workqueue_struct *wq; @@ -336,6 +340,9 @@ struct iavf_adapter { #define IAVF_FLAG_AQ_DISABLE_CTAG_VLAN_INSERTION BIT_ULL(36) #define IAVF_FLAG_AQ_ENABLE_STAG_VLAN_INSERTION BIT_ULL(37) #define IAVF_FLAG_AQ_DISABLE_STAG_VLAN_INSERTION BIT_ULL(38) +#define IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW BIT_ULL(39) +#define IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE BIT_ULL(40) +#define IAVF_FLAG_AQ_GET_QOS_CAPS BIT_ULL(41) /* flags for processing extended capability messages during * __IAVF_INIT_EXTENDED_CAPS. Each capability exchange requires @@ -408,6 +415,8 @@ struct iavf_adapter { VIRTCHNL_VF_OFFLOAD_FDIR_PF) #define ADV_RSS_SUPPORT(_a) ((_a)->vf_res->vf_cap_flags & \ VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF) +#define QOS_ALLOWED(_a) ((_a)->vf_res->vf_cap_flags & \ + VIRTCHNL_VF_OFFLOAD_QOS) struct virtchnl_vf_resource *vf_res; /* incl. all VSIs */ struct virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ struct virtchnl_version_info pf_version; @@ -416,6 +425,7 @@ struct iavf_adapter { struct virtchnl_vlan_caps vlan_v2_caps; u16 msg_enable; struct iavf_eth_stats current_stats; + struct virtchnl_qos_cap_list *qos_caps; struct iavf_vsi vsi; u32 aq_wait_count; /* RSS stuff */ @@ -529,22 +539,16 @@ static inline void iavf_change_state(struct iavf_adapter *adapter, iavf_state_str(adapter->state)); } -int iavf_up(struct iavf_adapter *adapter); void iavf_down(struct iavf_adapter *adapter); int iavf_process_config(struct iavf_adapter *adapter); int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter); void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags); void iavf_schedule_aq_request(struct iavf_adapter *adapter, u64 flags); void iavf_schedule_finish_config(struct iavf_adapter *adapter); -void iavf_reset(struct iavf_adapter *adapter); void iavf_set_ethtool_ops(struct net_device *netdev); -void iavf_update_stats(struct iavf_adapter *adapter); void iavf_free_all_tx_resources(struct iavf_adapter *adapter); void iavf_free_all_rx_resources(struct iavf_adapter *adapter); -void iavf_napi_add_all(struct iavf_adapter *adapter); -void iavf_napi_del_all(struct iavf_adapter *adapter); - int iavf_send_api_ver(struct iavf_adapter *adapter); int iavf_verify_api_ver(struct iavf_adapter *adapter); int iavf_send_vf_config_msg(struct iavf_adapter *adapter); @@ -555,11 +559,9 @@ void iavf_set_queue_vlan_tag_loc(struct iavf_adapter *adapter); u16 iavf_get_num_vlans_added(struct iavf_adapter *adapter); void iavf_irq_enable(struct iavf_adapter *adapter, bool flush); void iavf_configure_queues(struct iavf_adapter *adapter); -void iavf_deconfigure_queues(struct iavf_adapter *adapter); void iavf_enable_queues(struct iavf_adapter *adapter); void iavf_disable_queues(struct iavf_adapter *adapter); void iavf_map_queues(struct iavf_adapter *adapter); -int iavf_request_queues(struct iavf_adapter *adapter, int num); void iavf_add_ether_addrs(struct iavf_adapter *adapter); void iavf_del_ether_addrs(struct iavf_adapter *adapter); void iavf_add_vlans(struct iavf_adapter *adapter); @@ -579,8 +581,9 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, enum virtchnl_ops v_opcode, enum iavf_status v_retval, u8 *msg, u16 msglen); int iavf_config_rss(struct iavf_adapter *adapter); -int iavf_lan_add_device(struct iavf_adapter *adapter); -int iavf_lan_del_device(struct iavf_adapter *adapter); +void iavf_cfg_queues_bw(struct iavf_adapter *adapter); +void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter); +void iavf_get_qos_caps(struct iavf_adapter *adapter); void iavf_enable_channels(struct iavf_adapter *adapter); void iavf_disable_channels(struct iavf_adapter *adapter); void iavf_add_cloud_filter(struct iavf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index f782402cd78986..a9e54866ae6bfa 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -46,8 +46,8 @@ MODULE_DEVICE_TABLE(pci, iavf_pci_tbl); MODULE_ALIAS("i40evf"); MODULE_DESCRIPTION("Intel(R) Ethernet Adaptive Virtual Function Network Driver"); -MODULE_IMPORT_NS(LIBETH); -MODULE_IMPORT_NS(LIBIE); +MODULE_IMPORT_NS("LIBETH"); +MODULE_IMPORT_NS("LIBIE"); MODULE_LICENSE("GPL v2"); static const struct net_device_ops iavf_netdev_ops; @@ -1972,8 +1972,11 @@ static void iavf_finish_config(struct work_struct *work) adapter = container_of(work, struct iavf_adapter, finish_config); - /* Always take RTNL first to prevent circular lock dependency */ + /* Always take RTNL first to prevent circular lock dependency; + * The dev->lock is needed to update the queue number + */ rtnl_lock(); + mutex_lock(&adapter->netdev->lock); mutex_lock(&adapter->crit_lock); if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES) && @@ -2017,6 +2020,7 @@ static void iavf_finish_config(struct work_struct *work) out: mutex_unlock(&adapter->crit_lock); + mutex_unlock(&adapter->netdev->lock); rtnl_unlock(); } @@ -2085,6 +2089,21 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter) return 0; } + if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW) { + iavf_cfg_queues_bw(adapter); + return 0; + } + + if (adapter->aq_required & IAVF_FLAG_AQ_GET_QOS_CAPS) { + iavf_get_qos_caps(adapter); + return 0; + } + + if (adapter->aq_required & IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE) { + iavf_cfg_queues_quanta_size(adapter); + return 0; + } + if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_QUEUES) { iavf_configure_queues(adapter); return 0; @@ -2670,6 +2689,9 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter) /* request initial VLAN offload settings */ iavf_set_vlan_offload_features(adapter, 0, netdev->features); + if (QOS_ALLOWED(adapter)) + adapter->aq_required |= IAVF_FLAG_AQ_GET_QOS_CAPS; + iavf_schedule_finish_config(adapter); return; @@ -2918,6 +2940,30 @@ static void iavf_disable_vf(struct iavf_adapter *adapter) dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n"); } +/** + * iavf_reconfig_qs_bw - Call-back task to handle hardware reset + * @adapter: board private structure + * + * After a reset, the shaper parameters of queues need to be replayed again. + * Since the net_shaper object inside TX rings persists across reset, + * set the update flag for all queues so that the virtchnl message is triggered + * for all queues. + **/ +static void iavf_reconfig_qs_bw(struct iavf_adapter *adapter) +{ + int i, num = 0; + + for (i = 0; i < adapter->num_active_queues; i++) + if (adapter->tx_rings[i].q_shaper.bw_min || + adapter->tx_rings[i].q_shaper.bw_max) { + adapter->tx_rings[i].q_shaper_update = true; + num++; + } + + if (num) + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW; +} + /** * iavf_reset_task - Call-back task to handle hardware reset * @work: pointer to work_struct @@ -2944,10 +2990,12 @@ static void iavf_reset_task(struct work_struct *work) /* When device is being removed it doesn't make sense to run the reset * task, just return in such a case. */ + mutex_lock(&netdev->lock); if (!mutex_trylock(&adapter->crit_lock)) { if (adapter->state != __IAVF_REMOVE) queue_work(adapter->wq, &adapter->reset_task); + mutex_unlock(&netdev->lock); return; } @@ -2995,6 +3043,7 @@ static void iavf_reset_task(struct work_struct *work) reg_val); iavf_disable_vf(adapter); mutex_unlock(&adapter->crit_lock); + mutex_unlock(&netdev->lock); return; /* Do not attempt to reinit. It's dead, Jim. */ } @@ -3124,6 +3173,8 @@ static void iavf_reset_task(struct work_struct *work) iavf_up_complete(adapter); iavf_irq_enable(adapter, true); + + iavf_reconfig_qs_bw(adapter); } else { iavf_change_state(adapter, __IAVF_DOWN); wake_up(&adapter->down_waitqueue); @@ -3133,6 +3184,7 @@ static void iavf_reset_task(struct work_struct *work) wake_up(&adapter->reset_waitqueue); mutex_unlock(&adapter->crit_lock); + mutex_unlock(&netdev->lock); return; reset_err: @@ -3143,6 +3195,7 @@ static void iavf_reset_task(struct work_struct *work) iavf_disable_vf(adapter); mutex_unlock(&adapter->crit_lock); + mutex_unlock(&netdev->lock); dev_err(&adapter->pdev->dev, "failed to allocate resources during reinit\n"); } @@ -3614,8 +3667,10 @@ static int __iavf_setup_tc(struct net_device *netdev, void *type_data) if (test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) return 0; + mutex_lock(&netdev->lock); netif_set_real_num_rx_queues(netdev, total_qps); netif_set_real_num_tx_queues(netdev, total_qps); + mutex_unlock(&netdev->lock); return ret; } @@ -4893,6 +4948,98 @@ static netdev_features_t iavf_fix_features(struct net_device *netdev, return iavf_fix_strip_features(adapter, features); } +static int +iavf_verify_shaper(struct net_shaper_binding *binding, + const struct net_shaper *shaper, + struct netlink_ext_ack *extack) +{ + struct iavf_adapter *adapter = netdev_priv(binding->netdev); + u64 vf_max; + + if (shaper->handle.scope == NET_SHAPER_SCOPE_QUEUE) { + vf_max = adapter->qos_caps->cap[0].shaper.peak; + if (vf_max && shaper->bw_max > vf_max) { + NL_SET_ERR_MSG_FMT(extack, "Max rate (%llu) of queue %d can't exceed max TX rate of VF (%llu kbps)", + shaper->bw_max, shaper->handle.id, + vf_max); + return -EINVAL; + } + } + return 0; +} + +static int +iavf_shaper_set(struct net_shaper_binding *binding, + const struct net_shaper *shaper, + struct netlink_ext_ack *extack) +{ + struct iavf_adapter *adapter = netdev_priv(binding->netdev); + const struct net_shaper_handle *handle = &shaper->handle; + struct iavf_ring *tx_ring; + int ret = 0; + + mutex_lock(&adapter->crit_lock); + if (handle->id >= adapter->num_active_queues) + goto unlock; + + ret = iavf_verify_shaper(binding, shaper, extack); + if (ret) + goto unlock; + + tx_ring = &adapter->tx_rings[handle->id]; + + tx_ring->q_shaper.bw_min = div_u64(shaper->bw_min, 1000); + tx_ring->q_shaper.bw_max = div_u64(shaper->bw_max, 1000); + tx_ring->q_shaper_update = true; + + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW; + +unlock: + mutex_unlock(&adapter->crit_lock); + return ret; +} + +static int iavf_shaper_del(struct net_shaper_binding *binding, + const struct net_shaper_handle *handle, + struct netlink_ext_ack *extack) +{ + struct iavf_adapter *adapter = netdev_priv(binding->netdev); + struct iavf_ring *tx_ring; + + mutex_lock(&adapter->crit_lock); + if (handle->id >= adapter->num_active_queues) + goto unlock; + + tx_ring = &adapter->tx_rings[handle->id]; + tx_ring->q_shaper.bw_min = 0; + tx_ring->q_shaper.bw_max = 0; + tx_ring->q_shaper_update = true; + + adapter->aq_required |= IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW; + +unlock: + mutex_unlock(&adapter->crit_lock); + return 0; +} + +static void iavf_shaper_cap(struct net_shaper_binding *binding, + enum net_shaper_scope scope, + unsigned long *flags) +{ + if (scope != NET_SHAPER_SCOPE_QUEUE) + return; + + *flags = BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MIN) | + BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MAX) | + BIT(NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS); +} + +static const struct net_shaper_ops iavf_shaper_ops = { + .set = iavf_shaper_set, + .delete = iavf_shaper_del, + .capabilities = iavf_shaper_cap, +}; + static const struct net_device_ops iavf_netdev_ops = { .ndo_open = iavf_open, .ndo_stop = iavf_close, @@ -4908,6 +5055,7 @@ static const struct net_device_ops iavf_netdev_ops = { .ndo_fix_features = iavf_fix_features, .ndo_set_features = iavf_set_features, .ndo_setup_tc = iavf_setup_tc, + .net_shaper_ops = &iavf_shaper_ops, }; /** @@ -5054,7 +5202,7 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *netdev; struct iavf_adapter *adapter = NULL; struct iavf_hw *hw = NULL; - int err; + int err, len; err = pci_enable_device(pdev); if (err) @@ -5122,6 +5270,13 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->bus.func = PCI_FUNC(pdev->devfn); hw->bus.bus_id = pdev->bus->number; + len = struct_size(adapter->qos_caps, cap, IAVF_MAX_QOS_TC_NUM); + adapter->qos_caps = kzalloc(len, GFP_KERNEL); + if (!adapter->qos_caps) { + err = -ENOMEM; + goto err_alloc_qos_cap; + } + /* set up the locks for the AQ, do this only once in probe * and destroy them only once in remove */ @@ -5160,6 +5315,8 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Initialization goes on in the work. Do not add more of it below. */ return 0; +err_alloc_qos_cap: + iounmap(hw->hw_addr); err_ioremap: destroy_workqueue(adapter->wq); err_alloc_wq: diff --git a/drivers/net/ethernet/intel/iavf/iavf_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h index 48c3901381b4a0..cac9d1a35a527a 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_prototype.h +++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h @@ -18,7 +18,6 @@ /* adminq functions */ enum iavf_status iavf_init_adminq(struct iavf_hw *hw); enum iavf_status iavf_shutdown_adminq(struct iavf_hw *hw); -void iavf_adminq_init_ring_data(struct iavf_hw *hw); enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw, struct iavf_arq_event_info *e, u16 *events_pending); @@ -33,8 +32,6 @@ bool iavf_asq_done(struct iavf_hw *hw); void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask, void *desc, void *buffer, u16 buf_len); -void iavf_idle_aq(struct iavf_hw *hw); -void iavf_resume_aq(struct iavf_hw *hw); bool iavf_check_asq_alive(struct iavf_hw *hw); enum iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading); const char *iavf_aq_str(struct iavf_hw *hw, enum iavf_admin_queue_err aq_err); diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h index d7b5587aeb8e82..f97c702c0802d1 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.h +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.h @@ -296,6 +296,8 @@ struct iavf_ring { */ u32 rx_buf_len; + struct net_shaper q_shaper; + bool q_shaper_update; } ____cacheline_internodealigned_in_smp; #define IAVF_ITR_ADAPTIVE_MIN_INC 0x0002 diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 7e810b65380ca3..15d388b431c512 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -151,7 +151,8 @@ int iavf_send_vf_config_msg(struct iavf_adapter *adapter) VIRTCHNL_VF_OFFLOAD_USO | VIRTCHNL_VF_OFFLOAD_FDIR_PF | VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF | - VIRTCHNL_VF_CAP_ADV_LINK_SPEED; + VIRTCHNL_VF_CAP_ADV_LINK_SPEED | + VIRTCHNL_VF_OFFLOAD_QOS; adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES; adapter->aq_required &= ~IAVF_FLAG_AQ_GET_CONFIG; @@ -1507,6 +1508,130 @@ iavf_set_adapter_link_speed_from_vpe(struct iavf_adapter *adapter, adapter->link_speed = vpe->event_data.link_event.link_speed; } +/** + * iavf_get_qos_caps - get qos caps support + * @adapter: iavf adapter struct instance + * + * This function requests PF for Supported QoS Caps. + */ +void iavf_get_qos_caps(struct iavf_adapter *adapter) +{ + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { + /* bail because we already have a command pending */ + dev_err(&adapter->pdev->dev, + "Cannot get qos caps, command %d pending\n", + adapter->current_op); + return; + } + + adapter->current_op = VIRTCHNL_OP_GET_QOS_CAPS; + adapter->aq_required &= ~IAVF_FLAG_AQ_GET_QOS_CAPS; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_GET_QOS_CAPS, NULL, 0); +} + +/** + * iavf_set_quanta_size - set quanta size of queue chunk + * @adapter: iavf adapter struct instance + * @quanta_size: quanta size in bytes + * @queue_index: starting index of queue chunk + * @num_queues: number of queues in the queue chunk + * + * This function requests PF to set quanta size of queue chunk + * starting at queue_index. + */ +static void +iavf_set_quanta_size(struct iavf_adapter *adapter, u16 quanta_size, + u16 queue_index, u16 num_queues) +{ + struct virtchnl_quanta_cfg quanta_cfg; + + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { + /* bail because we already have a command pending */ + dev_err(&adapter->pdev->dev, + "Cannot set queue quanta size, command %d pending\n", + adapter->current_op); + return; + } + + adapter->current_op = VIRTCHNL_OP_CONFIG_QUANTA; + quanta_cfg.quanta_size = quanta_size; + quanta_cfg.queue_select.type = VIRTCHNL_QUEUE_TYPE_TX; + quanta_cfg.queue_select.start_queue_id = queue_index; + quanta_cfg.queue_select.num_queues = num_queues; + adapter->aq_required &= ~IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_QUANTA, + (u8 *)&quanta_cfg, sizeof(quanta_cfg)); +} + +/** + * iavf_cfg_queues_quanta_size - configure quanta size of queues + * @adapter: adapter structure + * + * Request that the PF configure quanta size of allocated queues. + **/ +void iavf_cfg_queues_quanta_size(struct iavf_adapter *adapter) +{ + int quanta_size = IAVF_DEFAULT_QUANTA_SIZE; + + /* Set Queue Quanta Size to default */ + iavf_set_quanta_size(adapter, quanta_size, 0, + adapter->num_active_queues); +} + +/** + * iavf_cfg_queues_bw - configure bandwidth of allocated queues + * @adapter: iavf adapter structure instance + * + * This function requests PF to configure queue bandwidth of allocated queues + */ +void iavf_cfg_queues_bw(struct iavf_adapter *adapter) +{ + struct virtchnl_queues_bw_cfg *qs_bw_cfg; + struct net_shaper *q_shaper; + int qs_to_update = 0; + int i, inx = 0; + size_t len; + + if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) { + /* bail because we already have a command pending */ + dev_err(&adapter->pdev->dev, + "Cannot set tc queue bw, command %d pending\n", + adapter->current_op); + return; + } + + for (i = 0; i < adapter->num_active_queues; i++) { + if (adapter->tx_rings[i].q_shaper_update) + qs_to_update++; + } + len = struct_size(qs_bw_cfg, cfg, qs_to_update); + qs_bw_cfg = kzalloc(len, GFP_KERNEL); + if (!qs_bw_cfg) + return; + + qs_bw_cfg->vsi_id = adapter->vsi.id; + qs_bw_cfg->num_queues = qs_to_update; + + for (i = 0; i < adapter->num_active_queues; i++) { + struct iavf_ring *tx_ring = &adapter->tx_rings[i]; + + q_shaper = &tx_ring->q_shaper; + if (tx_ring->q_shaper_update) { + qs_bw_cfg->cfg[inx].queue_id = i; + qs_bw_cfg->cfg[inx].shaper.peak = q_shaper->bw_max; + qs_bw_cfg->cfg[inx].shaper.committed = q_shaper->bw_min; + qs_bw_cfg->cfg[inx].tc = 0; + inx++; + } + } + + adapter->current_op = VIRTCHNL_OP_CONFIG_QUEUE_BW; + adapter->aq_required &= ~IAVF_FLAG_AQ_CONFIGURE_QUEUES_BW; + iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_QUEUE_BW, + (u8 *)qs_bw_cfg, len); + kfree(qs_bw_cfg); +} + /** * iavf_enable_channels * @adapter: adapter structure @@ -2227,6 +2352,18 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC; break; + case VIRTCHNL_OP_GET_QOS_CAPS: + dev_warn(&adapter->pdev->dev, "Failed to Get Qos CAPs, error %s\n", + iavf_stat_str(&adapter->hw, v_retval)); + break; + case VIRTCHNL_OP_CONFIG_QUANTA: + dev_warn(&adapter->pdev->dev, "Failed to Config Quanta, error %s\n", + iavf_stat_str(&adapter->hw, v_retval)); + break; + case VIRTCHNL_OP_CONFIG_QUEUE_BW: + dev_warn(&adapter->pdev->dev, "Failed to Config Queue BW, error %s\n", + iavf_stat_str(&adapter->hw, v_retval)); + break; default: dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n", v_retval, iavf_stat_str(&adapter->hw, v_retval), @@ -2569,6 +2706,24 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, if (!v_retval) iavf_netdev_features_vlan_strip_set(netdev, false); break; + case VIRTCHNL_OP_GET_QOS_CAPS: { + u16 len = struct_size(adapter->qos_caps, cap, + IAVF_MAX_QOS_TC_NUM); + + memcpy(adapter->qos_caps, msg, min(msglen, len)); + + adapter->aq_required |= IAVF_FLAG_AQ_CFG_QUEUES_QUANTA_SIZE; + } + break; + case VIRTCHNL_OP_CONFIG_QUANTA: + break; + case VIRTCHNL_OP_CONFIG_QUEUE_BW: { + int i; + /* shaper configuration is successful for all queues */ + for (i = 0; i < adapter->num_active_queues; i++) + adapter->tx_rings[i].q_shaper_update = false; + } + break; default: if (adapter->current_op && (v_opcode != adapter->current_op)) dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n", diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index d6f80da30decf4..2f5d6f974185a3 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -181,11 +181,9 @@ #define ice_for_each_chnl_tc(i) \ for ((i) = ICE_CHNL_START_TC; (i) < ICE_CHNL_MAX_TC; (i)++) -#define ICE_UCAST_PROMISC_BITS (ICE_PROMISC_UCAST_TX | ICE_PROMISC_UCAST_RX) +#define ICE_UCAST_PROMISC_BITS ICE_PROMISC_UCAST_RX -#define ICE_UCAST_VLAN_PROMISC_BITS (ICE_PROMISC_UCAST_TX | \ - ICE_PROMISC_UCAST_RX | \ - ICE_PROMISC_VLAN_TX | \ +#define ICE_UCAST_VLAN_PROMISC_BITS (ICE_PROMISC_UCAST_RX | \ ICE_PROMISC_VLAN_RX) #define ICE_MCAST_PROMISC_BITS (ICE_PROMISC_MCAST_TX | ICE_PROMISC_MCAST_RX) @@ -207,6 +205,7 @@ enum ice_feature { ICE_F_GNSS, ICE_F_ROCE_LAG, ICE_F_SRIOV_LAG, + ICE_F_MBX_LIMIT, ICE_F_MAX }; @@ -371,9 +370,6 @@ struct ice_vsi { spinlock_t arfs_lock; /* protects aRFS hash table and filter state */ atomic_t *arfs_last_fltr_id; - u16 max_frame; - u16 rx_buf_len; - struct ice_aqc_vsi_props info; /* VSI properties */ struct ice_vsi_vlan_info vlan_info; /* vlan config to be restored */ @@ -669,6 +665,8 @@ struct ice_pf { struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES]; struct ice_dplls dplls; struct device *hwmon_dev; + + u8 num_quanta_prof_used; }; extern struct workqueue_struct *ice_lag_wq; @@ -1047,5 +1045,10 @@ static inline void ice_clear_rdma_cap(struct ice_pf *pf) clear_bit(ICE_FLAG_RDMA_ENA, pf->flags); } +static inline enum ice_phy_model ice_get_phy_model(const struct ice_hw *hw) +{ + return hw->ptp.phy_model; +} + extern const struct xdp_metadata_ops ice_xdp_md_ops; #endif /* _ICE_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.c b/drivers/net/ethernet/intel/ice/ice_adapter.c index ad84d8ad49a63f..01a08cfd0090ac 100644 --- a/drivers/net/ethernet/intel/ice/ice_adapter.c +++ b/drivers/net/ethernet/intel/ice/ice_adapter.c @@ -9,12 +9,14 @@ #include #include #include "ice_adapter.h" +#include "ice.h" static DEFINE_XARRAY(ice_adapters); static DEFINE_MUTEX(ice_adapters_mutex); /* PCI bus number is 8 bits. Slot is 5 bits. Domain can have the rest. */ #define INDEX_FIELD_DOMAIN GENMASK(BITS_PER_LONG - 1, 13) +#define INDEX_FIELD_DEV GENMASK(31, 16) #define INDEX_FIELD_BUS GENMASK(12, 5) #define INDEX_FIELD_SLOT GENMASK(4, 0) @@ -24,9 +26,17 @@ static unsigned long ice_adapter_index(const struct pci_dev *pdev) WARN_ON(domain > FIELD_MAX(INDEX_FIELD_DOMAIN)); - return FIELD_PREP(INDEX_FIELD_DOMAIN, domain) | - FIELD_PREP(INDEX_FIELD_BUS, pdev->bus->number) | - FIELD_PREP(INDEX_FIELD_SLOT, PCI_SLOT(pdev->devfn)); + switch (pdev->device) { + case ICE_DEV_ID_E825C_BACKPLANE: + case ICE_DEV_ID_E825C_QSFP: + case ICE_DEV_ID_E825C_SFP: + case ICE_DEV_ID_E825C_SGMII: + return FIELD_PREP(INDEX_FIELD_DEV, pdev->device); + default: + return FIELD_PREP(INDEX_FIELD_DOMAIN, domain) | + FIELD_PREP(INDEX_FIELD_BUS, pdev->bus->number) | + FIELD_PREP(INDEX_FIELD_SLOT, PCI_SLOT(pdev->devfn)); + } } static struct ice_adapter *ice_adapter_new(void) @@ -40,11 +50,17 @@ static struct ice_adapter *ice_adapter_new(void) spin_lock_init(&adapter->ptp_gltsyn_time_lock); refcount_set(&adapter->refcount, 1); + mutex_init(&adapter->ports.lock); + INIT_LIST_HEAD(&adapter->ports.ports); + return adapter; } static void ice_adapter_free(struct ice_adapter *adapter) { + WARN_ON(!list_empty(&adapter->ports.ports)); + mutex_destroy(&adapter->ports.lock); + kfree(adapter); } diff --git a/drivers/net/ethernet/intel/ice/ice_adapter.h b/drivers/net/ethernet/intel/ice/ice_adapter.h index 9d11014ec02ff2..e233225848b384 100644 --- a/drivers/net/ethernet/intel/ice/ice_adapter.h +++ b/drivers/net/ethernet/intel/ice/ice_adapter.h @@ -4,22 +4,42 @@ #ifndef _ICE_ADAPTER_H_ #define _ICE_ADAPTER_H_ +#include #include #include struct pci_dev; +struct ice_pf; + +/** + * struct ice_port_list - data used to store the list of adapter ports + * + * This structure contains data used to maintain a list of adapter ports + * + * @ports: list of ports + * @lock: protect access to the ports list + */ +struct ice_port_list { + struct list_head ports; + /* To synchronize the ports list operations */ + struct mutex lock; +}; /** * struct ice_adapter - PCI adapter resources shared across PFs * @ptp_gltsyn_time_lock: Spinlock protecting access to the GLTSYN_TIME * register of the PTP clock. * @refcount: Reference count. struct ice_pf objects hold the references. + * @ctrl_pf: Control PF of the adapter + * @ports: Ports list */ struct ice_adapter { + refcount_t refcount; /* For access to the GLTSYN_TIME register */ spinlock_t ptp_gltsyn_time_lock; - refcount_t refcount; + struct ice_pf *ctrl_pf; + struct ice_port_list ports; }; struct ice_adapter *ice_adapter_get(const struct pci_dev *pdev); diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 0be1a98d7cc1b5..1489a8ceec51df 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1492,6 +1492,23 @@ struct ice_aqc_dnl_equa_param { #define ICE_AQC_RX_EQU_BFLF (0x13 << ICE_AQC_RX_EQU_SHIFT) #define ICE_AQC_RX_EQU_BFHF (0x14 << ICE_AQC_RX_EQU_SHIFT) #define ICE_AQC_RX_EQU_DRATE (0x15 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_CTLE_GAINHF (0x20 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_CTLE_GAINLF (0x21 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_CTLE_GAINDC (0x22 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_CTLE_BW (0x23 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_GAIN (0x30 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_GAIN2 (0x31 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_2 (0x32 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_3 (0x33 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_4 (0x34 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_5 (0x35 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_6 (0x36 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_7 (0x37 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_8 (0x38 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_9 (0x39 << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_10 (0x3A << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_11 (0x3B << ICE_AQC_RX_EQU_SHIFT) +#define ICE_AQC_RX_EQU_DFE_12 (0x3C << ICE_AQC_RX_EQU_SHIFT) #define ICE_AQC_TX_EQU_PRE1 0x0 #define ICE_AQC_TX_EQU_PRE3 0x3 #define ICE_AQC_TX_EQU_ATTEN 0x4 @@ -1742,6 +1759,15 @@ struct ice_aqc_nvm { }; #define ICE_AQC_NVM_START_POINT 0 +#define ICE_AQC_NVM_SECTOR_UNIT 4096 +#define ICE_AQC_NVM_SDP_AC_PTR_OFFSET 0xD8 +#define ICE_AQC_NVM_SDP_AC_PTR_M GENMASK(14, 0) +#define ICE_AQC_NVM_SDP_AC_PTR_INVAL 0x7FFF +#define ICE_AQC_NVM_SDP_AC_PTR_TYPE_M BIT(15) +#define ICE_AQC_NVM_SDP_AC_SDP_NUM_M GENMASK(2, 0) +#define ICE_AQC_NVM_SDP_AC_DIR_M BIT(3) +#define ICE_AQC_NVM_SDP_AC_PIN_M GENMASK(15, 6) +#define ICE_AQC_NVM_SDP_AC_MAX_SIZE 7 #define ICE_AQC_NVM_TX_TOPO_MOD_ID 0x14B diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 4a9a6899fc453c..82a9cd4ec7aec9 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -156,7 +156,8 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx) * handler here (i.e. resume, reset/rebuild, etc.) */ if (vsi->netdev) - netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll); + netif_napi_add_config(vsi->netdev, &q_vector->napi, + ice_napi_poll, v_idx); out: /* tie q_vector and VSI together */ @@ -347,6 +348,8 @@ ice_setup_tx_ctx(struct ice_tx_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf break; } + tlan_ctx->quanta_prof_idx = ring->quanta_prof_id; + tlan_ctx->tso_ena = ICE_TX_LEGACY; tlan_ctx->tso_qnum = pf_q; @@ -445,7 +448,7 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring) /* Max packet size for this queue - must not be set to a larger value * than 5 x DBUF */ - rlan_ctx.rxmax = min_t(u32, vsi->max_frame, + rlan_ctx.rxmax = min_t(u32, ring->max_frame, ICE_MAX_CHAINED_RX_BUFS * ring->rx_buf_len); /* Rx queue threshold in units of 64 */ @@ -541,8 +544,6 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring) u32 num_bufs = ICE_RX_DESC_UNUSED(ring); int err; - ring->rx_buf_len = ring->vsi->rx_buf_len; - if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF) { if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) { err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev, @@ -641,21 +642,25 @@ int ice_vsi_cfg_single_rxq(struct ice_vsi *vsi, u16 q_idx) /** * ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length * @vsi: VSI + * @ring: Rx ring to configure + * + * Determine the maximum frame size and Rx buffer length to use for a PF VSI. + * Set these in the associated Rx ring structure. */ -static void ice_vsi_cfg_frame_size(struct ice_vsi *vsi) +static void ice_vsi_cfg_frame_size(struct ice_vsi *vsi, struct ice_rx_ring *ring) { if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) { - vsi->max_frame = ICE_MAX_FRAME_LEGACY_RX; - vsi->rx_buf_len = ICE_RXBUF_1664; + ring->max_frame = ICE_MAX_FRAME_LEGACY_RX; + ring->rx_buf_len = ICE_RXBUF_1664; #if (PAGE_SIZE < 8192) } else if (!ICE_2K_TOO_SMALL_WITH_PADDING && (vsi->netdev->mtu <= ETH_DATA_LEN)) { - vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN; - vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN; + ring->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN; + ring->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN; #endif } else { - vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; - vsi->rx_buf_len = ICE_RXBUF_3072; + ring->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; + ring->rx_buf_len = ICE_RXBUF_3072; } } @@ -670,15 +675,15 @@ int ice_vsi_cfg_rxqs(struct ice_vsi *vsi) { u16 i; - if (vsi->type == ICE_VSI_VF) - goto setup_rings; - - ice_vsi_cfg_frame_size(vsi); -setup_rings: /* set up individual rings */ ice_for_each_rxq(vsi, i) { - int err = ice_vsi_cfg_rxq(vsi->rx_rings[i]); + struct ice_rx_ring *ring = vsi->rx_rings[i]; + int err; + + if (vsi->type != ICE_VSI_VF) + ice_vsi_cfg_frame_size(vsi, ring); + err = ice_vsi_cfg_rxq(ring); if (err) return err; } diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 009716a12a26af..496d86cbd13fc3 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -542,7 +542,8 @@ ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, /** * ice_find_netlist_node * @hw: pointer to the hw struct - * @node_type_ctx: type of netlist node to look for + * @node_type: type of netlist node to look for + * @ctx: context of the search * @node_part_number: node part number to look for * @node_handle: output parameter if node found - optional * @@ -552,10 +553,12 @@ ice_aq_get_netlist_node(struct ice_hw *hw, struct ice_aqc_get_link_topo *cmd, * valid if the function returns zero, and should be ignored on any non-zero * return value. * - * Returns: 0 if the node is found, -ENOENT if no handle was found, and - * a negative error code on failure to access the AQ. + * Return: + * * 0 if the node is found, + * * -ENOENT if no handle was found, + * * negative error code on failure to access the AQ. */ -static int ice_find_netlist_node(struct ice_hw *hw, u8 node_type_ctx, +static int ice_find_netlist_node(struct ice_hw *hw, u8 node_type, u8 ctx, u8 node_part_number, u16 *node_handle) { u8 idx; @@ -566,8 +569,8 @@ static int ice_find_netlist_node(struct ice_hw *hw, u8 node_type_ctx, int status; cmd.addr.topo_params.node_type_ctx = - FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_TYPE_M, - node_type_ctx); + FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_TYPE_M, node_type) | + FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, ctx); cmd.addr.topo_params.index = idx; status = ice_aq_get_netlist_node(hw, &cmd, @@ -2436,6 +2439,25 @@ ice_parse_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p, ice_recalc_port_limited_caps(hw, &func_p->common_cap); } +/** + * ice_func_id_to_logical_id - map from function id to logical pf id + * @active_function_bitmap: active function bitmap + * @pf_id: function number of device + * + * Return: logical PF ID. + */ +static int ice_func_id_to_logical_id(u32 active_function_bitmap, u8 pf_id) +{ + u8 logical_id = 0; + u8 i; + + for (i = 0; i < pf_id; i++) + if (active_function_bitmap & BIT(i)) + logical_id++; + + return logical_id; +} + /** * ice_parse_valid_functions_cap - Parse ICE_AQC_CAPS_VALID_FUNCTIONS caps * @hw: pointer to the HW struct @@ -2453,6 +2475,8 @@ ice_parse_valid_functions_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p, dev_p->num_funcs = hweight32(number); ice_debug(hw, ICE_DBG_INIT, "dev caps: num_funcs = %d\n", dev_p->num_funcs); + + hw->logical_pf_id = ice_func_id_to_logical_id(number, hw->pf_id); } /** @@ -2726,9 +2750,11 @@ bool ice_is_pf_c827(struct ice_hw *hw) */ bool ice_is_phy_rclk_in_netlist(struct ice_hw *hw) { - if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_PHY, + ICE_AQC_LINK_TOPO_NODE_CTX_PORT, ICE_AQC_GET_LINK_TOPO_NODE_NR_C827, NULL) && - ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_PHY, + ICE_AQC_LINK_TOPO_NODE_CTX_PORT, ICE_AQC_GET_LINK_TOPO_NODE_NR_E822_PHY, NULL)) return false; @@ -2744,6 +2770,7 @@ bool ice_is_phy_rclk_in_netlist(struct ice_hw *hw) bool ice_is_clock_mux_in_netlist(struct ice_hw *hw) { if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_MUX, + ICE_AQC_LINK_TOPO_NODE_CTX_GLOBAL, ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_CLK_MUX, NULL)) return false; @@ -2764,12 +2791,14 @@ bool ice_is_clock_mux_in_netlist(struct ice_hw *hw) bool ice_is_cgu_in_netlist(struct ice_hw *hw) { if (!ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + ICE_AQC_LINK_TOPO_NODE_CTX_GLOBAL, ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032, NULL)) { hw->cgu_part_number = ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032; return true; } else if (!ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_CLK_CTRL, + ICE_AQC_LINK_TOPO_NODE_CTX_GLOBAL, ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384, NULL)) { hw->cgu_part_number = ICE_AQC_GET_LINK_TOPO_NODE_NR_SI5383_5384; @@ -2788,6 +2817,7 @@ bool ice_is_cgu_in_netlist(struct ice_hw *hw) bool ice_is_gps_in_netlist(struct ice_hw *hw) { if (ice_find_netlist_node(hw, ICE_AQC_LINK_TOPO_NODE_TYPE_GPS, + ICE_AQC_LINK_TOPO_NODE_CTX_GLOBAL, ICE_AQC_GET_LINK_TOPO_NODE_NR_GEN_GPS, NULL)) return false; diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.c b/drivers/net/ethernet/intel/ice/ice_ddp.c index 272fd823a825d0..03988be03729b7 100644 --- a/drivers/net/ethernet/intel/ice/ice_ddp.c +++ b/drivers/net/ethernet/intel/ice/ice_ddp.c @@ -1210,6 +1210,131 @@ ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, return status; } +/** + * ice_is_buffer_metadata - determine if package buffer is a metadata buffer + * @buf: pointer to buffer header + * Return: whether given @buf is a metadata one. + */ +static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf) +{ + return le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF; +} + +/** + * struct ice_ddp_send_ctx - sending context of current DDP segment + * @hw: pointer to the hardware struct + * + * Keeps current sending state (header, error) for the purpose of proper "last" + * bit setting in ice_aq_download_pkg(). Use via calls to ice_ddp_send_hunk(). + */ +struct ice_ddp_send_ctx { + struct ice_hw *hw; +/* private: only for ice_ddp_send_hunk() */ + struct ice_buf_hdr *hdr; + int err; +}; + +static void ice_ddp_send_ctx_set_err(struct ice_ddp_send_ctx *ctx, int err) +{ + ctx->err = err; +} + +/** + * ice_ddp_send_hunk - send one hunk of data to FW + * @ctx: current segment sending context + * @hunk: next hunk to send, size is always ICE_PKG_BUF_SIZE + * + * Send the next hunk of data to FW, retrying if needed. + * + * Notice: must be called once more with a NULL @hunk to finish up; such call + * will set up the "last" bit of an AQ request. After such call @ctx.hdr is + * cleared, @hw is still valid. + * + * Return: %ICE_DDP_PKG_SUCCESS if there were no problems; a sticky @err + * otherwise. + */ +static enum ice_ddp_state ice_ddp_send_hunk(struct ice_ddp_send_ctx *ctx, + struct ice_buf_hdr *hunk) +{ + struct ice_buf_hdr *prev_hunk = ctx->hdr; + struct ice_hw *hw = ctx->hw; + bool prev_was_last = !hunk; + enum ice_aq_err aq_err; + u32 offset, info; + int attempt, err; + + if (ctx->err) + return ctx->err; + + ctx->hdr = hunk; + if (!prev_hunk) + return ICE_DDP_PKG_SUCCESS; /* no problem so far */ + + for (attempt = 0; attempt < 5; attempt++) { + if (attempt) + msleep(20); + + err = ice_aq_download_pkg(hw, prev_hunk, ICE_PKG_BUF_SIZE, + prev_was_last, &offset, &info, NULL); + + aq_err = hw->adminq.sq_last_status; + if (aq_err != ICE_AQ_RC_ENOSEC && aq_err != ICE_AQ_RC_EBADSIG) + break; + } + + if (err) { + ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n", + err, offset, info); + ctx->err = ice_map_aq_err_to_ddp_state(aq_err); + } else if (attempt) { + dev_dbg(ice_hw_to_dev(hw), + "ice_aq_download_pkg number of retries: %d\n", attempt); + } + + return ctx->err; +} + +/** + * ice_dwnld_cfg_bufs_no_lock + * @ctx: context of the current buffers section to send + * @bufs: pointer to an array of buffers + * @start: buffer index of first buffer to download + * @count: the number of buffers to download + * + * Downloads package configuration buffers to the firmware. Metadata buffers + * are skipped, and the first metadata buffer found indicates that the rest + * of the buffers are all metadata buffers. + */ +static enum ice_ddp_state +ice_dwnld_cfg_bufs_no_lock(struct ice_ddp_send_ctx *ctx, struct ice_buf *bufs, + u32 start, u32 count) +{ + struct ice_buf_hdr *bh; + enum ice_ddp_state err; + + if (!bufs || !count) { + ice_ddp_send_ctx_set_err(ctx, ICE_DDP_PKG_ERR); + return ICE_DDP_PKG_ERR; + } + + bufs += start; + + for (int i = 0; i < count; i++, bufs++) { + bh = (struct ice_buf_hdr *)bufs; + /* Metadata buffers should not be sent to FW, + * their presence means "we are done here". + */ + if (ice_is_buffer_metadata(bh)) + break; + + err = ice_ddp_send_hunk(ctx, bh); + if (err) + return err; + } + + return 0; +} + /** * ice_get_pkg_seg_by_idx * @pkg_hdr: pointer to the package header to be searched @@ -1269,137 +1394,21 @@ ice_is_signing_seg_type_at_idx(struct ice_pkg_hdr *pkg_hdr, u32 idx, return false; } -/** - * ice_is_buffer_metadata - determine if package buffer is a metadata buffer - * @buf: pointer to buffer header - */ -static bool ice_is_buffer_metadata(struct ice_buf_hdr *buf) -{ - if (le32_to_cpu(buf->section_entry[0].type) & ICE_METADATA_BUF) - return true; - - return false; -} - -/** - * ice_is_last_download_buffer - * @buf: pointer to current buffer header - * @idx: index of the buffer in the current sequence - * @count: the buffer count in the current sequence - * - * Note: this routine should only be called if the buffer is not the last buffer - */ -static bool -ice_is_last_download_buffer(struct ice_buf_hdr *buf, u32 idx, u32 count) -{ - struct ice_buf *next_buf; - - if ((idx + 1) == count) - return true; - - /* A set metadata flag in the next buffer will signal that the current - * buffer will be the last buffer downloaded - */ - next_buf = ((struct ice_buf *)buf) + 1; - - return ice_is_buffer_metadata((struct ice_buf_hdr *)next_buf); -} - -/** - * ice_dwnld_cfg_bufs_no_lock - * @hw: pointer to the hardware structure - * @bufs: pointer to an array of buffers - * @start: buffer index of first buffer to download - * @count: the number of buffers to download - * @indicate_last: if true, then set last buffer flag on last buffer download - * - * Downloads package configuration buffers to the firmware. Metadata buffers - * are skipped, and the first metadata buffer found indicates that the rest - * of the buffers are all metadata buffers. - */ -static enum ice_ddp_state -ice_dwnld_cfg_bufs_no_lock(struct ice_hw *hw, struct ice_buf *bufs, u32 start, - u32 count, bool indicate_last) -{ - enum ice_ddp_state state = ICE_DDP_PKG_SUCCESS; - struct ice_buf_hdr *bh; - enum ice_aq_err err; - u32 offset, info, i; - - if (!bufs || !count) - return ICE_DDP_PKG_ERR; - - /* If the first buffer's first section has its metadata bit set - * then there are no buffers to be downloaded, and the operation is - * considered a success. - */ - bh = (struct ice_buf_hdr *)(bufs + start); - if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) - return ICE_DDP_PKG_SUCCESS; - - for (i = 0; i < count; i++) { - bool last = false; - int try_cnt = 0; - int status; - - bh = (struct ice_buf_hdr *)(bufs + start + i); - - if (indicate_last) - last = ice_is_last_download_buffer(bh, i, count); - - while (1) { - status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, - last, &offset, &info, - NULL); - if (hw->adminq.sq_last_status != ICE_AQ_RC_ENOSEC && - hw->adminq.sq_last_status != ICE_AQ_RC_EBADSIG) - break; - - try_cnt++; - - if (try_cnt == 5) - break; - - msleep(20); - } - - if (try_cnt) - dev_dbg(ice_hw_to_dev(hw), - "ice_aq_download_pkg number of retries: %d\n", - try_cnt); - - /* Save AQ status from download package */ - if (status) { - ice_debug(hw, ICE_DBG_PKG, "Pkg download failed: err %d off %d inf %d\n", - status, offset, info); - err = hw->adminq.sq_last_status; - state = ice_map_aq_err_to_ddp_state(err); - break; - } - - if (last) - break; - } - - return state; -} - /** * ice_download_pkg_sig_seg - download a signature segment - * @hw: pointer to the hardware structure + * @ctx: context of the current buffers section to send * @seg: pointer to signature segment */ static enum ice_ddp_state -ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg) +ice_download_pkg_sig_seg(struct ice_ddp_send_ctx *ctx, struct ice_sign_seg *seg) { - return ice_dwnld_cfg_bufs_no_lock(hw, seg->buf_tbl.buf_array, 0, - le32_to_cpu(seg->buf_tbl.buf_count), - false); + return ice_dwnld_cfg_bufs_no_lock(ctx, seg->buf_tbl.buf_array, 0, + le32_to_cpu(seg->buf_tbl.buf_count)); } /** * ice_download_pkg_config_seg - download a config segment - * @hw: pointer to the hardware structure + * @ctx: context of the current buffers section to send * @pkg_hdr: pointer to package header * @idx: segment index * @start: starting buffer @@ -1408,8 +1417,9 @@ ice_download_pkg_sig_seg(struct ice_hw *hw, struct ice_sign_seg *seg) * Note: idx must reference a ICE segment */ static enum ice_ddp_state -ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, - u32 idx, u32 start, u32 count) +ice_download_pkg_config_seg(struct ice_ddp_send_ctx *ctx, + struct ice_pkg_hdr *pkg_hdr, u32 idx, u32 start, + u32 count) { struct ice_buf_table *bufs; struct ice_seg *seg; @@ -1425,46 +1435,56 @@ ice_download_pkg_config_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, if (start >= buf_count || start + count > buf_count) return ICE_DDP_PKG_ERR; - return ice_dwnld_cfg_bufs_no_lock(hw, bufs->buf_array, start, count, - true); + return ice_dwnld_cfg_bufs_no_lock(ctx, bufs->buf_array, start, count); +} + +static bool ice_is_last_sign_seg(u32 flags) +{ + return !(flags & ICE_SIGN_SEG_FLAGS_VALID) || /* behavior prior to valid */ + (flags & ICE_SIGN_SEG_FLAGS_LAST); } /** * ice_dwnld_sign_and_cfg_segs - download a signing segment and config segment - * @hw: pointer to the hardware structure + * @ctx: context of the current buffers section to send * @pkg_hdr: pointer to package header * @idx: segment index (must be a signature segment) * * Note: idx must reference a signature segment */ static enum ice_ddp_state -ice_dwnld_sign_and_cfg_segs(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr, - u32 idx) +ice_dwnld_sign_and_cfg_segs(struct ice_ddp_send_ctx *ctx, + struct ice_pkg_hdr *pkg_hdr, u32 idx) { + u32 conf_idx, start, count, flags; enum ice_ddp_state state; struct ice_sign_seg *seg; - u32 conf_idx; - u32 start; - u32 count; seg = (struct ice_sign_seg *)ice_get_pkg_seg_by_idx(pkg_hdr, idx); if (!seg) { state = ICE_DDP_PKG_ERR; - goto exit; + ice_ddp_send_ctx_set_err(ctx, state); + return state; } count = le32_to_cpu(seg->signed_buf_count); - state = ice_download_pkg_sig_seg(hw, seg); + state = ice_download_pkg_sig_seg(ctx, seg); if (state || !count) - goto exit; + return state; conf_idx = le32_to_cpu(seg->signed_seg_idx); start = le32_to_cpu(seg->signed_buf_start); - state = ice_download_pkg_config_seg(hw, pkg_hdr, conf_idx, start, + state = ice_download_pkg_config_seg(ctx, pkg_hdr, conf_idx, start, count); -exit: + /* finish up by sending last hunk with "last" flag set if requested by + * DDP content + */ + flags = le32_to_cpu(seg->flags); + if (ice_is_last_sign_seg(flags)) + state = ice_ddp_send_hunk(ctx, NULL); + return state; } @@ -1519,6 +1539,7 @@ ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) { enum ice_aq_err aq_err = hw->adminq.sq_last_status; enum ice_ddp_state state = ICE_DDP_PKG_ERR; + struct ice_ddp_send_ctx ctx = { .hw = hw }; int status; u32 i; @@ -1539,7 +1560,7 @@ ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) hw->pkg_sign_type)) continue; - state = ice_dwnld_sign_and_cfg_segs(hw, pkg_hdr, i); + state = ice_dwnld_sign_and_cfg_segs(&ctx, pkg_hdr, i); if (state) break; } @@ -1564,6 +1585,7 @@ ice_download_pkg_with_sig_seg(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) static enum ice_ddp_state ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count) { + struct ice_ddp_send_ctx ctx = { .hw = hw }; enum ice_ddp_state state; struct ice_buf_hdr *bh; int status; @@ -1576,7 +1598,7 @@ ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count) * considered a success. */ bh = (struct ice_buf_hdr *)bufs; - if (le32_to_cpu(bh->section_entry[0].type) & ICE_METADATA_BUF) + if (ice_is_buffer_metadata(bh)) return ICE_DDP_PKG_SUCCESS; status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE); @@ -1586,7 +1608,9 @@ ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count) return ice_map_aq_err_to_ddp_state(hw->adminq.sq_last_status); } - state = ice_dwnld_cfg_bufs_no_lock(hw, bufs, 0, count, true); + ice_dwnld_cfg_bufs_no_lock(&ctx, bufs, 0, count); + /* finish up by sending last hunk with "last" flag set */ + state = ice_ddp_send_hunk(&ctx, NULL); if (!state) state = ice_post_dwnld_pkg_actions(hw); diff --git a/drivers/net/ethernet/intel/ice/ice_ddp.h b/drivers/net/ethernet/intel/ice/ice_ddp.h index 79551da2a4b022..8a2d57fc5dae10 100644 --- a/drivers/net/ethernet/intel/ice/ice_ddp.h +++ b/drivers/net/ethernet/intel/ice/ice_ddp.h @@ -181,7 +181,10 @@ struct ice_sign_seg { __le32 signed_seg_idx; __le32 signed_buf_start; __le32 signed_buf_count; -#define ICE_SIGN_SEG_RESERVED_COUNT 44 +#define ICE_SIGN_SEG_FLAGS_VALID 0x80000000 +#define ICE_SIGN_SEG_FLAGS_LAST 0x00000001 + __le32 flags; +#define ICE_SIGN_SEG_RESERVED_COUNT 40 u8 reserved[ICE_SIGN_SEG_RESERVED_COUNT]; struct ice_buf_table buf_tbl; }; diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.h b/drivers/net/ethernet/intel/ice/ice_eswitch.h index 20ce32dda69cbe..ac7db100e2cd35 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.h +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.h @@ -60,11 +60,6 @@ ice_eswitch_set_target_vsi(struct sk_buff *skb, static inline void ice_eswitch_update_repr(unsigned long *repr_id, struct ice_vsi *vsi) { } -static inline int ice_eswitch_configure(struct ice_pf *pf) -{ - return 0; -} - static inline int ice_eswitch_mode_get(struct devlink *devlink, u16 *mode) { return DEVLINK_ESWITCH_MODE_LEGACY; diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index d5cc934d135949..3072634bf049c4 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -693,75 +693,53 @@ static int ice_get_port_topology(struct ice_hw *hw, u8 lport, static int ice_get_tx_rx_equa(struct ice_hw *hw, u8 serdes_num, struct ice_serdes_equalization_to_ethtool *ptr) { + static const int tx = ICE_AQC_OP_CODE_TX_EQU; + static const int rx = ICE_AQC_OP_CODE_RX_EQU; + struct { + int data_in; + int opcode; + int *out; + } aq_params[] = { + { ICE_AQC_TX_EQU_PRE1, tx, &ptr->tx_equ_pre1 }, + { ICE_AQC_TX_EQU_PRE3, tx, &ptr->tx_equ_pre3 }, + { ICE_AQC_TX_EQU_ATTEN, tx, &ptr->tx_equ_atten }, + { ICE_AQC_TX_EQU_POST1, tx, &ptr->tx_equ_post1 }, + { ICE_AQC_TX_EQU_PRE2, tx, &ptr->tx_equ_pre2 }, + { ICE_AQC_RX_EQU_PRE2, rx, &ptr->rx_equ_pre2 }, + { ICE_AQC_RX_EQU_PRE1, rx, &ptr->rx_equ_pre1 }, + { ICE_AQC_RX_EQU_POST1, rx, &ptr->rx_equ_post1 }, + { ICE_AQC_RX_EQU_BFLF, rx, &ptr->rx_equ_bflf }, + { ICE_AQC_RX_EQU_BFHF, rx, &ptr->rx_equ_bfhf }, + { ICE_AQC_RX_EQU_DRATE, rx, &ptr->rx_equ_drate }, + { ICE_AQC_RX_EQU_CTLE_GAINHF, rx, &ptr->rx_equ_ctle_gainhf }, + { ICE_AQC_RX_EQU_CTLE_GAINLF, rx, &ptr->rx_equ_ctle_gainlf }, + { ICE_AQC_RX_EQU_CTLE_GAINDC, rx, &ptr->rx_equ_ctle_gaindc }, + { ICE_AQC_RX_EQU_CTLE_BW, rx, &ptr->rx_equ_ctle_bw }, + { ICE_AQC_RX_EQU_DFE_GAIN, rx, &ptr->rx_equ_dfe_gain }, + { ICE_AQC_RX_EQU_DFE_GAIN2, rx, &ptr->rx_equ_dfe_gain_2 }, + { ICE_AQC_RX_EQU_DFE_2, rx, &ptr->rx_equ_dfe_2 }, + { ICE_AQC_RX_EQU_DFE_3, rx, &ptr->rx_equ_dfe_3 }, + { ICE_AQC_RX_EQU_DFE_4, rx, &ptr->rx_equ_dfe_4 }, + { ICE_AQC_RX_EQU_DFE_5, rx, &ptr->rx_equ_dfe_5 }, + { ICE_AQC_RX_EQU_DFE_6, rx, &ptr->rx_equ_dfe_6 }, + { ICE_AQC_RX_EQU_DFE_7, rx, &ptr->rx_equ_dfe_7 }, + { ICE_AQC_RX_EQU_DFE_8, rx, &ptr->rx_equ_dfe_8 }, + { ICE_AQC_RX_EQU_DFE_9, rx, &ptr->rx_equ_dfe_9 }, + { ICE_AQC_RX_EQU_DFE_10, rx, &ptr->rx_equ_dfe_10 }, + { ICE_AQC_RX_EQU_DFE_11, rx, &ptr->rx_equ_dfe_11 }, + { ICE_AQC_RX_EQU_DFE_12, rx, &ptr->rx_equ_dfe_12 }, + }; int err; - err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE1, - ICE_AQC_OP_CODE_TX_EQU, serdes_num, - &ptr->tx_equalization_pre1); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE3, - ICE_AQC_OP_CODE_TX_EQU, serdes_num, - &ptr->tx_equalization_pre3); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_ATTEN, - ICE_AQC_OP_CODE_TX_EQU, serdes_num, - &ptr->tx_equalization_atten); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_POST1, - ICE_AQC_OP_CODE_TX_EQU, serdes_num, - &ptr->tx_equalization_post1); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE2, - ICE_AQC_OP_CODE_TX_EQU, serdes_num, - &ptr->tx_equalization_pre2); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_PRE2, - ICE_AQC_OP_CODE_RX_EQU, serdes_num, - &ptr->rx_equalization_pre2); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_PRE1, - ICE_AQC_OP_CODE_RX_EQU, serdes_num, - &ptr->rx_equalization_pre1); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_POST1, - ICE_AQC_OP_CODE_RX_EQU, serdes_num, - &ptr->rx_equalization_post1); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_BFLF, - ICE_AQC_OP_CODE_RX_EQU, serdes_num, - &ptr->rx_equalization_bflf); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_BFHF, - ICE_AQC_OP_CODE_RX_EQU, serdes_num, - &ptr->rx_equalization_bfhf); - if (err) - return err; - - err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_DRATE, - ICE_AQC_OP_CODE_RX_EQU, serdes_num, - &ptr->rx_equalization_drate); - if (err) - return err; + for (int i = 0; i < ARRAY_SIZE(aq_params); i++) { + err = ice_aq_get_phy_equalization(hw, aq_params[i].data_in, + aq_params[i].opcode, + serdes_num, aq_params[i].out); + if (err) + break; + } - return 0; + return err; } /** @@ -4716,6 +4694,81 @@ static void ice_get_fec_stats(struct net_device *netdev, pi->lport, err); } +#define ICE_ETHTOOL_PFR (ETH_RESET_IRQ | ETH_RESET_DMA | \ + ETH_RESET_FILTER | ETH_RESET_OFFLOAD) + +#define ICE_ETHTOOL_CORER ((ICE_ETHTOOL_PFR | ETH_RESET_RAM) << \ + ETH_RESET_SHARED_SHIFT) + +#define ICE_ETHTOOL_GLOBR (ICE_ETHTOOL_CORER | \ + (ETH_RESET_MAC << ETH_RESET_SHARED_SHIFT) | \ + (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)) + +#define ICE_ETHTOOL_VFR ICE_ETHTOOL_PFR + +/** + * ice_ethtool_reset - triggers a given type of reset + * @dev: network interface device structure + * @flags: set of reset flags + * + * Return: 0 on success, -EOPNOTSUPP when using unsupported set of flags. + */ +static int ice_ethtool_reset(struct net_device *dev, u32 *flags) +{ + struct ice_netdev_priv *np = netdev_priv(dev); + struct ice_pf *pf = np->vsi->back; + enum ice_reset_req reset; + + switch (*flags) { + case ICE_ETHTOOL_CORER: + reset = ICE_RESET_CORER; + break; + case ICE_ETHTOOL_GLOBR: + reset = ICE_RESET_GLOBR; + break; + case ICE_ETHTOOL_PFR: + reset = ICE_RESET_PFR; + break; + default: + netdev_info(dev, "Unsupported set of ethtool flags"); + return -EOPNOTSUPP; + } + + ice_schedule_reset(pf, reset); + + *flags = 0; + + return 0; +} + +/** + * ice_repr_ethtool_reset - triggers a VF reset + * @dev: network interface device structure + * @flags: set of reset flags + * + * Return: 0 on success, + * -EOPNOTSUPP when using unsupported set of flags + * -EBUSY when VF is not ready for reset. + */ +static int ice_repr_ethtool_reset(struct net_device *dev, u32 *flags) +{ + struct ice_repr *repr = ice_netdev_to_repr(dev); + struct ice_vf *vf; + + if (repr->type != ICE_REPR_TYPE_VF || + *flags != ICE_ETHTOOL_VFR) + return -EOPNOTSUPP; + + vf = repr->vf; + + if (ice_check_vf_ready_for_cfg(vf)) + return -EBUSY; + + *flags = 0; + + return ice_reset_vf(vf, ICE_VF_RESET_VFLR | ICE_VF_RESET_LOCK); +} + static const struct ethtool_ops ice_ethtool_ops = { .cap_rss_ctx_supported = true, .supported_coalesce_params = ETHTOOL_COALESCE_USECS | @@ -4752,6 +4805,7 @@ static const struct ethtool_ops ice_ethtool_ops = { .nway_reset = ice_nway_reset, .get_pauseparam = ice_get_pauseparam, .set_pauseparam = ice_set_pauseparam, + .reset = ice_ethtool_reset, .get_rxfh_key_size = ice_get_rxfh_key_size, .get_rxfh_indir_size = ice_get_rxfh_indir_size, .get_rxfh = ice_get_rxfh, @@ -4804,6 +4858,7 @@ static const struct ethtool_ops ice_ethtool_repr_ops = { .get_strings = ice_repr_get_strings, .get_ethtool_stats = ice_repr_get_ethtool_stats, .get_sset_count = ice_repr_get_sset_count, + .reset = ice_repr_ethtool_reset, }; /** diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.h b/drivers/net/ethernet/intel/ice/ice_ethtool.h index 9acccae38625ae..8f2ad1c172c061 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.h +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.h @@ -10,17 +10,34 @@ struct ice_phy_type_to_ethtool { }; struct ice_serdes_equalization_to_ethtool { - int rx_equalization_pre2; - int rx_equalization_pre1; - int rx_equalization_post1; - int rx_equalization_bflf; - int rx_equalization_bfhf; - int rx_equalization_drate; - int tx_equalization_pre1; - int tx_equalization_pre3; - int tx_equalization_atten; - int tx_equalization_post1; - int tx_equalization_pre2; + int rx_equ_pre2; + int rx_equ_pre1; + int rx_equ_post1; + int rx_equ_bflf; + int rx_equ_bfhf; + int rx_equ_drate; + int rx_equ_ctle_gainhf; + int rx_equ_ctle_gainlf; + int rx_equ_ctle_gaindc; + int rx_equ_ctle_bw; + int rx_equ_dfe_gain; + int rx_equ_dfe_gain_2; + int rx_equ_dfe_2; + int rx_equ_dfe_3; + int rx_equ_dfe_4; + int rx_equ_dfe_5; + int rx_equ_dfe_6; + int rx_equ_dfe_7; + int rx_equ_dfe_8; + int rx_equ_dfe_9; + int rx_equ_dfe_10; + int rx_equ_dfe_11; + int rx_equ_dfe_12; + int tx_equ_pre1; + int tx_equ_pre3; + int tx_equ_atten; + int tx_equ_post1; + int tx_equ_pre2; }; struct ice_regdump_to_ethtool { diff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h index 90b9b09931221d..28b0897adf32f0 100644 --- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h +++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h @@ -23,9 +23,6 @@ int ice_get_sw_fv_list(struct ice_hw *hw, struct ice_prot_lkup_ext *lkups, unsigned long *bm, struct list_head *fv_list); int -ice_pkg_buf_unreserve_section(struct ice_buf_build *bld, u16 count); -u16 ice_pkg_buf_get_free_space(struct ice_buf_build *bld); -int ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, u16 buf_size, struct ice_sq_cd *cd); bool diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c index c8ea1af51ad38d..f02e8ca5537507 100644 --- a/drivers/net/ethernet/intel/ice/ice_gnss.c +++ b/drivers/net/ethernet/intel/ice/ice_gnss.c @@ -397,8 +397,8 @@ bool ice_gnss_is_gps_present(struct ice_hw *hw) int err; u8 data; - err = ice_read_pca9575_reg_e810t(hw, ICE_PCA9575_P0_IN, &data); - if (err || !!(data & ICE_E810T_P0_GNSS_PRSNT_N)) + err = ice_read_pca9575_reg(hw, ICE_PCA9575_P0_IN, &data); + if (err || !!(data & ICE_P0_GNSS_PRSNT_N)) return false; } else { return false; diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 91cbae1eec89a0..dc88aea9f47317 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -6,6 +6,14 @@ #ifndef _ICE_HW_AUTOGEN_H_ #define _ICE_HW_AUTOGEN_H_ +#define GLCOMM_QUANTA_PROF(_i) (0x002D2D68 + ((_i) * 4)) +#define GLCOMM_QUANTA_PROF_MAX_INDEX 15 +#define GLCOMM_QUANTA_PROF_QUANTA_SIZE_S 0 +#define GLCOMM_QUANTA_PROF_QUANTA_SIZE_M ICE_M(0x3FFF, 0) +#define GLCOMM_QUANTA_PROF_MAX_CMD_S 16 +#define GLCOMM_QUANTA_PROF_MAX_CMD_M ICE_M(0xFF, 16) +#define GLCOMM_QUANTA_PROF_MAX_DESC_S 24 +#define GLCOMM_QUANTA_PROF_MAX_DESC_M ICE_M(0x3F, 24) #define QTX_COMM_DBELL(_DBQM) (0x002C0000 + ((_DBQM) * 4)) #define QTX_COMM_HEAD(_DBQM) (0x000E0000 + ((_DBQM) * 4)) #define QTX_COMM_HEAD_HEAD_S 0 @@ -539,5 +547,8 @@ #define E830_PRTMAC_CL01_QNT_THR_CL0_M GENMASK(15, 0) #define VFINT_DYN_CTLN(_i) (0x00003800 + ((_i) * 4)) #define VFINT_DYN_CTLN_CLEARPBA_M BIT(1) +#define E830_MBX_PF_IN_FLIGHT_VF_MSGS_THRESH 0x00234000 +#define E830_MBX_VF_DEC_TRIG(_VF) (0x00233800 + (_VF) * 4) +#define E830_MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT(_VF) (0x00233000 + (_VF) * 4) #endif /* _ICE_HW_AUTOGEN_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 06e712cdc3d9ed..a7d45a8ce7ac00 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2777,8 +2777,10 @@ void ice_napi_add(struct ice_vsi *vsi) return; ice_for_each_q_vector(vsi, v_idx) - netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi, - ice_napi_poll); + netif_napi_add_config(vsi->netdev, + &vsi->q_vectors[v_idx]->napi, + ice_napi_poll, + v_idx); } /** @@ -3880,6 +3882,9 @@ void ice_init_feature_support(struct ice_pf *pf) default: break; } + + if (pf->hw.mac_type == ICE_MAC_E830) + ice_set_feature_support(pf, ICE_F_MBX_LIMIT); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 1a6cfc8693ce47..10d6fc479a3211 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -88,8 +88,6 @@ void ice_write_intrl(struct ice_q_vector *q_vector, u8 intrl); void ice_write_itr(struct ice_ring_container *rc, u16 itr); void ice_set_q_vector_intrl(struct ice_q_vector *q_vector); -int ice_vsi_cfg_mac_fltr(struct ice_vsi *vsi, const u8 *macaddr, bool set); - bool ice_is_safe_mode(struct ice_pf *pf); bool ice_is_rdma_ena(struct ice_pf *pf); bool ice_is_dflt_vsi_in_use(struct ice_port_info *pi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b1e7727b8677f9..0ab35607e5d569 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -37,7 +37,7 @@ static const char ice_copyright[] = "Copyright (c) 2018, Intel Corporation."; #define ICE_DDP_PKG_FILE ICE_DDP_PKG_PATH "ice.pkg" MODULE_DESCRIPTION(DRV_SUMMARY); -MODULE_IMPORT_NS(LIBIE); +MODULE_IMPORT_NS("LIBIE"); MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE(ICE_DDP_PKG_FILE); @@ -1546,12 +1546,20 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) ice_vf_lan_overflow_event(pf, &event); break; case ice_mbx_opc_send_msg_to_pf: - data.num_msg_proc = i; - data.num_pending_arq = pending; - data.max_num_msgs_mbx = hw->mailboxq.num_rq_entries; - data.async_watermark_val = ICE_MBX_OVERFLOW_WATERMARK; + if (ice_is_feature_supported(pf, ICE_F_MBX_LIMIT)) { + ice_vc_process_vf_msg(pf, &event, NULL); + ice_mbx_vf_dec_trig_e830(hw, &event); + } else { + u16 val = hw->mailboxq.num_rq_entries; + + data.max_num_msgs_mbx = val; + val = ICE_MBX_OVERFLOW_WATERMARK; + data.async_watermark_val = val; + data.num_msg_proc = i; + data.num_pending_arq = pending; - ice_vc_process_vf_msg(pf, &event, &data); + ice_vc_process_vf_msg(pf, &event, &data); + } break; case ice_aqc_opc_fw_logs_event: ice_get_fwlog_data(pf, &event); @@ -4082,7 +4090,11 @@ static int ice_init_pf(struct ice_pf *pf) mutex_init(&pf->vfs.table_lock); hash_init(pf->vfs.table); - ice_mbx_init_snapshot(&pf->hw); + if (ice_is_feature_supported(pf, ICE_F_MBX_LIMIT)) + wr32(&pf->hw, E830_MBX_PF_IN_FLIGHT_VF_MSGS_THRESH, + ICE_MBX_OVERFLOW_WATERMARK); + else + ice_mbx_init_snapshot(&pf->hw); xa_init(&pf->dyn_ports); xa_init(&pf->sf_nums); @@ -4542,6 +4554,34 @@ ice_init_tx_topology(struct ice_hw *hw, const struct firmware *firmware) return 0; } +/** + * ice_init_supported_rxdids - Initialize supported Rx descriptor IDs + * @hw: pointer to the hardware structure + * @pf: pointer to pf structure + * + * The pf->supported_rxdids bitmap is used to indicate to VFs which descriptor + * formats the PF hardware supports. The exact list of supported RXDIDs + * depends on the loaded DDP package. The IDs can be determined by reading the + * GLFLXP_RXDID_FLAGS register after the DDP package is loaded. + * + * Note that the legacy 32-byte RXDID 0 is always supported but is not listed + * in the DDP package. The 16-byte legacy descriptor is never supported by + * VFs. + */ +static void ice_init_supported_rxdids(struct ice_hw *hw, struct ice_pf *pf) +{ + pf->supported_rxdids = BIT(ICE_RXDID_LEGACY_1); + + for (int i = ICE_RXDID_FLEX_NIC; i < ICE_FLEX_DESC_RXDID_MAX_NUM; i++) { + u32 regval; + + regval = rd32(hw, GLFLXP_RXDID_FLAGS(i, 0)); + if ((regval >> GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S) + & GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M) + pf->supported_rxdids |= BIT(i); + } +} + /** * ice_init_ddp_config - DDP related configuration * @hw: pointer to the hardware structure @@ -4576,6 +4616,9 @@ static int ice_init_ddp_config(struct ice_hw *hw, struct ice_pf *pf) ice_load_pkg(firmware, pf); release_firmware(firmware); + /* Initialize the supported Rx descriptor IDs after loading DDP */ + ice_init_supported_rxdids(hw, pf); + return 0; } @@ -5888,7 +5931,7 @@ static int __init ice_module_init(void) ice_adv_lnk_speed_maps_init(); - ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME); + ice_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, KBUILD_MODNAME); if (!ice_wq) { pr_err("Failed to create workqueue\n"); return status; @@ -6113,12 +6156,14 @@ ice_set_tx_maxrate(struct net_device *netdev, int queue_index, u32 maxrate) * @addr: the MAC address entry being added * @vid: VLAN ID * @flags: instructions from stack about fdb operation + * @notified: whether notification was emitted * @extack: netlink extended ack */ static int ice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags, struct netlink_ext_ack __always_unused *extack) + u16 flags, bool *notified, + struct netlink_ext_ack __always_unused *extack) { int err; @@ -6152,12 +6197,14 @@ ice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[], * @dev: the net device pointer * @addr: the MAC address entry being added * @vid: VLAN ID + * @notified: whether notification was emitted * @extack: netlink extended ack */ static int ice_fdb_del(struct ndmsg *ndm, __always_unused struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, - __always_unused u16 vid, struct netlink_ext_ack *extack) + __always_unused u16 vid, bool *notified, + struct netlink_ext_ack *extack) { int err; @@ -6361,10 +6408,12 @@ ice_set_vlan_filtering_features(struct ice_vsi *vsi, netdev_features_t features) int err = 0; /* support Single VLAN Mode (SVM) and Double VLAN Mode (DVM) by checking - * if either bit is set + * if either bit is set. In switchdev mode Rx filtering should never be + * enabled. */ - if (features & - (NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER)) + if ((features & + (NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER)) && + !ice_is_eswitch_mode_switchdev(vsi->back)) err = vlan_ops->ena_rx_filtering(vsi); else err = vlan_ops->dis_rx_filtering(vsi); @@ -6512,8 +6561,7 @@ ice_set_features(struct net_device *netdev, netdev_features_t features) if (changed & NETIF_F_HW_TC) { bool ena = !!(features & NETIF_F_HW_TC); - ena ? set_bit(ICE_FLAG_CLS_FLOWER, pf->flags) : - clear_bit(ICE_FLAG_CLS_FLOWER, pf->flags); + assign_bit(ICE_FLAG_CLS_FLOWER, pf->flags, ena); } if (changed & NETIF_F_LOOPBACK) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index ef2e858f49bb0e..a999fface27281 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -4,253 +4,187 @@ #include "ice.h" #include "ice_lib.h" #include "ice_trace.h" +#include "ice_cgu_regs.h" + +static const char ice_pin_names[][64] = { + "SDP0", + "SDP1", + "SDP2", + "SDP3", + "TIME_SYNC", + "1PPS" +}; -#define E810_OUT_PROP_DELAY_NS 1 +static const struct ice_ptp_pin_desc ice_pin_desc_e82x[] = { + /* name, gpio */ + { TIME_SYNC, { 4, -1 }}, + { ONE_PPS, { -1, 5 }}, +}; -static const struct ptp_pin_desc ice_pin_desc_e810t[] = { - /* name idx func chan */ - { "GNSS", GNSS, PTP_PF_EXTTS, 0, { 0, } }, - { "SMA1", SMA1, PTP_PF_NONE, 1, { 0, } }, - { "U.FL1", UFL1, PTP_PF_NONE, 1, { 0, } }, - { "SMA2", SMA2, PTP_PF_NONE, 2, { 0, } }, - { "U.FL2", UFL2, PTP_PF_NONE, 2, { 0, } }, +static const struct ice_ptp_pin_desc ice_pin_desc_e825c[] = { + /* name, gpio */ + { SDP0, { 0, 0 }}, + { SDP1, { 1, 1 }}, + { SDP2, { 2, 2 }}, + { SDP3, { 3, 3 }}, + { TIME_SYNC, { 4, -1 }}, + { ONE_PPS, { -1, 5 }}, }; -/** - * ice_get_sma_config_e810t - * @hw: pointer to the hw struct - * @ptp_pins: pointer to the ptp_pin_desc struture - * - * Read the configuration of the SMA control logic and put it into the - * ptp_pin_desc structure - */ -static int -ice_get_sma_config_e810t(struct ice_hw *hw, struct ptp_pin_desc *ptp_pins) -{ - u8 data, i; - int status; +static const struct ice_ptp_pin_desc ice_pin_desc_e810[] = { + /* name, gpio */ + { SDP0, { 0, 0 }}, + { SDP1, { 1, 1 }}, + { SDP2, { 2, 2 }}, + { SDP3, { 3, 3 }}, + { ONE_PPS, { -1, 5 }}, +}; - /* Read initial pin state */ - status = ice_read_sma_ctrl_e810t(hw, &data); - if (status) - return status; +static const char ice_pin_names_nvm[][64] = { + "GNSS", + "SMA1", + "U.FL1", + "SMA2", + "U.FL2", +}; - /* initialize with defaults */ - for (i = 0; i < NUM_PTP_PINS_E810T; i++) { - strscpy(ptp_pins[i].name, ice_pin_desc_e810t[i].name, - sizeof(ptp_pins[i].name)); - ptp_pins[i].index = ice_pin_desc_e810t[i].index; - ptp_pins[i].func = ice_pin_desc_e810t[i].func; - ptp_pins[i].chan = ice_pin_desc_e810t[i].chan; - } +static const struct ice_ptp_pin_desc ice_pin_desc_e810_sma[] = { + /* name, gpio */ + { GNSS, { 1, -1 }}, + { SMA1, { 1, 0 }}, + { UFL1, { -1, 0 }}, + { SMA2, { 3, 2 }}, + { UFL2, { 3, -1 }}, +}; - /* Parse SMA1/UFL1 */ - switch (data & ICE_SMA1_MASK_E810T) { - case ICE_SMA1_MASK_E810T: - default: - ptp_pins[SMA1].func = PTP_PF_NONE; - ptp_pins[UFL1].func = PTP_PF_NONE; - break; - case ICE_SMA1_DIR_EN_E810T: - ptp_pins[SMA1].func = PTP_PF_PEROUT; - ptp_pins[UFL1].func = PTP_PF_NONE; - break; - case ICE_SMA1_TX_EN_E810T: - ptp_pins[SMA1].func = PTP_PF_EXTTS; - ptp_pins[UFL1].func = PTP_PF_NONE; - break; - case 0: - ptp_pins[SMA1].func = PTP_PF_EXTTS; - ptp_pins[UFL1].func = PTP_PF_PEROUT; - break; - } +static struct ice_pf *ice_get_ctrl_pf(struct ice_pf *pf) +{ + return !pf->adapter ? NULL : pf->adapter->ctrl_pf; +} - /* Parse SMA2/UFL2 */ - switch (data & ICE_SMA2_MASK_E810T) { - case ICE_SMA2_MASK_E810T: - default: - ptp_pins[SMA2].func = PTP_PF_NONE; - ptp_pins[UFL2].func = PTP_PF_NONE; - break; - case (ICE_SMA2_TX_EN_E810T | ICE_SMA2_UFL2_RX_DIS_E810T): - ptp_pins[SMA2].func = PTP_PF_EXTTS; - ptp_pins[UFL2].func = PTP_PF_NONE; - break; - case (ICE_SMA2_DIR_EN_E810T | ICE_SMA2_UFL2_RX_DIS_E810T): - ptp_pins[SMA2].func = PTP_PF_PEROUT; - ptp_pins[UFL2].func = PTP_PF_NONE; - break; - case (ICE_SMA2_DIR_EN_E810T | ICE_SMA2_TX_EN_E810T): - ptp_pins[SMA2].func = PTP_PF_NONE; - ptp_pins[UFL2].func = PTP_PF_EXTTS; - break; - case ICE_SMA2_DIR_EN_E810T: - ptp_pins[SMA2].func = PTP_PF_PEROUT; - ptp_pins[UFL2].func = PTP_PF_EXTTS; - break; - } +static struct ice_ptp *ice_get_ctrl_ptp(struct ice_pf *pf) +{ + struct ice_pf *ctrl_pf = ice_get_ctrl_pf(pf); - return 0; + return !ctrl_pf ? NULL : &ctrl_pf->ptp; } /** - * ice_ptp_set_sma_config_e810t - * @hw: pointer to the hw struct - * @ptp_pins: pointer to the ptp_pin_desc struture + * ice_ptp_find_pin_idx - Find pin index in ptp_pin_desc + * @pf: Board private structure + * @func: Pin function + * @chan: GPIO channel * - * Set the configuration of the SMA control logic based on the configuration in - * num_pins parameter + * Return: positive pin number when pin is present, -1 otherwise */ -static int -ice_ptp_set_sma_config_e810t(struct ice_hw *hw, - const struct ptp_pin_desc *ptp_pins) +static int ice_ptp_find_pin_idx(struct ice_pf *pf, enum ptp_pin_function func, + unsigned int chan) { - int status; - u8 data; + const struct ptp_clock_info *info = &pf->ptp.info; + int i; - /* SMA1 and UFL1 cannot be set to TX at the same time */ - if (ptp_pins[SMA1].func == PTP_PF_PEROUT && - ptp_pins[UFL1].func == PTP_PF_PEROUT) - return -EINVAL; + for (i = 0; i < info->n_pins; i++) { + if (info->pin_config[i].func == func && + info->pin_config[i].chan == chan) + return i; + } - /* SMA2 and UFL2 cannot be set to RX at the same time */ - if (ptp_pins[SMA2].func == PTP_PF_EXTTS && - ptp_pins[UFL2].func == PTP_PF_EXTTS) - return -EINVAL; + return -1; +} - /* Read initial pin state value */ - status = ice_read_sma_ctrl_e810t(hw, &data); - if (status) - return status; - - /* Set the right sate based on the desired configuration */ - data &= ~ICE_SMA1_MASK_E810T; - if (ptp_pins[SMA1].func == PTP_PF_NONE && - ptp_pins[UFL1].func == PTP_PF_NONE) { - dev_info(ice_hw_to_dev(hw), "SMA1 + U.FL1 disabled"); - data |= ICE_SMA1_MASK_E810T; - } else if (ptp_pins[SMA1].func == PTP_PF_EXTTS && - ptp_pins[UFL1].func == PTP_PF_NONE) { - dev_info(ice_hw_to_dev(hw), "SMA1 RX"); - data |= ICE_SMA1_TX_EN_E810T; - } else if (ptp_pins[SMA1].func == PTP_PF_NONE && - ptp_pins[UFL1].func == PTP_PF_PEROUT) { - /* U.FL 1 TX will always enable SMA 1 RX */ - dev_info(ice_hw_to_dev(hw), "SMA1 RX + U.FL1 TX"); - } else if (ptp_pins[SMA1].func == PTP_PF_EXTTS && - ptp_pins[UFL1].func == PTP_PF_PEROUT) { - dev_info(ice_hw_to_dev(hw), "SMA1 RX + U.FL1 TX"); - } else if (ptp_pins[SMA1].func == PTP_PF_PEROUT && - ptp_pins[UFL1].func == PTP_PF_NONE) { - dev_info(ice_hw_to_dev(hw), "SMA1 TX"); - data |= ICE_SMA1_DIR_EN_E810T; - } - - data &= ~ICE_SMA2_MASK_E810T; - if (ptp_pins[SMA2].func == PTP_PF_NONE && - ptp_pins[UFL2].func == PTP_PF_NONE) { - dev_info(ice_hw_to_dev(hw), "SMA2 + U.FL2 disabled"); - data |= ICE_SMA2_MASK_E810T; - } else if (ptp_pins[SMA2].func == PTP_PF_EXTTS && - ptp_pins[UFL2].func == PTP_PF_NONE) { - dev_info(ice_hw_to_dev(hw), "SMA2 RX"); - data |= (ICE_SMA2_TX_EN_E810T | - ICE_SMA2_UFL2_RX_DIS_E810T); - } else if (ptp_pins[SMA2].func == PTP_PF_NONE && - ptp_pins[UFL2].func == PTP_PF_EXTTS) { - dev_info(ice_hw_to_dev(hw), "UFL2 RX"); - data |= (ICE_SMA2_DIR_EN_E810T | ICE_SMA2_TX_EN_E810T); - } else if (ptp_pins[SMA2].func == PTP_PF_PEROUT && - ptp_pins[UFL2].func == PTP_PF_NONE) { - dev_info(ice_hw_to_dev(hw), "SMA2 TX"); - data |= (ICE_SMA2_DIR_EN_E810T | - ICE_SMA2_UFL2_RX_DIS_E810T); - } else if (ptp_pins[SMA2].func == PTP_PF_PEROUT && - ptp_pins[UFL2].func == PTP_PF_EXTTS) { - dev_info(ice_hw_to_dev(hw), "SMA2 TX + U.FL2 RX"); - data |= ICE_SMA2_DIR_EN_E810T; - } - - return ice_write_sma_ctrl_e810t(hw, data); -} - -/** - * ice_ptp_set_sma_e810t - * @info: the driver's PTP info structure - * @pin: pin index in kernel structure - * @func: Pin function to be set (PTP_PF_NONE, PTP_PF_EXTTS or PTP_PF_PEROUT) - * - * Set the configuration of a single SMA pin +/** + * ice_ptp_update_sma_data - update SMA pins data according to pins setup + * @pf: Board private structure + * @sma_pins: parsed SMA pins status + * @data: SMA data to update */ -static int -ice_ptp_set_sma_e810t(struct ptp_clock_info *info, unsigned int pin, - enum ptp_pin_function func) +static void ice_ptp_update_sma_data(struct ice_pf *pf, unsigned int sma_pins[], + u8 *data) { - struct ptp_pin_desc ptp_pins[NUM_PTP_PINS_E810T]; - struct ice_pf *pf = ptp_info_to_pf(info); - struct ice_hw *hw = &pf->hw; - int err; + const char *state1, *state2; - if (pin < SMA1 || func > PTP_PF_PEROUT) - return -EOPNOTSUPP; - - err = ice_get_sma_config_e810t(hw, ptp_pins); - if (err) - return err; - - /* Disable the same function on the other pin sharing the channel */ - if (pin == SMA1 && ptp_pins[UFL1].func == func) - ptp_pins[UFL1].func = PTP_PF_NONE; - if (pin == UFL1 && ptp_pins[SMA1].func == func) - ptp_pins[SMA1].func = PTP_PF_NONE; - - if (pin == SMA2 && ptp_pins[UFL2].func == func) - ptp_pins[UFL2].func = PTP_PF_NONE; - if (pin == UFL2 && ptp_pins[SMA2].func == func) - ptp_pins[SMA2].func = PTP_PF_NONE; + /* Set the right state based on the desired configuration. + * When bit is set, functionality is disabled. + */ + *data &= ~ICE_ALL_SMA_MASK; + if (!sma_pins[UFL1 - 1]) { + if (sma_pins[SMA1 - 1] == PTP_PF_EXTTS) { + state1 = "SMA1 Rx, U.FL1 disabled"; + *data |= ICE_SMA1_TX_EN; + } else if (sma_pins[SMA1 - 1] == PTP_PF_PEROUT) { + state1 = "SMA1 Tx U.FL1 disabled"; + *data |= ICE_SMA1_DIR_EN; + } else { + state1 = "SMA1 disabled, U.FL1 disabled"; + *data |= ICE_SMA1_MASK; + } + } else { + /* U.FL1 Tx will always enable SMA1 Rx */ + state1 = "SMA1 Rx, U.FL1 Tx"; + } - /* Set up new pin function in the temp table */ - ptp_pins[pin].func = func; + if (!sma_pins[UFL2 - 1]) { + if (sma_pins[SMA2 - 1] == PTP_PF_EXTTS) { + state2 = "SMA2 Rx, U.FL2 disabled"; + *data |= ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS; + } else if (sma_pins[SMA2 - 1] == PTP_PF_PEROUT) { + state2 = "SMA2 Tx, U.FL2 disabled"; + *data |= ICE_SMA2_DIR_EN | ICE_SMA2_UFL2_RX_DIS; + } else { + state2 = "SMA2 disabled, U.FL2 disabled"; + *data |= ICE_SMA2_MASK; + } + } else { + if (!sma_pins[SMA2 - 1]) { + state2 = "SMA2 disabled, U.FL2 Rx"; + *data |= ICE_SMA2_DIR_EN | ICE_SMA2_TX_EN; + } else { + state2 = "SMA2 Tx, U.FL2 Rx"; + *data |= ICE_SMA2_DIR_EN; + } + } - return ice_ptp_set_sma_config_e810t(hw, ptp_pins); + dev_dbg(ice_pf_to_dev(pf), "%s, %s\n", state1, state2); } /** - * ice_verify_pin_e810t - * @info: the driver's PTP info structure - * @pin: Pin index - * @func: Assigned function - * @chan: Assigned channel + * ice_ptp_set_sma_cfg - set the configuration of the SMA control logic + * @pf: Board private structure * - * Verify if pin supports requested pin function. If the Check pins consistency. - * Reconfigure the SMA logic attached to the given pin to enable its - * desired functionality + * Return: 0 on success, negative error code otherwise */ -static int -ice_verify_pin_e810t(struct ptp_clock_info *info, unsigned int pin, - enum ptp_pin_function func, unsigned int chan) +static int ice_ptp_set_sma_cfg(struct ice_pf *pf) { - /* Don't allow channel reassignment */ - if (chan != ice_pin_desc_e810t[pin].chan) - return -EOPNOTSUPP; + const struct ice_ptp_pin_desc *ice_pins = pf->ptp.ice_pin_desc; + struct ptp_pin_desc *pins = pf->ptp.pin_desc; + unsigned int sma_pins[ICE_SMA_PINS_NUM] = {}; + int err; + u8 data; - /* Check if functions are properly assigned */ - switch (func) { - case PTP_PF_NONE: - break; - case PTP_PF_EXTTS: - if (pin == UFL1) - return -EOPNOTSUPP; - break; - case PTP_PF_PEROUT: - if (pin == UFL2 || pin == GNSS) - return -EOPNOTSUPP; - break; - case PTP_PF_PHYSYNC: - return -EOPNOTSUPP; - } + /* Read initial pin state value */ + err = ice_read_sma_ctrl(&pf->hw, &data); + if (err) + return err; - return ice_ptp_set_sma_e810t(info, pin, func); + /* Get SMA/U.FL pins states */ + for (int i = 0; i < pf->ptp.info.n_pins; i++) + if (pins[i].func) { + int name_idx = ice_pins[i].name_idx; + + switch (name_idx) { + case SMA1: + case UFL1: + case SMA2: + case UFL2: + sma_pins[name_idx - 1] = pins[i].func; + break; + default: + continue; + } + } + + ice_ptp_update_sma_data(pf, sma_pins, &data); + return ice_write_sma_ctrl(&pf->hw, data); } /** @@ -800,8 +734,8 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf) struct ice_ptp_port *port; unsigned int i; - mutex_lock(&pf->ptp.ports_owner.lock); - list_for_each_entry(port, &pf->ptp.ports_owner.ports, list_member) { + mutex_lock(&pf->adapter->ports.lock); + list_for_each_entry(port, &pf->adapter->ports.ports, list_node) { struct ice_ptp_tx *tx = &port->tx; if (!tx || !tx->init) @@ -809,7 +743,7 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf) ice_ptp_process_tx_tstamp(tx); } - mutex_unlock(&pf->ptp.ports_owner.lock); + mutex_unlock(&pf->adapter->ports.lock); for (i = 0; i < ICE_GET_QUAD_NUM(pf->hw.ptp.num_lports); i++) { u64 tstamp_ready; @@ -974,7 +908,7 @@ ice_ptp_flush_all_tx_tracker(struct ice_pf *pf) { struct ice_ptp_port *port; - list_for_each_entry(port, &pf->ptp.ports_owner.ports, list_member) + list_for_each_entry(port, &pf->adapter->ports.ports, list_node) ice_ptp_flush_tx_tracker(ptp_port_to_pf(port), &port->tx); } @@ -1363,7 +1297,7 @@ ice_ptp_port_phy_stop(struct ice_ptp_port *ptp_port) mutex_lock(&ptp_port->ps_lock); - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: err = ice_stop_phy_timer_eth56g(hw, port, true); break; @@ -1409,7 +1343,7 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port) mutex_lock(&ptp_port->ps_lock); - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: err = ice_start_phy_timer_eth56g(hw, port); break; @@ -1480,8 +1414,7 @@ void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) /* Skip HW writes if reset is in progress */ if (pf->hw.reset_ongoing) return; - - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_E810: /* Do not reconfigure E810 PHY */ return; @@ -1514,7 +1447,7 @@ static int ice_ptp_cfg_phy_interrupt(struct ice_pf *pf, bool ena, u32 threshold) ice_ptp_reset_ts_memory(hw); - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: { int port; @@ -1553,7 +1486,7 @@ static int ice_ptp_cfg_phy_interrupt(struct ice_pf *pf, bool ena, u32 threshold) case ICE_PHY_UNSUP: default: dev_warn(dev, "%s: Unexpected PHY model %d\n", __func__, - hw->ptp.phy_model); + ice_get_phy_model(hw)); return -EOPNOTSUPP; } } @@ -1575,10 +1508,10 @@ static void ice_ptp_restart_all_phy(struct ice_pf *pf) { struct list_head *entry; - list_for_each(entry, &pf->ptp.ports_owner.ports) { + list_for_each(entry, &pf->adapter->ports.ports) { struct ice_ptp_port *port = list_entry(entry, struct ice_ptp_port, - list_member); + list_node); if (port->link_up) ice_ptp_port_phy_restart(port); @@ -1651,33 +1584,41 @@ void ice_ptp_extts_event(struct ice_pf *pf) /** * ice_ptp_cfg_extts - Configure EXTTS pin and channel * @pf: Board private structure - * @chan: GPIO channel (0-3) - * @config: desired EXTTS configuration. - * @store: If set to true, the values will be stored + * @rq: External timestamp request + * @on: Enable/disable flag * * Configure an external timestamp event on the requested channel. * - * Return: 0 on success, -EOPNOTUSPP on unsupported flags + * Return: 0 on success, negative error code otherwise */ -static int ice_ptp_cfg_extts(struct ice_pf *pf, unsigned int chan, - struct ice_extts_channel *config, bool store) +static int ice_ptp_cfg_extts(struct ice_pf *pf, struct ptp_extts_request *rq, + int on) { - u32 func, aux_reg, gpio_reg, irq_reg; + u32 aux_reg, gpio_reg, irq_reg; struct ice_hw *hw = &pf->hw; + unsigned int chan, gpio_pin; + int pin_desc_idx; u8 tmr_idx; /* Reject requests with unsupported flags */ - if (config->flags & ~(PTP_ENABLE_FEATURE | - PTP_RISING_EDGE | - PTP_FALLING_EDGE | - PTP_STRICT_FLAGS)) + + if (rq->flags & ~(PTP_ENABLE_FEATURE | + PTP_RISING_EDGE | + PTP_FALLING_EDGE | + PTP_STRICT_FLAGS)) return -EOPNOTSUPP; tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; + chan = rq->index; + pin_desc_idx = ice_ptp_find_pin_idx(pf, PTP_PF_EXTTS, chan); + if (pin_desc_idx < 0) + return -EIO; + + gpio_pin = pf->ptp.ice_pin_desc[pin_desc_idx].gpio[0]; irq_reg = rd32(hw, PFINT_OICR_ENA); - if (config->ena) { + if (on) { /* Enable the interrupt */ irq_reg |= PFINT_OICR_TSYN_EVNT_M; aux_reg = GLTSYN_AUX_IN_0_INT_ENA_M; @@ -1686,33 +1627,38 @@ static int ice_ptp_cfg_extts(struct ice_pf *pf, unsigned int chan, #define GLTSYN_AUX_IN_0_EVNTLVL_FALLING_EDGE BIT(1) /* set event level to requested edge */ - if (config->flags & PTP_FALLING_EDGE) + if (rq->flags & PTP_FALLING_EDGE) aux_reg |= GLTSYN_AUX_IN_0_EVNTLVL_FALLING_EDGE; - if (config->flags & PTP_RISING_EDGE) + if (rq->flags & PTP_RISING_EDGE) aux_reg |= GLTSYN_AUX_IN_0_EVNTLVL_RISING_EDGE; /* Write GPIO CTL reg. * 0x1 is input sampled by EVENT register(channel) * + num_in_channels * tmr_idx */ - func = 1 + chan + (tmr_idx * 3); - gpio_reg = FIELD_PREP(GLGEN_GPIO_CTL_PIN_FUNC_M, func); - pf->ptp.ext_ts_chan |= (1 << chan); + gpio_reg = FIELD_PREP(GLGEN_GPIO_CTL_PIN_FUNC_M, + 1 + chan + (tmr_idx * 3)); } else { + bool last_enabled = true; + /* clear the values we set to reset defaults */ aux_reg = 0; gpio_reg = 0; - pf->ptp.ext_ts_chan &= ~(1 << chan); - if (!pf->ptp.ext_ts_chan) + + for (unsigned int i = 0; i < pf->ptp.info.n_ext_ts; i++) + if ((pf->ptp.extts_rqs[i].flags & + PTP_ENABLE_FEATURE) && + i != chan) { + last_enabled = false; + } + + if (last_enabled) irq_reg &= ~PFINT_OICR_TSYN_EVNT_M; } wr32(hw, PFINT_OICR_ENA, irq_reg); wr32(hw, GLTSYN_AUX_IN(chan, tmr_idx), aux_reg); - wr32(hw, GLGEN_GPIO_CTL(config->gpio_pin), gpio_reg); - - if (store) - memcpy(&pf->ptp.extts_channels[chan], config, sizeof(*config)); + wr32(hw, GLGEN_GPIO_CTL(gpio_pin), gpio_reg); return 0; } @@ -1723,16 +1669,10 @@ static int ice_ptp_cfg_extts(struct ice_pf *pf, unsigned int chan, */ static void ice_ptp_disable_all_extts(struct ice_pf *pf) { - struct ice_extts_channel extts_cfg = {}; - int i; - - for (i = 0; i < pf->ptp.info.n_ext_ts; i++) { - if (pf->ptp.extts_channels[i].ena) { - extts_cfg.gpio_pin = pf->ptp.extts_channels[i].gpio_pin; - extts_cfg.ena = false; - ice_ptp_cfg_extts(pf, i, &extts_cfg, false); - } - } + for (unsigned int i = 0; i < pf->ptp.info.n_ext_ts ; i++) + if (pf->ptp.extts_rqs[i].flags & PTP_ENABLE_FEATURE) + ice_ptp_cfg_extts(pf, &pf->ptp.extts_rqs[i], + false); synchronize_irq(pf->oicr_irq.virq); } @@ -1745,273 +1685,322 @@ static void ice_ptp_disable_all_extts(struct ice_pf *pf) */ static void ice_ptp_enable_all_extts(struct ice_pf *pf) { - int i; - - for (i = 0; i < pf->ptp.info.n_ext_ts; i++) { - if (pf->ptp.extts_channels[i].ena) - ice_ptp_cfg_extts(pf, i, &pf->ptp.extts_channels[i], - false); - } + for (unsigned int i = 0; i < pf->ptp.info.n_ext_ts ; i++) + if (pf->ptp.extts_rqs[i].flags & PTP_ENABLE_FEATURE) + ice_ptp_cfg_extts(pf, &pf->ptp.extts_rqs[i], + true); } /** - * ice_ptp_cfg_clkout - Configure clock to generate periodic wave - * @pf: Board private structure - * @chan: GPIO channel (0-3) - * @config: desired periodic clk configuration. NULL will disable channel - * @store: If set to true the values will be stored + * ice_ptp_write_perout - Write periodic wave parameters to HW + * @hw: pointer to the HW struct + * @chan: target channel + * @gpio_pin: target GPIO pin + * @start: target time to start periodic output + * @period: target period * - * Configure the internal clock generator modules to generate the clock wave of - * specified period. + * Return: 0 on success, negative error code otherwise */ -static int ice_ptp_cfg_clkout(struct ice_pf *pf, unsigned int chan, - struct ice_perout_channel *config, bool store) +static int ice_ptp_write_perout(struct ice_hw *hw, unsigned int chan, + unsigned int gpio_pin, u64 start, u64 period) { - u64 current_time, period, start_time, phase; - struct ice_hw *hw = &pf->hw; - u32 func, val, gpio_pin; - u8 tmr_idx; - if (config && config->flags & ~PTP_PEROUT_PHASE) - return -EOPNOTSUPP; - - tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; + u8 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; + u32 val = 0; /* 0. Reset mode & out_en in AUX_OUT */ wr32(hw, GLTSYN_AUX_OUT(chan, tmr_idx), 0); - /* If we're disabling the output, clear out CLKO and TGT and keep - * output level low - */ - if (!config || !config->ena) { - wr32(hw, GLTSYN_CLKO(chan, tmr_idx), 0); - wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), 0); - wr32(hw, GLTSYN_TGT_H(chan, tmr_idx), 0); - - val = GLGEN_GPIO_CTL_PIN_DIR_M; - gpio_pin = pf->ptp.perout_channels[chan].gpio_pin; - wr32(hw, GLGEN_GPIO_CTL(gpio_pin), val); - - /* Store the value if requested */ - if (store) - memset(&pf->ptp.perout_channels[chan], 0, - sizeof(struct ice_perout_channel)); - - return 0; - } - period = config->period; - start_time = config->start_time; - div64_u64_rem(start_time, period, &phase); - gpio_pin = config->gpio_pin; + if (ice_is_e825c(hw)) { + int err; - /* 1. Write clkout with half of required period value */ - if (period & 0x1) { - dev_err(ice_pf_to_dev(pf), "CLK Period must be an even value\n"); - goto err; + /* Enable/disable CGU 1PPS output for E825C */ + err = ice_cgu_cfg_pps_out(hw, !!period); + if (err) + return err; } + /* 1. Write perout with half of required period value. + * HW toggles output when source clock hits the TGT and then adds + * GLTSYN_CLKO value to the target, so it ends up with 50% duty cycle. + */ period >>= 1; - /* For proper operation, the GLTSYN_CLKO must be larger than clock tick + /* For proper operation, GLTSYN_CLKO must be larger than clock tick and + * period has to fit in 32 bit register. */ #define MIN_PULSE 3 - if (period <= MIN_PULSE || period > U32_MAX) { - dev_err(ice_pf_to_dev(pf), "CLK Period must be > %d && < 2^33", - MIN_PULSE * 2); - goto err; + if (!!period && (period <= MIN_PULSE || period > U32_MAX)) { + dev_err(ice_hw_to_dev(hw), "CLK period ticks must be >= %d && <= 2^32", + MIN_PULSE); + return -EIO; } wr32(hw, GLTSYN_CLKO(chan, tmr_idx), lower_32_bits(period)); - /* Allow time for programming before start_time is hit */ - current_time = ice_ptp_read_src_clk_reg(pf, NULL); - - /* if start time is in the past start the timer at the nearest second - * maintaining phase - */ - if (start_time < current_time) - start_time = roundup_u64(current_time, NSEC_PER_SEC) + phase; - - if (ice_is_e810(hw)) - start_time -= E810_OUT_PROP_DELAY_NS; - else - start_time -= ice_e82x_pps_delay(ice_e82x_time_ref(hw)); - /* 2. Write TARGET time */ - wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), lower_32_bits(start_time)); - wr32(hw, GLTSYN_TGT_H(chan, tmr_idx), upper_32_bits(start_time)); + wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), lower_32_bits(start)); + wr32(hw, GLTSYN_TGT_H(chan, tmr_idx), upper_32_bits(start)); /* 3. Write AUX_OUT register */ - val = GLTSYN_AUX_OUT_0_OUT_ENA_M | GLTSYN_AUX_OUT_0_OUTMOD_M; + if (!!period) + val = GLTSYN_AUX_OUT_0_OUT_ENA_M | GLTSYN_AUX_OUT_0_OUTMOD_M; wr32(hw, GLTSYN_AUX_OUT(chan, tmr_idx), val); /* 4. write GPIO CTL reg */ - func = 8 + chan + (tmr_idx * 4); - val = GLGEN_GPIO_CTL_PIN_DIR_M | - FIELD_PREP(GLGEN_GPIO_CTL_PIN_FUNC_M, func); + val = GLGEN_GPIO_CTL_PIN_DIR_M; + if (!!period) + val |= FIELD_PREP(GLGEN_GPIO_CTL_PIN_FUNC_M, + 8 + chan + (tmr_idx * 4)); + wr32(hw, GLGEN_GPIO_CTL(gpio_pin), val); - /* Store the value if requested */ - if (store) { - memcpy(&pf->ptp.perout_channels[chan], config, - sizeof(struct ice_perout_channel)); - pf->ptp.perout_channels[chan].start_time = phase; + return 0; +} + +/** + * ice_ptp_cfg_perout - Configure clock to generate periodic wave + * @pf: Board private structure + * @rq: Periodic output request + * @on: Enable/disable flag + * + * Configure the internal clock generator modules to generate the clock wave of + * specified period. + * + * Return: 0 on success, negative error code otherwise + */ +static int ice_ptp_cfg_perout(struct ice_pf *pf, struct ptp_perout_request *rq, + int on) +{ + u64 clk, period, start, phase; + struct ice_hw *hw = &pf->hw; + unsigned int gpio_pin; + int pin_desc_idx; + + if (rq->flags & ~PTP_PEROUT_PHASE) + return -EOPNOTSUPP; + + pin_desc_idx = ice_ptp_find_pin_idx(pf, PTP_PF_PEROUT, rq->index); + if (pin_desc_idx < 0) + return -EIO; + + gpio_pin = pf->ptp.ice_pin_desc[pin_desc_idx].gpio[1]; + period = rq->period.sec * NSEC_PER_SEC + rq->period.nsec; + + /* If we're disabling the output or period is 0, clear out CLKO and TGT + * and keep output level low. + */ + if (!on || !period) + return ice_ptp_write_perout(hw, rq->index, gpio_pin, 0, 0); + + if (strncmp(pf->ptp.pin_desc[pin_desc_idx].name, "1PPS", 64) == 0 && + period != NSEC_PER_SEC && hw->ptp.phy_model == ICE_PHY_E82X) { + dev_err(ice_pf_to_dev(pf), "1PPS pin supports only 1 s period\n"); + return -EOPNOTSUPP; } - return 0; -err: - dev_err(ice_pf_to_dev(pf), "PTP failed to cfg per_clk\n"); - return -EFAULT; + if (period & 0x1) { + dev_err(ice_pf_to_dev(pf), "CLK Period must be an even value\n"); + return -EIO; + } + + start = rq->start.sec * NSEC_PER_SEC + rq->start.nsec; + + /* If PTP_PEROUT_PHASE is set, rq has phase instead of start time */ + if (rq->flags & PTP_PEROUT_PHASE) + phase = start; + else + div64_u64_rem(start, period, &phase); + + /* If we have only phase or start time is in the past, start the timer + * at the next multiple of period, maintaining phase. + */ + clk = ice_ptp_read_src_clk_reg(pf, NULL); + if (rq->flags & PTP_PEROUT_PHASE || start <= clk - ice_prop_delay(hw)) + start = div64_u64(clk + period - 1, period) * period + phase; + + /* Compensate for propagation delay from the generator to the pin. */ + start -= ice_prop_delay(hw); + + return ice_ptp_write_perout(hw, rq->index, gpio_pin, start, period); } /** - * ice_ptp_disable_all_clkout - Disable all currently configured outputs - * @pf: pointer to the PF structure + * ice_ptp_disable_all_perout - Disable all currently configured outputs + * @pf: Board private structure * * Disable all currently configured clock outputs. This is necessary before - * certain changes to the PTP hardware clock. Use ice_ptp_enable_all_clkout to + * certain changes to the PTP hardware clock. Use ice_ptp_enable_all_perout to * re-enable the clocks again. */ -static void ice_ptp_disable_all_clkout(struct ice_pf *pf) +static void ice_ptp_disable_all_perout(struct ice_pf *pf) { - uint i; - - for (i = 0; i < pf->ptp.info.n_per_out; i++) - if (pf->ptp.perout_channels[i].ena) - ice_ptp_cfg_clkout(pf, i, NULL, false); + for (unsigned int i = 0; i < pf->ptp.info.n_per_out; i++) + if (pf->ptp.perout_rqs[i].period.sec || + pf->ptp.perout_rqs[i].period.nsec) + ice_ptp_cfg_perout(pf, &pf->ptp.perout_rqs[i], + false); } /** - * ice_ptp_enable_all_clkout - Enable all configured periodic clock outputs - * @pf: pointer to the PF structure + * ice_ptp_enable_all_perout - Enable all configured periodic clock outputs + * @pf: Board private structure * * Enable all currently configured clock outputs. Use this after - * ice_ptp_disable_all_clkout to reconfigure the output signals according to + * ice_ptp_disable_all_perout to reconfigure the output signals according to * their configuration. */ -static void ice_ptp_enable_all_clkout(struct ice_pf *pf) +static void ice_ptp_enable_all_perout(struct ice_pf *pf) { - uint i; - - for (i = 0; i < pf->ptp.info.n_per_out; i++) - if (pf->ptp.perout_channels[i].ena) - ice_ptp_cfg_clkout(pf, i, &pf->ptp.perout_channels[i], - false); + for (unsigned int i = 0; i < pf->ptp.info.n_per_out; i++) + if (pf->ptp.perout_rqs[i].period.sec || + pf->ptp.perout_rqs[i].period.nsec) + ice_ptp_cfg_perout(pf, &pf->ptp.perout_rqs[i], + true); } /** - * ice_ptp_gpio_enable_e810 - Enable/disable ancillary features of PHC - * @info: the driver's PTP info structure - * @rq: The requested feature to change - * @on: Enable/disable flag + * ice_ptp_disable_shared_pin - Disable enabled pin that shares GPIO + * @pf: Board private structure + * @pin: Pin index + * @func: Assigned function + * + * Return: 0 on success, negative error code otherwise */ -static int -ice_ptp_gpio_enable_e810(struct ptp_clock_info *info, - struct ptp_clock_request *rq, int on) +static int ice_ptp_disable_shared_pin(struct ice_pf *pf, unsigned int pin, + enum ptp_pin_function func) { - struct ice_pf *pf = ptp_info_to_pf(info); - bool sma_pres = false; - unsigned int chan; - u32 gpio_pin; + unsigned int gpio_pin; - if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) - sma_pres = true; + switch (func) { + case PTP_PF_PEROUT: + gpio_pin = pf->ptp.ice_pin_desc[pin].gpio[1]; + break; + case PTP_PF_EXTTS: + gpio_pin = pf->ptp.ice_pin_desc[pin].gpio[0]; + break; + default: + return -EOPNOTSUPP; + } - switch (rq->type) { - case PTP_CLK_REQ_PEROUT: - { - struct ice_perout_channel clk_cfg = {}; - - chan = rq->perout.index; - if (sma_pres) { - if (chan == ice_pin_desc_e810t[SMA1].chan) - clk_cfg.gpio_pin = GPIO_20; - else if (chan == ice_pin_desc_e810t[SMA2].chan) - clk_cfg.gpio_pin = GPIO_22; - else - return -1; - } else if (ice_is_e810t(&pf->hw)) { - if (chan == 0) - clk_cfg.gpio_pin = GPIO_20; - else - clk_cfg.gpio_pin = GPIO_22; - } else if (chan == PPS_CLK_GEN_CHAN) { - clk_cfg.gpio_pin = PPS_PIN_INDEX; - } else { - clk_cfg.gpio_pin = chan; - } + for (unsigned int i = 0; i < pf->ptp.info.n_pins; i++) { + struct ptp_pin_desc *pin_desc = &pf->ptp.pin_desc[i]; + unsigned int chan = pin_desc->chan; - clk_cfg.flags = rq->perout.flags; - clk_cfg.period = ((rq->perout.period.sec * NSEC_PER_SEC) + - rq->perout.period.nsec); - clk_cfg.start_time = ((rq->perout.start.sec * NSEC_PER_SEC) + - rq->perout.start.nsec); - clk_cfg.ena = !!on; + /* Skip pin idx from the request */ + if (i == pin) + continue; - return ice_ptp_cfg_clkout(pf, chan, &clk_cfg, true); - } - case PTP_CLK_REQ_EXTTS: - { - struct ice_extts_channel extts_cfg = {}; - - chan = rq->extts.index; - if (sma_pres) { - if (chan < ice_pin_desc_e810t[SMA2].chan) - gpio_pin = GPIO_21; - else - gpio_pin = GPIO_23; - } else if (ice_is_e810t(&pf->hw)) { - if (chan == 0) - gpio_pin = GPIO_21; - else - gpio_pin = GPIO_23; - } else { - gpio_pin = chan; + if (pin_desc->func == PTP_PF_PEROUT && + pf->ptp.ice_pin_desc[i].gpio[1] == gpio_pin) { + pf->ptp.perout_rqs[chan].period.sec = 0; + pf->ptp.perout_rqs[chan].period.nsec = 0; + pin_desc->func = PTP_PF_NONE; + pin_desc->chan = 0; + dev_dbg(ice_pf_to_dev(pf), "Disabling pin %u with shared output GPIO pin %u\n", + i, gpio_pin); + return ice_ptp_cfg_perout(pf, &pf->ptp.perout_rqs[chan], + false); + } else if (pf->ptp.pin_desc->func == PTP_PF_EXTTS && + pf->ptp.ice_pin_desc[i].gpio[0] == gpio_pin) { + pf->ptp.extts_rqs[chan].flags &= ~PTP_ENABLE_FEATURE; + pin_desc->func = PTP_PF_NONE; + pin_desc->chan = 0; + dev_dbg(ice_pf_to_dev(pf), "Disabling pin %u with shared input GPIO pin %u\n", + i, gpio_pin); + return ice_ptp_cfg_extts(pf, &pf->ptp.extts_rqs[chan], + false); } + } - extts_cfg.flags = rq->extts.flags; - extts_cfg.gpio_pin = gpio_pin; - extts_cfg.ena = !!on; + return 0; +} - return ice_ptp_cfg_extts(pf, chan, &extts_cfg, true); - } +/** + * ice_verify_pin - verify if pin supports requested pin function + * @info: the driver's PTP info structure + * @pin: Pin index + * @func: Assigned function + * @chan: Assigned channel + * + * Return: 0 on success, -EOPNOTSUPP when function is not supported. + */ +static int ice_verify_pin(struct ptp_clock_info *info, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + struct ice_pf *pf = ptp_info_to_pf(info); + const struct ice_ptp_pin_desc *pin_desc; + + pin_desc = &pf->ptp.ice_pin_desc[pin]; + + /* Is assigned function allowed? */ + switch (func) { + case PTP_PF_EXTTS: + if (pin_desc->gpio[0] < 0) + return -EOPNOTSUPP; + break; + case PTP_PF_PEROUT: + if (pin_desc->gpio[1] < 0) + return -EOPNOTSUPP; + break; + case PTP_PF_NONE: + break; + case PTP_PF_PHYSYNC: default: return -EOPNOTSUPP; } + + /* On adapters with SMA_CTRL disable other pins that share same GPIO */ + if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) { + ice_ptp_disable_shared_pin(pf, pin, func); + pf->ptp.pin_desc[pin].func = func; + pf->ptp.pin_desc[pin].chan = chan; + return ice_ptp_set_sma_cfg(pf); + } + + return 0; } /** - * ice_ptp_gpio_enable_e823 - Enable/disable ancillary features of PHC - * @info: the driver's PTP info structure + * ice_ptp_gpio_enable - Enable/disable ancillary features of PHC + * @info: The driver's PTP info structure * @rq: The requested feature to change * @on: Enable/disable flag + * + * Return: 0 on success, negative error code otherwise */ -static int ice_ptp_gpio_enable_e823(struct ptp_clock_info *info, - struct ptp_clock_request *rq, int on) +static int ice_ptp_gpio_enable(struct ptp_clock_info *info, + struct ptp_clock_request *rq, int on) { struct ice_pf *pf = ptp_info_to_pf(info); + int err; switch (rq->type) { - case PTP_CLK_REQ_PPS: + case PTP_CLK_REQ_PEROUT: { - struct ice_perout_channel clk_cfg = {}; + struct ptp_perout_request *cached = + &pf->ptp.perout_rqs[rq->perout.index]; - clk_cfg.flags = rq->perout.flags; - clk_cfg.gpio_pin = PPS_PIN_INDEX; - clk_cfg.period = NSEC_PER_SEC; - clk_cfg.ena = !!on; - - return ice_ptp_cfg_clkout(pf, PPS_CLK_GEN_CHAN, &clk_cfg, true); + err = ice_ptp_cfg_perout(pf, &rq->perout, on); + if (!err) { + *cached = rq->perout; + } else { + cached->period.sec = 0; + cached->period.nsec = 0; + } + return err; } case PTP_CLK_REQ_EXTTS: { - struct ice_extts_channel extts_cfg = {}; - - extts_cfg.flags = rq->extts.flags; - extts_cfg.gpio_pin = TIME_SYNC_PIN_INDEX; - extts_cfg.ena = !!on; + struct ptp_extts_request *cached = + &pf->ptp.extts_rqs[rq->extts.index]; - return ice_ptp_cfg_extts(pf, rq->extts.index, &extts_cfg, true); + err = ice_ptp_cfg_extts(pf, &rq->extts, on); + if (!err) + *cached = rq->extts; + else + cached->flags &= ~PTP_ENABLE_FEATURE; + return err; } default: return -EOPNOTSUPP; @@ -2059,7 +2048,7 @@ ice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts) /* For Vernier mode on E82X, we need to recalibrate after new settime. * Start with marking timestamps as invalid. */ - if (hw->ptp.phy_model == ICE_PHY_E82X) { + if (ice_get_phy_model(hw) == ICE_PHY_E82X) { err = ice_ptp_clear_phy_offset_ready_e82x(hw); if (err) dev_warn(ice_pf_to_dev(pf), "Failed to mark timestamps as invalid before settime\n"); @@ -2071,7 +2060,7 @@ ice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts) } /* Disable periodic outputs */ - ice_ptp_disable_all_clkout(pf); + ice_ptp_disable_all_perout(pf); err = ice_ptp_write_init(pf, &ts64); ice_ptp_unlock(hw); @@ -2080,10 +2069,10 @@ ice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts) ice_ptp_reset_cached_phctime(pf); /* Reenable periodic outputs */ - ice_ptp_enable_all_clkout(pf); + ice_ptp_enable_all_perout(pf); /* Recalibrate and re-enable timestamp blocks for E822/E823 */ - if (hw->ptp.phy_model == ICE_PHY_E82X) + if (ice_get_phy_model(hw) == ICE_PHY_E82X) ice_ptp_restart_all_phy(pf); exit: if (err) { @@ -2142,12 +2131,12 @@ static int ice_ptp_adjtime(struct ptp_clock_info *info, s64 delta) } /* Disable periodic outputs */ - ice_ptp_disable_all_clkout(pf); + ice_ptp_disable_all_perout(pf); err = ice_ptp_write_adj(pf, delta); /* Reenable periodic outputs */ - ice_ptp_enable_all_clkout(pf); + ice_ptp_enable_all_perout(pf); ice_ptp_unlock(hw); @@ -2405,20 +2394,41 @@ u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc, } /** - * ice_ptp_disable_sma_pins_e810t - Disable E810-T SMA pins + * ice_ptp_setup_pin_cfg - setup PTP pin_config structure + * @pf: Board private structure + */ +static void ice_ptp_setup_pin_cfg(struct ice_pf *pf) +{ + for (unsigned int i = 0; i < pf->ptp.info.n_pins; i++) { + const struct ice_ptp_pin_desc *desc = &pf->ptp.ice_pin_desc[i]; + struct ptp_pin_desc *pin = &pf->ptp.pin_desc[i]; + const char *name = NULL; + + if (!ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) + name = ice_pin_names[desc->name_idx]; + else if (desc->name_idx != GPIO_NA) + name = ice_pin_names_nvm[desc->name_idx]; + if (name) + strscpy(pin->name, name, sizeof(pin->name)); + + pin->index = i; + } + + pf->ptp.info.pin_config = pf->ptp.pin_desc; +} + +/** + * ice_ptp_disable_pins - Disable PTP pins * @pf: pointer to the PF structure - * @info: PTP clock info structure * * Disable the OS access to the SMA pins. Called to clear out the OS - * indications of pin support when we fail to setup the E810-T SMA control - * register. + * indications of pin support when we fail to setup the SMA control register. */ -static void -ice_ptp_disable_sma_pins_e810t(struct ice_pf *pf, struct ptp_clock_info *info) +static void ice_ptp_disable_pins(struct ice_pf *pf) { - struct device *dev = ice_pf_to_dev(pf); + struct ptp_clock_info *info = &pf->ptp.info; - dev_warn(dev, "Failed to configure E810-T SMA pin control\n"); + dev_warn(ice_pf_to_dev(pf), "Failed to configure PTP pin control\n"); info->enable = NULL; info->verify = NULL; @@ -2428,126 +2438,158 @@ ice_ptp_disable_sma_pins_e810t(struct ice_pf *pf, struct ptp_clock_info *info) } /** - * ice_ptp_setup_sma_pins_e810t - Setup the SMA pins + * ice_ptp_parse_sdp_entries - update ice_ptp_pin_desc structure from NVM * @pf: pointer to the PF structure - * @info: PTP clock info structure + * @entries: SDP connection section from NVM + * @num_entries: number of valid entries in sdp_entries + * @pins: PTP pins array to update * - * Finish setting up the SMA pins by allocating pin_config, and setting it up - * according to the current status of the SMA. On failure, disable all of the - * extended SMA pin support. + * Return: 0 on success, negative error code otherwise. */ -static void -ice_ptp_setup_sma_pins_e810t(struct ice_pf *pf, struct ptp_clock_info *info) +static int ice_ptp_parse_sdp_entries(struct ice_pf *pf, __le16 *entries, + unsigned int num_entries, + struct ice_ptp_pin_desc *pins) { - struct device *dev = ice_pf_to_dev(pf); - int err; + unsigned int n_pins = 0; + unsigned int i; - /* Allocate memory for kernel pins interface */ - info->pin_config = devm_kcalloc(dev, info->n_pins, - sizeof(*info->pin_config), GFP_KERNEL); - if (!info->pin_config) { - ice_ptp_disable_sma_pins_e810t(pf, info); - return; - } + /* Setup ice_pin_desc array */ + for (i = 0; i < ICE_N_PINS_MAX; i++) { + pins[i].name_idx = -1; + pins[i].gpio[0] = -1; + pins[i].gpio[1] = -1; + } + + for (i = 0; i < num_entries; i++) { + u16 entry = le16_to_cpu(entries[i]); + DECLARE_BITMAP(bitmap, GPIO_NA); + unsigned int bitmap_idx; + bool dir; + u16 gpio; + + *bitmap = FIELD_GET(ICE_AQC_NVM_SDP_AC_PIN_M, entry); + dir = !!FIELD_GET(ICE_AQC_NVM_SDP_AC_DIR_M, entry); + gpio = FIELD_GET(ICE_AQC_NVM_SDP_AC_SDP_NUM_M, entry); + for_each_set_bit(bitmap_idx, bitmap, GPIO_NA + 1) { + unsigned int idx; + + /* Check if entry's pin bit is valid */ + if (bitmap_idx >= NUM_PTP_PINS_NVM && + bitmap_idx != GPIO_NA) + continue; - /* Read current SMA status */ - err = ice_get_sma_config_e810t(&pf->hw, info->pin_config); - if (err) - ice_ptp_disable_sma_pins_e810t(pf, info); -} + /* Check if pin already exists */ + for (idx = 0; idx < ICE_N_PINS_MAX; idx++) + if (pins[idx].name_idx == bitmap_idx) + break; + + if (idx == ICE_N_PINS_MAX) { + /* Pin not found, setup its entry and name */ + idx = n_pins++; + pins[idx].name_idx = bitmap_idx; + if (bitmap_idx == GPIO_NA) + strscpy(pf->ptp.pin_desc[idx].name, + ice_pin_names[gpio], + sizeof(pf->ptp.pin_desc[idx] + .name)); + } -/** - * ice_ptp_setup_pins_e810 - Setup PTP pins in sysfs - * @pf: pointer to the PF instance - * @info: PTP clock capabilities - */ -static void -ice_ptp_setup_pins_e810(struct ice_pf *pf, struct ptp_clock_info *info) -{ - if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) { - info->n_ext_ts = N_EXT_TS_E810; - info->n_per_out = N_PER_OUT_E810T; - info->n_pins = NUM_PTP_PINS_E810T; - info->verify = ice_verify_pin_e810t; - - /* Complete setup of the SMA pins */ - ice_ptp_setup_sma_pins_e810t(pf, info); - } else if (ice_is_e810t(&pf->hw)) { - info->n_ext_ts = N_EXT_TS_NO_SMA_E810T; - info->n_per_out = N_PER_OUT_NO_SMA_E810T; - } else { - info->n_per_out = N_PER_OUT_E810; - info->n_ext_ts = N_EXT_TS_E810; + /* Setup in/out GPIO number */ + pins[idx].gpio[dir] = gpio; + } } -} -/** - * ice_ptp_setup_pins_e823 - Setup PTP pins in sysfs - * @pf: pointer to the PF instance - * @info: PTP clock capabilities - */ -static void -ice_ptp_setup_pins_e823(struct ice_pf *pf, struct ptp_clock_info *info) -{ - info->pps = 1; - info->n_per_out = 0; - info->n_ext_ts = 1; + for (i = 0; i < n_pins; i++) { + dev_dbg(ice_pf_to_dev(pf), + "NVM pin entry[%d] : name_idx %d gpio_out %d gpio_in %d\n", + i, pins[i].name_idx, pins[i].gpio[1], pins[i].gpio[0]); + } + + pf->ptp.info.n_pins = n_pins; + return 0; } /** - * ice_ptp_set_funcs_e82x - Set specialized functions for E82x support + * ice_ptp_set_funcs_e82x - Set specialized functions for E82X support * @pf: Board private structure - * @info: PTP info to fill * - * Assign functions to the PTP capabiltiies structure for E82x devices. + * Assign functions to the PTP capabilities structure for E82X devices. * Functions which operate across all device families should be set directly - * in ice_ptp_set_caps. Only add functions here which are distinct for E82x + * in ice_ptp_set_caps. Only add functions here which are distinct for E82X * devices. */ -static void -ice_ptp_set_funcs_e82x(struct ice_pf *pf, struct ptp_clock_info *info) +static void ice_ptp_set_funcs_e82x(struct ice_pf *pf) { #ifdef CONFIG_ICE_HWTS if (boot_cpu_has(X86_FEATURE_ART) && boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ)) - info->getcrosststamp = ice_ptp_getcrosststamp_e82x; + pf->ptp.info.getcrosststamp = ice_ptp_getcrosststamp_e82x; + #endif /* CONFIG_ICE_HWTS */ + if (ice_is_e825c(&pf->hw)) { + pf->ptp.ice_pin_desc = ice_pin_desc_e825c; + pf->ptp.info.n_pins = ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e825c); + } else { + pf->ptp.ice_pin_desc = ice_pin_desc_e82x; + pf->ptp.info.n_pins = ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e82x); + } + ice_ptp_setup_pin_cfg(pf); } /** * ice_ptp_set_funcs_e810 - Set specialized functions for E810 support * @pf: Board private structure - * @info: PTP info to fill * * Assign functions to the PTP capabiltiies structure for E810 devices. * Functions which operate across all device families should be set directly - * in ice_ptp_set_caps. Only add functions here which are distinct for e810 + * in ice_ptp_set_caps. Only add functions here which are distinct for E810 * devices. */ -static void -ice_ptp_set_funcs_e810(struct ice_pf *pf, struct ptp_clock_info *info) +static void ice_ptp_set_funcs_e810(struct ice_pf *pf) { - info->enable = ice_ptp_gpio_enable_e810; - ice_ptp_setup_pins_e810(pf, info); -} + __le16 entries[ICE_AQC_NVM_SDP_AC_MAX_SIZE]; + struct ice_ptp_pin_desc *desc = NULL; + struct ice_ptp *ptp = &pf->ptp; + unsigned int num_entries; + int err; -/** - * ice_ptp_set_funcs_e823 - Set specialized functions for E823 support - * @pf: Board private structure - * @info: PTP info to fill - * - * Assign functions to the PTP capabiltiies structure for E823 devices. - * Functions which operate across all device families should be set directly - * in ice_ptp_set_caps. Only add functions here which are distinct for e823 - * devices. - */ -static void -ice_ptp_set_funcs_e823(struct ice_pf *pf, struct ptp_clock_info *info) -{ - ice_ptp_set_funcs_e82x(pf, info); + err = ice_ptp_read_sdp_ac(&pf->hw, entries, &num_entries); + if (err) { + /* SDP section does not exist in NVM or is corrupted */ + if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) { + ptp->ice_pin_desc = ice_pin_desc_e810_sma; + ptp->info.n_pins = + ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e810_sma); + } else { + pf->ptp.ice_pin_desc = ice_pin_desc_e810; + pf->ptp.info.n_pins = + ICE_PIN_DESC_ARR_LEN(ice_pin_desc_e810); + err = 0; + } + } else { + desc = devm_kcalloc(ice_pf_to_dev(pf), ICE_N_PINS_MAX, + sizeof(struct ice_ptp_pin_desc), + GFP_KERNEL); + if (!desc) + goto err; - info->enable = ice_ptp_gpio_enable_e823; - ice_ptp_setup_pins_e823(pf, info); + err = ice_ptp_parse_sdp_entries(pf, entries, num_entries, desc); + if (err) + goto err; + + ptp->ice_pin_desc = (const struct ice_ptp_pin_desc *)desc; + } + + ptp->info.pin_config = ptp->pin_desc; + ice_ptp_setup_pin_cfg(pf); + + if (ice_is_feature_supported(pf, ICE_F_SMA_CTRL)) + err = ice_ptp_set_sma_cfg(pf); +err: + if (err) { + devm_kfree(ice_pf_to_dev(pf), desc); + ice_ptp_disable_pins(pf); + } } /** @@ -2567,13 +2609,15 @@ static void ice_ptp_set_caps(struct ice_pf *pf) info->adjfine = ice_ptp_adjfine; info->gettimex64 = ice_ptp_gettimex64; info->settime64 = ice_ptp_settime64; + info->n_per_out = GLTSYN_TGT_H_IDX_MAX; + info->n_ext_ts = GLTSYN_EVNT_H_IDX_MAX; + info->enable = ice_ptp_gpio_enable; + info->verify = ice_verify_pin; if (ice_is_e810(&pf->hw)) - ice_ptp_set_funcs_e810(pf, info); - else if (ice_is_e823(&pf->hw)) - ice_ptp_set_funcs_e823(pf, info); + ice_ptp_set_funcs_e810(pf); else - ice_ptp_set_funcs_e82x(pf, info); + ice_ptp_set_funcs_e82x(pf); } /** @@ -2775,7 +2819,7 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type) ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); /* Disable periodic outputs */ - ice_ptp_disable_all_clkout(pf); + ice_ptp_disable_all_perout(pf); src_tmr = ice_get_ptp_src_clock_index(&pf->hw); @@ -2813,10 +2857,8 @@ static int ice_ptp_rebuild_owner(struct ice_pf *pf) /* Write the increment time value to PHY and LAN */ err = ice_ptp_write_incval(hw, ice_base_incval(pf)); - if (err) { - ice_ptp_unlock(hw); - return err; - } + if (err) + goto err_unlock; /* Write the initial Time value to PHY and LAN using the cached PHC * time before the reset and time difference between stopping and @@ -2829,10 +2871,8 @@ static int ice_ptp_rebuild_owner(struct ice_pf *pf) ts = ktime_to_timespec64(ktime_get_real()); } err = ice_ptp_write_init(pf, &ts); - if (err) { - ice_ptp_unlock(hw); - return err; - } + if (err) + goto err_unlock; /* Release the global hardware lock */ ice_ptp_unlock(hw); @@ -2852,10 +2892,14 @@ static int ice_ptp_rebuild_owner(struct ice_pf *pf) } /* Re-enable all periodic outputs and external timestamp events */ - ice_ptp_enable_all_clkout(pf); + ice_ptp_enable_all_perout(pf); ice_ptp_enable_all_extts(pf); return 0; + +err_unlock: + ice_ptp_unlock(hw); + return err; } /** @@ -2895,187 +2939,49 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) dev_err(ice_pf_to_dev(pf), "PTP reset failed %d\n", err); } -/** - * ice_ptp_aux_dev_to_aux_pf - Get auxiliary PF handle for the auxiliary device - * @aux_dev: auxiliary device to get the auxiliary PF for - */ -static struct ice_pf * -ice_ptp_aux_dev_to_aux_pf(struct auxiliary_device *aux_dev) -{ - struct ice_ptp_port *aux_port; - struct ice_ptp *aux_ptp; - - aux_port = container_of(aux_dev, struct ice_ptp_port, aux_dev); - aux_ptp = container_of(aux_port, struct ice_ptp, port); - - return container_of(aux_ptp, struct ice_pf, ptp); -} - -/** - * ice_ptp_aux_dev_to_owner_pf - Get PF handle for the auxiliary device - * @aux_dev: auxiliary device to get the PF for - */ -static struct ice_pf * -ice_ptp_aux_dev_to_owner_pf(struct auxiliary_device *aux_dev) +static bool ice_is_primary(struct ice_hw *hw) { - struct ice_ptp_port_owner *ports_owner; - const struct auxiliary_driver *aux_drv; - struct ice_ptp *owner_ptp; - - if (!aux_dev->dev.driver) - return NULL; - - aux_drv = to_auxiliary_drv(aux_dev->dev.driver); - ports_owner = container_of(aux_drv, struct ice_ptp_port_owner, - aux_driver); - owner_ptp = container_of(ports_owner, struct ice_ptp, ports_owner); - return container_of(owner_ptp, struct ice_pf, ptp); + return ice_is_e825c(hw) && ice_is_dual(hw) ? + !!(hw->dev_caps.nac_topo.mode & ICE_NAC_TOPO_PRIMARY_M) : true; } -/** - * ice_ptp_auxbus_probe - Probe auxiliary devices - * @aux_dev: PF's auxiliary device - * @id: Auxiliary device ID - */ -static int ice_ptp_auxbus_probe(struct auxiliary_device *aux_dev, - const struct auxiliary_device_id *id) +static int ice_ptp_setup_adapter(struct ice_pf *pf) { - struct ice_pf *owner_pf = ice_ptp_aux_dev_to_owner_pf(aux_dev); - struct ice_pf *aux_pf = ice_ptp_aux_dev_to_aux_pf(aux_dev); - - if (WARN_ON(!owner_pf)) - return -ENODEV; + if (!ice_pf_src_tmr_owned(pf) || !ice_is_primary(&pf->hw)) + return -EPERM; - INIT_LIST_HEAD(&aux_pf->ptp.port.list_member); - mutex_lock(&owner_pf->ptp.ports_owner.lock); - list_add(&aux_pf->ptp.port.list_member, - &owner_pf->ptp.ports_owner.ports); - mutex_unlock(&owner_pf->ptp.ports_owner.lock); + pf->adapter->ctrl_pf = pf; return 0; } -/** - * ice_ptp_auxbus_remove - Remove auxiliary devices from the bus - * @aux_dev: PF's auxiliary device - */ -static void ice_ptp_auxbus_remove(struct auxiliary_device *aux_dev) +static int ice_ptp_setup_pf(struct ice_pf *pf) { - struct ice_pf *owner_pf = ice_ptp_aux_dev_to_owner_pf(aux_dev); - struct ice_pf *aux_pf = ice_ptp_aux_dev_to_aux_pf(aux_dev); + struct ice_ptp *ctrl_ptp = ice_get_ctrl_ptp(pf); + struct ice_ptp *ptp = &pf->ptp; - mutex_lock(&owner_pf->ptp.ports_owner.lock); - list_del(&aux_pf->ptp.port.list_member); - mutex_unlock(&owner_pf->ptp.ports_owner.lock); -} + if (WARN_ON(!ctrl_ptp) || ice_get_phy_model(&pf->hw) == ICE_PHY_UNSUP) + return -ENODEV; -/** - * ice_ptp_auxbus_shutdown - * @aux_dev: PF's auxiliary device - */ -static void ice_ptp_auxbus_shutdown(struct auxiliary_device *aux_dev) -{ - /* Doing nothing here, but handle to auxbus driver must be satisfied */ -} + INIT_LIST_HEAD(&ptp->port.list_node); + mutex_lock(&pf->adapter->ports.lock); -/** - * ice_ptp_auxbus_suspend - * @aux_dev: PF's auxiliary device - * @state: power management state indicator - */ -static int -ice_ptp_auxbus_suspend(struct auxiliary_device *aux_dev, pm_message_t state) -{ - /* Doing nothing here, but handle to auxbus driver must be satisfied */ - return 0; -} + list_add(&ptp->port.list_node, + &pf->adapter->ports.ports); + mutex_unlock(&pf->adapter->ports.lock); -/** - * ice_ptp_auxbus_resume - * @aux_dev: PF's auxiliary device - */ -static int ice_ptp_auxbus_resume(struct auxiliary_device *aux_dev) -{ - /* Doing nothing here, but handle to auxbus driver must be satisfied */ return 0; } -/** - * ice_ptp_auxbus_create_id_table - Create auxiliary device ID table - * @pf: Board private structure - * @name: auxiliary bus driver name - */ -static struct auxiliary_device_id * -ice_ptp_auxbus_create_id_table(struct ice_pf *pf, const char *name) -{ - struct auxiliary_device_id *ids; - - /* Second id left empty to terminate the array */ - ids = devm_kcalloc(ice_pf_to_dev(pf), 2, - sizeof(struct auxiliary_device_id), GFP_KERNEL); - if (!ids) - return NULL; - - snprintf(ids[0].name, sizeof(ids[0].name), "ice.%s", name); - - return ids; -} - -/** - * ice_ptp_register_auxbus_driver - Register PTP auxiliary bus driver - * @pf: Board private structure - */ -static int ice_ptp_register_auxbus_driver(struct ice_pf *pf) +static void ice_ptp_cleanup_pf(struct ice_pf *pf) { - struct auxiliary_driver *aux_driver; - struct ice_ptp *ptp; - struct device *dev; - char *name; - int err; - - ptp = &pf->ptp; - dev = ice_pf_to_dev(pf); - aux_driver = &ptp->ports_owner.aux_driver; - INIT_LIST_HEAD(&ptp->ports_owner.ports); - mutex_init(&ptp->ports_owner.lock); - name = devm_kasprintf(dev, GFP_KERNEL, "ptp_aux_dev_%u_%u_clk%u", - pf->pdev->bus->number, PCI_SLOT(pf->pdev->devfn), - ice_get_ptp_src_clock_index(&pf->hw)); - if (!name) - return -ENOMEM; - - aux_driver->name = name; - aux_driver->shutdown = ice_ptp_auxbus_shutdown; - aux_driver->suspend = ice_ptp_auxbus_suspend; - aux_driver->remove = ice_ptp_auxbus_remove; - aux_driver->resume = ice_ptp_auxbus_resume; - aux_driver->probe = ice_ptp_auxbus_probe; - aux_driver->id_table = ice_ptp_auxbus_create_id_table(pf, name); - if (!aux_driver->id_table) - return -ENOMEM; + struct ice_ptp *ptp = &pf->ptp; - err = auxiliary_driver_register(aux_driver); - if (err) { - devm_kfree(dev, aux_driver->id_table); - dev_err(dev, "Failed registering aux_driver, name <%s>\n", - name); + if (ice_get_phy_model(&pf->hw) != ICE_PHY_UNSUP) { + mutex_lock(&pf->adapter->ports.lock); + list_del(&ptp->port.list_node); + mutex_unlock(&pf->adapter->ports.lock); } - - return err; -} - -/** - * ice_ptp_unregister_auxbus_driver - Unregister PTP auxiliary bus driver - * @pf: Board private structure - */ -static void ice_ptp_unregister_auxbus_driver(struct ice_pf *pf) -{ - struct auxiliary_driver *aux_driver = &pf->ptp.ports_owner.aux_driver; - - auxiliary_driver_unregister(aux_driver); - devm_kfree(ice_pf_to_dev(pf), aux_driver->id_table); - - mutex_destroy(&pf->ptp.ports_owner.lock); } /** @@ -3087,15 +2993,12 @@ static void ice_ptp_unregister_auxbus_driver(struct ice_pf *pf) */ int ice_ptp_clock_index(struct ice_pf *pf) { - struct auxiliary_device *aux_dev; - struct ice_pf *owner_pf; + struct ice_ptp *ctrl_ptp = ice_get_ctrl_ptp(pf); struct ptp_clock *clock; - aux_dev = &pf->ptp.port.aux_dev; - owner_pf = ice_ptp_aux_dev_to_owner_pf(aux_dev); - if (!owner_pf) + if (!ctrl_ptp) return -1; - clock = owner_pf->ptp.clock; + clock = ctrl_ptp->clock; return clock ? ptp_clock_index(clock) : -1; } @@ -3129,18 +3032,14 @@ static int ice_ptp_init_owner(struct ice_pf *pf) /* Write the increment time value to PHY and LAN */ err = ice_ptp_write_incval(hw, ice_base_incval(pf)); - if (err) { - ice_ptp_unlock(hw); - goto err_exit; - } + if (err) + goto err_unlock; ts = ktime_to_timespec64(ktime_get_real()); /* Write the initial Time value to PHY and LAN */ err = ice_ptp_write_init(pf, &ts); - if (err) { - ice_ptp_unlock(hw); - goto err_exit; - } + if (err) + goto err_unlock; /* Release the global hardware lock */ ice_ptp_unlock(hw); @@ -3155,19 +3054,15 @@ static int ice_ptp_init_owner(struct ice_pf *pf) if (err) goto err_clk; - err = ice_ptp_register_auxbus_driver(pf); - if (err) { - dev_err(ice_pf_to_dev(pf), "Failed to register PTP auxbus driver"); - goto err_aux; - } - return 0; -err_aux: - ptp_clock_unregister(pf->ptp.clock); err_clk: pf->ptp.clock = NULL; err_exit: return err; + +err_unlock: + ice_ptp_unlock(hw); + return err; } /** @@ -3209,7 +3104,7 @@ static int ice_ptp_init_port(struct ice_pf *pf, struct ice_ptp_port *ptp_port) mutex_init(&ptp_port->ps_lock); - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: return ice_ptp_init_tx_eth56g(pf, &ptp_port->tx, ptp_port->port_num); @@ -3226,76 +3121,6 @@ static int ice_ptp_init_port(struct ice_pf *pf, struct ice_ptp_port *ptp_port) } } -/** - * ice_ptp_release_auxbus_device - * @dev: device that utilizes the auxbus - */ -static void ice_ptp_release_auxbus_device(struct device *dev) -{ - /* Doing nothing here, but handle to auxbux device must be satisfied */ -} - -/** - * ice_ptp_create_auxbus_device - Create PTP auxiliary bus device - * @pf: Board private structure - */ -static int ice_ptp_create_auxbus_device(struct ice_pf *pf) -{ - struct auxiliary_device *aux_dev; - struct ice_ptp *ptp; - struct device *dev; - char *name; - int err; - u32 id; - - ptp = &pf->ptp; - id = ptp->port.port_num; - dev = ice_pf_to_dev(pf); - - aux_dev = &ptp->port.aux_dev; - - name = devm_kasprintf(dev, GFP_KERNEL, "ptp_aux_dev_%u_%u_clk%u", - pf->pdev->bus->number, PCI_SLOT(pf->pdev->devfn), - ice_get_ptp_src_clock_index(&pf->hw)); - if (!name) - return -ENOMEM; - - aux_dev->name = name; - aux_dev->id = id; - aux_dev->dev.release = ice_ptp_release_auxbus_device; - aux_dev->dev.parent = dev; - - err = auxiliary_device_init(aux_dev); - if (err) - goto aux_err; - - err = auxiliary_device_add(aux_dev); - if (err) { - auxiliary_device_uninit(aux_dev); - goto aux_err; - } - - return 0; -aux_err: - dev_err(dev, "Failed to create PTP auxiliary bus device <%s>\n", name); - devm_kfree(dev, name); - return err; -} - -/** - * ice_ptp_remove_auxbus_device - Remove PTP auxiliary bus device - * @pf: Board private structure - */ -static void ice_ptp_remove_auxbus_device(struct ice_pf *pf) -{ - struct auxiliary_device *aux_dev = &pf->ptp.port.aux_dev; - - auxiliary_device_delete(aux_dev); - auxiliary_device_uninit(aux_dev); - - memset(aux_dev, 0, sizeof(*aux_dev)); -} - /** * ice_ptp_init_tx_interrupt_mode - Initialize device Tx interrupt mode * @pf: Board private structure @@ -3307,7 +3132,7 @@ static void ice_ptp_remove_auxbus_device(struct ice_pf *pf) */ static void ice_ptp_init_tx_interrupt_mode(struct ice_pf *pf) { - switch (pf->hw.ptp.phy_model) { + switch (ice_get_phy_model(&pf->hw)) { case ICE_PHY_E82X: /* E822 based PHY has the clock owner process the interrupt * for all ports. @@ -3350,19 +3175,26 @@ void ice_ptp_init(struct ice_pf *pf) /* If this function owns the clock hardware, it must allocate and * configure the PTP clock device to represent it. */ - if (ice_pf_src_tmr_owned(pf)) { + if (ice_pf_src_tmr_owned(pf) && ice_is_primary(hw)) { + err = ice_ptp_setup_adapter(pf); + if (err) + goto err_exit; err = ice_ptp_init_owner(pf); if (err) - goto err; + goto err_exit; } + err = ice_ptp_setup_pf(pf); + if (err) + goto err_exit; + ptp->port.port_num = hw->pf_id; if (ice_is_e825c(hw) && hw->ptp.is_2x50g_muxed_topo) ptp->port.port_num = hw->pf_id * 2; err = ice_ptp_init_port(pf, &ptp->port); if (err) - goto err; + goto err_exit; /* Start the PHY timestamping block */ ice_ptp_reset_phy_timestamping(pf); @@ -3370,20 +3202,16 @@ void ice_ptp_init(struct ice_pf *pf) /* Configure initial Tx interrupt settings */ ice_ptp_cfg_tx_interrupt(pf); - err = ice_ptp_create_auxbus_device(pf); - if (err) - goto err; - ptp->state = ICE_PTP_READY; err = ice_ptp_init_work(pf, ptp); if (err) - goto err; + goto err_exit; dev_info(ice_pf_to_dev(pf), "PTP init successful\n"); return; -err: +err_exit: /* If we registered a PTP clock, release it */ if (pf->ptp.clock) { ptp_clock_unregister(ptp->clock); @@ -3410,7 +3238,7 @@ void ice_ptp_release(struct ice_pf *pf) /* Disable timestamping for both Tx and Rx */ ice_ptp_disable_timestamp_mode(pf); - ice_ptp_remove_auxbus_device(pf); + ice_ptp_cleanup_pf(pf); ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); @@ -3425,14 +3253,11 @@ void ice_ptp_release(struct ice_pf *pf) pf->ptp.kworker = NULL; } - if (ice_pf_src_tmr_owned(pf)) - ice_ptp_unregister_auxbus_driver(pf); - if (!pf->ptp.clock) return; /* Disable periodic outputs */ - ice_ptp_disable_all_clkout(pf); + ice_ptp_disable_all_perout(pf); ptp_clock_unregister(pf->ptp.clock); pf->ptp.clock = NULL; diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 2db2257a0fb2f3..824e73b677a43c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -9,37 +9,6 @@ #include "ice_ptp_hw.h" -enum ice_ptp_pin_e810 { - GPIO_20 = 0, - GPIO_21, - GPIO_22, - GPIO_23, - NUM_PTP_PIN_E810 -}; - -enum ice_ptp_pin_e810t { - GNSS = 0, - SMA1, - UFL1, - SMA2, - UFL2, - NUM_PTP_PINS_E810T -}; - -struct ice_perout_channel { - bool ena; - u32 gpio_pin; - u32 flags; - u64 period; - u64 start_time; -}; - -struct ice_extts_channel { - bool ena; - u32 gpio_pin; - u32 flags; -}; - /* The ice hardware captures Tx hardware timestamps in the PHY. The timestamp * is stored in a buffer of registers. Depending on the specific hardware, * this buffer might be shared across multiple PHY ports. @@ -169,9 +138,8 @@ struct ice_ptp_tx { * ready for PTP functionality. It is used to track the port initialization * and determine when the port's PHY offset is valid. * - * @list_member: list member structure of auxiliary device + * @list_node: list member structure * @tx: Tx timestamp tracking for this port - * @aux_dev: auxiliary device associated with this port * @ov_work: delayed work task for tracking when PHY offset is valid * @ps_lock: mutex used to protect the overall PTP PHY start procedure * @link_up: indicates whether the link is up @@ -179,9 +147,8 @@ struct ice_ptp_tx { * @port_num: the port number this structure represents */ struct ice_ptp_port { - struct list_head list_member; + struct list_head list_node; struct ice_ptp_tx tx; - struct auxiliary_device aux_dev; struct kthread_delayed_work ov_work; struct mutex ps_lock; /* protects overall PTP PHY start procedure */ bool link_up; @@ -195,22 +162,6 @@ enum ice_ptp_tx_interrupt { ICE_PTP_TX_INTERRUPT_ALL, }; -/** - * struct ice_ptp_port_owner - data used to handle the PTP clock owner info - * - * This structure contains data necessary for the PTP clock owner to correctly - * handle the timestamping feature for all attached ports. - * - * @aux_driver: the structure carring the auxiliary driver information - * @ports: list of porst handled by this port owner - * @lock: protect access to ports list - */ -struct ice_ptp_port_owner { - struct auxiliary_driver aux_driver; - struct list_head ports; - struct mutex lock; -}; - #define GLTSYN_TGT_H_IDX_MAX 4 enum ice_ptp_state { @@ -221,20 +172,69 @@ enum ice_ptp_state { ICE_PTP_ERROR, }; +enum ice_ptp_pin { + SDP0 = 0, + SDP1, + SDP2, + SDP3, + TIME_SYNC, + ONE_PPS +}; + +enum ice_ptp_pin_nvm { + GNSS = 0, + SMA1, + UFL1, + SMA2, + UFL2, + NUM_PTP_PINS_NVM, + GPIO_NA = 9 +}; + +/* Per-channel register definitions */ +#define GLTSYN_AUX_OUT(_chan, _idx) (GLTSYN_AUX_OUT_0(_idx) + ((_chan) * 8)) +#define GLTSYN_AUX_IN(_chan, _idx) (GLTSYN_AUX_IN_0(_idx) + ((_chan) * 8)) +#define GLTSYN_CLKO(_chan, _idx) (GLTSYN_CLKO_0(_idx) + ((_chan) * 8)) +#define GLTSYN_TGT_L(_chan, _idx) (GLTSYN_TGT_L_0(_idx) + ((_chan) * 16)) +#define GLTSYN_TGT_H(_chan, _idx) (GLTSYN_TGT_H_0(_idx) + ((_chan) * 16)) +#define GLTSYN_EVNT_L(_chan, _idx) (GLTSYN_EVNT_L_0(_idx) + ((_chan) * 16)) +#define GLTSYN_EVNT_H(_chan, _idx) (GLTSYN_EVNT_H_0(_idx) + ((_chan) * 16)) +#define GLTSYN_EVNT_H_IDX_MAX 3 + +/* Pin definitions for PTP */ +#define ICE_N_PINS_MAX 6 +#define ICE_SMA_PINS_NUM 4 +#define ICE_PIN_DESC_ARR_LEN(_arr) (sizeof(_arr) / \ + sizeof(struct ice_ptp_pin_desc)) + +/** + * struct ice_ptp_pin_desc - hardware pin description data + * @name_idx: index of the name of pin in ice_pin_names + * @gpio: the associated GPIO input and output pins + * + * Structure describing a PTP-capable GPIO pin that extends ptp_pin_desc array + * for the device. Device families have separate sets of available pins with + * varying restrictions. + */ +struct ice_ptp_pin_desc { + int name_idx; + int gpio[2]; +}; + /** * struct ice_ptp - data used for integrating with CONFIG_PTP_1588_CLOCK * @state: current state of PTP state machine * @tx_interrupt_mode: the TX interrupt mode for the PTP clock * @port: data for the PHY port initialization procedure - * @ports_owner: data for the auxiliary driver owner * @work: delayed work function for periodic tasks * @cached_phc_time: a cached copy of the PHC time for timestamp extension * @cached_phc_jiffies: jiffies when cached_phc_time was last updated - * @ext_ts_chan: the external timestamp channel in use - * @ext_ts_irq: the external timestamp IRQ in use * @kworker: kwork thread for handling periodic work - * @perout_channels: periodic output data - * @extts_channels: channels for external timestamps + * @ext_ts_irq: the external timestamp IRQ in use + * @pin_desc: structure defining pins + * @ice_pin_desc: internal structure describing pin relations + * @perout_rqs: cached periodic output requests + * @extts_rqs: cached external timestamp requests * @info: structure defining PTP hardware capabilities * @clock: pointer to registered PTP clock device * @tstamp_config: hardware timestamping configuration @@ -250,15 +250,15 @@ struct ice_ptp { enum ice_ptp_state state; enum ice_ptp_tx_interrupt tx_interrupt_mode; struct ice_ptp_port port; - struct ice_ptp_port_owner ports_owner; struct kthread_delayed_work work; u64 cached_phc_time; unsigned long cached_phc_jiffies; - u8 ext_ts_chan; - u8 ext_ts_irq; struct kthread_worker *kworker; - struct ice_perout_channel perout_channels[GLTSYN_TGT_H_IDX_MAX]; - struct ice_extts_channel extts_channels[GLTSYN_TGT_H_IDX_MAX]; + u8 ext_ts_irq; + struct ptp_pin_desc pin_desc[ICE_N_PINS_MAX]; + const struct ice_ptp_pin_desc *ice_pin_desc; + struct ptp_perout_request perout_rqs[GLTSYN_TGT_H_IDX_MAX]; + struct ptp_extts_request extts_rqs[GLTSYN_EVNT_H_IDX_MAX]; struct ptp_clock_info info; struct ptp_clock *clock; struct hwtstamp_config tstamp_config; @@ -289,27 +289,6 @@ struct ice_ptp { #define FIFO_EMPTY BIT(2) #define FIFO_OK 0xFF #define ICE_PTP_FIFO_NUM_CHECKS 5 -/* Per-channel register definitions */ -#define GLTSYN_AUX_OUT(_chan, _idx) (GLTSYN_AUX_OUT_0(_idx) + ((_chan) * 8)) -#define GLTSYN_AUX_IN(_chan, _idx) (GLTSYN_AUX_IN_0(_idx) + ((_chan) * 8)) -#define GLTSYN_CLKO(_chan, _idx) (GLTSYN_CLKO_0(_idx) + ((_chan) * 8)) -#define GLTSYN_TGT_L(_chan, _idx) (GLTSYN_TGT_L_0(_idx) + ((_chan) * 16)) -#define GLTSYN_TGT_H(_chan, _idx) (GLTSYN_TGT_H_0(_idx) + ((_chan) * 16)) -#define GLTSYN_EVNT_L(_chan, _idx) (GLTSYN_EVNT_L_0(_idx) + ((_chan) * 16)) -#define GLTSYN_EVNT_H(_chan, _idx) (GLTSYN_EVNT_H_0(_idx) + ((_chan) * 16)) -#define GLTSYN_EVNT_H_IDX_MAX 3 - -/* Pin definitions for PTP PPS out */ -#define PPS_CLK_GEN_CHAN 3 -#define PPS_CLK_SRC_CHAN 2 -#define PPS_PIN_INDEX 5 -#define TIME_SYNC_PIN_INDEX 4 -#define N_EXT_TS_E810 3 -#define N_PER_OUT_E810 4 -#define N_PER_OUT_E810T 3 -#define N_PER_OUT_NO_SMA_E810T 2 -#define N_EXT_TS_NO_SMA_E810T 2 -#define ETH_GLTSYN_ENA(_i) (0x03000348 + ((_i) * 4)) #if IS_ENABLED(CONFIG_PTP_1588_CLOCK) int ice_ptp_clock_index(struct ice_pf *pf); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h index e6980b94a6c1d6..585ce200c60f13 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h @@ -334,7 +334,7 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { * reference. See the struct ice_time_ref_info_e82x for information about the * meaning of each constant. */ -const struct ice_time_ref_info_e82x e822_time_ref[NUM_ICE_TIME_REF_FREQ] = { +const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ] = { /* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */ { /* pll_freq */ diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index ec8db830ac73ae..518893f23372bf 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -659,6 +659,29 @@ static int ice_cfg_cgu_pll_e825c(struct ice_hw *hw, return 0; } +#define ICE_ONE_PPS_OUT_AMP_MAX 3 + +/** + * ice_cgu_cfg_pps_out - Configure 1PPS output from CGU + * @hw: pointer to the HW struct + * @enable: true to enable 1PPS output, false to disable it + * + * Return: 0 on success, other negative error code when CGU read/write failed + */ +int ice_cgu_cfg_pps_out(struct ice_hw *hw, bool enable) +{ + union nac_cgu_dword9 dw9; + int err; + + err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val); + if (err) + return err; + + dw9.one_pps_out_en = enable; + dw9.one_pps_out_amp = enable * ICE_ONE_PPS_OUT_AMP_MAX; + return ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val); +} + /** * ice_cfg_cgu_pll_dis_sticky_bits_e82x - disable TS PLL sticky bits * @hw: pointer to the HW struct @@ -804,7 +827,7 @@ static u32 ice_ptp_tmr_cmd_to_port_reg(struct ice_hw *hw, /* Certain hardware families share the same register values for the * port register and source timer register. */ - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_E810: return ice_ptp_tmr_cmd_to_src_reg(hw, cmd) & TS_CMD_MASK_E810; default: @@ -1495,7 +1518,8 @@ static int ice_read_ptp_tstamp_eth56g(struct ice_hw *hw, u8 port, u8 idx, * lower 8 bits in the low register, and the upper 32 bits in the high * register. */ - *tstamp = ((u64)hi) << TS_PHY_HIGH_S | ((u64)lo & TS_PHY_LOW_M); + *tstamp = FIELD_PREP(TS_PHY_HIGH_M, hi) | + FIELD_PREP(TS_PHY_LOW_M, lo); return 0; } @@ -5148,9 +5172,9 @@ ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready) return 0; } -/* E810T SMA functions +/* E810 SMA functions * - * The following functions operate specifically on E810T hardware and are used + * The following functions operate specifically on E810 hardware and are used * to access the extended GPIOs available. */ @@ -5217,14 +5241,14 @@ ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle) } /** - * ice_read_sma_ctrl_e810t + * ice_read_sma_ctrl * @hw: pointer to the hw struct * @data: pointer to data to be read from the GPIO controller * * Read the SMA controller state. It is connected to pins 3-7 of Port 1 of the * PCA9575 expander, so only bits 3-7 in data are valid. */ -int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) +int ice_read_sma_ctrl(struct ice_hw *hw, u8 *data) { int status; u16 handle; @@ -5236,7 +5260,7 @@ int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) *data = 0; - for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { + for (i = ICE_SMA_MIN_BIT; i <= ICE_SMA_MAX_BIT; i++) { bool pin; status = ice_aq_get_gpio(hw, handle, i + ICE_PCA9575_P1_OFFSET, @@ -5250,14 +5274,14 @@ int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data) } /** - * ice_write_sma_ctrl_e810t + * ice_write_sma_ctrl * @hw: pointer to the hw struct * @data: data to be written to the GPIO controller * * Write the data to the SMA controller. It is connected to pins 3-7 of Port 1 * of the PCA9575 expander, so only bits 3-7 in data are valid. */ -int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) +int ice_write_sma_ctrl(struct ice_hw *hw, u8 data) { int status; u16 handle; @@ -5267,7 +5291,7 @@ int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) if (status) return status; - for (i = ICE_SMA_MIN_BIT_E810T; i <= ICE_SMA_MAX_BIT_E810T; i++) { + for (i = ICE_SMA_MIN_BIT; i <= ICE_SMA_MAX_BIT; i++) { bool pin; pin = !(data & (1 << i)); @@ -5281,14 +5305,14 @@ int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data) } /** - * ice_read_pca9575_reg_e810t + * ice_read_pca9575_reg * @hw: pointer to the hw struct * @offset: GPIO controller register offset * @data: pointer to data to be read from the GPIO controller * * Read the register from the GPIO controller */ -int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data) +int ice_read_pca9575_reg(struct ice_hw *hw, u8 offset, u8 *data) { struct ice_aqc_link_topo_addr link_topo; __le16 addr; @@ -5311,6 +5335,66 @@ int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data) return ice_aq_read_i2c(hw, link_topo, 0, addr, 1, data, NULL); } +/** + * ice_ptp_read_sdp_ac - read SDP available connections section from NVM + * @hw: pointer to the HW struct + * @entries: returns the SDP available connections section from NVM + * @num_entries: returns the number of valid entries + * + * Return: 0 on success, negative error code if NVM read failed or section does + * not exist or is corrupted + */ +int ice_ptp_read_sdp_ac(struct ice_hw *hw, __le16 *entries, uint *num_entries) +{ + __le16 data; + u32 offset; + int err; + + err = ice_acquire_nvm(hw, ICE_RES_READ); + if (err) + goto exit; + + /* Read the offset of SDP_AC */ + offset = ICE_AQC_NVM_SDP_AC_PTR_OFFSET; + err = ice_aq_read_nvm(hw, 0, offset, sizeof(data), &data, false, true, + NULL); + if (err) + goto exit; + + /* Check if section exist */ + offset = FIELD_GET(ICE_AQC_NVM_SDP_AC_PTR_M, le16_to_cpu(data)); + if (offset == ICE_AQC_NVM_SDP_AC_PTR_INVAL) { + err = -EINVAL; + goto exit; + } + + if (offset & ICE_AQC_NVM_SDP_AC_PTR_TYPE_M) { + offset &= ICE_AQC_NVM_SDP_AC_PTR_M; + offset *= ICE_AQC_NVM_SECTOR_UNIT; + } else { + offset *= sizeof(data); + } + + /* Skip reading section length and read the number of valid entries */ + offset += sizeof(data); + err = ice_aq_read_nvm(hw, 0, offset, sizeof(data), &data, false, true, + NULL); + if (err) + goto exit; + *num_entries = le16_to_cpu(data); + + /* Read SDP configuration section */ + offset += sizeof(data); + err = ice_aq_read_nvm(hw, 0, offset, *num_entries * sizeof(data), + entries, false, true, NULL); + +exit: + if (err) + dev_dbg(ice_hw_to_dev(hw), "Failed to configure SDP connection section\n"); + ice_release_nvm(hw); + return err; +} + /** * ice_ptp_init_phy_e810 - initialize PHY parameters * @ptp: pointer to the PTP HW struct @@ -5417,7 +5501,7 @@ void ice_ptp_init_hw(struct ice_hw *hw) static int ice_ptp_write_port_cmd(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd) { - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: return ice_ptp_write_port_cmd_eth56g(hw, port, cmd); case ICE_PHY_E82X: @@ -5482,7 +5566,7 @@ static int ice_ptp_port_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd) u32 port; /* PHY models which can program all ports simultaneously */ - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_E810: return ice_ptp_port_cmd_e810(hw, cmd); default: @@ -5561,7 +5645,7 @@ int ice_ptp_init_time(struct ice_hw *hw, u64 time) /* PHY timers */ /* Fill Rx and Tx ports and send msg to PHY */ - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: err = ice_ptp_prep_phy_time_eth56g(hw, (u32)(time & 0xFFFFFFFF)); @@ -5607,7 +5691,7 @@ int ice_ptp_write_incval(struct ice_hw *hw, u64 incval) wr32(hw, GLTSYN_SHADJ_L(tmr_idx), lower_32_bits(incval)); wr32(hw, GLTSYN_SHADJ_H(tmr_idx), upper_32_bits(incval)); - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: err = ice_ptp_prep_phy_incval_eth56g(hw, incval); break; @@ -5676,7 +5760,7 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) wr32(hw, GLTSYN_SHADJ_L(tmr_idx), 0); wr32(hw, GLTSYN_SHADJ_H(tmr_idx), adj); - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: err = ice_ptp_prep_phy_adj_eth56g(hw, adj); break; @@ -5709,7 +5793,7 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) */ int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) { - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: return ice_read_ptp_tstamp_eth56g(hw, block, idx, tstamp); case ICE_PHY_E810: @@ -5739,7 +5823,7 @@ int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp) */ int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx) { - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: return ice_clear_ptp_tstamp_eth56g(hw, block, idx); case ICE_PHY_E810: @@ -5802,7 +5886,7 @@ static int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx) */ void ice_ptp_reset_ts_memory(struct ice_hw *hw) { - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: ice_ptp_reset_ts_memory_eth56g(hw); break; @@ -5831,7 +5915,7 @@ int ice_ptp_init_phc(struct ice_hw *hw) /* Clear event err indications for auxiliary pins */ (void)rd32(hw, GLTSYN_STAT(src_idx)); - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: return ice_ptp_init_phc_eth56g(hw); case ICE_PHY_E810: @@ -5856,7 +5940,7 @@ int ice_ptp_init_phc(struct ice_hw *hw) */ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) { - switch (hw->ptp.phy_model) { + switch (ice_get_phy_model(hw)) { case ICE_PHY_ETH56G: return ice_get_phy_tx_tstamp_ready_eth56g(hw, block, tstamp_ready); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index 6cedc1a906afb6..1cee0f1bba2df3 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -316,7 +316,7 @@ ice_cgu_pll_params_e825c e825c_cgu_params[NUM_ICE_TIME_REF_FREQ]; extern const struct ice_phy_reg_info_eth56g eth56g_phy_res[NUM_ETH56G_PHY_RES]; /* Table of constants related to possible TIME_REF sources */ -extern const struct ice_time_ref_info_e82x e822_time_ref[NUM_ICE_TIME_REF_FREQ]; +extern const struct ice_time_ref_info_e82x e82x_time_ref[NUM_ICE_TIME_REF_FREQ]; /* Table of constants for Vernier calibration on E822 */ extern const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD]; @@ -326,10 +326,12 @@ extern const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD]; */ #define ICE_E810_PLL_FREQ 812500000 #define ICE_PTP_NOMINAL_INCVAL_E810 0x13b13b13bULL -#define E810_OUT_PROP_DELAY_NS 1 +#define ICE_E810_OUT_PROP_DELAY_NS 1 +#define ICE_E825C_OUT_PROP_DELAY_NS 11 /* Device agnostic functions */ u8 ice_get_ptp_src_clock_index(struct ice_hw *hw); +int ice_cgu_cfg_pps_out(struct ice_hw *hw, bool enable); bool ice_ptp_lock(struct ice_hw *hw); void ice_ptp_unlock(struct ice_hw *hw); void ice_ptp_src_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd); @@ -358,7 +360,7 @@ void ice_ptp_reset_ts_memory_quad_e82x(struct ice_hw *hw, u8 quad); * * Returns the current TIME_REF from the capabilities structure. */ -static inline enum ice_time_ref_freq ice_e82x_time_ref(struct ice_hw *hw) +static inline enum ice_time_ref_freq ice_e82x_time_ref(const struct ice_hw *hw) { return hw->func_caps.ts_func_info.time_ref; } @@ -379,17 +381,17 @@ ice_set_e82x_time_ref(struct ice_hw *hw, enum ice_time_ref_freq time_ref) static inline u64 ice_e82x_pll_freq(enum ice_time_ref_freq time_ref) { - return e822_time_ref[time_ref].pll_freq; + return e82x_time_ref[time_ref].pll_freq; } static inline u64 ice_e82x_nominal_incval(enum ice_time_ref_freq time_ref) { - return e822_time_ref[time_ref].nominal_incval; + return e82x_time_ref[time_ref].nominal_incval; } static inline u64 ice_e82x_pps_delay(enum ice_time_ref_freq time_ref) { - return e822_time_ref[time_ref].pps_delay; + return e82x_time_ref[time_ref].pps_delay; } /* E822 Vernier calibration functions */ @@ -400,10 +402,10 @@ int ice_phy_cfg_rx_offset_e82x(struct ice_hw *hw, u8 port); int ice_phy_cfg_intr_e82x(struct ice_hw *hw, u8 quad, bool ena, u8 threshold); /* E810 family functions */ -int ice_read_sma_ctrl_e810t(struct ice_hw *hw, u8 *data); -int ice_write_sma_ctrl_e810t(struct ice_hw *hw, u8 data); -int ice_read_pca9575_reg_e810t(struct ice_hw *hw, u8 offset, u8 *data); -bool ice_is_pca9575_present(struct ice_hw *hw); +int ice_read_sma_ctrl(struct ice_hw *hw, u8 *data); +int ice_write_sma_ctrl(struct ice_hw *hw, u8 data); +int ice_read_pca9575_reg(struct ice_hw *hw, u8 offset, u8 *data); +int ice_ptp_read_sdp_ac(struct ice_hw *hw, __le16 *entries, uint *num_entries); int ice_cgu_get_num_pins(struct ice_hw *hw, bool input); enum dpll_pin_type ice_cgu_get_pin_type(struct ice_hw *hw, u8 pin, bool input); struct dpll_pin_frequency * @@ -421,8 +423,6 @@ int ice_cgu_get_output_pin_state_caps(struct ice_hw *hw, u8 pin_id, int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status); int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset); int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port); -int ice_phy_cfg_tx_offset_eth56g(struct ice_hw *hw, u8 port); -int ice_phy_cfg_rx_offset_eth56g(struct ice_hw *hw, u8 port); int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold); int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port); @@ -432,6 +432,20 @@ int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port); #define ICE_ETH56G_NOMINAL_THRESH4 0x7777 #define ICE_ETH56G_NOMINAL_TX_THRESH 0x6 +static inline u64 ice_prop_delay(const struct ice_hw *hw) +{ + switch (hw->ptp.phy_model) { + case ICE_PHY_ETH56G: + return ICE_E825C_OUT_PROP_DELAY_NS; + case ICE_PHY_E810: + return ICE_E810_OUT_PROP_DELAY_NS; + case ICE_PHY_E82X: + return ice_e82x_pps_delay(ice_e82x_time_ref(hw)); + default: + return 0; + } +} + /** * ice_get_base_incval - Get base clock increment value * @hw: pointer to the HW struct @@ -452,6 +466,11 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw) } } +static inline bool ice_is_dual(struct ice_hw *hw) +{ + return !!(hw->dev_caps.nac_topo.mode & ICE_NAC_TOPO_DUAL_M); +} + #define PFTSYN_SEM_BYTES 4 #define ICE_PTP_CLOCK_INDEX_0 0x00 @@ -663,9 +682,8 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw) #define TS_HIGH_M 0xFF #define TS_HIGH_S 32 -#define TS_PHY_LOW_M 0xFF -#define TS_PHY_HIGH_M 0xFFFFFFFF -#define TS_PHY_HIGH_S 8 +#define TS_PHY_LOW_M GENMASK(7, 0) +#define TS_PHY_HIGH_M GENMASK_ULL(39, 8) #define BYTES_PER_IDX_ADDR_L_U 8 #define BYTES_PER_IDX_ADDR_L 4 @@ -689,30 +707,27 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw) #define LOW_TX_MEMORY_BANK_START 0x03090000 #define HIGH_TX_MEMORY_BANK_START 0x03090004 -/* E810T SMA controller pin control */ -#define ICE_SMA1_DIR_EN_E810T BIT(4) -#define ICE_SMA1_TX_EN_E810T BIT(5) -#define ICE_SMA2_UFL2_RX_DIS_E810T BIT(3) -#define ICE_SMA2_DIR_EN_E810T BIT(6) -#define ICE_SMA2_TX_EN_E810T BIT(7) - -#define ICE_SMA1_MASK_E810T (ICE_SMA1_DIR_EN_E810T | \ - ICE_SMA1_TX_EN_E810T) -#define ICE_SMA2_MASK_E810T (ICE_SMA2_UFL2_RX_DIS_E810T | \ - ICE_SMA2_DIR_EN_E810T | \ - ICE_SMA2_TX_EN_E810T) -#define ICE_ALL_SMA_MASK_E810T (ICE_SMA1_MASK_E810T | \ - ICE_SMA2_MASK_E810T) - -#define ICE_SMA_MIN_BIT_E810T 3 -#define ICE_SMA_MAX_BIT_E810T 7 +/* SMA controller pin control */ +#define ICE_SMA1_DIR_EN BIT(4) +#define ICE_SMA1_TX_EN BIT(5) +#define ICE_SMA2_UFL2_RX_DIS BIT(3) +#define ICE_SMA2_DIR_EN BIT(6) +#define ICE_SMA2_TX_EN BIT(7) + +#define ICE_SMA1_MASK (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN) +#define ICE_SMA2_MASK (ICE_SMA2_UFL2_RX_DIS | ICE_SMA2_DIR_EN | \ + ICE_SMA2_TX_EN) +#define ICE_ALL_SMA_MASK (ICE_SMA1_MASK | ICE_SMA2_MASK) + +#define ICE_SMA_MIN_BIT 3 +#define ICE_SMA_MAX_BIT 7 #define ICE_PCA9575_P1_OFFSET 8 -/* E810T PCA9575 IO controller registers */ +/* PCA9575 IO controller registers */ #define ICE_PCA9575_P0_IN 0x0 -/* E810T PCA9575 IO controller pin control */ -#define ICE_E810T_P0_GNSS_PRSNT_N BIT(4) +/* PCA9575 IO controller pin control */ +#define ICE_P0_GNSS_PRSNT_N BIT(4) /* ETH56G PHY register addresses */ /* Timestamp PHY incval registers */ diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 91cb393f616f2b..b83f99c01d91b9 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -194,7 +194,8 @@ void ice_free_vfs(struct ice_pf *pf) } /* clear malicious info since the VF is getting released */ - list_del(&vf->mbx_info.list_entry); + if (!ice_is_feature_supported(pf, ICE_F_MBX_LIMIT)) + list_del(&vf->mbx_info.list_entry); mutex_unlock(&vf->cfg_lock); } diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 8208055d6e7fc5..5d2d7736fd5f12 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1352,14 +1352,14 @@ static void ice_net_dim(struct ice_q_vector *q_vector) struct dim_sample dim_sample; __ice_update_sample(q_vector, tx, &dim_sample, true); - net_dim(&tx->dim, dim_sample); + net_dim(&tx->dim, &dim_sample); } if (ITR_IS_DYNAMIC(rx)) { struct dim_sample dim_sample; __ice_update_sample(q_vector, rx, &dim_sample, false); - net_dim(&rx->dim, dim_sample); + net_dim(&rx->dim, &dim_sample); } } diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index feba314a3fe441..cb347c852ba9e8 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -359,8 +359,9 @@ struct ice_rx_ring { struct ice_rx_ring *next; /* pointer to next ring in q_vector */ struct xsk_buff_pool *xsk_pool; u32 nr_frags; - dma_addr_t dma; /* physical address of ring */ + u16 max_frame; u16 rx_buf_len; + dma_addr_t dma; /* physical address of ring */ u8 dcb_tc; /* Traffic class of ring */ u8 ptp_rx; #define ICE_RX_FLAGS_RING_BUILD_SKB BIT(1) @@ -406,6 +407,7 @@ struct ice_tx_ring { #define ICE_TX_FLAGS_RING_VLAN_L2TAG2 BIT(2) u8 flags; u8 dcb_tc; /* Traffic class of ring */ + u16 quanta_prof_id; } ____cacheline_internodealigned_in_smp; static inline bool ice_ring_uses_build_skb(struct ice_rx_ring *ring) diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h index afcead4baef4b1..79f960c6680d17 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h @@ -154,7 +154,6 @@ static inline u32 ice_set_rs_bit(const struct ice_tx_ring *xdp_ring) } void ice_finalize_xdp_rx(struct ice_tx_ring *xdp_ring, unsigned int xdp_res, u32 first_idx); -int ice_xmit_xdp_buff(struct xdp_buff *xdp, struct ice_tx_ring *xdp_ring); int __ice_xmit_xdp_ring(struct xdp_buff *xdp, struct ice_tx_ring *xdp_ring, bool frame); void ice_release_rx_desc(struct ice_rx_ring *rx_ring, u16 val); diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 45768796691fec..adb168860711c0 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -905,6 +905,7 @@ struct ice_hw { u8 revision_id; u8 pf_id; /* device profile info */ + u8 logical_pf_id; u16 max_burst_size; /* driver sets this value */ diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 8c434689e3f78e..c7c0c2f50c2652 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -716,6 +716,23 @@ ice_vf_clear_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m) return 0; } +/** + * ice_reset_vf_mbx_cnt - reset VF mailbox message count + * @vf: pointer to the VF structure + * + * This function clears the VF mailbox message count, and should be called on + * VF reset. + */ +static void ice_reset_vf_mbx_cnt(struct ice_vf *vf) +{ + struct ice_pf *pf = vf->pf; + + if (ice_is_feature_supported(pf, ICE_F_MBX_LIMIT)) + ice_mbx_vf_clear_cnt_e830(&pf->hw, vf->vf_id); + else + ice_mbx_clear_malvf(&vf->mbx_info); +} + /** * ice_reset_all_vfs - reset all allocated VFs in one go * @pf: pointer to the PF structure @@ -742,7 +759,7 @@ void ice_reset_all_vfs(struct ice_pf *pf) /* clear all malicious info if the VFs are getting reset */ ice_for_each_vf(pf, bkt, vf) - ice_mbx_clear_malvf(&vf->mbx_info); + ice_reset_vf_mbx_cnt(vf); /* If VFs have been disabled, there is no need to reset */ if (test_and_set_bit(ICE_VF_DIS, pf->state)) { @@ -958,7 +975,7 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags) ice_eswitch_update_repr(&vf->repr_id, vsi); /* if the VF has been reset allow it to come up again */ - ice_mbx_clear_malvf(&vf->mbx_info); + ice_reset_vf_mbx_cnt(vf); out_unlock: if (lag && lag->bonded && lag->primary && @@ -1011,7 +1028,10 @@ void ice_initialize_vf_entry(struct ice_vf *vf) ice_vf_fdir_init(vf); /* Initialize mailbox info for this VF */ - ice_mbx_init_vf_info(&pf->hw, &vf->mbx_info); + if (ice_is_feature_supported(pf, ICE_F_MBX_LIMIT)) + ice_mbx_vf_clear_cnt_e830(&pf->hw, vf->vf_id); + else + ice_mbx_init_vf_info(&pf->hw, &vf->mbx_info); mutex_init(&vf->cfg_lock); } diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h index be4266899690ab..4261fe1c2bcd70 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h @@ -59,6 +59,13 @@ struct ice_fdir_prof_info { u64 fdir_active_cnt; }; +struct ice_vf_qs_bw { + u32 committed; + u32 peak; + u16 queue_id; + u8 tc; +}; + /* VF operations */ struct ice_vf_ops { enum ice_disq_rst_src reset_type; @@ -140,6 +147,7 @@ struct ice_vf { struct devlink_port devlink_port; u16 num_msix; /* num of MSI-X configured on this VF */ + struct ice_vf_qs_bw qs_bw[ICE_MAX_RSS_QS_PER_VF]; }; /* Flags for controlling behavior of ice_reset_vf */ diff --git a/drivers/net/ethernet/intel/ice/ice_vf_mbx.c b/drivers/net/ethernet/intel/ice/ice_vf_mbx.c index 40cb4ba0789ced..75c8113e58ee92 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_mbx.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_mbx.c @@ -210,6 +210,38 @@ ice_mbx_detect_malvf(struct ice_hw *hw, struct ice_mbx_vf_info *vf_info, return 0; } +/** + * ice_mbx_vf_dec_trig_e830 - Decrements the VF mailbox queue counter + * @hw: pointer to the HW struct + * @event: pointer to the control queue receive event + * + * This function triggers to decrement the counter + * MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT when the driver replenishes + * the buffers at the PF mailbox queue. + */ +void ice_mbx_vf_dec_trig_e830(const struct ice_hw *hw, + const struct ice_rq_event_info *event) +{ + u16 vfid = le16_to_cpu(event->desc.retval); + + wr32(hw, E830_MBX_VF_DEC_TRIG(vfid), 1); +} + +/** + * ice_mbx_vf_clear_cnt_e830 - Clear the VF mailbox queue count + * @hw: pointer to the HW struct + * @vf_id: VF ID in the PF space + * + * This function clears the counter MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT, and should + * be called when a VF is created and on VF reset. + */ +void ice_mbx_vf_clear_cnt_e830(const struct ice_hw *hw, u16 vf_id) +{ + u32 reg = rd32(hw, E830_MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT(vf_id)); + + wr32(hw, E830_MBX_VF_DEC_TRIG(vf_id), reg); +} + /** * ice_mbx_vf_state_handler - Handle states of the overflow algorithm * @hw: pointer to the HW struct diff --git a/drivers/net/ethernet/intel/ice/ice_vf_mbx.h b/drivers/net/ethernet/intel/ice/ice_vf_mbx.h index 44bc030d17e07a..684de89e5c5ed7 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_mbx.h +++ b/drivers/net/ethernet/intel/ice/ice_vf_mbx.h @@ -19,6 +19,9 @@ ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen, struct ice_sq_cd *cd); u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed); +void ice_mbx_vf_dec_trig_e830(const struct ice_hw *hw, + const struct ice_rq_event_info *event); +void ice_mbx_vf_clear_cnt_e830(const struct ice_hw *hw, u16 vf_id); int ice_mbx_vf_state_handler(struct ice_hw *hw, struct ice_mbx_data *mbx_data, struct ice_mbx_vf_info *vf_info, bool *report_malvf); @@ -47,5 +50,11 @@ static inline void ice_mbx_init_snapshot(struct ice_hw *hw) { } +static inline void +ice_mbx_vf_dec_trig_e830(const struct ice_hw *hw, + const struct ice_rq_event_info *event) +{ +} + #endif /* CONFIG_PCI_IOV */ #endif /* _ICE_VF_MBX_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index 59f62306b9cb02..ff4ad788d96ac5 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -495,6 +495,9 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_USO) vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_USO; + if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_QOS) + vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_QOS; + vfres->num_vsis = 1; /* Tx and Rx queue are equal for VF */ vfres->num_queue_pairs = vsi->num_txq; @@ -1034,6 +1037,191 @@ static int ice_vc_config_rss_hfunc(struct ice_vf *vf, u8 *msg) NULL, 0); } +/** + * ice_vc_get_qos_caps - Get current QoS caps from PF + * @vf: pointer to the VF info + * + * Get VF's QoS capabilities, such as TC number, arbiter and + * bandwidth from PF. + * + * Return: 0 on success or negative error value. + */ +static int ice_vc_get_qos_caps(struct ice_vf *vf) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_qos_cap_list *cap_list = NULL; + u8 tc_prio[ICE_MAX_TRAFFIC_CLASS] = { 0 }; + struct virtchnl_qos_cap_elem *cfg = NULL; + struct ice_vsi_ctx *vsi_ctx; + struct ice_pf *pf = vf->pf; + struct ice_port_info *pi; + struct ice_vsi *vsi; + u8 numtc, tc; + u16 len = 0; + int ret, i; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + pi = pf->hw.port_info; + numtc = vsi->tc_cfg.numtc; + + vsi_ctx = ice_get_vsi_ctx(pi->hw, vf->lan_vsi_idx); + if (!vsi_ctx) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + len = struct_size(cap_list, cap, numtc); + cap_list = kzalloc(len, GFP_KERNEL); + if (!cap_list) { + v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; + len = 0; + goto err; + } + + cap_list->vsi_id = vsi->vsi_num; + cap_list->num_elem = numtc; + + /* Store the UP2TC configuration from DCB to a user priority bitmap + * of each TC. Each element of prio_of_tc represents one TC. Each + * bitmap indicates the user priorities belong to this TC. + */ + for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) { + tc = pi->qos_cfg.local_dcbx_cfg.etscfg.prio_table[i]; + tc_prio[tc] |= BIT(i); + } + + for (i = 0; i < numtc; i++) { + cfg = &cap_list->cap[i]; + cfg->tc_num = i; + cfg->tc_prio = tc_prio[i]; + cfg->arbiter = pi->qos_cfg.local_dcbx_cfg.etscfg.tsatable[i]; + cfg->weight = VIRTCHNL_STRICT_WEIGHT; + cfg->type = VIRTCHNL_BW_SHAPER; + cfg->shaper.committed = vsi_ctx->sched.bw_t_info[i].cir_bw.bw; + cfg->shaper.peak = vsi_ctx->sched.bw_t_info[i].eir_bw.bw; + } + +err: + ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_QOS_CAPS, v_ret, + (u8 *)cap_list, len); + kfree(cap_list); + return ret; +} + +/** + * ice_vf_cfg_qs_bw - Configure per queue bandwidth + * @vf: pointer to the VF info + * @num_queues: number of queues to be configured + * + * Configure per queue bandwidth. + * + * Return: 0 on success or negative error value. + */ +static int ice_vf_cfg_qs_bw(struct ice_vf *vf, u16 num_queues) +{ + struct ice_hw *hw = &vf->pf->hw; + struct ice_vsi *vsi; + int ret; + u16 i; + + vsi = ice_get_vf_vsi(vf); + if (!vsi) + return -EINVAL; + + for (i = 0; i < num_queues; i++) { + u32 p_rate, min_rate; + u8 tc; + + p_rate = vf->qs_bw[i].peak; + min_rate = vf->qs_bw[i].committed; + tc = vf->qs_bw[i].tc; + if (p_rate) + ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc, + vf->qs_bw[i].queue_id, + ICE_MAX_BW, p_rate); + else + ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc, + vf->qs_bw[i].queue_id, + ICE_MAX_BW); + if (ret) + return ret; + + if (min_rate) + ret = ice_cfg_q_bw_lmt(hw->port_info, vsi->idx, tc, + vf->qs_bw[i].queue_id, + ICE_MIN_BW, min_rate); + else + ret = ice_cfg_q_bw_dflt_lmt(hw->port_info, vsi->idx, tc, + vf->qs_bw[i].queue_id, + ICE_MIN_BW); + + if (ret) + return ret; + } + + return 0; +} + +/** + * ice_vf_cfg_q_quanta_profile - Configure quanta profile + * @vf: pointer to the VF info + * @quanta_prof_idx: pointer to the quanta profile index + * @quanta_size: quanta size to be set + * + * This function chooses available quanta profile and configures the register. + * The quanta profile is evenly divided by the number of device ports, and then + * available to the specific PF and VFs. The first profile for each PF is a + * reserved default profile. Only quanta size of the rest unused profile can be + * modified. + * + * Return: 0 on success or negative error value. + */ +static int ice_vf_cfg_q_quanta_profile(struct ice_vf *vf, u16 quanta_size, + u16 *quanta_prof_idx) +{ + const u16 n_desc = calc_quanta_desc(quanta_size); + struct ice_hw *hw = &vf->pf->hw; + const u16 n_cmd = 2 * n_desc; + struct ice_pf *pf = vf->pf; + u16 per_pf, begin_id; + u8 n_used; + u32 reg; + + begin_id = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / hw->dev_caps.num_funcs * + hw->logical_pf_id; + + if (quanta_size == ICE_DFLT_QUANTA) { + *quanta_prof_idx = begin_id; + } else { + per_pf = (GLCOMM_QUANTA_PROF_MAX_INDEX + 1) / + hw->dev_caps.num_funcs; + n_used = pf->num_quanta_prof_used; + if (n_used < per_pf) { + *quanta_prof_idx = begin_id + 1 + n_used; + pf->num_quanta_prof_used++; + } else { + return -EINVAL; + } + } + + reg = FIELD_PREP(GLCOMM_QUANTA_PROF_QUANTA_SIZE_M, quanta_size) | + FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_CMD_M, n_cmd) | + FIELD_PREP(GLCOMM_QUANTA_PROF_MAX_DESC_M, n_desc); + wr32(hw, GLCOMM_QUANTA_PROF(*quanta_prof_idx), reg); + + return 0; +} + /** * ice_vc_cfg_promiscuous_mode_msg * @vf: pointer to the VF info @@ -1635,6 +1823,141 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) NULL, 0); } +/** + * ice_vc_cfg_q_bw - Configure per queue bandwidth + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer which holds the command descriptor + * + * Configure VF queues bandwidth. + * + * Return: 0 on success or negative error value. + */ +static int ice_vc_cfg_q_bw(struct ice_vf *vf, u8 *msg) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + struct virtchnl_queues_bw_cfg *qbw = + (struct virtchnl_queues_bw_cfg *)msg; + struct ice_vsi *vsi; + u16 i; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states) || + !ice_vc_isvalid_vsi_id(vf, qbw->vsi_id)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (qbw->num_queues > ICE_MAX_RSS_QS_PER_VF || + qbw->num_queues > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { + dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n", + vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + for (i = 0; i < qbw->num_queues; i++) { + if (qbw->cfg[i].shaper.peak != 0 && vf->max_tx_rate != 0 && + qbw->cfg[i].shaper.peak > vf->max_tx_rate) + dev_warn(ice_pf_to_dev(vf->pf), "The maximum queue %d rate limit configuration may not take effect because the maximum TX rate for VF-%d is %d\n", + qbw->cfg[i].queue_id, vf->vf_id, + vf->max_tx_rate); + if (qbw->cfg[i].shaper.committed != 0 && vf->min_tx_rate != 0 && + qbw->cfg[i].shaper.committed < vf->min_tx_rate) + dev_warn(ice_pf_to_dev(vf->pf), "The minimum queue %d rate limit configuration may not take effect because the minimum TX rate for VF-%d is %d\n", + qbw->cfg[i].queue_id, vf->vf_id, + vf->max_tx_rate); + } + + for (i = 0; i < qbw->num_queues; i++) { + vf->qs_bw[i].queue_id = qbw->cfg[i].queue_id; + vf->qs_bw[i].peak = qbw->cfg[i].shaper.peak; + vf->qs_bw[i].committed = qbw->cfg[i].shaper.committed; + vf->qs_bw[i].tc = qbw->cfg[i].tc; + } + + if (ice_vf_cfg_qs_bw(vf, qbw->num_queues)) + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + +err: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUEUE_BW, + v_ret, NULL, 0); +} + +/** + * ice_vc_cfg_q_quanta - Configure per queue quanta + * @vf: pointer to the VF info + * @msg: pointer to the msg buffer which holds the command descriptor + * + * Configure VF queues quanta. + * + * Return: 0 on success or negative error value. + */ +static int ice_vc_cfg_q_quanta(struct ice_vf *vf, u8 *msg) +{ + enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; + u16 quanta_prof_id, quanta_size, start_qid, end_qid, i; + struct virtchnl_quanta_cfg *qquanta = + (struct virtchnl_quanta_cfg *)msg; + struct ice_vsi *vsi; + int ret; + + if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + vsi = ice_get_vf_vsi(vf); + if (!vsi) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + end_qid = qquanta->queue_select.start_queue_id + + qquanta->queue_select.num_queues; + if (end_qid > ICE_MAX_RSS_QS_PER_VF || + end_qid > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { + dev_err(ice_pf_to_dev(vf->pf), "VF-%d trying to configure more than allocated number of queues: %d\n", + vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + quanta_size = qquanta->quanta_size; + if (quanta_size > ICE_MAX_QUANTA_SIZE || + quanta_size < ICE_MIN_QUANTA_SIZE) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + if (quanta_size % 64) { + dev_err(ice_pf_to_dev(vf->pf), "quanta size should be the product of 64\n"); + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto err; + } + + ret = ice_vf_cfg_q_quanta_profile(vf, quanta_size, + &quanta_prof_id); + if (ret) { + v_ret = VIRTCHNL_STATUS_ERR_NOT_SUPPORTED; + goto err; + } + + start_qid = qquanta->queue_select.start_queue_id; + for (i = start_qid; i < end_qid; i++) + vsi->tx_rings[i]->quanta_prof_id = quanta_prof_id; + +err: + /* send the response to the VF */ + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_QUANTA, + v_ret, NULL, 0); +} + /** * ice_vc_cfg_qs_msg * @vf: pointer to the VF info @@ -1715,8 +2038,8 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) /* copy Tx queue info from VF into VSI */ if (qpi->txq.ring_len > 0) { - vsi->tx_rings[i]->dma = qpi->txq.dma_ring_addr; - vsi->tx_rings[i]->count = qpi->txq.ring_len; + vsi->tx_rings[q_idx]->dma = qpi->txq.dma_ring_addr; + vsi->tx_rings[q_idx]->count = qpi->txq.ring_len; /* Disable any existing queue first */ if (ice_vf_vsi_dis_single_txq(vf, vsi, q_idx)) @@ -1725,7 +2048,7 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) /* Configure a queue with the requested settings */ if (ice_vsi_cfg_single_txq(vsi, vsi->tx_rings, q_idx)) { dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure TX queue %d\n", - vf->vf_id, i); + vf->vf_id, q_idx); goto error_param; } } @@ -1733,39 +2056,37 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) /* copy Rx queue info from VF into VSI */ if (qpi->rxq.ring_len > 0) { u16 max_frame_size = ice_vc_get_max_frame_size(vf); + struct ice_rx_ring *ring = vsi->rx_rings[q_idx]; u32 rxdid; - vsi->rx_rings[i]->dma = qpi->rxq.dma_ring_addr; - vsi->rx_rings[i]->count = qpi->rxq.ring_len; + ring->dma = qpi->rxq.dma_ring_addr; + ring->count = qpi->rxq.ring_len; if (qpi->rxq.crc_disable) - vsi->rx_rings[q_idx]->flags |= - ICE_RX_FLAGS_CRC_STRIP_DIS; + ring->flags |= ICE_RX_FLAGS_CRC_STRIP_DIS; else - vsi->rx_rings[q_idx]->flags &= - ~ICE_RX_FLAGS_CRC_STRIP_DIS; + ring->flags &= ~ICE_RX_FLAGS_CRC_STRIP_DIS; if (qpi->rxq.databuffer_size != 0 && (qpi->rxq.databuffer_size > ((16 * 1024) - 128) || qpi->rxq.databuffer_size < 1024)) goto error_param; - vsi->rx_buf_len = qpi->rxq.databuffer_size; - vsi->rx_rings[i]->rx_buf_len = vsi->rx_buf_len; + ring->rx_buf_len = qpi->rxq.databuffer_size; if (qpi->rxq.max_pkt_size > max_frame_size || qpi->rxq.max_pkt_size < 64) goto error_param; - vsi->max_frame = qpi->rxq.max_pkt_size; + ring->max_frame = qpi->rxq.max_pkt_size; /* add space for the port VLAN since the VF driver is * not expected to account for it in the MTU * calculation */ if (ice_vf_is_port_vlan_ena(vf)) - vsi->max_frame += VLAN_HLEN; + ring->max_frame += VLAN_HLEN; if (ice_vsi_cfg_single_rxq(vsi, q_idx)) { dev_warn(ice_pf_to_dev(pf), "VF-%d failed to configure RX queue %d\n", - vf->vf_id, i); + vf->vf_id, q_idx); goto error_param; } @@ -2233,17 +2554,27 @@ static bool ice_is_vlan_promisc_allowed(struct ice_vf *vf) /** * ice_vf_ena_vlan_promisc - Enable Tx/Rx VLAN promiscuous for the VLAN + * @vf: VF to enable VLAN promisc on * @vsi: VF's VSI used to enable VLAN promiscuous mode * @vlan: VLAN used to enable VLAN promiscuous * * This function should only be called if VLAN promiscuous mode is allowed, * which can be determined via ice_is_vlan_promisc_allowed(). */ -static int ice_vf_ena_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan) +static int ice_vf_ena_vlan_promisc(struct ice_vf *vf, struct ice_vsi *vsi, + struct ice_vlan *vlan) { - u8 promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX; + u8 promisc_m = 0; int status; + if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states)) + promisc_m |= ICE_UCAST_VLAN_PROMISC_BITS; + if (test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) + promisc_m |= ICE_MCAST_VLAN_PROMISC_BITS; + + if (!promisc_m) + return 0; + status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, vlan->vid); if (status && status != -EEXIST) @@ -2262,7 +2593,7 @@ static int ice_vf_ena_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan) */ static int ice_vf_dis_vlan_promisc(struct ice_vsi *vsi, struct ice_vlan *vlan) { - u8 promisc_m = ICE_PROMISC_VLAN_TX | ICE_PROMISC_VLAN_RX; + u8 promisc_m = ICE_UCAST_VLAN_PROMISC_BITS | ICE_MCAST_VLAN_PROMISC_BITS; int status; status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, @@ -2417,7 +2748,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) goto error_param; } } else if (vlan_promisc) { - status = ice_vf_ena_vlan_promisc(vsi, &vlan); + status = ice_vf_ena_vlan_promisc(vf, vsi, &vlan); if (status) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; dev_err(dev, "Enable Unicast/multicast promiscuous mode on VLAN ID:%d failed error-%d\n", @@ -2700,12 +3031,8 @@ static int ice_vc_set_rss_hena(struct ice_vf *vf, u8 *msg) static int ice_vc_query_rxdid(struct ice_vf *vf) { enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; - struct virtchnl_supported_rxdids *rxdid = NULL; - struct ice_hw *hw = &vf->pf->hw; + struct virtchnl_supported_rxdids rxdid = {}; struct ice_pf *pf = vf->pf; - int len = 0; - int ret, i; - u32 regval; if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2717,35 +3044,11 @@ static int ice_vc_query_rxdid(struct ice_vf *vf) goto err; } - len = sizeof(struct virtchnl_supported_rxdids); - rxdid = kzalloc(len, GFP_KERNEL); - if (!rxdid) { - v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; - len = 0; - goto err; - } - - /* RXDIDs supported by DDP package can be read from the register - * to get the supported RXDID bitmap. But the legacy 32byte RXDID - * is not listed in DDP package, add it in the bitmap manually. - * Legacy 16byte descriptor is not supported. - */ - rxdid->supported_rxdids |= BIT(ICE_RXDID_LEGACY_1); - - for (i = ICE_RXDID_FLEX_NIC; i < ICE_FLEX_DESC_RXDID_MAX_NUM; i++) { - regval = rd32(hw, GLFLXP_RXDID_FLAGS(i, 0)); - if ((regval >> GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_S) - & GLFLXP_RXDID_FLAGS_FLEXIFLAG_4N_M) - rxdid->supported_rxdids |= BIT(i); - } - - pf->supported_rxdids = rxdid->supported_rxdids; + rxdid.supported_rxdids = pf->supported_rxdids; err: - ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_SUPPORTED_RXDIDS, - v_ret, (u8 *)rxdid, len); - kfree(rxdid); - return ret; + return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_SUPPORTED_RXDIDS, + v_ret, (u8 *)&rxdid, sizeof(rxdid)); } /** @@ -3254,7 +3557,7 @@ ice_vc_add_vlans(struct ice_vf *vf, struct ice_vsi *vsi, return err; if (vlan_promisc) { - err = ice_vf_ena_vlan_promisc(vsi, &vlan); + err = ice_vf_ena_vlan_promisc(vf, vsi, &vlan); if (err) return err; } @@ -3282,7 +3585,8 @@ ice_vc_add_vlans(struct ice_vf *vf, struct ice_vsi *vsi, */ if (!ice_is_dvm_ena(&vsi->back->hw)) { if (vlan_promisc) { - err = ice_vf_ena_vlan_promisc(vsi, &vlan); + err = ice_vf_ena_vlan_promisc(vf, vsi, + &vlan); if (err) return err; } @@ -3821,6 +4125,12 @@ static const struct ice_virtchnl_ops ice_virtchnl_dflt_ops = { .dis_vlan_stripping_v2_msg = ice_vc_dis_vlan_stripping_v2_msg, .ena_vlan_insertion_v2_msg = ice_vc_ena_vlan_insertion_v2_msg, .dis_vlan_insertion_v2_msg = ice_vc_dis_vlan_insertion_v2_msg, + .get_qos_caps = ice_vc_get_qos_caps, + .cfg_q_bw = ice_vc_cfg_q_bw, + .cfg_q_quanta = ice_vc_cfg_q_quanta, + /* If you add a new op here please make sure to add it to + * ice_virtchnl_repr_ops as well. + */ }; /** @@ -3951,6 +4261,9 @@ static const struct ice_virtchnl_ops ice_virtchnl_repr_ops = { .dis_vlan_stripping_v2_msg = ice_vc_dis_vlan_stripping_v2_msg, .ena_vlan_insertion_v2_msg = ice_vc_ena_vlan_insertion_v2_msg, .dis_vlan_insertion_v2_msg = ice_vc_dis_vlan_insertion_v2_msg, + .get_qos_caps = ice_vc_get_qos_caps, + .cfg_q_bw = ice_vc_cfg_q_bw, + .cfg_q_quanta = ice_vc_cfg_q_quanta, }; /** @@ -4009,8 +4322,10 @@ ice_is_malicious_vf(struct ice_vf *vf, struct ice_mbx_data *mbxdata) * @event: pointer to the AQ event * @mbxdata: information used to detect VF attempting mailbox overflow * - * called from the common asq/arq handler to - * process request from VF + * Called from the common asq/arq handler to process request from VF. When this + * flow is used for devices with hardware VF to PF message queue overflow + * support (ICE_F_MBX_LIMIT) mbxdata is set to NULL and ice_is_malicious_vf + * check is skipped. */ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event, struct ice_mbx_data *mbxdata) @@ -4036,7 +4351,7 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event, mutex_lock(&vf->cfg_lock); /* Check if the VF is trying to overflow the mailbox */ - if (ice_is_malicious_vf(vf, mbxdata)) + if (mbxdata && ice_is_malicious_vf(vf, mbxdata)) goto finish; /* Check if VF is disabled. */ @@ -4177,6 +4492,15 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event, case VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2: err = ops->dis_vlan_insertion_v2_msg(vf, msg); break; + case VIRTCHNL_OP_GET_QOS_CAPS: + err = ops->get_qos_caps(vf); + break; + case VIRTCHNL_OP_CONFIG_QUEUE_BW: + err = ops->cfg_q_bw(vf, msg); + break; + case VIRTCHNL_OP_CONFIG_QUANTA: + err = ops->cfg_q_quanta(vf, msg); + break; case VIRTCHNL_OP_UNKNOWN: default: dev_err(dev, "Unsupported opcode %d from VF %d\n", v_opcode, diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.h b/drivers/net/ethernet/intel/ice/ice_virtchnl.h index 3a411586915328..0c629aef9baf1c 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.h @@ -13,6 +13,13 @@ /* Restrict number of MAC Addr and VLAN that non-trusted VF can programmed */ #define ICE_MAX_VLAN_PER_VF 8 +#define ICE_DFLT_QUANTA 1024 +#define ICE_MAX_QUANTA_SIZE 4096 +#define ICE_MIN_QUANTA_SIZE 256 + +#define calc_quanta_desc(x) \ + max_t(u16, 12, min_t(u16, 63, (((x) + 66) / 132) * 2 + 4)) + /* MAC filters: 1 is reserved for the VF's default/perm_addr/LAA MAC, 1 for * broadcast, and 16 for additional unicast/multicast filters */ @@ -61,6 +68,10 @@ struct ice_virtchnl_ops { int (*dis_vlan_stripping_v2_msg)(struct ice_vf *vf, u8 *msg); int (*ena_vlan_insertion_v2_msg)(struct ice_vf *vf, u8 *msg); int (*dis_vlan_insertion_v2_msg)(struct ice_vf *vf, u8 *msg); + int (*get_qos_caps)(struct ice_vf *vf); + int (*cfg_q_tc_map)(struct ice_vf *vf, u8 *msg); + int (*cfg_q_bw)(struct ice_vf *vf, u8 *msg); + int (*cfg_q_quanta)(struct ice_vf *vf, u8 *msg); }; #ifdef CONFIG_PCI_IOV diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c index d796dbd2a440cd..c105a82ee1364a 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c @@ -84,6 +84,11 @@ static const u32 fdir_pf_allowlist_opcodes[] = { VIRTCHNL_OP_ADD_FDIR_FILTER, VIRTCHNL_OP_DEL_FDIR_FILTER, }; +static const u32 tc_allowlist_opcodes[] = { + VIRTCHNL_OP_GET_QOS_CAPS, VIRTCHNL_OP_CONFIG_QUEUE_BW, + VIRTCHNL_OP_CONFIG_QUANTA, +}; + struct allowlist_opcode_info { const u32 *opcodes; size_t size; @@ -104,6 +109,7 @@ static const struct allowlist_opcode_info allowlist_opcodes[] = { ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF, adv_rss_pf_allowlist_opcodes), ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_FDIR_PF, fdir_pf_allowlist_opcodes), ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_VLAN_V2, vlan_v2_allowlist_opcodes), + ALLOW_ITEM(VIRTCHNL_VF_OFFLOAD_QOS, tc_allowlist_opcodes), }; /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c index 6c913a703df647..41e4bd49402a83 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_dev.c +++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c @@ -101,6 +101,9 @@ static int idpf_intr_reg_init(struct idpf_vport *vport) intr->dyn_ctl_itridx_s = PF_GLINT_DYN_CTL_ITR_INDX_S; intr->dyn_ctl_intrvl_s = PF_GLINT_DYN_CTL_INTERVAL_S; intr->dyn_ctl_wb_on_itr_m = PF_GLINT_DYN_CTL_WB_ON_ITR_M; + intr->dyn_ctl_swint_trig_m = PF_GLINT_DYN_CTL_SWINT_TRIG_M; + intr->dyn_ctl_sw_itridx_ena_m = + PF_GLINT_DYN_CTL_SW_ITR_INDX_ENA_M; spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing, IDPF_PF_ITR_IDX_SPACING); diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c index db476b3314c8a5..f71d3182580b6a 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_main.c +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c @@ -8,7 +8,7 @@ #define DRV_SUMMARY "Intel(R) Infrastructure Data Path Function Linux Driver" MODULE_DESCRIPTION(DRV_SUMMARY); -MODULE_IMPORT_NS(LIBETH); +MODULE_IMPORT_NS("LIBETH"); MODULE_LICENSE("GPL"); /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index d4e6f0e104872d..2fa9c36e33c9c8 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -2448,6 +2448,7 @@ static void idpf_tx_splitq_map(struct idpf_tx_queue *tx_q, * rest of the packet. */ tx_buf->type = LIBETH_SQE_EMPTY; + idpf_tx_buf_compl_tag(tx_buf) = params->compl_tag; /* Adjust the DMA offset and the remaining size of the * fragment. On the first iteration of this loop, @@ -3603,21 +3604,31 @@ static void idpf_vport_intr_dis_irq_all(struct idpf_vport *vport) /** * idpf_vport_intr_buildreg_itr - Enable default interrupt generation settings * @q_vector: pointer to q_vector - * @type: itr index - * @itr: itr value */ -static u32 idpf_vport_intr_buildreg_itr(struct idpf_q_vector *q_vector, - const int type, u16 itr) +static u32 idpf_vport_intr_buildreg_itr(struct idpf_q_vector *q_vector) { - u32 itr_val; + u32 itr_val = q_vector->intr_reg.dyn_ctl_intena_m; + int type = IDPF_NO_ITR_UPDATE_IDX; + u16 itr = 0; + + if (q_vector->wb_on_itr) { + /* + * Trigger a software interrupt when exiting wb_on_itr, to make + * sure we catch any pending write backs that might have been + * missed due to interrupt state transition. + */ + itr_val |= q_vector->intr_reg.dyn_ctl_swint_trig_m | + q_vector->intr_reg.dyn_ctl_sw_itridx_ena_m; + type = IDPF_SW_ITR_UPDATE_IDX; + itr = IDPF_ITR_20K; + } itr &= IDPF_ITR_MASK; /* Don't clear PBA because that can cause lost interrupts that * came in while we were cleaning/polling */ - itr_val = q_vector->intr_reg.dyn_ctl_intena_m | - (type << q_vector->intr_reg.dyn_ctl_itridx_s) | - (itr << (q_vector->intr_reg.dyn_ctl_intrvl_s - 1)); + itr_val |= (type << q_vector->intr_reg.dyn_ctl_itridx_s) | + (itr << (q_vector->intr_reg.dyn_ctl_intrvl_s - 1)); return itr_val; } @@ -3679,7 +3690,7 @@ static void idpf_net_dim(struct idpf_q_vector *q_vector) idpf_update_dim_sample(q_vector, &dim_sample, &q_vector->tx_dim, packets, bytes); - net_dim(&q_vector->tx_dim, dim_sample); + net_dim(&q_vector->tx_dim, &dim_sample); check_rx_itr: if (!IDPF_ITR_IS_DYNAMIC(q_vector->rx_intr_mode)) @@ -3698,7 +3709,7 @@ static void idpf_net_dim(struct idpf_q_vector *q_vector) idpf_update_dim_sample(q_vector, &dim_sample, &q_vector->rx_dim, packets, bytes); - net_dim(&q_vector->rx_dim, dim_sample); + net_dim(&q_vector->rx_dim, &dim_sample); } /** @@ -3715,9 +3726,8 @@ void idpf_vport_intr_update_itr_ena_irq(struct idpf_q_vector *q_vector) /* net_dim() updates ITR out-of-band using a work item */ idpf_net_dim(q_vector); + intval = idpf_vport_intr_buildreg_itr(q_vector); q_vector->wb_on_itr = false; - intval = idpf_vport_intr_buildreg_itr(q_vector, - IDPF_NO_ITR_UPDATE_IDX, 0); writel(intval, q_vector->intr_reg.dyn_ctl); } diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h index f0537826f8403f..0f71a6f5557b91 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h @@ -354,6 +354,8 @@ struct idpf_vec_regs { * @dyn_ctl_itridx_m: Mask for ITR index * @dyn_ctl_intrvl_s: Register bit offset for ITR interval * @dyn_ctl_wb_on_itr_m: Mask for WB on ITR feature + * @dyn_ctl_sw_itridx_ena_m: Mask for SW ITR index + * @dyn_ctl_swint_trig_m: Mask for dyn_ctl SW triggered interrupt enable * @rx_itr: RX ITR register * @tx_itr: TX ITR register * @icr_ena: Interrupt cause register offset @@ -367,6 +369,8 @@ struct idpf_intr_reg { u32 dyn_ctl_itridx_m; u32 dyn_ctl_intrvl_s; u32 dyn_ctl_wb_on_itr_m; + u32 dyn_ctl_sw_itridx_ena_m; + u32 dyn_ctl_swint_trig_m; void __iomem *rx_itr; void __iomem *tx_itr; void __iomem *icr_ena; @@ -437,8 +441,9 @@ struct idpf_q_vector { cpumask_var_t affinity_mask; __cacheline_group_end_aligned(cold); }; -libeth_cacheline_set_assert(struct idpf_q_vector, 112, - 424 + 2 * sizeof(struct dim), +libeth_cacheline_set_assert(struct idpf_q_vector, 120, + 24 + sizeof(struct napi_struct) + + 2 * sizeof(struct dim), 8 + sizeof(cpumask_var_t)); struct idpf_rx_queue_stats { @@ -470,6 +475,8 @@ struct idpf_tx_queue_stats { #define IDPF_ITR_IS_DYNAMIC(itr_mode) (itr_mode) #define IDPF_ITR_TX_DEF IDPF_ITR_20K #define IDPF_ITR_RX_DEF IDPF_ITR_20K +/* Index used for 'SW ITR' update in DYN_CTL register */ +#define IDPF_SW_ITR_UPDATE_IDX 2 /* Index used for 'No ITR' update in DYN_CTL register */ #define IDPF_NO_ITR_UPDATE_IDX 3 #define IDPF_ITR_IDX_SPACING(spacing, dflt) (spacing ? spacing : dflt) diff --git a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c index aad62e270ae40e..aba828abcb1718 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c +++ b/drivers/net/ethernet/intel/idpf/idpf_vf_dev.c @@ -101,6 +101,9 @@ static int idpf_vf_intr_reg_init(struct idpf_vport *vport) intr->dyn_ctl_itridx_s = VF_INT_DYN_CTLN_ITR_INDX_S; intr->dyn_ctl_intrvl_s = VF_INT_DYN_CTLN_INTERVAL_S; intr->dyn_ctl_wb_on_itr_m = VF_INT_DYN_CTLN_WB_ON_ITR_M; + intr->dyn_ctl_swint_trig_m = VF_INT_DYN_CTLN_SWINT_TRIG_M; + intr->dyn_ctl_sw_itridx_ena_m = + VF_INT_DYN_CTLN_SW_ITR_INDX_ENA_M; spacing = IDPF_ITR_IDX_SPACING(reg_vals[vec_id].itrn_index_spacing, IDPF_VF_ITR_IDX_SPACING); diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h index 6e110f28f92260..529b7d18b66238 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.h +++ b/drivers/net/ethernet/intel/igb/e1000_mac.h @@ -63,6 +63,5 @@ enum e1000_mng_mode { #define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 -void e1000_init_function_pointers_82575(struct e1000_hw *hw); #endif diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h index 091cddf4ada80c..4f652ab713b3d4 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.h +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h @@ -7,7 +7,6 @@ s32 igb_acquire_nvm(struct e1000_hw *hw); void igb_release_nvm(struct e1000_hw *hw); s32 igb_read_mac_addr(struct e1000_hw *hw); -s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num); s32 igb_read_part_string(struct e1000_hw *hw, u8 *part_num, u32 part_num_size); s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index f1d0881687233e..288a4bb2683a92 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -637,6 +637,10 @@ static int __init igb_init_module(void) dca_register_notify(&dca_notifier); #endif ret = pci_register_driver(&igb_driver); +#ifdef CONFIG_IGB_DCA + if (ret) + dca_unregister_notify(&dca_notifier); +#endif return ret; } @@ -1204,7 +1208,7 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter, /* initialize pointer to rings */ ring = q_vector->ring; - /* intialize ITR */ + /* initialize ITR */ if (rxr_count) { /* rx or rx/tx vector */ if (!adapter->rx_itr_setting || adapter->rx_itr_setting > 3) @@ -2486,7 +2490,7 @@ static int igb_set_features(struct net_device *netdev, static int igb_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags, + u16 flags, bool *notified, struct netlink_ext_ack *extack) { /* guarantee we can provide a unique filter for the unicast address */ @@ -3906,7 +3910,7 @@ static void igb_remove(struct pci_dev *pdev) * * This function initializes the vf specific data storage and then attempts to * allocate the VFs. The reason for ordering it this way is because it is much - * mor expensive time wise to disable SR-IOV than it is to allocate and free + * more expensive time wise to disable SR-IOV than it is to allocate and free * the memory for the VFs. **/ static void igb_probe_vfs(struct igb_adapter *adapter) diff --git a/drivers/net/ethernet/intel/igbvf/igbvf.h b/drivers/net/ethernet/intel/igbvf/igbvf.h index 6ad35a00a28736..ca6e44245a7b8b 100644 --- a/drivers/net/ethernet/intel/igbvf/igbvf.h +++ b/drivers/net/ethernet/intel/igbvf/igbvf.h @@ -169,8 +169,6 @@ struct igbvf_adapter { u16 link_speed; u16 link_duplex; - spinlock_t tx_queue_lock; /* prevent concurrent tail updates */ - /* track device up/down/testing state */ unsigned long state; @@ -220,7 +218,6 @@ struct igbvf_adapter { /* OS defined structs */ struct net_device *netdev; struct pci_dev *pdev; - spinlock_t stats_lock; /* prevent concurrent stats updates */ /* structs defined in e1000_hw.h */ struct e1000_hw hw; diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 925d7286a8ee48..02044aa2181b97 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -1656,12 +1656,9 @@ static int igbvf_sw_init(struct igbvf_adapter *adapter) if (igbvf_alloc_queues(adapter)) return -ENOMEM; - spin_lock_init(&adapter->tx_queue_lock); - /* Explicitly disable IRQ since the NIC can be in any state. */ igbvf_irq_disable(adapter); - spin_lock_init(&adapter->stats_lock); spin_lock_init(&adapter->hw.mbx_lock); set_bit(__IGBVF_DOWN, &adapter->state); diff --git a/drivers/net/ethernet/intel/igc/igc_diag.c b/drivers/net/ethernet/intel/igc/igc_diag.c index cc621970c0cd36..a43d7244ee7051 100644 --- a/drivers/net/ethernet/intel/igc/igc_diag.c +++ b/drivers/net/ethernet/intel/igc/igc_diag.c @@ -173,8 +173,7 @@ bool igc_link_test(struct igc_adapter *adapter, u64 *data) *data = 0; /* add delay to give enough time for autonegotioation to finish */ - if (adapter->hw.mac.autoneg) - ssleep(5); + ssleep(5); link_up = igc_has_link(adapter); if (!link_up) { diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 5b0c6f43376797..8178386778176f 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1821,11 +1821,8 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, ethtool_link_ksettings_add_link_mode(cmd, advertising, 2500baseT_Full); /* set autoneg settings */ - if (hw->mac.autoneg == 1) { - ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); - ethtool_link_ksettings_add_link_mode(cmd, advertising, - Autoneg); - } + ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); + ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); /* Set pause flow control settings */ ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); @@ -1878,10 +1875,7 @@ static int igc_ethtool_get_link_ksettings(struct net_device *netdev, cmd->base.duplex = DUPLEX_UNKNOWN; } cmd->base.speed = speed; - if (hw->mac.autoneg) - cmd->base.autoneg = AUTONEG_ENABLE; - else - cmd->base.autoneg = AUTONEG_DISABLE; + cmd->base.autoneg = AUTONEG_ENABLE; /* MDI-X => 2; MDI =>1; Invalid =>0 */ if (hw->phy.media_type == igc_media_type_copper) @@ -1955,7 +1949,6 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev, advertised |= ADVERTISE_10_HALF; if (cmd->base.autoneg == AUTONEG_ENABLE) { - hw->mac.autoneg = 1; hw->phy.autoneg_advertised = advertised; if (adapter->fc_autoneg) hw->fc.requested_mode = igc_fc_default; diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index e1c572e0d4ef07..d9d1a1a11daf81 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -92,7 +92,6 @@ struct igc_mac_info { bool asf_firmware_present; bool arc_subsystem_valid; - bool autoneg; bool autoneg_failed; bool get_link_status; }; diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index a5c4b19d71a29f..d344e0a1cd5e2a 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -386,14 +386,6 @@ s32 igc_check_for_copper_link(struct igc_hw *hw) */ igc_check_downshift(hw); - /* If we are forcing speed/duplex, then we simply return since - * we have already determined whether we have link or not. - */ - if (!mac->autoneg) { - ret_val = -IGC_ERR_CONFIG; - goto out; - } - /* Auto-Neg is enabled. Auto Speed Detection takes care * of MAC speed/duplex configuration. So we only need to * configure Collision Distance in the MAC. @@ -468,173 +460,171 @@ s32 igc_config_fc_after_link_up(struct igc_hw *hw) goto out; } - /* Check for the case where we have copper media and auto-neg is - * enabled. In this case, we need to check and see if Auto-Neg - * has completed, and if so, how the PHY and link partner has - * flow control configured. + /* In auto-neg, we need to check and see if Auto-Neg has completed, + * and if so, how the PHY and link partner has flow control + * configured. */ - if (mac->autoneg) { - /* Read the MII Status Register and check to see if AutoNeg - * has completed. We read this twice because this reg has - * some "sticky" (latched) bits. - */ - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, - &mii_status_reg); - if (ret_val) - goto out; - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, - &mii_status_reg); - if (ret_val) - goto out; - if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { - hw_dbg("Copper PHY and Auto Neg has not completed.\n"); - goto out; - } + /* Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, + &mii_status_reg); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, + &mii_status_reg); + if (ret_val) + goto out; - /* The AutoNeg process has completed, so we now need to - * read both the Auto Negotiation Advertisement - * Register (Address 4) and the Auto_Negotiation Base - * Page Ability Register (Address 5) to determine how - * flow control was negotiated. - */ - ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, - &mii_nway_adv_reg); - if (ret_val) - goto out; - ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, - &mii_nway_lp_ability_reg); - if (ret_val) - goto out; - /* Two bits in the Auto Negotiation Advertisement Register - * (Address 4) and two bits in the Auto Negotiation Base - * Page Ability Register (Address 5) determine flow control - * for both the PHY and the link partner. The following - * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, - * 1999, describes these PAUSE resolution bits and how flow - * control is determined based upon these settings. - * NOTE: DC = Don't Care - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution - *-------|---------|-------|---------|-------------------- - * 0 | 0 | DC | DC | igc_fc_none - * 0 | 1 | 0 | DC | igc_fc_none - * 0 | 1 | 1 | 0 | igc_fc_none - * 0 | 1 | 1 | 1 | igc_fc_tx_pause - * 1 | 0 | 0 | DC | igc_fc_none - * 1 | DC | 1 | DC | igc_fc_full - * 1 | 1 | 0 | 0 | igc_fc_none - * 1 | 1 | 0 | 1 | igc_fc_rx_pause - * - * Are both PAUSE bits set to 1? If so, this implies - * Symmetric Flow Control is enabled at both ends. The - * ASM_DIR bits are irrelevant per the spec. - * - * For Symmetric Flow Control: - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 1 | DC | 1 | DC | IGC_fc_full - * - */ - if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { - /* Now we need to check if the user selected RX ONLY - * of pause frames. In this case, we had to advertise - * FULL flow control because we could not advertise RX - * ONLY. Hence, we must now check to see if we need to - * turn OFF the TRANSMISSION of PAUSE frames. - */ - if (hw->fc.requested_mode == igc_fc_full) { - hw->fc.current_mode = igc_fc_full; - hw_dbg("Flow Control = FULL.\n"); - } else { - hw->fc.current_mode = igc_fc_rx_pause; - hw_dbg("Flow Control = RX PAUSE frames only.\n"); - } - } + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { + hw_dbg("Copper PHY and Auto Neg has not completed.\n"); + goto out; + } - /* For receiving PAUSE frames ONLY. - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 0 | 1 | 1 | 1 | igc_fc_tx_pause - */ - else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.current_mode = igc_fc_tx_pause; - hw_dbg("Flow Control = TX PAUSE frames only.\n"); - } - /* For transmitting PAUSE frames ONLY. - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 1 | 1 | 0 | 1 | igc_fc_rx_pause - */ - else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.current_mode = igc_fc_rx_pause; - hw_dbg("Flow Control = RX PAUSE frames only.\n"); - } - /* Per the IEEE spec, at this point flow control should be - * disabled. However, we want to consider that we could - * be connected to a legacy switch that doesn't advertise - * desired flow control, but can be forced on the link - * partner. So if we advertised no flow control, that is - * what we will resolve to. If we advertised some kind of - * receive capability (Rx Pause Only or Full Flow Control) - * and the link partner advertised none, we will configure - * ourselves to enable Rx Flow Control only. We can do - * this safely for two reasons: If the link partner really - * didn't want flow control enabled, and we enable Rx, no - * harm done since we won't be receiving any PAUSE frames - * anyway. If the intent on the link partner was to have - * flow control enabled, then by us enabling RX only, we - * can at least receive pause frames and process them. - * This is a good idea because in most cases, since we are - * predominantly a server NIC, more times than not we will - * be asked to delay transmission of packets than asking - * our link partner to pause transmission of frames. + /* The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement + * Register (Address 4) and the Auto_Negotiation Base + * Page Ability Register (Address 5) to determine how + * flow control was negotiated. + */ + ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, + &mii_nway_adv_reg); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, + &mii_nway_lp_ability_reg); + if (ret_val) + goto out; + /* Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | igc_fc_none + * 0 | 1 | 0 | DC | igc_fc_none + * 0 | 1 | 1 | 0 | igc_fc_none + * 0 | 1 | 1 | 1 | igc_fc_tx_pause + * 1 | 0 | 0 | DC | igc_fc_none + * 1 | DC | 1 | DC | igc_fc_full + * 1 | 1 | 0 | 0 | igc_fc_none + * 1 | 1 | 0 | 1 | igc_fc_rx_pause + * + * Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | IGC_fc_full + * + */ + if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. */ - else if ((hw->fc.requested_mode == igc_fc_none) || - (hw->fc.requested_mode == igc_fc_tx_pause) || - (hw->fc.strict_ieee)) { - hw->fc.current_mode = igc_fc_none; - hw_dbg("Flow Control = NONE.\n"); + if (hw->fc.requested_mode == igc_fc_full) { + hw->fc.current_mode = igc_fc_full; + hw_dbg("Flow Control = FULL.\n"); } else { hw->fc.current_mode = igc_fc_rx_pause; hw_dbg("Flow Control = RX PAUSE frames only.\n"); } + } - /* Now we need to do one last check... If we auto- - * negotiated to HALF DUPLEX, flow control should not be - * enabled per IEEE 802.3 spec. - */ - ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); - if (ret_val) { - hw_dbg("Error getting link speed and duplex\n"); - goto out; - } + /* For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | igc_fc_tx_pause + */ + else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + hw->fc.current_mode = igc_fc_tx_pause; + hw_dbg("Flow Control = TX PAUSE frames only.\n"); + } + /* For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | igc_fc_rx_pause + */ + else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + hw->fc.current_mode = igc_fc_rx_pause; + hw_dbg("Flow Control = RX PAUSE frames only.\n"); + } + /* Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if ((hw->fc.requested_mode == igc_fc_none) || + (hw->fc.requested_mode == igc_fc_tx_pause) || + (hw->fc.strict_ieee)) { + hw->fc.current_mode = igc_fc_none; + hw_dbg("Flow Control = NONE.\n"); + } else { + hw->fc.current_mode = igc_fc_rx_pause; + hw_dbg("Flow Control = RX PAUSE frames only.\n"); + } - if (duplex == HALF_DUPLEX) - hw->fc.current_mode = igc_fc_none; + /* Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) { + hw_dbg("Error getting link speed and duplex\n"); + goto out; + } - /* Now we call a subroutine to actually force the MAC - * controller to use the correct flow control settings. - */ - ret_val = igc_force_mac_fc(hw); - if (ret_val) { - hw_dbg("Error forcing flow control settings\n"); - goto out; - } + if (duplex == HALF_DUPLEX) + hw->fc.current_mode = igc_fc_none; + + /* Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + ret_val = igc_force_mac_fc(hw); + if (ret_val) { + hw_dbg("Error forcing flow control settings\n"); + goto out; } out: diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 6e70bca15db1d8..27872bdea9bd1f 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -7108,7 +7108,6 @@ static int igc_probe(struct pci_dev *pdev, /* Initialize link properties that are user-changeable */ adapter->fc_autoneg = true; - hw->mac.autoneg = true; hw->phy.autoneg_advertised = 0xaf; hw->fc.requested_mode = igc_fc_default; diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c index 2801e5f24df902..6c4d204aecfaed 100644 --- a/drivers/net/ethernet/intel/igc/igc_phy.c +++ b/drivers/net/ethernet/intel/igc/igc_phy.c @@ -494,24 +494,12 @@ s32 igc_setup_copper_link(struct igc_hw *hw) s32 ret_val = 0; bool link; - if (hw->mac.autoneg) { - /* Setup autoneg and flow control advertisement and perform - * autonegotiation. - */ - ret_val = igc_copper_link_autoneg(hw); - if (ret_val) - goto out; - } else { - /* PHY will be set to 10H, 10F, 100H or 100F - * depending on user settings. - */ - hw_dbg("Forcing Speed and Duplex\n"); - ret_val = hw->phy.ops.force_speed_duplex(hw); - if (ret_val) { - hw_dbg("Error Forcing Speed and Duplex\n"); - goto out; - } - } + /* Setup autoneg and flow control advertisement and perform + * autonegotiation. + */ + ret_val = igc_copper_link_autoneg(hw); + if (ret_val) + goto out; /* Check link status. Wait up to 100 microseconds for link to become * valid. diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 283a23150a4d44..4aaaea3b5f8ff8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -6,6 +6,7 @@ #include #include "ixgbe.h" +#include "ixgbe_mbx.h" #include "ixgbe_phy.h" #define IXGBE_82598_MAX_TX_QUEUES 32 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h index 6493abf189de5e..6639069ad52834 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h @@ -194,6 +194,8 @@ u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg); dev_err(&adapter->pdev->dev, format, ## arg) #define e_dev_notice(format, arg...) \ dev_notice(&adapter->pdev->dev, format, ## arg) +#define e_dbg(msglvl, format, arg...) \ + netif_dbg(adapter, msglvl, adapter->netdev, format, ## arg) #define e_info(msglvl, format, arg...) \ netif_info(adapter, msglvl, adapter->netdev, format, ## arg) #define e_err(msglvl, format, arg...) \ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 8b8404d8c94606..2e38e8f6fac18d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -43,6 +43,7 @@ #include "ixgbe.h" #include "ixgbe_common.h" #include "ixgbe_dcb_82599.h" +#include "ixgbe_mbx.h" #include "ixgbe_phy.h" #include "ixgbe_sriov.h" #include "ixgbe_model.h" @@ -9954,7 +9955,7 @@ static int ixgbe_set_features(struct net_device *netdev, static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags, + u16 flags, bool *notified, struct netlink_ext_ack *extack) { /* guarantee we can provide a unique filter for the unicast address */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h index bd205306934b8f..bf65e82b4c611e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h @@ -4,7 +4,7 @@ #ifndef _IXGBE_MBX_H_ #define _IXGBE_MBX_H_ -#include "ixgbe_type.h" +#include #define IXGBE_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */ @@ -96,6 +96,8 @@ enum ixgbe_pfvf_api_rev { #define IXGBE_VF_MBX_INIT_TIMEOUT 2000 /* number of retries on mailbox */ #define IXGBE_VF_MBX_INIT_DELAY 500 /* microseconds between retries */ +struct ixgbe_hw; + int ixgbe_read_mbx(struct ixgbe_hw *, u32 *, u16, u16); int ixgbe_write_mbx(struct ixgbe_hw *, u32 *, u16, u16); int ixgbe_check_for_msg(struct ixgbe_hw *, u16); @@ -105,6 +107,18 @@ int ixgbe_check_for_rst(struct ixgbe_hw *, u16); void ixgbe_init_mbx_params_pf(struct ixgbe_hw *); #endif /* CONFIG_PCI_IOV */ +struct ixgbe_mbx_operations { + int (*init_params)(struct ixgbe_hw *hw); + int (*read)(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 vf_number); + int (*write)(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 vf_number); + int (*read_posted)(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id); + int (*write_posted)(struct ixgbe_hw *hw, u32 *msg, u16 size, + u16 mbx_id); + int (*check_for_msg)(struct ixgbe_hw *hw, u16 vf_number); + int (*check_for_ack)(struct ixgbe_hw *hw, u16 vf_number); + int (*check_for_rst)(struct ixgbe_hw *hw, u16 vf_number); +}; + extern const struct ixgbe_mbx_operations mbx_ops_generic; #endif /* _IXGBE_MBX_H_ */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h index 14aa2ca51f70ec..81179c60af4e01 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h @@ -40,7 +40,7 @@ #define IXGBE_SFF_1GBASESX_CAPABLE 0x1 #define IXGBE_SFF_1GBASELX_CAPABLE 0x2 #define IXGBE_SFF_1GBASET_CAPABLE 0x8 -#define IXGBE_SFF_BASEBX10_CAPABLE 0x64 +#define IXGBE_SFF_BASEBX10_CAPABLE 0x40 #define IXGBE_SFF_10GBASESR_CAPABLE 0x10 #define IXGBE_SFF_10GBASELR_CAPABLE 0x20 #define IXGBE_SFF_SOFT_RS_SELECT_MASK 0x8 diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index e71715f5da2287..ccdce80edd1422 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -18,6 +18,7 @@ #include "ixgbe.h" #include "ixgbe_type.h" +#include "ixgbe_mbx.h" #include "ixgbe_sriov.h" #ifdef CONFIG_PCI_IOV @@ -1047,7 +1048,7 @@ static int ixgbe_negotiate_vf_api(struct ixgbe_adapter *adapter, break; } - e_info(drv, "VF %d requested invalid api version %u\n", vf, api); + e_dbg(drv, "VF %d requested unsupported api version %u\n", vf, api); return -1; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 346e3d9114a837..9baccacd02a1e5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3601,19 +3601,6 @@ struct ixgbe_phy_info { u32 nw_mng_if_sel; }; -#include "ixgbe_mbx.h" - -struct ixgbe_mbx_operations { - int (*init_params)(struct ixgbe_hw *hw); - int (*read)(struct ixgbe_hw *, u32 *, u16, u16); - int (*write)(struct ixgbe_hw *, u32 *, u16, u16); - int (*read_posted)(struct ixgbe_hw *, u32 *, u16, u16); - int (*write_posted)(struct ixgbe_hw *, u32 *, u16, u16); - int (*check_for_msg)(struct ixgbe_hw *, u16); - int (*check_for_ack)(struct ixgbe_hw *, u16); - int (*check_for_rst)(struct ixgbe_hw *, u16); -}; - struct ixgbe_mbx_stats { u32 msgs_tx; u32 msgs_rx; @@ -3623,6 +3610,8 @@ struct ixgbe_mbx_stats { u32 rsts; }; +struct ixgbe_mbx_operations; + struct ixgbe_mbx_info { const struct ixgbe_mbx_operations *ops; struct ixgbe_mbx_stats stats; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index f1ffa398f6df42..81e1df83f13697 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -6,6 +6,7 @@ #include #include "ixgbe.h" +#include "ixgbe_mbx.h" #include "ixgbe_phy.h" #include "ixgbe_x540.h" diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index a5f6449344450c..d9a8cf018d3bb2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -4,6 +4,7 @@ #include "ixgbe_x540.h" #include "ixgbe_type.h" #include "ixgbe_common.h" +#include "ixgbe_mbx.h" #include "ixgbe_phy.h" static int ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *, ixgbe_link_speed); diff --git a/drivers/net/ethernet/intel/ixgbevf/ipsec.c b/drivers/net/ethernet/intel/ixgbevf/ipsec.c index 66cf17f1940820..f804b35d79c726 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ipsec.c +++ b/drivers/net/ethernet/intel/ixgbevf/ipsec.c @@ -629,7 +629,6 @@ void ixgbevf_init_ipsec_offload(struct ixgbevf_adapter *adapter) switch (adapter->hw.api_version) { case ixgbe_mbox_api_14: - case ixgbe_mbox_api_15: break; default: return; diff --git a/drivers/net/ethernet/intel/libeth/rx.c b/drivers/net/ethernet/intel/libeth/rx.c index f209266693185b..66d1d23b8ad240 100644 --- a/drivers/net/ethernet/intel/libeth/rx.c +++ b/drivers/net/ethernet/intel/libeth/rx.c @@ -186,7 +186,7 @@ int libeth_rx_fq_create(struct libeth_fq *fq, struct napi_struct *napi) return -ENOMEM; } -EXPORT_SYMBOL_NS_GPL(libeth_rx_fq_create, LIBETH); +EXPORT_SYMBOL_NS_GPL(libeth_rx_fq_create, "LIBETH"); /** * libeth_rx_fq_destroy - destroy a &page_pool created by libeth @@ -197,7 +197,7 @@ void libeth_rx_fq_destroy(struct libeth_fq *fq) kvfree(fq->fqes); page_pool_destroy(fq->pp); } -EXPORT_SYMBOL_NS_GPL(libeth_rx_fq_destroy, LIBETH); +EXPORT_SYMBOL_NS_GPL(libeth_rx_fq_destroy, "LIBETH"); /** * libeth_rx_recycle_slow - recycle a libeth page from the NAPI context @@ -209,7 +209,7 @@ void libeth_rx_recycle_slow(struct page *page) { page_pool_recycle_direct(page->pp, page); } -EXPORT_SYMBOL_NS_GPL(libeth_rx_recycle_slow, LIBETH); +EXPORT_SYMBOL_NS_GPL(libeth_rx_recycle_slow, "LIBETH"); /* Converting abstract packet type numbers into a software structure with * the packet parameters to do O(1) lookup on Rx. @@ -251,7 +251,7 @@ void libeth_rx_pt_gen_hash_type(struct libeth_rx_pt *pt) pt->hash_type |= libeth_rx_pt_xdp_iprot[pt->inner_prot]; pt->hash_type |= libeth_rx_pt_xdp_pl[pt->payload_layer]; } -EXPORT_SYMBOL_NS_GPL(libeth_rx_pt_gen_hash_type, LIBETH); +EXPORT_SYMBOL_NS_GPL(libeth_rx_pt_gen_hash_type, "LIBETH"); /* Module */ diff --git a/drivers/net/ethernet/intel/libie/rx.c b/drivers/net/ethernet/intel/libie/rx.c index aceb8d8813c4cb..66a9825fe11f74 100644 --- a/drivers/net/ethernet/intel/libie/rx.c +++ b/drivers/net/ethernet/intel/libie/rx.c @@ -116,8 +116,8 @@ const struct libeth_rx_pt libie_rx_pt_lut[LIBIE_RX_PT_NUM] = { LIBIE_RX_PT_IP(4), LIBIE_RX_PT_IP(6), }; -EXPORT_SYMBOL_NS_GPL(libie_rx_pt_lut, LIBIE); +EXPORT_SYMBOL_NS_GPL(libie_rx_pt_lut, "LIBIE"); MODULE_DESCRIPTION("Intel(R) Ethernet common library"); -MODULE_IMPORT_NS(LIBETH); +MODULE_IMPORT_NS("LIBETH"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c index 81cf3361a1e52b..87c7e6251a4f8d 100644 --- a/drivers/net/ethernet/korina.c +++ b/drivers/net/ethernet/korina.c @@ -1403,7 +1403,7 @@ static struct platform_driver korina_driver = { .of_match_table = of_match_ptr(korina_match), }, .probe = korina_probe, - .remove_new = korina_remove, + .remove = korina_remove, }; module_platform_driver(korina_driver); diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 7179271f63b655..660dff5426e7f0 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -734,7 +734,7 @@ static void ltq_etop_remove(struct platform_device *pdev) } static struct platform_driver ltq_mii_driver = { - .remove_new = ltq_etop_remove, + .remove = ltq_etop_remove, .driver = { .name = "ltq_etop", }, diff --git a/drivers/net/ethernet/lantiq_xrx200.c b/drivers/net/ethernet/lantiq_xrx200.c index 07904a528f2151..b8766fb7a8444b 100644 --- a/drivers/net/ethernet/lantiq_xrx200.c +++ b/drivers/net/ethernet/lantiq_xrx200.c @@ -669,7 +669,7 @@ MODULE_DEVICE_TABLE(of, xrx200_match); static struct platform_driver xrx200_driver = { .probe = xrx200_probe, - .remove_new = xrx200_remove, + .remove = xrx200_remove, .driver = { .name = "lantiq,xrx200-net", .of_match_table = xrx200_match, diff --git a/drivers/net/ethernet/litex/litex_liteeth.c b/drivers/net/ethernet/litex/litex_liteeth.c index ff54fbe41bccc8..829a4b828f8e22 100644 --- a/drivers/net/ethernet/litex/litex_liteeth.c +++ b/drivers/net/ethernet/litex/litex_liteeth.c @@ -309,7 +309,7 @@ MODULE_DEVICE_TABLE(of, liteeth_of_match); static struct platform_driver liteeth_driver = { .probe = liteeth_probe, - .remove_new = liteeth_remove, + .remove = liteeth_remove, .driver = { .name = DRV_NAME, .of_match_table = liteeth_of_match, diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 9e80899546d996..a06048719e8443 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -1698,13 +1698,9 @@ static void mv643xx_eth_get_strings(struct net_device *dev, { int i; - if (stringset == ETH_SS_STATS) { - for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) { - memcpy(data + i * ETH_GSTRING_LEN, - mv643xx_eth_stats[i].stat_string, - ETH_GSTRING_LEN); - } - } + if (stringset == ETH_SS_STATS) + for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) + ethtool_puts(&data, mv643xx_eth_stats[i].stat_string); } static void mv643xx_eth_get_ethtool_stats(struct net_device *dev, @@ -2843,29 +2839,24 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) struct mv643xx_eth_shared_platform_data *pd; struct mv643xx_eth_shared_private *msp; const struct mbus_dram_target_info *dram; - struct resource *res; int ret; if (!mv643xx_eth_version_printed++) pr_notice("MV-643xx 10/100/1000 ethernet driver version %s\n", mv643xx_eth_driver_version); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) - return -EINVAL; - msp = devm_kzalloc(&pdev->dev, sizeof(*msp), GFP_KERNEL); if (msp == NULL) return -ENOMEM; platform_set_drvdata(pdev, msp); - msp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (msp->base == NULL) - return -ENOMEM; + msp->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(msp->base)) + return PTR_ERR(msp->base); - msp->clk = devm_clk_get(&pdev->dev, NULL); - if (!IS_ERR(msp->clk)) - clk_prepare_enable(msp->clk); + msp->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); + if (IS_ERR(msp->clk)) + return PTR_ERR(msp->clk); /* * (Re-)program MBUS remapping windows if we are asked to. @@ -2876,7 +2867,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) ret = mv643xx_eth_shared_of_probe(pdev); if (ret) - goto err_put_clk; + return ret; pd = dev_get_platdata(&pdev->dev); msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ? @@ -2884,25 +2875,16 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) infer_hw_params(msp); return 0; - -err_put_clk: - if (!IS_ERR(msp->clk)) - clk_disable_unprepare(msp->clk); - return ret; } static void mv643xx_eth_shared_remove(struct platform_device *pdev) { - struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev); - mv643xx_eth_shared_of_remove(); - if (!IS_ERR(msp->clk)) - clk_disable_unprepare(msp->clk); } static struct platform_driver mv643xx_eth_shared_driver = { .probe = mv643xx_eth_shared_probe, - .remove_new = mv643xx_eth_shared_remove, + .remove = mv643xx_eth_shared_remove, .driver = { .name = MV643XX_ETH_SHARED_NAME, .of_match_table = of_match_ptr(mv643xx_eth_shared_ids), @@ -3307,7 +3289,7 @@ static void mv643xx_eth_shutdown(struct platform_device *pdev) static struct platform_driver mv643xx_eth_driver = { .probe = mv643xx_eth_probe, - .remove_new = mv643xx_eth_remove, + .remove = mv643xx_eth_remove, .shutdown = mv643xx_eth_shutdown, .driver = { .name = MV643XX_ETH_NAME, diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index e1d003fdbc2ed2..3f4447e6888824 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -348,13 +348,12 @@ static int orion_mdio_probe(struct platform_device *pdev) if (type == BUS_TYPE_XSMI) orion_mdio_xsmi_set_mdc_freq(bus); } else { - dev->clk[0] = clk_get(&pdev->dev, NULL); - if (PTR_ERR(dev->clk[0]) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + dev->clk[0] = clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(dev->clk[0])) { + ret = PTR_ERR(dev->clk[0]); goto out_clk; } - if (!IS_ERR(dev->clk[0])) - clk_prepare_enable(dev->clk[0]); + clk_prepare_enable(dev->clk[0]); } @@ -422,8 +421,6 @@ static void orion_mdio_remove(struct platform_device *pdev) mdiobus_unregister(bus); for (i = 0; i < ARRAY_SIZE(dev->clk); i++) { - if (IS_ERR(dev->clk[i])) - break; clk_disable_unprepare(dev->clk[i]); clk_put(dev->clk[i]); } @@ -447,7 +444,7 @@ MODULE_DEVICE_TABLE(acpi, orion_mdio_acpi_match); static struct platform_driver orion_mdio_driver = { .probe = orion_mdio_probe, - .remove_new = orion_mdio_remove, + .remove = orion_mdio_remove, .driver = { .name = "orion-mdio", .of_match_table = orion_mdio_match, diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index d72b2d5f96db87..1fb285fa0bdb7d 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -4795,11 +4795,9 @@ static void mvneta_ethtool_get_strings(struct net_device *netdev, u32 sset, int i; for (i = 0; i < ARRAY_SIZE(mvneta_statistics); i++) - memcpy(data + i * ETH_GSTRING_LEN, - mvneta_statistics[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, mvneta_statistics[i].name); if (!pp->bm_priv) { - data += ETH_GSTRING_LEN * ARRAY_SIZE(mvneta_statistics); page_pool_ethtool_stats_get_strings(data); } } @@ -5883,7 +5881,7 @@ MODULE_DEVICE_TABLE(of, mvneta_match); static struct platform_driver mvneta_driver = { .probe = mvneta_probe, - .remove_new = mvneta_remove, + .remove = mvneta_remove, .driver = { .name = MVNETA_DRIVER_NAME, .of_match_table = mvneta_match, diff --git a/drivers/net/ethernet/marvell/mvneta_bm.c b/drivers/net/ethernet/marvell/mvneta_bm.c index 3f46a0fed04867..6bb38049491906 100644 --- a/drivers/net/ethernet/marvell/mvneta_bm.c +++ b/drivers/net/ethernet/marvell/mvneta_bm.c @@ -485,7 +485,7 @@ MODULE_DEVICE_TABLE(of, mvneta_bm_match); static struct platform_driver mvneta_bm_driver = { .probe = mvneta_bm_probe, - .remove_new = mvneta_bm_remove, + .remove = mvneta_bm_remove, .driver = { .name = MVNETA_BM_DRIVER_NAME, .of_match_table = mvneta_bm_match, diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 3880dcc0418b2d..571631a3032024 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -1985,45 +1985,32 @@ static void mvpp2_ethtool_get_strings(struct net_device *netdev, u32 sset, u8 *data) { struct mvpp2_port *port = netdev_priv(netdev); + const char *str; int i, q; if (sset != ETH_SS_STATS) return; - for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_mib_regs); i++) { - strscpy(data, mvpp2_ethtool_mib_regs[i].string, - ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_mib_regs); i++) + ethtool_puts(&data, mvpp2_ethtool_mib_regs[i].string); - for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_port_regs); i++) { - strscpy(data, mvpp2_ethtool_port_regs[i].string, - ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_port_regs); i++) + ethtool_puts(&data, mvpp2_ethtool_port_regs[i].string); - for (q = 0; q < port->ntxqs; q++) { + for (q = 0; q < port->ntxqs; q++) for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_txq_regs); i++) { - snprintf(data, ETH_GSTRING_LEN, - mvpp2_ethtool_txq_regs[i].string, q); - data += ETH_GSTRING_LEN; + str = mvpp2_ethtool_txq_regs[i].string; + ethtool_sprintf(&data, str, q); } - } - for (q = 0; q < port->nrxqs; q++) { + for (q = 0; q < port->nrxqs; q++) for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_rxq_regs); i++) { - snprintf(data, ETH_GSTRING_LEN, - mvpp2_ethtool_rxq_regs[i].string, - q); - data += ETH_GSTRING_LEN; + str = mvpp2_ethtool_rxq_regs[i].string; + ethtool_sprintf(&data, str, q); } - } - for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_xdp); i++) { - strscpy(data, mvpp2_ethtool_xdp[i].string, - ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_xdp); i++) + ethtool_puts(&data, mvpp2_ethtool_xdp[i].string); } static void @@ -7774,7 +7761,7 @@ MODULE_DEVICE_TABLE(acpi, mvpp2_acpi_match); static struct platform_driver mvpp2_driver = { .probe = mvpp2_probe, - .remove_new = mvpp2_remove, + .remove = mvpp2_remove, .driver = { .name = MVPP2_DRIVER_NAME, .of_match_table = mvpp2_match, diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c index 7d0124b283dace..4f4d5818911885 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ethtool.c @@ -47,7 +47,7 @@ static const char octep_gstrings_global_stats[][ETH_GSTRING_LEN] = { "rx_err_pkts", }; -#define OCTEP_GLOBAL_STATS_CNT (sizeof(octep_gstrings_global_stats) / ETH_GSTRING_LEN) +#define OCTEP_GLOBAL_STATS_CNT ARRAY_SIZE(octep_gstrings_global_stats) static const char octep_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = { "tx_packets_posted[Q-%u]", @@ -56,7 +56,7 @@ static const char octep_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = { "tx_busy[Q-%u]", }; -#define OCTEP_TX_Q_STATS_CNT (sizeof(octep_gstrings_tx_q_stats) / ETH_GSTRING_LEN) +#define OCTEP_TX_Q_STATS_CNT ARRAY_SIZE(octep_gstrings_tx_q_stats) static const char octep_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = { "rx_packets[Q-%u]", @@ -64,7 +64,7 @@ static const char octep_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = { "rx_alloc_errors[Q-%u]", }; -#define OCTEP_RX_Q_STATS_CNT (sizeof(octep_gstrings_rx_q_stats) / ETH_GSTRING_LEN) +#define OCTEP_RX_Q_STATS_CNT ARRAY_SIZE(octep_gstrings_rx_q_stats) static void octep_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) @@ -80,32 +80,25 @@ static void octep_get_strings(struct net_device *netdev, { struct octep_device *oct = netdev_priv(netdev); u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); - char *strings = (char *)data; + const char *str; int i, j; switch (stringset) { case ETH_SS_STATS: - for (i = 0; i < OCTEP_GLOBAL_STATS_CNT; i++) { - snprintf(strings, ETH_GSTRING_LEN, - octep_gstrings_global_stats[i]); - strings += ETH_GSTRING_LEN; - } + for (i = 0; i < OCTEP_GLOBAL_STATS_CNT; i++) + ethtool_puts(&data, octep_gstrings_global_stats[i]); - for (i = 0; i < num_queues; i++) { + for (i = 0; i < num_queues; i++) for (j = 0; j < OCTEP_TX_Q_STATS_CNT; j++) { - snprintf(strings, ETH_GSTRING_LEN, - octep_gstrings_tx_q_stats[j], i); - strings += ETH_GSTRING_LEN; + str = octep_gstrings_tx_q_stats[j]; + ethtool_sprintf(&data, str, i); } - } - for (i = 0; i < num_queues; i++) { + for (i = 0; i < num_queues; i++) for (j = 0; j < OCTEP_RX_Q_STATS_CNT; j++) { - snprintf(strings, ETH_GSTRING_LEN, - octep_gstrings_rx_q_stats[j], i); - strings += ETH_GSTRING_LEN; + str = octep_gstrings_rx_q_stats[j]; + ethtool_sprintf(&data, str, i); } - } break; default: break; diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c index a1979b45e355c6..7b21439a315f2b 100644 --- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c +++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_ethtool.c @@ -25,7 +25,7 @@ static const char octep_vf_gstrings_global_stats[][ETH_GSTRING_LEN] = { "rx_dropped_bytes_fifo_full", }; -#define OCTEP_VF_GLOBAL_STATS_CNT (sizeof(octep_vf_gstrings_global_stats) / ETH_GSTRING_LEN) +#define OCTEP_VF_GLOBAL_STATS_CNT ARRAY_SIZE(octep_vf_gstrings_global_stats) static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = { "tx_packets_posted[Q-%u]", @@ -34,7 +34,7 @@ static const char octep_vf_gstrings_tx_q_stats[][ETH_GSTRING_LEN] = { "tx_busy[Q-%u]", }; -#define OCTEP_VF_TX_Q_STATS_CNT (sizeof(octep_vf_gstrings_tx_q_stats) / ETH_GSTRING_LEN) +#define OCTEP_VF_TX_Q_STATS_CNT ARRAY_SIZE(octep_vf_gstrings_tx_q_stats) static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = { "rx_packets[Q-%u]", @@ -42,7 +42,7 @@ static const char octep_vf_gstrings_rx_q_stats[][ETH_GSTRING_LEN] = { "rx_alloc_errors[Q-%u]", }; -#define OCTEP_VF_RX_Q_STATS_CNT (sizeof(octep_vf_gstrings_rx_q_stats) / ETH_GSTRING_LEN) +#define OCTEP_VF_RX_Q_STATS_CNT ARRAY_SIZE(octep_vf_gstrings_rx_q_stats) static void octep_vf_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) @@ -58,32 +58,25 @@ static void octep_vf_get_strings(struct net_device *netdev, { struct octep_vf_device *oct = netdev_priv(netdev); u16 num_queues = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); - char *strings = (char *)data; + const char *str; int i, j; switch (stringset) { case ETH_SS_STATS: - for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++) { - snprintf(strings, ETH_GSTRING_LEN, - octep_vf_gstrings_global_stats[i]); - strings += ETH_GSTRING_LEN; - } + for (i = 0; i < OCTEP_VF_GLOBAL_STATS_CNT; i++) + ethtool_puts(&data, octep_vf_gstrings_global_stats[i]); - for (i = 0; i < num_queues; i++) { + for (i = 0; i < num_queues; i++) for (j = 0; j < OCTEP_VF_TX_Q_STATS_CNT; j++) { - snprintf(strings, ETH_GSTRING_LEN, - octep_vf_gstrings_tx_q_stats[j], i); - strings += ETH_GSTRING_LEN; + str = octep_vf_gstrings_tx_q_stats[j]; + ethtool_sprintf(&data, str, i); } - } - for (i = 0; i < num_queues; i++) { + for (i = 0; i < num_queues; i++) for (j = 0; j < OCTEP_VF_RX_Q_STATS_CNT; j++) { - snprintf(strings, ETH_GSTRING_LEN, - octep_vf_gstrings_rx_q_stats[j], i); - strings += ETH_GSTRING_LEN; + str = octep_vf_gstrings_rx_q_stats[j]; + ethtool_sprintf(&data, str, i); } - } break; default: break; diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig index a32d85d6f599f2..35c4f5f64f58ce 100644 --- a/drivers/net/ethernet/marvell/octeontx2/Kconfig +++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig @@ -46,3 +46,11 @@ config OCTEONTX2_VF depends on OCTEONTX2_PF help This driver supports Marvell's OcteonTX2 NIC virtual function. + +config RVU_ESWITCH + tristate "Marvell RVU E-Switch support" + depends on OCTEONTX2_PF + default m + help + This driver supports Marvell's RVU E-Switch that + provides internal SRIOV packet steering and switching. diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile index 3cf4c8285c9072..ccea37847df8f3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -11,4 +11,5 @@ rvu_mbox-y := mbox.o rvu_trace.o rvu_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \ rvu_reg.o rvu_npc.o rvu_debugfs.o ptp.o rvu_npc_fs.o \ rvu_cpt.o rvu_devlink.o rpm.o rvu_cn10k.o rvu_switch.o \ - rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o + rvu_sdp.o rvu_npc_hash.o mcs.o mcs_rvu_if.o mcs_cnf10kb.o \ + rvu_rep.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 27935c54b91bc7..8216f843a7cd5f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -112,6 +112,11 @@ struct mac_ops *get_mac_ops(void *cgxd) return ((struct cgx *)cgxd)->mac_ops; } +u32 cgx_get_fifo_len(void *cgxd) +{ + return ((struct cgx *)cgxd)->fifo_len; +} + void cgx_write(struct cgx *cgx, u64 lmac, u64 offset, u64 val) { writeq(val, cgx->reg_base + (lmac << cgx->mac_ops->lmac_offset) + @@ -209,6 +214,24 @@ u8 cgx_lmac_get_p2x(int cgx_id, int lmac_id) return (cfg & CMR_P2X_SEL_MASK) >> CMR_P2X_SEL_SHIFT; } +static u8 cgx_get_nix_resetbit(struct cgx *cgx) +{ + int first_lmac; + u8 p2x; + + /* non 98XX silicons supports only NIX0 block */ + if (cgx->pdev->subsystem_device != PCI_SUBSYS_DEVID_98XX) + return CGX_NIX0_RESET; + + first_lmac = find_first_bit(&cgx->lmac_bmap, cgx->max_lmac_per_mac); + p2x = cgx_lmac_get_p2x(cgx->cgx_id, first_lmac); + + if (p2x == CMR_P2X_SEL_NIX1) + return CGX_NIX1_RESET; + else + return CGX_NIX0_RESET; +} + /* Ensure the required lock for event queue(where asynchronous events are * posted) is acquired before calling this API. Else an asynchronous event(with * latest link status) can reach the destination before this function returns @@ -501,7 +524,7 @@ static u32 cgx_get_lmac_fifo_len(void *cgxd, int lmac_id) u8 num_lmacs; u32 fifo_len; - fifo_len = cgx->mac_ops->fifo_len; + fifo_len = cgx->fifo_len; num_lmacs = cgx->mac_ops->get_nr_lmacs(cgx); switch (num_lmacs) { @@ -1719,6 +1742,8 @@ static int cgx_lmac_init(struct cgx *cgx) lmac->lmac_type = cgx->mac_ops->get_lmac_type(cgx, lmac->lmac_id); } + /* Start X2P reset on given MAC block */ + cgx->mac_ops->mac_x2p_reset(cgx, true); return cgx_lmac_verify_fwi_version(cgx); err_bitmap_free: @@ -1764,7 +1789,7 @@ static void cgx_populate_features(struct cgx *cgx) u64 cfg; cfg = cgx_read(cgx, 0, CGX_CONST); - cgx->mac_ops->fifo_len = FIELD_GET(CGX_CONST_RXFIFO_SIZE, cfg); + cgx->fifo_len = FIELD_GET(CGX_CONST_RXFIFO_SIZE, cfg); cgx->max_lmac_per_mac = FIELD_GET(CGX_CONST_MAX_LMACS, cfg); if (is_dev_rpm(cgx)) @@ -1784,6 +1809,45 @@ static u8 cgx_get_rxid_mapoffset(struct cgx *cgx) return 0x60; } +static void cgx_x2p_reset(void *cgxd, bool enable) +{ + struct cgx *cgx = cgxd; + int lmac_id; + u64 cfg; + + if (enable) { + for_each_set_bit(lmac_id, &cgx->lmac_bmap, cgx->max_lmac_per_mac) + cgx->mac_ops->mac_enadis_rx(cgx, lmac_id, false); + + usleep_range(1000, 2000); + + cfg = cgx_read(cgx, 0, CGXX_CMR_GLOBAL_CONFIG); + cfg |= cgx_get_nix_resetbit(cgx) | CGX_NSCI_DROP; + cgx_write(cgx, 0, CGXX_CMR_GLOBAL_CONFIG, cfg); + } else { + cfg = cgx_read(cgx, 0, CGXX_CMR_GLOBAL_CONFIG); + cfg &= ~(cgx_get_nix_resetbit(cgx) | CGX_NSCI_DROP); + cgx_write(cgx, 0, CGXX_CMR_GLOBAL_CONFIG, cfg); + } +} + +static int cgx_enadis_rx(void *cgxd, int lmac_id, bool enable) +{ + struct cgx *cgx = cgxd; + u64 cfg; + + if (!is_lmac_valid(cgx, lmac_id)) + return -ENODEV; + + cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG); + if (enable) + cfg |= DATA_PKT_RX_EN; + else + cfg &= ~DATA_PKT_RX_EN; + cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg); + return 0; +} + static struct mac_ops cgx_mac_ops = { .name = "cgx", .csr_offset = 0, @@ -1815,6 +1879,8 @@ static struct mac_ops cgx_mac_ops = { .mac_get_pfc_frm_cfg = cgx_lmac_get_pfc_frm_cfg, .mac_reset = cgx_lmac_reset, .mac_stats_reset = cgx_stats_reset, + .mac_x2p_reset = cgx_x2p_reset, + .mac_enadis_rx = cgx_enadis_rx, }; static int cgx_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index dc9ace30554af6..1cf12e5c7da873 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -32,6 +32,10 @@ #define CGX_LMAC_TYPE_MASK 0xF #define CGXX_CMRX_INT 0x040 #define FW_CGX_INT BIT_ULL(1) +#define CGXX_CMR_GLOBAL_CONFIG 0x08 +#define CGX_NIX0_RESET BIT_ULL(2) +#define CGX_NIX1_RESET BIT_ULL(3) +#define CGX_NSCI_DROP BIT_ULL(9) #define CGXX_CMRX_INT_ENA_W1S 0x058 #define CGXX_CMRX_RX_ID_MAP 0x060 #define CGXX_CMRX_RX_STAT0 0x070 @@ -185,4 +189,5 @@ int cgx_lmac_get_pfc_frm_cfg(void *cgxd, int lmac_id, u8 *tx_pause, int verify_lmac_fc_cfg(void *cgxd, int lmac_id, u8 tx_pause, u8 rx_pause, int pfvf_idx); int cgx_lmac_reset(void *cgxd, int lmac_id, u8 pf_req_flr); +u32 cgx_get_fifo_len(void *cgxd); #endif /* CGX_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index 2436c1ff9ba4cf..406c59100a35a1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -156,8 +156,10 @@ enum nix_scheduler { #define NIC_HW_MIN_FRS 40 #define NIC_HW_MAX_FRS 9212 #define SDP_HW_MAX_FRS 65535 +#define SDP_HW_MIN_FRS 16 #define CN10K_LMAC_LINK_MAX_FRS 16380 /* 16k - FCS */ #define CN10K_LBK_LINK_MAX_FRS 65535 /* 64k */ +#define SDP_LINK_CREDIT 0x320202 /* NIX RX action operation*/ #define NIX_RX_ACTIONOP_DROP (0x0ull) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h b/drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h index 9ffc6790c51307..6180e68e1765a7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/lmac_common.h @@ -72,7 +72,6 @@ struct mac_ops { u8 irq_offset; u8 int_ena_bit; u8 lmac_fwi; - u32 fifo_len; bool non_contiguous_serdes_lane; /* RPM & CGX differs in number of Receive/transmit stats */ u8 rx_stats_cnt; @@ -133,6 +132,8 @@ struct mac_ops { int (*get_fec_stats)(void *cgxd, int lmac_id, struct cgx_fec_stats_rsp *rsp); int (*mac_stats_reset)(void *cgxd, int lmac_id); + void (*mac_x2p_reset)(void *cgxd, bool enable); + int (*mac_enadis_rx)(void *cgxd, int lmac_id, bool enable); }; struct cgx { @@ -142,6 +143,10 @@ struct cgx { u8 lmac_count; /* number of LMACs per MAC could be 4 or 8 */ u8 max_lmac_per_mac; + /* length of fifo varies depending on the number + * of LMACS + */ + u32 fifo_len; #define MAX_LMAC_COUNT 8 struct lmac *lmac_idmap[MAX_LMAC_COUNT]; struct work_struct cgx_cmd_work; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 6ea2f3071fe8f7..62c07407eb9419 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -144,6 +144,9 @@ M(LMTST_TBL_SETUP, 0x00a, lmtst_tbl_setup, lmtst_tbl_setup_req, \ msg_rsp) \ M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \ M(PTP_GET_CAP, 0x00c, ptp_get_cap, msg_req, ptp_get_cap_rsp) \ +M(GET_REP_CNT, 0x00d, get_rep_cnt, msg_req, get_rep_cnt_rsp) \ +M(ESW_CFG, 0x00e, esw_cfg, esw_cfg_req, msg_rsp) \ +M(REP_EVENT_NOTIFY, 0x00f, rep_event_notify, rep_event, msg_rsp) \ /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \ M(CGX_STOP_RXTX, 0x201, cgx_stop_rxtx, msg_req, msg_rsp) \ @@ -319,6 +322,7 @@ M(NIX_MCAST_GRP_DESTROY, 0x802c, nix_mcast_grp_destroy, nix_mcast_grp_destroy_re M(NIX_MCAST_GRP_UPDATE, 0x802d, nix_mcast_grp_update, \ nix_mcast_grp_update_req, \ nix_mcast_grp_update_rsp) \ +M(NIX_LF_STATS, 0x802e, nix_lf_stats, nix_stats_req, nix_stats_rsp) \ /* MCS mbox IDs (range 0xA000 - 0xBFFF) */ \ M(MCS_ALLOC_RESOURCES, 0xa000, mcs_alloc_resources, mcs_alloc_rsrc_req, \ mcs_alloc_rsrc_rsp) \ @@ -380,12 +384,16 @@ M(CPT_INST_LMTST, 0xD00, cpt_inst_lmtst, cpt_inst_lmtst_req, msg_rsp) #define MBOX_UP_MCS_MESSAGES \ M(MCS_INTR_NOTIFY, 0xE00, mcs_intr_notify, mcs_intr_info, msg_rsp) +#define MBOX_UP_REP_MESSAGES \ +M(REP_EVENT_UP_NOTIFY, 0xEF0, rep_event_up_notify, rep_event, msg_rsp) \ + enum { #define M(_name, _id, _1, _2, _3) MBOX_MSG_ ## _name = _id, MBOX_MESSAGES MBOX_UP_CGX_MESSAGES MBOX_UP_CPT_MESSAGES MBOX_UP_MCS_MESSAGES +MBOX_UP_REP_MESSAGES #undef M }; @@ -1364,6 +1372,37 @@ struct nix_bandprof_get_hwinfo_rsp { u32 policer_timeunit; }; +struct nix_stats_req { + struct mbox_msghdr hdr; + u8 reset; + u16 pcifunc; + u64 rsvd; +}; + +struct nix_stats_rsp { + struct mbox_msghdr hdr; + u16 pcifunc; + struct { + u64 octs; + u64 ucast; + u64 bcast; + u64 mcast; + u64 drop; + u64 drop_octs; + u64 drop_mcast; + u64 drop_bcast; + u64 err; + u64 rsvd[5]; + } rx; + struct { + u64 ucast; + u64 bcast; + u64 mcast; + u64 drop; + u64 octs; + } tx; +}; + /* NPC mbox message structs */ #define NPC_MCAM_ENTRY_INVALID 0xFFFF @@ -1525,6 +1564,41 @@ struct ptp_get_cap_rsp { u64 cap; }; +struct get_rep_cnt_rsp { + struct mbox_msghdr hdr; + u16 rep_cnt; + u16 rep_pf_map[64]; + u64 rsvd; +}; + +struct esw_cfg_req { + struct mbox_msghdr hdr; + u8 ena; + u64 rsvd; +}; + +struct rep_evt_data { + u8 port_state; + u8 vf_state; + u16 rx_mode; + u16 rx_flags; + u16 mtu; + u8 mac[ETH_ALEN]; + u64 rsvd[5]; +}; + +struct rep_event { + struct mbox_msghdr hdr; + u16 pcifunc; +#define RVU_EVENT_PORT_STATE BIT_ULL(0) +#define RVU_EVENT_PFVF_STATE BIT_ULL(1) +#define RVU_EVENT_MTU_CHANGE BIT_ULL(2) +#define RVU_EVENT_RX_MODE_CHANGE BIT_ULL(3) +#define RVU_EVENT_MAC_ADDR_CHANGE BIT_ULL(4) + u16 event; + struct rep_evt_data evt_data; +}; + struct flow_msg { unsigned char dmac[6]; unsigned char smac[6]; @@ -1563,6 +1637,7 @@ struct flow_msg { u8 icmp_type; u8 icmp_code; __be16 tcp_flags; + u16 sq_id; }; struct npc_install_flow_req { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rpm.c b/drivers/net/ethernet/marvell/octeontx2/af/rpm.c index 1b34cf9c97035a..2e9945446199ec 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rpm.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rpm.c @@ -39,6 +39,8 @@ static struct mac_ops rpm_mac_ops = { .mac_get_pfc_frm_cfg = rpm_lmac_get_pfc_frm_cfg, .mac_reset = rpm_lmac_reset, .mac_stats_reset = rpm_stats_reset, + .mac_x2p_reset = rpm_x2p_reset, + .mac_enadis_rx = rpm_enadis_rx, }; static struct mac_ops rpm2_mac_ops = { @@ -72,6 +74,8 @@ static struct mac_ops rpm2_mac_ops = { .mac_get_pfc_frm_cfg = rpm_lmac_get_pfc_frm_cfg, .mac_reset = rpm_lmac_reset, .mac_stats_reset = rpm_stats_reset, + .mac_x2p_reset = rpm_x2p_reset, + .mac_enadis_rx = rpm_enadis_rx, }; bool is_dev_rpm2(void *rpmd) @@ -467,7 +471,7 @@ u8 rpm_get_lmac_type(void *rpmd, int lmac_id) int err; req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_LINK_STS, req); - err = cgx_fwi_cmd_generic(req, &resp, rpm, 0); + err = cgx_fwi_cmd_generic(req, &resp, rpm, lmac_id); if (!err) return FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, resp); return err; @@ -480,7 +484,7 @@ u32 rpm_get_lmac_fifo_len(void *rpmd, int lmac_id) u8 num_lmacs; u32 fifo_len; - fifo_len = rpm->mac_ops->fifo_len; + fifo_len = rpm->fifo_len; num_lmacs = rpm->mac_ops->get_nr_lmacs(rpm); switch (num_lmacs) { @@ -533,9 +537,9 @@ u32 rpm2_get_lmac_fifo_len(void *rpmd, int lmac_id) */ max_lmac = (rpm_read(rpm, 0, CGX_CONST) >> 24) & 0xFF; if (max_lmac > 4) - fifo_len = rpm->mac_ops->fifo_len / 2; + fifo_len = rpm->fifo_len / 2; else - fifo_len = rpm->mac_ops->fifo_len; + fifo_len = rpm->fifo_len; if (lmac_id < 4) { num_lmacs = hweight8(lmac_info & 0xF); @@ -699,46 +703,51 @@ int rpm_get_fec_stats(void *rpmd, int lmac_id, struct cgx_fec_stats_rsp *rsp) if (rpm->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_NONE) return 0; + /* latched registers FCFECX_CW_HI/RSFEC_STAT_FAST_DATA_HI_CDC are common + * for all counters. Acquire lock to ensure serialized reads + */ + mutex_lock(&rpm->lock); if (rpm->lmac_idmap[lmac_id]->link_info.fec == OTX2_FEC_BASER) { - val_lo = rpm_read(rpm, lmac_id, RPMX_MTI_FCFECX_VL0_CCW_LO); - val_hi = rpm_read(rpm, lmac_id, RPMX_MTI_FCFECX_CW_HI); + val_lo = rpm_read(rpm, 0, RPMX_MTI_FCFECX_VL0_CCW_LO(lmac_id)); + val_hi = rpm_read(rpm, 0, RPMX_MTI_FCFECX_CW_HI(lmac_id)); rsp->fec_corr_blks = (val_hi << 16 | val_lo); - val_lo = rpm_read(rpm, lmac_id, RPMX_MTI_FCFECX_VL0_NCCW_LO); - val_hi = rpm_read(rpm, lmac_id, RPMX_MTI_FCFECX_CW_HI); + val_lo = rpm_read(rpm, 0, RPMX_MTI_FCFECX_VL0_NCCW_LO(lmac_id)); + val_hi = rpm_read(rpm, 0, RPMX_MTI_FCFECX_CW_HI(lmac_id)); rsp->fec_uncorr_blks = (val_hi << 16 | val_lo); /* 50G uses 2 Physical serdes lines */ if (rpm->lmac_idmap[lmac_id]->link_info.lmac_type_id == LMAC_MODE_50G_R) { - val_lo = rpm_read(rpm, lmac_id, - RPMX_MTI_FCFECX_VL1_CCW_LO); - val_hi = rpm_read(rpm, lmac_id, - RPMX_MTI_FCFECX_CW_HI); + val_lo = rpm_read(rpm, 0, + RPMX_MTI_FCFECX_VL1_CCW_LO(lmac_id)); + val_hi = rpm_read(rpm, 0, + RPMX_MTI_FCFECX_CW_HI(lmac_id)); rsp->fec_corr_blks += (val_hi << 16 | val_lo); - val_lo = rpm_read(rpm, lmac_id, - RPMX_MTI_FCFECX_VL1_NCCW_LO); - val_hi = rpm_read(rpm, lmac_id, - RPMX_MTI_FCFECX_CW_HI); + val_lo = rpm_read(rpm, 0, + RPMX_MTI_FCFECX_VL1_NCCW_LO(lmac_id)); + val_hi = rpm_read(rpm, 0, + RPMX_MTI_FCFECX_CW_HI(lmac_id)); rsp->fec_uncorr_blks += (val_hi << 16 | val_lo); } } else { /* enable RS-FEC capture */ - cfg = rpm_read(rpm, 0, RPMX_MTI_STAT_STATN_CONTROL); + cfg = rpm_read(rpm, 0, RPMX_MTI_RSFEC_STAT_STATN_CONTROL); cfg |= RPMX_RSFEC_RX_CAPTURE | BIT(lmac_id); - rpm_write(rpm, 0, RPMX_MTI_STAT_STATN_CONTROL, cfg); + rpm_write(rpm, 0, RPMX_MTI_RSFEC_STAT_STATN_CONTROL, cfg); val_lo = rpm_read(rpm, 0, RPMX_MTI_RSFEC_STAT_COUNTER_CAPTURE_2); - val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC); + val_hi = rpm_read(rpm, 0, RPMX_MTI_RSFEC_STAT_FAST_DATA_HI_CDC); rsp->fec_corr_blks = (val_hi << 32 | val_lo); val_lo = rpm_read(rpm, 0, RPMX_MTI_RSFEC_STAT_COUNTER_CAPTURE_3); - val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC); + val_hi = rpm_read(rpm, 0, RPMX_MTI_RSFEC_STAT_FAST_DATA_HI_CDC); rsp->fec_uncorr_blks = (val_hi << 32 | val_lo); } + mutex_unlock(&rpm->lock); return 0; } @@ -763,3 +772,41 @@ int rpm_lmac_reset(void *rpmd, int lmac_id, u8 pf_req_flr) return 0; } + +void rpm_x2p_reset(void *rpmd, bool enable) +{ + rpm_t *rpm = rpmd; + int lmac_id; + u64 cfg; + + if (enable) { + for_each_set_bit(lmac_id, &rpm->lmac_bmap, rpm->max_lmac_per_mac) + rpm->mac_ops->mac_enadis_rx(rpm, lmac_id, false); + + usleep_range(1000, 2000); + + cfg = rpm_read(rpm, 0, RPMX_CMR_GLOBAL_CFG); + rpm_write(rpm, 0, RPMX_CMR_GLOBAL_CFG, cfg | RPM_NIX0_RESET); + } else { + cfg = rpm_read(rpm, 0, RPMX_CMR_GLOBAL_CFG); + cfg &= ~RPM_NIX0_RESET; + rpm_write(rpm, 0, RPMX_CMR_GLOBAL_CFG, cfg); + } +} + +int rpm_enadis_rx(void *rpmd, int lmac_id, bool enable) +{ + rpm_t *rpm = rpmd; + u64 cfg; + + if (!is_lmac_valid(rpm, lmac_id)) + return -ENODEV; + + cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); + if (enable) + cfg |= RPM_RX_EN; + else + cfg &= ~RPM_RX_EN; + rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rpm.h b/drivers/net/ethernet/marvell/octeontx2/af/rpm.h index 34b11deb0f3c1d..b8d3972e096aed 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rpm.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rpm.h @@ -17,6 +17,8 @@ /* Registers */ #define RPMX_CMRX_CFG 0x00 +#define RPMX_CMR_GLOBAL_CFG 0x08 +#define RPM_NIX0_RESET BIT_ULL(3) #define RPMX_RX_TS_PREPEND BIT_ULL(22) #define RPMX_TX_PTP_1S_SUPPORT BIT_ULL(17) #define RPMX_CMRX_RX_ID_MAP 0x80 @@ -84,16 +86,18 @@ /* FEC stats */ #define RPMX_MTI_STAT_STATN_CONTROL 0x10018 #define RPMX_MTI_STAT_DATA_HI_CDC 0x10038 -#define RPMX_RSFEC_RX_CAPTURE BIT_ULL(27) +#define RPMX_RSFEC_RX_CAPTURE BIT_ULL(28) #define RPMX_CMD_CLEAR_RX BIT_ULL(30) #define RPMX_CMD_CLEAR_TX BIT_ULL(31) +#define RPMX_MTI_RSFEC_STAT_STATN_CONTROL 0x40018 +#define RPMX_MTI_RSFEC_STAT_FAST_DATA_HI_CDC 0x40000 #define RPMX_MTI_RSFEC_STAT_COUNTER_CAPTURE_2 0x40050 #define RPMX_MTI_RSFEC_STAT_COUNTER_CAPTURE_3 0x40058 -#define RPMX_MTI_FCFECX_VL0_CCW_LO 0x38618 -#define RPMX_MTI_FCFECX_VL0_NCCW_LO 0x38620 -#define RPMX_MTI_FCFECX_VL1_CCW_LO 0x38628 -#define RPMX_MTI_FCFECX_VL1_NCCW_LO 0x38630 -#define RPMX_MTI_FCFECX_CW_HI 0x38638 +#define RPMX_MTI_FCFECX_VL0_CCW_LO(a) (0x38618 + ((a) * 0x40)) +#define RPMX_MTI_FCFECX_VL0_NCCW_LO(a) (0x38620 + ((a) * 0x40)) +#define RPMX_MTI_FCFECX_VL1_CCW_LO(a) (0x38628 + ((a) * 0x40)) +#define RPMX_MTI_FCFECX_VL1_NCCW_LO(a) (0x38630 + ((a) * 0x40)) +#define RPMX_MTI_FCFECX_CW_HI(a) (0x38638 + ((a) * 0x40)) /* CN10KB CSR Declaration */ #define RPM2_CMRX_SW_INT 0x1b0 @@ -137,4 +141,6 @@ bool is_dev_rpm2(void *rpmd); int rpm_get_fec_stats(void *cgxd, int lmac_id, struct cgx_fec_stats_rsp *rsp); int rpm_lmac_reset(void *rpmd, int lmac_id, u8 pf_req_flr); int rpm_stats_reset(void *rpmd, int lmac_id); +void rpm_x2p_reset(void *rpmd, bool enable); +int rpm_enadis_rx(void *rpmd, int lmac_id, bool enable); #endif /* RPM_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 1a97fb9032fa44..cd0d7b7774f1af 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1162,6 +1162,7 @@ static int rvu_setup_hw_resources(struct rvu *rvu) } rvu_program_channels(rvu); + cgx_start_linkup(rvu); err = rvu_mcs_init(rvu); if (err) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 5016ba82e1423a..a383b5ef5b2d8d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -513,6 +513,11 @@ struct rvu_switch { u16 start_entry; }; +struct rep_evtq_ent { + struct list_head node; + struct rep_event event; +}; + struct rvu { void __iomem *afreg_base; void __iomem *pfreg_base; @@ -525,6 +530,7 @@ struct rvu { struct mutex alias_lock; /* Serialize bar2 alias access */ int vfs; /* Number of VFs attached to RVU */ u16 vf_devid; /* VF devices id */ + bool def_rule_cntr_en; int nix_blkaddr[MAX_NIX_BLKS]; /* Mbox */ @@ -594,6 +600,15 @@ struct rvu { spinlock_t cpt_intr_lock; struct mutex mbox_lock; /* Serialize mbox up and down msgs */ + u16 rep_pcifunc; + int rep_cnt; + u16 *rep2pfvf_map; + u8 rep_mode; + struct work_struct rep_evt_work; + struct workqueue_struct *rep_evt_wq; + struct list_head rep_evtq_head; + /* Representor event lock */ + spinlock_t rep_evtq_lock; }; static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val) @@ -852,6 +867,14 @@ bool is_sdp_pfvf(u16 pcifunc); bool is_sdp_pf(u16 pcifunc); bool is_sdp_vf(struct rvu *rvu, u16 pcifunc); +static inline bool is_rep_dev(struct rvu *rvu, u16 pcifunc) +{ + if (rvu->rep_pcifunc && rvu->rep_pcifunc == pcifunc) + return true; + + return false; +} + /* CGX APIs */ static inline bool is_pf_cgxmapped(struct rvu *rvu, u8 pf) { @@ -960,7 +983,11 @@ void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf); void rvu_npc_enable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf); void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf, int group, int alg_idx, int mcam_index); - +void __rvu_mcam_remove_counter_from_rule(struct rvu *rvu, u16 pcifunc, + struct rvu_npc_mcam_rule *rule); +void __rvu_mcam_add_counter_to_rule(struct rvu *rvu, u16 pcifunc, + struct rvu_npc_mcam_rule *rule, + struct npc_install_flow_rsp *rsp); void rvu_npc_get_mcam_entry_alloc_info(struct rvu *rvu, u16 pcifunc, int blkaddr, int *alloc_cnt, int *enable_cnt); @@ -985,6 +1012,7 @@ void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam, void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, u16 src, struct mcam_entry *entry, u8 *intf, u8 *ena); +int npc_config_cntr_default_entries(struct rvu *rvu, bool enable); bool is_cgx_config_permitted(struct rvu *rvu, u16 pcifunc); bool is_mac_feature_supported(struct rvu *rvu, int pf, int feature); u32 rvu_cgx_get_fifolen(struct rvu *rvu); @@ -997,6 +1025,7 @@ int rvu_cgx_prio_flow_ctrl_cfg(struct rvu *rvu, u16 pcifunc, u8 tx_pause, u8 rx_ int rvu_cgx_cfg_pause_frm(struct rvu *rvu, u16 pcifunc, u8 tx_pause, u8 rx_pause); void rvu_mac_reset(struct rvu *rvu, u16 pcifunc); u32 rvu_cgx_get_lmac_fifolen(struct rvu *rvu, int cgx, int lmac); +void cgx_start_linkup(struct rvu *rvu); int npc_get_nixlf_mcam_index(struct npc_mcam *mcam, u16 pcifunc, int nixlf, int type); bool is_mcam_entry_enabled(struct rvu *rvu, struct npc_mcam *mcam, int blkaddr, @@ -1045,7 +1074,8 @@ int rvu_ndc_fix_locked_cacheline(struct rvu *rvu, int blkaddr); /* RVU Switch */ void rvu_switch_enable(struct rvu *rvu); void rvu_switch_disable(struct rvu *rvu); -void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc); +void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc, bool ena); +void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool ena); int rvu_npc_set_parse_mode(struct rvu *rvu, u16 pcifunc, u64 mode, u8 dir, u64 pkind, u8 var_len_off, u8 var_len_off_mask, @@ -1058,4 +1088,9 @@ 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); +/* Representor APIs */ +int rvu_rep_pf_init(struct rvu *rvu); +int rvu_rep_install_mcam_rules(struct rvu *rvu); +void rvu_rep_update_rules(struct rvu *rvu, u16 pcifunc, bool ena); +int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable); #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 266ecbc1b97a68..992fa0b82e8d2d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -349,6 +349,7 @@ static void rvu_cgx_wq_destroy(struct rvu *rvu) int rvu_cgx_init(struct rvu *rvu) { + struct mac_ops *mac_ops; int cgx, err; void *cgxd; @@ -375,6 +376,15 @@ int rvu_cgx_init(struct rvu *rvu) if (err) return err; + /* Clear X2P reset on all MAC blocks */ + for (cgx = 0; cgx < rvu->cgx_cnt_max; cgx++) { + cgxd = rvu_cgx_pdata(cgx, rvu); + if (!cgxd) + continue; + mac_ops = get_mac_ops(cgxd); + mac_ops->mac_x2p_reset(cgxd, false); + } + /* Register for CGX events */ err = cgx_lmac_event_handler_init(rvu); if (err) @@ -382,10 +392,26 @@ int rvu_cgx_init(struct rvu *rvu) mutex_init(&rvu->cgx_cfg_lock); - /* Ensure event handler registration is completed, before - * we turn on the links - */ - mb(); + return 0; +} + +void cgx_start_linkup(struct rvu *rvu) +{ + unsigned long lmac_bmap; + struct mac_ops *mac_ops; + int cgx, lmac, err; + void *cgxd; + + /* Enable receive on all LMACS */ + for (cgx = 0; cgx <= rvu->cgx_cnt_max; cgx++) { + cgxd = rvu_cgx_pdata(cgx, rvu); + if (!cgxd) + continue; + mac_ops = get_mac_ops(cgxd); + lmac_bmap = cgx_get_lmac_bmap(cgxd); + for_each_set_bit(lmac, &lmac_bmap, rvu->hw->lmac_per_cgx) + mac_ops->mac_enadis_rx(cgxd, lmac, true); + } /* Do link up for all CGX ports */ for (cgx = 0; cgx <= rvu->cgx_cnt_max; cgx++) { @@ -398,8 +424,6 @@ int rvu_cgx_init(struct rvu *rvu) "Link up process failed to start on cgx %d\n", cgx); } - - return 0; } int rvu_cgx_exit(struct rvu *rvu) @@ -923,13 +947,12 @@ int rvu_mbox_handler_cgx_features_get(struct rvu *rvu, u32 rvu_cgx_get_fifolen(struct rvu *rvu) { - struct mac_ops *mac_ops; - u32 fifo_len; + void *cgxd = rvu_first_cgx_pdata(rvu); - mac_ops = get_mac_ops(rvu_first_cgx_pdata(rvu)); - fifo_len = mac_ops ? mac_ops->fifo_len : 0; + if (!cgxd) + return 0; - return fifo_len; + return cgx_get_fifo_len(cgxd); } u32 rvu_cgx_get_lmac_fifolen(struct rvu *rvu, int cgx, int lmac) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 87ba77e5026a02..148144f5b61df7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -45,33 +45,6 @@ enum { CGX_STAT18, }; -/* NIX TX stats */ -enum nix_stat_lf_tx { - TX_UCAST = 0x0, - TX_BCAST = 0x1, - TX_MCAST = 0x2, - TX_DROP = 0x3, - TX_OCTS = 0x4, - TX_STATS_ENUM_LAST, -}; - -/* NIX RX stats */ -enum nix_stat_lf_rx { - RX_OCTS = 0x0, - RX_UCAST = 0x1, - RX_BCAST = 0x2, - RX_MCAST = 0x3, - RX_DROP = 0x4, - RX_DROP_OCTS = 0x5, - RX_FCS = 0x6, - RX_ERR = 0x7, - RX_DRP_BCAST = 0x8, - RX_DRP_MCAST = 0x9, - RX_DRP_L3BCAST = 0xa, - RX_DRP_L3MCAST = 0xb, - RX_STATS_ENUM_LAST, -}; - static char *cgx_rx_stats_fields[] = { [CGX_STAT0] = "Received packets", [CGX_STAT1] = "Octets of received packets", @@ -663,16 +636,16 @@ static ssize_t rvu_dbg_lmtst_map_table_display(struct file *filp, RVU_DEBUG_FOPS(lmtst_map_table, lmtst_map_table_display, NULL); -static void get_lf_str_list(struct rvu_block block, int pcifunc, +static void get_lf_str_list(const struct rvu_block *block, int pcifunc, char *lfs) { - int lf = 0, seq = 0, len = 0, prev_lf = block.lf.max; + int lf = 0, seq = 0, len = 0, prev_lf = block->lf.max; - for_each_set_bit(lf, block.lf.bmap, block.lf.max) { - if (lf >= block.lf.max) + for_each_set_bit(lf, block->lf.bmap, block->lf.max) { + if (lf >= block->lf.max) break; - if (block.fn_map[lf] != pcifunc) + if (block->fn_map[lf] != pcifunc) continue; if (lf == prev_lf + 1) { @@ -719,7 +692,7 @@ static int get_max_column_width(struct rvu *rvu) if (!strlen(block.name)) continue; - get_lf_str_list(block, pcifunc, buf); + get_lf_str_list(&block, pcifunc, buf); if (lf_str_size <= strlen(buf)) lf_str_size = strlen(buf) + 1; } @@ -803,7 +776,7 @@ static ssize_t rvu_dbg_rsrc_attach_status(struct file *filp, continue; len = 0; lfs[len] = '\0'; - get_lf_str_list(block, pcifunc, lfs); + get_lf_str_list(&block, pcifunc, lfs); if (strlen(lfs)) flag = 1; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c index 7498ab429963d4..dab4deca893f5d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c @@ -1238,6 +1238,7 @@ enum rvu_af_dl_param_id { RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU, RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT, RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE, + RVU_AF_DEVLINK_PARAM_ID_NPC_DEF_RULE_CNTR_ENABLE, RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF, }; @@ -1358,6 +1359,32 @@ static int rvu_af_dl_npc_mcam_high_zone_percent_validate(struct devlink *devlink return 0; } +static int rvu_af_dl_npc_def_rule_cntr_get(struct devlink *devlink, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct rvu_devlink *rvu_dl = devlink_priv(devlink); + struct rvu *rvu = rvu_dl->rvu; + + ctx->val.vbool = rvu->def_rule_cntr_en; + + return 0; +} + +static int rvu_af_dl_npc_def_rule_cntr_set(struct devlink *devlink, u32 id, + struct devlink_param_gset_ctx *ctx, + struct netlink_ext_ack *extack) +{ + struct rvu_devlink *rvu_dl = devlink_priv(devlink); + struct rvu *rvu = rvu_dl->rvu; + int err; + + err = npc_config_cntr_default_entries(rvu, ctx->val.vbool); + if (!err) + rvu->def_rule_cntr_en = ctx->val.vbool; + + return err; +} + static int rvu_af_dl_nix_maxlf_get(struct devlink *devlink, u32 id, struct devlink_param_gset_ctx *ctx) { @@ -1444,6 +1471,11 @@ static const struct devlink_param rvu_af_dl_params[] = { rvu_af_dl_npc_mcam_high_zone_percent_get, rvu_af_dl_npc_mcam_high_zone_percent_set, rvu_af_dl_npc_mcam_high_zone_percent_validate), + DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_DEF_RULE_CNTR_ENABLE, + "npc_def_rule_cntr", DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + rvu_af_dl_npc_def_rule_cntr_get, + rvu_af_dl_npc_def_rule_cntr_set, NULL), DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF, "nix_maxlf", DEVLINK_PARAM_TYPE_U16, BIT(DEVLINK_PARAM_CMODE_RUNTIME), @@ -1468,6 +1500,9 @@ static int rvu_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) struct rvu *rvu = rvu_dl->rvu; struct rvu_switch *rswitch; + if (rvu->rep_mode) + return -EOPNOTSUPP; + rswitch = &rvu->rswitch; *mode = rswitch->mode; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index da69350c6f7654..a5d1e2bddd58db 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -31,6 +31,7 @@ static int nix_free_all_bandprof(struct rvu *rvu, u16 pcifunc); static void nix_clear_ratelimit_aggr(struct rvu *rvu, struct nix_hw *nix_hw, u32 leaf_prof); static const char *nix_get_ctx_name(int ctype); +static int nix_get_tx_link(struct rvu *rvu, u16 pcifunc); enum mc_tbl_sz { MC_TBL_SZ_256, @@ -312,7 +313,9 @@ static bool is_valid_txschq(struct rvu *rvu, int blkaddr, /* TLs aggegating traffic are shared across PF and VFs */ if (lvl >= hw->cap.nix_tx_aggr_lvl) { - if (rvu_get_pf(map_func) != rvu_get_pf(pcifunc)) + if ((nix_get_tx_link(rvu, map_func) != + nix_get_tx_link(rvu, pcifunc)) && + (rvu_get_pf(map_func) != rvu_get_pf(pcifunc))) return false; else return true; @@ -360,7 +363,6 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf, cgx_set_pkind(rvu_cgx_pdata(cgx_id, rvu), lmac_id, pkind); rvu_npc_set_pkind(rvu, pkind, pfvf); - break; case NIX_INTF_TYPE_LBK: vf = (pcifunc & RVU_PFVF_FUNC_MASK) - 1; @@ -584,6 +586,9 @@ int rvu_mbox_handler_nix_bp_disable(struct rvu *rvu, if (!is_pf_cgxmapped(rvu, pf) && type != NIX_INTF_TYPE_LBK) return 0; + if (is_sdp_pfvf(pcifunc)) + type = NIX_INTF_TYPE_SDP; + pfvf = rvu_get_pfvf(rvu, pcifunc); err = nix_get_struct_ptrs(rvu, pcifunc, &nix_hw, &blkaddr); if (err) @@ -1614,6 +1619,12 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, cfg = NPC_TX_DEF_PKIND; rvu_write64(rvu, blkaddr, NIX_AF_LFX_TX_PARSE_CFG(nixlf), cfg); + if (is_rep_dev(rvu, pcifunc)) { + pfvf->tx_chan_base = RVU_SWITCH_LBK_CHAN; + pfvf->tx_chan_cnt = 1; + goto exit; + } + intf = is_lbk_vf(rvu, pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX; if (is_sdp_pfvf(pcifunc)) intf = NIX_INTF_TYPE_SDP; @@ -1684,6 +1695,9 @@ int rvu_mbox_handler_nix_lf_free(struct rvu *rvu, struct nix_lf_free_req *req, if (nixlf < 0) return NIX_AF_ERR_AF_LF_INVALID; + if (is_rep_dev(rvu, pcifunc)) + goto free_lf; + if (req->flags & NIX_LF_DISABLE_FLOWS) rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf); else @@ -1695,6 +1709,7 @@ int rvu_mbox_handler_nix_lf_free(struct rvu *rvu, struct nix_lf_free_req *req, nix_interface_deinit(rvu, pcifunc, nixlf); +free_lf: /* Reset this NIX LF */ err = rvu_lf_reset(rvu, block, nixlf); if (err) { @@ -2007,7 +2022,8 @@ static void nix_get_txschq_range(struct rvu *rvu, u16 pcifunc, struct rvu_hwinfo *hw = rvu->hw; int pf = rvu_get_pf(pcifunc); - if (is_lbk_vf(rvu, pcifunc)) { /* LBK links */ + /* LBK links */ + if (is_lbk_vf(rvu, pcifunc) || is_rep_dev(rvu, pcifunc)) { *start = hw->cap.nix_txsch_per_cgx_lmac * link; *end = *start + hw->cap.nix_txsch_per_lbk_lmac; } else if (is_pf_cgxmapped(rvu, pf)) { /* CGX links */ @@ -2760,7 +2776,7 @@ void rvu_nix_tx_tl2_cfg(struct rvu *rvu, int blkaddr, u16 pcifunc, int schq; u64 cfg; - if (!is_pf_cgxmapped(rvu, pf)) + if (!is_pf_cgxmapped(rvu, pf) && !is_rep_dev(rvu, pcifunc)) return; cfg = enable ? (BIT_ULL(12) | RVU_SWITCH_LBK_CHAN) : 0; @@ -4393,8 +4409,6 @@ int rvu_mbox_handler_nix_set_mac_addr(struct rvu *rvu, if (test_bit(PF_SET_VF_TRUSTED, &pfvf->flags) && from_vf) ether_addr_copy(pfvf->default_mac, req->mac_addr); - rvu_switch_update_rules(rvu, pcifunc); - return 0; } @@ -4555,7 +4569,7 @@ int rvu_mbox_handler_nix_set_hw_frs(struct rvu *rvu, struct nix_frs_cfg *req, if (!nix_hw) return NIX_AF_ERR_INVALID_NIXBLK; - if (is_lbk_vf(rvu, pcifunc)) + if (is_lbk_vf(rvu, pcifunc) || is_rep_dev(rvu, pcifunc)) rvu_get_lbk_link_max_frs(rvu, &max_mtu); else rvu_get_lmac_link_max_frs(rvu, &max_mtu); @@ -4583,6 +4597,8 @@ int rvu_mbox_handler_nix_set_hw_frs(struct rvu *rvu, struct nix_frs_cfg *req, /* For VFs of PF0 ingress is LBK port, so config LBK link */ pfvf = rvu_get_pfvf(rvu, pcifunc); link = hw->cgx_links + pfvf->lbkid; + } else if (is_rep_dev(rvu, pcifunc)) { + link = hw->cgx_links + 0; } if (link < 0) @@ -4656,6 +4672,9 @@ static void nix_link_config(struct rvu *rvu, int blkaddr, rvu_get_lbk_link_max_frs(rvu, &lbk_max_frs); rvu_get_lmac_link_max_frs(rvu, &lmac_max_frs); + /* Set SDP link credit */ + rvu_write64(rvu, blkaddr, NIX_AF_SDP_LINK_CREDIT, SDP_LINK_CREDIT); + /* Set default min/max packet lengths allowed on NIX Rx links. * * With HW reset minlen value of 60byte, HW will treat ARP pkts @@ -4674,7 +4693,7 @@ static void nix_link_config(struct rvu *rvu, int blkaddr, if (hw->sdp_links) { link = hw->cgx_links + hw->lbk_links; rvu_write64(rvu, blkaddr, NIX_AF_RX_LINKX_CFG(link), - SDP_HW_MAX_FRS << 16 | NIC_HW_MIN_FRS); + SDP_HW_MAX_FRS << 16 | SDP_HW_MIN_FRS); } /* Get MCS external bypass status for CN10K-B */ @@ -5166,7 +5185,7 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req, { u16 pcifunc = req->hdr.pcifunc; struct rvu_pfvf *pfvf; - int nixlf, err; + int nixlf, err, pf; err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL); if (err) @@ -5182,7 +5201,11 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req, pfvf = rvu_get_pfvf(rvu, pcifunc); set_bit(NIXLF_INITIALIZED, &pfvf->flags); - rvu_switch_update_rules(rvu, pcifunc); + rvu_switch_update_rules(rvu, pcifunc, true); + + pf = rvu_get_pf(pcifunc); + if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode) + rvu_rep_notify_pfvf_state(rvu, pcifunc, true); return rvu_cgx_start_stop_io(rvu, pcifunc, true); } @@ -5192,7 +5215,7 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req, { u16 pcifunc = req->hdr.pcifunc; struct rvu_pfvf *pfvf; - int nixlf, err; + int nixlf, err, pf; err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL); if (err) @@ -5210,8 +5233,12 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req, if (err) return err; + rvu_switch_update_rules(rvu, pcifunc, false); rvu_cgx_tx_enable(rvu, pcifunc, true); + pf = rvu_get_pf(pcifunc); + if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode) + rvu_rep_notify_pfvf_state(rvu, pcifunc, false); return 0; } @@ -5239,6 +5266,9 @@ void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int nixlf) clear_bit(NIXLF_INITIALIZED, &pfvf->flags); + if (is_pf_cgxmapped(rvu, pf) && rvu->rep_mode) + rvu_rep_notify_pfvf_state(rvu, pcifunc, false); + rvu_cgx_start_stop_io(rvu, pcifunc, false); if (pfvf->sq_ctx) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index 97722ce8c4cb34..821fe242f821f1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -2691,6 +2691,49 @@ void npc_mcam_rsrcs_reserve(struct rvu *rvu, int blkaddr, int entry_idx) npc_mcam_set_bit(mcam, entry_idx); } +int npc_config_cntr_default_entries(struct rvu *rvu, bool enable) +{ + struct npc_mcam *mcam = &rvu->hw->mcam; + struct npc_install_flow_rsp rsp; + struct rvu_npc_mcam_rule *rule; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return -EINVAL; + + mutex_lock(&mcam->lock); + list_for_each_entry(rule, &mcam->mcam_rules, list) { + if (!is_mcam_entry_enabled(rvu, mcam, blkaddr, rule->entry)) + continue; + if (!rule->default_rule) + continue; + if (enable && !rule->has_cntr) { /* Alloc and map new counter */ + __rvu_mcam_add_counter_to_rule(rvu, rule->owner, + rule, &rsp); + if (rsp.counter < 0) { + dev_err(rvu->dev, + "%s: Failed to allocate cntr for default rule (err=%d)\n", + __func__, rsp.counter); + break; + } + npc_map_mcam_entry_and_cntr(rvu, mcam, blkaddr, + rule->entry, rsp.counter); + /* Reset counter before use */ + rvu_write64(rvu, blkaddr, + NPC_AF_MATCH_STATX(rule->cntr), 0x0); + } + + /* Free and unmap counter */ + if (!enable && rule->has_cntr) + __rvu_mcam_remove_counter_from_rule(rvu, rule->owner, + rule); + } + mutex_unlock(&mcam->lock); + + return 0; +} + int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu, struct npc_mcam_alloc_entry_req *req, struct npc_mcam_alloc_entry_rsp *rsp) @@ -2975,9 +3018,9 @@ int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu *rvu, return rc; } -int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu, - struct npc_mcam_alloc_counter_req *req, - struct npc_mcam_alloc_counter_rsp *rsp) +static int __npc_mcam_alloc_counter(struct rvu *rvu, + struct npc_mcam_alloc_counter_req *req, + struct npc_mcam_alloc_counter_rsp *rsp) { struct npc_mcam *mcam = &rvu->hw->mcam; u16 pcifunc = req->hdr.pcifunc; @@ -2998,11 +3041,9 @@ int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu, if (!req->contig && req->count > NPC_MAX_NONCONTIG_COUNTERS) return NPC_MCAM_INVALID_REQ; - mutex_lock(&mcam->lock); /* Check if unused counters are available or not */ if (!rvu_rsrc_free_count(&mcam->counters)) { - mutex_unlock(&mcam->lock); return NPC_MCAM_ALLOC_FAILED; } @@ -3035,12 +3076,27 @@ int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu, } } - mutex_unlock(&mcam->lock); return 0; } -int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu, - struct npc_mcam_oper_counter_req *req, struct msg_rsp *rsp) +int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu, + struct npc_mcam_alloc_counter_req *req, + struct npc_mcam_alloc_counter_rsp *rsp) +{ + struct npc_mcam *mcam = &rvu->hw->mcam; + int err; + + mutex_lock(&mcam->lock); + + err = __npc_mcam_alloc_counter(rvu, req, rsp); + + mutex_unlock(&mcam->lock); + return err; +} + +static int __npc_mcam_free_counter(struct rvu *rvu, + struct npc_mcam_oper_counter_req *req, + struct msg_rsp *rsp) { struct npc_mcam *mcam = &rvu->hw->mcam; u16 index, entry = 0; @@ -3050,10 +3106,8 @@ int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu, if (blkaddr < 0) return NPC_MCAM_INVALID_REQ; - mutex_lock(&mcam->lock); err = npc_mcam_verify_counter(mcam, req->hdr.pcifunc, req->cntr); if (err) { - mutex_unlock(&mcam->lock); return err; } @@ -3077,10 +3131,66 @@ int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu, index, req->cntr); } - mutex_unlock(&mcam->lock); return 0; } +int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu, + struct npc_mcam_oper_counter_req *req, struct msg_rsp *rsp) +{ + struct npc_mcam *mcam = &rvu->hw->mcam; + int err; + + mutex_lock(&mcam->lock); + + err = __npc_mcam_free_counter(rvu, req, rsp); + + mutex_unlock(&mcam->lock); + + return err; +} + +void __rvu_mcam_remove_counter_from_rule(struct rvu *rvu, u16 pcifunc, + struct rvu_npc_mcam_rule *rule) +{ + struct npc_mcam_oper_counter_req free_req = { 0 }; + struct msg_rsp free_rsp; + + if (!rule->has_cntr) + return; + + free_req.hdr.pcifunc = pcifunc; + free_req.cntr = rule->cntr; + + __npc_mcam_free_counter(rvu, &free_req, &free_rsp); + rule->has_cntr = false; +} + +void __rvu_mcam_add_counter_to_rule(struct rvu *rvu, u16 pcifunc, + struct rvu_npc_mcam_rule *rule, + struct npc_install_flow_rsp *rsp) +{ + struct npc_mcam_alloc_counter_req cntr_req = { 0 }; + struct npc_mcam_alloc_counter_rsp cntr_rsp = { 0 }; + int err; + + cntr_req.hdr.pcifunc = pcifunc; + cntr_req.contig = true; + cntr_req.count = 1; + + /* we try to allocate a counter to track the stats of this + * rule. If counter could not be allocated then proceed + * without counter because counters are limited than entries. + */ + err = __npc_mcam_alloc_counter(rvu, &cntr_req, &cntr_rsp); + if (!err && cntr_rsp.count) { + rule->cntr = cntr_rsp.cntr; + rule->has_cntr = true; + rsp->counter = rule->cntr; + } else { + rsp->counter = err; + } +} + int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu, struct npc_mcam_unmap_counter_req *req, struct msg_rsp *rsp) { 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 150635de2bd5a1..1b765045aa636b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c @@ -1081,44 +1081,26 @@ static void rvu_mcam_add_rule(struct npc_mcam *mcam, static void rvu_mcam_remove_counter_from_rule(struct rvu *rvu, u16 pcifunc, struct rvu_npc_mcam_rule *rule) { - struct npc_mcam_oper_counter_req free_req = { 0 }; - struct msg_rsp free_rsp; + struct npc_mcam *mcam = &rvu->hw->mcam; - if (!rule->has_cntr) - return; + mutex_lock(&mcam->lock); - free_req.hdr.pcifunc = pcifunc; - free_req.cntr = rule->cntr; + __rvu_mcam_remove_counter_from_rule(rvu, pcifunc, rule); - rvu_mbox_handler_npc_mcam_free_counter(rvu, &free_req, &free_rsp); - rule->has_cntr = false; + mutex_unlock(&mcam->lock); } static void rvu_mcam_add_counter_to_rule(struct rvu *rvu, u16 pcifunc, struct rvu_npc_mcam_rule *rule, struct npc_install_flow_rsp *rsp) { - struct npc_mcam_alloc_counter_req cntr_req = { 0 }; - struct npc_mcam_alloc_counter_rsp cntr_rsp = { 0 }; - int err; + struct npc_mcam *mcam = &rvu->hw->mcam; - cntr_req.hdr.pcifunc = pcifunc; - cntr_req.contig = true; - cntr_req.count = 1; + mutex_lock(&mcam->lock); - /* we try to allocate a counter to track the stats of this - * rule. If counter could not be allocated then proceed - * without counter because counters are limited than entries. - */ - err = rvu_mbox_handler_npc_mcam_alloc_counter(rvu, &cntr_req, - &cntr_rsp); - if (!err && cntr_rsp.count) { - rule->cntr = cntr_rsp.cntr; - rule->has_cntr = true; - rsp->counter = rule->cntr; - } else { - rsp->counter = err; - } + __rvu_mcam_add_counter_to_rule(rvu, pcifunc, rule, rsp); + + mutex_unlock(&mcam->lock); } static int npc_mcast_update_action_index(struct rvu *rvu, struct npc_install_flow_req *req, @@ -1416,6 +1398,7 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, struct npc_install_flow_rsp *rsp) { bool from_vf = !!(req->hdr.pcifunc & RVU_PFVF_FUNC_MASK); + bool from_rep_dev = !!is_rep_dev(rvu, req->hdr.pcifunc); struct rvu_switch *rswitch = &rvu->rswitch; int blkaddr, nixlf, err; struct rvu_pfvf *pfvf; @@ -1469,18 +1452,21 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, * hence modify pcifunc accordingly. */ - /* AF installing for a PF/VF */ - if (!req->hdr.pcifunc) + if (!req->hdr.pcifunc) { + /* AF installing for a PF/VF */ target = req->vf; - /* PF installing for its VF */ - else if (!from_vf && req->vf) { + } else if (!from_vf && req->vf && !from_rep_dev) { + /* PF installing for its VF */ target = (req->hdr.pcifunc & ~RVU_PFVF_FUNC_MASK) | req->vf; pf_set_vfs_mac = req->default_rule && (req->features & BIT_ULL(NPC_DMAC)); - } - /* msg received from PF/VF */ - else + } else if (from_rep_dev && req->vf) { + /* Representor device installing for a representee */ + target = req->vf; + } else { + /* msg received from PF/VF */ target = req->hdr.pcifunc; + } /* ignore chan_mask in case pf func is not AF, revisit later */ if (!is_pffunc_af(req->hdr.pcifunc)) @@ -1492,8 +1478,10 @@ int rvu_mbox_handler_npc_install_flow(struct rvu *rvu, pfvf = rvu_get_pfvf(rvu, target); + if (from_rep_dev) + req->channel = pfvf->rx_chan_base; /* PF installing for its VF */ - if (req->hdr.pcifunc && !from_vf && req->vf) + if (req->hdr.pcifunc && !from_vf && req->vf && !from_rep_dev) set_bit(PF_SET_VF_CFG, &pfvf->flags); /* update req destination mac addr */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index 2b299fa8515913..62cdc714ba5772 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -445,6 +445,7 @@ #define NIX_CONST_MAX_BPIDS GENMASK_ULL(23, 12) #define NIX_CONST_SDP_CHANS GENMASK_ULL(11, 0) +#define NIX_VLAN_ETYPE_MASK GENMASK_ULL(63, 48) #define NIX_AF_MDQ_PARENT_MASK GENMASK_ULL(24, 16) #define NIX_AF_TL4_PARENT_MASK GENMASK_ULL(23, 16) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c new file mode 100644 index 00000000000000..052ae5923e3a85 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_rep.c @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU Admin Function driver + * + * Copyright (C) 2024 Marvell. + * + */ + +#include +#include +#include +#include +#include + +#include "rvu.h" +#include "rvu_reg.h" + +#define M(_name, _id, _fn_name, _req_type, _rsp_type) \ +static struct _req_type __maybe_unused \ +*otx2_mbox_alloc_msg_ ## _fn_name(struct rvu *rvu, int devid) \ +{ \ + struct _req_type *req; \ + \ + req = (struct _req_type *)otx2_mbox_alloc_msg_rsp( \ + &rvu->afpf_wq_info.mbox_up, devid, sizeof(struct _req_type), \ + sizeof(struct _rsp_type)); \ + if (!req) \ + return NULL; \ + req->hdr.sig = OTX2_MBOX_REQ_SIG; \ + req->hdr.id = _id; \ + return req; \ +} + +MBOX_UP_REP_MESSAGES +#undef M + +static int rvu_rep_up_notify(struct rvu *rvu, struct rep_event *event) +{ + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, event->pcifunc); + struct rep_event *msg; + int pf; + + pf = rvu_get_pf(event->pcifunc); + + if (event->event & RVU_EVENT_MAC_ADDR_CHANGE) + ether_addr_copy(pfvf->mac_addr, event->evt_data.mac); + + mutex_lock(&rvu->mbox_lock); + msg = otx2_mbox_alloc_msg_rep_event_up_notify(rvu, pf); + if (!msg) { + mutex_unlock(&rvu->mbox_lock); + return -ENOMEM; + } + + msg->hdr.pcifunc = event->pcifunc; + msg->event = event->event; + + memcpy(&msg->evt_data, &event->evt_data, sizeof(struct rep_evt_data)); + + otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf); + + otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf); + + mutex_unlock(&rvu->mbox_lock); + return 0; +} + +static void rvu_rep_wq_handler(struct work_struct *work) +{ + struct rvu *rvu = container_of(work, struct rvu, rep_evt_work); + struct rep_evtq_ent *qentry; + struct rep_event *event; + unsigned long flags; + + do { + spin_lock_irqsave(&rvu->rep_evtq_lock, flags); + qentry = list_first_entry_or_null(&rvu->rep_evtq_head, + struct rep_evtq_ent, + node); + if (qentry) + list_del(&qentry->node); + + spin_unlock_irqrestore(&rvu->rep_evtq_lock, flags); + if (!qentry) + break; /* nothing more to process */ + + event = &qentry->event; + + rvu_rep_up_notify(rvu, event); + kfree(qentry); + } while (1); +} + +int rvu_mbox_handler_rep_event_notify(struct rvu *rvu, struct rep_event *req, + struct msg_rsp *rsp) +{ + struct rep_evtq_ent *qentry; + + qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC); + if (!qentry) + return -ENOMEM; + + qentry->event = *req; + spin_lock(&rvu->rep_evtq_lock); + list_add_tail(&qentry->node, &rvu->rep_evtq_head); + spin_unlock(&rvu->rep_evtq_lock); + queue_work(rvu->rep_evt_wq, &rvu->rep_evt_work); + return 0; +} + +int rvu_rep_notify_pfvf_state(struct rvu *rvu, u16 pcifunc, bool enable) +{ + struct rep_event *req; + int pf; + + if (!is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc))) + return 0; + + pf = rvu_get_pf(rvu->rep_pcifunc); + + mutex_lock(&rvu->mbox_lock); + req = otx2_mbox_alloc_msg_rep_event_up_notify(rvu, pf); + if (!req) { + mutex_unlock(&rvu->mbox_lock); + return -ENOMEM; + } + + req->hdr.pcifunc = rvu->rep_pcifunc; + req->event |= RVU_EVENT_PFVF_STATE; + req->pcifunc = pcifunc; + req->evt_data.vf_state = enable; + + otx2_mbox_wait_for_zero(&rvu->afpf_wq_info.mbox_up, pf); + otx2_mbox_msg_send_up(&rvu->afpf_wq_info.mbox_up, pf); + + mutex_unlock(&rvu->mbox_lock); + return 0; +} + +#define RVU_LF_RX_STATS(reg) \ + rvu_read64(rvu, blkaddr, NIX_AF_LFX_RX_STATX(nixlf, reg)) + +#define RVU_LF_TX_STATS(reg) \ + rvu_read64(rvu, blkaddr, NIX_AF_LFX_TX_STATX(nixlf, reg)) + +int rvu_mbox_handler_nix_lf_stats(struct rvu *rvu, + struct nix_stats_req *req, + struct nix_stats_rsp *rsp) +{ + u16 pcifunc = req->pcifunc; + int nixlf, blkaddr, err; + struct msg_req rst_req; + struct msg_rsp rst_rsp; + + err = nix_get_nixlf(rvu, pcifunc, &nixlf, &blkaddr); + if (err) + return 0; + + if (req->reset) { + rst_req.hdr.pcifunc = pcifunc; + return rvu_mbox_handler_nix_stats_rst(rvu, &rst_req, &rst_rsp); + } + rsp->rx.octs = RVU_LF_RX_STATS(RX_OCTS); + rsp->rx.ucast = RVU_LF_RX_STATS(RX_UCAST); + rsp->rx.bcast = RVU_LF_RX_STATS(RX_BCAST); + rsp->rx.mcast = RVU_LF_RX_STATS(RX_MCAST); + rsp->rx.drop = RVU_LF_RX_STATS(RX_DROP); + rsp->rx.err = RVU_LF_RX_STATS(RX_ERR); + rsp->rx.drop_octs = RVU_LF_RX_STATS(RX_DROP_OCTS); + rsp->rx.drop_mcast = RVU_LF_RX_STATS(RX_DRP_MCAST); + rsp->rx.drop_bcast = RVU_LF_RX_STATS(RX_DRP_BCAST); + + rsp->tx.octs = RVU_LF_TX_STATS(TX_OCTS); + rsp->tx.ucast = RVU_LF_TX_STATS(TX_UCAST); + rsp->tx.bcast = RVU_LF_TX_STATS(TX_BCAST); + rsp->tx.mcast = RVU_LF_TX_STATS(TX_MCAST); + rsp->tx.drop = RVU_LF_TX_STATS(TX_DROP); + + rsp->pcifunc = req->pcifunc; + return 0; +} + +static u16 rvu_rep_get_vlan_id(struct rvu *rvu, u16 pcifunc) +{ + int id; + + for (id = 0; id < rvu->rep_cnt; id++) + if (rvu->rep2pfvf_map[id] == pcifunc) + return id; + return 0; +} + +static int rvu_rep_tx_vlan_cfg(struct rvu *rvu, u16 pcifunc, + u16 vlan_tci, int *vidx) +{ + struct nix_vtag_config_rsp rsp = {}; + struct nix_vtag_config req = {}; + u64 etype = ETH_P_8021Q; + int err; + + /* Insert vlan tag */ + req.hdr.pcifunc = pcifunc; + req.vtag_size = VTAGSIZE_T4; + req.cfg_type = 0; /* tx vlan cfg */ + req.tx.cfg_vtag0 = true; + req.tx.vtag0 = FIELD_PREP(NIX_VLAN_ETYPE_MASK, etype) | vlan_tci; + + err = rvu_mbox_handler_nix_vtag_cfg(rvu, &req, &rsp); + if (err) { + dev_err(rvu->dev, "Tx vlan config failed\n"); + return err; + } + *vidx = rsp.vtag0_idx; + return 0; +} + +static int rvu_rep_rx_vlan_cfg(struct rvu *rvu, u16 pcifunc) +{ + struct nix_vtag_config req = {}; + struct nix_vtag_config_rsp rsp; + + /* config strip, capture and size */ + req.hdr.pcifunc = pcifunc; + req.vtag_size = VTAGSIZE_T4; + req.cfg_type = 1; /* rx vlan cfg */ + req.rx.vtag_type = NIX_AF_LFX_RX_VTAG_TYPE0; + req.rx.strip_vtag = true; + req.rx.capture_vtag = false; + + return rvu_mbox_handler_nix_vtag_cfg(rvu, &req, &rsp); +} + +static int rvu_rep_install_rx_rule(struct rvu *rvu, u16 pcifunc, + u16 entry, bool rte) +{ + struct npc_install_flow_req req = {}; + struct npc_install_flow_rsp rsp = {}; + struct rvu_pfvf *pfvf; + u16 vlan_tci, rep_id; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + + /* To steer the traffic from Representee to Representor */ + rep_id = rvu_rep_get_vlan_id(rvu, pcifunc); + if (rte) { + vlan_tci = rep_id | BIT_ULL(8); + req.vf = rvu->rep_pcifunc; + req.op = NIX_RX_ACTIONOP_UCAST; + req.index = rep_id; + } else { + vlan_tci = rep_id; + req.vf = pcifunc; + req.op = NIX_RX_ACTION_DEFAULT; + } + + rvu_rep_rx_vlan_cfg(rvu, req.vf); + req.entry = entry; + req.hdr.pcifunc = 0; /* AF is requester */ + req.features = BIT_ULL(NPC_OUTER_VID) | BIT_ULL(NPC_VLAN_ETYPE_CTAG); + req.vtag0_valid = true; + req.vtag0_type = NIX_AF_LFX_RX_VTAG_TYPE0; + req.packet.vlan_etype = cpu_to_be16(ETH_P_8021Q); + req.mask.vlan_etype = cpu_to_be16(ETH_P_8021Q); + req.packet.vlan_tci = cpu_to_be16(vlan_tci); + req.mask.vlan_tci = cpu_to_be16(0xffff); + + req.channel = RVU_SWITCH_LBK_CHAN; + req.chan_mask = 0xffff; + req.intf = pfvf->nix_rx_intf; + + return rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp); +} + +static int rvu_rep_install_tx_rule(struct rvu *rvu, u16 pcifunc, u16 entry, + bool rte) +{ + struct npc_install_flow_req req = {}; + struct npc_install_flow_rsp rsp = {}; + struct rvu_pfvf *pfvf; + int vidx, err; + u16 vlan_tci; + u8 lbkid; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + vlan_tci = rvu_rep_get_vlan_id(rvu, pcifunc); + if (rte) + vlan_tci |= BIT_ULL(8); + + err = rvu_rep_tx_vlan_cfg(rvu, pcifunc, vlan_tci, &vidx); + if (err) + return err; + + lbkid = pfvf->nix_blkaddr == BLKADDR_NIX0 ? 0 : 1; + req.hdr.pcifunc = 0; /* AF is requester */ + if (rte) { + req.vf = pcifunc; + } else { + req.vf = rvu->rep_pcifunc; + req.packet.sq_id = vlan_tci; + req.mask.sq_id = 0xffff; + } + + req.entry = entry; + req.intf = pfvf->nix_tx_intf; + req.op = NIX_TX_ACTIONOP_UCAST_CHAN; + req.index = (lbkid << 8) | RVU_SWITCH_LBK_CHAN; + req.set_cntr = 1; + req.vtag0_def = vidx; + req.vtag0_op = 1; + return rvu_mbox_handler_npc_install_flow(rvu, &req, &rsp); +} + +int rvu_rep_install_mcam_rules(struct rvu *rvu) +{ + struct rvu_switch *rswitch = &rvu->rswitch; + u16 start = rswitch->start_entry; + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc, entry = 0; + int pf, vf, numvfs; + int err, nixlf, i; + u8 rep; + + for (pf = 1; pf < hw->total_pfs; pf++) { + if (!is_pf_cgxmapped(rvu, pf)) + continue; + + pcifunc = pf << RVU_PFVF_PF_SHIFT; + rvu_get_nix_blkaddr(rvu, pcifunc); + rep = true; + for (i = 0; i < 2; i++) { + err = rvu_rep_install_rx_rule(rvu, pcifunc, + start + entry, rep); + if (err) + return err; + rswitch->entry2pcifunc[entry++] = pcifunc; + + err = rvu_rep_install_tx_rule(rvu, pcifunc, + start + entry, rep); + if (err) + return err; + rswitch->entry2pcifunc[entry++] = pcifunc; + rep = false; + } + + rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL); + for (vf = 0; vf < numvfs; vf++) { + pcifunc = pf << RVU_PFVF_PF_SHIFT | + ((vf + 1) & RVU_PFVF_FUNC_MASK); + rvu_get_nix_blkaddr(rvu, pcifunc); + + /* Skip installimg rules if nixlf is not attached */ + err = nix_get_nixlf(rvu, pcifunc, &nixlf, NULL); + if (err) + continue; + rep = true; + for (i = 0; i < 2; i++) { + err = rvu_rep_install_rx_rule(rvu, pcifunc, + start + entry, + rep); + if (err) + return err; + rswitch->entry2pcifunc[entry++] = pcifunc; + + err = rvu_rep_install_tx_rule(rvu, pcifunc, + start + entry, + rep); + if (err) + return err; + rswitch->entry2pcifunc[entry++] = pcifunc; + rep = false; + } + } + } + + /* Initialize the wq for handling REP events */ + spin_lock_init(&rvu->rep_evtq_lock); + INIT_LIST_HEAD(&rvu->rep_evtq_head); + INIT_WORK(&rvu->rep_evt_work, rvu_rep_wq_handler); + rvu->rep_evt_wq = alloc_workqueue("rep_evt_wq", 0, 0); + if (!rvu->rep_evt_wq) { + dev_err(rvu->dev, "REP workqueue allocation failed\n"); + return -ENOMEM; + } + return 0; +} + +void rvu_rep_update_rules(struct rvu *rvu, u16 pcifunc, bool ena) +{ + struct rvu_switch *rswitch = &rvu->rswitch; + struct npc_mcam *mcam = &rvu->hw->mcam; + u32 max = rswitch->used_entries; + int blkaddr; + u16 entry; + + if (!rswitch->used_entries) + return; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + + if (blkaddr < 0) + return; + + rvu_switch_enable_lbk_link(rvu, pcifunc, ena); + mutex_lock(&mcam->lock); + for (entry = 0; entry < max; entry++) { + if (rswitch->entry2pcifunc[entry] == pcifunc) + npc_enable_mcam_entry(rvu, mcam, blkaddr, entry, ena); + } + mutex_unlock(&mcam->lock); +} + +int rvu_rep_pf_init(struct rvu *rvu) +{ + u16 pcifunc = rvu->rep_pcifunc; + struct rvu_pfvf *pfvf; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + set_bit(NIXLF_INITIALIZED, &pfvf->flags); + rvu_switch_enable_lbk_link(rvu, pcifunc, true); + rvu_rep_rx_vlan_cfg(rvu, pcifunc); + return 0; +} + +int rvu_mbox_handler_esw_cfg(struct rvu *rvu, struct esw_cfg_req *req, + struct msg_rsp *rsp) +{ + if (req->hdr.pcifunc != rvu->rep_pcifunc) + return 0; + + rvu->rep_mode = req->ena; + + if (!rvu->rep_mode) + rvu_npc_free_mcam_entries(rvu, req->hdr.pcifunc, -1); + + return 0; +} + +int rvu_mbox_handler_get_rep_cnt(struct rvu *rvu, struct msg_req *req, + struct get_rep_cnt_rsp *rsp) +{ + int pf, vf, numvfs, hwvf, rep = 0; + u16 pcifunc; + + rvu->rep_pcifunc = req->hdr.pcifunc; + rsp->rep_cnt = rvu->cgx_mapped_pfs + rvu->cgx_mapped_vfs; + rvu->rep_cnt = rsp->rep_cnt; + + rvu->rep2pfvf_map = devm_kzalloc(rvu->dev, rvu->rep_cnt * + sizeof(u16), GFP_KERNEL); + if (!rvu->rep2pfvf_map) + return -ENOMEM; + + for (pf = 0; pf < rvu->hw->total_pfs; pf++) { + if (!is_pf_cgxmapped(rvu, pf)) + continue; + pcifunc = pf << RVU_PFVF_PF_SHIFT; + rvu->rep2pfvf_map[rep] = pcifunc; + rsp->rep_pf_map[rep] = pcifunc; + rep++; + rvu_get_pf_numvfs(rvu, pf, &numvfs, &hwvf); + for (vf = 0; vf < numvfs; vf++) { + rvu->rep2pfvf_map[rep] = pcifunc | + ((vf + 1) & RVU_PFVF_FUNC_MASK); + rsp->rep_pf_map[rep] = rvu->rep2pfvf_map[rep]; + rep++; + } + } + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index fc8da209065705..77ac94cb2ec401 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -823,4 +823,30 @@ enum nix_tx_vtag_op { #define VTAG_STRIP BIT_ULL(4) #define VTAG_CAPTURE BIT_ULL(5) +/* NIX TX stats */ +enum nix_stat_lf_tx { + TX_UCAST = 0x0, + TX_BCAST = 0x1, + TX_MCAST = 0x2, + TX_DROP = 0x3, + TX_OCTS = 0x4, + TX_STATS_ENUM_LAST, +}; + +/* NIX RX stats */ +enum nix_stat_lf_rx { + RX_OCTS = 0x0, + RX_UCAST = 0x1, + RX_BCAST = 0x2, + RX_MCAST = 0x3, + RX_DROP = 0x4, + RX_DROP_OCTS = 0x5, + RX_FCS = 0x6, + RX_ERR = 0x7, + RX_DRP_BCAST = 0x8, + RX_DRP_MCAST = 0x9, + RX_DRP_L3BCAST = 0xa, + RX_DRP_L3MCAST = 0xb, + RX_STATS_ENUM_LAST, +}; #endif /* RVU_STRUCT_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c index 854045ed3b0682..268efb7c1c15d2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c @@ -8,7 +8,7 @@ #include #include "rvu.h" -static void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool enable) +void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool enable) { struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); struct nix_hw *nix_hw; @@ -166,6 +166,8 @@ void rvu_switch_enable(struct rvu *rvu) alloc_req.contig = true; alloc_req.count = rvu->cgx_mapped_pfs + rvu->cgx_mapped_vfs; + if (rvu->rep_mode) + alloc_req.count = alloc_req.count * 4; ret = rvu_mbox_handler_npc_mcam_alloc_entry(rvu, &alloc_req, &alloc_rsp); if (ret) { @@ -189,7 +191,12 @@ void rvu_switch_enable(struct rvu *rvu) rswitch->used_entries = alloc_rsp.count; rswitch->start_entry = alloc_rsp.entry; - ret = rvu_switch_install_rules(rvu); + if (rvu->rep_mode) { + rvu_rep_pf_init(rvu); + ret = rvu_rep_install_mcam_rules(rvu); + } else { + ret = rvu_switch_install_rules(rvu); + } if (ret) goto uninstall_rules; @@ -222,6 +229,9 @@ void rvu_switch_disable(struct rvu *rvu) if (!rswitch->used_entries) return; + if (rvu->rep_mode) + goto free_ents; + for (pf = 1; pf < hw->total_pfs; pf++) { if (!is_pf_cgxmapped(rvu, pf)) continue; @@ -249,6 +259,7 @@ void rvu_switch_disable(struct rvu *rvu) } } +free_ents: uninstall_req.start = rswitch->start_entry; uninstall_req.end = rswitch->start_entry + rswitch->used_entries - 1; free_req.all = 1; @@ -258,12 +269,15 @@ void rvu_switch_disable(struct rvu *rvu) kfree(rswitch->entry2pcifunc); } -void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc) +void rvu_switch_update_rules(struct rvu *rvu, u16 pcifunc, bool ena) { struct rvu_switch *rswitch = &rvu->rswitch; u32 max = rswitch->used_entries; u16 entry; + if (rvu->rep_mode) + return rvu_rep_update_rules(rvu, pcifunc, ena); + if (!rswitch->used_entries) return; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile index 64a97a0a10ed6a..dbc97126686585 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile @@ -5,11 +5,13 @@ obj-$(CONFIG_OCTEONTX2_PF) += rvu_nicpf.o otx2_ptp.o obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o otx2_ptp.o +obj-$(CONFIG_RVU_ESWITCH) += rvu_rep.o rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \ otx2_flows.o otx2_tc.o cn10k.o otx2_dmac_flt.o \ otx2_devlink.o qos_sq.o qos.o rvu_nicvf-y := otx2_vf.o +rvu_rep-y := rep.o rvu_nicpf-$(CONFIG_DCB) += otx2_dcbnl.o rvu_nicpf-$(CONFIG_MACSEC) += cn10k_macsec.o diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c index c1c99d7054f87f..a15cc86635d66c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c @@ -72,7 +72,7 @@ int cn10k_lmtst_init(struct otx2_nic *pfvf) } EXPORT_SYMBOL(cn10k_lmtst_init); -int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) +int cn10k_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura) { struct nix_cn10k_aq_enq_req *aq; struct otx2_nic *pfvf = dev; @@ -88,7 +88,7 @@ int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) aq->sq.ena = 1; aq->sq.smq = otx2_get_smq_idx(pfvf, qidx); aq->sq.smq_rr_weight = mtu_to_dwrr_weight(pfvf, pfvf->tx_max_pktlen); - aq->sq.default_chan = pfvf->hw.tx_chan_base; + aq->sq.default_chan = pfvf->hw.tx_chan_base + chan_offset; aq->sq.sqe_stype = NIX_STYPE_STF; /* Cache SQB */ aq->sq.sqb_aura = sqb_aura; aq->sq.sq_int_ena = NIX_SQINT_BITS; @@ -203,6 +203,11 @@ int cn10k_alloc_leaf_profile(struct otx2_nic *pfvf, u16 *leaf) rsp = (struct nix_bandprof_alloc_rsp *) otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + rc = PTR_ERR(rsp); + goto out; + } + if (!rsp->prof_count[BAND_PROF_LEAF_LAYER]) { rc = -EIO; goto out; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h index c1861f7de25450..e3f0bce9908fb1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h @@ -26,7 +26,7 @@ static inline int mtu_to_dwrr_weight(struct otx2_nic *pfvf, int mtu) int cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx); -int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); +int cn10k_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura); int cn10k_lmtst_init(struct otx2_nic *pfvf); int cn10k_free_all_ipolicers(struct otx2_nic *pfvf); int cn10k_alloc_matchall_ipolicer(struct otx2_nic *pfvf); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index 87d5776e3b88e9..523ecb798a7a25 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -83,6 +83,7 @@ int otx2_update_rq_stats(struct otx2_nic *pfvf, int qidx) otx2_nix_rq_op_stats(&rq->stats, pfvf, qidx); return 1; } +EXPORT_SYMBOL(otx2_update_rq_stats); int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx) { @@ -99,6 +100,7 @@ int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx) otx2_nix_sq_op_stats(&sq->stats, pfvf, qidx); return 1; } +EXPORT_SYMBOL(otx2_update_sq_stats); void otx2_get_dev_stats(struct otx2_nic *pfvf) { @@ -227,7 +229,7 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu) u16 maxlen; int err; - maxlen = otx2_get_max_mtu(pfvf) + OTX2_ETH_HLEN + OTX2_HW_TIMESTAMP_LEN; + maxlen = pfvf->hw.max_mtu + OTX2_ETH_HLEN + OTX2_HW_TIMESTAMP_LEN; mutex_lock(&pfvf->mbox.lock); req = otx2_mbox_alloc_msg_nix_set_hw_frs(&pfvf->mbox); @@ -236,7 +238,7 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu) return -ENOMEM; } - req->maxlen = pfvf->netdev->mtu + OTX2_ETH_HLEN + OTX2_HW_TIMESTAMP_LEN; + req->maxlen = mtu + OTX2_ETH_HLEN + OTX2_HW_TIMESTAMP_LEN; /* Use max receive length supported by hardware for loopback devices */ if (is_otx2_lbkvf(pfvf->pdev)) @@ -246,13 +248,14 @@ int otx2_hw_set_mtu(struct otx2_nic *pfvf, int mtu) mutex_unlock(&pfvf->mbox.lock); return err; } +EXPORT_SYMBOL(otx2_hw_set_mtu); int otx2_config_pause_frm(struct otx2_nic *pfvf) { struct cgx_pause_frm_cfg *req; int err; - if (is_otx2_lbkvf(pfvf->pdev)) + if (is_otx2_lbkvf(pfvf->pdev) || is_otx2_sdp_rep(pfvf->pdev)) return 0; mutex_lock(&pfvf->mbox.lock); @@ -646,12 +649,22 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for req->reg[2] = NIX_AF_MDQX_SCHEDULE(schq); req->regval[2] = dwrr_val; } else if (lvl == NIX_TXSCH_LVL_TL4) { + int sdp_chan = hw->tx_chan_base + prio; + + if (is_otx2_sdp_rep(pfvf->pdev)) + prio = 0; parent = schq_list[NIX_TXSCH_LVL_TL3][prio]; req->reg[0] = NIX_AF_TL4X_PARENT(schq); req->regval[0] = (u64)parent << 16; req->num_regs++; req->reg[1] = NIX_AF_TL4X_SCHEDULE(schq); req->regval[1] = dwrr_val; + if (is_otx2_sdp_rep(pfvf->pdev)) { + req->num_regs++; + req->reg[2] = NIX_AF_TL4X_SDP_LINK_CFG(schq); + req->regval[2] = BIT_ULL(12) | BIT_ULL(13) | + (sdp_chan & 0xff); + } } else if (lvl == NIX_TXSCH_LVL_TL3) { parent = schq_list[NIX_TXSCH_LVL_TL2][prio]; req->reg[0] = NIX_AF_TL3X_PARENT(schq); @@ -659,7 +672,8 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for req->num_regs++; req->reg[1] = NIX_AF_TL3X_SCHEDULE(schq); req->regval[1] = dwrr_val; - if (lvl == hw->txschq_link_cfg_lvl) { + if (lvl == hw->txschq_link_cfg_lvl && + !is_otx2_sdp_rep(pfvf->pdev)) { req->num_regs++; req->reg[2] = NIX_AF_TL3_TL2X_LINKX_CFG(schq, hw->tx_link); /* Enable this queue and backpressure @@ -676,7 +690,8 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for req->reg[1] = NIX_AF_TL2X_SCHEDULE(schq); req->regval[1] = (u64)hw->txschq_aggr_lvl_rr_prio << 24 | dwrr_val; - if (lvl == hw->txschq_link_cfg_lvl) { + if (lvl == hw->txschq_link_cfg_lvl && + !is_otx2_sdp_rep(pfvf->pdev)) { req->num_regs++; req->reg[2] = NIX_AF_TL3_TL2X_LINKX_CFG(schq, hw->tx_link); /* Enable this queue and backpressure @@ -735,6 +750,7 @@ EXPORT_SYMBOL(otx2_smq_flush); int otx2_txsch_alloc(struct otx2_nic *pfvf) { + int chan_cnt = pfvf->hw.tx_chan_cnt; struct nix_txsch_alloc_req *req; struct nix_txsch_alloc_rsp *rsp; int lvl, schq, rc; @@ -747,6 +763,12 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf) /* Request one schq per level */ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) req->schq[lvl] = 1; + + if (is_otx2_sdp_rep(pfvf->pdev) && chan_cnt > 1) { + req->schq[NIX_TXSCH_LVL_SMQ] = chan_cnt; + req->schq[NIX_TXSCH_LVL_TL4] = chan_cnt; + } + rc = otx2_sync_mbox_msg(&pfvf->mbox); if (rc) return rc; @@ -757,10 +779,12 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf) return PTR_ERR(rsp); /* Setup transmit scheduler list */ - for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + pfvf->hw.txschq_cnt[lvl] = rsp->schq[lvl]; for (schq = 0; schq < rsp->schq[lvl]; schq++) pfvf->hw.txschq_list[lvl][schq] = rsp->schq_list[lvl][schq]; + } pfvf->hw.txschq_link_cfg_lvl = rsp->link_cfg_lvl; pfvf->hw.txschq_aggr_lvl_rr_prio = rsp->aggr_lvl_rr_prio; @@ -798,12 +822,15 @@ EXPORT_SYMBOL(otx2_txschq_free_one); void otx2_txschq_stop(struct otx2_nic *pfvf) { - int lvl, schq; + int lvl, schq, idx; /* free non QOS TLx nodes */ - for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) - otx2_txschq_free_one(pfvf, lvl, - pfvf->hw.txschq_list[lvl][0]); + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + for (idx = 0; idx < pfvf->hw.txschq_cnt[lvl]; idx++) { + otx2_txschq_free_one(pfvf, lvl, + pfvf->hw.txschq_list[lvl][idx]); + } + } /* Clear the txschq list */ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { @@ -883,7 +910,7 @@ static int otx2_rq_init(struct otx2_nic *pfvf, u16 qidx, u16 lpb_aura) return otx2_sync_mbox_msg(&pfvf->mbox); } -int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) +int otx2_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura) { struct otx2_nic *pfvf = dev; struct otx2_snd_queue *sq; @@ -902,7 +929,7 @@ int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) aq->sq.ena = 1; aq->sq.smq = otx2_get_smq_idx(pfvf, qidx); aq->sq.smq_rr_quantum = mtu_to_dwrr_weight(pfvf, pfvf->tx_max_pktlen); - aq->sq.default_chan = pfvf->hw.tx_chan_base; + aq->sq.default_chan = pfvf->hw.tx_chan_base + chan_offset; aq->sq.sqe_stype = NIX_STYPE_STF; /* Cache SQB */ aq->sq.sqb_aura = sqb_aura; aq->sq.sq_int_ena = NIX_SQINT_BITS; @@ -925,6 +952,7 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura) struct otx2_qset *qset = &pfvf->qset; struct otx2_snd_queue *sq; struct otx2_pool *pool; + u8 chan_offset; int err; pool = &pfvf->qset.pool[sqb_aura]; @@ -971,7 +999,8 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura) sq->stats.bytes = 0; sq->stats.pkts = 0; - err = pfvf->hw_ops->sq_aq_init(pfvf, qidx, sqb_aura); + chan_offset = qidx % pfvf->hw.tx_chan_cnt; + err = pfvf->hw_ops->sq_aq_init(pfvf, qidx, chan_offset, sqb_aura); if (err) { kfree(sq->sg); sq->sg = NULL; @@ -1738,6 +1767,8 @@ void mbox_handler_nix_lf_alloc(struct otx2_nic *pfvf, pfvf->hw.sqb_size = rsp->sqb_size; pfvf->hw.rx_chan_base = rsp->rx_chan_base; pfvf->hw.tx_chan_base = rsp->tx_chan_base; + pfvf->hw.rx_chan_cnt = rsp->rx_chan_cnt; + pfvf->hw.tx_chan_cnt = rsp->tx_chan_cnt; pfvf->hw.lso_tsov4_idx = rsp->lso_tsov4_idx; pfvf->hw.lso_tsov6_idx = rsp->lso_tsov6_idx; pfvf->hw.cgx_links = rsp->cgx_links; @@ -1782,6 +1813,7 @@ void otx2_free_cints(struct otx2_nic *pfvf, int n) free_irq(vector, &qset->napi[qidx]); } } +EXPORT_SYMBOL(otx2_free_cints); void otx2_set_cints_affinity(struct otx2_nic *pfvf) { @@ -1837,6 +1869,10 @@ u16 otx2_get_max_mtu(struct otx2_nic *pfvf) if (!rc) { rsp = (struct nix_hw_info *) otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + rc = PTR_ERR(rsp); + goto out; + } /* HW counts VLAN insertion bytes (8 for double tag) * irrespective of whether SQE is requesting to insert VLAN diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index f27a3456ae64fe..566848663fea77 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -29,6 +29,7 @@ #include "otx2_devlink.h" #include #include "qos.h" +#include "rep.h" /* IPv4 flag more fragment bit */ #define IPV4_FLAG_MORE 0x20 @@ -41,6 +42,8 @@ #define PCI_SUBSYS_DEVID_96XX_RVU_PFVF 0xB200 #define PCI_SUBSYS_DEVID_CN10K_B_RVU_PFVF 0xBD00 +#define PCI_DEVID_OCTEONTX2_SDP_REP 0xA0F7 + /* PCI BAR nos */ #define PCI_CFG_REG_BAR_NUM 2 #define PCI_MBOX_BAR_NUM 4 @@ -120,33 +123,6 @@ enum otx2_errcodes_re { ERRCODE_IL4_CSUM = 0x22, }; -/* NIX TX stats */ -enum nix_stat_lf_tx { - TX_UCAST = 0x0, - TX_BCAST = 0x1, - TX_MCAST = 0x2, - TX_DROP = 0x3, - TX_OCTS = 0x4, - TX_STATS_ENUM_LAST, -}; - -/* NIX RX stats */ -enum nix_stat_lf_rx { - RX_OCTS = 0x0, - RX_UCAST = 0x1, - RX_BCAST = 0x2, - RX_MCAST = 0x3, - RX_DROP = 0x4, - RX_DROP_OCTS = 0x5, - RX_FCS = 0x6, - RX_ERR = 0x7, - RX_DRP_BCAST = 0x8, - RX_DRP_MCAST = 0x9, - RX_DRP_L3BCAST = 0xa, - RX_DRP_L3MCAST = 0xb, - RX_STATS_ENUM_LAST, -}; - struct otx2_dev_stats { u64 rx_bytes; u64 rx_frames; @@ -224,15 +200,19 @@ struct otx2_hw { /* NIX */ u8 txschq_link_cfg_lvl; + u8 txschq_cnt[NIX_TXSCH_LVL_CNT]; u8 txschq_aggr_lvl_rr_prio; u16 txschq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC]; u16 matchall_ipolicer; u32 dwrr_mtu; + u32 max_mtu; u8 smq_link_type; /* HW settings, coalescing etc */ u16 rx_chan_base; u16 tx_chan_base; + u8 rx_chan_cnt; + u8 tx_chan_cnt; u16 cq_qcount_wait; u16 cq_ecount_wait; u16 rq_skid; @@ -367,7 +347,8 @@ struct otx2_flow_config { }; struct dev_hw_ops { - int (*sq_aq_init)(void *dev, u16 qidx, u16 sqb_aura); + int (*sq_aq_init)(void *dev, u16 qidx, u8 chan_offset, + u16 sqb_aura); void (*sqe_flush)(void *dev, struct otx2_snd_queue *sq, int size, int qidx); int (*refill_pool_ptrs)(void *dev, struct otx2_cq_queue *cq); @@ -465,6 +446,8 @@ struct otx2_nic { #define OTX2_FLAG_PTP_ONESTEP_SYNC BIT_ULL(15) #define OTX2_FLAG_ADPTV_INT_COAL_ENABLED BIT_ULL(16) #define OTX2_FLAG_TC_MARK_ENABLED BIT_ULL(17) +#define OTX2_FLAG_REP_MODE_ENABLED BIT_ULL(18) +#define OTX2_FLAG_PORT_UP BIT_ULL(19) u64 flags; u64 *cq_op_addr; @@ -532,11 +515,19 @@ struct otx2_nic { #if IS_ENABLED(CONFIG_MACSEC) struct cn10k_mcs_cfg *macsec_cfg; #endif + +#if IS_ENABLED(CONFIG_RVU_ESWITCH) + struct rep_dev **reps; + int rep_cnt; + u16 rep_pf_map[RVU_MAX_REP]; + u16 esw_mode; +#endif }; static inline bool is_otx2_lbkvf(struct pci_dev *pdev) { - return pdev->device == PCI_DEVID_OCTEONTX2_RVU_AFVF; + return (pdev->device == PCI_DEVID_OCTEONTX2_RVU_AFVF) || + (pdev->device == PCI_DEVID_RVU_REP); } static inline bool is_96xx_A0(struct pci_dev *pdev) @@ -551,6 +542,11 @@ static inline bool is_96xx_B0(struct pci_dev *pdev) (pdev->subsystem_device == PCI_SUBSYS_DEVID_96XX_RVU_PFVF); } +static inline bool is_otx2_sdp_rep(struct pci_dev *pdev) +{ + return pdev->device == PCI_DEVID_OCTEONTX2_SDP_REP; +} + /* REVID for PCIe devices. * Bits 0..1: minor pass, bit 3..2: major pass * bits 7..4: midr id @@ -913,15 +909,19 @@ static inline void otx2_dma_unmap_page(struct otx2_nic *pfvf, static inline u16 otx2_get_smq_idx(struct otx2_nic *pfvf, u16 qidx) { u16 smq; + int idx; + #ifdef CONFIG_DCB if (qidx < NIX_PF_PFC_PRIO_MAX && pfvf->pfc_alloc_status[qidx]) return pfvf->pfc_schq_list[NIX_TXSCH_LVL_SMQ][qidx]; #endif /* check if qidx falls under QOS queues */ - if (qidx >= pfvf->hw.non_qos_queues) + if (qidx >= pfvf->hw.non_qos_queues) { smq = pfvf->qos.qid_to_sqmap[qidx - pfvf->hw.non_qos_queues]; - else - smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][0]; + } else { + idx = qidx % pfvf->hw.txschq_cnt[NIX_TXSCH_LVL_SMQ]; + smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][idx]; + } return smq; } @@ -988,14 +988,28 @@ int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable); void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, int qidx); void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq); int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura); -int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); -int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); +int otx2_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura); +int cn10k_sq_aq_init(void *dev, u16 qidx, u8 chan_offset, u16 sqb_aura); int otx2_alloc_buffer(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, dma_addr_t *dma); int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, int stack_pages, int numptrs, int buf_size, int type); int otx2_aura_init(struct otx2_nic *pfvf, int aura_id, int pool_id, int numptrs); +int otx2_init_rsrc(struct pci_dev *pdev, struct otx2_nic *pf); +void otx2_free_queue_mem(struct otx2_qset *qset); +int otx2_alloc_queue_mem(struct otx2_nic *pf); +int otx2_init_hw_resources(struct otx2_nic *pfvf); +void otx2_free_hw_resources(struct otx2_nic *pf); +int otx2_wq_init(struct otx2_nic *pf); +int otx2_check_pf_usable(struct otx2_nic *pf); +int otx2_pfaf_mbox_init(struct otx2_nic *pf); +int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af); +int otx2_realloc_msix_vectors(struct otx2_nic *pf); +void otx2_pfaf_mbox_destroy(struct otx2_nic *pf); +void otx2_disable_mbox_intr(struct otx2_nic *pf); +void otx2_disable_napi(struct otx2_nic *pf); +irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq); /* RSS configuration APIs*/ int otx2_rss_init(struct otx2_nic *pfvf); @@ -1127,4 +1141,12 @@ u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb, int otx2_get_txq_by_classid(struct otx2_nic *pfvf, u16 classid); void otx2_qos_config_txschq(struct otx2_nic *pfvf); void otx2_clean_qos_queues(struct otx2_nic *pfvf); +int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info); +int otx2_setup_tc_cls_flower(struct otx2_nic *nic, + struct flow_cls_offload *cls_flower); + +static inline int mcam_entry_cmp(const void *a, const void *b) +{ + return *(u16 *)a - *(u16 *)b; +} #endif /* OTX2_COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c index aa01110f04a339..294fba58b67095 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dcbnl.c @@ -315,6 +315,11 @@ int otx2_config_priority_flow_ctrl(struct otx2_nic *pfvf) if (!otx2_sync_mbox_msg(&pfvf->mbox)) { rsp = (struct cgx_pfc_rsp *) otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + err = PTR_ERR(rsp); + goto unlock; + } + if (req->rx_pause != rsp->rx_pause || req->tx_pause != rsp->tx_pause) { dev_warn(pfvf->dev, "Failed to config PFC\n"); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c index 53f14aa944bdba..33ec9a7f7c0339 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_devlink.c @@ -141,7 +141,56 @@ static const struct devlink_param otx2_dl_params[] = { otx2_dl_ucast_flt_cnt_validate), }; +#ifdef CONFIG_RVU_ESWITCH +static int otx2_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode) +{ + struct otx2_devlink *otx2_dl = devlink_priv(devlink); + struct otx2_nic *pfvf = otx2_dl->pfvf; + + if (!otx2_rep_dev(pfvf->pdev)) + return -EOPNOTSUPP; + + *mode = pfvf->esw_mode; + + return 0; +} + +static int otx2_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, + struct netlink_ext_ack *extack) +{ + struct otx2_devlink *otx2_dl = devlink_priv(devlink); + struct otx2_nic *pfvf = otx2_dl->pfvf; + int ret = 0; + + if (!otx2_rep_dev(pfvf->pdev)) + return -EOPNOTSUPP; + + if (pfvf->esw_mode == mode) + return 0; + + switch (mode) { + case DEVLINK_ESWITCH_MODE_LEGACY: + rvu_rep_destroy(pfvf); + break; + case DEVLINK_ESWITCH_MODE_SWITCHDEV: + ret = rvu_rep_create(pfvf, extack); + break; + default: + return -EINVAL; + } + + if (!ret) + pfvf->esw_mode = mode; + + return ret; +} +#endif + static const struct devlink_ops otx2_devlink_ops = { +#ifdef CONFIG_RVU_ESWITCH + .eswitch_mode_get = otx2_devlink_eswitch_mode_get, + .eswitch_mode_set = otx2_devlink_eswitch_mode_set, +#endif }; int otx2_register_dl(struct otx2_nic *pfvf) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c index 80d853b343f98f..2046dd0da00d85 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_dmac_flt.c @@ -28,6 +28,11 @@ static int otx2_dmacflt_do_add(struct otx2_nic *pf, const u8 *mac, if (!err) { rsp = (struct cgx_mac_addr_add_rsp *) otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + mutex_unlock(&pf->mbox.lock); + return PTR_ERR(rsp); + } + *dmac_index = rsp->index; } @@ -200,6 +205,10 @@ int otx2_dmacflt_update(struct otx2_nic *pf, u8 *mac, u32 bit_pos) rsp = (struct cgx_mac_addr_update_rsp *) otx2_mbox_get_rsp(&pf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + rc = PTR_ERR(rsp); + goto out; + } pf->flow_cfg->bmap_to_dmacindex[bit_pos] = rsp->index; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c index 32468c663605ef..2d53dc77ef1eff 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c @@ -85,26 +85,22 @@ static void otx2_get_qset_strings(struct otx2_nic *pfvf, u8 **data, int qset) int start_qidx = qset * pfvf->hw.rx_queues; int qidx, stats; - for (qidx = 0; qidx < pfvf->hw.rx_queues; qidx++) { - for (stats = 0; stats < otx2_n_queue_stats; stats++) { - sprintf(*data, "rxq%d: %s", qidx + start_qidx, - otx2_queue_stats[stats].name); - *data += ETH_GSTRING_LEN; - } - } + for (qidx = 0; qidx < pfvf->hw.rx_queues; qidx++) + for (stats = 0; stats < otx2_n_queue_stats; stats++) + ethtool_sprintf(data, "rxq%d: %s", qidx + start_qidx, + otx2_queue_stats[stats].name); - for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) { - for (stats = 0; stats < otx2_n_queue_stats; stats++) { + for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) + for (stats = 0; stats < otx2_n_queue_stats; stats++) if (qidx >= pfvf->hw.non_qos_queues) - sprintf(*data, "txq_qos%d: %s", - qidx + start_qidx - pfvf->hw.non_qos_queues, - otx2_queue_stats[stats].name); + ethtool_sprintf(data, "txq_qos%d: %s", + qidx + start_qidx - + pfvf->hw.non_qos_queues, + otx2_queue_stats[stats].name); else - sprintf(*data, "txq%d: %s", qidx + start_qidx, - otx2_queue_stats[stats].name); - *data += ETH_GSTRING_LEN; - } - } + ethtool_sprintf(data, "txq%d: %s", + qidx + start_qidx, + otx2_queue_stats[stats].name); } static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data) @@ -115,36 +111,25 @@ static void otx2_get_strings(struct net_device *netdev, u32 sset, u8 *data) if (sset != ETH_SS_STATS) return; - for (stats = 0; stats < otx2_n_dev_stats; stats++) { - memcpy(data, otx2_dev_stats[stats].name, ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (stats = 0; stats < otx2_n_dev_stats; stats++) + ethtool_puts(&data, otx2_dev_stats[stats].name); - for (stats = 0; stats < otx2_n_drv_stats; stats++) { - memcpy(data, otx2_drv_stats[stats].name, ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (stats = 0; stats < otx2_n_drv_stats; stats++) + ethtool_puts(&data, otx2_drv_stats[stats].name); otx2_get_qset_strings(pfvf, &data, 0); if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) { - for (stats = 0; stats < CGX_RX_STATS_COUNT; stats++) { - sprintf(data, "cgx_rxstat%d: ", stats); - data += ETH_GSTRING_LEN; - } + for (stats = 0; stats < CGX_RX_STATS_COUNT; stats++) + ethtool_sprintf(&data, "cgx_rxstat%d: ", stats); - for (stats = 0; stats < CGX_TX_STATS_COUNT; stats++) { - sprintf(data, "cgx_txstat%d: ", stats); - data += ETH_GSTRING_LEN; - } + for (stats = 0; stats < CGX_TX_STATS_COUNT; stats++) + ethtool_sprintf(&data, "cgx_txstat%d: ", stats); } - strcpy(data, "reset_count"); - data += ETH_GSTRING_LEN; - sprintf(data, "Fec Corrected Errors: "); - data += ETH_GSTRING_LEN; - sprintf(data, "Fec Uncorrected Errors: "); - data += ETH_GSTRING_LEN; + ethtool_puts(&data, "reset_count"); + ethtool_puts(&data, "Fec Corrected Errors: "); + ethtool_puts(&data, "Fec Uncorrected Errors: "); } static void otx2_get_qset_stats(struct otx2_nic *pfvf, @@ -343,6 +328,11 @@ static void otx2_get_pauseparam(struct net_device *netdev, if (!otx2_sync_mbox_msg(&pfvf->mbox)) { rsp = (struct cgx_pause_frm_cfg *) otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + mutex_unlock(&pfvf->mbox.lock); + return; + } + pause->rx_pause = rsp->rx_pause; pause->tx_pause = rsp->tx_pause; } @@ -1072,6 +1062,11 @@ static int otx2_set_fecparam(struct net_device *netdev, rsp = (struct fec_mode *)otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + err = PTR_ERR(rsp); + goto end; + } + if (rsp->fec >= 0) pfvf->linfo.fec = rsp->fec; else @@ -1365,20 +1360,15 @@ static void otx2vf_get_strings(struct net_device *netdev, u32 sset, u8 *data) if (sset != ETH_SS_STATS) return; - for (stats = 0; stats < otx2_n_dev_stats; stats++) { - memcpy(data, otx2_dev_stats[stats].name, ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (stats = 0; stats < otx2_n_dev_stats; stats++) + ethtool_puts(&data, otx2_dev_stats[stats].name); - for (stats = 0; stats < otx2_n_drv_stats; stats++) { - memcpy(data, otx2_drv_stats[stats].name, ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (stats = 0; stats < otx2_n_drv_stats; stats++) + ethtool_puts(&data, otx2_drv_stats[stats].name); otx2_get_qset_strings(vf, &data, 0); - strcpy(data, "reset_count"); - data += ETH_GSTRING_LEN; + ethtool_puts(&data, "reset_count"); } static void otx2vf_get_ethtool_stats(struct net_device *netdev, diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c index 98c31a16c70b4f..47bfd1fb37d4bc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c @@ -64,11 +64,6 @@ static int otx2_free_ntuple_mcam_entries(struct otx2_nic *pfvf) return 0; } -static int mcam_entry_cmp(const void *a, const void *b) -{ - return *(u16 *)a - *(u16 *)b; -} - int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count) { struct otx2_flow_config *flow_cfg = pfvf->flow_cfg; @@ -119,6 +114,8 @@ int otx2_alloc_mcam_entries(struct otx2_nic *pfvf, u16 count) rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp (&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) + goto exit; for (ent = 0; ent < rsp->count; ent++) flow_cfg->flow_ent[ent + allocated] = rsp->entry_list[ent]; @@ -197,6 +194,10 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf) rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp (&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) { + mutex_unlock(&pfvf->mbox.lock); + return PTR_ERR(rsp); + } if (rsp->count != req->count) { netdev_info(pfvf->netdev, @@ -232,6 +233,10 @@ int otx2_mcam_entry_init(struct otx2_nic *pfvf) frsp = (struct npc_get_field_status_rsp *)otx2_mbox_get_rsp (&pfvf->mbox.mbox, 0, &freq->hdr); + if (IS_ERR(frsp)) { + mutex_unlock(&pfvf->mbox.lock); + return PTR_ERR(frsp); + } if (frsp->enable) { pfvf->flags |= OTX2_FLAG_RX_VLAN_SUPPORT; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index 5492dea547a190..e310f99b173661 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -519,6 +519,7 @@ static void otx2_pfvf_mbox_up_handler(struct work_struct *work) switch (msg->id) { case MBOX_MSG_CGX_LINK_EVENT: + case MBOX_MSG_REP_EVENT_UP_NOTIFY: break; default: if (msg->rc) @@ -832,6 +833,9 @@ static void otx2_handle_link_event(struct otx2_nic *pf) struct cgx_link_user_info *linfo = &pf->linfo; struct net_device *netdev = pf->netdev; + if (pf->flags & OTX2_FLAG_PORT_UP) + return; + pr_info("%s NIC Link is %s %d Mbps %s duplex\n", netdev->name, linfo->link_up ? "UP" : "DOWN", linfo->speed, linfo->full_duplex ? "Full" : "Half"); @@ -844,6 +848,35 @@ static void otx2_handle_link_event(struct otx2_nic *pf) } } +static int otx2_mbox_up_handler_rep_event_up_notify(struct otx2_nic *pf, + struct rep_event *info, + struct msg_rsp *rsp) +{ + struct net_device *netdev = pf->netdev; + + if (info->event == RVU_EVENT_MTU_CHANGE) { + netdev->mtu = info->evt_data.mtu; + return 0; + } + + if (info->event == RVU_EVENT_PORT_STATE) { + if (info->evt_data.port_state) { + pf->flags |= OTX2_FLAG_PORT_UP; + netif_carrier_on(netdev); + netif_tx_start_all_queues(netdev); + } else { + pf->flags &= ~OTX2_FLAG_PORT_UP; + netif_tx_stop_all_queues(netdev); + netif_carrier_off(netdev); + } + return 0; + } +#ifdef CONFIG_RVU_ESWITCH + rvu_event_up_notify(pf, info); +#endif + return 0; +} + int otx2_mbox_up_handler_mcs_intr_notify(struct otx2_nic *pf, struct mcs_intr_info *event, struct msg_rsp *rsp) @@ -913,6 +946,7 @@ static int otx2_process_mbox_msg_up(struct otx2_nic *pf, } MBOX_UP_CGX_MESSAGES MBOX_UP_MCS_MESSAGES +MBOX_UP_REP_MESSAGES #undef M break; default: @@ -1008,7 +1042,7 @@ static irqreturn_t otx2_pfaf_mbox_intr_handler(int irq, void *pf_irq) return IRQ_HANDLED; } -static void otx2_disable_mbox_intr(struct otx2_nic *pf) +void otx2_disable_mbox_intr(struct otx2_nic *pf) { int vector = pci_irq_vector(pf->pdev, RVU_PF_INT_VEC_AFPF_MBOX); @@ -1016,8 +1050,9 @@ static void otx2_disable_mbox_intr(struct otx2_nic *pf) otx2_write64(pf, RVU_PF_INT_ENA_W1C, BIT_ULL(0)); free_irq(vector, pf); } +EXPORT_SYMBOL(otx2_disable_mbox_intr); -static int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af) +int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af) { struct otx2_hw *hw = &pf->hw; struct msg_req *req; @@ -1061,7 +1096,7 @@ static int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af) return 0; } -static void otx2_pfaf_mbox_destroy(struct otx2_nic *pf) +void otx2_pfaf_mbox_destroy(struct otx2_nic *pf) { struct mbox *mbox = &pf->mbox; @@ -1076,8 +1111,9 @@ static void otx2_pfaf_mbox_destroy(struct otx2_nic *pf) otx2_mbox_destroy(&mbox->mbox); otx2_mbox_destroy(&mbox->mbox_up); } +EXPORT_SYMBOL(otx2_pfaf_mbox_destroy); -static int otx2_pfaf_mbox_init(struct otx2_nic *pf) +int otx2_pfaf_mbox_init(struct otx2_nic *pf) { struct mbox *mbox = &pf->mbox; void __iomem *hwbase; @@ -1379,7 +1415,7 @@ static irqreturn_t otx2_q_intr_handler(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq) +irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq) { struct otx2_cq_poll *cq_poll = (struct otx2_cq_poll *)cq_irq; struct otx2_nic *pf = (struct otx2_nic *)cq_poll->dev; @@ -1398,20 +1434,25 @@ static irqreturn_t otx2_cq_intr_handler(int irq, void *cq_irq) return IRQ_HANDLED; } +EXPORT_SYMBOL(otx2_cq_intr_handler); -static void otx2_disable_napi(struct otx2_nic *pf) +void otx2_disable_napi(struct otx2_nic *pf) { struct otx2_qset *qset = &pf->qset; struct otx2_cq_poll *cq_poll; + struct work_struct *work; int qidx; for (qidx = 0; qidx < pf->hw.cint_cnt; qidx++) { cq_poll = &qset->napi[qidx]; - cancel_work_sync(&cq_poll->dim.work); + work = &cq_poll->dim.work; + if (work->func) + cancel_work_sync(work); napi_disable(&cq_poll->napi); netif_napi_del(&cq_poll->napi); } } +EXPORT_SYMBOL(otx2_disable_napi); static void otx2_free_cq_res(struct otx2_nic *pf) { @@ -1477,7 +1518,7 @@ static int otx2_get_rbuf_size(struct otx2_nic *pf, int mtu) return ALIGN(rbuf_size, 2048); } -static int otx2_init_hw_resources(struct otx2_nic *pf) +int otx2_init_hw_resources(struct otx2_nic *pf) { struct nix_lf_free_req *free_req; struct mbox *mbox = &pf->mbox; @@ -1493,10 +1534,11 @@ static int otx2_init_hw_resources(struct otx2_nic *pf) hw->sqpool_cnt = otx2_get_total_tx_queues(pf); hw->pool_cnt = hw->rqpool_cnt + hw->sqpool_cnt; - /* Maximum hardware supported transmit length */ - pf->tx_max_pktlen = pf->netdev->max_mtu + OTX2_ETH_HLEN; - - pf->rbsize = otx2_get_rbuf_size(pf, pf->netdev->mtu); + if (!otx2_rep_dev(pf->pdev)) { + /* Maximum hardware supported transmit length */ + pf->tx_max_pktlen = pf->netdev->max_mtu + OTX2_ETH_HLEN; + pf->rbsize = otx2_get_rbuf_size(pf, pf->netdev->mtu); + } mutex_lock(&mbox->lock); /* NPA init */ @@ -1549,10 +1591,15 @@ static int otx2_init_hw_resources(struct otx2_nic *pf) } for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { - err = otx2_txschq_config(pf, lvl, 0, false); - if (err) { - mutex_unlock(&mbox->lock); - goto err_free_nix_queues; + int idx; + + for (idx = 0; idx < pf->hw.txschq_cnt[lvl]; idx++) { + err = otx2_txschq_config(pf, lvl, idx, false); + if (err) { + dev_err(pf->dev, "Failed to config TXSCH\n"); + mutex_unlock(&mbox->lock); + goto err_free_nix_queues; + } } } @@ -1601,8 +1648,9 @@ static int otx2_init_hw_resources(struct otx2_nic *pf) mutex_unlock(&mbox->lock); return err; } +EXPORT_SYMBOL(otx2_init_hw_resources); -static void otx2_free_hw_resources(struct otx2_nic *pf) +void otx2_free_hw_resources(struct otx2_nic *pf) { struct otx2_qset *qset = &pf->qset; struct nix_lf_free_req *free_req; @@ -1624,11 +1672,12 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) otx2_pfc_txschq_stop(pf); #endif - otx2_clean_qos_queues(pf); + if (!otx2_rep_dev(pf->pdev)) + otx2_clean_qos_queues(pf); mutex_lock(&mbox->lock); /* Disable backpressure */ - if (!(pf->pcifunc & RVU_PFVF_FUNC_MASK)) + if (!is_otx2_lbkvf(pf->pdev)) otx2_nix_config_bp(pf, false); mutex_unlock(&mbox->lock); @@ -1660,7 +1709,8 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) otx2_free_cq_res(pf); /* Free all ingress bandwidth profiles allocated */ - cn10k_free_all_ipolicers(pf); + if (!otx2_rep_dev(pf->pdev)) + cn10k_free_all_ipolicers(pf); mutex_lock(&mbox->lock); /* Reset NIX LF */ @@ -1688,6 +1738,7 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) } mutex_unlock(&mbox->lock); } +EXPORT_SYMBOL(otx2_free_hw_resources); static bool otx2_promisc_use_mce_list(struct otx2_nic *pfvf) { @@ -1770,15 +1821,24 @@ static void otx2_dim_work(struct work_struct *w) dim->state = DIM_START_MEASURE; } -int otx2_open(struct net_device *netdev) +void otx2_free_queue_mem(struct otx2_qset *qset) +{ + kfree(qset->sq); + qset->sq = NULL; + kfree(qset->cq); + qset->cq = NULL; + kfree(qset->rq); + qset->rq = NULL; + kfree(qset->napi); + qset->napi = NULL; +} +EXPORT_SYMBOL(otx2_free_queue_mem); + +int otx2_alloc_queue_mem(struct otx2_nic *pf) { - struct otx2_nic *pf = netdev_priv(netdev); - struct otx2_cq_poll *cq_poll = NULL; struct otx2_qset *qset = &pf->qset; - int err = 0, qidx, vec; - char *irq_name; + struct otx2_cq_poll *cq_poll; - netif_carrier_off(netdev); /* RQ and SQs are mapped to different CQs, * so find out max CQ IRQs (i.e CINTs) needed. @@ -1798,7 +1858,6 @@ int otx2_open(struct net_device *netdev) /* CQ size of SQ */ qset->sqe_cnt = qset->sqe_cnt ? qset->sqe_cnt : Q_COUNT(Q_SIZE_4K); - err = -ENOMEM; qset->cq = kcalloc(pf->qset.cq_cnt, sizeof(struct otx2_cq_queue), GFP_KERNEL); if (!qset->cq) @@ -1814,6 +1873,28 @@ int otx2_open(struct net_device *netdev) if (!qset->rq) goto err_free_mem; + return 0; + +err_free_mem: + otx2_free_queue_mem(qset); + return -ENOMEM; +} +EXPORT_SYMBOL(otx2_alloc_queue_mem); + +int otx2_open(struct net_device *netdev) +{ + struct otx2_nic *pf = netdev_priv(netdev); + struct otx2_cq_poll *cq_poll = NULL; + struct otx2_qset *qset = &pf->qset; + int err = 0, qidx, vec; + char *irq_name; + + netif_carrier_off(netdev); + + err = otx2_alloc_queue_mem(pf); + if (err) + return err; + err = otx2_init_hw_resources(pf); if (err) goto err_free_mem; @@ -1932,6 +2013,7 @@ int otx2_open(struct net_device *netdev) } pf->flags &= ~OTX2_FLAG_INTF_DOWN; + pf->flags &= ~OTX2_FLAG_PORT_UP; /* 'intf_down' may be checked on any cpu */ smp_wmb(); @@ -1979,10 +2061,7 @@ int otx2_open(struct net_device *netdev) otx2_disable_napi(pf); otx2_free_hw_resources(pf); err_free_mem: - kfree(qset->sq); - kfree(qset->cq); - kfree(qset->rq); - kfree(qset->napi); + otx2_free_queue_mem(qset); return err; } EXPORT_SYMBOL(otx2_open); @@ -2047,11 +2126,7 @@ int otx2_stop(struct net_device *netdev) for (qidx = 0; qidx < netdev->num_tx_queues; qidx++) netdev_tx_reset_queue(netdev_get_tx_queue(netdev, qidx)); - - kfree(qset->sq); - kfree(qset->cq); - kfree(qset->rq); - kfree(qset->napi); + otx2_free_queue_mem(qset); /* Do not clear RQ/SQ ringsize settings */ memset_startat(qset, 0, sqe_cnt); return 0; @@ -2081,7 +2156,7 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev) sq = &pf->qset.sq[sq_idx]; txq = netdev_get_tx_queue(netdev, qidx); - if (!otx2_sq_append_skb(netdev, sq, skb, qidx)) { + if (!otx2_sq_append_skb(pf, txq, sq, skb, qidx)) { netif_tx_stop_queue(txq); /* Check again, incase SQBs got freed up */ @@ -2786,7 +2861,7 @@ static const struct net_device_ops otx2_netdev_ops = { .ndo_set_vf_trust = otx2_ndo_set_vf_trust, }; -static int otx2_wq_init(struct otx2_nic *pf) +int otx2_wq_init(struct otx2_nic *pf) { pf->otx2_wq = create_singlethread_workqueue("otx2_wq"); if (!pf->otx2_wq) @@ -2797,7 +2872,7 @@ static int otx2_wq_init(struct otx2_nic *pf) return 0; } -static int otx2_check_pf_usable(struct otx2_nic *nic) +int otx2_check_pf_usable(struct otx2_nic *nic) { u64 rev; @@ -2815,7 +2890,7 @@ static int otx2_check_pf_usable(struct otx2_nic *nic) return 0; } -static int otx2_realloc_msix_vectors(struct otx2_nic *pf) +int otx2_realloc_msix_vectors(struct otx2_nic *pf) { struct otx2_hw *hw = &pf->hw; int num_vec, err; @@ -2837,6 +2912,7 @@ static int otx2_realloc_msix_vectors(struct otx2_nic *pf) return otx2_register_mbox_intr(pf, false); } +EXPORT_SYMBOL(otx2_realloc_msix_vectors); static int otx2_sriov_vfcfg_init(struct otx2_nic *pf) { @@ -2872,6 +2948,88 @@ static void otx2_sriov_vfcfg_cleanup(struct otx2_nic *pf) } } +int otx2_init_rsrc(struct pci_dev *pdev, struct otx2_nic *pf) +{ + struct device *dev = &pdev->dev; + struct otx2_hw *hw = &pf->hw; + int num_vec, err; + + num_vec = pci_msix_vec_count(pdev); + hw->irq_name = devm_kmalloc_array(&hw->pdev->dev, num_vec, NAME_SIZE, + GFP_KERNEL); + if (!hw->irq_name) + return -ENOMEM; + + hw->affinity_mask = devm_kcalloc(&hw->pdev->dev, num_vec, + sizeof(cpumask_var_t), GFP_KERNEL); + if (!hw->affinity_mask) + return -ENOMEM; + + /* Map CSRs */ + pf->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); + if (!pf->reg_base) { + dev_err(dev, "Unable to map physical function CSRs, aborting\n"); + return -ENOMEM; + } + + err = otx2_check_pf_usable(pf); + if (err) + return err; + + err = pci_alloc_irq_vectors(hw->pdev, RVU_PF_INT_VEC_CNT, + RVU_PF_INT_VEC_CNT, PCI_IRQ_MSIX); + if (err < 0) { + dev_err(dev, "%s: Failed to alloc %d IRQ vectors\n", + __func__, num_vec); + return err; + } + + otx2_setup_dev_hw_settings(pf); + + /* Init PF <=> AF mailbox stuff */ + err = otx2_pfaf_mbox_init(pf); + if (err) + goto err_free_irq_vectors; + + /* Register mailbox interrupt */ + err = otx2_register_mbox_intr(pf, true); + if (err) + goto err_mbox_destroy; + + /* Request AF to attach NPA and NIX LFs to this PF. + * NIX and NPA LFs are needed for this PF to function as a NIC. + */ + err = otx2_attach_npa_nix(pf); + if (err) + goto err_disable_mbox_intr; + + err = otx2_realloc_msix_vectors(pf); + if (err) + goto err_detach_rsrc; + + err = cn10k_lmtst_init(pf); + if (err) + goto err_detach_rsrc; + + return 0; + +err_detach_rsrc: + if (pf->hw.lmt_info) + free_percpu(pf->hw.lmt_info); + if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) + qmem_free(pf->dev, pf->dync_lmt); + otx2_detach_resources(&pf->mbox); +err_disable_mbox_intr: + otx2_disable_mbox_intr(pf); +err_mbox_destroy: + otx2_pfaf_mbox_destroy(pf); +err_free_irq_vectors: + pci_free_irq_vectors(hw->pdev); + + return err; +} +EXPORT_SYMBOL(otx2_init_rsrc); + static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *dev = &pdev->dev; @@ -2879,7 +3037,6 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct net_device *netdev; struct otx2_nic *pf; struct otx2_hw *hw; - int num_vec; err = pcim_enable_device(pdev); if (err) { @@ -2930,72 +3087,14 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Use CQE of 128 byte descriptor size by default */ hw->xqe_size = 128; - num_vec = pci_msix_vec_count(pdev); - hw->irq_name = devm_kmalloc_array(&hw->pdev->dev, num_vec, NAME_SIZE, - GFP_KERNEL); - if (!hw->irq_name) { - err = -ENOMEM; - goto err_free_netdev; - } - - hw->affinity_mask = devm_kcalloc(&hw->pdev->dev, num_vec, - sizeof(cpumask_var_t), GFP_KERNEL); - if (!hw->affinity_mask) { - err = -ENOMEM; - goto err_free_netdev; - } - - /* Map CSRs */ - pf->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); - if (!pf->reg_base) { - dev_err(dev, "Unable to map physical function CSRs, aborting\n"); - err = -ENOMEM; - goto err_free_netdev; - } - - err = otx2_check_pf_usable(pf); + err = otx2_init_rsrc(pdev, pf); if (err) goto err_free_netdev; - err = pci_alloc_irq_vectors(hw->pdev, RVU_PF_INT_VEC_CNT, - RVU_PF_INT_VEC_CNT, PCI_IRQ_MSIX); - if (err < 0) { - dev_err(dev, "%s: Failed to alloc %d IRQ vectors\n", - __func__, num_vec); - goto err_free_netdev; - } - - otx2_setup_dev_hw_settings(pf); - - /* Init PF <=> AF mailbox stuff */ - err = otx2_pfaf_mbox_init(pf); - if (err) - goto err_free_irq_vectors; - - /* Register mailbox interrupt */ - err = otx2_register_mbox_intr(pf, true); - if (err) - goto err_mbox_destroy; - - /* Request AF to attach NPA and NIX LFs to this PF. - * NIX and NPA LFs are needed for this PF to function as a NIC. - */ - err = otx2_attach_npa_nix(pf); - if (err) - goto err_disable_mbox_intr; - - err = otx2_realloc_msix_vectors(pf); - if (err) - goto err_detach_rsrc; - err = otx2_set_real_num_queues(netdev, hw->tx_queues, hw->rx_queues); if (err) goto err_detach_rsrc; - err = cn10k_lmtst_init(pf); - if (err) - goto err_detach_rsrc; - /* Assign default mac address */ otx2_get_mac_from_af(netdev); @@ -3058,6 +3157,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) netdev->min_mtu = OTX2_MIN_MTU; netdev->max_mtu = otx2_get_max_mtu(pf); + hw->max_mtu = netdev->max_mtu; /* reset CGX/RPM MAC stats */ otx2_reset_mac_stats(pf); @@ -3118,11 +3218,8 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (test_bit(CN10K_LMTST, &pf->hw.cap_flag)) qmem_free(pf->dev, pf->dync_lmt); otx2_detach_resources(&pf->mbox); -err_disable_mbox_intr: otx2_disable_mbox_intr(pf); -err_mbox_destroy: otx2_pfaf_mbox_destroy(pf); -err_free_irq_vectors: pci_free_irq_vectors(hw->pdev); err_free_netdev: pci_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c index e63cc1eb6d8917..9a226ca7442546 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -443,6 +443,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, struct flow_action_entry *act; struct net_device *target; struct otx2_nic *priv; + struct rep_dev *rdev; u32 burst, mark = 0; u8 nr_police = 0; u8 num_intf = 1; @@ -464,14 +465,18 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, return 0; case FLOW_ACTION_REDIRECT_INGRESS: target = act->dev; - priv = netdev_priv(target); - /* npc_install_flow_req doesn't support passing a target pcifunc */ - if (rvu_get_pf(nic->pcifunc) != rvu_get_pf(priv->pcifunc)) { - NL_SET_ERR_MSG_MOD(extack, - "can't redirect to other pf/vf"); - return -EOPNOTSUPP; + if (target->dev.parent) { + priv = netdev_priv(target); + if (rvu_get_pf(nic->pcifunc) != rvu_get_pf(priv->pcifunc)) { + NL_SET_ERR_MSG_MOD(extack, + "can't redirect to other pf/vf"); + return -EOPNOTSUPP; + } + req->vf = priv->pcifunc & RVU_PFVF_FUNC_MASK; + } else { + rdev = netdev_priv(target); + req->vf = rdev->pcifunc & RVU_PFVF_FUNC_MASK; } - req->vf = priv->pcifunc & RVU_PFVF_FUNC_MASK; /* if op is already set; avoid overwriting the same */ if (!req->op) @@ -1300,6 +1305,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic, req->channel = nic->hw.rx_chan_base; req->entry = flow_cfg->flow_ent[mcam_idx]; req->intf = NIX_INTF_RX; + req->vf = nic->pcifunc; req->set_cntr = 1; new_node->entry = req->entry; @@ -1400,8 +1406,8 @@ static int otx2_tc_get_flow_stats(struct otx2_nic *nic, return 0; } -static int otx2_setup_tc_cls_flower(struct otx2_nic *nic, - struct flow_cls_offload *cls_flower) +int otx2_setup_tc_cls_flower(struct otx2_nic *nic, + struct flow_cls_offload *cls_flower) { switch (cls_flower->command) { case FLOW_CLS_REPLACE: @@ -1414,6 +1420,7 @@ static int otx2_setup_tc_cls_flower(struct otx2_nic *nic, return -EOPNOTSUPP; } } +EXPORT_SYMBOL(otx2_setup_tc_cls_flower); static int otx2_tc_ingress_matchall_install(struct otx2_nic *nic, struct tc_cls_matchall_offload *cls) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c index 933e18ba2fb2c3..04bc06a80e23a8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c @@ -376,9 +376,11 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf, } otx2_set_rxhash(pfvf, cqe, skb); - skb_record_rx_queue(skb, cq->cq_idx); - if (pfvf->netdev->features & NETIF_F_RXCSUM) - skb->ip_summed = CHECKSUM_UNNECESSARY; + if (!(pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED)) { + skb_record_rx_queue(skb, cq->cq_idx); + if (pfvf->netdev->features & NETIF_F_RXCSUM) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } if (pfvf->flags & OTX2_FLAG_TC_MARK_ENABLED) skb->mark = parse->match_id; @@ -453,6 +455,7 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf, int tx_pkts = 0, tx_bytes = 0, qidx; struct otx2_snd_queue *sq; struct nix_cqe_tx_s *cqe; + struct net_device *ndev; int processed_cqe = 0; if (cq->pend_cqe >= budget) @@ -493,6 +496,13 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf, otx2_write64(pfvf, NIX_LF_CQ_OP_DOOR, ((u64)cq->cq_idx << 32) | processed_cqe); +#if IS_ENABLED(CONFIG_RVU_ESWITCH) + if (pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED) + ndev = pfvf->reps[qidx]->netdev; + else +#endif + ndev = pfvf->netdev; + if (likely(tx_pkts)) { struct netdev_queue *txq; @@ -500,12 +510,14 @@ static int otx2_tx_napi_handler(struct otx2_nic *pfvf, if (qidx >= pfvf->hw.tx_queues) qidx -= pfvf->hw.xdp_queues; - txq = netdev_get_tx_queue(pfvf->netdev, qidx); + if (pfvf->flags & OTX2_FLAG_REP_MODE_ENABLED) + qidx = 0; + txq = netdev_get_tx_queue(ndev, qidx); netdev_tx_completed_queue(txq, tx_pkts, tx_bytes); /* Check if queue was stopped earlier due to ring full */ smp_mb(); if (netif_tx_queue_stopped(txq) && - netif_carrier_ok(pfvf->netdev)) + netif_carrier_ok(ndev)) netif_tx_wake_queue(txq); } return 0; @@ -527,7 +539,7 @@ static void otx2_adjust_adaptive_coalese(struct otx2_nic *pfvf, struct otx2_cq_p rx_frames + tx_frames, rx_bytes + tx_bytes, &dim_sample); - net_dim(&cq_poll->dim, dim_sample); + net_dim(&cq_poll->dim, &dim_sample); } int otx2_napi_handler(struct napi_struct *napi, int budget) @@ -594,6 +606,7 @@ int otx2_napi_handler(struct napi_struct *napi, int budget) } return workdone; } +EXPORT_SYMBOL(otx2_napi_handler); void otx2_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx) @@ -1141,13 +1154,13 @@ static void otx2_set_txtstamp(struct otx2_nic *pfvf, struct sk_buff *skb, } } -bool otx2_sq_append_skb(struct net_device *netdev, struct otx2_snd_queue *sq, +bool otx2_sq_append_skb(void *dev, struct netdev_queue *txq, + struct otx2_snd_queue *sq, struct sk_buff *skb, u16 qidx) { - struct netdev_queue *txq = netdev_get_tx_queue(netdev, qidx); - struct otx2_nic *pfvf = netdev_priv(netdev); int offset, num_segs, free_desc; struct nix_sqe_hdr_s *sqe_hdr; + struct otx2_nic *pfvf = dev; /* Check if there is enough room between producer * and consumer index. diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h index 3f1d2655ff777c..e1db5f9618772f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h @@ -167,7 +167,8 @@ static inline u64 otx2_iova_to_phys(void *iommu_domain, dma_addr_t dma_addr) } int otx2_napi_handler(struct napi_struct *napi, int budget); -bool otx2_sq_append_skb(struct net_device *netdev, struct otx2_snd_queue *sq, +bool otx2_sq_append_skb(void *dev, struct netdev_queue *txq, + struct otx2_snd_queue *sq, struct sk_buff *skb, u16 qidx); void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index 99fcc5661674be..839fc77c11b238 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -21,6 +21,7 @@ static const struct pci_device_id otx2_vf_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_AFVF) }, { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_RVU_VF) }, + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_OCTEONTX2_SDP_REP) }, { } }; @@ -371,7 +372,7 @@ static int otx2vf_open(struct net_device *netdev) /* LBKs do not receive link events so tell everyone we are up here */ vf = netdev_priv(netdev); - if (is_otx2_lbkvf(vf->pdev)) { + if (is_otx2_lbkvf(vf->pdev) || is_otx2_sdp_rep(vf->pdev)) { pr_info("%s NIC Link is UP\n", netdev->name); netif_carrier_on(netdev); netif_tx_start_all_queues(netdev); @@ -395,7 +396,7 @@ static netdev_tx_t otx2vf_xmit(struct sk_buff *skb, struct net_device *netdev) sq = &vf->qset.sq[qidx]; txq = netdev_get_tx_queue(netdev, qidx); - if (!otx2_sq_append_skb(netdev, sq, skb, qidx)) { + if (!otx2_sq_append_skb(vf, txq, sq, skb, qidx)) { netif_tx_stop_queue(txq); /* Check again, incase SQBs got freed up */ @@ -500,7 +501,7 @@ static const struct net_device_ops otx2vf_netdev_ops = { .ndo_setup_tc = otx2_setup_tc, }; -static int otx2_wq_init(struct otx2_nic *vf) +static int otx2_vf_wq_init(struct otx2_nic *vf) { vf->otx2_wq = create_singlethread_workqueue("otx2vf_wq"); if (!vf->otx2_wq) @@ -671,6 +672,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) netdev->min_mtu = OTX2_MIN_MTU; netdev->max_mtu = otx2_get_max_mtu(vf); + hw->max_mtu = netdev->max_mtu; /* To distinguish, for LBK VFs set netdev name explicitly */ if (is_otx2_lbkvf(vf->pdev)) { @@ -682,13 +684,22 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) snprintf(netdev->name, sizeof(netdev->name), "lbk%d", n); } + if (is_otx2_sdp_rep(vf->pdev)) { + int n; + + n = vf->pcifunc & RVU_PFVF_FUNC_MASK; + n -= 1; + snprintf(netdev->name, sizeof(netdev->name), "sdp%d-%d", + pdev->bus->number, n); + } + err = register_netdev(netdev); if (err) { dev_err(dev, "Failed to register netdevice\n"); goto err_ptp_destroy; } - err = otx2_wq_init(vf); + err = otx2_vf_wq_init(vf); if (err) goto err_unreg_netdev; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.c b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c new file mode 100644 index 00000000000000..04e08e06f30ff2 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.c @@ -0,0 +1,867 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU representor driver + * + * Copyright (C) 2024 Marvell. + * + */ + +#include +#include +#include +#include +#include + +#include "otx2_common.h" +#include "cn10k.h" +#include "otx2_reg.h" +#include "rep.h" + +#define DRV_NAME "rvu_rep" +#define DRV_STRING "Marvell RVU Representor Driver" + +static const struct pci_device_id rvu_rep_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_RVU_REP) }, + { } +}; + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION(DRV_STRING); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, rvu_rep_id_table); + +static int rvu_rep_notify_pfvf(struct otx2_nic *priv, u16 event, + struct rep_event *data); + +static int rvu_rep_mcam_flow_init(struct rep_dev *rep) +{ + struct npc_mcam_alloc_entry_req *req; + struct npc_mcam_alloc_entry_rsp *rsp; + struct otx2_nic *priv = rep->mdev; + int ent, allocated = 0; + int count; + + rep->flow_cfg = kcalloc(1, sizeof(struct otx2_flow_config), GFP_KERNEL); + + if (!rep->flow_cfg) + return -ENOMEM; + + count = OTX2_DEFAULT_FLOWCOUNT; + + rep->flow_cfg->flow_ent = kcalloc(count, sizeof(u16), GFP_KERNEL); + if (!rep->flow_cfg->flow_ent) + return -ENOMEM; + + while (allocated < count) { + req = otx2_mbox_alloc_msg_npc_mcam_alloc_entry(&priv->mbox); + if (!req) + goto exit; + + req->hdr.pcifunc = rep->pcifunc; + req->contig = false; + req->ref_entry = 0; + req->count = (count - allocated) > NPC_MAX_NONCONTIG_ENTRIES ? + NPC_MAX_NONCONTIG_ENTRIES : count - allocated; + + if (otx2_sync_mbox_msg(&priv->mbox)) + goto exit; + + rsp = (struct npc_mcam_alloc_entry_rsp *)otx2_mbox_get_rsp + (&priv->mbox.mbox, 0, &req->hdr); + + for (ent = 0; ent < rsp->count; ent++) + rep->flow_cfg->flow_ent[ent + allocated] = rsp->entry_list[ent]; + + allocated += rsp->count; + + if (rsp->count != req->count) + break; + } +exit: + /* Multiple MCAM entry alloc requests could result in non-sequential + * MCAM entries in the flow_ent[] array. Sort them in an ascending + * order, otherwise user installed ntuple filter index and MCAM entry + * index will not be in sync. + */ + if (allocated) + sort(&rep->flow_cfg->flow_ent[0], allocated, + sizeof(rep->flow_cfg->flow_ent[0]), mcam_entry_cmp, NULL); + + mutex_unlock(&priv->mbox.lock); + + rep->flow_cfg->max_flows = allocated; + + if (allocated) { + rep->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC; + rep->flags |= OTX2_FLAG_NTUPLE_SUPPORT; + rep->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT; + } + + INIT_LIST_HEAD(&rep->flow_cfg->flow_list); + INIT_LIST_HEAD(&rep->flow_cfg->flow_list_tc); + return 0; +} + +static int rvu_rep_setup_tc_cb(enum tc_setup_type type, + void *type_data, void *cb_priv) +{ + struct rep_dev *rep = cb_priv; + struct otx2_nic *priv = rep->mdev; + + if (!(rep->flags & RVU_REP_VF_INITIALIZED)) + return -EINVAL; + + if (!(rep->flags & OTX2_FLAG_TC_FLOWER_SUPPORT)) + rvu_rep_mcam_flow_init(rep); + + priv->netdev = rep->netdev; + priv->flags = rep->flags; + priv->pcifunc = rep->pcifunc; + priv->flow_cfg = rep->flow_cfg; + + switch (type) { + case TC_SETUP_CLSFLOWER: + return otx2_setup_tc_cls_flower(priv, type_data); + default: + return -EOPNOTSUPP; + } +} + +static LIST_HEAD(rvu_rep_block_cb_list); +static int rvu_rep_setup_tc(struct net_device *netdev, enum tc_setup_type type, + void *type_data) +{ + struct rvu_rep *rep = netdev_priv(netdev); + + switch (type) { + case TC_SETUP_BLOCK: + return flow_block_cb_setup_simple(type_data, + &rvu_rep_block_cb_list, + rvu_rep_setup_tc_cb, + rep, rep, true); + default: + return -EOPNOTSUPP; + } +} + +static int +rvu_rep_sp_stats64(const struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + struct rep_dev *rep = netdev_priv(dev); + struct otx2_nic *priv = rep->mdev; + struct otx2_rcv_queue *rq; + struct otx2_snd_queue *sq; + u16 qidx = rep->rep_id; + + otx2_update_rq_stats(priv, qidx); + rq = &priv->qset.rq[qidx]; + + otx2_update_sq_stats(priv, qidx); + sq = &priv->qset.sq[qidx]; + + stats->tx_bytes = sq->stats.bytes; + stats->tx_packets = sq->stats.pkts; + stats->rx_bytes = rq->stats.bytes; + stats->rx_packets = rq->stats.pkts; + return 0; +} + +static bool +rvu_rep_has_offload_stats(const struct net_device *dev, int attr_id) +{ + return attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT; +} + +static int +rvu_rep_get_offload_stats(int attr_id, const struct net_device *dev, + void *sp) +{ + if (attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT) + return rvu_rep_sp_stats64(dev, (struct rtnl_link_stats64 *)sp); + + return -EINVAL; +} + +static int rvu_rep_dl_port_fn_hw_addr_get(struct devlink_port *port, + u8 *hw_addr, int *hw_addr_len, + struct netlink_ext_ack *extack) +{ + struct rep_dev *rep = container_of(port, struct rep_dev, dl_port); + + ether_addr_copy(hw_addr, rep->mac); + *hw_addr_len = ETH_ALEN; + return 0; +} + +static int rvu_rep_dl_port_fn_hw_addr_set(struct devlink_port *port, + const u8 *hw_addr, int hw_addr_len, + struct netlink_ext_ack *extack) +{ + struct rep_dev *rep = container_of(port, struct rep_dev, dl_port); + struct otx2_nic *priv = rep->mdev; + struct rep_event evt = {0}; + + eth_hw_addr_set(rep->netdev, hw_addr); + ether_addr_copy(rep->mac, hw_addr); + + ether_addr_copy(evt.evt_data.mac, hw_addr); + evt.pcifunc = rep->pcifunc; + rvu_rep_notify_pfvf(priv, RVU_EVENT_MAC_ADDR_CHANGE, &evt); + return 0; +} + +static const struct devlink_port_ops rvu_rep_dl_port_ops = { + .port_fn_hw_addr_get = rvu_rep_dl_port_fn_hw_addr_get, + .port_fn_hw_addr_set = rvu_rep_dl_port_fn_hw_addr_set, +}; + +static void +rvu_rep_devlink_set_switch_id(struct otx2_nic *priv, + struct netdev_phys_item_id *ppid) +{ + struct pci_dev *pdev = priv->pdev; + u64 id; + + id = pci_get_dsn(pdev); + + ppid->id_len = sizeof(id); + put_unaligned_be64(id, &ppid->id); +} + +static void rvu_rep_devlink_port_unregister(struct rep_dev *rep) +{ + devlink_port_unregister(&rep->dl_port); +} + +static int rvu_rep_devlink_port_register(struct rep_dev *rep) +{ + struct devlink_port_attrs attrs = {}; + struct otx2_nic *priv = rep->mdev; + struct devlink *dl = priv->dl->dl; + int err; + + if (!(rep->pcifunc & RVU_PFVF_FUNC_MASK)) { + attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; + attrs.phys.port_number = rvu_get_pf(rep->pcifunc); + } else { + attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF; + attrs.pci_vf.pf = rvu_get_pf(rep->pcifunc); + attrs.pci_vf.vf = rep->pcifunc & RVU_PFVF_FUNC_MASK; + } + + rvu_rep_devlink_set_switch_id(priv, &attrs.switch_id); + devlink_port_attrs_set(&rep->dl_port, &attrs); + + err = devl_port_register_with_ops(dl, &rep->dl_port, rep->rep_id, + &rvu_rep_dl_port_ops); + if (err) { + dev_err(rep->mdev->dev, "devlink_port_register failed: %d\n", + err); + return err; + } + return 0; +} + +static int rvu_rep_get_repid(struct otx2_nic *priv, u16 pcifunc) +{ + int rep_id; + + for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++) + if (priv->rep_pf_map[rep_id] == pcifunc) + return rep_id; + return -EINVAL; +} + +static int rvu_rep_notify_pfvf(struct otx2_nic *priv, u16 event, + struct rep_event *data) +{ + struct rep_event *req; + + mutex_lock(&priv->mbox.lock); + req = otx2_mbox_alloc_msg_rep_event_notify(&priv->mbox); + if (!req) { + mutex_unlock(&priv->mbox.lock); + return -ENOMEM; + } + req->event = event; + req->pcifunc = data->pcifunc; + + memcpy(&req->evt_data, &data->evt_data, sizeof(struct rep_evt_data)); + otx2_sync_mbox_msg(&priv->mbox); + mutex_unlock(&priv->mbox.lock); + return 0; +} + +static void rvu_rep_state_evt_handler(struct otx2_nic *priv, + struct rep_event *info) +{ + struct rep_dev *rep; + int rep_id; + + rep_id = rvu_rep_get_repid(priv, info->pcifunc); + rep = priv->reps[rep_id]; + if (info->evt_data.vf_state) + rep->flags |= RVU_REP_VF_INITIALIZED; + else + rep->flags &= ~RVU_REP_VF_INITIALIZED; +} + +int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info) +{ + if (info->event & RVU_EVENT_PFVF_STATE) + rvu_rep_state_evt_handler(pf, info); + return 0; +} + +static int rvu_rep_change_mtu(struct net_device *dev, int new_mtu) +{ + struct rep_dev *rep = netdev_priv(dev); + struct otx2_nic *priv = rep->mdev; + struct rep_event evt = {0}; + + netdev_info(dev, "Changing MTU from %d to %d\n", + dev->mtu, new_mtu); + dev->mtu = new_mtu; + + evt.evt_data.mtu = new_mtu; + evt.pcifunc = rep->pcifunc; + rvu_rep_notify_pfvf(priv, RVU_EVENT_MTU_CHANGE, &evt); + return 0; +} + +static void rvu_rep_get_stats(struct work_struct *work) +{ + struct delayed_work *del_work = to_delayed_work(work); + struct nix_stats_req *req; + struct nix_stats_rsp *rsp; + struct rep_stats *stats; + struct otx2_nic *priv; + struct rep_dev *rep; + int err; + + rep = container_of(del_work, struct rep_dev, stats_wrk); + priv = rep->mdev; + + mutex_lock(&priv->mbox.lock); + req = otx2_mbox_alloc_msg_nix_lf_stats(&priv->mbox); + if (!req) { + mutex_unlock(&priv->mbox.lock); + return; + } + req->pcifunc = rep->pcifunc; + err = otx2_sync_mbox_msg_busy_poll(&priv->mbox); + if (err) + goto exit; + + rsp = (struct nix_stats_rsp *) + otx2_mbox_get_rsp(&priv->mbox.mbox, 0, &req->hdr); + + if (IS_ERR(rsp)) { + err = PTR_ERR(rsp); + goto exit; + } + + stats = &rep->stats; + stats->rx_bytes = rsp->rx.octs; + stats->rx_frames = rsp->rx.ucast + rsp->rx.bcast + + rsp->rx.mcast; + stats->rx_drops = rsp->rx.drop; + stats->rx_mcast_frames = rsp->rx.mcast; + stats->tx_bytes = rsp->tx.octs; + stats->tx_frames = rsp->tx.ucast + rsp->tx.bcast + rsp->tx.mcast; + stats->tx_drops = rsp->tx.drop; +exit: + mutex_unlock(&priv->mbox.lock); +} + +static void rvu_rep_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + struct rep_dev *rep = netdev_priv(dev); + + if (!(rep->flags & RVU_REP_VF_INITIALIZED)) + return; + + stats->rx_packets = rep->stats.rx_frames; + stats->rx_bytes = rep->stats.rx_bytes; + stats->rx_dropped = rep->stats.rx_drops; + stats->multicast = rep->stats.rx_mcast_frames; + + stats->tx_packets = rep->stats.tx_frames; + stats->tx_bytes = rep->stats.tx_bytes; + stats->tx_dropped = rep->stats.tx_drops; + + schedule_delayed_work(&rep->stats_wrk, msecs_to_jiffies(100)); +} + +static int rvu_eswitch_config(struct otx2_nic *priv, u8 ena) +{ + struct esw_cfg_req *req; + + mutex_lock(&priv->mbox.lock); + req = otx2_mbox_alloc_msg_esw_cfg(&priv->mbox); + if (!req) { + mutex_unlock(&priv->mbox.lock); + return -ENOMEM; + } + req->ena = ena; + otx2_sync_mbox_msg(&priv->mbox); + mutex_unlock(&priv->mbox.lock); + return 0; +} + +static netdev_tx_t rvu_rep_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct rep_dev *rep = netdev_priv(dev); + struct otx2_nic *pf = rep->mdev; + struct otx2_snd_queue *sq; + struct netdev_queue *txq; + + sq = &pf->qset.sq[rep->rep_id]; + txq = netdev_get_tx_queue(dev, 0); + + if (!otx2_sq_append_skb(pf, txq, sq, skb, rep->rep_id)) { + netif_tx_stop_queue(txq); + + /* Check again, in case SQBs got freed up */ + smp_mb(); + if (((sq->num_sqbs - *sq->aura_fc_addr) * sq->sqe_per_sqb) + > sq->sqe_thresh) + netif_tx_wake_queue(txq); + + return NETDEV_TX_BUSY; + } + return NETDEV_TX_OK; +} + +static int rvu_rep_open(struct net_device *dev) +{ + struct rep_dev *rep = netdev_priv(dev); + struct otx2_nic *priv = rep->mdev; + struct rep_event evt = {0}; + + if (!(rep->flags & RVU_REP_VF_INITIALIZED)) + return 0; + + netif_carrier_on(dev); + netif_tx_start_all_queues(dev); + + evt.event = RVU_EVENT_PORT_STATE; + evt.evt_data.port_state = 1; + evt.pcifunc = rep->pcifunc; + rvu_rep_notify_pfvf(priv, RVU_EVENT_PORT_STATE, &evt); + return 0; +} + +static int rvu_rep_stop(struct net_device *dev) +{ + struct rep_dev *rep = netdev_priv(dev); + struct otx2_nic *priv = rep->mdev; + struct rep_event evt = {0}; + + if (!(rep->flags & RVU_REP_VF_INITIALIZED)) + return 0; + + netif_carrier_off(dev); + netif_tx_disable(dev); + + evt.event = RVU_EVENT_PORT_STATE; + evt.pcifunc = rep->pcifunc; + rvu_rep_notify_pfvf(priv, RVU_EVENT_PORT_STATE, &evt); + return 0; +} + +static const struct net_device_ops rvu_rep_netdev_ops = { + .ndo_open = rvu_rep_open, + .ndo_stop = rvu_rep_stop, + .ndo_start_xmit = rvu_rep_xmit, + .ndo_get_stats64 = rvu_rep_get_stats64, + .ndo_change_mtu = rvu_rep_change_mtu, + .ndo_has_offload_stats = rvu_rep_has_offload_stats, + .ndo_get_offload_stats = rvu_rep_get_offload_stats, + .ndo_setup_tc = rvu_rep_setup_tc, +}; + +static int rvu_rep_napi_init(struct otx2_nic *priv, + struct netlink_ext_ack *extack) +{ + struct otx2_qset *qset = &priv->qset; + struct otx2_cq_poll *cq_poll = NULL; + struct otx2_hw *hw = &priv->hw; + int err = 0, qidx, vec; + char *irq_name; + + qset->napi = kcalloc(hw->cint_cnt, sizeof(*cq_poll), GFP_KERNEL); + if (!qset->napi) + return -ENOMEM; + + /* Register NAPI handler */ + for (qidx = 0; qidx < hw->cint_cnt; qidx++) { + cq_poll = &qset->napi[qidx]; + cq_poll->cint_idx = qidx; + cq_poll->cq_ids[CQ_RX] = + (qidx < hw->rx_queues) ? qidx : CINT_INVALID_CQ; + cq_poll->cq_ids[CQ_TX] = (qidx < hw->tx_queues) ? + qidx + hw->rx_queues : + CINT_INVALID_CQ; + cq_poll->cq_ids[CQ_XDP] = CINT_INVALID_CQ; + cq_poll->cq_ids[CQ_QOS] = CINT_INVALID_CQ; + + cq_poll->dev = (void *)priv; + netif_napi_add(priv->reps[qidx]->netdev, &cq_poll->napi, + otx2_napi_handler); + napi_enable(&cq_poll->napi); + } + /* Register CQ IRQ handlers */ + vec = hw->nix_msixoff + NIX_LF_CINT_VEC_START; + for (qidx = 0; qidx < hw->cint_cnt; qidx++) { + irq_name = &hw->irq_name[vec * NAME_SIZE]; + + snprintf(irq_name, NAME_SIZE, "rep%d-rxtx-%d", qidx, qidx); + + err = request_irq(pci_irq_vector(priv->pdev, vec), + otx2_cq_intr_handler, 0, irq_name, + &qset->napi[qidx]); + if (err) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "RVU REP IRQ registration failed for CQ%d", + qidx); + goto err_free_cints; + } + vec++; + + /* Enable CQ IRQ */ + otx2_write64(priv, NIX_LF_CINTX_INT(qidx), BIT_ULL(0)); + otx2_write64(priv, NIX_LF_CINTX_ENA_W1S(qidx), BIT_ULL(0)); + } + priv->flags &= ~OTX2_FLAG_INTF_DOWN; + return 0; + +err_free_cints: + otx2_free_cints(priv, qidx); + otx2_disable_napi(priv); + return err; +} + +static void rvu_rep_free_cq_rsrc(struct otx2_nic *priv) +{ + struct otx2_qset *qset = &priv->qset; + struct otx2_cq_poll *cq_poll = NULL; + int qidx, vec; + + /* Cleanup CQ NAPI and IRQ */ + vec = priv->hw.nix_msixoff + NIX_LF_CINT_VEC_START; + for (qidx = 0; qidx < priv->hw.cint_cnt; qidx++) { + /* Disable interrupt */ + otx2_write64(priv, NIX_LF_CINTX_ENA_W1C(qidx), BIT_ULL(0)); + + synchronize_irq(pci_irq_vector(priv->pdev, vec)); + + cq_poll = &qset->napi[qidx]; + napi_synchronize(&cq_poll->napi); + vec++; + } + otx2_free_cints(priv, priv->hw.cint_cnt); + otx2_disable_napi(priv); +} + +static void rvu_rep_rsrc_free(struct otx2_nic *priv) +{ + struct otx2_qset *qset = &priv->qset; + struct delayed_work *work; + int wrk; + + for (wrk = 0; wrk < priv->qset.cq_cnt; wrk++) { + work = &priv->refill_wrk[wrk].pool_refill_work; + cancel_delayed_work_sync(work); + } + devm_kfree(priv->dev, priv->refill_wrk); + + otx2_free_hw_resources(priv); + otx2_free_queue_mem(qset); +} + +static int rvu_rep_rsrc_init(struct otx2_nic *priv) +{ + struct otx2_qset *qset = &priv->qset; + int err; + + err = otx2_alloc_queue_mem(priv); + if (err) + return err; + + priv->hw.max_mtu = otx2_get_max_mtu(priv); + priv->tx_max_pktlen = priv->hw.max_mtu + OTX2_ETH_HLEN; + priv->rbsize = ALIGN(priv->hw.rbuf_len, OTX2_ALIGN) + OTX2_HEAD_ROOM; + + err = otx2_init_hw_resources(priv); + if (err) + goto err_free_rsrc; + + /* Set maximum frame size allowed in HW */ + err = otx2_hw_set_mtu(priv, priv->hw.max_mtu); + if (err) { + dev_err(priv->dev, "Failed to set HW MTU\n"); + goto err_free_rsrc; + } + return 0; + +err_free_rsrc: + otx2_free_hw_resources(priv); + otx2_free_queue_mem(qset); + return err; +} + +void rvu_rep_destroy(struct otx2_nic *priv) +{ + struct rep_dev *rep; + int rep_id; + + rvu_eswitch_config(priv, false); + priv->flags |= OTX2_FLAG_INTF_DOWN; + rvu_rep_free_cq_rsrc(priv); + for (rep_id = 0; rep_id < priv->rep_cnt; rep_id++) { + rep = priv->reps[rep_id]; + unregister_netdev(rep->netdev); + rvu_rep_devlink_port_unregister(rep); + free_netdev(rep->netdev); + kfree(rep->flow_cfg); + } + kfree(priv->reps); + rvu_rep_rsrc_free(priv); +} + +int rvu_rep_create(struct otx2_nic *priv, struct netlink_ext_ack *extack) +{ + int rep_cnt = priv->rep_cnt; + struct net_device *ndev; + struct rep_dev *rep; + int rep_id, err; + u16 pcifunc; + + err = rvu_rep_rsrc_init(priv); + if (err) + return -ENOMEM; + + priv->reps = kcalloc(rep_cnt, sizeof(struct rep_dev *), GFP_KERNEL); + if (!priv->reps) + return -ENOMEM; + + for (rep_id = 0; rep_id < rep_cnt; rep_id++) { + ndev = alloc_etherdev(sizeof(*rep)); + if (!ndev) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "PFVF representor:%d creation failed", + rep_id); + err = -ENOMEM; + goto exit; + } + + rep = netdev_priv(ndev); + priv->reps[rep_id] = rep; + rep->mdev = priv; + rep->netdev = ndev; + rep->rep_id = rep_id; + + ndev->min_mtu = OTX2_MIN_MTU; + ndev->max_mtu = priv->hw.max_mtu; + ndev->netdev_ops = &rvu_rep_netdev_ops; + pcifunc = priv->rep_pf_map[rep_id]; + rep->pcifunc = pcifunc; + + snprintf(ndev->name, sizeof(ndev->name), "Rpf%dvf%d", + rvu_get_pf(pcifunc), (pcifunc & RVU_PFVF_FUNC_MASK)); + + ndev->hw_features = (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | NETIF_F_RXHASH | + NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6); + + ndev->hw_features |= NETIF_F_HW_TC; + ndev->features |= ndev->hw_features; + eth_hw_addr_random(ndev); + err = rvu_rep_devlink_port_register(rep); + if (err) { + free_netdev(ndev); + goto exit; + } + + SET_NETDEV_DEVLINK_PORT(ndev, &rep->dl_port); + err = register_netdev(ndev); + if (err) { + NL_SET_ERR_MSG_MOD(extack, + "PFVF representor registration failed"); + rvu_rep_devlink_port_unregister(rep); + free_netdev(ndev); + goto exit; + } + + INIT_DELAYED_WORK(&rep->stats_wrk, rvu_rep_get_stats); + } + err = rvu_rep_napi_init(priv, extack); + if (err) + goto exit; + + rvu_eswitch_config(priv, true); + return 0; +exit: + while (--rep_id >= 0) { + rep = priv->reps[rep_id]; + unregister_netdev(rep->netdev); + rvu_rep_devlink_port_unregister(rep); + free_netdev(rep->netdev); + } + kfree(priv->reps); + rvu_rep_rsrc_free(priv); + return err; +} + +static int rvu_get_rep_cnt(struct otx2_nic *priv) +{ + struct get_rep_cnt_rsp *rsp; + struct mbox_msghdr *msghdr; + struct msg_req *req; + int err, rep; + + mutex_lock(&priv->mbox.lock); + req = otx2_mbox_alloc_msg_get_rep_cnt(&priv->mbox); + if (!req) { + mutex_unlock(&priv->mbox.lock); + return -ENOMEM; + } + err = otx2_sync_mbox_msg(&priv->mbox); + if (err) + goto exit; + + msghdr = otx2_mbox_get_rsp(&priv->mbox.mbox, 0, &req->hdr); + if (IS_ERR(msghdr)) { + err = PTR_ERR(msghdr); + goto exit; + } + + rsp = (struct get_rep_cnt_rsp *)msghdr; + priv->hw.tx_queues = rsp->rep_cnt; + priv->hw.rx_queues = rsp->rep_cnt; + priv->rep_cnt = rsp->rep_cnt; + for (rep = 0; rep < priv->rep_cnt; rep++) + priv->rep_pf_map[rep] = rsp->rep_pf_map[rep]; + +exit: + mutex_unlock(&priv->mbox.lock); + return err; +} + +static int rvu_rep_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct device *dev = &pdev->dev; + struct otx2_nic *priv; + struct otx2_hw *hw; + int err; + + err = pcim_enable_device(pdev); + if (err) { + dev_err(dev, "Failed to enable PCI device\n"); + return err; + } + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + dev_err(dev, "PCI request regions failed 0x%x\n", err); + return err; + } + + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)); + if (err) { + dev_err(dev, "DMA mask config failed, abort\n"); + goto err_release_regions; + } + + pci_set_master(pdev); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + err = -ENOMEM; + goto err_release_regions; + } + + pci_set_drvdata(pdev, priv); + priv->pdev = pdev; + priv->dev = dev; + priv->flags |= OTX2_FLAG_INTF_DOWN; + priv->flags |= OTX2_FLAG_REP_MODE_ENABLED; + + hw = &priv->hw; + hw->pdev = pdev; + hw->max_queues = OTX2_MAX_CQ_CNT; + hw->rbuf_len = OTX2_DEFAULT_RBUF_LEN; + hw->xqe_size = 128; + + err = otx2_init_rsrc(pdev, priv); + if (err) + goto err_release_regions; + + priv->iommu_domain = iommu_get_domain_for_dev(dev); + + err = rvu_get_rep_cnt(priv); + if (err) + goto err_detach_rsrc; + + err = otx2_register_dl(priv); + if (err) + goto err_detach_rsrc; + + return 0; + +err_detach_rsrc: + if (priv->hw.lmt_info) + free_percpu(priv->hw.lmt_info); + if (test_bit(CN10K_LMTST, &priv->hw.cap_flag)) + qmem_free(priv->dev, priv->dync_lmt); + otx2_detach_resources(&priv->mbox); + otx2_disable_mbox_intr(priv); + otx2_pfaf_mbox_destroy(priv); + pci_free_irq_vectors(pdev); +err_release_regions: + pci_set_drvdata(pdev, NULL); + pci_release_regions(pdev); + return err; +} + +static void rvu_rep_remove(struct pci_dev *pdev) +{ + struct otx2_nic *priv = pci_get_drvdata(pdev); + + otx2_unregister_dl(priv); + if (!(priv->flags & OTX2_FLAG_INTF_DOWN)) + rvu_rep_destroy(priv); + otx2_detach_resources(&priv->mbox); + if (priv->hw.lmt_info) + free_percpu(priv->hw.lmt_info); + if (test_bit(CN10K_LMTST, &priv->hw.cap_flag)) + qmem_free(priv->dev, priv->dync_lmt); + otx2_disable_mbox_intr(priv); + otx2_pfaf_mbox_destroy(priv); + pci_free_irq_vectors(priv->pdev); + pci_set_drvdata(pdev, NULL); + pci_release_regions(pdev); +} + +static struct pci_driver rvu_rep_driver = { + .name = DRV_NAME, + .id_table = rvu_rep_id_table, + .probe = rvu_rep_probe, + .remove = rvu_rep_remove, + .shutdown = rvu_rep_remove, +}; + +static int __init rvu_rep_init_module(void) +{ + return pci_register_driver(&rvu_rep_driver); +} + +static void __exit rvu_rep_cleanup_module(void) +{ + pci_unregister_driver(&rvu_rep_driver); +} + +module_init(rvu_rep_init_module); +module_exit(rvu_rep_cleanup_module); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/rep.h b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h new file mode 100644 index 00000000000000..38446b3e4f13cc --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/rep.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell RVU REPRESENTOR driver + * + * Copyright (C) 2024 Marvell. + * + */ + +#ifndef REP_H +#define REP_H + +#include + +#include "otx2_reg.h" +#include "otx2_txrx.h" +#include "otx2_common.h" + +#define PCI_DEVID_RVU_REP 0xA0E0 + +#define RVU_MAX_REP OTX2_MAX_CQ_CNT + +struct rep_stats { + u64 rx_bytes; + u64 rx_frames; + u64 rx_drops; + u64 rx_mcast_frames; + + u64 tx_bytes; + u64 tx_frames; + u64 tx_drops; +}; + +struct rep_dev { + struct otx2_nic *mdev; + struct net_device *netdev; + struct rep_stats stats; + struct delayed_work stats_wrk; + struct devlink_port dl_port; + struct otx2_flow_config *flow_cfg; +#define RVU_REP_VF_INITIALIZED BIT_ULL(0) + u64 flags; + u16 rep_id; + u16 pcifunc; + u8 mac[ETH_ALEN]; +}; + +static inline bool otx2_rep_dev(struct pci_dev *pdev) +{ + return pdev->device == PCI_DEVID_RVU_REP; +} + +int rvu_rep_create(struct otx2_nic *priv, struct netlink_ext_ack *extack); +void rvu_rep_destroy(struct otx2_nic *priv); +int rvu_event_up_notify(struct otx2_nic *pf, struct rep_event *info); +#endif /* REP_H */ diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 1a59c952aa01c1..2bf426cea6ddcc 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -1394,18 +1394,15 @@ static int pxa168_eth_probe(struct platform_device *pdev) printk(KERN_NOTICE "PXA168 10/100 Ethernet Driver\n"); - clk = devm_clk_get(&pdev->dev, NULL); + clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(clk)) { - dev_err(&pdev->dev, "Fast Ethernet failed to get clock\n"); + dev_err(&pdev->dev, "Fast Ethernet failed to get and enable clock\n"); return -ENODEV; } - clk_prepare_enable(clk); dev = alloc_etherdev(sizeof(struct pxa168_eth_private)); - if (!dev) { - err = -ENOMEM; - goto err_clk; - } + if (!dev) + return -ENOMEM; platform_set_drvdata(pdev, dev); pep = netdev_priv(dev); @@ -1523,8 +1520,6 @@ static int pxa168_eth_probe(struct platform_device *pdev) mdiobus_free(pep->smi_bus); err_netdev: free_netdev(dev); -err_clk: - clk_disable_unprepare(clk); return err; } @@ -1542,7 +1537,6 @@ static void pxa168_eth_remove(struct platform_device *pdev) if (dev->phydev) phy_disconnect(dev->phydev); - clk_disable_unprepare(pep->clk); mdiobus_unregister(pep->smi_bus); mdiobus_free(pep->smi_bus); unregister_netdev(dev); @@ -1579,7 +1573,7 @@ MODULE_DEVICE_TABLE(of, pxa168_eth_of_match); static struct platform_driver pxa168_eth_driver = { .probe = pxa168_eth_probe, - .remove_new = pxa168_eth_remove, + .remove = pxa168_eth_remove, .shutdown = pxa168_eth_shutdown, .resume = pxa168_eth_resume, .suspend = pxa168_eth_suspend, diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index fcfb34561882b0..25bf6ec4428964 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -484,8 +484,7 @@ static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(skge_stats); i++) - memcpy(data + i * ETH_GSTRING_LEN, - skge_stats[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, skge_stats[i].name); break; } } diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index a7a16eac189134..3914cd9210d49a 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -3800,8 +3800,7 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data) switch (stringset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(sky2_stats); i++) - memcpy(data + i * ETH_GSTRING_LEN, - sky2_stats[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, sky2_stats[i].name); break; } } diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c index 2c26eb18528372..6c683a12d5aa52 100644 --- a/drivers/net/ethernet/mediatek/airoha_eth.c +++ b/drivers/net/ethernet/mediatek/airoha_eth.c @@ -554,7 +554,7 @@ #define FWD_DSCP_LOW_THR_MASK GENMASK(17, 0) #define REG_EGRESS_RATE_METER_CFG 0x100c -#define EGRESS_RATE_METER_EN_MASK BIT(29) +#define EGRESS_RATE_METER_EN_MASK BIT(31) #define EGRESS_RATE_METER_EQ_RATE_EN_MASK BIT(17) #define EGRESS_RATE_METER_WINDOW_SZ_MASK GENMASK(16, 12) #define EGRESS_RATE_METER_TIMESLICE_MASK GENMASK(10, 0) @@ -752,11 +752,9 @@ struct airoha_tx_irq_queue { struct airoha_qdma *qdma; struct napi_struct napi; - u32 *q; int size; - int queued; - u16 head; + u32 *q; }; struct airoha_hw_stats { @@ -1116,17 +1114,23 @@ static void airoha_fe_set_pse_queue_rsv_pages(struct airoha_eth *eth, PSE_CFG_WR_EN_MASK | PSE_CFG_OQRSV_SEL_MASK); } +static u32 airoha_fe_get_pse_all_rsv(struct airoha_eth *eth) +{ + u32 val = airoha_fe_rr(eth, REG_FE_PSE_BUF_SET); + + return FIELD_GET(PSE_ALLRSV_MASK, val); +} + static int airoha_fe_set_pse_oq_rsv(struct airoha_eth *eth, u32 port, u32 queue, u32 val) { - u32 orig_val, tmp, all_rsv, fq_limit; + u32 orig_val = airoha_fe_get_pse_queue_rsv_pages(eth, port, queue); + u32 tmp, all_rsv, fq_limit; airoha_fe_set_pse_queue_rsv_pages(eth, port, queue, val); /* modify all rsv */ - orig_val = airoha_fe_get_pse_queue_rsv_pages(eth, port, queue); - tmp = airoha_fe_rr(eth, REG_FE_PSE_BUF_SET); - all_rsv = FIELD_GET(PSE_ALLRSV_MASK, tmp); + all_rsv = airoha_fe_get_pse_all_rsv(eth); all_rsv += (val - orig_val); airoha_fe_rmw(eth, REG_FE_PSE_BUF_SET, PSE_ALLRSV_MASK, FIELD_PREP(PSE_ALLRSV_MASK, all_rsv)); @@ -1166,11 +1170,13 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth) [FE_PSE_PORT_GDM4] = 2, [FE_PSE_PORT_CDM5] = 2, }; + u32 all_rsv; int q; + all_rsv = airoha_fe_get_pse_all_rsv(eth); /* hw misses PPE2 oq rsv */ - airoha_fe_set(eth, REG_FE_PSE_BUF_SET, - PSE_RSV_PAGES * pse_port_num_queues[FE_PSE_PORT_PPE2]); + all_rsv += PSE_RSV_PAGES * pse_port_num_queues[FE_PSE_PORT_PPE2]; + airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv); /* CMD1 */ for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_CDM1]; q++) @@ -1363,7 +1369,8 @@ static int airoha_fe_init(struct airoha_eth *eth) airoha_fe_set(eth, REG_GDM_MISC_CFG, GDM2_RDM_ACK_WAIT_PREF_MASK | GDM2_CHN_VLD_MODE_MASK); - airoha_fe_rmw(eth, REG_CDM2_FWD_CFG, CDM2_OAM_QSEL_MASK, 15); + airoha_fe_rmw(eth, REG_CDM2_FWD_CFG, CDM2_OAM_QSEL_MASK, + FIELD_PREP(CDM2_OAM_QSEL_MASK, 15)); /* init fragment and assemble Force Port */ /* NPU Core-3, NPU Bridge Channel-3 */ @@ -1647,30 +1654,38 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma) static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) { struct airoha_tx_irq_queue *irq_q; + int id, done = 0, irq_queued; struct airoha_qdma *qdma; struct airoha_eth *eth; - int id, done = 0; + u32 status, head; irq_q = container_of(napi, struct airoha_tx_irq_queue, napi); qdma = irq_q->qdma; id = irq_q - &qdma->q_tx_irq[0]; eth = qdma->eth; - while (irq_q->queued > 0 && done < budget) { - u32 qid, last, val = irq_q->q[irq_q->head]; + status = airoha_qdma_rr(qdma, REG_IRQ_STATUS(id)); + head = FIELD_GET(IRQ_HEAD_IDX_MASK, status); + head = head % irq_q->size; + irq_queued = FIELD_GET(IRQ_ENTRY_LEN_MASK, status); + + while (irq_queued > 0 && done < budget) { + u32 qid, val = irq_q->q[head]; + struct airoha_qdma_desc *desc; + struct airoha_queue_entry *e; struct airoha_queue *q; + u32 index, desc_ctrl; + struct sk_buff *skb; if (val == 0xff) break; - irq_q->q[irq_q->head] = 0xff; /* mark as done */ - irq_q->head = (irq_q->head + 1) % irq_q->size; - irq_q->queued--; + irq_q->q[head] = 0xff; /* mark as done */ + head = (head + 1) % irq_q->size; + irq_queued--; done++; - last = FIELD_GET(IRQ_DESC_IDX_MASK, val); qid = FIELD_GET(IRQ_RING_IDX_MASK, val); - if (qid >= ARRAY_SIZE(qdma->q_tx)) continue; @@ -1678,44 +1693,53 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) if (!q->ndesc) continue; + index = FIELD_GET(IRQ_DESC_IDX_MASK, val); + if (index >= q->ndesc) + continue; + spin_lock_bh(&q->lock); - while (q->queued > 0) { - struct airoha_qdma_desc *desc = &q->desc[q->tail]; - struct airoha_queue_entry *e = &q->entry[q->tail]; - u32 desc_ctrl = le32_to_cpu(desc->ctrl); - struct sk_buff *skb = e->skb; - u16 index = q->tail; + if (!q->queued) + goto unlock; - if (!(desc_ctrl & QDMA_DESC_DONE_MASK) && - !(desc_ctrl & QDMA_DESC_DROP_MASK)) - break; + desc = &q->desc[index]; + desc_ctrl = le32_to_cpu(desc->ctrl); - q->tail = (q->tail + 1) % q->ndesc; - q->queued--; + if (!(desc_ctrl & QDMA_DESC_DONE_MASK) && + !(desc_ctrl & QDMA_DESC_DROP_MASK)) + goto unlock; - dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, - DMA_TO_DEVICE); + e = &q->entry[index]; + skb = e->skb; - WRITE_ONCE(desc->msg0, 0); - WRITE_ONCE(desc->msg1, 0); + dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, + DMA_TO_DEVICE); + memset(e, 0, sizeof(*e)); + WRITE_ONCE(desc->msg0, 0); + WRITE_ONCE(desc->msg1, 0); + q->queued--; - if (skb) { - struct netdev_queue *txq; + /* completion ring can report out-of-order indexes if hw QoS + * is enabled and packets with different priority are queued + * to same DMA ring. Take into account possible out-of-order + * reports incrementing DMA ring tail pointer + */ + while (q->tail != q->head && !q->entry[q->tail].dma_addr) + q->tail = (q->tail + 1) % q->ndesc; - txq = netdev_get_tx_queue(skb->dev, qid); - if (netif_tx_queue_stopped(txq) && - q->ndesc - q->queued >= q->free_thr) - netif_tx_wake_queue(txq); + if (skb) { + u16 queue = skb_get_queue_mapping(skb); + struct netdev_queue *txq; - dev_kfree_skb_any(skb); - e->skb = NULL; - } + txq = netdev_get_tx_queue(skb->dev, queue); + netdev_tx_completed_queue(txq, 1, skb->len); + if (netif_tx_queue_stopped(txq) && + q->ndesc - q->queued >= q->free_thr) + netif_tx_wake_queue(txq); - if (index == last) - break; + dev_kfree_skb_any(skb); } - +unlock: spin_unlock_bh(&q->lock); } @@ -2015,20 +2039,11 @@ static irqreturn_t airoha_irq_handler(int irq, void *dev_instance) if (intr[0] & INT_TX_MASK) { for (i = 0; i < ARRAY_SIZE(qdma->q_tx_irq); i++) { - struct airoha_tx_irq_queue *irq_q = &qdma->q_tx_irq[i]; - u32 status, head; - if (!(intr[0] & TX_DONE_INT_MASK(i))) continue; airoha_qdma_irq_disable(qdma, QDMA_INT_REG_IDX0, TX_DONE_INT_MASK(i)); - - status = airoha_qdma_rr(qdma, REG_IRQ_STATUS(i)); - head = FIELD_GET(IRQ_HEAD_IDX_MASK, status); - irq_q->head = head % irq_q->size; - irq_q->queued = FIELD_GET(IRQ_ENTRY_LEN_MASK, status); - napi_schedule(&qdma->q_tx_irq[i].napi); } } @@ -2331,7 +2346,7 @@ static int airoha_dev_stop(struct net_device *dev) { struct airoha_gdm_port *port = netdev_priv(dev); struct airoha_qdma *qdma = port->qdma; - int err; + int i, err; netif_tx_disable(dev); err = airoha_set_gdm_ports(qdma->eth, false); @@ -2342,6 +2357,14 @@ static int airoha_dev_stop(struct net_device *dev) GLOBAL_CFG_TX_DMA_EN_MASK | GLOBAL_CFG_RX_DMA_EN_MASK); + for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { + if (!qdma->q_tx[i].ndesc) + continue; + + airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); + netdev_tx_reset_subqueue(dev, i); + } + return 0; } @@ -2479,7 +2502,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, q->queued += i; skb_tx_timestamp(skb); - if (!netdev_xmit_more()) + netdev_tx_sent_queue(txq, skb->len); + + if (netif_xmit_stopped(txq) || !netdev_xmit_more()) airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head)); @@ -2780,7 +2805,7 @@ MODULE_DEVICE_TABLE(of, of_airoha_match); static struct platform_driver airoha_driver = { .probe = airoha_probe, - .remove_new = airoha_remove, + .remove = airoha_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_airoha_match, diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index ed7313c10a0524..53485142938c47 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2227,7 +2227,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, eth->rx_bytes += bytes; dim_update_sample(eth->rx_events, eth->rx_packets, eth->rx_bytes, &dim_sample); - net_dim(ð->rx_dim, dim_sample); + net_dim(ð->rx_dim, &dim_sample); if (xdp_flush) xdp_do_flush(); @@ -2377,7 +2377,7 @@ static int mtk_poll_tx(struct mtk_eth *eth, int budget) dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes, &dim_sample); - net_dim(ð->tx_dim, dim_sample); + net_dim(ð->tx_dim, &dim_sample); if (mtk_queue_stopped(eth) && (atomic_read(&ring->free_count) > ring->thresh)) @@ -4329,10 +4329,8 @@ static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data) case ETH_SS_STATS: { struct mtk_mac *mac = netdev_priv(dev); - for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) { - memcpy(data, mtk_ethtool_stats[i].str, ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } + for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) + ethtool_puts(&data, mtk_ethtool_stats[i].str); if (mtk_page_pool_enabled(mac->hw)) page_pool_ethtool_stats_get_strings(data); break; @@ -5358,7 +5356,7 @@ MODULE_DEVICE_TABLE(of, of_mtk_match); static struct platform_driver mtk_driver = { .probe = mtk_probe, - .remove_new = mtk_remove, + .remove = mtk_remove, .driver = { .name = "mtk_soc_eth", .of_match_table = of_mtk_match, diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 461cc2c79c71f5..0e92956e84cfcb 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -156,7 +156,8 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, break; case RX: cq->mcq.comp = mlx4_en_rx_irq; - netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq); + netif_napi_add_config(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, + cq_idx); netif_napi_set_irq(&cq->napi, irq); napi_enable(&cq->napi); netif_queue_set_napi(cq->dev, cq_idx, NETDEV_QUEUE_TYPE_RX, &cq->napi); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 5912f7e614f9c0..be3d0876c521d1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -109,35 +109,48 @@ mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/ktls_stats.o \ en_accel/fs_tcp.o en_accel/ktls.o en_accel/ktls_txrx.o \ en_accel/ktls_tx.o en_accel/ktls_rx.o -mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \ - steering/dr_matcher.o steering/dr_rule.o \ - steering/dr_icm_pool.o steering/dr_buddy.o \ - steering/dr_ste.o steering/dr_send.o \ - steering/dr_ste_v0.o steering/dr_ste_v1.o \ - steering/dr_ste_v2.o \ - steering/dr_cmd.o steering/dr_fw.o \ - steering/dr_action.o steering/fs_dr.o \ - steering/dr_definer.o steering/dr_ptrn.o \ - steering/dr_arg.o steering/dr_dbg.o lib/smfs.o +# +# SW Steering +# +mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/sws/dr_domain.o \ + steering/sws/dr_table.o \ + steering/sws/dr_matcher.o \ + steering/sws/dr_rule.o \ + steering/sws/dr_icm_pool.o \ + steering/sws/dr_buddy.o \ + steering/sws/dr_ste.o \ + steering/sws/dr_send.o \ + steering/sws/dr_ste_v0.o \ + steering/sws/dr_ste_v1.o \ + steering/sws/dr_ste_v2.o \ + steering/sws/dr_cmd.o \ + steering/sws/dr_fw.o \ + steering/sws/dr_action.o \ + steering/sws/dr_definer.o \ + steering/sws/dr_ptrn.o \ + steering/sws/dr_arg.o \ + steering/sws/dr_dbg.o \ + steering/sws/fs_dr.o \ + lib/smfs.o # # HW Steering # -mlx5_core-$(CONFIG_MLX5_HW_STEERING) += steering/hws/mlx5hws_cmd.o \ - steering/hws/mlx5hws_context.o \ - steering/hws/mlx5hws_pat_arg.o \ - steering/hws/mlx5hws_buddy.o \ - steering/hws/mlx5hws_pool.o \ - steering/hws/mlx5hws_table.o \ - steering/hws/mlx5hws_action.o \ - steering/hws/mlx5hws_rule.o \ - steering/hws/mlx5hws_matcher.o \ - steering/hws/mlx5hws_send.o \ - steering/hws/mlx5hws_definer.o \ - steering/hws/mlx5hws_bwc.o \ - steering/hws/mlx5hws_debug.o \ - steering/hws/mlx5hws_vport.o \ - steering/hws/mlx5hws_bwc_complex.o +mlx5_core-$(CONFIG_MLX5_HW_STEERING) += steering/hws/cmd.o \ + steering/hws/context.o \ + steering/hws/pat_arg.o \ + steering/hws/buddy.o \ + steering/hws/pool.o \ + steering/hws/table.o \ + steering/hws/action.o \ + steering/hws/rule.o \ + steering/hws/matcher.o \ + steering/hws/send.o \ + steering/hws/definer.o \ + steering/hws/bwc.o \ + steering/hws/debug.o \ + steering/hws/vport.o \ + steering/hws/bwc_complex.o # diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cq.c b/drivers/net/ethernet/mellanox/mlx5/core/cq.c index 4caa1b6f40ba43..1fd403713bafc5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cq.c @@ -71,6 +71,7 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, { unsigned long flags; struct mlx5_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv; + bool schedule_tasklet = false; spin_lock_irqsave(&tasklet_ctx->lock, flags); /* When migrating CQs between EQs will be implemented, please note @@ -80,9 +81,19 @@ static void mlx5_add_cq_to_tasklet(struct mlx5_core_cq *cq, */ if (list_empty_careful(&cq->tasklet_ctx.list)) { mlx5_cq_hold(cq); + /* If the tasklet CQ work list isn't empty, mlx5_cq_tasklet_cb() + * is scheduled/running and hasn't processed the list yet, so it + * will see this added CQ when it runs. If the list is empty, + * the tasklet needs to be scheduled to pick up the CQ. The + * spinlock avoids any race with the tasklet accessing the list. + */ + schedule_tasklet = list_empty(&tasklet_ctx->list); list_add_tail(&cq->tasklet_ctx.list, &tasklet_ctx->list); } spin_unlock_irqrestore(&tasklet_ctx->lock, flags); + + if (schedule_tasklet) + tasklet_schedule(&tasklet_ctx->task); } /* Callers must verify outbox status in case of err */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 904e08de852eac..31142f6cc37293 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -166,9 +166,90 @@ static int mlx5_dpll_device_mode_get(const struct dpll_device *dpll, return 0; } +enum { + MLX5_DPLL_SSM_CODE_PRC = 0b0010, + MLX5_DPLL_SSM_CODE_SSU_A = 0b0100, + MLX5_DPLL_SSM_CODE_SSU_B = 0b1000, + MLX5_DPLL_SSM_CODE_EEC1 = 0b1011, + MLX5_DPLL_SSM_CODE_PRTC = 0b0010, + MLX5_DPLL_SSM_CODE_EPRTC = 0b0010, + MLX5_DPLL_SSM_CODE_EEEC = 0b1011, + MLX5_DPLL_SSM_CODE_EPRC = 0b0010, +}; + +enum { + MLX5_DPLL_ENHANCED_SSM_CODE_PRC = 0xff, + MLX5_DPLL_ENHANCED_SSM_CODE_SSU_A = 0xff, + MLX5_DPLL_ENHANCED_SSM_CODE_SSU_B = 0xff, + MLX5_DPLL_ENHANCED_SSM_CODE_EEC1 = 0xff, + MLX5_DPLL_ENHANCED_SSM_CODE_PRTC = 0x20, + MLX5_DPLL_ENHANCED_SSM_CODE_EPRTC = 0x21, + MLX5_DPLL_ENHANCED_SSM_CODE_EEEC = 0x22, + MLX5_DPLL_ENHANCED_SSM_CODE_EPRC = 0x23, +}; + +#define __MLX5_DPLL_SSM_COMBINED_CODE(ssm_code, enhanced_ssm_code) \ + ((ssm_code) | ((enhanced_ssm_code) << 8)) + +#define MLX5_DPLL_SSM_COMBINED_CODE(type) \ + __MLX5_DPLL_SSM_COMBINED_CODE(MLX5_DPLL_SSM_CODE_##type, \ + MLX5_DPLL_ENHANCED_SSM_CODE_##type) + +static int mlx5_dpll_clock_quality_level_get(const struct dpll_device *dpll, + void *priv, unsigned long *qls, + struct netlink_ext_ack *extack) +{ + u8 network_option, ssm_code, enhanced_ssm_code; + u32 out[MLX5_ST_SZ_DW(msecq_reg)] = {}; + u32 in[MLX5_ST_SZ_DW(msecq_reg)] = {}; + struct mlx5_dpll *mdpll = priv; + int err; + + err = mlx5_core_access_reg(mdpll->mdev, in, sizeof(in), + out, sizeof(out), MLX5_REG_MSECQ, 0, 0); + if (err) + return err; + network_option = MLX5_GET(msecq_reg, out, network_option); + if (network_option != 1) + goto errout; + ssm_code = MLX5_GET(msecq_reg, out, local_ssm_code); + enhanced_ssm_code = MLX5_GET(msecq_reg, out, local_enhanced_ssm_code); + + switch (__MLX5_DPLL_SSM_COMBINED_CODE(ssm_code, enhanced_ssm_code)) { + case MLX5_DPLL_SSM_COMBINED_CODE(PRC): + __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRC, qls); + return 0; + case MLX5_DPLL_SSM_COMBINED_CODE(SSU_A): + __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_A, qls); + return 0; + case MLX5_DPLL_SSM_COMBINED_CODE(SSU_B): + __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_SSU_B, qls); + return 0; + case MLX5_DPLL_SSM_COMBINED_CODE(EEC1): + __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEC1, qls); + return 0; + case MLX5_DPLL_SSM_COMBINED_CODE(PRTC): + __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_PRTC, qls); + return 0; + case MLX5_DPLL_SSM_COMBINED_CODE(EPRTC): + __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRTC, qls); + return 0; + case MLX5_DPLL_SSM_COMBINED_CODE(EEEC): + __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EEEC, qls); + return 0; + case MLX5_DPLL_SSM_COMBINED_CODE(EPRC): + __set_bit(DPLL_CLOCK_QUALITY_LEVEL_ITU_OPT1_EPRC, qls); + return 0; + } +errout: + NL_SET_ERR_MSG_MOD(extack, "Invalid clock quality level obtained from firmware\n"); + return -EINVAL; +} + static const struct dpll_device_ops mlx5_dpll_device_ops = { .lock_status_get = mlx5_dpll_device_lock_status_get, .mode_get = mlx5_dpll_device_mode_get, + .clock_quality_level_get = mlx5_dpll_clock_quality_level_get, }; static int mlx5_dpll_pin_direction_get(const struct dpll_pin *pin, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 57b7298a0e793c..979fc56205e1fe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -83,6 +83,7 @@ struct page_pool; #define MLX5E_SHAMPO_LOG_HEADER_ENTRY_SIZE (8) #define MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE (9) #define MLX5E_SHAMPO_WQ_HEADER_PER_PAGE (PAGE_SIZE >> MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE) +#define MLX5E_SHAMPO_LOG_WQ_HEADER_PER_PAGE (PAGE_SHIFT - MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE) #define MLX5E_SHAMPO_WQ_BASE_HEAD_ENTRY_SIZE (64) #define MLX5E_SHAMPO_WQ_RESRV_SIZE (64 * 1024) #define MLX5E_SHAMPO_WQ_BASE_RESRV_SIZE (4096) @@ -624,16 +625,14 @@ struct mlx5e_dma_info { struct mlx5e_shampo_hd { u32 mkey; - struct mlx5e_dma_info *info; struct mlx5e_frag_page *pages; - u16 curr_page_index; u32 hd_per_wq; u16 hd_per_wqe; + u16 pages_per_wq; unsigned long *bitmap; u16 pi; u16 ci; __be32 key; - u64 last_addr; }; struct mlx5e_hw_gro_data { @@ -755,7 +754,7 @@ struct mlx5e_channel { u8 lag_port; /* XDP_REDIRECT */ - struct mlx5e_xdpsq xdpsq; + struct mlx5e_xdpsq *xdpsq; /* AF_XDP zero-copy */ struct mlx5e_rq xskrq; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c index 1c062a2e8996e7..45737d039252fd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/ct_fs_smfs.c @@ -318,7 +318,7 @@ mlx5_ct_fs_smfs_ct_rule_add(struct mlx5_ct_fs *fs, struct mlx5_flow_spec *spec, } actions[num_actions++] = smfs_rule->count_action; - actions[num_actions++] = attr->modify_hdr->action.dr_action; + actions[num_actions++] = attr->modify_hdr->fs_dr_action.dr_action; actions[num_actions++] = fs_smfs->fwd_action; nat = (attr->ft == fs_smfs->ct_nat); @@ -379,7 +379,7 @@ static int mlx5_ct_fs_smfs_ct_rule_update(struct mlx5_ct_fs *fs, struct mlx5_ct_ struct mlx5dr_rule *rule; actions[0] = smfs_rule->count_action; - actions[1] = attr->modify_hdr->action.dr_action; + actions[1] = attr->modify_hdr->fs_dr_action.dr_action; actions[2] = fs_smfs->fwd_action; rule = mlx5_smfs_rule_create(smfs_rule->smfs_matcher->dr_matcher, spec, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c index 92d5cfec3dc018..a84ebac2f011ad 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c @@ -1026,7 +1026,7 @@ mlx5_tc_ct_counter_create(struct mlx5_tc_ct_priv *ct_priv) return ERR_PTR(-ENOMEM); counter->is_shared = false; - counter->counter = mlx5_fc_create_ex(ct_priv->dev, true); + counter->counter = mlx5_fc_create(ct_priv->dev, true); if (IS_ERR(counter->counter)) { ct_dbg("Failed to create counter for ct entry"); ret = PTR_ERR(counter->counter); 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 878cbdbf5ec8b4..e7e01f3298efb0 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 @@ -5,6 +5,7 @@ #include #include #include "tc_tun_encap.h" +#include "fs_core.h" #include "en_tc.h" #include "tc_tun.h" #include "rep/tc.h" @@ -24,10 +25,18 @@ static int mlx5e_set_int_port_tunnel(struct mlx5e_priv *priv, route_dev = dev_get_by_index(dev_net(e->out_dev), e->route_dev_ifindex); - if (!route_dev || !netif_is_ovs_master(route_dev) || - attr->parse_attr->filter_dev == e->out_dev) + if (!route_dev || !netif_is_ovs_master(route_dev)) goto out; + if (priv->mdev->priv.steering->mode == MLX5_FLOW_STEERING_MODE_DMFS && + mlx5e_eswitch_uplink_rep(attr->parse_attr->filter_dev) && + (attr->esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP)) { + mlx5_core_warn(priv->mdev, + "Matching on external port with encap + fwd to table actions is not allowed for firmware steering\n"); + err = -EINVAL; + goto out; + } + err = mlx5e_set_fwd_to_int_port_actions(priv, attr, e->route_dev_ifindex, MLX5E_TC_INT_PORT_EGRESS, &attr->action, out_index); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c index 4610621a340e50..94b2916620873c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c @@ -865,7 +865,7 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, if (unlikely(sq_num >= priv->channels.num)) return -ENXIO; - sq = &priv->channels.c[sq_num]->xdpsq; + sq = priv->channels.c[sq_num]->xdpsq; for (i = 0; i < n; i++) { struct mlx5e_xmit_data_frags xdptxdf = {}; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 1966736f98b4af..cae39198b4dbc7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -406,6 +406,9 @@ int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv, unlock: mutex_unlock(&priv->state_lock); + if (!err) + netdev_update_features(priv->netdev); + return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 13a3fa8dc0cb09..dd16d73000c312 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -350,19 +350,15 @@ static int mlx5e_rq_shampo_hd_info_alloc(struct mlx5e_rq *rq, int node) shampo->bitmap = bitmap_zalloc_node(shampo->hd_per_wq, GFP_KERNEL, node); - shampo->info = kvzalloc_node(array_size(shampo->hd_per_wq, - sizeof(*shampo->info)), - GFP_KERNEL, node); shampo->pages = kvzalloc_node(array_size(shampo->hd_per_wq, sizeof(*shampo->pages)), GFP_KERNEL, node); - if (!shampo->bitmap || !shampo->info || !shampo->pages) + if (!shampo->bitmap || !shampo->pages) goto err_nomem; return 0; err_nomem: - kvfree(shampo->info); kvfree(shampo->bitmap); kvfree(shampo->pages); @@ -372,7 +368,6 @@ static int mlx5e_rq_shampo_hd_info_alloc(struct mlx5e_rq *rq, int node) static void mlx5e_rq_shampo_hd_info_free(struct mlx5e_rq *rq) { kvfree(rq->mpwqe.shampo->bitmap); - kvfree(rq->mpwqe.shampo->info); kvfree(rq->mpwqe.shampo->pages); } @@ -767,8 +762,6 @@ static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev, u32 *pool_size, int node) { - void *wqc = MLX5_ADDR_OF(rqc, rqp->rqc, wq); - int wq_size; int err; if (!test_bit(MLX5E_RQ_STATE_SHAMPO, &rq->state)) @@ -793,9 +786,9 @@ static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev, cpu_to_be32(rq->mpwqe.shampo->mkey); rq->mpwqe.shampo->hd_per_wqe = mlx5e_shampo_hd_per_wqe(mdev, params, rqp); - wq_size = BIT(MLX5_GET(wq, wqc, log_wq_sz)); - *pool_size += (rq->mpwqe.shampo->hd_per_wqe * wq_size) / - MLX5E_SHAMPO_WQ_HEADER_PER_PAGE; + rq->mpwqe.shampo->pages_per_wq = + rq->mpwqe.shampo->hd_per_wq / MLX5E_SHAMPO_WQ_HEADER_PER_PAGE; + *pool_size += rq->mpwqe.shampo->pages_per_wq; return 0; err_hw_gro_data: @@ -1126,7 +1119,7 @@ static void mlx5e_flush_rq_cq(struct mlx5e_rq *rq) struct mlx5_cqe64 *cqe; if (test_bit(MLX5E_RQ_STATE_MINI_CQE_ENHANCED, &rq->state)) { - while ((cqe = mlx5_cqwq_get_cqe_enahnced_comp(cqwq))) + while ((cqe = mlx5_cqwq_get_cqe_enhanced_comp(cqwq))) mlx5_cqwq_pop(cqwq); } else { while ((cqe = mlx5_cqwq_get_cqe(cqwq))) @@ -2086,6 +2079,44 @@ void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq) mlx5e_free_xdpsq(sq); } +static struct mlx5e_xdpsq *mlx5e_open_xdpredirect_sq(struct mlx5e_channel *c, + struct mlx5e_params *params, + struct mlx5e_channel_param *cparam, + struct mlx5e_create_cq_param *ccp) +{ + struct mlx5e_xdpsq *xdpsq; + int err; + + xdpsq = kvzalloc_node(sizeof(*xdpsq), GFP_KERNEL, c->cpu); + if (!xdpsq) + return ERR_PTR(-ENOMEM); + + err = mlx5e_open_cq(c->mdev, params->tx_cq_moderation, + &cparam->xdp_sq.cqp, ccp, &xdpsq->cq); + if (err) + goto err_free_xdpsq; + + err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, NULL, xdpsq, true); + if (err) + goto err_close_xdpsq_cq; + + return xdpsq; + +err_close_xdpsq_cq: + mlx5e_close_cq(&xdpsq->cq); +err_free_xdpsq: + kvfree(xdpsq); + + return ERR_PTR(err); +} + +static void mlx5e_close_xdpredirect_sq(struct mlx5e_xdpsq *xdpsq) +{ + mlx5e_close_xdpsq(xdpsq); + mlx5e_close_cq(&xdpsq->cq); + kvfree(xdpsq); +} + static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev, struct net_device *netdev, struct workqueue_struct *workqueue, @@ -2476,6 +2507,7 @@ static int mlx5e_open_queues(struct mlx5e_channel *c, struct mlx5e_params *params, struct mlx5e_channel_param *cparam) { + const struct net_device_ops *netdev_ops = c->netdev->netdev_ops; struct dim_cq_moder icocq_moder = {0, 0}; struct mlx5e_create_cq_param ccp; int err; @@ -2496,15 +2528,18 @@ static int mlx5e_open_queues(struct mlx5e_channel *c, if (err) goto err_close_icosq_cq; - err = mlx5e_open_cq(c->mdev, params->tx_cq_moderation, &cparam->xdp_sq.cqp, &ccp, - &c->xdpsq.cq); - if (err) - goto err_close_tx_cqs; + if (netdev_ops->ndo_xdp_xmit) { + c->xdpsq = mlx5e_open_xdpredirect_sq(c, params, cparam, &ccp); + if (IS_ERR(c->xdpsq)) { + err = PTR_ERR(c->xdpsq); + goto err_close_tx_cqs; + } + } err = mlx5e_open_cq(c->mdev, params->rx_cq_moderation, &cparam->rq.cqp, &ccp, &c->rq.cq); if (err) - goto err_close_xdp_tx_cqs; + goto err_close_xdpredirect_sq; err = c->xdp ? mlx5e_open_cq(c->mdev, params->tx_cq_moderation, &cparam->xdp_sq.cqp, &ccp, &c->rq_xdpsq.cq) : 0; @@ -2516,7 +2551,7 @@ static int mlx5e_open_queues(struct mlx5e_channel *c, err = mlx5e_open_icosq(c, params, &cparam->async_icosq, &c->async_icosq, mlx5e_async_icosq_err_cqe_work); if (err) - goto err_close_xdpsq_cq; + goto err_close_rq_xdpsq_cq; mutex_init(&c->icosq_recovery_lock); @@ -2540,16 +2575,8 @@ static int mlx5e_open_queues(struct mlx5e_channel *c, goto err_close_rq; } - err = mlx5e_open_xdpsq(c, params, &cparam->xdp_sq, NULL, &c->xdpsq, true); - if (err) - goto err_close_xdp_sq; - return 0; -err_close_xdp_sq: - if (c->xdp) - mlx5e_close_xdpsq(&c->rq_xdpsq); - err_close_rq: mlx5e_close_rq(&c->rq); @@ -2562,15 +2589,16 @@ static int mlx5e_open_queues(struct mlx5e_channel *c, err_close_async_icosq: mlx5e_close_icosq(&c->async_icosq); -err_close_xdpsq_cq: +err_close_rq_xdpsq_cq: if (c->xdp) mlx5e_close_cq(&c->rq_xdpsq.cq); err_close_rx_cq: mlx5e_close_cq(&c->rq.cq); -err_close_xdp_tx_cqs: - mlx5e_close_cq(&c->xdpsq.cq); +err_close_xdpredirect_sq: + if (c->xdpsq) + mlx5e_close_xdpredirect_sq(c->xdpsq); err_close_tx_cqs: mlx5e_close_tx_cqs(c); @@ -2586,7 +2614,6 @@ static int mlx5e_open_queues(struct mlx5e_channel *c, static void mlx5e_close_queues(struct mlx5e_channel *c) { - mlx5e_close_xdpsq(&c->xdpsq); if (c->xdp) mlx5e_close_xdpsq(&c->rq_xdpsq); /* The same ICOSQ is used for UMRs for both RQ and XSKRQ. */ @@ -2599,7 +2626,8 @@ static void mlx5e_close_queues(struct mlx5e_channel *c) if (c->xdp) mlx5e_close_cq(&c->rq_xdpsq.cq); mlx5e_close_cq(&c->rq.cq); - mlx5e_close_cq(&c->xdpsq.cq); + if (c->xdpsq) + mlx5e_close_xdpredirect_sq(c->xdpsq); mlx5e_close_tx_cqs(c); mlx5e_close_cq(&c->icosq.cq); mlx5e_close_cq(&c->async_icosq.cq); @@ -2652,11 +2680,11 @@ void mlx5e_trigger_napi_sched(struct napi_struct *napi) static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, struct mlx5e_params *params, - struct mlx5e_channel_param *cparam, struct xsk_buff_pool *xsk_pool, struct mlx5e_channel **cp) { struct net_device *netdev = priv->netdev; + struct mlx5e_channel_param *cparam; struct mlx5_core_dev *mdev; struct mlx5e_xsk_param xsk; struct mlx5e_channel *c; @@ -2678,8 +2706,15 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, return err; c = kvzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu)); - if (!c) - return -ENOMEM; + cparam = kvzalloc(sizeof(*cparam), GFP_KERNEL); + if (!c || !cparam) { + err = -ENOMEM; + goto err_free; + } + + err = mlx5e_build_channel_param(mdev, params, cparam); + if (err) + goto err_free; c->priv = priv; c->mdev = mdev; @@ -2697,7 +2732,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, c->aff_mask = irq_get_effective_affinity_mask(irq); c->lag_port = mlx5e_enumerate_lag_port(mdev, ix); - netif_napi_add(netdev, &c->napi, mlx5e_napi_poll); + netif_napi_add_config(netdev, &c->napi, mlx5e_napi_poll, ix); netif_napi_set_irq(&c->napi, irq); err = mlx5e_open_queues(c, params, cparam); @@ -2713,6 +2748,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, *cp = c; + kvfree(cparam); return 0; err_close_queues: @@ -2721,6 +2757,8 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, err_napi_del: netif_napi_del(&c->napi); +err_free: + kvfree(cparam); kvfree(c); return err; @@ -2779,20 +2817,14 @@ static void mlx5e_close_channel(struct mlx5e_channel *c) int mlx5e_open_channels(struct mlx5e_priv *priv, struct mlx5e_channels *chs) { - struct mlx5e_channel_param *cparam; int err = -ENOMEM; int i; chs->num = chs->params.num_channels; chs->c = kcalloc(chs->num, sizeof(struct mlx5e_channel *), GFP_KERNEL); - cparam = kvzalloc(sizeof(struct mlx5e_channel_param), GFP_KERNEL); - if (!chs->c || !cparam) - goto err_free; - - err = mlx5e_build_channel_param(priv->mdev, &chs->params, cparam); - if (err) - goto err_free; + if (!chs->c) + goto err_out; for (i = 0; i < chs->num; i++) { struct xsk_buff_pool *xsk_pool = NULL; @@ -2800,7 +2832,7 @@ int mlx5e_open_channels(struct mlx5e_priv *priv, if (chs->params.xdp_prog) xsk_pool = mlx5e_xsk_get_pool(&chs->params, chs->params.xsk, i); - err = mlx5e_open_channel(priv, i, &chs->params, cparam, xsk_pool, &chs->c[i]); + err = mlx5e_open_channel(priv, i, &chs->params, xsk_pool, &chs->c[i]); if (err) goto err_close_channels; } @@ -2818,7 +2850,6 @@ int mlx5e_open_channels(struct mlx5e_priv *priv, } mlx5e_health_channels_update(priv); - kvfree(cparam); return 0; err_close_ptp: @@ -2829,9 +2860,8 @@ int mlx5e_open_channels(struct mlx5e_priv *priv, for (i--; i >= 0; i--) mlx5e_close_channel(chs->c[i]); -err_free: kfree(chs->c); - kvfree(cparam); +err_out: chs->num = 0; return err; } @@ -4558,6 +4588,10 @@ int mlx5e_change_mtu(struct net_device *netdev, int new_mtu, out: WRITE_ONCE(netdev->mtu, params->sw_mtu); mutex_unlock(&priv->state_lock); + + if (!err) + netdev_update_features(netdev); + return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 92094bf60d5986..554f9cb5b53fd9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -600,7 +600,8 @@ mlx5e_add_sqs_fwd_rules(struct mlx5e_priv *priv) if (c->xdp) sqs[num_sqs++] = c->rq_xdpsq.sqn; - sqs[num_sqs++] = c->xdpsq.sqn; + if (c->xdpsq) + sqs[num_sqs++] = c->xdpsq->sqn; } } if (ptp_sq) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 8e24ba96c779ae..1963bc5adb1887 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -643,83 +643,82 @@ static void build_ksm_umr(struct mlx5e_icosq *sq, struct mlx5e_umr_wqe *umr_wqe, umr_wqe->uctrl.mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE); } +static struct mlx5e_frag_page *mlx5e_shampo_hd_to_frag_page(struct mlx5e_rq *rq, int header_index) +{ + BUILD_BUG_ON(MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE > PAGE_SHIFT); + + return &rq->mpwqe.shampo->pages[header_index >> MLX5E_SHAMPO_LOG_WQ_HEADER_PER_PAGE]; +} + +static u64 mlx5e_shampo_hd_offset(int header_index) +{ + return (header_index & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) << + MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE; +} + +static void mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index); + static int mlx5e_build_shampo_hd_umr(struct mlx5e_rq *rq, struct mlx5e_icosq *sq, u16 ksm_entries, u16 index) { struct mlx5e_shampo_hd *shampo = rq->mpwqe.shampo; - u16 entries, pi, header_offset, err, wqe_bbs, new_entries; + u16 pi, header_offset, err, wqe_bbs; u32 lkey = rq->mdev->mlx5e_res.hw_objs.mkey; - u16 page_index = shampo->curr_page_index; - struct mlx5e_frag_page *frag_page; - u64 addr = shampo->last_addr; - struct mlx5e_dma_info *dma_info; struct mlx5e_umr_wqe *umr_wqe; - int headroom, i; + int headroom, i = 0; headroom = rq->buff.headroom; - new_entries = ksm_entries - (shampo->pi & (MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT - 1)); - entries = ALIGN(ksm_entries, MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT); - wqe_bbs = MLX5E_KSM_UMR_WQEBBS(entries); + wqe_bbs = MLX5E_KSM_UMR_WQEBBS(ksm_entries); pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs); umr_wqe = mlx5_wq_cyc_get_wqe(&sq->wq, pi); - build_ksm_umr(sq, umr_wqe, shampo->key, index, entries); + build_ksm_umr(sq, umr_wqe, shampo->key, index, ksm_entries); - frag_page = &shampo->pages[page_index]; + WARN_ON_ONCE(ksm_entries & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)); + while (i < ksm_entries) { + struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, index); + u64 addr; - for (i = 0; i < entries; i++, index++) { - dma_info = &shampo->info[index]; - if (i >= ksm_entries || (index < shampo->pi && shampo->pi - index < - MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT)) - goto update_ksm; - header_offset = (index & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) << - MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE; - if (!(header_offset & (PAGE_SIZE - 1))) { - page_index = (page_index + 1) & (shampo->hd_per_wq - 1); - frag_page = &shampo->pages[page_index]; + err = mlx5e_page_alloc_fragmented(rq, frag_page); + if (unlikely(err)) + goto err_unmap; - err = mlx5e_page_alloc_fragmented(rq, frag_page); - if (unlikely(err)) - goto err_unmap; - addr = page_pool_get_dma_addr(frag_page->page); + addr = page_pool_get_dma_addr(frag_page->page); - dma_info->addr = addr; - dma_info->frag_page = frag_page; - } else { - dma_info->addr = addr + header_offset; - dma_info->frag_page = frag_page; - } + for (int j = 0; j < MLX5E_SHAMPO_WQ_HEADER_PER_PAGE; j++) { + header_offset = mlx5e_shampo_hd_offset(index++); -update_ksm: - umr_wqe->inline_ksms[i] = (struct mlx5_ksm) { - .key = cpu_to_be32(lkey), - .va = cpu_to_be64(dma_info->addr + headroom), - }; + umr_wqe->inline_ksms[i++] = (struct mlx5_ksm) { + .key = cpu_to_be32(lkey), + .va = cpu_to_be64(addr + header_offset + headroom), + }; + } } sq->db.wqe_info[pi] = (struct mlx5e_icosq_wqe_info) { .wqe_type = MLX5E_ICOSQ_WQE_SHAMPO_HD_UMR, .num_wqebbs = wqe_bbs, - .shampo.len = new_entries, + .shampo.len = ksm_entries, }; - shampo->pi = (shampo->pi + new_entries) & (shampo->hd_per_wq - 1); - shampo->curr_page_index = page_index; - shampo->last_addr = addr; + shampo->pi = (shampo->pi + ksm_entries) & (shampo->hd_per_wq - 1); sq->pc += wqe_bbs; sq->doorbell_cseg = &umr_wqe->ctrl; return 0; err_unmap: - while (--i >= 0) { - dma_info = &shampo->info[--index]; - if (!(i & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1))) { - dma_info->addr = ALIGN_DOWN(dma_info->addr, PAGE_SIZE); - mlx5e_page_release_fragmented(rq, dma_info->frag_page); + while (--i) { + --index; + header_offset = mlx5e_shampo_hd_offset(index); + if (!header_offset) { + struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, index); + + mlx5e_page_release_fragmented(rq, frag_page); } } + rq->stats->buff_alloc_err++; return err; } @@ -731,7 +730,8 @@ static int mlx5e_alloc_rx_hd_mpwqe(struct mlx5e_rq *rq) struct mlx5e_icosq *sq = rq->icosq; int i, err, max_ksm_entries, len; - max_ksm_entries = MLX5E_MAX_KSM_PER_WQE(rq->mdev); + max_ksm_entries = ALIGN_DOWN(MLX5E_MAX_KSM_PER_WQE(rq->mdev), + MLX5E_SHAMPO_WQ_HEADER_PER_PAGE); ksm_entries = bitmap_find_window(shampo->bitmap, shampo->hd_per_wqe, shampo->hd_per_wq, shampo->pi); @@ -739,8 +739,8 @@ static int mlx5e_alloc_rx_hd_mpwqe(struct mlx5e_rq *rq) if (!ksm_entries) return 0; - ksm_entries += (shampo->pi & (MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT - 1)); - index = ALIGN_DOWN(shampo->pi, MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT); + /* pi is aligned to MLX5E_SHAMPO_WQ_HEADER_PER_PAGE */ + index = shampo->pi; entries_before = shampo->hd_per_wq - index; if (unlikely(entries_before < ksm_entries)) @@ -851,13 +851,11 @@ static void mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index) { struct mlx5e_shampo_hd *shampo = rq->mpwqe.shampo; - u64 addr = shampo->info[header_index].addr; if (((header_index + 1) & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) == 0) { - struct mlx5e_dma_info *dma_info = &shampo->info[header_index]; + struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index); - dma_info->addr = ALIGN_DOWN(addr, PAGE_SIZE); - mlx5e_page_release_fragmented(rq, dma_info->frag_page); + mlx5e_page_release_fragmented(rq, frag_page); } clear_bit(header_index, shampo->bitmap); } @@ -1211,10 +1209,10 @@ static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe, static void *mlx5e_shampo_get_packet_hd(struct mlx5e_rq *rq, u16 header_index) { - struct mlx5e_dma_info *last_head = &rq->mpwqe.shampo->info[header_index]; - u16 head_offset = (last_head->addr & (PAGE_SIZE - 1)) + rq->buff.headroom; + struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index); + u16 head_offset = mlx5e_shampo_hd_offset(header_index) + rq->buff.headroom; - return page_address(last_head->frag_page->page) + head_offset; + return page_address(frag_page->page) + head_offset; } static void mlx5e_shampo_update_ipv4_udp_hdr(struct mlx5e_rq *rq, struct iphdr *ipv4) @@ -2185,29 +2183,30 @@ static struct sk_buff * mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi, struct mlx5_cqe64 *cqe, u16 header_index) { - struct mlx5e_dma_info *head = &rq->mpwqe.shampo->info[header_index]; - u16 head_offset = head->addr & (PAGE_SIZE - 1); + struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index); + dma_addr_t page_dma_addr = page_pool_get_dma_addr(frag_page->page); + u16 head_offset = mlx5e_shampo_hd_offset(header_index); + dma_addr_t dma_addr = page_dma_addr + head_offset; u16 head_size = cqe->shampo.header_size; u16 rx_headroom = rq->buff.headroom; struct sk_buff *skb = NULL; void *hdr, *data; u32 frag_size; - hdr = page_address(head->frag_page->page) + head_offset; + hdr = page_address(frag_page->page) + head_offset; data = hdr + rx_headroom; frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + head_size); if (likely(frag_size <= BIT(MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE))) { /* build SKB around header */ - dma_sync_single_range_for_cpu(rq->pdev, head->addr, 0, frag_size, rq->buff.map_dir); + dma_sync_single_range_for_cpu(rq->pdev, dma_addr, 0, frag_size, rq->buff.map_dir); net_prefetchw(hdr); net_prefetch(data); skb = mlx5e_build_linear_skb(rq, hdr, frag_size, rx_headroom, head_size, 0); - if (unlikely(!skb)) return NULL; - head->frag_page->frags++; + frag_page->frags++; } else { /* allocate SKB and copy header for large header */ rq->stats->gro_large_hds++; @@ -2219,7 +2218,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi, } net_prefetchw(skb->data); - mlx5e_copy_skb_header(rq, skb, head->frag_page->page, head->addr, + mlx5e_copy_skb_header(rq, skb, frag_page->page, dma_addr, head_offset + rx_headroom, rx_headroom, head_size); /* skb linear part was allocated with headlen and aligned to long */ @@ -2436,7 +2435,7 @@ static int mlx5e_rx_cq_process_enhanced_cqe_comp(struct mlx5e_rq *rq, struct mlx5e_cq_decomp *cqd = &rq->cqd; int work_done = 0; - cqe = mlx5_cqwq_get_cqe_enahnced_comp(cqwq); + cqe = mlx5_cqwq_get_cqe_enhanced_comp(cqwq); if (!cqe) return work_done; @@ -2466,7 +2465,7 @@ static int mlx5e_rx_cq_process_enhanced_cqe_comp(struct mlx5e_rq *rq, rq, cqe); work_done++; } while (work_done < budget_rem && - (cqe = mlx5_cqwq_get_cqe_enahnced_comp(cqwq))); + (cqe = mlx5_cqwq_get_cqe_enhanced_comp(cqwq))); /* last cqe might be title on next poll bulk */ if (title_cqe) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c index 5873fde65c2e33..76108299ea57de 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c @@ -55,7 +55,7 @@ static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq) return; dim_update_sample(sq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample); - net_dim(sq->dim, dim_sample); + net_dim(sq->dim, &dim_sample); } static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq) @@ -67,7 +67,7 @@ static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq) return; dim_update_sample(rq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample); - net_dim(rq->dim, dim_sample); + net_dim(rq->dim, &dim_sample); } void mlx5e_trigger_irq(struct mlx5e_icosq *sq) @@ -165,7 +165,8 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget) if (unlikely(!budget)) goto out; - busy |= mlx5e_poll_xdpsq_cq(&c->xdpsq.cq); + if (c->xdpsq) + busy |= mlx5e_poll_xdpsq_cq(&c->xdpsq->cq); if (c->xdp) busy |= mlx5e_poll_xdpsq_cq(&c->rq_xdpsq.cq); @@ -236,7 +237,8 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget) mlx5e_cq_arm(&rq->cq); mlx5e_cq_arm(&c->icosq.cq); mlx5e_cq_arm(&c->async_icosq.cq); - mlx5e_cq_arm(&c->xdpsq.cq); + if (c->xdpsq) + mlx5e_cq_arm(&c->xdpsq->cq); if (xsk_open) { mlx5e_handle_rx_dim(xskrq); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index 68cb86b37e561f..2b229b6226c6a7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -114,14 +114,10 @@ static int mlx5_eq_comp_int(struct notifier_block *nb, struct mlx5_eq *eq = &eq_comp->core; struct mlx5_eqe *eqe; int num_eqes = 0; - u32 cqn = -1; - eqe = next_eqe_sw(eq); - if (!eqe) - goto out; - - do { + while ((eqe = next_eqe_sw(eq))) { struct mlx5_core_cq *cq; + u32 cqn; /* Make sure we read EQ entry contents after we've * checked the ownership bit. @@ -142,14 +138,12 @@ static int mlx5_eq_comp_int(struct notifier_block *nb, ++eq->cons_index; - } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq))); + if (++num_eqes >= MLX5_EQ_POLLING_BUDGET) + break; + } -out: eq_update_ci(eq, 1); - if (cqn != -1) - tasklet_schedule(&eq_comp->tasklet_ctx.task); - return 0; } @@ -215,11 +209,7 @@ static int mlx5_eq_async_int(struct notifier_block *nb, recovery = action == ASYNC_EQ_RECOVER; mlx5_eq_async_int_lock(eq_async, recovery, &flags); - eqe = next_eqe_sw(eq); - if (!eqe) - goto out; - - do { + while ((eqe = next_eqe_sw(eq))) { /* * Make sure we read EQ entry contents after we've * checked the ownership bit. @@ -231,9 +221,10 @@ static int mlx5_eq_async_int(struct notifier_block *nb, ++eq->cons_index; - } while ((++num_eqes < MLX5_EQ_POLLING_BUDGET) && (eqe = next_eqe_sw(eq))); + if (++num_eqes >= MLX5_EQ_POLLING_BUDGET) + break; + } -out: eq_update_ci(eq, 1); mlx5_eq_async_int_unlock(eq_async, recovery, &flags); @@ -810,15 +801,8 @@ EXPORT_SYMBOL(mlx5_eq_get_eqe); void mlx5_eq_update_ci(struct mlx5_eq *eq, u32 cc, bool arm) { - __be32 __iomem *addr = eq->doorbell + (arm ? 0 : 2); - u32 val; - eq->cons_index += cc; - val = (eq->cons_index & 0xffffff) | (eq->eqn << 24); - - __raw_writel((__force u32)cpu_to_be32(val), addr); - /* We still want ordering, just not swabbing, so add a barrier */ - wmb(); + eq_update_ci(eq, arm); } EXPORT_SYMBOL(mlx5_eq_update_ci); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index f8869c9b68029f..982fe371468345 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -187,7 +187,7 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx return err; } -void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct mlx5_vport *vport) +void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport) { struct mlx5_devlink_port *dl_port; @@ -195,7 +195,7 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct return; dl_port = vport->dl_port; - mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL); + mlx5_esw_qos_vport_update_parent(vport, NULL, NULL); devl_rate_leaf_destroy(&dl_port->dl_port); devl_port_unregister(&dl_port->dl_port); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/diag/qos_tracepoint.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/diag/qos_tracepoint.h index 1ce332f21ebe99..43550a416a6ffe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/diag/qos_tracepoint.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/diag/qos_tracepoint.h @@ -9,107 +9,111 @@ #include #include "eswitch.h" +#include "qos.h" TRACE_EVENT(mlx5_esw_vport_qos_destroy, - TP_PROTO(const struct mlx5_vport *vport), - TP_ARGS(vport), - TP_STRUCT__entry(__string(devname, dev_name(vport->dev->device)) + TP_PROTO(const struct mlx5_core_dev *dev, const struct mlx5_vport *vport), + TP_ARGS(dev, vport), + TP_STRUCT__entry(__string(devname, dev_name(dev->device)) __field(unsigned short, vport_id) - __field(unsigned int, tsar_ix) + __field(unsigned int, sched_elem_ix) ), TP_fast_assign(__assign_str(devname); __entry->vport_id = vport->vport; - __entry->tsar_ix = vport->qos.esw_tsar_ix; + __entry->sched_elem_ix = mlx5_esw_qos_vport_get_sched_elem_ix(vport); ), - TP_printk("(%s) vport=%hu tsar_ix=%u\n", - __get_str(devname), __entry->vport_id, __entry->tsar_ix + TP_printk("(%s) vport=%hu sched_elem_ix=%u\n", + __get_str(devname), __entry->vport_id, __entry->sched_elem_ix ) ); DECLARE_EVENT_CLASS(mlx5_esw_vport_qos_template, - TP_PROTO(const struct mlx5_vport *vport, u32 bw_share, u32 max_rate), - TP_ARGS(vport, bw_share, max_rate), - TP_STRUCT__entry(__string(devname, dev_name(vport->dev->device)) + TP_PROTO(const struct mlx5_core_dev *dev, const struct mlx5_vport *vport, + u32 bw_share, u32 max_rate), + TP_ARGS(dev, vport, bw_share, max_rate), + TP_STRUCT__entry(__string(devname, dev_name(dev->device)) __field(unsigned short, vport_id) - __field(unsigned int, tsar_ix) + __field(unsigned int, sched_elem_ix) __field(unsigned int, bw_share) __field(unsigned int, max_rate) - __field(void *, group) + __field(void *, parent) ), TP_fast_assign(__assign_str(devname); __entry->vport_id = vport->vport; - __entry->tsar_ix = vport->qos.esw_tsar_ix; + __entry->sched_elem_ix = mlx5_esw_qos_vport_get_sched_elem_ix(vport); __entry->bw_share = bw_share; __entry->max_rate = max_rate; - __entry->group = vport->qos.group; + __entry->parent = mlx5_esw_qos_vport_get_parent(vport); ), - TP_printk("(%s) vport=%hu tsar_ix=%u bw_share=%u, max_rate=%u group=%p\n", - __get_str(devname), __entry->vport_id, __entry->tsar_ix, - __entry->bw_share, __entry->max_rate, __entry->group + TP_printk("(%s) vport=%hu sched_elem_ix=%u bw_share=%u, max_rate=%u parent=%p\n", + __get_str(devname), __entry->vport_id, __entry->sched_elem_ix, + __entry->bw_share, __entry->max_rate, __entry->parent ) ); DEFINE_EVENT(mlx5_esw_vport_qos_template, mlx5_esw_vport_qos_create, - TP_PROTO(const struct mlx5_vport *vport, u32 bw_share, u32 max_rate), - TP_ARGS(vport, bw_share, max_rate) + TP_PROTO(const struct mlx5_core_dev *dev, const struct mlx5_vport *vport, + u32 bw_share, u32 max_rate), + TP_ARGS(dev, vport, bw_share, max_rate) ); DEFINE_EVENT(mlx5_esw_vport_qos_template, mlx5_esw_vport_qos_config, - TP_PROTO(const struct mlx5_vport *vport, u32 bw_share, u32 max_rate), - TP_ARGS(vport, bw_share, max_rate) + TP_PROTO(const struct mlx5_core_dev *dev, const struct mlx5_vport *vport, + u32 bw_share, u32 max_rate), + TP_ARGS(dev, vport, bw_share, max_rate) ); -DECLARE_EVENT_CLASS(mlx5_esw_group_qos_template, +DECLARE_EVENT_CLASS(mlx5_esw_node_qos_template, TP_PROTO(const struct mlx5_core_dev *dev, - const struct mlx5_esw_rate_group *group, + const struct mlx5_esw_sched_node *node, unsigned int tsar_ix), - TP_ARGS(dev, group, tsar_ix), + TP_ARGS(dev, node, tsar_ix), TP_STRUCT__entry(__string(devname, dev_name(dev->device)) - __field(const void *, group) + __field(const void *, node) __field(unsigned int, tsar_ix) ), TP_fast_assign(__assign_str(devname); - __entry->group = group; + __entry->node = node; __entry->tsar_ix = tsar_ix; ), - TP_printk("(%s) group=%p tsar_ix=%u\n", - __get_str(devname), __entry->group, __entry->tsar_ix + TP_printk("(%s) node=%p tsar_ix=%u\n", + __get_str(devname), __entry->node, __entry->tsar_ix ) ); -DEFINE_EVENT(mlx5_esw_group_qos_template, mlx5_esw_group_qos_create, +DEFINE_EVENT(mlx5_esw_node_qos_template, mlx5_esw_node_qos_create, TP_PROTO(const struct mlx5_core_dev *dev, - const struct mlx5_esw_rate_group *group, + const struct mlx5_esw_sched_node *node, unsigned int tsar_ix), - TP_ARGS(dev, group, tsar_ix) + TP_ARGS(dev, node, tsar_ix) ); -DEFINE_EVENT(mlx5_esw_group_qos_template, mlx5_esw_group_qos_destroy, +DEFINE_EVENT(mlx5_esw_node_qos_template, mlx5_esw_node_qos_destroy, TP_PROTO(const struct mlx5_core_dev *dev, - const struct mlx5_esw_rate_group *group, + const struct mlx5_esw_sched_node *node, unsigned int tsar_ix), - TP_ARGS(dev, group, tsar_ix) + TP_ARGS(dev, node, tsar_ix) ); -TRACE_EVENT(mlx5_esw_group_qos_config, +TRACE_EVENT(mlx5_esw_node_qos_config, TP_PROTO(const struct mlx5_core_dev *dev, - const struct mlx5_esw_rate_group *group, + const struct mlx5_esw_sched_node *node, unsigned int tsar_ix, u32 bw_share, u32 max_rate), - TP_ARGS(dev, group, tsar_ix, bw_share, max_rate), + TP_ARGS(dev, node, tsar_ix, bw_share, max_rate), TP_STRUCT__entry(__string(devname, dev_name(dev->device)) - __field(const void *, group) + __field(const void *, node) __field(unsigned int, tsar_ix) __field(unsigned int, bw_share) __field(unsigned int, max_rate) ), TP_fast_assign(__assign_str(devname); - __entry->group = group; + __entry->node = node; __entry->tsar_ix = tsar_ix; __entry->bw_share = bw_share; __entry->max_rate = max_rate; ), - TP_printk("(%s) group=%p tsar_ix=%u bw_share=%u max_rate=%u\n", - __get_str(devname), __entry->group, __entry->tsar_ix, + TP_printk("(%s) node=%p tsar_ix=%u bw_share=%u max_rate=%u\n", + __get_str(devname), __entry->node, __entry->tsar_ix, __entry->bw_share, __entry->max_rate ) ); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c index 8587cd572da536..45183de424f3dd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c @@ -176,20 +176,10 @@ static void esw_destroy_legacy_vepa_table(struct mlx5_eswitch *esw) static int esw_create_legacy_table(struct mlx5_eswitch *esw) { - int err; - memset(&esw->fdb_table.legacy, 0, sizeof(struct legacy_fdb)); atomic64_set(&esw->user_count, 0); - err = esw_create_legacy_vepa_table(esw); - if (err) - return err; - - err = esw_create_legacy_fdb_table(esw); - if (err) - esw_destroy_legacy_vepa_table(esw); - - return err; + return esw_create_legacy_fdb_table(esw); } static void esw_cleanup_vepa_rules(struct mlx5_eswitch *esw) @@ -259,15 +249,22 @@ static int _mlx5_eswitch_set_vepa_locked(struct mlx5_eswitch *esw, if (!setting) { esw_cleanup_vepa_rules(esw); + esw_destroy_legacy_vepa_table(esw); return 0; } if (esw->fdb_table.legacy.vepa_uplink_rule) return 0; + err = esw_create_legacy_vepa_table(esw); + if (err) + return err; + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; + if (!spec) { + err = -ENOMEM; + goto out; + } /* Uplink rule forward uplink traffic to FDB */ misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); @@ -303,8 +300,10 @@ static int _mlx5_eswitch_set_vepa_locked(struct mlx5_eswitch *esw, out: kvfree(spec); - if (err) + if (err) { esw_cleanup_vepa_rules(esw); + esw_destroy_legacy_vepa_table(esw); + } return err; } @@ -513,15 +512,11 @@ int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, u16 vport, u32 max_rate, u32 min_rate) { struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport); - int err; if (!mlx5_esw_allowed(esw)) return -EPERM; if (IS_ERR(evport)) return PTR_ERR(evport); - mutex_lock(&esw->state_lock); - err = mlx5_esw_qos_set_vport_rate(esw, evport, max_rate, min_rate); - mutex_unlock(&esw->state_lock); - return err; + return mlx5_esw_qos_set_vport_rate(evport, max_rate, min_rate); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c index 02a3563f51ad26..8b7c843446e115 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c @@ -11,497 +11,427 @@ /* Minimum supported BW share value by the HW is 1 Mbit/sec */ #define MLX5_MIN_BW_SHARE 1 -#define MLX5_RATE_TO_BW_SHARE(rate, divider, limit) \ - min_t(u32, max_t(u32, DIV_ROUND_UP(rate, divider), MLX5_MIN_BW_SHARE), limit) - -struct mlx5_esw_rate_group { - u32 tsar_ix; - u32 max_rate; - u32 min_rate; - u32 bw_share; - struct list_head list; +/* Holds rate nodes associated with an E-Switch. */ +struct mlx5_qos_domain { + /* Serializes access to all qos changes in the qos domain. */ + struct mutex lock; + /* List of all mlx5_esw_sched_nodes. */ + struct list_head nodes; }; -static int esw_qos_tsar_config(struct mlx5_core_dev *dev, u32 *sched_ctx, - u32 tsar_ix, u32 max_rate, u32 bw_share) +static void esw_qos_lock(struct mlx5_eswitch *esw) { - u32 bitmask = 0; - - if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling)) - return -EOPNOTSUPP; + mutex_lock(&esw->qos.domain->lock); +} - MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate); - MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share); - bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW; - bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE; +static void esw_qos_unlock(struct mlx5_eswitch *esw) +{ + mutex_unlock(&esw->qos.domain->lock); +} - return mlx5_modify_scheduling_element_cmd(dev, - SCHEDULING_HIERARCHY_E_SWITCH, - sched_ctx, - tsar_ix, - bitmask); +static void esw_assert_qos_lock_held(struct mlx5_eswitch *esw) +{ + lockdep_assert_held(&esw->qos.domain->lock); } -static int esw_qos_group_config(struct mlx5_eswitch *esw, struct mlx5_esw_rate_group *group, - u32 max_rate, u32 bw_share, struct netlink_ext_ack *extack) +static struct mlx5_qos_domain *esw_qos_domain_alloc(void) { - u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; - struct mlx5_core_dev *dev = esw->dev; - int err; + struct mlx5_qos_domain *qos_domain; - err = esw_qos_tsar_config(dev, sched_ctx, - group->tsar_ix, - max_rate, bw_share); - if (err) - NL_SET_ERR_MSG_MOD(extack, "E-Switch modify group TSAR element failed"); + qos_domain = kzalloc(sizeof(*qos_domain), GFP_KERNEL); + if (!qos_domain) + return NULL; - trace_mlx5_esw_group_qos_config(dev, group, group->tsar_ix, bw_share, max_rate); + mutex_init(&qos_domain->lock); + INIT_LIST_HEAD(&qos_domain->nodes); - return err; + return qos_domain; } -static int esw_qos_vport_config(struct mlx5_eswitch *esw, - struct mlx5_vport *vport, - u32 max_rate, u32 bw_share, - struct netlink_ext_ack *extack) +static int esw_qos_domain_init(struct mlx5_eswitch *esw) { - u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; - struct mlx5_core_dev *dev = esw->dev; - int err; - - if (!vport->qos.enabled) - return -EIO; - - err = esw_qos_tsar_config(dev, sched_ctx, vport->qos.esw_tsar_ix, - max_rate, bw_share); - if (err) { - esw_warn(esw->dev, - "E-Switch modify TSAR vport element failed (vport=%d,err=%d)\n", - vport->vport, err); - NL_SET_ERR_MSG_MOD(extack, "E-Switch modify TSAR vport element failed"); - return err; - } + esw->qos.domain = esw_qos_domain_alloc(); - trace_mlx5_esw_vport_qos_config(vport, bw_share, max_rate); - - return 0; + return esw->qos.domain ? 0 : -ENOMEM; } -static u32 esw_qos_calculate_min_rate_divider(struct mlx5_eswitch *esw, - struct mlx5_esw_rate_group *group, - bool group_level) +static void esw_qos_domain_release(struct mlx5_eswitch *esw) { - u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share); - struct mlx5_vport *evport; - u32 max_guarantee = 0; - unsigned long i; + kfree(esw->qos.domain); + esw->qos.domain = NULL; +} - if (group_level) { - struct mlx5_esw_rate_group *group; +enum sched_node_type { + SCHED_NODE_TYPE_VPORTS_TSAR, + SCHED_NODE_TYPE_VPORT, +}; - list_for_each_entry(group, &esw->qos.groups, list) { - if (group->min_rate < max_guarantee) - continue; - max_guarantee = group->min_rate; - } - } else { - mlx5_esw_for_each_vport(esw, i, evport) { - if (!evport->enabled || !evport->qos.enabled || - evport->qos.group != group || evport->qos.min_rate < max_guarantee) - continue; - max_guarantee = evport->qos.min_rate; - } - } +static const char * const sched_node_type_str[] = { + [SCHED_NODE_TYPE_VPORTS_TSAR] = "vports TSAR", + [SCHED_NODE_TYPE_VPORT] = "vport", +}; - if (max_guarantee) - return max_t(u32, max_guarantee / fw_max_bw_share, 1); +struct mlx5_esw_sched_node { + u32 ix; + /* Bandwidth parameters. */ + u32 max_rate; + u32 min_rate; + /* A computed value indicating relative min_rate between node's children. */ + u32 bw_share; + /* The parent node in the rate hierarchy. */ + struct mlx5_esw_sched_node *parent; + /* Entry in the parent node's children list. */ + struct list_head entry; + /* The type of this node in the rate hierarchy. */ + enum sched_node_type type; + /* The eswitch this node belongs to. */ + struct mlx5_eswitch *esw; + /* The children nodes of this node, empty list for leaf nodes. */ + struct list_head children; + /* Valid only if this node is associated with a vport. */ + struct mlx5_vport *vport; +}; - /* If vports min rate divider is 0 but their group has bw_share configured, then - * need to set bw_share for vports to minimal value. - */ - if (!group_level && !max_guarantee && group && group->bw_share) - return 1; - return 0; +static void +esw_qos_node_set_parent(struct mlx5_esw_sched_node *node, struct mlx5_esw_sched_node *parent) +{ + list_del_init(&node->entry); + node->parent = parent; + list_add_tail(&node->entry, &parent->children); + node->esw = parent->esw; } -static u32 esw_qos_calc_bw_share(u32 min_rate, u32 divider, u32 fw_max) +void mlx5_esw_qos_vport_qos_free(struct mlx5_vport *vport) { - if (divider) - return MLX5_RATE_TO_BW_SHARE(min_rate, divider, fw_max); - - return 0; + kfree(vport->qos.sched_node); + memset(&vport->qos, 0, sizeof(vport->qos)); } -static int esw_qos_normalize_vports_min_rate(struct mlx5_eswitch *esw, - struct mlx5_esw_rate_group *group, - struct netlink_ext_ack *extack) +u32 mlx5_esw_qos_vport_get_sched_elem_ix(const struct mlx5_vport *vport) { - u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share); - u32 divider = esw_qos_calculate_min_rate_divider(esw, group, false); - struct mlx5_vport *evport; - unsigned long i; - u32 bw_share; - int err; + if (!vport->qos.sched_node) + return 0; - mlx5_esw_for_each_vport(esw, i, evport) { - if (!evport->enabled || !evport->qos.enabled || evport->qos.group != group) - continue; - bw_share = esw_qos_calc_bw_share(evport->qos.min_rate, divider, fw_max_bw_share); + return vport->qos.sched_node->ix; +} - if (bw_share == evport->qos.bw_share) - continue; +struct mlx5_esw_sched_node * +mlx5_esw_qos_vport_get_parent(const struct mlx5_vport *vport) +{ + if (!vport->qos.sched_node) + return NULL; - err = esw_qos_vport_config(esw, evport, evport->qos.max_rate, bw_share, extack); - if (err) - return err; + return vport->qos.sched_node->parent; +} - evport->qos.bw_share = bw_share; +static void esw_qos_sched_elem_warn(struct mlx5_esw_sched_node *node, int err, const char *op) +{ + if (node->vport) { + esw_warn(node->esw->dev, + "E-Switch %s %s scheduling element failed (vport=%d,err=%d)\n", + op, sched_node_type_str[node->type], node->vport->vport, err); + return; } - return 0; + esw_warn(node->esw->dev, + "E-Switch %s %s scheduling element failed (err=%d)\n", + op, sched_node_type_str[node->type], err); } -static int esw_qos_normalize_groups_min_rate(struct mlx5_eswitch *esw, u32 divider, +static int esw_qos_node_create_sched_element(struct mlx5_esw_sched_node *node, void *ctx, struct netlink_ext_ack *extack) { - u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share); - struct mlx5_esw_rate_group *group; - u32 bw_share; int err; - list_for_each_entry(group, &esw->qos.groups, list) { - bw_share = esw_qos_calc_bw_share(group->min_rate, divider, fw_max_bw_share); - - if (bw_share == group->bw_share) - continue; - - err = esw_qos_group_config(esw, group, group->max_rate, bw_share, extack); - if (err) - return err; - - group->bw_share = bw_share; - - /* All the group's vports need to be set with default bw_share - * to enable them with QOS - */ - err = esw_qos_normalize_vports_min_rate(esw, group, extack); - - if (err) - return err; + err = mlx5_create_scheduling_element_cmd(node->esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, ctx, + &node->ix); + if (err) { + esw_qos_sched_elem_warn(node, err, "create"); + NL_SET_ERR_MSG_MOD(extack, "E-Switch create scheduling element failed"); } - return 0; + return err; } -static int esw_qos_set_vport_min_rate(struct mlx5_eswitch *esw, struct mlx5_vport *evport, - u32 min_rate, struct netlink_ext_ack *extack) +static int esw_qos_node_destroy_sched_element(struct mlx5_esw_sched_node *node, + struct netlink_ext_ack *extack) { - u32 fw_max_bw_share, previous_min_rate; - bool min_rate_supported; int err; - lockdep_assert_held(&esw->state_lock); - fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share); - min_rate_supported = MLX5_CAP_QOS(esw->dev, esw_bw_share) && - fw_max_bw_share >= MLX5_MIN_BW_SHARE; - if (min_rate && !min_rate_supported) - return -EOPNOTSUPP; - if (min_rate == evport->qos.min_rate) - return 0; - - previous_min_rate = evport->qos.min_rate; - evport->qos.min_rate = min_rate; - err = esw_qos_normalize_vports_min_rate(esw, evport->qos.group, extack); - if (err) - evport->qos.min_rate = previous_min_rate; + err = mlx5_destroy_scheduling_element_cmd(node->esw->dev, + SCHEDULING_HIERARCHY_E_SWITCH, + node->ix); + if (err) { + esw_qos_sched_elem_warn(node, err, "destroy"); + NL_SET_ERR_MSG_MOD(extack, "E-Switch destroying scheduling element failed."); + } return err; } -static int esw_qos_set_vport_max_rate(struct mlx5_eswitch *esw, struct mlx5_vport *evport, - u32 max_rate, struct netlink_ext_ack *extack) +static int esw_qos_sched_elem_config(struct mlx5_esw_sched_node *node, u32 max_rate, u32 bw_share, + struct netlink_ext_ack *extack) { - u32 act_max_rate = max_rate; - bool max_rate_supported; + u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; + struct mlx5_core_dev *dev = node->esw->dev; + u32 bitmask = 0; int err; - lockdep_assert_held(&esw->state_lock); - max_rate_supported = MLX5_CAP_QOS(esw->dev, esw_rate_limit); + if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling)) + return -EOPNOTSUPP; - if (max_rate && !max_rate_supported) + if (bw_share && (!MLX5_CAP_QOS(dev, esw_bw_share) || + MLX5_CAP_QOS(dev, max_tsar_bw_share) < MLX5_MIN_BW_SHARE)) return -EOPNOTSUPP; - if (max_rate == evport->qos.max_rate) + + if (node->max_rate == max_rate && node->bw_share == bw_share) return 0; - /* If parent group has rate limit need to set to group - * value when new max rate is 0. - */ - if (evport->qos.group && !max_rate) - act_max_rate = evport->qos.group->max_rate; + if (node->max_rate != max_rate) { + MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate); + bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW; + } + if (node->bw_share != bw_share) { + MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share); + bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE; + } + + err = mlx5_modify_scheduling_element_cmd(dev, + SCHEDULING_HIERARCHY_E_SWITCH, + sched_ctx, + node->ix, + bitmask); + if (err) { + esw_qos_sched_elem_warn(node, err, "modify"); + NL_SET_ERR_MSG_MOD(extack, "E-Switch modify scheduling element failed"); - err = esw_qos_vport_config(esw, evport, act_max_rate, evport->qos.bw_share, extack); + return err; + } - if (!err) - evport->qos.max_rate = max_rate; + node->max_rate = max_rate; + node->bw_share = bw_share; + if (node->type == SCHED_NODE_TYPE_VPORTS_TSAR) + trace_mlx5_esw_node_qos_config(dev, node, node->ix, bw_share, max_rate); + else if (node->type == SCHED_NODE_TYPE_VPORT) + trace_mlx5_esw_vport_qos_config(dev, node->vport, bw_share, max_rate); - return err; + return 0; } -static int esw_qos_set_group_min_rate(struct mlx5_eswitch *esw, struct mlx5_esw_rate_group *group, - u32 min_rate, struct netlink_ext_ack *extack) +static u32 esw_qos_calculate_min_rate_divider(struct mlx5_eswitch *esw, + struct mlx5_esw_sched_node *parent) { + struct list_head *nodes = parent ? &parent->children : &esw->qos.domain->nodes; u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share); - struct mlx5_core_dev *dev = esw->dev; - u32 previous_min_rate, divider; - int err; + struct mlx5_esw_sched_node *node; + u32 max_guarantee = 0; - if (!(MLX5_CAP_QOS(dev, esw_bw_share) && fw_max_bw_share >= MLX5_MIN_BW_SHARE)) - return -EOPNOTSUPP; + /* Find max min_rate across all nodes. + * This will correspond to fw_max_bw_share in the final bw_share calculation. + */ + list_for_each_entry(node, nodes, entry) { + if (node->esw == esw && node->ix != esw->qos.root_tsar_ix && + node->min_rate > max_guarantee) + max_guarantee = node->min_rate; + } - if (min_rate == group->min_rate) - return 0; + if (max_guarantee) + return max_t(u32, max_guarantee / fw_max_bw_share, 1); - previous_min_rate = group->min_rate; - group->min_rate = min_rate; - divider = esw_qos_calculate_min_rate_divider(esw, group, true); - err = esw_qos_normalize_groups_min_rate(esw, divider, extack); - if (err) { - group->min_rate = previous_min_rate; - NL_SET_ERR_MSG_MOD(extack, "E-Switch group min rate setting failed"); + /* If nodes max min_rate divider is 0 but their parent has bw_share + * configured, then set bw_share for nodes to minimal value. + */ - /* Attempt restoring previous configuration */ - divider = esw_qos_calculate_min_rate_divider(esw, group, true); - if (esw_qos_normalize_groups_min_rate(esw, divider, extack)) - NL_SET_ERR_MSG_MOD(extack, "E-Switch BW share restore failed"); - } + if (parent && parent->bw_share) + return 1; - return err; + /* If the node nodes has min_rate configured, a divider of 0 sets all + * nodes' bw_share to 0, effectively disabling min guarantees. + */ + return 0; } -static int esw_qos_set_group_max_rate(struct mlx5_eswitch *esw, - struct mlx5_esw_rate_group *group, - u32 max_rate, struct netlink_ext_ack *extack) +static u32 esw_qos_calc_bw_share(u32 min_rate, u32 divider, u32 fw_max) { - struct mlx5_vport *vport; - unsigned long i; - int err; - - if (group->max_rate == max_rate) + if (!divider) return 0; + return min_t(u32, max_t(u32, DIV_ROUND_UP(min_rate, divider), MLX5_MIN_BW_SHARE), fw_max); +} - err = esw_qos_group_config(esw, group, max_rate, group->bw_share, extack); - if (err) - return err; +static void esw_qos_update_sched_node_bw_share(struct mlx5_esw_sched_node *node, + u32 divider, + struct netlink_ext_ack *extack) +{ + u32 fw_max_bw_share = MLX5_CAP_QOS(node->esw->dev, max_tsar_bw_share); + u32 bw_share; - group->max_rate = max_rate; + bw_share = esw_qos_calc_bw_share(node->min_rate, divider, fw_max_bw_share); - /* Any unlimited vports in the group should be set - * with the value of the group. - */ - mlx5_esw_for_each_vport(esw, i, vport) { - if (!vport->enabled || !vport->qos.enabled || - vport->qos.group != group || vport->qos.max_rate) + esw_qos_sched_elem_config(node, node->max_rate, bw_share, extack); +} + +static void esw_qos_normalize_min_rate(struct mlx5_eswitch *esw, + struct mlx5_esw_sched_node *parent, + struct netlink_ext_ack *extack) +{ + struct list_head *nodes = parent ? &parent->children : &esw->qos.domain->nodes; + u32 divider = esw_qos_calculate_min_rate_divider(esw, parent); + struct mlx5_esw_sched_node *node; + + list_for_each_entry(node, nodes, entry) { + if (node->esw != esw || node->ix == esw->qos.root_tsar_ix) continue; - err = esw_qos_vport_config(esw, vport, max_rate, vport->qos.bw_share, extack); - if (err) - NL_SET_ERR_MSG_MOD(extack, - "E-Switch vport implicit rate limit setting failed"); - } + esw_qos_update_sched_node_bw_share(node, divider, extack); - return err; -} + if (list_empty(&node->children)) + continue; -static bool esw_qos_element_type_supported(struct mlx5_core_dev *dev, int type) -{ - switch (type) { - case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR: - return MLX5_CAP_QOS(dev, esw_element_type) & - ELEMENT_TYPE_CAP_MASK_TSAR; - case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT: - return MLX5_CAP_QOS(dev, esw_element_type) & - ELEMENT_TYPE_CAP_MASK_VPORT; - case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC: - return MLX5_CAP_QOS(dev, esw_element_type) & - ELEMENT_TYPE_CAP_MASK_VPORT_TC; - case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC: - return MLX5_CAP_QOS(dev, esw_element_type) & - ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC; + esw_qos_normalize_min_rate(node->esw, node, extack); } - return false; } -static int esw_qos_vport_create_sched_element(struct mlx5_eswitch *esw, - struct mlx5_vport *vport, - u32 max_rate, u32 bw_share) +static int esw_qos_set_node_min_rate(struct mlx5_esw_sched_node *node, + u32 min_rate, struct netlink_ext_ack *extack) { - u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; - struct mlx5_esw_rate_group *group = vport->qos.group; - struct mlx5_core_dev *dev = esw->dev; - u32 parent_tsar_ix; - void *vport_elem; - int err; + struct mlx5_eswitch *esw = node->esw; - if (!esw_qos_element_type_supported(dev, SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT)) - return -EOPNOTSUPP; + if (min_rate == node->min_rate) + return 0; - parent_tsar_ix = group ? group->tsar_ix : esw->qos.root_tsar_ix; - MLX5_SET(scheduling_context, sched_ctx, element_type, - SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT); - vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes); - MLX5_SET(vport_element, vport_elem, vport_number, vport->vport); - MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_tsar_ix); - MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate); - MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share); - - err = mlx5_create_scheduling_element_cmd(dev, - SCHEDULING_HIERARCHY_E_SWITCH, - sched_ctx, - &vport->qos.esw_tsar_ix); - if (err) { - esw_warn(esw->dev, "E-Switch create TSAR vport element failed (vport=%d,err=%d)\n", - vport->vport, err); - return err; - } + node->min_rate = min_rate; + esw_qos_normalize_min_rate(esw, node->parent, extack); return 0; } -static int esw_qos_update_group_scheduling_element(struct mlx5_eswitch *esw, - struct mlx5_vport *vport, - struct mlx5_esw_rate_group *curr_group, - struct mlx5_esw_rate_group *new_group, - struct netlink_ext_ack *extack) +static int esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_element_id, + u32 *tsar_ix) { - u32 max_rate; - int err; + u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; + void *attr; + + if (!mlx5_qos_element_type_supported(dev, + SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR, + SCHEDULING_HIERARCHY_E_SWITCH) || + !mlx5_qos_tsar_type_supported(dev, + TSAR_ELEMENT_TSAR_TYPE_DWRR, + SCHEDULING_HIERARCHY_E_SWITCH)) + return -EOPNOTSUPP; - err = mlx5_destroy_scheduling_element_cmd(esw->dev, - SCHEDULING_HIERARCHY_E_SWITCH, - vport->qos.esw_tsar_ix); - if (err) { - NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR vport element failed"); - return err; - } + MLX5_SET(scheduling_context, tsar_ctx, element_type, + SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR); + MLX5_SET(scheduling_context, tsar_ctx, parent_element_id, + parent_element_id); + attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes); + MLX5_SET(tsar_element, attr, tsar_type, TSAR_ELEMENT_TSAR_TYPE_DWRR); - vport->qos.group = new_group; - max_rate = vport->qos.max_rate ? vport->qos.max_rate : new_group->max_rate; + return mlx5_create_scheduling_element_cmd(dev, + SCHEDULING_HIERARCHY_E_SWITCH, + tsar_ctx, + tsar_ix); +} - /* If vport is unlimited, we set the group's value. - * Therefore, if the group is limited it will apply to - * the vport as well and if not, vport will remain unlimited. - */ - err = esw_qos_vport_create_sched_element(esw, vport, max_rate, vport->qos.bw_share); - if (err) { - NL_SET_ERR_MSG_MOD(extack, "E-Switch vport group set failed."); - goto err_sched; - } +static int esw_qos_vport_create_sched_element(struct mlx5_esw_sched_node *vport_node, + struct netlink_ext_ack *extack) +{ + u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; + struct mlx5_core_dev *dev = vport_node->esw->dev; + void *attr; - return 0; + if (!mlx5_qos_element_type_supported(dev, + SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT, + SCHEDULING_HIERARCHY_E_SWITCH)) + return -EOPNOTSUPP; -err_sched: - vport->qos.group = curr_group; - max_rate = vport->qos.max_rate ? vport->qos.max_rate : curr_group->max_rate; - if (esw_qos_vport_create_sched_element(esw, vport, max_rate, vport->qos.bw_share)) - esw_warn(esw->dev, "E-Switch vport group restore failed (vport=%d)\n", - vport->vport); + MLX5_SET(scheduling_context, sched_ctx, element_type, + SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT); + attr = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes); + MLX5_SET(vport_element, attr, vport_number, vport_node->vport->vport); + MLX5_SET(scheduling_context, sched_ctx, parent_element_id, vport_node->parent->ix); + MLX5_SET(scheduling_context, sched_ctx, max_average_bw, vport_node->max_rate); - return err; + return esw_qos_node_create_sched_element(vport_node, sched_ctx, extack); } -static int esw_qos_vport_update_group(struct mlx5_eswitch *esw, - struct mlx5_vport *vport, - struct mlx5_esw_rate_group *group, - struct netlink_ext_ack *extack) +static struct mlx5_esw_sched_node * +__esw_qos_alloc_node(struct mlx5_eswitch *esw, u32 tsar_ix, enum sched_node_type type, + struct mlx5_esw_sched_node *parent) { - struct mlx5_esw_rate_group *new_group, *curr_group; - int err; + struct list_head *parent_children; + struct mlx5_esw_sched_node *node; - if (!vport->enabled) - return -EINVAL; + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return NULL; - curr_group = vport->qos.group; - new_group = group ?: esw->qos.group0; - if (curr_group == new_group) - return 0; + node->esw = esw; + node->ix = tsar_ix; + node->type = type; + node->parent = parent; + INIT_LIST_HEAD(&node->children); + parent_children = parent ? &parent->children : &esw->qos.domain->nodes; + list_add_tail(&node->entry, parent_children); - err = esw_qos_update_group_scheduling_element(esw, vport, curr_group, new_group, extack); - if (err) - return err; + return node; +} - /* Recalculate bw share weights of old and new groups */ - if (vport->qos.bw_share || new_group->bw_share) { - esw_qos_normalize_vports_min_rate(esw, curr_group, extack); - esw_qos_normalize_vports_min_rate(esw, new_group, extack); - } +static void __esw_qos_free_node(struct mlx5_esw_sched_node *node) +{ + list_del(&node->entry); + kfree(node); +} - return 0; +static void esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack) +{ + esw_qos_node_destroy_sched_element(node, extack); + __esw_qos_free_node(node); } -static struct mlx5_esw_rate_group * -__esw_qos_create_rate_group(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack) +static struct mlx5_esw_sched_node * +__esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct mlx5_esw_sched_node *parent, + struct netlink_ext_ack *extack) { - u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; - struct mlx5_esw_rate_group *group; - __be32 *attr; - u32 divider; + struct mlx5_esw_sched_node *node; + u32 tsar_ix; int err; - group = kzalloc(sizeof(*group), GFP_KERNEL); - if (!group) - return ERR_PTR(-ENOMEM); - - MLX5_SET(scheduling_context, tsar_ctx, element_type, - SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR); - - attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes); - *attr = cpu_to_be32(TSAR_ELEMENT_TSAR_TYPE_DWRR << 16); - - MLX5_SET(scheduling_context, tsar_ctx, parent_element_id, - esw->qos.root_tsar_ix); - err = mlx5_create_scheduling_element_cmd(esw->dev, - SCHEDULING_HIERARCHY_E_SWITCH, - tsar_ctx, - &group->tsar_ix); + err = esw_qos_create_node_sched_elem(esw->dev, esw->qos.root_tsar_ix, &tsar_ix); if (err) { - NL_SET_ERR_MSG_MOD(extack, "E-Switch create TSAR for group failed"); - goto err_sched_elem; + NL_SET_ERR_MSG_MOD(extack, "E-Switch create TSAR for node failed"); + return ERR_PTR(err); } - list_add_tail(&group->list, &esw->qos.groups); - - divider = esw_qos_calculate_min_rate_divider(esw, group, true); - if (divider) { - err = esw_qos_normalize_groups_min_rate(esw, divider, extack); - if (err) { - NL_SET_ERR_MSG_MOD(extack, "E-Switch groups normalization failed"); - goto err_min_rate; - } + node = __esw_qos_alloc_node(esw, tsar_ix, SCHED_NODE_TYPE_VPORTS_TSAR, parent); + if (!node) { + NL_SET_ERR_MSG_MOD(extack, "E-Switch alloc node failed"); + err = -ENOMEM; + goto err_alloc_node; } - trace_mlx5_esw_group_qos_create(esw->dev, group, group->tsar_ix); - return group; + esw_qos_normalize_min_rate(esw, NULL, extack); + trace_mlx5_esw_node_qos_create(esw->dev, node, node->ix); + + return node; -err_min_rate: - list_del(&group->list); +err_alloc_node: if (mlx5_destroy_scheduling_element_cmd(esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, - group->tsar_ix)) - NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR for group failed"); -err_sched_elem: - kfree(group); + tsar_ix)) + NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR for node failed"); return ERR_PTR(err); } static int esw_qos_get(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack); static void esw_qos_put(struct mlx5_eswitch *esw); -static struct mlx5_esw_rate_group * -esw_qos_create_rate_group(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack) +static struct mlx5_esw_sched_node * +esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack) { - struct mlx5_esw_rate_group *group; + struct mlx5_esw_sched_node *node; int err; + esw_assert_qos_lock_held(esw); if (!MLX5_CAP_QOS(esw->dev, log_esw_max_sched_depth)) return ERR_PTR(-EOPNOTSUPP); @@ -509,96 +439,58 @@ esw_qos_create_rate_group(struct mlx5_eswitch *esw, struct netlink_ext_ack *exta if (err) return ERR_PTR(err); - group = __esw_qos_create_rate_group(esw, extack); - if (IS_ERR(group)) + node = __esw_qos_create_vports_sched_node(esw, NULL, extack); + if (IS_ERR(node)) esw_qos_put(esw); - return group; + return node; } -static int __esw_qos_destroy_rate_group(struct mlx5_eswitch *esw, - struct mlx5_esw_rate_group *group, - struct netlink_ext_ack *extack) +static void __esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack) { - u32 divider; - int err; - - list_del(&group->list); - - divider = esw_qos_calculate_min_rate_divider(esw, NULL, true); - err = esw_qos_normalize_groups_min_rate(esw, divider, extack); - if (err) - NL_SET_ERR_MSG_MOD(extack, "E-Switch groups' normalization failed"); + struct mlx5_eswitch *esw = node->esw; - err = mlx5_destroy_scheduling_element_cmd(esw->dev, - SCHEDULING_HIERARCHY_E_SWITCH, - group->tsar_ix); - if (err) - NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR_ID failed"); - - trace_mlx5_esw_group_qos_destroy(esw->dev, group, group->tsar_ix); - - kfree(group); - - return err; -} - -static int esw_qos_destroy_rate_group(struct mlx5_eswitch *esw, - struct mlx5_esw_rate_group *group, - struct netlink_ext_ack *extack) -{ - int err; - - err = __esw_qos_destroy_rate_group(esw, group, extack); - esw_qos_put(esw); - - return err; + trace_mlx5_esw_node_qos_destroy(esw->dev, node, node->ix); + esw_qos_destroy_node(node, extack); + esw_qos_normalize_min_rate(esw, NULL, extack); } static int esw_qos_create(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack) { - u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; struct mlx5_core_dev *dev = esw->dev; - __be32 *attr; int err; if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling)) return -EOPNOTSUPP; - if (!esw_qos_element_type_supported(dev, SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR) || - !(MLX5_CAP_QOS(dev, esw_tsar_type) & TSAR_TYPE_CAP_MASK_DWRR)) - return -EOPNOTSUPP; - - MLX5_SET(scheduling_context, tsar_ctx, element_type, - SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR); - - attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes); - *attr = cpu_to_be32(TSAR_ELEMENT_TSAR_TYPE_DWRR << 16); - - err = mlx5_create_scheduling_element_cmd(dev, - SCHEDULING_HIERARCHY_E_SWITCH, - tsar_ctx, - &esw->qos.root_tsar_ix); + err = esw_qos_create_node_sched_elem(esw->dev, 0, &esw->qos.root_tsar_ix); if (err) { esw_warn(dev, "E-Switch create root TSAR failed (%d)\n", err); return err; } - INIT_LIST_HEAD(&esw->qos.groups); if (MLX5_CAP_QOS(dev, log_esw_max_sched_depth)) { - esw->qos.group0 = __esw_qos_create_rate_group(esw, extack); - if (IS_ERR(esw->qos.group0)) { - esw_warn(dev, "E-Switch create rate group 0 failed (%ld)\n", - PTR_ERR(esw->qos.group0)); - err = PTR_ERR(esw->qos.group0); - goto err_group0; - } + esw->qos.node0 = __esw_qos_create_vports_sched_node(esw, NULL, extack); + } else { + /* The eswitch doesn't support scheduling nodes. + * Create a software-only node0 using the root TSAR to attach vport QoS to. + */ + if (!__esw_qos_alloc_node(esw, + esw->qos.root_tsar_ix, + SCHED_NODE_TYPE_VPORTS_TSAR, + NULL)) + esw->qos.node0 = ERR_PTR(-ENOMEM); + } + if (IS_ERR(esw->qos.node0)) { + err = PTR_ERR(esw->qos.node0); + esw_warn(dev, "E-Switch create rate node 0 failed (%d)\n", err); + goto err_node0; } refcount_set(&esw->qos.refcnt, 1); return 0; -err_group0: +err_node0: if (mlx5_destroy_scheduling_element_cmd(esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, esw->qos.root_tsar_ix)) esw_warn(esw->dev, "E-Switch destroy root TSAR failed.\n"); @@ -610,8 +502,11 @@ static void esw_qos_destroy(struct mlx5_eswitch *esw) { int err; - if (esw->qos.group0) - __esw_qos_destroy_rate_group(esw, esw->qos.group0, NULL); + if (esw->qos.node0->ix != esw->qos.root_tsar_ix) + __esw_qos_destroy_node(esw->qos.node0, NULL); + else + __esw_qos_free_node(esw->qos.node0); + esw->qos.node0 = NULL; err = mlx5_destroy_scheduling_element_cmd(esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, @@ -624,8 +519,7 @@ static int esw_qos_get(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack) { int err = 0; - lockdep_assert_held(&esw->state_lock); - + esw_assert_qos_lock_held(esw); if (!refcount_inc_not_zero(&esw->qos.refcnt)) { /* esw_qos_create() set refcount to 1 only on success. * No need to decrement on failure. @@ -638,77 +532,169 @@ static int esw_qos_get(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack) static void esw_qos_put(struct mlx5_eswitch *esw) { - lockdep_assert_held(&esw->state_lock); + esw_assert_qos_lock_held(esw); if (refcount_dec_and_test(&esw->qos.refcnt)) esw_qos_destroy(esw); } -static int esw_qos_vport_enable(struct mlx5_eswitch *esw, struct mlx5_vport *vport, - u32 max_rate, u32 bw_share, struct netlink_ext_ack *extack) +static void esw_qos_vport_disable(struct mlx5_vport *vport, struct netlink_ext_ack *extack) +{ + struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node; + struct mlx5_esw_sched_node *parent = vport_node->parent; + + esw_qos_node_destroy_sched_element(vport_node, extack); + + vport_node->bw_share = 0; + list_del_init(&vport_node->entry); + esw_qos_normalize_min_rate(parent->esw, parent, extack); + + trace_mlx5_esw_vport_qos_destroy(vport_node->esw->dev, vport); +} + +static int esw_qos_vport_enable(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent, + struct netlink_ext_ack *extack) { int err; - lockdep_assert_held(&esw->state_lock); - if (vport->qos.enabled) - return 0; + esw_assert_qos_lock_held(vport->dev->priv.eswitch); + + esw_qos_node_set_parent(vport->qos.sched_node, parent); + err = esw_qos_vport_create_sched_element(vport->qos.sched_node, extack); + if (err) + return err; + + esw_qos_normalize_min_rate(parent->esw, parent, extack); + + return 0; +} + +static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_type type, + struct mlx5_esw_sched_node *parent, u32 max_rate, + u32 min_rate, struct netlink_ext_ack *extack) +{ + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; + struct mlx5_esw_sched_node *sched_node; + int err; + esw_assert_qos_lock_held(esw); err = esw_qos_get(esw, extack); if (err) return err; - vport->qos.group = esw->qos.group0; + parent = parent ?: esw->qos.node0; + sched_node = __esw_qos_alloc_node(parent->esw, 0, type, parent); + if (!sched_node) + return -ENOMEM; - err = esw_qos_vport_create_sched_element(esw, vport, max_rate, bw_share); + sched_node->max_rate = max_rate; + sched_node->min_rate = min_rate; + sched_node->vport = vport; + vport->qos.sched_node = sched_node; + err = esw_qos_vport_enable(vport, parent, extack); if (err) - goto err_out; + esw_qos_put(esw); - vport->qos.enabled = true; - trace_mlx5_esw_vport_qos_create(vport, bw_share, max_rate); + return err; +} - return 0; +void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport) +{ + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; + struct mlx5_esw_sched_node *parent; -err_out: + lockdep_assert_held(&esw->state_lock); + esw_qos_lock(esw); + if (!vport->qos.sched_node) + goto unlock; + + parent = vport->qos.sched_node->parent; + WARN(parent != esw->qos.node0, "Disabling QoS on port before detaching it from node"); + + esw_qos_vport_disable(vport, NULL); + mlx5_esw_qos_vport_qos_free(vport); esw_qos_put(esw); +unlock: + esw_qos_unlock(esw); +} - return err; +static int mlx5_esw_qos_set_vport_max_rate(struct mlx5_vport *vport, u32 max_rate, + struct netlink_ext_ack *extack) +{ + struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node; + + esw_assert_qos_lock_held(vport->dev->priv.eswitch); + + if (!vport_node) + return mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, NULL, max_rate, 0, + extack); + else + return esw_qos_sched_elem_config(vport_node, max_rate, vport_node->bw_share, + extack); } -void mlx5_esw_qos_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport) +static int mlx5_esw_qos_set_vport_min_rate(struct mlx5_vport *vport, u32 min_rate, + struct netlink_ext_ack *extack) { - int err; + struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node; - lockdep_assert_held(&esw->state_lock); - if (!vport->qos.enabled) - return; - WARN(vport->qos.group && vport->qos.group != esw->qos.group0, - "Disabling QoS on port before detaching it from group"); + esw_assert_qos_lock_held(vport->dev->priv.eswitch); - err = mlx5_destroy_scheduling_element_cmd(esw->dev, - SCHEDULING_HIERARCHY_E_SWITCH, - vport->qos.esw_tsar_ix); - if (err) - esw_warn(esw->dev, "E-Switch destroy TSAR vport element failed (vport=%d,err=%d)\n", - vport->vport, err); + if (!vport_node) + return mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, NULL, 0, min_rate, + extack); + else + return esw_qos_set_node_min_rate(vport_node, min_rate, extack); +} - memset(&vport->qos, 0, sizeof(vport->qos)); - trace_mlx5_esw_vport_qos_destroy(vport); +int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *vport, u32 max_rate, u32 min_rate) +{ + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; + int err; - esw_qos_put(esw); + esw_qos_lock(esw); + err = mlx5_esw_qos_set_vport_min_rate(vport, min_rate, NULL); + if (!err) + err = mlx5_esw_qos_set_vport_max_rate(vport, max_rate, NULL); + esw_qos_unlock(esw); + return err; +} + +bool mlx5_esw_qos_get_vport_rate(struct mlx5_vport *vport, u32 *max_rate, u32 *min_rate) +{ + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; + bool enabled; + + esw_qos_lock(esw); + enabled = !!vport->qos.sched_node; + if (enabled) { + *max_rate = vport->qos.sched_node->max_rate; + *min_rate = vport->qos.sched_node->min_rate; + } + esw_qos_unlock(esw); + return enabled; } -int mlx5_esw_qos_set_vport_rate(struct mlx5_eswitch *esw, struct mlx5_vport *vport, - u32 max_rate, u32 min_rate) +static int esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent, + struct netlink_ext_ack *extack) { + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; + struct mlx5_esw_sched_node *curr_parent; int err; - lockdep_assert_held(&esw->state_lock); - err = esw_qos_vport_enable(esw, vport, 0, 0, NULL); - if (err) - return err; + esw_assert_qos_lock_held(esw); + curr_parent = vport->qos.sched_node->parent; + parent = parent ?: esw->qos.node0; + if (curr_parent == parent) + return 0; - err = esw_qos_set_vport_min_rate(esw, vport, min_rate, NULL); - if (!err) - err = esw_qos_set_vport_max_rate(esw, vport, max_rate, NULL); + esw_qos_vport_disable(vport, extack); + + err = esw_qos_vport_enable(vport, parent, extack); + if (err) { + if (esw_qos_vport_enable(vport, curr_parent, NULL)) + esw_warn(parent->esw->dev, "vport restore QoS failed (vport=%d)\n", + vport->vport); + } return err; } @@ -779,10 +765,8 @@ static int mlx5_esw_qos_link_speed_verify(struct mlx5_core_dev *mdev, int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps) { - u32 ctx[MLX5_ST_SZ_DW(scheduling_context)] = {}; struct mlx5_vport *vport; u32 link_speed_max; - u32 bitmask; int err; vport = mlx5_eswitch_get_vport(esw, vport_num); @@ -800,21 +784,9 @@ int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 return err; } - mutex_lock(&esw->state_lock); - if (!vport->qos.enabled) { - /* Eswitch QoS wasn't enabled yet. Enable it and vport QoS. */ - err = esw_qos_vport_enable(esw, vport, rate_mbps, vport->qos.bw_share, NULL); - } else { - MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps); - - bitmask = MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW; - err = mlx5_modify_scheduling_element_cmd(esw->dev, - SCHEDULING_HIERARCHY_E_SWITCH, - ctx, - vport->qos.esw_tsar_ix, - bitmask); - } - mutex_unlock(&esw->state_lock); + esw_qos_lock(esw); + err = mlx5_esw_qos_set_vport_max_rate(vport, rate_mbps, NULL); + esw_qos_unlock(esw); return err; } @@ -852,6 +824,20 @@ static int esw_qos_devlink_rate_to_mbps(struct mlx5_core_dev *mdev, const char * return 0; } +int mlx5_esw_qos_init(struct mlx5_eswitch *esw) +{ + if (esw->qos.domain) + return 0; /* Nothing to change. */ + + return esw_qos_domain_init(esw); +} + +void mlx5_esw_qos_cleanup(struct mlx5_eswitch *esw) +{ + if (esw->qos.domain) + esw_qos_domain_release(esw); +} + /* Eswitch devlink rate API */ int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void *priv, @@ -869,14 +855,9 @@ int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void if (err) return err; - mutex_lock(&esw->state_lock); - err = esw_qos_vport_enable(esw, vport, 0, 0, extack); - if (err) - goto unlock; - - err = esw_qos_set_vport_min_rate(esw, vport, tx_share, extack); -unlock: - mutex_unlock(&esw->state_lock); + esw_qos_lock(esw); + err = mlx5_esw_qos_set_vport_min_rate(vport, tx_share, extack); + esw_qos_unlock(esw); return err; } @@ -895,57 +876,50 @@ int mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void * if (err) return err; - mutex_lock(&esw->state_lock); - err = esw_qos_vport_enable(esw, vport, 0, 0, extack); - if (err) - goto unlock; - - err = esw_qos_set_vport_max_rate(esw, vport, tx_max, extack); -unlock: - mutex_unlock(&esw->state_lock); + esw_qos_lock(esw); + err = mlx5_esw_qos_set_vport_max_rate(vport, tx_max, extack); + esw_qos_unlock(esw); return err; } int mlx5_esw_devlink_rate_node_tx_share_set(struct devlink_rate *rate_node, void *priv, u64 tx_share, struct netlink_ext_ack *extack) { - struct mlx5_core_dev *dev = devlink_priv(rate_node->devlink); - struct mlx5_eswitch *esw = dev->priv.eswitch; - struct mlx5_esw_rate_group *group = priv; + struct mlx5_esw_sched_node *node = priv; + struct mlx5_eswitch *esw = node->esw; int err; - err = esw_qos_devlink_rate_to_mbps(dev, "tx_share", &tx_share, extack); + err = esw_qos_devlink_rate_to_mbps(esw->dev, "tx_share", &tx_share, extack); if (err) return err; - mutex_lock(&esw->state_lock); - err = esw_qos_set_group_min_rate(esw, group, tx_share, extack); - mutex_unlock(&esw->state_lock); + esw_qos_lock(esw); + err = esw_qos_set_node_min_rate(node, tx_share, extack); + esw_qos_unlock(esw); return err; } int mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *priv, u64 tx_max, struct netlink_ext_ack *extack) { - struct mlx5_core_dev *dev = devlink_priv(rate_node->devlink); - struct mlx5_eswitch *esw = dev->priv.eswitch; - struct mlx5_esw_rate_group *group = priv; + struct mlx5_esw_sched_node *node = priv; + struct mlx5_eswitch *esw = node->esw; int err; - err = esw_qos_devlink_rate_to_mbps(dev, "tx_max", &tx_max, extack); + err = esw_qos_devlink_rate_to_mbps(esw->dev, "tx_max", &tx_max, extack); if (err) return err; - mutex_lock(&esw->state_lock); - err = esw_qos_set_group_max_rate(esw, group, tx_max, extack); - mutex_unlock(&esw->state_lock); + esw_qos_lock(esw); + err = esw_qos_sched_elem_config(node, tx_max, node->bw_share, extack); + esw_qos_unlock(esw); return err; } int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv, struct netlink_ext_ack *extack) { - struct mlx5_esw_rate_group *group; + struct mlx5_esw_sched_node *node; struct mlx5_eswitch *esw; int err = 0; @@ -953,7 +927,7 @@ int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv, if (IS_ERR(esw)) return PTR_ERR(esw); - mutex_lock(&esw->state_lock); + esw_qos_lock(esw); if (esw->mode != MLX5_ESWITCH_OFFLOADS) { NL_SET_ERR_MSG_MOD(extack, "Rate node creation supported only in switchdev mode"); @@ -961,51 +935,48 @@ int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv, goto unlock; } - group = esw_qos_create_rate_group(esw, extack); - if (IS_ERR(group)) { - err = PTR_ERR(group); + node = esw_qos_create_vports_sched_node(esw, extack); + if (IS_ERR(node)) { + err = PTR_ERR(node); goto unlock; } - *priv = group; + *priv = node; unlock: - mutex_unlock(&esw->state_lock); + esw_qos_unlock(esw); return err; } int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv, struct netlink_ext_ack *extack) { - struct mlx5_esw_rate_group *group = priv; - struct mlx5_eswitch *esw; - int err; + struct mlx5_esw_sched_node *node = priv; + struct mlx5_eswitch *esw = node->esw; - esw = mlx5_devlink_eswitch_get(rate_node->devlink); - if (IS_ERR(esw)) - return PTR_ERR(esw); - - mutex_lock(&esw->state_lock); - err = esw_qos_destroy_rate_group(esw, group, extack); - mutex_unlock(&esw->state_lock); - return err; + esw_qos_lock(esw); + __esw_qos_destroy_node(node, extack); + esw_qos_put(esw); + esw_qos_unlock(esw); + return 0; } -int mlx5_esw_qos_vport_update_group(struct mlx5_eswitch *esw, - struct mlx5_vport *vport, - struct mlx5_esw_rate_group *group, - struct netlink_ext_ack *extack) +int mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent, + struct netlink_ext_ack *extack) { + struct mlx5_eswitch *esw = vport->dev->priv.eswitch; int err = 0; - mutex_lock(&esw->state_lock); - if (!vport->qos.enabled && !group) - goto unlock; + if (parent && parent->esw != esw) { + NL_SET_ERR_MSG_MOD(extack, "Cross E-Switch scheduling is not supported"); + return -EOPNOTSUPP; + } - err = esw_qos_vport_enable(esw, vport, 0, 0, extack); - if (!err) - err = esw_qos_vport_update_group(esw, vport, group, extack); -unlock: - mutex_unlock(&esw->state_lock); + esw_qos_lock(esw); + if (!vport->qos.sched_node && parent) + err = mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, parent, 0, 0, extack); + else if (vport->qos.sched_node) + err = esw_qos_vport_update_parent(vport, parent, extack); + esw_qos_unlock(esw); return err; } @@ -1014,13 +985,12 @@ int mlx5_esw_devlink_rate_parent_set(struct devlink_rate *devlink_rate, void *priv, void *parent_priv, struct netlink_ext_ack *extack) { - struct mlx5_esw_rate_group *group; + struct mlx5_esw_sched_node *node; struct mlx5_vport *vport = priv; if (!parent) - return mlx5_esw_qos_vport_update_group(vport->dev->priv.eswitch, - vport, NULL, extack); + return mlx5_esw_qos_vport_update_parent(vport, NULL, extack); - group = parent_priv; - return mlx5_esw_qos_vport_update_group(vport->dev->priv.eswitch, vport, group, extack); + node = parent_priv; + return mlx5_esw_qos_vport_update_parent(vport, node, extack); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h index 0141e9d52037fa..6eb8f6a648c83f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.h @@ -6,9 +6,16 @@ #ifdef CONFIG_MLX5_ESWITCH -int mlx5_esw_qos_set_vport_rate(struct mlx5_eswitch *esw, struct mlx5_vport *evport, - u32 max_rate, u32 min_rate); -void mlx5_esw_qos_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport); +int mlx5_esw_qos_init(struct mlx5_eswitch *esw); +void mlx5_esw_qos_cleanup(struct mlx5_eswitch *esw); + +int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *evport, u32 max_rate, u32 min_rate); +bool mlx5_esw_qos_get_vport_rate(struct mlx5_vport *vport, u32 *max_rate, u32 *min_rate); +void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport); + +void mlx5_esw_qos_vport_qos_free(struct mlx5_vport *vport); +u32 mlx5_esw_qos_vport_get_sched_elem_ix(const struct mlx5_vport *vport); +struct mlx5_esw_sched_node *mlx5_esw_qos_vport_get_parent(const struct mlx5_vport *vport); int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void *priv, u64 tx_share, struct netlink_ext_ack *extack); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 7aef30dbd82d6c..7fb8a3381f849e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -894,7 +894,7 @@ static void esw_vport_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport vport_num, 1, MLX5_VPORT_ADMIN_STATE_DOWN); - mlx5_esw_qos_vport_disable(esw, vport); + mlx5_esw_qos_vport_disable(vport); esw_vport_cleanup_acl(esw, vport); } @@ -1061,7 +1061,7 @@ static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw) unsigned long i; mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) { - memset(&vport->qos, 0, sizeof(vport->qos)); + mlx5_esw_qos_vport_qos_free(vport); memset(&vport->info, 0, sizeof(vport->info)); vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO; } @@ -1073,7 +1073,7 @@ static void mlx5_eswitch_clear_ec_vf_vports_info(struct mlx5_eswitch *esw) unsigned long i; mlx5_esw_for_each_ec_vf_vport(esw, i, vport, esw->esw_funcs.num_ec_vfs) { - memset(&vport->qos, 0, sizeof(vport->qos)); + mlx5_esw_qos_vport_qos_free(vport); memset(&vport->info, 0, sizeof(vport->info)); vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO; } @@ -1481,15 +1481,18 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs) MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE); mlx5_eq_notifier_register(esw->dev, &esw->nb); + err = mlx5_esw_qos_init(esw); + if (err) + goto err_esw_init; + if (esw->mode == MLX5_ESWITCH_LEGACY) { err = esw_legacy_enable(esw); } else { - mlx5_rescan_drivers(esw->dev); err = esw_offloads_enable(esw); } if (err) - goto err_esw_enable; + goto err_esw_init; esw->fdb_table.flags |= MLX5_ESW_FDB_CREATED; @@ -1503,7 +1506,7 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs) return 0; -err_esw_enable: +err_esw_init: mlx5_eq_notifier_unregister(esw->dev, &esw->nb); mlx5_esw_acls_ns_cleanup(esw); return err; @@ -1875,6 +1878,11 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) if (err) goto reps_err; + esw->mode = MLX5_ESWITCH_LEGACY; + err = mlx5_esw_qos_init(esw); + if (err) + goto reps_err; + mutex_init(&esw->offloads.encap_tbl_lock); hash_init(esw->offloads.encap_tbl); mutex_init(&esw->offloads.decap_tbl_lock); @@ -1888,7 +1896,6 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) refcount_set(&esw->qos.refcnt, 0); esw->enabled_vports = 0; - esw->mode = MLX5_ESWITCH_LEGACY; esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE; if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) && MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)) @@ -1925,6 +1932,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) esw_info(esw->dev, "cleanup\n"); + mlx5_esw_qos_cleanup(esw); destroy_workqueue(esw->work_queue); WARN_ON(refcount_read(&esw->qos.refcnt)); mutex_destroy(&esw->state_lock); @@ -2061,6 +2069,7 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw, u16 vport, struct ifla_vf_info *ivi) { struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport); + u32 max_rate, min_rate; if (IS_ERR(evport)) return PTR_ERR(evport); @@ -2075,9 +2084,10 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw, ivi->qos = evport->info.qos; ivi->spoofchk = evport->info.spoofchk; ivi->trusted = evport->info.trusted; - if (evport->qos.enabled) { - ivi->min_tx_rate = evport->qos.min_rate; - ivi->max_tx_rate = evport->qos.max_rate; + + if (mlx5_esw_qos_get_vport_rate(evport, &max_rate, &min_rate)) { + ivi->max_tx_rate = max_rate; + ivi->min_tx_rate = min_rate; } mutex_unlock(&esw->state_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index f44b4c7ebcfd73..a83d41121db671 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -212,13 +212,10 @@ struct mlx5_vport { struct mlx5_vport_info info; + /* Protected with the E-Switch qos domain lock. */ struct { - bool enabled; - u32 esw_tsar_ix; - u32 bw_share; - u32 min_rate; - u32 max_rate; - struct mlx5_esw_rate_group *group; + /* Vport scheduling element node. */ + struct mlx5_esw_sched_node *sched_node; } qos; u16 vport; @@ -333,6 +330,7 @@ enum { }; struct dentry; +struct mlx5_qos_domain; struct mlx5_eswitch { struct mlx5_core_dev *dev; @@ -359,15 +357,17 @@ struct mlx5_eswitch { struct rw_semaphore mode_lock; atomic64_t user_count; + /* Protected with the E-Switch qos domain lock. */ struct { - u32 root_tsar_ix; - struct mlx5_esw_rate_group *group0; - struct list_head groups; /* Protected by esw->state_lock */ - - /* Protected by esw->state_lock. - * Initially 0, meaning no QoS users and QoS is disabled. - */ + /* Initially 0, meaning no QoS users and QoS is disabled. */ refcount_t refcnt; + u32 root_tsar_ix; + struct mlx5_qos_domain *domain; + /* Contains all vports with QoS enabled but no explicit node. + * Cannot be NULL if QoS is enabled, but may be a fake node + * referencing the root TSAR if the esw doesn't support nodes. + */ + struct mlx5_esw_sched_node *node0; } qos; struct mlx5_esw_bridge_offloads *br_offloads; @@ -427,10 +427,8 @@ int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw, u16 vport_num, bool setting); int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, u16 vport, u32 max_rate, u32 min_rate); -int mlx5_esw_qos_vport_update_group(struct mlx5_eswitch *esw, - struct mlx5_vport *vport, - struct mlx5_esw_rate_group *group, - struct netlink_ext_ack *extack); +int mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *node, + struct netlink_ext_ack *extack); int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting); int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting); int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw, @@ -806,7 +804,7 @@ int mlx5_esw_offloads_sf_devlink_port_init(struct mlx5_eswitch *esw, struct mlx5 void mlx5_esw_offloads_sf_devlink_port_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport); int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx5_vport *vport); -void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct mlx5_vport *vport); +void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport); struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num); int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 *sf_base_id); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 8cf61ae8b89d24..d5b42b3a19fdf7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2332,18 +2332,36 @@ static int esw_create_restore_table(struct mlx5_eswitch *esw) return err; } +static void esw_mode_change(struct mlx5_eswitch *esw, u16 mode) +{ + mlx5_devcom_comp_lock(esw->dev->priv.hca_devcom_comp); + if (esw->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV || + mlx5_core_mp_enabled(esw->dev)) { + esw->mode = mode; + mlx5_rescan_drivers_locked(esw->dev); + mlx5_devcom_comp_unlock(esw->dev->priv.hca_devcom_comp); + return; + } + + esw->dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; + mlx5_rescan_drivers_locked(esw->dev); + esw->mode = mode; + esw->dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; + mlx5_rescan_drivers_locked(esw->dev); + mlx5_devcom_comp_unlock(esw->dev->priv.hca_devcom_comp); +} + static int esw_offloads_start(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack) { int err; - esw->mode = MLX5_ESWITCH_OFFLOADS; + esw_mode_change(esw, MLX5_ESWITCH_OFFLOADS); err = mlx5_eswitch_enable_locked(esw, esw->dev->priv.sriov.num_vfs); if (err) { NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to offloads"); - esw->mode = MLX5_ESWITCH_LEGACY; - mlx5_rescan_drivers(esw->dev); + esw_mode_change(esw, MLX5_ESWITCH_LEGACY); return err; } if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) { @@ -2620,7 +2638,7 @@ int mlx5_esw_offloads_load_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vpor return err; load_err: - mlx5_esw_offloads_devlink_port_unregister(esw, vport); + mlx5_esw_offloads_devlink_port_unregister(vport); return err; } @@ -2631,7 +2649,7 @@ void mlx5_esw_offloads_unload_rep(struct mlx5_eswitch *esw, struct mlx5_vport *v mlx5_esw_offloads_rep_unload(esw, vport->vport); - mlx5_esw_offloads_devlink_port_unregister(esw, vport); + mlx5_esw_offloads_devlink_port_unregister(vport); } static int esw_set_slave_root_fdb(struct mlx5_core_dev *master, @@ -3587,7 +3605,7 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw, { int err; - esw->mode = MLX5_ESWITCH_LEGACY; + esw_mode_change(esw, MLX5_ESWITCH_LEGACY); /* If changing from switchdev to legacy mode without sriov enabled, * no need to create legacy fdb. @@ -3773,7 +3791,6 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, err = esw_offloads_start(esw, extack); } else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) { err = esw_offloads_stop(esw, extack); - mlx5_rescan_drivers(esw->dev); } else { err = -EINVAL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 6e4f8aaf8d2f21..2eabfcc247c6ae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -3698,6 +3698,7 @@ void mlx5_fs_core_free(struct mlx5_core_dev *dev) int mlx5_fs_core_alloc(struct mlx5_core_dev *dev) { struct mlx5_flow_steering *steering; + char name[80]; int err = 0; err = mlx5_init_fc_stats(dev); @@ -3722,10 +3723,12 @@ int mlx5_fs_core_alloc(struct mlx5_core_dev *dev) else steering->mode = MLX5_FLOW_STEERING_MODE_DMFS; - steering->fgs_cache = kmem_cache_create("mlx5_fs_fgs", + snprintf(name, sizeof(name), "%s-mlx5_fs_fgs", dev_name(dev->device)); + steering->fgs_cache = kmem_cache_create(name, sizeof(struct mlx5_flow_group), 0, 0, NULL); - steering->ftes_cache = kmem_cache_create("mlx5_fs_ftes", sizeof(struct fs_fte), 0, + snprintf(name, sizeof(name), "%s-mlx5_fs_ftes", dev_name(dev->device)); + steering->ftes_cache = kmem_cache_create(name, sizeof(struct fs_fte), 0, 0, NULL); if (!steering->ftes_cache || !steering->fgs_cache) { err = -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index 964937f17cf54b..bad2df0715ecc9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include #define FDB_TC_MAX_CHAIN 3 #define FDB_FT_CHAIN (FDB_TC_MAX_CHAIN + 1) @@ -63,7 +63,7 @@ struct mlx5_modify_hdr { enum mlx5_flow_namespace_type ns_type; enum mlx5_flow_resource_owner owner; union { - struct mlx5_fs_dr_action action; + struct mlx5_fs_dr_action fs_dr_action; u32 id; }; }; @@ -73,7 +73,7 @@ struct mlx5_pkt_reformat { int reformat_type; /* from mlx5_ifc */ enum mlx5_flow_resource_owner owner; union { - struct mlx5_fs_dr_action action; + struct mlx5_fs_dr_action fs_dr_action; u32 id; }; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index 0c26d707eed27b..62d0c689796b97 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -32,13 +32,11 @@ #include #include -#include #include "mlx5_core.h" #include "fs_core.h" #include "fs_cmd.h" #define MLX5_FC_STATS_PERIOD msecs_to_jiffies(1000) -#define MLX5_FC_BULK_QUERY_ALLOC_PERIOD msecs_to_jiffies(180 * 1000) /* Max number of counters to query in bulk read is 32K */ #define MLX5_SW_MAX_COUNTERS_BULK BIT(15) #define MLX5_INIT_COUNTERS_BULK 8 @@ -52,21 +50,37 @@ struct mlx5_fc_cache { }; struct mlx5_fc { - struct list_head list; - struct llist_node addlist; - struct llist_node dellist; - - /* last{packets,bytes} members are used when calculating the delta since - * last reading - */ + u32 id; + bool aging; + struct mlx5_fc_bulk *bulk; + struct mlx5_fc_cache cache; + /* last{packets,bytes} are used for calculating deltas since last reading. */ u64 lastpackets; u64 lastbytes; +}; - struct mlx5_fc_bulk *bulk; - u32 id; - bool aging; +struct mlx5_fc_pool { + struct mlx5_core_dev *dev; + struct mutex pool_lock; /* protects pool lists */ + struct list_head fully_used; + struct list_head partially_used; + struct list_head unused; + int available_fcs; + int used_fcs; + int threshold; +}; - struct mlx5_fc_cache cache ____cacheline_aligned_in_smp; +struct mlx5_fc_stats { + struct xarray counters; + + struct workqueue_struct *wq; + struct delayed_work work; + unsigned long sampling_interval; /* jiffies */ + u32 *bulk_query_out; + int bulk_query_len; + bool bulk_query_alloc_failed; + unsigned long next_bulk_query_alloc; + struct mlx5_fc_pool fc_pool; }; static void mlx5_fc_pool_init(struct mlx5_fc_pool *fc_pool, struct mlx5_core_dev *dev); @@ -74,78 +88,6 @@ static void mlx5_fc_pool_cleanup(struct mlx5_fc_pool *fc_pool); static struct mlx5_fc *mlx5_fc_pool_acquire_counter(struct mlx5_fc_pool *fc_pool); static void mlx5_fc_pool_release_counter(struct mlx5_fc_pool *fc_pool, struct mlx5_fc *fc); -/* locking scheme: - * - * It is the responsibility of the user to prevent concurrent calls or bad - * ordering to mlx5_fc_create(), mlx5_fc_destroy() and accessing a reference - * to struct mlx5_fc. - * e.g en_tc.c is protected by RTNL lock of its caller, and will never call a - * dump (access to struct mlx5_fc) after a counter is destroyed. - * - * access to counter list: - * - create (user context) - * - mlx5_fc_create() only adds to an addlist to be used by - * mlx5_fc_stats_work(). addlist is a lockless single linked list - * that doesn't require any additional synchronization when adding single - * node. - * - spawn thread to do the actual destroy - * - * - destroy (user context) - * - add a counter to lockless dellist - * - spawn thread to do the actual del - * - * - dump (user context) - * user should not call dump after destroy - * - * - query (single thread workqueue context) - * destroy/dump - no conflict (see destroy) - * query/dump - packets and bytes might be inconsistent (since update is not - * atomic) - * query/create - no conflict (see create) - * since every create/destroy spawn the work, only after necessary time has - * elapsed, the thread will actually query the hardware. - */ - -static struct list_head *mlx5_fc_counters_lookup_next(struct mlx5_core_dev *dev, - u32 id) -{ - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - unsigned long next_id = (unsigned long)id + 1; - struct mlx5_fc *counter; - unsigned long tmp; - - rcu_read_lock(); - /* skip counters that are in idr, but not yet in counters list */ - idr_for_each_entry_continue_ul(&fc_stats->counters_idr, - counter, tmp, next_id) { - if (!list_empty(&counter->list)) - break; - } - rcu_read_unlock(); - - return counter ? &counter->list : &fc_stats->counters; -} - -static void mlx5_fc_stats_insert(struct mlx5_core_dev *dev, - struct mlx5_fc *counter) -{ - struct list_head *next = mlx5_fc_counters_lookup_next(dev, counter->id); - - list_add_tail(&counter->list, next); -} - -static void mlx5_fc_stats_remove(struct mlx5_core_dev *dev, - struct mlx5_fc *counter) -{ - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - - list_del(&counter->list); - - spin_lock(&fc_stats->counters_idr_lock); - WARN_ON(!idr_remove(&fc_stats->counters_idr, counter->id)); - spin_unlock(&fc_stats->counters_idr_lock); -} - static int get_init_bulk_query_len(struct mlx5_core_dev *dev) { return min_t(int, MLX5_INIT_COUNTERS_BULK, @@ -174,47 +116,64 @@ static void update_counter_cache(int index, u32 *bulk_raw_data, cache->lastuse = jiffies; } -static void mlx5_fc_stats_query_counter_range(struct mlx5_core_dev *dev, - struct mlx5_fc *first, - u32 last_id) +/* Synchronization notes + * + * Access to counter array: + * - create - mlx5_fc_create() (user context) + * - inserts the counter into the xarray. + * + * - destroy - mlx5_fc_destroy() (user context) + * - erases the counter from the xarray and releases it. + * + * - query mlx5_fc_query(), mlx5_fc_query_cached{,_raw}() (user context) + * - user should not access a counter after destroy. + * + * - bulk query (single thread workqueue context) + * - create: query relies on 'lastuse' to avoid updating counters added + * around the same time as the current bulk cmd. + * - destroy: destroyed counters will not be accessed, even if they are + * destroyed during a bulk query command. + */ +static void mlx5_fc_stats_query_all_counters(struct mlx5_core_dev *dev) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - bool query_more_counters = (first->id <= last_id); - int cur_bulk_len = fc_stats->bulk_query_len; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; + u32 bulk_len = fc_stats->bulk_query_len; + XA_STATE(xas, &fc_stats->counters, 0); u32 *data = fc_stats->bulk_query_out; - struct mlx5_fc *counter = first; + struct mlx5_fc *counter; + u32 last_bulk_id = 0; + u64 bulk_query_time; u32 bulk_base_id; - int bulk_len; int err; - while (query_more_counters) { - /* first id must be aligned to 4 when using bulk query */ - bulk_base_id = counter->id & ~0x3; - - /* number of counters to query inc. the last counter */ - bulk_len = min_t(int, cur_bulk_len, - ALIGN(last_id - bulk_base_id + 1, 4)); - - err = mlx5_cmd_fc_bulk_query(dev, bulk_base_id, bulk_len, - data); - if (err) { - mlx5_core_err(dev, "Error doing bulk query: %d\n", err); - return; - } - query_more_counters = false; - - list_for_each_entry_from(counter, &fc_stats->counters, list) { - int counter_index = counter->id - bulk_base_id; - struct mlx5_fc_cache *cache = &counter->cache; - - if (counter->id >= bulk_base_id + bulk_len) { - query_more_counters = true; - break; + xas_lock(&xas); + xas_for_each(&xas, counter, U32_MAX) { + if (xas_retry(&xas, counter)) + continue; + if (unlikely(counter->id >= last_bulk_id)) { + /* Start new bulk query. */ + /* First id must be aligned to 4 when using bulk query. */ + bulk_base_id = counter->id & ~0x3; + last_bulk_id = bulk_base_id + bulk_len; + /* The lock is released while querying the hw and reacquired after. */ + xas_unlock(&xas); + /* The same id needs to be processed again in the next loop iteration. */ + xas_reset(&xas); + bulk_query_time = jiffies; + err = mlx5_cmd_fc_bulk_query(dev, bulk_base_id, bulk_len, data); + if (err) { + mlx5_core_err(dev, "Error doing bulk query: %d\n", err); + return; } - - update_counter_cache(counter_index, data, cache); + xas_lock(&xas); + continue; } + /* Do not update counters added after bulk query was started. */ + if (time_after64(bulk_query_time, counter->cache.lastuse)) + update_counter_cache(counter->id - bulk_base_id, data, + &counter->cache); } + xas_unlock(&xas); } static void mlx5_fc_free(struct mlx5_core_dev *dev, struct mlx5_fc *counter) @@ -225,7 +184,7 @@ static void mlx5_fc_free(struct mlx5_core_dev *dev, struct mlx5_fc *counter) static void mlx5_fc_release(struct mlx5_core_dev *dev, struct mlx5_fc *counter) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; if (counter->bulk) mlx5_fc_pool_release_counter(&fc_stats->fc_pool, counter); @@ -233,85 +192,55 @@ static void mlx5_fc_release(struct mlx5_core_dev *dev, struct mlx5_fc *counter) mlx5_fc_free(dev, counter); } -static void mlx5_fc_stats_bulk_query_size_increase(struct mlx5_core_dev *dev) +static void mlx5_fc_stats_bulk_query_buf_realloc(struct mlx5_core_dev *dev, + int bulk_query_len) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - int max_bulk_len = get_max_bulk_query_len(dev); - unsigned long now = jiffies; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; u32 *bulk_query_out_tmp; - int max_out_len; - - if (fc_stats->bulk_query_alloc_failed && - time_before(now, fc_stats->next_bulk_query_alloc)) - return; + int out_len; - max_out_len = mlx5_cmd_fc_get_bulk_query_out_len(max_bulk_len); - bulk_query_out_tmp = kzalloc(max_out_len, GFP_KERNEL); + out_len = mlx5_cmd_fc_get_bulk_query_out_len(bulk_query_len); + bulk_query_out_tmp = kvzalloc(out_len, GFP_KERNEL); if (!bulk_query_out_tmp) { mlx5_core_warn_once(dev, - "Can't increase flow counters bulk query buffer size, insufficient memory, bulk_size(%d)\n", - max_bulk_len); - fc_stats->bulk_query_alloc_failed = true; - fc_stats->next_bulk_query_alloc = - now + MLX5_FC_BULK_QUERY_ALLOC_PERIOD; + "Can't increase flow counters bulk query buffer size, alloc failed, bulk_query_len(%d)\n", + bulk_query_len); return; } - kfree(fc_stats->bulk_query_out); + kvfree(fc_stats->bulk_query_out); fc_stats->bulk_query_out = bulk_query_out_tmp; - fc_stats->bulk_query_len = max_bulk_len; - if (fc_stats->bulk_query_alloc_failed) { - mlx5_core_info(dev, - "Flow counters bulk query buffer size increased, bulk_size(%d)\n", - max_bulk_len); - fc_stats->bulk_query_alloc_failed = false; - } + fc_stats->bulk_query_len = bulk_query_len; + mlx5_core_info(dev, + "Flow counters bulk query buffer size increased, bulk_query_len(%d)\n", + bulk_query_len); } -static void mlx5_fc_stats_work(struct work_struct *work) +static int mlx5_fc_num_counters(struct mlx5_fc_stats *fc_stats) { - struct mlx5_core_dev *dev = container_of(work, struct mlx5_core_dev, - priv.fc_stats.work.work); - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - /* Take dellist first to ensure that counters cannot be deleted before - * they are inserted. - */ - struct llist_node *dellist = llist_del_all(&fc_stats->dellist); - struct llist_node *addlist = llist_del_all(&fc_stats->addlist); - struct mlx5_fc *counter = NULL, *last = NULL, *tmp; - unsigned long now = jiffies; - - if (addlist || !list_empty(&fc_stats->counters)) - queue_delayed_work(fc_stats->wq, &fc_stats->work, - fc_stats->sampling_interval); - - llist_for_each_entry(counter, addlist, addlist) { - mlx5_fc_stats_insert(dev, counter); - fc_stats->num_counters++; - } - - llist_for_each_entry_safe(counter, tmp, dellist, dellist) { - mlx5_fc_stats_remove(dev, counter); + struct mlx5_fc *counter; + int num_counters = 0; + unsigned long id; - mlx5_fc_release(dev, counter); - fc_stats->num_counters--; - } + xa_for_each(&fc_stats->counters, id, counter) + num_counters++; + return num_counters; +} - if (fc_stats->bulk_query_len < get_max_bulk_query_len(dev) && - fc_stats->num_counters > get_init_bulk_query_len(dev)) - mlx5_fc_stats_bulk_query_size_increase(dev); +static void mlx5_fc_stats_work(struct work_struct *work) +{ + struct mlx5_fc_stats *fc_stats = container_of(work, struct mlx5_fc_stats, + work.work); + struct mlx5_core_dev *dev = fc_stats->fc_pool.dev; - if (time_before(now, fc_stats->next_query) || - list_empty(&fc_stats->counters)) - return; - last = list_last_entry(&fc_stats->counters, struct mlx5_fc, list); + queue_delayed_work(fc_stats->wq, &fc_stats->work, fc_stats->sampling_interval); - counter = list_first_entry(&fc_stats->counters, struct mlx5_fc, - list); - if (counter) - mlx5_fc_stats_query_counter_range(dev, counter, last->id); + /* Grow the bulk query buffer to max if not maxed and enough counters are present. */ + if (unlikely(fc_stats->bulk_query_len < get_max_bulk_query_len(dev) && + mlx5_fc_num_counters(fc_stats) > get_init_bulk_query_len(dev))) + mlx5_fc_stats_bulk_query_buf_realloc(dev, get_max_bulk_query_len(dev)); - fc_stats->next_query = now + fc_stats->sampling_interval; + mlx5_fc_stats_query_all_counters(dev); } static struct mlx5_fc *mlx5_fc_single_alloc(struct mlx5_core_dev *dev) @@ -334,7 +263,7 @@ static struct mlx5_fc *mlx5_fc_single_alloc(struct mlx5_core_dev *dev) static struct mlx5_fc *mlx5_fc_acquire(struct mlx5_core_dev *dev, bool aging) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; struct mlx5_fc *counter; if (aging && MLX5_CAP_GEN(dev, flow_counter_bulk_alloc) != 0) { @@ -346,16 +275,15 @@ static struct mlx5_fc *mlx5_fc_acquire(struct mlx5_core_dev *dev, bool aging) return mlx5_fc_single_alloc(dev); } -struct mlx5_fc *mlx5_fc_create_ex(struct mlx5_core_dev *dev, bool aging) +struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging) { struct mlx5_fc *counter = mlx5_fc_acquire(dev, aging); - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; int err; if (IS_ERR(counter)) return counter; - INIT_LIST_HEAD(&counter->list); counter->aging = aging; if (aging) { @@ -365,18 +293,9 @@ struct mlx5_fc *mlx5_fc_create_ex(struct mlx5_core_dev *dev, bool aging) counter->lastbytes = counter->cache.bytes; counter->lastpackets = counter->cache.packets; - idr_preload(GFP_KERNEL); - spin_lock(&fc_stats->counters_idr_lock); - - err = idr_alloc_u32(&fc_stats->counters_idr, counter, &id, id, - GFP_NOWAIT); - - spin_unlock(&fc_stats->counters_idr_lock); - idr_preload_end(); - if (err) + err = xa_err(xa_store(&fc_stats->counters, id, counter, GFP_KERNEL)); + if (err != 0) goto err_out_alloc; - - llist_add(&counter->addlist, &fc_stats->addlist); } return counter; @@ -385,16 +304,6 @@ struct mlx5_fc *mlx5_fc_create_ex(struct mlx5_core_dev *dev, bool aging) mlx5_fc_release(dev, counter); return ERR_PTR(err); } - -struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging) -{ - struct mlx5_fc *counter = mlx5_fc_create_ex(dev, aging); - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - - if (aging) - mod_delayed_work(fc_stats->wq, &fc_stats->work, 0); - return counter; -} EXPORT_SYMBOL(mlx5_fc_create); u32 mlx5_fc_id(struct mlx5_fc *counter) @@ -405,39 +314,32 @@ EXPORT_SYMBOL(mlx5_fc_id); void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; if (!counter) return; - if (counter->aging) { - llist_add(&counter->dellist, &fc_stats->dellist); - mod_delayed_work(fc_stats->wq, &fc_stats->work, 0); - return; - } - + if (counter->aging) + xa_erase(&fc_stats->counters, counter->id); mlx5_fc_release(dev, counter); } EXPORT_SYMBOL(mlx5_fc_destroy); int mlx5_init_fc_stats(struct mlx5_core_dev *dev) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - int init_bulk_len; - int init_out_len; + struct mlx5_fc_stats *fc_stats; + + fc_stats = kzalloc(sizeof(*fc_stats), GFP_KERNEL); + if (!fc_stats) + return -ENOMEM; + dev->priv.fc_stats = fc_stats; - spin_lock_init(&fc_stats->counters_idr_lock); - idr_init(&fc_stats->counters_idr); - INIT_LIST_HEAD(&fc_stats->counters); - init_llist_head(&fc_stats->addlist); - init_llist_head(&fc_stats->dellist); + xa_init(&fc_stats->counters); - init_bulk_len = get_init_bulk_query_len(dev); - init_out_len = mlx5_cmd_fc_get_bulk_query_out_len(init_bulk_len); - fc_stats->bulk_query_out = kzalloc(init_out_len, GFP_KERNEL); + /* Allocate initial (small) bulk query buffer. */ + mlx5_fc_stats_bulk_query_buf_realloc(dev, get_init_bulk_query_len(dev)); if (!fc_stats->bulk_query_out) - return -ENOMEM; - fc_stats->bulk_query_len = init_bulk_len; + goto err_bulk; fc_stats->wq = create_singlethread_workqueue("mlx5_fc"); if (!fc_stats->wq) @@ -447,34 +349,35 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev) INIT_DELAYED_WORK(&fc_stats->work, mlx5_fc_stats_work); mlx5_fc_pool_init(&fc_stats->fc_pool, dev); + queue_delayed_work(fc_stats->wq, &fc_stats->work, MLX5_FC_STATS_PERIOD); return 0; err_wq_create: - kfree(fc_stats->bulk_query_out); + kvfree(fc_stats->bulk_query_out); +err_bulk: + kfree(fc_stats); return -ENOMEM; } void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; - struct llist_node *tmplist; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; struct mlx5_fc *counter; - struct mlx5_fc *tmp; - - cancel_delayed_work_sync(&dev->priv.fc_stats.work); - destroy_workqueue(dev->priv.fc_stats.wq); - dev->priv.fc_stats.wq = NULL; + unsigned long id; - tmplist = llist_del_all(&fc_stats->addlist); - llist_for_each_entry_safe(counter, tmp, tmplist, addlist) - mlx5_fc_release(dev, counter); + cancel_delayed_work_sync(&fc_stats->work); + destroy_workqueue(fc_stats->wq); + fc_stats->wq = NULL; - list_for_each_entry_safe(counter, tmp, &fc_stats->counters, list) + xa_for_each(&fc_stats->counters, id, counter) { + xa_erase(&fc_stats->counters, id); mlx5_fc_release(dev, counter); + } + xa_destroy(&fc_stats->counters); mlx5_fc_pool_cleanup(&fc_stats->fc_pool); - idr_destroy(&fc_stats->counters_idr); - kfree(fc_stats->bulk_query_out); + kvfree(fc_stats->bulk_query_out); + kfree(fc_stats); } int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter, @@ -518,7 +421,7 @@ void mlx5_fc_queue_stats_work(struct mlx5_core_dev *dev, struct delayed_work *dwork, unsigned long delay) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; queue_delayed_work(fc_stats->wq, dwork, delay); } @@ -526,7 +429,7 @@ void mlx5_fc_queue_stats_work(struct mlx5_core_dev *dev, void mlx5_fc_update_sampling_interval(struct mlx5_core_dev *dev, unsigned long interval) { - struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats; + struct mlx5_fc_stats *fc_stats = dev->priv.fc_stats; fc_stats->sampling_interval = min_t(unsigned long, interval, fc_stats->sampling_interval); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 4f55e55ecb5513..566710d34a7b2e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -35,6 +35,7 @@ struct mlx5_fw_reset { enum { MLX5_FW_RST_STATE_IDLE = 0, MLX5_FW_RST_STATE_TOGGLE_REQ = 4, + MLX5_FW_RST_STATE_DROP_MODE = 5, }; enum { @@ -616,6 +617,7 @@ static void mlx5_sync_reset_unload_event(struct work_struct *work) struct mlx5_fw_reset *fw_reset; struct mlx5_core_dev *dev; unsigned long timeout; + int poll_freq = 20; bool reset_action; u8 rst_state; int err; @@ -651,7 +653,12 @@ static void mlx5_sync_reset_unload_event(struct work_struct *work) reset_action = true; break; } - msleep(20); + if (rst_state == MLX5_FW_RST_STATE_DROP_MODE) { + mlx5_core_info(dev, "Sync Reset Drop mode ack\n"); + mlx5_set_fw_rst_ack(dev); + poll_freq = 1000; + } + msleep(poll_freq); } while (!time_after(jiffies, timeout)); if (!reset_action) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index 8577db3308cc56..7f68468c2e7598 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -516,6 +516,7 @@ void mlx5_modify_lag(struct mlx5_lag *ldev, blocking_notifier_call_chain(&dev0->priv.lag_nh, MLX5_DRIVER_EVENT_ACTIVE_BACKUP_LAG_CHANGE_LOWERSTATE, ndev); + dev_put(ndev); } } @@ -918,6 +919,7 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) { struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; struct lag_tracker tracker = { }; + struct net_device *ndev; bool do_bond, roce_lag; int err; int i; @@ -981,6 +983,16 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) return; } } + if (tracker.tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) { + ndev = mlx5_lag_active_backup_get_netdev(dev0); + /** Only sriov and roce lag should have tracker->TX_type + * set so no need to check the mode + */ + blocking_notifier_call_chain(&dev0->priv.lag_nh, + MLX5_DRIVER_EVENT_ACTIVE_BACKUP_LAG_CHANGE_LOWERSTATE, + ndev); + dev_put(ndev); + } } else if (mlx5_lag_should_modify_lag(ldev, do_bond)) { mlx5_modify_lag(ldev, &tracker); } else if (mlx5_lag_should_disable_lag(ldev, do_bond)) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index b306ae79bf97a6..4822d01123b45d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -402,9 +402,7 @@ static int mlx5_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *sts) { struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info); - struct mlx5_timer *timer = &clock->timer; struct mlx5_core_dev *mdev; - unsigned long flags; u64 cycles, ns; mdev = container_of(clock, struct mlx5_core_dev, clock); @@ -413,10 +411,8 @@ static int mlx5_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, goto out; } - write_seqlock_irqsave(&clock->lock, flags); cycles = mlx5_read_time(mdev, sts, false); - ns = timecounter_cyc2time(&timer->tc, cycles); - write_sequnlock_irqrestore(&clock->lock, flags); + ns = mlx5_timecounter_cyc2time(clock, cycles); *ts = ns_to_timespec64(ns); out: return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h index 4b7f7131c56084..b1edc71ffc6ddc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/eq.h @@ -72,7 +72,7 @@ static inline void eq_update_ci(struct mlx5_eq *eq, int arm) __raw_writel((__force u32)cpu_to_be32(val), addr); /* We still want ordering, just not swabbing, so add a barrier */ - mb(); + wmb(); } int mlx5_eq_table_init(struct mlx5_core_dev *dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h index 452d0df339acd4..404f3d4b6380ca 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/smfs.h @@ -4,8 +4,8 @@ #ifndef __MLX5_LIB_SMFS_H__ #define __MLX5_LIB_SMFS_H__ -#include "steering/mlx5dr.h" -#include "steering/dr_types.h" +#include "steering/sws/mlx5dr.h" +#include "steering/sws/dr_types.h" struct mlx5dr_matcher * mlx5_smfs_matcher_create(struct mlx5dr_table *table, u32 priority, struct mlx5_flow_spec *spec); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 62c770b0eaa83a..99de67c3aa7435 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -224,6 +224,8 @@ void mlx5_sriov_disable(struct pci_dev *pdev, bool num_vf_change); int mlx5_core_sriov_set_msix_vec_count(struct pci_dev *vf, int msix_vec_count); int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id); int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id); +bool mlx5_qos_element_type_supported(struct mlx5_core_dev *dev, int type, u8 hierarchy); +bool mlx5_qos_tsar_type_supported(struct mlx5_core_dev *dev, int type, u8 hierarchy); int mlx5_create_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy, void *context, u32 *element_id); int mlx5_modify_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/qos.c index db2bd3ad63ba36..6be9981bb6b1cd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qos.c @@ -28,7 +28,9 @@ int mlx5_qos_create_leaf_node(struct mlx5_core_dev *mdev, u32 parent_id, { u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0}; - if (!(MLX5_CAP_QOS(mdev, nic_element_type) & ELEMENT_TYPE_CAP_MASK_QUEUE_GROUP)) + if (!mlx5_qos_element_type_supported(mdev, + SCHEDULING_CONTEXT_ELEMENT_TYPE_QUEUE_GROUP, + SCHEDULING_HIERARCHY_NIC)) return -EOPNOTSUPP; MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_id); @@ -47,8 +49,12 @@ int mlx5_qos_create_inner_node(struct mlx5_core_dev *mdev, u32 parent_id, u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0}; void *attr; - if (!(MLX5_CAP_QOS(mdev, nic_element_type) & ELEMENT_TYPE_CAP_MASK_TSAR) || - !(MLX5_CAP_QOS(mdev, nic_tsar_type) & TSAR_TYPE_CAP_MASK_DWRR)) + if (!mlx5_qos_element_type_supported(mdev, + SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR, + SCHEDULING_HIERARCHY_NIC) || + !mlx5_qos_tsar_type_supported(mdev, + TSAR_ELEMENT_TSAR_TYPE_DWRR, + SCHEDULING_HIERARCHY_NIC)) return -EOPNOTSUPP; MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_id); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rl.c b/drivers/net/ethernet/mellanox/mlx5/core/rl.c index 9f8b4005f4bd05..e393391966e0f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/rl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/rl.c @@ -34,6 +34,64 @@ #include #include "mlx5_core.h" +bool mlx5_qos_tsar_type_supported(struct mlx5_core_dev *dev, int type, u8 hierarchy) +{ + int cap; + + switch (hierarchy) { + case SCHEDULING_HIERARCHY_E_SWITCH: + cap = MLX5_CAP_QOS(dev, esw_tsar_type); + break; + case SCHEDULING_HIERARCHY_NIC: + cap = MLX5_CAP_QOS(dev, nic_tsar_type); + break; + default: + return false; + } + + switch (type) { + case TSAR_ELEMENT_TSAR_TYPE_DWRR: + return cap & TSAR_TYPE_CAP_MASK_DWRR; + case TSAR_ELEMENT_TSAR_TYPE_ROUND_ROBIN: + return cap & TSAR_TYPE_CAP_MASK_ROUND_ROBIN; + case TSAR_ELEMENT_TSAR_TYPE_ETS: + return cap & TSAR_TYPE_CAP_MASK_ETS; + } + + return false; +} + +bool mlx5_qos_element_type_supported(struct mlx5_core_dev *dev, int type, u8 hierarchy) +{ + int cap; + + switch (hierarchy) { + case SCHEDULING_HIERARCHY_E_SWITCH: + cap = MLX5_CAP_QOS(dev, esw_element_type); + break; + case SCHEDULING_HIERARCHY_NIC: + cap = MLX5_CAP_QOS(dev, nic_element_type); + break; + default: + return false; + } + + switch (type) { + case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR: + return cap & ELEMENT_TYPE_CAP_MASK_TSAR; + case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT: + return cap & ELEMENT_TYPE_CAP_MASK_VPORT; + case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC: + return cap & ELEMENT_TYPE_CAP_MASK_VPORT_TC; + case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC: + return cap & ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC; + case SCHEDULING_CONTEXT_ELEMENT_TYPE_QUEUE_GROUP: + return cap & ELEMENT_TYPE_CAP_MASK_QUEUE_GROUP; + } + + return false; +} + /* Scheduling element fw management */ int mlx5_create_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy, void *ctx, u32 *element_id) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c deleted file mode 100644 index 2ebb61ef3ea9f6..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c +++ /dev/null @@ -1,2245 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include "dr_types.h" -#include "dr_ste.h" - -enum dr_action_domain { - DR_ACTION_DOMAIN_NIC_INGRESS, - DR_ACTION_DOMAIN_NIC_EGRESS, - DR_ACTION_DOMAIN_FDB_INGRESS, - DR_ACTION_DOMAIN_FDB_EGRESS, - DR_ACTION_DOMAIN_MAX, -}; - -enum dr_action_valid_state { - DR_ACTION_STATE_ERR, - DR_ACTION_STATE_NO_ACTION, - DR_ACTION_STATE_ENCAP, - DR_ACTION_STATE_DECAP, - DR_ACTION_STATE_MODIFY_HDR, - DR_ACTION_STATE_POP_VLAN, - DR_ACTION_STATE_PUSH_VLAN, - DR_ACTION_STATE_NON_TERM, - DR_ACTION_STATE_TERM, - DR_ACTION_STATE_ASO, - DR_ACTION_STATE_MAX, -}; - -static const char * const action_type_to_str[] = { - [DR_ACTION_TYP_TNL_L2_TO_L2] = "DR_ACTION_TYP_TNL_L2_TO_L2", - [DR_ACTION_TYP_L2_TO_TNL_L2] = "DR_ACTION_TYP_L2_TO_TNL_L2", - [DR_ACTION_TYP_TNL_L3_TO_L2] = "DR_ACTION_TYP_TNL_L3_TO_L2", - [DR_ACTION_TYP_L2_TO_TNL_L3] = "DR_ACTION_TYP_L2_TO_TNL_L3", - [DR_ACTION_TYP_DROP] = "DR_ACTION_TYP_DROP", - [DR_ACTION_TYP_QP] = "DR_ACTION_TYP_QP", - [DR_ACTION_TYP_FT] = "DR_ACTION_TYP_FT", - [DR_ACTION_TYP_CTR] = "DR_ACTION_TYP_CTR", - [DR_ACTION_TYP_TAG] = "DR_ACTION_TYP_TAG", - [DR_ACTION_TYP_MODIFY_HDR] = "DR_ACTION_TYP_MODIFY_HDR", - [DR_ACTION_TYP_VPORT] = "DR_ACTION_TYP_VPORT", - [DR_ACTION_TYP_POP_VLAN] = "DR_ACTION_TYP_POP_VLAN", - [DR_ACTION_TYP_PUSH_VLAN] = "DR_ACTION_TYP_PUSH_VLAN", - [DR_ACTION_TYP_SAMPLER] = "DR_ACTION_TYP_SAMPLER", - [DR_ACTION_TYP_INSERT_HDR] = "DR_ACTION_TYP_INSERT_HDR", - [DR_ACTION_TYP_REMOVE_HDR] = "DR_ACTION_TYP_REMOVE_HDR", - [DR_ACTION_TYP_ASO_FLOW_METER] = "DR_ACTION_TYP_ASO_FLOW_METER", - [DR_ACTION_TYP_RANGE] = "DR_ACTION_TYP_RANGE", - [DR_ACTION_TYP_MAX] = "DR_ACTION_UNKNOWN", -}; - -static const char *dr_action_id_to_str(enum mlx5dr_action_type action_id) -{ - if (action_id > DR_ACTION_TYP_MAX) - action_id = DR_ACTION_TYP_MAX; - return action_type_to_str[action_id]; -} - -static bool mlx5dr_action_supp_fwd_fdb_multi_ft(struct mlx5_core_dev *dev) -{ - return (MLX5_CAP_GEN(dev, steering_format_version) < MLX5_STEERING_FORMAT_CONNECTX_6DX || - MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_any_table_limit_regc) || - MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_any_table)); -} - -static const enum dr_action_valid_state -next_action_state[DR_ACTION_DOMAIN_MAX][DR_ACTION_STATE_MAX][DR_ACTION_TYP_MAX] = { - [DR_ACTION_DOMAIN_NIC_INGRESS] = { - [DR_ACTION_STATE_NO_ACTION] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_DECAP] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_ENCAP] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_MODIFY_HDR] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_POP_VLAN] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_PUSH_VLAN] = { - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_NON_TERM] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_ASO] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_TERM] = { - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, - }, - }, - [DR_ACTION_DOMAIN_NIC_EGRESS] = { - [DR_ACTION_STATE_NO_ACTION] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_DECAP] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_ENCAP] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_MODIFY_HDR] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_POP_VLAN] = { - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_PUSH_VLAN] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_NON_TERM] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_ASO] = { - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ASO, - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - }, - [DR_ACTION_STATE_TERM] = { - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, - }, - }, - [DR_ACTION_DOMAIN_FDB_INGRESS] = { - [DR_ACTION_STATE_NO_ACTION] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_DECAP] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_ENCAP] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_MODIFY_HDR] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_POP_VLAN] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_PUSH_VLAN] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_NON_TERM] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_ASO] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_TERM] = { - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, - }, - }, - [DR_ACTION_DOMAIN_FDB_EGRESS] = { - [DR_ACTION_STATE_NO_ACTION] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_DECAP] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_ENCAP] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_MODIFY_HDR] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_POP_VLAN] = { - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_PUSH_VLAN] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_NON_TERM] = { - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_ASO] = { - [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, - [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, - [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, - [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ASO, - }, - [DR_ACTION_STATE_TERM] = { - [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, - }, - }, -}; - -static int -dr_action_reformat_to_action_type(enum mlx5dr_action_reformat_type reformat_type, - enum mlx5dr_action_type *action_type) -{ - switch (reformat_type) { - case DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2: - *action_type = DR_ACTION_TYP_TNL_L2_TO_L2; - break; - case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2: - *action_type = DR_ACTION_TYP_L2_TO_TNL_L2; - break; - case DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2: - *action_type = DR_ACTION_TYP_TNL_L3_TO_L2; - break; - case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3: - *action_type = DR_ACTION_TYP_L2_TO_TNL_L3; - break; - case DR_ACTION_REFORMAT_TYP_INSERT_HDR: - *action_type = DR_ACTION_TYP_INSERT_HDR; - break; - case DR_ACTION_REFORMAT_TYP_REMOVE_HDR: - *action_type = DR_ACTION_TYP_REMOVE_HDR; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* Apply the actions on the rule STE array starting from the last_ste. - * Actions might require more than one STE, new_num_stes will return - * the new size of the STEs array, rule with actions. - */ -static void dr_actions_apply(struct mlx5dr_domain *dmn, - enum mlx5dr_domain_nic_type nic_type, - u8 *action_type_set, - u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, - u32 *new_num_stes) -{ - struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; - u32 added_stes = 0; - - if (nic_type == DR_DOMAIN_NIC_TYPE_RX) - mlx5dr_ste_set_actions_rx(ste_ctx, dmn, action_type_set, - last_ste, attr, &added_stes); - else - mlx5dr_ste_set_actions_tx(ste_ctx, dmn, action_type_set, - last_ste, attr, &added_stes); - - *new_num_stes += added_stes; -} - -static enum dr_action_domain -dr_action_get_action_domain(enum mlx5dr_domain_type domain, - enum mlx5dr_domain_nic_type nic_type) -{ - switch (domain) { - case MLX5DR_DOMAIN_TYPE_NIC_RX: - return DR_ACTION_DOMAIN_NIC_INGRESS; - case MLX5DR_DOMAIN_TYPE_NIC_TX: - return DR_ACTION_DOMAIN_NIC_EGRESS; - case MLX5DR_DOMAIN_TYPE_FDB: - if (nic_type == DR_DOMAIN_NIC_TYPE_RX) - return DR_ACTION_DOMAIN_FDB_INGRESS; - return DR_ACTION_DOMAIN_FDB_EGRESS; - default: - WARN_ON(true); - return DR_ACTION_DOMAIN_MAX; - } -} - -static -int dr_action_validate_and_get_next_state(enum dr_action_domain action_domain, - u32 action_type, - u32 *state) -{ - u32 cur_state = *state; - - /* Check action state machine is valid */ - *state = next_action_state[action_domain][cur_state][action_type]; - - if (*state == DR_ACTION_STATE_ERR) - return -EOPNOTSUPP; - - return 0; -} - -static int dr_action_handle_cs_recalc(struct mlx5dr_domain *dmn, - struct mlx5dr_action *dest_action, - u64 *final_icm_addr) -{ - int ret; - - switch (dest_action->action_type) { - case DR_ACTION_TYP_FT: - /* Allow destination flow table only if table is a terminating - * table, since there is an *assumption* that in such case FW - * will recalculate the CS. - */ - if (dest_action->dest_tbl->is_fw_tbl) { - *final_icm_addr = dest_action->dest_tbl->fw_tbl.rx_icm_addr; - } else { - mlx5dr_dbg(dmn, - "Destination FT should be terminating when modify TTL is used\n"); - return -EINVAL; - } - break; - - case DR_ACTION_TYP_VPORT: - /* If destination is vport we will get the FW flow table - * that recalculates the CS and forwards to the vport. - */ - ret = mlx5dr_domain_get_recalc_cs_ft_addr(dest_action->vport->dmn, - dest_action->vport->caps->num, - final_icm_addr); - if (ret) { - mlx5dr_err(dmn, "Failed to get FW cs recalc flow table\n"); - return ret; - } - break; - - default: - break; - } - - return 0; -} - -static void dr_action_modify_ttl_adjust(struct mlx5dr_domain *dmn, - struct mlx5dr_ste_actions_attr *attr, - bool rx_rule, - bool *recalc_cs_required) -{ - *recalc_cs_required = false; - - /* if device supports csum recalculation - no adjustment needed */ - if (mlx5dr_ste_supp_ttl_cs_recalc(&dmn->info.caps)) - return; - - /* no adjustment needed on TX rules */ - if (!rx_rule) - return; - - if (!MLX5_CAP_ESW_FLOWTABLE(dmn->mdev, fdb_ipv4_ttl_modify)) { - /* Ignore the modify TTL action. - * It is always kept as last HW action. - */ - attr->modify_actions--; - return; - } - - if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB) - /* Due to a HW bug on some devices, modifying TTL on RX flows - * will cause an incorrect checksum calculation. In such cases - * we will use a FW table to recalculate the checksum. - */ - *recalc_cs_required = true; -} - -static void dr_action_print_sequence(struct mlx5dr_domain *dmn, - struct mlx5dr_action *actions[], - int last_idx) -{ - int i; - - for (i = 0; i <= last_idx; i++) - mlx5dr_err(dmn, "< %s (%d) > ", - dr_action_id_to_str(actions[i]->action_type), - actions[i]->action_type); -} - -static int dr_action_get_dest_fw_tbl_addr(struct mlx5dr_matcher *matcher, - struct mlx5dr_action_dest_tbl *dest_tbl, - bool is_rx_rule, - u64 *final_icm_addr) -{ - struct mlx5dr_cmd_query_flow_table_details output; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - int ret; - - if (!dest_tbl->fw_tbl.rx_icm_addr) { - ret = mlx5dr_cmd_query_flow_table(dmn->mdev, - dest_tbl->fw_tbl.type, - dest_tbl->fw_tbl.id, - &output); - if (ret) { - mlx5dr_err(dmn, - "Failed mlx5_cmd_query_flow_table ret: %d\n", - ret); - return ret; - } - - dest_tbl->fw_tbl.tx_icm_addr = output.sw_owner_icm_root_1; - dest_tbl->fw_tbl.rx_icm_addr = output.sw_owner_icm_root_0; - } - - *final_icm_addr = is_rx_rule ? dest_tbl->fw_tbl.rx_icm_addr : - dest_tbl->fw_tbl.tx_icm_addr; - return 0; -} - -static int dr_action_get_dest_sw_tbl_addr(struct mlx5dr_matcher *matcher, - struct mlx5dr_action_dest_tbl *dest_tbl, - bool is_rx_rule, - u64 *final_icm_addr) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_icm_chunk *chunk; - - if (dest_tbl->tbl->dmn != dmn) { - mlx5dr_err(dmn, - "Destination table belongs to a different domain\n"); - return -EINVAL; - } - - if (dest_tbl->tbl->level <= matcher->tbl->level) { - mlx5_core_dbg_once(dmn->mdev, - "Connecting table to a lower/same level destination table\n"); - mlx5dr_dbg(dmn, - "Connecting table at level %d to a destination table at level %d\n", - matcher->tbl->level, - dest_tbl->tbl->level); - } - - chunk = is_rx_rule ? dest_tbl->tbl->rx.s_anchor->chunk : - dest_tbl->tbl->tx.s_anchor->chunk; - - *final_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(chunk); - return 0; -} - -static int dr_action_get_dest_tbl_addr(struct mlx5dr_matcher *matcher, - struct mlx5dr_action_dest_tbl *dest_tbl, - bool is_rx_rule, - u64 *final_icm_addr) -{ - if (dest_tbl->is_fw_tbl) - return dr_action_get_dest_fw_tbl_addr(matcher, - dest_tbl, - is_rx_rule, - final_icm_addr); - - return dr_action_get_dest_sw_tbl_addr(matcher, - dest_tbl, - is_rx_rule, - final_icm_addr); -} - -#define WITH_VLAN_NUM_HW_ACTIONS 6 - -int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_action *actions[], - u32 num_actions, - u8 *ste_arr, - u32 *new_hw_ste_arr_sz) -{ - struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; - bool rx_rule = nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - u8 action_type_set[DR_ACTION_TYP_MAX] = {}; - struct mlx5dr_ste_actions_attr attr = {}; - struct mlx5dr_action *dest_action = NULL; - u32 state = DR_ACTION_STATE_NO_ACTION; - enum dr_action_domain action_domain; - bool recalc_cs_required = false; - u8 *last_ste; - int i, ret; - - attr.gvmi = dmn->info.caps.gvmi; - attr.hit_gvmi = dmn->info.caps.gvmi; - attr.final_icm_addr = nic_dmn->default_icm_addr; - action_domain = dr_action_get_action_domain(dmn->type, nic_dmn->type); - - for (i = 0; i < num_actions; i++) { - struct mlx5dr_action *action; - int max_actions_type = 1; - u32 action_type; - - action = actions[i]; - action_type = action->action_type; - - switch (action_type) { - case DR_ACTION_TYP_DROP: - attr.final_icm_addr = nic_dmn->drop_icm_addr; - attr.hit_gvmi = nic_dmn->drop_icm_addr >> 48; - break; - case DR_ACTION_TYP_FT: - dest_action = action; - ret = dr_action_get_dest_tbl_addr(matcher, action->dest_tbl, - rx_rule, &attr.final_icm_addr); - if (ret) - return ret; - break; - case DR_ACTION_TYP_RANGE: - ret = dr_action_get_dest_tbl_addr(matcher, - action->range->hit_tbl_action->dest_tbl, - rx_rule, &attr.final_icm_addr); - if (ret) - return ret; - - ret = dr_action_get_dest_tbl_addr(matcher, - action->range->miss_tbl_action->dest_tbl, - rx_rule, &attr.range.miss_icm_addr); - if (ret) - return ret; - - attr.range.definer_id = action->range->definer_id; - attr.range.min = action->range->min; - attr.range.max = action->range->max; - break; - case DR_ACTION_TYP_QP: - mlx5dr_info(dmn, "Domain doesn't support QP\n"); - return -EOPNOTSUPP; - case DR_ACTION_TYP_CTR: - attr.ctr_id = action->ctr->ctr_id + - action->ctr->offset; - break; - case DR_ACTION_TYP_TAG: - attr.flow_tag = action->flow_tag->flow_tag; - break; - case DR_ACTION_TYP_TNL_L2_TO_L2: - break; - case DR_ACTION_TYP_TNL_L3_TO_L2: - if (action->rewrite->ptrn && action->rewrite->arg) { - attr.decap_index = mlx5dr_arg_get_obj_id(action->rewrite->arg); - attr.decap_actions = action->rewrite->ptrn->num_of_actions; - attr.decap_pat_idx = action->rewrite->ptrn->index; - } else { - attr.decap_index = action->rewrite->index; - attr.decap_actions = action->rewrite->num_of_actions; - attr.decap_with_vlan = - attr.decap_actions == WITH_VLAN_NUM_HW_ACTIONS; - attr.decap_pat_idx = MLX5DR_INVALID_PATTERN_INDEX; - } - break; - case DR_ACTION_TYP_MODIFY_HDR: - if (action->rewrite->single_action_opt) { - attr.modify_actions = action->rewrite->num_of_actions; - attr.single_modify_action = action->rewrite->data; - } else { - if (action->rewrite->ptrn && action->rewrite->arg) { - attr.modify_index = - mlx5dr_arg_get_obj_id(action->rewrite->arg); - attr.modify_actions = action->rewrite->ptrn->num_of_actions; - attr.modify_pat_idx = action->rewrite->ptrn->index; - } else { - attr.modify_index = action->rewrite->index; - attr.modify_actions = action->rewrite->num_of_actions; - attr.modify_pat_idx = MLX5DR_INVALID_PATTERN_INDEX; - } - } - if (action->rewrite->modify_ttl) - dr_action_modify_ttl_adjust(dmn, &attr, rx_rule, - &recalc_cs_required); - break; - case DR_ACTION_TYP_L2_TO_TNL_L2: - case DR_ACTION_TYP_L2_TO_TNL_L3: - if (rx_rule && - !(dmn->ste_ctx->actions_caps & DR_STE_CTX_ACTION_CAP_RX_ENCAP)) { - mlx5dr_info(dmn, "Device doesn't support Encap on RX\n"); - return -EOPNOTSUPP; - } - attr.reformat.size = action->reformat->size; - attr.reformat.id = action->reformat->id; - break; - case DR_ACTION_TYP_SAMPLER: - attr.final_icm_addr = rx_rule ? action->sampler->rx_icm_addr : - action->sampler->tx_icm_addr; - break; - case DR_ACTION_TYP_VPORT: - if (unlikely(rx_rule && action->vport->caps->num == MLX5_VPORT_UPLINK)) { - /* can't go to uplink on RX rule - dropping instead */ - attr.final_icm_addr = nic_dmn->drop_icm_addr; - attr.hit_gvmi = nic_dmn->drop_icm_addr >> 48; - } else { - attr.hit_gvmi = action->vport->caps->vhca_gvmi; - dest_action = action; - attr.final_icm_addr = rx_rule ? - action->vport->caps->icm_address_rx : - action->vport->caps->icm_address_tx; - } - break; - case DR_ACTION_TYP_POP_VLAN: - if (!rx_rule && !(dmn->ste_ctx->actions_caps & - DR_STE_CTX_ACTION_CAP_TX_POP)) { - mlx5dr_dbg(dmn, "Device doesn't support POP VLAN action on TX\n"); - return -EOPNOTSUPP; - } - - max_actions_type = MLX5DR_MAX_VLANS; - attr.vlans.count++; - break; - case DR_ACTION_TYP_PUSH_VLAN: - if (rx_rule && !(dmn->ste_ctx->actions_caps & - DR_STE_CTX_ACTION_CAP_RX_PUSH)) { - mlx5dr_dbg(dmn, "Device doesn't support PUSH VLAN action on RX\n"); - return -EOPNOTSUPP; - } - - max_actions_type = MLX5DR_MAX_VLANS; - if (attr.vlans.count == MLX5DR_MAX_VLANS) { - mlx5dr_dbg(dmn, "Max VLAN push/pop count exceeded\n"); - return -EINVAL; - } - - attr.vlans.headers[attr.vlans.count++] = action->push_vlan->vlan_hdr; - break; - case DR_ACTION_TYP_INSERT_HDR: - case DR_ACTION_TYP_REMOVE_HDR: - attr.reformat.size = action->reformat->size; - attr.reformat.id = action->reformat->id; - attr.reformat.param_0 = action->reformat->param_0; - attr.reformat.param_1 = action->reformat->param_1; - break; - case DR_ACTION_TYP_ASO_FLOW_METER: - attr.aso_flow_meter.obj_id = action->aso->obj_id; - attr.aso_flow_meter.offset = action->aso->offset; - attr.aso_flow_meter.dest_reg_id = action->aso->dest_reg_id; - attr.aso_flow_meter.init_color = action->aso->init_color; - break; - default: - mlx5dr_err(dmn, "Unsupported action type %d\n", action_type); - return -EINVAL; - } - - /* Check action duplication */ - if (++action_type_set[action_type] > max_actions_type) { - mlx5dr_err(dmn, "Action type %d supports only max %d time(s)\n", - action_type, max_actions_type); - return -EINVAL; - } - - /* Check action state machine is valid */ - if (dr_action_validate_and_get_next_state(action_domain, - action_type, - &state)) { - mlx5dr_err(dmn, "Invalid action (gvmi: %d, is_rx: %d) sequence provided:", - attr.gvmi, rx_rule); - dr_action_print_sequence(dmn, actions, i); - return -EOPNOTSUPP; - } - } - - *new_hw_ste_arr_sz = nic_matcher->num_of_builders; - last_ste = ste_arr + DR_STE_SIZE * (nic_matcher->num_of_builders - 1); - - if (recalc_cs_required && dest_action) { - ret = dr_action_handle_cs_recalc(dmn, dest_action, &attr.final_icm_addr); - if (ret) { - mlx5dr_err(dmn, - "Failed to handle checksum recalculation err %d\n", - ret); - return ret; - } - } - - dr_actions_apply(dmn, - nic_dmn->type, - action_type_set, - last_ste, - &attr, - new_hw_ste_arr_sz); - - return 0; -} - -static unsigned int action_size[DR_ACTION_TYP_MAX] = { - [DR_ACTION_TYP_TNL_L2_TO_L2] = sizeof(struct mlx5dr_action_reformat), - [DR_ACTION_TYP_L2_TO_TNL_L2] = sizeof(struct mlx5dr_action_reformat), - [DR_ACTION_TYP_TNL_L3_TO_L2] = sizeof(struct mlx5dr_action_rewrite), - [DR_ACTION_TYP_L2_TO_TNL_L3] = sizeof(struct mlx5dr_action_reformat), - [DR_ACTION_TYP_FT] = sizeof(struct mlx5dr_action_dest_tbl), - [DR_ACTION_TYP_CTR] = sizeof(struct mlx5dr_action_ctr), - [DR_ACTION_TYP_TAG] = sizeof(struct mlx5dr_action_flow_tag), - [DR_ACTION_TYP_MODIFY_HDR] = sizeof(struct mlx5dr_action_rewrite), - [DR_ACTION_TYP_VPORT] = sizeof(struct mlx5dr_action_vport), - [DR_ACTION_TYP_PUSH_VLAN] = sizeof(struct mlx5dr_action_push_vlan), - [DR_ACTION_TYP_INSERT_HDR] = sizeof(struct mlx5dr_action_reformat), - [DR_ACTION_TYP_REMOVE_HDR] = sizeof(struct mlx5dr_action_reformat), - [DR_ACTION_TYP_SAMPLER] = sizeof(struct mlx5dr_action_sampler), - [DR_ACTION_TYP_ASO_FLOW_METER] = sizeof(struct mlx5dr_action_aso_flow_meter), - [DR_ACTION_TYP_RANGE] = sizeof(struct mlx5dr_action_range), -}; - -static struct mlx5dr_action * -dr_action_create_generic(enum mlx5dr_action_type action_type) -{ - struct mlx5dr_action *action; - int extra_size; - - if (action_type < DR_ACTION_TYP_MAX) - extra_size = action_size[action_type]; - else - return NULL; - - action = kzalloc(sizeof(*action) + extra_size, GFP_KERNEL); - if (!action) - return NULL; - - action->action_type = action_type; - refcount_set(&action->refcount, 1); - action->data = action + 1; - - return action; -} - -struct mlx5dr_action *mlx5dr_action_create_drop(void) -{ - return dr_action_create_generic(DR_ACTION_TYP_DROP); -} - -struct mlx5dr_action * -mlx5dr_action_create_dest_table_num(struct mlx5dr_domain *dmn, u32 table_num) -{ - struct mlx5dr_action *action; - - action = dr_action_create_generic(DR_ACTION_TYP_FT); - if (!action) - return NULL; - - action->dest_tbl->is_fw_tbl = true; - action->dest_tbl->fw_tbl.dmn = dmn; - action->dest_tbl->fw_tbl.id = table_num; - action->dest_tbl->fw_tbl.type = FS_FT_FDB; - refcount_inc(&dmn->refcount); - - return action; -} - -struct mlx5dr_action * -mlx5dr_action_create_dest_table(struct mlx5dr_table *tbl) -{ - struct mlx5dr_action *action; - - refcount_inc(&tbl->refcount); - - action = dr_action_create_generic(DR_ACTION_TYP_FT); - if (!action) - goto dec_ref; - - action->dest_tbl->tbl = tbl; - - return action; - -dec_ref: - refcount_dec(&tbl->refcount); - return NULL; -} - -static void dr_action_range_definer_fill(u16 *format_id, - u8 *dw_selectors, - u8 *byte_selectors, - u8 *match_mask) -{ - int i; - - *format_id = MLX5_IFC_DEFINER_FORMAT_ID_SELECT; - - dw_selectors[0] = MLX5_IFC_DEFINER_FORMAT_OFFSET_OUTER_ETH_PKT_LEN / 4; - - for (i = 1; i < MLX5_IFC_DEFINER_DW_SELECTORS_NUM; i++) - dw_selectors[i] = MLX5_IFC_DEFINER_FORMAT_OFFSET_UNUSED; - - for (i = 0; i < MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM; i++) - byte_selectors[i] = MLX5_IFC_DEFINER_FORMAT_OFFSET_UNUSED; - - MLX5_SET(match_definer_match_mask, match_mask, - match_dw_0, 0xffffUL << 16); -} - -static int dr_action_create_range_definer(struct mlx5dr_action *action) -{ - u8 match_mask[MLX5_FLD_SZ_BYTES(match_definer, match_mask)] = {}; - u8 byte_selectors[MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM] = {}; - u8 dw_selectors[MLX5_IFC_DEFINER_DW_SELECTORS_NUM] = {}; - struct mlx5dr_domain *dmn = action->range->dmn; - u32 definer_id; - u16 format_id; - int ret; - - dr_action_range_definer_fill(&format_id, - dw_selectors, - byte_selectors, - match_mask); - - ret = mlx5dr_definer_get(dmn, format_id, - dw_selectors, byte_selectors, - match_mask, &definer_id); - if (ret) - return ret; - - action->range->definer_id = definer_id; - return 0; -} - -static void dr_action_destroy_range_definer(struct mlx5dr_action *action) -{ - mlx5dr_definer_put(action->range->dmn, action->range->definer_id); -} - -struct mlx5dr_action * -mlx5dr_action_create_dest_match_range(struct mlx5dr_domain *dmn, - u32 field, - struct mlx5_flow_table *hit_ft, - struct mlx5_flow_table *miss_ft, - u32 min, - u32 max) -{ - struct mlx5dr_action *action; - int ret; - - if (!mlx5dr_supp_match_ranges(dmn->mdev)) { - mlx5dr_dbg(dmn, "SELECT definer support is needed for match range\n"); - return NULL; - } - - if (field != MLX5_FLOW_DEST_RANGE_FIELD_PKT_LEN || - min > 0xffff || max > 0xffff) { - mlx5dr_err(dmn, "Invalid match range parameters\n"); - return NULL; - } - - action = dr_action_create_generic(DR_ACTION_TYP_RANGE); - if (!action) - return NULL; - - action->range->hit_tbl_action = - mlx5dr_is_fw_table(hit_ft) ? - mlx5dr_action_create_dest_flow_fw_table(dmn, hit_ft) : - mlx5dr_action_create_dest_table(hit_ft->fs_dr_table.dr_table); - - if (!action->range->hit_tbl_action) - goto free_action; - - action->range->miss_tbl_action = - mlx5dr_is_fw_table(miss_ft) ? - mlx5dr_action_create_dest_flow_fw_table(dmn, miss_ft) : - mlx5dr_action_create_dest_table(miss_ft->fs_dr_table.dr_table); - - if (!action->range->miss_tbl_action) - goto free_hit_tbl_action; - - action->range->min = min; - action->range->max = max; - action->range->dmn = dmn; - - ret = dr_action_create_range_definer(action); - if (ret) - goto free_miss_tbl_action; - - /* No need to increase refcount on domain for this action, - * the hit/miss table actions will do it internally. - */ - - return action; - -free_miss_tbl_action: - mlx5dr_action_destroy(action->range->miss_tbl_action); -free_hit_tbl_action: - mlx5dr_action_destroy(action->range->hit_tbl_action); -free_action: - kfree(action); - - return NULL; -} - -struct mlx5dr_action * -mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn, - struct mlx5dr_action_dest *dests, - u32 num_of_dests, - bool ignore_flow_level, - u32 flow_source) -{ - struct mlx5dr_cmd_flow_destination_hw_info *hw_dests; - struct mlx5dr_action **ref_actions; - struct mlx5dr_action *action; - bool reformat_req = false; - bool is_ft_wire = false; - u16 num_dst_ft = 0; - u32 num_of_ref = 0; - u32 ref_act_cnt; - u16 last_dest; - int ret; - int i; - - if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) { - mlx5dr_err(dmn, "Multiple destination support is for FDB only\n"); - return NULL; - } - - hw_dests = kcalloc(num_of_dests, sizeof(*hw_dests), GFP_KERNEL); - if (!hw_dests) - return NULL; - - if (unlikely(check_mul_overflow(num_of_dests, 2u, &ref_act_cnt))) - goto free_hw_dests; - - ref_actions = kcalloc(ref_act_cnt, sizeof(*ref_actions), GFP_KERNEL); - if (!ref_actions) - goto free_hw_dests; - - for (i = 0; i < num_of_dests; i++) { - struct mlx5dr_action *reformat_action = dests[i].reformat; - struct mlx5dr_action *dest_action = dests[i].dest; - - ref_actions[num_of_ref++] = dest_action; - - switch (dest_action->action_type) { - case DR_ACTION_TYP_VPORT: - hw_dests[i].vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID; - hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT; - hw_dests[i].vport.num = dest_action->vport->caps->num; - hw_dests[i].vport.vhca_id = dest_action->vport->caps->vhca_gvmi; - if (reformat_action) { - reformat_req = true; - hw_dests[i].vport.reformat_id = - reformat_action->reformat->id; - ref_actions[num_of_ref++] = reformat_action; - hw_dests[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID; - } - break; - - case DR_ACTION_TYP_FT: - if (num_dst_ft && - !mlx5dr_action_supp_fwd_fdb_multi_ft(dmn->mdev)) { - mlx5dr_dbg(dmn, "multiple FT destinations not supported\n"); - goto free_ref_actions; - } - num_dst_ft++; - hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; - if (dest_action->dest_tbl->is_fw_tbl) { - hw_dests[i].ft_id = dest_action->dest_tbl->fw_tbl.id; - } else { - hw_dests[i].ft_id = dest_action->dest_tbl->tbl->table_id; - if (dest_action->dest_tbl->is_wire_ft) { - is_ft_wire = true; - last_dest = i; - } - } - break; - - default: - mlx5dr_dbg(dmn, "Invalid multiple destinations action\n"); - goto free_ref_actions; - } - } - - /* In multidest, the FW does the iterator in the RX except of the last - * one that done in the TX. - * So, if one of the ft target is wire, put it at the end of the dest list. - */ - if (is_ft_wire && num_dst_ft > 1) - swap(hw_dests[last_dest], hw_dests[num_of_dests - 1]); - - action = dr_action_create_generic(DR_ACTION_TYP_FT); - if (!action) - goto free_ref_actions; - - ret = mlx5dr_fw_create_md_tbl(dmn, - hw_dests, - num_of_dests, - reformat_req, - &action->dest_tbl->fw_tbl.id, - &action->dest_tbl->fw_tbl.group_id, - ignore_flow_level, - flow_source); - if (ret) - goto free_action; - - refcount_inc(&dmn->refcount); - - for (i = 0; i < num_of_ref; i++) - refcount_inc(&ref_actions[i]->refcount); - - action->dest_tbl->is_fw_tbl = true; - action->dest_tbl->fw_tbl.dmn = dmn; - action->dest_tbl->fw_tbl.type = FS_FT_FDB; - action->dest_tbl->fw_tbl.ref_actions = ref_actions; - action->dest_tbl->fw_tbl.num_of_ref_actions = num_of_ref; - - kfree(hw_dests); - - return action; - -free_action: - kfree(action); -free_ref_actions: - kfree(ref_actions); -free_hw_dests: - kfree(hw_dests); - return NULL; -} - -struct mlx5dr_action * -mlx5dr_action_create_dest_flow_fw_table(struct mlx5dr_domain *dmn, - struct mlx5_flow_table *ft) -{ - struct mlx5dr_action *action; - - action = dr_action_create_generic(DR_ACTION_TYP_FT); - if (!action) - return NULL; - - action->dest_tbl->is_fw_tbl = 1; - action->dest_tbl->fw_tbl.type = ft->type; - action->dest_tbl->fw_tbl.id = ft->id; - action->dest_tbl->fw_tbl.dmn = dmn; - - refcount_inc(&dmn->refcount); - - return action; -} - -struct mlx5dr_action * -mlx5dr_action_create_flow_counter(u32 counter_id) -{ - struct mlx5dr_action *action; - - action = dr_action_create_generic(DR_ACTION_TYP_CTR); - if (!action) - return NULL; - - action->ctr->ctr_id = counter_id; - - return action; -} - -struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value) -{ - struct mlx5dr_action *action; - - action = dr_action_create_generic(DR_ACTION_TYP_TAG); - if (!action) - return NULL; - - action->flow_tag->flow_tag = tag_value & 0xffffff; - - return action; -} - -struct mlx5dr_action * -mlx5dr_action_create_flow_sampler(struct mlx5dr_domain *dmn, u32 sampler_id) -{ - struct mlx5dr_action *action; - u64 icm_rx, icm_tx; - int ret; - - ret = mlx5dr_cmd_query_flow_sampler(dmn->mdev, sampler_id, - &icm_rx, &icm_tx); - if (ret) - return NULL; - - action = dr_action_create_generic(DR_ACTION_TYP_SAMPLER); - if (!action) - return NULL; - - action->sampler->dmn = dmn; - action->sampler->sampler_id = sampler_id; - action->sampler->rx_icm_addr = icm_rx; - action->sampler->tx_icm_addr = icm_tx; - - refcount_inc(&dmn->refcount); - return action; -} - -static int -dr_action_verify_reformat_params(enum mlx5dr_action_type reformat_type, - struct mlx5dr_domain *dmn, - u8 reformat_param_0, - u8 reformat_param_1, - size_t data_sz, - void *data) -{ - if (reformat_type == DR_ACTION_TYP_INSERT_HDR) { - if ((!data && data_sz) || (data && !data_sz) || - MLX5_CAP_GEN_2(dmn->mdev, max_reformat_insert_size) < data_sz || - MLX5_CAP_GEN_2(dmn->mdev, max_reformat_insert_offset) < reformat_param_1) { - mlx5dr_dbg(dmn, "Invalid reformat parameters for INSERT_HDR\n"); - goto out_err; - } - } else if (reformat_type == DR_ACTION_TYP_REMOVE_HDR) { - if (data || - MLX5_CAP_GEN_2(dmn->mdev, max_reformat_remove_size) < data_sz || - MLX5_CAP_GEN_2(dmn->mdev, max_reformat_remove_offset) < reformat_param_1) { - mlx5dr_dbg(dmn, "Invalid reformat parameters for REMOVE_HDR\n"); - goto out_err; - } - } else if (reformat_param_0 || reformat_param_1 || - reformat_type > DR_ACTION_TYP_REMOVE_HDR) { - mlx5dr_dbg(dmn, "Invalid reformat parameters\n"); - goto out_err; - } - - if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB) - return 0; - - if (dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) { - if (reformat_type != DR_ACTION_TYP_TNL_L2_TO_L2 && - reformat_type != DR_ACTION_TYP_TNL_L3_TO_L2) { - mlx5dr_dbg(dmn, "Action reformat type not support on RX domain\n"); - goto out_err; - } - } else if (dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) { - if (reformat_type != DR_ACTION_TYP_L2_TO_TNL_L2 && - reformat_type != DR_ACTION_TYP_L2_TO_TNL_L3) { - mlx5dr_dbg(dmn, "Action reformat type not support on TX domain\n"); - goto out_err; - } - } - - return 0; - -out_err: - return -EINVAL; -} - -static int -dr_action_create_reformat_action(struct mlx5dr_domain *dmn, - u8 reformat_param_0, u8 reformat_param_1, - size_t data_sz, void *data, - struct mlx5dr_action *action) -{ - u32 reformat_id; - int ret; - - switch (action->action_type) { - case DR_ACTION_TYP_L2_TO_TNL_L2: - case DR_ACTION_TYP_L2_TO_TNL_L3: - { - enum mlx5_reformat_ctx_type rt; - - if (action->action_type == DR_ACTION_TYP_L2_TO_TNL_L2) - rt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL; - else - rt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; - - ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, rt, 0, 0, - data_sz, data, - &reformat_id); - if (ret) - return ret; - - action->reformat->id = reformat_id; - action->reformat->size = data_sz; - return 0; - } - case DR_ACTION_TYP_TNL_L2_TO_L2: - { - return 0; - } - case DR_ACTION_TYP_TNL_L3_TO_L2: - { - u8 *hw_actions; - - hw_actions = kzalloc(DR_ACTION_CACHE_LINE_SIZE, GFP_KERNEL); - if (!hw_actions) - return -ENOMEM; - - ret = mlx5dr_ste_set_action_decap_l3_list(dmn->ste_ctx, - data, data_sz, - hw_actions, - DR_ACTION_CACHE_LINE_SIZE, - &action->rewrite->num_of_actions); - if (ret) { - mlx5dr_dbg(dmn, "Failed creating decap l3 action list\n"); - kfree(hw_actions); - return ret; - } - - action->rewrite->data = hw_actions; - action->rewrite->dmn = dmn; - - ret = mlx5dr_ste_alloc_modify_hdr(action); - if (ret) { - mlx5dr_dbg(dmn, "Failed preparing reformat data\n"); - kfree(hw_actions); - return ret; - } - return 0; - } - case DR_ACTION_TYP_INSERT_HDR: - ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, - MLX5_REFORMAT_TYPE_INSERT_HDR, - reformat_param_0, - reformat_param_1, - data_sz, data, - &reformat_id); - if (ret) - return ret; - - action->reformat->id = reformat_id; - action->reformat->size = data_sz; - action->reformat->param_0 = reformat_param_0; - action->reformat->param_1 = reformat_param_1; - return 0; - case DR_ACTION_TYP_REMOVE_HDR: - action->reformat->id = 0; - action->reformat->size = data_sz; - action->reformat->param_0 = reformat_param_0; - action->reformat->param_1 = reformat_param_1; - return 0; - default: - mlx5dr_info(dmn, "Reformat type is not supported %d\n", action->action_type); - return -EINVAL; - } -} - -#define CVLAN_ETHERTYPE 0x8100 -#define SVLAN_ETHERTYPE 0x88a8 - -struct mlx5dr_action *mlx5dr_action_create_pop_vlan(void) -{ - return dr_action_create_generic(DR_ACTION_TYP_POP_VLAN); -} - -struct mlx5dr_action *mlx5dr_action_create_push_vlan(struct mlx5dr_domain *dmn, - __be32 vlan_hdr) -{ - u32 vlan_hdr_h = ntohl(vlan_hdr); - u16 ethertype = vlan_hdr_h >> 16; - struct mlx5dr_action *action; - - if (ethertype != SVLAN_ETHERTYPE && ethertype != CVLAN_ETHERTYPE) { - mlx5dr_dbg(dmn, "Invalid vlan ethertype\n"); - return NULL; - } - - action = dr_action_create_generic(DR_ACTION_TYP_PUSH_VLAN); - if (!action) - return NULL; - - action->push_vlan->vlan_hdr = vlan_hdr_h; - return action; -} - -struct mlx5dr_action * -mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn, - enum mlx5dr_action_reformat_type reformat_type, - u8 reformat_param_0, - u8 reformat_param_1, - size_t data_sz, - void *data) -{ - enum mlx5dr_action_type action_type; - struct mlx5dr_action *action; - int ret; - - refcount_inc(&dmn->refcount); - - /* General checks */ - ret = dr_action_reformat_to_action_type(reformat_type, &action_type); - if (ret) { - mlx5dr_dbg(dmn, "Invalid reformat_type provided\n"); - goto dec_ref; - } - - ret = dr_action_verify_reformat_params(action_type, dmn, - reformat_param_0, reformat_param_1, - data_sz, data); - if (ret) - goto dec_ref; - - action = dr_action_create_generic(action_type); - if (!action) - goto dec_ref; - - action->reformat->dmn = dmn; - - ret = dr_action_create_reformat_action(dmn, - reformat_param_0, - reformat_param_1, - data_sz, - data, - action); - if (ret) { - mlx5dr_dbg(dmn, "Failed creating reformat action %d\n", ret); - goto free_action; - } - - return action; - -free_action: - kfree(action); -dec_ref: - refcount_dec(&dmn->refcount); - return NULL; -} - -static int -dr_action_modify_sw_to_hw_add(struct mlx5dr_domain *dmn, - __be64 *sw_action, - __be64 *hw_action, - const struct mlx5dr_ste_action_modify_field **ret_hw_info) -{ - const struct mlx5dr_ste_action_modify_field *hw_action_info; - u8 max_length; - u16 sw_field; - u32 data; - - /* Get SW modify action data */ - sw_field = MLX5_GET(set_action_in, sw_action, field); - data = MLX5_GET(set_action_in, sw_action, data); - - /* Convert SW data to HW modify action format */ - hw_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, sw_field); - if (!hw_action_info) { - mlx5dr_dbg(dmn, "Modify add action invalid field given\n"); - return -EINVAL; - } - - max_length = hw_action_info->end - hw_action_info->start + 1; - - mlx5dr_ste_set_action_add(dmn->ste_ctx, - hw_action, - hw_action_info->hw_field, - hw_action_info->start, - max_length, - data); - - *ret_hw_info = hw_action_info; - - return 0; -} - -static int -dr_action_modify_sw_to_hw_set(struct mlx5dr_domain *dmn, - __be64 *sw_action, - __be64 *hw_action, - const struct mlx5dr_ste_action_modify_field **ret_hw_info) -{ - const struct mlx5dr_ste_action_modify_field *hw_action_info; - u8 offset, length, max_length; - u16 sw_field; - u32 data; - - /* Get SW modify action data */ - length = MLX5_GET(set_action_in, sw_action, length); - offset = MLX5_GET(set_action_in, sw_action, offset); - sw_field = MLX5_GET(set_action_in, sw_action, field); - data = MLX5_GET(set_action_in, sw_action, data); - - /* Convert SW data to HW modify action format */ - hw_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, sw_field); - if (!hw_action_info) { - mlx5dr_dbg(dmn, "Modify set action invalid field given\n"); - return -EINVAL; - } - - /* PRM defines that length zero specific length of 32bits */ - length = length ? length : 32; - - max_length = hw_action_info->end - hw_action_info->start + 1; - - if (length + offset > max_length) { - mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n"); - return -EINVAL; - } - - mlx5dr_ste_set_action_set(dmn->ste_ctx, - hw_action, - hw_action_info->hw_field, - hw_action_info->start + offset, - length, - data); - - *ret_hw_info = hw_action_info; - - return 0; -} - -static int -dr_action_modify_sw_to_hw_copy(struct mlx5dr_domain *dmn, - __be64 *sw_action, - __be64 *hw_action, - const struct mlx5dr_ste_action_modify_field **ret_dst_hw_info, - const struct mlx5dr_ste_action_modify_field **ret_src_hw_info) -{ - u8 src_offset, dst_offset, src_max_length, dst_max_length, length; - const struct mlx5dr_ste_action_modify_field *hw_dst_action_info; - const struct mlx5dr_ste_action_modify_field *hw_src_action_info; - u16 src_field, dst_field; - - /* Get SW modify action data */ - src_field = MLX5_GET(copy_action_in, sw_action, src_field); - dst_field = MLX5_GET(copy_action_in, sw_action, dst_field); - src_offset = MLX5_GET(copy_action_in, sw_action, src_offset); - dst_offset = MLX5_GET(copy_action_in, sw_action, dst_offset); - length = MLX5_GET(copy_action_in, sw_action, length); - - /* Convert SW data to HW modify action format */ - hw_src_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, src_field); - hw_dst_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, dst_field); - if (!hw_src_action_info || !hw_dst_action_info) { - mlx5dr_dbg(dmn, "Modify copy action invalid field given\n"); - return -EINVAL; - } - - /* PRM defines that length zero specific length of 32bits */ - length = length ? length : 32; - - src_max_length = hw_src_action_info->end - - hw_src_action_info->start + 1; - dst_max_length = hw_dst_action_info->end - - hw_dst_action_info->start + 1; - - if (length + src_offset > src_max_length || - length + dst_offset > dst_max_length) { - mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n"); - return -EINVAL; - } - - mlx5dr_ste_set_action_copy(dmn->ste_ctx, - hw_action, - hw_dst_action_info->hw_field, - hw_dst_action_info->start + dst_offset, - length, - hw_src_action_info->hw_field, - hw_src_action_info->start + src_offset); - - *ret_dst_hw_info = hw_dst_action_info; - *ret_src_hw_info = hw_src_action_info; - - return 0; -} - -static int -dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn, - __be64 *sw_action, - __be64 *hw_action, - const struct mlx5dr_ste_action_modify_field **ret_dst_hw_info, - const struct mlx5dr_ste_action_modify_field **ret_src_hw_info) -{ - u8 action; - int ret; - - *hw_action = 0; - *ret_src_hw_info = NULL; - - /* Get SW modify action type */ - action = MLX5_GET(set_action_in, sw_action, action_type); - - switch (action) { - case MLX5_ACTION_TYPE_SET: - ret = dr_action_modify_sw_to_hw_set(dmn, sw_action, - hw_action, - ret_dst_hw_info); - break; - - case MLX5_ACTION_TYPE_ADD: - ret = dr_action_modify_sw_to_hw_add(dmn, sw_action, - hw_action, - ret_dst_hw_info); - break; - - case MLX5_ACTION_TYPE_COPY: - ret = dr_action_modify_sw_to_hw_copy(dmn, sw_action, - hw_action, - ret_dst_hw_info, - ret_src_hw_info); - break; - - default: - mlx5dr_info(dmn, "Unsupported action_type for modify action\n"); - ret = -EOPNOTSUPP; - } - - return ret; -} - -static int -dr_action_modify_check_set_field_limitation(struct mlx5dr_action *action, - const __be64 *sw_action) -{ - u16 sw_field = MLX5_GET(set_action_in, sw_action, field); - struct mlx5dr_domain *dmn = action->rewrite->dmn; - - if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_A) { - action->rewrite->allow_rx = 0; - if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) { - mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n", - sw_field); - return -EINVAL; - } - } else if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_B) { - action->rewrite->allow_tx = 0; - if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) { - mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n", - sw_field); - return -EINVAL; - } - } - - if (!action->rewrite->allow_rx && !action->rewrite->allow_tx) { - mlx5dr_dbg(dmn, "Modify SET actions not supported on both RX and TX\n"); - return -EINVAL; - } - - return 0; -} - -static int -dr_action_modify_check_add_field_limitation(struct mlx5dr_action *action, - const __be64 *sw_action) -{ - u16 sw_field = MLX5_GET(set_action_in, sw_action, field); - struct mlx5dr_domain *dmn = action->rewrite->dmn; - - if (sw_field != MLX5_ACTION_IN_FIELD_OUT_IP_TTL && - sw_field != MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT && - sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM && - sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM) { - mlx5dr_dbg(dmn, "Unsupported field %d for add action\n", - sw_field); - return -EINVAL; - } - - return 0; -} - -static int -dr_action_modify_check_copy_field_limitation(struct mlx5dr_action *action, - const __be64 *sw_action) -{ - struct mlx5dr_domain *dmn = action->rewrite->dmn; - u16 sw_fields[2]; - int i; - - sw_fields[0] = MLX5_GET(copy_action_in, sw_action, src_field); - sw_fields[1] = MLX5_GET(copy_action_in, sw_action, dst_field); - - for (i = 0; i < 2; i++) { - if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_A) { - action->rewrite->allow_rx = 0; - if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) { - mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n", - sw_fields[i]); - return -EINVAL; - } - } else if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_B) { - action->rewrite->allow_tx = 0; - if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) { - mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n", - sw_fields[i]); - return -EINVAL; - } - } - } - - if (!action->rewrite->allow_rx && !action->rewrite->allow_tx) { - mlx5dr_dbg(dmn, "Modify copy actions not supported on both RX and TX\n"); - return -EINVAL; - } - - return 0; -} - -static int -dr_action_modify_check_field_limitation(struct mlx5dr_action *action, - const __be64 *sw_action) -{ - struct mlx5dr_domain *dmn = action->rewrite->dmn; - u8 action_type; - int ret; - - action_type = MLX5_GET(set_action_in, sw_action, action_type); - - switch (action_type) { - case MLX5_ACTION_TYPE_SET: - ret = dr_action_modify_check_set_field_limitation(action, - sw_action); - break; - - case MLX5_ACTION_TYPE_ADD: - ret = dr_action_modify_check_add_field_limitation(action, - sw_action); - break; - - case MLX5_ACTION_TYPE_COPY: - ret = dr_action_modify_check_copy_field_limitation(action, - sw_action); - break; - - default: - mlx5dr_info(dmn, "Unsupported action %d modify action\n", - action_type); - ret = -EOPNOTSUPP; - } - - return ret; -} - -static bool -dr_action_modify_check_is_ttl_modify(const void *sw_action) -{ - u16 sw_field = MLX5_GET(set_action_in, sw_action, field); - - return sw_field == MLX5_ACTION_IN_FIELD_OUT_IP_TTL; -} - -static int dr_actions_convert_modify_header(struct mlx5dr_action *action, - u32 max_hw_actions, - u32 num_sw_actions, - __be64 sw_actions[], - __be64 hw_actions[], - u32 *num_hw_actions, - bool *modify_ttl) -{ - const struct mlx5dr_ste_action_modify_field *hw_dst_action_info; - const struct mlx5dr_ste_action_modify_field *hw_src_action_info; - struct mlx5dr_domain *dmn = action->rewrite->dmn; - __be64 *modify_ttl_sw_action = NULL; - int ret, i, hw_idx = 0; - __be64 *sw_action; - __be64 hw_action; - u16 hw_field = 0; - u32 l3_type = 0; - u32 l4_type = 0; - - *modify_ttl = false; - - action->rewrite->allow_rx = 1; - action->rewrite->allow_tx = 1; - - for (i = 0; i < num_sw_actions || modify_ttl_sw_action; i++) { - /* modify TTL is handled separately, as a last action */ - if (i == num_sw_actions) { - sw_action = modify_ttl_sw_action; - modify_ttl_sw_action = NULL; - } else { - sw_action = &sw_actions[i]; - } - - ret = dr_action_modify_check_field_limitation(action, - sw_action); - if (ret) - return ret; - - if (!(*modify_ttl) && - dr_action_modify_check_is_ttl_modify(sw_action)) { - modify_ttl_sw_action = sw_action; - *modify_ttl = true; - continue; - } - - /* Convert SW action to HW action */ - ret = dr_action_modify_sw_to_hw(dmn, - sw_action, - &hw_action, - &hw_dst_action_info, - &hw_src_action_info); - if (ret) - return ret; - - /* Due to a HW limitation we cannot modify 2 different L3 types */ - if (l3_type && hw_dst_action_info->l3_type && - hw_dst_action_info->l3_type != l3_type) { - mlx5dr_dbg(dmn, "Action list can't support two different L3 types\n"); - return -EINVAL; - } - if (hw_dst_action_info->l3_type) - l3_type = hw_dst_action_info->l3_type; - - /* Due to a HW limitation we cannot modify two different L4 types */ - if (l4_type && hw_dst_action_info->l4_type && - hw_dst_action_info->l4_type != l4_type) { - mlx5dr_dbg(dmn, "Action list can't support two different L4 types\n"); - return -EINVAL; - } - if (hw_dst_action_info->l4_type) - l4_type = hw_dst_action_info->l4_type; - - /* HW reads and executes two actions at once this means we - * need to create a gap if two actions access the same field - */ - if ((hw_idx % 2) && (hw_field == hw_dst_action_info->hw_field || - (hw_src_action_info && - hw_field == hw_src_action_info->hw_field))) { - /* Check if after gap insertion the total number of HW - * modify actions doesn't exceeds the limit - */ - hw_idx++; - if (hw_idx >= max_hw_actions) { - mlx5dr_dbg(dmn, "Modify header action number exceeds HW limit\n"); - return -EINVAL; - } - } - hw_field = hw_dst_action_info->hw_field; - - hw_actions[hw_idx] = hw_action; - hw_idx++; - } - - /* if the resulting HW actions list is empty, add NOP action */ - if (!hw_idx) - hw_idx++; - - *num_hw_actions = hw_idx; - - return 0; -} - -static int dr_action_create_modify_action(struct mlx5dr_domain *dmn, - size_t actions_sz, - __be64 actions[], - struct mlx5dr_action *action) -{ - u32 max_hw_actions; - u32 num_hw_actions; - u32 num_sw_actions; - __be64 *hw_actions; - bool modify_ttl; - int ret; - - num_sw_actions = actions_sz / DR_MODIFY_ACTION_SIZE; - max_hw_actions = mlx5dr_icm_pool_chunk_size_to_entries(DR_CHUNK_SIZE_16); - - if (num_sw_actions > max_hw_actions) { - mlx5dr_dbg(dmn, "Max number of actions %d exceeds limit %d\n", - num_sw_actions, max_hw_actions); - return -EINVAL; - } - - hw_actions = kcalloc(1, max_hw_actions * DR_MODIFY_ACTION_SIZE, GFP_KERNEL); - if (!hw_actions) - return -ENOMEM; - - ret = dr_actions_convert_modify_header(action, - max_hw_actions, - num_sw_actions, - actions, - hw_actions, - &num_hw_actions, - &modify_ttl); - if (ret) - goto free_hw_actions; - - action->rewrite->modify_ttl = modify_ttl; - action->rewrite->data = (u8 *)hw_actions; - action->rewrite->num_of_actions = num_hw_actions; - - if (num_hw_actions == 1 && - dmn->info.caps.sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) { - action->rewrite->single_action_opt = true; - } else { - action->rewrite->single_action_opt = false; - ret = mlx5dr_ste_alloc_modify_hdr(action); - if (ret) - goto free_hw_actions; - } - - return 0; - -free_hw_actions: - kfree(hw_actions); - return ret; -} - -struct mlx5dr_action * -mlx5dr_action_create_modify_header(struct mlx5dr_domain *dmn, - u32 flags, - size_t actions_sz, - __be64 actions[]) -{ - struct mlx5dr_action *action; - int ret = 0; - - refcount_inc(&dmn->refcount); - - if (actions_sz % DR_MODIFY_ACTION_SIZE) { - mlx5dr_dbg(dmn, "Invalid modify actions size provided\n"); - goto dec_ref; - } - - action = dr_action_create_generic(DR_ACTION_TYP_MODIFY_HDR); - if (!action) - goto dec_ref; - - action->rewrite->dmn = dmn; - - ret = dr_action_create_modify_action(dmn, - actions_sz, - actions, - action); - if (ret) { - mlx5dr_dbg(dmn, "Failed creating modify header action %d\n", ret); - goto free_action; - } - - return action; - -free_action: - kfree(action); -dec_ref: - refcount_dec(&dmn->refcount); - return NULL; -} - -struct mlx5dr_action * -mlx5dr_action_create_dest_vport(struct mlx5dr_domain *dmn, - u16 vport, u8 vhca_id_valid, - u16 vhca_id) -{ - struct mlx5dr_cmd_vport_cap *vport_cap; - struct mlx5dr_domain *vport_dmn; - struct mlx5dr_action *action; - u8 peer_vport; - - peer_vport = vhca_id_valid && mlx5_core_is_pf(dmn->mdev) && - (vhca_id != dmn->info.caps.gvmi); - vport_dmn = peer_vport ? xa_load(&dmn->peer_dmn_xa, vhca_id) : dmn; - if (!vport_dmn) { - mlx5dr_dbg(dmn, "No peer vport domain for given vhca_id\n"); - return NULL; - } - - if (vport_dmn->type != MLX5DR_DOMAIN_TYPE_FDB) { - mlx5dr_dbg(dmn, "Domain doesn't support vport actions\n"); - return NULL; - } - - vport_cap = mlx5dr_domain_get_vport_cap(vport_dmn, vport); - if (!vport_cap) { - mlx5dr_err(dmn, - "Failed to get vport 0x%x caps - vport is disabled or invalid\n", - vport); - return NULL; - } - - action = dr_action_create_generic(DR_ACTION_TYP_VPORT); - if (!action) - return NULL; - - action->vport->dmn = vport_dmn; - action->vport->caps = vport_cap; - - return action; -} - -struct mlx5dr_action * -mlx5dr_action_create_aso(struct mlx5dr_domain *dmn, u32 obj_id, - u8 dest_reg_id, u8 aso_type, - u8 init_color, u8 meter_id) -{ - struct mlx5dr_action *action; - - if (aso_type != MLX5_EXE_ASO_FLOW_METER) - return NULL; - - if (init_color > MLX5_FLOW_METER_COLOR_UNDEFINED) - return NULL; - - action = dr_action_create_generic(DR_ACTION_TYP_ASO_FLOW_METER); - if (!action) - return NULL; - - action->aso->obj_id = obj_id; - action->aso->offset = meter_id; - action->aso->dest_reg_id = dest_reg_id; - action->aso->init_color = init_color; - action->aso->dmn = dmn; - - refcount_inc(&dmn->refcount); - - return action; -} - -u32 mlx5dr_action_get_pkt_reformat_id(struct mlx5dr_action *action) -{ - return action->reformat->id; -} - -int mlx5dr_action_destroy(struct mlx5dr_action *action) -{ - if (WARN_ON_ONCE(refcount_read(&action->refcount) > 1)) - return -EBUSY; - - switch (action->action_type) { - case DR_ACTION_TYP_FT: - if (action->dest_tbl->is_fw_tbl) - refcount_dec(&action->dest_tbl->fw_tbl.dmn->refcount); - else - refcount_dec(&action->dest_tbl->tbl->refcount); - - if (action->dest_tbl->is_fw_tbl && - action->dest_tbl->fw_tbl.num_of_ref_actions) { - struct mlx5dr_action **ref_actions; - int i; - - ref_actions = action->dest_tbl->fw_tbl.ref_actions; - for (i = 0; i < action->dest_tbl->fw_tbl.num_of_ref_actions; i++) - refcount_dec(&ref_actions[i]->refcount); - - kfree(ref_actions); - - mlx5dr_fw_destroy_md_tbl(action->dest_tbl->fw_tbl.dmn, - action->dest_tbl->fw_tbl.id, - action->dest_tbl->fw_tbl.group_id); - } - break; - case DR_ACTION_TYP_TNL_L2_TO_L2: - case DR_ACTION_TYP_REMOVE_HDR: - refcount_dec(&action->reformat->dmn->refcount); - break; - case DR_ACTION_TYP_TNL_L3_TO_L2: - mlx5dr_ste_free_modify_hdr(action); - kfree(action->rewrite->data); - refcount_dec(&action->rewrite->dmn->refcount); - break; - case DR_ACTION_TYP_L2_TO_TNL_L2: - case DR_ACTION_TYP_L2_TO_TNL_L3: - case DR_ACTION_TYP_INSERT_HDR: - mlx5dr_cmd_destroy_reformat_ctx((action->reformat->dmn)->mdev, - action->reformat->id); - refcount_dec(&action->reformat->dmn->refcount); - break; - case DR_ACTION_TYP_MODIFY_HDR: - if (!action->rewrite->single_action_opt) - mlx5dr_ste_free_modify_hdr(action); - kfree(action->rewrite->data); - refcount_dec(&action->rewrite->dmn->refcount); - break; - case DR_ACTION_TYP_SAMPLER: - refcount_dec(&action->sampler->dmn->refcount); - break; - case DR_ACTION_TYP_ASO_FLOW_METER: - refcount_dec(&action->aso->dmn->refcount); - break; - case DR_ACTION_TYP_RANGE: - dr_action_destroy_range_definer(action); - mlx5dr_action_destroy(action->range->miss_tbl_action); - mlx5dr_action_destroy(action->range->hit_tbl_action); - break; - default: - break; - } - - kfree(action); - return 0; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_arg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_arg.c deleted file mode 100644 index 01ed6442095d78..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_arg.c +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - -#include "dr_types.h" - -#define DR_ICM_MODIFY_HDR_GRANULARITY_4K 12 - -/* modify-header arg pool */ -enum dr_arg_chunk_size { - DR_ARG_CHUNK_SIZE_1, - DR_ARG_CHUNK_SIZE_MIN = DR_ARG_CHUNK_SIZE_1, /* keep updated when changing */ - DR_ARG_CHUNK_SIZE_2, - DR_ARG_CHUNK_SIZE_3, - DR_ARG_CHUNK_SIZE_4, - DR_ARG_CHUNK_SIZE_MAX, -}; - -/* argument pool area */ -struct dr_arg_pool { - enum dr_arg_chunk_size log_chunk_size; - struct mlx5dr_domain *dmn; - struct list_head free_list; - struct mutex mutex; /* protect arg pool */ -}; - -struct mlx5dr_arg_mgr { - struct mlx5dr_domain *dmn; - struct dr_arg_pool *pools[DR_ARG_CHUNK_SIZE_MAX]; -}; - -static int dr_arg_pool_alloc_objs(struct dr_arg_pool *pool) -{ - struct mlx5dr_arg_obj *arg_obj, *tmp_arg; - struct list_head cur_list; - u16 object_range; - int num_of_objects; - u32 obj_id = 0; - int i, ret; - - INIT_LIST_HEAD(&cur_list); - - object_range = - pool->dmn->info.caps.log_header_modify_argument_granularity; - - object_range = - max_t(u32, pool->dmn->info.caps.log_header_modify_argument_granularity, - DR_ICM_MODIFY_HDR_GRANULARITY_4K); - object_range = - min_t(u32, pool->dmn->info.caps.log_header_modify_argument_max_alloc, - object_range); - - if (pool->log_chunk_size > object_range) { - mlx5dr_err(pool->dmn, "Required chunk size (%d) is not supported\n", - pool->log_chunk_size); - return -ENOMEM; - } - - num_of_objects = (1 << (object_range - pool->log_chunk_size)); - /* Only one devx object per range */ - ret = mlx5dr_cmd_create_modify_header_arg(pool->dmn->mdev, - object_range, - pool->dmn->pdn, - &obj_id); - if (ret) { - mlx5dr_err(pool->dmn, "failed allocating object with range: %d:\n", - object_range); - return -EAGAIN; - } - - for (i = 0; i < num_of_objects; i++) { - arg_obj = kzalloc(sizeof(*arg_obj), GFP_KERNEL); - if (!arg_obj) { - ret = -ENOMEM; - goto clean_arg_obj; - } - - arg_obj->log_chunk_size = pool->log_chunk_size; - - list_add_tail(&arg_obj->list_node, &cur_list); - - arg_obj->obj_id = obj_id; - arg_obj->obj_offset = i * (1 << pool->log_chunk_size); - } - list_splice_tail_init(&cur_list, &pool->free_list); - - return 0; - -clean_arg_obj: - mlx5dr_cmd_destroy_modify_header_arg(pool->dmn->mdev, obj_id); - list_for_each_entry_safe(arg_obj, tmp_arg, &cur_list, list_node) { - list_del(&arg_obj->list_node); - kfree(arg_obj); - } - return ret; -} - -static struct mlx5dr_arg_obj *dr_arg_pool_get_arg_obj(struct dr_arg_pool *pool) -{ - struct mlx5dr_arg_obj *arg_obj = NULL; - int ret; - - mutex_lock(&pool->mutex); - if (list_empty(&pool->free_list)) { - ret = dr_arg_pool_alloc_objs(pool); - if (ret) - goto out; - } - - arg_obj = list_first_entry_or_null(&pool->free_list, - struct mlx5dr_arg_obj, - list_node); - WARN(!arg_obj, "couldn't get dr arg obj from pool"); - - if (arg_obj) - list_del_init(&arg_obj->list_node); - -out: - mutex_unlock(&pool->mutex); - return arg_obj; -} - -static void dr_arg_pool_put_arg_obj(struct dr_arg_pool *pool, - struct mlx5dr_arg_obj *arg_obj) -{ - mutex_lock(&pool->mutex); - list_add(&arg_obj->list_node, &pool->free_list); - mutex_unlock(&pool->mutex); -} - -static struct dr_arg_pool *dr_arg_pool_create(struct mlx5dr_domain *dmn, - enum dr_arg_chunk_size chunk_size) -{ - struct dr_arg_pool *pool; - - pool = kzalloc(sizeof(*pool), GFP_KERNEL); - if (!pool) - return NULL; - - pool->dmn = dmn; - - INIT_LIST_HEAD(&pool->free_list); - mutex_init(&pool->mutex); - - pool->log_chunk_size = chunk_size; - if (dr_arg_pool_alloc_objs(pool)) - goto free_pool; - - return pool; - -free_pool: - kfree(pool); - - return NULL; -} - -static void dr_arg_pool_destroy(struct dr_arg_pool *pool) -{ - struct mlx5dr_arg_obj *arg_obj, *tmp_arg; - - list_for_each_entry_safe(arg_obj, tmp_arg, &pool->free_list, list_node) { - list_del(&arg_obj->list_node); - if (!arg_obj->obj_offset) /* the first in range */ - mlx5dr_cmd_destroy_modify_header_arg(pool->dmn->mdev, arg_obj->obj_id); - kfree(arg_obj); - } - - mutex_destroy(&pool->mutex); - kfree(pool); -} - -static enum dr_arg_chunk_size dr_arg_get_chunk_size(u16 num_of_actions) -{ - if (num_of_actions <= 8) - return DR_ARG_CHUNK_SIZE_1; - if (num_of_actions <= 16) - return DR_ARG_CHUNK_SIZE_2; - if (num_of_actions <= 32) - return DR_ARG_CHUNK_SIZE_3; - if (num_of_actions <= 64) - return DR_ARG_CHUNK_SIZE_4; - - return DR_ARG_CHUNK_SIZE_MAX; -} - -u32 mlx5dr_arg_get_obj_id(struct mlx5dr_arg_obj *arg_obj) -{ - return (arg_obj->obj_id + arg_obj->obj_offset); -} - -struct mlx5dr_arg_obj *mlx5dr_arg_get_obj(struct mlx5dr_arg_mgr *mgr, - u16 num_of_actions, - u8 *data) -{ - u32 size = dr_arg_get_chunk_size(num_of_actions); - struct mlx5dr_arg_obj *arg_obj; - int ret; - - if (size >= DR_ARG_CHUNK_SIZE_MAX) - return NULL; - - arg_obj = dr_arg_pool_get_arg_obj(mgr->pools[size]); - if (!arg_obj) { - mlx5dr_err(mgr->dmn, "Failed allocating args object for modify header\n"); - return NULL; - } - - /* write it into the hw */ - ret = mlx5dr_send_postsend_args(mgr->dmn, - mlx5dr_arg_get_obj_id(arg_obj), - num_of_actions, data); - if (ret) { - mlx5dr_err(mgr->dmn, "Failed writing args object\n"); - goto put_obj; - } - - return arg_obj; - -put_obj: - mlx5dr_arg_put_obj(mgr, arg_obj); - return NULL; -} - -void mlx5dr_arg_put_obj(struct mlx5dr_arg_mgr *mgr, - struct mlx5dr_arg_obj *arg_obj) -{ - dr_arg_pool_put_arg_obj(mgr->pools[arg_obj->log_chunk_size], arg_obj); -} - -struct mlx5dr_arg_mgr* -mlx5dr_arg_mgr_create(struct mlx5dr_domain *dmn) -{ - struct mlx5dr_arg_mgr *pool_mgr; - int i; - - if (!mlx5dr_domain_is_support_ptrn_arg(dmn)) - return NULL; - - pool_mgr = kzalloc(sizeof(*pool_mgr), GFP_KERNEL); - if (!pool_mgr) - return NULL; - - pool_mgr->dmn = dmn; - - for (i = 0; i < DR_ARG_CHUNK_SIZE_MAX; i++) { - pool_mgr->pools[i] = dr_arg_pool_create(dmn, i); - if (!pool_mgr->pools[i]) - goto clean_pools; - } - - return pool_mgr; - -clean_pools: - for (i--; i >= 0; i--) - dr_arg_pool_destroy(pool_mgr->pools[i]); - - kfree(pool_mgr); - return NULL; -} - -void mlx5dr_arg_mgr_destroy(struct mlx5dr_arg_mgr *mgr) -{ - struct dr_arg_pool **pools; - int i; - - if (!mgr) - return; - - pools = mgr->pools; - for (i = 0; i < DR_ARG_CHUNK_SIZE_MAX; i++) - dr_arg_pool_destroy(pools[i]); - - kfree(mgr); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_buddy.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_buddy.c deleted file mode 100644 index fe228d948b4764..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_buddy.c +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2004 Topspin Communications. All rights reserved. - * Copyright (c) 2005 - 2008 Mellanox Technologies. All rights reserved. - * Copyright (c) 2006 - 2007 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. - */ - -#include "dr_types.h" - -int mlx5dr_buddy_init(struct mlx5dr_icm_buddy_mem *buddy, - unsigned int max_order) -{ - int i; - - buddy->max_order = max_order; - - INIT_LIST_HEAD(&buddy->list_node); - - buddy->bitmap = kcalloc(buddy->max_order + 1, - sizeof(*buddy->bitmap), - GFP_KERNEL); - buddy->num_free = kcalloc(buddy->max_order + 1, - sizeof(*buddy->num_free), - GFP_KERNEL); - - if (!buddy->bitmap || !buddy->num_free) - goto err_free_all; - - /* Allocating max_order bitmaps, one for each order */ - - for (i = 0; i <= buddy->max_order; ++i) { - unsigned int size = 1 << (buddy->max_order - i); - - buddy->bitmap[i] = bitmap_zalloc(size, GFP_KERNEL); - if (!buddy->bitmap[i]) - goto err_out_free_each_bit_per_order; - } - - /* In the beginning, we have only one order that is available for - * use (the biggest one), so mark the first bit in both bitmaps. - */ - - bitmap_set(buddy->bitmap[buddy->max_order], 0, 1); - - buddy->num_free[buddy->max_order] = 1; - - return 0; - -err_out_free_each_bit_per_order: - for (i = 0; i <= buddy->max_order; ++i) - bitmap_free(buddy->bitmap[i]); - -err_free_all: - kfree(buddy->num_free); - kfree(buddy->bitmap); - return -ENOMEM; -} - -void mlx5dr_buddy_cleanup(struct mlx5dr_icm_buddy_mem *buddy) -{ - int i; - - list_del(&buddy->list_node); - - for (i = 0; i <= buddy->max_order; ++i) - bitmap_free(buddy->bitmap[i]); - - kfree(buddy->num_free); - kfree(buddy->bitmap); -} - -static int dr_buddy_find_free_seg(struct mlx5dr_icm_buddy_mem *buddy, - unsigned int start_order, - unsigned int *segment, - unsigned int *order) -{ - unsigned int seg, order_iter, m; - - for (order_iter = start_order; - order_iter <= buddy->max_order; ++order_iter) { - if (!buddy->num_free[order_iter]) - continue; - - m = 1 << (buddy->max_order - order_iter); - seg = find_first_bit(buddy->bitmap[order_iter], m); - - if (WARN(seg >= m, - "ICM Buddy: failed finding free mem for order %d\n", - order_iter)) - return -ENOMEM; - - break; - } - - if (order_iter > buddy->max_order) - return -ENOMEM; - - *segment = seg; - *order = order_iter; - return 0; -} - -/** - * mlx5dr_buddy_alloc_mem() - Update second level bitmap. - * @buddy: Buddy to update. - * @order: Order of the buddy to update. - * @segment: Segment number. - * - * This function finds the first area of the ICM memory managed by this buddy. - * It uses the data structures of the buddy system in order to find the first - * area of free place, starting from the current order till the maximum order - * in the system. - * - * Return: 0 when segment is set, non-zero error status otherwise. - * - * The function returns the location (segment) in the whole buddy ICM memory - * area - the index of the memory segment that is available for use. - */ -int mlx5dr_buddy_alloc_mem(struct mlx5dr_icm_buddy_mem *buddy, - unsigned int order, - unsigned int *segment) -{ - unsigned int seg, order_iter; - int err; - - err = dr_buddy_find_free_seg(buddy, order, &seg, &order_iter); - if (err) - return err; - - bitmap_clear(buddy->bitmap[order_iter], seg, 1); - --buddy->num_free[order_iter]; - - /* If we found free memory in some order that is bigger than the - * required order, we need to split every order between the required - * order and the order that we found into two parts, and mark accordingly. - */ - while (order_iter > order) { - --order_iter; - seg <<= 1; - bitmap_set(buddy->bitmap[order_iter], seg ^ 1, 1); - ++buddy->num_free[order_iter]; - } - - seg <<= order; - *segment = seg; - - return 0; -} - -void mlx5dr_buddy_free_mem(struct mlx5dr_icm_buddy_mem *buddy, - unsigned int seg, unsigned int order) -{ - seg >>= order; - - /* Whenever a segment is free, - * the mem is added to the buddy that gave it. - */ - while (test_bit(seg ^ 1, buddy->bitmap[order])) { - bitmap_clear(buddy->bitmap[order], seg ^ 1, 1); - --buddy->num_free[order]; - seg >>= 1; - ++order; - } - bitmap_set(buddy->bitmap[order], seg, 1); - - ++buddy->num_free[order]; -} - diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c deleted file mode 100644 index baefb9a3fa05ea..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c +++ /dev/null @@ -1,970 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include "dr_types.h" - -int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, - bool other_vport, - u16 vport_number, - u64 *icm_address_rx, - u64 *icm_address_tx) -{ - u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {}; - u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {}; - int err; - - MLX5_SET(query_esw_vport_context_in, in, opcode, - MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT); - MLX5_SET(query_esw_vport_context_in, in, other_vport, other_vport); - MLX5_SET(query_esw_vport_context_in, in, vport_number, vport_number); - - err = mlx5_cmd_exec_inout(mdev, query_esw_vport_context, in, out); - if (err) - return err; - - *icm_address_rx = - MLX5_GET64(query_esw_vport_context_out, out, - esw_vport_context.sw_steering_vport_icm_address_rx); - *icm_address_tx = - MLX5_GET64(query_esw_vport_context_out, out, - esw_vport_context.sw_steering_vport_icm_address_tx); - return 0; -} - -int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport, - u16 vport_number, u16 *gvmi) -{ - bool ec_vf_func = other_vport ? mlx5_core_is_ec_vf_vport(mdev, vport_number) : false; - u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; - int out_size; - void *out; - int err; - - out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); - out = kzalloc(out_size, GFP_KERNEL); - if (!out) - return -ENOMEM; - - MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); - MLX5_SET(query_hca_cap_in, in, other_function, other_vport); - MLX5_SET(query_hca_cap_in, in, function_id, mlx5_vport_to_func_id(mdev, vport_number, ec_vf_func)); - MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | - HCA_CAP_OPMOD_GET_CUR); - - err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); - if (err) { - kfree(out); - return err; - } - - *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); - - kfree(out); - return 0; -} - -int mlx5dr_cmd_query_esw_caps(struct mlx5_core_dev *mdev, - struct mlx5dr_esw_caps *caps) -{ - caps->drop_icm_address_rx = - MLX5_CAP64_ESW_FLOWTABLE(mdev, - sw_steering_fdb_action_drop_icm_address_rx); - caps->drop_icm_address_tx = - MLX5_CAP64_ESW_FLOWTABLE(mdev, - sw_steering_fdb_action_drop_icm_address_tx); - caps->uplink_icm_address_rx = - MLX5_CAP64_ESW_FLOWTABLE(mdev, - sw_steering_uplink_icm_address_rx); - caps->uplink_icm_address_tx = - MLX5_CAP64_ESW_FLOWTABLE(mdev, - sw_steering_uplink_icm_address_tx); - caps->sw_owner_v2 = MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, sw_owner_v2); - if (!caps->sw_owner_v2) - caps->sw_owner = MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, sw_owner); - - return 0; -} - -static int dr_cmd_query_nic_vport_roce_en(struct mlx5_core_dev *mdev, - u16 vport, bool *roce_en) -{ - u32 out[MLX5_ST_SZ_DW(query_nic_vport_context_out)] = {}; - u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {}; - int err; - - MLX5_SET(query_nic_vport_context_in, in, opcode, - MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT); - MLX5_SET(query_nic_vport_context_in, in, vport_number, vport); - MLX5_SET(query_nic_vport_context_in, in, other_vport, !!vport); - - err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (err) - return err; - - *roce_en = MLX5_GET(query_nic_vport_context_out, out, - nic_vport_context.roce_en); - return 0; -} - -int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev, - struct mlx5dr_cmd_caps *caps) -{ - bool roce_en; - int err; - - caps->prio_tag_required = MLX5_CAP_GEN(mdev, prio_tag_required); - caps->eswitch_manager = MLX5_CAP_GEN(mdev, eswitch_manager); - 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); - if (err) - return err; - - caps->roce_caps.roce_en = roce_en; - 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); - } - - caps->isolate_vl_tc = MLX5_CAP_GEN(mdev, isolate_vl_tc_new); - - caps->support_modify_argument = - MLX5_CAP_GEN_64(mdev, general_obj_types) & - MLX5_GENERAL_OBJ_TYPES_CAP_HEADER_MODIFY_ARGUMENT; - - if (caps->support_modify_argument) { - caps->log_header_modify_argument_granularity = - MLX5_CAP_GEN(mdev, log_header_modify_argument_granularity); - caps->log_header_modify_argument_max_alloc = - MLX5_CAP_GEN(mdev, log_header_modify_argument_max_alloc); - } - - /* geneve_tlv_option_0_exist is the indication of - * STE support for lookup type flex_parser_ok - */ - caps->flex_parser_ok_bits_supp = - MLX5_CAP_FLOWTABLE(mdev, - flow_table_properties_nic_receive.ft_field_support.geneve_tlv_option_0_exist); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V4_ENABLED) { - caps->flex_parser_id_icmp_dw0 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw0); - caps->flex_parser_id_icmp_dw1 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw1); - } - - if (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V6_ENABLED) { - caps->flex_parser_id_icmpv6_dw0 = - MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw0); - caps->flex_parser_id_icmpv6_dw1 = - MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw1); - } - - if (caps->flex_protocols & MLX5_FLEX_PARSER_GENEVE_TLV_OPTION_0_ENABLED) - caps->flex_parser_id_geneve_tlv_option_0 = - MLX5_CAP_GEN(mdev, flex_parser_id_geneve_tlv_option_0); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED) - caps->flex_parser_id_mpls_over_gre = - MLX5_CAP_GEN(mdev, flex_parser_id_outer_first_mpls_over_gre); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED) - caps->flex_parser_id_mpls_over_udp = - MLX5_CAP_GEN(mdev, flex_parser_id_outer_first_mpls_over_udp_label); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_0_ENABLED) - caps->flex_parser_id_gtpu_dw_0 = - MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_dw_0); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_TEID_ENABLED) - caps->flex_parser_id_gtpu_teid = - MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_teid); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_2_ENABLED) - caps->flex_parser_id_gtpu_dw_2 = - MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_dw_2); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_FIRST_EXT_DW_0_ENABLED) - caps->flex_parser_id_gtpu_first_ext_dw_0 = - MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_first_ext_dw_0); - - caps->nic_rx_drop_address = - MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_rx_action_drop_icm_address); - caps->nic_tx_drop_address = - MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_drop_icm_address); - caps->nic_tx_allow_address = - MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_allow_icm_address); - - caps->rx_sw_owner_v2 = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner_v2); - caps->tx_sw_owner_v2 = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner_v2); - - if (!caps->rx_sw_owner_v2) - caps->rx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner); - if (!caps->tx_sw_owner_v2) - caps->tx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner); - - caps->max_ft_level = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, max_ft_level); - - caps->log_icm_size = MLX5_CAP_DEV_MEM(mdev, log_steering_sw_icm_size); - caps->hdr_modify_icm_addr = - MLX5_CAP64_DEV_MEM(mdev, header_modify_sw_icm_start_address); - - caps->log_modify_pattern_icm_size = - MLX5_CAP_DEV_MEM(mdev, log_header_modify_pattern_sw_icm_size); - - caps->hdr_modify_pattern_icm_addr = - MLX5_CAP64_DEV_MEM(mdev, header_modify_pattern_sw_icm_start_address); - - caps->roce_min_src_udp = MLX5_CAP_ROCE(mdev, r_roce_min_src_udp_port); - - caps->is_ecpf = mlx5_core_is_ecpf_esw_manager(mdev); - - return 0; -} - -int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev, - enum fs_flow_table_type type, - u32 table_id, - struct mlx5dr_cmd_query_flow_table_details *output) -{ - u32 out[MLX5_ST_SZ_DW(query_flow_table_out)] = {}; - u32 in[MLX5_ST_SZ_DW(query_flow_table_in)] = {}; - int err; - - MLX5_SET(query_flow_table_in, in, opcode, - MLX5_CMD_OP_QUERY_FLOW_TABLE); - - MLX5_SET(query_flow_table_in, in, table_type, type); - MLX5_SET(query_flow_table_in, in, table_id, table_id); - - err = mlx5_cmd_exec_inout(dev, query_flow_table, in, out); - if (err) - return err; - - output->status = MLX5_GET(query_flow_table_out, out, status); - output->level = MLX5_GET(query_flow_table_out, out, flow_table_context.level); - - output->sw_owner_icm_root_1 = MLX5_GET64(query_flow_table_out, out, - flow_table_context.sws.sw_owner_icm_root_1); - output->sw_owner_icm_root_0 = MLX5_GET64(query_flow_table_out, out, - flow_table_context.sws.sw_owner_icm_root_0); - - return 0; -} - -int mlx5dr_cmd_query_flow_sampler(struct mlx5_core_dev *dev, - u32 sampler_id, - u64 *rx_icm_addr, - u64 *tx_icm_addr) -{ - u32 out[MLX5_ST_SZ_DW(query_sampler_obj_out)] = {}; - u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; - void *attr; - int ret; - - MLX5_SET(general_obj_in_cmd_hdr, in, opcode, - MLX5_CMD_OP_QUERY_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, - MLX5_GENERAL_OBJECT_TYPES_SAMPLER); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, sampler_id); - - ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); - if (ret) - return ret; - - attr = MLX5_ADDR_OF(query_sampler_obj_out, out, sampler_object); - - *rx_icm_addr = MLX5_GET64(sampler_obj, attr, - sw_steering_icm_address_rx); - *tx_icm_addr = MLX5_GET64(sampler_obj, attr, - sw_steering_icm_address_tx); - - return 0; -} - -int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev) -{ - u32 in[MLX5_ST_SZ_DW(sync_steering_in)] = {}; - - /* Skip SYNC in case the device is internal error state. - * Besides a device error, this also happens when we're - * in fast teardown - */ - if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) - return 0; - - MLX5_SET(sync_steering_in, in, opcode, MLX5_CMD_OP_SYNC_STEERING); - - return mlx5_cmd_exec_in(mdev, sync_steering, in); -} - -int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id, - u32 group_id, - u32 modify_header_id, - u16 vport) -{ - u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {}; - void *in_flow_context; - unsigned int inlen; - void *in_dests; - u32 *in; - int err; - - inlen = MLX5_ST_SZ_BYTES(set_fte_in) + - 1 * MLX5_ST_SZ_BYTES(dest_format_struct); /* One destination only */ - - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); - MLX5_SET(set_fte_in, in, table_type, table_type); - MLX5_SET(set_fte_in, in, table_id, table_id); - - in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); - MLX5_SET(flow_context, in_flow_context, group_id, group_id); - MLX5_SET(flow_context, in_flow_context, modify_header_id, modify_header_id); - MLX5_SET(flow_context, in_flow_context, destination_list_size, 1); - MLX5_SET(flow_context, in_flow_context, action, - MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | - MLX5_FLOW_CONTEXT_ACTION_MOD_HDR); - - in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); - MLX5_SET(dest_format_struct, in_dests, destination_type, - MLX5_IFC_FLOW_DESTINATION_TYPE_VPORT); - MLX5_SET(dest_format_struct, in_dests, destination_id, vport); - - err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); - kvfree(in); - - return err; -} - -int mlx5dr_cmd_del_flow_table_entry(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id) -{ - u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {}; - - MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); - MLX5_SET(delete_fte_in, in, table_type, table_type); - MLX5_SET(delete_fte_in, in, table_id, table_id); - - return mlx5_cmd_exec_in(mdev, delete_fte, in); -} - -int mlx5dr_cmd_alloc_modify_header(struct mlx5_core_dev *mdev, - u32 table_type, - u8 num_of_actions, - u64 *actions, - u32 *modify_header_id) -{ - u32 out[MLX5_ST_SZ_DW(alloc_modify_header_context_out)] = {}; - void *p_actions; - u32 inlen; - u32 *in; - int err; - - inlen = MLX5_ST_SZ_BYTES(alloc_modify_header_context_in) + - num_of_actions * sizeof(u64); - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(alloc_modify_header_context_in, in, opcode, - MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT); - MLX5_SET(alloc_modify_header_context_in, in, table_type, table_type); - MLX5_SET(alloc_modify_header_context_in, in, num_of_actions, num_of_actions); - p_actions = MLX5_ADDR_OF(alloc_modify_header_context_in, in, actions); - memcpy(p_actions, actions, num_of_actions * sizeof(u64)); - - err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); - if (err) - goto out; - - *modify_header_id = MLX5_GET(alloc_modify_header_context_out, out, - modify_header_id); -out: - kvfree(in); - return err; -} - -int mlx5dr_cmd_dealloc_modify_header(struct mlx5_core_dev *mdev, - u32 modify_header_id) -{ - u32 in[MLX5_ST_SZ_DW(dealloc_modify_header_context_in)] = {}; - - MLX5_SET(dealloc_modify_header_context_in, in, opcode, - MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT); - MLX5_SET(dealloc_modify_header_context_in, in, modify_header_id, - modify_header_id); - - return mlx5_cmd_exec_in(mdev, dealloc_modify_header_context, in); -} - -int mlx5dr_cmd_create_empty_flow_group(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id, - u32 *group_id) -{ - u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {}; - int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); - u32 *in; - int err; - - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP); - MLX5_SET(create_flow_group_in, in, table_type, table_type); - MLX5_SET(create_flow_group_in, in, table_id, table_id); - - err = mlx5_cmd_exec_inout(mdev, create_flow_group, in, out); - if (err) - goto out; - - *group_id = MLX5_GET(create_flow_group_out, out, group_id); - -out: - kvfree(in); - return err; -} - -int mlx5dr_cmd_destroy_flow_group(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id, - u32 group_id) -{ - u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {}; - - MLX5_SET(destroy_flow_group_in, in, opcode, - MLX5_CMD_OP_DESTROY_FLOW_GROUP); - MLX5_SET(destroy_flow_group_in, in, table_type, table_type); - MLX5_SET(destroy_flow_group_in, in, table_id, table_id); - MLX5_SET(destroy_flow_group_in, in, group_id, group_id); - - return mlx5_cmd_exec_in(mdev, destroy_flow_group, in); -} - -int mlx5dr_cmd_create_flow_table(struct mlx5_core_dev *mdev, - struct mlx5dr_cmd_create_flow_table_attr *attr, - u64 *fdb_rx_icm_addr, - u32 *table_id) -{ - u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {}; - u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {}; - void *ft_mdev; - int err; - - MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE); - MLX5_SET(create_flow_table_in, in, table_type, attr->table_type); - MLX5_SET(create_flow_table_in, in, uid, attr->uid); - - ft_mdev = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context); - MLX5_SET(flow_table_context, ft_mdev, termination_table, attr->term_tbl); - MLX5_SET(flow_table_context, ft_mdev, sw_owner, attr->sw_owner); - MLX5_SET(flow_table_context, ft_mdev, level, attr->level); - - if (attr->sw_owner) { - /* icm_addr_0 used for FDB RX / NIC TX / NIC_RX - * icm_addr_1 used for FDB TX - */ - if (attr->table_type == MLX5_FLOW_TABLE_TYPE_NIC_RX) { - MLX5_SET64(flow_table_context, ft_mdev, - sws.sw_owner_icm_root_0, attr->icm_addr_rx); - } else if (attr->table_type == MLX5_FLOW_TABLE_TYPE_NIC_TX) { - MLX5_SET64(flow_table_context, ft_mdev, - sws.sw_owner_icm_root_0, attr->icm_addr_tx); - } else if (attr->table_type == MLX5_FLOW_TABLE_TYPE_FDB) { - MLX5_SET64(flow_table_context, ft_mdev, - sws.sw_owner_icm_root_0, attr->icm_addr_rx); - MLX5_SET64(flow_table_context, ft_mdev, - sws.sw_owner_icm_root_1, attr->icm_addr_tx); - } - } - - MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en, - attr->decap_en); - MLX5_SET(create_flow_table_in, in, flow_table_context.reformat_en, - attr->reformat_en); - - err = mlx5_cmd_exec_inout(mdev, create_flow_table, in, out); - if (err) - return err; - - *table_id = MLX5_GET(create_flow_table_out, out, table_id); - if (!attr->sw_owner && attr->table_type == MLX5_FLOW_TABLE_TYPE_FDB && - fdb_rx_icm_addr) - *fdb_rx_icm_addr = - (u64)MLX5_GET(create_flow_table_out, out, icm_address_31_0) | - (u64)MLX5_GET(create_flow_table_out, out, icm_address_39_32) << 32 | - (u64)MLX5_GET(create_flow_table_out, out, icm_address_63_40) << 40; - - return 0; -} - -int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev, - u32 table_id, - u32 table_type) -{ - u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {}; - - MLX5_SET(destroy_flow_table_in, in, opcode, - MLX5_CMD_OP_DESTROY_FLOW_TABLE); - MLX5_SET(destroy_flow_table_in, in, table_type, table_type); - MLX5_SET(destroy_flow_table_in, in, table_id, table_id); - - return mlx5_cmd_exec_in(mdev, destroy_flow_table, in); -} - -int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev, - enum mlx5_reformat_ctx_type rt, - u8 reformat_param_0, - u8 reformat_param_1, - size_t reformat_size, - void *reformat_data, - u32 *reformat_id) -{ - u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)] = {}; - size_t inlen, cmd_data_sz, cmd_total_sz; - void *prctx; - void *pdata; - void *in; - int err; - - cmd_total_sz = MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in); - cmd_data_sz = MLX5_FLD_SZ_BYTES(alloc_packet_reformat_context_in, - packet_reformat_context.reformat_data); - inlen = ALIGN(cmd_total_sz + reformat_size - cmd_data_sz, 4); - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(alloc_packet_reformat_context_in, in, opcode, - MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT); - - prctx = MLX5_ADDR_OF(alloc_packet_reformat_context_in, in, packet_reformat_context); - pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data); - - MLX5_SET(packet_reformat_context_in, prctx, reformat_type, rt); - MLX5_SET(packet_reformat_context_in, prctx, reformat_param_0, reformat_param_0); - MLX5_SET(packet_reformat_context_in, prctx, reformat_param_1, reformat_param_1); - MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, reformat_size); - if (reformat_data && reformat_size) - memcpy(pdata, reformat_data, reformat_size); - - err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); - if (err) - goto err_free_in; - - *reformat_id = MLX5_GET(alloc_packet_reformat_context_out, out, packet_reformat_id); - -err_free_in: - kvfree(in); - return err; -} - -void mlx5dr_cmd_destroy_reformat_ctx(struct mlx5_core_dev *mdev, - u32 reformat_id) -{ - u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)] = {}; - - MLX5_SET(dealloc_packet_reformat_context_in, in, opcode, - MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT); - MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id, - reformat_id); - - mlx5_cmd_exec_in(mdev, dealloc_packet_reformat_context, in); -} - -static void dr_cmd_set_definer_format(void *ptr, u16 format_id, - u8 *dw_selectors, - u8 *byte_selectors) -{ - if (format_id != MLX5_IFC_DEFINER_FORMAT_ID_SELECT) - return; - - MLX5_SET(match_definer, ptr, format_select_dw0, dw_selectors[0]); - MLX5_SET(match_definer, ptr, format_select_dw1, dw_selectors[1]); - MLX5_SET(match_definer, ptr, format_select_dw2, dw_selectors[2]); - MLX5_SET(match_definer, ptr, format_select_dw3, dw_selectors[3]); - MLX5_SET(match_definer, ptr, format_select_dw4, dw_selectors[4]); - MLX5_SET(match_definer, ptr, format_select_dw5, dw_selectors[5]); - MLX5_SET(match_definer, ptr, format_select_dw6, dw_selectors[6]); - MLX5_SET(match_definer, ptr, format_select_dw7, dw_selectors[7]); - MLX5_SET(match_definer, ptr, format_select_dw8, dw_selectors[8]); - - MLX5_SET(match_definer, ptr, format_select_byte0, byte_selectors[0]); - MLX5_SET(match_definer, ptr, format_select_byte1, byte_selectors[1]); - MLX5_SET(match_definer, ptr, format_select_byte2, byte_selectors[2]); - MLX5_SET(match_definer, ptr, format_select_byte3, byte_selectors[3]); - MLX5_SET(match_definer, ptr, format_select_byte4, byte_selectors[4]); - MLX5_SET(match_definer, ptr, format_select_byte5, byte_selectors[5]); - MLX5_SET(match_definer, ptr, format_select_byte6, byte_selectors[6]); - MLX5_SET(match_definer, ptr, format_select_byte7, byte_selectors[7]); -} - -int mlx5dr_cmd_create_definer(struct mlx5_core_dev *mdev, - u16 format_id, - u8 *dw_selectors, - u8 *byte_selectors, - u8 *match_mask, - u32 *definer_id) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; - u32 in[MLX5_ST_SZ_DW(create_match_definer_in)] = {}; - void *ptr; - int err; - - ptr = MLX5_ADDR_OF(create_match_definer_in, in, - general_obj_in_cmd_hdr); - MLX5_SET(general_obj_in_cmd_hdr, ptr, opcode, - MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, ptr, obj_type, - MLX5_OBJ_TYPE_MATCH_DEFINER); - - ptr = MLX5_ADDR_OF(create_match_definer_in, in, obj_context); - MLX5_SET(match_definer, ptr, format_id, format_id); - - dr_cmd_set_definer_format(ptr, format_id, - dw_selectors, byte_selectors); - - ptr = MLX5_ADDR_OF(match_definer, ptr, match_mask); - memcpy(ptr, match_mask, MLX5_FLD_SZ_BYTES(match_definer, match_mask)); - - err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (err) - return err; - - *definer_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); - - return 0; -} - -void -mlx5dr_cmd_destroy_definer(struct mlx5_core_dev *mdev, u32 definer_id) -{ - u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; - - MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_MATCH_DEFINER); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, definer_id); - - mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); -} - -int mlx5dr_cmd_query_gid(struct mlx5_core_dev *mdev, u8 vhca_port_num, - u16 index, struct mlx5dr_cmd_gid_attr *attr) -{ - u32 out[MLX5_ST_SZ_DW(query_roce_address_out)] = {}; - u32 in[MLX5_ST_SZ_DW(query_roce_address_in)] = {}; - int err; - - MLX5_SET(query_roce_address_in, in, opcode, - MLX5_CMD_OP_QUERY_ROCE_ADDRESS); - - MLX5_SET(query_roce_address_in, in, roce_address_index, index); - MLX5_SET(query_roce_address_in, in, vhca_port_num, vhca_port_num); - - err = mlx5_cmd_exec_inout(mdev, query_roce_address, in, out); - if (err) - return err; - - memcpy(&attr->gid, - MLX5_ADDR_OF(query_roce_address_out, - out, roce_address.source_l3_address), - sizeof(attr->gid)); - memcpy(attr->mac, - MLX5_ADDR_OF(query_roce_address_out, out, - roce_address.source_mac_47_32), - sizeof(attr->mac)); - - if (MLX5_GET(query_roce_address_out, out, - roce_address.roce_version) == MLX5_ROCE_VERSION_2) - attr->roce_ver = MLX5_ROCE_VERSION_2; - else - attr->roce_ver = MLX5_ROCE_VERSION_1; - - return 0; -} - -int mlx5dr_cmd_create_modify_header_arg(struct mlx5_core_dev *dev, - u16 log_obj_range, u32 pd, - u32 *obj_id) -{ - u32 in[MLX5_ST_SZ_DW(create_modify_header_arg_in)] = {}; - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; - void *attr; - int ret; - - attr = MLX5_ADDR_OF(create_modify_header_arg_in, in, hdr); - MLX5_SET(general_obj_in_cmd_hdr, attr, opcode, - MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, attr, obj_type, - MLX5_OBJ_TYPE_HEADER_MODIFY_ARGUMENT); - MLX5_SET(general_obj_in_cmd_hdr, attr, - op_param.create.log_obj_range, log_obj_range); - - attr = MLX5_ADDR_OF(create_modify_header_arg_in, in, arg); - MLX5_SET(modify_header_arg, attr, access_pd, pd); - - ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); - if (ret) - return ret; - - *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); - return 0; -} - -void mlx5dr_cmd_destroy_modify_header_arg(struct mlx5_core_dev *dev, - u32 obj_id) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; - u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; - - MLX5_SET(general_obj_in_cmd_hdr, in, opcode, - MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, - MLX5_OBJ_TYPE_HEADER_MODIFY_ARGUMENT); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id); - - mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); -} - -static int mlx5dr_cmd_set_extended_dest(struct mlx5_core_dev *dev, - struct mlx5dr_cmd_fte_info *fte, - bool *extended_dest) -{ - int fw_log_max_fdb_encap_uplink = MLX5_CAP_ESW(dev, log_max_fdb_encap_uplink); - int num_fwd_destinations = 0; - int num_encap = 0; - int i; - - *extended_dest = false; - if (!(fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST)) - return 0; - for (i = 0; i < fte->dests_size; i++) { - if (fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_COUNTER || - fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_NONE) - continue; - if ((fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_VPORT || - fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_UPLINK) && - fte->dest_arr[i].vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID) - num_encap++; - num_fwd_destinations++; - } - - if (num_fwd_destinations > 1 && num_encap > 0) - *extended_dest = true; - - if (*extended_dest && !fw_log_max_fdb_encap_uplink) { - mlx5_core_warn(dev, "FW does not support extended destination"); - return -EOPNOTSUPP; - } - if (num_encap > (1 << fw_log_max_fdb_encap_uplink)) { - mlx5_core_warn(dev, "FW does not support more than %d encaps", - 1 << fw_log_max_fdb_encap_uplink); - return -EOPNOTSUPP; - } - - return 0; -} - -int mlx5dr_cmd_set_fte(struct mlx5_core_dev *dev, - int opmod, int modify_mask, - struct mlx5dr_cmd_ft_info *ft, - u32 group_id, - struct mlx5dr_cmd_fte_info *fte) -{ - u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {}; - void *in_flow_context, *vlan; - bool extended_dest = false; - void *in_match_value; - unsigned int inlen; - int dst_cnt_size; - void *in_dests; - u32 *in; - int err; - int i; - - if (mlx5dr_cmd_set_extended_dest(dev, fte, &extended_dest)) - return -EOPNOTSUPP; - - if (!extended_dest) - dst_cnt_size = MLX5_ST_SZ_BYTES(dest_format_struct); - else - dst_cnt_size = MLX5_ST_SZ_BYTES(extended_dest_format); - - inlen = MLX5_ST_SZ_BYTES(set_fte_in) + fte->dests_size * dst_cnt_size; - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); - MLX5_SET(set_fte_in, in, op_mod, opmod); - MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask); - MLX5_SET(set_fte_in, in, table_type, ft->type); - MLX5_SET(set_fte_in, in, table_id, ft->id); - MLX5_SET(set_fte_in, in, flow_index, fte->index); - MLX5_SET(set_fte_in, in, ignore_flow_level, fte->ignore_flow_level); - if (ft->vport) { - MLX5_SET(set_fte_in, in, vport_number, ft->vport); - MLX5_SET(set_fte_in, in, other_vport, 1); - } - - in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); - MLX5_SET(flow_context, in_flow_context, group_id, group_id); - - MLX5_SET(flow_context, in_flow_context, flow_tag, - fte->flow_context.flow_tag); - MLX5_SET(flow_context, in_flow_context, flow_source, - fte->flow_context.flow_source); - - MLX5_SET(flow_context, in_flow_context, extended_destination, - extended_dest); - if (extended_dest) { - u32 action; - - action = fte->action.action & - ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; - MLX5_SET(flow_context, in_flow_context, action, action); - } else { - MLX5_SET(flow_context, in_flow_context, action, - fte->action.action); - if (fte->action.pkt_reformat) - MLX5_SET(flow_context, in_flow_context, packet_reformat_id, - fte->action.pkt_reformat->id); - } - if (fte->action.modify_hdr) - MLX5_SET(flow_context, in_flow_context, modify_header_id, - fte->action.modify_hdr->id); - - vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan); - - MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[0].ethtype); - MLX5_SET(vlan, vlan, vid, fte->action.vlan[0].vid); - MLX5_SET(vlan, vlan, prio, fte->action.vlan[0].prio); - - vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan_2); - - MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[1].ethtype); - MLX5_SET(vlan, vlan, vid, fte->action.vlan[1].vid); - MLX5_SET(vlan, vlan, prio, fte->action.vlan[1].prio); - - in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context, - match_value); - memcpy(in_match_value, fte->val, sizeof(u32) * MLX5_ST_SZ_DW_MATCH_PARAM); - - in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); - if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { - int list_size = 0; - - for (i = 0; i < fte->dests_size; i++) { - enum mlx5_flow_destination_type type = fte->dest_arr[i].type; - enum mlx5_ifc_flow_destination_type ifc_type; - unsigned int id; - - if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) - continue; - - switch (type) { - case MLX5_FLOW_DESTINATION_TYPE_NONE: - continue; - case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: - id = fte->dest_arr[i].ft_num; - ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_TABLE; - break; - case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: - id = fte->dest_arr[i].ft_id; - ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_TABLE; - - break; - case MLX5_FLOW_DESTINATION_TYPE_UPLINK: - case MLX5_FLOW_DESTINATION_TYPE_VPORT: - if (type == MLX5_FLOW_DESTINATION_TYPE_VPORT) { - id = fte->dest_arr[i].vport.num; - MLX5_SET(dest_format_struct, in_dests, - destination_eswitch_owner_vhca_id_valid, - !!(fte->dest_arr[i].vport.flags & - MLX5_FLOW_DEST_VPORT_VHCA_ID)); - ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_VPORT; - } else { - id = 0; - ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_UPLINK; - MLX5_SET(dest_format_struct, in_dests, - destination_eswitch_owner_vhca_id_valid, 1); - } - MLX5_SET(dest_format_struct, in_dests, - destination_eswitch_owner_vhca_id, - fte->dest_arr[i].vport.vhca_id); - if (extended_dest && (fte->dest_arr[i].vport.flags & - MLX5_FLOW_DEST_VPORT_REFORMAT_ID)) { - MLX5_SET(dest_format_struct, in_dests, - packet_reformat, - !!(fte->dest_arr[i].vport.flags & - MLX5_FLOW_DEST_VPORT_REFORMAT_ID)); - MLX5_SET(extended_dest_format, in_dests, - packet_reformat_id, - fte->dest_arr[i].vport.reformat_id); - } - break; - case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER: - id = fte->dest_arr[i].sampler_id; - ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_SAMPLER; - break; - default: - id = fte->dest_arr[i].tir_num; - ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_TIR; - } - - MLX5_SET(dest_format_struct, in_dests, destination_type, - ifc_type); - MLX5_SET(dest_format_struct, in_dests, destination_id, id); - in_dests += dst_cnt_size; - list_size++; - } - - MLX5_SET(flow_context, in_flow_context, destination_list_size, - list_size); - } - - if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { - int max_list_size = BIT(MLX5_CAP_FLOWTABLE_TYPE(dev, - log_max_flow_counter, - ft->type)); - int list_size = 0; - - for (i = 0; i < fte->dests_size; i++) { - if (fte->dest_arr[i].type != - MLX5_FLOW_DESTINATION_TYPE_COUNTER) - continue; - - MLX5_SET(flow_counter_list, in_dests, flow_counter_id, - fte->dest_arr[i].counter_id); - in_dests += dst_cnt_size; - list_size++; - } - if (list_size > max_list_size) { - err = -EINVAL; - goto err_out; - } - - MLX5_SET(flow_context, in_flow_context, flow_counter_list_size, - list_size); - } - - err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); -err_out: - kvfree(in); - return err; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c deleted file mode 100644 index 030a5776c93740..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.c +++ /dev/null @@ -1,1186 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - -#include -#include -#include -#include -#include "dr_types.h" - -#define DR_DBG_PTR_TO_ID(p) ((u64)(uintptr_t)(p) & 0xFFFFFFFFULL) - -enum dr_dump_rec_type { - DR_DUMP_REC_TYPE_DOMAIN = 3000, - DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER = 3001, - DR_DUMP_REC_TYPE_DOMAIN_INFO_DEV_ATTR = 3002, - DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT = 3003, - DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS = 3004, - DR_DUMP_REC_TYPE_DOMAIN_SEND_RING = 3005, - - DR_DUMP_REC_TYPE_TABLE = 3100, - DR_DUMP_REC_TYPE_TABLE_RX = 3101, - DR_DUMP_REC_TYPE_TABLE_TX = 3102, - - DR_DUMP_REC_TYPE_MATCHER = 3200, - DR_DUMP_REC_TYPE_MATCHER_MASK_DEPRECATED = 3201, - DR_DUMP_REC_TYPE_MATCHER_RX = 3202, - DR_DUMP_REC_TYPE_MATCHER_TX = 3203, - DR_DUMP_REC_TYPE_MATCHER_BUILDER = 3204, - DR_DUMP_REC_TYPE_MATCHER_MASK = 3205, - - DR_DUMP_REC_TYPE_RULE = 3300, - DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 = 3301, - DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0 = 3302, - DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 = 3303, - DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1 = 3304, - - DR_DUMP_REC_TYPE_ACTION_ENCAP_L2 = 3400, - DR_DUMP_REC_TYPE_ACTION_ENCAP_L3 = 3401, - DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR = 3402, - DR_DUMP_REC_TYPE_ACTION_DROP = 3403, - DR_DUMP_REC_TYPE_ACTION_QP = 3404, - DR_DUMP_REC_TYPE_ACTION_FT = 3405, - DR_DUMP_REC_TYPE_ACTION_CTR = 3406, - DR_DUMP_REC_TYPE_ACTION_TAG = 3407, - DR_DUMP_REC_TYPE_ACTION_VPORT = 3408, - DR_DUMP_REC_TYPE_ACTION_DECAP_L2 = 3409, - DR_DUMP_REC_TYPE_ACTION_DECAP_L3 = 3410, - DR_DUMP_REC_TYPE_ACTION_DEVX_TIR = 3411, - DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN = 3412, - DR_DUMP_REC_TYPE_ACTION_POP_VLAN = 3413, - DR_DUMP_REC_TYPE_ACTION_SAMPLER = 3415, - DR_DUMP_REC_TYPE_ACTION_INSERT_HDR = 3420, - DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR = 3421, - DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE = 3425, -}; - -static struct mlx5dr_dbg_dump_buff * -mlx5dr_dbg_dump_data_init_new_buff(struct mlx5dr_dbg_dump_data *dump_data) -{ - struct mlx5dr_dbg_dump_buff *new_buff; - - new_buff = kzalloc(sizeof(*new_buff), GFP_KERNEL); - if (!new_buff) - return NULL; - - new_buff->buff = kvzalloc(MLX5DR_DEBUG_DUMP_BUFF_SIZE, GFP_KERNEL); - if (!new_buff->buff) { - kfree(new_buff); - return NULL; - } - - INIT_LIST_HEAD(&new_buff->node); - list_add_tail(&new_buff->node, &dump_data->buff_list); - - return new_buff; -} - -static struct mlx5dr_dbg_dump_data * -mlx5dr_dbg_create_dump_data(void) -{ - struct mlx5dr_dbg_dump_data *dump_data; - - dump_data = kzalloc(sizeof(*dump_data), GFP_KERNEL); - if (!dump_data) - return NULL; - - INIT_LIST_HEAD(&dump_data->buff_list); - - if (!mlx5dr_dbg_dump_data_init_new_buff(dump_data)) { - kfree(dump_data); - return NULL; - } - - return dump_data; -} - -static void -mlx5dr_dbg_destroy_dump_data(struct mlx5dr_dbg_dump_data *dump_data) -{ - struct mlx5dr_dbg_dump_buff *dump_buff, *tmp_buff; - - if (!dump_data) - return; - - list_for_each_entry_safe(dump_buff, tmp_buff, &dump_data->buff_list, node) { - kvfree(dump_buff->buff); - list_del(&dump_buff->node); - kfree(dump_buff); - } - - kfree(dump_data); -} - -static int -mlx5dr_dbg_dump_data_print(struct seq_file *file, char *str, u32 size) -{ - struct mlx5dr_domain *dmn = file->private; - struct mlx5dr_dbg_dump_data *dump_data; - struct mlx5dr_dbg_dump_buff *buff; - u32 buff_capacity, write_size; - int remain_size, ret; - - if (size >= MLX5DR_DEBUG_DUMP_BUFF_SIZE) - return -EINVAL; - - dump_data = dmn->dump_info.dump_data; - buff = list_last_entry(&dump_data->buff_list, - struct mlx5dr_dbg_dump_buff, node); - - buff_capacity = (MLX5DR_DEBUG_DUMP_BUFF_SIZE - 1) - buff->index; - remain_size = buff_capacity - size; - write_size = (remain_size > 0) ? size : buff_capacity; - - if (likely(write_size)) { - ret = snprintf(buff->buff + buff->index, write_size + 1, "%s", str); - if (ret < 0) - return ret; - - buff->index += write_size; - } - - if (remain_size < 0) { - remain_size *= -1; - buff = mlx5dr_dbg_dump_data_init_new_buff(dump_data); - if (!buff) - return -ENOMEM; - - ret = snprintf(buff->buff, remain_size + 1, "%s", str + write_size); - if (ret < 0) - return ret; - - buff->index += remain_size; - } - - return 0; -} - -void mlx5dr_dbg_tbl_add(struct mlx5dr_table *tbl) -{ - mutex_lock(&tbl->dmn->dump_info.dbg_mutex); - list_add_tail(&tbl->dbg_node, &tbl->dmn->dbg_tbl_list); - mutex_unlock(&tbl->dmn->dump_info.dbg_mutex); -} - -void mlx5dr_dbg_tbl_del(struct mlx5dr_table *tbl) -{ - mutex_lock(&tbl->dmn->dump_info.dbg_mutex); - list_del(&tbl->dbg_node); - mutex_unlock(&tbl->dmn->dump_info.dbg_mutex); -} - -void mlx5dr_dbg_rule_add(struct mlx5dr_rule *rule) -{ - struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; - - mutex_lock(&dmn->dump_info.dbg_mutex); - list_add_tail(&rule->dbg_node, &rule->matcher->dbg_rule_list); - mutex_unlock(&dmn->dump_info.dbg_mutex); -} - -void mlx5dr_dbg_rule_del(struct mlx5dr_rule *rule) -{ - struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; - - mutex_lock(&dmn->dump_info.dbg_mutex); - list_del(&rule->dbg_node); - mutex_unlock(&dmn->dump_info.dbg_mutex); -} - -static u64 dr_dump_icm_to_idx(u64 icm_addr) -{ - return (icm_addr >> 6) & 0xffffffff; -} - -#define DR_HEX_SIZE 256 - -static void -dr_dump_hex_print(char hex[DR_HEX_SIZE], char *src, u32 size) -{ - if (WARN_ON_ONCE(DR_HEX_SIZE < 2 * size + 1)) - size = DR_HEX_SIZE / 2 - 1; /* truncate */ - - bin2hex(hex, src, size); - hex[2 * size] = 0; /* NULL-terminate */ -} - -static int -dr_dump_rule_action_mem(struct seq_file *file, char *buff, const u64 rule_id, - struct mlx5dr_rule_action_member *action_mem) -{ - struct mlx5dr_action *action = action_mem->action; - const u64 action_id = DR_DBG_PTR_TO_ID(action); - u64 hit_tbl_ptr, miss_tbl_ptr; - u32 hit_tbl_id, miss_tbl_id; - int ret; - - switch (action->action_type) { - case DR_ACTION_TYP_DROP: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_DROP, action_id, - rule_id); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_FT: - if (action->dest_tbl->is_fw_tbl) - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_FT, action_id, - rule_id, action->dest_tbl->fw_tbl.id, - -1); - else - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_FT, action_id, - rule_id, action->dest_tbl->tbl->table_id, - DR_DBG_PTR_TO_ID(action->dest_tbl->tbl)); - - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_CTR: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_CTR, action_id, rule_id, - action->ctr->ctr_id + action->ctr->offset); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_TAG: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_TAG, action_id, rule_id, - action->flow_tag->flow_tag); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_MODIFY_HDR: - { - struct mlx5dr_ptrn_obj *ptrn = action->rewrite->ptrn; - struct mlx5dr_arg_obj *arg = action->rewrite->arg; - u8 *rewrite_data = action->rewrite->data; - bool ptrn_arg; - int i; - - ptrn_arg = !action->rewrite->single_action_opt && ptrn && arg; - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x,%d,0x%x,0x%x,0x%x", - DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR, action_id, - rule_id, action->rewrite->index, - action->rewrite->single_action_opt, - ptrn_arg ? action->rewrite->num_of_actions : 0, - ptrn_arg ? ptrn->index : 0, - ptrn_arg ? mlx5dr_arg_get_obj_id(arg) : 0); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - if (ptrn_arg) { - for (i = 0; i < action->rewrite->num_of_actions; i++) { - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - ",0x%016llx", - be64_to_cpu(((__be64 *)rewrite_data)[i])); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - } - } - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, "\n"); - if (ret < 0) - return ret; - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - } - case DR_ACTION_TYP_VPORT: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_VPORT, action_id, rule_id, - action->vport->caps->num); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_TNL_L2_TO_L2: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_DECAP_L2, action_id, - rule_id); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_TNL_L3_TO_L2: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_DECAP_L3, action_id, - rule_id, - (action->rewrite->ptrn && action->rewrite->arg) ? - mlx5dr_arg_get_obj_id(action->rewrite->arg) : - action->rewrite->index); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_L2_TO_TNL_L2: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_ENCAP_L2, action_id, - rule_id, action->reformat->id); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_L2_TO_TNL_L3: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_ENCAP_L3, action_id, - rule_id, action->reformat->id); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_POP_VLAN: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_POP_VLAN, action_id, - rule_id); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_PUSH_VLAN: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN, action_id, - rule_id, action->push_vlan->vlan_hdr); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_INSERT_HDR: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_INSERT_HDR, action_id, - rule_id, action->reformat->id, - action->reformat->param_0, - action->reformat->param_1); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_REMOVE_HDR: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR, action_id, - rule_id, action->reformat->id, - action->reformat->param_0, - action->reformat->param_1); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_SAMPLER: - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_ACTION_SAMPLER, action_id, - rule_id, 0, 0, action->sampler->sampler_id, - action->sampler->rx_icm_addr, - action->sampler->tx_icm_addr); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - case DR_ACTION_TYP_RANGE: - if (action->range->hit_tbl_action->dest_tbl->is_fw_tbl) { - hit_tbl_id = action->range->hit_tbl_action->dest_tbl->fw_tbl.id; - hit_tbl_ptr = 0; - } else { - hit_tbl_id = action->range->hit_tbl_action->dest_tbl->tbl->table_id; - hit_tbl_ptr = - DR_DBG_PTR_TO_ID(action->range->hit_tbl_action->dest_tbl->tbl); - } - - if (action->range->miss_tbl_action->dest_tbl->is_fw_tbl) { - miss_tbl_id = action->range->miss_tbl_action->dest_tbl->fw_tbl.id; - miss_tbl_ptr = 0; - } else { - miss_tbl_id = action->range->miss_tbl_action->dest_tbl->tbl->table_id; - miss_tbl_ptr = - DR_DBG_PTR_TO_ID(action->range->miss_tbl_action->dest_tbl->tbl); - } - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x,0x%llx,0x%x,0x%llx,0x%x\n", - DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE, action_id, - rule_id, hit_tbl_id, hit_tbl_ptr, miss_tbl_id, - miss_tbl_ptr, action->range->definer_id); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - break; - default: - return 0; - } - - return 0; -} - -static int -dr_dump_rule_mem(struct seq_file *file, char *buff, struct mlx5dr_ste *ste, - bool is_rx, const u64 rule_id, u8 format_ver) -{ - char hw_ste_dump[DR_HEX_SIZE]; - u32 mem_rec_type; - int ret; - - if (format_ver == MLX5_STEERING_FORMAT_CONNECTX_5) { - mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 : - DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0; - } else { - mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 : - DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1; - } - - dr_dump_hex_print(hw_ste_dump, (char *)mlx5dr_ste_get_hw_ste(ste), - DR_STE_SIZE_REDUCED); - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,%s\n", mem_rec_type, - dr_dump_icm_to_idx(mlx5dr_ste_get_icm_addr(ste)), - rule_id, hw_ste_dump); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - return 0; -} - -static int -dr_dump_rule_rx_tx(struct seq_file *file, char *buff, - struct mlx5dr_rule_rx_tx *rule_rx_tx, - bool is_rx, const u64 rule_id, u8 format_ver) -{ - struct mlx5dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES]; - struct mlx5dr_ste *curr_ste = rule_rx_tx->last_rule_ste; - int ret, i; - - if (mlx5dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i)) - return 0; - - while (i--) { - ret = dr_dump_rule_mem(file, buff, ste_arr[i], is_rx, rule_id, - format_ver); - if (ret < 0) - return ret; - } - - return 0; -} - -static noinline_for_stack int -dr_dump_rule(struct seq_file *file, struct mlx5dr_rule *rule) -{ - struct mlx5dr_rule_action_member *action_mem; - const u64 rule_id = DR_DBG_PTR_TO_ID(rule); - char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; - struct mlx5dr_rule_rx_tx *rx = &rule->rx; - struct mlx5dr_rule_rx_tx *tx = &rule->tx; - u8 format_ver; - int ret; - - format_ver = rule->matcher->tbl->dmn->info.caps.sw_format_ver; - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx\n", DR_DUMP_REC_TYPE_RULE, - rule_id, DR_DBG_PTR_TO_ID(rule->matcher)); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - if (rx->nic_matcher) { - ret = dr_dump_rule_rx_tx(file, buff, rx, true, rule_id, format_ver); - if (ret < 0) - return ret; - } - - if (tx->nic_matcher) { - ret = dr_dump_rule_rx_tx(file, buff, tx, false, rule_id, format_ver); - if (ret < 0) - return ret; - } - - list_for_each_entry(action_mem, &rule->rule_actions_list, list) { - ret = dr_dump_rule_action_mem(file, buff, rule_id, action_mem); - if (ret < 0) - return ret; - } - - return 0; -} - -static int -dr_dump_matcher_mask(struct seq_file *file, char *buff, - struct mlx5dr_match_param *mask, - u8 criteria, const u64 matcher_id) -{ - char dump[DR_HEX_SIZE]; - int ret; - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, "%d,0x%llx,", - DR_DUMP_REC_TYPE_MATCHER_MASK, matcher_id); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - if (criteria & DR_MATCHER_CRITERIA_OUTER) { - dr_dump_hex_print(dump, (char *)&mask->outer, sizeof(mask->outer)); - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%s,", dump); - } else { - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); - } - - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - if (criteria & DR_MATCHER_CRITERIA_INNER) { - dr_dump_hex_print(dump, (char *)&mask->inner, sizeof(mask->inner)); - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%s,", dump); - } else { - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); - } - - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - if (criteria & DR_MATCHER_CRITERIA_MISC) { - dr_dump_hex_print(dump, (char *)&mask->misc, sizeof(mask->misc)); - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%s,", dump); - } else { - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); - } - - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - if (criteria & DR_MATCHER_CRITERIA_MISC2) { - dr_dump_hex_print(dump, (char *)&mask->misc2, sizeof(mask->misc2)); - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%s,", dump); - } else { - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); - } - - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - if (criteria & DR_MATCHER_CRITERIA_MISC3) { - dr_dump_hex_print(dump, (char *)&mask->misc3, sizeof(mask->misc3)); - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%s\n", dump); - } else { - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ",\n"); - } - - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - return 0; -} - -static int -dr_dump_matcher_builder(struct seq_file *file, char *buff, - struct mlx5dr_ste_build *builder, - u32 index, bool is_rx, const u64 matcher_id) -{ - int ret; - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,%d,%d,0x%x\n", - DR_DUMP_REC_TYPE_MATCHER_BUILDER, matcher_id, index, - is_rx, builder->lu_type); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - return 0; -} - -static int -dr_dump_matcher_rx_tx(struct seq_file *file, char *buff, bool is_rx, - struct mlx5dr_matcher_rx_tx *matcher_rx_tx, - const u64 matcher_id) -{ - enum dr_dump_rec_type rec_type; - u64 s_icm_addr, e_icm_addr; - int i, ret; - - rec_type = is_rx ? DR_DUMP_REC_TYPE_MATCHER_RX : - DR_DUMP_REC_TYPE_MATCHER_TX; - - s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->s_htbl->chunk); - e_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->e_anchor->chunk); - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,%d,0x%llx,0x%llx\n", - rec_type, DR_DBG_PTR_TO_ID(matcher_rx_tx), - matcher_id, matcher_rx_tx->num_of_builders, - dr_dump_icm_to_idx(s_icm_addr), - dr_dump_icm_to_idx(e_icm_addr)); - - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - for (i = 0; i < matcher_rx_tx->num_of_builders; i++) { - ret = dr_dump_matcher_builder(file, buff, - &matcher_rx_tx->ste_builder[i], - i, is_rx, matcher_id); - if (ret < 0) - return ret; - } - - return 0; -} - -static noinline_for_stack int -dr_dump_matcher(struct seq_file *file, struct mlx5dr_matcher *matcher) -{ - struct mlx5dr_matcher_rx_tx *rx = &matcher->rx; - struct mlx5dr_matcher_rx_tx *tx = &matcher->tx; - char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; - u64 matcher_id; - int ret; - - matcher_id = DR_DBG_PTR_TO_ID(matcher); - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,%d\n", DR_DUMP_REC_TYPE_MATCHER, - matcher_id, DR_DBG_PTR_TO_ID(matcher->tbl), - matcher->prio); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - ret = dr_dump_matcher_mask(file, buff, &matcher->mask, - matcher->match_criteria, matcher_id); - if (ret < 0) - return ret; - - if (rx->nic_tbl) { - ret = dr_dump_matcher_rx_tx(file, buff, true, rx, matcher_id); - if (ret < 0) - return ret; - } - - if (tx->nic_tbl) { - ret = dr_dump_matcher_rx_tx(file, buff, false, tx, matcher_id); - if (ret < 0) - return ret; - } - - return 0; -} - -static int -dr_dump_matcher_all(struct seq_file *file, struct mlx5dr_matcher *matcher) -{ - struct mlx5dr_rule *rule; - int ret; - - ret = dr_dump_matcher(file, matcher); - if (ret < 0) - return ret; - - list_for_each_entry(rule, &matcher->dbg_rule_list, dbg_node) { - ret = dr_dump_rule(file, rule); - if (ret < 0) - return ret; - } - - return 0; -} - -static int -dr_dump_table_rx_tx(struct seq_file *file, char *buff, bool is_rx, - struct mlx5dr_table_rx_tx *table_rx_tx, - const u64 table_id) -{ - enum dr_dump_rec_type rec_type; - u64 s_icm_addr; - int ret; - - rec_type = is_rx ? DR_DUMP_REC_TYPE_TABLE_RX : - DR_DUMP_REC_TYPE_TABLE_TX; - - s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(table_rx_tx->s_anchor->chunk); - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx\n", rec_type, table_id, - dr_dump_icm_to_idx(s_icm_addr)); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - return 0; -} - -static noinline_for_stack int -dr_dump_table(struct seq_file *file, struct mlx5dr_table *table) -{ - struct mlx5dr_table_rx_tx *rx = &table->rx; - struct mlx5dr_table_rx_tx *tx = &table->tx; - char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; - int ret; - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,%d,%d\n", DR_DUMP_REC_TYPE_TABLE, - DR_DBG_PTR_TO_ID(table), DR_DBG_PTR_TO_ID(table->dmn), - table->table_type, table->level); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - if (rx->nic_dmn) { - ret = dr_dump_table_rx_tx(file, buff, true, rx, - DR_DBG_PTR_TO_ID(table)); - if (ret < 0) - return ret; - } - - if (tx->nic_dmn) { - ret = dr_dump_table_rx_tx(file, buff, false, tx, - DR_DBG_PTR_TO_ID(table)); - if (ret < 0) - return ret; - } - return 0; -} - -static int dr_dump_table_all(struct seq_file *file, struct mlx5dr_table *tbl) -{ - struct mlx5dr_matcher *matcher; - int ret; - - ret = dr_dump_table(file, tbl); - if (ret < 0) - return ret; - - list_for_each_entry(matcher, &tbl->matcher_list, list_node) { - ret = dr_dump_matcher_all(file, matcher); - if (ret < 0) - return ret; - } - return 0; -} - -static int -dr_dump_send_ring(struct seq_file *file, char *buff, - struct mlx5dr_send_ring *ring, - const u64 domain_id) -{ - int ret; - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%llx,0x%x,0x%x\n", - DR_DUMP_REC_TYPE_DOMAIN_SEND_RING, - DR_DBG_PTR_TO_ID(ring), domain_id, - ring->cq->mcq.cqn, ring->qp->qpn); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - return 0; -} - -static int -dr_dump_domain_info_flex_parser(struct seq_file *file, - char *buff, - const char *flex_parser_name, - const u8 flex_parser_value, - const u64 domain_id) -{ - int ret; - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,%s,0x%x\n", - DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER, domain_id, - flex_parser_name, flex_parser_value); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - return 0; -} - -static int -dr_dump_domain_info_caps(struct seq_file *file, char *buff, - struct mlx5dr_cmd_caps *caps, - const u64 domain_id) -{ - struct mlx5dr_cmd_vport_cap *vport_caps; - unsigned long i, vports_num; - int ret; - - xa_for_each(&caps->vports.vports_caps_xa, vports_num, vport_caps) - ; /* count the number of vports in xarray */ - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,0x%x,0x%llx,0x%llx,0x%x,%lu,%d\n", - DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS, domain_id, caps->gvmi, - caps->nic_rx_drop_address, caps->nic_tx_drop_address, - caps->flex_protocols, vports_num, caps->eswitch_manager); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - xa_for_each(&caps->vports.vports_caps_xa, i, vport_caps) { - vport_caps = xa_load(&caps->vports.vports_caps_xa, i); - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,%lu,0x%x,0x%llx,0x%llx\n", - DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT, - domain_id, i, vport_caps->vport_gvmi, - vport_caps->icm_address_rx, - vport_caps->icm_address_tx); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - } - return 0; -} - -static int -dr_dump_domain_info(struct seq_file *file, char *buff, - struct mlx5dr_domain_info *info, - const u64 domain_id) -{ - int ret; - - ret = dr_dump_domain_info_caps(file, buff, &info->caps, domain_id); - if (ret < 0) - return ret; - - ret = dr_dump_domain_info_flex_parser(file, buff, "icmp_dw0", - info->caps.flex_parser_id_icmp_dw0, - domain_id); - if (ret < 0) - return ret; - - ret = dr_dump_domain_info_flex_parser(file, buff, "icmp_dw1", - info->caps.flex_parser_id_icmp_dw1, - domain_id); - if (ret < 0) - return ret; - - ret = dr_dump_domain_info_flex_parser(file, buff, "icmpv6_dw0", - info->caps.flex_parser_id_icmpv6_dw0, - domain_id); - if (ret < 0) - return ret; - - ret = dr_dump_domain_info_flex_parser(file, buff, "icmpv6_dw1", - info->caps.flex_parser_id_icmpv6_dw1, - domain_id); - if (ret < 0) - return ret; - - return 0; -} - -static noinline_for_stack int -dr_dump_domain(struct seq_file *file, struct mlx5dr_domain *dmn) -{ - char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; - u64 domain_id = DR_DBG_PTR_TO_ID(dmn); - int ret; - - ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, - "%d,0x%llx,%d,0%x,%d,%u.%u.%u,%s,%d,%u,%u,%u\n", - DR_DUMP_REC_TYPE_DOMAIN, - domain_id, dmn->type, dmn->info.caps.gvmi, - dmn->info.supp_sw_steering, - /* package version */ - LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL, - LINUX_VERSION_SUBLEVEL, - pci_name(dmn->mdev->pdev), - 0, /* domain flags */ - dmn->num_buddies[DR_ICM_TYPE_STE], - dmn->num_buddies[DR_ICM_TYPE_MODIFY_ACTION], - dmn->num_buddies[DR_ICM_TYPE_MODIFY_HDR_PTRN]); - if (ret < 0) - return ret; - - ret = mlx5dr_dbg_dump_data_print(file, buff, ret); - if (ret) - return ret; - - ret = dr_dump_domain_info(file, buff, &dmn->info, domain_id); - if (ret < 0) - return ret; - - if (dmn->info.supp_sw_steering) { - ret = dr_dump_send_ring(file, buff, dmn->send_ring, domain_id); - if (ret < 0) - return ret; - } - - return 0; -} - -static int dr_dump_domain_all(struct seq_file *file, struct mlx5dr_domain *dmn) -{ - struct mlx5dr_table *tbl; - int ret; - - mutex_lock(&dmn->dump_info.dbg_mutex); - mlx5dr_domain_lock(dmn); - - ret = dr_dump_domain(file, dmn); - if (ret < 0) - goto unlock_mutex; - - list_for_each_entry(tbl, &dmn->dbg_tbl_list, dbg_node) { - ret = dr_dump_table_all(file, tbl); - if (ret < 0) - break; - } - -unlock_mutex: - mlx5dr_domain_unlock(dmn); - mutex_unlock(&dmn->dump_info.dbg_mutex); - return ret; -} - -static void * -dr_dump_start(struct seq_file *file, loff_t *pos) -{ - struct mlx5dr_domain *dmn = file->private; - struct mlx5dr_dbg_dump_data *dump_data; - - if (atomic_read(&dmn->dump_info.state) != MLX5DR_DEBUG_DUMP_STATE_FREE) { - mlx5_core_warn(dmn->mdev, "Dump already in progress\n"); - return ERR_PTR(-EBUSY); - } - - atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_IN_PROGRESS); - dump_data = dmn->dump_info.dump_data; - - if (dump_data) { - return seq_list_start(&dump_data->buff_list, *pos); - } else if (*pos == 0) { - dump_data = mlx5dr_dbg_create_dump_data(); - if (!dump_data) - goto exit; - - dmn->dump_info.dump_data = dump_data; - if (dr_dump_domain_all(file, dmn)) { - mlx5dr_dbg_destroy_dump_data(dump_data); - dmn->dump_info.dump_data = NULL; - goto exit; - } - - return seq_list_start(&dump_data->buff_list, *pos); - } - -exit: - atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE); - return NULL; -} - -static void * -dr_dump_next(struct seq_file *file, void *v, loff_t *pos) -{ - struct mlx5dr_domain *dmn = file->private; - struct mlx5dr_dbg_dump_data *dump_data; - - dump_data = dmn->dump_info.dump_data; - - return seq_list_next(v, &dump_data->buff_list, pos); -} - -static void -dr_dump_stop(struct seq_file *file, void *v) -{ - struct mlx5dr_domain *dmn = file->private; - struct mlx5dr_dbg_dump_data *dump_data; - - if (v && IS_ERR(v)) - return; - - if (!v) { - dump_data = dmn->dump_info.dump_data; - if (dump_data) { - mlx5dr_dbg_destroy_dump_data(dump_data); - dmn->dump_info.dump_data = NULL; - } - } - - atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE); -} - -static int -dr_dump_show(struct seq_file *file, void *v) -{ - struct mlx5dr_dbg_dump_buff *entry; - - entry = list_entry(v, struct mlx5dr_dbg_dump_buff, node); - seq_printf(file, "%s", entry->buff); - - return 0; -} - -static const struct seq_operations dr_dump_sops = { - .start = dr_dump_start, - .next = dr_dump_next, - .stop = dr_dump_stop, - .show = dr_dump_show, -}; -DEFINE_SEQ_ATTRIBUTE(dr_dump); - -void mlx5dr_dbg_init_dump(struct mlx5dr_domain *dmn) -{ - struct mlx5_core_dev *dev = dmn->mdev; - char file_name[128]; - - if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) { - mlx5_core_warn(dev, - "Steering dump is not supported for NIC RX/TX domains\n"); - return; - } - - dmn->dump_info.steering_debugfs = - debugfs_create_dir("steering", mlx5_debugfs_get_dev_root(dev)); - dmn->dump_info.fdb_debugfs = - debugfs_create_dir("fdb", dmn->dump_info.steering_debugfs); - - sprintf(file_name, "dmn_%p", dmn); - debugfs_create_file(file_name, 0444, dmn->dump_info.fdb_debugfs, - dmn, &dr_dump_fops); - - INIT_LIST_HEAD(&dmn->dbg_tbl_list); - mutex_init(&dmn->dump_info.dbg_mutex); -} - -void mlx5dr_dbg_uninit_dump(struct mlx5dr_domain *dmn) -{ - debugfs_remove_recursive(dmn->dump_info.steering_debugfs); - mutex_destroy(&dmn->dump_info.dbg_mutex); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h deleted file mode 100644 index 57c6b363b87074..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_dbg.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ - -#define MLX5DR_DEBUG_DUMP_BUFF_SIZE (64 * 1024 * 1024) -#define MLX5DR_DEBUG_DUMP_BUFF_LENGTH 512 - -enum { - MLX5DR_DEBUG_DUMP_STATE_FREE, - MLX5DR_DEBUG_DUMP_STATE_IN_PROGRESS, -}; - -struct mlx5dr_dbg_dump_buff { - char *buff; - u32 index; - struct list_head node; -}; - -struct mlx5dr_dbg_dump_data { - struct list_head buff_list; -}; - -struct mlx5dr_dbg_dump_info { - struct mutex dbg_mutex; /* protect dbg lists */ - struct dentry *steering_debugfs; - struct dentry *fdb_debugfs; - struct mlx5dr_dbg_dump_data *dump_data; - atomic_t state; -}; - -void mlx5dr_dbg_init_dump(struct mlx5dr_domain *dmn); -void mlx5dr_dbg_uninit_dump(struct mlx5dr_domain *dmn); -void mlx5dr_dbg_tbl_add(struct mlx5dr_table *tbl); -void mlx5dr_dbg_tbl_del(struct mlx5dr_table *tbl); -void mlx5dr_dbg_rule_add(struct mlx5dr_rule *rule); -void mlx5dr_dbg_rule_del(struct mlx5dr_rule *rule); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_definer.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_definer.c deleted file mode 100644 index d5ea9775194561..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_definer.c +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - -#include "dr_types.h" -#include "dr_ste.h" - -struct dr_definer_object { - u32 id; - u16 format_id; - u8 dw_selectors[MLX5_IFC_DEFINER_DW_SELECTORS_NUM]; - u8 byte_selectors[MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM]; - u8 match_mask[DR_STE_SIZE_MATCH_TAG]; - refcount_t refcount; -}; - -static bool dr_definer_compare(struct dr_definer_object *definer, - u16 format_id, u8 *dw_selectors, - u8 *byte_selectors, u8 *match_mask) -{ - int i; - - if (definer->format_id != format_id) - return false; - - for (i = 0; i < MLX5_IFC_DEFINER_DW_SELECTORS_NUM; i++) - if (definer->dw_selectors[i] != dw_selectors[i]) - return false; - - for (i = 0; i < MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM; i++) - if (definer->byte_selectors[i] != byte_selectors[i]) - return false; - - if (memcmp(definer->match_mask, match_mask, DR_STE_SIZE_MATCH_TAG)) - return false; - - return true; -} - -static struct dr_definer_object * -dr_definer_find_obj(struct mlx5dr_domain *dmn, u16 format_id, - u8 *dw_selectors, u8 *byte_selectors, u8 *match_mask) -{ - struct dr_definer_object *definer_obj; - unsigned long id; - - xa_for_each(&dmn->definers_xa, id, definer_obj) { - if (dr_definer_compare(definer_obj, format_id, - dw_selectors, byte_selectors, - match_mask)) - return definer_obj; - } - - return NULL; -} - -static struct dr_definer_object * -dr_definer_create_obj(struct mlx5dr_domain *dmn, u16 format_id, - u8 *dw_selectors, u8 *byte_selectors, u8 *match_mask) -{ - struct dr_definer_object *definer_obj; - int ret = 0; - - definer_obj = kzalloc(sizeof(*definer_obj), GFP_KERNEL); - if (!definer_obj) - return NULL; - - ret = mlx5dr_cmd_create_definer(dmn->mdev, - format_id, - dw_selectors, - byte_selectors, - match_mask, - &definer_obj->id); - if (ret) - goto err_free_definer_obj; - - /* Definer ID can have 32 bits, but STE format - * supports only definers with 8 bit IDs. - */ - if (definer_obj->id > 0xff) { - mlx5dr_err(dmn, "Unsupported definer ID (%d)\n", definer_obj->id); - goto err_destroy_definer; - } - - definer_obj->format_id = format_id; - memcpy(definer_obj->dw_selectors, dw_selectors, sizeof(definer_obj->dw_selectors)); - memcpy(definer_obj->byte_selectors, byte_selectors, sizeof(definer_obj->byte_selectors)); - memcpy(definer_obj->match_mask, match_mask, sizeof(definer_obj->match_mask)); - - refcount_set(&definer_obj->refcount, 1); - - ret = xa_insert(&dmn->definers_xa, definer_obj->id, definer_obj, GFP_KERNEL); - if (ret) { - mlx5dr_dbg(dmn, "Couldn't insert new definer into xarray (%d)\n", ret); - goto err_destroy_definer; - } - - return definer_obj; - -err_destroy_definer: - mlx5dr_cmd_destroy_definer(dmn->mdev, definer_obj->id); -err_free_definer_obj: - kfree(definer_obj); - - return NULL; -} - -static void dr_definer_destroy_obj(struct mlx5dr_domain *dmn, - struct dr_definer_object *definer_obj) -{ - mlx5dr_cmd_destroy_definer(dmn->mdev, definer_obj->id); - xa_erase(&dmn->definers_xa, definer_obj->id); - kfree(definer_obj); -} - -int mlx5dr_definer_get(struct mlx5dr_domain *dmn, u16 format_id, - u8 *dw_selectors, u8 *byte_selectors, - u8 *match_mask, u32 *definer_id) -{ - struct dr_definer_object *definer_obj; - int ret = 0; - - definer_obj = dr_definer_find_obj(dmn, format_id, dw_selectors, - byte_selectors, match_mask); - if (!definer_obj) { - definer_obj = dr_definer_create_obj(dmn, format_id, - dw_selectors, byte_selectors, - match_mask); - if (!definer_obj) - return -ENOMEM; - } else { - refcount_inc(&definer_obj->refcount); - } - - *definer_id = definer_obj->id; - - return ret; -} - -void mlx5dr_definer_put(struct mlx5dr_domain *dmn, u32 definer_id) -{ - struct dr_definer_object *definer_obj; - - definer_obj = xa_load(&dmn->definers_xa, definer_id); - if (!definer_obj) { - mlx5dr_err(dmn, "Definer ID %d not found\n", definer_id); - return; - } - - if (refcount_dec_and_test(&definer_obj->refcount)) - dr_definer_destroy_obj(dmn, definer_obj); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c deleted file mode 100644 index 3d74109f82300e..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c +++ /dev/null @@ -1,579 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include -#include -#include "dr_types.h" - -#define DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, dmn_type) \ - ((dmn)->info.caps.dmn_type##_sw_owner || \ - ((dmn)->info.caps.dmn_type##_sw_owner_v2 && \ - (dmn)->info.caps.sw_format_ver <= MLX5_STEERING_FORMAT_CONNECTX_7)) - -bool mlx5dr_domain_is_support_ptrn_arg(struct mlx5dr_domain *dmn) -{ - return dmn->info.caps.sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX && - dmn->info.caps.support_modify_argument; -} - -static int dr_domain_init_modify_header_resources(struct mlx5dr_domain *dmn) -{ - if (!mlx5dr_domain_is_support_ptrn_arg(dmn)) - return 0; - - dmn->ptrn_mgr = mlx5dr_ptrn_mgr_create(dmn); - if (!dmn->ptrn_mgr) { - mlx5dr_err(dmn, "Couldn't create ptrn_mgr\n"); - return -ENOMEM; - } - - /* create argument pool */ - dmn->arg_mgr = mlx5dr_arg_mgr_create(dmn); - if (!dmn->arg_mgr) { - mlx5dr_err(dmn, "Couldn't create arg_mgr\n"); - goto free_modify_header_pattern; - } - - return 0; - -free_modify_header_pattern: - mlx5dr_ptrn_mgr_destroy(dmn->ptrn_mgr); - return -ENOMEM; -} - -static void dr_domain_destroy_modify_header_resources(struct mlx5dr_domain *dmn) -{ - if (!mlx5dr_domain_is_support_ptrn_arg(dmn)) - return; - - mlx5dr_arg_mgr_destroy(dmn->arg_mgr); - mlx5dr_ptrn_mgr_destroy(dmn->ptrn_mgr); -} - -static void dr_domain_init_csum_recalc_fts(struct mlx5dr_domain *dmn) -{ - /* Per vport cached FW FT for checksum recalculation, this - * recalculation is needed due to a HW bug in STEv0. - */ - xa_init(&dmn->csum_fts_xa); -} - -static void dr_domain_uninit_csum_recalc_fts(struct mlx5dr_domain *dmn) -{ - struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft; - unsigned long i; - - xa_for_each(&dmn->csum_fts_xa, i, recalc_cs_ft) { - if (recalc_cs_ft) - mlx5dr_fw_destroy_recalc_cs_ft(dmn, recalc_cs_ft); - } - - xa_destroy(&dmn->csum_fts_xa); -} - -int mlx5dr_domain_get_recalc_cs_ft_addr(struct mlx5dr_domain *dmn, - u16 vport_num, - u64 *rx_icm_addr) -{ - struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft; - int ret; - - recalc_cs_ft = xa_load(&dmn->csum_fts_xa, vport_num); - if (!recalc_cs_ft) { - /* Table hasn't been created yet */ - recalc_cs_ft = mlx5dr_fw_create_recalc_cs_ft(dmn, vport_num); - if (!recalc_cs_ft) - return -EINVAL; - - ret = xa_err(xa_store(&dmn->csum_fts_xa, vport_num, - recalc_cs_ft, GFP_KERNEL)); - if (ret) - return ret; - } - - *rx_icm_addr = recalc_cs_ft->rx_icm_addr; - - return 0; -} - -static int dr_domain_init_mem_resources(struct mlx5dr_domain *dmn) -{ - int ret; - - dmn->chunks_kmem_cache = kmem_cache_create("mlx5_dr_chunks", - sizeof(struct mlx5dr_icm_chunk), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!dmn->chunks_kmem_cache) { - mlx5dr_err(dmn, "Couldn't create chunks kmem_cache\n"); - return -ENOMEM; - } - - dmn->htbls_kmem_cache = kmem_cache_create("mlx5_dr_htbls", - sizeof(struct mlx5dr_ste_htbl), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!dmn->htbls_kmem_cache) { - mlx5dr_err(dmn, "Couldn't create hash tables kmem_cache\n"); - ret = -ENOMEM; - goto free_chunks_kmem_cache; - } - - dmn->ste_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_STE); - if (!dmn->ste_icm_pool) { - mlx5dr_err(dmn, "Couldn't get icm memory\n"); - ret = -ENOMEM; - goto free_htbls_kmem_cache; - } - - dmn->action_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_MODIFY_ACTION); - if (!dmn->action_icm_pool) { - mlx5dr_err(dmn, "Couldn't get action icm memory\n"); - ret = -ENOMEM; - goto free_ste_icm_pool; - } - - ret = mlx5dr_send_info_pool_create(dmn); - if (ret) { - mlx5dr_err(dmn, "Couldn't create send info pool\n"); - goto free_action_icm_pool; - } - - return 0; - -free_action_icm_pool: - mlx5dr_icm_pool_destroy(dmn->action_icm_pool); -free_ste_icm_pool: - mlx5dr_icm_pool_destroy(dmn->ste_icm_pool); -free_htbls_kmem_cache: - kmem_cache_destroy(dmn->htbls_kmem_cache); -free_chunks_kmem_cache: - kmem_cache_destroy(dmn->chunks_kmem_cache); - - return ret; -} - -static void dr_domain_uninit_mem_resources(struct mlx5dr_domain *dmn) -{ - mlx5dr_send_info_pool_destroy(dmn); - mlx5dr_icm_pool_destroy(dmn->action_icm_pool); - mlx5dr_icm_pool_destroy(dmn->ste_icm_pool); - kmem_cache_destroy(dmn->htbls_kmem_cache); - kmem_cache_destroy(dmn->chunks_kmem_cache); -} - -static int dr_domain_init_resources(struct mlx5dr_domain *dmn) -{ - int ret; - - dmn->ste_ctx = mlx5dr_ste_get_ctx(dmn->info.caps.sw_format_ver); - if (!dmn->ste_ctx) { - mlx5dr_err(dmn, "SW Steering on this device is unsupported\n"); - return -EOPNOTSUPP; - } - - ret = mlx5_core_alloc_pd(dmn->mdev, &dmn->pdn); - if (ret) { - mlx5dr_err(dmn, "Couldn't allocate PD, ret: %d", ret); - return ret; - } - - dmn->uar = mlx5_get_uars_page(dmn->mdev); - if (IS_ERR(dmn->uar)) { - mlx5dr_err(dmn, "Couldn't allocate UAR\n"); - ret = PTR_ERR(dmn->uar); - goto clean_pd; - } - - ret = dr_domain_init_mem_resources(dmn); - if (ret) { - mlx5dr_err(dmn, "Couldn't create domain memory resources\n"); - goto clean_uar; - } - - ret = dr_domain_init_modify_header_resources(dmn); - if (ret) { - mlx5dr_err(dmn, "Couldn't create modify-header-resources\n"); - goto clean_mem_resources; - } - - ret = mlx5dr_send_ring_alloc(dmn); - if (ret) { - mlx5dr_err(dmn, "Couldn't create send-ring\n"); - goto clean_modify_hdr; - } - - return 0; - -clean_modify_hdr: - dr_domain_destroy_modify_header_resources(dmn); -clean_mem_resources: - dr_domain_uninit_mem_resources(dmn); -clean_uar: - mlx5_put_uars_page(dmn->mdev, dmn->uar); -clean_pd: - mlx5_core_dealloc_pd(dmn->mdev, dmn->pdn); - - return ret; -} - -static void dr_domain_uninit_resources(struct mlx5dr_domain *dmn) -{ - mlx5dr_send_ring_free(dmn, dmn->send_ring); - dr_domain_destroy_modify_header_resources(dmn); - dr_domain_uninit_mem_resources(dmn); - mlx5_put_uars_page(dmn->mdev, dmn->uar); - mlx5_core_dealloc_pd(dmn->mdev, dmn->pdn); -} - -static void dr_domain_fill_uplink_caps(struct mlx5dr_domain *dmn, - struct mlx5dr_cmd_vport_cap *uplink_vport) -{ - struct mlx5dr_esw_caps *esw_caps = &dmn->info.caps.esw_caps; - - uplink_vport->num = MLX5_VPORT_UPLINK; - uplink_vport->icm_address_rx = esw_caps->uplink_icm_address_rx; - uplink_vport->icm_address_tx = esw_caps->uplink_icm_address_tx; - uplink_vport->vport_gvmi = 0; - uplink_vport->vhca_gvmi = dmn->info.caps.gvmi; -} - -static int dr_domain_query_vport(struct mlx5dr_domain *dmn, - u16 vport_number, - bool other_vport, - struct mlx5dr_cmd_vport_cap *vport_caps) -{ - int ret; - - ret = mlx5dr_cmd_query_esw_vport_context(dmn->mdev, - other_vport, - vport_number, - &vport_caps->icm_address_rx, - &vport_caps->icm_address_tx); - if (ret) - return ret; - - ret = mlx5dr_cmd_query_gvmi(dmn->mdev, - other_vport, - vport_number, - &vport_caps->vport_gvmi); - if (ret) - return ret; - - vport_caps->num = vport_number; - vport_caps->vhca_gvmi = dmn->info.caps.gvmi; - - return 0; -} - -static int dr_domain_query_esw_mgr(struct mlx5dr_domain *dmn) -{ - return dr_domain_query_vport(dmn, 0, false, - &dmn->info.caps.vports.esw_manager_caps); -} - -static void dr_domain_query_uplink(struct mlx5dr_domain *dmn) -{ - dr_domain_fill_uplink_caps(dmn, &dmn->info.caps.vports.uplink_caps); -} - -static struct mlx5dr_cmd_vport_cap * -dr_domain_add_vport_cap(struct mlx5dr_domain *dmn, u16 vport) -{ - struct mlx5dr_cmd_caps *caps = &dmn->info.caps; - struct mlx5dr_cmd_vport_cap *vport_caps; - int ret; - - vport_caps = kvzalloc(sizeof(*vport_caps), GFP_KERNEL); - if (!vport_caps) - return NULL; - - ret = dr_domain_query_vport(dmn, vport, true, vport_caps); - if (ret) { - kvfree(vport_caps); - return NULL; - } - - ret = xa_insert(&caps->vports.vports_caps_xa, vport, - vport_caps, GFP_KERNEL); - if (ret) { - mlx5dr_dbg(dmn, "Couldn't insert new vport into xarray (%d)\n", ret); - kvfree(vport_caps); - return ERR_PTR(ret); - } - - return vport_caps; -} - -static bool dr_domain_is_esw_mgr_vport(struct mlx5dr_domain *dmn, u16 vport) -{ - struct mlx5dr_cmd_caps *caps = &dmn->info.caps; - - return (caps->is_ecpf && vport == MLX5_VPORT_ECPF) || - (!caps->is_ecpf && vport == 0); -} - -struct mlx5dr_cmd_vport_cap * -mlx5dr_domain_get_vport_cap(struct mlx5dr_domain *dmn, u16 vport) -{ - struct mlx5dr_cmd_caps *caps = &dmn->info.caps; - struct mlx5dr_cmd_vport_cap *vport_caps; - - if (dr_domain_is_esw_mgr_vport(dmn, vport)) - return &caps->vports.esw_manager_caps; - - if (vport == MLX5_VPORT_UPLINK) - return &caps->vports.uplink_caps; - -vport_load: - vport_caps = xa_load(&caps->vports.vports_caps_xa, vport); - if (vport_caps) - return vport_caps; - - vport_caps = dr_domain_add_vport_cap(dmn, vport); - if (PTR_ERR(vport_caps) == -EBUSY) - /* caps were already stored by another thread */ - goto vport_load; - - return vport_caps; -} - -static void dr_domain_clear_vports(struct mlx5dr_domain *dmn) -{ - struct mlx5dr_cmd_vport_cap *vport_caps; - unsigned long i; - - xa_for_each(&dmn->info.caps.vports.vports_caps_xa, i, vport_caps) { - vport_caps = xa_erase(&dmn->info.caps.vports.vports_caps_xa, i); - kvfree(vport_caps); - } -} - -static int dr_domain_query_fdb_caps(struct mlx5_core_dev *mdev, - struct mlx5dr_domain *dmn) -{ - int ret; - - if (!dmn->info.caps.eswitch_manager) - return -EOPNOTSUPP; - - ret = mlx5dr_cmd_query_esw_caps(mdev, &dmn->info.caps.esw_caps); - if (ret) - return ret; - - dmn->info.caps.fdb_sw_owner = dmn->info.caps.esw_caps.sw_owner; - dmn->info.caps.fdb_sw_owner_v2 = dmn->info.caps.esw_caps.sw_owner_v2; - dmn->info.caps.esw_rx_drop_address = dmn->info.caps.esw_caps.drop_icm_address_rx; - dmn->info.caps.esw_tx_drop_address = dmn->info.caps.esw_caps.drop_icm_address_tx; - - xa_init(&dmn->info.caps.vports.vports_caps_xa); - - /* Query eswitch manager and uplink vports only. Rest of the - * vports (vport 0, VFs and SFs) will be queried dynamically. - */ - - ret = dr_domain_query_esw_mgr(dmn); - if (ret) { - mlx5dr_err(dmn, "Failed to query eswitch manager vport caps (err: %d)", ret); - goto free_vports_caps_xa; - } - - dr_domain_query_uplink(dmn); - - return 0; - -free_vports_caps_xa: - xa_destroy(&dmn->info.caps.vports.vports_caps_xa); - - return ret; -} - -static int dr_domain_caps_init(struct mlx5_core_dev *mdev, - struct mlx5dr_domain *dmn) -{ - struct mlx5dr_cmd_vport_cap *vport_cap; - int ret; - - if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) { - mlx5dr_err(dmn, "Failed to allocate domain, bad link type\n"); - return -EOPNOTSUPP; - } - - ret = mlx5dr_cmd_query_device(mdev, &dmn->info.caps); - if (ret) - return ret; - - ret = dr_domain_query_fdb_caps(mdev, dmn); - if (ret) - return ret; - - switch (dmn->type) { - case MLX5DR_DOMAIN_TYPE_NIC_RX: - if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, rx)) - return -ENOTSUPP; - - dmn->info.supp_sw_steering = true; - dmn->info.rx.type = DR_DOMAIN_NIC_TYPE_RX; - dmn->info.rx.default_icm_addr = dmn->info.caps.nic_rx_drop_address; - dmn->info.rx.drop_icm_addr = dmn->info.caps.nic_rx_drop_address; - break; - case MLX5DR_DOMAIN_TYPE_NIC_TX: - if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, tx)) - return -ENOTSUPP; - - dmn->info.supp_sw_steering = true; - dmn->info.tx.type = DR_DOMAIN_NIC_TYPE_TX; - dmn->info.tx.default_icm_addr = dmn->info.caps.nic_tx_allow_address; - dmn->info.tx.drop_icm_addr = dmn->info.caps.nic_tx_drop_address; - break; - case MLX5DR_DOMAIN_TYPE_FDB: - if (!dmn->info.caps.eswitch_manager) - return -ENOTSUPP; - - if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, fdb)) - return -ENOTSUPP; - - dmn->info.rx.type = DR_DOMAIN_NIC_TYPE_RX; - dmn->info.tx.type = DR_DOMAIN_NIC_TYPE_TX; - vport_cap = &dmn->info.caps.vports.esw_manager_caps; - - dmn->info.supp_sw_steering = true; - dmn->info.tx.default_icm_addr = vport_cap->icm_address_tx; - dmn->info.rx.default_icm_addr = vport_cap->icm_address_rx; - dmn->info.rx.drop_icm_addr = dmn->info.caps.esw_rx_drop_address; - dmn->info.tx.drop_icm_addr = dmn->info.caps.esw_tx_drop_address; - break; - default: - mlx5dr_err(dmn, "Invalid domain\n"); - ret = -EINVAL; - break; - } - - return ret; -} - -static void dr_domain_caps_uninit(struct mlx5dr_domain *dmn) -{ - dr_domain_clear_vports(dmn); - xa_destroy(&dmn->info.caps.vports.vports_caps_xa); -} - -struct mlx5dr_domain * -mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type) -{ - struct mlx5dr_domain *dmn; - int ret; - - if (type > MLX5DR_DOMAIN_TYPE_FDB) - return NULL; - - dmn = kzalloc(sizeof(*dmn), GFP_KERNEL); - if (!dmn) - return NULL; - - dmn->mdev = mdev; - dmn->type = type; - refcount_set(&dmn->refcount, 1); - mutex_init(&dmn->info.rx.mutex); - mutex_init(&dmn->info.tx.mutex); - xa_init(&dmn->definers_xa); - xa_init(&dmn->peer_dmn_xa); - - if (dr_domain_caps_init(mdev, dmn)) { - mlx5dr_err(dmn, "Failed init domain, no caps\n"); - goto def_xa_destroy; - } - - dmn->info.max_log_action_icm_sz = DR_CHUNK_SIZE_4K; - dmn->info.max_log_sw_icm_sz = min_t(u32, DR_CHUNK_SIZE_1024K, - dmn->info.caps.log_icm_size); - dmn->info.max_log_modify_hdr_pattern_icm_sz = - min_t(u32, DR_CHUNK_SIZE_4K, - dmn->info.caps.log_modify_pattern_icm_size); - - if (!dmn->info.supp_sw_steering) { - mlx5dr_err(dmn, "SW steering is not supported\n"); - goto uninit_caps; - } - - /* Allocate resources */ - ret = dr_domain_init_resources(dmn); - if (ret) { - mlx5dr_err(dmn, "Failed init domain resources\n"); - goto uninit_caps; - } - - dr_domain_init_csum_recalc_fts(dmn); - mlx5dr_dbg_init_dump(dmn); - return dmn; - -uninit_caps: - dr_domain_caps_uninit(dmn); -def_xa_destroy: - xa_destroy(&dmn->peer_dmn_xa); - xa_destroy(&dmn->definers_xa); - kfree(dmn); - return NULL; -} - -/* Assure synchronization of the device steering tables with updates made by SW - * insertion. - */ -int mlx5dr_domain_sync(struct mlx5dr_domain *dmn, u32 flags) -{ - int ret = 0; - - if (flags & MLX5DR_DOMAIN_SYNC_FLAGS_SW) { - mlx5dr_domain_lock(dmn); - ret = mlx5dr_send_ring_force_drain(dmn); - mlx5dr_domain_unlock(dmn); - if (ret) { - mlx5dr_err(dmn, "Force drain failed flags: %d, ret: %d\n", - flags, ret); - return ret; - } - } - - if (flags & MLX5DR_DOMAIN_SYNC_FLAGS_HW) - ret = mlx5dr_cmd_sync_steering(dmn->mdev); - - return ret; -} - -int mlx5dr_domain_destroy(struct mlx5dr_domain *dmn) -{ - if (WARN_ON_ONCE(refcount_read(&dmn->refcount) > 1)) - return -EBUSY; - - /* make sure resources are not used by the hardware */ - mlx5dr_cmd_sync_steering(dmn->mdev); - mlx5dr_dbg_uninit_dump(dmn); - dr_domain_uninit_csum_recalc_fts(dmn); - dr_domain_uninit_resources(dmn); - dr_domain_caps_uninit(dmn); - xa_destroy(&dmn->peer_dmn_xa); - xa_destroy(&dmn->definers_xa); - mutex_destroy(&dmn->info.tx.mutex); - mutex_destroy(&dmn->info.rx.mutex); - kfree(dmn); - return 0; -} - -void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn, - struct mlx5dr_domain *peer_dmn, - u16 peer_vhca_id) -{ - struct mlx5dr_domain *peer; - - mlx5dr_domain_lock(dmn); - - peer = xa_load(&dmn->peer_dmn_xa, peer_vhca_id); - if (peer) - refcount_dec(&peer->refcount); - - WARN_ON(xa_err(xa_store(&dmn->peer_dmn_xa, peer_vhca_id, peer_dmn, GFP_KERNEL))); - - peer = xa_load(&dmn->peer_dmn_xa, peer_vhca_id); - if (peer) - refcount_inc(&peer->refcount); - - mlx5dr_domain_unlock(dmn); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_fw.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_fw.c deleted file mode 100644 index f05ef0cd54baca..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_fw.c +++ /dev/null @@ -1,171 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include -#include "dr_types.h" - -struct mlx5dr_fw_recalc_cs_ft * -mlx5dr_fw_create_recalc_cs_ft(struct mlx5dr_domain *dmn, u16 vport_num) -{ - struct mlx5dr_cmd_create_flow_table_attr ft_attr = {}; - struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft; - u32 table_id, group_id, modify_hdr_id; - u64 rx_icm_addr, modify_ttl_action; - int ret; - - recalc_cs_ft = kzalloc(sizeof(*recalc_cs_ft), GFP_KERNEL); - if (!recalc_cs_ft) - return NULL; - - ft_attr.table_type = MLX5_FLOW_TABLE_TYPE_FDB; - ft_attr.level = dmn->info.caps.max_ft_level - 1; - ft_attr.term_tbl = true; - - ret = mlx5dr_cmd_create_flow_table(dmn->mdev, - &ft_attr, - &rx_icm_addr, - &table_id); - if (ret) { - mlx5dr_err(dmn, "Failed creating TTL W/A FW flow table %d\n", ret); - goto free_ttl_tbl; - } - - ret = mlx5dr_cmd_create_empty_flow_group(dmn->mdev, - MLX5_FLOW_TABLE_TYPE_FDB, - table_id, &group_id); - if (ret) { - mlx5dr_err(dmn, "Failed creating TTL W/A FW flow group %d\n", ret); - goto destroy_flow_table; - } - - /* Modify TTL action by adding zero to trigger CS recalculation */ - modify_ttl_action = 0; - MLX5_SET(set_action_in, &modify_ttl_action, action_type, MLX5_ACTION_TYPE_ADD); - MLX5_SET(set_action_in, &modify_ttl_action, field, MLX5_ACTION_IN_FIELD_OUT_IP_TTL); - - ret = mlx5dr_cmd_alloc_modify_header(dmn->mdev, MLX5_FLOW_TABLE_TYPE_FDB, 1, - &modify_ttl_action, - &modify_hdr_id); - if (ret) { - mlx5dr_err(dmn, "Failed modify header TTL %d\n", ret); - goto destroy_flow_group; - } - - ret = mlx5dr_cmd_set_fte_modify_and_vport(dmn->mdev, - MLX5_FLOW_TABLE_TYPE_FDB, - table_id, group_id, modify_hdr_id, - vport_num); - if (ret) { - mlx5dr_err(dmn, "Failed setting TTL W/A flow table entry %d\n", ret); - goto dealloc_modify_header; - } - - recalc_cs_ft->modify_hdr_id = modify_hdr_id; - recalc_cs_ft->rx_icm_addr = rx_icm_addr; - recalc_cs_ft->table_id = table_id; - recalc_cs_ft->group_id = group_id; - - return recalc_cs_ft; - -dealloc_modify_header: - mlx5dr_cmd_dealloc_modify_header(dmn->mdev, modify_hdr_id); -destroy_flow_group: - mlx5dr_cmd_destroy_flow_group(dmn->mdev, - MLX5_FLOW_TABLE_TYPE_FDB, - table_id, group_id); -destroy_flow_table: - mlx5dr_cmd_destroy_flow_table(dmn->mdev, table_id, MLX5_FLOW_TABLE_TYPE_FDB); -free_ttl_tbl: - kfree(recalc_cs_ft); - return NULL; -} - -void mlx5dr_fw_destroy_recalc_cs_ft(struct mlx5dr_domain *dmn, - struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft) -{ - mlx5dr_cmd_del_flow_table_entry(dmn->mdev, - MLX5_FLOW_TABLE_TYPE_FDB, - recalc_cs_ft->table_id); - mlx5dr_cmd_dealloc_modify_header(dmn->mdev, recalc_cs_ft->modify_hdr_id); - mlx5dr_cmd_destroy_flow_group(dmn->mdev, - MLX5_FLOW_TABLE_TYPE_FDB, - recalc_cs_ft->table_id, - recalc_cs_ft->group_id); - mlx5dr_cmd_destroy_flow_table(dmn->mdev, - recalc_cs_ft->table_id, - MLX5_FLOW_TABLE_TYPE_FDB); - - kfree(recalc_cs_ft); -} - -int mlx5dr_fw_create_md_tbl(struct mlx5dr_domain *dmn, - struct mlx5dr_cmd_flow_destination_hw_info *dest, - int num_dest, - bool reformat_req, - u32 *tbl_id, - u32 *group_id, - bool ignore_flow_level, - u32 flow_source) -{ - struct mlx5dr_cmd_create_flow_table_attr ft_attr = {}; - struct mlx5dr_cmd_fte_info fte_info = {}; - u32 val[MLX5_ST_SZ_DW_MATCH_PARAM] = {}; - struct mlx5dr_cmd_ft_info ft_info = {}; - int ret; - - ft_attr.table_type = MLX5_FLOW_TABLE_TYPE_FDB; - ft_attr.level = min_t(int, dmn->info.caps.max_ft_level - 2, - MLX5_FT_MAX_MULTIPATH_LEVEL); - ft_attr.reformat_en = reformat_req; - ft_attr.decap_en = reformat_req; - - ret = mlx5dr_cmd_create_flow_table(dmn->mdev, &ft_attr, NULL, tbl_id); - if (ret) { - mlx5dr_err(dmn, "Failed creating multi dest FW flow table %d\n", ret); - return ret; - } - - ret = mlx5dr_cmd_create_empty_flow_group(dmn->mdev, - MLX5_FLOW_TABLE_TYPE_FDB, - *tbl_id, group_id); - if (ret) { - mlx5dr_err(dmn, "Failed creating multi dest FW flow group %d\n", ret); - goto free_flow_table; - } - - ft_info.id = *tbl_id; - ft_info.type = FS_FT_FDB; - fte_info.action.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; - fte_info.dests_size = num_dest; - fte_info.val = val; - fte_info.dest_arr = dest; - fte_info.ignore_flow_level = ignore_flow_level; - fte_info.flow_context.flow_source = flow_source; - - ret = mlx5dr_cmd_set_fte(dmn->mdev, 0, 0, &ft_info, *group_id, &fte_info); - if (ret) { - mlx5dr_err(dmn, "Failed setting fte into table %d\n", ret); - goto free_flow_group; - } - - return 0; - -free_flow_group: - mlx5dr_cmd_destroy_flow_group(dmn->mdev, MLX5_FLOW_TABLE_TYPE_FDB, - *tbl_id, *group_id); -free_flow_table: - mlx5dr_cmd_destroy_flow_table(dmn->mdev, *tbl_id, - MLX5_FLOW_TABLE_TYPE_FDB); - return ret; -} - -void mlx5dr_fw_destroy_md_tbl(struct mlx5dr_domain *dmn, - u32 tbl_id, u32 group_id) -{ - mlx5dr_cmd_del_flow_table_entry(dmn->mdev, FS_FT_FDB, tbl_id); - mlx5dr_cmd_destroy_flow_group(dmn->mdev, - MLX5_FLOW_TABLE_TYPE_FDB, - tbl_id, group_id); - mlx5dr_cmd_destroy_flow_table(dmn->mdev, tbl_id, - MLX5_FLOW_TABLE_TYPE_FDB); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_icm_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_icm_pool.c deleted file mode 100644 index 0b5af9f3f605b7..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_icm_pool.c +++ /dev/null @@ -1,576 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include "dr_types.h" - -#define DR_ICM_MODIFY_HDR_ALIGN_BASE 64 -#define DR_ICM_POOL_STE_HOT_MEM_PERCENT 25 -#define DR_ICM_POOL_MODIFY_HDR_PTRN_HOT_MEM_PERCENT 50 -#define DR_ICM_POOL_MODIFY_ACTION_HOT_MEM_PERCENT 90 - -struct mlx5dr_icm_hot_chunk { - struct mlx5dr_icm_buddy_mem *buddy_mem; - unsigned int seg; - enum mlx5dr_icm_chunk_size size; -}; - -struct mlx5dr_icm_pool { - enum mlx5dr_icm_type icm_type; - enum mlx5dr_icm_chunk_size max_log_chunk_sz; - struct mlx5dr_domain *dmn; - struct kmem_cache *chunks_kmem_cache; - - /* memory management */ - struct mutex mutex; /* protect the ICM pool and ICM buddy */ - struct list_head buddy_mem_list; - - /* Hardware may be accessing this memory but at some future, - * undetermined time, it might cease to do so. - * sync_ste command sets them free. - */ - struct mlx5dr_icm_hot_chunk *hot_chunks_arr; - u32 hot_chunks_num; - u64 hot_memory_size; - /* hot memory size threshold for triggering sync */ - u64 th; -}; - -struct mlx5dr_icm_dm { - u32 obj_id; - enum mlx5_sw_icm_type type; - phys_addr_t addr; - size_t length; -}; - -struct mlx5dr_icm_mr { - u32 mkey; - struct mlx5dr_icm_dm dm; - struct mlx5dr_domain *dmn; - size_t length; - u64 icm_start_addr; -}; - -static int dr_icm_create_dm_mkey(struct mlx5_core_dev *mdev, - u32 pd, u64 length, u64 start_addr, int mode, - u32 *mkey) -{ - u32 inlen = MLX5_ST_SZ_BYTES(create_mkey_in); - u32 in[MLX5_ST_SZ_DW(create_mkey_in)] = {}; - void *mkc; - - mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); - - MLX5_SET(mkc, mkc, access_mode_1_0, mode); - MLX5_SET(mkc, mkc, access_mode_4_2, (mode >> 2) & 0x7); - MLX5_SET(mkc, mkc, lw, 1); - MLX5_SET(mkc, mkc, lr, 1); - if (mode == MLX5_MKC_ACCESS_MODE_SW_ICM) { - MLX5_SET(mkc, mkc, rw, 1); - MLX5_SET(mkc, mkc, rr, 1); - } - - MLX5_SET64(mkc, mkc, len, length); - MLX5_SET(mkc, mkc, pd, pd); - MLX5_SET(mkc, mkc, qpn, 0xffffff); - MLX5_SET64(mkc, mkc, start_addr, start_addr); - - return mlx5_core_create_mkey(mdev, mkey, in, inlen); -} - -u64 mlx5dr_icm_pool_get_chunk_mr_addr(struct mlx5dr_icm_chunk *chunk) -{ - u32 offset = mlx5dr_icm_pool_dm_type_to_entry_size(chunk->buddy_mem->pool->icm_type); - - return (u64)offset * chunk->seg; -} - -u32 mlx5dr_icm_pool_get_chunk_rkey(struct mlx5dr_icm_chunk *chunk) -{ - return chunk->buddy_mem->icm_mr->mkey; -} - -u64 mlx5dr_icm_pool_get_chunk_icm_addr(struct mlx5dr_icm_chunk *chunk) -{ - u32 size = mlx5dr_icm_pool_dm_type_to_entry_size(chunk->buddy_mem->pool->icm_type); - - return (u64)chunk->buddy_mem->icm_mr->icm_start_addr + size * chunk->seg; -} - -u32 mlx5dr_icm_pool_get_chunk_byte_size(struct mlx5dr_icm_chunk *chunk) -{ - return mlx5dr_icm_pool_chunk_size_to_byte(chunk->size, - chunk->buddy_mem->pool->icm_type); -} - -u32 mlx5dr_icm_pool_get_chunk_num_of_entries(struct mlx5dr_icm_chunk *chunk) -{ - return mlx5dr_icm_pool_chunk_size_to_entries(chunk->size); -} - -static struct mlx5dr_icm_mr * -dr_icm_pool_mr_create(struct mlx5dr_icm_pool *pool) -{ - struct mlx5_core_dev *mdev = pool->dmn->mdev; - enum mlx5_sw_icm_type dm_type = 0; - struct mlx5dr_icm_mr *icm_mr; - size_t log_align_base = 0; - int err; - - icm_mr = kvzalloc(sizeof(*icm_mr), GFP_KERNEL); - if (!icm_mr) - return NULL; - - icm_mr->dmn = pool->dmn; - - icm_mr->dm.length = mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz, - pool->icm_type); - - switch (pool->icm_type) { - case DR_ICM_TYPE_STE: - dm_type = MLX5_SW_ICM_TYPE_STEERING; - log_align_base = ilog2(icm_mr->dm.length); - break; - case DR_ICM_TYPE_MODIFY_ACTION: - dm_type = MLX5_SW_ICM_TYPE_HEADER_MODIFY; - /* Align base is 64B */ - log_align_base = ilog2(DR_ICM_MODIFY_HDR_ALIGN_BASE); - break; - case DR_ICM_TYPE_MODIFY_HDR_PTRN: - dm_type = MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN; - /* Align base is 64B */ - log_align_base = ilog2(DR_ICM_MODIFY_HDR_ALIGN_BASE); - break; - default: - WARN_ON(pool->icm_type); - } - - icm_mr->dm.type = dm_type; - - err = mlx5_dm_sw_icm_alloc(mdev, icm_mr->dm.type, icm_mr->dm.length, - log_align_base, 0, &icm_mr->dm.addr, - &icm_mr->dm.obj_id); - if (err) { - mlx5dr_err(pool->dmn, "Failed to allocate SW ICM memory, err (%d)\n", err); - goto free_icm_mr; - } - - /* Register device memory */ - err = dr_icm_create_dm_mkey(mdev, pool->dmn->pdn, - icm_mr->dm.length, - icm_mr->dm.addr, - MLX5_MKC_ACCESS_MODE_SW_ICM, - &icm_mr->mkey); - if (err) { - mlx5dr_err(pool->dmn, "Failed to create SW ICM MKEY, err (%d)\n", err); - goto free_dm; - } - - icm_mr->icm_start_addr = icm_mr->dm.addr; - - if (icm_mr->icm_start_addr & (BIT(log_align_base) - 1)) { - mlx5dr_err(pool->dmn, "Failed to get Aligned ICM mem (asked: %zu)\n", - log_align_base); - goto free_mkey; - } - - return icm_mr; - -free_mkey: - mlx5_core_destroy_mkey(mdev, icm_mr->mkey); -free_dm: - mlx5_dm_sw_icm_dealloc(mdev, icm_mr->dm.type, icm_mr->dm.length, 0, - icm_mr->dm.addr, icm_mr->dm.obj_id); -free_icm_mr: - kvfree(icm_mr); - return NULL; -} - -static void dr_icm_pool_mr_destroy(struct mlx5dr_icm_mr *icm_mr) -{ - struct mlx5_core_dev *mdev = icm_mr->dmn->mdev; - struct mlx5dr_icm_dm *dm = &icm_mr->dm; - - mlx5_core_destroy_mkey(mdev, icm_mr->mkey); - mlx5_dm_sw_icm_dealloc(mdev, dm->type, dm->length, 0, - dm->addr, dm->obj_id); - kvfree(icm_mr); -} - -static int dr_icm_buddy_get_ste_size(struct mlx5dr_icm_buddy_mem *buddy) -{ - /* We support only one type of STE size, both for ConnectX-5 and later - * devices. Once the support for match STE which has a larger tag is - * added (32B instead of 16B), the STE size for devices later than - * ConnectX-5 needs to account for that. - */ - return DR_STE_SIZE_REDUCED; -} - -static void dr_icm_chunk_ste_init(struct mlx5dr_icm_chunk *chunk, int offset) -{ - int num_of_entries = mlx5dr_icm_pool_get_chunk_num_of_entries(chunk); - struct mlx5dr_icm_buddy_mem *buddy = chunk->buddy_mem; - int ste_size = dr_icm_buddy_get_ste_size(buddy); - int index = offset / DR_STE_SIZE; - - chunk->ste_arr = &buddy->ste_arr[index]; - chunk->miss_list = &buddy->miss_list[index]; - chunk->hw_ste_arr = buddy->hw_ste_arr + index * ste_size; - - memset(chunk->hw_ste_arr, 0, num_of_entries * ste_size); - memset(chunk->ste_arr, 0, - num_of_entries * sizeof(chunk->ste_arr[0])); -} - -static int dr_icm_buddy_init_ste_cache(struct mlx5dr_icm_buddy_mem *buddy) -{ - int num_of_entries = - mlx5dr_icm_pool_chunk_size_to_entries(buddy->pool->max_log_chunk_sz); - - buddy->ste_arr = kvcalloc(num_of_entries, - sizeof(struct mlx5dr_ste), GFP_KERNEL); - if (!buddy->ste_arr) - return -ENOMEM; - - /* Preallocate full STE size on non-ConnectX-5 devices since - * we need to support both full and reduced with the same cache. - */ - buddy->hw_ste_arr = kvcalloc(num_of_entries, - dr_icm_buddy_get_ste_size(buddy), GFP_KERNEL); - if (!buddy->hw_ste_arr) - goto free_ste_arr; - - buddy->miss_list = kvmalloc(num_of_entries * sizeof(struct list_head), GFP_KERNEL); - if (!buddy->miss_list) - goto free_hw_ste_arr; - - return 0; - -free_hw_ste_arr: - kvfree(buddy->hw_ste_arr); -free_ste_arr: - kvfree(buddy->ste_arr); - return -ENOMEM; -} - -static void dr_icm_buddy_cleanup_ste_cache(struct mlx5dr_icm_buddy_mem *buddy) -{ - kvfree(buddy->ste_arr); - kvfree(buddy->hw_ste_arr); - kvfree(buddy->miss_list); -} - -static int dr_icm_buddy_create(struct mlx5dr_icm_pool *pool) -{ - struct mlx5dr_icm_buddy_mem *buddy; - struct mlx5dr_icm_mr *icm_mr; - - icm_mr = dr_icm_pool_mr_create(pool); - if (!icm_mr) - return -ENOMEM; - - buddy = kvzalloc(sizeof(*buddy), GFP_KERNEL); - if (!buddy) - goto free_mr; - - if (mlx5dr_buddy_init(buddy, pool->max_log_chunk_sz)) - goto err_free_buddy; - - buddy->icm_mr = icm_mr; - buddy->pool = pool; - - if (pool->icm_type == DR_ICM_TYPE_STE) { - /* Reduce allocations by preallocating and reusing the STE structures */ - if (dr_icm_buddy_init_ste_cache(buddy)) - goto err_cleanup_buddy; - } - - /* add it to the -start- of the list in order to search in it first */ - list_add(&buddy->list_node, &pool->buddy_mem_list); - - pool->dmn->num_buddies[pool->icm_type]++; - - return 0; - -err_cleanup_buddy: - mlx5dr_buddy_cleanup(buddy); -err_free_buddy: - kvfree(buddy); -free_mr: - dr_icm_pool_mr_destroy(icm_mr); - return -ENOMEM; -} - -static void dr_icm_buddy_destroy(struct mlx5dr_icm_buddy_mem *buddy) -{ - enum mlx5dr_icm_type icm_type = buddy->pool->icm_type; - - dr_icm_pool_mr_destroy(buddy->icm_mr); - - mlx5dr_buddy_cleanup(buddy); - - if (icm_type == DR_ICM_TYPE_STE) - dr_icm_buddy_cleanup_ste_cache(buddy); - - buddy->pool->dmn->num_buddies[icm_type]--; - - kvfree(buddy); -} - -static void -dr_icm_chunk_init(struct mlx5dr_icm_chunk *chunk, - struct mlx5dr_icm_pool *pool, - enum mlx5dr_icm_chunk_size chunk_size, - struct mlx5dr_icm_buddy_mem *buddy_mem_pool, - unsigned int seg) -{ - int offset; - - chunk->seg = seg; - chunk->size = chunk_size; - chunk->buddy_mem = buddy_mem_pool; - - if (pool->icm_type == DR_ICM_TYPE_STE) { - offset = mlx5dr_icm_pool_dm_type_to_entry_size(pool->icm_type) * seg; - dr_icm_chunk_ste_init(chunk, offset); - } - - buddy_mem_pool->used_memory += mlx5dr_icm_pool_get_chunk_byte_size(chunk); -} - -static bool dr_icm_pool_is_sync_required(struct mlx5dr_icm_pool *pool) -{ - return pool->hot_memory_size > pool->th; -} - -static void dr_icm_pool_clear_hot_chunks_arr(struct mlx5dr_icm_pool *pool) -{ - struct mlx5dr_icm_hot_chunk *hot_chunk; - u32 i, num_entries; - - for (i = 0; i < pool->hot_chunks_num; i++) { - hot_chunk = &pool->hot_chunks_arr[i]; - num_entries = mlx5dr_icm_pool_chunk_size_to_entries(hot_chunk->size); - mlx5dr_buddy_free_mem(hot_chunk->buddy_mem, - hot_chunk->seg, ilog2(num_entries)); - hot_chunk->buddy_mem->used_memory -= - mlx5dr_icm_pool_chunk_size_to_byte(hot_chunk->size, - pool->icm_type); - } - - pool->hot_chunks_num = 0; - pool->hot_memory_size = 0; -} - -static int dr_icm_pool_sync_all_buddy_pools(struct mlx5dr_icm_pool *pool) -{ - struct mlx5dr_icm_buddy_mem *buddy, *tmp_buddy; - int err; - - err = mlx5dr_cmd_sync_steering(pool->dmn->mdev); - if (err) { - mlx5dr_err(pool->dmn, "Failed to sync to HW (err: %d)\n", err); - return err; - } - - dr_icm_pool_clear_hot_chunks_arr(pool); - - list_for_each_entry_safe(buddy, tmp_buddy, &pool->buddy_mem_list, list_node) { - if (!buddy->used_memory && pool->icm_type == DR_ICM_TYPE_STE) - dr_icm_buddy_destroy(buddy); - } - - return 0; -} - -static int dr_icm_handle_buddies_get_mem(struct mlx5dr_icm_pool *pool, - enum mlx5dr_icm_chunk_size chunk_size, - struct mlx5dr_icm_buddy_mem **buddy, - unsigned int *seg) -{ - struct mlx5dr_icm_buddy_mem *buddy_mem_pool; - bool new_mem = false; - int err; - -alloc_buddy_mem: - /* find the next free place from the buddy list */ - list_for_each_entry(buddy_mem_pool, &pool->buddy_mem_list, list_node) { - err = mlx5dr_buddy_alloc_mem(buddy_mem_pool, - chunk_size, seg); - if (!err) - goto found; - - if (WARN_ON(new_mem)) { - /* We have new memory pool, first in the list */ - mlx5dr_err(pool->dmn, - "No memory for order: %d\n", - chunk_size); - goto out; - } - } - - /* no more available allocators in that pool, create new */ - err = dr_icm_buddy_create(pool); - if (err) { - mlx5dr_err(pool->dmn, - "Failed creating buddy for order %d\n", - chunk_size); - goto out; - } - - /* mark we have new memory, first in list */ - new_mem = true; - goto alloc_buddy_mem; - -found: - *buddy = buddy_mem_pool; -out: - return err; -} - -/* Allocate an ICM chunk, each chunk holds a piece of ICM memory and - * also memory used for HW STE management for optimizations. - */ -struct mlx5dr_icm_chunk * -mlx5dr_icm_alloc_chunk(struct mlx5dr_icm_pool *pool, - enum mlx5dr_icm_chunk_size chunk_size) -{ - struct mlx5dr_icm_chunk *chunk = NULL; - struct mlx5dr_icm_buddy_mem *buddy; - unsigned int seg; - int ret; - - if (chunk_size > pool->max_log_chunk_sz) - return NULL; - - mutex_lock(&pool->mutex); - /* find mem, get back the relevant buddy pool and seg in that mem */ - ret = dr_icm_handle_buddies_get_mem(pool, chunk_size, &buddy, &seg); - if (ret) - goto out; - - chunk = kmem_cache_alloc(pool->chunks_kmem_cache, GFP_KERNEL); - if (!chunk) - goto out_err; - - dr_icm_chunk_init(chunk, pool, chunk_size, buddy, seg); - - goto out; - -out_err: - mlx5dr_buddy_free_mem(buddy, seg, chunk_size); -out: - mutex_unlock(&pool->mutex); - return chunk; -} - -void mlx5dr_icm_free_chunk(struct mlx5dr_icm_chunk *chunk) -{ - struct mlx5dr_icm_buddy_mem *buddy = chunk->buddy_mem; - struct mlx5dr_icm_pool *pool = buddy->pool; - struct mlx5dr_icm_hot_chunk *hot_chunk; - struct kmem_cache *chunks_cache; - - chunks_cache = pool->chunks_kmem_cache; - - /* move the chunk to the waiting chunks array, AKA "hot" memory */ - mutex_lock(&pool->mutex); - - pool->hot_memory_size += mlx5dr_icm_pool_get_chunk_byte_size(chunk); - - hot_chunk = &pool->hot_chunks_arr[pool->hot_chunks_num++]; - hot_chunk->buddy_mem = chunk->buddy_mem; - hot_chunk->seg = chunk->seg; - hot_chunk->size = chunk->size; - - kmem_cache_free(chunks_cache, chunk); - - /* Check if we have chunks that are waiting for sync-ste */ - if (dr_icm_pool_is_sync_required(pool)) - dr_icm_pool_sync_all_buddy_pools(pool); - - mutex_unlock(&pool->mutex); -} - -struct mlx5dr_ste_htbl *mlx5dr_icm_pool_alloc_htbl(struct mlx5dr_icm_pool *pool) -{ - return kmem_cache_alloc(pool->dmn->htbls_kmem_cache, GFP_KERNEL); -} - -void mlx5dr_icm_pool_free_htbl(struct mlx5dr_icm_pool *pool, struct mlx5dr_ste_htbl *htbl) -{ - kmem_cache_free(pool->dmn->htbls_kmem_cache, htbl); -} - -struct mlx5dr_icm_pool *mlx5dr_icm_pool_create(struct mlx5dr_domain *dmn, - enum mlx5dr_icm_type icm_type) -{ - u32 num_of_chunks, entry_size; - struct mlx5dr_icm_pool *pool; - u32 max_hot_size = 0; - - pool = kvzalloc(sizeof(*pool), GFP_KERNEL); - if (!pool) - return NULL; - - pool->dmn = dmn; - pool->icm_type = icm_type; - pool->chunks_kmem_cache = dmn->chunks_kmem_cache; - - INIT_LIST_HEAD(&pool->buddy_mem_list); - mutex_init(&pool->mutex); - - switch (icm_type) { - case DR_ICM_TYPE_STE: - pool->max_log_chunk_sz = dmn->info.max_log_sw_icm_sz; - max_hot_size = mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz, - pool->icm_type) * - DR_ICM_POOL_STE_HOT_MEM_PERCENT / 100; - break; - case DR_ICM_TYPE_MODIFY_ACTION: - pool->max_log_chunk_sz = dmn->info.max_log_action_icm_sz; - max_hot_size = mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz, - pool->icm_type) * - DR_ICM_POOL_MODIFY_ACTION_HOT_MEM_PERCENT / 100; - break; - case DR_ICM_TYPE_MODIFY_HDR_PTRN: - pool->max_log_chunk_sz = dmn->info.max_log_modify_hdr_pattern_icm_sz; - max_hot_size = mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz, - pool->icm_type) * - DR_ICM_POOL_MODIFY_HDR_PTRN_HOT_MEM_PERCENT / 100; - break; - default: - WARN_ON(icm_type); - } - - entry_size = mlx5dr_icm_pool_dm_type_to_entry_size(pool->icm_type); - - num_of_chunks = DIV_ROUND_UP(max_hot_size, entry_size) + 1; - pool->th = max_hot_size; - - pool->hot_chunks_arr = kvcalloc(num_of_chunks, - sizeof(struct mlx5dr_icm_hot_chunk), - GFP_KERNEL); - if (!pool->hot_chunks_arr) - goto free_pool; - - return pool; - -free_pool: - kvfree(pool); - return NULL; -} - -void mlx5dr_icm_pool_destroy(struct mlx5dr_icm_pool *pool) -{ - struct mlx5dr_icm_buddy_mem *buddy, *tmp_buddy; - - dr_icm_pool_clear_hot_chunks_arr(pool); - - list_for_each_entry_safe(buddy, tmp_buddy, &pool->buddy_mem_list, list_node) - dr_icm_buddy_destroy(buddy); - - kvfree(pool->hot_chunks_arr); - mutex_destroy(&pool->mutex); - kvfree(pool); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c deleted file mode 100644 index 0726848eb3ff25..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c +++ /dev/null @@ -1,1108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include "dr_types.h" - -static bool dr_mask_is_smac_set(struct mlx5dr_match_spec *spec) -{ - return (spec->smac_47_16 || spec->smac_15_0); -} - -static bool dr_mask_is_dmac_set(struct mlx5dr_match_spec *spec) -{ - return (spec->dmac_47_16 || spec->dmac_15_0); -} - -static bool dr_mask_is_l3_base_set(struct mlx5dr_match_spec *spec) -{ - return (spec->ip_protocol || spec->frag || spec->tcp_flags || - spec->ip_ecn || spec->ip_dscp); -} - -static bool dr_mask_is_tcp_udp_base_set(struct mlx5dr_match_spec *spec) -{ - return (spec->tcp_sport || spec->tcp_dport || - spec->udp_sport || spec->udp_dport); -} - -static bool dr_mask_is_ipv4_set(struct mlx5dr_match_spec *spec) -{ - return (spec->dst_ip_31_0 || spec->src_ip_31_0); -} - -static bool dr_mask_is_ipv4_5_tuple_set(struct mlx5dr_match_spec *spec) -{ - return (dr_mask_is_l3_base_set(spec) || - dr_mask_is_tcp_udp_base_set(spec) || - dr_mask_is_ipv4_set(spec)); -} - -static bool dr_mask_is_eth_l2_tnl_set(struct mlx5dr_match_misc *misc) -{ - return misc->vxlan_vni; -} - -static bool dr_mask_is_ttl_set(struct mlx5dr_match_spec *spec) -{ - return spec->ttl_hoplimit; -} - -static bool dr_mask_is_ipv4_ihl_set(struct mlx5dr_match_spec *spec) -{ - return spec->ipv4_ihl; -} - -#define DR_MASK_IS_L2_DST(_spec, _misc, _inner_outer) (_spec.first_vid || \ - (_spec).first_cfi || (_spec).first_prio || (_spec).cvlan_tag || \ - (_spec).svlan_tag || (_spec).dmac_47_16 || (_spec).dmac_15_0 || \ - (_spec).ethertype || (_spec).ip_version || \ - (_misc)._inner_outer##_second_vid || \ - (_misc)._inner_outer##_second_cfi || \ - (_misc)._inner_outer##_second_prio || \ - (_misc)._inner_outer##_second_cvlan_tag || \ - (_misc)._inner_outer##_second_svlan_tag) - -#define DR_MASK_IS_ETH_L4_SET(_spec, _misc, _inner_outer) ( \ - dr_mask_is_l3_base_set(&(_spec)) || \ - dr_mask_is_tcp_udp_base_set(&(_spec)) || \ - dr_mask_is_ttl_set(&(_spec)) || \ - (_misc)._inner_outer##_ipv6_flow_label) - -#define DR_MASK_IS_ETH_L4_MISC_SET(_misc3, _inner_outer) ( \ - (_misc3)._inner_outer##_tcp_seq_num || \ - (_misc3)._inner_outer##_tcp_ack_num) - -#define DR_MASK_IS_FIRST_MPLS_SET(_misc2, _inner_outer) ( \ - (_misc2)._inner_outer##_first_mpls_label || \ - (_misc2)._inner_outer##_first_mpls_exp || \ - (_misc2)._inner_outer##_first_mpls_s_bos || \ - (_misc2)._inner_outer##_first_mpls_ttl) - -static bool dr_mask_is_tnl_gre_set(struct mlx5dr_match_misc *misc) -{ - return (misc->gre_key_h || misc->gre_key_l || - misc->gre_protocol || misc->gre_c_present || - misc->gre_k_present || misc->gre_s_present); -} - -#define DR_MASK_IS_OUTER_MPLS_OVER_GRE_SET(_misc) (\ - (_misc)->outer_first_mpls_over_gre_label || \ - (_misc)->outer_first_mpls_over_gre_exp || \ - (_misc)->outer_first_mpls_over_gre_s_bos || \ - (_misc)->outer_first_mpls_over_gre_ttl) - -#define DR_MASK_IS_OUTER_MPLS_OVER_UDP_SET(_misc) (\ - (_misc)->outer_first_mpls_over_udp_label || \ - (_misc)->outer_first_mpls_over_udp_exp || \ - (_misc)->outer_first_mpls_over_udp_s_bos || \ - (_misc)->outer_first_mpls_over_udp_ttl) - -static bool -dr_mask_is_vxlan_gpe_set(struct mlx5dr_match_misc3 *misc3) -{ - return (misc3->outer_vxlan_gpe_vni || - misc3->outer_vxlan_gpe_next_protocol || - misc3->outer_vxlan_gpe_flags); -} - -static bool -dr_matcher_supp_vxlan_gpe(struct mlx5dr_cmd_caps *caps) -{ - return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || - (caps->flex_protocols & MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED); -} - -static bool -dr_mask_is_tnl_vxlan_gpe(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return dr_mask_is_vxlan_gpe_set(&mask->misc3) && - dr_matcher_supp_vxlan_gpe(&dmn->info.caps); -} - -static bool dr_mask_is_tnl_geneve_set(struct mlx5dr_match_misc *misc) -{ - return misc->geneve_vni || - misc->geneve_oam || - misc->geneve_protocol_type || - misc->geneve_opt_len; -} - -static bool dr_mask_is_tnl_geneve_tlv_opt(struct mlx5dr_match_misc3 *misc3) -{ - return misc3->geneve_tlv_option_0_data; -} - -static bool -dr_matcher_supp_flex_parser_ok(struct mlx5dr_cmd_caps *caps) -{ - return caps->flex_parser_ok_bits_supp; -} - -static bool dr_mask_is_tnl_geneve_tlv_opt_exist_set(struct mlx5dr_match_misc *misc, - struct mlx5dr_domain *dmn) -{ - return dr_matcher_supp_flex_parser_ok(&dmn->info.caps) && - misc->geneve_tlv_option_0_exist; -} - -static bool -dr_matcher_supp_tnl_geneve(struct mlx5dr_cmd_caps *caps) -{ - return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || - (caps->flex_protocols & MLX5_FLEX_PARSER_GENEVE_ENABLED); -} - -static bool -dr_mask_is_tnl_geneve(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return dr_mask_is_tnl_geneve_set(&mask->misc) && - dr_matcher_supp_tnl_geneve(&dmn->info.caps); -} - -static bool dr_mask_is_tnl_gtpu_set(struct mlx5dr_match_misc3 *misc3) -{ - return misc3->gtpu_msg_flags || misc3->gtpu_msg_type || misc3->gtpu_teid; -} - -static bool dr_matcher_supp_tnl_gtpu(struct mlx5dr_cmd_caps *caps) -{ - return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_ENABLED; -} - -static bool dr_mask_is_tnl_gtpu(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return dr_mask_is_tnl_gtpu_set(&mask->misc3) && - dr_matcher_supp_tnl_gtpu(&dmn->info.caps); -} - -static int dr_matcher_supp_tnl_gtpu_dw_0(struct mlx5dr_cmd_caps *caps) -{ - return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_0_ENABLED; -} - -static bool dr_mask_is_tnl_gtpu_dw_0(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return mask->misc3.gtpu_dw_0 && - dr_matcher_supp_tnl_gtpu_dw_0(&dmn->info.caps); -} - -static int dr_matcher_supp_tnl_gtpu_teid(struct mlx5dr_cmd_caps *caps) -{ - return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_TEID_ENABLED; -} - -static bool dr_mask_is_tnl_gtpu_teid(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return mask->misc3.gtpu_teid && - dr_matcher_supp_tnl_gtpu_teid(&dmn->info.caps); -} - -static int dr_matcher_supp_tnl_gtpu_dw_2(struct mlx5dr_cmd_caps *caps) -{ - return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_2_ENABLED; -} - -static bool dr_mask_is_tnl_gtpu_dw_2(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return mask->misc3.gtpu_dw_2 && - dr_matcher_supp_tnl_gtpu_dw_2(&dmn->info.caps); -} - -static int dr_matcher_supp_tnl_gtpu_first_ext(struct mlx5dr_cmd_caps *caps) -{ - return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_FIRST_EXT_DW_0_ENABLED; -} - -static bool dr_mask_is_tnl_gtpu_first_ext(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return mask->misc3.gtpu_first_ext_dw_0 && - dr_matcher_supp_tnl_gtpu_first_ext(&dmn->info.caps); -} - -static bool dr_mask_is_tnl_gtpu_flex_parser_0(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - struct mlx5dr_cmd_caps *caps = &dmn->info.caps; - - return (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_dw_0) && - dr_mask_is_tnl_gtpu_dw_0(mask, dmn)) || - (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_teid) && - dr_mask_is_tnl_gtpu_teid(mask, dmn)) || - (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_dw_2) && - dr_mask_is_tnl_gtpu_dw_2(mask, dmn)) || - (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_first_ext_dw_0) && - dr_mask_is_tnl_gtpu_first_ext(mask, dmn)); -} - -static bool dr_mask_is_tnl_gtpu_flex_parser_1(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - struct mlx5dr_cmd_caps *caps = &dmn->info.caps; - - return (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_dw_0) && - dr_mask_is_tnl_gtpu_dw_0(mask, dmn)) || - (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_teid) && - dr_mask_is_tnl_gtpu_teid(mask, dmn)) || - (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_dw_2) && - dr_mask_is_tnl_gtpu_dw_2(mask, dmn)) || - (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_first_ext_dw_0) && - dr_mask_is_tnl_gtpu_first_ext(mask, dmn)); -} - -static bool dr_mask_is_tnl_gtpu_any(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return dr_mask_is_tnl_gtpu_flex_parser_0(mask, dmn) || - dr_mask_is_tnl_gtpu_flex_parser_1(mask, dmn) || - dr_mask_is_tnl_gtpu(mask, dmn); -} - -static int dr_matcher_supp_icmp_v4(struct mlx5dr_cmd_caps *caps) -{ - return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || - (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V4_ENABLED); -} - -static int dr_matcher_supp_icmp_v6(struct mlx5dr_cmd_caps *caps) -{ - return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || - (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V6_ENABLED); -} - -static bool dr_mask_is_icmpv6_set(struct mlx5dr_match_misc3 *misc3) -{ - return (misc3->icmpv6_type || misc3->icmpv6_code || - misc3->icmpv6_header_data); -} - -static bool dr_mask_is_icmp(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - if (DR_MASK_IS_ICMPV4_SET(&mask->misc3)) - return dr_matcher_supp_icmp_v4(&dmn->info.caps); - else if (dr_mask_is_icmpv6_set(&mask->misc3)) - return dr_matcher_supp_icmp_v6(&dmn->info.caps); - - return false; -} - -static bool dr_mask_is_wqe_metadata_set(struct mlx5dr_match_misc2 *misc2) -{ - return misc2->metadata_reg_a; -} - -static bool dr_mask_is_reg_c_0_3_set(struct mlx5dr_match_misc2 *misc2) -{ - return (misc2->metadata_reg_c_0 || misc2->metadata_reg_c_1 || - misc2->metadata_reg_c_2 || misc2->metadata_reg_c_3); -} - -static bool dr_mask_is_reg_c_4_7_set(struct mlx5dr_match_misc2 *misc2) -{ - return (misc2->metadata_reg_c_4 || misc2->metadata_reg_c_5 || - misc2->metadata_reg_c_6 || misc2->metadata_reg_c_7); -} - -static bool dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc *misc) -{ - return (misc->source_sqn || misc->source_port); -} - -static bool dr_mask_is_flex_parser_id_0_3_set(u32 flex_parser_id, - u32 flex_parser_value) -{ - if (flex_parser_id) - return flex_parser_id <= DR_STE_MAX_FLEX_0_ID; - - /* Using flex_parser 0 means that id is zero, thus value must be set. */ - return flex_parser_value; -} - -static bool dr_mask_is_flex_parser_0_3_set(struct mlx5dr_match_misc4 *misc4) -{ - return (dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_0, - misc4->prog_sample_field_value_0) || - dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_1, - misc4->prog_sample_field_value_1) || - dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_2, - misc4->prog_sample_field_value_2) || - dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_3, - misc4->prog_sample_field_value_3)); -} - -static bool dr_mask_is_flex_parser_id_4_7_set(u32 flex_parser_id) -{ - return flex_parser_id > DR_STE_MAX_FLEX_0_ID && - flex_parser_id <= DR_STE_MAX_FLEX_1_ID; -} - -static bool dr_mask_is_flex_parser_4_7_set(struct mlx5dr_match_misc4 *misc4) -{ - return (dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_0) || - dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_1) || - dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_2) || - dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_3)); -} - -static int dr_matcher_supp_tnl_mpls_over_gre(struct mlx5dr_cmd_caps *caps) -{ - return caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED; -} - -static bool dr_mask_is_tnl_mpls_over_gre(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return DR_MASK_IS_OUTER_MPLS_OVER_GRE_SET(&mask->misc2) && - dr_matcher_supp_tnl_mpls_over_gre(&dmn->info.caps); -} - -static int dr_matcher_supp_tnl_mpls_over_udp(struct mlx5dr_cmd_caps *caps) -{ - return caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED; -} - -static bool dr_mask_is_tnl_mpls_over_udp(struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn) -{ - return DR_MASK_IS_OUTER_MPLS_OVER_UDP_SET(&mask->misc2) && - dr_matcher_supp_tnl_mpls_over_udp(&dmn->info.caps); -} - -static bool dr_mask_is_tnl_header_0_1_set(struct mlx5dr_match_misc5 *misc5) -{ - return misc5->tunnel_header_0 || misc5->tunnel_header_1; -} - -int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - enum mlx5dr_ipv outer_ipv, - enum mlx5dr_ipv inner_ipv) -{ - nic_matcher->ste_builder = - nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; - nic_matcher->num_of_builders = - nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv]; - - if (!nic_matcher->num_of_builders) { - mlx5dr_dbg(matcher->tbl->dmn, - "Rule not supported on this matcher due to IP related fields\n"); - return -EINVAL; - } - - return 0; -} - -static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - enum mlx5dr_ipv outer_ipv, - enum mlx5dr_ipv inner_ipv) -{ - struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; - struct mlx5dr_match_param mask = {}; - bool allow_empty_match = false; - struct mlx5dr_ste_build *sb; - bool inner, rx; - int idx = 0; - int ret, i; - - sb = nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; - rx = nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX; - - /* Create a temporary mask to track and clear used mask fields */ - if (matcher->match_criteria & DR_MATCHER_CRITERIA_OUTER) - mask.outer = matcher->mask.outer; - - if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC) - mask.misc = matcher->mask.misc; - - if (matcher->match_criteria & DR_MATCHER_CRITERIA_INNER) - mask.inner = matcher->mask.inner; - - if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC2) - mask.misc2 = matcher->mask.misc2; - - if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC3) - mask.misc3 = matcher->mask.misc3; - - if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC4) - mask.misc4 = matcher->mask.misc4; - - if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC5) - mask.misc5 = matcher->mask.misc5; - - ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria, - &matcher->mask, NULL); - if (ret) - return ret; - - /* Optimize RX pipe by reducing source port match, since - * the FDB RX part is connected only to the wire. - */ - if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB && - rx && mask.misc.source_port) { - mask.misc.source_port = 0; - mask.misc.source_eswitch_owner_vhca_id = 0; - allow_empty_match = true; - } - - /* Outer */ - if (matcher->match_criteria & (DR_MATCHER_CRITERIA_OUTER | - DR_MATCHER_CRITERIA_MISC | - DR_MATCHER_CRITERIA_MISC2 | - DR_MATCHER_CRITERIA_MISC3 | - DR_MATCHER_CRITERIA_MISC5)) { - inner = false; - - if (dr_mask_is_wqe_metadata_set(&mask.misc2)) - mlx5dr_ste_build_general_purpose(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (dr_mask_is_reg_c_0_3_set(&mask.misc2)) - mlx5dr_ste_build_register_0(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (dr_mask_is_reg_c_4_7_set(&mask.misc2)) - mlx5dr_ste_build_register_1(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (dr_mask_is_gvmi_or_qpn_set(&mask.misc) && - (dmn->type == MLX5DR_DOMAIN_TYPE_FDB || - dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX)) { - mlx5dr_ste_build_src_gvmi_qpn(ste_ctx, &sb[idx++], - &mask, dmn, inner, rx); - } - - if (dr_mask_is_smac_set(&mask.outer) && - dr_mask_is_dmac_set(&mask.outer)) { - mlx5dr_ste_build_eth_l2_src_dst(ste_ctx, &sb[idx++], - &mask, inner, rx); - } - - if (dr_mask_is_smac_set(&mask.outer)) - mlx5dr_ste_build_eth_l2_src(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer)) - mlx5dr_ste_build_eth_l2_dst(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (outer_ipv == DR_RULE_IPV6) { - if (DR_MASK_IS_DST_IP_SET(&mask.outer)) - mlx5dr_ste_build_eth_l3_ipv6_dst(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (DR_MASK_IS_SRC_IP_SET(&mask.outer)) - mlx5dr_ste_build_eth_l3_ipv6_src(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (DR_MASK_IS_ETH_L4_SET(mask.outer, mask.misc, outer)) - mlx5dr_ste_build_eth_ipv6_l3_l4(ste_ctx, &sb[idx++], - &mask, inner, rx); - } else { - if (dr_mask_is_ipv4_5_tuple_set(&mask.outer)) - mlx5dr_ste_build_eth_l3_ipv4_5_tuple(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (dr_mask_is_ttl_set(&mask.outer) || - dr_mask_is_ipv4_ihl_set(&mask.outer)) - mlx5dr_ste_build_eth_l3_ipv4_misc(ste_ctx, &sb[idx++], - &mask, inner, rx); - } - - if (dr_mask_is_tnl_vxlan_gpe(&mask, dmn)) - mlx5dr_ste_build_tnl_vxlan_gpe(ste_ctx, &sb[idx++], - &mask, inner, rx); - else if (dr_mask_is_tnl_geneve(&mask, dmn)) { - mlx5dr_ste_build_tnl_geneve(ste_ctx, &sb[idx++], - &mask, inner, rx); - if (dr_mask_is_tnl_geneve_tlv_opt(&mask.misc3)) - mlx5dr_ste_build_tnl_geneve_tlv_opt(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - if (dr_mask_is_tnl_geneve_tlv_opt_exist_set(&mask.misc, dmn)) - mlx5dr_ste_build_tnl_geneve_tlv_opt_exist(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - } else if (dr_mask_is_tnl_gtpu_any(&mask, dmn)) { - if (dr_mask_is_tnl_gtpu_flex_parser_0(&mask, dmn)) - mlx5dr_ste_build_tnl_gtpu_flex_parser_0(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - - if (dr_mask_is_tnl_gtpu_flex_parser_1(&mask, dmn)) - mlx5dr_ste_build_tnl_gtpu_flex_parser_1(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - - if (dr_mask_is_tnl_gtpu(&mask, dmn)) - mlx5dr_ste_build_tnl_gtpu(ste_ctx, &sb[idx++], - &mask, inner, rx); - } else if (dr_mask_is_tnl_header_0_1_set(&mask.misc5)) { - mlx5dr_ste_build_tnl_header_0_1(ste_ctx, &sb[idx++], - &mask, inner, rx); - } - - if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer)) - mlx5dr_ste_build_eth_l4_misc(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, outer)) - mlx5dr_ste_build_mpls(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (dr_mask_is_tnl_mpls_over_gre(&mask, dmn)) - mlx5dr_ste_build_tnl_mpls_over_gre(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - else if (dr_mask_is_tnl_mpls_over_udp(&mask, dmn)) - mlx5dr_ste_build_tnl_mpls_over_udp(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - - if (dr_mask_is_icmp(&mask, dmn)) - mlx5dr_ste_build_icmp(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - - if (dr_mask_is_tnl_gre_set(&mask.misc)) - mlx5dr_ste_build_tnl_gre(ste_ctx, &sb[idx++], - &mask, inner, rx); - } - - /* Inner */ - if (matcher->match_criteria & (DR_MATCHER_CRITERIA_INNER | - DR_MATCHER_CRITERIA_MISC | - DR_MATCHER_CRITERIA_MISC2 | - DR_MATCHER_CRITERIA_MISC3)) { - inner = true; - - if (dr_mask_is_eth_l2_tnl_set(&mask.misc)) - mlx5dr_ste_build_eth_l2_tnl(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (dr_mask_is_smac_set(&mask.inner) && - dr_mask_is_dmac_set(&mask.inner)) { - mlx5dr_ste_build_eth_l2_src_dst(ste_ctx, &sb[idx++], - &mask, inner, rx); - } - - if (dr_mask_is_smac_set(&mask.inner)) - mlx5dr_ste_build_eth_l2_src(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner)) - mlx5dr_ste_build_eth_l2_dst(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (inner_ipv == DR_RULE_IPV6) { - if (DR_MASK_IS_DST_IP_SET(&mask.inner)) - mlx5dr_ste_build_eth_l3_ipv6_dst(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (DR_MASK_IS_SRC_IP_SET(&mask.inner)) - mlx5dr_ste_build_eth_l3_ipv6_src(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (DR_MASK_IS_ETH_L4_SET(mask.inner, mask.misc, inner)) - mlx5dr_ste_build_eth_ipv6_l3_l4(ste_ctx, &sb[idx++], - &mask, inner, rx); - } else { - if (dr_mask_is_ipv4_5_tuple_set(&mask.inner)) - mlx5dr_ste_build_eth_l3_ipv4_5_tuple(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (dr_mask_is_ttl_set(&mask.inner) || - dr_mask_is_ipv4_ihl_set(&mask.inner)) - mlx5dr_ste_build_eth_l3_ipv4_misc(ste_ctx, &sb[idx++], - &mask, inner, rx); - } - - if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, inner)) - mlx5dr_ste_build_eth_l4_misc(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, inner)) - mlx5dr_ste_build_mpls(ste_ctx, &sb[idx++], - &mask, inner, rx); - - if (dr_mask_is_tnl_mpls_over_gre(&mask, dmn)) - mlx5dr_ste_build_tnl_mpls_over_gre(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - else if (dr_mask_is_tnl_mpls_over_udp(&mask, dmn)) - mlx5dr_ste_build_tnl_mpls_over_udp(ste_ctx, &sb[idx++], - &mask, &dmn->info.caps, - inner, rx); - } - - if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC4) { - if (dr_mask_is_flex_parser_0_3_set(&mask.misc4)) - mlx5dr_ste_build_flex_parser_0(ste_ctx, &sb[idx++], - &mask, false, rx); - - if (dr_mask_is_flex_parser_4_7_set(&mask.misc4)) - mlx5dr_ste_build_flex_parser_1(ste_ctx, &sb[idx++], - &mask, false, rx); - } - - /* Empty matcher, takes all */ - if ((!idx && allow_empty_match) || - matcher->match_criteria == DR_MATCHER_CRITERIA_EMPTY) - mlx5dr_ste_build_empty_always_hit(&sb[idx++], rx); - - if (idx == 0) { - mlx5dr_err(dmn, "Cannot generate any valid rules from mask\n"); - return -EINVAL; - } - - /* Check that all mask fields were consumed */ - for (i = 0; i < sizeof(struct mlx5dr_match_param); i++) { - if (((u8 *)&mask)[i] != 0) { - mlx5dr_dbg(dmn, "Mask contains unsupported parameters\n"); - return -EOPNOTSUPP; - } - } - - nic_matcher->ste_builder = sb; - nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv] = idx; - - return 0; -} - -static int dr_nic_matcher_connect(struct mlx5dr_domain *dmn, - struct mlx5dr_matcher_rx_tx *curr_nic_matcher, - struct mlx5dr_matcher_rx_tx *next_nic_matcher, - struct mlx5dr_matcher_rx_tx *prev_nic_matcher) -{ - struct mlx5dr_table_rx_tx *nic_tbl = curr_nic_matcher->nic_tbl; - struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; - struct mlx5dr_htbl_connect_info info; - struct mlx5dr_ste_htbl *prev_htbl; - int ret; - - /* Connect end anchor hash table to next_htbl or to the default address */ - if (next_nic_matcher) { - info.type = CONNECT_HIT; - info.hit_next_htbl = next_nic_matcher->s_htbl; - } else { - info.type = CONNECT_MISS; - info.miss_icm_addr = nic_tbl->default_icm_addr; - } - ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, - curr_nic_matcher->e_anchor, - &info, info.type == CONNECT_HIT); - if (ret) - return ret; - - /* Connect start hash table to end anchor */ - info.type = CONNECT_MISS; - info.miss_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(curr_nic_matcher->e_anchor->chunk); - ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, - curr_nic_matcher->s_htbl, - &info, false); - if (ret) - return ret; - - /* Connect previous hash table to matcher start hash table */ - if (prev_nic_matcher) - prev_htbl = prev_nic_matcher->e_anchor; - else - prev_htbl = nic_tbl->s_anchor; - - info.type = CONNECT_HIT; - info.hit_next_htbl = curr_nic_matcher->s_htbl; - ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_htbl, - &info, true); - if (ret) - return ret; - - /* Update the pointing ste and next hash table */ - curr_nic_matcher->s_htbl->pointing_ste = prev_htbl->chunk->ste_arr; - prev_htbl->chunk->ste_arr[0].next_htbl = curr_nic_matcher->s_htbl; - - if (next_nic_matcher) { - next_nic_matcher->s_htbl->pointing_ste = - curr_nic_matcher->e_anchor->chunk->ste_arr; - curr_nic_matcher->e_anchor->chunk->ste_arr[0].next_htbl = - next_nic_matcher->s_htbl; - } - - return 0; -} - -int mlx5dr_matcher_add_to_tbl_nic(struct mlx5dr_domain *dmn, - struct mlx5dr_matcher_rx_tx *nic_matcher) -{ - struct mlx5dr_matcher_rx_tx *next_nic_matcher, *prev_nic_matcher, *tmp_nic_matcher; - struct mlx5dr_table_rx_tx *nic_tbl = nic_matcher->nic_tbl; - bool first = true; - int ret; - - /* If the nic matcher is already on its parent nic table list, - * then it is already connected to the chain of nic matchers. - */ - if (!list_empty(&nic_matcher->list_node)) - return 0; - - next_nic_matcher = NULL; - list_for_each_entry(tmp_nic_matcher, &nic_tbl->nic_matcher_list, list_node) { - if (tmp_nic_matcher->prio >= nic_matcher->prio) { - next_nic_matcher = tmp_nic_matcher; - break; - } - first = false; - } - - prev_nic_matcher = NULL; - if (next_nic_matcher && !first) - prev_nic_matcher = list_prev_entry(next_nic_matcher, list_node); - else if (!first) - prev_nic_matcher = list_last_entry(&nic_tbl->nic_matcher_list, - struct mlx5dr_matcher_rx_tx, - list_node); - - ret = dr_nic_matcher_connect(dmn, nic_matcher, - next_nic_matcher, prev_nic_matcher); - if (ret) - return ret; - - if (prev_nic_matcher) - list_add(&nic_matcher->list_node, &prev_nic_matcher->list_node); - else if (next_nic_matcher) - list_add_tail(&nic_matcher->list_node, &next_nic_matcher->list_node); - else - list_add(&nic_matcher->list_node, &nic_matcher->nic_tbl->nic_matcher_list); - - return ret; -} - -static void dr_matcher_uninit_nic(struct mlx5dr_matcher_rx_tx *nic_matcher) -{ - mlx5dr_htbl_put(nic_matcher->s_htbl); - mlx5dr_htbl_put(nic_matcher->e_anchor); -} - -static void dr_matcher_uninit_fdb(struct mlx5dr_matcher *matcher) -{ - dr_matcher_uninit_nic(&matcher->rx); - dr_matcher_uninit_nic(&matcher->tx); -} - -static void dr_matcher_uninit(struct mlx5dr_matcher *matcher) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - - switch (dmn->type) { - case MLX5DR_DOMAIN_TYPE_NIC_RX: - dr_matcher_uninit_nic(&matcher->rx); - break; - case MLX5DR_DOMAIN_TYPE_NIC_TX: - dr_matcher_uninit_nic(&matcher->tx); - break; - case MLX5DR_DOMAIN_TYPE_FDB: - dr_matcher_uninit_fdb(matcher); - break; - default: - WARN_ON(true); - break; - } -} - -static int dr_matcher_set_all_ste_builders(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - - dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV4); - dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV6); - dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV4); - dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV6); - - if (!nic_matcher->ste_builder) { - mlx5dr_err(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n"); - return -EINVAL; - } - - return 0; -} - -static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - int ret; - - nic_matcher->prio = matcher->prio; - INIT_LIST_HEAD(&nic_matcher->list_node); - - ret = dr_matcher_set_all_ste_builders(matcher, nic_matcher); - if (ret) - return ret; - - nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, - DR_CHUNK_SIZE_1, - MLX5DR_STE_LU_TYPE_DONT_CARE, - 0); - if (!nic_matcher->e_anchor) - return -ENOMEM; - - nic_matcher->s_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, - DR_CHUNK_SIZE_1, - nic_matcher->ste_builder[0].lu_type, - nic_matcher->ste_builder[0].byte_mask); - if (!nic_matcher->s_htbl) { - ret = -ENOMEM; - goto free_e_htbl; - } - - /* make sure the tables exist while empty */ - mlx5dr_htbl_get(nic_matcher->s_htbl); - mlx5dr_htbl_get(nic_matcher->e_anchor); - - return 0; - -free_e_htbl: - mlx5dr_ste_htbl_free(nic_matcher->e_anchor); - return ret; -} - -static int dr_matcher_init_fdb(struct mlx5dr_matcher *matcher) -{ - int ret; - - ret = dr_matcher_init_nic(matcher, &matcher->rx); - if (ret) - return ret; - - ret = dr_matcher_init_nic(matcher, &matcher->tx); - if (ret) - goto uninit_nic_rx; - - return 0; - -uninit_nic_rx: - dr_matcher_uninit_nic(&matcher->rx); - return ret; -} - -static int dr_matcher_copy_param(struct mlx5dr_matcher *matcher, - struct mlx5dr_match_parameters *mask) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_match_parameters consumed_mask; - int i, ret = 0; - - if (matcher->match_criteria >= DR_MATCHER_CRITERIA_MAX) { - mlx5dr_err(dmn, "Invalid match criteria attribute\n"); - return -EINVAL; - } - - if (mask) { - if (mask->match_sz > DR_SZ_MATCH_PARAM) { - mlx5dr_err(dmn, "Invalid match size attribute\n"); - return -EINVAL; - } - - consumed_mask.match_buf = kzalloc(mask->match_sz, GFP_KERNEL); - if (!consumed_mask.match_buf) - return -ENOMEM; - - consumed_mask.match_sz = mask->match_sz; - memcpy(consumed_mask.match_buf, mask->match_buf, mask->match_sz); - mlx5dr_ste_copy_param(matcher->match_criteria, - &matcher->mask, &consumed_mask, true); - - /* Check that all mask data was consumed */ - for (i = 0; i < consumed_mask.match_sz; i++) { - if (!((u8 *)consumed_mask.match_buf)[i]) - continue; - - mlx5dr_dbg(dmn, - "Match param mask contains unsupported parameters\n"); - ret = -EOPNOTSUPP; - break; - } - - kfree(consumed_mask.match_buf); - } - - return ret; -} - -static int dr_matcher_init(struct mlx5dr_matcher *matcher, - struct mlx5dr_match_parameters *mask) -{ - struct mlx5dr_table *tbl = matcher->tbl; - struct mlx5dr_domain *dmn = tbl->dmn; - int ret; - - ret = dr_matcher_copy_param(matcher, mask); - if (ret) - return ret; - - switch (dmn->type) { - case MLX5DR_DOMAIN_TYPE_NIC_RX: - matcher->rx.nic_tbl = &tbl->rx; - ret = dr_matcher_init_nic(matcher, &matcher->rx); - break; - case MLX5DR_DOMAIN_TYPE_NIC_TX: - matcher->tx.nic_tbl = &tbl->tx; - ret = dr_matcher_init_nic(matcher, &matcher->tx); - break; - case MLX5DR_DOMAIN_TYPE_FDB: - matcher->rx.nic_tbl = &tbl->rx; - matcher->tx.nic_tbl = &tbl->tx; - ret = dr_matcher_init_fdb(matcher); - break; - default: - WARN_ON(true); - ret = -EINVAL; - } - - return ret; -} - -static void dr_matcher_add_to_dbg_list(struct mlx5dr_matcher *matcher) -{ - mutex_lock(&matcher->tbl->dmn->dump_info.dbg_mutex); - list_add(&matcher->list_node, &matcher->tbl->matcher_list); - mutex_unlock(&matcher->tbl->dmn->dump_info.dbg_mutex); -} - -static void dr_matcher_remove_from_dbg_list(struct mlx5dr_matcher *matcher) -{ - mutex_lock(&matcher->tbl->dmn->dump_info.dbg_mutex); - list_del(&matcher->list_node); - mutex_unlock(&matcher->tbl->dmn->dump_info.dbg_mutex); -} - -struct mlx5dr_matcher * -mlx5dr_matcher_create(struct mlx5dr_table *tbl, - u32 priority, - u8 match_criteria_enable, - struct mlx5dr_match_parameters *mask) -{ - struct mlx5dr_matcher *matcher; - int ret; - - refcount_inc(&tbl->refcount); - - matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); - if (!matcher) - goto dec_ref; - - matcher->tbl = tbl; - matcher->prio = priority; - matcher->match_criteria = match_criteria_enable; - refcount_set(&matcher->refcount, 1); - INIT_LIST_HEAD(&matcher->list_node); - INIT_LIST_HEAD(&matcher->dbg_rule_list); - - mlx5dr_domain_lock(tbl->dmn); - - ret = dr_matcher_init(matcher, mask); - if (ret) - goto free_matcher; - - dr_matcher_add_to_dbg_list(matcher); - - mlx5dr_domain_unlock(tbl->dmn); - - return matcher; - -free_matcher: - mlx5dr_domain_unlock(tbl->dmn); - kfree(matcher); -dec_ref: - refcount_dec(&tbl->refcount); - return NULL; -} - -static int dr_matcher_disconnect_nic(struct mlx5dr_domain *dmn, - struct mlx5dr_table_rx_tx *nic_tbl, - struct mlx5dr_matcher_rx_tx *next_nic_matcher, - struct mlx5dr_matcher_rx_tx *prev_nic_matcher) -{ - struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; - struct mlx5dr_htbl_connect_info info; - struct mlx5dr_ste_htbl *prev_anchor; - - if (prev_nic_matcher) - prev_anchor = prev_nic_matcher->e_anchor; - else - prev_anchor = nic_tbl->s_anchor; - - /* Connect previous anchor hash table to next matcher or to the default address */ - if (next_nic_matcher) { - info.type = CONNECT_HIT; - info.hit_next_htbl = next_nic_matcher->s_htbl; - next_nic_matcher->s_htbl->pointing_ste = prev_anchor->chunk->ste_arr; - prev_anchor->chunk->ste_arr[0].next_htbl = next_nic_matcher->s_htbl; - } else { - info.type = CONNECT_MISS; - info.miss_icm_addr = nic_tbl->default_icm_addr; - prev_anchor->chunk->ste_arr[0].next_htbl = NULL; - } - - return mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_anchor, - &info, true); -} - -int mlx5dr_matcher_remove_from_tbl_nic(struct mlx5dr_domain *dmn, - struct mlx5dr_matcher_rx_tx *nic_matcher) -{ - struct mlx5dr_matcher_rx_tx *prev_nic_matcher, *next_nic_matcher; - struct mlx5dr_table_rx_tx *nic_tbl = nic_matcher->nic_tbl; - int ret; - - /* If the nic matcher is not on its parent nic table list, - * then it is detached - no need to disconnect it. - */ - if (list_empty(&nic_matcher->list_node)) - return 0; - - if (list_is_last(&nic_matcher->list_node, &nic_tbl->nic_matcher_list)) - next_nic_matcher = NULL; - else - next_nic_matcher = list_next_entry(nic_matcher, list_node); - - if (nic_matcher->list_node.prev == &nic_tbl->nic_matcher_list) - prev_nic_matcher = NULL; - else - prev_nic_matcher = list_prev_entry(nic_matcher, list_node); - - ret = dr_matcher_disconnect_nic(dmn, nic_tbl, next_nic_matcher, prev_nic_matcher); - if (ret) - return ret; - - list_del_init(&nic_matcher->list_node); - return 0; -} - -int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher) -{ - struct mlx5dr_table *tbl = matcher->tbl; - - if (WARN_ON_ONCE(refcount_read(&matcher->refcount) > 1)) - return -EBUSY; - - mlx5dr_domain_lock(tbl->dmn); - - dr_matcher_remove_from_dbg_list(matcher); - dr_matcher_uninit(matcher); - refcount_dec(&matcher->tbl->refcount); - - mlx5dr_domain_unlock(tbl->dmn); - kfree(matcher); - - return 0; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c deleted file mode 100644 index 8ca534ef5d0316..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - -#include "dr_types.h" -#include "mlx5_ifc_dr_ste_v1.h" - -enum dr_ptrn_modify_hdr_action_id { - DR_PTRN_MODIFY_HDR_ACTION_ID_NOP = 0x00, - DR_PTRN_MODIFY_HDR_ACTION_ID_COPY = 0x05, - DR_PTRN_MODIFY_HDR_ACTION_ID_SET = 0x06, - DR_PTRN_MODIFY_HDR_ACTION_ID_ADD = 0x07, - DR_PTRN_MODIFY_HDR_ACTION_ID_INSERT_INLINE = 0x0a, -}; - -struct mlx5dr_ptrn_mgr { - struct mlx5dr_domain *dmn; - struct mlx5dr_icm_pool *ptrn_icm_pool; - /* cache for modify_header ptrn */ - struct list_head ptrn_list; - struct mutex modify_hdr_mutex; /* protect the pattern cache */ -}; - -/* Cache structure and functions */ -static bool dr_ptrn_compare_modify_hdr(size_t cur_num_of_actions, - __be64 cur_hw_actions[], - size_t num_of_actions, - __be64 hw_actions[]) -{ - int i; - - if (cur_num_of_actions != num_of_actions) - return false; - - for (i = 0; i < num_of_actions; i++) { - u8 action_id = - MLX5_GET(ste_double_action_set_v1, &hw_actions[i], action_id); - - if (action_id == DR_PTRN_MODIFY_HDR_ACTION_ID_COPY) { - if (hw_actions[i] != cur_hw_actions[i]) - return false; - } else { - if ((__force __be32)hw_actions[i] != - (__force __be32)cur_hw_actions[i]) - return false; - } - } - - return true; -} - -static struct mlx5dr_ptrn_obj * -dr_ptrn_find_cached_pattern(struct mlx5dr_ptrn_mgr *mgr, - size_t num_of_actions, - __be64 hw_actions[]) -{ - struct mlx5dr_ptrn_obj *cached_pattern; - struct mlx5dr_ptrn_obj *tmp; - - list_for_each_entry_safe(cached_pattern, tmp, &mgr->ptrn_list, list) { - if (dr_ptrn_compare_modify_hdr(cached_pattern->num_of_actions, - (__be64 *)cached_pattern->data, - num_of_actions, - hw_actions)) { - /* Put this pattern in the head of the list, - * as we will probably use it more. - */ - list_del_init(&cached_pattern->list); - list_add(&cached_pattern->list, &mgr->ptrn_list); - return cached_pattern; - } - } - - return NULL; -} - -static struct mlx5dr_ptrn_obj * -dr_ptrn_alloc_pattern(struct mlx5dr_ptrn_mgr *mgr, - u16 num_of_actions, u8 *data) -{ - struct mlx5dr_ptrn_obj *pattern; - struct mlx5dr_icm_chunk *chunk; - u32 chunk_size; - u32 index; - - chunk_size = ilog2(roundup_pow_of_two(num_of_actions)); - /* HW modify action index granularity is at least 64B */ - chunk_size = max_t(u32, chunk_size, DR_CHUNK_SIZE_8); - - chunk = mlx5dr_icm_alloc_chunk(mgr->ptrn_icm_pool, chunk_size); - if (!chunk) - return NULL; - - index = (mlx5dr_icm_pool_get_chunk_icm_addr(chunk) - - mgr->dmn->info.caps.hdr_modify_pattern_icm_addr) / - DR_ACTION_CACHE_LINE_SIZE; - - pattern = kzalloc(sizeof(*pattern), GFP_KERNEL); - if (!pattern) - goto free_chunk; - - pattern->data = kzalloc(num_of_actions * DR_MODIFY_ACTION_SIZE * - sizeof(*pattern->data), GFP_KERNEL); - if (!pattern->data) - goto free_pattern; - - memcpy(pattern->data, data, num_of_actions * DR_MODIFY_ACTION_SIZE); - pattern->chunk = chunk; - pattern->index = index; - pattern->num_of_actions = num_of_actions; - - list_add(&pattern->list, &mgr->ptrn_list); - refcount_set(&pattern->refcount, 1); - - return pattern; - -free_pattern: - kfree(pattern); -free_chunk: - mlx5dr_icm_free_chunk(chunk); - return NULL; -} - -static void -dr_ptrn_free_pattern(struct mlx5dr_ptrn_obj *pattern) -{ - list_del(&pattern->list); - mlx5dr_icm_free_chunk(pattern->chunk); - kfree(pattern->data); - kfree(pattern); -} - -struct mlx5dr_ptrn_obj * -mlx5dr_ptrn_cache_get_pattern(struct mlx5dr_ptrn_mgr *mgr, - u16 num_of_actions, - u8 *data) -{ - struct mlx5dr_ptrn_obj *pattern; - u64 *hw_actions; - u8 action_id; - int i; - - mutex_lock(&mgr->modify_hdr_mutex); - pattern = dr_ptrn_find_cached_pattern(mgr, - num_of_actions, - (__be64 *)data); - if (!pattern) { - /* Alloc and add new pattern to cache */ - pattern = dr_ptrn_alloc_pattern(mgr, num_of_actions, data); - if (!pattern) - goto out_unlock; - - hw_actions = (u64 *)pattern->data; - /* Here we mask the pattern data to create a valid pattern - * since we do an OR operation between the arg and pattern - */ - for (i = 0; i < num_of_actions; i++) { - action_id = MLX5_GET(ste_double_action_set_v1, &hw_actions[i], action_id); - - if (action_id == DR_PTRN_MODIFY_HDR_ACTION_ID_SET || - action_id == DR_PTRN_MODIFY_HDR_ACTION_ID_ADD || - action_id == DR_PTRN_MODIFY_HDR_ACTION_ID_INSERT_INLINE) - MLX5_SET(ste_double_action_set_v1, &hw_actions[i], inline_data, 0); - } - - if (mlx5dr_send_postsend_pattern(mgr->dmn, pattern->chunk, - num_of_actions, pattern->data)) { - refcount_dec(&pattern->refcount); - goto free_pattern; - } - } else { - refcount_inc(&pattern->refcount); - } - - mutex_unlock(&mgr->modify_hdr_mutex); - - return pattern; - -free_pattern: - dr_ptrn_free_pattern(pattern); -out_unlock: - mutex_unlock(&mgr->modify_hdr_mutex); - return NULL; -} - -void -mlx5dr_ptrn_cache_put_pattern(struct mlx5dr_ptrn_mgr *mgr, - struct mlx5dr_ptrn_obj *pattern) -{ - mutex_lock(&mgr->modify_hdr_mutex); - - if (refcount_dec_and_test(&pattern->refcount)) - dr_ptrn_free_pattern(pattern); - - mutex_unlock(&mgr->modify_hdr_mutex); -} - -struct mlx5dr_ptrn_mgr *mlx5dr_ptrn_mgr_create(struct mlx5dr_domain *dmn) -{ - struct mlx5dr_ptrn_mgr *mgr; - - if (!mlx5dr_domain_is_support_ptrn_arg(dmn)) - return NULL; - - mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); - if (!mgr) - return NULL; - - mgr->dmn = dmn; - mgr->ptrn_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_MODIFY_HDR_PTRN); - if (!mgr->ptrn_icm_pool) { - mlx5dr_err(dmn, "Couldn't get modify-header-pattern memory\n"); - goto free_mgr; - } - - INIT_LIST_HEAD(&mgr->ptrn_list); - mutex_init(&mgr->modify_hdr_mutex); - - return mgr; - -free_mgr: - kfree(mgr); - return NULL; -} - -void mlx5dr_ptrn_mgr_destroy(struct mlx5dr_ptrn_mgr *mgr) -{ - struct mlx5dr_ptrn_obj *pattern; - struct mlx5dr_ptrn_obj *tmp; - - if (!mgr) - return; - - WARN_ON(!list_empty(&mgr->ptrn_list)); - - list_for_each_entry_safe(pattern, tmp, &mgr->ptrn_list, list) { - list_del(&pattern->list); - kfree(pattern->data); - kfree(pattern); - } - - 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_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c deleted file mode 100644 index d1db04baa1fa6f..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c +++ /dev/null @@ -1,1377 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include "dr_types.h" - -#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN < 2048) -/* don't try to optimize STE allocation if the stack is too constaraining */ -#define DR_RULE_MAX_STES_OPTIMIZED 0 -#else -#define DR_RULE_MAX_STES_OPTIMIZED 2 -#endif -#define DR_RULE_MAX_STE_CHAIN_OPTIMIZED (DR_RULE_MAX_STES_OPTIMIZED + DR_ACTION_MAX_STES) - -static int dr_rule_append_to_miss_list(struct mlx5dr_domain *dmn, - enum mlx5dr_domain_nic_type nic_type, - struct mlx5dr_ste *new_last_ste, - struct list_head *miss_list, - struct list_head *send_list) -{ - struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; - struct mlx5dr_ste_send_info *ste_info_last; - struct mlx5dr_ste *last_ste; - - /* The new entry will be inserted after the last */ - last_ste = list_last_entry(miss_list, struct mlx5dr_ste, miss_list_node); - WARN_ON(!last_ste); - - ste_info_last = mlx5dr_send_info_alloc(dmn, nic_type); - if (!ste_info_last) - return -ENOMEM; - - mlx5dr_ste_set_miss_addr(ste_ctx, mlx5dr_ste_get_hw_ste(last_ste), - mlx5dr_ste_get_icm_addr(new_last_ste)); - list_add_tail(&new_last_ste->miss_list_node, miss_list); - - mlx5dr_send_fill_and_append_ste_send_info(last_ste, DR_STE_SIZE_CTRL, - 0, mlx5dr_ste_get_hw_ste(last_ste), - ste_info_last, send_list, true); - - return 0; -} - -static void dr_rule_set_last_ste_miss_addr(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - u8 *hw_ste) -{ - struct mlx5dr_ste_ctx *ste_ctx = matcher->tbl->dmn->ste_ctx; - u64 icm_addr; - - if (mlx5dr_ste_is_miss_addr_set(ste_ctx, hw_ste)) - return; - - icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk); - mlx5dr_ste_set_miss_addr(ste_ctx, hw_ste, icm_addr); -} - -static struct mlx5dr_ste * -dr_rule_create_collision_htbl(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - u8 *hw_ste) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste_htbl *new_htbl; - struct mlx5dr_ste *ste; - - /* Create new table for miss entry */ - new_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, - DR_CHUNK_SIZE_1, - MLX5DR_STE_LU_TYPE_DONT_CARE, - 0); - if (!new_htbl) { - mlx5dr_dbg(dmn, "Failed allocating collision table\n"); - return NULL; - } - - /* One and only entry, never grows */ - ste = new_htbl->chunk->ste_arr; - dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste); - mlx5dr_htbl_get(new_htbl); - - return ste; -} - -static struct mlx5dr_ste * -dr_rule_create_collision_entry(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - u8 *hw_ste, - struct mlx5dr_ste *orig_ste) -{ - struct mlx5dr_ste *ste; - - ste = dr_rule_create_collision_htbl(matcher, nic_matcher, hw_ste); - if (!ste) { - mlx5dr_dbg(matcher->tbl->dmn, "Failed creating collision entry\n"); - return NULL; - } - - ste->ste_chain_location = orig_ste->ste_chain_location; - ste->htbl->pointing_ste = orig_ste->htbl->pointing_ste; - - /* In collision entry, all members share the same miss_list_head */ - ste->htbl->chunk->miss_list = mlx5dr_ste_get_miss_list(orig_ste); - - /* Next table */ - if (mlx5dr_ste_create_next_htbl(matcher, nic_matcher, ste, hw_ste, - DR_CHUNK_SIZE_1)) { - mlx5dr_dbg(matcher->tbl->dmn, "Failed allocating table\n"); - goto free_tbl; - } - - return ste; - -free_tbl: - mlx5dr_ste_free(ste, matcher, nic_matcher); - return NULL; -} - -static int -dr_rule_handle_one_ste_in_update_list(struct mlx5dr_ste_send_info *ste_info, - struct mlx5dr_domain *dmn) -{ - int ret; - - list_del(&ste_info->send_list); - - /* Copy data to ste, only reduced size or control, the last 16B (mask) - * is already written to the hw. - */ - if (ste_info->size == DR_STE_SIZE_CTRL) - memcpy(mlx5dr_ste_get_hw_ste(ste_info->ste), - ste_info->data, DR_STE_SIZE_CTRL); - else - memcpy(mlx5dr_ste_get_hw_ste(ste_info->ste), - ste_info->data, DR_STE_SIZE_REDUCED); - - ret = mlx5dr_send_postsend_ste(dmn, ste_info->ste, ste_info->data, - ste_info->size, ste_info->offset); - if (ret) - goto out; - -out: - mlx5dr_send_info_free(ste_info); - return ret; -} - -static int dr_rule_send_update_list(struct list_head *send_ste_list, - struct mlx5dr_domain *dmn, - bool is_reverse) -{ - struct mlx5dr_ste_send_info *ste_info, *tmp_ste_info; - int ret; - - if (is_reverse) { - list_for_each_entry_safe_reverse(ste_info, tmp_ste_info, - send_ste_list, send_list) { - ret = dr_rule_handle_one_ste_in_update_list(ste_info, - dmn); - if (ret) - return ret; - } - } else { - list_for_each_entry_safe(ste_info, tmp_ste_info, - send_ste_list, send_list) { - ret = dr_rule_handle_one_ste_in_update_list(ste_info, - dmn); - if (ret) - return ret; - } - } - - return 0; -} - -static struct mlx5dr_ste * -dr_rule_find_ste_in_miss_list(struct list_head *miss_list, u8 *hw_ste) -{ - struct mlx5dr_ste *ste; - - if (list_empty(miss_list)) - return NULL; - - /* Check if hw_ste is present in the list */ - list_for_each_entry(ste, miss_list, miss_list_node) { - if (mlx5dr_ste_equal_tag(mlx5dr_ste_get_hw_ste(ste), hw_ste)) - return ste; - } - - return NULL; -} - -static struct mlx5dr_ste * -dr_rule_rehash_handle_collision(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct list_head *update_list, - struct mlx5dr_ste *col_ste, - u8 *hw_ste) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste *new_ste; - int ret; - - new_ste = dr_rule_create_collision_htbl(matcher, nic_matcher, hw_ste); - if (!new_ste) - return NULL; - - /* Update collision pointing STE */ - new_ste->htbl->pointing_ste = col_ste->htbl->pointing_ste; - - /* In collision entry, all members share the same miss_list_head */ - new_ste->htbl->chunk->miss_list = mlx5dr_ste_get_miss_list(col_ste); - - /* Update the previous from the list */ - ret = dr_rule_append_to_miss_list(dmn, nic_matcher->nic_tbl->nic_dmn->type, - new_ste, mlx5dr_ste_get_miss_list(col_ste), - update_list); - if (ret) { - mlx5dr_dbg(dmn, "Failed update dup entry\n"); - goto err_exit; - } - - return new_ste; - -err_exit: - mlx5dr_ste_free(new_ste, matcher, nic_matcher); - return NULL; -} - -static void dr_rule_rehash_copy_ste_ctrl(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste *cur_ste, - struct mlx5dr_ste *new_ste) -{ - new_ste->next_htbl = cur_ste->next_htbl; - new_ste->ste_chain_location = cur_ste->ste_chain_location; - - if (new_ste->next_htbl) - new_ste->next_htbl->pointing_ste = new_ste; - - /* We need to copy the refcount since this ste - * may have been traversed several times - */ - new_ste->refcount = cur_ste->refcount; - - /* Link old STEs rule to the new ste */ - mlx5dr_rule_set_last_member(cur_ste->rule_rx_tx, new_ste, false); -} - -static struct mlx5dr_ste * -dr_rule_rehash_copy_ste(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste *cur_ste, - struct mlx5dr_ste_htbl *new_htbl, - struct list_head *update_list) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste_send_info *ste_info; - bool use_update_list = false; - u8 hw_ste[DR_STE_SIZE] = {}; - struct mlx5dr_ste *new_ste; - int new_idx; - u8 sb_idx; - - /* Copy STE mask from the matcher */ - sb_idx = cur_ste->ste_chain_location - 1; - mlx5dr_ste_set_bit_mask(hw_ste, nic_matcher->ste_builder[sb_idx].bit_mask); - - /* Copy STE control and tag */ - memcpy(hw_ste, mlx5dr_ste_get_hw_ste(cur_ste), DR_STE_SIZE_REDUCED); - dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste); - - new_idx = mlx5dr_ste_calc_hash_index(hw_ste, new_htbl); - new_ste = &new_htbl->chunk->ste_arr[new_idx]; - - if (mlx5dr_ste_is_not_used(new_ste)) { - mlx5dr_htbl_get(new_htbl); - list_add_tail(&new_ste->miss_list_node, - mlx5dr_ste_get_miss_list(new_ste)); - } else { - new_ste = dr_rule_rehash_handle_collision(matcher, - nic_matcher, - update_list, - new_ste, - hw_ste); - if (!new_ste) { - mlx5dr_dbg(dmn, "Failed adding collision entry, index: %d\n", - new_idx); - return NULL; - } - new_htbl->ctrl.num_of_collisions++; - use_update_list = true; - } - - memcpy(mlx5dr_ste_get_hw_ste(new_ste), hw_ste, DR_STE_SIZE_REDUCED); - - new_htbl->ctrl.num_of_valid_entries++; - - if (use_update_list) { - ste_info = mlx5dr_send_info_alloc(dmn, - nic_matcher->nic_tbl->nic_dmn->type); - if (!ste_info) - goto err_exit; - - mlx5dr_send_fill_and_append_ste_send_info(new_ste, DR_STE_SIZE, 0, - hw_ste, ste_info, - update_list, true); - } - - dr_rule_rehash_copy_ste_ctrl(matcher, nic_matcher, cur_ste, new_ste); - - return new_ste; - -err_exit: - mlx5dr_ste_free(new_ste, matcher, nic_matcher); - return NULL; -} - -static int dr_rule_rehash_copy_miss_list(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct list_head *cur_miss_list, - struct mlx5dr_ste_htbl *new_htbl, - struct list_head *update_list) -{ - struct mlx5dr_ste *tmp_ste, *cur_ste, *new_ste; - - if (list_empty(cur_miss_list)) - return 0; - - list_for_each_entry_safe(cur_ste, tmp_ste, cur_miss_list, miss_list_node) { - new_ste = dr_rule_rehash_copy_ste(matcher, - nic_matcher, - cur_ste, - new_htbl, - update_list); - if (!new_ste) - goto err_insert; - - list_del(&cur_ste->miss_list_node); - mlx5dr_htbl_put(cur_ste->htbl); - } - return 0; - -err_insert: - mlx5dr_err(matcher->tbl->dmn, "Fatal error during resize\n"); - WARN_ON(true); - return -EINVAL; -} - -static int dr_rule_rehash_copy_htbl(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste_htbl *cur_htbl, - struct mlx5dr_ste_htbl *new_htbl, - struct list_head *update_list) -{ - struct mlx5dr_ste *cur_ste; - int cur_entries; - int err = 0; - int i; - - cur_entries = mlx5dr_icm_pool_chunk_size_to_entries(cur_htbl->chunk->size); - - if (cur_entries < 1) { - mlx5dr_dbg(matcher->tbl->dmn, "Invalid number of entries\n"); - return -EINVAL; - } - - for (i = 0; i < cur_entries; i++) { - cur_ste = &cur_htbl->chunk->ste_arr[i]; - if (mlx5dr_ste_is_not_used(cur_ste)) /* Empty, nothing to copy */ - continue; - - err = dr_rule_rehash_copy_miss_list(matcher, - nic_matcher, - mlx5dr_ste_get_miss_list(cur_ste), - new_htbl, - update_list); - if (err) - goto clean_copy; - - /* In order to decrease the number of allocated ste_send_info - * structs, send the current table row now. - */ - err = dr_rule_send_update_list(update_list, matcher->tbl->dmn, false); - if (err) { - mlx5dr_dbg(matcher->tbl->dmn, "Failed updating table to HW\n"); - goto clean_copy; - } - } - -clean_copy: - return err; -} - -static struct mlx5dr_ste_htbl * -dr_rule_rehash_htbl(struct mlx5dr_rule *rule, - struct mlx5dr_rule_rx_tx *nic_rule, - struct mlx5dr_ste_htbl *cur_htbl, - u8 ste_location, - struct list_head *update_list, - enum mlx5dr_icm_chunk_size new_size) -{ - struct mlx5dr_ste_send_info *del_ste_info, *tmp_ste_info; - struct mlx5dr_matcher *matcher = rule->matcher; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_matcher_rx_tx *nic_matcher; - struct mlx5dr_ste_send_info *ste_info; - struct mlx5dr_htbl_connect_info info; - struct mlx5dr_domain_rx_tx *nic_dmn; - u8 formatted_ste[DR_STE_SIZE] = {}; - LIST_HEAD(rehash_table_send_list); - struct mlx5dr_ste *ste_to_update; - struct mlx5dr_ste_htbl *new_htbl; - int err; - - nic_matcher = nic_rule->nic_matcher; - nic_dmn = nic_matcher->nic_tbl->nic_dmn; - - ste_info = mlx5dr_send_info_alloc(dmn, - nic_matcher->nic_tbl->nic_dmn->type); - if (!ste_info) - return NULL; - - new_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, - new_size, - cur_htbl->lu_type, - cur_htbl->byte_mask); - if (!new_htbl) { - mlx5dr_err(dmn, "Failed to allocate new hash table\n"); - goto free_ste_info; - } - - /* Write new table to HW */ - info.type = CONNECT_MISS; - info.miss_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk); - mlx5dr_ste_set_formatted_ste(dmn->ste_ctx, - dmn->info.caps.gvmi, - nic_dmn->type, - new_htbl, - formatted_ste, - &info); - - new_htbl->pointing_ste = cur_htbl->pointing_ste; - new_htbl->pointing_ste->next_htbl = new_htbl; - err = dr_rule_rehash_copy_htbl(matcher, - nic_matcher, - cur_htbl, - new_htbl, - &rehash_table_send_list); - if (err) - goto free_new_htbl; - - if (mlx5dr_send_postsend_htbl(dmn, new_htbl, formatted_ste, - nic_matcher->ste_builder[ste_location - 1].bit_mask)) { - mlx5dr_err(dmn, "Failed writing table to HW\n"); - goto free_new_htbl; - } - - /* Writing to the hw is done in regular order of rehash_table_send_list, - * in order to have the origin data written before the miss address of - * collision entries, if exists. - */ - if (dr_rule_send_update_list(&rehash_table_send_list, dmn, false)) { - mlx5dr_err(dmn, "Failed updating table to HW\n"); - goto free_ste_list; - } - - /* Connect previous hash table to current */ - if (ste_location == 1) { - /* The previous table is an anchor, anchors size is always one STE */ - struct mlx5dr_ste_htbl *prev_htbl = cur_htbl->pointing_ste->htbl; - - /* On matcher s_anchor we keep an extra refcount */ - mlx5dr_htbl_get(new_htbl); - mlx5dr_htbl_put(cur_htbl); - - nic_matcher->s_htbl = new_htbl; - - /* It is safe to operate dr_ste_set_hit_addr on the hw_ste here - * (48B len) which works only on first 32B - */ - mlx5dr_ste_set_hit_addr(dmn->ste_ctx, - prev_htbl->chunk->hw_ste_arr, - mlx5dr_icm_pool_get_chunk_icm_addr(new_htbl->chunk), - mlx5dr_icm_pool_get_chunk_num_of_entries(new_htbl->chunk)); - - ste_to_update = &prev_htbl->chunk->ste_arr[0]; - } else { - mlx5dr_ste_set_hit_addr_by_next_htbl(dmn->ste_ctx, - mlx5dr_ste_get_hw_ste(cur_htbl->pointing_ste), - new_htbl); - ste_to_update = cur_htbl->pointing_ste; - } - - mlx5dr_send_fill_and_append_ste_send_info(ste_to_update, DR_STE_SIZE_CTRL, - 0, mlx5dr_ste_get_hw_ste(ste_to_update), - ste_info, update_list, false); - - return new_htbl; - -free_ste_list: - /* Clean all ste_info's from the new table */ - list_for_each_entry_safe(del_ste_info, tmp_ste_info, - &rehash_table_send_list, send_list) { - list_del(&del_ste_info->send_list); - mlx5dr_send_info_free(del_ste_info); - } - -free_new_htbl: - mlx5dr_ste_htbl_free(new_htbl); -free_ste_info: - mlx5dr_send_info_free(ste_info); - mlx5dr_info(dmn, "Failed creating rehash table\n"); - return NULL; -} - -static struct mlx5dr_ste_htbl *dr_rule_rehash(struct mlx5dr_rule *rule, - struct mlx5dr_rule_rx_tx *nic_rule, - struct mlx5dr_ste_htbl *cur_htbl, - u8 ste_location, - struct list_head *update_list) -{ - struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; - enum mlx5dr_icm_chunk_size new_size; - - new_size = mlx5dr_icm_next_higher_chunk(cur_htbl->chunk->size); - new_size = min_t(u32, new_size, dmn->info.max_log_sw_icm_sz); - - if (new_size == cur_htbl->chunk->size) - return NULL; /* Skip rehash, we already at the max size */ - - return dr_rule_rehash_htbl(rule, nic_rule, cur_htbl, ste_location, - update_list, new_size); -} - -static struct mlx5dr_ste * -dr_rule_handle_collision(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste *ste, - u8 *hw_ste, - struct list_head *miss_list, - struct list_head *send_list) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste_send_info *ste_info; - struct mlx5dr_ste *new_ste; - - ste_info = mlx5dr_send_info_alloc(dmn, - nic_matcher->nic_tbl->nic_dmn->type); - if (!ste_info) - return NULL; - - new_ste = dr_rule_create_collision_entry(matcher, nic_matcher, hw_ste, ste); - if (!new_ste) - goto free_send_info; - - if (dr_rule_append_to_miss_list(dmn, nic_matcher->nic_tbl->nic_dmn->type, - new_ste, miss_list, send_list)) { - mlx5dr_dbg(dmn, "Failed to update prev miss_list\n"); - goto err_exit; - } - - mlx5dr_send_fill_and_append_ste_send_info(new_ste, DR_STE_SIZE, 0, hw_ste, - ste_info, send_list, false); - - ste->htbl->ctrl.num_of_collisions++; - ste->htbl->ctrl.num_of_valid_entries++; - - return new_ste; - -err_exit: - mlx5dr_ste_free(new_ste, matcher, nic_matcher); -free_send_info: - mlx5dr_send_info_free(ste_info); - return NULL; -} - -static void dr_rule_remove_action_members(struct mlx5dr_rule *rule) -{ - struct mlx5dr_rule_action_member *action_mem; - struct mlx5dr_rule_action_member *tmp; - - list_for_each_entry_safe(action_mem, tmp, &rule->rule_actions_list, list) { - list_del(&action_mem->list); - refcount_dec(&action_mem->action->refcount); - kvfree(action_mem); - } -} - -static int dr_rule_add_action_members(struct mlx5dr_rule *rule, - size_t num_actions, - struct mlx5dr_action *actions[]) -{ - struct mlx5dr_rule_action_member *action_mem; - int i; - - for (i = 0; i < num_actions; i++) { - action_mem = kvzalloc(sizeof(*action_mem), GFP_KERNEL); - if (!action_mem) - goto free_action_members; - - action_mem->action = actions[i]; - INIT_LIST_HEAD(&action_mem->list); - list_add_tail(&action_mem->list, &rule->rule_actions_list); - refcount_inc(&action_mem->action->refcount); - } - - return 0; - -free_action_members: - dr_rule_remove_action_members(rule); - return -ENOMEM; -} - -void mlx5dr_rule_set_last_member(struct mlx5dr_rule_rx_tx *nic_rule, - struct mlx5dr_ste *ste, - bool force) -{ - /* Update rule member is usually done for the last STE or during rule - * creation to recover from mid-creation failure (for this peruse the - * force flag is used) - */ - if (ste->next_htbl && !force) - return; - - /* Update is required since each rule keeps track of its last STE */ - ste->rule_rx_tx = nic_rule; - nic_rule->last_rule_ste = ste; -} - -static struct mlx5dr_ste *dr_rule_get_pointed_ste(struct mlx5dr_ste *curr_ste) -{ - struct mlx5dr_ste *first_ste; - - first_ste = list_first_entry(mlx5dr_ste_get_miss_list(curr_ste), - struct mlx5dr_ste, miss_list_node); - - return first_ste->htbl->pointing_ste; -} - -int mlx5dr_rule_get_reverse_rule_members(struct mlx5dr_ste **ste_arr, - struct mlx5dr_ste *curr_ste, - int *num_of_stes) -{ - bool first = false; - - *num_of_stes = 0; - - if (!curr_ste) - return -ENOENT; - - /* Iterate from last to first */ - while (!first) { - first = curr_ste->ste_chain_location == 1; - ste_arr[*num_of_stes] = curr_ste; - *num_of_stes += 1; - curr_ste = dr_rule_get_pointed_ste(curr_ste); - } - - return 0; -} - -static void dr_rule_clean_rule_members(struct mlx5dr_rule *rule, - struct mlx5dr_rule_rx_tx *nic_rule) -{ - struct mlx5dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES]; - struct mlx5dr_ste *curr_ste = nic_rule->last_rule_ste; - int i; - - if (mlx5dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i)) - return; - - while (i--) - mlx5dr_ste_put(ste_arr[i], rule->matcher, nic_rule->nic_matcher); -} - -static u16 dr_get_bits_per_mask(u16 byte_mask) -{ - u16 bits = 0; - - while (byte_mask) { - byte_mask = byte_mask & (byte_mask - 1); - bits++; - } - - return bits; -} - -static bool dr_rule_need_enlarge_hash(struct mlx5dr_ste_htbl *htbl, - struct mlx5dr_domain *dmn, - struct mlx5dr_domain_rx_tx *nic_dmn) -{ - struct mlx5dr_ste_htbl_ctrl *ctrl = &htbl->ctrl; - int threshold; - - if (dmn->info.max_log_sw_icm_sz <= htbl->chunk->size) - return false; - - if (!mlx5dr_ste_htbl_may_grow(htbl)) - return false; - - if (dr_get_bits_per_mask(htbl->byte_mask) * BITS_PER_BYTE <= htbl->chunk->size) - return false; - - threshold = mlx5dr_ste_htbl_increase_threshold(htbl); - if (ctrl->num_of_collisions >= threshold && - (ctrl->num_of_valid_entries - ctrl->num_of_collisions) >= threshold) - return true; - - return false; -} - -static int dr_rule_handle_action_stes(struct mlx5dr_rule *rule, - struct mlx5dr_rule_rx_tx *nic_rule, - struct list_head *send_ste_list, - struct mlx5dr_ste *last_ste, - u8 *hw_ste_arr, - u32 new_hw_ste_arr_sz) -{ - struct mlx5dr_matcher_rx_tx *nic_matcher = nic_rule->nic_matcher; - struct mlx5dr_ste_send_info *ste_info_arr[DR_ACTION_MAX_STES]; - u8 num_of_builders = nic_matcher->num_of_builders; - struct mlx5dr_matcher *matcher = rule->matcher; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - u8 *curr_hw_ste, *prev_hw_ste; - struct mlx5dr_ste *action_ste; - int i, k; - - /* Two cases: - * 1. num_of_builders is equal to new_hw_ste_arr_sz, the action in the ste - * 2. num_of_builders is less then new_hw_ste_arr_sz, new ste was added - * to support the action. - */ - - for (i = num_of_builders, k = 0; i < new_hw_ste_arr_sz; i++, k++) { - curr_hw_ste = hw_ste_arr + i * DR_STE_SIZE; - prev_hw_ste = (i == 0) ? curr_hw_ste : hw_ste_arr + ((i - 1) * DR_STE_SIZE); - action_ste = dr_rule_create_collision_htbl(matcher, - nic_matcher, - curr_hw_ste); - if (!action_ste) - return -ENOMEM; - - mlx5dr_ste_get(action_ste); - - action_ste->htbl->pointing_ste = last_ste; - last_ste->next_htbl = action_ste->htbl; - last_ste = action_ste; - - /* While free ste we go over the miss list, so add this ste to the list */ - list_add_tail(&action_ste->miss_list_node, - mlx5dr_ste_get_miss_list(action_ste)); - - ste_info_arr[k] = mlx5dr_send_info_alloc(dmn, - nic_matcher->nic_tbl->nic_dmn->type); - if (!ste_info_arr[k]) - goto err_exit; - - /* Point current ste to the new action */ - mlx5dr_ste_set_hit_addr_by_next_htbl(dmn->ste_ctx, - prev_hw_ste, - action_ste->htbl); - - mlx5dr_rule_set_last_member(nic_rule, action_ste, true); - - mlx5dr_send_fill_and_append_ste_send_info(action_ste, DR_STE_SIZE, 0, - curr_hw_ste, - ste_info_arr[k], - send_ste_list, false); - } - - last_ste->next_htbl = NULL; - - return 0; - -err_exit: - mlx5dr_ste_put(action_ste, matcher, nic_matcher); - return -ENOMEM; -} - -static int dr_rule_handle_empty_entry(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste_htbl *cur_htbl, - struct mlx5dr_ste *ste, - u8 ste_location, - u8 *hw_ste, - struct list_head *miss_list, - struct list_head *send_list) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste_send_info *ste_info; - - /* Take ref on table, only on first time this ste is used */ - mlx5dr_htbl_get(cur_htbl); - - /* new entry -> new branch */ - list_add_tail(&ste->miss_list_node, miss_list); - - dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste); - - ste->ste_chain_location = ste_location; - - ste_info = mlx5dr_send_info_alloc(dmn, - nic_matcher->nic_tbl->nic_dmn->type); - if (!ste_info) - goto clean_ste_setting; - - if (mlx5dr_ste_create_next_htbl(matcher, - nic_matcher, - ste, - hw_ste, - DR_CHUNK_SIZE_1)) { - mlx5dr_dbg(dmn, "Failed allocating table\n"); - goto clean_ste_info; - } - - cur_htbl->ctrl.num_of_valid_entries++; - - mlx5dr_send_fill_and_append_ste_send_info(ste, DR_STE_SIZE, 0, hw_ste, - ste_info, send_list, false); - - return 0; - -clean_ste_info: - mlx5dr_send_info_free(ste_info); -clean_ste_setting: - list_del_init(&ste->miss_list_node); - mlx5dr_htbl_put(cur_htbl); - - return -ENOMEM; -} - -static struct mlx5dr_ste * -dr_rule_handle_ste_branch(struct mlx5dr_rule *rule, - struct mlx5dr_rule_rx_tx *nic_rule, - struct list_head *send_ste_list, - struct mlx5dr_ste_htbl *cur_htbl, - u8 *hw_ste, - u8 ste_location, - struct mlx5dr_ste_htbl **put_htbl) -{ - struct mlx5dr_matcher *matcher = rule->matcher; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_matcher_rx_tx *nic_matcher; - struct mlx5dr_domain_rx_tx *nic_dmn; - struct mlx5dr_ste_htbl *new_htbl; - struct mlx5dr_ste *matched_ste; - struct list_head *miss_list; - bool skip_rehash = false; - struct mlx5dr_ste *ste; - int index; - - nic_matcher = nic_rule->nic_matcher; - nic_dmn = nic_matcher->nic_tbl->nic_dmn; - -again: - index = mlx5dr_ste_calc_hash_index(hw_ste, cur_htbl); - miss_list = &cur_htbl->chunk->miss_list[index]; - ste = &cur_htbl->chunk->ste_arr[index]; - - if (mlx5dr_ste_is_not_used(ste)) { - if (dr_rule_handle_empty_entry(matcher, nic_matcher, cur_htbl, - ste, ste_location, - hw_ste, miss_list, - send_ste_list)) - return NULL; - } else { - /* Hash table index in use, check if this ste is in the miss list */ - matched_ste = dr_rule_find_ste_in_miss_list(miss_list, hw_ste); - if (matched_ste) { - /* If it is last STE in the chain, and has the same tag - * it means that all the previous stes are the same, - * if so, this rule is duplicated. - */ - if (!mlx5dr_ste_is_last_in_rule(nic_matcher, ste_location)) - return matched_ste; - - mlx5dr_dbg(dmn, "Duplicate rule inserted\n"); - } - - if (!skip_rehash && dr_rule_need_enlarge_hash(cur_htbl, dmn, nic_dmn)) { - /* Hash table index in use, try to resize of the hash */ - skip_rehash = true; - - /* Hold the table till we update. - * Release in dr_rule_create_rule() - */ - *put_htbl = cur_htbl; - mlx5dr_htbl_get(cur_htbl); - - new_htbl = dr_rule_rehash(rule, nic_rule, cur_htbl, - ste_location, send_ste_list); - if (!new_htbl) { - mlx5dr_err(dmn, "Failed creating rehash table, htbl-log_size: %d\n", - cur_htbl->chunk->size); - mlx5dr_htbl_put(cur_htbl); - } else { - cur_htbl = new_htbl; - } - goto again; - } else { - /* Hash table index in use, add another collision (miss) */ - ste = dr_rule_handle_collision(matcher, - nic_matcher, - ste, - hw_ste, - miss_list, - send_ste_list); - if (!ste) { - mlx5dr_dbg(dmn, "failed adding collision entry, index: %d\n", - index); - return NULL; - } - } - } - return ste; -} - -static bool dr_rule_cmp_value_to_mask(u8 *mask, u8 *value, - u32 s_idx, u32 e_idx) -{ - u32 i; - - for (i = s_idx; i < e_idx; i++) { - if (value[i] & ~mask[i]) { - pr_info("Rule parameters contains a value not specified by mask\n"); - return false; - } - } - return true; -} - -static bool dr_rule_verify(struct mlx5dr_matcher *matcher, - struct mlx5dr_match_parameters *value, - struct mlx5dr_match_param *param) -{ - u8 match_criteria = matcher->match_criteria; - size_t value_size = value->match_sz; - u8 *mask_p = (u8 *)&matcher->mask; - u8 *param_p = (u8 *)param; - u32 s_idx, e_idx; - - if (!value_size || - (value_size > DR_SZ_MATCH_PARAM || (value_size % sizeof(u32)))) { - mlx5dr_err(matcher->tbl->dmn, "Rule parameters length is incorrect\n"); - return false; - } - - mlx5dr_ste_copy_param(matcher->match_criteria, param, value, false); - - if (match_criteria & DR_MATCHER_CRITERIA_OUTER) { - s_idx = offsetof(struct mlx5dr_match_param, outer); - e_idx = min(s_idx + sizeof(param->outer), value_size); - - if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { - mlx5dr_err(matcher->tbl->dmn, "Rule outer parameters contains a value not specified by mask\n"); - return false; - } - } - - if (match_criteria & DR_MATCHER_CRITERIA_MISC) { - s_idx = offsetof(struct mlx5dr_match_param, misc); - e_idx = min(s_idx + sizeof(param->misc), value_size); - - if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { - mlx5dr_err(matcher->tbl->dmn, "Rule misc parameters contains a value not specified by mask\n"); - return false; - } - } - - if (match_criteria & DR_MATCHER_CRITERIA_INNER) { - s_idx = offsetof(struct mlx5dr_match_param, inner); - e_idx = min(s_idx + sizeof(param->inner), value_size); - - if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { - mlx5dr_err(matcher->tbl->dmn, "Rule inner parameters contains a value not specified by mask\n"); - return false; - } - } - - if (match_criteria & DR_MATCHER_CRITERIA_MISC2) { - s_idx = offsetof(struct mlx5dr_match_param, misc2); - e_idx = min(s_idx + sizeof(param->misc2), value_size); - - if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { - mlx5dr_err(matcher->tbl->dmn, "Rule misc2 parameters contains a value not specified by mask\n"); - return false; - } - } - - if (match_criteria & DR_MATCHER_CRITERIA_MISC3) { - s_idx = offsetof(struct mlx5dr_match_param, misc3); - e_idx = min(s_idx + sizeof(param->misc3), value_size); - - if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { - mlx5dr_err(matcher->tbl->dmn, "Rule misc3 parameters contains a value not specified by mask\n"); - return false; - } - } - - if (match_criteria & DR_MATCHER_CRITERIA_MISC4) { - s_idx = offsetof(struct mlx5dr_match_param, misc4); - e_idx = min(s_idx + sizeof(param->misc4), value_size); - - if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { - mlx5dr_err(matcher->tbl->dmn, - "Rule misc4 parameters contains a value not specified by mask\n"); - return false; - } - } - - if (match_criteria & DR_MATCHER_CRITERIA_MISC5) { - s_idx = offsetof(struct mlx5dr_match_param, misc5); - e_idx = min(s_idx + sizeof(param->misc5), value_size); - - if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { - mlx5dr_err(matcher->tbl->dmn, "Rule misc5 parameters contains a value not specified by mask\n"); - return false; - } - } - return true; -} - -static int dr_rule_destroy_rule_nic(struct mlx5dr_rule *rule, - struct mlx5dr_rule_rx_tx *nic_rule) -{ - /* Check if this nic rule was actually created, or was it skipped - * and only the other type of the RX/TX nic rule was created. - */ - if (!nic_rule->last_rule_ste) - return 0; - - mlx5dr_domain_nic_lock(nic_rule->nic_matcher->nic_tbl->nic_dmn); - dr_rule_clean_rule_members(rule, nic_rule); - - nic_rule->nic_matcher->rules--; - if (!nic_rule->nic_matcher->rules) - mlx5dr_matcher_remove_from_tbl_nic(rule->matcher->tbl->dmn, - nic_rule->nic_matcher); - - mlx5dr_domain_nic_unlock(nic_rule->nic_matcher->nic_tbl->nic_dmn); - - return 0; -} - -static int dr_rule_destroy_rule_fdb(struct mlx5dr_rule *rule) -{ - dr_rule_destroy_rule_nic(rule, &rule->rx); - dr_rule_destroy_rule_nic(rule, &rule->tx); - return 0; -} - -static int dr_rule_destroy_rule(struct mlx5dr_rule *rule) -{ - struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; - - mlx5dr_dbg_rule_del(rule); - - switch (dmn->type) { - case MLX5DR_DOMAIN_TYPE_NIC_RX: - dr_rule_destroy_rule_nic(rule, &rule->rx); - break; - case MLX5DR_DOMAIN_TYPE_NIC_TX: - dr_rule_destroy_rule_nic(rule, &rule->tx); - break; - case MLX5DR_DOMAIN_TYPE_FDB: - dr_rule_destroy_rule_fdb(rule); - break; - default: - return -EINVAL; - } - - dr_rule_remove_action_members(rule); - kfree(rule); - return 0; -} - -static enum mlx5dr_ipv dr_rule_get_ipv(struct mlx5dr_match_spec *spec) -{ - if (spec->ip_version == 6 || spec->ethertype == ETH_P_IPV6) - return DR_RULE_IPV6; - - return DR_RULE_IPV4; -} - -static bool dr_rule_skip(enum mlx5dr_domain_type domain, - enum mlx5dr_domain_nic_type nic_type, - struct mlx5dr_match_param *mask, - struct mlx5dr_match_param *value, - u32 flow_source) -{ - bool rx = nic_type == DR_DOMAIN_NIC_TYPE_RX; - - if (domain != MLX5DR_DOMAIN_TYPE_FDB) - return false; - - if (mask->misc.source_port) { - if (rx && value->misc.source_port != MLX5_VPORT_UPLINK) - return true; - - if (!rx && value->misc.source_port == MLX5_VPORT_UPLINK) - return true; - } - - if (rx && flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT) - return true; - - if (!rx && flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK) - return true; - - return false; -} - -static int -dr_rule_create_rule_nic(struct mlx5dr_rule *rule, - struct mlx5dr_rule_rx_tx *nic_rule, - struct mlx5dr_match_param *param, - size_t num_actions, - struct mlx5dr_action *actions[]) -{ - u8 hw_ste_arr_optimized[DR_RULE_MAX_STE_CHAIN_OPTIMIZED * DR_STE_SIZE] = {}; - struct mlx5dr_ste_send_info *ste_info, *tmp_ste_info; - struct mlx5dr_matcher *matcher = rule->matcher; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_matcher_rx_tx *nic_matcher; - struct mlx5dr_domain_rx_tx *nic_dmn; - struct mlx5dr_ste_htbl *htbl = NULL; - struct mlx5dr_ste_htbl *cur_htbl; - struct mlx5dr_ste *ste = NULL; - LIST_HEAD(send_ste_list); - bool hw_ste_arr_is_opt; - u8 *hw_ste_arr = NULL; - u32 new_hw_ste_arr_sz; - int ret, i; - - nic_matcher = nic_rule->nic_matcher; - nic_dmn = nic_matcher->nic_tbl->nic_dmn; - - if (dr_rule_skip(dmn->type, nic_dmn->type, &matcher->mask, param, - rule->flow_source)) - return 0; - - mlx5dr_domain_nic_lock(nic_dmn); - - ret = mlx5dr_matcher_select_builders(matcher, - nic_matcher, - dr_rule_get_ipv(¶m->outer), - dr_rule_get_ipv(¶m->inner)); - if (ret) - goto err_unlock; - - hw_ste_arr_is_opt = nic_matcher->num_of_builders <= DR_RULE_MAX_STES_OPTIMIZED; - if (likely(hw_ste_arr_is_opt)) { - hw_ste_arr = hw_ste_arr_optimized; - } else { - hw_ste_arr = kzalloc((nic_matcher->num_of_builders + DR_ACTION_MAX_STES) * - DR_STE_SIZE, GFP_KERNEL); - - if (!hw_ste_arr) { - ret = -ENOMEM; - goto err_unlock; - } - } - - ret = mlx5dr_matcher_add_to_tbl_nic(dmn, nic_matcher); - if (ret) - goto free_hw_ste; - - /* Set the tag values inside the ste array */ - ret = mlx5dr_ste_build_ste_arr(matcher, nic_matcher, param, hw_ste_arr); - if (ret) - goto remove_from_nic_tbl; - - /* Set the actions values/addresses inside the ste array */ - ret = mlx5dr_actions_build_ste_arr(matcher, nic_matcher, actions, - num_actions, hw_ste_arr, - &new_hw_ste_arr_sz); - if (ret) - goto remove_from_nic_tbl; - - cur_htbl = nic_matcher->s_htbl; - - /* Go over the array of STEs, and build dr_ste accordingly. - * The loop is over only the builders which are equal or less to the - * number of stes, in case we have actions that lives in other stes. - */ - for (i = 0; i < nic_matcher->num_of_builders; i++) { - /* Calculate CRC and keep new ste entry */ - u8 *cur_hw_ste_ent = hw_ste_arr + (i * DR_STE_SIZE); - - ste = dr_rule_handle_ste_branch(rule, - nic_rule, - &send_ste_list, - cur_htbl, - cur_hw_ste_ent, - i + 1, - &htbl); - if (!ste) { - mlx5dr_err(dmn, "Failed creating next branch\n"); - ret = -ENOENT; - goto free_rule; - } - - cur_htbl = ste->next_htbl; - - mlx5dr_ste_get(ste); - mlx5dr_rule_set_last_member(nic_rule, ste, true); - } - - /* Connect actions */ - ret = dr_rule_handle_action_stes(rule, nic_rule, &send_ste_list, - ste, hw_ste_arr, new_hw_ste_arr_sz); - if (ret) { - mlx5dr_dbg(dmn, "Failed apply actions\n"); - goto free_rule; - } - ret = dr_rule_send_update_list(&send_ste_list, dmn, true); - if (ret) { - mlx5dr_err(dmn, "Failed sending ste!\n"); - goto free_rule; - } - - if (htbl) - mlx5dr_htbl_put(htbl); - - nic_matcher->rules++; - - mlx5dr_domain_nic_unlock(nic_dmn); - - if (unlikely(!hw_ste_arr_is_opt)) - kfree(hw_ste_arr); - - return 0; - -free_rule: - dr_rule_clean_rule_members(rule, nic_rule); - /* Clean all ste_info's */ - list_for_each_entry_safe(ste_info, tmp_ste_info, &send_ste_list, send_list) { - list_del(&ste_info->send_list); - mlx5dr_send_info_free(ste_info); - } - -remove_from_nic_tbl: - if (!nic_matcher->rules) - mlx5dr_matcher_remove_from_tbl_nic(dmn, nic_matcher); - -free_hw_ste: - if (!hw_ste_arr_is_opt) - kfree(hw_ste_arr); - -err_unlock: - mlx5dr_domain_nic_unlock(nic_dmn); - - return ret; -} - -static int -dr_rule_create_rule_fdb(struct mlx5dr_rule *rule, - struct mlx5dr_match_param *param, - size_t num_actions, - struct mlx5dr_action *actions[]) -{ - struct mlx5dr_match_param copy_param = {}; - int ret; - - /* Copy match_param since they will be consumed during the first - * nic_rule insertion. - */ - memcpy(©_param, param, sizeof(struct mlx5dr_match_param)); - - ret = dr_rule_create_rule_nic(rule, &rule->rx, param, - num_actions, actions); - if (ret) - return ret; - - ret = dr_rule_create_rule_nic(rule, &rule->tx, ©_param, - num_actions, actions); - if (ret) - goto destroy_rule_nic_rx; - - return 0; - -destroy_rule_nic_rx: - dr_rule_destroy_rule_nic(rule, &rule->rx); - return ret; -} - -static struct mlx5dr_rule * -dr_rule_create_rule(struct mlx5dr_matcher *matcher, - struct mlx5dr_match_parameters *value, - size_t num_actions, - struct mlx5dr_action *actions[], - u32 flow_source) -{ - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_match_param param = {}; - struct mlx5dr_rule *rule; - int ret; - - if (!dr_rule_verify(matcher, value, ¶m)) - return NULL; - - rule = kzalloc(sizeof(*rule), GFP_KERNEL); - if (!rule) - return NULL; - - rule->matcher = matcher; - rule->flow_source = flow_source; - INIT_LIST_HEAD(&rule->rule_actions_list); - - ret = dr_rule_add_action_members(rule, num_actions, actions); - if (ret) - goto free_rule; - - switch (dmn->type) { - case MLX5DR_DOMAIN_TYPE_NIC_RX: - rule->rx.nic_matcher = &matcher->rx; - ret = dr_rule_create_rule_nic(rule, &rule->rx, ¶m, - num_actions, actions); - break; - case MLX5DR_DOMAIN_TYPE_NIC_TX: - rule->tx.nic_matcher = &matcher->tx; - ret = dr_rule_create_rule_nic(rule, &rule->tx, ¶m, - num_actions, actions); - break; - case MLX5DR_DOMAIN_TYPE_FDB: - rule->rx.nic_matcher = &matcher->rx; - rule->tx.nic_matcher = &matcher->tx; - ret = dr_rule_create_rule_fdb(rule, ¶m, - num_actions, actions); - break; - default: - ret = -EINVAL; - break; - } - - if (ret) - goto remove_action_members; - - INIT_LIST_HEAD(&rule->dbg_node); - mlx5dr_dbg_rule_add(rule); - return rule; - -remove_action_members: - dr_rule_remove_action_members(rule); -free_rule: - kfree(rule); - mlx5dr_err(dmn, "Failed creating rule\n"); - return NULL; -} - -struct mlx5dr_rule *mlx5dr_rule_create(struct mlx5dr_matcher *matcher, - struct mlx5dr_match_parameters *value, - size_t num_actions, - struct mlx5dr_action *actions[], - u32 flow_source) -{ - struct mlx5dr_rule *rule; - - refcount_inc(&matcher->refcount); - - rule = dr_rule_create_rule(matcher, value, num_actions, actions, flow_source); - if (!rule) - refcount_dec(&matcher->refcount); - - return rule; -} - -int mlx5dr_rule_destroy(struct mlx5dr_rule *rule) -{ - struct mlx5dr_matcher *matcher = rule->matcher; - int ret; - - ret = dr_rule_destroy_rule(rule); - if (!ret) - refcount_dec(&matcher->refcount); - - return ret; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c deleted file mode 100644 index 6fa06ba2d34653..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c +++ /dev/null @@ -1,1368 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include -#include "dr_types.h" - -#define QUEUE_SIZE 128 -#define SIGNAL_PER_DIV_QUEUE 16 -#define TH_NUMS_TO_DRAIN 2 -#define DR_SEND_INFO_POOL_SIZE 1000 - -enum { CQ_OK = 0, CQ_EMPTY = -1, CQ_POLL_ERR = -2 }; - -struct dr_data_seg { - u64 addr; - u32 length; - u32 lkey; - unsigned int send_flags; -}; - -enum send_info_type { - WRITE_ICM = 0, - GTA_ARG = 1, -}; - -struct postsend_info { - enum send_info_type type; - struct dr_data_seg write; - struct dr_data_seg read; - u64 remote_addr; - u32 rkey; -}; - -struct dr_qp_rtr_attr { - struct mlx5dr_cmd_gid_attr dgid_attr; - enum ib_mtu mtu; - u32 qp_num; - u16 port_num; - u8 min_rnr_timer; - u8 sgid_index; - u16 udp_src_port; - u8 fl:1; -}; - -struct dr_qp_rts_attr { - u8 timeout; - u8 retry_cnt; - u8 rnr_retry; -}; - -struct dr_qp_init_attr { - u32 cqn; - u32 pdn; - u32 max_send_wr; - struct mlx5_uars_page *uar; - u8 isolate_vl_tc:1; -}; - -struct mlx5dr_send_info_pool_obj { - struct mlx5dr_ste_send_info ste_send_info; - struct mlx5dr_send_info_pool *pool; - struct list_head list_node; -}; - -struct mlx5dr_send_info_pool { - struct list_head free_list; -}; - -static int dr_send_info_pool_fill(struct mlx5dr_send_info_pool *pool) -{ - struct mlx5dr_send_info_pool_obj *pool_obj, *tmp_pool_obj; - int i; - - for (i = 0; i < DR_SEND_INFO_POOL_SIZE; i++) { - pool_obj = kzalloc(sizeof(*pool_obj), GFP_KERNEL); - if (!pool_obj) - goto clean_pool; - - pool_obj->pool = pool; - list_add_tail(&pool_obj->list_node, &pool->free_list); - } - - return 0; - -clean_pool: - list_for_each_entry_safe(pool_obj, tmp_pool_obj, &pool->free_list, list_node) { - list_del(&pool_obj->list_node); - kfree(pool_obj); - } - - return -ENOMEM; -} - -static void dr_send_info_pool_destroy(struct mlx5dr_send_info_pool *pool) -{ - struct mlx5dr_send_info_pool_obj *pool_obj, *tmp_pool_obj; - - list_for_each_entry_safe(pool_obj, tmp_pool_obj, &pool->free_list, list_node) { - list_del(&pool_obj->list_node); - kfree(pool_obj); - } - - kfree(pool); -} - -void mlx5dr_send_info_pool_destroy(struct mlx5dr_domain *dmn) -{ - dr_send_info_pool_destroy(dmn->send_info_pool_tx); - dr_send_info_pool_destroy(dmn->send_info_pool_rx); -} - -static struct mlx5dr_send_info_pool *dr_send_info_pool_create(void) -{ - struct mlx5dr_send_info_pool *pool; - int ret; - - pool = kzalloc(sizeof(*pool), GFP_KERNEL); - if (!pool) - return NULL; - - INIT_LIST_HEAD(&pool->free_list); - - ret = dr_send_info_pool_fill(pool); - if (ret) { - kfree(pool); - return NULL; - } - - return pool; -} - -int mlx5dr_send_info_pool_create(struct mlx5dr_domain *dmn) -{ - dmn->send_info_pool_rx = dr_send_info_pool_create(); - if (!dmn->send_info_pool_rx) - return -ENOMEM; - - dmn->send_info_pool_tx = dr_send_info_pool_create(); - if (!dmn->send_info_pool_tx) { - dr_send_info_pool_destroy(dmn->send_info_pool_rx); - return -ENOMEM; - } - - return 0; -} - -struct mlx5dr_ste_send_info -*mlx5dr_send_info_alloc(struct mlx5dr_domain *dmn, - enum mlx5dr_domain_nic_type nic_type) -{ - struct mlx5dr_send_info_pool_obj *pool_obj; - struct mlx5dr_send_info_pool *pool; - int ret; - - pool = nic_type == DR_DOMAIN_NIC_TYPE_RX ? dmn->send_info_pool_rx : - dmn->send_info_pool_tx; - - if (unlikely(list_empty(&pool->free_list))) { - ret = dr_send_info_pool_fill(pool); - if (ret) - return NULL; - } - - pool_obj = list_first_entry_or_null(&pool->free_list, - struct mlx5dr_send_info_pool_obj, - list_node); - - if (likely(pool_obj)) { - list_del_init(&pool_obj->list_node); - } else { - WARN_ONCE(!pool_obj, "Failed getting ste send info obj from pool"); - return NULL; - } - - return &pool_obj->ste_send_info; -} - -void mlx5dr_send_info_free(struct mlx5dr_ste_send_info *ste_send_info) -{ - struct mlx5dr_send_info_pool_obj *pool_obj; - - pool_obj = container_of(ste_send_info, - struct mlx5dr_send_info_pool_obj, - ste_send_info); - - list_add(&pool_obj->list_node, &pool_obj->pool->free_list); -} - -static int dr_parse_cqe(struct mlx5dr_cq *dr_cq, struct mlx5_cqe64 *cqe64) -{ - unsigned int idx; - u8 opcode; - - opcode = get_cqe_opcode(cqe64); - if (opcode == MLX5_CQE_REQ_ERR) { - idx = be16_to_cpu(cqe64->wqe_counter) & - (dr_cq->qp->sq.wqe_cnt - 1); - dr_cq->qp->sq.cc = dr_cq->qp->sq.wqe_head[idx] + 1; - } else if (opcode == MLX5_CQE_RESP_ERR) { - ++dr_cq->qp->sq.cc; - } else { - idx = be16_to_cpu(cqe64->wqe_counter) & - (dr_cq->qp->sq.wqe_cnt - 1); - dr_cq->qp->sq.cc = dr_cq->qp->sq.wqe_head[idx] + 1; - - return CQ_OK; - } - - return CQ_POLL_ERR; -} - -static int dr_cq_poll_one(struct mlx5dr_cq *dr_cq) -{ - struct mlx5_cqe64 *cqe64; - int err; - - cqe64 = mlx5_cqwq_get_cqe(&dr_cq->wq); - if (!cqe64) { - if (unlikely(dr_cq->mdev->state == - MLX5_DEVICE_STATE_INTERNAL_ERROR)) { - mlx5_core_dbg_once(dr_cq->mdev, - "Polling CQ while device is shutting down\n"); - return CQ_POLL_ERR; - } - return CQ_EMPTY; - } - - mlx5_cqwq_pop(&dr_cq->wq); - err = dr_parse_cqe(dr_cq, cqe64); - mlx5_cqwq_update_db_record(&dr_cq->wq); - - return err; -} - -static int dr_poll_cq(struct mlx5dr_cq *dr_cq, int ne) -{ - int npolled; - int err = 0; - - for (npolled = 0; npolled < ne; ++npolled) { - err = dr_cq_poll_one(dr_cq); - if (err != CQ_OK) - break; - } - - return err == CQ_POLL_ERR ? err : npolled; -} - -static struct mlx5dr_qp *dr_create_rc_qp(struct mlx5_core_dev *mdev, - struct dr_qp_init_attr *attr) -{ - u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {}; - u32 temp_qpc[MLX5_ST_SZ_DW(qpc)] = {}; - struct mlx5_wq_param wqp; - struct mlx5dr_qp *dr_qp; - int inlen; - void *qpc; - void *in; - int err; - - dr_qp = kzalloc(sizeof(*dr_qp), GFP_KERNEL); - if (!dr_qp) - return NULL; - - wqp.buf_numa_node = mdev->priv.numa_node; - wqp.db_numa_node = mdev->priv.numa_node; - - dr_qp->rq.pc = 0; - dr_qp->rq.cc = 0; - dr_qp->rq.wqe_cnt = 256; - dr_qp->sq.pc = 0; - dr_qp->sq.cc = 0; - dr_qp->sq.head = 0; - dr_qp->sq.wqe_cnt = roundup_pow_of_two(attr->max_send_wr); - - MLX5_SET(qpc, temp_qpc, log_rq_stride, ilog2(MLX5_SEND_WQE_DS) - 4); - MLX5_SET(qpc, temp_qpc, log_rq_size, ilog2(dr_qp->rq.wqe_cnt)); - MLX5_SET(qpc, temp_qpc, log_sq_size, ilog2(dr_qp->sq.wqe_cnt)); - err = mlx5_wq_qp_create(mdev, &wqp, temp_qpc, &dr_qp->wq, - &dr_qp->wq_ctrl); - if (err) { - mlx5_core_warn(mdev, "Can't create QP WQ\n"); - goto err_wq; - } - - dr_qp->sq.wqe_head = kcalloc(dr_qp->sq.wqe_cnt, - sizeof(dr_qp->sq.wqe_head[0]), - GFP_KERNEL); - - if (!dr_qp->sq.wqe_head) { - mlx5_core_warn(mdev, "Can't allocate wqe head\n"); - goto err_wqe_head; - } - - inlen = MLX5_ST_SZ_BYTES(create_qp_in) + - MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * - dr_qp->wq_ctrl.buf.npages; - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) { - err = -ENOMEM; - goto err_in; - } - - qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); - MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); - MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); - MLX5_SET(qpc, qpc, isolate_vl_tc, attr->isolate_vl_tc); - MLX5_SET(qpc, qpc, pd, attr->pdn); - MLX5_SET(qpc, qpc, uar_page, attr->uar->index); - MLX5_SET(qpc, qpc, log_page_size, - dr_qp->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); - MLX5_SET(qpc, qpc, fre, 1); - MLX5_SET(qpc, qpc, rlky, 1); - MLX5_SET(qpc, qpc, cqn_snd, attr->cqn); - MLX5_SET(qpc, qpc, cqn_rcv, attr->cqn); - MLX5_SET(qpc, qpc, log_rq_stride, ilog2(MLX5_SEND_WQE_DS) - 4); - MLX5_SET(qpc, qpc, log_rq_size, ilog2(dr_qp->rq.wqe_cnt)); - MLX5_SET(qpc, qpc, rq_type, MLX5_NON_ZERO_RQ); - MLX5_SET(qpc, qpc, log_sq_size, ilog2(dr_qp->sq.wqe_cnt)); - MLX5_SET(qpc, qpc, ts_format, mlx5_get_qp_default_ts(mdev)); - MLX5_SET64(qpc, qpc, dbr_addr, dr_qp->wq_ctrl.db.dma); - if (MLX5_CAP_GEN(mdev, cqe_version) == 1) - MLX5_SET(qpc, qpc, user_index, 0xFFFFFF); - mlx5_fill_page_frag_array(&dr_qp->wq_ctrl.buf, - (__be64 *)MLX5_ADDR_OF(create_qp_in, - in, pas)); - - MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP); - err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); - dr_qp->qpn = MLX5_GET(create_qp_out, out, qpn); - kvfree(in); - if (err) - goto err_in; - dr_qp->uar = attr->uar; - - return dr_qp; - -err_in: - kfree(dr_qp->sq.wqe_head); -err_wqe_head: - mlx5_wq_destroy(&dr_qp->wq_ctrl); -err_wq: - kfree(dr_qp); - return NULL; -} - -static void dr_destroy_qp(struct mlx5_core_dev *mdev, - struct mlx5dr_qp *dr_qp) -{ - u32 in[MLX5_ST_SZ_DW(destroy_qp_in)] = {}; - - MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP); - MLX5_SET(destroy_qp_in, in, qpn, dr_qp->qpn); - mlx5_cmd_exec_in(mdev, destroy_qp, in); - - kfree(dr_qp->sq.wqe_head); - mlx5_wq_destroy(&dr_qp->wq_ctrl); - kfree(dr_qp); -} - -static void dr_cmd_notify_hw(struct mlx5dr_qp *dr_qp, void *ctrl) -{ - dma_wmb(); - *dr_qp->wq.sq.db = cpu_to_be32(dr_qp->sq.pc & 0xffff); - - /* After wmb() the hw aware of new work */ - wmb(); - - mlx5_write64(ctrl, dr_qp->uar->map + MLX5_BF_OFFSET); -} - -static void -dr_rdma_handle_flow_access_arg_segments(struct mlx5_wqe_ctrl_seg *wq_ctrl, - u32 remote_addr, - struct dr_data_seg *data_seg, - int *size) -{ - struct mlx5_wqe_header_modify_argument_update_seg *wq_arg_seg; - struct mlx5_wqe_flow_update_ctrl_seg *wq_flow_seg; - - wq_ctrl->general_id = cpu_to_be32(remote_addr); - wq_flow_seg = (void *)(wq_ctrl + 1); - - /* mlx5_wqe_flow_update_ctrl_seg - all reserved */ - memset(wq_flow_seg, 0, sizeof(*wq_flow_seg)); - wq_arg_seg = (void *)(wq_flow_seg + 1); - - memcpy(wq_arg_seg->argument_list, - (void *)(uintptr_t)data_seg->addr, - data_seg->length); - - *size = (sizeof(*wq_ctrl) + /* WQE ctrl segment */ - sizeof(*wq_flow_seg) + /* WQE flow update ctrl seg - reserved */ - sizeof(*wq_arg_seg)) / /* WQE hdr modify arg seg - data */ - MLX5_SEND_WQE_DS; -} - -static void -dr_rdma_handle_icm_write_segments(struct mlx5_wqe_ctrl_seg *wq_ctrl, - u64 remote_addr, - u32 rkey, - struct dr_data_seg *data_seg, - unsigned int *size) -{ - struct mlx5_wqe_raddr_seg *wq_raddr; - struct mlx5_wqe_data_seg *wq_dseg; - - wq_raddr = (void *)(wq_ctrl + 1); - - wq_raddr->raddr = cpu_to_be64(remote_addr); - wq_raddr->rkey = cpu_to_be32(rkey); - wq_raddr->reserved = 0; - - wq_dseg = (void *)(wq_raddr + 1); - - wq_dseg->byte_count = cpu_to_be32(data_seg->length); - wq_dseg->lkey = cpu_to_be32(data_seg->lkey); - wq_dseg->addr = cpu_to_be64(data_seg->addr); - - *size = (sizeof(*wq_ctrl) + /* WQE ctrl segment */ - sizeof(*wq_dseg) + /* WQE data segment */ - sizeof(*wq_raddr)) / /* WQE remote addr segment */ - MLX5_SEND_WQE_DS; -} - -static void dr_set_ctrl_seg(struct mlx5_wqe_ctrl_seg *wq_ctrl, - struct dr_data_seg *data_seg) -{ - wq_ctrl->signature = 0; - wq_ctrl->rsvd[0] = 0; - wq_ctrl->rsvd[1] = 0; - wq_ctrl->fm_ce_se = data_seg->send_flags & IB_SEND_SIGNALED ? - MLX5_WQE_CTRL_CQ_UPDATE : 0; - wq_ctrl->imm = 0; -} - -static void dr_rdma_segments(struct mlx5dr_qp *dr_qp, u64 remote_addr, - u32 rkey, struct dr_data_seg *data_seg, - u32 opcode, bool notify_hw) -{ - struct mlx5_wqe_ctrl_seg *wq_ctrl; - int opcode_mod = 0; - unsigned int size; - unsigned int idx; - - idx = dr_qp->sq.pc & (dr_qp->sq.wqe_cnt - 1); - - wq_ctrl = mlx5_wq_cyc_get_wqe(&dr_qp->wq.sq, idx); - dr_set_ctrl_seg(wq_ctrl, data_seg); - - switch (opcode) { - case MLX5_OPCODE_RDMA_READ: - case MLX5_OPCODE_RDMA_WRITE: - dr_rdma_handle_icm_write_segments(wq_ctrl, remote_addr, - rkey, data_seg, &size); - break; - case MLX5_OPCODE_FLOW_TBL_ACCESS: - opcode_mod = MLX5_CMD_OP_MOD_UPDATE_HEADER_MODIFY_ARGUMENT; - dr_rdma_handle_flow_access_arg_segments(wq_ctrl, remote_addr, - data_seg, &size); - break; - default: - WARN(true, "illegal opcode %d", opcode); - return; - } - - /* -------------------------------------------------------- - * |opcode_mod (8 bit)|wqe_index (16 bits)| opcod (8 bits)| - * -------------------------------------------------------- - */ - wq_ctrl->opmod_idx_opcode = - cpu_to_be32((opcode_mod << 24) | - ((dr_qp->sq.pc & 0xffff) << 8) | - opcode); - wq_ctrl->qpn_ds = cpu_to_be32(size | dr_qp->qpn << 8); - - dr_qp->sq.pc += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB); - dr_qp->sq.wqe_head[idx] = dr_qp->sq.head++; - - if (notify_hw) - dr_cmd_notify_hw(dr_qp, wq_ctrl); -} - -static void dr_post_send(struct mlx5dr_qp *dr_qp, struct postsend_info *send_info) -{ - if (send_info->type == WRITE_ICM) { - dr_rdma_segments(dr_qp, send_info->remote_addr, send_info->rkey, - &send_info->write, MLX5_OPCODE_RDMA_WRITE, false); - dr_rdma_segments(dr_qp, send_info->remote_addr, send_info->rkey, - &send_info->read, MLX5_OPCODE_RDMA_READ, true); - } else { /* GTA_ARG */ - dr_rdma_segments(dr_qp, send_info->remote_addr, send_info->rkey, - &send_info->write, MLX5_OPCODE_FLOW_TBL_ACCESS, true); - } - -} - -/** - * mlx5dr_send_fill_and_append_ste_send_info: Add data to be sent - * with send_list parameters: - * - * @ste: The data that attached to this specific ste - * @size: of data to write - * @offset: of the data from start of the hw_ste entry - * @data: data - * @ste_info: ste to be sent with send_list - * @send_list: to append into it - * @copy_data: if true indicates that the data should be kept because - * it's not backuped any where (like in re-hash). - * if false, it lets the data to be updated after - * it was added to the list. - */ -void mlx5dr_send_fill_and_append_ste_send_info(struct mlx5dr_ste *ste, u16 size, - u16 offset, u8 *data, - struct mlx5dr_ste_send_info *ste_info, - struct list_head *send_list, - bool copy_data) -{ - ste_info->size = size; - ste_info->ste = ste; - ste_info->offset = offset; - - if (copy_data) { - memcpy(ste_info->data_cont, data, size); - ste_info->data = ste_info->data_cont; - } else { - ste_info->data = data; - } - - list_add_tail(&ste_info->send_list, send_list); -} - -/* The function tries to consume one wc each time, unless the queue is full, in - * that case, which means that the hw is behind the sw in a full queue len - * the function will drain the cq till it empty. - */ -static int dr_handle_pending_wc(struct mlx5dr_domain *dmn, - struct mlx5dr_send_ring *send_ring) -{ - bool is_drain = false; - int ne; - - if (send_ring->pending_wqe < send_ring->signal_th) - return 0; - - /* Queue is full start drain it */ - if (send_ring->pending_wqe >= - dmn->send_ring->signal_th * TH_NUMS_TO_DRAIN) - is_drain = true; - - do { - ne = dr_poll_cq(send_ring->cq, 1); - if (unlikely(ne < 0)) { - mlx5_core_warn_once(dmn->mdev, "SMFS QPN 0x%x is disabled/limited", - send_ring->qp->qpn); - send_ring->err_state = true; - return ne; - } else if (ne == 1) { - send_ring->pending_wqe -= send_ring->signal_th; - } - } while (ne == 1 || - (is_drain && send_ring->pending_wqe >= send_ring->signal_th)); - - return 0; -} - -static void dr_fill_write_args_segs(struct mlx5dr_send_ring *send_ring, - struct postsend_info *send_info) -{ - send_ring->pending_wqe++; - - if (send_ring->pending_wqe % send_ring->signal_th == 0) - send_info->write.send_flags |= IB_SEND_SIGNALED; - else - send_info->write.send_flags = 0; -} - -static void dr_fill_write_icm_segs(struct mlx5dr_domain *dmn, - struct mlx5dr_send_ring *send_ring, - struct postsend_info *send_info) -{ - u32 buff_offset; - - if (send_info->write.length > dmn->info.max_inline_size) { - buff_offset = (send_ring->tx_head & - (dmn->send_ring->signal_th - 1)) * - send_ring->max_post_send_size; - /* Copy to ring mr */ - memcpy(send_ring->buf + buff_offset, - (void *)(uintptr_t)send_info->write.addr, - send_info->write.length); - send_info->write.addr = (uintptr_t)send_ring->mr->dma_addr + buff_offset; - send_info->write.lkey = send_ring->mr->mkey; - - send_ring->tx_head++; - } - - send_ring->pending_wqe++; - - if (send_ring->pending_wqe % send_ring->signal_th == 0) - send_info->write.send_flags |= IB_SEND_SIGNALED; - - send_ring->pending_wqe++; - send_info->read.length = send_info->write.length; - - /* Read into dedicated sync buffer */ - send_info->read.addr = (uintptr_t)send_ring->sync_mr->dma_addr; - send_info->read.lkey = send_ring->sync_mr->mkey; - - if (send_ring->pending_wqe % send_ring->signal_th == 0) - send_info->read.send_flags = IB_SEND_SIGNALED; - else - send_info->read.send_flags = 0; -} - -static void dr_fill_data_segs(struct mlx5dr_domain *dmn, - struct mlx5dr_send_ring *send_ring, - struct postsend_info *send_info) -{ - if (send_info->type == WRITE_ICM) - dr_fill_write_icm_segs(dmn, send_ring, send_info); - else /* args */ - dr_fill_write_args_segs(send_ring, send_info); -} - -static int dr_postsend_icm_data(struct mlx5dr_domain *dmn, - struct postsend_info *send_info) -{ - struct mlx5dr_send_ring *send_ring = dmn->send_ring; - int ret; - - if (unlikely(dmn->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR || - send_ring->err_state)) { - mlx5_core_dbg_once(dmn->mdev, - "Skipping post send: QP err state: %d, device state: %d\n", - send_ring->err_state, dmn->mdev->state); - return 0; - } - - spin_lock(&send_ring->lock); - - ret = dr_handle_pending_wc(dmn, send_ring); - if (ret) - goto out_unlock; - - dr_fill_data_segs(dmn, send_ring, send_info); - dr_post_send(send_ring->qp, send_info); - -out_unlock: - spin_unlock(&send_ring->lock); - return ret; -} - -static int dr_get_tbl_copy_details(struct mlx5dr_domain *dmn, - struct mlx5dr_ste_htbl *htbl, - u8 **data, - u32 *byte_size, - int *iterations, - int *num_stes) -{ - u32 chunk_byte_size = mlx5dr_icm_pool_get_chunk_byte_size(htbl->chunk); - int alloc_size; - - if (chunk_byte_size > dmn->send_ring->max_post_send_size) { - *iterations = chunk_byte_size / dmn->send_ring->max_post_send_size; - *byte_size = dmn->send_ring->max_post_send_size; - alloc_size = *byte_size; - *num_stes = *byte_size / DR_STE_SIZE; - } else { - *iterations = 1; - *num_stes = mlx5dr_icm_pool_get_chunk_num_of_entries(htbl->chunk); - alloc_size = *num_stes * DR_STE_SIZE; - } - - *data = kvzalloc(alloc_size, GFP_KERNEL); - if (!*data) - return -ENOMEM; - - return 0; -} - -/** - * mlx5dr_send_postsend_ste: write size bytes into offset from the hw cm. - * - * @dmn: Domain - * @ste: The ste struct that contains the data (at - * least part of it) - * @data: The real data to send size data - * @size: for writing. - * @offset: The offset from the icm mapped data to - * start write to this for write only part of the - * buffer. - * - * Return: 0 on success. - */ -int mlx5dr_send_postsend_ste(struct mlx5dr_domain *dmn, struct mlx5dr_ste *ste, - u8 *data, u16 size, u16 offset) -{ - struct postsend_info send_info = {}; - - mlx5dr_ste_prepare_for_postsend(dmn->ste_ctx, data, size); - - send_info.write.addr = (uintptr_t)data; - send_info.write.length = size; - send_info.write.lkey = 0; - send_info.remote_addr = mlx5dr_ste_get_mr_addr(ste) + offset; - send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(ste->htbl->chunk); - - return dr_postsend_icm_data(dmn, &send_info); -} - -int mlx5dr_send_postsend_htbl(struct mlx5dr_domain *dmn, - struct mlx5dr_ste_htbl *htbl, - u8 *formatted_ste, u8 *mask) -{ - u32 byte_size = mlx5dr_icm_pool_get_chunk_byte_size(htbl->chunk); - int num_stes_per_iter; - int iterations; - u8 *data; - int ret; - int i; - int j; - - ret = dr_get_tbl_copy_details(dmn, htbl, &data, &byte_size, - &iterations, &num_stes_per_iter); - if (ret) - return ret; - - mlx5dr_ste_prepare_for_postsend(dmn->ste_ctx, formatted_ste, DR_STE_SIZE); - - /* Send the data iteration times */ - for (i = 0; i < iterations; i++) { - u32 ste_index = i * (byte_size / DR_STE_SIZE); - struct postsend_info send_info = {}; - - /* Copy all ste's on the data buffer - * need to add the bit_mask - */ - for (j = 0; j < num_stes_per_iter; j++) { - struct mlx5dr_ste *ste = &htbl->chunk->ste_arr[ste_index + j]; - u32 ste_off = j * DR_STE_SIZE; - - if (mlx5dr_ste_is_not_used(ste)) { - memcpy(data + ste_off, - formatted_ste, DR_STE_SIZE); - } else { - /* Copy data */ - memcpy(data + ste_off, - htbl->chunk->hw_ste_arr + - DR_STE_SIZE_REDUCED * (ste_index + j), - DR_STE_SIZE_REDUCED); - /* Copy bit_mask */ - memcpy(data + ste_off + DR_STE_SIZE_REDUCED, - mask, DR_STE_SIZE_MASK); - /* Only when we have mask we need to re-arrange the STE */ - mlx5dr_ste_prepare_for_postsend(dmn->ste_ctx, - data + (j * DR_STE_SIZE), - DR_STE_SIZE); - } - } - - send_info.write.addr = (uintptr_t)data; - send_info.write.length = byte_size; - send_info.write.lkey = 0; - send_info.remote_addr = - mlx5dr_ste_get_mr_addr(htbl->chunk->ste_arr + ste_index); - send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(htbl->chunk); - - ret = dr_postsend_icm_data(dmn, &send_info); - if (ret) - goto out_free; - } - -out_free: - kvfree(data); - return ret; -} - -/* Initialize htble with default STEs */ -int mlx5dr_send_postsend_formatted_htbl(struct mlx5dr_domain *dmn, - struct mlx5dr_ste_htbl *htbl, - u8 *ste_init_data, - bool update_hw_ste) -{ - u32 byte_size = mlx5dr_icm_pool_get_chunk_byte_size(htbl->chunk); - int iterations; - int num_stes; - u8 *copy_dst; - u8 *data; - int ret; - int i; - - ret = dr_get_tbl_copy_details(dmn, htbl, &data, &byte_size, - &iterations, &num_stes); - if (ret) - return ret; - - if (update_hw_ste) { - /* Copy the reduced STE to hash table ste_arr */ - for (i = 0; i < num_stes; i++) { - copy_dst = htbl->chunk->hw_ste_arr + i * DR_STE_SIZE_REDUCED; - memcpy(copy_dst, ste_init_data, DR_STE_SIZE_REDUCED); - } - } - - mlx5dr_ste_prepare_for_postsend(dmn->ste_ctx, ste_init_data, DR_STE_SIZE); - - /* Copy the same STE on the data buffer */ - for (i = 0; i < num_stes; i++) { - copy_dst = data + i * DR_STE_SIZE; - memcpy(copy_dst, ste_init_data, DR_STE_SIZE); - } - - /* Send the data iteration times */ - for (i = 0; i < iterations; i++) { - u8 ste_index = i * (byte_size / DR_STE_SIZE); - struct postsend_info send_info = {}; - - send_info.write.addr = (uintptr_t)data; - send_info.write.length = byte_size; - send_info.write.lkey = 0; - send_info.remote_addr = - mlx5dr_ste_get_mr_addr(htbl->chunk->ste_arr + ste_index); - send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(htbl->chunk); - - ret = dr_postsend_icm_data(dmn, &send_info); - if (ret) - goto out_free; - } - -out_free: - kvfree(data); - return ret; -} - -int mlx5dr_send_postsend_action(struct mlx5dr_domain *dmn, - struct mlx5dr_action *action) -{ - struct postsend_info send_info = {}; - - send_info.write.addr = (uintptr_t)action->rewrite->data; - send_info.write.length = action->rewrite->num_of_actions * - DR_MODIFY_ACTION_SIZE; - send_info.write.lkey = 0; - send_info.remote_addr = - mlx5dr_icm_pool_get_chunk_mr_addr(action->rewrite->chunk); - send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(action->rewrite->chunk); - - return dr_postsend_icm_data(dmn, &send_info); -} - -int mlx5dr_send_postsend_pattern(struct mlx5dr_domain *dmn, - struct mlx5dr_icm_chunk *chunk, - u16 num_of_actions, - u8 *data) -{ - struct postsend_info send_info = {}; - int ret; - - send_info.write.addr = (uintptr_t)data; - send_info.write.length = num_of_actions * DR_MODIFY_ACTION_SIZE; - send_info.remote_addr = mlx5dr_icm_pool_get_chunk_mr_addr(chunk); - send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(chunk); - - ret = dr_postsend_icm_data(dmn, &send_info); - if (ret) - return ret; - - return 0; -} - -int mlx5dr_send_postsend_args(struct mlx5dr_domain *dmn, u64 arg_id, - u16 num_of_actions, u8 *actions_data) -{ - int data_len, iter = 0, cur_sent; - u64 addr; - int ret; - - addr = (uintptr_t)actions_data; - data_len = num_of_actions * DR_MODIFY_ACTION_SIZE; - - do { - struct postsend_info send_info = {}; - - send_info.type = GTA_ARG; - send_info.write.addr = addr; - cur_sent = min_t(u32, data_len, DR_ACTION_CACHE_LINE_SIZE); - send_info.write.length = cur_sent; - send_info.write.lkey = 0; - send_info.remote_addr = arg_id + iter; - - ret = dr_postsend_icm_data(dmn, &send_info); - if (ret) - goto out; - - iter++; - addr += cur_sent; - data_len -= cur_sent; - } while (data_len > 0); - -out: - return ret; -} - -static int dr_modify_qp_rst2init(struct mlx5_core_dev *mdev, - struct mlx5dr_qp *dr_qp, - int port) -{ - u32 in[MLX5_ST_SZ_DW(rst2init_qp_in)] = {}; - void *qpc; - - qpc = MLX5_ADDR_OF(rst2init_qp_in, in, qpc); - - MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, port); - MLX5_SET(qpc, qpc, pm_state, MLX5_QPC_PM_STATE_MIGRATED); - MLX5_SET(qpc, qpc, rre, 1); - MLX5_SET(qpc, qpc, rwe, 1); - - MLX5_SET(rst2init_qp_in, in, opcode, MLX5_CMD_OP_RST2INIT_QP); - MLX5_SET(rst2init_qp_in, in, qpn, dr_qp->qpn); - - return mlx5_cmd_exec_in(mdev, rst2init_qp, in); -} - -static int dr_cmd_modify_qp_rtr2rts(struct mlx5_core_dev *mdev, - struct mlx5dr_qp *dr_qp, - struct dr_qp_rts_attr *attr) -{ - u32 in[MLX5_ST_SZ_DW(rtr2rts_qp_in)] = {}; - void *qpc; - - qpc = MLX5_ADDR_OF(rtr2rts_qp_in, in, qpc); - - MLX5_SET(rtr2rts_qp_in, in, qpn, dr_qp->qpn); - - MLX5_SET(qpc, qpc, retry_count, attr->retry_cnt); - MLX5_SET(qpc, qpc, rnr_retry, attr->rnr_retry); - MLX5_SET(qpc, qpc, primary_address_path.ack_timeout, 0x8); /* ~1ms */ - - MLX5_SET(rtr2rts_qp_in, in, opcode, MLX5_CMD_OP_RTR2RTS_QP); - MLX5_SET(rtr2rts_qp_in, in, qpn, dr_qp->qpn); - - return mlx5_cmd_exec_in(mdev, rtr2rts_qp, in); -} - -static int dr_cmd_modify_qp_init2rtr(struct mlx5_core_dev *mdev, - struct mlx5dr_qp *dr_qp, - struct dr_qp_rtr_attr *attr) -{ - u32 in[MLX5_ST_SZ_DW(init2rtr_qp_in)] = {}; - void *qpc; - - qpc = MLX5_ADDR_OF(init2rtr_qp_in, in, qpc); - - MLX5_SET(init2rtr_qp_in, in, qpn, dr_qp->qpn); - - MLX5_SET(qpc, qpc, mtu, attr->mtu); - MLX5_SET(qpc, qpc, log_msg_max, DR_CHUNK_SIZE_MAX - 1); - MLX5_SET(qpc, qpc, remote_qpn, attr->qp_num); - memcpy(MLX5_ADDR_OF(qpc, qpc, primary_address_path.rmac_47_32), - attr->dgid_attr.mac, sizeof(attr->dgid_attr.mac)); - memcpy(MLX5_ADDR_OF(qpc, qpc, primary_address_path.rgid_rip), - attr->dgid_attr.gid, sizeof(attr->dgid_attr.gid)); - MLX5_SET(qpc, qpc, primary_address_path.src_addr_index, - attr->sgid_index); - - if (attr->dgid_attr.roce_ver == MLX5_ROCE_VERSION_2) - MLX5_SET(qpc, qpc, primary_address_path.udp_sport, - attr->udp_src_port); - - MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, attr->port_num); - MLX5_SET(qpc, qpc, primary_address_path.fl, attr->fl); - MLX5_SET(qpc, qpc, min_rnr_nak, 1); - - MLX5_SET(init2rtr_qp_in, in, opcode, MLX5_CMD_OP_INIT2RTR_QP); - MLX5_SET(init2rtr_qp_in, in, qpn, dr_qp->qpn); - - return mlx5_cmd_exec_in(mdev, init2rtr_qp, in); -} - -static bool dr_send_allow_fl(struct mlx5dr_cmd_caps *caps) -{ - /* Check whether RC RoCE QP creation with force loopback is allowed. - * There are two separate capability bits for this: - * - force loopback when RoCE is enabled - * - force loopback when RoCE is disabled - */ - return ((caps->roce_caps.roce_en && - caps->roce_caps.fl_rc_qp_when_roce_enabled) || - (!caps->roce_caps.roce_en && - caps->roce_caps.fl_rc_qp_when_roce_disabled)); -} - -static int dr_prepare_qp_to_rts(struct mlx5dr_domain *dmn) -{ - struct mlx5dr_qp *dr_qp = dmn->send_ring->qp; - struct dr_qp_rts_attr rts_attr = {}; - struct dr_qp_rtr_attr rtr_attr = {}; - enum ib_mtu mtu = IB_MTU_1024; - u16 gid_index = 0; - int port = 1; - int ret; - - /* Init */ - ret = dr_modify_qp_rst2init(dmn->mdev, dr_qp, port); - if (ret) { - mlx5dr_err(dmn, "Failed modify QP rst2init\n"); - return ret; - } - - /* RTR */ - rtr_attr.mtu = mtu; - rtr_attr.qp_num = dr_qp->qpn; - rtr_attr.min_rnr_timer = 12; - rtr_attr.port_num = port; - rtr_attr.udp_src_port = dmn->info.caps.roce_min_src_udp; - - /* If QP creation with force loopback is allowed, then there - * is no need for GID index when creating the QP. - * Otherwise we query GID attributes and use GID index. - */ - rtr_attr.fl = dr_send_allow_fl(&dmn->info.caps); - if (!rtr_attr.fl) { - ret = mlx5dr_cmd_query_gid(dmn->mdev, port, gid_index, - &rtr_attr.dgid_attr); - if (ret) - return ret; - - rtr_attr.sgid_index = gid_index; - } - - ret = dr_cmd_modify_qp_init2rtr(dmn->mdev, dr_qp, &rtr_attr); - if (ret) { - mlx5dr_err(dmn, "Failed modify QP init2rtr\n"); - return ret; - } - - /* RTS */ - rts_attr.timeout = 14; - rts_attr.retry_cnt = 7; - rts_attr.rnr_retry = 7; - - ret = dr_cmd_modify_qp_rtr2rts(dmn->mdev, dr_qp, &rts_attr); - if (ret) { - mlx5dr_err(dmn, "Failed modify QP rtr2rts\n"); - return ret; - } - - return 0; -} - -static void dr_cq_complete(struct mlx5_core_cq *mcq, - struct mlx5_eqe *eqe) -{ - pr_err("CQ completion CQ: #%u\n", mcq->cqn); -} - -static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev, - struct mlx5_uars_page *uar, - size_t ncqe) -{ - u32 temp_cqc[MLX5_ST_SZ_DW(cqc)] = {}; - u32 out[MLX5_ST_SZ_DW(create_cq_out)]; - struct mlx5_wq_param wqp; - struct mlx5_cqe64 *cqe; - struct mlx5dr_cq *cq; - int inlen, err, eqn; - void *cqc, *in; - __be64 *pas; - int vector; - u32 i; - - cq = kzalloc(sizeof(*cq), GFP_KERNEL); - if (!cq) - return NULL; - - ncqe = roundup_pow_of_two(ncqe); - MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(ncqe)); - - wqp.buf_numa_node = mdev->priv.numa_node; - wqp.db_numa_node = mdev->priv.numa_node; - - err = mlx5_cqwq_create(mdev, &wqp, temp_cqc, &cq->wq, - &cq->wq_ctrl); - if (err) - goto out; - - for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) { - cqe = mlx5_cqwq_get_wqe(&cq->wq, i); - cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK; - } - - inlen = MLX5_ST_SZ_BYTES(create_cq_in) + - sizeof(u64) * cq->wq_ctrl.buf.npages; - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - goto err_cqwq; - - vector = raw_smp_processor_id() % mlx5_comp_vectors_max(mdev); - err = mlx5_comp_eqn_get(mdev, vector, &eqn); - if (err) { - kvfree(in); - goto err_cqwq; - } - - cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); - MLX5_SET(cqc, cqc, log_cq_size, ilog2(ncqe)); - MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn); - MLX5_SET(cqc, cqc, uar_page, uar->index); - MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift - - MLX5_ADAPTER_PAGE_SHIFT); - MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma); - - pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas); - mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, pas); - - cq->mcq.comp = dr_cq_complete; - - err = mlx5_core_create_cq(mdev, &cq->mcq, in, inlen, out, sizeof(out)); - kvfree(in); - - if (err) - goto err_cqwq; - - cq->mcq.cqe_sz = 64; - cq->mcq.set_ci_db = cq->wq_ctrl.db.db; - cq->mcq.arm_db = cq->wq_ctrl.db.db + 1; - *cq->mcq.set_ci_db = 0; - - /* set no-zero value, in order to avoid the HW to run db-recovery on - * CQ that used in polling mode. - */ - *cq->mcq.arm_db = cpu_to_be32(2 << 28); - - cq->mcq.vector = 0; - cq->mcq.uar = uar; - cq->mdev = mdev; - - return cq; - -err_cqwq: - mlx5_wq_destroy(&cq->wq_ctrl); -out: - kfree(cq); - return NULL; -} - -static void dr_destroy_cq(struct mlx5_core_dev *mdev, struct mlx5dr_cq *cq) -{ - mlx5_core_destroy_cq(mdev, &cq->mcq); - mlx5_wq_destroy(&cq->wq_ctrl); - kfree(cq); -} - -static int dr_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, u32 *mkey) -{ - u32 in[MLX5_ST_SZ_DW(create_mkey_in)] = {}; - void *mkc; - - mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); - MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA); - MLX5_SET(mkc, mkc, a, 1); - MLX5_SET(mkc, mkc, rw, 1); - MLX5_SET(mkc, mkc, rr, 1); - MLX5_SET(mkc, mkc, lw, 1); - MLX5_SET(mkc, mkc, lr, 1); - - MLX5_SET(mkc, mkc, pd, pdn); - MLX5_SET(mkc, mkc, length64, 1); - MLX5_SET(mkc, mkc, qpn, 0xffffff); - - return mlx5_core_create_mkey(mdev, mkey, in, sizeof(in)); -} - -static struct mlx5dr_mr *dr_reg_mr(struct mlx5_core_dev *mdev, - u32 pdn, void *buf, size_t size) -{ - struct mlx5dr_mr *mr = kzalloc(sizeof(*mr), GFP_KERNEL); - struct device *dma_device; - dma_addr_t dma_addr; - int err; - - if (!mr) - return NULL; - - dma_device = mlx5_core_dma_dev(mdev); - dma_addr = dma_map_single(dma_device, buf, size, - DMA_BIDIRECTIONAL); - err = dma_mapping_error(dma_device, dma_addr); - if (err) { - mlx5_core_warn(mdev, "Can't dma buf\n"); - kfree(mr); - return NULL; - } - - err = dr_create_mkey(mdev, pdn, &mr->mkey); - if (err) { - mlx5_core_warn(mdev, "Can't create mkey\n"); - dma_unmap_single(dma_device, dma_addr, size, - DMA_BIDIRECTIONAL); - kfree(mr); - return NULL; - } - - mr->dma_addr = dma_addr; - mr->size = size; - mr->addr = buf; - - return mr; -} - -static void dr_dereg_mr(struct mlx5_core_dev *mdev, struct mlx5dr_mr *mr) -{ - mlx5_core_destroy_mkey(mdev, mr->mkey); - dma_unmap_single(mlx5_core_dma_dev(mdev), mr->dma_addr, mr->size, - DMA_BIDIRECTIONAL); - kfree(mr); -} - -int mlx5dr_send_ring_alloc(struct mlx5dr_domain *dmn) -{ - struct dr_qp_init_attr init_attr = {}; - int cq_size; - int size; - int ret; - - dmn->send_ring = kzalloc(sizeof(*dmn->send_ring), GFP_KERNEL); - if (!dmn->send_ring) - return -ENOMEM; - - cq_size = QUEUE_SIZE + 1; - dmn->send_ring->cq = dr_create_cq(dmn->mdev, dmn->uar, cq_size); - if (!dmn->send_ring->cq) { - mlx5dr_err(dmn, "Failed creating CQ\n"); - ret = -ENOMEM; - goto free_send_ring; - } - - init_attr.cqn = dmn->send_ring->cq->mcq.cqn; - init_attr.pdn = dmn->pdn; - init_attr.uar = dmn->uar; - init_attr.max_send_wr = QUEUE_SIZE; - - /* Isolated VL is applicable only if force loopback is supported */ - if (dr_send_allow_fl(&dmn->info.caps)) - init_attr.isolate_vl_tc = dmn->info.caps.isolate_vl_tc; - - spin_lock_init(&dmn->send_ring->lock); - - dmn->send_ring->qp = dr_create_rc_qp(dmn->mdev, &init_attr); - if (!dmn->send_ring->qp) { - mlx5dr_err(dmn, "Failed creating QP\n"); - ret = -ENOMEM; - goto clean_cq; - } - - dmn->send_ring->cq->qp = dmn->send_ring->qp; - - dmn->info.max_send_wr = QUEUE_SIZE; - dmn->info.max_inline_size = min(dmn->send_ring->qp->max_inline_data, - DR_STE_SIZE); - - dmn->send_ring->signal_th = dmn->info.max_send_wr / - SIGNAL_PER_DIV_QUEUE; - - /* Prepare qp to be used */ - ret = dr_prepare_qp_to_rts(dmn); - if (ret) - goto clean_qp; - - dmn->send_ring->max_post_send_size = - mlx5dr_icm_pool_chunk_size_to_byte(DR_CHUNK_SIZE_1K, - DR_ICM_TYPE_STE); - - /* Allocating the max size as a buffer for writing */ - size = dmn->send_ring->signal_th * dmn->send_ring->max_post_send_size; - dmn->send_ring->buf = kzalloc(size, GFP_KERNEL); - if (!dmn->send_ring->buf) { - ret = -ENOMEM; - goto clean_qp; - } - - dmn->send_ring->buf_size = size; - - dmn->send_ring->mr = dr_reg_mr(dmn->mdev, - dmn->pdn, dmn->send_ring->buf, size); - if (!dmn->send_ring->mr) { - ret = -ENOMEM; - goto free_mem; - } - - dmn->send_ring->sync_buff = kzalloc(dmn->send_ring->max_post_send_size, - GFP_KERNEL); - if (!dmn->send_ring->sync_buff) { - ret = -ENOMEM; - goto clean_mr; - } - - dmn->send_ring->sync_mr = dr_reg_mr(dmn->mdev, - dmn->pdn, dmn->send_ring->sync_buff, - dmn->send_ring->max_post_send_size); - if (!dmn->send_ring->sync_mr) { - ret = -ENOMEM; - goto free_sync_mem; - } - - return 0; - -free_sync_mem: - kfree(dmn->send_ring->sync_buff); -clean_mr: - dr_dereg_mr(dmn->mdev, dmn->send_ring->mr); -free_mem: - kfree(dmn->send_ring->buf); -clean_qp: - dr_destroy_qp(dmn->mdev, dmn->send_ring->qp); -clean_cq: - dr_destroy_cq(dmn->mdev, dmn->send_ring->cq); -free_send_ring: - kfree(dmn->send_ring); - - return ret; -} - -void mlx5dr_send_ring_free(struct mlx5dr_domain *dmn, - struct mlx5dr_send_ring *send_ring) -{ - dr_destroy_qp(dmn->mdev, send_ring->qp); - dr_destroy_cq(dmn->mdev, send_ring->cq); - dr_dereg_mr(dmn->mdev, send_ring->sync_mr); - dr_dereg_mr(dmn->mdev, send_ring->mr); - kfree(send_ring->buf); - kfree(send_ring->sync_buff); - kfree(send_ring); -} - -int mlx5dr_send_ring_force_drain(struct mlx5dr_domain *dmn) -{ - struct mlx5dr_send_ring *send_ring = dmn->send_ring; - struct postsend_info send_info = {}; - u8 data[DR_STE_SIZE]; - int num_of_sends_req; - int ret; - int i; - - /* Sending this amount of requests makes sure we will get drain */ - num_of_sends_req = send_ring->signal_th * TH_NUMS_TO_DRAIN / 2; - - /* Send fake requests forcing the last to be signaled */ - send_info.write.addr = (uintptr_t)data; - send_info.write.length = DR_STE_SIZE; - send_info.write.lkey = 0; - /* Using the sync_mr in order to write/read */ - send_info.remote_addr = (uintptr_t)send_ring->sync_mr->addr; - send_info.rkey = send_ring->sync_mr->mkey; - - for (i = 0; i < num_of_sends_req; i++) { - ret = dr_postsend_icm_data(dmn, &send_info); - if (ret) - return ret; - } - - spin_lock(&send_ring->lock); - ret = dr_handle_pending_wc(dmn, send_ring); - spin_unlock(&send_ring->lock); - - return ret; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c deleted file mode 100644 index e94fbb015efad7..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c +++ /dev/null @@ -1,1463 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include -#include -#include "dr_ste.h" - -struct dr_hw_ste_format { - u8 ctrl[DR_STE_SIZE_CTRL]; - u8 tag[DR_STE_SIZE_TAG]; - u8 mask[DR_STE_SIZE_MASK]; -}; - -static u32 dr_ste_crc32_calc(const void *input_data, size_t length) -{ - u32 crc = crc32(0, input_data, length); - - 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) -{ - return caps->sw_format_ver > MLX5_STEERING_FORMAT_CONNECTX_5; -} - -u32 mlx5dr_ste_calc_hash_index(u8 *hw_ste_p, struct mlx5dr_ste_htbl *htbl) -{ - u32 num_entries = mlx5dr_icm_pool_get_chunk_num_of_entries(htbl->chunk); - struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; - u8 masked[DR_STE_SIZE_TAG] = {}; - u32 crc32, index; - u16 bit; - int i; - - /* Don't calculate CRC if the result is predicted */ - if (num_entries == 1 || htbl->byte_mask == 0) - return 0; - - /* Mask tag using byte mask, bit per byte */ - bit = 1 << (DR_STE_SIZE_TAG - 1); - for (i = 0; i < DR_STE_SIZE_TAG; i++) { - if (htbl->byte_mask & bit) - masked[i] = hw_ste->tag[i]; - - bit = bit >> 1; - } - - crc32 = dr_ste_crc32_calc(masked, DR_STE_SIZE_TAG); - index = crc32 & (num_entries - 1); - - return index; -} - -u16 mlx5dr_ste_conv_bit_to_byte_mask(u8 *bit_mask) -{ - u16 byte_mask = 0; - int i; - - for (i = 0; i < DR_STE_SIZE_MASK; i++) { - byte_mask = byte_mask << 1; - if (bit_mask[i] == 0xff) - byte_mask |= 1; - } - return byte_mask; -} - -static u8 *dr_ste_get_tag(u8 *hw_ste_p) -{ - struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; - - return hw_ste->tag; -} - -void mlx5dr_ste_set_bit_mask(u8 *hw_ste_p, u8 *bit_mask) -{ - struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; - - memcpy(hw_ste->mask, bit_mask, DR_STE_SIZE_MASK); -} - -static void dr_ste_set_always_hit(struct dr_hw_ste_format *hw_ste) -{ - memset(&hw_ste->tag, 0, sizeof(hw_ste->tag)); - memset(&hw_ste->mask, 0, sizeof(hw_ste->mask)); -} - -static void dr_ste_set_always_miss(struct dr_hw_ste_format *hw_ste) -{ - hw_ste->tag[0] = 0xdc; - hw_ste->mask[0] = 0; -} - -bool mlx5dr_ste_is_miss_addr_set(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste_p) -{ - if (!ste_ctx->is_miss_addr_set) - return false; - - /* check if miss address is already set for this type of STE */ - return ste_ctx->is_miss_addr_set(hw_ste_p); -} - -void mlx5dr_ste_set_miss_addr(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste_p, u64 miss_addr) -{ - ste_ctx->set_miss_addr(hw_ste_p, miss_addr); -} - -static void dr_ste_always_miss_addr(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste, u64 miss_addr) -{ - ste_ctx->set_next_lu_type(hw_ste, MLX5DR_STE_LU_TYPE_DONT_CARE); - ste_ctx->set_miss_addr(hw_ste, miss_addr); - dr_ste_set_always_miss((struct dr_hw_ste_format *)hw_ste); -} - -void mlx5dr_ste_set_hit_addr(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste, u64 icm_addr, u32 ht_size) -{ - ste_ctx->set_hit_addr(hw_ste, icm_addr, ht_size); -} - -u64 mlx5dr_ste_get_icm_addr(struct mlx5dr_ste *ste) -{ - u64 base_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(ste->htbl->chunk); - u32 index = ste - ste->htbl->chunk->ste_arr; - - return base_icm_addr + DR_STE_SIZE * index; -} - -u64 mlx5dr_ste_get_mr_addr(struct mlx5dr_ste *ste) -{ - u32 index = ste - ste->htbl->chunk->ste_arr; - - return mlx5dr_icm_pool_get_chunk_mr_addr(ste->htbl->chunk) + DR_STE_SIZE * index; -} - -u8 *mlx5dr_ste_get_hw_ste(struct mlx5dr_ste *ste) -{ - u64 index = ste - ste->htbl->chunk->ste_arr; - - return ste->htbl->chunk->hw_ste_arr + DR_STE_SIZE_REDUCED * index; -} - -struct list_head *mlx5dr_ste_get_miss_list(struct mlx5dr_ste *ste) -{ - u32 index = ste - ste->htbl->chunk->ste_arr; - - return &ste->htbl->chunk->miss_list[index]; -} - -static void dr_ste_always_hit_htbl(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste, - struct mlx5dr_ste_htbl *next_htbl) -{ - struct mlx5dr_icm_chunk *chunk = next_htbl->chunk; - - ste_ctx->set_byte_mask(hw_ste, next_htbl->byte_mask); - ste_ctx->set_next_lu_type(hw_ste, next_htbl->lu_type); - ste_ctx->set_hit_addr(hw_ste, mlx5dr_icm_pool_get_chunk_icm_addr(chunk), - mlx5dr_icm_pool_get_chunk_num_of_entries(chunk)); - - dr_ste_set_always_hit((struct dr_hw_ste_format *)hw_ste); -} - -bool mlx5dr_ste_is_last_in_rule(struct mlx5dr_matcher_rx_tx *nic_matcher, - u8 ste_location) -{ - return ste_location == nic_matcher->num_of_builders; -} - -/* Replace relevant fields, except of: - * htbl - keep the origin htbl - * miss_list + list - already took the src from the list. - * icm_addr/mr_addr - depends on the hosting table. - * - * Before: - * | a | -> | b | -> | c | -> - * - * After: - * | a | -> | c | -> - * While the data that was in b copied to a. - */ -static void dr_ste_replace(struct mlx5dr_ste *dst, struct mlx5dr_ste *src) -{ - memcpy(mlx5dr_ste_get_hw_ste(dst), mlx5dr_ste_get_hw_ste(src), - DR_STE_SIZE_REDUCED); - dst->next_htbl = src->next_htbl; - if (dst->next_htbl) - dst->next_htbl->pointing_ste = dst; - - dst->refcount = src->refcount; -} - -/* Free ste which is the head and the only one in miss_list */ -static void -dr_ste_remove_head_ste(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste *ste, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste_send_info *ste_info_head, - struct list_head *send_ste_list, - struct mlx5dr_ste_htbl *stats_tbl) -{ - u8 tmp_data_ste[DR_STE_SIZE] = {}; - u64 miss_addr; - - miss_addr = mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk); - - /* Use temp ste because dr_ste_always_miss_addr - * touches bit_mask area which doesn't exist at ste->hw_ste. - * Need to use a full-sized (DR_STE_SIZE) hw_ste. - */ - memcpy(tmp_data_ste, mlx5dr_ste_get_hw_ste(ste), DR_STE_SIZE_REDUCED); - dr_ste_always_miss_addr(ste_ctx, tmp_data_ste, miss_addr); - memcpy(mlx5dr_ste_get_hw_ste(ste), tmp_data_ste, DR_STE_SIZE_REDUCED); - - list_del_init(&ste->miss_list_node); - - /* Write full STE size in order to have "always_miss" */ - mlx5dr_send_fill_and_append_ste_send_info(ste, DR_STE_SIZE, - 0, tmp_data_ste, - ste_info_head, - send_ste_list, - true /* Copy data */); - - stats_tbl->ctrl.num_of_valid_entries--; -} - -/* Free ste which is the head but NOT the only one in miss_list: - * |_ste_| --> |_next_ste_| -->|__| -->|__| -->/0 - */ -static void -dr_ste_replace_head_ste(struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste *ste, - struct mlx5dr_ste *next_ste, - struct mlx5dr_ste_send_info *ste_info_head, - struct list_head *send_ste_list, - struct mlx5dr_ste_htbl *stats_tbl) - -{ - struct mlx5dr_ste_htbl *next_miss_htbl; - u8 hw_ste[DR_STE_SIZE] = {}; - int sb_idx; - - next_miss_htbl = next_ste->htbl; - - /* Remove from the miss_list the next_ste before copy */ - list_del_init(&next_ste->miss_list_node); - - /* Move data from next into ste */ - dr_ste_replace(ste, next_ste); - - /* Update the rule on STE change */ - mlx5dr_rule_set_last_member(next_ste->rule_rx_tx, ste, false); - - /* Copy all 64 hw_ste bytes */ - memcpy(hw_ste, mlx5dr_ste_get_hw_ste(ste), DR_STE_SIZE_REDUCED); - sb_idx = ste->ste_chain_location - 1; - mlx5dr_ste_set_bit_mask(hw_ste, - nic_matcher->ste_builder[sb_idx].bit_mask); - - /* Del the htbl that contains the next_ste. - * The origin htbl stay with the same number of entries. - */ - mlx5dr_htbl_put(next_miss_htbl); - - mlx5dr_send_fill_and_append_ste_send_info(ste, DR_STE_SIZE, - 0, hw_ste, - ste_info_head, - send_ste_list, - true /* Copy data */); - - stats_tbl->ctrl.num_of_collisions--; - stats_tbl->ctrl.num_of_valid_entries--; -} - -/* Free ste that is located in the middle of the miss list: - * |__| -->|_prev_ste_|->|_ste_|-->|_next_ste_| - */ -static void dr_ste_remove_middle_ste(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste *ste, - struct mlx5dr_ste_send_info *ste_info, - struct list_head *send_ste_list, - struct mlx5dr_ste_htbl *stats_tbl) -{ - struct mlx5dr_ste *prev_ste; - u64 miss_addr; - - prev_ste = list_prev_entry(ste, miss_list_node); - if (WARN_ON(!prev_ste)) - return; - - miss_addr = ste_ctx->get_miss_addr(mlx5dr_ste_get_hw_ste(ste)); - ste_ctx->set_miss_addr(mlx5dr_ste_get_hw_ste(prev_ste), miss_addr); - - mlx5dr_send_fill_and_append_ste_send_info(prev_ste, DR_STE_SIZE_CTRL, 0, - mlx5dr_ste_get_hw_ste(prev_ste), - ste_info, send_ste_list, - true /* Copy data*/); - - list_del_init(&ste->miss_list_node); - - stats_tbl->ctrl.num_of_valid_entries--; - stats_tbl->ctrl.num_of_collisions--; -} - -void mlx5dr_ste_free(struct mlx5dr_ste *ste, - struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher) -{ - struct mlx5dr_ste_send_info *cur_ste_info, *tmp_ste_info; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; - struct mlx5dr_ste_send_info ste_info_head; - struct mlx5dr_ste *next_ste, *first_ste; - bool put_on_origin_table = true; - struct mlx5dr_ste_htbl *stats_tbl; - LIST_HEAD(send_ste_list); - - first_ste = list_first_entry(mlx5dr_ste_get_miss_list(ste), - struct mlx5dr_ste, miss_list_node); - stats_tbl = first_ste->htbl; - - /* Two options: - * 1. ste is head: - * a. head ste is the only ste in the miss list - * b. head ste is not the only ste in the miss-list - * 2. ste is not head - */ - if (first_ste == ste) { /* Ste is the head */ - struct mlx5dr_ste *last_ste; - - last_ste = list_last_entry(mlx5dr_ste_get_miss_list(ste), - struct mlx5dr_ste, miss_list_node); - if (last_ste == first_ste) - next_ste = NULL; - else - next_ste = list_next_entry(ste, miss_list_node); - - if (!next_ste) { - /* One and only entry in the list */ - dr_ste_remove_head_ste(ste_ctx, ste, - nic_matcher, - &ste_info_head, - &send_ste_list, - stats_tbl); - } else { - /* First but not only entry in the list */ - dr_ste_replace_head_ste(nic_matcher, ste, - next_ste, &ste_info_head, - &send_ste_list, stats_tbl); - put_on_origin_table = false; - } - } else { /* Ste in the middle of the list */ - dr_ste_remove_middle_ste(ste_ctx, ste, - &ste_info_head, &send_ste_list, - stats_tbl); - } - - /* Update HW */ - list_for_each_entry_safe(cur_ste_info, tmp_ste_info, - &send_ste_list, send_list) { - list_del(&cur_ste_info->send_list); - mlx5dr_send_postsend_ste(dmn, cur_ste_info->ste, - cur_ste_info->data, cur_ste_info->size, - cur_ste_info->offset); - } - - if (put_on_origin_table) - mlx5dr_htbl_put(ste->htbl); -} - -bool mlx5dr_ste_equal_tag(void *src, void *dst) -{ - struct dr_hw_ste_format *s_hw_ste = (struct dr_hw_ste_format *)src; - struct dr_hw_ste_format *d_hw_ste = (struct dr_hw_ste_format *)dst; - - return !memcmp(s_hw_ste->tag, d_hw_ste->tag, DR_STE_SIZE_TAG); -} - -void mlx5dr_ste_set_hit_addr_by_next_htbl(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste, - struct mlx5dr_ste_htbl *next_htbl) -{ - u64 icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(next_htbl->chunk); - u32 num_entries = - mlx5dr_icm_pool_get_chunk_num_of_entries(next_htbl->chunk); - - ste_ctx->set_hit_addr(hw_ste, icm_addr, num_entries); -} - -void mlx5dr_ste_prepare_for_postsend(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste_p, u32 ste_size) -{ - if (ste_ctx->prepare_for_postsend) - ste_ctx->prepare_for_postsend(hw_ste_p, ste_size); -} - -/* Init one ste as a pattern for ste data array */ -void mlx5dr_ste_set_formatted_ste(struct mlx5dr_ste_ctx *ste_ctx, - u16 gvmi, - enum mlx5dr_domain_nic_type nic_type, - struct mlx5dr_ste_htbl *htbl, - u8 *formatted_ste, - struct mlx5dr_htbl_connect_info *connect_info) -{ - bool is_rx = nic_type == DR_DOMAIN_NIC_TYPE_RX; - u8 tmp_hw_ste[DR_STE_SIZE] = {0}; - - ste_ctx->ste_init(formatted_ste, htbl->lu_type, is_rx, gvmi); - - /* Use temp ste because dr_ste_always_miss_addr/hit_htbl - * touches bit_mask area which doesn't exist at ste->hw_ste. - * Need to use a full-sized (DR_STE_SIZE) hw_ste. - */ - memcpy(tmp_hw_ste, formatted_ste, DR_STE_SIZE_REDUCED); - if (connect_info->type == CONNECT_HIT) - dr_ste_always_hit_htbl(ste_ctx, tmp_hw_ste, - connect_info->hit_next_htbl); - else - dr_ste_always_miss_addr(ste_ctx, tmp_hw_ste, - connect_info->miss_icm_addr); - memcpy(formatted_ste, tmp_hw_ste, DR_STE_SIZE_REDUCED); -} - -int mlx5dr_ste_htbl_init_and_postsend(struct mlx5dr_domain *dmn, - struct mlx5dr_domain_rx_tx *nic_dmn, - struct mlx5dr_ste_htbl *htbl, - struct mlx5dr_htbl_connect_info *connect_info, - bool update_hw_ste) -{ - u8 formatted_ste[DR_STE_SIZE] = {}; - - mlx5dr_ste_set_formatted_ste(dmn->ste_ctx, - dmn->info.caps.gvmi, - nic_dmn->type, - htbl, - formatted_ste, - connect_info); - - return mlx5dr_send_postsend_formatted_htbl(dmn, htbl, formatted_ste, update_hw_ste); -} - -int mlx5dr_ste_create_next_htbl(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste *ste, - u8 *cur_hw_ste, - enum mlx5dr_icm_chunk_size log_table_size) -{ - struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; - struct mlx5dr_htbl_connect_info info; - struct mlx5dr_ste_htbl *next_htbl; - - if (!mlx5dr_ste_is_last_in_rule(nic_matcher, ste->ste_chain_location)) { - u16 next_lu_type; - u16 byte_mask; - - next_lu_type = ste_ctx->get_next_lu_type(cur_hw_ste); - byte_mask = ste_ctx->get_byte_mask(cur_hw_ste); - - next_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, - log_table_size, - next_lu_type, - byte_mask); - if (!next_htbl) { - mlx5dr_dbg(dmn, "Failed allocating table\n"); - return -ENOMEM; - } - - /* Write new table to HW */ - info.type = CONNECT_MISS; - info.miss_icm_addr = - mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk); - if (mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, next_htbl, - &info, false)) { - mlx5dr_info(dmn, "Failed writing table to HW\n"); - goto free_table; - } - - mlx5dr_ste_set_hit_addr_by_next_htbl(ste_ctx, - cur_hw_ste, next_htbl); - ste->next_htbl = next_htbl; - next_htbl->pointing_ste = ste; - } - - return 0; - -free_table: - mlx5dr_ste_htbl_free(next_htbl); - return -ENOENT; -} - -struct mlx5dr_ste_htbl *mlx5dr_ste_htbl_alloc(struct mlx5dr_icm_pool *pool, - enum mlx5dr_icm_chunk_size chunk_size, - u16 lu_type, u16 byte_mask) -{ - struct mlx5dr_icm_chunk *chunk; - struct mlx5dr_ste_htbl *htbl; - u32 num_entries; - int i; - - htbl = mlx5dr_icm_pool_alloc_htbl(pool); - if (!htbl) - return NULL; - - chunk = mlx5dr_icm_alloc_chunk(pool, chunk_size); - if (!chunk) - goto out_free_htbl; - - htbl->chunk = chunk; - htbl->lu_type = lu_type; - htbl->byte_mask = byte_mask; - htbl->refcount = 0; - htbl->pointing_ste = NULL; - htbl->ctrl.num_of_valid_entries = 0; - htbl->ctrl.num_of_collisions = 0; - num_entries = mlx5dr_icm_pool_get_chunk_num_of_entries(chunk); - - for (i = 0; i < num_entries; i++) { - struct mlx5dr_ste *ste = &chunk->ste_arr[i]; - - ste->htbl = htbl; - ste->refcount = 0; - INIT_LIST_HEAD(&ste->miss_list_node); - INIT_LIST_HEAD(&chunk->miss_list[i]); - } - - return htbl; - -out_free_htbl: - mlx5dr_icm_pool_free_htbl(pool, htbl); - return NULL; -} - -int mlx5dr_ste_htbl_free(struct mlx5dr_ste_htbl *htbl) -{ - struct mlx5dr_icm_pool *pool = htbl->chunk->buddy_mem->pool; - - if (htbl->refcount) - return -EBUSY; - - mlx5dr_icm_free_chunk(htbl->chunk); - mlx5dr_icm_pool_free_htbl(pool, htbl); - - return 0; -} - -void mlx5dr_ste_set_actions_tx(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_domain *dmn, - u8 *action_type_set, - u8 *hw_ste_arr, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes) -{ - ste_ctx->set_actions_tx(dmn, action_type_set, ste_ctx->actions_caps, - hw_ste_arr, attr, added_stes); -} - -void mlx5dr_ste_set_actions_rx(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_domain *dmn, - u8 *action_type_set, - u8 *hw_ste_arr, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes) -{ - ste_ctx->set_actions_rx(dmn, action_type_set, ste_ctx->actions_caps, - hw_ste_arr, attr, added_stes); -} - -const struct mlx5dr_ste_action_modify_field * -mlx5dr_ste_conv_modify_hdr_sw_field(struct mlx5dr_ste_ctx *ste_ctx, u16 sw_field) -{ - const struct mlx5dr_ste_action_modify_field *hw_field; - - if (sw_field >= ste_ctx->modify_field_arr_sz) - return NULL; - - hw_field = &ste_ctx->modify_field_arr[sw_field]; - if (!hw_field->end && !hw_field->start) - return NULL; - - return hw_field; -} - -void mlx5dr_ste_set_action_set(struct mlx5dr_ste_ctx *ste_ctx, - __be64 *hw_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data) -{ - ste_ctx->set_action_set((u8 *)hw_action, - hw_field, shifter, length, data); -} - -void mlx5dr_ste_set_action_add(struct mlx5dr_ste_ctx *ste_ctx, - __be64 *hw_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data) -{ - ste_ctx->set_action_add((u8 *)hw_action, - hw_field, shifter, length, data); -} - -void mlx5dr_ste_set_action_copy(struct mlx5dr_ste_ctx *ste_ctx, - __be64 *hw_action, - u8 dst_hw_field, - u8 dst_shifter, - u8 dst_len, - u8 src_hw_field, - u8 src_shifter) -{ - ste_ctx->set_action_copy((u8 *)hw_action, - dst_hw_field, dst_shifter, dst_len, - src_hw_field, src_shifter); -} - -int mlx5dr_ste_set_action_decap_l3_list(struct mlx5dr_ste_ctx *ste_ctx, - void *data, u32 data_sz, - u8 *hw_action, u32 hw_action_sz, - u16 *used_hw_action_num) -{ - /* Only Ethernet frame is supported, with VLAN (18) or without (14) */ - if (data_sz != HDR_LEN_L2 && data_sz != HDR_LEN_L2_W_VLAN) - return -EINVAL; - - return ste_ctx->set_action_decap_l3_list(data, data_sz, - hw_action, hw_action_sz, - used_hw_action_num); -} - -static int -dr_ste_alloc_modify_hdr_chunk(struct mlx5dr_action *action) -{ - struct mlx5dr_domain *dmn = action->rewrite->dmn; - u32 chunk_size; - int ret; - - chunk_size = ilog2(roundup_pow_of_two(action->rewrite->num_of_actions)); - - /* HW modify action index granularity is at least 64B */ - chunk_size = max_t(u32, chunk_size, DR_CHUNK_SIZE_8); - - action->rewrite->chunk = mlx5dr_icm_alloc_chunk(dmn->action_icm_pool, - chunk_size); - if (!action->rewrite->chunk) - return -ENOMEM; - - action->rewrite->index = (mlx5dr_icm_pool_get_chunk_icm_addr(action->rewrite->chunk) - - dmn->info.caps.hdr_modify_icm_addr) / - DR_ACTION_CACHE_LINE_SIZE; - - ret = mlx5dr_send_postsend_action(action->rewrite->dmn, action); - if (ret) - goto free_chunk; - - return 0; - -free_chunk: - mlx5dr_icm_free_chunk(action->rewrite->chunk); - return -ENOMEM; -} - -static void dr_ste_free_modify_hdr_chunk(struct mlx5dr_action *action) -{ - mlx5dr_icm_free_chunk(action->rewrite->chunk); -} - -int mlx5dr_ste_alloc_modify_hdr(struct mlx5dr_action *action) -{ - struct mlx5dr_domain *dmn = action->rewrite->dmn; - - if (mlx5dr_domain_is_support_ptrn_arg(dmn)) - return dmn->ste_ctx->alloc_modify_hdr_chunk(action); - - return dr_ste_alloc_modify_hdr_chunk(action); -} - -void mlx5dr_ste_free_modify_hdr(struct mlx5dr_action *action) -{ - struct mlx5dr_domain *dmn = action->rewrite->dmn; - - if (mlx5dr_domain_is_support_ptrn_arg(dmn)) - return dmn->ste_ctx->dealloc_modify_hdr_chunk(action); - - return dr_ste_free_modify_hdr_chunk(action); -} - -static int dr_ste_build_pre_check_spec(struct mlx5dr_domain *dmn, - struct mlx5dr_match_spec *spec) -{ - if (spec->ip_version) { - if (spec->ip_version != 0xf) { - mlx5dr_err(dmn, - "Partial ip_version mask with src/dst IP is not supported\n"); - return -EINVAL; - } - } else if (spec->ethertype != 0xffff && - (DR_MASK_IS_SRC_IP_SET(spec) || DR_MASK_IS_DST_IP_SET(spec))) { - mlx5dr_err(dmn, - "Partial/no ethertype mask with src/dst IP is not supported\n"); - return -EINVAL; - } - - return 0; -} - -int mlx5dr_ste_build_pre_check(struct mlx5dr_domain *dmn, - u8 match_criteria, - struct mlx5dr_match_param *mask, - struct mlx5dr_match_param *value) -{ - if (value) - return 0; - - if (match_criteria & DR_MATCHER_CRITERIA_MISC) { - if (mask->misc.source_port && mask->misc.source_port != 0xffff) { - mlx5dr_err(dmn, - "Partial mask source_port is not supported\n"); - return -EINVAL; - } - if (mask->misc.source_eswitch_owner_vhca_id && - mask->misc.source_eswitch_owner_vhca_id != 0xffff) { - mlx5dr_err(dmn, - "Partial mask source_eswitch_owner_vhca_id is not supported\n"); - return -EINVAL; - } - } - - if ((match_criteria & DR_MATCHER_CRITERIA_OUTER) && - dr_ste_build_pre_check_spec(dmn, &mask->outer)) - return -EINVAL; - - if ((match_criteria & DR_MATCHER_CRITERIA_INNER) && - dr_ste_build_pre_check_spec(dmn, &mask->inner)) - return -EINVAL; - - return 0; -} - -int mlx5dr_ste_build_ste_arr(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_match_param *value, - u8 *ste_arr) -{ - struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; - bool is_rx = nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX; - struct mlx5dr_domain *dmn = matcher->tbl->dmn; - struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; - struct mlx5dr_ste_build *sb; - int ret, i; - - ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria, - &matcher->mask, value); - if (ret) - return ret; - - sb = nic_matcher->ste_builder; - for (i = 0; i < nic_matcher->num_of_builders; i++) { - ste_ctx->ste_init(ste_arr, - sb->lu_type, - is_rx, - dmn->info.caps.gvmi); - - mlx5dr_ste_set_bit_mask(ste_arr, sb->bit_mask); - - ret = sb->ste_build_tag_func(value, sb, dr_ste_get_tag(ste_arr)); - if (ret) - return ret; - - /* Connect the STEs */ - if (i < (nic_matcher->num_of_builders - 1)) { - /* Need the next builder for these fields, - * not relevant for the last ste in the chain. - */ - sb++; - ste_ctx->set_next_lu_type(ste_arr, sb->lu_type); - ste_ctx->set_byte_mask(ste_arr, sb->byte_mask); - } - ste_arr += DR_STE_SIZE; - } - return 0; -} - -#define IFC_GET_CLR(typ, p, fld, clear) ({ \ - void *__p = (p); \ - u32 __t = MLX5_GET(typ, __p, fld); \ - if (clear) \ - MLX5_SET(typ, __p, fld, 0); \ - __t; \ -}) - -#define memcpy_and_clear(to, from, len, clear) ({ \ - void *__to = (to), *__from = (from); \ - size_t __len = (len); \ - memcpy(__to, __from, __len); \ - if (clear) \ - memset(__from, 0, __len); \ -}) - -static void dr_ste_copy_mask_misc(char *mask, struct mlx5dr_match_misc *spec, bool clr) -{ - spec->gre_c_present = IFC_GET_CLR(fte_match_set_misc, mask, gre_c_present, clr); - spec->gre_k_present = IFC_GET_CLR(fte_match_set_misc, mask, gre_k_present, clr); - spec->gre_s_present = IFC_GET_CLR(fte_match_set_misc, mask, gre_s_present, clr); - spec->source_vhca_port = IFC_GET_CLR(fte_match_set_misc, mask, source_vhca_port, clr); - spec->source_sqn = IFC_GET_CLR(fte_match_set_misc, mask, source_sqn, clr); - - spec->source_port = IFC_GET_CLR(fte_match_set_misc, mask, source_port, clr); - spec->source_eswitch_owner_vhca_id = - IFC_GET_CLR(fte_match_set_misc, mask, source_eswitch_owner_vhca_id, clr); - - spec->outer_second_prio = IFC_GET_CLR(fte_match_set_misc, mask, outer_second_prio, clr); - spec->outer_second_cfi = IFC_GET_CLR(fte_match_set_misc, mask, outer_second_cfi, clr); - spec->outer_second_vid = IFC_GET_CLR(fte_match_set_misc, mask, outer_second_vid, clr); - spec->inner_second_prio = IFC_GET_CLR(fte_match_set_misc, mask, inner_second_prio, clr); - spec->inner_second_cfi = IFC_GET_CLR(fte_match_set_misc, mask, inner_second_cfi, clr); - spec->inner_second_vid = IFC_GET_CLR(fte_match_set_misc, mask, inner_second_vid, clr); - - spec->outer_second_cvlan_tag = - IFC_GET_CLR(fte_match_set_misc, mask, outer_second_cvlan_tag, clr); - spec->inner_second_cvlan_tag = - IFC_GET_CLR(fte_match_set_misc, mask, inner_second_cvlan_tag, clr); - spec->outer_second_svlan_tag = - IFC_GET_CLR(fte_match_set_misc, mask, outer_second_svlan_tag, clr); - spec->inner_second_svlan_tag = - IFC_GET_CLR(fte_match_set_misc, mask, inner_second_svlan_tag, clr); - spec->gre_protocol = IFC_GET_CLR(fte_match_set_misc, mask, gre_protocol, clr); - - spec->gre_key_h = IFC_GET_CLR(fte_match_set_misc, mask, gre_key.nvgre.hi, clr); - spec->gre_key_l = IFC_GET_CLR(fte_match_set_misc, mask, gre_key.nvgre.lo, clr); - - spec->vxlan_vni = IFC_GET_CLR(fte_match_set_misc, mask, vxlan_vni, clr); - - spec->geneve_vni = IFC_GET_CLR(fte_match_set_misc, mask, geneve_vni, clr); - spec->geneve_tlv_option_0_exist = - IFC_GET_CLR(fte_match_set_misc, mask, geneve_tlv_option_0_exist, clr); - spec->geneve_oam = IFC_GET_CLR(fte_match_set_misc, mask, geneve_oam, clr); - - spec->outer_ipv6_flow_label = - IFC_GET_CLR(fte_match_set_misc, mask, outer_ipv6_flow_label, clr); - - spec->inner_ipv6_flow_label = - IFC_GET_CLR(fte_match_set_misc, mask, inner_ipv6_flow_label, clr); - - spec->geneve_opt_len = IFC_GET_CLR(fte_match_set_misc, mask, geneve_opt_len, clr); - spec->geneve_protocol_type = - IFC_GET_CLR(fte_match_set_misc, mask, geneve_protocol_type, clr); - - spec->bth_dst_qp = IFC_GET_CLR(fte_match_set_misc, mask, bth_dst_qp, clr); -} - -static void dr_ste_copy_mask_spec(char *mask, struct mlx5dr_match_spec *spec, bool clr) -{ - __be32 raw_ip[4]; - - spec->smac_47_16 = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, smac_47_16, clr); - - spec->smac_15_0 = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, smac_15_0, clr); - spec->ethertype = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ethertype, clr); - - spec->dmac_47_16 = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, dmac_47_16, clr); - - spec->dmac_15_0 = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, dmac_15_0, clr); - spec->first_prio = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, first_prio, clr); - spec->first_cfi = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, first_cfi, clr); - spec->first_vid = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, first_vid, clr); - - spec->ip_protocol = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ip_protocol, clr); - spec->ip_dscp = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ip_dscp, clr); - spec->ip_ecn = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ip_ecn, clr); - spec->cvlan_tag = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, cvlan_tag, clr); - spec->svlan_tag = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, svlan_tag, clr); - spec->frag = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, frag, clr); - spec->ip_version = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ip_version, clr); - spec->tcp_flags = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, tcp_flags, clr); - spec->tcp_sport = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, tcp_sport, clr); - spec->tcp_dport = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, tcp_dport, clr); - - spec->ipv4_ihl = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ipv4_ihl, clr); - spec->ttl_hoplimit = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ttl_hoplimit, clr); - - spec->udp_sport = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, udp_sport, clr); - spec->udp_dport = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, udp_dport, clr); - - memcpy_and_clear(raw_ip, MLX5_ADDR_OF(fte_match_set_lyr_2_4, mask, - src_ipv4_src_ipv6.ipv6_layout.ipv6), - sizeof(raw_ip), clr); - - spec->src_ip_127_96 = be32_to_cpu(raw_ip[0]); - spec->src_ip_95_64 = be32_to_cpu(raw_ip[1]); - spec->src_ip_63_32 = be32_to_cpu(raw_ip[2]); - spec->src_ip_31_0 = be32_to_cpu(raw_ip[3]); - - memcpy_and_clear(raw_ip, MLX5_ADDR_OF(fte_match_set_lyr_2_4, mask, - dst_ipv4_dst_ipv6.ipv6_layout.ipv6), - sizeof(raw_ip), clr); - - spec->dst_ip_127_96 = be32_to_cpu(raw_ip[0]); - spec->dst_ip_95_64 = be32_to_cpu(raw_ip[1]); - spec->dst_ip_63_32 = be32_to_cpu(raw_ip[2]); - spec->dst_ip_31_0 = be32_to_cpu(raw_ip[3]); -} - -static void dr_ste_copy_mask_misc2(char *mask, struct mlx5dr_match_misc2 *spec, bool clr) -{ - spec->outer_first_mpls_label = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls.mpls_label, clr); - spec->outer_first_mpls_exp = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls.mpls_exp, clr); - spec->outer_first_mpls_s_bos = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls.mpls_s_bos, clr); - spec->outer_first_mpls_ttl = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls.mpls_ttl, clr); - spec->inner_first_mpls_label = - IFC_GET_CLR(fte_match_set_misc2, mask, inner_first_mpls.mpls_label, clr); - spec->inner_first_mpls_exp = - IFC_GET_CLR(fte_match_set_misc2, mask, inner_first_mpls.mpls_exp, clr); - spec->inner_first_mpls_s_bos = - IFC_GET_CLR(fte_match_set_misc2, mask, inner_first_mpls.mpls_s_bos, clr); - spec->inner_first_mpls_ttl = - IFC_GET_CLR(fte_match_set_misc2, mask, inner_first_mpls.mpls_ttl, clr); - spec->outer_first_mpls_over_gre_label = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_gre.mpls_label, clr); - spec->outer_first_mpls_over_gre_exp = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_gre.mpls_exp, clr); - spec->outer_first_mpls_over_gre_s_bos = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_gre.mpls_s_bos, clr); - spec->outer_first_mpls_over_gre_ttl = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_gre.mpls_ttl, clr); - spec->outer_first_mpls_over_udp_label = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_udp.mpls_label, clr); - spec->outer_first_mpls_over_udp_exp = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_udp.mpls_exp, clr); - spec->outer_first_mpls_over_udp_s_bos = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_udp.mpls_s_bos, clr); - spec->outer_first_mpls_over_udp_ttl = - IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_udp.mpls_ttl, clr); - spec->metadata_reg_c_7 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_7, clr); - spec->metadata_reg_c_6 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_6, clr); - spec->metadata_reg_c_5 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_5, clr); - spec->metadata_reg_c_4 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_4, clr); - spec->metadata_reg_c_3 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_3, clr); - spec->metadata_reg_c_2 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_2, clr); - spec->metadata_reg_c_1 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_1, clr); - spec->metadata_reg_c_0 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_0, clr); - spec->metadata_reg_a = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_a, clr); -} - -static void dr_ste_copy_mask_misc3(char *mask, struct mlx5dr_match_misc3 *spec, bool clr) -{ - spec->inner_tcp_seq_num = IFC_GET_CLR(fte_match_set_misc3, mask, inner_tcp_seq_num, clr); - spec->outer_tcp_seq_num = IFC_GET_CLR(fte_match_set_misc3, mask, outer_tcp_seq_num, clr); - spec->inner_tcp_ack_num = IFC_GET_CLR(fte_match_set_misc3, mask, inner_tcp_ack_num, clr); - spec->outer_tcp_ack_num = IFC_GET_CLR(fte_match_set_misc3, mask, outer_tcp_ack_num, clr); - spec->outer_vxlan_gpe_vni = - IFC_GET_CLR(fte_match_set_misc3, mask, outer_vxlan_gpe_vni, clr); - spec->outer_vxlan_gpe_next_protocol = - IFC_GET_CLR(fte_match_set_misc3, mask, outer_vxlan_gpe_next_protocol, clr); - spec->outer_vxlan_gpe_flags = - IFC_GET_CLR(fte_match_set_misc3, mask, outer_vxlan_gpe_flags, clr); - spec->icmpv4_header_data = IFC_GET_CLR(fte_match_set_misc3, mask, icmp_header_data, clr); - spec->icmpv6_header_data = - IFC_GET_CLR(fte_match_set_misc3, mask, icmpv6_header_data, clr); - spec->icmpv4_type = IFC_GET_CLR(fte_match_set_misc3, mask, icmp_type, clr); - spec->icmpv4_code = IFC_GET_CLR(fte_match_set_misc3, mask, icmp_code, clr); - spec->icmpv6_type = IFC_GET_CLR(fte_match_set_misc3, mask, icmpv6_type, clr); - spec->icmpv6_code = IFC_GET_CLR(fte_match_set_misc3, mask, icmpv6_code, clr); - spec->geneve_tlv_option_0_data = - IFC_GET_CLR(fte_match_set_misc3, mask, geneve_tlv_option_0_data, clr); - spec->gtpu_teid = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_teid, clr); - spec->gtpu_msg_flags = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_msg_flags, clr); - spec->gtpu_msg_type = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_msg_type, clr); - spec->gtpu_dw_0 = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_dw_0, clr); - spec->gtpu_dw_2 = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_dw_2, clr); - spec->gtpu_first_ext_dw_0 = - IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_first_ext_dw_0, clr); -} - -static void dr_ste_copy_mask_misc4(char *mask, struct mlx5dr_match_misc4 *spec, bool clr) -{ - spec->prog_sample_field_id_0 = - IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_id_0, clr); - spec->prog_sample_field_value_0 = - IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_value_0, clr); - spec->prog_sample_field_id_1 = - IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_id_1, clr); - spec->prog_sample_field_value_1 = - IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_value_1, clr); - spec->prog_sample_field_id_2 = - IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_id_2, clr); - spec->prog_sample_field_value_2 = - IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_value_2, clr); - spec->prog_sample_field_id_3 = - IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_id_3, clr); - spec->prog_sample_field_value_3 = - IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_value_3, clr); -} - -static void dr_ste_copy_mask_misc5(char *mask, struct mlx5dr_match_misc5 *spec, bool clr) -{ - spec->macsec_tag_0 = - IFC_GET_CLR(fte_match_set_misc5, mask, macsec_tag_0, clr); - spec->macsec_tag_1 = - IFC_GET_CLR(fte_match_set_misc5, mask, macsec_tag_1, clr); - spec->macsec_tag_2 = - IFC_GET_CLR(fte_match_set_misc5, mask, macsec_tag_2, clr); - spec->macsec_tag_3 = - IFC_GET_CLR(fte_match_set_misc5, mask, macsec_tag_3, clr); - spec->tunnel_header_0 = - IFC_GET_CLR(fte_match_set_misc5, mask, tunnel_header_0, clr); - spec->tunnel_header_1 = - IFC_GET_CLR(fte_match_set_misc5, mask, tunnel_header_1, clr); - spec->tunnel_header_2 = - IFC_GET_CLR(fte_match_set_misc5, mask, tunnel_header_2, clr); - spec->tunnel_header_3 = - IFC_GET_CLR(fte_match_set_misc5, mask, tunnel_header_3, clr); -} - -void mlx5dr_ste_copy_param(u8 match_criteria, - struct mlx5dr_match_param *set_param, - struct mlx5dr_match_parameters *mask, - bool clr) -{ - u8 tail_param[MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)] = {}; - u8 *data = (u8 *)mask->match_buf; - size_t param_location; - void *buff; - - if (match_criteria & DR_MATCHER_CRITERIA_OUTER) { - if (mask->match_sz < sizeof(struct mlx5dr_match_spec)) { - memcpy(tail_param, data, mask->match_sz); - buff = tail_param; - } else { - buff = mask->match_buf; - } - dr_ste_copy_mask_spec(buff, &set_param->outer, clr); - } - param_location = sizeof(struct mlx5dr_match_spec); - - if (match_criteria & DR_MATCHER_CRITERIA_MISC) { - if (mask->match_sz < param_location + - sizeof(struct mlx5dr_match_misc)) { - memcpy(tail_param, data + param_location, - mask->match_sz - param_location); - buff = tail_param; - } else { - buff = data + param_location; - } - dr_ste_copy_mask_misc(buff, &set_param->misc, clr); - } - param_location += sizeof(struct mlx5dr_match_misc); - - if (match_criteria & DR_MATCHER_CRITERIA_INNER) { - if (mask->match_sz < param_location + - sizeof(struct mlx5dr_match_spec)) { - memcpy(tail_param, data + param_location, - mask->match_sz - param_location); - buff = tail_param; - } else { - buff = data + param_location; - } - dr_ste_copy_mask_spec(buff, &set_param->inner, clr); - } - param_location += sizeof(struct mlx5dr_match_spec); - - if (match_criteria & DR_MATCHER_CRITERIA_MISC2) { - if (mask->match_sz < param_location + - sizeof(struct mlx5dr_match_misc2)) { - memcpy(tail_param, data + param_location, - mask->match_sz - param_location); - buff = tail_param; - } else { - buff = data + param_location; - } - dr_ste_copy_mask_misc2(buff, &set_param->misc2, clr); - } - - param_location += sizeof(struct mlx5dr_match_misc2); - - if (match_criteria & DR_MATCHER_CRITERIA_MISC3) { - if (mask->match_sz < param_location + - sizeof(struct mlx5dr_match_misc3)) { - memcpy(tail_param, data + param_location, - mask->match_sz - param_location); - buff = tail_param; - } else { - buff = data + param_location; - } - dr_ste_copy_mask_misc3(buff, &set_param->misc3, clr); - } - - param_location += sizeof(struct mlx5dr_match_misc3); - - if (match_criteria & DR_MATCHER_CRITERIA_MISC4) { - if (mask->match_sz < param_location + - sizeof(struct mlx5dr_match_misc4)) { - memcpy(tail_param, data + param_location, - mask->match_sz - param_location); - buff = tail_param; - } else { - buff = data + param_location; - } - dr_ste_copy_mask_misc4(buff, &set_param->misc4, clr); - } - - param_location += sizeof(struct mlx5dr_match_misc4); - - if (match_criteria & DR_MATCHER_CRITERIA_MISC5) { - if (mask->match_sz < param_location + - sizeof(struct mlx5dr_match_misc5)) { - memcpy(tail_param, data + param_location, - mask->match_sz - param_location); - buff = tail_param; - } else { - buff = data + param_location; - } - dr_ste_copy_mask_misc5(buff, &set_param->misc5, clr); - } -} - -void mlx5dr_ste_build_eth_l2_src_dst(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l2_src_dst_init(sb, mask); -} - -void mlx5dr_ste_build_eth_l3_ipv6_dst(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l3_ipv6_dst_init(sb, mask); -} - -void mlx5dr_ste_build_eth_l3_ipv6_src(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l3_ipv6_src_init(sb, mask); -} - -void mlx5dr_ste_build_eth_l3_ipv4_5_tuple(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l3_ipv4_5_tuple_init(sb, mask); -} - -void mlx5dr_ste_build_eth_l2_src(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l2_src_init(sb, mask); -} - -void mlx5dr_ste_build_eth_l2_dst(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l2_dst_init(sb, mask); -} - -void mlx5dr_ste_build_eth_l2_tnl(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l2_tnl_init(sb, mask); -} - -void mlx5dr_ste_build_eth_l3_ipv4_misc(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l3_ipv4_misc_init(sb, mask); -} - -void mlx5dr_ste_build_eth_ipv6_l3_l4(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_ipv6_l3_l4_init(sb, mask); -} - -static int dr_ste_build_empty_always_hit_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - return 0; -} - -void mlx5dr_ste_build_empty_always_hit(struct mlx5dr_ste_build *sb, bool rx) -{ - sb->rx = rx; - sb->lu_type = MLX5DR_STE_LU_TYPE_DONT_CARE; - sb->byte_mask = 0; - sb->ste_build_tag_func = &dr_ste_build_empty_always_hit_tag; -} - -void mlx5dr_ste_build_mpls(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_mpls_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_gre(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_tnl_gre_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_mpls_over_gre(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - sb->caps = caps; - return ste_ctx->build_tnl_mpls_over_gre_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_mpls_over_udp(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - sb->caps = caps; - return ste_ctx->build_tnl_mpls_over_udp_init(sb, mask); -} - -void mlx5dr_ste_build_icmp(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - sb->caps = caps; - ste_ctx->build_icmp_init(sb, mask); -} - -void mlx5dr_ste_build_general_purpose(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_general_purpose_init(sb, mask); -} - -void mlx5dr_ste_build_eth_l4_misc(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_eth_l4_misc_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_vxlan_gpe(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_tnl_vxlan_gpe_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_geneve(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_tnl_geneve_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_geneve_tlv_opt(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx) -{ - sb->rx = rx; - sb->caps = caps; - sb->inner = inner; - ste_ctx->build_tnl_geneve_tlv_opt_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_geneve_tlv_opt_exist(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx) -{ - if (!ste_ctx->build_tnl_geneve_tlv_opt_exist_init) - return; - - sb->rx = rx; - sb->caps = caps; - sb->inner = inner; - ste_ctx->build_tnl_geneve_tlv_opt_exist_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_gtpu(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_tnl_gtpu_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_gtpu_flex_parser_0(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx) -{ - sb->rx = rx; - sb->caps = caps; - sb->inner = inner; - ste_ctx->build_tnl_gtpu_flex_parser_0_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_gtpu_flex_parser_1(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx) -{ - sb->rx = rx; - sb->caps = caps; - sb->inner = inner; - ste_ctx->build_tnl_gtpu_flex_parser_1_init(sb, mask); -} - -void mlx5dr_ste_build_register_0(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_register_0_init(sb, mask); -} - -void mlx5dr_ste_build_register_1(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_register_1_init(sb, mask); -} - -void mlx5dr_ste_build_src_gvmi_qpn(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn, - bool inner, bool rx) -{ - /* Set vhca_id_valid before we reset source_eswitch_owner_vhca_id */ - sb->vhca_id_valid = mask->misc.source_eswitch_owner_vhca_id; - - sb->rx = rx; - sb->dmn = dmn; - sb->inner = inner; - ste_ctx->build_src_gvmi_qpn_init(sb, mask); -} - -void mlx5dr_ste_build_flex_parser_0(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_flex_parser_0_init(sb, mask); -} - -void mlx5dr_ste_build_flex_parser_1(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_flex_parser_1_init(sb, mask); -} - -void mlx5dr_ste_build_tnl_header_0_1(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) -{ - sb->rx = rx; - sb->inner = inner; - ste_ctx->build_tnl_header_0_1_init(sb, mask); -} - -struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx(u8 version) -{ - if (version == MLX5_STEERING_FORMAT_CONNECTX_5) - return mlx5dr_ste_get_ctx_v0(); - else if (version == MLX5_STEERING_FORMAT_CONNECTX_6DX) - return mlx5dr_ste_get_ctx_v1(); - else if (version == MLX5_STEERING_FORMAT_CONNECTX_7) - return mlx5dr_ste_get_ctx_v2(); - - return NULL; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h deleted file mode 100644 index 54a6619c3ecbf8..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.h +++ /dev/null @@ -1,209 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. */ - -#ifndef _DR_STE_ -#define _DR_STE_ - -#include "dr_types.h" - -#define STE_IPV4 0x1 -#define STE_IPV6 0x2 -#define STE_TCP 0x1 -#define STE_UDP 0x2 -#define STE_SPI 0x3 -#define IP_VERSION_IPV4 0x4 -#define IP_VERSION_IPV6 0x6 -#define STE_SVLAN 0x1 -#define STE_CVLAN 0x2 -#define HDR_LEN_L2_MACS 0xC -#define HDR_LEN_L2_VLAN 0x4 -#define HDR_LEN_L2_ETHER 0x2 -#define HDR_LEN_L2 (HDR_LEN_L2_MACS + HDR_LEN_L2_ETHER) -#define HDR_LEN_L2_W_VLAN (HDR_LEN_L2 + HDR_LEN_L2_VLAN) - -/* Set to STE a specific value using DR_STE_SET */ -#define DR_STE_SET_VAL(lookup_type, tag, t_fname, spec, s_fname, value) do { \ - if ((spec)->s_fname) { \ - MLX5_SET(ste_##lookup_type, tag, t_fname, value); \ - (spec)->s_fname = 0; \ - } \ -} while (0) - -/* Set to STE spec->s_fname to tag->t_fname set spec->s_fname as used */ -#define DR_STE_SET_TAG(lookup_type, tag, t_fname, spec, s_fname) \ - DR_STE_SET_VAL(lookup_type, tag, t_fname, spec, s_fname, spec->s_fname) - -/* Set to STE -1 to tag->t_fname and set spec->s_fname as used */ -#define DR_STE_SET_ONES(lookup_type, tag, t_fname, spec, s_fname) \ - DR_STE_SET_VAL(lookup_type, tag, t_fname, spec, s_fname, -1) - -#define DR_STE_SET_TCP_FLAGS(lookup_type, tag, spec) do { \ - MLX5_SET(ste_##lookup_type, tag, tcp_ns, !!((spec)->tcp_flags & (1 << 8))); \ - MLX5_SET(ste_##lookup_type, tag, tcp_cwr, !!((spec)->tcp_flags & (1 << 7))); \ - MLX5_SET(ste_##lookup_type, tag, tcp_ece, !!((spec)->tcp_flags & (1 << 6))); \ - MLX5_SET(ste_##lookup_type, tag, tcp_urg, !!((spec)->tcp_flags & (1 << 5))); \ - MLX5_SET(ste_##lookup_type, tag, tcp_ack, !!((spec)->tcp_flags & (1 << 4))); \ - MLX5_SET(ste_##lookup_type, tag, tcp_psh, !!((spec)->tcp_flags & (1 << 3))); \ - MLX5_SET(ste_##lookup_type, tag, tcp_rst, !!((spec)->tcp_flags & (1 << 2))); \ - MLX5_SET(ste_##lookup_type, tag, tcp_syn, !!((spec)->tcp_flags & (1 << 1))); \ - MLX5_SET(ste_##lookup_type, tag, tcp_fin, !!((spec)->tcp_flags & (1 << 0))); \ -} while (0) - -#define DR_STE_SET_MPLS(lookup_type, mask, in_out, tag) do { \ - struct mlx5dr_match_misc2 *_mask = mask; \ - u8 *_tag = tag; \ - DR_STE_SET_TAG(lookup_type, _tag, mpls0_label, _mask, \ - in_out##_first_mpls_label);\ - DR_STE_SET_TAG(lookup_type, _tag, mpls0_s_bos, _mask, \ - in_out##_first_mpls_s_bos); \ - DR_STE_SET_TAG(lookup_type, _tag, mpls0_exp, _mask, \ - in_out##_first_mpls_exp); \ - DR_STE_SET_TAG(lookup_type, _tag, mpls0_ttl, _mask, \ - in_out##_first_mpls_ttl); \ -} while (0) - -#define DR_STE_SET_FLEX_PARSER_FIELD(tag, fname, caps, spec) do { \ - u8 parser_id = (caps)->flex_parser_id_##fname; \ - u8 *parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); \ - *(__be32 *)parser_ptr = cpu_to_be32((spec)->fname);\ - (spec)->fname = 0;\ -} while (0) - -#define DR_STE_IS_OUTER_MPLS_OVER_GRE_SET(_misc) (\ - (_misc)->outer_first_mpls_over_gre_label || \ - (_misc)->outer_first_mpls_over_gre_exp || \ - (_misc)->outer_first_mpls_over_gre_s_bos || \ - (_misc)->outer_first_mpls_over_gre_ttl) - -#define DR_STE_IS_OUTER_MPLS_OVER_UDP_SET(_misc) (\ - (_misc)->outer_first_mpls_over_udp_label || \ - (_misc)->outer_first_mpls_over_udp_exp || \ - (_misc)->outer_first_mpls_over_udp_s_bos || \ - (_misc)->outer_first_mpls_over_udp_ttl) - -enum dr_ste_action_modify_type_l3 { - DR_STE_ACTION_MDFY_TYPE_L3_NONE = 0x0, - DR_STE_ACTION_MDFY_TYPE_L3_IPV4 = 0x1, - DR_STE_ACTION_MDFY_TYPE_L3_IPV6 = 0x2, -}; - -enum dr_ste_action_modify_type_l4 { - DR_STE_ACTION_MDFY_TYPE_L4_NONE = 0x0, - DR_STE_ACTION_MDFY_TYPE_L4_TCP = 0x1, - DR_STE_ACTION_MDFY_TYPE_L4_UDP = 0x2, -}; - -enum { - HDR_MPLS_OFFSET_LABEL = 12, - HDR_MPLS_OFFSET_EXP = 9, - HDR_MPLS_OFFSET_S_BOS = 8, - HDR_MPLS_OFFSET_TTL = 0, -}; - -u16 mlx5dr_ste_conv_bit_to_byte_mask(u8 *bit_mask); - -static inline u8 * -dr_ste_calc_flex_parser_offset(u8 *tag, u8 parser_id) -{ - /* Calculate tag byte offset based on flex parser id */ - return tag + 4 * (3 - (parser_id % 4)); -} - -#define DR_STE_CTX_BUILDER(fname) \ - ((*build_##fname##_init)(struct mlx5dr_ste_build *sb, \ - struct mlx5dr_match_param *mask)) - -struct mlx5dr_ste_ctx { - /* Builders */ - void DR_STE_CTX_BUILDER(eth_l2_src_dst); - void DR_STE_CTX_BUILDER(eth_l3_ipv6_src); - void DR_STE_CTX_BUILDER(eth_l3_ipv6_dst); - void DR_STE_CTX_BUILDER(eth_l3_ipv4_5_tuple); - void DR_STE_CTX_BUILDER(eth_l2_src); - void DR_STE_CTX_BUILDER(eth_l2_dst); - void DR_STE_CTX_BUILDER(eth_l2_tnl); - void DR_STE_CTX_BUILDER(eth_l3_ipv4_misc); - void DR_STE_CTX_BUILDER(eth_ipv6_l3_l4); - void DR_STE_CTX_BUILDER(mpls); - void DR_STE_CTX_BUILDER(tnl_gre); - void DR_STE_CTX_BUILDER(tnl_mpls); - void DR_STE_CTX_BUILDER(tnl_mpls_over_gre); - void DR_STE_CTX_BUILDER(tnl_mpls_over_udp); - void DR_STE_CTX_BUILDER(icmp); - void DR_STE_CTX_BUILDER(general_purpose); - void DR_STE_CTX_BUILDER(eth_l4_misc); - void DR_STE_CTX_BUILDER(tnl_vxlan_gpe); - void DR_STE_CTX_BUILDER(tnl_geneve); - void DR_STE_CTX_BUILDER(tnl_geneve_tlv_opt); - void DR_STE_CTX_BUILDER(tnl_geneve_tlv_opt_exist); - void DR_STE_CTX_BUILDER(register_0); - void DR_STE_CTX_BUILDER(register_1); - void DR_STE_CTX_BUILDER(src_gvmi_qpn); - void DR_STE_CTX_BUILDER(flex_parser_0); - void DR_STE_CTX_BUILDER(flex_parser_1); - void DR_STE_CTX_BUILDER(tnl_gtpu); - void DR_STE_CTX_BUILDER(tnl_header_0_1); - void DR_STE_CTX_BUILDER(tnl_gtpu_flex_parser_0); - void DR_STE_CTX_BUILDER(tnl_gtpu_flex_parser_1); - - /* Getters and Setters */ - void (*ste_init)(u8 *hw_ste_p, u16 lu_type, - bool is_rx, u16 gvmi); - void (*set_next_lu_type)(u8 *hw_ste_p, u16 lu_type); - u16 (*get_next_lu_type)(u8 *hw_ste_p); - bool (*is_miss_addr_set)(u8 *hw_ste_p); - void (*set_miss_addr)(u8 *hw_ste_p, u64 miss_addr); - u64 (*get_miss_addr)(u8 *hw_ste_p); - void (*set_hit_addr)(u8 *hw_ste_p, u64 icm_addr, u32 ht_size); - void (*set_byte_mask)(u8 *hw_ste_p, u16 byte_mask); - u16 (*get_byte_mask)(u8 *hw_ste_p); - - /* Actions */ - u32 actions_caps; - void (*set_actions_rx)(struct mlx5dr_domain *dmn, - u8 *action_type_set, - u32 actions_caps, - u8 *hw_ste_arr, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes); - void (*set_actions_tx)(struct mlx5dr_domain *dmn, - u8 *action_type_set, - u32 actions_caps, - u8 *hw_ste_arr, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes); - u32 modify_field_arr_sz; - const struct mlx5dr_ste_action_modify_field *modify_field_arr; - void (*set_action_set)(u8 *hw_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data); - void (*set_action_add)(u8 *hw_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data); - void (*set_action_copy)(u8 *hw_action, - u8 dst_hw_field, - u8 dst_shifter, - u8 dst_len, - u8 src_hw_field, - u8 src_shifter); - int (*set_action_decap_l3_list)(void *data, - u32 data_sz, - u8 *hw_action, - u32 hw_action_sz, - u16 *used_hw_action_num); - int (*alloc_modify_hdr_chunk)(struct mlx5dr_action *action); - void (*dealloc_modify_hdr_chunk)(struct mlx5dr_action *action); - - /* Send */ - void (*prepare_for_postsend)(u8 *hw_ste_p, u32 ste_size); -}; - -struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v0(void); -struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v1(void); -struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v2(void); - -#endif /* _DR_STE_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c deleted file mode 100644 index e9f6c7ed7a7bef..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c +++ /dev/null @@ -1,1962 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. */ - -#include -#include -#include "dr_ste.h" - -#define SVLAN_ETHERTYPE 0x88a8 -#define DR_STE_ENABLE_FLOW_TAG BIT(31) - -enum dr_ste_v0_entry_type { - DR_STE_TYPE_TX = 1, - DR_STE_TYPE_RX = 2, - DR_STE_TYPE_MODIFY_PKT = 6, -}; - -enum dr_ste_v0_action_tunl { - DR_STE_TUNL_ACTION_NONE = 0, - DR_STE_TUNL_ACTION_ENABLE = 1, - DR_STE_TUNL_ACTION_DECAP = 2, - DR_STE_TUNL_ACTION_L3_DECAP = 3, - DR_STE_TUNL_ACTION_POP_VLAN = 4, -}; - -enum dr_ste_v0_action_type { - DR_STE_ACTION_TYPE_PUSH_VLAN = 1, - DR_STE_ACTION_TYPE_ENCAP_L3 = 3, - DR_STE_ACTION_TYPE_ENCAP = 4, -}; - -enum dr_ste_v0_action_mdfy_op { - DR_STE_ACTION_MDFY_OP_COPY = 0x1, - DR_STE_ACTION_MDFY_OP_SET = 0x2, - DR_STE_ACTION_MDFY_OP_ADD = 0x3, -}; - -#define DR_STE_CALC_LU_TYPE(lookup_type, rx, inner) \ - ((inner) ? DR_STE_V0_LU_TYPE_##lookup_type##_I : \ - (rx) ? DR_STE_V0_LU_TYPE_##lookup_type##_D : \ - DR_STE_V0_LU_TYPE_##lookup_type##_O) - -enum { - DR_STE_V0_LU_TYPE_NOP = 0x00, - DR_STE_V0_LU_TYPE_SRC_GVMI_AND_QP = 0x05, - DR_STE_V0_LU_TYPE_ETHL2_TUNNELING_I = 0x0a, - DR_STE_V0_LU_TYPE_ETHL2_DST_O = 0x06, - DR_STE_V0_LU_TYPE_ETHL2_DST_I = 0x07, - DR_STE_V0_LU_TYPE_ETHL2_DST_D = 0x1b, - DR_STE_V0_LU_TYPE_ETHL2_SRC_O = 0x08, - DR_STE_V0_LU_TYPE_ETHL2_SRC_I = 0x09, - DR_STE_V0_LU_TYPE_ETHL2_SRC_D = 0x1c, - DR_STE_V0_LU_TYPE_ETHL2_SRC_DST_O = 0x36, - DR_STE_V0_LU_TYPE_ETHL2_SRC_DST_I = 0x37, - DR_STE_V0_LU_TYPE_ETHL2_SRC_DST_D = 0x38, - DR_STE_V0_LU_TYPE_ETHL3_IPV6_DST_O = 0x0d, - DR_STE_V0_LU_TYPE_ETHL3_IPV6_DST_I = 0x0e, - DR_STE_V0_LU_TYPE_ETHL3_IPV6_DST_D = 0x1e, - DR_STE_V0_LU_TYPE_ETHL3_IPV6_SRC_O = 0x0f, - DR_STE_V0_LU_TYPE_ETHL3_IPV6_SRC_I = 0x10, - DR_STE_V0_LU_TYPE_ETHL3_IPV6_SRC_D = 0x1f, - DR_STE_V0_LU_TYPE_ETHL3_IPV4_5_TUPLE_O = 0x11, - DR_STE_V0_LU_TYPE_ETHL3_IPV4_5_TUPLE_I = 0x12, - DR_STE_V0_LU_TYPE_ETHL3_IPV4_5_TUPLE_D = 0x20, - DR_STE_V0_LU_TYPE_ETHL3_IPV4_MISC_O = 0x29, - DR_STE_V0_LU_TYPE_ETHL3_IPV4_MISC_I = 0x2a, - DR_STE_V0_LU_TYPE_ETHL3_IPV4_MISC_D = 0x2b, - DR_STE_V0_LU_TYPE_ETHL4_O = 0x13, - DR_STE_V0_LU_TYPE_ETHL4_I = 0x14, - DR_STE_V0_LU_TYPE_ETHL4_D = 0x21, - DR_STE_V0_LU_TYPE_ETHL4_MISC_O = 0x2c, - DR_STE_V0_LU_TYPE_ETHL4_MISC_I = 0x2d, - DR_STE_V0_LU_TYPE_ETHL4_MISC_D = 0x2e, - DR_STE_V0_LU_TYPE_MPLS_FIRST_O = 0x15, - DR_STE_V0_LU_TYPE_MPLS_FIRST_I = 0x24, - DR_STE_V0_LU_TYPE_MPLS_FIRST_D = 0x25, - DR_STE_V0_LU_TYPE_GRE = 0x16, - DR_STE_V0_LU_TYPE_FLEX_PARSER_0 = 0x22, - DR_STE_V0_LU_TYPE_FLEX_PARSER_1 = 0x23, - DR_STE_V0_LU_TYPE_FLEX_PARSER_TNL_HEADER = 0x19, - DR_STE_V0_LU_TYPE_GENERAL_PURPOSE = 0x18, - DR_STE_V0_LU_TYPE_STEERING_REGISTERS_0 = 0x2f, - DR_STE_V0_LU_TYPE_STEERING_REGISTERS_1 = 0x30, - DR_STE_V0_LU_TYPE_TUNNEL_HEADER = 0x34, - DR_STE_V0_LU_TYPE_DONT_CARE = MLX5DR_STE_LU_TYPE_DONT_CARE, -}; - -enum { - DR_STE_V0_ACTION_MDFY_FLD_L2_0 = 0, - DR_STE_V0_ACTION_MDFY_FLD_L2_1 = 1, - DR_STE_V0_ACTION_MDFY_FLD_L2_2 = 2, - DR_STE_V0_ACTION_MDFY_FLD_L3_0 = 3, - DR_STE_V0_ACTION_MDFY_FLD_L3_1 = 4, - DR_STE_V0_ACTION_MDFY_FLD_L3_2 = 5, - DR_STE_V0_ACTION_MDFY_FLD_L3_3 = 6, - DR_STE_V0_ACTION_MDFY_FLD_L3_4 = 7, - DR_STE_V0_ACTION_MDFY_FLD_L4_0 = 8, - DR_STE_V0_ACTION_MDFY_FLD_L4_1 = 9, - DR_STE_V0_ACTION_MDFY_FLD_MPLS = 10, - DR_STE_V0_ACTION_MDFY_FLD_L2_TNL_0 = 11, - DR_STE_V0_ACTION_MDFY_FLD_REG_0 = 12, - DR_STE_V0_ACTION_MDFY_FLD_REG_1 = 13, - DR_STE_V0_ACTION_MDFY_FLD_REG_2 = 14, - DR_STE_V0_ACTION_MDFY_FLD_REG_3 = 15, - DR_STE_V0_ACTION_MDFY_FLD_L4_2 = 16, - DR_STE_V0_ACTION_MDFY_FLD_FLEX_0 = 17, - DR_STE_V0_ACTION_MDFY_FLD_FLEX_1 = 18, - DR_STE_V0_ACTION_MDFY_FLD_FLEX_2 = 19, - DR_STE_V0_ACTION_MDFY_FLD_FLEX_3 = 20, - DR_STE_V0_ACTION_MDFY_FLD_L2_TNL_1 = 21, - DR_STE_V0_ACTION_MDFY_FLD_METADATA = 22, - DR_STE_V0_ACTION_MDFY_FLD_RESERVED = 23, -}; - -static const struct mlx5dr_ste_action_modify_field dr_ste_v0_action_modify_field_arr[] = { - [MLX5_ACTION_IN_FIELD_OUT_SMAC_47_16] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_1, .start = 16, .end = 47, - }, - [MLX5_ACTION_IN_FIELD_OUT_SMAC_15_0] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_1, .start = 0, .end = 15, - }, - [MLX5_ACTION_IN_FIELD_OUT_ETHERTYPE] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_2, .start = 32, .end = 47, - }, - [MLX5_ACTION_IN_FIELD_OUT_DMAC_47_16] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_0, .start = 16, .end = 47, - }, - [MLX5_ACTION_IN_FIELD_OUT_DMAC_15_0] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_0, .start = 0, .end = 15, - }, - [MLX5_ACTION_IN_FIELD_OUT_IP_DSCP] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_1, .start = 0, .end = 5, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_FLAGS] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 48, .end = 56, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 0, .end = 15, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 16, .end = 31, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_IP_TTL] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_1, .start = 8, .end = 15, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_1, .start = 8, .end = 15, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 0, .end = 15, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, - }, - [MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 16, .end = 31, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_3, .start = 32, .end = 63, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_3, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_4, .start = 32, .end = 63, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_4, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_0, .start = 32, .end = 63, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_0, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_2, .start = 32, .end = 63, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_2, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV4] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_0, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV4] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_0, .start = 32, .end = 63, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_A] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_METADATA, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_B] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_METADATA, .start = 32, .end = 63, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_0] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_0, .start = 32, .end = 63, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_1] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_2] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_1, .start = 32, .end = 63, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_3] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_4] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_2, .start = 32, .end = 63, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_5] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_2, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_1, .start = 32, .end = 63, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_FIRST_VID] = { - .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_2, .start = 0, .end = 15, - }, -}; - -static void dr_ste_v0_set_entry_type(u8 *hw_ste_p, u8 entry_type) -{ - MLX5_SET(ste_general, hw_ste_p, entry_type, entry_type); -} - -static u8 dr_ste_v0_get_entry_type(u8 *hw_ste_p) -{ - return MLX5_GET(ste_general, hw_ste_p, entry_type); -} - -static void dr_ste_v0_set_miss_addr(u8 *hw_ste_p, u64 miss_addr) -{ - u64 index = miss_addr >> 6; - - /* Miss address for TX and RX STEs located in the same offsets */ - MLX5_SET(ste_rx_steering_mult, hw_ste_p, miss_address_39_32, index >> 26); - MLX5_SET(ste_rx_steering_mult, hw_ste_p, miss_address_31_6, index); -} - -static u64 dr_ste_v0_get_miss_addr(u8 *hw_ste_p) -{ - u64 index = - ((u64)MLX5_GET(ste_rx_steering_mult, hw_ste_p, miss_address_31_6) | - ((u64)MLX5_GET(ste_rx_steering_mult, hw_ste_p, miss_address_39_32)) << 26); - - return index << 6; -} - -static void dr_ste_v0_set_byte_mask(u8 *hw_ste_p, u16 byte_mask) -{ - MLX5_SET(ste_general, hw_ste_p, byte_mask, byte_mask); -} - -static u16 dr_ste_v0_get_byte_mask(u8 *hw_ste_p) -{ - return MLX5_GET(ste_general, hw_ste_p, byte_mask); -} - -static void dr_ste_v0_set_lu_type(u8 *hw_ste_p, u16 lu_type) -{ - MLX5_SET(ste_general, hw_ste_p, entry_sub_type, lu_type); -} - -static void dr_ste_v0_set_next_lu_type(u8 *hw_ste_p, u16 lu_type) -{ - MLX5_SET(ste_general, hw_ste_p, next_lu_type, lu_type); -} - -static u16 dr_ste_v0_get_next_lu_type(u8 *hw_ste_p) -{ - return MLX5_GET(ste_general, hw_ste_p, next_lu_type); -} - -static void dr_ste_v0_set_hit_gvmi(u8 *hw_ste_p, u16 gvmi) -{ - MLX5_SET(ste_general, hw_ste_p, next_table_base_63_48, gvmi); -} - -static void dr_ste_v0_set_hit_addr(u8 *hw_ste_p, u64 icm_addr, u32 ht_size) -{ - u64 index = (icm_addr >> 5) | ht_size; - - MLX5_SET(ste_general, hw_ste_p, next_table_base_39_32_size, index >> 27); - MLX5_SET(ste_general, hw_ste_p, next_table_base_31_5_size, index); -} - -static void dr_ste_v0_init_full(u8 *hw_ste_p, u16 lu_type, - enum dr_ste_v0_entry_type entry_type, u16 gvmi) -{ - dr_ste_v0_set_entry_type(hw_ste_p, entry_type); - dr_ste_v0_set_lu_type(hw_ste_p, lu_type); - dr_ste_v0_set_next_lu_type(hw_ste_p, MLX5DR_STE_LU_TYPE_DONT_CARE); - - /* Set GVMI once, this is the same for RX/TX - * bits 63_48 of next table base / miss address encode the next GVMI - */ - MLX5_SET(ste_rx_steering_mult, hw_ste_p, gvmi, gvmi); - MLX5_SET(ste_rx_steering_mult, hw_ste_p, next_table_base_63_48, gvmi); - MLX5_SET(ste_rx_steering_mult, hw_ste_p, miss_address_63_48, gvmi); -} - -static void dr_ste_v0_init(u8 *hw_ste_p, u16 lu_type, - bool is_rx, u16 gvmi) -{ - enum dr_ste_v0_entry_type entry_type; - - entry_type = is_rx ? DR_STE_TYPE_RX : DR_STE_TYPE_TX; - dr_ste_v0_init_full(hw_ste_p, lu_type, entry_type, gvmi); -} - -static void dr_ste_v0_rx_set_flow_tag(u8 *hw_ste_p, u32 flow_tag) -{ - MLX5_SET(ste_rx_steering_mult, hw_ste_p, qp_list_pointer, - DR_STE_ENABLE_FLOW_TAG | flow_tag); -} - -static void dr_ste_v0_set_counter_id(u8 *hw_ste_p, u32 ctr_id) -{ - /* This can be used for both rx_steering_mult and for sx_transmit */ - MLX5_SET(ste_rx_steering_mult, hw_ste_p, counter_trigger_15_0, ctr_id); - MLX5_SET(ste_rx_steering_mult, hw_ste_p, counter_trigger_23_16, ctr_id >> 16); -} - -static void dr_ste_v0_set_go_back_bit(u8 *hw_ste_p) -{ - MLX5_SET(ste_sx_transmit, hw_ste_p, go_back, 1); -} - -static void dr_ste_v0_set_tx_push_vlan(u8 *hw_ste_p, u32 vlan_hdr, - bool go_back) -{ - MLX5_SET(ste_sx_transmit, hw_ste_p, action_type, - DR_STE_ACTION_TYPE_PUSH_VLAN); - MLX5_SET(ste_sx_transmit, hw_ste_p, encap_pointer_vlan_data, vlan_hdr); - /* Due to HW limitation we need to set this bit, otherwise reformat + - * push vlan will not work. - */ - if (go_back) - dr_ste_v0_set_go_back_bit(hw_ste_p); -} - -static void dr_ste_v0_set_tx_encap(void *hw_ste_p, u32 reformat_id, - int size, bool encap_l3) -{ - MLX5_SET(ste_sx_transmit, hw_ste_p, action_type, - encap_l3 ? DR_STE_ACTION_TYPE_ENCAP_L3 : DR_STE_ACTION_TYPE_ENCAP); - /* The hardware expects here size in words (2 byte) */ - MLX5_SET(ste_sx_transmit, hw_ste_p, action_description, size / 2); - MLX5_SET(ste_sx_transmit, hw_ste_p, encap_pointer_vlan_data, reformat_id); -} - -static void dr_ste_v0_set_rx_decap(u8 *hw_ste_p) -{ - MLX5_SET(ste_rx_steering_mult, hw_ste_p, tunneling_action, - DR_STE_TUNL_ACTION_DECAP); - MLX5_SET(ste_rx_steering_mult, hw_ste_p, fail_on_error, 1); -} - -static void dr_ste_v0_set_rx_pop_vlan(u8 *hw_ste_p) -{ - MLX5_SET(ste_rx_steering_mult, hw_ste_p, tunneling_action, - DR_STE_TUNL_ACTION_POP_VLAN); -} - -static void dr_ste_v0_set_rx_decap_l3(u8 *hw_ste_p, bool vlan) -{ - MLX5_SET(ste_rx_steering_mult, hw_ste_p, tunneling_action, - DR_STE_TUNL_ACTION_L3_DECAP); - MLX5_SET(ste_modify_packet, hw_ste_p, action_description, vlan ? 1 : 0); - MLX5_SET(ste_rx_steering_mult, hw_ste_p, fail_on_error, 1); -} - -static void dr_ste_v0_set_rewrite_actions(u8 *hw_ste_p, u16 num_of_actions, - u32 re_write_index) -{ - MLX5_SET(ste_modify_packet, hw_ste_p, number_of_re_write_actions, - num_of_actions); - MLX5_SET(ste_modify_packet, hw_ste_p, header_re_write_actions_pointer, - re_write_index); -} - -static void dr_ste_v0_arr_init_next(u8 **last_ste, - u32 *added_stes, - enum dr_ste_v0_entry_type entry_type, - u16 gvmi) -{ - (*added_stes)++; - *last_ste += DR_STE_SIZE; - dr_ste_v0_init_full(*last_ste, MLX5DR_STE_LU_TYPE_DONT_CARE, - entry_type, gvmi); -} - -static void -dr_ste_v0_set_actions_tx(struct mlx5dr_domain *dmn, - u8 *action_type_set, - u32 actions_caps, - u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes) -{ - bool encap = action_type_set[DR_ACTION_TYP_L2_TO_TNL_L2] || - action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]; - - /* We want to make sure the modify header comes before L2 - * encapsulation. The reason for that is that we support - * modify headers for outer headers only - */ - if (action_type_set[DR_ACTION_TYP_MODIFY_HDR] && attr->modify_actions) { - dr_ste_v0_set_entry_type(last_ste, DR_STE_TYPE_MODIFY_PKT); - dr_ste_v0_set_rewrite_actions(last_ste, - attr->modify_actions, - attr->modify_index); - } - - if (action_type_set[DR_ACTION_TYP_PUSH_VLAN]) { - int i; - - for (i = 0; i < attr->vlans.count; i++) { - if (i || action_type_set[DR_ACTION_TYP_MODIFY_HDR]) - dr_ste_v0_arr_init_next(&last_ste, - added_stes, - DR_STE_TYPE_TX, - attr->gvmi); - - dr_ste_v0_set_tx_push_vlan(last_ste, - attr->vlans.headers[i], - encap); - } - } - - if (encap) { - /* Modify header and encapsulation require a different STEs. - * Since modify header STE format doesn't support encapsulation - * tunneling_action. - */ - if (action_type_set[DR_ACTION_TYP_MODIFY_HDR] || - action_type_set[DR_ACTION_TYP_PUSH_VLAN]) - dr_ste_v0_arr_init_next(&last_ste, - added_stes, - DR_STE_TYPE_TX, - attr->gvmi); - - dr_ste_v0_set_tx_encap(last_ste, - attr->reformat.id, - attr->reformat.size, - action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]); - /* Whenever prio_tag_required enabled, we can be sure that the - * previous table (ACL) already push vlan to our packet, - * And due to HW limitation we need to set this bit, otherwise - * push vlan + reformat will not work. - */ - if (MLX5_CAP_GEN(dmn->mdev, prio_tag_required)) - dr_ste_v0_set_go_back_bit(last_ste); - } - - if (action_type_set[DR_ACTION_TYP_CTR]) - dr_ste_v0_set_counter_id(last_ste, attr->ctr_id); - - dr_ste_v0_set_hit_gvmi(last_ste, attr->hit_gvmi); - dr_ste_v0_set_hit_addr(last_ste, attr->final_icm_addr, 1); -} - -static void -dr_ste_v0_set_actions_rx(struct mlx5dr_domain *dmn, - u8 *action_type_set, - u32 actions_caps, - u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes) -{ - if (action_type_set[DR_ACTION_TYP_CTR]) - dr_ste_v0_set_counter_id(last_ste, attr->ctr_id); - - if (action_type_set[DR_ACTION_TYP_TNL_L3_TO_L2]) { - dr_ste_v0_set_entry_type(last_ste, DR_STE_TYPE_MODIFY_PKT); - dr_ste_v0_set_rx_decap_l3(last_ste, attr->decap_with_vlan); - dr_ste_v0_set_rewrite_actions(last_ste, - attr->decap_actions, - attr->decap_index); - } - - if (action_type_set[DR_ACTION_TYP_TNL_L2_TO_L2]) - dr_ste_v0_set_rx_decap(last_ste); - - if (action_type_set[DR_ACTION_TYP_POP_VLAN]) { - int i; - - for (i = 0; i < attr->vlans.count; i++) { - if (i || - action_type_set[DR_ACTION_TYP_TNL_L2_TO_L2] || - action_type_set[DR_ACTION_TYP_TNL_L3_TO_L2]) - dr_ste_v0_arr_init_next(&last_ste, - added_stes, - DR_STE_TYPE_RX, - attr->gvmi); - - dr_ste_v0_set_rx_pop_vlan(last_ste); - } - } - - if (action_type_set[DR_ACTION_TYP_MODIFY_HDR] && attr->modify_actions) { - if (dr_ste_v0_get_entry_type(last_ste) == DR_STE_TYPE_MODIFY_PKT) - dr_ste_v0_arr_init_next(&last_ste, - added_stes, - DR_STE_TYPE_MODIFY_PKT, - attr->gvmi); - else - dr_ste_v0_set_entry_type(last_ste, DR_STE_TYPE_MODIFY_PKT); - - dr_ste_v0_set_rewrite_actions(last_ste, - attr->modify_actions, - attr->modify_index); - } - - if (action_type_set[DR_ACTION_TYP_TAG]) { - if (dr_ste_v0_get_entry_type(last_ste) == DR_STE_TYPE_MODIFY_PKT) - dr_ste_v0_arr_init_next(&last_ste, - added_stes, - DR_STE_TYPE_RX, - attr->gvmi); - - dr_ste_v0_rx_set_flow_tag(last_ste, attr->flow_tag); - } - - dr_ste_v0_set_hit_gvmi(last_ste, attr->hit_gvmi); - dr_ste_v0_set_hit_addr(last_ste, attr->final_icm_addr, 1); -} - -static void dr_ste_v0_set_action_set(u8 *hw_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data) -{ - length = (length == 32) ? 0 : length; - MLX5_SET(dr_action_hw_set, hw_action, opcode, DR_STE_ACTION_MDFY_OP_SET); - MLX5_SET(dr_action_hw_set, hw_action, destination_field_code, hw_field); - MLX5_SET(dr_action_hw_set, hw_action, destination_left_shifter, shifter); - MLX5_SET(dr_action_hw_set, hw_action, destination_length, length); - MLX5_SET(dr_action_hw_set, hw_action, inline_data, data); -} - -static void dr_ste_v0_set_action_add(u8 *hw_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data) -{ - length = (length == 32) ? 0 : length; - MLX5_SET(dr_action_hw_set, hw_action, opcode, DR_STE_ACTION_MDFY_OP_ADD); - MLX5_SET(dr_action_hw_set, hw_action, destination_field_code, hw_field); - MLX5_SET(dr_action_hw_set, hw_action, destination_left_shifter, shifter); - MLX5_SET(dr_action_hw_set, hw_action, destination_length, length); - MLX5_SET(dr_action_hw_set, hw_action, inline_data, data); -} - -static void dr_ste_v0_set_action_copy(u8 *hw_action, - u8 dst_hw_field, - u8 dst_shifter, - u8 dst_len, - u8 src_hw_field, - u8 src_shifter) -{ - MLX5_SET(dr_action_hw_copy, hw_action, opcode, DR_STE_ACTION_MDFY_OP_COPY); - MLX5_SET(dr_action_hw_copy, hw_action, destination_field_code, dst_hw_field); - MLX5_SET(dr_action_hw_copy, hw_action, destination_left_shifter, dst_shifter); - MLX5_SET(dr_action_hw_copy, hw_action, destination_length, dst_len); - MLX5_SET(dr_action_hw_copy, hw_action, source_field_code, src_hw_field); - MLX5_SET(dr_action_hw_copy, hw_action, source_left_shifter, src_shifter); -} - -#define DR_STE_DECAP_L3_MIN_ACTION_NUM 5 - -static int -dr_ste_v0_set_action_decap_l3_list(void *data, u32 data_sz, - u8 *hw_action, u32 hw_action_sz, - u16 *used_hw_action_num) -{ - struct mlx5_ifc_l2_hdr_bits *l2_hdr = data; - u32 hw_action_num; - int required_actions; - u32 hdr_fld_4b; - u16 hdr_fld_2b; - u16 vlan_type; - bool vlan; - - vlan = (data_sz != HDR_LEN_L2); - hw_action_num = hw_action_sz / MLX5_ST_SZ_BYTES(dr_action_hw_set); - required_actions = DR_STE_DECAP_L3_MIN_ACTION_NUM + !!vlan; - - if (hw_action_num < required_actions) - return -ENOMEM; - - /* dmac_47_16 */ - MLX5_SET(dr_action_hw_set, hw_action, - opcode, DR_STE_ACTION_MDFY_OP_SET); - MLX5_SET(dr_action_hw_set, hw_action, - destination_length, 0); - MLX5_SET(dr_action_hw_set, hw_action, - destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_0); - MLX5_SET(dr_action_hw_set, hw_action, - destination_left_shifter, 16); - hdr_fld_4b = MLX5_GET(l2_hdr, l2_hdr, dmac_47_16); - MLX5_SET(dr_action_hw_set, hw_action, - inline_data, hdr_fld_4b); - hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); - - /* smac_47_16 */ - MLX5_SET(dr_action_hw_set, hw_action, - opcode, DR_STE_ACTION_MDFY_OP_SET); - MLX5_SET(dr_action_hw_set, hw_action, - destination_length, 0); - MLX5_SET(dr_action_hw_set, hw_action, - destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_1); - MLX5_SET(dr_action_hw_set, hw_action, destination_left_shifter, 16); - hdr_fld_4b = (MLX5_GET(l2_hdr, l2_hdr, smac_31_0) >> 16 | - MLX5_GET(l2_hdr, l2_hdr, smac_47_32) << 16); - MLX5_SET(dr_action_hw_set, hw_action, inline_data, hdr_fld_4b); - hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); - - /* dmac_15_0 */ - MLX5_SET(dr_action_hw_set, hw_action, - opcode, DR_STE_ACTION_MDFY_OP_SET); - MLX5_SET(dr_action_hw_set, hw_action, - destination_length, 16); - MLX5_SET(dr_action_hw_set, hw_action, - destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_0); - MLX5_SET(dr_action_hw_set, hw_action, - destination_left_shifter, 0); - hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, dmac_15_0); - MLX5_SET(dr_action_hw_set, hw_action, - inline_data, hdr_fld_2b); - hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); - - /* ethertype + (optional) vlan */ - MLX5_SET(dr_action_hw_set, hw_action, - opcode, DR_STE_ACTION_MDFY_OP_SET); - MLX5_SET(dr_action_hw_set, hw_action, - destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_2); - MLX5_SET(dr_action_hw_set, hw_action, - destination_left_shifter, 32); - if (!vlan) { - hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, ethertype); - MLX5_SET(dr_action_hw_set, hw_action, inline_data, hdr_fld_2b); - MLX5_SET(dr_action_hw_set, hw_action, destination_length, 16); - } else { - hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, ethertype); - vlan_type = hdr_fld_2b == SVLAN_ETHERTYPE ? DR_STE_SVLAN : DR_STE_CVLAN; - hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, vlan); - hdr_fld_4b = (vlan_type << 16) | hdr_fld_2b; - MLX5_SET(dr_action_hw_set, hw_action, inline_data, hdr_fld_4b); - MLX5_SET(dr_action_hw_set, hw_action, destination_length, 18); - } - hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); - - /* smac_15_0 */ - MLX5_SET(dr_action_hw_set, hw_action, - opcode, DR_STE_ACTION_MDFY_OP_SET); - MLX5_SET(dr_action_hw_set, hw_action, - destination_length, 16); - MLX5_SET(dr_action_hw_set, hw_action, - destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_1); - MLX5_SET(dr_action_hw_set, hw_action, - destination_left_shifter, 0); - hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, smac_31_0); - MLX5_SET(dr_action_hw_set, hw_action, inline_data, hdr_fld_2b); - hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); - - if (vlan) { - MLX5_SET(dr_action_hw_set, hw_action, - opcode, DR_STE_ACTION_MDFY_OP_SET); - hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, vlan_type); - MLX5_SET(dr_action_hw_set, hw_action, - inline_data, hdr_fld_2b); - MLX5_SET(dr_action_hw_set, hw_action, - destination_length, 16); - MLX5_SET(dr_action_hw_set, hw_action, - destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_2); - MLX5_SET(dr_action_hw_set, hw_action, - destination_left_shifter, 0); - } - - *used_hw_action_num = required_actions; - - return 0; -} - -static void -dr_ste_v0_build_eth_l2_src_dst_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, dmac_47_16, mask, dmac_47_16); - DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, dmac_15_0, mask, dmac_15_0); - - if (mask->smac_47_16 || mask->smac_15_0) { - MLX5_SET(ste_eth_l2_src_dst, bit_mask, smac_47_32, - mask->smac_47_16 >> 16); - MLX5_SET(ste_eth_l2_src_dst, bit_mask, smac_31_0, - mask->smac_47_16 << 16 | mask->smac_15_0); - mask->smac_47_16 = 0; - mask->smac_15_0 = 0; - } - - DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, first_vlan_id, mask, first_vid); - DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, first_cfi, mask, first_cfi); - DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, first_priority, mask, first_prio); - DR_STE_SET_ONES(eth_l2_src_dst, bit_mask, l3_type, mask, ip_version); - - if (mask->cvlan_tag) { - MLX5_SET(ste_eth_l2_src_dst, bit_mask, first_vlan_qualifier, -1); - mask->cvlan_tag = 0; - } else if (mask->svlan_tag) { - MLX5_SET(ste_eth_l2_src_dst, bit_mask, first_vlan_qualifier, -1); - mask->svlan_tag = 0; - } -} - -static int -dr_ste_v0_build_eth_l2_src_dst_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_src_dst, tag, dmac_47_16, spec, dmac_47_16); - DR_STE_SET_TAG(eth_l2_src_dst, tag, dmac_15_0, spec, dmac_15_0); - - if (spec->smac_47_16 || spec->smac_15_0) { - MLX5_SET(ste_eth_l2_src_dst, tag, smac_47_32, - spec->smac_47_16 >> 16); - MLX5_SET(ste_eth_l2_src_dst, tag, smac_31_0, - spec->smac_47_16 << 16 | spec->smac_15_0); - spec->smac_47_16 = 0; - spec->smac_15_0 = 0; - } - - if (spec->ip_version) { - if (spec->ip_version == IP_VERSION_IPV4) { - MLX5_SET(ste_eth_l2_src_dst, tag, l3_type, STE_IPV4); - spec->ip_version = 0; - } else if (spec->ip_version == IP_VERSION_IPV6) { - MLX5_SET(ste_eth_l2_src_dst, tag, l3_type, STE_IPV6); - spec->ip_version = 0; - } else { - return -EINVAL; - } - } - - DR_STE_SET_TAG(eth_l2_src_dst, tag, first_vlan_id, spec, first_vid); - DR_STE_SET_TAG(eth_l2_src_dst, tag, first_cfi, spec, first_cfi); - DR_STE_SET_TAG(eth_l2_src_dst, tag, first_priority, spec, first_prio); - - if (spec->cvlan_tag) { - MLX5_SET(ste_eth_l2_src_dst, tag, first_vlan_qualifier, DR_STE_CVLAN); - spec->cvlan_tag = 0; - } else if (spec->svlan_tag) { - MLX5_SET(ste_eth_l2_src_dst, tag, first_vlan_qualifier, DR_STE_SVLAN); - spec->svlan_tag = 0; - } - return 0; -} - -static void -dr_ste_v0_build_eth_l2_src_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l2_src_dst_bit_mask(mask, sb->inner, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL2_SRC_DST, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l2_src_dst_tag; -} - -static int -dr_ste_v0_build_eth_l3_ipv6_dst_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_127_96, spec, dst_ip_127_96); - DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_95_64, spec, dst_ip_95_64); - DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_63_32, spec, dst_ip_63_32); - DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_31_0, spec, dst_ip_31_0); - - return 0; -} - -static void -dr_ste_v0_build_eth_l3_ipv6_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l3_ipv6_dst_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL3_IPV6_DST, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l3_ipv6_dst_tag; -} - -static int -dr_ste_v0_build_eth_l3_ipv6_src_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_127_96, spec, src_ip_127_96); - DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_95_64, spec, src_ip_95_64); - DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_63_32, spec, src_ip_63_32); - DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_31_0, spec, src_ip_31_0); - - return 0; -} - -static void -dr_ste_v0_build_eth_l3_ipv6_src_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l3_ipv6_src_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL3_IPV6_SRC, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l3_ipv6_src_tag; -} - -static int -dr_ste_v0_build_eth_l3_ipv4_5_tuple_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, destination_address, spec, dst_ip_31_0); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, source_address, spec, src_ip_31_0); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, destination_port, spec, tcp_dport); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, destination_port, spec, udp_dport); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, source_port, spec, tcp_sport); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, source_port, spec, udp_sport); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, protocol, spec, ip_protocol); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, fragmented, spec, frag); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, dscp, spec, ip_dscp); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, ecn, spec, ip_ecn); - - if (spec->tcp_flags) { - DR_STE_SET_TCP_FLAGS(eth_l3_ipv4_5_tuple, tag, spec); - spec->tcp_flags = 0; - } - - return 0; -} - -static void -dr_ste_v0_build_eth_l3_ipv4_5_tuple_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l3_ipv4_5_tuple_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL3_IPV4_5_TUPLE, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l3_ipv4_5_tuple_tag; -} - -static void -dr_ste_v0_build_eth_l2_src_or_dst_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc_mask = &value->misc; - - DR_STE_SET_TAG(eth_l2_src, bit_mask, first_vlan_id, mask, first_vid); - DR_STE_SET_TAG(eth_l2_src, bit_mask, first_cfi, mask, first_cfi); - DR_STE_SET_TAG(eth_l2_src, bit_mask, first_priority, mask, first_prio); - DR_STE_SET_TAG(eth_l2_src, bit_mask, ip_fragmented, mask, frag); - DR_STE_SET_TAG(eth_l2_src, bit_mask, l3_ethertype, mask, ethertype); - DR_STE_SET_ONES(eth_l2_src, bit_mask, l3_type, mask, ip_version); - - if (mask->svlan_tag || mask->cvlan_tag) { - MLX5_SET(ste_eth_l2_src, bit_mask, first_vlan_qualifier, -1); - mask->cvlan_tag = 0; - mask->svlan_tag = 0; - } - - if (inner) { - if (misc_mask->inner_second_cvlan_tag || - misc_mask->inner_second_svlan_tag) { - MLX5_SET(ste_eth_l2_src, bit_mask, second_vlan_qualifier, -1); - misc_mask->inner_second_cvlan_tag = 0; - misc_mask->inner_second_svlan_tag = 0; - } - - DR_STE_SET_TAG(eth_l2_src, bit_mask, - second_vlan_id, misc_mask, inner_second_vid); - DR_STE_SET_TAG(eth_l2_src, bit_mask, - second_cfi, misc_mask, inner_second_cfi); - DR_STE_SET_TAG(eth_l2_src, bit_mask, - second_priority, misc_mask, inner_second_prio); - } else { - if (misc_mask->outer_second_cvlan_tag || - misc_mask->outer_second_svlan_tag) { - MLX5_SET(ste_eth_l2_src, bit_mask, second_vlan_qualifier, -1); - misc_mask->outer_second_cvlan_tag = 0; - misc_mask->outer_second_svlan_tag = 0; - } - - DR_STE_SET_TAG(eth_l2_src, bit_mask, - second_vlan_id, misc_mask, outer_second_vid); - DR_STE_SET_TAG(eth_l2_src, bit_mask, - second_cfi, misc_mask, outer_second_cfi); - DR_STE_SET_TAG(eth_l2_src, bit_mask, - second_priority, misc_mask, outer_second_prio); - } -} - -static int -dr_ste_v0_build_eth_l2_src_or_dst_tag(struct mlx5dr_match_param *value, - bool inner, u8 *tag) -{ - struct mlx5dr_match_spec *spec = inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc_spec = &value->misc; - - DR_STE_SET_TAG(eth_l2_src, tag, first_vlan_id, spec, first_vid); - DR_STE_SET_TAG(eth_l2_src, tag, first_cfi, spec, first_cfi); - DR_STE_SET_TAG(eth_l2_src, tag, first_priority, spec, first_prio); - DR_STE_SET_TAG(eth_l2_src, tag, ip_fragmented, spec, frag); - DR_STE_SET_TAG(eth_l2_src, tag, l3_ethertype, spec, ethertype); - - if (spec->ip_version) { - if (spec->ip_version == IP_VERSION_IPV4) { - MLX5_SET(ste_eth_l2_src, tag, l3_type, STE_IPV4); - spec->ip_version = 0; - } else if (spec->ip_version == IP_VERSION_IPV6) { - MLX5_SET(ste_eth_l2_src, tag, l3_type, STE_IPV6); - spec->ip_version = 0; - } else { - return -EINVAL; - } - } - - if (spec->cvlan_tag) { - MLX5_SET(ste_eth_l2_src, tag, first_vlan_qualifier, DR_STE_CVLAN); - spec->cvlan_tag = 0; - } else if (spec->svlan_tag) { - MLX5_SET(ste_eth_l2_src, tag, first_vlan_qualifier, DR_STE_SVLAN); - spec->svlan_tag = 0; - } - - if (inner) { - if (misc_spec->inner_second_cvlan_tag) { - MLX5_SET(ste_eth_l2_src, tag, second_vlan_qualifier, DR_STE_CVLAN); - misc_spec->inner_second_cvlan_tag = 0; - } else if (misc_spec->inner_second_svlan_tag) { - MLX5_SET(ste_eth_l2_src, tag, second_vlan_qualifier, DR_STE_SVLAN); - misc_spec->inner_second_svlan_tag = 0; - } - - DR_STE_SET_TAG(eth_l2_src, tag, second_vlan_id, misc_spec, inner_second_vid); - DR_STE_SET_TAG(eth_l2_src, tag, second_cfi, misc_spec, inner_second_cfi); - DR_STE_SET_TAG(eth_l2_src, tag, second_priority, misc_spec, inner_second_prio); - } else { - if (misc_spec->outer_second_cvlan_tag) { - MLX5_SET(ste_eth_l2_src, tag, second_vlan_qualifier, DR_STE_CVLAN); - misc_spec->outer_second_cvlan_tag = 0; - } else if (misc_spec->outer_second_svlan_tag) { - MLX5_SET(ste_eth_l2_src, tag, second_vlan_qualifier, DR_STE_SVLAN); - misc_spec->outer_second_svlan_tag = 0; - } - DR_STE_SET_TAG(eth_l2_src, tag, second_vlan_id, misc_spec, outer_second_vid); - DR_STE_SET_TAG(eth_l2_src, tag, second_cfi, misc_spec, outer_second_cfi); - DR_STE_SET_TAG(eth_l2_src, tag, second_priority, misc_spec, outer_second_prio); - } - - return 0; -} - -static void -dr_ste_v0_build_eth_l2_src_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_src, bit_mask, smac_47_16, mask, smac_47_16); - DR_STE_SET_TAG(eth_l2_src, bit_mask, smac_15_0, mask, smac_15_0); - - dr_ste_v0_build_eth_l2_src_or_dst_bit_mask(value, inner, bit_mask); -} - -static int -dr_ste_v0_build_eth_l2_src_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_src, tag, smac_47_16, spec, smac_47_16); - DR_STE_SET_TAG(eth_l2_src, tag, smac_15_0, spec, smac_15_0); - - return dr_ste_v0_build_eth_l2_src_or_dst_tag(value, sb->inner, tag); -} - -static void -dr_ste_v0_build_eth_l2_src_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l2_src_bit_mask(mask, sb->inner, sb->bit_mask); - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL2_SRC, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l2_src_tag; -} - -static void -dr_ste_v0_build_eth_l2_dst_bit_mask(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_dst, bit_mask, dmac_47_16, mask, dmac_47_16); - DR_STE_SET_TAG(eth_l2_dst, bit_mask, dmac_15_0, mask, dmac_15_0); - - dr_ste_v0_build_eth_l2_src_or_dst_bit_mask(value, sb->inner, bit_mask); -} - -static int -dr_ste_v0_build_eth_l2_dst_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_dst, tag, dmac_47_16, spec, dmac_47_16); - DR_STE_SET_TAG(eth_l2_dst, tag, dmac_15_0, spec, dmac_15_0); - - return dr_ste_v0_build_eth_l2_src_or_dst_tag(value, sb->inner, tag); -} - -static void -dr_ste_v0_build_eth_l2_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l2_dst_bit_mask(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL2_DST, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l2_dst_tag; -} - -static void -dr_ste_v0_build_eth_l2_tnl_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(eth_l2_tnl, bit_mask, dmac_47_16, mask, dmac_47_16); - DR_STE_SET_TAG(eth_l2_tnl, bit_mask, dmac_15_0, mask, dmac_15_0); - DR_STE_SET_TAG(eth_l2_tnl, bit_mask, first_vlan_id, mask, first_vid); - DR_STE_SET_TAG(eth_l2_tnl, bit_mask, first_cfi, mask, first_cfi); - DR_STE_SET_TAG(eth_l2_tnl, bit_mask, first_priority, mask, first_prio); - DR_STE_SET_TAG(eth_l2_tnl, bit_mask, ip_fragmented, mask, frag); - DR_STE_SET_TAG(eth_l2_tnl, bit_mask, l3_ethertype, mask, ethertype); - DR_STE_SET_ONES(eth_l2_tnl, bit_mask, l3_type, mask, ip_version); - - if (misc->vxlan_vni) { - MLX5_SET(ste_eth_l2_tnl, bit_mask, - l2_tunneling_network_id, (misc->vxlan_vni << 8)); - misc->vxlan_vni = 0; - } - - if (mask->svlan_tag || mask->cvlan_tag) { - MLX5_SET(ste_eth_l2_tnl, bit_mask, first_vlan_qualifier, -1); - mask->cvlan_tag = 0; - mask->svlan_tag = 0; - } -} - -static int -dr_ste_v0_build_eth_l2_tnl_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(eth_l2_tnl, tag, dmac_47_16, spec, dmac_47_16); - DR_STE_SET_TAG(eth_l2_tnl, tag, dmac_15_0, spec, dmac_15_0); - DR_STE_SET_TAG(eth_l2_tnl, tag, first_vlan_id, spec, first_vid); - DR_STE_SET_TAG(eth_l2_tnl, tag, first_cfi, spec, first_cfi); - DR_STE_SET_TAG(eth_l2_tnl, tag, ip_fragmented, spec, frag); - DR_STE_SET_TAG(eth_l2_tnl, tag, first_priority, spec, first_prio); - DR_STE_SET_TAG(eth_l2_tnl, tag, l3_ethertype, spec, ethertype); - - if (misc->vxlan_vni) { - MLX5_SET(ste_eth_l2_tnl, tag, l2_tunneling_network_id, - (misc->vxlan_vni << 8)); - misc->vxlan_vni = 0; - } - - if (spec->cvlan_tag) { - MLX5_SET(ste_eth_l2_tnl, tag, first_vlan_qualifier, DR_STE_CVLAN); - spec->cvlan_tag = 0; - } else if (spec->svlan_tag) { - MLX5_SET(ste_eth_l2_tnl, tag, first_vlan_qualifier, DR_STE_SVLAN); - spec->svlan_tag = 0; - } - - if (spec->ip_version) { - if (spec->ip_version == IP_VERSION_IPV4) { - MLX5_SET(ste_eth_l2_tnl, tag, l3_type, STE_IPV4); - spec->ip_version = 0; - } else if (spec->ip_version == IP_VERSION_IPV6) { - MLX5_SET(ste_eth_l2_tnl, tag, l3_type, STE_IPV6); - spec->ip_version = 0; - } else { - return -EINVAL; - } - } - - return 0; -} - -static void -dr_ste_v0_build_eth_l2_tnl_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l2_tnl_bit_mask(mask, sb->inner, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_ETHL2_TUNNELING_I; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l2_tnl_tag; -} - -static int -dr_ste_v0_build_eth_l3_ipv4_misc_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l3_ipv4_misc, tag, time_to_live, spec, ttl_hoplimit); - DR_STE_SET_TAG(eth_l3_ipv4_misc, tag, ihl, spec, ipv4_ihl); - - return 0; -} - -static void -dr_ste_v0_build_eth_l3_ipv4_misc_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l3_ipv4_misc_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL3_IPV4_MISC, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l3_ipv4_misc_tag; -} - -static int -dr_ste_v0_build_eth_ipv6_l3_l4_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(eth_l4, tag, dst_port, spec, tcp_dport); - DR_STE_SET_TAG(eth_l4, tag, src_port, spec, tcp_sport); - DR_STE_SET_TAG(eth_l4, tag, dst_port, spec, udp_dport); - DR_STE_SET_TAG(eth_l4, tag, src_port, spec, udp_sport); - DR_STE_SET_TAG(eth_l4, tag, protocol, spec, ip_protocol); - DR_STE_SET_TAG(eth_l4, tag, fragmented, spec, frag); - DR_STE_SET_TAG(eth_l4, tag, dscp, spec, ip_dscp); - DR_STE_SET_TAG(eth_l4, tag, ecn, spec, ip_ecn); - DR_STE_SET_TAG(eth_l4, tag, ipv6_hop_limit, spec, ttl_hoplimit); - - if (sb->inner) - DR_STE_SET_TAG(eth_l4, tag, flow_label, misc, inner_ipv6_flow_label); - else - DR_STE_SET_TAG(eth_l4, tag, flow_label, misc, outer_ipv6_flow_label); - - if (spec->tcp_flags) { - DR_STE_SET_TCP_FLAGS(eth_l4, tag, spec); - spec->tcp_flags = 0; - } - - return 0; -} - -static void -dr_ste_v0_build_eth_ipv6_l3_l4_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_ipv6_l3_l4_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL4, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_ipv6_l3_l4_tag; -} - -static int -dr_ste_v0_build_mpls_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - - if (sb->inner) - DR_STE_SET_MPLS(mpls, misc2, inner, tag); - else - DR_STE_SET_MPLS(mpls, misc2, outer, tag); - - return 0; -} - -static void -dr_ste_v0_build_mpls_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_mpls_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(MPLS_FIRST, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_mpls_tag; -} - -static int -dr_ste_v0_build_tnl_gre_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(gre, tag, gre_protocol, misc, gre_protocol); - - DR_STE_SET_TAG(gre, tag, gre_k_present, misc, gre_k_present); - DR_STE_SET_TAG(gre, tag, gre_key_h, misc, gre_key_h); - DR_STE_SET_TAG(gre, tag, gre_key_l, misc, gre_key_l); - - DR_STE_SET_TAG(gre, tag, gre_c_present, misc, gre_c_present); - - DR_STE_SET_TAG(gre, tag, gre_s_present, misc, gre_s_present); - - return 0; -} - -static void -dr_ste_v0_build_tnl_gre_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_tnl_gre_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_GRE; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_tnl_gre_tag; -} - -static int -dr_ste_v0_build_tnl_mpls_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc_2 = &value->misc2; - u32 mpls_hdr; - - if (DR_STE_IS_OUTER_MPLS_OVER_GRE_SET(misc_2)) { - mpls_hdr = misc_2->outer_first_mpls_over_gre_label << HDR_MPLS_OFFSET_LABEL; - misc_2->outer_first_mpls_over_gre_label = 0; - mpls_hdr |= misc_2->outer_first_mpls_over_gre_exp << HDR_MPLS_OFFSET_EXP; - misc_2->outer_first_mpls_over_gre_exp = 0; - mpls_hdr |= misc_2->outer_first_mpls_over_gre_s_bos << HDR_MPLS_OFFSET_S_BOS; - misc_2->outer_first_mpls_over_gre_s_bos = 0; - mpls_hdr |= misc_2->outer_first_mpls_over_gre_ttl << HDR_MPLS_OFFSET_TTL; - misc_2->outer_first_mpls_over_gre_ttl = 0; - } else { - mpls_hdr = misc_2->outer_first_mpls_over_udp_label << HDR_MPLS_OFFSET_LABEL; - misc_2->outer_first_mpls_over_udp_label = 0; - mpls_hdr |= misc_2->outer_first_mpls_over_udp_exp << HDR_MPLS_OFFSET_EXP; - misc_2->outer_first_mpls_over_udp_exp = 0; - mpls_hdr |= misc_2->outer_first_mpls_over_udp_s_bos << HDR_MPLS_OFFSET_S_BOS; - misc_2->outer_first_mpls_over_udp_s_bos = 0; - mpls_hdr |= misc_2->outer_first_mpls_over_udp_ttl << HDR_MPLS_OFFSET_TTL; - misc_2->outer_first_mpls_over_udp_ttl = 0; - } - - MLX5_SET(ste_flex_parser_0, tag, flex_parser_3, mpls_hdr); - return 0; -} - -static void -dr_ste_v0_build_tnl_mpls_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_tnl_mpls_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_0; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_tnl_mpls_tag; -} - -static int -dr_ste_v0_build_tnl_mpls_over_udp_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - u8 *parser_ptr; - u8 parser_id; - u32 mpls_hdr; - - mpls_hdr = misc2->outer_first_mpls_over_udp_label << HDR_MPLS_OFFSET_LABEL; - misc2->outer_first_mpls_over_udp_label = 0; - mpls_hdr |= misc2->outer_first_mpls_over_udp_exp << HDR_MPLS_OFFSET_EXP; - misc2->outer_first_mpls_over_udp_exp = 0; - mpls_hdr |= misc2->outer_first_mpls_over_udp_s_bos << HDR_MPLS_OFFSET_S_BOS; - misc2->outer_first_mpls_over_udp_s_bos = 0; - mpls_hdr |= misc2->outer_first_mpls_over_udp_ttl << HDR_MPLS_OFFSET_TTL; - misc2->outer_first_mpls_over_udp_ttl = 0; - - parser_id = sb->caps->flex_parser_id_mpls_over_udp; - parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); - *(__be32 *)parser_ptr = cpu_to_be32(mpls_hdr); - - return 0; -} - -static void -dr_ste_v0_build_tnl_mpls_over_udp_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_tnl_mpls_over_udp_tag(mask, sb, sb->bit_mask); - /* STEs with lookup type FLEX_PARSER_{0/1} includes - * flex parsers_{0-3}/{4-7} respectively. - */ - sb->lu_type = sb->caps->flex_parser_id_mpls_over_udp > DR_STE_MAX_FLEX_0_ID ? - DR_STE_V0_LU_TYPE_FLEX_PARSER_1 : - DR_STE_V0_LU_TYPE_FLEX_PARSER_0; - - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_tnl_mpls_over_udp_tag; -} - -static int -dr_ste_v0_build_tnl_mpls_over_gre_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - u8 *parser_ptr; - u8 parser_id; - u32 mpls_hdr; - - mpls_hdr = misc2->outer_first_mpls_over_gre_label << HDR_MPLS_OFFSET_LABEL; - misc2->outer_first_mpls_over_gre_label = 0; - mpls_hdr |= misc2->outer_first_mpls_over_gre_exp << HDR_MPLS_OFFSET_EXP; - misc2->outer_first_mpls_over_gre_exp = 0; - mpls_hdr |= misc2->outer_first_mpls_over_gre_s_bos << HDR_MPLS_OFFSET_S_BOS; - misc2->outer_first_mpls_over_gre_s_bos = 0; - mpls_hdr |= misc2->outer_first_mpls_over_gre_ttl << HDR_MPLS_OFFSET_TTL; - misc2->outer_first_mpls_over_gre_ttl = 0; - - parser_id = sb->caps->flex_parser_id_mpls_over_gre; - parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); - *(__be32 *)parser_ptr = cpu_to_be32(mpls_hdr); - - return 0; -} - -static void -dr_ste_v0_build_tnl_mpls_over_gre_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_tnl_mpls_over_gre_tag(mask, sb, sb->bit_mask); - - /* STEs with lookup type FLEX_PARSER_{0/1} includes - * flex parsers_{0-3}/{4-7} respectively. - */ - sb->lu_type = sb->caps->flex_parser_id_mpls_over_gre > DR_STE_MAX_FLEX_0_ID ? - DR_STE_V0_LU_TYPE_FLEX_PARSER_1 : - DR_STE_V0_LU_TYPE_FLEX_PARSER_0; - - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_tnl_mpls_over_gre_tag; -} - -#define ICMP_TYPE_OFFSET_FIRST_DW 24 -#define ICMP_CODE_OFFSET_FIRST_DW 16 - -static int -dr_ste_v0_build_icmp_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc_3 = &value->misc3; - u32 *icmp_header_data; - int dw0_location; - int dw1_location; - u8 *parser_ptr; - u8 *icmp_type; - u8 *icmp_code; - bool is_ipv4; - u32 icmp_hdr; - - is_ipv4 = DR_MASK_IS_ICMPV4_SET(misc_3); - if (is_ipv4) { - icmp_header_data = &misc_3->icmpv4_header_data; - icmp_type = &misc_3->icmpv4_type; - icmp_code = &misc_3->icmpv4_code; - dw0_location = sb->caps->flex_parser_id_icmp_dw0; - dw1_location = sb->caps->flex_parser_id_icmp_dw1; - } else { - icmp_header_data = &misc_3->icmpv6_header_data; - icmp_type = &misc_3->icmpv6_type; - icmp_code = &misc_3->icmpv6_code; - dw0_location = sb->caps->flex_parser_id_icmpv6_dw0; - dw1_location = sb->caps->flex_parser_id_icmpv6_dw1; - } - - parser_ptr = dr_ste_calc_flex_parser_offset(tag, dw0_location); - icmp_hdr = (*icmp_type << ICMP_TYPE_OFFSET_FIRST_DW) | - (*icmp_code << ICMP_CODE_OFFSET_FIRST_DW); - *(__be32 *)parser_ptr = cpu_to_be32(icmp_hdr); - *icmp_code = 0; - *icmp_type = 0; - - parser_ptr = dr_ste_calc_flex_parser_offset(tag, dw1_location); - *(__be32 *)parser_ptr = cpu_to_be32(*icmp_header_data); - *icmp_header_data = 0; - - return 0; -} - -static void -dr_ste_v0_build_icmp_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - u8 parser_id; - bool is_ipv4; - - dr_ste_v0_build_icmp_tag(mask, sb, sb->bit_mask); - - /* STEs with lookup type FLEX_PARSER_{0/1} includes - * flex parsers_{0-3}/{4-7} respectively. - */ - is_ipv4 = DR_MASK_IS_ICMPV4_SET(&mask->misc3); - parser_id = is_ipv4 ? sb->caps->flex_parser_id_icmp_dw0 : - sb->caps->flex_parser_id_icmpv6_dw0; - sb->lu_type = parser_id > DR_STE_MAX_FLEX_0_ID ? - DR_STE_V0_LU_TYPE_FLEX_PARSER_1 : - DR_STE_V0_LU_TYPE_FLEX_PARSER_0; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_icmp_tag; -} - -static int -dr_ste_v0_build_general_purpose_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc_2 = &value->misc2; - - DR_STE_SET_TAG(general_purpose, tag, general_purpose_lookup_field, - misc_2, metadata_reg_a); - - return 0; -} - -static void -dr_ste_v0_build_general_purpose_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_general_purpose_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_GENERAL_PURPOSE; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_general_purpose_tag; -} - -static int -dr_ste_v0_build_eth_l4_misc_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - - if (sb->inner) { - DR_STE_SET_TAG(eth_l4_misc, tag, seq_num, misc3, inner_tcp_seq_num); - DR_STE_SET_TAG(eth_l4_misc, tag, ack_num, misc3, inner_tcp_ack_num); - } else { - DR_STE_SET_TAG(eth_l4_misc, tag, seq_num, misc3, outer_tcp_seq_num); - DR_STE_SET_TAG(eth_l4_misc, tag, ack_num, misc3, outer_tcp_ack_num); - } - - return 0; -} - -static void -dr_ste_v0_build_eth_l4_misc_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_eth_l4_misc_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL4_MISC, sb->rx, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_eth_l4_misc_tag; -} - -static int -dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - - DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, - outer_vxlan_gpe_flags, misc3, - outer_vxlan_gpe_flags); - DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, - outer_vxlan_gpe_next_protocol, misc3, - outer_vxlan_gpe_next_protocol); - DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, - outer_vxlan_gpe_vni, misc3, - outer_vxlan_gpe_vni); - - return 0; -} - -static void -dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_tag(mask, sb, sb->bit_mask); - sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_TNL_HEADER; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_tag; -} - -static int -dr_ste_v0_build_flex_parser_tnl_geneve_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, - geneve_protocol_type, misc, geneve_protocol_type); - DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, - geneve_oam, misc, geneve_oam); - DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, - geneve_opt_len, misc, geneve_opt_len); - DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, - geneve_vni, misc, geneve_vni); - - return 0; -} - -static void -dr_ste_v0_build_flex_parser_tnl_geneve_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_flex_parser_tnl_geneve_tag(mask, sb, sb->bit_mask); - sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_TNL_HEADER; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tnl_geneve_tag; -} - -static int -dr_ste_v0_build_register_0_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - - DR_STE_SET_TAG(register_0, tag, register_0_h, misc2, metadata_reg_c_0); - DR_STE_SET_TAG(register_0, tag, register_0_l, misc2, metadata_reg_c_1); - DR_STE_SET_TAG(register_0, tag, register_1_h, misc2, metadata_reg_c_2); - DR_STE_SET_TAG(register_0, tag, register_1_l, misc2, metadata_reg_c_3); - - return 0; -} - -static void -dr_ste_v0_build_register_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_register_0_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_STEERING_REGISTERS_0; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_register_0_tag; -} - -static int -dr_ste_v0_build_register_1_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - - DR_STE_SET_TAG(register_1, tag, register_2_h, misc2, metadata_reg_c_4); - DR_STE_SET_TAG(register_1, tag, register_2_l, misc2, metadata_reg_c_5); - DR_STE_SET_TAG(register_1, tag, register_3_h, misc2, metadata_reg_c_6); - DR_STE_SET_TAG(register_1, tag, register_3_l, misc2, metadata_reg_c_7); - - return 0; -} - -static void -dr_ste_v0_build_register_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_register_1_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_STEERING_REGISTERS_1; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_register_1_tag; -} - -static void -dr_ste_v0_build_src_gvmi_qpn_bit_mask(struct mlx5dr_match_param *value, - u8 *bit_mask) -{ - struct mlx5dr_match_misc *misc_mask = &value->misc; - - DR_STE_SET_ONES(src_gvmi_qp, bit_mask, source_gvmi, misc_mask, source_port); - DR_STE_SET_ONES(src_gvmi_qp, bit_mask, source_qp, misc_mask, source_sqn); - misc_mask->source_eswitch_owner_vhca_id = 0; -} - -static int -dr_ste_v0_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc *misc = &value->misc; - int id = misc->source_eswitch_owner_vhca_id; - struct mlx5dr_cmd_vport_cap *vport_cap; - struct mlx5dr_domain *dmn = sb->dmn; - struct mlx5dr_domain *vport_dmn; - u8 *bit_mask = sb->bit_mask; - struct mlx5dr_domain *peer; - bool source_gvmi_set; - - DR_STE_SET_TAG(src_gvmi_qp, tag, source_qp, misc, source_sqn); - - if (sb->vhca_id_valid) { - peer = xa_load(&dmn->peer_dmn_xa, id); - /* Find port GVMI based on the eswitch_owner_vhca_id */ - if (id == dmn->info.caps.gvmi) - vport_dmn = dmn; - else if (peer && (id == peer->info.caps.gvmi)) - vport_dmn = peer; - else - return -EINVAL; - - misc->source_eswitch_owner_vhca_id = 0; - } else { - vport_dmn = dmn; - } - - source_gvmi_set = MLX5_GET(ste_src_gvmi_qp, bit_mask, source_gvmi); - if (source_gvmi_set) { - vport_cap = mlx5dr_domain_get_vport_cap(vport_dmn, - misc->source_port); - if (!vport_cap) { - mlx5dr_err(dmn, "Vport 0x%x is disabled or invalid\n", - misc->source_port); - return -EINVAL; - } - - if (vport_cap->vport_gvmi) - MLX5_SET(ste_src_gvmi_qp, tag, source_gvmi, vport_cap->vport_gvmi); - - misc->source_port = 0; - } - - return 0; -} - -static void -dr_ste_v0_build_src_gvmi_qpn_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_src_gvmi_qpn_bit_mask(mask, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_SRC_GVMI_AND_QP; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_src_gvmi_qpn_tag; -} - -static void dr_ste_v0_set_flex_parser(u32 *misc4_field_id, - u32 *misc4_field_value, - bool *parser_is_used, - u8 *tag) -{ - u32 id = *misc4_field_id; - u8 *parser_ptr; - - if (id >= DR_NUM_OF_FLEX_PARSERS || parser_is_used[id]) - return; - - parser_is_used[id] = true; - parser_ptr = dr_ste_calc_flex_parser_offset(tag, id); - - *(__be32 *)parser_ptr = cpu_to_be32(*misc4_field_value); - *misc4_field_id = 0; - *misc4_field_value = 0; -} - -static int dr_ste_v0_build_flex_parser_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc4 *misc_4_mask = &value->misc4; - bool parser_is_used[DR_NUM_OF_FLEX_PARSERS] = {}; - - dr_ste_v0_set_flex_parser(&misc_4_mask->prog_sample_field_id_0, - &misc_4_mask->prog_sample_field_value_0, - parser_is_used, tag); - - dr_ste_v0_set_flex_parser(&misc_4_mask->prog_sample_field_id_1, - &misc_4_mask->prog_sample_field_value_1, - parser_is_used, tag); - - dr_ste_v0_set_flex_parser(&misc_4_mask->prog_sample_field_id_2, - &misc_4_mask->prog_sample_field_value_2, - parser_is_used, tag); - - dr_ste_v0_set_flex_parser(&misc_4_mask->prog_sample_field_id_3, - &misc_4_mask->prog_sample_field_value_3, - parser_is_used, tag); - - return 0; -} - -static void dr_ste_v0_build_flex_parser_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_0; - dr_ste_v0_build_flex_parser_tag(mask, sb, sb->bit_mask); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tag; -} - -static void dr_ste_v0_build_flex_parser_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_1; - dr_ste_v0_build_flex_parser_tag(mask, sb, sb->bit_mask); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tag; -} - -static int -dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - u8 parser_id = sb->caps->flex_parser_id_geneve_tlv_option_0; - u8 *parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); - - MLX5_SET(ste_flex_parser_0, parser_ptr, flex_parser_3, - misc3->geneve_tlv_option_0_data); - misc3->geneve_tlv_option_0_data = 0; - - return 0; -} - -static void -dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_tag(mask, sb, sb->bit_mask); - - /* STEs with lookup type FLEX_PARSER_{0/1} includes - * flex parsers_{0-3}/{4-7} respectively. - */ - sb->lu_type = sb->caps->flex_parser_id_geneve_tlv_option_0 > 3 ? - DR_STE_V0_LU_TYPE_FLEX_PARSER_1 : - DR_STE_V0_LU_TYPE_FLEX_PARSER_0; - - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_tag; -} - -static int dr_ste_v0_build_flex_parser_tnl_gtpu_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - - DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, - gtpu_msg_flags, misc3, - gtpu_msg_flags); - DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, - gtpu_msg_type, misc3, - gtpu_msg_type); - DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, - gtpu_teid, misc3, - gtpu_teid); - - return 0; -} - -static void dr_ste_v0_build_flex_parser_tnl_gtpu_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_flex_parser_tnl_gtpu_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_TNL_HEADER; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tnl_gtpu_tag; -} - -static int -dr_ste_v0_build_tnl_gtpu_flex_parser_0_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_dw_0)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_0, sb->caps, &value->misc3); - if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_teid)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_teid, sb->caps, &value->misc3); - if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_dw_2)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_2, sb->caps, &value->misc3); - if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_first_ext_dw_0)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_first_ext_dw_0, sb->caps, &value->misc3); - return 0; -} - -static void -dr_ste_v0_build_tnl_gtpu_flex_parser_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_tnl_gtpu_flex_parser_0_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_0; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_tnl_gtpu_flex_parser_0_tag; -} - -static int -dr_ste_v0_build_tnl_gtpu_flex_parser_1_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_dw_0)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_0, sb->caps, &value->misc3); - if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_teid)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_teid, sb->caps, &value->misc3); - if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_dw_2)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_2, sb->caps, &value->misc3); - if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_first_ext_dw_0)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_first_ext_dw_0, sb->caps, &value->misc3); - return 0; -} - -static void -dr_ste_v0_build_tnl_gtpu_flex_parser_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v0_build_tnl_gtpu_flex_parser_1_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_1; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_tnl_gtpu_flex_parser_1_tag; -} - -static int dr_ste_v0_build_tnl_header_0_1_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc5 *misc5 = &value->misc5; - - DR_STE_SET_TAG(tunnel_header, tag, tunnel_header_0, misc5, tunnel_header_0); - DR_STE_SET_TAG(tunnel_header, tag, tunnel_header_1, misc5, tunnel_header_1); - - return 0; -} - -static void dr_ste_v0_build_tnl_header_0_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - sb->lu_type = DR_STE_V0_LU_TYPE_TUNNEL_HEADER; - dr_ste_v0_build_tnl_header_0_1_tag(mask, sb, sb->bit_mask); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v0_build_tnl_header_0_1_tag; -} - -static struct mlx5dr_ste_ctx ste_ctx_v0 = { - /* Builders */ - .build_eth_l2_src_dst_init = &dr_ste_v0_build_eth_l2_src_dst_init, - .build_eth_l3_ipv6_src_init = &dr_ste_v0_build_eth_l3_ipv6_src_init, - .build_eth_l3_ipv6_dst_init = &dr_ste_v0_build_eth_l3_ipv6_dst_init, - .build_eth_l3_ipv4_5_tuple_init = &dr_ste_v0_build_eth_l3_ipv4_5_tuple_init, - .build_eth_l2_src_init = &dr_ste_v0_build_eth_l2_src_init, - .build_eth_l2_dst_init = &dr_ste_v0_build_eth_l2_dst_init, - .build_eth_l2_tnl_init = &dr_ste_v0_build_eth_l2_tnl_init, - .build_eth_l3_ipv4_misc_init = &dr_ste_v0_build_eth_l3_ipv4_misc_init, - .build_eth_ipv6_l3_l4_init = &dr_ste_v0_build_eth_ipv6_l3_l4_init, - .build_mpls_init = &dr_ste_v0_build_mpls_init, - .build_tnl_gre_init = &dr_ste_v0_build_tnl_gre_init, - .build_tnl_mpls_init = &dr_ste_v0_build_tnl_mpls_init, - .build_tnl_mpls_over_udp_init = &dr_ste_v0_build_tnl_mpls_over_udp_init, - .build_tnl_mpls_over_gre_init = &dr_ste_v0_build_tnl_mpls_over_gre_init, - .build_icmp_init = &dr_ste_v0_build_icmp_init, - .build_general_purpose_init = &dr_ste_v0_build_general_purpose_init, - .build_eth_l4_misc_init = &dr_ste_v0_build_eth_l4_misc_init, - .build_tnl_vxlan_gpe_init = &dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_init, - .build_tnl_geneve_init = &dr_ste_v0_build_flex_parser_tnl_geneve_init, - .build_tnl_geneve_tlv_opt_init = &dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_init, - .build_register_0_init = &dr_ste_v0_build_register_0_init, - .build_register_1_init = &dr_ste_v0_build_register_1_init, - .build_src_gvmi_qpn_init = &dr_ste_v0_build_src_gvmi_qpn_init, - .build_flex_parser_0_init = &dr_ste_v0_build_flex_parser_0_init, - .build_flex_parser_1_init = &dr_ste_v0_build_flex_parser_1_init, - .build_tnl_gtpu_init = &dr_ste_v0_build_flex_parser_tnl_gtpu_init, - .build_tnl_header_0_1_init = &dr_ste_v0_build_tnl_header_0_1_init, - .build_tnl_gtpu_flex_parser_0_init = &dr_ste_v0_build_tnl_gtpu_flex_parser_0_init, - .build_tnl_gtpu_flex_parser_1_init = &dr_ste_v0_build_tnl_gtpu_flex_parser_1_init, - - /* Getters and Setters */ - .ste_init = &dr_ste_v0_init, - .set_next_lu_type = &dr_ste_v0_set_next_lu_type, - .get_next_lu_type = &dr_ste_v0_get_next_lu_type, - .set_miss_addr = &dr_ste_v0_set_miss_addr, - .get_miss_addr = &dr_ste_v0_get_miss_addr, - .set_hit_addr = &dr_ste_v0_set_hit_addr, - .set_byte_mask = &dr_ste_v0_set_byte_mask, - .get_byte_mask = &dr_ste_v0_get_byte_mask, - - /* Actions */ - .actions_caps = DR_STE_CTX_ACTION_CAP_NONE, - .set_actions_rx = &dr_ste_v0_set_actions_rx, - .set_actions_tx = &dr_ste_v0_set_actions_tx, - .modify_field_arr_sz = ARRAY_SIZE(dr_ste_v0_action_modify_field_arr), - .modify_field_arr = dr_ste_v0_action_modify_field_arr, - .set_action_set = &dr_ste_v0_set_action_set, - .set_action_add = &dr_ste_v0_set_action_add, - .set_action_copy = &dr_ste_v0_set_action_copy, - .set_action_decap_l3_list = &dr_ste_v0_set_action_decap_l3_list, -}; - -struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v0(void) -{ - return &ste_ctx_v0; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c deleted file mode 100644 index 1d49704b95427e..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c +++ /dev/null @@ -1,2341 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. */ - -#include -#include "mlx5_ifc_dr_ste_v1.h" -#include "dr_ste_v1.h" - -#define DR_STE_CALC_DFNR_TYPE(lookup_type, inner) \ - ((inner) ? DR_STE_V1_LU_TYPE_##lookup_type##_I : \ - DR_STE_V1_LU_TYPE_##lookup_type##_O) - -enum dr_ste_v1_entry_format { - DR_STE_V1_TYPE_BWC_BYTE = 0x0, - DR_STE_V1_TYPE_BWC_DW = 0x1, - DR_STE_V1_TYPE_MATCH = 0x2, - DR_STE_V1_TYPE_MATCH_RANGES = 0x7, -}; - -/* Lookup type is built from 2B: [ Definer mode 1B ][ Definer index 1B ] */ -enum { - DR_STE_V1_LU_TYPE_NOP = 0x0000, - DR_STE_V1_LU_TYPE_ETHL2_TNL = 0x0002, - DR_STE_V1_LU_TYPE_IBL3_EXT = 0x0102, - DR_STE_V1_LU_TYPE_ETHL2_O = 0x0003, - DR_STE_V1_LU_TYPE_IBL4 = 0x0103, - DR_STE_V1_LU_TYPE_ETHL2_I = 0x0004, - DR_STE_V1_LU_TYPE_SRC_QP_GVMI = 0x0104, - DR_STE_V1_LU_TYPE_ETHL2_SRC_O = 0x0005, - DR_STE_V1_LU_TYPE_ETHL2_HEADERS_O = 0x0105, - DR_STE_V1_LU_TYPE_ETHL2_SRC_I = 0x0006, - DR_STE_V1_LU_TYPE_ETHL2_HEADERS_I = 0x0106, - DR_STE_V1_LU_TYPE_ETHL3_IPV4_5_TUPLE_O = 0x0007, - DR_STE_V1_LU_TYPE_IPV6_DES_O = 0x0107, - DR_STE_V1_LU_TYPE_ETHL3_IPV4_5_TUPLE_I = 0x0008, - DR_STE_V1_LU_TYPE_IPV6_DES_I = 0x0108, - DR_STE_V1_LU_TYPE_ETHL4_O = 0x0009, - DR_STE_V1_LU_TYPE_IPV6_SRC_O = 0x0109, - DR_STE_V1_LU_TYPE_ETHL4_I = 0x000a, - DR_STE_V1_LU_TYPE_IPV6_SRC_I = 0x010a, - DR_STE_V1_LU_TYPE_ETHL2_SRC_DST_O = 0x000b, - DR_STE_V1_LU_TYPE_MPLS_O = 0x010b, - DR_STE_V1_LU_TYPE_ETHL2_SRC_DST_I = 0x000c, - DR_STE_V1_LU_TYPE_MPLS_I = 0x010c, - DR_STE_V1_LU_TYPE_ETHL3_IPV4_MISC_O = 0x000d, - DR_STE_V1_LU_TYPE_GRE = 0x010d, - DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER = 0x000e, - DR_STE_V1_LU_TYPE_GENERAL_PURPOSE = 0x010e, - DR_STE_V1_LU_TYPE_ETHL3_IPV4_MISC_I = 0x000f, - DR_STE_V1_LU_TYPE_STEERING_REGISTERS_0 = 0x010f, - DR_STE_V1_LU_TYPE_STEERING_REGISTERS_1 = 0x0110, - DR_STE_V1_LU_TYPE_FLEX_PARSER_OK = 0x0011, - DR_STE_V1_LU_TYPE_FLEX_PARSER_0 = 0x0111, - DR_STE_V1_LU_TYPE_FLEX_PARSER_1 = 0x0112, - DR_STE_V1_LU_TYPE_ETHL4_MISC_O = 0x0113, - DR_STE_V1_LU_TYPE_ETHL4_MISC_I = 0x0114, - DR_STE_V1_LU_TYPE_INVALID = 0x00ff, - DR_STE_V1_LU_TYPE_DONT_CARE = MLX5DR_STE_LU_TYPE_DONT_CARE, -}; - -enum dr_ste_v1_header_anchors { - DR_STE_HEADER_ANCHOR_START_OUTER = 0x00, - DR_STE_HEADER_ANCHOR_1ST_VLAN = 0x02, - DR_STE_HEADER_ANCHOR_IPV6_IPV4 = 0x07, - DR_STE_HEADER_ANCHOR_INNER_MAC = 0x13, - DR_STE_HEADER_ANCHOR_INNER_IPV6_IPV4 = 0x19, -}; - -enum dr_ste_v1_action_size { - DR_STE_ACTION_SINGLE_SZ = 4, - DR_STE_ACTION_DOUBLE_SZ = 8, - DR_STE_ACTION_TRIPLE_SZ = 12, -}; - -enum dr_ste_v1_action_insert_ptr_attr { - DR_STE_V1_ACTION_INSERT_PTR_ATTR_NONE = 0, /* Regular push header (e.g. push vlan) */ - DR_STE_V1_ACTION_INSERT_PTR_ATTR_ENCAP = 1, /* Encapsulation / Tunneling */ - DR_STE_V1_ACTION_INSERT_PTR_ATTR_ESP = 2, /* IPsec */ -}; - -enum dr_ste_v1_action_id { - DR_STE_V1_ACTION_ID_NOP = 0x00, - DR_STE_V1_ACTION_ID_COPY = 0x05, - DR_STE_V1_ACTION_ID_SET = 0x06, - DR_STE_V1_ACTION_ID_ADD = 0x07, - DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE = 0x08, - DR_STE_V1_ACTION_ID_REMOVE_HEADER_TO_HEADER = 0x09, - DR_STE_V1_ACTION_ID_INSERT_INLINE = 0x0a, - DR_STE_V1_ACTION_ID_INSERT_POINTER = 0x0b, - DR_STE_V1_ACTION_ID_FLOW_TAG = 0x0c, - DR_STE_V1_ACTION_ID_QUEUE_ID_SEL = 0x0d, - DR_STE_V1_ACTION_ID_ACCELERATED_LIST = 0x0e, - DR_STE_V1_ACTION_ID_MODIFY_LIST = 0x0f, - DR_STE_V1_ACTION_ID_ASO = 0x12, - DR_STE_V1_ACTION_ID_TRAILER = 0x13, - DR_STE_V1_ACTION_ID_COUNTER_ID = 0x14, - DR_STE_V1_ACTION_ID_MAX = 0x21, - /* use for special cases */ - DR_STE_V1_ACTION_ID_SPECIAL_ENCAP_L3 = 0x22, -}; - -enum { - DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_0 = 0x00, - DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_1 = 0x01, - DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_2 = 0x02, - DR_STE_V1_ACTION_MDFY_FLD_SRC_L2_OUT_0 = 0x08, - DR_STE_V1_ACTION_MDFY_FLD_SRC_L2_OUT_1 = 0x09, - DR_STE_V1_ACTION_MDFY_FLD_L3_OUT_0 = 0x0e, - DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0 = 0x18, - DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_1 = 0x19, - DR_STE_V1_ACTION_MDFY_FLD_IPV4_OUT_0 = 0x40, - DR_STE_V1_ACTION_MDFY_FLD_IPV4_OUT_1 = 0x41, - DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_0 = 0x44, - DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_1 = 0x45, - DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_2 = 0x46, - DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_3 = 0x47, - DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_0 = 0x4c, - DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_1 = 0x4d, - DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_2 = 0x4e, - DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_3 = 0x4f, - DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_0 = 0x5e, - DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_1 = 0x5f, - DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_0 = 0x6f, - DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_1 = 0x70, - DR_STE_V1_ACTION_MDFY_FLD_METADATA_2_CQE = 0x7b, - DR_STE_V1_ACTION_MDFY_FLD_GNRL_PURPOSE = 0x7c, - DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2_0 = 0x8c, - DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2_1 = 0x8d, - DR_STE_V1_ACTION_MDFY_FLD_REGISTER_1_0 = 0x8e, - DR_STE_V1_ACTION_MDFY_FLD_REGISTER_1_1 = 0x8f, - DR_STE_V1_ACTION_MDFY_FLD_REGISTER_0_0 = 0x90, - DR_STE_V1_ACTION_MDFY_FLD_REGISTER_0_1 = 0x91, -}; - -enum dr_ste_v1_aso_ctx_type { - DR_STE_V1_ASO_CTX_TYPE_POLICERS = 0x2, -}; - -static const struct mlx5dr_ste_action_modify_field dr_ste_v1_action_modify_field_arr[] = { - [MLX5_ACTION_IN_FIELD_OUT_SMAC_47_16] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_SRC_L2_OUT_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_SMAC_15_0] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_SRC_L2_OUT_1, .start = 16, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_ETHERTYPE] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_1, .start = 0, .end = 15, - }, - [MLX5_ACTION_IN_FIELD_OUT_DMAC_47_16] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_DMAC_15_0] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_1, .start = 16, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_IP_DSCP] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L3_OUT_0, .start = 18, .end = 23, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_FLAGS] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_1, .start = 16, .end = 24, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0, .start = 16, .end = 31, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0, .start = 0, .end = 15, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_IP_TTL] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L3_OUT_0, .start = 8, .end = 15, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L3_OUT_0, .start = 8, .end = 15, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0, .start = 16, .end = 31, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, - }, - [MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0, .start = 0, .end = 15, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_0, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_1, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_2, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_3, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_0, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_1, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_2, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_3, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV4] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV4_OUT_0, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV4] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV4_OUT_1, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_A] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_GNRL_PURPOSE, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_B] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_METADATA_2_CQE, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_0] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_0_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_1] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_0_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_2] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_1_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_3] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_1_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_4] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_5] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_FIRST_VID] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_2, .start = 0, .end = 15, - }, - [MLX5_ACTION_IN_FIELD_OUT_EMD_31_0] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_EMD_47_32] = { - .hw_field = DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_0, .start = 0, .end = 15, - }, -}; - -static void dr_ste_v1_set_entry_type(u8 *hw_ste_p, u8 entry_type) -{ - MLX5_SET(ste_match_bwc_v1, hw_ste_p, entry_format, entry_type); -} - -bool dr_ste_v1_is_miss_addr_set(u8 *hw_ste_p) -{ - u8 entry_type = MLX5_GET(ste_match_bwc_v1, hw_ste_p, entry_format); - - /* unlike MATCH STE, for MATCH_RANGES STE both hit and miss addresses - * are part of the action, so they both set as part of STE init - */ - return entry_type == DR_STE_V1_TYPE_MATCH_RANGES; -} - -void dr_ste_v1_set_miss_addr(u8 *hw_ste_p, u64 miss_addr) -{ - u64 index = miss_addr >> 6; - - MLX5_SET(ste_match_bwc_v1, hw_ste_p, miss_address_39_32, index >> 26); - MLX5_SET(ste_match_bwc_v1, hw_ste_p, miss_address_31_6, index); -} - -u64 dr_ste_v1_get_miss_addr(u8 *hw_ste_p) -{ - u64 index = - ((u64)MLX5_GET(ste_match_bwc_v1, hw_ste_p, miss_address_31_6) | - ((u64)MLX5_GET(ste_match_bwc_v1, hw_ste_p, miss_address_39_32)) << 26); - - return index << 6; -} - -void dr_ste_v1_set_byte_mask(u8 *hw_ste_p, u16 byte_mask) -{ - MLX5_SET(ste_match_bwc_v1, hw_ste_p, byte_mask, byte_mask); -} - -u16 dr_ste_v1_get_byte_mask(u8 *hw_ste_p) -{ - return MLX5_GET(ste_match_bwc_v1, hw_ste_p, byte_mask); -} - -static void dr_ste_v1_set_lu_type(u8 *hw_ste_p, u16 lu_type) -{ - MLX5_SET(ste_match_bwc_v1, hw_ste_p, entry_format, lu_type >> 8); - MLX5_SET(ste_match_bwc_v1, hw_ste_p, match_definer_ctx_idx, lu_type & 0xFF); -} - -void dr_ste_v1_set_next_lu_type(u8 *hw_ste_p, u16 lu_type) -{ - MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_entry_format, lu_type >> 8); - MLX5_SET(ste_match_bwc_v1, hw_ste_p, hash_definer_ctx_idx, lu_type & 0xFF); -} - -u16 dr_ste_v1_get_next_lu_type(u8 *hw_ste_p) -{ - u8 mode = MLX5_GET(ste_match_bwc_v1, hw_ste_p, next_entry_format); - u8 index = MLX5_GET(ste_match_bwc_v1, hw_ste_p, hash_definer_ctx_idx); - - return (mode << 8 | index); -} - -static void dr_ste_v1_set_hit_gvmi(u8 *hw_ste_p, u16 gvmi) -{ - MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_table_base_63_48, gvmi); -} - -void dr_ste_v1_set_hit_addr(u8 *hw_ste_p, u64 icm_addr, u32 ht_size) -{ - u64 index = (icm_addr >> 5) | ht_size; - - MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_table_base_39_32_size, index >> 27); - MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_table_base_31_5_size, index); -} - -void dr_ste_v1_init(u8 *hw_ste_p, u16 lu_type, bool is_rx, u16 gvmi) -{ - dr_ste_v1_set_lu_type(hw_ste_p, lu_type); - dr_ste_v1_set_next_lu_type(hw_ste_p, MLX5DR_STE_LU_TYPE_DONT_CARE); - - MLX5_SET(ste_match_bwc_v1, hw_ste_p, gvmi, gvmi); - MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_table_base_63_48, gvmi); - MLX5_SET(ste_match_bwc_v1, hw_ste_p, miss_address_63_48, gvmi); -} - -void dr_ste_v1_prepare_for_postsend(u8 *hw_ste_p, u32 ste_size) -{ - u8 *tag = hw_ste_p + DR_STE_SIZE_CTRL; - u8 *mask = tag + DR_STE_SIZE_TAG; - u8 tmp_tag[DR_STE_SIZE_TAG] = {}; - - if (ste_size == DR_STE_SIZE_CTRL) - return; - - WARN_ON(ste_size != DR_STE_SIZE); - - /* Backup tag */ - memcpy(tmp_tag, tag, DR_STE_SIZE_TAG); - - /* Swap mask and tag both are the same size */ - memcpy(tag, mask, DR_STE_SIZE_MASK); - memcpy(mask, tmp_tag, DR_STE_SIZE_TAG); -} - -static void dr_ste_v1_set_rx_flow_tag(u8 *s_action, u32 flow_tag) -{ - MLX5_SET(ste_single_action_flow_tag_v1, s_action, action_id, - DR_STE_V1_ACTION_ID_FLOW_TAG); - MLX5_SET(ste_single_action_flow_tag_v1, s_action, flow_tag, flow_tag); -} - -static void dr_ste_v1_set_counter_id(u8 *hw_ste_p, u32 ctr_id) -{ - MLX5_SET(ste_match_bwc_v1, hw_ste_p, counter_id, ctr_id); -} - -static void dr_ste_v1_set_reparse(u8 *hw_ste_p) -{ - MLX5_SET(ste_match_bwc_v1, hw_ste_p, reparse, 1); -} - -static void dr_ste_v1_set_encap(u8 *hw_ste_p, u8 *d_action, - u32 reformat_id, int size) -{ - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, action_id, - DR_STE_V1_ACTION_ID_INSERT_POINTER); - /* The hardware expects here size in words (2 byte) */ - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, size, size / 2); - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, pointer, reformat_id); - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, attributes, - DR_STE_V1_ACTION_INSERT_PTR_ATTR_ENCAP); - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_insert_hdr(u8 *hw_ste_p, u8 *d_action, - u32 reformat_id, - u8 anchor, u8 offset, - int size) -{ - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, - action_id, DR_STE_V1_ACTION_ID_INSERT_POINTER); - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, start_anchor, anchor); - - /* The hardware expects here size and offset in words (2 byte) */ - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, size, size / 2); - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, start_offset, offset / 2); - - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, pointer, reformat_id); - MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, attributes, - DR_STE_V1_ACTION_INSERT_PTR_ATTR_NONE); - - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_remove_hdr(u8 *hw_ste_p, u8 *s_action, - u8 anchor, u8 offset, - int size) -{ - MLX5_SET(ste_single_action_remove_header_size_v1, s_action, - action_id, DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE); - MLX5_SET(ste_single_action_remove_header_size_v1, s_action, start_anchor, anchor); - - /* The hardware expects here size and offset in words (2 byte) */ - MLX5_SET(ste_single_action_remove_header_size_v1, s_action, remove_size, size / 2); - MLX5_SET(ste_single_action_remove_header_size_v1, s_action, start_offset, offset / 2); - - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_push_vlan(u8 *hw_ste_p, u8 *d_action, - u32 vlan_hdr) -{ - MLX5_SET(ste_double_action_insert_with_inline_v1, d_action, - action_id, DR_STE_V1_ACTION_ID_INSERT_INLINE); - /* The hardware expects offset to vlan header in words (2 byte) */ - MLX5_SET(ste_double_action_insert_with_inline_v1, d_action, - start_offset, HDR_LEN_L2_MACS >> 1); - MLX5_SET(ste_double_action_insert_with_inline_v1, d_action, - inline_data, vlan_hdr); - - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_pop_vlan(u8 *hw_ste_p, u8 *s_action, u8 vlans_num) -{ - MLX5_SET(ste_single_action_remove_header_size_v1, s_action, - action_id, DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE); - MLX5_SET(ste_single_action_remove_header_size_v1, s_action, - start_anchor, DR_STE_HEADER_ANCHOR_1ST_VLAN); - /* The hardware expects here size in words (2 byte) */ - MLX5_SET(ste_single_action_remove_header_size_v1, s_action, - remove_size, (HDR_LEN_L2_VLAN >> 1) * vlans_num); - - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_encap_l3(u8 *hw_ste_p, - u8 *frst_s_action, - u8 *scnd_d_action, - u32 reformat_id, - int size) -{ - /* Remove L2 headers */ - MLX5_SET(ste_single_action_remove_header_v1, frst_s_action, action_id, - DR_STE_V1_ACTION_ID_REMOVE_HEADER_TO_HEADER); - MLX5_SET(ste_single_action_remove_header_v1, frst_s_action, end_anchor, - DR_STE_HEADER_ANCHOR_IPV6_IPV4); - - /* Encapsulate with given reformat ID */ - MLX5_SET(ste_double_action_insert_with_ptr_v1, scnd_d_action, action_id, - DR_STE_V1_ACTION_ID_INSERT_POINTER); - /* The hardware expects here size in words (2 byte) */ - MLX5_SET(ste_double_action_insert_with_ptr_v1, scnd_d_action, size, size / 2); - MLX5_SET(ste_double_action_insert_with_ptr_v1, scnd_d_action, pointer, reformat_id); - MLX5_SET(ste_double_action_insert_with_ptr_v1, scnd_d_action, attributes, - DR_STE_V1_ACTION_INSERT_PTR_ATTR_ENCAP); - - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_rx_decap(u8 *hw_ste_p, u8 *s_action) -{ - MLX5_SET(ste_single_action_remove_header_v1, s_action, action_id, - DR_STE_V1_ACTION_ID_REMOVE_HEADER_TO_HEADER); - MLX5_SET(ste_single_action_remove_header_v1, s_action, decap, 1); - MLX5_SET(ste_single_action_remove_header_v1, s_action, vni_to_cqe, 1); - MLX5_SET(ste_single_action_remove_header_v1, s_action, end_anchor, - DR_STE_HEADER_ANCHOR_INNER_MAC); - - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_accelerated_rewrite_actions(u8 *hw_ste_p, - u8 *d_action, - u16 num_of_actions, - u32 rewrite_pattern, - u32 rewrite_args, - u8 *action_data) -{ - if (action_data) { - memcpy(d_action, action_data, DR_MODIFY_ACTION_SIZE); - } else { - MLX5_SET(ste_double_action_accelerated_modify_action_list_v1, d_action, - action_id, DR_STE_V1_ACTION_ID_ACCELERATED_LIST); - MLX5_SET(ste_double_action_accelerated_modify_action_list_v1, d_action, - modify_actions_pattern_pointer, rewrite_pattern); - MLX5_SET(ste_double_action_accelerated_modify_action_list_v1, d_action, - number_of_modify_actions, num_of_actions); - MLX5_SET(ste_double_action_accelerated_modify_action_list_v1, d_action, - modify_actions_argument_pointer, rewrite_args); - } - - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_basic_rewrite_actions(u8 *hw_ste_p, - u8 *s_action, - u16 num_of_actions, - u32 rewrite_index) -{ - MLX5_SET(ste_single_action_modify_list_v1, s_action, action_id, - DR_STE_V1_ACTION_ID_MODIFY_LIST); - MLX5_SET(ste_single_action_modify_list_v1, s_action, num_of_modify_actions, - num_of_actions); - MLX5_SET(ste_single_action_modify_list_v1, s_action, modify_actions_ptr, - rewrite_index); - - dr_ste_v1_set_reparse(hw_ste_p); -} - -static void dr_ste_v1_set_rewrite_actions(u8 *hw_ste_p, - u8 *action, - u16 num_of_actions, - u32 rewrite_pattern, - u32 rewrite_args, - u8 *action_data) -{ - if (rewrite_pattern != MLX5DR_INVALID_PATTERN_INDEX) - return dr_ste_v1_set_accelerated_rewrite_actions(hw_ste_p, - action, - num_of_actions, - rewrite_pattern, - rewrite_args, - action_data); - - /* fall back to the code that doesn't support accelerated modify header */ - return dr_ste_v1_set_basic_rewrite_actions(hw_ste_p, - action, - num_of_actions, - rewrite_args); -} - -static void dr_ste_v1_set_aso_flow_meter(u8 *d_action, - u32 object_id, - u32 offset, - u8 dest_reg_id, - u8 init_color) -{ - MLX5_SET(ste_double_action_aso_v1, d_action, action_id, - DR_STE_V1_ACTION_ID_ASO); - MLX5_SET(ste_double_action_aso_v1, d_action, aso_context_number, - object_id + (offset / MLX5DR_ASO_FLOW_METER_NUM_PER_OBJ)); - /* Convert reg_c index to HW 64bit index */ - MLX5_SET(ste_double_action_aso_v1, d_action, dest_reg_id, - (dest_reg_id - 1) / 2); - MLX5_SET(ste_double_action_aso_v1, d_action, aso_context_type, - DR_STE_V1_ASO_CTX_TYPE_POLICERS); - MLX5_SET(ste_double_action_aso_v1, d_action, flow_meter.line_id, - offset % MLX5DR_ASO_FLOW_METER_NUM_PER_OBJ); - MLX5_SET(ste_double_action_aso_v1, d_action, flow_meter.initial_color, - init_color); -} - -static void dr_ste_v1_set_match_range_pkt_len(u8 *hw_ste_p, u32 definer_id, - u32 min, u32 max) -{ - MLX5_SET(ste_match_ranges_v1, hw_ste_p, match_definer_ctx_idx, definer_id); - - /* When the STE will be sent, its mask and tags will be swapped in - * dr_ste_v1_prepare_for_postsend(). This, however, is match range STE - * which doesn't have mask, and shouldn't have mask/tag swapped. - * We're using the common utilities functions to send this STE, so need - * to allow for this swapping - place the values in the corresponding - * locations to allow flipping them when writing to ICM. - * - * min/max_value_2 corresponds to match_dw_0 in its definer. - * To allow mask/tag swapping, writing the min/max_2 to min/max_0. - * - * Pkt len is 2 bytes that are stored in the higher section of the DW. - */ - MLX5_SET(ste_match_ranges_v1, hw_ste_p, min_value_0, min << 16); - MLX5_SET(ste_match_ranges_v1, hw_ste_p, max_value_0, max << 16); -} - -static void dr_ste_v1_arr_init_next_match(u8 **last_ste, - u32 *added_stes, - u16 gvmi) -{ - u8 *action; - - (*added_stes)++; - *last_ste += DR_STE_SIZE; - dr_ste_v1_init(*last_ste, MLX5DR_STE_LU_TYPE_DONT_CARE, 0, gvmi); - dr_ste_v1_set_entry_type(*last_ste, DR_STE_V1_TYPE_MATCH); - - action = MLX5_ADDR_OF(ste_mask_and_match_v1, *last_ste, action); - memset(action, 0, MLX5_FLD_SZ_BYTES(ste_mask_and_match_v1, action)); -} - -static void dr_ste_v1_arr_init_next_match_range(u8 **last_ste, - u32 *added_stes, - u16 gvmi) -{ - dr_ste_v1_arr_init_next_match(last_ste, added_stes, gvmi); - dr_ste_v1_set_entry_type(*last_ste, DR_STE_V1_TYPE_MATCH_RANGES); -} - -void dr_ste_v1_set_actions_tx(struct mlx5dr_domain *dmn, - u8 *action_type_set, - u32 actions_caps, - u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes) -{ - u8 *action = MLX5_ADDR_OF(ste_match_bwc_v1, last_ste, action); - u8 action_sz = DR_STE_ACTION_DOUBLE_SZ; - bool allow_modify_hdr = true; - bool allow_encap = true; - - if (action_type_set[DR_ACTION_TYP_POP_VLAN]) { - if (action_sz < DR_STE_ACTION_SINGLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, - attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, - last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_pop_vlan(last_ste, action, attr->vlans.count); - action_sz -= DR_STE_ACTION_SINGLE_SZ; - action += DR_STE_ACTION_SINGLE_SZ; - - /* Check if vlan_pop and modify_hdr on same STE is supported */ - if (!(actions_caps & DR_STE_CTX_ACTION_CAP_POP_MDFY)) - allow_modify_hdr = false; - } - - if (action_type_set[DR_ACTION_TYP_MODIFY_HDR]) { - if (!allow_modify_hdr || action_sz < DR_STE_ACTION_DOUBLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, - attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, - last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_rewrite_actions(last_ste, action, - attr->modify_actions, - attr->modify_pat_idx, - attr->modify_index, - attr->single_modify_action); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - allow_encap = false; - } - - if (action_type_set[DR_ACTION_TYP_PUSH_VLAN]) { - int i; - - for (i = 0; i < attr->vlans.count; i++) { - if (action_sz < DR_STE_ACTION_DOUBLE_SZ || !allow_encap) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - allow_encap = true; - } - dr_ste_v1_set_push_vlan(last_ste, action, - attr->vlans.headers[i]); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - } - } - - if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L2]) { - if (!allow_encap || action_sz < DR_STE_ACTION_DOUBLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - allow_encap = true; - } - dr_ste_v1_set_encap(last_ste, action, - attr->reformat.id, - attr->reformat.size); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - } else if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]) { - u8 *d_action; - - if (action_sz < DR_STE_ACTION_TRIPLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - d_action = action + DR_STE_ACTION_SINGLE_SZ; - - dr_ste_v1_set_encap_l3(last_ste, - action, d_action, - attr->reformat.id, - attr->reformat.size); - action_sz -= DR_STE_ACTION_TRIPLE_SZ; - action += DR_STE_ACTION_TRIPLE_SZ; - } else if (action_type_set[DR_ACTION_TYP_INSERT_HDR]) { - if (!allow_encap || action_sz < DR_STE_ACTION_DOUBLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_insert_hdr(last_ste, action, - attr->reformat.id, - attr->reformat.param_0, - attr->reformat.param_1, - attr->reformat.size); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - } else if (action_type_set[DR_ACTION_TYP_REMOVE_HDR]) { - if (action_sz < DR_STE_ACTION_SINGLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_remove_hdr(last_ste, action, - attr->reformat.param_0, - attr->reformat.param_1, - attr->reformat.size); - action_sz -= DR_STE_ACTION_SINGLE_SZ; - action += DR_STE_ACTION_SINGLE_SZ; - } - - if (action_type_set[DR_ACTION_TYP_ASO_FLOW_METER]) { - if (action_sz < DR_STE_ACTION_DOUBLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_aso_flow_meter(action, - attr->aso_flow_meter.obj_id, - attr->aso_flow_meter.offset, - attr->aso_flow_meter.dest_reg_id, - attr->aso_flow_meter.init_color); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - } - - if (action_type_set[DR_ACTION_TYP_RANGE]) { - /* match ranges requires a new STE of its own type */ - dr_ste_v1_arr_init_next_match_range(&last_ste, added_stes, attr->gvmi); - dr_ste_v1_set_miss_addr(last_ste, attr->range.miss_icm_addr); - - /* we do not support setting any action on the match ranges STE */ - action_sz = 0; - - dr_ste_v1_set_match_range_pkt_len(last_ste, - attr->range.definer_id, - attr->range.min, - attr->range.max); - } - - /* set counter ID on the last STE to adhere to DMFS behavior */ - if (action_type_set[DR_ACTION_TYP_CTR]) - dr_ste_v1_set_counter_id(last_ste, attr->ctr_id); - - dr_ste_v1_set_hit_gvmi(last_ste, attr->hit_gvmi); - dr_ste_v1_set_hit_addr(last_ste, attr->final_icm_addr, 1); -} - -void dr_ste_v1_set_actions_rx(struct mlx5dr_domain *dmn, - u8 *action_type_set, - u32 actions_caps, - u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes) -{ - u8 *action = MLX5_ADDR_OF(ste_match_bwc_v1, last_ste, action); - u8 action_sz = DR_STE_ACTION_DOUBLE_SZ; - bool allow_modify_hdr = true; - bool allow_ctr = true; - - if (action_type_set[DR_ACTION_TYP_TNL_L3_TO_L2]) { - dr_ste_v1_set_rewrite_actions(last_ste, action, - attr->decap_actions, - attr->decap_pat_idx, - attr->decap_index, - NULL); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - allow_modify_hdr = false; - allow_ctr = false; - } else if (action_type_set[DR_ACTION_TYP_TNL_L2_TO_L2]) { - dr_ste_v1_set_rx_decap(last_ste, action); - action_sz -= DR_STE_ACTION_SINGLE_SZ; - action += DR_STE_ACTION_SINGLE_SZ; - allow_modify_hdr = false; - allow_ctr = false; - } - - if (action_type_set[DR_ACTION_TYP_TAG]) { - if (action_sz < DR_STE_ACTION_SINGLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - allow_modify_hdr = true; - allow_ctr = true; - } - dr_ste_v1_set_rx_flow_tag(action, attr->flow_tag); - action_sz -= DR_STE_ACTION_SINGLE_SZ; - action += DR_STE_ACTION_SINGLE_SZ; - } - - if (action_type_set[DR_ACTION_TYP_POP_VLAN]) { - if (action_sz < DR_STE_ACTION_SINGLE_SZ || - !allow_modify_hdr) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - - dr_ste_v1_set_pop_vlan(last_ste, action, attr->vlans.count); - action_sz -= DR_STE_ACTION_SINGLE_SZ; - action += DR_STE_ACTION_SINGLE_SZ; - allow_ctr = false; - - /* Check if vlan_pop and modify_hdr on same STE is supported */ - if (!(actions_caps & DR_STE_CTX_ACTION_CAP_POP_MDFY)) - allow_modify_hdr = false; - } - - if (action_type_set[DR_ACTION_TYP_MODIFY_HDR]) { - /* Modify header and decapsulation must use different STEs */ - if (!allow_modify_hdr || action_sz < DR_STE_ACTION_DOUBLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - allow_modify_hdr = true; - allow_ctr = true; - } - dr_ste_v1_set_rewrite_actions(last_ste, action, - attr->modify_actions, - attr->modify_pat_idx, - attr->modify_index, - attr->single_modify_action); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - } - - if (action_type_set[DR_ACTION_TYP_PUSH_VLAN]) { - int i; - - for (i = 0; i < attr->vlans.count; i++) { - if (action_sz < DR_STE_ACTION_DOUBLE_SZ || - !allow_modify_hdr) { - dr_ste_v1_arr_init_next_match(&last_ste, - added_stes, - attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, - last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_push_vlan(last_ste, action, - attr->vlans.headers[i]); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - } - } - - if (action_type_set[DR_ACTION_TYP_CTR]) { - /* Counter action set after decap and before insert_hdr - * to exclude decaped / encaped header respectively. - */ - if (!allow_ctr) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - allow_modify_hdr = true; - } - dr_ste_v1_set_counter_id(last_ste, attr->ctr_id); - allow_ctr = false; - } - - if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L2]) { - if (action_sz < DR_STE_ACTION_DOUBLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_encap(last_ste, action, - attr->reformat.id, - attr->reformat.size); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - allow_modify_hdr = false; - } else if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]) { - u8 *d_action; - - if (action_sz < DR_STE_ACTION_TRIPLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - - d_action = action + DR_STE_ACTION_SINGLE_SZ; - - dr_ste_v1_set_encap_l3(last_ste, - action, d_action, - attr->reformat.id, - attr->reformat.size); - action_sz -= DR_STE_ACTION_TRIPLE_SZ; - allow_modify_hdr = false; - } else if (action_type_set[DR_ACTION_TYP_INSERT_HDR]) { - /* Modify header, decap, and encap must use different STEs */ - if (!allow_modify_hdr || action_sz < DR_STE_ACTION_DOUBLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_insert_hdr(last_ste, action, - attr->reformat.id, - attr->reformat.param_0, - attr->reformat.param_1, - attr->reformat.size); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - allow_modify_hdr = false; - } else if (action_type_set[DR_ACTION_TYP_REMOVE_HDR]) { - if (action_sz < DR_STE_ACTION_SINGLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - allow_modify_hdr = true; - allow_ctr = true; - } - dr_ste_v1_set_remove_hdr(last_ste, action, - attr->reformat.param_0, - attr->reformat.param_1, - attr->reformat.size); - action_sz -= DR_STE_ACTION_SINGLE_SZ; - action += DR_STE_ACTION_SINGLE_SZ; - } - - if (action_type_set[DR_ACTION_TYP_ASO_FLOW_METER]) { - if (action_sz < DR_STE_ACTION_DOUBLE_SZ) { - dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); - action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); - action_sz = DR_STE_ACTION_TRIPLE_SZ; - } - dr_ste_v1_set_aso_flow_meter(action, - attr->aso_flow_meter.obj_id, - attr->aso_flow_meter.offset, - attr->aso_flow_meter.dest_reg_id, - attr->aso_flow_meter.init_color); - action_sz -= DR_STE_ACTION_DOUBLE_SZ; - action += DR_STE_ACTION_DOUBLE_SZ; - } - - if (action_type_set[DR_ACTION_TYP_RANGE]) { - /* match ranges requires a new STE of its own type */ - dr_ste_v1_arr_init_next_match_range(&last_ste, added_stes, attr->gvmi); - dr_ste_v1_set_miss_addr(last_ste, attr->range.miss_icm_addr); - - /* we do not support setting any action on the match ranges STE */ - action_sz = 0; - - dr_ste_v1_set_match_range_pkt_len(last_ste, - attr->range.definer_id, - attr->range.min, - attr->range.max); - } - - dr_ste_v1_set_hit_gvmi(last_ste, attr->hit_gvmi); - dr_ste_v1_set_hit_addr(last_ste, attr->final_icm_addr, 1); -} - -void dr_ste_v1_set_action_set(u8 *d_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data) -{ - shifter += MLX5_MODIFY_HEADER_V1_QW_OFFSET; - MLX5_SET(ste_double_action_set_v1, d_action, action_id, DR_STE_V1_ACTION_ID_SET); - MLX5_SET(ste_double_action_set_v1, d_action, destination_dw_offset, hw_field); - MLX5_SET(ste_double_action_set_v1, d_action, destination_left_shifter, shifter); - MLX5_SET(ste_double_action_set_v1, d_action, destination_length, length); - MLX5_SET(ste_double_action_set_v1, d_action, inline_data, data); -} - -void dr_ste_v1_set_action_add(u8 *d_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data) -{ - shifter += MLX5_MODIFY_HEADER_V1_QW_OFFSET; - MLX5_SET(ste_double_action_add_v1, d_action, action_id, DR_STE_V1_ACTION_ID_ADD); - MLX5_SET(ste_double_action_add_v1, d_action, destination_dw_offset, hw_field); - MLX5_SET(ste_double_action_add_v1, d_action, destination_left_shifter, shifter); - MLX5_SET(ste_double_action_add_v1, d_action, destination_length, length); - MLX5_SET(ste_double_action_add_v1, d_action, add_value, data); -} - -void dr_ste_v1_set_action_copy(u8 *d_action, - u8 dst_hw_field, - u8 dst_shifter, - u8 dst_len, - u8 src_hw_field, - u8 src_shifter) -{ - dst_shifter += MLX5_MODIFY_HEADER_V1_QW_OFFSET; - src_shifter += MLX5_MODIFY_HEADER_V1_QW_OFFSET; - MLX5_SET(ste_double_action_copy_v1, d_action, action_id, DR_STE_V1_ACTION_ID_COPY); - MLX5_SET(ste_double_action_copy_v1, d_action, destination_dw_offset, dst_hw_field); - MLX5_SET(ste_double_action_copy_v1, d_action, destination_left_shifter, dst_shifter); - MLX5_SET(ste_double_action_copy_v1, d_action, destination_length, dst_len); - MLX5_SET(ste_double_action_copy_v1, d_action, source_dw_offset, src_hw_field); - MLX5_SET(ste_double_action_copy_v1, d_action, source_right_shifter, src_shifter); -} - -#define DR_STE_DECAP_L3_ACTION_NUM 8 -#define DR_STE_L2_HDR_MAX_SZ 20 - -int dr_ste_v1_set_action_decap_l3_list(void *data, - u32 data_sz, - u8 *hw_action, - u32 hw_action_sz, - u16 *used_hw_action_num) -{ - u8 padded_data[DR_STE_L2_HDR_MAX_SZ] = {}; - void *data_ptr = padded_data; - u16 used_actions = 0; - u32 inline_data_sz; - u32 i; - - if (hw_action_sz / DR_STE_ACTION_DOUBLE_SZ < DR_STE_DECAP_L3_ACTION_NUM) - return -EINVAL; - - inline_data_sz = - MLX5_FLD_SZ_BYTES(ste_double_action_insert_with_inline_v1, inline_data); - - /* Add an alignment padding */ - memcpy(padded_data + data_sz % inline_data_sz, data, data_sz); - - /* Remove L2L3 outer headers */ - MLX5_SET(ste_single_action_remove_header_v1, hw_action, action_id, - DR_STE_V1_ACTION_ID_REMOVE_HEADER_TO_HEADER); - MLX5_SET(ste_single_action_remove_header_v1, hw_action, decap, 1); - MLX5_SET(ste_single_action_remove_header_v1, hw_action, vni_to_cqe, 1); - MLX5_SET(ste_single_action_remove_header_v1, hw_action, end_anchor, - DR_STE_HEADER_ANCHOR_INNER_IPV6_IPV4); - hw_action += DR_STE_ACTION_DOUBLE_SZ; - used_actions++; /* Remove and NOP are a single double action */ - - /* Point to the last dword of the header */ - data_ptr += (data_sz / inline_data_sz) * inline_data_sz; - - /* Add the new header using inline action 4Byte at a time, the header - * is added in reversed order to the beginning of the packet to avoid - * incorrect parsing by the HW. Since header is 14B or 18B an extra - * two bytes are padded and later removed. - */ - for (i = 0; i < data_sz / inline_data_sz + 1; i++) { - void *addr_inline; - - MLX5_SET(ste_double_action_insert_with_inline_v1, hw_action, action_id, - DR_STE_V1_ACTION_ID_INSERT_INLINE); - /* The hardware expects here offset to words (2 bytes) */ - MLX5_SET(ste_double_action_insert_with_inline_v1, hw_action, start_offset, 0); - - /* Copy bytes one by one to avoid endianness problem */ - addr_inline = MLX5_ADDR_OF(ste_double_action_insert_with_inline_v1, - hw_action, inline_data); - memcpy(addr_inline, data_ptr - i * inline_data_sz, inline_data_sz); - hw_action += DR_STE_ACTION_DOUBLE_SZ; - used_actions++; - } - - /* Remove first 2 extra bytes */ - MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, action_id, - DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE); - MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, start_offset, 0); - /* The hardware expects here size in words (2 bytes) */ - MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, remove_size, 1); - used_actions++; - - *used_hw_action_num = used_actions; - - return 0; -} - -static void dr_ste_v1_build_eth_l2_src_dst_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, dmac_47_16, mask, dmac_47_16); - DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, dmac_15_0, mask, dmac_15_0); - - DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, smac_47_16, mask, smac_47_16); - DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, smac_15_0, mask, smac_15_0); - - DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, first_vlan_id, mask, first_vid); - DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, first_cfi, mask, first_cfi); - DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, first_priority, mask, first_prio); - DR_STE_SET_ONES(eth_l2_src_dst_v1, bit_mask, l3_type, mask, ip_version); - - if (mask->cvlan_tag) { - MLX5_SET(ste_eth_l2_src_dst_v1, bit_mask, first_vlan_qualifier, -1); - mask->cvlan_tag = 0; - } else if (mask->svlan_tag) { - MLX5_SET(ste_eth_l2_src_dst_v1, bit_mask, first_vlan_qualifier, -1); - mask->svlan_tag = 0; - } -} - -static int dr_ste_v1_build_eth_l2_src_dst_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, dmac_47_16, spec, dmac_47_16); - DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, dmac_15_0, spec, dmac_15_0); - - DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, smac_47_16, spec, smac_47_16); - DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, smac_15_0, spec, smac_15_0); - - if (spec->ip_version == IP_VERSION_IPV4) { - MLX5_SET(ste_eth_l2_src_dst_v1, tag, l3_type, STE_IPV4); - spec->ip_version = 0; - } else if (spec->ip_version == IP_VERSION_IPV6) { - MLX5_SET(ste_eth_l2_src_dst_v1, tag, l3_type, STE_IPV6); - spec->ip_version = 0; - } else if (spec->ip_version) { - return -EINVAL; - } - - DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, first_vlan_id, spec, first_vid); - DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, first_cfi, spec, first_cfi); - DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, first_priority, spec, first_prio); - - if (spec->cvlan_tag) { - MLX5_SET(ste_eth_l2_src_dst_v1, tag, first_vlan_qualifier, DR_STE_CVLAN); - spec->cvlan_tag = 0; - } else if (spec->svlan_tag) { - MLX5_SET(ste_eth_l2_src_dst_v1, tag, first_vlan_qualifier, DR_STE_SVLAN); - spec->svlan_tag = 0; - } - return 0; -} - -void dr_ste_v1_build_eth_l2_src_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l2_src_dst_bit_mask(mask, sb->inner, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL2_SRC_DST, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l2_src_dst_tag; -} - -static int dr_ste_v1_build_eth_l3_ipv6_dst_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_127_96, spec, dst_ip_127_96); - DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_95_64, spec, dst_ip_95_64); - DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_63_32, spec, dst_ip_63_32); - DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_31_0, spec, dst_ip_31_0); - - return 0; -} - -void dr_ste_v1_build_eth_l3_ipv6_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l3_ipv6_dst_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(IPV6_DES, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l3_ipv6_dst_tag; -} - -static int dr_ste_v1_build_eth_l3_ipv6_src_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_127_96, spec, src_ip_127_96); - DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_95_64, spec, src_ip_95_64); - DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_63_32, spec, src_ip_63_32); - DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_31_0, spec, src_ip_31_0); - - return 0; -} - -void dr_ste_v1_build_eth_l3_ipv6_src_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l3_ipv6_src_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(IPV6_SRC, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l3_ipv6_src_tag; -} - -static int dr_ste_v1_build_eth_l3_ipv4_5_tuple_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, destination_address, spec, dst_ip_31_0); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, source_address, spec, src_ip_31_0); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, destination_port, spec, tcp_dport); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, destination_port, spec, udp_dport); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, source_port, spec, tcp_sport); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, source_port, spec, udp_sport); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, protocol, spec, ip_protocol); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, fragmented, spec, frag); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, dscp, spec, ip_dscp); - DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, ecn, spec, ip_ecn); - - if (spec->tcp_flags) { - DR_STE_SET_TCP_FLAGS(eth_l3_ipv4_5_tuple_v1, tag, spec); - spec->tcp_flags = 0; - } - - return 0; -} - -void dr_ste_v1_build_eth_l3_ipv4_5_tuple_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l3_ipv4_5_tuple_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL3_IPV4_5_TUPLE, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l3_ipv4_5_tuple_tag; -} - -static void dr_ste_v1_build_eth_l2_src_or_dst_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc_mask = &value->misc; - - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, first_vlan_id, mask, first_vid); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, first_cfi, mask, first_cfi); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, first_priority, mask, first_prio); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, ip_fragmented, mask, frag); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, l3_ethertype, mask, ethertype); - DR_STE_SET_ONES(eth_l2_src_v1, bit_mask, l3_type, mask, ip_version); - - if (mask->svlan_tag || mask->cvlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, bit_mask, first_vlan_qualifier, -1); - mask->cvlan_tag = 0; - mask->svlan_tag = 0; - } - - if (inner) { - if (misc_mask->inner_second_cvlan_tag || - misc_mask->inner_second_svlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, bit_mask, second_vlan_qualifier, -1); - misc_mask->inner_second_cvlan_tag = 0; - misc_mask->inner_second_svlan_tag = 0; - } - - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, - second_vlan_id, misc_mask, inner_second_vid); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, - second_cfi, misc_mask, inner_second_cfi); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, - second_priority, misc_mask, inner_second_prio); - } else { - if (misc_mask->outer_second_cvlan_tag || - misc_mask->outer_second_svlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, bit_mask, second_vlan_qualifier, -1); - misc_mask->outer_second_cvlan_tag = 0; - misc_mask->outer_second_svlan_tag = 0; - } - - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, - second_vlan_id, misc_mask, outer_second_vid); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, - second_cfi, misc_mask, outer_second_cfi); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, - second_priority, misc_mask, outer_second_prio); - } -} - -static int dr_ste_v1_build_eth_l2_src_or_dst_tag(struct mlx5dr_match_param *value, - bool inner, u8 *tag) -{ - struct mlx5dr_match_spec *spec = inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc_spec = &value->misc; - - DR_STE_SET_TAG(eth_l2_src_v1, tag, first_vlan_id, spec, first_vid); - DR_STE_SET_TAG(eth_l2_src_v1, tag, first_cfi, spec, first_cfi); - DR_STE_SET_TAG(eth_l2_src_v1, tag, first_priority, spec, first_prio); - DR_STE_SET_TAG(eth_l2_src_v1, tag, ip_fragmented, spec, frag); - DR_STE_SET_TAG(eth_l2_src_v1, tag, l3_ethertype, spec, ethertype); - - if (spec->ip_version == IP_VERSION_IPV4) { - MLX5_SET(ste_eth_l2_src_v1, tag, l3_type, STE_IPV4); - spec->ip_version = 0; - } else if (spec->ip_version == IP_VERSION_IPV6) { - MLX5_SET(ste_eth_l2_src_v1, tag, l3_type, STE_IPV6); - spec->ip_version = 0; - } else if (spec->ip_version) { - return -EINVAL; - } - - if (spec->cvlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, tag, first_vlan_qualifier, DR_STE_CVLAN); - spec->cvlan_tag = 0; - } else if (spec->svlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, tag, first_vlan_qualifier, DR_STE_SVLAN); - spec->svlan_tag = 0; - } - - if (inner) { - if (misc_spec->inner_second_cvlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, tag, second_vlan_qualifier, DR_STE_CVLAN); - misc_spec->inner_second_cvlan_tag = 0; - } else if (misc_spec->inner_second_svlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, tag, second_vlan_qualifier, DR_STE_SVLAN); - misc_spec->inner_second_svlan_tag = 0; - } - - DR_STE_SET_TAG(eth_l2_src_v1, tag, second_vlan_id, misc_spec, inner_second_vid); - DR_STE_SET_TAG(eth_l2_src_v1, tag, second_cfi, misc_spec, inner_second_cfi); - DR_STE_SET_TAG(eth_l2_src_v1, tag, second_priority, misc_spec, inner_second_prio); - } else { - if (misc_spec->outer_second_cvlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, tag, second_vlan_qualifier, DR_STE_CVLAN); - misc_spec->outer_second_cvlan_tag = 0; - } else if (misc_spec->outer_second_svlan_tag) { - MLX5_SET(ste_eth_l2_src_v1, tag, second_vlan_qualifier, DR_STE_SVLAN); - misc_spec->outer_second_svlan_tag = 0; - } - DR_STE_SET_TAG(eth_l2_src_v1, tag, second_vlan_id, misc_spec, outer_second_vid); - DR_STE_SET_TAG(eth_l2_src_v1, tag, second_cfi, misc_spec, outer_second_cfi); - DR_STE_SET_TAG(eth_l2_src_v1, tag, second_priority, misc_spec, outer_second_prio); - } - - return 0; -} - -static void dr_ste_v1_build_eth_l2_src_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, smac_47_16, mask, smac_47_16); - DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, smac_15_0, mask, smac_15_0); - - dr_ste_v1_build_eth_l2_src_or_dst_bit_mask(value, inner, bit_mask); -} - -static int dr_ste_v1_build_eth_l2_src_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_src_v1, tag, smac_47_16, spec, smac_47_16); - DR_STE_SET_TAG(eth_l2_src_v1, tag, smac_15_0, spec, smac_15_0); - - return dr_ste_v1_build_eth_l2_src_or_dst_tag(value, sb->inner, tag); -} - -void dr_ste_v1_build_eth_l2_src_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l2_src_bit_mask(mask, sb->inner, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL2_SRC, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l2_src_tag; -} - -static void dr_ste_v1_build_eth_l2_dst_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_dst_v1, bit_mask, dmac_47_16, mask, dmac_47_16); - DR_STE_SET_TAG(eth_l2_dst_v1, bit_mask, dmac_15_0, mask, dmac_15_0); - - dr_ste_v1_build_eth_l2_src_or_dst_bit_mask(value, inner, bit_mask); -} - -static int dr_ste_v1_build_eth_l2_dst_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l2_dst_v1, tag, dmac_47_16, spec, dmac_47_16); - DR_STE_SET_TAG(eth_l2_dst_v1, tag, dmac_15_0, spec, dmac_15_0); - - return dr_ste_v1_build_eth_l2_src_or_dst_tag(value, sb->inner, tag); -} - -void dr_ste_v1_build_eth_l2_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l2_dst_bit_mask(mask, sb->inner, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL2, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l2_dst_tag; -} - -static void dr_ste_v1_build_eth_l2_tnl_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) -{ - struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, dmac_47_16, mask, dmac_47_16); - DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, dmac_15_0, mask, dmac_15_0); - DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, first_vlan_id, mask, first_vid); - DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, first_cfi, mask, first_cfi); - DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, first_priority, mask, first_prio); - DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, ip_fragmented, mask, frag); - DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, l3_ethertype, mask, ethertype); - DR_STE_SET_ONES(eth_l2_tnl_v1, bit_mask, l3_type, mask, ip_version); - - if (misc->vxlan_vni) { - MLX5_SET(ste_eth_l2_tnl_v1, bit_mask, - l2_tunneling_network_id, (misc->vxlan_vni << 8)); - misc->vxlan_vni = 0; - } - - if (mask->svlan_tag || mask->cvlan_tag) { - MLX5_SET(ste_eth_l2_tnl_v1, bit_mask, first_vlan_qualifier, -1); - mask->cvlan_tag = 0; - mask->svlan_tag = 0; - } -} - -static int dr_ste_v1_build_eth_l2_tnl_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(eth_l2_tnl_v1, tag, dmac_47_16, spec, dmac_47_16); - DR_STE_SET_TAG(eth_l2_tnl_v1, tag, dmac_15_0, spec, dmac_15_0); - DR_STE_SET_TAG(eth_l2_tnl_v1, tag, first_vlan_id, spec, first_vid); - DR_STE_SET_TAG(eth_l2_tnl_v1, tag, first_cfi, spec, first_cfi); - DR_STE_SET_TAG(eth_l2_tnl_v1, tag, ip_fragmented, spec, frag); - DR_STE_SET_TAG(eth_l2_tnl_v1, tag, first_priority, spec, first_prio); - DR_STE_SET_TAG(eth_l2_tnl_v1, tag, l3_ethertype, spec, ethertype); - - if (misc->vxlan_vni) { - MLX5_SET(ste_eth_l2_tnl_v1, tag, l2_tunneling_network_id, - (misc->vxlan_vni << 8)); - misc->vxlan_vni = 0; - } - - if (spec->cvlan_tag) { - MLX5_SET(ste_eth_l2_tnl_v1, tag, first_vlan_qualifier, DR_STE_CVLAN); - spec->cvlan_tag = 0; - } else if (spec->svlan_tag) { - MLX5_SET(ste_eth_l2_tnl_v1, tag, first_vlan_qualifier, DR_STE_SVLAN); - spec->svlan_tag = 0; - } - - if (spec->ip_version == IP_VERSION_IPV4) { - MLX5_SET(ste_eth_l2_tnl_v1, tag, l3_type, STE_IPV4); - spec->ip_version = 0; - } else if (spec->ip_version == IP_VERSION_IPV6) { - MLX5_SET(ste_eth_l2_tnl_v1, tag, l3_type, STE_IPV6); - spec->ip_version = 0; - } else if (spec->ip_version) { - return -EINVAL; - } - - return 0; -} - -void dr_ste_v1_build_eth_l2_tnl_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l2_tnl_bit_mask(mask, sb->inner, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_ETHL2_TNL; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l2_tnl_tag; -} - -static int dr_ste_v1_build_eth_l3_ipv4_misc_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - - DR_STE_SET_TAG(eth_l3_ipv4_misc_v1, tag, time_to_live, spec, ttl_hoplimit); - DR_STE_SET_TAG(eth_l3_ipv4_misc_v1, tag, ihl, spec, ipv4_ihl); - - return 0; -} - -void dr_ste_v1_build_eth_l3_ipv4_misc_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l3_ipv4_misc_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL3_IPV4_MISC, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l3_ipv4_misc_tag; -} - -static int dr_ste_v1_build_eth_ipv6_l3_l4_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(eth_l4_v1, tag, dst_port, spec, tcp_dport); - DR_STE_SET_TAG(eth_l4_v1, tag, src_port, spec, tcp_sport); - DR_STE_SET_TAG(eth_l4_v1, tag, dst_port, spec, udp_dport); - DR_STE_SET_TAG(eth_l4_v1, tag, src_port, spec, udp_sport); - DR_STE_SET_TAG(eth_l4_v1, tag, protocol, spec, ip_protocol); - DR_STE_SET_TAG(eth_l4_v1, tag, fragmented, spec, frag); - DR_STE_SET_TAG(eth_l4_v1, tag, dscp, spec, ip_dscp); - DR_STE_SET_TAG(eth_l4_v1, tag, ecn, spec, ip_ecn); - DR_STE_SET_TAG(eth_l4_v1, tag, ipv6_hop_limit, spec, ttl_hoplimit); - - if (sb->inner) - DR_STE_SET_TAG(eth_l4_v1, tag, flow_label, misc, inner_ipv6_flow_label); - else - DR_STE_SET_TAG(eth_l4_v1, tag, flow_label, misc, outer_ipv6_flow_label); - - if (spec->tcp_flags) { - DR_STE_SET_TCP_FLAGS(eth_l4_v1, tag, spec); - spec->tcp_flags = 0; - } - - return 0; -} - -void dr_ste_v1_build_eth_ipv6_l3_l4_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_ipv6_l3_l4_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL4, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_ipv6_l3_l4_tag; -} - -static int dr_ste_v1_build_mpls_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - - if (sb->inner) - DR_STE_SET_MPLS(mpls_v1, misc2, inner, tag); - else - DR_STE_SET_MPLS(mpls_v1, misc2, outer, tag); - - return 0; -} - -void dr_ste_v1_build_mpls_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_mpls_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_CALC_DFNR_TYPE(MPLS, sb->inner); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_mpls_tag; -} - -static int dr_ste_v1_build_tnl_gre_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(gre_v1, tag, gre_protocol, misc, gre_protocol); - DR_STE_SET_TAG(gre_v1, tag, gre_k_present, misc, gre_k_present); - DR_STE_SET_TAG(gre_v1, tag, gre_key_h, misc, gre_key_h); - DR_STE_SET_TAG(gre_v1, tag, gre_key_l, misc, gre_key_l); - - DR_STE_SET_TAG(gre_v1, tag, gre_c_present, misc, gre_c_present); - DR_STE_SET_TAG(gre_v1, tag, gre_s_present, misc, gre_s_present); - - return 0; -} - -void dr_ste_v1_build_tnl_gre_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_tnl_gre_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_GRE; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_tnl_gre_tag; -} - -static int dr_ste_v1_build_tnl_mpls_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - - if (DR_STE_IS_OUTER_MPLS_OVER_GRE_SET(misc2)) { - DR_STE_SET_TAG(mpls_v1, tag, mpls0_label, - misc2, outer_first_mpls_over_gre_label); - - DR_STE_SET_TAG(mpls_v1, tag, mpls0_exp, - misc2, outer_first_mpls_over_gre_exp); - - DR_STE_SET_TAG(mpls_v1, tag, mpls0_s_bos, - misc2, outer_first_mpls_over_gre_s_bos); - - DR_STE_SET_TAG(mpls_v1, tag, mpls0_ttl, - misc2, outer_first_mpls_over_gre_ttl); - } else { - DR_STE_SET_TAG(mpls_v1, tag, mpls0_label, - misc2, outer_first_mpls_over_udp_label); - - DR_STE_SET_TAG(mpls_v1, tag, mpls0_exp, - misc2, outer_first_mpls_over_udp_exp); - - DR_STE_SET_TAG(mpls_v1, tag, mpls0_s_bos, - misc2, outer_first_mpls_over_udp_s_bos); - - DR_STE_SET_TAG(mpls_v1, tag, mpls0_ttl, - misc2, outer_first_mpls_over_udp_ttl); - } - - return 0; -} - -void dr_ste_v1_build_tnl_mpls_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_tnl_mpls_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_MPLS_I; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_tnl_mpls_tag; -} - -static int dr_ste_v1_build_tnl_mpls_over_udp_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - u8 *parser_ptr; - u8 parser_id; - u32 mpls_hdr; - - mpls_hdr = misc2->outer_first_mpls_over_udp_label << HDR_MPLS_OFFSET_LABEL; - misc2->outer_first_mpls_over_udp_label = 0; - mpls_hdr |= misc2->outer_first_mpls_over_udp_exp << HDR_MPLS_OFFSET_EXP; - misc2->outer_first_mpls_over_udp_exp = 0; - mpls_hdr |= misc2->outer_first_mpls_over_udp_s_bos << HDR_MPLS_OFFSET_S_BOS; - misc2->outer_first_mpls_over_udp_s_bos = 0; - mpls_hdr |= misc2->outer_first_mpls_over_udp_ttl << HDR_MPLS_OFFSET_TTL; - misc2->outer_first_mpls_over_udp_ttl = 0; - - parser_id = sb->caps->flex_parser_id_mpls_over_udp; - parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); - *(__be32 *)parser_ptr = cpu_to_be32(mpls_hdr); - - return 0; -} - -void dr_ste_v1_build_tnl_mpls_over_udp_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_tnl_mpls_over_udp_tag(mask, sb, sb->bit_mask); - - /* STEs with lookup type FLEX_PARSER_{0/1} includes - * flex parsers_{0-3}/{4-7} respectively. - */ - sb->lu_type = sb->caps->flex_parser_id_mpls_over_udp > DR_STE_MAX_FLEX_0_ID ? - DR_STE_V1_LU_TYPE_FLEX_PARSER_1 : - DR_STE_V1_LU_TYPE_FLEX_PARSER_0; - - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_tnl_mpls_over_udp_tag; -} - -static int dr_ste_v1_build_tnl_mpls_over_gre_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - u8 *parser_ptr; - u8 parser_id; - u32 mpls_hdr; - - mpls_hdr = misc2->outer_first_mpls_over_gre_label << HDR_MPLS_OFFSET_LABEL; - misc2->outer_first_mpls_over_gre_label = 0; - mpls_hdr |= misc2->outer_first_mpls_over_gre_exp << HDR_MPLS_OFFSET_EXP; - misc2->outer_first_mpls_over_gre_exp = 0; - mpls_hdr |= misc2->outer_first_mpls_over_gre_s_bos << HDR_MPLS_OFFSET_S_BOS; - misc2->outer_first_mpls_over_gre_s_bos = 0; - mpls_hdr |= misc2->outer_first_mpls_over_gre_ttl << HDR_MPLS_OFFSET_TTL; - misc2->outer_first_mpls_over_gre_ttl = 0; - - parser_id = sb->caps->flex_parser_id_mpls_over_gre; - parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); - *(__be32 *)parser_ptr = cpu_to_be32(mpls_hdr); - - return 0; -} - -void dr_ste_v1_build_tnl_mpls_over_gre_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_tnl_mpls_over_gre_tag(mask, sb, sb->bit_mask); - - /* STEs with lookup type FLEX_PARSER_{0/1} includes - * flex parsers_{0-3}/{4-7} respectively. - */ - sb->lu_type = sb->caps->flex_parser_id_mpls_over_gre > DR_STE_MAX_FLEX_0_ID ? - DR_STE_V1_LU_TYPE_FLEX_PARSER_1 : - DR_STE_V1_LU_TYPE_FLEX_PARSER_0; - - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_tnl_mpls_over_gre_tag; -} - -static int dr_ste_v1_build_icmp_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - bool is_ipv4 = DR_MASK_IS_ICMPV4_SET(misc3); - u32 *icmp_header_data; - u8 *icmp_type; - u8 *icmp_code; - - if (is_ipv4) { - icmp_header_data = &misc3->icmpv4_header_data; - icmp_type = &misc3->icmpv4_type; - icmp_code = &misc3->icmpv4_code; - } else { - icmp_header_data = &misc3->icmpv6_header_data; - icmp_type = &misc3->icmpv6_type; - icmp_code = &misc3->icmpv6_code; - } - - MLX5_SET(ste_icmp_v1, tag, icmp_header_data, *icmp_header_data); - MLX5_SET(ste_icmp_v1, tag, icmp_type, *icmp_type); - MLX5_SET(ste_icmp_v1, tag, icmp_code, *icmp_code); - - *icmp_header_data = 0; - *icmp_type = 0; - *icmp_code = 0; - - return 0; -} - -void dr_ste_v1_build_icmp_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_icmp_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_ETHL4_MISC_O; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_icmp_tag; -} - -static int dr_ste_v1_build_general_purpose_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - - DR_STE_SET_TAG(general_purpose, tag, general_purpose_lookup_field, - misc2, metadata_reg_a); - - return 0; -} - -void dr_ste_v1_build_general_purpose_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_general_purpose_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_GENERAL_PURPOSE; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_general_purpose_tag; -} - -static int dr_ste_v1_build_eth_l4_misc_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - - if (sb->inner) { - DR_STE_SET_TAG(eth_l4_misc_v1, tag, seq_num, misc3, inner_tcp_seq_num); - DR_STE_SET_TAG(eth_l4_misc_v1, tag, ack_num, misc3, inner_tcp_ack_num); - } else { - DR_STE_SET_TAG(eth_l4_misc_v1, tag, seq_num, misc3, outer_tcp_seq_num); - DR_STE_SET_TAG(eth_l4_misc_v1, tag, ack_num, misc3, outer_tcp_ack_num); - } - - return 0; -} - -void dr_ste_v1_build_eth_l4_misc_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_eth_l4_misc_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_ETHL4_MISC_O; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_eth_l4_misc_tag; -} - -static int -dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - - DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, - outer_vxlan_gpe_flags, misc3, - outer_vxlan_gpe_flags); - DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, - outer_vxlan_gpe_next_protocol, misc3, - outer_vxlan_gpe_next_protocol); - DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, - outer_vxlan_gpe_vni, misc3, - outer_vxlan_gpe_vni); - - return 0; -} - -void dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_tag; -} - -static int -dr_ste_v1_build_flex_parser_tnl_geneve_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc *misc = &value->misc; - - DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, - geneve_protocol_type, misc, geneve_protocol_type); - DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, - geneve_oam, misc, geneve_oam); - DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, - geneve_opt_len, misc, geneve_opt_len); - DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, - geneve_vni, misc, geneve_vni); - - return 0; -} - -void dr_ste_v1_build_flex_parser_tnl_geneve_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_flex_parser_tnl_geneve_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_geneve_tag; -} - -static int dr_ste_v1_build_tnl_header_0_1_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc5 *misc5 = &value->misc5; - - DR_STE_SET_TAG(tunnel_header, tag, tunnel_header_0, misc5, tunnel_header_0); - DR_STE_SET_TAG(tunnel_header, tag, tunnel_header_1, misc5, tunnel_header_1); - - return 0; -} - -void dr_ste_v1_build_tnl_header_0_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER; - dr_ste_v1_build_tnl_header_0_1_tag(mask, sb, sb->bit_mask); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_tnl_header_0_1_tag; -} - -static int dr_ste_v1_build_register_0_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - - DR_STE_SET_TAG(register_0, tag, register_0_h, misc2, metadata_reg_c_0); - DR_STE_SET_TAG(register_0, tag, register_0_l, misc2, metadata_reg_c_1); - DR_STE_SET_TAG(register_0, tag, register_1_h, misc2, metadata_reg_c_2); - DR_STE_SET_TAG(register_0, tag, register_1_l, misc2, metadata_reg_c_3); - - return 0; -} - -void dr_ste_v1_build_register_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_register_0_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_STEERING_REGISTERS_0; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_register_0_tag; -} - -static int dr_ste_v1_build_register_1_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc2 *misc2 = &value->misc2; - - DR_STE_SET_TAG(register_1, tag, register_2_h, misc2, metadata_reg_c_4); - DR_STE_SET_TAG(register_1, tag, register_2_l, misc2, metadata_reg_c_5); - DR_STE_SET_TAG(register_1, tag, register_3_h, misc2, metadata_reg_c_6); - DR_STE_SET_TAG(register_1, tag, register_3_l, misc2, metadata_reg_c_7); - - return 0; -} - -void dr_ste_v1_build_register_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_register_1_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_STEERING_REGISTERS_1; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_register_1_tag; -} - -static void dr_ste_v1_build_src_gvmi_qpn_bit_mask(struct mlx5dr_match_param *value, - u8 *bit_mask) -{ - struct mlx5dr_match_misc *misc_mask = &value->misc; - - DR_STE_SET_ONES(src_gvmi_qp_v1, bit_mask, source_gvmi, misc_mask, source_port); - DR_STE_SET_ONES(src_gvmi_qp_v1, bit_mask, source_qp, misc_mask, source_sqn); - misc_mask->source_eswitch_owner_vhca_id = 0; -} - -static int dr_ste_v1_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc *misc = &value->misc; - int id = misc->source_eswitch_owner_vhca_id; - struct mlx5dr_cmd_vport_cap *vport_cap; - struct mlx5dr_domain *dmn = sb->dmn; - struct mlx5dr_domain *vport_dmn; - u8 *bit_mask = sb->bit_mask; - struct mlx5dr_domain *peer; - - DR_STE_SET_TAG(src_gvmi_qp_v1, tag, source_qp, misc, source_sqn); - - if (sb->vhca_id_valid) { - peer = xa_load(&dmn->peer_dmn_xa, id); - /* Find port GVMI based on the eswitch_owner_vhca_id */ - if (id == dmn->info.caps.gvmi) - vport_dmn = dmn; - else if (peer && (id == peer->info.caps.gvmi)) - vport_dmn = peer; - else - return -EINVAL; - - misc->source_eswitch_owner_vhca_id = 0; - } else { - vport_dmn = dmn; - } - - if (!MLX5_GET(ste_src_gvmi_qp_v1, bit_mask, source_gvmi)) - return 0; - - vport_cap = mlx5dr_domain_get_vport_cap(vport_dmn, misc->source_port); - if (!vport_cap) { - mlx5dr_err(dmn, "Vport 0x%x is disabled or invalid\n", - misc->source_port); - return -EINVAL; - } - - if (vport_cap->vport_gvmi) - MLX5_SET(ste_src_gvmi_qp_v1, tag, source_gvmi, vport_cap->vport_gvmi); - - misc->source_port = 0; - return 0; -} - -void dr_ste_v1_build_src_gvmi_qpn_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_src_gvmi_qpn_bit_mask(mask, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_SRC_QP_GVMI; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_src_gvmi_qpn_tag; -} - -static void dr_ste_v1_set_flex_parser(u32 *misc4_field_id, - u32 *misc4_field_value, - bool *parser_is_used, - u8 *tag) -{ - u32 id = *misc4_field_id; - u8 *parser_ptr; - - if (id >= DR_NUM_OF_FLEX_PARSERS || parser_is_used[id]) - return; - - parser_is_used[id] = true; - parser_ptr = dr_ste_calc_flex_parser_offset(tag, id); - - *(__be32 *)parser_ptr = cpu_to_be32(*misc4_field_value); - *misc4_field_id = 0; - *misc4_field_value = 0; -} - -static int dr_ste_v1_build_felx_parser_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc4 *misc_4_mask = &value->misc4; - bool parser_is_used[DR_NUM_OF_FLEX_PARSERS] = {}; - - dr_ste_v1_set_flex_parser(&misc_4_mask->prog_sample_field_id_0, - &misc_4_mask->prog_sample_field_value_0, - parser_is_used, tag); - - dr_ste_v1_set_flex_parser(&misc_4_mask->prog_sample_field_id_1, - &misc_4_mask->prog_sample_field_value_1, - parser_is_used, tag); - - dr_ste_v1_set_flex_parser(&misc_4_mask->prog_sample_field_id_2, - &misc_4_mask->prog_sample_field_value_2, - parser_is_used, tag); - - dr_ste_v1_set_flex_parser(&misc_4_mask->prog_sample_field_id_3, - &misc_4_mask->prog_sample_field_value_3, - parser_is_used, tag); - - return 0; -} - -void dr_ste_v1_build_flex_parser_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_0; - dr_ste_v1_build_felx_parser_tag(mask, sb, sb->bit_mask); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_felx_parser_tag; -} - -void dr_ste_v1_build_flex_parser_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_1; - dr_ste_v1_build_felx_parser_tag(mask, sb, sb->bit_mask); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_felx_parser_tag; -} - -static int -dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - u8 parser_id = sb->caps->flex_parser_id_geneve_tlv_option_0; - u8 *parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); - - MLX5_SET(ste_flex_parser_0, parser_ptr, flex_parser_3, - misc3->geneve_tlv_option_0_data); - misc3->geneve_tlv_option_0_data = 0; - - return 0; -} - -void -dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_tag(mask, sb, sb->bit_mask); - - /* STEs with lookup type FLEX_PARSER_{0/1} includes - * flex parsers_{0-3}/{4-7} respectively. - */ - sb->lu_type = sb->caps->flex_parser_id_geneve_tlv_option_0 > 3 ? - DR_STE_V1_LU_TYPE_FLEX_PARSER_1 : - DR_STE_V1_LU_TYPE_FLEX_PARSER_0; - - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_tag; -} - -static int -dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - u8 parser_id = sb->caps->flex_parser_id_geneve_tlv_option_0; - struct mlx5dr_match_misc *misc = &value->misc; - - if (misc->geneve_tlv_option_0_exist) { - MLX5_SET(ste_flex_parser_ok, tag, flex_parsers_ok, 1 << parser_id); - misc->geneve_tlv_option_0_exist = 0; - } - - return 0; -} - -void -dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_OK; - dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_tag(mask, sb, sb->bit_mask); - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_tag; -} - -static int dr_ste_v1_build_flex_parser_tnl_gtpu_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - struct mlx5dr_match_misc3 *misc3 = &value->misc3; - - DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, gtpu_msg_flags, misc3, gtpu_msg_flags); - DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, gtpu_msg_type, misc3, gtpu_msg_type); - DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, gtpu_teid, misc3, gtpu_teid); - - return 0; -} - -void dr_ste_v1_build_flex_parser_tnl_gtpu_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_flex_parser_tnl_gtpu_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_gtpu_tag; -} - -static int -dr_ste_v1_build_tnl_gtpu_flex_parser_0_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_dw_0)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_0, sb->caps, &value->misc3); - if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_teid)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_teid, sb->caps, &value->misc3); - if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_dw_2)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_2, sb->caps, &value->misc3); - if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_first_ext_dw_0)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_first_ext_dw_0, sb->caps, &value->misc3); - return 0; -} - -void -dr_ste_v1_build_tnl_gtpu_flex_parser_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_tnl_gtpu_flex_parser_0_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_0; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_tnl_gtpu_flex_parser_0_tag; -} - -static int -dr_ste_v1_build_tnl_gtpu_flex_parser_1_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *tag) -{ - if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_dw_0)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_0, sb->caps, &value->misc3); - if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_teid)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_teid, sb->caps, &value->misc3); - if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_dw_2)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_2, sb->caps, &value->misc3); - if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_first_ext_dw_0)) - DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_first_ext_dw_0, sb->caps, &value->misc3); - return 0; -} - -void -dr_ste_v1_build_tnl_gtpu_flex_parser_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask) -{ - dr_ste_v1_build_tnl_gtpu_flex_parser_1_tag(mask, sb, sb->bit_mask); - - sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_1; - sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_v1_build_tnl_gtpu_flex_parser_1_tag; -} - -int dr_ste_v1_alloc_modify_hdr_ptrn_arg(struct mlx5dr_action *action) -{ - struct mlx5dr_ptrn_mgr *ptrn_mgr; - int ret; - - ptrn_mgr = action->rewrite->dmn->ptrn_mgr; - if (!ptrn_mgr) - return -EOPNOTSUPP; - - action->rewrite->arg = mlx5dr_arg_get_obj(action->rewrite->dmn->arg_mgr, - action->rewrite->num_of_actions, - action->rewrite->data); - if (!action->rewrite->arg) { - mlx5dr_err(action->rewrite->dmn, "Failed allocating args for modify header\n"); - return -EAGAIN; - } - - action->rewrite->ptrn = - mlx5dr_ptrn_cache_get_pattern(ptrn_mgr, - action->rewrite->num_of_actions, - action->rewrite->data); - if (!action->rewrite->ptrn) { - mlx5dr_err(action->rewrite->dmn, "Failed to get pattern\n"); - ret = -EAGAIN; - goto put_arg; - } - - return 0; - -put_arg: - mlx5dr_arg_put_obj(action->rewrite->dmn->arg_mgr, - action->rewrite->arg); - return ret; -} - -void dr_ste_v1_free_modify_hdr_ptrn_arg(struct mlx5dr_action *action) -{ - mlx5dr_ptrn_cache_put_pattern(action->rewrite->dmn->ptrn_mgr, - action->rewrite->ptrn); - mlx5dr_arg_put_obj(action->rewrite->dmn->arg_mgr, - action->rewrite->arg); -} - -static struct mlx5dr_ste_ctx ste_ctx_v1 = { - /* Builders */ - .build_eth_l2_src_dst_init = &dr_ste_v1_build_eth_l2_src_dst_init, - .build_eth_l3_ipv6_src_init = &dr_ste_v1_build_eth_l3_ipv6_src_init, - .build_eth_l3_ipv6_dst_init = &dr_ste_v1_build_eth_l3_ipv6_dst_init, - .build_eth_l3_ipv4_5_tuple_init = &dr_ste_v1_build_eth_l3_ipv4_5_tuple_init, - .build_eth_l2_src_init = &dr_ste_v1_build_eth_l2_src_init, - .build_eth_l2_dst_init = &dr_ste_v1_build_eth_l2_dst_init, - .build_eth_l2_tnl_init = &dr_ste_v1_build_eth_l2_tnl_init, - .build_eth_l3_ipv4_misc_init = &dr_ste_v1_build_eth_l3_ipv4_misc_init, - .build_eth_ipv6_l3_l4_init = &dr_ste_v1_build_eth_ipv6_l3_l4_init, - .build_mpls_init = &dr_ste_v1_build_mpls_init, - .build_tnl_gre_init = &dr_ste_v1_build_tnl_gre_init, - .build_tnl_mpls_init = &dr_ste_v1_build_tnl_mpls_init, - .build_tnl_mpls_over_udp_init = &dr_ste_v1_build_tnl_mpls_over_udp_init, - .build_tnl_mpls_over_gre_init = &dr_ste_v1_build_tnl_mpls_over_gre_init, - .build_icmp_init = &dr_ste_v1_build_icmp_init, - .build_general_purpose_init = &dr_ste_v1_build_general_purpose_init, - .build_eth_l4_misc_init = &dr_ste_v1_build_eth_l4_misc_init, - .build_tnl_vxlan_gpe_init = &dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_init, - .build_tnl_geneve_init = &dr_ste_v1_build_flex_parser_tnl_geneve_init, - .build_tnl_geneve_tlv_opt_init = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_init, - .build_tnl_geneve_tlv_opt_exist_init = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_init, - .build_register_0_init = &dr_ste_v1_build_register_0_init, - .build_register_1_init = &dr_ste_v1_build_register_1_init, - .build_src_gvmi_qpn_init = &dr_ste_v1_build_src_gvmi_qpn_init, - .build_flex_parser_0_init = &dr_ste_v1_build_flex_parser_0_init, - .build_flex_parser_1_init = &dr_ste_v1_build_flex_parser_1_init, - .build_tnl_gtpu_init = &dr_ste_v1_build_flex_parser_tnl_gtpu_init, - .build_tnl_header_0_1_init = &dr_ste_v1_build_tnl_header_0_1_init, - .build_tnl_gtpu_flex_parser_0_init = &dr_ste_v1_build_tnl_gtpu_flex_parser_0_init, - .build_tnl_gtpu_flex_parser_1_init = &dr_ste_v1_build_tnl_gtpu_flex_parser_1_init, - - /* Getters and Setters */ - .ste_init = &dr_ste_v1_init, - .set_next_lu_type = &dr_ste_v1_set_next_lu_type, - .get_next_lu_type = &dr_ste_v1_get_next_lu_type, - .is_miss_addr_set = &dr_ste_v1_is_miss_addr_set, - .set_miss_addr = &dr_ste_v1_set_miss_addr, - .get_miss_addr = &dr_ste_v1_get_miss_addr, - .set_hit_addr = &dr_ste_v1_set_hit_addr, - .set_byte_mask = &dr_ste_v1_set_byte_mask, - .get_byte_mask = &dr_ste_v1_get_byte_mask, - /* Actions */ - .actions_caps = DR_STE_CTX_ACTION_CAP_TX_POP | - DR_STE_CTX_ACTION_CAP_RX_PUSH | - DR_STE_CTX_ACTION_CAP_RX_ENCAP | - DR_STE_CTX_ACTION_CAP_POP_MDFY, - .set_actions_rx = &dr_ste_v1_set_actions_rx, - .set_actions_tx = &dr_ste_v1_set_actions_tx, - .modify_field_arr_sz = ARRAY_SIZE(dr_ste_v1_action_modify_field_arr), - .modify_field_arr = dr_ste_v1_action_modify_field_arr, - .set_action_set = &dr_ste_v1_set_action_set, - .set_action_add = &dr_ste_v1_set_action_add, - .set_action_copy = &dr_ste_v1_set_action_copy, - .set_action_decap_l3_list = &dr_ste_v1_set_action_decap_l3_list, - .alloc_modify_hdr_chunk = &dr_ste_v1_alloc_modify_hdr_ptrn_arg, - .dealloc_modify_hdr_chunk = &dr_ste_v1_free_modify_hdr_ptrn_arg, - - /* Send */ - .prepare_for_postsend = &dr_ste_v1_prepare_for_postsend, -}; - -struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v1(void) -{ - return &ste_ctx_v1; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.h deleted file mode 100644 index e2fc698670880c..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.h +++ /dev/null @@ -1,97 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ - -#ifndef _DR_STE_V1_ -#define _DR_STE_V1_ - -#include "dr_types.h" -#include "dr_ste.h" - -bool dr_ste_v1_is_miss_addr_set(u8 *hw_ste_p); -void dr_ste_v1_set_miss_addr(u8 *hw_ste_p, u64 miss_addr); -u64 dr_ste_v1_get_miss_addr(u8 *hw_ste_p); -void dr_ste_v1_set_byte_mask(u8 *hw_ste_p, u16 byte_mask); -u16 dr_ste_v1_get_byte_mask(u8 *hw_ste_p); -void dr_ste_v1_set_next_lu_type(u8 *hw_ste_p, u16 lu_type); -u16 dr_ste_v1_get_next_lu_type(u8 *hw_ste_p); -void dr_ste_v1_set_hit_addr(u8 *hw_ste_p, u64 icm_addr, u32 ht_size); -void dr_ste_v1_init(u8 *hw_ste_p, u16 lu_type, bool is_rx, u16 gvmi); -void dr_ste_v1_prepare_for_postsend(u8 *hw_ste_p, u32 ste_size); -void dr_ste_v1_set_actions_tx(struct mlx5dr_domain *dmn, u8 *action_type_set, - u32 actions_caps, u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, u32 *added_stes); -void dr_ste_v1_set_actions_rx(struct mlx5dr_domain *dmn, u8 *action_type_set, - u32 actions_caps, u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, u32 *added_stes); -void dr_ste_v1_set_action_set(u8 *d_action, u8 hw_field, u8 shifter, - u8 length, u32 data); -void dr_ste_v1_set_action_add(u8 *d_action, u8 hw_field, u8 shifter, - u8 length, u32 data); -void dr_ste_v1_set_action_copy(u8 *d_action, u8 dst_hw_field, u8 dst_shifter, - u8 dst_len, u8 src_hw_field, u8 src_shifter); -int dr_ste_v1_set_action_decap_l3_list(void *data, u32 data_sz, u8 *hw_action, - u32 hw_action_sz, u16 *used_hw_action_num); -int dr_ste_v1_alloc_modify_hdr_ptrn_arg(struct mlx5dr_action *action); -void dr_ste_v1_free_modify_hdr_ptrn_arg(struct mlx5dr_action *action); -void dr_ste_v1_build_eth_l2_src_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_l3_ipv6_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_l3_ipv6_src_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_l3_ipv4_5_tuple_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_l2_src_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_l2_dst_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_l2_tnl_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_l3_ipv4_misc_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_ipv6_l3_l4_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_mpls_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_tnl_gre_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_tnl_mpls_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_tnl_mpls_over_udp_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_tnl_mpls_over_gre_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_icmp_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_general_purpose_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_eth_l4_misc_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_flex_parser_tnl_geneve_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_tnl_header_0_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_register_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_register_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_src_gvmi_qpn_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_flex_parser_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_flex_parser_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_flex_parser_tnl_gtpu_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_tnl_gtpu_flex_parser_0_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); -void dr_ste_v1_build_tnl_gtpu_flex_parser_1_init(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask); - -#endif /* _DR_STE_V1_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v2.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v2.c deleted file mode 100644 index 808b013cf48cbd..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v2.c +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ - -#include "dr_ste_v1.h" - -enum { - DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_0 = 0x00, - DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_1 = 0x01, - DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_2 = 0x02, - DR_STE_V2_ACTION_MDFY_FLD_SRC_L2_OUT_0 = 0x08, - DR_STE_V2_ACTION_MDFY_FLD_SRC_L2_OUT_1 = 0x09, - DR_STE_V2_ACTION_MDFY_FLD_L3_OUT_0 = 0x0e, - DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0 = 0x18, - DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_1 = 0x19, - DR_STE_V2_ACTION_MDFY_FLD_IPV4_OUT_0 = 0x40, - DR_STE_V2_ACTION_MDFY_FLD_IPV4_OUT_1 = 0x41, - DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_0 = 0x44, - DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_1 = 0x45, - DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_2 = 0x46, - DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_3 = 0x47, - DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_0 = 0x4c, - DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_1 = 0x4d, - DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_2 = 0x4e, - DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_3 = 0x4f, - DR_STE_V2_ACTION_MDFY_FLD_TCP_MISC_0 = 0x5e, - DR_STE_V2_ACTION_MDFY_FLD_TCP_MISC_1 = 0x5f, - DR_STE_V2_ACTION_MDFY_FLD_CFG_HDR_0_0 = 0x6f, - DR_STE_V2_ACTION_MDFY_FLD_CFG_HDR_0_1 = 0x70, - DR_STE_V2_ACTION_MDFY_FLD_METADATA_2_CQE = 0x7b, - DR_STE_V2_ACTION_MDFY_FLD_GNRL_PURPOSE = 0x7c, - DR_STE_V2_ACTION_MDFY_FLD_REGISTER_2_0 = 0x90, - DR_STE_V2_ACTION_MDFY_FLD_REGISTER_2_1 = 0x91, - DR_STE_V2_ACTION_MDFY_FLD_REGISTER_1_0 = 0x92, - DR_STE_V2_ACTION_MDFY_FLD_REGISTER_1_1 = 0x93, - DR_STE_V2_ACTION_MDFY_FLD_REGISTER_0_0 = 0x94, - DR_STE_V2_ACTION_MDFY_FLD_REGISTER_0_1 = 0x95, -}; - -static const struct mlx5dr_ste_action_modify_field dr_ste_v2_action_modify_field_arr[] = { - [MLX5_ACTION_IN_FIELD_OUT_SMAC_47_16] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_SRC_L2_OUT_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_SMAC_15_0] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_SRC_L2_OUT_1, .start = 16, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_ETHERTYPE] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_1, .start = 0, .end = 15, - }, - [MLX5_ACTION_IN_FIELD_OUT_DMAC_47_16] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_DMAC_15_0] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_1, .start = 16, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_IP_DSCP] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L3_OUT_0, .start = 18, .end = 23, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_FLAGS] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_1, .start = 16, .end = 24, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0, .start = 16, .end = 31, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0, .start = 0, .end = 15, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, - }, - [MLX5_ACTION_IN_FIELD_OUT_IP_TTL] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L3_OUT_0, .start = 8, .end = 15, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L3_OUT_0, .start = 8, .end = 15, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0, .start = 16, .end = 31, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, - }, - [MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0, .start = 0, .end = 15, - .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_0, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_1, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_2, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_3, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_0, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_1, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_2, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_3, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, - }, - [MLX5_ACTION_IN_FIELD_OUT_SIPV4] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV4_OUT_0, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_OUT_DIPV4] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV4_OUT_1, .start = 0, .end = 31, - .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_A] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_GNRL_PURPOSE, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_B] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_METADATA_2_CQE, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_0] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_0_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_1] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_0_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_2] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_1_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_3] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_1_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_4] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_2_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_METADATA_REG_C_5] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_2_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_TCP_MISC_0, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_TCP_MISC_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_FIRST_VID] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_2, .start = 0, .end = 15, - }, - [MLX5_ACTION_IN_FIELD_OUT_EMD_31_0] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_CFG_HDR_0_1, .start = 0, .end = 31, - }, - [MLX5_ACTION_IN_FIELD_OUT_EMD_47_32] = { - .hw_field = DR_STE_V2_ACTION_MDFY_FLD_CFG_HDR_0_0, .start = 0, .end = 15, - }, -}; - -static struct mlx5dr_ste_ctx ste_ctx_v2 = { - /* Builders */ - .build_eth_l2_src_dst_init = &dr_ste_v1_build_eth_l2_src_dst_init, - .build_eth_l3_ipv6_src_init = &dr_ste_v1_build_eth_l3_ipv6_src_init, - .build_eth_l3_ipv6_dst_init = &dr_ste_v1_build_eth_l3_ipv6_dst_init, - .build_eth_l3_ipv4_5_tuple_init = &dr_ste_v1_build_eth_l3_ipv4_5_tuple_init, - .build_eth_l2_src_init = &dr_ste_v1_build_eth_l2_src_init, - .build_eth_l2_dst_init = &dr_ste_v1_build_eth_l2_dst_init, - .build_eth_l2_tnl_init = &dr_ste_v1_build_eth_l2_tnl_init, - .build_eth_l3_ipv4_misc_init = &dr_ste_v1_build_eth_l3_ipv4_misc_init, - .build_eth_ipv6_l3_l4_init = &dr_ste_v1_build_eth_ipv6_l3_l4_init, - .build_mpls_init = &dr_ste_v1_build_mpls_init, - .build_tnl_gre_init = &dr_ste_v1_build_tnl_gre_init, - .build_tnl_mpls_init = &dr_ste_v1_build_tnl_mpls_init, - .build_tnl_mpls_over_udp_init = &dr_ste_v1_build_tnl_mpls_over_udp_init, - .build_tnl_mpls_over_gre_init = &dr_ste_v1_build_tnl_mpls_over_gre_init, - .build_icmp_init = &dr_ste_v1_build_icmp_init, - .build_general_purpose_init = &dr_ste_v1_build_general_purpose_init, - .build_eth_l4_misc_init = &dr_ste_v1_build_eth_l4_misc_init, - .build_tnl_vxlan_gpe_init = &dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_init, - .build_tnl_geneve_init = &dr_ste_v1_build_flex_parser_tnl_geneve_init, - .build_tnl_geneve_tlv_opt_init = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_init, - .build_tnl_geneve_tlv_opt_exist_init = - &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_init, - .build_register_0_init = &dr_ste_v1_build_register_0_init, - .build_register_1_init = &dr_ste_v1_build_register_1_init, - .build_src_gvmi_qpn_init = &dr_ste_v1_build_src_gvmi_qpn_init, - .build_flex_parser_0_init = &dr_ste_v1_build_flex_parser_0_init, - .build_flex_parser_1_init = &dr_ste_v1_build_flex_parser_1_init, - .build_tnl_gtpu_init = &dr_ste_v1_build_flex_parser_tnl_gtpu_init, - .build_tnl_header_0_1_init = &dr_ste_v1_build_tnl_header_0_1_init, - .build_tnl_gtpu_flex_parser_0_init = &dr_ste_v1_build_tnl_gtpu_flex_parser_0_init, - .build_tnl_gtpu_flex_parser_1_init = &dr_ste_v1_build_tnl_gtpu_flex_parser_1_init, - - /* Getters and Setters */ - .ste_init = &dr_ste_v1_init, - .set_next_lu_type = &dr_ste_v1_set_next_lu_type, - .get_next_lu_type = &dr_ste_v1_get_next_lu_type, - .is_miss_addr_set = &dr_ste_v1_is_miss_addr_set, - .set_miss_addr = &dr_ste_v1_set_miss_addr, - .get_miss_addr = &dr_ste_v1_get_miss_addr, - .set_hit_addr = &dr_ste_v1_set_hit_addr, - .set_byte_mask = &dr_ste_v1_set_byte_mask, - .get_byte_mask = &dr_ste_v1_get_byte_mask, - - /* Actions */ - .actions_caps = DR_STE_CTX_ACTION_CAP_TX_POP | - DR_STE_CTX_ACTION_CAP_RX_PUSH | - DR_STE_CTX_ACTION_CAP_RX_ENCAP, - .set_actions_rx = &dr_ste_v1_set_actions_rx, - .set_actions_tx = &dr_ste_v1_set_actions_tx, - .modify_field_arr_sz = ARRAY_SIZE(dr_ste_v2_action_modify_field_arr), - .modify_field_arr = dr_ste_v2_action_modify_field_arr, - .set_action_set = &dr_ste_v1_set_action_set, - .set_action_add = &dr_ste_v1_set_action_add, - .set_action_copy = &dr_ste_v1_set_action_copy, - .set_action_decap_l3_list = &dr_ste_v1_set_action_decap_l3_list, - .alloc_modify_hdr_chunk = &dr_ste_v1_alloc_modify_hdr_ptrn_arg, - .dealloc_modify_hdr_chunk = &dr_ste_v1_free_modify_hdr_ptrn_arg, - - /* Send */ - .prepare_for_postsend = &dr_ste_v1_prepare_for_postsend, -}; - -struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v2(void) -{ - return &ste_ctx_v2; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c deleted file mode 100644 index 69294a66fd7f0c..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c +++ /dev/null @@ -1,319 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -#include "dr_types.h" - -static int dr_table_set_miss_action_nic(struct mlx5dr_domain *dmn, - struct mlx5dr_table_rx_tx *nic_tbl, - struct mlx5dr_action *action) -{ - struct mlx5dr_matcher_rx_tx *last_nic_matcher = NULL; - struct mlx5dr_htbl_connect_info info; - struct mlx5dr_ste_htbl *last_htbl; - struct mlx5dr_icm_chunk *chunk; - int ret; - - if (!list_empty(&nic_tbl->nic_matcher_list)) - last_nic_matcher = list_last_entry(&nic_tbl->nic_matcher_list, - struct mlx5dr_matcher_rx_tx, - list_node); - - if (last_nic_matcher) - last_htbl = last_nic_matcher->e_anchor; - else - last_htbl = nic_tbl->s_anchor; - - if (action) { - chunk = nic_tbl->nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX ? - action->dest_tbl->tbl->rx.s_anchor->chunk : - action->dest_tbl->tbl->tx.s_anchor->chunk; - nic_tbl->default_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(chunk); - } else { - nic_tbl->default_icm_addr = nic_tbl->nic_dmn->default_icm_addr; - } - - info.type = CONNECT_MISS; - info.miss_icm_addr = nic_tbl->default_icm_addr; - - ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_tbl->nic_dmn, - last_htbl, &info, true); - if (ret) - mlx5dr_dbg(dmn, "Failed to set NIC RX/TX miss action, ret %d\n", ret); - - return ret; -} - -int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl, - struct mlx5dr_action *action) -{ - int ret = -EOPNOTSUPP; - - if (action && action->action_type != DR_ACTION_TYP_FT) - return -EOPNOTSUPP; - - mlx5dr_domain_lock(tbl->dmn); - - if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX || - tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) { - ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->rx, action); - if (ret) - goto out; - } - - if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX || - tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) { - ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->tx, action); - if (ret) - goto out; - } - - if (ret) - goto out; - - /* Release old action */ - if (tbl->miss_action) - refcount_dec(&tbl->miss_action->refcount); - - /* Set new miss action */ - tbl->miss_action = action; - if (tbl->miss_action) - refcount_inc(&action->refcount); - -out: - mlx5dr_domain_unlock(tbl->dmn); - return ret; -} - -static void dr_table_uninit_nic(struct mlx5dr_table_rx_tx *nic_tbl) -{ - mlx5dr_htbl_put(nic_tbl->s_anchor); -} - -static void dr_table_uninit_fdb(struct mlx5dr_table *tbl) -{ - dr_table_uninit_nic(&tbl->rx); - dr_table_uninit_nic(&tbl->tx); -} - -static void dr_table_uninit(struct mlx5dr_table *tbl) -{ - mlx5dr_domain_lock(tbl->dmn); - - switch (tbl->dmn->type) { - case MLX5DR_DOMAIN_TYPE_NIC_RX: - dr_table_uninit_nic(&tbl->rx); - break; - case MLX5DR_DOMAIN_TYPE_NIC_TX: - dr_table_uninit_nic(&tbl->tx); - break; - case MLX5DR_DOMAIN_TYPE_FDB: - dr_table_uninit_fdb(tbl); - break; - default: - WARN_ON(true); - break; - } - - mlx5dr_domain_unlock(tbl->dmn); -} - -static int dr_table_init_nic(struct mlx5dr_domain *dmn, - struct mlx5dr_table_rx_tx *nic_tbl) -{ - struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; - struct mlx5dr_htbl_connect_info info; - int ret; - - INIT_LIST_HEAD(&nic_tbl->nic_matcher_list); - - nic_tbl->default_icm_addr = nic_dmn->default_icm_addr; - - nic_tbl->s_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, - DR_CHUNK_SIZE_1, - MLX5DR_STE_LU_TYPE_DONT_CARE, - 0); - if (!nic_tbl->s_anchor) { - mlx5dr_err(dmn, "Failed allocating htbl\n"); - return -ENOMEM; - } - - info.type = CONNECT_MISS; - info.miss_icm_addr = nic_dmn->default_icm_addr; - ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, - nic_tbl->s_anchor, - &info, true); - if (ret) { - mlx5dr_err(dmn, "Failed int and send htbl\n"); - goto free_s_anchor; - } - - mlx5dr_htbl_get(nic_tbl->s_anchor); - - return 0; - -free_s_anchor: - mlx5dr_ste_htbl_free(nic_tbl->s_anchor); - return ret; -} - -static int dr_table_init_fdb(struct mlx5dr_table *tbl) -{ - int ret; - - ret = dr_table_init_nic(tbl->dmn, &tbl->rx); - if (ret) - return ret; - - ret = dr_table_init_nic(tbl->dmn, &tbl->tx); - if (ret) - goto destroy_rx; - - return 0; - -destroy_rx: - dr_table_uninit_nic(&tbl->rx); - return ret; -} - -static int dr_table_init(struct mlx5dr_table *tbl) -{ - int ret = 0; - - INIT_LIST_HEAD(&tbl->matcher_list); - - mlx5dr_domain_lock(tbl->dmn); - - switch (tbl->dmn->type) { - case MLX5DR_DOMAIN_TYPE_NIC_RX: - tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_RX; - tbl->rx.nic_dmn = &tbl->dmn->info.rx; - ret = dr_table_init_nic(tbl->dmn, &tbl->rx); - break; - case MLX5DR_DOMAIN_TYPE_NIC_TX: - tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_TX; - tbl->tx.nic_dmn = &tbl->dmn->info.tx; - ret = dr_table_init_nic(tbl->dmn, &tbl->tx); - break; - case MLX5DR_DOMAIN_TYPE_FDB: - tbl->table_type = MLX5_FLOW_TABLE_TYPE_FDB; - tbl->rx.nic_dmn = &tbl->dmn->info.rx; - tbl->tx.nic_dmn = &tbl->dmn->info.tx; - ret = dr_table_init_fdb(tbl); - break; - default: - WARN_ON(true); - break; - } - - mlx5dr_domain_unlock(tbl->dmn); - - return ret; -} - -static int dr_table_destroy_sw_owned_tbl(struct mlx5dr_table *tbl) -{ - return mlx5dr_cmd_destroy_flow_table(tbl->dmn->mdev, - tbl->table_id, - tbl->table_type); -} - -static int dr_table_create_sw_owned_tbl(struct mlx5dr_table *tbl, u16 uid) -{ - bool en_encap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT); - bool en_decap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); - struct mlx5dr_cmd_create_flow_table_attr ft_attr = {}; - u64 icm_addr_rx = 0; - u64 icm_addr_tx = 0; - int ret; - - if (tbl->rx.s_anchor) - icm_addr_rx = mlx5dr_icm_pool_get_chunk_icm_addr(tbl->rx.s_anchor->chunk); - - if (tbl->tx.s_anchor) - icm_addr_tx = mlx5dr_icm_pool_get_chunk_icm_addr(tbl->tx.s_anchor->chunk); - - ft_attr.table_type = tbl->table_type; - ft_attr.icm_addr_rx = icm_addr_rx; - ft_attr.icm_addr_tx = icm_addr_tx; - ft_attr.level = tbl->dmn->info.caps.max_ft_level - 1; - ft_attr.sw_owner = true; - ft_attr.decap_en = en_decap; - ft_attr.reformat_en = en_encap; - ft_attr.uid = uid; - - ret = mlx5dr_cmd_create_flow_table(tbl->dmn->mdev, &ft_attr, - NULL, &tbl->table_id); - - return ret; -} - -struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_domain *dmn, u32 level, - u32 flags, u16 uid) -{ - struct mlx5dr_table *tbl; - int ret; - - refcount_inc(&dmn->refcount); - - tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); - if (!tbl) - goto dec_ref; - - tbl->dmn = dmn; - tbl->level = level; - tbl->flags = flags; - refcount_set(&tbl->refcount, 1); - - ret = dr_table_init(tbl); - if (ret) - goto free_tbl; - - ret = dr_table_create_sw_owned_tbl(tbl, uid); - if (ret) - goto uninit_tbl; - - INIT_LIST_HEAD(&tbl->dbg_node); - mlx5dr_dbg_tbl_add(tbl); - return tbl; - -uninit_tbl: - dr_table_uninit(tbl); -free_tbl: - kfree(tbl); -dec_ref: - refcount_dec(&dmn->refcount); - return NULL; -} - -int mlx5dr_table_destroy(struct mlx5dr_table *tbl) -{ - int ret; - - if (WARN_ON_ONCE(refcount_read(&tbl->refcount) > 1)) - return -EBUSY; - - mlx5dr_dbg_tbl_del(tbl); - ret = dr_table_destroy_sw_owned_tbl(tbl); - if (ret) - mlx5dr_err(tbl->dmn, "Failed to destroy sw owned table\n"); - - dr_table_uninit(tbl); - - if (tbl->miss_action) - refcount_dec(&tbl->miss_action->refcount); - - refcount_dec(&tbl->dmn->refcount); - kfree(tbl); - - return ret; -} - -u32 mlx5dr_table_get_id(struct mlx5dr_table *tbl) -{ - return tbl->table_id; -} - -struct mlx5dr_table *mlx5dr_table_get_from_fs_ft(struct mlx5_flow_table *ft) -{ - return ft->fs_dr_table.dr_table; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h deleted file mode 100644 index 7618c6147f8665..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h +++ /dev/null @@ -1,1599 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2019, Mellanox Technologies */ - -#ifndef _DR_TYPES_ -#define _DR_TYPES_ - -#include -#include -#include "fs_core.h" -#include "wq.h" -#include "lib/mlx5.h" -#include "mlx5_ifc_dr.h" -#include "mlx5dr.h" -#include "dr_dbg.h" - -#define DR_RULE_MAX_STES 18 -#define DR_ACTION_MAX_STES 5 -#define DR_STE_SVLAN 0x1 -#define DR_STE_CVLAN 0x2 -#define DR_SZ_MATCH_PARAM (MLX5_ST_SZ_DW_MATCH_PARAM * 4) -#define DR_NUM_OF_FLEX_PARSERS 8 -#define DR_STE_MAX_FLEX_0_ID 3 -#define DR_STE_MAX_FLEX_1_ID 7 -#define DR_ACTION_CACHE_LINE_SIZE 64 - -#define mlx5dr_err(dmn, arg...) mlx5_core_err((dmn)->mdev, ##arg) -#define mlx5dr_info(dmn, arg...) mlx5_core_info((dmn)->mdev, ##arg) -#define mlx5dr_dbg(dmn, arg...) mlx5_core_dbg((dmn)->mdev, ##arg) - -struct mlx5dr_ptrn_mgr; -struct mlx5dr_arg_mgr; -struct mlx5dr_arg_obj; - -static inline bool dr_is_flex_parser_0_id(u8 parser_id) -{ - return parser_id <= DR_STE_MAX_FLEX_0_ID; -} - -static inline bool dr_is_flex_parser_1_id(u8 parser_id) -{ - return parser_id > DR_STE_MAX_FLEX_0_ID; -} - -enum mlx5dr_icm_chunk_size { - DR_CHUNK_SIZE_1, - DR_CHUNK_SIZE_MIN = DR_CHUNK_SIZE_1, /* keep updated when changing */ - DR_CHUNK_SIZE_2, - DR_CHUNK_SIZE_4, - DR_CHUNK_SIZE_8, - DR_CHUNK_SIZE_16, - DR_CHUNK_SIZE_32, - DR_CHUNK_SIZE_64, - DR_CHUNK_SIZE_128, - DR_CHUNK_SIZE_256, - DR_CHUNK_SIZE_512, - DR_CHUNK_SIZE_1K, - DR_CHUNK_SIZE_2K, - DR_CHUNK_SIZE_4K, - DR_CHUNK_SIZE_8K, - DR_CHUNK_SIZE_16K, - DR_CHUNK_SIZE_32K, - DR_CHUNK_SIZE_64K, - DR_CHUNK_SIZE_128K, - DR_CHUNK_SIZE_256K, - DR_CHUNK_SIZE_512K, - DR_CHUNK_SIZE_1024K, - DR_CHUNK_SIZE_2048K, - DR_CHUNK_SIZE_MAX, -}; - -enum mlx5dr_icm_type { - DR_ICM_TYPE_STE, - DR_ICM_TYPE_MODIFY_ACTION, - DR_ICM_TYPE_MODIFY_HDR_PTRN, - DR_ICM_TYPE_MAX, -}; - -static inline enum mlx5dr_icm_chunk_size -mlx5dr_icm_next_higher_chunk(enum mlx5dr_icm_chunk_size chunk) -{ - chunk += 2; - if (chunk < DR_CHUNK_SIZE_MAX) - return chunk; - - return DR_CHUNK_SIZE_MAX; -} - -enum { - DR_STE_SIZE = 64, - DR_STE_SIZE_CTRL = 32, - DR_STE_SIZE_MATCH_TAG = 32, - DR_STE_SIZE_TAG = 16, - DR_STE_SIZE_MASK = 16, - DR_STE_SIZE_REDUCED = DR_STE_SIZE - DR_STE_SIZE_MASK, -}; - -enum mlx5dr_ste_ctx_action_cap { - DR_STE_CTX_ACTION_CAP_NONE = 0, - DR_STE_CTX_ACTION_CAP_TX_POP = 1 << 0, - DR_STE_CTX_ACTION_CAP_RX_PUSH = 1 << 1, - DR_STE_CTX_ACTION_CAP_RX_ENCAP = 1 << 2, - DR_STE_CTX_ACTION_CAP_POP_MDFY = 1 << 3, -}; - -enum { - DR_MODIFY_ACTION_SIZE = 8, -}; - -enum mlx5dr_matcher_criteria { - DR_MATCHER_CRITERIA_EMPTY = 0, - DR_MATCHER_CRITERIA_OUTER = 1 << 0, - DR_MATCHER_CRITERIA_MISC = 1 << 1, - DR_MATCHER_CRITERIA_INNER = 1 << 2, - DR_MATCHER_CRITERIA_MISC2 = 1 << 3, - DR_MATCHER_CRITERIA_MISC3 = 1 << 4, - DR_MATCHER_CRITERIA_MISC4 = 1 << 5, - DR_MATCHER_CRITERIA_MISC5 = 1 << 6, - DR_MATCHER_CRITERIA_MAX = 1 << 7, -}; - -enum mlx5dr_action_type { - DR_ACTION_TYP_TNL_L2_TO_L2, - DR_ACTION_TYP_L2_TO_TNL_L2, - DR_ACTION_TYP_TNL_L3_TO_L2, - DR_ACTION_TYP_L2_TO_TNL_L3, - DR_ACTION_TYP_DROP, - DR_ACTION_TYP_QP, - DR_ACTION_TYP_FT, - DR_ACTION_TYP_CTR, - DR_ACTION_TYP_TAG, - DR_ACTION_TYP_MODIFY_HDR, - DR_ACTION_TYP_VPORT, - DR_ACTION_TYP_POP_VLAN, - DR_ACTION_TYP_PUSH_VLAN, - DR_ACTION_TYP_INSERT_HDR, - DR_ACTION_TYP_REMOVE_HDR, - DR_ACTION_TYP_SAMPLER, - DR_ACTION_TYP_ASO_FLOW_METER, - DR_ACTION_TYP_RANGE, - DR_ACTION_TYP_MAX, -}; - -enum mlx5dr_ipv { - DR_RULE_IPV4, - DR_RULE_IPV6, - DR_RULE_IPV_MAX, -}; - -struct mlx5dr_icm_pool; -struct mlx5dr_icm_chunk; -struct mlx5dr_icm_buddy_mem; -struct mlx5dr_ste_htbl; -struct mlx5dr_match_param; -struct mlx5dr_cmd_caps; -struct mlx5dr_rule_rx_tx; -struct mlx5dr_matcher_rx_tx; -struct mlx5dr_ste_ctx; -struct mlx5dr_send_info_pool; -struct mlx5dr_icm_hot_chunk; - -struct mlx5dr_ste { - /* refcount: indicates the num of rules that using this ste */ - u32 refcount; - - /* this ste is part of a rule, located in ste's chain */ - u8 ste_chain_location; - - /* attached to the miss_list head at each htbl entry */ - struct list_head miss_list_node; - - /* this ste is member of htbl */ - struct mlx5dr_ste_htbl *htbl; - - struct mlx5dr_ste_htbl *next_htbl; - - /* The rule this STE belongs to */ - struct mlx5dr_rule_rx_tx *rule_rx_tx; -}; - -struct mlx5dr_ste_htbl_ctrl { - /* total number of valid entries belonging to this hash table. This - * includes the non collision and collision entries - */ - unsigned int num_of_valid_entries; - - /* total number of collisions entries attached to this table */ - unsigned int num_of_collisions; -}; - -struct mlx5dr_ste_htbl { - u16 lu_type; - u16 byte_mask; - u32 refcount; - struct mlx5dr_icm_chunk *chunk; - struct mlx5dr_ste *pointing_ste; - struct mlx5dr_ste_htbl_ctrl ctrl; -}; - -struct mlx5dr_ste_send_info { - struct mlx5dr_ste *ste; - struct list_head send_list; - u16 size; - u16 offset; - u8 data_cont[DR_STE_SIZE]; - u8 *data; -}; - -void mlx5dr_send_fill_and_append_ste_send_info(struct mlx5dr_ste *ste, u16 size, - u16 offset, u8 *data, - struct mlx5dr_ste_send_info *ste_info, - struct list_head *send_list, - bool copy_data); - -struct mlx5dr_ste_build { - u8 inner:1; - u8 rx:1; - u8 vhca_id_valid:1; - struct mlx5dr_domain *dmn; - struct mlx5dr_cmd_caps *caps; - u16 lu_type; - u16 byte_mask; - u8 bit_mask[DR_STE_SIZE_MASK]; - int (*ste_build_tag_func)(struct mlx5dr_match_param *spec, - struct mlx5dr_ste_build *sb, - u8 *tag); -}; - -struct mlx5dr_ste_htbl * -mlx5dr_ste_htbl_alloc(struct mlx5dr_icm_pool *pool, - enum mlx5dr_icm_chunk_size chunk_size, - u16 lu_type, u16 byte_mask); - -int mlx5dr_ste_htbl_free(struct mlx5dr_ste_htbl *htbl); - -static inline void mlx5dr_htbl_put(struct mlx5dr_ste_htbl *htbl) -{ - htbl->refcount--; - if (!htbl->refcount) - mlx5dr_ste_htbl_free(htbl); -} - -static inline void mlx5dr_htbl_get(struct mlx5dr_ste_htbl *htbl) -{ - htbl->refcount++; -} - -/* STE utils */ -u32 mlx5dr_ste_calc_hash_index(u8 *hw_ste_p, struct mlx5dr_ste_htbl *htbl); -bool mlx5dr_ste_is_miss_addr_set(struct mlx5dr_ste_ctx *ste_ctx, u8 *hw_ste_p); -void mlx5dr_ste_set_miss_addr(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste, u64 miss_addr); -void mlx5dr_ste_set_hit_addr(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste, u64 icm_addr, u32 ht_size); -void mlx5dr_ste_set_hit_addr_by_next_htbl(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste, - struct mlx5dr_ste_htbl *next_htbl); -void mlx5dr_ste_set_bit_mask(u8 *hw_ste_p, u8 *bit_mask); -bool mlx5dr_ste_is_last_in_rule(struct mlx5dr_matcher_rx_tx *nic_matcher, - u8 ste_location); -u64 mlx5dr_ste_get_icm_addr(struct mlx5dr_ste *ste); -u64 mlx5dr_ste_get_mr_addr(struct mlx5dr_ste *ste); -struct list_head *mlx5dr_ste_get_miss_list(struct mlx5dr_ste *ste); - -#define MLX5DR_MAX_VLANS 2 -#define MLX5DR_INVALID_PATTERN_INDEX 0xffffffff - -struct mlx5dr_ste_actions_attr { - u32 modify_index; - u32 modify_pat_idx; - u16 modify_actions; - u8 *single_modify_action; - u32 decap_index; - u32 decap_pat_idx; - u16 decap_actions; - u8 decap_with_vlan:1; - u64 final_icm_addr; - u32 flow_tag; - u32 ctr_id; - u16 gvmi; - u16 hit_gvmi; - struct { - u32 id; - u32 size; - u8 param_0; - u8 param_1; - } reformat; - struct { - int count; - u32 headers[MLX5DR_MAX_VLANS]; - } vlans; - - struct { - u32 obj_id; - u32 offset; - u8 dest_reg_id; - u8 init_color; - } aso_flow_meter; - - struct { - u64 miss_icm_addr; - u32 definer_id; - u32 min; - u32 max; - } range; -}; - -void mlx5dr_ste_set_actions_rx(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_domain *dmn, - u8 *action_type_set, - u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes); -void mlx5dr_ste_set_actions_tx(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_domain *dmn, - u8 *action_type_set, - u8 *last_ste, - struct mlx5dr_ste_actions_attr *attr, - u32 *added_stes); - -void mlx5dr_ste_set_action_set(struct mlx5dr_ste_ctx *ste_ctx, - __be64 *hw_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data); -void mlx5dr_ste_set_action_add(struct mlx5dr_ste_ctx *ste_ctx, - __be64 *hw_action, - u8 hw_field, - u8 shifter, - u8 length, - u32 data); -void mlx5dr_ste_set_action_copy(struct mlx5dr_ste_ctx *ste_ctx, - __be64 *hw_action, - u8 dst_hw_field, - u8 dst_shifter, - u8 dst_len, - u8 src_hw_field, - u8 src_shifter); -int mlx5dr_ste_set_action_decap_l3_list(struct mlx5dr_ste_ctx *ste_ctx, - void *data, - u32 data_sz, - u8 *hw_action, - u32 hw_action_sz, - u16 *used_hw_action_num); -int mlx5dr_ste_alloc_modify_hdr(struct mlx5dr_action *action); -void mlx5dr_ste_free_modify_hdr(struct mlx5dr_action *action); - -const struct mlx5dr_ste_action_modify_field * -mlx5dr_ste_conv_modify_hdr_sw_field(struct mlx5dr_ste_ctx *ste_ctx, u16 sw_field); - -struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx(u8 version); -void mlx5dr_ste_free(struct mlx5dr_ste *ste, - struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher); -static inline void mlx5dr_ste_put(struct mlx5dr_ste *ste, - struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher) -{ - ste->refcount--; - if (!ste->refcount) - mlx5dr_ste_free(ste, matcher, nic_matcher); -} - -/* initial as 0, increased only when ste appears in a new rule */ -static inline void mlx5dr_ste_get(struct mlx5dr_ste *ste) -{ - ste->refcount++; -} - -static inline bool mlx5dr_ste_is_not_used(struct mlx5dr_ste *ste) -{ - return !ste->refcount; -} - -bool mlx5dr_ste_equal_tag(void *src, void *dst); -int mlx5dr_ste_create_next_htbl(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_ste *ste, - u8 *cur_hw_ste, - enum mlx5dr_icm_chunk_size log_table_size); - -/* STE build functions */ -int mlx5dr_ste_build_pre_check(struct mlx5dr_domain *dmn, - u8 match_criteria, - struct mlx5dr_match_param *mask, - struct mlx5dr_match_param *value); -int mlx5dr_ste_build_ste_arr(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_match_param *value, - u8 *ste_arr); -void mlx5dr_ste_build_eth_l2_src_dst(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *builder, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_l3_ipv4_5_tuple(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_l3_ipv4_misc(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_l3_ipv6_dst(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_l3_ipv6_src(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_l2_src(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_l2_dst(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_l2_tnl(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_ipv6_l3_l4(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_eth_l4_misc(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_gre(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_mpls(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_mpls_over_gre(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_mpls_over_udp(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx); -void mlx5dr_ste_build_icmp(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_vxlan_gpe(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_geneve(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_geneve_tlv_opt(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_geneve_tlv_opt_exist(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_gtpu(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_gtpu_flex_parser_0(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_gtpu_flex_parser_1(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_cmd_caps *caps, - bool inner, bool rx); -void mlx5dr_ste_build_tnl_header_0_1(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_general_purpose(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_register_0(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_register_1(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_src_gvmi_qpn(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - struct mlx5dr_domain *dmn, - bool inner, bool rx); -void mlx5dr_ste_build_flex_parser_0(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_flex_parser_1(struct mlx5dr_ste_ctx *ste_ctx, - struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); -void mlx5dr_ste_build_empty_always_hit(struct mlx5dr_ste_build *sb, bool rx); - -/* Actions utils */ -int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - struct mlx5dr_action *actions[], - u32 num_actions, - u8 *ste_arr, - u32 *new_hw_ste_arr_sz); - -struct mlx5dr_match_spec { - u32 smac_47_16; /* Source MAC address of incoming packet */ - /* Incoming packet Ethertype - this is the Ethertype - * following the last VLAN tag of the packet - */ - u32 smac_15_0:16; /* Source MAC address of incoming packet */ - u32 ethertype:16; - - u32 dmac_47_16; /* Destination MAC address of incoming packet */ - - u32 dmac_15_0:16; /* Destination MAC address of incoming packet */ - /* Priority of first VLAN tag in the incoming packet. - * Valid only when cvlan_tag==1 or svlan_tag==1 - */ - u32 first_prio:3; - /* CFI bit of first VLAN tag in the incoming packet. - * Valid only when cvlan_tag==1 or svlan_tag==1 - */ - u32 first_cfi:1; - /* VLAN ID of first VLAN tag in the incoming packet. - * Valid only when cvlan_tag==1 or svlan_tag==1 - */ - u32 first_vid:12; - - u32 ip_protocol:8; /* IP protocol */ - /* Differentiated Services Code Point derived from - * Traffic Class/TOS field of IPv6/v4 - */ - u32 ip_dscp:6; - /* Explicit Congestion Notification derived from - * Traffic Class/TOS field of IPv6/v4 - */ - u32 ip_ecn:2; - /* The first vlan in the packet is c-vlan (0x8100). - * cvlan_tag and svlan_tag cannot be set together - */ - u32 cvlan_tag:1; - /* The first vlan in the packet is s-vlan (0x8a88). - * cvlan_tag and svlan_tag cannot be set together - */ - u32 svlan_tag:1; - u32 frag:1; /* Packet is an IP fragment */ - u32 ip_version:4; /* IP version */ - /* TCP flags. ;Bit 0: FIN;Bit 1: SYN;Bit 2: RST;Bit 3: PSH;Bit 4: ACK; - * Bit 5: URG;Bit 6: ECE;Bit 7: CWR;Bit 8: NS - */ - u32 tcp_flags:9; - - /* TCP source port.;tcp and udp sport/dport are mutually exclusive */ - u32 tcp_sport:16; - /* TCP destination port. - * tcp and udp sport/dport are mutually exclusive - */ - u32 tcp_dport:16; - - u32 reserved_auto1:16; - u32 ipv4_ihl:4; - u32 reserved_auto2:4; - u32 ttl_hoplimit:8; - - /* UDP source port.;tcp and udp sport/dport are mutually exclusive */ - u32 udp_sport:16; - /* UDP destination port.;tcp and udp sport/dport are mutually exclusive */ - u32 udp_dport:16; - - /* IPv6 source address of incoming packets - * For IPv4 address use bits 31:0 (rest of the bits are reserved) - * This field should be qualified by an appropriate ethertype - */ - u32 src_ip_127_96; - /* IPv6 source address of incoming packets - * For IPv4 address use bits 31:0 (rest of the bits are reserved) - * This field should be qualified by an appropriate ethertype - */ - u32 src_ip_95_64; - /* IPv6 source address of incoming packets - * For IPv4 address use bits 31:0 (rest of the bits are reserved) - * This field should be qualified by an appropriate ethertype - */ - u32 src_ip_63_32; - /* IPv6 source address of incoming packets - * For IPv4 address use bits 31:0 (rest of the bits are reserved) - * This field should be qualified by an appropriate ethertype - */ - u32 src_ip_31_0; - /* IPv6 destination address of incoming packets - * For IPv4 address use bits 31:0 (rest of the bits are reserved) - * This field should be qualified by an appropriate ethertype - */ - u32 dst_ip_127_96; - /* IPv6 destination address of incoming packets - * For IPv4 address use bits 31:0 (rest of the bits are reserved) - * This field should be qualified by an appropriate ethertype - */ - u32 dst_ip_95_64; - /* IPv6 destination address of incoming packets - * For IPv4 address use bits 31:0 (rest of the bits are reserved) - * This field should be qualified by an appropriate ethertype - */ - u32 dst_ip_63_32; - /* IPv6 destination address of incoming packets - * For IPv4 address use bits 31:0 (rest of the bits are reserved) - * This field should be qualified by an appropriate ethertype - */ - u32 dst_ip_31_0; -}; - -struct mlx5dr_match_misc { - /* used with GRE, checksum exist when gre_c_present == 1 */ - u32 gre_c_present:1; - u32 reserved_auto1:1; - /* used with GRE, key exist when gre_k_present == 1 */ - u32 gre_k_present:1; - /* used with GRE, sequence number exist when gre_s_present == 1 */ - u32 gre_s_present:1; - u32 source_vhca_port:4; - u32 source_sqn:24; /* Source SQN */ - - u32 source_eswitch_owner_vhca_id:16; - /* Source port.;0xffff determines wire port */ - u32 source_port:16; - - /* Priority of second VLAN tag in the outer header of the incoming packet. - * Valid only when outer_second_cvlan_tag ==1 or outer_second_svlan_tag ==1 - */ - u32 outer_second_prio:3; - /* CFI bit of first VLAN tag in the outer header of the incoming packet. - * Valid only when outer_second_cvlan_tag ==1 or outer_second_svlan_tag ==1 - */ - u32 outer_second_cfi:1; - /* VLAN ID of first VLAN tag the outer header of the incoming packet. - * Valid only when outer_second_cvlan_tag ==1 or outer_second_svlan_tag ==1 - */ - u32 outer_second_vid:12; - /* Priority of second VLAN tag in the inner header of the incoming packet. - * Valid only when inner_second_cvlan_tag ==1 or inner_second_svlan_tag ==1 - */ - u32 inner_second_prio:3; - /* CFI bit of first VLAN tag in the inner header of the incoming packet. - * Valid only when inner_second_cvlan_tag ==1 or inner_second_svlan_tag ==1 - */ - u32 inner_second_cfi:1; - /* VLAN ID of first VLAN tag the inner header of the incoming packet. - * Valid only when inner_second_cvlan_tag ==1 or inner_second_svlan_tag ==1 - */ - u32 inner_second_vid:12; - - u32 outer_second_cvlan_tag:1; - u32 inner_second_cvlan_tag:1; - /* The second vlan in the outer header of the packet is c-vlan (0x8100). - * outer_second_cvlan_tag and outer_second_svlan_tag cannot be set together - */ - u32 outer_second_svlan_tag:1; - /* The second vlan in the inner header of the packet is c-vlan (0x8100). - * inner_second_cvlan_tag and inner_second_svlan_tag cannot be set together - */ - u32 inner_second_svlan_tag:1; - /* The second vlan in the outer header of the packet is s-vlan (0x8a88). - * outer_second_cvlan_tag and outer_second_svlan_tag cannot be set together - */ - u32 reserved_auto2:12; - /* The second vlan in the inner header of the packet is s-vlan (0x8a88). - * inner_second_cvlan_tag and inner_second_svlan_tag cannot be set together - */ - u32 gre_protocol:16; /* GRE Protocol (outer) */ - - u32 gre_key_h:24; /* GRE Key[31:8] (outer) */ - u32 gre_key_l:8; /* GRE Key [7:0] (outer) */ - - u32 vxlan_vni:24; /* VXLAN VNI (outer) */ - u32 reserved_auto3:8; - - u32 geneve_vni:24; /* GENEVE VNI field (outer) */ - u32 reserved_auto4:6; - u32 geneve_tlv_option_0_exist:1; - u32 geneve_oam:1; /* GENEVE OAM field (outer) */ - - u32 reserved_auto5:12; - u32 outer_ipv6_flow_label:20; /* Flow label of incoming IPv6 packet (outer) */ - - u32 reserved_auto6:12; - u32 inner_ipv6_flow_label:20; /* Flow label of incoming IPv6 packet (inner) */ - - u32 reserved_auto7:10; - u32 geneve_opt_len:6; /* GENEVE OptLen (outer) */ - u32 geneve_protocol_type:16; /* GENEVE protocol type (outer) */ - - u32 reserved_auto8:8; - u32 bth_dst_qp:24; /* Destination QP in BTH header */ - - u32 reserved_auto9; - u32 outer_esp_spi; - u32 reserved_auto10[3]; -}; - -struct mlx5dr_match_misc2 { - u32 outer_first_mpls_label:20; /* First MPLS LABEL (outer) */ - u32 outer_first_mpls_exp:3; /* First MPLS EXP (outer) */ - u32 outer_first_mpls_s_bos:1; /* First MPLS S_BOS (outer) */ - u32 outer_first_mpls_ttl:8; /* First MPLS TTL (outer) */ - - u32 inner_first_mpls_label:20; /* First MPLS LABEL (inner) */ - u32 inner_first_mpls_exp:3; /* First MPLS EXP (inner) */ - u32 inner_first_mpls_s_bos:1; /* First MPLS S_BOS (inner) */ - u32 inner_first_mpls_ttl:8; /* First MPLS TTL (inner) */ - - u32 outer_first_mpls_over_gre_label:20; /* last MPLS LABEL (outer) */ - u32 outer_first_mpls_over_gre_exp:3; /* last MPLS EXP (outer) */ - u32 outer_first_mpls_over_gre_s_bos:1; /* last MPLS S_BOS (outer) */ - u32 outer_first_mpls_over_gre_ttl:8; /* last MPLS TTL (outer) */ - - u32 outer_first_mpls_over_udp_label:20; /* last MPLS LABEL (outer) */ - u32 outer_first_mpls_over_udp_exp:3; /* last MPLS EXP (outer) */ - u32 outer_first_mpls_over_udp_s_bos:1; /* last MPLS S_BOS (outer) */ - u32 outer_first_mpls_over_udp_ttl:8; /* last MPLS TTL (outer) */ - - u32 metadata_reg_c_7; /* metadata_reg_c_7 */ - u32 metadata_reg_c_6; /* metadata_reg_c_6 */ - u32 metadata_reg_c_5; /* metadata_reg_c_5 */ - u32 metadata_reg_c_4; /* metadata_reg_c_4 */ - u32 metadata_reg_c_3; /* metadata_reg_c_3 */ - u32 metadata_reg_c_2; /* metadata_reg_c_2 */ - u32 metadata_reg_c_1; /* metadata_reg_c_1 */ - u32 metadata_reg_c_0; /* metadata_reg_c_0 */ - u32 metadata_reg_a; /* metadata_reg_a */ - u32 reserved_auto1[3]; -}; - -struct mlx5dr_match_misc3 { - u32 inner_tcp_seq_num; - u32 outer_tcp_seq_num; - u32 inner_tcp_ack_num; - u32 outer_tcp_ack_num; - - u32 reserved_auto1:8; - u32 outer_vxlan_gpe_vni:24; - - u32 outer_vxlan_gpe_next_protocol:8; - u32 outer_vxlan_gpe_flags:8; - u32 reserved_auto2:16; - - u32 icmpv4_header_data; - u32 icmpv6_header_data; - - u8 icmpv4_type; - u8 icmpv4_code; - u8 icmpv6_type; - u8 icmpv6_code; - - u32 geneve_tlv_option_0_data; - - u32 gtpu_teid; - - u8 gtpu_msg_type; - u8 gtpu_msg_flags; - u32 reserved_auto3:16; - - u32 gtpu_dw_2; - u32 gtpu_first_ext_dw_0; - u32 gtpu_dw_0; - u32 reserved_auto4; -}; - -struct mlx5dr_match_misc4 { - u32 prog_sample_field_value_0; - u32 prog_sample_field_id_0; - u32 prog_sample_field_value_1; - u32 prog_sample_field_id_1; - u32 prog_sample_field_value_2; - u32 prog_sample_field_id_2; - u32 prog_sample_field_value_3; - u32 prog_sample_field_id_3; - u32 reserved_auto1[8]; -}; - -struct mlx5dr_match_misc5 { - u32 macsec_tag_0; - u32 macsec_tag_1; - u32 macsec_tag_2; - u32 macsec_tag_3; - u32 tunnel_header_0; - u32 tunnel_header_1; - u32 tunnel_header_2; - u32 tunnel_header_3; -}; - -struct mlx5dr_match_param { - struct mlx5dr_match_spec outer; - struct mlx5dr_match_misc misc; - struct mlx5dr_match_spec inner; - struct mlx5dr_match_misc2 misc2; - struct mlx5dr_match_misc3 misc3; - struct mlx5dr_match_misc4 misc4; - struct mlx5dr_match_misc5 misc5; -}; - -#define DR_MASK_IS_ICMPV4_SET(_misc3) ((_misc3)->icmpv4_type || \ - (_misc3)->icmpv4_code || \ - (_misc3)->icmpv4_header_data) - -#define DR_MASK_IS_SRC_IP_SET(_spec) ((_spec)->src_ip_127_96 || \ - (_spec)->src_ip_95_64 || \ - (_spec)->src_ip_63_32 || \ - (_spec)->src_ip_31_0) - -#define DR_MASK_IS_DST_IP_SET(_spec) ((_spec)->dst_ip_127_96 || \ - (_spec)->dst_ip_95_64 || \ - (_spec)->dst_ip_63_32 || \ - (_spec)->dst_ip_31_0) - -struct mlx5dr_esw_caps { - u64 drop_icm_address_rx; - u64 drop_icm_address_tx; - u64 uplink_icm_address_rx; - u64 uplink_icm_address_tx; - u8 sw_owner:1; - u8 sw_owner_v2:1; -}; - -struct mlx5dr_cmd_vport_cap { - u16 vport_gvmi; - u16 vhca_gvmi; - u16 num; - u64 icm_address_rx; - u64 icm_address_tx; -}; - -struct mlx5dr_roce_cap { - u8 roce_en:1; - u8 fl_rc_qp_when_roce_disabled:1; - u8 fl_rc_qp_when_roce_enabled:1; -}; - -struct mlx5dr_vports { - struct mlx5dr_cmd_vport_cap esw_manager_caps; - struct mlx5dr_cmd_vport_cap uplink_caps; - struct xarray vports_caps_xa; -}; - -struct mlx5dr_cmd_caps { - u16 gvmi; - u64 nic_rx_drop_address; - u64 nic_tx_drop_address; - u64 nic_tx_allow_address; - u64 esw_rx_drop_address; - u64 esw_tx_drop_address; - u32 log_icm_size; - u64 hdr_modify_icm_addr; - u32 log_modify_pattern_icm_size; - u64 hdr_modify_pattern_icm_addr; - u32 flex_protocols; - u8 flex_parser_id_icmp_dw0; - u8 flex_parser_id_icmp_dw1; - u8 flex_parser_id_icmpv6_dw0; - u8 flex_parser_id_icmpv6_dw1; - u8 flex_parser_id_geneve_tlv_option_0; - u8 flex_parser_id_mpls_over_gre; - u8 flex_parser_id_mpls_over_udp; - u8 flex_parser_id_gtpu_dw_0; - u8 flex_parser_id_gtpu_teid; - u8 flex_parser_id_gtpu_dw_2; - u8 flex_parser_id_gtpu_first_ext_dw_0; - u8 flex_parser_ok_bits_supp; - u8 max_ft_level; - u16 roce_min_src_udp; - u8 sw_format_ver; - bool eswitch_manager; - bool rx_sw_owner; - bool tx_sw_owner; - bool fdb_sw_owner; - u8 rx_sw_owner_v2:1; - u8 tx_sw_owner_v2:1; - u8 fdb_sw_owner_v2:1; - struct mlx5dr_esw_caps esw_caps; - struct mlx5dr_vports vports; - bool prio_tag_required; - struct mlx5dr_roce_cap roce_caps; - u16 log_header_modify_argument_granularity; - u16 log_header_modify_argument_max_alloc; - bool support_modify_argument; - u8 is_ecpf:1; - u8 isolate_vl_tc:1; -}; - -enum mlx5dr_domain_nic_type { - DR_DOMAIN_NIC_TYPE_RX, - DR_DOMAIN_NIC_TYPE_TX, -}; - -struct mlx5dr_domain_rx_tx { - u64 drop_icm_addr; - u64 default_icm_addr; - enum mlx5dr_domain_nic_type type; - struct mutex mutex; /* protect rx/tx domain */ -}; - -struct mlx5dr_domain_info { - bool supp_sw_steering; - u32 max_inline_size; - u32 max_send_wr; - u32 max_log_sw_icm_sz; - u32 max_log_action_icm_sz; - u32 max_log_modify_hdr_pattern_icm_sz; - struct mlx5dr_domain_rx_tx rx; - struct mlx5dr_domain_rx_tx tx; - struct mlx5dr_cmd_caps caps; -}; - -struct mlx5dr_domain { - struct mlx5_core_dev *mdev; - u32 pdn; - struct mlx5_uars_page *uar; - enum mlx5dr_domain_type type; - refcount_t refcount; - struct mlx5dr_icm_pool *ste_icm_pool; - struct mlx5dr_icm_pool *action_icm_pool; - struct mlx5dr_send_info_pool *send_info_pool_rx; - struct mlx5dr_send_info_pool *send_info_pool_tx; - struct kmem_cache *chunks_kmem_cache; - struct kmem_cache *htbls_kmem_cache; - struct mlx5dr_ptrn_mgr *ptrn_mgr; - struct mlx5dr_arg_mgr *arg_mgr; - struct mlx5dr_send_ring *send_ring; - struct mlx5dr_domain_info info; - struct xarray csum_fts_xa; - struct mlx5dr_ste_ctx *ste_ctx; - struct list_head dbg_tbl_list; - struct mlx5dr_dbg_dump_info dump_info; - struct xarray definers_xa; - struct xarray peer_dmn_xa; - /* memory management statistics */ - u32 num_buddies[DR_ICM_TYPE_MAX]; -}; - -struct mlx5dr_table_rx_tx { - struct mlx5dr_ste_htbl *s_anchor; - struct mlx5dr_domain_rx_tx *nic_dmn; - u64 default_icm_addr; - struct list_head nic_matcher_list; -}; - -struct mlx5dr_table { - struct mlx5dr_domain *dmn; - struct mlx5dr_table_rx_tx rx; - struct mlx5dr_table_rx_tx tx; - u32 level; - u32 table_type; - u32 table_id; - u32 flags; - struct list_head matcher_list; - struct mlx5dr_action *miss_action; - refcount_t refcount; - struct list_head dbg_node; -}; - -struct mlx5dr_matcher_rx_tx { - struct mlx5dr_ste_htbl *s_htbl; - struct mlx5dr_ste_htbl *e_anchor; - struct mlx5dr_ste_build *ste_builder; - struct mlx5dr_ste_build ste_builder_arr[DR_RULE_IPV_MAX] - [DR_RULE_IPV_MAX] - [DR_RULE_MAX_STES]; - u8 num_of_builders; - u8 num_of_builders_arr[DR_RULE_IPV_MAX][DR_RULE_IPV_MAX]; - u64 default_icm_addr; - struct mlx5dr_table_rx_tx *nic_tbl; - u32 prio; - struct list_head list_node; - u32 rules; -}; - -struct mlx5dr_matcher { - struct mlx5dr_table *tbl; - struct mlx5dr_matcher_rx_tx rx; - struct mlx5dr_matcher_rx_tx tx; - struct list_head list_node; /* Used for both matchers and dbg managing */ - u32 prio; - struct mlx5dr_match_param mask; - u8 match_criteria; - refcount_t refcount; - struct list_head dbg_rule_list; -}; - -struct mlx5dr_ste_action_modify_field { - u16 hw_field; - u8 start; - u8 end; - u8 l3_type; - u8 l4_type; -}; - -struct mlx5dr_ptrn_obj { - struct mlx5dr_icm_chunk *chunk; - u8 *data; - u16 num_of_actions; - u32 index; - refcount_t refcount; - struct list_head list; -}; - -struct mlx5dr_arg_obj { - u32 obj_id; - u32 obj_offset; - struct list_head list_node; - u32 log_chunk_size; -}; - -struct mlx5dr_action_rewrite { - struct mlx5dr_domain *dmn; - struct mlx5dr_icm_chunk *chunk; - u8 *data; - u16 num_of_actions; - u32 index; - u8 single_action_opt:1; - u8 allow_rx:1; - u8 allow_tx:1; - u8 modify_ttl:1; - struct mlx5dr_ptrn_obj *ptrn; - struct mlx5dr_arg_obj *arg; -}; - -struct mlx5dr_action_reformat { - struct mlx5dr_domain *dmn; - u32 id; - u32 size; - u8 param_0; - u8 param_1; -}; - -struct mlx5dr_action_sampler { - struct mlx5dr_domain *dmn; - u64 rx_icm_addr; - u64 tx_icm_addr; - u32 sampler_id; -}; - -struct mlx5dr_action_dest_tbl { - u8 is_fw_tbl:1; - u8 is_wire_ft:1; - union { - struct mlx5dr_table *tbl; - struct { - struct mlx5dr_domain *dmn; - u32 id; - u32 group_id; - enum fs_flow_table_type type; - u64 rx_icm_addr; - u64 tx_icm_addr; - struct mlx5dr_action **ref_actions; - u32 num_of_ref_actions; - } fw_tbl; - }; -}; - -struct mlx5dr_action_range { - struct mlx5dr_domain *dmn; - struct mlx5dr_action *hit_tbl_action; - struct mlx5dr_action *miss_tbl_action; - u32 definer_id; - u32 min; - u32 max; -}; - -struct mlx5dr_action_ctr { - u32 ctr_id; - u32 offset; -}; - -struct mlx5dr_action_vport { - struct mlx5dr_domain *dmn; - struct mlx5dr_cmd_vport_cap *caps; -}; - -struct mlx5dr_action_push_vlan { - u32 vlan_hdr; /* tpid_pcp_dei_vid */ -}; - -struct mlx5dr_action_flow_tag { - u32 flow_tag; -}; - -struct mlx5dr_rule_action_member { - struct mlx5dr_action *action; - struct list_head list; -}; - -struct mlx5dr_action_aso_flow_meter { - struct mlx5dr_domain *dmn; - u32 obj_id; - u32 offset; - u8 dest_reg_id; - u8 init_color; -}; - -struct mlx5dr_action { - enum mlx5dr_action_type action_type; - refcount_t refcount; - - union { - void *data; - struct mlx5dr_action_rewrite *rewrite; - struct mlx5dr_action_reformat *reformat; - struct mlx5dr_action_sampler *sampler; - struct mlx5dr_action_dest_tbl *dest_tbl; - struct mlx5dr_action_ctr *ctr; - struct mlx5dr_action_vport *vport; - struct mlx5dr_action_push_vlan *push_vlan; - struct mlx5dr_action_flow_tag *flow_tag; - struct mlx5dr_action_aso_flow_meter *aso; - struct mlx5dr_action_range *range; - }; -}; - -enum mlx5dr_connect_type { - CONNECT_HIT = 1, - CONNECT_MISS = 2, -}; - -struct mlx5dr_htbl_connect_info { - enum mlx5dr_connect_type type; - union { - struct mlx5dr_ste_htbl *hit_next_htbl; - u64 miss_icm_addr; - }; -}; - -struct mlx5dr_rule_rx_tx { - struct mlx5dr_matcher_rx_tx *nic_matcher; - struct mlx5dr_ste *last_rule_ste; -}; - -struct mlx5dr_rule { - struct mlx5dr_matcher *matcher; - struct mlx5dr_rule_rx_tx rx; - struct mlx5dr_rule_rx_tx tx; - struct list_head rule_actions_list; - struct list_head dbg_node; - u32 flow_source; -}; - -void mlx5dr_rule_set_last_member(struct mlx5dr_rule_rx_tx *nic_rule, - struct mlx5dr_ste *ste, - bool force); -int mlx5dr_rule_get_reverse_rule_members(struct mlx5dr_ste **ste_arr, - struct mlx5dr_ste *curr_ste, - int *num_of_stes); - -struct mlx5dr_icm_chunk { - struct mlx5dr_icm_buddy_mem *buddy_mem; - - /* indicates the index of this chunk in the whole memory, - * used for deleting the chunk from the buddy - */ - unsigned int seg; - enum mlx5dr_icm_chunk_size size; - - /* Memory optimisation */ - struct mlx5dr_ste *ste_arr; - u8 *hw_ste_arr; - struct list_head *miss_list; -}; - -static inline void mlx5dr_domain_nic_lock(struct mlx5dr_domain_rx_tx *nic_dmn) -{ - mutex_lock(&nic_dmn->mutex); -} - -static inline void mlx5dr_domain_nic_unlock(struct mlx5dr_domain_rx_tx *nic_dmn) -{ - mutex_unlock(&nic_dmn->mutex); -} - -static inline void mlx5dr_domain_lock(struct mlx5dr_domain *dmn) -{ - mlx5dr_domain_nic_lock(&dmn->info.rx); - mlx5dr_domain_nic_lock(&dmn->info.tx); -} - -static inline void mlx5dr_domain_unlock(struct mlx5dr_domain *dmn) -{ - mlx5dr_domain_nic_unlock(&dmn->info.tx); - mlx5dr_domain_nic_unlock(&dmn->info.rx); -} - -int mlx5dr_matcher_add_to_tbl_nic(struct mlx5dr_domain *dmn, - struct mlx5dr_matcher_rx_tx *nic_matcher); -int mlx5dr_matcher_remove_from_tbl_nic(struct mlx5dr_domain *dmn, - struct mlx5dr_matcher_rx_tx *nic_matcher); - -int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher, - enum mlx5dr_ipv outer_ipv, - enum mlx5dr_ipv inner_ipv); - -u64 mlx5dr_icm_pool_get_chunk_mr_addr(struct mlx5dr_icm_chunk *chunk); -u32 mlx5dr_icm_pool_get_chunk_rkey(struct mlx5dr_icm_chunk *chunk); -u64 mlx5dr_icm_pool_get_chunk_icm_addr(struct mlx5dr_icm_chunk *chunk); -u32 mlx5dr_icm_pool_get_chunk_num_of_entries(struct mlx5dr_icm_chunk *chunk); -u32 mlx5dr_icm_pool_get_chunk_byte_size(struct mlx5dr_icm_chunk *chunk); -u8 *mlx5dr_ste_get_hw_ste(struct mlx5dr_ste *ste); - -struct mlx5dr_ste_htbl *mlx5dr_icm_pool_alloc_htbl(struct mlx5dr_icm_pool *pool); -void mlx5dr_icm_pool_free_htbl(struct mlx5dr_icm_pool *pool, struct mlx5dr_ste_htbl *htbl); - -static inline int -mlx5dr_icm_pool_dm_type_to_entry_size(enum mlx5dr_icm_type icm_type) -{ - if (icm_type == DR_ICM_TYPE_STE) - return DR_STE_SIZE; - - return DR_MODIFY_ACTION_SIZE; -} - -static inline u32 -mlx5dr_icm_pool_chunk_size_to_entries(enum mlx5dr_icm_chunk_size chunk_size) -{ - return 1 << chunk_size; -} - -static inline int -mlx5dr_icm_pool_chunk_size_to_byte(enum mlx5dr_icm_chunk_size chunk_size, - enum mlx5dr_icm_type icm_type) -{ - int num_of_entries; - int entry_size; - - entry_size = mlx5dr_icm_pool_dm_type_to_entry_size(icm_type); - num_of_entries = mlx5dr_icm_pool_chunk_size_to_entries(chunk_size); - - return entry_size * num_of_entries; -} - -static inline int -mlx5dr_ste_htbl_increase_threshold(struct mlx5dr_ste_htbl *htbl) -{ - int num_of_entries = - mlx5dr_icm_pool_chunk_size_to_entries(htbl->chunk->size); - - /* Threshold is 50%, one is added to table of size 1 */ - return (num_of_entries + 1) / 2; -} - -static inline bool -mlx5dr_ste_htbl_may_grow(struct mlx5dr_ste_htbl *htbl) -{ - if (htbl->chunk->size == DR_CHUNK_SIZE_MAX - 1 || !htbl->byte_mask) - return false; - - return true; -} - -struct mlx5dr_cmd_vport_cap * -mlx5dr_domain_get_vport_cap(struct mlx5dr_domain *dmn, u16 vport); - -struct mlx5dr_cmd_query_flow_table_details { - u8 status; - u8 level; - u64 sw_owner_icm_root_1; - u64 sw_owner_icm_root_0; -}; - -struct mlx5dr_cmd_create_flow_table_attr { - u32 table_type; - u16 uid; - u64 icm_addr_rx; - u64 icm_addr_tx; - u8 level; - bool sw_owner; - bool term_tbl; - bool decap_en; - bool reformat_en; -}; - -/* internal API functions */ -int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev, - struct mlx5dr_cmd_caps *caps); -int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, - bool other_vport, u16 vport_number, - u64 *icm_address_rx, - u64 *icm_address_tx); -int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, - bool other_vport, u16 vport_number, u16 *gvmi); -int mlx5dr_cmd_query_esw_caps(struct mlx5_core_dev *mdev, - struct mlx5dr_esw_caps *caps); -int mlx5dr_cmd_query_flow_sampler(struct mlx5_core_dev *dev, - u32 sampler_id, - u64 *rx_icm_addr, - u64 *tx_icm_addr); -int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev); -int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id, - u32 group_id, - u32 modify_header_id, - u16 vport_id); -int mlx5dr_cmd_del_flow_table_entry(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id); -int mlx5dr_cmd_alloc_modify_header(struct mlx5_core_dev *mdev, - u32 table_type, - u8 num_of_actions, - u64 *actions, - u32 *modify_header_id); -int mlx5dr_cmd_dealloc_modify_header(struct mlx5_core_dev *mdev, - u32 modify_header_id); -int mlx5dr_cmd_create_empty_flow_group(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id, - u32 *group_id); -int mlx5dr_cmd_destroy_flow_group(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id, - u32 group_id); -int mlx5dr_cmd_create_flow_table(struct mlx5_core_dev *mdev, - struct mlx5dr_cmd_create_flow_table_attr *attr, - u64 *fdb_rx_icm_addr, - u32 *table_id); -int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev, - u32 table_id, - u32 table_type); -int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev, - enum fs_flow_table_type type, - u32 table_id, - struct mlx5dr_cmd_query_flow_table_details *output); -int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev, - enum mlx5_reformat_ctx_type rt, - u8 reformat_param_0, - u8 reformat_param_1, - size_t reformat_size, - void *reformat_data, - u32 *reformat_id); -void mlx5dr_cmd_destroy_reformat_ctx(struct mlx5_core_dev *mdev, - u32 reformat_id); -int mlx5dr_cmd_create_definer(struct mlx5_core_dev *mdev, - u16 format_id, - u8 *dw_selectors, - u8 *byte_selectors, - u8 *match_mask, - u32 *definer_id); -void mlx5dr_cmd_destroy_definer(struct mlx5_core_dev *mdev, - u32 definer_id); - -struct mlx5dr_cmd_gid_attr { - u8 gid[16]; - u8 mac[6]; - u32 roce_ver; -}; - -int mlx5dr_cmd_query_gid(struct mlx5_core_dev *mdev, u8 vhca_port_num, - u16 index, struct mlx5dr_cmd_gid_attr *attr); - -int mlx5dr_cmd_create_modify_header_arg(struct mlx5_core_dev *dev, - u16 log_obj_range, u32 pd, - u32 *obj_id); -void mlx5dr_cmd_destroy_modify_header_arg(struct mlx5_core_dev *dev, - u32 obj_id); - -int mlx5dr_definer_get(struct mlx5dr_domain *dmn, u16 format_id, - u8 *dw_selectors, u8 *byte_selectors, - u8 *match_mask, u32 *definer_id); -void mlx5dr_definer_put(struct mlx5dr_domain *dmn, u32 definer_id); - -struct mlx5dr_icm_pool *mlx5dr_icm_pool_create(struct mlx5dr_domain *dmn, - enum mlx5dr_icm_type icm_type); -void mlx5dr_icm_pool_destroy(struct mlx5dr_icm_pool *pool); - -struct mlx5dr_icm_chunk * -mlx5dr_icm_alloc_chunk(struct mlx5dr_icm_pool *pool, - enum mlx5dr_icm_chunk_size chunk_size); -void mlx5dr_icm_free_chunk(struct mlx5dr_icm_chunk *chunk); - -void mlx5dr_ste_prepare_for_postsend(struct mlx5dr_ste_ctx *ste_ctx, - u8 *hw_ste_p, u32 ste_size); -int mlx5dr_ste_htbl_init_and_postsend(struct mlx5dr_domain *dmn, - struct mlx5dr_domain_rx_tx *nic_dmn, - struct mlx5dr_ste_htbl *htbl, - struct mlx5dr_htbl_connect_info *connect_info, - bool update_hw_ste); -void mlx5dr_ste_set_formatted_ste(struct mlx5dr_ste_ctx *ste_ctx, - u16 gvmi, - enum mlx5dr_domain_nic_type nic_type, - struct mlx5dr_ste_htbl *htbl, - u8 *formatted_ste, - struct mlx5dr_htbl_connect_info *connect_info); -void mlx5dr_ste_copy_param(u8 match_criteria, - struct mlx5dr_match_param *set_param, - struct mlx5dr_match_parameters *mask, - bool clear); - -struct mlx5dr_qp { - struct mlx5_core_dev *mdev; - struct mlx5_wq_qp wq; - struct mlx5_uars_page *uar; - struct mlx5_wq_ctrl wq_ctrl; - u32 qpn; - struct { - unsigned int head; - unsigned int pc; - unsigned int cc; - unsigned int size; - unsigned int *wqe_head; - unsigned int wqe_cnt; - } sq; - struct { - unsigned int pc; - unsigned int cc; - unsigned int size; - unsigned int wqe_cnt; - } rq; - int max_inline_data; -}; - -struct mlx5dr_cq { - struct mlx5_core_dev *mdev; - struct mlx5_cqwq wq; - struct mlx5_wq_ctrl wq_ctrl; - struct mlx5_core_cq mcq; - struct mlx5dr_qp *qp; -}; - -struct mlx5dr_mr { - struct mlx5_core_dev *mdev; - u32 mkey; - dma_addr_t dma_addr; - void *addr; - size_t size; -}; - -struct mlx5dr_send_ring { - struct mlx5dr_cq *cq; - struct mlx5dr_qp *qp; - struct mlx5dr_mr *mr; - /* How much wqes are waiting for completion */ - u32 pending_wqe; - /* Signal request per this trash hold value */ - u16 signal_th; - /* Each post_send_size less than max_post_send_size */ - u32 max_post_send_size; - /* manage the send queue */ - u32 tx_head; - void *buf; - u32 buf_size; - u8 *sync_buff; - struct mlx5dr_mr *sync_mr; - spinlock_t lock; /* Protect the data path of the send ring */ - bool err_state; /* send_ring is not usable in err state */ -}; - -int mlx5dr_send_ring_alloc(struct mlx5dr_domain *dmn); -void mlx5dr_send_ring_free(struct mlx5dr_domain *dmn, - struct mlx5dr_send_ring *send_ring); -int mlx5dr_send_ring_force_drain(struct mlx5dr_domain *dmn); -int mlx5dr_send_postsend_ste(struct mlx5dr_domain *dmn, - struct mlx5dr_ste *ste, - u8 *data, - u16 size, - u16 offset); -int mlx5dr_send_postsend_htbl(struct mlx5dr_domain *dmn, - struct mlx5dr_ste_htbl *htbl, - u8 *formatted_ste, u8 *mask); -int mlx5dr_send_postsend_formatted_htbl(struct mlx5dr_domain *dmn, - struct mlx5dr_ste_htbl *htbl, - u8 *ste_init_data, - bool update_hw_ste); -int mlx5dr_send_postsend_action(struct mlx5dr_domain *dmn, - struct mlx5dr_action *action); -int mlx5dr_send_postsend_pattern(struct mlx5dr_domain *dmn, - struct mlx5dr_icm_chunk *chunk, - u16 num_of_actions, - u8 *data); -int mlx5dr_send_postsend_args(struct mlx5dr_domain *dmn, u64 arg_id, - u16 num_of_actions, u8 *actions_data); - -int mlx5dr_send_info_pool_create(struct mlx5dr_domain *dmn); -void mlx5dr_send_info_pool_destroy(struct mlx5dr_domain *dmn); -struct mlx5dr_ste_send_info *mlx5dr_send_info_alloc(struct mlx5dr_domain *dmn, - enum mlx5dr_domain_nic_type nic_type); -void mlx5dr_send_info_free(struct mlx5dr_ste_send_info *ste_send_info); - -struct mlx5dr_cmd_ft_info { - u32 id; - u16 vport; - enum fs_flow_table_type type; -}; - -struct mlx5dr_cmd_flow_destination_hw_info { - enum mlx5_flow_destination_type type; - union { - u32 tir_num; - u32 ft_num; - u32 ft_id; - u32 counter_id; - u32 sampler_id; - struct { - u16 num; - u16 vhca_id; - u32 reformat_id; - u8 flags; - } vport; - }; -}; - -struct mlx5dr_cmd_fte_info { - u32 dests_size; - u32 index; - struct mlx5_flow_context flow_context; - u32 *val; - struct mlx5_flow_act action; - struct mlx5dr_cmd_flow_destination_hw_info *dest_arr; - bool ignore_flow_level; -}; - -int mlx5dr_cmd_set_fte(struct mlx5_core_dev *dev, - int opmod, int modify_mask, - struct mlx5dr_cmd_ft_info *ft, - u32 group_id, - struct mlx5dr_cmd_fte_info *fte); - -bool mlx5dr_ste_supp_ttl_cs_recalc(struct mlx5dr_cmd_caps *caps); - -struct mlx5dr_fw_recalc_cs_ft { - u64 rx_icm_addr; - u32 table_id; - u32 group_id; - u32 modify_hdr_id; -}; - -struct mlx5dr_fw_recalc_cs_ft * -mlx5dr_fw_create_recalc_cs_ft(struct mlx5dr_domain *dmn, u16 vport_num); -void mlx5dr_fw_destroy_recalc_cs_ft(struct mlx5dr_domain *dmn, - struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft); -int mlx5dr_domain_get_recalc_cs_ft_addr(struct mlx5dr_domain *dmn, - u16 vport_num, - u64 *rx_icm_addr); -int mlx5dr_fw_create_md_tbl(struct mlx5dr_domain *dmn, - struct mlx5dr_cmd_flow_destination_hw_info *dest, - int num_dest, - bool reformat_req, - u32 *tbl_id, - u32 *group_id, - bool ignore_flow_level, - u32 flow_source); -void mlx5dr_fw_destroy_md_tbl(struct mlx5dr_domain *dmn, u32 tbl_id, - u32 group_id); - -static inline bool mlx5dr_is_fw_table(struct mlx5_flow_table *ft) -{ - return !ft->fs_dr_table.dr_table; -} - -static inline bool mlx5dr_supp_match_ranges(struct mlx5_core_dev *dev) -{ - return (MLX5_CAP_GEN(dev, steering_format_version) >= - MLX5_STEERING_FORMAT_CONNECTX_6DX) && - (MLX5_CAP_GEN_64(dev, match_definer_format_supported) & - (1ULL << MLX5_IFC_DEFINER_FORMAT_ID_SELECT)); -} - -bool mlx5dr_domain_is_support_ptrn_arg(struct mlx5dr_domain *dmn); -struct mlx5dr_ptrn_mgr *mlx5dr_ptrn_mgr_create(struct mlx5dr_domain *dmn); -void mlx5dr_ptrn_mgr_destroy(struct mlx5dr_ptrn_mgr *mgr); -struct mlx5dr_ptrn_obj *mlx5dr_ptrn_cache_get_pattern(struct mlx5dr_ptrn_mgr *mgr, - u16 num_of_actions, u8 *data); -void mlx5dr_ptrn_cache_put_pattern(struct mlx5dr_ptrn_mgr *mgr, - struct mlx5dr_ptrn_obj *pattern); -struct mlx5dr_arg_mgr *mlx5dr_arg_mgr_create(struct mlx5dr_domain *dmn); -void mlx5dr_arg_mgr_destroy(struct mlx5dr_arg_mgr *mgr); -struct mlx5dr_arg_obj *mlx5dr_arg_get_obj(struct mlx5dr_arg_mgr *mgr, - u16 num_of_actions, - u8 *data); -void mlx5dr_arg_put_obj(struct mlx5dr_arg_mgr *mgr, - struct mlx5dr_arg_obj *arg_obj); -u32 mlx5dr_arg_get_obj_id(struct mlx5dr_arg_obj *arg_obj); - -#endif /* _DR_TYPES_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c deleted file mode 100644 index 833cb68c744f2e..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c +++ /dev/null @@ -1,874 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies */ - -#include -#include "mlx5_core.h" -#include "fs_core.h" -#include "fs_cmd.h" -#include "mlx5dr.h" -#include "fs_dr.h" -#include "dr_types.h" - -static int mlx5_cmd_dr_update_root_ft(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - u32 underlay_qpn, - bool disconnect) -{ - return mlx5_fs_cmd_get_fw_cmds()->update_root_ft(ns, ft, underlay_qpn, - disconnect); -} - -static int set_miss_action(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - struct mlx5_flow_table *next_ft) -{ - struct mlx5dr_action *old_miss_action; - struct mlx5dr_action *action = NULL; - struct mlx5dr_table *next_tbl; - int err; - - next_tbl = next_ft ? next_ft->fs_dr_table.dr_table : NULL; - if (next_tbl) { - action = mlx5dr_action_create_dest_table(next_tbl); - if (!action) - return -EINVAL; - } - old_miss_action = ft->fs_dr_table.miss_action; - err = mlx5dr_table_set_miss_action(ft->fs_dr_table.dr_table, action); - if (err && action) { - err = mlx5dr_action_destroy(action); - if (err) - mlx5_core_err(ns->dev, - "Failed to destroy action (%d)\n", err); - action = NULL; - } - ft->fs_dr_table.miss_action = action; - if (old_miss_action) { - err = mlx5dr_action_destroy(old_miss_action); - if (err) - mlx5_core_err(ns->dev, "Failed to destroy action (%d)\n", - err); - } - - return err; -} - -static int mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - struct mlx5_flow_table_attr *ft_attr, - struct mlx5_flow_table *next_ft) -{ - struct mlx5dr_table *tbl; - u32 flags; - int err; - - if (mlx5_fs_cmd_is_fw_term_table(ft)) - return mlx5_fs_cmd_get_fw_cmds()->create_flow_table(ns, ft, - ft_attr, - next_ft); - flags = ft->flags; - /* turn off encap/decap if not supported for sw-str by fw */ - if (!MLX5_CAP_FLOWTABLE(ns->dev, sw_owner_reformat_supported)) - flags = ft->flags & ~(MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | - MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); - - tbl = mlx5dr_table_create(ns->fs_dr_domain.dr_domain, ft->level, flags, - ft_attr->uid); - if (!tbl) { - mlx5_core_err(ns->dev, "Failed creating dr flow_table\n"); - return -EINVAL; - } - - ft->fs_dr_table.dr_table = tbl; - ft->id = mlx5dr_table_get_id(tbl); - - if (next_ft) { - err = set_miss_action(ns, ft, next_ft); - if (err) { - mlx5dr_table_destroy(tbl); - ft->fs_dr_table.dr_table = NULL; - return err; - } - } - - ft->max_fte = INT_MAX; - - return 0; -} - -static int mlx5_cmd_dr_destroy_flow_table(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft) -{ - struct mlx5dr_action *action = ft->fs_dr_table.miss_action; - int err; - - if (mlx5_fs_cmd_is_fw_term_table(ft)) - return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_table(ns, ft); - - err = mlx5dr_table_destroy(ft->fs_dr_table.dr_table); - if (err) { - mlx5_core_err(ns->dev, "Failed to destroy flow_table (%d)\n", - err); - return err; - } - if (action) { - err = mlx5dr_action_destroy(action); - if (err) { - mlx5_core_err(ns->dev, "Failed to destroy action(%d)\n", - err); - return err; - } - } - - return err; -} - -static int mlx5_cmd_dr_modify_flow_table(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - struct mlx5_flow_table *next_ft) -{ - if (mlx5_fs_cmd_is_fw_term_table(ft)) - return mlx5_fs_cmd_get_fw_cmds()->modify_flow_table(ns, ft, next_ft); - - return set_miss_action(ns, ft, next_ft); -} - -static int mlx5_cmd_dr_create_flow_group(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - u32 *in, - struct mlx5_flow_group *fg) -{ - struct mlx5dr_matcher *matcher; - u32 priority = MLX5_GET(create_flow_group_in, in, - start_flow_index); - u8 match_criteria_enable = MLX5_GET(create_flow_group_in, - in, - match_criteria_enable); - struct mlx5dr_match_parameters mask; - - if (mlx5_fs_cmd_is_fw_term_table(ft)) - return mlx5_fs_cmd_get_fw_cmds()->create_flow_group(ns, ft, in, - fg); - - mask.match_buf = MLX5_ADDR_OF(create_flow_group_in, - in, match_criteria); - mask.match_sz = sizeof(fg->mask.match_criteria); - - matcher = mlx5dr_matcher_create(ft->fs_dr_table.dr_table, - priority, - match_criteria_enable, - &mask); - if (!matcher) { - mlx5_core_err(ns->dev, "Failed creating matcher\n"); - return -EINVAL; - } - - fg->fs_dr_matcher.dr_matcher = matcher; - return 0; -} - -static int mlx5_cmd_dr_destroy_flow_group(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - struct mlx5_flow_group *fg) -{ - if (mlx5_fs_cmd_is_fw_term_table(ft)) - return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_group(ns, ft, fg); - - return mlx5dr_matcher_destroy(fg->fs_dr_matcher.dr_matcher); -} - -static struct mlx5dr_action *create_vport_action(struct mlx5dr_domain *domain, - struct mlx5_flow_rule *dst) -{ - struct mlx5_flow_destination *dest_attr = &dst->dest_attr; - - return mlx5dr_action_create_dest_vport(domain, dest_attr->vport.num, - dest_attr->vport.flags & - MLX5_FLOW_DEST_VPORT_VHCA_ID, - dest_attr->vport.vhca_id); -} - -static struct mlx5dr_action *create_uplink_action(struct mlx5dr_domain *domain, - struct mlx5_flow_rule *dst) -{ - struct mlx5_flow_destination *dest_attr = &dst->dest_attr; - - return mlx5dr_action_create_dest_vport(domain, MLX5_VPORT_UPLINK, 1, - dest_attr->vport.vhca_id); -} - -static struct mlx5dr_action *create_ft_action(struct mlx5dr_domain *domain, - struct mlx5_flow_rule *dst) -{ - struct mlx5_flow_table *dest_ft = dst->dest_attr.ft; - struct mlx5dr_action *tbl_action; - - if (mlx5dr_is_fw_table(dest_ft)) - return mlx5dr_action_create_dest_flow_fw_table(domain, dest_ft); - - tbl_action = mlx5dr_action_create_dest_table(dest_ft->fs_dr_table.dr_table); - if (tbl_action) - tbl_action->dest_tbl->is_wire_ft = - dest_ft->flags & MLX5_FLOW_TABLE_UPLINK_VPORT ? 1 : 0; - - return tbl_action; -} - -static struct mlx5dr_action *create_range_action(struct mlx5dr_domain *domain, - struct mlx5_flow_rule *dst) -{ - return mlx5dr_action_create_dest_match_range(domain, - dst->dest_attr.range.field, - dst->dest_attr.range.hit_ft, - dst->dest_attr.range.miss_ft, - dst->dest_attr.range.min, - dst->dest_attr.range.max); -} - -static struct mlx5dr_action *create_action_push_vlan(struct mlx5dr_domain *domain, - struct mlx5_fs_vlan *vlan) -{ - u16 n_ethtype = vlan->ethtype; - u8 prio = vlan->prio; - u16 vid = vlan->vid; - u32 vlan_hdr; - - vlan_hdr = (u32)n_ethtype << 16 | (u32)(prio) << 12 | (u32)vid; - return mlx5dr_action_create_push_vlan(domain, htonl(vlan_hdr)); -} - -static bool contain_vport_reformat_action(struct mlx5_flow_rule *dst) -{ - return (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_VPORT || - dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_UPLINK) && - dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID; -} - -/* We want to support a rule with 32 destinations, which means we need to - * account for 32 destinations plus usually a counter plus one more action - * for a multi-destination flow table. - */ -#define MLX5_FLOW_CONTEXT_ACTION_MAX 34 -static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - struct mlx5_flow_group *group, - struct fs_fte *fte) -{ - struct mlx5dr_domain *domain = ns->fs_dr_domain.dr_domain; - struct mlx5dr_action_dest *term_actions; - struct mlx5dr_match_parameters params; - struct mlx5_core_dev *dev = ns->dev; - struct mlx5dr_action **fs_dr_actions; - struct mlx5dr_action *tmp_action; - struct mlx5dr_action **actions; - bool delay_encap_set = false; - struct mlx5dr_rule *rule; - struct mlx5_flow_rule *dst; - int fs_dr_num_actions = 0; - int num_term_actions = 0; - int num_actions = 0; - size_t match_sz; - int err = 0; - int i; - - if (mlx5_fs_cmd_is_fw_term_table(ft)) - return mlx5_fs_cmd_get_fw_cmds()->create_fte(ns, ft, group, fte); - - actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, sizeof(*actions), - GFP_KERNEL); - if (!actions) { - err = -ENOMEM; - goto out_err; - } - - fs_dr_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, - sizeof(*fs_dr_actions), GFP_KERNEL); - if (!fs_dr_actions) { - err = -ENOMEM; - goto free_actions_alloc; - } - - term_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, - sizeof(*term_actions), GFP_KERNEL); - if (!term_actions) { - err = -ENOMEM; - goto free_fs_dr_actions_alloc; - } - - match_sz = sizeof(fte->val); - - /* Drop reformat action bit if destination vport set with reformat */ - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { - list_for_each_entry(dst, &fte->node.children, node.list) { - if (!contain_vport_reformat_action(dst)) - continue; - - fte->act_dests.action.action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; - break; - } - } - - /* The order of the actions are must to be keep, only the following - * order is supported by SW steering: - * TX: modify header -> push vlan -> encap - * RX: decap -> pop vlan -> modify header - */ - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) { - enum mlx5dr_action_reformat_type decap_type = - DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2; - - tmp_action = mlx5dr_action_create_packet_reformat(domain, - decap_type, - 0, 0, 0, - NULL); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { - bool is_decap; - - if (fte->act_dests.action.pkt_reformat->owner == MLX5_FLOW_RESOURCE_OWNER_FW) { - err = -EINVAL; - mlx5dr_err(domain, "FW-owned reformat can't be used in SW rule\n"); - goto free_actions; - } - - is_decap = fte->act_dests.action.pkt_reformat->reformat_type == - MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2; - - if (is_decap) - actions[num_actions++] = - fte->act_dests.action.pkt_reformat->action.dr_action; - else - delay_encap_set = true; - } - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) { - tmp_action = - mlx5dr_action_create_pop_vlan(); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP_2) { - tmp_action = - mlx5dr_action_create_pop_vlan(); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) - actions[num_actions++] = - fte->act_dests.action.modify_hdr->action.dr_action; - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) { - tmp_action = create_action_push_vlan(domain, &fte->act_dests.action.vlan[0]); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) { - tmp_action = create_action_push_vlan(domain, &fte->act_dests.action.vlan[1]); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - - if (delay_encap_set) - actions[num_actions++] = - fte->act_dests.action.pkt_reformat->action.dr_action; - - /* The order of the actions below is not important */ - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_DROP) { - tmp_action = mlx5dr_action_create_drop(); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - term_actions[num_term_actions++].dest = tmp_action; - } - - if (fte->act_dests.flow_context.flow_tag) { - tmp_action = - mlx5dr_action_create_tag(fte->act_dests.flow_context.flow_tag); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { - list_for_each_entry(dst, &fte->node.children, node.list) { - enum mlx5_flow_destination_type type = dst->dest_attr.type; - u32 id; - - if (fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || - num_term_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { - err = -EOPNOTSUPP; - goto free_actions; - } - - if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) - continue; - - switch (type) { - case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: - tmp_action = create_ft_action(domain, dst); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - term_actions[num_term_actions++].dest = tmp_action; - break; - case MLX5_FLOW_DESTINATION_TYPE_UPLINK: - case MLX5_FLOW_DESTINATION_TYPE_VPORT: - tmp_action = type == MLX5_FLOW_DESTINATION_TYPE_VPORT ? - create_vport_action(domain, dst) : - create_uplink_action(domain, dst); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - term_actions[num_term_actions].dest = tmp_action; - - if (dst->dest_attr.vport.flags & - MLX5_FLOW_DEST_VPORT_REFORMAT_ID) - term_actions[num_term_actions].reformat = - dst->dest_attr.vport.pkt_reformat->action.dr_action; - - num_term_actions++; - break; - case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: - id = dst->dest_attr.ft_num; - tmp_action = mlx5dr_action_create_dest_table_num(domain, - id); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - term_actions[num_term_actions++].dest = tmp_action; - break; - case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER: - id = dst->dest_attr.sampler_id; - tmp_action = mlx5dr_action_create_flow_sampler(domain, - id); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - term_actions[num_term_actions++].dest = tmp_action; - break; - case MLX5_FLOW_DESTINATION_TYPE_RANGE: - tmp_action = create_range_action(domain, dst); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - term_actions[num_term_actions++].dest = tmp_action; - break; - default: - err = -EOPNOTSUPP; - goto free_actions; - } - } - } - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { - list_for_each_entry(dst, &fte->node.children, node.list) { - u32 id; - - if (dst->dest_attr.type != - MLX5_FLOW_DESTINATION_TYPE_COUNTER) - continue; - - if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || - fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { - err = -EOPNOTSUPP; - goto free_actions; - } - - id = dst->dest_attr.counter_id; - tmp_action = - mlx5dr_action_create_flow_counter(id); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - } - - if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) { - struct mlx5_flow_act *action = &fte->act_dests.action; - - if (fte->act_dests.action.exe_aso.type != MLX5_EXE_ASO_FLOW_METER) { - err = -EOPNOTSUPP; - goto free_actions; - } - - tmp_action = - mlx5dr_action_create_aso(domain, - action->exe_aso.object_id, - action->exe_aso.return_reg_id, - action->exe_aso.type, - action->exe_aso.flow_meter.init_color, - action->exe_aso.flow_meter.meter_idx); - if (!tmp_action) { - err = -ENOMEM; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - - params.match_sz = match_sz; - params.match_buf = (u64 *)fte->val; - if (num_term_actions == 1) { - if (term_actions->reformat) { - if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { - err = -EOPNOTSUPP; - goto free_actions; - } - actions[num_actions++] = term_actions->reformat; - } - - if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { - err = -EOPNOTSUPP; - goto free_actions; - } - actions[num_actions++] = term_actions->dest; - } else if (num_term_actions > 1) { - bool ignore_flow_level = - !!(fte->act_dests.action.flags & FLOW_ACT_IGNORE_FLOW_LEVEL); - u32 flow_source = fte->act_dests.flow_context.flow_source; - - if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || - fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { - err = -EOPNOTSUPP; - goto free_actions; - } - tmp_action = mlx5dr_action_create_mult_dest_tbl(domain, - term_actions, - num_term_actions, - ignore_flow_level, - flow_source); - if (!tmp_action) { - err = -EOPNOTSUPP; - goto free_actions; - } - fs_dr_actions[fs_dr_num_actions++] = tmp_action; - actions[num_actions++] = tmp_action; - } - - rule = mlx5dr_rule_create(group->fs_dr_matcher.dr_matcher, - ¶ms, - num_actions, - actions, - fte->act_dests.flow_context.flow_source); - if (!rule) { - err = -EINVAL; - goto free_actions; - } - - kfree(term_actions); - kfree(actions); - - fte->fs_dr_rule.dr_rule = rule; - fte->fs_dr_rule.num_actions = fs_dr_num_actions; - fte->fs_dr_rule.dr_actions = fs_dr_actions; - - return 0; - -free_actions: - /* Free in reverse order to handle action dependencies */ - for (i = fs_dr_num_actions - 1; i >= 0; i--) - if (!IS_ERR_OR_NULL(fs_dr_actions[i])) - mlx5dr_action_destroy(fs_dr_actions[i]); - - kfree(term_actions); -free_fs_dr_actions_alloc: - kfree(fs_dr_actions); -free_actions_alloc: - kfree(actions); -out_err: - mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err); - return err; -} - -static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns, - struct mlx5_pkt_reformat_params *params, - enum mlx5_flow_namespace_type namespace, - struct mlx5_pkt_reformat *pkt_reformat) -{ - struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain; - struct mlx5dr_action *action; - int dr_reformat; - - switch (params->type) { - case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: - case MLX5_REFORMAT_TYPE_L2_TO_NVGRE: - case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL: - dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2; - break; - case MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2: - dr_reformat = DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2; - break; - case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL: - dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3; - break; - case MLX5_REFORMAT_TYPE_INSERT_HDR: - dr_reformat = DR_ACTION_REFORMAT_TYP_INSERT_HDR; - break; - case MLX5_REFORMAT_TYPE_REMOVE_HDR: - dr_reformat = DR_ACTION_REFORMAT_TYP_REMOVE_HDR; - break; - default: - mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n", - params->type); - return -EOPNOTSUPP; - } - - action = mlx5dr_action_create_packet_reformat(dr_domain, - dr_reformat, - params->param_0, - params->param_1, - params->size, - params->data); - if (!action) { - mlx5_core_err(ns->dev, "Failed allocating packet-reformat action\n"); - return -EINVAL; - } - - pkt_reformat->owner = MLX5_FLOW_RESOURCE_OWNER_SW; - pkt_reformat->action.dr_action = action; - - return 0; -} - -static void mlx5_cmd_dr_packet_reformat_dealloc(struct mlx5_flow_root_namespace *ns, - struct mlx5_pkt_reformat *pkt_reformat) -{ - mlx5dr_action_destroy(pkt_reformat->action.dr_action); -} - -static int mlx5_cmd_dr_modify_header_alloc(struct mlx5_flow_root_namespace *ns, - u8 namespace, u8 num_actions, - void *modify_actions, - struct mlx5_modify_hdr *modify_hdr) -{ - struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain; - struct mlx5dr_action *action; - size_t actions_sz; - - actions_sz = MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) * - num_actions; - action = mlx5dr_action_create_modify_header(dr_domain, 0, - actions_sz, - modify_actions); - if (!action) { - mlx5_core_err(ns->dev, "Failed allocating modify-header action\n"); - return -EINVAL; - } - - modify_hdr->owner = MLX5_FLOW_RESOURCE_OWNER_SW; - modify_hdr->action.dr_action = action; - - return 0; -} - -static void mlx5_cmd_dr_modify_header_dealloc(struct mlx5_flow_root_namespace *ns, - struct mlx5_modify_hdr *modify_hdr) -{ - mlx5dr_action_destroy(modify_hdr->action.dr_action); -} - -static int -mlx5_cmd_dr_destroy_match_definer(struct mlx5_flow_root_namespace *ns, - int definer_id) -{ - return -EOPNOTSUPP; -} - -static int mlx5_cmd_dr_create_match_definer(struct mlx5_flow_root_namespace *ns, - u16 format_id, u32 *match_mask) -{ - return -EOPNOTSUPP; -} - -static int mlx5_cmd_dr_delete_fte(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - struct fs_fte *fte) -{ - struct mlx5_fs_dr_rule *rule = &fte->fs_dr_rule; - int err; - int i; - - if (mlx5_fs_cmd_is_fw_term_table(ft)) - return mlx5_fs_cmd_get_fw_cmds()->delete_fte(ns, ft, fte); - - err = mlx5dr_rule_destroy(rule->dr_rule); - if (err) - return err; - - /* Free in reverse order to handle action dependencies */ - for (i = rule->num_actions - 1; i >= 0; i--) - if (!IS_ERR_OR_NULL(rule->dr_actions[i])) - mlx5dr_action_destroy(rule->dr_actions[i]); - - kfree(rule->dr_actions); - return 0; -} - -static int mlx5_cmd_dr_update_fte(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_table *ft, - struct mlx5_flow_group *group, - int modify_mask, - struct fs_fte *fte) -{ - struct fs_fte fte_tmp = {}; - int ret; - - if (mlx5_fs_cmd_is_fw_term_table(ft)) - return mlx5_fs_cmd_get_fw_cmds()->update_fte(ns, ft, group, modify_mask, fte); - - /* Backup current dr rule details */ - fte_tmp.fs_dr_rule = fte->fs_dr_rule; - memset(&fte->fs_dr_rule, 0, sizeof(struct mlx5_fs_dr_rule)); - - /* First add the new updated rule, then delete the old rule */ - ret = mlx5_cmd_dr_create_fte(ns, ft, group, fte); - if (ret) - goto restore_fte; - - ret = mlx5_cmd_dr_delete_fte(ns, ft, &fte_tmp); - WARN_ONCE(ret, "dr update fte duplicate rule deletion failed\n"); - return ret; - -restore_fte: - fte->fs_dr_rule = fte_tmp.fs_dr_rule; - return ret; -} - -static int mlx5_cmd_dr_set_peer(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_root_namespace *peer_ns, - u16 peer_vhca_id) -{ - struct mlx5dr_domain *peer_domain = NULL; - - if (peer_ns) - peer_domain = peer_ns->fs_dr_domain.dr_domain; - mlx5dr_domain_set_peer(ns->fs_dr_domain.dr_domain, - peer_domain, peer_vhca_id); - return 0; -} - -static int mlx5_cmd_dr_create_ns(struct mlx5_flow_root_namespace *ns) -{ - ns->fs_dr_domain.dr_domain = - mlx5dr_domain_create(ns->dev, - MLX5DR_DOMAIN_TYPE_FDB); - if (!ns->fs_dr_domain.dr_domain) { - mlx5_core_err(ns->dev, "Failed to create dr flow namespace\n"); - return -EOPNOTSUPP; - } - return 0; -} - -static int mlx5_cmd_dr_destroy_ns(struct mlx5_flow_root_namespace *ns) -{ - return mlx5dr_domain_destroy(ns->fs_dr_domain.dr_domain); -} - -static u32 mlx5_cmd_dr_get_capabilities(struct mlx5_flow_root_namespace *ns, - enum fs_flow_table_type ft_type) -{ - u32 steering_caps = MLX5_FLOW_STEERING_CAP_DUPLICATE_MATCH; - - if (ft_type != FS_FT_FDB || - MLX5_CAP_GEN(ns->dev, steering_format_version) == MLX5_STEERING_FORMAT_CONNECTX_5) - return steering_caps; - - steering_caps |= MLX5_FLOW_STEERING_CAP_VLAN_PUSH_ON_RX; - steering_caps |= MLX5_FLOW_STEERING_CAP_VLAN_POP_ON_TX; - - if (mlx5dr_supp_match_ranges(ns->dev)) - steering_caps |= MLX5_FLOW_STEERING_CAP_MATCH_RANGES; - - return steering_caps; -} - -int mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat) -{ - switch (pkt_reformat->reformat_type) { - case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: - case MLX5_REFORMAT_TYPE_L2_TO_NVGRE: - case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL: - case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL: - case MLX5_REFORMAT_TYPE_INSERT_HDR: - return mlx5dr_action_get_pkt_reformat_id(pkt_reformat->action.dr_action); - } - return -EOPNOTSUPP; -} - -bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev) -{ - return mlx5dr_is_supported(dev); -} - -static const struct mlx5_flow_cmds mlx5_flow_cmds_dr = { - .create_flow_table = mlx5_cmd_dr_create_flow_table, - .destroy_flow_table = mlx5_cmd_dr_destroy_flow_table, - .modify_flow_table = mlx5_cmd_dr_modify_flow_table, - .create_flow_group = mlx5_cmd_dr_create_flow_group, - .destroy_flow_group = mlx5_cmd_dr_destroy_flow_group, - .create_fte = mlx5_cmd_dr_create_fte, - .update_fte = mlx5_cmd_dr_update_fte, - .delete_fte = mlx5_cmd_dr_delete_fte, - .update_root_ft = mlx5_cmd_dr_update_root_ft, - .packet_reformat_alloc = mlx5_cmd_dr_packet_reformat_alloc, - .packet_reformat_dealloc = mlx5_cmd_dr_packet_reformat_dealloc, - .modify_header_alloc = mlx5_cmd_dr_modify_header_alloc, - .modify_header_dealloc = mlx5_cmd_dr_modify_header_dealloc, - .create_match_definer = mlx5_cmd_dr_create_match_definer, - .destroy_match_definer = mlx5_cmd_dr_destroy_match_definer, - .set_peer = mlx5_cmd_dr_set_peer, - .create_ns = mlx5_cmd_dr_create_ns, - .destroy_ns = mlx5_cmd_dr_destroy_ns, - .get_capabilities = mlx5_cmd_dr_get_capabilities, -}; - -const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void) -{ - return &mlx5_flow_cmds_dr; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.h deleted file mode 100644 index 99a3b2eff6b8fd..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB - * Copyright (c) 2019 Mellanox Technologies - */ - -#ifndef _MLX5_FS_DR_ -#define _MLX5_FS_DR_ - -#include "mlx5dr.h" - -struct mlx5_flow_root_namespace; -struct fs_fte; - -struct mlx5_fs_dr_action { - struct mlx5dr_action *dr_action; -}; - -struct mlx5_fs_dr_rule { - struct mlx5dr_rule *dr_rule; - /* Only actions created by fs_dr */ - struct mlx5dr_action **dr_actions; - int num_actions; -}; - -struct mlx5_fs_dr_domain { - struct mlx5dr_domain *dr_domain; -}; - -struct mlx5_fs_dr_matcher { - struct mlx5dr_matcher *dr_matcher; -}; - -struct mlx5_fs_dr_table { - struct mlx5dr_table *dr_table; - struct mlx5dr_action *miss_action; -}; - -#ifdef CONFIG_MLX5_SW_STEERING - -bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev); - -int mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat); - -const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void); - -#else - -static inline const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void) -{ - return NULL; -} - -static inline u32 mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat) -{ - return 0; -} - -static inline bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev) -{ - return false; -} - -#endif /* CONFIG_MLX5_SW_STEERING */ -#endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c new file mode 100644 index 00000000000000..a897cdc60fdbd4 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c @@ -0,0 +1,2604 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +#define MLX5HWS_ACTION_METER_INIT_COLOR_OFFSET 1 + +/* Header removal size limited to 128B (64 words) */ +#define MLX5HWS_ACTION_REMOVE_HEADER_MAX_SIZE 128 + +/* This is the longest supported action sequence for FDB table: + * DECAP, POP_VLAN, MODIFY, CTR, ASO, PUSH_VLAN, MODIFY, ENCAP, Term. + */ +static const u32 action_order_arr[MLX5HWS_TABLE_TYPE_MAX][MLX5HWS_ACTION_TYP_MAX] = { + [MLX5HWS_TABLE_TYPE_FDB] = { + BIT(MLX5HWS_ACTION_TYP_REMOVE_HEADER) | + BIT(MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2) | + BIT(MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2), + BIT(MLX5HWS_ACTION_TYP_POP_VLAN), + BIT(MLX5HWS_ACTION_TYP_POP_VLAN), + BIT(MLX5HWS_ACTION_TYP_MODIFY_HDR), + BIT(MLX5HWS_ACTION_TYP_PUSH_VLAN), + BIT(MLX5HWS_ACTION_TYP_PUSH_VLAN), + BIT(MLX5HWS_ACTION_TYP_INSERT_HEADER) | + BIT(MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) | + BIT(MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3), + BIT(MLX5HWS_ACTION_TYP_CTR), + BIT(MLX5HWS_ACTION_TYP_TAG), + BIT(MLX5HWS_ACTION_TYP_ASO_METER), + BIT(MLX5HWS_ACTION_TYP_MODIFY_HDR), + BIT(MLX5HWS_ACTION_TYP_TBL) | + BIT(MLX5HWS_ACTION_TYP_VPORT) | + BIT(MLX5HWS_ACTION_TYP_DROP) | + BIT(MLX5HWS_ACTION_TYP_SAMPLER) | + BIT(MLX5HWS_ACTION_TYP_RANGE) | + BIT(MLX5HWS_ACTION_TYP_DEST_ARRAY), + BIT(MLX5HWS_ACTION_TYP_LAST), + }, +}; + +static const char * const mlx5hws_action_type_str[] = { + [MLX5HWS_ACTION_TYP_LAST] = "LAST", + [MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2] = "TNL_L2_TO_L2", + [MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2] = "L2_TO_TNL_L2", + [MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2] = "TNL_L3_TO_L2", + [MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3] = "L2_TO_TNL_L3", + [MLX5HWS_ACTION_TYP_DROP] = "DROP", + [MLX5HWS_ACTION_TYP_TBL] = "TBL", + [MLX5HWS_ACTION_TYP_CTR] = "CTR", + [MLX5HWS_ACTION_TYP_TAG] = "TAG", + [MLX5HWS_ACTION_TYP_MODIFY_HDR] = "MODIFY_HDR", + [MLX5HWS_ACTION_TYP_VPORT] = "VPORT", + [MLX5HWS_ACTION_TYP_MISS] = "DEFAULT_MISS", + [MLX5HWS_ACTION_TYP_POP_VLAN] = "POP_VLAN", + [MLX5HWS_ACTION_TYP_PUSH_VLAN] = "PUSH_VLAN", + [MLX5HWS_ACTION_TYP_ASO_METER] = "ASO_METER", + [MLX5HWS_ACTION_TYP_DEST_ARRAY] = "DEST_ARRAY", + [MLX5HWS_ACTION_TYP_INSERT_HEADER] = "INSERT_HEADER", + [MLX5HWS_ACTION_TYP_REMOVE_HEADER] = "REMOVE_HEADER", + [MLX5HWS_ACTION_TYP_SAMPLER] = "SAMPLER", + [MLX5HWS_ACTION_TYP_RANGE] = "RANGE", +}; + +static_assert(ARRAY_SIZE(mlx5hws_action_type_str) == MLX5HWS_ACTION_TYP_MAX, + "Missing mlx5hws_action_type_str"); + +const char *mlx5hws_action_type_to_str(enum mlx5hws_action_type action_type) +{ + return mlx5hws_action_type_str[action_type]; +} + +enum mlx5hws_action_type mlx5hws_action_get_type(struct mlx5hws_action *action) +{ + return action->type; +} + +static int hws_action_get_shared_stc_nic(struct mlx5hws_context *ctx, + enum mlx5hws_context_shared_stc_type stc_type, + u8 tbl_type) +{ + struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; + struct mlx5hws_action_shared_stc *shared_stc; + int ret; + + mutex_lock(&ctx->ctrl_lock); + if (ctx->common_res[tbl_type].shared_stc[stc_type]) { + ctx->common_res[tbl_type].shared_stc[stc_type]->refcount++; + mutex_unlock(&ctx->ctrl_lock); + return 0; + } + + shared_stc = kzalloc(sizeof(*shared_stc), GFP_KERNEL); + if (!shared_stc) { + ret = -ENOMEM; + goto unlock_and_out; + } + switch (stc_type) { + case MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3: + stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW5; + stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; + stc_attr.remove_header.decap = 0; + stc_attr.remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START; + stc_attr.remove_header.end_anchor = MLX5_HEADER_ANCHOR_IPV6_IPV4; + break; + case MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP: + stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW5; + stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; + stc_attr.remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START; + stc_attr.remove_words.num_of_words = MLX5HWS_ACTION_HDR_LEN_L2_VLAN; + break; + default: + mlx5hws_err(ctx, "No such stc_type: %d\n", stc_type); + pr_warn("HWS: Invalid stc_type: %d\n", stc_type); + ret = -EINVAL; + goto unlock_and_out; + } + + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, + &shared_stc->stc_chunk); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate shared decap l2 STC\n"); + goto free_shared_stc; + } + + ctx->common_res[tbl_type].shared_stc[stc_type] = shared_stc; + ctx->common_res[tbl_type].shared_stc[stc_type]->refcount = 1; + + mutex_unlock(&ctx->ctrl_lock); + + return 0; + +free_shared_stc: + kfree(shared_stc); +unlock_and_out: + mutex_unlock(&ctx->ctrl_lock); + return ret; +} + +static int hws_action_get_shared_stc(struct mlx5hws_action *action, + enum mlx5hws_context_shared_stc_type stc_type) +{ + struct mlx5hws_context *ctx = action->ctx; + int ret; + + if (stc_type >= MLX5HWS_CONTEXT_SHARED_STC_MAX) { + pr_warn("HWS: Invalid shared stc_type: %d\n", stc_type); + return -EINVAL; + } + + if (unlikely(!(action->flags & MLX5HWS_ACTION_FLAG_HWS_FDB))) { + pr_warn("HWS: Invalid action->flags: %d\n", action->flags); + return -EINVAL; + } + + ret = hws_action_get_shared_stc_nic(ctx, stc_type, MLX5HWS_TABLE_TYPE_FDB); + if (ret) { + mlx5hws_err(ctx, + "Failed to allocate memory for FDB shared STCs (type: %d)\n", + stc_type); + return ret; + } + + return 0; +} + +static void hws_action_put_shared_stc(struct mlx5hws_action *action, + enum mlx5hws_context_shared_stc_type stc_type) +{ + enum mlx5hws_table_type tbl_type = MLX5HWS_TABLE_TYPE_FDB; + struct mlx5hws_action_shared_stc *shared_stc; + struct mlx5hws_context *ctx = action->ctx; + + if (stc_type >= MLX5HWS_CONTEXT_SHARED_STC_MAX) { + pr_warn("HWS: Invalid shared stc_type: %d\n", stc_type); + return; + } + + mutex_lock(&ctx->ctrl_lock); + if (--ctx->common_res[tbl_type].shared_stc[stc_type]->refcount) { + mutex_unlock(&ctx->ctrl_lock); + return; + } + + shared_stc = ctx->common_res[tbl_type].shared_stc[stc_type]; + + mlx5hws_action_free_single_stc(ctx, tbl_type, &shared_stc->stc_chunk); + kfree(shared_stc); + ctx->common_res[tbl_type].shared_stc[stc_type] = NULL; + mutex_unlock(&ctx->ctrl_lock); +} + +static void hws_action_print_combo(struct mlx5hws_context *ctx, + enum mlx5hws_action_type *user_actions) +{ + mlx5hws_err(ctx, "Invalid action_type sequence"); + while (*user_actions != MLX5HWS_ACTION_TYP_LAST) { + mlx5hws_err(ctx, " %s", mlx5hws_action_type_to_str(*user_actions)); + user_actions++; + } + mlx5hws_err(ctx, "\n"); +} + +bool mlx5hws_action_check_combo(struct mlx5hws_context *ctx, + enum mlx5hws_action_type *user_actions, + enum mlx5hws_table_type table_type) +{ + const u32 *order_arr = action_order_arr[table_type]; + u8 order_idx = 0; + u8 user_idx = 0; + bool valid_combo; + + if (table_type >= MLX5HWS_TABLE_TYPE_MAX) { + mlx5hws_err(ctx, "Invalid table_type %d", table_type); + return false; + } + + while (order_arr[order_idx] != BIT(MLX5HWS_ACTION_TYP_LAST)) { + /* User action order validated move to next user action */ + if (BIT(user_actions[user_idx]) & order_arr[order_idx]) + user_idx++; + + /* Iterate to the next supported action in the order */ + order_idx++; + } + + /* Combination is valid if all user action were processed */ + valid_combo = user_actions[user_idx] == MLX5HWS_ACTION_TYP_LAST; + if (!valid_combo) + hws_action_print_combo(ctx, user_actions); + + return valid_combo; +} + +static bool +hws_action_fixup_stc_attr(struct mlx5hws_context *ctx, + struct mlx5hws_cmd_stc_modify_attr *stc_attr, + struct mlx5hws_cmd_stc_modify_attr *fixup_stc_attr, + enum mlx5hws_table_type table_type, + bool is_mirror) +{ + bool use_fixup = false; + u32 fw_tbl_type; + u32 base_id; + + fw_tbl_type = mlx5hws_table_get_res_fw_ft_type(table_type, is_mirror); + + switch (stc_attr->action_type) { + case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE: + if (is_mirror && stc_attr->ste_table.ignore_tx) { + fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; + fixup_stc_attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; + fixup_stc_attr->stc_offset = stc_attr->stc_offset; + use_fixup = true; + break; + } + if (!is_mirror) + base_id = mlx5hws_pool_chunk_get_base_id(stc_attr->ste_table.ste_pool, + &stc_attr->ste_table.ste); + else + base_id = + mlx5hws_pool_chunk_get_base_mirror_id(stc_attr->ste_table.ste_pool, + &stc_attr->ste_table.ste); + + *fixup_stc_attr = *stc_attr; + fixup_stc_attr->ste_table.ste_obj_id = base_id; + use_fixup = true; + break; + + case MLX5_IFC_STC_ACTION_TYPE_TAG: + if (fw_tbl_type == FS_FT_FDB_TX) { + fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_NOP; + fixup_stc_attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; + fixup_stc_attr->stc_offset = stc_attr->stc_offset; + use_fixup = true; + } + break; + + case MLX5_IFC_STC_ACTION_TYPE_ALLOW: + if (fw_tbl_type == FS_FT_FDB_TX || fw_tbl_type == FS_FT_FDB_RX) { + fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT; + fixup_stc_attr->action_offset = stc_attr->action_offset; + fixup_stc_attr->stc_offset = stc_attr->stc_offset; + fixup_stc_attr->vport.esw_owner_vhca_id = ctx->caps->vhca_id; + fixup_stc_attr->vport.vport_num = ctx->caps->eswitch_manager_vport_number; + fixup_stc_attr->vport.eswitch_owner_vhca_id_valid = + ctx->caps->merged_eswitch; + use_fixup = true; + } + break; + + case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT: + if (stc_attr->vport.vport_num != MLX5_VPORT_UPLINK) + break; + + if (fw_tbl_type == FS_FT_FDB_TX || fw_tbl_type == FS_FT_FDB_RX) { + /* The FW doesn't allow to go to wire in the TX/RX by JUMP_TO_VPORT */ + fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK; + fixup_stc_attr->action_offset = stc_attr->action_offset; + fixup_stc_attr->stc_offset = stc_attr->stc_offset; + fixup_stc_attr->vport.vport_num = 0; + fixup_stc_attr->vport.esw_owner_vhca_id = stc_attr->vport.esw_owner_vhca_id; + fixup_stc_attr->vport.eswitch_owner_vhca_id_valid = + stc_attr->vport.eswitch_owner_vhca_id_valid; + } + use_fixup = true; + break; + + default: + break; + } + + return use_fixup; +} + +int mlx5hws_action_alloc_single_stc(struct mlx5hws_context *ctx, + struct mlx5hws_cmd_stc_modify_attr *stc_attr, + u32 table_type, + struct mlx5hws_pool_chunk *stc) +__must_hold(&ctx->ctrl_lock) +{ + struct mlx5hws_cmd_stc_modify_attr cleanup_stc_attr = {0}; + struct mlx5hws_pool *stc_pool = ctx->stc_pool[table_type]; + struct mlx5hws_cmd_stc_modify_attr fixup_stc_attr = {0}; + bool use_fixup; + u32 obj_0_id; + int ret; + + ret = mlx5hws_pool_chunk_alloc(stc_pool, stc); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate single action STC\n"); + return ret; + } + + stc_attr->stc_offset = stc->offset; + + /* Dynamic reparse not supported, overwrite and use default */ + if (!mlx5hws_context_cap_dynamic_reparse(ctx)) + stc_attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; + + obj_0_id = mlx5hws_pool_chunk_get_base_id(stc_pool, stc); + + /* According to table/action limitation change the stc_attr */ + use_fixup = hws_action_fixup_stc_attr(ctx, stc_attr, &fixup_stc_attr, table_type, false); + ret = mlx5hws_cmd_stc_modify(ctx->mdev, obj_0_id, + use_fixup ? &fixup_stc_attr : stc_attr); + if (ret) { + mlx5hws_err(ctx, "Failed to modify STC action_type %d tbl_type %d\n", + stc_attr->action_type, table_type); + goto free_chunk; + } + + /* Modify the FDB peer */ + if (table_type == MLX5HWS_TABLE_TYPE_FDB) { + u32 obj_1_id; + + obj_1_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, stc); + + use_fixup = hws_action_fixup_stc_attr(ctx, stc_attr, + &fixup_stc_attr, + table_type, true); + ret = mlx5hws_cmd_stc_modify(ctx->mdev, obj_1_id, + use_fixup ? &fixup_stc_attr : stc_attr); + if (ret) { + mlx5hws_err(ctx, + "Failed to modify peer STC action_type %d tbl_type %d\n", + stc_attr->action_type, table_type); + goto clean_obj_0; + } + } + + return 0; + +clean_obj_0: + cleanup_stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; + cleanup_stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; + cleanup_stc_attr.stc_offset = stc->offset; + mlx5hws_cmd_stc_modify(ctx->mdev, obj_0_id, &cleanup_stc_attr); +free_chunk: + mlx5hws_pool_chunk_free(stc_pool, stc); + return ret; +} + +void mlx5hws_action_free_single_stc(struct mlx5hws_context *ctx, + u32 table_type, + struct mlx5hws_pool_chunk *stc) +__must_hold(&ctx->ctrl_lock) +{ + struct mlx5hws_pool *stc_pool = ctx->stc_pool[table_type]; + struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; + u32 obj_id; + + /* Modify the STC not to point to an object */ + stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; + stc_attr.stc_offset = stc->offset; + obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, stc); + mlx5hws_cmd_stc_modify(ctx->mdev, obj_id, &stc_attr); + + if (table_type == MLX5HWS_TABLE_TYPE_FDB) { + obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, stc); + mlx5hws_cmd_stc_modify(ctx->mdev, obj_id, &stc_attr); + } + + mlx5hws_pool_chunk_free(stc_pool, stc); +} + +static u32 hws_action_get_mh_stc_type(struct mlx5hws_context *ctx, + __be64 pattern) +{ + u8 action_type = MLX5_GET(set_action_in, &pattern, action_type); + + switch (action_type) { + case MLX5_MODIFICATION_TYPE_SET: + return MLX5_IFC_STC_ACTION_TYPE_SET; + case MLX5_MODIFICATION_TYPE_ADD: + return MLX5_IFC_STC_ACTION_TYPE_ADD; + case MLX5_MODIFICATION_TYPE_COPY: + return MLX5_IFC_STC_ACTION_TYPE_COPY; + case MLX5_MODIFICATION_TYPE_ADD_FIELD: + return MLX5_IFC_STC_ACTION_TYPE_ADD_FIELD; + default: + mlx5hws_err(ctx, "Unsupported action type: 0x%x\n", action_type); + return MLX5_IFC_STC_ACTION_TYPE_NOP; + } +} + +static void hws_action_fill_stc_attr(struct mlx5hws_action *action, + u32 obj_id, + struct mlx5hws_cmd_stc_modify_attr *attr) +{ + attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; + + switch (action->type) { + case MLX5HWS_ACTION_TYP_TAG: + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_TAG; + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; + break; + case MLX5HWS_ACTION_TYP_DROP: + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; + attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; + break; + case MLX5HWS_ACTION_TYP_MISS: + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW; + attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; + break; + case MLX5HWS_ACTION_TYP_CTR: + attr->id = obj_id; + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_COUNTER; + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW0; + break; + case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: + case MLX5HWS_ACTION_TYP_MODIFY_HDR: + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW6; + attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; + if (action->modify_header.require_reparse) + attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; + + if (action->modify_header.num_of_actions == 1) { + attr->modify_action.data = action->modify_header.single_action; + attr->action_type = hws_action_get_mh_stc_type(action->ctx, + attr->modify_action.data); + + if (attr->action_type == MLX5_IFC_STC_ACTION_TYPE_ADD || + attr->action_type == MLX5_IFC_STC_ACTION_TYPE_SET) + MLX5_SET(set_action_in, &attr->modify_action.data, data, 0); + } else { + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST; + attr->modify_header.arg_id = action->modify_header.arg_id; + attr->modify_header.pattern_id = action->modify_header.pat_id; + } + break; + case MLX5HWS_ACTION_TYP_TBL: + case MLX5HWS_ACTION_TYP_DEST_ARRAY: + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT; + attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; + attr->dest_table_id = obj_id; + break; + case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; + attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; + attr->remove_header.decap = 1; + attr->remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START; + attr->remove_header.end_anchor = MLX5_HEADER_ANCHOR_INNER_MAC; + break; + case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: + case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: + case MLX5HWS_ACTION_TYP_INSERT_HEADER: + attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; + if (!action->reformat.require_reparse) + attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; + + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW6; + attr->insert_header.encap = action->reformat.encap; + attr->insert_header.insert_anchor = action->reformat.anchor; + attr->insert_header.arg_id = action->reformat.arg_id; + attr->insert_header.header_size = action->reformat.header_size; + attr->insert_header.insert_offset = action->reformat.offset; + break; + case MLX5HWS_ACTION_TYP_ASO_METER: + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW6; + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO; + attr->aso.aso_type = ASO_OPC_MOD_POLICER; + attr->aso.devx_obj_id = obj_id; + attr->aso.return_reg_id = action->aso.return_reg_id; + break; + case MLX5HWS_ACTION_TYP_VPORT: + attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT; + attr->vport.vport_num = action->vport.vport_num; + attr->vport.esw_owner_vhca_id = action->vport.esw_owner_vhca_id; + attr->vport.eswitch_owner_vhca_id_valid = action->vport.esw_owner_vhca_id_valid; + break; + case MLX5HWS_ACTION_TYP_POP_VLAN: + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; + attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; + attr->remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START; + attr->remove_words.num_of_words = MLX5HWS_ACTION_HDR_LEN_L2_VLAN / 2; + break; + case MLX5HWS_ACTION_TYP_PUSH_VLAN: + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW6; + attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; + attr->insert_header.encap = 0; + attr->insert_header.is_inline = 1; + attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START; + attr->insert_header.insert_offset = MLX5HWS_ACTION_HDR_LEN_L2_MACS; + attr->insert_header.header_size = MLX5HWS_ACTION_HDR_LEN_L2_VLAN; + break; + case MLX5HWS_ACTION_TYP_REMOVE_HEADER: + attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; + attr->remove_header.decap = 0; /* the mode we support decap is 0 */ + attr->remove_words.start_anchor = action->remove_header.anchor; + /* the size is in already in words */ + attr->remove_words.num_of_words = action->remove_header.size; + attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; + attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; + break; + default: + mlx5hws_err(action->ctx, "Invalid action type %d\n", action->type); + } +} + +static int +hws_action_create_stcs(struct mlx5hws_action *action, u32 obj_id) +{ + struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; + struct mlx5hws_context *ctx = action->ctx; + int ret; + + hws_action_fill_stc_attr(action, obj_id, &stc_attr); + + /* Block unsupported parallel obj modify over the same base */ + mutex_lock(&ctx->ctrl_lock); + + /* Allocate STC for FDB */ + if (action->flags & MLX5HWS_ACTION_FLAG_HWS_FDB) { + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, + MLX5HWS_TABLE_TYPE_FDB, + &action->stc[MLX5HWS_TABLE_TYPE_FDB]); + if (ret) + goto out_err; + } + + mutex_unlock(&ctx->ctrl_lock); + + return 0; + +out_err: + mutex_unlock(&ctx->ctrl_lock); + return ret; +} + +static void +hws_action_destroy_stcs(struct mlx5hws_action *action) +{ + struct mlx5hws_context *ctx = action->ctx; + + /* Block unsupported parallel obj modify over the same base */ + mutex_lock(&ctx->ctrl_lock); + + if (action->flags & MLX5HWS_ACTION_FLAG_HWS_FDB) + mlx5hws_action_free_single_stc(ctx, MLX5HWS_TABLE_TYPE_FDB, + &action->stc[MLX5HWS_TABLE_TYPE_FDB]); + + mutex_unlock(&ctx->ctrl_lock); +} + +static bool hws_action_is_flag_hws_fdb(u32 flags) +{ + return flags & MLX5HWS_ACTION_FLAG_HWS_FDB; +} + +static bool +hws_action_validate_hws_action(struct mlx5hws_context *ctx, u32 flags) +{ + if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) { + mlx5hws_err(ctx, "Cannot create HWS action since HWS is not supported\n"); + return false; + } + + if ((flags & MLX5HWS_ACTION_FLAG_HWS_FDB) && !ctx->caps->eswitch_manager) { + mlx5hws_err(ctx, "Cannot create HWS action for FDB for non-eswitch-manager\n"); + return false; + } + + return true; +} + +static struct mlx5hws_action * +hws_action_create_generic_bulk(struct mlx5hws_context *ctx, + u32 flags, + enum mlx5hws_action_type action_type, + u8 bulk_sz) +{ + struct mlx5hws_action *action; + int i; + + if (!hws_action_is_flag_hws_fdb(flags)) { + mlx5hws_err(ctx, + "Action (type: %d) flags must specify only HWS FDB\n", action_type); + return NULL; + } + + if (!hws_action_validate_hws_action(ctx, flags)) + return NULL; + + action = kcalloc(bulk_sz, sizeof(*action), GFP_KERNEL); + if (!action) + return NULL; + + for (i = 0; i < bulk_sz; i++) { + action[i].ctx = ctx; + action[i].flags = flags; + action[i].type = action_type; + } + + return action; +} + +static struct mlx5hws_action * +hws_action_create_generic(struct mlx5hws_context *ctx, + u32 flags, + enum mlx5hws_action_type action_type) +{ + return hws_action_create_generic_bulk(ctx, flags, action_type, 1); +} + +struct mlx5hws_action * +mlx5hws_action_create_dest_table_num(struct mlx5hws_context *ctx, + u32 table_id, + u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_TBL); + if (!action) + return NULL; + + ret = hws_action_create_stcs(action, table_id); + if (ret) + goto free_action; + + action->dest_obj.obj_id = table_id; + + return action; + +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_dest_table(struct mlx5hws_context *ctx, + struct mlx5hws_table *tbl, + u32 flags) +{ + return mlx5hws_action_create_dest_table_num(ctx, tbl->ft_id, flags); +} + +struct mlx5hws_action * +mlx5hws_action_create_dest_drop(struct mlx5hws_context *ctx, u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_DROP); + if (!action) + return NULL; + + ret = hws_action_create_stcs(action, 0); + if (ret) + goto free_action; + + return action; + +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_default_miss(struct mlx5hws_context *ctx, u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_MISS); + if (!action) + return NULL; + + ret = hws_action_create_stcs(action, 0); + if (ret) + goto free_action; + + return action; + +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_tag(struct mlx5hws_context *ctx, u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_TAG); + if (!action) + return NULL; + + ret = hws_action_create_stcs(action, 0); + if (ret) + goto free_action; + + return action; + +free_action: + kfree(action); + return NULL; +} + +static struct mlx5hws_action * +hws_action_create_aso(struct mlx5hws_context *ctx, + enum mlx5hws_action_type action_type, + u32 obj_id, + u8 return_reg_id, + u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + action = hws_action_create_generic(ctx, flags, action_type); + if (!action) + return NULL; + + action->aso.obj_id = obj_id; + action->aso.return_reg_id = return_reg_id; + + ret = hws_action_create_stcs(action, obj_id); + if (ret) + goto free_action; + + return action; + +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_aso_meter(struct mlx5hws_context *ctx, + u32 obj_id, + u8 return_reg_id, + u32 flags) +{ + return hws_action_create_aso(ctx, MLX5HWS_ACTION_TYP_ASO_METER, + obj_id, return_reg_id, flags); +} + +struct mlx5hws_action * +mlx5hws_action_create_counter(struct mlx5hws_context *ctx, + u32 obj_id, + u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_CTR); + if (!action) + return NULL; + + ret = hws_action_create_stcs(action, obj_id); + if (ret) + goto free_action; + + return action; + +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_dest_vport(struct mlx5hws_context *ctx, + u16 vport_num, + bool vhca_id_valid, + u16 vhca_id, + u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + if (!(flags & MLX5HWS_ACTION_FLAG_HWS_FDB)) { + mlx5hws_err(ctx, "Vport action is supported for FDB only\n"); + return NULL; + } + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_VPORT); + if (!action) + return NULL; + + if (!ctx->caps->merged_eswitch && vhca_id_valid && vhca_id != ctx->caps->vhca_id) { + mlx5hws_err(ctx, "Non merged eswitch cannot send to other vhca\n"); + goto free_action; + } + + action->vport.vport_num = vport_num; + action->vport.esw_owner_vhca_id_valid = vhca_id_valid; + + if (vhca_id_valid) + action->vport.esw_owner_vhca_id = vhca_id; + + ret = hws_action_create_stcs(action, 0); + if (ret) { + mlx5hws_err(ctx, "Failed creating stc for vport %d\n", vport_num); + goto free_action; + } + + return action; + +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_push_vlan(struct mlx5hws_context *ctx, u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_PUSH_VLAN); + if (!action) + return NULL; + + ret = hws_action_create_stcs(action, 0); + if (ret) { + mlx5hws_err(ctx, "Failed creating stc for push vlan\n"); + goto free_action; + } + + return action; + +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_pop_vlan(struct mlx5hws_context *ctx, u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_POP_VLAN); + if (!action) + return NULL; + + ret = hws_action_get_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP); + if (ret) { + mlx5hws_err(ctx, "Failed to create remove stc for reformat\n"); + goto free_action; + } + + ret = hws_action_create_stcs(action, 0); + if (ret) { + mlx5hws_err(ctx, "Failed creating stc for pop vlan\n"); + goto free_shared; + } + + return action; + +free_shared: + hws_action_put_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP); +free_action: + kfree(action); + return NULL; +} + +static int +hws_action_handle_insert_with_ptr(struct mlx5hws_action *action, + u8 num_of_hdrs, + struct mlx5hws_action_reformat_header *hdrs, + u32 log_bulk_sz) +{ + size_t max_sz = 0; + u32 arg_id; + int ret, i; + + for (i = 0; i < num_of_hdrs; i++) { + if (hdrs[i].sz % W_SIZE != 0) { + mlx5hws_err(action->ctx, + "Header data size should be in WORD granularity\n"); + return -EINVAL; + } + max_sz = max(hdrs[i].sz, max_sz); + } + + /* Allocate single shared arg object for all headers */ + ret = mlx5hws_arg_create(action->ctx, + hdrs->data, + max_sz, + log_bulk_sz, + action->flags & MLX5HWS_ACTION_FLAG_SHARED, + &arg_id); + if (ret) + return ret; + + for (i = 0; i < num_of_hdrs; i++) { + action[i].reformat.arg_id = arg_id; + action[i].reformat.header_size = hdrs[i].sz; + action[i].reformat.num_of_hdrs = num_of_hdrs; + action[i].reformat.max_hdr_sz = max_sz; + action[i].reformat.require_reparse = true; + + if (action[i].type == MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2 || + action[i].type == MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3) { + action[i].reformat.anchor = MLX5_HEADER_ANCHOR_PACKET_START; + action[i].reformat.offset = 0; + action[i].reformat.encap = 1; + } + + ret = hws_action_create_stcs(&action[i], 0); + if (ret) { + mlx5hws_err(action->ctx, "Failed to create stc for reformat\n"); + goto free_stc; + } + } + + return 0; + +free_stc: + while (i--) + hws_action_destroy_stcs(&action[i]); + + mlx5hws_arg_destroy(action->ctx, arg_id); + return ret; +} + +static int +hws_action_handle_l2_to_tunnel_l3(struct mlx5hws_action *action, + u8 num_of_hdrs, + struct mlx5hws_action_reformat_header *hdrs, + u32 log_bulk_sz) +{ + int ret; + + /* The action is remove-l2-header + insert-l3-header */ + ret = hws_action_get_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3); + if (ret) { + mlx5hws_err(action->ctx, "Failed to create remove stc for reformat\n"); + return ret; + } + + /* Reuse the insert with pointer for the L2L3 header */ + ret = hws_action_handle_insert_with_ptr(action, + num_of_hdrs, + hdrs, + log_bulk_sz); + if (ret) + goto put_shared_stc; + + return 0; + +put_shared_stc: + hws_action_put_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3); + return ret; +} + +static void hws_action_prepare_decap_l3_actions(size_t data_sz, + u8 *mh_data, + int *num_of_actions) +{ + int actions; + u32 i; + + /* Remove L2L3 outer headers */ + MLX5_SET(stc_ste_param_remove, mh_data, action_type, + MLX5_MODIFICATION_TYPE_REMOVE); + MLX5_SET(stc_ste_param_remove, mh_data, decap, 0x1); + MLX5_SET(stc_ste_param_remove, mh_data, remove_start_anchor, + MLX5_HEADER_ANCHOR_PACKET_START); + MLX5_SET(stc_ste_param_remove, mh_data, remove_end_anchor, + MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4); + mh_data += MLX5HWS_ACTION_DOUBLE_SIZE; /* Assume every action is 2 dw */ + actions = 1; + + /* Add the new header using inline action 4Byte at a time, the header + * is added in reversed order to the beginning of the packet to avoid + * incorrect parsing by the HW. Since header is 14B or 18B an extra + * two bytes are padded and later removed. + */ + for (i = 0; i < data_sz / MLX5HWS_ACTION_INLINE_DATA_SIZE + 1; i++) { + MLX5_SET(stc_ste_param_insert, mh_data, action_type, + MLX5_MODIFICATION_TYPE_INSERT); + MLX5_SET(stc_ste_param_insert, mh_data, inline_data, 0x1); + MLX5_SET(stc_ste_param_insert, mh_data, insert_anchor, + MLX5_HEADER_ANCHOR_PACKET_START); + MLX5_SET(stc_ste_param_insert, mh_data, insert_size, 2); + mh_data += MLX5HWS_ACTION_DOUBLE_SIZE; + actions++; + } + + /* Remove first 2 extra bytes */ + MLX5_SET(stc_ste_param_remove_words, mh_data, action_type, + MLX5_MODIFICATION_TYPE_REMOVE_WORDS); + MLX5_SET(stc_ste_param_remove_words, mh_data, remove_start_anchor, + MLX5_HEADER_ANCHOR_PACKET_START); + /* The hardware expects here size in words (2 bytes) */ + MLX5_SET(stc_ste_param_remove_words, mh_data, remove_size, 1); + actions++; + + *num_of_actions = actions; +} + +static int +hws_action_handle_tunnel_l3_to_l2(struct mlx5hws_action *action, + u8 num_of_hdrs, + struct mlx5hws_action_reformat_header *hdrs, + u32 log_bulk_sz) +{ + u8 mh_data[MLX5HWS_ACTION_REFORMAT_DATA_SIZE] = {0}; + struct mlx5hws_context *ctx = action->ctx; + u32 arg_id, pat_id; + int num_of_actions; + int mh_data_size; + int ret, i; + + for (i = 0; i < num_of_hdrs; i++) { + if (hdrs[i].sz != MLX5HWS_ACTION_HDR_LEN_L2 && + hdrs[i].sz != MLX5HWS_ACTION_HDR_LEN_L2_W_VLAN) { + mlx5hws_err(ctx, "Data size is not supported for decap-l3\n"); + return -EINVAL; + } + } + + /* Create a full modify header action list in case shared */ + hws_action_prepare_decap_l3_actions(hdrs->sz, mh_data, &num_of_actions); + if (action->flags & MLX5HWS_ACTION_FLAG_SHARED) + mlx5hws_action_prepare_decap_l3_data(hdrs->data, mh_data, num_of_actions); + + /* All DecapL3 cases require the same max arg size */ + ret = mlx5hws_arg_create_modify_header_arg(ctx, + (__be64 *)mh_data, + num_of_actions, + log_bulk_sz, + action->flags & MLX5HWS_ACTION_FLAG_SHARED, + &arg_id); + if (ret) + return ret; + + for (i = 0; i < num_of_hdrs; i++) { + memset(mh_data, 0, MLX5HWS_ACTION_REFORMAT_DATA_SIZE); + hws_action_prepare_decap_l3_actions(hdrs[i].sz, mh_data, &num_of_actions); + mh_data_size = num_of_actions * MLX5HWS_MODIFY_ACTION_SIZE; + + ret = mlx5hws_pat_get_pattern(ctx, (__be64 *)mh_data, mh_data_size, &pat_id); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate pattern for DecapL3\n"); + goto free_stc_and_pat; + } + + action[i].modify_header.max_num_of_actions = num_of_actions; + action[i].modify_header.num_of_actions = num_of_actions; + action[i].modify_header.num_of_patterns = num_of_hdrs; + action[i].modify_header.arg_id = arg_id; + action[i].modify_header.pat_id = pat_id; + action[i].modify_header.require_reparse = + mlx5hws_pat_require_reparse((__be64 *)mh_data, num_of_actions); + + ret = hws_action_create_stcs(&action[i], 0); + if (ret) { + mlx5hws_pat_put_pattern(ctx, pat_id); + goto free_stc_and_pat; + } + } + + return 0; + +free_stc_and_pat: + while (i--) { + hws_action_destroy_stcs(&action[i]); + mlx5hws_pat_put_pattern(ctx, action[i].modify_header.pat_id); + } + + mlx5hws_arg_destroy(action->ctx, arg_id); + return ret; +} + +static int +hws_action_create_reformat_hws(struct mlx5hws_action *action, + u8 num_of_hdrs, + struct mlx5hws_action_reformat_header *hdrs, + u32 bulk_size) +{ + int ret; + + switch (action->type) { + case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: + ret = hws_action_create_stcs(action, 0); + break; + case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: + ret = hws_action_handle_insert_with_ptr(action, num_of_hdrs, hdrs, bulk_size); + break; + case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: + ret = hws_action_handle_l2_to_tunnel_l3(action, num_of_hdrs, hdrs, bulk_size); + break; + case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: + ret = hws_action_handle_tunnel_l3_to_l2(action, num_of_hdrs, hdrs, bulk_size); + break; + default: + mlx5hws_err(action->ctx, "Invalid HWS reformat action type\n"); + return -EINVAL; + } + + return ret; +} + +struct mlx5hws_action * +mlx5hws_action_create_reformat(struct mlx5hws_context *ctx, + enum mlx5hws_action_type reformat_type, + u8 num_of_hdrs, + struct mlx5hws_action_reformat_header *hdrs, + u32 log_bulk_size, + u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + if (!num_of_hdrs) { + mlx5hws_err(ctx, "Reformat num_of_hdrs cannot be zero\n"); + return NULL; + } + + action = hws_action_create_generic_bulk(ctx, flags, reformat_type, num_of_hdrs); + if (!action) + return NULL; + + if ((flags & MLX5HWS_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_hdrs > 1)) { + mlx5hws_err(ctx, "Reformat flags don't fit HWS (flags: 0x%x)\n", flags); + goto free_action; + } + + ret = hws_action_create_reformat_hws(action, num_of_hdrs, hdrs, log_bulk_size); + if (ret) { + mlx5hws_err(ctx, "Failed to create HWS reformat action\n"); + goto free_action; + } + + return action; + +free_action: + kfree(action); + return NULL; +} + +static int +hws_action_create_modify_header_hws(struct mlx5hws_action *action, + u8 num_of_patterns, + struct mlx5hws_action_mh_pattern *pattern, + u32 log_bulk_size) +{ + struct mlx5hws_context *ctx = action->ctx; + u16 num_actions, max_mh_actions = 0; + int i, ret, size_in_bytes; + u32 pat_id, arg_id = 0; + __be64 *new_pattern; + size_t pat_max_sz; + + pat_max_sz = MLX5HWS_ARG_CHUNK_SIZE_MAX * MLX5HWS_ARG_DATA_SIZE; + size_in_bytes = pat_max_sz * sizeof(__be64); + new_pattern = kcalloc(num_of_patterns, size_in_bytes, GFP_KERNEL); + if (!new_pattern) + return -ENOMEM; + + /* Calculate maximum number of mh actions for shared arg allocation */ + for (i = 0; i < num_of_patterns; i++) { + size_t new_num_actions; + size_t cur_num_actions; + u32 nope_location; + + cur_num_actions = pattern[i].sz / MLX5HWS_MODIFY_ACTION_SIZE; + + mlx5hws_pat_calc_nope(pattern[i].data, cur_num_actions, + pat_max_sz / MLX5HWS_MODIFY_ACTION_SIZE, + &new_num_actions, &nope_location, + &new_pattern[i * pat_max_sz]); + + action[i].modify_header.nope_locations = nope_location; + action[i].modify_header.num_of_actions = new_num_actions; + + max_mh_actions = max(max_mh_actions, new_num_actions); + } + + if (mlx5hws_arg_get_arg_log_size(max_mh_actions) >= MLX5HWS_ARG_CHUNK_SIZE_MAX) { + mlx5hws_err(ctx, "Num of actions (%d) bigger than allowed\n", + max_mh_actions); + ret = -EINVAL; + goto free_new_pat; + } + + /* Allocate single shared arg for all patterns based on the max size */ + if (max_mh_actions > 1) { + ret = mlx5hws_arg_create_modify_header_arg(ctx, + pattern->data, + max_mh_actions, + log_bulk_size, + action->flags & + MLX5HWS_ACTION_FLAG_SHARED, + &arg_id); + if (ret) + goto free_new_pat; + } + + for (i = 0; i < num_of_patterns; i++) { + if (!mlx5hws_pat_verify_actions(ctx, pattern[i].data, pattern[i].sz)) { + mlx5hws_err(ctx, "Fail to verify pattern modify actions\n"); + ret = -EINVAL; + goto free_stc_and_pat; + } + num_actions = pattern[i].sz / MLX5HWS_MODIFY_ACTION_SIZE; + action[i].modify_header.num_of_patterns = num_of_patterns; + action[i].modify_header.max_num_of_actions = max_mh_actions; + + action[i].modify_header.require_reparse = + mlx5hws_pat_require_reparse(pattern[i].data, num_actions); + + if (num_actions == 1) { + pat_id = 0; + /* Optimize single modify action to be used inline */ + action[i].modify_header.single_action = pattern[i].data[0]; + action[i].modify_header.single_action_type = + MLX5_GET(set_action_in, pattern[i].data, action_type); + } else { + /* Multiple modify actions require a pattern */ + if (unlikely(action[i].modify_header.nope_locations)) { + size_t pattern_sz; + + pattern_sz = action[i].modify_header.num_of_actions * + MLX5HWS_MODIFY_ACTION_SIZE; + ret = + mlx5hws_pat_get_pattern(ctx, + &new_pattern[i * pat_max_sz], + pattern_sz, &pat_id); + } else { + ret = mlx5hws_pat_get_pattern(ctx, + pattern[i].data, + pattern[i].sz, + &pat_id); + } + if (ret) { + mlx5hws_err(ctx, + "Failed to allocate pattern for modify header\n"); + goto free_stc_and_pat; + } + + action[i].modify_header.arg_id = arg_id; + action[i].modify_header.pat_id = pat_id; + } + /* Allocate STC for each action representing a header */ + ret = hws_action_create_stcs(&action[i], 0); + if (ret) { + if (pat_id) + mlx5hws_pat_put_pattern(ctx, pat_id); + goto free_stc_and_pat; + } + } + + kfree(new_pattern); + return 0; + +free_stc_and_pat: + while (i--) { + hws_action_destroy_stcs(&action[i]); + if (action[i].modify_header.pat_id) + mlx5hws_pat_put_pattern(ctx, action[i].modify_header.pat_id); + } + + if (arg_id) + mlx5hws_arg_destroy(ctx, arg_id); +free_new_pat: + kfree(new_pattern); + return ret; +} + +struct mlx5hws_action * +mlx5hws_action_create_modify_header(struct mlx5hws_context *ctx, + u8 num_of_patterns, + struct mlx5hws_action_mh_pattern *patterns, + u32 log_bulk_size, + u32 flags) +{ + struct mlx5hws_action *action; + int ret; + + if (!num_of_patterns) { + mlx5hws_err(ctx, "Invalid number of patterns\n"); + return NULL; + } + action = hws_action_create_generic_bulk(ctx, flags, + MLX5HWS_ACTION_TYP_MODIFY_HDR, + num_of_patterns); + if (!action) + return NULL; + + if ((flags & MLX5HWS_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_patterns > 1)) { + mlx5hws_err(ctx, "Action cannot be shared with requested pattern or size\n"); + goto free_action; + } + + ret = hws_action_create_modify_header_hws(action, + num_of_patterns, + patterns, + log_bulk_size); + if (ret) + goto free_action; + + return action; + +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_dest_array(struct mlx5hws_context *ctx, + size_t num_dest, + struct mlx5hws_action_dest_attr *dests, + bool ignore_flow_level, + u32 flow_source, + u32 flags) +{ + struct mlx5hws_cmd_set_fte_dest *dest_list = NULL; + struct mlx5hws_cmd_ft_create_attr ft_attr = {0}; + struct mlx5hws_cmd_set_fte_attr fte_attr = {0}; + struct mlx5hws_cmd_forward_tbl *fw_island; + struct mlx5hws_action *action; + u32 i /*, packet_reformat_id*/; + int ret; + + if (num_dest <= 1) { + mlx5hws_err(ctx, "Action must have multiple dests\n"); + return NULL; + } + + if (flags == (MLX5HWS_ACTION_FLAG_HWS_FDB | MLX5HWS_ACTION_FLAG_SHARED)) { + ft_attr.type = FS_FT_FDB; + ft_attr.level = ctx->caps->fdb_ft.max_level - 1; + } else { + mlx5hws_err(ctx, "Action flags not supported\n"); + return NULL; + } + + dest_list = kcalloc(num_dest, sizeof(*dest_list), GFP_KERNEL); + if (!dest_list) + return NULL; + + for (i = 0; i < num_dest; i++) { + enum mlx5hws_action_type action_type = dests[i].dest->type; + struct mlx5hws_action *reformat_action = dests[i].reformat; + + switch (action_type) { + case MLX5HWS_ACTION_TYP_TBL: + dest_list[i].destination_type = + MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; + dest_list[i].destination_id = dests[i].dest->dest_obj.obj_id; + fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; + fte_attr.ignore_flow_level = ignore_flow_level; + /* ToDo: In SW steering we have a handling of 'go to WIRE' + * destination here by upper layer setting 'is_wire_ft' flag + * if the destination is wire. + * This is because uplink should be last dest in the list. + */ + break; + case MLX5HWS_ACTION_TYP_VPORT: + dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT; + dest_list[i].destination_id = dests[i].dest->vport.vport_num; + fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; + if (ctx->caps->merged_eswitch) { + dest_list[i].ext_flags |= + MLX5HWS_CMD_EXT_DEST_ESW_OWNER_VHCA_ID; + dest_list[i].esw_owner_vhca_id = + dests[i].dest->vport.esw_owner_vhca_id; + } + break; + default: + mlx5hws_err(ctx, "Unsupported action in dest_array\n"); + goto free_dest_list; + } + + if (reformat_action) { + mlx5hws_err(ctx, "dest_array with reformat action - unsupported\n"); + goto free_dest_list; + } + } + + fte_attr.dests_num = num_dest; + fte_attr.dests = dest_list; + + fw_island = mlx5hws_cmd_forward_tbl_create(ctx->mdev, &ft_attr, &fte_attr); + if (!fw_island) + goto free_dest_list; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_DEST_ARRAY); + if (!action) + goto destroy_fw_island; + + ret = hws_action_create_stcs(action, fw_island->ft_id); + if (ret) + goto free_action; + + action->dest_array.fw_island = fw_island; + action->dest_array.num_dest = num_dest; + action->dest_array.dest_list = dest_list; + + return action; + +free_action: + kfree(action); +destroy_fw_island: + mlx5hws_cmd_forward_tbl_destroy(ctx->mdev, fw_island); +free_dest_list: + for (i = 0; i < num_dest; i++) { + if (dest_list[i].ext_reformat_id) + mlx5hws_cmd_packet_reformat_destroy(ctx->mdev, + dest_list[i].ext_reformat_id); + } + kfree(dest_list); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_insert_header(struct mlx5hws_context *ctx, + u8 num_of_hdrs, + struct mlx5hws_action_insert_header *hdrs, + u32 log_bulk_size, + u32 flags) +{ + struct mlx5hws_action_reformat_header *reformat_hdrs; + struct mlx5hws_action *action; + int ret; + int i; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_INSERT_HEADER); + if (!action) + return NULL; + + reformat_hdrs = kcalloc(num_of_hdrs, sizeof(*reformat_hdrs), GFP_KERNEL); + if (!reformat_hdrs) + goto free_action; + + for (i = 0; i < num_of_hdrs; i++) { + if (hdrs[i].offset % W_SIZE != 0) { + mlx5hws_err(ctx, "Header offset should be in WORD granularity\n"); + goto free_reformat_hdrs; + } + + action[i].reformat.anchor = hdrs[i].anchor; + action[i].reformat.encap = hdrs[i].encap; + action[i].reformat.offset = hdrs[i].offset; + + reformat_hdrs[i].sz = hdrs[i].hdr.sz; + reformat_hdrs[i].data = hdrs[i].hdr.data; + } + + ret = hws_action_handle_insert_with_ptr(action, num_of_hdrs, + reformat_hdrs, log_bulk_size); + if (ret) { + mlx5hws_err(ctx, "Failed to create HWS reformat action\n"); + goto free_reformat_hdrs; + } + + kfree(reformat_hdrs); + + return action; + +free_reformat_hdrs: + kfree(reformat_hdrs); +free_action: + kfree(action); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_remove_header(struct mlx5hws_context *ctx, + struct mlx5hws_action_remove_header_attr *attr, + u32 flags) +{ + struct mlx5hws_action *action; + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_REMOVE_HEADER); + if (!action) + return NULL; + + /* support only remove anchor with size */ + if (attr->size % W_SIZE != 0) { + mlx5hws_err(ctx, + "Invalid size, HW supports header remove in WORD granularity\n"); + goto free_action; + } + + if (attr->size > MLX5HWS_ACTION_REMOVE_HEADER_MAX_SIZE) { + mlx5hws_err(ctx, "Header removal size limited to %u bytes\n", + MLX5HWS_ACTION_REMOVE_HEADER_MAX_SIZE); + goto free_action; + } + + action->remove_header.anchor = attr->anchor; + action->remove_header.size = attr->size / W_SIZE; + + if (hws_action_create_stcs(action, 0)) + goto free_action; + + return action; + +free_action: + kfree(action); + return NULL; +} + +static struct mlx5hws_definer * +hws_action_create_dest_match_range_definer(struct mlx5hws_context *ctx) +{ + struct mlx5hws_definer *definer; + __be32 *tag; + int ret; + + definer = kzalloc(sizeof(*definer), GFP_KERNEL); + if (!definer) + return NULL; + + definer->dw_selector[0] = MLX5_IFC_DEFINER_FORMAT_OFFSET_OUTER_ETH_PKT_LEN / 4; + /* Set DW0 tag mask */ + tag = (__force __be32 *)definer->mask.jumbo; + tag[MLX5HWS_RULE_JUMBO_MATCH_TAG_OFFSET_DW0] = htonl(0xffffUL << 16); + + mutex_lock(&ctx->ctrl_lock); + + ret = mlx5hws_definer_get_obj(ctx, definer); + if (ret < 0) { + mutex_unlock(&ctx->ctrl_lock); + kfree(definer); + return NULL; + } + + mutex_unlock(&ctx->ctrl_lock); + definer->obj_id = ret; + + return definer; +} + +static struct mlx5hws_matcher_action_ste * +hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx, + struct mlx5hws_definer *definer, + u32 miss_ft_id) +{ + struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0}; + struct mlx5hws_action_default_stc *default_stc; + struct mlx5hws_matcher_action_ste *table_ste; + struct mlx5hws_pool_attr pool_attr = {0}; + struct mlx5hws_pool *ste_pool, *stc_pool; + struct mlx5hws_pool_chunk *ste; + u32 *rtc_0_id, *rtc_1_id; + u32 obj_id; + int ret; + + /* Check if STE range is supported */ + if (!IS_BIT_SET(ctx->caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_RANGE)) { + mlx5hws_err(ctx, "Range STE format not supported\n"); + return NULL; + } + + table_ste = kzalloc(sizeof(*table_ste), GFP_KERNEL); + if (!table_ste) + return NULL; + + mutex_lock(&ctx->ctrl_lock); + + pool_attr.table_type = MLX5HWS_TABLE_TYPE_FDB; + pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; + pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL; + pool_attr.alloc_log_sz = 1; + table_ste->pool = mlx5hws_pool_create(ctx, &pool_attr); + if (!table_ste->pool) { + mlx5hws_err(ctx, "Failed to allocate memory ste pool\n"); + goto free_ste; + } + + /* Allocate RTC */ + rtc_0_id = &table_ste->rtc_0_id; + rtc_1_id = &table_ste->rtc_1_id; + ste_pool = table_ste->pool; + ste = &table_ste->ste; + ste->order = 1; + + rtc_attr.log_size = 0; + rtc_attr.log_depth = 0; + rtc_attr.miss_ft_id = miss_ft_id; + rtc_attr.num_hash_definer = 1; + rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; + rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH; + rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; + rtc_attr.fw_gen_wqe = true; + rtc_attr.is_scnd_range = true; + + obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); + + rtc_attr.pd = ctx->pd_num; + rtc_attr.ste_base = obj_id; + rtc_attr.ste_offset = ste->offset; + rtc_attr.reparse_mode = mlx5hws_context_get_reparse_mode(ctx); + rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(MLX5HWS_TABLE_TYPE_FDB, false); + + /* STC is a single resource (obj_id), use any STC for the ID */ + stc_pool = ctx->stc_pool[MLX5HWS_TABLE_TYPE_FDB]; + default_stc = ctx->common_res[MLX5HWS_TABLE_TYPE_FDB].default_stc; + obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit); + rtc_attr.stc_base = obj_id; + + ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id); + if (ret) { + mlx5hws_err(ctx, "Failed to create RTC"); + goto pool_destroy; + } + + /* Create mirror RTC */ + obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); + rtc_attr.ste_base = obj_id; + rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(MLX5HWS_TABLE_TYPE_FDB, true); + + obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit); + rtc_attr.stc_base = obj_id; + + ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_1_id); + if (ret) { + mlx5hws_err(ctx, "Failed to create mirror RTC"); + goto destroy_rtc_0; + } + + mutex_unlock(&ctx->ctrl_lock); + + return table_ste; + +destroy_rtc_0: + mlx5hws_cmd_rtc_destroy(ctx->mdev, *rtc_0_id); +pool_destroy: + mlx5hws_pool_destroy(table_ste->pool); +free_ste: + mutex_unlock(&ctx->ctrl_lock); + kfree(table_ste); + return NULL; +} + +static void +hws_action_destroy_dest_match_range_table(struct mlx5hws_context *ctx, + struct mlx5hws_matcher_action_ste *table_ste) +{ + mutex_lock(&ctx->ctrl_lock); + + mlx5hws_cmd_rtc_destroy(ctx->mdev, table_ste->rtc_1_id); + mlx5hws_cmd_rtc_destroy(ctx->mdev, table_ste->rtc_0_id); + mlx5hws_pool_destroy(table_ste->pool); + kfree(table_ste); + + mutex_unlock(&ctx->ctrl_lock); +} + +static int +hws_action_create_dest_match_range_fill_table(struct mlx5hws_context *ctx, + struct mlx5hws_matcher_action_ste *table_ste, + struct mlx5hws_action *hit_ft_action, + struct mlx5hws_definer *range_definer, + u32 min, u32 max) +{ + struct mlx5hws_wqe_gta_data_seg_ste match_wqe_data = {0}; + struct mlx5hws_wqe_gta_data_seg_ste range_wqe_data = {0}; + struct mlx5hws_wqe_gta_ctrl_seg wqe_ctrl = {0}; + u32 no_use, used_rtc_0_id, used_rtc_1_id, ret; + struct mlx5hws_context_common_res *common_res; + struct mlx5hws_send_ste_attr ste_attr = {0}; + struct mlx5hws_send_engine *queue; + __be32 *wqe_data_arr; + + mutex_lock(&ctx->ctrl_lock); + + /* Get the control queue */ + queue = &ctx->send_queue[ctx->queues - 1]; + if (unlikely(mlx5hws_send_engine_err(queue))) { + ret = -EIO; + goto error; + } + + /* Init default send STE attributes */ + ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; + ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; + ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; + ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; + ste_attr.send_attr.user_data = &no_use; + ste_attr.send_attr.rule = NULL; + ste_attr.send_attr.fence = 1; + ste_attr.send_attr.notify_hw = true; + ste_attr.rtc_0 = table_ste->rtc_0_id; + ste_attr.rtc_1 = table_ste->rtc_1_id; + ste_attr.used_id_rtc_0 = &used_rtc_0_id; + ste_attr.used_id_rtc_1 = &used_rtc_1_id; + + common_res = &ctx->common_res[MLX5HWS_TABLE_TYPE_FDB]; + + /* init an empty match STE which will always hit */ + ste_attr.wqe_ctrl = &wqe_ctrl; + ste_attr.wqe_data = &match_wqe_data; + ste_attr.send_attr.match_definer_id = ctx->caps->trivial_match_definer; + + /* Fill WQE control data */ + wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] = + htonl(common_res->default_stc->nop_ctr.offset); + wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = + htonl(common_res->default_stc->nop_dw5.offset); + wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = + htonl(common_res->default_stc->nop_dw6.offset); + wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = + htonl(common_res->default_stc->nop_dw7.offset); + wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] |= + htonl(MLX5HWS_ACTION_STC_IDX_LAST_COMBO2 << 29); + wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_HIT] = + htonl(hit_ft_action->stc[MLX5HWS_TABLE_TYPE_FDB].offset); + + wqe_data_arr = (__force __be32 *)&range_wqe_data; + + ste_attr.range_wqe_data = &range_wqe_data; + ste_attr.send_attr.len += MLX5HWS_WQE_SZ_GTA_DATA; + ste_attr.send_attr.range_definer_id = mlx5hws_definer_get_id(range_definer); + + /* Fill range matching fields, + * min/max_value_2 corresponds to match_dw_0 in its definer, + * min_value_2 sets in DW0 in the STE and max_value_2 sets in DW1 in the STE. + */ + wqe_data_arr[MLX5HWS_MATCHER_OFFSET_TAG_DW0] = htonl(min << 16); + wqe_data_arr[MLX5HWS_MATCHER_OFFSET_TAG_DW1] = htonl(max << 16); + + /* Send WQEs to FW */ + mlx5hws_send_stes_fw(ctx, queue, &ste_attr); + + /* Poll for completion */ + ret = mlx5hws_send_queue_action(ctx, ctx->queues - 1, + MLX5HWS_SEND_QUEUE_ACTION_DRAIN_SYNC); + if (ret) { + mlx5hws_err(ctx, "Failed to drain control queue"); + goto error; + } + + mutex_unlock(&ctx->ctrl_lock); + + return 0; + +error: + mutex_unlock(&ctx->ctrl_lock); + return ret; +} + +struct mlx5hws_action * +mlx5hws_action_create_dest_match_range(struct mlx5hws_context *ctx, + u32 field, + struct mlx5_flow_table *hit_ft, + struct mlx5_flow_table *miss_ft, + u32 min, u32 max, u32 flags) +{ + struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; + struct mlx5hws_matcher_action_ste *table_ste; + struct mlx5hws_action *hit_ft_action; + struct mlx5hws_definer *definer; + struct mlx5hws_action *action; + u32 miss_ft_id = miss_ft->id; + u32 hit_ft_id = hit_ft->id; + int ret; + + if (field != MLX5_FLOW_DEST_RANGE_FIELD_PKT_LEN || + min > 0xffff || max > 0xffff) { + mlx5hws_err(ctx, "Invalid match range parameters\n"); + return NULL; + } + + action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_RANGE); + if (!action) + return NULL; + + definer = hws_action_create_dest_match_range_definer(ctx); + if (!definer) + goto free_action; + + table_ste = hws_action_create_dest_match_range_table(ctx, definer, miss_ft_id); + if (!table_ste) + goto destroy_definer; + + hit_ft_action = mlx5hws_action_create_dest_table_num(ctx, hit_ft_id, flags); + if (!hit_ft_action) + goto destroy_table_ste; + + ret = hws_action_create_dest_match_range_fill_table(ctx, table_ste, + hit_ft_action, + definer, min, max); + if (ret) + goto destroy_hit_ft_action; + + action->range.table_ste = table_ste; + action->range.definer = definer; + action->range.hit_ft_action = hit_ft_action; + + /* Allocate STC for jumps to STE */ + mutex_lock(&ctx->ctrl_lock); + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; + stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; + stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; + stc_attr.ste_table.ste = table_ste->ste; + stc_attr.ste_table.ste_pool = table_ste->pool; + stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; + + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, MLX5HWS_TABLE_TYPE_FDB, + &action->stc[MLX5HWS_TABLE_TYPE_FDB]); + if (ret) + goto error_unlock; + + mutex_unlock(&ctx->ctrl_lock); + + return action; + +error_unlock: + mutex_unlock(&ctx->ctrl_lock); +destroy_hit_ft_action: + mlx5hws_action_destroy(hit_ft_action); +destroy_table_ste: + hws_action_destroy_dest_match_range_table(ctx, table_ste); +destroy_definer: + mlx5hws_definer_free(ctx, definer); +free_action: + kfree(action); + mlx5hws_err(ctx, "Failed to create action dest match range"); + return NULL; +} + +struct mlx5hws_action * +mlx5hws_action_create_last(struct mlx5hws_context *ctx, u32 flags) +{ + return hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_LAST); +} + +struct mlx5hws_action * +mlx5hws_action_create_flow_sampler(struct mlx5hws_context *ctx, + u32 sampler_id, u32 flags) +{ + mlx5hws_err(ctx, "Flow sampler action - unsupported\n"); + return NULL; +} + +static void hws_action_destroy_hws(struct mlx5hws_action *action) +{ + u32 ext_reformat_id; + bool shared_arg; + u32 obj_id; + u32 i; + + switch (action->type) { + case MLX5HWS_ACTION_TYP_MISS: + case MLX5HWS_ACTION_TYP_TAG: + case MLX5HWS_ACTION_TYP_DROP: + case MLX5HWS_ACTION_TYP_CTR: + case MLX5HWS_ACTION_TYP_TBL: + case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: + case MLX5HWS_ACTION_TYP_ASO_METER: + case MLX5HWS_ACTION_TYP_PUSH_VLAN: + case MLX5HWS_ACTION_TYP_REMOVE_HEADER: + case MLX5HWS_ACTION_TYP_VPORT: + hws_action_destroy_stcs(action); + break; + case MLX5HWS_ACTION_TYP_POP_VLAN: + hws_action_destroy_stcs(action); + hws_action_put_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP); + break; + case MLX5HWS_ACTION_TYP_DEST_ARRAY: + hws_action_destroy_stcs(action); + mlx5hws_cmd_forward_tbl_destroy(action->ctx->mdev, action->dest_array.fw_island); + for (i = 0; i < action->dest_array.num_dest; i++) { + ext_reformat_id = action->dest_array.dest_list[i].ext_reformat_id; + if (ext_reformat_id) + mlx5hws_cmd_packet_reformat_destroy(action->ctx->mdev, + ext_reformat_id); + } + kfree(action->dest_array.dest_list); + break; + case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: + case MLX5HWS_ACTION_TYP_MODIFY_HDR: + shared_arg = false; + for (i = 0; i < action->modify_header.num_of_patterns; i++) { + hws_action_destroy_stcs(&action[i]); + if (action[i].modify_header.num_of_actions > 1) { + mlx5hws_pat_put_pattern(action[i].ctx, + action[i].modify_header.pat_id); + /* Save shared arg object to be freed after */ + obj_id = action[i].modify_header.arg_id; + shared_arg = true; + } + } + if (shared_arg) + mlx5hws_arg_destroy(action->ctx, obj_id); + break; + case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: + hws_action_put_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3); + for (i = 0; i < action->reformat.num_of_hdrs; i++) + hws_action_destroy_stcs(&action[i]); + mlx5hws_arg_destroy(action->ctx, action->reformat.arg_id); + break; + case MLX5HWS_ACTION_TYP_INSERT_HEADER: + case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: + for (i = 0; i < action->reformat.num_of_hdrs; i++) + hws_action_destroy_stcs(&action[i]); + mlx5hws_arg_destroy(action->ctx, action->reformat.arg_id); + break; + case MLX5HWS_ACTION_TYP_RANGE: + hws_action_destroy_stcs(action); + hws_action_destroy_dest_match_range_table(action->ctx, action->range.table_ste); + mlx5hws_definer_free(action->ctx, action->range.definer); + mlx5hws_action_destroy(action->range.hit_ft_action); + break; + case MLX5HWS_ACTION_TYP_LAST: + break; + default: + pr_warn("HWS: Invalid action type: %d\n", action->type); + } +} + +int mlx5hws_action_destroy(struct mlx5hws_action *action) +{ + hws_action_destroy_hws(action); + + kfree(action); + return 0; +} + +int mlx5hws_action_get_default_stc(struct mlx5hws_context *ctx, u8 tbl_type) +__must_hold(&ctx->ctrl_lock) +{ + struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; + struct mlx5hws_action_default_stc *default_stc; + int ret; + + if (ctx->common_res[tbl_type].default_stc) { + ctx->common_res[tbl_type].default_stc->refcount++; + return 0; + } + + default_stc = kzalloc(sizeof(*default_stc), GFP_KERNEL); + if (!default_stc) + return -ENOMEM; + + stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_NOP; + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW0; + stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, + &default_stc->nop_ctr); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate default counter STC\n"); + goto free_default_stc; + } + + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW5; + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, + &default_stc->nop_dw5); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate default NOP DW5 STC\n"); + goto free_nop_ctr; + } + + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW6; + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, + &default_stc->nop_dw6); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate default NOP DW6 STC\n"); + goto free_nop_dw5; + } + + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW7; + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, + &default_stc->nop_dw7); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate default NOP DW7 STC\n"); + goto free_nop_dw6; + } + + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; + stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW; + + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, + &default_stc->default_hit); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate default allow STC\n"); + goto free_nop_dw7; + } + + ctx->common_res[tbl_type].default_stc = default_stc; + ctx->common_res[tbl_type].default_stc->refcount++; + + return 0; + +free_nop_dw7: + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7); +free_nop_dw6: + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6); +free_nop_dw5: + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5); +free_nop_ctr: + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr); +free_default_stc: + kfree(default_stc); + return ret; +} + +void mlx5hws_action_put_default_stc(struct mlx5hws_context *ctx, u8 tbl_type) +__must_hold(&ctx->ctrl_lock) +{ + struct mlx5hws_action_default_stc *default_stc; + + default_stc = ctx->common_res[tbl_type].default_stc; + + default_stc = ctx->common_res[tbl_type].default_stc; + if (--default_stc->refcount) + return; + + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->default_hit); + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7); + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6); + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5); + mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr); + kfree(default_stc); + ctx->common_res[tbl_type].default_stc = NULL; +} + +static void hws_action_modify_write(struct mlx5hws_send_engine *queue, + u32 arg_idx, + u8 *arg_data, + u16 num_of_actions, + u32 nope_locations) +{ + u8 *new_arg_data = NULL; + int i, j; + + if (unlikely(nope_locations)) { + new_arg_data = kcalloc(num_of_actions, + MLX5HWS_MODIFY_ACTION_SIZE, GFP_KERNEL); + if (unlikely(!new_arg_data)) + return; + + for (i = 0, j = 0; i < num_of_actions; i++, j++) { + memcpy(&new_arg_data[j], arg_data, MLX5HWS_MODIFY_ACTION_SIZE); + if (BIT(i) & nope_locations) + j++; + } + } + + mlx5hws_arg_write(queue, NULL, arg_idx, + new_arg_data ? new_arg_data : arg_data, + num_of_actions * MLX5HWS_MODIFY_ACTION_SIZE); + + kfree(new_arg_data); +} + +void mlx5hws_action_prepare_decap_l3_data(u8 *src, u8 *dst, u16 num_of_actions) +{ + u8 *e_src; + int i; + + /* num_of_actions = remove l3l2 + 4/5 inserts + remove extra 2 bytes + * copy from end of src to the start of dst. + * move to the end, 2 is the leftover from 14B or 18B + */ + if (num_of_actions == DECAP_L3_NUM_ACTIONS_W_NO_VLAN) + e_src = src + MLX5HWS_ACTION_HDR_LEN_L2; + else + e_src = src + MLX5HWS_ACTION_HDR_LEN_L2_W_VLAN; + + /* Move dst over the first remove action + zero data */ + dst += MLX5HWS_ACTION_DOUBLE_SIZE; + /* Move dst over the first insert ctrl action */ + dst += MLX5HWS_ACTION_DOUBLE_SIZE / 2; + /* Actions: + * no vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b. + * with vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b. + * the loop is without the last insertion. + */ + for (i = 0; i < num_of_actions - 3; i++) { + e_src -= MLX5HWS_ACTION_INLINE_DATA_SIZE; + memcpy(dst, e_src, MLX5HWS_ACTION_INLINE_DATA_SIZE); /* data */ + dst += MLX5HWS_ACTION_DOUBLE_SIZE; + } + /* Copy the last 2 bytes after a gap of 2 bytes which will be removed */ + e_src -= MLX5HWS_ACTION_INLINE_DATA_SIZE / 2; + dst += MLX5HWS_ACTION_INLINE_DATA_SIZE / 2; + memcpy(dst, e_src, 2); +} + +static int +hws_action_get_shared_stc_offset(struct mlx5hws_context_common_res *common_res, + enum mlx5hws_context_shared_stc_type stc_type) +{ + return common_res->shared_stc[stc_type]->stc_chunk.offset; +} + +static struct mlx5hws_actions_wqe_setter * +hws_action_setter_find_first(struct mlx5hws_actions_wqe_setter *setter, + u8 req_flags) +{ + /* Use a new setter if requested flags are taken */ + while (setter->flags & req_flags) + setter++; + + /* Use current setter in required flags are not used */ + return setter; +} + +static void +hws_action_apply_stc(struct mlx5hws_actions_apply_data *apply, + enum mlx5hws_action_stc_idx stc_idx, + u8 action_idx) +{ + struct mlx5hws_action *action = apply->rule_action[action_idx].action; + + apply->wqe_ctrl->stc_ix[stc_idx] = + htonl(action->stc[apply->tbl_type].offset); +} + +static void +hws_action_setter_push_vlan(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + struct mlx5hws_rule_action *rule_action; + + rule_action = &apply->rule_action[setter->idx_double]; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = rule_action->push_vlan.vlan_hdr; + + hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_DW6, setter->idx_double); + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; +} + +static void +hws_action_setter_modify_header(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + struct mlx5hws_rule_action *rule_action; + struct mlx5hws_action *action; + u32 arg_sz, arg_idx; + u8 *single_action; + __be32 stc_idx; + + rule_action = &apply->rule_action[setter->idx_double]; + action = rule_action->action; + + stc_idx = htonl(action->stc[apply->tbl_type].offset); + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; + + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; + + if (action->modify_header.num_of_actions == 1) { + if (action->modify_header.single_action_type == + MLX5_MODIFICATION_TYPE_COPY || + action->modify_header.single_action_type == + MLX5_MODIFICATION_TYPE_ADD_FIELD) { + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = 0; + return; + } + + if (action->flags & MLX5HWS_ACTION_FLAG_SHARED) + single_action = (u8 *)&action->modify_header.single_action; + else + single_action = rule_action->modify_header.data; + + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = + *(__be32 *)MLX5_ADDR_OF(set_action_in, single_action, data); + } else { + /* Argument offset multiple with number of args per these actions */ + arg_sz = mlx5hws_arg_get_arg_size(action->modify_header.max_num_of_actions); + arg_idx = rule_action->modify_header.offset * arg_sz; + + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(arg_idx); + + if (!(action->flags & MLX5HWS_ACTION_FLAG_SHARED)) { + apply->require_dep = 1; + hws_action_modify_write(apply->queue, + action->modify_header.arg_id + arg_idx, + rule_action->modify_header.data, + action->modify_header.num_of_actions, + action->modify_header.nope_locations); + } + } +} + +static void +hws_action_setter_insert_ptr(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + struct mlx5hws_rule_action *rule_action; + struct mlx5hws_action *action; + u32 arg_idx, arg_sz; + __be32 stc_idx; + + rule_action = &apply->rule_action[setter->idx_double]; + action = rule_action->action + rule_action->reformat.hdr_idx; + + /* Argument offset multiple on args required for header size */ + arg_sz = mlx5hws_arg_data_size_to_arg_size(action->reformat.max_hdr_sz); + arg_idx = rule_action->reformat.offset * arg_sz; + + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(arg_idx); + + stc_idx = htonl(action->stc[apply->tbl_type].offset); + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; + + if (!(action->flags & MLX5HWS_ACTION_FLAG_SHARED)) { + apply->require_dep = 1; + mlx5hws_arg_write(apply->queue, NULL, + action->reformat.arg_id + arg_idx, + rule_action->reformat.data, + action->reformat.header_size); + } +} + +static void +hws_action_setter_tnl_l3_to_l2(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + struct mlx5hws_rule_action *rule_action; + struct mlx5hws_action *action; + u32 arg_sz, arg_idx; + __be32 stc_idx; + + rule_action = &apply->rule_action[setter->idx_double]; + action = rule_action->action + rule_action->reformat.hdr_idx; + + /* Argument offset multiple on args required for num of actions */ + arg_sz = mlx5hws_arg_get_arg_size(action->modify_header.max_num_of_actions); + arg_idx = rule_action->reformat.offset * arg_sz; + + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(arg_idx); + + stc_idx = htonl(action->stc[apply->tbl_type].offset); + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; + + if (!(action->flags & MLX5HWS_ACTION_FLAG_SHARED)) { + apply->require_dep = 1; + mlx5hws_arg_decapl3_write(apply->queue, + action->modify_header.arg_id + arg_idx, + rule_action->reformat.data, + action->modify_header.num_of_actions); + } +} + +static void +hws_action_setter_aso(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + struct mlx5hws_rule_action *rule_action; + u32 exe_aso_ctrl; + u32 offset; + + rule_action = &apply->rule_action[setter->idx_double]; + + switch (rule_action->action->type) { + case MLX5HWS_ACTION_TYP_ASO_METER: + /* exe_aso_ctrl format: + * [STC only and reserved bits 29b][init_color 2b][meter_id 1b] + */ + offset = rule_action->aso_meter.offset / MLX5_ASO_METER_NUM_PER_OBJ; + exe_aso_ctrl = rule_action->aso_meter.offset % MLX5_ASO_METER_NUM_PER_OBJ; + exe_aso_ctrl |= rule_action->aso_meter.init_color << + MLX5HWS_ACTION_METER_INIT_COLOR_OFFSET; + break; + default: + mlx5hws_err(rule_action->action->ctx, + "Unsupported ASO action type: %d\n", rule_action->action->type); + return; + } + + /* aso_object_offset format: [24B] */ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = htonl(offset); + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(exe_aso_ctrl); + + hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_DW6, setter->idx_double); + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; +} + +static void +hws_action_setter_tag(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + struct mlx5hws_rule_action *rule_action; + + rule_action = &apply->rule_action[setter->idx_single]; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = htonl(rule_action->tag.value); + hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_DW5, setter->idx_single); +} + +static void +hws_action_setter_ctrl_ctr(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + struct mlx5hws_rule_action *rule_action; + + rule_action = &apply->rule_action[setter->idx_ctr]; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW0] = htonl(rule_action->counter.offset); + hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_CTRL, setter->idx_ctr); +} + +static void +hws_action_setter_single(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; + hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_DW5, setter->idx_single); +} + +static void +hws_action_setter_single_double_pop(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = + htonl(hws_action_get_shared_stc_offset(apply->common_res, + MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP)); +} + +static void +hws_action_setter_hit(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_HIT_LSB] = 0; + hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_HIT, setter->idx_hit); +} + +static void +hws_action_setter_default_hit(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_HIT_LSB] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_HIT] = + htonl(apply->common_res->default_stc->default_hit.offset); +} + +static void +hws_action_setter_hit_next_action(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_HIT_LSB] = htonl(apply->next_direct_idx << 6); + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_HIT] = htonl(apply->jump_to_action_stc); +} + +static void +hws_action_setter_common_decap(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = + htonl(hws_action_get_shared_stc_offset(apply->common_res, + MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3)); +} + +static void +hws_action_setter_range(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + /* Always jump to index zero */ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_HIT_LSB] = 0; + hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_HIT, setter->idx_hit); +} + +int mlx5hws_action_template_process(struct mlx5hws_action_template *at) +{ + struct mlx5hws_actions_wqe_setter *start_setter = at->setters + 1; + enum mlx5hws_action_type *action_type = at->action_type_arr; + struct mlx5hws_actions_wqe_setter *setter = at->setters; + struct mlx5hws_actions_wqe_setter *pop_setter = NULL; + struct mlx5hws_actions_wqe_setter *last_setter; + int i; + + /* Note: Given action combination must be valid */ + + /* Check if action were already processed */ + if (at->num_of_action_stes) + return 0; + + for (i = 0; i < MLX5HWS_ACTION_MAX_STE; i++) + setter[i].set_hit = &hws_action_setter_hit_next_action; + + /* The same action template setters can be used with jumbo or match + * STE, to support both cases we reserve the first setter for cases + * with jumbo STE to allow jump to the first action STE. + * This extra setter can be reduced in some cases on rule creation. + */ + setter = start_setter; + last_setter = start_setter; + + for (i = 0; i < at->num_actions; i++) { + switch (action_type[i]) { + case MLX5HWS_ACTION_TYP_DROP: + case MLX5HWS_ACTION_TYP_TBL: + case MLX5HWS_ACTION_TYP_DEST_ARRAY: + case MLX5HWS_ACTION_TYP_VPORT: + case MLX5HWS_ACTION_TYP_MISS: + /* Hit action */ + last_setter->flags |= ASF_HIT; + last_setter->set_hit = &hws_action_setter_hit; + last_setter->idx_hit = i; + break; + + case MLX5HWS_ACTION_TYP_RANGE: + last_setter->flags |= ASF_HIT; + last_setter->set_hit = &hws_action_setter_range; + last_setter->idx_hit = i; + break; + + case MLX5HWS_ACTION_TYP_POP_VLAN: + /* Single remove header to header */ + if (pop_setter) { + /* We have 2 pops, use the shared */ + pop_setter->set_single = &hws_action_setter_single_double_pop; + break; + } + setter = hws_action_setter_find_first(last_setter, + ASF_SINGLE1 | ASF_MODIFY | + ASF_INSERT); + setter->flags |= ASF_SINGLE1 | ASF_REMOVE; + setter->set_single = &hws_action_setter_single; + setter->idx_single = i; + pop_setter = setter; + break; + + case MLX5HWS_ACTION_TYP_PUSH_VLAN: + /* Double insert inline */ + setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); + setter->flags |= ASF_DOUBLE | ASF_INSERT; + setter->set_double = &hws_action_setter_push_vlan; + setter->idx_double = i; + break; + + case MLX5HWS_ACTION_TYP_MODIFY_HDR: + /* Double modify header list */ + setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); + setter->flags |= ASF_DOUBLE | ASF_MODIFY; + setter->set_double = &hws_action_setter_modify_header; + setter->idx_double = i; + break; + + case MLX5HWS_ACTION_TYP_ASO_METER: + /* Double ASO action */ + setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE); + setter->flags |= ASF_DOUBLE; + setter->set_double = &hws_action_setter_aso; + setter->idx_double = i; + break; + + case MLX5HWS_ACTION_TYP_REMOVE_HEADER: + case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: + /* Single remove header to header */ + setter = hws_action_setter_find_first(last_setter, + ASF_SINGLE1 | ASF_MODIFY); + setter->flags |= ASF_SINGLE1 | ASF_REMOVE; + setter->set_single = &hws_action_setter_single; + setter->idx_single = i; + break; + + case MLX5HWS_ACTION_TYP_INSERT_HEADER: + case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: + /* Double insert header with pointer */ + setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); + setter->flags |= ASF_DOUBLE | ASF_INSERT; + setter->set_double = &hws_action_setter_insert_ptr; + setter->idx_double = i; + break; + + case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: + /* Single remove + Double insert header with pointer */ + setter = hws_action_setter_find_first(last_setter, + ASF_SINGLE1 | ASF_DOUBLE); + setter->flags |= ASF_SINGLE1 | ASF_DOUBLE; + setter->set_double = &hws_action_setter_insert_ptr; + setter->idx_double = i; + setter->set_single = &hws_action_setter_common_decap; + setter->idx_single = i; + break; + + case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: + /* Double modify header list with remove and push inline */ + setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); + setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_INSERT; + setter->set_double = &hws_action_setter_tnl_l3_to_l2; + setter->idx_double = i; + break; + + case MLX5HWS_ACTION_TYP_TAG: + /* Single TAG action, search for any room from the start */ + setter = hws_action_setter_find_first(start_setter, ASF_SINGLE1); + setter->flags |= ASF_SINGLE1; + setter->set_single = &hws_action_setter_tag; + setter->idx_single = i; + break; + + case MLX5HWS_ACTION_TYP_CTR: + /* Control counter action + * TODO: Current counter executed first. Support is needed + * for single ation counter action which is done last. + * Example: Decap + CTR + */ + setter = hws_action_setter_find_first(start_setter, ASF_CTR); + setter->flags |= ASF_CTR; + setter->set_ctr = &hws_action_setter_ctrl_ctr; + setter->idx_ctr = i; + break; + default: + pr_warn("HWS: Invalid action type in processingaction template: action_type[%d]=%d\n", + i, action_type[i]); + return -EOPNOTSUPP; + } + + last_setter = max(setter, last_setter); + } + + /* Set default hit on the last STE if no hit action provided */ + if (!(last_setter->flags & ASF_HIT)) + last_setter->set_hit = &hws_action_setter_default_hit; + + at->num_of_action_stes = last_setter - start_setter + 1; + + /* Check if action template doesn't require any action DWs */ + at->only_term = (at->num_of_action_stes == 1) && + !(last_setter->flags & ~(ASF_CTR | ASF_HIT)); + + return 0; +} + +struct mlx5hws_action_template * +mlx5hws_action_template_create(enum mlx5hws_action_type action_type[]) +{ + struct mlx5hws_action_template *at; + u8 num_actions = 0; + int i; + + at = kzalloc(sizeof(*at), GFP_KERNEL); + if (!at) + return NULL; + + while (action_type[num_actions++] != MLX5HWS_ACTION_TYP_LAST) + ; + + at->num_actions = num_actions - 1; + at->action_type_arr = kcalloc(num_actions, sizeof(*action_type), GFP_KERNEL); + if (!at->action_type_arr) + goto free_at; + + for (i = 0; i < num_actions; i++) + at->action_type_arr[i] = action_type[i]; + + return at; + +free_at: + kfree(at); + return NULL; +} + +int mlx5hws_action_template_destroy(struct mlx5hws_action_template *at) +{ + kfree(at->action_type_arr); + kfree(at); + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.h new file mode 100644 index 00000000000000..e8f562c3182671 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.h @@ -0,0 +1,307 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_ACTION_H_ +#define HWS_ACTION_H_ + +/* Max number of STEs needed for a rule (including match) */ +#define MLX5HWS_ACTION_MAX_STE 20 + +/* Max number of internal subactions of ipv6_ext */ +#define MLX5HWS_ACTION_IPV6_EXT_MAX_SA 4 + +enum mlx5hws_action_stc_idx { + MLX5HWS_ACTION_STC_IDX_CTRL = 0, + MLX5HWS_ACTION_STC_IDX_HIT = 1, + MLX5HWS_ACTION_STC_IDX_DW5 = 2, + MLX5HWS_ACTION_STC_IDX_DW6 = 3, + MLX5HWS_ACTION_STC_IDX_DW7 = 4, + MLX5HWS_ACTION_STC_IDX_MAX = 5, + /* STC Jumvo STE combo: CTR, Hit */ + MLX5HWS_ACTION_STC_IDX_LAST_JUMBO_STE = 1, + /* STC combo1: CTR, SINGLE, DOUBLE, Hit */ + MLX5HWS_ACTION_STC_IDX_LAST_COMBO1 = 3, + /* STC combo2: CTR, 3 x SINGLE, Hit */ + MLX5HWS_ACTION_STC_IDX_LAST_COMBO2 = 4, + /* STC combo2: CTR, TRIPLE, Hit */ + MLX5HWS_ACTION_STC_IDX_LAST_COMBO3 = 2, +}; + +enum mlx5hws_action_offset { + MLX5HWS_ACTION_OFFSET_DW0 = 0, + MLX5HWS_ACTION_OFFSET_DW5 = 5, + MLX5HWS_ACTION_OFFSET_DW6 = 6, + MLX5HWS_ACTION_OFFSET_DW7 = 7, + MLX5HWS_ACTION_OFFSET_HIT = 3, + MLX5HWS_ACTION_OFFSET_HIT_LSB = 4, +}; + +enum { + MLX5HWS_ACTION_DOUBLE_SIZE = 8, + MLX5HWS_ACTION_INLINE_DATA_SIZE = 4, + MLX5HWS_ACTION_HDR_LEN_L2_MACS = 12, + MLX5HWS_ACTION_HDR_LEN_L2_VLAN = 4, + MLX5HWS_ACTION_HDR_LEN_L2_ETHER = 2, + MLX5HWS_ACTION_HDR_LEN_L2 = (MLX5HWS_ACTION_HDR_LEN_L2_MACS + + MLX5HWS_ACTION_HDR_LEN_L2_ETHER), + MLX5HWS_ACTION_HDR_LEN_L2_W_VLAN = (MLX5HWS_ACTION_HDR_LEN_L2 + + MLX5HWS_ACTION_HDR_LEN_L2_VLAN), + MLX5HWS_ACTION_REFORMAT_DATA_SIZE = 64, + DECAP_L3_NUM_ACTIONS_W_NO_VLAN = 6, + DECAP_L3_NUM_ACTIONS_W_VLAN = 7, +}; + +enum mlx5hws_action_setter_flag { + ASF_SINGLE1 = 1 << 0, + ASF_SINGLE2 = 1 << 1, + ASF_SINGLE3 = 1 << 2, + ASF_DOUBLE = ASF_SINGLE2 | ASF_SINGLE3, + ASF_TRIPLE = ASF_SINGLE1 | ASF_DOUBLE, + ASF_INSERT = 1 << 3, + ASF_REMOVE = 1 << 4, + ASF_MODIFY = 1 << 5, + ASF_CTR = 1 << 6, + ASF_HIT = 1 << 7, +}; + +struct mlx5hws_action_default_stc { + struct mlx5hws_pool_chunk nop_ctr; + struct mlx5hws_pool_chunk nop_dw5; + struct mlx5hws_pool_chunk nop_dw6; + struct mlx5hws_pool_chunk nop_dw7; + struct mlx5hws_pool_chunk default_hit; + u32 refcount; +}; + +struct mlx5hws_action_shared_stc { + struct mlx5hws_pool_chunk stc_chunk; + u32 refcount; +}; + +struct mlx5hws_actions_apply_data { + struct mlx5hws_send_engine *queue; + struct mlx5hws_rule_action *rule_action; + __be32 *wqe_data; + struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; + u32 jump_to_action_stc; + struct mlx5hws_context_common_res *common_res; + enum mlx5hws_table_type tbl_type; + u32 next_direct_idx; + u8 require_dep; +}; + +struct mlx5hws_actions_wqe_setter; + +typedef void (*mlx5hws_action_setter_fp)(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter); + +struct mlx5hws_actions_wqe_setter { + mlx5hws_action_setter_fp set_single; + mlx5hws_action_setter_fp set_double; + mlx5hws_action_setter_fp set_triple; + mlx5hws_action_setter_fp set_hit; + mlx5hws_action_setter_fp set_ctr; + u8 idx_single; + u8 idx_double; + u8 idx_triple; + u8 idx_ctr; + u8 idx_hit; + u8 stage_idx; + u8 flags; +}; + +struct mlx5hws_action_template { + struct mlx5hws_actions_wqe_setter setters[MLX5HWS_ACTION_MAX_STE]; + enum mlx5hws_action_type *action_type_arr; + u8 num_of_action_stes; + u8 num_actions; + u8 only_term; +}; + +struct mlx5hws_action { + u8 type; + u8 flags; + struct mlx5hws_context *ctx; + union { + struct { + struct mlx5hws_pool_chunk stc[MLX5HWS_TABLE_TYPE_MAX]; + union { + struct { + u32 pat_id; + u32 arg_id; + __be64 single_action; + u32 nope_locations; + u8 num_of_patterns; + u8 single_action_type; + u8 num_of_actions; + u8 max_num_of_actions; + u8 require_reparse; + } modify_header; + struct { + u32 arg_id; + u32 header_size; + u16 max_hdr_sz; + u8 num_of_hdrs; + u8 anchor; + u8 e_anchor; + u8 offset; + bool encap; + u8 require_reparse; + } reformat; + struct { + u32 obj_id; + u8 return_reg_id; + } aso; + struct { + u16 vport_num; + u16 esw_owner_vhca_id; + bool esw_owner_vhca_id_valid; + } vport; + struct { + u32 obj_id; + } dest_obj; + struct { + struct mlx5hws_cmd_forward_tbl *fw_island; + size_t num_dest; + struct mlx5hws_cmd_set_fte_dest *dest_list; + } dest_array; + struct { + u8 type; + u8 start_anchor; + u8 end_anchor; + u8 num_of_words; + bool decap; + } insert_hdr; + struct { + /* PRM start anchor from which header will be removed */ + u8 anchor; + /* Header remove offset in bytes, from the start + * anchor to the location where remove header starts. + */ + u8 offset; + /* Indicates the removed header size in bytes */ + size_t size; + } remove_header; + struct { + struct mlx5hws_matcher_action_ste *table_ste; + struct mlx5hws_action *hit_ft_action; + struct mlx5hws_definer *definer; + } range; + }; + }; + + struct ibv_flow_action *flow_action; + u32 obj_id; + struct ibv_qp *qp; + }; +}; + +const char *mlx5hws_action_type_to_str(enum mlx5hws_action_type action_type); + +int mlx5hws_action_get_default_stc(struct mlx5hws_context *ctx, + u8 tbl_type); + +void mlx5hws_action_put_default_stc(struct mlx5hws_context *ctx, + u8 tbl_type); + +void mlx5hws_action_prepare_decap_l3_data(u8 *src, u8 *dst, + u16 num_of_actions); + +int mlx5hws_action_template_process(struct mlx5hws_action_template *at); + +bool mlx5hws_action_check_combo(struct mlx5hws_context *ctx, + enum mlx5hws_action_type *user_actions, + enum mlx5hws_table_type table_type); + +int mlx5hws_action_alloc_single_stc(struct mlx5hws_context *ctx, + struct mlx5hws_cmd_stc_modify_attr *stc_attr, + u32 table_type, + struct mlx5hws_pool_chunk *stc); + +void mlx5hws_action_free_single_stc(struct mlx5hws_context *ctx, + u32 table_type, + struct mlx5hws_pool_chunk *stc); + +static inline void +mlx5hws_action_setter_default_single(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = + htonl(apply->common_res->default_stc->nop_dw5.offset); +} + +static inline void +mlx5hws_action_setter_default_double(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = + htonl(apply->common_res->default_stc->nop_dw6.offset); + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = + htonl(apply->common_res->default_stc->nop_dw7.offset); +} + +static inline void +mlx5hws_action_setter_default_ctr(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter) +{ + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW0] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] = + htonl(apply->common_res->default_stc->nop_ctr.offset); +} + +static inline void +mlx5hws_action_apply_setter(struct mlx5hws_actions_apply_data *apply, + struct mlx5hws_actions_wqe_setter *setter, + bool is_jumbo) +{ + u8 num_of_actions; + + /* Set control counter */ + if (setter->set_ctr) + setter->set_ctr(apply, setter); + else + mlx5hws_action_setter_default_ctr(apply, setter); + + if (!is_jumbo) { + if (unlikely(setter->set_triple)) { + /* Set triple on match */ + setter->set_triple(apply, setter); + num_of_actions = MLX5HWS_ACTION_STC_IDX_LAST_COMBO3; + } else { + /* Set single and double on match */ + if (setter->set_single) + setter->set_single(apply, setter); + else + mlx5hws_action_setter_default_single(apply, setter); + + if (setter->set_double) + setter->set_double(apply, setter); + else + mlx5hws_action_setter_default_double(apply, setter); + + num_of_actions = setter->set_double ? + MLX5HWS_ACTION_STC_IDX_LAST_COMBO1 : + MLX5HWS_ACTION_STC_IDX_LAST_COMBO2; + } + } else { + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; + apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = 0; + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; + num_of_actions = MLX5HWS_ACTION_STC_IDX_LAST_JUMBO_STE; + } + + /* Set next/final hit action */ + setter->set_hit(apply, setter); + + /* Set number of actions */ + apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] |= + htonl(num_of_actions << 29); +} + +#endif /* HWS_ACTION_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.c new file mode 100644 index 00000000000000..b9aef80ba094bb --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" +#include "buddy.h" + +static int hws_buddy_init(struct mlx5hws_buddy_mem *buddy, u32 max_order) +{ + int i, s, ret = 0; + + buddy->max_order = max_order; + + buddy->bitmap = kcalloc(buddy->max_order + 1, + sizeof(*buddy->bitmap), + GFP_KERNEL); + if (!buddy->bitmap) + return -ENOMEM; + + buddy->num_free = kcalloc(buddy->max_order + 1, + sizeof(*buddy->num_free), + GFP_KERNEL); + if (!buddy->num_free) { + ret = -ENOMEM; + goto err_out_free_bits; + } + + for (i = 0; i <= (int)buddy->max_order; ++i) { + s = 1 << (buddy->max_order - i); + + buddy->bitmap[i] = bitmap_zalloc(s, GFP_KERNEL); + if (!buddy->bitmap[i]) { + ret = -ENOMEM; + goto err_out_free_num_free; + } + } + + bitmap_set(buddy->bitmap[buddy->max_order], 0, 1); + buddy->num_free[buddy->max_order] = 1; + + return 0; + +err_out_free_num_free: + for (i = 0; i <= (int)buddy->max_order; ++i) + bitmap_free(buddy->bitmap[i]); + + kfree(buddy->num_free); + +err_out_free_bits: + kfree(buddy->bitmap); + return ret; +} + +struct mlx5hws_buddy_mem *mlx5hws_buddy_create(u32 max_order) +{ + struct mlx5hws_buddy_mem *buddy; + + buddy = kzalloc(sizeof(*buddy), GFP_KERNEL); + if (!buddy) + return NULL; + + if (hws_buddy_init(buddy, max_order)) + goto free_buddy; + + return buddy; + +free_buddy: + kfree(buddy); + return NULL; +} + +void mlx5hws_buddy_cleanup(struct mlx5hws_buddy_mem *buddy) +{ + int i; + + for (i = 0; i <= (int)buddy->max_order; ++i) + bitmap_free(buddy->bitmap[i]); + + kfree(buddy->num_free); + kfree(buddy->bitmap); +} + +static int hws_buddy_find_free_seg(struct mlx5hws_buddy_mem *buddy, + u32 start_order, + u32 *segment, + u32 *order) +{ + unsigned int seg, order_iter, m; + + for (order_iter = start_order; + order_iter <= buddy->max_order; ++order_iter) { + if (!buddy->num_free[order_iter]) + continue; + + m = 1 << (buddy->max_order - order_iter); + seg = find_first_bit(buddy->bitmap[order_iter], m); + + if (WARN(seg >= m, + "ICM Buddy: failed finding free mem for order %d\n", + order_iter)) + return -ENOMEM; + + break; + } + + if (order_iter > buddy->max_order) + return -ENOMEM; + + *segment = seg; + *order = order_iter; + return 0; +} + +int mlx5hws_buddy_alloc_mem(struct mlx5hws_buddy_mem *buddy, u32 order) +{ + u32 seg, order_iter, err; + + err = hws_buddy_find_free_seg(buddy, order, &seg, &order_iter); + if (err) + return err; + + bitmap_clear(buddy->bitmap[order_iter], seg, 1); + --buddy->num_free[order_iter]; + + while (order_iter > order) { + --order_iter; + seg <<= 1; + bitmap_set(buddy->bitmap[order_iter], seg ^ 1, 1); + ++buddy->num_free[order_iter]; + } + + seg <<= order; + + return seg; +} + +void mlx5hws_buddy_free_mem(struct mlx5hws_buddy_mem *buddy, u32 seg, u32 order) +{ + seg >>= order; + + while (test_bit(seg ^ 1, buddy->bitmap[order])) { + bitmap_clear(buddy->bitmap[order], seg ^ 1, 1); + --buddy->num_free[order]; + seg >>= 1; + ++order; + } + + bitmap_set(buddy->bitmap[order], seg, 1); + ++buddy->num_free[order]; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.h new file mode 100644 index 00000000000000..ef6b223677aa4d --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/buddy.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_BUDDY_H_ +#define HWS_BUDDY_H_ + +struct mlx5hws_buddy_mem { + unsigned long **bitmap; + unsigned int *num_free; + u32 max_order; +}; + +struct mlx5hws_buddy_mem *mlx5hws_buddy_create(u32 max_order); + +void mlx5hws_buddy_cleanup(struct mlx5hws_buddy_mem *buddy); + +int mlx5hws_buddy_alloc_mem(struct mlx5hws_buddy_mem *buddy, u32 order); + +void mlx5hws_buddy_free_mem(struct mlx5hws_buddy_mem *buddy, u32 seg, u32 order); + +#endif /* HWS_BUDDY_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c new file mode 100644 index 00000000000000..baacf662c0ab89 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c @@ -0,0 +1,995 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +static u16 hws_bwc_gen_queue_idx(struct mlx5hws_context *ctx) +{ + /* assign random queue */ + return get_random_u8() % mlx5hws_bwc_queues(ctx); +} + +static u16 +hws_bwc_get_burst_th(struct mlx5hws_context *ctx, u16 queue_id) +{ + return min(ctx->send_queue[queue_id].num_entries / 2, + MLX5HWS_BWC_MATCHER_REHASH_BURST_TH); +} + +static struct mutex * +hws_bwc_get_queue_lock(struct mlx5hws_context *ctx, u16 idx) +{ + return &ctx->bwc_send_queue_locks[idx]; +} + +static void hws_bwc_lock_all_queues(struct mlx5hws_context *ctx) +{ + u16 bwc_queues = mlx5hws_bwc_queues(ctx); + struct mutex *queue_lock; /* Protect the queue */ + int i; + + for (i = 0; i < bwc_queues; i++) { + queue_lock = hws_bwc_get_queue_lock(ctx, i); + mutex_lock(queue_lock); + } +} + +static void hws_bwc_unlock_all_queues(struct mlx5hws_context *ctx) +{ + u16 bwc_queues = mlx5hws_bwc_queues(ctx); + struct mutex *queue_lock; /* Protect the queue */ + int i = bwc_queues; + + while (i--) { + queue_lock = hws_bwc_get_queue_lock(ctx, i); + mutex_unlock(queue_lock); + } +} + +static void hws_bwc_matcher_init_attr(struct mlx5hws_matcher_attr *attr, + u32 priority, + u8 size_log) +{ + memset(attr, 0, sizeof(*attr)); + + attr->priority = priority; + attr->optimize_using_rule_idx = 0; + attr->mode = MLX5HWS_MATCHER_RESOURCE_MODE_RULE; + attr->optimize_flow_src = MLX5HWS_MATCHER_FLOW_SRC_ANY; + attr->insert_mode = MLX5HWS_MATCHER_INSERT_BY_HASH; + attr->distribute_mode = MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH; + attr->rule.num_log = size_log; + attr->resizable = true; + attr->max_num_of_at_attach = MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM; +} + +int mlx5hws_bwc_matcher_create_simple(struct mlx5hws_bwc_matcher *bwc_matcher, + struct mlx5hws_table *table, + u32 priority, + u8 match_criteria_enable, + struct mlx5hws_match_parameters *mask, + enum mlx5hws_action_type action_types[]) +{ + enum mlx5hws_action_type init_action_types[1] = { MLX5HWS_ACTION_TYP_LAST }; + struct mlx5hws_context *ctx = table->ctx; + u16 bwc_queues = mlx5hws_bwc_queues(ctx); + struct mlx5hws_matcher_attr attr = {0}; + int i; + + bwc_matcher->rules = kcalloc(bwc_queues, sizeof(*bwc_matcher->rules), GFP_KERNEL); + if (!bwc_matcher->rules) + goto err; + + for (i = 0; i < bwc_queues; i++) + INIT_LIST_HEAD(&bwc_matcher->rules[i]); + + hws_bwc_matcher_init_attr(&attr, + priority, + MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG); + + bwc_matcher->priority = priority; + bwc_matcher->size_log = MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG; + + /* create dummy action template */ + bwc_matcher->at[0] = + mlx5hws_action_template_create(action_types ? + action_types : init_action_types); + if (!bwc_matcher->at[0]) { + mlx5hws_err(table->ctx, "BWC matcher: failed creating action template\n"); + goto free_bwc_matcher_rules; + } + + bwc_matcher->num_of_at = 1; + + bwc_matcher->mt = mlx5hws_match_template_create(ctx, + mask->match_buf, + mask->match_sz, + match_criteria_enable); + if (!bwc_matcher->mt) { + mlx5hws_err(table->ctx, "BWC matcher: failed creating match template\n"); + goto free_at; + } + + bwc_matcher->matcher = mlx5hws_matcher_create(table, + &bwc_matcher->mt, 1, + &bwc_matcher->at[0], + bwc_matcher->num_of_at, + &attr); + if (!bwc_matcher->matcher) { + mlx5hws_err(table->ctx, "BWC matcher: failed creating HWS matcher\n"); + goto free_mt; + } + + return 0; + +free_mt: + mlx5hws_match_template_destroy(bwc_matcher->mt); +free_at: + mlx5hws_action_template_destroy(bwc_matcher->at[0]); +free_bwc_matcher_rules: + kfree(bwc_matcher->rules); +err: + return -EINVAL; +} + +struct mlx5hws_bwc_matcher * +mlx5hws_bwc_matcher_create(struct mlx5hws_table *table, + u32 priority, + u8 match_criteria_enable, + struct mlx5hws_match_parameters *mask) +{ + struct mlx5hws_bwc_matcher *bwc_matcher; + bool is_complex; + int ret; + + if (!mlx5hws_context_bwc_supported(table->ctx)) { + mlx5hws_err(table->ctx, + "BWC matcher: context created w/o BWC API compatibility\n"); + return NULL; + } + + bwc_matcher = kzalloc(sizeof(*bwc_matcher), GFP_KERNEL); + if (!bwc_matcher) + return NULL; + + /* Check if the required match params can be all matched + * in single STE, otherwise complex matcher is needed. + */ + + is_complex = mlx5hws_bwc_match_params_is_complex(table->ctx, match_criteria_enable, mask); + if (is_complex) + ret = mlx5hws_bwc_matcher_create_complex(bwc_matcher, + table, + priority, + match_criteria_enable, + mask); + else + ret = mlx5hws_bwc_matcher_create_simple(bwc_matcher, + table, + priority, + match_criteria_enable, + mask, + NULL); + if (ret) + goto free_bwc_matcher; + + return bwc_matcher; + +free_bwc_matcher: + kfree(bwc_matcher); + + return NULL; +} + +int mlx5hws_bwc_matcher_destroy_simple(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + int i; + + mlx5hws_matcher_destroy(bwc_matcher->matcher); + bwc_matcher->matcher = NULL; + + for (i = 0; i < bwc_matcher->num_of_at; i++) + mlx5hws_action_template_destroy(bwc_matcher->at[i]); + + mlx5hws_match_template_destroy(bwc_matcher->mt); + kfree(bwc_matcher->rules); + + return 0; +} + +int mlx5hws_bwc_matcher_destroy(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + if (bwc_matcher->num_of_rules) + mlx5hws_err(bwc_matcher->matcher->tbl->ctx, + "BWC matcher destroy: matcher still has %d rules\n", + bwc_matcher->num_of_rules); + + mlx5hws_bwc_matcher_destroy_simple(bwc_matcher); + + kfree(bwc_matcher); + return 0; +} + +static int hws_bwc_queue_poll(struct mlx5hws_context *ctx, + u16 queue_id, + u32 *pending_rules, + bool drain) +{ + struct mlx5hws_flow_op_result comp[MLX5HWS_BWC_MATCHER_REHASH_BURST_TH]; + u16 burst_th = hws_bwc_get_burst_th(ctx, queue_id); + bool got_comp = *pending_rules >= burst_th; + bool queue_full; + int err = 0; + int ret; + int i; + + /* Check if there are any completions at all */ + if (!got_comp && !drain) + return 0; + + queue_full = mlx5hws_send_engine_full(&ctx->send_queue[queue_id]); + while (queue_full || ((got_comp || drain) && *pending_rules)) { + ret = mlx5hws_send_queue_poll(ctx, queue_id, comp, burst_th); + if (unlikely(ret < 0)) { + mlx5hws_err(ctx, "BWC poll error: polling queue %d returned %d\n", + queue_id, ret); + return -EINVAL; + } + + if (ret) { + (*pending_rules) -= ret; + for (i = 0; i < ret; i++) { + if (unlikely(comp[i].status != MLX5HWS_FLOW_OP_SUCCESS)) { + mlx5hws_err(ctx, + "BWC poll error: polling queue %d returned completion with error\n", + queue_id); + err = -EINVAL; + } + } + queue_full = false; + } + + got_comp = !!ret; + } + + return err; +} + +void +mlx5hws_bwc_rule_fill_attr(struct mlx5hws_bwc_matcher *bwc_matcher, + u16 bwc_queue_idx, + u32 flow_source, + struct mlx5hws_rule_attr *rule_attr) +{ + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + + /* no use of INSERT_BY_INDEX in bwc rule */ + rule_attr->rule_idx = 0; + + /* notify HW at each rule insertion/deletion */ + rule_attr->burst = 0; + + /* We don't need user data, but the API requires it to exist */ + rule_attr->user_data = (void *)0xFACADE; + + rule_attr->queue_id = mlx5hws_bwc_get_queue_id(ctx, bwc_queue_idx); + rule_attr->flow_source = flow_source; +} + +struct mlx5hws_bwc_rule * +mlx5hws_bwc_rule_alloc(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + struct mlx5hws_bwc_rule *bwc_rule; + + bwc_rule = kzalloc(sizeof(*bwc_rule), GFP_KERNEL); + if (unlikely(!bwc_rule)) + goto out_err; + + bwc_rule->rule = kzalloc(sizeof(*bwc_rule->rule), GFP_KERNEL); + if (unlikely(!bwc_rule->rule)) + goto free_rule; + + bwc_rule->bwc_matcher = bwc_matcher; + return bwc_rule; + +free_rule: + kfree(bwc_rule); +out_err: + return NULL; +} + +void mlx5hws_bwc_rule_free(struct mlx5hws_bwc_rule *bwc_rule) +{ + if (likely(bwc_rule->rule)) + kfree(bwc_rule->rule); + kfree(bwc_rule); +} + +static void hws_bwc_rule_list_add(struct mlx5hws_bwc_rule *bwc_rule, u16 idx) +{ + struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; + + bwc_matcher->num_of_rules++; + bwc_rule->bwc_queue_idx = idx; + list_add(&bwc_rule->list_node, &bwc_matcher->rules[idx]); +} + +static void hws_bwc_rule_list_remove(struct mlx5hws_bwc_rule *bwc_rule) +{ + struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; + + bwc_matcher->num_of_rules--; + list_del_init(&bwc_rule->list_node); +} + +static int +hws_bwc_rule_destroy_hws_async(struct mlx5hws_bwc_rule *bwc_rule, + struct mlx5hws_rule_attr *attr) +{ + return mlx5hws_rule_destroy(bwc_rule->rule, attr); +} + +static int +hws_bwc_rule_destroy_hws_sync(struct mlx5hws_bwc_rule *bwc_rule, + struct mlx5hws_rule_attr *rule_attr) +{ + struct mlx5hws_context *ctx = bwc_rule->bwc_matcher->matcher->tbl->ctx; + struct mlx5hws_flow_op_result completion; + int ret; + + ret = hws_bwc_rule_destroy_hws_async(bwc_rule, rule_attr); + if (unlikely(ret)) + return ret; + + do { + ret = mlx5hws_send_queue_poll(ctx, rule_attr->queue_id, &completion, 1); + } while (ret != 1); + + if (unlikely(completion.status != MLX5HWS_FLOW_OP_SUCCESS || + (bwc_rule->rule->status != MLX5HWS_RULE_STATUS_DELETED && + bwc_rule->rule->status != MLX5HWS_RULE_STATUS_DELETING))) { + mlx5hws_err(ctx, "Failed destroying BWC rule: completion %d, rule status %d\n", + completion.status, bwc_rule->rule->status); + return -EINVAL; + } + + return 0; +} + +int mlx5hws_bwc_rule_destroy_simple(struct mlx5hws_bwc_rule *bwc_rule) +{ + struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + u16 idx = bwc_rule->bwc_queue_idx; + struct mlx5hws_rule_attr attr; + struct mutex *queue_lock; /* Protect the queue */ + int ret; + + mlx5hws_bwc_rule_fill_attr(bwc_matcher, idx, 0, &attr); + + queue_lock = hws_bwc_get_queue_lock(ctx, idx); + + mutex_lock(queue_lock); + + ret = hws_bwc_rule_destroy_hws_sync(bwc_rule, &attr); + hws_bwc_rule_list_remove(bwc_rule); + + mutex_unlock(queue_lock); + + return ret; +} + +int mlx5hws_bwc_rule_destroy(struct mlx5hws_bwc_rule *bwc_rule) +{ + int ret; + + ret = mlx5hws_bwc_rule_destroy_simple(bwc_rule); + + mlx5hws_bwc_rule_free(bwc_rule); + return ret; +} + +static int +hws_bwc_rule_create_async(struct mlx5hws_bwc_rule *bwc_rule, + u32 *match_param, + u8 at_idx, + struct mlx5hws_rule_action rule_actions[], + struct mlx5hws_rule_attr *rule_attr) +{ + return mlx5hws_rule_create(bwc_rule->bwc_matcher->matcher, + 0, /* only one match template supported */ + match_param, + at_idx, + rule_actions, + rule_attr, + bwc_rule->rule); +} + +static int +hws_bwc_rule_create_sync(struct mlx5hws_bwc_rule *bwc_rule, + u32 *match_param, + u8 at_idx, + struct mlx5hws_rule_action rule_actions[], + struct mlx5hws_rule_attr *rule_attr) + +{ + struct mlx5hws_context *ctx = bwc_rule->bwc_matcher->matcher->tbl->ctx; + u32 expected_completions = 1; + int ret; + + ret = hws_bwc_rule_create_async(bwc_rule, match_param, + at_idx, rule_actions, + rule_attr); + if (unlikely(ret)) + return ret; + + ret = hws_bwc_queue_poll(ctx, rule_attr->queue_id, &expected_completions, true); + + return ret; +} + +static int +hws_bwc_rule_update_sync(struct mlx5hws_bwc_rule *bwc_rule, + u8 at_idx, + struct mlx5hws_rule_action rule_actions[], + struct mlx5hws_rule_attr *rule_attr) +{ + struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + u32 expected_completions = 1; + int ret; + + ret = mlx5hws_rule_action_update(bwc_rule->rule, + at_idx, + rule_actions, + rule_attr); + if (unlikely(ret)) + return ret; + + ret = hws_bwc_queue_poll(ctx, rule_attr->queue_id, &expected_completions, true); + if (unlikely(ret)) + mlx5hws_err(ctx, "Failed updating BWC rule (%d)\n", ret); + + return ret; +} + +static bool +hws_bwc_matcher_size_maxed_out(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + struct mlx5hws_cmd_query_caps *caps = bwc_matcher->matcher->tbl->ctx->caps; + + return bwc_matcher->size_log + MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH >= + caps->ste_alloc_log_max - 1; +} + +static bool +hws_bwc_matcher_rehash_size_needed(struct mlx5hws_bwc_matcher *bwc_matcher, + u32 num_of_rules) +{ + if (unlikely(hws_bwc_matcher_size_maxed_out(bwc_matcher))) + return false; + + if (unlikely((num_of_rules * 100 / MLX5HWS_BWC_MATCHER_REHASH_PERCENT_TH) >= + (1UL << bwc_matcher->size_log))) + return true; + + return false; +} + +static void +hws_bwc_rule_actions_to_action_types(struct mlx5hws_rule_action rule_actions[], + enum mlx5hws_action_type action_types[]) +{ + int i = 0; + + for (i = 0; + rule_actions[i].action && (rule_actions[i].action->type != MLX5HWS_ACTION_TYP_LAST); + i++) { + action_types[i] = (enum mlx5hws_action_type)rule_actions[i].action->type; + } + + action_types[i] = MLX5HWS_ACTION_TYP_LAST; +} + +static int +hws_bwc_matcher_extend_at(struct mlx5hws_bwc_matcher *bwc_matcher, + struct mlx5hws_rule_action rule_actions[]) +{ + enum mlx5hws_action_type action_types[MLX5HWS_BWC_MAX_ACTS]; + + hws_bwc_rule_actions_to_action_types(rule_actions, action_types); + + bwc_matcher->at[bwc_matcher->num_of_at] = + mlx5hws_action_template_create(action_types); + + if (unlikely(!bwc_matcher->at[bwc_matcher->num_of_at])) + return -ENOMEM; + + bwc_matcher->num_of_at++; + return 0; +} + +static int +hws_bwc_matcher_extend_size(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + struct mlx5hws_cmd_query_caps *caps = ctx->caps; + + if (unlikely(hws_bwc_matcher_size_maxed_out(bwc_matcher))) { + mlx5hws_err(ctx, "Can't resize matcher: depth exceeds limit %d\n", + caps->rtc_log_depth_max); + return -ENOMEM; + } + + bwc_matcher->size_log = + min(bwc_matcher->size_log + MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP, + caps->ste_alloc_log_max - MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH); + + return 0; +} + +static int +hws_bwc_matcher_find_at(struct mlx5hws_bwc_matcher *bwc_matcher, + struct mlx5hws_rule_action rule_actions[]) +{ + enum mlx5hws_action_type *action_type_arr; + int i, j; + + /* start from index 1 - first action template is a dummy */ + for (i = 1; i < bwc_matcher->num_of_at; i++) { + j = 0; + action_type_arr = bwc_matcher->at[i]->action_type_arr; + + while (rule_actions[j].action && + rule_actions[j].action->type != MLX5HWS_ACTION_TYP_LAST) { + if (action_type_arr[j] != rule_actions[j].action->type) + break; + j++; + } + + if (action_type_arr[j] == MLX5HWS_ACTION_TYP_LAST && + (!rule_actions[j].action || + rule_actions[j].action->type == MLX5HWS_ACTION_TYP_LAST)) + return i; + } + + return -1; +} + +static int hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + u16 bwc_queues = mlx5hws_bwc_queues(ctx); + struct mlx5hws_bwc_rule **bwc_rules; + struct mlx5hws_rule_attr rule_attr; + u32 *pending_rules; + int i, j, ret = 0; + bool all_done; + u16 burst_th; + + mlx5hws_bwc_rule_fill_attr(bwc_matcher, 0, 0, &rule_attr); + + pending_rules = kcalloc(bwc_queues, sizeof(*pending_rules), GFP_KERNEL); + if (!pending_rules) + return -ENOMEM; + + bwc_rules = kcalloc(bwc_queues, sizeof(*bwc_rules), GFP_KERNEL); + if (!bwc_rules) { + ret = -ENOMEM; + goto free_pending_rules; + } + + for (i = 0; i < bwc_queues; i++) { + if (list_empty(&bwc_matcher->rules[i])) + bwc_rules[i] = NULL; + else + bwc_rules[i] = list_first_entry(&bwc_matcher->rules[i], + struct mlx5hws_bwc_rule, + list_node); + } + + do { + all_done = true; + + for (i = 0; i < bwc_queues; i++) { + rule_attr.queue_id = mlx5hws_bwc_get_queue_id(ctx, i); + burst_th = hws_bwc_get_burst_th(ctx, rule_attr.queue_id); + + for (j = 0; j < burst_th && bwc_rules[i]; j++) { + rule_attr.burst = !!((j + 1) % burst_th); + ret = mlx5hws_matcher_resize_rule_move(bwc_matcher->matcher, + bwc_rules[i]->rule, + &rule_attr); + if (unlikely(ret)) { + mlx5hws_err(ctx, + "Moving BWC rule failed during rehash (%d)\n", + ret); + goto free_bwc_rules; + } + + all_done = false; + pending_rules[i]++; + bwc_rules[i] = list_is_last(&bwc_rules[i]->list_node, + &bwc_matcher->rules[i]) ? + NULL : list_next_entry(bwc_rules[i], list_node); + + ret = hws_bwc_queue_poll(ctx, rule_attr.queue_id, + &pending_rules[i], false); + if (unlikely(ret)) + goto free_bwc_rules; + } + } + } while (!all_done); + + /* drain all the bwc queues */ + for (i = 0; i < bwc_queues; i++) { + if (pending_rules[i]) { + u16 queue_id = mlx5hws_bwc_get_queue_id(ctx, i); + + mlx5hws_send_engine_flush_queue(&ctx->send_queue[queue_id]); + ret = hws_bwc_queue_poll(ctx, queue_id, + &pending_rules[i], true); + if (unlikely(ret)) + goto free_bwc_rules; + } + } + +free_bwc_rules: + kfree(bwc_rules); +free_pending_rules: + kfree(pending_rules); + + return ret; +} + +static int hws_bwc_matcher_move_all(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + return hws_bwc_matcher_move_all_simple(bwc_matcher); +} + +static int hws_bwc_matcher_move(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + struct mlx5hws_matcher_attr matcher_attr = {0}; + struct mlx5hws_matcher *old_matcher; + struct mlx5hws_matcher *new_matcher; + int ret; + + hws_bwc_matcher_init_attr(&matcher_attr, + bwc_matcher->priority, + bwc_matcher->size_log); + + old_matcher = bwc_matcher->matcher; + new_matcher = mlx5hws_matcher_create(old_matcher->tbl, + &bwc_matcher->mt, 1, + bwc_matcher->at, + bwc_matcher->num_of_at, + &matcher_attr); + if (!new_matcher) { + mlx5hws_err(ctx, "Rehash error: matcher creation failed\n"); + return -ENOMEM; + } + + ret = mlx5hws_matcher_resize_set_target(old_matcher, new_matcher); + if (ret) { + mlx5hws_err(ctx, "Rehash error: failed setting resize target\n"); + return ret; + } + + ret = hws_bwc_matcher_move_all(bwc_matcher); + if (ret) { + mlx5hws_err(ctx, "Rehash error: moving rules failed\n"); + return -ENOMEM; + } + + bwc_matcher->matcher = new_matcher; + mlx5hws_matcher_destroy(old_matcher); + + return 0; +} + +static int +hws_bwc_matcher_rehash_size(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + int ret; + + /* If the current matcher size is already at its max size, we can't + * do the rehash. Skip it and try adding the rule again - perhaps + * there was some change. + */ + if (hws_bwc_matcher_size_maxed_out(bwc_matcher)) + return 0; + + /* It is possible that other rule has already performed rehash. + * Need to check again if we really need rehash. + * If the reason for rehash was size, but not any more - skip rehash. + */ + if (!hws_bwc_matcher_rehash_size_needed(bwc_matcher, bwc_matcher->num_of_rules)) + return 0; + + /* Now we're done all the checking - do the rehash: + * - extend match RTC size + * - create new matcher + * - move all the rules to the new matcher + * - destroy the old matcher + */ + + ret = hws_bwc_matcher_extend_size(bwc_matcher); + if (ret) + return ret; + + return hws_bwc_matcher_move(bwc_matcher); +} + +static int +hws_bwc_matcher_rehash_at(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + /* Rehash by action template doesn't require any additional checking. + * The bwc_matcher already contains the new action template. + * Just do the usual rehash: + * - create new matcher + * - move all the rules to the new matcher + * - destroy the old matcher + */ + return hws_bwc_matcher_move(bwc_matcher); +} + +int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, + u32 *match_param, + struct mlx5hws_rule_action rule_actions[], + u32 flow_source, + u16 bwc_queue_idx) +{ + struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + struct mlx5hws_rule_attr rule_attr; + struct mutex *queue_lock; /* Protect the queue */ + u32 num_of_rules; + int ret = 0; + int at_idx; + + mlx5hws_bwc_rule_fill_attr(bwc_matcher, bwc_queue_idx, flow_source, &rule_attr); + + queue_lock = hws_bwc_get_queue_lock(ctx, bwc_queue_idx); + + mutex_lock(queue_lock); + + /* check if rehash needed due to missing action template */ + at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions); + if (unlikely(at_idx < 0)) { + /* we need to extend BWC matcher action templates array */ + mutex_unlock(queue_lock); + hws_bwc_lock_all_queues(ctx); + + ret = hws_bwc_matcher_extend_at(bwc_matcher, rule_actions); + if (unlikely(ret)) { + hws_bwc_unlock_all_queues(ctx); + return ret; + } + + /* action templates array was extended, we need the last idx */ + at_idx = bwc_matcher->num_of_at - 1; + + ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher, + bwc_matcher->at[at_idx]); + if (unlikely(ret)) { + /* Action template attach failed, possibly due to + * requiring more action STEs. + * Need to attempt creating new matcher with all + * the action templates, including the new one. + */ + ret = hws_bwc_matcher_rehash_at(bwc_matcher); + if (unlikely(ret)) { + mlx5hws_action_template_destroy(bwc_matcher->at[at_idx]); + bwc_matcher->at[at_idx] = NULL; + bwc_matcher->num_of_at--; + + hws_bwc_unlock_all_queues(ctx); + + mlx5hws_err(ctx, + "BWC rule insertion: rehash AT failed (%d)\n", ret); + return ret; + } + } + + hws_bwc_unlock_all_queues(ctx); + mutex_lock(queue_lock); + } + + /* check if number of rules require rehash */ + num_of_rules = bwc_matcher->num_of_rules; + + if (unlikely(hws_bwc_matcher_rehash_size_needed(bwc_matcher, num_of_rules))) { + mutex_unlock(queue_lock); + + hws_bwc_lock_all_queues(ctx); + ret = hws_bwc_matcher_rehash_size(bwc_matcher); + hws_bwc_unlock_all_queues(ctx); + + if (ret) { + mlx5hws_err(ctx, "BWC rule insertion: rehash size [%d -> %d] failed (%d)\n", + bwc_matcher->size_log - MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP, + bwc_matcher->size_log, + ret); + return ret; + } + + mutex_lock(queue_lock); + } + + ret = hws_bwc_rule_create_sync(bwc_rule, + match_param, + at_idx, + rule_actions, + &rule_attr); + if (likely(!ret)) { + hws_bwc_rule_list_add(bwc_rule, bwc_queue_idx); + mutex_unlock(queue_lock); + return 0; /* rule inserted successfully */ + } + + /* At this point the rule wasn't added. + * It could be because there was collision, or some other problem. + * If we don't dive deeper than API, the only thing we know is that + * the status of completion is RTE_FLOW_OP_ERROR. + * Try rehash by size and insert rule again - last chance. + */ + + mutex_unlock(queue_lock); + + hws_bwc_lock_all_queues(ctx); + ret = hws_bwc_matcher_rehash_size(bwc_matcher); + hws_bwc_unlock_all_queues(ctx); + + if (ret) { + mlx5hws_err(ctx, "BWC rule insertion: rehash failed (%d)\n", ret); + return ret; + } + + /* Rehash done, but we still have that pesky rule to add */ + mutex_lock(queue_lock); + + ret = hws_bwc_rule_create_sync(bwc_rule, + match_param, + at_idx, + rule_actions, + &rule_attr); + + if (unlikely(ret)) { + mutex_unlock(queue_lock); + mlx5hws_err(ctx, "BWC rule insertion failed (%d)\n", ret); + return ret; + } + + hws_bwc_rule_list_add(bwc_rule, bwc_queue_idx); + mutex_unlock(queue_lock); + + return 0; +} + +struct mlx5hws_bwc_rule * +mlx5hws_bwc_rule_create(struct mlx5hws_bwc_matcher *bwc_matcher, + struct mlx5hws_match_parameters *params, + u32 flow_source, + struct mlx5hws_rule_action rule_actions[]) +{ + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + struct mlx5hws_bwc_rule *bwc_rule; + u16 bwc_queue_idx; + int ret; + + if (unlikely(!mlx5hws_context_bwc_supported(ctx))) { + mlx5hws_err(ctx, "BWC rule: Context created w/o BWC API compatibility\n"); + return NULL; + } + + bwc_rule = mlx5hws_bwc_rule_alloc(bwc_matcher); + if (unlikely(!bwc_rule)) + return NULL; + + bwc_queue_idx = hws_bwc_gen_queue_idx(ctx); + + ret = mlx5hws_bwc_rule_create_simple(bwc_rule, + params->match_buf, + rule_actions, + flow_source, + bwc_queue_idx); + if (unlikely(ret)) { + mlx5hws_bwc_rule_free(bwc_rule); + return NULL; + } + + return bwc_rule; +} + +static int +hws_bwc_rule_action_update(struct mlx5hws_bwc_rule *bwc_rule, + struct mlx5hws_rule_action rule_actions[]) +{ + struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + struct mlx5hws_rule_attr rule_attr; + struct mutex *queue_lock; /* Protect the queue */ + int at_idx, ret; + u16 idx; + + idx = bwc_rule->bwc_queue_idx; + + mlx5hws_bwc_rule_fill_attr(bwc_matcher, idx, 0, &rule_attr); + queue_lock = hws_bwc_get_queue_lock(ctx, idx); + + mutex_lock(queue_lock); + + /* check if rehash needed due to missing action template */ + at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions); + if (unlikely(at_idx < 0)) { + /* we need to extend BWC matcher action templates array */ + mutex_unlock(queue_lock); + hws_bwc_lock_all_queues(ctx); + + /* check again - perhaps other thread already did extend_at */ + at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions); + if (likely(at_idx < 0)) { + ret = hws_bwc_matcher_extend_at(bwc_matcher, rule_actions); + if (unlikely(ret)) { + hws_bwc_unlock_all_queues(ctx); + mlx5hws_err(ctx, "BWC rule update: failed extending AT (%d)", ret); + return -EINVAL; + } + + /* action templates array was extended, we need the last idx */ + at_idx = bwc_matcher->num_of_at - 1; + + ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher, + bwc_matcher->at[at_idx]); + if (unlikely(ret)) { + /* Action template attach failed, possibly due to + * requiring more action STEs. + * Need to attempt creating new matcher with all + * the action templates, including the new one. + */ + ret = hws_bwc_matcher_rehash_at(bwc_matcher); + if (unlikely(ret)) { + mlx5hws_action_template_destroy(bwc_matcher->at[at_idx]); + bwc_matcher->at[at_idx] = NULL; + bwc_matcher->num_of_at--; + + hws_bwc_unlock_all_queues(ctx); + + mlx5hws_err(ctx, + "BWC rule update: rehash AT failed (%d)\n", + ret); + return ret; + } + } + } + + hws_bwc_unlock_all_queues(ctx); + mutex_lock(queue_lock); + } + + ret = hws_bwc_rule_update_sync(bwc_rule, + at_idx, + rule_actions, + &rule_attr); + mutex_unlock(queue_lock); + + if (unlikely(ret)) + mlx5hws_err(ctx, "BWC rule: update failed (%d)\n", ret); + + return ret; +} + +int mlx5hws_bwc_rule_action_update(struct mlx5hws_bwc_rule *bwc_rule, + struct mlx5hws_rule_action rule_actions[]) +{ + struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; + struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; + + if (unlikely(!mlx5hws_context_bwc_supported(ctx))) { + mlx5hws_err(ctx, "BWC rule: Context created w/o BWC API compatibility\n"); + return -EINVAL; + } + + return hws_bwc_rule_action_update(bwc_rule, rule_actions); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.h new file mode 100644 index 00000000000000..0b745968e21e18 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_BWC_H_ +#define HWS_BWC_H_ + +#define MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG 1 +#define MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP 1 +#define MLX5HWS_BWC_MATCHER_REHASH_PERCENT_TH 70 +#define MLX5HWS_BWC_MATCHER_REHASH_BURST_TH 32 +#define MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM 255 + +#define MLX5HWS_BWC_MAX_ACTS 16 + +struct mlx5hws_bwc_matcher { + struct mlx5hws_matcher *matcher; + struct mlx5hws_match_template *mt; + struct mlx5hws_action_template *at[MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM]; + u8 num_of_at; + u16 priority; + u8 size_log; + u32 num_of_rules; /* atomically accessed */ + struct list_head *rules; +}; + +struct mlx5hws_bwc_rule { + struct mlx5hws_bwc_matcher *bwc_matcher; + struct mlx5hws_rule *rule; + u16 bwc_queue_idx; + struct list_head list_node; +}; + +int +mlx5hws_bwc_matcher_create_simple(struct mlx5hws_bwc_matcher *bwc_matcher, + struct mlx5hws_table *table, + u32 priority, + u8 match_criteria_enable, + struct mlx5hws_match_parameters *mask, + enum mlx5hws_action_type action_types[]); + +int mlx5hws_bwc_matcher_destroy_simple(struct mlx5hws_bwc_matcher *bwc_matcher); + +struct mlx5hws_bwc_rule *mlx5hws_bwc_rule_alloc(struct mlx5hws_bwc_matcher *bwc_matcher); + +void mlx5hws_bwc_rule_free(struct mlx5hws_bwc_rule *bwc_rule); + +int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, + u32 *match_param, + struct mlx5hws_rule_action rule_actions[], + u32 flow_source, + u16 bwc_queue_idx); + +int mlx5hws_bwc_rule_destroy_simple(struct mlx5hws_bwc_rule *bwc_rule); + +void mlx5hws_bwc_rule_fill_attr(struct mlx5hws_bwc_matcher *bwc_matcher, + u16 bwc_queue_idx, + u32 flow_source, + struct mlx5hws_rule_attr *rule_attr); + +static inline u16 mlx5hws_bwc_queues(struct mlx5hws_context *ctx) +{ + /* Besides the control queue, half of the queues are + * reguler HWS queues, and the other half are BWC queues. + */ + return (ctx->queues - 1) / 2; +} + +static inline u16 mlx5hws_bwc_get_queue_id(struct mlx5hws_context *ctx, u16 idx) +{ + return idx + mlx5hws_bwc_queues(ctx); +} + +#endif /* HWS_BWC_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c new file mode 100644 index 00000000000000..9fb059a6511f7f --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +bool mlx5hws_bwc_match_params_is_complex(struct mlx5hws_context *ctx, + u8 match_criteria_enable, + struct mlx5hws_match_parameters *mask) +{ + struct mlx5hws_definer match_layout = {0}; + struct mlx5hws_match_template *mt; + bool is_complex = false; + int ret; + + if (!match_criteria_enable) + return false; /* empty matcher */ + + mt = mlx5hws_match_template_create(ctx, + mask->match_buf, + mask->match_sz, + match_criteria_enable); + if (!mt) { + mlx5hws_err(ctx, "BWC: failed creating match template\n"); + return false; + } + + ret = mlx5hws_definer_calc_layout(ctx, mt, &match_layout); + if (ret) { + /* The only case that we're interested in is E2BIG, + * which means that the match parameters need to be + * split into complex martcher. + * For all other cases (good or bad) - just return true + * and let the usual match creation path handle it, + * both for good and bad flows. + */ + if (ret == -E2BIG) { + is_complex = true; + mlx5hws_dbg(ctx, "Matcher definer layout: need complex matcher\n"); + } else { + mlx5hws_err(ctx, "Failed to calculate matcher definer layout\n"); + } + } else { + kfree(mt->fc); + } + + mlx5hws_match_template_destroy(mt); + + return is_complex; +} + +int mlx5hws_bwc_matcher_create_complex(struct mlx5hws_bwc_matcher *bwc_matcher, + struct mlx5hws_table *table, + u32 priority, + u8 match_criteria_enable, + struct mlx5hws_match_parameters *mask) +{ + mlx5hws_err(table->ctx, "Complex matcher is not supported yet\n"); + return -EOPNOTSUPP; +} + +void +mlx5hws_bwc_matcher_destroy_complex(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + /* nothing to do here */ +} + +int mlx5hws_bwc_rule_create_complex(struct mlx5hws_bwc_rule *bwc_rule, + struct mlx5hws_match_parameters *params, + u32 flow_source, + struct mlx5hws_rule_action rule_actions[], + u16 bwc_queue_idx) +{ + mlx5hws_err(bwc_rule->bwc_matcher->matcher->tbl->ctx, + "Complex rule is not supported yet\n"); + return -EOPNOTSUPP; +} + +int mlx5hws_bwc_rule_destroy_complex(struct mlx5hws_bwc_rule *bwc_rule) +{ + return 0; +} + +int mlx5hws_bwc_matcher_move_all_complex(struct mlx5hws_bwc_matcher *bwc_matcher) +{ + mlx5hws_err(bwc_matcher->matcher->tbl->ctx, + "Moving complex rule is not supported yet\n"); + return -EOPNOTSUPP; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.h new file mode 100644 index 00000000000000..340f0688e3947f --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc_complex.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_BWC_COMPLEX_H_ +#define HWS_BWC_COMPLEX_H_ + +bool mlx5hws_bwc_match_params_is_complex(struct mlx5hws_context *ctx, + u8 match_criteria_enable, + struct mlx5hws_match_parameters *mask); + +int mlx5hws_bwc_matcher_create_complex(struct mlx5hws_bwc_matcher *bwc_matcher, + struct mlx5hws_table *table, + u32 priority, + u8 match_criteria_enable, + struct mlx5hws_match_parameters *mask); + +void mlx5hws_bwc_matcher_destroy_complex(struct mlx5hws_bwc_matcher *bwc_matcher); + +int mlx5hws_bwc_matcher_move_all_complex(struct mlx5hws_bwc_matcher *bwc_matcher); + +int mlx5hws_bwc_rule_create_complex(struct mlx5hws_bwc_rule *bwc_rule, + struct mlx5hws_match_parameters *params, + u32 flow_source, + struct mlx5hws_rule_action rule_actions[], + u16 bwc_queue_idx); + +int mlx5hws_bwc_rule_destroy_complex(struct mlx5hws_bwc_rule *bwc_rule); + +#endif /* HWS_BWC_COMPLEX_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c new file mode 100644 index 00000000000000..c00c138c3366ba --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c @@ -0,0 +1,1300 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +static enum mlx5_ifc_flow_destination_type +hws_cmd_dest_type_to_ifc_dest_type(enum mlx5_flow_destination_type type) +{ + switch (type) { + case MLX5_FLOW_DESTINATION_TYPE_VPORT: + return MLX5_IFC_FLOW_DESTINATION_TYPE_VPORT; + case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: + return MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_TABLE; + case MLX5_FLOW_DESTINATION_TYPE_TIR: + return MLX5_IFC_FLOW_DESTINATION_TYPE_TIR; + case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER: + return MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_SAMPLER; + case MLX5_FLOW_DESTINATION_TYPE_UPLINK: + return MLX5_IFC_FLOW_DESTINATION_TYPE_UPLINK; + case MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE: + return MLX5_IFC_FLOW_DESTINATION_TYPE_TABLE_TYPE; + case MLX5_FLOW_DESTINATION_TYPE_NONE: + case MLX5_FLOW_DESTINATION_TYPE_PORT: + case MLX5_FLOW_DESTINATION_TYPE_COUNTER: + case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: + case MLX5_FLOW_DESTINATION_TYPE_RANGE: + default: + pr_warn("HWS: unknown flow dest type %d\n", type); + return 0; + } +}; + +static int hws_cmd_general_obj_destroy(struct mlx5_core_dev *mdev, + u32 object_type, + u32 object_id) +{ + u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; + + MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, object_type); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, object_id); + + return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); +} + +int mlx5hws_cmd_flow_table_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_ft_create_attr *ft_attr, + u32 *table_id) +{ + u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0}; + void *ft_ctx; + int ret; + + MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE); + MLX5_SET(create_flow_table_in, in, table_type, ft_attr->type); + + ft_ctx = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context); + MLX5_SET(flow_table_context, ft_ctx, level, ft_attr->level); + MLX5_SET(flow_table_context, ft_ctx, rtc_valid, ft_attr->rtc_valid); + MLX5_SET(flow_table_context, ft_ctx, reformat_en, ft_attr->reformat_en); + MLX5_SET(flow_table_context, ft_ctx, decap_en, ft_attr->decap_en); + + ret = mlx5_cmd_exec_inout(mdev, create_flow_table, in, out); + if (ret) + return ret; + + *table_id = MLX5_GET(create_flow_table_out, out, table_id); + + return 0; +} + +int mlx5hws_cmd_flow_table_modify(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_ft_modify_attr *ft_attr, + u32 table_id) +{ + u32 in[MLX5_ST_SZ_DW(modify_flow_table_in)] = {0}; + void *ft_ctx; + + MLX5_SET(modify_flow_table_in, in, opcode, MLX5_CMD_OP_MODIFY_FLOW_TABLE); + MLX5_SET(modify_flow_table_in, in, table_type, ft_attr->type); + MLX5_SET(modify_flow_table_in, in, modify_field_select, ft_attr->modify_fs); + MLX5_SET(modify_flow_table_in, in, table_id, table_id); + + ft_ctx = MLX5_ADDR_OF(modify_flow_table_in, in, flow_table_context); + + MLX5_SET(flow_table_context, ft_ctx, table_miss_action, ft_attr->table_miss_action); + MLX5_SET(flow_table_context, ft_ctx, table_miss_id, ft_attr->table_miss_id); + MLX5_SET(flow_table_context, ft_ctx, hws.rtc_id_0, ft_attr->rtc_id_0); + MLX5_SET(flow_table_context, ft_ctx, hws.rtc_id_1, ft_attr->rtc_id_1); + + return mlx5_cmd_exec_in(mdev, modify_flow_table, in); +} + +int mlx5hws_cmd_flow_table_query(struct mlx5_core_dev *mdev, + u32 table_id, + struct mlx5hws_cmd_ft_query_attr *ft_attr, + u64 *icm_addr_0, u64 *icm_addr_1) +{ + u32 out[MLX5_ST_SZ_DW(query_flow_table_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(query_flow_table_in)] = {0}; + void *ft_ctx; + int ret; + + MLX5_SET(query_flow_table_in, in, opcode, MLX5_CMD_OP_QUERY_FLOW_TABLE); + MLX5_SET(query_flow_table_in, in, table_type, ft_attr->type); + MLX5_SET(query_flow_table_in, in, table_id, table_id); + + ret = mlx5_cmd_exec_inout(mdev, query_flow_table, in, out); + if (ret) + return ret; + + ft_ctx = MLX5_ADDR_OF(query_flow_table_out, out, flow_table_context); + *icm_addr_0 = MLX5_GET64(flow_table_context, ft_ctx, sws.sw_owner_icm_root_0); + *icm_addr_1 = MLX5_GET64(flow_table_context, ft_ctx, sws.sw_owner_icm_root_1); + + return ret; +} + +int mlx5hws_cmd_flow_table_destroy(struct mlx5_core_dev *mdev, + u8 fw_ft_type, u32 table_id) +{ + u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {0}; + + MLX5_SET(destroy_flow_table_in, in, opcode, MLX5_CMD_OP_DESTROY_FLOW_TABLE); + MLX5_SET(destroy_flow_table_in, in, table_type, fw_ft_type); + MLX5_SET(destroy_flow_table_in, in, table_id, table_id); + + return mlx5_cmd_exec_in(mdev, destroy_flow_table, in); +} + +void mlx5hws_cmd_alias_flow_table_destroy(struct mlx5_core_dev *mdev, + u32 table_id) +{ + hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_FT_ALIAS, table_id); +} + +static int hws_cmd_flow_group_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_fg_attr *fg_attr, + u32 *group_id) +{ + u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {0}; + int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); + u32 *in; + int ret; + + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP); + MLX5_SET(create_flow_group_in, in, table_type, fg_attr->table_type); + MLX5_SET(create_flow_group_in, in, table_id, fg_attr->table_id); + + ret = mlx5_cmd_exec_inout(mdev, create_flow_group, in, out); + if (ret) + goto out; + + *group_id = MLX5_GET(create_flow_group_out, out, group_id); + +out: + kvfree(in); + return ret; +} + +static int hws_cmd_flow_group_destroy(struct mlx5_core_dev *mdev, + u32 ft_id, u32 fg_id, u8 ft_type) +{ + u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {}; + + MLX5_SET(destroy_flow_group_in, in, opcode, MLX5_CMD_OP_DESTROY_FLOW_GROUP); + MLX5_SET(destroy_flow_group_in, in, table_type, ft_type); + MLX5_SET(destroy_flow_group_in, in, table_id, ft_id); + MLX5_SET(destroy_flow_group_in, in, group_id, fg_id); + + return mlx5_cmd_exec_in(mdev, destroy_flow_group, in); +} + +int mlx5hws_cmd_set_fte(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id, + u32 group_id, + struct mlx5hws_cmd_set_fte_attr *fte_attr) +{ + u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {0}; + void *in_flow_context; + u32 dest_entry_sz; + u32 total_dest_sz; + u32 action_flags; + u8 *in_dests; + u32 inlen; + u32 *in; + int ret; + u32 i; + + dest_entry_sz = fte_attr->extended_dest ? + MLX5_ST_SZ_BYTES(extended_dest_format) : + MLX5_ST_SZ_BYTES(dest_format); + total_dest_sz = dest_entry_sz * fte_attr->dests_num; + inlen = align((MLX5_ST_SZ_BYTES(set_fte_in) + total_dest_sz), DW_SIZE); + in = kzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); + MLX5_SET(set_fte_in, in, table_type, table_type); + MLX5_SET(set_fte_in, in, table_id, table_id); + + in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); + MLX5_SET(flow_context, in_flow_context, group_id, group_id); + MLX5_SET(flow_context, in_flow_context, flow_source, fte_attr->flow_source); + MLX5_SET(flow_context, in_flow_context, extended_destination, fte_attr->extended_dest); + MLX5_SET(set_fte_in, in, ignore_flow_level, fte_attr->ignore_flow_level); + + action_flags = fte_attr->action_flags; + MLX5_SET(flow_context, in_flow_context, action, action_flags); + + if (action_flags & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { + MLX5_SET(flow_context, in_flow_context, + packet_reformat_id, fte_attr->packet_reformat_id); + } + + if (action_flags & (MLX5_FLOW_CONTEXT_ACTION_DECRYPT | MLX5_FLOW_CONTEXT_ACTION_ENCRYPT)) { + MLX5_SET(flow_context, in_flow_context, + encrypt_decrypt_type, fte_attr->encrypt_decrypt_type); + MLX5_SET(flow_context, in_flow_context, + encrypt_decrypt_obj_id, fte_attr->encrypt_decrypt_obj_id); + } + + if (action_flags & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { + in_dests = (u8 *)MLX5_ADDR_OF(flow_context, in_flow_context, destination); + + for (i = 0; i < fte_attr->dests_num; i++) { + struct mlx5hws_cmd_set_fte_dest *dest = &fte_attr->dests[i]; + enum mlx5_ifc_flow_destination_type ifc_dest_type = + hws_cmd_dest_type_to_ifc_dest_type(dest->destination_type); + + switch (dest->destination_type) { + case MLX5_FLOW_DESTINATION_TYPE_VPORT: + if (dest->ext_flags & MLX5HWS_CMD_EXT_DEST_ESW_OWNER_VHCA_ID) { + MLX5_SET(dest_format, in_dests, + destination_eswitch_owner_vhca_id_valid, 1); + MLX5_SET(dest_format, in_dests, + destination_eswitch_owner_vhca_id, + dest->esw_owner_vhca_id); + } + fallthrough; + case MLX5_FLOW_DESTINATION_TYPE_TIR: + case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: + MLX5_SET(dest_format, in_dests, destination_type, ifc_dest_type); + MLX5_SET(dest_format, in_dests, destination_id, + dest->destination_id); + if (dest->ext_flags & MLX5HWS_CMD_EXT_DEST_REFORMAT) { + MLX5_SET(dest_format, in_dests, packet_reformat, 1); + MLX5_SET(extended_dest_format, in_dests, packet_reformat_id, + dest->ext_reformat_id); + } + break; + default: + ret = -EOPNOTSUPP; + goto out; + } + + in_dests = in_dests + dest_entry_sz; + } + MLX5_SET(flow_context, in_flow_context, destination_list_size, fte_attr->dests_num); + } + + ret = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); + if (ret) + mlx5_core_err(mdev, "Failed creating FLOW_TABLE_ENTRY\n"); + +out: + kfree(in); + return ret; +} + +int mlx5hws_cmd_delete_fte(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id) +{ + u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {}; + + MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); + MLX5_SET(delete_fte_in, in, table_type, table_type); + MLX5_SET(delete_fte_in, in, table_id, table_id); + + return mlx5_cmd_exec_in(mdev, delete_fte, in); +} + +struct mlx5hws_cmd_forward_tbl * +mlx5hws_cmd_forward_tbl_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_ft_create_attr *ft_attr, + struct mlx5hws_cmd_set_fte_attr *fte_attr) +{ + struct mlx5hws_cmd_fg_attr fg_attr = {0}; + struct mlx5hws_cmd_forward_tbl *tbl; + int ret; + + tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); + if (!tbl) + return NULL; + + ret = mlx5hws_cmd_flow_table_create(mdev, ft_attr, &tbl->ft_id); + if (ret) { + mlx5_core_err(mdev, "Failed to create FT\n"); + goto free_tbl; + } + + fg_attr.table_id = tbl->ft_id; + fg_attr.table_type = ft_attr->type; + + ret = hws_cmd_flow_group_create(mdev, &fg_attr, &tbl->fg_id); + if (ret) { + mlx5_core_err(mdev, "Failed to create FG\n"); + goto free_ft; + } + + ret = mlx5hws_cmd_set_fte(mdev, ft_attr->type, + tbl->ft_id, tbl->fg_id, fte_attr); + if (ret) { + mlx5_core_err(mdev, "Failed to create FTE\n"); + goto free_fg; + } + + tbl->type = ft_attr->type; + return tbl; + +free_fg: + hws_cmd_flow_group_destroy(mdev, tbl->ft_id, tbl->fg_id, ft_attr->type); +free_ft: + mlx5hws_cmd_flow_table_destroy(mdev, ft_attr->type, tbl->ft_id); +free_tbl: + kfree(tbl); + return NULL; +} + +void mlx5hws_cmd_forward_tbl_destroy(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_forward_tbl *tbl) +{ + mlx5hws_cmd_delete_fte(mdev, tbl->type, tbl->ft_id); + hws_cmd_flow_group_destroy(mdev, tbl->ft_id, tbl->fg_id, tbl->type); + mlx5hws_cmd_flow_table_destroy(mdev, tbl->type, tbl->ft_id); + kfree(tbl); +} + +void mlx5hws_cmd_set_attr_connect_miss_tbl(struct mlx5hws_context *ctx, + u32 fw_ft_type, + enum mlx5hws_table_type type, + struct mlx5hws_cmd_ft_modify_attr *ft_attr) +{ + u32 default_miss_tbl; + + if (type != MLX5HWS_TABLE_TYPE_FDB) + return; + + ft_attr->modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION; + ft_attr->type = fw_ft_type; + ft_attr->table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL; + + default_miss_tbl = ctx->common_res[type].default_miss->ft_id; + if (!default_miss_tbl) { + pr_warn("HWS: no flow table ID for default miss\n"); + return; + } + + ft_attr->table_miss_id = default_miss_tbl; +} + +int mlx5hws_cmd_rtc_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_rtc_create_attr *rtc_attr, + u32 *rtc_id) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; + u32 in[MLX5_ST_SZ_DW(create_rtc_in)] = {0}; + void *attr; + int ret; + + attr = MLX5_ADDR_OF(create_rtc_in, in, hdr); + MLX5_SET(general_obj_in_cmd_hdr, + attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, + attr, obj_type, MLX5_OBJ_TYPE_RTC); + + attr = MLX5_ADDR_OF(create_rtc_in, in, rtc); + MLX5_SET(rtc, attr, ste_format_0, rtc_attr->is_frst_jumbo ? + MLX5_IFC_RTC_STE_FORMAT_11DW : + MLX5_IFC_RTC_STE_FORMAT_8DW); + + if (rtc_attr->is_scnd_range) { + MLX5_SET(rtc, attr, ste_format_1, MLX5_IFC_RTC_STE_FORMAT_RANGE); + MLX5_SET(rtc, attr, num_match_ste, 2); + } + + MLX5_SET(rtc, attr, pd, rtc_attr->pd); + MLX5_SET(rtc, attr, update_method, rtc_attr->fw_gen_wqe); + MLX5_SET(rtc, attr, update_index_mode, rtc_attr->update_index_mode); + MLX5_SET(rtc, attr, access_index_mode, rtc_attr->access_index_mode); + MLX5_SET(rtc, attr, num_hash_definer, rtc_attr->num_hash_definer); + MLX5_SET(rtc, attr, log_depth, rtc_attr->log_depth); + MLX5_SET(rtc, attr, log_hash_size, rtc_attr->log_size); + MLX5_SET(rtc, attr, table_type, rtc_attr->table_type); + MLX5_SET(rtc, attr, num_hash_definer, rtc_attr->num_hash_definer); + MLX5_SET(rtc, attr, match_definer_0, rtc_attr->match_definer_0); + MLX5_SET(rtc, attr, match_definer_1, rtc_attr->match_definer_1); + MLX5_SET(rtc, attr, stc_id, rtc_attr->stc_base); + MLX5_SET(rtc, attr, ste_table_base_id, rtc_attr->ste_base); + MLX5_SET(rtc, attr, ste_table_offset, rtc_attr->ste_offset); + MLX5_SET(rtc, attr, miss_flow_table_id, rtc_attr->miss_ft_id); + MLX5_SET(rtc, attr, reparse_mode, rtc_attr->reparse_mode); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to create RTC\n"); + goto out; + } + + *rtc_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); +out: + return ret; +} + +void mlx5hws_cmd_rtc_destroy(struct mlx5_core_dev *mdev, u32 rtc_id) +{ + hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_RTC, rtc_id); +} + +int mlx5hws_cmd_stc_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_stc_create_attr *stc_attr, + u32 *stc_id) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; + u32 in[MLX5_ST_SZ_DW(create_stc_in)] = {0}; + void *attr; + int ret; + + attr = MLX5_ADDR_OF(create_stc_in, in, hdr); + MLX5_SET(general_obj_in_cmd_hdr, + attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, + attr, obj_type, MLX5_OBJ_TYPE_STC); + MLX5_SET(general_obj_in_cmd_hdr, + attr, op_param.create.log_obj_range, stc_attr->log_obj_range); + + attr = MLX5_ADDR_OF(create_stc_in, in, stc); + MLX5_SET(stc, attr, table_type, stc_attr->table_type); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to create STC\n"); + goto out; + } + + *stc_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); +out: + return ret; +} + +void mlx5hws_cmd_stc_destroy(struct mlx5_core_dev *mdev, u32 stc_id) +{ + hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_STC, stc_id); +} + +static int +hws_cmd_stc_modify_set_stc_param(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_stc_modify_attr *stc_attr, + void *stc_param) +{ + switch (stc_attr->action_type) { + case MLX5_IFC_STC_ACTION_TYPE_COUNTER: + MLX5_SET(stc_ste_param_flow_counter, stc_param, flow_counter_id, stc_attr->id); + break; + case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR: + MLX5_SET(stc_ste_param_tir, stc_param, tirn, stc_attr->dest_tir_num); + break; + case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT: + MLX5_SET(stc_ste_param_table, stc_param, table_id, stc_attr->dest_table_id); + break; + case MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST: + MLX5_SET(stc_ste_param_header_modify_list, stc_param, + header_modify_pattern_id, stc_attr->modify_header.pattern_id); + MLX5_SET(stc_ste_param_header_modify_list, stc_param, + header_modify_argument_id, stc_attr->modify_header.arg_id); + break; + case MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE: + MLX5_SET(stc_ste_param_remove, stc_param, action_type, + MLX5_MODIFICATION_TYPE_REMOVE); + MLX5_SET(stc_ste_param_remove, stc_param, decap, + stc_attr->remove_header.decap); + MLX5_SET(stc_ste_param_remove, stc_param, remove_start_anchor, + stc_attr->remove_header.start_anchor); + MLX5_SET(stc_ste_param_remove, stc_param, remove_end_anchor, + stc_attr->remove_header.end_anchor); + break; + case MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT: + MLX5_SET(stc_ste_param_insert, stc_param, action_type, + MLX5_MODIFICATION_TYPE_INSERT); + MLX5_SET(stc_ste_param_insert, stc_param, encap, + stc_attr->insert_header.encap); + MLX5_SET(stc_ste_param_insert, stc_param, inline_data, + stc_attr->insert_header.is_inline); + MLX5_SET(stc_ste_param_insert, stc_param, insert_anchor, + stc_attr->insert_header.insert_anchor); + /* HW gets the next 2 sizes in words */ + MLX5_SET(stc_ste_param_insert, stc_param, insert_size, + stc_attr->insert_header.header_size / W_SIZE); + MLX5_SET(stc_ste_param_insert, stc_param, insert_offset, + stc_attr->insert_header.insert_offset / W_SIZE); + MLX5_SET(stc_ste_param_insert, stc_param, insert_argument, + stc_attr->insert_header.arg_id); + break; + case MLX5_IFC_STC_ACTION_TYPE_COPY: + case MLX5_IFC_STC_ACTION_TYPE_SET: + case MLX5_IFC_STC_ACTION_TYPE_ADD: + case MLX5_IFC_STC_ACTION_TYPE_ADD_FIELD: + *(__be64 *)stc_param = stc_attr->modify_action.data; + break; + case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT: + case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK: + MLX5_SET(stc_ste_param_vport, stc_param, vport_number, + stc_attr->vport.vport_num); + MLX5_SET(stc_ste_param_vport, stc_param, eswitch_owner_vhca_id, + stc_attr->vport.esw_owner_vhca_id); + MLX5_SET(stc_ste_param_vport, stc_param, eswitch_owner_vhca_id_valid, + stc_attr->vport.eswitch_owner_vhca_id_valid); + break; + case MLX5_IFC_STC_ACTION_TYPE_DROP: + case MLX5_IFC_STC_ACTION_TYPE_NOP: + case MLX5_IFC_STC_ACTION_TYPE_TAG: + case MLX5_IFC_STC_ACTION_TYPE_ALLOW: + break; + case MLX5_IFC_STC_ACTION_TYPE_ASO: + MLX5_SET(stc_ste_param_execute_aso, stc_param, aso_object_id, + stc_attr->aso.devx_obj_id); + MLX5_SET(stc_ste_param_execute_aso, stc_param, return_reg_id, + stc_attr->aso.return_reg_id); + MLX5_SET(stc_ste_param_execute_aso, stc_param, aso_type, + stc_attr->aso.aso_type); + break; + case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE: + MLX5_SET(stc_ste_param_ste_table, stc_param, ste_obj_id, + stc_attr->ste_table.ste_obj_id); + MLX5_SET(stc_ste_param_ste_table, stc_param, match_definer_id, + stc_attr->ste_table.match_definer_id); + MLX5_SET(stc_ste_param_ste_table, stc_param, log_hash_size, + stc_attr->ste_table.log_hash_size); + break; + case MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS: + MLX5_SET(stc_ste_param_remove_words, stc_param, action_type, + MLX5_MODIFICATION_TYPE_REMOVE_WORDS); + MLX5_SET(stc_ste_param_remove_words, stc_param, remove_start_anchor, + stc_attr->remove_words.start_anchor); + MLX5_SET(stc_ste_param_remove_words, stc_param, + remove_size, stc_attr->remove_words.num_of_words); + break; + case MLX5_IFC_STC_ACTION_TYPE_CRYPTO_IPSEC_ENCRYPTION: + MLX5_SET(stc_ste_param_ipsec_encrypt, stc_param, ipsec_object_id, + stc_attr->id); + break; + case MLX5_IFC_STC_ACTION_TYPE_CRYPTO_IPSEC_DECRYPTION: + MLX5_SET(stc_ste_param_ipsec_decrypt, stc_param, ipsec_object_id, + stc_attr->id); + break; + case MLX5_IFC_STC_ACTION_TYPE_TRAILER: + MLX5_SET(stc_ste_param_trailer, stc_param, command, + stc_attr->reformat_trailer.op); + MLX5_SET(stc_ste_param_trailer, stc_param, type, + stc_attr->reformat_trailer.type); + MLX5_SET(stc_ste_param_trailer, stc_param, length, + stc_attr->reformat_trailer.size); + break; + default: + mlx5_core_err(mdev, "Not supported type %d\n", stc_attr->action_type); + return -EINVAL; + } + return 0; +} + +int mlx5hws_cmd_stc_modify(struct mlx5_core_dev *mdev, + u32 stc_id, + struct mlx5hws_cmd_stc_modify_attr *stc_attr) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; + u32 in[MLX5_ST_SZ_DW(create_stc_in)] = {0}; + void *stc_param; + void *attr; + int ret; + + attr = MLX5_ADDR_OF(create_stc_in, in, hdr); + MLX5_SET(general_obj_in_cmd_hdr, + attr, opcode, MLX5_CMD_OP_MODIFY_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, + attr, obj_type, MLX5_OBJ_TYPE_STC); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, stc_id); + MLX5_SET(general_obj_in_cmd_hdr, in, + op_param.query.obj_offset, stc_attr->stc_offset); + + attr = MLX5_ADDR_OF(create_stc_in, in, stc); + MLX5_SET(stc, attr, ste_action_offset, stc_attr->action_offset); + MLX5_SET(stc, attr, action_type, stc_attr->action_type); + MLX5_SET(stc, attr, reparse_mode, stc_attr->reparse_mode); + MLX5_SET64(stc, attr, modify_field_select, + MLX5_IFC_MODIFY_STC_FIELD_SELECT_NEW_STC); + + /* Set destination TIRN, TAG, FT ID, STE ID */ + stc_param = MLX5_ADDR_OF(stc, attr, stc_param); + ret = hws_cmd_stc_modify_set_stc_param(mdev, stc_attr, stc_param); + if (ret) + return ret; + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) + mlx5_core_err(mdev, "Failed to modify STC FW action_type %d\n", + stc_attr->action_type); + + return ret; +} + +int mlx5hws_cmd_arg_create(struct mlx5_core_dev *mdev, + u16 log_obj_range, + u32 pd, + u32 *arg_id) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; + u32 in[MLX5_ST_SZ_DW(create_arg_in)] = {0}; + void *attr; + int ret; + + attr = MLX5_ADDR_OF(create_arg_in, in, hdr); + MLX5_SET(general_obj_in_cmd_hdr, + attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, + attr, obj_type, MLX5_OBJ_TYPE_HEADER_MODIFY_ARGUMENT); + MLX5_SET(general_obj_in_cmd_hdr, + attr, op_param.create.log_obj_range, log_obj_range); + + attr = MLX5_ADDR_OF(create_arg_in, in, arg); + MLX5_SET(arg, attr, access_pd, pd); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to create ARG\n"); + goto out; + } + + *arg_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); +out: + return ret; +} + +void mlx5hws_cmd_arg_destroy(struct mlx5_core_dev *mdev, + u32 arg_id) +{ + hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_HEADER_MODIFY_ARGUMENT, arg_id); +} + +int mlx5hws_cmd_header_modify_pattern_create(struct mlx5_core_dev *mdev, + u32 pattern_length, + u8 *actions, + u32 *ptrn_id) +{ + u32 in[MLX5_ST_SZ_DW(create_header_modify_pattern_in)] = {0}; + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; + int num_of_actions; + u64 *pattern_data; + void *pattern; + void *attr; + int ret; + int i; + + if (pattern_length > MLX5_MAX_ACTIONS_DATA_IN_HEADER_MODIFY) { + mlx5_core_err(mdev, "Pattern length %d exceeds limit %d\n", + pattern_length, MLX5_MAX_ACTIONS_DATA_IN_HEADER_MODIFY); + return -EINVAL; + } + + attr = MLX5_ADDR_OF(create_header_modify_pattern_in, in, hdr); + MLX5_SET(general_obj_in_cmd_hdr, + attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, + attr, obj_type, MLX5_OBJ_TYPE_MODIFY_HDR_PATTERN); + + pattern = MLX5_ADDR_OF(create_header_modify_pattern_in, in, pattern); + /* Pattern_length is in ddwords */ + MLX5_SET(header_modify_pattern_in, pattern, pattern_length, pattern_length / (2 * DW_SIZE)); + + pattern_data = (u64 *)MLX5_ADDR_OF(header_modify_pattern_in, pattern, pattern_data); + memcpy(pattern_data, actions, pattern_length); + + num_of_actions = pattern_length / MLX5HWS_MODIFY_ACTION_SIZE; + for (i = 0; i < num_of_actions; i++) { + int type; + + type = MLX5_GET(set_action_in, &pattern_data[i], action_type); + if (type != MLX5_MODIFICATION_TYPE_COPY && + type != MLX5_MODIFICATION_TYPE_ADD_FIELD) + /* Action typ-copy use all bytes for control */ + MLX5_SET(set_action_in, &pattern_data[i], data, 0); + } + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to create header_modify_pattern\n"); + goto out; + } + + *ptrn_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); +out: + return ret; +} + +void mlx5hws_cmd_header_modify_pattern_destroy(struct mlx5_core_dev *mdev, + u32 ptrn_id) +{ + hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_MODIFY_HDR_PATTERN, ptrn_id); +} + +int mlx5hws_cmd_ste_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_ste_create_attr *ste_attr, + u32 *ste_id) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; + u32 in[MLX5_ST_SZ_DW(create_ste_in)] = {0}; + void *attr; + int ret; + + attr = MLX5_ADDR_OF(create_ste_in, in, hdr); + MLX5_SET(general_obj_in_cmd_hdr, + attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, + attr, obj_type, MLX5_OBJ_TYPE_STE); + MLX5_SET(general_obj_in_cmd_hdr, + attr, op_param.create.log_obj_range, ste_attr->log_obj_range); + + attr = MLX5_ADDR_OF(create_ste_in, in, ste); + MLX5_SET(ste, attr, table_type, ste_attr->table_type); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to create STE\n"); + goto out; + } + + *ste_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); +out: + return ret; +} + +void mlx5hws_cmd_ste_destroy(struct mlx5_core_dev *mdev, u32 ste_id) +{ + hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_STE, ste_id); +} + +int mlx5hws_cmd_definer_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_definer_create_attr *def_attr, + u32 *definer_id) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; + u32 in[MLX5_ST_SZ_DW(create_definer_in)] = {0}; + void *ptr; + int ret; + + MLX5_SET(general_obj_in_cmd_hdr, + in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, + in, obj_type, MLX5_OBJ_TYPE_MATCH_DEFINER); + + ptr = MLX5_ADDR_OF(create_definer_in, in, definer); + MLX5_SET(definer, ptr, format_id, MLX5_IFC_DEFINER_FORMAT_ID_SELECT); + + MLX5_SET(definer, ptr, format_select_dw0, def_attr->dw_selector[0]); + MLX5_SET(definer, ptr, format_select_dw1, def_attr->dw_selector[1]); + MLX5_SET(definer, ptr, format_select_dw2, def_attr->dw_selector[2]); + MLX5_SET(definer, ptr, format_select_dw3, def_attr->dw_selector[3]); + MLX5_SET(definer, ptr, format_select_dw4, def_attr->dw_selector[4]); + MLX5_SET(definer, ptr, format_select_dw5, def_attr->dw_selector[5]); + MLX5_SET(definer, ptr, format_select_dw6, def_attr->dw_selector[6]); + MLX5_SET(definer, ptr, format_select_dw7, def_attr->dw_selector[7]); + MLX5_SET(definer, ptr, format_select_dw8, def_attr->dw_selector[8]); + + MLX5_SET(definer, ptr, format_select_byte0, def_attr->byte_selector[0]); + MLX5_SET(definer, ptr, format_select_byte1, def_attr->byte_selector[1]); + MLX5_SET(definer, ptr, format_select_byte2, def_attr->byte_selector[2]); + MLX5_SET(definer, ptr, format_select_byte3, def_attr->byte_selector[3]); + MLX5_SET(definer, ptr, format_select_byte4, def_attr->byte_selector[4]); + MLX5_SET(definer, ptr, format_select_byte5, def_attr->byte_selector[5]); + MLX5_SET(definer, ptr, format_select_byte6, def_attr->byte_selector[6]); + MLX5_SET(definer, ptr, format_select_byte7, def_attr->byte_selector[7]); + + ptr = MLX5_ADDR_OF(definer, ptr, match_mask); + memcpy(ptr, def_attr->match_mask, MLX5_FLD_SZ_BYTES(definer, match_mask)); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to create Definer\n"); + goto out; + } + + *definer_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); +out: + return ret; +} + +void mlx5hws_cmd_definer_destroy(struct mlx5_core_dev *mdev, + u32 definer_id) +{ + hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_MATCH_DEFINER, definer_id); +} + +int mlx5hws_cmd_packet_reformat_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_packet_reformat_create_attr *attr, + u32 *reformat_id) +{ + u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_out)] = {0}; + size_t insz, cmd_data_sz, cmd_total_sz; + void *prctx; + void *pdata; + void *in; + int ret; + + cmd_total_sz = MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in); + cmd_total_sz += MLX5_ST_SZ_BYTES(packet_reformat_context_in); + cmd_data_sz = MLX5_FLD_SZ_BYTES(packet_reformat_context_in, reformat_data); + insz = align(cmd_total_sz + attr->data_sz - cmd_data_sz, DW_SIZE); + in = kzalloc(insz, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(alloc_packet_reformat_context_in, in, opcode, + MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT); + + prctx = MLX5_ADDR_OF(alloc_packet_reformat_context_in, in, + packet_reformat_context); + pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data); + + MLX5_SET(packet_reformat_context_in, prctx, reformat_type, attr->type); + MLX5_SET(packet_reformat_context_in, prctx, reformat_param_0, attr->reformat_param_0); + MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, attr->data_sz); + memcpy(pdata, attr->data, attr->data_sz); + + ret = mlx5_cmd_exec(mdev, in, insz, out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to create packet reformat\n"); + goto out; + } + + *reformat_id = MLX5_GET(alloc_packet_reformat_out, out, packet_reformat_id); +out: + kfree(in); + return ret; +} + +int mlx5hws_cmd_packet_reformat_destroy(struct mlx5_core_dev *mdev, + u32 reformat_id) +{ + u32 out[MLX5_ST_SZ_DW(dealloc_packet_reformat_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_in)] = {0}; + int ret; + + MLX5_SET(dealloc_packet_reformat_in, in, opcode, + MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT); + MLX5_SET(dealloc_packet_reformat_in, in, + packet_reformat_id, reformat_id); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) + mlx5_core_err(mdev, "Failed to destroy packet_reformat\n"); + + return ret; +} + +int mlx5hws_cmd_sq_modify_rdy(struct mlx5_core_dev *mdev, u32 sqn) +{ + u32 out[MLX5_ST_SZ_DW(modify_sq_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(modify_sq_in)] = {0}; + void *sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); + int ret; + + MLX5_SET(modify_sq_in, in, opcode, MLX5_CMD_OP_MODIFY_SQ); + MLX5_SET(modify_sq_in, in, sqn, sqn); + MLX5_SET(modify_sq_in, in, sq_state, MLX5_SQC_STATE_RST); + MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RDY); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) + mlx5_core_err(mdev, "Failed to modify SQ\n"); + + return ret; +} + +int mlx5hws_cmd_allow_other_vhca_access(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_allow_other_vhca_access_attr *attr) +{ + u32 out[MLX5_ST_SZ_DW(allow_other_vhca_access_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(allow_other_vhca_access_in)] = {0}; + void *key; + int ret; + + MLX5_SET(allow_other_vhca_access_in, + in, opcode, MLX5_CMD_OP_ALLOW_OTHER_VHCA_ACCESS); + MLX5_SET(allow_other_vhca_access_in, + in, object_type_to_be_accessed, attr->obj_type); + MLX5_SET(allow_other_vhca_access_in, + in, object_id_to_be_accessed, attr->obj_id); + + key = MLX5_ADDR_OF(allow_other_vhca_access_in, in, access_key); + memcpy(key, attr->access_key, sizeof(attr->access_key)); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) + mlx5_core_err(mdev, "Failed to execute ALLOW_OTHER_VHCA_ACCESS command\n"); + + return ret; +} + +int mlx5hws_cmd_alias_obj_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_alias_obj_create_attr *alias_attr, + u32 *obj_id) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; + u32 in[MLX5_ST_SZ_DW(create_alias_obj_in)] = {0}; + void *attr; + void *key; + int ret; + + attr = MLX5_ADDR_OF(create_alias_obj_in, in, hdr); + MLX5_SET(general_obj_in_cmd_hdr, + attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, + attr, obj_type, alias_attr->obj_type); + MLX5_SET(general_obj_in_cmd_hdr, attr, op_param.create.alias_object, 1); + + attr = MLX5_ADDR_OF(create_alias_obj_in, in, alias_ctx); + MLX5_SET(alias_context, attr, vhca_id_to_be_accessed, alias_attr->vhca_id); + MLX5_SET(alias_context, attr, object_id_to_be_accessed, alias_attr->obj_id); + + key = MLX5_ADDR_OF(alias_context, attr, access_key); + memcpy(key, alias_attr->access_key, sizeof(alias_attr->access_key)); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to create ALIAS OBJ\n"); + goto out; + } + + *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); +out: + return ret; +} + +int mlx5hws_cmd_alias_obj_destroy(struct mlx5_core_dev *mdev, + u16 obj_type, + u32 obj_id) +{ + return hws_cmd_general_obj_destroy(mdev, obj_type, obj_id); +} + +int mlx5hws_cmd_generate_wqe(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_generate_wqe_attr *attr, + struct mlx5_cqe64 *ret_cqe) +{ + u32 out[MLX5_ST_SZ_DW(generate_wqe_out)] = {0}; + u32 in[MLX5_ST_SZ_DW(generate_wqe_in)] = {0}; + u8 status; + void *ptr; + int ret; + + MLX5_SET(generate_wqe_in, in, opcode, MLX5_CMD_OP_GENERATE_WQE); + MLX5_SET(generate_wqe_in, in, pdn, attr->pdn); + + ptr = MLX5_ADDR_OF(generate_wqe_in, in, wqe_ctrl); + memcpy(ptr, attr->wqe_ctrl, MLX5_FLD_SZ_BYTES(generate_wqe_in, wqe_ctrl)); + + ptr = MLX5_ADDR_OF(generate_wqe_in, in, wqe_gta_ctrl); + memcpy(ptr, attr->gta_ctrl, MLX5_FLD_SZ_BYTES(generate_wqe_in, wqe_gta_ctrl)); + + ptr = MLX5_ADDR_OF(generate_wqe_in, in, wqe_gta_data_0); + memcpy(ptr, attr->gta_data_0, MLX5_FLD_SZ_BYTES(generate_wqe_in, wqe_gta_data_0)); + + if (attr->gta_data_1) { + ptr = MLX5_ADDR_OF(generate_wqe_in, in, wqe_gta_data_1); + memcpy(ptr, attr->gta_data_1, MLX5_FLD_SZ_BYTES(generate_wqe_in, wqe_gta_data_1)); + } + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (ret) { + mlx5_core_err(mdev, "Failed to write GTA WQE using FW\n"); + return ret; + } + + status = MLX5_GET(generate_wqe_out, out, status); + if (status) { + mlx5_core_err(mdev, "Invalid FW CQE status %d\n", status); + return -EINVAL; + } + + ptr = MLX5_ADDR_OF(generate_wqe_out, out, cqe_data); + memcpy(ret_cqe, ptr, sizeof(*ret_cqe)); + + return ret; +} + +int mlx5hws_cmd_query_caps(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_query_caps *caps) +{ + u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {0}; + u32 out_size; + u32 *out; + int ret; + + out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); + out = kzalloc(out_size, GFP_KERNEL); + if (!out) + return -ENOMEM; + + MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); + MLX5_SET(query_hca_cap_in, in, op_mod, + MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE | HCA_CAP_OPMOD_GET_CUR); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); + if (ret) { + mlx5_core_err(mdev, "Failed to query device caps\n"); + goto out; + } + + caps->wqe_based_update = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.wqe_based_flow_table_update_cap); + + caps->eswitch_manager = MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.eswitch_manager); + + caps->flex_protocols = MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.flex_parser_protocols); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_GENEVE_TLV_OPTION_0_ENABLED) + caps->flex_parser_id_geneve_tlv_option_0 = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.flex_parser_id_geneve_tlv_option_0); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED) + caps->flex_parser_id_mpls_over_gre = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.flex_parser_id_outer_first_mpls_over_gre); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED) + caps->flex_parser_id_mpls_over_udp = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.flex_parser_id_outer_first_mpls_over_udp_label); + + caps->log_header_modify_argument_granularity = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.log_header_modify_argument_granularity); + + caps->log_header_modify_argument_granularity -= + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.log_header_modify_argument_granularity_offset); + + caps->log_header_modify_argument_max_alloc = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.log_header_modify_argument_max_alloc); + + caps->definer_format_sup = + MLX5_GET64(query_hca_cap_out, out, + capability.cmd_hca_cap.match_definer_format_supported); + + caps->vhca_id = MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.vhca_id); + + caps->sq_ts_format = MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.sq_ts_format); + + caps->ipsec_offload = MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap.ipsec_offload); + + MLX5_SET(query_hca_cap_in, in, op_mod, + MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 | HCA_CAP_OPMOD_GET_CUR); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); + if (ret) { + mlx5_core_err(mdev, "Failed to query device caps 2\n"); + goto out; + } + + caps->full_dw_jumbo_support = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap_2.format_select_dw_8_6_ext); + + caps->format_select_gtpu_dw_0 = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap_2.format_select_dw_gtpu_dw_0); + + caps->format_select_gtpu_dw_1 = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap_2.format_select_dw_gtpu_dw_1); + + caps->format_select_gtpu_dw_2 = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap_2.format_select_dw_gtpu_dw_2); + + caps->format_select_gtpu_ext_dw_0 = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap_2.format_select_dw_gtpu_first_ext_dw_0); + + caps->supp_type_gen_wqe = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap_2.generate_wqe_type); + + caps->flow_table_hash_type = + MLX5_GET(query_hca_cap_out, out, + capability.cmd_hca_cap_2.flow_table_hash_type); + + MLX5_SET(query_hca_cap_in, in, op_mod, + MLX5_GET_HCA_CAP_OP_MOD_NIC_FLOW_TABLE | HCA_CAP_OPMOD_GET_CUR); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); + if (ret) { + mlx5_core_err(mdev, "Failed to query flow table caps\n"); + goto out; + } + + caps->nic_ft.max_level = + MLX5_GET(query_hca_cap_out, out, + capability.flow_table_nic_cap.flow_table_properties_nic_receive.max_ft_level); + + caps->nic_ft.reparse = + MLX5_GET(query_hca_cap_out, out, + capability.flow_table_nic_cap.flow_table_properties_nic_receive.reparse); + + caps->nic_ft.ignore_flow_level_rtc_valid = + MLX5_GET(query_hca_cap_out, out, + capability.flow_table_nic_cap.flow_table_properties_nic_receive.ignore_flow_level_rtc_valid); + + caps->flex_parser_ok_bits_supp = + MLX5_GET(query_hca_cap_out, out, + capability.flow_table_nic_cap.flow_table_properties_nic_receive.ft_field_support.geneve_tlv_option_0_exist); + + if (caps->wqe_based_update) { + MLX5_SET(query_hca_cap_in, in, op_mod, + MLX5_GET_HCA_CAP_OP_MOD_WQE_BASED_FLOW_TABLE | HCA_CAP_OPMOD_GET_CUR); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); + if (ret) { + mlx5_core_err(mdev, "Failed to query WQE based FT caps\n"); + goto out; + } + + caps->rtc_reparse_mode = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.rtc_reparse_mode); + + caps->ste_format = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.ste_format); + + caps->rtc_index_mode = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.rtc_index_mode); + + caps->rtc_log_depth_max = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.rtc_log_depth_max); + + caps->ste_alloc_log_max = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.ste_alloc_log_max); + + caps->ste_alloc_log_gran = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.ste_alloc_log_granularity); + + caps->trivial_match_definer = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.trivial_match_definer); + + caps->stc_alloc_log_max = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.stc_alloc_log_max); + + caps->stc_alloc_log_gran = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.stc_alloc_log_granularity); + + caps->rtc_hash_split_table = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.rtc_hash_split_table); + + caps->rtc_linear_lookup_table = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.rtc_linear_lookup_table); + + caps->access_index_mode = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.access_index_mode); + + caps->linear_match_definer = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.linear_match_definer_reg_c3); + + caps->rtc_max_hash_def_gen_wqe = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.rtc_max_num_hash_definer_gen_wqe); + + caps->supp_ste_format_gen_wqe = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.ste_format_gen_wqe); + + caps->fdb_tir_stc = + MLX5_GET(query_hca_cap_out, out, + capability.wqe_based_flow_table_cap.fdb_jump_to_tir_stc); + } + + if (caps->eswitch_manager) { + MLX5_SET(query_hca_cap_in, in, op_mod, + MLX5_GET_HCA_CAP_OP_MOD_ESW_FLOW_TABLE | HCA_CAP_OPMOD_GET_CUR); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); + if (ret) { + mlx5_core_err(mdev, "Failed to query flow table esw caps\n"); + goto out; + } + + caps->fdb_ft.max_level = + MLX5_GET(query_hca_cap_out, out, + capability.flow_table_nic_cap.flow_table_properties_nic_receive.max_ft_level); + + caps->fdb_ft.reparse = + MLX5_GET(query_hca_cap_out, out, + capability.flow_table_nic_cap.flow_table_properties_nic_receive.reparse); + + MLX5_SET(query_hca_cap_in, in, op_mod, + MLX5_SET_HCA_CAP_OP_MOD_ESW | HCA_CAP_OPMOD_GET_CUR); + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); + if (ret) { + mlx5_core_err(mdev, "Failed to query eswitch capabilities\n"); + goto out; + } + + if (MLX5_GET(query_hca_cap_out, out, + capability.esw_cap.esw_manager_vport_number_valid)) + caps->eswitch_manager_vport_number = + MLX5_GET(query_hca_cap_out, out, + capability.esw_cap.esw_manager_vport_number); + + caps->merged_eswitch = MLX5_GET(query_hca_cap_out, out, + capability.esw_cap.merged_eswitch); + } + + ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); + if (ret) { + mlx5_core_err(mdev, "Failed to query device attributes\n"); + goto out; + } + + snprintf(caps->fw_ver, sizeof(caps->fw_ver), "%d.%d.%d", + fw_rev_maj(mdev), fw_rev_min(mdev), fw_rev_sub(mdev)); + + caps->is_ecpf = mlx5_core_is_ecpf_esw_manager(mdev); + +out: + kfree(out); + return ret; +} + +int mlx5hws_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_function, + u16 vport_number, u16 *gvmi) +{ + bool ec_vf_func = other_function ? mlx5_core_is_ec_vf_vport(mdev, vport_number) : false; + u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; + int out_size; + void *out; + int err; + + out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); + out = kzalloc(out_size, GFP_KERNEL); + if (!out) + return -ENOMEM; + + MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); + MLX5_SET(query_hca_cap_in, in, other_function, other_function); + MLX5_SET(query_hca_cap_in, in, function_id, + mlx5_vport_to_func_id(mdev, vport_number, ec_vf_func)); + MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); + MLX5_SET(query_hca_cap_in, in, op_mod, + MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | HCA_CAP_OPMOD_GET_CUR); + + err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); + if (err) { + kfree(out); + return err; + } + + *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); + + kfree(out); + + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h new file mode 100644 index 00000000000000..434f62b0904ec4 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h @@ -0,0 +1,361 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_CMD_H_ +#define HWS_CMD_H_ + +#define WIRE_PORT 0xFFFF + +#define ACCESS_KEY_LEN 32 + +enum mlx5hws_cmd_ext_dest_flags { + MLX5HWS_CMD_EXT_DEST_REFORMAT = 1 << 0, + MLX5HWS_CMD_EXT_DEST_ESW_OWNER_VHCA_ID = 1 << 1, +}; + +struct mlx5hws_cmd_set_fte_dest { + u8 destination_type; + u32 destination_id; + enum mlx5hws_cmd_ext_dest_flags ext_flags; + u32 ext_reformat_id; + u16 esw_owner_vhca_id; +}; + +struct mlx5hws_cmd_set_fte_attr { + u32 action_flags; + bool ignore_flow_level; + u8 flow_source; + u8 extended_dest; + u8 encrypt_decrypt_type; + u32 encrypt_decrypt_obj_id; + u32 packet_reformat_id; + u32 dests_num; + struct mlx5hws_cmd_set_fte_dest *dests; +}; + +struct mlx5hws_cmd_ft_create_attr { + u8 type; + u8 level; + bool rtc_valid; + bool decap_en; + bool reformat_en; +}; + +struct mlx5hws_cmd_ft_modify_attr { + u8 type; + u32 rtc_id_0; + u32 rtc_id_1; + u32 table_miss_id; + u8 table_miss_action; + u64 modify_fs; +}; + +struct mlx5hws_cmd_ft_query_attr { + u8 type; +}; + +struct mlx5hws_cmd_fg_attr { + u32 table_id; + u32 table_type; +}; + +struct mlx5hws_cmd_forward_tbl { + u8 type; + u32 ft_id; + u32 fg_id; + u32 refcount; +}; + +struct mlx5hws_cmd_rtc_create_attr { + u32 pd; + u32 stc_base; + u32 ste_base; + u32 ste_offset; + u32 miss_ft_id; + bool fw_gen_wqe; + u8 update_index_mode; + u8 access_index_mode; + u8 num_hash_definer; + u8 log_depth; + u8 log_size; + u8 table_type; + u8 match_definer_0; + u8 match_definer_1; + u8 reparse_mode; + bool is_frst_jumbo; + bool is_scnd_range; +}; + +struct mlx5hws_cmd_alias_obj_create_attr { + u32 obj_id; + u16 vhca_id; + u16 obj_type; + u8 access_key[ACCESS_KEY_LEN]; +}; + +struct mlx5hws_cmd_stc_create_attr { + u8 log_obj_range; + u8 table_type; +}; + +struct mlx5hws_cmd_stc_modify_attr { + u32 stc_offset; + u8 action_offset; + u8 reparse_mode; + enum mlx5_ifc_stc_action_type action_type; + union { + u32 id; /* TIRN, TAG, FT ID, STE ID, CRYPTO */ + struct { + u8 decap; + u16 start_anchor; + u16 end_anchor; + } remove_header; + struct { + u32 arg_id; + u32 pattern_id; + } modify_header; + struct { + __be64 data; + } modify_action; + struct { + u32 arg_id; + u32 header_size; + u8 is_inline; + u8 encap; + u16 insert_anchor; + u16 insert_offset; + } insert_header; + struct { + u8 aso_type; + u32 devx_obj_id; + u8 return_reg_id; + } aso; + struct { + u16 vport_num; + u16 esw_owner_vhca_id; + u8 eswitch_owner_vhca_id_valid; + } vport; + struct { + struct mlx5hws_pool_chunk ste; + struct mlx5hws_pool *ste_pool; + u32 ste_obj_id; /* Internal */ + u32 match_definer_id; + u8 log_hash_size; + bool ignore_tx; + } ste_table; + struct { + u16 start_anchor; + u16 num_of_words; + } remove_words; + struct { + u8 type; + u8 op; + u8 size; + } reformat_trailer; + + u32 dest_table_id; + u32 dest_tir_num; + }; +}; + +struct mlx5hws_cmd_ste_create_attr { + u8 log_obj_range; + u8 table_type; +}; + +struct mlx5hws_cmd_definer_create_attr { + u8 *dw_selector; + u8 *byte_selector; + u8 *match_mask; +}; + +struct mlx5hws_cmd_allow_other_vhca_access_attr { + u16 obj_type; + u32 obj_id; + u8 access_key[ACCESS_KEY_LEN]; +}; + +struct mlx5hws_cmd_packet_reformat_create_attr { + u8 type; + size_t data_sz; + void *data; + u8 reformat_param_0; +}; + +struct mlx5hws_cmd_query_ft_caps { + u8 max_level; + u8 reparse; + u8 ignore_flow_level_rtc_valid; +}; + +struct mlx5hws_cmd_generate_wqe_attr { + u8 *wqe_ctrl; + u8 *gta_ctrl; + u8 *gta_data_0; + u8 *gta_data_1; + u32 pdn; +}; + +struct mlx5hws_cmd_query_caps { + u32 flex_protocols; + u8 wqe_based_update; + u8 rtc_reparse_mode; + u16 ste_format; + u8 rtc_index_mode; + u8 ste_alloc_log_max; + u8 ste_alloc_log_gran; + u8 stc_alloc_log_max; + u8 stc_alloc_log_gran; + u8 rtc_log_depth_max; + u8 format_select_gtpu_dw_0; + u8 format_select_gtpu_dw_1; + u8 flow_table_hash_type; + u8 format_select_gtpu_dw_2; + u8 format_select_gtpu_ext_dw_0; + u8 access_index_mode; + u32 linear_match_definer; + bool full_dw_jumbo_support; + bool rtc_hash_split_table; + bool rtc_linear_lookup_table; + u32 supp_type_gen_wqe; + u8 rtc_max_hash_def_gen_wqe; + u16 supp_ste_format_gen_wqe; + struct mlx5hws_cmd_query_ft_caps nic_ft; + struct mlx5hws_cmd_query_ft_caps fdb_ft; + bool eswitch_manager; + bool merged_eswitch; + u32 eswitch_manager_vport_number; + u8 log_header_modify_argument_granularity; + u8 log_header_modify_argument_max_alloc; + u8 sq_ts_format; + u8 fdb_tir_stc; + u64 definer_format_sup; + u32 trivial_match_definer; + u32 vhca_id; + u32 shared_vhca_id; + char fw_ver[64]; + bool ipsec_offload; + bool is_ecpf; + u8 flex_parser_ok_bits_supp; + u8 flex_parser_id_geneve_tlv_option_0; + u8 flex_parser_id_mpls_over_gre; + u8 flex_parser_id_mpls_over_udp; +}; + +int mlx5hws_cmd_flow_table_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_ft_create_attr *ft_attr, + u32 *table_id); + +int mlx5hws_cmd_flow_table_modify(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_ft_modify_attr *ft_attr, + u32 table_id); + +int mlx5hws_cmd_flow_table_query(struct mlx5_core_dev *mdev, + u32 obj_id, + struct mlx5hws_cmd_ft_query_attr *ft_attr, + u64 *icm_addr_0, u64 *icm_addr_1); + +int mlx5hws_cmd_flow_table_destroy(struct mlx5_core_dev *mdev, + u8 fw_ft_type, u32 table_id); + +void mlx5hws_cmd_alias_flow_table_destroy(struct mlx5_core_dev *mdev, + u32 table_id); + +int mlx5hws_cmd_rtc_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_rtc_create_attr *rtc_attr, + u32 *rtc_id); + +void mlx5hws_cmd_rtc_destroy(struct mlx5_core_dev *mdev, u32 rtc_id); + +int mlx5hws_cmd_stc_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_stc_create_attr *stc_attr, + u32 *stc_id); + +int mlx5hws_cmd_stc_modify(struct mlx5_core_dev *mdev, + u32 stc_id, + struct mlx5hws_cmd_stc_modify_attr *stc_attr); + +void mlx5hws_cmd_stc_destroy(struct mlx5_core_dev *mdev, u32 stc_id); + +int mlx5hws_cmd_generate_wqe(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_generate_wqe_attr *attr, + struct mlx5_cqe64 *ret_cqe); + +int mlx5hws_cmd_ste_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_ste_create_attr *ste_attr, + u32 *ste_id); + +void mlx5hws_cmd_ste_destroy(struct mlx5_core_dev *mdev, u32 ste_id); + +int mlx5hws_cmd_definer_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_definer_create_attr *def_attr, + u32 *definer_id); + +void mlx5hws_cmd_definer_destroy(struct mlx5_core_dev *mdev, + u32 definer_id); + +int mlx5hws_cmd_arg_create(struct mlx5_core_dev *mdev, + u16 log_obj_range, + u32 pd, + u32 *arg_id); + +void mlx5hws_cmd_arg_destroy(struct mlx5_core_dev *mdev, + u32 arg_id); + +int mlx5hws_cmd_header_modify_pattern_create(struct mlx5_core_dev *mdev, + u32 pattern_length, + u8 *actions, + u32 *ptrn_id); + +void mlx5hws_cmd_header_modify_pattern_destroy(struct mlx5_core_dev *mdev, + u32 ptrn_id); + +int mlx5hws_cmd_packet_reformat_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_packet_reformat_create_attr *attr, + u32 *reformat_id); + +int mlx5hws_cmd_packet_reformat_destroy(struct mlx5_core_dev *mdev, + u32 reformat_id); + +int mlx5hws_cmd_set_fte(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id, + u32 group_id, + struct mlx5hws_cmd_set_fte_attr *fte_attr); + +int mlx5hws_cmd_delete_fte(struct mlx5_core_dev *mdev, + u32 table_type, u32 table_id); + +struct mlx5hws_cmd_forward_tbl * +mlx5hws_cmd_forward_tbl_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_ft_create_attr *ft_attr, + struct mlx5hws_cmd_set_fte_attr *fte_attr); + +void mlx5hws_cmd_forward_tbl_destroy(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_forward_tbl *tbl); + +int mlx5hws_cmd_alias_obj_create(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_alias_obj_create_attr *alias_attr, + u32 *obj_id); + +int mlx5hws_cmd_alias_obj_destroy(struct mlx5_core_dev *mdev, + u16 obj_type, + u32 obj_id); + +int mlx5hws_cmd_sq_modify_rdy(struct mlx5_core_dev *mdev, u32 sqn); + +int mlx5hws_cmd_query_caps(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_query_caps *caps); + +void mlx5hws_cmd_set_attr_connect_miss_tbl(struct mlx5hws_context *ctx, + u32 fw_ft_type, + enum mlx5hws_table_type type, + struct mlx5hws_cmd_ft_modify_attr *ft_attr); + +int mlx5hws_cmd_allow_other_vhca_access(struct mlx5_core_dev *mdev, + struct mlx5hws_cmd_allow_other_vhca_access_attr *attr); + +int mlx5hws_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_function, + u16 vport_number, u16 *gvmi); + +#endif /* HWS_CMD_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.c new file mode 100644 index 00000000000000..fd48b05e91e054 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved. */ + +#include "internal.h" + +bool mlx5hws_context_cap_dynamic_reparse(struct mlx5hws_context *ctx) +{ + return IS_BIT_SET(ctx->caps->rtc_reparse_mode, MLX5_IFC_RTC_REPARSE_BY_STC); +} + +u8 mlx5hws_context_get_reparse_mode(struct mlx5hws_context *ctx) +{ + /* Prefer to use dynamic reparse, reparse only specific actions */ + if (mlx5hws_context_cap_dynamic_reparse(ctx)) + return MLX5_IFC_RTC_REPARSE_NEVER; + + /* Otherwise use less efficient static */ + return MLX5_IFC_RTC_REPARSE_ALWAYS; +} + +static int hws_context_pools_init(struct mlx5hws_context *ctx) +{ + struct mlx5hws_pool_attr pool_attr = {0}; + u8 max_log_sz; + int ret; + int i; + + ret = mlx5hws_pat_init_pattern_cache(&ctx->pattern_cache); + if (ret) + return ret; + + ret = mlx5hws_definer_init_cache(&ctx->definer_cache); + if (ret) + goto uninit_pat_cache; + + /* Create an STC pool per FT type */ + pool_attr.pool_type = MLX5HWS_POOL_TYPE_STC; + pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STC_POOL; + max_log_sz = min(MLX5HWS_POOL_STC_LOG_SZ, ctx->caps->stc_alloc_log_max); + pool_attr.alloc_log_sz = max(max_log_sz, ctx->caps->stc_alloc_log_gran); + + for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) { + pool_attr.table_type = i; + ctx->stc_pool[i] = mlx5hws_pool_create(ctx, &pool_attr); + if (!ctx->stc_pool[i]) { + mlx5hws_err(ctx, "Failed to allocate STC pool [%d]", i); + ret = -ENOMEM; + goto free_stc_pools; + } + } + + return 0; + +free_stc_pools: + for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) + if (ctx->stc_pool[i]) + mlx5hws_pool_destroy(ctx->stc_pool[i]); + + mlx5hws_definer_uninit_cache(ctx->definer_cache); +uninit_pat_cache: + mlx5hws_pat_uninit_pattern_cache(ctx->pattern_cache); + return ret; +} + +static void hws_context_pools_uninit(struct mlx5hws_context *ctx) +{ + int i; + + for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) { + if (ctx->stc_pool[i]) + mlx5hws_pool_destroy(ctx->stc_pool[i]); + } + + mlx5hws_definer_uninit_cache(ctx->definer_cache); + mlx5hws_pat_uninit_pattern_cache(ctx->pattern_cache); +} + +static int hws_context_init_pd(struct mlx5hws_context *ctx) +{ + int ret = 0; + + ret = mlx5_core_alloc_pd(ctx->mdev, &ctx->pd_num); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate PD\n"); + return ret; + } + + ctx->flags |= MLX5HWS_CONTEXT_FLAG_PRIVATE_PD; + + return 0; +} + +static int hws_context_uninit_pd(struct mlx5hws_context *ctx) +{ + if (ctx->flags & MLX5HWS_CONTEXT_FLAG_PRIVATE_PD) + mlx5_core_dealloc_pd(ctx->mdev, ctx->pd_num); + + return 0; +} + +static void hws_context_check_hws_supp(struct mlx5hws_context *ctx) +{ + struct mlx5hws_cmd_query_caps *caps = ctx->caps; + + /* HWS not supported on device / FW */ + if (!caps->wqe_based_update) { + mlx5hws_err(ctx, "Required HWS WQE based insertion cap not supported\n"); + return; + } + + if (!caps->eswitch_manager) { + mlx5hws_err(ctx, "HWS is not supported for non eswitch manager port\n"); + return; + } + + /* Current solution requires all rules to set reparse bit */ + if ((!caps->nic_ft.reparse || + (!caps->fdb_ft.reparse && caps->eswitch_manager)) || + !IS_BIT_SET(caps->rtc_reparse_mode, MLX5_IFC_RTC_REPARSE_ALWAYS)) { + mlx5hws_err(ctx, "Required HWS reparse cap not supported\n"); + return; + } + + /* FW/HW must support 8DW STE */ + if (!IS_BIT_SET(caps->ste_format, MLX5_IFC_RTC_STE_FORMAT_8DW)) { + mlx5hws_err(ctx, "Required HWS STE format not supported\n"); + return; + } + + /* Adding rules by hash and by offset are requirements */ + if (!IS_BIT_SET(caps->rtc_index_mode, MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH) || + !IS_BIT_SET(caps->rtc_index_mode, MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET)) { + mlx5hws_err(ctx, "Required HWS RTC update mode not supported\n"); + return; + } + + /* Support for SELECT definer ID is required */ + if (!IS_BIT_SET(caps->definer_format_sup, MLX5_IFC_DEFINER_FORMAT_ID_SELECT)) { + mlx5hws_err(ctx, "Required HWS Dynamic definer not supported\n"); + return; + } + + ctx->flags |= MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT; +} + +static int hws_context_init_hws(struct mlx5hws_context *ctx, + struct mlx5hws_context_attr *attr) +{ + int ret; + + hws_context_check_hws_supp(ctx); + + if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) + return 0; + + ret = hws_context_init_pd(ctx); + if (ret) + return ret; + + ret = hws_context_pools_init(ctx); + if (ret) + goto uninit_pd; + + if (attr->bwc) + ctx->flags |= MLX5HWS_CONTEXT_FLAG_BWC_SUPPORT; + + ret = mlx5hws_send_queues_open(ctx, attr->queues, attr->queue_size); + if (ret) + goto pools_uninit; + + INIT_LIST_HEAD(&ctx->tbl_list); + + return 0; + +pools_uninit: + hws_context_pools_uninit(ctx); +uninit_pd: + hws_context_uninit_pd(ctx); + return ret; +} + +static void hws_context_uninit_hws(struct mlx5hws_context *ctx) +{ + if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) + return; + + mlx5hws_send_queues_close(ctx); + hws_context_pools_uninit(ctx); + hws_context_uninit_pd(ctx); +} + +struct mlx5hws_context *mlx5hws_context_open(struct mlx5_core_dev *mdev, + struct mlx5hws_context_attr *attr) +{ + struct mlx5hws_context *ctx; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->mdev = mdev; + + mutex_init(&ctx->ctrl_lock); + xa_init(&ctx->peer_ctx_xa); + + ctx->caps = kzalloc(sizeof(*ctx->caps), GFP_KERNEL); + if (!ctx->caps) + goto free_ctx; + + ret = mlx5hws_cmd_query_caps(mdev, ctx->caps); + if (ret) + goto free_caps; + + ret = mlx5hws_vport_init_vports(ctx); + if (ret) + goto free_caps; + + ret = hws_context_init_hws(ctx, attr); + if (ret) + goto uninit_vports; + + mlx5hws_debug_init_dump(ctx); + + return ctx; + +uninit_vports: + mlx5hws_vport_uninit_vports(ctx); +free_caps: + kfree(ctx->caps); +free_ctx: + xa_destroy(&ctx->peer_ctx_xa); + mutex_destroy(&ctx->ctrl_lock); + kfree(ctx); + return NULL; +} + +int mlx5hws_context_close(struct mlx5hws_context *ctx) +{ + mlx5hws_debug_uninit_dump(ctx); + hws_context_uninit_hws(ctx); + mlx5hws_vport_uninit_vports(ctx); + kfree(ctx->caps); + xa_destroy(&ctx->peer_ctx_xa); + mutex_destroy(&ctx->ctrl_lock); + kfree(ctx); + return 0; +} + +void mlx5hws_context_set_peer(struct mlx5hws_context *ctx, + struct mlx5hws_context *peer_ctx, + u16 peer_vhca_id) +{ + mutex_lock(&ctx->ctrl_lock); + + if (xa_err(xa_store(&ctx->peer_ctx_xa, peer_vhca_id, peer_ctx, GFP_KERNEL))) + pr_warn("HWS: failed storing peer vhca ID in peer xarray\n"); + + mutex_unlock(&ctx->ctrl_lock); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h new file mode 100644 index 00000000000000..47f5cc8de73fa0 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_CONTEXT_H_ +#define HWS_CONTEXT_H_ + +enum mlx5hws_context_flags { + MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT = 1 << 0, + MLX5HWS_CONTEXT_FLAG_PRIVATE_PD = 1 << 1, + MLX5HWS_CONTEXT_FLAG_BWC_SUPPORT = 1 << 2, +}; + +enum mlx5hws_context_shared_stc_type { + MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3 = 0, + MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP = 1, + MLX5HWS_CONTEXT_SHARED_STC_MAX = 2, +}; + +struct mlx5hws_context_common_res { + struct mlx5hws_action_default_stc *default_stc; + struct mlx5hws_action_shared_stc *shared_stc[MLX5HWS_CONTEXT_SHARED_STC_MAX]; + struct mlx5hws_cmd_forward_tbl *default_miss; +}; + +struct mlx5hws_context_debug_info { + struct dentry *steering_debugfs; + struct dentry *fdb_debugfs; +}; + +struct mlx5hws_context_vports { + u16 esw_manager_gvmi; + u16 uplink_gvmi; + struct xarray vport_gvmi_xa; +}; + +struct mlx5hws_context { + struct mlx5_core_dev *mdev; + struct mlx5hws_cmd_query_caps *caps; + u32 pd_num; + struct mlx5hws_pool *stc_pool[MLX5HWS_TABLE_TYPE_MAX]; + struct mlx5hws_context_common_res common_res[MLX5HWS_TABLE_TYPE_MAX]; + struct mlx5hws_pattern_cache *pattern_cache; + struct mlx5hws_definer_cache *definer_cache; + struct mutex ctrl_lock; /* control lock to protect the whole context */ + enum mlx5hws_context_flags flags; + struct mlx5hws_send_engine *send_queue; + size_t queues; + struct mutex *bwc_send_queue_locks; /* protect BWC queues */ + struct lock_class_key *bwc_lock_class_keys; + struct list_head tbl_list; + struct mlx5hws_context_debug_info debug_info; + struct xarray peer_ctx_xa; + struct mlx5hws_context_vports vports; +}; + +static inline bool mlx5hws_context_bwc_supported(struct mlx5hws_context *ctx) +{ + return ctx->flags & MLX5HWS_CONTEXT_FLAG_BWC_SUPPORT; +} + +bool mlx5hws_context_cap_dynamic_reparse(struct mlx5hws_context *ctx); + +u8 mlx5hws_context_get_reparse_mode(struct mlx5hws_context *ctx); + +#endif /* HWS_CONTEXT_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.c new file mode 100644 index 00000000000000..5b200b4bc1a878 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.c @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include +#include +#include +#include +#include "internal.h" + +static int +hws_debug_dump_matcher_template_definer(struct seq_file *f, + void *parent_obj, + struct mlx5hws_definer *definer, + enum mlx5hws_debug_res_type type) +{ + int i; + + if (!definer) + return 0; + + seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,", + type, + HWS_PTR_TO_ID(definer), + HWS_PTR_TO_ID(parent_obj), + definer->obj_id, + definer->type); + + for (i = 0; i < DW_SELECTORS; i++) + seq_printf(f, "0x%x%s", definer->dw_selector[i], + (i == DW_SELECTORS - 1) ? "," : "-"); + + for (i = 0; i < BYTE_SELECTORS; i++) + seq_printf(f, "0x%x%s", definer->byte_selector[i], + (i == BYTE_SELECTORS - 1) ? "," : "-"); + + for (i = 0; i < MLX5HWS_JUMBO_TAG_SZ; i++) + seq_printf(f, "%02x", definer->mask.jumbo[i]); + + seq_puts(f, "\n"); + + return 0; +} + +static int +hws_debug_dump_matcher_match_template(struct seq_file *f, struct mlx5hws_matcher *matcher) +{ + enum mlx5hws_debug_res_type type; + int i, ret; + + for (i = 0; i < matcher->num_of_mt; i++) { + struct mlx5hws_match_template *mt = &matcher->mt[i]; + + seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d\n", + MLX5HWS_DEBUG_RES_TYPE_MATCHER_MATCH_TEMPLATE, + HWS_PTR_TO_ID(mt), + HWS_PTR_TO_ID(matcher), + mt->fc_sz, + 0, 0); + + type = MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_MATCH_DEFINER; + ret = hws_debug_dump_matcher_template_definer(f, mt, mt->definer, type); + if (ret) + return ret; + } + + return 0; +} + +static int +hws_debug_dump_matcher_action_template(struct seq_file *f, struct mlx5hws_matcher *matcher) +{ + enum mlx5hws_action_type action_type; + int i, j; + + for (i = 0; i < matcher->num_of_at; i++) { + struct mlx5hws_action_template *at = &matcher->at[i]; + + seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d", + MLX5HWS_DEBUG_RES_TYPE_MATCHER_ACTION_TEMPLATE, + HWS_PTR_TO_ID(at), + HWS_PTR_TO_ID(matcher), + at->only_term, + at->num_of_action_stes, + at->num_actions); + + for (j = 0; j < at->num_actions; j++) { + action_type = at->action_type_arr[j]; + seq_printf(f, ",%s", mlx5hws_action_type_to_str(action_type)); + } + + seq_puts(f, "\n"); + } + + return 0; +} + +static int +hws_debug_dump_matcher_attr(struct seq_file *f, struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_matcher_attr *attr = &matcher->attr; + + seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d\n", + MLX5HWS_DEBUG_RES_TYPE_MATCHER_ATTR, + HWS_PTR_TO_ID(matcher), + attr->priority, + attr->mode, + attr->table.sz_row_log, + attr->table.sz_col_log, + attr->optimize_using_rule_idx, + attr->optimize_flow_src, + attr->insert_mode, + attr->distribute_mode); + + return 0; +} + +static int hws_debug_dump_matcher(struct seq_file *f, struct mlx5hws_matcher *matcher) +{ + enum mlx5hws_table_type tbl_type = matcher->tbl->type; + struct mlx5hws_cmd_ft_query_attr ft_attr = {0}; + struct mlx5hws_pool_chunk *ste; + struct mlx5hws_pool *ste_pool; + u64 icm_addr_0 = 0; + u64 icm_addr_1 = 0; + u32 ste_0_id = -1; + u32 ste_1_id = -1; + int ret; + + seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,0x%llx", + MLX5HWS_DEBUG_RES_TYPE_MATCHER, + HWS_PTR_TO_ID(matcher), + HWS_PTR_TO_ID(matcher->tbl), + matcher->num_of_mt, + matcher->end_ft_id, + matcher->col_matcher ? HWS_PTR_TO_ID(matcher->col_matcher) : 0); + + ste = &matcher->match_ste.ste; + ste_pool = matcher->match_ste.pool; + if (ste_pool) { + ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); + if (tbl_type == MLX5HWS_TABLE_TYPE_FDB) + ste_1_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); + } + + seq_printf(f, ",%d,%d,%d,%d", + matcher->match_ste.rtc_0_id, + (int)ste_0_id, + matcher->match_ste.rtc_1_id, + (int)ste_1_id); + + ste = &matcher->action_ste[0].ste; + ste_pool = matcher->action_ste[0].pool; + if (ste_pool) { + ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); + if (tbl_type == MLX5HWS_TABLE_TYPE_FDB) + ste_1_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); + else + ste_1_id = -1; + } else { + ste_0_id = -1; + ste_1_id = -1; + } + + ft_attr.type = matcher->tbl->fw_ft_type; + ret = mlx5hws_cmd_flow_table_query(matcher->tbl->ctx->mdev, + matcher->end_ft_id, + &ft_attr, + &icm_addr_0, + &icm_addr_1); + if (ret) + return ret; + + seq_printf(f, ",%d,%d,%d,%d,%d,0x%llx,0x%llx\n", + matcher->action_ste[0].rtc_0_id, + (int)ste_0_id, + matcher->action_ste[0].rtc_1_id, + (int)ste_1_id, + 0, + mlx5hws_debug_icm_to_idx(icm_addr_0), + mlx5hws_debug_icm_to_idx(icm_addr_1)); + + ret = hws_debug_dump_matcher_attr(f, matcher); + if (ret) + return ret; + + ret = hws_debug_dump_matcher_match_template(f, matcher); + if (ret) + return ret; + + ret = hws_debug_dump_matcher_action_template(f, matcher); + if (ret) + return ret; + + return 0; +} + +static int hws_debug_dump_table(struct seq_file *f, struct mlx5hws_table *tbl) +{ + struct mlx5hws_cmd_ft_query_attr ft_attr = {0}; + struct mlx5hws_matcher *matcher; + u64 local_icm_addr_0 = 0; + u64 local_icm_addr_1 = 0; + u64 icm_addr_0 = 0; + u64 icm_addr_1 = 0; + int ret; + + seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d,%d,%d", + MLX5HWS_DEBUG_RES_TYPE_TABLE, + HWS_PTR_TO_ID(tbl), + HWS_PTR_TO_ID(tbl->ctx), + tbl->ft_id, + MLX5HWS_TABLE_TYPE_BASE + tbl->type, + tbl->fw_ft_type, + tbl->level, + 0); + + ft_attr.type = tbl->fw_ft_type; + ret = mlx5hws_cmd_flow_table_query(tbl->ctx->mdev, + tbl->ft_id, + &ft_attr, + &icm_addr_0, + &icm_addr_1); + if (ret) + return ret; + + seq_printf(f, ",0x%llx,0x%llx,0x%llx,0x%llx,0x%llx\n", + mlx5hws_debug_icm_to_idx(icm_addr_0), + mlx5hws_debug_icm_to_idx(icm_addr_1), + mlx5hws_debug_icm_to_idx(local_icm_addr_0), + mlx5hws_debug_icm_to_idx(local_icm_addr_1), + HWS_PTR_TO_ID(tbl->default_miss.miss_tbl)); + + list_for_each_entry(matcher, &tbl->matchers_list, list_node) { + ret = hws_debug_dump_matcher(f, matcher); + if (ret) + return ret; + } + + return 0; +} + +static int +hws_debug_dump_context_send_engine(struct seq_file *f, struct mlx5hws_context *ctx) +{ + struct mlx5hws_send_engine *send_queue; + struct mlx5hws_send_ring *send_ring; + struct mlx5hws_send_ring_cq *cq; + struct mlx5hws_send_ring_sq *sq; + int i; + + for (i = 0; i < (int)ctx->queues; i++) { + send_queue = &ctx->send_queue[i]; + seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_ENGINE, + HWS_PTR_TO_ID(ctx), + i, + send_queue->used_entries, + send_queue->num_entries, + 1, /* one send ring per queue */ + send_queue->num_entries, + send_queue->err, + send_queue->completed.ci, + send_queue->completed.pi, + send_queue->completed.mask); + + send_ring = &send_queue->send_ring; + cq = &send_ring->send_cq; + sq = &send_ring->send_sq; + + seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_RING, + HWS_PTR_TO_ID(ctx), + 0, /* one send ring per send queue */ + i, + cq->mcq.cqn, + 0, + 0, + 0, + 0, + 0, + 0, + cq->mcq.cqe_sz, + sq->sqn, + 0, + 0, + 0); + } + + return 0; +} + +static int hws_debug_dump_context_caps(struct seq_file *f, struct mlx5hws_context *ctx) +{ + struct mlx5hws_cmd_query_caps *caps = ctx->caps; + + seq_printf(f, "%d,0x%llx,%s,%d,%d,%d,%d,", + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_CAPS, + HWS_PTR_TO_ID(ctx), + caps->fw_ver, + caps->wqe_based_update, + caps->ste_format, + caps->ste_alloc_log_max, + caps->log_header_modify_argument_max_alloc); + + seq_printf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s\n", + caps->flex_protocols, + caps->rtc_reparse_mode, + caps->rtc_index_mode, + caps->ste_alloc_log_gran, + caps->stc_alloc_log_max, + caps->stc_alloc_log_gran, + caps->rtc_log_depth_max, + caps->format_select_gtpu_dw_0, + caps->format_select_gtpu_dw_1, + caps->format_select_gtpu_dw_2, + caps->format_select_gtpu_ext_dw_0, + caps->nic_ft.max_level, + caps->nic_ft.reparse, + caps->fdb_ft.max_level, + caps->fdb_ft.reparse, + caps->log_header_modify_argument_granularity, + caps->linear_match_definer, + "regc_3"); + + return 0; +} + +static int hws_debug_dump_context_attr(struct seq_file *f, struct mlx5hws_context *ctx) +{ + seq_printf(f, "%u,0x%llx,%d,%zu,%d,%s,%d,%d\n", + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_ATTR, + HWS_PTR_TO_ID(ctx), + ctx->pd_num, + ctx->queues, + ctx->send_queue->num_entries, + "None", /* no shared gvmi */ + ctx->caps->vhca_id, + 0xffff); /* no shared gvmi */ + + return 0; +} + +static int hws_debug_dump_context_info(struct seq_file *f, struct mlx5hws_context *ctx) +{ + struct mlx5_core_dev *dev = ctx->mdev; + int ret; + + seq_printf(f, "%d,0x%llx,%d,%s,%s.KERNEL_%u_%u_%u\n", + MLX5HWS_DEBUG_RES_TYPE_CONTEXT, + HWS_PTR_TO_ID(ctx), + ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT, + pci_name(dev->pdev), + HWS_DEBUG_FORMAT_VERSION, + LINUX_VERSION_MAJOR, + LINUX_VERSION_PATCHLEVEL, + LINUX_VERSION_SUBLEVEL); + + ret = hws_debug_dump_context_attr(f, ctx); + if (ret) + return ret; + + ret = hws_debug_dump_context_caps(f, ctx); + if (ret) + return ret; + + return 0; +} + +static int hws_debug_dump_context_stc_resource(struct seq_file *f, + struct mlx5hws_context *ctx, + u32 tbl_type, + struct mlx5hws_pool_resource *resource) +{ + seq_printf(f, "%d,0x%llx,%u,%u\n", + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_STC, + HWS_PTR_TO_ID(ctx), + tbl_type, + resource->base_id); + + return 0; +} + +static int hws_debug_dump_context_stc(struct seq_file *f, struct mlx5hws_context *ctx) +{ + struct mlx5hws_pool *stc_pool; + u32 table_type; + int ret; + int i; + + for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) { + stc_pool = ctx->stc_pool[i]; + table_type = MLX5HWS_TABLE_TYPE_BASE + i; + + if (!stc_pool) + continue; + + if (stc_pool->resource[0]) { + ret = hws_debug_dump_context_stc_resource(f, ctx, table_type, + stc_pool->resource[0]); + if (ret) + return ret; + } + + if (i == MLX5HWS_TABLE_TYPE_FDB && stc_pool->mirror_resource[0]) { + ret = hws_debug_dump_context_stc_resource(f, ctx, table_type, + stc_pool->mirror_resource[0]); + if (ret) + return ret; + } + } + + return 0; +} + +static int hws_debug_dump_context(struct seq_file *f, struct mlx5hws_context *ctx) +{ + struct mlx5hws_table *tbl; + int ret; + + ret = hws_debug_dump_context_info(f, ctx); + if (ret) + return ret; + + ret = hws_debug_dump_context_send_engine(f, ctx); + if (ret) + return ret; + + ret = hws_debug_dump_context_stc(f, ctx); + if (ret) + return ret; + + list_for_each_entry(tbl, &ctx->tbl_list, tbl_list_node) { + ret = hws_debug_dump_table(f, tbl); + if (ret) + return ret; + } + + return 0; +} + +static int +hws_debug_dump(struct seq_file *f, struct mlx5hws_context *ctx) +{ + int ret; + + if (!f || !ctx) + return -EINVAL; + + mutex_lock(&ctx->ctrl_lock); + ret = hws_debug_dump_context(f, ctx); + mutex_unlock(&ctx->ctrl_lock); + + return ret; +} + +static int hws_dump_show(struct seq_file *file, void *priv) +{ + return hws_debug_dump(file, file->private); +} +DEFINE_SHOW_ATTRIBUTE(hws_dump); + +void mlx5hws_debug_init_dump(struct mlx5hws_context *ctx) +{ + struct mlx5_core_dev *dev = ctx->mdev; + char file_name[128]; + + ctx->debug_info.steering_debugfs = + debugfs_create_dir("steering", mlx5_debugfs_get_dev_root(dev)); + ctx->debug_info.fdb_debugfs = + debugfs_create_dir("fdb", ctx->debug_info.steering_debugfs); + + sprintf(file_name, "ctx_%p", ctx); + debugfs_create_file(file_name, 0444, ctx->debug_info.fdb_debugfs, + ctx, &hws_dump_fops); +} + +void mlx5hws_debug_uninit_dump(struct mlx5hws_context *ctx) +{ + debugfs_remove_recursive(ctx->debug_info.steering_debugfs); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.h new file mode 100644 index 00000000000000..e44e7ae28f93ed --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_DEBUG_H_ +#define HWS_DEBUG_H_ + +#define HWS_DEBUG_FORMAT_VERSION "1.0" + +#define HWS_PTR_TO_ID(p) ((u64)(uintptr_t)(p) & 0xFFFFFFFFULL) + +enum mlx5hws_debug_res_type { + MLX5HWS_DEBUG_RES_TYPE_CONTEXT = 4000, + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_ATTR = 4001, + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_CAPS = 4002, + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_ENGINE = 4003, + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_RING = 4004, + MLX5HWS_DEBUG_RES_TYPE_CONTEXT_STC = 4005, + + MLX5HWS_DEBUG_RES_TYPE_TABLE = 4100, + + MLX5HWS_DEBUG_RES_TYPE_MATCHER = 4200, + MLX5HWS_DEBUG_RES_TYPE_MATCHER_ATTR = 4201, + MLX5HWS_DEBUG_RES_TYPE_MATCHER_MATCH_TEMPLATE = 4202, + MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_MATCH_DEFINER = 4203, + MLX5HWS_DEBUG_RES_TYPE_MATCHER_ACTION_TEMPLATE = 4204, + MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_HASH_DEFINER = 4205, + MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_RANGE_DEFINER = 4206, + MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_COMPARE_MATCH_DEFINER = 4207, +}; + +static inline u64 +mlx5hws_debug_icm_to_idx(u64 icm_addr) +{ + return (icm_addr >> 6) & 0xffffffff; +} + +void mlx5hws_debug_init_dump(struct mlx5hws_context *ctx); +void mlx5hws_debug_uninit_dump(struct mlx5hws_context *ctx); + +#endif /* HWS_DEBUG_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c new file mode 100644 index 00000000000000..8fe96eb76baff7 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c @@ -0,0 +1,2146 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +/* Pattern tunnel Layer bits. */ +#define MLX5_FLOW_LAYER_VXLAN BIT(12) +#define MLX5_FLOW_LAYER_VXLAN_GPE BIT(13) +#define MLX5_FLOW_LAYER_GRE BIT(14) +#define MLX5_FLOW_LAYER_MPLS BIT(15) + +/* Pattern tunnel Layer bits (continued). */ +#define MLX5_FLOW_LAYER_IPIP BIT(23) +#define MLX5_FLOW_LAYER_IPV6_ENCAP BIT(24) +#define MLX5_FLOW_LAYER_NVGRE BIT(25) +#define MLX5_FLOW_LAYER_GENEVE BIT(26) + +#define MLX5_FLOW_ITEM_FLEX_TUNNEL BIT_ULL(39) + +/* Tunnel Masks. */ +#define MLX5_FLOW_LAYER_TUNNEL \ + (MLX5_FLOW_LAYER_VXLAN | MLX5_FLOW_LAYER_VXLAN_GPE | \ + MLX5_FLOW_LAYER_GRE | MLX5_FLOW_LAYER_NVGRE | MLX5_FLOW_LAYER_MPLS | \ + MLX5_FLOW_LAYER_IPIP | MLX5_FLOW_LAYER_IPV6_ENCAP | \ + MLX5_FLOW_LAYER_GENEVE | MLX5_FLOW_LAYER_GTP | \ + MLX5_FLOW_ITEM_FLEX_TUNNEL) + +#define GTP_PDU_SC 0x85 +#define BAD_PORT 0xBAD +#define ETH_TYPE_IPV4_VXLAN 0x0800 +#define ETH_TYPE_IPV6_VXLAN 0x86DD +#define UDP_GTPU_PORT 2152 +#define UDP_PORT_MPLS 6635 +#define UDP_GENEVE_PORT 6081 +#define UDP_ROCEV2_PORT 4791 +#define HWS_FLOW_LAYER_TUNNEL_NO_MPLS (MLX5_FLOW_LAYER_TUNNEL & ~MLX5_FLOW_LAYER_MPLS) + +#define STE_NO_VLAN 0x0 +#define STE_SVLAN 0x1 +#define STE_CVLAN 0x2 +#define STE_NO_L3 0x0 +#define STE_IPV4 0x1 +#define STE_IPV6 0x2 +#define STE_NO_L4 0x0 +#define STE_TCP 0x1 +#define STE_UDP 0x2 +#define STE_ICMP 0x3 +#define STE_ESP 0x3 + +#define IPV4 0x4 +#define IPV6 0x6 + +/* Setter function based on bit offset and mask, for 32bit DW */ +#define _HWS_SET32(p, v, byte_off, bit_off, mask) \ + do { \ + u32 _v = v; \ + *((__be32 *)(p) + ((byte_off) / 4)) = \ + cpu_to_be32((be32_to_cpu(*((__be32 *)(p) + \ + ((byte_off) / 4))) & \ + (~((mask) << (bit_off)))) | \ + (((_v) & (mask)) << \ + (bit_off))); \ + } while (0) + +/* Setter function based on bit offset and mask, for unaligned 32bit DW */ +#define HWS_SET32(p, v, byte_off, bit_off, mask) \ + do { \ + if (unlikely((bit_off) < 0)) { \ + u32 _bit_off = -1 * (bit_off); \ + u32 second_dw_mask = (mask) & ((1 << _bit_off) - 1); \ + _HWS_SET32(p, (v) >> _bit_off, byte_off, 0, (mask) >> _bit_off); \ + _HWS_SET32(p, (v) & second_dw_mask, (byte_off) + DW_SIZE, \ + (bit_off) % BITS_IN_DW, second_dw_mask); \ + } else { \ + _HWS_SET32(p, v, byte_off, (bit_off), (mask)); \ + } \ + } while (0) + +/* Getter for up to aligned 32bit DW */ +#define HWS_GET32(p, byte_off, bit_off, mask) \ + ((be32_to_cpu(*((__be32 *)(p) + ((byte_off) / 4))) >> (bit_off)) & (mask)) + +#define HWS_CALC_FNAME(field, inner) \ + ((inner) ? MLX5HWS_DEFINER_FNAME_##field##_I : \ + MLX5HWS_DEFINER_FNAME_##field##_O) + +#define HWS_GET_MATCH_PARAM(match_param, hdr) \ + MLX5_GET(fte_match_param, match_param, hdr) + +#define HWS_IS_FLD_SET(match_param, hdr) \ + (!!(HWS_GET_MATCH_PARAM(match_param, hdr))) + +#define HWS_IS_FLD_SET_DW_ARR(match_param, hdr, sz_in_bits) ({ \ + BUILD_BUG_ON((sz_in_bits) % 32); \ + u32 sz = sz_in_bits; \ + u32 res = 0; \ + u32 dw_off = __mlx5_dw_off(fte_match_param, hdr); \ + while (!res && sz >= 32) { \ + res = *((match_param) + (dw_off++)); \ + sz -= 32; \ + } \ + res; \ + }) + +#define HWS_IS_FLD_SET_SZ(match_param, hdr, sz_in_bits) \ + (((sz_in_bits) > 32) ? HWS_IS_FLD_SET_DW_ARR(match_param, hdr, sz_in_bits) : \ + !!(HWS_GET_MATCH_PARAM(match_param, hdr))) + +#define HWS_GET64_MATCH_PARAM(match_param, hdr) \ + MLX5_GET64(fte_match_param, match_param, hdr) + +#define HWS_IS_FLD64_SET(match_param, hdr) \ + (!!(HWS_GET64_MATCH_PARAM(match_param, hdr))) + +#define HWS_CALC_HDR_SRC(fc, s_hdr) \ + do { \ + (fc)->s_bit_mask = __mlx5_mask(fte_match_param, s_hdr); \ + (fc)->s_bit_off = __mlx5_dw_bit_off(fte_match_param, s_hdr); \ + (fc)->s_byte_off = MLX5_BYTE_OFF(fte_match_param, s_hdr); \ + } while (0) + +#define HWS_CALC_HDR_DST(fc, d_hdr) \ + do { \ + (fc)->bit_mask = __mlx5_mask(definer_hl, d_hdr); \ + (fc)->bit_off = __mlx5_dw_bit_off(definer_hl, d_hdr); \ + (fc)->byte_off = MLX5_BYTE_OFF(definer_hl, d_hdr); \ + } while (0) + +#define HWS_CALC_HDR(fc, s_hdr, d_hdr) \ + do { \ + HWS_CALC_HDR_SRC(fc, s_hdr); \ + HWS_CALC_HDR_DST(fc, d_hdr); \ + (fc)->tag_set = &hws_definer_generic_set; \ + } while (0) + +#define HWS_SET_HDR(fc_arr, match_param, fname, s_hdr, d_hdr) \ + do { \ + if (HWS_IS_FLD_SET(match_param, s_hdr)) \ + HWS_CALC_HDR(&(fc_arr)[MLX5HWS_DEFINER_FNAME_##fname], s_hdr, d_hdr); \ + } while (0) + +struct mlx5hws_definer_sel_ctrl { + u8 allowed_full_dw; /* Full DW selectors cover all offsets */ + u8 allowed_lim_dw; /* Limited DW selectors cover offset < 64 */ + u8 allowed_bytes; /* Bytes selectors, up to offset 255 */ + u8 used_full_dw; + u8 used_lim_dw; + u8 used_bytes; + u8 full_dw_selector[DW_SELECTORS]; + u8 lim_dw_selector[DW_SELECTORS_LIMITED]; + u8 byte_selector[BYTE_SELECTORS]; +}; + +struct mlx5hws_definer_conv_data { + struct mlx5hws_context *ctx; + struct mlx5hws_definer_fc *fc; + /* enum mlx5hws_definer_match_flag */ + u32 match_flags; +}; + +static void +hws_definer_ones_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + HWS_SET32(tag, -1, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_generic_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + /* Can be optimized */ + u32 val = HWS_GET32(match_param, fc->s_byte_off, fc->s_bit_off, fc->s_bit_mask); + + HWS_SET32(tag, val, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_outer_vlan_type_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + if (HWS_GET_MATCH_PARAM(match_param, outer_headers.cvlan_tag)) + HWS_SET32(tag, STE_CVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); + else if (HWS_GET_MATCH_PARAM(match_param, outer_headers.svlan_tag)) + HWS_SET32(tag, STE_SVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); + else + HWS_SET32(tag, STE_NO_VLAN, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_inner_vlan_type_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + if (HWS_GET_MATCH_PARAM(match_param, inner_headers.cvlan_tag)) + HWS_SET32(tag, STE_CVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); + else if (HWS_GET_MATCH_PARAM(match_param, inner_headers.svlan_tag)) + HWS_SET32(tag, STE_SVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); + else + HWS_SET32(tag, STE_NO_VLAN, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_second_vlan_type_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag, + bool inner) +{ + u32 second_cvlan_tag = inner ? + HWS_GET_MATCH_PARAM(match_param, misc_parameters.inner_second_cvlan_tag) : + HWS_GET_MATCH_PARAM(match_param, misc_parameters.outer_second_cvlan_tag); + u32 second_svlan_tag = inner ? + HWS_GET_MATCH_PARAM(match_param, misc_parameters.inner_second_svlan_tag) : + HWS_GET_MATCH_PARAM(match_param, misc_parameters.outer_second_svlan_tag); + + if (second_cvlan_tag) + HWS_SET32(tag, STE_CVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); + else if (second_svlan_tag) + HWS_SET32(tag, STE_SVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); + else + HWS_SET32(tag, STE_NO_VLAN, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_inner_second_vlan_type_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + hws_definer_second_vlan_type_set(fc, match_param, tag, true); +} + +static void +hws_definer_outer_second_vlan_type_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + hws_definer_second_vlan_type_set(fc, match_param, tag, false); +} + +static void hws_definer_icmp_dw1_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + u32 code = HWS_GET_MATCH_PARAM(match_param, misc_parameters_3.icmp_code); + u32 type = HWS_GET_MATCH_PARAM(match_param, misc_parameters_3.icmp_type); + u32 dw = (type << __mlx5_dw_bit_off(header_icmp, type)) | + (code << __mlx5_dw_bit_off(header_icmp, code)); + + HWS_SET32(tag, dw, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_icmpv6_dw1_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + u32 code = HWS_GET_MATCH_PARAM(match_param, misc_parameters_3.icmpv6_code); + u32 type = HWS_GET_MATCH_PARAM(match_param, misc_parameters_3.icmpv6_type); + u32 dw = (type << __mlx5_dw_bit_off(header_icmp, type)) | + (code << __mlx5_dw_bit_off(header_icmp, code)); + + HWS_SET32(tag, dw, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_l3_type_set(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + u32 val = HWS_GET32(match_param, fc->s_byte_off, fc->s_bit_off, fc->s_bit_mask); + + if (val == IPV4) + HWS_SET32(tag, STE_IPV4, fc->byte_off, fc->bit_off, fc->bit_mask); + else if (val == IPV6) + HWS_SET32(tag, STE_IPV6, fc->byte_off, fc->bit_off, fc->bit_mask); + else + HWS_SET32(tag, STE_NO_L3, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_set_source_port_gvmi(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag, + struct mlx5hws_context *peer_ctx) +{ + u16 source_port = HWS_GET_MATCH_PARAM(match_param, misc_parameters.source_port); + u16 vport_gvmi = 0; + int ret; + + ret = mlx5hws_vport_get_gvmi(peer_ctx, source_port, &vport_gvmi); + if (ret) { + HWS_SET32(tag, BAD_PORT, fc->byte_off, fc->bit_off, fc->bit_mask); + mlx5hws_err(fc->ctx, "Vport 0x%x is disabled or invalid\n", source_port); + return; + } + + if (vport_gvmi) + HWS_SET32(tag, vport_gvmi, fc->byte_off, fc->bit_off, fc->bit_mask); +} + +static void +hws_definer_set_source_gvmi_vhca_id(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +__must_hold(&fc->ctx->ctrl_lock) +{ + int id = HWS_GET_MATCH_PARAM(match_param, misc_parameters.source_eswitch_owner_vhca_id); + struct mlx5hws_context *peer_ctx; + + if (id == fc->ctx->caps->vhca_id) + peer_ctx = fc->ctx; + else + peer_ctx = xa_load(&fc->ctx->peer_ctx_xa, id); + + if (!peer_ctx) { + HWS_SET32(tag, BAD_PORT, fc->byte_off, fc->bit_off, fc->bit_mask); + mlx5hws_err(fc->ctx, "Invalid vhca_id provided 0x%x\n", id); + return; + } + + hws_definer_set_source_port_gvmi(fc, match_param, tag, peer_ctx); +} + +static void +hws_definer_set_source_gvmi(struct mlx5hws_definer_fc *fc, + void *match_param, + u8 *tag) +{ + hws_definer_set_source_port_gvmi(fc, match_param, tag, fc->ctx); +} + +static struct mlx5hws_definer_fc * +hws_definer_flex_parser_steering_ok_bits_handler(struct mlx5hws_definer_conv_data *cd, + u8 parser_id) +{ + struct mlx5hws_definer_fc *fc; + + switch (parser_id) { + case 0: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER0_OK]; + HWS_CALC_HDR_DST(fc, oks1.flex_parser0_steering_ok); + fc->tag_set = &hws_definer_generic_set; + break; + case 1: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER1_OK]; + HWS_CALC_HDR_DST(fc, oks1.flex_parser1_steering_ok); + fc->tag_set = &hws_definer_generic_set; + break; + case 2: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER2_OK]; + HWS_CALC_HDR_DST(fc, oks1.flex_parser2_steering_ok); + fc->tag_set = &hws_definer_generic_set; + break; + case 3: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER3_OK]; + HWS_CALC_HDR_DST(fc, oks1.flex_parser3_steering_ok); + fc->tag_set = &hws_definer_generic_set; + break; + case 4: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER4_OK]; + HWS_CALC_HDR_DST(fc, oks1.flex_parser4_steering_ok); + fc->tag_set = &hws_definer_generic_set; + break; + case 5: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER5_OK]; + HWS_CALC_HDR_DST(fc, oks1.flex_parser5_steering_ok); + fc->tag_set = &hws_definer_generic_set; + break; + case 6: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER6_OK]; + HWS_CALC_HDR_DST(fc, oks1.flex_parser6_steering_ok); + fc->tag_set = &hws_definer_generic_set; + break; + case 7: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER7_OK]; + HWS_CALC_HDR_DST(fc, oks1.flex_parser7_steering_ok); + fc->tag_set = &hws_definer_generic_set; + break; + default: + mlx5hws_err(cd->ctx, "Unsupported flex parser steering ok index %u\n", parser_id); + return NULL; + } + + return fc; +} + +static struct mlx5hws_definer_fc * +hws_definer_flex_parser_handler(struct mlx5hws_definer_conv_data *cd, + u8 parser_id) +{ + struct mlx5hws_definer_fc *fc; + + switch (parser_id) { + case 0: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_0]; + HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_0); + fc->tag_set = &hws_definer_generic_set; + break; + case 1: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_1]; + HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_1); + fc->tag_set = &hws_definer_generic_set; + break; + case 2: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_2]; + HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_2); + fc->tag_set = &hws_definer_generic_set; + break; + case 3: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_3]; + HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_3); + fc->tag_set = &hws_definer_generic_set; + break; + case 4: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_4]; + HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_4); + fc->tag_set = &hws_definer_generic_set; + break; + case 5: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_5]; + HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_5); + fc->tag_set = &hws_definer_generic_set; + break; + case 6: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_6]; + HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_6); + fc->tag_set = &hws_definer_generic_set; + break; + case 7: + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_7]; + HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_7); + fc->tag_set = &hws_definer_generic_set; + break; + default: + mlx5hws_err(cd->ctx, "Unsupported flex parser %u\n", parser_id); + return NULL; + } + + return fc; +} + +static struct mlx5hws_definer_fc * +hws_definer_misc4_fields_handler(struct mlx5hws_definer_conv_data *cd, + bool *parser_is_used, + u32 id, + u32 value) +{ + if (id || value) { + if (id >= HWS_NUM_OF_FLEX_PARSERS) { + mlx5hws_err(cd->ctx, "Unsupported parser id\n"); + return NULL; + } + + if (parser_is_used[id]) { + mlx5hws_err(cd->ctx, "Parser id have been used\n"); + return NULL; + } + } + + parser_is_used[id] = true; + + return hws_definer_flex_parser_handler(cd, id); +} + +static int +hws_definer_check_match_flags(struct mlx5hws_definer_conv_data *cd) +{ + u32 flags; + + flags = cd->match_flags & (MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE | + MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE | + MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU | + MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE | + MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN | + MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_0_1); + if (flags & (flags - 1)) + goto err_conflict; + + flags = cd->match_flags & (MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE_OPT_KEY | + MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_2); + + if (flags & (flags - 1)) + goto err_conflict; + + flags = cd->match_flags & (MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_GRE | + MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_UDP); + if (flags & (flags - 1)) + goto err_conflict; + + flags = cd->match_flags & (MLX5HWS_DEFINER_MATCH_FLAG_ICMPV4 | + MLX5HWS_DEFINER_MATCH_FLAG_ICMPV6 | + MLX5HWS_DEFINER_MATCH_FLAG_TCP_O | + MLX5HWS_DEFINER_MATCH_FLAG_TCP_I); + if (flags & (flags - 1)) + goto err_conflict; + + return 0; + +err_conflict: + mlx5hws_err(cd->ctx, "Invalid definer fields combination\n"); + return -EINVAL; +} + +static int +hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd, + u32 *match_param) +{ + bool is_s_ipv6, is_d_ipv6, smac_set, dmac_set; + struct mlx5hws_definer_fc *fc = cd->fc; + struct mlx5hws_definer_fc *curr_fc; + u32 *s_ipv6, *d_ipv6; + + if (HWS_IS_FLD_SET_SZ(match_param, outer_headers.l4_type, 0x2) || + HWS_IS_FLD_SET_SZ(match_param, outer_headers.reserved_at_c2, 0xe) || + HWS_IS_FLD_SET_SZ(match_param, outer_headers.reserved_at_c4, 0x4)) { + mlx5hws_err(cd->ctx, "Unsupported outer parameters set\n"); + return -EINVAL; + } + + /* L2 Check ethertype */ + HWS_SET_HDR(fc, match_param, ETH_TYPE_O, + outer_headers.ethertype, + eth_l2_outer.l3_ethertype); + /* L2 Check SMAC 47_16 */ + HWS_SET_HDR(fc, match_param, ETH_SMAC_47_16_O, + outer_headers.smac_47_16, eth_l2_src_outer.smac_47_16); + /* L2 Check SMAC 15_0 */ + HWS_SET_HDR(fc, match_param, ETH_SMAC_15_0_O, + outer_headers.smac_15_0, eth_l2_src_outer.smac_15_0); + /* L2 Check DMAC 47_16 */ + HWS_SET_HDR(fc, match_param, ETH_DMAC_47_16_O, + outer_headers.dmac_47_16, eth_l2_outer.dmac_47_16); + /* L2 Check DMAC 15_0 */ + HWS_SET_HDR(fc, match_param, ETH_DMAC_15_0_O, + outer_headers.dmac_15_0, eth_l2_outer.dmac_15_0); + + /* L2 VLAN */ + HWS_SET_HDR(fc, match_param, VLAN_FIRST_PRIO_O, + outer_headers.first_prio, eth_l2_outer.first_priority); + HWS_SET_HDR(fc, match_param, VLAN_CFI_O, + outer_headers.first_cfi, eth_l2_outer.first_cfi); + HWS_SET_HDR(fc, match_param, VLAN_ID_O, + outer_headers.first_vid, eth_l2_outer.first_vlan_id); + + /* L2 CVLAN and SVLAN */ + if (HWS_GET_MATCH_PARAM(match_param, outer_headers.cvlan_tag) || + HWS_GET_MATCH_PARAM(match_param, outer_headers.svlan_tag)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VLAN_TYPE_O]; + HWS_CALC_HDR_DST(curr_fc, eth_l2_outer.first_vlan_qualifier); + curr_fc->tag_set = &hws_definer_outer_vlan_type_set; + curr_fc->tag_mask_set = &hws_definer_ones_set; + } + + /* L3 Check IP header */ + HWS_SET_HDR(fc, match_param, IP_PROTOCOL_O, + outer_headers.ip_protocol, + eth_l3_outer.protocol_next_header); + HWS_SET_HDR(fc, match_param, IP_TTL_O, + outer_headers.ttl_hoplimit, + eth_l3_outer.time_to_live_hop_limit); + + /* L3 Check IPv4/IPv6 addresses */ + s_ipv6 = MLX5_ADDR_OF(fte_match_param, match_param, + outer_headers.src_ipv4_src_ipv6.ipv6_layout); + d_ipv6 = MLX5_ADDR_OF(fte_match_param, match_param, + outer_headers.dst_ipv4_dst_ipv6.ipv6_layout); + + /* Assume IPv6 is used if ipv6 bits are set */ + is_s_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2]; + is_d_ipv6 = d_ipv6[0] || d_ipv6[1] || d_ipv6[2]; + + if (is_s_ipv6) { + /* Handle IPv6 source address */ + HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_O, + outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_127_96, + ipv6_src_outer.ipv6_address_127_96); + HWS_SET_HDR(fc, match_param, IPV6_SRC_95_64_O, + outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_95_64, + ipv6_src_outer.ipv6_address_95_64); + HWS_SET_HDR(fc, match_param, IPV6_SRC_63_32_O, + outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_63_32, + ipv6_src_outer.ipv6_address_63_32); + HWS_SET_HDR(fc, match_param, IPV6_SRC_31_0_O, + outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv6_src_outer.ipv6_address_31_0); + } else { + /* Handle IPv4 source address */ + HWS_SET_HDR(fc, match_param, IPV4_SRC_O, + outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv4_src_dest_outer.source_address); + } + if (is_d_ipv6) { + /* Handle IPv6 destination address */ + HWS_SET_HDR(fc, match_param, IPV6_DST_127_96_O, + outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_127_96, + ipv6_dst_outer.ipv6_address_127_96); + HWS_SET_HDR(fc, match_param, IPV6_DST_95_64_O, + outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_95_64, + ipv6_dst_outer.ipv6_address_95_64); + HWS_SET_HDR(fc, match_param, IPV6_DST_63_32_O, + outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_63_32, + ipv6_dst_outer.ipv6_address_63_32); + HWS_SET_HDR(fc, match_param, IPV6_DST_31_0_O, + outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv6_dst_outer.ipv6_address_31_0); + } else { + /* Handle IPv4 destination address */ + HWS_SET_HDR(fc, match_param, IPV4_DST_O, + outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv4_src_dest_outer.destination_address); + } + + /* L4 Handle TCP/UDP */ + HWS_SET_HDR(fc, match_param, L4_SPORT_O, + outer_headers.tcp_sport, eth_l4_outer.source_port); + HWS_SET_HDR(fc, match_param, L4_DPORT_O, + outer_headers.tcp_dport, eth_l4_outer.destination_port); + HWS_SET_HDR(fc, match_param, L4_SPORT_O, + outer_headers.udp_sport, eth_l4_outer.source_port); + HWS_SET_HDR(fc, match_param, L4_DPORT_O, + outer_headers.udp_dport, eth_l4_outer.destination_port); + HWS_SET_HDR(fc, match_param, TCP_FLAGS_O, + outer_headers.tcp_flags, eth_l4_outer.tcp_flags); + + /* L3 Handle DSCP, ECN and IHL */ + HWS_SET_HDR(fc, match_param, IP_DSCP_O, + outer_headers.ip_dscp, eth_l3_outer.dscp); + HWS_SET_HDR(fc, match_param, IP_ECN_O, + outer_headers.ip_ecn, eth_l3_outer.ecn); + HWS_SET_HDR(fc, match_param, IPV4_IHL_O, + outer_headers.ipv4_ihl, eth_l3_outer.ihl); + + /* Set IP fragmented bit */ + if (HWS_IS_FLD_SET(match_param, outer_headers.frag)) { + smac_set = HWS_IS_FLD_SET(match_param, outer_headers.smac_15_0) || + HWS_IS_FLD_SET(match_param, outer_headers.smac_47_16); + dmac_set = HWS_IS_FLD_SET(match_param, outer_headers.dmac_15_0) || + HWS_IS_FLD_SET(match_param, outer_headers.dmac_47_16); + if (smac_set == dmac_set) { + HWS_SET_HDR(fc, match_param, IP_FRAG_O, + outer_headers.frag, eth_l4_outer.ip_fragmented); + } else { + HWS_SET_HDR(fc, match_param, IP_FRAG_O, + outer_headers.frag, eth_l2_src_outer.ip_fragmented); + } + } + + /* L3_type set */ + if (HWS_IS_FLD_SET(match_param, outer_headers.ip_version)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_O]; + HWS_CALC_HDR_DST(curr_fc, eth_l2_outer.l3_type); + curr_fc->tag_set = &hws_definer_l3_type_set; + curr_fc->tag_mask_set = &hws_definer_ones_set; + HWS_CALC_HDR_SRC(curr_fc, outer_headers.ip_version); + } + + return 0; +} + +static int +hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd, + u32 *match_param) +{ + bool is_s_ipv6, is_d_ipv6, smac_set, dmac_set; + struct mlx5hws_definer_fc *fc = cd->fc; + struct mlx5hws_definer_fc *curr_fc; + u32 *s_ipv6, *d_ipv6; + + if (HWS_IS_FLD_SET_SZ(match_param, inner_headers.l4_type, 0x2) || + HWS_IS_FLD_SET_SZ(match_param, inner_headers.reserved_at_c2, 0xe) || + HWS_IS_FLD_SET_SZ(match_param, inner_headers.reserved_at_c4, 0x4)) { + mlx5hws_err(cd->ctx, "Unsupported inner parameters set\n"); + return -EINVAL; + } + + /* L2 Check ethertype */ + HWS_SET_HDR(fc, match_param, ETH_TYPE_I, + inner_headers.ethertype, + eth_l2_inner.l3_ethertype); + /* L2 Check SMAC 47_16 */ + HWS_SET_HDR(fc, match_param, ETH_SMAC_47_16_I, + inner_headers.smac_47_16, eth_l2_src_inner.smac_47_16); + /* L2 Check SMAC 15_0 */ + HWS_SET_HDR(fc, match_param, ETH_SMAC_15_0_I, + inner_headers.smac_15_0, eth_l2_src_inner.smac_15_0); + /* L2 Check DMAC 47_16 */ + HWS_SET_HDR(fc, match_param, ETH_DMAC_47_16_I, + inner_headers.dmac_47_16, eth_l2_inner.dmac_47_16); + /* L2 Check DMAC 15_0 */ + HWS_SET_HDR(fc, match_param, ETH_DMAC_15_0_I, + inner_headers.dmac_15_0, eth_l2_inner.dmac_15_0); + + /* L2 VLAN */ + HWS_SET_HDR(fc, match_param, VLAN_FIRST_PRIO_I, + inner_headers.first_prio, eth_l2_inner.first_priority); + HWS_SET_HDR(fc, match_param, VLAN_CFI_I, + inner_headers.first_cfi, eth_l2_inner.first_cfi); + HWS_SET_HDR(fc, match_param, VLAN_ID_I, + inner_headers.first_vid, eth_l2_inner.first_vlan_id); + + /* L2 CVLAN and SVLAN */ + if (HWS_GET_MATCH_PARAM(match_param, inner_headers.cvlan_tag) || + HWS_GET_MATCH_PARAM(match_param, inner_headers.svlan_tag)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VLAN_TYPE_I]; + HWS_CALC_HDR_DST(curr_fc, eth_l2_inner.first_vlan_qualifier); + curr_fc->tag_set = &hws_definer_inner_vlan_type_set; + curr_fc->tag_mask_set = &hws_definer_ones_set; + } + /* L3 Check IP header */ + HWS_SET_HDR(fc, match_param, IP_PROTOCOL_I, + inner_headers.ip_protocol, + eth_l3_inner.protocol_next_header); + HWS_SET_HDR(fc, match_param, IP_VERSION_I, + inner_headers.ip_version, + eth_l3_inner.ip_version); + HWS_SET_HDR(fc, match_param, IP_TTL_I, + inner_headers.ttl_hoplimit, + eth_l3_inner.time_to_live_hop_limit); + + /* L3 Check IPv4/IPv6 addresses */ + s_ipv6 = MLX5_ADDR_OF(fte_match_param, match_param, + inner_headers.src_ipv4_src_ipv6.ipv6_layout); + d_ipv6 = MLX5_ADDR_OF(fte_match_param, match_param, + inner_headers.dst_ipv4_dst_ipv6.ipv6_layout); + + /* Assume IPv6 is used if ipv6 bits are set */ + is_s_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2]; + is_d_ipv6 = d_ipv6[0] || d_ipv6[1] || d_ipv6[2]; + + if (is_s_ipv6) { + /* Handle IPv6 source address */ + HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_I, + inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_127_96, + ipv6_src_inner.ipv6_address_127_96); + HWS_SET_HDR(fc, match_param, IPV6_SRC_95_64_I, + inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_95_64, + ipv6_src_inner.ipv6_address_95_64); + HWS_SET_HDR(fc, match_param, IPV6_SRC_63_32_I, + inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_63_32, + ipv6_src_inner.ipv6_address_63_32); + HWS_SET_HDR(fc, match_param, IPV6_SRC_31_0_I, + inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv6_src_inner.ipv6_address_31_0); + } else { + /* Handle IPv4 source address */ + HWS_SET_HDR(fc, match_param, IPV4_SRC_I, + inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv4_src_dest_inner.source_address); + } + if (is_d_ipv6) { + /* Handle IPv6 destination address */ + HWS_SET_HDR(fc, match_param, IPV6_DST_127_96_I, + inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_127_96, + ipv6_dst_inner.ipv6_address_127_96); + HWS_SET_HDR(fc, match_param, IPV6_DST_95_64_I, + inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_95_64, + ipv6_dst_inner.ipv6_address_95_64); + HWS_SET_HDR(fc, match_param, IPV6_DST_63_32_I, + inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_63_32, + ipv6_dst_inner.ipv6_address_63_32); + HWS_SET_HDR(fc, match_param, IPV6_DST_31_0_I, + inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv6_dst_inner.ipv6_address_31_0); + } else { + /* Handle IPv4 destination address */ + HWS_SET_HDR(fc, match_param, IPV4_DST_I, + inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, + ipv4_src_dest_inner.destination_address); + } + + /* L4 Handle TCP/UDP */ + HWS_SET_HDR(fc, match_param, L4_SPORT_I, + inner_headers.tcp_sport, eth_l4_inner.source_port); + HWS_SET_HDR(fc, match_param, L4_DPORT_I, + inner_headers.tcp_dport, eth_l4_inner.destination_port); + HWS_SET_HDR(fc, match_param, L4_SPORT_I, + inner_headers.udp_sport, eth_l4_inner.source_port); + HWS_SET_HDR(fc, match_param, L4_DPORT_I, + inner_headers.udp_dport, eth_l4_inner.destination_port); + HWS_SET_HDR(fc, match_param, TCP_FLAGS_I, + inner_headers.tcp_flags, eth_l4_inner.tcp_flags); + + /* L3 Handle DSCP, ECN and IHL */ + HWS_SET_HDR(fc, match_param, IP_DSCP_I, + inner_headers.ip_dscp, eth_l3_inner.dscp); + HWS_SET_HDR(fc, match_param, IP_ECN_I, + inner_headers.ip_ecn, eth_l3_inner.ecn); + HWS_SET_HDR(fc, match_param, IPV4_IHL_I, + inner_headers.ipv4_ihl, eth_l3_inner.ihl); + + /* Set IP fragmented bit */ + if (HWS_IS_FLD_SET(match_param, inner_headers.frag)) { + if (HWS_IS_FLD_SET(match_param, misc_parameters.vxlan_vni)) { + HWS_SET_HDR(fc, match_param, IP_FRAG_I, + inner_headers.frag, eth_l2_inner.ip_fragmented); + } else { + smac_set = HWS_IS_FLD_SET(match_param, inner_headers.smac_15_0) || + HWS_IS_FLD_SET(match_param, inner_headers.smac_47_16); + dmac_set = HWS_IS_FLD_SET(match_param, inner_headers.dmac_15_0) || + HWS_IS_FLD_SET(match_param, inner_headers.dmac_47_16); + if (smac_set == dmac_set) { + HWS_SET_HDR(fc, match_param, IP_FRAG_I, + inner_headers.frag, eth_l4_inner.ip_fragmented); + } else { + HWS_SET_HDR(fc, match_param, IP_FRAG_I, + inner_headers.frag, eth_l2_src_inner.ip_fragmented); + } + } + } + + /* L3_type set */ + if (HWS_IS_FLD_SET(match_param, inner_headers.ip_version)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_I]; + HWS_CALC_HDR_DST(curr_fc, eth_l2_inner.l3_type); + curr_fc->tag_set = &hws_definer_l3_type_set; + curr_fc->tag_mask_set = &hws_definer_ones_set; + HWS_CALC_HDR_SRC(curr_fc, inner_headers.ip_version); + } + + return 0; +} + +static int +hws_definer_conv_misc(struct mlx5hws_definer_conv_data *cd, + u32 *match_param) +{ + struct mlx5hws_cmd_query_caps *caps = cd->ctx->caps; + struct mlx5hws_definer_fc *fc = cd->fc; + struct mlx5hws_definer_fc *curr_fc; + + if (HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_1, 0x1) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_64, 0xc) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_d8, 0x6) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_e0, 0xc) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_100, 0xc) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_120, 0xa) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_140, 0x8) || + HWS_IS_FLD_SET(match_param, misc_parameters.bth_dst_qp) || + HWS_IS_FLD_SET(match_param, misc_parameters.bth_opcode) || + HWS_IS_FLD_SET(match_param, misc_parameters.inner_esp_spi) || + HWS_IS_FLD_SET(match_param, misc_parameters.outer_esp_spi) || + HWS_IS_FLD_SET(match_param, misc_parameters.source_vhca_port) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_1a0, 0x60)) { + mlx5hws_err(cd->ctx, "Unsupported misc parameters set\n"); + return -EINVAL; + } + + /* Check GRE related fields */ + if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_c_present)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GRE_C]; + HWS_CALC_HDR(curr_fc, + misc_parameters.gre_c_present, + tunnel_header.tunnel_header_0); + curr_fc->bit_mask = __mlx5_mask(header_gre, gre_c_present); + curr_fc->bit_off = __mlx5_dw_bit_off(header_gre, gre_c_present); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_k_present)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GRE_K]; + HWS_CALC_HDR(curr_fc, + misc_parameters.gre_k_present, + tunnel_header.tunnel_header_0); + curr_fc->bit_mask = __mlx5_mask(header_gre, gre_k_present); + curr_fc->bit_off = __mlx5_dw_bit_off(header_gre, gre_k_present); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_s_present)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GRE_S]; + HWS_CALC_HDR(curr_fc, + misc_parameters.gre_s_present, + tunnel_header.tunnel_header_0); + curr_fc->bit_mask = __mlx5_mask(header_gre, gre_s_present); + curr_fc->bit_off = __mlx5_dw_bit_off(header_gre, gre_s_present); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_protocol)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GRE_PROTOCOL]; + HWS_CALC_HDR(curr_fc, + misc_parameters.gre_protocol, + tunnel_header.tunnel_header_0); + curr_fc->bit_mask = __mlx5_mask(header_gre, gre_protocol); + curr_fc->bit_off = __mlx5_dw_bit_off(header_gre, gre_protocol); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_key.key)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE | + MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE_OPT_KEY; + HWS_SET_HDR(fc, match_param, GRE_OPT_KEY, + misc_parameters.gre_key.key, tunnel_header.tunnel_header_2); + } + + /* Check GENEVE related fields */ + if (HWS_IS_FLD_SET(match_param, misc_parameters.geneve_vni)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GENEVE_VNI]; + HWS_CALC_HDR(curr_fc, + misc_parameters.geneve_vni, + tunnel_header.tunnel_header_1); + curr_fc->bit_mask = __mlx5_mask(header_geneve, vni); + curr_fc->bit_off = __mlx5_dw_bit_off(header_geneve, vni); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters.geneve_opt_len)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GENEVE_OPT_LEN]; + HWS_CALC_HDR(curr_fc, + misc_parameters.geneve_opt_len, + tunnel_header.tunnel_header_0); + curr_fc->bit_mask = __mlx5_mask(header_geneve, opt_len); + curr_fc->bit_off = __mlx5_dw_bit_off(header_geneve, opt_len); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters.geneve_protocol_type)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GENEVE_PROTO]; + HWS_CALC_HDR(curr_fc, + misc_parameters.geneve_protocol_type, + tunnel_header.tunnel_header_0); + curr_fc->bit_mask = __mlx5_mask(header_geneve, protocol_type); + curr_fc->bit_off = __mlx5_dw_bit_off(header_geneve, protocol_type); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters.geneve_oam)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GENEVE_OAM]; + HWS_CALC_HDR(curr_fc, + misc_parameters.geneve_oam, + tunnel_header.tunnel_header_0); + curr_fc->bit_mask = __mlx5_mask(header_geneve, o_flag); + curr_fc->bit_off = __mlx5_dw_bit_off(header_geneve, o_flag); + } + + HWS_SET_HDR(fc, match_param, SOURCE_QP, + misc_parameters.source_sqn, source_qp_gvmi.source_qp); + HWS_SET_HDR(fc, match_param, IPV6_FLOW_LABEL_O, + misc_parameters.outer_ipv6_flow_label, eth_l3_outer.flow_label); + HWS_SET_HDR(fc, match_param, IPV6_FLOW_LABEL_I, + misc_parameters.inner_ipv6_flow_label, eth_l3_inner.flow_label); + + /* L2 Second VLAN */ + HWS_SET_HDR(fc, match_param, VLAN_SECOND_PRIO_O, + misc_parameters.outer_second_prio, eth_l2_outer.second_priority); + HWS_SET_HDR(fc, match_param, VLAN_SECOND_PRIO_I, + misc_parameters.inner_second_prio, eth_l2_inner.second_priority); + HWS_SET_HDR(fc, match_param, VLAN_SECOND_CFI_O, + misc_parameters.outer_second_cfi, eth_l2_outer.second_cfi); + HWS_SET_HDR(fc, match_param, VLAN_SECOND_CFI_I, + misc_parameters.inner_second_cfi, eth_l2_inner.second_cfi); + HWS_SET_HDR(fc, match_param, VLAN_SECOND_ID_O, + misc_parameters.outer_second_vid, eth_l2_outer.second_vlan_id); + HWS_SET_HDR(fc, match_param, VLAN_SECOND_ID_I, + misc_parameters.inner_second_vid, eth_l2_inner.second_vlan_id); + + /* L2 Second CVLAN and SVLAN */ + if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.outer_second_cvlan_tag) || + HWS_GET_MATCH_PARAM(match_param, misc_parameters.outer_second_svlan_tag)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VLAN_SECOND_TYPE_O]; + HWS_CALC_HDR_DST(curr_fc, eth_l2_outer.second_vlan_qualifier); + curr_fc->tag_set = &hws_definer_outer_second_vlan_type_set; + curr_fc->tag_mask_set = &hws_definer_ones_set; + } + + if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.inner_second_cvlan_tag) || + HWS_GET_MATCH_PARAM(match_param, misc_parameters.inner_second_svlan_tag)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VLAN_SECOND_TYPE_I]; + HWS_CALC_HDR_DST(curr_fc, eth_l2_inner.second_vlan_qualifier); + curr_fc->tag_set = &hws_definer_inner_second_vlan_type_set; + curr_fc->tag_mask_set = &hws_definer_ones_set; + } + + /* VXLAN VNI */ + if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.vxlan_vni)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN; + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VXLAN_VNI]; + HWS_CALC_HDR(curr_fc, misc_parameters.vxlan_vni, tunnel_header.tunnel_header_1); + curr_fc->bit_mask = __mlx5_mask(header_vxlan, vni); + curr_fc->bit_off = __mlx5_dw_bit_off(header_vxlan, vni); + } + + /* Flex protocol steering ok bits */ + if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.geneve_tlv_option_0_exist)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; + + if (!caps->flex_parser_ok_bits_supp) { + mlx5hws_err(cd->ctx, "Unsupported flex_parser_ok_bits_supp capability\n"); + return -EOPNOTSUPP; + } + + curr_fc = hws_definer_flex_parser_steering_ok_bits_handler( + cd, caps->flex_parser_id_geneve_tlv_option_0); + if (!curr_fc) + return -EINVAL; + + HWS_CALC_HDR_SRC(fc, misc_parameters.geneve_tlv_option_0_exist); + } + + if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.source_port)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_SOURCE_GVMI]; + HWS_CALC_HDR_DST(curr_fc, source_qp_gvmi.source_gvmi); + curr_fc->tag_mask_set = &hws_definer_ones_set; + curr_fc->tag_set = HWS_IS_FLD_SET(match_param, + misc_parameters.source_eswitch_owner_vhca_id) ? + &hws_definer_set_source_gvmi_vhca_id : + &hws_definer_set_source_gvmi; + } else { + if (HWS_IS_FLD_SET(match_param, misc_parameters.source_eswitch_owner_vhca_id)) { + mlx5hws_err(cd->ctx, + "Unsupported source_eswitch_owner_vhca_id field usage\n"); + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int +hws_definer_conv_misc2(struct mlx5hws_definer_conv_data *cd, + u32 *match_param) +{ + struct mlx5hws_cmd_query_caps *caps = cd->ctx->caps; + struct mlx5hws_definer_fc *fc = cd->fc; + struct mlx5hws_definer_fc *curr_fc; + + if (HWS_IS_FLD_SET_SZ(match_param, misc_parameters_2.reserved_at_1a0, 0x8) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters_2.reserved_at_1b8, 0x8) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters_2.reserved_at_1c0, 0x40) || + HWS_IS_FLD_SET(match_param, misc_parameters_2.macsec_syndrome) || + HWS_IS_FLD_SET(match_param, misc_parameters_2.ipsec_syndrome)) { + mlx5hws_err(cd->ctx, "Unsupported misc2 parameters set\n"); + return -EINVAL; + } + + HWS_SET_HDR(fc, match_param, MPLS0_O, + misc_parameters_2.outer_first_mpls, mpls_outer.mpls0_label); + HWS_SET_HDR(fc, match_param, MPLS0_I, + misc_parameters_2.inner_first_mpls, mpls_inner.mpls0_label); + HWS_SET_HDR(fc, match_param, REG_0, + misc_parameters_2.metadata_reg_c_0, registers.register_c_0); + HWS_SET_HDR(fc, match_param, REG_1, + misc_parameters_2.metadata_reg_c_1, registers.register_c_1); + HWS_SET_HDR(fc, match_param, REG_2, + misc_parameters_2.metadata_reg_c_2, registers.register_c_2); + HWS_SET_HDR(fc, match_param, REG_3, + misc_parameters_2.metadata_reg_c_3, registers.register_c_3); + HWS_SET_HDR(fc, match_param, REG_4, + misc_parameters_2.metadata_reg_c_4, registers.register_c_4); + HWS_SET_HDR(fc, match_param, REG_5, + misc_parameters_2.metadata_reg_c_5, registers.register_c_5); + HWS_SET_HDR(fc, match_param, REG_6, + misc_parameters_2.metadata_reg_c_6, registers.register_c_6); + HWS_SET_HDR(fc, match_param, REG_7, + misc_parameters_2.metadata_reg_c_7, registers.register_c_7); + HWS_SET_HDR(fc, match_param, REG_A, + misc_parameters_2.metadata_reg_a, metadata.general_purpose); + + if (HWS_IS_FLD_SET(match_param, misc_parameters_2.outer_first_mpls_over_gre)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_GRE; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported misc2 first mpls over gre parameters set\n"); + return -EOPNOTSUPP; + } + + curr_fc = hws_definer_flex_parser_handler(cd, caps->flex_parser_id_mpls_over_gre); + if (!curr_fc) + return -EINVAL; + + HWS_CALC_HDR_SRC(fc, misc_parameters_2.outer_first_mpls_over_gre); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_2.outer_first_mpls_over_udp)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_UDP; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported misc2 first mpls over udp parameters set\n"); + return -EOPNOTSUPP; + } + + curr_fc = hws_definer_flex_parser_handler(cd, caps->flex_parser_id_mpls_over_udp); + if (!curr_fc) + return -EINVAL; + + HWS_CALC_HDR_SRC(fc, misc_parameters_2.outer_first_mpls_over_udp); + } + + return 0; +} + +static int +hws_definer_conv_misc3(struct mlx5hws_definer_conv_data *cd, u32 *match_param) +{ + struct mlx5hws_cmd_query_caps *caps = cd->ctx->caps; + struct mlx5hws_definer_fc *fc = cd->fc; + struct mlx5hws_definer_fc *curr_fc; + bool vxlan_gpe_flex_parser_enabled; + + /* Check reserved and unsupported fields */ + if (HWS_IS_FLD_SET_SZ(match_param, misc_parameters_3.reserved_at_80, 0x8) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters_3.reserved_at_b0, 0x10) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters_3.reserved_at_170, 0x10) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters_3.reserved_at_1e0, 0x20)) { + mlx5hws_err(cd->ctx, "Unsupported misc3 parameters set\n"); + return -EINVAL; + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.inner_tcp_seq_num) || + HWS_IS_FLD_SET(match_param, misc_parameters_3.inner_tcp_ack_num)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TCP_I; + HWS_SET_HDR(fc, match_param, TCP_SEQ_NUM, + misc_parameters_3.inner_tcp_seq_num, tcp_icmp.tcp_seq); + HWS_SET_HDR(fc, match_param, TCP_ACK_NUM, + misc_parameters_3.inner_tcp_ack_num, tcp_icmp.tcp_ack); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_tcp_seq_num) || + HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_tcp_ack_num)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TCP_O; + HWS_SET_HDR(fc, match_param, TCP_SEQ_NUM, + misc_parameters_3.outer_tcp_seq_num, tcp_icmp.tcp_seq); + HWS_SET_HDR(fc, match_param, TCP_ACK_NUM, + misc_parameters_3.outer_tcp_ack_num, tcp_icmp.tcp_ack); + } + + vxlan_gpe_flex_parser_enabled = caps->flex_protocols & MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED; + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_vxlan_gpe_vni)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE; + + if (!vxlan_gpe_flex_parser_enabled) { + mlx5hws_err(cd->ctx, "Unsupported VXLAN GPE flex parser\n"); + return -EOPNOTSUPP; + } + + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VXLAN_GPE_VNI]; + HWS_CALC_HDR(curr_fc, misc_parameters_3.outer_vxlan_gpe_vni, + tunnel_header.tunnel_header_1); + curr_fc->bit_mask = __mlx5_mask(header_vxlan_gpe, vni); + curr_fc->bit_off = __mlx5_dw_bit_off(header_vxlan_gpe, vni); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_vxlan_gpe_next_protocol)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE; + + if (!vxlan_gpe_flex_parser_enabled) { + mlx5hws_err(cd->ctx, "Unsupported VXLAN GPE flex parser\n"); + return -EOPNOTSUPP; + } + + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VXLAN_GPE_PROTO]; + HWS_CALC_HDR(curr_fc, misc_parameters_3.outer_vxlan_gpe_next_protocol, + tunnel_header.tunnel_header_0); + curr_fc->byte_off += MLX5_BYTE_OFF(header_vxlan_gpe, protocol); + curr_fc->bit_mask = __mlx5_mask(header_vxlan_gpe, protocol); + curr_fc->bit_off = __mlx5_dw_bit_off(header_vxlan_gpe, protocol); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_vxlan_gpe_flags)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE; + + if (!vxlan_gpe_flex_parser_enabled) { + mlx5hws_err(cd->ctx, "Unsupported VXLAN GPE flex parser\n"); + return -EOPNOTSUPP; + } + + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VXLAN_GPE_FLAGS]; + HWS_CALC_HDR(curr_fc, misc_parameters_3.outer_vxlan_gpe_flags, + tunnel_header.tunnel_header_0); + curr_fc->bit_mask = __mlx5_mask(header_vxlan_gpe, flags); + curr_fc->bit_off = __mlx5_dw_bit_off(header_vxlan_gpe, flags); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_header_data) || + HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_type) || + HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_code)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_ICMPV4; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V4_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported ICMPv4 flex parser\n"); + return -EOPNOTSUPP; + } + + HWS_SET_HDR(fc, match_param, ICMP_DW3, + misc_parameters_3.icmp_header_data, tcp_icmp.icmp_dw3); + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_type) || + HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_code)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_ICMP_DW1]; + HWS_CALC_HDR_DST(curr_fc, tcp_icmp.icmp_dw1); + curr_fc->tag_set = &hws_definer_icmp_dw1_set; + } + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_header_data) || + HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_type) || + HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_code)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_ICMPV6; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V6_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported ICMPv6 parser\n"); + return -EOPNOTSUPP; + } + + HWS_SET_HDR(fc, match_param, ICMP_DW3, + misc_parameters_3.icmpv6_header_data, tcp_icmp.icmp_dw3); + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_type) || + HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_code)) { + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_ICMP_DW1]; + HWS_CALC_HDR_DST(curr_fc, tcp_icmp.icmp_dw1); + curr_fc->tag_set = &hws_definer_icmpv6_dw1_set; + } + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.geneve_tlv_option_0_data)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; + + curr_fc = + hws_definer_flex_parser_handler(cd, + caps->flex_parser_id_geneve_tlv_option_0); + if (!curr_fc) + return -EINVAL; + + HWS_CALC_HDR_SRC(fc, misc_parameters_3.geneve_tlv_option_0_data); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_teid)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_TEID_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported GTPU TEID flex parser\n"); + return -EOPNOTSUPP; + } + + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_GTP_TEID]; + fc->tag_set = &hws_definer_generic_set; + fc->bit_mask = __mlx5_mask(header_gtp, teid); + fc->byte_off = caps->format_select_gtpu_dw_1 * DW_SIZE; + HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_teid); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_msg_type)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported GTPU flex parser\n"); + return -EOPNOTSUPP; + } + + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_GTP_MSG_TYPE]; + fc->tag_set = &hws_definer_generic_set; + fc->bit_mask = __mlx5_mask(header_gtp, msg_type); + fc->bit_off = __mlx5_dw_bit_off(header_gtp, msg_type); + fc->byte_off = caps->format_select_gtpu_dw_0 * DW_SIZE; + HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_msg_type); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_msg_flags)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported GTPU flex parser\n"); + return -EOPNOTSUPP; + } + + fc = &cd->fc[MLX5HWS_DEFINER_FNAME_GTP_MSG_TYPE]; + fc->tag_set = &hws_definer_generic_set; + fc->bit_mask = __mlx5_mask(header_gtp, msg_flags); + fc->bit_off = __mlx5_dw_bit_off(header_gtp, msg_flags); + fc->byte_off = caps->format_select_gtpu_dw_0 * DW_SIZE; + HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_msg_flags); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_dw_2)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_2_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported GTPU DW2 flex parser\n"); + return -EOPNOTSUPP; + } + + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GTPU_DW2]; + curr_fc->tag_set = &hws_definer_generic_set; + curr_fc->bit_mask = -1; + curr_fc->byte_off = caps->format_select_gtpu_dw_2 * DW_SIZE; + HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_dw_2); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_first_ext_dw_0)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_FIRST_EXT_DW_0_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported GTPU first EXT DW0 flex parser\n"); + return -EOPNOTSUPP; + } + + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GTPU_FIRST_EXT_DW0]; + curr_fc->tag_set = &hws_definer_generic_set; + curr_fc->bit_mask = -1; + curr_fc->byte_off = caps->format_select_gtpu_ext_dw_0 * DW_SIZE; + HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_first_ext_dw_0); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_dw_0)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; + + if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_0_ENABLED)) { + mlx5hws_err(cd->ctx, "Unsupported GTPU DW0 flex parser\n"); + return -EOPNOTSUPP; + } + + curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GTPU_DW0]; + curr_fc->tag_set = &hws_definer_generic_set; + curr_fc->bit_mask = -1; + curr_fc->byte_off = caps->format_select_gtpu_dw_0 * DW_SIZE; + HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_dw_0); + } + + return 0; +} + +static int +hws_definer_conv_misc4(struct mlx5hws_definer_conv_data *cd, + u32 *match_param) +{ + bool parser_is_used[HWS_NUM_OF_FLEX_PARSERS] = {}; + struct mlx5hws_definer_fc *fc; + u32 id, value; + + if (HWS_IS_FLD_SET_SZ(match_param, misc_parameters_4.reserved_at_100, 0x100)) { + mlx5hws_err(cd->ctx, "Unsupported misc4 parameters set\n"); + return -EINVAL; + } + + id = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_id_0); + value = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_value_0); + fc = hws_definer_misc4_fields_handler(cd, parser_is_used, id, value); + if (!fc) + return -EINVAL; + + HWS_CALC_HDR_SRC(fc, misc_parameters_4.prog_sample_field_value_0); + + id = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_id_1); + value = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_value_1); + fc = hws_definer_misc4_fields_handler(cd, parser_is_used, id, value); + if (!fc) + return -EINVAL; + + HWS_CALC_HDR_SRC(fc, misc_parameters_4.prog_sample_field_value_1); + + id = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_id_2); + value = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_value_2); + fc = hws_definer_misc4_fields_handler(cd, parser_is_used, id, value); + if (!fc) + return -EINVAL; + + HWS_CALC_HDR_SRC(fc, misc_parameters_4.prog_sample_field_value_2); + + id = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_id_3); + value = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_value_3); + fc = hws_definer_misc4_fields_handler(cd, parser_is_used, id, value); + if (!fc) + return -EINVAL; + + HWS_CALC_HDR_SRC(fc, misc_parameters_4.prog_sample_field_value_3); + + return 0; +} + +static int +hws_definer_conv_misc5(struct mlx5hws_definer_conv_data *cd, + u32 *match_param) +{ + struct mlx5hws_definer_fc *fc = cd->fc; + + if (HWS_IS_FLD_SET(match_param, misc_parameters_5.macsec_tag_0) || + HWS_IS_FLD_SET(match_param, misc_parameters_5.macsec_tag_1) || + HWS_IS_FLD_SET(match_param, misc_parameters_5.macsec_tag_2) || + HWS_IS_FLD_SET(match_param, misc_parameters_5.macsec_tag_3) || + HWS_IS_FLD_SET_SZ(match_param, misc_parameters_5.reserved_at_100, 0x100)) { + mlx5hws_err(cd->ctx, "Unsupported misc5 parameters set\n"); + return -EINVAL; + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_5.tunnel_header_0)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_0_1; + HWS_SET_HDR(fc, match_param, TNL_HDR_0, + misc_parameters_5.tunnel_header_0, tunnel_header.tunnel_header_0); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_5.tunnel_header_1)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_0_1; + HWS_SET_HDR(fc, match_param, TNL_HDR_1, + misc_parameters_5.tunnel_header_1, tunnel_header.tunnel_header_1); + } + + if (HWS_IS_FLD_SET(match_param, misc_parameters_5.tunnel_header_2)) { + cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_2; + HWS_SET_HDR(fc, match_param, TNL_HDR_2, + misc_parameters_5.tunnel_header_2, tunnel_header.tunnel_header_2); + } + + HWS_SET_HDR(fc, match_param, TNL_HDR_3, + misc_parameters_5.tunnel_header_3, tunnel_header.tunnel_header_3); + + return 0; +} + +static int hws_definer_get_fc_size(struct mlx5hws_definer_fc *fc) +{ + u32 fc_sz = 0; + int i; + + /* For empty matcher, ZERO_SIZE_PTR is returned */ + if (fc == ZERO_SIZE_PTR) + return 0; + + for (i = 0; i < MLX5HWS_DEFINER_FNAME_MAX; i++) + if (fc[i].tag_set) + fc_sz++; + return fc_sz; +} + +static struct mlx5hws_definer_fc * +hws_definer_alloc_compressed_fc(struct mlx5hws_definer_fc *fc) +{ + struct mlx5hws_definer_fc *compressed_fc = NULL; + u32 definer_size = hws_definer_get_fc_size(fc); + u32 fc_sz = 0; + int i; + + compressed_fc = kcalloc(definer_size, sizeof(*compressed_fc), GFP_KERNEL); + if (!compressed_fc) + return NULL; + + /* For empty matcher, ZERO_SIZE_PTR is returned */ + if (!definer_size) + return compressed_fc; + + for (i = 0, fc_sz = 0; i < MLX5HWS_DEFINER_FNAME_MAX; i++) { + if (!fc[i].tag_set) + continue; + + fc[i].fname = i; + memcpy(&compressed_fc[fc_sz++], &fc[i], sizeof(*compressed_fc)); + } + + return compressed_fc; +} + +static void +hws_definer_set_hl(u8 *hl, struct mlx5hws_definer_fc *fc) +{ + int i; + + /* nothing to do for empty matcher */ + if (fc == ZERO_SIZE_PTR) + return; + + for (i = 0; i < MLX5HWS_DEFINER_FNAME_MAX; i++) { + if (!fc[i].tag_set) + continue; + + HWS_SET32(hl, -1, fc[i].byte_off, fc[i].bit_off, fc[i].bit_mask); + } +} + +static struct mlx5hws_definer_fc * +hws_definer_alloc_fc(struct mlx5hws_context *ctx, + size_t len) +{ + struct mlx5hws_definer_fc *fc; + int i; + + fc = kcalloc(len, sizeof(*fc), GFP_KERNEL); + if (!fc) + return NULL; + + for (i = 0; i < len; i++) + fc[i].ctx = ctx; + + return fc; +} + +static int +hws_definer_conv_match_params_to_hl(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt, + u8 *hl) +{ + struct mlx5hws_definer_conv_data cd = {0}; + struct mlx5hws_definer_fc *fc; + int ret; + + fc = hws_definer_alloc_fc(ctx, MLX5HWS_DEFINER_FNAME_MAX); + if (!fc) + return -ENOMEM; + + cd.fc = fc; + cd.ctx = ctx; + + if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC6) { + mlx5hws_err(ctx, "Unsupported match_criteria_enable provided\n"); + ret = -EOPNOTSUPP; + goto err_free_fc; + } + + if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_OUTER) { + ret = hws_definer_conv_outer(&cd, mt->match_param); + if (ret) + goto err_free_fc; + } + + if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_INNER) { + ret = hws_definer_conv_inner(&cd, mt->match_param); + if (ret) + goto err_free_fc; + } + + if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC) { + ret = hws_definer_conv_misc(&cd, mt->match_param); + if (ret) + goto err_free_fc; + } + + if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC2) { + ret = hws_definer_conv_misc2(&cd, mt->match_param); + if (ret) + goto err_free_fc; + } + + if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC3) { + ret = hws_definer_conv_misc3(&cd, mt->match_param); + if (ret) + goto err_free_fc; + } + + if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC4) { + ret = hws_definer_conv_misc4(&cd, mt->match_param); + if (ret) + goto err_free_fc; + } + + if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC5) { + ret = hws_definer_conv_misc5(&cd, mt->match_param); + if (ret) + goto err_free_fc; + } + + /* Check there is no conflicted fields set together */ + ret = hws_definer_check_match_flags(&cd); + if (ret) + goto err_free_fc; + + /* Allocate fc array on mt */ + mt->fc = hws_definer_alloc_compressed_fc(fc); + if (!mt->fc) { + mlx5hws_err(ctx, + "Convert match params: failed to set field copy to match template\n"); + ret = -ENOMEM; + goto err_free_fc; + } + mt->fc_sz = hws_definer_get_fc_size(fc); + + /* Fill in headers layout */ + hws_definer_set_hl(hl, fc); + + kfree(fc); + return 0; + +err_free_fc: + kfree(fc); + return ret; +} + +struct mlx5hws_definer_fc * +mlx5hws_definer_conv_match_params_to_compressed_fc(struct mlx5hws_context *ctx, + u8 match_criteria_enable, + u32 *match_param, + int *fc_sz) +{ + struct mlx5hws_definer_fc *compressed_fc = NULL; + struct mlx5hws_definer_conv_data cd = {0}; + struct mlx5hws_definer_fc *fc; + int ret; + + fc = hws_definer_alloc_fc(ctx, MLX5HWS_DEFINER_FNAME_MAX); + if (!fc) + return NULL; + + cd.fc = fc; + cd.ctx = ctx; + + if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_OUTER) { + ret = hws_definer_conv_outer(&cd, match_param); + if (ret) + goto err_free_fc; + } + + if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_INNER) { + ret = hws_definer_conv_inner(&cd, match_param); + if (ret) + goto err_free_fc; + } + + if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC) { + ret = hws_definer_conv_misc(&cd, match_param); + if (ret) + goto err_free_fc; + } + + if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC2) { + ret = hws_definer_conv_misc2(&cd, match_param); + if (ret) + goto err_free_fc; + } + + if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC3) { + ret = hws_definer_conv_misc3(&cd, match_param); + if (ret) + goto err_free_fc; + } + + if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC4) { + ret = hws_definer_conv_misc4(&cd, match_param); + if (ret) + goto err_free_fc; + } + + if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC5) { + ret = hws_definer_conv_misc5(&cd, match_param); + if (ret) + goto err_free_fc; + } + + /* Allocate fc array on mt */ + compressed_fc = hws_definer_alloc_compressed_fc(fc); + if (!compressed_fc) { + mlx5hws_err(ctx, + "Convert to compressed fc: failed to set field copy to match template\n"); + goto err_free_fc; + } + *fc_sz = hws_definer_get_fc_size(fc); + +err_free_fc: + kfree(fc); + return compressed_fc; +} + +static int +hws_definer_find_byte_in_tag(struct mlx5hws_definer *definer, + u32 hl_byte_off, + u32 *tag_byte_off) +{ + int i, dw_to_scan; + u8 byte_offset; + + /* Avoid accessing unused DW selectors */ + dw_to_scan = mlx5hws_definer_is_jumbo(definer) ? + DW_SELECTORS : DW_SELECTORS_MATCH; + + /* Add offset since each DW covers multiple BYTEs */ + byte_offset = hl_byte_off % DW_SIZE; + for (i = 0; i < dw_to_scan; i++) { + if (definer->dw_selector[i] == hl_byte_off / DW_SIZE) { + *tag_byte_off = byte_offset + DW_SIZE * (DW_SELECTORS - i - 1); + return 0; + } + } + + /* Add offset to skip DWs in definer */ + byte_offset = DW_SIZE * DW_SELECTORS; + /* Iterate in reverse since the code uses bytes from 7 -> 0 */ + for (i = BYTE_SELECTORS; i-- > 0 ;) { + if (definer->byte_selector[i] == hl_byte_off) { + *tag_byte_off = byte_offset + (BYTE_SELECTORS - i - 1); + return 0; + } + } + + return -EINVAL; +} + +static int +hws_definer_fc_bind(struct mlx5hws_definer *definer, + struct mlx5hws_definer_fc *fc, + u32 fc_sz) +{ + u32 tag_offset = 0; + int ret, byte_diff; + u32 i; + + for (i = 0; i < fc_sz; i++) { + /* Map header layout byte offset to byte offset in tag */ + ret = hws_definer_find_byte_in_tag(definer, fc->byte_off, &tag_offset); + if (ret) + return ret; + + /* Move setter based on the location in the definer */ + byte_diff = fc->byte_off % DW_SIZE - tag_offset % DW_SIZE; + fc->bit_off = fc->bit_off + byte_diff * BITS_IN_BYTE; + + /* Update offset in headers layout to offset in tag */ + fc->byte_off = tag_offset; + fc++; + } + + return 0; +} + +static bool +hws_definer_best_hl_fit_recu(struct mlx5hws_definer_sel_ctrl *ctrl, + u32 cur_dw, + u32 *data) +{ + u8 bytes_set; + int byte_idx; + bool ret; + int i; + + /* Reached end, nothing left to do */ + if (cur_dw == MLX5_ST_SZ_DW(definer_hl)) + return true; + + /* No data set, can skip to next DW */ + while (!*data) { + cur_dw++; + data++; + + /* Reached end, nothing left to do */ + if (cur_dw == MLX5_ST_SZ_DW(definer_hl)) + return true; + } + + /* Used all DW selectors and Byte selectors, no possible solution */ + if (ctrl->allowed_full_dw == ctrl->used_full_dw && + ctrl->allowed_lim_dw == ctrl->used_lim_dw && + ctrl->allowed_bytes == ctrl->used_bytes) + return false; + + /* Try to use limited DW selectors */ + if (ctrl->allowed_lim_dw > ctrl->used_lim_dw && cur_dw < 64) { + ctrl->lim_dw_selector[ctrl->used_lim_dw++] = cur_dw; + + ret = hws_definer_best_hl_fit_recu(ctrl, cur_dw + 1, data + 1); + if (ret) + return ret; + + ctrl->lim_dw_selector[--ctrl->used_lim_dw] = 0; + } + + /* Try to use DW selectors */ + if (ctrl->allowed_full_dw > ctrl->used_full_dw) { + ctrl->full_dw_selector[ctrl->used_full_dw++] = cur_dw; + + ret = hws_definer_best_hl_fit_recu(ctrl, cur_dw + 1, data + 1); + if (ret) + return ret; + + ctrl->full_dw_selector[--ctrl->used_full_dw] = 0; + } + + /* No byte selector for offset bigger than 255 */ + if (cur_dw * DW_SIZE > 255) + return false; + + bytes_set = !!(0x000000ff & *data) + + !!(0x0000ff00 & *data) + + !!(0x00ff0000 & *data) + + !!(0xff000000 & *data); + + /* Check if there are enough byte selectors left */ + if (bytes_set + ctrl->used_bytes > ctrl->allowed_bytes) + return false; + + /* Try to use Byte selectors */ + for (i = 0; i < DW_SIZE; i++) + if ((0xff000000 >> (i * BITS_IN_BYTE)) & be32_to_cpu((__force __be32)*data)) { + /* Use byte selectors high to low */ + byte_idx = ctrl->allowed_bytes - ctrl->used_bytes - 1; + ctrl->byte_selector[byte_idx] = cur_dw * DW_SIZE + i; + ctrl->used_bytes++; + } + + ret = hws_definer_best_hl_fit_recu(ctrl, cur_dw + 1, data + 1); + if (ret) + return ret; + + for (i = 0; i < DW_SIZE; i++) + if ((0xff << (i * BITS_IN_BYTE)) & be32_to_cpu((__force __be32)*data)) { + ctrl->used_bytes--; + byte_idx = ctrl->allowed_bytes - ctrl->used_bytes - 1; + ctrl->byte_selector[byte_idx] = 0; + } + + return false; +} + +static void +hws_definer_copy_sel_ctrl(struct mlx5hws_definer_sel_ctrl *ctrl, + struct mlx5hws_definer *definer) +{ + memcpy(definer->byte_selector, ctrl->byte_selector, ctrl->allowed_bytes); + memcpy(definer->dw_selector, ctrl->full_dw_selector, ctrl->allowed_full_dw); + memcpy(definer->dw_selector + ctrl->allowed_full_dw, + ctrl->lim_dw_selector, ctrl->allowed_lim_dw); +} + +static int +hws_definer_find_best_match_fit(struct mlx5hws_context *ctx, + struct mlx5hws_definer *definer, + u8 *hl) +{ + struct mlx5hws_definer_sel_ctrl ctrl = {0}; + bool found; + + /* Try to create a match definer */ + ctrl.allowed_full_dw = DW_SELECTORS_MATCH; + ctrl.allowed_lim_dw = 0; + ctrl.allowed_bytes = BYTE_SELECTORS; + + found = hws_definer_best_hl_fit_recu(&ctrl, 0, (u32 *)hl); + if (found) { + hws_definer_copy_sel_ctrl(&ctrl, definer); + definer->type = MLX5HWS_DEFINER_TYPE_MATCH; + return 0; + } + + /* Try to create a full/limited jumbo definer */ + ctrl.allowed_full_dw = ctx->caps->full_dw_jumbo_support ? DW_SELECTORS : + DW_SELECTORS_MATCH; + ctrl.allowed_lim_dw = ctx->caps->full_dw_jumbo_support ? 0 : + DW_SELECTORS_LIMITED; + ctrl.allowed_bytes = BYTE_SELECTORS; + + found = hws_definer_best_hl_fit_recu(&ctrl, 0, (u32 *)hl); + if (found) { + hws_definer_copy_sel_ctrl(&ctrl, definer); + definer->type = MLX5HWS_DEFINER_TYPE_JUMBO; + return 0; + } + + return -E2BIG; +} + +static void +hws_definer_create_tag_mask(u32 *match_param, + struct mlx5hws_definer_fc *fc, + u32 fc_sz, + u8 *tag) +{ + u32 i; + + for (i = 0; i < fc_sz; i++) { + if (fc->tag_mask_set) + fc->tag_mask_set(fc, match_param, tag); + else + fc->tag_set(fc, match_param, tag); + fc++; + } +} + +void mlx5hws_definer_create_tag(u32 *match_param, + struct mlx5hws_definer_fc *fc, + u32 fc_sz, + u8 *tag) +{ + u32 i; + + for (i = 0; i < fc_sz; i++) { + fc->tag_set(fc, match_param, tag); + fc++; + } +} + +int mlx5hws_definer_get_id(struct mlx5hws_definer *definer) +{ + return definer->obj_id; +} + +int mlx5hws_definer_compare(struct mlx5hws_definer *definer_a, + struct mlx5hws_definer *definer_b) +{ + int i; + + /* Future: Optimize by comparing selectors with valid mask only */ + for (i = 0; i < BYTE_SELECTORS; i++) + if (definer_a->byte_selector[i] != definer_b->byte_selector[i]) + return 1; + + for (i = 0; i < DW_SELECTORS; i++) + if (definer_a->dw_selector[i] != definer_b->dw_selector[i]) + return 1; + + for (i = 0; i < MLX5HWS_JUMBO_TAG_SZ; i++) + if (definer_a->mask.jumbo[i] != definer_b->mask.jumbo[i]) + return 1; + + return 0; +} + +int +mlx5hws_definer_calc_layout(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt, + struct mlx5hws_definer *match_definer) +{ + u8 *match_hl; + int ret; + + /* Union header-layout (hl) is used for creating a single definer + * field layout used with different bitmasks for hash and match. + */ + match_hl = kzalloc(MLX5_ST_SZ_BYTES(definer_hl), GFP_KERNEL); + if (!match_hl) + return -ENOMEM; + + /* Convert all mt items to header layout (hl) + * and allocate the match and range field copy array (fc & fcr). + */ + ret = hws_definer_conv_match_params_to_hl(ctx, mt, match_hl); + if (ret) { + mlx5hws_err(ctx, "Failed to convert items to header layout\n"); + goto free_match_hl; + } + + /* Find the match definer layout for header layout match union */ + ret = hws_definer_find_best_match_fit(ctx, match_definer, match_hl); + if (ret) { + if (ret == -E2BIG) + mlx5hws_dbg(ctx, + "Failed to create match definer from header layout - E2BIG\n"); + else + mlx5hws_err(ctx, + "Failed to create match definer from header layout (%d)\n", + ret); + goto free_fc; + } + + kfree(match_hl); + return 0; + +free_fc: + kfree(mt->fc); +free_match_hl: + kfree(match_hl); + return ret; +} + +int mlx5hws_definer_init_cache(struct mlx5hws_definer_cache **cache) +{ + struct mlx5hws_definer_cache *new_cache; + + new_cache = kzalloc(sizeof(*new_cache), GFP_KERNEL); + if (!new_cache) + return -ENOMEM; + + INIT_LIST_HEAD(&new_cache->list_head); + *cache = new_cache; + + return 0; +} + +void mlx5hws_definer_uninit_cache(struct mlx5hws_definer_cache *cache) +{ + kfree(cache); +} + +int mlx5hws_definer_get_obj(struct mlx5hws_context *ctx, + struct mlx5hws_definer *definer) +{ + struct mlx5hws_definer_cache *cache = ctx->definer_cache; + struct mlx5hws_cmd_definer_create_attr def_attr = {0}; + struct mlx5hws_definer_cache_item *cached_definer; + u32 obj_id; + int ret; + + /* Search definer cache for requested definer */ + list_for_each_entry(cached_definer, &cache->list_head, list_node) { + if (mlx5hws_definer_compare(&cached_definer->definer, definer)) + continue; + + /* Reuse definer and set LRU (move to be first in the list) */ + list_del_init(&cached_definer->list_node); + list_add(&cached_definer->list_node, &cache->list_head); + cached_definer->refcount++; + return cached_definer->definer.obj_id; + } + + /* Allocate and create definer based on the bitmask tag */ + def_attr.match_mask = definer->mask.jumbo; + def_attr.dw_selector = definer->dw_selector; + def_attr.byte_selector = definer->byte_selector; + + ret = mlx5hws_cmd_definer_create(ctx->mdev, &def_attr, &obj_id); + if (ret) + return -1; + + cached_definer = kzalloc(sizeof(*cached_definer), GFP_KERNEL); + if (!cached_definer) + goto free_definer_obj; + + memcpy(&cached_definer->definer, definer, sizeof(*definer)); + cached_definer->definer.obj_id = obj_id; + cached_definer->refcount = 1; + list_add(&cached_definer->list_node, &cache->list_head); + + return obj_id; + +free_definer_obj: + mlx5hws_cmd_definer_destroy(ctx->mdev, obj_id); + return -1; +} + +static void +hws_definer_put_obj(struct mlx5hws_context *ctx, u32 obj_id) +{ + struct mlx5hws_definer_cache_item *cached_definer; + + list_for_each_entry(cached_definer, &ctx->definer_cache->list_head, list_node) { + if (cached_definer->definer.obj_id != obj_id) + continue; + + /* Object found */ + if (--cached_definer->refcount) + return; + + list_del_init(&cached_definer->list_node); + mlx5hws_cmd_definer_destroy(ctx->mdev, cached_definer->definer.obj_id); + kfree(cached_definer); + return; + } + + /* Programming error, object must be part of cache */ + pr_warn("HWS: failed putting definer object\n"); +} + +static struct mlx5hws_definer * +hws_definer_alloc(struct mlx5hws_context *ctx, + struct mlx5hws_definer_fc *fc, + int fc_sz, + u32 *match_param, + struct mlx5hws_definer *layout, + bool bind_fc) +{ + struct mlx5hws_definer *definer; + int ret; + + definer = kmemdup(layout, sizeof(*definer), GFP_KERNEL); + if (!definer) + return NULL; + + /* Align field copy array based on given layout */ + if (bind_fc) { + ret = hws_definer_fc_bind(definer, fc, fc_sz); + if (ret) { + mlx5hws_err(ctx, "Failed to bind field copy to definer\n"); + goto free_definer; + } + } + + /* Create the tag mask used for definer creation */ + hws_definer_create_tag_mask(match_param, fc, fc_sz, definer->mask.jumbo); + + ret = mlx5hws_definer_get_obj(ctx, definer); + if (ret < 0) + goto free_definer; + + definer->obj_id = ret; + return definer; + +free_definer: + kfree(definer); + return NULL; +} + +void mlx5hws_definer_free(struct mlx5hws_context *ctx, + struct mlx5hws_definer *definer) +{ + hws_definer_put_obj(ctx, definer->obj_id); + kfree(definer); +} + +static int +hws_definer_mt_match_init(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt, + struct mlx5hws_definer *match_layout) +{ + /* Create mandatory match definer */ + mt->definer = hws_definer_alloc(ctx, + mt->fc, + mt->fc_sz, + mt->match_param, + match_layout, + true); + if (!mt->definer) { + mlx5hws_err(ctx, "Failed to create match definer\n"); + return -EINVAL; + } + + return 0; +} + +static void +hws_definer_mt_match_uninit(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt) +{ + mlx5hws_definer_free(ctx, mt->definer); +} + +int mlx5hws_definer_mt_init(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt) +{ + struct mlx5hws_definer match_layout = {0}; + int ret; + + ret = mlx5hws_definer_calc_layout(ctx, mt, &match_layout); + if (ret) { + mlx5hws_err(ctx, "Failed to calculate matcher definer layout\n"); + return ret; + } + + /* Calculate definers needed for exact match */ + ret = hws_definer_mt_match_init(ctx, mt, &match_layout); + if (ret) { + mlx5hws_err(ctx, "Failed to init match definers\n"); + goto free_fc; + } + + return 0; + +free_fc: + kfree(mt->fc); + return ret; +} + +void mlx5hws_definer_mt_uninit(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt) +{ + hws_definer_mt_match_uninit(ctx, mt); + kfree(mt->fc); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.h new file mode 100644 index 00000000000000..9432d5084def3b --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.h @@ -0,0 +1,834 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_DEFINER_H_ +#define HWS_DEFINER_H_ + +/* Max available selecotrs */ +#define DW_SELECTORS 9 +#define BYTE_SELECTORS 8 + +/* Selectors based on match TAG */ +#define DW_SELECTORS_MATCH 6 +#define DW_SELECTORS_LIMITED 3 + +/* Selectors based on range TAG */ +#define DW_SELECTORS_RANGE 2 +#define BYTE_SELECTORS_RANGE 8 + +#define HWS_NUM_OF_FLEX_PARSERS 8 + +enum mlx5hws_definer_fname { + MLX5HWS_DEFINER_FNAME_ETH_SMAC_47_16_O, + MLX5HWS_DEFINER_FNAME_ETH_SMAC_47_16_I, + MLX5HWS_DEFINER_FNAME_ETH_SMAC_15_0_O, + MLX5HWS_DEFINER_FNAME_ETH_SMAC_15_0_I, + MLX5HWS_DEFINER_FNAME_ETH_DMAC_47_16_O, + MLX5HWS_DEFINER_FNAME_ETH_DMAC_47_16_I, + MLX5HWS_DEFINER_FNAME_ETH_DMAC_15_0_O, + MLX5HWS_DEFINER_FNAME_ETH_DMAC_15_0_I, + MLX5HWS_DEFINER_FNAME_ETH_TYPE_O, + MLX5HWS_DEFINER_FNAME_ETH_TYPE_I, + MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_O, + MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_I, + MLX5HWS_DEFINER_FNAME_VLAN_TYPE_O, + MLX5HWS_DEFINER_FNAME_VLAN_TYPE_I, + MLX5HWS_DEFINER_FNAME_VLAN_FIRST_PRIO_O, + MLX5HWS_DEFINER_FNAME_VLAN_FIRST_PRIO_I, + MLX5HWS_DEFINER_FNAME_VLAN_CFI_O, + MLX5HWS_DEFINER_FNAME_VLAN_CFI_I, + MLX5HWS_DEFINER_FNAME_VLAN_ID_O, + MLX5HWS_DEFINER_FNAME_VLAN_ID_I, + MLX5HWS_DEFINER_FNAME_VLAN_SECOND_TYPE_O, + MLX5HWS_DEFINER_FNAME_VLAN_SECOND_TYPE_I, + MLX5HWS_DEFINER_FNAME_VLAN_SECOND_PRIO_O, + MLX5HWS_DEFINER_FNAME_VLAN_SECOND_PRIO_I, + MLX5HWS_DEFINER_FNAME_VLAN_SECOND_CFI_O, + MLX5HWS_DEFINER_FNAME_VLAN_SECOND_CFI_I, + MLX5HWS_DEFINER_FNAME_VLAN_SECOND_ID_O, + MLX5HWS_DEFINER_FNAME_VLAN_SECOND_ID_I, + MLX5HWS_DEFINER_FNAME_IPV4_IHL_O, + MLX5HWS_DEFINER_FNAME_IPV4_IHL_I, + MLX5HWS_DEFINER_FNAME_IP_DSCP_O, + MLX5HWS_DEFINER_FNAME_IP_DSCP_I, + MLX5HWS_DEFINER_FNAME_IP_ECN_O, + MLX5HWS_DEFINER_FNAME_IP_ECN_I, + MLX5HWS_DEFINER_FNAME_IP_TTL_O, + MLX5HWS_DEFINER_FNAME_IP_TTL_I, + MLX5HWS_DEFINER_FNAME_IPV4_DST_O, + MLX5HWS_DEFINER_FNAME_IPV4_DST_I, + MLX5HWS_DEFINER_FNAME_IPV4_SRC_O, + MLX5HWS_DEFINER_FNAME_IPV4_SRC_I, + MLX5HWS_DEFINER_FNAME_IP_VERSION_O, + MLX5HWS_DEFINER_FNAME_IP_VERSION_I, + MLX5HWS_DEFINER_FNAME_IP_FRAG_O, + MLX5HWS_DEFINER_FNAME_IP_FRAG_I, + MLX5HWS_DEFINER_FNAME_IP_LEN_O, + MLX5HWS_DEFINER_FNAME_IP_LEN_I, + MLX5HWS_DEFINER_FNAME_IP_TOS_O, + MLX5HWS_DEFINER_FNAME_IP_TOS_I, + MLX5HWS_DEFINER_FNAME_IPV6_FLOW_LABEL_O, + MLX5HWS_DEFINER_FNAME_IPV6_FLOW_LABEL_I, + MLX5HWS_DEFINER_FNAME_IPV6_DST_127_96_O, + MLX5HWS_DEFINER_FNAME_IPV6_DST_95_64_O, + MLX5HWS_DEFINER_FNAME_IPV6_DST_63_32_O, + MLX5HWS_DEFINER_FNAME_IPV6_DST_31_0_O, + MLX5HWS_DEFINER_FNAME_IPV6_DST_127_96_I, + MLX5HWS_DEFINER_FNAME_IPV6_DST_95_64_I, + MLX5HWS_DEFINER_FNAME_IPV6_DST_63_32_I, + MLX5HWS_DEFINER_FNAME_IPV6_DST_31_0_I, + MLX5HWS_DEFINER_FNAME_IPV6_SRC_127_96_O, + MLX5HWS_DEFINER_FNAME_IPV6_SRC_95_64_O, + MLX5HWS_DEFINER_FNAME_IPV6_SRC_63_32_O, + MLX5HWS_DEFINER_FNAME_IPV6_SRC_31_0_O, + MLX5HWS_DEFINER_FNAME_IPV6_SRC_127_96_I, + MLX5HWS_DEFINER_FNAME_IPV6_SRC_95_64_I, + MLX5HWS_DEFINER_FNAME_IPV6_SRC_63_32_I, + MLX5HWS_DEFINER_FNAME_IPV6_SRC_31_0_I, + MLX5HWS_DEFINER_FNAME_IP_PROTOCOL_O, + MLX5HWS_DEFINER_FNAME_IP_PROTOCOL_I, + MLX5HWS_DEFINER_FNAME_L4_SPORT_O, + MLX5HWS_DEFINER_FNAME_L4_SPORT_I, + MLX5HWS_DEFINER_FNAME_L4_DPORT_O, + MLX5HWS_DEFINER_FNAME_L4_DPORT_I, + MLX5HWS_DEFINER_FNAME_TCP_FLAGS_I, + MLX5HWS_DEFINER_FNAME_TCP_FLAGS_O, + MLX5HWS_DEFINER_FNAME_TCP_SEQ_NUM, + MLX5HWS_DEFINER_FNAME_TCP_ACK_NUM, + MLX5HWS_DEFINER_FNAME_GTP_TEID, + MLX5HWS_DEFINER_FNAME_GTP_MSG_TYPE, + MLX5HWS_DEFINER_FNAME_GTP_EXT_FLAG, + MLX5HWS_DEFINER_FNAME_GTP_NEXT_EXT_HDR, + MLX5HWS_DEFINER_FNAME_GTP_EXT_HDR_PDU, + MLX5HWS_DEFINER_FNAME_GTP_EXT_HDR_QFI, + MLX5HWS_DEFINER_FNAME_GTPU_DW0, + MLX5HWS_DEFINER_FNAME_GTPU_FIRST_EXT_DW0, + MLX5HWS_DEFINER_FNAME_GTPU_DW2, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER_0, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER_1, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER_2, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER_3, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER_4, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER_5, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER_6, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER_7, + MLX5HWS_DEFINER_FNAME_VPORT_REG_C_0, + MLX5HWS_DEFINER_FNAME_VXLAN_FLAGS, + MLX5HWS_DEFINER_FNAME_VXLAN_VNI, + MLX5HWS_DEFINER_FNAME_VXLAN_GPE_FLAGS, + MLX5HWS_DEFINER_FNAME_VXLAN_GPE_RSVD0, + MLX5HWS_DEFINER_FNAME_VXLAN_GPE_PROTO, + MLX5HWS_DEFINER_FNAME_VXLAN_GPE_VNI, + MLX5HWS_DEFINER_FNAME_VXLAN_GPE_RSVD1, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_LEN, + MLX5HWS_DEFINER_FNAME_GENEVE_OAM, + MLX5HWS_DEFINER_FNAME_GENEVE_PROTO, + MLX5HWS_DEFINER_FNAME_GENEVE_VNI, + MLX5HWS_DEFINER_FNAME_SOURCE_QP, + MLX5HWS_DEFINER_FNAME_SOURCE_GVMI, + MLX5HWS_DEFINER_FNAME_REG_0, + MLX5HWS_DEFINER_FNAME_REG_1, + MLX5HWS_DEFINER_FNAME_REG_2, + MLX5HWS_DEFINER_FNAME_REG_3, + MLX5HWS_DEFINER_FNAME_REG_4, + MLX5HWS_DEFINER_FNAME_REG_5, + MLX5HWS_DEFINER_FNAME_REG_6, + MLX5HWS_DEFINER_FNAME_REG_7, + MLX5HWS_DEFINER_FNAME_REG_8, + MLX5HWS_DEFINER_FNAME_REG_9, + MLX5HWS_DEFINER_FNAME_REG_10, + MLX5HWS_DEFINER_FNAME_REG_11, + MLX5HWS_DEFINER_FNAME_REG_A, + MLX5HWS_DEFINER_FNAME_REG_B, + MLX5HWS_DEFINER_FNAME_GRE_KEY_PRESENT, + MLX5HWS_DEFINER_FNAME_GRE_C, + MLX5HWS_DEFINER_FNAME_GRE_K, + MLX5HWS_DEFINER_FNAME_GRE_S, + MLX5HWS_DEFINER_FNAME_GRE_PROTOCOL, + MLX5HWS_DEFINER_FNAME_GRE_OPT_KEY, + MLX5HWS_DEFINER_FNAME_GRE_OPT_SEQ, + MLX5HWS_DEFINER_FNAME_GRE_OPT_CHECKSUM, + MLX5HWS_DEFINER_FNAME_INTEGRITY_O, + MLX5HWS_DEFINER_FNAME_INTEGRITY_I, + MLX5HWS_DEFINER_FNAME_ICMP_DW1, + MLX5HWS_DEFINER_FNAME_ICMP_DW2, + MLX5HWS_DEFINER_FNAME_ICMP_DW3, + MLX5HWS_DEFINER_FNAME_IPSEC_SPI, + MLX5HWS_DEFINER_FNAME_IPSEC_SEQUENCE_NUMBER, + MLX5HWS_DEFINER_FNAME_IPSEC_SYNDROME, + MLX5HWS_DEFINER_FNAME_MPLS0_O, + MLX5HWS_DEFINER_FNAME_MPLS1_O, + MLX5HWS_DEFINER_FNAME_MPLS2_O, + MLX5HWS_DEFINER_FNAME_MPLS3_O, + MLX5HWS_DEFINER_FNAME_MPLS4_O, + MLX5HWS_DEFINER_FNAME_MPLS0_I, + MLX5HWS_DEFINER_FNAME_MPLS1_I, + MLX5HWS_DEFINER_FNAME_MPLS2_I, + MLX5HWS_DEFINER_FNAME_MPLS3_I, + MLX5HWS_DEFINER_FNAME_MPLS4_I, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER0_OK, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER1_OK, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER2_OK, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER3_OK, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER4_OK, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER5_OK, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER6_OK, + MLX5HWS_DEFINER_FNAME_FLEX_PARSER7_OK, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS0_O, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS1_O, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS2_O, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS3_O, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS4_O, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS0_I, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS1_I, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS2_I, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS3_I, + MLX5HWS_DEFINER_FNAME_OKS2_MPLS4_I, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_0, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_1, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_2, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_3, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_4, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_5, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_6, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_7, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_0, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_1, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_2, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_3, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_4, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_5, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_6, + MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_7, + MLX5HWS_DEFINER_FNAME_IB_L4_OPCODE, + MLX5HWS_DEFINER_FNAME_IB_L4_QPN, + MLX5HWS_DEFINER_FNAME_IB_L4_A, + MLX5HWS_DEFINER_FNAME_RANDOM_NUM, + MLX5HWS_DEFINER_FNAME_PTYPE_L2_O, + MLX5HWS_DEFINER_FNAME_PTYPE_L2_I, + MLX5HWS_DEFINER_FNAME_PTYPE_L3_O, + MLX5HWS_DEFINER_FNAME_PTYPE_L3_I, + MLX5HWS_DEFINER_FNAME_PTYPE_L4_O, + MLX5HWS_DEFINER_FNAME_PTYPE_L4_I, + MLX5HWS_DEFINER_FNAME_PTYPE_L4_EXT_O, + MLX5HWS_DEFINER_FNAME_PTYPE_L4_EXT_I, + MLX5HWS_DEFINER_FNAME_PTYPE_FRAG_O, + MLX5HWS_DEFINER_FNAME_PTYPE_FRAG_I, + MLX5HWS_DEFINER_FNAME_TNL_HDR_0, + MLX5HWS_DEFINER_FNAME_TNL_HDR_1, + MLX5HWS_DEFINER_FNAME_TNL_HDR_2, + MLX5HWS_DEFINER_FNAME_TNL_HDR_3, + MLX5HWS_DEFINER_FNAME_MAX, +}; + +enum mlx5hws_definer_match_criteria { + MLX5HWS_DEFINER_MATCH_CRITERIA_EMPTY = 0, + MLX5HWS_DEFINER_MATCH_CRITERIA_OUTER = 1 << 0, + MLX5HWS_DEFINER_MATCH_CRITERIA_MISC = 1 << 1, + MLX5HWS_DEFINER_MATCH_CRITERIA_INNER = 1 << 2, + MLX5HWS_DEFINER_MATCH_CRITERIA_MISC2 = 1 << 3, + MLX5HWS_DEFINER_MATCH_CRITERIA_MISC3 = 1 << 4, + MLX5HWS_DEFINER_MATCH_CRITERIA_MISC4 = 1 << 5, + MLX5HWS_DEFINER_MATCH_CRITERIA_MISC5 = 1 << 6, + MLX5HWS_DEFINER_MATCH_CRITERIA_MISC6 = 1 << 7, +}; + +enum mlx5hws_definer_type { + MLX5HWS_DEFINER_TYPE_MATCH, + MLX5HWS_DEFINER_TYPE_JUMBO, +}; + +enum mlx5hws_definer_match_flag { + MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE = 1 << 0, + MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE = 1 << 1, + MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU = 1 << 2, + MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE = 1 << 3, + MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN = 1 << 4, + MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_0_1 = 1 << 5, + + MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE_OPT_KEY = 1 << 6, + MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_2 = 1 << 7, + + MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_GRE = 1 << 8, + MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_UDP = 1 << 9, + + MLX5HWS_DEFINER_MATCH_FLAG_ICMPV4 = 1 << 10, + MLX5HWS_DEFINER_MATCH_FLAG_ICMPV6 = 1 << 11, + MLX5HWS_DEFINER_MATCH_FLAG_TCP_O = 1 << 12, + MLX5HWS_DEFINER_MATCH_FLAG_TCP_I = 1 << 13, +}; + +struct mlx5hws_definer_fc { + struct mlx5hws_context *ctx; + /* Source */ + u32 s_byte_off; + int s_bit_off; + u32 s_bit_mask; + /* Destination */ + u32 byte_off; + int bit_off; + u32 bit_mask; + enum mlx5hws_definer_fname fname; + void (*tag_set)(struct mlx5hws_definer_fc *fc, + void *mach_param, + u8 *tag); + void (*tag_mask_set)(struct mlx5hws_definer_fc *fc, + void *mach_param, + u8 *tag); +}; + +struct mlx5_ifc_definer_hl_eth_l2_bits { + u8 dmac_47_16[0x20]; + u8 dmac_15_0[0x10]; + u8 l3_ethertype[0x10]; + u8 reserved_at_40[0x1]; + u8 sx_sniffer[0x1]; + u8 functional_lb[0x1]; + u8 ip_fragmented[0x1]; + u8 qp_type[0x2]; + u8 encap_type[0x2]; + u8 port_number[0x2]; + u8 l3_type[0x2]; + u8 l4_type_bwc[0x2]; + u8 first_vlan_qualifier[0x2]; + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 first_vlan_id[0xc]; + u8 l4_type[0x4]; + u8 reserved_at_64[0x2]; + u8 ipsec_layer[0x2]; + u8 l2_type[0x2]; + u8 force_lb[0x1]; + u8 l2_ok[0x1]; + u8 l3_ok[0x1]; + u8 l4_ok[0x1]; + u8 second_vlan_qualifier[0x2]; + u8 second_priority[0x3]; + u8 second_cfi[0x1]; + u8 second_vlan_id[0xc]; +}; + +struct mlx5_ifc_definer_hl_eth_l2_src_bits { + u8 smac_47_16[0x20]; + u8 smac_15_0[0x10]; + u8 loopback_syndrome[0x8]; + u8 l3_type[0x2]; + u8 l4_type_bwc[0x2]; + u8 first_vlan_qualifier[0x2]; + u8 ip_fragmented[0x1]; + u8 functional_lb[0x1]; +}; + +struct mlx5_ifc_definer_hl_ib_l2_bits { + u8 sx_sniffer[0x1]; + u8 force_lb[0x1]; + u8 functional_lb[0x1]; + u8 reserved_at_3[0x3]; + u8 port_number[0x2]; + u8 sl[0x4]; + u8 qp_type[0x2]; + u8 lnh[0x2]; + u8 dlid[0x10]; + u8 vl[0x4]; + u8 lrh_packet_length[0xc]; + u8 slid[0x10]; +}; + +struct mlx5_ifc_definer_hl_eth_l3_bits { + u8 ip_version[0x4]; + u8 ihl[0x4]; + union { + u8 tos[0x8]; + struct { + u8 dscp[0x6]; + u8 ecn[0x2]; + }; + }; + u8 time_to_live_hop_limit[0x8]; + u8 protocol_next_header[0x8]; + u8 identification[0x10]; + union { + u8 ipv4_frag[0x10]; + struct { + u8 flags[0x3]; + u8 fragment_offset[0xd]; + }; + }; + u8 ipv4_total_length[0x10]; + u8 checksum[0x10]; + u8 reserved_at_60[0xc]; + u8 flow_label[0x14]; + u8 packet_length[0x10]; + u8 ipv6_payload_length[0x10]; +}; + +struct mlx5_ifc_definer_hl_eth_l4_bits { + u8 source_port[0x10]; + u8 destination_port[0x10]; + u8 data_offset[0x4]; + u8 l4_ok[0x1]; + u8 l3_ok[0x1]; + u8 ip_fragmented[0x1]; + u8 tcp_ns[0x1]; + union { + u8 tcp_flags[0x8]; + struct { + u8 tcp_cwr[0x1]; + u8 tcp_ece[0x1]; + u8 tcp_urg[0x1]; + u8 tcp_ack[0x1]; + u8 tcp_psh[0x1]; + u8 tcp_rst[0x1]; + u8 tcp_syn[0x1]; + u8 tcp_fin[0x1]; + }; + }; + u8 first_fragment[0x1]; + u8 reserved_at_31[0xf]; +}; + +struct mlx5_ifc_definer_hl_src_qp_gvmi_bits { + u8 loopback_syndrome[0x8]; + u8 l3_type[0x2]; + u8 l4_type_bwc[0x2]; + u8 first_vlan_qualifier[0x2]; + u8 reserved_at_e[0x1]; + u8 functional_lb[0x1]; + u8 source_gvmi[0x10]; + u8 force_lb[0x1]; + u8 ip_fragmented[0x1]; + u8 source_is_requestor[0x1]; + u8 reserved_at_23[0x5]; + u8 source_qp[0x18]; +}; + +struct mlx5_ifc_definer_hl_ib_l4_bits { + u8 opcode[0x8]; + u8 qp[0x18]; + u8 se[0x1]; + u8 migreq[0x1]; + u8 ackreq[0x1]; + u8 fecn[0x1]; + u8 becn[0x1]; + u8 bth[0x1]; + u8 deth[0x1]; + u8 dcceth[0x1]; + u8 reserved_at_28[0x2]; + u8 pad_count[0x2]; + u8 tver[0x4]; + u8 p_key[0x10]; + u8 reserved_at_40[0x8]; + u8 deth_source_qp[0x18]; +}; + +enum mlx5hws_integrity_ok1_bits { + MLX5HWS_DEFINER_OKS1_FIRST_L4_OK = 24, + MLX5HWS_DEFINER_OKS1_FIRST_L3_OK = 25, + MLX5HWS_DEFINER_OKS1_SECOND_L4_OK = 26, + MLX5HWS_DEFINER_OKS1_SECOND_L3_OK = 27, + MLX5HWS_DEFINER_OKS1_FIRST_L4_CSUM_OK = 28, + MLX5HWS_DEFINER_OKS1_FIRST_IPV4_CSUM_OK = 29, + MLX5HWS_DEFINER_OKS1_SECOND_L4_CSUM_OK = 30, + MLX5HWS_DEFINER_OKS1_SECOND_IPV4_CSUM_OK = 31, +}; + +struct mlx5_ifc_definer_hl_oks1_bits { + union { + u8 oks1_bits[0x20]; + struct { + u8 second_ipv4_checksum_ok[0x1]; + u8 second_l4_checksum_ok[0x1]; + u8 first_ipv4_checksum_ok[0x1]; + u8 first_l4_checksum_ok[0x1]; + u8 second_l3_ok[0x1]; + u8 second_l4_ok[0x1]; + u8 first_l3_ok[0x1]; + u8 first_l4_ok[0x1]; + u8 flex_parser7_steering_ok[0x1]; + u8 flex_parser6_steering_ok[0x1]; + u8 flex_parser5_steering_ok[0x1]; + u8 flex_parser4_steering_ok[0x1]; + u8 flex_parser3_steering_ok[0x1]; + u8 flex_parser2_steering_ok[0x1]; + u8 flex_parser1_steering_ok[0x1]; + u8 flex_parser0_steering_ok[0x1]; + u8 second_ipv6_extension_header_vld[0x1]; + u8 first_ipv6_extension_header_vld[0x1]; + u8 l3_tunneling_ok[0x1]; + u8 l2_tunneling_ok[0x1]; + u8 second_tcp_ok[0x1]; + u8 second_udp_ok[0x1]; + u8 second_ipv4_ok[0x1]; + u8 second_ipv6_ok[0x1]; + u8 second_l2_ok[0x1]; + u8 vxlan_ok[0x1]; + u8 gre_ok[0x1]; + u8 first_tcp_ok[0x1]; + u8 first_udp_ok[0x1]; + u8 first_ipv4_ok[0x1]; + u8 first_ipv6_ok[0x1]; + u8 first_l2_ok[0x1]; + }; + }; +}; + +struct mlx5_ifc_definer_hl_oks2_bits { + u8 reserved_at_0[0xa]; + u8 second_mpls_ok[0x1]; + u8 second_mpls4_s_bit[0x1]; + u8 second_mpls4_qualifier[0x1]; + u8 second_mpls3_s_bit[0x1]; + u8 second_mpls3_qualifier[0x1]; + u8 second_mpls2_s_bit[0x1]; + u8 second_mpls2_qualifier[0x1]; + u8 second_mpls1_s_bit[0x1]; + u8 second_mpls1_qualifier[0x1]; + u8 second_mpls0_s_bit[0x1]; + u8 second_mpls0_qualifier[0x1]; + u8 first_mpls_ok[0x1]; + u8 first_mpls4_s_bit[0x1]; + u8 first_mpls4_qualifier[0x1]; + u8 first_mpls3_s_bit[0x1]; + u8 first_mpls3_qualifier[0x1]; + u8 first_mpls2_s_bit[0x1]; + u8 first_mpls2_qualifier[0x1]; + u8 first_mpls1_s_bit[0x1]; + u8 first_mpls1_qualifier[0x1]; + u8 first_mpls0_s_bit[0x1]; + u8 first_mpls0_qualifier[0x1]; +}; + +struct mlx5_ifc_definer_hl_voq_bits { + u8 reserved_at_0[0x18]; + u8 ecn_ok[0x1]; + u8 congestion[0x1]; + u8 profile[0x2]; + u8 internal_prio[0x4]; +}; + +struct mlx5_ifc_definer_hl_ipv4_src_dst_bits { + u8 source_address[0x20]; + u8 destination_address[0x20]; +}; + +struct mlx5_ifc_definer_hl_random_number_bits { + u8 random_number[0x10]; + u8 reserved[0x10]; +}; + +struct mlx5_ifc_definer_hl_ipv6_addr_bits { + u8 ipv6_address_127_96[0x20]; + u8 ipv6_address_95_64[0x20]; + u8 ipv6_address_63_32[0x20]; + u8 ipv6_address_31_0[0x20]; +}; + +struct mlx5_ifc_definer_tcp_icmp_header_bits { + union { + struct { + u8 icmp_dw1[0x20]; + u8 icmp_dw2[0x20]; + u8 icmp_dw3[0x20]; + }; + struct { + u8 tcp_seq[0x20]; + u8 tcp_ack[0x20]; + u8 tcp_win_urg[0x20]; + }; + }; +}; + +struct mlx5_ifc_definer_hl_tunnel_header_bits { + u8 tunnel_header_0[0x20]; + u8 tunnel_header_1[0x20]; + u8 tunnel_header_2[0x20]; + u8 tunnel_header_3[0x20]; +}; + +struct mlx5_ifc_definer_hl_ipsec_bits { + u8 spi[0x20]; + u8 sequence_number[0x20]; + u8 reserved[0x10]; + u8 ipsec_syndrome[0x8]; + u8 next_header[0x8]; +}; + +struct mlx5_ifc_definer_hl_metadata_bits { + u8 metadata_to_cqe[0x20]; + u8 general_purpose[0x20]; + u8 acomulated_hash[0x20]; +}; + +struct mlx5_ifc_definer_hl_flex_parser_bits { + u8 flex_parser_7[0x20]; + u8 flex_parser_6[0x20]; + u8 flex_parser_5[0x20]; + u8 flex_parser_4[0x20]; + u8 flex_parser_3[0x20]; + u8 flex_parser_2[0x20]; + u8 flex_parser_1[0x20]; + u8 flex_parser_0[0x20]; +}; + +struct mlx5_ifc_definer_hl_registers_bits { + u8 register_c_10[0x20]; + u8 register_c_11[0x20]; + u8 register_c_8[0x20]; + u8 register_c_9[0x20]; + u8 register_c_6[0x20]; + u8 register_c_7[0x20]; + u8 register_c_4[0x20]; + u8 register_c_5[0x20]; + u8 register_c_2[0x20]; + u8 register_c_3[0x20]; + u8 register_c_0[0x20]; + u8 register_c_1[0x20]; +}; + +struct mlx5_ifc_definer_hl_mpls_bits { + u8 mpls0_label[0x20]; + u8 mpls1_label[0x20]; + u8 mpls2_label[0x20]; + u8 mpls3_label[0x20]; + u8 mpls4_label[0x20]; +}; + +struct mlx5_ifc_definer_hl_bits { + struct mlx5_ifc_definer_hl_eth_l2_bits eth_l2_outer; + struct mlx5_ifc_definer_hl_eth_l2_bits eth_l2_inner; + struct mlx5_ifc_definer_hl_eth_l2_src_bits eth_l2_src_outer; + struct mlx5_ifc_definer_hl_eth_l2_src_bits eth_l2_src_inner; + struct mlx5_ifc_definer_hl_ib_l2_bits ib_l2; + struct mlx5_ifc_definer_hl_eth_l3_bits eth_l3_outer; + struct mlx5_ifc_definer_hl_eth_l3_bits eth_l3_inner; + struct mlx5_ifc_definer_hl_eth_l4_bits eth_l4_outer; + struct mlx5_ifc_definer_hl_eth_l4_bits eth_l4_inner; + struct mlx5_ifc_definer_hl_src_qp_gvmi_bits source_qp_gvmi; + struct mlx5_ifc_definer_hl_ib_l4_bits ib_l4; + struct mlx5_ifc_definer_hl_oks1_bits oks1; + struct mlx5_ifc_definer_hl_oks2_bits oks2; + struct mlx5_ifc_definer_hl_voq_bits voq; + u8 reserved_at_480[0x380]; + struct mlx5_ifc_definer_hl_ipv4_src_dst_bits ipv4_src_dest_outer; + struct mlx5_ifc_definer_hl_ipv4_src_dst_bits ipv4_src_dest_inner; + struct mlx5_ifc_definer_hl_ipv6_addr_bits ipv6_dst_outer; + struct mlx5_ifc_definer_hl_ipv6_addr_bits ipv6_dst_inner; + struct mlx5_ifc_definer_hl_ipv6_addr_bits ipv6_src_outer; + struct mlx5_ifc_definer_hl_ipv6_addr_bits ipv6_src_inner; + u8 unsupported_dest_ib_l3[0x80]; + u8 unsupported_source_ib_l3[0x80]; + u8 unsupported_udp_misc_outer[0x20]; + u8 unsupported_udp_misc_inner[0x20]; + struct mlx5_ifc_definer_tcp_icmp_header_bits tcp_icmp; + struct mlx5_ifc_definer_hl_tunnel_header_bits tunnel_header; + struct mlx5_ifc_definer_hl_mpls_bits mpls_outer; + struct mlx5_ifc_definer_hl_mpls_bits mpls_inner; + u8 unsupported_config_headers_outer[0x80]; + u8 unsupported_config_headers_inner[0x80]; + struct mlx5_ifc_definer_hl_random_number_bits random_number; + struct mlx5_ifc_definer_hl_ipsec_bits ipsec; + struct mlx5_ifc_definer_hl_metadata_bits metadata; + u8 unsupported_utc_timestamp[0x40]; + u8 unsupported_free_running_timestamp[0x40]; + struct mlx5_ifc_definer_hl_flex_parser_bits flex_parser; + struct mlx5_ifc_definer_hl_registers_bits registers; + /* Reserved in case header layout on future HW */ + u8 unsupported_reserved[0xd40]; +}; + +enum mlx5hws_definer_gtp { + MLX5HWS_DEFINER_GTP_EXT_HDR_BIT = 0x04, +}; + +struct mlx5_ifc_header_gtp_bits { + u8 version[0x3]; + u8 proto_type[0x1]; + u8 reserved1[0x1]; + union { + u8 msg_flags[0x3]; + struct { + u8 ext_hdr_flag[0x1]; + u8 seq_num_flag[0x1]; + u8 pdu_flag[0x1]; + }; + }; + u8 msg_type[0x8]; + u8 msg_len[0x8]; + u8 teid[0x20]; +}; + +struct mlx5_ifc_header_opt_gtp_bits { + u8 seq_num[0x10]; + u8 pdu_num[0x8]; + u8 next_ext_hdr_type[0x8]; +}; + +struct mlx5_ifc_header_gtp_psc_bits { + u8 len[0x8]; + u8 pdu_type[0x4]; + u8 flags[0x4]; + u8 qfi[0x8]; + u8 reserved2[0x8]; +}; + +struct mlx5_ifc_header_ipv6_vtc_bits { + u8 version[0x4]; + union { + u8 tos[0x8]; + struct { + u8 dscp[0x6]; + u8 ecn[0x2]; + }; + }; + u8 flow_label[0x14]; +}; + +struct mlx5_ifc_header_ipv6_routing_ext_bits { + u8 next_hdr[0x8]; + u8 hdr_len[0x8]; + u8 type[0x8]; + u8 segments_left[0x8]; + union { + u8 flags[0x20]; + struct { + u8 last_entry[0x8]; + u8 flag[0x8]; + u8 tag[0x10]; + }; + }; +}; + +struct mlx5_ifc_header_vxlan_bits { + u8 flags[0x8]; + u8 reserved1[0x18]; + u8 vni[0x18]; + u8 reserved2[0x8]; +}; + +struct mlx5_ifc_header_vxlan_gpe_bits { + u8 flags[0x8]; + u8 rsvd0[0x10]; + u8 protocol[0x8]; + u8 vni[0x18]; + u8 rsvd1[0x8]; +}; + +struct mlx5_ifc_header_gre_bits { + union { + u8 c_rsvd0_ver[0x10]; + struct { + u8 gre_c_present[0x1]; + u8 reserved_at_1[0x1]; + u8 gre_k_present[0x1]; + u8 gre_s_present[0x1]; + u8 reserved_at_4[0x9]; + u8 version[0x3]; + }; + }; + u8 gre_protocol[0x10]; + u8 checksum[0x10]; + u8 reserved_at_30[0x10]; +}; + +struct mlx5_ifc_header_geneve_bits { + union { + u8 ver_opt_len_o_c_rsvd[0x10]; + struct { + u8 version[0x2]; + u8 opt_len[0x6]; + u8 o_flag[0x1]; + u8 c_flag[0x1]; + u8 reserved_at_a[0x6]; + }; + }; + u8 protocol_type[0x10]; + u8 vni[0x18]; + u8 reserved_at_38[0x8]; +}; + +struct mlx5_ifc_header_geneve_opt_bits { + u8 class[0x10]; + u8 type[0x8]; + u8 reserved[0x3]; + u8 len[0x5]; +}; + +struct mlx5_ifc_header_icmp_bits { + union { + u8 icmp_dw1[0x20]; + struct { + u8 type[0x8]; + u8 code[0x8]; + u8 cksum[0x10]; + }; + }; + union { + u8 icmp_dw2[0x20]; + struct { + u8 ident[0x10]; + u8 seq_nb[0x10]; + }; + }; +}; + +struct mlx5hws_definer { + enum mlx5hws_definer_type type; + u8 dw_selector[DW_SELECTORS]; + u8 byte_selector[BYTE_SELECTORS]; + struct mlx5hws_rule_match_tag mask; + u32 obj_id; +}; + +struct mlx5hws_definer_cache { + struct list_head list_head; +}; + +struct mlx5hws_definer_cache_item { + struct mlx5hws_definer definer; + u32 refcount; + struct list_head list_node; +}; + +static inline bool +mlx5hws_definer_is_jumbo(struct mlx5hws_definer *definer) +{ + return (definer->type == MLX5HWS_DEFINER_TYPE_JUMBO); +} + +void mlx5hws_definer_create_tag(u32 *match_param, + struct mlx5hws_definer_fc *fc, + u32 fc_sz, + u8 *tag); + +int mlx5hws_definer_get_id(struct mlx5hws_definer *definer); + +int mlx5hws_definer_mt_init(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt); + +void mlx5hws_definer_mt_uninit(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt); + +int mlx5hws_definer_init_cache(struct mlx5hws_definer_cache **cache); + +void mlx5hws_definer_uninit_cache(struct mlx5hws_definer_cache *cache); + +int mlx5hws_definer_compare(struct mlx5hws_definer *definer_a, + struct mlx5hws_definer *definer_b); + +int mlx5hws_definer_get_obj(struct mlx5hws_context *ctx, + struct mlx5hws_definer *definer); + +void mlx5hws_definer_free(struct mlx5hws_context *ctx, + struct mlx5hws_definer *definer); + +int mlx5hws_definer_calc_layout(struct mlx5hws_context *ctx, + struct mlx5hws_match_template *mt, + struct mlx5hws_definer *match_definer); + +struct mlx5hws_definer_fc * +mlx5hws_definer_conv_match_params_to_compressed_fc(struct mlx5hws_context *ctx, + u8 match_criteria_enable, + u32 *match_param, + int *fc_sz); + +#endif /* HWS_DEFINER_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/internal.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/internal.h new file mode 100644 index 00000000000000..3c8635f286cef5 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/internal.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_INTERNAL_H_ +#define HWS_INTERNAL_H_ + +#include +#include +#include "fs_core.h" +#include "wq.h" +#include "lib/mlx5.h" + +#include "prm.h" +#include "mlx5hws.h" +#include "pool.h" +#include "vport.h" +#include "context.h" +#include "table.h" +#include "send.h" +#include "rule.h" +#include "cmd.h" +#include "action.h" +#include "definer.h" +#include "matcher.h" +#include "debug.h" +#include "pat_arg.h" +#include "bwc.h" +#include "bwc_complex.h" + +#define W_SIZE 2 +#define DW_SIZE 4 +#define BITS_IN_BYTE 8 +#define BITS_IN_DW (BITS_IN_BYTE * DW_SIZE) + +#define IS_BIT_SET(_value, _bit) ((_value) & (1ULL << (_bit))) + +#define mlx5hws_err(ctx, arg...) mlx5_core_err((ctx)->mdev, ##arg) +#define mlx5hws_info(ctx, arg...) mlx5_core_info((ctx)->mdev, ##arg) +#define mlx5hws_dbg(ctx, arg...) mlx5_core_dbg((ctx)->mdev, ##arg) + +#define MLX5HWS_TABLE_TYPE_BASE 2 +#define MLX5HWS_ACTION_STE_IDX_ANY 0 + +static inline bool is_mem_zero(const u8 *mem, size_t size) +{ + if (unlikely(!size)) { + pr_warn("HWS: invalid buffer of size 0 in %s\n", __func__); + return true; + } + + return (*mem == 0) && memcmp(mem, mem + 1, size - 1) == 0; +} + +static inline unsigned long align(unsigned long val, unsigned long align) +{ + return (val + align - 1) & ~(align - 1); +} + +#endif /* HWS_INTERNAL_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c new file mode 100644 index 00000000000000..1bb3a6f8c3cda8 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c @@ -0,0 +1,1216 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +enum mlx5hws_matcher_rtc_type { + HWS_MATCHER_RTC_TYPE_MATCH, + HWS_MATCHER_RTC_TYPE_STE_ARRAY, + HWS_MATCHER_RTC_TYPE_MAX, +}; + +static const char * const mlx5hws_matcher_rtc_type_str[] = { + [HWS_MATCHER_RTC_TYPE_MATCH] = "MATCH", + [HWS_MATCHER_RTC_TYPE_STE_ARRAY] = "STE_ARRAY", + [HWS_MATCHER_RTC_TYPE_MAX] = "UNKNOWN", +}; + +static const char *hws_matcher_rtc_type_to_str(enum mlx5hws_matcher_rtc_type rtc_type) +{ + if (rtc_type > HWS_MATCHER_RTC_TYPE_MAX) + rtc_type = HWS_MATCHER_RTC_TYPE_MAX; + return mlx5hws_matcher_rtc_type_str[rtc_type]; +} + +static bool hws_matcher_requires_col_tbl(u8 log_num_of_rules) +{ + /* Collision table concatenation is done only for large rule tables */ + return log_num_of_rules > MLX5HWS_MATCHER_ASSURED_RULES_TH; +} + +static u8 hws_matcher_rules_to_tbl_depth(u8 log_num_of_rules) +{ + if (hws_matcher_requires_col_tbl(log_num_of_rules)) + return MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH; + + /* For small rule tables we use a single deep table to assure insertion */ + return min(log_num_of_rules, MLX5HWS_MATCHER_ASSURED_COL_TBL_DEPTH); +} + +static void hws_matcher_destroy_end_ft(struct mlx5hws_matcher *matcher) +{ + mlx5hws_table_destroy_default_ft(matcher->tbl, matcher->end_ft_id); +} + +static int hws_matcher_create_end_ft(struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_table *tbl = matcher->tbl; + int ret; + + ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, tbl, &matcher->end_ft_id); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed to create matcher end flow table\n"); + return ret; + } + return 0; +} + +static int hws_matcher_connect(struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_table *tbl = matcher->tbl; + struct mlx5hws_context *ctx = tbl->ctx; + struct mlx5hws_matcher *prev = NULL; + struct mlx5hws_matcher *next = NULL; + struct mlx5hws_matcher *tmp_matcher; + int ret; + + /* Find location in matcher list */ + if (list_empty(&tbl->matchers_list)) { + list_add(&matcher->list_node, &tbl->matchers_list); + goto connect; + } + + list_for_each_entry(tmp_matcher, &tbl->matchers_list, list_node) { + if (tmp_matcher->attr.priority > matcher->attr.priority) { + next = tmp_matcher; + break; + } + prev = tmp_matcher; + } + + if (next) + /* insert before next */ + list_add_tail(&matcher->list_node, &next->list_node); + else + /* insert after prev */ + list_add(&matcher->list_node, &prev->list_node); + +connect: + if (next) { + /* Connect to next RTC */ + ret = mlx5hws_table_ft_set_next_rtc(ctx, + matcher->end_ft_id, + tbl->fw_ft_type, + next->match_ste.rtc_0_id, + next->match_ste.rtc_1_id); + if (ret) { + mlx5hws_err(ctx, "Failed to connect new matcher to next RTC\n"); + goto remove_from_list; + } + } else { + /* Connect last matcher to next miss_tbl if exists */ + ret = mlx5hws_table_connect_to_miss_table(tbl, tbl->default_miss.miss_tbl); + if (ret) { + mlx5hws_err(ctx, "Failed connect new matcher to miss_tbl\n"); + goto remove_from_list; + } + } + + /* Connect to previous FT */ + ret = mlx5hws_table_ft_set_next_rtc(ctx, + prev ? prev->end_ft_id : tbl->ft_id, + tbl->fw_ft_type, + matcher->match_ste.rtc_0_id, + matcher->match_ste.rtc_1_id); + if (ret) { + mlx5hws_err(ctx, "Failed to connect new matcher to previous FT\n"); + goto remove_from_list; + } + + /* Reset prev matcher FT default miss (drop refcount) */ + ret = mlx5hws_table_ft_set_default_next_ft(tbl, prev ? prev->end_ft_id : tbl->ft_id); + if (ret) { + mlx5hws_err(ctx, "Failed to reset matcher ft default miss\n"); + goto remove_from_list; + } + + if (!prev) { + /* Update tables missing to current matcher in the table */ + ret = mlx5hws_table_update_connected_miss_tables(tbl); + if (ret) { + mlx5hws_err(ctx, "Fatal error, failed to update connected miss table\n"); + goto remove_from_list; + } + } + + return 0; + +remove_from_list: + list_del_init(&matcher->list_node); + return ret; +} + +static int hws_matcher_disconnect(struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_matcher *next = NULL, *prev = NULL; + struct mlx5hws_table *tbl = matcher->tbl; + u32 prev_ft_id = tbl->ft_id; + int ret; + + if (!list_is_first(&matcher->list_node, &tbl->matchers_list)) { + prev = list_prev_entry(matcher, list_node); + prev_ft_id = prev->end_ft_id; + } + + if (!list_is_last(&matcher->list_node, &tbl->matchers_list)) + next = list_next_entry(matcher, list_node); + + list_del_init(&matcher->list_node); + + if (next) { + /* Connect previous end FT to next RTC */ + ret = mlx5hws_table_ft_set_next_rtc(tbl->ctx, + prev_ft_id, + tbl->fw_ft_type, + next->match_ste.rtc_0_id, + next->match_ste.rtc_1_id); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed to disconnect matcher\n"); + goto matcher_reconnect; + } + } else { + ret = mlx5hws_table_connect_to_miss_table(tbl, tbl->default_miss.miss_tbl); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed to disconnect last matcher\n"); + goto matcher_reconnect; + } + } + + /* Removing first matcher, update connected miss tables if exists */ + if (prev_ft_id == tbl->ft_id) { + ret = mlx5hws_table_update_connected_miss_tables(tbl); + if (ret) { + mlx5hws_err(tbl->ctx, "Fatal error, failed to update connected miss table\n"); + goto matcher_reconnect; + } + } + + ret = mlx5hws_table_ft_set_default_next_ft(tbl, prev_ft_id); + if (ret) { + mlx5hws_err(tbl->ctx, "Fatal error, failed to restore matcher ft default miss\n"); + goto matcher_reconnect; + } + + return 0; + +matcher_reconnect: + if (list_empty(&tbl->matchers_list) || !prev) + list_add(&matcher->list_node, &tbl->matchers_list); + else + /* insert after prev matcher */ + list_add(&matcher->list_node, &prev->list_node); + + return ret; +} + +static void hws_matcher_set_rtc_attr_sz(struct mlx5hws_matcher *matcher, + struct mlx5hws_cmd_rtc_create_attr *rtc_attr, + enum mlx5hws_matcher_rtc_type rtc_type, + bool is_mirror) +{ + struct mlx5hws_pool_chunk *ste = &matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].ste; + enum mlx5hws_matcher_flow_src flow_src = matcher->attr.optimize_flow_src; + bool is_match_rtc = rtc_type == HWS_MATCHER_RTC_TYPE_MATCH; + + if ((flow_src == MLX5HWS_MATCHER_FLOW_SRC_VPORT && !is_mirror) || + (flow_src == MLX5HWS_MATCHER_FLOW_SRC_WIRE && is_mirror)) { + /* Optimize FDB RTC */ + rtc_attr->log_size = 0; + rtc_attr->log_depth = 0; + } else { + /* Keep original values */ + rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order; + rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0; + } +} + +static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher, + enum mlx5hws_matcher_rtc_type rtc_type, + u8 action_ste_selector) +{ + struct mlx5hws_matcher_attr *attr = &matcher->attr; + struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0}; + struct mlx5hws_match_template *mt = matcher->mt; + struct mlx5hws_context *ctx = matcher->tbl->ctx; + struct mlx5hws_action_default_stc *default_stc; + struct mlx5hws_matcher_action_ste *action_ste; + struct mlx5hws_table *tbl = matcher->tbl; + struct mlx5hws_pool *ste_pool, *stc_pool; + struct mlx5hws_pool_chunk *ste; + u32 *rtc_0_id, *rtc_1_id; + u32 obj_id; + int ret; + + switch (rtc_type) { + case HWS_MATCHER_RTC_TYPE_MATCH: + rtc_0_id = &matcher->match_ste.rtc_0_id; + rtc_1_id = &matcher->match_ste.rtc_1_id; + ste_pool = matcher->match_ste.pool; + ste = &matcher->match_ste.ste; + ste->order = attr->table.sz_col_log + attr->table.sz_row_log; + + rtc_attr.log_size = attr->table.sz_row_log; + rtc_attr.log_depth = attr->table.sz_col_log; + rtc_attr.is_frst_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); + rtc_attr.is_scnd_range = 0; + rtc_attr.miss_ft_id = matcher->end_ft_id; + + if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_HASH) { + /* The usual Hash Table */ + rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; + + /* The first mt is used since all share the same definer */ + rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer); + } else if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) { + rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; + rtc_attr.num_hash_definer = 1; + + if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) { + /* Hash Split Table */ + rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH; + rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer); + } else if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_LINEAR) { + /* Linear Lookup Table */ + rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR; + rtc_attr.match_definer_0 = ctx->caps->linear_match_definer; + } + } + + /* Match pool requires implicit allocation */ + ret = mlx5hws_pool_chunk_alloc(ste_pool, ste); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate STE for %s RTC", + hws_matcher_rtc_type_to_str(rtc_type)); + return ret; + } + break; + + case HWS_MATCHER_RTC_TYPE_STE_ARRAY: + action_ste = &matcher->action_ste[action_ste_selector]; + + rtc_0_id = &action_ste->rtc_0_id; + rtc_1_id = &action_ste->rtc_1_id; + ste_pool = action_ste->pool; + ste = &action_ste->ste; + ste->order = ilog2(roundup_pow_of_two(action_ste->max_stes)) + + attr->table.sz_row_log; + rtc_attr.log_size = ste->order; + rtc_attr.log_depth = 0; + rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; + /* The action STEs use the default always hit definer */ + rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; + rtc_attr.is_frst_jumbo = false; + rtc_attr.miss_ft_id = 0; + break; + + default: + mlx5hws_err(ctx, "HWS Invalid RTC type\n"); + return -EINVAL; + } + + obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); + + rtc_attr.pd = ctx->pd_num; + rtc_attr.ste_base = obj_id; + rtc_attr.ste_offset = ste->offset; + rtc_attr.reparse_mode = mlx5hws_context_get_reparse_mode(ctx); + rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, false); + hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, false); + + /* STC is a single resource (obj_id), use any STC for the ID */ + stc_pool = ctx->stc_pool[tbl->type]; + default_stc = ctx->common_res[tbl->type].default_stc; + obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit); + rtc_attr.stc_base = obj_id; + + ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id); + if (ret) { + mlx5hws_err(ctx, "Failed to create matcher RTC of type %s", + hws_matcher_rtc_type_to_str(rtc_type)); + goto free_ste; + } + + if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) { + obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); + rtc_attr.ste_base = obj_id; + rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, true); + + obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit); + rtc_attr.stc_base = obj_id; + hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, true); + + ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_1_id); + if (ret) { + mlx5hws_err(ctx, "Failed to create peer matcher RTC of type %s", + hws_matcher_rtc_type_to_str(rtc_type)); + goto destroy_rtc_0; + } + } + + return 0; + +destroy_rtc_0: + mlx5hws_cmd_rtc_destroy(ctx->mdev, *rtc_0_id); +free_ste: + if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH) + mlx5hws_pool_chunk_free(ste_pool, ste); + return ret; +} + +static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher, + enum mlx5hws_matcher_rtc_type rtc_type, + u8 action_ste_selector) +{ + struct mlx5hws_matcher_action_ste *action_ste; + struct mlx5hws_table *tbl = matcher->tbl; + struct mlx5hws_pool_chunk *ste; + struct mlx5hws_pool *ste_pool; + u32 rtc_0_id, rtc_1_id; + + switch (rtc_type) { + case HWS_MATCHER_RTC_TYPE_MATCH: + rtc_0_id = matcher->match_ste.rtc_0_id; + rtc_1_id = matcher->match_ste.rtc_1_id; + ste_pool = matcher->match_ste.pool; + ste = &matcher->match_ste.ste; + break; + case HWS_MATCHER_RTC_TYPE_STE_ARRAY: + action_ste = &matcher->action_ste[action_ste_selector]; + rtc_0_id = action_ste->rtc_0_id; + rtc_1_id = action_ste->rtc_1_id; + ste_pool = action_ste->pool; + ste = &action_ste->ste; + break; + default: + return; + } + + if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) + mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_1_id); + + mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_0_id); + if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH) + mlx5hws_pool_chunk_free(ste_pool, ste); +} + +static int +hws_matcher_check_attr_sz(struct mlx5hws_cmd_query_caps *caps, + struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_matcher_attr *attr = &matcher->attr; + + if (attr->table.sz_col_log > caps->rtc_log_depth_max) { + mlx5hws_err(matcher->tbl->ctx, "Matcher depth exceeds limit %d\n", + caps->rtc_log_depth_max); + return -EOPNOTSUPP; + } + + if (attr->table.sz_col_log + attr->table.sz_row_log > caps->ste_alloc_log_max) { + mlx5hws_err(matcher->tbl->ctx, "Total matcher size exceeds limit %d\n", + caps->ste_alloc_log_max); + return -EOPNOTSUPP; + } + + if (attr->table.sz_col_log + attr->table.sz_row_log < caps->ste_alloc_log_gran) { + mlx5hws_err(matcher->tbl->ctx, "Total matcher size below limit %d\n", + caps->ste_alloc_log_gran); + return -EOPNOTSUPP; + } + + return 0; +} + +static void hws_matcher_set_pool_attr(struct mlx5hws_pool_attr *attr, + struct mlx5hws_matcher *matcher) +{ + switch (matcher->attr.optimize_flow_src) { + case MLX5HWS_MATCHER_FLOW_SRC_VPORT: + attr->opt_type = MLX5HWS_POOL_OPTIMIZE_ORIG; + break; + case MLX5HWS_MATCHER_FLOW_SRC_WIRE: + attr->opt_type = MLX5HWS_POOL_OPTIMIZE_MIRROR; + break; + default: + break; + } +} + +static int hws_matcher_check_and_process_at(struct mlx5hws_matcher *matcher, + struct mlx5hws_action_template *at) +{ + struct mlx5hws_context *ctx = matcher->tbl->ctx; + bool valid; + int ret; + + valid = mlx5hws_action_check_combo(ctx, at->action_type_arr, matcher->tbl->type); + if (!valid) { + mlx5hws_err(ctx, "Invalid combination in action template\n"); + return -EINVAL; + } + + /* Process action template to setters */ + ret = mlx5hws_action_template_process(at); + if (ret) { + mlx5hws_err(ctx, "Failed to process action template\n"); + return ret; + } + + return 0; +} + +static int hws_matcher_resize_init(struct mlx5hws_matcher *src_matcher) +{ + struct mlx5hws_matcher_resize_data *resize_data; + + resize_data = kzalloc(sizeof(*resize_data), GFP_KERNEL); + if (!resize_data) + return -ENOMEM; + + resize_data->max_stes = src_matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes; + + resize_data->action_ste[0].stc = src_matcher->action_ste[0].stc; + resize_data->action_ste[0].rtc_0_id = src_matcher->action_ste[0].rtc_0_id; + resize_data->action_ste[0].rtc_1_id = src_matcher->action_ste[0].rtc_1_id; + resize_data->action_ste[0].pool = src_matcher->action_ste[0].max_stes ? + src_matcher->action_ste[0].pool : + NULL; + resize_data->action_ste[1].stc = src_matcher->action_ste[1].stc; + resize_data->action_ste[1].rtc_0_id = src_matcher->action_ste[1].rtc_0_id; + resize_data->action_ste[1].rtc_1_id = src_matcher->action_ste[1].rtc_1_id; + resize_data->action_ste[1].pool = src_matcher->action_ste[1].max_stes ? + src_matcher->action_ste[1].pool : + NULL; + + /* Place the new resized matcher on the dst matcher's list */ + list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data); + + /* Move all the previous resized matchers to the dst matcher's list */ + while (!list_empty(&src_matcher->resize_data)) { + resize_data = list_first_entry(&src_matcher->resize_data, + struct mlx5hws_matcher_resize_data, + list_node); + list_del_init(&resize_data->list_node); + list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data); + } + + return 0; +} + +static void hws_matcher_resize_uninit(struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_matcher_resize_data *resize_data; + + if (!mlx5hws_matcher_is_resizable(matcher)) + return; + + while (!list_empty(&matcher->resize_data)) { + resize_data = list_first_entry(&matcher->resize_data, + struct mlx5hws_matcher_resize_data, + list_node); + list_del_init(&resize_data->list_node); + + if (resize_data->max_stes) { + mlx5hws_action_free_single_stc(matcher->tbl->ctx, + matcher->tbl->type, + &resize_data->action_ste[1].stc); + mlx5hws_action_free_single_stc(matcher->tbl->ctx, + matcher->tbl->type, + &resize_data->action_ste[0].stc); + + if (matcher->tbl->type == MLX5HWS_TABLE_TYPE_FDB) { + mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, + resize_data->action_ste[1].rtc_1_id); + mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, + resize_data->action_ste[0].rtc_1_id); + } + mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, + resize_data->action_ste[1].rtc_0_id); + mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, + resize_data->action_ste[0].rtc_0_id); + if (resize_data->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].pool) { + mlx5hws_pool_destroy(resize_data->action_ste[1].pool); + mlx5hws_pool_destroy(resize_data->action_ste[0].pool); + } + } + + kfree(resize_data); + } +} + +static int +hws_matcher_bind_at_idx(struct mlx5hws_matcher *matcher, u8 action_ste_selector) +{ + struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; + struct mlx5hws_matcher_action_ste *action_ste; + struct mlx5hws_table *tbl = matcher->tbl; + struct mlx5hws_pool_attr pool_attr = {0}; + struct mlx5hws_context *ctx = tbl->ctx; + int ret; + + action_ste = &matcher->action_ste[action_ste_selector]; + + /* Allocate action STE mempool */ + pool_attr.table_type = tbl->type; + pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; + pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL; + pool_attr.alloc_log_sz = ilog2(roundup_pow_of_two(action_ste->max_stes)) + + matcher->attr.table.sz_row_log; + hws_matcher_set_pool_attr(&pool_attr, matcher); + action_ste->pool = mlx5hws_pool_create(ctx, &pool_attr); + if (!action_ste->pool) { + mlx5hws_err(ctx, "Failed to create action ste pool\n"); + return -EINVAL; + } + + /* Allocate action RTC */ + ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector); + if (ret) { + mlx5hws_err(ctx, "Failed to create action RTC\n"); + goto free_ste_pool; + } + + /* Allocate STC for jumps to STE */ + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; + stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; + stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; + stc_attr.ste_table.ste = action_ste->ste; + stc_attr.ste_table.ste_pool = action_ste->pool; + stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; + + ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl->type, + &action_ste->stc); + if (ret) { + mlx5hws_err(ctx, "Failed to create action jump to table STC\n"); + goto free_rtc; + } + + return 0; + +free_rtc: + hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector); +free_ste_pool: + mlx5hws_pool_destroy(action_ste->pool); + return ret; +} + +static void hws_matcher_unbind_at_idx(struct mlx5hws_matcher *matcher, u8 action_ste_selector) +{ + struct mlx5hws_matcher_action_ste *action_ste; + struct mlx5hws_table *tbl = matcher->tbl; + + action_ste = &matcher->action_ste[action_ste_selector]; + + if (!action_ste->max_stes || + matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION || + mlx5hws_matcher_is_in_resize(matcher)) + return; + + mlx5hws_action_free_single_stc(tbl->ctx, tbl->type, &action_ste->stc); + hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector); + mlx5hws_pool_destroy(action_ste->pool); +} + +static int hws_matcher_bind_at(struct mlx5hws_matcher *matcher) +{ + bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt); + struct mlx5hws_table *tbl = matcher->tbl; + struct mlx5hws_context *ctx = tbl->ctx; + u32 required_stes; + u8 max_stes = 0; + int i, ret; + + if (matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION) + return 0; + + for (i = 0; i < matcher->num_of_at; i++) { + struct mlx5hws_action_template *at = &matcher->at[i]; + + ret = hws_matcher_check_and_process_at(matcher, at); + if (ret) { + mlx5hws_err(ctx, "Invalid at %d", i); + return ret; + } + + required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); + max_stes = max(max_stes, required_stes); + + /* Future: Optimize reparse */ + } + + /* There are no additional STEs required for matcher */ + if (!max_stes) + return 0; + + matcher->action_ste[0].max_stes = max_stes; + matcher->action_ste[1].max_stes = max_stes; + + ret = hws_matcher_bind_at_idx(matcher, 0); + if (ret) + return ret; + + ret = hws_matcher_bind_at_idx(matcher, 1); + if (ret) + goto free_at_0; + + return 0; + +free_at_0: + hws_matcher_unbind_at_idx(matcher, 0); + return ret; +} + +static void hws_matcher_unbind_at(struct mlx5hws_matcher *matcher) +{ + hws_matcher_unbind_at_idx(matcher, 1); + hws_matcher_unbind_at_idx(matcher, 0); +} + +static int hws_matcher_bind_mt(struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_context *ctx = matcher->tbl->ctx; + struct mlx5hws_pool_attr pool_attr = {0}; + int ret; + + /* Calculate match, range and hash definers */ + if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)) { + ret = mlx5hws_definer_mt_init(ctx, matcher->mt); + if (ret) { + if (ret == -E2BIG) + mlx5hws_err(ctx, "Failed to set matcher templates with match definers\n"); + return ret; + } + } + + /* Create an STE pool per matcher*/ + pool_attr.table_type = matcher->tbl->type; + pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; + pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL; + pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log + + matcher->attr.table.sz_row_log; + hws_matcher_set_pool_attr(&pool_attr, matcher); + + matcher->match_ste.pool = mlx5hws_pool_create(ctx, &pool_attr); + if (!matcher->match_ste.pool) { + mlx5hws_err(ctx, "Failed to allocate matcher STE pool\n"); + ret = -EOPNOTSUPP; + goto uninit_match_definer; + } + + return 0; + +uninit_match_definer: + if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)) + mlx5hws_definer_mt_uninit(ctx, matcher->mt); + return ret; +} + +static void hws_matcher_unbind_mt(struct mlx5hws_matcher *matcher) +{ + mlx5hws_pool_destroy(matcher->match_ste.pool); + if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)) + mlx5hws_definer_mt_uninit(matcher->tbl->ctx, matcher->mt); +} + +static int +hws_matcher_validate_insert_mode(struct mlx5hws_cmd_query_caps *caps, + struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_matcher_attr *attr = &matcher->attr; + struct mlx5hws_context *ctx = matcher->tbl->ctx; + + switch (attr->insert_mode) { + case MLX5HWS_MATCHER_INSERT_BY_HASH: + if (matcher->attr.distribute_mode != MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) { + mlx5hws_err(ctx, "Invalid matcher distribute mode\n"); + return -EOPNOTSUPP; + } + break; + + case MLX5HWS_MATCHER_INSERT_BY_INDEX: + if (attr->table.sz_col_log) { + mlx5hws_err(ctx, "Matcher with INSERT_BY_INDEX supports only Nx1 table size\n"); + return -EOPNOTSUPP; + } + + if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) { + /* Hash Split Table */ + if (!caps->rtc_hash_split_table) { + mlx5hws_err(ctx, "FW doesn't support insert by index and hash distribute\n"); + return -EOPNOTSUPP; + } + } else if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_LINEAR) { + /* Linear Lookup Table */ + if (!caps->rtc_linear_lookup_table || + !IS_BIT_SET(caps->access_index_mode, + MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR)) { + mlx5hws_err(ctx, "FW doesn't support insert by index and linear distribute\n"); + return -EOPNOTSUPP; + } + + if (attr->table.sz_row_log > MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX) { + mlx5hws_err(ctx, "Matcher with linear distribute: rows exceed limit %d", + MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX); + return -EOPNOTSUPP; + } + } else { + mlx5hws_err(ctx, "Matcher has unsupported distribute mode\n"); + return -EOPNOTSUPP; + } + break; + + default: + mlx5hws_err(ctx, "Matcher has unsupported insert mode\n"); + return -EOPNOTSUPP; + } + + return 0; +} + +static int +hws_matcher_process_attr(struct mlx5hws_cmd_query_caps *caps, + struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_matcher_attr *attr = &matcher->attr; + + if (hws_matcher_validate_insert_mode(caps, matcher)) + return -EOPNOTSUPP; + + if (matcher->tbl->type != MLX5HWS_TABLE_TYPE_FDB && attr->optimize_flow_src) { + mlx5hws_err(matcher->tbl->ctx, "NIC domain doesn't support flow_src\n"); + return -EOPNOTSUPP; + } + + /* Convert number of rules to the required depth */ + if (attr->mode == MLX5HWS_MATCHER_RESOURCE_MODE_RULE && + attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_HASH) + attr->table.sz_col_log = hws_matcher_rules_to_tbl_depth(attr->rule.num_log); + + matcher->flags |= attr->resizable ? MLX5HWS_MATCHER_FLAGS_RESIZABLE : 0; + + return hws_matcher_check_attr_sz(caps, matcher); +} + +static int hws_matcher_create_and_connect(struct mlx5hws_matcher *matcher) +{ + int ret; + + /* Select and create the definers for current matcher */ + ret = hws_matcher_bind_mt(matcher); + if (ret) + return ret; + + /* Calculate and verify action combination */ + ret = hws_matcher_bind_at(matcher); + if (ret) + goto unbind_mt; + + /* Create matcher end flow table anchor */ + ret = hws_matcher_create_end_ft(matcher); + if (ret) + goto unbind_at; + + /* Allocate the RTC for the new matcher */ + ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0); + if (ret) + goto destroy_end_ft; + + /* Connect the matcher to the matcher list */ + ret = hws_matcher_connect(matcher); + if (ret) + goto destroy_rtc; + + return 0; + +destroy_rtc: + hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0); +destroy_end_ft: + hws_matcher_destroy_end_ft(matcher); +unbind_at: + hws_matcher_unbind_at(matcher); +unbind_mt: + hws_matcher_unbind_mt(matcher); + return ret; +} + +static void hws_matcher_destroy_and_disconnect(struct mlx5hws_matcher *matcher) +{ + hws_matcher_resize_uninit(matcher); + hws_matcher_disconnect(matcher); + hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0); + hws_matcher_destroy_end_ft(matcher); + hws_matcher_unbind_at(matcher); + hws_matcher_unbind_mt(matcher); +} + +static int +hws_matcher_create_col_matcher(struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_context *ctx = matcher->tbl->ctx; + struct mlx5hws_matcher *col_matcher; + int ret; + + if (matcher->attr.mode != MLX5HWS_MATCHER_RESOURCE_MODE_RULE || + matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) + return 0; + + if (!hws_matcher_requires_col_tbl(matcher->attr.rule.num_log)) + return 0; + + col_matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); + if (!col_matcher) + return -ENOMEM; + + INIT_LIST_HEAD(&col_matcher->resize_data); + + col_matcher->tbl = matcher->tbl; + col_matcher->mt = matcher->mt; + col_matcher->at = matcher->at; + col_matcher->num_of_at = matcher->num_of_at; + col_matcher->num_of_mt = matcher->num_of_mt; + col_matcher->attr.priority = matcher->attr.priority; + col_matcher->flags = matcher->flags; + col_matcher->flags |= MLX5HWS_MATCHER_FLAGS_COLLISION; + col_matcher->attr.mode = MLX5HWS_MATCHER_RESOURCE_MODE_HTABLE; + col_matcher->attr.optimize_flow_src = matcher->attr.optimize_flow_src; + col_matcher->attr.table.sz_row_log = matcher->attr.rule.num_log; + col_matcher->attr.table.sz_col_log = MLX5HWS_MATCHER_ASSURED_COL_TBL_DEPTH; + if (col_matcher->attr.table.sz_row_log > MLX5HWS_MATCHER_ASSURED_ROW_RATIO) + col_matcher->attr.table.sz_row_log -= MLX5HWS_MATCHER_ASSURED_ROW_RATIO; + + col_matcher->attr.max_num_of_at_attach = matcher->attr.max_num_of_at_attach; + + ret = hws_matcher_process_attr(ctx->caps, col_matcher); + if (ret) + goto free_col_matcher; + + ret = hws_matcher_create_and_connect(col_matcher); + if (ret) + goto free_col_matcher; + + matcher->col_matcher = col_matcher; + + return 0; + +free_col_matcher: + kfree(col_matcher); + mlx5hws_err(ctx, "Failed to create assured collision matcher\n"); + return ret; +} + +static void +hws_matcher_destroy_col_matcher(struct mlx5hws_matcher *matcher) +{ + if (matcher->attr.mode != MLX5HWS_MATCHER_RESOURCE_MODE_RULE || + matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) + return; + + if (matcher->col_matcher) { + hws_matcher_destroy_and_disconnect(matcher->col_matcher); + kfree(matcher->col_matcher); + } +} + +static int hws_matcher_init(struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_context *ctx = matcher->tbl->ctx; + int ret; + + INIT_LIST_HEAD(&matcher->resize_data); + + mutex_lock(&ctx->ctrl_lock); + + /* Allocate matcher resource and connect to the packet pipe */ + ret = hws_matcher_create_and_connect(matcher); + if (ret) + goto unlock_err; + + /* Create additional matcher for collision handling */ + ret = hws_matcher_create_col_matcher(matcher); + if (ret) + goto destory_and_disconnect; + mutex_unlock(&ctx->ctrl_lock); + + return 0; + +destory_and_disconnect: + hws_matcher_destroy_and_disconnect(matcher); +unlock_err: + mutex_unlock(&ctx->ctrl_lock); + return ret; +} + +static int hws_matcher_uninit(struct mlx5hws_matcher *matcher) +{ + struct mlx5hws_context *ctx = matcher->tbl->ctx; + + mutex_lock(&ctx->ctrl_lock); + hws_matcher_destroy_col_matcher(matcher); + hws_matcher_destroy_and_disconnect(matcher); + mutex_unlock(&ctx->ctrl_lock); + + return 0; +} + +int mlx5hws_matcher_attach_at(struct mlx5hws_matcher *matcher, + struct mlx5hws_action_template *at) +{ + bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt); + struct mlx5hws_context *ctx = matcher->tbl->ctx; + u32 required_stes; + int ret; + + if (!matcher->attr.max_num_of_at_attach) { + mlx5hws_dbg(ctx, "Num of current at (%d) exceed allowed value\n", + matcher->num_of_at); + return -EOPNOTSUPP; + } + + ret = hws_matcher_check_and_process_at(matcher, at); + if (ret) + return ret; + + required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); + if (matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes < required_stes) { + mlx5hws_dbg(ctx, "Required STEs [%d] exceeds initial action template STE [%d]\n", + required_stes, + matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes); + return -ENOMEM; + } + + matcher->at[matcher->num_of_at] = *at; + matcher->num_of_at += 1; + matcher->attr.max_num_of_at_attach -= 1; + + if (matcher->col_matcher) + matcher->col_matcher->num_of_at = matcher->num_of_at; + + return 0; +} + +static int +hws_matcher_set_templates(struct mlx5hws_matcher *matcher, + struct mlx5hws_match_template *mt[], + u8 num_of_mt, + struct mlx5hws_action_template *at[], + u8 num_of_at) +{ + struct mlx5hws_context *ctx = matcher->tbl->ctx; + int ret = 0; + int i; + + if (!num_of_mt || !num_of_at) { + mlx5hws_err(ctx, "Number of action/match template cannot be zero\n"); + return -EOPNOTSUPP; + } + + matcher->mt = kcalloc(num_of_mt, sizeof(*matcher->mt), GFP_KERNEL); + if (!matcher->mt) + return -ENOMEM; + + matcher->at = kcalloc(num_of_at + matcher->attr.max_num_of_at_attach, + sizeof(*matcher->at), + GFP_KERNEL); + if (!matcher->at) { + mlx5hws_err(ctx, "Failed to allocate action template array\n"); + ret = -ENOMEM; + goto free_mt; + } + + for (i = 0; i < num_of_mt; i++) + matcher->mt[i] = *mt[i]; + + for (i = 0; i < num_of_at; i++) + matcher->at[i] = *at[i]; + + matcher->num_of_mt = num_of_mt; + matcher->num_of_at = num_of_at; + + return 0; + +free_mt: + kfree(matcher->mt); + return ret; +} + +static void +hws_matcher_unset_templates(struct mlx5hws_matcher *matcher) +{ + kfree(matcher->at); + kfree(matcher->mt); +} + +struct mlx5hws_matcher * +mlx5hws_matcher_create(struct mlx5hws_table *tbl, + struct mlx5hws_match_template *mt[], + u8 num_of_mt, + struct mlx5hws_action_template *at[], + u8 num_of_at, + struct mlx5hws_matcher_attr *attr) +{ + struct mlx5hws_context *ctx = tbl->ctx; + struct mlx5hws_matcher *matcher; + int ret; + + matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); + if (!matcher) + return NULL; + + matcher->tbl = tbl; + matcher->attr = *attr; + + ret = hws_matcher_process_attr(tbl->ctx->caps, matcher); + if (ret) + goto free_matcher; + + ret = hws_matcher_set_templates(matcher, mt, num_of_mt, at, num_of_at); + if (ret) + goto free_matcher; + + ret = hws_matcher_init(matcher); + if (ret) { + mlx5hws_err(ctx, "Failed to initialise matcher: %d\n", ret); + goto unset_templates; + } + + return matcher; + +unset_templates: + hws_matcher_unset_templates(matcher); +free_matcher: + kfree(matcher); + return NULL; +} + +int mlx5hws_matcher_destroy(struct mlx5hws_matcher *matcher) +{ + hws_matcher_uninit(matcher); + hws_matcher_unset_templates(matcher); + kfree(matcher); + return 0; +} + +struct mlx5hws_match_template * +mlx5hws_match_template_create(struct mlx5hws_context *ctx, + u32 *match_param, + u32 match_param_sz, + u8 match_criteria_enable) +{ + struct mlx5hws_match_template *mt; + + mt = kzalloc(sizeof(*mt), GFP_KERNEL); + if (!mt) + return NULL; + + mt->match_param = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); + if (!mt->match_param) + goto free_template; + + memcpy(mt->match_param, match_param, match_param_sz); + mt->match_criteria_enable = match_criteria_enable; + + return mt; + +free_template: + kfree(mt); + return NULL; +} + +int mlx5hws_match_template_destroy(struct mlx5hws_match_template *mt) +{ + kfree(mt->match_param); + kfree(mt); + return 0; +} + +static int hws_matcher_resize_precheck(struct mlx5hws_matcher *src_matcher, + struct mlx5hws_matcher *dst_matcher) +{ + struct mlx5hws_context *ctx = src_matcher->tbl->ctx; + int i; + + if (src_matcher->tbl->type != dst_matcher->tbl->type) { + mlx5hws_err(ctx, "Table type mismatch for src/dst matchers\n"); + return -EINVAL; + } + + if (!mlx5hws_matcher_is_resizable(src_matcher) || + !mlx5hws_matcher_is_resizable(dst_matcher)) { + mlx5hws_err(ctx, "Src/dst matcher is not resizable\n"); + return -EINVAL; + } + + if (mlx5hws_matcher_is_insert_by_idx(src_matcher) != + mlx5hws_matcher_is_insert_by_idx(dst_matcher)) { + mlx5hws_err(ctx, "Src/dst matchers insert mode mismatch\n"); + return -EINVAL; + } + + if (mlx5hws_matcher_is_in_resize(src_matcher) || + mlx5hws_matcher_is_in_resize(dst_matcher)) { + mlx5hws_err(ctx, "Src/dst matcher is already in resize\n"); + return -EINVAL; + } + + /* Compare match templates - make sure the definers are equivalent */ + if (src_matcher->num_of_mt != dst_matcher->num_of_mt) { + mlx5hws_err(ctx, "Src/dst matcher match templates mismatch\n"); + return -EINVAL; + } + + if (src_matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes > + dst_matcher->action_ste[0].max_stes) { + mlx5hws_err(ctx, "Src/dst matcher max STEs mismatch\n"); + return -EINVAL; + } + + for (i = 0; i < src_matcher->num_of_mt; i++) { + if (mlx5hws_definer_compare(src_matcher->mt[i].definer, + dst_matcher->mt[i].definer)) { + mlx5hws_err(ctx, "Src/dst matcher definers mismatch\n"); + return -EINVAL; + } + } + + return 0; +} + +int mlx5hws_matcher_resize_set_target(struct mlx5hws_matcher *src_matcher, + struct mlx5hws_matcher *dst_matcher) +{ + int ret = 0; + + mutex_lock(&src_matcher->tbl->ctx->ctrl_lock); + + ret = hws_matcher_resize_precheck(src_matcher, dst_matcher); + if (ret) + goto out; + + src_matcher->resize_dst = dst_matcher; + + ret = hws_matcher_resize_init(src_matcher); + if (ret) + src_matcher->resize_dst = NULL; + +out: + mutex_unlock(&src_matcher->tbl->ctx->ctrl_lock); + return ret; +} + +int mlx5hws_matcher_resize_rule_move(struct mlx5hws_matcher *src_matcher, + struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + struct mlx5hws_context *ctx = src_matcher->tbl->ctx; + + if (unlikely(!mlx5hws_matcher_is_in_resize(src_matcher))) { + mlx5hws_err(ctx, "Matcher is not resizable or not in resize\n"); + return -EINVAL; + } + + if (unlikely(src_matcher != rule->matcher)) { + mlx5hws_err(ctx, "Rule doesn't belong to src matcher\n"); + return -EINVAL; + } + + return mlx5hws_rule_move_hws_add(rule, attr); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h new file mode 100644 index 00000000000000..81ff487f57be4e --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef HWS_MATCHER_H_ +#define HWS_MATCHER_H_ + +/* We calculated that concatenating a collision table to the main table with + * 3% of the main table rows will be enough resources for high insertion + * success probability. + * + * The calculation: log2(2^x * 3 / 100) = log2(2^x) + log2(3/100) = x - 5.05 ~ 5 + */ +#define MLX5HWS_MATCHER_ASSURED_ROW_RATIO 5 +/* Threshold to determine if amount of rules require a collision table */ +#define MLX5HWS_MATCHER_ASSURED_RULES_TH 10 +/* Required depth of an assured collision table */ +#define MLX5HWS_MATCHER_ASSURED_COL_TBL_DEPTH 4 +/* Required depth of the main large table */ +#define MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH 2 + +enum mlx5hws_matcher_offset { + MLX5HWS_MATCHER_OFFSET_TAG_DW1 = 12, + MLX5HWS_MATCHER_OFFSET_TAG_DW0 = 13, +}; + +enum mlx5hws_matcher_flags { + MLX5HWS_MATCHER_FLAGS_COLLISION = 1 << 2, + MLX5HWS_MATCHER_FLAGS_RESIZABLE = 1 << 3, +}; + +struct mlx5hws_match_template { + struct mlx5hws_definer *definer; + struct mlx5hws_definer_fc *fc; + u32 *match_param; + u8 match_criteria_enable; + u16 fc_sz; +}; + +struct mlx5hws_matcher_match_ste { + struct mlx5hws_pool_chunk ste; + u32 rtc_0_id; + u32 rtc_1_id; + struct mlx5hws_pool *pool; +}; + +struct mlx5hws_matcher_action_ste { + struct mlx5hws_pool_chunk ste; + struct mlx5hws_pool_chunk stc; + u32 rtc_0_id; + u32 rtc_1_id; + struct mlx5hws_pool *pool; + u8 max_stes; +}; + +struct mlx5hws_matcher_resize_data_node { + struct mlx5hws_pool_chunk stc; + u32 rtc_0_id; + u32 rtc_1_id; + struct mlx5hws_pool *pool; +}; + +struct mlx5hws_matcher_resize_data { + struct mlx5hws_matcher_resize_data_node action_ste[2]; + u8 max_stes; + struct list_head list_node; +}; + +struct mlx5hws_matcher { + struct mlx5hws_table *tbl; + struct mlx5hws_matcher_attr attr; + struct mlx5hws_match_template *mt; + struct mlx5hws_action_template *at; + u8 num_of_at; + u8 num_of_mt; + /* enum mlx5hws_matcher_flags */ + u8 flags; + u32 end_ft_id; + struct mlx5hws_matcher *col_matcher; + struct mlx5hws_matcher *resize_dst; + struct mlx5hws_matcher_match_ste match_ste; + struct mlx5hws_matcher_action_ste action_ste[2]; + struct list_head list_node; + struct list_head resize_data; +}; + +static inline bool +mlx5hws_matcher_mt_is_jumbo(struct mlx5hws_match_template *mt) +{ + return mlx5hws_definer_is_jumbo(mt->definer); +} + +static inline bool mlx5hws_matcher_is_resizable(struct mlx5hws_matcher *matcher) +{ + return !!(matcher->flags & MLX5HWS_MATCHER_FLAGS_RESIZABLE); +} + +static inline bool mlx5hws_matcher_is_in_resize(struct mlx5hws_matcher *matcher) +{ + return !!matcher->resize_dst; +} + +static inline bool mlx5hws_matcher_is_insert_by_idx(struct mlx5hws_matcher *matcher) +{ + return matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX; +} + +#endif /* HWS_MATCHER_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c deleted file mode 100644 index b27bb41065326d..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.c +++ /dev/null @@ -1,2604 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -#define MLX5HWS_ACTION_METER_INIT_COLOR_OFFSET 1 - -/* Header removal size limited to 128B (64 words) */ -#define MLX5HWS_ACTION_REMOVE_HEADER_MAX_SIZE 128 - -/* This is the longest supported action sequence for FDB table: - * DECAP, POP_VLAN, MODIFY, CTR, ASO, PUSH_VLAN, MODIFY, ENCAP, Term. - */ -static const u32 action_order_arr[MLX5HWS_TABLE_TYPE_MAX][MLX5HWS_ACTION_TYP_MAX] = { - [MLX5HWS_TABLE_TYPE_FDB] = { - BIT(MLX5HWS_ACTION_TYP_REMOVE_HEADER) | - BIT(MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2) | - BIT(MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2), - BIT(MLX5HWS_ACTION_TYP_POP_VLAN), - BIT(MLX5HWS_ACTION_TYP_POP_VLAN), - BIT(MLX5HWS_ACTION_TYP_MODIFY_HDR), - BIT(MLX5HWS_ACTION_TYP_PUSH_VLAN), - BIT(MLX5HWS_ACTION_TYP_PUSH_VLAN), - BIT(MLX5HWS_ACTION_TYP_INSERT_HEADER) | - BIT(MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2) | - BIT(MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3), - BIT(MLX5HWS_ACTION_TYP_CTR), - BIT(MLX5HWS_ACTION_TYP_TAG), - BIT(MLX5HWS_ACTION_TYP_ASO_METER), - BIT(MLX5HWS_ACTION_TYP_MODIFY_HDR), - BIT(MLX5HWS_ACTION_TYP_TBL) | - BIT(MLX5HWS_ACTION_TYP_VPORT) | - BIT(MLX5HWS_ACTION_TYP_DROP) | - BIT(MLX5HWS_ACTION_TYP_SAMPLER) | - BIT(MLX5HWS_ACTION_TYP_RANGE) | - BIT(MLX5HWS_ACTION_TYP_DEST_ARRAY), - BIT(MLX5HWS_ACTION_TYP_LAST), - }, -}; - -static const char * const mlx5hws_action_type_str[] = { - [MLX5HWS_ACTION_TYP_LAST] = "LAST", - [MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2] = "TNL_L2_TO_L2", - [MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2] = "L2_TO_TNL_L2", - [MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2] = "TNL_L3_TO_L2", - [MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3] = "L2_TO_TNL_L3", - [MLX5HWS_ACTION_TYP_DROP] = "DROP", - [MLX5HWS_ACTION_TYP_TBL] = "TBL", - [MLX5HWS_ACTION_TYP_CTR] = "CTR", - [MLX5HWS_ACTION_TYP_TAG] = "TAG", - [MLX5HWS_ACTION_TYP_MODIFY_HDR] = "MODIFY_HDR", - [MLX5HWS_ACTION_TYP_VPORT] = "VPORT", - [MLX5HWS_ACTION_TYP_MISS] = "DEFAULT_MISS", - [MLX5HWS_ACTION_TYP_POP_VLAN] = "POP_VLAN", - [MLX5HWS_ACTION_TYP_PUSH_VLAN] = "PUSH_VLAN", - [MLX5HWS_ACTION_TYP_ASO_METER] = "ASO_METER", - [MLX5HWS_ACTION_TYP_DEST_ARRAY] = "DEST_ARRAY", - [MLX5HWS_ACTION_TYP_INSERT_HEADER] = "INSERT_HEADER", - [MLX5HWS_ACTION_TYP_REMOVE_HEADER] = "REMOVE_HEADER", - [MLX5HWS_ACTION_TYP_SAMPLER] = "SAMPLER", - [MLX5HWS_ACTION_TYP_RANGE] = "RANGE", -}; - -static_assert(ARRAY_SIZE(mlx5hws_action_type_str) == MLX5HWS_ACTION_TYP_MAX, - "Missing mlx5hws_action_type_str"); - -const char *mlx5hws_action_type_to_str(enum mlx5hws_action_type action_type) -{ - return mlx5hws_action_type_str[action_type]; -} - -enum mlx5hws_action_type mlx5hws_action_get_type(struct mlx5hws_action *action) -{ - return action->type; -} - -static int hws_action_get_shared_stc_nic(struct mlx5hws_context *ctx, - enum mlx5hws_context_shared_stc_type stc_type, - u8 tbl_type) -{ - struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; - struct mlx5hws_action_shared_stc *shared_stc; - int ret; - - mutex_lock(&ctx->ctrl_lock); - if (ctx->common_res[tbl_type].shared_stc[stc_type]) { - ctx->common_res[tbl_type].shared_stc[stc_type]->refcount++; - mutex_unlock(&ctx->ctrl_lock); - return 0; - } - - shared_stc = kzalloc(sizeof(*shared_stc), GFP_KERNEL); - if (!shared_stc) { - ret = -ENOMEM; - goto unlock_and_out; - } - switch (stc_type) { - case MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3: - stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW5; - stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; - stc_attr.remove_header.decap = 0; - stc_attr.remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START; - stc_attr.remove_header.end_anchor = MLX5_HEADER_ANCHOR_IPV6_IPV4; - break; - case MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP: - stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW5; - stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; - stc_attr.remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START; - stc_attr.remove_words.num_of_words = MLX5HWS_ACTION_HDR_LEN_L2_VLAN; - break; - default: - mlx5hws_err(ctx, "No such stc_type: %d\n", stc_type); - pr_warn("HWS: Invalid stc_type: %d\n", stc_type); - ret = -EINVAL; - goto unlock_and_out; - } - - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, - &shared_stc->stc_chunk); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate shared decap l2 STC\n"); - goto free_shared_stc; - } - - ctx->common_res[tbl_type].shared_stc[stc_type] = shared_stc; - ctx->common_res[tbl_type].shared_stc[stc_type]->refcount = 1; - - mutex_unlock(&ctx->ctrl_lock); - - return 0; - -free_shared_stc: - kfree(shared_stc); -unlock_and_out: - mutex_unlock(&ctx->ctrl_lock); - return ret; -} - -static int hws_action_get_shared_stc(struct mlx5hws_action *action, - enum mlx5hws_context_shared_stc_type stc_type) -{ - struct mlx5hws_context *ctx = action->ctx; - int ret; - - if (stc_type >= MLX5HWS_CONTEXT_SHARED_STC_MAX) { - pr_warn("HWS: Invalid shared stc_type: %d\n", stc_type); - return -EINVAL; - } - - if (unlikely(!(action->flags & MLX5HWS_ACTION_FLAG_HWS_FDB))) { - pr_warn("HWS: Invalid action->flags: %d\n", action->flags); - return -EINVAL; - } - - ret = hws_action_get_shared_stc_nic(ctx, stc_type, MLX5HWS_TABLE_TYPE_FDB); - if (ret) { - mlx5hws_err(ctx, - "Failed to allocate memory for FDB shared STCs (type: %d)\n", - stc_type); - return ret; - } - - return 0; -} - -static void hws_action_put_shared_stc(struct mlx5hws_action *action, - enum mlx5hws_context_shared_stc_type stc_type) -{ - enum mlx5hws_table_type tbl_type = MLX5HWS_TABLE_TYPE_FDB; - struct mlx5hws_action_shared_stc *shared_stc; - struct mlx5hws_context *ctx = action->ctx; - - if (stc_type >= MLX5HWS_CONTEXT_SHARED_STC_MAX) { - pr_warn("HWS: Invalid shared stc_type: %d\n", stc_type); - return; - } - - mutex_lock(&ctx->ctrl_lock); - if (--ctx->common_res[tbl_type].shared_stc[stc_type]->refcount) { - mutex_unlock(&ctx->ctrl_lock); - return; - } - - shared_stc = ctx->common_res[tbl_type].shared_stc[stc_type]; - - mlx5hws_action_free_single_stc(ctx, tbl_type, &shared_stc->stc_chunk); - kfree(shared_stc); - ctx->common_res[tbl_type].shared_stc[stc_type] = NULL; - mutex_unlock(&ctx->ctrl_lock); -} - -static void hws_action_print_combo(struct mlx5hws_context *ctx, - enum mlx5hws_action_type *user_actions) -{ - mlx5hws_err(ctx, "Invalid action_type sequence"); - while (*user_actions != MLX5HWS_ACTION_TYP_LAST) { - mlx5hws_err(ctx, " %s", mlx5hws_action_type_to_str(*user_actions)); - user_actions++; - } - mlx5hws_err(ctx, "\n"); -} - -bool mlx5hws_action_check_combo(struct mlx5hws_context *ctx, - enum mlx5hws_action_type *user_actions, - enum mlx5hws_table_type table_type) -{ - const u32 *order_arr = action_order_arr[table_type]; - u8 order_idx = 0; - u8 user_idx = 0; - bool valid_combo; - - if (table_type >= MLX5HWS_TABLE_TYPE_MAX) { - mlx5hws_err(ctx, "Invalid table_type %d", table_type); - return false; - } - - while (order_arr[order_idx] != BIT(MLX5HWS_ACTION_TYP_LAST)) { - /* User action order validated move to next user action */ - if (BIT(user_actions[user_idx]) & order_arr[order_idx]) - user_idx++; - - /* Iterate to the next supported action in the order */ - order_idx++; - } - - /* Combination is valid if all user action were processed */ - valid_combo = user_actions[user_idx] == MLX5HWS_ACTION_TYP_LAST; - if (!valid_combo) - hws_action_print_combo(ctx, user_actions); - - return valid_combo; -} - -static bool -hws_action_fixup_stc_attr(struct mlx5hws_context *ctx, - struct mlx5hws_cmd_stc_modify_attr *stc_attr, - struct mlx5hws_cmd_stc_modify_attr *fixup_stc_attr, - enum mlx5hws_table_type table_type, - bool is_mirror) -{ - bool use_fixup = false; - u32 fw_tbl_type; - u32 base_id; - - fw_tbl_type = mlx5hws_table_get_res_fw_ft_type(table_type, is_mirror); - - switch (stc_attr->action_type) { - case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE: - if (is_mirror && stc_attr->ste_table.ignore_tx) { - fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; - fixup_stc_attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; - fixup_stc_attr->stc_offset = stc_attr->stc_offset; - use_fixup = true; - break; - } - if (!is_mirror) - base_id = mlx5hws_pool_chunk_get_base_id(stc_attr->ste_table.ste_pool, - &stc_attr->ste_table.ste); - else - base_id = - mlx5hws_pool_chunk_get_base_mirror_id(stc_attr->ste_table.ste_pool, - &stc_attr->ste_table.ste); - - *fixup_stc_attr = *stc_attr; - fixup_stc_attr->ste_table.ste_obj_id = base_id; - use_fixup = true; - break; - - case MLX5_IFC_STC_ACTION_TYPE_TAG: - if (fw_tbl_type == FS_FT_FDB_TX) { - fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_NOP; - fixup_stc_attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; - fixup_stc_attr->stc_offset = stc_attr->stc_offset; - use_fixup = true; - } - break; - - case MLX5_IFC_STC_ACTION_TYPE_ALLOW: - if (fw_tbl_type == FS_FT_FDB_TX || fw_tbl_type == FS_FT_FDB_RX) { - fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT; - fixup_stc_attr->action_offset = stc_attr->action_offset; - fixup_stc_attr->stc_offset = stc_attr->stc_offset; - fixup_stc_attr->vport.esw_owner_vhca_id = ctx->caps->vhca_id; - fixup_stc_attr->vport.vport_num = ctx->caps->eswitch_manager_vport_number; - fixup_stc_attr->vport.eswitch_owner_vhca_id_valid = - ctx->caps->merged_eswitch; - use_fixup = true; - } - break; - - case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT: - if (stc_attr->vport.vport_num != MLX5_VPORT_UPLINK) - break; - - if (fw_tbl_type == FS_FT_FDB_TX || fw_tbl_type == FS_FT_FDB_RX) { - /* The FW doesn't allow to go to wire in the TX/RX by JUMP_TO_VPORT */ - fixup_stc_attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK; - fixup_stc_attr->action_offset = stc_attr->action_offset; - fixup_stc_attr->stc_offset = stc_attr->stc_offset; - fixup_stc_attr->vport.vport_num = 0; - fixup_stc_attr->vport.esw_owner_vhca_id = stc_attr->vport.esw_owner_vhca_id; - fixup_stc_attr->vport.eswitch_owner_vhca_id_valid = - stc_attr->vport.eswitch_owner_vhca_id_valid; - } - use_fixup = true; - break; - - default: - break; - } - - return use_fixup; -} - -int mlx5hws_action_alloc_single_stc(struct mlx5hws_context *ctx, - struct mlx5hws_cmd_stc_modify_attr *stc_attr, - u32 table_type, - struct mlx5hws_pool_chunk *stc) -__must_hold(&ctx->ctrl_lock) -{ - struct mlx5hws_cmd_stc_modify_attr cleanup_stc_attr = {0}; - struct mlx5hws_pool *stc_pool = ctx->stc_pool[table_type]; - struct mlx5hws_cmd_stc_modify_attr fixup_stc_attr = {0}; - bool use_fixup; - u32 obj_0_id; - int ret; - - ret = mlx5hws_pool_chunk_alloc(stc_pool, stc); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate single action STC\n"); - return ret; - } - - stc_attr->stc_offset = stc->offset; - - /* Dynamic reparse not supported, overwrite and use default */ - if (!mlx5hws_context_cap_dynamic_reparse(ctx)) - stc_attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; - - obj_0_id = mlx5hws_pool_chunk_get_base_id(stc_pool, stc); - - /* According to table/action limitation change the stc_attr */ - use_fixup = hws_action_fixup_stc_attr(ctx, stc_attr, &fixup_stc_attr, table_type, false); - ret = mlx5hws_cmd_stc_modify(ctx->mdev, obj_0_id, - use_fixup ? &fixup_stc_attr : stc_attr); - if (ret) { - mlx5hws_err(ctx, "Failed to modify STC action_type %d tbl_type %d\n", - stc_attr->action_type, table_type); - goto free_chunk; - } - - /* Modify the FDB peer */ - if (table_type == MLX5HWS_TABLE_TYPE_FDB) { - u32 obj_1_id; - - obj_1_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, stc); - - use_fixup = hws_action_fixup_stc_attr(ctx, stc_attr, - &fixup_stc_attr, - table_type, true); - ret = mlx5hws_cmd_stc_modify(ctx->mdev, obj_1_id, - use_fixup ? &fixup_stc_attr : stc_attr); - if (ret) { - mlx5hws_err(ctx, - "Failed to modify peer STC action_type %d tbl_type %d\n", - stc_attr->action_type, table_type); - goto clean_obj_0; - } - } - - return 0; - -clean_obj_0: - cleanup_stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; - cleanup_stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; - cleanup_stc_attr.stc_offset = stc->offset; - mlx5hws_cmd_stc_modify(ctx->mdev, obj_0_id, &cleanup_stc_attr); -free_chunk: - mlx5hws_pool_chunk_free(stc_pool, stc); - return ret; -} - -void mlx5hws_action_free_single_stc(struct mlx5hws_context *ctx, - u32 table_type, - struct mlx5hws_pool_chunk *stc) -__must_hold(&ctx->ctrl_lock) -{ - struct mlx5hws_pool *stc_pool = ctx->stc_pool[table_type]; - struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; - u32 obj_id; - - /* Modify the STC not to point to an object */ - stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; - stc_attr.stc_offset = stc->offset; - obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, stc); - mlx5hws_cmd_stc_modify(ctx->mdev, obj_id, &stc_attr); - - if (table_type == MLX5HWS_TABLE_TYPE_FDB) { - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, stc); - mlx5hws_cmd_stc_modify(ctx->mdev, obj_id, &stc_attr); - } - - mlx5hws_pool_chunk_free(stc_pool, stc); -} - -static u32 hws_action_get_mh_stc_type(struct mlx5hws_context *ctx, - __be64 pattern) -{ - u8 action_type = MLX5_GET(set_action_in, &pattern, action_type); - - switch (action_type) { - case MLX5_MODIFICATION_TYPE_SET: - return MLX5_IFC_STC_ACTION_TYPE_SET; - case MLX5_MODIFICATION_TYPE_ADD: - return MLX5_IFC_STC_ACTION_TYPE_ADD; - case MLX5_MODIFICATION_TYPE_COPY: - return MLX5_IFC_STC_ACTION_TYPE_COPY; - case MLX5_MODIFICATION_TYPE_ADD_FIELD: - return MLX5_IFC_STC_ACTION_TYPE_ADD_FIELD; - default: - mlx5hws_err(ctx, "Unsupported action type: 0x%x\n", action_type); - return MLX5_IFC_STC_ACTION_TYPE_NOP; - } -} - -static void hws_action_fill_stc_attr(struct mlx5hws_action *action, - u32 obj_id, - struct mlx5hws_cmd_stc_modify_attr *attr) -{ - attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; - - switch (action->type) { - case MLX5HWS_ACTION_TYP_TAG: - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_TAG; - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; - break; - case MLX5HWS_ACTION_TYP_DROP: - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; - attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; - break; - case MLX5HWS_ACTION_TYP_MISS: - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW; - attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; - break; - case MLX5HWS_ACTION_TYP_CTR: - attr->id = obj_id; - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_COUNTER; - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW0; - break; - case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: - case MLX5HWS_ACTION_TYP_MODIFY_HDR: - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW6; - attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; - if (action->modify_header.require_reparse) - attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; - - if (action->modify_header.num_of_actions == 1) { - attr->modify_action.data = action->modify_header.single_action; - attr->action_type = hws_action_get_mh_stc_type(action->ctx, - attr->modify_action.data); - - if (attr->action_type == MLX5_IFC_STC_ACTION_TYPE_ADD || - attr->action_type == MLX5_IFC_STC_ACTION_TYPE_SET) - MLX5_SET(set_action_in, &attr->modify_action.data, data, 0); - } else { - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST; - attr->modify_header.arg_id = action->modify_header.arg_id; - attr->modify_header.pattern_id = action->modify_header.pat_id; - } - break; - case MLX5HWS_ACTION_TYP_TBL: - case MLX5HWS_ACTION_TYP_DEST_ARRAY: - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT; - attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; - attr->dest_table_id = obj_id; - break; - case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE; - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; - attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; - attr->remove_header.decap = 1; - attr->remove_header.start_anchor = MLX5_HEADER_ANCHOR_PACKET_START; - attr->remove_header.end_anchor = MLX5_HEADER_ANCHOR_INNER_MAC; - break; - case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: - case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: - case MLX5HWS_ACTION_TYP_INSERT_HEADER: - attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; - if (!action->reformat.require_reparse) - attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; - - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW6; - attr->insert_header.encap = action->reformat.encap; - attr->insert_header.insert_anchor = action->reformat.anchor; - attr->insert_header.arg_id = action->reformat.arg_id; - attr->insert_header.header_size = action->reformat.header_size; - attr->insert_header.insert_offset = action->reformat.offset; - break; - case MLX5HWS_ACTION_TYP_ASO_METER: - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW6; - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ASO; - attr->aso.aso_type = ASO_OPC_MOD_POLICER; - attr->aso.devx_obj_id = obj_id; - attr->aso.return_reg_id = action->aso.return_reg_id; - break; - case MLX5HWS_ACTION_TYP_VPORT: - attr->action_offset = MLX5HWS_ACTION_OFFSET_HIT; - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT; - attr->vport.vport_num = action->vport.vport_num; - attr->vport.esw_owner_vhca_id = action->vport.esw_owner_vhca_id; - attr->vport.eswitch_owner_vhca_id_valid = action->vport.esw_owner_vhca_id_valid; - break; - case MLX5HWS_ACTION_TYP_POP_VLAN: - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; - attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; - attr->remove_words.start_anchor = MLX5_HEADER_ANCHOR_FIRST_VLAN_START; - attr->remove_words.num_of_words = MLX5HWS_ACTION_HDR_LEN_L2_VLAN / 2; - break; - case MLX5HWS_ACTION_TYP_PUSH_VLAN: - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT; - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW6; - attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; - attr->insert_header.encap = 0; - attr->insert_header.is_inline = 1; - attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START; - attr->insert_header.insert_offset = MLX5HWS_ACTION_HDR_LEN_L2_MACS; - attr->insert_header.header_size = MLX5HWS_ACTION_HDR_LEN_L2_VLAN; - break; - case MLX5HWS_ACTION_TYP_REMOVE_HEADER: - attr->action_type = MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS; - attr->remove_header.decap = 0; /* the mode we support decap is 0 */ - attr->remove_words.start_anchor = action->remove_header.anchor; - /* the size is in already in words */ - attr->remove_words.num_of_words = action->remove_header.size; - attr->action_offset = MLX5HWS_ACTION_OFFSET_DW5; - attr->reparse_mode = MLX5_IFC_STC_REPARSE_ALWAYS; - break; - default: - mlx5hws_err(action->ctx, "Invalid action type %d\n", action->type); - } -} - -static int -hws_action_create_stcs(struct mlx5hws_action *action, u32 obj_id) -{ - struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; - struct mlx5hws_context *ctx = action->ctx; - int ret; - - hws_action_fill_stc_attr(action, obj_id, &stc_attr); - - /* Block unsupported parallel obj modify over the same base */ - mutex_lock(&ctx->ctrl_lock); - - /* Allocate STC for FDB */ - if (action->flags & MLX5HWS_ACTION_FLAG_HWS_FDB) { - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, - MLX5HWS_TABLE_TYPE_FDB, - &action->stc[MLX5HWS_TABLE_TYPE_FDB]); - if (ret) - goto out_err; - } - - mutex_unlock(&ctx->ctrl_lock); - - return 0; - -out_err: - mutex_unlock(&ctx->ctrl_lock); - return ret; -} - -static void -hws_action_destroy_stcs(struct mlx5hws_action *action) -{ - struct mlx5hws_context *ctx = action->ctx; - - /* Block unsupported parallel obj modify over the same base */ - mutex_lock(&ctx->ctrl_lock); - - if (action->flags & MLX5HWS_ACTION_FLAG_HWS_FDB) - mlx5hws_action_free_single_stc(ctx, MLX5HWS_TABLE_TYPE_FDB, - &action->stc[MLX5HWS_TABLE_TYPE_FDB]); - - mutex_unlock(&ctx->ctrl_lock); -} - -static bool hws_action_is_flag_hws_fdb(u32 flags) -{ - return flags & MLX5HWS_ACTION_FLAG_HWS_FDB; -} - -static bool -hws_action_validate_hws_action(struct mlx5hws_context *ctx, u32 flags) -{ - if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) { - mlx5hws_err(ctx, "Cannot create HWS action since HWS is not supported\n"); - return false; - } - - if ((flags & MLX5HWS_ACTION_FLAG_HWS_FDB) && !ctx->caps->eswitch_manager) { - mlx5hws_err(ctx, "Cannot create HWS action for FDB for non-eswitch-manager\n"); - return false; - } - - return true; -} - -static struct mlx5hws_action * -hws_action_create_generic_bulk(struct mlx5hws_context *ctx, - u32 flags, - enum mlx5hws_action_type action_type, - u8 bulk_sz) -{ - struct mlx5hws_action *action; - int i; - - if (!hws_action_is_flag_hws_fdb(flags)) { - mlx5hws_err(ctx, - "Action (type: %d) flags must specify only HWS FDB\n", action_type); - return NULL; - } - - if (!hws_action_validate_hws_action(ctx, flags)) - return NULL; - - action = kcalloc(bulk_sz, sizeof(*action), GFP_KERNEL); - if (!action) - return NULL; - - for (i = 0; i < bulk_sz; i++) { - action[i].ctx = ctx; - action[i].flags = flags; - action[i].type = action_type; - } - - return action; -} - -static struct mlx5hws_action * -hws_action_create_generic(struct mlx5hws_context *ctx, - u32 flags, - enum mlx5hws_action_type action_type) -{ - return hws_action_create_generic_bulk(ctx, flags, action_type, 1); -} - -struct mlx5hws_action * -mlx5hws_action_create_dest_table_num(struct mlx5hws_context *ctx, - u32 table_id, - u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_TBL); - if (!action) - return NULL; - - ret = hws_action_create_stcs(action, table_id); - if (ret) - goto free_action; - - action->dest_obj.obj_id = table_id; - - return action; - -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_dest_table(struct mlx5hws_context *ctx, - struct mlx5hws_table *tbl, - u32 flags) -{ - return mlx5hws_action_create_dest_table_num(ctx, tbl->ft_id, flags); -} - -struct mlx5hws_action * -mlx5hws_action_create_dest_drop(struct mlx5hws_context *ctx, u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_DROP); - if (!action) - return NULL; - - ret = hws_action_create_stcs(action, 0); - if (ret) - goto free_action; - - return action; - -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_default_miss(struct mlx5hws_context *ctx, u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_MISS); - if (!action) - return NULL; - - ret = hws_action_create_stcs(action, 0); - if (ret) - goto free_action; - - return action; - -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_tag(struct mlx5hws_context *ctx, u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_TAG); - if (!action) - return NULL; - - ret = hws_action_create_stcs(action, 0); - if (ret) - goto free_action; - - return action; - -free_action: - kfree(action); - return NULL; -} - -static struct mlx5hws_action * -hws_action_create_aso(struct mlx5hws_context *ctx, - enum mlx5hws_action_type action_type, - u32 obj_id, - u8 return_reg_id, - u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - action = hws_action_create_generic(ctx, flags, action_type); - if (!action) - return NULL; - - action->aso.obj_id = obj_id; - action->aso.return_reg_id = return_reg_id; - - ret = hws_action_create_stcs(action, obj_id); - if (ret) - goto free_action; - - return action; - -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_aso_meter(struct mlx5hws_context *ctx, - u32 obj_id, - u8 return_reg_id, - u32 flags) -{ - return hws_action_create_aso(ctx, MLX5HWS_ACTION_TYP_ASO_METER, - obj_id, return_reg_id, flags); -} - -struct mlx5hws_action * -mlx5hws_action_create_counter(struct mlx5hws_context *ctx, - u32 obj_id, - u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_CTR); - if (!action) - return NULL; - - ret = hws_action_create_stcs(action, obj_id); - if (ret) - goto free_action; - - return action; - -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_dest_vport(struct mlx5hws_context *ctx, - u16 vport_num, - bool vhca_id_valid, - u16 vhca_id, - u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - if (!(flags & MLX5HWS_ACTION_FLAG_HWS_FDB)) { - mlx5hws_err(ctx, "Vport action is supported for FDB only\n"); - return NULL; - } - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_VPORT); - if (!action) - return NULL; - - if (!ctx->caps->merged_eswitch && vhca_id_valid && vhca_id != ctx->caps->vhca_id) { - mlx5hws_err(ctx, "Non merged eswitch cannot send to other vhca\n"); - goto free_action; - } - - action->vport.vport_num = vport_num; - action->vport.esw_owner_vhca_id_valid = vhca_id_valid; - - if (vhca_id_valid) - action->vport.esw_owner_vhca_id = vhca_id; - - ret = hws_action_create_stcs(action, 0); - if (ret) { - mlx5hws_err(ctx, "Failed creating stc for vport %d\n", vport_num); - goto free_action; - } - - return action; - -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_push_vlan(struct mlx5hws_context *ctx, u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_PUSH_VLAN); - if (!action) - return NULL; - - ret = hws_action_create_stcs(action, 0); - if (ret) { - mlx5hws_err(ctx, "Failed creating stc for push vlan\n"); - goto free_action; - } - - return action; - -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_pop_vlan(struct mlx5hws_context *ctx, u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_POP_VLAN); - if (!action) - return NULL; - - ret = hws_action_get_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP); - if (ret) { - mlx5hws_err(ctx, "Failed to create remove stc for reformat\n"); - goto free_action; - } - - ret = hws_action_create_stcs(action, 0); - if (ret) { - mlx5hws_err(ctx, "Failed creating stc for pop vlan\n"); - goto free_shared; - } - - return action; - -free_shared: - hws_action_put_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP); -free_action: - kfree(action); - return NULL; -} - -static int -hws_action_handle_insert_with_ptr(struct mlx5hws_action *action, - u8 num_of_hdrs, - struct mlx5hws_action_reformat_header *hdrs, - u32 log_bulk_sz) -{ - size_t max_sz = 0; - u32 arg_id; - int ret, i; - - for (i = 0; i < num_of_hdrs; i++) { - if (hdrs[i].sz % W_SIZE != 0) { - mlx5hws_err(action->ctx, - "Header data size should be in WORD granularity\n"); - return -EINVAL; - } - max_sz = max(hdrs[i].sz, max_sz); - } - - /* Allocate single shared arg object for all headers */ - ret = mlx5hws_arg_create(action->ctx, - hdrs->data, - max_sz, - log_bulk_sz, - action->flags & MLX5HWS_ACTION_FLAG_SHARED, - &arg_id); - if (ret) - return ret; - - for (i = 0; i < num_of_hdrs; i++) { - action[i].reformat.arg_id = arg_id; - action[i].reformat.header_size = hdrs[i].sz; - action[i].reformat.num_of_hdrs = num_of_hdrs; - action[i].reformat.max_hdr_sz = max_sz; - action[i].reformat.require_reparse = true; - - if (action[i].type == MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2 || - action[i].type == MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3) { - action[i].reformat.anchor = MLX5_HEADER_ANCHOR_PACKET_START; - action[i].reformat.offset = 0; - action[i].reformat.encap = 1; - } - - ret = hws_action_create_stcs(&action[i], 0); - if (ret) { - mlx5hws_err(action->ctx, "Failed to create stc for reformat\n"); - goto free_stc; - } - } - - return 0; - -free_stc: - while (i--) - hws_action_destroy_stcs(&action[i]); - - mlx5hws_arg_destroy(action->ctx, arg_id); - return ret; -} - -static int -hws_action_handle_l2_to_tunnel_l3(struct mlx5hws_action *action, - u8 num_of_hdrs, - struct mlx5hws_action_reformat_header *hdrs, - u32 log_bulk_sz) -{ - int ret; - - /* The action is remove-l2-header + insert-l3-header */ - ret = hws_action_get_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3); - if (ret) { - mlx5hws_err(action->ctx, "Failed to create remove stc for reformat\n"); - return ret; - } - - /* Reuse the insert with pointer for the L2L3 header */ - ret = hws_action_handle_insert_with_ptr(action, - num_of_hdrs, - hdrs, - log_bulk_sz); - if (ret) - goto put_shared_stc; - - return 0; - -put_shared_stc: - hws_action_put_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3); - return ret; -} - -static void hws_action_prepare_decap_l3_actions(size_t data_sz, - u8 *mh_data, - int *num_of_actions) -{ - int actions; - u32 i; - - /* Remove L2L3 outer headers */ - MLX5_SET(stc_ste_param_remove, mh_data, action_type, - MLX5_MODIFICATION_TYPE_REMOVE); - MLX5_SET(stc_ste_param_remove, mh_data, decap, 0x1); - MLX5_SET(stc_ste_param_remove, mh_data, remove_start_anchor, - MLX5_HEADER_ANCHOR_PACKET_START); - MLX5_SET(stc_ste_param_remove, mh_data, remove_end_anchor, - MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4); - mh_data += MLX5HWS_ACTION_DOUBLE_SIZE; /* Assume every action is 2 dw */ - actions = 1; - - /* Add the new header using inline action 4Byte at a time, the header - * is added in reversed order to the beginning of the packet to avoid - * incorrect parsing by the HW. Since header is 14B or 18B an extra - * two bytes are padded and later removed. - */ - for (i = 0; i < data_sz / MLX5HWS_ACTION_INLINE_DATA_SIZE + 1; i++) { - MLX5_SET(stc_ste_param_insert, mh_data, action_type, - MLX5_MODIFICATION_TYPE_INSERT); - MLX5_SET(stc_ste_param_insert, mh_data, inline_data, 0x1); - MLX5_SET(stc_ste_param_insert, mh_data, insert_anchor, - MLX5_HEADER_ANCHOR_PACKET_START); - MLX5_SET(stc_ste_param_insert, mh_data, insert_size, 2); - mh_data += MLX5HWS_ACTION_DOUBLE_SIZE; - actions++; - } - - /* Remove first 2 extra bytes */ - MLX5_SET(stc_ste_param_remove_words, mh_data, action_type, - MLX5_MODIFICATION_TYPE_REMOVE_WORDS); - MLX5_SET(stc_ste_param_remove_words, mh_data, remove_start_anchor, - MLX5_HEADER_ANCHOR_PACKET_START); - /* The hardware expects here size in words (2 bytes) */ - MLX5_SET(stc_ste_param_remove_words, mh_data, remove_size, 1); - actions++; - - *num_of_actions = actions; -} - -static int -hws_action_handle_tunnel_l3_to_l2(struct mlx5hws_action *action, - u8 num_of_hdrs, - struct mlx5hws_action_reformat_header *hdrs, - u32 log_bulk_sz) -{ - u8 mh_data[MLX5HWS_ACTION_REFORMAT_DATA_SIZE] = {0}; - struct mlx5hws_context *ctx = action->ctx; - u32 arg_id, pat_id; - int num_of_actions; - int mh_data_size; - int ret, i; - - for (i = 0; i < num_of_hdrs; i++) { - if (hdrs[i].sz != MLX5HWS_ACTION_HDR_LEN_L2 && - hdrs[i].sz != MLX5HWS_ACTION_HDR_LEN_L2_W_VLAN) { - mlx5hws_err(ctx, "Data size is not supported for decap-l3\n"); - return -EINVAL; - } - } - - /* Create a full modify header action list in case shared */ - hws_action_prepare_decap_l3_actions(hdrs->sz, mh_data, &num_of_actions); - if (action->flags & MLX5HWS_ACTION_FLAG_SHARED) - mlx5hws_action_prepare_decap_l3_data(hdrs->data, mh_data, num_of_actions); - - /* All DecapL3 cases require the same max arg size */ - ret = mlx5hws_arg_create_modify_header_arg(ctx, - (__be64 *)mh_data, - num_of_actions, - log_bulk_sz, - action->flags & MLX5HWS_ACTION_FLAG_SHARED, - &arg_id); - if (ret) - return ret; - - for (i = 0; i < num_of_hdrs; i++) { - memset(mh_data, 0, MLX5HWS_ACTION_REFORMAT_DATA_SIZE); - hws_action_prepare_decap_l3_actions(hdrs[i].sz, mh_data, &num_of_actions); - mh_data_size = num_of_actions * MLX5HWS_MODIFY_ACTION_SIZE; - - ret = mlx5hws_pat_get_pattern(ctx, (__be64 *)mh_data, mh_data_size, &pat_id); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate pattern for DecapL3\n"); - goto free_stc_and_pat; - } - - action[i].modify_header.max_num_of_actions = num_of_actions; - action[i].modify_header.num_of_actions = num_of_actions; - action[i].modify_header.num_of_patterns = num_of_hdrs; - action[i].modify_header.arg_id = arg_id; - action[i].modify_header.pat_id = pat_id; - action[i].modify_header.require_reparse = - mlx5hws_pat_require_reparse((__be64 *)mh_data, num_of_actions); - - ret = hws_action_create_stcs(&action[i], 0); - if (ret) { - mlx5hws_pat_put_pattern(ctx, pat_id); - goto free_stc_and_pat; - } - } - - return 0; - -free_stc_and_pat: - while (i--) { - hws_action_destroy_stcs(&action[i]); - mlx5hws_pat_put_pattern(ctx, action[i].modify_header.pat_id); - } - - mlx5hws_arg_destroy(action->ctx, arg_id); - return ret; -} - -static int -hws_action_create_reformat_hws(struct mlx5hws_action *action, - u8 num_of_hdrs, - struct mlx5hws_action_reformat_header *hdrs, - u32 bulk_size) -{ - int ret; - - switch (action->type) { - case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: - ret = hws_action_create_stcs(action, 0); - break; - case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: - ret = hws_action_handle_insert_with_ptr(action, num_of_hdrs, hdrs, bulk_size); - break; - case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: - ret = hws_action_handle_l2_to_tunnel_l3(action, num_of_hdrs, hdrs, bulk_size); - break; - case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: - ret = hws_action_handle_tunnel_l3_to_l2(action, num_of_hdrs, hdrs, bulk_size); - break; - default: - mlx5hws_err(action->ctx, "Invalid HWS reformat action type\n"); - return -EINVAL; - } - - return ret; -} - -struct mlx5hws_action * -mlx5hws_action_create_reformat(struct mlx5hws_context *ctx, - enum mlx5hws_action_type reformat_type, - u8 num_of_hdrs, - struct mlx5hws_action_reformat_header *hdrs, - u32 log_bulk_size, - u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - if (!num_of_hdrs) { - mlx5hws_err(ctx, "Reformat num_of_hdrs cannot be zero\n"); - return NULL; - } - - action = hws_action_create_generic_bulk(ctx, flags, reformat_type, num_of_hdrs); - if (!action) - return NULL; - - if ((flags & MLX5HWS_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_hdrs > 1)) { - mlx5hws_err(ctx, "Reformat flags don't fit HWS (flags: 0x%x)\n", flags); - goto free_action; - } - - ret = hws_action_create_reformat_hws(action, num_of_hdrs, hdrs, log_bulk_size); - if (ret) { - mlx5hws_err(ctx, "Failed to create HWS reformat action\n"); - goto free_action; - } - - return action; - -free_action: - kfree(action); - return NULL; -} - -static int -hws_action_create_modify_header_hws(struct mlx5hws_action *action, - u8 num_of_patterns, - struct mlx5hws_action_mh_pattern *pattern, - u32 log_bulk_size) -{ - struct mlx5hws_context *ctx = action->ctx; - u16 num_actions, max_mh_actions = 0; - int i, ret, size_in_bytes; - u32 pat_id, arg_id = 0; - __be64 *new_pattern; - size_t pat_max_sz; - - pat_max_sz = MLX5HWS_ARG_CHUNK_SIZE_MAX * MLX5HWS_ARG_DATA_SIZE; - size_in_bytes = pat_max_sz * sizeof(__be64); - new_pattern = kcalloc(num_of_patterns, size_in_bytes, GFP_KERNEL); - if (!new_pattern) - return -ENOMEM; - - /* Calculate maximum number of mh actions for shared arg allocation */ - for (i = 0; i < num_of_patterns; i++) { - size_t new_num_actions; - size_t cur_num_actions; - u32 nope_location; - - cur_num_actions = pattern[i].sz / MLX5HWS_MODIFY_ACTION_SIZE; - - mlx5hws_pat_calc_nope(pattern[i].data, cur_num_actions, - pat_max_sz / MLX5HWS_MODIFY_ACTION_SIZE, - &new_num_actions, &nope_location, - &new_pattern[i * pat_max_sz]); - - action[i].modify_header.nope_locations = nope_location; - action[i].modify_header.num_of_actions = new_num_actions; - - max_mh_actions = max(max_mh_actions, new_num_actions); - } - - if (mlx5hws_arg_get_arg_log_size(max_mh_actions) >= MLX5HWS_ARG_CHUNK_SIZE_MAX) { - mlx5hws_err(ctx, "Num of actions (%d) bigger than allowed\n", - max_mh_actions); - ret = -EINVAL; - goto free_new_pat; - } - - /* Allocate single shared arg for all patterns based on the max size */ - if (max_mh_actions > 1) { - ret = mlx5hws_arg_create_modify_header_arg(ctx, - pattern->data, - max_mh_actions, - log_bulk_size, - action->flags & - MLX5HWS_ACTION_FLAG_SHARED, - &arg_id); - if (ret) - goto free_new_pat; - } - - for (i = 0; i < num_of_patterns; i++) { - if (!mlx5hws_pat_verify_actions(ctx, pattern[i].data, pattern[i].sz)) { - mlx5hws_err(ctx, "Fail to verify pattern modify actions\n"); - ret = -EINVAL; - goto free_stc_and_pat; - } - num_actions = pattern[i].sz / MLX5HWS_MODIFY_ACTION_SIZE; - action[i].modify_header.num_of_patterns = num_of_patterns; - action[i].modify_header.max_num_of_actions = max_mh_actions; - - action[i].modify_header.require_reparse = - mlx5hws_pat_require_reparse(pattern[i].data, num_actions); - - if (num_actions == 1) { - pat_id = 0; - /* Optimize single modify action to be used inline */ - action[i].modify_header.single_action = pattern[i].data[0]; - action[i].modify_header.single_action_type = - MLX5_GET(set_action_in, pattern[i].data, action_type); - } else { - /* Multiple modify actions require a pattern */ - if (unlikely(action[i].modify_header.nope_locations)) { - size_t pattern_sz; - - pattern_sz = action[i].modify_header.num_of_actions * - MLX5HWS_MODIFY_ACTION_SIZE; - ret = - mlx5hws_pat_get_pattern(ctx, - &new_pattern[i * pat_max_sz], - pattern_sz, &pat_id); - } else { - ret = mlx5hws_pat_get_pattern(ctx, - pattern[i].data, - pattern[i].sz, - &pat_id); - } - if (ret) { - mlx5hws_err(ctx, - "Failed to allocate pattern for modify header\n"); - goto free_stc_and_pat; - } - - action[i].modify_header.arg_id = arg_id; - action[i].modify_header.pat_id = pat_id; - } - /* Allocate STC for each action representing a header */ - ret = hws_action_create_stcs(&action[i], 0); - if (ret) { - if (pat_id) - mlx5hws_pat_put_pattern(ctx, pat_id); - goto free_stc_and_pat; - } - } - - kfree(new_pattern); - return 0; - -free_stc_and_pat: - while (i--) { - hws_action_destroy_stcs(&action[i]); - if (action[i].modify_header.pat_id) - mlx5hws_pat_put_pattern(ctx, action[i].modify_header.pat_id); - } - - if (arg_id) - mlx5hws_arg_destroy(ctx, arg_id); -free_new_pat: - kfree(new_pattern); - return ret; -} - -struct mlx5hws_action * -mlx5hws_action_create_modify_header(struct mlx5hws_context *ctx, - u8 num_of_patterns, - struct mlx5hws_action_mh_pattern *patterns, - u32 log_bulk_size, - u32 flags) -{ - struct mlx5hws_action *action; - int ret; - - if (!num_of_patterns) { - mlx5hws_err(ctx, "Invalid number of patterns\n"); - return NULL; - } - action = hws_action_create_generic_bulk(ctx, flags, - MLX5HWS_ACTION_TYP_MODIFY_HDR, - num_of_patterns); - if (!action) - return NULL; - - if ((flags & MLX5HWS_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_patterns > 1)) { - mlx5hws_err(ctx, "Action cannot be shared with requested pattern or size\n"); - goto free_action; - } - - ret = hws_action_create_modify_header_hws(action, - num_of_patterns, - patterns, - log_bulk_size); - if (ret) - goto free_action; - - return action; - -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_dest_array(struct mlx5hws_context *ctx, - size_t num_dest, - struct mlx5hws_action_dest_attr *dests, - bool ignore_flow_level, - u32 flow_source, - u32 flags) -{ - struct mlx5hws_cmd_set_fte_dest *dest_list = NULL; - struct mlx5hws_cmd_ft_create_attr ft_attr = {0}; - struct mlx5hws_cmd_set_fte_attr fte_attr = {0}; - struct mlx5hws_cmd_forward_tbl *fw_island; - struct mlx5hws_action *action; - u32 i /*, packet_reformat_id*/; - int ret; - - if (num_dest <= 1) { - mlx5hws_err(ctx, "Action must have multiple dests\n"); - return NULL; - } - - if (flags == (MLX5HWS_ACTION_FLAG_HWS_FDB | MLX5HWS_ACTION_FLAG_SHARED)) { - ft_attr.type = FS_FT_FDB; - ft_attr.level = ctx->caps->fdb_ft.max_level - 1; - } else { - mlx5hws_err(ctx, "Action flags not supported\n"); - return NULL; - } - - dest_list = kcalloc(num_dest, sizeof(*dest_list), GFP_KERNEL); - if (!dest_list) - return NULL; - - for (i = 0; i < num_dest; i++) { - enum mlx5hws_action_type action_type = dests[i].dest->type; - struct mlx5hws_action *reformat_action = dests[i].reformat; - - switch (action_type) { - case MLX5HWS_ACTION_TYP_TBL: - dest_list[i].destination_type = - MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; - dest_list[i].destination_id = dests[i].dest->dest_obj.obj_id; - fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; - fte_attr.ignore_flow_level = ignore_flow_level; - /* ToDo: In SW steering we have a handling of 'go to WIRE' - * destination here by upper layer setting 'is_wire_ft' flag - * if the destination is wire. - * This is because uplink should be last dest in the list. - */ - break; - case MLX5HWS_ACTION_TYP_VPORT: - dest_list[i].destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT; - dest_list[i].destination_id = dests[i].dest->vport.vport_num; - fte_attr.action_flags |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; - if (ctx->caps->merged_eswitch) { - dest_list[i].ext_flags |= - MLX5HWS_CMD_EXT_DEST_ESW_OWNER_VHCA_ID; - dest_list[i].esw_owner_vhca_id = - dests[i].dest->vport.esw_owner_vhca_id; - } - break; - default: - mlx5hws_err(ctx, "Unsupported action in dest_array\n"); - goto free_dest_list; - } - - if (reformat_action) { - mlx5hws_err(ctx, "dest_array with reformat action - unsupported\n"); - goto free_dest_list; - } - } - - fte_attr.dests_num = num_dest; - fte_attr.dests = dest_list; - - fw_island = mlx5hws_cmd_forward_tbl_create(ctx->mdev, &ft_attr, &fte_attr); - if (!fw_island) - goto free_dest_list; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_DEST_ARRAY); - if (!action) - goto destroy_fw_island; - - ret = hws_action_create_stcs(action, fw_island->ft_id); - if (ret) - goto free_action; - - action->dest_array.fw_island = fw_island; - action->dest_array.num_dest = num_dest; - action->dest_array.dest_list = dest_list; - - return action; - -free_action: - kfree(action); -destroy_fw_island: - mlx5hws_cmd_forward_tbl_destroy(ctx->mdev, fw_island); -free_dest_list: - for (i = 0; i < num_dest; i++) { - if (dest_list[i].ext_reformat_id) - mlx5hws_cmd_packet_reformat_destroy(ctx->mdev, - dest_list[i].ext_reformat_id); - } - kfree(dest_list); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_insert_header(struct mlx5hws_context *ctx, - u8 num_of_hdrs, - struct mlx5hws_action_insert_header *hdrs, - u32 log_bulk_size, - u32 flags) -{ - struct mlx5hws_action_reformat_header *reformat_hdrs; - struct mlx5hws_action *action; - int ret; - int i; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_INSERT_HEADER); - if (!action) - return NULL; - - reformat_hdrs = kcalloc(num_of_hdrs, sizeof(*reformat_hdrs), GFP_KERNEL); - if (!reformat_hdrs) - goto free_action; - - for (i = 0; i < num_of_hdrs; i++) { - if (hdrs[i].offset % W_SIZE != 0) { - mlx5hws_err(ctx, "Header offset should be in WORD granularity\n"); - goto free_reformat_hdrs; - } - - action[i].reformat.anchor = hdrs[i].anchor; - action[i].reformat.encap = hdrs[i].encap; - action[i].reformat.offset = hdrs[i].offset; - - reformat_hdrs[i].sz = hdrs[i].hdr.sz; - reformat_hdrs[i].data = hdrs[i].hdr.data; - } - - ret = hws_action_handle_insert_with_ptr(action, num_of_hdrs, - reformat_hdrs, log_bulk_size); - if (ret) { - mlx5hws_err(ctx, "Failed to create HWS reformat action\n"); - goto free_reformat_hdrs; - } - - kfree(reformat_hdrs); - - return action; - -free_reformat_hdrs: - kfree(reformat_hdrs); -free_action: - kfree(action); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_remove_header(struct mlx5hws_context *ctx, - struct mlx5hws_action_remove_header_attr *attr, - u32 flags) -{ - struct mlx5hws_action *action; - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_REMOVE_HEADER); - if (!action) - return NULL; - - /* support only remove anchor with size */ - if (attr->size % W_SIZE != 0) { - mlx5hws_err(ctx, - "Invalid size, HW supports header remove in WORD granularity\n"); - goto free_action; - } - - if (attr->size > MLX5HWS_ACTION_REMOVE_HEADER_MAX_SIZE) { - mlx5hws_err(ctx, "Header removal size limited to %u bytes\n", - MLX5HWS_ACTION_REMOVE_HEADER_MAX_SIZE); - goto free_action; - } - - action->remove_header.anchor = attr->anchor; - action->remove_header.size = attr->size / W_SIZE; - - if (hws_action_create_stcs(action, 0)) - goto free_action; - - return action; - -free_action: - kfree(action); - return NULL; -} - -static struct mlx5hws_definer * -hws_action_create_dest_match_range_definer(struct mlx5hws_context *ctx) -{ - struct mlx5hws_definer *definer; - __be32 *tag; - int ret; - - definer = kzalloc(sizeof(*definer), GFP_KERNEL); - if (!definer) - return NULL; - - definer->dw_selector[0] = MLX5_IFC_DEFINER_FORMAT_OFFSET_OUTER_ETH_PKT_LEN / 4; - /* Set DW0 tag mask */ - tag = (__force __be32 *)definer->mask.jumbo; - tag[MLX5HWS_RULE_JUMBO_MATCH_TAG_OFFSET_DW0] = htonl(0xffffUL << 16); - - mutex_lock(&ctx->ctrl_lock); - - ret = mlx5hws_definer_get_obj(ctx, definer); - if (ret < 0) { - mutex_unlock(&ctx->ctrl_lock); - kfree(definer); - return NULL; - } - - mutex_unlock(&ctx->ctrl_lock); - definer->obj_id = ret; - - return definer; -} - -static struct mlx5hws_matcher_action_ste * -hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx, - struct mlx5hws_definer *definer, - u32 miss_ft_id) -{ - struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0}; - struct mlx5hws_action_default_stc *default_stc; - struct mlx5hws_matcher_action_ste *table_ste; - struct mlx5hws_pool_attr pool_attr = {0}; - struct mlx5hws_pool *ste_pool, *stc_pool; - struct mlx5hws_pool_chunk *ste; - u32 *rtc_0_id, *rtc_1_id; - u32 obj_id; - int ret; - - /* Check if STE range is supported */ - if (!IS_BIT_SET(ctx->caps->supp_ste_format_gen_wqe, MLX5_IFC_RTC_STE_FORMAT_RANGE)) { - mlx5hws_err(ctx, "Range STE format not supported\n"); - return NULL; - } - - table_ste = kzalloc(sizeof(*table_ste), GFP_KERNEL); - if (!table_ste) - return NULL; - - mutex_lock(&ctx->ctrl_lock); - - pool_attr.table_type = MLX5HWS_TABLE_TYPE_FDB; - pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; - pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL; - pool_attr.alloc_log_sz = 1; - table_ste->pool = mlx5hws_pool_create(ctx, &pool_attr); - if (!table_ste->pool) { - mlx5hws_err(ctx, "Failed to allocate memory ste pool\n"); - goto free_ste; - } - - /* Allocate RTC */ - rtc_0_id = &table_ste->rtc_0_id; - rtc_1_id = &table_ste->rtc_1_id; - ste_pool = table_ste->pool; - ste = &table_ste->ste; - ste->order = 1; - - rtc_attr.log_size = 0; - rtc_attr.log_depth = 0; - rtc_attr.miss_ft_id = miss_ft_id; - rtc_attr.num_hash_definer = 1; - rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; - rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH; - rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; - rtc_attr.fw_gen_wqe = true; - rtc_attr.is_scnd_range = true; - - obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); - - rtc_attr.pd = ctx->pd_num; - rtc_attr.ste_base = obj_id; - rtc_attr.ste_offset = ste->offset; - rtc_attr.reparse_mode = mlx5hws_context_get_reparse_mode(ctx); - rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(MLX5HWS_TABLE_TYPE_FDB, false); - - /* STC is a single resource (obj_id), use any STC for the ID */ - stc_pool = ctx->stc_pool[MLX5HWS_TABLE_TYPE_FDB]; - default_stc = ctx->common_res[MLX5HWS_TABLE_TYPE_FDB].default_stc; - obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit); - rtc_attr.stc_base = obj_id; - - ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id); - if (ret) { - mlx5hws_err(ctx, "Failed to create RTC"); - goto pool_destroy; - } - - /* Create mirror RTC */ - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); - rtc_attr.ste_base = obj_id; - rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(MLX5HWS_TABLE_TYPE_FDB, true); - - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit); - rtc_attr.stc_base = obj_id; - - ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_1_id); - if (ret) { - mlx5hws_err(ctx, "Failed to create mirror RTC"); - goto destroy_rtc_0; - } - - mutex_unlock(&ctx->ctrl_lock); - - return table_ste; - -destroy_rtc_0: - mlx5hws_cmd_rtc_destroy(ctx->mdev, *rtc_0_id); -pool_destroy: - mlx5hws_pool_destroy(table_ste->pool); -free_ste: - mutex_unlock(&ctx->ctrl_lock); - kfree(table_ste); - return NULL; -} - -static void -hws_action_destroy_dest_match_range_table(struct mlx5hws_context *ctx, - struct mlx5hws_matcher_action_ste *table_ste) -{ - mutex_lock(&ctx->ctrl_lock); - - mlx5hws_cmd_rtc_destroy(ctx->mdev, table_ste->rtc_1_id); - mlx5hws_cmd_rtc_destroy(ctx->mdev, table_ste->rtc_0_id); - mlx5hws_pool_destroy(table_ste->pool); - kfree(table_ste); - - mutex_unlock(&ctx->ctrl_lock); -} - -static int -hws_action_create_dest_match_range_fill_table(struct mlx5hws_context *ctx, - struct mlx5hws_matcher_action_ste *table_ste, - struct mlx5hws_action *hit_ft_action, - struct mlx5hws_definer *range_definer, - u32 min, u32 max) -{ - struct mlx5hws_wqe_gta_data_seg_ste match_wqe_data = {0}; - struct mlx5hws_wqe_gta_data_seg_ste range_wqe_data = {0}; - struct mlx5hws_wqe_gta_ctrl_seg wqe_ctrl = {0}; - u32 no_use, used_rtc_0_id, used_rtc_1_id, ret; - struct mlx5hws_context_common_res *common_res; - struct mlx5hws_send_ste_attr ste_attr = {0}; - struct mlx5hws_send_engine *queue; - __be32 *wqe_data_arr; - - mutex_lock(&ctx->ctrl_lock); - - /* Get the control queue */ - queue = &ctx->send_queue[ctx->queues - 1]; - if (unlikely(mlx5hws_send_engine_err(queue))) { - ret = -EIO; - goto error; - } - - /* Init default send STE attributes */ - ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; - ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; - ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; - ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; - ste_attr.send_attr.user_data = &no_use; - ste_attr.send_attr.rule = NULL; - ste_attr.send_attr.fence = 1; - ste_attr.send_attr.notify_hw = true; - ste_attr.rtc_0 = table_ste->rtc_0_id; - ste_attr.rtc_1 = table_ste->rtc_1_id; - ste_attr.used_id_rtc_0 = &used_rtc_0_id; - ste_attr.used_id_rtc_1 = &used_rtc_1_id; - - common_res = &ctx->common_res[MLX5HWS_TABLE_TYPE_FDB]; - - /* init an empty match STE which will always hit */ - ste_attr.wqe_ctrl = &wqe_ctrl; - ste_attr.wqe_data = &match_wqe_data; - ste_attr.send_attr.match_definer_id = ctx->caps->trivial_match_definer; - - /* Fill WQE control data */ - wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] = - htonl(common_res->default_stc->nop_ctr.offset); - wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = - htonl(common_res->default_stc->nop_dw5.offset); - wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = - htonl(common_res->default_stc->nop_dw6.offset); - wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = - htonl(common_res->default_stc->nop_dw7.offset); - wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] |= - htonl(MLX5HWS_ACTION_STC_IDX_LAST_COMBO2 << 29); - wqe_ctrl.stc_ix[MLX5HWS_ACTION_STC_IDX_HIT] = - htonl(hit_ft_action->stc[MLX5HWS_TABLE_TYPE_FDB].offset); - - wqe_data_arr = (__force __be32 *)&range_wqe_data; - - ste_attr.range_wqe_data = &range_wqe_data; - ste_attr.send_attr.len += MLX5HWS_WQE_SZ_GTA_DATA; - ste_attr.send_attr.range_definer_id = mlx5hws_definer_get_id(range_definer); - - /* Fill range matching fields, - * min/max_value_2 corresponds to match_dw_0 in its definer, - * min_value_2 sets in DW0 in the STE and max_value_2 sets in DW1 in the STE. - */ - wqe_data_arr[MLX5HWS_MATCHER_OFFSET_TAG_DW0] = htonl(min << 16); - wqe_data_arr[MLX5HWS_MATCHER_OFFSET_TAG_DW1] = htonl(max << 16); - - /* Send WQEs to FW */ - mlx5hws_send_stes_fw(ctx, queue, &ste_attr); - - /* Poll for completion */ - ret = mlx5hws_send_queue_action(ctx, ctx->queues - 1, - MLX5HWS_SEND_QUEUE_ACTION_DRAIN_SYNC); - if (ret) { - mlx5hws_err(ctx, "Failed to drain control queue"); - goto error; - } - - mutex_unlock(&ctx->ctrl_lock); - - return 0; - -error: - mutex_unlock(&ctx->ctrl_lock); - return ret; -} - -struct mlx5hws_action * -mlx5hws_action_create_dest_match_range(struct mlx5hws_context *ctx, - u32 field, - struct mlx5_flow_table *hit_ft, - struct mlx5_flow_table *miss_ft, - u32 min, u32 max, u32 flags) -{ - struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; - struct mlx5hws_matcher_action_ste *table_ste; - struct mlx5hws_action *hit_ft_action; - struct mlx5hws_definer *definer; - struct mlx5hws_action *action; - u32 miss_ft_id = miss_ft->id; - u32 hit_ft_id = hit_ft->id; - int ret; - - if (field != MLX5_FLOW_DEST_RANGE_FIELD_PKT_LEN || - min > 0xffff || max > 0xffff) { - mlx5hws_err(ctx, "Invalid match range parameters\n"); - return NULL; - } - - action = hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_RANGE); - if (!action) - return NULL; - - definer = hws_action_create_dest_match_range_definer(ctx); - if (!definer) - goto free_action; - - table_ste = hws_action_create_dest_match_range_table(ctx, definer, miss_ft_id); - if (!table_ste) - goto destroy_definer; - - hit_ft_action = mlx5hws_action_create_dest_table_num(ctx, hit_ft_id, flags); - if (!hit_ft_action) - goto destroy_table_ste; - - ret = hws_action_create_dest_match_range_fill_table(ctx, table_ste, - hit_ft_action, - definer, min, max); - if (ret) - goto destroy_hit_ft_action; - - action->range.table_ste = table_ste; - action->range.definer = definer; - action->range.hit_ft_action = hit_ft_action; - - /* Allocate STC for jumps to STE */ - mutex_lock(&ctx->ctrl_lock); - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; - stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; - stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; - stc_attr.ste_table.ste = table_ste->ste; - stc_attr.ste_table.ste_pool = table_ste->pool; - stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; - - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, MLX5HWS_TABLE_TYPE_FDB, - &action->stc[MLX5HWS_TABLE_TYPE_FDB]); - if (ret) - goto error_unlock; - - mutex_unlock(&ctx->ctrl_lock); - - return action; - -error_unlock: - mutex_unlock(&ctx->ctrl_lock); -destroy_hit_ft_action: - mlx5hws_action_destroy(hit_ft_action); -destroy_table_ste: - hws_action_destroy_dest_match_range_table(ctx, table_ste); -destroy_definer: - mlx5hws_definer_free(ctx, definer); -free_action: - kfree(action); - mlx5hws_err(ctx, "Failed to create action dest match range"); - return NULL; -} - -struct mlx5hws_action * -mlx5hws_action_create_last(struct mlx5hws_context *ctx, u32 flags) -{ - return hws_action_create_generic(ctx, flags, MLX5HWS_ACTION_TYP_LAST); -} - -struct mlx5hws_action * -mlx5hws_action_create_flow_sampler(struct mlx5hws_context *ctx, - u32 sampler_id, u32 flags) -{ - mlx5hws_err(ctx, "Flow sampler action - unsupported\n"); - return NULL; -} - -static void hws_action_destroy_hws(struct mlx5hws_action *action) -{ - u32 ext_reformat_id; - bool shared_arg; - u32 obj_id; - u32 i; - - switch (action->type) { - case MLX5HWS_ACTION_TYP_MISS: - case MLX5HWS_ACTION_TYP_TAG: - case MLX5HWS_ACTION_TYP_DROP: - case MLX5HWS_ACTION_TYP_CTR: - case MLX5HWS_ACTION_TYP_TBL: - case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: - case MLX5HWS_ACTION_TYP_ASO_METER: - case MLX5HWS_ACTION_TYP_PUSH_VLAN: - case MLX5HWS_ACTION_TYP_REMOVE_HEADER: - case MLX5HWS_ACTION_TYP_VPORT: - hws_action_destroy_stcs(action); - break; - case MLX5HWS_ACTION_TYP_POP_VLAN: - hws_action_destroy_stcs(action); - hws_action_put_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP); - break; - case MLX5HWS_ACTION_TYP_DEST_ARRAY: - hws_action_destroy_stcs(action); - mlx5hws_cmd_forward_tbl_destroy(action->ctx->mdev, action->dest_array.fw_island); - for (i = 0; i < action->dest_array.num_dest; i++) { - ext_reformat_id = action->dest_array.dest_list[i].ext_reformat_id; - if (ext_reformat_id) - mlx5hws_cmd_packet_reformat_destroy(action->ctx->mdev, - ext_reformat_id); - } - kfree(action->dest_array.dest_list); - break; - case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: - case MLX5HWS_ACTION_TYP_MODIFY_HDR: - shared_arg = false; - for (i = 0; i < action->modify_header.num_of_patterns; i++) { - hws_action_destroy_stcs(&action[i]); - if (action[i].modify_header.num_of_actions > 1) { - mlx5hws_pat_put_pattern(action[i].ctx, - action[i].modify_header.pat_id); - /* Save shared arg object to be freed after */ - obj_id = action[i].modify_header.arg_id; - shared_arg = true; - } - } - if (shared_arg) - mlx5hws_arg_destroy(action->ctx, obj_id); - break; - case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: - hws_action_put_shared_stc(action, MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3); - for (i = 0; i < action->reformat.num_of_hdrs; i++) - hws_action_destroy_stcs(&action[i]); - mlx5hws_arg_destroy(action->ctx, action->reformat.arg_id); - break; - case MLX5HWS_ACTION_TYP_INSERT_HEADER: - case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: - for (i = 0; i < action->reformat.num_of_hdrs; i++) - hws_action_destroy_stcs(&action[i]); - mlx5hws_arg_destroy(action->ctx, action->reformat.arg_id); - break; - case MLX5HWS_ACTION_TYP_RANGE: - hws_action_destroy_stcs(action); - hws_action_destroy_dest_match_range_table(action->ctx, action->range.table_ste); - mlx5hws_definer_free(action->ctx, action->range.definer); - mlx5hws_action_destroy(action->range.hit_ft_action); - break; - case MLX5HWS_ACTION_TYP_LAST: - break; - default: - pr_warn("HWS: Invalid action type: %d\n", action->type); - } -} - -int mlx5hws_action_destroy(struct mlx5hws_action *action) -{ - hws_action_destroy_hws(action); - - kfree(action); - return 0; -} - -int mlx5hws_action_get_default_stc(struct mlx5hws_context *ctx, u8 tbl_type) -__must_hold(&ctx->ctrl_lock) -{ - struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; - struct mlx5hws_action_default_stc *default_stc; - int ret; - - if (ctx->common_res[tbl_type].default_stc) { - ctx->common_res[tbl_type].default_stc->refcount++; - return 0; - } - - default_stc = kzalloc(sizeof(*default_stc), GFP_KERNEL); - if (!default_stc) - return -ENOMEM; - - stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_NOP; - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW0; - stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, - &default_stc->nop_ctr); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate default counter STC\n"); - goto free_default_stc; - } - - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW5; - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, - &default_stc->nop_dw5); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate default NOP DW5 STC\n"); - goto free_nop_ctr; - } - - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW6; - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, - &default_stc->nop_dw6); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate default NOP DW6 STC\n"); - goto free_nop_dw5; - } - - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_DW7; - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, - &default_stc->nop_dw7); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate default NOP DW7 STC\n"); - goto free_nop_dw6; - } - - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; - stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_ALLOW; - - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl_type, - &default_stc->default_hit); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate default allow STC\n"); - goto free_nop_dw7; - } - - ctx->common_res[tbl_type].default_stc = default_stc; - ctx->common_res[tbl_type].default_stc->refcount++; - - return 0; - -free_nop_dw7: - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7); -free_nop_dw6: - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6); -free_nop_dw5: - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5); -free_nop_ctr: - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr); -free_default_stc: - kfree(default_stc); - return ret; -} - -void mlx5hws_action_put_default_stc(struct mlx5hws_context *ctx, u8 tbl_type) -__must_hold(&ctx->ctrl_lock) -{ - struct mlx5hws_action_default_stc *default_stc; - - default_stc = ctx->common_res[tbl_type].default_stc; - - default_stc = ctx->common_res[tbl_type].default_stc; - if (--default_stc->refcount) - return; - - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->default_hit); - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw7); - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw6); - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_dw5); - mlx5hws_action_free_single_stc(ctx, tbl_type, &default_stc->nop_ctr); - kfree(default_stc); - ctx->common_res[tbl_type].default_stc = NULL; -} - -static void hws_action_modify_write(struct mlx5hws_send_engine *queue, - u32 arg_idx, - u8 *arg_data, - u16 num_of_actions, - u32 nope_locations) -{ - u8 *new_arg_data = NULL; - int i, j; - - if (unlikely(nope_locations)) { - new_arg_data = kcalloc(num_of_actions, - MLX5HWS_MODIFY_ACTION_SIZE, GFP_KERNEL); - if (unlikely(!new_arg_data)) - return; - - for (i = 0, j = 0; i < num_of_actions; i++, j++) { - memcpy(&new_arg_data[j], arg_data, MLX5HWS_MODIFY_ACTION_SIZE); - if (BIT(i) & nope_locations) - j++; - } - } - - mlx5hws_arg_write(queue, NULL, arg_idx, - new_arg_data ? new_arg_data : arg_data, - num_of_actions * MLX5HWS_MODIFY_ACTION_SIZE); - - kfree(new_arg_data); -} - -void mlx5hws_action_prepare_decap_l3_data(u8 *src, u8 *dst, u16 num_of_actions) -{ - u8 *e_src; - int i; - - /* num_of_actions = remove l3l2 + 4/5 inserts + remove extra 2 bytes - * copy from end of src to the start of dst. - * move to the end, 2 is the leftover from 14B or 18B - */ - if (num_of_actions == DECAP_L3_NUM_ACTIONS_W_NO_VLAN) - e_src = src + MLX5HWS_ACTION_HDR_LEN_L2; - else - e_src = src + MLX5HWS_ACTION_HDR_LEN_L2_W_VLAN; - - /* Move dst over the first remove action + zero data */ - dst += MLX5HWS_ACTION_DOUBLE_SIZE; - /* Move dst over the first insert ctrl action */ - dst += MLX5HWS_ACTION_DOUBLE_SIZE / 2; - /* Actions: - * no vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b. - * with vlan: r_h-insert_4b-insert_4b-insert_4b-insert_4b-insert_4b-remove_2b. - * the loop is without the last insertion. - */ - for (i = 0; i < num_of_actions - 3; i++) { - e_src -= MLX5HWS_ACTION_INLINE_DATA_SIZE; - memcpy(dst, e_src, MLX5HWS_ACTION_INLINE_DATA_SIZE); /* data */ - dst += MLX5HWS_ACTION_DOUBLE_SIZE; - } - /* Copy the last 2 bytes after a gap of 2 bytes which will be removed */ - e_src -= MLX5HWS_ACTION_INLINE_DATA_SIZE / 2; - dst += MLX5HWS_ACTION_INLINE_DATA_SIZE / 2; - memcpy(dst, e_src, 2); -} - -static int -hws_action_get_shared_stc_offset(struct mlx5hws_context_common_res *common_res, - enum mlx5hws_context_shared_stc_type stc_type) -{ - return common_res->shared_stc[stc_type]->stc_chunk.offset; -} - -static struct mlx5hws_actions_wqe_setter * -hws_action_setter_find_first(struct mlx5hws_actions_wqe_setter *setter, - u8 req_flags) -{ - /* Use a new setter if requested flags are taken */ - while (setter->flags & req_flags) - setter++; - - /* Use current setter in required flags are not used */ - return setter; -} - -static void -hws_action_apply_stc(struct mlx5hws_actions_apply_data *apply, - enum mlx5hws_action_stc_idx stc_idx, - u8 action_idx) -{ - struct mlx5hws_action *action = apply->rule_action[action_idx].action; - - apply->wqe_ctrl->stc_ix[stc_idx] = - htonl(action->stc[apply->tbl_type].offset); -} - -static void -hws_action_setter_push_vlan(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - struct mlx5hws_rule_action *rule_action; - - rule_action = &apply->rule_action[setter->idx_double]; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = rule_action->push_vlan.vlan_hdr; - - hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_DW6, setter->idx_double); - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; -} - -static void -hws_action_setter_modify_header(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - struct mlx5hws_rule_action *rule_action; - struct mlx5hws_action *action; - u32 arg_sz, arg_idx; - u8 *single_action; - __be32 stc_idx; - - rule_action = &apply->rule_action[setter->idx_double]; - action = rule_action->action; - - stc_idx = htonl(action->stc[apply->tbl_type].offset); - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; - - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; - - if (action->modify_header.num_of_actions == 1) { - if (action->modify_header.single_action_type == - MLX5_MODIFICATION_TYPE_COPY || - action->modify_header.single_action_type == - MLX5_MODIFICATION_TYPE_ADD_FIELD) { - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = 0; - return; - } - - if (action->flags & MLX5HWS_ACTION_FLAG_SHARED) - single_action = (u8 *)&action->modify_header.single_action; - else - single_action = rule_action->modify_header.data; - - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = - *(__be32 *)MLX5_ADDR_OF(set_action_in, single_action, data); - } else { - /* Argument offset multiple with number of args per these actions */ - arg_sz = mlx5hws_arg_get_arg_size(action->modify_header.max_num_of_actions); - arg_idx = rule_action->modify_header.offset * arg_sz; - - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(arg_idx); - - if (!(action->flags & MLX5HWS_ACTION_FLAG_SHARED)) { - apply->require_dep = 1; - hws_action_modify_write(apply->queue, - action->modify_header.arg_id + arg_idx, - rule_action->modify_header.data, - action->modify_header.num_of_actions, - action->modify_header.nope_locations); - } - } -} - -static void -hws_action_setter_insert_ptr(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - struct mlx5hws_rule_action *rule_action; - struct mlx5hws_action *action; - u32 arg_idx, arg_sz; - __be32 stc_idx; - - rule_action = &apply->rule_action[setter->idx_double]; - action = rule_action->action + rule_action->reformat.hdr_idx; - - /* Argument offset multiple on args required for header size */ - arg_sz = mlx5hws_arg_data_size_to_arg_size(action->reformat.max_hdr_sz); - arg_idx = rule_action->reformat.offset * arg_sz; - - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(arg_idx); - - stc_idx = htonl(action->stc[apply->tbl_type].offset); - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; - - if (!(action->flags & MLX5HWS_ACTION_FLAG_SHARED)) { - apply->require_dep = 1; - mlx5hws_arg_write(apply->queue, NULL, - action->reformat.arg_id + arg_idx, - rule_action->reformat.data, - action->reformat.header_size); - } -} - -static void -hws_action_setter_tnl_l3_to_l2(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - struct mlx5hws_rule_action *rule_action; - struct mlx5hws_action *action; - u32 arg_sz, arg_idx; - __be32 stc_idx; - - rule_action = &apply->rule_action[setter->idx_double]; - action = rule_action->action + rule_action->reformat.hdr_idx; - - /* Argument offset multiple on args required for num of actions */ - arg_sz = mlx5hws_arg_get_arg_size(action->modify_header.max_num_of_actions); - arg_idx = rule_action->reformat.offset * arg_sz; - - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(arg_idx); - - stc_idx = htonl(action->stc[apply->tbl_type].offset); - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = stc_idx; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; - - if (!(action->flags & MLX5HWS_ACTION_FLAG_SHARED)) { - apply->require_dep = 1; - mlx5hws_arg_decapl3_write(apply->queue, - action->modify_header.arg_id + arg_idx, - rule_action->reformat.data, - action->modify_header.num_of_actions); - } -} - -static void -hws_action_setter_aso(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - struct mlx5hws_rule_action *rule_action; - u32 exe_aso_ctrl; - u32 offset; - - rule_action = &apply->rule_action[setter->idx_double]; - - switch (rule_action->action->type) { - case MLX5HWS_ACTION_TYP_ASO_METER: - /* exe_aso_ctrl format: - * [STC only and reserved bits 29b][init_color 2b][meter_id 1b] - */ - offset = rule_action->aso_meter.offset / MLX5_ASO_METER_NUM_PER_OBJ; - exe_aso_ctrl = rule_action->aso_meter.offset % MLX5_ASO_METER_NUM_PER_OBJ; - exe_aso_ctrl |= rule_action->aso_meter.init_color << - MLX5HWS_ACTION_METER_INIT_COLOR_OFFSET; - break; - default: - mlx5hws_err(rule_action->action->ctx, - "Unsupported ASO action type: %d\n", rule_action->action->type); - return; - } - - /* aso_object_offset format: [24B] */ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = htonl(offset); - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = htonl(exe_aso_ctrl); - - hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_DW6, setter->idx_double); - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; -} - -static void -hws_action_setter_tag(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - struct mlx5hws_rule_action *rule_action; - - rule_action = &apply->rule_action[setter->idx_single]; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = htonl(rule_action->tag.value); - hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_DW5, setter->idx_single); -} - -static void -hws_action_setter_ctrl_ctr(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - struct mlx5hws_rule_action *rule_action; - - rule_action = &apply->rule_action[setter->idx_ctr]; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW0] = htonl(rule_action->counter.offset); - hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_CTRL, setter->idx_ctr); -} - -static void -hws_action_setter_single(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; - hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_DW5, setter->idx_single); -} - -static void -hws_action_setter_single_double_pop(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = - htonl(hws_action_get_shared_stc_offset(apply->common_res, - MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP)); -} - -static void -hws_action_setter_hit(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_HIT_LSB] = 0; - hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_HIT, setter->idx_hit); -} - -static void -hws_action_setter_default_hit(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_HIT_LSB] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_HIT] = - htonl(apply->common_res->default_stc->default_hit.offset); -} - -static void -hws_action_setter_hit_next_action(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_HIT_LSB] = htonl(apply->next_direct_idx << 6); - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_HIT] = htonl(apply->jump_to_action_stc); -} - -static void -hws_action_setter_common_decap(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = - htonl(hws_action_get_shared_stc_offset(apply->common_res, - MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3)); -} - -static void -hws_action_setter_range(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - /* Always jump to index zero */ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_HIT_LSB] = 0; - hws_action_apply_stc(apply, MLX5HWS_ACTION_STC_IDX_HIT, setter->idx_hit); -} - -int mlx5hws_action_template_process(struct mlx5hws_action_template *at) -{ - struct mlx5hws_actions_wqe_setter *start_setter = at->setters + 1; - enum mlx5hws_action_type *action_type = at->action_type_arr; - struct mlx5hws_actions_wqe_setter *setter = at->setters; - struct mlx5hws_actions_wqe_setter *pop_setter = NULL; - struct mlx5hws_actions_wqe_setter *last_setter; - int i; - - /* Note: Given action combination must be valid */ - - /* Check if action were already processed */ - if (at->num_of_action_stes) - return 0; - - for (i = 0; i < MLX5HWS_ACTION_MAX_STE; i++) - setter[i].set_hit = &hws_action_setter_hit_next_action; - - /* The same action template setters can be used with jumbo or match - * STE, to support both cases we reserve the first setter for cases - * with jumbo STE to allow jump to the first action STE. - * This extra setter can be reduced in some cases on rule creation. - */ - setter = start_setter; - last_setter = start_setter; - - for (i = 0; i < at->num_actions; i++) { - switch (action_type[i]) { - case MLX5HWS_ACTION_TYP_DROP: - case MLX5HWS_ACTION_TYP_TBL: - case MLX5HWS_ACTION_TYP_DEST_ARRAY: - case MLX5HWS_ACTION_TYP_VPORT: - case MLX5HWS_ACTION_TYP_MISS: - /* Hit action */ - last_setter->flags |= ASF_HIT; - last_setter->set_hit = &hws_action_setter_hit; - last_setter->idx_hit = i; - break; - - case MLX5HWS_ACTION_TYP_RANGE: - last_setter->flags |= ASF_HIT; - last_setter->set_hit = &hws_action_setter_range; - last_setter->idx_hit = i; - break; - - case MLX5HWS_ACTION_TYP_POP_VLAN: - /* Single remove header to header */ - if (pop_setter) { - /* We have 2 pops, use the shared */ - pop_setter->set_single = &hws_action_setter_single_double_pop; - break; - } - setter = hws_action_setter_find_first(last_setter, - ASF_SINGLE1 | ASF_MODIFY | - ASF_INSERT); - setter->flags |= ASF_SINGLE1 | ASF_REMOVE; - setter->set_single = &hws_action_setter_single; - setter->idx_single = i; - pop_setter = setter; - break; - - case MLX5HWS_ACTION_TYP_PUSH_VLAN: - /* Double insert inline */ - setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); - setter->flags |= ASF_DOUBLE | ASF_INSERT; - setter->set_double = &hws_action_setter_push_vlan; - setter->idx_double = i; - break; - - case MLX5HWS_ACTION_TYP_MODIFY_HDR: - /* Double modify header list */ - setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); - setter->flags |= ASF_DOUBLE | ASF_MODIFY; - setter->set_double = &hws_action_setter_modify_header; - setter->idx_double = i; - break; - - case MLX5HWS_ACTION_TYP_ASO_METER: - /* Double ASO action */ - setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE); - setter->flags |= ASF_DOUBLE; - setter->set_double = &hws_action_setter_aso; - setter->idx_double = i; - break; - - case MLX5HWS_ACTION_TYP_REMOVE_HEADER: - case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L2_TO_L2: - /* Single remove header to header */ - setter = hws_action_setter_find_first(last_setter, - ASF_SINGLE1 | ASF_MODIFY); - setter->flags |= ASF_SINGLE1 | ASF_REMOVE; - setter->set_single = &hws_action_setter_single; - setter->idx_single = i; - break; - - case MLX5HWS_ACTION_TYP_INSERT_HEADER: - case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L2: - /* Double insert header with pointer */ - setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); - setter->flags |= ASF_DOUBLE | ASF_INSERT; - setter->set_double = &hws_action_setter_insert_ptr; - setter->idx_double = i; - break; - - case MLX5HWS_ACTION_TYP_REFORMAT_L2_TO_TNL_L3: - /* Single remove + Double insert header with pointer */ - setter = hws_action_setter_find_first(last_setter, - ASF_SINGLE1 | ASF_DOUBLE); - setter->flags |= ASF_SINGLE1 | ASF_DOUBLE; - setter->set_double = &hws_action_setter_insert_ptr; - setter->idx_double = i; - setter->set_single = &hws_action_setter_common_decap; - setter->idx_single = i; - break; - - case MLX5HWS_ACTION_TYP_REFORMAT_TNL_L3_TO_L2: - /* Double modify header list with remove and push inline */ - setter = hws_action_setter_find_first(last_setter, ASF_DOUBLE | ASF_REMOVE); - setter->flags |= ASF_DOUBLE | ASF_MODIFY | ASF_INSERT; - setter->set_double = &hws_action_setter_tnl_l3_to_l2; - setter->idx_double = i; - break; - - case MLX5HWS_ACTION_TYP_TAG: - /* Single TAG action, search for any room from the start */ - setter = hws_action_setter_find_first(start_setter, ASF_SINGLE1); - setter->flags |= ASF_SINGLE1; - setter->set_single = &hws_action_setter_tag; - setter->idx_single = i; - break; - - case MLX5HWS_ACTION_TYP_CTR: - /* Control counter action - * TODO: Current counter executed first. Support is needed - * for single ation counter action which is done last. - * Example: Decap + CTR - */ - setter = hws_action_setter_find_first(start_setter, ASF_CTR); - setter->flags |= ASF_CTR; - setter->set_ctr = &hws_action_setter_ctrl_ctr; - setter->idx_ctr = i; - break; - default: - pr_warn("HWS: Invalid action type in processingaction template: action_type[%d]=%d\n", - i, action_type[i]); - return -EOPNOTSUPP; - } - - last_setter = max(setter, last_setter); - } - - /* Set default hit on the last STE if no hit action provided */ - if (!(last_setter->flags & ASF_HIT)) - last_setter->set_hit = &hws_action_setter_default_hit; - - at->num_of_action_stes = last_setter - start_setter + 1; - - /* Check if action template doesn't require any action DWs */ - at->only_term = (at->num_of_action_stes == 1) && - !(last_setter->flags & ~(ASF_CTR | ASF_HIT)); - - return 0; -} - -struct mlx5hws_action_template * -mlx5hws_action_template_create(enum mlx5hws_action_type action_type[]) -{ - struct mlx5hws_action_template *at; - u8 num_actions = 0; - int i; - - at = kzalloc(sizeof(*at), GFP_KERNEL); - if (!at) - return NULL; - - while (action_type[num_actions++] != MLX5HWS_ACTION_TYP_LAST) - ; - - at->num_actions = num_actions - 1; - at->action_type_arr = kcalloc(num_actions, sizeof(*action_type), GFP_KERNEL); - if (!at->action_type_arr) - goto free_at; - - for (i = 0; i < num_actions; i++) - at->action_type_arr[i] = action_type[i]; - - return at; - -free_at: - kfree(at); - return NULL; -} - -int mlx5hws_action_template_destroy(struct mlx5hws_action_template *at) -{ - kfree(at->action_type_arr); - kfree(at); - return 0; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h deleted file mode 100644 index bf5c1b2410060c..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_action.h +++ /dev/null @@ -1,307 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_ACTION_H_ -#define MLX5HWS_ACTION_H_ - -/* Max number of STEs needed for a rule (including match) */ -#define MLX5HWS_ACTION_MAX_STE 20 - -/* Max number of internal subactions of ipv6_ext */ -#define MLX5HWS_ACTION_IPV6_EXT_MAX_SA 4 - -enum mlx5hws_action_stc_idx { - MLX5HWS_ACTION_STC_IDX_CTRL = 0, - MLX5HWS_ACTION_STC_IDX_HIT = 1, - MLX5HWS_ACTION_STC_IDX_DW5 = 2, - MLX5HWS_ACTION_STC_IDX_DW6 = 3, - MLX5HWS_ACTION_STC_IDX_DW7 = 4, - MLX5HWS_ACTION_STC_IDX_MAX = 5, - /* STC Jumvo STE combo: CTR, Hit */ - MLX5HWS_ACTION_STC_IDX_LAST_JUMBO_STE = 1, - /* STC combo1: CTR, SINGLE, DOUBLE, Hit */ - MLX5HWS_ACTION_STC_IDX_LAST_COMBO1 = 3, - /* STC combo2: CTR, 3 x SINGLE, Hit */ - MLX5HWS_ACTION_STC_IDX_LAST_COMBO2 = 4, - /* STC combo2: CTR, TRIPLE, Hit */ - MLX5HWS_ACTION_STC_IDX_LAST_COMBO3 = 2, -}; - -enum mlx5hws_action_offset { - MLX5HWS_ACTION_OFFSET_DW0 = 0, - MLX5HWS_ACTION_OFFSET_DW5 = 5, - MLX5HWS_ACTION_OFFSET_DW6 = 6, - MLX5HWS_ACTION_OFFSET_DW7 = 7, - MLX5HWS_ACTION_OFFSET_HIT = 3, - MLX5HWS_ACTION_OFFSET_HIT_LSB = 4, -}; - -enum { - MLX5HWS_ACTION_DOUBLE_SIZE = 8, - MLX5HWS_ACTION_INLINE_DATA_SIZE = 4, - MLX5HWS_ACTION_HDR_LEN_L2_MACS = 12, - MLX5HWS_ACTION_HDR_LEN_L2_VLAN = 4, - MLX5HWS_ACTION_HDR_LEN_L2_ETHER = 2, - MLX5HWS_ACTION_HDR_LEN_L2 = (MLX5HWS_ACTION_HDR_LEN_L2_MACS + - MLX5HWS_ACTION_HDR_LEN_L2_ETHER), - MLX5HWS_ACTION_HDR_LEN_L2_W_VLAN = (MLX5HWS_ACTION_HDR_LEN_L2 + - MLX5HWS_ACTION_HDR_LEN_L2_VLAN), - MLX5HWS_ACTION_REFORMAT_DATA_SIZE = 64, - DECAP_L3_NUM_ACTIONS_W_NO_VLAN = 6, - DECAP_L3_NUM_ACTIONS_W_VLAN = 7, -}; - -enum mlx5hws_action_setter_flag { - ASF_SINGLE1 = 1 << 0, - ASF_SINGLE2 = 1 << 1, - ASF_SINGLE3 = 1 << 2, - ASF_DOUBLE = ASF_SINGLE2 | ASF_SINGLE3, - ASF_TRIPLE = ASF_SINGLE1 | ASF_DOUBLE, - ASF_INSERT = 1 << 3, - ASF_REMOVE = 1 << 4, - ASF_MODIFY = 1 << 5, - ASF_CTR = 1 << 6, - ASF_HIT = 1 << 7, -}; - -struct mlx5hws_action_default_stc { - struct mlx5hws_pool_chunk nop_ctr; - struct mlx5hws_pool_chunk nop_dw5; - struct mlx5hws_pool_chunk nop_dw6; - struct mlx5hws_pool_chunk nop_dw7; - struct mlx5hws_pool_chunk default_hit; - u32 refcount; -}; - -struct mlx5hws_action_shared_stc { - struct mlx5hws_pool_chunk stc_chunk; - u32 refcount; -}; - -struct mlx5hws_actions_apply_data { - struct mlx5hws_send_engine *queue; - struct mlx5hws_rule_action *rule_action; - __be32 *wqe_data; - struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; - u32 jump_to_action_stc; - struct mlx5hws_context_common_res *common_res; - enum mlx5hws_table_type tbl_type; - u32 next_direct_idx; - u8 require_dep; -}; - -struct mlx5hws_actions_wqe_setter; - -typedef void (*mlx5hws_action_setter_fp)(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter); - -struct mlx5hws_actions_wqe_setter { - mlx5hws_action_setter_fp set_single; - mlx5hws_action_setter_fp set_double; - mlx5hws_action_setter_fp set_triple; - mlx5hws_action_setter_fp set_hit; - mlx5hws_action_setter_fp set_ctr; - u8 idx_single; - u8 idx_double; - u8 idx_triple; - u8 idx_ctr; - u8 idx_hit; - u8 stage_idx; - u8 flags; -}; - -struct mlx5hws_action_template { - struct mlx5hws_actions_wqe_setter setters[MLX5HWS_ACTION_MAX_STE]; - enum mlx5hws_action_type *action_type_arr; - u8 num_of_action_stes; - u8 num_actions; - u8 only_term; -}; - -struct mlx5hws_action { - u8 type; - u8 flags; - struct mlx5hws_context *ctx; - union { - struct { - struct mlx5hws_pool_chunk stc[MLX5HWS_TABLE_TYPE_MAX]; - union { - struct { - u32 pat_id; - u32 arg_id; - __be64 single_action; - u32 nope_locations; - u8 num_of_patterns; - u8 single_action_type; - u8 num_of_actions; - u8 max_num_of_actions; - u8 require_reparse; - } modify_header; - struct { - u32 arg_id; - u32 header_size; - u16 max_hdr_sz; - u8 num_of_hdrs; - u8 anchor; - u8 e_anchor; - u8 offset; - bool encap; - u8 require_reparse; - } reformat; - struct { - u32 obj_id; - u8 return_reg_id; - } aso; - struct { - u16 vport_num; - u16 esw_owner_vhca_id; - bool esw_owner_vhca_id_valid; - } vport; - struct { - u32 obj_id; - } dest_obj; - struct { - struct mlx5hws_cmd_forward_tbl *fw_island; - size_t num_dest; - struct mlx5hws_cmd_set_fte_dest *dest_list; - } dest_array; - struct { - u8 type; - u8 start_anchor; - u8 end_anchor; - u8 num_of_words; - bool decap; - } insert_hdr; - struct { - /* PRM start anchor from which header will be removed */ - u8 anchor; - /* Header remove offset in bytes, from the start - * anchor to the location where remove header starts. - */ - u8 offset; - /* Indicates the removed header size in bytes */ - size_t size; - } remove_header; - struct { - struct mlx5hws_matcher_action_ste *table_ste; - struct mlx5hws_action *hit_ft_action; - struct mlx5hws_definer *definer; - } range; - }; - }; - - struct ibv_flow_action *flow_action; - u32 obj_id; - struct ibv_qp *qp; - }; -}; - -const char *mlx5hws_action_type_to_str(enum mlx5hws_action_type action_type); - -int mlx5hws_action_get_default_stc(struct mlx5hws_context *ctx, - u8 tbl_type); - -void mlx5hws_action_put_default_stc(struct mlx5hws_context *ctx, - u8 tbl_type); - -void mlx5hws_action_prepare_decap_l3_data(u8 *src, u8 *dst, - u16 num_of_actions); - -int mlx5hws_action_template_process(struct mlx5hws_action_template *at); - -bool mlx5hws_action_check_combo(struct mlx5hws_context *ctx, - enum mlx5hws_action_type *user_actions, - enum mlx5hws_table_type table_type); - -int mlx5hws_action_alloc_single_stc(struct mlx5hws_context *ctx, - struct mlx5hws_cmd_stc_modify_attr *stc_attr, - u32 table_type, - struct mlx5hws_pool_chunk *stc); - -void mlx5hws_action_free_single_stc(struct mlx5hws_context *ctx, - u32 table_type, - struct mlx5hws_pool_chunk *stc); - -static inline void -mlx5hws_action_setter_default_single(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = - htonl(apply->common_res->default_stc->nop_dw5.offset); -} - -static inline void -mlx5hws_action_setter_default_double(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = - htonl(apply->common_res->default_stc->nop_dw6.offset); - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = - htonl(apply->common_res->default_stc->nop_dw7.offset); -} - -static inline void -mlx5hws_action_setter_default_ctr(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter) -{ - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW0] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] = - htonl(apply->common_res->default_stc->nop_ctr.offset); -} - -static inline void -mlx5hws_action_apply_setter(struct mlx5hws_actions_apply_data *apply, - struct mlx5hws_actions_wqe_setter *setter, - bool is_jumbo) -{ - u8 num_of_actions; - - /* Set control counter */ - if (setter->set_ctr) - setter->set_ctr(apply, setter); - else - mlx5hws_action_setter_default_ctr(apply, setter); - - if (!is_jumbo) { - if (unlikely(setter->set_triple)) { - /* Set triple on match */ - setter->set_triple(apply, setter); - num_of_actions = MLX5HWS_ACTION_STC_IDX_LAST_COMBO3; - } else { - /* Set single and double on match */ - if (setter->set_single) - setter->set_single(apply, setter); - else - mlx5hws_action_setter_default_single(apply, setter); - - if (setter->set_double) - setter->set_double(apply, setter); - else - mlx5hws_action_setter_default_double(apply, setter); - - num_of_actions = setter->set_double ? - MLX5HWS_ACTION_STC_IDX_LAST_COMBO1 : - MLX5HWS_ACTION_STC_IDX_LAST_COMBO2; - } - } else { - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW5] = 0; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW6] = 0; - apply->wqe_data[MLX5HWS_ACTION_OFFSET_DW7] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW5] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW6] = 0; - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_DW7] = 0; - num_of_actions = MLX5HWS_ACTION_STC_IDX_LAST_JUMBO_STE; - } - - /* Set next/final hit action */ - setter->set_hit(apply, setter); - - /* Set number of actions */ - apply->wqe_ctrl->stc_ix[MLX5HWS_ACTION_STC_IDX_CTRL] |= - htonl(num_of_actions << 29); -} - -#endif /* MLX5HWS_ACTION_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.c deleted file mode 100644 index e6ed66202a4040..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.c +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" -#include "mlx5hws_buddy.h" - -static int hws_buddy_init(struct mlx5hws_buddy_mem *buddy, u32 max_order) -{ - int i, s, ret = 0; - - buddy->max_order = max_order; - - buddy->bitmap = kcalloc(buddy->max_order + 1, - sizeof(*buddy->bitmap), - GFP_KERNEL); - if (!buddy->bitmap) - return -ENOMEM; - - buddy->num_free = kcalloc(buddy->max_order + 1, - sizeof(*buddy->num_free), - GFP_KERNEL); - if (!buddy->num_free) { - ret = -ENOMEM; - goto err_out_free_bits; - } - - for (i = 0; i <= (int)buddy->max_order; ++i) { - s = 1 << (buddy->max_order - i); - - buddy->bitmap[i] = bitmap_zalloc(s, GFP_KERNEL); - if (!buddy->bitmap[i]) { - ret = -ENOMEM; - goto err_out_free_num_free; - } - } - - bitmap_set(buddy->bitmap[buddy->max_order], 0, 1); - buddy->num_free[buddy->max_order] = 1; - - return 0; - -err_out_free_num_free: - for (i = 0; i <= (int)buddy->max_order; ++i) - bitmap_free(buddy->bitmap[i]); - - kfree(buddy->num_free); - -err_out_free_bits: - kfree(buddy->bitmap); - return ret; -} - -struct mlx5hws_buddy_mem *mlx5hws_buddy_create(u32 max_order) -{ - struct mlx5hws_buddy_mem *buddy; - - buddy = kzalloc(sizeof(*buddy), GFP_KERNEL); - if (!buddy) - return NULL; - - if (hws_buddy_init(buddy, max_order)) - goto free_buddy; - - return buddy; - -free_buddy: - kfree(buddy); - return NULL; -} - -void mlx5hws_buddy_cleanup(struct mlx5hws_buddy_mem *buddy) -{ - int i; - - for (i = 0; i <= (int)buddy->max_order; ++i) - bitmap_free(buddy->bitmap[i]); - - kfree(buddy->num_free); - kfree(buddy->bitmap); -} - -static int hws_buddy_find_free_seg(struct mlx5hws_buddy_mem *buddy, - u32 start_order, - u32 *segment, - u32 *order) -{ - unsigned int seg, order_iter, m; - - for (order_iter = start_order; - order_iter <= buddy->max_order; ++order_iter) { - if (!buddy->num_free[order_iter]) - continue; - - m = 1 << (buddy->max_order - order_iter); - seg = find_first_bit(buddy->bitmap[order_iter], m); - - if (WARN(seg >= m, - "ICM Buddy: failed finding free mem for order %d\n", - order_iter)) - return -ENOMEM; - - break; - } - - if (order_iter > buddy->max_order) - return -ENOMEM; - - *segment = seg; - *order = order_iter; - return 0; -} - -int mlx5hws_buddy_alloc_mem(struct mlx5hws_buddy_mem *buddy, u32 order) -{ - u32 seg, order_iter, err; - - err = hws_buddy_find_free_seg(buddy, order, &seg, &order_iter); - if (err) - return err; - - bitmap_clear(buddy->bitmap[order_iter], seg, 1); - --buddy->num_free[order_iter]; - - while (order_iter > order) { - --order_iter; - seg <<= 1; - bitmap_set(buddy->bitmap[order_iter], seg ^ 1, 1); - ++buddy->num_free[order_iter]; - } - - seg <<= order; - - return seg; -} - -void mlx5hws_buddy_free_mem(struct mlx5hws_buddy_mem *buddy, u32 seg, u32 order) -{ - seg >>= order; - - while (test_bit(seg ^ 1, buddy->bitmap[order])) { - bitmap_clear(buddy->bitmap[order], seg ^ 1, 1); - --buddy->num_free[order]; - seg >>= 1; - ++order; - } - - bitmap_set(buddy->bitmap[order], seg, 1); - ++buddy->num_free[order]; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.h deleted file mode 100644 index 338c44bbedaff6..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_buddy.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_BUDDY_H_ -#define MLX5HWS_BUDDY_H_ - -struct mlx5hws_buddy_mem { - unsigned long **bitmap; - unsigned int *num_free; - u32 max_order; -}; - -struct mlx5hws_buddy_mem *mlx5hws_buddy_create(u32 max_order); - -void mlx5hws_buddy_cleanup(struct mlx5hws_buddy_mem *buddy); - -int mlx5hws_buddy_alloc_mem(struct mlx5hws_buddy_mem *buddy, u32 order); - -void mlx5hws_buddy_free_mem(struct mlx5hws_buddy_mem *buddy, u32 seg, u32 order); - -#endif /* MLX5HWS_BUDDY_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.c deleted file mode 100644 index 8f3a6f9d703da4..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.c +++ /dev/null @@ -1,995 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -static u16 hws_bwc_gen_queue_idx(struct mlx5hws_context *ctx) -{ - /* assign random queue */ - return get_random_u8() % mlx5hws_bwc_queues(ctx); -} - -static u16 -hws_bwc_get_burst_th(struct mlx5hws_context *ctx, u16 queue_id) -{ - return min(ctx->send_queue[queue_id].num_entries / 2, - MLX5HWS_BWC_MATCHER_REHASH_BURST_TH); -} - -static struct mutex * -hws_bwc_get_queue_lock(struct mlx5hws_context *ctx, u16 idx) -{ - return &ctx->bwc_send_queue_locks[idx]; -} - -static void hws_bwc_lock_all_queues(struct mlx5hws_context *ctx) -{ - u16 bwc_queues = mlx5hws_bwc_queues(ctx); - struct mutex *queue_lock; /* Protect the queue */ - int i; - - for (i = 0; i < bwc_queues; i++) { - queue_lock = hws_bwc_get_queue_lock(ctx, i); - mutex_lock(queue_lock); - } -} - -static void hws_bwc_unlock_all_queues(struct mlx5hws_context *ctx) -{ - u16 bwc_queues = mlx5hws_bwc_queues(ctx); - struct mutex *queue_lock; /* Protect the queue */ - int i = bwc_queues; - - while (i--) { - queue_lock = hws_bwc_get_queue_lock(ctx, i); - mutex_unlock(queue_lock); - } -} - -static void hws_bwc_matcher_init_attr(struct mlx5hws_matcher_attr *attr, - u32 priority, - u8 size_log) -{ - memset(attr, 0, sizeof(*attr)); - - attr->priority = priority; - attr->optimize_using_rule_idx = 0; - attr->mode = MLX5HWS_MATCHER_RESOURCE_MODE_RULE; - attr->optimize_flow_src = MLX5HWS_MATCHER_FLOW_SRC_ANY; - attr->insert_mode = MLX5HWS_MATCHER_INSERT_BY_HASH; - attr->distribute_mode = MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH; - attr->rule.num_log = size_log; - attr->resizable = true; - attr->max_num_of_at_attach = MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM; -} - -int mlx5hws_bwc_matcher_create_simple(struct mlx5hws_bwc_matcher *bwc_matcher, - struct mlx5hws_table *table, - u32 priority, - u8 match_criteria_enable, - struct mlx5hws_match_parameters *mask, - enum mlx5hws_action_type action_types[]) -{ - enum mlx5hws_action_type init_action_types[1] = { MLX5HWS_ACTION_TYP_LAST }; - struct mlx5hws_context *ctx = table->ctx; - u16 bwc_queues = mlx5hws_bwc_queues(ctx); - struct mlx5hws_matcher_attr attr = {0}; - int i; - - bwc_matcher->rules = kcalloc(bwc_queues, sizeof(*bwc_matcher->rules), GFP_KERNEL); - if (!bwc_matcher->rules) - goto err; - - for (i = 0; i < bwc_queues; i++) - INIT_LIST_HEAD(&bwc_matcher->rules[i]); - - hws_bwc_matcher_init_attr(&attr, - priority, - MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG); - - bwc_matcher->priority = priority; - bwc_matcher->size_log = MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG; - - /* create dummy action template */ - bwc_matcher->at[0] = - mlx5hws_action_template_create(action_types ? - action_types : init_action_types); - if (!bwc_matcher->at[0]) { - mlx5hws_err(table->ctx, "BWC matcher: failed creating action template\n"); - goto free_bwc_matcher_rules; - } - - bwc_matcher->num_of_at = 1; - - bwc_matcher->mt = mlx5hws_match_template_create(ctx, - mask->match_buf, - mask->match_sz, - match_criteria_enable); - if (!bwc_matcher->mt) { - mlx5hws_err(table->ctx, "BWC matcher: failed creating match template\n"); - goto free_at; - } - - bwc_matcher->matcher = mlx5hws_matcher_create(table, - &bwc_matcher->mt, 1, - &bwc_matcher->at[0], - bwc_matcher->num_of_at, - &attr); - if (!bwc_matcher->matcher) { - mlx5hws_err(table->ctx, "BWC matcher: failed creating HWS matcher\n"); - goto free_mt; - } - - return 0; - -free_mt: - mlx5hws_match_template_destroy(bwc_matcher->mt); -free_at: - mlx5hws_action_template_destroy(bwc_matcher->at[0]); -free_bwc_matcher_rules: - kfree(bwc_matcher->rules); -err: - return -EINVAL; -} - -struct mlx5hws_bwc_matcher * -mlx5hws_bwc_matcher_create(struct mlx5hws_table *table, - u32 priority, - u8 match_criteria_enable, - struct mlx5hws_match_parameters *mask) -{ - struct mlx5hws_bwc_matcher *bwc_matcher; - bool is_complex; - int ret; - - if (!mlx5hws_context_bwc_supported(table->ctx)) { - mlx5hws_err(table->ctx, - "BWC matcher: context created w/o BWC API compatibility\n"); - return NULL; - } - - bwc_matcher = kzalloc(sizeof(*bwc_matcher), GFP_KERNEL); - if (!bwc_matcher) - return NULL; - - /* Check if the required match params can be all matched - * in single STE, otherwise complex matcher is needed. - */ - - is_complex = mlx5hws_bwc_match_params_is_complex(table->ctx, match_criteria_enable, mask); - if (is_complex) - ret = mlx5hws_bwc_matcher_create_complex(bwc_matcher, - table, - priority, - match_criteria_enable, - mask); - else - ret = mlx5hws_bwc_matcher_create_simple(bwc_matcher, - table, - priority, - match_criteria_enable, - mask, - NULL); - if (ret) - goto free_bwc_matcher; - - return bwc_matcher; - -free_bwc_matcher: - kfree(bwc_matcher); - - return NULL; -} - -int mlx5hws_bwc_matcher_destroy_simple(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - int i; - - mlx5hws_matcher_destroy(bwc_matcher->matcher); - bwc_matcher->matcher = NULL; - - for (i = 0; i < bwc_matcher->num_of_at; i++) - mlx5hws_action_template_destroy(bwc_matcher->at[i]); - - mlx5hws_match_template_destroy(bwc_matcher->mt); - kfree(bwc_matcher->rules); - - return 0; -} - -int mlx5hws_bwc_matcher_destroy(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - if (bwc_matcher->num_of_rules) - mlx5hws_err(bwc_matcher->matcher->tbl->ctx, - "BWC matcher destroy: matcher still has %d rules\n", - bwc_matcher->num_of_rules); - - mlx5hws_bwc_matcher_destroy_simple(bwc_matcher); - - kfree(bwc_matcher); - return 0; -} - -static int hws_bwc_queue_poll(struct mlx5hws_context *ctx, - u16 queue_id, - u32 *pending_rules, - bool drain) -{ - struct mlx5hws_flow_op_result comp[MLX5HWS_BWC_MATCHER_REHASH_BURST_TH]; - u16 burst_th = hws_bwc_get_burst_th(ctx, queue_id); - bool got_comp = *pending_rules >= burst_th; - bool queue_full; - int err = 0; - int ret; - int i; - - /* Check if there are any completions at all */ - if (!got_comp && !drain) - return 0; - - queue_full = mlx5hws_send_engine_full(&ctx->send_queue[queue_id]); - while (queue_full || ((got_comp || drain) && *pending_rules)) { - ret = mlx5hws_send_queue_poll(ctx, queue_id, comp, burst_th); - if (unlikely(ret < 0)) { - mlx5hws_err(ctx, "BWC poll error: polling queue %d returned %d\n", - queue_id, ret); - return -EINVAL; - } - - if (ret) { - (*pending_rules) -= ret; - for (i = 0; i < ret; i++) { - if (unlikely(comp[i].status != MLX5HWS_FLOW_OP_SUCCESS)) { - mlx5hws_err(ctx, - "BWC poll error: polling queue %d returned completion with error\n", - queue_id); - err = -EINVAL; - } - } - queue_full = false; - } - - got_comp = !!ret; - } - - return err; -} - -void -mlx5hws_bwc_rule_fill_attr(struct mlx5hws_bwc_matcher *bwc_matcher, - u16 bwc_queue_idx, - u32 flow_source, - struct mlx5hws_rule_attr *rule_attr) -{ - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - - /* no use of INSERT_BY_INDEX in bwc rule */ - rule_attr->rule_idx = 0; - - /* notify HW at each rule insertion/deletion */ - rule_attr->burst = 0; - - /* We don't need user data, but the API requires it to exist */ - rule_attr->user_data = (void *)0xFACADE; - - rule_attr->queue_id = mlx5hws_bwc_get_queue_id(ctx, bwc_queue_idx); - rule_attr->flow_source = flow_source; -} - -struct mlx5hws_bwc_rule * -mlx5hws_bwc_rule_alloc(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - struct mlx5hws_bwc_rule *bwc_rule; - - bwc_rule = kzalloc(sizeof(*bwc_rule), GFP_KERNEL); - if (unlikely(!bwc_rule)) - goto out_err; - - bwc_rule->rule = kzalloc(sizeof(*bwc_rule->rule), GFP_KERNEL); - if (unlikely(!bwc_rule->rule)) - goto free_rule; - - bwc_rule->bwc_matcher = bwc_matcher; - return bwc_rule; - -free_rule: - kfree(bwc_rule); -out_err: - return NULL; -} - -void mlx5hws_bwc_rule_free(struct mlx5hws_bwc_rule *bwc_rule) -{ - if (likely(bwc_rule->rule)) - kfree(bwc_rule->rule); - kfree(bwc_rule); -} - -static void hws_bwc_rule_list_add(struct mlx5hws_bwc_rule *bwc_rule, u16 idx) -{ - struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; - - bwc_matcher->num_of_rules++; - bwc_rule->bwc_queue_idx = idx; - list_add(&bwc_rule->list_node, &bwc_matcher->rules[idx]); -} - -static void hws_bwc_rule_list_remove(struct mlx5hws_bwc_rule *bwc_rule) -{ - struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; - - bwc_matcher->num_of_rules--; - list_del_init(&bwc_rule->list_node); -} - -static int -hws_bwc_rule_destroy_hws_async(struct mlx5hws_bwc_rule *bwc_rule, - struct mlx5hws_rule_attr *attr) -{ - return mlx5hws_rule_destroy(bwc_rule->rule, attr); -} - -static int -hws_bwc_rule_destroy_hws_sync(struct mlx5hws_bwc_rule *bwc_rule, - struct mlx5hws_rule_attr *rule_attr) -{ - struct mlx5hws_context *ctx = bwc_rule->bwc_matcher->matcher->tbl->ctx; - struct mlx5hws_flow_op_result completion; - int ret; - - ret = hws_bwc_rule_destroy_hws_async(bwc_rule, rule_attr); - if (unlikely(ret)) - return ret; - - do { - ret = mlx5hws_send_queue_poll(ctx, rule_attr->queue_id, &completion, 1); - } while (ret != 1); - - if (unlikely(completion.status != MLX5HWS_FLOW_OP_SUCCESS || - (bwc_rule->rule->status != MLX5HWS_RULE_STATUS_DELETED && - bwc_rule->rule->status != MLX5HWS_RULE_STATUS_DELETING))) { - mlx5hws_err(ctx, "Failed destroying BWC rule: completion %d, rule status %d\n", - completion.status, bwc_rule->rule->status); - return -EINVAL; - } - - return 0; -} - -int mlx5hws_bwc_rule_destroy_simple(struct mlx5hws_bwc_rule *bwc_rule) -{ - struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - u16 idx = bwc_rule->bwc_queue_idx; - struct mlx5hws_rule_attr attr; - struct mutex *queue_lock; /* Protect the queue */ - int ret; - - mlx5hws_bwc_rule_fill_attr(bwc_matcher, idx, 0, &attr); - - queue_lock = hws_bwc_get_queue_lock(ctx, idx); - - mutex_lock(queue_lock); - - ret = hws_bwc_rule_destroy_hws_sync(bwc_rule, &attr); - hws_bwc_rule_list_remove(bwc_rule); - - mutex_unlock(queue_lock); - - return ret; -} - -int mlx5hws_bwc_rule_destroy(struct mlx5hws_bwc_rule *bwc_rule) -{ - int ret; - - ret = mlx5hws_bwc_rule_destroy_simple(bwc_rule); - - mlx5hws_bwc_rule_free(bwc_rule); - return ret; -} - -static int -hws_bwc_rule_create_async(struct mlx5hws_bwc_rule *bwc_rule, - u32 *match_param, - u8 at_idx, - struct mlx5hws_rule_action rule_actions[], - struct mlx5hws_rule_attr *rule_attr) -{ - return mlx5hws_rule_create(bwc_rule->bwc_matcher->matcher, - 0, /* only one match template supported */ - match_param, - at_idx, - rule_actions, - rule_attr, - bwc_rule->rule); -} - -static int -hws_bwc_rule_create_sync(struct mlx5hws_bwc_rule *bwc_rule, - u32 *match_param, - u8 at_idx, - struct mlx5hws_rule_action rule_actions[], - struct mlx5hws_rule_attr *rule_attr) - -{ - struct mlx5hws_context *ctx = bwc_rule->bwc_matcher->matcher->tbl->ctx; - u32 expected_completions = 1; - int ret; - - ret = hws_bwc_rule_create_async(bwc_rule, match_param, - at_idx, rule_actions, - rule_attr); - if (unlikely(ret)) - return ret; - - ret = hws_bwc_queue_poll(ctx, rule_attr->queue_id, &expected_completions, true); - - return ret; -} - -static int -hws_bwc_rule_update_sync(struct mlx5hws_bwc_rule *bwc_rule, - u8 at_idx, - struct mlx5hws_rule_action rule_actions[], - struct mlx5hws_rule_attr *rule_attr) -{ - struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - u32 expected_completions = 1; - int ret; - - ret = mlx5hws_rule_action_update(bwc_rule->rule, - at_idx, - rule_actions, - rule_attr); - if (unlikely(ret)) - return ret; - - ret = hws_bwc_queue_poll(ctx, rule_attr->queue_id, &expected_completions, true); - if (unlikely(ret)) - mlx5hws_err(ctx, "Failed updating BWC rule (%d)\n", ret); - - return ret; -} - -static bool -hws_bwc_matcher_size_maxed_out(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - struct mlx5hws_cmd_query_caps *caps = bwc_matcher->matcher->tbl->ctx->caps; - - return bwc_matcher->size_log + MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH >= - caps->ste_alloc_log_max - 1; -} - -static bool -hws_bwc_matcher_rehash_size_needed(struct mlx5hws_bwc_matcher *bwc_matcher, - u32 num_of_rules) -{ - if (unlikely(hws_bwc_matcher_size_maxed_out(bwc_matcher))) - return false; - - if (unlikely((num_of_rules * 100 / MLX5HWS_BWC_MATCHER_REHASH_PERCENT_TH) >= - (1UL << bwc_matcher->size_log))) - return true; - - return false; -} - -static void -hws_bwc_rule_actions_to_action_types(struct mlx5hws_rule_action rule_actions[], - enum mlx5hws_action_type action_types[]) -{ - int i = 0; - - for (i = 0; - rule_actions[i].action && (rule_actions[i].action->type != MLX5HWS_ACTION_TYP_LAST); - i++) { - action_types[i] = (enum mlx5hws_action_type)rule_actions[i].action->type; - } - - action_types[i] = MLX5HWS_ACTION_TYP_LAST; -} - -static int -hws_bwc_matcher_extend_at(struct mlx5hws_bwc_matcher *bwc_matcher, - struct mlx5hws_rule_action rule_actions[]) -{ - enum mlx5hws_action_type action_types[MLX5HWS_BWC_MAX_ACTS]; - - hws_bwc_rule_actions_to_action_types(rule_actions, action_types); - - bwc_matcher->at[bwc_matcher->num_of_at] = - mlx5hws_action_template_create(action_types); - - if (unlikely(!bwc_matcher->at[bwc_matcher->num_of_at])) - return -ENOMEM; - - bwc_matcher->num_of_at++; - return 0; -} - -static int -hws_bwc_matcher_extend_size(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - struct mlx5hws_cmd_query_caps *caps = ctx->caps; - - if (unlikely(hws_bwc_matcher_size_maxed_out(bwc_matcher))) { - mlx5hws_err(ctx, "Can't resize matcher: depth exceeds limit %d\n", - caps->rtc_log_depth_max); - return -ENOMEM; - } - - bwc_matcher->size_log = - min(bwc_matcher->size_log + MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP, - caps->ste_alloc_log_max - MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH); - - return 0; -} - -static int -hws_bwc_matcher_find_at(struct mlx5hws_bwc_matcher *bwc_matcher, - struct mlx5hws_rule_action rule_actions[]) -{ - enum mlx5hws_action_type *action_type_arr; - int i, j; - - /* start from index 1 - first action template is a dummy */ - for (i = 1; i < bwc_matcher->num_of_at; i++) { - j = 0; - action_type_arr = bwc_matcher->at[i]->action_type_arr; - - while (rule_actions[j].action && - rule_actions[j].action->type != MLX5HWS_ACTION_TYP_LAST) { - if (action_type_arr[j] != rule_actions[j].action->type) - break; - j++; - } - - if (action_type_arr[j] == MLX5HWS_ACTION_TYP_LAST && - (!rule_actions[j].action || - rule_actions[j].action->type == MLX5HWS_ACTION_TYP_LAST)) - return i; - } - - return -1; -} - -static int hws_bwc_matcher_move_all_simple(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - u16 bwc_queues = mlx5hws_bwc_queues(ctx); - struct mlx5hws_bwc_rule **bwc_rules; - struct mlx5hws_rule_attr rule_attr; - u32 *pending_rules; - int i, j, ret = 0; - bool all_done; - u16 burst_th; - - mlx5hws_bwc_rule_fill_attr(bwc_matcher, 0, 0, &rule_attr); - - pending_rules = kcalloc(bwc_queues, sizeof(*pending_rules), GFP_KERNEL); - if (!pending_rules) - return -ENOMEM; - - bwc_rules = kcalloc(bwc_queues, sizeof(*bwc_rules), GFP_KERNEL); - if (!bwc_rules) { - ret = -ENOMEM; - goto free_pending_rules; - } - - for (i = 0; i < bwc_queues; i++) { - if (list_empty(&bwc_matcher->rules[i])) - bwc_rules[i] = NULL; - else - bwc_rules[i] = list_first_entry(&bwc_matcher->rules[i], - struct mlx5hws_bwc_rule, - list_node); - } - - do { - all_done = true; - - for (i = 0; i < bwc_queues; i++) { - rule_attr.queue_id = mlx5hws_bwc_get_queue_id(ctx, i); - burst_th = hws_bwc_get_burst_th(ctx, rule_attr.queue_id); - - for (j = 0; j < burst_th && bwc_rules[i]; j++) { - rule_attr.burst = !!((j + 1) % burst_th); - ret = mlx5hws_matcher_resize_rule_move(bwc_matcher->matcher, - bwc_rules[i]->rule, - &rule_attr); - if (unlikely(ret)) { - mlx5hws_err(ctx, - "Moving BWC rule failed during rehash (%d)\n", - ret); - goto free_bwc_rules; - } - - all_done = false; - pending_rules[i]++; - bwc_rules[i] = list_is_last(&bwc_rules[i]->list_node, - &bwc_matcher->rules[i]) ? - NULL : list_next_entry(bwc_rules[i], list_node); - - ret = hws_bwc_queue_poll(ctx, rule_attr.queue_id, - &pending_rules[i], false); - if (unlikely(ret)) - goto free_bwc_rules; - } - } - } while (!all_done); - - /* drain all the bwc queues */ - for (i = 0; i < bwc_queues; i++) { - if (pending_rules[i]) { - u16 queue_id = mlx5hws_bwc_get_queue_id(ctx, i); - - mlx5hws_send_engine_flush_queue(&ctx->send_queue[queue_id]); - ret = hws_bwc_queue_poll(ctx, queue_id, - &pending_rules[i], true); - if (unlikely(ret)) - goto free_bwc_rules; - } - } - -free_bwc_rules: - kfree(bwc_rules); -free_pending_rules: - kfree(pending_rules); - - return ret; -} - -static int hws_bwc_matcher_move_all(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - return hws_bwc_matcher_move_all_simple(bwc_matcher); -} - -static int hws_bwc_matcher_move(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - struct mlx5hws_matcher_attr matcher_attr = {0}; - struct mlx5hws_matcher *old_matcher; - struct mlx5hws_matcher *new_matcher; - int ret; - - hws_bwc_matcher_init_attr(&matcher_attr, - bwc_matcher->priority, - bwc_matcher->size_log); - - old_matcher = bwc_matcher->matcher; - new_matcher = mlx5hws_matcher_create(old_matcher->tbl, - &bwc_matcher->mt, 1, - bwc_matcher->at, - bwc_matcher->num_of_at, - &matcher_attr); - if (!new_matcher) { - mlx5hws_err(ctx, "Rehash error: matcher creation failed\n"); - return -ENOMEM; - } - - ret = mlx5hws_matcher_resize_set_target(old_matcher, new_matcher); - if (ret) { - mlx5hws_err(ctx, "Rehash error: failed setting resize target\n"); - return ret; - } - - ret = hws_bwc_matcher_move_all(bwc_matcher); - if (ret) { - mlx5hws_err(ctx, "Rehash error: moving rules failed\n"); - return -ENOMEM; - } - - bwc_matcher->matcher = new_matcher; - mlx5hws_matcher_destroy(old_matcher); - - return 0; -} - -static int -hws_bwc_matcher_rehash_size(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - int ret; - - /* If the current matcher size is already at its max size, we can't - * do the rehash. Skip it and try adding the rule again - perhaps - * there was some change. - */ - if (hws_bwc_matcher_size_maxed_out(bwc_matcher)) - return 0; - - /* It is possible that other rule has already performed rehash. - * Need to check again if we really need rehash. - * If the reason for rehash was size, but not any more - skip rehash. - */ - if (!hws_bwc_matcher_rehash_size_needed(bwc_matcher, bwc_matcher->num_of_rules)) - return 0; - - /* Now we're done all the checking - do the rehash: - * - extend match RTC size - * - create new matcher - * - move all the rules to the new matcher - * - destroy the old matcher - */ - - ret = hws_bwc_matcher_extend_size(bwc_matcher); - if (ret) - return ret; - - return hws_bwc_matcher_move(bwc_matcher); -} - -static int -hws_bwc_matcher_rehash_at(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - /* Rehash by action template doesn't require any additional checking. - * The bwc_matcher already contains the new action template. - * Just do the usual rehash: - * - create new matcher - * - move all the rules to the new matcher - * - destroy the old matcher - */ - return hws_bwc_matcher_move(bwc_matcher); -} - -int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, - u32 *match_param, - struct mlx5hws_rule_action rule_actions[], - u32 flow_source, - u16 bwc_queue_idx) -{ - struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - struct mlx5hws_rule_attr rule_attr; - struct mutex *queue_lock; /* Protect the queue */ - u32 num_of_rules; - int ret = 0; - int at_idx; - - mlx5hws_bwc_rule_fill_attr(bwc_matcher, bwc_queue_idx, flow_source, &rule_attr); - - queue_lock = hws_bwc_get_queue_lock(ctx, bwc_queue_idx); - - mutex_lock(queue_lock); - - /* check if rehash needed due to missing action template */ - at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions); - if (unlikely(at_idx < 0)) { - /* we need to extend BWC matcher action templates array */ - mutex_unlock(queue_lock); - hws_bwc_lock_all_queues(ctx); - - ret = hws_bwc_matcher_extend_at(bwc_matcher, rule_actions); - if (unlikely(ret)) { - hws_bwc_unlock_all_queues(ctx); - return ret; - } - - /* action templates array was extended, we need the last idx */ - at_idx = bwc_matcher->num_of_at - 1; - - ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher, - bwc_matcher->at[at_idx]); - if (unlikely(ret)) { - /* Action template attach failed, possibly due to - * requiring more action STEs. - * Need to attempt creating new matcher with all - * the action templates, including the new one. - */ - ret = hws_bwc_matcher_rehash_at(bwc_matcher); - if (unlikely(ret)) { - mlx5hws_action_template_destroy(bwc_matcher->at[at_idx]); - bwc_matcher->at[at_idx] = NULL; - bwc_matcher->num_of_at--; - - hws_bwc_unlock_all_queues(ctx); - - mlx5hws_err(ctx, - "BWC rule insertion: rehash AT failed (%d)\n", ret); - return ret; - } - } - - hws_bwc_unlock_all_queues(ctx); - mutex_lock(queue_lock); - } - - /* check if number of rules require rehash */ - num_of_rules = bwc_matcher->num_of_rules; - - if (unlikely(hws_bwc_matcher_rehash_size_needed(bwc_matcher, num_of_rules))) { - mutex_unlock(queue_lock); - - hws_bwc_lock_all_queues(ctx); - ret = hws_bwc_matcher_rehash_size(bwc_matcher); - hws_bwc_unlock_all_queues(ctx); - - if (ret) { - mlx5hws_err(ctx, "BWC rule insertion: rehash size [%d -> %d] failed (%d)\n", - bwc_matcher->size_log - MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP, - bwc_matcher->size_log, - ret); - return ret; - } - - mutex_lock(queue_lock); - } - - ret = hws_bwc_rule_create_sync(bwc_rule, - match_param, - at_idx, - rule_actions, - &rule_attr); - if (likely(!ret)) { - hws_bwc_rule_list_add(bwc_rule, bwc_queue_idx); - mutex_unlock(queue_lock); - return 0; /* rule inserted successfully */ - } - - /* At this point the rule wasn't added. - * It could be because there was collision, or some other problem. - * If we don't dive deeper than API, the only thing we know is that - * the status of completion is RTE_FLOW_OP_ERROR. - * Try rehash by size and insert rule again - last chance. - */ - - mutex_unlock(queue_lock); - - hws_bwc_lock_all_queues(ctx); - ret = hws_bwc_matcher_rehash_size(bwc_matcher); - hws_bwc_unlock_all_queues(ctx); - - if (ret) { - mlx5hws_err(ctx, "BWC rule insertion: rehash failed (%d)\n", ret); - return ret; - } - - /* Rehash done, but we still have that pesky rule to add */ - mutex_lock(queue_lock); - - ret = hws_bwc_rule_create_sync(bwc_rule, - match_param, - at_idx, - rule_actions, - &rule_attr); - - if (unlikely(ret)) { - mutex_unlock(queue_lock); - mlx5hws_err(ctx, "BWC rule insertion failed (%d)\n", ret); - return ret; - } - - hws_bwc_rule_list_add(bwc_rule, bwc_queue_idx); - mutex_unlock(queue_lock); - - return 0; -} - -struct mlx5hws_bwc_rule * -mlx5hws_bwc_rule_create(struct mlx5hws_bwc_matcher *bwc_matcher, - struct mlx5hws_match_parameters *params, - u32 flow_source, - struct mlx5hws_rule_action rule_actions[]) -{ - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - struct mlx5hws_bwc_rule *bwc_rule; - u16 bwc_queue_idx; - int ret; - - if (unlikely(!mlx5hws_context_bwc_supported(ctx))) { - mlx5hws_err(ctx, "BWC rule: Context created w/o BWC API compatibility\n"); - return NULL; - } - - bwc_rule = mlx5hws_bwc_rule_alloc(bwc_matcher); - if (unlikely(!bwc_rule)) - return NULL; - - bwc_queue_idx = hws_bwc_gen_queue_idx(ctx); - - ret = mlx5hws_bwc_rule_create_simple(bwc_rule, - params->match_buf, - rule_actions, - flow_source, - bwc_queue_idx); - if (unlikely(ret)) { - mlx5hws_bwc_rule_free(bwc_rule); - return NULL; - } - - return bwc_rule; -} - -static int -hws_bwc_rule_action_update(struct mlx5hws_bwc_rule *bwc_rule, - struct mlx5hws_rule_action rule_actions[]) -{ - struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - struct mlx5hws_rule_attr rule_attr; - struct mutex *queue_lock; /* Protect the queue */ - int at_idx, ret; - u16 idx; - - idx = bwc_rule->bwc_queue_idx; - - mlx5hws_bwc_rule_fill_attr(bwc_matcher, idx, 0, &rule_attr); - queue_lock = hws_bwc_get_queue_lock(ctx, idx); - - mutex_lock(queue_lock); - - /* check if rehash needed due to missing action template */ - at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions); - if (unlikely(at_idx < 0)) { - /* we need to extend BWC matcher action templates array */ - mutex_unlock(queue_lock); - hws_bwc_lock_all_queues(ctx); - - /* check again - perhaps other thread already did extend_at */ - at_idx = hws_bwc_matcher_find_at(bwc_matcher, rule_actions); - if (likely(at_idx < 0)) { - ret = hws_bwc_matcher_extend_at(bwc_matcher, rule_actions); - if (unlikely(ret)) { - hws_bwc_unlock_all_queues(ctx); - mlx5hws_err(ctx, "BWC rule update: failed extending AT (%d)", ret); - return -EINVAL; - } - - /* action templates array was extended, we need the last idx */ - at_idx = bwc_matcher->num_of_at - 1; - - ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher, - bwc_matcher->at[at_idx]); - if (unlikely(ret)) { - /* Action template attach failed, possibly due to - * requiring more action STEs. - * Need to attempt creating new matcher with all - * the action templates, including the new one. - */ - ret = hws_bwc_matcher_rehash_at(bwc_matcher); - if (unlikely(ret)) { - mlx5hws_action_template_destroy(bwc_matcher->at[at_idx]); - bwc_matcher->at[at_idx] = NULL; - bwc_matcher->num_of_at--; - - hws_bwc_unlock_all_queues(ctx); - - mlx5hws_err(ctx, - "BWC rule update: rehash AT failed (%d)\n", - ret); - return ret; - } - } - } - - hws_bwc_unlock_all_queues(ctx); - mutex_lock(queue_lock); - } - - ret = hws_bwc_rule_update_sync(bwc_rule, - at_idx, - rule_actions, - &rule_attr); - mutex_unlock(queue_lock); - - if (unlikely(ret)) - mlx5hws_err(ctx, "BWC rule: update failed (%d)\n", ret); - - return ret; -} - -int mlx5hws_bwc_rule_action_update(struct mlx5hws_bwc_rule *bwc_rule, - struct mlx5hws_rule_action rule_actions[]) -{ - struct mlx5hws_bwc_matcher *bwc_matcher = bwc_rule->bwc_matcher; - struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx; - - if (unlikely(!mlx5hws_context_bwc_supported(ctx))) { - mlx5hws_err(ctx, "BWC rule: Context created w/o BWC API compatibility\n"); - return -EINVAL; - } - - return hws_bwc_rule_action_update(bwc_rule, rule_actions); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.h deleted file mode 100644 index 4fe8c32d8fbe86..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_BWC_H_ -#define MLX5HWS_BWC_H_ - -#define MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG 1 -#define MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP 1 -#define MLX5HWS_BWC_MATCHER_REHASH_PERCENT_TH 70 -#define MLX5HWS_BWC_MATCHER_REHASH_BURST_TH 32 -#define MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM 255 - -#define MLX5HWS_BWC_MAX_ACTS 16 - -struct mlx5hws_bwc_matcher { - struct mlx5hws_matcher *matcher; - struct mlx5hws_match_template *mt; - struct mlx5hws_action_template *at[MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM]; - u8 num_of_at; - u16 priority; - u8 size_log; - u32 num_of_rules; /* atomically accessed */ - struct list_head *rules; -}; - -struct mlx5hws_bwc_rule { - struct mlx5hws_bwc_matcher *bwc_matcher; - struct mlx5hws_rule *rule; - u16 bwc_queue_idx; - struct list_head list_node; -}; - -int -mlx5hws_bwc_matcher_create_simple(struct mlx5hws_bwc_matcher *bwc_matcher, - struct mlx5hws_table *table, - u32 priority, - u8 match_criteria_enable, - struct mlx5hws_match_parameters *mask, - enum mlx5hws_action_type action_types[]); - -int mlx5hws_bwc_matcher_destroy_simple(struct mlx5hws_bwc_matcher *bwc_matcher); - -struct mlx5hws_bwc_rule *mlx5hws_bwc_rule_alloc(struct mlx5hws_bwc_matcher *bwc_matcher); - -void mlx5hws_bwc_rule_free(struct mlx5hws_bwc_rule *bwc_rule); - -int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, - u32 *match_param, - struct mlx5hws_rule_action rule_actions[], - u32 flow_source, - u16 bwc_queue_idx); - -int mlx5hws_bwc_rule_destroy_simple(struct mlx5hws_bwc_rule *bwc_rule); - -void mlx5hws_bwc_rule_fill_attr(struct mlx5hws_bwc_matcher *bwc_matcher, - u16 bwc_queue_idx, - u32 flow_source, - struct mlx5hws_rule_attr *rule_attr); - -static inline u16 mlx5hws_bwc_queues(struct mlx5hws_context *ctx) -{ - /* Besides the control queue, half of the queues are - * reguler HWS queues, and the other half are BWC queues. - */ - return (ctx->queues - 1) / 2; -} - -static inline u16 mlx5hws_bwc_get_queue_id(struct mlx5hws_context *ctx, u16 idx) -{ - return idx + mlx5hws_bwc_queues(ctx); -} - -#endif /* MLX5HWS_BWC_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.c deleted file mode 100644 index 601fad5fc54a39..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.c +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -bool mlx5hws_bwc_match_params_is_complex(struct mlx5hws_context *ctx, - u8 match_criteria_enable, - struct mlx5hws_match_parameters *mask) -{ - struct mlx5hws_definer match_layout = {0}; - struct mlx5hws_match_template *mt; - bool is_complex = false; - int ret; - - if (!match_criteria_enable) - return false; /* empty matcher */ - - mt = mlx5hws_match_template_create(ctx, - mask->match_buf, - mask->match_sz, - match_criteria_enable); - if (!mt) { - mlx5hws_err(ctx, "BWC: failed creating match template\n"); - return false; - } - - ret = mlx5hws_definer_calc_layout(ctx, mt, &match_layout); - if (ret) { - /* The only case that we're interested in is E2BIG, - * which means that the match parameters need to be - * split into complex martcher. - * For all other cases (good or bad) - just return true - * and let the usual match creation path handle it, - * both for good and bad flows. - */ - if (ret == -E2BIG) { - is_complex = true; - mlx5hws_dbg(ctx, "Matcher definer layout: need complex matcher\n"); - } else { - mlx5hws_err(ctx, "Failed to calculate matcher definer layout\n"); - } - } - - mlx5hws_match_template_destroy(mt); - - return is_complex; -} - -int mlx5hws_bwc_matcher_create_complex(struct mlx5hws_bwc_matcher *bwc_matcher, - struct mlx5hws_table *table, - u32 priority, - u8 match_criteria_enable, - struct mlx5hws_match_parameters *mask) -{ - mlx5hws_err(table->ctx, "Complex matcher is not supported yet\n"); - return -EOPNOTSUPP; -} - -void -mlx5hws_bwc_matcher_destroy_complex(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - /* nothing to do here */ -} - -int mlx5hws_bwc_rule_create_complex(struct mlx5hws_bwc_rule *bwc_rule, - struct mlx5hws_match_parameters *params, - u32 flow_source, - struct mlx5hws_rule_action rule_actions[], - u16 bwc_queue_idx) -{ - mlx5hws_err(bwc_rule->bwc_matcher->matcher->tbl->ctx, - "Complex rule is not supported yet\n"); - return -EOPNOTSUPP; -} - -int mlx5hws_bwc_rule_destroy_complex(struct mlx5hws_bwc_rule *bwc_rule) -{ - return 0; -} - -int mlx5hws_bwc_matcher_move_all_complex(struct mlx5hws_bwc_matcher *bwc_matcher) -{ - mlx5hws_err(bwc_matcher->matcher->tbl->ctx, - "Moving complex rule is not supported yet\n"); - return -EOPNOTSUPP; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.h deleted file mode 100644 index 068ee811860982..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_bwc_complex.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_BWC_COMPLEX_H_ -#define MLX5HWS_BWC_COMPLEX_H_ - -bool mlx5hws_bwc_match_params_is_complex(struct mlx5hws_context *ctx, - u8 match_criteria_enable, - struct mlx5hws_match_parameters *mask); - -int mlx5hws_bwc_matcher_create_complex(struct mlx5hws_bwc_matcher *bwc_matcher, - struct mlx5hws_table *table, - u32 priority, - u8 match_criteria_enable, - struct mlx5hws_match_parameters *mask); - -void mlx5hws_bwc_matcher_destroy_complex(struct mlx5hws_bwc_matcher *bwc_matcher); - -int mlx5hws_bwc_matcher_move_all_complex(struct mlx5hws_bwc_matcher *bwc_matcher); - -int mlx5hws_bwc_rule_create_complex(struct mlx5hws_bwc_rule *bwc_rule, - struct mlx5hws_match_parameters *params, - u32 flow_source, - struct mlx5hws_rule_action rule_actions[], - u16 bwc_queue_idx); - -int mlx5hws_bwc_rule_destroy_complex(struct mlx5hws_bwc_rule *bwc_rule); - -#endif /* MLX5HWS_BWC_COMPLEX_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c deleted file mode 100644 index 2c7b14172049b3..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.c +++ /dev/null @@ -1,1300 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -static enum mlx5_ifc_flow_destination_type -hws_cmd_dest_type_to_ifc_dest_type(enum mlx5_flow_destination_type type) -{ - switch (type) { - case MLX5_FLOW_DESTINATION_TYPE_VPORT: - return MLX5_IFC_FLOW_DESTINATION_TYPE_VPORT; - case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: - return MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_TABLE; - case MLX5_FLOW_DESTINATION_TYPE_TIR: - return MLX5_IFC_FLOW_DESTINATION_TYPE_TIR; - case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER: - return MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_SAMPLER; - case MLX5_FLOW_DESTINATION_TYPE_UPLINK: - return MLX5_IFC_FLOW_DESTINATION_TYPE_UPLINK; - case MLX5_FLOW_DESTINATION_TYPE_TABLE_TYPE: - return MLX5_IFC_FLOW_DESTINATION_TYPE_TABLE_TYPE; - case MLX5_FLOW_DESTINATION_TYPE_NONE: - case MLX5_FLOW_DESTINATION_TYPE_PORT: - case MLX5_FLOW_DESTINATION_TYPE_COUNTER: - case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: - case MLX5_FLOW_DESTINATION_TYPE_RANGE: - default: - pr_warn("HWS: unknown flow dest type %d\n", type); - return 0; - } -}; - -static int hws_cmd_general_obj_destroy(struct mlx5_core_dev *mdev, - u32 object_type, - u32 object_id) -{ - u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; - - MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, object_type); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, object_id); - - return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); -} - -int mlx5hws_cmd_flow_table_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_ft_create_attr *ft_attr, - u32 *table_id) -{ - u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0}; - u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0}; - void *ft_ctx; - int ret; - - MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE); - MLX5_SET(create_flow_table_in, in, table_type, ft_attr->type); - - ft_ctx = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context); - MLX5_SET(flow_table_context, ft_ctx, level, ft_attr->level); - MLX5_SET(flow_table_context, ft_ctx, rtc_valid, ft_attr->rtc_valid); - MLX5_SET(flow_table_context, ft_ctx, reformat_en, ft_attr->reformat_en); - MLX5_SET(flow_table_context, ft_ctx, decap_en, ft_attr->decap_en); - - ret = mlx5_cmd_exec_inout(mdev, create_flow_table, in, out); - if (ret) - return ret; - - *table_id = MLX5_GET(create_flow_table_out, out, table_id); - - return 0; -} - -int mlx5hws_cmd_flow_table_modify(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_ft_modify_attr *ft_attr, - u32 table_id) -{ - u32 in[MLX5_ST_SZ_DW(modify_flow_table_in)] = {0}; - void *ft_ctx; - - MLX5_SET(modify_flow_table_in, in, opcode, MLX5_CMD_OP_MODIFY_FLOW_TABLE); - MLX5_SET(modify_flow_table_in, in, table_type, ft_attr->type); - MLX5_SET(modify_flow_table_in, in, modify_field_select, ft_attr->modify_fs); - MLX5_SET(modify_flow_table_in, in, table_id, table_id); - - ft_ctx = MLX5_ADDR_OF(modify_flow_table_in, in, flow_table_context); - - MLX5_SET(flow_table_context, ft_ctx, table_miss_action, ft_attr->table_miss_action); - MLX5_SET(flow_table_context, ft_ctx, table_miss_id, ft_attr->table_miss_id); - MLX5_SET(flow_table_context, ft_ctx, hws.rtc_id_0, ft_attr->rtc_id_0); - MLX5_SET(flow_table_context, ft_ctx, hws.rtc_id_1, ft_attr->rtc_id_1); - - return mlx5_cmd_exec_in(mdev, modify_flow_table, in); -} - -int mlx5hws_cmd_flow_table_query(struct mlx5_core_dev *mdev, - u32 table_id, - struct mlx5hws_cmd_ft_query_attr *ft_attr, - u64 *icm_addr_0, u64 *icm_addr_1) -{ - u32 out[MLX5_ST_SZ_DW(query_flow_table_out)] = {0}; - u32 in[MLX5_ST_SZ_DW(query_flow_table_in)] = {0}; - void *ft_ctx; - int ret; - - MLX5_SET(query_flow_table_in, in, opcode, MLX5_CMD_OP_QUERY_FLOW_TABLE); - MLX5_SET(query_flow_table_in, in, table_type, ft_attr->type); - MLX5_SET(query_flow_table_in, in, table_id, table_id); - - ret = mlx5_cmd_exec_inout(mdev, query_flow_table, in, out); - if (ret) - return ret; - - ft_ctx = MLX5_ADDR_OF(query_flow_table_out, out, flow_table_context); - *icm_addr_0 = MLX5_GET64(flow_table_context, ft_ctx, sws.sw_owner_icm_root_0); - *icm_addr_1 = MLX5_GET64(flow_table_context, ft_ctx, sws.sw_owner_icm_root_1); - - return ret; -} - -int mlx5hws_cmd_flow_table_destroy(struct mlx5_core_dev *mdev, - u8 fw_ft_type, u32 table_id) -{ - u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {0}; - - MLX5_SET(destroy_flow_table_in, in, opcode, MLX5_CMD_OP_DESTROY_FLOW_TABLE); - MLX5_SET(destroy_flow_table_in, in, table_type, fw_ft_type); - MLX5_SET(destroy_flow_table_in, in, table_id, table_id); - - return mlx5_cmd_exec_in(mdev, destroy_flow_table, in); -} - -void mlx5hws_cmd_alias_flow_table_destroy(struct mlx5_core_dev *mdev, - u32 table_id) -{ - hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_FT_ALIAS, table_id); -} - -static int hws_cmd_flow_group_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_fg_attr *fg_attr, - u32 *group_id) -{ - u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {0}; - int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); - u32 *in; - int ret; - - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP); - MLX5_SET(create_flow_group_in, in, table_type, fg_attr->table_type); - MLX5_SET(create_flow_group_in, in, table_id, fg_attr->table_id); - - ret = mlx5_cmd_exec_inout(mdev, create_flow_group, in, out); - if (ret) - goto out; - - *group_id = MLX5_GET(create_flow_group_out, out, group_id); - -out: - kvfree(in); - return ret; -} - -static int hws_cmd_flow_group_destroy(struct mlx5_core_dev *mdev, - u32 ft_id, u32 fg_id, u8 ft_type) -{ - u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {}; - - MLX5_SET(destroy_flow_group_in, in, opcode, MLX5_CMD_OP_DESTROY_FLOW_GROUP); - MLX5_SET(destroy_flow_group_in, in, table_type, ft_type); - MLX5_SET(destroy_flow_group_in, in, table_id, ft_id); - MLX5_SET(destroy_flow_group_in, in, group_id, fg_id); - - return mlx5_cmd_exec_in(mdev, destroy_flow_group, in); -} - -int mlx5hws_cmd_set_fte(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id, - u32 group_id, - struct mlx5hws_cmd_set_fte_attr *fte_attr) -{ - u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {0}; - void *in_flow_context; - u32 dest_entry_sz; - u32 total_dest_sz; - u32 action_flags; - u8 *in_dests; - u32 inlen; - u32 *in; - int ret; - u32 i; - - dest_entry_sz = fte_attr->extended_dest ? - MLX5_ST_SZ_BYTES(extended_dest_format) : - MLX5_ST_SZ_BYTES(dest_format); - total_dest_sz = dest_entry_sz * fte_attr->dests_num; - inlen = align((MLX5_ST_SZ_BYTES(set_fte_in) + total_dest_sz), DW_SIZE); - in = kzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); - MLX5_SET(set_fte_in, in, table_type, table_type); - MLX5_SET(set_fte_in, in, table_id, table_id); - - in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); - MLX5_SET(flow_context, in_flow_context, group_id, group_id); - MLX5_SET(flow_context, in_flow_context, flow_source, fte_attr->flow_source); - MLX5_SET(flow_context, in_flow_context, extended_destination, fte_attr->extended_dest); - MLX5_SET(set_fte_in, in, ignore_flow_level, fte_attr->ignore_flow_level); - - action_flags = fte_attr->action_flags; - MLX5_SET(flow_context, in_flow_context, action, action_flags); - - if (action_flags & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { - MLX5_SET(flow_context, in_flow_context, - packet_reformat_id, fte_attr->packet_reformat_id); - } - - if (action_flags & (MLX5_FLOW_CONTEXT_ACTION_DECRYPT | MLX5_FLOW_CONTEXT_ACTION_ENCRYPT)) { - MLX5_SET(flow_context, in_flow_context, - encrypt_decrypt_type, fte_attr->encrypt_decrypt_type); - MLX5_SET(flow_context, in_flow_context, - encrypt_decrypt_obj_id, fte_attr->encrypt_decrypt_obj_id); - } - - if (action_flags & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { - in_dests = (u8 *)MLX5_ADDR_OF(flow_context, in_flow_context, destination); - - for (i = 0; i < fte_attr->dests_num; i++) { - struct mlx5hws_cmd_set_fte_dest *dest = &fte_attr->dests[i]; - enum mlx5_ifc_flow_destination_type ifc_dest_type = - hws_cmd_dest_type_to_ifc_dest_type(dest->destination_type); - - switch (dest->destination_type) { - case MLX5_FLOW_DESTINATION_TYPE_VPORT: - if (dest->ext_flags & MLX5HWS_CMD_EXT_DEST_ESW_OWNER_VHCA_ID) { - MLX5_SET(dest_format, in_dests, - destination_eswitch_owner_vhca_id_valid, 1); - MLX5_SET(dest_format, in_dests, - destination_eswitch_owner_vhca_id, - dest->esw_owner_vhca_id); - } - fallthrough; - case MLX5_FLOW_DESTINATION_TYPE_TIR: - case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: - MLX5_SET(dest_format, in_dests, destination_type, ifc_dest_type); - MLX5_SET(dest_format, in_dests, destination_id, - dest->destination_id); - if (dest->ext_flags & MLX5HWS_CMD_EXT_DEST_REFORMAT) { - MLX5_SET(dest_format, in_dests, packet_reformat, 1); - MLX5_SET(extended_dest_format, in_dests, packet_reformat_id, - dest->ext_reformat_id); - } - break; - default: - ret = -EOPNOTSUPP; - goto out; - } - - in_dests = in_dests + dest_entry_sz; - } - MLX5_SET(flow_context, in_flow_context, destination_list_size, fte_attr->dests_num); - } - - ret = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); - if (ret) - mlx5_core_err(mdev, "Failed creating FLOW_TABLE_ENTRY\n"); - -out: - kfree(in); - return ret; -} - -int mlx5hws_cmd_delete_fte(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id) -{ - u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {}; - - MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); - MLX5_SET(delete_fte_in, in, table_type, table_type); - MLX5_SET(delete_fte_in, in, table_id, table_id); - - return mlx5_cmd_exec_in(mdev, delete_fte, in); -} - -struct mlx5hws_cmd_forward_tbl * -mlx5hws_cmd_forward_tbl_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_ft_create_attr *ft_attr, - struct mlx5hws_cmd_set_fte_attr *fte_attr) -{ - struct mlx5hws_cmd_fg_attr fg_attr = {0}; - struct mlx5hws_cmd_forward_tbl *tbl; - int ret; - - tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); - if (!tbl) - return NULL; - - ret = mlx5hws_cmd_flow_table_create(mdev, ft_attr, &tbl->ft_id); - if (ret) { - mlx5_core_err(mdev, "Failed to create FT\n"); - goto free_tbl; - } - - fg_attr.table_id = tbl->ft_id; - fg_attr.table_type = ft_attr->type; - - ret = hws_cmd_flow_group_create(mdev, &fg_attr, &tbl->fg_id); - if (ret) { - mlx5_core_err(mdev, "Failed to create FG\n"); - goto free_ft; - } - - ret = mlx5hws_cmd_set_fte(mdev, ft_attr->type, - tbl->ft_id, tbl->fg_id, fte_attr); - if (ret) { - mlx5_core_err(mdev, "Failed to create FTE\n"); - goto free_fg; - } - - tbl->type = ft_attr->type; - return tbl; - -free_fg: - hws_cmd_flow_group_destroy(mdev, tbl->ft_id, tbl->fg_id, ft_attr->type); -free_ft: - mlx5hws_cmd_flow_table_destroy(mdev, ft_attr->type, tbl->ft_id); -free_tbl: - kfree(tbl); - return NULL; -} - -void mlx5hws_cmd_forward_tbl_destroy(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_forward_tbl *tbl) -{ - mlx5hws_cmd_delete_fte(mdev, tbl->type, tbl->ft_id); - hws_cmd_flow_group_destroy(mdev, tbl->ft_id, tbl->fg_id, tbl->type); - mlx5hws_cmd_flow_table_destroy(mdev, tbl->type, tbl->ft_id); - kfree(tbl); -} - -void mlx5hws_cmd_set_attr_connect_miss_tbl(struct mlx5hws_context *ctx, - u32 fw_ft_type, - enum mlx5hws_table_type type, - struct mlx5hws_cmd_ft_modify_attr *ft_attr) -{ - u32 default_miss_tbl; - - if (type != MLX5HWS_TABLE_TYPE_FDB) - return; - - ft_attr->modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION; - ft_attr->type = fw_ft_type; - ft_attr->table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL; - - default_miss_tbl = ctx->common_res[type].default_miss->ft_id; - if (!default_miss_tbl) { - pr_warn("HWS: no flow table ID for default miss\n"); - return; - } - - ft_attr->table_miss_id = default_miss_tbl; -} - -int mlx5hws_cmd_rtc_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_rtc_create_attr *rtc_attr, - u32 *rtc_id) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; - u32 in[MLX5_ST_SZ_DW(create_rtc_in)] = {0}; - void *attr; - int ret; - - attr = MLX5_ADDR_OF(create_rtc_in, in, hdr); - MLX5_SET(general_obj_in_cmd_hdr, - attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, - attr, obj_type, MLX5_OBJ_TYPE_RTC); - - attr = MLX5_ADDR_OF(create_rtc_in, in, rtc); - MLX5_SET(rtc, attr, ste_format_0, rtc_attr->is_frst_jumbo ? - MLX5_IFC_RTC_STE_FORMAT_11DW : - MLX5_IFC_RTC_STE_FORMAT_8DW); - - if (rtc_attr->is_scnd_range) { - MLX5_SET(rtc, attr, ste_format_1, MLX5_IFC_RTC_STE_FORMAT_RANGE); - MLX5_SET(rtc, attr, num_match_ste, 2); - } - - MLX5_SET(rtc, attr, pd, rtc_attr->pd); - MLX5_SET(rtc, attr, update_method, rtc_attr->fw_gen_wqe); - MLX5_SET(rtc, attr, update_index_mode, rtc_attr->update_index_mode); - MLX5_SET(rtc, attr, access_index_mode, rtc_attr->access_index_mode); - MLX5_SET(rtc, attr, num_hash_definer, rtc_attr->num_hash_definer); - MLX5_SET(rtc, attr, log_depth, rtc_attr->log_depth); - MLX5_SET(rtc, attr, log_hash_size, rtc_attr->log_size); - MLX5_SET(rtc, attr, table_type, rtc_attr->table_type); - MLX5_SET(rtc, attr, num_hash_definer, rtc_attr->num_hash_definer); - MLX5_SET(rtc, attr, match_definer_0, rtc_attr->match_definer_0); - MLX5_SET(rtc, attr, match_definer_1, rtc_attr->match_definer_1); - MLX5_SET(rtc, attr, stc_id, rtc_attr->stc_base); - MLX5_SET(rtc, attr, ste_table_base_id, rtc_attr->ste_base); - MLX5_SET(rtc, attr, ste_table_offset, rtc_attr->ste_offset); - MLX5_SET(rtc, attr, miss_flow_table_id, rtc_attr->miss_ft_id); - MLX5_SET(rtc, attr, reparse_mode, rtc_attr->reparse_mode); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to create RTC\n"); - goto out; - } - - *rtc_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); -out: - return ret; -} - -void mlx5hws_cmd_rtc_destroy(struct mlx5_core_dev *mdev, u32 rtc_id) -{ - hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_RTC, rtc_id); -} - -int mlx5hws_cmd_stc_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_stc_create_attr *stc_attr, - u32 *stc_id) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; - u32 in[MLX5_ST_SZ_DW(create_stc_in)] = {0}; - void *attr; - int ret; - - attr = MLX5_ADDR_OF(create_stc_in, in, hdr); - MLX5_SET(general_obj_in_cmd_hdr, - attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, - attr, obj_type, MLX5_OBJ_TYPE_STC); - MLX5_SET(general_obj_in_cmd_hdr, - attr, op_param.create.log_obj_range, stc_attr->log_obj_range); - - attr = MLX5_ADDR_OF(create_stc_in, in, stc); - MLX5_SET(stc, attr, table_type, stc_attr->table_type); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to create STC\n"); - goto out; - } - - *stc_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); -out: - return ret; -} - -void mlx5hws_cmd_stc_destroy(struct mlx5_core_dev *mdev, u32 stc_id) -{ - hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_STC, stc_id); -} - -static int -hws_cmd_stc_modify_set_stc_param(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_stc_modify_attr *stc_attr, - void *stc_param) -{ - switch (stc_attr->action_type) { - case MLX5_IFC_STC_ACTION_TYPE_COUNTER: - MLX5_SET(stc_ste_param_flow_counter, stc_param, flow_counter_id, stc_attr->id); - break; - case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR: - MLX5_SET(stc_ste_param_tir, stc_param, tirn, stc_attr->dest_tir_num); - break; - case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT: - MLX5_SET(stc_ste_param_table, stc_param, table_id, stc_attr->dest_table_id); - break; - case MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST: - MLX5_SET(stc_ste_param_header_modify_list, stc_param, - header_modify_pattern_id, stc_attr->modify_header.pattern_id); - MLX5_SET(stc_ste_param_header_modify_list, stc_param, - header_modify_argument_id, stc_attr->modify_header.arg_id); - break; - case MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE: - MLX5_SET(stc_ste_param_remove, stc_param, action_type, - MLX5_MODIFICATION_TYPE_REMOVE); - MLX5_SET(stc_ste_param_remove, stc_param, decap, - stc_attr->remove_header.decap); - MLX5_SET(stc_ste_param_remove, stc_param, remove_start_anchor, - stc_attr->remove_header.start_anchor); - MLX5_SET(stc_ste_param_remove, stc_param, remove_end_anchor, - stc_attr->remove_header.end_anchor); - break; - case MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT: - MLX5_SET(stc_ste_param_insert, stc_param, action_type, - MLX5_MODIFICATION_TYPE_INSERT); - MLX5_SET(stc_ste_param_insert, stc_param, encap, - stc_attr->insert_header.encap); - MLX5_SET(stc_ste_param_insert, stc_param, inline_data, - stc_attr->insert_header.is_inline); - MLX5_SET(stc_ste_param_insert, stc_param, insert_anchor, - stc_attr->insert_header.insert_anchor); - /* HW gets the next 2 sizes in words */ - MLX5_SET(stc_ste_param_insert, stc_param, insert_size, - stc_attr->insert_header.header_size / W_SIZE); - MLX5_SET(stc_ste_param_insert, stc_param, insert_offset, - stc_attr->insert_header.insert_offset / W_SIZE); - MLX5_SET(stc_ste_param_insert, stc_param, insert_argument, - stc_attr->insert_header.arg_id); - break; - case MLX5_IFC_STC_ACTION_TYPE_COPY: - case MLX5_IFC_STC_ACTION_TYPE_SET: - case MLX5_IFC_STC_ACTION_TYPE_ADD: - case MLX5_IFC_STC_ACTION_TYPE_ADD_FIELD: - *(__be64 *)stc_param = stc_attr->modify_action.data; - break; - case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT: - case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK: - MLX5_SET(stc_ste_param_vport, stc_param, vport_number, - stc_attr->vport.vport_num); - MLX5_SET(stc_ste_param_vport, stc_param, eswitch_owner_vhca_id, - stc_attr->vport.esw_owner_vhca_id); - MLX5_SET(stc_ste_param_vport, stc_param, eswitch_owner_vhca_id_valid, - stc_attr->vport.eswitch_owner_vhca_id_valid); - break; - case MLX5_IFC_STC_ACTION_TYPE_DROP: - case MLX5_IFC_STC_ACTION_TYPE_NOP: - case MLX5_IFC_STC_ACTION_TYPE_TAG: - case MLX5_IFC_STC_ACTION_TYPE_ALLOW: - break; - case MLX5_IFC_STC_ACTION_TYPE_ASO: - MLX5_SET(stc_ste_param_execute_aso, stc_param, aso_object_id, - stc_attr->aso.devx_obj_id); - MLX5_SET(stc_ste_param_execute_aso, stc_param, return_reg_id, - stc_attr->aso.return_reg_id); - MLX5_SET(stc_ste_param_execute_aso, stc_param, aso_type, - stc_attr->aso.aso_type); - break; - case MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE: - MLX5_SET(stc_ste_param_ste_table, stc_param, ste_obj_id, - stc_attr->ste_table.ste_obj_id); - MLX5_SET(stc_ste_param_ste_table, stc_param, match_definer_id, - stc_attr->ste_table.match_definer_id); - MLX5_SET(stc_ste_param_ste_table, stc_param, log_hash_size, - stc_attr->ste_table.log_hash_size); - break; - case MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS: - MLX5_SET(stc_ste_param_remove_words, stc_param, action_type, - MLX5_MODIFICATION_TYPE_REMOVE_WORDS); - MLX5_SET(stc_ste_param_remove_words, stc_param, remove_start_anchor, - stc_attr->remove_words.start_anchor); - MLX5_SET(stc_ste_param_remove_words, stc_param, - remove_size, stc_attr->remove_words.num_of_words); - break; - case MLX5_IFC_STC_ACTION_TYPE_CRYPTO_IPSEC_ENCRYPTION: - MLX5_SET(stc_ste_param_ipsec_encrypt, stc_param, ipsec_object_id, - stc_attr->id); - break; - case MLX5_IFC_STC_ACTION_TYPE_CRYPTO_IPSEC_DECRYPTION: - MLX5_SET(stc_ste_param_ipsec_decrypt, stc_param, ipsec_object_id, - stc_attr->id); - break; - case MLX5_IFC_STC_ACTION_TYPE_TRAILER: - MLX5_SET(stc_ste_param_trailer, stc_param, command, - stc_attr->reformat_trailer.op); - MLX5_SET(stc_ste_param_trailer, stc_param, type, - stc_attr->reformat_trailer.type); - MLX5_SET(stc_ste_param_trailer, stc_param, length, - stc_attr->reformat_trailer.size); - break; - default: - mlx5_core_err(mdev, "Not supported type %d\n", stc_attr->action_type); - return -EINVAL; - } - return 0; -} - -int mlx5hws_cmd_stc_modify(struct mlx5_core_dev *mdev, - u32 stc_id, - struct mlx5hws_cmd_stc_modify_attr *stc_attr) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; - u32 in[MLX5_ST_SZ_DW(create_stc_in)] = {0}; - void *stc_param; - void *attr; - int ret; - - attr = MLX5_ADDR_OF(create_stc_in, in, hdr); - MLX5_SET(general_obj_in_cmd_hdr, - attr, opcode, MLX5_CMD_OP_MODIFY_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, - attr, obj_type, MLX5_OBJ_TYPE_STC); - MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, stc_id); - MLX5_SET(general_obj_in_cmd_hdr, in, - op_param.query.obj_offset, stc_attr->stc_offset); - - attr = MLX5_ADDR_OF(create_stc_in, in, stc); - MLX5_SET(stc, attr, ste_action_offset, stc_attr->action_offset); - MLX5_SET(stc, attr, action_type, stc_attr->action_type); - MLX5_SET(stc, attr, reparse_mode, stc_attr->reparse_mode); - MLX5_SET64(stc, attr, modify_field_select, - MLX5_IFC_MODIFY_STC_FIELD_SELECT_NEW_STC); - - /* Set destination TIRN, TAG, FT ID, STE ID */ - stc_param = MLX5_ADDR_OF(stc, attr, stc_param); - ret = hws_cmd_stc_modify_set_stc_param(mdev, stc_attr, stc_param); - if (ret) - return ret; - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) - mlx5_core_err(mdev, "Failed to modify STC FW action_type %d\n", - stc_attr->action_type); - - return ret; -} - -int mlx5hws_cmd_arg_create(struct mlx5_core_dev *mdev, - u16 log_obj_range, - u32 pd, - u32 *arg_id) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; - u32 in[MLX5_ST_SZ_DW(create_arg_in)] = {0}; - void *attr; - int ret; - - attr = MLX5_ADDR_OF(create_arg_in, in, hdr); - MLX5_SET(general_obj_in_cmd_hdr, - attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, - attr, obj_type, MLX5_OBJ_TYPE_HEADER_MODIFY_ARGUMENT); - MLX5_SET(general_obj_in_cmd_hdr, - attr, op_param.create.log_obj_range, log_obj_range); - - attr = MLX5_ADDR_OF(create_arg_in, in, arg); - MLX5_SET(arg, attr, access_pd, pd); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to create ARG\n"); - goto out; - } - - *arg_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); -out: - return ret; -} - -void mlx5hws_cmd_arg_destroy(struct mlx5_core_dev *mdev, - u32 arg_id) -{ - hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_HEADER_MODIFY_ARGUMENT, arg_id); -} - -int mlx5hws_cmd_header_modify_pattern_create(struct mlx5_core_dev *mdev, - u32 pattern_length, - u8 *actions, - u32 *ptrn_id) -{ - u32 in[MLX5_ST_SZ_DW(create_header_modify_pattern_in)] = {0}; - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; - int num_of_actions; - u64 *pattern_data; - void *pattern; - void *attr; - int ret; - int i; - - if (pattern_length > MLX5_MAX_ACTIONS_DATA_IN_HEADER_MODIFY) { - mlx5_core_err(mdev, "Pattern length %d exceeds limit %d\n", - pattern_length, MLX5_MAX_ACTIONS_DATA_IN_HEADER_MODIFY); - return -EINVAL; - } - - attr = MLX5_ADDR_OF(create_header_modify_pattern_in, in, hdr); - MLX5_SET(general_obj_in_cmd_hdr, - attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, - attr, obj_type, MLX5_OBJ_TYPE_MODIFY_HDR_PATTERN); - - pattern = MLX5_ADDR_OF(create_header_modify_pattern_in, in, pattern); - /* Pattern_length is in ddwords */ - MLX5_SET(header_modify_pattern_in, pattern, pattern_length, pattern_length / (2 * DW_SIZE)); - - pattern_data = (u64 *)MLX5_ADDR_OF(header_modify_pattern_in, pattern, pattern_data); - memcpy(pattern_data, actions, pattern_length); - - num_of_actions = pattern_length / MLX5HWS_MODIFY_ACTION_SIZE; - for (i = 0; i < num_of_actions; i++) { - int type; - - type = MLX5_GET(set_action_in, &pattern_data[i], action_type); - if (type != MLX5_MODIFICATION_TYPE_COPY && - type != MLX5_MODIFICATION_TYPE_ADD_FIELD) - /* Action typ-copy use all bytes for control */ - MLX5_SET(set_action_in, &pattern_data[i], data, 0); - } - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to create header_modify_pattern\n"); - goto out; - } - - *ptrn_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); -out: - return ret; -} - -void mlx5hws_cmd_header_modify_pattern_destroy(struct mlx5_core_dev *mdev, - u32 ptrn_id) -{ - hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_MODIFY_HDR_PATTERN, ptrn_id); -} - -int mlx5hws_cmd_ste_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_ste_create_attr *ste_attr, - u32 *ste_id) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; - u32 in[MLX5_ST_SZ_DW(create_ste_in)] = {0}; - void *attr; - int ret; - - attr = MLX5_ADDR_OF(create_ste_in, in, hdr); - MLX5_SET(general_obj_in_cmd_hdr, - attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, - attr, obj_type, MLX5_OBJ_TYPE_STE); - MLX5_SET(general_obj_in_cmd_hdr, - attr, op_param.create.log_obj_range, ste_attr->log_obj_range); - - attr = MLX5_ADDR_OF(create_ste_in, in, ste); - MLX5_SET(ste, attr, table_type, ste_attr->table_type); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to create STE\n"); - goto out; - } - - *ste_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); -out: - return ret; -} - -void mlx5hws_cmd_ste_destroy(struct mlx5_core_dev *mdev, u32 ste_id) -{ - hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_STE, ste_id); -} - -int mlx5hws_cmd_definer_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_definer_create_attr *def_attr, - u32 *definer_id) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; - u32 in[MLX5_ST_SZ_DW(create_definer_in)] = {0}; - void *ptr; - int ret; - - MLX5_SET(general_obj_in_cmd_hdr, - in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, - in, obj_type, MLX5_OBJ_TYPE_MATCH_DEFINER); - - ptr = MLX5_ADDR_OF(create_definer_in, in, definer); - MLX5_SET(definer, ptr, format_id, MLX5_IFC_DEFINER_FORMAT_ID_SELECT); - - MLX5_SET(definer, ptr, format_select_dw0, def_attr->dw_selector[0]); - MLX5_SET(definer, ptr, format_select_dw1, def_attr->dw_selector[1]); - MLX5_SET(definer, ptr, format_select_dw2, def_attr->dw_selector[2]); - MLX5_SET(definer, ptr, format_select_dw3, def_attr->dw_selector[3]); - MLX5_SET(definer, ptr, format_select_dw4, def_attr->dw_selector[4]); - MLX5_SET(definer, ptr, format_select_dw5, def_attr->dw_selector[5]); - MLX5_SET(definer, ptr, format_select_dw6, def_attr->dw_selector[6]); - MLX5_SET(definer, ptr, format_select_dw7, def_attr->dw_selector[7]); - MLX5_SET(definer, ptr, format_select_dw8, def_attr->dw_selector[8]); - - MLX5_SET(definer, ptr, format_select_byte0, def_attr->byte_selector[0]); - MLX5_SET(definer, ptr, format_select_byte1, def_attr->byte_selector[1]); - MLX5_SET(definer, ptr, format_select_byte2, def_attr->byte_selector[2]); - MLX5_SET(definer, ptr, format_select_byte3, def_attr->byte_selector[3]); - MLX5_SET(definer, ptr, format_select_byte4, def_attr->byte_selector[4]); - MLX5_SET(definer, ptr, format_select_byte5, def_attr->byte_selector[5]); - MLX5_SET(definer, ptr, format_select_byte6, def_attr->byte_selector[6]); - MLX5_SET(definer, ptr, format_select_byte7, def_attr->byte_selector[7]); - - ptr = MLX5_ADDR_OF(definer, ptr, match_mask); - memcpy(ptr, def_attr->match_mask, MLX5_FLD_SZ_BYTES(definer, match_mask)); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to create Definer\n"); - goto out; - } - - *definer_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); -out: - return ret; -} - -void mlx5hws_cmd_definer_destroy(struct mlx5_core_dev *mdev, - u32 definer_id) -{ - hws_cmd_general_obj_destroy(mdev, MLX5_OBJ_TYPE_MATCH_DEFINER, definer_id); -} - -int mlx5hws_cmd_packet_reformat_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_packet_reformat_create_attr *attr, - u32 *reformat_id) -{ - u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_out)] = {0}; - size_t insz, cmd_data_sz, cmd_total_sz; - void *prctx; - void *pdata; - void *in; - int ret; - - cmd_total_sz = MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in); - cmd_total_sz += MLX5_ST_SZ_BYTES(packet_reformat_context_in); - cmd_data_sz = MLX5_FLD_SZ_BYTES(packet_reformat_context_in, reformat_data); - insz = align(cmd_total_sz + attr->data_sz - cmd_data_sz, DW_SIZE); - in = kzalloc(insz, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(alloc_packet_reformat_context_in, in, opcode, - MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT); - - prctx = MLX5_ADDR_OF(alloc_packet_reformat_context_in, in, - packet_reformat_context); - pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data); - - MLX5_SET(packet_reformat_context_in, prctx, reformat_type, attr->type); - MLX5_SET(packet_reformat_context_in, prctx, reformat_param_0, attr->reformat_param_0); - MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, attr->data_sz); - memcpy(pdata, attr->data, attr->data_sz); - - ret = mlx5_cmd_exec(mdev, in, insz, out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to create packet reformat\n"); - goto out; - } - - *reformat_id = MLX5_GET(alloc_packet_reformat_out, out, packet_reformat_id); -out: - kfree(in); - return ret; -} - -int mlx5hws_cmd_packet_reformat_destroy(struct mlx5_core_dev *mdev, - u32 reformat_id) -{ - u32 out[MLX5_ST_SZ_DW(dealloc_packet_reformat_out)] = {0}; - u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_in)] = {0}; - int ret; - - MLX5_SET(dealloc_packet_reformat_in, in, opcode, - MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT); - MLX5_SET(dealloc_packet_reformat_in, in, - packet_reformat_id, reformat_id); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) - mlx5_core_err(mdev, "Failed to destroy packet_reformat\n"); - - return ret; -} - -int mlx5hws_cmd_sq_modify_rdy(struct mlx5_core_dev *mdev, u32 sqn) -{ - u32 out[MLX5_ST_SZ_DW(modify_sq_out)] = {0}; - u32 in[MLX5_ST_SZ_DW(modify_sq_in)] = {0}; - void *sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); - int ret; - - MLX5_SET(modify_sq_in, in, opcode, MLX5_CMD_OP_MODIFY_SQ); - MLX5_SET(modify_sq_in, in, sqn, sqn); - MLX5_SET(modify_sq_in, in, sq_state, MLX5_SQC_STATE_RST); - MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RDY); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) - mlx5_core_err(mdev, "Failed to modify SQ\n"); - - return ret; -} - -int mlx5hws_cmd_allow_other_vhca_access(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_allow_other_vhca_access_attr *attr) -{ - u32 out[MLX5_ST_SZ_DW(allow_other_vhca_access_out)] = {0}; - u32 in[MLX5_ST_SZ_DW(allow_other_vhca_access_in)] = {0}; - void *key; - int ret; - - MLX5_SET(allow_other_vhca_access_in, - in, opcode, MLX5_CMD_OP_ALLOW_OTHER_VHCA_ACCESS); - MLX5_SET(allow_other_vhca_access_in, - in, object_type_to_be_accessed, attr->obj_type); - MLX5_SET(allow_other_vhca_access_in, - in, object_id_to_be_accessed, attr->obj_id); - - key = MLX5_ADDR_OF(allow_other_vhca_access_in, in, access_key); - memcpy(key, attr->access_key, sizeof(attr->access_key)); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) - mlx5_core_err(mdev, "Failed to execute ALLOW_OTHER_VHCA_ACCESS command\n"); - - return ret; -} - -int mlx5hws_cmd_alias_obj_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_alias_obj_create_attr *alias_attr, - u32 *obj_id) -{ - u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {0}; - u32 in[MLX5_ST_SZ_DW(create_alias_obj_in)] = {0}; - void *attr; - void *key; - int ret; - - attr = MLX5_ADDR_OF(create_alias_obj_in, in, hdr); - MLX5_SET(general_obj_in_cmd_hdr, - attr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT); - MLX5_SET(general_obj_in_cmd_hdr, - attr, obj_type, alias_attr->obj_type); - MLX5_SET(general_obj_in_cmd_hdr, attr, op_param.create.alias_object, 1); - - attr = MLX5_ADDR_OF(create_alias_obj_in, in, alias_ctx); - MLX5_SET(alias_context, attr, vhca_id_to_be_accessed, alias_attr->vhca_id); - MLX5_SET(alias_context, attr, object_id_to_be_accessed, alias_attr->obj_id); - - key = MLX5_ADDR_OF(alias_context, attr, access_key); - memcpy(key, alias_attr->access_key, sizeof(alias_attr->access_key)); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to create ALIAS OBJ\n"); - goto out; - } - - *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); -out: - return ret; -} - -int mlx5hws_cmd_alias_obj_destroy(struct mlx5_core_dev *mdev, - u16 obj_type, - u32 obj_id) -{ - return hws_cmd_general_obj_destroy(mdev, obj_type, obj_id); -} - -int mlx5hws_cmd_generate_wqe(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_generate_wqe_attr *attr, - struct mlx5_cqe64 *ret_cqe) -{ - u32 out[MLX5_ST_SZ_DW(generate_wqe_out)] = {0}; - u32 in[MLX5_ST_SZ_DW(generate_wqe_in)] = {0}; - u8 status; - void *ptr; - int ret; - - MLX5_SET(generate_wqe_in, in, opcode, MLX5_CMD_OP_GENERATE_WQE); - MLX5_SET(generate_wqe_in, in, pdn, attr->pdn); - - ptr = MLX5_ADDR_OF(generate_wqe_in, in, wqe_ctrl); - memcpy(ptr, attr->wqe_ctrl, MLX5_FLD_SZ_BYTES(generate_wqe_in, wqe_ctrl)); - - ptr = MLX5_ADDR_OF(generate_wqe_in, in, wqe_gta_ctrl); - memcpy(ptr, attr->gta_ctrl, MLX5_FLD_SZ_BYTES(generate_wqe_in, wqe_gta_ctrl)); - - ptr = MLX5_ADDR_OF(generate_wqe_in, in, wqe_gta_data_0); - memcpy(ptr, attr->gta_data_0, MLX5_FLD_SZ_BYTES(generate_wqe_in, wqe_gta_data_0)); - - if (attr->gta_data_1) { - ptr = MLX5_ADDR_OF(generate_wqe_in, in, wqe_gta_data_1); - memcpy(ptr, attr->gta_data_1, MLX5_FLD_SZ_BYTES(generate_wqe_in, wqe_gta_data_1)); - } - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); - if (ret) { - mlx5_core_err(mdev, "Failed to write GTA WQE using FW\n"); - return ret; - } - - status = MLX5_GET(generate_wqe_out, out, status); - if (status) { - mlx5_core_err(mdev, "Invalid FW CQE status %d\n", status); - return -EINVAL; - } - - ptr = MLX5_ADDR_OF(generate_wqe_out, out, cqe_data); - memcpy(ret_cqe, ptr, sizeof(*ret_cqe)); - - return ret; -} - -int mlx5hws_cmd_query_caps(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_query_caps *caps) -{ - u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {0}; - u32 out_size; - u32 *out; - int ret; - - out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); - out = kzalloc(out_size, GFP_KERNEL); - if (!out) - return -ENOMEM; - - MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE | HCA_CAP_OPMOD_GET_CUR); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); - if (ret) { - mlx5_core_err(mdev, "Failed to query device caps\n"); - goto out; - } - - caps->wqe_based_update = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.wqe_based_flow_table_update_cap); - - caps->eswitch_manager = MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.eswitch_manager); - - caps->flex_protocols = MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.flex_parser_protocols); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_GENEVE_TLV_OPTION_0_ENABLED) - caps->flex_parser_id_geneve_tlv_option_0 = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.flex_parser_id_geneve_tlv_option_0); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED) - caps->flex_parser_id_mpls_over_gre = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.flex_parser_id_outer_first_mpls_over_gre); - - if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED) - caps->flex_parser_id_mpls_over_udp = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.flex_parser_id_outer_first_mpls_over_udp_label); - - caps->log_header_modify_argument_granularity = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.log_header_modify_argument_granularity); - - caps->log_header_modify_argument_granularity -= - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.log_header_modify_argument_granularity_offset); - - caps->log_header_modify_argument_max_alloc = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.log_header_modify_argument_max_alloc); - - caps->definer_format_sup = - MLX5_GET64(query_hca_cap_out, out, - capability.cmd_hca_cap.match_definer_format_supported); - - caps->vhca_id = MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.vhca_id); - - caps->sq_ts_format = MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.sq_ts_format); - - caps->ipsec_offload = MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap.ipsec_offload); - - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 | HCA_CAP_OPMOD_GET_CUR); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); - if (ret) { - mlx5_core_err(mdev, "Failed to query device caps 2\n"); - goto out; - } - - caps->full_dw_jumbo_support = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap_2.format_select_dw_8_6_ext); - - caps->format_select_gtpu_dw_0 = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap_2.format_select_dw_gtpu_dw_0); - - caps->format_select_gtpu_dw_1 = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap_2.format_select_dw_gtpu_dw_1); - - caps->format_select_gtpu_dw_2 = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap_2.format_select_dw_gtpu_dw_2); - - caps->format_select_gtpu_ext_dw_0 = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap_2.format_select_dw_gtpu_first_ext_dw_0); - - caps->supp_type_gen_wqe = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap_2.generate_wqe_type); - - caps->flow_table_hash_type = - MLX5_GET(query_hca_cap_out, out, - capability.cmd_hca_cap_2.flow_table_hash_type); - - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_GET_HCA_CAP_OP_MOD_NIC_FLOW_TABLE | HCA_CAP_OPMOD_GET_CUR); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); - if (ret) { - mlx5_core_err(mdev, "Failed to query flow table caps\n"); - goto out; - } - - caps->nic_ft.max_level = - MLX5_GET(query_hca_cap_out, out, - capability.flow_table_nic_cap.flow_table_properties_nic_receive.max_ft_level); - - caps->nic_ft.reparse = - MLX5_GET(query_hca_cap_out, out, - capability.flow_table_nic_cap.flow_table_properties_nic_receive.reparse); - - caps->nic_ft.ignore_flow_level_rtc_valid = - MLX5_GET(query_hca_cap_out, out, - capability.flow_table_nic_cap.flow_table_properties_nic_receive.ignore_flow_level_rtc_valid); - - caps->flex_parser_ok_bits_supp = - MLX5_GET(query_hca_cap_out, out, - capability.flow_table_nic_cap.flow_table_properties_nic_receive.ft_field_support.geneve_tlv_option_0_exist); - - if (caps->wqe_based_update) { - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_GET_HCA_CAP_OP_MOD_WQE_BASED_FLOW_TABLE | HCA_CAP_OPMOD_GET_CUR); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); - if (ret) { - mlx5_core_err(mdev, "Failed to query WQE based FT caps\n"); - goto out; - } - - caps->rtc_reparse_mode = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.rtc_reparse_mode); - - caps->ste_format = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.ste_format); - - caps->rtc_index_mode = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.rtc_index_mode); - - caps->rtc_log_depth_max = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.rtc_log_depth_max); - - caps->ste_alloc_log_max = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.ste_alloc_log_max); - - caps->ste_alloc_log_gran = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.ste_alloc_log_granularity); - - caps->trivial_match_definer = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.trivial_match_definer); - - caps->stc_alloc_log_max = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.stc_alloc_log_max); - - caps->stc_alloc_log_gran = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.stc_alloc_log_granularity); - - caps->rtc_hash_split_table = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.rtc_hash_split_table); - - caps->rtc_linear_lookup_table = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.rtc_linear_lookup_table); - - caps->access_index_mode = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.access_index_mode); - - caps->linear_match_definer = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.linear_match_definer_reg_c3); - - caps->rtc_max_hash_def_gen_wqe = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.rtc_max_num_hash_definer_gen_wqe); - - caps->supp_ste_format_gen_wqe = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.ste_format_gen_wqe); - - caps->fdb_tir_stc = - MLX5_GET(query_hca_cap_out, out, - capability.wqe_based_flow_table_cap.fdb_jump_to_tir_stc); - } - - if (caps->eswitch_manager) { - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_GET_HCA_CAP_OP_MOD_ESW_FLOW_TABLE | HCA_CAP_OPMOD_GET_CUR); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); - if (ret) { - mlx5_core_err(mdev, "Failed to query flow table esw caps\n"); - goto out; - } - - caps->fdb_ft.max_level = - MLX5_GET(query_hca_cap_out, out, - capability.flow_table_nic_cap.flow_table_properties_nic_receive.max_ft_level); - - caps->fdb_ft.reparse = - MLX5_GET(query_hca_cap_out, out, - capability.flow_table_nic_cap.flow_table_properties_nic_receive.reparse); - - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_SET_HCA_CAP_OP_MOD_ESW | HCA_CAP_OPMOD_GET_CUR); - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); - if (ret) { - mlx5_core_err(mdev, "Failed to query eswitch capabilities\n"); - goto out; - } - - if (MLX5_GET(query_hca_cap_out, out, - capability.esw_cap.esw_manager_vport_number_valid)) - caps->eswitch_manager_vport_number = - MLX5_GET(query_hca_cap_out, out, - capability.esw_cap.esw_manager_vport_number); - - caps->merged_eswitch = MLX5_GET(query_hca_cap_out, out, - capability.esw_cap.merged_eswitch); - } - - ret = mlx5_cmd_exec(mdev, in, sizeof(in), out, out_size); - if (ret) { - mlx5_core_err(mdev, "Failed to query device attributes\n"); - goto out; - } - - snprintf(caps->fw_ver, sizeof(caps->fw_ver), "%d.%d.%d", - fw_rev_maj(mdev), fw_rev_min(mdev), fw_rev_sub(mdev)); - - caps->is_ecpf = mlx5_core_is_ecpf_esw_manager(mdev); - -out: - kfree(out); - return ret; -} - -int mlx5hws_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_function, - u16 vport_number, u16 *gvmi) -{ - bool ec_vf_func = other_function ? mlx5_core_is_ec_vf_vport(mdev, vport_number) : false; - u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; - int out_size; - void *out; - int err; - - out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); - out = kzalloc(out_size, GFP_KERNEL); - if (!out) - return -ENOMEM; - - MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); - MLX5_SET(query_hca_cap_in, in, other_function, other_function); - MLX5_SET(query_hca_cap_in, in, function_id, - mlx5_vport_to_func_id(mdev, vport_number, ec_vf_func)); - MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); - MLX5_SET(query_hca_cap_in, in, op_mod, - MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | HCA_CAP_OPMOD_GET_CUR); - - err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); - if (err) { - kfree(out); - return err; - } - - *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); - - kfree(out); - - return 0; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h deleted file mode 100644 index 2fbcf4ff571a06..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_cmd.h +++ /dev/null @@ -1,361 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_CMD_H_ -#define MLX5HWS_CMD_H_ - -#define WIRE_PORT 0xFFFF - -#define ACCESS_KEY_LEN 32 - -enum mlx5hws_cmd_ext_dest_flags { - MLX5HWS_CMD_EXT_DEST_REFORMAT = 1 << 0, - MLX5HWS_CMD_EXT_DEST_ESW_OWNER_VHCA_ID = 1 << 1, -}; - -struct mlx5hws_cmd_set_fte_dest { - u8 destination_type; - u32 destination_id; - enum mlx5hws_cmd_ext_dest_flags ext_flags; - u32 ext_reformat_id; - u16 esw_owner_vhca_id; -}; - -struct mlx5hws_cmd_set_fte_attr { - u32 action_flags; - bool ignore_flow_level; - u8 flow_source; - u8 extended_dest; - u8 encrypt_decrypt_type; - u32 encrypt_decrypt_obj_id; - u32 packet_reformat_id; - u32 dests_num; - struct mlx5hws_cmd_set_fte_dest *dests; -}; - -struct mlx5hws_cmd_ft_create_attr { - u8 type; - u8 level; - bool rtc_valid; - bool decap_en; - bool reformat_en; -}; - -struct mlx5hws_cmd_ft_modify_attr { - u8 type; - u32 rtc_id_0; - u32 rtc_id_1; - u32 table_miss_id; - u8 table_miss_action; - u64 modify_fs; -}; - -struct mlx5hws_cmd_ft_query_attr { - u8 type; -}; - -struct mlx5hws_cmd_fg_attr { - u32 table_id; - u32 table_type; -}; - -struct mlx5hws_cmd_forward_tbl { - u8 type; - u32 ft_id; - u32 fg_id; - u32 refcount; -}; - -struct mlx5hws_cmd_rtc_create_attr { - u32 pd; - u32 stc_base; - u32 ste_base; - u32 ste_offset; - u32 miss_ft_id; - bool fw_gen_wqe; - u8 update_index_mode; - u8 access_index_mode; - u8 num_hash_definer; - u8 log_depth; - u8 log_size; - u8 table_type; - u8 match_definer_0; - u8 match_definer_1; - u8 reparse_mode; - bool is_frst_jumbo; - bool is_scnd_range; -}; - -struct mlx5hws_cmd_alias_obj_create_attr { - u32 obj_id; - u16 vhca_id; - u16 obj_type; - u8 access_key[ACCESS_KEY_LEN]; -}; - -struct mlx5hws_cmd_stc_create_attr { - u8 log_obj_range; - u8 table_type; -}; - -struct mlx5hws_cmd_stc_modify_attr { - u32 stc_offset; - u8 action_offset; - u8 reparse_mode; - enum mlx5_ifc_stc_action_type action_type; - union { - u32 id; /* TIRN, TAG, FT ID, STE ID, CRYPTO */ - struct { - u8 decap; - u16 start_anchor; - u16 end_anchor; - } remove_header; - struct { - u32 arg_id; - u32 pattern_id; - } modify_header; - struct { - __be64 data; - } modify_action; - struct { - u32 arg_id; - u32 header_size; - u8 is_inline; - u8 encap; - u16 insert_anchor; - u16 insert_offset; - } insert_header; - struct { - u8 aso_type; - u32 devx_obj_id; - u8 return_reg_id; - } aso; - struct { - u16 vport_num; - u16 esw_owner_vhca_id; - u8 eswitch_owner_vhca_id_valid; - } vport; - struct { - struct mlx5hws_pool_chunk ste; - struct mlx5hws_pool *ste_pool; - u32 ste_obj_id; /* Internal */ - u32 match_definer_id; - u8 log_hash_size; - bool ignore_tx; - } ste_table; - struct { - u16 start_anchor; - u16 num_of_words; - } remove_words; - struct { - u8 type; - u8 op; - u8 size; - } reformat_trailer; - - u32 dest_table_id; - u32 dest_tir_num; - }; -}; - -struct mlx5hws_cmd_ste_create_attr { - u8 log_obj_range; - u8 table_type; -}; - -struct mlx5hws_cmd_definer_create_attr { - u8 *dw_selector; - u8 *byte_selector; - u8 *match_mask; -}; - -struct mlx5hws_cmd_allow_other_vhca_access_attr { - u16 obj_type; - u32 obj_id; - u8 access_key[ACCESS_KEY_LEN]; -}; - -struct mlx5hws_cmd_packet_reformat_create_attr { - u8 type; - size_t data_sz; - void *data; - u8 reformat_param_0; -}; - -struct mlx5hws_cmd_query_ft_caps { - u8 max_level; - u8 reparse; - u8 ignore_flow_level_rtc_valid; -}; - -struct mlx5hws_cmd_generate_wqe_attr { - u8 *wqe_ctrl; - u8 *gta_ctrl; - u8 *gta_data_0; - u8 *gta_data_1; - u32 pdn; -}; - -struct mlx5hws_cmd_query_caps { - u32 flex_protocols; - u8 wqe_based_update; - u8 rtc_reparse_mode; - u16 ste_format; - u8 rtc_index_mode; - u8 ste_alloc_log_max; - u8 ste_alloc_log_gran; - u8 stc_alloc_log_max; - u8 stc_alloc_log_gran; - u8 rtc_log_depth_max; - u8 format_select_gtpu_dw_0; - u8 format_select_gtpu_dw_1; - u8 flow_table_hash_type; - u8 format_select_gtpu_dw_2; - u8 format_select_gtpu_ext_dw_0; - u8 access_index_mode; - u32 linear_match_definer; - bool full_dw_jumbo_support; - bool rtc_hash_split_table; - bool rtc_linear_lookup_table; - u32 supp_type_gen_wqe; - u8 rtc_max_hash_def_gen_wqe; - u16 supp_ste_format_gen_wqe; - struct mlx5hws_cmd_query_ft_caps nic_ft; - struct mlx5hws_cmd_query_ft_caps fdb_ft; - bool eswitch_manager; - bool merged_eswitch; - u32 eswitch_manager_vport_number; - u8 log_header_modify_argument_granularity; - u8 log_header_modify_argument_max_alloc; - u8 sq_ts_format; - u8 fdb_tir_stc; - u64 definer_format_sup; - u32 trivial_match_definer; - u32 vhca_id; - u32 shared_vhca_id; - char fw_ver[64]; - bool ipsec_offload; - bool is_ecpf; - u8 flex_parser_ok_bits_supp; - u8 flex_parser_id_geneve_tlv_option_0; - u8 flex_parser_id_mpls_over_gre; - u8 flex_parser_id_mpls_over_udp; -}; - -int mlx5hws_cmd_flow_table_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_ft_create_attr *ft_attr, - u32 *table_id); - -int mlx5hws_cmd_flow_table_modify(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_ft_modify_attr *ft_attr, - u32 table_id); - -int mlx5hws_cmd_flow_table_query(struct mlx5_core_dev *mdev, - u32 obj_id, - struct mlx5hws_cmd_ft_query_attr *ft_attr, - u64 *icm_addr_0, u64 *icm_addr_1); - -int mlx5hws_cmd_flow_table_destroy(struct mlx5_core_dev *mdev, - u8 fw_ft_type, u32 table_id); - -void mlx5hws_cmd_alias_flow_table_destroy(struct mlx5_core_dev *mdev, - u32 table_id); - -int mlx5hws_cmd_rtc_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_rtc_create_attr *rtc_attr, - u32 *rtc_id); - -void mlx5hws_cmd_rtc_destroy(struct mlx5_core_dev *mdev, u32 rtc_id); - -int mlx5hws_cmd_stc_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_stc_create_attr *stc_attr, - u32 *stc_id); - -int mlx5hws_cmd_stc_modify(struct mlx5_core_dev *mdev, - u32 stc_id, - struct mlx5hws_cmd_stc_modify_attr *stc_attr); - -void mlx5hws_cmd_stc_destroy(struct mlx5_core_dev *mdev, u32 stc_id); - -int mlx5hws_cmd_generate_wqe(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_generate_wqe_attr *attr, - struct mlx5_cqe64 *ret_cqe); - -int mlx5hws_cmd_ste_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_ste_create_attr *ste_attr, - u32 *ste_id); - -void mlx5hws_cmd_ste_destroy(struct mlx5_core_dev *mdev, u32 ste_id); - -int mlx5hws_cmd_definer_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_definer_create_attr *def_attr, - u32 *definer_id); - -void mlx5hws_cmd_definer_destroy(struct mlx5_core_dev *mdev, - u32 definer_id); - -int mlx5hws_cmd_arg_create(struct mlx5_core_dev *mdev, - u16 log_obj_range, - u32 pd, - u32 *arg_id); - -void mlx5hws_cmd_arg_destroy(struct mlx5_core_dev *mdev, - u32 arg_id); - -int mlx5hws_cmd_header_modify_pattern_create(struct mlx5_core_dev *mdev, - u32 pattern_length, - u8 *actions, - u32 *ptrn_id); - -void mlx5hws_cmd_header_modify_pattern_destroy(struct mlx5_core_dev *mdev, - u32 ptrn_id); - -int mlx5hws_cmd_packet_reformat_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_packet_reformat_create_attr *attr, - u32 *reformat_id); - -int mlx5hws_cmd_packet_reformat_destroy(struct mlx5_core_dev *mdev, - u32 reformat_id); - -int mlx5hws_cmd_set_fte(struct mlx5_core_dev *mdev, - u32 table_type, - u32 table_id, - u32 group_id, - struct mlx5hws_cmd_set_fte_attr *fte_attr); - -int mlx5hws_cmd_delete_fte(struct mlx5_core_dev *mdev, - u32 table_type, u32 table_id); - -struct mlx5hws_cmd_forward_tbl * -mlx5hws_cmd_forward_tbl_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_ft_create_attr *ft_attr, - struct mlx5hws_cmd_set_fte_attr *fte_attr); - -void mlx5hws_cmd_forward_tbl_destroy(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_forward_tbl *tbl); - -int mlx5hws_cmd_alias_obj_create(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_alias_obj_create_attr *alias_attr, - u32 *obj_id); - -int mlx5hws_cmd_alias_obj_destroy(struct mlx5_core_dev *mdev, - u16 obj_type, - u32 obj_id); - -int mlx5hws_cmd_sq_modify_rdy(struct mlx5_core_dev *mdev, u32 sqn); - -int mlx5hws_cmd_query_caps(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_query_caps *caps); - -void mlx5hws_cmd_set_attr_connect_miss_tbl(struct mlx5hws_context *ctx, - u32 fw_ft_type, - enum mlx5hws_table_type type, - struct mlx5hws_cmd_ft_modify_attr *ft_attr); - -int mlx5hws_cmd_allow_other_vhca_access(struct mlx5_core_dev *mdev, - struct mlx5hws_cmd_allow_other_vhca_access_attr *attr); - -int mlx5hws_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_function, - u16 vport_number, u16 *gvmi); - -#endif /* MLX5HWS_CMD_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c deleted file mode 100644 index 00e4fdf4a558b3..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.c +++ /dev/null @@ -1,260 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved. */ - -#include "mlx5hws_internal.h" - -bool mlx5hws_context_cap_dynamic_reparse(struct mlx5hws_context *ctx) -{ - return IS_BIT_SET(ctx->caps->rtc_reparse_mode, MLX5_IFC_RTC_REPARSE_BY_STC); -} - -u8 mlx5hws_context_get_reparse_mode(struct mlx5hws_context *ctx) -{ - /* Prefer to use dynamic reparse, reparse only specific actions */ - if (mlx5hws_context_cap_dynamic_reparse(ctx)) - return MLX5_IFC_RTC_REPARSE_NEVER; - - /* Otherwise use less efficient static */ - return MLX5_IFC_RTC_REPARSE_ALWAYS; -} - -static int hws_context_pools_init(struct mlx5hws_context *ctx) -{ - struct mlx5hws_pool_attr pool_attr = {0}; - u8 max_log_sz; - int ret; - int i; - - ret = mlx5hws_pat_init_pattern_cache(&ctx->pattern_cache); - if (ret) - return ret; - - ret = mlx5hws_definer_init_cache(&ctx->definer_cache); - if (ret) - goto uninit_pat_cache; - - /* Create an STC pool per FT type */ - pool_attr.pool_type = MLX5HWS_POOL_TYPE_STC; - pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STC_POOL; - max_log_sz = min(MLX5HWS_POOL_STC_LOG_SZ, ctx->caps->stc_alloc_log_max); - pool_attr.alloc_log_sz = max(max_log_sz, ctx->caps->stc_alloc_log_gran); - - for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) { - pool_attr.table_type = i; - ctx->stc_pool[i] = mlx5hws_pool_create(ctx, &pool_attr); - if (!ctx->stc_pool[i]) { - mlx5hws_err(ctx, "Failed to allocate STC pool [%d]", i); - ret = -ENOMEM; - goto free_stc_pools; - } - } - - return 0; - -free_stc_pools: - for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) - if (ctx->stc_pool[i]) - mlx5hws_pool_destroy(ctx->stc_pool[i]); - - mlx5hws_definer_uninit_cache(ctx->definer_cache); -uninit_pat_cache: - mlx5hws_pat_uninit_pattern_cache(ctx->pattern_cache); - return ret; -} - -static void hws_context_pools_uninit(struct mlx5hws_context *ctx) -{ - int i; - - for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) { - if (ctx->stc_pool[i]) - mlx5hws_pool_destroy(ctx->stc_pool[i]); - } - - mlx5hws_definer_uninit_cache(ctx->definer_cache); - mlx5hws_pat_uninit_pattern_cache(ctx->pattern_cache); -} - -static int hws_context_init_pd(struct mlx5hws_context *ctx) -{ - int ret = 0; - - ret = mlx5_core_alloc_pd(ctx->mdev, &ctx->pd_num); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate PD\n"); - return ret; - } - - ctx->flags |= MLX5HWS_CONTEXT_FLAG_PRIVATE_PD; - - return 0; -} - -static int hws_context_uninit_pd(struct mlx5hws_context *ctx) -{ - if (ctx->flags & MLX5HWS_CONTEXT_FLAG_PRIVATE_PD) - mlx5_core_dealloc_pd(ctx->mdev, ctx->pd_num); - - return 0; -} - -static void hws_context_check_hws_supp(struct mlx5hws_context *ctx) -{ - struct mlx5hws_cmd_query_caps *caps = ctx->caps; - - /* HWS not supported on device / FW */ - if (!caps->wqe_based_update) { - mlx5hws_err(ctx, "Required HWS WQE based insertion cap not supported\n"); - return; - } - - if (!caps->eswitch_manager) { - mlx5hws_err(ctx, "HWS is not supported for non eswitch manager port\n"); - return; - } - - /* Current solution requires all rules to set reparse bit */ - if ((!caps->nic_ft.reparse || - (!caps->fdb_ft.reparse && caps->eswitch_manager)) || - !IS_BIT_SET(caps->rtc_reparse_mode, MLX5_IFC_RTC_REPARSE_ALWAYS)) { - mlx5hws_err(ctx, "Required HWS reparse cap not supported\n"); - return; - } - - /* FW/HW must support 8DW STE */ - if (!IS_BIT_SET(caps->ste_format, MLX5_IFC_RTC_STE_FORMAT_8DW)) { - mlx5hws_err(ctx, "Required HWS STE format not supported\n"); - return; - } - - /* Adding rules by hash and by offset are requirements */ - if (!IS_BIT_SET(caps->rtc_index_mode, MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH) || - !IS_BIT_SET(caps->rtc_index_mode, MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET)) { - mlx5hws_err(ctx, "Required HWS RTC update mode not supported\n"); - return; - } - - /* Support for SELECT definer ID is required */ - if (!IS_BIT_SET(caps->definer_format_sup, MLX5_IFC_DEFINER_FORMAT_ID_SELECT)) { - mlx5hws_err(ctx, "Required HWS Dynamic definer not supported\n"); - return; - } - - ctx->flags |= MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT; -} - -static int hws_context_init_hws(struct mlx5hws_context *ctx, - struct mlx5hws_context_attr *attr) -{ - int ret; - - hws_context_check_hws_supp(ctx); - - if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) - return 0; - - ret = hws_context_init_pd(ctx); - if (ret) - return ret; - - ret = hws_context_pools_init(ctx); - if (ret) - goto uninit_pd; - - if (attr->bwc) - ctx->flags |= MLX5HWS_CONTEXT_FLAG_BWC_SUPPORT; - - ret = mlx5hws_send_queues_open(ctx, attr->queues, attr->queue_size); - if (ret) - goto pools_uninit; - - INIT_LIST_HEAD(&ctx->tbl_list); - - return 0; - -pools_uninit: - hws_context_pools_uninit(ctx); -uninit_pd: - hws_context_uninit_pd(ctx); - return ret; -} - -static void hws_context_uninit_hws(struct mlx5hws_context *ctx) -{ - if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) - return; - - mlx5hws_send_queues_close(ctx); - hws_context_pools_uninit(ctx); - hws_context_uninit_pd(ctx); -} - -struct mlx5hws_context *mlx5hws_context_open(struct mlx5_core_dev *mdev, - struct mlx5hws_context_attr *attr) -{ - struct mlx5hws_context *ctx; - int ret; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return NULL; - - ctx->mdev = mdev; - - mutex_init(&ctx->ctrl_lock); - xa_init(&ctx->peer_ctx_xa); - - ctx->caps = kzalloc(sizeof(*ctx->caps), GFP_KERNEL); - if (!ctx->caps) - goto free_ctx; - - ret = mlx5hws_cmd_query_caps(mdev, ctx->caps); - if (ret) - goto free_caps; - - ret = mlx5hws_vport_init_vports(ctx); - if (ret) - goto free_caps; - - ret = hws_context_init_hws(ctx, attr); - if (ret) - goto uninit_vports; - - mlx5hws_debug_init_dump(ctx); - - return ctx; - -uninit_vports: - mlx5hws_vport_uninit_vports(ctx); -free_caps: - kfree(ctx->caps); -free_ctx: - xa_destroy(&ctx->peer_ctx_xa); - mutex_destroy(&ctx->ctrl_lock); - kfree(ctx); - return NULL; -} - -int mlx5hws_context_close(struct mlx5hws_context *ctx) -{ - mlx5hws_debug_uninit_dump(ctx); - hws_context_uninit_hws(ctx); - mlx5hws_vport_uninit_vports(ctx); - kfree(ctx->caps); - xa_destroy(&ctx->peer_ctx_xa); - mutex_destroy(&ctx->ctrl_lock); - kfree(ctx); - return 0; -} - -void mlx5hws_context_set_peer(struct mlx5hws_context *ctx, - struct mlx5hws_context *peer_ctx, - u16 peer_vhca_id) -{ - mutex_lock(&ctx->ctrl_lock); - - if (xa_err(xa_store(&ctx->peer_ctx_xa, peer_vhca_id, peer_ctx, GFP_KERNEL))) - pr_warn("HWS: failed storing peer vhca ID in peer xarray\n"); - - mutex_unlock(&ctx->ctrl_lock); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h deleted file mode 100644 index 8ab548aa402be2..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_context.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_CONTEXT_H_ -#define MLX5HWS_CONTEXT_H_ - -enum mlx5hws_context_flags { - MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT = 1 << 0, - MLX5HWS_CONTEXT_FLAG_PRIVATE_PD = 1 << 1, - MLX5HWS_CONTEXT_FLAG_BWC_SUPPORT = 1 << 2, -}; - -enum mlx5hws_context_shared_stc_type { - MLX5HWS_CONTEXT_SHARED_STC_DECAP_L3 = 0, - MLX5HWS_CONTEXT_SHARED_STC_DOUBLE_POP = 1, - MLX5HWS_CONTEXT_SHARED_STC_MAX = 2, -}; - -struct mlx5hws_context_common_res { - struct mlx5hws_action_default_stc *default_stc; - struct mlx5hws_action_shared_stc *shared_stc[MLX5HWS_CONTEXT_SHARED_STC_MAX]; - struct mlx5hws_cmd_forward_tbl *default_miss; -}; - -struct mlx5hws_context_debug_info { - struct dentry *steering_debugfs; - struct dentry *fdb_debugfs; -}; - -struct mlx5hws_context_vports { - u16 esw_manager_gvmi; - u16 uplink_gvmi; - struct xarray vport_gvmi_xa; -}; - -struct mlx5hws_context { - struct mlx5_core_dev *mdev; - struct mlx5hws_cmd_query_caps *caps; - u32 pd_num; - struct mlx5hws_pool *stc_pool[MLX5HWS_TABLE_TYPE_MAX]; - struct mlx5hws_context_common_res common_res[MLX5HWS_TABLE_TYPE_MAX]; - struct mlx5hws_pattern_cache *pattern_cache; - struct mlx5hws_definer_cache *definer_cache; - struct mutex ctrl_lock; /* control lock to protect the whole context */ - enum mlx5hws_context_flags flags; - struct mlx5hws_send_engine *send_queue; - size_t queues; - struct mutex *bwc_send_queue_locks; /* protect BWC queues */ - struct lock_class_key *bwc_lock_class_keys; - struct list_head tbl_list; - struct mlx5hws_context_debug_info debug_info; - struct xarray peer_ctx_xa; - struct mlx5hws_context_vports vports; -}; - -static inline bool mlx5hws_context_bwc_supported(struct mlx5hws_context *ctx) -{ - return ctx->flags & MLX5HWS_CONTEXT_FLAG_BWC_SUPPORT; -} - -bool mlx5hws_context_cap_dynamic_reparse(struct mlx5hws_context *ctx); - -u8 mlx5hws_context_get_reparse_mode(struct mlx5hws_context *ctx); - -#endif /* MLX5HWS_CONTEXT_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c deleted file mode 100644 index 2b8c5a4e1c4c0f..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.c +++ /dev/null @@ -1,480 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include -#include -#include -#include -#include "mlx5hws_internal.h" - -static int -hws_debug_dump_matcher_template_definer(struct seq_file *f, - void *parent_obj, - struct mlx5hws_definer *definer, - enum mlx5hws_debug_res_type type) -{ - int i; - - if (!definer) - return 0; - - seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,", - type, - HWS_PTR_TO_ID(definer), - HWS_PTR_TO_ID(parent_obj), - definer->obj_id, - definer->type); - - for (i = 0; i < DW_SELECTORS; i++) - seq_printf(f, "0x%x%s", definer->dw_selector[i], - (i == DW_SELECTORS - 1) ? "," : "-"); - - for (i = 0; i < BYTE_SELECTORS; i++) - seq_printf(f, "0x%x%s", definer->byte_selector[i], - (i == BYTE_SELECTORS - 1) ? "," : "-"); - - for (i = 0; i < MLX5HWS_JUMBO_TAG_SZ; i++) - seq_printf(f, "%02x", definer->mask.jumbo[i]); - - seq_puts(f, "\n"); - - return 0; -} - -static int -hws_debug_dump_matcher_match_template(struct seq_file *f, struct mlx5hws_matcher *matcher) -{ - enum mlx5hws_debug_res_type type; - int i, ret; - - for (i = 0; i < matcher->num_of_mt; i++) { - struct mlx5hws_match_template *mt = &matcher->mt[i]; - - seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d\n", - MLX5HWS_DEBUG_RES_TYPE_MATCHER_MATCH_TEMPLATE, - HWS_PTR_TO_ID(mt), - HWS_PTR_TO_ID(matcher), - mt->fc_sz, - 0, 0); - - type = MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_MATCH_DEFINER; - ret = hws_debug_dump_matcher_template_definer(f, mt, mt->definer, type); - if (ret) - return ret; - } - - return 0; -} - -static int -hws_debug_dump_matcher_action_template(struct seq_file *f, struct mlx5hws_matcher *matcher) -{ - enum mlx5hws_action_type action_type; - int i, j; - - for (i = 0; i < matcher->num_of_at; i++) { - struct mlx5hws_action_template *at = &matcher->at[i]; - - seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d", - MLX5HWS_DEBUG_RES_TYPE_MATCHER_ACTION_TEMPLATE, - HWS_PTR_TO_ID(at), - HWS_PTR_TO_ID(matcher), - at->only_term, - at->num_of_action_stes, - at->num_actions); - - for (j = 0; j < at->num_actions; j++) { - action_type = at->action_type_arr[j]; - seq_printf(f, ",%s", mlx5hws_action_type_to_str(action_type)); - } - - seq_puts(f, "\n"); - } - - return 0; -} - -static int -hws_debug_dump_matcher_attr(struct seq_file *f, struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_matcher_attr *attr = &matcher->attr; - - seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d\n", - MLX5HWS_DEBUG_RES_TYPE_MATCHER_ATTR, - HWS_PTR_TO_ID(matcher), - attr->priority, - attr->mode, - attr->table.sz_row_log, - attr->table.sz_col_log, - attr->optimize_using_rule_idx, - attr->optimize_flow_src, - attr->insert_mode, - attr->distribute_mode); - - return 0; -} - -static int hws_debug_dump_matcher(struct seq_file *f, struct mlx5hws_matcher *matcher) -{ - enum mlx5hws_table_type tbl_type = matcher->tbl->type; - struct mlx5hws_cmd_ft_query_attr ft_attr = {0}; - struct mlx5hws_pool_chunk *ste; - struct mlx5hws_pool *ste_pool; - u64 icm_addr_0 = 0; - u64 icm_addr_1 = 0; - u32 ste_0_id = -1; - u32 ste_1_id = -1; - int ret; - - seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,0x%llx", - MLX5HWS_DEBUG_RES_TYPE_MATCHER, - HWS_PTR_TO_ID(matcher), - HWS_PTR_TO_ID(matcher->tbl), - matcher->num_of_mt, - matcher->end_ft_id, - matcher->col_matcher ? HWS_PTR_TO_ID(matcher->col_matcher) : 0); - - ste = &matcher->match_ste.ste; - ste_pool = matcher->match_ste.pool; - if (ste_pool) { - ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); - if (tbl_type == MLX5HWS_TABLE_TYPE_FDB) - ste_1_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); - } - - seq_printf(f, ",%d,%d,%d,%d", - matcher->match_ste.rtc_0_id, - (int)ste_0_id, - matcher->match_ste.rtc_1_id, - (int)ste_1_id); - - ste = &matcher->action_ste[0].ste; - ste_pool = matcher->action_ste[0].pool; - if (ste_pool) { - ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); - if (tbl_type == MLX5HWS_TABLE_TYPE_FDB) - ste_1_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); - else - ste_1_id = -1; - } else { - ste_0_id = -1; - ste_1_id = -1; - } - - ft_attr.type = matcher->tbl->fw_ft_type; - ret = mlx5hws_cmd_flow_table_query(matcher->tbl->ctx->mdev, - matcher->end_ft_id, - &ft_attr, - &icm_addr_0, - &icm_addr_1); - if (ret) - return ret; - - seq_printf(f, ",%d,%d,%d,%d,%d,0x%llx,0x%llx\n", - matcher->action_ste[0].rtc_0_id, - (int)ste_0_id, - matcher->action_ste[0].rtc_1_id, - (int)ste_1_id, - 0, - mlx5hws_debug_icm_to_idx(icm_addr_0), - mlx5hws_debug_icm_to_idx(icm_addr_1)); - - ret = hws_debug_dump_matcher_attr(f, matcher); - if (ret) - return ret; - - ret = hws_debug_dump_matcher_match_template(f, matcher); - if (ret) - return ret; - - ret = hws_debug_dump_matcher_action_template(f, matcher); - if (ret) - return ret; - - return 0; -} - -static int hws_debug_dump_table(struct seq_file *f, struct mlx5hws_table *tbl) -{ - struct mlx5hws_cmd_ft_query_attr ft_attr = {0}; - struct mlx5hws_matcher *matcher; - u64 local_icm_addr_0 = 0; - u64 local_icm_addr_1 = 0; - u64 icm_addr_0 = 0; - u64 icm_addr_1 = 0; - int ret; - - seq_printf(f, "%d,0x%llx,0x%llx,%d,%d,%d,%d,%d", - MLX5HWS_DEBUG_RES_TYPE_TABLE, - HWS_PTR_TO_ID(tbl), - HWS_PTR_TO_ID(tbl->ctx), - tbl->ft_id, - MLX5HWS_TABLE_TYPE_BASE + tbl->type, - tbl->fw_ft_type, - tbl->level, - 0); - - ft_attr.type = tbl->fw_ft_type; - ret = mlx5hws_cmd_flow_table_query(tbl->ctx->mdev, - tbl->ft_id, - &ft_attr, - &icm_addr_0, - &icm_addr_1); - if (ret) - return ret; - - seq_printf(f, ",0x%llx,0x%llx,0x%llx,0x%llx,0x%llx\n", - mlx5hws_debug_icm_to_idx(icm_addr_0), - mlx5hws_debug_icm_to_idx(icm_addr_1), - mlx5hws_debug_icm_to_idx(local_icm_addr_0), - mlx5hws_debug_icm_to_idx(local_icm_addr_1), - HWS_PTR_TO_ID(tbl->default_miss.miss_tbl)); - - list_for_each_entry(matcher, &tbl->matchers_list, list_node) { - ret = hws_debug_dump_matcher(f, matcher); - if (ret) - return ret; - } - - return 0; -} - -static int -hws_debug_dump_context_send_engine(struct seq_file *f, struct mlx5hws_context *ctx) -{ - struct mlx5hws_send_engine *send_queue; - struct mlx5hws_send_ring *send_ring; - struct mlx5hws_send_ring_cq *cq; - struct mlx5hws_send_ring_sq *sq; - int i; - - for (i = 0; i < (int)ctx->queues; i++) { - send_queue = &ctx->send_queue[i]; - seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_ENGINE, - HWS_PTR_TO_ID(ctx), - i, - send_queue->used_entries, - send_queue->num_entries, - 1, /* one send ring per queue */ - send_queue->num_entries, - send_queue->err, - send_queue->completed.ci, - send_queue->completed.pi, - send_queue->completed.mask); - - send_ring = &send_queue->send_ring; - cq = &send_ring->send_cq; - sq = &send_ring->send_sq; - - seq_printf(f, "%d,0x%llx,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_RING, - HWS_PTR_TO_ID(ctx), - 0, /* one send ring per send queue */ - i, - cq->mcq.cqn, - 0, - 0, - 0, - 0, - 0, - 0, - cq->mcq.cqe_sz, - sq->sqn, - 0, - 0, - 0); - } - - return 0; -} - -static int hws_debug_dump_context_caps(struct seq_file *f, struct mlx5hws_context *ctx) -{ - struct mlx5hws_cmd_query_caps *caps = ctx->caps; - - seq_printf(f, "%d,0x%llx,%s,%d,%d,%d,%d,", - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_CAPS, - HWS_PTR_TO_ID(ctx), - caps->fw_ver, - caps->wqe_based_update, - caps->ste_format, - caps->ste_alloc_log_max, - caps->log_header_modify_argument_max_alloc); - - seq_printf(f, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s\n", - caps->flex_protocols, - caps->rtc_reparse_mode, - caps->rtc_index_mode, - caps->ste_alloc_log_gran, - caps->stc_alloc_log_max, - caps->stc_alloc_log_gran, - caps->rtc_log_depth_max, - caps->format_select_gtpu_dw_0, - caps->format_select_gtpu_dw_1, - caps->format_select_gtpu_dw_2, - caps->format_select_gtpu_ext_dw_0, - caps->nic_ft.max_level, - caps->nic_ft.reparse, - caps->fdb_ft.max_level, - caps->fdb_ft.reparse, - caps->log_header_modify_argument_granularity, - caps->linear_match_definer, - "regc_3"); - - return 0; -} - -static int hws_debug_dump_context_attr(struct seq_file *f, struct mlx5hws_context *ctx) -{ - seq_printf(f, "%u,0x%llx,%d,%zu,%d,%s,%d,%d\n", - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_ATTR, - HWS_PTR_TO_ID(ctx), - ctx->pd_num, - ctx->queues, - ctx->send_queue->num_entries, - "None", /* no shared gvmi */ - ctx->caps->vhca_id, - 0xffff); /* no shared gvmi */ - - return 0; -} - -static int hws_debug_dump_context_info(struct seq_file *f, struct mlx5hws_context *ctx) -{ - struct mlx5_core_dev *dev = ctx->mdev; - int ret; - - seq_printf(f, "%d,0x%llx,%d,%s,%s.KERNEL_%u_%u_%u\n", - MLX5HWS_DEBUG_RES_TYPE_CONTEXT, - HWS_PTR_TO_ID(ctx), - ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT, - pci_name(dev->pdev), - HWS_DEBUG_FORMAT_VERSION, - LINUX_VERSION_MAJOR, - LINUX_VERSION_PATCHLEVEL, - LINUX_VERSION_SUBLEVEL); - - ret = hws_debug_dump_context_attr(f, ctx); - if (ret) - return ret; - - ret = hws_debug_dump_context_caps(f, ctx); - if (ret) - return ret; - - return 0; -} - -static int hws_debug_dump_context_stc_resource(struct seq_file *f, - struct mlx5hws_context *ctx, - u32 tbl_type, - struct mlx5hws_pool_resource *resource) -{ - seq_printf(f, "%d,0x%llx,%u,%u\n", - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_STC, - HWS_PTR_TO_ID(ctx), - tbl_type, - resource->base_id); - - return 0; -} - -static int hws_debug_dump_context_stc(struct seq_file *f, struct mlx5hws_context *ctx) -{ - struct mlx5hws_pool *stc_pool; - u32 table_type; - int ret; - int i; - - for (i = 0; i < MLX5HWS_TABLE_TYPE_MAX; i++) { - stc_pool = ctx->stc_pool[i]; - table_type = MLX5HWS_TABLE_TYPE_BASE + i; - - if (!stc_pool) - continue; - - if (stc_pool->resource[0]) { - ret = hws_debug_dump_context_stc_resource(f, ctx, table_type, - stc_pool->resource[0]); - if (ret) - return ret; - } - - if (i == MLX5HWS_TABLE_TYPE_FDB && stc_pool->mirror_resource[0]) { - ret = hws_debug_dump_context_stc_resource(f, ctx, table_type, - stc_pool->mirror_resource[0]); - if (ret) - return ret; - } - } - - return 0; -} - -static int hws_debug_dump_context(struct seq_file *f, struct mlx5hws_context *ctx) -{ - struct mlx5hws_table *tbl; - int ret; - - ret = hws_debug_dump_context_info(f, ctx); - if (ret) - return ret; - - ret = hws_debug_dump_context_send_engine(f, ctx); - if (ret) - return ret; - - ret = hws_debug_dump_context_stc(f, ctx); - if (ret) - return ret; - - list_for_each_entry(tbl, &ctx->tbl_list, tbl_list_node) { - ret = hws_debug_dump_table(f, tbl); - if (ret) - return ret; - } - - return 0; -} - -static int -hws_debug_dump(struct seq_file *f, struct mlx5hws_context *ctx) -{ - int ret; - - if (!f || !ctx) - return -EINVAL; - - mutex_lock(&ctx->ctrl_lock); - ret = hws_debug_dump_context(f, ctx); - mutex_unlock(&ctx->ctrl_lock); - - return ret; -} - -static int hws_dump_show(struct seq_file *file, void *priv) -{ - return hws_debug_dump(file, file->private); -} -DEFINE_SHOW_ATTRIBUTE(hws_dump); - -void mlx5hws_debug_init_dump(struct mlx5hws_context *ctx) -{ - struct mlx5_core_dev *dev = ctx->mdev; - char file_name[128]; - - ctx->debug_info.steering_debugfs = - debugfs_create_dir("steering", mlx5_debugfs_get_dev_root(dev)); - ctx->debug_info.fdb_debugfs = - debugfs_create_dir("fdb", ctx->debug_info.steering_debugfs); - - sprintf(file_name, "ctx_%p", ctx); - debugfs_create_file(file_name, 0444, ctx->debug_info.fdb_debugfs, - ctx, &hws_dump_fops); -} - -void mlx5hws_debug_uninit_dump(struct mlx5hws_context *ctx) -{ - debugfs_remove_recursive(ctx->debug_info.steering_debugfs); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.h deleted file mode 100644 index b93a536035d960..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_debug.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_DEBUG_H_ -#define MLX5HWS_DEBUG_H_ - -#define HWS_DEBUG_FORMAT_VERSION "1.0" - -#define HWS_PTR_TO_ID(p) ((u64)(uintptr_t)(p) & 0xFFFFFFFFULL) - -enum mlx5hws_debug_res_type { - MLX5HWS_DEBUG_RES_TYPE_CONTEXT = 4000, - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_ATTR = 4001, - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_CAPS = 4002, - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_ENGINE = 4003, - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_SEND_RING = 4004, - MLX5HWS_DEBUG_RES_TYPE_CONTEXT_STC = 4005, - - MLX5HWS_DEBUG_RES_TYPE_TABLE = 4100, - - MLX5HWS_DEBUG_RES_TYPE_MATCHER = 4200, - MLX5HWS_DEBUG_RES_TYPE_MATCHER_ATTR = 4201, - MLX5HWS_DEBUG_RES_TYPE_MATCHER_MATCH_TEMPLATE = 4202, - MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_MATCH_DEFINER = 4203, - MLX5HWS_DEBUG_RES_TYPE_MATCHER_ACTION_TEMPLATE = 4204, - MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_HASH_DEFINER = 4205, - MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_RANGE_DEFINER = 4206, - MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_COMPARE_MATCH_DEFINER = 4207, -}; - -static inline u64 -mlx5hws_debug_icm_to_idx(u64 icm_addr) -{ - return (icm_addr >> 6) & 0xffffffff; -} - -void mlx5hws_debug_init_dump(struct mlx5hws_context *ctx); -void mlx5hws_debug_uninit_dump(struct mlx5hws_context *ctx); - -#endif /* MLX5HWS_DEBUG_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.c deleted file mode 100644 index 3f4c58bada3745..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.c +++ /dev/null @@ -1,2146 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -/* Pattern tunnel Layer bits. */ -#define MLX5_FLOW_LAYER_VXLAN BIT(12) -#define MLX5_FLOW_LAYER_VXLAN_GPE BIT(13) -#define MLX5_FLOW_LAYER_GRE BIT(14) -#define MLX5_FLOW_LAYER_MPLS BIT(15) - -/* Pattern tunnel Layer bits (continued). */ -#define MLX5_FLOW_LAYER_IPIP BIT(23) -#define MLX5_FLOW_LAYER_IPV6_ENCAP BIT(24) -#define MLX5_FLOW_LAYER_NVGRE BIT(25) -#define MLX5_FLOW_LAYER_GENEVE BIT(26) - -#define MLX5_FLOW_ITEM_FLEX_TUNNEL BIT_ULL(39) - -/* Tunnel Masks. */ -#define MLX5_FLOW_LAYER_TUNNEL \ - (MLX5_FLOW_LAYER_VXLAN | MLX5_FLOW_LAYER_VXLAN_GPE | \ - MLX5_FLOW_LAYER_GRE | MLX5_FLOW_LAYER_NVGRE | MLX5_FLOW_LAYER_MPLS | \ - MLX5_FLOW_LAYER_IPIP | MLX5_FLOW_LAYER_IPV6_ENCAP | \ - MLX5_FLOW_LAYER_GENEVE | MLX5_FLOW_LAYER_GTP | \ - MLX5_FLOW_ITEM_FLEX_TUNNEL) - -#define GTP_PDU_SC 0x85 -#define BAD_PORT 0xBAD -#define ETH_TYPE_IPV4_VXLAN 0x0800 -#define ETH_TYPE_IPV6_VXLAN 0x86DD -#define UDP_GTPU_PORT 2152 -#define UDP_PORT_MPLS 6635 -#define UDP_GENEVE_PORT 6081 -#define UDP_ROCEV2_PORT 4791 -#define HWS_FLOW_LAYER_TUNNEL_NO_MPLS (MLX5_FLOW_LAYER_TUNNEL & ~MLX5_FLOW_LAYER_MPLS) - -#define STE_NO_VLAN 0x0 -#define STE_SVLAN 0x1 -#define STE_CVLAN 0x2 -#define STE_NO_L3 0x0 -#define STE_IPV4 0x1 -#define STE_IPV6 0x2 -#define STE_NO_L4 0x0 -#define STE_TCP 0x1 -#define STE_UDP 0x2 -#define STE_ICMP 0x3 -#define STE_ESP 0x3 - -#define IPV4 0x4 -#define IPV6 0x6 - -/* Setter function based on bit offset and mask, for 32bit DW */ -#define _HWS_SET32(p, v, byte_off, bit_off, mask) \ - do { \ - u32 _v = v; \ - *((__be32 *)(p) + ((byte_off) / 4)) = \ - cpu_to_be32((be32_to_cpu(*((__be32 *)(p) + \ - ((byte_off) / 4))) & \ - (~((mask) << (bit_off)))) | \ - (((_v) & (mask)) << \ - (bit_off))); \ - } while (0) - -/* Setter function based on bit offset and mask, for unaligned 32bit DW */ -#define HWS_SET32(p, v, byte_off, bit_off, mask) \ - do { \ - if (unlikely((bit_off) < 0)) { \ - u32 _bit_off = -1 * (bit_off); \ - u32 second_dw_mask = (mask) & ((1 << _bit_off) - 1); \ - _HWS_SET32(p, (v) >> _bit_off, byte_off, 0, (mask) >> _bit_off); \ - _HWS_SET32(p, (v) & second_dw_mask, (byte_off) + DW_SIZE, \ - (bit_off) % BITS_IN_DW, second_dw_mask); \ - } else { \ - _HWS_SET32(p, v, byte_off, (bit_off), (mask)); \ - } \ - } while (0) - -/* Getter for up to aligned 32bit DW */ -#define HWS_GET32(p, byte_off, bit_off, mask) \ - ((be32_to_cpu(*((__be32 *)(p) + ((byte_off) / 4))) >> (bit_off)) & (mask)) - -#define HWS_CALC_FNAME(field, inner) \ - ((inner) ? MLX5HWS_DEFINER_FNAME_##field##_I : \ - MLX5HWS_DEFINER_FNAME_##field##_O) - -#define HWS_GET_MATCH_PARAM(match_param, hdr) \ - MLX5_GET(fte_match_param, match_param, hdr) - -#define HWS_IS_FLD_SET(match_param, hdr) \ - (!!(HWS_GET_MATCH_PARAM(match_param, hdr))) - -#define HWS_IS_FLD_SET_DW_ARR(match_param, hdr, sz_in_bits) ({ \ - BUILD_BUG_ON((sz_in_bits) % 32); \ - u32 sz = sz_in_bits; \ - u32 res = 0; \ - u32 dw_off = __mlx5_dw_off(fte_match_param, hdr); \ - while (!res && sz >= 32) { \ - res = *((match_param) + (dw_off++)); \ - sz -= 32; \ - } \ - res; \ - }) - -#define HWS_IS_FLD_SET_SZ(match_param, hdr, sz_in_bits) \ - (((sz_in_bits) > 32) ? HWS_IS_FLD_SET_DW_ARR(match_param, hdr, sz_in_bits) : \ - !!(HWS_GET_MATCH_PARAM(match_param, hdr))) - -#define HWS_GET64_MATCH_PARAM(match_param, hdr) \ - MLX5_GET64(fte_match_param, match_param, hdr) - -#define HWS_IS_FLD64_SET(match_param, hdr) \ - (!!(HWS_GET64_MATCH_PARAM(match_param, hdr))) - -#define HWS_CALC_HDR_SRC(fc, s_hdr) \ - do { \ - (fc)->s_bit_mask = __mlx5_mask(fte_match_param, s_hdr); \ - (fc)->s_bit_off = __mlx5_dw_bit_off(fte_match_param, s_hdr); \ - (fc)->s_byte_off = MLX5_BYTE_OFF(fte_match_param, s_hdr); \ - } while (0) - -#define HWS_CALC_HDR_DST(fc, d_hdr) \ - do { \ - (fc)->bit_mask = __mlx5_mask(definer_hl, d_hdr); \ - (fc)->bit_off = __mlx5_dw_bit_off(definer_hl, d_hdr); \ - (fc)->byte_off = MLX5_BYTE_OFF(definer_hl, d_hdr); \ - } while (0) - -#define HWS_CALC_HDR(fc, s_hdr, d_hdr) \ - do { \ - HWS_CALC_HDR_SRC(fc, s_hdr); \ - HWS_CALC_HDR_DST(fc, d_hdr); \ - (fc)->tag_set = &hws_definer_generic_set; \ - } while (0) - -#define HWS_SET_HDR(fc_arr, match_param, fname, s_hdr, d_hdr) \ - do { \ - if (HWS_IS_FLD_SET(match_param, s_hdr)) \ - HWS_CALC_HDR(&(fc_arr)[MLX5HWS_DEFINER_FNAME_##fname], s_hdr, d_hdr); \ - } while (0) - -struct mlx5hws_definer_sel_ctrl { - u8 allowed_full_dw; /* Full DW selectors cover all offsets */ - u8 allowed_lim_dw; /* Limited DW selectors cover offset < 64 */ - u8 allowed_bytes; /* Bytes selectors, up to offset 255 */ - u8 used_full_dw; - u8 used_lim_dw; - u8 used_bytes; - u8 full_dw_selector[DW_SELECTORS]; - u8 lim_dw_selector[DW_SELECTORS_LIMITED]; - u8 byte_selector[BYTE_SELECTORS]; -}; - -struct mlx5hws_definer_conv_data { - struct mlx5hws_context *ctx; - struct mlx5hws_definer_fc *fc; - /* enum mlx5hws_definer_match_flag */ - u32 match_flags; -}; - -static void -hws_definer_ones_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - HWS_SET32(tag, -1, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_generic_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - /* Can be optimized */ - u32 val = HWS_GET32(match_param, fc->s_byte_off, fc->s_bit_off, fc->s_bit_mask); - - HWS_SET32(tag, val, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_outer_vlan_type_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - if (HWS_GET_MATCH_PARAM(match_param, outer_headers.cvlan_tag)) - HWS_SET32(tag, STE_CVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); - else if (HWS_GET_MATCH_PARAM(match_param, outer_headers.svlan_tag)) - HWS_SET32(tag, STE_SVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); - else - HWS_SET32(tag, STE_NO_VLAN, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_inner_vlan_type_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - if (HWS_GET_MATCH_PARAM(match_param, inner_headers.cvlan_tag)) - HWS_SET32(tag, STE_CVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); - else if (HWS_GET_MATCH_PARAM(match_param, inner_headers.svlan_tag)) - HWS_SET32(tag, STE_SVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); - else - HWS_SET32(tag, STE_NO_VLAN, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_second_vlan_type_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag, - bool inner) -{ - u32 second_cvlan_tag = inner ? - HWS_GET_MATCH_PARAM(match_param, misc_parameters.inner_second_cvlan_tag) : - HWS_GET_MATCH_PARAM(match_param, misc_parameters.outer_second_cvlan_tag); - u32 second_svlan_tag = inner ? - HWS_GET_MATCH_PARAM(match_param, misc_parameters.inner_second_svlan_tag) : - HWS_GET_MATCH_PARAM(match_param, misc_parameters.outer_second_svlan_tag); - - if (second_cvlan_tag) - HWS_SET32(tag, STE_CVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); - else if (second_svlan_tag) - HWS_SET32(tag, STE_SVLAN, fc->byte_off, fc->bit_off, fc->bit_mask); - else - HWS_SET32(tag, STE_NO_VLAN, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_inner_second_vlan_type_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - hws_definer_second_vlan_type_set(fc, match_param, tag, true); -} - -static void -hws_definer_outer_second_vlan_type_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - hws_definer_second_vlan_type_set(fc, match_param, tag, false); -} - -static void hws_definer_icmp_dw1_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - u32 code = HWS_GET_MATCH_PARAM(match_param, misc_parameters_3.icmp_code); - u32 type = HWS_GET_MATCH_PARAM(match_param, misc_parameters_3.icmp_type); - u32 dw = (type << __mlx5_dw_bit_off(header_icmp, type)) | - (code << __mlx5_dw_bit_off(header_icmp, code)); - - HWS_SET32(tag, dw, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_icmpv6_dw1_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - u32 code = HWS_GET_MATCH_PARAM(match_param, misc_parameters_3.icmpv6_code); - u32 type = HWS_GET_MATCH_PARAM(match_param, misc_parameters_3.icmpv6_type); - u32 dw = (type << __mlx5_dw_bit_off(header_icmp, type)) | - (code << __mlx5_dw_bit_off(header_icmp, code)); - - HWS_SET32(tag, dw, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_l3_type_set(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - u32 val = HWS_GET32(match_param, fc->s_byte_off, fc->s_bit_off, fc->s_bit_mask); - - if (val == IPV4) - HWS_SET32(tag, STE_IPV4, fc->byte_off, fc->bit_off, fc->bit_mask); - else if (val == IPV6) - HWS_SET32(tag, STE_IPV6, fc->byte_off, fc->bit_off, fc->bit_mask); - else - HWS_SET32(tag, STE_NO_L3, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_set_source_port_gvmi(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag, - struct mlx5hws_context *peer_ctx) -{ - u16 source_port = HWS_GET_MATCH_PARAM(match_param, misc_parameters.source_port); - u16 vport_gvmi = 0; - int ret; - - ret = mlx5hws_vport_get_gvmi(peer_ctx, source_port, &vport_gvmi); - if (ret) { - HWS_SET32(tag, BAD_PORT, fc->byte_off, fc->bit_off, fc->bit_mask); - mlx5hws_err(fc->ctx, "Vport 0x%x is disabled or invalid\n", source_port); - return; - } - - if (vport_gvmi) - HWS_SET32(tag, vport_gvmi, fc->byte_off, fc->bit_off, fc->bit_mask); -} - -static void -hws_definer_set_source_gvmi_vhca_id(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -__must_hold(&fc->ctx->ctrl_lock) -{ - int id = HWS_GET_MATCH_PARAM(match_param, misc_parameters.source_eswitch_owner_vhca_id); - struct mlx5hws_context *peer_ctx; - - if (id == fc->ctx->caps->vhca_id) - peer_ctx = fc->ctx; - else - peer_ctx = xa_load(&fc->ctx->peer_ctx_xa, id); - - if (!peer_ctx) { - HWS_SET32(tag, BAD_PORT, fc->byte_off, fc->bit_off, fc->bit_mask); - mlx5hws_err(fc->ctx, "Invalid vhca_id provided 0x%x\n", id); - return; - } - - hws_definer_set_source_port_gvmi(fc, match_param, tag, peer_ctx); -} - -static void -hws_definer_set_source_gvmi(struct mlx5hws_definer_fc *fc, - void *match_param, - u8 *tag) -{ - hws_definer_set_source_port_gvmi(fc, match_param, tag, fc->ctx); -} - -static struct mlx5hws_definer_fc * -hws_definer_flex_parser_steering_ok_bits_handler(struct mlx5hws_definer_conv_data *cd, - u8 parser_id) -{ - struct mlx5hws_definer_fc *fc; - - switch (parser_id) { - case 0: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER0_OK]; - HWS_CALC_HDR_DST(fc, oks1.flex_parser0_steering_ok); - fc->tag_set = &hws_definer_generic_set; - break; - case 1: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER1_OK]; - HWS_CALC_HDR_DST(fc, oks1.flex_parser1_steering_ok); - fc->tag_set = &hws_definer_generic_set; - break; - case 2: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER2_OK]; - HWS_CALC_HDR_DST(fc, oks1.flex_parser2_steering_ok); - fc->tag_set = &hws_definer_generic_set; - break; - case 3: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER3_OK]; - HWS_CALC_HDR_DST(fc, oks1.flex_parser3_steering_ok); - fc->tag_set = &hws_definer_generic_set; - break; - case 4: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER4_OK]; - HWS_CALC_HDR_DST(fc, oks1.flex_parser4_steering_ok); - fc->tag_set = &hws_definer_generic_set; - break; - case 5: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER5_OK]; - HWS_CALC_HDR_DST(fc, oks1.flex_parser5_steering_ok); - fc->tag_set = &hws_definer_generic_set; - break; - case 6: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER6_OK]; - HWS_CALC_HDR_DST(fc, oks1.flex_parser6_steering_ok); - fc->tag_set = &hws_definer_generic_set; - break; - case 7: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER7_OK]; - HWS_CALC_HDR_DST(fc, oks1.flex_parser7_steering_ok); - fc->tag_set = &hws_definer_generic_set; - break; - default: - mlx5hws_err(cd->ctx, "Unsupported flex parser steering ok index %u\n", parser_id); - return NULL; - } - - return fc; -} - -static struct mlx5hws_definer_fc * -hws_definer_flex_parser_handler(struct mlx5hws_definer_conv_data *cd, - u8 parser_id) -{ - struct mlx5hws_definer_fc *fc; - - switch (parser_id) { - case 0: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_0]; - HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_0); - fc->tag_set = &hws_definer_generic_set; - break; - case 1: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_1]; - HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_1); - fc->tag_set = &hws_definer_generic_set; - break; - case 2: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_2]; - HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_2); - fc->tag_set = &hws_definer_generic_set; - break; - case 3: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_3]; - HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_3); - fc->tag_set = &hws_definer_generic_set; - break; - case 4: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_4]; - HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_4); - fc->tag_set = &hws_definer_generic_set; - break; - case 5: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_5]; - HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_5); - fc->tag_set = &hws_definer_generic_set; - break; - case 6: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_6]; - HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_6); - fc->tag_set = &hws_definer_generic_set; - break; - case 7: - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_FLEX_PARSER_7]; - HWS_CALC_HDR_DST(fc, flex_parser.flex_parser_7); - fc->tag_set = &hws_definer_generic_set; - break; - default: - mlx5hws_err(cd->ctx, "Unsupported flex parser %u\n", parser_id); - return NULL; - } - - return fc; -} - -static struct mlx5hws_definer_fc * -hws_definer_misc4_fields_handler(struct mlx5hws_definer_conv_data *cd, - bool *parser_is_used, - u32 id, - u32 value) -{ - if (id || value) { - if (id >= HWS_NUM_OF_FLEX_PARSERS) { - mlx5hws_err(cd->ctx, "Unsupported parser id\n"); - return NULL; - } - - if (parser_is_used[id]) { - mlx5hws_err(cd->ctx, "Parser id have been used\n"); - return NULL; - } - } - - parser_is_used[id] = true; - - return hws_definer_flex_parser_handler(cd, id); -} - -static int -hws_definer_check_match_flags(struct mlx5hws_definer_conv_data *cd) -{ - u32 flags; - - flags = cd->match_flags & (MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE | - MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE | - MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU | - MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE | - MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN | - MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_0_1); - if (flags & (flags - 1)) - goto err_conflict; - - flags = cd->match_flags & (MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE_OPT_KEY | - MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_2); - - if (flags & (flags - 1)) - goto err_conflict; - - flags = cd->match_flags & (MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_GRE | - MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_UDP); - if (flags & (flags - 1)) - goto err_conflict; - - flags = cd->match_flags & (MLX5HWS_DEFINER_MATCH_FLAG_ICMPV4 | - MLX5HWS_DEFINER_MATCH_FLAG_ICMPV6 | - MLX5HWS_DEFINER_MATCH_FLAG_TCP_O | - MLX5HWS_DEFINER_MATCH_FLAG_TCP_I); - if (flags & (flags - 1)) - goto err_conflict; - - return 0; - -err_conflict: - mlx5hws_err(cd->ctx, "Invalid definer fields combination\n"); - return -EINVAL; -} - -static int -hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd, - u32 *match_param) -{ - bool is_s_ipv6, is_d_ipv6, smac_set, dmac_set; - struct mlx5hws_definer_fc *fc = cd->fc; - struct mlx5hws_definer_fc *curr_fc; - u32 *s_ipv6, *d_ipv6; - - if (HWS_IS_FLD_SET_SZ(match_param, outer_headers.l4_type, 0x2) || - HWS_IS_FLD_SET_SZ(match_param, outer_headers.reserved_at_c2, 0xe) || - HWS_IS_FLD_SET_SZ(match_param, outer_headers.reserved_at_c4, 0x4)) { - mlx5hws_err(cd->ctx, "Unsupported outer parameters set\n"); - return -EINVAL; - } - - /* L2 Check ethertype */ - HWS_SET_HDR(fc, match_param, ETH_TYPE_O, - outer_headers.ethertype, - eth_l2_outer.l3_ethertype); - /* L2 Check SMAC 47_16 */ - HWS_SET_HDR(fc, match_param, ETH_SMAC_47_16_O, - outer_headers.smac_47_16, eth_l2_src_outer.smac_47_16); - /* L2 Check SMAC 15_0 */ - HWS_SET_HDR(fc, match_param, ETH_SMAC_15_0_O, - outer_headers.smac_15_0, eth_l2_src_outer.smac_15_0); - /* L2 Check DMAC 47_16 */ - HWS_SET_HDR(fc, match_param, ETH_DMAC_47_16_O, - outer_headers.dmac_47_16, eth_l2_outer.dmac_47_16); - /* L2 Check DMAC 15_0 */ - HWS_SET_HDR(fc, match_param, ETH_DMAC_15_0_O, - outer_headers.dmac_15_0, eth_l2_outer.dmac_15_0); - - /* L2 VLAN */ - HWS_SET_HDR(fc, match_param, VLAN_FIRST_PRIO_O, - outer_headers.first_prio, eth_l2_outer.first_priority); - HWS_SET_HDR(fc, match_param, VLAN_CFI_O, - outer_headers.first_cfi, eth_l2_outer.first_cfi); - HWS_SET_HDR(fc, match_param, VLAN_ID_O, - outer_headers.first_vid, eth_l2_outer.first_vlan_id); - - /* L2 CVLAN and SVLAN */ - if (HWS_GET_MATCH_PARAM(match_param, outer_headers.cvlan_tag) || - HWS_GET_MATCH_PARAM(match_param, outer_headers.svlan_tag)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VLAN_TYPE_O]; - HWS_CALC_HDR_DST(curr_fc, eth_l2_outer.first_vlan_qualifier); - curr_fc->tag_set = &hws_definer_outer_vlan_type_set; - curr_fc->tag_mask_set = &hws_definer_ones_set; - } - - /* L3 Check IP header */ - HWS_SET_HDR(fc, match_param, IP_PROTOCOL_O, - outer_headers.ip_protocol, - eth_l3_outer.protocol_next_header); - HWS_SET_HDR(fc, match_param, IP_TTL_O, - outer_headers.ttl_hoplimit, - eth_l3_outer.time_to_live_hop_limit); - - /* L3 Check IPv4/IPv6 addresses */ - s_ipv6 = MLX5_ADDR_OF(fte_match_param, match_param, - outer_headers.src_ipv4_src_ipv6.ipv6_layout); - d_ipv6 = MLX5_ADDR_OF(fte_match_param, match_param, - outer_headers.dst_ipv4_dst_ipv6.ipv6_layout); - - /* Assume IPv6 is used if ipv6 bits are set */ - is_s_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2]; - is_d_ipv6 = d_ipv6[0] || d_ipv6[1] || d_ipv6[2]; - - if (is_s_ipv6) { - /* Handle IPv6 source address */ - HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_O, - outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_127_96, - ipv6_src_outer.ipv6_address_127_96); - HWS_SET_HDR(fc, match_param, IPV6_SRC_95_64_O, - outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_95_64, - ipv6_src_outer.ipv6_address_95_64); - HWS_SET_HDR(fc, match_param, IPV6_SRC_63_32_O, - outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_63_32, - ipv6_src_outer.ipv6_address_63_32); - HWS_SET_HDR(fc, match_param, IPV6_SRC_31_0_O, - outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, - ipv6_src_outer.ipv6_address_31_0); - } else { - /* Handle IPv4 source address */ - HWS_SET_HDR(fc, match_param, IPV4_SRC_O, - outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, - ipv4_src_dest_outer.source_address); - } - if (is_d_ipv6) { - /* Handle IPv6 destination address */ - HWS_SET_HDR(fc, match_param, IPV6_DST_127_96_O, - outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_127_96, - ipv6_dst_outer.ipv6_address_127_96); - HWS_SET_HDR(fc, match_param, IPV6_DST_95_64_O, - outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_95_64, - ipv6_dst_outer.ipv6_address_95_64); - HWS_SET_HDR(fc, match_param, IPV6_DST_63_32_O, - outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_63_32, - ipv6_dst_outer.ipv6_address_63_32); - HWS_SET_HDR(fc, match_param, IPV6_DST_31_0_O, - outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, - ipv6_dst_outer.ipv6_address_31_0); - } else { - /* Handle IPv4 destination address */ - HWS_SET_HDR(fc, match_param, IPV4_DST_O, - outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, - ipv4_src_dest_outer.destination_address); - } - - /* L4 Handle TCP/UDP */ - HWS_SET_HDR(fc, match_param, L4_SPORT_O, - outer_headers.tcp_sport, eth_l4_outer.source_port); - HWS_SET_HDR(fc, match_param, L4_DPORT_O, - outer_headers.tcp_dport, eth_l4_outer.destination_port); - HWS_SET_HDR(fc, match_param, L4_SPORT_O, - outer_headers.udp_sport, eth_l4_outer.source_port); - HWS_SET_HDR(fc, match_param, L4_DPORT_O, - outer_headers.udp_dport, eth_l4_outer.destination_port); - HWS_SET_HDR(fc, match_param, TCP_FLAGS_O, - outer_headers.tcp_flags, eth_l4_outer.tcp_flags); - - /* L3 Handle DSCP, ECN and IHL */ - HWS_SET_HDR(fc, match_param, IP_DSCP_O, - outer_headers.ip_dscp, eth_l3_outer.dscp); - HWS_SET_HDR(fc, match_param, IP_ECN_O, - outer_headers.ip_ecn, eth_l3_outer.ecn); - HWS_SET_HDR(fc, match_param, IPV4_IHL_O, - outer_headers.ipv4_ihl, eth_l3_outer.ihl); - - /* Set IP fragmented bit */ - if (HWS_IS_FLD_SET(match_param, outer_headers.frag)) { - smac_set = HWS_IS_FLD_SET(match_param, outer_headers.smac_15_0) || - HWS_IS_FLD_SET(match_param, outer_headers.smac_47_16); - dmac_set = HWS_IS_FLD_SET(match_param, outer_headers.dmac_15_0) || - HWS_IS_FLD_SET(match_param, outer_headers.dmac_47_16); - if (smac_set == dmac_set) { - HWS_SET_HDR(fc, match_param, IP_FRAG_O, - outer_headers.frag, eth_l4_outer.ip_fragmented); - } else { - HWS_SET_HDR(fc, match_param, IP_FRAG_O, - outer_headers.frag, eth_l2_src_outer.ip_fragmented); - } - } - - /* L3_type set */ - if (HWS_IS_FLD_SET(match_param, outer_headers.ip_version)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_O]; - HWS_CALC_HDR_DST(curr_fc, eth_l2_outer.l3_type); - curr_fc->tag_set = &hws_definer_l3_type_set; - curr_fc->tag_mask_set = &hws_definer_ones_set; - HWS_CALC_HDR_SRC(curr_fc, outer_headers.ip_version); - } - - return 0; -} - -static int -hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd, - u32 *match_param) -{ - bool is_s_ipv6, is_d_ipv6, smac_set, dmac_set; - struct mlx5hws_definer_fc *fc = cd->fc; - struct mlx5hws_definer_fc *curr_fc; - u32 *s_ipv6, *d_ipv6; - - if (HWS_IS_FLD_SET_SZ(match_param, inner_headers.l4_type, 0x2) || - HWS_IS_FLD_SET_SZ(match_param, inner_headers.reserved_at_c2, 0xe) || - HWS_IS_FLD_SET_SZ(match_param, inner_headers.reserved_at_c4, 0x4)) { - mlx5hws_err(cd->ctx, "Unsupported inner parameters set\n"); - return -EINVAL; - } - - /* L2 Check ethertype */ - HWS_SET_HDR(fc, match_param, ETH_TYPE_I, - inner_headers.ethertype, - eth_l2_inner.l3_ethertype); - /* L2 Check SMAC 47_16 */ - HWS_SET_HDR(fc, match_param, ETH_SMAC_47_16_I, - inner_headers.smac_47_16, eth_l2_src_inner.smac_47_16); - /* L2 Check SMAC 15_0 */ - HWS_SET_HDR(fc, match_param, ETH_SMAC_15_0_I, - inner_headers.smac_15_0, eth_l2_src_inner.smac_15_0); - /* L2 Check DMAC 47_16 */ - HWS_SET_HDR(fc, match_param, ETH_DMAC_47_16_I, - inner_headers.dmac_47_16, eth_l2_inner.dmac_47_16); - /* L2 Check DMAC 15_0 */ - HWS_SET_HDR(fc, match_param, ETH_DMAC_15_0_I, - inner_headers.dmac_15_0, eth_l2_inner.dmac_15_0); - - /* L2 VLAN */ - HWS_SET_HDR(fc, match_param, VLAN_FIRST_PRIO_I, - inner_headers.first_prio, eth_l2_inner.first_priority); - HWS_SET_HDR(fc, match_param, VLAN_CFI_I, - inner_headers.first_cfi, eth_l2_inner.first_cfi); - HWS_SET_HDR(fc, match_param, VLAN_ID_I, - inner_headers.first_vid, eth_l2_inner.first_vlan_id); - - /* L2 CVLAN and SVLAN */ - if (HWS_GET_MATCH_PARAM(match_param, inner_headers.cvlan_tag) || - HWS_GET_MATCH_PARAM(match_param, inner_headers.svlan_tag)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VLAN_TYPE_I]; - HWS_CALC_HDR_DST(curr_fc, eth_l2_inner.first_vlan_qualifier); - curr_fc->tag_set = &hws_definer_inner_vlan_type_set; - curr_fc->tag_mask_set = &hws_definer_ones_set; - } - /* L3 Check IP header */ - HWS_SET_HDR(fc, match_param, IP_PROTOCOL_I, - inner_headers.ip_protocol, - eth_l3_inner.protocol_next_header); - HWS_SET_HDR(fc, match_param, IP_VERSION_I, - inner_headers.ip_version, - eth_l3_inner.ip_version); - HWS_SET_HDR(fc, match_param, IP_TTL_I, - inner_headers.ttl_hoplimit, - eth_l3_inner.time_to_live_hop_limit); - - /* L3 Check IPv4/IPv6 addresses */ - s_ipv6 = MLX5_ADDR_OF(fte_match_param, match_param, - inner_headers.src_ipv4_src_ipv6.ipv6_layout); - d_ipv6 = MLX5_ADDR_OF(fte_match_param, match_param, - inner_headers.dst_ipv4_dst_ipv6.ipv6_layout); - - /* Assume IPv6 is used if ipv6 bits are set */ - is_s_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2]; - is_d_ipv6 = d_ipv6[0] || d_ipv6[1] || d_ipv6[2]; - - if (is_s_ipv6) { - /* Handle IPv6 source address */ - HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_I, - inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_127_96, - ipv6_src_inner.ipv6_address_127_96); - HWS_SET_HDR(fc, match_param, IPV6_SRC_95_64_I, - inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_95_64, - ipv6_src_inner.ipv6_address_95_64); - HWS_SET_HDR(fc, match_param, IPV6_SRC_63_32_I, - inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_63_32, - ipv6_src_inner.ipv6_address_63_32); - HWS_SET_HDR(fc, match_param, IPV6_SRC_31_0_I, - inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, - ipv6_src_inner.ipv6_address_31_0); - } else { - /* Handle IPv4 source address */ - HWS_SET_HDR(fc, match_param, IPV4_SRC_I, - inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0, - ipv4_src_dest_inner.source_address); - } - if (is_d_ipv6) { - /* Handle IPv6 destination address */ - HWS_SET_HDR(fc, match_param, IPV6_DST_127_96_I, - inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_127_96, - ipv6_dst_inner.ipv6_address_127_96); - HWS_SET_HDR(fc, match_param, IPV6_DST_95_64_I, - inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_95_64, - ipv6_dst_inner.ipv6_address_95_64); - HWS_SET_HDR(fc, match_param, IPV6_DST_63_32_I, - inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_63_32, - ipv6_dst_inner.ipv6_address_63_32); - HWS_SET_HDR(fc, match_param, IPV6_DST_31_0_I, - inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, - ipv6_dst_inner.ipv6_address_31_0); - } else { - /* Handle IPv4 destination address */ - HWS_SET_HDR(fc, match_param, IPV4_DST_I, - inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0, - ipv4_src_dest_inner.destination_address); - } - - /* L4 Handle TCP/UDP */ - HWS_SET_HDR(fc, match_param, L4_SPORT_I, - inner_headers.tcp_sport, eth_l4_inner.source_port); - HWS_SET_HDR(fc, match_param, L4_DPORT_I, - inner_headers.tcp_dport, eth_l4_inner.destination_port); - HWS_SET_HDR(fc, match_param, L4_SPORT_I, - inner_headers.udp_sport, eth_l4_inner.source_port); - HWS_SET_HDR(fc, match_param, L4_DPORT_I, - inner_headers.udp_dport, eth_l4_inner.destination_port); - HWS_SET_HDR(fc, match_param, TCP_FLAGS_I, - inner_headers.tcp_flags, eth_l4_inner.tcp_flags); - - /* L3 Handle DSCP, ECN and IHL */ - HWS_SET_HDR(fc, match_param, IP_DSCP_I, - inner_headers.ip_dscp, eth_l3_inner.dscp); - HWS_SET_HDR(fc, match_param, IP_ECN_I, - inner_headers.ip_ecn, eth_l3_inner.ecn); - HWS_SET_HDR(fc, match_param, IPV4_IHL_I, - inner_headers.ipv4_ihl, eth_l3_inner.ihl); - - /* Set IP fragmented bit */ - if (HWS_IS_FLD_SET(match_param, inner_headers.frag)) { - if (HWS_IS_FLD_SET(match_param, misc_parameters.vxlan_vni)) { - HWS_SET_HDR(fc, match_param, IP_FRAG_I, - inner_headers.frag, eth_l2_inner.ip_fragmented); - } else { - smac_set = HWS_IS_FLD_SET(match_param, inner_headers.smac_15_0) || - HWS_IS_FLD_SET(match_param, inner_headers.smac_47_16); - dmac_set = HWS_IS_FLD_SET(match_param, inner_headers.dmac_15_0) || - HWS_IS_FLD_SET(match_param, inner_headers.dmac_47_16); - if (smac_set == dmac_set) { - HWS_SET_HDR(fc, match_param, IP_FRAG_I, - inner_headers.frag, eth_l4_inner.ip_fragmented); - } else { - HWS_SET_HDR(fc, match_param, IP_FRAG_I, - inner_headers.frag, eth_l2_src_inner.ip_fragmented); - } - } - } - - /* L3_type set */ - if (HWS_IS_FLD_SET(match_param, inner_headers.ip_version)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_I]; - HWS_CALC_HDR_DST(curr_fc, eth_l2_inner.l3_type); - curr_fc->tag_set = &hws_definer_l3_type_set; - curr_fc->tag_mask_set = &hws_definer_ones_set; - HWS_CALC_HDR_SRC(curr_fc, inner_headers.ip_version); - } - - return 0; -} - -static int -hws_definer_conv_misc(struct mlx5hws_definer_conv_data *cd, - u32 *match_param) -{ - struct mlx5hws_cmd_query_caps *caps = cd->ctx->caps; - struct mlx5hws_definer_fc *fc = cd->fc; - struct mlx5hws_definer_fc *curr_fc; - - if (HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_1, 0x1) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_64, 0xc) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_d8, 0x6) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_e0, 0xc) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_100, 0xc) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_120, 0xa) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_140, 0x8) || - HWS_IS_FLD_SET(match_param, misc_parameters.bth_dst_qp) || - HWS_IS_FLD_SET(match_param, misc_parameters.bth_opcode) || - HWS_IS_FLD_SET(match_param, misc_parameters.inner_esp_spi) || - HWS_IS_FLD_SET(match_param, misc_parameters.outer_esp_spi) || - HWS_IS_FLD_SET(match_param, misc_parameters.source_vhca_port) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters.reserved_at_1a0, 0x60)) { - mlx5hws_err(cd->ctx, "Unsupported misc parameters set\n"); - return -EINVAL; - } - - /* Check GRE related fields */ - if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_c_present)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GRE_C]; - HWS_CALC_HDR(curr_fc, - misc_parameters.gre_c_present, - tunnel_header.tunnel_header_0); - curr_fc->bit_mask = __mlx5_mask(header_gre, gre_c_present); - curr_fc->bit_off = __mlx5_dw_bit_off(header_gre, gre_c_present); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_k_present)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GRE_K]; - HWS_CALC_HDR(curr_fc, - misc_parameters.gre_k_present, - tunnel_header.tunnel_header_0); - curr_fc->bit_mask = __mlx5_mask(header_gre, gre_k_present); - curr_fc->bit_off = __mlx5_dw_bit_off(header_gre, gre_k_present); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_s_present)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GRE_S]; - HWS_CALC_HDR(curr_fc, - misc_parameters.gre_s_present, - tunnel_header.tunnel_header_0); - curr_fc->bit_mask = __mlx5_mask(header_gre, gre_s_present); - curr_fc->bit_off = __mlx5_dw_bit_off(header_gre, gre_s_present); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_protocol)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GRE_PROTOCOL]; - HWS_CALC_HDR(curr_fc, - misc_parameters.gre_protocol, - tunnel_header.tunnel_header_0); - curr_fc->bit_mask = __mlx5_mask(header_gre, gre_protocol); - curr_fc->bit_off = __mlx5_dw_bit_off(header_gre, gre_protocol); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters.gre_key.key)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE | - MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE_OPT_KEY; - HWS_SET_HDR(fc, match_param, GRE_OPT_KEY, - misc_parameters.gre_key.key, tunnel_header.tunnel_header_2); - } - - /* Check GENEVE related fields */ - if (HWS_IS_FLD_SET(match_param, misc_parameters.geneve_vni)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GENEVE_VNI]; - HWS_CALC_HDR(curr_fc, - misc_parameters.geneve_vni, - tunnel_header.tunnel_header_1); - curr_fc->bit_mask = __mlx5_mask(header_geneve, vni); - curr_fc->bit_off = __mlx5_dw_bit_off(header_geneve, vni); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters.geneve_opt_len)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GENEVE_OPT_LEN]; - HWS_CALC_HDR(curr_fc, - misc_parameters.geneve_opt_len, - tunnel_header.tunnel_header_0); - curr_fc->bit_mask = __mlx5_mask(header_geneve, opt_len); - curr_fc->bit_off = __mlx5_dw_bit_off(header_geneve, opt_len); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters.geneve_protocol_type)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GENEVE_PROTO]; - HWS_CALC_HDR(curr_fc, - misc_parameters.geneve_protocol_type, - tunnel_header.tunnel_header_0); - curr_fc->bit_mask = __mlx5_mask(header_geneve, protocol_type); - curr_fc->bit_off = __mlx5_dw_bit_off(header_geneve, protocol_type); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters.geneve_oam)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GENEVE_OAM]; - HWS_CALC_HDR(curr_fc, - misc_parameters.geneve_oam, - tunnel_header.tunnel_header_0); - curr_fc->bit_mask = __mlx5_mask(header_geneve, o_flag); - curr_fc->bit_off = __mlx5_dw_bit_off(header_geneve, o_flag); - } - - HWS_SET_HDR(fc, match_param, SOURCE_QP, - misc_parameters.source_sqn, source_qp_gvmi.source_qp); - HWS_SET_HDR(fc, match_param, IPV6_FLOW_LABEL_O, - misc_parameters.outer_ipv6_flow_label, eth_l3_outer.flow_label); - HWS_SET_HDR(fc, match_param, IPV6_FLOW_LABEL_I, - misc_parameters.inner_ipv6_flow_label, eth_l3_inner.flow_label); - - /* L2 Second VLAN */ - HWS_SET_HDR(fc, match_param, VLAN_SECOND_PRIO_O, - misc_parameters.outer_second_prio, eth_l2_outer.second_priority); - HWS_SET_HDR(fc, match_param, VLAN_SECOND_PRIO_I, - misc_parameters.inner_second_prio, eth_l2_inner.second_priority); - HWS_SET_HDR(fc, match_param, VLAN_SECOND_CFI_O, - misc_parameters.outer_second_cfi, eth_l2_outer.second_cfi); - HWS_SET_HDR(fc, match_param, VLAN_SECOND_CFI_I, - misc_parameters.inner_second_cfi, eth_l2_inner.second_cfi); - HWS_SET_HDR(fc, match_param, VLAN_SECOND_ID_O, - misc_parameters.outer_second_vid, eth_l2_outer.second_vlan_id); - HWS_SET_HDR(fc, match_param, VLAN_SECOND_ID_I, - misc_parameters.inner_second_vid, eth_l2_inner.second_vlan_id); - - /* L2 Second CVLAN and SVLAN */ - if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.outer_second_cvlan_tag) || - HWS_GET_MATCH_PARAM(match_param, misc_parameters.outer_second_svlan_tag)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VLAN_SECOND_TYPE_O]; - HWS_CALC_HDR_DST(curr_fc, eth_l2_outer.second_vlan_qualifier); - curr_fc->tag_set = &hws_definer_outer_second_vlan_type_set; - curr_fc->tag_mask_set = &hws_definer_ones_set; - } - - if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.inner_second_cvlan_tag) || - HWS_GET_MATCH_PARAM(match_param, misc_parameters.inner_second_svlan_tag)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VLAN_SECOND_TYPE_I]; - HWS_CALC_HDR_DST(curr_fc, eth_l2_inner.second_vlan_qualifier); - curr_fc->tag_set = &hws_definer_inner_second_vlan_type_set; - curr_fc->tag_mask_set = &hws_definer_ones_set; - } - - /* VXLAN VNI */ - if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.vxlan_vni)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN; - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VXLAN_VNI]; - HWS_CALC_HDR(curr_fc, misc_parameters.vxlan_vni, tunnel_header.tunnel_header_1); - curr_fc->bit_mask = __mlx5_mask(header_vxlan, vni); - curr_fc->bit_off = __mlx5_dw_bit_off(header_vxlan, vni); - } - - /* Flex protocol steering ok bits */ - if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.geneve_tlv_option_0_exist)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; - - if (!caps->flex_parser_ok_bits_supp) { - mlx5hws_err(cd->ctx, "Unsupported flex_parser_ok_bits_supp capability\n"); - return -EOPNOTSUPP; - } - - curr_fc = hws_definer_flex_parser_steering_ok_bits_handler( - cd, caps->flex_parser_id_geneve_tlv_option_0); - if (!curr_fc) - return -EINVAL; - - HWS_CALC_HDR_SRC(fc, misc_parameters.geneve_tlv_option_0_exist); - } - - if (HWS_GET_MATCH_PARAM(match_param, misc_parameters.source_port)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_SOURCE_GVMI]; - HWS_CALC_HDR_DST(curr_fc, source_qp_gvmi.source_gvmi); - curr_fc->tag_mask_set = &hws_definer_ones_set; - curr_fc->tag_set = HWS_IS_FLD_SET(match_param, - misc_parameters.source_eswitch_owner_vhca_id) ? - &hws_definer_set_source_gvmi_vhca_id : - &hws_definer_set_source_gvmi; - } else { - if (HWS_IS_FLD_SET(match_param, misc_parameters.source_eswitch_owner_vhca_id)) { - mlx5hws_err(cd->ctx, - "Unsupported source_eswitch_owner_vhca_id field usage\n"); - return -EOPNOTSUPP; - } - } - - return 0; -} - -static int -hws_definer_conv_misc2(struct mlx5hws_definer_conv_data *cd, - u32 *match_param) -{ - struct mlx5hws_cmd_query_caps *caps = cd->ctx->caps; - struct mlx5hws_definer_fc *fc = cd->fc; - struct mlx5hws_definer_fc *curr_fc; - - if (HWS_IS_FLD_SET_SZ(match_param, misc_parameters_2.reserved_at_1a0, 0x8) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters_2.reserved_at_1b8, 0x8) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters_2.reserved_at_1c0, 0x40) || - HWS_IS_FLD_SET(match_param, misc_parameters_2.macsec_syndrome) || - HWS_IS_FLD_SET(match_param, misc_parameters_2.ipsec_syndrome)) { - mlx5hws_err(cd->ctx, "Unsupported misc2 parameters set\n"); - return -EINVAL; - } - - HWS_SET_HDR(fc, match_param, MPLS0_O, - misc_parameters_2.outer_first_mpls, mpls_outer.mpls0_label); - HWS_SET_HDR(fc, match_param, MPLS0_I, - misc_parameters_2.inner_first_mpls, mpls_inner.mpls0_label); - HWS_SET_HDR(fc, match_param, REG_0, - misc_parameters_2.metadata_reg_c_0, registers.register_c_0); - HWS_SET_HDR(fc, match_param, REG_1, - misc_parameters_2.metadata_reg_c_1, registers.register_c_1); - HWS_SET_HDR(fc, match_param, REG_2, - misc_parameters_2.metadata_reg_c_2, registers.register_c_2); - HWS_SET_HDR(fc, match_param, REG_3, - misc_parameters_2.metadata_reg_c_3, registers.register_c_3); - HWS_SET_HDR(fc, match_param, REG_4, - misc_parameters_2.metadata_reg_c_4, registers.register_c_4); - HWS_SET_HDR(fc, match_param, REG_5, - misc_parameters_2.metadata_reg_c_5, registers.register_c_5); - HWS_SET_HDR(fc, match_param, REG_6, - misc_parameters_2.metadata_reg_c_6, registers.register_c_6); - HWS_SET_HDR(fc, match_param, REG_7, - misc_parameters_2.metadata_reg_c_7, registers.register_c_7); - HWS_SET_HDR(fc, match_param, REG_A, - misc_parameters_2.metadata_reg_a, metadata.general_purpose); - - if (HWS_IS_FLD_SET(match_param, misc_parameters_2.outer_first_mpls_over_gre)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_GRE; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported misc2 first mpls over gre parameters set\n"); - return -EOPNOTSUPP; - } - - curr_fc = hws_definer_flex_parser_handler(cd, caps->flex_parser_id_mpls_over_gre); - if (!curr_fc) - return -EINVAL; - - HWS_CALC_HDR_SRC(fc, misc_parameters_2.outer_first_mpls_over_gre); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_2.outer_first_mpls_over_udp)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_UDP; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported misc2 first mpls over udp parameters set\n"); - return -EOPNOTSUPP; - } - - curr_fc = hws_definer_flex_parser_handler(cd, caps->flex_parser_id_mpls_over_udp); - if (!curr_fc) - return -EINVAL; - - HWS_CALC_HDR_SRC(fc, misc_parameters_2.outer_first_mpls_over_udp); - } - - return 0; -} - -static int -hws_definer_conv_misc3(struct mlx5hws_definer_conv_data *cd, u32 *match_param) -{ - struct mlx5hws_cmd_query_caps *caps = cd->ctx->caps; - struct mlx5hws_definer_fc *fc = cd->fc; - struct mlx5hws_definer_fc *curr_fc; - bool vxlan_gpe_flex_parser_enabled; - - /* Check reserved and unsupported fields */ - if (HWS_IS_FLD_SET_SZ(match_param, misc_parameters_3.reserved_at_80, 0x8) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters_3.reserved_at_b0, 0x10) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters_3.reserved_at_170, 0x10) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters_3.reserved_at_1e0, 0x20)) { - mlx5hws_err(cd->ctx, "Unsupported misc3 parameters set\n"); - return -EINVAL; - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.inner_tcp_seq_num) || - HWS_IS_FLD_SET(match_param, misc_parameters_3.inner_tcp_ack_num)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TCP_I; - HWS_SET_HDR(fc, match_param, TCP_SEQ_NUM, - misc_parameters_3.inner_tcp_seq_num, tcp_icmp.tcp_seq); - HWS_SET_HDR(fc, match_param, TCP_ACK_NUM, - misc_parameters_3.inner_tcp_ack_num, tcp_icmp.tcp_ack); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_tcp_seq_num) || - HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_tcp_ack_num)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TCP_O; - HWS_SET_HDR(fc, match_param, TCP_SEQ_NUM, - misc_parameters_3.outer_tcp_seq_num, tcp_icmp.tcp_seq); - HWS_SET_HDR(fc, match_param, TCP_ACK_NUM, - misc_parameters_3.outer_tcp_ack_num, tcp_icmp.tcp_ack); - } - - vxlan_gpe_flex_parser_enabled = caps->flex_protocols & MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED; - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_vxlan_gpe_vni)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE; - - if (!vxlan_gpe_flex_parser_enabled) { - mlx5hws_err(cd->ctx, "Unsupported VXLAN GPE flex parser\n"); - return -EOPNOTSUPP; - } - - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VXLAN_GPE_VNI]; - HWS_CALC_HDR(curr_fc, misc_parameters_3.outer_vxlan_gpe_vni, - tunnel_header.tunnel_header_1); - curr_fc->bit_mask = __mlx5_mask(header_vxlan_gpe, vni); - curr_fc->bit_off = __mlx5_dw_bit_off(header_vxlan_gpe, vni); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_vxlan_gpe_next_protocol)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE; - - if (!vxlan_gpe_flex_parser_enabled) { - mlx5hws_err(cd->ctx, "Unsupported VXLAN GPE flex parser\n"); - return -EOPNOTSUPP; - } - - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VXLAN_GPE_PROTO]; - HWS_CALC_HDR(curr_fc, misc_parameters_3.outer_vxlan_gpe_next_protocol, - tunnel_header.tunnel_header_0); - curr_fc->byte_off += MLX5_BYTE_OFF(header_vxlan_gpe, protocol); - curr_fc->bit_mask = __mlx5_mask(header_vxlan_gpe, protocol); - curr_fc->bit_off = __mlx5_dw_bit_off(header_vxlan_gpe, protocol); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.outer_vxlan_gpe_flags)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE; - - if (!vxlan_gpe_flex_parser_enabled) { - mlx5hws_err(cd->ctx, "Unsupported VXLAN GPE flex parser\n"); - return -EOPNOTSUPP; - } - - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_VXLAN_GPE_FLAGS]; - HWS_CALC_HDR(curr_fc, misc_parameters_3.outer_vxlan_gpe_flags, - tunnel_header.tunnel_header_0); - curr_fc->bit_mask = __mlx5_mask(header_vxlan_gpe, flags); - curr_fc->bit_off = __mlx5_dw_bit_off(header_vxlan_gpe, flags); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_header_data) || - HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_type) || - HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_code)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_ICMPV4; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V4_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported ICMPv4 flex parser\n"); - return -EOPNOTSUPP; - } - - HWS_SET_HDR(fc, match_param, ICMP_DW3, - misc_parameters_3.icmp_header_data, tcp_icmp.icmp_dw3); - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_type) || - HWS_IS_FLD_SET(match_param, misc_parameters_3.icmp_code)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_ICMP_DW1]; - HWS_CALC_HDR_DST(curr_fc, tcp_icmp.icmp_dw1); - curr_fc->tag_set = &hws_definer_icmp_dw1_set; - } - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_header_data) || - HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_type) || - HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_code)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_ICMPV6; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V6_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported ICMPv6 parser\n"); - return -EOPNOTSUPP; - } - - HWS_SET_HDR(fc, match_param, ICMP_DW3, - misc_parameters_3.icmpv6_header_data, tcp_icmp.icmp_dw3); - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_type) || - HWS_IS_FLD_SET(match_param, misc_parameters_3.icmpv6_code)) { - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_ICMP_DW1]; - HWS_CALC_HDR_DST(curr_fc, tcp_icmp.icmp_dw1); - curr_fc->tag_set = &hws_definer_icmpv6_dw1_set; - } - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.geneve_tlv_option_0_data)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE; - - curr_fc = - hws_definer_flex_parser_handler(cd, - caps->flex_parser_id_geneve_tlv_option_0); - if (!curr_fc) - return -EINVAL; - - HWS_CALC_HDR_SRC(fc, misc_parameters_3.geneve_tlv_option_0_data); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_teid)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_TEID_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported GTPU TEID flex parser\n"); - return -EOPNOTSUPP; - } - - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_GTP_TEID]; - fc->tag_set = &hws_definer_generic_set; - fc->bit_mask = __mlx5_mask(header_gtp, teid); - fc->byte_off = caps->format_select_gtpu_dw_1 * DW_SIZE; - HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_teid); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_msg_type)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported GTPU flex parser\n"); - return -EOPNOTSUPP; - } - - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_GTP_MSG_TYPE]; - fc->tag_set = &hws_definer_generic_set; - fc->bit_mask = __mlx5_mask(header_gtp, msg_type); - fc->bit_off = __mlx5_dw_bit_off(header_gtp, msg_type); - fc->byte_off = caps->format_select_gtpu_dw_0 * DW_SIZE; - HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_msg_type); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_msg_flags)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported GTPU flex parser\n"); - return -EOPNOTSUPP; - } - - fc = &cd->fc[MLX5HWS_DEFINER_FNAME_GTP_MSG_TYPE]; - fc->tag_set = &hws_definer_generic_set; - fc->bit_mask = __mlx5_mask(header_gtp, msg_flags); - fc->bit_off = __mlx5_dw_bit_off(header_gtp, msg_flags); - fc->byte_off = caps->format_select_gtpu_dw_0 * DW_SIZE; - HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_msg_flags); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_dw_2)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_2_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported GTPU DW2 flex parser\n"); - return -EOPNOTSUPP; - } - - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GTPU_DW2]; - curr_fc->tag_set = &hws_definer_generic_set; - curr_fc->bit_mask = -1; - curr_fc->byte_off = caps->format_select_gtpu_dw_2 * DW_SIZE; - HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_dw_2); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_first_ext_dw_0)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_FIRST_EXT_DW_0_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported GTPU first EXT DW0 flex parser\n"); - return -EOPNOTSUPP; - } - - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GTPU_FIRST_EXT_DW0]; - curr_fc->tag_set = &hws_definer_generic_set; - curr_fc->bit_mask = -1; - curr_fc->byte_off = caps->format_select_gtpu_ext_dw_0 * DW_SIZE; - HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_first_ext_dw_0); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_3.gtpu_dw_0)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU; - - if (!(caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_0_ENABLED)) { - mlx5hws_err(cd->ctx, "Unsupported GTPU DW0 flex parser\n"); - return -EOPNOTSUPP; - } - - curr_fc = &fc[MLX5HWS_DEFINER_FNAME_GTPU_DW0]; - curr_fc->tag_set = &hws_definer_generic_set; - curr_fc->bit_mask = -1; - curr_fc->byte_off = caps->format_select_gtpu_dw_0 * DW_SIZE; - HWS_CALC_HDR_SRC(fc, misc_parameters_3.gtpu_dw_0); - } - - return 0; -} - -static int -hws_definer_conv_misc4(struct mlx5hws_definer_conv_data *cd, - u32 *match_param) -{ - bool parser_is_used[HWS_NUM_OF_FLEX_PARSERS] = {}; - struct mlx5hws_definer_fc *fc; - u32 id, value; - - if (HWS_IS_FLD_SET_SZ(match_param, misc_parameters_4.reserved_at_100, 0x100)) { - mlx5hws_err(cd->ctx, "Unsupported misc4 parameters set\n"); - return -EINVAL; - } - - id = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_id_0); - value = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_value_0); - fc = hws_definer_misc4_fields_handler(cd, parser_is_used, id, value); - if (!fc) - return -EINVAL; - - HWS_CALC_HDR_SRC(fc, misc_parameters_4.prog_sample_field_value_0); - - id = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_id_1); - value = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_value_1); - fc = hws_definer_misc4_fields_handler(cd, parser_is_used, id, value); - if (!fc) - return -EINVAL; - - HWS_CALC_HDR_SRC(fc, misc_parameters_4.prog_sample_field_value_1); - - id = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_id_2); - value = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_value_2); - fc = hws_definer_misc4_fields_handler(cd, parser_is_used, id, value); - if (!fc) - return -EINVAL; - - HWS_CALC_HDR_SRC(fc, misc_parameters_4.prog_sample_field_value_2); - - id = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_id_3); - value = HWS_GET_MATCH_PARAM(match_param, misc_parameters_4.prog_sample_field_value_3); - fc = hws_definer_misc4_fields_handler(cd, parser_is_used, id, value); - if (!fc) - return -EINVAL; - - HWS_CALC_HDR_SRC(fc, misc_parameters_4.prog_sample_field_value_3); - - return 0; -} - -static int -hws_definer_conv_misc5(struct mlx5hws_definer_conv_data *cd, - u32 *match_param) -{ - struct mlx5hws_definer_fc *fc = cd->fc; - - if (HWS_IS_FLD_SET(match_param, misc_parameters_5.macsec_tag_0) || - HWS_IS_FLD_SET(match_param, misc_parameters_5.macsec_tag_1) || - HWS_IS_FLD_SET(match_param, misc_parameters_5.macsec_tag_2) || - HWS_IS_FLD_SET(match_param, misc_parameters_5.macsec_tag_3) || - HWS_IS_FLD_SET_SZ(match_param, misc_parameters_5.reserved_at_100, 0x100)) { - mlx5hws_err(cd->ctx, "Unsupported misc5 parameters set\n"); - return -EINVAL; - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_5.tunnel_header_0)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_0_1; - HWS_SET_HDR(fc, match_param, TNL_HDR_0, - misc_parameters_5.tunnel_header_0, tunnel_header.tunnel_header_0); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_5.tunnel_header_1)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_0_1; - HWS_SET_HDR(fc, match_param, TNL_HDR_1, - misc_parameters_5.tunnel_header_1, tunnel_header.tunnel_header_1); - } - - if (HWS_IS_FLD_SET(match_param, misc_parameters_5.tunnel_header_2)) { - cd->match_flags |= MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_2; - HWS_SET_HDR(fc, match_param, TNL_HDR_2, - misc_parameters_5.tunnel_header_2, tunnel_header.tunnel_header_2); - } - - HWS_SET_HDR(fc, match_param, TNL_HDR_3, - misc_parameters_5.tunnel_header_3, tunnel_header.tunnel_header_3); - - return 0; -} - -static int hws_definer_get_fc_size(struct mlx5hws_definer_fc *fc) -{ - u32 fc_sz = 0; - int i; - - /* For empty matcher, ZERO_SIZE_PTR is returned */ - if (fc == ZERO_SIZE_PTR) - return 0; - - for (i = 0; i < MLX5HWS_DEFINER_FNAME_MAX; i++) - if (fc[i].tag_set) - fc_sz++; - return fc_sz; -} - -static struct mlx5hws_definer_fc * -hws_definer_alloc_compressed_fc(struct mlx5hws_definer_fc *fc) -{ - struct mlx5hws_definer_fc *compressed_fc = NULL; - u32 definer_size = hws_definer_get_fc_size(fc); - u32 fc_sz = 0; - int i; - - compressed_fc = kcalloc(definer_size, sizeof(*compressed_fc), GFP_KERNEL); - if (!compressed_fc) - return NULL; - - /* For empty matcher, ZERO_SIZE_PTR is returned */ - if (!definer_size) - return compressed_fc; - - for (i = 0, fc_sz = 0; i < MLX5HWS_DEFINER_FNAME_MAX; i++) { - if (!fc[i].tag_set) - continue; - - fc[i].fname = i; - memcpy(&compressed_fc[fc_sz++], &fc[i], sizeof(*compressed_fc)); - } - - return compressed_fc; -} - -static void -hws_definer_set_hl(u8 *hl, struct mlx5hws_definer_fc *fc) -{ - int i; - - /* nothing to do for empty matcher */ - if (fc == ZERO_SIZE_PTR) - return; - - for (i = 0; i < MLX5HWS_DEFINER_FNAME_MAX; i++) { - if (!fc[i].tag_set) - continue; - - HWS_SET32(hl, -1, fc[i].byte_off, fc[i].bit_off, fc[i].bit_mask); - } -} - -static struct mlx5hws_definer_fc * -hws_definer_alloc_fc(struct mlx5hws_context *ctx, - size_t len) -{ - struct mlx5hws_definer_fc *fc; - int i; - - fc = kcalloc(len, sizeof(*fc), GFP_KERNEL); - if (!fc) - return NULL; - - for (i = 0; i < len; i++) - fc[i].ctx = ctx; - - return fc; -} - -static int -hws_definer_conv_match_params_to_hl(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt, - u8 *hl) -{ - struct mlx5hws_definer_conv_data cd = {0}; - struct mlx5hws_definer_fc *fc; - int ret; - - fc = hws_definer_alloc_fc(ctx, MLX5HWS_DEFINER_FNAME_MAX); - if (!fc) - return -ENOMEM; - - cd.fc = fc; - cd.ctx = ctx; - - if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC6) { - mlx5hws_err(ctx, "Unsupported match_criteria_enable provided\n"); - ret = -EOPNOTSUPP; - goto err_free_fc; - } - - if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_OUTER) { - ret = hws_definer_conv_outer(&cd, mt->match_param); - if (ret) - goto err_free_fc; - } - - if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_INNER) { - ret = hws_definer_conv_inner(&cd, mt->match_param); - if (ret) - goto err_free_fc; - } - - if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC) { - ret = hws_definer_conv_misc(&cd, mt->match_param); - if (ret) - goto err_free_fc; - } - - if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC2) { - ret = hws_definer_conv_misc2(&cd, mt->match_param); - if (ret) - goto err_free_fc; - } - - if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC3) { - ret = hws_definer_conv_misc3(&cd, mt->match_param); - if (ret) - goto err_free_fc; - } - - if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC4) { - ret = hws_definer_conv_misc4(&cd, mt->match_param); - if (ret) - goto err_free_fc; - } - - if (mt->match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC5) { - ret = hws_definer_conv_misc5(&cd, mt->match_param); - if (ret) - goto err_free_fc; - } - - /* Check there is no conflicted fields set together */ - ret = hws_definer_check_match_flags(&cd); - if (ret) - goto err_free_fc; - - /* Allocate fc array on mt */ - mt->fc = hws_definer_alloc_compressed_fc(fc); - if (!mt->fc) { - mlx5hws_err(ctx, - "Convert match params: failed to set field copy to match template\n"); - ret = -ENOMEM; - goto err_free_fc; - } - mt->fc_sz = hws_definer_get_fc_size(fc); - - /* Fill in headers layout */ - hws_definer_set_hl(hl, fc); - - kfree(fc); - return 0; - -err_free_fc: - kfree(fc); - return ret; -} - -struct mlx5hws_definer_fc * -mlx5hws_definer_conv_match_params_to_compressed_fc(struct mlx5hws_context *ctx, - u8 match_criteria_enable, - u32 *match_param, - int *fc_sz) -{ - struct mlx5hws_definer_fc *compressed_fc = NULL; - struct mlx5hws_definer_conv_data cd = {0}; - struct mlx5hws_definer_fc *fc; - int ret; - - fc = hws_definer_alloc_fc(ctx, MLX5HWS_DEFINER_FNAME_MAX); - if (!fc) - return NULL; - - cd.fc = fc; - cd.ctx = ctx; - - if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_OUTER) { - ret = hws_definer_conv_outer(&cd, match_param); - if (ret) - goto err_free_fc; - } - - if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_INNER) { - ret = hws_definer_conv_inner(&cd, match_param); - if (ret) - goto err_free_fc; - } - - if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC) { - ret = hws_definer_conv_misc(&cd, match_param); - if (ret) - goto err_free_fc; - } - - if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC2) { - ret = hws_definer_conv_misc2(&cd, match_param); - if (ret) - goto err_free_fc; - } - - if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC3) { - ret = hws_definer_conv_misc3(&cd, match_param); - if (ret) - goto err_free_fc; - } - - if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC4) { - ret = hws_definer_conv_misc4(&cd, match_param); - if (ret) - goto err_free_fc; - } - - if (match_criteria_enable & MLX5HWS_DEFINER_MATCH_CRITERIA_MISC5) { - ret = hws_definer_conv_misc5(&cd, match_param); - if (ret) - goto err_free_fc; - } - - /* Allocate fc array on mt */ - compressed_fc = hws_definer_alloc_compressed_fc(fc); - if (!compressed_fc) { - mlx5hws_err(ctx, - "Convert to compressed fc: failed to set field copy to match template\n"); - goto err_free_fc; - } - *fc_sz = hws_definer_get_fc_size(fc); - -err_free_fc: - kfree(fc); - return compressed_fc; -} - -static int -hws_definer_find_byte_in_tag(struct mlx5hws_definer *definer, - u32 hl_byte_off, - u32 *tag_byte_off) -{ - int i, dw_to_scan; - u8 byte_offset; - - /* Avoid accessing unused DW selectors */ - dw_to_scan = mlx5hws_definer_is_jumbo(definer) ? - DW_SELECTORS : DW_SELECTORS_MATCH; - - /* Add offset since each DW covers multiple BYTEs */ - byte_offset = hl_byte_off % DW_SIZE; - for (i = 0; i < dw_to_scan; i++) { - if (definer->dw_selector[i] == hl_byte_off / DW_SIZE) { - *tag_byte_off = byte_offset + DW_SIZE * (DW_SELECTORS - i - 1); - return 0; - } - } - - /* Add offset to skip DWs in definer */ - byte_offset = DW_SIZE * DW_SELECTORS; - /* Iterate in reverse since the code uses bytes from 7 -> 0 */ - for (i = BYTE_SELECTORS; i-- > 0 ;) { - if (definer->byte_selector[i] == hl_byte_off) { - *tag_byte_off = byte_offset + (BYTE_SELECTORS - i - 1); - return 0; - } - } - - return -EINVAL; -} - -static int -hws_definer_fc_bind(struct mlx5hws_definer *definer, - struct mlx5hws_definer_fc *fc, - u32 fc_sz) -{ - u32 tag_offset = 0; - int ret, byte_diff; - u32 i; - - for (i = 0; i < fc_sz; i++) { - /* Map header layout byte offset to byte offset in tag */ - ret = hws_definer_find_byte_in_tag(definer, fc->byte_off, &tag_offset); - if (ret) - return ret; - - /* Move setter based on the location in the definer */ - byte_diff = fc->byte_off % DW_SIZE - tag_offset % DW_SIZE; - fc->bit_off = fc->bit_off + byte_diff * BITS_IN_BYTE; - - /* Update offset in headers layout to offset in tag */ - fc->byte_off = tag_offset; - fc++; - } - - return 0; -} - -static bool -hws_definer_best_hl_fit_recu(struct mlx5hws_definer_sel_ctrl *ctrl, - u32 cur_dw, - u32 *data) -{ - u8 bytes_set; - int byte_idx; - bool ret; - int i; - - /* Reached end, nothing left to do */ - if (cur_dw == MLX5_ST_SZ_DW(definer_hl)) - return true; - - /* No data set, can skip to next DW */ - while (!*data) { - cur_dw++; - data++; - - /* Reached end, nothing left to do */ - if (cur_dw == MLX5_ST_SZ_DW(definer_hl)) - return true; - } - - /* Used all DW selectors and Byte selectors, no possible solution */ - if (ctrl->allowed_full_dw == ctrl->used_full_dw && - ctrl->allowed_lim_dw == ctrl->used_lim_dw && - ctrl->allowed_bytes == ctrl->used_bytes) - return false; - - /* Try to use limited DW selectors */ - if (ctrl->allowed_lim_dw > ctrl->used_lim_dw && cur_dw < 64) { - ctrl->lim_dw_selector[ctrl->used_lim_dw++] = cur_dw; - - ret = hws_definer_best_hl_fit_recu(ctrl, cur_dw + 1, data + 1); - if (ret) - return ret; - - ctrl->lim_dw_selector[--ctrl->used_lim_dw] = 0; - } - - /* Try to use DW selectors */ - if (ctrl->allowed_full_dw > ctrl->used_full_dw) { - ctrl->full_dw_selector[ctrl->used_full_dw++] = cur_dw; - - ret = hws_definer_best_hl_fit_recu(ctrl, cur_dw + 1, data + 1); - if (ret) - return ret; - - ctrl->full_dw_selector[--ctrl->used_full_dw] = 0; - } - - /* No byte selector for offset bigger than 255 */ - if (cur_dw * DW_SIZE > 255) - return false; - - bytes_set = !!(0x000000ff & *data) + - !!(0x0000ff00 & *data) + - !!(0x00ff0000 & *data) + - !!(0xff000000 & *data); - - /* Check if there are enough byte selectors left */ - if (bytes_set + ctrl->used_bytes > ctrl->allowed_bytes) - return false; - - /* Try to use Byte selectors */ - for (i = 0; i < DW_SIZE; i++) - if ((0xff000000 >> (i * BITS_IN_BYTE)) & be32_to_cpu((__force __be32)*data)) { - /* Use byte selectors high to low */ - byte_idx = ctrl->allowed_bytes - ctrl->used_bytes - 1; - ctrl->byte_selector[byte_idx] = cur_dw * DW_SIZE + i; - ctrl->used_bytes++; - } - - ret = hws_definer_best_hl_fit_recu(ctrl, cur_dw + 1, data + 1); - if (ret) - return ret; - - for (i = 0; i < DW_SIZE; i++) - if ((0xff << (i * BITS_IN_BYTE)) & be32_to_cpu((__force __be32)*data)) { - ctrl->used_bytes--; - byte_idx = ctrl->allowed_bytes - ctrl->used_bytes - 1; - ctrl->byte_selector[byte_idx] = 0; - } - - return false; -} - -static void -hws_definer_copy_sel_ctrl(struct mlx5hws_definer_sel_ctrl *ctrl, - struct mlx5hws_definer *definer) -{ - memcpy(definer->byte_selector, ctrl->byte_selector, ctrl->allowed_bytes); - memcpy(definer->dw_selector, ctrl->full_dw_selector, ctrl->allowed_full_dw); - memcpy(definer->dw_selector + ctrl->allowed_full_dw, - ctrl->lim_dw_selector, ctrl->allowed_lim_dw); -} - -static int -hws_definer_find_best_match_fit(struct mlx5hws_context *ctx, - struct mlx5hws_definer *definer, - u8 *hl) -{ - struct mlx5hws_definer_sel_ctrl ctrl = {0}; - bool found; - - /* Try to create a match definer */ - ctrl.allowed_full_dw = DW_SELECTORS_MATCH; - ctrl.allowed_lim_dw = 0; - ctrl.allowed_bytes = BYTE_SELECTORS; - - found = hws_definer_best_hl_fit_recu(&ctrl, 0, (u32 *)hl); - if (found) { - hws_definer_copy_sel_ctrl(&ctrl, definer); - definer->type = MLX5HWS_DEFINER_TYPE_MATCH; - return 0; - } - - /* Try to create a full/limited jumbo definer */ - ctrl.allowed_full_dw = ctx->caps->full_dw_jumbo_support ? DW_SELECTORS : - DW_SELECTORS_MATCH; - ctrl.allowed_lim_dw = ctx->caps->full_dw_jumbo_support ? 0 : - DW_SELECTORS_LIMITED; - ctrl.allowed_bytes = BYTE_SELECTORS; - - found = hws_definer_best_hl_fit_recu(&ctrl, 0, (u32 *)hl); - if (found) { - hws_definer_copy_sel_ctrl(&ctrl, definer); - definer->type = MLX5HWS_DEFINER_TYPE_JUMBO; - return 0; - } - - return -E2BIG; -} - -static void -hws_definer_create_tag_mask(u32 *match_param, - struct mlx5hws_definer_fc *fc, - u32 fc_sz, - u8 *tag) -{ - u32 i; - - for (i = 0; i < fc_sz; i++) { - if (fc->tag_mask_set) - fc->tag_mask_set(fc, match_param, tag); - else - fc->tag_set(fc, match_param, tag); - fc++; - } -} - -void mlx5hws_definer_create_tag(u32 *match_param, - struct mlx5hws_definer_fc *fc, - u32 fc_sz, - u8 *tag) -{ - u32 i; - - for (i = 0; i < fc_sz; i++) { - fc->tag_set(fc, match_param, tag); - fc++; - } -} - -int mlx5hws_definer_get_id(struct mlx5hws_definer *definer) -{ - return definer->obj_id; -} - -int mlx5hws_definer_compare(struct mlx5hws_definer *definer_a, - struct mlx5hws_definer *definer_b) -{ - int i; - - /* Future: Optimize by comparing selectors with valid mask only */ - for (i = 0; i < BYTE_SELECTORS; i++) - if (definer_a->byte_selector[i] != definer_b->byte_selector[i]) - return 1; - - for (i = 0; i < DW_SELECTORS; i++) - if (definer_a->dw_selector[i] != definer_b->dw_selector[i]) - return 1; - - for (i = 0; i < MLX5HWS_JUMBO_TAG_SZ; i++) - if (definer_a->mask.jumbo[i] != definer_b->mask.jumbo[i]) - return 1; - - return 0; -} - -int -mlx5hws_definer_calc_layout(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt, - struct mlx5hws_definer *match_definer) -{ - u8 *match_hl; - int ret; - - /* Union header-layout (hl) is used for creating a single definer - * field layout used with different bitmasks for hash and match. - */ - match_hl = kzalloc(MLX5_ST_SZ_BYTES(definer_hl), GFP_KERNEL); - if (!match_hl) - return -ENOMEM; - - /* Convert all mt items to header layout (hl) - * and allocate the match and range field copy array (fc & fcr). - */ - ret = hws_definer_conv_match_params_to_hl(ctx, mt, match_hl); - if (ret) { - mlx5hws_err(ctx, "Failed to convert items to header layout\n"); - goto free_match_hl; - } - - /* Find the match definer layout for header layout match union */ - ret = hws_definer_find_best_match_fit(ctx, match_definer, match_hl); - if (ret) { - if (ret == -E2BIG) - mlx5hws_dbg(ctx, - "Failed to create match definer from header layout - E2BIG\n"); - else - mlx5hws_err(ctx, - "Failed to create match definer from header layout (%d)\n", - ret); - goto free_fc; - } - - kfree(match_hl); - return 0; - -free_fc: - kfree(mt->fc); -free_match_hl: - kfree(match_hl); - return ret; -} - -int mlx5hws_definer_init_cache(struct mlx5hws_definer_cache **cache) -{ - struct mlx5hws_definer_cache *new_cache; - - new_cache = kzalloc(sizeof(*new_cache), GFP_KERNEL); - if (!new_cache) - return -ENOMEM; - - INIT_LIST_HEAD(&new_cache->list_head); - *cache = new_cache; - - return 0; -} - -void mlx5hws_definer_uninit_cache(struct mlx5hws_definer_cache *cache) -{ - kfree(cache); -} - -int mlx5hws_definer_get_obj(struct mlx5hws_context *ctx, - struct mlx5hws_definer *definer) -{ - struct mlx5hws_definer_cache *cache = ctx->definer_cache; - struct mlx5hws_cmd_definer_create_attr def_attr = {0}; - struct mlx5hws_definer_cache_item *cached_definer; - u32 obj_id; - int ret; - - /* Search definer cache for requested definer */ - list_for_each_entry(cached_definer, &cache->list_head, list_node) { - if (mlx5hws_definer_compare(&cached_definer->definer, definer)) - continue; - - /* Reuse definer and set LRU (move to be first in the list) */ - list_del_init(&cached_definer->list_node); - list_add(&cached_definer->list_node, &cache->list_head); - cached_definer->refcount++; - return cached_definer->definer.obj_id; - } - - /* Allocate and create definer based on the bitmask tag */ - def_attr.match_mask = definer->mask.jumbo; - def_attr.dw_selector = definer->dw_selector; - def_attr.byte_selector = definer->byte_selector; - - ret = mlx5hws_cmd_definer_create(ctx->mdev, &def_attr, &obj_id); - if (ret) - return -1; - - cached_definer = kzalloc(sizeof(*cached_definer), GFP_KERNEL); - if (!cached_definer) - goto free_definer_obj; - - memcpy(&cached_definer->definer, definer, sizeof(*definer)); - cached_definer->definer.obj_id = obj_id; - cached_definer->refcount = 1; - list_add(&cached_definer->list_node, &cache->list_head); - - return obj_id; - -free_definer_obj: - mlx5hws_cmd_definer_destroy(ctx->mdev, obj_id); - return -1; -} - -static void -hws_definer_put_obj(struct mlx5hws_context *ctx, u32 obj_id) -{ - struct mlx5hws_definer_cache_item *cached_definer; - - list_for_each_entry(cached_definer, &ctx->definer_cache->list_head, list_node) { - if (cached_definer->definer.obj_id != obj_id) - continue; - - /* Object found */ - if (--cached_definer->refcount) - return; - - list_del_init(&cached_definer->list_node); - mlx5hws_cmd_definer_destroy(ctx->mdev, cached_definer->definer.obj_id); - kfree(cached_definer); - return; - } - - /* Programming error, object must be part of cache */ - pr_warn("HWS: failed putting definer object\n"); -} - -static struct mlx5hws_definer * -hws_definer_alloc(struct mlx5hws_context *ctx, - struct mlx5hws_definer_fc *fc, - int fc_sz, - u32 *match_param, - struct mlx5hws_definer *layout, - bool bind_fc) -{ - struct mlx5hws_definer *definer; - int ret; - - definer = kmemdup(layout, sizeof(*definer), GFP_KERNEL); - if (!definer) - return NULL; - - /* Align field copy array based on given layout */ - if (bind_fc) { - ret = hws_definer_fc_bind(definer, fc, fc_sz); - if (ret) { - mlx5hws_err(ctx, "Failed to bind field copy to definer\n"); - goto free_definer; - } - } - - /* Create the tag mask used for definer creation */ - hws_definer_create_tag_mask(match_param, fc, fc_sz, definer->mask.jumbo); - - ret = mlx5hws_definer_get_obj(ctx, definer); - if (ret < 0) - goto free_definer; - - definer->obj_id = ret; - return definer; - -free_definer: - kfree(definer); - return NULL; -} - -void mlx5hws_definer_free(struct mlx5hws_context *ctx, - struct mlx5hws_definer *definer) -{ - hws_definer_put_obj(ctx, definer->obj_id); - kfree(definer); -} - -static int -hws_definer_mt_match_init(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt, - struct mlx5hws_definer *match_layout) -{ - /* Create mandatory match definer */ - mt->definer = hws_definer_alloc(ctx, - mt->fc, - mt->fc_sz, - mt->match_param, - match_layout, - true); - if (!mt->definer) { - mlx5hws_err(ctx, "Failed to create match definer\n"); - return -EINVAL; - } - - return 0; -} - -static void -hws_definer_mt_match_uninit(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt) -{ - mlx5hws_definer_free(ctx, mt->definer); -} - -int mlx5hws_definer_mt_init(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt) -{ - struct mlx5hws_definer match_layout = {0}; - int ret; - - ret = mlx5hws_definer_calc_layout(ctx, mt, &match_layout); - if (ret) { - mlx5hws_err(ctx, "Failed to calculate matcher definer layout\n"); - return ret; - } - - /* Calculate definers needed for exact match */ - ret = hws_definer_mt_match_init(ctx, mt, &match_layout); - if (ret) { - mlx5hws_err(ctx, "Failed to init match definers\n"); - goto free_fc; - } - - return 0; - -free_fc: - kfree(mt->fc); - return ret; -} - -void mlx5hws_definer_mt_uninit(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt) -{ - hws_definer_mt_match_uninit(ctx, mt); - kfree(mt->fc); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h deleted file mode 100644 index 2f6a7df4021c8d..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_definer.h +++ /dev/null @@ -1,834 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_DEFINER_H_ -#define MLX5HWS_DEFINER_H_ - -/* Max available selecotrs */ -#define DW_SELECTORS 9 -#define BYTE_SELECTORS 8 - -/* Selectors based on match TAG */ -#define DW_SELECTORS_MATCH 6 -#define DW_SELECTORS_LIMITED 3 - -/* Selectors based on range TAG */ -#define DW_SELECTORS_RANGE 2 -#define BYTE_SELECTORS_RANGE 8 - -#define HWS_NUM_OF_FLEX_PARSERS 8 - -enum mlx5hws_definer_fname { - MLX5HWS_DEFINER_FNAME_ETH_SMAC_47_16_O, - MLX5HWS_DEFINER_FNAME_ETH_SMAC_47_16_I, - MLX5HWS_DEFINER_FNAME_ETH_SMAC_15_0_O, - MLX5HWS_DEFINER_FNAME_ETH_SMAC_15_0_I, - MLX5HWS_DEFINER_FNAME_ETH_DMAC_47_16_O, - MLX5HWS_DEFINER_FNAME_ETH_DMAC_47_16_I, - MLX5HWS_DEFINER_FNAME_ETH_DMAC_15_0_O, - MLX5HWS_DEFINER_FNAME_ETH_DMAC_15_0_I, - MLX5HWS_DEFINER_FNAME_ETH_TYPE_O, - MLX5HWS_DEFINER_FNAME_ETH_TYPE_I, - MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_O, - MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_I, - MLX5HWS_DEFINER_FNAME_VLAN_TYPE_O, - MLX5HWS_DEFINER_FNAME_VLAN_TYPE_I, - MLX5HWS_DEFINER_FNAME_VLAN_FIRST_PRIO_O, - MLX5HWS_DEFINER_FNAME_VLAN_FIRST_PRIO_I, - MLX5HWS_DEFINER_FNAME_VLAN_CFI_O, - MLX5HWS_DEFINER_FNAME_VLAN_CFI_I, - MLX5HWS_DEFINER_FNAME_VLAN_ID_O, - MLX5HWS_DEFINER_FNAME_VLAN_ID_I, - MLX5HWS_DEFINER_FNAME_VLAN_SECOND_TYPE_O, - MLX5HWS_DEFINER_FNAME_VLAN_SECOND_TYPE_I, - MLX5HWS_DEFINER_FNAME_VLAN_SECOND_PRIO_O, - MLX5HWS_DEFINER_FNAME_VLAN_SECOND_PRIO_I, - MLX5HWS_DEFINER_FNAME_VLAN_SECOND_CFI_O, - MLX5HWS_DEFINER_FNAME_VLAN_SECOND_CFI_I, - MLX5HWS_DEFINER_FNAME_VLAN_SECOND_ID_O, - MLX5HWS_DEFINER_FNAME_VLAN_SECOND_ID_I, - MLX5HWS_DEFINER_FNAME_IPV4_IHL_O, - MLX5HWS_DEFINER_FNAME_IPV4_IHL_I, - MLX5HWS_DEFINER_FNAME_IP_DSCP_O, - MLX5HWS_DEFINER_FNAME_IP_DSCP_I, - MLX5HWS_DEFINER_FNAME_IP_ECN_O, - MLX5HWS_DEFINER_FNAME_IP_ECN_I, - MLX5HWS_DEFINER_FNAME_IP_TTL_O, - MLX5HWS_DEFINER_FNAME_IP_TTL_I, - MLX5HWS_DEFINER_FNAME_IPV4_DST_O, - MLX5HWS_DEFINER_FNAME_IPV4_DST_I, - MLX5HWS_DEFINER_FNAME_IPV4_SRC_O, - MLX5HWS_DEFINER_FNAME_IPV4_SRC_I, - MLX5HWS_DEFINER_FNAME_IP_VERSION_O, - MLX5HWS_DEFINER_FNAME_IP_VERSION_I, - MLX5HWS_DEFINER_FNAME_IP_FRAG_O, - MLX5HWS_DEFINER_FNAME_IP_FRAG_I, - MLX5HWS_DEFINER_FNAME_IP_LEN_O, - MLX5HWS_DEFINER_FNAME_IP_LEN_I, - MLX5HWS_DEFINER_FNAME_IP_TOS_O, - MLX5HWS_DEFINER_FNAME_IP_TOS_I, - MLX5HWS_DEFINER_FNAME_IPV6_FLOW_LABEL_O, - MLX5HWS_DEFINER_FNAME_IPV6_FLOW_LABEL_I, - MLX5HWS_DEFINER_FNAME_IPV6_DST_127_96_O, - MLX5HWS_DEFINER_FNAME_IPV6_DST_95_64_O, - MLX5HWS_DEFINER_FNAME_IPV6_DST_63_32_O, - MLX5HWS_DEFINER_FNAME_IPV6_DST_31_0_O, - MLX5HWS_DEFINER_FNAME_IPV6_DST_127_96_I, - MLX5HWS_DEFINER_FNAME_IPV6_DST_95_64_I, - MLX5HWS_DEFINER_FNAME_IPV6_DST_63_32_I, - MLX5HWS_DEFINER_FNAME_IPV6_DST_31_0_I, - MLX5HWS_DEFINER_FNAME_IPV6_SRC_127_96_O, - MLX5HWS_DEFINER_FNAME_IPV6_SRC_95_64_O, - MLX5HWS_DEFINER_FNAME_IPV6_SRC_63_32_O, - MLX5HWS_DEFINER_FNAME_IPV6_SRC_31_0_O, - MLX5HWS_DEFINER_FNAME_IPV6_SRC_127_96_I, - MLX5HWS_DEFINER_FNAME_IPV6_SRC_95_64_I, - MLX5HWS_DEFINER_FNAME_IPV6_SRC_63_32_I, - MLX5HWS_DEFINER_FNAME_IPV6_SRC_31_0_I, - MLX5HWS_DEFINER_FNAME_IP_PROTOCOL_O, - MLX5HWS_DEFINER_FNAME_IP_PROTOCOL_I, - MLX5HWS_DEFINER_FNAME_L4_SPORT_O, - MLX5HWS_DEFINER_FNAME_L4_SPORT_I, - MLX5HWS_DEFINER_FNAME_L4_DPORT_O, - MLX5HWS_DEFINER_FNAME_L4_DPORT_I, - MLX5HWS_DEFINER_FNAME_TCP_FLAGS_I, - MLX5HWS_DEFINER_FNAME_TCP_FLAGS_O, - MLX5HWS_DEFINER_FNAME_TCP_SEQ_NUM, - MLX5HWS_DEFINER_FNAME_TCP_ACK_NUM, - MLX5HWS_DEFINER_FNAME_GTP_TEID, - MLX5HWS_DEFINER_FNAME_GTP_MSG_TYPE, - MLX5HWS_DEFINER_FNAME_GTP_EXT_FLAG, - MLX5HWS_DEFINER_FNAME_GTP_NEXT_EXT_HDR, - MLX5HWS_DEFINER_FNAME_GTP_EXT_HDR_PDU, - MLX5HWS_DEFINER_FNAME_GTP_EXT_HDR_QFI, - MLX5HWS_DEFINER_FNAME_GTPU_DW0, - MLX5HWS_DEFINER_FNAME_GTPU_FIRST_EXT_DW0, - MLX5HWS_DEFINER_FNAME_GTPU_DW2, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER_0, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER_1, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER_2, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER_3, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER_4, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER_5, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER_6, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER_7, - MLX5HWS_DEFINER_FNAME_VPORT_REG_C_0, - MLX5HWS_DEFINER_FNAME_VXLAN_FLAGS, - MLX5HWS_DEFINER_FNAME_VXLAN_VNI, - MLX5HWS_DEFINER_FNAME_VXLAN_GPE_FLAGS, - MLX5HWS_DEFINER_FNAME_VXLAN_GPE_RSVD0, - MLX5HWS_DEFINER_FNAME_VXLAN_GPE_PROTO, - MLX5HWS_DEFINER_FNAME_VXLAN_GPE_VNI, - MLX5HWS_DEFINER_FNAME_VXLAN_GPE_RSVD1, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_LEN, - MLX5HWS_DEFINER_FNAME_GENEVE_OAM, - MLX5HWS_DEFINER_FNAME_GENEVE_PROTO, - MLX5HWS_DEFINER_FNAME_GENEVE_VNI, - MLX5HWS_DEFINER_FNAME_SOURCE_QP, - MLX5HWS_DEFINER_FNAME_SOURCE_GVMI, - MLX5HWS_DEFINER_FNAME_REG_0, - MLX5HWS_DEFINER_FNAME_REG_1, - MLX5HWS_DEFINER_FNAME_REG_2, - MLX5HWS_DEFINER_FNAME_REG_3, - MLX5HWS_DEFINER_FNAME_REG_4, - MLX5HWS_DEFINER_FNAME_REG_5, - MLX5HWS_DEFINER_FNAME_REG_6, - MLX5HWS_DEFINER_FNAME_REG_7, - MLX5HWS_DEFINER_FNAME_REG_8, - MLX5HWS_DEFINER_FNAME_REG_9, - MLX5HWS_DEFINER_FNAME_REG_10, - MLX5HWS_DEFINER_FNAME_REG_11, - MLX5HWS_DEFINER_FNAME_REG_A, - MLX5HWS_DEFINER_FNAME_REG_B, - MLX5HWS_DEFINER_FNAME_GRE_KEY_PRESENT, - MLX5HWS_DEFINER_FNAME_GRE_C, - MLX5HWS_DEFINER_FNAME_GRE_K, - MLX5HWS_DEFINER_FNAME_GRE_S, - MLX5HWS_DEFINER_FNAME_GRE_PROTOCOL, - MLX5HWS_DEFINER_FNAME_GRE_OPT_KEY, - MLX5HWS_DEFINER_FNAME_GRE_OPT_SEQ, - MLX5HWS_DEFINER_FNAME_GRE_OPT_CHECKSUM, - MLX5HWS_DEFINER_FNAME_INTEGRITY_O, - MLX5HWS_DEFINER_FNAME_INTEGRITY_I, - MLX5HWS_DEFINER_FNAME_ICMP_DW1, - MLX5HWS_DEFINER_FNAME_ICMP_DW2, - MLX5HWS_DEFINER_FNAME_ICMP_DW3, - MLX5HWS_DEFINER_FNAME_IPSEC_SPI, - MLX5HWS_DEFINER_FNAME_IPSEC_SEQUENCE_NUMBER, - MLX5HWS_DEFINER_FNAME_IPSEC_SYNDROME, - MLX5HWS_DEFINER_FNAME_MPLS0_O, - MLX5HWS_DEFINER_FNAME_MPLS1_O, - MLX5HWS_DEFINER_FNAME_MPLS2_O, - MLX5HWS_DEFINER_FNAME_MPLS3_O, - MLX5HWS_DEFINER_FNAME_MPLS4_O, - MLX5HWS_DEFINER_FNAME_MPLS0_I, - MLX5HWS_DEFINER_FNAME_MPLS1_I, - MLX5HWS_DEFINER_FNAME_MPLS2_I, - MLX5HWS_DEFINER_FNAME_MPLS3_I, - MLX5HWS_DEFINER_FNAME_MPLS4_I, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER0_OK, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER1_OK, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER2_OK, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER3_OK, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER4_OK, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER5_OK, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER6_OK, - MLX5HWS_DEFINER_FNAME_FLEX_PARSER7_OK, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS0_O, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS1_O, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS2_O, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS3_O, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS4_O, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS0_I, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS1_I, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS2_I, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS3_I, - MLX5HWS_DEFINER_FNAME_OKS2_MPLS4_I, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_0, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_1, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_2, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_3, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_4, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_5, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_6, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_OK_7, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_0, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_1, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_2, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_3, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_4, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_5, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_6, - MLX5HWS_DEFINER_FNAME_GENEVE_OPT_DW_7, - MLX5HWS_DEFINER_FNAME_IB_L4_OPCODE, - MLX5HWS_DEFINER_FNAME_IB_L4_QPN, - MLX5HWS_DEFINER_FNAME_IB_L4_A, - MLX5HWS_DEFINER_FNAME_RANDOM_NUM, - MLX5HWS_DEFINER_FNAME_PTYPE_L2_O, - MLX5HWS_DEFINER_FNAME_PTYPE_L2_I, - MLX5HWS_DEFINER_FNAME_PTYPE_L3_O, - MLX5HWS_DEFINER_FNAME_PTYPE_L3_I, - MLX5HWS_DEFINER_FNAME_PTYPE_L4_O, - MLX5HWS_DEFINER_FNAME_PTYPE_L4_I, - MLX5HWS_DEFINER_FNAME_PTYPE_L4_EXT_O, - MLX5HWS_DEFINER_FNAME_PTYPE_L4_EXT_I, - MLX5HWS_DEFINER_FNAME_PTYPE_FRAG_O, - MLX5HWS_DEFINER_FNAME_PTYPE_FRAG_I, - MLX5HWS_DEFINER_FNAME_TNL_HDR_0, - MLX5HWS_DEFINER_FNAME_TNL_HDR_1, - MLX5HWS_DEFINER_FNAME_TNL_HDR_2, - MLX5HWS_DEFINER_FNAME_TNL_HDR_3, - MLX5HWS_DEFINER_FNAME_MAX, -}; - -enum mlx5hws_definer_match_criteria { - MLX5HWS_DEFINER_MATCH_CRITERIA_EMPTY = 0, - MLX5HWS_DEFINER_MATCH_CRITERIA_OUTER = 1 << 0, - MLX5HWS_DEFINER_MATCH_CRITERIA_MISC = 1 << 1, - MLX5HWS_DEFINER_MATCH_CRITERIA_INNER = 1 << 2, - MLX5HWS_DEFINER_MATCH_CRITERIA_MISC2 = 1 << 3, - MLX5HWS_DEFINER_MATCH_CRITERIA_MISC3 = 1 << 4, - MLX5HWS_DEFINER_MATCH_CRITERIA_MISC4 = 1 << 5, - MLX5HWS_DEFINER_MATCH_CRITERIA_MISC5 = 1 << 6, - MLX5HWS_DEFINER_MATCH_CRITERIA_MISC6 = 1 << 7, -}; - -enum mlx5hws_definer_type { - MLX5HWS_DEFINER_TYPE_MATCH, - MLX5HWS_DEFINER_TYPE_JUMBO, -}; - -enum mlx5hws_definer_match_flag { - MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN_GPE = 1 << 0, - MLX5HWS_DEFINER_MATCH_FLAG_TNL_GENEVE = 1 << 1, - MLX5HWS_DEFINER_MATCH_FLAG_TNL_GTPU = 1 << 2, - MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE = 1 << 3, - MLX5HWS_DEFINER_MATCH_FLAG_TNL_VXLAN = 1 << 4, - MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_0_1 = 1 << 5, - - MLX5HWS_DEFINER_MATCH_FLAG_TNL_GRE_OPT_KEY = 1 << 6, - MLX5HWS_DEFINER_MATCH_FLAG_TNL_HEADER_2 = 1 << 7, - - MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_GRE = 1 << 8, - MLX5HWS_DEFINER_MATCH_FLAG_TNL_MPLS_OVER_UDP = 1 << 9, - - MLX5HWS_DEFINER_MATCH_FLAG_ICMPV4 = 1 << 10, - MLX5HWS_DEFINER_MATCH_FLAG_ICMPV6 = 1 << 11, - MLX5HWS_DEFINER_MATCH_FLAG_TCP_O = 1 << 12, - MLX5HWS_DEFINER_MATCH_FLAG_TCP_I = 1 << 13, -}; - -struct mlx5hws_definer_fc { - struct mlx5hws_context *ctx; - /* Source */ - u32 s_byte_off; - int s_bit_off; - u32 s_bit_mask; - /* Destination */ - u32 byte_off; - int bit_off; - u32 bit_mask; - enum mlx5hws_definer_fname fname; - void (*tag_set)(struct mlx5hws_definer_fc *fc, - void *mach_param, - u8 *tag); - void (*tag_mask_set)(struct mlx5hws_definer_fc *fc, - void *mach_param, - u8 *tag); -}; - -struct mlx5_ifc_definer_hl_eth_l2_bits { - u8 dmac_47_16[0x20]; - u8 dmac_15_0[0x10]; - u8 l3_ethertype[0x10]; - u8 reserved_at_40[0x1]; - u8 sx_sniffer[0x1]; - u8 functional_lb[0x1]; - u8 ip_fragmented[0x1]; - u8 qp_type[0x2]; - u8 encap_type[0x2]; - u8 port_number[0x2]; - u8 l3_type[0x2]; - u8 l4_type_bwc[0x2]; - u8 first_vlan_qualifier[0x2]; - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 first_vlan_id[0xc]; - u8 l4_type[0x4]; - u8 reserved_at_64[0x2]; - u8 ipsec_layer[0x2]; - u8 l2_type[0x2]; - u8 force_lb[0x1]; - u8 l2_ok[0x1]; - u8 l3_ok[0x1]; - u8 l4_ok[0x1]; - u8 second_vlan_qualifier[0x2]; - u8 second_priority[0x3]; - u8 second_cfi[0x1]; - u8 second_vlan_id[0xc]; -}; - -struct mlx5_ifc_definer_hl_eth_l2_src_bits { - u8 smac_47_16[0x20]; - u8 smac_15_0[0x10]; - u8 loopback_syndrome[0x8]; - u8 l3_type[0x2]; - u8 l4_type_bwc[0x2]; - u8 first_vlan_qualifier[0x2]; - u8 ip_fragmented[0x1]; - u8 functional_lb[0x1]; -}; - -struct mlx5_ifc_definer_hl_ib_l2_bits { - u8 sx_sniffer[0x1]; - u8 force_lb[0x1]; - u8 functional_lb[0x1]; - u8 reserved_at_3[0x3]; - u8 port_number[0x2]; - u8 sl[0x4]; - u8 qp_type[0x2]; - u8 lnh[0x2]; - u8 dlid[0x10]; - u8 vl[0x4]; - u8 lrh_packet_length[0xc]; - u8 slid[0x10]; -}; - -struct mlx5_ifc_definer_hl_eth_l3_bits { - u8 ip_version[0x4]; - u8 ihl[0x4]; - union { - u8 tos[0x8]; - struct { - u8 dscp[0x6]; - u8 ecn[0x2]; - }; - }; - u8 time_to_live_hop_limit[0x8]; - u8 protocol_next_header[0x8]; - u8 identification[0x10]; - union { - u8 ipv4_frag[0x10]; - struct { - u8 flags[0x3]; - u8 fragment_offset[0xd]; - }; - }; - u8 ipv4_total_length[0x10]; - u8 checksum[0x10]; - u8 reserved_at_60[0xc]; - u8 flow_label[0x14]; - u8 packet_length[0x10]; - u8 ipv6_payload_length[0x10]; -}; - -struct mlx5_ifc_definer_hl_eth_l4_bits { - u8 source_port[0x10]; - u8 destination_port[0x10]; - u8 data_offset[0x4]; - u8 l4_ok[0x1]; - u8 l3_ok[0x1]; - u8 ip_fragmented[0x1]; - u8 tcp_ns[0x1]; - union { - u8 tcp_flags[0x8]; - struct { - u8 tcp_cwr[0x1]; - u8 tcp_ece[0x1]; - u8 tcp_urg[0x1]; - u8 tcp_ack[0x1]; - u8 tcp_psh[0x1]; - u8 tcp_rst[0x1]; - u8 tcp_syn[0x1]; - u8 tcp_fin[0x1]; - }; - }; - u8 first_fragment[0x1]; - u8 reserved_at_31[0xf]; -}; - -struct mlx5_ifc_definer_hl_src_qp_gvmi_bits { - u8 loopback_syndrome[0x8]; - u8 l3_type[0x2]; - u8 l4_type_bwc[0x2]; - u8 first_vlan_qualifier[0x2]; - u8 reserved_at_e[0x1]; - u8 functional_lb[0x1]; - u8 source_gvmi[0x10]; - u8 force_lb[0x1]; - u8 ip_fragmented[0x1]; - u8 source_is_requestor[0x1]; - u8 reserved_at_23[0x5]; - u8 source_qp[0x18]; -}; - -struct mlx5_ifc_definer_hl_ib_l4_bits { - u8 opcode[0x8]; - u8 qp[0x18]; - u8 se[0x1]; - u8 migreq[0x1]; - u8 ackreq[0x1]; - u8 fecn[0x1]; - u8 becn[0x1]; - u8 bth[0x1]; - u8 deth[0x1]; - u8 dcceth[0x1]; - u8 reserved_at_28[0x2]; - u8 pad_count[0x2]; - u8 tver[0x4]; - u8 p_key[0x10]; - u8 reserved_at_40[0x8]; - u8 deth_source_qp[0x18]; -}; - -enum mlx5hws_integrity_ok1_bits { - MLX5HWS_DEFINER_OKS1_FIRST_L4_OK = 24, - MLX5HWS_DEFINER_OKS1_FIRST_L3_OK = 25, - MLX5HWS_DEFINER_OKS1_SECOND_L4_OK = 26, - MLX5HWS_DEFINER_OKS1_SECOND_L3_OK = 27, - MLX5HWS_DEFINER_OKS1_FIRST_L4_CSUM_OK = 28, - MLX5HWS_DEFINER_OKS1_FIRST_IPV4_CSUM_OK = 29, - MLX5HWS_DEFINER_OKS1_SECOND_L4_CSUM_OK = 30, - MLX5HWS_DEFINER_OKS1_SECOND_IPV4_CSUM_OK = 31, -}; - -struct mlx5_ifc_definer_hl_oks1_bits { - union { - u8 oks1_bits[0x20]; - struct { - u8 second_ipv4_checksum_ok[0x1]; - u8 second_l4_checksum_ok[0x1]; - u8 first_ipv4_checksum_ok[0x1]; - u8 first_l4_checksum_ok[0x1]; - u8 second_l3_ok[0x1]; - u8 second_l4_ok[0x1]; - u8 first_l3_ok[0x1]; - u8 first_l4_ok[0x1]; - u8 flex_parser7_steering_ok[0x1]; - u8 flex_parser6_steering_ok[0x1]; - u8 flex_parser5_steering_ok[0x1]; - u8 flex_parser4_steering_ok[0x1]; - u8 flex_parser3_steering_ok[0x1]; - u8 flex_parser2_steering_ok[0x1]; - u8 flex_parser1_steering_ok[0x1]; - u8 flex_parser0_steering_ok[0x1]; - u8 second_ipv6_extension_header_vld[0x1]; - u8 first_ipv6_extension_header_vld[0x1]; - u8 l3_tunneling_ok[0x1]; - u8 l2_tunneling_ok[0x1]; - u8 second_tcp_ok[0x1]; - u8 second_udp_ok[0x1]; - u8 second_ipv4_ok[0x1]; - u8 second_ipv6_ok[0x1]; - u8 second_l2_ok[0x1]; - u8 vxlan_ok[0x1]; - u8 gre_ok[0x1]; - u8 first_tcp_ok[0x1]; - u8 first_udp_ok[0x1]; - u8 first_ipv4_ok[0x1]; - u8 first_ipv6_ok[0x1]; - u8 first_l2_ok[0x1]; - }; - }; -}; - -struct mlx5_ifc_definer_hl_oks2_bits { - u8 reserved_at_0[0xa]; - u8 second_mpls_ok[0x1]; - u8 second_mpls4_s_bit[0x1]; - u8 second_mpls4_qualifier[0x1]; - u8 second_mpls3_s_bit[0x1]; - u8 second_mpls3_qualifier[0x1]; - u8 second_mpls2_s_bit[0x1]; - u8 second_mpls2_qualifier[0x1]; - u8 second_mpls1_s_bit[0x1]; - u8 second_mpls1_qualifier[0x1]; - u8 second_mpls0_s_bit[0x1]; - u8 second_mpls0_qualifier[0x1]; - u8 first_mpls_ok[0x1]; - u8 first_mpls4_s_bit[0x1]; - u8 first_mpls4_qualifier[0x1]; - u8 first_mpls3_s_bit[0x1]; - u8 first_mpls3_qualifier[0x1]; - u8 first_mpls2_s_bit[0x1]; - u8 first_mpls2_qualifier[0x1]; - u8 first_mpls1_s_bit[0x1]; - u8 first_mpls1_qualifier[0x1]; - u8 first_mpls0_s_bit[0x1]; - u8 first_mpls0_qualifier[0x1]; -}; - -struct mlx5_ifc_definer_hl_voq_bits { - u8 reserved_at_0[0x18]; - u8 ecn_ok[0x1]; - u8 congestion[0x1]; - u8 profile[0x2]; - u8 internal_prio[0x4]; -}; - -struct mlx5_ifc_definer_hl_ipv4_src_dst_bits { - u8 source_address[0x20]; - u8 destination_address[0x20]; -}; - -struct mlx5_ifc_definer_hl_random_number_bits { - u8 random_number[0x10]; - u8 reserved[0x10]; -}; - -struct mlx5_ifc_definer_hl_ipv6_addr_bits { - u8 ipv6_address_127_96[0x20]; - u8 ipv6_address_95_64[0x20]; - u8 ipv6_address_63_32[0x20]; - u8 ipv6_address_31_0[0x20]; -}; - -struct mlx5_ifc_definer_tcp_icmp_header_bits { - union { - struct { - u8 icmp_dw1[0x20]; - u8 icmp_dw2[0x20]; - u8 icmp_dw3[0x20]; - }; - struct { - u8 tcp_seq[0x20]; - u8 tcp_ack[0x20]; - u8 tcp_win_urg[0x20]; - }; - }; -}; - -struct mlx5_ifc_definer_hl_tunnel_header_bits { - u8 tunnel_header_0[0x20]; - u8 tunnel_header_1[0x20]; - u8 tunnel_header_2[0x20]; - u8 tunnel_header_3[0x20]; -}; - -struct mlx5_ifc_definer_hl_ipsec_bits { - u8 spi[0x20]; - u8 sequence_number[0x20]; - u8 reserved[0x10]; - u8 ipsec_syndrome[0x8]; - u8 next_header[0x8]; -}; - -struct mlx5_ifc_definer_hl_metadata_bits { - u8 metadata_to_cqe[0x20]; - u8 general_purpose[0x20]; - u8 acomulated_hash[0x20]; -}; - -struct mlx5_ifc_definer_hl_flex_parser_bits { - u8 flex_parser_7[0x20]; - u8 flex_parser_6[0x20]; - u8 flex_parser_5[0x20]; - u8 flex_parser_4[0x20]; - u8 flex_parser_3[0x20]; - u8 flex_parser_2[0x20]; - u8 flex_parser_1[0x20]; - u8 flex_parser_0[0x20]; -}; - -struct mlx5_ifc_definer_hl_registers_bits { - u8 register_c_10[0x20]; - u8 register_c_11[0x20]; - u8 register_c_8[0x20]; - u8 register_c_9[0x20]; - u8 register_c_6[0x20]; - u8 register_c_7[0x20]; - u8 register_c_4[0x20]; - u8 register_c_5[0x20]; - u8 register_c_2[0x20]; - u8 register_c_3[0x20]; - u8 register_c_0[0x20]; - u8 register_c_1[0x20]; -}; - -struct mlx5_ifc_definer_hl_mpls_bits { - u8 mpls0_label[0x20]; - u8 mpls1_label[0x20]; - u8 mpls2_label[0x20]; - u8 mpls3_label[0x20]; - u8 mpls4_label[0x20]; -}; - -struct mlx5_ifc_definer_hl_bits { - struct mlx5_ifc_definer_hl_eth_l2_bits eth_l2_outer; - struct mlx5_ifc_definer_hl_eth_l2_bits eth_l2_inner; - struct mlx5_ifc_definer_hl_eth_l2_src_bits eth_l2_src_outer; - struct mlx5_ifc_definer_hl_eth_l2_src_bits eth_l2_src_inner; - struct mlx5_ifc_definer_hl_ib_l2_bits ib_l2; - struct mlx5_ifc_definer_hl_eth_l3_bits eth_l3_outer; - struct mlx5_ifc_definer_hl_eth_l3_bits eth_l3_inner; - struct mlx5_ifc_definer_hl_eth_l4_bits eth_l4_outer; - struct mlx5_ifc_definer_hl_eth_l4_bits eth_l4_inner; - struct mlx5_ifc_definer_hl_src_qp_gvmi_bits source_qp_gvmi; - struct mlx5_ifc_definer_hl_ib_l4_bits ib_l4; - struct mlx5_ifc_definer_hl_oks1_bits oks1; - struct mlx5_ifc_definer_hl_oks2_bits oks2; - struct mlx5_ifc_definer_hl_voq_bits voq; - u8 reserved_at_480[0x380]; - struct mlx5_ifc_definer_hl_ipv4_src_dst_bits ipv4_src_dest_outer; - struct mlx5_ifc_definer_hl_ipv4_src_dst_bits ipv4_src_dest_inner; - struct mlx5_ifc_definer_hl_ipv6_addr_bits ipv6_dst_outer; - struct mlx5_ifc_definer_hl_ipv6_addr_bits ipv6_dst_inner; - struct mlx5_ifc_definer_hl_ipv6_addr_bits ipv6_src_outer; - struct mlx5_ifc_definer_hl_ipv6_addr_bits ipv6_src_inner; - u8 unsupported_dest_ib_l3[0x80]; - u8 unsupported_source_ib_l3[0x80]; - u8 unsupported_udp_misc_outer[0x20]; - u8 unsupported_udp_misc_inner[0x20]; - struct mlx5_ifc_definer_tcp_icmp_header_bits tcp_icmp; - struct mlx5_ifc_definer_hl_tunnel_header_bits tunnel_header; - struct mlx5_ifc_definer_hl_mpls_bits mpls_outer; - struct mlx5_ifc_definer_hl_mpls_bits mpls_inner; - u8 unsupported_config_headers_outer[0x80]; - u8 unsupported_config_headers_inner[0x80]; - struct mlx5_ifc_definer_hl_random_number_bits random_number; - struct mlx5_ifc_definer_hl_ipsec_bits ipsec; - struct mlx5_ifc_definer_hl_metadata_bits metadata; - u8 unsupported_utc_timestamp[0x40]; - u8 unsupported_free_running_timestamp[0x40]; - struct mlx5_ifc_definer_hl_flex_parser_bits flex_parser; - struct mlx5_ifc_definer_hl_registers_bits registers; - /* Reserved in case header layout on future HW */ - u8 unsupported_reserved[0xd40]; -}; - -enum mlx5hws_definer_gtp { - MLX5HWS_DEFINER_GTP_EXT_HDR_BIT = 0x04, -}; - -struct mlx5_ifc_header_gtp_bits { - u8 version[0x3]; - u8 proto_type[0x1]; - u8 reserved1[0x1]; - union { - u8 msg_flags[0x3]; - struct { - u8 ext_hdr_flag[0x1]; - u8 seq_num_flag[0x1]; - u8 pdu_flag[0x1]; - }; - }; - u8 msg_type[0x8]; - u8 msg_len[0x8]; - u8 teid[0x20]; -}; - -struct mlx5_ifc_header_opt_gtp_bits { - u8 seq_num[0x10]; - u8 pdu_num[0x8]; - u8 next_ext_hdr_type[0x8]; -}; - -struct mlx5_ifc_header_gtp_psc_bits { - u8 len[0x8]; - u8 pdu_type[0x4]; - u8 flags[0x4]; - u8 qfi[0x8]; - u8 reserved2[0x8]; -}; - -struct mlx5_ifc_header_ipv6_vtc_bits { - u8 version[0x4]; - union { - u8 tos[0x8]; - struct { - u8 dscp[0x6]; - u8 ecn[0x2]; - }; - }; - u8 flow_label[0x14]; -}; - -struct mlx5_ifc_header_ipv6_routing_ext_bits { - u8 next_hdr[0x8]; - u8 hdr_len[0x8]; - u8 type[0x8]; - u8 segments_left[0x8]; - union { - u8 flags[0x20]; - struct { - u8 last_entry[0x8]; - u8 flag[0x8]; - u8 tag[0x10]; - }; - }; -}; - -struct mlx5_ifc_header_vxlan_bits { - u8 flags[0x8]; - u8 reserved1[0x18]; - u8 vni[0x18]; - u8 reserved2[0x8]; -}; - -struct mlx5_ifc_header_vxlan_gpe_bits { - u8 flags[0x8]; - u8 rsvd0[0x10]; - u8 protocol[0x8]; - u8 vni[0x18]; - u8 rsvd1[0x8]; -}; - -struct mlx5_ifc_header_gre_bits { - union { - u8 c_rsvd0_ver[0x10]; - struct { - u8 gre_c_present[0x1]; - u8 reserved_at_1[0x1]; - u8 gre_k_present[0x1]; - u8 gre_s_present[0x1]; - u8 reserved_at_4[0x9]; - u8 version[0x3]; - }; - }; - u8 gre_protocol[0x10]; - u8 checksum[0x10]; - u8 reserved_at_30[0x10]; -}; - -struct mlx5_ifc_header_geneve_bits { - union { - u8 ver_opt_len_o_c_rsvd[0x10]; - struct { - u8 version[0x2]; - u8 opt_len[0x6]; - u8 o_flag[0x1]; - u8 c_flag[0x1]; - u8 reserved_at_a[0x6]; - }; - }; - u8 protocol_type[0x10]; - u8 vni[0x18]; - u8 reserved_at_38[0x8]; -}; - -struct mlx5_ifc_header_geneve_opt_bits { - u8 class[0x10]; - u8 type[0x8]; - u8 reserved[0x3]; - u8 len[0x5]; -}; - -struct mlx5_ifc_header_icmp_bits { - union { - u8 icmp_dw1[0x20]; - struct { - u8 type[0x8]; - u8 code[0x8]; - u8 cksum[0x10]; - }; - }; - union { - u8 icmp_dw2[0x20]; - struct { - u8 ident[0x10]; - u8 seq_nb[0x10]; - }; - }; -}; - -struct mlx5hws_definer { - enum mlx5hws_definer_type type; - u8 dw_selector[DW_SELECTORS]; - u8 byte_selector[BYTE_SELECTORS]; - struct mlx5hws_rule_match_tag mask; - u32 obj_id; -}; - -struct mlx5hws_definer_cache { - struct list_head list_head; -}; - -struct mlx5hws_definer_cache_item { - struct mlx5hws_definer definer; - u32 refcount; - struct list_head list_node; -}; - -static inline bool -mlx5hws_definer_is_jumbo(struct mlx5hws_definer *definer) -{ - return (definer->type == MLX5HWS_DEFINER_TYPE_JUMBO); -} - -void mlx5hws_definer_create_tag(u32 *match_param, - struct mlx5hws_definer_fc *fc, - u32 fc_sz, - u8 *tag); - -int mlx5hws_definer_get_id(struct mlx5hws_definer *definer); - -int mlx5hws_definer_mt_init(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt); - -void mlx5hws_definer_mt_uninit(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt); - -int mlx5hws_definer_init_cache(struct mlx5hws_definer_cache **cache); - -void mlx5hws_definer_uninit_cache(struct mlx5hws_definer_cache *cache); - -int mlx5hws_definer_compare(struct mlx5hws_definer *definer_a, - struct mlx5hws_definer *definer_b); - -int mlx5hws_definer_get_obj(struct mlx5hws_context *ctx, - struct mlx5hws_definer *definer); - -void mlx5hws_definer_free(struct mlx5hws_context *ctx, - struct mlx5hws_definer *definer); - -int mlx5hws_definer_calc_layout(struct mlx5hws_context *ctx, - struct mlx5hws_match_template *mt, - struct mlx5hws_definer *match_definer); - -struct mlx5hws_definer_fc * -mlx5hws_definer_conv_match_params_to_compressed_fc(struct mlx5hws_context *ctx, - u8 match_criteria_enable, - u32 *match_param, - int *fc_sz); - -#endif /* MLX5HWS_DEFINER_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h deleted file mode 100644 index 5643be1cd5bf39..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_internal.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_INTERNAL_H_ -#define MLX5HWS_INTERNAL_H_ - -#include -#include -#include "fs_core.h" -#include "wq.h" -#include "lib/mlx5.h" - -#include "mlx5hws_prm.h" -#include "mlx5hws.h" -#include "mlx5hws_pool.h" -#include "mlx5hws_vport.h" -#include "mlx5hws_context.h" -#include "mlx5hws_table.h" -#include "mlx5hws_send.h" -#include "mlx5hws_rule.h" -#include "mlx5hws_cmd.h" -#include "mlx5hws_action.h" -#include "mlx5hws_definer.h" -#include "mlx5hws_matcher.h" -#include "mlx5hws_debug.h" -#include "mlx5hws_pat_arg.h" -#include "mlx5hws_bwc.h" -#include "mlx5hws_bwc_complex.h" - -#define W_SIZE 2 -#define DW_SIZE 4 -#define BITS_IN_BYTE 8 -#define BITS_IN_DW (BITS_IN_BYTE * DW_SIZE) - -#define IS_BIT_SET(_value, _bit) ((_value) & (1ULL << (_bit))) - -#define mlx5hws_err(ctx, arg...) mlx5_core_err((ctx)->mdev, ##arg) -#define mlx5hws_info(ctx, arg...) mlx5_core_info((ctx)->mdev, ##arg) -#define mlx5hws_dbg(ctx, arg...) mlx5_core_dbg((ctx)->mdev, ##arg) - -#define MLX5HWS_TABLE_TYPE_BASE 2 -#define MLX5HWS_ACTION_STE_IDX_ANY 0 - -static inline bool is_mem_zero(const u8 *mem, size_t size) -{ - if (unlikely(!size)) { - pr_warn("HWS: invalid buffer of size 0 in %s\n", __func__); - return true; - } - - return (*mem == 0) && memcmp(mem, mem + 1, size - 1) == 0; -} - -static inline unsigned long align(unsigned long val, unsigned long align) -{ - return (val + align - 1) & ~(align - 1); -} - -#endif /* MLX5HWS_INTERNAL_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c deleted file mode 100644 index 61a1155d4b4fdb..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.c +++ /dev/null @@ -1,1216 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -enum mlx5hws_matcher_rtc_type { - HWS_MATCHER_RTC_TYPE_MATCH, - HWS_MATCHER_RTC_TYPE_STE_ARRAY, - HWS_MATCHER_RTC_TYPE_MAX, -}; - -static const char * const mlx5hws_matcher_rtc_type_str[] = { - [HWS_MATCHER_RTC_TYPE_MATCH] = "MATCH", - [HWS_MATCHER_RTC_TYPE_STE_ARRAY] = "STE_ARRAY", - [HWS_MATCHER_RTC_TYPE_MAX] = "UNKNOWN", -}; - -static const char *hws_matcher_rtc_type_to_str(enum mlx5hws_matcher_rtc_type rtc_type) -{ - if (rtc_type > HWS_MATCHER_RTC_TYPE_MAX) - rtc_type = HWS_MATCHER_RTC_TYPE_MAX; - return mlx5hws_matcher_rtc_type_str[rtc_type]; -} - -static bool hws_matcher_requires_col_tbl(u8 log_num_of_rules) -{ - /* Collision table concatenation is done only for large rule tables */ - return log_num_of_rules > MLX5HWS_MATCHER_ASSURED_RULES_TH; -} - -static u8 hws_matcher_rules_to_tbl_depth(u8 log_num_of_rules) -{ - if (hws_matcher_requires_col_tbl(log_num_of_rules)) - return MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH; - - /* For small rule tables we use a single deep table to assure insertion */ - return min(log_num_of_rules, MLX5HWS_MATCHER_ASSURED_COL_TBL_DEPTH); -} - -static void hws_matcher_destroy_end_ft(struct mlx5hws_matcher *matcher) -{ - mlx5hws_table_destroy_default_ft(matcher->tbl, matcher->end_ft_id); -} - -static int hws_matcher_create_end_ft(struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_table *tbl = matcher->tbl; - int ret; - - ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, tbl, &matcher->end_ft_id); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed to create matcher end flow table\n"); - return ret; - } - return 0; -} - -static int hws_matcher_connect(struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_table *tbl = matcher->tbl; - struct mlx5hws_context *ctx = tbl->ctx; - struct mlx5hws_matcher *prev = NULL; - struct mlx5hws_matcher *next = NULL; - struct mlx5hws_matcher *tmp_matcher; - int ret; - - /* Find location in matcher list */ - if (list_empty(&tbl->matchers_list)) { - list_add(&matcher->list_node, &tbl->matchers_list); - goto connect; - } - - list_for_each_entry(tmp_matcher, &tbl->matchers_list, list_node) { - if (tmp_matcher->attr.priority > matcher->attr.priority) { - next = tmp_matcher; - break; - } - prev = tmp_matcher; - } - - if (next) - /* insert before next */ - list_add_tail(&matcher->list_node, &next->list_node); - else - /* insert after prev */ - list_add(&matcher->list_node, &prev->list_node); - -connect: - if (next) { - /* Connect to next RTC */ - ret = mlx5hws_table_ft_set_next_rtc(ctx, - matcher->end_ft_id, - tbl->fw_ft_type, - next->match_ste.rtc_0_id, - next->match_ste.rtc_1_id); - if (ret) { - mlx5hws_err(ctx, "Failed to connect new matcher to next RTC\n"); - goto remove_from_list; - } - } else { - /* Connect last matcher to next miss_tbl if exists */ - ret = mlx5hws_table_connect_to_miss_table(tbl, tbl->default_miss.miss_tbl); - if (ret) { - mlx5hws_err(ctx, "Failed connect new matcher to miss_tbl\n"); - goto remove_from_list; - } - } - - /* Connect to previous FT */ - ret = mlx5hws_table_ft_set_next_rtc(ctx, - prev ? prev->end_ft_id : tbl->ft_id, - tbl->fw_ft_type, - matcher->match_ste.rtc_0_id, - matcher->match_ste.rtc_1_id); - if (ret) { - mlx5hws_err(ctx, "Failed to connect new matcher to previous FT\n"); - goto remove_from_list; - } - - /* Reset prev matcher FT default miss (drop refcount) */ - ret = mlx5hws_table_ft_set_default_next_ft(tbl, prev ? prev->end_ft_id : tbl->ft_id); - if (ret) { - mlx5hws_err(ctx, "Failed to reset matcher ft default miss\n"); - goto remove_from_list; - } - - if (!prev) { - /* Update tables missing to current matcher in the table */ - ret = mlx5hws_table_update_connected_miss_tables(tbl); - if (ret) { - mlx5hws_err(ctx, "Fatal error, failed to update connected miss table\n"); - goto remove_from_list; - } - } - - return 0; - -remove_from_list: - list_del_init(&matcher->list_node); - return ret; -} - -static int hws_matcher_disconnect(struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_matcher *next = NULL, *prev = NULL; - struct mlx5hws_table *tbl = matcher->tbl; - u32 prev_ft_id = tbl->ft_id; - int ret; - - if (!list_is_first(&matcher->list_node, &tbl->matchers_list)) { - prev = list_prev_entry(matcher, list_node); - prev_ft_id = prev->end_ft_id; - } - - if (!list_is_last(&matcher->list_node, &tbl->matchers_list)) - next = list_next_entry(matcher, list_node); - - list_del_init(&matcher->list_node); - - if (next) { - /* Connect previous end FT to next RTC */ - ret = mlx5hws_table_ft_set_next_rtc(tbl->ctx, - prev_ft_id, - tbl->fw_ft_type, - next->match_ste.rtc_0_id, - next->match_ste.rtc_1_id); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed to disconnect matcher\n"); - goto matcher_reconnect; - } - } else { - ret = mlx5hws_table_connect_to_miss_table(tbl, tbl->default_miss.miss_tbl); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed to disconnect last matcher\n"); - goto matcher_reconnect; - } - } - - /* Removing first matcher, update connected miss tables if exists */ - if (prev_ft_id == tbl->ft_id) { - ret = mlx5hws_table_update_connected_miss_tables(tbl); - if (ret) { - mlx5hws_err(tbl->ctx, "Fatal error, failed to update connected miss table\n"); - goto matcher_reconnect; - } - } - - ret = mlx5hws_table_ft_set_default_next_ft(tbl, prev_ft_id); - if (ret) { - mlx5hws_err(tbl->ctx, "Fatal error, failed to restore matcher ft default miss\n"); - goto matcher_reconnect; - } - - return 0; - -matcher_reconnect: - if (list_empty(&tbl->matchers_list) || !prev) - list_add(&matcher->list_node, &tbl->matchers_list); - else - /* insert after prev matcher */ - list_add(&matcher->list_node, &prev->list_node); - - return ret; -} - -static void hws_matcher_set_rtc_attr_sz(struct mlx5hws_matcher *matcher, - struct mlx5hws_cmd_rtc_create_attr *rtc_attr, - enum mlx5hws_matcher_rtc_type rtc_type, - bool is_mirror) -{ - struct mlx5hws_pool_chunk *ste = &matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].ste; - enum mlx5hws_matcher_flow_src flow_src = matcher->attr.optimize_flow_src; - bool is_match_rtc = rtc_type == HWS_MATCHER_RTC_TYPE_MATCH; - - if ((flow_src == MLX5HWS_MATCHER_FLOW_SRC_VPORT && !is_mirror) || - (flow_src == MLX5HWS_MATCHER_FLOW_SRC_WIRE && is_mirror)) { - /* Optimize FDB RTC */ - rtc_attr->log_size = 0; - rtc_attr->log_depth = 0; - } else { - /* Keep original values */ - rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order; - rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0; - } -} - -static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher, - enum mlx5hws_matcher_rtc_type rtc_type, - u8 action_ste_selector) -{ - struct mlx5hws_matcher_attr *attr = &matcher->attr; - struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0}; - struct mlx5hws_match_template *mt = matcher->mt; - struct mlx5hws_context *ctx = matcher->tbl->ctx; - struct mlx5hws_action_default_stc *default_stc; - struct mlx5hws_matcher_action_ste *action_ste; - struct mlx5hws_table *tbl = matcher->tbl; - struct mlx5hws_pool *ste_pool, *stc_pool; - struct mlx5hws_pool_chunk *ste; - u32 *rtc_0_id, *rtc_1_id; - u32 obj_id; - int ret; - - switch (rtc_type) { - case HWS_MATCHER_RTC_TYPE_MATCH: - rtc_0_id = &matcher->match_ste.rtc_0_id; - rtc_1_id = &matcher->match_ste.rtc_1_id; - ste_pool = matcher->match_ste.pool; - ste = &matcher->match_ste.ste; - ste->order = attr->table.sz_col_log + attr->table.sz_row_log; - - rtc_attr.log_size = attr->table.sz_row_log; - rtc_attr.log_depth = attr->table.sz_col_log; - rtc_attr.is_frst_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); - rtc_attr.is_scnd_range = 0; - rtc_attr.miss_ft_id = matcher->end_ft_id; - - if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_HASH) { - /* The usual Hash Table */ - rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; - - /* The first mt is used since all share the same definer */ - rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer); - } else if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) { - rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; - rtc_attr.num_hash_definer = 1; - - if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) { - /* Hash Split Table */ - rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH; - rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer); - } else if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_LINEAR) { - /* Linear Lookup Table */ - rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR; - rtc_attr.match_definer_0 = ctx->caps->linear_match_definer; - } - } - - /* Match pool requires implicit allocation */ - ret = mlx5hws_pool_chunk_alloc(ste_pool, ste); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate STE for %s RTC", - hws_matcher_rtc_type_to_str(rtc_type)); - return ret; - } - break; - - case HWS_MATCHER_RTC_TYPE_STE_ARRAY: - action_ste = &matcher->action_ste[action_ste_selector]; - - rtc_0_id = &action_ste->rtc_0_id; - rtc_1_id = &action_ste->rtc_1_id; - ste_pool = action_ste->pool; - ste = &action_ste->ste; - ste->order = ilog2(roundup_pow_of_two(action_ste->max_stes)) + - attr->table.sz_row_log; - rtc_attr.log_size = ste->order; - rtc_attr.log_depth = 0; - rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; - /* The action STEs use the default always hit definer */ - rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; - rtc_attr.is_frst_jumbo = false; - rtc_attr.miss_ft_id = 0; - break; - - default: - mlx5hws_err(ctx, "HWS Invalid RTC type\n"); - return -EINVAL; - } - - obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); - - rtc_attr.pd = ctx->pd_num; - rtc_attr.ste_base = obj_id; - rtc_attr.ste_offset = ste->offset; - rtc_attr.reparse_mode = mlx5hws_context_get_reparse_mode(ctx); - rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, false); - hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, false); - - /* STC is a single resource (obj_id), use any STC for the ID */ - stc_pool = ctx->stc_pool[tbl->type]; - default_stc = ctx->common_res[tbl->type].default_stc; - obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit); - rtc_attr.stc_base = obj_id; - - ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id); - if (ret) { - mlx5hws_err(ctx, "Failed to create matcher RTC of type %s", - hws_matcher_rtc_type_to_str(rtc_type)); - goto free_ste; - } - - if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) { - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); - rtc_attr.ste_base = obj_id; - rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, true); - - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit); - rtc_attr.stc_base = obj_id; - hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, true); - - ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_1_id); - if (ret) { - mlx5hws_err(ctx, "Failed to create peer matcher RTC of type %s", - hws_matcher_rtc_type_to_str(rtc_type)); - goto destroy_rtc_0; - } - } - - return 0; - -destroy_rtc_0: - mlx5hws_cmd_rtc_destroy(ctx->mdev, *rtc_0_id); -free_ste: - if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH) - mlx5hws_pool_chunk_free(ste_pool, ste); - return ret; -} - -static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher, - enum mlx5hws_matcher_rtc_type rtc_type, - u8 action_ste_selector) -{ - struct mlx5hws_matcher_action_ste *action_ste; - struct mlx5hws_table *tbl = matcher->tbl; - struct mlx5hws_pool_chunk *ste; - struct mlx5hws_pool *ste_pool; - u32 rtc_0_id, rtc_1_id; - - switch (rtc_type) { - case HWS_MATCHER_RTC_TYPE_MATCH: - rtc_0_id = matcher->match_ste.rtc_0_id; - rtc_1_id = matcher->match_ste.rtc_1_id; - ste_pool = matcher->match_ste.pool; - ste = &matcher->match_ste.ste; - break; - case HWS_MATCHER_RTC_TYPE_STE_ARRAY: - action_ste = &matcher->action_ste[action_ste_selector]; - rtc_0_id = action_ste->rtc_0_id; - rtc_1_id = action_ste->rtc_1_id; - ste_pool = action_ste->pool; - ste = &action_ste->ste; - break; - default: - return; - } - - if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_1_id); - - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_0_id); - if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH) - mlx5hws_pool_chunk_free(ste_pool, ste); -} - -static int -hws_matcher_check_attr_sz(struct mlx5hws_cmd_query_caps *caps, - struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_matcher_attr *attr = &matcher->attr; - - if (attr->table.sz_col_log > caps->rtc_log_depth_max) { - mlx5hws_err(matcher->tbl->ctx, "Matcher depth exceeds limit %d\n", - caps->rtc_log_depth_max); - return -EOPNOTSUPP; - } - - if (attr->table.sz_col_log + attr->table.sz_row_log > caps->ste_alloc_log_max) { - mlx5hws_err(matcher->tbl->ctx, "Total matcher size exceeds limit %d\n", - caps->ste_alloc_log_max); - return -EOPNOTSUPP; - } - - if (attr->table.sz_col_log + attr->table.sz_row_log < caps->ste_alloc_log_gran) { - mlx5hws_err(matcher->tbl->ctx, "Total matcher size below limit %d\n", - caps->ste_alloc_log_gran); - return -EOPNOTSUPP; - } - - return 0; -} - -static void hws_matcher_set_pool_attr(struct mlx5hws_pool_attr *attr, - struct mlx5hws_matcher *matcher) -{ - switch (matcher->attr.optimize_flow_src) { - case MLX5HWS_MATCHER_FLOW_SRC_VPORT: - attr->opt_type = MLX5HWS_POOL_OPTIMIZE_ORIG; - break; - case MLX5HWS_MATCHER_FLOW_SRC_WIRE: - attr->opt_type = MLX5HWS_POOL_OPTIMIZE_MIRROR; - break; - default: - break; - } -} - -static int hws_matcher_check_and_process_at(struct mlx5hws_matcher *matcher, - struct mlx5hws_action_template *at) -{ - struct mlx5hws_context *ctx = matcher->tbl->ctx; - bool valid; - int ret; - - valid = mlx5hws_action_check_combo(ctx, at->action_type_arr, matcher->tbl->type); - if (!valid) { - mlx5hws_err(ctx, "Invalid combination in action template\n"); - return -EINVAL; - } - - /* Process action template to setters */ - ret = mlx5hws_action_template_process(at); - if (ret) { - mlx5hws_err(ctx, "Failed to process action template\n"); - return ret; - } - - return 0; -} - -static int hws_matcher_resize_init(struct mlx5hws_matcher *src_matcher) -{ - struct mlx5hws_matcher_resize_data *resize_data; - - resize_data = kzalloc(sizeof(*resize_data), GFP_KERNEL); - if (!resize_data) - return -ENOMEM; - - resize_data->max_stes = src_matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes; - - resize_data->action_ste[0].stc = src_matcher->action_ste[0].stc; - resize_data->action_ste[0].rtc_0_id = src_matcher->action_ste[0].rtc_0_id; - resize_data->action_ste[0].rtc_1_id = src_matcher->action_ste[0].rtc_1_id; - resize_data->action_ste[0].pool = src_matcher->action_ste[0].max_stes ? - src_matcher->action_ste[0].pool : - NULL; - resize_data->action_ste[1].stc = src_matcher->action_ste[1].stc; - resize_data->action_ste[1].rtc_0_id = src_matcher->action_ste[1].rtc_0_id; - resize_data->action_ste[1].rtc_1_id = src_matcher->action_ste[1].rtc_1_id; - resize_data->action_ste[1].pool = src_matcher->action_ste[1].max_stes ? - src_matcher->action_ste[1].pool : - NULL; - - /* Place the new resized matcher on the dst matcher's list */ - list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data); - - /* Move all the previous resized matchers to the dst matcher's list */ - while (!list_empty(&src_matcher->resize_data)) { - resize_data = list_first_entry(&src_matcher->resize_data, - struct mlx5hws_matcher_resize_data, - list_node); - list_del_init(&resize_data->list_node); - list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data); - } - - return 0; -} - -static void hws_matcher_resize_uninit(struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_matcher_resize_data *resize_data; - - if (!mlx5hws_matcher_is_resizable(matcher)) - return; - - while (!list_empty(&matcher->resize_data)) { - resize_data = list_first_entry(&matcher->resize_data, - struct mlx5hws_matcher_resize_data, - list_node); - list_del_init(&resize_data->list_node); - - if (resize_data->max_stes) { - mlx5hws_action_free_single_stc(matcher->tbl->ctx, - matcher->tbl->type, - &resize_data->action_ste[1].stc); - mlx5hws_action_free_single_stc(matcher->tbl->ctx, - matcher->tbl->type, - &resize_data->action_ste[0].stc); - - if (matcher->tbl->type == MLX5HWS_TABLE_TYPE_FDB) { - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, - resize_data->action_ste[1].rtc_1_id); - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, - resize_data->action_ste[0].rtc_1_id); - } - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, - resize_data->action_ste[1].rtc_0_id); - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, - resize_data->action_ste[0].rtc_0_id); - if (resize_data->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].pool) { - mlx5hws_pool_destroy(resize_data->action_ste[1].pool); - mlx5hws_pool_destroy(resize_data->action_ste[0].pool); - } - } - - kfree(resize_data); - } -} - -static int -hws_matcher_bind_at_idx(struct mlx5hws_matcher *matcher, u8 action_ste_selector) -{ - struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; - struct mlx5hws_matcher_action_ste *action_ste; - struct mlx5hws_table *tbl = matcher->tbl; - struct mlx5hws_pool_attr pool_attr = {0}; - struct mlx5hws_context *ctx = tbl->ctx; - int ret; - - action_ste = &matcher->action_ste[action_ste_selector]; - - /* Allocate action STE mempool */ - pool_attr.table_type = tbl->type; - pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; - pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL; - pool_attr.alloc_log_sz = ilog2(roundup_pow_of_two(action_ste->max_stes)) + - matcher->attr.table.sz_row_log; - hws_matcher_set_pool_attr(&pool_attr, matcher); - action_ste->pool = mlx5hws_pool_create(ctx, &pool_attr); - if (!action_ste->pool) { - mlx5hws_err(ctx, "Failed to create action ste pool\n"); - return -EINVAL; - } - - /* Allocate action RTC */ - ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector); - if (ret) { - mlx5hws_err(ctx, "Failed to create action RTC\n"); - goto free_ste_pool; - } - - /* Allocate STC for jumps to STE */ - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; - stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; - stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; - stc_attr.ste_table.ste = action_ste->ste; - stc_attr.ste_table.ste_pool = action_ste->pool; - stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; - - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl->type, - &action_ste->stc); - if (ret) { - mlx5hws_err(ctx, "Failed to create action jump to table STC\n"); - goto free_rtc; - } - - return 0; - -free_rtc: - hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector); -free_ste_pool: - mlx5hws_pool_destroy(action_ste->pool); - return ret; -} - -static void hws_matcher_unbind_at_idx(struct mlx5hws_matcher *matcher, u8 action_ste_selector) -{ - struct mlx5hws_matcher_action_ste *action_ste; - struct mlx5hws_table *tbl = matcher->tbl; - - action_ste = &matcher->action_ste[action_ste_selector]; - - if (!action_ste->max_stes || - matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION || - mlx5hws_matcher_is_in_resize(matcher)) - return; - - mlx5hws_action_free_single_stc(tbl->ctx, tbl->type, &action_ste->stc); - hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY, action_ste_selector); - mlx5hws_pool_destroy(action_ste->pool); -} - -static int hws_matcher_bind_at(struct mlx5hws_matcher *matcher) -{ - bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt); - struct mlx5hws_table *tbl = matcher->tbl; - struct mlx5hws_context *ctx = tbl->ctx; - u32 required_stes; - u8 max_stes = 0; - int i, ret; - - if (matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION) - return 0; - - for (i = 0; i < matcher->num_of_at; i++) { - struct mlx5hws_action_template *at = &matcher->at[i]; - - ret = hws_matcher_check_and_process_at(matcher, at); - if (ret) { - mlx5hws_err(ctx, "Invalid at %d", i); - return ret; - } - - required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); - max_stes = max(max_stes, required_stes); - - /* Future: Optimize reparse */ - } - - /* There are no additional STEs required for matcher */ - if (!max_stes) - return 0; - - matcher->action_ste[0].max_stes = max_stes; - matcher->action_ste[1].max_stes = max_stes; - - ret = hws_matcher_bind_at_idx(matcher, 0); - if (ret) - return ret; - - ret = hws_matcher_bind_at_idx(matcher, 1); - if (ret) - goto free_at_0; - - return 0; - -free_at_0: - hws_matcher_unbind_at_idx(matcher, 0); - return ret; -} - -static void hws_matcher_unbind_at(struct mlx5hws_matcher *matcher) -{ - hws_matcher_unbind_at_idx(matcher, 1); - hws_matcher_unbind_at_idx(matcher, 0); -} - -static int hws_matcher_bind_mt(struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_context *ctx = matcher->tbl->ctx; - struct mlx5hws_pool_attr pool_attr = {0}; - int ret; - - /* Calculate match, range and hash definers */ - if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)) { - ret = mlx5hws_definer_mt_init(ctx, matcher->mt); - if (ret) { - if (ret == -E2BIG) - mlx5hws_err(ctx, "Failed to set matcher templates with match definers\n"); - return ret; - } - } - - /* Create an STE pool per matcher*/ - pool_attr.table_type = matcher->tbl->type; - pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; - pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL; - pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log + - matcher->attr.table.sz_row_log; - hws_matcher_set_pool_attr(&pool_attr, matcher); - - matcher->match_ste.pool = mlx5hws_pool_create(ctx, &pool_attr); - if (!matcher->match_ste.pool) { - mlx5hws_err(ctx, "Failed to allocate matcher STE pool\n"); - ret = -EOPNOTSUPP; - goto uninit_match_definer; - } - - return 0; - -uninit_match_definer: - if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)) - mlx5hws_definer_mt_uninit(ctx, matcher->mt); - return ret; -} - -static void hws_matcher_unbind_mt(struct mlx5hws_matcher *matcher) -{ - mlx5hws_pool_destroy(matcher->match_ste.pool); - if (!(matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION)) - mlx5hws_definer_mt_uninit(matcher->tbl->ctx, matcher->mt); -} - -static int -hws_matcher_validate_insert_mode(struct mlx5hws_cmd_query_caps *caps, - struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_matcher_attr *attr = &matcher->attr; - struct mlx5hws_context *ctx = matcher->tbl->ctx; - - switch (attr->insert_mode) { - case MLX5HWS_MATCHER_INSERT_BY_HASH: - if (matcher->attr.distribute_mode != MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) { - mlx5hws_err(ctx, "Invalid matcher distribute mode\n"); - return -EOPNOTSUPP; - } - break; - - case MLX5HWS_MATCHER_INSERT_BY_INDEX: - if (attr->table.sz_col_log) { - mlx5hws_err(ctx, "Matcher with INSERT_BY_INDEX supports only Nx1 table size\n"); - return -EOPNOTSUPP; - } - - if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) { - /* Hash Split Table */ - if (!caps->rtc_hash_split_table) { - mlx5hws_err(ctx, "FW doesn't support insert by index and hash distribute\n"); - return -EOPNOTSUPP; - } - } else if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_LINEAR) { - /* Linear Lookup Table */ - if (!caps->rtc_linear_lookup_table || - !IS_BIT_SET(caps->access_index_mode, - MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR)) { - mlx5hws_err(ctx, "FW doesn't support insert by index and linear distribute\n"); - return -EOPNOTSUPP; - } - - if (attr->table.sz_row_log > MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX) { - mlx5hws_err(ctx, "Matcher with linear distribute: rows exceed limit %d", - MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX); - return -EOPNOTSUPP; - } - } else { - mlx5hws_err(ctx, "Matcher has unsupported distribute mode\n"); - return -EOPNOTSUPP; - } - break; - - default: - mlx5hws_err(ctx, "Matcher has unsupported insert mode\n"); - return -EOPNOTSUPP; - } - - return 0; -} - -static int -hws_matcher_process_attr(struct mlx5hws_cmd_query_caps *caps, - struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_matcher_attr *attr = &matcher->attr; - - if (hws_matcher_validate_insert_mode(caps, matcher)) - return -EOPNOTSUPP; - - if (matcher->tbl->type != MLX5HWS_TABLE_TYPE_FDB && attr->optimize_flow_src) { - mlx5hws_err(matcher->tbl->ctx, "NIC domain doesn't support flow_src\n"); - return -EOPNOTSUPP; - } - - /* Convert number of rules to the required depth */ - if (attr->mode == MLX5HWS_MATCHER_RESOURCE_MODE_RULE && - attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_HASH) - attr->table.sz_col_log = hws_matcher_rules_to_tbl_depth(attr->rule.num_log); - - matcher->flags |= attr->resizable ? MLX5HWS_MATCHER_FLAGS_RESIZABLE : 0; - - return hws_matcher_check_attr_sz(caps, matcher); -} - -static int hws_matcher_create_and_connect(struct mlx5hws_matcher *matcher) -{ - int ret; - - /* Select and create the definers for current matcher */ - ret = hws_matcher_bind_mt(matcher); - if (ret) - return ret; - - /* Calculate and verify action combination */ - ret = hws_matcher_bind_at(matcher); - if (ret) - goto unbind_mt; - - /* Create matcher end flow table anchor */ - ret = hws_matcher_create_end_ft(matcher); - if (ret) - goto unbind_at; - - /* Allocate the RTC for the new matcher */ - ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0); - if (ret) - goto destroy_end_ft; - - /* Connect the matcher to the matcher list */ - ret = hws_matcher_connect(matcher); - if (ret) - goto destroy_rtc; - - return 0; - -destroy_rtc: - hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0); -destroy_end_ft: - hws_matcher_destroy_end_ft(matcher); -unbind_at: - hws_matcher_unbind_at(matcher); -unbind_mt: - hws_matcher_unbind_mt(matcher); - return ret; -} - -static void hws_matcher_destroy_and_disconnect(struct mlx5hws_matcher *matcher) -{ - hws_matcher_resize_uninit(matcher); - hws_matcher_disconnect(matcher); - hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH, 0); - hws_matcher_destroy_end_ft(matcher); - hws_matcher_unbind_at(matcher); - hws_matcher_unbind_mt(matcher); -} - -static int -hws_matcher_create_col_matcher(struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_context *ctx = matcher->tbl->ctx; - struct mlx5hws_matcher *col_matcher; - int ret; - - if (matcher->attr.mode != MLX5HWS_MATCHER_RESOURCE_MODE_RULE || - matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) - return 0; - - if (!hws_matcher_requires_col_tbl(matcher->attr.rule.num_log)) - return 0; - - col_matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); - if (!col_matcher) - return -ENOMEM; - - INIT_LIST_HEAD(&col_matcher->resize_data); - - col_matcher->tbl = matcher->tbl; - col_matcher->mt = matcher->mt; - col_matcher->at = matcher->at; - col_matcher->num_of_at = matcher->num_of_at; - col_matcher->num_of_mt = matcher->num_of_mt; - col_matcher->attr.priority = matcher->attr.priority; - col_matcher->flags = matcher->flags; - col_matcher->flags |= MLX5HWS_MATCHER_FLAGS_COLLISION; - col_matcher->attr.mode = MLX5HWS_MATCHER_RESOURCE_MODE_HTABLE; - col_matcher->attr.optimize_flow_src = matcher->attr.optimize_flow_src; - col_matcher->attr.table.sz_row_log = matcher->attr.rule.num_log; - col_matcher->attr.table.sz_col_log = MLX5HWS_MATCHER_ASSURED_COL_TBL_DEPTH; - if (col_matcher->attr.table.sz_row_log > MLX5HWS_MATCHER_ASSURED_ROW_RATIO) - col_matcher->attr.table.sz_row_log -= MLX5HWS_MATCHER_ASSURED_ROW_RATIO; - - col_matcher->attr.max_num_of_at_attach = matcher->attr.max_num_of_at_attach; - - ret = hws_matcher_process_attr(ctx->caps, col_matcher); - if (ret) - goto free_col_matcher; - - ret = hws_matcher_create_and_connect(col_matcher); - if (ret) - goto free_col_matcher; - - matcher->col_matcher = col_matcher; - - return 0; - -free_col_matcher: - kfree(col_matcher); - mlx5hws_err(ctx, "Failed to create assured collision matcher\n"); - return ret; -} - -static void -hws_matcher_destroy_col_matcher(struct mlx5hws_matcher *matcher) -{ - if (matcher->attr.mode != MLX5HWS_MATCHER_RESOURCE_MODE_RULE || - matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) - return; - - if (matcher->col_matcher) { - hws_matcher_destroy_and_disconnect(matcher->col_matcher); - kfree(matcher->col_matcher); - } -} - -static int hws_matcher_init(struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_context *ctx = matcher->tbl->ctx; - int ret; - - INIT_LIST_HEAD(&matcher->resize_data); - - mutex_lock(&ctx->ctrl_lock); - - /* Allocate matcher resource and connect to the packet pipe */ - ret = hws_matcher_create_and_connect(matcher); - if (ret) - goto unlock_err; - - /* Create additional matcher for collision handling */ - ret = hws_matcher_create_col_matcher(matcher); - if (ret) - goto destory_and_disconnect; - mutex_unlock(&ctx->ctrl_lock); - - return 0; - -destory_and_disconnect: - hws_matcher_destroy_and_disconnect(matcher); -unlock_err: - mutex_unlock(&ctx->ctrl_lock); - return ret; -} - -static int hws_matcher_uninit(struct mlx5hws_matcher *matcher) -{ - struct mlx5hws_context *ctx = matcher->tbl->ctx; - - mutex_lock(&ctx->ctrl_lock); - hws_matcher_destroy_col_matcher(matcher); - hws_matcher_destroy_and_disconnect(matcher); - mutex_unlock(&ctx->ctrl_lock); - - return 0; -} - -int mlx5hws_matcher_attach_at(struct mlx5hws_matcher *matcher, - struct mlx5hws_action_template *at) -{ - bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt); - struct mlx5hws_context *ctx = matcher->tbl->ctx; - u32 required_stes; - int ret; - - if (!matcher->attr.max_num_of_at_attach) { - mlx5hws_dbg(ctx, "Num of current at (%d) exceed allowed value\n", - matcher->num_of_at); - return -EOPNOTSUPP; - } - - ret = hws_matcher_check_and_process_at(matcher, at); - if (ret) - return ret; - - required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); - if (matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes < required_stes) { - mlx5hws_dbg(ctx, "Required STEs [%d] exceeds initial action template STE [%d]\n", - required_stes, - matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes); - return -ENOMEM; - } - - matcher->at[matcher->num_of_at] = *at; - matcher->num_of_at += 1; - matcher->attr.max_num_of_at_attach -= 1; - - if (matcher->col_matcher) - matcher->col_matcher->num_of_at = matcher->num_of_at; - - return 0; -} - -static int -hws_matcher_set_templates(struct mlx5hws_matcher *matcher, - struct mlx5hws_match_template *mt[], - u8 num_of_mt, - struct mlx5hws_action_template *at[], - u8 num_of_at) -{ - struct mlx5hws_context *ctx = matcher->tbl->ctx; - int ret = 0; - int i; - - if (!num_of_mt || !num_of_at) { - mlx5hws_err(ctx, "Number of action/match template cannot be zero\n"); - return -EOPNOTSUPP; - } - - matcher->mt = kcalloc(num_of_mt, sizeof(*matcher->mt), GFP_KERNEL); - if (!matcher->mt) - return -ENOMEM; - - matcher->at = kcalloc(num_of_at + matcher->attr.max_num_of_at_attach, - sizeof(*matcher->at), - GFP_KERNEL); - if (!matcher->at) { - mlx5hws_err(ctx, "Failed to allocate action template array\n"); - ret = -ENOMEM; - goto free_mt; - } - - for (i = 0; i < num_of_mt; i++) - matcher->mt[i] = *mt[i]; - - for (i = 0; i < num_of_at; i++) - matcher->at[i] = *at[i]; - - matcher->num_of_mt = num_of_mt; - matcher->num_of_at = num_of_at; - - return 0; - -free_mt: - kfree(matcher->mt); - return ret; -} - -static void -hws_matcher_unset_templates(struct mlx5hws_matcher *matcher) -{ - kfree(matcher->at); - kfree(matcher->mt); -} - -struct mlx5hws_matcher * -mlx5hws_matcher_create(struct mlx5hws_table *tbl, - struct mlx5hws_match_template *mt[], - u8 num_of_mt, - struct mlx5hws_action_template *at[], - u8 num_of_at, - struct mlx5hws_matcher_attr *attr) -{ - struct mlx5hws_context *ctx = tbl->ctx; - struct mlx5hws_matcher *matcher; - int ret; - - matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); - if (!matcher) - return NULL; - - matcher->tbl = tbl; - matcher->attr = *attr; - - ret = hws_matcher_process_attr(tbl->ctx->caps, matcher); - if (ret) - goto free_matcher; - - ret = hws_matcher_set_templates(matcher, mt, num_of_mt, at, num_of_at); - if (ret) - goto free_matcher; - - ret = hws_matcher_init(matcher); - if (ret) { - mlx5hws_err(ctx, "Failed to initialise matcher: %d\n", ret); - goto unset_templates; - } - - return matcher; - -unset_templates: - hws_matcher_unset_templates(matcher); -free_matcher: - kfree(matcher); - return NULL; -} - -int mlx5hws_matcher_destroy(struct mlx5hws_matcher *matcher) -{ - hws_matcher_uninit(matcher); - hws_matcher_unset_templates(matcher); - kfree(matcher); - return 0; -} - -struct mlx5hws_match_template * -mlx5hws_match_template_create(struct mlx5hws_context *ctx, - u32 *match_param, - u32 match_param_sz, - u8 match_criteria_enable) -{ - struct mlx5hws_match_template *mt; - - mt = kzalloc(sizeof(*mt), GFP_KERNEL); - if (!mt) - return NULL; - - mt->match_param = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL); - if (!mt->match_param) - goto free_template; - - memcpy(mt->match_param, match_param, match_param_sz); - mt->match_criteria_enable = match_criteria_enable; - - return mt; - -free_template: - kfree(mt); - return NULL; -} - -int mlx5hws_match_template_destroy(struct mlx5hws_match_template *mt) -{ - kfree(mt->match_param); - kfree(mt); - return 0; -} - -static int hws_matcher_resize_precheck(struct mlx5hws_matcher *src_matcher, - struct mlx5hws_matcher *dst_matcher) -{ - struct mlx5hws_context *ctx = src_matcher->tbl->ctx; - int i; - - if (src_matcher->tbl->type != dst_matcher->tbl->type) { - mlx5hws_err(ctx, "Table type mismatch for src/dst matchers\n"); - return -EINVAL; - } - - if (!mlx5hws_matcher_is_resizable(src_matcher) || - !mlx5hws_matcher_is_resizable(dst_matcher)) { - mlx5hws_err(ctx, "Src/dst matcher is not resizable\n"); - return -EINVAL; - } - - if (mlx5hws_matcher_is_insert_by_idx(src_matcher) != - mlx5hws_matcher_is_insert_by_idx(dst_matcher)) { - mlx5hws_err(ctx, "Src/dst matchers insert mode mismatch\n"); - return -EINVAL; - } - - if (mlx5hws_matcher_is_in_resize(src_matcher) || - mlx5hws_matcher_is_in_resize(dst_matcher)) { - mlx5hws_err(ctx, "Src/dst matcher is already in resize\n"); - return -EINVAL; - } - - /* Compare match templates - make sure the definers are equivalent */ - if (src_matcher->num_of_mt != dst_matcher->num_of_mt) { - mlx5hws_err(ctx, "Src/dst matcher match templates mismatch\n"); - return -EINVAL; - } - - if (src_matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes > - dst_matcher->action_ste[0].max_stes) { - mlx5hws_err(ctx, "Src/dst matcher max STEs mismatch\n"); - return -EINVAL; - } - - for (i = 0; i < src_matcher->num_of_mt; i++) { - if (mlx5hws_definer_compare(src_matcher->mt[i].definer, - dst_matcher->mt[i].definer)) { - mlx5hws_err(ctx, "Src/dst matcher definers mismatch\n"); - return -EINVAL; - } - } - - return 0; -} - -int mlx5hws_matcher_resize_set_target(struct mlx5hws_matcher *src_matcher, - struct mlx5hws_matcher *dst_matcher) -{ - int ret = 0; - - mutex_lock(&src_matcher->tbl->ctx->ctrl_lock); - - ret = hws_matcher_resize_precheck(src_matcher, dst_matcher); - if (ret) - goto out; - - src_matcher->resize_dst = dst_matcher; - - ret = hws_matcher_resize_init(src_matcher); - if (ret) - src_matcher->resize_dst = NULL; - -out: - mutex_unlock(&src_matcher->tbl->ctx->ctrl_lock); - return ret; -} - -int mlx5hws_matcher_resize_rule_move(struct mlx5hws_matcher *src_matcher, - struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - struct mlx5hws_context *ctx = src_matcher->tbl->ctx; - - if (unlikely(!mlx5hws_matcher_is_in_resize(src_matcher))) { - mlx5hws_err(ctx, "Matcher is not resizable or not in resize\n"); - return -EINVAL; - } - - if (unlikely(src_matcher != rule->matcher)) { - mlx5hws_err(ctx, "Rule doesn't belong to src matcher\n"); - return -EINVAL; - } - - return mlx5hws_rule_move_hws_add(rule, attr); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h deleted file mode 100644 index 125391d1a11483..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_matcher.h +++ /dev/null @@ -1,107 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_MATCHER_H_ -#define MLX5HWS_MATCHER_H_ - -/* We calculated that concatenating a collision table to the main table with - * 3% of the main table rows will be enough resources for high insertion - * success probability. - * - * The calculation: log2(2^x * 3 / 100) = log2(2^x) + log2(3/100) = x - 5.05 ~ 5 - */ -#define MLX5HWS_MATCHER_ASSURED_ROW_RATIO 5 -/* Threshold to determine if amount of rules require a collision table */ -#define MLX5HWS_MATCHER_ASSURED_RULES_TH 10 -/* Required depth of an assured collision table */ -#define MLX5HWS_MATCHER_ASSURED_COL_TBL_DEPTH 4 -/* Required depth of the main large table */ -#define MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH 2 - -enum mlx5hws_matcher_offset { - MLX5HWS_MATCHER_OFFSET_TAG_DW1 = 12, - MLX5HWS_MATCHER_OFFSET_TAG_DW0 = 13, -}; - -enum mlx5hws_matcher_flags { - MLX5HWS_MATCHER_FLAGS_COLLISION = 1 << 2, - MLX5HWS_MATCHER_FLAGS_RESIZABLE = 1 << 3, -}; - -struct mlx5hws_match_template { - struct mlx5hws_definer *definer; - struct mlx5hws_definer_fc *fc; - u32 *match_param; - u8 match_criteria_enable; - u16 fc_sz; -}; - -struct mlx5hws_matcher_match_ste { - struct mlx5hws_pool_chunk ste; - u32 rtc_0_id; - u32 rtc_1_id; - struct mlx5hws_pool *pool; -}; - -struct mlx5hws_matcher_action_ste { - struct mlx5hws_pool_chunk ste; - struct mlx5hws_pool_chunk stc; - u32 rtc_0_id; - u32 rtc_1_id; - struct mlx5hws_pool *pool; - u8 max_stes; -}; - -struct mlx5hws_matcher_resize_data_node { - struct mlx5hws_pool_chunk stc; - u32 rtc_0_id; - u32 rtc_1_id; - struct mlx5hws_pool *pool; -}; - -struct mlx5hws_matcher_resize_data { - struct mlx5hws_matcher_resize_data_node action_ste[2]; - u8 max_stes; - struct list_head list_node; -}; - -struct mlx5hws_matcher { - struct mlx5hws_table *tbl; - struct mlx5hws_matcher_attr attr; - struct mlx5hws_match_template *mt; - struct mlx5hws_action_template *at; - u8 num_of_at; - u8 num_of_mt; - /* enum mlx5hws_matcher_flags */ - u8 flags; - u32 end_ft_id; - struct mlx5hws_matcher *col_matcher; - struct mlx5hws_matcher *resize_dst; - struct mlx5hws_matcher_match_ste match_ste; - struct mlx5hws_matcher_action_ste action_ste[2]; - struct list_head list_node; - struct list_head resize_data; -}; - -static inline bool -mlx5hws_matcher_mt_is_jumbo(struct mlx5hws_match_template *mt) -{ - return mlx5hws_definer_is_jumbo(mt->definer); -} - -static inline bool mlx5hws_matcher_is_resizable(struct mlx5hws_matcher *matcher) -{ - return !!(matcher->flags & MLX5HWS_MATCHER_FLAGS_RESIZABLE); -} - -static inline bool mlx5hws_matcher_is_in_resize(struct mlx5hws_matcher *matcher) -{ - return !!matcher->resize_dst; -} - -static inline bool mlx5hws_matcher_is_insert_by_idx(struct mlx5hws_matcher *matcher) -{ - return matcher->attr.insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX; -} - -#endif /* MLX5HWS_MATCHER_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.c deleted file mode 100644 index e084a5cbf81fd4..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.c +++ /dev/null @@ -1,579 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -enum mlx5hws_arg_chunk_size -mlx5hws_arg_data_size_to_arg_log_size(u16 data_size) -{ - /* Return the roundup of log2(data_size) */ - if (data_size <= MLX5HWS_ARG_DATA_SIZE) - return MLX5HWS_ARG_CHUNK_SIZE_1; - if (data_size <= MLX5HWS_ARG_DATA_SIZE * 2) - return MLX5HWS_ARG_CHUNK_SIZE_2; - if (data_size <= MLX5HWS_ARG_DATA_SIZE * 4) - return MLX5HWS_ARG_CHUNK_SIZE_3; - if (data_size <= MLX5HWS_ARG_DATA_SIZE * 8) - return MLX5HWS_ARG_CHUNK_SIZE_4; - - return MLX5HWS_ARG_CHUNK_SIZE_MAX; -} - -u32 mlx5hws_arg_data_size_to_arg_size(u16 data_size) -{ - return BIT(mlx5hws_arg_data_size_to_arg_log_size(data_size)); -} - -enum mlx5hws_arg_chunk_size -mlx5hws_arg_get_arg_log_size(u16 num_of_actions) -{ - return mlx5hws_arg_data_size_to_arg_log_size(num_of_actions * - MLX5HWS_MODIFY_ACTION_SIZE); -} - -u32 mlx5hws_arg_get_arg_size(u16 num_of_actions) -{ - return BIT(mlx5hws_arg_get_arg_log_size(num_of_actions)); -} - -bool mlx5hws_pat_require_reparse(__be64 *actions, u16 num_of_actions) -{ - u16 i, field; - u8 action_id; - - for (i = 0; i < num_of_actions; i++) { - action_id = MLX5_GET(set_action_in, &actions[i], action_type); - - switch (action_id) { - case MLX5_MODIFICATION_TYPE_NOP: - field = MLX5_MODI_OUT_NONE; - break; - - case MLX5_MODIFICATION_TYPE_SET: - case MLX5_MODIFICATION_TYPE_ADD: - field = MLX5_GET(set_action_in, &actions[i], field); - break; - - case MLX5_MODIFICATION_TYPE_COPY: - case MLX5_MODIFICATION_TYPE_ADD_FIELD: - field = MLX5_GET(copy_action_in, &actions[i], dst_field); - break; - - default: - /* Insert/Remove/Unknown actions require reparse */ - return true; - } - - /* Below fields can change packet structure require a reparse */ - if (field == MLX5_MODI_OUT_ETHERTYPE || - field == MLX5_MODI_OUT_IPV6_NEXT_HDR) - return true; - } - - return false; -} - -/* Cache and cache element handling */ -int mlx5hws_pat_init_pattern_cache(struct mlx5hws_pattern_cache **cache) -{ - struct mlx5hws_pattern_cache *new_cache; - - new_cache = kzalloc(sizeof(*new_cache), GFP_KERNEL); - if (!new_cache) - return -ENOMEM; - - INIT_LIST_HEAD(&new_cache->ptrn_list); - mutex_init(&new_cache->lock); - - *cache = new_cache; - - return 0; -} - -void mlx5hws_pat_uninit_pattern_cache(struct mlx5hws_pattern_cache *cache) -{ - mutex_destroy(&cache->lock); - kfree(cache); -} - -static bool mlx5hws_pat_compare_pattern(int cur_num_of_actions, - __be64 cur_actions[], - int num_of_actions, - __be64 actions[]) -{ - int i; - - if (cur_num_of_actions != num_of_actions) - return false; - - for (i = 0; i < num_of_actions; i++) { - u8 action_id = - MLX5_GET(set_action_in, &actions[i], action_type); - - if (action_id == MLX5_MODIFICATION_TYPE_COPY || - action_id == MLX5_MODIFICATION_TYPE_ADD_FIELD) { - if (actions[i] != cur_actions[i]) - return false; - } else { - /* Compare just the control, not the values */ - if ((__force __be32)actions[i] != - (__force __be32)cur_actions[i]) - return false; - } - } - - return true; -} - -static struct mlx5hws_pattern_cache_item * -mlx5hws_pat_find_cached_pattern(struct mlx5hws_pattern_cache *cache, - u16 num_of_actions, - __be64 *actions) -{ - struct mlx5hws_pattern_cache_item *cached_pat = NULL; - - list_for_each_entry(cached_pat, &cache->ptrn_list, ptrn_list_node) { - if (mlx5hws_pat_compare_pattern(cached_pat->mh_data.num_of_actions, - (__be64 *)cached_pat->mh_data.data, - num_of_actions, - actions)) - return cached_pat; - } - - return NULL; -} - -static struct mlx5hws_pattern_cache_item * -mlx5hws_pat_get_existing_cached_pattern(struct mlx5hws_pattern_cache *cache, - u16 num_of_actions, - __be64 *actions) -{ - struct mlx5hws_pattern_cache_item *cached_pattern; - - cached_pattern = mlx5hws_pat_find_cached_pattern(cache, num_of_actions, actions); - if (cached_pattern) { - /* LRU: move it to be first in the list */ - list_del_init(&cached_pattern->ptrn_list_node); - list_add(&cached_pattern->ptrn_list_node, &cache->ptrn_list); - cached_pattern->refcount++; - } - - return cached_pattern; -} - -static struct mlx5hws_pattern_cache_item * -mlx5hws_pat_add_pattern_to_cache(struct mlx5hws_pattern_cache *cache, - u32 pattern_id, - u16 num_of_actions, - __be64 *actions) -{ - struct mlx5hws_pattern_cache_item *cached_pattern; - - cached_pattern = kzalloc(sizeof(*cached_pattern), GFP_KERNEL); - if (!cached_pattern) - return NULL; - - cached_pattern->mh_data.num_of_actions = num_of_actions; - cached_pattern->mh_data.pattern_id = pattern_id; - cached_pattern->mh_data.data = - kmemdup(actions, num_of_actions * MLX5HWS_MODIFY_ACTION_SIZE, GFP_KERNEL); - if (!cached_pattern->mh_data.data) - goto free_cached_obj; - - list_add(&cached_pattern->ptrn_list_node, &cache->ptrn_list); - cached_pattern->refcount = 1; - - return cached_pattern; - -free_cached_obj: - kfree(cached_pattern); - return NULL; -} - -static struct mlx5hws_pattern_cache_item * -mlx5hws_pat_find_cached_pattern_by_id(struct mlx5hws_pattern_cache *cache, - u32 ptrn_id) -{ - struct mlx5hws_pattern_cache_item *cached_pattern = NULL; - - list_for_each_entry(cached_pattern, &cache->ptrn_list, ptrn_list_node) { - if (cached_pattern->mh_data.pattern_id == ptrn_id) - return cached_pattern; - } - - return NULL; -} - -static void -mlx5hws_pat_remove_pattern(struct mlx5hws_pattern_cache_item *cached_pattern) -{ - list_del_init(&cached_pattern->ptrn_list_node); - - kfree(cached_pattern->mh_data.data); - kfree(cached_pattern); -} - -void mlx5hws_pat_put_pattern(struct mlx5hws_context *ctx, u32 ptrn_id) -{ - struct mlx5hws_pattern_cache *cache = ctx->pattern_cache; - struct mlx5hws_pattern_cache_item *cached_pattern; - - mutex_lock(&cache->lock); - cached_pattern = mlx5hws_pat_find_cached_pattern_by_id(cache, ptrn_id); - if (!cached_pattern) { - mlx5hws_err(ctx, "Failed to find cached pattern with provided ID\n"); - pr_warn("HWS: pattern ID %d is not found\n", ptrn_id); - goto out; - } - - if (--cached_pattern->refcount) - goto out; - - mlx5hws_pat_remove_pattern(cached_pattern); - mlx5hws_cmd_header_modify_pattern_destroy(ctx->mdev, ptrn_id); - -out: - mutex_unlock(&cache->lock); -} - -int mlx5hws_pat_get_pattern(struct mlx5hws_context *ctx, - __be64 *pattern, size_t pattern_sz, - u32 *pattern_id) -{ - u16 num_of_actions = pattern_sz / MLX5HWS_MODIFY_ACTION_SIZE; - struct mlx5hws_pattern_cache_item *cached_pattern; - u32 ptrn_id = 0; - int ret = 0; - - mutex_lock(&ctx->pattern_cache->lock); - - cached_pattern = mlx5hws_pat_get_existing_cached_pattern(ctx->pattern_cache, - num_of_actions, - pattern); - if (cached_pattern) { - *pattern_id = cached_pattern->mh_data.pattern_id; - goto out_unlock; - } - - ret = mlx5hws_cmd_header_modify_pattern_create(ctx->mdev, - pattern_sz, - (u8 *)pattern, - &ptrn_id); - if (ret) { - mlx5hws_err(ctx, "Failed to create pattern FW object\n"); - goto out_unlock; - } - - cached_pattern = mlx5hws_pat_add_pattern_to_cache(ctx->pattern_cache, - ptrn_id, - num_of_actions, - pattern); - if (!cached_pattern) { - mlx5hws_err(ctx, "Failed to add pattern to cache\n"); - ret = -EINVAL; - goto clean_pattern; - } - - mutex_unlock(&ctx->pattern_cache->lock); - *pattern_id = ptrn_id; - - return ret; - -clean_pattern: - mlx5hws_cmd_header_modify_pattern_destroy(ctx->mdev, *pattern_id); -out_unlock: - mutex_unlock(&ctx->pattern_cache->lock); - return ret; -} - -static void -mlx5d_arg_init_send_attr(struct mlx5hws_send_engine_post_attr *send_attr, - void *comp_data, - u32 arg_idx) -{ - send_attr->opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; - send_attr->opmod = MLX5HWS_WQE_GTA_OPMOD_MOD_ARG; - send_attr->len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; - send_attr->id = arg_idx; - send_attr->user_data = comp_data; -} - -void mlx5hws_arg_decapl3_write(struct mlx5hws_send_engine *queue, - u32 arg_idx, - u8 *arg_data, - u16 num_of_actions) -{ - struct mlx5hws_send_engine_post_attr send_attr = {0}; - struct mlx5hws_wqe_gta_data_seg_arg *wqe_arg = NULL; - struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl = NULL; - struct mlx5hws_send_engine_post_ctrl ctrl; - size_t wqe_len; - - mlx5d_arg_init_send_attr(&send_attr, NULL, arg_idx); - - ctrl = mlx5hws_send_engine_post_start(queue); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); - memset(wqe_ctrl, 0, wqe_len); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_arg, &wqe_len); - mlx5hws_action_prepare_decap_l3_data(arg_data, (u8 *)wqe_arg, - num_of_actions); - mlx5hws_send_engine_post_end(&ctrl, &send_attr); -} - -void mlx5hws_arg_write(struct mlx5hws_send_engine *queue, - void *comp_data, - u32 arg_idx, - u8 *arg_data, - size_t data_size) -{ - struct mlx5hws_send_engine_post_attr send_attr = {0}; - struct mlx5hws_wqe_gta_data_seg_arg *wqe_arg; - struct mlx5hws_send_engine_post_ctrl ctrl; - struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; - int i, full_iter, leftover; - size_t wqe_len; - - mlx5d_arg_init_send_attr(&send_attr, comp_data, arg_idx); - - /* Each WQE can hold 64B of data, it might require multiple iteration */ - full_iter = data_size / MLX5HWS_ARG_DATA_SIZE; - leftover = data_size & (MLX5HWS_ARG_DATA_SIZE - 1); - - for (i = 0; i < full_iter; i++) { - ctrl = mlx5hws_send_engine_post_start(queue); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); - memset(wqe_ctrl, 0, wqe_len); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_arg, &wqe_len); - memcpy(wqe_arg, arg_data, wqe_len); - send_attr.id = arg_idx++; - mlx5hws_send_engine_post_end(&ctrl, &send_attr); - - /* Move to next argument data */ - arg_data += MLX5HWS_ARG_DATA_SIZE; - } - - if (leftover) { - ctrl = mlx5hws_send_engine_post_start(queue); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); - memset(wqe_ctrl, 0, wqe_len); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_arg, &wqe_len); - memcpy(wqe_arg, arg_data, leftover); - send_attr.id = arg_idx; - mlx5hws_send_engine_post_end(&ctrl, &send_attr); - } -} - -int mlx5hws_arg_write_inline_arg_data(struct mlx5hws_context *ctx, - u32 arg_idx, - u8 *arg_data, - size_t data_size) -{ - struct mlx5hws_send_engine *queue; - int ret; - - mutex_lock(&ctx->ctrl_lock); - - /* Get the control queue */ - queue = &ctx->send_queue[ctx->queues - 1]; - - mlx5hws_arg_write(queue, arg_data, arg_idx, arg_data, data_size); - - mlx5hws_send_engine_flush_queue(queue); - - /* Poll for completion */ - ret = mlx5hws_send_queue_action(ctx, ctx->queues - 1, - MLX5HWS_SEND_QUEUE_ACTION_DRAIN_SYNC); - - if (ret) - mlx5hws_err(ctx, "Failed to drain arg queue\n"); - - mutex_unlock(&ctx->ctrl_lock); - - return ret; -} - -bool mlx5hws_arg_is_valid_arg_request_size(struct mlx5hws_context *ctx, - u32 arg_size) -{ - if (arg_size < ctx->caps->log_header_modify_argument_granularity || - arg_size > ctx->caps->log_header_modify_argument_max_alloc) { - return false; - } - return true; -} - -int mlx5hws_arg_create(struct mlx5hws_context *ctx, - u8 *data, - size_t data_sz, - u32 log_bulk_sz, - bool write_data, - u32 *arg_id) -{ - u16 single_arg_log_sz; - u16 multi_arg_log_sz; - int ret; - u32 id; - - single_arg_log_sz = mlx5hws_arg_data_size_to_arg_log_size(data_sz); - multi_arg_log_sz = single_arg_log_sz + log_bulk_sz; - - if (single_arg_log_sz >= MLX5HWS_ARG_CHUNK_SIZE_MAX) { - mlx5hws_err(ctx, "Requested single arg %u not supported\n", single_arg_log_sz); - return -EOPNOTSUPP; - } - - if (!mlx5hws_arg_is_valid_arg_request_size(ctx, multi_arg_log_sz)) { - mlx5hws_err(ctx, "Argument log size %d not supported by FW\n", multi_arg_log_sz); - return -EOPNOTSUPP; - } - - /* Alloc bulk of args */ - ret = mlx5hws_cmd_arg_create(ctx->mdev, multi_arg_log_sz, ctx->pd_num, &id); - if (ret) { - mlx5hws_err(ctx, "Failed allocating arg in order: %d\n", multi_arg_log_sz); - return ret; - } - - if (write_data) { - ret = mlx5hws_arg_write_inline_arg_data(ctx, id, - data, data_sz); - if (ret) { - mlx5hws_err(ctx, "Failed writing arg data\n"); - mlx5hws_cmd_arg_destroy(ctx->mdev, id); - return ret; - } - } - - *arg_id = id; - return ret; -} - -void mlx5hws_arg_destroy(struct mlx5hws_context *ctx, u32 arg_id) -{ - mlx5hws_cmd_arg_destroy(ctx->mdev, arg_id); -} - -int mlx5hws_arg_create_modify_header_arg(struct mlx5hws_context *ctx, - __be64 *data, - u8 num_of_actions, - u32 log_bulk_sz, - bool write_data, - u32 *arg_id) -{ - size_t data_sz = num_of_actions * MLX5HWS_MODIFY_ACTION_SIZE; - int ret; - - ret = mlx5hws_arg_create(ctx, - (u8 *)data, - data_sz, - log_bulk_sz, - write_data, - arg_id); - if (ret) - mlx5hws_err(ctx, "Failed creating modify header arg\n"); - - return ret; -} - -static int -hws_action_modify_check_field_limitation(u8 action_type, __be64 *pattern) -{ - /* Need to check field limitation here, but for now - return OK */ - return 0; -} - -#define INVALID_FIELD 0xffff - -static void -hws_action_modify_get_target_fields(u8 action_type, __be64 *pattern, - u16 *src_field, u16 *dst_field) -{ - switch (action_type) { - case MLX5_ACTION_TYPE_SET: - case MLX5_ACTION_TYPE_ADD: - *src_field = MLX5_GET(set_action_in, pattern, field); - *dst_field = INVALID_FIELD; - break; - case MLX5_ACTION_TYPE_COPY: - *src_field = MLX5_GET(copy_action_in, pattern, src_field); - *dst_field = MLX5_GET(copy_action_in, pattern, dst_field); - break; - default: - pr_warn("HWS: invalid modify header action type %d\n", action_type); - } -} - -bool mlx5hws_pat_verify_actions(struct mlx5hws_context *ctx, __be64 pattern[], size_t sz) -{ - size_t i; - - for (i = 0; i < sz / MLX5HWS_MODIFY_ACTION_SIZE; i++) { - u8 action_type = - MLX5_GET(set_action_in, &pattern[i], action_type); - if (action_type >= MLX5_MODIFICATION_TYPE_MAX) { - mlx5hws_err(ctx, "Unsupported action id %d\n", action_type); - return false; - } - if (hws_action_modify_check_field_limitation(action_type, &pattern[i])) { - mlx5hws_err(ctx, "Unsupported action number %zu\n", i); - return false; - } - } - - return true; -} - -void mlx5hws_pat_calc_nope(__be64 *pattern, size_t num_actions, - size_t max_actions, size_t *new_size, - u32 *nope_location, __be64 *new_pat) -{ - u16 prev_src_field = 0, prev_dst_field = 0; - u16 src_field, dst_field; - u8 action_type; - size_t i, j; - - *new_size = num_actions; - *nope_location = 0; - - if (num_actions == 1) - return; - - for (i = 0, j = 0; i < num_actions; i++, j++) { - action_type = MLX5_GET(set_action_in, &pattern[i], action_type); - - hws_action_modify_get_target_fields(action_type, &pattern[i], - &src_field, &dst_field); - if (i % 2) { - if (action_type == MLX5_ACTION_TYPE_COPY && - (prev_src_field == src_field || - prev_dst_field == dst_field)) { - /* need Nope */ - *new_size += 1; - *nope_location |= BIT(i); - memset(&new_pat[j], 0, MLX5HWS_MODIFY_ACTION_SIZE); - MLX5_SET(set_action_in, &new_pat[j], - action_type, - MLX5_MODIFICATION_TYPE_NOP); - j++; - } else if (prev_src_field == src_field) { - /* need Nope*/ - *new_size += 1; - *nope_location |= BIT(i); - MLX5_SET(set_action_in, &new_pat[j], - action_type, - MLX5_MODIFICATION_TYPE_NOP); - j++; - } - } - memcpy(&new_pat[j], &pattern[i], MLX5HWS_MODIFY_ACTION_SIZE); - /* check if no more space */ - if (j > max_actions) { - *new_size = num_actions; - *nope_location = 0; - return; - } - - prev_src_field = src_field; - prev_dst_field = dst_field; - } -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h deleted file mode 100644 index 27ca93385b0841..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pat_arg.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_PAT_ARG_H_ -#define MLX5HWS_PAT_ARG_H_ - -/* Modify-header arg pool */ -enum mlx5hws_arg_chunk_size { - MLX5HWS_ARG_CHUNK_SIZE_1, - /* Keep MIN updated when changing */ - MLX5HWS_ARG_CHUNK_SIZE_MIN = MLX5HWS_ARG_CHUNK_SIZE_1, - MLX5HWS_ARG_CHUNK_SIZE_2, - MLX5HWS_ARG_CHUNK_SIZE_3, - MLX5HWS_ARG_CHUNK_SIZE_4, - MLX5HWS_ARG_CHUNK_SIZE_MAX, -}; - -enum { - MLX5HWS_MODIFY_ACTION_SIZE = 8, - MLX5HWS_ARG_DATA_SIZE = 64, -}; - -struct mlx5hws_pattern_cache { - struct mutex lock; /* Protect pattern list */ - struct list_head ptrn_list; -}; - -struct mlx5hws_pattern_cache_item { - struct { - u32 pattern_id; - u8 *data; - u16 num_of_actions; - } mh_data; - u32 refcount; - struct list_head ptrn_list_node; -}; - -enum mlx5hws_arg_chunk_size -mlx5hws_arg_get_arg_log_size(u16 num_of_actions); - -u32 mlx5hws_arg_get_arg_size(u16 num_of_actions); - -enum mlx5hws_arg_chunk_size -mlx5hws_arg_data_size_to_arg_log_size(u16 data_size); - -u32 mlx5hws_arg_data_size_to_arg_size(u16 data_size); - -int mlx5hws_pat_init_pattern_cache(struct mlx5hws_pattern_cache **cache); - -void mlx5hws_pat_uninit_pattern_cache(struct mlx5hws_pattern_cache *cache); - -bool mlx5hws_pat_verify_actions(struct mlx5hws_context *ctx, __be64 pattern[], size_t sz); - -int mlx5hws_arg_create(struct mlx5hws_context *ctx, - u8 *data, - size_t data_sz, - u32 log_bulk_sz, - bool write_data, - u32 *arg_id); - -void mlx5hws_arg_destroy(struct mlx5hws_context *ctx, u32 arg_id); - -int mlx5hws_arg_create_modify_header_arg(struct mlx5hws_context *ctx, - __be64 *data, - u8 num_of_actions, - u32 log_bulk_sz, - bool write_data, - u32 *modify_hdr_arg_id); - -int mlx5hws_pat_get_pattern(struct mlx5hws_context *ctx, - __be64 *pattern, - size_t pattern_sz, - u32 *ptrn_id); - -void mlx5hws_pat_put_pattern(struct mlx5hws_context *ctx, - u32 ptrn_id); - -bool mlx5hws_arg_is_valid_arg_request_size(struct mlx5hws_context *ctx, - u32 arg_size); - -bool mlx5hws_pat_require_reparse(__be64 *actions, u16 num_of_actions); - -void mlx5hws_arg_write(struct mlx5hws_send_engine *queue, - void *comp_data, - u32 arg_idx, - u8 *arg_data, - size_t data_size); - -void mlx5hws_arg_decapl3_write(struct mlx5hws_send_engine *queue, - u32 arg_idx, - u8 *arg_data, - u16 num_of_actions); - -int mlx5hws_arg_write_inline_arg_data(struct mlx5hws_context *ctx, - u32 arg_idx, - u8 *arg_data, - size_t data_size); - -void mlx5hws_pat_calc_nope(__be64 *pattern, size_t num_actions, size_t max_actions, - size_t *new_size, u32 *nope_location, __be64 *new_pat); -#endif /* MLX5HWS_PAT_ARG_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c deleted file mode 100644 index a8a63e3278be30..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.c +++ /dev/null @@ -1,640 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" -#include "mlx5hws_buddy.h" - -static void hws_pool_free_one_resource(struct mlx5hws_pool_resource *resource) -{ - switch (resource->pool->type) { - case MLX5HWS_POOL_TYPE_STE: - mlx5hws_cmd_ste_destroy(resource->pool->ctx->mdev, resource->base_id); - break; - case MLX5HWS_POOL_TYPE_STC: - mlx5hws_cmd_stc_destroy(resource->pool->ctx->mdev, resource->base_id); - break; - default: - break; - } - - kfree(resource); -} - -static void hws_pool_resource_free(struct mlx5hws_pool *pool, - int resource_idx) -{ - hws_pool_free_one_resource(pool->resource[resource_idx]); - pool->resource[resource_idx] = NULL; - - if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) { - hws_pool_free_one_resource(pool->mirror_resource[resource_idx]); - pool->mirror_resource[resource_idx] = NULL; - } -} - -static struct mlx5hws_pool_resource * -hws_pool_create_one_resource(struct mlx5hws_pool *pool, u32 log_range, - u32 fw_ft_type) -{ - struct mlx5hws_cmd_ste_create_attr ste_attr; - struct mlx5hws_cmd_stc_create_attr stc_attr; - struct mlx5hws_pool_resource *resource; - u32 obj_id = 0; - int ret; - - resource = kzalloc(sizeof(*resource), GFP_KERNEL); - if (!resource) - return NULL; - - switch (pool->type) { - case MLX5HWS_POOL_TYPE_STE: - ste_attr.log_obj_range = log_range; - ste_attr.table_type = fw_ft_type; - ret = mlx5hws_cmd_ste_create(pool->ctx->mdev, &ste_attr, &obj_id); - break; - case MLX5HWS_POOL_TYPE_STC: - stc_attr.log_obj_range = log_range; - stc_attr.table_type = fw_ft_type; - ret = mlx5hws_cmd_stc_create(pool->ctx->mdev, &stc_attr, &obj_id); - break; - default: - ret = -EINVAL; - } - - if (ret) { - mlx5hws_err(pool->ctx, "Failed to allocate resource objects\n"); - goto free_resource; - } - - resource->pool = pool; - resource->range = 1 << log_range; - resource->base_id = obj_id; - - return resource; - -free_resource: - kfree(resource); - return NULL; -} - -static int -hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range, int idx) -{ - struct mlx5hws_pool_resource *resource; - u32 fw_ft_type, opt_log_range; - - fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, false); - opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_ORIG ? 0 : log_range; - resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type); - if (!resource) { - mlx5hws_err(pool->ctx, "Failed allocating resource\n"); - return -EINVAL; - } - - pool->resource[idx] = resource; - - if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) { - struct mlx5hws_pool_resource *mirror_resource; - - fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, true); - opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_MIRROR ? 0 : log_range; - mirror_resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type); - if (!mirror_resource) { - mlx5hws_err(pool->ctx, "Failed allocating mirrored resource\n"); - hws_pool_free_one_resource(resource); - pool->resource[idx] = NULL; - return -EINVAL; - } - pool->mirror_resource[idx] = mirror_resource; - } - - return 0; -} - -static unsigned long *hws_pool_create_and_init_bitmap(u32 log_range) -{ - unsigned long *cur_bmp; - - cur_bmp = bitmap_zalloc(1 << log_range, GFP_KERNEL); - if (!cur_bmp) - return NULL; - - bitmap_fill(cur_bmp, 1 << log_range); - - return cur_bmp; -} - -static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - struct mlx5hws_buddy_mem *buddy; - - buddy = pool->db.buddy_manager->buddies[chunk->resource_idx]; - if (!buddy) { - mlx5hws_err(pool->ctx, "No such buddy (%d)\n", chunk->resource_idx); - return; - } - - mlx5hws_buddy_free_mem(buddy, chunk->offset, chunk->order); -} - -static struct mlx5hws_buddy_mem * -hws_pool_buddy_get_next_buddy(struct mlx5hws_pool *pool, int idx, - u32 order, bool *is_new_buddy) -{ - static struct mlx5hws_buddy_mem *buddy; - u32 new_buddy_size; - - buddy = pool->db.buddy_manager->buddies[idx]; - if (buddy) - return buddy; - - new_buddy_size = max(pool->alloc_log_sz, order); - *is_new_buddy = true; - buddy = mlx5hws_buddy_create(new_buddy_size); - if (!buddy) { - mlx5hws_err(pool->ctx, "Failed to create buddy order: %d index: %d\n", - new_buddy_size, idx); - return NULL; - } - - if (hws_pool_resource_alloc(pool, new_buddy_size, idx) != 0) { - mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", - pool->type, new_buddy_size, idx); - mlx5hws_buddy_cleanup(buddy); - return NULL; - } - - pool->db.buddy_manager->buddies[idx] = buddy; - - return buddy; -} - -static int hws_pool_buddy_get_mem_chunk(struct mlx5hws_pool *pool, - int order, - u32 *buddy_idx, - int *seg) -{ - struct mlx5hws_buddy_mem *buddy; - bool new_mem = false; - int ret = 0; - int i; - - *seg = -1; - - /* Find the next free place from the buddy array */ - while (*seg == -1) { - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { - buddy = hws_pool_buddy_get_next_buddy(pool, i, - order, - &new_mem); - if (!buddy) { - ret = -ENOMEM; - goto out; - } - - *seg = mlx5hws_buddy_alloc_mem(buddy, order); - if (*seg != -1) - goto found; - - if (pool->flags & MLX5HWS_POOL_FLAGS_ONE_RESOURCE) { - mlx5hws_err(pool->ctx, - "Fail to allocate seg for one resource pool\n"); - ret = -ENOMEM; - goto out; - } - - if (new_mem) { - /* We have new memory pool, should be place for us */ - mlx5hws_err(pool->ctx, - "No memory for order: %d with buddy no: %d\n", - order, i); - ret = -ENOMEM; - goto out; - } - } - } - -found: - *buddy_idx = i; -out: - return ret; -} - -static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - int ret = 0; - - /* Go over the buddies and find next free slot */ - ret = hws_pool_buddy_get_mem_chunk(pool, chunk->order, - &chunk->resource_idx, - &chunk->offset); - if (ret) - mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", - chunk->order); - - return ret; -} - -static void hws_pool_buddy_db_uninit(struct mlx5hws_pool *pool) -{ - struct mlx5hws_buddy_mem *buddy; - int i; - - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { - buddy = pool->db.buddy_manager->buddies[i]; - if (buddy) { - mlx5hws_buddy_cleanup(buddy); - kfree(buddy); - pool->db.buddy_manager->buddies[i] = NULL; - } - } - - kfree(pool->db.buddy_manager); -} - -static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool, u32 log_range) -{ - pool->db.buddy_manager = kzalloc(sizeof(*pool->db.buddy_manager), GFP_KERNEL); - if (!pool->db.buddy_manager) - return -ENOMEM; - - if (pool->flags & MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE) { - bool new_buddy; - - if (!hws_pool_buddy_get_next_buddy(pool, 0, log_range, &new_buddy)) { - mlx5hws_err(pool->ctx, - "Failed allocating memory on create log_sz: %d\n", log_range); - kfree(pool->db.buddy_manager); - return -ENOMEM; - } - } - - pool->p_db_uninit = &hws_pool_buddy_db_uninit; - pool->p_get_chunk = &hws_pool_buddy_db_get_chunk; - pool->p_put_chunk = &hws_pool_buddy_db_put_chunk; - - return 0; -} - -static int hws_pool_create_resource_on_index(struct mlx5hws_pool *pool, - u32 alloc_size, int idx) -{ - int ret = hws_pool_resource_alloc(pool, alloc_size, idx); - - if (ret) { - mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", - pool->type, alloc_size, idx); - return ret; - } - - return 0; -} - -static struct mlx5hws_pool_elements * -hws_pool_element_create_new_elem(struct mlx5hws_pool *pool, u32 order, int idx) -{ - struct mlx5hws_pool_elements *elem; - u32 alloc_size; - - alloc_size = pool->alloc_log_sz; - - elem = kzalloc(sizeof(*elem), GFP_KERNEL); - if (!elem) - return NULL; - - /* Sharing the same resource, also means that all the elements are with size 1 */ - if ((pool->flags & MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS) && - !(pool->flags & MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK)) { - /* Currently all chunks in size 1 */ - elem->bitmap = hws_pool_create_and_init_bitmap(alloc_size - order); - if (!elem->bitmap) { - mlx5hws_err(pool->ctx, - "Failed to create bitmap type: %d: size %d index: %d\n", - pool->type, alloc_size, idx); - goto free_elem; - } - - elem->log_size = alloc_size - order; - } - - if (hws_pool_create_resource_on_index(pool, alloc_size, idx)) { - mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", - pool->type, alloc_size, idx); - goto free_db; - } - - pool->db.element_manager->elements[idx] = elem; - - return elem; - -free_db: - bitmap_free(elem->bitmap); -free_elem: - kfree(elem); - return NULL; -} - -static int hws_pool_element_find_seg(struct mlx5hws_pool_elements *elem, int *seg) -{ - unsigned int segment, size; - - size = 1 << elem->log_size; - - segment = find_first_bit(elem->bitmap, size); - if (segment >= size) { - elem->is_full = true; - return -ENOMEM; - } - - bitmap_clear(elem->bitmap, segment, 1); - *seg = segment; - return 0; -} - -static int -hws_pool_onesize_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order, - u32 *idx, int *seg) -{ - struct mlx5hws_pool_elements *elem; - - elem = pool->db.element_manager->elements[0]; - if (!elem) - elem = hws_pool_element_create_new_elem(pool, order, 0); - if (!elem) - goto err_no_elem; - - if (hws_pool_element_find_seg(elem, seg) != 0) { - mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order); - return -ENOMEM; - } - - *idx = 0; - elem->num_of_elements++; - return 0; - -err_no_elem: - mlx5hws_err(pool->ctx, "Failed to allocate element for order: %d\n", order); - return -ENOMEM; -} - -static int -hws_pool_general_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order, - u32 *idx, int *seg) -{ - int ret, i; - - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { - if (!pool->resource[i]) { - ret = hws_pool_create_resource_on_index(pool, order, i); - if (ret) - goto err_no_res; - *idx = i; - *seg = 0; /* One memory slot in that element */ - return 0; - } - } - - mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order); - return -ENOMEM; - -err_no_res: - mlx5hws_err(pool->ctx, "Failed to allocate element for order: %d\n", order); - return -ENOMEM; -} - -static int hws_pool_general_element_db_get_chunk(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - int ret; - - /* Go over all memory elements and find/allocate free slot */ - ret = hws_pool_general_element_get_mem_chunk(pool, chunk->order, - &chunk->resource_idx, - &chunk->offset); - if (ret) - mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", - chunk->order); - - return ret; -} - -static void hws_pool_general_element_db_put_chunk(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - if (unlikely(!pool->resource[chunk->resource_idx])) - pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); - - if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE) - hws_pool_resource_free(pool, chunk->resource_idx); -} - -static void hws_pool_general_element_db_uninit(struct mlx5hws_pool *pool) -{ - (void)pool; -} - -/* This memory management works as the following: - * - At start doesn't allocate no mem at all. - * - When new request for chunk arrived: - * allocate resource and give it. - * - When free that chunk: - * the resource is freed. - */ -static int hws_pool_general_element_db_init(struct mlx5hws_pool *pool) -{ - pool->p_db_uninit = &hws_pool_general_element_db_uninit; - pool->p_get_chunk = &hws_pool_general_element_db_get_chunk; - pool->p_put_chunk = &hws_pool_general_element_db_put_chunk; - - return 0; -} - -static void hws_onesize_element_db_destroy_element(struct mlx5hws_pool *pool, - struct mlx5hws_pool_elements *elem, - struct mlx5hws_pool_chunk *chunk) -{ - if (unlikely(!pool->resource[chunk->resource_idx])) - pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); - - hws_pool_resource_free(pool, chunk->resource_idx); - kfree(elem); - pool->db.element_manager->elements[chunk->resource_idx] = NULL; -} - -static void hws_onesize_element_db_put_chunk(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - struct mlx5hws_pool_elements *elem; - - if (unlikely(chunk->resource_idx)) - pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); - - elem = pool->db.element_manager->elements[chunk->resource_idx]; - if (!elem) { - mlx5hws_err(pool->ctx, "No such element (%d)\n", chunk->resource_idx); - return; - } - - bitmap_set(elem->bitmap, chunk->offset, 1); - elem->is_full = false; - elem->num_of_elements--; - - if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE && - !elem->num_of_elements) - hws_onesize_element_db_destroy_element(pool, elem, chunk); -} - -static int hws_onesize_element_db_get_chunk(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - int ret = 0; - - /* Go over all memory elements and find/allocate free slot */ - ret = hws_pool_onesize_element_get_mem_chunk(pool, chunk->order, - &chunk->resource_idx, - &chunk->offset); - if (ret) - mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", - chunk->order); - - return ret; -} - -static void hws_onesize_element_db_uninit(struct mlx5hws_pool *pool) -{ - struct mlx5hws_pool_elements *elem; - int i; - - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { - elem = pool->db.element_manager->elements[i]; - if (elem) { - bitmap_free(elem->bitmap); - kfree(elem); - pool->db.element_manager->elements[i] = NULL; - } - } - kfree(pool->db.element_manager); -} - -/* This memory management works as the following: - * - At start doesn't allocate no mem at all. - * - When new request for chunk arrived: - * aloocate the first and only slot of memory/resource - * when it ended return error. - */ -static int hws_pool_onesize_element_db_init(struct mlx5hws_pool *pool) -{ - pool->db.element_manager = kzalloc(sizeof(*pool->db.element_manager), GFP_KERNEL); - if (!pool->db.element_manager) - return -ENOMEM; - - pool->p_db_uninit = &hws_onesize_element_db_uninit; - pool->p_get_chunk = &hws_onesize_element_db_get_chunk; - pool->p_put_chunk = &hws_onesize_element_db_put_chunk; - - return 0; -} - -static int hws_pool_db_init(struct mlx5hws_pool *pool, - enum mlx5hws_db_type db_type) -{ - int ret; - - if (db_type == MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE) - ret = hws_pool_general_element_db_init(pool); - else if (db_type == MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE) - ret = hws_pool_onesize_element_db_init(pool); - else - ret = hws_pool_buddy_db_init(pool, pool->alloc_log_sz); - - if (ret) { - mlx5hws_err(pool->ctx, "Failed to init general db : %d (ret: %d)\n", db_type, ret); - return ret; - } - - return 0; -} - -static void hws_pool_db_unint(struct mlx5hws_pool *pool) -{ - pool->p_db_uninit(pool); -} - -int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - int ret; - - mutex_lock(&pool->lock); - ret = pool->p_get_chunk(pool, chunk); - mutex_unlock(&pool->lock); - - return ret; -} - -void mlx5hws_pool_chunk_free(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - mutex_lock(&pool->lock); - pool->p_put_chunk(pool, chunk); - mutex_unlock(&pool->lock); -} - -struct mlx5hws_pool * -mlx5hws_pool_create(struct mlx5hws_context *ctx, struct mlx5hws_pool_attr *pool_attr) -{ - enum mlx5hws_db_type res_db_type; - struct mlx5hws_pool *pool; - - pool = kzalloc(sizeof(*pool), GFP_KERNEL); - if (!pool) - return NULL; - - pool->ctx = ctx; - pool->type = pool_attr->pool_type; - pool->alloc_log_sz = pool_attr->alloc_log_sz; - pool->flags = pool_attr->flags; - pool->tbl_type = pool_attr->table_type; - pool->opt_type = pool_attr->opt_type; - - /* Support general db */ - if (pool->flags == (MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE | - MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK)) - res_db_type = MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE; - else if (pool->flags == (MLX5HWS_POOL_FLAGS_ONE_RESOURCE | - MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS)) - res_db_type = MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE; - else - res_db_type = MLX5HWS_POOL_DB_TYPE_BUDDY; - - pool->alloc_log_sz = pool_attr->alloc_log_sz; - - if (hws_pool_db_init(pool, res_db_type)) - goto free_pool; - - mutex_init(&pool->lock); - - return pool; - -free_pool: - kfree(pool); - return NULL; -} - -int mlx5hws_pool_destroy(struct mlx5hws_pool *pool) -{ - int i; - - mutex_destroy(&pool->lock); - - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) - if (pool->resource[i]) - hws_pool_resource_free(pool, i); - - hws_pool_db_unint(pool); - - kfree(pool); - return 0; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h deleted file mode 100644 index 621298b352b244..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_pool.h +++ /dev/null @@ -1,151 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_POOL_H_ -#define MLX5HWS_POOL_H_ - -#define MLX5HWS_POOL_STC_LOG_SZ 15 - -#define MLX5HWS_POOL_RESOURCE_ARR_SZ 100 - -enum mlx5hws_pool_type { - MLX5HWS_POOL_TYPE_STE, - MLX5HWS_POOL_TYPE_STC, -}; - -struct mlx5hws_pool_chunk { - u32 resource_idx; - /* Internal offset, relative to base index */ - int offset; - int order; -}; - -struct mlx5hws_pool_resource { - struct mlx5hws_pool *pool; - u32 base_id; - u32 range; -}; - -enum mlx5hws_pool_flags { - /* Only a one resource in that pool */ - MLX5HWS_POOL_FLAGS_ONE_RESOURCE = 1 << 0, - MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE = 1 << 1, - /* No sharing resources between chunks */ - MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK = 1 << 2, - /* All objects are in the same size */ - MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS = 1 << 3, - /* Managed by buddy allocator */ - MLX5HWS_POOL_FLAGS_BUDDY_MANAGED = 1 << 4, - /* Allocate pool_type memory on pool creation */ - MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE = 1 << 5, - - /* These values should be used by the caller */ - MLX5HWS_POOL_FLAGS_FOR_STC_POOL = - MLX5HWS_POOL_FLAGS_ONE_RESOURCE | - MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS, - MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL = - MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE | - MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK, - MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL = - MLX5HWS_POOL_FLAGS_ONE_RESOURCE | - MLX5HWS_POOL_FLAGS_BUDDY_MANAGED | - MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE, -}; - -enum mlx5hws_pool_optimize { - MLX5HWS_POOL_OPTIMIZE_NONE = 0x0, - MLX5HWS_POOL_OPTIMIZE_ORIG = 0x1, - MLX5HWS_POOL_OPTIMIZE_MIRROR = 0x2, -}; - -struct mlx5hws_pool_attr { - enum mlx5hws_pool_type pool_type; - enum mlx5hws_table_type table_type; - enum mlx5hws_pool_flags flags; - enum mlx5hws_pool_optimize opt_type; - /* Allocation size once memory is depleted */ - size_t alloc_log_sz; -}; - -enum mlx5hws_db_type { - /* Uses for allocating chunk of big memory, each element has its own resource in the FW*/ - MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE, - /* One resource only, all the elements are with same one size */ - MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE, - /* Many resources, the memory allocated with buddy mechanism */ - MLX5HWS_POOL_DB_TYPE_BUDDY, -}; - -struct mlx5hws_buddy_manager { - struct mlx5hws_buddy_mem *buddies[MLX5HWS_POOL_RESOURCE_ARR_SZ]; -}; - -struct mlx5hws_pool_elements { - u32 num_of_elements; - unsigned long *bitmap; - u32 log_size; - bool is_full; -}; - -struct mlx5hws_element_manager { - struct mlx5hws_pool_elements *elements[MLX5HWS_POOL_RESOURCE_ARR_SZ]; -}; - -struct mlx5hws_pool_db { - enum mlx5hws_db_type type; - union { - struct mlx5hws_element_manager *element_manager; - struct mlx5hws_buddy_manager *buddy_manager; - }; -}; - -typedef int (*mlx5hws_pool_db_get_chunk)(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk); -typedef void (*mlx5hws_pool_db_put_chunk)(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk); -typedef void (*mlx5hws_pool_unint_db)(struct mlx5hws_pool *pool); - -struct mlx5hws_pool { - struct mlx5hws_context *ctx; - enum mlx5hws_pool_type type; - enum mlx5hws_pool_flags flags; - struct mutex lock; /* protect the pool */ - size_t alloc_log_sz; - enum mlx5hws_table_type tbl_type; - enum mlx5hws_pool_optimize opt_type; - struct mlx5hws_pool_resource *resource[MLX5HWS_POOL_RESOURCE_ARR_SZ]; - struct mlx5hws_pool_resource *mirror_resource[MLX5HWS_POOL_RESOURCE_ARR_SZ]; - /* DB */ - struct mlx5hws_pool_db db; - /* Functions */ - mlx5hws_pool_unint_db p_db_uninit; - mlx5hws_pool_db_get_chunk p_get_chunk; - mlx5hws_pool_db_put_chunk p_put_chunk; -}; - -struct mlx5hws_pool * -mlx5hws_pool_create(struct mlx5hws_context *ctx, - struct mlx5hws_pool_attr *pool_attr); - -int mlx5hws_pool_destroy(struct mlx5hws_pool *pool); - -int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk); - -void mlx5hws_pool_chunk_free(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk); - -static inline u32 -mlx5hws_pool_chunk_get_base_id(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - return pool->resource[chunk->resource_idx]->base_id; -} - -static inline u32 -mlx5hws_pool_chunk_get_base_mirror_id(struct mlx5hws_pool *pool, - struct mlx5hws_pool_chunk *chunk) -{ - return pool->mirror_resource[chunk->resource_idx]->base_id; -} -#endif /* MLX5HWS_POOL_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_prm.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_prm.h deleted file mode 100644 index de92cecbeb928a..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_prm.h +++ /dev/null @@ -1,514 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5_PRM_H_ -#define MLX5_PRM_H_ - -#define MLX5_MAX_ACTIONS_DATA_IN_HEADER_MODIFY 512 - -/* Action type of header modification. */ -enum { - MLX5_MODIFICATION_TYPE_SET = 0x1, - MLX5_MODIFICATION_TYPE_ADD = 0x2, - MLX5_MODIFICATION_TYPE_COPY = 0x3, - MLX5_MODIFICATION_TYPE_INSERT = 0x4, - MLX5_MODIFICATION_TYPE_REMOVE = 0x5, - MLX5_MODIFICATION_TYPE_NOP = 0x6, - MLX5_MODIFICATION_TYPE_REMOVE_WORDS = 0x7, - MLX5_MODIFICATION_TYPE_ADD_FIELD = 0x8, - MLX5_MODIFICATION_TYPE_MAX, -}; - -/* The field of packet to be modified. */ -enum mlx5_modification_field { - MLX5_MODI_OUT_NONE = -1, - MLX5_MODI_OUT_SMAC_47_16 = 1, - MLX5_MODI_OUT_SMAC_15_0, - MLX5_MODI_OUT_ETHERTYPE, - MLX5_MODI_OUT_DMAC_47_16, - MLX5_MODI_OUT_DMAC_15_0, - MLX5_MODI_OUT_IP_DSCP, - MLX5_MODI_OUT_TCP_FLAGS, - MLX5_MODI_OUT_TCP_SPORT, - MLX5_MODI_OUT_TCP_DPORT, - MLX5_MODI_OUT_IPV4_TTL, - MLX5_MODI_OUT_UDP_SPORT, - MLX5_MODI_OUT_UDP_DPORT, - MLX5_MODI_OUT_SIPV6_127_96, - MLX5_MODI_OUT_SIPV6_95_64, - MLX5_MODI_OUT_SIPV6_63_32, - MLX5_MODI_OUT_SIPV6_31_0, - MLX5_MODI_OUT_DIPV6_127_96, - MLX5_MODI_OUT_DIPV6_95_64, - MLX5_MODI_OUT_DIPV6_63_32, - MLX5_MODI_OUT_DIPV6_31_0, - MLX5_MODI_OUT_SIPV4, - MLX5_MODI_OUT_DIPV4, - MLX5_MODI_OUT_FIRST_VID, - MLX5_MODI_IN_SMAC_47_16 = 0x31, - MLX5_MODI_IN_SMAC_15_0, - MLX5_MODI_IN_ETHERTYPE, - MLX5_MODI_IN_DMAC_47_16, - MLX5_MODI_IN_DMAC_15_0, - MLX5_MODI_IN_IP_DSCP, - MLX5_MODI_IN_TCP_FLAGS, - MLX5_MODI_IN_TCP_SPORT, - MLX5_MODI_IN_TCP_DPORT, - MLX5_MODI_IN_IPV4_TTL, - MLX5_MODI_IN_UDP_SPORT, - MLX5_MODI_IN_UDP_DPORT, - MLX5_MODI_IN_SIPV6_127_96, - MLX5_MODI_IN_SIPV6_95_64, - MLX5_MODI_IN_SIPV6_63_32, - MLX5_MODI_IN_SIPV6_31_0, - MLX5_MODI_IN_DIPV6_127_96, - MLX5_MODI_IN_DIPV6_95_64, - MLX5_MODI_IN_DIPV6_63_32, - MLX5_MODI_IN_DIPV6_31_0, - MLX5_MODI_IN_SIPV4, - MLX5_MODI_IN_DIPV4, - MLX5_MODI_OUT_IPV6_HOPLIMIT, - MLX5_MODI_IN_IPV6_HOPLIMIT, - MLX5_MODI_META_DATA_REG_A, - MLX5_MODI_META_DATA_REG_B = 0x50, - MLX5_MODI_META_REG_C_0, - MLX5_MODI_META_REG_C_1, - MLX5_MODI_META_REG_C_2, - MLX5_MODI_META_REG_C_3, - MLX5_MODI_META_REG_C_4, - MLX5_MODI_META_REG_C_5, - MLX5_MODI_META_REG_C_6, - MLX5_MODI_META_REG_C_7, - MLX5_MODI_OUT_TCP_SEQ_NUM, - MLX5_MODI_IN_TCP_SEQ_NUM, - MLX5_MODI_OUT_TCP_ACK_NUM, - MLX5_MODI_IN_TCP_ACK_NUM = 0x5C, - MLX5_MODI_GTP_TEID = 0x6E, - MLX5_MODI_OUT_IP_ECN = 0x73, - MLX5_MODI_TUNNEL_HDR_DW_1 = 0x75, - MLX5_MODI_GTPU_FIRST_EXT_DW_0 = 0x76, - MLX5_MODI_HASH_RESULT = 0x81, - MLX5_MODI_IN_MPLS_LABEL_0 = 0x8a, - MLX5_MODI_IN_MPLS_LABEL_1, - MLX5_MODI_IN_MPLS_LABEL_2, - MLX5_MODI_IN_MPLS_LABEL_3, - MLX5_MODI_IN_MPLS_LABEL_4, - MLX5_MODI_OUT_IP_PROTOCOL = 0x4A, - MLX5_MODI_OUT_IPV6_NEXT_HDR = 0x4A, - MLX5_MODI_META_REG_C_8 = 0x8F, - MLX5_MODI_META_REG_C_9 = 0x90, - MLX5_MODI_META_REG_C_10 = 0x91, - MLX5_MODI_META_REG_C_11 = 0x92, - MLX5_MODI_META_REG_C_12 = 0x93, - MLX5_MODI_META_REG_C_13 = 0x94, - MLX5_MODI_META_REG_C_14 = 0x95, - MLX5_MODI_META_REG_C_15 = 0x96, - MLX5_MODI_OUT_IPV4_TOTAL_LEN = 0x11D, - MLX5_MODI_OUT_IPV6_PAYLOAD_LEN = 0x11E, - MLX5_MODI_OUT_IPV4_IHL = 0x11F, - MLX5_MODI_OUT_TCP_DATA_OFFSET = 0x120, - MLX5_MODI_OUT_ESP_SPI = 0x5E, - MLX5_MODI_OUT_ESP_SEQ_NUM = 0x82, - MLX5_MODI_OUT_IPSEC_NEXT_HDR = 0x126, - MLX5_MODI_INVALID = INT_MAX, -}; - -enum { - MLX5_GET_HCA_CAP_OP_MOD_NIC_FLOW_TABLE = 0x7 << 1, - MLX5_GET_HCA_CAP_OP_MOD_ESW_FLOW_TABLE = 0x8 << 1, - MLX5_SET_HCA_CAP_OP_MOD_ESW = 0x9 << 1, - MLX5_GET_HCA_CAP_OP_MOD_WQE_BASED_FLOW_TABLE = 0x1B << 1, - MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 = 0x20 << 1, -}; - -enum mlx5_ifc_rtc_update_mode { - MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH = 0x0, - MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET = 0x1, -}; - -enum mlx5_ifc_rtc_access_mode { - MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH = 0x0, - MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR = 0x1, -}; - -enum mlx5_ifc_rtc_ste_format { - MLX5_IFC_RTC_STE_FORMAT_8DW = 0x4, - MLX5_IFC_RTC_STE_FORMAT_11DW = 0x5, - MLX5_IFC_RTC_STE_FORMAT_RANGE = 0x7, -}; - -enum mlx5_ifc_rtc_reparse_mode { - MLX5_IFC_RTC_REPARSE_NEVER = 0x0, - MLX5_IFC_RTC_REPARSE_ALWAYS = 0x1, - MLX5_IFC_RTC_REPARSE_BY_STC = 0x2, -}; - -#define MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX 16 - -struct mlx5_ifc_rtc_bits { - u8 modify_field_select[0x40]; - u8 reserved_at_40[0x40]; - u8 update_index_mode[0x2]; - u8 reparse_mode[0x2]; - u8 num_match_ste[0x4]; - u8 pd[0x18]; - u8 reserved_at_a0[0x9]; - u8 access_index_mode[0x3]; - u8 num_hash_definer[0x4]; - u8 update_method[0x1]; - u8 reserved_at_b1[0x2]; - u8 log_depth[0x5]; - u8 log_hash_size[0x8]; - u8 ste_format_0[0x8]; - u8 table_type[0x8]; - u8 ste_format_1[0x8]; - u8 reserved_at_d8[0x8]; - u8 match_definer_0[0x20]; - u8 stc_id[0x20]; - u8 ste_table_base_id[0x20]; - u8 ste_table_offset[0x20]; - u8 reserved_at_160[0x8]; - u8 miss_flow_table_id[0x18]; - u8 match_definer_1[0x20]; - u8 reserved_at_1a0[0x260]; -}; - -enum mlx5_ifc_stc_action_type { - MLX5_IFC_STC_ACTION_TYPE_NOP = 0x00, - MLX5_IFC_STC_ACTION_TYPE_COPY = 0x05, - MLX5_IFC_STC_ACTION_TYPE_SET = 0x06, - MLX5_IFC_STC_ACTION_TYPE_ADD = 0x07, - MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS = 0x08, - MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE = 0x09, - MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT = 0x0b, - MLX5_IFC_STC_ACTION_TYPE_TAG = 0x0c, - MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST = 0x0e, - MLX5_IFC_STC_ACTION_TYPE_CRYPTO_IPSEC_ENCRYPTION = 0x10, - MLX5_IFC_STC_ACTION_TYPE_CRYPTO_IPSEC_DECRYPTION = 0x11, - MLX5_IFC_STC_ACTION_TYPE_ASO = 0x12, - MLX5_IFC_STC_ACTION_TYPE_TRAILER = 0x13, - MLX5_IFC_STC_ACTION_TYPE_COUNTER = 0x14, - MLX5_IFC_STC_ACTION_TYPE_ADD_FIELD = 0x1b, - MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE = 0x80, - MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR = 0x81, - MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT = 0x82, - MLX5_IFC_STC_ACTION_TYPE_DROP = 0x83, - MLX5_IFC_STC_ACTION_TYPE_ALLOW = 0x84, - MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT = 0x85, - MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK = 0x86, -}; - -enum mlx5_ifc_stc_reparse_mode { - MLX5_IFC_STC_REPARSE_IGNORE = 0x0, - MLX5_IFC_STC_REPARSE_NEVER = 0x1, - MLX5_IFC_STC_REPARSE_ALWAYS = 0x2, -}; - -struct mlx5_ifc_stc_ste_param_ste_table_bits { - u8 ste_obj_id[0x20]; - u8 match_definer_id[0x20]; - u8 reserved_at_40[0x3]; - u8 log_hash_size[0x5]; - u8 reserved_at_48[0x38]; -}; - -struct mlx5_ifc_stc_ste_param_tir_bits { - u8 reserved_at_0[0x8]; - u8 tirn[0x18]; - u8 reserved_at_20[0x60]; -}; - -struct mlx5_ifc_stc_ste_param_table_bits { - u8 reserved_at_0[0x8]; - u8 table_id[0x18]; - u8 reserved_at_20[0x60]; -}; - -struct mlx5_ifc_stc_ste_param_flow_counter_bits { - u8 flow_counter_id[0x20]; -}; - -enum { - MLX5_ASO_CT_NUM_PER_OBJ = 1, - MLX5_ASO_METER_NUM_PER_OBJ = 2, - MLX5_ASO_IPSEC_NUM_PER_OBJ = 1, - MLX5_ASO_FIRST_HIT_NUM_PER_OBJ = 512, -}; - -struct mlx5_ifc_stc_ste_param_execute_aso_bits { - u8 aso_object_id[0x20]; - u8 return_reg_id[0x4]; - u8 aso_type[0x4]; - u8 reserved_at_28[0x18]; -}; - -struct mlx5_ifc_stc_ste_param_ipsec_encrypt_bits { - u8 ipsec_object_id[0x20]; -}; - -struct mlx5_ifc_stc_ste_param_ipsec_decrypt_bits { - u8 ipsec_object_id[0x20]; -}; - -struct mlx5_ifc_stc_ste_param_trailer_bits { - u8 reserved_at_0[0x8]; - u8 command[0x4]; - u8 reserved_at_c[0x2]; - u8 type[0x2]; - u8 reserved_at_10[0xa]; - u8 length[0x6]; -}; - -struct mlx5_ifc_stc_ste_param_header_modify_list_bits { - u8 header_modify_pattern_id[0x20]; - u8 header_modify_argument_id[0x20]; -}; - -enum mlx5_ifc_header_anchors { - MLX5_HEADER_ANCHOR_PACKET_START = 0x0, - MLX5_HEADER_ANCHOR_MAC = 0x1, - MLX5_HEADER_ANCHOR_FIRST_VLAN_START = 0x2, - MLX5_HEADER_ANCHOR_IPV6_IPV4 = 0x07, - MLX5_HEADER_ANCHOR_ESP = 0x08, - MLX5_HEADER_ANCHOR_TCP_UDP = 0x09, - MLX5_HEADER_ANCHOR_TUNNEL_HEADER = 0x0a, - MLX5_HEADER_ANCHOR_INNER_MAC = 0x13, - MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4 = 0x19, - MLX5_HEADER_ANCHOR_INNER_TCP_UDP = 0x1a, - MLX5_HEADER_ANCHOR_L4_PAYLOAD = 0x1b, - MLX5_HEADER_ANCHOR_INNER_L4_PAYLOAD = 0x1c -}; - -struct mlx5_ifc_stc_ste_param_remove_bits { - u8 action_type[0x4]; - u8 decap[0x1]; - u8 reserved_at_5[0x5]; - u8 remove_start_anchor[0x6]; - u8 reserved_at_10[0x2]; - u8 remove_end_anchor[0x6]; - u8 reserved_at_18[0x8]; -}; - -struct mlx5_ifc_stc_ste_param_remove_words_bits { - u8 action_type[0x4]; - u8 reserved_at_4[0x6]; - u8 remove_start_anchor[0x6]; - u8 reserved_at_10[0x1]; - u8 remove_offset[0x7]; - u8 reserved_at_18[0x2]; - u8 remove_size[0x6]; -}; - -struct mlx5_ifc_stc_ste_param_insert_bits { - u8 action_type[0x4]; - u8 encap[0x1]; - u8 inline_data[0x1]; - u8 reserved_at_6[0x4]; - u8 insert_anchor[0x6]; - u8 reserved_at_10[0x1]; - u8 insert_offset[0x7]; - u8 reserved_at_18[0x1]; - u8 insert_size[0x7]; - u8 insert_argument[0x20]; -}; - -struct mlx5_ifc_stc_ste_param_vport_bits { - u8 eswitch_owner_vhca_id[0x10]; - u8 vport_number[0x10]; - u8 eswitch_owner_vhca_id_valid[0x1]; - u8 reserved_at_21[0x5f]; -}; - -union mlx5_ifc_stc_param_bits { - struct mlx5_ifc_stc_ste_param_ste_table_bits ste_table; - struct mlx5_ifc_stc_ste_param_tir_bits tir; - struct mlx5_ifc_stc_ste_param_table_bits table; - struct mlx5_ifc_stc_ste_param_flow_counter_bits counter; - struct mlx5_ifc_stc_ste_param_header_modify_list_bits modify_header; - struct mlx5_ifc_stc_ste_param_execute_aso_bits aso; - struct mlx5_ifc_stc_ste_param_remove_bits remove_header; - struct mlx5_ifc_stc_ste_param_insert_bits insert_header; - struct mlx5_ifc_set_action_in_bits add; - struct mlx5_ifc_set_action_in_bits set; - struct mlx5_ifc_copy_action_in_bits copy; - struct mlx5_ifc_stc_ste_param_vport_bits vport; - struct mlx5_ifc_stc_ste_param_ipsec_encrypt_bits ipsec_encrypt; - struct mlx5_ifc_stc_ste_param_ipsec_decrypt_bits ipsec_decrypt; - struct mlx5_ifc_stc_ste_param_trailer_bits trailer; - u8 reserved_at_0[0x80]; -}; - -enum { - MLX5_IFC_MODIFY_STC_FIELD_SELECT_NEW_STC = BIT(0), -}; - -struct mlx5_ifc_stc_bits { - u8 modify_field_select[0x40]; - u8 reserved_at_40[0x46]; - u8 reparse_mode[0x2]; - u8 table_type[0x8]; - u8 ste_action_offset[0x8]; - u8 action_type[0x8]; - u8 reserved_at_a0[0x60]; - union mlx5_ifc_stc_param_bits stc_param; - u8 reserved_at_180[0x280]; -}; - -struct mlx5_ifc_ste_bits { - u8 modify_field_select[0x40]; - u8 reserved_at_40[0x48]; - u8 table_type[0x8]; - u8 reserved_at_90[0x370]; -}; - -struct mlx5_ifc_definer_bits { - u8 modify_field_select[0x40]; - u8 reserved_at_40[0x50]; - u8 format_id[0x10]; - u8 reserved_at_60[0x60]; - u8 format_select_dw3[0x8]; - u8 format_select_dw2[0x8]; - u8 format_select_dw1[0x8]; - u8 format_select_dw0[0x8]; - u8 format_select_dw7[0x8]; - u8 format_select_dw6[0x8]; - u8 format_select_dw5[0x8]; - u8 format_select_dw4[0x8]; - u8 reserved_at_100[0x18]; - u8 format_select_dw8[0x8]; - u8 reserved_at_120[0x20]; - u8 format_select_byte3[0x8]; - u8 format_select_byte2[0x8]; - u8 format_select_byte1[0x8]; - u8 format_select_byte0[0x8]; - u8 format_select_byte7[0x8]; - u8 format_select_byte6[0x8]; - u8 format_select_byte5[0x8]; - u8 format_select_byte4[0x8]; - u8 reserved_at_180[0x40]; - u8 ctrl[0xa0]; - u8 match_mask[0x160]; -}; - -struct mlx5_ifc_arg_bits { - u8 rsvd0[0x88]; - u8 access_pd[0x18]; -}; - -struct mlx5_ifc_header_modify_pattern_in_bits { - u8 modify_field_select[0x40]; - - u8 reserved_at_40[0x40]; - - u8 pattern_length[0x8]; - u8 reserved_at_88[0x18]; - - u8 reserved_at_a0[0x60]; - - u8 pattern_data[MLX5_MAX_ACTIONS_DATA_IN_HEADER_MODIFY * 8]; -}; - -struct mlx5_ifc_create_rtc_in_bits { - struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; - struct mlx5_ifc_rtc_bits rtc; -}; - -struct mlx5_ifc_create_stc_in_bits { - struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; - struct mlx5_ifc_stc_bits stc; -}; - -struct mlx5_ifc_create_ste_in_bits { - struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; - struct mlx5_ifc_ste_bits ste; -}; - -struct mlx5_ifc_create_definer_in_bits { - struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; - struct mlx5_ifc_definer_bits definer; -}; - -struct mlx5_ifc_create_arg_in_bits { - struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; - struct mlx5_ifc_arg_bits arg; -}; - -struct mlx5_ifc_create_header_modify_pattern_in_bits { - struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; - struct mlx5_ifc_header_modify_pattern_in_bits pattern; -}; - -struct mlx5_ifc_generate_wqe_in_bits { - u8 opcode[0x10]; - u8 uid[0x10]; - u8 reserved_at_20[0x10]; - u8 op_mode[0x10]; - u8 reserved_at_40[0x40]; - u8 reserved_at_80[0x8]; - u8 pdn[0x18]; - u8 reserved_at_a0[0x160]; - u8 wqe_ctrl[0x80]; - u8 wqe_gta_ctrl[0x180]; - u8 wqe_gta_data_0[0x200]; - u8 wqe_gta_data_1[0x200]; -}; - -struct mlx5_ifc_generate_wqe_out_bits { - u8 status[0x8]; - u8 reserved_at_8[0x18]; - u8 syndrome[0x20]; - u8 reserved_at_40[0x1c0]; - u8 cqe_data[0x200]; -}; - -enum mlx5_access_aso_opc_mod { - ASO_OPC_MOD_IPSEC = 0x0, - ASO_OPC_MOD_CONNECTION_TRACKING = 0x1, - ASO_OPC_MOD_POLICER = 0x2, - ASO_OPC_MOD_RACE_AVOIDANCE = 0x3, - ASO_OPC_MOD_FLOW_HIT = 0x4, -}; - -enum { - MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION = BIT(0), - MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID = BIT(1), -}; - -enum { - MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_DEFAULT = 0, - MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL = 1, -}; - -struct mlx5_ifc_alloc_packet_reformat_out_bits { - u8 status[0x8]; - u8 reserved_at_8[0x18]; - - u8 syndrome[0x20]; - - u8 packet_reformat_id[0x20]; - - u8 reserved_at_60[0x20]; -}; - -struct mlx5_ifc_dealloc_packet_reformat_in_bits { - u8 opcode[0x10]; - u8 reserved_at_10[0x10]; - - u8 reserved_at_20[0x10]; - u8 op_mod[0x10]; - - u8 packet_reformat_id[0x20]; - - u8 reserved_at_60[0x20]; -}; - -struct mlx5_ifc_dealloc_packet_reformat_out_bits { - u8 status[0x8]; - u8 reserved_at_8[0x18]; - - u8 syndrome[0x20]; - - u8 reserved_at_40[0x40]; -}; - -#endif /* MLX5_PRM_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c deleted file mode 100644 index 8a011b958b431c..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.c +++ /dev/null @@ -1,780 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -static void hws_rule_skip(struct mlx5hws_matcher *matcher, - struct mlx5hws_match_template *mt, - u32 flow_source, - bool *skip_rx, bool *skip_tx) -{ - /* By default FDB rules are added to both RX and TX */ - *skip_rx = false; - *skip_tx = false; - - if (flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT) { - *skip_rx = true; - } else if (flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK) { - *skip_tx = true; - } else { - /* If no flow source was set for current rule, - * check for flow source in matcher attributes. - */ - if (matcher->attr.optimize_flow_src) { - *skip_tx = - matcher->attr.optimize_flow_src == MLX5HWS_MATCHER_FLOW_SRC_WIRE; - *skip_rx = - matcher->attr.optimize_flow_src == MLX5HWS_MATCHER_FLOW_SRC_VPORT; - return; - } - } -} - -static void -hws_rule_update_copy_tag(struct mlx5hws_rule *rule, - struct mlx5hws_wqe_gta_data_seg_ste *wqe_data, - bool is_jumbo) -{ - struct mlx5hws_rule_match_tag *tag; - - if (!mlx5hws_matcher_is_resizable(rule->matcher)) { - tag = &rule->tag; - } else { - struct mlx5hws_wqe_gta_data_seg_ste *data_seg = - (struct mlx5hws_wqe_gta_data_seg_ste *)(void *)rule->resize_info->data_seg; - tag = (struct mlx5hws_rule_match_tag *)(void *)data_seg->action; - } - - if (is_jumbo) - memcpy(wqe_data->jumbo, tag->jumbo, MLX5HWS_JUMBO_TAG_SZ); - else - memcpy(wqe_data->tag, tag->match, MLX5HWS_MATCH_TAG_SZ); -} - -static void hws_rule_init_dep_wqe(struct mlx5hws_send_ring_dep_wqe *dep_wqe, - struct mlx5hws_rule *rule, - struct mlx5hws_match_template *mt, - struct mlx5hws_rule_attr *attr) -{ - struct mlx5hws_matcher *matcher = rule->matcher; - struct mlx5hws_table *tbl = matcher->tbl; - bool skip_rx, skip_tx; - - dep_wqe->rule = rule; - dep_wqe->user_data = attr->user_data; - dep_wqe->direct_index = mlx5hws_matcher_is_insert_by_idx(matcher) ? - attr->rule_idx : 0; - - if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) { - hws_rule_skip(matcher, mt, attr->flow_source, &skip_rx, &skip_tx); - - if (!skip_rx) { - dep_wqe->rtc_0 = matcher->match_ste.rtc_0_id; - dep_wqe->retry_rtc_0 = matcher->col_matcher ? - matcher->col_matcher->match_ste.rtc_0_id : 0; - } else { - dep_wqe->rtc_0 = 0; - dep_wqe->retry_rtc_0 = 0; - } - - if (!skip_tx) { - dep_wqe->rtc_1 = matcher->match_ste.rtc_1_id; - dep_wqe->retry_rtc_1 = matcher->col_matcher ? - matcher->col_matcher->match_ste.rtc_1_id : 0; - } else { - dep_wqe->rtc_1 = 0; - dep_wqe->retry_rtc_1 = 0; - } - } else { - pr_warn("HWS: invalid tbl->type: %d\n", tbl->type); - } -} - -static void hws_rule_move_get_rtc(struct mlx5hws_rule *rule, - struct mlx5hws_send_ste_attr *ste_attr) -{ - struct mlx5hws_matcher *dst_matcher = rule->matcher->resize_dst; - - if (rule->resize_info->rtc_0) { - ste_attr->rtc_0 = dst_matcher->match_ste.rtc_0_id; - ste_attr->retry_rtc_0 = dst_matcher->col_matcher ? - dst_matcher->col_matcher->match_ste.rtc_0_id : 0; - } - if (rule->resize_info->rtc_1) { - ste_attr->rtc_1 = dst_matcher->match_ste.rtc_1_id; - ste_attr->retry_rtc_1 = dst_matcher->col_matcher ? - dst_matcher->col_matcher->match_ste.rtc_1_id : 0; - } -} - -static void hws_rule_gen_comp(struct mlx5hws_send_engine *queue, - struct mlx5hws_rule *rule, - bool err, - void *user_data, - enum mlx5hws_rule_status rule_status_on_succ) -{ - enum mlx5hws_flow_op_status comp_status; - - if (!err) { - comp_status = MLX5HWS_FLOW_OP_SUCCESS; - rule->status = rule_status_on_succ; - } else { - comp_status = MLX5HWS_FLOW_OP_ERROR; - rule->status = MLX5HWS_RULE_STATUS_FAILED; - } - - mlx5hws_send_engine_inc_rule(queue); - mlx5hws_send_engine_gen_comp(queue, user_data, comp_status); -} - -static void -hws_rule_save_resize_info(struct mlx5hws_rule *rule, - struct mlx5hws_send_ste_attr *ste_attr, - bool is_update) -{ - if (!mlx5hws_matcher_is_resizable(rule->matcher)) - return; - - if (likely(!is_update)) { - rule->resize_info = kzalloc(sizeof(*rule->resize_info), GFP_KERNEL); - if (unlikely(!rule->resize_info)) { - pr_warn("HWS: resize info isn't allocated for rule\n"); - return; - } - - rule->resize_info->max_stes = - rule->matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes; - rule->resize_info->action_ste_pool[0] = rule->matcher->action_ste[0].max_stes ? - rule->matcher->action_ste[0].pool : - NULL; - rule->resize_info->action_ste_pool[1] = rule->matcher->action_ste[1].max_stes ? - rule->matcher->action_ste[1].pool : - NULL; - } - - memcpy(rule->resize_info->ctrl_seg, ste_attr->wqe_ctrl, - sizeof(rule->resize_info->ctrl_seg)); - memcpy(rule->resize_info->data_seg, ste_attr->wqe_data, - sizeof(rule->resize_info->data_seg)); -} - -void mlx5hws_rule_clear_resize_info(struct mlx5hws_rule *rule) -{ - if (mlx5hws_matcher_is_resizable(rule->matcher) && - rule->resize_info) { - kfree(rule->resize_info); - rule->resize_info = NULL; - } -} - -static void -hws_rule_save_delete_info(struct mlx5hws_rule *rule, - struct mlx5hws_send_ste_attr *ste_attr) -{ - struct mlx5hws_match_template *mt = rule->matcher->mt; - bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); - - if (mlx5hws_matcher_is_resizable(rule->matcher)) - return; - - if (is_jumbo) - memcpy(&rule->tag.jumbo, ste_attr->wqe_data->jumbo, MLX5HWS_JUMBO_TAG_SZ); - else - memcpy(&rule->tag.match, ste_attr->wqe_data->tag, MLX5HWS_MATCH_TAG_SZ); -} - -static void -hws_rule_clear_delete_info(struct mlx5hws_rule *rule) -{ - /* nothing to do here */ -} - -static void -hws_rule_load_delete_info(struct mlx5hws_rule *rule, - struct mlx5hws_send_ste_attr *ste_attr) -{ - if (unlikely(!mlx5hws_matcher_is_resizable(rule->matcher))) { - ste_attr->wqe_tag = &rule->tag; - } else { - struct mlx5hws_wqe_gta_data_seg_ste *data_seg = - (struct mlx5hws_wqe_gta_data_seg_ste *)(void *)rule->resize_info->data_seg; - struct mlx5hws_rule_match_tag *tag = - (struct mlx5hws_rule_match_tag *)(void *)data_seg->action; - ste_attr->wqe_tag = tag; - } -} - -static int hws_rule_alloc_action_ste_idx(struct mlx5hws_rule *rule, - u8 action_ste_selector) -{ - struct mlx5hws_matcher *matcher = rule->matcher; - struct mlx5hws_matcher_action_ste *action_ste; - struct mlx5hws_pool_chunk ste = {0}; - int ret; - - action_ste = &matcher->action_ste[action_ste_selector]; - ste.order = ilog2(roundup_pow_of_two(action_ste->max_stes)); - ret = mlx5hws_pool_chunk_alloc(action_ste->pool, &ste); - if (unlikely(ret)) { - mlx5hws_err(matcher->tbl->ctx, - "Failed to allocate STE for rule actions"); - return ret; - } - rule->action_ste_idx = ste.offset; - - return 0; -} - -static void hws_rule_free_action_ste_idx(struct mlx5hws_rule *rule, - u8 action_ste_selector) -{ - struct mlx5hws_matcher *matcher = rule->matcher; - struct mlx5hws_pool_chunk ste = {0}; - struct mlx5hws_pool *pool; - u8 max_stes; - - if (mlx5hws_matcher_is_resizable(matcher)) { - /* Free the original action pool if rule was resized */ - max_stes = rule->resize_info->max_stes; - pool = rule->resize_info->action_ste_pool[action_ste_selector]; - } else { - max_stes = matcher->action_ste[action_ste_selector].max_stes; - pool = matcher->action_ste[action_ste_selector].pool; - } - - /* This release is safe only when the rule match part was deleted */ - ste.order = ilog2(roundup_pow_of_two(max_stes)); - ste.offset = rule->action_ste_idx; - - mlx5hws_pool_chunk_free(pool, &ste); -} - -static int hws_rule_alloc_action_ste(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - int action_ste_idx; - int ret; - - ret = hws_rule_alloc_action_ste_idx(rule, 0); - if (unlikely(ret)) - return ret; - - action_ste_idx = rule->action_ste_idx; - - ret = hws_rule_alloc_action_ste_idx(rule, 1); - if (unlikely(ret)) { - hws_rule_free_action_ste_idx(rule, 0); - return ret; - } - - /* Both pools have to return the same index */ - if (unlikely(rule->action_ste_idx != action_ste_idx)) { - pr_warn("HWS: allocation of action STE failed - pool indexes mismatch\n"); - return -EINVAL; - } - - return 0; -} - -void mlx5hws_rule_free_action_ste(struct mlx5hws_rule *rule) -{ - if (rule->action_ste_idx > -1) { - hws_rule_free_action_ste_idx(rule, 1); - hws_rule_free_action_ste_idx(rule, 0); - } -} - -static void hws_rule_create_init(struct mlx5hws_rule *rule, - struct mlx5hws_send_ste_attr *ste_attr, - struct mlx5hws_actions_apply_data *apply, - bool is_update) -{ - struct mlx5hws_matcher *matcher = rule->matcher; - struct mlx5hws_table *tbl = matcher->tbl; - struct mlx5hws_context *ctx = tbl->ctx; - - /* Init rule before reuse */ - if (!is_update) { - /* In update we use these rtc's */ - rule->rtc_0 = 0; - rule->rtc_1 = 0; - rule->action_ste_selector = 0; - } else { - rule->action_ste_selector = !rule->action_ste_selector; - } - - rule->pending_wqes = 0; - rule->action_ste_idx = -1; - rule->status = MLX5HWS_RULE_STATUS_CREATING; - - /* Init default send STE attributes */ - ste_attr->gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; - ste_attr->send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; - ste_attr->send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; - ste_attr->send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; - - /* Init default action apply */ - apply->tbl_type = tbl->type; - apply->common_res = &ctx->common_res[tbl->type]; - apply->jump_to_action_stc = matcher->action_ste[0].stc.offset; - apply->require_dep = 0; -} - -static void hws_rule_move_init(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - /* Save the old RTC IDs to be later used in match STE delete */ - rule->resize_info->rtc_0 = rule->rtc_0; - rule->resize_info->rtc_1 = rule->rtc_1; - rule->resize_info->rule_idx = attr->rule_idx; - - rule->rtc_0 = 0; - rule->rtc_1 = 0; - - rule->pending_wqes = 0; - rule->action_ste_idx = -1; - rule->action_ste_selector = 0; - rule->status = MLX5HWS_RULE_STATUS_CREATING; - rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_WRITING; -} - -bool mlx5hws_rule_move_in_progress(struct mlx5hws_rule *rule) -{ - return mlx5hws_matcher_is_in_resize(rule->matcher) && - rule->resize_info && - rule->resize_info->state != MLX5HWS_RULE_RESIZE_STATE_IDLE; -} - -static int hws_rule_create_hws(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr, - u8 mt_idx, - u32 *match_param, - u8 at_idx, - struct mlx5hws_rule_action rule_actions[]) -{ - struct mlx5hws_action_template *at = &rule->matcher->at[at_idx]; - struct mlx5hws_match_template *mt = &rule->matcher->mt[mt_idx]; - bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); - struct mlx5hws_matcher *matcher = rule->matcher; - struct mlx5hws_context *ctx = matcher->tbl->ctx; - struct mlx5hws_send_ste_attr ste_attr = {0}; - struct mlx5hws_send_ring_dep_wqe *dep_wqe; - struct mlx5hws_actions_wqe_setter *setter; - struct mlx5hws_actions_apply_data apply; - struct mlx5hws_send_engine *queue; - u8 total_stes, action_stes; - bool is_update; - int i, ret; - - is_update = !match_param; - - setter = &at->setters[at->num_of_action_stes]; - total_stes = at->num_of_action_stes + (is_jumbo && !at->only_term); - action_stes = total_stes - 1; - - queue = &ctx->send_queue[attr->queue_id]; - if (unlikely(mlx5hws_send_engine_err(queue))) - return -EIO; - - hws_rule_create_init(rule, &ste_attr, &apply, is_update); - - /* Allocate dependent match WQE since rule might have dependent writes. - * The queued dependent WQE can be later aborted or kept as a dependency. - * dep_wqe buffers (ctrl, data) are also reused for all STE writes. - */ - dep_wqe = mlx5hws_send_add_new_dep_wqe(queue); - hws_rule_init_dep_wqe(dep_wqe, rule, mt, attr); - - ste_attr.wqe_ctrl = &dep_wqe->wqe_ctrl; - ste_attr.wqe_data = &dep_wqe->wqe_data; - apply.wqe_ctrl = &dep_wqe->wqe_ctrl; - apply.wqe_data = (__force __be32 *)&dep_wqe->wqe_data; - apply.rule_action = rule_actions; - apply.queue = queue; - - if (action_stes) { - /* Allocate action STEs for rules that need more than match STE */ - if (!is_update) { - ret = hws_rule_alloc_action_ste(rule, attr); - if (ret) { - mlx5hws_err(ctx, "Failed to allocate action memory %d", ret); - mlx5hws_send_abort_new_dep_wqe(queue); - return ret; - } - } - /* Skip RX/TX based on the dep_wqe init */ - ste_attr.rtc_0 = dep_wqe->rtc_0 ? - matcher->action_ste[rule->action_ste_selector].rtc_0_id : 0; - ste_attr.rtc_1 = dep_wqe->rtc_1 ? - matcher->action_ste[rule->action_ste_selector].rtc_1_id : 0; - /* Action STEs are written to a specific index last to first */ - ste_attr.direct_index = rule->action_ste_idx + action_stes; - apply.next_direct_idx = ste_attr.direct_index; - } else { - apply.next_direct_idx = 0; - } - - for (i = total_stes; i-- > 0;) { - mlx5hws_action_apply_setter(&apply, setter--, !i && is_jumbo); - - if (i == 0) { - /* Handle last match STE. - * For hash split / linear lookup RTCs, packets reaching any STE - * will always match and perform the specified actions, which - * makes the tag irrelevant. - */ - if (likely(!mlx5hws_matcher_is_insert_by_idx(matcher) && !is_update)) - mlx5hws_definer_create_tag(match_param, mt->fc, mt->fc_sz, - (u8 *)dep_wqe->wqe_data.action); - else if (is_update) - hws_rule_update_copy_tag(rule, &dep_wqe->wqe_data, is_jumbo); - - /* Rule has dependent WQEs, match dep_wqe is queued */ - if (action_stes || apply.require_dep) - break; - - /* Rule has no dependencies, abort dep_wqe and send WQE now */ - mlx5hws_send_abort_new_dep_wqe(queue); - ste_attr.wqe_tag_is_jumbo = is_jumbo; - ste_attr.send_attr.notify_hw = !attr->burst; - ste_attr.send_attr.user_data = dep_wqe->user_data; - ste_attr.send_attr.rule = dep_wqe->rule; - ste_attr.rtc_0 = dep_wqe->rtc_0; - ste_attr.rtc_1 = dep_wqe->rtc_1; - ste_attr.used_id_rtc_0 = &rule->rtc_0; - ste_attr.used_id_rtc_1 = &rule->rtc_1; - ste_attr.retry_rtc_0 = dep_wqe->retry_rtc_0; - ste_attr.retry_rtc_1 = dep_wqe->retry_rtc_1; - ste_attr.direct_index = dep_wqe->direct_index; - } else { - apply.next_direct_idx = --ste_attr.direct_index; - } - - mlx5hws_send_ste(queue, &ste_attr); - } - - /* Backup TAG on the rule for deletion and resize info for - * moving rules to a new matcher, only after insertion. - */ - if (!is_update) - hws_rule_save_delete_info(rule, &ste_attr); - - hws_rule_save_resize_info(rule, &ste_attr, is_update); - mlx5hws_send_engine_inc_rule(queue); - - if (!attr->burst) - mlx5hws_send_all_dep_wqe(queue); - - return 0; -} - -static void hws_rule_destroy_failed_hws(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; - struct mlx5hws_send_engine *queue; - - queue = &ctx->send_queue[attr->queue_id]; - - hws_rule_gen_comp(queue, rule, false, - attr->user_data, MLX5HWS_RULE_STATUS_DELETED); - - /* Rule failed now we can safely release action STEs */ - mlx5hws_rule_free_action_ste(rule); - - /* Clear complex tag */ - hws_rule_clear_delete_info(rule); - - /* Clear info that was saved for resizing */ - mlx5hws_rule_clear_resize_info(rule); - - /* If a rule that was indicated as burst (need to trigger HW) has failed - * insertion we won't ring the HW as nothing is being written to the WQ. - * In such case update the last WQE and ring the HW with that work - */ - if (attr->burst) - return; - - mlx5hws_send_all_dep_wqe(queue); - mlx5hws_send_engine_flush_queue(queue); -} - -static int hws_rule_destroy_hws(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); - struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; - struct mlx5hws_matcher *matcher = rule->matcher; - struct mlx5hws_wqe_gta_ctrl_seg wqe_ctrl = {0}; - struct mlx5hws_send_ste_attr ste_attr = {0}; - struct mlx5hws_send_engine *queue; - - queue = &ctx->send_queue[attr->queue_id]; - - if (unlikely(mlx5hws_send_engine_err(queue))) { - hws_rule_destroy_failed_hws(rule, attr); - return 0; - } - - /* Rule is not completed yet */ - if (rule->status == MLX5HWS_RULE_STATUS_CREATING) - return -EBUSY; - - /* Rule failed and doesn't require cleanup */ - if (rule->status == MLX5HWS_RULE_STATUS_FAILED) { - hws_rule_destroy_failed_hws(rule, attr); - return 0; - } - - if (rule->skip_delete) { - /* Rule shouldn't be deleted in HW. - * Generate completion as if write succeeded, and we can - * safely release action STEs and clear resize info. - */ - hws_rule_gen_comp(queue, rule, false, - attr->user_data, MLX5HWS_RULE_STATUS_DELETED); - - mlx5hws_rule_free_action_ste(rule); - mlx5hws_rule_clear_resize_info(rule); - return 0; - } - - mlx5hws_send_engine_inc_rule(queue); - - /* Send dependent WQE */ - if (!attr->burst) - mlx5hws_send_all_dep_wqe(queue); - - rule->status = MLX5HWS_RULE_STATUS_DELETING; - - ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; - ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; - ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; - - ste_attr.send_attr.rule = rule; - ste_attr.send_attr.notify_hw = !attr->burst; - ste_attr.send_attr.user_data = attr->user_data; - - ste_attr.rtc_0 = rule->rtc_0; - ste_attr.rtc_1 = rule->rtc_1; - ste_attr.used_id_rtc_0 = &rule->rtc_0; - ste_attr.used_id_rtc_1 = &rule->rtc_1; - ste_attr.wqe_ctrl = &wqe_ctrl; - ste_attr.wqe_tag_is_jumbo = is_jumbo; - ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_DEACTIVATE; - if (unlikely(mlx5hws_matcher_is_insert_by_idx(matcher))) - ste_attr.direct_index = attr->rule_idx; - - hws_rule_load_delete_info(rule, &ste_attr); - mlx5hws_send_ste(queue, &ste_attr); - hws_rule_clear_delete_info(rule); - - return 0; -} - -static int hws_rule_enqueue_precheck(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; - - if (unlikely(!attr->user_data)) - return -EINVAL; - - /* Check if there is room in queue */ - if (unlikely(mlx5hws_send_engine_full(&ctx->send_queue[attr->queue_id]))) - return -EBUSY; - - return 0; -} - -static int hws_rule_enqueue_precheck_move(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - if (unlikely(rule->status != MLX5HWS_RULE_STATUS_CREATED)) - return -EINVAL; - - return hws_rule_enqueue_precheck(rule, attr); -} - -static int hws_rule_enqueue_precheck_create(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - if (unlikely(mlx5hws_matcher_is_in_resize(rule->matcher))) - /* Matcher in resize - new rules are not allowed */ - return -EAGAIN; - - return hws_rule_enqueue_precheck(rule, attr); -} - -static int hws_rule_enqueue_precheck_update(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - struct mlx5hws_matcher *matcher = rule->matcher; - - if (unlikely(!mlx5hws_matcher_is_resizable(rule->matcher) && - !matcher->attr.optimize_using_rule_idx && - !mlx5hws_matcher_is_insert_by_idx(matcher))) { - return -EOPNOTSUPP; - } - - if (unlikely(rule->status != MLX5HWS_RULE_STATUS_CREATED)) - return -EBUSY; - - return hws_rule_enqueue_precheck_create(rule, attr); -} - -int mlx5hws_rule_move_hws_remove(struct mlx5hws_rule *rule, - void *queue_ptr, - void *user_data) -{ - bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); - struct mlx5hws_wqe_gta_ctrl_seg empty_wqe_ctrl = {0}; - struct mlx5hws_matcher *matcher = rule->matcher; - struct mlx5hws_send_engine *queue = queue_ptr; - struct mlx5hws_send_ste_attr ste_attr = {0}; - - mlx5hws_send_all_dep_wqe(queue); - - rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_DELETING; - - ste_attr.send_attr.fence = 0; - ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; - ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; - ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; - ste_attr.send_attr.rule = rule; - ste_attr.send_attr.notify_hw = 1; - ste_attr.send_attr.user_data = user_data; - ste_attr.rtc_0 = rule->resize_info->rtc_0; - ste_attr.rtc_1 = rule->resize_info->rtc_1; - ste_attr.used_id_rtc_0 = &rule->resize_info->rtc_0; - ste_attr.used_id_rtc_1 = &rule->resize_info->rtc_1; - ste_attr.wqe_ctrl = &empty_wqe_ctrl; - ste_attr.wqe_tag_is_jumbo = is_jumbo; - ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_DEACTIVATE; - - if (unlikely(mlx5hws_matcher_is_insert_by_idx(matcher))) - ste_attr.direct_index = rule->resize_info->rule_idx; - - hws_rule_load_delete_info(rule, &ste_attr); - mlx5hws_send_ste(queue, &ste_attr); - - return 0; -} - -int mlx5hws_rule_move_hws_add(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); - struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; - struct mlx5hws_matcher *matcher = rule->matcher; - struct mlx5hws_send_ste_attr ste_attr = {0}; - struct mlx5hws_send_engine *queue; - int ret; - - ret = hws_rule_enqueue_precheck_move(rule, attr); - if (unlikely(ret)) - return ret; - - queue = &ctx->send_queue[attr->queue_id]; - - ret = mlx5hws_send_engine_err(queue); - if (ret) - return ret; - - hws_rule_move_init(rule, attr); - hws_rule_move_get_rtc(rule, &ste_attr); - - ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; - ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; - ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; - ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; - ste_attr.wqe_tag_is_jumbo = is_jumbo; - - ste_attr.send_attr.rule = rule; - ste_attr.send_attr.fence = 0; - ste_attr.send_attr.notify_hw = !attr->burst; - ste_attr.send_attr.user_data = attr->user_data; - - ste_attr.used_id_rtc_0 = &rule->rtc_0; - ste_attr.used_id_rtc_1 = &rule->rtc_1; - ste_attr.wqe_ctrl = (struct mlx5hws_wqe_gta_ctrl_seg *)rule->resize_info->ctrl_seg; - ste_attr.wqe_data = (struct mlx5hws_wqe_gta_data_seg_ste *)rule->resize_info->data_seg; - ste_attr.direct_index = mlx5hws_matcher_is_insert_by_idx(matcher) ? - attr->rule_idx : 0; - - mlx5hws_send_ste(queue, &ste_attr); - mlx5hws_send_engine_inc_rule(queue); - - if (!attr->burst) - mlx5hws_send_all_dep_wqe(queue); - - return 0; -} - -int mlx5hws_rule_create(struct mlx5hws_matcher *matcher, - u8 mt_idx, - u32 *match_param, - u8 at_idx, - struct mlx5hws_rule_action rule_actions[], - struct mlx5hws_rule_attr *attr, - struct mlx5hws_rule *rule_handle) -{ - int ret; - - rule_handle->matcher = matcher; - - ret = hws_rule_enqueue_precheck_create(rule_handle, attr); - if (unlikely(ret)) - return ret; - - if (unlikely(!(matcher->num_of_mt >= mt_idx) || - !(matcher->num_of_at >= at_idx) || - !match_param)) { - pr_warn("HWS: Invalid rule creation parameters (MTs, ATs or match params)\n"); - return -EINVAL; - } - - ret = hws_rule_create_hws(rule_handle, - attr, - mt_idx, - match_param, - at_idx, - rule_actions); - - return ret; -} - -int mlx5hws_rule_destroy(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr) -{ - int ret; - - ret = hws_rule_enqueue_precheck(rule, attr); - if (unlikely(ret)) - return ret; - - ret = hws_rule_destroy_hws(rule, attr); - - return ret; -} - -int mlx5hws_rule_action_update(struct mlx5hws_rule *rule, - u8 at_idx, - struct mlx5hws_rule_action rule_actions[], - struct mlx5hws_rule_attr *attr) -{ - int ret; - - ret = hws_rule_enqueue_precheck_update(rule, attr); - if (unlikely(ret)) - return ret; - - ret = hws_rule_create_hws(rule, - attr, - 0, - NULL, - at_idx, - rule_actions); - - return ret; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h deleted file mode 100644 index 495cdd17e9f3cb..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_rule.h +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_RULE_H_ -#define MLX5HWS_RULE_H_ - -enum { - MLX5HWS_STE_CTRL_SZ = 20, - MLX5HWS_ACTIONS_SZ = 12, - MLX5HWS_MATCH_TAG_SZ = 32, - MLX5HWS_JUMBO_TAG_SZ = 44, -}; - -enum mlx5hws_rule_status { - MLX5HWS_RULE_STATUS_UNKNOWN, - MLX5HWS_RULE_STATUS_CREATING, - MLX5HWS_RULE_STATUS_CREATED, - MLX5HWS_RULE_STATUS_DELETING, - MLX5HWS_RULE_STATUS_DELETED, - MLX5HWS_RULE_STATUS_FAILING, - MLX5HWS_RULE_STATUS_FAILED, -}; - -enum mlx5hws_rule_move_state { - MLX5HWS_RULE_RESIZE_STATE_IDLE, - MLX5HWS_RULE_RESIZE_STATE_WRITING, - MLX5HWS_RULE_RESIZE_STATE_DELETING, -}; - -enum mlx5hws_rule_jumbo_match_tag_offset { - MLX5HWS_RULE_JUMBO_MATCH_TAG_OFFSET_DW0 = 8, -}; - -struct mlx5hws_rule_match_tag { - union { - u8 jumbo[MLX5HWS_JUMBO_TAG_SZ]; - struct { - u8 reserved[MLX5HWS_ACTIONS_SZ]; - u8 match[MLX5HWS_MATCH_TAG_SZ]; - }; - }; -}; - -struct mlx5hws_rule_resize_info { - struct mlx5hws_pool *action_ste_pool[2]; - u32 rtc_0; - u32 rtc_1; - u32 rule_idx; - u8 state; - u8 max_stes; - u8 ctrl_seg[MLX5HWS_WQE_SZ_GTA_CTRL]; /* Ctrl segment of STE: 48 bytes */ - u8 data_seg[MLX5HWS_WQE_SZ_GTA_DATA]; /* Data segment of STE: 64 bytes */ -}; - -struct mlx5hws_rule { - struct mlx5hws_matcher *matcher; - union { - struct mlx5hws_rule_match_tag tag; - struct mlx5hws_rule_resize_info *resize_info; - }; - u32 rtc_0; /* The RTC into which the STE was inserted */ - u32 rtc_1; /* The RTC into which the STE was inserted */ - int action_ste_idx; /* STE array index */ - u8 status; /* enum mlx5hws_rule_status */ - u8 action_ste_selector; /* For rule update - which action STE is in use */ - u8 pending_wqes; - bool skip_delete; /* For complex rules - another rule with same tag - * still exists, so don't actually delete this rule. - */ -}; - -void mlx5hws_rule_free_action_ste(struct mlx5hws_rule *rule); - -int mlx5hws_rule_move_hws_remove(struct mlx5hws_rule *rule, - void *queue, void *user_data); - -int mlx5hws_rule_move_hws_add(struct mlx5hws_rule *rule, - struct mlx5hws_rule_attr *attr); - -bool mlx5hws_rule_move_in_progress(struct mlx5hws_rule *rule); - -void mlx5hws_rule_clear_resize_info(struct mlx5hws_rule *rule); - -#endif /* MLX5HWS_RULE_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c deleted file mode 100644 index 6d443e6ee8d9e9..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.c +++ /dev/null @@ -1,1231 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" -#include "lib/clock.h" - -enum { CQ_OK = 0, CQ_EMPTY = -1, CQ_POLL_ERR = -2 }; - -struct mlx5hws_send_ring_dep_wqe * -mlx5hws_send_add_new_dep_wqe(struct mlx5hws_send_engine *queue) -{ - struct mlx5hws_send_ring_sq *send_sq = &queue->send_ring.send_sq; - unsigned int idx = send_sq->head_dep_idx++ & (queue->num_entries - 1); - - memset(&send_sq->dep_wqe[idx].wqe_data.tag, 0, MLX5HWS_MATCH_TAG_SZ); - - return &send_sq->dep_wqe[idx]; -} - -void mlx5hws_send_abort_new_dep_wqe(struct mlx5hws_send_engine *queue) -{ - queue->send_ring.send_sq.head_dep_idx--; -} - -void mlx5hws_send_all_dep_wqe(struct mlx5hws_send_engine *queue) -{ - struct mlx5hws_send_ring_sq *send_sq = &queue->send_ring.send_sq; - struct mlx5hws_send_ste_attr ste_attr = {0}; - struct mlx5hws_send_ring_dep_wqe *dep_wqe; - - ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; - ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; - ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; - ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; - - /* Fence first from previous depend WQEs */ - ste_attr.send_attr.fence = 1; - - while (send_sq->head_dep_idx != send_sq->tail_dep_idx) { - dep_wqe = &send_sq->dep_wqe[send_sq->tail_dep_idx++ & (queue->num_entries - 1)]; - - /* Notify HW on the last WQE */ - ste_attr.send_attr.notify_hw = (send_sq->tail_dep_idx == send_sq->head_dep_idx); - ste_attr.send_attr.user_data = dep_wqe->user_data; - ste_attr.send_attr.rule = dep_wqe->rule; - - ste_attr.rtc_0 = dep_wqe->rtc_0; - ste_attr.rtc_1 = dep_wqe->rtc_1; - ste_attr.retry_rtc_0 = dep_wqe->retry_rtc_0; - ste_attr.retry_rtc_1 = dep_wqe->retry_rtc_1; - ste_attr.used_id_rtc_0 = &dep_wqe->rule->rtc_0; - ste_attr.used_id_rtc_1 = &dep_wqe->rule->rtc_1; - ste_attr.wqe_ctrl = &dep_wqe->wqe_ctrl; - ste_attr.wqe_data = &dep_wqe->wqe_data; - ste_attr.direct_index = dep_wqe->direct_index; - - mlx5hws_send_ste(queue, &ste_attr); - - /* Fencing is done only on the first WQE */ - ste_attr.send_attr.fence = 0; - } -} - -struct mlx5hws_send_engine_post_ctrl -mlx5hws_send_engine_post_start(struct mlx5hws_send_engine *queue) -{ - struct mlx5hws_send_engine_post_ctrl ctrl; - - ctrl.queue = queue; - /* Currently only one send ring is supported */ - ctrl.send_ring = &queue->send_ring; - ctrl.num_wqebbs = 0; - - return ctrl; -} - -void mlx5hws_send_engine_post_req_wqe(struct mlx5hws_send_engine_post_ctrl *ctrl, - char **buf, size_t *len) -{ - struct mlx5hws_send_ring_sq *send_sq = &ctrl->send_ring->send_sq; - unsigned int idx; - - idx = (send_sq->cur_post + ctrl->num_wqebbs) & send_sq->buf_mask; - - /* Note that *buf is a single MLX5_SEND_WQE_BB. It cannot be used - * as buffer of more than one WQE_BB, since the two MLX5_SEND_WQE_BB - * can be on 2 different kernel memory pages. - */ - *buf = mlx5_wq_cyc_get_wqe(&send_sq->wq, idx); - *len = MLX5_SEND_WQE_BB; - - if (!ctrl->num_wqebbs) { - *buf += sizeof(struct mlx5hws_wqe_ctrl_seg); - *len -= sizeof(struct mlx5hws_wqe_ctrl_seg); - } - - ctrl->num_wqebbs++; -} - -static void hws_send_engine_post_ring(struct mlx5hws_send_ring_sq *sq, - struct mlx5hws_wqe_ctrl_seg *doorbell_cseg) -{ - /* ensure wqe is visible to device before updating doorbell record */ - dma_wmb(); - - *sq->wq.db = cpu_to_be32(sq->cur_post); - - /* ensure doorbell record is visible to device before ringing the - * doorbell - */ - wmb(); - - mlx5_write64((__be32 *)doorbell_cseg, sq->uar_map); - - /* Ensure doorbell is written on uar_page before poll_cq */ - WRITE_ONCE(doorbell_cseg, NULL); -} - -static void -hws_send_wqe_set_tag(struct mlx5hws_wqe_gta_data_seg_ste *wqe_data, - struct mlx5hws_rule_match_tag *tag, - bool is_jumbo) -{ - if (is_jumbo) { - /* Clear previous possibly dirty control */ - memset(wqe_data, 0, MLX5HWS_STE_CTRL_SZ); - memcpy(wqe_data->jumbo, tag->jumbo, MLX5HWS_JUMBO_TAG_SZ); - } else { - /* Clear previous possibly dirty control and actions */ - memset(wqe_data, 0, MLX5HWS_STE_CTRL_SZ + MLX5HWS_ACTIONS_SZ); - memcpy(wqe_data->tag, tag->match, MLX5HWS_MATCH_TAG_SZ); - } -} - -void mlx5hws_send_engine_post_end(struct mlx5hws_send_engine_post_ctrl *ctrl, - struct mlx5hws_send_engine_post_attr *attr) -{ - struct mlx5hws_wqe_ctrl_seg *wqe_ctrl; - struct mlx5hws_send_ring_sq *sq; - unsigned int idx; - u32 flags = 0; - - sq = &ctrl->send_ring->send_sq; - idx = sq->cur_post & sq->buf_mask; - sq->last_idx = idx; - - wqe_ctrl = mlx5_wq_cyc_get_wqe(&sq->wq, idx); - - wqe_ctrl->opmod_idx_opcode = - cpu_to_be32((attr->opmod << 24) | - ((sq->cur_post & 0xffff) << 8) | - attr->opcode); - wqe_ctrl->qpn_ds = - cpu_to_be32((attr->len + sizeof(struct mlx5hws_wqe_ctrl_seg)) / 16 | - sq->sqn << 8); - wqe_ctrl->imm = cpu_to_be32(attr->id); - - flags |= attr->notify_hw ? MLX5_WQE_CTRL_CQ_UPDATE : 0; - flags |= attr->fence ? MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE : 0; - wqe_ctrl->flags = cpu_to_be32(flags); - - sq->wr_priv[idx].id = attr->id; - sq->wr_priv[idx].retry_id = attr->retry_id; - - sq->wr_priv[idx].rule = attr->rule; - sq->wr_priv[idx].user_data = attr->user_data; - sq->wr_priv[idx].num_wqebbs = ctrl->num_wqebbs; - - if (attr->rule) { - sq->wr_priv[idx].rule->pending_wqes++; - sq->wr_priv[idx].used_id = attr->used_id; - } - - sq->cur_post += ctrl->num_wqebbs; - - if (attr->notify_hw) - hws_send_engine_post_ring(sq, wqe_ctrl); -} - -static void hws_send_wqe(struct mlx5hws_send_engine *queue, - struct mlx5hws_send_engine_post_attr *send_attr, - struct mlx5hws_wqe_gta_ctrl_seg *send_wqe_ctrl, - void *send_wqe_data, - void *send_wqe_tag, - bool is_jumbo, - u8 gta_opcode, - u32 direct_index) -{ - struct mlx5hws_wqe_gta_data_seg_ste *wqe_data; - struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; - struct mlx5hws_send_engine_post_ctrl ctrl; - size_t wqe_len; - - ctrl = mlx5hws_send_engine_post_start(queue); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_data, &wqe_len); - - wqe_ctrl->op_dirix = cpu_to_be32(gta_opcode << 28 | direct_index); - memcpy(wqe_ctrl->stc_ix, send_wqe_ctrl->stc_ix, - sizeof(send_wqe_ctrl->stc_ix)); - - if (send_wqe_data) - memcpy(wqe_data, send_wqe_data, sizeof(*wqe_data)); - else - hws_send_wqe_set_tag(wqe_data, send_wqe_tag, is_jumbo); - - mlx5hws_send_engine_post_end(&ctrl, send_attr); -} - -void mlx5hws_send_ste(struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ste_attr *ste_attr) -{ - struct mlx5hws_send_engine_post_attr *send_attr = &ste_attr->send_attr; - u8 notify_hw = send_attr->notify_hw; - u8 fence = send_attr->fence; - - if (ste_attr->rtc_1) { - send_attr->id = ste_attr->rtc_1; - send_attr->used_id = ste_attr->used_id_rtc_1; - send_attr->retry_id = ste_attr->retry_rtc_1; - send_attr->fence = fence; - send_attr->notify_hw = notify_hw && !ste_attr->rtc_0; - hws_send_wqe(queue, send_attr, - ste_attr->wqe_ctrl, - ste_attr->wqe_data, - ste_attr->wqe_tag, - ste_attr->wqe_tag_is_jumbo, - ste_attr->gta_opcode, - ste_attr->direct_index); - } - - if (ste_attr->rtc_0) { - send_attr->id = ste_attr->rtc_0; - send_attr->used_id = ste_attr->used_id_rtc_0; - send_attr->retry_id = ste_attr->retry_rtc_0; - send_attr->fence = fence && !ste_attr->rtc_1; - send_attr->notify_hw = notify_hw; - hws_send_wqe(queue, send_attr, - ste_attr->wqe_ctrl, - ste_attr->wqe_data, - ste_attr->wqe_tag, - ste_attr->wqe_tag_is_jumbo, - ste_attr->gta_opcode, - ste_attr->direct_index); - } - - /* Restore to original requested values */ - send_attr->notify_hw = notify_hw; - send_attr->fence = fence; -} - -static void hws_send_engine_retry_post_send(struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ring_priv *priv, - u16 wqe_cnt) -{ - struct mlx5hws_send_engine_post_attr send_attr = {0}; - struct mlx5hws_wqe_gta_data_seg_ste *wqe_data; - struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; - struct mlx5hws_send_engine_post_ctrl ctrl; - struct mlx5hws_send_ring_sq *send_sq; - unsigned int idx; - size_t wqe_len; - char *p; - - send_attr.rule = priv->rule; - send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; - send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; - send_attr.len = MLX5_SEND_WQE_BB * 2 - sizeof(struct mlx5hws_wqe_ctrl_seg); - send_attr.notify_hw = 1; - send_attr.fence = 0; - send_attr.user_data = priv->user_data; - send_attr.id = priv->retry_id; - send_attr.used_id = priv->used_id; - - ctrl = mlx5hws_send_engine_post_start(queue); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); - mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_data, &wqe_len); - - send_sq = &ctrl.send_ring->send_sq; - idx = wqe_cnt & send_sq->buf_mask; - p = mlx5_wq_cyc_get_wqe(&send_sq->wq, idx); - - /* Copy old gta ctrl */ - memcpy(wqe_ctrl, p + sizeof(struct mlx5hws_wqe_ctrl_seg), - MLX5_SEND_WQE_BB - sizeof(struct mlx5hws_wqe_ctrl_seg)); - - idx = (wqe_cnt + 1) & send_sq->buf_mask; - p = mlx5_wq_cyc_get_wqe(&send_sq->wq, idx); - - /* Copy old gta data */ - memcpy(wqe_data, p, MLX5_SEND_WQE_BB); - - mlx5hws_send_engine_post_end(&ctrl, &send_attr); -} - -void mlx5hws_send_engine_flush_queue(struct mlx5hws_send_engine *queue) -{ - struct mlx5hws_send_ring_sq *sq = &queue->send_ring.send_sq; - struct mlx5hws_wqe_ctrl_seg *wqe_ctrl; - - wqe_ctrl = mlx5_wq_cyc_get_wqe(&sq->wq, sq->last_idx); - wqe_ctrl->flags |= cpu_to_be32(MLX5_WQE_CTRL_CQ_UPDATE); - - hws_send_engine_post_ring(sq, wqe_ctrl); -} - -static void -hws_send_engine_update_rule_resize(struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ring_priv *priv, - enum mlx5hws_flow_op_status *status) -{ - switch (priv->rule->resize_info->state) { - case MLX5HWS_RULE_RESIZE_STATE_WRITING: - if (priv->rule->status == MLX5HWS_RULE_STATUS_FAILING) { - /* Backup original RTCs */ - u32 orig_rtc_0 = priv->rule->resize_info->rtc_0; - u32 orig_rtc_1 = priv->rule->resize_info->rtc_1; - - /* Delete partially failed move rule using resize_info */ - priv->rule->resize_info->rtc_0 = priv->rule->rtc_0; - priv->rule->resize_info->rtc_1 = priv->rule->rtc_1; - - /* Move rule to original RTC for future delete */ - priv->rule->rtc_0 = orig_rtc_0; - priv->rule->rtc_1 = orig_rtc_1; - } - /* Clean leftovers */ - mlx5hws_rule_move_hws_remove(priv->rule, queue, priv->user_data); - break; - - case MLX5HWS_RULE_RESIZE_STATE_DELETING: - if (priv->rule->status == MLX5HWS_RULE_STATUS_FAILING) { - *status = MLX5HWS_FLOW_OP_ERROR; - } else { - *status = MLX5HWS_FLOW_OP_SUCCESS; - priv->rule->matcher = priv->rule->matcher->resize_dst; - } - priv->rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_IDLE; - priv->rule->status = MLX5HWS_RULE_STATUS_CREATED; - break; - - default: - break; - } -} - -static void hws_send_engine_update_rule(struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ring_priv *priv, - u16 wqe_cnt, - enum mlx5hws_flow_op_status *status) -{ - priv->rule->pending_wqes--; - - if (*status == MLX5HWS_FLOW_OP_ERROR) { - if (priv->retry_id) { - hws_send_engine_retry_post_send(queue, priv, wqe_cnt); - return; - } - /* Some part of the rule failed */ - priv->rule->status = MLX5HWS_RULE_STATUS_FAILING; - *priv->used_id = 0; - } else { - *priv->used_id = priv->id; - } - - /* Update rule status for the last completion */ - if (!priv->rule->pending_wqes) { - if (unlikely(mlx5hws_rule_move_in_progress(priv->rule))) { - hws_send_engine_update_rule_resize(queue, priv, status); - return; - } - - if (unlikely(priv->rule->status == MLX5HWS_RULE_STATUS_FAILING)) { - /* Rule completely failed and doesn't require cleanup */ - if (!priv->rule->rtc_0 && !priv->rule->rtc_1) - priv->rule->status = MLX5HWS_RULE_STATUS_FAILED; - - *status = MLX5HWS_FLOW_OP_ERROR; - } else { - /* Increase the status, this only works on good flow as the enum - * is arrange it away creating -> created -> deleting -> deleted - */ - priv->rule->status++; - *status = MLX5HWS_FLOW_OP_SUCCESS; - /* Rule was deleted now we can safely release action STEs - * and clear resize info - */ - if (priv->rule->status == MLX5HWS_RULE_STATUS_DELETED) { - mlx5hws_rule_free_action_ste(priv->rule); - mlx5hws_rule_clear_resize_info(priv->rule); - } - } - } -} - -static void hws_send_engine_update(struct mlx5hws_send_engine *queue, - struct mlx5_cqe64 *cqe, - struct mlx5hws_send_ring_priv *priv, - struct mlx5hws_flow_op_result res[], - s64 *i, - u32 res_nb, - u16 wqe_cnt) -{ - enum mlx5hws_flow_op_status status; - - if (!cqe || (likely(be32_to_cpu(cqe->byte_cnt) >> 31 == 0) && - likely(get_cqe_opcode(cqe) == MLX5_CQE_REQ))) { - status = MLX5HWS_FLOW_OP_SUCCESS; - } else { - status = MLX5HWS_FLOW_OP_ERROR; - } - - if (priv->user_data) { - if (priv->rule) { - hws_send_engine_update_rule(queue, priv, wqe_cnt, &status); - /* Completion is provided on the last rule WQE */ - if (priv->rule->pending_wqes) - return; - } - - if (*i < res_nb) { - res[*i].user_data = priv->user_data; - res[*i].status = status; - (*i)++; - mlx5hws_send_engine_dec_rule(queue); - } else { - mlx5hws_send_engine_gen_comp(queue, priv->user_data, status); - } - } -} - -static int mlx5hws_parse_cqe(struct mlx5hws_send_ring_cq *cq, - struct mlx5_cqe64 *cqe64) -{ - if (unlikely(get_cqe_opcode(cqe64) != MLX5_CQE_REQ)) { - struct mlx5_err_cqe *err_cqe = (struct mlx5_err_cqe *)cqe64; - - mlx5_core_err(cq->mdev, "Bad OP in HWS SQ CQE: 0x%x\n", get_cqe_opcode(cqe64)); - mlx5_core_err(cq->mdev, "vendor_err_synd=%x\n", err_cqe->vendor_err_synd); - mlx5_core_err(cq->mdev, "syndrome=%x\n", err_cqe->syndrome); - print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, - 16, 1, err_cqe, - sizeof(*err_cqe), false); - return CQ_POLL_ERR; - } - - return CQ_OK; -} - -static int mlx5hws_cq_poll_one(struct mlx5hws_send_ring_cq *cq) -{ - struct mlx5_cqe64 *cqe64; - int err; - - cqe64 = mlx5_cqwq_get_cqe(&cq->wq); - if (!cqe64) { - if (unlikely(cq->mdev->state == - MLX5_DEVICE_STATE_INTERNAL_ERROR)) { - mlx5_core_dbg_once(cq->mdev, - "Polling CQ while device is shutting down\n"); - return CQ_POLL_ERR; - } - return CQ_EMPTY; - } - - mlx5_cqwq_pop(&cq->wq); - err = mlx5hws_parse_cqe(cq, cqe64); - mlx5_cqwq_update_db_record(&cq->wq); - - return err; -} - -static void hws_send_engine_poll_cq(struct mlx5hws_send_engine *queue, - struct mlx5hws_flow_op_result res[], - s64 *polled, - u32 res_nb) -{ - struct mlx5hws_send_ring *send_ring = &queue->send_ring; - struct mlx5hws_send_ring_cq *cq = &send_ring->send_cq; - struct mlx5hws_send_ring_sq *sq = &send_ring->send_sq; - struct mlx5hws_send_ring_priv *priv; - struct mlx5_cqe64 *cqe; - u8 cqe_opcode; - u16 wqe_cnt; - - cqe = mlx5_cqwq_get_cqe(&cq->wq); - if (!cqe) - return; - - cqe_opcode = get_cqe_opcode(cqe); - if (cqe_opcode == MLX5_CQE_INVALID) - return; - - if (unlikely(cqe_opcode != MLX5_CQE_REQ)) - queue->err = true; - - wqe_cnt = be16_to_cpu(cqe->wqe_counter) & sq->buf_mask; - - while (cq->poll_wqe != wqe_cnt) { - priv = &sq->wr_priv[cq->poll_wqe]; - hws_send_engine_update(queue, NULL, priv, res, polled, res_nb, 0); - cq->poll_wqe = (cq->poll_wqe + priv->num_wqebbs) & sq->buf_mask; - } - - priv = &sq->wr_priv[wqe_cnt]; - cq->poll_wqe = (wqe_cnt + priv->num_wqebbs) & sq->buf_mask; - hws_send_engine_update(queue, cqe, priv, res, polled, res_nb, wqe_cnt); - mlx5hws_cq_poll_one(cq); -} - -static void hws_send_engine_poll_list(struct mlx5hws_send_engine *queue, - struct mlx5hws_flow_op_result res[], - s64 *polled, - u32 res_nb) -{ - struct mlx5hws_completed_poll *comp = &queue->completed; - - while (comp->ci != comp->pi) { - if (*polled < res_nb) { - res[*polled].status = - comp->entries[comp->ci].status; - res[*polled].user_data = - comp->entries[comp->ci].user_data; - (*polled)++; - comp->ci = (comp->ci + 1) & comp->mask; - mlx5hws_send_engine_dec_rule(queue); - } else { - return; - } - } -} - -static int hws_send_engine_poll(struct mlx5hws_send_engine *queue, - struct mlx5hws_flow_op_result res[], - u32 res_nb) -{ - s64 polled = 0; - - hws_send_engine_poll_list(queue, res, &polled, res_nb); - - if (polled >= res_nb) - return polled; - - hws_send_engine_poll_cq(queue, res, &polled, res_nb); - - return polled; -} - -int mlx5hws_send_queue_poll(struct mlx5hws_context *ctx, - u16 queue_id, - struct mlx5hws_flow_op_result res[], - u32 res_nb) -{ - return hws_send_engine_poll(&ctx->send_queue[queue_id], res, res_nb); -} - -static int hws_send_ring_alloc_sq(struct mlx5_core_dev *mdev, - int numa_node, - struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ring_sq *sq, - void *sqc_data) -{ - void *sqc_wq = MLX5_ADDR_OF(sqc, sqc_data, wq); - struct mlx5_wq_cyc *wq = &sq->wq; - struct mlx5_wq_param param; - size_t buf_sz; - int err; - - sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map; - sq->mdev = mdev; - - param.db_numa_node = numa_node; - param.buf_numa_node = numa_node; - err = mlx5_wq_cyc_create(mdev, ¶m, sqc_wq, wq, &sq->wq_ctrl); - if (err) - return err; - wq->db = &wq->db[MLX5_SND_DBR]; - - buf_sz = queue->num_entries * MAX_WQES_PER_RULE; - sq->dep_wqe = kcalloc(queue->num_entries, sizeof(*sq->dep_wqe), GFP_KERNEL); - if (!sq->dep_wqe) { - err = -ENOMEM; - goto destroy_wq_cyc; - } - - sq->wr_priv = kzalloc(sizeof(*sq->wr_priv) * buf_sz, GFP_KERNEL); - if (!sq->wr_priv) { - err = -ENOMEM; - goto free_dep_wqe; - } - - sq->buf_mask = (queue->num_entries * MAX_WQES_PER_RULE) - 1; - - return 0; - -free_dep_wqe: - kfree(sq->dep_wqe); -destroy_wq_cyc: - mlx5_wq_destroy(&sq->wq_ctrl); - return err; -} - -static void hws_send_ring_free_sq(struct mlx5hws_send_ring_sq *sq) -{ - if (!sq) - return; - kfree(sq->wr_priv); - kfree(sq->dep_wqe); - mlx5_wq_destroy(&sq->wq_ctrl); -} - -static int hws_send_ring_create_sq(struct mlx5_core_dev *mdev, u32 pdn, - void *sqc_data, - struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ring_sq *sq, - struct mlx5hws_send_ring_cq *cq) -{ - void *in, *sqc, *wq; - int inlen, err; - u8 ts_format; - - inlen = MLX5_ST_SZ_BYTES(create_sq_in) + - sizeof(u64) * sq->wq_ctrl.buf.npages; - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - sqc = MLX5_ADDR_OF(create_sq_in, in, ctx); - wq = MLX5_ADDR_OF(sqc, sqc, wq); - - memcpy(sqc, sqc_data, MLX5_ST_SZ_BYTES(sqc)); - MLX5_SET(sqc, sqc, cqn, cq->mcq.cqn); - - MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST); - MLX5_SET(sqc, sqc, flush_in_error_en, 1); - - ts_format = mlx5_is_real_time_sq(mdev) ? MLX5_TIMESTAMP_FORMAT_REAL_TIME : - MLX5_TIMESTAMP_FORMAT_FREE_RUNNING; - MLX5_SET(sqc, sqc, ts_format, ts_format); - - MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC); - MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index); - MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); - MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma); - - mlx5_fill_page_frag_array(&sq->wq_ctrl.buf, - (__be64 *)MLX5_ADDR_OF(wq, wq, pas)); - - err = mlx5_core_create_sq(mdev, in, inlen, &sq->sqn); - - kvfree(in); - - return err; -} - -static void hws_send_ring_destroy_sq(struct mlx5_core_dev *mdev, - struct mlx5hws_send_ring_sq *sq) -{ - mlx5_core_destroy_sq(mdev, sq->sqn); -} - -static int hws_send_ring_set_sq_rdy(struct mlx5_core_dev *mdev, u32 sqn) -{ - void *in, *sqc; - int inlen, err; - - inlen = MLX5_ST_SZ_BYTES(modify_sq_in); - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - MLX5_SET(modify_sq_in, in, sq_state, MLX5_SQC_STATE_RST); - sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); - MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RDY); - - err = mlx5_core_modify_sq(mdev, sqn, in); - - kvfree(in); - - return err; -} - -static void hws_send_ring_close_sq(struct mlx5hws_send_ring_sq *sq) -{ - mlx5_core_destroy_sq(sq->mdev, sq->sqn); - mlx5_wq_destroy(&sq->wq_ctrl); - kfree(sq->wr_priv); - kfree(sq->dep_wqe); -} - -static int hws_send_ring_create_sq_rdy(struct mlx5_core_dev *mdev, u32 pdn, - void *sqc_data, - struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ring_sq *sq, - struct mlx5hws_send_ring_cq *cq) -{ - int err; - - err = hws_send_ring_create_sq(mdev, pdn, sqc_data, queue, sq, cq); - if (err) - return err; - - err = hws_send_ring_set_sq_rdy(mdev, sq->sqn); - if (err) - hws_send_ring_destroy_sq(mdev, sq); - - return err; -} - -static int hws_send_ring_open_sq(struct mlx5hws_context *ctx, - int numa_node, - struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ring_sq *sq, - struct mlx5hws_send_ring_cq *cq) -{ - size_t buf_sz, sq_log_buf_sz; - void *sqc_data, *wq; - int err; - - sqc_data = kvzalloc(MLX5_ST_SZ_BYTES(sqc), GFP_KERNEL); - if (!sqc_data) - return -ENOMEM; - - buf_sz = queue->num_entries * MAX_WQES_PER_RULE; - sq_log_buf_sz = ilog2(roundup_pow_of_two(buf_sz)); - - wq = MLX5_ADDR_OF(sqc, sqc_data, wq); - MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB)); - MLX5_SET(wq, wq, pd, ctx->pd_num); - MLX5_SET(wq, wq, log_wq_sz, sq_log_buf_sz); - - err = hws_send_ring_alloc_sq(ctx->mdev, numa_node, queue, sq, sqc_data); - if (err) - goto err_free_sqc; - - err = hws_send_ring_create_sq_rdy(ctx->mdev, ctx->pd_num, sqc_data, - queue, sq, cq); - if (err) - goto err_free_sq; - - kvfree(sqc_data); - - return 0; -err_free_sq: - hws_send_ring_free_sq(sq); -err_free_sqc: - kvfree(sqc_data); - return err; -} - -static void hws_cq_complete(struct mlx5_core_cq *mcq, - struct mlx5_eqe *eqe) -{ - pr_err("CQ completion CQ: #%u\n", mcq->cqn); -} - -static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev, - int numa_node, - struct mlx5hws_send_engine *queue, - void *cqc_data, - struct mlx5hws_send_ring_cq *cq) -{ - struct mlx5_core_cq *mcq = &cq->mcq; - struct mlx5_wq_param param; - struct mlx5_cqe64 *cqe; - int err; - u32 i; - - param.buf_numa_node = numa_node; - param.db_numa_node = numa_node; - - err = mlx5_cqwq_create(mdev, ¶m, cqc_data, &cq->wq, &cq->wq_ctrl); - if (err) - return err; - - mcq->cqe_sz = 64; - mcq->set_ci_db = cq->wq_ctrl.db.db; - mcq->arm_db = cq->wq_ctrl.db.db + 1; - mcq->comp = hws_cq_complete; - - for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) { - cqe = mlx5_cqwq_get_wqe(&cq->wq, i); - cqe->op_own = 0xf1; - } - - cq->mdev = mdev; - - return 0; -} - -static int hws_send_ring_create_cq(struct mlx5_core_dev *mdev, - struct mlx5hws_send_engine *queue, - void *cqc_data, - struct mlx5hws_send_ring_cq *cq) -{ - u32 out[MLX5_ST_SZ_DW(create_cq_out)]; - struct mlx5_core_cq *mcq = &cq->mcq; - void *in, *cqc; - int inlen, eqn; - int err; - - err = mlx5_comp_eqn_get(mdev, 0, &eqn); - if (err) - return err; - - inlen = MLX5_ST_SZ_BYTES(create_cq_in) + - sizeof(u64) * cq->wq_ctrl.buf.npages; - in = kvzalloc(inlen, GFP_KERNEL); - if (!in) - return -ENOMEM; - - cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); - memcpy(cqc, cqc_data, MLX5_ST_SZ_BYTES(cqc)); - mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, - (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas)); - - MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn); - MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index); - MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); - MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma); - - err = mlx5_core_create_cq(mdev, mcq, in, inlen, out, sizeof(out)); - - kvfree(in); - - return err; -} - -static int hws_send_ring_open_cq(struct mlx5_core_dev *mdev, - struct mlx5hws_send_engine *queue, - int numa_node, - struct mlx5hws_send_ring_cq *cq) -{ - void *cqc_data; - int err; - - cqc_data = kvzalloc(MLX5_ST_SZ_BYTES(cqc), GFP_KERNEL); - if (!cqc_data) - return -ENOMEM; - - MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index); - MLX5_SET(cqc, cqc_data, cqe_sz, queue->num_entries); - MLX5_SET(cqc, cqc_data, log_cq_size, ilog2(queue->num_entries)); - - err = hws_send_ring_alloc_cq(mdev, numa_node, queue, cqc_data, cq); - if (err) - goto err_out; - - err = hws_send_ring_create_cq(mdev, queue, cqc_data, cq); - if (err) - goto err_free_cq; - - kvfree(cqc_data); - - return 0; - -err_free_cq: - mlx5_wq_destroy(&cq->wq_ctrl); -err_out: - kvfree(cqc_data); - return err; -} - -static void hws_send_ring_close_cq(struct mlx5hws_send_ring_cq *cq) -{ - mlx5_core_destroy_cq(cq->mdev, &cq->mcq); - mlx5_wq_destroy(&cq->wq_ctrl); -} - -static void hws_send_ring_close(struct mlx5hws_send_engine *queue) -{ - hws_send_ring_close_sq(&queue->send_ring.send_sq); - hws_send_ring_close_cq(&queue->send_ring.send_cq); -} - -static int mlx5hws_send_ring_open(struct mlx5hws_context *ctx, - struct mlx5hws_send_engine *queue) -{ - int numa_node = dev_to_node(mlx5_core_dma_dev(ctx->mdev)); - struct mlx5hws_send_ring *ring = &queue->send_ring; - int err; - - err = hws_send_ring_open_cq(ctx->mdev, queue, numa_node, &ring->send_cq); - if (err) - return err; - - err = hws_send_ring_open_sq(ctx, numa_node, queue, &ring->send_sq, - &ring->send_cq); - if (err) - goto close_cq; - - return err; - -close_cq: - hws_send_ring_close_cq(&ring->send_cq); - return err; -} - -void mlx5hws_send_queue_close(struct mlx5hws_send_engine *queue) -{ - hws_send_ring_close(queue); - kfree(queue->completed.entries); -} - -int mlx5hws_send_queue_open(struct mlx5hws_context *ctx, - struct mlx5hws_send_engine *queue, - u16 queue_size) -{ - int err; - - mutex_init(&queue->lock); - - queue->num_entries = roundup_pow_of_two(queue_size); - queue->used_entries = 0; - - queue->completed.entries = kcalloc(queue->num_entries, - sizeof(queue->completed.entries[0]), - GFP_KERNEL); - if (!queue->completed.entries) - return -ENOMEM; - - queue->completed.pi = 0; - queue->completed.ci = 0; - queue->completed.mask = queue->num_entries - 1; - err = mlx5hws_send_ring_open(ctx, queue); - if (err) - goto free_completed_entries; - - return 0; - -free_completed_entries: - kfree(queue->completed.entries); - return err; -} - -static void __hws_send_queues_close(struct mlx5hws_context *ctx, u16 queues) -{ - while (queues--) - mlx5hws_send_queue_close(&ctx->send_queue[queues]); -} - -static void hws_send_queues_bwc_locks_destroy(struct mlx5hws_context *ctx) -{ - int bwc_queues = mlx5hws_bwc_queues(ctx); - int i; - - if (!mlx5hws_context_bwc_supported(ctx)) - return; - - for (i = 0; i < bwc_queues; i++) { - mutex_destroy(&ctx->bwc_send_queue_locks[i]); - lockdep_unregister_key(ctx->bwc_lock_class_keys + i); - } - - kfree(ctx->bwc_lock_class_keys); - kfree(ctx->bwc_send_queue_locks); -} - -void mlx5hws_send_queues_close(struct mlx5hws_context *ctx) -{ - hws_send_queues_bwc_locks_destroy(ctx); - __hws_send_queues_close(ctx, ctx->queues); - kfree(ctx->send_queue); -} - -static int hws_bwc_send_queues_init(struct mlx5hws_context *ctx) -{ - /* Number of BWC queues is equal to number of the usual HWS queues */ - int bwc_queues = ctx->queues - 1; - int i; - - if (!mlx5hws_context_bwc_supported(ctx)) - return 0; - - ctx->queues += bwc_queues; - - ctx->bwc_send_queue_locks = kcalloc(bwc_queues, - sizeof(*ctx->bwc_send_queue_locks), - GFP_KERNEL); - - if (!ctx->bwc_send_queue_locks) - return -ENOMEM; - - ctx->bwc_lock_class_keys = kcalloc(bwc_queues, - sizeof(*ctx->bwc_lock_class_keys), - GFP_KERNEL); - if (!ctx->bwc_lock_class_keys) - goto err_lock_class_keys; - - for (i = 0; i < bwc_queues; i++) { - mutex_init(&ctx->bwc_send_queue_locks[i]); - lockdep_register_key(ctx->bwc_lock_class_keys + i); - } - - return 0; - -err_lock_class_keys: - kfree(ctx->bwc_send_queue_locks); - return -ENOMEM; -} - -int mlx5hws_send_queues_open(struct mlx5hws_context *ctx, - u16 queues, - u16 queue_size) -{ - int err = 0; - u32 i; - - /* Open one extra queue for control path */ - ctx->queues = queues + 1; - - /* open a separate set of queues and locks for bwc API */ - err = hws_bwc_send_queues_init(ctx); - if (err) - return err; - - ctx->send_queue = kcalloc(ctx->queues, sizeof(*ctx->send_queue), GFP_KERNEL); - if (!ctx->send_queue) { - err = -ENOMEM; - goto free_bwc_locks; - } - - for (i = 0; i < ctx->queues; i++) { - err = mlx5hws_send_queue_open(ctx, &ctx->send_queue[i], queue_size); - if (err) - goto close_send_queues; - } - - return 0; - -close_send_queues: - __hws_send_queues_close(ctx, i); - - kfree(ctx->send_queue); - -free_bwc_locks: - hws_send_queues_bwc_locks_destroy(ctx); - - return err; -} - -int mlx5hws_send_queue_action(struct mlx5hws_context *ctx, - u16 queue_id, - u32 actions) -{ - struct mlx5hws_send_ring_sq *send_sq; - struct mlx5hws_send_engine *queue; - bool wait_comp = false; - s64 polled = 0; - - queue = &ctx->send_queue[queue_id]; - send_sq = &queue->send_ring.send_sq; - - switch (actions) { - case MLX5HWS_SEND_QUEUE_ACTION_DRAIN_SYNC: - wait_comp = true; - fallthrough; - case MLX5HWS_SEND_QUEUE_ACTION_DRAIN_ASYNC: - if (send_sq->head_dep_idx != send_sq->tail_dep_idx) - /* Send dependent WQEs to drain the queue */ - mlx5hws_send_all_dep_wqe(queue); - else - /* Signal on the last posted WQE */ - mlx5hws_send_engine_flush_queue(queue); - - /* Poll queue until empty */ - while (wait_comp && !mlx5hws_send_engine_empty(queue)) - hws_send_engine_poll_cq(queue, NULL, &polled, 0); - - break; - default: - return -EINVAL; - } - - return 0; -} - -static int -hws_send_wqe_fw(struct mlx5_core_dev *mdev, - u32 pd_num, - struct mlx5hws_send_engine_post_attr *send_attr, - struct mlx5hws_wqe_gta_ctrl_seg *send_wqe_ctrl, - void *send_wqe_match_data, - void *send_wqe_match_tag, - void *send_wqe_range_data, - void *send_wqe_range_tag, - bool is_jumbo, - u8 gta_opcode) -{ - bool has_range = send_wqe_range_data || send_wqe_range_tag; - bool has_match = send_wqe_match_data || send_wqe_match_tag; - struct mlx5hws_wqe_gta_data_seg_ste gta_wqe_data0 = {0}; - struct mlx5hws_wqe_gta_data_seg_ste gta_wqe_data1 = {0}; - struct mlx5hws_wqe_gta_ctrl_seg gta_wqe_ctrl = {0}; - struct mlx5hws_cmd_generate_wqe_attr attr = {0}; - struct mlx5hws_wqe_ctrl_seg wqe_ctrl = {0}; - struct mlx5_cqe64 cqe; - u32 flags = 0; - int ret; - - /* Set WQE control */ - wqe_ctrl.opmod_idx_opcode = cpu_to_be32((send_attr->opmod << 24) | send_attr->opcode); - wqe_ctrl.qpn_ds = cpu_to_be32((send_attr->len + sizeof(struct mlx5hws_wqe_ctrl_seg)) / 16); - flags |= send_attr->notify_hw ? MLX5_WQE_CTRL_CQ_UPDATE : 0; - wqe_ctrl.flags = cpu_to_be32(flags); - wqe_ctrl.imm = cpu_to_be32(send_attr->id); - - /* Set GTA WQE CTRL */ - memcpy(gta_wqe_ctrl.stc_ix, send_wqe_ctrl->stc_ix, sizeof(send_wqe_ctrl->stc_ix)); - gta_wqe_ctrl.op_dirix = cpu_to_be32(gta_opcode << 28); - - /* Set GTA match WQE DATA */ - if (has_match) { - if (send_wqe_match_data) - memcpy(>a_wqe_data0, send_wqe_match_data, sizeof(gta_wqe_data0)); - else - hws_send_wqe_set_tag(>a_wqe_data0, send_wqe_match_tag, is_jumbo); - - gta_wqe_data0.rsvd1_definer = cpu_to_be32(send_attr->match_definer_id << 8); - attr.gta_data_0 = (u8 *)>a_wqe_data0; - } - - /* Set GTA range WQE DATA */ - if (has_range) { - if (send_wqe_range_data) - memcpy(>a_wqe_data1, send_wqe_range_data, sizeof(gta_wqe_data1)); - else - hws_send_wqe_set_tag(>a_wqe_data1, send_wqe_range_tag, false); - - gta_wqe_data1.rsvd1_definer = cpu_to_be32(send_attr->range_definer_id << 8); - attr.gta_data_1 = (u8 *)>a_wqe_data1; - } - - attr.pdn = pd_num; - attr.wqe_ctrl = (u8 *)&wqe_ctrl; - attr.gta_ctrl = (u8 *)>a_wqe_ctrl; - -send_wqe: - ret = mlx5hws_cmd_generate_wqe(mdev, &attr, &cqe); - if (ret) { - mlx5_core_err(mdev, "Failed to write WQE using command"); - return ret; - } - - if ((get_cqe_opcode(&cqe) == MLX5_CQE_REQ) && - (be32_to_cpu(cqe.byte_cnt) >> 31 == 0)) { - *send_attr->used_id = send_attr->id; - return 0; - } - - /* Retry if rule failed */ - if (send_attr->retry_id) { - wqe_ctrl.imm = cpu_to_be32(send_attr->retry_id); - send_attr->id = send_attr->retry_id; - send_attr->retry_id = 0; - goto send_wqe; - } - - return -1; -} - -void mlx5hws_send_stes_fw(struct mlx5hws_context *ctx, - struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ste_attr *ste_attr) -{ - struct mlx5hws_send_engine_post_attr *send_attr = &ste_attr->send_attr; - struct mlx5hws_rule *rule = send_attr->rule; - struct mlx5_core_dev *mdev; - u16 queue_id; - u32 pdn; - int ret; - - queue_id = queue - ctx->send_queue; - mdev = ctx->mdev; - pdn = ctx->pd_num; - - /* Writing through FW can't HW fence, therefore we drain the queue */ - if (send_attr->fence) - mlx5hws_send_queue_action(ctx, - queue_id, - MLX5HWS_SEND_QUEUE_ACTION_DRAIN_SYNC); - - if (ste_attr->rtc_1) { - send_attr->id = ste_attr->rtc_1; - send_attr->used_id = ste_attr->used_id_rtc_1; - send_attr->retry_id = ste_attr->retry_rtc_1; - ret = hws_send_wqe_fw(mdev, pdn, send_attr, - ste_attr->wqe_ctrl, - ste_attr->wqe_data, - ste_attr->wqe_tag, - ste_attr->range_wqe_data, - ste_attr->range_wqe_tag, - ste_attr->wqe_tag_is_jumbo, - ste_attr->gta_opcode); - if (ret) - goto fail_rule; - } - - if (ste_attr->rtc_0) { - send_attr->id = ste_attr->rtc_0; - send_attr->used_id = ste_attr->used_id_rtc_0; - send_attr->retry_id = ste_attr->retry_rtc_0; - ret = hws_send_wqe_fw(mdev, pdn, send_attr, - ste_attr->wqe_ctrl, - ste_attr->wqe_data, - ste_attr->wqe_tag, - ste_attr->range_wqe_data, - ste_attr->range_wqe_tag, - ste_attr->wqe_tag_is_jumbo, - ste_attr->gta_opcode); - if (ret) - goto fail_rule; - } - - /* Increase the status, this only works on good flow as the enum - * is arrange it away creating -> created -> deleting -> deleted - */ - if (likely(rule)) - rule->status++; - - mlx5hws_send_engine_gen_comp(queue, send_attr->user_data, MLX5HWS_FLOW_OP_SUCCESS); - - return; - -fail_rule: - if (likely(rule)) - rule->status = !rule->rtc_0 && !rule->rtc_1 ? - MLX5HWS_RULE_STATUS_FAILED : MLX5HWS_RULE_STATUS_FAILING; - - mlx5hws_send_engine_gen_comp(queue, send_attr->user_data, MLX5HWS_FLOW_OP_ERROR); -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.h deleted file mode 100644 index b50825d6dc53dc..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_send.h +++ /dev/null @@ -1,270 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_SEND_H_ -#define MLX5HWS_SEND_H_ - -/* As a single operation requires at least two WQEBBS. - * This means a maximum of 16 such operations per rule. - */ -#define MAX_WQES_PER_RULE 32 - -enum mlx5hws_wqe_opcode { - MLX5HWS_WQE_OPCODE_TBL_ACCESS = 0x2c, -}; - -enum mlx5hws_wqe_opmod { - MLX5HWS_WQE_OPMOD_GTA_STE = 0, - MLX5HWS_WQE_OPMOD_GTA_MOD_ARG = 1, -}; - -enum mlx5hws_wqe_gta_opcode { - MLX5HWS_WQE_GTA_OP_ACTIVATE = 0, - MLX5HWS_WQE_GTA_OP_DEACTIVATE = 1, -}; - -enum mlx5hws_wqe_gta_opmod { - MLX5HWS_WQE_GTA_OPMOD_STE = 0, - MLX5HWS_WQE_GTA_OPMOD_MOD_ARG = 1, -}; - -enum mlx5hws_wqe_gta_sz { - MLX5HWS_WQE_SZ_GTA_CTRL = 48, - MLX5HWS_WQE_SZ_GTA_DATA = 64, -}; - -/* WQE Control segment. */ -struct mlx5hws_wqe_ctrl_seg { - __be32 opmod_idx_opcode; - __be32 qpn_ds; - __be32 flags; - __be32 imm; -}; - -struct mlx5hws_wqe_gta_ctrl_seg { - __be32 op_dirix; - __be32 stc_ix[5]; - __be32 rsvd0[6]; -}; - -struct mlx5hws_wqe_gta_data_seg_ste { - __be32 rsvd0_ctr_id; - __be32 rsvd1_definer; - __be32 rsvd2[3]; - union { - struct { - __be32 action[3]; - __be32 tag[8]; - }; - __be32 jumbo[11]; - }; -}; - -struct mlx5hws_wqe_gta_data_seg_arg { - __be32 action_args[8]; -}; - -struct mlx5hws_wqe_gta { - struct mlx5hws_wqe_gta_ctrl_seg gta_ctrl; - union { - struct mlx5hws_wqe_gta_data_seg_ste seg_ste; - struct mlx5hws_wqe_gta_data_seg_arg seg_arg; - }; -}; - -struct mlx5hws_send_ring_cq { - struct mlx5_core_dev *mdev; - struct mlx5_cqwq wq; - struct mlx5_wq_ctrl wq_ctrl; - struct mlx5_core_cq mcq; - u16 poll_wqe; -}; - -struct mlx5hws_send_ring_priv { - struct mlx5hws_rule *rule; - void *user_data; - u32 num_wqebbs; - u32 id; - u32 retry_id; - u32 *used_id; -}; - -struct mlx5hws_send_ring_dep_wqe { - struct mlx5hws_wqe_gta_ctrl_seg wqe_ctrl; - struct mlx5hws_wqe_gta_data_seg_ste wqe_data; - struct mlx5hws_rule *rule; - u32 rtc_0; - u32 rtc_1; - u32 retry_rtc_0; - u32 retry_rtc_1; - u32 direct_index; - void *user_data; -}; - -struct mlx5hws_send_ring_sq { - struct mlx5_core_dev *mdev; - u16 cur_post; - u16 buf_mask; - struct mlx5hws_send_ring_priv *wr_priv; - unsigned int last_idx; - struct mlx5hws_send_ring_dep_wqe *dep_wqe; - unsigned int head_dep_idx; - unsigned int tail_dep_idx; - u32 sqn; - struct mlx5_wq_cyc wq; - struct mlx5_wq_ctrl wq_ctrl; - void __iomem *uar_map; -}; - -struct mlx5hws_send_ring { - struct mlx5hws_send_ring_cq send_cq; - struct mlx5hws_send_ring_sq send_sq; -}; - -struct mlx5hws_completed_poll_entry { - void *user_data; - enum mlx5hws_flow_op_status status; -}; - -struct mlx5hws_completed_poll { - struct mlx5hws_completed_poll_entry *entries; - u16 ci; - u16 pi; - u16 mask; -}; - -struct mlx5hws_send_engine { - struct mlx5hws_send_ring send_ring; - struct mlx5_uars_page *uar; /* Uar is shared between rings of a queue */ - struct mlx5hws_completed_poll completed; - u16 used_entries; - u16 num_entries; - bool err; - struct mutex lock; /* Protects the send engine */ -}; - -struct mlx5hws_send_engine_post_ctrl { - struct mlx5hws_send_engine *queue; - struct mlx5hws_send_ring *send_ring; - size_t num_wqebbs; -}; - -struct mlx5hws_send_engine_post_attr { - u8 opcode; - u8 opmod; - u8 notify_hw; - u8 fence; - u8 match_definer_id; - u8 range_definer_id; - size_t len; - struct mlx5hws_rule *rule; - u32 id; - u32 retry_id; - u32 *used_id; - void *user_data; -}; - -struct mlx5hws_send_ste_attr { - u32 rtc_0; - u32 rtc_1; - u32 retry_rtc_0; - u32 retry_rtc_1; - u32 *used_id_rtc_0; - u32 *used_id_rtc_1; - bool wqe_tag_is_jumbo; - u8 gta_opcode; - u32 direct_index; - struct mlx5hws_send_engine_post_attr send_attr; - struct mlx5hws_rule_match_tag *wqe_tag; - struct mlx5hws_rule_match_tag *range_wqe_tag; - struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; - struct mlx5hws_wqe_gta_data_seg_ste *wqe_data; - struct mlx5hws_wqe_gta_data_seg_ste *range_wqe_data; -}; - -struct mlx5hws_send_ring_dep_wqe * -mlx5hws_send_add_new_dep_wqe(struct mlx5hws_send_engine *queue); - -void mlx5hws_send_abort_new_dep_wqe(struct mlx5hws_send_engine *queue); - -void mlx5hws_send_all_dep_wqe(struct mlx5hws_send_engine *queue); - -void mlx5hws_send_queue_close(struct mlx5hws_send_engine *queue); - -int mlx5hws_send_queue_open(struct mlx5hws_context *ctx, - struct mlx5hws_send_engine *queue, - u16 queue_size); - -void mlx5hws_send_queues_close(struct mlx5hws_context *ctx); - -int mlx5hws_send_queues_open(struct mlx5hws_context *ctx, - u16 queues, - u16 queue_size); - -int mlx5hws_send_queue_action(struct mlx5hws_context *ctx, - u16 queue_id, - u32 actions); - -int mlx5hws_send_test(struct mlx5hws_context *ctx, - u16 queues, - u16 queue_size); - -struct mlx5hws_send_engine_post_ctrl -mlx5hws_send_engine_post_start(struct mlx5hws_send_engine *queue); - -void mlx5hws_send_engine_post_req_wqe(struct mlx5hws_send_engine_post_ctrl *ctrl, - char **buf, size_t *len); - -void mlx5hws_send_engine_post_end(struct mlx5hws_send_engine_post_ctrl *ctrl, - struct mlx5hws_send_engine_post_attr *attr); - -void mlx5hws_send_ste(struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ste_attr *ste_attr); - -void mlx5hws_send_stes_fw(struct mlx5hws_context *ctx, - struct mlx5hws_send_engine *queue, - struct mlx5hws_send_ste_attr *ste_attr); - -void mlx5hws_send_engine_flush_queue(struct mlx5hws_send_engine *queue); - -static inline bool mlx5hws_send_engine_empty(struct mlx5hws_send_engine *queue) -{ - struct mlx5hws_send_ring_sq *send_sq = &queue->send_ring.send_sq; - struct mlx5hws_send_ring_cq *send_cq = &queue->send_ring.send_cq; - - return ((send_sq->cur_post & send_sq->buf_mask) == send_cq->poll_wqe); -} - -static inline bool mlx5hws_send_engine_full(struct mlx5hws_send_engine *queue) -{ - return queue->used_entries >= queue->num_entries; -} - -static inline void mlx5hws_send_engine_inc_rule(struct mlx5hws_send_engine *queue) -{ - queue->used_entries++; -} - -static inline void mlx5hws_send_engine_dec_rule(struct mlx5hws_send_engine *queue) -{ - queue->used_entries--; -} - -static inline void mlx5hws_send_engine_gen_comp(struct mlx5hws_send_engine *queue, - void *user_data, - int comp_status) -{ - struct mlx5hws_completed_poll *comp = &queue->completed; - - comp->entries[comp->pi].status = comp_status; - comp->entries[comp->pi].user_data = user_data; - - comp->pi = (comp->pi + 1) & comp->mask; -} - -static inline bool mlx5hws_send_engine_err(struct mlx5hws_send_engine *queue) -{ - return queue->err; -} - -#endif /* MLX5HWS_SEND_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c deleted file mode 100644 index 8c063a8d87d7dc..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.c +++ /dev/null @@ -1,493 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -u32 mlx5hws_table_get_id(struct mlx5hws_table *tbl) -{ - return tbl->ft_id; -} - -static void hws_table_init_next_ft_attr(struct mlx5hws_table *tbl, - struct mlx5hws_cmd_ft_create_attr *ft_attr) -{ - ft_attr->type = tbl->fw_ft_type; - if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) - ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1; - else - ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1; - ft_attr->rtc_valid = true; -} - -static void hws_table_set_cap_attr(struct mlx5hws_table *tbl, - struct mlx5hws_cmd_ft_create_attr *ft_attr) -{ - /* Enabling reformat_en or decap_en for the first flow table - * must be done when all VFs are down. - * However, HWS doesn't know when it is required to create the first FT. - * On the other hand, HWS doesn't use all these FT capabilities at all - * (the API doesn't even provide a way to specify these flags), so we'll - * just set these caps on all the flow tables. - * If HCA_CAP.fdb_dynamic_tunnel is set, this constraint is N/A. - */ - if (!MLX5_CAP_ESW_FLOWTABLE(tbl->ctx->mdev, fdb_dynamic_tunnel)) { - ft_attr->reformat_en = true; - ft_attr->decap_en = true; - } -} - -static int hws_table_up_default_fdb_miss_tbl(struct mlx5hws_table *tbl) -{ - struct mlx5hws_cmd_ft_create_attr ft_attr = {0}; - struct mlx5hws_cmd_set_fte_attr fte_attr = {0}; - struct mlx5hws_cmd_forward_tbl *default_miss; - struct mlx5hws_cmd_set_fte_dest dest = {0}; - struct mlx5hws_context *ctx = tbl->ctx; - u8 tbl_type = tbl->type; - - if (tbl->type != MLX5HWS_TABLE_TYPE_FDB) - return 0; - - if (ctx->common_res[tbl_type].default_miss) { - ctx->common_res[tbl_type].default_miss->refcount++; - return 0; - } - - ft_attr.type = tbl->fw_ft_type; - ft_attr.level = tbl->ctx->caps->fdb_ft.max_level; /* The last level */ - ft_attr.rtc_valid = false; - - dest.destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT; - dest.destination_id = ctx->caps->eswitch_manager_vport_number; - - fte_attr.action_flags = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; - fte_attr.dests_num = 1; - fte_attr.dests = &dest; - - default_miss = mlx5hws_cmd_forward_tbl_create(ctx->mdev, &ft_attr, &fte_attr); - if (!default_miss) { - mlx5hws_err(ctx, "Failed to default miss table type: 0x%x\n", tbl_type); - return -EINVAL; - } - - /* ctx->ctrl_lock must be held here */ - ctx->common_res[tbl_type].default_miss = default_miss; - ctx->common_res[tbl_type].default_miss->refcount++; - - return 0; -} - -/* Called under ctx->ctrl_lock */ -static void hws_table_down_default_fdb_miss_tbl(struct mlx5hws_table *tbl) -{ - struct mlx5hws_cmd_forward_tbl *default_miss; - struct mlx5hws_context *ctx = tbl->ctx; - u8 tbl_type = tbl->type; - - if (tbl->type != MLX5HWS_TABLE_TYPE_FDB) - return; - - default_miss = ctx->common_res[tbl_type].default_miss; - if (--default_miss->refcount) - return; - - mlx5hws_cmd_forward_tbl_destroy(ctx->mdev, default_miss); - ctx->common_res[tbl_type].default_miss = NULL; -} - -static int hws_table_connect_to_default_miss_tbl(struct mlx5hws_table *tbl, u32 ft_id) -{ - struct mlx5hws_cmd_ft_modify_attr ft_attr = {0}; - int ret; - - if (unlikely(tbl->type != MLX5HWS_TABLE_TYPE_FDB)) - pr_warn("HWS: invalid table type %d\n", tbl->type); - - mlx5hws_cmd_set_attr_connect_miss_tbl(tbl->ctx, - tbl->fw_ft_type, - tbl->type, - &ft_attr); - - ret = mlx5hws_cmd_flow_table_modify(tbl->ctx->mdev, &ft_attr, ft_id); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed to connect FT to default FDB FT\n"); - return ret; - } - - return 0; -} - -int mlx5hws_table_create_default_ft(struct mlx5_core_dev *mdev, - struct mlx5hws_table *tbl, - u32 *ft_id) -{ - struct mlx5hws_cmd_ft_create_attr ft_attr = {0}; - int ret; - - hws_table_init_next_ft_attr(tbl, &ft_attr); - hws_table_set_cap_attr(tbl, &ft_attr); - - ret = mlx5hws_cmd_flow_table_create(mdev, &ft_attr, ft_id); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed creating default ft\n"); - return ret; - } - - if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) { - /* Take/create ref over the default miss */ - ret = hws_table_up_default_fdb_miss_tbl(tbl); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed to get default fdb miss\n"); - goto free_ft_obj; - } - ret = hws_table_connect_to_default_miss_tbl(tbl, *ft_id); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed connecting to default miss tbl\n"); - goto down_miss_tbl; - } - } - - return 0; - -down_miss_tbl: - hws_table_down_default_fdb_miss_tbl(tbl); -free_ft_obj: - mlx5hws_cmd_flow_table_destroy(mdev, ft_attr.type, *ft_id); - return ret; -} - -void mlx5hws_table_destroy_default_ft(struct mlx5hws_table *tbl, - u32 ft_id) -{ - mlx5hws_cmd_flow_table_destroy(tbl->ctx->mdev, tbl->fw_ft_type, ft_id); - hws_table_down_default_fdb_miss_tbl(tbl); -} - -static int hws_table_init_check_hws_support(struct mlx5hws_context *ctx, - struct mlx5hws_table *tbl) -{ - if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) { - mlx5hws_err(ctx, "HWS not supported, cannot create mlx5hws_table\n"); - return -EOPNOTSUPP; - } - - return 0; -} - -static int hws_table_init(struct mlx5hws_table *tbl) -{ - struct mlx5hws_context *ctx = tbl->ctx; - int ret; - - ret = hws_table_init_check_hws_support(ctx, tbl); - if (ret) - return ret; - - if (mlx5hws_table_get_fw_ft_type(tbl->type, (u8 *)&tbl->fw_ft_type)) { - pr_warn("HWS: invalid table type %d\n", tbl->type); - return -EOPNOTSUPP; - } - - mutex_lock(&ctx->ctrl_lock); - ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, tbl, &tbl->ft_id); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed to create flow table object\n"); - mutex_unlock(&ctx->ctrl_lock); - return ret; - } - - ret = mlx5hws_action_get_default_stc(ctx, tbl->type); - if (ret) - goto tbl_destroy; - - INIT_LIST_HEAD(&tbl->matchers_list); - INIT_LIST_HEAD(&tbl->default_miss.head); - - mutex_unlock(&ctx->ctrl_lock); - - return 0; - -tbl_destroy: - mlx5hws_table_destroy_default_ft(tbl, tbl->ft_id); - mutex_unlock(&ctx->ctrl_lock); - return ret; -} - -static void hws_table_uninit(struct mlx5hws_table *tbl) -{ - mutex_lock(&tbl->ctx->ctrl_lock); - mlx5hws_action_put_default_stc(tbl->ctx, tbl->type); - mlx5hws_table_destroy_default_ft(tbl, tbl->ft_id); - mutex_unlock(&tbl->ctx->ctrl_lock); -} - -struct mlx5hws_table *mlx5hws_table_create(struct mlx5hws_context *ctx, - struct mlx5hws_table_attr *attr) -{ - struct mlx5hws_table *tbl; - int ret; - - if (attr->type > MLX5HWS_TABLE_TYPE_FDB) { - mlx5hws_err(ctx, "Invalid table type %d\n", attr->type); - return NULL; - } - - tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); - if (!tbl) - return NULL; - - tbl->ctx = ctx; - tbl->type = attr->type; - tbl->level = attr->level; - - ret = hws_table_init(tbl); - if (ret) { - mlx5hws_err(ctx, "Failed to initialise table\n"); - goto free_tbl; - } - - mutex_lock(&ctx->ctrl_lock); - list_add(&tbl->tbl_list_node, &ctx->tbl_list); - mutex_unlock(&ctx->ctrl_lock); - - return tbl; - -free_tbl: - kfree(tbl); - return NULL; -} - -int mlx5hws_table_destroy(struct mlx5hws_table *tbl) -{ - struct mlx5hws_context *ctx = tbl->ctx; - int ret; - - mutex_lock(&ctx->ctrl_lock); - if (!list_empty(&tbl->matchers_list)) { - mlx5hws_err(tbl->ctx, "Cannot destroy table containing matchers\n"); - ret = -EBUSY; - goto unlock_err; - } - - if (!list_empty(&tbl->default_miss.head)) { - mlx5hws_err(tbl->ctx, "Cannot destroy table pointed by default miss\n"); - ret = -EBUSY; - goto unlock_err; - } - - list_del_init(&tbl->tbl_list_node); - mutex_unlock(&ctx->ctrl_lock); - - hws_table_uninit(tbl); - kfree(tbl); - - return 0; - -unlock_err: - mutex_unlock(&ctx->ctrl_lock); - return ret; -} - -static u32 hws_table_get_last_ft(struct mlx5hws_table *tbl) -{ - struct mlx5hws_matcher *matcher; - - if (list_empty(&tbl->matchers_list)) - return tbl->ft_id; - - matcher = list_last_entry(&tbl->matchers_list, struct mlx5hws_matcher, list_node); - return matcher->end_ft_id; -} - -int mlx5hws_table_ft_set_default_next_ft(struct mlx5hws_table *tbl, u32 ft_id) -{ - struct mlx5hws_cmd_ft_modify_attr ft_attr = {0}; - int ret; - - /* Due to FW limitation, resetting the flow table to default action will - * disconnect RTC when ignore_flow_level_rtc_valid is not supported. - */ - if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid) - return 0; - - if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) - return hws_table_connect_to_default_miss_tbl(tbl, ft_id); - - ft_attr.type = tbl->fw_ft_type; - ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION; - ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_DEFAULT; - - ret = mlx5hws_cmd_flow_table_modify(tbl->ctx->mdev, &ft_attr, ft_id); - if (ret) { - mlx5hws_err(tbl->ctx, "Failed to set FT default miss action\n"); - return ret; - } - - return 0; -} - -int mlx5hws_table_ft_set_next_rtc(struct mlx5hws_context *ctx, - u32 ft_id, - u32 fw_ft_type, - u32 rtc_0_id, - u32 rtc_1_id) -{ - struct mlx5hws_cmd_ft_modify_attr ft_attr = {0}; - - ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; - ft_attr.type = fw_ft_type; - ft_attr.rtc_id_0 = rtc_0_id; - ft_attr.rtc_id_1 = rtc_1_id; - - return mlx5hws_cmd_flow_table_modify(ctx->mdev, &ft_attr, ft_id); -} - -static int hws_table_ft_set_next_ft(struct mlx5hws_context *ctx, - u32 ft_id, - u32 fw_ft_type, - u32 next_ft_id) -{ - struct mlx5hws_cmd_ft_modify_attr ft_attr = {0}; - - ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION; - ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL; - ft_attr.type = fw_ft_type; - ft_attr.table_miss_id = next_ft_id; - - return mlx5hws_cmd_flow_table_modify(ctx->mdev, &ft_attr, ft_id); -} - -int mlx5hws_table_update_connected_miss_tables(struct mlx5hws_table *dst_tbl) -{ - struct mlx5hws_table *src_tbl; - int ret; - - if (list_empty(&dst_tbl->default_miss.head)) - return 0; - - list_for_each_entry(src_tbl, &dst_tbl->default_miss.head, default_miss.next) { - ret = mlx5hws_table_connect_to_miss_table(src_tbl, dst_tbl); - if (ret) { - mlx5hws_err(dst_tbl->ctx, - "Failed to update source miss table, unexpected behavior\n"); - return ret; - } - } - - return 0; -} - -int mlx5hws_table_connect_to_miss_table(struct mlx5hws_table *src_tbl, - struct mlx5hws_table *dst_tbl) -{ - struct mlx5hws_matcher *matcher; - u32 last_ft_id; - int ret; - - last_ft_id = hws_table_get_last_ft(src_tbl); - - if (dst_tbl) { - if (list_empty(&dst_tbl->matchers_list)) { - /* Connect src_tbl last_ft to dst_tbl start anchor */ - ret = hws_table_ft_set_next_ft(src_tbl->ctx, - last_ft_id, - src_tbl->fw_ft_type, - dst_tbl->ft_id); - if (ret) - return ret; - - /* Reset last_ft RTC to default RTC */ - ret = mlx5hws_table_ft_set_next_rtc(src_tbl->ctx, - last_ft_id, - src_tbl->fw_ft_type, - 0, 0); - if (ret) - return ret; - } else { - /* Connect src_tbl last_ft to first matcher RTC */ - matcher = list_first_entry(&dst_tbl->matchers_list, - struct mlx5hws_matcher, - list_node); - ret = mlx5hws_table_ft_set_next_rtc(src_tbl->ctx, - last_ft_id, - src_tbl->fw_ft_type, - matcher->match_ste.rtc_0_id, - matcher->match_ste.rtc_1_id); - if (ret) - return ret; - - /* Reset next miss FT to default */ - ret = mlx5hws_table_ft_set_default_next_ft(src_tbl, last_ft_id); - if (ret) - return ret; - } - } else { - /* Reset next miss FT to default */ - ret = mlx5hws_table_ft_set_default_next_ft(src_tbl, last_ft_id); - if (ret) - return ret; - - /* Reset last_ft RTC to default RTC */ - ret = mlx5hws_table_ft_set_next_rtc(src_tbl->ctx, - last_ft_id, - src_tbl->fw_ft_type, - 0, 0); - if (ret) - return ret; - } - - src_tbl->default_miss.miss_tbl = dst_tbl; - - return 0; -} - -static int hws_table_set_default_miss_not_valid(struct mlx5hws_table *tbl, - struct mlx5hws_table *miss_tbl) -{ - if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid) { - mlx5hws_err(tbl->ctx, "Default miss table is not supported\n"); - return -EOPNOTSUPP; - } - - if ((miss_tbl && miss_tbl->type != tbl->type)) { - mlx5hws_err(tbl->ctx, "Invalid arguments\n"); - return -EINVAL; - } - - return 0; -} - -int mlx5hws_table_set_default_miss(struct mlx5hws_table *tbl, - struct mlx5hws_table *miss_tbl) -{ - struct mlx5hws_context *ctx = tbl->ctx; - struct mlx5hws_table *old_miss_tbl; - int ret; - - ret = hws_table_set_default_miss_not_valid(tbl, miss_tbl); - if (ret) - return ret; - - mutex_lock(&ctx->ctrl_lock); - - old_miss_tbl = tbl->default_miss.miss_tbl; - ret = mlx5hws_table_connect_to_miss_table(tbl, miss_tbl); - if (ret) - goto out; - - if (old_miss_tbl) - list_del_init(&tbl->default_miss.next); - - old_miss_tbl = tbl->default_miss.miss_tbl; - if (old_miss_tbl) - list_del_init(&old_miss_tbl->default_miss.head); - - if (miss_tbl) - list_add(&tbl->default_miss.next, &miss_tbl->default_miss.head); - - mutex_unlock(&ctx->ctrl_lock); - return 0; -out: - mutex_unlock(&ctx->ctrl_lock); - return ret; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.h deleted file mode 100644 index dd50420eec9eae..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_table.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_TABLE_H_ -#define MLX5HWS_TABLE_H_ - -struct mlx5hws_default_miss { - /* My miss table */ - struct mlx5hws_table *miss_tbl; - struct list_head next; - /* Tables missing to my table */ - struct list_head head; -}; - -struct mlx5hws_table { - struct mlx5hws_context *ctx; - u32 ft_id; - enum mlx5hws_table_type type; - u32 fw_ft_type; - u32 level; - struct list_head matchers_list; - struct list_head tbl_list_node; - struct mlx5hws_default_miss default_miss; -}; - -static inline -u32 mlx5hws_table_get_fw_ft_type(enum mlx5hws_table_type type, - u8 *ret_type) -{ - if (type != MLX5HWS_TABLE_TYPE_FDB) - return -EOPNOTSUPP; - - *ret_type = FS_FT_FDB; - - return 0; -} - -static inline -u32 mlx5hws_table_get_res_fw_ft_type(enum mlx5hws_table_type tbl_type, - bool is_mirror) -{ - if (tbl_type == MLX5HWS_TABLE_TYPE_FDB) - return is_mirror ? FS_FT_FDB_TX : FS_FT_FDB_RX; - - return 0; -} - -int mlx5hws_table_create_default_ft(struct mlx5_core_dev *mdev, - struct mlx5hws_table *tbl, - u32 *ft_id); - -void mlx5hws_table_destroy_default_ft(struct mlx5hws_table *tbl, - u32 ft_id); - -int mlx5hws_table_connect_to_miss_table(struct mlx5hws_table *src_tbl, - struct mlx5hws_table *dst_tbl); - -int mlx5hws_table_update_connected_miss_tables(struct mlx5hws_table *dst_tbl); - -int mlx5hws_table_ft_set_default_next_ft(struct mlx5hws_table *tbl, u32 ft_id); - -int mlx5hws_table_ft_set_next_rtc(struct mlx5hws_context *ctx, - u32 ft_id, - u32 fw_ft_type, - u32 rtc_0_id, - u32 rtc_1_id); - -#endif /* MLX5HWS_TABLE_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.c deleted file mode 100644 index faf42421c43fd6..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.c +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#include "mlx5hws_internal.h" - -int mlx5hws_vport_init_vports(struct mlx5hws_context *ctx) -{ - int ret; - - if (!ctx->caps->eswitch_manager) - return 0; - - xa_init(&ctx->vports.vport_gvmi_xa); - - /* Set gvmi for eswitch manager and uplink vports only. Rest of the vports - * (vport 0 of other function, VFs and SFs) will be queried dynamically. - */ - - ret = mlx5hws_cmd_query_gvmi(ctx->mdev, false, 0, &ctx->vports.esw_manager_gvmi); - if (ret) - return ret; - - ctx->vports.uplink_gvmi = 0; - return 0; -} - -void mlx5hws_vport_uninit_vports(struct mlx5hws_context *ctx) -{ - if (ctx->caps->eswitch_manager) - xa_destroy(&ctx->vports.vport_gvmi_xa); -} - -static int hws_vport_add_gvmi(struct mlx5hws_context *ctx, u16 vport) -{ - u16 vport_gvmi; - int ret; - - ret = mlx5hws_cmd_query_gvmi(ctx->mdev, true, vport, &vport_gvmi); - if (ret) - return -EINVAL; - - ret = xa_insert(&ctx->vports.vport_gvmi_xa, vport, - xa_mk_value(vport_gvmi), GFP_KERNEL); - if (ret) - mlx5hws_dbg(ctx, "Couldn't insert new vport gvmi into xarray (%d)\n", ret); - - return ret; -} - -static bool hws_vport_is_esw_mgr_vport(struct mlx5hws_context *ctx, u16 vport) -{ - return ctx->caps->is_ecpf ? vport == MLX5_VPORT_ECPF : - vport == MLX5_VPORT_PF; -} - -int mlx5hws_vport_get_gvmi(struct mlx5hws_context *ctx, u16 vport, u16 *vport_gvmi) -{ - void *entry; - int ret; - - if (!ctx->caps->eswitch_manager) - return -EINVAL; - - if (hws_vport_is_esw_mgr_vport(ctx, vport)) { - *vport_gvmi = ctx->vports.esw_manager_gvmi; - return 0; - } - - if (vport == MLX5_VPORT_UPLINK) { - *vport_gvmi = ctx->vports.uplink_gvmi; - return 0; - } - -load_entry: - entry = xa_load(&ctx->vports.vport_gvmi_xa, vport); - - if (!xa_is_value(entry)) { - ret = hws_vport_add_gvmi(ctx, vport); - if (ret && ret != -EBUSY) - return ret; - goto load_entry; - } - - *vport_gvmi = (u16)xa_to_value(entry); - return 0; -} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.h deleted file mode 100644 index 0912fc166b3a63..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws_vport.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ - -#ifndef MLX5HWS_VPORT_H_ -#define MLX5HWS_VPORT_H_ - -int mlx5hws_vport_init_vports(struct mlx5hws_context *ctx); - -void mlx5hws_vport_uninit_vports(struct mlx5hws_context *ctx); - -int mlx5hws_vport_get_gvmi(struct mlx5hws_context *ctx, u16 vport, u16 *vport_gvmi); - -#endif /* MLX5HWS_VPORT_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c new file mode 100644 index 00000000000000..06db5e4726aee4 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.c @@ -0,0 +1,579 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +enum mlx5hws_arg_chunk_size +mlx5hws_arg_data_size_to_arg_log_size(u16 data_size) +{ + /* Return the roundup of log2(data_size) */ + if (data_size <= MLX5HWS_ARG_DATA_SIZE) + return MLX5HWS_ARG_CHUNK_SIZE_1; + if (data_size <= MLX5HWS_ARG_DATA_SIZE * 2) + return MLX5HWS_ARG_CHUNK_SIZE_2; + if (data_size <= MLX5HWS_ARG_DATA_SIZE * 4) + return MLX5HWS_ARG_CHUNK_SIZE_3; + if (data_size <= MLX5HWS_ARG_DATA_SIZE * 8) + return MLX5HWS_ARG_CHUNK_SIZE_4; + + return MLX5HWS_ARG_CHUNK_SIZE_MAX; +} + +u32 mlx5hws_arg_data_size_to_arg_size(u16 data_size) +{ + return BIT(mlx5hws_arg_data_size_to_arg_log_size(data_size)); +} + +enum mlx5hws_arg_chunk_size +mlx5hws_arg_get_arg_log_size(u16 num_of_actions) +{ + return mlx5hws_arg_data_size_to_arg_log_size(num_of_actions * + MLX5HWS_MODIFY_ACTION_SIZE); +} + +u32 mlx5hws_arg_get_arg_size(u16 num_of_actions) +{ + return BIT(mlx5hws_arg_get_arg_log_size(num_of_actions)); +} + +bool mlx5hws_pat_require_reparse(__be64 *actions, u16 num_of_actions) +{ + u16 i, field; + u8 action_id; + + for (i = 0; i < num_of_actions; i++) { + action_id = MLX5_GET(set_action_in, &actions[i], action_type); + + switch (action_id) { + case MLX5_MODIFICATION_TYPE_NOP: + field = MLX5_MODI_OUT_NONE; + break; + + case MLX5_MODIFICATION_TYPE_SET: + case MLX5_MODIFICATION_TYPE_ADD: + field = MLX5_GET(set_action_in, &actions[i], field); + break; + + case MLX5_MODIFICATION_TYPE_COPY: + case MLX5_MODIFICATION_TYPE_ADD_FIELD: + field = MLX5_GET(copy_action_in, &actions[i], dst_field); + break; + + default: + /* Insert/Remove/Unknown actions require reparse */ + return true; + } + + /* Below fields can change packet structure require a reparse */ + if (field == MLX5_MODI_OUT_ETHERTYPE || + field == MLX5_MODI_OUT_IPV6_NEXT_HDR) + return true; + } + + return false; +} + +/* Cache and cache element handling */ +int mlx5hws_pat_init_pattern_cache(struct mlx5hws_pattern_cache **cache) +{ + struct mlx5hws_pattern_cache *new_cache; + + new_cache = kzalloc(sizeof(*new_cache), GFP_KERNEL); + if (!new_cache) + return -ENOMEM; + + INIT_LIST_HEAD(&new_cache->ptrn_list); + mutex_init(&new_cache->lock); + + *cache = new_cache; + + return 0; +} + +void mlx5hws_pat_uninit_pattern_cache(struct mlx5hws_pattern_cache *cache) +{ + mutex_destroy(&cache->lock); + kfree(cache); +} + +static bool mlx5hws_pat_compare_pattern(int cur_num_of_actions, + __be64 cur_actions[], + int num_of_actions, + __be64 actions[]) +{ + int i; + + if (cur_num_of_actions != num_of_actions) + return false; + + for (i = 0; i < num_of_actions; i++) { + u8 action_id = + MLX5_GET(set_action_in, &actions[i], action_type); + + if (action_id == MLX5_MODIFICATION_TYPE_COPY || + action_id == MLX5_MODIFICATION_TYPE_ADD_FIELD) { + if (actions[i] != cur_actions[i]) + return false; + } else { + /* Compare just the control, not the values */ + if ((__force __be32)actions[i] != + (__force __be32)cur_actions[i]) + return false; + } + } + + return true; +} + +static struct mlx5hws_pattern_cache_item * +mlx5hws_pat_find_cached_pattern(struct mlx5hws_pattern_cache *cache, + u16 num_of_actions, + __be64 *actions) +{ + struct mlx5hws_pattern_cache_item *cached_pat = NULL; + + list_for_each_entry(cached_pat, &cache->ptrn_list, ptrn_list_node) { + if (mlx5hws_pat_compare_pattern(cached_pat->mh_data.num_of_actions, + (__be64 *)cached_pat->mh_data.data, + num_of_actions, + actions)) + return cached_pat; + } + + return NULL; +} + +static struct mlx5hws_pattern_cache_item * +mlx5hws_pat_get_existing_cached_pattern(struct mlx5hws_pattern_cache *cache, + u16 num_of_actions, + __be64 *actions) +{ + struct mlx5hws_pattern_cache_item *cached_pattern; + + cached_pattern = mlx5hws_pat_find_cached_pattern(cache, num_of_actions, actions); + if (cached_pattern) { + /* LRU: move it to be first in the list */ + list_del_init(&cached_pattern->ptrn_list_node); + list_add(&cached_pattern->ptrn_list_node, &cache->ptrn_list); + cached_pattern->refcount++; + } + + return cached_pattern; +} + +static struct mlx5hws_pattern_cache_item * +mlx5hws_pat_add_pattern_to_cache(struct mlx5hws_pattern_cache *cache, + u32 pattern_id, + u16 num_of_actions, + __be64 *actions) +{ + struct mlx5hws_pattern_cache_item *cached_pattern; + + cached_pattern = kzalloc(sizeof(*cached_pattern), GFP_KERNEL); + if (!cached_pattern) + return NULL; + + cached_pattern->mh_data.num_of_actions = num_of_actions; + cached_pattern->mh_data.pattern_id = pattern_id; + cached_pattern->mh_data.data = + kmemdup(actions, num_of_actions * MLX5HWS_MODIFY_ACTION_SIZE, GFP_KERNEL); + if (!cached_pattern->mh_data.data) + goto free_cached_obj; + + list_add(&cached_pattern->ptrn_list_node, &cache->ptrn_list); + cached_pattern->refcount = 1; + + return cached_pattern; + +free_cached_obj: + kfree(cached_pattern); + return NULL; +} + +static struct mlx5hws_pattern_cache_item * +mlx5hws_pat_find_cached_pattern_by_id(struct mlx5hws_pattern_cache *cache, + u32 ptrn_id) +{ + struct mlx5hws_pattern_cache_item *cached_pattern = NULL; + + list_for_each_entry(cached_pattern, &cache->ptrn_list, ptrn_list_node) { + if (cached_pattern->mh_data.pattern_id == ptrn_id) + return cached_pattern; + } + + return NULL; +} + +static void +mlx5hws_pat_remove_pattern(struct mlx5hws_pattern_cache_item *cached_pattern) +{ + list_del_init(&cached_pattern->ptrn_list_node); + + kfree(cached_pattern->mh_data.data); + kfree(cached_pattern); +} + +void mlx5hws_pat_put_pattern(struct mlx5hws_context *ctx, u32 ptrn_id) +{ + struct mlx5hws_pattern_cache *cache = ctx->pattern_cache; + struct mlx5hws_pattern_cache_item *cached_pattern; + + mutex_lock(&cache->lock); + cached_pattern = mlx5hws_pat_find_cached_pattern_by_id(cache, ptrn_id); + if (!cached_pattern) { + mlx5hws_err(ctx, "Failed to find cached pattern with provided ID\n"); + pr_warn("HWS: pattern ID %d is not found\n", ptrn_id); + goto out; + } + + if (--cached_pattern->refcount) + goto out; + + mlx5hws_pat_remove_pattern(cached_pattern); + mlx5hws_cmd_header_modify_pattern_destroy(ctx->mdev, ptrn_id); + +out: + mutex_unlock(&cache->lock); +} + +int mlx5hws_pat_get_pattern(struct mlx5hws_context *ctx, + __be64 *pattern, size_t pattern_sz, + u32 *pattern_id) +{ + u16 num_of_actions = pattern_sz / MLX5HWS_MODIFY_ACTION_SIZE; + struct mlx5hws_pattern_cache_item *cached_pattern; + u32 ptrn_id = 0; + int ret = 0; + + mutex_lock(&ctx->pattern_cache->lock); + + cached_pattern = mlx5hws_pat_get_existing_cached_pattern(ctx->pattern_cache, + num_of_actions, + pattern); + if (cached_pattern) { + *pattern_id = cached_pattern->mh_data.pattern_id; + goto out_unlock; + } + + ret = mlx5hws_cmd_header_modify_pattern_create(ctx->mdev, + pattern_sz, + (u8 *)pattern, + &ptrn_id); + if (ret) { + mlx5hws_err(ctx, "Failed to create pattern FW object\n"); + goto out_unlock; + } + + cached_pattern = mlx5hws_pat_add_pattern_to_cache(ctx->pattern_cache, + ptrn_id, + num_of_actions, + pattern); + if (!cached_pattern) { + mlx5hws_err(ctx, "Failed to add pattern to cache\n"); + ret = -EINVAL; + goto clean_pattern; + } + + mutex_unlock(&ctx->pattern_cache->lock); + *pattern_id = ptrn_id; + + return ret; + +clean_pattern: + mlx5hws_cmd_header_modify_pattern_destroy(ctx->mdev, *pattern_id); +out_unlock: + mutex_unlock(&ctx->pattern_cache->lock); + return ret; +} + +static void +mlx5d_arg_init_send_attr(struct mlx5hws_send_engine_post_attr *send_attr, + void *comp_data, + u32 arg_idx) +{ + send_attr->opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; + send_attr->opmod = MLX5HWS_WQE_GTA_OPMOD_MOD_ARG; + send_attr->len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; + send_attr->id = arg_idx; + send_attr->user_data = comp_data; +} + +void mlx5hws_arg_decapl3_write(struct mlx5hws_send_engine *queue, + u32 arg_idx, + u8 *arg_data, + u16 num_of_actions) +{ + struct mlx5hws_send_engine_post_attr send_attr = {0}; + struct mlx5hws_wqe_gta_data_seg_arg *wqe_arg = NULL; + struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl = NULL; + struct mlx5hws_send_engine_post_ctrl ctrl; + size_t wqe_len; + + mlx5d_arg_init_send_attr(&send_attr, NULL, arg_idx); + + ctrl = mlx5hws_send_engine_post_start(queue); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); + memset(wqe_ctrl, 0, wqe_len); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_arg, &wqe_len); + mlx5hws_action_prepare_decap_l3_data(arg_data, (u8 *)wqe_arg, + num_of_actions); + mlx5hws_send_engine_post_end(&ctrl, &send_attr); +} + +void mlx5hws_arg_write(struct mlx5hws_send_engine *queue, + void *comp_data, + u32 arg_idx, + u8 *arg_data, + size_t data_size) +{ + struct mlx5hws_send_engine_post_attr send_attr = {0}; + struct mlx5hws_wqe_gta_data_seg_arg *wqe_arg; + struct mlx5hws_send_engine_post_ctrl ctrl; + struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; + int i, full_iter, leftover; + size_t wqe_len; + + mlx5d_arg_init_send_attr(&send_attr, comp_data, arg_idx); + + /* Each WQE can hold 64B of data, it might require multiple iteration */ + full_iter = data_size / MLX5HWS_ARG_DATA_SIZE; + leftover = data_size & (MLX5HWS_ARG_DATA_SIZE - 1); + + for (i = 0; i < full_iter; i++) { + ctrl = mlx5hws_send_engine_post_start(queue); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); + memset(wqe_ctrl, 0, wqe_len); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_arg, &wqe_len); + memcpy(wqe_arg, arg_data, wqe_len); + send_attr.id = arg_idx++; + mlx5hws_send_engine_post_end(&ctrl, &send_attr); + + /* Move to next argument data */ + arg_data += MLX5HWS_ARG_DATA_SIZE; + } + + if (leftover) { + ctrl = mlx5hws_send_engine_post_start(queue); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); + memset(wqe_ctrl, 0, wqe_len); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_arg, &wqe_len); + memcpy(wqe_arg, arg_data, leftover); + send_attr.id = arg_idx; + mlx5hws_send_engine_post_end(&ctrl, &send_attr); + } +} + +int mlx5hws_arg_write_inline_arg_data(struct mlx5hws_context *ctx, + u32 arg_idx, + u8 *arg_data, + size_t data_size) +{ + struct mlx5hws_send_engine *queue; + int ret; + + mutex_lock(&ctx->ctrl_lock); + + /* Get the control queue */ + queue = &ctx->send_queue[ctx->queues - 1]; + + mlx5hws_arg_write(queue, arg_data, arg_idx, arg_data, data_size); + + mlx5hws_send_engine_flush_queue(queue); + + /* Poll for completion */ + ret = mlx5hws_send_queue_action(ctx, ctx->queues - 1, + MLX5HWS_SEND_QUEUE_ACTION_DRAIN_SYNC); + + if (ret) + mlx5hws_err(ctx, "Failed to drain arg queue\n"); + + mutex_unlock(&ctx->ctrl_lock); + + return ret; +} + +bool mlx5hws_arg_is_valid_arg_request_size(struct mlx5hws_context *ctx, + u32 arg_size) +{ + if (arg_size < ctx->caps->log_header_modify_argument_granularity || + arg_size > ctx->caps->log_header_modify_argument_max_alloc) { + return false; + } + return true; +} + +int mlx5hws_arg_create(struct mlx5hws_context *ctx, + u8 *data, + size_t data_sz, + u32 log_bulk_sz, + bool write_data, + u32 *arg_id) +{ + u16 single_arg_log_sz; + u16 multi_arg_log_sz; + int ret; + u32 id; + + single_arg_log_sz = mlx5hws_arg_data_size_to_arg_log_size(data_sz); + multi_arg_log_sz = single_arg_log_sz + log_bulk_sz; + + if (single_arg_log_sz >= MLX5HWS_ARG_CHUNK_SIZE_MAX) { + mlx5hws_err(ctx, "Requested single arg %u not supported\n", single_arg_log_sz); + return -EOPNOTSUPP; + } + + if (!mlx5hws_arg_is_valid_arg_request_size(ctx, multi_arg_log_sz)) { + mlx5hws_err(ctx, "Argument log size %d not supported by FW\n", multi_arg_log_sz); + return -EOPNOTSUPP; + } + + /* Alloc bulk of args */ + ret = mlx5hws_cmd_arg_create(ctx->mdev, multi_arg_log_sz, ctx->pd_num, &id); + if (ret) { + mlx5hws_err(ctx, "Failed allocating arg in order: %d\n", multi_arg_log_sz); + return ret; + } + + if (write_data) { + ret = mlx5hws_arg_write_inline_arg_data(ctx, id, + data, data_sz); + if (ret) { + mlx5hws_err(ctx, "Failed writing arg data\n"); + mlx5hws_cmd_arg_destroy(ctx->mdev, id); + return ret; + } + } + + *arg_id = id; + return ret; +} + +void mlx5hws_arg_destroy(struct mlx5hws_context *ctx, u32 arg_id) +{ + mlx5hws_cmd_arg_destroy(ctx->mdev, arg_id); +} + +int mlx5hws_arg_create_modify_header_arg(struct mlx5hws_context *ctx, + __be64 *data, + u8 num_of_actions, + u32 log_bulk_sz, + bool write_data, + u32 *arg_id) +{ + size_t data_sz = num_of_actions * MLX5HWS_MODIFY_ACTION_SIZE; + int ret; + + ret = mlx5hws_arg_create(ctx, + (u8 *)data, + data_sz, + log_bulk_sz, + write_data, + arg_id); + if (ret) + mlx5hws_err(ctx, "Failed creating modify header arg\n"); + + return ret; +} + +static int +hws_action_modify_check_field_limitation(u8 action_type, __be64 *pattern) +{ + /* Need to check field limitation here, but for now - return OK */ + return 0; +} + +#define INVALID_FIELD 0xffff + +static void +hws_action_modify_get_target_fields(u8 action_type, __be64 *pattern, + u16 *src_field, u16 *dst_field) +{ + switch (action_type) { + case MLX5_ACTION_TYPE_SET: + case MLX5_ACTION_TYPE_ADD: + *src_field = MLX5_GET(set_action_in, pattern, field); + *dst_field = INVALID_FIELD; + break; + case MLX5_ACTION_TYPE_COPY: + *src_field = MLX5_GET(copy_action_in, pattern, src_field); + *dst_field = MLX5_GET(copy_action_in, pattern, dst_field); + break; + default: + pr_warn("HWS: invalid modify header action type %d\n", action_type); + } +} + +bool mlx5hws_pat_verify_actions(struct mlx5hws_context *ctx, __be64 pattern[], size_t sz) +{ + size_t i; + + for (i = 0; i < sz / MLX5HWS_MODIFY_ACTION_SIZE; i++) { + u8 action_type = + MLX5_GET(set_action_in, &pattern[i], action_type); + if (action_type >= MLX5_MODIFICATION_TYPE_MAX) { + mlx5hws_err(ctx, "Unsupported action id %d\n", action_type); + return false; + } + if (hws_action_modify_check_field_limitation(action_type, &pattern[i])) { + mlx5hws_err(ctx, "Unsupported action number %zu\n", i); + return false; + } + } + + return true; +} + +void mlx5hws_pat_calc_nope(__be64 *pattern, size_t num_actions, + size_t max_actions, size_t *new_size, + u32 *nope_location, __be64 *new_pat) +{ + u16 prev_src_field = 0, prev_dst_field = 0; + u16 src_field, dst_field; + u8 action_type; + size_t i, j; + + *new_size = num_actions; + *nope_location = 0; + + if (num_actions == 1) + return; + + for (i = 0, j = 0; i < num_actions; i++, j++) { + action_type = MLX5_GET(set_action_in, &pattern[i], action_type); + + hws_action_modify_get_target_fields(action_type, &pattern[i], + &src_field, &dst_field); + if (i % 2) { + if (action_type == MLX5_ACTION_TYPE_COPY && + (prev_src_field == src_field || + prev_dst_field == dst_field)) { + /* need Nope */ + *new_size += 1; + *nope_location |= BIT(i); + memset(&new_pat[j], 0, MLX5HWS_MODIFY_ACTION_SIZE); + MLX5_SET(set_action_in, &new_pat[j], + action_type, + MLX5_MODIFICATION_TYPE_NOP); + j++; + } else if (prev_src_field == src_field) { + /* need Nope*/ + *new_size += 1; + *nope_location |= BIT(i); + MLX5_SET(set_action_in, &new_pat[j], + action_type, + MLX5_MODIFICATION_TYPE_NOP); + j++; + } + } + memcpy(&new_pat[j], &pattern[i], MLX5HWS_MODIFY_ACTION_SIZE); + /* check if no more space */ + if (j > max_actions) { + *new_size = num_actions; + *nope_location = 0; + return; + } + + prev_src_field = src_field; + prev_dst_field = dst_field; + } +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.h new file mode 100644 index 00000000000000..27ca93385b0841 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pat_arg.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef MLX5HWS_PAT_ARG_H_ +#define MLX5HWS_PAT_ARG_H_ + +/* Modify-header arg pool */ +enum mlx5hws_arg_chunk_size { + MLX5HWS_ARG_CHUNK_SIZE_1, + /* Keep MIN updated when changing */ + MLX5HWS_ARG_CHUNK_SIZE_MIN = MLX5HWS_ARG_CHUNK_SIZE_1, + MLX5HWS_ARG_CHUNK_SIZE_2, + MLX5HWS_ARG_CHUNK_SIZE_3, + MLX5HWS_ARG_CHUNK_SIZE_4, + MLX5HWS_ARG_CHUNK_SIZE_MAX, +}; + +enum { + MLX5HWS_MODIFY_ACTION_SIZE = 8, + MLX5HWS_ARG_DATA_SIZE = 64, +}; + +struct mlx5hws_pattern_cache { + struct mutex lock; /* Protect pattern list */ + struct list_head ptrn_list; +}; + +struct mlx5hws_pattern_cache_item { + struct { + u32 pattern_id; + u8 *data; + u16 num_of_actions; + } mh_data; + u32 refcount; + struct list_head ptrn_list_node; +}; + +enum mlx5hws_arg_chunk_size +mlx5hws_arg_get_arg_log_size(u16 num_of_actions); + +u32 mlx5hws_arg_get_arg_size(u16 num_of_actions); + +enum mlx5hws_arg_chunk_size +mlx5hws_arg_data_size_to_arg_log_size(u16 data_size); + +u32 mlx5hws_arg_data_size_to_arg_size(u16 data_size); + +int mlx5hws_pat_init_pattern_cache(struct mlx5hws_pattern_cache **cache); + +void mlx5hws_pat_uninit_pattern_cache(struct mlx5hws_pattern_cache *cache); + +bool mlx5hws_pat_verify_actions(struct mlx5hws_context *ctx, __be64 pattern[], size_t sz); + +int mlx5hws_arg_create(struct mlx5hws_context *ctx, + u8 *data, + size_t data_sz, + u32 log_bulk_sz, + bool write_data, + u32 *arg_id); + +void mlx5hws_arg_destroy(struct mlx5hws_context *ctx, u32 arg_id); + +int mlx5hws_arg_create_modify_header_arg(struct mlx5hws_context *ctx, + __be64 *data, + u8 num_of_actions, + u32 log_bulk_sz, + bool write_data, + u32 *modify_hdr_arg_id); + +int mlx5hws_pat_get_pattern(struct mlx5hws_context *ctx, + __be64 *pattern, + size_t pattern_sz, + u32 *ptrn_id); + +void mlx5hws_pat_put_pattern(struct mlx5hws_context *ctx, + u32 ptrn_id); + +bool mlx5hws_arg_is_valid_arg_request_size(struct mlx5hws_context *ctx, + u32 arg_size); + +bool mlx5hws_pat_require_reparse(__be64 *actions, u16 num_of_actions); + +void mlx5hws_arg_write(struct mlx5hws_send_engine *queue, + void *comp_data, + u32 arg_idx, + u8 *arg_data, + size_t data_size); + +void mlx5hws_arg_decapl3_write(struct mlx5hws_send_engine *queue, + u32 arg_idx, + u8 *arg_data, + u16 num_of_actions); + +int mlx5hws_arg_write_inline_arg_data(struct mlx5hws_context *ctx, + u32 arg_idx, + u8 *arg_data, + size_t data_size); + +void mlx5hws_pat_calc_nope(__be64 *pattern, size_t num_actions, size_t max_actions, + size_t *new_size, u32 *nope_location, __be64 *new_pat); +#endif /* MLX5HWS_PAT_ARG_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c new file mode 100644 index 00000000000000..fed2d913f3b89f --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c @@ -0,0 +1,640 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" +#include "buddy.h" + +static void hws_pool_free_one_resource(struct mlx5hws_pool_resource *resource) +{ + switch (resource->pool->type) { + case MLX5HWS_POOL_TYPE_STE: + mlx5hws_cmd_ste_destroy(resource->pool->ctx->mdev, resource->base_id); + break; + case MLX5HWS_POOL_TYPE_STC: + mlx5hws_cmd_stc_destroy(resource->pool->ctx->mdev, resource->base_id); + break; + default: + break; + } + + kfree(resource); +} + +static void hws_pool_resource_free(struct mlx5hws_pool *pool, + int resource_idx) +{ + hws_pool_free_one_resource(pool->resource[resource_idx]); + pool->resource[resource_idx] = NULL; + + if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) { + hws_pool_free_one_resource(pool->mirror_resource[resource_idx]); + pool->mirror_resource[resource_idx] = NULL; + } +} + +static struct mlx5hws_pool_resource * +hws_pool_create_one_resource(struct mlx5hws_pool *pool, u32 log_range, + u32 fw_ft_type) +{ + struct mlx5hws_cmd_ste_create_attr ste_attr; + struct mlx5hws_cmd_stc_create_attr stc_attr; + struct mlx5hws_pool_resource *resource; + u32 obj_id = 0; + int ret; + + resource = kzalloc(sizeof(*resource), GFP_KERNEL); + if (!resource) + return NULL; + + switch (pool->type) { + case MLX5HWS_POOL_TYPE_STE: + ste_attr.log_obj_range = log_range; + ste_attr.table_type = fw_ft_type; + ret = mlx5hws_cmd_ste_create(pool->ctx->mdev, &ste_attr, &obj_id); + break; + case MLX5HWS_POOL_TYPE_STC: + stc_attr.log_obj_range = log_range; + stc_attr.table_type = fw_ft_type; + ret = mlx5hws_cmd_stc_create(pool->ctx->mdev, &stc_attr, &obj_id); + break; + default: + ret = -EINVAL; + } + + if (ret) { + mlx5hws_err(pool->ctx, "Failed to allocate resource objects\n"); + goto free_resource; + } + + resource->pool = pool; + resource->range = 1 << log_range; + resource->base_id = obj_id; + + return resource; + +free_resource: + kfree(resource); + return NULL; +} + +static int +hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range, int idx) +{ + struct mlx5hws_pool_resource *resource; + u32 fw_ft_type, opt_log_range; + + fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, false); + opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_ORIG ? 0 : log_range; + resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type); + if (!resource) { + mlx5hws_err(pool->ctx, "Failed allocating resource\n"); + return -EINVAL; + } + + pool->resource[idx] = resource; + + if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) { + struct mlx5hws_pool_resource *mirror_resource; + + fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, true); + opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_MIRROR ? 0 : log_range; + mirror_resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type); + if (!mirror_resource) { + mlx5hws_err(pool->ctx, "Failed allocating mirrored resource\n"); + hws_pool_free_one_resource(resource); + pool->resource[idx] = NULL; + return -EINVAL; + } + pool->mirror_resource[idx] = mirror_resource; + } + + return 0; +} + +static unsigned long *hws_pool_create_and_init_bitmap(u32 log_range) +{ + unsigned long *cur_bmp; + + cur_bmp = bitmap_zalloc(1 << log_range, GFP_KERNEL); + if (!cur_bmp) + return NULL; + + bitmap_fill(cur_bmp, 1 << log_range); + + return cur_bmp; +} + +static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + struct mlx5hws_buddy_mem *buddy; + + buddy = pool->db.buddy_manager->buddies[chunk->resource_idx]; + if (!buddy) { + mlx5hws_err(pool->ctx, "No such buddy (%d)\n", chunk->resource_idx); + return; + } + + mlx5hws_buddy_free_mem(buddy, chunk->offset, chunk->order); +} + +static struct mlx5hws_buddy_mem * +hws_pool_buddy_get_next_buddy(struct mlx5hws_pool *pool, int idx, + u32 order, bool *is_new_buddy) +{ + static struct mlx5hws_buddy_mem *buddy; + u32 new_buddy_size; + + buddy = pool->db.buddy_manager->buddies[idx]; + if (buddy) + return buddy; + + new_buddy_size = max(pool->alloc_log_sz, order); + *is_new_buddy = true; + buddy = mlx5hws_buddy_create(new_buddy_size); + if (!buddy) { + mlx5hws_err(pool->ctx, "Failed to create buddy order: %d index: %d\n", + new_buddy_size, idx); + return NULL; + } + + if (hws_pool_resource_alloc(pool, new_buddy_size, idx) != 0) { + mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", + pool->type, new_buddy_size, idx); + mlx5hws_buddy_cleanup(buddy); + return NULL; + } + + pool->db.buddy_manager->buddies[idx] = buddy; + + return buddy; +} + +static int hws_pool_buddy_get_mem_chunk(struct mlx5hws_pool *pool, + int order, + u32 *buddy_idx, + int *seg) +{ + struct mlx5hws_buddy_mem *buddy; + bool new_mem = false; + int ret = 0; + int i; + + *seg = -1; + + /* Find the next free place from the buddy array */ + while (*seg == -1) { + for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { + buddy = hws_pool_buddy_get_next_buddy(pool, i, + order, + &new_mem); + if (!buddy) { + ret = -ENOMEM; + goto out; + } + + *seg = mlx5hws_buddy_alloc_mem(buddy, order); + if (*seg != -1) + goto found; + + if (pool->flags & MLX5HWS_POOL_FLAGS_ONE_RESOURCE) { + mlx5hws_err(pool->ctx, + "Fail to allocate seg for one resource pool\n"); + ret = -ENOMEM; + goto out; + } + + if (new_mem) { + /* We have new memory pool, should be place for us */ + mlx5hws_err(pool->ctx, + "No memory for order: %d with buddy no: %d\n", + order, i); + ret = -ENOMEM; + goto out; + } + } + } + +found: + *buddy_idx = i; +out: + return ret; +} + +static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + int ret = 0; + + /* Go over the buddies and find next free slot */ + ret = hws_pool_buddy_get_mem_chunk(pool, chunk->order, + &chunk->resource_idx, + &chunk->offset); + if (ret) + mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", + chunk->order); + + return ret; +} + +static void hws_pool_buddy_db_uninit(struct mlx5hws_pool *pool) +{ + struct mlx5hws_buddy_mem *buddy; + int i; + + for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { + buddy = pool->db.buddy_manager->buddies[i]; + if (buddy) { + mlx5hws_buddy_cleanup(buddy); + kfree(buddy); + pool->db.buddy_manager->buddies[i] = NULL; + } + } + + kfree(pool->db.buddy_manager); +} + +static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool, u32 log_range) +{ + pool->db.buddy_manager = kzalloc(sizeof(*pool->db.buddy_manager), GFP_KERNEL); + if (!pool->db.buddy_manager) + return -ENOMEM; + + if (pool->flags & MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE) { + bool new_buddy; + + if (!hws_pool_buddy_get_next_buddy(pool, 0, log_range, &new_buddy)) { + mlx5hws_err(pool->ctx, + "Failed allocating memory on create log_sz: %d\n", log_range); + kfree(pool->db.buddy_manager); + return -ENOMEM; + } + } + + pool->p_db_uninit = &hws_pool_buddy_db_uninit; + pool->p_get_chunk = &hws_pool_buddy_db_get_chunk; + pool->p_put_chunk = &hws_pool_buddy_db_put_chunk; + + return 0; +} + +static int hws_pool_create_resource_on_index(struct mlx5hws_pool *pool, + u32 alloc_size, int idx) +{ + int ret = hws_pool_resource_alloc(pool, alloc_size, idx); + + if (ret) { + mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", + pool->type, alloc_size, idx); + return ret; + } + + return 0; +} + +static struct mlx5hws_pool_elements * +hws_pool_element_create_new_elem(struct mlx5hws_pool *pool, u32 order, int idx) +{ + struct mlx5hws_pool_elements *elem; + u32 alloc_size; + + alloc_size = pool->alloc_log_sz; + + elem = kzalloc(sizeof(*elem), GFP_KERNEL); + if (!elem) + return NULL; + + /* Sharing the same resource, also means that all the elements are with size 1 */ + if ((pool->flags & MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS) && + !(pool->flags & MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK)) { + /* Currently all chunks in size 1 */ + elem->bitmap = hws_pool_create_and_init_bitmap(alloc_size - order); + if (!elem->bitmap) { + mlx5hws_err(pool->ctx, + "Failed to create bitmap type: %d: size %d index: %d\n", + pool->type, alloc_size, idx); + goto free_elem; + } + + elem->log_size = alloc_size - order; + } + + if (hws_pool_create_resource_on_index(pool, alloc_size, idx)) { + mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", + pool->type, alloc_size, idx); + goto free_db; + } + + pool->db.element_manager->elements[idx] = elem; + + return elem; + +free_db: + bitmap_free(elem->bitmap); +free_elem: + kfree(elem); + return NULL; +} + +static int hws_pool_element_find_seg(struct mlx5hws_pool_elements *elem, int *seg) +{ + unsigned int segment, size; + + size = 1 << elem->log_size; + + segment = find_first_bit(elem->bitmap, size); + if (segment >= size) { + elem->is_full = true; + return -ENOMEM; + } + + bitmap_clear(elem->bitmap, segment, 1); + *seg = segment; + return 0; +} + +static int +hws_pool_onesize_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order, + u32 *idx, int *seg) +{ + struct mlx5hws_pool_elements *elem; + + elem = pool->db.element_manager->elements[0]; + if (!elem) + elem = hws_pool_element_create_new_elem(pool, order, 0); + if (!elem) + goto err_no_elem; + + if (hws_pool_element_find_seg(elem, seg) != 0) { + mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order); + return -ENOMEM; + } + + *idx = 0; + elem->num_of_elements++; + return 0; + +err_no_elem: + mlx5hws_err(pool->ctx, "Failed to allocate element for order: %d\n", order); + return -ENOMEM; +} + +static int +hws_pool_general_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order, + u32 *idx, int *seg) +{ + int ret, i; + + for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { + if (!pool->resource[i]) { + ret = hws_pool_create_resource_on_index(pool, order, i); + if (ret) + goto err_no_res; + *idx = i; + *seg = 0; /* One memory slot in that element */ + return 0; + } + } + + mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order); + return -ENOMEM; + +err_no_res: + mlx5hws_err(pool->ctx, "Failed to allocate element for order: %d\n", order); + return -ENOMEM; +} + +static int hws_pool_general_element_db_get_chunk(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + int ret; + + /* Go over all memory elements and find/allocate free slot */ + ret = hws_pool_general_element_get_mem_chunk(pool, chunk->order, + &chunk->resource_idx, + &chunk->offset); + if (ret) + mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", + chunk->order); + + return ret; +} + +static void hws_pool_general_element_db_put_chunk(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + if (unlikely(!pool->resource[chunk->resource_idx])) + pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); + + if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE) + hws_pool_resource_free(pool, chunk->resource_idx); +} + +static void hws_pool_general_element_db_uninit(struct mlx5hws_pool *pool) +{ + (void)pool; +} + +/* This memory management works as the following: + * - At start doesn't allocate no mem at all. + * - When new request for chunk arrived: + * allocate resource and give it. + * - When free that chunk: + * the resource is freed. + */ +static int hws_pool_general_element_db_init(struct mlx5hws_pool *pool) +{ + pool->p_db_uninit = &hws_pool_general_element_db_uninit; + pool->p_get_chunk = &hws_pool_general_element_db_get_chunk; + pool->p_put_chunk = &hws_pool_general_element_db_put_chunk; + + return 0; +} + +static void hws_onesize_element_db_destroy_element(struct mlx5hws_pool *pool, + struct mlx5hws_pool_elements *elem, + struct mlx5hws_pool_chunk *chunk) +{ + if (unlikely(!pool->resource[chunk->resource_idx])) + pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); + + hws_pool_resource_free(pool, chunk->resource_idx); + kfree(elem); + pool->db.element_manager->elements[chunk->resource_idx] = NULL; +} + +static void hws_onesize_element_db_put_chunk(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + struct mlx5hws_pool_elements *elem; + + if (unlikely(chunk->resource_idx)) + pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); + + elem = pool->db.element_manager->elements[chunk->resource_idx]; + if (!elem) { + mlx5hws_err(pool->ctx, "No such element (%d)\n", chunk->resource_idx); + return; + } + + bitmap_set(elem->bitmap, chunk->offset, 1); + elem->is_full = false; + elem->num_of_elements--; + + if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE && + !elem->num_of_elements) + hws_onesize_element_db_destroy_element(pool, elem, chunk); +} + +static int hws_onesize_element_db_get_chunk(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + int ret = 0; + + /* Go over all memory elements and find/allocate free slot */ + ret = hws_pool_onesize_element_get_mem_chunk(pool, chunk->order, + &chunk->resource_idx, + &chunk->offset); + if (ret) + mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", + chunk->order); + + return ret; +} + +static void hws_onesize_element_db_uninit(struct mlx5hws_pool *pool) +{ + struct mlx5hws_pool_elements *elem; + int i; + + for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { + elem = pool->db.element_manager->elements[i]; + if (elem) { + bitmap_free(elem->bitmap); + kfree(elem); + pool->db.element_manager->elements[i] = NULL; + } + } + kfree(pool->db.element_manager); +} + +/* This memory management works as the following: + * - At start doesn't allocate no mem at all. + * - When new request for chunk arrived: + * aloocate the first and only slot of memory/resource + * when it ended return error. + */ +static int hws_pool_onesize_element_db_init(struct mlx5hws_pool *pool) +{ + pool->db.element_manager = kzalloc(sizeof(*pool->db.element_manager), GFP_KERNEL); + if (!pool->db.element_manager) + return -ENOMEM; + + pool->p_db_uninit = &hws_onesize_element_db_uninit; + pool->p_get_chunk = &hws_onesize_element_db_get_chunk; + pool->p_put_chunk = &hws_onesize_element_db_put_chunk; + + return 0; +} + +static int hws_pool_db_init(struct mlx5hws_pool *pool, + enum mlx5hws_db_type db_type) +{ + int ret; + + if (db_type == MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE) + ret = hws_pool_general_element_db_init(pool); + else if (db_type == MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE) + ret = hws_pool_onesize_element_db_init(pool); + else + ret = hws_pool_buddy_db_init(pool, pool->alloc_log_sz); + + if (ret) { + mlx5hws_err(pool->ctx, "Failed to init general db : %d (ret: %d)\n", db_type, ret); + return ret; + } + + return 0; +} + +static void hws_pool_db_unint(struct mlx5hws_pool *pool) +{ + pool->p_db_uninit(pool); +} + +int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + int ret; + + mutex_lock(&pool->lock); + ret = pool->p_get_chunk(pool, chunk); + mutex_unlock(&pool->lock); + + return ret; +} + +void mlx5hws_pool_chunk_free(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + mutex_lock(&pool->lock); + pool->p_put_chunk(pool, chunk); + mutex_unlock(&pool->lock); +} + +struct mlx5hws_pool * +mlx5hws_pool_create(struct mlx5hws_context *ctx, struct mlx5hws_pool_attr *pool_attr) +{ + enum mlx5hws_db_type res_db_type; + struct mlx5hws_pool *pool; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return NULL; + + pool->ctx = ctx; + pool->type = pool_attr->pool_type; + pool->alloc_log_sz = pool_attr->alloc_log_sz; + pool->flags = pool_attr->flags; + pool->tbl_type = pool_attr->table_type; + pool->opt_type = pool_attr->opt_type; + + /* Support general db */ + if (pool->flags == (MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE | + MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK)) + res_db_type = MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE; + else if (pool->flags == (MLX5HWS_POOL_FLAGS_ONE_RESOURCE | + MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS)) + res_db_type = MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE; + else + res_db_type = MLX5HWS_POOL_DB_TYPE_BUDDY; + + pool->alloc_log_sz = pool_attr->alloc_log_sz; + + if (hws_pool_db_init(pool, res_db_type)) + goto free_pool; + + mutex_init(&pool->lock); + + return pool; + +free_pool: + kfree(pool); + return NULL; +} + +int mlx5hws_pool_destroy(struct mlx5hws_pool *pool) +{ + int i; + + mutex_destroy(&pool->lock); + + for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) + if (pool->resource[i]) + hws_pool_resource_free(pool, i); + + hws_pool_db_unint(pool); + + kfree(pool); + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.h new file mode 100644 index 00000000000000..621298b352b244 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef MLX5HWS_POOL_H_ +#define MLX5HWS_POOL_H_ + +#define MLX5HWS_POOL_STC_LOG_SZ 15 + +#define MLX5HWS_POOL_RESOURCE_ARR_SZ 100 + +enum mlx5hws_pool_type { + MLX5HWS_POOL_TYPE_STE, + MLX5HWS_POOL_TYPE_STC, +}; + +struct mlx5hws_pool_chunk { + u32 resource_idx; + /* Internal offset, relative to base index */ + int offset; + int order; +}; + +struct mlx5hws_pool_resource { + struct mlx5hws_pool *pool; + u32 base_id; + u32 range; +}; + +enum mlx5hws_pool_flags { + /* Only a one resource in that pool */ + MLX5HWS_POOL_FLAGS_ONE_RESOURCE = 1 << 0, + MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE = 1 << 1, + /* No sharing resources between chunks */ + MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK = 1 << 2, + /* All objects are in the same size */ + MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS = 1 << 3, + /* Managed by buddy allocator */ + MLX5HWS_POOL_FLAGS_BUDDY_MANAGED = 1 << 4, + /* Allocate pool_type memory on pool creation */ + MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE = 1 << 5, + + /* These values should be used by the caller */ + MLX5HWS_POOL_FLAGS_FOR_STC_POOL = + MLX5HWS_POOL_FLAGS_ONE_RESOURCE | + MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS, + MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL = + MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE | + MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK, + MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL = + MLX5HWS_POOL_FLAGS_ONE_RESOURCE | + MLX5HWS_POOL_FLAGS_BUDDY_MANAGED | + MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE, +}; + +enum mlx5hws_pool_optimize { + MLX5HWS_POOL_OPTIMIZE_NONE = 0x0, + MLX5HWS_POOL_OPTIMIZE_ORIG = 0x1, + MLX5HWS_POOL_OPTIMIZE_MIRROR = 0x2, +}; + +struct mlx5hws_pool_attr { + enum mlx5hws_pool_type pool_type; + enum mlx5hws_table_type table_type; + enum mlx5hws_pool_flags flags; + enum mlx5hws_pool_optimize opt_type; + /* Allocation size once memory is depleted */ + size_t alloc_log_sz; +}; + +enum mlx5hws_db_type { + /* Uses for allocating chunk of big memory, each element has its own resource in the FW*/ + MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE, + /* One resource only, all the elements are with same one size */ + MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE, + /* Many resources, the memory allocated with buddy mechanism */ + MLX5HWS_POOL_DB_TYPE_BUDDY, +}; + +struct mlx5hws_buddy_manager { + struct mlx5hws_buddy_mem *buddies[MLX5HWS_POOL_RESOURCE_ARR_SZ]; +}; + +struct mlx5hws_pool_elements { + u32 num_of_elements; + unsigned long *bitmap; + u32 log_size; + bool is_full; +}; + +struct mlx5hws_element_manager { + struct mlx5hws_pool_elements *elements[MLX5HWS_POOL_RESOURCE_ARR_SZ]; +}; + +struct mlx5hws_pool_db { + enum mlx5hws_db_type type; + union { + struct mlx5hws_element_manager *element_manager; + struct mlx5hws_buddy_manager *buddy_manager; + }; +}; + +typedef int (*mlx5hws_pool_db_get_chunk)(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk); +typedef void (*mlx5hws_pool_db_put_chunk)(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk); +typedef void (*mlx5hws_pool_unint_db)(struct mlx5hws_pool *pool); + +struct mlx5hws_pool { + struct mlx5hws_context *ctx; + enum mlx5hws_pool_type type; + enum mlx5hws_pool_flags flags; + struct mutex lock; /* protect the pool */ + size_t alloc_log_sz; + enum mlx5hws_table_type tbl_type; + enum mlx5hws_pool_optimize opt_type; + struct mlx5hws_pool_resource *resource[MLX5HWS_POOL_RESOURCE_ARR_SZ]; + struct mlx5hws_pool_resource *mirror_resource[MLX5HWS_POOL_RESOURCE_ARR_SZ]; + /* DB */ + struct mlx5hws_pool_db db; + /* Functions */ + mlx5hws_pool_unint_db p_db_uninit; + mlx5hws_pool_db_get_chunk p_get_chunk; + mlx5hws_pool_db_put_chunk p_put_chunk; +}; + +struct mlx5hws_pool * +mlx5hws_pool_create(struct mlx5hws_context *ctx, + struct mlx5hws_pool_attr *pool_attr); + +int mlx5hws_pool_destroy(struct mlx5hws_pool *pool); + +int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk); + +void mlx5hws_pool_chunk_free(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk); + +static inline u32 +mlx5hws_pool_chunk_get_base_id(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + return pool->resource[chunk->resource_idx]->base_id; +} + +static inline u32 +mlx5hws_pool_chunk_get_base_mirror_id(struct mlx5hws_pool *pool, + struct mlx5hws_pool_chunk *chunk) +{ + return pool->mirror_resource[chunk->resource_idx]->base_id; +} +#endif /* MLX5HWS_POOL_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/prm.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/prm.h new file mode 100644 index 00000000000000..de92cecbeb928a --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/prm.h @@ -0,0 +1,514 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef MLX5_PRM_H_ +#define MLX5_PRM_H_ + +#define MLX5_MAX_ACTIONS_DATA_IN_HEADER_MODIFY 512 + +/* Action type of header modification. */ +enum { + MLX5_MODIFICATION_TYPE_SET = 0x1, + MLX5_MODIFICATION_TYPE_ADD = 0x2, + MLX5_MODIFICATION_TYPE_COPY = 0x3, + MLX5_MODIFICATION_TYPE_INSERT = 0x4, + MLX5_MODIFICATION_TYPE_REMOVE = 0x5, + MLX5_MODIFICATION_TYPE_NOP = 0x6, + MLX5_MODIFICATION_TYPE_REMOVE_WORDS = 0x7, + MLX5_MODIFICATION_TYPE_ADD_FIELD = 0x8, + MLX5_MODIFICATION_TYPE_MAX, +}; + +/* The field of packet to be modified. */ +enum mlx5_modification_field { + MLX5_MODI_OUT_NONE = -1, + MLX5_MODI_OUT_SMAC_47_16 = 1, + MLX5_MODI_OUT_SMAC_15_0, + MLX5_MODI_OUT_ETHERTYPE, + MLX5_MODI_OUT_DMAC_47_16, + MLX5_MODI_OUT_DMAC_15_0, + MLX5_MODI_OUT_IP_DSCP, + MLX5_MODI_OUT_TCP_FLAGS, + MLX5_MODI_OUT_TCP_SPORT, + MLX5_MODI_OUT_TCP_DPORT, + MLX5_MODI_OUT_IPV4_TTL, + MLX5_MODI_OUT_UDP_SPORT, + MLX5_MODI_OUT_UDP_DPORT, + MLX5_MODI_OUT_SIPV6_127_96, + MLX5_MODI_OUT_SIPV6_95_64, + MLX5_MODI_OUT_SIPV6_63_32, + MLX5_MODI_OUT_SIPV6_31_0, + MLX5_MODI_OUT_DIPV6_127_96, + MLX5_MODI_OUT_DIPV6_95_64, + MLX5_MODI_OUT_DIPV6_63_32, + MLX5_MODI_OUT_DIPV6_31_0, + MLX5_MODI_OUT_SIPV4, + MLX5_MODI_OUT_DIPV4, + MLX5_MODI_OUT_FIRST_VID, + MLX5_MODI_IN_SMAC_47_16 = 0x31, + MLX5_MODI_IN_SMAC_15_0, + MLX5_MODI_IN_ETHERTYPE, + MLX5_MODI_IN_DMAC_47_16, + MLX5_MODI_IN_DMAC_15_0, + MLX5_MODI_IN_IP_DSCP, + MLX5_MODI_IN_TCP_FLAGS, + MLX5_MODI_IN_TCP_SPORT, + MLX5_MODI_IN_TCP_DPORT, + MLX5_MODI_IN_IPV4_TTL, + MLX5_MODI_IN_UDP_SPORT, + MLX5_MODI_IN_UDP_DPORT, + MLX5_MODI_IN_SIPV6_127_96, + MLX5_MODI_IN_SIPV6_95_64, + MLX5_MODI_IN_SIPV6_63_32, + MLX5_MODI_IN_SIPV6_31_0, + MLX5_MODI_IN_DIPV6_127_96, + MLX5_MODI_IN_DIPV6_95_64, + MLX5_MODI_IN_DIPV6_63_32, + MLX5_MODI_IN_DIPV6_31_0, + MLX5_MODI_IN_SIPV4, + MLX5_MODI_IN_DIPV4, + MLX5_MODI_OUT_IPV6_HOPLIMIT, + MLX5_MODI_IN_IPV6_HOPLIMIT, + MLX5_MODI_META_DATA_REG_A, + MLX5_MODI_META_DATA_REG_B = 0x50, + MLX5_MODI_META_REG_C_0, + MLX5_MODI_META_REG_C_1, + MLX5_MODI_META_REG_C_2, + MLX5_MODI_META_REG_C_3, + MLX5_MODI_META_REG_C_4, + MLX5_MODI_META_REG_C_5, + MLX5_MODI_META_REG_C_6, + MLX5_MODI_META_REG_C_7, + MLX5_MODI_OUT_TCP_SEQ_NUM, + MLX5_MODI_IN_TCP_SEQ_NUM, + MLX5_MODI_OUT_TCP_ACK_NUM, + MLX5_MODI_IN_TCP_ACK_NUM = 0x5C, + MLX5_MODI_GTP_TEID = 0x6E, + MLX5_MODI_OUT_IP_ECN = 0x73, + MLX5_MODI_TUNNEL_HDR_DW_1 = 0x75, + MLX5_MODI_GTPU_FIRST_EXT_DW_0 = 0x76, + MLX5_MODI_HASH_RESULT = 0x81, + MLX5_MODI_IN_MPLS_LABEL_0 = 0x8a, + MLX5_MODI_IN_MPLS_LABEL_1, + MLX5_MODI_IN_MPLS_LABEL_2, + MLX5_MODI_IN_MPLS_LABEL_3, + MLX5_MODI_IN_MPLS_LABEL_4, + MLX5_MODI_OUT_IP_PROTOCOL = 0x4A, + MLX5_MODI_OUT_IPV6_NEXT_HDR = 0x4A, + MLX5_MODI_META_REG_C_8 = 0x8F, + MLX5_MODI_META_REG_C_9 = 0x90, + MLX5_MODI_META_REG_C_10 = 0x91, + MLX5_MODI_META_REG_C_11 = 0x92, + MLX5_MODI_META_REG_C_12 = 0x93, + MLX5_MODI_META_REG_C_13 = 0x94, + MLX5_MODI_META_REG_C_14 = 0x95, + MLX5_MODI_META_REG_C_15 = 0x96, + MLX5_MODI_OUT_IPV4_TOTAL_LEN = 0x11D, + MLX5_MODI_OUT_IPV6_PAYLOAD_LEN = 0x11E, + MLX5_MODI_OUT_IPV4_IHL = 0x11F, + MLX5_MODI_OUT_TCP_DATA_OFFSET = 0x120, + MLX5_MODI_OUT_ESP_SPI = 0x5E, + MLX5_MODI_OUT_ESP_SEQ_NUM = 0x82, + MLX5_MODI_OUT_IPSEC_NEXT_HDR = 0x126, + MLX5_MODI_INVALID = INT_MAX, +}; + +enum { + MLX5_GET_HCA_CAP_OP_MOD_NIC_FLOW_TABLE = 0x7 << 1, + MLX5_GET_HCA_CAP_OP_MOD_ESW_FLOW_TABLE = 0x8 << 1, + MLX5_SET_HCA_CAP_OP_MOD_ESW = 0x9 << 1, + MLX5_GET_HCA_CAP_OP_MOD_WQE_BASED_FLOW_TABLE = 0x1B << 1, + MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 = 0x20 << 1, +}; + +enum mlx5_ifc_rtc_update_mode { + MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH = 0x0, + MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET = 0x1, +}; + +enum mlx5_ifc_rtc_access_mode { + MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH = 0x0, + MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR = 0x1, +}; + +enum mlx5_ifc_rtc_ste_format { + MLX5_IFC_RTC_STE_FORMAT_8DW = 0x4, + MLX5_IFC_RTC_STE_FORMAT_11DW = 0x5, + MLX5_IFC_RTC_STE_FORMAT_RANGE = 0x7, +}; + +enum mlx5_ifc_rtc_reparse_mode { + MLX5_IFC_RTC_REPARSE_NEVER = 0x0, + MLX5_IFC_RTC_REPARSE_ALWAYS = 0x1, + MLX5_IFC_RTC_REPARSE_BY_STC = 0x2, +}; + +#define MLX5_IFC_RTC_LINEAR_LOOKUP_TBL_LOG_MAX 16 + +struct mlx5_ifc_rtc_bits { + u8 modify_field_select[0x40]; + u8 reserved_at_40[0x40]; + u8 update_index_mode[0x2]; + u8 reparse_mode[0x2]; + u8 num_match_ste[0x4]; + u8 pd[0x18]; + u8 reserved_at_a0[0x9]; + u8 access_index_mode[0x3]; + u8 num_hash_definer[0x4]; + u8 update_method[0x1]; + u8 reserved_at_b1[0x2]; + u8 log_depth[0x5]; + u8 log_hash_size[0x8]; + u8 ste_format_0[0x8]; + u8 table_type[0x8]; + u8 ste_format_1[0x8]; + u8 reserved_at_d8[0x8]; + u8 match_definer_0[0x20]; + u8 stc_id[0x20]; + u8 ste_table_base_id[0x20]; + u8 ste_table_offset[0x20]; + u8 reserved_at_160[0x8]; + u8 miss_flow_table_id[0x18]; + u8 match_definer_1[0x20]; + u8 reserved_at_1a0[0x260]; +}; + +enum mlx5_ifc_stc_action_type { + MLX5_IFC_STC_ACTION_TYPE_NOP = 0x00, + MLX5_IFC_STC_ACTION_TYPE_COPY = 0x05, + MLX5_IFC_STC_ACTION_TYPE_SET = 0x06, + MLX5_IFC_STC_ACTION_TYPE_ADD = 0x07, + MLX5_IFC_STC_ACTION_TYPE_REMOVE_WORDS = 0x08, + MLX5_IFC_STC_ACTION_TYPE_HEADER_REMOVE = 0x09, + MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT = 0x0b, + MLX5_IFC_STC_ACTION_TYPE_TAG = 0x0c, + MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST = 0x0e, + MLX5_IFC_STC_ACTION_TYPE_CRYPTO_IPSEC_ENCRYPTION = 0x10, + MLX5_IFC_STC_ACTION_TYPE_CRYPTO_IPSEC_DECRYPTION = 0x11, + MLX5_IFC_STC_ACTION_TYPE_ASO = 0x12, + MLX5_IFC_STC_ACTION_TYPE_TRAILER = 0x13, + MLX5_IFC_STC_ACTION_TYPE_COUNTER = 0x14, + MLX5_IFC_STC_ACTION_TYPE_ADD_FIELD = 0x1b, + MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE = 0x80, + MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_TIR = 0x81, + MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_FT = 0x82, + MLX5_IFC_STC_ACTION_TYPE_DROP = 0x83, + MLX5_IFC_STC_ACTION_TYPE_ALLOW = 0x84, + MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_VPORT = 0x85, + MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_UPLINK = 0x86, +}; + +enum mlx5_ifc_stc_reparse_mode { + MLX5_IFC_STC_REPARSE_IGNORE = 0x0, + MLX5_IFC_STC_REPARSE_NEVER = 0x1, + MLX5_IFC_STC_REPARSE_ALWAYS = 0x2, +}; + +struct mlx5_ifc_stc_ste_param_ste_table_bits { + u8 ste_obj_id[0x20]; + u8 match_definer_id[0x20]; + u8 reserved_at_40[0x3]; + u8 log_hash_size[0x5]; + u8 reserved_at_48[0x38]; +}; + +struct mlx5_ifc_stc_ste_param_tir_bits { + u8 reserved_at_0[0x8]; + u8 tirn[0x18]; + u8 reserved_at_20[0x60]; +}; + +struct mlx5_ifc_stc_ste_param_table_bits { + u8 reserved_at_0[0x8]; + u8 table_id[0x18]; + u8 reserved_at_20[0x60]; +}; + +struct mlx5_ifc_stc_ste_param_flow_counter_bits { + u8 flow_counter_id[0x20]; +}; + +enum { + MLX5_ASO_CT_NUM_PER_OBJ = 1, + MLX5_ASO_METER_NUM_PER_OBJ = 2, + MLX5_ASO_IPSEC_NUM_PER_OBJ = 1, + MLX5_ASO_FIRST_HIT_NUM_PER_OBJ = 512, +}; + +struct mlx5_ifc_stc_ste_param_execute_aso_bits { + u8 aso_object_id[0x20]; + u8 return_reg_id[0x4]; + u8 aso_type[0x4]; + u8 reserved_at_28[0x18]; +}; + +struct mlx5_ifc_stc_ste_param_ipsec_encrypt_bits { + u8 ipsec_object_id[0x20]; +}; + +struct mlx5_ifc_stc_ste_param_ipsec_decrypt_bits { + u8 ipsec_object_id[0x20]; +}; + +struct mlx5_ifc_stc_ste_param_trailer_bits { + u8 reserved_at_0[0x8]; + u8 command[0x4]; + u8 reserved_at_c[0x2]; + u8 type[0x2]; + u8 reserved_at_10[0xa]; + u8 length[0x6]; +}; + +struct mlx5_ifc_stc_ste_param_header_modify_list_bits { + u8 header_modify_pattern_id[0x20]; + u8 header_modify_argument_id[0x20]; +}; + +enum mlx5_ifc_header_anchors { + MLX5_HEADER_ANCHOR_PACKET_START = 0x0, + MLX5_HEADER_ANCHOR_MAC = 0x1, + MLX5_HEADER_ANCHOR_FIRST_VLAN_START = 0x2, + MLX5_HEADER_ANCHOR_IPV6_IPV4 = 0x07, + MLX5_HEADER_ANCHOR_ESP = 0x08, + MLX5_HEADER_ANCHOR_TCP_UDP = 0x09, + MLX5_HEADER_ANCHOR_TUNNEL_HEADER = 0x0a, + MLX5_HEADER_ANCHOR_INNER_MAC = 0x13, + MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4 = 0x19, + MLX5_HEADER_ANCHOR_INNER_TCP_UDP = 0x1a, + MLX5_HEADER_ANCHOR_L4_PAYLOAD = 0x1b, + MLX5_HEADER_ANCHOR_INNER_L4_PAYLOAD = 0x1c +}; + +struct mlx5_ifc_stc_ste_param_remove_bits { + u8 action_type[0x4]; + u8 decap[0x1]; + u8 reserved_at_5[0x5]; + u8 remove_start_anchor[0x6]; + u8 reserved_at_10[0x2]; + u8 remove_end_anchor[0x6]; + u8 reserved_at_18[0x8]; +}; + +struct mlx5_ifc_stc_ste_param_remove_words_bits { + u8 action_type[0x4]; + u8 reserved_at_4[0x6]; + u8 remove_start_anchor[0x6]; + u8 reserved_at_10[0x1]; + u8 remove_offset[0x7]; + u8 reserved_at_18[0x2]; + u8 remove_size[0x6]; +}; + +struct mlx5_ifc_stc_ste_param_insert_bits { + u8 action_type[0x4]; + u8 encap[0x1]; + u8 inline_data[0x1]; + u8 reserved_at_6[0x4]; + u8 insert_anchor[0x6]; + u8 reserved_at_10[0x1]; + u8 insert_offset[0x7]; + u8 reserved_at_18[0x1]; + u8 insert_size[0x7]; + u8 insert_argument[0x20]; +}; + +struct mlx5_ifc_stc_ste_param_vport_bits { + u8 eswitch_owner_vhca_id[0x10]; + u8 vport_number[0x10]; + u8 eswitch_owner_vhca_id_valid[0x1]; + u8 reserved_at_21[0x5f]; +}; + +union mlx5_ifc_stc_param_bits { + struct mlx5_ifc_stc_ste_param_ste_table_bits ste_table; + struct mlx5_ifc_stc_ste_param_tir_bits tir; + struct mlx5_ifc_stc_ste_param_table_bits table; + struct mlx5_ifc_stc_ste_param_flow_counter_bits counter; + struct mlx5_ifc_stc_ste_param_header_modify_list_bits modify_header; + struct mlx5_ifc_stc_ste_param_execute_aso_bits aso; + struct mlx5_ifc_stc_ste_param_remove_bits remove_header; + struct mlx5_ifc_stc_ste_param_insert_bits insert_header; + struct mlx5_ifc_set_action_in_bits add; + struct mlx5_ifc_set_action_in_bits set; + struct mlx5_ifc_copy_action_in_bits copy; + struct mlx5_ifc_stc_ste_param_vport_bits vport; + struct mlx5_ifc_stc_ste_param_ipsec_encrypt_bits ipsec_encrypt; + struct mlx5_ifc_stc_ste_param_ipsec_decrypt_bits ipsec_decrypt; + struct mlx5_ifc_stc_ste_param_trailer_bits trailer; + u8 reserved_at_0[0x80]; +}; + +enum { + MLX5_IFC_MODIFY_STC_FIELD_SELECT_NEW_STC = BIT(0), +}; + +struct mlx5_ifc_stc_bits { + u8 modify_field_select[0x40]; + u8 reserved_at_40[0x46]; + u8 reparse_mode[0x2]; + u8 table_type[0x8]; + u8 ste_action_offset[0x8]; + u8 action_type[0x8]; + u8 reserved_at_a0[0x60]; + union mlx5_ifc_stc_param_bits stc_param; + u8 reserved_at_180[0x280]; +}; + +struct mlx5_ifc_ste_bits { + u8 modify_field_select[0x40]; + u8 reserved_at_40[0x48]; + u8 table_type[0x8]; + u8 reserved_at_90[0x370]; +}; + +struct mlx5_ifc_definer_bits { + u8 modify_field_select[0x40]; + u8 reserved_at_40[0x50]; + u8 format_id[0x10]; + u8 reserved_at_60[0x60]; + u8 format_select_dw3[0x8]; + u8 format_select_dw2[0x8]; + u8 format_select_dw1[0x8]; + u8 format_select_dw0[0x8]; + u8 format_select_dw7[0x8]; + u8 format_select_dw6[0x8]; + u8 format_select_dw5[0x8]; + u8 format_select_dw4[0x8]; + u8 reserved_at_100[0x18]; + u8 format_select_dw8[0x8]; + u8 reserved_at_120[0x20]; + u8 format_select_byte3[0x8]; + u8 format_select_byte2[0x8]; + u8 format_select_byte1[0x8]; + u8 format_select_byte0[0x8]; + u8 format_select_byte7[0x8]; + u8 format_select_byte6[0x8]; + u8 format_select_byte5[0x8]; + u8 format_select_byte4[0x8]; + u8 reserved_at_180[0x40]; + u8 ctrl[0xa0]; + u8 match_mask[0x160]; +}; + +struct mlx5_ifc_arg_bits { + u8 rsvd0[0x88]; + u8 access_pd[0x18]; +}; + +struct mlx5_ifc_header_modify_pattern_in_bits { + u8 modify_field_select[0x40]; + + u8 reserved_at_40[0x40]; + + u8 pattern_length[0x8]; + u8 reserved_at_88[0x18]; + + u8 reserved_at_a0[0x60]; + + u8 pattern_data[MLX5_MAX_ACTIONS_DATA_IN_HEADER_MODIFY * 8]; +}; + +struct mlx5_ifc_create_rtc_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; + struct mlx5_ifc_rtc_bits rtc; +}; + +struct mlx5_ifc_create_stc_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; + struct mlx5_ifc_stc_bits stc; +}; + +struct mlx5_ifc_create_ste_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; + struct mlx5_ifc_ste_bits ste; +}; + +struct mlx5_ifc_create_definer_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; + struct mlx5_ifc_definer_bits definer; +}; + +struct mlx5_ifc_create_arg_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; + struct mlx5_ifc_arg_bits arg; +}; + +struct mlx5_ifc_create_header_modify_pattern_in_bits { + struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr; + struct mlx5_ifc_header_modify_pattern_in_bits pattern; +}; + +struct mlx5_ifc_generate_wqe_in_bits { + u8 opcode[0x10]; + u8 uid[0x10]; + u8 reserved_at_20[0x10]; + u8 op_mode[0x10]; + u8 reserved_at_40[0x40]; + u8 reserved_at_80[0x8]; + u8 pdn[0x18]; + u8 reserved_at_a0[0x160]; + u8 wqe_ctrl[0x80]; + u8 wqe_gta_ctrl[0x180]; + u8 wqe_gta_data_0[0x200]; + u8 wqe_gta_data_1[0x200]; +}; + +struct mlx5_ifc_generate_wqe_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + u8 syndrome[0x20]; + u8 reserved_at_40[0x1c0]; + u8 cqe_data[0x200]; +}; + +enum mlx5_access_aso_opc_mod { + ASO_OPC_MOD_IPSEC = 0x0, + ASO_OPC_MOD_CONNECTION_TRACKING = 0x1, + ASO_OPC_MOD_POLICER = 0x2, + ASO_OPC_MOD_RACE_AVOIDANCE = 0x3, + ASO_OPC_MOD_FLOW_HIT = 0x4, +}; + +enum { + MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION = BIT(0), + MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID = BIT(1), +}; + +enum { + MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_DEFAULT = 0, + MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL = 1, +}; + +struct mlx5_ifc_alloc_packet_reformat_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 packet_reformat_id[0x20]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_dealloc_packet_reformat_in_bits { + u8 opcode[0x10]; + u8 reserved_at_10[0x10]; + + u8 reserved_at_20[0x10]; + u8 op_mod[0x10]; + + u8 packet_reformat_id[0x20]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_dealloc_packet_reformat_out_bits { + u8 status[0x8]; + u8 reserved_at_8[0x18]; + + u8 syndrome[0x20]; + + u8 reserved_at_40[0x40]; +}; + +#endif /* MLX5_PRM_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c new file mode 100644 index 00000000000000..e20c67a04203fc --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c @@ -0,0 +1,780 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +static void hws_rule_skip(struct mlx5hws_matcher *matcher, + struct mlx5hws_match_template *mt, + u32 flow_source, + bool *skip_rx, bool *skip_tx) +{ + /* By default FDB rules are added to both RX and TX */ + *skip_rx = false; + *skip_tx = false; + + if (flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT) { + *skip_rx = true; + } else if (flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK) { + *skip_tx = true; + } else { + /* If no flow source was set for current rule, + * check for flow source in matcher attributes. + */ + if (matcher->attr.optimize_flow_src) { + *skip_tx = + matcher->attr.optimize_flow_src == MLX5HWS_MATCHER_FLOW_SRC_WIRE; + *skip_rx = + matcher->attr.optimize_flow_src == MLX5HWS_MATCHER_FLOW_SRC_VPORT; + return; + } + } +} + +static void +hws_rule_update_copy_tag(struct mlx5hws_rule *rule, + struct mlx5hws_wqe_gta_data_seg_ste *wqe_data, + bool is_jumbo) +{ + struct mlx5hws_rule_match_tag *tag; + + if (!mlx5hws_matcher_is_resizable(rule->matcher)) { + tag = &rule->tag; + } else { + struct mlx5hws_wqe_gta_data_seg_ste *data_seg = + (struct mlx5hws_wqe_gta_data_seg_ste *)(void *)rule->resize_info->data_seg; + tag = (struct mlx5hws_rule_match_tag *)(void *)data_seg->action; + } + + if (is_jumbo) + memcpy(wqe_data->jumbo, tag->jumbo, MLX5HWS_JUMBO_TAG_SZ); + else + memcpy(wqe_data->tag, tag->match, MLX5HWS_MATCH_TAG_SZ); +} + +static void hws_rule_init_dep_wqe(struct mlx5hws_send_ring_dep_wqe *dep_wqe, + struct mlx5hws_rule *rule, + struct mlx5hws_match_template *mt, + struct mlx5hws_rule_attr *attr) +{ + struct mlx5hws_matcher *matcher = rule->matcher; + struct mlx5hws_table *tbl = matcher->tbl; + bool skip_rx, skip_tx; + + dep_wqe->rule = rule; + dep_wqe->user_data = attr->user_data; + dep_wqe->direct_index = mlx5hws_matcher_is_insert_by_idx(matcher) ? + attr->rule_idx : 0; + + if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) { + hws_rule_skip(matcher, mt, attr->flow_source, &skip_rx, &skip_tx); + + if (!skip_rx) { + dep_wqe->rtc_0 = matcher->match_ste.rtc_0_id; + dep_wqe->retry_rtc_0 = matcher->col_matcher ? + matcher->col_matcher->match_ste.rtc_0_id : 0; + } else { + dep_wqe->rtc_0 = 0; + dep_wqe->retry_rtc_0 = 0; + } + + if (!skip_tx) { + dep_wqe->rtc_1 = matcher->match_ste.rtc_1_id; + dep_wqe->retry_rtc_1 = matcher->col_matcher ? + matcher->col_matcher->match_ste.rtc_1_id : 0; + } else { + dep_wqe->rtc_1 = 0; + dep_wqe->retry_rtc_1 = 0; + } + } else { + pr_warn("HWS: invalid tbl->type: %d\n", tbl->type); + } +} + +static void hws_rule_move_get_rtc(struct mlx5hws_rule *rule, + struct mlx5hws_send_ste_attr *ste_attr) +{ + struct mlx5hws_matcher *dst_matcher = rule->matcher->resize_dst; + + if (rule->resize_info->rtc_0) { + ste_attr->rtc_0 = dst_matcher->match_ste.rtc_0_id; + ste_attr->retry_rtc_0 = dst_matcher->col_matcher ? + dst_matcher->col_matcher->match_ste.rtc_0_id : 0; + } + if (rule->resize_info->rtc_1) { + ste_attr->rtc_1 = dst_matcher->match_ste.rtc_1_id; + ste_attr->retry_rtc_1 = dst_matcher->col_matcher ? + dst_matcher->col_matcher->match_ste.rtc_1_id : 0; + } +} + +static void hws_rule_gen_comp(struct mlx5hws_send_engine *queue, + struct mlx5hws_rule *rule, + bool err, + void *user_data, + enum mlx5hws_rule_status rule_status_on_succ) +{ + enum mlx5hws_flow_op_status comp_status; + + if (!err) { + comp_status = MLX5HWS_FLOW_OP_SUCCESS; + rule->status = rule_status_on_succ; + } else { + comp_status = MLX5HWS_FLOW_OP_ERROR; + rule->status = MLX5HWS_RULE_STATUS_FAILED; + } + + mlx5hws_send_engine_inc_rule(queue); + mlx5hws_send_engine_gen_comp(queue, user_data, comp_status); +} + +static void +hws_rule_save_resize_info(struct mlx5hws_rule *rule, + struct mlx5hws_send_ste_attr *ste_attr, + bool is_update) +{ + if (!mlx5hws_matcher_is_resizable(rule->matcher)) + return; + + if (likely(!is_update)) { + rule->resize_info = kzalloc(sizeof(*rule->resize_info), GFP_KERNEL); + if (unlikely(!rule->resize_info)) { + pr_warn("HWS: resize info isn't allocated for rule\n"); + return; + } + + rule->resize_info->max_stes = + rule->matcher->action_ste[MLX5HWS_ACTION_STE_IDX_ANY].max_stes; + rule->resize_info->action_ste_pool[0] = rule->matcher->action_ste[0].max_stes ? + rule->matcher->action_ste[0].pool : + NULL; + rule->resize_info->action_ste_pool[1] = rule->matcher->action_ste[1].max_stes ? + rule->matcher->action_ste[1].pool : + NULL; + } + + memcpy(rule->resize_info->ctrl_seg, ste_attr->wqe_ctrl, + sizeof(rule->resize_info->ctrl_seg)); + memcpy(rule->resize_info->data_seg, ste_attr->wqe_data, + sizeof(rule->resize_info->data_seg)); +} + +void mlx5hws_rule_clear_resize_info(struct mlx5hws_rule *rule) +{ + if (mlx5hws_matcher_is_resizable(rule->matcher) && + rule->resize_info) { + kfree(rule->resize_info); + rule->resize_info = NULL; + } +} + +static void +hws_rule_save_delete_info(struct mlx5hws_rule *rule, + struct mlx5hws_send_ste_attr *ste_attr) +{ + struct mlx5hws_match_template *mt = rule->matcher->mt; + bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); + + if (mlx5hws_matcher_is_resizable(rule->matcher)) + return; + + if (is_jumbo) + memcpy(&rule->tag.jumbo, ste_attr->wqe_data->jumbo, MLX5HWS_JUMBO_TAG_SZ); + else + memcpy(&rule->tag.match, ste_attr->wqe_data->tag, MLX5HWS_MATCH_TAG_SZ); +} + +static void +hws_rule_clear_delete_info(struct mlx5hws_rule *rule) +{ + /* nothing to do here */ +} + +static void +hws_rule_load_delete_info(struct mlx5hws_rule *rule, + struct mlx5hws_send_ste_attr *ste_attr) +{ + if (unlikely(!mlx5hws_matcher_is_resizable(rule->matcher))) { + ste_attr->wqe_tag = &rule->tag; + } else { + struct mlx5hws_wqe_gta_data_seg_ste *data_seg = + (struct mlx5hws_wqe_gta_data_seg_ste *)(void *)rule->resize_info->data_seg; + struct mlx5hws_rule_match_tag *tag = + (struct mlx5hws_rule_match_tag *)(void *)data_seg->action; + ste_attr->wqe_tag = tag; + } +} + +static int hws_rule_alloc_action_ste_idx(struct mlx5hws_rule *rule, + u8 action_ste_selector) +{ + struct mlx5hws_matcher *matcher = rule->matcher; + struct mlx5hws_matcher_action_ste *action_ste; + struct mlx5hws_pool_chunk ste = {0}; + int ret; + + action_ste = &matcher->action_ste[action_ste_selector]; + ste.order = ilog2(roundup_pow_of_two(action_ste->max_stes)); + ret = mlx5hws_pool_chunk_alloc(action_ste->pool, &ste); + if (unlikely(ret)) { + mlx5hws_err(matcher->tbl->ctx, + "Failed to allocate STE for rule actions"); + return ret; + } + rule->action_ste_idx = ste.offset; + + return 0; +} + +static void hws_rule_free_action_ste_idx(struct mlx5hws_rule *rule, + u8 action_ste_selector) +{ + struct mlx5hws_matcher *matcher = rule->matcher; + struct mlx5hws_pool_chunk ste = {0}; + struct mlx5hws_pool *pool; + u8 max_stes; + + if (mlx5hws_matcher_is_resizable(matcher)) { + /* Free the original action pool if rule was resized */ + max_stes = rule->resize_info->max_stes; + pool = rule->resize_info->action_ste_pool[action_ste_selector]; + } else { + max_stes = matcher->action_ste[action_ste_selector].max_stes; + pool = matcher->action_ste[action_ste_selector].pool; + } + + /* This release is safe only when the rule match part was deleted */ + ste.order = ilog2(roundup_pow_of_two(max_stes)); + ste.offset = rule->action_ste_idx; + + mlx5hws_pool_chunk_free(pool, &ste); +} + +static int hws_rule_alloc_action_ste(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + int action_ste_idx; + int ret; + + ret = hws_rule_alloc_action_ste_idx(rule, 0); + if (unlikely(ret)) + return ret; + + action_ste_idx = rule->action_ste_idx; + + ret = hws_rule_alloc_action_ste_idx(rule, 1); + if (unlikely(ret)) { + hws_rule_free_action_ste_idx(rule, 0); + return ret; + } + + /* Both pools have to return the same index */ + if (unlikely(rule->action_ste_idx != action_ste_idx)) { + pr_warn("HWS: allocation of action STE failed - pool indexes mismatch\n"); + return -EINVAL; + } + + return 0; +} + +void mlx5hws_rule_free_action_ste(struct mlx5hws_rule *rule) +{ + if (rule->action_ste_idx > -1) { + hws_rule_free_action_ste_idx(rule, 1); + hws_rule_free_action_ste_idx(rule, 0); + } +} + +static void hws_rule_create_init(struct mlx5hws_rule *rule, + struct mlx5hws_send_ste_attr *ste_attr, + struct mlx5hws_actions_apply_data *apply, + bool is_update) +{ + struct mlx5hws_matcher *matcher = rule->matcher; + struct mlx5hws_table *tbl = matcher->tbl; + struct mlx5hws_context *ctx = tbl->ctx; + + /* Init rule before reuse */ + if (!is_update) { + /* In update we use these rtc's */ + rule->rtc_0 = 0; + rule->rtc_1 = 0; + rule->action_ste_selector = 0; + } else { + rule->action_ste_selector = !rule->action_ste_selector; + } + + rule->pending_wqes = 0; + rule->action_ste_idx = -1; + rule->status = MLX5HWS_RULE_STATUS_CREATING; + + /* Init default send STE attributes */ + ste_attr->gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; + ste_attr->send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; + ste_attr->send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; + ste_attr->send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; + + /* Init default action apply */ + apply->tbl_type = tbl->type; + apply->common_res = &ctx->common_res[tbl->type]; + apply->jump_to_action_stc = matcher->action_ste[0].stc.offset; + apply->require_dep = 0; +} + +static void hws_rule_move_init(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + /* Save the old RTC IDs to be later used in match STE delete */ + rule->resize_info->rtc_0 = rule->rtc_0; + rule->resize_info->rtc_1 = rule->rtc_1; + rule->resize_info->rule_idx = attr->rule_idx; + + rule->rtc_0 = 0; + rule->rtc_1 = 0; + + rule->pending_wqes = 0; + rule->action_ste_idx = -1; + rule->action_ste_selector = 0; + rule->status = MLX5HWS_RULE_STATUS_CREATING; + rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_WRITING; +} + +bool mlx5hws_rule_move_in_progress(struct mlx5hws_rule *rule) +{ + return mlx5hws_matcher_is_in_resize(rule->matcher) && + rule->resize_info && + rule->resize_info->state != MLX5HWS_RULE_RESIZE_STATE_IDLE; +} + +static int hws_rule_create_hws(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr, + u8 mt_idx, + u32 *match_param, + u8 at_idx, + struct mlx5hws_rule_action rule_actions[]) +{ + struct mlx5hws_action_template *at = &rule->matcher->at[at_idx]; + struct mlx5hws_match_template *mt = &rule->matcher->mt[mt_idx]; + bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); + struct mlx5hws_matcher *matcher = rule->matcher; + struct mlx5hws_context *ctx = matcher->tbl->ctx; + struct mlx5hws_send_ste_attr ste_attr = {0}; + struct mlx5hws_send_ring_dep_wqe *dep_wqe; + struct mlx5hws_actions_wqe_setter *setter; + struct mlx5hws_actions_apply_data apply; + struct mlx5hws_send_engine *queue; + u8 total_stes, action_stes; + bool is_update; + int i, ret; + + is_update = !match_param; + + setter = &at->setters[at->num_of_action_stes]; + total_stes = at->num_of_action_stes + (is_jumbo && !at->only_term); + action_stes = total_stes - 1; + + queue = &ctx->send_queue[attr->queue_id]; + if (unlikely(mlx5hws_send_engine_err(queue))) + return -EIO; + + hws_rule_create_init(rule, &ste_attr, &apply, is_update); + + /* Allocate dependent match WQE since rule might have dependent writes. + * The queued dependent WQE can be later aborted or kept as a dependency. + * dep_wqe buffers (ctrl, data) are also reused for all STE writes. + */ + dep_wqe = mlx5hws_send_add_new_dep_wqe(queue); + hws_rule_init_dep_wqe(dep_wqe, rule, mt, attr); + + ste_attr.wqe_ctrl = &dep_wqe->wqe_ctrl; + ste_attr.wqe_data = &dep_wqe->wqe_data; + apply.wqe_ctrl = &dep_wqe->wqe_ctrl; + apply.wqe_data = (__force __be32 *)&dep_wqe->wqe_data; + apply.rule_action = rule_actions; + apply.queue = queue; + + if (action_stes) { + /* Allocate action STEs for rules that need more than match STE */ + if (!is_update) { + ret = hws_rule_alloc_action_ste(rule, attr); + if (ret) { + mlx5hws_err(ctx, "Failed to allocate action memory %d", ret); + mlx5hws_send_abort_new_dep_wqe(queue); + return ret; + } + } + /* Skip RX/TX based on the dep_wqe init */ + ste_attr.rtc_0 = dep_wqe->rtc_0 ? + matcher->action_ste[rule->action_ste_selector].rtc_0_id : 0; + ste_attr.rtc_1 = dep_wqe->rtc_1 ? + matcher->action_ste[rule->action_ste_selector].rtc_1_id : 0; + /* Action STEs are written to a specific index last to first */ + ste_attr.direct_index = rule->action_ste_idx + action_stes; + apply.next_direct_idx = ste_attr.direct_index; + } else { + apply.next_direct_idx = 0; + } + + for (i = total_stes; i-- > 0;) { + mlx5hws_action_apply_setter(&apply, setter--, !i && is_jumbo); + + if (i == 0) { + /* Handle last match STE. + * For hash split / linear lookup RTCs, packets reaching any STE + * will always match and perform the specified actions, which + * makes the tag irrelevant. + */ + if (likely(!mlx5hws_matcher_is_insert_by_idx(matcher) && !is_update)) + mlx5hws_definer_create_tag(match_param, mt->fc, mt->fc_sz, + (u8 *)dep_wqe->wqe_data.action); + else if (is_update) + hws_rule_update_copy_tag(rule, &dep_wqe->wqe_data, is_jumbo); + + /* Rule has dependent WQEs, match dep_wqe is queued */ + if (action_stes || apply.require_dep) + break; + + /* Rule has no dependencies, abort dep_wqe and send WQE now */ + mlx5hws_send_abort_new_dep_wqe(queue); + ste_attr.wqe_tag_is_jumbo = is_jumbo; + ste_attr.send_attr.notify_hw = !attr->burst; + ste_attr.send_attr.user_data = dep_wqe->user_data; + ste_attr.send_attr.rule = dep_wqe->rule; + ste_attr.rtc_0 = dep_wqe->rtc_0; + ste_attr.rtc_1 = dep_wqe->rtc_1; + ste_attr.used_id_rtc_0 = &rule->rtc_0; + ste_attr.used_id_rtc_1 = &rule->rtc_1; + ste_attr.retry_rtc_0 = dep_wqe->retry_rtc_0; + ste_attr.retry_rtc_1 = dep_wqe->retry_rtc_1; + ste_attr.direct_index = dep_wqe->direct_index; + } else { + apply.next_direct_idx = --ste_attr.direct_index; + } + + mlx5hws_send_ste(queue, &ste_attr); + } + + /* Backup TAG on the rule for deletion and resize info for + * moving rules to a new matcher, only after insertion. + */ + if (!is_update) + hws_rule_save_delete_info(rule, &ste_attr); + + hws_rule_save_resize_info(rule, &ste_attr, is_update); + mlx5hws_send_engine_inc_rule(queue); + + if (!attr->burst) + mlx5hws_send_all_dep_wqe(queue); + + return 0; +} + +static void hws_rule_destroy_failed_hws(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; + struct mlx5hws_send_engine *queue; + + queue = &ctx->send_queue[attr->queue_id]; + + hws_rule_gen_comp(queue, rule, false, + attr->user_data, MLX5HWS_RULE_STATUS_DELETED); + + /* Rule failed now we can safely release action STEs */ + mlx5hws_rule_free_action_ste(rule); + + /* Clear complex tag */ + hws_rule_clear_delete_info(rule); + + /* Clear info that was saved for resizing */ + mlx5hws_rule_clear_resize_info(rule); + + /* If a rule that was indicated as burst (need to trigger HW) has failed + * insertion we won't ring the HW as nothing is being written to the WQ. + * In such case update the last WQE and ring the HW with that work + */ + if (attr->burst) + return; + + mlx5hws_send_all_dep_wqe(queue); + mlx5hws_send_engine_flush_queue(queue); +} + +static int hws_rule_destroy_hws(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); + struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; + struct mlx5hws_matcher *matcher = rule->matcher; + struct mlx5hws_wqe_gta_ctrl_seg wqe_ctrl = {0}; + struct mlx5hws_send_ste_attr ste_attr = {0}; + struct mlx5hws_send_engine *queue; + + queue = &ctx->send_queue[attr->queue_id]; + + if (unlikely(mlx5hws_send_engine_err(queue))) { + hws_rule_destroy_failed_hws(rule, attr); + return 0; + } + + /* Rule is not completed yet */ + if (rule->status == MLX5HWS_RULE_STATUS_CREATING) + return -EBUSY; + + /* Rule failed and doesn't require cleanup */ + if (rule->status == MLX5HWS_RULE_STATUS_FAILED) { + hws_rule_destroy_failed_hws(rule, attr); + return 0; + } + + if (rule->skip_delete) { + /* Rule shouldn't be deleted in HW. + * Generate completion as if write succeeded, and we can + * safely release action STEs and clear resize info. + */ + hws_rule_gen_comp(queue, rule, false, + attr->user_data, MLX5HWS_RULE_STATUS_DELETED); + + mlx5hws_rule_free_action_ste(rule); + mlx5hws_rule_clear_resize_info(rule); + return 0; + } + + mlx5hws_send_engine_inc_rule(queue); + + /* Send dependent WQE */ + if (!attr->burst) + mlx5hws_send_all_dep_wqe(queue); + + rule->status = MLX5HWS_RULE_STATUS_DELETING; + + ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; + ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; + ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; + + ste_attr.send_attr.rule = rule; + ste_attr.send_attr.notify_hw = !attr->burst; + ste_attr.send_attr.user_data = attr->user_data; + + ste_attr.rtc_0 = rule->rtc_0; + ste_attr.rtc_1 = rule->rtc_1; + ste_attr.used_id_rtc_0 = &rule->rtc_0; + ste_attr.used_id_rtc_1 = &rule->rtc_1; + ste_attr.wqe_ctrl = &wqe_ctrl; + ste_attr.wqe_tag_is_jumbo = is_jumbo; + ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_DEACTIVATE; + if (unlikely(mlx5hws_matcher_is_insert_by_idx(matcher))) + ste_attr.direct_index = attr->rule_idx; + + hws_rule_load_delete_info(rule, &ste_attr); + mlx5hws_send_ste(queue, &ste_attr); + hws_rule_clear_delete_info(rule); + + return 0; +} + +static int hws_rule_enqueue_precheck(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; + + if (unlikely(!attr->user_data)) + return -EINVAL; + + /* Check if there is room in queue */ + if (unlikely(mlx5hws_send_engine_full(&ctx->send_queue[attr->queue_id]))) + return -EBUSY; + + return 0; +} + +static int hws_rule_enqueue_precheck_move(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + if (unlikely(rule->status != MLX5HWS_RULE_STATUS_CREATED)) + return -EINVAL; + + return hws_rule_enqueue_precheck(rule, attr); +} + +static int hws_rule_enqueue_precheck_create(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + if (unlikely(mlx5hws_matcher_is_in_resize(rule->matcher))) + /* Matcher in resize - new rules are not allowed */ + return -EAGAIN; + + return hws_rule_enqueue_precheck(rule, attr); +} + +static int hws_rule_enqueue_precheck_update(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + struct mlx5hws_matcher *matcher = rule->matcher; + + if (unlikely(!mlx5hws_matcher_is_resizable(rule->matcher) && + !matcher->attr.optimize_using_rule_idx && + !mlx5hws_matcher_is_insert_by_idx(matcher))) { + return -EOPNOTSUPP; + } + + if (unlikely(rule->status != MLX5HWS_RULE_STATUS_CREATED)) + return -EBUSY; + + return hws_rule_enqueue_precheck_create(rule, attr); +} + +int mlx5hws_rule_move_hws_remove(struct mlx5hws_rule *rule, + void *queue_ptr, + void *user_data) +{ + bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); + struct mlx5hws_wqe_gta_ctrl_seg empty_wqe_ctrl = {0}; + struct mlx5hws_matcher *matcher = rule->matcher; + struct mlx5hws_send_engine *queue = queue_ptr; + struct mlx5hws_send_ste_attr ste_attr = {0}; + + mlx5hws_send_all_dep_wqe(queue); + + rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_DELETING; + + ste_attr.send_attr.fence = 0; + ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; + ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; + ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; + ste_attr.send_attr.rule = rule; + ste_attr.send_attr.notify_hw = 1; + ste_attr.send_attr.user_data = user_data; + ste_attr.rtc_0 = rule->resize_info->rtc_0; + ste_attr.rtc_1 = rule->resize_info->rtc_1; + ste_attr.used_id_rtc_0 = &rule->resize_info->rtc_0; + ste_attr.used_id_rtc_1 = &rule->resize_info->rtc_1; + ste_attr.wqe_ctrl = &empty_wqe_ctrl; + ste_attr.wqe_tag_is_jumbo = is_jumbo; + ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_DEACTIVATE; + + if (unlikely(mlx5hws_matcher_is_insert_by_idx(matcher))) + ste_attr.direct_index = rule->resize_info->rule_idx; + + hws_rule_load_delete_info(rule, &ste_attr); + mlx5hws_send_ste(queue, &ste_attr); + + return 0; +} + +int mlx5hws_rule_move_hws_add(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(rule->matcher->mt); + struct mlx5hws_context *ctx = rule->matcher->tbl->ctx; + struct mlx5hws_matcher *matcher = rule->matcher; + struct mlx5hws_send_ste_attr ste_attr = {0}; + struct mlx5hws_send_engine *queue; + int ret; + + ret = hws_rule_enqueue_precheck_move(rule, attr); + if (unlikely(ret)) + return ret; + + queue = &ctx->send_queue[attr->queue_id]; + + ret = mlx5hws_send_engine_err(queue); + if (ret) + return ret; + + hws_rule_move_init(rule, attr); + hws_rule_move_get_rtc(rule, &ste_attr); + + ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; + ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; + ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; + ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; + ste_attr.wqe_tag_is_jumbo = is_jumbo; + + ste_attr.send_attr.rule = rule; + ste_attr.send_attr.fence = 0; + ste_attr.send_attr.notify_hw = !attr->burst; + ste_attr.send_attr.user_data = attr->user_data; + + ste_attr.used_id_rtc_0 = &rule->rtc_0; + ste_attr.used_id_rtc_1 = &rule->rtc_1; + ste_attr.wqe_ctrl = (struct mlx5hws_wqe_gta_ctrl_seg *)rule->resize_info->ctrl_seg; + ste_attr.wqe_data = (struct mlx5hws_wqe_gta_data_seg_ste *)rule->resize_info->data_seg; + ste_attr.direct_index = mlx5hws_matcher_is_insert_by_idx(matcher) ? + attr->rule_idx : 0; + + mlx5hws_send_ste(queue, &ste_attr); + mlx5hws_send_engine_inc_rule(queue); + + if (!attr->burst) + mlx5hws_send_all_dep_wqe(queue); + + return 0; +} + +int mlx5hws_rule_create(struct mlx5hws_matcher *matcher, + u8 mt_idx, + u32 *match_param, + u8 at_idx, + struct mlx5hws_rule_action rule_actions[], + struct mlx5hws_rule_attr *attr, + struct mlx5hws_rule *rule_handle) +{ + int ret; + + rule_handle->matcher = matcher; + + ret = hws_rule_enqueue_precheck_create(rule_handle, attr); + if (unlikely(ret)) + return ret; + + if (unlikely(!(matcher->num_of_mt >= mt_idx) || + !(matcher->num_of_at >= at_idx) || + !match_param)) { + pr_warn("HWS: Invalid rule creation parameters (MTs, ATs or match params)\n"); + return -EINVAL; + } + + ret = hws_rule_create_hws(rule_handle, + attr, + mt_idx, + match_param, + at_idx, + rule_actions); + + return ret; +} + +int mlx5hws_rule_destroy(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr) +{ + int ret; + + ret = hws_rule_enqueue_precheck(rule, attr); + if (unlikely(ret)) + return ret; + + ret = hws_rule_destroy_hws(rule, attr); + + return ret; +} + +int mlx5hws_rule_action_update(struct mlx5hws_rule *rule, + u8 at_idx, + struct mlx5hws_rule_action rule_actions[], + struct mlx5hws_rule_attr *attr) +{ + int ret; + + ret = hws_rule_enqueue_precheck_update(rule, attr); + if (unlikely(ret)) + return ret; + + ret = hws_rule_create_hws(rule, + attr, + 0, + NULL, + at_idx, + rule_actions); + + return ret; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.h new file mode 100644 index 00000000000000..495cdd17e9f3cb --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef MLX5HWS_RULE_H_ +#define MLX5HWS_RULE_H_ + +enum { + MLX5HWS_STE_CTRL_SZ = 20, + MLX5HWS_ACTIONS_SZ = 12, + MLX5HWS_MATCH_TAG_SZ = 32, + MLX5HWS_JUMBO_TAG_SZ = 44, +}; + +enum mlx5hws_rule_status { + MLX5HWS_RULE_STATUS_UNKNOWN, + MLX5HWS_RULE_STATUS_CREATING, + MLX5HWS_RULE_STATUS_CREATED, + MLX5HWS_RULE_STATUS_DELETING, + MLX5HWS_RULE_STATUS_DELETED, + MLX5HWS_RULE_STATUS_FAILING, + MLX5HWS_RULE_STATUS_FAILED, +}; + +enum mlx5hws_rule_move_state { + MLX5HWS_RULE_RESIZE_STATE_IDLE, + MLX5HWS_RULE_RESIZE_STATE_WRITING, + MLX5HWS_RULE_RESIZE_STATE_DELETING, +}; + +enum mlx5hws_rule_jumbo_match_tag_offset { + MLX5HWS_RULE_JUMBO_MATCH_TAG_OFFSET_DW0 = 8, +}; + +struct mlx5hws_rule_match_tag { + union { + u8 jumbo[MLX5HWS_JUMBO_TAG_SZ]; + struct { + u8 reserved[MLX5HWS_ACTIONS_SZ]; + u8 match[MLX5HWS_MATCH_TAG_SZ]; + }; + }; +}; + +struct mlx5hws_rule_resize_info { + struct mlx5hws_pool *action_ste_pool[2]; + u32 rtc_0; + u32 rtc_1; + u32 rule_idx; + u8 state; + u8 max_stes; + u8 ctrl_seg[MLX5HWS_WQE_SZ_GTA_CTRL]; /* Ctrl segment of STE: 48 bytes */ + u8 data_seg[MLX5HWS_WQE_SZ_GTA_DATA]; /* Data segment of STE: 64 bytes */ +}; + +struct mlx5hws_rule { + struct mlx5hws_matcher *matcher; + union { + struct mlx5hws_rule_match_tag tag; + struct mlx5hws_rule_resize_info *resize_info; + }; + u32 rtc_0; /* The RTC into which the STE was inserted */ + u32 rtc_1; /* The RTC into which the STE was inserted */ + int action_ste_idx; /* STE array index */ + u8 status; /* enum mlx5hws_rule_status */ + u8 action_ste_selector; /* For rule update - which action STE is in use */ + u8 pending_wqes; + bool skip_delete; /* For complex rules - another rule with same tag + * still exists, so don't actually delete this rule. + */ +}; + +void mlx5hws_rule_free_action_ste(struct mlx5hws_rule *rule); + +int mlx5hws_rule_move_hws_remove(struct mlx5hws_rule *rule, + void *queue, void *user_data); + +int mlx5hws_rule_move_hws_add(struct mlx5hws_rule *rule, + struct mlx5hws_rule_attr *attr); + +bool mlx5hws_rule_move_in_progress(struct mlx5hws_rule *rule); + +void mlx5hws_rule_clear_resize_info(struct mlx5hws_rule *rule); + +#endif /* MLX5HWS_RULE_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c new file mode 100644 index 00000000000000..883b4ed30892c4 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.c @@ -0,0 +1,1232 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" +#include "lib/clock.h" + +enum { CQ_OK = 0, CQ_EMPTY = -1, CQ_POLL_ERR = -2 }; + +struct mlx5hws_send_ring_dep_wqe * +mlx5hws_send_add_new_dep_wqe(struct mlx5hws_send_engine *queue) +{ + struct mlx5hws_send_ring_sq *send_sq = &queue->send_ring.send_sq; + unsigned int idx = send_sq->head_dep_idx++ & (queue->num_entries - 1); + + memset(&send_sq->dep_wqe[idx].wqe_data.tag, 0, MLX5HWS_MATCH_TAG_SZ); + + return &send_sq->dep_wqe[idx]; +} + +void mlx5hws_send_abort_new_dep_wqe(struct mlx5hws_send_engine *queue) +{ + queue->send_ring.send_sq.head_dep_idx--; +} + +void mlx5hws_send_all_dep_wqe(struct mlx5hws_send_engine *queue) +{ + struct mlx5hws_send_ring_sq *send_sq = &queue->send_ring.send_sq; + struct mlx5hws_send_ste_attr ste_attr = {0}; + struct mlx5hws_send_ring_dep_wqe *dep_wqe; + + ste_attr.send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; + ste_attr.send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; + ste_attr.send_attr.len = MLX5HWS_WQE_SZ_GTA_CTRL + MLX5HWS_WQE_SZ_GTA_DATA; + ste_attr.gta_opcode = MLX5HWS_WQE_GTA_OP_ACTIVATE; + + /* Fence first from previous depend WQEs */ + ste_attr.send_attr.fence = 1; + + while (send_sq->head_dep_idx != send_sq->tail_dep_idx) { + dep_wqe = &send_sq->dep_wqe[send_sq->tail_dep_idx++ & (queue->num_entries - 1)]; + + /* Notify HW on the last WQE */ + ste_attr.send_attr.notify_hw = (send_sq->tail_dep_idx == send_sq->head_dep_idx); + ste_attr.send_attr.user_data = dep_wqe->user_data; + ste_attr.send_attr.rule = dep_wqe->rule; + + ste_attr.rtc_0 = dep_wqe->rtc_0; + ste_attr.rtc_1 = dep_wqe->rtc_1; + ste_attr.retry_rtc_0 = dep_wqe->retry_rtc_0; + ste_attr.retry_rtc_1 = dep_wqe->retry_rtc_1; + ste_attr.used_id_rtc_0 = &dep_wqe->rule->rtc_0; + ste_attr.used_id_rtc_1 = &dep_wqe->rule->rtc_1; + ste_attr.wqe_ctrl = &dep_wqe->wqe_ctrl; + ste_attr.wqe_data = &dep_wqe->wqe_data; + ste_attr.direct_index = dep_wqe->direct_index; + + mlx5hws_send_ste(queue, &ste_attr); + + /* Fencing is done only on the first WQE */ + ste_attr.send_attr.fence = 0; + } +} + +struct mlx5hws_send_engine_post_ctrl +mlx5hws_send_engine_post_start(struct mlx5hws_send_engine *queue) +{ + struct mlx5hws_send_engine_post_ctrl ctrl; + + ctrl.queue = queue; + /* Currently only one send ring is supported */ + ctrl.send_ring = &queue->send_ring; + ctrl.num_wqebbs = 0; + + return ctrl; +} + +void mlx5hws_send_engine_post_req_wqe(struct mlx5hws_send_engine_post_ctrl *ctrl, + char **buf, size_t *len) +{ + struct mlx5hws_send_ring_sq *send_sq = &ctrl->send_ring->send_sq; + unsigned int idx; + + idx = (send_sq->cur_post + ctrl->num_wqebbs) & send_sq->buf_mask; + + /* Note that *buf is a single MLX5_SEND_WQE_BB. It cannot be used + * as buffer of more than one WQE_BB, since the two MLX5_SEND_WQE_BB + * can be on 2 different kernel memory pages. + */ + *buf = mlx5_wq_cyc_get_wqe(&send_sq->wq, idx); + *len = MLX5_SEND_WQE_BB; + + if (!ctrl->num_wqebbs) { + *buf += sizeof(struct mlx5hws_wqe_ctrl_seg); + *len -= sizeof(struct mlx5hws_wqe_ctrl_seg); + } + + ctrl->num_wqebbs++; +} + +static void hws_send_engine_post_ring(struct mlx5hws_send_ring_sq *sq, + struct mlx5hws_wqe_ctrl_seg *doorbell_cseg) +{ + /* ensure wqe is visible to device before updating doorbell record */ + dma_wmb(); + + *sq->wq.db = cpu_to_be32(sq->cur_post); + + /* ensure doorbell record is visible to device before ringing the + * doorbell + */ + wmb(); + + mlx5_write64((__be32 *)doorbell_cseg, sq->uar_map); + + /* Ensure doorbell is written on uar_page before poll_cq */ + WRITE_ONCE(doorbell_cseg, NULL); +} + +static void +hws_send_wqe_set_tag(struct mlx5hws_wqe_gta_data_seg_ste *wqe_data, + struct mlx5hws_rule_match_tag *tag, + bool is_jumbo) +{ + if (is_jumbo) { + /* Clear previous possibly dirty control */ + memset(wqe_data, 0, MLX5HWS_STE_CTRL_SZ); + memcpy(wqe_data->jumbo, tag->jumbo, MLX5HWS_JUMBO_TAG_SZ); + } else { + /* Clear previous possibly dirty control and actions */ + memset(wqe_data, 0, MLX5HWS_STE_CTRL_SZ + MLX5HWS_ACTIONS_SZ); + memcpy(wqe_data->tag, tag->match, MLX5HWS_MATCH_TAG_SZ); + } +} + +void mlx5hws_send_engine_post_end(struct mlx5hws_send_engine_post_ctrl *ctrl, + struct mlx5hws_send_engine_post_attr *attr) +{ + struct mlx5hws_wqe_ctrl_seg *wqe_ctrl; + struct mlx5hws_send_ring_sq *sq; + unsigned int idx; + u32 flags = 0; + + sq = &ctrl->send_ring->send_sq; + idx = sq->cur_post & sq->buf_mask; + sq->last_idx = idx; + + wqe_ctrl = mlx5_wq_cyc_get_wqe(&sq->wq, idx); + + wqe_ctrl->opmod_idx_opcode = + cpu_to_be32((attr->opmod << 24) | + ((sq->cur_post & 0xffff) << 8) | + attr->opcode); + wqe_ctrl->qpn_ds = + cpu_to_be32((attr->len + sizeof(struct mlx5hws_wqe_ctrl_seg)) / 16 | + sq->sqn << 8); + wqe_ctrl->imm = cpu_to_be32(attr->id); + + flags |= attr->notify_hw ? MLX5_WQE_CTRL_CQ_UPDATE : 0; + flags |= attr->fence ? MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE : 0; + wqe_ctrl->flags = cpu_to_be32(flags); + + sq->wr_priv[idx].id = attr->id; + sq->wr_priv[idx].retry_id = attr->retry_id; + + sq->wr_priv[idx].rule = attr->rule; + sq->wr_priv[idx].user_data = attr->user_data; + sq->wr_priv[idx].num_wqebbs = ctrl->num_wqebbs; + + if (attr->rule) { + sq->wr_priv[idx].rule->pending_wqes++; + sq->wr_priv[idx].used_id = attr->used_id; + } + + sq->cur_post += ctrl->num_wqebbs; + + if (attr->notify_hw) + hws_send_engine_post_ring(sq, wqe_ctrl); +} + +static void hws_send_wqe(struct mlx5hws_send_engine *queue, + struct mlx5hws_send_engine_post_attr *send_attr, + struct mlx5hws_wqe_gta_ctrl_seg *send_wqe_ctrl, + void *send_wqe_data, + void *send_wqe_tag, + bool is_jumbo, + u8 gta_opcode, + u32 direct_index) +{ + struct mlx5hws_wqe_gta_data_seg_ste *wqe_data; + struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; + struct mlx5hws_send_engine_post_ctrl ctrl; + size_t wqe_len; + + ctrl = mlx5hws_send_engine_post_start(queue); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_data, &wqe_len); + + wqe_ctrl->op_dirix = cpu_to_be32(gta_opcode << 28 | direct_index); + memcpy(wqe_ctrl->stc_ix, send_wqe_ctrl->stc_ix, + sizeof(send_wqe_ctrl->stc_ix)); + + if (send_wqe_data) + memcpy(wqe_data, send_wqe_data, sizeof(*wqe_data)); + else + hws_send_wqe_set_tag(wqe_data, send_wqe_tag, is_jumbo); + + mlx5hws_send_engine_post_end(&ctrl, send_attr); +} + +void mlx5hws_send_ste(struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ste_attr *ste_attr) +{ + struct mlx5hws_send_engine_post_attr *send_attr = &ste_attr->send_attr; + u8 notify_hw = send_attr->notify_hw; + u8 fence = send_attr->fence; + + if (ste_attr->rtc_1) { + send_attr->id = ste_attr->rtc_1; + send_attr->used_id = ste_attr->used_id_rtc_1; + send_attr->retry_id = ste_attr->retry_rtc_1; + send_attr->fence = fence; + send_attr->notify_hw = notify_hw && !ste_attr->rtc_0; + hws_send_wqe(queue, send_attr, + ste_attr->wqe_ctrl, + ste_attr->wqe_data, + ste_attr->wqe_tag, + ste_attr->wqe_tag_is_jumbo, + ste_attr->gta_opcode, + ste_attr->direct_index); + } + + if (ste_attr->rtc_0) { + send_attr->id = ste_attr->rtc_0; + send_attr->used_id = ste_attr->used_id_rtc_0; + send_attr->retry_id = ste_attr->retry_rtc_0; + send_attr->fence = fence && !ste_attr->rtc_1; + send_attr->notify_hw = notify_hw; + hws_send_wqe(queue, send_attr, + ste_attr->wqe_ctrl, + ste_attr->wqe_data, + ste_attr->wqe_tag, + ste_attr->wqe_tag_is_jumbo, + ste_attr->gta_opcode, + ste_attr->direct_index); + } + + /* Restore to original requested values */ + send_attr->notify_hw = notify_hw; + send_attr->fence = fence; +} + +static void hws_send_engine_retry_post_send(struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ring_priv *priv, + u16 wqe_cnt) +{ + struct mlx5hws_send_engine_post_attr send_attr = {0}; + struct mlx5hws_wqe_gta_data_seg_ste *wqe_data; + struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; + struct mlx5hws_send_engine_post_ctrl ctrl; + struct mlx5hws_send_ring_sq *send_sq; + unsigned int idx; + size_t wqe_len; + char *p; + + send_attr.rule = priv->rule; + send_attr.opcode = MLX5HWS_WQE_OPCODE_TBL_ACCESS; + send_attr.opmod = MLX5HWS_WQE_GTA_OPMOD_STE; + send_attr.len = MLX5_SEND_WQE_BB * 2 - sizeof(struct mlx5hws_wqe_ctrl_seg); + send_attr.notify_hw = 1; + send_attr.fence = 0; + send_attr.user_data = priv->user_data; + send_attr.id = priv->retry_id; + send_attr.used_id = priv->used_id; + + ctrl = mlx5hws_send_engine_post_start(queue); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_ctrl, &wqe_len); + mlx5hws_send_engine_post_req_wqe(&ctrl, (void *)&wqe_data, &wqe_len); + + send_sq = &ctrl.send_ring->send_sq; + idx = wqe_cnt & send_sq->buf_mask; + p = mlx5_wq_cyc_get_wqe(&send_sq->wq, idx); + + /* Copy old gta ctrl */ + memcpy(wqe_ctrl, p + sizeof(struct mlx5hws_wqe_ctrl_seg), + MLX5_SEND_WQE_BB - sizeof(struct mlx5hws_wqe_ctrl_seg)); + + idx = (wqe_cnt + 1) & send_sq->buf_mask; + p = mlx5_wq_cyc_get_wqe(&send_sq->wq, idx); + + /* Copy old gta data */ + memcpy(wqe_data, p, MLX5_SEND_WQE_BB); + + mlx5hws_send_engine_post_end(&ctrl, &send_attr); +} + +void mlx5hws_send_engine_flush_queue(struct mlx5hws_send_engine *queue) +{ + struct mlx5hws_send_ring_sq *sq = &queue->send_ring.send_sq; + struct mlx5hws_wqe_ctrl_seg *wqe_ctrl; + + wqe_ctrl = mlx5_wq_cyc_get_wqe(&sq->wq, sq->last_idx); + wqe_ctrl->flags |= cpu_to_be32(MLX5_WQE_CTRL_CQ_UPDATE); + + hws_send_engine_post_ring(sq, wqe_ctrl); +} + +static void +hws_send_engine_update_rule_resize(struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ring_priv *priv, + enum mlx5hws_flow_op_status *status) +{ + switch (priv->rule->resize_info->state) { + case MLX5HWS_RULE_RESIZE_STATE_WRITING: + if (priv->rule->status == MLX5HWS_RULE_STATUS_FAILING) { + /* Backup original RTCs */ + u32 orig_rtc_0 = priv->rule->resize_info->rtc_0; + u32 orig_rtc_1 = priv->rule->resize_info->rtc_1; + + /* Delete partially failed move rule using resize_info */ + priv->rule->resize_info->rtc_0 = priv->rule->rtc_0; + priv->rule->resize_info->rtc_1 = priv->rule->rtc_1; + + /* Move rule to original RTC for future delete */ + priv->rule->rtc_0 = orig_rtc_0; + priv->rule->rtc_1 = orig_rtc_1; + } + /* Clean leftovers */ + mlx5hws_rule_move_hws_remove(priv->rule, queue, priv->user_data); + break; + + case MLX5HWS_RULE_RESIZE_STATE_DELETING: + if (priv->rule->status == MLX5HWS_RULE_STATUS_FAILING) { + *status = MLX5HWS_FLOW_OP_ERROR; + } else { + *status = MLX5HWS_FLOW_OP_SUCCESS; + priv->rule->matcher = priv->rule->matcher->resize_dst; + } + priv->rule->resize_info->state = MLX5HWS_RULE_RESIZE_STATE_IDLE; + priv->rule->status = MLX5HWS_RULE_STATUS_CREATED; + break; + + default: + break; + } +} + +static void hws_send_engine_update_rule(struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ring_priv *priv, + u16 wqe_cnt, + enum mlx5hws_flow_op_status *status) +{ + priv->rule->pending_wqes--; + + if (*status == MLX5HWS_FLOW_OP_ERROR) { + if (priv->retry_id) { + hws_send_engine_retry_post_send(queue, priv, wqe_cnt); + return; + } + /* Some part of the rule failed */ + priv->rule->status = MLX5HWS_RULE_STATUS_FAILING; + *priv->used_id = 0; + } else { + *priv->used_id = priv->id; + } + + /* Update rule status for the last completion */ + if (!priv->rule->pending_wqes) { + if (unlikely(mlx5hws_rule_move_in_progress(priv->rule))) { + hws_send_engine_update_rule_resize(queue, priv, status); + return; + } + + if (unlikely(priv->rule->status == MLX5HWS_RULE_STATUS_FAILING)) { + /* Rule completely failed and doesn't require cleanup */ + if (!priv->rule->rtc_0 && !priv->rule->rtc_1) + priv->rule->status = MLX5HWS_RULE_STATUS_FAILED; + + *status = MLX5HWS_FLOW_OP_ERROR; + } else { + /* Increase the status, this only works on good flow as the enum + * is arrange it away creating -> created -> deleting -> deleted + */ + priv->rule->status++; + *status = MLX5HWS_FLOW_OP_SUCCESS; + /* Rule was deleted now we can safely release action STEs + * and clear resize info + */ + if (priv->rule->status == MLX5HWS_RULE_STATUS_DELETED) { + mlx5hws_rule_free_action_ste(priv->rule); + mlx5hws_rule_clear_resize_info(priv->rule); + } + } + } +} + +static void hws_send_engine_update(struct mlx5hws_send_engine *queue, + struct mlx5_cqe64 *cqe, + struct mlx5hws_send_ring_priv *priv, + struct mlx5hws_flow_op_result res[], + s64 *i, + u32 res_nb, + u16 wqe_cnt) +{ + enum mlx5hws_flow_op_status status; + + if (!cqe || (likely(be32_to_cpu(cqe->byte_cnt) >> 31 == 0) && + likely(get_cqe_opcode(cqe) == MLX5_CQE_REQ))) { + status = MLX5HWS_FLOW_OP_SUCCESS; + } else { + status = MLX5HWS_FLOW_OP_ERROR; + } + + if (priv->user_data) { + if (priv->rule) { + hws_send_engine_update_rule(queue, priv, wqe_cnt, &status); + /* Completion is provided on the last rule WQE */ + if (priv->rule->pending_wqes) + return; + } + + if (*i < res_nb) { + res[*i].user_data = priv->user_data; + res[*i].status = status; + (*i)++; + mlx5hws_send_engine_dec_rule(queue); + } else { + mlx5hws_send_engine_gen_comp(queue, priv->user_data, status); + } + } +} + +static int mlx5hws_parse_cqe(struct mlx5hws_send_ring_cq *cq, + struct mlx5_cqe64 *cqe64) +{ + if (unlikely(get_cqe_opcode(cqe64) != MLX5_CQE_REQ)) { + struct mlx5_err_cqe *err_cqe = (struct mlx5_err_cqe *)cqe64; + + mlx5_core_err(cq->mdev, "Bad OP in HWS SQ CQE: 0x%x\n", get_cqe_opcode(cqe64)); + mlx5_core_err(cq->mdev, "vendor_err_synd=%x\n", err_cqe->vendor_err_synd); + mlx5_core_err(cq->mdev, "syndrome=%x\n", err_cqe->syndrome); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, + 16, 1, err_cqe, + sizeof(*err_cqe), false); + return CQ_POLL_ERR; + } + + return CQ_OK; +} + +static int mlx5hws_cq_poll_one(struct mlx5hws_send_ring_cq *cq) +{ + struct mlx5_cqe64 *cqe64; + int err; + + cqe64 = mlx5_cqwq_get_cqe(&cq->wq); + if (!cqe64) { + if (unlikely(cq->mdev->state == + MLX5_DEVICE_STATE_INTERNAL_ERROR)) { + mlx5_core_dbg_once(cq->mdev, + "Polling CQ while device is shutting down\n"); + return CQ_POLL_ERR; + } + return CQ_EMPTY; + } + + mlx5_cqwq_pop(&cq->wq); + err = mlx5hws_parse_cqe(cq, cqe64); + mlx5_cqwq_update_db_record(&cq->wq); + + return err; +} + +static void hws_send_engine_poll_cq(struct mlx5hws_send_engine *queue, + struct mlx5hws_flow_op_result res[], + s64 *polled, + u32 res_nb) +{ + struct mlx5hws_send_ring *send_ring = &queue->send_ring; + struct mlx5hws_send_ring_cq *cq = &send_ring->send_cq; + struct mlx5hws_send_ring_sq *sq = &send_ring->send_sq; + struct mlx5hws_send_ring_priv *priv; + struct mlx5_cqe64 *cqe; + u8 cqe_opcode; + u16 wqe_cnt; + + cqe = mlx5_cqwq_get_cqe(&cq->wq); + if (!cqe) + return; + + cqe_opcode = get_cqe_opcode(cqe); + if (cqe_opcode == MLX5_CQE_INVALID) + return; + + if (unlikely(cqe_opcode != MLX5_CQE_REQ)) + queue->err = true; + + wqe_cnt = be16_to_cpu(cqe->wqe_counter) & sq->buf_mask; + + while (cq->poll_wqe != wqe_cnt) { + priv = &sq->wr_priv[cq->poll_wqe]; + hws_send_engine_update(queue, NULL, priv, res, polled, res_nb, 0); + cq->poll_wqe = (cq->poll_wqe + priv->num_wqebbs) & sq->buf_mask; + } + + priv = &sq->wr_priv[wqe_cnt]; + cq->poll_wqe = (wqe_cnt + priv->num_wqebbs) & sq->buf_mask; + hws_send_engine_update(queue, cqe, priv, res, polled, res_nb, wqe_cnt); + mlx5hws_cq_poll_one(cq); +} + +static void hws_send_engine_poll_list(struct mlx5hws_send_engine *queue, + struct mlx5hws_flow_op_result res[], + s64 *polled, + u32 res_nb) +{ + struct mlx5hws_completed_poll *comp = &queue->completed; + + while (comp->ci != comp->pi) { + if (*polled < res_nb) { + res[*polled].status = + comp->entries[comp->ci].status; + res[*polled].user_data = + comp->entries[comp->ci].user_data; + (*polled)++; + comp->ci = (comp->ci + 1) & comp->mask; + mlx5hws_send_engine_dec_rule(queue); + } else { + return; + } + } +} + +static int hws_send_engine_poll(struct mlx5hws_send_engine *queue, + struct mlx5hws_flow_op_result res[], + u32 res_nb) +{ + s64 polled = 0; + + hws_send_engine_poll_list(queue, res, &polled, res_nb); + + if (polled >= res_nb) + return polled; + + hws_send_engine_poll_cq(queue, res, &polled, res_nb); + + return polled; +} + +int mlx5hws_send_queue_poll(struct mlx5hws_context *ctx, + u16 queue_id, + struct mlx5hws_flow_op_result res[], + u32 res_nb) +{ + return hws_send_engine_poll(&ctx->send_queue[queue_id], res, res_nb); +} + +static int hws_send_ring_alloc_sq(struct mlx5_core_dev *mdev, + int numa_node, + struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ring_sq *sq, + void *sqc_data) +{ + void *sqc_wq = MLX5_ADDR_OF(sqc, sqc_data, wq); + struct mlx5_wq_cyc *wq = &sq->wq; + struct mlx5_wq_param param; + size_t buf_sz; + int err; + + sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map; + sq->mdev = mdev; + + param.db_numa_node = numa_node; + param.buf_numa_node = numa_node; + err = mlx5_wq_cyc_create(mdev, ¶m, sqc_wq, wq, &sq->wq_ctrl); + if (err) + return err; + wq->db = &wq->db[MLX5_SND_DBR]; + + buf_sz = queue->num_entries * MAX_WQES_PER_RULE; + sq->dep_wqe = kcalloc(queue->num_entries, sizeof(*sq->dep_wqe), GFP_KERNEL); + if (!sq->dep_wqe) { + err = -ENOMEM; + goto destroy_wq_cyc; + } + + sq->wr_priv = kzalloc(sizeof(*sq->wr_priv) * buf_sz, GFP_KERNEL); + if (!sq->wr_priv) { + err = -ENOMEM; + goto free_dep_wqe; + } + + sq->buf_mask = (queue->num_entries * MAX_WQES_PER_RULE) - 1; + + return 0; + +free_dep_wqe: + kfree(sq->dep_wqe); +destroy_wq_cyc: + mlx5_wq_destroy(&sq->wq_ctrl); + return err; +} + +static void hws_send_ring_free_sq(struct mlx5hws_send_ring_sq *sq) +{ + if (!sq) + return; + kfree(sq->wr_priv); + kfree(sq->dep_wqe); + mlx5_wq_destroy(&sq->wq_ctrl); +} + +static int hws_send_ring_create_sq(struct mlx5_core_dev *mdev, u32 pdn, + void *sqc_data, + struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ring_sq *sq, + struct mlx5hws_send_ring_cq *cq) +{ + void *in, *sqc, *wq; + int inlen, err; + u8 ts_format; + + inlen = MLX5_ST_SZ_BYTES(create_sq_in) + + sizeof(u64) * sq->wq_ctrl.buf.npages; + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + sqc = MLX5_ADDR_OF(create_sq_in, in, ctx); + wq = MLX5_ADDR_OF(sqc, sqc, wq); + + memcpy(sqc, sqc_data, MLX5_ST_SZ_BYTES(sqc)); + MLX5_SET(sqc, sqc, cqn, cq->mcq.cqn); + + MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST); + MLX5_SET(sqc, sqc, flush_in_error_en, 1); + + ts_format = mlx5_is_real_time_sq(mdev) ? MLX5_TIMESTAMP_FORMAT_REAL_TIME : + MLX5_TIMESTAMP_FORMAT_FREE_RUNNING; + MLX5_SET(sqc, sqc, ts_format, ts_format); + + MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC); + MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index); + MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); + MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma); + + mlx5_fill_page_frag_array(&sq->wq_ctrl.buf, + (__be64 *)MLX5_ADDR_OF(wq, wq, pas)); + + err = mlx5_core_create_sq(mdev, in, inlen, &sq->sqn); + + kvfree(in); + + return err; +} + +static void hws_send_ring_destroy_sq(struct mlx5_core_dev *mdev, + struct mlx5hws_send_ring_sq *sq) +{ + mlx5_core_destroy_sq(mdev, sq->sqn); +} + +static int hws_send_ring_set_sq_rdy(struct mlx5_core_dev *mdev, u32 sqn) +{ + void *in, *sqc; + int inlen, err; + + inlen = MLX5_ST_SZ_BYTES(modify_sq_in); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(modify_sq_in, in, sq_state, MLX5_SQC_STATE_RST); + sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); + MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RDY); + + err = mlx5_core_modify_sq(mdev, sqn, in); + + kvfree(in); + + return err; +} + +static void hws_send_ring_close_sq(struct mlx5hws_send_ring_sq *sq) +{ + mlx5_core_destroy_sq(sq->mdev, sq->sqn); + mlx5_wq_destroy(&sq->wq_ctrl); + kfree(sq->wr_priv); + kfree(sq->dep_wqe); +} + +static int hws_send_ring_create_sq_rdy(struct mlx5_core_dev *mdev, u32 pdn, + void *sqc_data, + struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ring_sq *sq, + struct mlx5hws_send_ring_cq *cq) +{ + int err; + + err = hws_send_ring_create_sq(mdev, pdn, sqc_data, queue, sq, cq); + if (err) + return err; + + err = hws_send_ring_set_sq_rdy(mdev, sq->sqn); + if (err) + hws_send_ring_destroy_sq(mdev, sq); + + return err; +} + +static int hws_send_ring_open_sq(struct mlx5hws_context *ctx, + int numa_node, + struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ring_sq *sq, + struct mlx5hws_send_ring_cq *cq) +{ + size_t buf_sz, sq_log_buf_sz; + void *sqc_data, *wq; + int err; + + sqc_data = kvzalloc(MLX5_ST_SZ_BYTES(sqc), GFP_KERNEL); + if (!sqc_data) + return -ENOMEM; + + buf_sz = queue->num_entries * MAX_WQES_PER_RULE; + sq_log_buf_sz = ilog2(roundup_pow_of_two(buf_sz)); + + wq = MLX5_ADDR_OF(sqc, sqc_data, wq); + MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB)); + MLX5_SET(wq, wq, pd, ctx->pd_num); + MLX5_SET(wq, wq, log_wq_sz, sq_log_buf_sz); + + err = hws_send_ring_alloc_sq(ctx->mdev, numa_node, queue, sq, sqc_data); + if (err) + goto err_free_sqc; + + err = hws_send_ring_create_sq_rdy(ctx->mdev, ctx->pd_num, sqc_data, + queue, sq, cq); + if (err) + goto err_free_sq; + + kvfree(sqc_data); + + return 0; +err_free_sq: + hws_send_ring_free_sq(sq); +err_free_sqc: + kvfree(sqc_data); + return err; +} + +static void hws_cq_complete(struct mlx5_core_cq *mcq, + struct mlx5_eqe *eqe) +{ + pr_err("CQ completion CQ: #%u\n", mcq->cqn); +} + +static int hws_send_ring_alloc_cq(struct mlx5_core_dev *mdev, + int numa_node, + struct mlx5hws_send_engine *queue, + void *cqc_data, + struct mlx5hws_send_ring_cq *cq) +{ + struct mlx5_core_cq *mcq = &cq->mcq; + struct mlx5_wq_param param; + struct mlx5_cqe64 *cqe; + int err; + u32 i; + + param.buf_numa_node = numa_node; + param.db_numa_node = numa_node; + + err = mlx5_cqwq_create(mdev, ¶m, cqc_data, &cq->wq, &cq->wq_ctrl); + if (err) + return err; + + mcq->cqe_sz = 64; + mcq->set_ci_db = cq->wq_ctrl.db.db; + mcq->arm_db = cq->wq_ctrl.db.db + 1; + mcq->comp = hws_cq_complete; + + for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) { + cqe = mlx5_cqwq_get_wqe(&cq->wq, i); + cqe->op_own = 0xf1; + } + + cq->mdev = mdev; + + return 0; +} + +static int hws_send_ring_create_cq(struct mlx5_core_dev *mdev, + struct mlx5hws_send_engine *queue, + void *cqc_data, + struct mlx5hws_send_ring_cq *cq) +{ + u32 out[MLX5_ST_SZ_DW(create_cq_out)]; + struct mlx5_core_cq *mcq = &cq->mcq; + void *in, *cqc; + int inlen, eqn; + int err; + + err = mlx5_comp_eqn_get(mdev, 0, &eqn); + if (err) + return err; + + inlen = MLX5_ST_SZ_BYTES(create_cq_in) + + sizeof(u64) * cq->wq_ctrl.buf.npages; + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); + memcpy(cqc, cqc_data, MLX5_ST_SZ_BYTES(cqc)); + mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, + (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas)); + + MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn); + MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index); + MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); + MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma); + + err = mlx5_core_create_cq(mdev, mcq, in, inlen, out, sizeof(out)); + + kvfree(in); + + return err; +} + +static int hws_send_ring_open_cq(struct mlx5_core_dev *mdev, + struct mlx5hws_send_engine *queue, + int numa_node, + struct mlx5hws_send_ring_cq *cq) +{ + void *cqc_data; + int err; + + cqc_data = kvzalloc(MLX5_ST_SZ_BYTES(cqc), GFP_KERNEL); + if (!cqc_data) + return -ENOMEM; + + MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index); + MLX5_SET(cqc, cqc_data, cqe_sz, queue->num_entries); + MLX5_SET(cqc, cqc_data, log_cq_size, ilog2(queue->num_entries)); + + err = hws_send_ring_alloc_cq(mdev, numa_node, queue, cqc_data, cq); + if (err) + goto err_out; + + err = hws_send_ring_create_cq(mdev, queue, cqc_data, cq); + if (err) + goto err_free_cq; + + kvfree(cqc_data); + + return 0; + +err_free_cq: + mlx5_wq_destroy(&cq->wq_ctrl); +err_out: + kvfree(cqc_data); + return err; +} + +static void hws_send_ring_close_cq(struct mlx5hws_send_ring_cq *cq) +{ + mlx5_core_destroy_cq(cq->mdev, &cq->mcq); + mlx5_wq_destroy(&cq->wq_ctrl); +} + +static void hws_send_ring_close(struct mlx5hws_send_engine *queue) +{ + hws_send_ring_close_sq(&queue->send_ring.send_sq); + hws_send_ring_close_cq(&queue->send_ring.send_cq); +} + +static int mlx5hws_send_ring_open(struct mlx5hws_context *ctx, + struct mlx5hws_send_engine *queue) +{ + int numa_node = dev_to_node(mlx5_core_dma_dev(ctx->mdev)); + struct mlx5hws_send_ring *ring = &queue->send_ring; + int err; + + err = hws_send_ring_open_cq(ctx->mdev, queue, numa_node, &ring->send_cq); + if (err) + return err; + + err = hws_send_ring_open_sq(ctx, numa_node, queue, &ring->send_sq, + &ring->send_cq); + if (err) + goto close_cq; + + return err; + +close_cq: + hws_send_ring_close_cq(&ring->send_cq); + return err; +} + +void mlx5hws_send_queue_close(struct mlx5hws_send_engine *queue) +{ + hws_send_ring_close(queue); + kfree(queue->completed.entries); +} + +int mlx5hws_send_queue_open(struct mlx5hws_context *ctx, + struct mlx5hws_send_engine *queue, + u16 queue_size) +{ + int err; + + mutex_init(&queue->lock); + + queue->num_entries = roundup_pow_of_two(queue_size); + queue->used_entries = 0; + + queue->completed.entries = kcalloc(queue->num_entries, + sizeof(queue->completed.entries[0]), + GFP_KERNEL); + if (!queue->completed.entries) + return -ENOMEM; + + queue->completed.pi = 0; + queue->completed.ci = 0; + queue->completed.mask = queue->num_entries - 1; + err = mlx5hws_send_ring_open(ctx, queue); + if (err) + goto free_completed_entries; + + return 0; + +free_completed_entries: + kfree(queue->completed.entries); + return err; +} + +static void __hws_send_queues_close(struct mlx5hws_context *ctx, u16 queues) +{ + while (queues--) + mlx5hws_send_queue_close(&ctx->send_queue[queues]); +} + +static void hws_send_queues_bwc_locks_destroy(struct mlx5hws_context *ctx) +{ + int bwc_queues = mlx5hws_bwc_queues(ctx); + int i; + + if (!mlx5hws_context_bwc_supported(ctx)) + return; + + for (i = 0; i < bwc_queues; i++) { + mutex_destroy(&ctx->bwc_send_queue_locks[i]); + lockdep_unregister_key(ctx->bwc_lock_class_keys + i); + } + + kfree(ctx->bwc_lock_class_keys); + kfree(ctx->bwc_send_queue_locks); +} + +void mlx5hws_send_queues_close(struct mlx5hws_context *ctx) +{ + hws_send_queues_bwc_locks_destroy(ctx); + __hws_send_queues_close(ctx, ctx->queues); + kfree(ctx->send_queue); +} + +static int hws_bwc_send_queues_init(struct mlx5hws_context *ctx) +{ + /* Number of BWC queues is equal to number of the usual HWS queues */ + int bwc_queues = ctx->queues - 1; + int i; + + if (!mlx5hws_context_bwc_supported(ctx)) + return 0; + + ctx->queues += bwc_queues; + + ctx->bwc_send_queue_locks = kcalloc(bwc_queues, + sizeof(*ctx->bwc_send_queue_locks), + GFP_KERNEL); + + if (!ctx->bwc_send_queue_locks) + return -ENOMEM; + + ctx->bwc_lock_class_keys = kcalloc(bwc_queues, + sizeof(*ctx->bwc_lock_class_keys), + GFP_KERNEL); + if (!ctx->bwc_lock_class_keys) + goto err_lock_class_keys; + + for (i = 0; i < bwc_queues; i++) { + mutex_init(&ctx->bwc_send_queue_locks[i]); + lockdep_register_key(ctx->bwc_lock_class_keys + i); + lockdep_set_class(ctx->bwc_send_queue_locks + i, ctx->bwc_lock_class_keys + i); + } + + return 0; + +err_lock_class_keys: + kfree(ctx->bwc_send_queue_locks); + return -ENOMEM; +} + +int mlx5hws_send_queues_open(struct mlx5hws_context *ctx, + u16 queues, + u16 queue_size) +{ + int err = 0; + u32 i; + + /* Open one extra queue for control path */ + ctx->queues = queues + 1; + + /* open a separate set of queues and locks for bwc API */ + err = hws_bwc_send_queues_init(ctx); + if (err) + return err; + + ctx->send_queue = kcalloc(ctx->queues, sizeof(*ctx->send_queue), GFP_KERNEL); + if (!ctx->send_queue) { + err = -ENOMEM; + goto free_bwc_locks; + } + + for (i = 0; i < ctx->queues; i++) { + err = mlx5hws_send_queue_open(ctx, &ctx->send_queue[i], queue_size); + if (err) + goto close_send_queues; + } + + return 0; + +close_send_queues: + __hws_send_queues_close(ctx, i); + + kfree(ctx->send_queue); + +free_bwc_locks: + hws_send_queues_bwc_locks_destroy(ctx); + + return err; +} + +int mlx5hws_send_queue_action(struct mlx5hws_context *ctx, + u16 queue_id, + u32 actions) +{ + struct mlx5hws_send_ring_sq *send_sq; + struct mlx5hws_send_engine *queue; + bool wait_comp = false; + s64 polled = 0; + + queue = &ctx->send_queue[queue_id]; + send_sq = &queue->send_ring.send_sq; + + switch (actions) { + case MLX5HWS_SEND_QUEUE_ACTION_DRAIN_SYNC: + wait_comp = true; + fallthrough; + case MLX5HWS_SEND_QUEUE_ACTION_DRAIN_ASYNC: + if (send_sq->head_dep_idx != send_sq->tail_dep_idx) + /* Send dependent WQEs to drain the queue */ + mlx5hws_send_all_dep_wqe(queue); + else + /* Signal on the last posted WQE */ + mlx5hws_send_engine_flush_queue(queue); + + /* Poll queue until empty */ + while (wait_comp && !mlx5hws_send_engine_empty(queue)) + hws_send_engine_poll_cq(queue, NULL, &polled, 0); + + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +hws_send_wqe_fw(struct mlx5_core_dev *mdev, + u32 pd_num, + struct mlx5hws_send_engine_post_attr *send_attr, + struct mlx5hws_wqe_gta_ctrl_seg *send_wqe_ctrl, + void *send_wqe_match_data, + void *send_wqe_match_tag, + void *send_wqe_range_data, + void *send_wqe_range_tag, + bool is_jumbo, + u8 gta_opcode) +{ + bool has_range = send_wqe_range_data || send_wqe_range_tag; + bool has_match = send_wqe_match_data || send_wqe_match_tag; + struct mlx5hws_wqe_gta_data_seg_ste gta_wqe_data0 = {0}; + struct mlx5hws_wqe_gta_data_seg_ste gta_wqe_data1 = {0}; + struct mlx5hws_wqe_gta_ctrl_seg gta_wqe_ctrl = {0}; + struct mlx5hws_cmd_generate_wqe_attr attr = {0}; + struct mlx5hws_wqe_ctrl_seg wqe_ctrl = {0}; + struct mlx5_cqe64 cqe; + u32 flags = 0; + int ret; + + /* Set WQE control */ + wqe_ctrl.opmod_idx_opcode = cpu_to_be32((send_attr->opmod << 24) | send_attr->opcode); + wqe_ctrl.qpn_ds = cpu_to_be32((send_attr->len + sizeof(struct mlx5hws_wqe_ctrl_seg)) / 16); + flags |= send_attr->notify_hw ? MLX5_WQE_CTRL_CQ_UPDATE : 0; + wqe_ctrl.flags = cpu_to_be32(flags); + wqe_ctrl.imm = cpu_to_be32(send_attr->id); + + /* Set GTA WQE CTRL */ + memcpy(gta_wqe_ctrl.stc_ix, send_wqe_ctrl->stc_ix, sizeof(send_wqe_ctrl->stc_ix)); + gta_wqe_ctrl.op_dirix = cpu_to_be32(gta_opcode << 28); + + /* Set GTA match WQE DATA */ + if (has_match) { + if (send_wqe_match_data) + memcpy(>a_wqe_data0, send_wqe_match_data, sizeof(gta_wqe_data0)); + else + hws_send_wqe_set_tag(>a_wqe_data0, send_wqe_match_tag, is_jumbo); + + gta_wqe_data0.rsvd1_definer = cpu_to_be32(send_attr->match_definer_id << 8); + attr.gta_data_0 = (u8 *)>a_wqe_data0; + } + + /* Set GTA range WQE DATA */ + if (has_range) { + if (send_wqe_range_data) + memcpy(>a_wqe_data1, send_wqe_range_data, sizeof(gta_wqe_data1)); + else + hws_send_wqe_set_tag(>a_wqe_data1, send_wqe_range_tag, false); + + gta_wqe_data1.rsvd1_definer = cpu_to_be32(send_attr->range_definer_id << 8); + attr.gta_data_1 = (u8 *)>a_wqe_data1; + } + + attr.pdn = pd_num; + attr.wqe_ctrl = (u8 *)&wqe_ctrl; + attr.gta_ctrl = (u8 *)>a_wqe_ctrl; + +send_wqe: + ret = mlx5hws_cmd_generate_wqe(mdev, &attr, &cqe); + if (ret) { + mlx5_core_err(mdev, "Failed to write WQE using command"); + return ret; + } + + if ((get_cqe_opcode(&cqe) == MLX5_CQE_REQ) && + (be32_to_cpu(cqe.byte_cnt) >> 31 == 0)) { + *send_attr->used_id = send_attr->id; + return 0; + } + + /* Retry if rule failed */ + if (send_attr->retry_id) { + wqe_ctrl.imm = cpu_to_be32(send_attr->retry_id); + send_attr->id = send_attr->retry_id; + send_attr->retry_id = 0; + goto send_wqe; + } + + return -1; +} + +void mlx5hws_send_stes_fw(struct mlx5hws_context *ctx, + struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ste_attr *ste_attr) +{ + struct mlx5hws_send_engine_post_attr *send_attr = &ste_attr->send_attr; + struct mlx5hws_rule *rule = send_attr->rule; + struct mlx5_core_dev *mdev; + u16 queue_id; + u32 pdn; + int ret; + + queue_id = queue - ctx->send_queue; + mdev = ctx->mdev; + pdn = ctx->pd_num; + + /* Writing through FW can't HW fence, therefore we drain the queue */ + if (send_attr->fence) + mlx5hws_send_queue_action(ctx, + queue_id, + MLX5HWS_SEND_QUEUE_ACTION_DRAIN_SYNC); + + if (ste_attr->rtc_1) { + send_attr->id = ste_attr->rtc_1; + send_attr->used_id = ste_attr->used_id_rtc_1; + send_attr->retry_id = ste_attr->retry_rtc_1; + ret = hws_send_wqe_fw(mdev, pdn, send_attr, + ste_attr->wqe_ctrl, + ste_attr->wqe_data, + ste_attr->wqe_tag, + ste_attr->range_wqe_data, + ste_attr->range_wqe_tag, + ste_attr->wqe_tag_is_jumbo, + ste_attr->gta_opcode); + if (ret) + goto fail_rule; + } + + if (ste_attr->rtc_0) { + send_attr->id = ste_attr->rtc_0; + send_attr->used_id = ste_attr->used_id_rtc_0; + send_attr->retry_id = ste_attr->retry_rtc_0; + ret = hws_send_wqe_fw(mdev, pdn, send_attr, + ste_attr->wqe_ctrl, + ste_attr->wqe_data, + ste_attr->wqe_tag, + ste_attr->range_wqe_data, + ste_attr->range_wqe_tag, + ste_attr->wqe_tag_is_jumbo, + ste_attr->gta_opcode); + if (ret) + goto fail_rule; + } + + /* Increase the status, this only works on good flow as the enum + * is arrange it away creating -> created -> deleting -> deleted + */ + if (likely(rule)) + rule->status++; + + mlx5hws_send_engine_gen_comp(queue, send_attr->user_data, MLX5HWS_FLOW_OP_SUCCESS); + + return; + +fail_rule: + if (likely(rule)) + rule->status = !rule->rtc_0 && !rule->rtc_1 ? + MLX5HWS_RULE_STATUS_FAILED : MLX5HWS_RULE_STATUS_FAILING; + + mlx5hws_send_engine_gen_comp(queue, send_attr->user_data, MLX5HWS_FLOW_OP_ERROR); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.h new file mode 100644 index 00000000000000..b50825d6dc53dc --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/send.h @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef MLX5HWS_SEND_H_ +#define MLX5HWS_SEND_H_ + +/* As a single operation requires at least two WQEBBS. + * This means a maximum of 16 such operations per rule. + */ +#define MAX_WQES_PER_RULE 32 + +enum mlx5hws_wqe_opcode { + MLX5HWS_WQE_OPCODE_TBL_ACCESS = 0x2c, +}; + +enum mlx5hws_wqe_opmod { + MLX5HWS_WQE_OPMOD_GTA_STE = 0, + MLX5HWS_WQE_OPMOD_GTA_MOD_ARG = 1, +}; + +enum mlx5hws_wqe_gta_opcode { + MLX5HWS_WQE_GTA_OP_ACTIVATE = 0, + MLX5HWS_WQE_GTA_OP_DEACTIVATE = 1, +}; + +enum mlx5hws_wqe_gta_opmod { + MLX5HWS_WQE_GTA_OPMOD_STE = 0, + MLX5HWS_WQE_GTA_OPMOD_MOD_ARG = 1, +}; + +enum mlx5hws_wqe_gta_sz { + MLX5HWS_WQE_SZ_GTA_CTRL = 48, + MLX5HWS_WQE_SZ_GTA_DATA = 64, +}; + +/* WQE Control segment. */ +struct mlx5hws_wqe_ctrl_seg { + __be32 opmod_idx_opcode; + __be32 qpn_ds; + __be32 flags; + __be32 imm; +}; + +struct mlx5hws_wqe_gta_ctrl_seg { + __be32 op_dirix; + __be32 stc_ix[5]; + __be32 rsvd0[6]; +}; + +struct mlx5hws_wqe_gta_data_seg_ste { + __be32 rsvd0_ctr_id; + __be32 rsvd1_definer; + __be32 rsvd2[3]; + union { + struct { + __be32 action[3]; + __be32 tag[8]; + }; + __be32 jumbo[11]; + }; +}; + +struct mlx5hws_wqe_gta_data_seg_arg { + __be32 action_args[8]; +}; + +struct mlx5hws_wqe_gta { + struct mlx5hws_wqe_gta_ctrl_seg gta_ctrl; + union { + struct mlx5hws_wqe_gta_data_seg_ste seg_ste; + struct mlx5hws_wqe_gta_data_seg_arg seg_arg; + }; +}; + +struct mlx5hws_send_ring_cq { + struct mlx5_core_dev *mdev; + struct mlx5_cqwq wq; + struct mlx5_wq_ctrl wq_ctrl; + struct mlx5_core_cq mcq; + u16 poll_wqe; +}; + +struct mlx5hws_send_ring_priv { + struct mlx5hws_rule *rule; + void *user_data; + u32 num_wqebbs; + u32 id; + u32 retry_id; + u32 *used_id; +}; + +struct mlx5hws_send_ring_dep_wqe { + struct mlx5hws_wqe_gta_ctrl_seg wqe_ctrl; + struct mlx5hws_wqe_gta_data_seg_ste wqe_data; + struct mlx5hws_rule *rule; + u32 rtc_0; + u32 rtc_1; + u32 retry_rtc_0; + u32 retry_rtc_1; + u32 direct_index; + void *user_data; +}; + +struct mlx5hws_send_ring_sq { + struct mlx5_core_dev *mdev; + u16 cur_post; + u16 buf_mask; + struct mlx5hws_send_ring_priv *wr_priv; + unsigned int last_idx; + struct mlx5hws_send_ring_dep_wqe *dep_wqe; + unsigned int head_dep_idx; + unsigned int tail_dep_idx; + u32 sqn; + struct mlx5_wq_cyc wq; + struct mlx5_wq_ctrl wq_ctrl; + void __iomem *uar_map; +}; + +struct mlx5hws_send_ring { + struct mlx5hws_send_ring_cq send_cq; + struct mlx5hws_send_ring_sq send_sq; +}; + +struct mlx5hws_completed_poll_entry { + void *user_data; + enum mlx5hws_flow_op_status status; +}; + +struct mlx5hws_completed_poll { + struct mlx5hws_completed_poll_entry *entries; + u16 ci; + u16 pi; + u16 mask; +}; + +struct mlx5hws_send_engine { + struct mlx5hws_send_ring send_ring; + struct mlx5_uars_page *uar; /* Uar is shared between rings of a queue */ + struct mlx5hws_completed_poll completed; + u16 used_entries; + u16 num_entries; + bool err; + struct mutex lock; /* Protects the send engine */ +}; + +struct mlx5hws_send_engine_post_ctrl { + struct mlx5hws_send_engine *queue; + struct mlx5hws_send_ring *send_ring; + size_t num_wqebbs; +}; + +struct mlx5hws_send_engine_post_attr { + u8 opcode; + u8 opmod; + u8 notify_hw; + u8 fence; + u8 match_definer_id; + u8 range_definer_id; + size_t len; + struct mlx5hws_rule *rule; + u32 id; + u32 retry_id; + u32 *used_id; + void *user_data; +}; + +struct mlx5hws_send_ste_attr { + u32 rtc_0; + u32 rtc_1; + u32 retry_rtc_0; + u32 retry_rtc_1; + u32 *used_id_rtc_0; + u32 *used_id_rtc_1; + bool wqe_tag_is_jumbo; + u8 gta_opcode; + u32 direct_index; + struct mlx5hws_send_engine_post_attr send_attr; + struct mlx5hws_rule_match_tag *wqe_tag; + struct mlx5hws_rule_match_tag *range_wqe_tag; + struct mlx5hws_wqe_gta_ctrl_seg *wqe_ctrl; + struct mlx5hws_wqe_gta_data_seg_ste *wqe_data; + struct mlx5hws_wqe_gta_data_seg_ste *range_wqe_data; +}; + +struct mlx5hws_send_ring_dep_wqe * +mlx5hws_send_add_new_dep_wqe(struct mlx5hws_send_engine *queue); + +void mlx5hws_send_abort_new_dep_wqe(struct mlx5hws_send_engine *queue); + +void mlx5hws_send_all_dep_wqe(struct mlx5hws_send_engine *queue); + +void mlx5hws_send_queue_close(struct mlx5hws_send_engine *queue); + +int mlx5hws_send_queue_open(struct mlx5hws_context *ctx, + struct mlx5hws_send_engine *queue, + u16 queue_size); + +void mlx5hws_send_queues_close(struct mlx5hws_context *ctx); + +int mlx5hws_send_queues_open(struct mlx5hws_context *ctx, + u16 queues, + u16 queue_size); + +int mlx5hws_send_queue_action(struct mlx5hws_context *ctx, + u16 queue_id, + u32 actions); + +int mlx5hws_send_test(struct mlx5hws_context *ctx, + u16 queues, + u16 queue_size); + +struct mlx5hws_send_engine_post_ctrl +mlx5hws_send_engine_post_start(struct mlx5hws_send_engine *queue); + +void mlx5hws_send_engine_post_req_wqe(struct mlx5hws_send_engine_post_ctrl *ctrl, + char **buf, size_t *len); + +void mlx5hws_send_engine_post_end(struct mlx5hws_send_engine_post_ctrl *ctrl, + struct mlx5hws_send_engine_post_attr *attr); + +void mlx5hws_send_ste(struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ste_attr *ste_attr); + +void mlx5hws_send_stes_fw(struct mlx5hws_context *ctx, + struct mlx5hws_send_engine *queue, + struct mlx5hws_send_ste_attr *ste_attr); + +void mlx5hws_send_engine_flush_queue(struct mlx5hws_send_engine *queue); + +static inline bool mlx5hws_send_engine_empty(struct mlx5hws_send_engine *queue) +{ + struct mlx5hws_send_ring_sq *send_sq = &queue->send_ring.send_sq; + struct mlx5hws_send_ring_cq *send_cq = &queue->send_ring.send_cq; + + return ((send_sq->cur_post & send_sq->buf_mask) == send_cq->poll_wqe); +} + +static inline bool mlx5hws_send_engine_full(struct mlx5hws_send_engine *queue) +{ + return queue->used_entries >= queue->num_entries; +} + +static inline void mlx5hws_send_engine_inc_rule(struct mlx5hws_send_engine *queue) +{ + queue->used_entries++; +} + +static inline void mlx5hws_send_engine_dec_rule(struct mlx5hws_send_engine *queue) +{ + queue->used_entries--; +} + +static inline void mlx5hws_send_engine_gen_comp(struct mlx5hws_send_engine *queue, + void *user_data, + int comp_status) +{ + struct mlx5hws_completed_poll *comp = &queue->completed; + + comp->entries[comp->pi].status = comp_status; + comp->entries[comp->pi].user_data = user_data; + + comp->pi = (comp->pi + 1) & comp->mask; +} + +static inline bool mlx5hws_send_engine_err(struct mlx5hws_send_engine *queue) +{ + return queue->err; +} + +#endif /* MLX5HWS_SEND_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c new file mode 100644 index 00000000000000..9576e02d00c3d2 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.c @@ -0,0 +1,493 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +u32 mlx5hws_table_get_id(struct mlx5hws_table *tbl) +{ + return tbl->ft_id; +} + +static void hws_table_init_next_ft_attr(struct mlx5hws_table *tbl, + struct mlx5hws_cmd_ft_create_attr *ft_attr) +{ + ft_attr->type = tbl->fw_ft_type; + if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) + ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1; + else + ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1; + ft_attr->rtc_valid = true; +} + +static void hws_table_set_cap_attr(struct mlx5hws_table *tbl, + struct mlx5hws_cmd_ft_create_attr *ft_attr) +{ + /* Enabling reformat_en or decap_en for the first flow table + * must be done when all VFs are down. + * However, HWS doesn't know when it is required to create the first FT. + * On the other hand, HWS doesn't use all these FT capabilities at all + * (the API doesn't even provide a way to specify these flags), so we'll + * just set these caps on all the flow tables. + * If HCA_CAP.fdb_dynamic_tunnel is set, this constraint is N/A. + */ + if (!MLX5_CAP_ESW_FLOWTABLE(tbl->ctx->mdev, fdb_dynamic_tunnel)) { + ft_attr->reformat_en = true; + ft_attr->decap_en = true; + } +} + +static int hws_table_up_default_fdb_miss_tbl(struct mlx5hws_table *tbl) +{ + struct mlx5hws_cmd_ft_create_attr ft_attr = {0}; + struct mlx5hws_cmd_set_fte_attr fte_attr = {0}; + struct mlx5hws_cmd_forward_tbl *default_miss; + struct mlx5hws_cmd_set_fte_dest dest = {0}; + struct mlx5hws_context *ctx = tbl->ctx; + u8 tbl_type = tbl->type; + + if (tbl->type != MLX5HWS_TABLE_TYPE_FDB) + return 0; + + if (ctx->common_res[tbl_type].default_miss) { + ctx->common_res[tbl_type].default_miss->refcount++; + return 0; + } + + ft_attr.type = tbl->fw_ft_type; + ft_attr.level = tbl->ctx->caps->fdb_ft.max_level; /* The last level */ + ft_attr.rtc_valid = false; + + dest.destination_type = MLX5_FLOW_DESTINATION_TYPE_VPORT; + dest.destination_id = ctx->caps->eswitch_manager_vport_number; + + fte_attr.action_flags = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; + fte_attr.dests_num = 1; + fte_attr.dests = &dest; + + default_miss = mlx5hws_cmd_forward_tbl_create(ctx->mdev, &ft_attr, &fte_attr); + if (!default_miss) { + mlx5hws_err(ctx, "Failed to default miss table type: 0x%x\n", tbl_type); + return -EINVAL; + } + + /* ctx->ctrl_lock must be held here */ + ctx->common_res[tbl_type].default_miss = default_miss; + ctx->common_res[tbl_type].default_miss->refcount++; + + return 0; +} + +/* Called under ctx->ctrl_lock */ +static void hws_table_down_default_fdb_miss_tbl(struct mlx5hws_table *tbl) +{ + struct mlx5hws_cmd_forward_tbl *default_miss; + struct mlx5hws_context *ctx = tbl->ctx; + u8 tbl_type = tbl->type; + + if (tbl->type != MLX5HWS_TABLE_TYPE_FDB) + return; + + default_miss = ctx->common_res[tbl_type].default_miss; + if (--default_miss->refcount) + return; + + mlx5hws_cmd_forward_tbl_destroy(ctx->mdev, default_miss); + ctx->common_res[tbl_type].default_miss = NULL; +} + +static int hws_table_connect_to_default_miss_tbl(struct mlx5hws_table *tbl, u32 ft_id) +{ + struct mlx5hws_cmd_ft_modify_attr ft_attr = {0}; + int ret; + + if (unlikely(tbl->type != MLX5HWS_TABLE_TYPE_FDB)) + pr_warn("HWS: invalid table type %d\n", tbl->type); + + mlx5hws_cmd_set_attr_connect_miss_tbl(tbl->ctx, + tbl->fw_ft_type, + tbl->type, + &ft_attr); + + ret = mlx5hws_cmd_flow_table_modify(tbl->ctx->mdev, &ft_attr, ft_id); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed to connect FT to default FDB FT\n"); + return ret; + } + + return 0; +} + +int mlx5hws_table_create_default_ft(struct mlx5_core_dev *mdev, + struct mlx5hws_table *tbl, + u32 *ft_id) +{ + struct mlx5hws_cmd_ft_create_attr ft_attr = {0}; + int ret; + + hws_table_init_next_ft_attr(tbl, &ft_attr); + hws_table_set_cap_attr(tbl, &ft_attr); + + ret = mlx5hws_cmd_flow_table_create(mdev, &ft_attr, ft_id); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed creating default ft\n"); + return ret; + } + + if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) { + /* Take/create ref over the default miss */ + ret = hws_table_up_default_fdb_miss_tbl(tbl); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed to get default fdb miss\n"); + goto free_ft_obj; + } + ret = hws_table_connect_to_default_miss_tbl(tbl, *ft_id); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed connecting to default miss tbl\n"); + goto down_miss_tbl; + } + } + + return 0; + +down_miss_tbl: + hws_table_down_default_fdb_miss_tbl(tbl); +free_ft_obj: + mlx5hws_cmd_flow_table_destroy(mdev, ft_attr.type, *ft_id); + return ret; +} + +void mlx5hws_table_destroy_default_ft(struct mlx5hws_table *tbl, + u32 ft_id) +{ + mlx5hws_cmd_flow_table_destroy(tbl->ctx->mdev, tbl->fw_ft_type, ft_id); + hws_table_down_default_fdb_miss_tbl(tbl); +} + +static int hws_table_init_check_hws_support(struct mlx5hws_context *ctx, + struct mlx5hws_table *tbl) +{ + if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) { + mlx5hws_err(ctx, "HWS not supported, cannot create mlx5hws_table\n"); + return -EOPNOTSUPP; + } + + return 0; +} + +static int hws_table_init(struct mlx5hws_table *tbl) +{ + struct mlx5hws_context *ctx = tbl->ctx; + int ret; + + ret = hws_table_init_check_hws_support(ctx, tbl); + if (ret) + return ret; + + if (mlx5hws_table_get_fw_ft_type(tbl->type, (u8 *)&tbl->fw_ft_type)) { + pr_warn("HWS: invalid table type %d\n", tbl->type); + return -EOPNOTSUPP; + } + + mutex_lock(&ctx->ctrl_lock); + ret = mlx5hws_table_create_default_ft(tbl->ctx->mdev, tbl, &tbl->ft_id); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed to create flow table object\n"); + mutex_unlock(&ctx->ctrl_lock); + return ret; + } + + ret = mlx5hws_action_get_default_stc(ctx, tbl->type); + if (ret) + goto tbl_destroy; + + INIT_LIST_HEAD(&tbl->matchers_list); + INIT_LIST_HEAD(&tbl->default_miss.head); + + mutex_unlock(&ctx->ctrl_lock); + + return 0; + +tbl_destroy: + mlx5hws_table_destroy_default_ft(tbl, tbl->ft_id); + mutex_unlock(&ctx->ctrl_lock); + return ret; +} + +static void hws_table_uninit(struct mlx5hws_table *tbl) +{ + mutex_lock(&tbl->ctx->ctrl_lock); + mlx5hws_action_put_default_stc(tbl->ctx, tbl->type); + mlx5hws_table_destroy_default_ft(tbl, tbl->ft_id); + mutex_unlock(&tbl->ctx->ctrl_lock); +} + +struct mlx5hws_table *mlx5hws_table_create(struct mlx5hws_context *ctx, + struct mlx5hws_table_attr *attr) +{ + struct mlx5hws_table *tbl; + int ret; + + if (attr->type > MLX5HWS_TABLE_TYPE_FDB) { + mlx5hws_err(ctx, "Invalid table type %d\n", attr->type); + return NULL; + } + + tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); + if (!tbl) + return NULL; + + tbl->ctx = ctx; + tbl->type = attr->type; + tbl->level = attr->level; + + ret = hws_table_init(tbl); + if (ret) { + mlx5hws_err(ctx, "Failed to initialise table\n"); + goto free_tbl; + } + + mutex_lock(&ctx->ctrl_lock); + list_add(&tbl->tbl_list_node, &ctx->tbl_list); + mutex_unlock(&ctx->ctrl_lock); + + return tbl; + +free_tbl: + kfree(tbl); + return NULL; +} + +int mlx5hws_table_destroy(struct mlx5hws_table *tbl) +{ + struct mlx5hws_context *ctx = tbl->ctx; + int ret; + + mutex_lock(&ctx->ctrl_lock); + if (!list_empty(&tbl->matchers_list)) { + mlx5hws_err(tbl->ctx, "Cannot destroy table containing matchers\n"); + ret = -EBUSY; + goto unlock_err; + } + + if (!list_empty(&tbl->default_miss.head)) { + mlx5hws_err(tbl->ctx, "Cannot destroy table pointed by default miss\n"); + ret = -EBUSY; + goto unlock_err; + } + + list_del_init(&tbl->tbl_list_node); + mutex_unlock(&ctx->ctrl_lock); + + hws_table_uninit(tbl); + kfree(tbl); + + return 0; + +unlock_err: + mutex_unlock(&ctx->ctrl_lock); + return ret; +} + +static u32 hws_table_get_last_ft(struct mlx5hws_table *tbl) +{ + struct mlx5hws_matcher *matcher; + + if (list_empty(&tbl->matchers_list)) + return tbl->ft_id; + + matcher = list_last_entry(&tbl->matchers_list, struct mlx5hws_matcher, list_node); + return matcher->end_ft_id; +} + +int mlx5hws_table_ft_set_default_next_ft(struct mlx5hws_table *tbl, u32 ft_id) +{ + struct mlx5hws_cmd_ft_modify_attr ft_attr = {0}; + int ret; + + /* Due to FW limitation, resetting the flow table to default action will + * disconnect RTC when ignore_flow_level_rtc_valid is not supported. + */ + if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid) + return 0; + + if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) + return hws_table_connect_to_default_miss_tbl(tbl, ft_id); + + ft_attr.type = tbl->fw_ft_type; + ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION; + ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_DEFAULT; + + ret = mlx5hws_cmd_flow_table_modify(tbl->ctx->mdev, &ft_attr, ft_id); + if (ret) { + mlx5hws_err(tbl->ctx, "Failed to set FT default miss action\n"); + return ret; + } + + return 0; +} + +int mlx5hws_table_ft_set_next_rtc(struct mlx5hws_context *ctx, + u32 ft_id, + u32 fw_ft_type, + u32 rtc_0_id, + u32 rtc_1_id) +{ + struct mlx5hws_cmd_ft_modify_attr ft_attr = {0}; + + ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_RTC_ID; + ft_attr.type = fw_ft_type; + ft_attr.rtc_id_0 = rtc_0_id; + ft_attr.rtc_id_1 = rtc_1_id; + + return mlx5hws_cmd_flow_table_modify(ctx->mdev, &ft_attr, ft_id); +} + +static int hws_table_ft_set_next_ft(struct mlx5hws_context *ctx, + u32 ft_id, + u32 fw_ft_type, + u32 next_ft_id) +{ + struct mlx5hws_cmd_ft_modify_attr ft_attr = {0}; + + ft_attr.modify_fs = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION; + ft_attr.table_miss_action = MLX5_IFC_MODIFY_FLOW_TABLE_MISS_ACTION_GOTO_TBL; + ft_attr.type = fw_ft_type; + ft_attr.table_miss_id = next_ft_id; + + return mlx5hws_cmd_flow_table_modify(ctx->mdev, &ft_attr, ft_id); +} + +int mlx5hws_table_update_connected_miss_tables(struct mlx5hws_table *dst_tbl) +{ + struct mlx5hws_table *src_tbl; + int ret; + + if (list_empty(&dst_tbl->default_miss.head)) + return 0; + + list_for_each_entry(src_tbl, &dst_tbl->default_miss.head, default_miss.next) { + ret = mlx5hws_table_connect_to_miss_table(src_tbl, dst_tbl); + if (ret) { + mlx5hws_err(dst_tbl->ctx, + "Failed to update source miss table, unexpected behavior\n"); + return ret; + } + } + + return 0; +} + +int mlx5hws_table_connect_to_miss_table(struct mlx5hws_table *src_tbl, + struct mlx5hws_table *dst_tbl) +{ + struct mlx5hws_matcher *matcher; + u32 last_ft_id; + int ret; + + last_ft_id = hws_table_get_last_ft(src_tbl); + + if (dst_tbl) { + if (list_empty(&dst_tbl->matchers_list)) { + /* Connect src_tbl last_ft to dst_tbl start anchor */ + ret = hws_table_ft_set_next_ft(src_tbl->ctx, + last_ft_id, + src_tbl->fw_ft_type, + dst_tbl->ft_id); + if (ret) + return ret; + + /* Reset last_ft RTC to default RTC */ + ret = mlx5hws_table_ft_set_next_rtc(src_tbl->ctx, + last_ft_id, + src_tbl->fw_ft_type, + 0, 0); + if (ret) + return ret; + } else { + /* Connect src_tbl last_ft to first matcher RTC */ + matcher = list_first_entry(&dst_tbl->matchers_list, + struct mlx5hws_matcher, + list_node); + ret = mlx5hws_table_ft_set_next_rtc(src_tbl->ctx, + last_ft_id, + src_tbl->fw_ft_type, + matcher->match_ste.rtc_0_id, + matcher->match_ste.rtc_1_id); + if (ret) + return ret; + + /* Reset next miss FT to default */ + ret = mlx5hws_table_ft_set_default_next_ft(src_tbl, last_ft_id); + if (ret) + return ret; + } + } else { + /* Reset next miss FT to default */ + ret = mlx5hws_table_ft_set_default_next_ft(src_tbl, last_ft_id); + if (ret) + return ret; + + /* Reset last_ft RTC to default RTC */ + ret = mlx5hws_table_ft_set_next_rtc(src_tbl->ctx, + last_ft_id, + src_tbl->fw_ft_type, + 0, 0); + if (ret) + return ret; + } + + src_tbl->default_miss.miss_tbl = dst_tbl; + + return 0; +} + +static int hws_table_set_default_miss_not_valid(struct mlx5hws_table *tbl, + struct mlx5hws_table *miss_tbl) +{ + if (!tbl->ctx->caps->nic_ft.ignore_flow_level_rtc_valid) { + mlx5hws_err(tbl->ctx, "Default miss table is not supported\n"); + return -EOPNOTSUPP; + } + + if ((miss_tbl && miss_tbl->type != tbl->type)) { + mlx5hws_err(tbl->ctx, "Invalid arguments\n"); + return -EINVAL; + } + + return 0; +} + +int mlx5hws_table_set_default_miss(struct mlx5hws_table *tbl, + struct mlx5hws_table *miss_tbl) +{ + struct mlx5hws_context *ctx = tbl->ctx; + struct mlx5hws_table *old_miss_tbl; + int ret; + + ret = hws_table_set_default_miss_not_valid(tbl, miss_tbl); + if (ret) + return ret; + + mutex_lock(&ctx->ctrl_lock); + + old_miss_tbl = tbl->default_miss.miss_tbl; + ret = mlx5hws_table_connect_to_miss_table(tbl, miss_tbl); + if (ret) + goto out; + + if (old_miss_tbl) + list_del_init(&tbl->default_miss.next); + + old_miss_tbl = tbl->default_miss.miss_tbl; + if (old_miss_tbl) + list_del_init(&old_miss_tbl->default_miss.head); + + if (miss_tbl) + list_add(&tbl->default_miss.next, &miss_tbl->default_miss.head); + + mutex_unlock(&ctx->ctrl_lock); + return 0; +out: + mutex_unlock(&ctx->ctrl_lock); + return ret; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h new file mode 100644 index 00000000000000..dd50420eec9eae --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/table.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef MLX5HWS_TABLE_H_ +#define MLX5HWS_TABLE_H_ + +struct mlx5hws_default_miss { + /* My miss table */ + struct mlx5hws_table *miss_tbl; + struct list_head next; + /* Tables missing to my table */ + struct list_head head; +}; + +struct mlx5hws_table { + struct mlx5hws_context *ctx; + u32 ft_id; + enum mlx5hws_table_type type; + u32 fw_ft_type; + u32 level; + struct list_head matchers_list; + struct list_head tbl_list_node; + struct mlx5hws_default_miss default_miss; +}; + +static inline +u32 mlx5hws_table_get_fw_ft_type(enum mlx5hws_table_type type, + u8 *ret_type) +{ + if (type != MLX5HWS_TABLE_TYPE_FDB) + return -EOPNOTSUPP; + + *ret_type = FS_FT_FDB; + + return 0; +} + +static inline +u32 mlx5hws_table_get_res_fw_ft_type(enum mlx5hws_table_type tbl_type, + bool is_mirror) +{ + if (tbl_type == MLX5HWS_TABLE_TYPE_FDB) + return is_mirror ? FS_FT_FDB_TX : FS_FT_FDB_RX; + + return 0; +} + +int mlx5hws_table_create_default_ft(struct mlx5_core_dev *mdev, + struct mlx5hws_table *tbl, + u32 *ft_id); + +void mlx5hws_table_destroy_default_ft(struct mlx5hws_table *tbl, + u32 ft_id); + +int mlx5hws_table_connect_to_miss_table(struct mlx5hws_table *src_tbl, + struct mlx5hws_table *dst_tbl); + +int mlx5hws_table_update_connected_miss_tables(struct mlx5hws_table *dst_tbl); + +int mlx5hws_table_ft_set_default_next_ft(struct mlx5hws_table *tbl, u32 ft_id); + +int mlx5hws_table_ft_set_next_rtc(struct mlx5hws_context *ctx, + u32 ft_id, + u32 fw_ft_type, + u32 rtc_0_id, + u32 rtc_1_id); + +#endif /* MLX5HWS_TABLE_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.c new file mode 100644 index 00000000000000..d8e382b9fa61e0 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#include "internal.h" + +int mlx5hws_vport_init_vports(struct mlx5hws_context *ctx) +{ + int ret; + + if (!ctx->caps->eswitch_manager) + return 0; + + xa_init(&ctx->vports.vport_gvmi_xa); + + /* Set gvmi for eswitch manager and uplink vports only. Rest of the vports + * (vport 0 of other function, VFs and SFs) will be queried dynamically. + */ + + ret = mlx5hws_cmd_query_gvmi(ctx->mdev, false, 0, &ctx->vports.esw_manager_gvmi); + if (ret) + return ret; + + ctx->vports.uplink_gvmi = 0; + return 0; +} + +void mlx5hws_vport_uninit_vports(struct mlx5hws_context *ctx) +{ + if (ctx->caps->eswitch_manager) + xa_destroy(&ctx->vports.vport_gvmi_xa); +} + +static int hws_vport_add_gvmi(struct mlx5hws_context *ctx, u16 vport) +{ + u16 vport_gvmi; + int ret; + + ret = mlx5hws_cmd_query_gvmi(ctx->mdev, true, vport, &vport_gvmi); + if (ret) + return -EINVAL; + + ret = xa_insert(&ctx->vports.vport_gvmi_xa, vport, + xa_mk_value(vport_gvmi), GFP_KERNEL); + if (ret) + mlx5hws_dbg(ctx, "Couldn't insert new vport gvmi into xarray (%d)\n", ret); + + return ret; +} + +static bool hws_vport_is_esw_mgr_vport(struct mlx5hws_context *ctx, u16 vport) +{ + return ctx->caps->is_ecpf ? vport == MLX5_VPORT_ECPF : + vport == MLX5_VPORT_PF; +} + +int mlx5hws_vport_get_gvmi(struct mlx5hws_context *ctx, u16 vport, u16 *vport_gvmi) +{ + void *entry; + int ret; + + if (!ctx->caps->eswitch_manager) + return -EINVAL; + + if (hws_vport_is_esw_mgr_vport(ctx, vport)) { + *vport_gvmi = ctx->vports.esw_manager_gvmi; + return 0; + } + + if (vport == MLX5_VPORT_UPLINK) { + *vport_gvmi = ctx->vports.uplink_gvmi; + return 0; + } + +load_entry: + entry = xa_load(&ctx->vports.vport_gvmi_xa, vport); + + if (!xa_is_value(entry)) { + ret = hws_vport_add_gvmi(ctx, vport); + if (ret && ret != -EBUSY) + return ret; + goto load_entry; + } + + *vport_gvmi = (u16)xa_to_value(entry); + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.h new file mode 100644 index 00000000000000..0912fc166b3a63 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/vport.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2024 NVIDIA Corporation & Affiliates */ + +#ifndef MLX5HWS_VPORT_H_ +#define MLX5HWS_VPORT_H_ + +int mlx5hws_vport_init_vports(struct mlx5hws_context *ctx); + +void mlx5hws_vport_uninit_vports(struct mlx5hws_context *ctx); + +int mlx5hws_vport_get_gvmi(struct mlx5hws_context *ctx, u16 vport, u16 *vport_gvmi); + +#endif /* MLX5HWS_VPORT_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h deleted file mode 100644 index fb078fa0f0cc83..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h +++ /dev/null @@ -1,603 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2019, Mellanox Technologies */ - -#ifndef MLX5_IFC_DR_H -#define MLX5_IFC_DR_H - -enum { - MLX5DR_STE_LU_TYPE_DONT_CARE = 0x0f, -}; - -struct mlx5_ifc_ste_general_bits { - u8 entry_type[0x4]; - u8 reserved_at_4[0x4]; - u8 entry_sub_type[0x8]; - u8 byte_mask[0x10]; - - u8 next_table_base_63_48[0x10]; - u8 next_lu_type[0x8]; - u8 next_table_base_39_32_size[0x8]; - - u8 next_table_base_31_5_size[0x1b]; - u8 linear_hash_enable[0x1]; - u8 reserved_at_5c[0x2]; - u8 next_table_rank[0x2]; - - u8 reserved_at_60[0xa0]; - u8 tag_value[0x60]; - u8 bit_mask[0x60]; -}; - -struct mlx5_ifc_ste_sx_transmit_bits { - u8 entry_type[0x4]; - u8 reserved_at_4[0x4]; - u8 entry_sub_type[0x8]; - u8 byte_mask[0x10]; - - u8 next_table_base_63_48[0x10]; - u8 next_lu_type[0x8]; - u8 next_table_base_39_32_size[0x8]; - - u8 next_table_base_31_5_size[0x1b]; - u8 linear_hash_enable[0x1]; - u8 reserved_at_5c[0x2]; - u8 next_table_rank[0x2]; - - u8 sx_wire[0x1]; - u8 sx_func_lb[0x1]; - u8 sx_sniffer[0x1]; - u8 sx_wire_enable[0x1]; - u8 sx_func_lb_enable[0x1]; - u8 sx_sniffer_enable[0x1]; - u8 action_type[0x3]; - u8 reserved_at_69[0x1]; - u8 action_description[0x6]; - u8 gvmi[0x10]; - - u8 encap_pointer_vlan_data[0x20]; - - u8 loopback_syndome_en[0x8]; - u8 loopback_syndome[0x8]; - u8 counter_trigger[0x10]; - - u8 miss_address_63_48[0x10]; - u8 counter_trigger_23_16[0x8]; - u8 miss_address_39_32[0x8]; - - u8 miss_address_31_6[0x1a]; - u8 learning_point[0x1]; - u8 go_back[0x1]; - u8 match_polarity[0x1]; - u8 mask_mode[0x1]; - u8 miss_rank[0x2]; -}; - -struct mlx5_ifc_ste_rx_steering_mult_bits { - u8 entry_type[0x4]; - u8 reserved_at_4[0x4]; - u8 entry_sub_type[0x8]; - u8 byte_mask[0x10]; - - u8 next_table_base_63_48[0x10]; - u8 next_lu_type[0x8]; - u8 next_table_base_39_32_size[0x8]; - - u8 next_table_base_31_5_size[0x1b]; - u8 linear_hash_enable[0x1]; - u8 reserved_at_[0x2]; - u8 next_table_rank[0x2]; - - u8 member_count[0x10]; - u8 gvmi[0x10]; - - u8 qp_list_pointer[0x20]; - - u8 reserved_at_a0[0x1]; - u8 tunneling_action[0x3]; - u8 action_description[0x4]; - u8 reserved_at_a8[0x8]; - u8 counter_trigger_15_0[0x10]; - - u8 miss_address_63_48[0x10]; - u8 counter_trigger_23_16[0x08]; - u8 miss_address_39_32[0x8]; - - u8 miss_address_31_6[0x1a]; - u8 learning_point[0x1]; - u8 fail_on_error[0x1]; - u8 match_polarity[0x1]; - u8 mask_mode[0x1]; - u8 miss_rank[0x2]; -}; - -struct mlx5_ifc_ste_modify_packet_bits { - u8 entry_type[0x4]; - u8 reserved_at_4[0x4]; - u8 entry_sub_type[0x8]; - u8 byte_mask[0x10]; - - u8 next_table_base_63_48[0x10]; - u8 next_lu_type[0x8]; - u8 next_table_base_39_32_size[0x8]; - - u8 next_table_base_31_5_size[0x1b]; - u8 linear_hash_enable[0x1]; - u8 reserved_at_[0x2]; - u8 next_table_rank[0x2]; - - u8 number_of_re_write_actions[0x10]; - u8 gvmi[0x10]; - - u8 header_re_write_actions_pointer[0x20]; - - u8 reserved_at_a0[0x1]; - u8 tunneling_action[0x3]; - u8 action_description[0x4]; - u8 reserved_at_a8[0x8]; - u8 counter_trigger_15_0[0x10]; - - u8 miss_address_63_48[0x10]; - u8 counter_trigger_23_16[0x08]; - u8 miss_address_39_32[0x8]; - - u8 miss_address_31_6[0x1a]; - u8 learning_point[0x1]; - u8 fail_on_error[0x1]; - u8 match_polarity[0x1]; - u8 mask_mode[0x1]; - u8 miss_rank[0x2]; -}; - -struct mlx5_ifc_ste_eth_l2_src_bits { - u8 smac_47_16[0x20]; - - u8 smac_15_0[0x10]; - u8 l3_ethertype[0x10]; - - u8 qp_type[0x2]; - u8 ethertype_filter[0x1]; - u8 reserved_at_43[0x1]; - u8 sx_sniffer[0x1]; - u8 force_lb[0x1]; - u8 functional_lb[0x1]; - u8 port[0x1]; - u8 reserved_at_48[0x4]; - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 first_vlan_qualifier[0x2]; - u8 reserved_at_52[0x2]; - u8 first_vlan_id[0xc]; - - u8 ip_fragmented[0x1]; - u8 tcp_syn[0x1]; - u8 encp_type[0x2]; - u8 l3_type[0x2]; - u8 l4_type[0x2]; - u8 reserved_at_68[0x4]; - u8 second_priority[0x3]; - u8 second_cfi[0x1]; - u8 second_vlan_qualifier[0x2]; - u8 reserved_at_72[0x2]; - u8 second_vlan_id[0xc]; -}; - -struct mlx5_ifc_ste_eth_l2_dst_bits { - u8 dmac_47_16[0x20]; - - u8 dmac_15_0[0x10]; - u8 l3_ethertype[0x10]; - - u8 qp_type[0x2]; - u8 ethertype_filter[0x1]; - u8 reserved_at_43[0x1]; - u8 sx_sniffer[0x1]; - u8 force_lb[0x1]; - u8 functional_lb[0x1]; - u8 port[0x1]; - u8 reserved_at_48[0x4]; - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 first_vlan_qualifier[0x2]; - u8 reserved_at_52[0x2]; - u8 first_vlan_id[0xc]; - - u8 ip_fragmented[0x1]; - u8 tcp_syn[0x1]; - u8 encp_type[0x2]; - u8 l3_type[0x2]; - u8 l4_type[0x2]; - u8 reserved_at_68[0x4]; - u8 second_priority[0x3]; - u8 second_cfi[0x1]; - u8 second_vlan_qualifier[0x2]; - u8 reserved_at_72[0x2]; - u8 second_vlan_id[0xc]; -}; - -struct mlx5_ifc_ste_eth_l2_src_dst_bits { - u8 dmac_47_16[0x20]; - - u8 dmac_15_0[0x10]; - u8 smac_47_32[0x10]; - - u8 smac_31_0[0x20]; - - u8 sx_sniffer[0x1]; - u8 force_lb[0x1]; - u8 functional_lb[0x1]; - u8 port[0x1]; - u8 l3_type[0x2]; - u8 reserved_at_66[0x6]; - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 first_vlan_qualifier[0x2]; - u8 reserved_at_72[0x2]; - u8 first_vlan_id[0xc]; -}; - -struct mlx5_ifc_ste_eth_l3_ipv4_5_tuple_bits { - u8 destination_address[0x20]; - - u8 source_address[0x20]; - - u8 source_port[0x10]; - u8 destination_port[0x10]; - - u8 fragmented[0x1]; - u8 first_fragment[0x1]; - u8 reserved_at_62[0x2]; - u8 reserved_at_64[0x1]; - u8 ecn[0x2]; - u8 tcp_ns[0x1]; - u8 tcp_cwr[0x1]; - u8 tcp_ece[0x1]; - u8 tcp_urg[0x1]; - u8 tcp_ack[0x1]; - u8 tcp_psh[0x1]; - u8 tcp_rst[0x1]; - u8 tcp_syn[0x1]; - u8 tcp_fin[0x1]; - u8 dscp[0x6]; - u8 reserved_at_76[0x2]; - u8 protocol[0x8]; -}; - -struct mlx5_ifc_ste_eth_l3_ipv6_dst_bits { - u8 dst_ip_127_96[0x20]; - - u8 dst_ip_95_64[0x20]; - - u8 dst_ip_63_32[0x20]; - - u8 dst_ip_31_0[0x20]; -}; - -struct mlx5_ifc_ste_eth_l2_tnl_bits { - u8 dmac_47_16[0x20]; - - u8 dmac_15_0[0x10]; - u8 l3_ethertype[0x10]; - - u8 l2_tunneling_network_id[0x20]; - - u8 ip_fragmented[0x1]; - u8 tcp_syn[0x1]; - u8 encp_type[0x2]; - u8 l3_type[0x2]; - u8 l4_type[0x2]; - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 reserved_at_6c[0x3]; - u8 gre_key_flag[0x1]; - u8 first_vlan_qualifier[0x2]; - u8 reserved_at_72[0x2]; - u8 first_vlan_id[0xc]; -}; - -struct mlx5_ifc_ste_eth_l3_ipv6_src_bits { - u8 src_ip_127_96[0x20]; - - u8 src_ip_95_64[0x20]; - - u8 src_ip_63_32[0x20]; - - u8 src_ip_31_0[0x20]; -}; - -struct mlx5_ifc_ste_eth_l3_ipv4_misc_bits { - u8 version[0x4]; - u8 ihl[0x4]; - u8 reserved_at_8[0x8]; - u8 total_length[0x10]; - - u8 identification[0x10]; - u8 flags[0x3]; - u8 fragment_offset[0xd]; - - u8 time_to_live[0x8]; - u8 reserved_at_48[0x8]; - u8 checksum[0x10]; - - u8 reserved_at_60[0x20]; -}; - -struct mlx5_ifc_ste_eth_l4_bits { - u8 fragmented[0x1]; - u8 first_fragment[0x1]; - u8 reserved_at_2[0x6]; - u8 protocol[0x8]; - u8 dst_port[0x10]; - - u8 ipv6_version[0x4]; - u8 reserved_at_24[0x1]; - u8 ecn[0x2]; - u8 tcp_ns[0x1]; - u8 tcp_cwr[0x1]; - u8 tcp_ece[0x1]; - u8 tcp_urg[0x1]; - u8 tcp_ack[0x1]; - u8 tcp_psh[0x1]; - u8 tcp_rst[0x1]; - u8 tcp_syn[0x1]; - u8 tcp_fin[0x1]; - u8 src_port[0x10]; - - u8 ipv6_payload_length[0x10]; - u8 ipv6_hop_limit[0x8]; - u8 dscp[0x6]; - u8 reserved_at_5e[0x2]; - - u8 tcp_data_offset[0x4]; - u8 reserved_at_64[0x8]; - u8 flow_label[0x14]; -}; - -struct mlx5_ifc_ste_eth_l4_misc_bits { - u8 checksum[0x10]; - u8 length[0x10]; - - u8 seq_num[0x20]; - - u8 ack_num[0x20]; - - u8 urgent_pointer[0x10]; - u8 window_size[0x10]; -}; - -struct mlx5_ifc_ste_mpls_bits { - u8 mpls0_label[0x14]; - u8 mpls0_exp[0x3]; - u8 mpls0_s_bos[0x1]; - u8 mpls0_ttl[0x8]; - - u8 mpls1_label[0x20]; - - u8 mpls2_label[0x20]; - - u8 reserved_at_60[0x16]; - u8 mpls4_s_bit[0x1]; - u8 mpls4_qualifier[0x1]; - u8 mpls3_s_bit[0x1]; - u8 mpls3_qualifier[0x1]; - u8 mpls2_s_bit[0x1]; - u8 mpls2_qualifier[0x1]; - u8 mpls1_s_bit[0x1]; - u8 mpls1_qualifier[0x1]; - u8 mpls0_s_bit[0x1]; - u8 mpls0_qualifier[0x1]; -}; - -struct mlx5_ifc_ste_register_0_bits { - u8 register_0_h[0x20]; - - u8 register_0_l[0x20]; - - u8 register_1_h[0x20]; - - u8 register_1_l[0x20]; -}; - -struct mlx5_ifc_ste_register_1_bits { - u8 register_2_h[0x20]; - - u8 register_2_l[0x20]; - - u8 register_3_h[0x20]; - - u8 register_3_l[0x20]; -}; - -struct mlx5_ifc_ste_gre_bits { - u8 gre_c_present[0x1]; - u8 reserved_at_30[0x1]; - u8 gre_k_present[0x1]; - u8 gre_s_present[0x1]; - u8 strict_src_route[0x1]; - u8 recur[0x3]; - u8 flags[0x5]; - u8 version[0x3]; - u8 gre_protocol[0x10]; - - u8 checksum[0x10]; - u8 offset[0x10]; - - u8 gre_key_h[0x18]; - u8 gre_key_l[0x8]; - - u8 seq_num[0x20]; -}; - -struct mlx5_ifc_ste_flex_parser_0_bits { - u8 flex_parser_3[0x20]; - - u8 flex_parser_2[0x20]; - - u8 flex_parser_1[0x20]; - - u8 flex_parser_0[0x20]; -}; - -struct mlx5_ifc_ste_flex_parser_1_bits { - u8 flex_parser_7[0x20]; - - u8 flex_parser_6[0x20]; - - u8 flex_parser_5[0x20]; - - u8 flex_parser_4[0x20]; -}; - -struct mlx5_ifc_ste_flex_parser_ok_bits { - u8 flex_parser_3[0x20]; - u8 flex_parser_2[0x20]; - u8 flex_parsers_ok[0x8]; - u8 reserved_at_48[0x18]; - u8 flex_parser_0[0x20]; -}; - -struct mlx5_ifc_ste_flex_parser_tnl_bits { - u8 flex_parser_tunneling_header_63_32[0x20]; - - u8 flex_parser_tunneling_header_31_0[0x20]; - - u8 reserved_at_40[0x40]; -}; - -struct mlx5_ifc_ste_flex_parser_tnl_vxlan_gpe_bits { - u8 outer_vxlan_gpe_flags[0x8]; - u8 reserved_at_8[0x10]; - u8 outer_vxlan_gpe_next_protocol[0x8]; - - u8 outer_vxlan_gpe_vni[0x18]; - u8 reserved_at_38[0x8]; - - u8 reserved_at_40[0x40]; -}; - -struct mlx5_ifc_ste_flex_parser_tnl_geneve_bits { - u8 reserved_at_0[0x2]; - u8 geneve_opt_len[0x6]; - u8 geneve_oam[0x1]; - u8 reserved_at_9[0x7]; - u8 geneve_protocol_type[0x10]; - - u8 geneve_vni[0x18]; - u8 reserved_at_38[0x8]; - - u8 reserved_at_40[0x40]; -}; - -struct mlx5_ifc_ste_flex_parser_tnl_gtpu_bits { - u8 reserved_at_0[0x5]; - u8 gtpu_msg_flags[0x3]; - u8 gtpu_msg_type[0x8]; - u8 reserved_at_10[0x10]; - - u8 gtpu_teid[0x20]; - - u8 reserved_at_40[0x40]; -}; - -struct mlx5_ifc_ste_tunnel_header_bits { - u8 tunnel_header_0[0x20]; - - u8 tunnel_header_1[0x20]; - - u8 reserved_at_40[0x40]; -}; - -struct mlx5_ifc_ste_general_purpose_bits { - u8 general_purpose_lookup_field[0x20]; - - u8 reserved_at_20[0x20]; - - u8 reserved_at_40[0x20]; - - u8 reserved_at_60[0x20]; -}; - -struct mlx5_ifc_ste_src_gvmi_qp_bits { - u8 loopback_syndrome[0x8]; - u8 reserved_at_8[0x8]; - u8 source_gvmi[0x10]; - - u8 reserved_at_20[0x5]; - u8 force_lb[0x1]; - u8 functional_lb[0x1]; - u8 source_is_requestor[0x1]; - u8 source_qp[0x18]; - - u8 reserved_at_40[0x20]; - - u8 reserved_at_60[0x20]; -}; - -struct mlx5_ifc_l2_hdr_bits { - u8 dmac_47_16[0x20]; - - u8 dmac_15_0[0x10]; - u8 smac_47_32[0x10]; - - u8 smac_31_0[0x20]; - - u8 ethertype[0x10]; - u8 vlan_type[0x10]; - - u8 vlan[0x10]; - u8 reserved_at_90[0x10]; -}; - -/* Both HW set and HW add share the same HW format with different opcodes */ -struct mlx5_ifc_dr_action_hw_set_bits { - u8 opcode[0x8]; - u8 destination_field_code[0x8]; - u8 reserved_at_10[0x2]; - u8 destination_left_shifter[0x6]; - u8 reserved_at_18[0x3]; - u8 destination_length[0x5]; - - u8 inline_data[0x20]; -}; - -struct mlx5_ifc_dr_action_hw_copy_bits { - u8 opcode[0x8]; - u8 destination_field_code[0x8]; - u8 reserved_at_10[0x2]; - u8 destination_left_shifter[0x6]; - u8 reserved_at_18[0x2]; - u8 destination_length[0x6]; - - u8 reserved_at_20[0x8]; - u8 source_field_code[0x8]; - u8 reserved_at_30[0x2]; - u8 source_left_shifter[0x6]; - u8 reserved_at_38[0x8]; -}; - -enum { - MLX5DR_ASO_FLOW_METER_NUM_PER_OBJ = 2, -}; - -struct mlx5_ifc_ste_aso_flow_meter_action_bits { - u8 reserved_at_0[0xc]; - u8 action[0x1]; - u8 initial_color[0x2]; - u8 line_id[0x1]; -}; - -struct mlx5_ifc_ste_double_action_aso_v1_bits { - u8 action_id[0x8]; - u8 aso_context_number[0x18]; - - u8 dest_reg_id[0x2]; - u8 change_ordering_tag[0x1]; - u8 aso_check_ordering[0x1]; - u8 aso_context_type[0x4]; - u8 reserved_at_28[0x8]; - union { - u8 aso_fields[0x10]; - struct mlx5_ifc_ste_aso_flow_meter_action_bits flow_meter; - }; -}; - -#endif /* MLX5_IFC_DR_H */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr_ste_v1.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr_ste_v1.h deleted file mode 100644 index ca3b0f1453a72a..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr_ste_v1.h +++ /dev/null @@ -1,469 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. */ - -#ifndef MLX5_IFC_DR_STE_V1_H -#define MLX5_IFC_DR_STE_V1_H - -enum mlx5_ifc_ste_v1_modify_hdr_offset { - MLX5_MODIFY_HEADER_V1_QW_OFFSET = 0x20, -}; - -struct mlx5_ifc_ste_single_action_flow_tag_v1_bits { - u8 action_id[0x8]; - u8 flow_tag[0x18]; -}; - -struct mlx5_ifc_ste_single_action_modify_list_v1_bits { - u8 action_id[0x8]; - u8 num_of_modify_actions[0x8]; - u8 modify_actions_ptr[0x10]; -}; - -struct mlx5_ifc_ste_single_action_remove_header_v1_bits { - u8 action_id[0x8]; - u8 reserved_at_8[0x2]; - u8 start_anchor[0x6]; - u8 reserved_at_10[0x2]; - u8 end_anchor[0x6]; - u8 reserved_at_18[0x4]; - u8 decap[0x1]; - u8 vni_to_cqe[0x1]; - u8 qos_profile[0x2]; -}; - -struct mlx5_ifc_ste_single_action_remove_header_size_v1_bits { - u8 action_id[0x8]; - u8 reserved_at_8[0x2]; - u8 start_anchor[0x6]; - u8 outer_l4_remove[0x1]; - u8 reserved_at_11[0x1]; - u8 start_offset[0x7]; - u8 reserved_at_18[0x1]; - u8 remove_size[0x6]; -}; - -struct mlx5_ifc_ste_double_action_copy_v1_bits { - u8 action_id[0x8]; - u8 destination_dw_offset[0x8]; - u8 reserved_at_10[0x2]; - u8 destination_left_shifter[0x6]; - u8 reserved_at_17[0x2]; - u8 destination_length[0x6]; - - u8 reserved_at_20[0x8]; - u8 source_dw_offset[0x8]; - u8 reserved_at_30[0x2]; - u8 source_right_shifter[0x6]; - u8 reserved_at_38[0x8]; -}; - -struct mlx5_ifc_ste_double_action_set_v1_bits { - u8 action_id[0x8]; - u8 destination_dw_offset[0x8]; - u8 reserved_at_10[0x2]; - u8 destination_left_shifter[0x6]; - u8 reserved_at_18[0x2]; - u8 destination_length[0x6]; - - u8 inline_data[0x20]; -}; - -struct mlx5_ifc_ste_double_action_add_v1_bits { - u8 action_id[0x8]; - u8 destination_dw_offset[0x8]; - u8 reserved_at_10[0x2]; - u8 destination_left_shifter[0x6]; - u8 reserved_at_18[0x2]; - u8 destination_length[0x6]; - - u8 add_value[0x20]; -}; - -struct mlx5_ifc_ste_double_action_insert_with_inline_v1_bits { - u8 action_id[0x8]; - u8 reserved_at_8[0x2]; - u8 start_anchor[0x6]; - u8 start_offset[0x7]; - u8 reserved_at_17[0x9]; - - u8 inline_data[0x20]; -}; - -struct mlx5_ifc_ste_double_action_insert_with_ptr_v1_bits { - u8 action_id[0x8]; - u8 reserved_at_8[0x2]; - u8 start_anchor[0x6]; - u8 start_offset[0x7]; - u8 size[0x6]; - u8 attributes[0x3]; - - u8 pointer[0x20]; -}; - -struct mlx5_ifc_ste_double_action_accelerated_modify_action_list_v1_bits { - u8 action_id[0x8]; - u8 modify_actions_pattern_pointer[0x18]; - - u8 number_of_modify_actions[0x8]; - u8 modify_actions_argument_pointer[0x18]; -}; - -struct mlx5_ifc_ste_match_bwc_v1_bits { - u8 entry_format[0x8]; - u8 counter_id[0x18]; - - u8 miss_address_63_48[0x10]; - u8 match_definer_ctx_idx[0x8]; - u8 miss_address_39_32[0x8]; - - u8 miss_address_31_6[0x1a]; - u8 reserved_at_5a[0x1]; - u8 match_polarity[0x1]; - u8 reparse[0x1]; - u8 reserved_at_5d[0x3]; - - u8 next_table_base_63_48[0x10]; - u8 hash_definer_ctx_idx[0x8]; - u8 next_table_base_39_32_size[0x8]; - - u8 next_table_base_31_5_size[0x1b]; - u8 hash_type[0x2]; - u8 hash_after_actions[0x1]; - u8 reserved_at_9e[0x2]; - - u8 byte_mask[0x10]; - u8 next_entry_format[0x1]; - u8 mask_mode[0x1]; - u8 gvmi[0xe]; - - u8 action[0x40]; -}; - -struct mlx5_ifc_ste_mask_and_match_v1_bits { - u8 entry_format[0x8]; - u8 counter_id[0x18]; - - u8 miss_address_63_48[0x10]; - u8 match_definer_ctx_idx[0x8]; - u8 miss_address_39_32[0x8]; - - u8 miss_address_31_6[0x1a]; - u8 reserved_at_5a[0x1]; - u8 match_polarity[0x1]; - u8 reparse[0x1]; - u8 reserved_at_5d[0x3]; - - u8 next_table_base_63_48[0x10]; - u8 hash_definer_ctx_idx[0x8]; - u8 next_table_base_39_32_size[0x8]; - - u8 next_table_base_31_5_size[0x1b]; - u8 hash_type[0x2]; - u8 hash_after_actions[0x1]; - u8 reserved_at_9e[0x2]; - - u8 action[0x60]; -}; - -struct mlx5_ifc_ste_match_ranges_v1_bits { - u8 entry_format[0x8]; - u8 counter_id[0x18]; - - u8 miss_address_63_48[0x10]; - u8 match_definer_ctx_idx[0x8]; - u8 miss_address_39_32[0x8]; - - u8 miss_address_31_6[0x1a]; - u8 reserved_at_5a[0x1]; - u8 match_polarity[0x1]; - u8 reparse[0x1]; - u8 reserved_at_5d[0x3]; - - u8 next_table_base_63_48[0x10]; - u8 hash_definer_ctx_idx[0x8]; - u8 next_table_base_39_32_size[0x8]; - - u8 next_table_base_31_5_size[0x1b]; - u8 hash_type[0x2]; - u8 hash_after_actions[0x1]; - u8 reserved_at_9e[0x2]; - - u8 action[0x60]; - - u8 max_value_0[0x20]; - u8 min_value_0[0x20]; - u8 max_value_1[0x20]; - u8 min_value_1[0x20]; - u8 max_value_2[0x20]; - u8 min_value_2[0x20]; - u8 max_value_3[0x20]; - u8 min_value_3[0x20]; -}; - -struct mlx5_ifc_ste_eth_l2_src_v1_bits { - u8 reserved_at_0[0x1]; - u8 sx_sniffer[0x1]; - u8 functional_loopback[0x1]; - u8 ip_fragmented[0x1]; - u8 qp_type[0x2]; - u8 encapsulation_type[0x2]; - u8 port[0x2]; - u8 l3_type[0x2]; - u8 l4_type[0x2]; - u8 first_vlan_qualifier[0x2]; - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 first_vlan_id[0xc]; - - u8 smac_47_16[0x20]; - - u8 smac_15_0[0x10]; - u8 l3_ethertype[0x10]; - - u8 reserved_at_60[0x6]; - u8 tcp_syn[0x1]; - u8 reserved_at_67[0x3]; - u8 force_loopback[0x1]; - u8 l2_ok[0x1]; - u8 l3_ok[0x1]; - u8 l4_ok[0x1]; - u8 second_vlan_qualifier[0x2]; - - u8 second_priority[0x3]; - u8 second_cfi[0x1]; - u8 second_vlan_id[0xc]; -}; - -struct mlx5_ifc_ste_eth_l2_dst_v1_bits { - u8 reserved_at_0[0x1]; - u8 sx_sniffer[0x1]; - u8 functional_lb[0x1]; - u8 ip_fragmented[0x1]; - u8 qp_type[0x2]; - u8 encapsulation_type[0x2]; - u8 port[0x2]; - u8 l3_type[0x2]; - u8 l4_type[0x2]; - u8 first_vlan_qualifier[0x2]; - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 first_vlan_id[0xc]; - - u8 dmac_47_16[0x20]; - - u8 dmac_15_0[0x10]; - u8 l3_ethertype[0x10]; - - u8 reserved_at_60[0x6]; - u8 tcp_syn[0x1]; - u8 reserved_at_67[0x3]; - u8 force_lb[0x1]; - u8 l2_ok[0x1]; - u8 l3_ok[0x1]; - u8 l4_ok[0x1]; - u8 second_vlan_qualifier[0x2]; - u8 second_priority[0x3]; - u8 second_cfi[0x1]; - u8 second_vlan_id[0xc]; -}; - -struct mlx5_ifc_ste_eth_l2_src_dst_v1_bits { - u8 dmac_47_16[0x20]; - - u8 smac_47_16[0x20]; - - u8 dmac_15_0[0x10]; - u8 reserved_at_50[0x2]; - u8 functional_lb[0x1]; - u8 reserved_at_53[0x5]; - u8 port[0x2]; - u8 l3_type[0x2]; - u8 reserved_at_5c[0x2]; - u8 first_vlan_qualifier[0x2]; - - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 first_vlan_id[0xc]; - u8 smac_15_0[0x10]; -}; - -struct mlx5_ifc_ste_eth_l3_ipv4_5_tuple_v1_bits { - u8 source_address[0x20]; - - u8 destination_address[0x20]; - - u8 source_port[0x10]; - u8 destination_port[0x10]; - - u8 reserved_at_60[0x4]; - u8 l4_ok[0x1]; - u8 l3_ok[0x1]; - u8 fragmented[0x1]; - u8 tcp_ns[0x1]; - u8 tcp_cwr[0x1]; - u8 tcp_ece[0x1]; - u8 tcp_urg[0x1]; - u8 tcp_ack[0x1]; - u8 tcp_psh[0x1]; - u8 tcp_rst[0x1]; - u8 tcp_syn[0x1]; - u8 tcp_fin[0x1]; - u8 dscp[0x6]; - u8 ecn[0x2]; - u8 protocol[0x8]; -}; - -struct mlx5_ifc_ste_eth_l2_tnl_v1_bits { - u8 l2_tunneling_network_id[0x20]; - - u8 dmac_47_16[0x20]; - - u8 dmac_15_0[0x10]; - u8 l3_ethertype[0x10]; - - u8 reserved_at_60[0x3]; - u8 ip_fragmented[0x1]; - u8 reserved_at_64[0x2]; - u8 encp_type[0x2]; - u8 reserved_at_68[0x2]; - u8 l3_type[0x2]; - u8 l4_type[0x2]; - u8 first_vlan_qualifier[0x2]; - u8 first_priority[0x3]; - u8 first_cfi[0x1]; - u8 first_vlan_id[0xc]; -}; - -struct mlx5_ifc_ste_eth_l3_ipv4_misc_v1_bits { - u8 identification[0x10]; - u8 flags[0x3]; - u8 fragment_offset[0xd]; - - u8 total_length[0x10]; - u8 checksum[0x10]; - - u8 version[0x4]; - u8 ihl[0x4]; - u8 time_to_live[0x8]; - u8 reserved_at_50[0x10]; - - u8 reserved_at_60[0x1c]; - u8 voq_internal_prio[0x4]; -}; - -struct mlx5_ifc_ste_eth_l4_v1_bits { - u8 ipv6_version[0x4]; - u8 reserved_at_4[0x4]; - u8 dscp[0x6]; - u8 ecn[0x2]; - u8 ipv6_hop_limit[0x8]; - u8 protocol[0x8]; - - u8 src_port[0x10]; - u8 dst_port[0x10]; - - u8 first_fragment[0x1]; - u8 reserved_at_41[0xb]; - u8 flow_label[0x14]; - - u8 tcp_data_offset[0x4]; - u8 l4_ok[0x1]; - u8 l3_ok[0x1]; - u8 fragmented[0x1]; - u8 tcp_ns[0x1]; - u8 tcp_cwr[0x1]; - u8 tcp_ece[0x1]; - u8 tcp_urg[0x1]; - u8 tcp_ack[0x1]; - u8 tcp_psh[0x1]; - u8 tcp_rst[0x1]; - u8 tcp_syn[0x1]; - u8 tcp_fin[0x1]; - u8 ipv6_paylen[0x10]; -}; - -struct mlx5_ifc_ste_eth_l4_misc_v1_bits { - u8 window_size[0x10]; - u8 urgent_pointer[0x10]; - - u8 ack_num[0x20]; - - u8 seq_num[0x20]; - - u8 length[0x10]; - u8 checksum[0x10]; -}; - -struct mlx5_ifc_ste_mpls_v1_bits { - u8 reserved_at_0[0x15]; - u8 mpls_ok[0x1]; - u8 mpls4_s_bit[0x1]; - u8 mpls4_qualifier[0x1]; - u8 mpls3_s_bit[0x1]; - u8 mpls3_qualifier[0x1]; - u8 mpls2_s_bit[0x1]; - u8 mpls2_qualifier[0x1]; - u8 mpls1_s_bit[0x1]; - u8 mpls1_qualifier[0x1]; - u8 mpls0_s_bit[0x1]; - u8 mpls0_qualifier[0x1]; - - u8 mpls0_label[0x14]; - u8 mpls0_exp[0x3]; - u8 mpls0_s_bos[0x1]; - u8 mpls0_ttl[0x8]; - - u8 mpls1_label[0x20]; - - u8 mpls2_label[0x20]; -}; - -struct mlx5_ifc_ste_gre_v1_bits { - u8 gre_c_present[0x1]; - u8 reserved_at_1[0x1]; - u8 gre_k_present[0x1]; - u8 gre_s_present[0x1]; - u8 strict_src_route[0x1]; - u8 recur[0x3]; - u8 flags[0x5]; - u8 version[0x3]; - u8 gre_protocol[0x10]; - - u8 reserved_at_20[0x20]; - - u8 gre_key_h[0x18]; - u8 gre_key_l[0x8]; - - u8 reserved_at_60[0x20]; -}; - -struct mlx5_ifc_ste_src_gvmi_qp_v1_bits { - u8 loopback_synd[0x8]; - u8 reserved_at_8[0x7]; - u8 functional_lb[0x1]; - u8 source_gvmi[0x10]; - - u8 force_lb[0x1]; - u8 reserved_at_21[0x1]; - u8 source_is_requestor[0x1]; - u8 reserved_at_23[0x5]; - u8 source_qp[0x18]; - - u8 reserved_at_40[0x20]; - - u8 reserved_at_60[0x20]; -}; - -struct mlx5_ifc_ste_icmp_v1_bits { - u8 icmp_payload_data[0x20]; - - u8 icmp_header_data[0x20]; - - u8 icmp_type[0x8]; - u8 icmp_code[0x8]; - u8 reserved_at_50[0x10]; - - u8 reserved_at_60[0x20]; -}; - -#endif /* MLX5_IFC_DR_STE_V1_H */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h deleted file mode 100644 index 3ac7dc67509fca..00000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h +++ /dev/null @@ -1,196 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ -/* Copyright (c) 2019, Mellanox Technologies */ - -#ifndef _MLX5DR_H_ -#define _MLX5DR_H_ - -struct mlx5dr_domain; -struct mlx5dr_table; -struct mlx5dr_matcher; -struct mlx5dr_rule; -struct mlx5dr_action; - -enum mlx5dr_domain_type { - MLX5DR_DOMAIN_TYPE_NIC_RX, - MLX5DR_DOMAIN_TYPE_NIC_TX, - MLX5DR_DOMAIN_TYPE_FDB, -}; - -enum mlx5dr_domain_sync_flags { - MLX5DR_DOMAIN_SYNC_FLAGS_SW = 1 << 0, - MLX5DR_DOMAIN_SYNC_FLAGS_HW = 1 << 1, -}; - -enum mlx5dr_action_reformat_type { - DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2, - DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2, - DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2, - DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3, - DR_ACTION_REFORMAT_TYP_INSERT_HDR, - DR_ACTION_REFORMAT_TYP_REMOVE_HDR, -}; - -struct mlx5dr_match_parameters { - size_t match_sz; - u64 *match_buf; /* Device spec format */ -}; - -struct mlx5dr_action_dest { - struct mlx5dr_action *dest; - struct mlx5dr_action *reformat; -}; - -struct mlx5dr_domain * -mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type); - -int mlx5dr_domain_destroy(struct mlx5dr_domain *domain); - -int mlx5dr_domain_sync(struct mlx5dr_domain *domain, u32 flags); - -void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn, - struct mlx5dr_domain *peer_dmn, - u16 peer_vhca_id); - -struct mlx5dr_table * -mlx5dr_table_create(struct mlx5dr_domain *domain, u32 level, u32 flags, - u16 uid); - -struct mlx5dr_table * -mlx5dr_table_get_from_fs_ft(struct mlx5_flow_table *ft); - -int mlx5dr_table_destroy(struct mlx5dr_table *table); - -u32 mlx5dr_table_get_id(struct mlx5dr_table *table); - -struct mlx5dr_matcher * -mlx5dr_matcher_create(struct mlx5dr_table *table, - u32 priority, - u8 match_criteria_enable, - struct mlx5dr_match_parameters *mask); - -int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher); - -struct mlx5dr_rule * -mlx5dr_rule_create(struct mlx5dr_matcher *matcher, - struct mlx5dr_match_parameters *value, - size_t num_actions, - struct mlx5dr_action *actions[], - u32 flow_source); - -int mlx5dr_rule_destroy(struct mlx5dr_rule *rule); - -int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl, - struct mlx5dr_action *action); - -struct mlx5dr_action * -mlx5dr_action_create_dest_table_num(struct mlx5dr_domain *dmn, u32 table_num); - -struct mlx5dr_action * -mlx5dr_action_create_dest_table(struct mlx5dr_table *table); - -struct mlx5dr_action * -mlx5dr_action_create_dest_flow_fw_table(struct mlx5dr_domain *domain, - struct mlx5_flow_table *ft); - -struct mlx5dr_action * -mlx5dr_action_create_dest_vport(struct mlx5dr_domain *domain, - u16 vport, u8 vhca_id_valid, - u16 vhca_id); - -struct mlx5dr_action * -mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn, - struct mlx5dr_action_dest *dests, - u32 num_of_dests, - bool ignore_flow_level, - u32 flow_source); - -struct mlx5dr_action *mlx5dr_action_create_drop(void); - -struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value); - -struct mlx5dr_action * -mlx5dr_action_create_flow_sampler(struct mlx5dr_domain *dmn, u32 sampler_id); - -struct mlx5dr_action * -mlx5dr_action_create_flow_counter(u32 counter_id); - -struct mlx5dr_action * -mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn, - enum mlx5dr_action_reformat_type reformat_type, - u8 reformat_param_0, - u8 reformat_param_1, - size_t data_sz, - void *data); - -struct mlx5dr_action * -mlx5dr_action_create_modify_header(struct mlx5dr_domain *domain, - u32 flags, - size_t actions_sz, - __be64 actions[]); - -struct mlx5dr_action *mlx5dr_action_create_pop_vlan(void); - -struct mlx5dr_action * -mlx5dr_action_create_push_vlan(struct mlx5dr_domain *domain, __be32 vlan_hdr); - -struct mlx5dr_action * -mlx5dr_action_create_aso(struct mlx5dr_domain *dmn, - u32 obj_id, - u8 return_reg_id, - u8 aso_type, - u8 init_color, - u8 meter_id); - -struct mlx5dr_action * -mlx5dr_action_create_dest_match_range(struct mlx5dr_domain *dmn, - u32 field, - struct mlx5_flow_table *hit_ft, - struct mlx5_flow_table *miss_ft, - u32 min, - u32 max); - -int mlx5dr_action_destroy(struct mlx5dr_action *action); - -u32 mlx5dr_action_get_pkt_reformat_id(struct mlx5dr_action *action); - -static inline bool -mlx5dr_is_supported(struct mlx5_core_dev *dev) -{ - return MLX5_CAP_GEN(dev, roce) && - (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, sw_owner) || - (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, sw_owner_v2) && - (MLX5_CAP_GEN(dev, steering_format_version) <= - MLX5_STEERING_FORMAT_CONNECTX_7))); -} - -/* buddy functions & structure */ - -struct mlx5dr_icm_mr; - -struct mlx5dr_icm_buddy_mem { - unsigned long **bitmap; - unsigned int *num_free; - u32 max_order; - struct list_head list_node; - struct mlx5dr_icm_mr *icm_mr; - struct mlx5dr_icm_pool *pool; - - /* Amount of memory in used chunks - HW may be accessing this memory */ - u64 used_memory; - - /* Memory optimisation */ - struct mlx5dr_ste *ste_arr; - struct list_head *miss_list; - u8 *hw_ste_arr; -}; - -int mlx5dr_buddy_init(struct mlx5dr_icm_buddy_mem *buddy, - unsigned int max_order); -void mlx5dr_buddy_cleanup(struct mlx5dr_icm_buddy_mem *buddy); -int mlx5dr_buddy_alloc_mem(struct mlx5dr_icm_buddy_mem *buddy, - unsigned int order, - unsigned int *segment); -void mlx5dr_buddy_free_mem(struct mlx5dr_icm_buddy_mem *buddy, - unsigned int seg, unsigned int order); - -#endif /* _MLX5DR_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_action.c new file mode 100644 index 00000000000000..2ebb61ef3ea9f6 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_action.c @@ -0,0 +1,2245 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include "dr_types.h" +#include "dr_ste.h" + +enum dr_action_domain { + DR_ACTION_DOMAIN_NIC_INGRESS, + DR_ACTION_DOMAIN_NIC_EGRESS, + DR_ACTION_DOMAIN_FDB_INGRESS, + DR_ACTION_DOMAIN_FDB_EGRESS, + DR_ACTION_DOMAIN_MAX, +}; + +enum dr_action_valid_state { + DR_ACTION_STATE_ERR, + DR_ACTION_STATE_NO_ACTION, + DR_ACTION_STATE_ENCAP, + DR_ACTION_STATE_DECAP, + DR_ACTION_STATE_MODIFY_HDR, + DR_ACTION_STATE_POP_VLAN, + DR_ACTION_STATE_PUSH_VLAN, + DR_ACTION_STATE_NON_TERM, + DR_ACTION_STATE_TERM, + DR_ACTION_STATE_ASO, + DR_ACTION_STATE_MAX, +}; + +static const char * const action_type_to_str[] = { + [DR_ACTION_TYP_TNL_L2_TO_L2] = "DR_ACTION_TYP_TNL_L2_TO_L2", + [DR_ACTION_TYP_L2_TO_TNL_L2] = "DR_ACTION_TYP_L2_TO_TNL_L2", + [DR_ACTION_TYP_TNL_L3_TO_L2] = "DR_ACTION_TYP_TNL_L3_TO_L2", + [DR_ACTION_TYP_L2_TO_TNL_L3] = "DR_ACTION_TYP_L2_TO_TNL_L3", + [DR_ACTION_TYP_DROP] = "DR_ACTION_TYP_DROP", + [DR_ACTION_TYP_QP] = "DR_ACTION_TYP_QP", + [DR_ACTION_TYP_FT] = "DR_ACTION_TYP_FT", + [DR_ACTION_TYP_CTR] = "DR_ACTION_TYP_CTR", + [DR_ACTION_TYP_TAG] = "DR_ACTION_TYP_TAG", + [DR_ACTION_TYP_MODIFY_HDR] = "DR_ACTION_TYP_MODIFY_HDR", + [DR_ACTION_TYP_VPORT] = "DR_ACTION_TYP_VPORT", + [DR_ACTION_TYP_POP_VLAN] = "DR_ACTION_TYP_POP_VLAN", + [DR_ACTION_TYP_PUSH_VLAN] = "DR_ACTION_TYP_PUSH_VLAN", + [DR_ACTION_TYP_SAMPLER] = "DR_ACTION_TYP_SAMPLER", + [DR_ACTION_TYP_INSERT_HDR] = "DR_ACTION_TYP_INSERT_HDR", + [DR_ACTION_TYP_REMOVE_HDR] = "DR_ACTION_TYP_REMOVE_HDR", + [DR_ACTION_TYP_ASO_FLOW_METER] = "DR_ACTION_TYP_ASO_FLOW_METER", + [DR_ACTION_TYP_RANGE] = "DR_ACTION_TYP_RANGE", + [DR_ACTION_TYP_MAX] = "DR_ACTION_UNKNOWN", +}; + +static const char *dr_action_id_to_str(enum mlx5dr_action_type action_id) +{ + if (action_id > DR_ACTION_TYP_MAX) + action_id = DR_ACTION_TYP_MAX; + return action_type_to_str[action_id]; +} + +static bool mlx5dr_action_supp_fwd_fdb_multi_ft(struct mlx5_core_dev *dev) +{ + return (MLX5_CAP_GEN(dev, steering_format_version) < MLX5_STEERING_FORMAT_CONNECTX_6DX || + MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_any_table_limit_regc) || + MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_any_table)); +} + +static const enum dr_action_valid_state +next_action_state[DR_ACTION_DOMAIN_MAX][DR_ACTION_STATE_MAX][DR_ACTION_TYP_MAX] = { + [DR_ACTION_DOMAIN_NIC_INGRESS] = { + [DR_ACTION_STATE_NO_ACTION] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_DECAP] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_ENCAP] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_MODIFY_HDR] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_POP_VLAN] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_PUSH_VLAN] = { + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_NON_TERM] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_ASO] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_TERM] = { + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, + }, + }, + [DR_ACTION_DOMAIN_NIC_EGRESS] = { + [DR_ACTION_STATE_NO_ACTION] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_DECAP] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_ENCAP] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_MODIFY_HDR] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_POP_VLAN] = { + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_PUSH_VLAN] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_NON_TERM] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_ASO] = { + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ASO, + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + }, + [DR_ACTION_STATE_TERM] = { + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, + }, + }, + [DR_ACTION_DOMAIN_FDB_INGRESS] = { + [DR_ACTION_STATE_NO_ACTION] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_DECAP] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_ENCAP] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_MODIFY_HDR] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_POP_VLAN] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_PUSH_VLAN] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_NON_TERM] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_ASO] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_TERM] = { + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, + }, + }, + [DR_ACTION_DOMAIN_FDB_EGRESS] = { + [DR_ACTION_STATE_NO_ACTION] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_DECAP] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_ENCAP] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_MODIFY_HDR] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_POP_VLAN] = { + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_PUSH_VLAN] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_NON_TERM] = { + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_SAMPLER] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_INSERT_HDR] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_REMOVE_HDR] = DR_ACTION_STATE_DECAP, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_POP_VLAN, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_ASO_FLOW_METER] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_ASO] = { + [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_ENCAP, + [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR, + [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_PUSH_VLAN, + [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_RANGE] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM, + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_ASO, + }, + [DR_ACTION_STATE_TERM] = { + [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM, + }, + }, +}; + +static int +dr_action_reformat_to_action_type(enum mlx5dr_action_reformat_type reformat_type, + enum mlx5dr_action_type *action_type) +{ + switch (reformat_type) { + case DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2: + *action_type = DR_ACTION_TYP_TNL_L2_TO_L2; + break; + case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2: + *action_type = DR_ACTION_TYP_L2_TO_TNL_L2; + break; + case DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2: + *action_type = DR_ACTION_TYP_TNL_L3_TO_L2; + break; + case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3: + *action_type = DR_ACTION_TYP_L2_TO_TNL_L3; + break; + case DR_ACTION_REFORMAT_TYP_INSERT_HDR: + *action_type = DR_ACTION_TYP_INSERT_HDR; + break; + case DR_ACTION_REFORMAT_TYP_REMOVE_HDR: + *action_type = DR_ACTION_TYP_REMOVE_HDR; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* Apply the actions on the rule STE array starting from the last_ste. + * Actions might require more than one STE, new_num_stes will return + * the new size of the STEs array, rule with actions. + */ +static void dr_actions_apply(struct mlx5dr_domain *dmn, + enum mlx5dr_domain_nic_type nic_type, + u8 *action_type_set, + u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, + u32 *new_num_stes) +{ + struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; + u32 added_stes = 0; + + if (nic_type == DR_DOMAIN_NIC_TYPE_RX) + mlx5dr_ste_set_actions_rx(ste_ctx, dmn, action_type_set, + last_ste, attr, &added_stes); + else + mlx5dr_ste_set_actions_tx(ste_ctx, dmn, action_type_set, + last_ste, attr, &added_stes); + + *new_num_stes += added_stes; +} + +static enum dr_action_domain +dr_action_get_action_domain(enum mlx5dr_domain_type domain, + enum mlx5dr_domain_nic_type nic_type) +{ + switch (domain) { + case MLX5DR_DOMAIN_TYPE_NIC_RX: + return DR_ACTION_DOMAIN_NIC_INGRESS; + case MLX5DR_DOMAIN_TYPE_NIC_TX: + return DR_ACTION_DOMAIN_NIC_EGRESS; + case MLX5DR_DOMAIN_TYPE_FDB: + if (nic_type == DR_DOMAIN_NIC_TYPE_RX) + return DR_ACTION_DOMAIN_FDB_INGRESS; + return DR_ACTION_DOMAIN_FDB_EGRESS; + default: + WARN_ON(true); + return DR_ACTION_DOMAIN_MAX; + } +} + +static +int dr_action_validate_and_get_next_state(enum dr_action_domain action_domain, + u32 action_type, + u32 *state) +{ + u32 cur_state = *state; + + /* Check action state machine is valid */ + *state = next_action_state[action_domain][cur_state][action_type]; + + if (*state == DR_ACTION_STATE_ERR) + return -EOPNOTSUPP; + + return 0; +} + +static int dr_action_handle_cs_recalc(struct mlx5dr_domain *dmn, + struct mlx5dr_action *dest_action, + u64 *final_icm_addr) +{ + int ret; + + switch (dest_action->action_type) { + case DR_ACTION_TYP_FT: + /* Allow destination flow table only if table is a terminating + * table, since there is an *assumption* that in such case FW + * will recalculate the CS. + */ + if (dest_action->dest_tbl->is_fw_tbl) { + *final_icm_addr = dest_action->dest_tbl->fw_tbl.rx_icm_addr; + } else { + mlx5dr_dbg(dmn, + "Destination FT should be terminating when modify TTL is used\n"); + return -EINVAL; + } + break; + + case DR_ACTION_TYP_VPORT: + /* If destination is vport we will get the FW flow table + * that recalculates the CS and forwards to the vport. + */ + ret = mlx5dr_domain_get_recalc_cs_ft_addr(dest_action->vport->dmn, + dest_action->vport->caps->num, + final_icm_addr); + if (ret) { + mlx5dr_err(dmn, "Failed to get FW cs recalc flow table\n"); + return ret; + } + break; + + default: + break; + } + + return 0; +} + +static void dr_action_modify_ttl_adjust(struct mlx5dr_domain *dmn, + struct mlx5dr_ste_actions_attr *attr, + bool rx_rule, + bool *recalc_cs_required) +{ + *recalc_cs_required = false; + + /* if device supports csum recalculation - no adjustment needed */ + if (mlx5dr_ste_supp_ttl_cs_recalc(&dmn->info.caps)) + return; + + /* no adjustment needed on TX rules */ + if (!rx_rule) + return; + + if (!MLX5_CAP_ESW_FLOWTABLE(dmn->mdev, fdb_ipv4_ttl_modify)) { + /* Ignore the modify TTL action. + * It is always kept as last HW action. + */ + attr->modify_actions--; + return; + } + + if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB) + /* Due to a HW bug on some devices, modifying TTL on RX flows + * will cause an incorrect checksum calculation. In such cases + * we will use a FW table to recalculate the checksum. + */ + *recalc_cs_required = true; +} + +static void dr_action_print_sequence(struct mlx5dr_domain *dmn, + struct mlx5dr_action *actions[], + int last_idx) +{ + int i; + + for (i = 0; i <= last_idx; i++) + mlx5dr_err(dmn, "< %s (%d) > ", + dr_action_id_to_str(actions[i]->action_type), + actions[i]->action_type); +} + +static int dr_action_get_dest_fw_tbl_addr(struct mlx5dr_matcher *matcher, + struct mlx5dr_action_dest_tbl *dest_tbl, + bool is_rx_rule, + u64 *final_icm_addr) +{ + struct mlx5dr_cmd_query_flow_table_details output; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + int ret; + + if (!dest_tbl->fw_tbl.rx_icm_addr) { + ret = mlx5dr_cmd_query_flow_table(dmn->mdev, + dest_tbl->fw_tbl.type, + dest_tbl->fw_tbl.id, + &output); + if (ret) { + mlx5dr_err(dmn, + "Failed mlx5_cmd_query_flow_table ret: %d\n", + ret); + return ret; + } + + dest_tbl->fw_tbl.tx_icm_addr = output.sw_owner_icm_root_1; + dest_tbl->fw_tbl.rx_icm_addr = output.sw_owner_icm_root_0; + } + + *final_icm_addr = is_rx_rule ? dest_tbl->fw_tbl.rx_icm_addr : + dest_tbl->fw_tbl.tx_icm_addr; + return 0; +} + +static int dr_action_get_dest_sw_tbl_addr(struct mlx5dr_matcher *matcher, + struct mlx5dr_action_dest_tbl *dest_tbl, + bool is_rx_rule, + u64 *final_icm_addr) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_icm_chunk *chunk; + + if (dest_tbl->tbl->dmn != dmn) { + mlx5dr_err(dmn, + "Destination table belongs to a different domain\n"); + return -EINVAL; + } + + if (dest_tbl->tbl->level <= matcher->tbl->level) { + mlx5_core_dbg_once(dmn->mdev, + "Connecting table to a lower/same level destination table\n"); + mlx5dr_dbg(dmn, + "Connecting table at level %d to a destination table at level %d\n", + matcher->tbl->level, + dest_tbl->tbl->level); + } + + chunk = is_rx_rule ? dest_tbl->tbl->rx.s_anchor->chunk : + dest_tbl->tbl->tx.s_anchor->chunk; + + *final_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(chunk); + return 0; +} + +static int dr_action_get_dest_tbl_addr(struct mlx5dr_matcher *matcher, + struct mlx5dr_action_dest_tbl *dest_tbl, + bool is_rx_rule, + u64 *final_icm_addr) +{ + if (dest_tbl->is_fw_tbl) + return dr_action_get_dest_fw_tbl_addr(matcher, + dest_tbl, + is_rx_rule, + final_icm_addr); + + return dr_action_get_dest_sw_tbl_addr(matcher, + dest_tbl, + is_rx_rule, + final_icm_addr); +} + +#define WITH_VLAN_NUM_HW_ACTIONS 6 + +int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_action *actions[], + u32 num_actions, + u8 *ste_arr, + u32 *new_hw_ste_arr_sz) +{ + struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; + bool rx_rule = nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + u8 action_type_set[DR_ACTION_TYP_MAX] = {}; + struct mlx5dr_ste_actions_attr attr = {}; + struct mlx5dr_action *dest_action = NULL; + u32 state = DR_ACTION_STATE_NO_ACTION; + enum dr_action_domain action_domain; + bool recalc_cs_required = false; + u8 *last_ste; + int i, ret; + + attr.gvmi = dmn->info.caps.gvmi; + attr.hit_gvmi = dmn->info.caps.gvmi; + attr.final_icm_addr = nic_dmn->default_icm_addr; + action_domain = dr_action_get_action_domain(dmn->type, nic_dmn->type); + + for (i = 0; i < num_actions; i++) { + struct mlx5dr_action *action; + int max_actions_type = 1; + u32 action_type; + + action = actions[i]; + action_type = action->action_type; + + switch (action_type) { + case DR_ACTION_TYP_DROP: + attr.final_icm_addr = nic_dmn->drop_icm_addr; + attr.hit_gvmi = nic_dmn->drop_icm_addr >> 48; + break; + case DR_ACTION_TYP_FT: + dest_action = action; + ret = dr_action_get_dest_tbl_addr(matcher, action->dest_tbl, + rx_rule, &attr.final_icm_addr); + if (ret) + return ret; + break; + case DR_ACTION_TYP_RANGE: + ret = dr_action_get_dest_tbl_addr(matcher, + action->range->hit_tbl_action->dest_tbl, + rx_rule, &attr.final_icm_addr); + if (ret) + return ret; + + ret = dr_action_get_dest_tbl_addr(matcher, + action->range->miss_tbl_action->dest_tbl, + rx_rule, &attr.range.miss_icm_addr); + if (ret) + return ret; + + attr.range.definer_id = action->range->definer_id; + attr.range.min = action->range->min; + attr.range.max = action->range->max; + break; + case DR_ACTION_TYP_QP: + mlx5dr_info(dmn, "Domain doesn't support QP\n"); + return -EOPNOTSUPP; + case DR_ACTION_TYP_CTR: + attr.ctr_id = action->ctr->ctr_id + + action->ctr->offset; + break; + case DR_ACTION_TYP_TAG: + attr.flow_tag = action->flow_tag->flow_tag; + break; + case DR_ACTION_TYP_TNL_L2_TO_L2: + break; + case DR_ACTION_TYP_TNL_L3_TO_L2: + if (action->rewrite->ptrn && action->rewrite->arg) { + attr.decap_index = mlx5dr_arg_get_obj_id(action->rewrite->arg); + attr.decap_actions = action->rewrite->ptrn->num_of_actions; + attr.decap_pat_idx = action->rewrite->ptrn->index; + } else { + attr.decap_index = action->rewrite->index; + attr.decap_actions = action->rewrite->num_of_actions; + attr.decap_with_vlan = + attr.decap_actions == WITH_VLAN_NUM_HW_ACTIONS; + attr.decap_pat_idx = MLX5DR_INVALID_PATTERN_INDEX; + } + break; + case DR_ACTION_TYP_MODIFY_HDR: + if (action->rewrite->single_action_opt) { + attr.modify_actions = action->rewrite->num_of_actions; + attr.single_modify_action = action->rewrite->data; + } else { + if (action->rewrite->ptrn && action->rewrite->arg) { + attr.modify_index = + mlx5dr_arg_get_obj_id(action->rewrite->arg); + attr.modify_actions = action->rewrite->ptrn->num_of_actions; + attr.modify_pat_idx = action->rewrite->ptrn->index; + } else { + attr.modify_index = action->rewrite->index; + attr.modify_actions = action->rewrite->num_of_actions; + attr.modify_pat_idx = MLX5DR_INVALID_PATTERN_INDEX; + } + } + if (action->rewrite->modify_ttl) + dr_action_modify_ttl_adjust(dmn, &attr, rx_rule, + &recalc_cs_required); + break; + case DR_ACTION_TYP_L2_TO_TNL_L2: + case DR_ACTION_TYP_L2_TO_TNL_L3: + if (rx_rule && + !(dmn->ste_ctx->actions_caps & DR_STE_CTX_ACTION_CAP_RX_ENCAP)) { + mlx5dr_info(dmn, "Device doesn't support Encap on RX\n"); + return -EOPNOTSUPP; + } + attr.reformat.size = action->reformat->size; + attr.reformat.id = action->reformat->id; + break; + case DR_ACTION_TYP_SAMPLER: + attr.final_icm_addr = rx_rule ? action->sampler->rx_icm_addr : + action->sampler->tx_icm_addr; + break; + case DR_ACTION_TYP_VPORT: + if (unlikely(rx_rule && action->vport->caps->num == MLX5_VPORT_UPLINK)) { + /* can't go to uplink on RX rule - dropping instead */ + attr.final_icm_addr = nic_dmn->drop_icm_addr; + attr.hit_gvmi = nic_dmn->drop_icm_addr >> 48; + } else { + attr.hit_gvmi = action->vport->caps->vhca_gvmi; + dest_action = action; + attr.final_icm_addr = rx_rule ? + action->vport->caps->icm_address_rx : + action->vport->caps->icm_address_tx; + } + break; + case DR_ACTION_TYP_POP_VLAN: + if (!rx_rule && !(dmn->ste_ctx->actions_caps & + DR_STE_CTX_ACTION_CAP_TX_POP)) { + mlx5dr_dbg(dmn, "Device doesn't support POP VLAN action on TX\n"); + return -EOPNOTSUPP; + } + + max_actions_type = MLX5DR_MAX_VLANS; + attr.vlans.count++; + break; + case DR_ACTION_TYP_PUSH_VLAN: + if (rx_rule && !(dmn->ste_ctx->actions_caps & + DR_STE_CTX_ACTION_CAP_RX_PUSH)) { + mlx5dr_dbg(dmn, "Device doesn't support PUSH VLAN action on RX\n"); + return -EOPNOTSUPP; + } + + max_actions_type = MLX5DR_MAX_VLANS; + if (attr.vlans.count == MLX5DR_MAX_VLANS) { + mlx5dr_dbg(dmn, "Max VLAN push/pop count exceeded\n"); + return -EINVAL; + } + + attr.vlans.headers[attr.vlans.count++] = action->push_vlan->vlan_hdr; + break; + case DR_ACTION_TYP_INSERT_HDR: + case DR_ACTION_TYP_REMOVE_HDR: + attr.reformat.size = action->reformat->size; + attr.reformat.id = action->reformat->id; + attr.reformat.param_0 = action->reformat->param_0; + attr.reformat.param_1 = action->reformat->param_1; + break; + case DR_ACTION_TYP_ASO_FLOW_METER: + attr.aso_flow_meter.obj_id = action->aso->obj_id; + attr.aso_flow_meter.offset = action->aso->offset; + attr.aso_flow_meter.dest_reg_id = action->aso->dest_reg_id; + attr.aso_flow_meter.init_color = action->aso->init_color; + break; + default: + mlx5dr_err(dmn, "Unsupported action type %d\n", action_type); + return -EINVAL; + } + + /* Check action duplication */ + if (++action_type_set[action_type] > max_actions_type) { + mlx5dr_err(dmn, "Action type %d supports only max %d time(s)\n", + action_type, max_actions_type); + return -EINVAL; + } + + /* Check action state machine is valid */ + if (dr_action_validate_and_get_next_state(action_domain, + action_type, + &state)) { + mlx5dr_err(dmn, "Invalid action (gvmi: %d, is_rx: %d) sequence provided:", + attr.gvmi, rx_rule); + dr_action_print_sequence(dmn, actions, i); + return -EOPNOTSUPP; + } + } + + *new_hw_ste_arr_sz = nic_matcher->num_of_builders; + last_ste = ste_arr + DR_STE_SIZE * (nic_matcher->num_of_builders - 1); + + if (recalc_cs_required && dest_action) { + ret = dr_action_handle_cs_recalc(dmn, dest_action, &attr.final_icm_addr); + if (ret) { + mlx5dr_err(dmn, + "Failed to handle checksum recalculation err %d\n", + ret); + return ret; + } + } + + dr_actions_apply(dmn, + nic_dmn->type, + action_type_set, + last_ste, + &attr, + new_hw_ste_arr_sz); + + return 0; +} + +static unsigned int action_size[DR_ACTION_TYP_MAX] = { + [DR_ACTION_TYP_TNL_L2_TO_L2] = sizeof(struct mlx5dr_action_reformat), + [DR_ACTION_TYP_L2_TO_TNL_L2] = sizeof(struct mlx5dr_action_reformat), + [DR_ACTION_TYP_TNL_L3_TO_L2] = sizeof(struct mlx5dr_action_rewrite), + [DR_ACTION_TYP_L2_TO_TNL_L3] = sizeof(struct mlx5dr_action_reformat), + [DR_ACTION_TYP_FT] = sizeof(struct mlx5dr_action_dest_tbl), + [DR_ACTION_TYP_CTR] = sizeof(struct mlx5dr_action_ctr), + [DR_ACTION_TYP_TAG] = sizeof(struct mlx5dr_action_flow_tag), + [DR_ACTION_TYP_MODIFY_HDR] = sizeof(struct mlx5dr_action_rewrite), + [DR_ACTION_TYP_VPORT] = sizeof(struct mlx5dr_action_vport), + [DR_ACTION_TYP_PUSH_VLAN] = sizeof(struct mlx5dr_action_push_vlan), + [DR_ACTION_TYP_INSERT_HDR] = sizeof(struct mlx5dr_action_reformat), + [DR_ACTION_TYP_REMOVE_HDR] = sizeof(struct mlx5dr_action_reformat), + [DR_ACTION_TYP_SAMPLER] = sizeof(struct mlx5dr_action_sampler), + [DR_ACTION_TYP_ASO_FLOW_METER] = sizeof(struct mlx5dr_action_aso_flow_meter), + [DR_ACTION_TYP_RANGE] = sizeof(struct mlx5dr_action_range), +}; + +static struct mlx5dr_action * +dr_action_create_generic(enum mlx5dr_action_type action_type) +{ + struct mlx5dr_action *action; + int extra_size; + + if (action_type < DR_ACTION_TYP_MAX) + extra_size = action_size[action_type]; + else + return NULL; + + action = kzalloc(sizeof(*action) + extra_size, GFP_KERNEL); + if (!action) + return NULL; + + action->action_type = action_type; + refcount_set(&action->refcount, 1); + action->data = action + 1; + + return action; +} + +struct mlx5dr_action *mlx5dr_action_create_drop(void) +{ + return dr_action_create_generic(DR_ACTION_TYP_DROP); +} + +struct mlx5dr_action * +mlx5dr_action_create_dest_table_num(struct mlx5dr_domain *dmn, u32 table_num) +{ + struct mlx5dr_action *action; + + action = dr_action_create_generic(DR_ACTION_TYP_FT); + if (!action) + return NULL; + + action->dest_tbl->is_fw_tbl = true; + action->dest_tbl->fw_tbl.dmn = dmn; + action->dest_tbl->fw_tbl.id = table_num; + action->dest_tbl->fw_tbl.type = FS_FT_FDB; + refcount_inc(&dmn->refcount); + + return action; +} + +struct mlx5dr_action * +mlx5dr_action_create_dest_table(struct mlx5dr_table *tbl) +{ + struct mlx5dr_action *action; + + refcount_inc(&tbl->refcount); + + action = dr_action_create_generic(DR_ACTION_TYP_FT); + if (!action) + goto dec_ref; + + action->dest_tbl->tbl = tbl; + + return action; + +dec_ref: + refcount_dec(&tbl->refcount); + return NULL; +} + +static void dr_action_range_definer_fill(u16 *format_id, + u8 *dw_selectors, + u8 *byte_selectors, + u8 *match_mask) +{ + int i; + + *format_id = MLX5_IFC_DEFINER_FORMAT_ID_SELECT; + + dw_selectors[0] = MLX5_IFC_DEFINER_FORMAT_OFFSET_OUTER_ETH_PKT_LEN / 4; + + for (i = 1; i < MLX5_IFC_DEFINER_DW_SELECTORS_NUM; i++) + dw_selectors[i] = MLX5_IFC_DEFINER_FORMAT_OFFSET_UNUSED; + + for (i = 0; i < MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM; i++) + byte_selectors[i] = MLX5_IFC_DEFINER_FORMAT_OFFSET_UNUSED; + + MLX5_SET(match_definer_match_mask, match_mask, + match_dw_0, 0xffffUL << 16); +} + +static int dr_action_create_range_definer(struct mlx5dr_action *action) +{ + u8 match_mask[MLX5_FLD_SZ_BYTES(match_definer, match_mask)] = {}; + u8 byte_selectors[MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM] = {}; + u8 dw_selectors[MLX5_IFC_DEFINER_DW_SELECTORS_NUM] = {}; + struct mlx5dr_domain *dmn = action->range->dmn; + u32 definer_id; + u16 format_id; + int ret; + + dr_action_range_definer_fill(&format_id, + dw_selectors, + byte_selectors, + match_mask); + + ret = mlx5dr_definer_get(dmn, format_id, + dw_selectors, byte_selectors, + match_mask, &definer_id); + if (ret) + return ret; + + action->range->definer_id = definer_id; + return 0; +} + +static void dr_action_destroy_range_definer(struct mlx5dr_action *action) +{ + mlx5dr_definer_put(action->range->dmn, action->range->definer_id); +} + +struct mlx5dr_action * +mlx5dr_action_create_dest_match_range(struct mlx5dr_domain *dmn, + u32 field, + struct mlx5_flow_table *hit_ft, + struct mlx5_flow_table *miss_ft, + u32 min, + u32 max) +{ + struct mlx5dr_action *action; + int ret; + + if (!mlx5dr_supp_match_ranges(dmn->mdev)) { + mlx5dr_dbg(dmn, "SELECT definer support is needed for match range\n"); + return NULL; + } + + if (field != MLX5_FLOW_DEST_RANGE_FIELD_PKT_LEN || + min > 0xffff || max > 0xffff) { + mlx5dr_err(dmn, "Invalid match range parameters\n"); + return NULL; + } + + action = dr_action_create_generic(DR_ACTION_TYP_RANGE); + if (!action) + return NULL; + + action->range->hit_tbl_action = + mlx5dr_is_fw_table(hit_ft) ? + mlx5dr_action_create_dest_flow_fw_table(dmn, hit_ft) : + mlx5dr_action_create_dest_table(hit_ft->fs_dr_table.dr_table); + + if (!action->range->hit_tbl_action) + goto free_action; + + action->range->miss_tbl_action = + mlx5dr_is_fw_table(miss_ft) ? + mlx5dr_action_create_dest_flow_fw_table(dmn, miss_ft) : + mlx5dr_action_create_dest_table(miss_ft->fs_dr_table.dr_table); + + if (!action->range->miss_tbl_action) + goto free_hit_tbl_action; + + action->range->min = min; + action->range->max = max; + action->range->dmn = dmn; + + ret = dr_action_create_range_definer(action); + if (ret) + goto free_miss_tbl_action; + + /* No need to increase refcount on domain for this action, + * the hit/miss table actions will do it internally. + */ + + return action; + +free_miss_tbl_action: + mlx5dr_action_destroy(action->range->miss_tbl_action); +free_hit_tbl_action: + mlx5dr_action_destroy(action->range->hit_tbl_action); +free_action: + kfree(action); + + return NULL; +} + +struct mlx5dr_action * +mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn, + struct mlx5dr_action_dest *dests, + u32 num_of_dests, + bool ignore_flow_level, + u32 flow_source) +{ + struct mlx5dr_cmd_flow_destination_hw_info *hw_dests; + struct mlx5dr_action **ref_actions; + struct mlx5dr_action *action; + bool reformat_req = false; + bool is_ft_wire = false; + u16 num_dst_ft = 0; + u32 num_of_ref = 0; + u32 ref_act_cnt; + u16 last_dest; + int ret; + int i; + + if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) { + mlx5dr_err(dmn, "Multiple destination support is for FDB only\n"); + return NULL; + } + + hw_dests = kcalloc(num_of_dests, sizeof(*hw_dests), GFP_KERNEL); + if (!hw_dests) + return NULL; + + if (unlikely(check_mul_overflow(num_of_dests, 2u, &ref_act_cnt))) + goto free_hw_dests; + + ref_actions = kcalloc(ref_act_cnt, sizeof(*ref_actions), GFP_KERNEL); + if (!ref_actions) + goto free_hw_dests; + + for (i = 0; i < num_of_dests; i++) { + struct mlx5dr_action *reformat_action = dests[i].reformat; + struct mlx5dr_action *dest_action = dests[i].dest; + + ref_actions[num_of_ref++] = dest_action; + + switch (dest_action->action_type) { + case DR_ACTION_TYP_VPORT: + hw_dests[i].vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID; + hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT; + hw_dests[i].vport.num = dest_action->vport->caps->num; + hw_dests[i].vport.vhca_id = dest_action->vport->caps->vhca_gvmi; + if (reformat_action) { + reformat_req = true; + hw_dests[i].vport.reformat_id = + reformat_action->reformat->id; + ref_actions[num_of_ref++] = reformat_action; + hw_dests[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID; + } + break; + + case DR_ACTION_TYP_FT: + if (num_dst_ft && + !mlx5dr_action_supp_fwd_fdb_multi_ft(dmn->mdev)) { + mlx5dr_dbg(dmn, "multiple FT destinations not supported\n"); + goto free_ref_actions; + } + num_dst_ft++; + hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; + if (dest_action->dest_tbl->is_fw_tbl) { + hw_dests[i].ft_id = dest_action->dest_tbl->fw_tbl.id; + } else { + hw_dests[i].ft_id = dest_action->dest_tbl->tbl->table_id; + if (dest_action->dest_tbl->is_wire_ft) { + is_ft_wire = true; + last_dest = i; + } + } + break; + + default: + mlx5dr_dbg(dmn, "Invalid multiple destinations action\n"); + goto free_ref_actions; + } + } + + /* In multidest, the FW does the iterator in the RX except of the last + * one that done in the TX. + * So, if one of the ft target is wire, put it at the end of the dest list. + */ + if (is_ft_wire && num_dst_ft > 1) + swap(hw_dests[last_dest], hw_dests[num_of_dests - 1]); + + action = dr_action_create_generic(DR_ACTION_TYP_FT); + if (!action) + goto free_ref_actions; + + ret = mlx5dr_fw_create_md_tbl(dmn, + hw_dests, + num_of_dests, + reformat_req, + &action->dest_tbl->fw_tbl.id, + &action->dest_tbl->fw_tbl.group_id, + ignore_flow_level, + flow_source); + if (ret) + goto free_action; + + refcount_inc(&dmn->refcount); + + for (i = 0; i < num_of_ref; i++) + refcount_inc(&ref_actions[i]->refcount); + + action->dest_tbl->is_fw_tbl = true; + action->dest_tbl->fw_tbl.dmn = dmn; + action->dest_tbl->fw_tbl.type = FS_FT_FDB; + action->dest_tbl->fw_tbl.ref_actions = ref_actions; + action->dest_tbl->fw_tbl.num_of_ref_actions = num_of_ref; + + kfree(hw_dests); + + return action; + +free_action: + kfree(action); +free_ref_actions: + kfree(ref_actions); +free_hw_dests: + kfree(hw_dests); + return NULL; +} + +struct mlx5dr_action * +mlx5dr_action_create_dest_flow_fw_table(struct mlx5dr_domain *dmn, + struct mlx5_flow_table *ft) +{ + struct mlx5dr_action *action; + + action = dr_action_create_generic(DR_ACTION_TYP_FT); + if (!action) + return NULL; + + action->dest_tbl->is_fw_tbl = 1; + action->dest_tbl->fw_tbl.type = ft->type; + action->dest_tbl->fw_tbl.id = ft->id; + action->dest_tbl->fw_tbl.dmn = dmn; + + refcount_inc(&dmn->refcount); + + return action; +} + +struct mlx5dr_action * +mlx5dr_action_create_flow_counter(u32 counter_id) +{ + struct mlx5dr_action *action; + + action = dr_action_create_generic(DR_ACTION_TYP_CTR); + if (!action) + return NULL; + + action->ctr->ctr_id = counter_id; + + return action; +} + +struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value) +{ + struct mlx5dr_action *action; + + action = dr_action_create_generic(DR_ACTION_TYP_TAG); + if (!action) + return NULL; + + action->flow_tag->flow_tag = tag_value & 0xffffff; + + return action; +} + +struct mlx5dr_action * +mlx5dr_action_create_flow_sampler(struct mlx5dr_domain *dmn, u32 sampler_id) +{ + struct mlx5dr_action *action; + u64 icm_rx, icm_tx; + int ret; + + ret = mlx5dr_cmd_query_flow_sampler(dmn->mdev, sampler_id, + &icm_rx, &icm_tx); + if (ret) + return NULL; + + action = dr_action_create_generic(DR_ACTION_TYP_SAMPLER); + if (!action) + return NULL; + + action->sampler->dmn = dmn; + action->sampler->sampler_id = sampler_id; + action->sampler->rx_icm_addr = icm_rx; + action->sampler->tx_icm_addr = icm_tx; + + refcount_inc(&dmn->refcount); + return action; +} + +static int +dr_action_verify_reformat_params(enum mlx5dr_action_type reformat_type, + struct mlx5dr_domain *dmn, + u8 reformat_param_0, + u8 reformat_param_1, + size_t data_sz, + void *data) +{ + if (reformat_type == DR_ACTION_TYP_INSERT_HDR) { + if ((!data && data_sz) || (data && !data_sz) || + MLX5_CAP_GEN_2(dmn->mdev, max_reformat_insert_size) < data_sz || + MLX5_CAP_GEN_2(dmn->mdev, max_reformat_insert_offset) < reformat_param_1) { + mlx5dr_dbg(dmn, "Invalid reformat parameters for INSERT_HDR\n"); + goto out_err; + } + } else if (reformat_type == DR_ACTION_TYP_REMOVE_HDR) { + if (data || + MLX5_CAP_GEN_2(dmn->mdev, max_reformat_remove_size) < data_sz || + MLX5_CAP_GEN_2(dmn->mdev, max_reformat_remove_offset) < reformat_param_1) { + mlx5dr_dbg(dmn, "Invalid reformat parameters for REMOVE_HDR\n"); + goto out_err; + } + } else if (reformat_param_0 || reformat_param_1 || + reformat_type > DR_ACTION_TYP_REMOVE_HDR) { + mlx5dr_dbg(dmn, "Invalid reformat parameters\n"); + goto out_err; + } + + if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB) + return 0; + + if (dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) { + if (reformat_type != DR_ACTION_TYP_TNL_L2_TO_L2 && + reformat_type != DR_ACTION_TYP_TNL_L3_TO_L2) { + mlx5dr_dbg(dmn, "Action reformat type not support on RX domain\n"); + goto out_err; + } + } else if (dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) { + if (reformat_type != DR_ACTION_TYP_L2_TO_TNL_L2 && + reformat_type != DR_ACTION_TYP_L2_TO_TNL_L3) { + mlx5dr_dbg(dmn, "Action reformat type not support on TX domain\n"); + goto out_err; + } + } + + return 0; + +out_err: + return -EINVAL; +} + +static int +dr_action_create_reformat_action(struct mlx5dr_domain *dmn, + u8 reformat_param_0, u8 reformat_param_1, + size_t data_sz, void *data, + struct mlx5dr_action *action) +{ + u32 reformat_id; + int ret; + + switch (action->action_type) { + case DR_ACTION_TYP_L2_TO_TNL_L2: + case DR_ACTION_TYP_L2_TO_TNL_L3: + { + enum mlx5_reformat_ctx_type rt; + + if (action->action_type == DR_ACTION_TYP_L2_TO_TNL_L2) + rt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL; + else + rt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL; + + ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, rt, 0, 0, + data_sz, data, + &reformat_id); + if (ret) + return ret; + + action->reformat->id = reformat_id; + action->reformat->size = data_sz; + return 0; + } + case DR_ACTION_TYP_TNL_L2_TO_L2: + { + return 0; + } + case DR_ACTION_TYP_TNL_L3_TO_L2: + { + u8 *hw_actions; + + hw_actions = kzalloc(DR_ACTION_CACHE_LINE_SIZE, GFP_KERNEL); + if (!hw_actions) + return -ENOMEM; + + ret = mlx5dr_ste_set_action_decap_l3_list(dmn->ste_ctx, + data, data_sz, + hw_actions, + DR_ACTION_CACHE_LINE_SIZE, + &action->rewrite->num_of_actions); + if (ret) { + mlx5dr_dbg(dmn, "Failed creating decap l3 action list\n"); + kfree(hw_actions); + return ret; + } + + action->rewrite->data = hw_actions; + action->rewrite->dmn = dmn; + + ret = mlx5dr_ste_alloc_modify_hdr(action); + if (ret) { + mlx5dr_dbg(dmn, "Failed preparing reformat data\n"); + kfree(hw_actions); + return ret; + } + return 0; + } + case DR_ACTION_TYP_INSERT_HDR: + ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, + MLX5_REFORMAT_TYPE_INSERT_HDR, + reformat_param_0, + reformat_param_1, + data_sz, data, + &reformat_id); + if (ret) + return ret; + + action->reformat->id = reformat_id; + action->reformat->size = data_sz; + action->reformat->param_0 = reformat_param_0; + action->reformat->param_1 = reformat_param_1; + return 0; + case DR_ACTION_TYP_REMOVE_HDR: + action->reformat->id = 0; + action->reformat->size = data_sz; + action->reformat->param_0 = reformat_param_0; + action->reformat->param_1 = reformat_param_1; + return 0; + default: + mlx5dr_info(dmn, "Reformat type is not supported %d\n", action->action_type); + return -EINVAL; + } +} + +#define CVLAN_ETHERTYPE 0x8100 +#define SVLAN_ETHERTYPE 0x88a8 + +struct mlx5dr_action *mlx5dr_action_create_pop_vlan(void) +{ + return dr_action_create_generic(DR_ACTION_TYP_POP_VLAN); +} + +struct mlx5dr_action *mlx5dr_action_create_push_vlan(struct mlx5dr_domain *dmn, + __be32 vlan_hdr) +{ + u32 vlan_hdr_h = ntohl(vlan_hdr); + u16 ethertype = vlan_hdr_h >> 16; + struct mlx5dr_action *action; + + if (ethertype != SVLAN_ETHERTYPE && ethertype != CVLAN_ETHERTYPE) { + mlx5dr_dbg(dmn, "Invalid vlan ethertype\n"); + return NULL; + } + + action = dr_action_create_generic(DR_ACTION_TYP_PUSH_VLAN); + if (!action) + return NULL; + + action->push_vlan->vlan_hdr = vlan_hdr_h; + return action; +} + +struct mlx5dr_action * +mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn, + enum mlx5dr_action_reformat_type reformat_type, + u8 reformat_param_0, + u8 reformat_param_1, + size_t data_sz, + void *data) +{ + enum mlx5dr_action_type action_type; + struct mlx5dr_action *action; + int ret; + + refcount_inc(&dmn->refcount); + + /* General checks */ + ret = dr_action_reformat_to_action_type(reformat_type, &action_type); + if (ret) { + mlx5dr_dbg(dmn, "Invalid reformat_type provided\n"); + goto dec_ref; + } + + ret = dr_action_verify_reformat_params(action_type, dmn, + reformat_param_0, reformat_param_1, + data_sz, data); + if (ret) + goto dec_ref; + + action = dr_action_create_generic(action_type); + if (!action) + goto dec_ref; + + action->reformat->dmn = dmn; + + ret = dr_action_create_reformat_action(dmn, + reformat_param_0, + reformat_param_1, + data_sz, + data, + action); + if (ret) { + mlx5dr_dbg(dmn, "Failed creating reformat action %d\n", ret); + goto free_action; + } + + return action; + +free_action: + kfree(action); +dec_ref: + refcount_dec(&dmn->refcount); + return NULL; +} + +static int +dr_action_modify_sw_to_hw_add(struct mlx5dr_domain *dmn, + __be64 *sw_action, + __be64 *hw_action, + const struct mlx5dr_ste_action_modify_field **ret_hw_info) +{ + const struct mlx5dr_ste_action_modify_field *hw_action_info; + u8 max_length; + u16 sw_field; + u32 data; + + /* Get SW modify action data */ + sw_field = MLX5_GET(set_action_in, sw_action, field); + data = MLX5_GET(set_action_in, sw_action, data); + + /* Convert SW data to HW modify action format */ + hw_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, sw_field); + if (!hw_action_info) { + mlx5dr_dbg(dmn, "Modify add action invalid field given\n"); + return -EINVAL; + } + + max_length = hw_action_info->end - hw_action_info->start + 1; + + mlx5dr_ste_set_action_add(dmn->ste_ctx, + hw_action, + hw_action_info->hw_field, + hw_action_info->start, + max_length, + data); + + *ret_hw_info = hw_action_info; + + return 0; +} + +static int +dr_action_modify_sw_to_hw_set(struct mlx5dr_domain *dmn, + __be64 *sw_action, + __be64 *hw_action, + const struct mlx5dr_ste_action_modify_field **ret_hw_info) +{ + const struct mlx5dr_ste_action_modify_field *hw_action_info; + u8 offset, length, max_length; + u16 sw_field; + u32 data; + + /* Get SW modify action data */ + length = MLX5_GET(set_action_in, sw_action, length); + offset = MLX5_GET(set_action_in, sw_action, offset); + sw_field = MLX5_GET(set_action_in, sw_action, field); + data = MLX5_GET(set_action_in, sw_action, data); + + /* Convert SW data to HW modify action format */ + hw_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, sw_field); + if (!hw_action_info) { + mlx5dr_dbg(dmn, "Modify set action invalid field given\n"); + return -EINVAL; + } + + /* PRM defines that length zero specific length of 32bits */ + length = length ? length : 32; + + max_length = hw_action_info->end - hw_action_info->start + 1; + + if (length + offset > max_length) { + mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n"); + return -EINVAL; + } + + mlx5dr_ste_set_action_set(dmn->ste_ctx, + hw_action, + hw_action_info->hw_field, + hw_action_info->start + offset, + length, + data); + + *ret_hw_info = hw_action_info; + + return 0; +} + +static int +dr_action_modify_sw_to_hw_copy(struct mlx5dr_domain *dmn, + __be64 *sw_action, + __be64 *hw_action, + const struct mlx5dr_ste_action_modify_field **ret_dst_hw_info, + const struct mlx5dr_ste_action_modify_field **ret_src_hw_info) +{ + u8 src_offset, dst_offset, src_max_length, dst_max_length, length; + const struct mlx5dr_ste_action_modify_field *hw_dst_action_info; + const struct mlx5dr_ste_action_modify_field *hw_src_action_info; + u16 src_field, dst_field; + + /* Get SW modify action data */ + src_field = MLX5_GET(copy_action_in, sw_action, src_field); + dst_field = MLX5_GET(copy_action_in, sw_action, dst_field); + src_offset = MLX5_GET(copy_action_in, sw_action, src_offset); + dst_offset = MLX5_GET(copy_action_in, sw_action, dst_offset); + length = MLX5_GET(copy_action_in, sw_action, length); + + /* Convert SW data to HW modify action format */ + hw_src_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, src_field); + hw_dst_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, dst_field); + if (!hw_src_action_info || !hw_dst_action_info) { + mlx5dr_dbg(dmn, "Modify copy action invalid field given\n"); + return -EINVAL; + } + + /* PRM defines that length zero specific length of 32bits */ + length = length ? length : 32; + + src_max_length = hw_src_action_info->end - + hw_src_action_info->start + 1; + dst_max_length = hw_dst_action_info->end - + hw_dst_action_info->start + 1; + + if (length + src_offset > src_max_length || + length + dst_offset > dst_max_length) { + mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n"); + return -EINVAL; + } + + mlx5dr_ste_set_action_copy(dmn->ste_ctx, + hw_action, + hw_dst_action_info->hw_field, + hw_dst_action_info->start + dst_offset, + length, + hw_src_action_info->hw_field, + hw_src_action_info->start + src_offset); + + *ret_dst_hw_info = hw_dst_action_info; + *ret_src_hw_info = hw_src_action_info; + + return 0; +} + +static int +dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn, + __be64 *sw_action, + __be64 *hw_action, + const struct mlx5dr_ste_action_modify_field **ret_dst_hw_info, + const struct mlx5dr_ste_action_modify_field **ret_src_hw_info) +{ + u8 action; + int ret; + + *hw_action = 0; + *ret_src_hw_info = NULL; + + /* Get SW modify action type */ + action = MLX5_GET(set_action_in, sw_action, action_type); + + switch (action) { + case MLX5_ACTION_TYPE_SET: + ret = dr_action_modify_sw_to_hw_set(dmn, sw_action, + hw_action, + ret_dst_hw_info); + break; + + case MLX5_ACTION_TYPE_ADD: + ret = dr_action_modify_sw_to_hw_add(dmn, sw_action, + hw_action, + ret_dst_hw_info); + break; + + case MLX5_ACTION_TYPE_COPY: + ret = dr_action_modify_sw_to_hw_copy(dmn, sw_action, + hw_action, + ret_dst_hw_info, + ret_src_hw_info); + break; + + default: + mlx5dr_info(dmn, "Unsupported action_type for modify action\n"); + ret = -EOPNOTSUPP; + } + + return ret; +} + +static int +dr_action_modify_check_set_field_limitation(struct mlx5dr_action *action, + const __be64 *sw_action) +{ + u16 sw_field = MLX5_GET(set_action_in, sw_action, field); + struct mlx5dr_domain *dmn = action->rewrite->dmn; + + if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_A) { + action->rewrite->allow_rx = 0; + if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) { + mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n", + sw_field); + return -EINVAL; + } + } else if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_B) { + action->rewrite->allow_tx = 0; + if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) { + mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n", + sw_field); + return -EINVAL; + } + } + + if (!action->rewrite->allow_rx && !action->rewrite->allow_tx) { + mlx5dr_dbg(dmn, "Modify SET actions not supported on both RX and TX\n"); + return -EINVAL; + } + + return 0; +} + +static int +dr_action_modify_check_add_field_limitation(struct mlx5dr_action *action, + const __be64 *sw_action) +{ + u16 sw_field = MLX5_GET(set_action_in, sw_action, field); + struct mlx5dr_domain *dmn = action->rewrite->dmn; + + if (sw_field != MLX5_ACTION_IN_FIELD_OUT_IP_TTL && + sw_field != MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT && + sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM && + sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM) { + mlx5dr_dbg(dmn, "Unsupported field %d for add action\n", + sw_field); + return -EINVAL; + } + + return 0; +} + +static int +dr_action_modify_check_copy_field_limitation(struct mlx5dr_action *action, + const __be64 *sw_action) +{ + struct mlx5dr_domain *dmn = action->rewrite->dmn; + u16 sw_fields[2]; + int i; + + sw_fields[0] = MLX5_GET(copy_action_in, sw_action, src_field); + sw_fields[1] = MLX5_GET(copy_action_in, sw_action, dst_field); + + for (i = 0; i < 2; i++) { + if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_A) { + action->rewrite->allow_rx = 0; + if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) { + mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n", + sw_fields[i]); + return -EINVAL; + } + } else if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_B) { + action->rewrite->allow_tx = 0; + if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) { + mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n", + sw_fields[i]); + return -EINVAL; + } + } + } + + if (!action->rewrite->allow_rx && !action->rewrite->allow_tx) { + mlx5dr_dbg(dmn, "Modify copy actions not supported on both RX and TX\n"); + return -EINVAL; + } + + return 0; +} + +static int +dr_action_modify_check_field_limitation(struct mlx5dr_action *action, + const __be64 *sw_action) +{ + struct mlx5dr_domain *dmn = action->rewrite->dmn; + u8 action_type; + int ret; + + action_type = MLX5_GET(set_action_in, sw_action, action_type); + + switch (action_type) { + case MLX5_ACTION_TYPE_SET: + ret = dr_action_modify_check_set_field_limitation(action, + sw_action); + break; + + case MLX5_ACTION_TYPE_ADD: + ret = dr_action_modify_check_add_field_limitation(action, + sw_action); + break; + + case MLX5_ACTION_TYPE_COPY: + ret = dr_action_modify_check_copy_field_limitation(action, + sw_action); + break; + + default: + mlx5dr_info(dmn, "Unsupported action %d modify action\n", + action_type); + ret = -EOPNOTSUPP; + } + + return ret; +} + +static bool +dr_action_modify_check_is_ttl_modify(const void *sw_action) +{ + u16 sw_field = MLX5_GET(set_action_in, sw_action, field); + + return sw_field == MLX5_ACTION_IN_FIELD_OUT_IP_TTL; +} + +static int dr_actions_convert_modify_header(struct mlx5dr_action *action, + u32 max_hw_actions, + u32 num_sw_actions, + __be64 sw_actions[], + __be64 hw_actions[], + u32 *num_hw_actions, + bool *modify_ttl) +{ + const struct mlx5dr_ste_action_modify_field *hw_dst_action_info; + const struct mlx5dr_ste_action_modify_field *hw_src_action_info; + struct mlx5dr_domain *dmn = action->rewrite->dmn; + __be64 *modify_ttl_sw_action = NULL; + int ret, i, hw_idx = 0; + __be64 *sw_action; + __be64 hw_action; + u16 hw_field = 0; + u32 l3_type = 0; + u32 l4_type = 0; + + *modify_ttl = false; + + action->rewrite->allow_rx = 1; + action->rewrite->allow_tx = 1; + + for (i = 0; i < num_sw_actions || modify_ttl_sw_action; i++) { + /* modify TTL is handled separately, as a last action */ + if (i == num_sw_actions) { + sw_action = modify_ttl_sw_action; + modify_ttl_sw_action = NULL; + } else { + sw_action = &sw_actions[i]; + } + + ret = dr_action_modify_check_field_limitation(action, + sw_action); + if (ret) + return ret; + + if (!(*modify_ttl) && + dr_action_modify_check_is_ttl_modify(sw_action)) { + modify_ttl_sw_action = sw_action; + *modify_ttl = true; + continue; + } + + /* Convert SW action to HW action */ + ret = dr_action_modify_sw_to_hw(dmn, + sw_action, + &hw_action, + &hw_dst_action_info, + &hw_src_action_info); + if (ret) + return ret; + + /* Due to a HW limitation we cannot modify 2 different L3 types */ + if (l3_type && hw_dst_action_info->l3_type && + hw_dst_action_info->l3_type != l3_type) { + mlx5dr_dbg(dmn, "Action list can't support two different L3 types\n"); + return -EINVAL; + } + if (hw_dst_action_info->l3_type) + l3_type = hw_dst_action_info->l3_type; + + /* Due to a HW limitation we cannot modify two different L4 types */ + if (l4_type && hw_dst_action_info->l4_type && + hw_dst_action_info->l4_type != l4_type) { + mlx5dr_dbg(dmn, "Action list can't support two different L4 types\n"); + return -EINVAL; + } + if (hw_dst_action_info->l4_type) + l4_type = hw_dst_action_info->l4_type; + + /* HW reads and executes two actions at once this means we + * need to create a gap if two actions access the same field + */ + if ((hw_idx % 2) && (hw_field == hw_dst_action_info->hw_field || + (hw_src_action_info && + hw_field == hw_src_action_info->hw_field))) { + /* Check if after gap insertion the total number of HW + * modify actions doesn't exceeds the limit + */ + hw_idx++; + if (hw_idx >= max_hw_actions) { + mlx5dr_dbg(dmn, "Modify header action number exceeds HW limit\n"); + return -EINVAL; + } + } + hw_field = hw_dst_action_info->hw_field; + + hw_actions[hw_idx] = hw_action; + hw_idx++; + } + + /* if the resulting HW actions list is empty, add NOP action */ + if (!hw_idx) + hw_idx++; + + *num_hw_actions = hw_idx; + + return 0; +} + +static int dr_action_create_modify_action(struct mlx5dr_domain *dmn, + size_t actions_sz, + __be64 actions[], + struct mlx5dr_action *action) +{ + u32 max_hw_actions; + u32 num_hw_actions; + u32 num_sw_actions; + __be64 *hw_actions; + bool modify_ttl; + int ret; + + num_sw_actions = actions_sz / DR_MODIFY_ACTION_SIZE; + max_hw_actions = mlx5dr_icm_pool_chunk_size_to_entries(DR_CHUNK_SIZE_16); + + if (num_sw_actions > max_hw_actions) { + mlx5dr_dbg(dmn, "Max number of actions %d exceeds limit %d\n", + num_sw_actions, max_hw_actions); + return -EINVAL; + } + + hw_actions = kcalloc(1, max_hw_actions * DR_MODIFY_ACTION_SIZE, GFP_KERNEL); + if (!hw_actions) + return -ENOMEM; + + ret = dr_actions_convert_modify_header(action, + max_hw_actions, + num_sw_actions, + actions, + hw_actions, + &num_hw_actions, + &modify_ttl); + if (ret) + goto free_hw_actions; + + action->rewrite->modify_ttl = modify_ttl; + action->rewrite->data = (u8 *)hw_actions; + action->rewrite->num_of_actions = num_hw_actions; + + if (num_hw_actions == 1 && + dmn->info.caps.sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) { + action->rewrite->single_action_opt = true; + } else { + action->rewrite->single_action_opt = false; + ret = mlx5dr_ste_alloc_modify_hdr(action); + if (ret) + goto free_hw_actions; + } + + return 0; + +free_hw_actions: + kfree(hw_actions); + return ret; +} + +struct mlx5dr_action * +mlx5dr_action_create_modify_header(struct mlx5dr_domain *dmn, + u32 flags, + size_t actions_sz, + __be64 actions[]) +{ + struct mlx5dr_action *action; + int ret = 0; + + refcount_inc(&dmn->refcount); + + if (actions_sz % DR_MODIFY_ACTION_SIZE) { + mlx5dr_dbg(dmn, "Invalid modify actions size provided\n"); + goto dec_ref; + } + + action = dr_action_create_generic(DR_ACTION_TYP_MODIFY_HDR); + if (!action) + goto dec_ref; + + action->rewrite->dmn = dmn; + + ret = dr_action_create_modify_action(dmn, + actions_sz, + actions, + action); + if (ret) { + mlx5dr_dbg(dmn, "Failed creating modify header action %d\n", ret); + goto free_action; + } + + return action; + +free_action: + kfree(action); +dec_ref: + refcount_dec(&dmn->refcount); + return NULL; +} + +struct mlx5dr_action * +mlx5dr_action_create_dest_vport(struct mlx5dr_domain *dmn, + u16 vport, u8 vhca_id_valid, + u16 vhca_id) +{ + struct mlx5dr_cmd_vport_cap *vport_cap; + struct mlx5dr_domain *vport_dmn; + struct mlx5dr_action *action; + u8 peer_vport; + + peer_vport = vhca_id_valid && mlx5_core_is_pf(dmn->mdev) && + (vhca_id != dmn->info.caps.gvmi); + vport_dmn = peer_vport ? xa_load(&dmn->peer_dmn_xa, vhca_id) : dmn; + if (!vport_dmn) { + mlx5dr_dbg(dmn, "No peer vport domain for given vhca_id\n"); + return NULL; + } + + if (vport_dmn->type != MLX5DR_DOMAIN_TYPE_FDB) { + mlx5dr_dbg(dmn, "Domain doesn't support vport actions\n"); + return NULL; + } + + vport_cap = mlx5dr_domain_get_vport_cap(vport_dmn, vport); + if (!vport_cap) { + mlx5dr_err(dmn, + "Failed to get vport 0x%x caps - vport is disabled or invalid\n", + vport); + return NULL; + } + + action = dr_action_create_generic(DR_ACTION_TYP_VPORT); + if (!action) + return NULL; + + action->vport->dmn = vport_dmn; + action->vport->caps = vport_cap; + + return action; +} + +struct mlx5dr_action * +mlx5dr_action_create_aso(struct mlx5dr_domain *dmn, u32 obj_id, + u8 dest_reg_id, u8 aso_type, + u8 init_color, u8 meter_id) +{ + struct mlx5dr_action *action; + + if (aso_type != MLX5_EXE_ASO_FLOW_METER) + return NULL; + + if (init_color > MLX5_FLOW_METER_COLOR_UNDEFINED) + return NULL; + + action = dr_action_create_generic(DR_ACTION_TYP_ASO_FLOW_METER); + if (!action) + return NULL; + + action->aso->obj_id = obj_id; + action->aso->offset = meter_id; + action->aso->dest_reg_id = dest_reg_id; + action->aso->init_color = init_color; + action->aso->dmn = dmn; + + refcount_inc(&dmn->refcount); + + return action; +} + +u32 mlx5dr_action_get_pkt_reformat_id(struct mlx5dr_action *action) +{ + return action->reformat->id; +} + +int mlx5dr_action_destroy(struct mlx5dr_action *action) +{ + if (WARN_ON_ONCE(refcount_read(&action->refcount) > 1)) + return -EBUSY; + + switch (action->action_type) { + case DR_ACTION_TYP_FT: + if (action->dest_tbl->is_fw_tbl) + refcount_dec(&action->dest_tbl->fw_tbl.dmn->refcount); + else + refcount_dec(&action->dest_tbl->tbl->refcount); + + if (action->dest_tbl->is_fw_tbl && + action->dest_tbl->fw_tbl.num_of_ref_actions) { + struct mlx5dr_action **ref_actions; + int i; + + ref_actions = action->dest_tbl->fw_tbl.ref_actions; + for (i = 0; i < action->dest_tbl->fw_tbl.num_of_ref_actions; i++) + refcount_dec(&ref_actions[i]->refcount); + + kfree(ref_actions); + + mlx5dr_fw_destroy_md_tbl(action->dest_tbl->fw_tbl.dmn, + action->dest_tbl->fw_tbl.id, + action->dest_tbl->fw_tbl.group_id); + } + break; + case DR_ACTION_TYP_TNL_L2_TO_L2: + case DR_ACTION_TYP_REMOVE_HDR: + refcount_dec(&action->reformat->dmn->refcount); + break; + case DR_ACTION_TYP_TNL_L3_TO_L2: + mlx5dr_ste_free_modify_hdr(action); + kfree(action->rewrite->data); + refcount_dec(&action->rewrite->dmn->refcount); + break; + case DR_ACTION_TYP_L2_TO_TNL_L2: + case DR_ACTION_TYP_L2_TO_TNL_L3: + case DR_ACTION_TYP_INSERT_HDR: + mlx5dr_cmd_destroy_reformat_ctx((action->reformat->dmn)->mdev, + action->reformat->id); + refcount_dec(&action->reformat->dmn->refcount); + break; + case DR_ACTION_TYP_MODIFY_HDR: + if (!action->rewrite->single_action_opt) + mlx5dr_ste_free_modify_hdr(action); + kfree(action->rewrite->data); + refcount_dec(&action->rewrite->dmn->refcount); + break; + case DR_ACTION_TYP_SAMPLER: + refcount_dec(&action->sampler->dmn->refcount); + break; + case DR_ACTION_TYP_ASO_FLOW_METER: + refcount_dec(&action->aso->dmn->refcount); + break; + case DR_ACTION_TYP_RANGE: + dr_action_destroy_range_definer(action); + mlx5dr_action_destroy(action->range->miss_tbl_action); + mlx5dr_action_destroy(action->range->hit_tbl_action); + break; + default: + break; + } + + kfree(action); + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_arg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_arg.c new file mode 100644 index 00000000000000..01ed6442095d78 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_arg.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +#include "dr_types.h" + +#define DR_ICM_MODIFY_HDR_GRANULARITY_4K 12 + +/* modify-header arg pool */ +enum dr_arg_chunk_size { + DR_ARG_CHUNK_SIZE_1, + DR_ARG_CHUNK_SIZE_MIN = DR_ARG_CHUNK_SIZE_1, /* keep updated when changing */ + DR_ARG_CHUNK_SIZE_2, + DR_ARG_CHUNK_SIZE_3, + DR_ARG_CHUNK_SIZE_4, + DR_ARG_CHUNK_SIZE_MAX, +}; + +/* argument pool area */ +struct dr_arg_pool { + enum dr_arg_chunk_size log_chunk_size; + struct mlx5dr_domain *dmn; + struct list_head free_list; + struct mutex mutex; /* protect arg pool */ +}; + +struct mlx5dr_arg_mgr { + struct mlx5dr_domain *dmn; + struct dr_arg_pool *pools[DR_ARG_CHUNK_SIZE_MAX]; +}; + +static int dr_arg_pool_alloc_objs(struct dr_arg_pool *pool) +{ + struct mlx5dr_arg_obj *arg_obj, *tmp_arg; + struct list_head cur_list; + u16 object_range; + int num_of_objects; + u32 obj_id = 0; + int i, ret; + + INIT_LIST_HEAD(&cur_list); + + object_range = + pool->dmn->info.caps.log_header_modify_argument_granularity; + + object_range = + max_t(u32, pool->dmn->info.caps.log_header_modify_argument_granularity, + DR_ICM_MODIFY_HDR_GRANULARITY_4K); + object_range = + min_t(u32, pool->dmn->info.caps.log_header_modify_argument_max_alloc, + object_range); + + if (pool->log_chunk_size > object_range) { + mlx5dr_err(pool->dmn, "Required chunk size (%d) is not supported\n", + pool->log_chunk_size); + return -ENOMEM; + } + + num_of_objects = (1 << (object_range - pool->log_chunk_size)); + /* Only one devx object per range */ + ret = mlx5dr_cmd_create_modify_header_arg(pool->dmn->mdev, + object_range, + pool->dmn->pdn, + &obj_id); + if (ret) { + mlx5dr_err(pool->dmn, "failed allocating object with range: %d:\n", + object_range); + return -EAGAIN; + } + + for (i = 0; i < num_of_objects; i++) { + arg_obj = kzalloc(sizeof(*arg_obj), GFP_KERNEL); + if (!arg_obj) { + ret = -ENOMEM; + goto clean_arg_obj; + } + + arg_obj->log_chunk_size = pool->log_chunk_size; + + list_add_tail(&arg_obj->list_node, &cur_list); + + arg_obj->obj_id = obj_id; + arg_obj->obj_offset = i * (1 << pool->log_chunk_size); + } + list_splice_tail_init(&cur_list, &pool->free_list); + + return 0; + +clean_arg_obj: + mlx5dr_cmd_destroy_modify_header_arg(pool->dmn->mdev, obj_id); + list_for_each_entry_safe(arg_obj, tmp_arg, &cur_list, list_node) { + list_del(&arg_obj->list_node); + kfree(arg_obj); + } + return ret; +} + +static struct mlx5dr_arg_obj *dr_arg_pool_get_arg_obj(struct dr_arg_pool *pool) +{ + struct mlx5dr_arg_obj *arg_obj = NULL; + int ret; + + mutex_lock(&pool->mutex); + if (list_empty(&pool->free_list)) { + ret = dr_arg_pool_alloc_objs(pool); + if (ret) + goto out; + } + + arg_obj = list_first_entry_or_null(&pool->free_list, + struct mlx5dr_arg_obj, + list_node); + WARN(!arg_obj, "couldn't get dr arg obj from pool"); + + if (arg_obj) + list_del_init(&arg_obj->list_node); + +out: + mutex_unlock(&pool->mutex); + return arg_obj; +} + +static void dr_arg_pool_put_arg_obj(struct dr_arg_pool *pool, + struct mlx5dr_arg_obj *arg_obj) +{ + mutex_lock(&pool->mutex); + list_add(&arg_obj->list_node, &pool->free_list); + mutex_unlock(&pool->mutex); +} + +static struct dr_arg_pool *dr_arg_pool_create(struct mlx5dr_domain *dmn, + enum dr_arg_chunk_size chunk_size) +{ + struct dr_arg_pool *pool; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return NULL; + + pool->dmn = dmn; + + INIT_LIST_HEAD(&pool->free_list); + mutex_init(&pool->mutex); + + pool->log_chunk_size = chunk_size; + if (dr_arg_pool_alloc_objs(pool)) + goto free_pool; + + return pool; + +free_pool: + kfree(pool); + + return NULL; +} + +static void dr_arg_pool_destroy(struct dr_arg_pool *pool) +{ + struct mlx5dr_arg_obj *arg_obj, *tmp_arg; + + list_for_each_entry_safe(arg_obj, tmp_arg, &pool->free_list, list_node) { + list_del(&arg_obj->list_node); + if (!arg_obj->obj_offset) /* the first in range */ + mlx5dr_cmd_destroy_modify_header_arg(pool->dmn->mdev, arg_obj->obj_id); + kfree(arg_obj); + } + + mutex_destroy(&pool->mutex); + kfree(pool); +} + +static enum dr_arg_chunk_size dr_arg_get_chunk_size(u16 num_of_actions) +{ + if (num_of_actions <= 8) + return DR_ARG_CHUNK_SIZE_1; + if (num_of_actions <= 16) + return DR_ARG_CHUNK_SIZE_2; + if (num_of_actions <= 32) + return DR_ARG_CHUNK_SIZE_3; + if (num_of_actions <= 64) + return DR_ARG_CHUNK_SIZE_4; + + return DR_ARG_CHUNK_SIZE_MAX; +} + +u32 mlx5dr_arg_get_obj_id(struct mlx5dr_arg_obj *arg_obj) +{ + return (arg_obj->obj_id + arg_obj->obj_offset); +} + +struct mlx5dr_arg_obj *mlx5dr_arg_get_obj(struct mlx5dr_arg_mgr *mgr, + u16 num_of_actions, + u8 *data) +{ + u32 size = dr_arg_get_chunk_size(num_of_actions); + struct mlx5dr_arg_obj *arg_obj; + int ret; + + if (size >= DR_ARG_CHUNK_SIZE_MAX) + return NULL; + + arg_obj = dr_arg_pool_get_arg_obj(mgr->pools[size]); + if (!arg_obj) { + mlx5dr_err(mgr->dmn, "Failed allocating args object for modify header\n"); + return NULL; + } + + /* write it into the hw */ + ret = mlx5dr_send_postsend_args(mgr->dmn, + mlx5dr_arg_get_obj_id(arg_obj), + num_of_actions, data); + if (ret) { + mlx5dr_err(mgr->dmn, "Failed writing args object\n"); + goto put_obj; + } + + return arg_obj; + +put_obj: + mlx5dr_arg_put_obj(mgr, arg_obj); + return NULL; +} + +void mlx5dr_arg_put_obj(struct mlx5dr_arg_mgr *mgr, + struct mlx5dr_arg_obj *arg_obj) +{ + dr_arg_pool_put_arg_obj(mgr->pools[arg_obj->log_chunk_size], arg_obj); +} + +struct mlx5dr_arg_mgr* +mlx5dr_arg_mgr_create(struct mlx5dr_domain *dmn) +{ + struct mlx5dr_arg_mgr *pool_mgr; + int i; + + if (!mlx5dr_domain_is_support_ptrn_arg(dmn)) + return NULL; + + pool_mgr = kzalloc(sizeof(*pool_mgr), GFP_KERNEL); + if (!pool_mgr) + return NULL; + + pool_mgr->dmn = dmn; + + for (i = 0; i < DR_ARG_CHUNK_SIZE_MAX; i++) { + pool_mgr->pools[i] = dr_arg_pool_create(dmn, i); + if (!pool_mgr->pools[i]) + goto clean_pools; + } + + return pool_mgr; + +clean_pools: + for (i--; i >= 0; i--) + dr_arg_pool_destroy(pool_mgr->pools[i]); + + kfree(pool_mgr); + return NULL; +} + +void mlx5dr_arg_mgr_destroy(struct mlx5dr_arg_mgr *mgr) +{ + struct dr_arg_pool **pools; + int i; + + if (!mgr) + return; + + pools = mgr->pools; + for (i = 0; i < DR_ARG_CHUNK_SIZE_MAX; i++) + dr_arg_pool_destroy(pools[i]); + + kfree(mgr); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_buddy.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_buddy.c new file mode 100644 index 00000000000000..fe228d948b4764 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_buddy.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 - 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006 - 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. + */ + +#include "dr_types.h" + +int mlx5dr_buddy_init(struct mlx5dr_icm_buddy_mem *buddy, + unsigned int max_order) +{ + int i; + + buddy->max_order = max_order; + + INIT_LIST_HEAD(&buddy->list_node); + + buddy->bitmap = kcalloc(buddy->max_order + 1, + sizeof(*buddy->bitmap), + GFP_KERNEL); + buddy->num_free = kcalloc(buddy->max_order + 1, + sizeof(*buddy->num_free), + GFP_KERNEL); + + if (!buddy->bitmap || !buddy->num_free) + goto err_free_all; + + /* Allocating max_order bitmaps, one for each order */ + + for (i = 0; i <= buddy->max_order; ++i) { + unsigned int size = 1 << (buddy->max_order - i); + + buddy->bitmap[i] = bitmap_zalloc(size, GFP_KERNEL); + if (!buddy->bitmap[i]) + goto err_out_free_each_bit_per_order; + } + + /* In the beginning, we have only one order that is available for + * use (the biggest one), so mark the first bit in both bitmaps. + */ + + bitmap_set(buddy->bitmap[buddy->max_order], 0, 1); + + buddy->num_free[buddy->max_order] = 1; + + return 0; + +err_out_free_each_bit_per_order: + for (i = 0; i <= buddy->max_order; ++i) + bitmap_free(buddy->bitmap[i]); + +err_free_all: + kfree(buddy->num_free); + kfree(buddy->bitmap); + return -ENOMEM; +} + +void mlx5dr_buddy_cleanup(struct mlx5dr_icm_buddy_mem *buddy) +{ + int i; + + list_del(&buddy->list_node); + + for (i = 0; i <= buddy->max_order; ++i) + bitmap_free(buddy->bitmap[i]); + + kfree(buddy->num_free); + kfree(buddy->bitmap); +} + +static int dr_buddy_find_free_seg(struct mlx5dr_icm_buddy_mem *buddy, + unsigned int start_order, + unsigned int *segment, + unsigned int *order) +{ + unsigned int seg, order_iter, m; + + for (order_iter = start_order; + order_iter <= buddy->max_order; ++order_iter) { + if (!buddy->num_free[order_iter]) + continue; + + m = 1 << (buddy->max_order - order_iter); + seg = find_first_bit(buddy->bitmap[order_iter], m); + + if (WARN(seg >= m, + "ICM Buddy: failed finding free mem for order %d\n", + order_iter)) + return -ENOMEM; + + break; + } + + if (order_iter > buddy->max_order) + return -ENOMEM; + + *segment = seg; + *order = order_iter; + return 0; +} + +/** + * mlx5dr_buddy_alloc_mem() - Update second level bitmap. + * @buddy: Buddy to update. + * @order: Order of the buddy to update. + * @segment: Segment number. + * + * This function finds the first area of the ICM memory managed by this buddy. + * It uses the data structures of the buddy system in order to find the first + * area of free place, starting from the current order till the maximum order + * in the system. + * + * Return: 0 when segment is set, non-zero error status otherwise. + * + * The function returns the location (segment) in the whole buddy ICM memory + * area - the index of the memory segment that is available for use. + */ +int mlx5dr_buddy_alloc_mem(struct mlx5dr_icm_buddy_mem *buddy, + unsigned int order, + unsigned int *segment) +{ + unsigned int seg, order_iter; + int err; + + err = dr_buddy_find_free_seg(buddy, order, &seg, &order_iter); + if (err) + return err; + + bitmap_clear(buddy->bitmap[order_iter], seg, 1); + --buddy->num_free[order_iter]; + + /* If we found free memory in some order that is bigger than the + * required order, we need to split every order between the required + * order and the order that we found into two parts, and mark accordingly. + */ + while (order_iter > order) { + --order_iter; + seg <<= 1; + bitmap_set(buddy->bitmap[order_iter], seg ^ 1, 1); + ++buddy->num_free[order_iter]; + } + + seg <<= order; + *segment = seg; + + return 0; +} + +void mlx5dr_buddy_free_mem(struct mlx5dr_icm_buddy_mem *buddy, + unsigned int seg, unsigned int order) +{ + seg >>= order; + + /* Whenever a segment is free, + * the mem is added to the buddy that gave it. + */ + while (test_bit(seg ^ 1, buddy->bitmap[order])) { + bitmap_clear(buddy->bitmap[order], seg ^ 1, 1); + --buddy->num_free[order]; + seg >>= 1; + ++order; + } + bitmap_set(buddy->bitmap[order], seg, 1); + + ++buddy->num_free[order]; +} + diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c new file mode 100644 index 00000000000000..baefb9a3fa05ea --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_cmd.c @@ -0,0 +1,970 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include "dr_types.h" + +int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, + bool other_vport, + u16 vport_number, + u64 *icm_address_rx, + u64 *icm_address_tx) +{ + u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {}; + u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {}; + int err; + + MLX5_SET(query_esw_vport_context_in, in, opcode, + MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT); + MLX5_SET(query_esw_vport_context_in, in, other_vport, other_vport); + MLX5_SET(query_esw_vport_context_in, in, vport_number, vport_number); + + err = mlx5_cmd_exec_inout(mdev, query_esw_vport_context, in, out); + if (err) + return err; + + *icm_address_rx = + MLX5_GET64(query_esw_vport_context_out, out, + esw_vport_context.sw_steering_vport_icm_address_rx); + *icm_address_tx = + MLX5_GET64(query_esw_vport_context_out, out, + esw_vport_context.sw_steering_vport_icm_address_tx); + return 0; +} + +int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport, + u16 vport_number, u16 *gvmi) +{ + bool ec_vf_func = other_vport ? mlx5_core_is_ec_vf_vport(mdev, vport_number) : false; + u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; + int out_size; + void *out; + int err; + + out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out); + out = kzalloc(out_size, GFP_KERNEL); + if (!out) + return -ENOMEM; + + MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); + MLX5_SET(query_hca_cap_in, in, other_function, other_vport); + MLX5_SET(query_hca_cap_in, in, function_id, mlx5_vport_to_func_id(mdev, vport_number, ec_vf_func)); + MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); + MLX5_SET(query_hca_cap_in, in, op_mod, + MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | + HCA_CAP_OPMOD_GET_CUR); + + err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out); + if (err) { + kfree(out); + return err; + } + + *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id); + + kfree(out); + return 0; +} + +int mlx5dr_cmd_query_esw_caps(struct mlx5_core_dev *mdev, + struct mlx5dr_esw_caps *caps) +{ + caps->drop_icm_address_rx = + MLX5_CAP64_ESW_FLOWTABLE(mdev, + sw_steering_fdb_action_drop_icm_address_rx); + caps->drop_icm_address_tx = + MLX5_CAP64_ESW_FLOWTABLE(mdev, + sw_steering_fdb_action_drop_icm_address_tx); + caps->uplink_icm_address_rx = + MLX5_CAP64_ESW_FLOWTABLE(mdev, + sw_steering_uplink_icm_address_rx); + caps->uplink_icm_address_tx = + MLX5_CAP64_ESW_FLOWTABLE(mdev, + sw_steering_uplink_icm_address_tx); + caps->sw_owner_v2 = MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, sw_owner_v2); + if (!caps->sw_owner_v2) + caps->sw_owner = MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, sw_owner); + + return 0; +} + +static int dr_cmd_query_nic_vport_roce_en(struct mlx5_core_dev *mdev, + u16 vport, bool *roce_en) +{ + u32 out[MLX5_ST_SZ_DW(query_nic_vport_context_out)] = {}; + u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {}; + int err; + + MLX5_SET(query_nic_vport_context_in, in, opcode, + MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT); + MLX5_SET(query_nic_vport_context_in, in, vport_number, vport); + MLX5_SET(query_nic_vport_context_in, in, other_vport, !!vport); + + err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (err) + return err; + + *roce_en = MLX5_GET(query_nic_vport_context_out, out, + nic_vport_context.roce_en); + return 0; +} + +int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev, + struct mlx5dr_cmd_caps *caps) +{ + bool roce_en; + int err; + + caps->prio_tag_required = MLX5_CAP_GEN(mdev, prio_tag_required); + caps->eswitch_manager = MLX5_CAP_GEN(mdev, eswitch_manager); + 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); + if (err) + return err; + + caps->roce_caps.roce_en = roce_en; + 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); + } + + caps->isolate_vl_tc = MLX5_CAP_GEN(mdev, isolate_vl_tc_new); + + caps->support_modify_argument = + MLX5_CAP_GEN_64(mdev, general_obj_types) & + MLX5_GENERAL_OBJ_TYPES_CAP_HEADER_MODIFY_ARGUMENT; + + if (caps->support_modify_argument) { + caps->log_header_modify_argument_granularity = + MLX5_CAP_GEN(mdev, log_header_modify_argument_granularity); + caps->log_header_modify_argument_max_alloc = + MLX5_CAP_GEN(mdev, log_header_modify_argument_max_alloc); + } + + /* geneve_tlv_option_0_exist is the indication of + * STE support for lookup type flex_parser_ok + */ + caps->flex_parser_ok_bits_supp = + MLX5_CAP_FLOWTABLE(mdev, + flow_table_properties_nic_receive.ft_field_support.geneve_tlv_option_0_exist); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V4_ENABLED) { + caps->flex_parser_id_icmp_dw0 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw0); + caps->flex_parser_id_icmp_dw1 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw1); + } + + if (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V6_ENABLED) { + caps->flex_parser_id_icmpv6_dw0 = + MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw0); + caps->flex_parser_id_icmpv6_dw1 = + MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw1); + } + + if (caps->flex_protocols & MLX5_FLEX_PARSER_GENEVE_TLV_OPTION_0_ENABLED) + caps->flex_parser_id_geneve_tlv_option_0 = + MLX5_CAP_GEN(mdev, flex_parser_id_geneve_tlv_option_0); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED) + caps->flex_parser_id_mpls_over_gre = + MLX5_CAP_GEN(mdev, flex_parser_id_outer_first_mpls_over_gre); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED) + caps->flex_parser_id_mpls_over_udp = + MLX5_CAP_GEN(mdev, flex_parser_id_outer_first_mpls_over_udp_label); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_0_ENABLED) + caps->flex_parser_id_gtpu_dw_0 = + MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_dw_0); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_TEID_ENABLED) + caps->flex_parser_id_gtpu_teid = + MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_teid); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_2_ENABLED) + caps->flex_parser_id_gtpu_dw_2 = + MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_dw_2); + + if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_FIRST_EXT_DW_0_ENABLED) + caps->flex_parser_id_gtpu_first_ext_dw_0 = + MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_first_ext_dw_0); + + caps->nic_rx_drop_address = + MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_rx_action_drop_icm_address); + caps->nic_tx_drop_address = + MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_drop_icm_address); + caps->nic_tx_allow_address = + MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_allow_icm_address); + + caps->rx_sw_owner_v2 = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner_v2); + caps->tx_sw_owner_v2 = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner_v2); + + if (!caps->rx_sw_owner_v2) + caps->rx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner); + if (!caps->tx_sw_owner_v2) + caps->tx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner); + + caps->max_ft_level = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, max_ft_level); + + caps->log_icm_size = MLX5_CAP_DEV_MEM(mdev, log_steering_sw_icm_size); + caps->hdr_modify_icm_addr = + MLX5_CAP64_DEV_MEM(mdev, header_modify_sw_icm_start_address); + + caps->log_modify_pattern_icm_size = + MLX5_CAP_DEV_MEM(mdev, log_header_modify_pattern_sw_icm_size); + + caps->hdr_modify_pattern_icm_addr = + MLX5_CAP64_DEV_MEM(mdev, header_modify_pattern_sw_icm_start_address); + + caps->roce_min_src_udp = MLX5_CAP_ROCE(mdev, r_roce_min_src_udp_port); + + caps->is_ecpf = mlx5_core_is_ecpf_esw_manager(mdev); + + return 0; +} + +int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev, + enum fs_flow_table_type type, + u32 table_id, + struct mlx5dr_cmd_query_flow_table_details *output) +{ + u32 out[MLX5_ST_SZ_DW(query_flow_table_out)] = {}; + u32 in[MLX5_ST_SZ_DW(query_flow_table_in)] = {}; + int err; + + MLX5_SET(query_flow_table_in, in, opcode, + MLX5_CMD_OP_QUERY_FLOW_TABLE); + + MLX5_SET(query_flow_table_in, in, table_type, type); + MLX5_SET(query_flow_table_in, in, table_id, table_id); + + err = mlx5_cmd_exec_inout(dev, query_flow_table, in, out); + if (err) + return err; + + output->status = MLX5_GET(query_flow_table_out, out, status); + output->level = MLX5_GET(query_flow_table_out, out, flow_table_context.level); + + output->sw_owner_icm_root_1 = MLX5_GET64(query_flow_table_out, out, + flow_table_context.sws.sw_owner_icm_root_1); + output->sw_owner_icm_root_0 = MLX5_GET64(query_flow_table_out, out, + flow_table_context.sws.sw_owner_icm_root_0); + + return 0; +} + +int mlx5dr_cmd_query_flow_sampler(struct mlx5_core_dev *dev, + u32 sampler_id, + u64 *rx_icm_addr, + u64 *tx_icm_addr) +{ + u32 out[MLX5_ST_SZ_DW(query_sampler_obj_out)] = {}; + u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; + void *attr; + int ret; + + MLX5_SET(general_obj_in_cmd_hdr, in, opcode, + MLX5_CMD_OP_QUERY_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, + MLX5_GENERAL_OBJECT_TYPES_SAMPLER); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, sampler_id); + + ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); + if (ret) + return ret; + + attr = MLX5_ADDR_OF(query_sampler_obj_out, out, sampler_object); + + *rx_icm_addr = MLX5_GET64(sampler_obj, attr, + sw_steering_icm_address_rx); + *tx_icm_addr = MLX5_GET64(sampler_obj, attr, + sw_steering_icm_address_tx); + + return 0; +} + +int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev) +{ + u32 in[MLX5_ST_SZ_DW(sync_steering_in)] = {}; + + /* Skip SYNC in case the device is internal error state. + * Besides a device error, this also happens when we're + * in fast teardown + */ + if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) + return 0; + + MLX5_SET(sync_steering_in, in, opcode, MLX5_CMD_OP_SYNC_STEERING); + + return mlx5_cmd_exec_in(mdev, sync_steering, in); +} + +int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id, + u32 group_id, + u32 modify_header_id, + u16 vport) +{ + u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {}; + void *in_flow_context; + unsigned int inlen; + void *in_dests; + u32 *in; + int err; + + inlen = MLX5_ST_SZ_BYTES(set_fte_in) + + 1 * MLX5_ST_SZ_BYTES(dest_format_struct); /* One destination only */ + + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); + MLX5_SET(set_fte_in, in, table_type, table_type); + MLX5_SET(set_fte_in, in, table_id, table_id); + + in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); + MLX5_SET(flow_context, in_flow_context, group_id, group_id); + MLX5_SET(flow_context, in_flow_context, modify_header_id, modify_header_id); + MLX5_SET(flow_context, in_flow_context, destination_list_size, 1); + MLX5_SET(flow_context, in_flow_context, action, + MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | + MLX5_FLOW_CONTEXT_ACTION_MOD_HDR); + + in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); + MLX5_SET(dest_format_struct, in_dests, destination_type, + MLX5_IFC_FLOW_DESTINATION_TYPE_VPORT); + MLX5_SET(dest_format_struct, in_dests, destination_id, vport); + + err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); + kvfree(in); + + return err; +} + +int mlx5dr_cmd_del_flow_table_entry(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id) +{ + u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {}; + + MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY); + MLX5_SET(delete_fte_in, in, table_type, table_type); + MLX5_SET(delete_fte_in, in, table_id, table_id); + + return mlx5_cmd_exec_in(mdev, delete_fte, in); +} + +int mlx5dr_cmd_alloc_modify_header(struct mlx5_core_dev *mdev, + u32 table_type, + u8 num_of_actions, + u64 *actions, + u32 *modify_header_id) +{ + u32 out[MLX5_ST_SZ_DW(alloc_modify_header_context_out)] = {}; + void *p_actions; + u32 inlen; + u32 *in; + int err; + + inlen = MLX5_ST_SZ_BYTES(alloc_modify_header_context_in) + + num_of_actions * sizeof(u64); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(alloc_modify_header_context_in, in, opcode, + MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT); + MLX5_SET(alloc_modify_header_context_in, in, table_type, table_type); + MLX5_SET(alloc_modify_header_context_in, in, num_of_actions, num_of_actions); + p_actions = MLX5_ADDR_OF(alloc_modify_header_context_in, in, actions); + memcpy(p_actions, actions, num_of_actions * sizeof(u64)); + + err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); + if (err) + goto out; + + *modify_header_id = MLX5_GET(alloc_modify_header_context_out, out, + modify_header_id); +out: + kvfree(in); + return err; +} + +int mlx5dr_cmd_dealloc_modify_header(struct mlx5_core_dev *mdev, + u32 modify_header_id) +{ + u32 in[MLX5_ST_SZ_DW(dealloc_modify_header_context_in)] = {}; + + MLX5_SET(dealloc_modify_header_context_in, in, opcode, + MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT); + MLX5_SET(dealloc_modify_header_context_in, in, modify_header_id, + modify_header_id); + + return mlx5_cmd_exec_in(mdev, dealloc_modify_header_context, in); +} + +int mlx5dr_cmd_create_empty_flow_group(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id, + u32 *group_id) +{ + u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {}; + int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); + u32 *in; + int err; + + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP); + MLX5_SET(create_flow_group_in, in, table_type, table_type); + MLX5_SET(create_flow_group_in, in, table_id, table_id); + + err = mlx5_cmd_exec_inout(mdev, create_flow_group, in, out); + if (err) + goto out; + + *group_id = MLX5_GET(create_flow_group_out, out, group_id); + +out: + kvfree(in); + return err; +} + +int mlx5dr_cmd_destroy_flow_group(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id, + u32 group_id) +{ + u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {}; + + MLX5_SET(destroy_flow_group_in, in, opcode, + MLX5_CMD_OP_DESTROY_FLOW_GROUP); + MLX5_SET(destroy_flow_group_in, in, table_type, table_type); + MLX5_SET(destroy_flow_group_in, in, table_id, table_id); + MLX5_SET(destroy_flow_group_in, in, group_id, group_id); + + return mlx5_cmd_exec_in(mdev, destroy_flow_group, in); +} + +int mlx5dr_cmd_create_flow_table(struct mlx5_core_dev *mdev, + struct mlx5dr_cmd_create_flow_table_attr *attr, + u64 *fdb_rx_icm_addr, + u32 *table_id) +{ + u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {}; + u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {}; + void *ft_mdev; + int err; + + MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE); + MLX5_SET(create_flow_table_in, in, table_type, attr->table_type); + MLX5_SET(create_flow_table_in, in, uid, attr->uid); + + ft_mdev = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context); + MLX5_SET(flow_table_context, ft_mdev, termination_table, attr->term_tbl); + MLX5_SET(flow_table_context, ft_mdev, sw_owner, attr->sw_owner); + MLX5_SET(flow_table_context, ft_mdev, level, attr->level); + + if (attr->sw_owner) { + /* icm_addr_0 used for FDB RX / NIC TX / NIC_RX + * icm_addr_1 used for FDB TX + */ + if (attr->table_type == MLX5_FLOW_TABLE_TYPE_NIC_RX) { + MLX5_SET64(flow_table_context, ft_mdev, + sws.sw_owner_icm_root_0, attr->icm_addr_rx); + } else if (attr->table_type == MLX5_FLOW_TABLE_TYPE_NIC_TX) { + MLX5_SET64(flow_table_context, ft_mdev, + sws.sw_owner_icm_root_0, attr->icm_addr_tx); + } else if (attr->table_type == MLX5_FLOW_TABLE_TYPE_FDB) { + MLX5_SET64(flow_table_context, ft_mdev, + sws.sw_owner_icm_root_0, attr->icm_addr_rx); + MLX5_SET64(flow_table_context, ft_mdev, + sws.sw_owner_icm_root_1, attr->icm_addr_tx); + } + } + + MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en, + attr->decap_en); + MLX5_SET(create_flow_table_in, in, flow_table_context.reformat_en, + attr->reformat_en); + + err = mlx5_cmd_exec_inout(mdev, create_flow_table, in, out); + if (err) + return err; + + *table_id = MLX5_GET(create_flow_table_out, out, table_id); + if (!attr->sw_owner && attr->table_type == MLX5_FLOW_TABLE_TYPE_FDB && + fdb_rx_icm_addr) + *fdb_rx_icm_addr = + (u64)MLX5_GET(create_flow_table_out, out, icm_address_31_0) | + (u64)MLX5_GET(create_flow_table_out, out, icm_address_39_32) << 32 | + (u64)MLX5_GET(create_flow_table_out, out, icm_address_63_40) << 40; + + return 0; +} + +int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev, + u32 table_id, + u32 table_type) +{ + u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {}; + + MLX5_SET(destroy_flow_table_in, in, opcode, + MLX5_CMD_OP_DESTROY_FLOW_TABLE); + MLX5_SET(destroy_flow_table_in, in, table_type, table_type); + MLX5_SET(destroy_flow_table_in, in, table_id, table_id); + + return mlx5_cmd_exec_in(mdev, destroy_flow_table, in); +} + +int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev, + enum mlx5_reformat_ctx_type rt, + u8 reformat_param_0, + u8 reformat_param_1, + size_t reformat_size, + void *reformat_data, + u32 *reformat_id) +{ + u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)] = {}; + size_t inlen, cmd_data_sz, cmd_total_sz; + void *prctx; + void *pdata; + void *in; + int err; + + cmd_total_sz = MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in); + cmd_data_sz = MLX5_FLD_SZ_BYTES(alloc_packet_reformat_context_in, + packet_reformat_context.reformat_data); + inlen = ALIGN(cmd_total_sz + reformat_size - cmd_data_sz, 4); + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(alloc_packet_reformat_context_in, in, opcode, + MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT); + + prctx = MLX5_ADDR_OF(alloc_packet_reformat_context_in, in, packet_reformat_context); + pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data); + + MLX5_SET(packet_reformat_context_in, prctx, reformat_type, rt); + MLX5_SET(packet_reformat_context_in, prctx, reformat_param_0, reformat_param_0); + MLX5_SET(packet_reformat_context_in, prctx, reformat_param_1, reformat_param_1); + MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, reformat_size); + if (reformat_data && reformat_size) + memcpy(pdata, reformat_data, reformat_size); + + err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); + if (err) + goto err_free_in; + + *reformat_id = MLX5_GET(alloc_packet_reformat_context_out, out, packet_reformat_id); + +err_free_in: + kvfree(in); + return err; +} + +void mlx5dr_cmd_destroy_reformat_ctx(struct mlx5_core_dev *mdev, + u32 reformat_id) +{ + u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)] = {}; + + MLX5_SET(dealloc_packet_reformat_context_in, in, opcode, + MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT); + MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id, + reformat_id); + + mlx5_cmd_exec_in(mdev, dealloc_packet_reformat_context, in); +} + +static void dr_cmd_set_definer_format(void *ptr, u16 format_id, + u8 *dw_selectors, + u8 *byte_selectors) +{ + if (format_id != MLX5_IFC_DEFINER_FORMAT_ID_SELECT) + return; + + MLX5_SET(match_definer, ptr, format_select_dw0, dw_selectors[0]); + MLX5_SET(match_definer, ptr, format_select_dw1, dw_selectors[1]); + MLX5_SET(match_definer, ptr, format_select_dw2, dw_selectors[2]); + MLX5_SET(match_definer, ptr, format_select_dw3, dw_selectors[3]); + MLX5_SET(match_definer, ptr, format_select_dw4, dw_selectors[4]); + MLX5_SET(match_definer, ptr, format_select_dw5, dw_selectors[5]); + MLX5_SET(match_definer, ptr, format_select_dw6, dw_selectors[6]); + MLX5_SET(match_definer, ptr, format_select_dw7, dw_selectors[7]); + MLX5_SET(match_definer, ptr, format_select_dw8, dw_selectors[8]); + + MLX5_SET(match_definer, ptr, format_select_byte0, byte_selectors[0]); + MLX5_SET(match_definer, ptr, format_select_byte1, byte_selectors[1]); + MLX5_SET(match_definer, ptr, format_select_byte2, byte_selectors[2]); + MLX5_SET(match_definer, ptr, format_select_byte3, byte_selectors[3]); + MLX5_SET(match_definer, ptr, format_select_byte4, byte_selectors[4]); + MLX5_SET(match_definer, ptr, format_select_byte5, byte_selectors[5]); + MLX5_SET(match_definer, ptr, format_select_byte6, byte_selectors[6]); + MLX5_SET(match_definer, ptr, format_select_byte7, byte_selectors[7]); +} + +int mlx5dr_cmd_create_definer(struct mlx5_core_dev *mdev, + u16 format_id, + u8 *dw_selectors, + u8 *byte_selectors, + u8 *match_mask, + u32 *definer_id) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; + u32 in[MLX5_ST_SZ_DW(create_match_definer_in)] = {}; + void *ptr; + int err; + + ptr = MLX5_ADDR_OF(create_match_definer_in, in, + general_obj_in_cmd_hdr); + MLX5_SET(general_obj_in_cmd_hdr, ptr, opcode, + MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, ptr, obj_type, + MLX5_OBJ_TYPE_MATCH_DEFINER); + + ptr = MLX5_ADDR_OF(create_match_definer_in, in, obj_context); + MLX5_SET(match_definer, ptr, format_id, format_id); + + dr_cmd_set_definer_format(ptr, format_id, + dw_selectors, byte_selectors); + + ptr = MLX5_ADDR_OF(match_definer, ptr, match_mask); + memcpy(ptr, match_mask, MLX5_FLD_SZ_BYTES(match_definer, match_mask)); + + err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); + if (err) + return err; + + *definer_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); + + return 0; +} + +void +mlx5dr_cmd_destroy_definer(struct mlx5_core_dev *mdev, u32 definer_id) +{ + u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)]; + + MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_MATCH_DEFINER); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, definer_id); + + mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); +} + +int mlx5dr_cmd_query_gid(struct mlx5_core_dev *mdev, u8 vhca_port_num, + u16 index, struct mlx5dr_cmd_gid_attr *attr) +{ + u32 out[MLX5_ST_SZ_DW(query_roce_address_out)] = {}; + u32 in[MLX5_ST_SZ_DW(query_roce_address_in)] = {}; + int err; + + MLX5_SET(query_roce_address_in, in, opcode, + MLX5_CMD_OP_QUERY_ROCE_ADDRESS); + + MLX5_SET(query_roce_address_in, in, roce_address_index, index); + MLX5_SET(query_roce_address_in, in, vhca_port_num, vhca_port_num); + + err = mlx5_cmd_exec_inout(mdev, query_roce_address, in, out); + if (err) + return err; + + memcpy(&attr->gid, + MLX5_ADDR_OF(query_roce_address_out, + out, roce_address.source_l3_address), + sizeof(attr->gid)); + memcpy(attr->mac, + MLX5_ADDR_OF(query_roce_address_out, out, + roce_address.source_mac_47_32), + sizeof(attr->mac)); + + if (MLX5_GET(query_roce_address_out, out, + roce_address.roce_version) == MLX5_ROCE_VERSION_2) + attr->roce_ver = MLX5_ROCE_VERSION_2; + else + attr->roce_ver = MLX5_ROCE_VERSION_1; + + return 0; +} + +int mlx5dr_cmd_create_modify_header_arg(struct mlx5_core_dev *dev, + u16 log_obj_range, u32 pd, + u32 *obj_id) +{ + u32 in[MLX5_ST_SZ_DW(create_modify_header_arg_in)] = {}; + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; + void *attr; + int ret; + + attr = MLX5_ADDR_OF(create_modify_header_arg_in, in, hdr); + MLX5_SET(general_obj_in_cmd_hdr, attr, opcode, + MLX5_CMD_OP_CREATE_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, attr, obj_type, + MLX5_OBJ_TYPE_HEADER_MODIFY_ARGUMENT); + MLX5_SET(general_obj_in_cmd_hdr, attr, + op_param.create.log_obj_range, log_obj_range); + + attr = MLX5_ADDR_OF(create_modify_header_arg_in, in, arg); + MLX5_SET(modify_header_arg, attr, access_pd, pd); + + ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); + if (ret) + return ret; + + *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id); + return 0; +} + +void mlx5dr_cmd_destroy_modify_header_arg(struct mlx5_core_dev *dev, + u32 obj_id) +{ + u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {}; + u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {}; + + MLX5_SET(general_obj_in_cmd_hdr, in, opcode, + MLX5_CMD_OP_DESTROY_GENERAL_OBJECT); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, + MLX5_OBJ_TYPE_HEADER_MODIFY_ARGUMENT); + MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id); + + mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out)); +} + +static int mlx5dr_cmd_set_extended_dest(struct mlx5_core_dev *dev, + struct mlx5dr_cmd_fte_info *fte, + bool *extended_dest) +{ + int fw_log_max_fdb_encap_uplink = MLX5_CAP_ESW(dev, log_max_fdb_encap_uplink); + int num_fwd_destinations = 0; + int num_encap = 0; + int i; + + *extended_dest = false; + if (!(fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST)) + return 0; + for (i = 0; i < fte->dests_size; i++) { + if (fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_COUNTER || + fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_NONE) + continue; + if ((fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_VPORT || + fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_UPLINK) && + fte->dest_arr[i].vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID) + num_encap++; + num_fwd_destinations++; + } + + if (num_fwd_destinations > 1 && num_encap > 0) + *extended_dest = true; + + if (*extended_dest && !fw_log_max_fdb_encap_uplink) { + mlx5_core_warn(dev, "FW does not support extended destination"); + return -EOPNOTSUPP; + } + if (num_encap > (1 << fw_log_max_fdb_encap_uplink)) { + mlx5_core_warn(dev, "FW does not support more than %d encaps", + 1 << fw_log_max_fdb_encap_uplink); + return -EOPNOTSUPP; + } + + return 0; +} + +int mlx5dr_cmd_set_fte(struct mlx5_core_dev *dev, + int opmod, int modify_mask, + struct mlx5dr_cmd_ft_info *ft, + u32 group_id, + struct mlx5dr_cmd_fte_info *fte) +{ + u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {}; + void *in_flow_context, *vlan; + bool extended_dest = false; + void *in_match_value; + unsigned int inlen; + int dst_cnt_size; + void *in_dests; + u32 *in; + int err; + int i; + + if (mlx5dr_cmd_set_extended_dest(dev, fte, &extended_dest)) + return -EOPNOTSUPP; + + if (!extended_dest) + dst_cnt_size = MLX5_ST_SZ_BYTES(dest_format_struct); + else + dst_cnt_size = MLX5_ST_SZ_BYTES(extended_dest_format); + + inlen = MLX5_ST_SZ_BYTES(set_fte_in) + fte->dests_size * dst_cnt_size; + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + return -ENOMEM; + + MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY); + MLX5_SET(set_fte_in, in, op_mod, opmod); + MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask); + MLX5_SET(set_fte_in, in, table_type, ft->type); + MLX5_SET(set_fte_in, in, table_id, ft->id); + MLX5_SET(set_fte_in, in, flow_index, fte->index); + MLX5_SET(set_fte_in, in, ignore_flow_level, fte->ignore_flow_level); + if (ft->vport) { + MLX5_SET(set_fte_in, in, vport_number, ft->vport); + MLX5_SET(set_fte_in, in, other_vport, 1); + } + + in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context); + MLX5_SET(flow_context, in_flow_context, group_id, group_id); + + MLX5_SET(flow_context, in_flow_context, flow_tag, + fte->flow_context.flow_tag); + MLX5_SET(flow_context, in_flow_context, flow_source, + fte->flow_context.flow_source); + + MLX5_SET(flow_context, in_flow_context, extended_destination, + extended_dest); + if (extended_dest) { + u32 action; + + action = fte->action.action & + ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; + MLX5_SET(flow_context, in_flow_context, action, action); + } else { + MLX5_SET(flow_context, in_flow_context, action, + fte->action.action); + if (fte->action.pkt_reformat) + MLX5_SET(flow_context, in_flow_context, packet_reformat_id, + fte->action.pkt_reformat->id); + } + if (fte->action.modify_hdr) + MLX5_SET(flow_context, in_flow_context, modify_header_id, + fte->action.modify_hdr->id); + + vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan); + + MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[0].ethtype); + MLX5_SET(vlan, vlan, vid, fte->action.vlan[0].vid); + MLX5_SET(vlan, vlan, prio, fte->action.vlan[0].prio); + + vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan_2); + + MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[1].ethtype); + MLX5_SET(vlan, vlan, vid, fte->action.vlan[1].vid); + MLX5_SET(vlan, vlan, prio, fte->action.vlan[1].prio); + + in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context, + match_value); + memcpy(in_match_value, fte->val, sizeof(u32) * MLX5_ST_SZ_DW_MATCH_PARAM); + + in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination); + if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { + int list_size = 0; + + for (i = 0; i < fte->dests_size; i++) { + enum mlx5_flow_destination_type type = fte->dest_arr[i].type; + enum mlx5_ifc_flow_destination_type ifc_type; + unsigned int id; + + if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) + continue; + + switch (type) { + case MLX5_FLOW_DESTINATION_TYPE_NONE: + continue; + case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: + id = fte->dest_arr[i].ft_num; + ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_TABLE; + break; + case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: + id = fte->dest_arr[i].ft_id; + ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_TABLE; + + break; + case MLX5_FLOW_DESTINATION_TYPE_UPLINK: + case MLX5_FLOW_DESTINATION_TYPE_VPORT: + if (type == MLX5_FLOW_DESTINATION_TYPE_VPORT) { + id = fte->dest_arr[i].vport.num; + MLX5_SET(dest_format_struct, in_dests, + destination_eswitch_owner_vhca_id_valid, + !!(fte->dest_arr[i].vport.flags & + MLX5_FLOW_DEST_VPORT_VHCA_ID)); + ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_VPORT; + } else { + id = 0; + ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_UPLINK; + MLX5_SET(dest_format_struct, in_dests, + destination_eswitch_owner_vhca_id_valid, 1); + } + MLX5_SET(dest_format_struct, in_dests, + destination_eswitch_owner_vhca_id, + fte->dest_arr[i].vport.vhca_id); + if (extended_dest && (fte->dest_arr[i].vport.flags & + MLX5_FLOW_DEST_VPORT_REFORMAT_ID)) { + MLX5_SET(dest_format_struct, in_dests, + packet_reformat, + !!(fte->dest_arr[i].vport.flags & + MLX5_FLOW_DEST_VPORT_REFORMAT_ID)); + MLX5_SET(extended_dest_format, in_dests, + packet_reformat_id, + fte->dest_arr[i].vport.reformat_id); + } + break; + case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER: + id = fte->dest_arr[i].sampler_id; + ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_SAMPLER; + break; + default: + id = fte->dest_arr[i].tir_num; + ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_TIR; + } + + MLX5_SET(dest_format_struct, in_dests, destination_type, + ifc_type); + MLX5_SET(dest_format_struct, in_dests, destination_id, id); + in_dests += dst_cnt_size; + list_size++; + } + + MLX5_SET(flow_context, in_flow_context, destination_list_size, + list_size); + } + + if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { + int max_list_size = BIT(MLX5_CAP_FLOWTABLE_TYPE(dev, + log_max_flow_counter, + ft->type)); + int list_size = 0; + + for (i = 0; i < fte->dests_size; i++) { + if (fte->dest_arr[i].type != + MLX5_FLOW_DESTINATION_TYPE_COUNTER) + continue; + + MLX5_SET(flow_counter_list, in_dests, flow_counter_id, + fte->dest_arr[i].counter_id); + in_dests += dst_cnt_size; + list_size++; + } + if (list_size > max_list_size) { + err = -EINVAL; + goto err_out; + } + + MLX5_SET(flow_context, in_flow_context, flow_counter_list_size, + list_size); + } + + err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); +err_out: + kvfree(in); + return err; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c new file mode 100644 index 00000000000000..030a5776c93740 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.c @@ -0,0 +1,1186 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +#include +#include +#include +#include +#include "dr_types.h" + +#define DR_DBG_PTR_TO_ID(p) ((u64)(uintptr_t)(p) & 0xFFFFFFFFULL) + +enum dr_dump_rec_type { + DR_DUMP_REC_TYPE_DOMAIN = 3000, + DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER = 3001, + DR_DUMP_REC_TYPE_DOMAIN_INFO_DEV_ATTR = 3002, + DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT = 3003, + DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS = 3004, + DR_DUMP_REC_TYPE_DOMAIN_SEND_RING = 3005, + + DR_DUMP_REC_TYPE_TABLE = 3100, + DR_DUMP_REC_TYPE_TABLE_RX = 3101, + DR_DUMP_REC_TYPE_TABLE_TX = 3102, + + DR_DUMP_REC_TYPE_MATCHER = 3200, + DR_DUMP_REC_TYPE_MATCHER_MASK_DEPRECATED = 3201, + DR_DUMP_REC_TYPE_MATCHER_RX = 3202, + DR_DUMP_REC_TYPE_MATCHER_TX = 3203, + DR_DUMP_REC_TYPE_MATCHER_BUILDER = 3204, + DR_DUMP_REC_TYPE_MATCHER_MASK = 3205, + + DR_DUMP_REC_TYPE_RULE = 3300, + DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 = 3301, + DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0 = 3302, + DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 = 3303, + DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1 = 3304, + + DR_DUMP_REC_TYPE_ACTION_ENCAP_L2 = 3400, + DR_DUMP_REC_TYPE_ACTION_ENCAP_L3 = 3401, + DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR = 3402, + DR_DUMP_REC_TYPE_ACTION_DROP = 3403, + DR_DUMP_REC_TYPE_ACTION_QP = 3404, + DR_DUMP_REC_TYPE_ACTION_FT = 3405, + DR_DUMP_REC_TYPE_ACTION_CTR = 3406, + DR_DUMP_REC_TYPE_ACTION_TAG = 3407, + DR_DUMP_REC_TYPE_ACTION_VPORT = 3408, + DR_DUMP_REC_TYPE_ACTION_DECAP_L2 = 3409, + DR_DUMP_REC_TYPE_ACTION_DECAP_L3 = 3410, + DR_DUMP_REC_TYPE_ACTION_DEVX_TIR = 3411, + DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN = 3412, + DR_DUMP_REC_TYPE_ACTION_POP_VLAN = 3413, + DR_DUMP_REC_TYPE_ACTION_SAMPLER = 3415, + DR_DUMP_REC_TYPE_ACTION_INSERT_HDR = 3420, + DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR = 3421, + DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE = 3425, +}; + +static struct mlx5dr_dbg_dump_buff * +mlx5dr_dbg_dump_data_init_new_buff(struct mlx5dr_dbg_dump_data *dump_data) +{ + struct mlx5dr_dbg_dump_buff *new_buff; + + new_buff = kzalloc(sizeof(*new_buff), GFP_KERNEL); + if (!new_buff) + return NULL; + + new_buff->buff = kvzalloc(MLX5DR_DEBUG_DUMP_BUFF_SIZE, GFP_KERNEL); + if (!new_buff->buff) { + kfree(new_buff); + return NULL; + } + + INIT_LIST_HEAD(&new_buff->node); + list_add_tail(&new_buff->node, &dump_data->buff_list); + + return new_buff; +} + +static struct mlx5dr_dbg_dump_data * +mlx5dr_dbg_create_dump_data(void) +{ + struct mlx5dr_dbg_dump_data *dump_data; + + dump_data = kzalloc(sizeof(*dump_data), GFP_KERNEL); + if (!dump_data) + return NULL; + + INIT_LIST_HEAD(&dump_data->buff_list); + + if (!mlx5dr_dbg_dump_data_init_new_buff(dump_data)) { + kfree(dump_data); + return NULL; + } + + return dump_data; +} + +static void +mlx5dr_dbg_destroy_dump_data(struct mlx5dr_dbg_dump_data *dump_data) +{ + struct mlx5dr_dbg_dump_buff *dump_buff, *tmp_buff; + + if (!dump_data) + return; + + list_for_each_entry_safe(dump_buff, tmp_buff, &dump_data->buff_list, node) { + kvfree(dump_buff->buff); + list_del(&dump_buff->node); + kfree(dump_buff); + } + + kfree(dump_data); +} + +static int +mlx5dr_dbg_dump_data_print(struct seq_file *file, char *str, u32 size) +{ + struct mlx5dr_domain *dmn = file->private; + struct mlx5dr_dbg_dump_data *dump_data; + struct mlx5dr_dbg_dump_buff *buff; + u32 buff_capacity, write_size; + int remain_size, ret; + + if (size >= MLX5DR_DEBUG_DUMP_BUFF_SIZE) + return -EINVAL; + + dump_data = dmn->dump_info.dump_data; + buff = list_last_entry(&dump_data->buff_list, + struct mlx5dr_dbg_dump_buff, node); + + buff_capacity = (MLX5DR_DEBUG_DUMP_BUFF_SIZE - 1) - buff->index; + remain_size = buff_capacity - size; + write_size = (remain_size > 0) ? size : buff_capacity; + + if (likely(write_size)) { + ret = snprintf(buff->buff + buff->index, write_size + 1, "%s", str); + if (ret < 0) + return ret; + + buff->index += write_size; + } + + if (remain_size < 0) { + remain_size *= -1; + buff = mlx5dr_dbg_dump_data_init_new_buff(dump_data); + if (!buff) + return -ENOMEM; + + ret = snprintf(buff->buff, remain_size + 1, "%s", str + write_size); + if (ret < 0) + return ret; + + buff->index += remain_size; + } + + return 0; +} + +void mlx5dr_dbg_tbl_add(struct mlx5dr_table *tbl) +{ + mutex_lock(&tbl->dmn->dump_info.dbg_mutex); + list_add_tail(&tbl->dbg_node, &tbl->dmn->dbg_tbl_list); + mutex_unlock(&tbl->dmn->dump_info.dbg_mutex); +} + +void mlx5dr_dbg_tbl_del(struct mlx5dr_table *tbl) +{ + mutex_lock(&tbl->dmn->dump_info.dbg_mutex); + list_del(&tbl->dbg_node); + mutex_unlock(&tbl->dmn->dump_info.dbg_mutex); +} + +void mlx5dr_dbg_rule_add(struct mlx5dr_rule *rule) +{ + struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; + + mutex_lock(&dmn->dump_info.dbg_mutex); + list_add_tail(&rule->dbg_node, &rule->matcher->dbg_rule_list); + mutex_unlock(&dmn->dump_info.dbg_mutex); +} + +void mlx5dr_dbg_rule_del(struct mlx5dr_rule *rule) +{ + struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; + + mutex_lock(&dmn->dump_info.dbg_mutex); + list_del(&rule->dbg_node); + mutex_unlock(&dmn->dump_info.dbg_mutex); +} + +static u64 dr_dump_icm_to_idx(u64 icm_addr) +{ + return (icm_addr >> 6) & 0xffffffff; +} + +#define DR_HEX_SIZE 256 + +static void +dr_dump_hex_print(char hex[DR_HEX_SIZE], char *src, u32 size) +{ + if (WARN_ON_ONCE(DR_HEX_SIZE < 2 * size + 1)) + size = DR_HEX_SIZE / 2 - 1; /* truncate */ + + bin2hex(hex, src, size); + hex[2 * size] = 0; /* NULL-terminate */ +} + +static int +dr_dump_rule_action_mem(struct seq_file *file, char *buff, const u64 rule_id, + struct mlx5dr_rule_action_member *action_mem) +{ + struct mlx5dr_action *action = action_mem->action; + const u64 action_id = DR_DBG_PTR_TO_ID(action); + u64 hit_tbl_ptr, miss_tbl_ptr; + u32 hit_tbl_id, miss_tbl_id; + int ret; + + switch (action->action_type) { + case DR_ACTION_TYP_DROP: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_DROP, action_id, + rule_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_FT: + if (action->dest_tbl->is_fw_tbl) + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_FT, action_id, + rule_id, action->dest_tbl->fw_tbl.id, + -1); + else + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_FT, action_id, + rule_id, action->dest_tbl->tbl->table_id, + DR_DBG_PTR_TO_ID(action->dest_tbl->tbl)); + + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_CTR: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_CTR, action_id, rule_id, + action->ctr->ctr_id + action->ctr->offset); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_TAG: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_TAG, action_id, rule_id, + action->flow_tag->flow_tag); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_MODIFY_HDR: + { + struct mlx5dr_ptrn_obj *ptrn = action->rewrite->ptrn; + struct mlx5dr_arg_obj *arg = action->rewrite->arg; + u8 *rewrite_data = action->rewrite->data; + bool ptrn_arg; + int i; + + ptrn_arg = !action->rewrite->single_action_opt && ptrn && arg; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,%d,0x%x,0x%x,0x%x", + DR_DUMP_REC_TYPE_ACTION_MODIFY_HDR, action_id, + rule_id, action->rewrite->index, + action->rewrite->single_action_opt, + ptrn_arg ? action->rewrite->num_of_actions : 0, + ptrn_arg ? ptrn->index : 0, + ptrn_arg ? mlx5dr_arg_get_obj_id(arg) : 0); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + if (ptrn_arg) { + for (i = 0; i < action->rewrite->num_of_actions; i++) { + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + ",0x%016llx", + be64_to_cpu(((__be64 *)rewrite_data)[i])); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + } + } + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, "\n"); + if (ret < 0) + return ret; + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + } + case DR_ACTION_TYP_VPORT: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_VPORT, action_id, rule_id, + action->vport->caps->num); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_TNL_L2_TO_L2: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_DECAP_L2, action_id, + rule_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_TNL_L3_TO_L2: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_DECAP_L3, action_id, + rule_id, + (action->rewrite->ptrn && action->rewrite->arg) ? + mlx5dr_arg_get_obj_id(action->rewrite->arg) : + action->rewrite->index); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_L2_TO_TNL_L2: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_ENCAP_L2, action_id, + rule_id, action->reformat->id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_L2_TO_TNL_L3: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_ENCAP_L3, action_id, + rule_id, action->reformat->id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_POP_VLAN: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_POP_VLAN, action_id, + rule_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_PUSH_VLAN: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_PUSH_VLAN, action_id, + rule_id, action->push_vlan->vlan_hdr); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_INSERT_HDR: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_INSERT_HDR, action_id, + rule_id, action->reformat->id, + action->reformat->param_0, + action->reformat->param_1); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_REMOVE_HDR: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_REMOVE_HDR, action_id, + rule_id, action->reformat->id, + action->reformat->param_0, + action->reformat->param_1); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_SAMPLER: + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x,0x%x,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_ACTION_SAMPLER, action_id, + rule_id, 0, 0, action->sampler->sampler_id, + action->sampler->rx_icm_addr, + action->sampler->tx_icm_addr); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + case DR_ACTION_TYP_RANGE: + if (action->range->hit_tbl_action->dest_tbl->is_fw_tbl) { + hit_tbl_id = action->range->hit_tbl_action->dest_tbl->fw_tbl.id; + hit_tbl_ptr = 0; + } else { + hit_tbl_id = action->range->hit_tbl_action->dest_tbl->tbl->table_id; + hit_tbl_ptr = + DR_DBG_PTR_TO_ID(action->range->hit_tbl_action->dest_tbl->tbl); + } + + if (action->range->miss_tbl_action->dest_tbl->is_fw_tbl) { + miss_tbl_id = action->range->miss_tbl_action->dest_tbl->fw_tbl.id; + miss_tbl_ptr = 0; + } else { + miss_tbl_id = action->range->miss_tbl_action->dest_tbl->tbl->table_id; + miss_tbl_ptr = + DR_DBG_PTR_TO_ID(action->range->miss_tbl_action->dest_tbl->tbl); + } + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%llx,0x%x,0x%llx,0x%x\n", + DR_DUMP_REC_TYPE_ACTION_MATCH_RANGE, action_id, + rule_id, hit_tbl_id, hit_tbl_ptr, miss_tbl_id, + miss_tbl_ptr, action->range->definer_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + break; + default: + return 0; + } + + return 0; +} + +static int +dr_dump_rule_mem(struct seq_file *file, char *buff, struct mlx5dr_ste *ste, + bool is_rx, const u64 rule_id, u8 format_ver) +{ + char hw_ste_dump[DR_HEX_SIZE]; + u32 mem_rec_type; + int ret; + + if (format_ver == MLX5_STEERING_FORMAT_CONNECTX_5) { + mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V0 : + DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V0; + } else { + mem_rec_type = is_rx ? DR_DUMP_REC_TYPE_RULE_RX_ENTRY_V1 : + DR_DUMP_REC_TYPE_RULE_TX_ENTRY_V1; + } + + dr_dump_hex_print(hw_ste_dump, (char *)mlx5dr_ste_get_hw_ste(ste), + DR_STE_SIZE_REDUCED); + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,%s\n", mem_rec_type, + dr_dump_icm_to_idx(mlx5dr_ste_get_icm_addr(ste)), + rule_id, hw_ste_dump); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + return 0; +} + +static int +dr_dump_rule_rx_tx(struct seq_file *file, char *buff, + struct mlx5dr_rule_rx_tx *rule_rx_tx, + bool is_rx, const u64 rule_id, u8 format_ver) +{ + struct mlx5dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES]; + struct mlx5dr_ste *curr_ste = rule_rx_tx->last_rule_ste; + int ret, i; + + if (mlx5dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i)) + return 0; + + while (i--) { + ret = dr_dump_rule_mem(file, buff, ste_arr[i], is_rx, rule_id, + format_ver); + if (ret < 0) + return ret; + } + + return 0; +} + +static noinline_for_stack int +dr_dump_rule(struct seq_file *file, struct mlx5dr_rule *rule) +{ + struct mlx5dr_rule_action_member *action_mem; + const u64 rule_id = DR_DBG_PTR_TO_ID(rule); + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; + struct mlx5dr_rule_rx_tx *rx = &rule->rx; + struct mlx5dr_rule_rx_tx *tx = &rule->tx; + u8 format_ver; + int ret; + + format_ver = rule->matcher->tbl->dmn->info.caps.sw_format_ver; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", DR_DUMP_REC_TYPE_RULE, + rule_id, DR_DBG_PTR_TO_ID(rule->matcher)); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + if (rx->nic_matcher) { + ret = dr_dump_rule_rx_tx(file, buff, rx, true, rule_id, format_ver); + if (ret < 0) + return ret; + } + + if (tx->nic_matcher) { + ret = dr_dump_rule_rx_tx(file, buff, tx, false, rule_id, format_ver); + if (ret < 0) + return ret; + } + + list_for_each_entry(action_mem, &rule->rule_actions_list, list) { + ret = dr_dump_rule_action_mem(file, buff, rule_id, action_mem); + if (ret < 0) + return ret; + } + + return 0; +} + +static int +dr_dump_matcher_mask(struct seq_file *file, char *buff, + struct mlx5dr_match_param *mask, + u8 criteria, const u64 matcher_id) +{ + char dump[DR_HEX_SIZE]; + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, "%d,0x%llx,", + DR_DUMP_REC_TYPE_MATCHER_MASK, matcher_id); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + if (criteria & DR_MATCHER_CRITERIA_OUTER) { + dr_dump_hex_print(dump, (char *)&mask->outer, sizeof(mask->outer)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s,", dump); + } else { + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); + } + + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + if (criteria & DR_MATCHER_CRITERIA_INNER) { + dr_dump_hex_print(dump, (char *)&mask->inner, sizeof(mask->inner)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s,", dump); + } else { + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); + } + + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + if (criteria & DR_MATCHER_CRITERIA_MISC) { + dr_dump_hex_print(dump, (char *)&mask->misc, sizeof(mask->misc)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s,", dump); + } else { + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); + } + + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + if (criteria & DR_MATCHER_CRITERIA_MISC2) { + dr_dump_hex_print(dump, (char *)&mask->misc2, sizeof(mask->misc2)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s,", dump); + } else { + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ","); + } + + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + if (criteria & DR_MATCHER_CRITERIA_MISC3) { + dr_dump_hex_print(dump, (char *)&mask->misc3, sizeof(mask->misc3)); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%s\n", dump); + } else { + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, ",\n"); + } + + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + return 0; +} + +static int +dr_dump_matcher_builder(struct seq_file *file, char *buff, + struct mlx5dr_ste_build *builder, + u32 index, bool is_rx, const u64 matcher_id) +{ + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,%d,%d,0x%x\n", + DR_DUMP_REC_TYPE_MATCHER_BUILDER, matcher_id, index, + is_rx, builder->lu_type); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + return 0; +} + +static int +dr_dump_matcher_rx_tx(struct seq_file *file, char *buff, bool is_rx, + struct mlx5dr_matcher_rx_tx *matcher_rx_tx, + const u64 matcher_id) +{ + enum dr_dump_rec_type rec_type; + u64 s_icm_addr, e_icm_addr; + int i, ret; + + rec_type = is_rx ? DR_DUMP_REC_TYPE_MATCHER_RX : + DR_DUMP_REC_TYPE_MATCHER_TX; + + s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->s_htbl->chunk); + e_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(matcher_rx_tx->e_anchor->chunk); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,%d,0x%llx,0x%llx\n", + rec_type, DR_DBG_PTR_TO_ID(matcher_rx_tx), + matcher_id, matcher_rx_tx->num_of_builders, + dr_dump_icm_to_idx(s_icm_addr), + dr_dump_icm_to_idx(e_icm_addr)); + + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + for (i = 0; i < matcher_rx_tx->num_of_builders; i++) { + ret = dr_dump_matcher_builder(file, buff, + &matcher_rx_tx->ste_builder[i], + i, is_rx, matcher_id); + if (ret < 0) + return ret; + } + + return 0; +} + +static noinline_for_stack int +dr_dump_matcher(struct seq_file *file, struct mlx5dr_matcher *matcher) +{ + struct mlx5dr_matcher_rx_tx *rx = &matcher->rx; + struct mlx5dr_matcher_rx_tx *tx = &matcher->tx; + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; + u64 matcher_id; + int ret; + + matcher_id = DR_DBG_PTR_TO_ID(matcher); + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,%d\n", DR_DUMP_REC_TYPE_MATCHER, + matcher_id, DR_DBG_PTR_TO_ID(matcher->tbl), + matcher->prio); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + ret = dr_dump_matcher_mask(file, buff, &matcher->mask, + matcher->match_criteria, matcher_id); + if (ret < 0) + return ret; + + if (rx->nic_tbl) { + ret = dr_dump_matcher_rx_tx(file, buff, true, rx, matcher_id); + if (ret < 0) + return ret; + } + + if (tx->nic_tbl) { + ret = dr_dump_matcher_rx_tx(file, buff, false, tx, matcher_id); + if (ret < 0) + return ret; + } + + return 0; +} + +static int +dr_dump_matcher_all(struct seq_file *file, struct mlx5dr_matcher *matcher) +{ + struct mlx5dr_rule *rule; + int ret; + + ret = dr_dump_matcher(file, matcher); + if (ret < 0) + return ret; + + list_for_each_entry(rule, &matcher->dbg_rule_list, dbg_node) { + ret = dr_dump_rule(file, rule); + if (ret < 0) + return ret; + } + + return 0; +} + +static int +dr_dump_table_rx_tx(struct seq_file *file, char *buff, bool is_rx, + struct mlx5dr_table_rx_tx *table_rx_tx, + const u64 table_id) +{ + enum dr_dump_rec_type rec_type; + u64 s_icm_addr; + int ret; + + rec_type = is_rx ? DR_DUMP_REC_TYPE_TABLE_RX : + DR_DUMP_REC_TYPE_TABLE_TX; + + s_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(table_rx_tx->s_anchor->chunk); + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx\n", rec_type, table_id, + dr_dump_icm_to_idx(s_icm_addr)); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + return 0; +} + +static noinline_for_stack int +dr_dump_table(struct seq_file *file, struct mlx5dr_table *table) +{ + struct mlx5dr_table_rx_tx *rx = &table->rx; + struct mlx5dr_table_rx_tx *tx = &table->tx; + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,%d,%d\n", DR_DUMP_REC_TYPE_TABLE, + DR_DBG_PTR_TO_ID(table), DR_DBG_PTR_TO_ID(table->dmn), + table->table_type, table->level); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + if (rx->nic_dmn) { + ret = dr_dump_table_rx_tx(file, buff, true, rx, + DR_DBG_PTR_TO_ID(table)); + if (ret < 0) + return ret; + } + + if (tx->nic_dmn) { + ret = dr_dump_table_rx_tx(file, buff, false, tx, + DR_DBG_PTR_TO_ID(table)); + if (ret < 0) + return ret; + } + return 0; +} + +static int dr_dump_table_all(struct seq_file *file, struct mlx5dr_table *tbl) +{ + struct mlx5dr_matcher *matcher; + int ret; + + ret = dr_dump_table(file, tbl); + if (ret < 0) + return ret; + + list_for_each_entry(matcher, &tbl->matcher_list, list_node) { + ret = dr_dump_matcher_all(file, matcher); + if (ret < 0) + return ret; + } + return 0; +} + +static int +dr_dump_send_ring(struct seq_file *file, char *buff, + struct mlx5dr_send_ring *ring, + const u64 domain_id) +{ + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%llx,0x%x,0x%x\n", + DR_DUMP_REC_TYPE_DOMAIN_SEND_RING, + DR_DBG_PTR_TO_ID(ring), domain_id, + ring->cq->mcq.cqn, ring->qp->qpn); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + return 0; +} + +static int +dr_dump_domain_info_flex_parser(struct seq_file *file, + char *buff, + const char *flex_parser_name, + const u8 flex_parser_value, + const u64 domain_id) +{ + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,%s,0x%x\n", + DR_DUMP_REC_TYPE_DOMAIN_INFO_FLEX_PARSER, domain_id, + flex_parser_name, flex_parser_value); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + return 0; +} + +static int +dr_dump_domain_info_caps(struct seq_file *file, char *buff, + struct mlx5dr_cmd_caps *caps, + const u64 domain_id) +{ + struct mlx5dr_cmd_vport_cap *vport_caps; + unsigned long i, vports_num; + int ret; + + xa_for_each(&caps->vports.vports_caps_xa, vports_num, vport_caps) + ; /* count the number of vports in xarray */ + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,0x%x,0x%llx,0x%llx,0x%x,%lu,%d\n", + DR_DUMP_REC_TYPE_DOMAIN_INFO_CAPS, domain_id, caps->gvmi, + caps->nic_rx_drop_address, caps->nic_tx_drop_address, + caps->flex_protocols, vports_num, caps->eswitch_manager); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + xa_for_each(&caps->vports.vports_caps_xa, i, vport_caps) { + vport_caps = xa_load(&caps->vports.vports_caps_xa, i); + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,%lu,0x%x,0x%llx,0x%llx\n", + DR_DUMP_REC_TYPE_DOMAIN_INFO_VPORT, + domain_id, i, vport_caps->vport_gvmi, + vport_caps->icm_address_rx, + vport_caps->icm_address_tx); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + } + return 0; +} + +static int +dr_dump_domain_info(struct seq_file *file, char *buff, + struct mlx5dr_domain_info *info, + const u64 domain_id) +{ + int ret; + + ret = dr_dump_domain_info_caps(file, buff, &info->caps, domain_id); + if (ret < 0) + return ret; + + ret = dr_dump_domain_info_flex_parser(file, buff, "icmp_dw0", + info->caps.flex_parser_id_icmp_dw0, + domain_id); + if (ret < 0) + return ret; + + ret = dr_dump_domain_info_flex_parser(file, buff, "icmp_dw1", + info->caps.flex_parser_id_icmp_dw1, + domain_id); + if (ret < 0) + return ret; + + ret = dr_dump_domain_info_flex_parser(file, buff, "icmpv6_dw0", + info->caps.flex_parser_id_icmpv6_dw0, + domain_id); + if (ret < 0) + return ret; + + ret = dr_dump_domain_info_flex_parser(file, buff, "icmpv6_dw1", + info->caps.flex_parser_id_icmpv6_dw1, + domain_id); + if (ret < 0) + return ret; + + return 0; +} + +static noinline_for_stack int +dr_dump_domain(struct seq_file *file, struct mlx5dr_domain *dmn) +{ + char buff[MLX5DR_DEBUG_DUMP_BUFF_LENGTH]; + u64 domain_id = DR_DBG_PTR_TO_ID(dmn); + int ret; + + ret = snprintf(buff, MLX5DR_DEBUG_DUMP_BUFF_LENGTH, + "%d,0x%llx,%d,0%x,%d,%u.%u.%u,%s,%d,%u,%u,%u\n", + DR_DUMP_REC_TYPE_DOMAIN, + domain_id, dmn->type, dmn->info.caps.gvmi, + dmn->info.supp_sw_steering, + /* package version */ + LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL, + LINUX_VERSION_SUBLEVEL, + pci_name(dmn->mdev->pdev), + 0, /* domain flags */ + dmn->num_buddies[DR_ICM_TYPE_STE], + dmn->num_buddies[DR_ICM_TYPE_MODIFY_ACTION], + dmn->num_buddies[DR_ICM_TYPE_MODIFY_HDR_PTRN]); + if (ret < 0) + return ret; + + ret = mlx5dr_dbg_dump_data_print(file, buff, ret); + if (ret) + return ret; + + ret = dr_dump_domain_info(file, buff, &dmn->info, domain_id); + if (ret < 0) + return ret; + + if (dmn->info.supp_sw_steering) { + ret = dr_dump_send_ring(file, buff, dmn->send_ring, domain_id); + if (ret < 0) + return ret; + } + + return 0; +} + +static int dr_dump_domain_all(struct seq_file *file, struct mlx5dr_domain *dmn) +{ + struct mlx5dr_table *tbl; + int ret; + + mutex_lock(&dmn->dump_info.dbg_mutex); + mlx5dr_domain_lock(dmn); + + ret = dr_dump_domain(file, dmn); + if (ret < 0) + goto unlock_mutex; + + list_for_each_entry(tbl, &dmn->dbg_tbl_list, dbg_node) { + ret = dr_dump_table_all(file, tbl); + if (ret < 0) + break; + } + +unlock_mutex: + mlx5dr_domain_unlock(dmn); + mutex_unlock(&dmn->dump_info.dbg_mutex); + return ret; +} + +static void * +dr_dump_start(struct seq_file *file, loff_t *pos) +{ + struct mlx5dr_domain *dmn = file->private; + struct mlx5dr_dbg_dump_data *dump_data; + + if (atomic_read(&dmn->dump_info.state) != MLX5DR_DEBUG_DUMP_STATE_FREE) { + mlx5_core_warn(dmn->mdev, "Dump already in progress\n"); + return ERR_PTR(-EBUSY); + } + + atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_IN_PROGRESS); + dump_data = dmn->dump_info.dump_data; + + if (dump_data) { + return seq_list_start(&dump_data->buff_list, *pos); + } else if (*pos == 0) { + dump_data = mlx5dr_dbg_create_dump_data(); + if (!dump_data) + goto exit; + + dmn->dump_info.dump_data = dump_data; + if (dr_dump_domain_all(file, dmn)) { + mlx5dr_dbg_destroy_dump_data(dump_data); + dmn->dump_info.dump_data = NULL; + goto exit; + } + + return seq_list_start(&dump_data->buff_list, *pos); + } + +exit: + atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE); + return NULL; +} + +static void * +dr_dump_next(struct seq_file *file, void *v, loff_t *pos) +{ + struct mlx5dr_domain *dmn = file->private; + struct mlx5dr_dbg_dump_data *dump_data; + + dump_data = dmn->dump_info.dump_data; + + return seq_list_next(v, &dump_data->buff_list, pos); +} + +static void +dr_dump_stop(struct seq_file *file, void *v) +{ + struct mlx5dr_domain *dmn = file->private; + struct mlx5dr_dbg_dump_data *dump_data; + + if (v && IS_ERR(v)) + return; + + if (!v) { + dump_data = dmn->dump_info.dump_data; + if (dump_data) { + mlx5dr_dbg_destroy_dump_data(dump_data); + dmn->dump_info.dump_data = NULL; + } + } + + atomic_set(&dmn->dump_info.state, MLX5DR_DEBUG_DUMP_STATE_FREE); +} + +static int +dr_dump_show(struct seq_file *file, void *v) +{ + struct mlx5dr_dbg_dump_buff *entry; + + entry = list_entry(v, struct mlx5dr_dbg_dump_buff, node); + seq_printf(file, "%s", entry->buff); + + return 0; +} + +static const struct seq_operations dr_dump_sops = { + .start = dr_dump_start, + .next = dr_dump_next, + .stop = dr_dump_stop, + .show = dr_dump_show, +}; +DEFINE_SEQ_ATTRIBUTE(dr_dump); + +void mlx5dr_dbg_init_dump(struct mlx5dr_domain *dmn) +{ + struct mlx5_core_dev *dev = dmn->mdev; + char file_name[128]; + + if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) { + mlx5_core_warn(dev, + "Steering dump is not supported for NIC RX/TX domains\n"); + return; + } + + dmn->dump_info.steering_debugfs = + debugfs_create_dir("steering", mlx5_debugfs_get_dev_root(dev)); + dmn->dump_info.fdb_debugfs = + debugfs_create_dir("fdb", dmn->dump_info.steering_debugfs); + + sprintf(file_name, "dmn_%p", dmn); + debugfs_create_file(file_name, 0444, dmn->dump_info.fdb_debugfs, + dmn, &dr_dump_fops); + + INIT_LIST_HEAD(&dmn->dbg_tbl_list); + mutex_init(&dmn->dump_info.dbg_mutex); +} + +void mlx5dr_dbg_uninit_dump(struct mlx5dr_domain *dmn) +{ + debugfs_remove_recursive(dmn->dump_info.steering_debugfs); + mutex_destroy(&dmn->dump_info.dbg_mutex); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.h new file mode 100644 index 00000000000000..57c6b363b87074 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_dbg.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#define MLX5DR_DEBUG_DUMP_BUFF_SIZE (64 * 1024 * 1024) +#define MLX5DR_DEBUG_DUMP_BUFF_LENGTH 512 + +enum { + MLX5DR_DEBUG_DUMP_STATE_FREE, + MLX5DR_DEBUG_DUMP_STATE_IN_PROGRESS, +}; + +struct mlx5dr_dbg_dump_buff { + char *buff; + u32 index; + struct list_head node; +}; + +struct mlx5dr_dbg_dump_data { + struct list_head buff_list; +}; + +struct mlx5dr_dbg_dump_info { + struct mutex dbg_mutex; /* protect dbg lists */ + struct dentry *steering_debugfs; + struct dentry *fdb_debugfs; + struct mlx5dr_dbg_dump_data *dump_data; + atomic_t state; +}; + +void mlx5dr_dbg_init_dump(struct mlx5dr_domain *dmn); +void mlx5dr_dbg_uninit_dump(struct mlx5dr_domain *dmn); +void mlx5dr_dbg_tbl_add(struct mlx5dr_table *tbl); +void mlx5dr_dbg_tbl_del(struct mlx5dr_table *tbl); +void mlx5dr_dbg_rule_add(struct mlx5dr_rule *rule); +void mlx5dr_dbg_rule_del(struct mlx5dr_rule *rule); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_definer.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_definer.c new file mode 100644 index 00000000000000..d5ea9775194561 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_definer.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +#include "dr_types.h" +#include "dr_ste.h" + +struct dr_definer_object { + u32 id; + u16 format_id; + u8 dw_selectors[MLX5_IFC_DEFINER_DW_SELECTORS_NUM]; + u8 byte_selectors[MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM]; + u8 match_mask[DR_STE_SIZE_MATCH_TAG]; + refcount_t refcount; +}; + +static bool dr_definer_compare(struct dr_definer_object *definer, + u16 format_id, u8 *dw_selectors, + u8 *byte_selectors, u8 *match_mask) +{ + int i; + + if (definer->format_id != format_id) + return false; + + for (i = 0; i < MLX5_IFC_DEFINER_DW_SELECTORS_NUM; i++) + if (definer->dw_selectors[i] != dw_selectors[i]) + return false; + + for (i = 0; i < MLX5_IFC_DEFINER_BYTE_SELECTORS_NUM; i++) + if (definer->byte_selectors[i] != byte_selectors[i]) + return false; + + if (memcmp(definer->match_mask, match_mask, DR_STE_SIZE_MATCH_TAG)) + return false; + + return true; +} + +static struct dr_definer_object * +dr_definer_find_obj(struct mlx5dr_domain *dmn, u16 format_id, + u8 *dw_selectors, u8 *byte_selectors, u8 *match_mask) +{ + struct dr_definer_object *definer_obj; + unsigned long id; + + xa_for_each(&dmn->definers_xa, id, definer_obj) { + if (dr_definer_compare(definer_obj, format_id, + dw_selectors, byte_selectors, + match_mask)) + return definer_obj; + } + + return NULL; +} + +static struct dr_definer_object * +dr_definer_create_obj(struct mlx5dr_domain *dmn, u16 format_id, + u8 *dw_selectors, u8 *byte_selectors, u8 *match_mask) +{ + struct dr_definer_object *definer_obj; + int ret = 0; + + definer_obj = kzalloc(sizeof(*definer_obj), GFP_KERNEL); + if (!definer_obj) + return NULL; + + ret = mlx5dr_cmd_create_definer(dmn->mdev, + format_id, + dw_selectors, + byte_selectors, + match_mask, + &definer_obj->id); + if (ret) + goto err_free_definer_obj; + + /* Definer ID can have 32 bits, but STE format + * supports only definers with 8 bit IDs. + */ + if (definer_obj->id > 0xff) { + mlx5dr_err(dmn, "Unsupported definer ID (%d)\n", definer_obj->id); + goto err_destroy_definer; + } + + definer_obj->format_id = format_id; + memcpy(definer_obj->dw_selectors, dw_selectors, sizeof(definer_obj->dw_selectors)); + memcpy(definer_obj->byte_selectors, byte_selectors, sizeof(definer_obj->byte_selectors)); + memcpy(definer_obj->match_mask, match_mask, sizeof(definer_obj->match_mask)); + + refcount_set(&definer_obj->refcount, 1); + + ret = xa_insert(&dmn->definers_xa, definer_obj->id, definer_obj, GFP_KERNEL); + if (ret) { + mlx5dr_dbg(dmn, "Couldn't insert new definer into xarray (%d)\n", ret); + goto err_destroy_definer; + } + + return definer_obj; + +err_destroy_definer: + mlx5dr_cmd_destroy_definer(dmn->mdev, definer_obj->id); +err_free_definer_obj: + kfree(definer_obj); + + return NULL; +} + +static void dr_definer_destroy_obj(struct mlx5dr_domain *dmn, + struct dr_definer_object *definer_obj) +{ + mlx5dr_cmd_destroy_definer(dmn->mdev, definer_obj->id); + xa_erase(&dmn->definers_xa, definer_obj->id); + kfree(definer_obj); +} + +int mlx5dr_definer_get(struct mlx5dr_domain *dmn, u16 format_id, + u8 *dw_selectors, u8 *byte_selectors, + u8 *match_mask, u32 *definer_id) +{ + struct dr_definer_object *definer_obj; + int ret = 0; + + definer_obj = dr_definer_find_obj(dmn, format_id, dw_selectors, + byte_selectors, match_mask); + if (!definer_obj) { + definer_obj = dr_definer_create_obj(dmn, format_id, + dw_selectors, byte_selectors, + match_mask); + if (!definer_obj) + return -ENOMEM; + } else { + refcount_inc(&definer_obj->refcount); + } + + *definer_id = definer_obj->id; + + return ret; +} + +void mlx5dr_definer_put(struct mlx5dr_domain *dmn, u32 definer_id) +{ + struct dr_definer_object *definer_obj; + + definer_obj = xa_load(&dmn->definers_xa, definer_id); + if (!definer_obj) { + mlx5dr_err(dmn, "Definer ID %d not found\n", definer_id); + return; + } + + if (refcount_dec_and_test(&definer_obj->refcount)) + dr_definer_destroy_obj(dmn, definer_obj); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_domain.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_domain.c new file mode 100644 index 00000000000000..49f22cad92bfd0 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_domain.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include +#include +#include "dr_types.h" + +#define DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, dmn_type) \ + ((dmn)->info.caps.dmn_type##_sw_owner || \ + ((dmn)->info.caps.dmn_type##_sw_owner_v2 && \ + (dmn)->info.caps.sw_format_ver <= MLX5_STEERING_FORMAT_CONNECTX_7)) + +bool mlx5dr_domain_is_support_ptrn_arg(struct mlx5dr_domain *dmn) +{ + return dmn->info.caps.sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX && + dmn->info.caps.support_modify_argument; +} + +static int dr_domain_init_modify_header_resources(struct mlx5dr_domain *dmn) +{ + if (!mlx5dr_domain_is_support_ptrn_arg(dmn)) + return 0; + + dmn->ptrn_mgr = mlx5dr_ptrn_mgr_create(dmn); + if (!dmn->ptrn_mgr) { + mlx5dr_err(dmn, "Couldn't create ptrn_mgr\n"); + return -ENOMEM; + } + + /* create argument pool */ + dmn->arg_mgr = mlx5dr_arg_mgr_create(dmn); + if (!dmn->arg_mgr) { + mlx5dr_err(dmn, "Couldn't create arg_mgr\n"); + goto free_modify_header_pattern; + } + + return 0; + +free_modify_header_pattern: + mlx5dr_ptrn_mgr_destroy(dmn->ptrn_mgr); + return -ENOMEM; +} + +static void dr_domain_destroy_modify_header_resources(struct mlx5dr_domain *dmn) +{ + if (!mlx5dr_domain_is_support_ptrn_arg(dmn)) + return; + + mlx5dr_arg_mgr_destroy(dmn->arg_mgr); + mlx5dr_ptrn_mgr_destroy(dmn->ptrn_mgr); +} + +static void dr_domain_init_csum_recalc_fts(struct mlx5dr_domain *dmn) +{ + /* Per vport cached FW FT for checksum recalculation, this + * recalculation is needed due to a HW bug in STEv0. + */ + xa_init(&dmn->csum_fts_xa); +} + +static void dr_domain_uninit_csum_recalc_fts(struct mlx5dr_domain *dmn) +{ + struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft; + unsigned long i; + + xa_for_each(&dmn->csum_fts_xa, i, recalc_cs_ft) { + if (recalc_cs_ft) + mlx5dr_fw_destroy_recalc_cs_ft(dmn, recalc_cs_ft); + } + + xa_destroy(&dmn->csum_fts_xa); +} + +int mlx5dr_domain_get_recalc_cs_ft_addr(struct mlx5dr_domain *dmn, + u16 vport_num, + u64 *rx_icm_addr) +{ + struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft; + int ret; + + recalc_cs_ft = xa_load(&dmn->csum_fts_xa, vport_num); + if (!recalc_cs_ft) { + /* Table hasn't been created yet */ + recalc_cs_ft = mlx5dr_fw_create_recalc_cs_ft(dmn, vport_num); + if (!recalc_cs_ft) + return -EINVAL; + + ret = xa_err(xa_store(&dmn->csum_fts_xa, vport_num, + recalc_cs_ft, GFP_KERNEL)); + if (ret) + return ret; + } + + *rx_icm_addr = recalc_cs_ft->rx_icm_addr; + + return 0; +} + +static int dr_domain_init_mem_resources(struct mlx5dr_domain *dmn) +{ + int ret; + + dmn->chunks_kmem_cache = kmem_cache_create("mlx5_dr_chunks", + sizeof(struct mlx5dr_icm_chunk), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!dmn->chunks_kmem_cache) { + mlx5dr_err(dmn, "Couldn't create chunks kmem_cache\n"); + return -ENOMEM; + } + + dmn->htbls_kmem_cache = kmem_cache_create("mlx5_dr_htbls", + sizeof(struct mlx5dr_ste_htbl), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!dmn->htbls_kmem_cache) { + mlx5dr_err(dmn, "Couldn't create hash tables kmem_cache\n"); + ret = -ENOMEM; + goto free_chunks_kmem_cache; + } + + dmn->ste_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_STE); + if (!dmn->ste_icm_pool) { + mlx5dr_err(dmn, "Couldn't get icm memory\n"); + ret = -ENOMEM; + goto free_htbls_kmem_cache; + } + + dmn->action_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_MODIFY_ACTION); + if (!dmn->action_icm_pool) { + mlx5dr_err(dmn, "Couldn't get action icm memory\n"); + ret = -ENOMEM; + goto free_ste_icm_pool; + } + + ret = mlx5dr_send_info_pool_create(dmn); + if (ret) { + mlx5dr_err(dmn, "Couldn't create send info pool\n"); + goto free_action_icm_pool; + } + + return 0; + +free_action_icm_pool: + mlx5dr_icm_pool_destroy(dmn->action_icm_pool); +free_ste_icm_pool: + mlx5dr_icm_pool_destroy(dmn->ste_icm_pool); +free_htbls_kmem_cache: + kmem_cache_destroy(dmn->htbls_kmem_cache); +free_chunks_kmem_cache: + kmem_cache_destroy(dmn->chunks_kmem_cache); + + return ret; +} + +static void dr_domain_uninit_mem_resources(struct mlx5dr_domain *dmn) +{ + mlx5dr_send_info_pool_destroy(dmn); + mlx5dr_icm_pool_destroy(dmn->action_icm_pool); + mlx5dr_icm_pool_destroy(dmn->ste_icm_pool); + kmem_cache_destroy(dmn->htbls_kmem_cache); + kmem_cache_destroy(dmn->chunks_kmem_cache); +} + +static int dr_domain_init_resources(struct mlx5dr_domain *dmn) +{ + int ret; + + dmn->ste_ctx = mlx5dr_ste_get_ctx(dmn->info.caps.sw_format_ver); + if (!dmn->ste_ctx) { + mlx5dr_err(dmn, "SW Steering on this device is unsupported\n"); + return -EOPNOTSUPP; + } + + ret = mlx5_core_alloc_pd(dmn->mdev, &dmn->pdn); + if (ret) { + mlx5dr_err(dmn, "Couldn't allocate PD, ret: %d", ret); + return ret; + } + + dmn->uar = mlx5_get_uars_page(dmn->mdev); + if (IS_ERR(dmn->uar)) { + mlx5dr_err(dmn, "Couldn't allocate UAR\n"); + ret = PTR_ERR(dmn->uar); + goto clean_pd; + } + + ret = dr_domain_init_mem_resources(dmn); + if (ret) { + mlx5dr_err(dmn, "Couldn't create domain memory resources\n"); + goto clean_uar; + } + + ret = dr_domain_init_modify_header_resources(dmn); + if (ret) { + mlx5dr_err(dmn, "Couldn't create modify-header-resources\n"); + goto clean_mem_resources; + } + + ret = mlx5dr_send_ring_alloc(dmn); + if (ret) { + mlx5dr_err(dmn, "Couldn't create send-ring\n"); + goto clean_modify_hdr; + } + + return 0; + +clean_modify_hdr: + dr_domain_destroy_modify_header_resources(dmn); +clean_mem_resources: + dr_domain_uninit_mem_resources(dmn); +clean_uar: + mlx5_put_uars_page(dmn->mdev, dmn->uar); +clean_pd: + mlx5_core_dealloc_pd(dmn->mdev, dmn->pdn); + + return ret; +} + +static void dr_domain_uninit_resources(struct mlx5dr_domain *dmn) +{ + mlx5dr_send_ring_free(dmn, dmn->send_ring); + dr_domain_destroy_modify_header_resources(dmn); + dr_domain_uninit_mem_resources(dmn); + mlx5_put_uars_page(dmn->mdev, dmn->uar); + mlx5_core_dealloc_pd(dmn->mdev, dmn->pdn); +} + +static void dr_domain_fill_uplink_caps(struct mlx5dr_domain *dmn, + struct mlx5dr_cmd_vport_cap *uplink_vport) +{ + struct mlx5dr_esw_caps *esw_caps = &dmn->info.caps.esw_caps; + + uplink_vport->num = MLX5_VPORT_UPLINK; + uplink_vport->icm_address_rx = esw_caps->uplink_icm_address_rx; + uplink_vport->icm_address_tx = esw_caps->uplink_icm_address_tx; + uplink_vport->vport_gvmi = 0; + uplink_vport->vhca_gvmi = dmn->info.caps.gvmi; +} + +static int dr_domain_query_vport(struct mlx5dr_domain *dmn, + u16 vport_number, + bool other_vport, + struct mlx5dr_cmd_vport_cap *vport_caps) +{ + int ret; + + ret = mlx5dr_cmd_query_esw_vport_context(dmn->mdev, + other_vport, + vport_number, + &vport_caps->icm_address_rx, + &vport_caps->icm_address_tx); + if (ret) + return ret; + + ret = mlx5dr_cmd_query_gvmi(dmn->mdev, + other_vport, + vport_number, + &vport_caps->vport_gvmi); + if (ret) + return ret; + + vport_caps->num = vport_number; + vport_caps->vhca_gvmi = dmn->info.caps.gvmi; + + return 0; +} + +static int dr_domain_query_esw_mgr(struct mlx5dr_domain *dmn) +{ + return dr_domain_query_vport(dmn, 0, false, + &dmn->info.caps.vports.esw_manager_caps); +} + +static void dr_domain_query_uplink(struct mlx5dr_domain *dmn) +{ + dr_domain_fill_uplink_caps(dmn, &dmn->info.caps.vports.uplink_caps); +} + +static struct mlx5dr_cmd_vport_cap * +dr_domain_add_vport_cap(struct mlx5dr_domain *dmn, u16 vport) +{ + struct mlx5dr_cmd_caps *caps = &dmn->info.caps; + struct mlx5dr_cmd_vport_cap *vport_caps; + int ret; + + vport_caps = kvzalloc(sizeof(*vport_caps), GFP_KERNEL); + if (!vport_caps) + return NULL; + + ret = dr_domain_query_vport(dmn, vport, true, vport_caps); + if (ret) { + kvfree(vport_caps); + return NULL; + } + + ret = xa_insert(&caps->vports.vports_caps_xa, vport, + vport_caps, GFP_KERNEL); + if (ret) { + mlx5dr_dbg(dmn, "Couldn't insert new vport into xarray (%d)\n", ret); + kvfree(vport_caps); + if (ret == -EBUSY) + return ERR_PTR(-EBUSY); + return NULL; + } + + return vport_caps; +} + +static bool dr_domain_is_esw_mgr_vport(struct mlx5dr_domain *dmn, u16 vport) +{ + struct mlx5dr_cmd_caps *caps = &dmn->info.caps; + + return (caps->is_ecpf && vport == MLX5_VPORT_ECPF) || + (!caps->is_ecpf && vport == 0); +} + +struct mlx5dr_cmd_vport_cap * +mlx5dr_domain_get_vport_cap(struct mlx5dr_domain *dmn, u16 vport) +{ + struct mlx5dr_cmd_caps *caps = &dmn->info.caps; + struct mlx5dr_cmd_vport_cap *vport_caps; + + if (dr_domain_is_esw_mgr_vport(dmn, vport)) + return &caps->vports.esw_manager_caps; + + if (vport == MLX5_VPORT_UPLINK) + return &caps->vports.uplink_caps; + +vport_load: + vport_caps = xa_load(&caps->vports.vports_caps_xa, vport); + if (vport_caps) + return vport_caps; + + vport_caps = dr_domain_add_vport_cap(dmn, vport); + if (PTR_ERR(vport_caps) == -EBUSY) + /* caps were already stored by another thread */ + goto vport_load; + + return vport_caps; +} + +static void dr_domain_clear_vports(struct mlx5dr_domain *dmn) +{ + struct mlx5dr_cmd_vport_cap *vport_caps; + unsigned long i; + + xa_for_each(&dmn->info.caps.vports.vports_caps_xa, i, vport_caps) { + vport_caps = xa_erase(&dmn->info.caps.vports.vports_caps_xa, i); + kvfree(vport_caps); + } +} + +static int dr_domain_query_fdb_caps(struct mlx5_core_dev *mdev, + struct mlx5dr_domain *dmn) +{ + int ret; + + if (!dmn->info.caps.eswitch_manager) + return -EOPNOTSUPP; + + ret = mlx5dr_cmd_query_esw_caps(mdev, &dmn->info.caps.esw_caps); + if (ret) + return ret; + + dmn->info.caps.fdb_sw_owner = dmn->info.caps.esw_caps.sw_owner; + dmn->info.caps.fdb_sw_owner_v2 = dmn->info.caps.esw_caps.sw_owner_v2; + dmn->info.caps.esw_rx_drop_address = dmn->info.caps.esw_caps.drop_icm_address_rx; + dmn->info.caps.esw_tx_drop_address = dmn->info.caps.esw_caps.drop_icm_address_tx; + + xa_init(&dmn->info.caps.vports.vports_caps_xa); + + /* Query eswitch manager and uplink vports only. Rest of the + * vports (vport 0, VFs and SFs) will be queried dynamically. + */ + + ret = dr_domain_query_esw_mgr(dmn); + if (ret) { + mlx5dr_err(dmn, "Failed to query eswitch manager vport caps (err: %d)", ret); + goto free_vports_caps_xa; + } + + dr_domain_query_uplink(dmn); + + return 0; + +free_vports_caps_xa: + xa_destroy(&dmn->info.caps.vports.vports_caps_xa); + + return ret; +} + +static int dr_domain_caps_init(struct mlx5_core_dev *mdev, + struct mlx5dr_domain *dmn) +{ + struct mlx5dr_cmd_vport_cap *vport_cap; + int ret; + + if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) { + mlx5dr_err(dmn, "Failed to allocate domain, bad link type\n"); + return -EOPNOTSUPP; + } + + ret = mlx5dr_cmd_query_device(mdev, &dmn->info.caps); + if (ret) + return ret; + + ret = dr_domain_query_fdb_caps(mdev, dmn); + if (ret) + return ret; + + switch (dmn->type) { + case MLX5DR_DOMAIN_TYPE_NIC_RX: + if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, rx)) + return -ENOTSUPP; + + dmn->info.supp_sw_steering = true; + dmn->info.rx.type = DR_DOMAIN_NIC_TYPE_RX; + dmn->info.rx.default_icm_addr = dmn->info.caps.nic_rx_drop_address; + dmn->info.rx.drop_icm_addr = dmn->info.caps.nic_rx_drop_address; + break; + case MLX5DR_DOMAIN_TYPE_NIC_TX: + if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, tx)) + return -ENOTSUPP; + + dmn->info.supp_sw_steering = true; + dmn->info.tx.type = DR_DOMAIN_NIC_TYPE_TX; + dmn->info.tx.default_icm_addr = dmn->info.caps.nic_tx_allow_address; + dmn->info.tx.drop_icm_addr = dmn->info.caps.nic_tx_drop_address; + break; + case MLX5DR_DOMAIN_TYPE_FDB: + if (!dmn->info.caps.eswitch_manager) + return -ENOTSUPP; + + if (!DR_DOMAIN_SW_STEERING_SUPPORTED(dmn, fdb)) + return -ENOTSUPP; + + dmn->info.rx.type = DR_DOMAIN_NIC_TYPE_RX; + dmn->info.tx.type = DR_DOMAIN_NIC_TYPE_TX; + vport_cap = &dmn->info.caps.vports.esw_manager_caps; + + dmn->info.supp_sw_steering = true; + dmn->info.tx.default_icm_addr = vport_cap->icm_address_tx; + dmn->info.rx.default_icm_addr = vport_cap->icm_address_rx; + dmn->info.rx.drop_icm_addr = dmn->info.caps.esw_rx_drop_address; + dmn->info.tx.drop_icm_addr = dmn->info.caps.esw_tx_drop_address; + break; + default: + mlx5dr_err(dmn, "Invalid domain\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +static void dr_domain_caps_uninit(struct mlx5dr_domain *dmn) +{ + dr_domain_clear_vports(dmn); + xa_destroy(&dmn->info.caps.vports.vports_caps_xa); +} + +struct mlx5dr_domain * +mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type) +{ + struct mlx5dr_domain *dmn; + int ret; + + if (type > MLX5DR_DOMAIN_TYPE_FDB) + return NULL; + + dmn = kzalloc(sizeof(*dmn), GFP_KERNEL); + if (!dmn) + return NULL; + + dmn->mdev = mdev; + dmn->type = type; + refcount_set(&dmn->refcount, 1); + mutex_init(&dmn->info.rx.mutex); + mutex_init(&dmn->info.tx.mutex); + xa_init(&dmn->definers_xa); + xa_init(&dmn->peer_dmn_xa); + + if (dr_domain_caps_init(mdev, dmn)) { + mlx5dr_err(dmn, "Failed init domain, no caps\n"); + goto def_xa_destroy; + } + + dmn->info.max_log_action_icm_sz = DR_CHUNK_SIZE_4K; + dmn->info.max_log_sw_icm_sz = min_t(u32, DR_CHUNK_SIZE_1024K, + dmn->info.caps.log_icm_size); + dmn->info.max_log_modify_hdr_pattern_icm_sz = + min_t(u32, DR_CHUNK_SIZE_4K, + dmn->info.caps.log_modify_pattern_icm_size); + + if (!dmn->info.supp_sw_steering) { + mlx5dr_err(dmn, "SW steering is not supported\n"); + goto uninit_caps; + } + + /* Allocate resources */ + ret = dr_domain_init_resources(dmn); + if (ret) { + mlx5dr_err(dmn, "Failed init domain resources\n"); + goto uninit_caps; + } + + dr_domain_init_csum_recalc_fts(dmn); + mlx5dr_dbg_init_dump(dmn); + return dmn; + +uninit_caps: + dr_domain_caps_uninit(dmn); +def_xa_destroy: + xa_destroy(&dmn->peer_dmn_xa); + xa_destroy(&dmn->definers_xa); + kfree(dmn); + return NULL; +} + +/* Assure synchronization of the device steering tables with updates made by SW + * insertion. + */ +int mlx5dr_domain_sync(struct mlx5dr_domain *dmn, u32 flags) +{ + int ret = 0; + + if (flags & MLX5DR_DOMAIN_SYNC_FLAGS_SW) { + mlx5dr_domain_lock(dmn); + ret = mlx5dr_send_ring_force_drain(dmn); + mlx5dr_domain_unlock(dmn); + if (ret) { + mlx5dr_err(dmn, "Force drain failed flags: %d, ret: %d\n", + flags, ret); + return ret; + } + } + + if (flags & MLX5DR_DOMAIN_SYNC_FLAGS_HW) + ret = mlx5dr_cmd_sync_steering(dmn->mdev); + + return ret; +} + +int mlx5dr_domain_destroy(struct mlx5dr_domain *dmn) +{ + if (WARN_ON_ONCE(refcount_read(&dmn->refcount) > 1)) + return -EBUSY; + + /* make sure resources are not used by the hardware */ + mlx5dr_cmd_sync_steering(dmn->mdev); + mlx5dr_dbg_uninit_dump(dmn); + dr_domain_uninit_csum_recalc_fts(dmn); + dr_domain_uninit_resources(dmn); + dr_domain_caps_uninit(dmn); + xa_destroy(&dmn->peer_dmn_xa); + xa_destroy(&dmn->definers_xa); + mutex_destroy(&dmn->info.tx.mutex); + mutex_destroy(&dmn->info.rx.mutex); + kfree(dmn); + return 0; +} + +void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn, + struct mlx5dr_domain *peer_dmn, + u16 peer_vhca_id) +{ + struct mlx5dr_domain *peer; + + mlx5dr_domain_lock(dmn); + + peer = xa_load(&dmn->peer_dmn_xa, peer_vhca_id); + if (peer) + refcount_dec(&peer->refcount); + + WARN_ON(xa_err(xa_store(&dmn->peer_dmn_xa, peer_vhca_id, peer_dmn, GFP_KERNEL))); + + peer = xa_load(&dmn->peer_dmn_xa, peer_vhca_id); + if (peer) + refcount_inc(&peer->refcount); + + mlx5dr_domain_unlock(dmn); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_fw.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_fw.c new file mode 100644 index 00000000000000..f05ef0cd54baca --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_fw.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include +#include "dr_types.h" + +struct mlx5dr_fw_recalc_cs_ft * +mlx5dr_fw_create_recalc_cs_ft(struct mlx5dr_domain *dmn, u16 vport_num) +{ + struct mlx5dr_cmd_create_flow_table_attr ft_attr = {}; + struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft; + u32 table_id, group_id, modify_hdr_id; + u64 rx_icm_addr, modify_ttl_action; + int ret; + + recalc_cs_ft = kzalloc(sizeof(*recalc_cs_ft), GFP_KERNEL); + if (!recalc_cs_ft) + return NULL; + + ft_attr.table_type = MLX5_FLOW_TABLE_TYPE_FDB; + ft_attr.level = dmn->info.caps.max_ft_level - 1; + ft_attr.term_tbl = true; + + ret = mlx5dr_cmd_create_flow_table(dmn->mdev, + &ft_attr, + &rx_icm_addr, + &table_id); + if (ret) { + mlx5dr_err(dmn, "Failed creating TTL W/A FW flow table %d\n", ret); + goto free_ttl_tbl; + } + + ret = mlx5dr_cmd_create_empty_flow_group(dmn->mdev, + MLX5_FLOW_TABLE_TYPE_FDB, + table_id, &group_id); + if (ret) { + mlx5dr_err(dmn, "Failed creating TTL W/A FW flow group %d\n", ret); + goto destroy_flow_table; + } + + /* Modify TTL action by adding zero to trigger CS recalculation */ + modify_ttl_action = 0; + MLX5_SET(set_action_in, &modify_ttl_action, action_type, MLX5_ACTION_TYPE_ADD); + MLX5_SET(set_action_in, &modify_ttl_action, field, MLX5_ACTION_IN_FIELD_OUT_IP_TTL); + + ret = mlx5dr_cmd_alloc_modify_header(dmn->mdev, MLX5_FLOW_TABLE_TYPE_FDB, 1, + &modify_ttl_action, + &modify_hdr_id); + if (ret) { + mlx5dr_err(dmn, "Failed modify header TTL %d\n", ret); + goto destroy_flow_group; + } + + ret = mlx5dr_cmd_set_fte_modify_and_vport(dmn->mdev, + MLX5_FLOW_TABLE_TYPE_FDB, + table_id, group_id, modify_hdr_id, + vport_num); + if (ret) { + mlx5dr_err(dmn, "Failed setting TTL W/A flow table entry %d\n", ret); + goto dealloc_modify_header; + } + + recalc_cs_ft->modify_hdr_id = modify_hdr_id; + recalc_cs_ft->rx_icm_addr = rx_icm_addr; + recalc_cs_ft->table_id = table_id; + recalc_cs_ft->group_id = group_id; + + return recalc_cs_ft; + +dealloc_modify_header: + mlx5dr_cmd_dealloc_modify_header(dmn->mdev, modify_hdr_id); +destroy_flow_group: + mlx5dr_cmd_destroy_flow_group(dmn->mdev, + MLX5_FLOW_TABLE_TYPE_FDB, + table_id, group_id); +destroy_flow_table: + mlx5dr_cmd_destroy_flow_table(dmn->mdev, table_id, MLX5_FLOW_TABLE_TYPE_FDB); +free_ttl_tbl: + kfree(recalc_cs_ft); + return NULL; +} + +void mlx5dr_fw_destroy_recalc_cs_ft(struct mlx5dr_domain *dmn, + struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft) +{ + mlx5dr_cmd_del_flow_table_entry(dmn->mdev, + MLX5_FLOW_TABLE_TYPE_FDB, + recalc_cs_ft->table_id); + mlx5dr_cmd_dealloc_modify_header(dmn->mdev, recalc_cs_ft->modify_hdr_id); + mlx5dr_cmd_destroy_flow_group(dmn->mdev, + MLX5_FLOW_TABLE_TYPE_FDB, + recalc_cs_ft->table_id, + recalc_cs_ft->group_id); + mlx5dr_cmd_destroy_flow_table(dmn->mdev, + recalc_cs_ft->table_id, + MLX5_FLOW_TABLE_TYPE_FDB); + + kfree(recalc_cs_ft); +} + +int mlx5dr_fw_create_md_tbl(struct mlx5dr_domain *dmn, + struct mlx5dr_cmd_flow_destination_hw_info *dest, + int num_dest, + bool reformat_req, + u32 *tbl_id, + u32 *group_id, + bool ignore_flow_level, + u32 flow_source) +{ + struct mlx5dr_cmd_create_flow_table_attr ft_attr = {}; + struct mlx5dr_cmd_fte_info fte_info = {}; + u32 val[MLX5_ST_SZ_DW_MATCH_PARAM] = {}; + struct mlx5dr_cmd_ft_info ft_info = {}; + int ret; + + ft_attr.table_type = MLX5_FLOW_TABLE_TYPE_FDB; + ft_attr.level = min_t(int, dmn->info.caps.max_ft_level - 2, + MLX5_FT_MAX_MULTIPATH_LEVEL); + ft_attr.reformat_en = reformat_req; + ft_attr.decap_en = reformat_req; + + ret = mlx5dr_cmd_create_flow_table(dmn->mdev, &ft_attr, NULL, tbl_id); + if (ret) { + mlx5dr_err(dmn, "Failed creating multi dest FW flow table %d\n", ret); + return ret; + } + + ret = mlx5dr_cmd_create_empty_flow_group(dmn->mdev, + MLX5_FLOW_TABLE_TYPE_FDB, + *tbl_id, group_id); + if (ret) { + mlx5dr_err(dmn, "Failed creating multi dest FW flow group %d\n", ret); + goto free_flow_table; + } + + ft_info.id = *tbl_id; + ft_info.type = FS_FT_FDB; + fte_info.action.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; + fte_info.dests_size = num_dest; + fte_info.val = val; + fte_info.dest_arr = dest; + fte_info.ignore_flow_level = ignore_flow_level; + fte_info.flow_context.flow_source = flow_source; + + ret = mlx5dr_cmd_set_fte(dmn->mdev, 0, 0, &ft_info, *group_id, &fte_info); + if (ret) { + mlx5dr_err(dmn, "Failed setting fte into table %d\n", ret); + goto free_flow_group; + } + + return 0; + +free_flow_group: + mlx5dr_cmd_destroy_flow_group(dmn->mdev, MLX5_FLOW_TABLE_TYPE_FDB, + *tbl_id, *group_id); +free_flow_table: + mlx5dr_cmd_destroy_flow_table(dmn->mdev, *tbl_id, + MLX5_FLOW_TABLE_TYPE_FDB); + return ret; +} + +void mlx5dr_fw_destroy_md_tbl(struct mlx5dr_domain *dmn, + u32 tbl_id, u32 group_id) +{ + mlx5dr_cmd_del_flow_table_entry(dmn->mdev, FS_FT_FDB, tbl_id); + mlx5dr_cmd_destroy_flow_group(dmn->mdev, + MLX5_FLOW_TABLE_TYPE_FDB, + tbl_id, group_id); + mlx5dr_cmd_destroy_flow_table(dmn->mdev, tbl_id, + MLX5_FLOW_TABLE_TYPE_FDB); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_icm_pool.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_icm_pool.c new file mode 100644 index 00000000000000..0b5af9f3f605b7 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_icm_pool.c @@ -0,0 +1,576 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include "dr_types.h" + +#define DR_ICM_MODIFY_HDR_ALIGN_BASE 64 +#define DR_ICM_POOL_STE_HOT_MEM_PERCENT 25 +#define DR_ICM_POOL_MODIFY_HDR_PTRN_HOT_MEM_PERCENT 50 +#define DR_ICM_POOL_MODIFY_ACTION_HOT_MEM_PERCENT 90 + +struct mlx5dr_icm_hot_chunk { + struct mlx5dr_icm_buddy_mem *buddy_mem; + unsigned int seg; + enum mlx5dr_icm_chunk_size size; +}; + +struct mlx5dr_icm_pool { + enum mlx5dr_icm_type icm_type; + enum mlx5dr_icm_chunk_size max_log_chunk_sz; + struct mlx5dr_domain *dmn; + struct kmem_cache *chunks_kmem_cache; + + /* memory management */ + struct mutex mutex; /* protect the ICM pool and ICM buddy */ + struct list_head buddy_mem_list; + + /* Hardware may be accessing this memory but at some future, + * undetermined time, it might cease to do so. + * sync_ste command sets them free. + */ + struct mlx5dr_icm_hot_chunk *hot_chunks_arr; + u32 hot_chunks_num; + u64 hot_memory_size; + /* hot memory size threshold for triggering sync */ + u64 th; +}; + +struct mlx5dr_icm_dm { + u32 obj_id; + enum mlx5_sw_icm_type type; + phys_addr_t addr; + size_t length; +}; + +struct mlx5dr_icm_mr { + u32 mkey; + struct mlx5dr_icm_dm dm; + struct mlx5dr_domain *dmn; + size_t length; + u64 icm_start_addr; +}; + +static int dr_icm_create_dm_mkey(struct mlx5_core_dev *mdev, + u32 pd, u64 length, u64 start_addr, int mode, + u32 *mkey) +{ + u32 inlen = MLX5_ST_SZ_BYTES(create_mkey_in); + u32 in[MLX5_ST_SZ_DW(create_mkey_in)] = {}; + void *mkc; + + mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); + + MLX5_SET(mkc, mkc, access_mode_1_0, mode); + MLX5_SET(mkc, mkc, access_mode_4_2, (mode >> 2) & 0x7); + MLX5_SET(mkc, mkc, lw, 1); + MLX5_SET(mkc, mkc, lr, 1); + if (mode == MLX5_MKC_ACCESS_MODE_SW_ICM) { + MLX5_SET(mkc, mkc, rw, 1); + MLX5_SET(mkc, mkc, rr, 1); + } + + MLX5_SET64(mkc, mkc, len, length); + MLX5_SET(mkc, mkc, pd, pd); + MLX5_SET(mkc, mkc, qpn, 0xffffff); + MLX5_SET64(mkc, mkc, start_addr, start_addr); + + return mlx5_core_create_mkey(mdev, mkey, in, inlen); +} + +u64 mlx5dr_icm_pool_get_chunk_mr_addr(struct mlx5dr_icm_chunk *chunk) +{ + u32 offset = mlx5dr_icm_pool_dm_type_to_entry_size(chunk->buddy_mem->pool->icm_type); + + return (u64)offset * chunk->seg; +} + +u32 mlx5dr_icm_pool_get_chunk_rkey(struct mlx5dr_icm_chunk *chunk) +{ + return chunk->buddy_mem->icm_mr->mkey; +} + +u64 mlx5dr_icm_pool_get_chunk_icm_addr(struct mlx5dr_icm_chunk *chunk) +{ + u32 size = mlx5dr_icm_pool_dm_type_to_entry_size(chunk->buddy_mem->pool->icm_type); + + return (u64)chunk->buddy_mem->icm_mr->icm_start_addr + size * chunk->seg; +} + +u32 mlx5dr_icm_pool_get_chunk_byte_size(struct mlx5dr_icm_chunk *chunk) +{ + return mlx5dr_icm_pool_chunk_size_to_byte(chunk->size, + chunk->buddy_mem->pool->icm_type); +} + +u32 mlx5dr_icm_pool_get_chunk_num_of_entries(struct mlx5dr_icm_chunk *chunk) +{ + return mlx5dr_icm_pool_chunk_size_to_entries(chunk->size); +} + +static struct mlx5dr_icm_mr * +dr_icm_pool_mr_create(struct mlx5dr_icm_pool *pool) +{ + struct mlx5_core_dev *mdev = pool->dmn->mdev; + enum mlx5_sw_icm_type dm_type = 0; + struct mlx5dr_icm_mr *icm_mr; + size_t log_align_base = 0; + int err; + + icm_mr = kvzalloc(sizeof(*icm_mr), GFP_KERNEL); + if (!icm_mr) + return NULL; + + icm_mr->dmn = pool->dmn; + + icm_mr->dm.length = mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz, + pool->icm_type); + + switch (pool->icm_type) { + case DR_ICM_TYPE_STE: + dm_type = MLX5_SW_ICM_TYPE_STEERING; + log_align_base = ilog2(icm_mr->dm.length); + break; + case DR_ICM_TYPE_MODIFY_ACTION: + dm_type = MLX5_SW_ICM_TYPE_HEADER_MODIFY; + /* Align base is 64B */ + log_align_base = ilog2(DR_ICM_MODIFY_HDR_ALIGN_BASE); + break; + case DR_ICM_TYPE_MODIFY_HDR_PTRN: + dm_type = MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN; + /* Align base is 64B */ + log_align_base = ilog2(DR_ICM_MODIFY_HDR_ALIGN_BASE); + break; + default: + WARN_ON(pool->icm_type); + } + + icm_mr->dm.type = dm_type; + + err = mlx5_dm_sw_icm_alloc(mdev, icm_mr->dm.type, icm_mr->dm.length, + log_align_base, 0, &icm_mr->dm.addr, + &icm_mr->dm.obj_id); + if (err) { + mlx5dr_err(pool->dmn, "Failed to allocate SW ICM memory, err (%d)\n", err); + goto free_icm_mr; + } + + /* Register device memory */ + err = dr_icm_create_dm_mkey(mdev, pool->dmn->pdn, + icm_mr->dm.length, + icm_mr->dm.addr, + MLX5_MKC_ACCESS_MODE_SW_ICM, + &icm_mr->mkey); + if (err) { + mlx5dr_err(pool->dmn, "Failed to create SW ICM MKEY, err (%d)\n", err); + goto free_dm; + } + + icm_mr->icm_start_addr = icm_mr->dm.addr; + + if (icm_mr->icm_start_addr & (BIT(log_align_base) - 1)) { + mlx5dr_err(pool->dmn, "Failed to get Aligned ICM mem (asked: %zu)\n", + log_align_base); + goto free_mkey; + } + + return icm_mr; + +free_mkey: + mlx5_core_destroy_mkey(mdev, icm_mr->mkey); +free_dm: + mlx5_dm_sw_icm_dealloc(mdev, icm_mr->dm.type, icm_mr->dm.length, 0, + icm_mr->dm.addr, icm_mr->dm.obj_id); +free_icm_mr: + kvfree(icm_mr); + return NULL; +} + +static void dr_icm_pool_mr_destroy(struct mlx5dr_icm_mr *icm_mr) +{ + struct mlx5_core_dev *mdev = icm_mr->dmn->mdev; + struct mlx5dr_icm_dm *dm = &icm_mr->dm; + + mlx5_core_destroy_mkey(mdev, icm_mr->mkey); + mlx5_dm_sw_icm_dealloc(mdev, dm->type, dm->length, 0, + dm->addr, dm->obj_id); + kvfree(icm_mr); +} + +static int dr_icm_buddy_get_ste_size(struct mlx5dr_icm_buddy_mem *buddy) +{ + /* We support only one type of STE size, both for ConnectX-5 and later + * devices. Once the support for match STE which has a larger tag is + * added (32B instead of 16B), the STE size for devices later than + * ConnectX-5 needs to account for that. + */ + return DR_STE_SIZE_REDUCED; +} + +static void dr_icm_chunk_ste_init(struct mlx5dr_icm_chunk *chunk, int offset) +{ + int num_of_entries = mlx5dr_icm_pool_get_chunk_num_of_entries(chunk); + struct mlx5dr_icm_buddy_mem *buddy = chunk->buddy_mem; + int ste_size = dr_icm_buddy_get_ste_size(buddy); + int index = offset / DR_STE_SIZE; + + chunk->ste_arr = &buddy->ste_arr[index]; + chunk->miss_list = &buddy->miss_list[index]; + chunk->hw_ste_arr = buddy->hw_ste_arr + index * ste_size; + + memset(chunk->hw_ste_arr, 0, num_of_entries * ste_size); + memset(chunk->ste_arr, 0, + num_of_entries * sizeof(chunk->ste_arr[0])); +} + +static int dr_icm_buddy_init_ste_cache(struct mlx5dr_icm_buddy_mem *buddy) +{ + int num_of_entries = + mlx5dr_icm_pool_chunk_size_to_entries(buddy->pool->max_log_chunk_sz); + + buddy->ste_arr = kvcalloc(num_of_entries, + sizeof(struct mlx5dr_ste), GFP_KERNEL); + if (!buddy->ste_arr) + return -ENOMEM; + + /* Preallocate full STE size on non-ConnectX-5 devices since + * we need to support both full and reduced with the same cache. + */ + buddy->hw_ste_arr = kvcalloc(num_of_entries, + dr_icm_buddy_get_ste_size(buddy), GFP_KERNEL); + if (!buddy->hw_ste_arr) + goto free_ste_arr; + + buddy->miss_list = kvmalloc(num_of_entries * sizeof(struct list_head), GFP_KERNEL); + if (!buddy->miss_list) + goto free_hw_ste_arr; + + return 0; + +free_hw_ste_arr: + kvfree(buddy->hw_ste_arr); +free_ste_arr: + kvfree(buddy->ste_arr); + return -ENOMEM; +} + +static void dr_icm_buddy_cleanup_ste_cache(struct mlx5dr_icm_buddy_mem *buddy) +{ + kvfree(buddy->ste_arr); + kvfree(buddy->hw_ste_arr); + kvfree(buddy->miss_list); +} + +static int dr_icm_buddy_create(struct mlx5dr_icm_pool *pool) +{ + struct mlx5dr_icm_buddy_mem *buddy; + struct mlx5dr_icm_mr *icm_mr; + + icm_mr = dr_icm_pool_mr_create(pool); + if (!icm_mr) + return -ENOMEM; + + buddy = kvzalloc(sizeof(*buddy), GFP_KERNEL); + if (!buddy) + goto free_mr; + + if (mlx5dr_buddy_init(buddy, pool->max_log_chunk_sz)) + goto err_free_buddy; + + buddy->icm_mr = icm_mr; + buddy->pool = pool; + + if (pool->icm_type == DR_ICM_TYPE_STE) { + /* Reduce allocations by preallocating and reusing the STE structures */ + if (dr_icm_buddy_init_ste_cache(buddy)) + goto err_cleanup_buddy; + } + + /* add it to the -start- of the list in order to search in it first */ + list_add(&buddy->list_node, &pool->buddy_mem_list); + + pool->dmn->num_buddies[pool->icm_type]++; + + return 0; + +err_cleanup_buddy: + mlx5dr_buddy_cleanup(buddy); +err_free_buddy: + kvfree(buddy); +free_mr: + dr_icm_pool_mr_destroy(icm_mr); + return -ENOMEM; +} + +static void dr_icm_buddy_destroy(struct mlx5dr_icm_buddy_mem *buddy) +{ + enum mlx5dr_icm_type icm_type = buddy->pool->icm_type; + + dr_icm_pool_mr_destroy(buddy->icm_mr); + + mlx5dr_buddy_cleanup(buddy); + + if (icm_type == DR_ICM_TYPE_STE) + dr_icm_buddy_cleanup_ste_cache(buddy); + + buddy->pool->dmn->num_buddies[icm_type]--; + + kvfree(buddy); +} + +static void +dr_icm_chunk_init(struct mlx5dr_icm_chunk *chunk, + struct mlx5dr_icm_pool *pool, + enum mlx5dr_icm_chunk_size chunk_size, + struct mlx5dr_icm_buddy_mem *buddy_mem_pool, + unsigned int seg) +{ + int offset; + + chunk->seg = seg; + chunk->size = chunk_size; + chunk->buddy_mem = buddy_mem_pool; + + if (pool->icm_type == DR_ICM_TYPE_STE) { + offset = mlx5dr_icm_pool_dm_type_to_entry_size(pool->icm_type) * seg; + dr_icm_chunk_ste_init(chunk, offset); + } + + buddy_mem_pool->used_memory += mlx5dr_icm_pool_get_chunk_byte_size(chunk); +} + +static bool dr_icm_pool_is_sync_required(struct mlx5dr_icm_pool *pool) +{ + return pool->hot_memory_size > pool->th; +} + +static void dr_icm_pool_clear_hot_chunks_arr(struct mlx5dr_icm_pool *pool) +{ + struct mlx5dr_icm_hot_chunk *hot_chunk; + u32 i, num_entries; + + for (i = 0; i < pool->hot_chunks_num; i++) { + hot_chunk = &pool->hot_chunks_arr[i]; + num_entries = mlx5dr_icm_pool_chunk_size_to_entries(hot_chunk->size); + mlx5dr_buddy_free_mem(hot_chunk->buddy_mem, + hot_chunk->seg, ilog2(num_entries)); + hot_chunk->buddy_mem->used_memory -= + mlx5dr_icm_pool_chunk_size_to_byte(hot_chunk->size, + pool->icm_type); + } + + pool->hot_chunks_num = 0; + pool->hot_memory_size = 0; +} + +static int dr_icm_pool_sync_all_buddy_pools(struct mlx5dr_icm_pool *pool) +{ + struct mlx5dr_icm_buddy_mem *buddy, *tmp_buddy; + int err; + + err = mlx5dr_cmd_sync_steering(pool->dmn->mdev); + if (err) { + mlx5dr_err(pool->dmn, "Failed to sync to HW (err: %d)\n", err); + return err; + } + + dr_icm_pool_clear_hot_chunks_arr(pool); + + list_for_each_entry_safe(buddy, tmp_buddy, &pool->buddy_mem_list, list_node) { + if (!buddy->used_memory && pool->icm_type == DR_ICM_TYPE_STE) + dr_icm_buddy_destroy(buddy); + } + + return 0; +} + +static int dr_icm_handle_buddies_get_mem(struct mlx5dr_icm_pool *pool, + enum mlx5dr_icm_chunk_size chunk_size, + struct mlx5dr_icm_buddy_mem **buddy, + unsigned int *seg) +{ + struct mlx5dr_icm_buddy_mem *buddy_mem_pool; + bool new_mem = false; + int err; + +alloc_buddy_mem: + /* find the next free place from the buddy list */ + list_for_each_entry(buddy_mem_pool, &pool->buddy_mem_list, list_node) { + err = mlx5dr_buddy_alloc_mem(buddy_mem_pool, + chunk_size, seg); + if (!err) + goto found; + + if (WARN_ON(new_mem)) { + /* We have new memory pool, first in the list */ + mlx5dr_err(pool->dmn, + "No memory for order: %d\n", + chunk_size); + goto out; + } + } + + /* no more available allocators in that pool, create new */ + err = dr_icm_buddy_create(pool); + if (err) { + mlx5dr_err(pool->dmn, + "Failed creating buddy for order %d\n", + chunk_size); + goto out; + } + + /* mark we have new memory, first in list */ + new_mem = true; + goto alloc_buddy_mem; + +found: + *buddy = buddy_mem_pool; +out: + return err; +} + +/* Allocate an ICM chunk, each chunk holds a piece of ICM memory and + * also memory used for HW STE management for optimizations. + */ +struct mlx5dr_icm_chunk * +mlx5dr_icm_alloc_chunk(struct mlx5dr_icm_pool *pool, + enum mlx5dr_icm_chunk_size chunk_size) +{ + struct mlx5dr_icm_chunk *chunk = NULL; + struct mlx5dr_icm_buddy_mem *buddy; + unsigned int seg; + int ret; + + if (chunk_size > pool->max_log_chunk_sz) + return NULL; + + mutex_lock(&pool->mutex); + /* find mem, get back the relevant buddy pool and seg in that mem */ + ret = dr_icm_handle_buddies_get_mem(pool, chunk_size, &buddy, &seg); + if (ret) + goto out; + + chunk = kmem_cache_alloc(pool->chunks_kmem_cache, GFP_KERNEL); + if (!chunk) + goto out_err; + + dr_icm_chunk_init(chunk, pool, chunk_size, buddy, seg); + + goto out; + +out_err: + mlx5dr_buddy_free_mem(buddy, seg, chunk_size); +out: + mutex_unlock(&pool->mutex); + return chunk; +} + +void mlx5dr_icm_free_chunk(struct mlx5dr_icm_chunk *chunk) +{ + struct mlx5dr_icm_buddy_mem *buddy = chunk->buddy_mem; + struct mlx5dr_icm_pool *pool = buddy->pool; + struct mlx5dr_icm_hot_chunk *hot_chunk; + struct kmem_cache *chunks_cache; + + chunks_cache = pool->chunks_kmem_cache; + + /* move the chunk to the waiting chunks array, AKA "hot" memory */ + mutex_lock(&pool->mutex); + + pool->hot_memory_size += mlx5dr_icm_pool_get_chunk_byte_size(chunk); + + hot_chunk = &pool->hot_chunks_arr[pool->hot_chunks_num++]; + hot_chunk->buddy_mem = chunk->buddy_mem; + hot_chunk->seg = chunk->seg; + hot_chunk->size = chunk->size; + + kmem_cache_free(chunks_cache, chunk); + + /* Check if we have chunks that are waiting for sync-ste */ + if (dr_icm_pool_is_sync_required(pool)) + dr_icm_pool_sync_all_buddy_pools(pool); + + mutex_unlock(&pool->mutex); +} + +struct mlx5dr_ste_htbl *mlx5dr_icm_pool_alloc_htbl(struct mlx5dr_icm_pool *pool) +{ + return kmem_cache_alloc(pool->dmn->htbls_kmem_cache, GFP_KERNEL); +} + +void mlx5dr_icm_pool_free_htbl(struct mlx5dr_icm_pool *pool, struct mlx5dr_ste_htbl *htbl) +{ + kmem_cache_free(pool->dmn->htbls_kmem_cache, htbl); +} + +struct mlx5dr_icm_pool *mlx5dr_icm_pool_create(struct mlx5dr_domain *dmn, + enum mlx5dr_icm_type icm_type) +{ + u32 num_of_chunks, entry_size; + struct mlx5dr_icm_pool *pool; + u32 max_hot_size = 0; + + pool = kvzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return NULL; + + pool->dmn = dmn; + pool->icm_type = icm_type; + pool->chunks_kmem_cache = dmn->chunks_kmem_cache; + + INIT_LIST_HEAD(&pool->buddy_mem_list); + mutex_init(&pool->mutex); + + switch (icm_type) { + case DR_ICM_TYPE_STE: + pool->max_log_chunk_sz = dmn->info.max_log_sw_icm_sz; + max_hot_size = mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz, + pool->icm_type) * + DR_ICM_POOL_STE_HOT_MEM_PERCENT / 100; + break; + case DR_ICM_TYPE_MODIFY_ACTION: + pool->max_log_chunk_sz = dmn->info.max_log_action_icm_sz; + max_hot_size = mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz, + pool->icm_type) * + DR_ICM_POOL_MODIFY_ACTION_HOT_MEM_PERCENT / 100; + break; + case DR_ICM_TYPE_MODIFY_HDR_PTRN: + pool->max_log_chunk_sz = dmn->info.max_log_modify_hdr_pattern_icm_sz; + max_hot_size = mlx5dr_icm_pool_chunk_size_to_byte(pool->max_log_chunk_sz, + pool->icm_type) * + DR_ICM_POOL_MODIFY_HDR_PTRN_HOT_MEM_PERCENT / 100; + break; + default: + WARN_ON(icm_type); + } + + entry_size = mlx5dr_icm_pool_dm_type_to_entry_size(pool->icm_type); + + num_of_chunks = DIV_ROUND_UP(max_hot_size, entry_size) + 1; + pool->th = max_hot_size; + + pool->hot_chunks_arr = kvcalloc(num_of_chunks, + sizeof(struct mlx5dr_icm_hot_chunk), + GFP_KERNEL); + if (!pool->hot_chunks_arr) + goto free_pool; + + return pool; + +free_pool: + kvfree(pool); + return NULL; +} + +void mlx5dr_icm_pool_destroy(struct mlx5dr_icm_pool *pool) +{ + struct mlx5dr_icm_buddy_mem *buddy, *tmp_buddy; + + dr_icm_pool_clear_hot_chunks_arr(pool); + + list_for_each_entry_safe(buddy, tmp_buddy, &pool->buddy_mem_list, list_node) + dr_icm_buddy_destroy(buddy); + + kvfree(pool->hot_chunks_arr); + mutex_destroy(&pool->mutex); + kvfree(pool); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_matcher.c new file mode 100644 index 00000000000000..0726848eb3ff25 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_matcher.c @@ -0,0 +1,1108 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include "dr_types.h" + +static bool dr_mask_is_smac_set(struct mlx5dr_match_spec *spec) +{ + return (spec->smac_47_16 || spec->smac_15_0); +} + +static bool dr_mask_is_dmac_set(struct mlx5dr_match_spec *spec) +{ + return (spec->dmac_47_16 || spec->dmac_15_0); +} + +static bool dr_mask_is_l3_base_set(struct mlx5dr_match_spec *spec) +{ + return (spec->ip_protocol || spec->frag || spec->tcp_flags || + spec->ip_ecn || spec->ip_dscp); +} + +static bool dr_mask_is_tcp_udp_base_set(struct mlx5dr_match_spec *spec) +{ + return (spec->tcp_sport || spec->tcp_dport || + spec->udp_sport || spec->udp_dport); +} + +static bool dr_mask_is_ipv4_set(struct mlx5dr_match_spec *spec) +{ + return (spec->dst_ip_31_0 || spec->src_ip_31_0); +} + +static bool dr_mask_is_ipv4_5_tuple_set(struct mlx5dr_match_spec *spec) +{ + return (dr_mask_is_l3_base_set(spec) || + dr_mask_is_tcp_udp_base_set(spec) || + dr_mask_is_ipv4_set(spec)); +} + +static bool dr_mask_is_eth_l2_tnl_set(struct mlx5dr_match_misc *misc) +{ + return misc->vxlan_vni; +} + +static bool dr_mask_is_ttl_set(struct mlx5dr_match_spec *spec) +{ + return spec->ttl_hoplimit; +} + +static bool dr_mask_is_ipv4_ihl_set(struct mlx5dr_match_spec *spec) +{ + return spec->ipv4_ihl; +} + +#define DR_MASK_IS_L2_DST(_spec, _misc, _inner_outer) (_spec.first_vid || \ + (_spec).first_cfi || (_spec).first_prio || (_spec).cvlan_tag || \ + (_spec).svlan_tag || (_spec).dmac_47_16 || (_spec).dmac_15_0 || \ + (_spec).ethertype || (_spec).ip_version || \ + (_misc)._inner_outer##_second_vid || \ + (_misc)._inner_outer##_second_cfi || \ + (_misc)._inner_outer##_second_prio || \ + (_misc)._inner_outer##_second_cvlan_tag || \ + (_misc)._inner_outer##_second_svlan_tag) + +#define DR_MASK_IS_ETH_L4_SET(_spec, _misc, _inner_outer) ( \ + dr_mask_is_l3_base_set(&(_spec)) || \ + dr_mask_is_tcp_udp_base_set(&(_spec)) || \ + dr_mask_is_ttl_set(&(_spec)) || \ + (_misc)._inner_outer##_ipv6_flow_label) + +#define DR_MASK_IS_ETH_L4_MISC_SET(_misc3, _inner_outer) ( \ + (_misc3)._inner_outer##_tcp_seq_num || \ + (_misc3)._inner_outer##_tcp_ack_num) + +#define DR_MASK_IS_FIRST_MPLS_SET(_misc2, _inner_outer) ( \ + (_misc2)._inner_outer##_first_mpls_label || \ + (_misc2)._inner_outer##_first_mpls_exp || \ + (_misc2)._inner_outer##_first_mpls_s_bos || \ + (_misc2)._inner_outer##_first_mpls_ttl) + +static bool dr_mask_is_tnl_gre_set(struct mlx5dr_match_misc *misc) +{ + return (misc->gre_key_h || misc->gre_key_l || + misc->gre_protocol || misc->gre_c_present || + misc->gre_k_present || misc->gre_s_present); +} + +#define DR_MASK_IS_OUTER_MPLS_OVER_GRE_SET(_misc) (\ + (_misc)->outer_first_mpls_over_gre_label || \ + (_misc)->outer_first_mpls_over_gre_exp || \ + (_misc)->outer_first_mpls_over_gre_s_bos || \ + (_misc)->outer_first_mpls_over_gre_ttl) + +#define DR_MASK_IS_OUTER_MPLS_OVER_UDP_SET(_misc) (\ + (_misc)->outer_first_mpls_over_udp_label || \ + (_misc)->outer_first_mpls_over_udp_exp || \ + (_misc)->outer_first_mpls_over_udp_s_bos || \ + (_misc)->outer_first_mpls_over_udp_ttl) + +static bool +dr_mask_is_vxlan_gpe_set(struct mlx5dr_match_misc3 *misc3) +{ + return (misc3->outer_vxlan_gpe_vni || + misc3->outer_vxlan_gpe_next_protocol || + misc3->outer_vxlan_gpe_flags); +} + +static bool +dr_matcher_supp_vxlan_gpe(struct mlx5dr_cmd_caps *caps) +{ + return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || + (caps->flex_protocols & MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED); +} + +static bool +dr_mask_is_tnl_vxlan_gpe(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return dr_mask_is_vxlan_gpe_set(&mask->misc3) && + dr_matcher_supp_vxlan_gpe(&dmn->info.caps); +} + +static bool dr_mask_is_tnl_geneve_set(struct mlx5dr_match_misc *misc) +{ + return misc->geneve_vni || + misc->geneve_oam || + misc->geneve_protocol_type || + misc->geneve_opt_len; +} + +static bool dr_mask_is_tnl_geneve_tlv_opt(struct mlx5dr_match_misc3 *misc3) +{ + return misc3->geneve_tlv_option_0_data; +} + +static bool +dr_matcher_supp_flex_parser_ok(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_parser_ok_bits_supp; +} + +static bool dr_mask_is_tnl_geneve_tlv_opt_exist_set(struct mlx5dr_match_misc *misc, + struct mlx5dr_domain *dmn) +{ + return dr_matcher_supp_flex_parser_ok(&dmn->info.caps) && + misc->geneve_tlv_option_0_exist; +} + +static bool +dr_matcher_supp_tnl_geneve(struct mlx5dr_cmd_caps *caps) +{ + return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || + (caps->flex_protocols & MLX5_FLEX_PARSER_GENEVE_ENABLED); +} + +static bool +dr_mask_is_tnl_geneve(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return dr_mask_is_tnl_geneve_set(&mask->misc) && + dr_matcher_supp_tnl_geneve(&dmn->info.caps); +} + +static bool dr_mask_is_tnl_gtpu_set(struct mlx5dr_match_misc3 *misc3) +{ + return misc3->gtpu_msg_flags || misc3->gtpu_msg_type || misc3->gtpu_teid; +} + +static bool dr_matcher_supp_tnl_gtpu(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_ENABLED; +} + +static bool dr_mask_is_tnl_gtpu(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return dr_mask_is_tnl_gtpu_set(&mask->misc3) && + dr_matcher_supp_tnl_gtpu(&dmn->info.caps); +} + +static int dr_matcher_supp_tnl_gtpu_dw_0(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_0_ENABLED; +} + +static bool dr_mask_is_tnl_gtpu_dw_0(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return mask->misc3.gtpu_dw_0 && + dr_matcher_supp_tnl_gtpu_dw_0(&dmn->info.caps); +} + +static int dr_matcher_supp_tnl_gtpu_teid(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_TEID_ENABLED; +} + +static bool dr_mask_is_tnl_gtpu_teid(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return mask->misc3.gtpu_teid && + dr_matcher_supp_tnl_gtpu_teid(&dmn->info.caps); +} + +static int dr_matcher_supp_tnl_gtpu_dw_2(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_2_ENABLED; +} + +static bool dr_mask_is_tnl_gtpu_dw_2(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return mask->misc3.gtpu_dw_2 && + dr_matcher_supp_tnl_gtpu_dw_2(&dmn->info.caps); +} + +static int dr_matcher_supp_tnl_gtpu_first_ext(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_FIRST_EXT_DW_0_ENABLED; +} + +static bool dr_mask_is_tnl_gtpu_first_ext(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return mask->misc3.gtpu_first_ext_dw_0 && + dr_matcher_supp_tnl_gtpu_first_ext(&dmn->info.caps); +} + +static bool dr_mask_is_tnl_gtpu_flex_parser_0(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + struct mlx5dr_cmd_caps *caps = &dmn->info.caps; + + return (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_dw_0) && + dr_mask_is_tnl_gtpu_dw_0(mask, dmn)) || + (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_teid) && + dr_mask_is_tnl_gtpu_teid(mask, dmn)) || + (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_dw_2) && + dr_mask_is_tnl_gtpu_dw_2(mask, dmn)) || + (dr_is_flex_parser_0_id(caps->flex_parser_id_gtpu_first_ext_dw_0) && + dr_mask_is_tnl_gtpu_first_ext(mask, dmn)); +} + +static bool dr_mask_is_tnl_gtpu_flex_parser_1(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + struct mlx5dr_cmd_caps *caps = &dmn->info.caps; + + return (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_dw_0) && + dr_mask_is_tnl_gtpu_dw_0(mask, dmn)) || + (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_teid) && + dr_mask_is_tnl_gtpu_teid(mask, dmn)) || + (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_dw_2) && + dr_mask_is_tnl_gtpu_dw_2(mask, dmn)) || + (dr_is_flex_parser_1_id(caps->flex_parser_id_gtpu_first_ext_dw_0) && + dr_mask_is_tnl_gtpu_first_ext(mask, dmn)); +} + +static bool dr_mask_is_tnl_gtpu_any(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return dr_mask_is_tnl_gtpu_flex_parser_0(mask, dmn) || + dr_mask_is_tnl_gtpu_flex_parser_1(mask, dmn) || + dr_mask_is_tnl_gtpu(mask, dmn); +} + +static int dr_matcher_supp_icmp_v4(struct mlx5dr_cmd_caps *caps) +{ + return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || + (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V4_ENABLED); +} + +static int dr_matcher_supp_icmp_v6(struct mlx5dr_cmd_caps *caps) +{ + return (caps->sw_format_ver >= MLX5_STEERING_FORMAT_CONNECTX_6DX) || + (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V6_ENABLED); +} + +static bool dr_mask_is_icmpv6_set(struct mlx5dr_match_misc3 *misc3) +{ + return (misc3->icmpv6_type || misc3->icmpv6_code || + misc3->icmpv6_header_data); +} + +static bool dr_mask_is_icmp(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + if (DR_MASK_IS_ICMPV4_SET(&mask->misc3)) + return dr_matcher_supp_icmp_v4(&dmn->info.caps); + else if (dr_mask_is_icmpv6_set(&mask->misc3)) + return dr_matcher_supp_icmp_v6(&dmn->info.caps); + + return false; +} + +static bool dr_mask_is_wqe_metadata_set(struct mlx5dr_match_misc2 *misc2) +{ + return misc2->metadata_reg_a; +} + +static bool dr_mask_is_reg_c_0_3_set(struct mlx5dr_match_misc2 *misc2) +{ + return (misc2->metadata_reg_c_0 || misc2->metadata_reg_c_1 || + misc2->metadata_reg_c_2 || misc2->metadata_reg_c_3); +} + +static bool dr_mask_is_reg_c_4_7_set(struct mlx5dr_match_misc2 *misc2) +{ + return (misc2->metadata_reg_c_4 || misc2->metadata_reg_c_5 || + misc2->metadata_reg_c_6 || misc2->metadata_reg_c_7); +} + +static bool dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc *misc) +{ + return (misc->source_sqn || misc->source_port); +} + +static bool dr_mask_is_flex_parser_id_0_3_set(u32 flex_parser_id, + u32 flex_parser_value) +{ + if (flex_parser_id) + return flex_parser_id <= DR_STE_MAX_FLEX_0_ID; + + /* Using flex_parser 0 means that id is zero, thus value must be set. */ + return flex_parser_value; +} + +static bool dr_mask_is_flex_parser_0_3_set(struct mlx5dr_match_misc4 *misc4) +{ + return (dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_0, + misc4->prog_sample_field_value_0) || + dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_1, + misc4->prog_sample_field_value_1) || + dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_2, + misc4->prog_sample_field_value_2) || + dr_mask_is_flex_parser_id_0_3_set(misc4->prog_sample_field_id_3, + misc4->prog_sample_field_value_3)); +} + +static bool dr_mask_is_flex_parser_id_4_7_set(u32 flex_parser_id) +{ + return flex_parser_id > DR_STE_MAX_FLEX_0_ID && + flex_parser_id <= DR_STE_MAX_FLEX_1_ID; +} + +static bool dr_mask_is_flex_parser_4_7_set(struct mlx5dr_match_misc4 *misc4) +{ + return (dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_0) || + dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_1) || + dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_2) || + dr_mask_is_flex_parser_id_4_7_set(misc4->prog_sample_field_id_3)); +} + +static int dr_matcher_supp_tnl_mpls_over_gre(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED; +} + +static bool dr_mask_is_tnl_mpls_over_gre(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return DR_MASK_IS_OUTER_MPLS_OVER_GRE_SET(&mask->misc2) && + dr_matcher_supp_tnl_mpls_over_gre(&dmn->info.caps); +} + +static int dr_matcher_supp_tnl_mpls_over_udp(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED; +} + +static bool dr_mask_is_tnl_mpls_over_udp(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return DR_MASK_IS_OUTER_MPLS_OVER_UDP_SET(&mask->misc2) && + dr_matcher_supp_tnl_mpls_over_udp(&dmn->info.caps); +} + +static bool dr_mask_is_tnl_header_0_1_set(struct mlx5dr_match_misc5 *misc5) +{ + return misc5->tunnel_header_0 || misc5->tunnel_header_1; +} + +int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv) +{ + nic_matcher->ste_builder = + nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; + nic_matcher->num_of_builders = + nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv]; + + if (!nic_matcher->num_of_builders) { + mlx5dr_dbg(matcher->tbl->dmn, + "Rule not supported on this matcher due to IP related fields\n"); + return -EINVAL; + } + + return 0; +} + +static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv) +{ + struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; + struct mlx5dr_match_param mask = {}; + bool allow_empty_match = false; + struct mlx5dr_ste_build *sb; + bool inner, rx; + int idx = 0; + int ret, i; + + sb = nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; + rx = nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX; + + /* Create a temporary mask to track and clear used mask fields */ + if (matcher->match_criteria & DR_MATCHER_CRITERIA_OUTER) + mask.outer = matcher->mask.outer; + + if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC) + mask.misc = matcher->mask.misc; + + if (matcher->match_criteria & DR_MATCHER_CRITERIA_INNER) + mask.inner = matcher->mask.inner; + + if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC2) + mask.misc2 = matcher->mask.misc2; + + if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC3) + mask.misc3 = matcher->mask.misc3; + + if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC4) + mask.misc4 = matcher->mask.misc4; + + if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC5) + mask.misc5 = matcher->mask.misc5; + + ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria, + &matcher->mask, NULL); + if (ret) + return ret; + + /* Optimize RX pipe by reducing source port match, since + * the FDB RX part is connected only to the wire. + */ + if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB && + rx && mask.misc.source_port) { + mask.misc.source_port = 0; + mask.misc.source_eswitch_owner_vhca_id = 0; + allow_empty_match = true; + } + + /* Outer */ + if (matcher->match_criteria & (DR_MATCHER_CRITERIA_OUTER | + DR_MATCHER_CRITERIA_MISC | + DR_MATCHER_CRITERIA_MISC2 | + DR_MATCHER_CRITERIA_MISC3 | + DR_MATCHER_CRITERIA_MISC5)) { + inner = false; + + if (dr_mask_is_wqe_metadata_set(&mask.misc2)) + mlx5dr_ste_build_general_purpose(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (dr_mask_is_reg_c_0_3_set(&mask.misc2)) + mlx5dr_ste_build_register_0(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (dr_mask_is_reg_c_4_7_set(&mask.misc2)) + mlx5dr_ste_build_register_1(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (dr_mask_is_gvmi_or_qpn_set(&mask.misc) && + (dmn->type == MLX5DR_DOMAIN_TYPE_FDB || + dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX)) { + mlx5dr_ste_build_src_gvmi_qpn(ste_ctx, &sb[idx++], + &mask, dmn, inner, rx); + } + + if (dr_mask_is_smac_set(&mask.outer) && + dr_mask_is_dmac_set(&mask.outer)) { + mlx5dr_ste_build_eth_l2_src_dst(ste_ctx, &sb[idx++], + &mask, inner, rx); + } + + if (dr_mask_is_smac_set(&mask.outer)) + mlx5dr_ste_build_eth_l2_src(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer)) + mlx5dr_ste_build_eth_l2_dst(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (outer_ipv == DR_RULE_IPV6) { + if (DR_MASK_IS_DST_IP_SET(&mask.outer)) + mlx5dr_ste_build_eth_l3_ipv6_dst(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (DR_MASK_IS_SRC_IP_SET(&mask.outer)) + mlx5dr_ste_build_eth_l3_ipv6_src(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (DR_MASK_IS_ETH_L4_SET(mask.outer, mask.misc, outer)) + mlx5dr_ste_build_eth_ipv6_l3_l4(ste_ctx, &sb[idx++], + &mask, inner, rx); + } else { + if (dr_mask_is_ipv4_5_tuple_set(&mask.outer)) + mlx5dr_ste_build_eth_l3_ipv4_5_tuple(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (dr_mask_is_ttl_set(&mask.outer) || + dr_mask_is_ipv4_ihl_set(&mask.outer)) + mlx5dr_ste_build_eth_l3_ipv4_misc(ste_ctx, &sb[idx++], + &mask, inner, rx); + } + + if (dr_mask_is_tnl_vxlan_gpe(&mask, dmn)) + mlx5dr_ste_build_tnl_vxlan_gpe(ste_ctx, &sb[idx++], + &mask, inner, rx); + else if (dr_mask_is_tnl_geneve(&mask, dmn)) { + mlx5dr_ste_build_tnl_geneve(ste_ctx, &sb[idx++], + &mask, inner, rx); + if (dr_mask_is_tnl_geneve_tlv_opt(&mask.misc3)) + mlx5dr_ste_build_tnl_geneve_tlv_opt(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + if (dr_mask_is_tnl_geneve_tlv_opt_exist_set(&mask.misc, dmn)) + mlx5dr_ste_build_tnl_geneve_tlv_opt_exist(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + } else if (dr_mask_is_tnl_gtpu_any(&mask, dmn)) { + if (dr_mask_is_tnl_gtpu_flex_parser_0(&mask, dmn)) + mlx5dr_ste_build_tnl_gtpu_flex_parser_0(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + + if (dr_mask_is_tnl_gtpu_flex_parser_1(&mask, dmn)) + mlx5dr_ste_build_tnl_gtpu_flex_parser_1(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + + if (dr_mask_is_tnl_gtpu(&mask, dmn)) + mlx5dr_ste_build_tnl_gtpu(ste_ctx, &sb[idx++], + &mask, inner, rx); + } else if (dr_mask_is_tnl_header_0_1_set(&mask.misc5)) { + mlx5dr_ste_build_tnl_header_0_1(ste_ctx, &sb[idx++], + &mask, inner, rx); + } + + if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer)) + mlx5dr_ste_build_eth_l4_misc(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, outer)) + mlx5dr_ste_build_mpls(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (dr_mask_is_tnl_mpls_over_gre(&mask, dmn)) + mlx5dr_ste_build_tnl_mpls_over_gre(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + else if (dr_mask_is_tnl_mpls_over_udp(&mask, dmn)) + mlx5dr_ste_build_tnl_mpls_over_udp(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + + if (dr_mask_is_icmp(&mask, dmn)) + mlx5dr_ste_build_icmp(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + + if (dr_mask_is_tnl_gre_set(&mask.misc)) + mlx5dr_ste_build_tnl_gre(ste_ctx, &sb[idx++], + &mask, inner, rx); + } + + /* Inner */ + if (matcher->match_criteria & (DR_MATCHER_CRITERIA_INNER | + DR_MATCHER_CRITERIA_MISC | + DR_MATCHER_CRITERIA_MISC2 | + DR_MATCHER_CRITERIA_MISC3)) { + inner = true; + + if (dr_mask_is_eth_l2_tnl_set(&mask.misc)) + mlx5dr_ste_build_eth_l2_tnl(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (dr_mask_is_smac_set(&mask.inner) && + dr_mask_is_dmac_set(&mask.inner)) { + mlx5dr_ste_build_eth_l2_src_dst(ste_ctx, &sb[idx++], + &mask, inner, rx); + } + + if (dr_mask_is_smac_set(&mask.inner)) + mlx5dr_ste_build_eth_l2_src(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner)) + mlx5dr_ste_build_eth_l2_dst(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (inner_ipv == DR_RULE_IPV6) { + if (DR_MASK_IS_DST_IP_SET(&mask.inner)) + mlx5dr_ste_build_eth_l3_ipv6_dst(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (DR_MASK_IS_SRC_IP_SET(&mask.inner)) + mlx5dr_ste_build_eth_l3_ipv6_src(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (DR_MASK_IS_ETH_L4_SET(mask.inner, mask.misc, inner)) + mlx5dr_ste_build_eth_ipv6_l3_l4(ste_ctx, &sb[idx++], + &mask, inner, rx); + } else { + if (dr_mask_is_ipv4_5_tuple_set(&mask.inner)) + mlx5dr_ste_build_eth_l3_ipv4_5_tuple(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (dr_mask_is_ttl_set(&mask.inner) || + dr_mask_is_ipv4_ihl_set(&mask.inner)) + mlx5dr_ste_build_eth_l3_ipv4_misc(ste_ctx, &sb[idx++], + &mask, inner, rx); + } + + if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, inner)) + mlx5dr_ste_build_eth_l4_misc(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, inner)) + mlx5dr_ste_build_mpls(ste_ctx, &sb[idx++], + &mask, inner, rx); + + if (dr_mask_is_tnl_mpls_over_gre(&mask, dmn)) + mlx5dr_ste_build_tnl_mpls_over_gre(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + else if (dr_mask_is_tnl_mpls_over_udp(&mask, dmn)) + mlx5dr_ste_build_tnl_mpls_over_udp(ste_ctx, &sb[idx++], + &mask, &dmn->info.caps, + inner, rx); + } + + if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC4) { + if (dr_mask_is_flex_parser_0_3_set(&mask.misc4)) + mlx5dr_ste_build_flex_parser_0(ste_ctx, &sb[idx++], + &mask, false, rx); + + if (dr_mask_is_flex_parser_4_7_set(&mask.misc4)) + mlx5dr_ste_build_flex_parser_1(ste_ctx, &sb[idx++], + &mask, false, rx); + } + + /* Empty matcher, takes all */ + if ((!idx && allow_empty_match) || + matcher->match_criteria == DR_MATCHER_CRITERIA_EMPTY) + mlx5dr_ste_build_empty_always_hit(&sb[idx++], rx); + + if (idx == 0) { + mlx5dr_err(dmn, "Cannot generate any valid rules from mask\n"); + return -EINVAL; + } + + /* Check that all mask fields were consumed */ + for (i = 0; i < sizeof(struct mlx5dr_match_param); i++) { + if (((u8 *)&mask)[i] != 0) { + mlx5dr_dbg(dmn, "Mask contains unsupported parameters\n"); + return -EOPNOTSUPP; + } + } + + nic_matcher->ste_builder = sb; + nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv] = idx; + + return 0; +} + +static int dr_nic_matcher_connect(struct mlx5dr_domain *dmn, + struct mlx5dr_matcher_rx_tx *curr_nic_matcher, + struct mlx5dr_matcher_rx_tx *next_nic_matcher, + struct mlx5dr_matcher_rx_tx *prev_nic_matcher) +{ + struct mlx5dr_table_rx_tx *nic_tbl = curr_nic_matcher->nic_tbl; + struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; + struct mlx5dr_htbl_connect_info info; + struct mlx5dr_ste_htbl *prev_htbl; + int ret; + + /* Connect end anchor hash table to next_htbl or to the default address */ + if (next_nic_matcher) { + info.type = CONNECT_HIT; + info.hit_next_htbl = next_nic_matcher->s_htbl; + } else { + info.type = CONNECT_MISS; + info.miss_icm_addr = nic_tbl->default_icm_addr; + } + ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, + curr_nic_matcher->e_anchor, + &info, info.type == CONNECT_HIT); + if (ret) + return ret; + + /* Connect start hash table to end anchor */ + info.type = CONNECT_MISS; + info.miss_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(curr_nic_matcher->e_anchor->chunk); + ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, + curr_nic_matcher->s_htbl, + &info, false); + if (ret) + return ret; + + /* Connect previous hash table to matcher start hash table */ + if (prev_nic_matcher) + prev_htbl = prev_nic_matcher->e_anchor; + else + prev_htbl = nic_tbl->s_anchor; + + info.type = CONNECT_HIT; + info.hit_next_htbl = curr_nic_matcher->s_htbl; + ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_htbl, + &info, true); + if (ret) + return ret; + + /* Update the pointing ste and next hash table */ + curr_nic_matcher->s_htbl->pointing_ste = prev_htbl->chunk->ste_arr; + prev_htbl->chunk->ste_arr[0].next_htbl = curr_nic_matcher->s_htbl; + + if (next_nic_matcher) { + next_nic_matcher->s_htbl->pointing_ste = + curr_nic_matcher->e_anchor->chunk->ste_arr; + curr_nic_matcher->e_anchor->chunk->ste_arr[0].next_htbl = + next_nic_matcher->s_htbl; + } + + return 0; +} + +int mlx5dr_matcher_add_to_tbl_nic(struct mlx5dr_domain *dmn, + struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + struct mlx5dr_matcher_rx_tx *next_nic_matcher, *prev_nic_matcher, *tmp_nic_matcher; + struct mlx5dr_table_rx_tx *nic_tbl = nic_matcher->nic_tbl; + bool first = true; + int ret; + + /* If the nic matcher is already on its parent nic table list, + * then it is already connected to the chain of nic matchers. + */ + if (!list_empty(&nic_matcher->list_node)) + return 0; + + next_nic_matcher = NULL; + list_for_each_entry(tmp_nic_matcher, &nic_tbl->nic_matcher_list, list_node) { + if (tmp_nic_matcher->prio >= nic_matcher->prio) { + next_nic_matcher = tmp_nic_matcher; + break; + } + first = false; + } + + prev_nic_matcher = NULL; + if (next_nic_matcher && !first) + prev_nic_matcher = list_prev_entry(next_nic_matcher, list_node); + else if (!first) + prev_nic_matcher = list_last_entry(&nic_tbl->nic_matcher_list, + struct mlx5dr_matcher_rx_tx, + list_node); + + ret = dr_nic_matcher_connect(dmn, nic_matcher, + next_nic_matcher, prev_nic_matcher); + if (ret) + return ret; + + if (prev_nic_matcher) + list_add(&nic_matcher->list_node, &prev_nic_matcher->list_node); + else if (next_nic_matcher) + list_add_tail(&nic_matcher->list_node, &next_nic_matcher->list_node); + else + list_add(&nic_matcher->list_node, &nic_matcher->nic_tbl->nic_matcher_list); + + return ret; +} + +static void dr_matcher_uninit_nic(struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + mlx5dr_htbl_put(nic_matcher->s_htbl); + mlx5dr_htbl_put(nic_matcher->e_anchor); +} + +static void dr_matcher_uninit_fdb(struct mlx5dr_matcher *matcher) +{ + dr_matcher_uninit_nic(&matcher->rx); + dr_matcher_uninit_nic(&matcher->tx); +} + +static void dr_matcher_uninit(struct mlx5dr_matcher *matcher) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + + switch (dmn->type) { + case MLX5DR_DOMAIN_TYPE_NIC_RX: + dr_matcher_uninit_nic(&matcher->rx); + break; + case MLX5DR_DOMAIN_TYPE_NIC_TX: + dr_matcher_uninit_nic(&matcher->tx); + break; + case MLX5DR_DOMAIN_TYPE_FDB: + dr_matcher_uninit_fdb(matcher); + break; + default: + WARN_ON(true); + break; + } +} + +static int dr_matcher_set_all_ste_builders(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV4); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV6); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV4); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV6); + + if (!nic_matcher->ste_builder) { + mlx5dr_err(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n"); + return -EINVAL; + } + + return 0; +} + +static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + int ret; + + nic_matcher->prio = matcher->prio; + INIT_LIST_HEAD(&nic_matcher->list_node); + + ret = dr_matcher_set_all_ste_builders(matcher, nic_matcher); + if (ret) + return ret; + + nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, + DR_CHUNK_SIZE_1, + MLX5DR_STE_LU_TYPE_DONT_CARE, + 0); + if (!nic_matcher->e_anchor) + return -ENOMEM; + + nic_matcher->s_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, + DR_CHUNK_SIZE_1, + nic_matcher->ste_builder[0].lu_type, + nic_matcher->ste_builder[0].byte_mask); + if (!nic_matcher->s_htbl) { + ret = -ENOMEM; + goto free_e_htbl; + } + + /* make sure the tables exist while empty */ + mlx5dr_htbl_get(nic_matcher->s_htbl); + mlx5dr_htbl_get(nic_matcher->e_anchor); + + return 0; + +free_e_htbl: + mlx5dr_ste_htbl_free(nic_matcher->e_anchor); + return ret; +} + +static int dr_matcher_init_fdb(struct mlx5dr_matcher *matcher) +{ + int ret; + + ret = dr_matcher_init_nic(matcher, &matcher->rx); + if (ret) + return ret; + + ret = dr_matcher_init_nic(matcher, &matcher->tx); + if (ret) + goto uninit_nic_rx; + + return 0; + +uninit_nic_rx: + dr_matcher_uninit_nic(&matcher->rx); + return ret; +} + +static int dr_matcher_copy_param(struct mlx5dr_matcher *matcher, + struct mlx5dr_match_parameters *mask) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_match_parameters consumed_mask; + int i, ret = 0; + + if (matcher->match_criteria >= DR_MATCHER_CRITERIA_MAX) { + mlx5dr_err(dmn, "Invalid match criteria attribute\n"); + return -EINVAL; + } + + if (mask) { + if (mask->match_sz > DR_SZ_MATCH_PARAM) { + mlx5dr_err(dmn, "Invalid match size attribute\n"); + return -EINVAL; + } + + consumed_mask.match_buf = kzalloc(mask->match_sz, GFP_KERNEL); + if (!consumed_mask.match_buf) + return -ENOMEM; + + consumed_mask.match_sz = mask->match_sz; + memcpy(consumed_mask.match_buf, mask->match_buf, mask->match_sz); + mlx5dr_ste_copy_param(matcher->match_criteria, + &matcher->mask, &consumed_mask, true); + + /* Check that all mask data was consumed */ + for (i = 0; i < consumed_mask.match_sz; i++) { + if (!((u8 *)consumed_mask.match_buf)[i]) + continue; + + mlx5dr_dbg(dmn, + "Match param mask contains unsupported parameters\n"); + ret = -EOPNOTSUPP; + break; + } + + kfree(consumed_mask.match_buf); + } + + return ret; +} + +static int dr_matcher_init(struct mlx5dr_matcher *matcher, + struct mlx5dr_match_parameters *mask) +{ + struct mlx5dr_table *tbl = matcher->tbl; + struct mlx5dr_domain *dmn = tbl->dmn; + int ret; + + ret = dr_matcher_copy_param(matcher, mask); + if (ret) + return ret; + + switch (dmn->type) { + case MLX5DR_DOMAIN_TYPE_NIC_RX: + matcher->rx.nic_tbl = &tbl->rx; + ret = dr_matcher_init_nic(matcher, &matcher->rx); + break; + case MLX5DR_DOMAIN_TYPE_NIC_TX: + matcher->tx.nic_tbl = &tbl->tx; + ret = dr_matcher_init_nic(matcher, &matcher->tx); + break; + case MLX5DR_DOMAIN_TYPE_FDB: + matcher->rx.nic_tbl = &tbl->rx; + matcher->tx.nic_tbl = &tbl->tx; + ret = dr_matcher_init_fdb(matcher); + break; + default: + WARN_ON(true); + ret = -EINVAL; + } + + return ret; +} + +static void dr_matcher_add_to_dbg_list(struct mlx5dr_matcher *matcher) +{ + mutex_lock(&matcher->tbl->dmn->dump_info.dbg_mutex); + list_add(&matcher->list_node, &matcher->tbl->matcher_list); + mutex_unlock(&matcher->tbl->dmn->dump_info.dbg_mutex); +} + +static void dr_matcher_remove_from_dbg_list(struct mlx5dr_matcher *matcher) +{ + mutex_lock(&matcher->tbl->dmn->dump_info.dbg_mutex); + list_del(&matcher->list_node); + mutex_unlock(&matcher->tbl->dmn->dump_info.dbg_mutex); +} + +struct mlx5dr_matcher * +mlx5dr_matcher_create(struct mlx5dr_table *tbl, + u32 priority, + u8 match_criteria_enable, + struct mlx5dr_match_parameters *mask) +{ + struct mlx5dr_matcher *matcher; + int ret; + + refcount_inc(&tbl->refcount); + + matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); + if (!matcher) + goto dec_ref; + + matcher->tbl = tbl; + matcher->prio = priority; + matcher->match_criteria = match_criteria_enable; + refcount_set(&matcher->refcount, 1); + INIT_LIST_HEAD(&matcher->list_node); + INIT_LIST_HEAD(&matcher->dbg_rule_list); + + mlx5dr_domain_lock(tbl->dmn); + + ret = dr_matcher_init(matcher, mask); + if (ret) + goto free_matcher; + + dr_matcher_add_to_dbg_list(matcher); + + mlx5dr_domain_unlock(tbl->dmn); + + return matcher; + +free_matcher: + mlx5dr_domain_unlock(tbl->dmn); + kfree(matcher); +dec_ref: + refcount_dec(&tbl->refcount); + return NULL; +} + +static int dr_matcher_disconnect_nic(struct mlx5dr_domain *dmn, + struct mlx5dr_table_rx_tx *nic_tbl, + struct mlx5dr_matcher_rx_tx *next_nic_matcher, + struct mlx5dr_matcher_rx_tx *prev_nic_matcher) +{ + struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; + struct mlx5dr_htbl_connect_info info; + struct mlx5dr_ste_htbl *prev_anchor; + + if (prev_nic_matcher) + prev_anchor = prev_nic_matcher->e_anchor; + else + prev_anchor = nic_tbl->s_anchor; + + /* Connect previous anchor hash table to next matcher or to the default address */ + if (next_nic_matcher) { + info.type = CONNECT_HIT; + info.hit_next_htbl = next_nic_matcher->s_htbl; + next_nic_matcher->s_htbl->pointing_ste = prev_anchor->chunk->ste_arr; + prev_anchor->chunk->ste_arr[0].next_htbl = next_nic_matcher->s_htbl; + } else { + info.type = CONNECT_MISS; + info.miss_icm_addr = nic_tbl->default_icm_addr; + prev_anchor->chunk->ste_arr[0].next_htbl = NULL; + } + + return mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_anchor, + &info, true); +} + +int mlx5dr_matcher_remove_from_tbl_nic(struct mlx5dr_domain *dmn, + struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + struct mlx5dr_matcher_rx_tx *prev_nic_matcher, *next_nic_matcher; + struct mlx5dr_table_rx_tx *nic_tbl = nic_matcher->nic_tbl; + int ret; + + /* If the nic matcher is not on its parent nic table list, + * then it is detached - no need to disconnect it. + */ + if (list_empty(&nic_matcher->list_node)) + return 0; + + if (list_is_last(&nic_matcher->list_node, &nic_tbl->nic_matcher_list)) + next_nic_matcher = NULL; + else + next_nic_matcher = list_next_entry(nic_matcher, list_node); + + if (nic_matcher->list_node.prev == &nic_tbl->nic_matcher_list) + prev_nic_matcher = NULL; + else + prev_nic_matcher = list_prev_entry(nic_matcher, list_node); + + ret = dr_matcher_disconnect_nic(dmn, nic_tbl, next_nic_matcher, prev_nic_matcher); + if (ret) + return ret; + + list_del_init(&nic_matcher->list_node); + return 0; +} + +int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher) +{ + struct mlx5dr_table *tbl = matcher->tbl; + + if (WARN_ON_ONCE(refcount_read(&matcher->refcount) > 1)) + return -EBUSY; + + mlx5dr_domain_lock(tbl->dmn); + + dr_matcher_remove_from_dbg_list(matcher); + dr_matcher_uninit(matcher); + refcount_dec(&matcher->tbl->refcount); + + mlx5dr_domain_unlock(tbl->dmn); + kfree(matcher); + + return 0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ptrn.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ptrn.c new file mode 100644 index 00000000000000..8ca534ef5d0316 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ptrn.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +#include "dr_types.h" +#include "mlx5_ifc_dr_ste_v1.h" + +enum dr_ptrn_modify_hdr_action_id { + DR_PTRN_MODIFY_HDR_ACTION_ID_NOP = 0x00, + DR_PTRN_MODIFY_HDR_ACTION_ID_COPY = 0x05, + DR_PTRN_MODIFY_HDR_ACTION_ID_SET = 0x06, + DR_PTRN_MODIFY_HDR_ACTION_ID_ADD = 0x07, + DR_PTRN_MODIFY_HDR_ACTION_ID_INSERT_INLINE = 0x0a, +}; + +struct mlx5dr_ptrn_mgr { + struct mlx5dr_domain *dmn; + struct mlx5dr_icm_pool *ptrn_icm_pool; + /* cache for modify_header ptrn */ + struct list_head ptrn_list; + struct mutex modify_hdr_mutex; /* protect the pattern cache */ +}; + +/* Cache structure and functions */ +static bool dr_ptrn_compare_modify_hdr(size_t cur_num_of_actions, + __be64 cur_hw_actions[], + size_t num_of_actions, + __be64 hw_actions[]) +{ + int i; + + if (cur_num_of_actions != num_of_actions) + return false; + + for (i = 0; i < num_of_actions; i++) { + u8 action_id = + MLX5_GET(ste_double_action_set_v1, &hw_actions[i], action_id); + + if (action_id == DR_PTRN_MODIFY_HDR_ACTION_ID_COPY) { + if (hw_actions[i] != cur_hw_actions[i]) + return false; + } else { + if ((__force __be32)hw_actions[i] != + (__force __be32)cur_hw_actions[i]) + return false; + } + } + + return true; +} + +static struct mlx5dr_ptrn_obj * +dr_ptrn_find_cached_pattern(struct mlx5dr_ptrn_mgr *mgr, + size_t num_of_actions, + __be64 hw_actions[]) +{ + struct mlx5dr_ptrn_obj *cached_pattern; + struct mlx5dr_ptrn_obj *tmp; + + list_for_each_entry_safe(cached_pattern, tmp, &mgr->ptrn_list, list) { + if (dr_ptrn_compare_modify_hdr(cached_pattern->num_of_actions, + (__be64 *)cached_pattern->data, + num_of_actions, + hw_actions)) { + /* Put this pattern in the head of the list, + * as we will probably use it more. + */ + list_del_init(&cached_pattern->list); + list_add(&cached_pattern->list, &mgr->ptrn_list); + return cached_pattern; + } + } + + return NULL; +} + +static struct mlx5dr_ptrn_obj * +dr_ptrn_alloc_pattern(struct mlx5dr_ptrn_mgr *mgr, + u16 num_of_actions, u8 *data) +{ + struct mlx5dr_ptrn_obj *pattern; + struct mlx5dr_icm_chunk *chunk; + u32 chunk_size; + u32 index; + + chunk_size = ilog2(roundup_pow_of_two(num_of_actions)); + /* HW modify action index granularity is at least 64B */ + chunk_size = max_t(u32, chunk_size, DR_CHUNK_SIZE_8); + + chunk = mlx5dr_icm_alloc_chunk(mgr->ptrn_icm_pool, chunk_size); + if (!chunk) + return NULL; + + index = (mlx5dr_icm_pool_get_chunk_icm_addr(chunk) - + mgr->dmn->info.caps.hdr_modify_pattern_icm_addr) / + DR_ACTION_CACHE_LINE_SIZE; + + pattern = kzalloc(sizeof(*pattern), GFP_KERNEL); + if (!pattern) + goto free_chunk; + + pattern->data = kzalloc(num_of_actions * DR_MODIFY_ACTION_SIZE * + sizeof(*pattern->data), GFP_KERNEL); + if (!pattern->data) + goto free_pattern; + + memcpy(pattern->data, data, num_of_actions * DR_MODIFY_ACTION_SIZE); + pattern->chunk = chunk; + pattern->index = index; + pattern->num_of_actions = num_of_actions; + + list_add(&pattern->list, &mgr->ptrn_list); + refcount_set(&pattern->refcount, 1); + + return pattern; + +free_pattern: + kfree(pattern); +free_chunk: + mlx5dr_icm_free_chunk(chunk); + return NULL; +} + +static void +dr_ptrn_free_pattern(struct mlx5dr_ptrn_obj *pattern) +{ + list_del(&pattern->list); + mlx5dr_icm_free_chunk(pattern->chunk); + kfree(pattern->data); + kfree(pattern); +} + +struct mlx5dr_ptrn_obj * +mlx5dr_ptrn_cache_get_pattern(struct mlx5dr_ptrn_mgr *mgr, + u16 num_of_actions, + u8 *data) +{ + struct mlx5dr_ptrn_obj *pattern; + u64 *hw_actions; + u8 action_id; + int i; + + mutex_lock(&mgr->modify_hdr_mutex); + pattern = dr_ptrn_find_cached_pattern(mgr, + num_of_actions, + (__be64 *)data); + if (!pattern) { + /* Alloc and add new pattern to cache */ + pattern = dr_ptrn_alloc_pattern(mgr, num_of_actions, data); + if (!pattern) + goto out_unlock; + + hw_actions = (u64 *)pattern->data; + /* Here we mask the pattern data to create a valid pattern + * since we do an OR operation between the arg and pattern + */ + for (i = 0; i < num_of_actions; i++) { + action_id = MLX5_GET(ste_double_action_set_v1, &hw_actions[i], action_id); + + if (action_id == DR_PTRN_MODIFY_HDR_ACTION_ID_SET || + action_id == DR_PTRN_MODIFY_HDR_ACTION_ID_ADD || + action_id == DR_PTRN_MODIFY_HDR_ACTION_ID_INSERT_INLINE) + MLX5_SET(ste_double_action_set_v1, &hw_actions[i], inline_data, 0); + } + + if (mlx5dr_send_postsend_pattern(mgr->dmn, pattern->chunk, + num_of_actions, pattern->data)) { + refcount_dec(&pattern->refcount); + goto free_pattern; + } + } else { + refcount_inc(&pattern->refcount); + } + + mutex_unlock(&mgr->modify_hdr_mutex); + + return pattern; + +free_pattern: + dr_ptrn_free_pattern(pattern); +out_unlock: + mutex_unlock(&mgr->modify_hdr_mutex); + return NULL; +} + +void +mlx5dr_ptrn_cache_put_pattern(struct mlx5dr_ptrn_mgr *mgr, + struct mlx5dr_ptrn_obj *pattern) +{ + mutex_lock(&mgr->modify_hdr_mutex); + + if (refcount_dec_and_test(&pattern->refcount)) + dr_ptrn_free_pattern(pattern); + + mutex_unlock(&mgr->modify_hdr_mutex); +} + +struct mlx5dr_ptrn_mgr *mlx5dr_ptrn_mgr_create(struct mlx5dr_domain *dmn) +{ + struct mlx5dr_ptrn_mgr *mgr; + + if (!mlx5dr_domain_is_support_ptrn_arg(dmn)) + return NULL; + + mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); + if (!mgr) + return NULL; + + mgr->dmn = dmn; + mgr->ptrn_icm_pool = mlx5dr_icm_pool_create(dmn, DR_ICM_TYPE_MODIFY_HDR_PTRN); + if (!mgr->ptrn_icm_pool) { + mlx5dr_err(dmn, "Couldn't get modify-header-pattern memory\n"); + goto free_mgr; + } + + INIT_LIST_HEAD(&mgr->ptrn_list); + mutex_init(&mgr->modify_hdr_mutex); + + return mgr; + +free_mgr: + kfree(mgr); + return NULL; +} + +void mlx5dr_ptrn_mgr_destroy(struct mlx5dr_ptrn_mgr *mgr) +{ + struct mlx5dr_ptrn_obj *pattern; + struct mlx5dr_ptrn_obj *tmp; + + if (!mgr) + return; + + WARN_ON(!list_empty(&mgr->ptrn_list)); + + list_for_each_entry_safe(pattern, tmp, &mgr->ptrn_list, list) { + list_del(&pattern->list); + kfree(pattern->data); + kfree(pattern); + } + + 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/sws/dr_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_rule.c new file mode 100644 index 00000000000000..d1db04baa1fa6f --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_rule.c @@ -0,0 +1,1377 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include "dr_types.h" + +#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN < 2048) +/* don't try to optimize STE allocation if the stack is too constaraining */ +#define DR_RULE_MAX_STES_OPTIMIZED 0 +#else +#define DR_RULE_MAX_STES_OPTIMIZED 2 +#endif +#define DR_RULE_MAX_STE_CHAIN_OPTIMIZED (DR_RULE_MAX_STES_OPTIMIZED + DR_ACTION_MAX_STES) + +static int dr_rule_append_to_miss_list(struct mlx5dr_domain *dmn, + enum mlx5dr_domain_nic_type nic_type, + struct mlx5dr_ste *new_last_ste, + struct list_head *miss_list, + struct list_head *send_list) +{ + struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; + struct mlx5dr_ste_send_info *ste_info_last; + struct mlx5dr_ste *last_ste; + + /* The new entry will be inserted after the last */ + last_ste = list_last_entry(miss_list, struct mlx5dr_ste, miss_list_node); + WARN_ON(!last_ste); + + ste_info_last = mlx5dr_send_info_alloc(dmn, nic_type); + if (!ste_info_last) + return -ENOMEM; + + mlx5dr_ste_set_miss_addr(ste_ctx, mlx5dr_ste_get_hw_ste(last_ste), + mlx5dr_ste_get_icm_addr(new_last_ste)); + list_add_tail(&new_last_ste->miss_list_node, miss_list); + + mlx5dr_send_fill_and_append_ste_send_info(last_ste, DR_STE_SIZE_CTRL, + 0, mlx5dr_ste_get_hw_ste(last_ste), + ste_info_last, send_list, true); + + return 0; +} + +static void dr_rule_set_last_ste_miss_addr(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + u8 *hw_ste) +{ + struct mlx5dr_ste_ctx *ste_ctx = matcher->tbl->dmn->ste_ctx; + u64 icm_addr; + + if (mlx5dr_ste_is_miss_addr_set(ste_ctx, hw_ste)) + return; + + icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk); + mlx5dr_ste_set_miss_addr(ste_ctx, hw_ste, icm_addr); +} + +static struct mlx5dr_ste * +dr_rule_create_collision_htbl(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + u8 *hw_ste) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste_htbl *new_htbl; + struct mlx5dr_ste *ste; + + /* Create new table for miss entry */ + new_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, + DR_CHUNK_SIZE_1, + MLX5DR_STE_LU_TYPE_DONT_CARE, + 0); + if (!new_htbl) { + mlx5dr_dbg(dmn, "Failed allocating collision table\n"); + return NULL; + } + + /* One and only entry, never grows */ + ste = new_htbl->chunk->ste_arr; + dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste); + mlx5dr_htbl_get(new_htbl); + + return ste; +} + +static struct mlx5dr_ste * +dr_rule_create_collision_entry(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + u8 *hw_ste, + struct mlx5dr_ste *orig_ste) +{ + struct mlx5dr_ste *ste; + + ste = dr_rule_create_collision_htbl(matcher, nic_matcher, hw_ste); + if (!ste) { + mlx5dr_dbg(matcher->tbl->dmn, "Failed creating collision entry\n"); + return NULL; + } + + ste->ste_chain_location = orig_ste->ste_chain_location; + ste->htbl->pointing_ste = orig_ste->htbl->pointing_ste; + + /* In collision entry, all members share the same miss_list_head */ + ste->htbl->chunk->miss_list = mlx5dr_ste_get_miss_list(orig_ste); + + /* Next table */ + if (mlx5dr_ste_create_next_htbl(matcher, nic_matcher, ste, hw_ste, + DR_CHUNK_SIZE_1)) { + mlx5dr_dbg(matcher->tbl->dmn, "Failed allocating table\n"); + goto free_tbl; + } + + return ste; + +free_tbl: + mlx5dr_ste_free(ste, matcher, nic_matcher); + return NULL; +} + +static int +dr_rule_handle_one_ste_in_update_list(struct mlx5dr_ste_send_info *ste_info, + struct mlx5dr_domain *dmn) +{ + int ret; + + list_del(&ste_info->send_list); + + /* Copy data to ste, only reduced size or control, the last 16B (mask) + * is already written to the hw. + */ + if (ste_info->size == DR_STE_SIZE_CTRL) + memcpy(mlx5dr_ste_get_hw_ste(ste_info->ste), + ste_info->data, DR_STE_SIZE_CTRL); + else + memcpy(mlx5dr_ste_get_hw_ste(ste_info->ste), + ste_info->data, DR_STE_SIZE_REDUCED); + + ret = mlx5dr_send_postsend_ste(dmn, ste_info->ste, ste_info->data, + ste_info->size, ste_info->offset); + if (ret) + goto out; + +out: + mlx5dr_send_info_free(ste_info); + return ret; +} + +static int dr_rule_send_update_list(struct list_head *send_ste_list, + struct mlx5dr_domain *dmn, + bool is_reverse) +{ + struct mlx5dr_ste_send_info *ste_info, *tmp_ste_info; + int ret; + + if (is_reverse) { + list_for_each_entry_safe_reverse(ste_info, tmp_ste_info, + send_ste_list, send_list) { + ret = dr_rule_handle_one_ste_in_update_list(ste_info, + dmn); + if (ret) + return ret; + } + } else { + list_for_each_entry_safe(ste_info, tmp_ste_info, + send_ste_list, send_list) { + ret = dr_rule_handle_one_ste_in_update_list(ste_info, + dmn); + if (ret) + return ret; + } + } + + return 0; +} + +static struct mlx5dr_ste * +dr_rule_find_ste_in_miss_list(struct list_head *miss_list, u8 *hw_ste) +{ + struct mlx5dr_ste *ste; + + if (list_empty(miss_list)) + return NULL; + + /* Check if hw_ste is present in the list */ + list_for_each_entry(ste, miss_list, miss_list_node) { + if (mlx5dr_ste_equal_tag(mlx5dr_ste_get_hw_ste(ste), hw_ste)) + return ste; + } + + return NULL; +} + +static struct mlx5dr_ste * +dr_rule_rehash_handle_collision(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct list_head *update_list, + struct mlx5dr_ste *col_ste, + u8 *hw_ste) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste *new_ste; + int ret; + + new_ste = dr_rule_create_collision_htbl(matcher, nic_matcher, hw_ste); + if (!new_ste) + return NULL; + + /* Update collision pointing STE */ + new_ste->htbl->pointing_ste = col_ste->htbl->pointing_ste; + + /* In collision entry, all members share the same miss_list_head */ + new_ste->htbl->chunk->miss_list = mlx5dr_ste_get_miss_list(col_ste); + + /* Update the previous from the list */ + ret = dr_rule_append_to_miss_list(dmn, nic_matcher->nic_tbl->nic_dmn->type, + new_ste, mlx5dr_ste_get_miss_list(col_ste), + update_list); + if (ret) { + mlx5dr_dbg(dmn, "Failed update dup entry\n"); + goto err_exit; + } + + return new_ste; + +err_exit: + mlx5dr_ste_free(new_ste, matcher, nic_matcher); + return NULL; +} + +static void dr_rule_rehash_copy_ste_ctrl(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste *cur_ste, + struct mlx5dr_ste *new_ste) +{ + new_ste->next_htbl = cur_ste->next_htbl; + new_ste->ste_chain_location = cur_ste->ste_chain_location; + + if (new_ste->next_htbl) + new_ste->next_htbl->pointing_ste = new_ste; + + /* We need to copy the refcount since this ste + * may have been traversed several times + */ + new_ste->refcount = cur_ste->refcount; + + /* Link old STEs rule to the new ste */ + mlx5dr_rule_set_last_member(cur_ste->rule_rx_tx, new_ste, false); +} + +static struct mlx5dr_ste * +dr_rule_rehash_copy_ste(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste *cur_ste, + struct mlx5dr_ste_htbl *new_htbl, + struct list_head *update_list) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste_send_info *ste_info; + bool use_update_list = false; + u8 hw_ste[DR_STE_SIZE] = {}; + struct mlx5dr_ste *new_ste; + int new_idx; + u8 sb_idx; + + /* Copy STE mask from the matcher */ + sb_idx = cur_ste->ste_chain_location - 1; + mlx5dr_ste_set_bit_mask(hw_ste, nic_matcher->ste_builder[sb_idx].bit_mask); + + /* Copy STE control and tag */ + memcpy(hw_ste, mlx5dr_ste_get_hw_ste(cur_ste), DR_STE_SIZE_REDUCED); + dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste); + + new_idx = mlx5dr_ste_calc_hash_index(hw_ste, new_htbl); + new_ste = &new_htbl->chunk->ste_arr[new_idx]; + + if (mlx5dr_ste_is_not_used(new_ste)) { + mlx5dr_htbl_get(new_htbl); + list_add_tail(&new_ste->miss_list_node, + mlx5dr_ste_get_miss_list(new_ste)); + } else { + new_ste = dr_rule_rehash_handle_collision(matcher, + nic_matcher, + update_list, + new_ste, + hw_ste); + if (!new_ste) { + mlx5dr_dbg(dmn, "Failed adding collision entry, index: %d\n", + new_idx); + return NULL; + } + new_htbl->ctrl.num_of_collisions++; + use_update_list = true; + } + + memcpy(mlx5dr_ste_get_hw_ste(new_ste), hw_ste, DR_STE_SIZE_REDUCED); + + new_htbl->ctrl.num_of_valid_entries++; + + if (use_update_list) { + ste_info = mlx5dr_send_info_alloc(dmn, + nic_matcher->nic_tbl->nic_dmn->type); + if (!ste_info) + goto err_exit; + + mlx5dr_send_fill_and_append_ste_send_info(new_ste, DR_STE_SIZE, 0, + hw_ste, ste_info, + update_list, true); + } + + dr_rule_rehash_copy_ste_ctrl(matcher, nic_matcher, cur_ste, new_ste); + + return new_ste; + +err_exit: + mlx5dr_ste_free(new_ste, matcher, nic_matcher); + return NULL; +} + +static int dr_rule_rehash_copy_miss_list(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct list_head *cur_miss_list, + struct mlx5dr_ste_htbl *new_htbl, + struct list_head *update_list) +{ + struct mlx5dr_ste *tmp_ste, *cur_ste, *new_ste; + + if (list_empty(cur_miss_list)) + return 0; + + list_for_each_entry_safe(cur_ste, tmp_ste, cur_miss_list, miss_list_node) { + new_ste = dr_rule_rehash_copy_ste(matcher, + nic_matcher, + cur_ste, + new_htbl, + update_list); + if (!new_ste) + goto err_insert; + + list_del(&cur_ste->miss_list_node); + mlx5dr_htbl_put(cur_ste->htbl); + } + return 0; + +err_insert: + mlx5dr_err(matcher->tbl->dmn, "Fatal error during resize\n"); + WARN_ON(true); + return -EINVAL; +} + +static int dr_rule_rehash_copy_htbl(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste_htbl *cur_htbl, + struct mlx5dr_ste_htbl *new_htbl, + struct list_head *update_list) +{ + struct mlx5dr_ste *cur_ste; + int cur_entries; + int err = 0; + int i; + + cur_entries = mlx5dr_icm_pool_chunk_size_to_entries(cur_htbl->chunk->size); + + if (cur_entries < 1) { + mlx5dr_dbg(matcher->tbl->dmn, "Invalid number of entries\n"); + return -EINVAL; + } + + for (i = 0; i < cur_entries; i++) { + cur_ste = &cur_htbl->chunk->ste_arr[i]; + if (mlx5dr_ste_is_not_used(cur_ste)) /* Empty, nothing to copy */ + continue; + + err = dr_rule_rehash_copy_miss_list(matcher, + nic_matcher, + mlx5dr_ste_get_miss_list(cur_ste), + new_htbl, + update_list); + if (err) + goto clean_copy; + + /* In order to decrease the number of allocated ste_send_info + * structs, send the current table row now. + */ + err = dr_rule_send_update_list(update_list, matcher->tbl->dmn, false); + if (err) { + mlx5dr_dbg(matcher->tbl->dmn, "Failed updating table to HW\n"); + goto clean_copy; + } + } + +clean_copy: + return err; +} + +static struct mlx5dr_ste_htbl * +dr_rule_rehash_htbl(struct mlx5dr_rule *rule, + struct mlx5dr_rule_rx_tx *nic_rule, + struct mlx5dr_ste_htbl *cur_htbl, + u8 ste_location, + struct list_head *update_list, + enum mlx5dr_icm_chunk_size new_size) +{ + struct mlx5dr_ste_send_info *del_ste_info, *tmp_ste_info; + struct mlx5dr_matcher *matcher = rule->matcher; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_matcher_rx_tx *nic_matcher; + struct mlx5dr_ste_send_info *ste_info; + struct mlx5dr_htbl_connect_info info; + struct mlx5dr_domain_rx_tx *nic_dmn; + u8 formatted_ste[DR_STE_SIZE] = {}; + LIST_HEAD(rehash_table_send_list); + struct mlx5dr_ste *ste_to_update; + struct mlx5dr_ste_htbl *new_htbl; + int err; + + nic_matcher = nic_rule->nic_matcher; + nic_dmn = nic_matcher->nic_tbl->nic_dmn; + + ste_info = mlx5dr_send_info_alloc(dmn, + nic_matcher->nic_tbl->nic_dmn->type); + if (!ste_info) + return NULL; + + new_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, + new_size, + cur_htbl->lu_type, + cur_htbl->byte_mask); + if (!new_htbl) { + mlx5dr_err(dmn, "Failed to allocate new hash table\n"); + goto free_ste_info; + } + + /* Write new table to HW */ + info.type = CONNECT_MISS; + info.miss_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk); + mlx5dr_ste_set_formatted_ste(dmn->ste_ctx, + dmn->info.caps.gvmi, + nic_dmn->type, + new_htbl, + formatted_ste, + &info); + + new_htbl->pointing_ste = cur_htbl->pointing_ste; + new_htbl->pointing_ste->next_htbl = new_htbl; + err = dr_rule_rehash_copy_htbl(matcher, + nic_matcher, + cur_htbl, + new_htbl, + &rehash_table_send_list); + if (err) + goto free_new_htbl; + + if (mlx5dr_send_postsend_htbl(dmn, new_htbl, formatted_ste, + nic_matcher->ste_builder[ste_location - 1].bit_mask)) { + mlx5dr_err(dmn, "Failed writing table to HW\n"); + goto free_new_htbl; + } + + /* Writing to the hw is done in regular order of rehash_table_send_list, + * in order to have the origin data written before the miss address of + * collision entries, if exists. + */ + if (dr_rule_send_update_list(&rehash_table_send_list, dmn, false)) { + mlx5dr_err(dmn, "Failed updating table to HW\n"); + goto free_ste_list; + } + + /* Connect previous hash table to current */ + if (ste_location == 1) { + /* The previous table is an anchor, anchors size is always one STE */ + struct mlx5dr_ste_htbl *prev_htbl = cur_htbl->pointing_ste->htbl; + + /* On matcher s_anchor we keep an extra refcount */ + mlx5dr_htbl_get(new_htbl); + mlx5dr_htbl_put(cur_htbl); + + nic_matcher->s_htbl = new_htbl; + + /* It is safe to operate dr_ste_set_hit_addr on the hw_ste here + * (48B len) which works only on first 32B + */ + mlx5dr_ste_set_hit_addr(dmn->ste_ctx, + prev_htbl->chunk->hw_ste_arr, + mlx5dr_icm_pool_get_chunk_icm_addr(new_htbl->chunk), + mlx5dr_icm_pool_get_chunk_num_of_entries(new_htbl->chunk)); + + ste_to_update = &prev_htbl->chunk->ste_arr[0]; + } else { + mlx5dr_ste_set_hit_addr_by_next_htbl(dmn->ste_ctx, + mlx5dr_ste_get_hw_ste(cur_htbl->pointing_ste), + new_htbl); + ste_to_update = cur_htbl->pointing_ste; + } + + mlx5dr_send_fill_and_append_ste_send_info(ste_to_update, DR_STE_SIZE_CTRL, + 0, mlx5dr_ste_get_hw_ste(ste_to_update), + ste_info, update_list, false); + + return new_htbl; + +free_ste_list: + /* Clean all ste_info's from the new table */ + list_for_each_entry_safe(del_ste_info, tmp_ste_info, + &rehash_table_send_list, send_list) { + list_del(&del_ste_info->send_list); + mlx5dr_send_info_free(del_ste_info); + } + +free_new_htbl: + mlx5dr_ste_htbl_free(new_htbl); +free_ste_info: + mlx5dr_send_info_free(ste_info); + mlx5dr_info(dmn, "Failed creating rehash table\n"); + return NULL; +} + +static struct mlx5dr_ste_htbl *dr_rule_rehash(struct mlx5dr_rule *rule, + struct mlx5dr_rule_rx_tx *nic_rule, + struct mlx5dr_ste_htbl *cur_htbl, + u8 ste_location, + struct list_head *update_list) +{ + struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; + enum mlx5dr_icm_chunk_size new_size; + + new_size = mlx5dr_icm_next_higher_chunk(cur_htbl->chunk->size); + new_size = min_t(u32, new_size, dmn->info.max_log_sw_icm_sz); + + if (new_size == cur_htbl->chunk->size) + return NULL; /* Skip rehash, we already at the max size */ + + return dr_rule_rehash_htbl(rule, nic_rule, cur_htbl, ste_location, + update_list, new_size); +} + +static struct mlx5dr_ste * +dr_rule_handle_collision(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste *ste, + u8 *hw_ste, + struct list_head *miss_list, + struct list_head *send_list) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste_send_info *ste_info; + struct mlx5dr_ste *new_ste; + + ste_info = mlx5dr_send_info_alloc(dmn, + nic_matcher->nic_tbl->nic_dmn->type); + if (!ste_info) + return NULL; + + new_ste = dr_rule_create_collision_entry(matcher, nic_matcher, hw_ste, ste); + if (!new_ste) + goto free_send_info; + + if (dr_rule_append_to_miss_list(dmn, nic_matcher->nic_tbl->nic_dmn->type, + new_ste, miss_list, send_list)) { + mlx5dr_dbg(dmn, "Failed to update prev miss_list\n"); + goto err_exit; + } + + mlx5dr_send_fill_and_append_ste_send_info(new_ste, DR_STE_SIZE, 0, hw_ste, + ste_info, send_list, false); + + ste->htbl->ctrl.num_of_collisions++; + ste->htbl->ctrl.num_of_valid_entries++; + + return new_ste; + +err_exit: + mlx5dr_ste_free(new_ste, matcher, nic_matcher); +free_send_info: + mlx5dr_send_info_free(ste_info); + return NULL; +} + +static void dr_rule_remove_action_members(struct mlx5dr_rule *rule) +{ + struct mlx5dr_rule_action_member *action_mem; + struct mlx5dr_rule_action_member *tmp; + + list_for_each_entry_safe(action_mem, tmp, &rule->rule_actions_list, list) { + list_del(&action_mem->list); + refcount_dec(&action_mem->action->refcount); + kvfree(action_mem); + } +} + +static int dr_rule_add_action_members(struct mlx5dr_rule *rule, + size_t num_actions, + struct mlx5dr_action *actions[]) +{ + struct mlx5dr_rule_action_member *action_mem; + int i; + + for (i = 0; i < num_actions; i++) { + action_mem = kvzalloc(sizeof(*action_mem), GFP_KERNEL); + if (!action_mem) + goto free_action_members; + + action_mem->action = actions[i]; + INIT_LIST_HEAD(&action_mem->list); + list_add_tail(&action_mem->list, &rule->rule_actions_list); + refcount_inc(&action_mem->action->refcount); + } + + return 0; + +free_action_members: + dr_rule_remove_action_members(rule); + return -ENOMEM; +} + +void mlx5dr_rule_set_last_member(struct mlx5dr_rule_rx_tx *nic_rule, + struct mlx5dr_ste *ste, + bool force) +{ + /* Update rule member is usually done for the last STE or during rule + * creation to recover from mid-creation failure (for this peruse the + * force flag is used) + */ + if (ste->next_htbl && !force) + return; + + /* Update is required since each rule keeps track of its last STE */ + ste->rule_rx_tx = nic_rule; + nic_rule->last_rule_ste = ste; +} + +static struct mlx5dr_ste *dr_rule_get_pointed_ste(struct mlx5dr_ste *curr_ste) +{ + struct mlx5dr_ste *first_ste; + + first_ste = list_first_entry(mlx5dr_ste_get_miss_list(curr_ste), + struct mlx5dr_ste, miss_list_node); + + return first_ste->htbl->pointing_ste; +} + +int mlx5dr_rule_get_reverse_rule_members(struct mlx5dr_ste **ste_arr, + struct mlx5dr_ste *curr_ste, + int *num_of_stes) +{ + bool first = false; + + *num_of_stes = 0; + + if (!curr_ste) + return -ENOENT; + + /* Iterate from last to first */ + while (!first) { + first = curr_ste->ste_chain_location == 1; + ste_arr[*num_of_stes] = curr_ste; + *num_of_stes += 1; + curr_ste = dr_rule_get_pointed_ste(curr_ste); + } + + return 0; +} + +static void dr_rule_clean_rule_members(struct mlx5dr_rule *rule, + struct mlx5dr_rule_rx_tx *nic_rule) +{ + struct mlx5dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES]; + struct mlx5dr_ste *curr_ste = nic_rule->last_rule_ste; + int i; + + if (mlx5dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i)) + return; + + while (i--) + mlx5dr_ste_put(ste_arr[i], rule->matcher, nic_rule->nic_matcher); +} + +static u16 dr_get_bits_per_mask(u16 byte_mask) +{ + u16 bits = 0; + + while (byte_mask) { + byte_mask = byte_mask & (byte_mask - 1); + bits++; + } + + return bits; +} + +static bool dr_rule_need_enlarge_hash(struct mlx5dr_ste_htbl *htbl, + struct mlx5dr_domain *dmn, + struct mlx5dr_domain_rx_tx *nic_dmn) +{ + struct mlx5dr_ste_htbl_ctrl *ctrl = &htbl->ctrl; + int threshold; + + if (dmn->info.max_log_sw_icm_sz <= htbl->chunk->size) + return false; + + if (!mlx5dr_ste_htbl_may_grow(htbl)) + return false; + + if (dr_get_bits_per_mask(htbl->byte_mask) * BITS_PER_BYTE <= htbl->chunk->size) + return false; + + threshold = mlx5dr_ste_htbl_increase_threshold(htbl); + if (ctrl->num_of_collisions >= threshold && + (ctrl->num_of_valid_entries - ctrl->num_of_collisions) >= threshold) + return true; + + return false; +} + +static int dr_rule_handle_action_stes(struct mlx5dr_rule *rule, + struct mlx5dr_rule_rx_tx *nic_rule, + struct list_head *send_ste_list, + struct mlx5dr_ste *last_ste, + u8 *hw_ste_arr, + u32 new_hw_ste_arr_sz) +{ + struct mlx5dr_matcher_rx_tx *nic_matcher = nic_rule->nic_matcher; + struct mlx5dr_ste_send_info *ste_info_arr[DR_ACTION_MAX_STES]; + u8 num_of_builders = nic_matcher->num_of_builders; + struct mlx5dr_matcher *matcher = rule->matcher; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + u8 *curr_hw_ste, *prev_hw_ste; + struct mlx5dr_ste *action_ste; + int i, k; + + /* Two cases: + * 1. num_of_builders is equal to new_hw_ste_arr_sz, the action in the ste + * 2. num_of_builders is less then new_hw_ste_arr_sz, new ste was added + * to support the action. + */ + + for (i = num_of_builders, k = 0; i < new_hw_ste_arr_sz; i++, k++) { + curr_hw_ste = hw_ste_arr + i * DR_STE_SIZE; + prev_hw_ste = (i == 0) ? curr_hw_ste : hw_ste_arr + ((i - 1) * DR_STE_SIZE); + action_ste = dr_rule_create_collision_htbl(matcher, + nic_matcher, + curr_hw_ste); + if (!action_ste) + return -ENOMEM; + + mlx5dr_ste_get(action_ste); + + action_ste->htbl->pointing_ste = last_ste; + last_ste->next_htbl = action_ste->htbl; + last_ste = action_ste; + + /* While free ste we go over the miss list, so add this ste to the list */ + list_add_tail(&action_ste->miss_list_node, + mlx5dr_ste_get_miss_list(action_ste)); + + ste_info_arr[k] = mlx5dr_send_info_alloc(dmn, + nic_matcher->nic_tbl->nic_dmn->type); + if (!ste_info_arr[k]) + goto err_exit; + + /* Point current ste to the new action */ + mlx5dr_ste_set_hit_addr_by_next_htbl(dmn->ste_ctx, + prev_hw_ste, + action_ste->htbl); + + mlx5dr_rule_set_last_member(nic_rule, action_ste, true); + + mlx5dr_send_fill_and_append_ste_send_info(action_ste, DR_STE_SIZE, 0, + curr_hw_ste, + ste_info_arr[k], + send_ste_list, false); + } + + last_ste->next_htbl = NULL; + + return 0; + +err_exit: + mlx5dr_ste_put(action_ste, matcher, nic_matcher); + return -ENOMEM; +} + +static int dr_rule_handle_empty_entry(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste_htbl *cur_htbl, + struct mlx5dr_ste *ste, + u8 ste_location, + u8 *hw_ste, + struct list_head *miss_list, + struct list_head *send_list) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste_send_info *ste_info; + + /* Take ref on table, only on first time this ste is used */ + mlx5dr_htbl_get(cur_htbl); + + /* new entry -> new branch */ + list_add_tail(&ste->miss_list_node, miss_list); + + dr_rule_set_last_ste_miss_addr(matcher, nic_matcher, hw_ste); + + ste->ste_chain_location = ste_location; + + ste_info = mlx5dr_send_info_alloc(dmn, + nic_matcher->nic_tbl->nic_dmn->type); + if (!ste_info) + goto clean_ste_setting; + + if (mlx5dr_ste_create_next_htbl(matcher, + nic_matcher, + ste, + hw_ste, + DR_CHUNK_SIZE_1)) { + mlx5dr_dbg(dmn, "Failed allocating table\n"); + goto clean_ste_info; + } + + cur_htbl->ctrl.num_of_valid_entries++; + + mlx5dr_send_fill_and_append_ste_send_info(ste, DR_STE_SIZE, 0, hw_ste, + ste_info, send_list, false); + + return 0; + +clean_ste_info: + mlx5dr_send_info_free(ste_info); +clean_ste_setting: + list_del_init(&ste->miss_list_node); + mlx5dr_htbl_put(cur_htbl); + + return -ENOMEM; +} + +static struct mlx5dr_ste * +dr_rule_handle_ste_branch(struct mlx5dr_rule *rule, + struct mlx5dr_rule_rx_tx *nic_rule, + struct list_head *send_ste_list, + struct mlx5dr_ste_htbl *cur_htbl, + u8 *hw_ste, + u8 ste_location, + struct mlx5dr_ste_htbl **put_htbl) +{ + struct mlx5dr_matcher *matcher = rule->matcher; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_matcher_rx_tx *nic_matcher; + struct mlx5dr_domain_rx_tx *nic_dmn; + struct mlx5dr_ste_htbl *new_htbl; + struct mlx5dr_ste *matched_ste; + struct list_head *miss_list; + bool skip_rehash = false; + struct mlx5dr_ste *ste; + int index; + + nic_matcher = nic_rule->nic_matcher; + nic_dmn = nic_matcher->nic_tbl->nic_dmn; + +again: + index = mlx5dr_ste_calc_hash_index(hw_ste, cur_htbl); + miss_list = &cur_htbl->chunk->miss_list[index]; + ste = &cur_htbl->chunk->ste_arr[index]; + + if (mlx5dr_ste_is_not_used(ste)) { + if (dr_rule_handle_empty_entry(matcher, nic_matcher, cur_htbl, + ste, ste_location, + hw_ste, miss_list, + send_ste_list)) + return NULL; + } else { + /* Hash table index in use, check if this ste is in the miss list */ + matched_ste = dr_rule_find_ste_in_miss_list(miss_list, hw_ste); + if (matched_ste) { + /* If it is last STE in the chain, and has the same tag + * it means that all the previous stes are the same, + * if so, this rule is duplicated. + */ + if (!mlx5dr_ste_is_last_in_rule(nic_matcher, ste_location)) + return matched_ste; + + mlx5dr_dbg(dmn, "Duplicate rule inserted\n"); + } + + if (!skip_rehash && dr_rule_need_enlarge_hash(cur_htbl, dmn, nic_dmn)) { + /* Hash table index in use, try to resize of the hash */ + skip_rehash = true; + + /* Hold the table till we update. + * Release in dr_rule_create_rule() + */ + *put_htbl = cur_htbl; + mlx5dr_htbl_get(cur_htbl); + + new_htbl = dr_rule_rehash(rule, nic_rule, cur_htbl, + ste_location, send_ste_list); + if (!new_htbl) { + mlx5dr_err(dmn, "Failed creating rehash table, htbl-log_size: %d\n", + cur_htbl->chunk->size); + mlx5dr_htbl_put(cur_htbl); + } else { + cur_htbl = new_htbl; + } + goto again; + } else { + /* Hash table index in use, add another collision (miss) */ + ste = dr_rule_handle_collision(matcher, + nic_matcher, + ste, + hw_ste, + miss_list, + send_ste_list); + if (!ste) { + mlx5dr_dbg(dmn, "failed adding collision entry, index: %d\n", + index); + return NULL; + } + } + } + return ste; +} + +static bool dr_rule_cmp_value_to_mask(u8 *mask, u8 *value, + u32 s_idx, u32 e_idx) +{ + u32 i; + + for (i = s_idx; i < e_idx; i++) { + if (value[i] & ~mask[i]) { + pr_info("Rule parameters contains a value not specified by mask\n"); + return false; + } + } + return true; +} + +static bool dr_rule_verify(struct mlx5dr_matcher *matcher, + struct mlx5dr_match_parameters *value, + struct mlx5dr_match_param *param) +{ + u8 match_criteria = matcher->match_criteria; + size_t value_size = value->match_sz; + u8 *mask_p = (u8 *)&matcher->mask; + u8 *param_p = (u8 *)param; + u32 s_idx, e_idx; + + if (!value_size || + (value_size > DR_SZ_MATCH_PARAM || (value_size % sizeof(u32)))) { + mlx5dr_err(matcher->tbl->dmn, "Rule parameters length is incorrect\n"); + return false; + } + + mlx5dr_ste_copy_param(matcher->match_criteria, param, value, false); + + if (match_criteria & DR_MATCHER_CRITERIA_OUTER) { + s_idx = offsetof(struct mlx5dr_match_param, outer); + e_idx = min(s_idx + sizeof(param->outer), value_size); + + if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { + mlx5dr_err(matcher->tbl->dmn, "Rule outer parameters contains a value not specified by mask\n"); + return false; + } + } + + if (match_criteria & DR_MATCHER_CRITERIA_MISC) { + s_idx = offsetof(struct mlx5dr_match_param, misc); + e_idx = min(s_idx + sizeof(param->misc), value_size); + + if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { + mlx5dr_err(matcher->tbl->dmn, "Rule misc parameters contains a value not specified by mask\n"); + return false; + } + } + + if (match_criteria & DR_MATCHER_CRITERIA_INNER) { + s_idx = offsetof(struct mlx5dr_match_param, inner); + e_idx = min(s_idx + sizeof(param->inner), value_size); + + if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { + mlx5dr_err(matcher->tbl->dmn, "Rule inner parameters contains a value not specified by mask\n"); + return false; + } + } + + if (match_criteria & DR_MATCHER_CRITERIA_MISC2) { + s_idx = offsetof(struct mlx5dr_match_param, misc2); + e_idx = min(s_idx + sizeof(param->misc2), value_size); + + if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { + mlx5dr_err(matcher->tbl->dmn, "Rule misc2 parameters contains a value not specified by mask\n"); + return false; + } + } + + if (match_criteria & DR_MATCHER_CRITERIA_MISC3) { + s_idx = offsetof(struct mlx5dr_match_param, misc3); + e_idx = min(s_idx + sizeof(param->misc3), value_size); + + if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { + mlx5dr_err(matcher->tbl->dmn, "Rule misc3 parameters contains a value not specified by mask\n"); + return false; + } + } + + if (match_criteria & DR_MATCHER_CRITERIA_MISC4) { + s_idx = offsetof(struct mlx5dr_match_param, misc4); + e_idx = min(s_idx + sizeof(param->misc4), value_size); + + if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { + mlx5dr_err(matcher->tbl->dmn, + "Rule misc4 parameters contains a value not specified by mask\n"); + return false; + } + } + + if (match_criteria & DR_MATCHER_CRITERIA_MISC5) { + s_idx = offsetof(struct mlx5dr_match_param, misc5); + e_idx = min(s_idx + sizeof(param->misc5), value_size); + + if (!dr_rule_cmp_value_to_mask(mask_p, param_p, s_idx, e_idx)) { + mlx5dr_err(matcher->tbl->dmn, "Rule misc5 parameters contains a value not specified by mask\n"); + return false; + } + } + return true; +} + +static int dr_rule_destroy_rule_nic(struct mlx5dr_rule *rule, + struct mlx5dr_rule_rx_tx *nic_rule) +{ + /* Check if this nic rule was actually created, or was it skipped + * and only the other type of the RX/TX nic rule was created. + */ + if (!nic_rule->last_rule_ste) + return 0; + + mlx5dr_domain_nic_lock(nic_rule->nic_matcher->nic_tbl->nic_dmn); + dr_rule_clean_rule_members(rule, nic_rule); + + nic_rule->nic_matcher->rules--; + if (!nic_rule->nic_matcher->rules) + mlx5dr_matcher_remove_from_tbl_nic(rule->matcher->tbl->dmn, + nic_rule->nic_matcher); + + mlx5dr_domain_nic_unlock(nic_rule->nic_matcher->nic_tbl->nic_dmn); + + return 0; +} + +static int dr_rule_destroy_rule_fdb(struct mlx5dr_rule *rule) +{ + dr_rule_destroy_rule_nic(rule, &rule->rx); + dr_rule_destroy_rule_nic(rule, &rule->tx); + return 0; +} + +static int dr_rule_destroy_rule(struct mlx5dr_rule *rule) +{ + struct mlx5dr_domain *dmn = rule->matcher->tbl->dmn; + + mlx5dr_dbg_rule_del(rule); + + switch (dmn->type) { + case MLX5DR_DOMAIN_TYPE_NIC_RX: + dr_rule_destroy_rule_nic(rule, &rule->rx); + break; + case MLX5DR_DOMAIN_TYPE_NIC_TX: + dr_rule_destroy_rule_nic(rule, &rule->tx); + break; + case MLX5DR_DOMAIN_TYPE_FDB: + dr_rule_destroy_rule_fdb(rule); + break; + default: + return -EINVAL; + } + + dr_rule_remove_action_members(rule); + kfree(rule); + return 0; +} + +static enum mlx5dr_ipv dr_rule_get_ipv(struct mlx5dr_match_spec *spec) +{ + if (spec->ip_version == 6 || spec->ethertype == ETH_P_IPV6) + return DR_RULE_IPV6; + + return DR_RULE_IPV4; +} + +static bool dr_rule_skip(enum mlx5dr_domain_type domain, + enum mlx5dr_domain_nic_type nic_type, + struct mlx5dr_match_param *mask, + struct mlx5dr_match_param *value, + u32 flow_source) +{ + bool rx = nic_type == DR_DOMAIN_NIC_TYPE_RX; + + if (domain != MLX5DR_DOMAIN_TYPE_FDB) + return false; + + if (mask->misc.source_port) { + if (rx && value->misc.source_port != MLX5_VPORT_UPLINK) + return true; + + if (!rx && value->misc.source_port == MLX5_VPORT_UPLINK) + return true; + } + + if (rx && flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT) + return true; + + if (!rx && flow_source == MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK) + return true; + + return false; +} + +static int +dr_rule_create_rule_nic(struct mlx5dr_rule *rule, + struct mlx5dr_rule_rx_tx *nic_rule, + struct mlx5dr_match_param *param, + size_t num_actions, + struct mlx5dr_action *actions[]) +{ + u8 hw_ste_arr_optimized[DR_RULE_MAX_STE_CHAIN_OPTIMIZED * DR_STE_SIZE] = {}; + struct mlx5dr_ste_send_info *ste_info, *tmp_ste_info; + struct mlx5dr_matcher *matcher = rule->matcher; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_matcher_rx_tx *nic_matcher; + struct mlx5dr_domain_rx_tx *nic_dmn; + struct mlx5dr_ste_htbl *htbl = NULL; + struct mlx5dr_ste_htbl *cur_htbl; + struct mlx5dr_ste *ste = NULL; + LIST_HEAD(send_ste_list); + bool hw_ste_arr_is_opt; + u8 *hw_ste_arr = NULL; + u32 new_hw_ste_arr_sz; + int ret, i; + + nic_matcher = nic_rule->nic_matcher; + nic_dmn = nic_matcher->nic_tbl->nic_dmn; + + if (dr_rule_skip(dmn->type, nic_dmn->type, &matcher->mask, param, + rule->flow_source)) + return 0; + + mlx5dr_domain_nic_lock(nic_dmn); + + ret = mlx5dr_matcher_select_builders(matcher, + nic_matcher, + dr_rule_get_ipv(¶m->outer), + dr_rule_get_ipv(¶m->inner)); + if (ret) + goto err_unlock; + + hw_ste_arr_is_opt = nic_matcher->num_of_builders <= DR_RULE_MAX_STES_OPTIMIZED; + if (likely(hw_ste_arr_is_opt)) { + hw_ste_arr = hw_ste_arr_optimized; + } else { + hw_ste_arr = kzalloc((nic_matcher->num_of_builders + DR_ACTION_MAX_STES) * + DR_STE_SIZE, GFP_KERNEL); + + if (!hw_ste_arr) { + ret = -ENOMEM; + goto err_unlock; + } + } + + ret = mlx5dr_matcher_add_to_tbl_nic(dmn, nic_matcher); + if (ret) + goto free_hw_ste; + + /* Set the tag values inside the ste array */ + ret = mlx5dr_ste_build_ste_arr(matcher, nic_matcher, param, hw_ste_arr); + if (ret) + goto remove_from_nic_tbl; + + /* Set the actions values/addresses inside the ste array */ + ret = mlx5dr_actions_build_ste_arr(matcher, nic_matcher, actions, + num_actions, hw_ste_arr, + &new_hw_ste_arr_sz); + if (ret) + goto remove_from_nic_tbl; + + cur_htbl = nic_matcher->s_htbl; + + /* Go over the array of STEs, and build dr_ste accordingly. + * The loop is over only the builders which are equal or less to the + * number of stes, in case we have actions that lives in other stes. + */ + for (i = 0; i < nic_matcher->num_of_builders; i++) { + /* Calculate CRC and keep new ste entry */ + u8 *cur_hw_ste_ent = hw_ste_arr + (i * DR_STE_SIZE); + + ste = dr_rule_handle_ste_branch(rule, + nic_rule, + &send_ste_list, + cur_htbl, + cur_hw_ste_ent, + i + 1, + &htbl); + if (!ste) { + mlx5dr_err(dmn, "Failed creating next branch\n"); + ret = -ENOENT; + goto free_rule; + } + + cur_htbl = ste->next_htbl; + + mlx5dr_ste_get(ste); + mlx5dr_rule_set_last_member(nic_rule, ste, true); + } + + /* Connect actions */ + ret = dr_rule_handle_action_stes(rule, nic_rule, &send_ste_list, + ste, hw_ste_arr, new_hw_ste_arr_sz); + if (ret) { + mlx5dr_dbg(dmn, "Failed apply actions\n"); + goto free_rule; + } + ret = dr_rule_send_update_list(&send_ste_list, dmn, true); + if (ret) { + mlx5dr_err(dmn, "Failed sending ste!\n"); + goto free_rule; + } + + if (htbl) + mlx5dr_htbl_put(htbl); + + nic_matcher->rules++; + + mlx5dr_domain_nic_unlock(nic_dmn); + + if (unlikely(!hw_ste_arr_is_opt)) + kfree(hw_ste_arr); + + return 0; + +free_rule: + dr_rule_clean_rule_members(rule, nic_rule); + /* Clean all ste_info's */ + list_for_each_entry_safe(ste_info, tmp_ste_info, &send_ste_list, send_list) { + list_del(&ste_info->send_list); + mlx5dr_send_info_free(ste_info); + } + +remove_from_nic_tbl: + if (!nic_matcher->rules) + mlx5dr_matcher_remove_from_tbl_nic(dmn, nic_matcher); + +free_hw_ste: + if (!hw_ste_arr_is_opt) + kfree(hw_ste_arr); + +err_unlock: + mlx5dr_domain_nic_unlock(nic_dmn); + + return ret; +} + +static int +dr_rule_create_rule_fdb(struct mlx5dr_rule *rule, + struct mlx5dr_match_param *param, + size_t num_actions, + struct mlx5dr_action *actions[]) +{ + struct mlx5dr_match_param copy_param = {}; + int ret; + + /* Copy match_param since they will be consumed during the first + * nic_rule insertion. + */ + memcpy(©_param, param, sizeof(struct mlx5dr_match_param)); + + ret = dr_rule_create_rule_nic(rule, &rule->rx, param, + num_actions, actions); + if (ret) + return ret; + + ret = dr_rule_create_rule_nic(rule, &rule->tx, ©_param, + num_actions, actions); + if (ret) + goto destroy_rule_nic_rx; + + return 0; + +destroy_rule_nic_rx: + dr_rule_destroy_rule_nic(rule, &rule->rx); + return ret; +} + +static struct mlx5dr_rule * +dr_rule_create_rule(struct mlx5dr_matcher *matcher, + struct mlx5dr_match_parameters *value, + size_t num_actions, + struct mlx5dr_action *actions[], + u32 flow_source) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_match_param param = {}; + struct mlx5dr_rule *rule; + int ret; + + if (!dr_rule_verify(matcher, value, ¶m)) + return NULL; + + rule = kzalloc(sizeof(*rule), GFP_KERNEL); + if (!rule) + return NULL; + + rule->matcher = matcher; + rule->flow_source = flow_source; + INIT_LIST_HEAD(&rule->rule_actions_list); + + ret = dr_rule_add_action_members(rule, num_actions, actions); + if (ret) + goto free_rule; + + switch (dmn->type) { + case MLX5DR_DOMAIN_TYPE_NIC_RX: + rule->rx.nic_matcher = &matcher->rx; + ret = dr_rule_create_rule_nic(rule, &rule->rx, ¶m, + num_actions, actions); + break; + case MLX5DR_DOMAIN_TYPE_NIC_TX: + rule->tx.nic_matcher = &matcher->tx; + ret = dr_rule_create_rule_nic(rule, &rule->tx, ¶m, + num_actions, actions); + break; + case MLX5DR_DOMAIN_TYPE_FDB: + rule->rx.nic_matcher = &matcher->rx; + rule->tx.nic_matcher = &matcher->tx; + ret = dr_rule_create_rule_fdb(rule, ¶m, + num_actions, actions); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + goto remove_action_members; + + INIT_LIST_HEAD(&rule->dbg_node); + mlx5dr_dbg_rule_add(rule); + return rule; + +remove_action_members: + dr_rule_remove_action_members(rule); +free_rule: + kfree(rule); + mlx5dr_err(dmn, "Failed creating rule\n"); + return NULL; +} + +struct mlx5dr_rule *mlx5dr_rule_create(struct mlx5dr_matcher *matcher, + struct mlx5dr_match_parameters *value, + size_t num_actions, + struct mlx5dr_action *actions[], + u32 flow_source) +{ + struct mlx5dr_rule *rule; + + refcount_inc(&matcher->refcount); + + rule = dr_rule_create_rule(matcher, value, num_actions, actions, flow_source); + if (!rule) + refcount_dec(&matcher->refcount); + + return rule; +} + +int mlx5dr_rule_destroy(struct mlx5dr_rule *rule) +{ + struct mlx5dr_matcher *matcher = rule->matcher; + int ret; + + ret = dr_rule_destroy_rule(rule); + if (!ret) + refcount_dec(&matcher->refcount); + + return ret; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_send.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_send.c new file mode 100644 index 00000000000000..6fa06ba2d34653 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_send.c @@ -0,0 +1,1368 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include +#include "dr_types.h" + +#define QUEUE_SIZE 128 +#define SIGNAL_PER_DIV_QUEUE 16 +#define TH_NUMS_TO_DRAIN 2 +#define DR_SEND_INFO_POOL_SIZE 1000 + +enum { CQ_OK = 0, CQ_EMPTY = -1, CQ_POLL_ERR = -2 }; + +struct dr_data_seg { + u64 addr; + u32 length; + u32 lkey; + unsigned int send_flags; +}; + +enum send_info_type { + WRITE_ICM = 0, + GTA_ARG = 1, +}; + +struct postsend_info { + enum send_info_type type; + struct dr_data_seg write; + struct dr_data_seg read; + u64 remote_addr; + u32 rkey; +}; + +struct dr_qp_rtr_attr { + struct mlx5dr_cmd_gid_attr dgid_attr; + enum ib_mtu mtu; + u32 qp_num; + u16 port_num; + u8 min_rnr_timer; + u8 sgid_index; + u16 udp_src_port; + u8 fl:1; +}; + +struct dr_qp_rts_attr { + u8 timeout; + u8 retry_cnt; + u8 rnr_retry; +}; + +struct dr_qp_init_attr { + u32 cqn; + u32 pdn; + u32 max_send_wr; + struct mlx5_uars_page *uar; + u8 isolate_vl_tc:1; +}; + +struct mlx5dr_send_info_pool_obj { + struct mlx5dr_ste_send_info ste_send_info; + struct mlx5dr_send_info_pool *pool; + struct list_head list_node; +}; + +struct mlx5dr_send_info_pool { + struct list_head free_list; +}; + +static int dr_send_info_pool_fill(struct mlx5dr_send_info_pool *pool) +{ + struct mlx5dr_send_info_pool_obj *pool_obj, *tmp_pool_obj; + int i; + + for (i = 0; i < DR_SEND_INFO_POOL_SIZE; i++) { + pool_obj = kzalloc(sizeof(*pool_obj), GFP_KERNEL); + if (!pool_obj) + goto clean_pool; + + pool_obj->pool = pool; + list_add_tail(&pool_obj->list_node, &pool->free_list); + } + + return 0; + +clean_pool: + list_for_each_entry_safe(pool_obj, tmp_pool_obj, &pool->free_list, list_node) { + list_del(&pool_obj->list_node); + kfree(pool_obj); + } + + return -ENOMEM; +} + +static void dr_send_info_pool_destroy(struct mlx5dr_send_info_pool *pool) +{ + struct mlx5dr_send_info_pool_obj *pool_obj, *tmp_pool_obj; + + list_for_each_entry_safe(pool_obj, tmp_pool_obj, &pool->free_list, list_node) { + list_del(&pool_obj->list_node); + kfree(pool_obj); + } + + kfree(pool); +} + +void mlx5dr_send_info_pool_destroy(struct mlx5dr_domain *dmn) +{ + dr_send_info_pool_destroy(dmn->send_info_pool_tx); + dr_send_info_pool_destroy(dmn->send_info_pool_rx); +} + +static struct mlx5dr_send_info_pool *dr_send_info_pool_create(void) +{ + struct mlx5dr_send_info_pool *pool; + int ret; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return NULL; + + INIT_LIST_HEAD(&pool->free_list); + + ret = dr_send_info_pool_fill(pool); + if (ret) { + kfree(pool); + return NULL; + } + + return pool; +} + +int mlx5dr_send_info_pool_create(struct mlx5dr_domain *dmn) +{ + dmn->send_info_pool_rx = dr_send_info_pool_create(); + if (!dmn->send_info_pool_rx) + return -ENOMEM; + + dmn->send_info_pool_tx = dr_send_info_pool_create(); + if (!dmn->send_info_pool_tx) { + dr_send_info_pool_destroy(dmn->send_info_pool_rx); + return -ENOMEM; + } + + return 0; +} + +struct mlx5dr_ste_send_info +*mlx5dr_send_info_alloc(struct mlx5dr_domain *dmn, + enum mlx5dr_domain_nic_type nic_type) +{ + struct mlx5dr_send_info_pool_obj *pool_obj; + struct mlx5dr_send_info_pool *pool; + int ret; + + pool = nic_type == DR_DOMAIN_NIC_TYPE_RX ? dmn->send_info_pool_rx : + dmn->send_info_pool_tx; + + if (unlikely(list_empty(&pool->free_list))) { + ret = dr_send_info_pool_fill(pool); + if (ret) + return NULL; + } + + pool_obj = list_first_entry_or_null(&pool->free_list, + struct mlx5dr_send_info_pool_obj, + list_node); + + if (likely(pool_obj)) { + list_del_init(&pool_obj->list_node); + } else { + WARN_ONCE(!pool_obj, "Failed getting ste send info obj from pool"); + return NULL; + } + + return &pool_obj->ste_send_info; +} + +void mlx5dr_send_info_free(struct mlx5dr_ste_send_info *ste_send_info) +{ + struct mlx5dr_send_info_pool_obj *pool_obj; + + pool_obj = container_of(ste_send_info, + struct mlx5dr_send_info_pool_obj, + ste_send_info); + + list_add(&pool_obj->list_node, &pool_obj->pool->free_list); +} + +static int dr_parse_cqe(struct mlx5dr_cq *dr_cq, struct mlx5_cqe64 *cqe64) +{ + unsigned int idx; + u8 opcode; + + opcode = get_cqe_opcode(cqe64); + if (opcode == MLX5_CQE_REQ_ERR) { + idx = be16_to_cpu(cqe64->wqe_counter) & + (dr_cq->qp->sq.wqe_cnt - 1); + dr_cq->qp->sq.cc = dr_cq->qp->sq.wqe_head[idx] + 1; + } else if (opcode == MLX5_CQE_RESP_ERR) { + ++dr_cq->qp->sq.cc; + } else { + idx = be16_to_cpu(cqe64->wqe_counter) & + (dr_cq->qp->sq.wqe_cnt - 1); + dr_cq->qp->sq.cc = dr_cq->qp->sq.wqe_head[idx] + 1; + + return CQ_OK; + } + + return CQ_POLL_ERR; +} + +static int dr_cq_poll_one(struct mlx5dr_cq *dr_cq) +{ + struct mlx5_cqe64 *cqe64; + int err; + + cqe64 = mlx5_cqwq_get_cqe(&dr_cq->wq); + if (!cqe64) { + if (unlikely(dr_cq->mdev->state == + MLX5_DEVICE_STATE_INTERNAL_ERROR)) { + mlx5_core_dbg_once(dr_cq->mdev, + "Polling CQ while device is shutting down\n"); + return CQ_POLL_ERR; + } + return CQ_EMPTY; + } + + mlx5_cqwq_pop(&dr_cq->wq); + err = dr_parse_cqe(dr_cq, cqe64); + mlx5_cqwq_update_db_record(&dr_cq->wq); + + return err; +} + +static int dr_poll_cq(struct mlx5dr_cq *dr_cq, int ne) +{ + int npolled; + int err = 0; + + for (npolled = 0; npolled < ne; ++npolled) { + err = dr_cq_poll_one(dr_cq); + if (err != CQ_OK) + break; + } + + return err == CQ_POLL_ERR ? err : npolled; +} + +static struct mlx5dr_qp *dr_create_rc_qp(struct mlx5_core_dev *mdev, + struct dr_qp_init_attr *attr) +{ + u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {}; + u32 temp_qpc[MLX5_ST_SZ_DW(qpc)] = {}; + struct mlx5_wq_param wqp; + struct mlx5dr_qp *dr_qp; + int inlen; + void *qpc; + void *in; + int err; + + dr_qp = kzalloc(sizeof(*dr_qp), GFP_KERNEL); + if (!dr_qp) + return NULL; + + wqp.buf_numa_node = mdev->priv.numa_node; + wqp.db_numa_node = mdev->priv.numa_node; + + dr_qp->rq.pc = 0; + dr_qp->rq.cc = 0; + dr_qp->rq.wqe_cnt = 256; + dr_qp->sq.pc = 0; + dr_qp->sq.cc = 0; + dr_qp->sq.head = 0; + dr_qp->sq.wqe_cnt = roundup_pow_of_two(attr->max_send_wr); + + MLX5_SET(qpc, temp_qpc, log_rq_stride, ilog2(MLX5_SEND_WQE_DS) - 4); + MLX5_SET(qpc, temp_qpc, log_rq_size, ilog2(dr_qp->rq.wqe_cnt)); + MLX5_SET(qpc, temp_qpc, log_sq_size, ilog2(dr_qp->sq.wqe_cnt)); + err = mlx5_wq_qp_create(mdev, &wqp, temp_qpc, &dr_qp->wq, + &dr_qp->wq_ctrl); + if (err) { + mlx5_core_warn(mdev, "Can't create QP WQ\n"); + goto err_wq; + } + + dr_qp->sq.wqe_head = kcalloc(dr_qp->sq.wqe_cnt, + sizeof(dr_qp->sq.wqe_head[0]), + GFP_KERNEL); + + if (!dr_qp->sq.wqe_head) { + mlx5_core_warn(mdev, "Can't allocate wqe head\n"); + goto err_wqe_head; + } + + inlen = MLX5_ST_SZ_BYTES(create_qp_in) + + MLX5_FLD_SZ_BYTES(create_qp_in, pas[0]) * + dr_qp->wq_ctrl.buf.npages; + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) { + err = -ENOMEM; + goto err_in; + } + + qpc = MLX5_ADDR_OF(create_qp_in, in, qpc); + MLX5_SET(qpc, qpc, st, MLX5_QP_ST_RC); + MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED); + MLX5_SET(qpc, qpc, isolate_vl_tc, attr->isolate_vl_tc); + MLX5_SET(qpc, qpc, pd, attr->pdn); + MLX5_SET(qpc, qpc, uar_page, attr->uar->index); + MLX5_SET(qpc, qpc, log_page_size, + dr_qp->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT); + MLX5_SET(qpc, qpc, fre, 1); + MLX5_SET(qpc, qpc, rlky, 1); + MLX5_SET(qpc, qpc, cqn_snd, attr->cqn); + MLX5_SET(qpc, qpc, cqn_rcv, attr->cqn); + MLX5_SET(qpc, qpc, log_rq_stride, ilog2(MLX5_SEND_WQE_DS) - 4); + MLX5_SET(qpc, qpc, log_rq_size, ilog2(dr_qp->rq.wqe_cnt)); + MLX5_SET(qpc, qpc, rq_type, MLX5_NON_ZERO_RQ); + MLX5_SET(qpc, qpc, log_sq_size, ilog2(dr_qp->sq.wqe_cnt)); + MLX5_SET(qpc, qpc, ts_format, mlx5_get_qp_default_ts(mdev)); + MLX5_SET64(qpc, qpc, dbr_addr, dr_qp->wq_ctrl.db.dma); + if (MLX5_CAP_GEN(mdev, cqe_version) == 1) + MLX5_SET(qpc, qpc, user_index, 0xFFFFFF); + mlx5_fill_page_frag_array(&dr_qp->wq_ctrl.buf, + (__be64 *)MLX5_ADDR_OF(create_qp_in, + in, pas)); + + MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP); + err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out)); + dr_qp->qpn = MLX5_GET(create_qp_out, out, qpn); + kvfree(in); + if (err) + goto err_in; + dr_qp->uar = attr->uar; + + return dr_qp; + +err_in: + kfree(dr_qp->sq.wqe_head); +err_wqe_head: + mlx5_wq_destroy(&dr_qp->wq_ctrl); +err_wq: + kfree(dr_qp); + return NULL; +} + +static void dr_destroy_qp(struct mlx5_core_dev *mdev, + struct mlx5dr_qp *dr_qp) +{ + u32 in[MLX5_ST_SZ_DW(destroy_qp_in)] = {}; + + MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP); + MLX5_SET(destroy_qp_in, in, qpn, dr_qp->qpn); + mlx5_cmd_exec_in(mdev, destroy_qp, in); + + kfree(dr_qp->sq.wqe_head); + mlx5_wq_destroy(&dr_qp->wq_ctrl); + kfree(dr_qp); +} + +static void dr_cmd_notify_hw(struct mlx5dr_qp *dr_qp, void *ctrl) +{ + dma_wmb(); + *dr_qp->wq.sq.db = cpu_to_be32(dr_qp->sq.pc & 0xffff); + + /* After wmb() the hw aware of new work */ + wmb(); + + mlx5_write64(ctrl, dr_qp->uar->map + MLX5_BF_OFFSET); +} + +static void +dr_rdma_handle_flow_access_arg_segments(struct mlx5_wqe_ctrl_seg *wq_ctrl, + u32 remote_addr, + struct dr_data_seg *data_seg, + int *size) +{ + struct mlx5_wqe_header_modify_argument_update_seg *wq_arg_seg; + struct mlx5_wqe_flow_update_ctrl_seg *wq_flow_seg; + + wq_ctrl->general_id = cpu_to_be32(remote_addr); + wq_flow_seg = (void *)(wq_ctrl + 1); + + /* mlx5_wqe_flow_update_ctrl_seg - all reserved */ + memset(wq_flow_seg, 0, sizeof(*wq_flow_seg)); + wq_arg_seg = (void *)(wq_flow_seg + 1); + + memcpy(wq_arg_seg->argument_list, + (void *)(uintptr_t)data_seg->addr, + data_seg->length); + + *size = (sizeof(*wq_ctrl) + /* WQE ctrl segment */ + sizeof(*wq_flow_seg) + /* WQE flow update ctrl seg - reserved */ + sizeof(*wq_arg_seg)) / /* WQE hdr modify arg seg - data */ + MLX5_SEND_WQE_DS; +} + +static void +dr_rdma_handle_icm_write_segments(struct mlx5_wqe_ctrl_seg *wq_ctrl, + u64 remote_addr, + u32 rkey, + struct dr_data_seg *data_seg, + unsigned int *size) +{ + struct mlx5_wqe_raddr_seg *wq_raddr; + struct mlx5_wqe_data_seg *wq_dseg; + + wq_raddr = (void *)(wq_ctrl + 1); + + wq_raddr->raddr = cpu_to_be64(remote_addr); + wq_raddr->rkey = cpu_to_be32(rkey); + wq_raddr->reserved = 0; + + wq_dseg = (void *)(wq_raddr + 1); + + wq_dseg->byte_count = cpu_to_be32(data_seg->length); + wq_dseg->lkey = cpu_to_be32(data_seg->lkey); + wq_dseg->addr = cpu_to_be64(data_seg->addr); + + *size = (sizeof(*wq_ctrl) + /* WQE ctrl segment */ + sizeof(*wq_dseg) + /* WQE data segment */ + sizeof(*wq_raddr)) / /* WQE remote addr segment */ + MLX5_SEND_WQE_DS; +} + +static void dr_set_ctrl_seg(struct mlx5_wqe_ctrl_seg *wq_ctrl, + struct dr_data_seg *data_seg) +{ + wq_ctrl->signature = 0; + wq_ctrl->rsvd[0] = 0; + wq_ctrl->rsvd[1] = 0; + wq_ctrl->fm_ce_se = data_seg->send_flags & IB_SEND_SIGNALED ? + MLX5_WQE_CTRL_CQ_UPDATE : 0; + wq_ctrl->imm = 0; +} + +static void dr_rdma_segments(struct mlx5dr_qp *dr_qp, u64 remote_addr, + u32 rkey, struct dr_data_seg *data_seg, + u32 opcode, bool notify_hw) +{ + struct mlx5_wqe_ctrl_seg *wq_ctrl; + int opcode_mod = 0; + unsigned int size; + unsigned int idx; + + idx = dr_qp->sq.pc & (dr_qp->sq.wqe_cnt - 1); + + wq_ctrl = mlx5_wq_cyc_get_wqe(&dr_qp->wq.sq, idx); + dr_set_ctrl_seg(wq_ctrl, data_seg); + + switch (opcode) { + case MLX5_OPCODE_RDMA_READ: + case MLX5_OPCODE_RDMA_WRITE: + dr_rdma_handle_icm_write_segments(wq_ctrl, remote_addr, + rkey, data_seg, &size); + break; + case MLX5_OPCODE_FLOW_TBL_ACCESS: + opcode_mod = MLX5_CMD_OP_MOD_UPDATE_HEADER_MODIFY_ARGUMENT; + dr_rdma_handle_flow_access_arg_segments(wq_ctrl, remote_addr, + data_seg, &size); + break; + default: + WARN(true, "illegal opcode %d", opcode); + return; + } + + /* -------------------------------------------------------- + * |opcode_mod (8 bit)|wqe_index (16 bits)| opcod (8 bits)| + * -------------------------------------------------------- + */ + wq_ctrl->opmod_idx_opcode = + cpu_to_be32((opcode_mod << 24) | + ((dr_qp->sq.pc & 0xffff) << 8) | + opcode); + wq_ctrl->qpn_ds = cpu_to_be32(size | dr_qp->qpn << 8); + + dr_qp->sq.pc += DIV_ROUND_UP(size * 16, MLX5_SEND_WQE_BB); + dr_qp->sq.wqe_head[idx] = dr_qp->sq.head++; + + if (notify_hw) + dr_cmd_notify_hw(dr_qp, wq_ctrl); +} + +static void dr_post_send(struct mlx5dr_qp *dr_qp, struct postsend_info *send_info) +{ + if (send_info->type == WRITE_ICM) { + dr_rdma_segments(dr_qp, send_info->remote_addr, send_info->rkey, + &send_info->write, MLX5_OPCODE_RDMA_WRITE, false); + dr_rdma_segments(dr_qp, send_info->remote_addr, send_info->rkey, + &send_info->read, MLX5_OPCODE_RDMA_READ, true); + } else { /* GTA_ARG */ + dr_rdma_segments(dr_qp, send_info->remote_addr, send_info->rkey, + &send_info->write, MLX5_OPCODE_FLOW_TBL_ACCESS, true); + } + +} + +/** + * mlx5dr_send_fill_and_append_ste_send_info: Add data to be sent + * with send_list parameters: + * + * @ste: The data that attached to this specific ste + * @size: of data to write + * @offset: of the data from start of the hw_ste entry + * @data: data + * @ste_info: ste to be sent with send_list + * @send_list: to append into it + * @copy_data: if true indicates that the data should be kept because + * it's not backuped any where (like in re-hash). + * if false, it lets the data to be updated after + * it was added to the list. + */ +void mlx5dr_send_fill_and_append_ste_send_info(struct mlx5dr_ste *ste, u16 size, + u16 offset, u8 *data, + struct mlx5dr_ste_send_info *ste_info, + struct list_head *send_list, + bool copy_data) +{ + ste_info->size = size; + ste_info->ste = ste; + ste_info->offset = offset; + + if (copy_data) { + memcpy(ste_info->data_cont, data, size); + ste_info->data = ste_info->data_cont; + } else { + ste_info->data = data; + } + + list_add_tail(&ste_info->send_list, send_list); +} + +/* The function tries to consume one wc each time, unless the queue is full, in + * that case, which means that the hw is behind the sw in a full queue len + * the function will drain the cq till it empty. + */ +static int dr_handle_pending_wc(struct mlx5dr_domain *dmn, + struct mlx5dr_send_ring *send_ring) +{ + bool is_drain = false; + int ne; + + if (send_ring->pending_wqe < send_ring->signal_th) + return 0; + + /* Queue is full start drain it */ + if (send_ring->pending_wqe >= + dmn->send_ring->signal_th * TH_NUMS_TO_DRAIN) + is_drain = true; + + do { + ne = dr_poll_cq(send_ring->cq, 1); + if (unlikely(ne < 0)) { + mlx5_core_warn_once(dmn->mdev, "SMFS QPN 0x%x is disabled/limited", + send_ring->qp->qpn); + send_ring->err_state = true; + return ne; + } else if (ne == 1) { + send_ring->pending_wqe -= send_ring->signal_th; + } + } while (ne == 1 || + (is_drain && send_ring->pending_wqe >= send_ring->signal_th)); + + return 0; +} + +static void dr_fill_write_args_segs(struct mlx5dr_send_ring *send_ring, + struct postsend_info *send_info) +{ + send_ring->pending_wqe++; + + if (send_ring->pending_wqe % send_ring->signal_th == 0) + send_info->write.send_flags |= IB_SEND_SIGNALED; + else + send_info->write.send_flags = 0; +} + +static void dr_fill_write_icm_segs(struct mlx5dr_domain *dmn, + struct mlx5dr_send_ring *send_ring, + struct postsend_info *send_info) +{ + u32 buff_offset; + + if (send_info->write.length > dmn->info.max_inline_size) { + buff_offset = (send_ring->tx_head & + (dmn->send_ring->signal_th - 1)) * + send_ring->max_post_send_size; + /* Copy to ring mr */ + memcpy(send_ring->buf + buff_offset, + (void *)(uintptr_t)send_info->write.addr, + send_info->write.length); + send_info->write.addr = (uintptr_t)send_ring->mr->dma_addr + buff_offset; + send_info->write.lkey = send_ring->mr->mkey; + + send_ring->tx_head++; + } + + send_ring->pending_wqe++; + + if (send_ring->pending_wqe % send_ring->signal_th == 0) + send_info->write.send_flags |= IB_SEND_SIGNALED; + + send_ring->pending_wqe++; + send_info->read.length = send_info->write.length; + + /* Read into dedicated sync buffer */ + send_info->read.addr = (uintptr_t)send_ring->sync_mr->dma_addr; + send_info->read.lkey = send_ring->sync_mr->mkey; + + if (send_ring->pending_wqe % send_ring->signal_th == 0) + send_info->read.send_flags = IB_SEND_SIGNALED; + else + send_info->read.send_flags = 0; +} + +static void dr_fill_data_segs(struct mlx5dr_domain *dmn, + struct mlx5dr_send_ring *send_ring, + struct postsend_info *send_info) +{ + if (send_info->type == WRITE_ICM) + dr_fill_write_icm_segs(dmn, send_ring, send_info); + else /* args */ + dr_fill_write_args_segs(send_ring, send_info); +} + +static int dr_postsend_icm_data(struct mlx5dr_domain *dmn, + struct postsend_info *send_info) +{ + struct mlx5dr_send_ring *send_ring = dmn->send_ring; + int ret; + + if (unlikely(dmn->mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR || + send_ring->err_state)) { + mlx5_core_dbg_once(dmn->mdev, + "Skipping post send: QP err state: %d, device state: %d\n", + send_ring->err_state, dmn->mdev->state); + return 0; + } + + spin_lock(&send_ring->lock); + + ret = dr_handle_pending_wc(dmn, send_ring); + if (ret) + goto out_unlock; + + dr_fill_data_segs(dmn, send_ring, send_info); + dr_post_send(send_ring->qp, send_info); + +out_unlock: + spin_unlock(&send_ring->lock); + return ret; +} + +static int dr_get_tbl_copy_details(struct mlx5dr_domain *dmn, + struct mlx5dr_ste_htbl *htbl, + u8 **data, + u32 *byte_size, + int *iterations, + int *num_stes) +{ + u32 chunk_byte_size = mlx5dr_icm_pool_get_chunk_byte_size(htbl->chunk); + int alloc_size; + + if (chunk_byte_size > dmn->send_ring->max_post_send_size) { + *iterations = chunk_byte_size / dmn->send_ring->max_post_send_size; + *byte_size = dmn->send_ring->max_post_send_size; + alloc_size = *byte_size; + *num_stes = *byte_size / DR_STE_SIZE; + } else { + *iterations = 1; + *num_stes = mlx5dr_icm_pool_get_chunk_num_of_entries(htbl->chunk); + alloc_size = *num_stes * DR_STE_SIZE; + } + + *data = kvzalloc(alloc_size, GFP_KERNEL); + if (!*data) + return -ENOMEM; + + return 0; +} + +/** + * mlx5dr_send_postsend_ste: write size bytes into offset from the hw cm. + * + * @dmn: Domain + * @ste: The ste struct that contains the data (at + * least part of it) + * @data: The real data to send size data + * @size: for writing. + * @offset: The offset from the icm mapped data to + * start write to this for write only part of the + * buffer. + * + * Return: 0 on success. + */ +int mlx5dr_send_postsend_ste(struct mlx5dr_domain *dmn, struct mlx5dr_ste *ste, + u8 *data, u16 size, u16 offset) +{ + struct postsend_info send_info = {}; + + mlx5dr_ste_prepare_for_postsend(dmn->ste_ctx, data, size); + + send_info.write.addr = (uintptr_t)data; + send_info.write.length = size; + send_info.write.lkey = 0; + send_info.remote_addr = mlx5dr_ste_get_mr_addr(ste) + offset; + send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(ste->htbl->chunk); + + return dr_postsend_icm_data(dmn, &send_info); +} + +int mlx5dr_send_postsend_htbl(struct mlx5dr_domain *dmn, + struct mlx5dr_ste_htbl *htbl, + u8 *formatted_ste, u8 *mask) +{ + u32 byte_size = mlx5dr_icm_pool_get_chunk_byte_size(htbl->chunk); + int num_stes_per_iter; + int iterations; + u8 *data; + int ret; + int i; + int j; + + ret = dr_get_tbl_copy_details(dmn, htbl, &data, &byte_size, + &iterations, &num_stes_per_iter); + if (ret) + return ret; + + mlx5dr_ste_prepare_for_postsend(dmn->ste_ctx, formatted_ste, DR_STE_SIZE); + + /* Send the data iteration times */ + for (i = 0; i < iterations; i++) { + u32 ste_index = i * (byte_size / DR_STE_SIZE); + struct postsend_info send_info = {}; + + /* Copy all ste's on the data buffer + * need to add the bit_mask + */ + for (j = 0; j < num_stes_per_iter; j++) { + struct mlx5dr_ste *ste = &htbl->chunk->ste_arr[ste_index + j]; + u32 ste_off = j * DR_STE_SIZE; + + if (mlx5dr_ste_is_not_used(ste)) { + memcpy(data + ste_off, + formatted_ste, DR_STE_SIZE); + } else { + /* Copy data */ + memcpy(data + ste_off, + htbl->chunk->hw_ste_arr + + DR_STE_SIZE_REDUCED * (ste_index + j), + DR_STE_SIZE_REDUCED); + /* Copy bit_mask */ + memcpy(data + ste_off + DR_STE_SIZE_REDUCED, + mask, DR_STE_SIZE_MASK); + /* Only when we have mask we need to re-arrange the STE */ + mlx5dr_ste_prepare_for_postsend(dmn->ste_ctx, + data + (j * DR_STE_SIZE), + DR_STE_SIZE); + } + } + + send_info.write.addr = (uintptr_t)data; + send_info.write.length = byte_size; + send_info.write.lkey = 0; + send_info.remote_addr = + mlx5dr_ste_get_mr_addr(htbl->chunk->ste_arr + ste_index); + send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(htbl->chunk); + + ret = dr_postsend_icm_data(dmn, &send_info); + if (ret) + goto out_free; + } + +out_free: + kvfree(data); + return ret; +} + +/* Initialize htble with default STEs */ +int mlx5dr_send_postsend_formatted_htbl(struct mlx5dr_domain *dmn, + struct mlx5dr_ste_htbl *htbl, + u8 *ste_init_data, + bool update_hw_ste) +{ + u32 byte_size = mlx5dr_icm_pool_get_chunk_byte_size(htbl->chunk); + int iterations; + int num_stes; + u8 *copy_dst; + u8 *data; + int ret; + int i; + + ret = dr_get_tbl_copy_details(dmn, htbl, &data, &byte_size, + &iterations, &num_stes); + if (ret) + return ret; + + if (update_hw_ste) { + /* Copy the reduced STE to hash table ste_arr */ + for (i = 0; i < num_stes; i++) { + copy_dst = htbl->chunk->hw_ste_arr + i * DR_STE_SIZE_REDUCED; + memcpy(copy_dst, ste_init_data, DR_STE_SIZE_REDUCED); + } + } + + mlx5dr_ste_prepare_for_postsend(dmn->ste_ctx, ste_init_data, DR_STE_SIZE); + + /* Copy the same STE on the data buffer */ + for (i = 0; i < num_stes; i++) { + copy_dst = data + i * DR_STE_SIZE; + memcpy(copy_dst, ste_init_data, DR_STE_SIZE); + } + + /* Send the data iteration times */ + for (i = 0; i < iterations; i++) { + u8 ste_index = i * (byte_size / DR_STE_SIZE); + struct postsend_info send_info = {}; + + send_info.write.addr = (uintptr_t)data; + send_info.write.length = byte_size; + send_info.write.lkey = 0; + send_info.remote_addr = + mlx5dr_ste_get_mr_addr(htbl->chunk->ste_arr + ste_index); + send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(htbl->chunk); + + ret = dr_postsend_icm_data(dmn, &send_info); + if (ret) + goto out_free; + } + +out_free: + kvfree(data); + return ret; +} + +int mlx5dr_send_postsend_action(struct mlx5dr_domain *dmn, + struct mlx5dr_action *action) +{ + struct postsend_info send_info = {}; + + send_info.write.addr = (uintptr_t)action->rewrite->data; + send_info.write.length = action->rewrite->num_of_actions * + DR_MODIFY_ACTION_SIZE; + send_info.write.lkey = 0; + send_info.remote_addr = + mlx5dr_icm_pool_get_chunk_mr_addr(action->rewrite->chunk); + send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(action->rewrite->chunk); + + return dr_postsend_icm_data(dmn, &send_info); +} + +int mlx5dr_send_postsend_pattern(struct mlx5dr_domain *dmn, + struct mlx5dr_icm_chunk *chunk, + u16 num_of_actions, + u8 *data) +{ + struct postsend_info send_info = {}; + int ret; + + send_info.write.addr = (uintptr_t)data; + send_info.write.length = num_of_actions * DR_MODIFY_ACTION_SIZE; + send_info.remote_addr = mlx5dr_icm_pool_get_chunk_mr_addr(chunk); + send_info.rkey = mlx5dr_icm_pool_get_chunk_rkey(chunk); + + ret = dr_postsend_icm_data(dmn, &send_info); + if (ret) + return ret; + + return 0; +} + +int mlx5dr_send_postsend_args(struct mlx5dr_domain *dmn, u64 arg_id, + u16 num_of_actions, u8 *actions_data) +{ + int data_len, iter = 0, cur_sent; + u64 addr; + int ret; + + addr = (uintptr_t)actions_data; + data_len = num_of_actions * DR_MODIFY_ACTION_SIZE; + + do { + struct postsend_info send_info = {}; + + send_info.type = GTA_ARG; + send_info.write.addr = addr; + cur_sent = min_t(u32, data_len, DR_ACTION_CACHE_LINE_SIZE); + send_info.write.length = cur_sent; + send_info.write.lkey = 0; + send_info.remote_addr = arg_id + iter; + + ret = dr_postsend_icm_data(dmn, &send_info); + if (ret) + goto out; + + iter++; + addr += cur_sent; + data_len -= cur_sent; + } while (data_len > 0); + +out: + return ret; +} + +static int dr_modify_qp_rst2init(struct mlx5_core_dev *mdev, + struct mlx5dr_qp *dr_qp, + int port) +{ + u32 in[MLX5_ST_SZ_DW(rst2init_qp_in)] = {}; + void *qpc; + + qpc = MLX5_ADDR_OF(rst2init_qp_in, in, qpc); + + MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, port); + MLX5_SET(qpc, qpc, pm_state, MLX5_QPC_PM_STATE_MIGRATED); + MLX5_SET(qpc, qpc, rre, 1); + MLX5_SET(qpc, qpc, rwe, 1); + + MLX5_SET(rst2init_qp_in, in, opcode, MLX5_CMD_OP_RST2INIT_QP); + MLX5_SET(rst2init_qp_in, in, qpn, dr_qp->qpn); + + return mlx5_cmd_exec_in(mdev, rst2init_qp, in); +} + +static int dr_cmd_modify_qp_rtr2rts(struct mlx5_core_dev *mdev, + struct mlx5dr_qp *dr_qp, + struct dr_qp_rts_attr *attr) +{ + u32 in[MLX5_ST_SZ_DW(rtr2rts_qp_in)] = {}; + void *qpc; + + qpc = MLX5_ADDR_OF(rtr2rts_qp_in, in, qpc); + + MLX5_SET(rtr2rts_qp_in, in, qpn, dr_qp->qpn); + + MLX5_SET(qpc, qpc, retry_count, attr->retry_cnt); + MLX5_SET(qpc, qpc, rnr_retry, attr->rnr_retry); + MLX5_SET(qpc, qpc, primary_address_path.ack_timeout, 0x8); /* ~1ms */ + + MLX5_SET(rtr2rts_qp_in, in, opcode, MLX5_CMD_OP_RTR2RTS_QP); + MLX5_SET(rtr2rts_qp_in, in, qpn, dr_qp->qpn); + + return mlx5_cmd_exec_in(mdev, rtr2rts_qp, in); +} + +static int dr_cmd_modify_qp_init2rtr(struct mlx5_core_dev *mdev, + struct mlx5dr_qp *dr_qp, + struct dr_qp_rtr_attr *attr) +{ + u32 in[MLX5_ST_SZ_DW(init2rtr_qp_in)] = {}; + void *qpc; + + qpc = MLX5_ADDR_OF(init2rtr_qp_in, in, qpc); + + MLX5_SET(init2rtr_qp_in, in, qpn, dr_qp->qpn); + + MLX5_SET(qpc, qpc, mtu, attr->mtu); + MLX5_SET(qpc, qpc, log_msg_max, DR_CHUNK_SIZE_MAX - 1); + MLX5_SET(qpc, qpc, remote_qpn, attr->qp_num); + memcpy(MLX5_ADDR_OF(qpc, qpc, primary_address_path.rmac_47_32), + attr->dgid_attr.mac, sizeof(attr->dgid_attr.mac)); + memcpy(MLX5_ADDR_OF(qpc, qpc, primary_address_path.rgid_rip), + attr->dgid_attr.gid, sizeof(attr->dgid_attr.gid)); + MLX5_SET(qpc, qpc, primary_address_path.src_addr_index, + attr->sgid_index); + + if (attr->dgid_attr.roce_ver == MLX5_ROCE_VERSION_2) + MLX5_SET(qpc, qpc, primary_address_path.udp_sport, + attr->udp_src_port); + + MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, attr->port_num); + MLX5_SET(qpc, qpc, primary_address_path.fl, attr->fl); + MLX5_SET(qpc, qpc, min_rnr_nak, 1); + + MLX5_SET(init2rtr_qp_in, in, opcode, MLX5_CMD_OP_INIT2RTR_QP); + MLX5_SET(init2rtr_qp_in, in, qpn, dr_qp->qpn); + + return mlx5_cmd_exec_in(mdev, init2rtr_qp, in); +} + +static bool dr_send_allow_fl(struct mlx5dr_cmd_caps *caps) +{ + /* Check whether RC RoCE QP creation with force loopback is allowed. + * There are two separate capability bits for this: + * - force loopback when RoCE is enabled + * - force loopback when RoCE is disabled + */ + return ((caps->roce_caps.roce_en && + caps->roce_caps.fl_rc_qp_when_roce_enabled) || + (!caps->roce_caps.roce_en && + caps->roce_caps.fl_rc_qp_when_roce_disabled)); +} + +static int dr_prepare_qp_to_rts(struct mlx5dr_domain *dmn) +{ + struct mlx5dr_qp *dr_qp = dmn->send_ring->qp; + struct dr_qp_rts_attr rts_attr = {}; + struct dr_qp_rtr_attr rtr_attr = {}; + enum ib_mtu mtu = IB_MTU_1024; + u16 gid_index = 0; + int port = 1; + int ret; + + /* Init */ + ret = dr_modify_qp_rst2init(dmn->mdev, dr_qp, port); + if (ret) { + mlx5dr_err(dmn, "Failed modify QP rst2init\n"); + return ret; + } + + /* RTR */ + rtr_attr.mtu = mtu; + rtr_attr.qp_num = dr_qp->qpn; + rtr_attr.min_rnr_timer = 12; + rtr_attr.port_num = port; + rtr_attr.udp_src_port = dmn->info.caps.roce_min_src_udp; + + /* If QP creation with force loopback is allowed, then there + * is no need for GID index when creating the QP. + * Otherwise we query GID attributes and use GID index. + */ + rtr_attr.fl = dr_send_allow_fl(&dmn->info.caps); + if (!rtr_attr.fl) { + ret = mlx5dr_cmd_query_gid(dmn->mdev, port, gid_index, + &rtr_attr.dgid_attr); + if (ret) + return ret; + + rtr_attr.sgid_index = gid_index; + } + + ret = dr_cmd_modify_qp_init2rtr(dmn->mdev, dr_qp, &rtr_attr); + if (ret) { + mlx5dr_err(dmn, "Failed modify QP init2rtr\n"); + return ret; + } + + /* RTS */ + rts_attr.timeout = 14; + rts_attr.retry_cnt = 7; + rts_attr.rnr_retry = 7; + + ret = dr_cmd_modify_qp_rtr2rts(dmn->mdev, dr_qp, &rts_attr); + if (ret) { + mlx5dr_err(dmn, "Failed modify QP rtr2rts\n"); + return ret; + } + + return 0; +} + +static void dr_cq_complete(struct mlx5_core_cq *mcq, + struct mlx5_eqe *eqe) +{ + pr_err("CQ completion CQ: #%u\n", mcq->cqn); +} + +static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev, + struct mlx5_uars_page *uar, + size_t ncqe) +{ + u32 temp_cqc[MLX5_ST_SZ_DW(cqc)] = {}; + u32 out[MLX5_ST_SZ_DW(create_cq_out)]; + struct mlx5_wq_param wqp; + struct mlx5_cqe64 *cqe; + struct mlx5dr_cq *cq; + int inlen, err, eqn; + void *cqc, *in; + __be64 *pas; + int vector; + u32 i; + + cq = kzalloc(sizeof(*cq), GFP_KERNEL); + if (!cq) + return NULL; + + ncqe = roundup_pow_of_two(ncqe); + MLX5_SET(cqc, temp_cqc, log_cq_size, ilog2(ncqe)); + + wqp.buf_numa_node = mdev->priv.numa_node; + wqp.db_numa_node = mdev->priv.numa_node; + + err = mlx5_cqwq_create(mdev, &wqp, temp_cqc, &cq->wq, + &cq->wq_ctrl); + if (err) + goto out; + + for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) { + cqe = mlx5_cqwq_get_wqe(&cq->wq, i); + cqe->op_own = MLX5_CQE_INVALID << 4 | MLX5_CQE_OWNER_MASK; + } + + inlen = MLX5_ST_SZ_BYTES(create_cq_in) + + sizeof(u64) * cq->wq_ctrl.buf.npages; + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) + goto err_cqwq; + + vector = raw_smp_processor_id() % mlx5_comp_vectors_max(mdev); + err = mlx5_comp_eqn_get(mdev, vector, &eqn); + if (err) { + kvfree(in); + goto err_cqwq; + } + + cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context); + MLX5_SET(cqc, cqc, log_cq_size, ilog2(ncqe)); + MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn); + MLX5_SET(cqc, cqc, uar_page, uar->index); + MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift - + MLX5_ADAPTER_PAGE_SHIFT); + MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma); + + pas = (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas); + mlx5_fill_page_frag_array(&cq->wq_ctrl.buf, pas); + + cq->mcq.comp = dr_cq_complete; + + err = mlx5_core_create_cq(mdev, &cq->mcq, in, inlen, out, sizeof(out)); + kvfree(in); + + if (err) + goto err_cqwq; + + cq->mcq.cqe_sz = 64; + cq->mcq.set_ci_db = cq->wq_ctrl.db.db; + cq->mcq.arm_db = cq->wq_ctrl.db.db + 1; + *cq->mcq.set_ci_db = 0; + + /* set no-zero value, in order to avoid the HW to run db-recovery on + * CQ that used in polling mode. + */ + *cq->mcq.arm_db = cpu_to_be32(2 << 28); + + cq->mcq.vector = 0; + cq->mcq.uar = uar; + cq->mdev = mdev; + + return cq; + +err_cqwq: + mlx5_wq_destroy(&cq->wq_ctrl); +out: + kfree(cq); + return NULL; +} + +static void dr_destroy_cq(struct mlx5_core_dev *mdev, struct mlx5dr_cq *cq) +{ + mlx5_core_destroy_cq(mdev, &cq->mcq); + mlx5_wq_destroy(&cq->wq_ctrl); + kfree(cq); +} + +static int dr_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, u32 *mkey) +{ + u32 in[MLX5_ST_SZ_DW(create_mkey_in)] = {}; + void *mkc; + + mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); + MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA); + MLX5_SET(mkc, mkc, a, 1); + MLX5_SET(mkc, mkc, rw, 1); + MLX5_SET(mkc, mkc, rr, 1); + MLX5_SET(mkc, mkc, lw, 1); + MLX5_SET(mkc, mkc, lr, 1); + + MLX5_SET(mkc, mkc, pd, pdn); + MLX5_SET(mkc, mkc, length64, 1); + MLX5_SET(mkc, mkc, qpn, 0xffffff); + + return mlx5_core_create_mkey(mdev, mkey, in, sizeof(in)); +} + +static struct mlx5dr_mr *dr_reg_mr(struct mlx5_core_dev *mdev, + u32 pdn, void *buf, size_t size) +{ + struct mlx5dr_mr *mr = kzalloc(sizeof(*mr), GFP_KERNEL); + struct device *dma_device; + dma_addr_t dma_addr; + int err; + + if (!mr) + return NULL; + + dma_device = mlx5_core_dma_dev(mdev); + dma_addr = dma_map_single(dma_device, buf, size, + DMA_BIDIRECTIONAL); + err = dma_mapping_error(dma_device, dma_addr); + if (err) { + mlx5_core_warn(mdev, "Can't dma buf\n"); + kfree(mr); + return NULL; + } + + err = dr_create_mkey(mdev, pdn, &mr->mkey); + if (err) { + mlx5_core_warn(mdev, "Can't create mkey\n"); + dma_unmap_single(dma_device, dma_addr, size, + DMA_BIDIRECTIONAL); + kfree(mr); + return NULL; + } + + mr->dma_addr = dma_addr; + mr->size = size; + mr->addr = buf; + + return mr; +} + +static void dr_dereg_mr(struct mlx5_core_dev *mdev, struct mlx5dr_mr *mr) +{ + mlx5_core_destroy_mkey(mdev, mr->mkey); + dma_unmap_single(mlx5_core_dma_dev(mdev), mr->dma_addr, mr->size, + DMA_BIDIRECTIONAL); + kfree(mr); +} + +int mlx5dr_send_ring_alloc(struct mlx5dr_domain *dmn) +{ + struct dr_qp_init_attr init_attr = {}; + int cq_size; + int size; + int ret; + + dmn->send_ring = kzalloc(sizeof(*dmn->send_ring), GFP_KERNEL); + if (!dmn->send_ring) + return -ENOMEM; + + cq_size = QUEUE_SIZE + 1; + dmn->send_ring->cq = dr_create_cq(dmn->mdev, dmn->uar, cq_size); + if (!dmn->send_ring->cq) { + mlx5dr_err(dmn, "Failed creating CQ\n"); + ret = -ENOMEM; + goto free_send_ring; + } + + init_attr.cqn = dmn->send_ring->cq->mcq.cqn; + init_attr.pdn = dmn->pdn; + init_attr.uar = dmn->uar; + init_attr.max_send_wr = QUEUE_SIZE; + + /* Isolated VL is applicable only if force loopback is supported */ + if (dr_send_allow_fl(&dmn->info.caps)) + init_attr.isolate_vl_tc = dmn->info.caps.isolate_vl_tc; + + spin_lock_init(&dmn->send_ring->lock); + + dmn->send_ring->qp = dr_create_rc_qp(dmn->mdev, &init_attr); + if (!dmn->send_ring->qp) { + mlx5dr_err(dmn, "Failed creating QP\n"); + ret = -ENOMEM; + goto clean_cq; + } + + dmn->send_ring->cq->qp = dmn->send_ring->qp; + + dmn->info.max_send_wr = QUEUE_SIZE; + dmn->info.max_inline_size = min(dmn->send_ring->qp->max_inline_data, + DR_STE_SIZE); + + dmn->send_ring->signal_th = dmn->info.max_send_wr / + SIGNAL_PER_DIV_QUEUE; + + /* Prepare qp to be used */ + ret = dr_prepare_qp_to_rts(dmn); + if (ret) + goto clean_qp; + + dmn->send_ring->max_post_send_size = + mlx5dr_icm_pool_chunk_size_to_byte(DR_CHUNK_SIZE_1K, + DR_ICM_TYPE_STE); + + /* Allocating the max size as a buffer for writing */ + size = dmn->send_ring->signal_th * dmn->send_ring->max_post_send_size; + dmn->send_ring->buf = kzalloc(size, GFP_KERNEL); + if (!dmn->send_ring->buf) { + ret = -ENOMEM; + goto clean_qp; + } + + dmn->send_ring->buf_size = size; + + dmn->send_ring->mr = dr_reg_mr(dmn->mdev, + dmn->pdn, dmn->send_ring->buf, size); + if (!dmn->send_ring->mr) { + ret = -ENOMEM; + goto free_mem; + } + + dmn->send_ring->sync_buff = kzalloc(dmn->send_ring->max_post_send_size, + GFP_KERNEL); + if (!dmn->send_ring->sync_buff) { + ret = -ENOMEM; + goto clean_mr; + } + + dmn->send_ring->sync_mr = dr_reg_mr(dmn->mdev, + dmn->pdn, dmn->send_ring->sync_buff, + dmn->send_ring->max_post_send_size); + if (!dmn->send_ring->sync_mr) { + ret = -ENOMEM; + goto free_sync_mem; + } + + return 0; + +free_sync_mem: + kfree(dmn->send_ring->sync_buff); +clean_mr: + dr_dereg_mr(dmn->mdev, dmn->send_ring->mr); +free_mem: + kfree(dmn->send_ring->buf); +clean_qp: + dr_destroy_qp(dmn->mdev, dmn->send_ring->qp); +clean_cq: + dr_destroy_cq(dmn->mdev, dmn->send_ring->cq); +free_send_ring: + kfree(dmn->send_ring); + + return ret; +} + +void mlx5dr_send_ring_free(struct mlx5dr_domain *dmn, + struct mlx5dr_send_ring *send_ring) +{ + dr_destroy_qp(dmn->mdev, send_ring->qp); + dr_destroy_cq(dmn->mdev, send_ring->cq); + dr_dereg_mr(dmn->mdev, send_ring->sync_mr); + dr_dereg_mr(dmn->mdev, send_ring->mr); + kfree(send_ring->buf); + kfree(send_ring->sync_buff); + kfree(send_ring); +} + +int mlx5dr_send_ring_force_drain(struct mlx5dr_domain *dmn) +{ + struct mlx5dr_send_ring *send_ring = dmn->send_ring; + struct postsend_info send_info = {}; + u8 data[DR_STE_SIZE]; + int num_of_sends_req; + int ret; + int i; + + /* Sending this amount of requests makes sure we will get drain */ + num_of_sends_req = send_ring->signal_th * TH_NUMS_TO_DRAIN / 2; + + /* Send fake requests forcing the last to be signaled */ + send_info.write.addr = (uintptr_t)data; + send_info.write.length = DR_STE_SIZE; + send_info.write.lkey = 0; + /* Using the sync_mr in order to write/read */ + send_info.remote_addr = (uintptr_t)send_ring->sync_mr->addr; + send_info.rkey = send_ring->sync_mr->mkey; + + for (i = 0; i < num_of_sends_req; i++) { + ret = dr_postsend_icm_data(dmn, &send_info); + if (ret) + return ret; + } + + spin_lock(&send_ring->lock); + ret = dr_handle_pending_wc(dmn, send_ring); + spin_unlock(&send_ring->lock); + + return ret; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.c new file mode 100644 index 00000000000000..e94fbb015efad7 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.c @@ -0,0 +1,1463 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include +#include +#include "dr_ste.h" + +struct dr_hw_ste_format { + u8 ctrl[DR_STE_SIZE_CTRL]; + u8 tag[DR_STE_SIZE_TAG]; + u8 mask[DR_STE_SIZE_MASK]; +}; + +static u32 dr_ste_crc32_calc(const void *input_data, size_t length) +{ + u32 crc = crc32(0, input_data, length); + + 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) +{ + return caps->sw_format_ver > MLX5_STEERING_FORMAT_CONNECTX_5; +} + +u32 mlx5dr_ste_calc_hash_index(u8 *hw_ste_p, struct mlx5dr_ste_htbl *htbl) +{ + u32 num_entries = mlx5dr_icm_pool_get_chunk_num_of_entries(htbl->chunk); + struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; + u8 masked[DR_STE_SIZE_TAG] = {}; + u32 crc32, index; + u16 bit; + int i; + + /* Don't calculate CRC if the result is predicted */ + if (num_entries == 1 || htbl->byte_mask == 0) + return 0; + + /* Mask tag using byte mask, bit per byte */ + bit = 1 << (DR_STE_SIZE_TAG - 1); + for (i = 0; i < DR_STE_SIZE_TAG; i++) { + if (htbl->byte_mask & bit) + masked[i] = hw_ste->tag[i]; + + bit = bit >> 1; + } + + crc32 = dr_ste_crc32_calc(masked, DR_STE_SIZE_TAG); + index = crc32 & (num_entries - 1); + + return index; +} + +u16 mlx5dr_ste_conv_bit_to_byte_mask(u8 *bit_mask) +{ + u16 byte_mask = 0; + int i; + + for (i = 0; i < DR_STE_SIZE_MASK; i++) { + byte_mask = byte_mask << 1; + if (bit_mask[i] == 0xff) + byte_mask |= 1; + } + return byte_mask; +} + +static u8 *dr_ste_get_tag(u8 *hw_ste_p) +{ + struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; + + return hw_ste->tag; +} + +void mlx5dr_ste_set_bit_mask(u8 *hw_ste_p, u8 *bit_mask) +{ + struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; + + memcpy(hw_ste->mask, bit_mask, DR_STE_SIZE_MASK); +} + +static void dr_ste_set_always_hit(struct dr_hw_ste_format *hw_ste) +{ + memset(&hw_ste->tag, 0, sizeof(hw_ste->tag)); + memset(&hw_ste->mask, 0, sizeof(hw_ste->mask)); +} + +static void dr_ste_set_always_miss(struct dr_hw_ste_format *hw_ste) +{ + hw_ste->tag[0] = 0xdc; + hw_ste->mask[0] = 0; +} + +bool mlx5dr_ste_is_miss_addr_set(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste_p) +{ + if (!ste_ctx->is_miss_addr_set) + return false; + + /* check if miss address is already set for this type of STE */ + return ste_ctx->is_miss_addr_set(hw_ste_p); +} + +void mlx5dr_ste_set_miss_addr(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste_p, u64 miss_addr) +{ + ste_ctx->set_miss_addr(hw_ste_p, miss_addr); +} + +static void dr_ste_always_miss_addr(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste, u64 miss_addr) +{ + ste_ctx->set_next_lu_type(hw_ste, MLX5DR_STE_LU_TYPE_DONT_CARE); + ste_ctx->set_miss_addr(hw_ste, miss_addr); + dr_ste_set_always_miss((struct dr_hw_ste_format *)hw_ste); +} + +void mlx5dr_ste_set_hit_addr(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste, u64 icm_addr, u32 ht_size) +{ + ste_ctx->set_hit_addr(hw_ste, icm_addr, ht_size); +} + +u64 mlx5dr_ste_get_icm_addr(struct mlx5dr_ste *ste) +{ + u64 base_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(ste->htbl->chunk); + u32 index = ste - ste->htbl->chunk->ste_arr; + + return base_icm_addr + DR_STE_SIZE * index; +} + +u64 mlx5dr_ste_get_mr_addr(struct mlx5dr_ste *ste) +{ + u32 index = ste - ste->htbl->chunk->ste_arr; + + return mlx5dr_icm_pool_get_chunk_mr_addr(ste->htbl->chunk) + DR_STE_SIZE * index; +} + +u8 *mlx5dr_ste_get_hw_ste(struct mlx5dr_ste *ste) +{ + u64 index = ste - ste->htbl->chunk->ste_arr; + + return ste->htbl->chunk->hw_ste_arr + DR_STE_SIZE_REDUCED * index; +} + +struct list_head *mlx5dr_ste_get_miss_list(struct mlx5dr_ste *ste) +{ + u32 index = ste - ste->htbl->chunk->ste_arr; + + return &ste->htbl->chunk->miss_list[index]; +} + +static void dr_ste_always_hit_htbl(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste, + struct mlx5dr_ste_htbl *next_htbl) +{ + struct mlx5dr_icm_chunk *chunk = next_htbl->chunk; + + ste_ctx->set_byte_mask(hw_ste, next_htbl->byte_mask); + ste_ctx->set_next_lu_type(hw_ste, next_htbl->lu_type); + ste_ctx->set_hit_addr(hw_ste, mlx5dr_icm_pool_get_chunk_icm_addr(chunk), + mlx5dr_icm_pool_get_chunk_num_of_entries(chunk)); + + dr_ste_set_always_hit((struct dr_hw_ste_format *)hw_ste); +} + +bool mlx5dr_ste_is_last_in_rule(struct mlx5dr_matcher_rx_tx *nic_matcher, + u8 ste_location) +{ + return ste_location == nic_matcher->num_of_builders; +} + +/* Replace relevant fields, except of: + * htbl - keep the origin htbl + * miss_list + list - already took the src from the list. + * icm_addr/mr_addr - depends on the hosting table. + * + * Before: + * | a | -> | b | -> | c | -> + * + * After: + * | a | -> | c | -> + * While the data that was in b copied to a. + */ +static void dr_ste_replace(struct mlx5dr_ste *dst, struct mlx5dr_ste *src) +{ + memcpy(mlx5dr_ste_get_hw_ste(dst), mlx5dr_ste_get_hw_ste(src), + DR_STE_SIZE_REDUCED); + dst->next_htbl = src->next_htbl; + if (dst->next_htbl) + dst->next_htbl->pointing_ste = dst; + + dst->refcount = src->refcount; +} + +/* Free ste which is the head and the only one in miss_list */ +static void +dr_ste_remove_head_ste(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste *ste, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste_send_info *ste_info_head, + struct list_head *send_ste_list, + struct mlx5dr_ste_htbl *stats_tbl) +{ + u8 tmp_data_ste[DR_STE_SIZE] = {}; + u64 miss_addr; + + miss_addr = mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk); + + /* Use temp ste because dr_ste_always_miss_addr + * touches bit_mask area which doesn't exist at ste->hw_ste. + * Need to use a full-sized (DR_STE_SIZE) hw_ste. + */ + memcpy(tmp_data_ste, mlx5dr_ste_get_hw_ste(ste), DR_STE_SIZE_REDUCED); + dr_ste_always_miss_addr(ste_ctx, tmp_data_ste, miss_addr); + memcpy(mlx5dr_ste_get_hw_ste(ste), tmp_data_ste, DR_STE_SIZE_REDUCED); + + list_del_init(&ste->miss_list_node); + + /* Write full STE size in order to have "always_miss" */ + mlx5dr_send_fill_and_append_ste_send_info(ste, DR_STE_SIZE, + 0, tmp_data_ste, + ste_info_head, + send_ste_list, + true /* Copy data */); + + stats_tbl->ctrl.num_of_valid_entries--; +} + +/* Free ste which is the head but NOT the only one in miss_list: + * |_ste_| --> |_next_ste_| -->|__| -->|__| -->/0 + */ +static void +dr_ste_replace_head_ste(struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste *ste, + struct mlx5dr_ste *next_ste, + struct mlx5dr_ste_send_info *ste_info_head, + struct list_head *send_ste_list, + struct mlx5dr_ste_htbl *stats_tbl) + +{ + struct mlx5dr_ste_htbl *next_miss_htbl; + u8 hw_ste[DR_STE_SIZE] = {}; + int sb_idx; + + next_miss_htbl = next_ste->htbl; + + /* Remove from the miss_list the next_ste before copy */ + list_del_init(&next_ste->miss_list_node); + + /* Move data from next into ste */ + dr_ste_replace(ste, next_ste); + + /* Update the rule on STE change */ + mlx5dr_rule_set_last_member(next_ste->rule_rx_tx, ste, false); + + /* Copy all 64 hw_ste bytes */ + memcpy(hw_ste, mlx5dr_ste_get_hw_ste(ste), DR_STE_SIZE_REDUCED); + sb_idx = ste->ste_chain_location - 1; + mlx5dr_ste_set_bit_mask(hw_ste, + nic_matcher->ste_builder[sb_idx].bit_mask); + + /* Del the htbl that contains the next_ste. + * The origin htbl stay with the same number of entries. + */ + mlx5dr_htbl_put(next_miss_htbl); + + mlx5dr_send_fill_and_append_ste_send_info(ste, DR_STE_SIZE, + 0, hw_ste, + ste_info_head, + send_ste_list, + true /* Copy data */); + + stats_tbl->ctrl.num_of_collisions--; + stats_tbl->ctrl.num_of_valid_entries--; +} + +/* Free ste that is located in the middle of the miss list: + * |__| -->|_prev_ste_|->|_ste_|-->|_next_ste_| + */ +static void dr_ste_remove_middle_ste(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste *ste, + struct mlx5dr_ste_send_info *ste_info, + struct list_head *send_ste_list, + struct mlx5dr_ste_htbl *stats_tbl) +{ + struct mlx5dr_ste *prev_ste; + u64 miss_addr; + + prev_ste = list_prev_entry(ste, miss_list_node); + if (WARN_ON(!prev_ste)) + return; + + miss_addr = ste_ctx->get_miss_addr(mlx5dr_ste_get_hw_ste(ste)); + ste_ctx->set_miss_addr(mlx5dr_ste_get_hw_ste(prev_ste), miss_addr); + + mlx5dr_send_fill_and_append_ste_send_info(prev_ste, DR_STE_SIZE_CTRL, 0, + mlx5dr_ste_get_hw_ste(prev_ste), + ste_info, send_ste_list, + true /* Copy data*/); + + list_del_init(&ste->miss_list_node); + + stats_tbl->ctrl.num_of_valid_entries--; + stats_tbl->ctrl.num_of_collisions--; +} + +void mlx5dr_ste_free(struct mlx5dr_ste *ste, + struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + struct mlx5dr_ste_send_info *cur_ste_info, *tmp_ste_info; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; + struct mlx5dr_ste_send_info ste_info_head; + struct mlx5dr_ste *next_ste, *first_ste; + bool put_on_origin_table = true; + struct mlx5dr_ste_htbl *stats_tbl; + LIST_HEAD(send_ste_list); + + first_ste = list_first_entry(mlx5dr_ste_get_miss_list(ste), + struct mlx5dr_ste, miss_list_node); + stats_tbl = first_ste->htbl; + + /* Two options: + * 1. ste is head: + * a. head ste is the only ste in the miss list + * b. head ste is not the only ste in the miss-list + * 2. ste is not head + */ + if (first_ste == ste) { /* Ste is the head */ + struct mlx5dr_ste *last_ste; + + last_ste = list_last_entry(mlx5dr_ste_get_miss_list(ste), + struct mlx5dr_ste, miss_list_node); + if (last_ste == first_ste) + next_ste = NULL; + else + next_ste = list_next_entry(ste, miss_list_node); + + if (!next_ste) { + /* One and only entry in the list */ + dr_ste_remove_head_ste(ste_ctx, ste, + nic_matcher, + &ste_info_head, + &send_ste_list, + stats_tbl); + } else { + /* First but not only entry in the list */ + dr_ste_replace_head_ste(nic_matcher, ste, + next_ste, &ste_info_head, + &send_ste_list, stats_tbl); + put_on_origin_table = false; + } + } else { /* Ste in the middle of the list */ + dr_ste_remove_middle_ste(ste_ctx, ste, + &ste_info_head, &send_ste_list, + stats_tbl); + } + + /* Update HW */ + list_for_each_entry_safe(cur_ste_info, tmp_ste_info, + &send_ste_list, send_list) { + list_del(&cur_ste_info->send_list); + mlx5dr_send_postsend_ste(dmn, cur_ste_info->ste, + cur_ste_info->data, cur_ste_info->size, + cur_ste_info->offset); + } + + if (put_on_origin_table) + mlx5dr_htbl_put(ste->htbl); +} + +bool mlx5dr_ste_equal_tag(void *src, void *dst) +{ + struct dr_hw_ste_format *s_hw_ste = (struct dr_hw_ste_format *)src; + struct dr_hw_ste_format *d_hw_ste = (struct dr_hw_ste_format *)dst; + + return !memcmp(s_hw_ste->tag, d_hw_ste->tag, DR_STE_SIZE_TAG); +} + +void mlx5dr_ste_set_hit_addr_by_next_htbl(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste, + struct mlx5dr_ste_htbl *next_htbl) +{ + u64 icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(next_htbl->chunk); + u32 num_entries = + mlx5dr_icm_pool_get_chunk_num_of_entries(next_htbl->chunk); + + ste_ctx->set_hit_addr(hw_ste, icm_addr, num_entries); +} + +void mlx5dr_ste_prepare_for_postsend(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste_p, u32 ste_size) +{ + if (ste_ctx->prepare_for_postsend) + ste_ctx->prepare_for_postsend(hw_ste_p, ste_size); +} + +/* Init one ste as a pattern for ste data array */ +void mlx5dr_ste_set_formatted_ste(struct mlx5dr_ste_ctx *ste_ctx, + u16 gvmi, + enum mlx5dr_domain_nic_type nic_type, + struct mlx5dr_ste_htbl *htbl, + u8 *formatted_ste, + struct mlx5dr_htbl_connect_info *connect_info) +{ + bool is_rx = nic_type == DR_DOMAIN_NIC_TYPE_RX; + u8 tmp_hw_ste[DR_STE_SIZE] = {0}; + + ste_ctx->ste_init(formatted_ste, htbl->lu_type, is_rx, gvmi); + + /* Use temp ste because dr_ste_always_miss_addr/hit_htbl + * touches bit_mask area which doesn't exist at ste->hw_ste. + * Need to use a full-sized (DR_STE_SIZE) hw_ste. + */ + memcpy(tmp_hw_ste, formatted_ste, DR_STE_SIZE_REDUCED); + if (connect_info->type == CONNECT_HIT) + dr_ste_always_hit_htbl(ste_ctx, tmp_hw_ste, + connect_info->hit_next_htbl); + else + dr_ste_always_miss_addr(ste_ctx, tmp_hw_ste, + connect_info->miss_icm_addr); + memcpy(formatted_ste, tmp_hw_ste, DR_STE_SIZE_REDUCED); +} + +int mlx5dr_ste_htbl_init_and_postsend(struct mlx5dr_domain *dmn, + struct mlx5dr_domain_rx_tx *nic_dmn, + struct mlx5dr_ste_htbl *htbl, + struct mlx5dr_htbl_connect_info *connect_info, + bool update_hw_ste) +{ + u8 formatted_ste[DR_STE_SIZE] = {}; + + mlx5dr_ste_set_formatted_ste(dmn->ste_ctx, + dmn->info.caps.gvmi, + nic_dmn->type, + htbl, + formatted_ste, + connect_info); + + return mlx5dr_send_postsend_formatted_htbl(dmn, htbl, formatted_ste, update_hw_ste); +} + +int mlx5dr_ste_create_next_htbl(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste *ste, + u8 *cur_hw_ste, + enum mlx5dr_icm_chunk_size log_table_size) +{ + struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; + struct mlx5dr_htbl_connect_info info; + struct mlx5dr_ste_htbl *next_htbl; + + if (!mlx5dr_ste_is_last_in_rule(nic_matcher, ste->ste_chain_location)) { + u16 next_lu_type; + u16 byte_mask; + + next_lu_type = ste_ctx->get_next_lu_type(cur_hw_ste); + byte_mask = ste_ctx->get_byte_mask(cur_hw_ste); + + next_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, + log_table_size, + next_lu_type, + byte_mask); + if (!next_htbl) { + mlx5dr_dbg(dmn, "Failed allocating table\n"); + return -ENOMEM; + } + + /* Write new table to HW */ + info.type = CONNECT_MISS; + info.miss_icm_addr = + mlx5dr_icm_pool_get_chunk_icm_addr(nic_matcher->e_anchor->chunk); + if (mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, next_htbl, + &info, false)) { + mlx5dr_info(dmn, "Failed writing table to HW\n"); + goto free_table; + } + + mlx5dr_ste_set_hit_addr_by_next_htbl(ste_ctx, + cur_hw_ste, next_htbl); + ste->next_htbl = next_htbl; + next_htbl->pointing_ste = ste; + } + + return 0; + +free_table: + mlx5dr_ste_htbl_free(next_htbl); + return -ENOENT; +} + +struct mlx5dr_ste_htbl *mlx5dr_ste_htbl_alloc(struct mlx5dr_icm_pool *pool, + enum mlx5dr_icm_chunk_size chunk_size, + u16 lu_type, u16 byte_mask) +{ + struct mlx5dr_icm_chunk *chunk; + struct mlx5dr_ste_htbl *htbl; + u32 num_entries; + int i; + + htbl = mlx5dr_icm_pool_alloc_htbl(pool); + if (!htbl) + return NULL; + + chunk = mlx5dr_icm_alloc_chunk(pool, chunk_size); + if (!chunk) + goto out_free_htbl; + + htbl->chunk = chunk; + htbl->lu_type = lu_type; + htbl->byte_mask = byte_mask; + htbl->refcount = 0; + htbl->pointing_ste = NULL; + htbl->ctrl.num_of_valid_entries = 0; + htbl->ctrl.num_of_collisions = 0; + num_entries = mlx5dr_icm_pool_get_chunk_num_of_entries(chunk); + + for (i = 0; i < num_entries; i++) { + struct mlx5dr_ste *ste = &chunk->ste_arr[i]; + + ste->htbl = htbl; + ste->refcount = 0; + INIT_LIST_HEAD(&ste->miss_list_node); + INIT_LIST_HEAD(&chunk->miss_list[i]); + } + + return htbl; + +out_free_htbl: + mlx5dr_icm_pool_free_htbl(pool, htbl); + return NULL; +} + +int mlx5dr_ste_htbl_free(struct mlx5dr_ste_htbl *htbl) +{ + struct mlx5dr_icm_pool *pool = htbl->chunk->buddy_mem->pool; + + if (htbl->refcount) + return -EBUSY; + + mlx5dr_icm_free_chunk(htbl->chunk); + mlx5dr_icm_pool_free_htbl(pool, htbl); + + return 0; +} + +void mlx5dr_ste_set_actions_tx(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_domain *dmn, + u8 *action_type_set, + u8 *hw_ste_arr, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes) +{ + ste_ctx->set_actions_tx(dmn, action_type_set, ste_ctx->actions_caps, + hw_ste_arr, attr, added_stes); +} + +void mlx5dr_ste_set_actions_rx(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_domain *dmn, + u8 *action_type_set, + u8 *hw_ste_arr, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes) +{ + ste_ctx->set_actions_rx(dmn, action_type_set, ste_ctx->actions_caps, + hw_ste_arr, attr, added_stes); +} + +const struct mlx5dr_ste_action_modify_field * +mlx5dr_ste_conv_modify_hdr_sw_field(struct mlx5dr_ste_ctx *ste_ctx, u16 sw_field) +{ + const struct mlx5dr_ste_action_modify_field *hw_field; + + if (sw_field >= ste_ctx->modify_field_arr_sz) + return NULL; + + hw_field = &ste_ctx->modify_field_arr[sw_field]; + if (!hw_field->end && !hw_field->start) + return NULL; + + return hw_field; +} + +void mlx5dr_ste_set_action_set(struct mlx5dr_ste_ctx *ste_ctx, + __be64 *hw_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data) +{ + ste_ctx->set_action_set((u8 *)hw_action, + hw_field, shifter, length, data); +} + +void mlx5dr_ste_set_action_add(struct mlx5dr_ste_ctx *ste_ctx, + __be64 *hw_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data) +{ + ste_ctx->set_action_add((u8 *)hw_action, + hw_field, shifter, length, data); +} + +void mlx5dr_ste_set_action_copy(struct mlx5dr_ste_ctx *ste_ctx, + __be64 *hw_action, + u8 dst_hw_field, + u8 dst_shifter, + u8 dst_len, + u8 src_hw_field, + u8 src_shifter) +{ + ste_ctx->set_action_copy((u8 *)hw_action, + dst_hw_field, dst_shifter, dst_len, + src_hw_field, src_shifter); +} + +int mlx5dr_ste_set_action_decap_l3_list(struct mlx5dr_ste_ctx *ste_ctx, + void *data, u32 data_sz, + u8 *hw_action, u32 hw_action_sz, + u16 *used_hw_action_num) +{ + /* Only Ethernet frame is supported, with VLAN (18) or without (14) */ + if (data_sz != HDR_LEN_L2 && data_sz != HDR_LEN_L2_W_VLAN) + return -EINVAL; + + return ste_ctx->set_action_decap_l3_list(data, data_sz, + hw_action, hw_action_sz, + used_hw_action_num); +} + +static int +dr_ste_alloc_modify_hdr_chunk(struct mlx5dr_action *action) +{ + struct mlx5dr_domain *dmn = action->rewrite->dmn; + u32 chunk_size; + int ret; + + chunk_size = ilog2(roundup_pow_of_two(action->rewrite->num_of_actions)); + + /* HW modify action index granularity is at least 64B */ + chunk_size = max_t(u32, chunk_size, DR_CHUNK_SIZE_8); + + action->rewrite->chunk = mlx5dr_icm_alloc_chunk(dmn->action_icm_pool, + chunk_size); + if (!action->rewrite->chunk) + return -ENOMEM; + + action->rewrite->index = (mlx5dr_icm_pool_get_chunk_icm_addr(action->rewrite->chunk) - + dmn->info.caps.hdr_modify_icm_addr) / + DR_ACTION_CACHE_LINE_SIZE; + + ret = mlx5dr_send_postsend_action(action->rewrite->dmn, action); + if (ret) + goto free_chunk; + + return 0; + +free_chunk: + mlx5dr_icm_free_chunk(action->rewrite->chunk); + return -ENOMEM; +} + +static void dr_ste_free_modify_hdr_chunk(struct mlx5dr_action *action) +{ + mlx5dr_icm_free_chunk(action->rewrite->chunk); +} + +int mlx5dr_ste_alloc_modify_hdr(struct mlx5dr_action *action) +{ + struct mlx5dr_domain *dmn = action->rewrite->dmn; + + if (mlx5dr_domain_is_support_ptrn_arg(dmn)) + return dmn->ste_ctx->alloc_modify_hdr_chunk(action); + + return dr_ste_alloc_modify_hdr_chunk(action); +} + +void mlx5dr_ste_free_modify_hdr(struct mlx5dr_action *action) +{ + struct mlx5dr_domain *dmn = action->rewrite->dmn; + + if (mlx5dr_domain_is_support_ptrn_arg(dmn)) + return dmn->ste_ctx->dealloc_modify_hdr_chunk(action); + + return dr_ste_free_modify_hdr_chunk(action); +} + +static int dr_ste_build_pre_check_spec(struct mlx5dr_domain *dmn, + struct mlx5dr_match_spec *spec) +{ + if (spec->ip_version) { + if (spec->ip_version != 0xf) { + mlx5dr_err(dmn, + "Partial ip_version mask with src/dst IP is not supported\n"); + return -EINVAL; + } + } else if (spec->ethertype != 0xffff && + (DR_MASK_IS_SRC_IP_SET(spec) || DR_MASK_IS_DST_IP_SET(spec))) { + mlx5dr_err(dmn, + "Partial/no ethertype mask with src/dst IP is not supported\n"); + return -EINVAL; + } + + return 0; +} + +int mlx5dr_ste_build_pre_check(struct mlx5dr_domain *dmn, + u8 match_criteria, + struct mlx5dr_match_param *mask, + struct mlx5dr_match_param *value) +{ + if (value) + return 0; + + if (match_criteria & DR_MATCHER_CRITERIA_MISC) { + if (mask->misc.source_port && mask->misc.source_port != 0xffff) { + mlx5dr_err(dmn, + "Partial mask source_port is not supported\n"); + return -EINVAL; + } + if (mask->misc.source_eswitch_owner_vhca_id && + mask->misc.source_eswitch_owner_vhca_id != 0xffff) { + mlx5dr_err(dmn, + "Partial mask source_eswitch_owner_vhca_id is not supported\n"); + return -EINVAL; + } + } + + if ((match_criteria & DR_MATCHER_CRITERIA_OUTER) && + dr_ste_build_pre_check_spec(dmn, &mask->outer)) + return -EINVAL; + + if ((match_criteria & DR_MATCHER_CRITERIA_INNER) && + dr_ste_build_pre_check_spec(dmn, &mask->inner)) + return -EINVAL; + + return 0; +} + +int mlx5dr_ste_build_ste_arr(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_match_param *value, + u8 *ste_arr) +{ + struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; + bool is_rx = nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX; + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx; + struct mlx5dr_ste_build *sb; + int ret, i; + + ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria, + &matcher->mask, value); + if (ret) + return ret; + + sb = nic_matcher->ste_builder; + for (i = 0; i < nic_matcher->num_of_builders; i++) { + ste_ctx->ste_init(ste_arr, + sb->lu_type, + is_rx, + dmn->info.caps.gvmi); + + mlx5dr_ste_set_bit_mask(ste_arr, sb->bit_mask); + + ret = sb->ste_build_tag_func(value, sb, dr_ste_get_tag(ste_arr)); + if (ret) + return ret; + + /* Connect the STEs */ + if (i < (nic_matcher->num_of_builders - 1)) { + /* Need the next builder for these fields, + * not relevant for the last ste in the chain. + */ + sb++; + ste_ctx->set_next_lu_type(ste_arr, sb->lu_type); + ste_ctx->set_byte_mask(ste_arr, sb->byte_mask); + } + ste_arr += DR_STE_SIZE; + } + return 0; +} + +#define IFC_GET_CLR(typ, p, fld, clear) ({ \ + void *__p = (p); \ + u32 __t = MLX5_GET(typ, __p, fld); \ + if (clear) \ + MLX5_SET(typ, __p, fld, 0); \ + __t; \ +}) + +#define memcpy_and_clear(to, from, len, clear) ({ \ + void *__to = (to), *__from = (from); \ + size_t __len = (len); \ + memcpy(__to, __from, __len); \ + if (clear) \ + memset(__from, 0, __len); \ +}) + +static void dr_ste_copy_mask_misc(char *mask, struct mlx5dr_match_misc *spec, bool clr) +{ + spec->gre_c_present = IFC_GET_CLR(fte_match_set_misc, mask, gre_c_present, clr); + spec->gre_k_present = IFC_GET_CLR(fte_match_set_misc, mask, gre_k_present, clr); + spec->gre_s_present = IFC_GET_CLR(fte_match_set_misc, mask, gre_s_present, clr); + spec->source_vhca_port = IFC_GET_CLR(fte_match_set_misc, mask, source_vhca_port, clr); + spec->source_sqn = IFC_GET_CLR(fte_match_set_misc, mask, source_sqn, clr); + + spec->source_port = IFC_GET_CLR(fte_match_set_misc, mask, source_port, clr); + spec->source_eswitch_owner_vhca_id = + IFC_GET_CLR(fte_match_set_misc, mask, source_eswitch_owner_vhca_id, clr); + + spec->outer_second_prio = IFC_GET_CLR(fte_match_set_misc, mask, outer_second_prio, clr); + spec->outer_second_cfi = IFC_GET_CLR(fte_match_set_misc, mask, outer_second_cfi, clr); + spec->outer_second_vid = IFC_GET_CLR(fte_match_set_misc, mask, outer_second_vid, clr); + spec->inner_second_prio = IFC_GET_CLR(fte_match_set_misc, mask, inner_second_prio, clr); + spec->inner_second_cfi = IFC_GET_CLR(fte_match_set_misc, mask, inner_second_cfi, clr); + spec->inner_second_vid = IFC_GET_CLR(fte_match_set_misc, mask, inner_second_vid, clr); + + spec->outer_second_cvlan_tag = + IFC_GET_CLR(fte_match_set_misc, mask, outer_second_cvlan_tag, clr); + spec->inner_second_cvlan_tag = + IFC_GET_CLR(fte_match_set_misc, mask, inner_second_cvlan_tag, clr); + spec->outer_second_svlan_tag = + IFC_GET_CLR(fte_match_set_misc, mask, outer_second_svlan_tag, clr); + spec->inner_second_svlan_tag = + IFC_GET_CLR(fte_match_set_misc, mask, inner_second_svlan_tag, clr); + spec->gre_protocol = IFC_GET_CLR(fte_match_set_misc, mask, gre_protocol, clr); + + spec->gre_key_h = IFC_GET_CLR(fte_match_set_misc, mask, gre_key.nvgre.hi, clr); + spec->gre_key_l = IFC_GET_CLR(fte_match_set_misc, mask, gre_key.nvgre.lo, clr); + + spec->vxlan_vni = IFC_GET_CLR(fte_match_set_misc, mask, vxlan_vni, clr); + + spec->geneve_vni = IFC_GET_CLR(fte_match_set_misc, mask, geneve_vni, clr); + spec->geneve_tlv_option_0_exist = + IFC_GET_CLR(fte_match_set_misc, mask, geneve_tlv_option_0_exist, clr); + spec->geneve_oam = IFC_GET_CLR(fte_match_set_misc, mask, geneve_oam, clr); + + spec->outer_ipv6_flow_label = + IFC_GET_CLR(fte_match_set_misc, mask, outer_ipv6_flow_label, clr); + + spec->inner_ipv6_flow_label = + IFC_GET_CLR(fte_match_set_misc, mask, inner_ipv6_flow_label, clr); + + spec->geneve_opt_len = IFC_GET_CLR(fte_match_set_misc, mask, geneve_opt_len, clr); + spec->geneve_protocol_type = + IFC_GET_CLR(fte_match_set_misc, mask, geneve_protocol_type, clr); + + spec->bth_dst_qp = IFC_GET_CLR(fte_match_set_misc, mask, bth_dst_qp, clr); +} + +static void dr_ste_copy_mask_spec(char *mask, struct mlx5dr_match_spec *spec, bool clr) +{ + __be32 raw_ip[4]; + + spec->smac_47_16 = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, smac_47_16, clr); + + spec->smac_15_0 = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, smac_15_0, clr); + spec->ethertype = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ethertype, clr); + + spec->dmac_47_16 = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, dmac_47_16, clr); + + spec->dmac_15_0 = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, dmac_15_0, clr); + spec->first_prio = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, first_prio, clr); + spec->first_cfi = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, first_cfi, clr); + spec->first_vid = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, first_vid, clr); + + spec->ip_protocol = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ip_protocol, clr); + spec->ip_dscp = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ip_dscp, clr); + spec->ip_ecn = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ip_ecn, clr); + spec->cvlan_tag = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, cvlan_tag, clr); + spec->svlan_tag = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, svlan_tag, clr); + spec->frag = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, frag, clr); + spec->ip_version = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ip_version, clr); + spec->tcp_flags = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, tcp_flags, clr); + spec->tcp_sport = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, tcp_sport, clr); + spec->tcp_dport = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, tcp_dport, clr); + + spec->ipv4_ihl = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ipv4_ihl, clr); + spec->ttl_hoplimit = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, ttl_hoplimit, clr); + + spec->udp_sport = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, udp_sport, clr); + spec->udp_dport = IFC_GET_CLR(fte_match_set_lyr_2_4, mask, udp_dport, clr); + + memcpy_and_clear(raw_ip, MLX5_ADDR_OF(fte_match_set_lyr_2_4, mask, + src_ipv4_src_ipv6.ipv6_layout.ipv6), + sizeof(raw_ip), clr); + + spec->src_ip_127_96 = be32_to_cpu(raw_ip[0]); + spec->src_ip_95_64 = be32_to_cpu(raw_ip[1]); + spec->src_ip_63_32 = be32_to_cpu(raw_ip[2]); + spec->src_ip_31_0 = be32_to_cpu(raw_ip[3]); + + memcpy_and_clear(raw_ip, MLX5_ADDR_OF(fte_match_set_lyr_2_4, mask, + dst_ipv4_dst_ipv6.ipv6_layout.ipv6), + sizeof(raw_ip), clr); + + spec->dst_ip_127_96 = be32_to_cpu(raw_ip[0]); + spec->dst_ip_95_64 = be32_to_cpu(raw_ip[1]); + spec->dst_ip_63_32 = be32_to_cpu(raw_ip[2]); + spec->dst_ip_31_0 = be32_to_cpu(raw_ip[3]); +} + +static void dr_ste_copy_mask_misc2(char *mask, struct mlx5dr_match_misc2 *spec, bool clr) +{ + spec->outer_first_mpls_label = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls.mpls_label, clr); + spec->outer_first_mpls_exp = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls.mpls_exp, clr); + spec->outer_first_mpls_s_bos = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls.mpls_s_bos, clr); + spec->outer_first_mpls_ttl = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls.mpls_ttl, clr); + spec->inner_first_mpls_label = + IFC_GET_CLR(fte_match_set_misc2, mask, inner_first_mpls.mpls_label, clr); + spec->inner_first_mpls_exp = + IFC_GET_CLR(fte_match_set_misc2, mask, inner_first_mpls.mpls_exp, clr); + spec->inner_first_mpls_s_bos = + IFC_GET_CLR(fte_match_set_misc2, mask, inner_first_mpls.mpls_s_bos, clr); + spec->inner_first_mpls_ttl = + IFC_GET_CLR(fte_match_set_misc2, mask, inner_first_mpls.mpls_ttl, clr); + spec->outer_first_mpls_over_gre_label = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_gre.mpls_label, clr); + spec->outer_first_mpls_over_gre_exp = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_gre.mpls_exp, clr); + spec->outer_first_mpls_over_gre_s_bos = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_gre.mpls_s_bos, clr); + spec->outer_first_mpls_over_gre_ttl = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_gre.mpls_ttl, clr); + spec->outer_first_mpls_over_udp_label = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_udp.mpls_label, clr); + spec->outer_first_mpls_over_udp_exp = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_udp.mpls_exp, clr); + spec->outer_first_mpls_over_udp_s_bos = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_udp.mpls_s_bos, clr); + spec->outer_first_mpls_over_udp_ttl = + IFC_GET_CLR(fte_match_set_misc2, mask, outer_first_mpls_over_udp.mpls_ttl, clr); + spec->metadata_reg_c_7 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_7, clr); + spec->metadata_reg_c_6 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_6, clr); + spec->metadata_reg_c_5 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_5, clr); + spec->metadata_reg_c_4 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_4, clr); + spec->metadata_reg_c_3 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_3, clr); + spec->metadata_reg_c_2 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_2, clr); + spec->metadata_reg_c_1 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_1, clr); + spec->metadata_reg_c_0 = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_c_0, clr); + spec->metadata_reg_a = IFC_GET_CLR(fte_match_set_misc2, mask, metadata_reg_a, clr); +} + +static void dr_ste_copy_mask_misc3(char *mask, struct mlx5dr_match_misc3 *spec, bool clr) +{ + spec->inner_tcp_seq_num = IFC_GET_CLR(fte_match_set_misc3, mask, inner_tcp_seq_num, clr); + spec->outer_tcp_seq_num = IFC_GET_CLR(fte_match_set_misc3, mask, outer_tcp_seq_num, clr); + spec->inner_tcp_ack_num = IFC_GET_CLR(fte_match_set_misc3, mask, inner_tcp_ack_num, clr); + spec->outer_tcp_ack_num = IFC_GET_CLR(fte_match_set_misc3, mask, outer_tcp_ack_num, clr); + spec->outer_vxlan_gpe_vni = + IFC_GET_CLR(fte_match_set_misc3, mask, outer_vxlan_gpe_vni, clr); + spec->outer_vxlan_gpe_next_protocol = + IFC_GET_CLR(fte_match_set_misc3, mask, outer_vxlan_gpe_next_protocol, clr); + spec->outer_vxlan_gpe_flags = + IFC_GET_CLR(fte_match_set_misc3, mask, outer_vxlan_gpe_flags, clr); + spec->icmpv4_header_data = IFC_GET_CLR(fte_match_set_misc3, mask, icmp_header_data, clr); + spec->icmpv6_header_data = + IFC_GET_CLR(fte_match_set_misc3, mask, icmpv6_header_data, clr); + spec->icmpv4_type = IFC_GET_CLR(fte_match_set_misc3, mask, icmp_type, clr); + spec->icmpv4_code = IFC_GET_CLR(fte_match_set_misc3, mask, icmp_code, clr); + spec->icmpv6_type = IFC_GET_CLR(fte_match_set_misc3, mask, icmpv6_type, clr); + spec->icmpv6_code = IFC_GET_CLR(fte_match_set_misc3, mask, icmpv6_code, clr); + spec->geneve_tlv_option_0_data = + IFC_GET_CLR(fte_match_set_misc3, mask, geneve_tlv_option_0_data, clr); + spec->gtpu_teid = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_teid, clr); + spec->gtpu_msg_flags = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_msg_flags, clr); + spec->gtpu_msg_type = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_msg_type, clr); + spec->gtpu_dw_0 = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_dw_0, clr); + spec->gtpu_dw_2 = IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_dw_2, clr); + spec->gtpu_first_ext_dw_0 = + IFC_GET_CLR(fte_match_set_misc3, mask, gtpu_first_ext_dw_0, clr); +} + +static void dr_ste_copy_mask_misc4(char *mask, struct mlx5dr_match_misc4 *spec, bool clr) +{ + spec->prog_sample_field_id_0 = + IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_id_0, clr); + spec->prog_sample_field_value_0 = + IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_value_0, clr); + spec->prog_sample_field_id_1 = + IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_id_1, clr); + spec->prog_sample_field_value_1 = + IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_value_1, clr); + spec->prog_sample_field_id_2 = + IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_id_2, clr); + spec->prog_sample_field_value_2 = + IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_value_2, clr); + spec->prog_sample_field_id_3 = + IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_id_3, clr); + spec->prog_sample_field_value_3 = + IFC_GET_CLR(fte_match_set_misc4, mask, prog_sample_field_value_3, clr); +} + +static void dr_ste_copy_mask_misc5(char *mask, struct mlx5dr_match_misc5 *spec, bool clr) +{ + spec->macsec_tag_0 = + IFC_GET_CLR(fte_match_set_misc5, mask, macsec_tag_0, clr); + spec->macsec_tag_1 = + IFC_GET_CLR(fte_match_set_misc5, mask, macsec_tag_1, clr); + spec->macsec_tag_2 = + IFC_GET_CLR(fte_match_set_misc5, mask, macsec_tag_2, clr); + spec->macsec_tag_3 = + IFC_GET_CLR(fte_match_set_misc5, mask, macsec_tag_3, clr); + spec->tunnel_header_0 = + IFC_GET_CLR(fte_match_set_misc5, mask, tunnel_header_0, clr); + spec->tunnel_header_1 = + IFC_GET_CLR(fte_match_set_misc5, mask, tunnel_header_1, clr); + spec->tunnel_header_2 = + IFC_GET_CLR(fte_match_set_misc5, mask, tunnel_header_2, clr); + spec->tunnel_header_3 = + IFC_GET_CLR(fte_match_set_misc5, mask, tunnel_header_3, clr); +} + +void mlx5dr_ste_copy_param(u8 match_criteria, + struct mlx5dr_match_param *set_param, + struct mlx5dr_match_parameters *mask, + bool clr) +{ + u8 tail_param[MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)] = {}; + u8 *data = (u8 *)mask->match_buf; + size_t param_location; + void *buff; + + if (match_criteria & DR_MATCHER_CRITERIA_OUTER) { + if (mask->match_sz < sizeof(struct mlx5dr_match_spec)) { + memcpy(tail_param, data, mask->match_sz); + buff = tail_param; + } else { + buff = mask->match_buf; + } + dr_ste_copy_mask_spec(buff, &set_param->outer, clr); + } + param_location = sizeof(struct mlx5dr_match_spec); + + if (match_criteria & DR_MATCHER_CRITERIA_MISC) { + if (mask->match_sz < param_location + + sizeof(struct mlx5dr_match_misc)) { + memcpy(tail_param, data + param_location, + mask->match_sz - param_location); + buff = tail_param; + } else { + buff = data + param_location; + } + dr_ste_copy_mask_misc(buff, &set_param->misc, clr); + } + param_location += sizeof(struct mlx5dr_match_misc); + + if (match_criteria & DR_MATCHER_CRITERIA_INNER) { + if (mask->match_sz < param_location + + sizeof(struct mlx5dr_match_spec)) { + memcpy(tail_param, data + param_location, + mask->match_sz - param_location); + buff = tail_param; + } else { + buff = data + param_location; + } + dr_ste_copy_mask_spec(buff, &set_param->inner, clr); + } + param_location += sizeof(struct mlx5dr_match_spec); + + if (match_criteria & DR_MATCHER_CRITERIA_MISC2) { + if (mask->match_sz < param_location + + sizeof(struct mlx5dr_match_misc2)) { + memcpy(tail_param, data + param_location, + mask->match_sz - param_location); + buff = tail_param; + } else { + buff = data + param_location; + } + dr_ste_copy_mask_misc2(buff, &set_param->misc2, clr); + } + + param_location += sizeof(struct mlx5dr_match_misc2); + + if (match_criteria & DR_MATCHER_CRITERIA_MISC3) { + if (mask->match_sz < param_location + + sizeof(struct mlx5dr_match_misc3)) { + memcpy(tail_param, data + param_location, + mask->match_sz - param_location); + buff = tail_param; + } else { + buff = data + param_location; + } + dr_ste_copy_mask_misc3(buff, &set_param->misc3, clr); + } + + param_location += sizeof(struct mlx5dr_match_misc3); + + if (match_criteria & DR_MATCHER_CRITERIA_MISC4) { + if (mask->match_sz < param_location + + sizeof(struct mlx5dr_match_misc4)) { + memcpy(tail_param, data + param_location, + mask->match_sz - param_location); + buff = tail_param; + } else { + buff = data + param_location; + } + dr_ste_copy_mask_misc4(buff, &set_param->misc4, clr); + } + + param_location += sizeof(struct mlx5dr_match_misc4); + + if (match_criteria & DR_MATCHER_CRITERIA_MISC5) { + if (mask->match_sz < param_location + + sizeof(struct mlx5dr_match_misc5)) { + memcpy(tail_param, data + param_location, + mask->match_sz - param_location); + buff = tail_param; + } else { + buff = data + param_location; + } + dr_ste_copy_mask_misc5(buff, &set_param->misc5, clr); + } +} + +void mlx5dr_ste_build_eth_l2_src_dst(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l2_src_dst_init(sb, mask); +} + +void mlx5dr_ste_build_eth_l3_ipv6_dst(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l3_ipv6_dst_init(sb, mask); +} + +void mlx5dr_ste_build_eth_l3_ipv6_src(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l3_ipv6_src_init(sb, mask); +} + +void mlx5dr_ste_build_eth_l3_ipv4_5_tuple(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l3_ipv4_5_tuple_init(sb, mask); +} + +void mlx5dr_ste_build_eth_l2_src(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l2_src_init(sb, mask); +} + +void mlx5dr_ste_build_eth_l2_dst(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l2_dst_init(sb, mask); +} + +void mlx5dr_ste_build_eth_l2_tnl(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l2_tnl_init(sb, mask); +} + +void mlx5dr_ste_build_eth_l3_ipv4_misc(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l3_ipv4_misc_init(sb, mask); +} + +void mlx5dr_ste_build_eth_ipv6_l3_l4(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_ipv6_l3_l4_init(sb, mask); +} + +static int dr_ste_build_empty_always_hit_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + return 0; +} + +void mlx5dr_ste_build_empty_always_hit(struct mlx5dr_ste_build *sb, bool rx) +{ + sb->rx = rx; + sb->lu_type = MLX5DR_STE_LU_TYPE_DONT_CARE; + sb->byte_mask = 0; + sb->ste_build_tag_func = &dr_ste_build_empty_always_hit_tag; +} + +void mlx5dr_ste_build_mpls(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_mpls_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_gre(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_tnl_gre_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_mpls_over_gre(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + sb->caps = caps; + return ste_ctx->build_tnl_mpls_over_gre_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_mpls_over_udp(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + sb->caps = caps; + return ste_ctx->build_tnl_mpls_over_udp_init(sb, mask); +} + +void mlx5dr_ste_build_icmp(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + sb->caps = caps; + ste_ctx->build_icmp_init(sb, mask); +} + +void mlx5dr_ste_build_general_purpose(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_general_purpose_init(sb, mask); +} + +void mlx5dr_ste_build_eth_l4_misc(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_eth_l4_misc_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_vxlan_gpe(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_tnl_vxlan_gpe_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_geneve(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_tnl_geneve_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_geneve_tlv_opt(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx) +{ + sb->rx = rx; + sb->caps = caps; + sb->inner = inner; + ste_ctx->build_tnl_geneve_tlv_opt_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_geneve_tlv_opt_exist(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx) +{ + if (!ste_ctx->build_tnl_geneve_tlv_opt_exist_init) + return; + + sb->rx = rx; + sb->caps = caps; + sb->inner = inner; + ste_ctx->build_tnl_geneve_tlv_opt_exist_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_gtpu(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_tnl_gtpu_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_gtpu_flex_parser_0(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx) +{ + sb->rx = rx; + sb->caps = caps; + sb->inner = inner; + ste_ctx->build_tnl_gtpu_flex_parser_0_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_gtpu_flex_parser_1(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx) +{ + sb->rx = rx; + sb->caps = caps; + sb->inner = inner; + ste_ctx->build_tnl_gtpu_flex_parser_1_init(sb, mask); +} + +void mlx5dr_ste_build_register_0(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_register_0_init(sb, mask); +} + +void mlx5dr_ste_build_register_1(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_register_1_init(sb, mask); +} + +void mlx5dr_ste_build_src_gvmi_qpn(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn, + bool inner, bool rx) +{ + /* Set vhca_id_valid before we reset source_eswitch_owner_vhca_id */ + sb->vhca_id_valid = mask->misc.source_eswitch_owner_vhca_id; + + sb->rx = rx; + sb->dmn = dmn; + sb->inner = inner; + ste_ctx->build_src_gvmi_qpn_init(sb, mask); +} + +void mlx5dr_ste_build_flex_parser_0(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_flex_parser_0_init(sb, mask); +} + +void mlx5dr_ste_build_flex_parser_1(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_flex_parser_1_init(sb, mask); +} + +void mlx5dr_ste_build_tnl_header_0_1(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + sb->rx = rx; + sb->inner = inner; + ste_ctx->build_tnl_header_0_1_init(sb, mask); +} + +struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx(u8 version) +{ + if (version == MLX5_STEERING_FORMAT_CONNECTX_5) + return mlx5dr_ste_get_ctx_v0(); + else if (version == MLX5_STEERING_FORMAT_CONNECTX_6DX) + return mlx5dr_ste_get_ctx_v1(); + else if (version == MLX5_STEERING_FORMAT_CONNECTX_7) + return mlx5dr_ste_get_ctx_v2(); + + return NULL; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.h new file mode 100644 index 00000000000000..54a6619c3ecbf8 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste.h @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. */ + +#ifndef _DR_STE_ +#define _DR_STE_ + +#include "dr_types.h" + +#define STE_IPV4 0x1 +#define STE_IPV6 0x2 +#define STE_TCP 0x1 +#define STE_UDP 0x2 +#define STE_SPI 0x3 +#define IP_VERSION_IPV4 0x4 +#define IP_VERSION_IPV6 0x6 +#define STE_SVLAN 0x1 +#define STE_CVLAN 0x2 +#define HDR_LEN_L2_MACS 0xC +#define HDR_LEN_L2_VLAN 0x4 +#define HDR_LEN_L2_ETHER 0x2 +#define HDR_LEN_L2 (HDR_LEN_L2_MACS + HDR_LEN_L2_ETHER) +#define HDR_LEN_L2_W_VLAN (HDR_LEN_L2 + HDR_LEN_L2_VLAN) + +/* Set to STE a specific value using DR_STE_SET */ +#define DR_STE_SET_VAL(lookup_type, tag, t_fname, spec, s_fname, value) do { \ + if ((spec)->s_fname) { \ + MLX5_SET(ste_##lookup_type, tag, t_fname, value); \ + (spec)->s_fname = 0; \ + } \ +} while (0) + +/* Set to STE spec->s_fname to tag->t_fname set spec->s_fname as used */ +#define DR_STE_SET_TAG(lookup_type, tag, t_fname, spec, s_fname) \ + DR_STE_SET_VAL(lookup_type, tag, t_fname, spec, s_fname, spec->s_fname) + +/* Set to STE -1 to tag->t_fname and set spec->s_fname as used */ +#define DR_STE_SET_ONES(lookup_type, tag, t_fname, spec, s_fname) \ + DR_STE_SET_VAL(lookup_type, tag, t_fname, spec, s_fname, -1) + +#define DR_STE_SET_TCP_FLAGS(lookup_type, tag, spec) do { \ + MLX5_SET(ste_##lookup_type, tag, tcp_ns, !!((spec)->tcp_flags & (1 << 8))); \ + MLX5_SET(ste_##lookup_type, tag, tcp_cwr, !!((spec)->tcp_flags & (1 << 7))); \ + MLX5_SET(ste_##lookup_type, tag, tcp_ece, !!((spec)->tcp_flags & (1 << 6))); \ + MLX5_SET(ste_##lookup_type, tag, tcp_urg, !!((spec)->tcp_flags & (1 << 5))); \ + MLX5_SET(ste_##lookup_type, tag, tcp_ack, !!((spec)->tcp_flags & (1 << 4))); \ + MLX5_SET(ste_##lookup_type, tag, tcp_psh, !!((spec)->tcp_flags & (1 << 3))); \ + MLX5_SET(ste_##lookup_type, tag, tcp_rst, !!((spec)->tcp_flags & (1 << 2))); \ + MLX5_SET(ste_##lookup_type, tag, tcp_syn, !!((spec)->tcp_flags & (1 << 1))); \ + MLX5_SET(ste_##lookup_type, tag, tcp_fin, !!((spec)->tcp_flags & (1 << 0))); \ +} while (0) + +#define DR_STE_SET_MPLS(lookup_type, mask, in_out, tag) do { \ + struct mlx5dr_match_misc2 *_mask = mask; \ + u8 *_tag = tag; \ + DR_STE_SET_TAG(lookup_type, _tag, mpls0_label, _mask, \ + in_out##_first_mpls_label);\ + DR_STE_SET_TAG(lookup_type, _tag, mpls0_s_bos, _mask, \ + in_out##_first_mpls_s_bos); \ + DR_STE_SET_TAG(lookup_type, _tag, mpls0_exp, _mask, \ + in_out##_first_mpls_exp); \ + DR_STE_SET_TAG(lookup_type, _tag, mpls0_ttl, _mask, \ + in_out##_first_mpls_ttl); \ +} while (0) + +#define DR_STE_SET_FLEX_PARSER_FIELD(tag, fname, caps, spec) do { \ + u8 parser_id = (caps)->flex_parser_id_##fname; \ + u8 *parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); \ + *(__be32 *)parser_ptr = cpu_to_be32((spec)->fname);\ + (spec)->fname = 0;\ +} while (0) + +#define DR_STE_IS_OUTER_MPLS_OVER_GRE_SET(_misc) (\ + (_misc)->outer_first_mpls_over_gre_label || \ + (_misc)->outer_first_mpls_over_gre_exp || \ + (_misc)->outer_first_mpls_over_gre_s_bos || \ + (_misc)->outer_first_mpls_over_gre_ttl) + +#define DR_STE_IS_OUTER_MPLS_OVER_UDP_SET(_misc) (\ + (_misc)->outer_first_mpls_over_udp_label || \ + (_misc)->outer_first_mpls_over_udp_exp || \ + (_misc)->outer_first_mpls_over_udp_s_bos || \ + (_misc)->outer_first_mpls_over_udp_ttl) + +enum dr_ste_action_modify_type_l3 { + DR_STE_ACTION_MDFY_TYPE_L3_NONE = 0x0, + DR_STE_ACTION_MDFY_TYPE_L3_IPV4 = 0x1, + DR_STE_ACTION_MDFY_TYPE_L3_IPV6 = 0x2, +}; + +enum dr_ste_action_modify_type_l4 { + DR_STE_ACTION_MDFY_TYPE_L4_NONE = 0x0, + DR_STE_ACTION_MDFY_TYPE_L4_TCP = 0x1, + DR_STE_ACTION_MDFY_TYPE_L4_UDP = 0x2, +}; + +enum { + HDR_MPLS_OFFSET_LABEL = 12, + HDR_MPLS_OFFSET_EXP = 9, + HDR_MPLS_OFFSET_S_BOS = 8, + HDR_MPLS_OFFSET_TTL = 0, +}; + +u16 mlx5dr_ste_conv_bit_to_byte_mask(u8 *bit_mask); + +static inline u8 * +dr_ste_calc_flex_parser_offset(u8 *tag, u8 parser_id) +{ + /* Calculate tag byte offset based on flex parser id */ + return tag + 4 * (3 - (parser_id % 4)); +} + +#define DR_STE_CTX_BUILDER(fname) \ + ((*build_##fname##_init)(struct mlx5dr_ste_build *sb, \ + struct mlx5dr_match_param *mask)) + +struct mlx5dr_ste_ctx { + /* Builders */ + void DR_STE_CTX_BUILDER(eth_l2_src_dst); + void DR_STE_CTX_BUILDER(eth_l3_ipv6_src); + void DR_STE_CTX_BUILDER(eth_l3_ipv6_dst); + void DR_STE_CTX_BUILDER(eth_l3_ipv4_5_tuple); + void DR_STE_CTX_BUILDER(eth_l2_src); + void DR_STE_CTX_BUILDER(eth_l2_dst); + void DR_STE_CTX_BUILDER(eth_l2_tnl); + void DR_STE_CTX_BUILDER(eth_l3_ipv4_misc); + void DR_STE_CTX_BUILDER(eth_ipv6_l3_l4); + void DR_STE_CTX_BUILDER(mpls); + void DR_STE_CTX_BUILDER(tnl_gre); + void DR_STE_CTX_BUILDER(tnl_mpls); + void DR_STE_CTX_BUILDER(tnl_mpls_over_gre); + void DR_STE_CTX_BUILDER(tnl_mpls_over_udp); + void DR_STE_CTX_BUILDER(icmp); + void DR_STE_CTX_BUILDER(general_purpose); + void DR_STE_CTX_BUILDER(eth_l4_misc); + void DR_STE_CTX_BUILDER(tnl_vxlan_gpe); + void DR_STE_CTX_BUILDER(tnl_geneve); + void DR_STE_CTX_BUILDER(tnl_geneve_tlv_opt); + void DR_STE_CTX_BUILDER(tnl_geneve_tlv_opt_exist); + void DR_STE_CTX_BUILDER(register_0); + void DR_STE_CTX_BUILDER(register_1); + void DR_STE_CTX_BUILDER(src_gvmi_qpn); + void DR_STE_CTX_BUILDER(flex_parser_0); + void DR_STE_CTX_BUILDER(flex_parser_1); + void DR_STE_CTX_BUILDER(tnl_gtpu); + void DR_STE_CTX_BUILDER(tnl_header_0_1); + void DR_STE_CTX_BUILDER(tnl_gtpu_flex_parser_0); + void DR_STE_CTX_BUILDER(tnl_gtpu_flex_parser_1); + + /* Getters and Setters */ + void (*ste_init)(u8 *hw_ste_p, u16 lu_type, + bool is_rx, u16 gvmi); + void (*set_next_lu_type)(u8 *hw_ste_p, u16 lu_type); + u16 (*get_next_lu_type)(u8 *hw_ste_p); + bool (*is_miss_addr_set)(u8 *hw_ste_p); + void (*set_miss_addr)(u8 *hw_ste_p, u64 miss_addr); + u64 (*get_miss_addr)(u8 *hw_ste_p); + void (*set_hit_addr)(u8 *hw_ste_p, u64 icm_addr, u32 ht_size); + void (*set_byte_mask)(u8 *hw_ste_p, u16 byte_mask); + u16 (*get_byte_mask)(u8 *hw_ste_p); + + /* Actions */ + u32 actions_caps; + void (*set_actions_rx)(struct mlx5dr_domain *dmn, + u8 *action_type_set, + u32 actions_caps, + u8 *hw_ste_arr, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes); + void (*set_actions_tx)(struct mlx5dr_domain *dmn, + u8 *action_type_set, + u32 actions_caps, + u8 *hw_ste_arr, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes); + u32 modify_field_arr_sz; + const struct mlx5dr_ste_action_modify_field *modify_field_arr; + void (*set_action_set)(u8 *hw_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data); + void (*set_action_add)(u8 *hw_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data); + void (*set_action_copy)(u8 *hw_action, + u8 dst_hw_field, + u8 dst_shifter, + u8 dst_len, + u8 src_hw_field, + u8 src_shifter); + int (*set_action_decap_l3_list)(void *data, + u32 data_sz, + u8 *hw_action, + u32 hw_action_sz, + u16 *used_hw_action_num); + int (*alloc_modify_hdr_chunk)(struct mlx5dr_action *action); + void (*dealloc_modify_hdr_chunk)(struct mlx5dr_action *action); + + /* Send */ + void (*prepare_for_postsend)(u8 *hw_ste_p, u32 ste_size); +}; + +struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v0(void); +struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v1(void); +struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v2(void); + +#endif /* _DR_STE_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v0.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v0.c new file mode 100644 index 00000000000000..e9f6c7ed7a7bef --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v0.c @@ -0,0 +1,1962 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. */ + +#include +#include +#include "dr_ste.h" + +#define SVLAN_ETHERTYPE 0x88a8 +#define DR_STE_ENABLE_FLOW_TAG BIT(31) + +enum dr_ste_v0_entry_type { + DR_STE_TYPE_TX = 1, + DR_STE_TYPE_RX = 2, + DR_STE_TYPE_MODIFY_PKT = 6, +}; + +enum dr_ste_v0_action_tunl { + DR_STE_TUNL_ACTION_NONE = 0, + DR_STE_TUNL_ACTION_ENABLE = 1, + DR_STE_TUNL_ACTION_DECAP = 2, + DR_STE_TUNL_ACTION_L3_DECAP = 3, + DR_STE_TUNL_ACTION_POP_VLAN = 4, +}; + +enum dr_ste_v0_action_type { + DR_STE_ACTION_TYPE_PUSH_VLAN = 1, + DR_STE_ACTION_TYPE_ENCAP_L3 = 3, + DR_STE_ACTION_TYPE_ENCAP = 4, +}; + +enum dr_ste_v0_action_mdfy_op { + DR_STE_ACTION_MDFY_OP_COPY = 0x1, + DR_STE_ACTION_MDFY_OP_SET = 0x2, + DR_STE_ACTION_MDFY_OP_ADD = 0x3, +}; + +#define DR_STE_CALC_LU_TYPE(lookup_type, rx, inner) \ + ((inner) ? DR_STE_V0_LU_TYPE_##lookup_type##_I : \ + (rx) ? DR_STE_V0_LU_TYPE_##lookup_type##_D : \ + DR_STE_V0_LU_TYPE_##lookup_type##_O) + +enum { + DR_STE_V0_LU_TYPE_NOP = 0x00, + DR_STE_V0_LU_TYPE_SRC_GVMI_AND_QP = 0x05, + DR_STE_V0_LU_TYPE_ETHL2_TUNNELING_I = 0x0a, + DR_STE_V0_LU_TYPE_ETHL2_DST_O = 0x06, + DR_STE_V0_LU_TYPE_ETHL2_DST_I = 0x07, + DR_STE_V0_LU_TYPE_ETHL2_DST_D = 0x1b, + DR_STE_V0_LU_TYPE_ETHL2_SRC_O = 0x08, + DR_STE_V0_LU_TYPE_ETHL2_SRC_I = 0x09, + DR_STE_V0_LU_TYPE_ETHL2_SRC_D = 0x1c, + DR_STE_V0_LU_TYPE_ETHL2_SRC_DST_O = 0x36, + DR_STE_V0_LU_TYPE_ETHL2_SRC_DST_I = 0x37, + DR_STE_V0_LU_TYPE_ETHL2_SRC_DST_D = 0x38, + DR_STE_V0_LU_TYPE_ETHL3_IPV6_DST_O = 0x0d, + DR_STE_V0_LU_TYPE_ETHL3_IPV6_DST_I = 0x0e, + DR_STE_V0_LU_TYPE_ETHL3_IPV6_DST_D = 0x1e, + DR_STE_V0_LU_TYPE_ETHL3_IPV6_SRC_O = 0x0f, + DR_STE_V0_LU_TYPE_ETHL3_IPV6_SRC_I = 0x10, + DR_STE_V0_LU_TYPE_ETHL3_IPV6_SRC_D = 0x1f, + DR_STE_V0_LU_TYPE_ETHL3_IPV4_5_TUPLE_O = 0x11, + DR_STE_V0_LU_TYPE_ETHL3_IPV4_5_TUPLE_I = 0x12, + DR_STE_V0_LU_TYPE_ETHL3_IPV4_5_TUPLE_D = 0x20, + DR_STE_V0_LU_TYPE_ETHL3_IPV4_MISC_O = 0x29, + DR_STE_V0_LU_TYPE_ETHL3_IPV4_MISC_I = 0x2a, + DR_STE_V0_LU_TYPE_ETHL3_IPV4_MISC_D = 0x2b, + DR_STE_V0_LU_TYPE_ETHL4_O = 0x13, + DR_STE_V0_LU_TYPE_ETHL4_I = 0x14, + DR_STE_V0_LU_TYPE_ETHL4_D = 0x21, + DR_STE_V0_LU_TYPE_ETHL4_MISC_O = 0x2c, + DR_STE_V0_LU_TYPE_ETHL4_MISC_I = 0x2d, + DR_STE_V0_LU_TYPE_ETHL4_MISC_D = 0x2e, + DR_STE_V0_LU_TYPE_MPLS_FIRST_O = 0x15, + DR_STE_V0_LU_TYPE_MPLS_FIRST_I = 0x24, + DR_STE_V0_LU_TYPE_MPLS_FIRST_D = 0x25, + DR_STE_V0_LU_TYPE_GRE = 0x16, + DR_STE_V0_LU_TYPE_FLEX_PARSER_0 = 0x22, + DR_STE_V0_LU_TYPE_FLEX_PARSER_1 = 0x23, + DR_STE_V0_LU_TYPE_FLEX_PARSER_TNL_HEADER = 0x19, + DR_STE_V0_LU_TYPE_GENERAL_PURPOSE = 0x18, + DR_STE_V0_LU_TYPE_STEERING_REGISTERS_0 = 0x2f, + DR_STE_V0_LU_TYPE_STEERING_REGISTERS_1 = 0x30, + DR_STE_V0_LU_TYPE_TUNNEL_HEADER = 0x34, + DR_STE_V0_LU_TYPE_DONT_CARE = MLX5DR_STE_LU_TYPE_DONT_CARE, +}; + +enum { + DR_STE_V0_ACTION_MDFY_FLD_L2_0 = 0, + DR_STE_V0_ACTION_MDFY_FLD_L2_1 = 1, + DR_STE_V0_ACTION_MDFY_FLD_L2_2 = 2, + DR_STE_V0_ACTION_MDFY_FLD_L3_0 = 3, + DR_STE_V0_ACTION_MDFY_FLD_L3_1 = 4, + DR_STE_V0_ACTION_MDFY_FLD_L3_2 = 5, + DR_STE_V0_ACTION_MDFY_FLD_L3_3 = 6, + DR_STE_V0_ACTION_MDFY_FLD_L3_4 = 7, + DR_STE_V0_ACTION_MDFY_FLD_L4_0 = 8, + DR_STE_V0_ACTION_MDFY_FLD_L4_1 = 9, + DR_STE_V0_ACTION_MDFY_FLD_MPLS = 10, + DR_STE_V0_ACTION_MDFY_FLD_L2_TNL_0 = 11, + DR_STE_V0_ACTION_MDFY_FLD_REG_0 = 12, + DR_STE_V0_ACTION_MDFY_FLD_REG_1 = 13, + DR_STE_V0_ACTION_MDFY_FLD_REG_2 = 14, + DR_STE_V0_ACTION_MDFY_FLD_REG_3 = 15, + DR_STE_V0_ACTION_MDFY_FLD_L4_2 = 16, + DR_STE_V0_ACTION_MDFY_FLD_FLEX_0 = 17, + DR_STE_V0_ACTION_MDFY_FLD_FLEX_1 = 18, + DR_STE_V0_ACTION_MDFY_FLD_FLEX_2 = 19, + DR_STE_V0_ACTION_MDFY_FLD_FLEX_3 = 20, + DR_STE_V0_ACTION_MDFY_FLD_L2_TNL_1 = 21, + DR_STE_V0_ACTION_MDFY_FLD_METADATA = 22, + DR_STE_V0_ACTION_MDFY_FLD_RESERVED = 23, +}; + +static const struct mlx5dr_ste_action_modify_field dr_ste_v0_action_modify_field_arr[] = { + [MLX5_ACTION_IN_FIELD_OUT_SMAC_47_16] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_1, .start = 16, .end = 47, + }, + [MLX5_ACTION_IN_FIELD_OUT_SMAC_15_0] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_1, .start = 0, .end = 15, + }, + [MLX5_ACTION_IN_FIELD_OUT_ETHERTYPE] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_2, .start = 32, .end = 47, + }, + [MLX5_ACTION_IN_FIELD_OUT_DMAC_47_16] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_0, .start = 16, .end = 47, + }, + [MLX5_ACTION_IN_FIELD_OUT_DMAC_15_0] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_0, .start = 0, .end = 15, + }, + [MLX5_ACTION_IN_FIELD_OUT_IP_DSCP] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_1, .start = 0, .end = 5, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_FLAGS] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 48, .end = 56, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 0, .end = 15, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 16, .end = 31, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_IP_TTL] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_1, .start = 8, .end = 15, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_1, .start = 8, .end = 15, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 0, .end = 15, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, + }, + [MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_0, .start = 16, .end = 31, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_3, .start = 32, .end = 63, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_3, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_4, .start = 32, .end = 63, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_4, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_0, .start = 32, .end = 63, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_0, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_2, .start = 32, .end = 63, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_2, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV4] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_0, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV4] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L3_0, .start = 32, .end = 63, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_A] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_METADATA, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_B] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_METADATA, .start = 32, .end = 63, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_0] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_0, .start = 32, .end = 63, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_1] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_2] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_1, .start = 32, .end = 63, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_3] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_4] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_2, .start = 32, .end = 63, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_5] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_REG_2, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_1, .start = 32, .end = 63, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L4_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_FIRST_VID] = { + .hw_field = DR_STE_V0_ACTION_MDFY_FLD_L2_2, .start = 0, .end = 15, + }, +}; + +static void dr_ste_v0_set_entry_type(u8 *hw_ste_p, u8 entry_type) +{ + MLX5_SET(ste_general, hw_ste_p, entry_type, entry_type); +} + +static u8 dr_ste_v0_get_entry_type(u8 *hw_ste_p) +{ + return MLX5_GET(ste_general, hw_ste_p, entry_type); +} + +static void dr_ste_v0_set_miss_addr(u8 *hw_ste_p, u64 miss_addr) +{ + u64 index = miss_addr >> 6; + + /* Miss address for TX and RX STEs located in the same offsets */ + MLX5_SET(ste_rx_steering_mult, hw_ste_p, miss_address_39_32, index >> 26); + MLX5_SET(ste_rx_steering_mult, hw_ste_p, miss_address_31_6, index); +} + +static u64 dr_ste_v0_get_miss_addr(u8 *hw_ste_p) +{ + u64 index = + ((u64)MLX5_GET(ste_rx_steering_mult, hw_ste_p, miss_address_31_6) | + ((u64)MLX5_GET(ste_rx_steering_mult, hw_ste_p, miss_address_39_32)) << 26); + + return index << 6; +} + +static void dr_ste_v0_set_byte_mask(u8 *hw_ste_p, u16 byte_mask) +{ + MLX5_SET(ste_general, hw_ste_p, byte_mask, byte_mask); +} + +static u16 dr_ste_v0_get_byte_mask(u8 *hw_ste_p) +{ + return MLX5_GET(ste_general, hw_ste_p, byte_mask); +} + +static void dr_ste_v0_set_lu_type(u8 *hw_ste_p, u16 lu_type) +{ + MLX5_SET(ste_general, hw_ste_p, entry_sub_type, lu_type); +} + +static void dr_ste_v0_set_next_lu_type(u8 *hw_ste_p, u16 lu_type) +{ + MLX5_SET(ste_general, hw_ste_p, next_lu_type, lu_type); +} + +static u16 dr_ste_v0_get_next_lu_type(u8 *hw_ste_p) +{ + return MLX5_GET(ste_general, hw_ste_p, next_lu_type); +} + +static void dr_ste_v0_set_hit_gvmi(u8 *hw_ste_p, u16 gvmi) +{ + MLX5_SET(ste_general, hw_ste_p, next_table_base_63_48, gvmi); +} + +static void dr_ste_v0_set_hit_addr(u8 *hw_ste_p, u64 icm_addr, u32 ht_size) +{ + u64 index = (icm_addr >> 5) | ht_size; + + MLX5_SET(ste_general, hw_ste_p, next_table_base_39_32_size, index >> 27); + MLX5_SET(ste_general, hw_ste_p, next_table_base_31_5_size, index); +} + +static void dr_ste_v0_init_full(u8 *hw_ste_p, u16 lu_type, + enum dr_ste_v0_entry_type entry_type, u16 gvmi) +{ + dr_ste_v0_set_entry_type(hw_ste_p, entry_type); + dr_ste_v0_set_lu_type(hw_ste_p, lu_type); + dr_ste_v0_set_next_lu_type(hw_ste_p, MLX5DR_STE_LU_TYPE_DONT_CARE); + + /* Set GVMI once, this is the same for RX/TX + * bits 63_48 of next table base / miss address encode the next GVMI + */ + MLX5_SET(ste_rx_steering_mult, hw_ste_p, gvmi, gvmi); + MLX5_SET(ste_rx_steering_mult, hw_ste_p, next_table_base_63_48, gvmi); + MLX5_SET(ste_rx_steering_mult, hw_ste_p, miss_address_63_48, gvmi); +} + +static void dr_ste_v0_init(u8 *hw_ste_p, u16 lu_type, + bool is_rx, u16 gvmi) +{ + enum dr_ste_v0_entry_type entry_type; + + entry_type = is_rx ? DR_STE_TYPE_RX : DR_STE_TYPE_TX; + dr_ste_v0_init_full(hw_ste_p, lu_type, entry_type, gvmi); +} + +static void dr_ste_v0_rx_set_flow_tag(u8 *hw_ste_p, u32 flow_tag) +{ + MLX5_SET(ste_rx_steering_mult, hw_ste_p, qp_list_pointer, + DR_STE_ENABLE_FLOW_TAG | flow_tag); +} + +static void dr_ste_v0_set_counter_id(u8 *hw_ste_p, u32 ctr_id) +{ + /* This can be used for both rx_steering_mult and for sx_transmit */ + MLX5_SET(ste_rx_steering_mult, hw_ste_p, counter_trigger_15_0, ctr_id); + MLX5_SET(ste_rx_steering_mult, hw_ste_p, counter_trigger_23_16, ctr_id >> 16); +} + +static void dr_ste_v0_set_go_back_bit(u8 *hw_ste_p) +{ + MLX5_SET(ste_sx_transmit, hw_ste_p, go_back, 1); +} + +static void dr_ste_v0_set_tx_push_vlan(u8 *hw_ste_p, u32 vlan_hdr, + bool go_back) +{ + MLX5_SET(ste_sx_transmit, hw_ste_p, action_type, + DR_STE_ACTION_TYPE_PUSH_VLAN); + MLX5_SET(ste_sx_transmit, hw_ste_p, encap_pointer_vlan_data, vlan_hdr); + /* Due to HW limitation we need to set this bit, otherwise reformat + + * push vlan will not work. + */ + if (go_back) + dr_ste_v0_set_go_back_bit(hw_ste_p); +} + +static void dr_ste_v0_set_tx_encap(void *hw_ste_p, u32 reformat_id, + int size, bool encap_l3) +{ + MLX5_SET(ste_sx_transmit, hw_ste_p, action_type, + encap_l3 ? DR_STE_ACTION_TYPE_ENCAP_L3 : DR_STE_ACTION_TYPE_ENCAP); + /* The hardware expects here size in words (2 byte) */ + MLX5_SET(ste_sx_transmit, hw_ste_p, action_description, size / 2); + MLX5_SET(ste_sx_transmit, hw_ste_p, encap_pointer_vlan_data, reformat_id); +} + +static void dr_ste_v0_set_rx_decap(u8 *hw_ste_p) +{ + MLX5_SET(ste_rx_steering_mult, hw_ste_p, tunneling_action, + DR_STE_TUNL_ACTION_DECAP); + MLX5_SET(ste_rx_steering_mult, hw_ste_p, fail_on_error, 1); +} + +static void dr_ste_v0_set_rx_pop_vlan(u8 *hw_ste_p) +{ + MLX5_SET(ste_rx_steering_mult, hw_ste_p, tunneling_action, + DR_STE_TUNL_ACTION_POP_VLAN); +} + +static void dr_ste_v0_set_rx_decap_l3(u8 *hw_ste_p, bool vlan) +{ + MLX5_SET(ste_rx_steering_mult, hw_ste_p, tunneling_action, + DR_STE_TUNL_ACTION_L3_DECAP); + MLX5_SET(ste_modify_packet, hw_ste_p, action_description, vlan ? 1 : 0); + MLX5_SET(ste_rx_steering_mult, hw_ste_p, fail_on_error, 1); +} + +static void dr_ste_v0_set_rewrite_actions(u8 *hw_ste_p, u16 num_of_actions, + u32 re_write_index) +{ + MLX5_SET(ste_modify_packet, hw_ste_p, number_of_re_write_actions, + num_of_actions); + MLX5_SET(ste_modify_packet, hw_ste_p, header_re_write_actions_pointer, + re_write_index); +} + +static void dr_ste_v0_arr_init_next(u8 **last_ste, + u32 *added_stes, + enum dr_ste_v0_entry_type entry_type, + u16 gvmi) +{ + (*added_stes)++; + *last_ste += DR_STE_SIZE; + dr_ste_v0_init_full(*last_ste, MLX5DR_STE_LU_TYPE_DONT_CARE, + entry_type, gvmi); +} + +static void +dr_ste_v0_set_actions_tx(struct mlx5dr_domain *dmn, + u8 *action_type_set, + u32 actions_caps, + u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes) +{ + bool encap = action_type_set[DR_ACTION_TYP_L2_TO_TNL_L2] || + action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]; + + /* We want to make sure the modify header comes before L2 + * encapsulation. The reason for that is that we support + * modify headers for outer headers only + */ + if (action_type_set[DR_ACTION_TYP_MODIFY_HDR] && attr->modify_actions) { + dr_ste_v0_set_entry_type(last_ste, DR_STE_TYPE_MODIFY_PKT); + dr_ste_v0_set_rewrite_actions(last_ste, + attr->modify_actions, + attr->modify_index); + } + + if (action_type_set[DR_ACTION_TYP_PUSH_VLAN]) { + int i; + + for (i = 0; i < attr->vlans.count; i++) { + if (i || action_type_set[DR_ACTION_TYP_MODIFY_HDR]) + dr_ste_v0_arr_init_next(&last_ste, + added_stes, + DR_STE_TYPE_TX, + attr->gvmi); + + dr_ste_v0_set_tx_push_vlan(last_ste, + attr->vlans.headers[i], + encap); + } + } + + if (encap) { + /* Modify header and encapsulation require a different STEs. + * Since modify header STE format doesn't support encapsulation + * tunneling_action. + */ + if (action_type_set[DR_ACTION_TYP_MODIFY_HDR] || + action_type_set[DR_ACTION_TYP_PUSH_VLAN]) + dr_ste_v0_arr_init_next(&last_ste, + added_stes, + DR_STE_TYPE_TX, + attr->gvmi); + + dr_ste_v0_set_tx_encap(last_ste, + attr->reformat.id, + attr->reformat.size, + action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]); + /* Whenever prio_tag_required enabled, we can be sure that the + * previous table (ACL) already push vlan to our packet, + * And due to HW limitation we need to set this bit, otherwise + * push vlan + reformat will not work. + */ + if (MLX5_CAP_GEN(dmn->mdev, prio_tag_required)) + dr_ste_v0_set_go_back_bit(last_ste); + } + + if (action_type_set[DR_ACTION_TYP_CTR]) + dr_ste_v0_set_counter_id(last_ste, attr->ctr_id); + + dr_ste_v0_set_hit_gvmi(last_ste, attr->hit_gvmi); + dr_ste_v0_set_hit_addr(last_ste, attr->final_icm_addr, 1); +} + +static void +dr_ste_v0_set_actions_rx(struct mlx5dr_domain *dmn, + u8 *action_type_set, + u32 actions_caps, + u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes) +{ + if (action_type_set[DR_ACTION_TYP_CTR]) + dr_ste_v0_set_counter_id(last_ste, attr->ctr_id); + + if (action_type_set[DR_ACTION_TYP_TNL_L3_TO_L2]) { + dr_ste_v0_set_entry_type(last_ste, DR_STE_TYPE_MODIFY_PKT); + dr_ste_v0_set_rx_decap_l3(last_ste, attr->decap_with_vlan); + dr_ste_v0_set_rewrite_actions(last_ste, + attr->decap_actions, + attr->decap_index); + } + + if (action_type_set[DR_ACTION_TYP_TNL_L2_TO_L2]) + dr_ste_v0_set_rx_decap(last_ste); + + if (action_type_set[DR_ACTION_TYP_POP_VLAN]) { + int i; + + for (i = 0; i < attr->vlans.count; i++) { + if (i || + action_type_set[DR_ACTION_TYP_TNL_L2_TO_L2] || + action_type_set[DR_ACTION_TYP_TNL_L3_TO_L2]) + dr_ste_v0_arr_init_next(&last_ste, + added_stes, + DR_STE_TYPE_RX, + attr->gvmi); + + dr_ste_v0_set_rx_pop_vlan(last_ste); + } + } + + if (action_type_set[DR_ACTION_TYP_MODIFY_HDR] && attr->modify_actions) { + if (dr_ste_v0_get_entry_type(last_ste) == DR_STE_TYPE_MODIFY_PKT) + dr_ste_v0_arr_init_next(&last_ste, + added_stes, + DR_STE_TYPE_MODIFY_PKT, + attr->gvmi); + else + dr_ste_v0_set_entry_type(last_ste, DR_STE_TYPE_MODIFY_PKT); + + dr_ste_v0_set_rewrite_actions(last_ste, + attr->modify_actions, + attr->modify_index); + } + + if (action_type_set[DR_ACTION_TYP_TAG]) { + if (dr_ste_v0_get_entry_type(last_ste) == DR_STE_TYPE_MODIFY_PKT) + dr_ste_v0_arr_init_next(&last_ste, + added_stes, + DR_STE_TYPE_RX, + attr->gvmi); + + dr_ste_v0_rx_set_flow_tag(last_ste, attr->flow_tag); + } + + dr_ste_v0_set_hit_gvmi(last_ste, attr->hit_gvmi); + dr_ste_v0_set_hit_addr(last_ste, attr->final_icm_addr, 1); +} + +static void dr_ste_v0_set_action_set(u8 *hw_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data) +{ + length = (length == 32) ? 0 : length; + MLX5_SET(dr_action_hw_set, hw_action, opcode, DR_STE_ACTION_MDFY_OP_SET); + MLX5_SET(dr_action_hw_set, hw_action, destination_field_code, hw_field); + MLX5_SET(dr_action_hw_set, hw_action, destination_left_shifter, shifter); + MLX5_SET(dr_action_hw_set, hw_action, destination_length, length); + MLX5_SET(dr_action_hw_set, hw_action, inline_data, data); +} + +static void dr_ste_v0_set_action_add(u8 *hw_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data) +{ + length = (length == 32) ? 0 : length; + MLX5_SET(dr_action_hw_set, hw_action, opcode, DR_STE_ACTION_MDFY_OP_ADD); + MLX5_SET(dr_action_hw_set, hw_action, destination_field_code, hw_field); + MLX5_SET(dr_action_hw_set, hw_action, destination_left_shifter, shifter); + MLX5_SET(dr_action_hw_set, hw_action, destination_length, length); + MLX5_SET(dr_action_hw_set, hw_action, inline_data, data); +} + +static void dr_ste_v0_set_action_copy(u8 *hw_action, + u8 dst_hw_field, + u8 dst_shifter, + u8 dst_len, + u8 src_hw_field, + u8 src_shifter) +{ + MLX5_SET(dr_action_hw_copy, hw_action, opcode, DR_STE_ACTION_MDFY_OP_COPY); + MLX5_SET(dr_action_hw_copy, hw_action, destination_field_code, dst_hw_field); + MLX5_SET(dr_action_hw_copy, hw_action, destination_left_shifter, dst_shifter); + MLX5_SET(dr_action_hw_copy, hw_action, destination_length, dst_len); + MLX5_SET(dr_action_hw_copy, hw_action, source_field_code, src_hw_field); + MLX5_SET(dr_action_hw_copy, hw_action, source_left_shifter, src_shifter); +} + +#define DR_STE_DECAP_L3_MIN_ACTION_NUM 5 + +static int +dr_ste_v0_set_action_decap_l3_list(void *data, u32 data_sz, + u8 *hw_action, u32 hw_action_sz, + u16 *used_hw_action_num) +{ + struct mlx5_ifc_l2_hdr_bits *l2_hdr = data; + u32 hw_action_num; + int required_actions; + u32 hdr_fld_4b; + u16 hdr_fld_2b; + u16 vlan_type; + bool vlan; + + vlan = (data_sz != HDR_LEN_L2); + hw_action_num = hw_action_sz / MLX5_ST_SZ_BYTES(dr_action_hw_set); + required_actions = DR_STE_DECAP_L3_MIN_ACTION_NUM + !!vlan; + + if (hw_action_num < required_actions) + return -ENOMEM; + + /* dmac_47_16 */ + MLX5_SET(dr_action_hw_set, hw_action, + opcode, DR_STE_ACTION_MDFY_OP_SET); + MLX5_SET(dr_action_hw_set, hw_action, + destination_length, 0); + MLX5_SET(dr_action_hw_set, hw_action, + destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_0); + MLX5_SET(dr_action_hw_set, hw_action, + destination_left_shifter, 16); + hdr_fld_4b = MLX5_GET(l2_hdr, l2_hdr, dmac_47_16); + MLX5_SET(dr_action_hw_set, hw_action, + inline_data, hdr_fld_4b); + hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); + + /* smac_47_16 */ + MLX5_SET(dr_action_hw_set, hw_action, + opcode, DR_STE_ACTION_MDFY_OP_SET); + MLX5_SET(dr_action_hw_set, hw_action, + destination_length, 0); + MLX5_SET(dr_action_hw_set, hw_action, + destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_1); + MLX5_SET(dr_action_hw_set, hw_action, destination_left_shifter, 16); + hdr_fld_4b = (MLX5_GET(l2_hdr, l2_hdr, smac_31_0) >> 16 | + MLX5_GET(l2_hdr, l2_hdr, smac_47_32) << 16); + MLX5_SET(dr_action_hw_set, hw_action, inline_data, hdr_fld_4b); + hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); + + /* dmac_15_0 */ + MLX5_SET(dr_action_hw_set, hw_action, + opcode, DR_STE_ACTION_MDFY_OP_SET); + MLX5_SET(dr_action_hw_set, hw_action, + destination_length, 16); + MLX5_SET(dr_action_hw_set, hw_action, + destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_0); + MLX5_SET(dr_action_hw_set, hw_action, + destination_left_shifter, 0); + hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, dmac_15_0); + MLX5_SET(dr_action_hw_set, hw_action, + inline_data, hdr_fld_2b); + hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); + + /* ethertype + (optional) vlan */ + MLX5_SET(dr_action_hw_set, hw_action, + opcode, DR_STE_ACTION_MDFY_OP_SET); + MLX5_SET(dr_action_hw_set, hw_action, + destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_2); + MLX5_SET(dr_action_hw_set, hw_action, + destination_left_shifter, 32); + if (!vlan) { + hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, ethertype); + MLX5_SET(dr_action_hw_set, hw_action, inline_data, hdr_fld_2b); + MLX5_SET(dr_action_hw_set, hw_action, destination_length, 16); + } else { + hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, ethertype); + vlan_type = hdr_fld_2b == SVLAN_ETHERTYPE ? DR_STE_SVLAN : DR_STE_CVLAN; + hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, vlan); + hdr_fld_4b = (vlan_type << 16) | hdr_fld_2b; + MLX5_SET(dr_action_hw_set, hw_action, inline_data, hdr_fld_4b); + MLX5_SET(dr_action_hw_set, hw_action, destination_length, 18); + } + hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); + + /* smac_15_0 */ + MLX5_SET(dr_action_hw_set, hw_action, + opcode, DR_STE_ACTION_MDFY_OP_SET); + MLX5_SET(dr_action_hw_set, hw_action, + destination_length, 16); + MLX5_SET(dr_action_hw_set, hw_action, + destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_1); + MLX5_SET(dr_action_hw_set, hw_action, + destination_left_shifter, 0); + hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, smac_31_0); + MLX5_SET(dr_action_hw_set, hw_action, inline_data, hdr_fld_2b); + hw_action += MLX5_ST_SZ_BYTES(dr_action_hw_set); + + if (vlan) { + MLX5_SET(dr_action_hw_set, hw_action, + opcode, DR_STE_ACTION_MDFY_OP_SET); + hdr_fld_2b = MLX5_GET(l2_hdr, l2_hdr, vlan_type); + MLX5_SET(dr_action_hw_set, hw_action, + inline_data, hdr_fld_2b); + MLX5_SET(dr_action_hw_set, hw_action, + destination_length, 16); + MLX5_SET(dr_action_hw_set, hw_action, + destination_field_code, DR_STE_V0_ACTION_MDFY_FLD_L2_2); + MLX5_SET(dr_action_hw_set, hw_action, + destination_left_shifter, 0); + } + + *used_hw_action_num = required_actions; + + return 0; +} + +static void +dr_ste_v0_build_eth_l2_src_dst_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, dmac_47_16, mask, dmac_47_16); + DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, dmac_15_0, mask, dmac_15_0); + + if (mask->smac_47_16 || mask->smac_15_0) { + MLX5_SET(ste_eth_l2_src_dst, bit_mask, smac_47_32, + mask->smac_47_16 >> 16); + MLX5_SET(ste_eth_l2_src_dst, bit_mask, smac_31_0, + mask->smac_47_16 << 16 | mask->smac_15_0); + mask->smac_47_16 = 0; + mask->smac_15_0 = 0; + } + + DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, first_vlan_id, mask, first_vid); + DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, first_cfi, mask, first_cfi); + DR_STE_SET_TAG(eth_l2_src_dst, bit_mask, first_priority, mask, first_prio); + DR_STE_SET_ONES(eth_l2_src_dst, bit_mask, l3_type, mask, ip_version); + + if (mask->cvlan_tag) { + MLX5_SET(ste_eth_l2_src_dst, bit_mask, first_vlan_qualifier, -1); + mask->cvlan_tag = 0; + } else if (mask->svlan_tag) { + MLX5_SET(ste_eth_l2_src_dst, bit_mask, first_vlan_qualifier, -1); + mask->svlan_tag = 0; + } +} + +static int +dr_ste_v0_build_eth_l2_src_dst_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_src_dst, tag, dmac_47_16, spec, dmac_47_16); + DR_STE_SET_TAG(eth_l2_src_dst, tag, dmac_15_0, spec, dmac_15_0); + + if (spec->smac_47_16 || spec->smac_15_0) { + MLX5_SET(ste_eth_l2_src_dst, tag, smac_47_32, + spec->smac_47_16 >> 16); + MLX5_SET(ste_eth_l2_src_dst, tag, smac_31_0, + spec->smac_47_16 << 16 | spec->smac_15_0); + spec->smac_47_16 = 0; + spec->smac_15_0 = 0; + } + + if (spec->ip_version) { + if (spec->ip_version == IP_VERSION_IPV4) { + MLX5_SET(ste_eth_l2_src_dst, tag, l3_type, STE_IPV4); + spec->ip_version = 0; + } else if (spec->ip_version == IP_VERSION_IPV6) { + MLX5_SET(ste_eth_l2_src_dst, tag, l3_type, STE_IPV6); + spec->ip_version = 0; + } else { + return -EINVAL; + } + } + + DR_STE_SET_TAG(eth_l2_src_dst, tag, first_vlan_id, spec, first_vid); + DR_STE_SET_TAG(eth_l2_src_dst, tag, first_cfi, spec, first_cfi); + DR_STE_SET_TAG(eth_l2_src_dst, tag, first_priority, spec, first_prio); + + if (spec->cvlan_tag) { + MLX5_SET(ste_eth_l2_src_dst, tag, first_vlan_qualifier, DR_STE_CVLAN); + spec->cvlan_tag = 0; + } else if (spec->svlan_tag) { + MLX5_SET(ste_eth_l2_src_dst, tag, first_vlan_qualifier, DR_STE_SVLAN); + spec->svlan_tag = 0; + } + return 0; +} + +static void +dr_ste_v0_build_eth_l2_src_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l2_src_dst_bit_mask(mask, sb->inner, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL2_SRC_DST, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l2_src_dst_tag; +} + +static int +dr_ste_v0_build_eth_l3_ipv6_dst_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_127_96, spec, dst_ip_127_96); + DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_95_64, spec, dst_ip_95_64); + DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_63_32, spec, dst_ip_63_32); + DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_31_0, spec, dst_ip_31_0); + + return 0; +} + +static void +dr_ste_v0_build_eth_l3_ipv6_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l3_ipv6_dst_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL3_IPV6_DST, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l3_ipv6_dst_tag; +} + +static int +dr_ste_v0_build_eth_l3_ipv6_src_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_127_96, spec, src_ip_127_96); + DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_95_64, spec, src_ip_95_64); + DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_63_32, spec, src_ip_63_32); + DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_31_0, spec, src_ip_31_0); + + return 0; +} + +static void +dr_ste_v0_build_eth_l3_ipv6_src_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l3_ipv6_src_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL3_IPV6_SRC, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l3_ipv6_src_tag; +} + +static int +dr_ste_v0_build_eth_l3_ipv4_5_tuple_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, destination_address, spec, dst_ip_31_0); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, source_address, spec, src_ip_31_0); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, destination_port, spec, tcp_dport); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, destination_port, spec, udp_dport); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, source_port, spec, tcp_sport); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, source_port, spec, udp_sport); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, protocol, spec, ip_protocol); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, fragmented, spec, frag); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, dscp, spec, ip_dscp); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple, tag, ecn, spec, ip_ecn); + + if (spec->tcp_flags) { + DR_STE_SET_TCP_FLAGS(eth_l3_ipv4_5_tuple, tag, spec); + spec->tcp_flags = 0; + } + + return 0; +} + +static void +dr_ste_v0_build_eth_l3_ipv4_5_tuple_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l3_ipv4_5_tuple_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL3_IPV4_5_TUPLE, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l3_ipv4_5_tuple_tag; +} + +static void +dr_ste_v0_build_eth_l2_src_or_dst_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc_mask = &value->misc; + + DR_STE_SET_TAG(eth_l2_src, bit_mask, first_vlan_id, mask, first_vid); + DR_STE_SET_TAG(eth_l2_src, bit_mask, first_cfi, mask, first_cfi); + DR_STE_SET_TAG(eth_l2_src, bit_mask, first_priority, mask, first_prio); + DR_STE_SET_TAG(eth_l2_src, bit_mask, ip_fragmented, mask, frag); + DR_STE_SET_TAG(eth_l2_src, bit_mask, l3_ethertype, mask, ethertype); + DR_STE_SET_ONES(eth_l2_src, bit_mask, l3_type, mask, ip_version); + + if (mask->svlan_tag || mask->cvlan_tag) { + MLX5_SET(ste_eth_l2_src, bit_mask, first_vlan_qualifier, -1); + mask->cvlan_tag = 0; + mask->svlan_tag = 0; + } + + if (inner) { + if (misc_mask->inner_second_cvlan_tag || + misc_mask->inner_second_svlan_tag) { + MLX5_SET(ste_eth_l2_src, bit_mask, second_vlan_qualifier, -1); + misc_mask->inner_second_cvlan_tag = 0; + misc_mask->inner_second_svlan_tag = 0; + } + + DR_STE_SET_TAG(eth_l2_src, bit_mask, + second_vlan_id, misc_mask, inner_second_vid); + DR_STE_SET_TAG(eth_l2_src, bit_mask, + second_cfi, misc_mask, inner_second_cfi); + DR_STE_SET_TAG(eth_l2_src, bit_mask, + second_priority, misc_mask, inner_second_prio); + } else { + if (misc_mask->outer_second_cvlan_tag || + misc_mask->outer_second_svlan_tag) { + MLX5_SET(ste_eth_l2_src, bit_mask, second_vlan_qualifier, -1); + misc_mask->outer_second_cvlan_tag = 0; + misc_mask->outer_second_svlan_tag = 0; + } + + DR_STE_SET_TAG(eth_l2_src, bit_mask, + second_vlan_id, misc_mask, outer_second_vid); + DR_STE_SET_TAG(eth_l2_src, bit_mask, + second_cfi, misc_mask, outer_second_cfi); + DR_STE_SET_TAG(eth_l2_src, bit_mask, + second_priority, misc_mask, outer_second_prio); + } +} + +static int +dr_ste_v0_build_eth_l2_src_or_dst_tag(struct mlx5dr_match_param *value, + bool inner, u8 *tag) +{ + struct mlx5dr_match_spec *spec = inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc_spec = &value->misc; + + DR_STE_SET_TAG(eth_l2_src, tag, first_vlan_id, spec, first_vid); + DR_STE_SET_TAG(eth_l2_src, tag, first_cfi, spec, first_cfi); + DR_STE_SET_TAG(eth_l2_src, tag, first_priority, spec, first_prio); + DR_STE_SET_TAG(eth_l2_src, tag, ip_fragmented, spec, frag); + DR_STE_SET_TAG(eth_l2_src, tag, l3_ethertype, spec, ethertype); + + if (spec->ip_version) { + if (spec->ip_version == IP_VERSION_IPV4) { + MLX5_SET(ste_eth_l2_src, tag, l3_type, STE_IPV4); + spec->ip_version = 0; + } else if (spec->ip_version == IP_VERSION_IPV6) { + MLX5_SET(ste_eth_l2_src, tag, l3_type, STE_IPV6); + spec->ip_version = 0; + } else { + return -EINVAL; + } + } + + if (spec->cvlan_tag) { + MLX5_SET(ste_eth_l2_src, tag, first_vlan_qualifier, DR_STE_CVLAN); + spec->cvlan_tag = 0; + } else if (spec->svlan_tag) { + MLX5_SET(ste_eth_l2_src, tag, first_vlan_qualifier, DR_STE_SVLAN); + spec->svlan_tag = 0; + } + + if (inner) { + if (misc_spec->inner_second_cvlan_tag) { + MLX5_SET(ste_eth_l2_src, tag, second_vlan_qualifier, DR_STE_CVLAN); + misc_spec->inner_second_cvlan_tag = 0; + } else if (misc_spec->inner_second_svlan_tag) { + MLX5_SET(ste_eth_l2_src, tag, second_vlan_qualifier, DR_STE_SVLAN); + misc_spec->inner_second_svlan_tag = 0; + } + + DR_STE_SET_TAG(eth_l2_src, tag, second_vlan_id, misc_spec, inner_second_vid); + DR_STE_SET_TAG(eth_l2_src, tag, second_cfi, misc_spec, inner_second_cfi); + DR_STE_SET_TAG(eth_l2_src, tag, second_priority, misc_spec, inner_second_prio); + } else { + if (misc_spec->outer_second_cvlan_tag) { + MLX5_SET(ste_eth_l2_src, tag, second_vlan_qualifier, DR_STE_CVLAN); + misc_spec->outer_second_cvlan_tag = 0; + } else if (misc_spec->outer_second_svlan_tag) { + MLX5_SET(ste_eth_l2_src, tag, second_vlan_qualifier, DR_STE_SVLAN); + misc_spec->outer_second_svlan_tag = 0; + } + DR_STE_SET_TAG(eth_l2_src, tag, second_vlan_id, misc_spec, outer_second_vid); + DR_STE_SET_TAG(eth_l2_src, tag, second_cfi, misc_spec, outer_second_cfi); + DR_STE_SET_TAG(eth_l2_src, tag, second_priority, misc_spec, outer_second_prio); + } + + return 0; +} + +static void +dr_ste_v0_build_eth_l2_src_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_src, bit_mask, smac_47_16, mask, smac_47_16); + DR_STE_SET_TAG(eth_l2_src, bit_mask, smac_15_0, mask, smac_15_0); + + dr_ste_v0_build_eth_l2_src_or_dst_bit_mask(value, inner, bit_mask); +} + +static int +dr_ste_v0_build_eth_l2_src_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_src, tag, smac_47_16, spec, smac_47_16); + DR_STE_SET_TAG(eth_l2_src, tag, smac_15_0, spec, smac_15_0); + + return dr_ste_v0_build_eth_l2_src_or_dst_tag(value, sb->inner, tag); +} + +static void +dr_ste_v0_build_eth_l2_src_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l2_src_bit_mask(mask, sb->inner, sb->bit_mask); + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL2_SRC, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l2_src_tag; +} + +static void +dr_ste_v0_build_eth_l2_dst_bit_mask(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_dst, bit_mask, dmac_47_16, mask, dmac_47_16); + DR_STE_SET_TAG(eth_l2_dst, bit_mask, dmac_15_0, mask, dmac_15_0); + + dr_ste_v0_build_eth_l2_src_or_dst_bit_mask(value, sb->inner, bit_mask); +} + +static int +dr_ste_v0_build_eth_l2_dst_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_dst, tag, dmac_47_16, spec, dmac_47_16); + DR_STE_SET_TAG(eth_l2_dst, tag, dmac_15_0, spec, dmac_15_0); + + return dr_ste_v0_build_eth_l2_src_or_dst_tag(value, sb->inner, tag); +} + +static void +dr_ste_v0_build_eth_l2_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l2_dst_bit_mask(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL2_DST, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l2_dst_tag; +} + +static void +dr_ste_v0_build_eth_l2_tnl_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(eth_l2_tnl, bit_mask, dmac_47_16, mask, dmac_47_16); + DR_STE_SET_TAG(eth_l2_tnl, bit_mask, dmac_15_0, mask, dmac_15_0); + DR_STE_SET_TAG(eth_l2_tnl, bit_mask, first_vlan_id, mask, first_vid); + DR_STE_SET_TAG(eth_l2_tnl, bit_mask, first_cfi, mask, first_cfi); + DR_STE_SET_TAG(eth_l2_tnl, bit_mask, first_priority, mask, first_prio); + DR_STE_SET_TAG(eth_l2_tnl, bit_mask, ip_fragmented, mask, frag); + DR_STE_SET_TAG(eth_l2_tnl, bit_mask, l3_ethertype, mask, ethertype); + DR_STE_SET_ONES(eth_l2_tnl, bit_mask, l3_type, mask, ip_version); + + if (misc->vxlan_vni) { + MLX5_SET(ste_eth_l2_tnl, bit_mask, + l2_tunneling_network_id, (misc->vxlan_vni << 8)); + misc->vxlan_vni = 0; + } + + if (mask->svlan_tag || mask->cvlan_tag) { + MLX5_SET(ste_eth_l2_tnl, bit_mask, first_vlan_qualifier, -1); + mask->cvlan_tag = 0; + mask->svlan_tag = 0; + } +} + +static int +dr_ste_v0_build_eth_l2_tnl_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(eth_l2_tnl, tag, dmac_47_16, spec, dmac_47_16); + DR_STE_SET_TAG(eth_l2_tnl, tag, dmac_15_0, spec, dmac_15_0); + DR_STE_SET_TAG(eth_l2_tnl, tag, first_vlan_id, spec, first_vid); + DR_STE_SET_TAG(eth_l2_tnl, tag, first_cfi, spec, first_cfi); + DR_STE_SET_TAG(eth_l2_tnl, tag, ip_fragmented, spec, frag); + DR_STE_SET_TAG(eth_l2_tnl, tag, first_priority, spec, first_prio); + DR_STE_SET_TAG(eth_l2_tnl, tag, l3_ethertype, spec, ethertype); + + if (misc->vxlan_vni) { + MLX5_SET(ste_eth_l2_tnl, tag, l2_tunneling_network_id, + (misc->vxlan_vni << 8)); + misc->vxlan_vni = 0; + } + + if (spec->cvlan_tag) { + MLX5_SET(ste_eth_l2_tnl, tag, first_vlan_qualifier, DR_STE_CVLAN); + spec->cvlan_tag = 0; + } else if (spec->svlan_tag) { + MLX5_SET(ste_eth_l2_tnl, tag, first_vlan_qualifier, DR_STE_SVLAN); + spec->svlan_tag = 0; + } + + if (spec->ip_version) { + if (spec->ip_version == IP_VERSION_IPV4) { + MLX5_SET(ste_eth_l2_tnl, tag, l3_type, STE_IPV4); + spec->ip_version = 0; + } else if (spec->ip_version == IP_VERSION_IPV6) { + MLX5_SET(ste_eth_l2_tnl, tag, l3_type, STE_IPV6); + spec->ip_version = 0; + } else { + return -EINVAL; + } + } + + return 0; +} + +static void +dr_ste_v0_build_eth_l2_tnl_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l2_tnl_bit_mask(mask, sb->inner, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_ETHL2_TUNNELING_I; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l2_tnl_tag; +} + +static int +dr_ste_v0_build_eth_l3_ipv4_misc_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l3_ipv4_misc, tag, time_to_live, spec, ttl_hoplimit); + DR_STE_SET_TAG(eth_l3_ipv4_misc, tag, ihl, spec, ipv4_ihl); + + return 0; +} + +static void +dr_ste_v0_build_eth_l3_ipv4_misc_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l3_ipv4_misc_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL3_IPV4_MISC, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l3_ipv4_misc_tag; +} + +static int +dr_ste_v0_build_eth_ipv6_l3_l4_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(eth_l4, tag, dst_port, spec, tcp_dport); + DR_STE_SET_TAG(eth_l4, tag, src_port, spec, tcp_sport); + DR_STE_SET_TAG(eth_l4, tag, dst_port, spec, udp_dport); + DR_STE_SET_TAG(eth_l4, tag, src_port, spec, udp_sport); + DR_STE_SET_TAG(eth_l4, tag, protocol, spec, ip_protocol); + DR_STE_SET_TAG(eth_l4, tag, fragmented, spec, frag); + DR_STE_SET_TAG(eth_l4, tag, dscp, spec, ip_dscp); + DR_STE_SET_TAG(eth_l4, tag, ecn, spec, ip_ecn); + DR_STE_SET_TAG(eth_l4, tag, ipv6_hop_limit, spec, ttl_hoplimit); + + if (sb->inner) + DR_STE_SET_TAG(eth_l4, tag, flow_label, misc, inner_ipv6_flow_label); + else + DR_STE_SET_TAG(eth_l4, tag, flow_label, misc, outer_ipv6_flow_label); + + if (spec->tcp_flags) { + DR_STE_SET_TCP_FLAGS(eth_l4, tag, spec); + spec->tcp_flags = 0; + } + + return 0; +} + +static void +dr_ste_v0_build_eth_ipv6_l3_l4_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_ipv6_l3_l4_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL4, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_ipv6_l3_l4_tag; +} + +static int +dr_ste_v0_build_mpls_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + + if (sb->inner) + DR_STE_SET_MPLS(mpls, misc2, inner, tag); + else + DR_STE_SET_MPLS(mpls, misc2, outer, tag); + + return 0; +} + +static void +dr_ste_v0_build_mpls_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_mpls_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(MPLS_FIRST, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_mpls_tag; +} + +static int +dr_ste_v0_build_tnl_gre_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(gre, tag, gre_protocol, misc, gre_protocol); + + DR_STE_SET_TAG(gre, tag, gre_k_present, misc, gre_k_present); + DR_STE_SET_TAG(gre, tag, gre_key_h, misc, gre_key_h); + DR_STE_SET_TAG(gre, tag, gre_key_l, misc, gre_key_l); + + DR_STE_SET_TAG(gre, tag, gre_c_present, misc, gre_c_present); + + DR_STE_SET_TAG(gre, tag, gre_s_present, misc, gre_s_present); + + return 0; +} + +static void +dr_ste_v0_build_tnl_gre_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_tnl_gre_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_GRE; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_tnl_gre_tag; +} + +static int +dr_ste_v0_build_tnl_mpls_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc_2 = &value->misc2; + u32 mpls_hdr; + + if (DR_STE_IS_OUTER_MPLS_OVER_GRE_SET(misc_2)) { + mpls_hdr = misc_2->outer_first_mpls_over_gre_label << HDR_MPLS_OFFSET_LABEL; + misc_2->outer_first_mpls_over_gre_label = 0; + mpls_hdr |= misc_2->outer_first_mpls_over_gre_exp << HDR_MPLS_OFFSET_EXP; + misc_2->outer_first_mpls_over_gre_exp = 0; + mpls_hdr |= misc_2->outer_first_mpls_over_gre_s_bos << HDR_MPLS_OFFSET_S_BOS; + misc_2->outer_first_mpls_over_gre_s_bos = 0; + mpls_hdr |= misc_2->outer_first_mpls_over_gre_ttl << HDR_MPLS_OFFSET_TTL; + misc_2->outer_first_mpls_over_gre_ttl = 0; + } else { + mpls_hdr = misc_2->outer_first_mpls_over_udp_label << HDR_MPLS_OFFSET_LABEL; + misc_2->outer_first_mpls_over_udp_label = 0; + mpls_hdr |= misc_2->outer_first_mpls_over_udp_exp << HDR_MPLS_OFFSET_EXP; + misc_2->outer_first_mpls_over_udp_exp = 0; + mpls_hdr |= misc_2->outer_first_mpls_over_udp_s_bos << HDR_MPLS_OFFSET_S_BOS; + misc_2->outer_first_mpls_over_udp_s_bos = 0; + mpls_hdr |= misc_2->outer_first_mpls_over_udp_ttl << HDR_MPLS_OFFSET_TTL; + misc_2->outer_first_mpls_over_udp_ttl = 0; + } + + MLX5_SET(ste_flex_parser_0, tag, flex_parser_3, mpls_hdr); + return 0; +} + +static void +dr_ste_v0_build_tnl_mpls_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_tnl_mpls_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_0; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_tnl_mpls_tag; +} + +static int +dr_ste_v0_build_tnl_mpls_over_udp_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + u8 *parser_ptr; + u8 parser_id; + u32 mpls_hdr; + + mpls_hdr = misc2->outer_first_mpls_over_udp_label << HDR_MPLS_OFFSET_LABEL; + misc2->outer_first_mpls_over_udp_label = 0; + mpls_hdr |= misc2->outer_first_mpls_over_udp_exp << HDR_MPLS_OFFSET_EXP; + misc2->outer_first_mpls_over_udp_exp = 0; + mpls_hdr |= misc2->outer_first_mpls_over_udp_s_bos << HDR_MPLS_OFFSET_S_BOS; + misc2->outer_first_mpls_over_udp_s_bos = 0; + mpls_hdr |= misc2->outer_first_mpls_over_udp_ttl << HDR_MPLS_OFFSET_TTL; + misc2->outer_first_mpls_over_udp_ttl = 0; + + parser_id = sb->caps->flex_parser_id_mpls_over_udp; + parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); + *(__be32 *)parser_ptr = cpu_to_be32(mpls_hdr); + + return 0; +} + +static void +dr_ste_v0_build_tnl_mpls_over_udp_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_tnl_mpls_over_udp_tag(mask, sb, sb->bit_mask); + /* STEs with lookup type FLEX_PARSER_{0/1} includes + * flex parsers_{0-3}/{4-7} respectively. + */ + sb->lu_type = sb->caps->flex_parser_id_mpls_over_udp > DR_STE_MAX_FLEX_0_ID ? + DR_STE_V0_LU_TYPE_FLEX_PARSER_1 : + DR_STE_V0_LU_TYPE_FLEX_PARSER_0; + + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_tnl_mpls_over_udp_tag; +} + +static int +dr_ste_v0_build_tnl_mpls_over_gre_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + u8 *parser_ptr; + u8 parser_id; + u32 mpls_hdr; + + mpls_hdr = misc2->outer_first_mpls_over_gre_label << HDR_MPLS_OFFSET_LABEL; + misc2->outer_first_mpls_over_gre_label = 0; + mpls_hdr |= misc2->outer_first_mpls_over_gre_exp << HDR_MPLS_OFFSET_EXP; + misc2->outer_first_mpls_over_gre_exp = 0; + mpls_hdr |= misc2->outer_first_mpls_over_gre_s_bos << HDR_MPLS_OFFSET_S_BOS; + misc2->outer_first_mpls_over_gre_s_bos = 0; + mpls_hdr |= misc2->outer_first_mpls_over_gre_ttl << HDR_MPLS_OFFSET_TTL; + misc2->outer_first_mpls_over_gre_ttl = 0; + + parser_id = sb->caps->flex_parser_id_mpls_over_gre; + parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); + *(__be32 *)parser_ptr = cpu_to_be32(mpls_hdr); + + return 0; +} + +static void +dr_ste_v0_build_tnl_mpls_over_gre_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_tnl_mpls_over_gre_tag(mask, sb, sb->bit_mask); + + /* STEs with lookup type FLEX_PARSER_{0/1} includes + * flex parsers_{0-3}/{4-7} respectively. + */ + sb->lu_type = sb->caps->flex_parser_id_mpls_over_gre > DR_STE_MAX_FLEX_0_ID ? + DR_STE_V0_LU_TYPE_FLEX_PARSER_1 : + DR_STE_V0_LU_TYPE_FLEX_PARSER_0; + + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_tnl_mpls_over_gre_tag; +} + +#define ICMP_TYPE_OFFSET_FIRST_DW 24 +#define ICMP_CODE_OFFSET_FIRST_DW 16 + +static int +dr_ste_v0_build_icmp_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc_3 = &value->misc3; + u32 *icmp_header_data; + int dw0_location; + int dw1_location; + u8 *parser_ptr; + u8 *icmp_type; + u8 *icmp_code; + bool is_ipv4; + u32 icmp_hdr; + + is_ipv4 = DR_MASK_IS_ICMPV4_SET(misc_3); + if (is_ipv4) { + icmp_header_data = &misc_3->icmpv4_header_data; + icmp_type = &misc_3->icmpv4_type; + icmp_code = &misc_3->icmpv4_code; + dw0_location = sb->caps->flex_parser_id_icmp_dw0; + dw1_location = sb->caps->flex_parser_id_icmp_dw1; + } else { + icmp_header_data = &misc_3->icmpv6_header_data; + icmp_type = &misc_3->icmpv6_type; + icmp_code = &misc_3->icmpv6_code; + dw0_location = sb->caps->flex_parser_id_icmpv6_dw0; + dw1_location = sb->caps->flex_parser_id_icmpv6_dw1; + } + + parser_ptr = dr_ste_calc_flex_parser_offset(tag, dw0_location); + icmp_hdr = (*icmp_type << ICMP_TYPE_OFFSET_FIRST_DW) | + (*icmp_code << ICMP_CODE_OFFSET_FIRST_DW); + *(__be32 *)parser_ptr = cpu_to_be32(icmp_hdr); + *icmp_code = 0; + *icmp_type = 0; + + parser_ptr = dr_ste_calc_flex_parser_offset(tag, dw1_location); + *(__be32 *)parser_ptr = cpu_to_be32(*icmp_header_data); + *icmp_header_data = 0; + + return 0; +} + +static void +dr_ste_v0_build_icmp_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + u8 parser_id; + bool is_ipv4; + + dr_ste_v0_build_icmp_tag(mask, sb, sb->bit_mask); + + /* STEs with lookup type FLEX_PARSER_{0/1} includes + * flex parsers_{0-3}/{4-7} respectively. + */ + is_ipv4 = DR_MASK_IS_ICMPV4_SET(&mask->misc3); + parser_id = is_ipv4 ? sb->caps->flex_parser_id_icmp_dw0 : + sb->caps->flex_parser_id_icmpv6_dw0; + sb->lu_type = parser_id > DR_STE_MAX_FLEX_0_ID ? + DR_STE_V0_LU_TYPE_FLEX_PARSER_1 : + DR_STE_V0_LU_TYPE_FLEX_PARSER_0; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_icmp_tag; +} + +static int +dr_ste_v0_build_general_purpose_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc_2 = &value->misc2; + + DR_STE_SET_TAG(general_purpose, tag, general_purpose_lookup_field, + misc_2, metadata_reg_a); + + return 0; +} + +static void +dr_ste_v0_build_general_purpose_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_general_purpose_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_GENERAL_PURPOSE; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_general_purpose_tag; +} + +static int +dr_ste_v0_build_eth_l4_misc_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + + if (sb->inner) { + DR_STE_SET_TAG(eth_l4_misc, tag, seq_num, misc3, inner_tcp_seq_num); + DR_STE_SET_TAG(eth_l4_misc, tag, ack_num, misc3, inner_tcp_ack_num); + } else { + DR_STE_SET_TAG(eth_l4_misc, tag, seq_num, misc3, outer_tcp_seq_num); + DR_STE_SET_TAG(eth_l4_misc, tag, ack_num, misc3, outer_tcp_ack_num); + } + + return 0; +} + +static void +dr_ste_v0_build_eth_l4_misc_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_eth_l4_misc_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_LU_TYPE(ETHL4_MISC, sb->rx, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_eth_l4_misc_tag; +} + +static int +dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_flags, misc3, + outer_vxlan_gpe_flags); + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_next_protocol, misc3, + outer_vxlan_gpe_next_protocol); + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_vni, misc3, + outer_vxlan_gpe_vni); + + return 0; +} + +static void +dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_tag(mask, sb, sb->bit_mask); + sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_TNL_HEADER; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_tag; +} + +static int +dr_ste_v0_build_flex_parser_tnl_geneve_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_protocol_type, misc, geneve_protocol_type); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_oam, misc, geneve_oam); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_opt_len, misc, geneve_opt_len); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_vni, misc, geneve_vni); + + return 0; +} + +static void +dr_ste_v0_build_flex_parser_tnl_geneve_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_flex_parser_tnl_geneve_tag(mask, sb, sb->bit_mask); + sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_TNL_HEADER; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tnl_geneve_tag; +} + +static int +dr_ste_v0_build_register_0_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + + DR_STE_SET_TAG(register_0, tag, register_0_h, misc2, metadata_reg_c_0); + DR_STE_SET_TAG(register_0, tag, register_0_l, misc2, metadata_reg_c_1); + DR_STE_SET_TAG(register_0, tag, register_1_h, misc2, metadata_reg_c_2); + DR_STE_SET_TAG(register_0, tag, register_1_l, misc2, metadata_reg_c_3); + + return 0; +} + +static void +dr_ste_v0_build_register_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_register_0_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_STEERING_REGISTERS_0; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_register_0_tag; +} + +static int +dr_ste_v0_build_register_1_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + + DR_STE_SET_TAG(register_1, tag, register_2_h, misc2, metadata_reg_c_4); + DR_STE_SET_TAG(register_1, tag, register_2_l, misc2, metadata_reg_c_5); + DR_STE_SET_TAG(register_1, tag, register_3_h, misc2, metadata_reg_c_6); + DR_STE_SET_TAG(register_1, tag, register_3_l, misc2, metadata_reg_c_7); + + return 0; +} + +static void +dr_ste_v0_build_register_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_register_1_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_STEERING_REGISTERS_1; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_register_1_tag; +} + +static void +dr_ste_v0_build_src_gvmi_qpn_bit_mask(struct mlx5dr_match_param *value, + u8 *bit_mask) +{ + struct mlx5dr_match_misc *misc_mask = &value->misc; + + DR_STE_SET_ONES(src_gvmi_qp, bit_mask, source_gvmi, misc_mask, source_port); + DR_STE_SET_ONES(src_gvmi_qp, bit_mask, source_qp, misc_mask, source_sqn); + misc_mask->source_eswitch_owner_vhca_id = 0; +} + +static int +dr_ste_v0_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc *misc = &value->misc; + int id = misc->source_eswitch_owner_vhca_id; + struct mlx5dr_cmd_vport_cap *vport_cap; + struct mlx5dr_domain *dmn = sb->dmn; + struct mlx5dr_domain *vport_dmn; + u8 *bit_mask = sb->bit_mask; + struct mlx5dr_domain *peer; + bool source_gvmi_set; + + DR_STE_SET_TAG(src_gvmi_qp, tag, source_qp, misc, source_sqn); + + if (sb->vhca_id_valid) { + peer = xa_load(&dmn->peer_dmn_xa, id); + /* Find port GVMI based on the eswitch_owner_vhca_id */ + if (id == dmn->info.caps.gvmi) + vport_dmn = dmn; + else if (peer && (id == peer->info.caps.gvmi)) + vport_dmn = peer; + else + return -EINVAL; + + misc->source_eswitch_owner_vhca_id = 0; + } else { + vport_dmn = dmn; + } + + source_gvmi_set = MLX5_GET(ste_src_gvmi_qp, bit_mask, source_gvmi); + if (source_gvmi_set) { + vport_cap = mlx5dr_domain_get_vport_cap(vport_dmn, + misc->source_port); + if (!vport_cap) { + mlx5dr_err(dmn, "Vport 0x%x is disabled or invalid\n", + misc->source_port); + return -EINVAL; + } + + if (vport_cap->vport_gvmi) + MLX5_SET(ste_src_gvmi_qp, tag, source_gvmi, vport_cap->vport_gvmi); + + misc->source_port = 0; + } + + return 0; +} + +static void +dr_ste_v0_build_src_gvmi_qpn_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_src_gvmi_qpn_bit_mask(mask, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_SRC_GVMI_AND_QP; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_src_gvmi_qpn_tag; +} + +static void dr_ste_v0_set_flex_parser(u32 *misc4_field_id, + u32 *misc4_field_value, + bool *parser_is_used, + u8 *tag) +{ + u32 id = *misc4_field_id; + u8 *parser_ptr; + + if (id >= DR_NUM_OF_FLEX_PARSERS || parser_is_used[id]) + return; + + parser_is_used[id] = true; + parser_ptr = dr_ste_calc_flex_parser_offset(tag, id); + + *(__be32 *)parser_ptr = cpu_to_be32(*misc4_field_value); + *misc4_field_id = 0; + *misc4_field_value = 0; +} + +static int dr_ste_v0_build_flex_parser_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc4 *misc_4_mask = &value->misc4; + bool parser_is_used[DR_NUM_OF_FLEX_PARSERS] = {}; + + dr_ste_v0_set_flex_parser(&misc_4_mask->prog_sample_field_id_0, + &misc_4_mask->prog_sample_field_value_0, + parser_is_used, tag); + + dr_ste_v0_set_flex_parser(&misc_4_mask->prog_sample_field_id_1, + &misc_4_mask->prog_sample_field_value_1, + parser_is_used, tag); + + dr_ste_v0_set_flex_parser(&misc_4_mask->prog_sample_field_id_2, + &misc_4_mask->prog_sample_field_value_2, + parser_is_used, tag); + + dr_ste_v0_set_flex_parser(&misc_4_mask->prog_sample_field_id_3, + &misc_4_mask->prog_sample_field_value_3, + parser_is_used, tag); + + return 0; +} + +static void dr_ste_v0_build_flex_parser_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_0; + dr_ste_v0_build_flex_parser_tag(mask, sb, sb->bit_mask); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tag; +} + +static void dr_ste_v0_build_flex_parser_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_1; + dr_ste_v0_build_flex_parser_tag(mask, sb, sb->bit_mask); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tag; +} + +static int +dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + u8 parser_id = sb->caps->flex_parser_id_geneve_tlv_option_0; + u8 *parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); + + MLX5_SET(ste_flex_parser_0, parser_ptr, flex_parser_3, + misc3->geneve_tlv_option_0_data); + misc3->geneve_tlv_option_0_data = 0; + + return 0; +} + +static void +dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_tag(mask, sb, sb->bit_mask); + + /* STEs with lookup type FLEX_PARSER_{0/1} includes + * flex parsers_{0-3}/{4-7} respectively. + */ + sb->lu_type = sb->caps->flex_parser_id_geneve_tlv_option_0 > 3 ? + DR_STE_V0_LU_TYPE_FLEX_PARSER_1 : + DR_STE_V0_LU_TYPE_FLEX_PARSER_0; + + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_tag; +} + +static int dr_ste_v0_build_flex_parser_tnl_gtpu_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + + DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, + gtpu_msg_flags, misc3, + gtpu_msg_flags); + DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, + gtpu_msg_type, misc3, + gtpu_msg_type); + DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, + gtpu_teid, misc3, + gtpu_teid); + + return 0; +} + +static void dr_ste_v0_build_flex_parser_tnl_gtpu_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_flex_parser_tnl_gtpu_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_TNL_HEADER; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_flex_parser_tnl_gtpu_tag; +} + +static int +dr_ste_v0_build_tnl_gtpu_flex_parser_0_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_dw_0)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_0, sb->caps, &value->misc3); + if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_teid)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_teid, sb->caps, &value->misc3); + if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_dw_2)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_2, sb->caps, &value->misc3); + if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_first_ext_dw_0)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_first_ext_dw_0, sb->caps, &value->misc3); + return 0; +} + +static void +dr_ste_v0_build_tnl_gtpu_flex_parser_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_tnl_gtpu_flex_parser_0_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_0; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_tnl_gtpu_flex_parser_0_tag; +} + +static int +dr_ste_v0_build_tnl_gtpu_flex_parser_1_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_dw_0)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_0, sb->caps, &value->misc3); + if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_teid)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_teid, sb->caps, &value->misc3); + if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_dw_2)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_2, sb->caps, &value->misc3); + if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_first_ext_dw_0)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_first_ext_dw_0, sb->caps, &value->misc3); + return 0; +} + +static void +dr_ste_v0_build_tnl_gtpu_flex_parser_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v0_build_tnl_gtpu_flex_parser_1_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V0_LU_TYPE_FLEX_PARSER_1; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_tnl_gtpu_flex_parser_1_tag; +} + +static int dr_ste_v0_build_tnl_header_0_1_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc5 *misc5 = &value->misc5; + + DR_STE_SET_TAG(tunnel_header, tag, tunnel_header_0, misc5, tunnel_header_0); + DR_STE_SET_TAG(tunnel_header, tag, tunnel_header_1, misc5, tunnel_header_1); + + return 0; +} + +static void dr_ste_v0_build_tnl_header_0_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + sb->lu_type = DR_STE_V0_LU_TYPE_TUNNEL_HEADER; + dr_ste_v0_build_tnl_header_0_1_tag(mask, sb, sb->bit_mask); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v0_build_tnl_header_0_1_tag; +} + +static struct mlx5dr_ste_ctx ste_ctx_v0 = { + /* Builders */ + .build_eth_l2_src_dst_init = &dr_ste_v0_build_eth_l2_src_dst_init, + .build_eth_l3_ipv6_src_init = &dr_ste_v0_build_eth_l3_ipv6_src_init, + .build_eth_l3_ipv6_dst_init = &dr_ste_v0_build_eth_l3_ipv6_dst_init, + .build_eth_l3_ipv4_5_tuple_init = &dr_ste_v0_build_eth_l3_ipv4_5_tuple_init, + .build_eth_l2_src_init = &dr_ste_v0_build_eth_l2_src_init, + .build_eth_l2_dst_init = &dr_ste_v0_build_eth_l2_dst_init, + .build_eth_l2_tnl_init = &dr_ste_v0_build_eth_l2_tnl_init, + .build_eth_l3_ipv4_misc_init = &dr_ste_v0_build_eth_l3_ipv4_misc_init, + .build_eth_ipv6_l3_l4_init = &dr_ste_v0_build_eth_ipv6_l3_l4_init, + .build_mpls_init = &dr_ste_v0_build_mpls_init, + .build_tnl_gre_init = &dr_ste_v0_build_tnl_gre_init, + .build_tnl_mpls_init = &dr_ste_v0_build_tnl_mpls_init, + .build_tnl_mpls_over_udp_init = &dr_ste_v0_build_tnl_mpls_over_udp_init, + .build_tnl_mpls_over_gre_init = &dr_ste_v0_build_tnl_mpls_over_gre_init, + .build_icmp_init = &dr_ste_v0_build_icmp_init, + .build_general_purpose_init = &dr_ste_v0_build_general_purpose_init, + .build_eth_l4_misc_init = &dr_ste_v0_build_eth_l4_misc_init, + .build_tnl_vxlan_gpe_init = &dr_ste_v0_build_flex_parser_tnl_vxlan_gpe_init, + .build_tnl_geneve_init = &dr_ste_v0_build_flex_parser_tnl_geneve_init, + .build_tnl_geneve_tlv_opt_init = &dr_ste_v0_build_flex_parser_tnl_geneve_tlv_opt_init, + .build_register_0_init = &dr_ste_v0_build_register_0_init, + .build_register_1_init = &dr_ste_v0_build_register_1_init, + .build_src_gvmi_qpn_init = &dr_ste_v0_build_src_gvmi_qpn_init, + .build_flex_parser_0_init = &dr_ste_v0_build_flex_parser_0_init, + .build_flex_parser_1_init = &dr_ste_v0_build_flex_parser_1_init, + .build_tnl_gtpu_init = &dr_ste_v0_build_flex_parser_tnl_gtpu_init, + .build_tnl_header_0_1_init = &dr_ste_v0_build_tnl_header_0_1_init, + .build_tnl_gtpu_flex_parser_0_init = &dr_ste_v0_build_tnl_gtpu_flex_parser_0_init, + .build_tnl_gtpu_flex_parser_1_init = &dr_ste_v0_build_tnl_gtpu_flex_parser_1_init, + + /* Getters and Setters */ + .ste_init = &dr_ste_v0_init, + .set_next_lu_type = &dr_ste_v0_set_next_lu_type, + .get_next_lu_type = &dr_ste_v0_get_next_lu_type, + .set_miss_addr = &dr_ste_v0_set_miss_addr, + .get_miss_addr = &dr_ste_v0_get_miss_addr, + .set_hit_addr = &dr_ste_v0_set_hit_addr, + .set_byte_mask = &dr_ste_v0_set_byte_mask, + .get_byte_mask = &dr_ste_v0_get_byte_mask, + + /* Actions */ + .actions_caps = DR_STE_CTX_ACTION_CAP_NONE, + .set_actions_rx = &dr_ste_v0_set_actions_rx, + .set_actions_tx = &dr_ste_v0_set_actions_tx, + .modify_field_arr_sz = ARRAY_SIZE(dr_ste_v0_action_modify_field_arr), + .modify_field_arr = dr_ste_v0_action_modify_field_arr, + .set_action_set = &dr_ste_v0_set_action_set, + .set_action_add = &dr_ste_v0_set_action_add, + .set_action_copy = &dr_ste_v0_set_action_copy, + .set_action_decap_l3_list = &dr_ste_v0_set_action_decap_l3_list, +}; + +struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v0(void) +{ + return &ste_ctx_v0; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.c new file mode 100644 index 00000000000000..1d49704b95427e --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.c @@ -0,0 +1,2341 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. */ + +#include +#include "mlx5_ifc_dr_ste_v1.h" +#include "dr_ste_v1.h" + +#define DR_STE_CALC_DFNR_TYPE(lookup_type, inner) \ + ((inner) ? DR_STE_V1_LU_TYPE_##lookup_type##_I : \ + DR_STE_V1_LU_TYPE_##lookup_type##_O) + +enum dr_ste_v1_entry_format { + DR_STE_V1_TYPE_BWC_BYTE = 0x0, + DR_STE_V1_TYPE_BWC_DW = 0x1, + DR_STE_V1_TYPE_MATCH = 0x2, + DR_STE_V1_TYPE_MATCH_RANGES = 0x7, +}; + +/* Lookup type is built from 2B: [ Definer mode 1B ][ Definer index 1B ] */ +enum { + DR_STE_V1_LU_TYPE_NOP = 0x0000, + DR_STE_V1_LU_TYPE_ETHL2_TNL = 0x0002, + DR_STE_V1_LU_TYPE_IBL3_EXT = 0x0102, + DR_STE_V1_LU_TYPE_ETHL2_O = 0x0003, + DR_STE_V1_LU_TYPE_IBL4 = 0x0103, + DR_STE_V1_LU_TYPE_ETHL2_I = 0x0004, + DR_STE_V1_LU_TYPE_SRC_QP_GVMI = 0x0104, + DR_STE_V1_LU_TYPE_ETHL2_SRC_O = 0x0005, + DR_STE_V1_LU_TYPE_ETHL2_HEADERS_O = 0x0105, + DR_STE_V1_LU_TYPE_ETHL2_SRC_I = 0x0006, + DR_STE_V1_LU_TYPE_ETHL2_HEADERS_I = 0x0106, + DR_STE_V1_LU_TYPE_ETHL3_IPV4_5_TUPLE_O = 0x0007, + DR_STE_V1_LU_TYPE_IPV6_DES_O = 0x0107, + DR_STE_V1_LU_TYPE_ETHL3_IPV4_5_TUPLE_I = 0x0008, + DR_STE_V1_LU_TYPE_IPV6_DES_I = 0x0108, + DR_STE_V1_LU_TYPE_ETHL4_O = 0x0009, + DR_STE_V1_LU_TYPE_IPV6_SRC_O = 0x0109, + DR_STE_V1_LU_TYPE_ETHL4_I = 0x000a, + DR_STE_V1_LU_TYPE_IPV6_SRC_I = 0x010a, + DR_STE_V1_LU_TYPE_ETHL2_SRC_DST_O = 0x000b, + DR_STE_V1_LU_TYPE_MPLS_O = 0x010b, + DR_STE_V1_LU_TYPE_ETHL2_SRC_DST_I = 0x000c, + DR_STE_V1_LU_TYPE_MPLS_I = 0x010c, + DR_STE_V1_LU_TYPE_ETHL3_IPV4_MISC_O = 0x000d, + DR_STE_V1_LU_TYPE_GRE = 0x010d, + DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER = 0x000e, + DR_STE_V1_LU_TYPE_GENERAL_PURPOSE = 0x010e, + DR_STE_V1_LU_TYPE_ETHL3_IPV4_MISC_I = 0x000f, + DR_STE_V1_LU_TYPE_STEERING_REGISTERS_0 = 0x010f, + DR_STE_V1_LU_TYPE_STEERING_REGISTERS_1 = 0x0110, + DR_STE_V1_LU_TYPE_FLEX_PARSER_OK = 0x0011, + DR_STE_V1_LU_TYPE_FLEX_PARSER_0 = 0x0111, + DR_STE_V1_LU_TYPE_FLEX_PARSER_1 = 0x0112, + DR_STE_V1_LU_TYPE_ETHL4_MISC_O = 0x0113, + DR_STE_V1_LU_TYPE_ETHL4_MISC_I = 0x0114, + DR_STE_V1_LU_TYPE_INVALID = 0x00ff, + DR_STE_V1_LU_TYPE_DONT_CARE = MLX5DR_STE_LU_TYPE_DONT_CARE, +}; + +enum dr_ste_v1_header_anchors { + DR_STE_HEADER_ANCHOR_START_OUTER = 0x00, + DR_STE_HEADER_ANCHOR_1ST_VLAN = 0x02, + DR_STE_HEADER_ANCHOR_IPV6_IPV4 = 0x07, + DR_STE_HEADER_ANCHOR_INNER_MAC = 0x13, + DR_STE_HEADER_ANCHOR_INNER_IPV6_IPV4 = 0x19, +}; + +enum dr_ste_v1_action_size { + DR_STE_ACTION_SINGLE_SZ = 4, + DR_STE_ACTION_DOUBLE_SZ = 8, + DR_STE_ACTION_TRIPLE_SZ = 12, +}; + +enum dr_ste_v1_action_insert_ptr_attr { + DR_STE_V1_ACTION_INSERT_PTR_ATTR_NONE = 0, /* Regular push header (e.g. push vlan) */ + DR_STE_V1_ACTION_INSERT_PTR_ATTR_ENCAP = 1, /* Encapsulation / Tunneling */ + DR_STE_V1_ACTION_INSERT_PTR_ATTR_ESP = 2, /* IPsec */ +}; + +enum dr_ste_v1_action_id { + DR_STE_V1_ACTION_ID_NOP = 0x00, + DR_STE_V1_ACTION_ID_COPY = 0x05, + DR_STE_V1_ACTION_ID_SET = 0x06, + DR_STE_V1_ACTION_ID_ADD = 0x07, + DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE = 0x08, + DR_STE_V1_ACTION_ID_REMOVE_HEADER_TO_HEADER = 0x09, + DR_STE_V1_ACTION_ID_INSERT_INLINE = 0x0a, + DR_STE_V1_ACTION_ID_INSERT_POINTER = 0x0b, + DR_STE_V1_ACTION_ID_FLOW_TAG = 0x0c, + DR_STE_V1_ACTION_ID_QUEUE_ID_SEL = 0x0d, + DR_STE_V1_ACTION_ID_ACCELERATED_LIST = 0x0e, + DR_STE_V1_ACTION_ID_MODIFY_LIST = 0x0f, + DR_STE_V1_ACTION_ID_ASO = 0x12, + DR_STE_V1_ACTION_ID_TRAILER = 0x13, + DR_STE_V1_ACTION_ID_COUNTER_ID = 0x14, + DR_STE_V1_ACTION_ID_MAX = 0x21, + /* use for special cases */ + DR_STE_V1_ACTION_ID_SPECIAL_ENCAP_L3 = 0x22, +}; + +enum { + DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_0 = 0x00, + DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_1 = 0x01, + DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_2 = 0x02, + DR_STE_V1_ACTION_MDFY_FLD_SRC_L2_OUT_0 = 0x08, + DR_STE_V1_ACTION_MDFY_FLD_SRC_L2_OUT_1 = 0x09, + DR_STE_V1_ACTION_MDFY_FLD_L3_OUT_0 = 0x0e, + DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0 = 0x18, + DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_1 = 0x19, + DR_STE_V1_ACTION_MDFY_FLD_IPV4_OUT_0 = 0x40, + DR_STE_V1_ACTION_MDFY_FLD_IPV4_OUT_1 = 0x41, + DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_0 = 0x44, + DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_1 = 0x45, + DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_2 = 0x46, + DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_3 = 0x47, + DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_0 = 0x4c, + DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_1 = 0x4d, + DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_2 = 0x4e, + DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_3 = 0x4f, + DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_0 = 0x5e, + DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_1 = 0x5f, + DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_0 = 0x6f, + DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_1 = 0x70, + DR_STE_V1_ACTION_MDFY_FLD_METADATA_2_CQE = 0x7b, + DR_STE_V1_ACTION_MDFY_FLD_GNRL_PURPOSE = 0x7c, + DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2_0 = 0x8c, + DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2_1 = 0x8d, + DR_STE_V1_ACTION_MDFY_FLD_REGISTER_1_0 = 0x8e, + DR_STE_V1_ACTION_MDFY_FLD_REGISTER_1_1 = 0x8f, + DR_STE_V1_ACTION_MDFY_FLD_REGISTER_0_0 = 0x90, + DR_STE_V1_ACTION_MDFY_FLD_REGISTER_0_1 = 0x91, +}; + +enum dr_ste_v1_aso_ctx_type { + DR_STE_V1_ASO_CTX_TYPE_POLICERS = 0x2, +}; + +static const struct mlx5dr_ste_action_modify_field dr_ste_v1_action_modify_field_arr[] = { + [MLX5_ACTION_IN_FIELD_OUT_SMAC_47_16] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_SRC_L2_OUT_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_SMAC_15_0] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_SRC_L2_OUT_1, .start = 16, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_ETHERTYPE] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_1, .start = 0, .end = 15, + }, + [MLX5_ACTION_IN_FIELD_OUT_DMAC_47_16] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_DMAC_15_0] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_1, .start = 16, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_IP_DSCP] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L3_OUT_0, .start = 18, .end = 23, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_FLAGS] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_1, .start = 16, .end = 24, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0, .start = 16, .end = 31, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0, .start = 0, .end = 15, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_IP_TTL] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L3_OUT_0, .start = 8, .end = 15, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L3_OUT_0, .start = 8, .end = 15, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0, .start = 16, .end = 31, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, + }, + [MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L4_OUT_0, .start = 0, .end = 15, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_0, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_1, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_2, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_SRC_OUT_3, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_0, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_1, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_2, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV6_DST_OUT_3, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV4] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV4_OUT_0, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV4] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_IPV4_OUT_1, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_A] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_GNRL_PURPOSE, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_B] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_METADATA_2_CQE, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_0] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_0_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_1] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_0_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_2] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_1_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_3] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_1_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_4] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_5] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_REGISTER_2_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_TCP_MISC_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_FIRST_VID] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_L2_OUT_2, .start = 0, .end = 15, + }, + [MLX5_ACTION_IN_FIELD_OUT_EMD_31_0] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_EMD_47_32] = { + .hw_field = DR_STE_V1_ACTION_MDFY_FLD_CFG_HDR_0_0, .start = 0, .end = 15, + }, +}; + +static void dr_ste_v1_set_entry_type(u8 *hw_ste_p, u8 entry_type) +{ + MLX5_SET(ste_match_bwc_v1, hw_ste_p, entry_format, entry_type); +} + +bool dr_ste_v1_is_miss_addr_set(u8 *hw_ste_p) +{ + u8 entry_type = MLX5_GET(ste_match_bwc_v1, hw_ste_p, entry_format); + + /* unlike MATCH STE, for MATCH_RANGES STE both hit and miss addresses + * are part of the action, so they both set as part of STE init + */ + return entry_type == DR_STE_V1_TYPE_MATCH_RANGES; +} + +void dr_ste_v1_set_miss_addr(u8 *hw_ste_p, u64 miss_addr) +{ + u64 index = miss_addr >> 6; + + MLX5_SET(ste_match_bwc_v1, hw_ste_p, miss_address_39_32, index >> 26); + MLX5_SET(ste_match_bwc_v1, hw_ste_p, miss_address_31_6, index); +} + +u64 dr_ste_v1_get_miss_addr(u8 *hw_ste_p) +{ + u64 index = + ((u64)MLX5_GET(ste_match_bwc_v1, hw_ste_p, miss_address_31_6) | + ((u64)MLX5_GET(ste_match_bwc_v1, hw_ste_p, miss_address_39_32)) << 26); + + return index << 6; +} + +void dr_ste_v1_set_byte_mask(u8 *hw_ste_p, u16 byte_mask) +{ + MLX5_SET(ste_match_bwc_v1, hw_ste_p, byte_mask, byte_mask); +} + +u16 dr_ste_v1_get_byte_mask(u8 *hw_ste_p) +{ + return MLX5_GET(ste_match_bwc_v1, hw_ste_p, byte_mask); +} + +static void dr_ste_v1_set_lu_type(u8 *hw_ste_p, u16 lu_type) +{ + MLX5_SET(ste_match_bwc_v1, hw_ste_p, entry_format, lu_type >> 8); + MLX5_SET(ste_match_bwc_v1, hw_ste_p, match_definer_ctx_idx, lu_type & 0xFF); +} + +void dr_ste_v1_set_next_lu_type(u8 *hw_ste_p, u16 lu_type) +{ + MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_entry_format, lu_type >> 8); + MLX5_SET(ste_match_bwc_v1, hw_ste_p, hash_definer_ctx_idx, lu_type & 0xFF); +} + +u16 dr_ste_v1_get_next_lu_type(u8 *hw_ste_p) +{ + u8 mode = MLX5_GET(ste_match_bwc_v1, hw_ste_p, next_entry_format); + u8 index = MLX5_GET(ste_match_bwc_v1, hw_ste_p, hash_definer_ctx_idx); + + return (mode << 8 | index); +} + +static void dr_ste_v1_set_hit_gvmi(u8 *hw_ste_p, u16 gvmi) +{ + MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_table_base_63_48, gvmi); +} + +void dr_ste_v1_set_hit_addr(u8 *hw_ste_p, u64 icm_addr, u32 ht_size) +{ + u64 index = (icm_addr >> 5) | ht_size; + + MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_table_base_39_32_size, index >> 27); + MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_table_base_31_5_size, index); +} + +void dr_ste_v1_init(u8 *hw_ste_p, u16 lu_type, bool is_rx, u16 gvmi) +{ + dr_ste_v1_set_lu_type(hw_ste_p, lu_type); + dr_ste_v1_set_next_lu_type(hw_ste_p, MLX5DR_STE_LU_TYPE_DONT_CARE); + + MLX5_SET(ste_match_bwc_v1, hw_ste_p, gvmi, gvmi); + MLX5_SET(ste_match_bwc_v1, hw_ste_p, next_table_base_63_48, gvmi); + MLX5_SET(ste_match_bwc_v1, hw_ste_p, miss_address_63_48, gvmi); +} + +void dr_ste_v1_prepare_for_postsend(u8 *hw_ste_p, u32 ste_size) +{ + u8 *tag = hw_ste_p + DR_STE_SIZE_CTRL; + u8 *mask = tag + DR_STE_SIZE_TAG; + u8 tmp_tag[DR_STE_SIZE_TAG] = {}; + + if (ste_size == DR_STE_SIZE_CTRL) + return; + + WARN_ON(ste_size != DR_STE_SIZE); + + /* Backup tag */ + memcpy(tmp_tag, tag, DR_STE_SIZE_TAG); + + /* Swap mask and tag both are the same size */ + memcpy(tag, mask, DR_STE_SIZE_MASK); + memcpy(mask, tmp_tag, DR_STE_SIZE_TAG); +} + +static void dr_ste_v1_set_rx_flow_tag(u8 *s_action, u32 flow_tag) +{ + MLX5_SET(ste_single_action_flow_tag_v1, s_action, action_id, + DR_STE_V1_ACTION_ID_FLOW_TAG); + MLX5_SET(ste_single_action_flow_tag_v1, s_action, flow_tag, flow_tag); +} + +static void dr_ste_v1_set_counter_id(u8 *hw_ste_p, u32 ctr_id) +{ + MLX5_SET(ste_match_bwc_v1, hw_ste_p, counter_id, ctr_id); +} + +static void dr_ste_v1_set_reparse(u8 *hw_ste_p) +{ + MLX5_SET(ste_match_bwc_v1, hw_ste_p, reparse, 1); +} + +static void dr_ste_v1_set_encap(u8 *hw_ste_p, u8 *d_action, + u32 reformat_id, int size) +{ + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, action_id, + DR_STE_V1_ACTION_ID_INSERT_POINTER); + /* The hardware expects here size in words (2 byte) */ + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, size, size / 2); + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, pointer, reformat_id); + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, attributes, + DR_STE_V1_ACTION_INSERT_PTR_ATTR_ENCAP); + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_insert_hdr(u8 *hw_ste_p, u8 *d_action, + u32 reformat_id, + u8 anchor, u8 offset, + int size) +{ + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, + action_id, DR_STE_V1_ACTION_ID_INSERT_POINTER); + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, start_anchor, anchor); + + /* The hardware expects here size and offset in words (2 byte) */ + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, size, size / 2); + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, start_offset, offset / 2); + + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, pointer, reformat_id); + MLX5_SET(ste_double_action_insert_with_ptr_v1, d_action, attributes, + DR_STE_V1_ACTION_INSERT_PTR_ATTR_NONE); + + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_remove_hdr(u8 *hw_ste_p, u8 *s_action, + u8 anchor, u8 offset, + int size) +{ + MLX5_SET(ste_single_action_remove_header_size_v1, s_action, + action_id, DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE); + MLX5_SET(ste_single_action_remove_header_size_v1, s_action, start_anchor, anchor); + + /* The hardware expects here size and offset in words (2 byte) */ + MLX5_SET(ste_single_action_remove_header_size_v1, s_action, remove_size, size / 2); + MLX5_SET(ste_single_action_remove_header_size_v1, s_action, start_offset, offset / 2); + + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_push_vlan(u8 *hw_ste_p, u8 *d_action, + u32 vlan_hdr) +{ + MLX5_SET(ste_double_action_insert_with_inline_v1, d_action, + action_id, DR_STE_V1_ACTION_ID_INSERT_INLINE); + /* The hardware expects offset to vlan header in words (2 byte) */ + MLX5_SET(ste_double_action_insert_with_inline_v1, d_action, + start_offset, HDR_LEN_L2_MACS >> 1); + MLX5_SET(ste_double_action_insert_with_inline_v1, d_action, + inline_data, vlan_hdr); + + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_pop_vlan(u8 *hw_ste_p, u8 *s_action, u8 vlans_num) +{ + MLX5_SET(ste_single_action_remove_header_size_v1, s_action, + action_id, DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE); + MLX5_SET(ste_single_action_remove_header_size_v1, s_action, + start_anchor, DR_STE_HEADER_ANCHOR_1ST_VLAN); + /* The hardware expects here size in words (2 byte) */ + MLX5_SET(ste_single_action_remove_header_size_v1, s_action, + remove_size, (HDR_LEN_L2_VLAN >> 1) * vlans_num); + + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_encap_l3(u8 *hw_ste_p, + u8 *frst_s_action, + u8 *scnd_d_action, + u32 reformat_id, + int size) +{ + /* Remove L2 headers */ + MLX5_SET(ste_single_action_remove_header_v1, frst_s_action, action_id, + DR_STE_V1_ACTION_ID_REMOVE_HEADER_TO_HEADER); + MLX5_SET(ste_single_action_remove_header_v1, frst_s_action, end_anchor, + DR_STE_HEADER_ANCHOR_IPV6_IPV4); + + /* Encapsulate with given reformat ID */ + MLX5_SET(ste_double_action_insert_with_ptr_v1, scnd_d_action, action_id, + DR_STE_V1_ACTION_ID_INSERT_POINTER); + /* The hardware expects here size in words (2 byte) */ + MLX5_SET(ste_double_action_insert_with_ptr_v1, scnd_d_action, size, size / 2); + MLX5_SET(ste_double_action_insert_with_ptr_v1, scnd_d_action, pointer, reformat_id); + MLX5_SET(ste_double_action_insert_with_ptr_v1, scnd_d_action, attributes, + DR_STE_V1_ACTION_INSERT_PTR_ATTR_ENCAP); + + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_rx_decap(u8 *hw_ste_p, u8 *s_action) +{ + MLX5_SET(ste_single_action_remove_header_v1, s_action, action_id, + DR_STE_V1_ACTION_ID_REMOVE_HEADER_TO_HEADER); + MLX5_SET(ste_single_action_remove_header_v1, s_action, decap, 1); + MLX5_SET(ste_single_action_remove_header_v1, s_action, vni_to_cqe, 1); + MLX5_SET(ste_single_action_remove_header_v1, s_action, end_anchor, + DR_STE_HEADER_ANCHOR_INNER_MAC); + + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_accelerated_rewrite_actions(u8 *hw_ste_p, + u8 *d_action, + u16 num_of_actions, + u32 rewrite_pattern, + u32 rewrite_args, + u8 *action_data) +{ + if (action_data) { + memcpy(d_action, action_data, DR_MODIFY_ACTION_SIZE); + } else { + MLX5_SET(ste_double_action_accelerated_modify_action_list_v1, d_action, + action_id, DR_STE_V1_ACTION_ID_ACCELERATED_LIST); + MLX5_SET(ste_double_action_accelerated_modify_action_list_v1, d_action, + modify_actions_pattern_pointer, rewrite_pattern); + MLX5_SET(ste_double_action_accelerated_modify_action_list_v1, d_action, + number_of_modify_actions, num_of_actions); + MLX5_SET(ste_double_action_accelerated_modify_action_list_v1, d_action, + modify_actions_argument_pointer, rewrite_args); + } + + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_basic_rewrite_actions(u8 *hw_ste_p, + u8 *s_action, + u16 num_of_actions, + u32 rewrite_index) +{ + MLX5_SET(ste_single_action_modify_list_v1, s_action, action_id, + DR_STE_V1_ACTION_ID_MODIFY_LIST); + MLX5_SET(ste_single_action_modify_list_v1, s_action, num_of_modify_actions, + num_of_actions); + MLX5_SET(ste_single_action_modify_list_v1, s_action, modify_actions_ptr, + rewrite_index); + + dr_ste_v1_set_reparse(hw_ste_p); +} + +static void dr_ste_v1_set_rewrite_actions(u8 *hw_ste_p, + u8 *action, + u16 num_of_actions, + u32 rewrite_pattern, + u32 rewrite_args, + u8 *action_data) +{ + if (rewrite_pattern != MLX5DR_INVALID_PATTERN_INDEX) + return dr_ste_v1_set_accelerated_rewrite_actions(hw_ste_p, + action, + num_of_actions, + rewrite_pattern, + rewrite_args, + action_data); + + /* fall back to the code that doesn't support accelerated modify header */ + return dr_ste_v1_set_basic_rewrite_actions(hw_ste_p, + action, + num_of_actions, + rewrite_args); +} + +static void dr_ste_v1_set_aso_flow_meter(u8 *d_action, + u32 object_id, + u32 offset, + u8 dest_reg_id, + u8 init_color) +{ + MLX5_SET(ste_double_action_aso_v1, d_action, action_id, + DR_STE_V1_ACTION_ID_ASO); + MLX5_SET(ste_double_action_aso_v1, d_action, aso_context_number, + object_id + (offset / MLX5DR_ASO_FLOW_METER_NUM_PER_OBJ)); + /* Convert reg_c index to HW 64bit index */ + MLX5_SET(ste_double_action_aso_v1, d_action, dest_reg_id, + (dest_reg_id - 1) / 2); + MLX5_SET(ste_double_action_aso_v1, d_action, aso_context_type, + DR_STE_V1_ASO_CTX_TYPE_POLICERS); + MLX5_SET(ste_double_action_aso_v1, d_action, flow_meter.line_id, + offset % MLX5DR_ASO_FLOW_METER_NUM_PER_OBJ); + MLX5_SET(ste_double_action_aso_v1, d_action, flow_meter.initial_color, + init_color); +} + +static void dr_ste_v1_set_match_range_pkt_len(u8 *hw_ste_p, u32 definer_id, + u32 min, u32 max) +{ + MLX5_SET(ste_match_ranges_v1, hw_ste_p, match_definer_ctx_idx, definer_id); + + /* When the STE will be sent, its mask and tags will be swapped in + * dr_ste_v1_prepare_for_postsend(). This, however, is match range STE + * which doesn't have mask, and shouldn't have mask/tag swapped. + * We're using the common utilities functions to send this STE, so need + * to allow for this swapping - place the values in the corresponding + * locations to allow flipping them when writing to ICM. + * + * min/max_value_2 corresponds to match_dw_0 in its definer. + * To allow mask/tag swapping, writing the min/max_2 to min/max_0. + * + * Pkt len is 2 bytes that are stored in the higher section of the DW. + */ + MLX5_SET(ste_match_ranges_v1, hw_ste_p, min_value_0, min << 16); + MLX5_SET(ste_match_ranges_v1, hw_ste_p, max_value_0, max << 16); +} + +static void dr_ste_v1_arr_init_next_match(u8 **last_ste, + u32 *added_stes, + u16 gvmi) +{ + u8 *action; + + (*added_stes)++; + *last_ste += DR_STE_SIZE; + dr_ste_v1_init(*last_ste, MLX5DR_STE_LU_TYPE_DONT_CARE, 0, gvmi); + dr_ste_v1_set_entry_type(*last_ste, DR_STE_V1_TYPE_MATCH); + + action = MLX5_ADDR_OF(ste_mask_and_match_v1, *last_ste, action); + memset(action, 0, MLX5_FLD_SZ_BYTES(ste_mask_and_match_v1, action)); +} + +static void dr_ste_v1_arr_init_next_match_range(u8 **last_ste, + u32 *added_stes, + u16 gvmi) +{ + dr_ste_v1_arr_init_next_match(last_ste, added_stes, gvmi); + dr_ste_v1_set_entry_type(*last_ste, DR_STE_V1_TYPE_MATCH_RANGES); +} + +void dr_ste_v1_set_actions_tx(struct mlx5dr_domain *dmn, + u8 *action_type_set, + u32 actions_caps, + u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes) +{ + u8 *action = MLX5_ADDR_OF(ste_match_bwc_v1, last_ste, action); + u8 action_sz = DR_STE_ACTION_DOUBLE_SZ; + bool allow_modify_hdr = true; + bool allow_encap = true; + + if (action_type_set[DR_ACTION_TYP_POP_VLAN]) { + if (action_sz < DR_STE_ACTION_SINGLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, + attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, + last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_pop_vlan(last_ste, action, attr->vlans.count); + action_sz -= DR_STE_ACTION_SINGLE_SZ; + action += DR_STE_ACTION_SINGLE_SZ; + + /* Check if vlan_pop and modify_hdr on same STE is supported */ + if (!(actions_caps & DR_STE_CTX_ACTION_CAP_POP_MDFY)) + allow_modify_hdr = false; + } + + if (action_type_set[DR_ACTION_TYP_MODIFY_HDR]) { + if (!allow_modify_hdr || action_sz < DR_STE_ACTION_DOUBLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, + attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, + last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_rewrite_actions(last_ste, action, + attr->modify_actions, + attr->modify_pat_idx, + attr->modify_index, + attr->single_modify_action); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + allow_encap = false; + } + + if (action_type_set[DR_ACTION_TYP_PUSH_VLAN]) { + int i; + + for (i = 0; i < attr->vlans.count; i++) { + if (action_sz < DR_STE_ACTION_DOUBLE_SZ || !allow_encap) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + allow_encap = true; + } + dr_ste_v1_set_push_vlan(last_ste, action, + attr->vlans.headers[i]); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + } + } + + if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L2]) { + if (!allow_encap || action_sz < DR_STE_ACTION_DOUBLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + allow_encap = true; + } + dr_ste_v1_set_encap(last_ste, action, + attr->reformat.id, + attr->reformat.size); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + } else if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]) { + u8 *d_action; + + if (action_sz < DR_STE_ACTION_TRIPLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + d_action = action + DR_STE_ACTION_SINGLE_SZ; + + dr_ste_v1_set_encap_l3(last_ste, + action, d_action, + attr->reformat.id, + attr->reformat.size); + action_sz -= DR_STE_ACTION_TRIPLE_SZ; + action += DR_STE_ACTION_TRIPLE_SZ; + } else if (action_type_set[DR_ACTION_TYP_INSERT_HDR]) { + if (!allow_encap || action_sz < DR_STE_ACTION_DOUBLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_insert_hdr(last_ste, action, + attr->reformat.id, + attr->reformat.param_0, + attr->reformat.param_1, + attr->reformat.size); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + } else if (action_type_set[DR_ACTION_TYP_REMOVE_HDR]) { + if (action_sz < DR_STE_ACTION_SINGLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_remove_hdr(last_ste, action, + attr->reformat.param_0, + attr->reformat.param_1, + attr->reformat.size); + action_sz -= DR_STE_ACTION_SINGLE_SZ; + action += DR_STE_ACTION_SINGLE_SZ; + } + + if (action_type_set[DR_ACTION_TYP_ASO_FLOW_METER]) { + if (action_sz < DR_STE_ACTION_DOUBLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_aso_flow_meter(action, + attr->aso_flow_meter.obj_id, + attr->aso_flow_meter.offset, + attr->aso_flow_meter.dest_reg_id, + attr->aso_flow_meter.init_color); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + } + + if (action_type_set[DR_ACTION_TYP_RANGE]) { + /* match ranges requires a new STE of its own type */ + dr_ste_v1_arr_init_next_match_range(&last_ste, added_stes, attr->gvmi); + dr_ste_v1_set_miss_addr(last_ste, attr->range.miss_icm_addr); + + /* we do not support setting any action on the match ranges STE */ + action_sz = 0; + + dr_ste_v1_set_match_range_pkt_len(last_ste, + attr->range.definer_id, + attr->range.min, + attr->range.max); + } + + /* set counter ID on the last STE to adhere to DMFS behavior */ + if (action_type_set[DR_ACTION_TYP_CTR]) + dr_ste_v1_set_counter_id(last_ste, attr->ctr_id); + + dr_ste_v1_set_hit_gvmi(last_ste, attr->hit_gvmi); + dr_ste_v1_set_hit_addr(last_ste, attr->final_icm_addr, 1); +} + +void dr_ste_v1_set_actions_rx(struct mlx5dr_domain *dmn, + u8 *action_type_set, + u32 actions_caps, + u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes) +{ + u8 *action = MLX5_ADDR_OF(ste_match_bwc_v1, last_ste, action); + u8 action_sz = DR_STE_ACTION_DOUBLE_SZ; + bool allow_modify_hdr = true; + bool allow_ctr = true; + + if (action_type_set[DR_ACTION_TYP_TNL_L3_TO_L2]) { + dr_ste_v1_set_rewrite_actions(last_ste, action, + attr->decap_actions, + attr->decap_pat_idx, + attr->decap_index, + NULL); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + allow_modify_hdr = false; + allow_ctr = false; + } else if (action_type_set[DR_ACTION_TYP_TNL_L2_TO_L2]) { + dr_ste_v1_set_rx_decap(last_ste, action); + action_sz -= DR_STE_ACTION_SINGLE_SZ; + action += DR_STE_ACTION_SINGLE_SZ; + allow_modify_hdr = false; + allow_ctr = false; + } + + if (action_type_set[DR_ACTION_TYP_TAG]) { + if (action_sz < DR_STE_ACTION_SINGLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + allow_modify_hdr = true; + allow_ctr = true; + } + dr_ste_v1_set_rx_flow_tag(action, attr->flow_tag); + action_sz -= DR_STE_ACTION_SINGLE_SZ; + action += DR_STE_ACTION_SINGLE_SZ; + } + + if (action_type_set[DR_ACTION_TYP_POP_VLAN]) { + if (action_sz < DR_STE_ACTION_SINGLE_SZ || + !allow_modify_hdr) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + + dr_ste_v1_set_pop_vlan(last_ste, action, attr->vlans.count); + action_sz -= DR_STE_ACTION_SINGLE_SZ; + action += DR_STE_ACTION_SINGLE_SZ; + allow_ctr = false; + + /* Check if vlan_pop and modify_hdr on same STE is supported */ + if (!(actions_caps & DR_STE_CTX_ACTION_CAP_POP_MDFY)) + allow_modify_hdr = false; + } + + if (action_type_set[DR_ACTION_TYP_MODIFY_HDR]) { + /* Modify header and decapsulation must use different STEs */ + if (!allow_modify_hdr || action_sz < DR_STE_ACTION_DOUBLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + allow_modify_hdr = true; + allow_ctr = true; + } + dr_ste_v1_set_rewrite_actions(last_ste, action, + attr->modify_actions, + attr->modify_pat_idx, + attr->modify_index, + attr->single_modify_action); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + } + + if (action_type_set[DR_ACTION_TYP_PUSH_VLAN]) { + int i; + + for (i = 0; i < attr->vlans.count; i++) { + if (action_sz < DR_STE_ACTION_DOUBLE_SZ || + !allow_modify_hdr) { + dr_ste_v1_arr_init_next_match(&last_ste, + added_stes, + attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, + last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_push_vlan(last_ste, action, + attr->vlans.headers[i]); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + } + } + + if (action_type_set[DR_ACTION_TYP_CTR]) { + /* Counter action set after decap and before insert_hdr + * to exclude decaped / encaped header respectively. + */ + if (!allow_ctr) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + allow_modify_hdr = true; + } + dr_ste_v1_set_counter_id(last_ste, attr->ctr_id); + allow_ctr = false; + } + + if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L2]) { + if (action_sz < DR_STE_ACTION_DOUBLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_encap(last_ste, action, + attr->reformat.id, + attr->reformat.size); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + allow_modify_hdr = false; + } else if (action_type_set[DR_ACTION_TYP_L2_TO_TNL_L3]) { + u8 *d_action; + + if (action_sz < DR_STE_ACTION_TRIPLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + + d_action = action + DR_STE_ACTION_SINGLE_SZ; + + dr_ste_v1_set_encap_l3(last_ste, + action, d_action, + attr->reformat.id, + attr->reformat.size); + action_sz -= DR_STE_ACTION_TRIPLE_SZ; + allow_modify_hdr = false; + } else if (action_type_set[DR_ACTION_TYP_INSERT_HDR]) { + /* Modify header, decap, and encap must use different STEs */ + if (!allow_modify_hdr || action_sz < DR_STE_ACTION_DOUBLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_insert_hdr(last_ste, action, + attr->reformat.id, + attr->reformat.param_0, + attr->reformat.param_1, + attr->reformat.size); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + allow_modify_hdr = false; + } else if (action_type_set[DR_ACTION_TYP_REMOVE_HDR]) { + if (action_sz < DR_STE_ACTION_SINGLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + allow_modify_hdr = true; + allow_ctr = true; + } + dr_ste_v1_set_remove_hdr(last_ste, action, + attr->reformat.param_0, + attr->reformat.param_1, + attr->reformat.size); + action_sz -= DR_STE_ACTION_SINGLE_SZ; + action += DR_STE_ACTION_SINGLE_SZ; + } + + if (action_type_set[DR_ACTION_TYP_ASO_FLOW_METER]) { + if (action_sz < DR_STE_ACTION_DOUBLE_SZ) { + dr_ste_v1_arr_init_next_match(&last_ste, added_stes, attr->gvmi); + action = MLX5_ADDR_OF(ste_mask_and_match_v1, last_ste, action); + action_sz = DR_STE_ACTION_TRIPLE_SZ; + } + dr_ste_v1_set_aso_flow_meter(action, + attr->aso_flow_meter.obj_id, + attr->aso_flow_meter.offset, + attr->aso_flow_meter.dest_reg_id, + attr->aso_flow_meter.init_color); + action_sz -= DR_STE_ACTION_DOUBLE_SZ; + action += DR_STE_ACTION_DOUBLE_SZ; + } + + if (action_type_set[DR_ACTION_TYP_RANGE]) { + /* match ranges requires a new STE of its own type */ + dr_ste_v1_arr_init_next_match_range(&last_ste, added_stes, attr->gvmi); + dr_ste_v1_set_miss_addr(last_ste, attr->range.miss_icm_addr); + + /* we do not support setting any action on the match ranges STE */ + action_sz = 0; + + dr_ste_v1_set_match_range_pkt_len(last_ste, + attr->range.definer_id, + attr->range.min, + attr->range.max); + } + + dr_ste_v1_set_hit_gvmi(last_ste, attr->hit_gvmi); + dr_ste_v1_set_hit_addr(last_ste, attr->final_icm_addr, 1); +} + +void dr_ste_v1_set_action_set(u8 *d_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data) +{ + shifter += MLX5_MODIFY_HEADER_V1_QW_OFFSET; + MLX5_SET(ste_double_action_set_v1, d_action, action_id, DR_STE_V1_ACTION_ID_SET); + MLX5_SET(ste_double_action_set_v1, d_action, destination_dw_offset, hw_field); + MLX5_SET(ste_double_action_set_v1, d_action, destination_left_shifter, shifter); + MLX5_SET(ste_double_action_set_v1, d_action, destination_length, length); + MLX5_SET(ste_double_action_set_v1, d_action, inline_data, data); +} + +void dr_ste_v1_set_action_add(u8 *d_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data) +{ + shifter += MLX5_MODIFY_HEADER_V1_QW_OFFSET; + MLX5_SET(ste_double_action_add_v1, d_action, action_id, DR_STE_V1_ACTION_ID_ADD); + MLX5_SET(ste_double_action_add_v1, d_action, destination_dw_offset, hw_field); + MLX5_SET(ste_double_action_add_v1, d_action, destination_left_shifter, shifter); + MLX5_SET(ste_double_action_add_v1, d_action, destination_length, length); + MLX5_SET(ste_double_action_add_v1, d_action, add_value, data); +} + +void dr_ste_v1_set_action_copy(u8 *d_action, + u8 dst_hw_field, + u8 dst_shifter, + u8 dst_len, + u8 src_hw_field, + u8 src_shifter) +{ + dst_shifter += MLX5_MODIFY_HEADER_V1_QW_OFFSET; + src_shifter += MLX5_MODIFY_HEADER_V1_QW_OFFSET; + MLX5_SET(ste_double_action_copy_v1, d_action, action_id, DR_STE_V1_ACTION_ID_COPY); + MLX5_SET(ste_double_action_copy_v1, d_action, destination_dw_offset, dst_hw_field); + MLX5_SET(ste_double_action_copy_v1, d_action, destination_left_shifter, dst_shifter); + MLX5_SET(ste_double_action_copy_v1, d_action, destination_length, dst_len); + MLX5_SET(ste_double_action_copy_v1, d_action, source_dw_offset, src_hw_field); + MLX5_SET(ste_double_action_copy_v1, d_action, source_right_shifter, src_shifter); +} + +#define DR_STE_DECAP_L3_ACTION_NUM 8 +#define DR_STE_L2_HDR_MAX_SZ 20 + +int dr_ste_v1_set_action_decap_l3_list(void *data, + u32 data_sz, + u8 *hw_action, + u32 hw_action_sz, + u16 *used_hw_action_num) +{ + u8 padded_data[DR_STE_L2_HDR_MAX_SZ] = {}; + void *data_ptr = padded_data; + u16 used_actions = 0; + u32 inline_data_sz; + u32 i; + + if (hw_action_sz / DR_STE_ACTION_DOUBLE_SZ < DR_STE_DECAP_L3_ACTION_NUM) + return -EINVAL; + + inline_data_sz = + MLX5_FLD_SZ_BYTES(ste_double_action_insert_with_inline_v1, inline_data); + + /* Add an alignment padding */ + memcpy(padded_data + data_sz % inline_data_sz, data, data_sz); + + /* Remove L2L3 outer headers */ + MLX5_SET(ste_single_action_remove_header_v1, hw_action, action_id, + DR_STE_V1_ACTION_ID_REMOVE_HEADER_TO_HEADER); + MLX5_SET(ste_single_action_remove_header_v1, hw_action, decap, 1); + MLX5_SET(ste_single_action_remove_header_v1, hw_action, vni_to_cqe, 1); + MLX5_SET(ste_single_action_remove_header_v1, hw_action, end_anchor, + DR_STE_HEADER_ANCHOR_INNER_IPV6_IPV4); + hw_action += DR_STE_ACTION_DOUBLE_SZ; + used_actions++; /* Remove and NOP are a single double action */ + + /* Point to the last dword of the header */ + data_ptr += (data_sz / inline_data_sz) * inline_data_sz; + + /* Add the new header using inline action 4Byte at a time, the header + * is added in reversed order to the beginning of the packet to avoid + * incorrect parsing by the HW. Since header is 14B or 18B an extra + * two bytes are padded and later removed. + */ + for (i = 0; i < data_sz / inline_data_sz + 1; i++) { + void *addr_inline; + + MLX5_SET(ste_double_action_insert_with_inline_v1, hw_action, action_id, + DR_STE_V1_ACTION_ID_INSERT_INLINE); + /* The hardware expects here offset to words (2 bytes) */ + MLX5_SET(ste_double_action_insert_with_inline_v1, hw_action, start_offset, 0); + + /* Copy bytes one by one to avoid endianness problem */ + addr_inline = MLX5_ADDR_OF(ste_double_action_insert_with_inline_v1, + hw_action, inline_data); + memcpy(addr_inline, data_ptr - i * inline_data_sz, inline_data_sz); + hw_action += DR_STE_ACTION_DOUBLE_SZ; + used_actions++; + } + + /* Remove first 2 extra bytes */ + MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, action_id, + DR_STE_V1_ACTION_ID_REMOVE_BY_SIZE); + MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, start_offset, 0); + /* The hardware expects here size in words (2 bytes) */ + MLX5_SET(ste_single_action_remove_header_size_v1, hw_action, remove_size, 1); + used_actions++; + + *used_hw_action_num = used_actions; + + return 0; +} + +static void dr_ste_v1_build_eth_l2_src_dst_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, dmac_47_16, mask, dmac_47_16); + DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, dmac_15_0, mask, dmac_15_0); + + DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, smac_47_16, mask, smac_47_16); + DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, smac_15_0, mask, smac_15_0); + + DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, first_vlan_id, mask, first_vid); + DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, first_cfi, mask, first_cfi); + DR_STE_SET_TAG(eth_l2_src_dst_v1, bit_mask, first_priority, mask, first_prio); + DR_STE_SET_ONES(eth_l2_src_dst_v1, bit_mask, l3_type, mask, ip_version); + + if (mask->cvlan_tag) { + MLX5_SET(ste_eth_l2_src_dst_v1, bit_mask, first_vlan_qualifier, -1); + mask->cvlan_tag = 0; + } else if (mask->svlan_tag) { + MLX5_SET(ste_eth_l2_src_dst_v1, bit_mask, first_vlan_qualifier, -1); + mask->svlan_tag = 0; + } +} + +static int dr_ste_v1_build_eth_l2_src_dst_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, dmac_47_16, spec, dmac_47_16); + DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, dmac_15_0, spec, dmac_15_0); + + DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, smac_47_16, spec, smac_47_16); + DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, smac_15_0, spec, smac_15_0); + + if (spec->ip_version == IP_VERSION_IPV4) { + MLX5_SET(ste_eth_l2_src_dst_v1, tag, l3_type, STE_IPV4); + spec->ip_version = 0; + } else if (spec->ip_version == IP_VERSION_IPV6) { + MLX5_SET(ste_eth_l2_src_dst_v1, tag, l3_type, STE_IPV6); + spec->ip_version = 0; + } else if (spec->ip_version) { + return -EINVAL; + } + + DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, first_vlan_id, spec, first_vid); + DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, first_cfi, spec, first_cfi); + DR_STE_SET_TAG(eth_l2_src_dst_v1, tag, first_priority, spec, first_prio); + + if (spec->cvlan_tag) { + MLX5_SET(ste_eth_l2_src_dst_v1, tag, first_vlan_qualifier, DR_STE_CVLAN); + spec->cvlan_tag = 0; + } else if (spec->svlan_tag) { + MLX5_SET(ste_eth_l2_src_dst_v1, tag, first_vlan_qualifier, DR_STE_SVLAN); + spec->svlan_tag = 0; + } + return 0; +} + +void dr_ste_v1_build_eth_l2_src_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l2_src_dst_bit_mask(mask, sb->inner, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL2_SRC_DST, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l2_src_dst_tag; +} + +static int dr_ste_v1_build_eth_l3_ipv6_dst_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_127_96, spec, dst_ip_127_96); + DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_95_64, spec, dst_ip_95_64); + DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_63_32, spec, dst_ip_63_32); + DR_STE_SET_TAG(eth_l3_ipv6_dst, tag, dst_ip_31_0, spec, dst_ip_31_0); + + return 0; +} + +void dr_ste_v1_build_eth_l3_ipv6_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l3_ipv6_dst_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(IPV6_DES, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l3_ipv6_dst_tag; +} + +static int dr_ste_v1_build_eth_l3_ipv6_src_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_127_96, spec, src_ip_127_96); + DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_95_64, spec, src_ip_95_64); + DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_63_32, spec, src_ip_63_32); + DR_STE_SET_TAG(eth_l3_ipv6_src, tag, src_ip_31_0, spec, src_ip_31_0); + + return 0; +} + +void dr_ste_v1_build_eth_l3_ipv6_src_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l3_ipv6_src_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(IPV6_SRC, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l3_ipv6_src_tag; +} + +static int dr_ste_v1_build_eth_l3_ipv4_5_tuple_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, destination_address, spec, dst_ip_31_0); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, source_address, spec, src_ip_31_0); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, destination_port, spec, tcp_dport); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, destination_port, spec, udp_dport); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, source_port, spec, tcp_sport); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, source_port, spec, udp_sport); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, protocol, spec, ip_protocol); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, fragmented, spec, frag); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, dscp, spec, ip_dscp); + DR_STE_SET_TAG(eth_l3_ipv4_5_tuple_v1, tag, ecn, spec, ip_ecn); + + if (spec->tcp_flags) { + DR_STE_SET_TCP_FLAGS(eth_l3_ipv4_5_tuple_v1, tag, spec); + spec->tcp_flags = 0; + } + + return 0; +} + +void dr_ste_v1_build_eth_l3_ipv4_5_tuple_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l3_ipv4_5_tuple_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL3_IPV4_5_TUPLE, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l3_ipv4_5_tuple_tag; +} + +static void dr_ste_v1_build_eth_l2_src_or_dst_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc_mask = &value->misc; + + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, first_vlan_id, mask, first_vid); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, first_cfi, mask, first_cfi); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, first_priority, mask, first_prio); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, ip_fragmented, mask, frag); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, l3_ethertype, mask, ethertype); + DR_STE_SET_ONES(eth_l2_src_v1, bit_mask, l3_type, mask, ip_version); + + if (mask->svlan_tag || mask->cvlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, bit_mask, first_vlan_qualifier, -1); + mask->cvlan_tag = 0; + mask->svlan_tag = 0; + } + + if (inner) { + if (misc_mask->inner_second_cvlan_tag || + misc_mask->inner_second_svlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, bit_mask, second_vlan_qualifier, -1); + misc_mask->inner_second_cvlan_tag = 0; + misc_mask->inner_second_svlan_tag = 0; + } + + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, + second_vlan_id, misc_mask, inner_second_vid); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, + second_cfi, misc_mask, inner_second_cfi); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, + second_priority, misc_mask, inner_second_prio); + } else { + if (misc_mask->outer_second_cvlan_tag || + misc_mask->outer_second_svlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, bit_mask, second_vlan_qualifier, -1); + misc_mask->outer_second_cvlan_tag = 0; + misc_mask->outer_second_svlan_tag = 0; + } + + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, + second_vlan_id, misc_mask, outer_second_vid); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, + second_cfi, misc_mask, outer_second_cfi); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, + second_priority, misc_mask, outer_second_prio); + } +} + +static int dr_ste_v1_build_eth_l2_src_or_dst_tag(struct mlx5dr_match_param *value, + bool inner, u8 *tag) +{ + struct mlx5dr_match_spec *spec = inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc_spec = &value->misc; + + DR_STE_SET_TAG(eth_l2_src_v1, tag, first_vlan_id, spec, first_vid); + DR_STE_SET_TAG(eth_l2_src_v1, tag, first_cfi, spec, first_cfi); + DR_STE_SET_TAG(eth_l2_src_v1, tag, first_priority, spec, first_prio); + DR_STE_SET_TAG(eth_l2_src_v1, tag, ip_fragmented, spec, frag); + DR_STE_SET_TAG(eth_l2_src_v1, tag, l3_ethertype, spec, ethertype); + + if (spec->ip_version == IP_VERSION_IPV4) { + MLX5_SET(ste_eth_l2_src_v1, tag, l3_type, STE_IPV4); + spec->ip_version = 0; + } else if (spec->ip_version == IP_VERSION_IPV6) { + MLX5_SET(ste_eth_l2_src_v1, tag, l3_type, STE_IPV6); + spec->ip_version = 0; + } else if (spec->ip_version) { + return -EINVAL; + } + + if (spec->cvlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, tag, first_vlan_qualifier, DR_STE_CVLAN); + spec->cvlan_tag = 0; + } else if (spec->svlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, tag, first_vlan_qualifier, DR_STE_SVLAN); + spec->svlan_tag = 0; + } + + if (inner) { + if (misc_spec->inner_second_cvlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, tag, second_vlan_qualifier, DR_STE_CVLAN); + misc_spec->inner_second_cvlan_tag = 0; + } else if (misc_spec->inner_second_svlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, tag, second_vlan_qualifier, DR_STE_SVLAN); + misc_spec->inner_second_svlan_tag = 0; + } + + DR_STE_SET_TAG(eth_l2_src_v1, tag, second_vlan_id, misc_spec, inner_second_vid); + DR_STE_SET_TAG(eth_l2_src_v1, tag, second_cfi, misc_spec, inner_second_cfi); + DR_STE_SET_TAG(eth_l2_src_v1, tag, second_priority, misc_spec, inner_second_prio); + } else { + if (misc_spec->outer_second_cvlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, tag, second_vlan_qualifier, DR_STE_CVLAN); + misc_spec->outer_second_cvlan_tag = 0; + } else if (misc_spec->outer_second_svlan_tag) { + MLX5_SET(ste_eth_l2_src_v1, tag, second_vlan_qualifier, DR_STE_SVLAN); + misc_spec->outer_second_svlan_tag = 0; + } + DR_STE_SET_TAG(eth_l2_src_v1, tag, second_vlan_id, misc_spec, outer_second_vid); + DR_STE_SET_TAG(eth_l2_src_v1, tag, second_cfi, misc_spec, outer_second_cfi); + DR_STE_SET_TAG(eth_l2_src_v1, tag, second_priority, misc_spec, outer_second_prio); + } + + return 0; +} + +static void dr_ste_v1_build_eth_l2_src_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, smac_47_16, mask, smac_47_16); + DR_STE_SET_TAG(eth_l2_src_v1, bit_mask, smac_15_0, mask, smac_15_0); + + dr_ste_v1_build_eth_l2_src_or_dst_bit_mask(value, inner, bit_mask); +} + +static int dr_ste_v1_build_eth_l2_src_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_src_v1, tag, smac_47_16, spec, smac_47_16); + DR_STE_SET_TAG(eth_l2_src_v1, tag, smac_15_0, spec, smac_15_0); + + return dr_ste_v1_build_eth_l2_src_or_dst_tag(value, sb->inner, tag); +} + +void dr_ste_v1_build_eth_l2_src_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l2_src_bit_mask(mask, sb->inner, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL2_SRC, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l2_src_tag; +} + +static void dr_ste_v1_build_eth_l2_dst_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_dst_v1, bit_mask, dmac_47_16, mask, dmac_47_16); + DR_STE_SET_TAG(eth_l2_dst_v1, bit_mask, dmac_15_0, mask, dmac_15_0); + + dr_ste_v1_build_eth_l2_src_or_dst_bit_mask(value, inner, bit_mask); +} + +static int dr_ste_v1_build_eth_l2_dst_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l2_dst_v1, tag, dmac_47_16, spec, dmac_47_16); + DR_STE_SET_TAG(eth_l2_dst_v1, tag, dmac_15_0, spec, dmac_15_0); + + return dr_ste_v1_build_eth_l2_src_or_dst_tag(value, sb->inner, tag); +} + +void dr_ste_v1_build_eth_l2_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l2_dst_bit_mask(mask, sb->inner, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL2, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l2_dst_tag; +} + +static void dr_ste_v1_build_eth_l2_tnl_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) +{ + struct mlx5dr_match_spec *mask = inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, dmac_47_16, mask, dmac_47_16); + DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, dmac_15_0, mask, dmac_15_0); + DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, first_vlan_id, mask, first_vid); + DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, first_cfi, mask, first_cfi); + DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, first_priority, mask, first_prio); + DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, ip_fragmented, mask, frag); + DR_STE_SET_TAG(eth_l2_tnl_v1, bit_mask, l3_ethertype, mask, ethertype); + DR_STE_SET_ONES(eth_l2_tnl_v1, bit_mask, l3_type, mask, ip_version); + + if (misc->vxlan_vni) { + MLX5_SET(ste_eth_l2_tnl_v1, bit_mask, + l2_tunneling_network_id, (misc->vxlan_vni << 8)); + misc->vxlan_vni = 0; + } + + if (mask->svlan_tag || mask->cvlan_tag) { + MLX5_SET(ste_eth_l2_tnl_v1, bit_mask, first_vlan_qualifier, -1); + mask->cvlan_tag = 0; + mask->svlan_tag = 0; + } +} + +static int dr_ste_v1_build_eth_l2_tnl_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(eth_l2_tnl_v1, tag, dmac_47_16, spec, dmac_47_16); + DR_STE_SET_TAG(eth_l2_tnl_v1, tag, dmac_15_0, spec, dmac_15_0); + DR_STE_SET_TAG(eth_l2_tnl_v1, tag, first_vlan_id, spec, first_vid); + DR_STE_SET_TAG(eth_l2_tnl_v1, tag, first_cfi, spec, first_cfi); + DR_STE_SET_TAG(eth_l2_tnl_v1, tag, ip_fragmented, spec, frag); + DR_STE_SET_TAG(eth_l2_tnl_v1, tag, first_priority, spec, first_prio); + DR_STE_SET_TAG(eth_l2_tnl_v1, tag, l3_ethertype, spec, ethertype); + + if (misc->vxlan_vni) { + MLX5_SET(ste_eth_l2_tnl_v1, tag, l2_tunneling_network_id, + (misc->vxlan_vni << 8)); + misc->vxlan_vni = 0; + } + + if (spec->cvlan_tag) { + MLX5_SET(ste_eth_l2_tnl_v1, tag, first_vlan_qualifier, DR_STE_CVLAN); + spec->cvlan_tag = 0; + } else if (spec->svlan_tag) { + MLX5_SET(ste_eth_l2_tnl_v1, tag, first_vlan_qualifier, DR_STE_SVLAN); + spec->svlan_tag = 0; + } + + if (spec->ip_version == IP_VERSION_IPV4) { + MLX5_SET(ste_eth_l2_tnl_v1, tag, l3_type, STE_IPV4); + spec->ip_version = 0; + } else if (spec->ip_version == IP_VERSION_IPV6) { + MLX5_SET(ste_eth_l2_tnl_v1, tag, l3_type, STE_IPV6); + spec->ip_version = 0; + } else if (spec->ip_version) { + return -EINVAL; + } + + return 0; +} + +void dr_ste_v1_build_eth_l2_tnl_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l2_tnl_bit_mask(mask, sb->inner, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_ETHL2_TNL; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l2_tnl_tag; +} + +static int dr_ste_v1_build_eth_l3_ipv4_misc_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + + DR_STE_SET_TAG(eth_l3_ipv4_misc_v1, tag, time_to_live, spec, ttl_hoplimit); + DR_STE_SET_TAG(eth_l3_ipv4_misc_v1, tag, ihl, spec, ipv4_ihl); + + return 0; +} + +void dr_ste_v1_build_eth_l3_ipv4_misc_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l3_ipv4_misc_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL3_IPV4_MISC, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l3_ipv4_misc_tag; +} + +static int dr_ste_v1_build_eth_ipv6_l3_l4_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_spec *spec = sb->inner ? &value->inner : &value->outer; + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(eth_l4_v1, tag, dst_port, spec, tcp_dport); + DR_STE_SET_TAG(eth_l4_v1, tag, src_port, spec, tcp_sport); + DR_STE_SET_TAG(eth_l4_v1, tag, dst_port, spec, udp_dport); + DR_STE_SET_TAG(eth_l4_v1, tag, src_port, spec, udp_sport); + DR_STE_SET_TAG(eth_l4_v1, tag, protocol, spec, ip_protocol); + DR_STE_SET_TAG(eth_l4_v1, tag, fragmented, spec, frag); + DR_STE_SET_TAG(eth_l4_v1, tag, dscp, spec, ip_dscp); + DR_STE_SET_TAG(eth_l4_v1, tag, ecn, spec, ip_ecn); + DR_STE_SET_TAG(eth_l4_v1, tag, ipv6_hop_limit, spec, ttl_hoplimit); + + if (sb->inner) + DR_STE_SET_TAG(eth_l4_v1, tag, flow_label, misc, inner_ipv6_flow_label); + else + DR_STE_SET_TAG(eth_l4_v1, tag, flow_label, misc, outer_ipv6_flow_label); + + if (spec->tcp_flags) { + DR_STE_SET_TCP_FLAGS(eth_l4_v1, tag, spec); + spec->tcp_flags = 0; + } + + return 0; +} + +void dr_ste_v1_build_eth_ipv6_l3_l4_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_ipv6_l3_l4_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(ETHL4, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_ipv6_l3_l4_tag; +} + +static int dr_ste_v1_build_mpls_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + + if (sb->inner) + DR_STE_SET_MPLS(mpls_v1, misc2, inner, tag); + else + DR_STE_SET_MPLS(mpls_v1, misc2, outer, tag); + + return 0; +} + +void dr_ste_v1_build_mpls_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_mpls_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_CALC_DFNR_TYPE(MPLS, sb->inner); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_mpls_tag; +} + +static int dr_ste_v1_build_tnl_gre_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(gre_v1, tag, gre_protocol, misc, gre_protocol); + DR_STE_SET_TAG(gre_v1, tag, gre_k_present, misc, gre_k_present); + DR_STE_SET_TAG(gre_v1, tag, gre_key_h, misc, gre_key_h); + DR_STE_SET_TAG(gre_v1, tag, gre_key_l, misc, gre_key_l); + + DR_STE_SET_TAG(gre_v1, tag, gre_c_present, misc, gre_c_present); + DR_STE_SET_TAG(gre_v1, tag, gre_s_present, misc, gre_s_present); + + return 0; +} + +void dr_ste_v1_build_tnl_gre_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_tnl_gre_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_GRE; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_tnl_gre_tag; +} + +static int dr_ste_v1_build_tnl_mpls_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + + if (DR_STE_IS_OUTER_MPLS_OVER_GRE_SET(misc2)) { + DR_STE_SET_TAG(mpls_v1, tag, mpls0_label, + misc2, outer_first_mpls_over_gre_label); + + DR_STE_SET_TAG(mpls_v1, tag, mpls0_exp, + misc2, outer_first_mpls_over_gre_exp); + + DR_STE_SET_TAG(mpls_v1, tag, mpls0_s_bos, + misc2, outer_first_mpls_over_gre_s_bos); + + DR_STE_SET_TAG(mpls_v1, tag, mpls0_ttl, + misc2, outer_first_mpls_over_gre_ttl); + } else { + DR_STE_SET_TAG(mpls_v1, tag, mpls0_label, + misc2, outer_first_mpls_over_udp_label); + + DR_STE_SET_TAG(mpls_v1, tag, mpls0_exp, + misc2, outer_first_mpls_over_udp_exp); + + DR_STE_SET_TAG(mpls_v1, tag, mpls0_s_bos, + misc2, outer_first_mpls_over_udp_s_bos); + + DR_STE_SET_TAG(mpls_v1, tag, mpls0_ttl, + misc2, outer_first_mpls_over_udp_ttl); + } + + return 0; +} + +void dr_ste_v1_build_tnl_mpls_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_tnl_mpls_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_MPLS_I; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_tnl_mpls_tag; +} + +static int dr_ste_v1_build_tnl_mpls_over_udp_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + u8 *parser_ptr; + u8 parser_id; + u32 mpls_hdr; + + mpls_hdr = misc2->outer_first_mpls_over_udp_label << HDR_MPLS_OFFSET_LABEL; + misc2->outer_first_mpls_over_udp_label = 0; + mpls_hdr |= misc2->outer_first_mpls_over_udp_exp << HDR_MPLS_OFFSET_EXP; + misc2->outer_first_mpls_over_udp_exp = 0; + mpls_hdr |= misc2->outer_first_mpls_over_udp_s_bos << HDR_MPLS_OFFSET_S_BOS; + misc2->outer_first_mpls_over_udp_s_bos = 0; + mpls_hdr |= misc2->outer_first_mpls_over_udp_ttl << HDR_MPLS_OFFSET_TTL; + misc2->outer_first_mpls_over_udp_ttl = 0; + + parser_id = sb->caps->flex_parser_id_mpls_over_udp; + parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); + *(__be32 *)parser_ptr = cpu_to_be32(mpls_hdr); + + return 0; +} + +void dr_ste_v1_build_tnl_mpls_over_udp_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_tnl_mpls_over_udp_tag(mask, sb, sb->bit_mask); + + /* STEs with lookup type FLEX_PARSER_{0/1} includes + * flex parsers_{0-3}/{4-7} respectively. + */ + sb->lu_type = sb->caps->flex_parser_id_mpls_over_udp > DR_STE_MAX_FLEX_0_ID ? + DR_STE_V1_LU_TYPE_FLEX_PARSER_1 : + DR_STE_V1_LU_TYPE_FLEX_PARSER_0; + + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_tnl_mpls_over_udp_tag; +} + +static int dr_ste_v1_build_tnl_mpls_over_gre_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + u8 *parser_ptr; + u8 parser_id; + u32 mpls_hdr; + + mpls_hdr = misc2->outer_first_mpls_over_gre_label << HDR_MPLS_OFFSET_LABEL; + misc2->outer_first_mpls_over_gre_label = 0; + mpls_hdr |= misc2->outer_first_mpls_over_gre_exp << HDR_MPLS_OFFSET_EXP; + misc2->outer_first_mpls_over_gre_exp = 0; + mpls_hdr |= misc2->outer_first_mpls_over_gre_s_bos << HDR_MPLS_OFFSET_S_BOS; + misc2->outer_first_mpls_over_gre_s_bos = 0; + mpls_hdr |= misc2->outer_first_mpls_over_gre_ttl << HDR_MPLS_OFFSET_TTL; + misc2->outer_first_mpls_over_gre_ttl = 0; + + parser_id = sb->caps->flex_parser_id_mpls_over_gre; + parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); + *(__be32 *)parser_ptr = cpu_to_be32(mpls_hdr); + + return 0; +} + +void dr_ste_v1_build_tnl_mpls_over_gre_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_tnl_mpls_over_gre_tag(mask, sb, sb->bit_mask); + + /* STEs with lookup type FLEX_PARSER_{0/1} includes + * flex parsers_{0-3}/{4-7} respectively. + */ + sb->lu_type = sb->caps->flex_parser_id_mpls_over_gre > DR_STE_MAX_FLEX_0_ID ? + DR_STE_V1_LU_TYPE_FLEX_PARSER_1 : + DR_STE_V1_LU_TYPE_FLEX_PARSER_0; + + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_tnl_mpls_over_gre_tag; +} + +static int dr_ste_v1_build_icmp_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + bool is_ipv4 = DR_MASK_IS_ICMPV4_SET(misc3); + u32 *icmp_header_data; + u8 *icmp_type; + u8 *icmp_code; + + if (is_ipv4) { + icmp_header_data = &misc3->icmpv4_header_data; + icmp_type = &misc3->icmpv4_type; + icmp_code = &misc3->icmpv4_code; + } else { + icmp_header_data = &misc3->icmpv6_header_data; + icmp_type = &misc3->icmpv6_type; + icmp_code = &misc3->icmpv6_code; + } + + MLX5_SET(ste_icmp_v1, tag, icmp_header_data, *icmp_header_data); + MLX5_SET(ste_icmp_v1, tag, icmp_type, *icmp_type); + MLX5_SET(ste_icmp_v1, tag, icmp_code, *icmp_code); + + *icmp_header_data = 0; + *icmp_type = 0; + *icmp_code = 0; + + return 0; +} + +void dr_ste_v1_build_icmp_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_icmp_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_ETHL4_MISC_O; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_icmp_tag; +} + +static int dr_ste_v1_build_general_purpose_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + + DR_STE_SET_TAG(general_purpose, tag, general_purpose_lookup_field, + misc2, metadata_reg_a); + + return 0; +} + +void dr_ste_v1_build_general_purpose_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_general_purpose_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_GENERAL_PURPOSE; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_general_purpose_tag; +} + +static int dr_ste_v1_build_eth_l4_misc_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + + if (sb->inner) { + DR_STE_SET_TAG(eth_l4_misc_v1, tag, seq_num, misc3, inner_tcp_seq_num); + DR_STE_SET_TAG(eth_l4_misc_v1, tag, ack_num, misc3, inner_tcp_ack_num); + } else { + DR_STE_SET_TAG(eth_l4_misc_v1, tag, seq_num, misc3, outer_tcp_seq_num); + DR_STE_SET_TAG(eth_l4_misc_v1, tag, ack_num, misc3, outer_tcp_ack_num); + } + + return 0; +} + +void dr_ste_v1_build_eth_l4_misc_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_eth_l4_misc_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_ETHL4_MISC_O; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_eth_l4_misc_tag; +} + +static int +dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_flags, misc3, + outer_vxlan_gpe_flags); + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_next_protocol, misc3, + outer_vxlan_gpe_next_protocol); + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_vni, misc3, + outer_vxlan_gpe_vni); + + return 0; +} + +void dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_tag; +} + +static int +dr_ste_v1_build_flex_parser_tnl_geneve_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc *misc = &value->misc; + + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_protocol_type, misc, geneve_protocol_type); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_oam, misc, geneve_oam); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_opt_len, misc, geneve_opt_len); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_vni, misc, geneve_vni); + + return 0; +} + +void dr_ste_v1_build_flex_parser_tnl_geneve_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_flex_parser_tnl_geneve_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_geneve_tag; +} + +static int dr_ste_v1_build_tnl_header_0_1_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc5 *misc5 = &value->misc5; + + DR_STE_SET_TAG(tunnel_header, tag, tunnel_header_0, misc5, tunnel_header_0); + DR_STE_SET_TAG(tunnel_header, tag, tunnel_header_1, misc5, tunnel_header_1); + + return 0; +} + +void dr_ste_v1_build_tnl_header_0_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER; + dr_ste_v1_build_tnl_header_0_1_tag(mask, sb, sb->bit_mask); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_tnl_header_0_1_tag; +} + +static int dr_ste_v1_build_register_0_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + + DR_STE_SET_TAG(register_0, tag, register_0_h, misc2, metadata_reg_c_0); + DR_STE_SET_TAG(register_0, tag, register_0_l, misc2, metadata_reg_c_1); + DR_STE_SET_TAG(register_0, tag, register_1_h, misc2, metadata_reg_c_2); + DR_STE_SET_TAG(register_0, tag, register_1_l, misc2, metadata_reg_c_3); + + return 0; +} + +void dr_ste_v1_build_register_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_register_0_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_STEERING_REGISTERS_0; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_register_0_tag; +} + +static int dr_ste_v1_build_register_1_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc2 *misc2 = &value->misc2; + + DR_STE_SET_TAG(register_1, tag, register_2_h, misc2, metadata_reg_c_4); + DR_STE_SET_TAG(register_1, tag, register_2_l, misc2, metadata_reg_c_5); + DR_STE_SET_TAG(register_1, tag, register_3_h, misc2, metadata_reg_c_6); + DR_STE_SET_TAG(register_1, tag, register_3_l, misc2, metadata_reg_c_7); + + return 0; +} + +void dr_ste_v1_build_register_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_register_1_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_STEERING_REGISTERS_1; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_register_1_tag; +} + +static void dr_ste_v1_build_src_gvmi_qpn_bit_mask(struct mlx5dr_match_param *value, + u8 *bit_mask) +{ + struct mlx5dr_match_misc *misc_mask = &value->misc; + + DR_STE_SET_ONES(src_gvmi_qp_v1, bit_mask, source_gvmi, misc_mask, source_port); + DR_STE_SET_ONES(src_gvmi_qp_v1, bit_mask, source_qp, misc_mask, source_sqn); + misc_mask->source_eswitch_owner_vhca_id = 0; +} + +static int dr_ste_v1_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc *misc = &value->misc; + int id = misc->source_eswitch_owner_vhca_id; + struct mlx5dr_cmd_vport_cap *vport_cap; + struct mlx5dr_domain *dmn = sb->dmn; + struct mlx5dr_domain *vport_dmn; + u8 *bit_mask = sb->bit_mask; + struct mlx5dr_domain *peer; + + DR_STE_SET_TAG(src_gvmi_qp_v1, tag, source_qp, misc, source_sqn); + + if (sb->vhca_id_valid) { + peer = xa_load(&dmn->peer_dmn_xa, id); + /* Find port GVMI based on the eswitch_owner_vhca_id */ + if (id == dmn->info.caps.gvmi) + vport_dmn = dmn; + else if (peer && (id == peer->info.caps.gvmi)) + vport_dmn = peer; + else + return -EINVAL; + + misc->source_eswitch_owner_vhca_id = 0; + } else { + vport_dmn = dmn; + } + + if (!MLX5_GET(ste_src_gvmi_qp_v1, bit_mask, source_gvmi)) + return 0; + + vport_cap = mlx5dr_domain_get_vport_cap(vport_dmn, misc->source_port); + if (!vport_cap) { + mlx5dr_err(dmn, "Vport 0x%x is disabled or invalid\n", + misc->source_port); + return -EINVAL; + } + + if (vport_cap->vport_gvmi) + MLX5_SET(ste_src_gvmi_qp_v1, tag, source_gvmi, vport_cap->vport_gvmi); + + misc->source_port = 0; + return 0; +} + +void dr_ste_v1_build_src_gvmi_qpn_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_src_gvmi_qpn_bit_mask(mask, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_SRC_QP_GVMI; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_src_gvmi_qpn_tag; +} + +static void dr_ste_v1_set_flex_parser(u32 *misc4_field_id, + u32 *misc4_field_value, + bool *parser_is_used, + u8 *tag) +{ + u32 id = *misc4_field_id; + u8 *parser_ptr; + + if (id >= DR_NUM_OF_FLEX_PARSERS || parser_is_used[id]) + return; + + parser_is_used[id] = true; + parser_ptr = dr_ste_calc_flex_parser_offset(tag, id); + + *(__be32 *)parser_ptr = cpu_to_be32(*misc4_field_value); + *misc4_field_id = 0; + *misc4_field_value = 0; +} + +static int dr_ste_v1_build_felx_parser_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc4 *misc_4_mask = &value->misc4; + bool parser_is_used[DR_NUM_OF_FLEX_PARSERS] = {}; + + dr_ste_v1_set_flex_parser(&misc_4_mask->prog_sample_field_id_0, + &misc_4_mask->prog_sample_field_value_0, + parser_is_used, tag); + + dr_ste_v1_set_flex_parser(&misc_4_mask->prog_sample_field_id_1, + &misc_4_mask->prog_sample_field_value_1, + parser_is_used, tag); + + dr_ste_v1_set_flex_parser(&misc_4_mask->prog_sample_field_id_2, + &misc_4_mask->prog_sample_field_value_2, + parser_is_used, tag); + + dr_ste_v1_set_flex_parser(&misc_4_mask->prog_sample_field_id_3, + &misc_4_mask->prog_sample_field_value_3, + parser_is_used, tag); + + return 0; +} + +void dr_ste_v1_build_flex_parser_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_0; + dr_ste_v1_build_felx_parser_tag(mask, sb, sb->bit_mask); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_felx_parser_tag; +} + +void dr_ste_v1_build_flex_parser_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_1; + dr_ste_v1_build_felx_parser_tag(mask, sb, sb->bit_mask); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_felx_parser_tag; +} + +static int +dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + u8 parser_id = sb->caps->flex_parser_id_geneve_tlv_option_0; + u8 *parser_ptr = dr_ste_calc_flex_parser_offset(tag, parser_id); + + MLX5_SET(ste_flex_parser_0, parser_ptr, flex_parser_3, + misc3->geneve_tlv_option_0_data); + misc3->geneve_tlv_option_0_data = 0; + + return 0; +} + +void +dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_tag(mask, sb, sb->bit_mask); + + /* STEs with lookup type FLEX_PARSER_{0/1} includes + * flex parsers_{0-3}/{4-7} respectively. + */ + sb->lu_type = sb->caps->flex_parser_id_geneve_tlv_option_0 > 3 ? + DR_STE_V1_LU_TYPE_FLEX_PARSER_1 : + DR_STE_V1_LU_TYPE_FLEX_PARSER_0; + + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_tag; +} + +static int +dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + u8 parser_id = sb->caps->flex_parser_id_geneve_tlv_option_0; + struct mlx5dr_match_misc *misc = &value->misc; + + if (misc->geneve_tlv_option_0_exist) { + MLX5_SET(ste_flex_parser_ok, tag, flex_parsers_ok, 1 << parser_id); + misc->geneve_tlv_option_0_exist = 0; + } + + return 0; +} + +void +dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_OK; + dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_tag(mask, sb, sb->bit_mask); + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_tag; +} + +static int dr_ste_v1_build_flex_parser_tnl_gtpu_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + struct mlx5dr_match_misc3 *misc3 = &value->misc3; + + DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, gtpu_msg_flags, misc3, gtpu_msg_flags); + DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, gtpu_msg_type, misc3, gtpu_msg_type); + DR_STE_SET_TAG(flex_parser_tnl_gtpu, tag, gtpu_teid, misc3, gtpu_teid); + + return 0; +} + +void dr_ste_v1_build_flex_parser_tnl_gtpu_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_flex_parser_tnl_gtpu_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_TNL_HEADER; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_flex_parser_tnl_gtpu_tag; +} + +static int +dr_ste_v1_build_tnl_gtpu_flex_parser_0_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_dw_0)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_0, sb->caps, &value->misc3); + if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_teid)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_teid, sb->caps, &value->misc3); + if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_dw_2)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_2, sb->caps, &value->misc3); + if (dr_is_flex_parser_0_id(sb->caps->flex_parser_id_gtpu_first_ext_dw_0)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_first_ext_dw_0, sb->caps, &value->misc3); + return 0; +} + +void +dr_ste_v1_build_tnl_gtpu_flex_parser_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_tnl_gtpu_flex_parser_0_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_0; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_tnl_gtpu_flex_parser_0_tag; +} + +static int +dr_ste_v1_build_tnl_gtpu_flex_parser_1_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *tag) +{ + if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_dw_0)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_0, sb->caps, &value->misc3); + if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_teid)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_teid, sb->caps, &value->misc3); + if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_dw_2)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_dw_2, sb->caps, &value->misc3); + if (dr_is_flex_parser_1_id(sb->caps->flex_parser_id_gtpu_first_ext_dw_0)) + DR_STE_SET_FLEX_PARSER_FIELD(tag, gtpu_first_ext_dw_0, sb->caps, &value->misc3); + return 0; +} + +void +dr_ste_v1_build_tnl_gtpu_flex_parser_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask) +{ + dr_ste_v1_build_tnl_gtpu_flex_parser_1_tag(mask, sb, sb->bit_mask); + + sb->lu_type = DR_STE_V1_LU_TYPE_FLEX_PARSER_1; + sb->byte_mask = mlx5dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_v1_build_tnl_gtpu_flex_parser_1_tag; +} + +int dr_ste_v1_alloc_modify_hdr_ptrn_arg(struct mlx5dr_action *action) +{ + struct mlx5dr_ptrn_mgr *ptrn_mgr; + int ret; + + ptrn_mgr = action->rewrite->dmn->ptrn_mgr; + if (!ptrn_mgr) + return -EOPNOTSUPP; + + action->rewrite->arg = mlx5dr_arg_get_obj(action->rewrite->dmn->arg_mgr, + action->rewrite->num_of_actions, + action->rewrite->data); + if (!action->rewrite->arg) { + mlx5dr_err(action->rewrite->dmn, "Failed allocating args for modify header\n"); + return -EAGAIN; + } + + action->rewrite->ptrn = + mlx5dr_ptrn_cache_get_pattern(ptrn_mgr, + action->rewrite->num_of_actions, + action->rewrite->data); + if (!action->rewrite->ptrn) { + mlx5dr_err(action->rewrite->dmn, "Failed to get pattern\n"); + ret = -EAGAIN; + goto put_arg; + } + + return 0; + +put_arg: + mlx5dr_arg_put_obj(action->rewrite->dmn->arg_mgr, + action->rewrite->arg); + return ret; +} + +void dr_ste_v1_free_modify_hdr_ptrn_arg(struct mlx5dr_action *action) +{ + mlx5dr_ptrn_cache_put_pattern(action->rewrite->dmn->ptrn_mgr, + action->rewrite->ptrn); + mlx5dr_arg_put_obj(action->rewrite->dmn->arg_mgr, + action->rewrite->arg); +} + +static struct mlx5dr_ste_ctx ste_ctx_v1 = { + /* Builders */ + .build_eth_l2_src_dst_init = &dr_ste_v1_build_eth_l2_src_dst_init, + .build_eth_l3_ipv6_src_init = &dr_ste_v1_build_eth_l3_ipv6_src_init, + .build_eth_l3_ipv6_dst_init = &dr_ste_v1_build_eth_l3_ipv6_dst_init, + .build_eth_l3_ipv4_5_tuple_init = &dr_ste_v1_build_eth_l3_ipv4_5_tuple_init, + .build_eth_l2_src_init = &dr_ste_v1_build_eth_l2_src_init, + .build_eth_l2_dst_init = &dr_ste_v1_build_eth_l2_dst_init, + .build_eth_l2_tnl_init = &dr_ste_v1_build_eth_l2_tnl_init, + .build_eth_l3_ipv4_misc_init = &dr_ste_v1_build_eth_l3_ipv4_misc_init, + .build_eth_ipv6_l3_l4_init = &dr_ste_v1_build_eth_ipv6_l3_l4_init, + .build_mpls_init = &dr_ste_v1_build_mpls_init, + .build_tnl_gre_init = &dr_ste_v1_build_tnl_gre_init, + .build_tnl_mpls_init = &dr_ste_v1_build_tnl_mpls_init, + .build_tnl_mpls_over_udp_init = &dr_ste_v1_build_tnl_mpls_over_udp_init, + .build_tnl_mpls_over_gre_init = &dr_ste_v1_build_tnl_mpls_over_gre_init, + .build_icmp_init = &dr_ste_v1_build_icmp_init, + .build_general_purpose_init = &dr_ste_v1_build_general_purpose_init, + .build_eth_l4_misc_init = &dr_ste_v1_build_eth_l4_misc_init, + .build_tnl_vxlan_gpe_init = &dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_init, + .build_tnl_geneve_init = &dr_ste_v1_build_flex_parser_tnl_geneve_init, + .build_tnl_geneve_tlv_opt_init = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_init, + .build_tnl_geneve_tlv_opt_exist_init = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_init, + .build_register_0_init = &dr_ste_v1_build_register_0_init, + .build_register_1_init = &dr_ste_v1_build_register_1_init, + .build_src_gvmi_qpn_init = &dr_ste_v1_build_src_gvmi_qpn_init, + .build_flex_parser_0_init = &dr_ste_v1_build_flex_parser_0_init, + .build_flex_parser_1_init = &dr_ste_v1_build_flex_parser_1_init, + .build_tnl_gtpu_init = &dr_ste_v1_build_flex_parser_tnl_gtpu_init, + .build_tnl_header_0_1_init = &dr_ste_v1_build_tnl_header_0_1_init, + .build_tnl_gtpu_flex_parser_0_init = &dr_ste_v1_build_tnl_gtpu_flex_parser_0_init, + .build_tnl_gtpu_flex_parser_1_init = &dr_ste_v1_build_tnl_gtpu_flex_parser_1_init, + + /* Getters and Setters */ + .ste_init = &dr_ste_v1_init, + .set_next_lu_type = &dr_ste_v1_set_next_lu_type, + .get_next_lu_type = &dr_ste_v1_get_next_lu_type, + .is_miss_addr_set = &dr_ste_v1_is_miss_addr_set, + .set_miss_addr = &dr_ste_v1_set_miss_addr, + .get_miss_addr = &dr_ste_v1_get_miss_addr, + .set_hit_addr = &dr_ste_v1_set_hit_addr, + .set_byte_mask = &dr_ste_v1_set_byte_mask, + .get_byte_mask = &dr_ste_v1_get_byte_mask, + /* Actions */ + .actions_caps = DR_STE_CTX_ACTION_CAP_TX_POP | + DR_STE_CTX_ACTION_CAP_RX_PUSH | + DR_STE_CTX_ACTION_CAP_RX_ENCAP | + DR_STE_CTX_ACTION_CAP_POP_MDFY, + .set_actions_rx = &dr_ste_v1_set_actions_rx, + .set_actions_tx = &dr_ste_v1_set_actions_tx, + .modify_field_arr_sz = ARRAY_SIZE(dr_ste_v1_action_modify_field_arr), + .modify_field_arr = dr_ste_v1_action_modify_field_arr, + .set_action_set = &dr_ste_v1_set_action_set, + .set_action_add = &dr_ste_v1_set_action_add, + .set_action_copy = &dr_ste_v1_set_action_copy, + .set_action_decap_l3_list = &dr_ste_v1_set_action_decap_l3_list, + .alloc_modify_hdr_chunk = &dr_ste_v1_alloc_modify_hdr_ptrn_arg, + .dealloc_modify_hdr_chunk = &dr_ste_v1_free_modify_hdr_ptrn_arg, + + /* Send */ + .prepare_for_postsend = &dr_ste_v1_prepare_for_postsend, +}; + +struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v1(void) +{ + return &ste_ctx_v1; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.h new file mode 100644 index 00000000000000..e2fc698670880c --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v1.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#ifndef _DR_STE_V1_ +#define _DR_STE_V1_ + +#include "dr_types.h" +#include "dr_ste.h" + +bool dr_ste_v1_is_miss_addr_set(u8 *hw_ste_p); +void dr_ste_v1_set_miss_addr(u8 *hw_ste_p, u64 miss_addr); +u64 dr_ste_v1_get_miss_addr(u8 *hw_ste_p); +void dr_ste_v1_set_byte_mask(u8 *hw_ste_p, u16 byte_mask); +u16 dr_ste_v1_get_byte_mask(u8 *hw_ste_p); +void dr_ste_v1_set_next_lu_type(u8 *hw_ste_p, u16 lu_type); +u16 dr_ste_v1_get_next_lu_type(u8 *hw_ste_p); +void dr_ste_v1_set_hit_addr(u8 *hw_ste_p, u64 icm_addr, u32 ht_size); +void dr_ste_v1_init(u8 *hw_ste_p, u16 lu_type, bool is_rx, u16 gvmi); +void dr_ste_v1_prepare_for_postsend(u8 *hw_ste_p, u32 ste_size); +void dr_ste_v1_set_actions_tx(struct mlx5dr_domain *dmn, u8 *action_type_set, + u32 actions_caps, u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, u32 *added_stes); +void dr_ste_v1_set_actions_rx(struct mlx5dr_domain *dmn, u8 *action_type_set, + u32 actions_caps, u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, u32 *added_stes); +void dr_ste_v1_set_action_set(u8 *d_action, u8 hw_field, u8 shifter, + u8 length, u32 data); +void dr_ste_v1_set_action_add(u8 *d_action, u8 hw_field, u8 shifter, + u8 length, u32 data); +void dr_ste_v1_set_action_copy(u8 *d_action, u8 dst_hw_field, u8 dst_shifter, + u8 dst_len, u8 src_hw_field, u8 src_shifter); +int dr_ste_v1_set_action_decap_l3_list(void *data, u32 data_sz, u8 *hw_action, + u32 hw_action_sz, u16 *used_hw_action_num); +int dr_ste_v1_alloc_modify_hdr_ptrn_arg(struct mlx5dr_action *action); +void dr_ste_v1_free_modify_hdr_ptrn_arg(struct mlx5dr_action *action); +void dr_ste_v1_build_eth_l2_src_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_l3_ipv6_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_l3_ipv6_src_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_l3_ipv4_5_tuple_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_l2_src_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_l2_dst_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_l2_tnl_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_l3_ipv4_misc_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_ipv6_l3_l4_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_mpls_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_tnl_gre_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_tnl_mpls_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_tnl_mpls_over_udp_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_tnl_mpls_over_gre_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_icmp_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_general_purpose_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_eth_l4_misc_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_flex_parser_tnl_geneve_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_tnl_header_0_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_register_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_register_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_src_gvmi_qpn_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_flex_parser_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_flex_parser_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_flex_parser_tnl_gtpu_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_tnl_gtpu_flex_parser_0_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); +void dr_ste_v1_build_tnl_gtpu_flex_parser_1_init(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask); + +#endif /* _DR_STE_V1_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v2.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v2.c new file mode 100644 index 00000000000000..808b013cf48cbd --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_ste_v2.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#include "dr_ste_v1.h" + +enum { + DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_0 = 0x00, + DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_1 = 0x01, + DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_2 = 0x02, + DR_STE_V2_ACTION_MDFY_FLD_SRC_L2_OUT_0 = 0x08, + DR_STE_V2_ACTION_MDFY_FLD_SRC_L2_OUT_1 = 0x09, + DR_STE_V2_ACTION_MDFY_FLD_L3_OUT_0 = 0x0e, + DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0 = 0x18, + DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_1 = 0x19, + DR_STE_V2_ACTION_MDFY_FLD_IPV4_OUT_0 = 0x40, + DR_STE_V2_ACTION_MDFY_FLD_IPV4_OUT_1 = 0x41, + DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_0 = 0x44, + DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_1 = 0x45, + DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_2 = 0x46, + DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_3 = 0x47, + DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_0 = 0x4c, + DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_1 = 0x4d, + DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_2 = 0x4e, + DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_3 = 0x4f, + DR_STE_V2_ACTION_MDFY_FLD_TCP_MISC_0 = 0x5e, + DR_STE_V2_ACTION_MDFY_FLD_TCP_MISC_1 = 0x5f, + DR_STE_V2_ACTION_MDFY_FLD_CFG_HDR_0_0 = 0x6f, + DR_STE_V2_ACTION_MDFY_FLD_CFG_HDR_0_1 = 0x70, + DR_STE_V2_ACTION_MDFY_FLD_METADATA_2_CQE = 0x7b, + DR_STE_V2_ACTION_MDFY_FLD_GNRL_PURPOSE = 0x7c, + DR_STE_V2_ACTION_MDFY_FLD_REGISTER_2_0 = 0x90, + DR_STE_V2_ACTION_MDFY_FLD_REGISTER_2_1 = 0x91, + DR_STE_V2_ACTION_MDFY_FLD_REGISTER_1_0 = 0x92, + DR_STE_V2_ACTION_MDFY_FLD_REGISTER_1_1 = 0x93, + DR_STE_V2_ACTION_MDFY_FLD_REGISTER_0_0 = 0x94, + DR_STE_V2_ACTION_MDFY_FLD_REGISTER_0_1 = 0x95, +}; + +static const struct mlx5dr_ste_action_modify_field dr_ste_v2_action_modify_field_arr[] = { + [MLX5_ACTION_IN_FIELD_OUT_SMAC_47_16] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_SRC_L2_OUT_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_SMAC_15_0] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_SRC_L2_OUT_1, .start = 16, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_ETHERTYPE] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_1, .start = 0, .end = 15, + }, + [MLX5_ACTION_IN_FIELD_OUT_DMAC_47_16] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_DMAC_15_0] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_1, .start = 16, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_IP_DSCP] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L3_OUT_0, .start = 18, .end = 23, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_FLAGS] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_1, .start = 16, .end = 24, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_SPORT] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0, .start = 16, .end = 31, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_DPORT] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0, .start = 0, .end = 15, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_TCP, + }, + [MLX5_ACTION_IN_FIELD_OUT_IP_TTL] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L3_OUT_0, .start = 8, .end = 15, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L3_OUT_0, .start = 8, .end = 15, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_UDP_SPORT] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0, .start = 16, .end = 31, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, + }, + [MLX5_ACTION_IN_FIELD_OUT_UDP_DPORT] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L4_OUT_0, .start = 0, .end = 15, + .l4_type = DR_STE_ACTION_MDFY_TYPE_L4_UDP, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_127_96] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_0, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_95_64] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_1, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_63_32] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_2, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV6_31_0] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_SRC_OUT_3, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_127_96] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_0, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_95_64] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_1, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_63_32] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_2, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV6_31_0] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV6_DST_OUT_3, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV6, + }, + [MLX5_ACTION_IN_FIELD_OUT_SIPV4] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV4_OUT_0, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_OUT_DIPV4] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_IPV4_OUT_1, .start = 0, .end = 31, + .l3_type = DR_STE_ACTION_MDFY_TYPE_L3_IPV4, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_A] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_GNRL_PURPOSE, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_B] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_METADATA_2_CQE, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_0] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_0_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_1] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_0_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_2] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_1_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_3] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_1_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_4] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_2_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_METADATA_REG_C_5] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_REGISTER_2_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_TCP_MISC_0, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_TCP_MISC_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_FIRST_VID] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_L2_OUT_2, .start = 0, .end = 15, + }, + [MLX5_ACTION_IN_FIELD_OUT_EMD_31_0] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_CFG_HDR_0_1, .start = 0, .end = 31, + }, + [MLX5_ACTION_IN_FIELD_OUT_EMD_47_32] = { + .hw_field = DR_STE_V2_ACTION_MDFY_FLD_CFG_HDR_0_0, .start = 0, .end = 15, + }, +}; + +static struct mlx5dr_ste_ctx ste_ctx_v2 = { + /* Builders */ + .build_eth_l2_src_dst_init = &dr_ste_v1_build_eth_l2_src_dst_init, + .build_eth_l3_ipv6_src_init = &dr_ste_v1_build_eth_l3_ipv6_src_init, + .build_eth_l3_ipv6_dst_init = &dr_ste_v1_build_eth_l3_ipv6_dst_init, + .build_eth_l3_ipv4_5_tuple_init = &dr_ste_v1_build_eth_l3_ipv4_5_tuple_init, + .build_eth_l2_src_init = &dr_ste_v1_build_eth_l2_src_init, + .build_eth_l2_dst_init = &dr_ste_v1_build_eth_l2_dst_init, + .build_eth_l2_tnl_init = &dr_ste_v1_build_eth_l2_tnl_init, + .build_eth_l3_ipv4_misc_init = &dr_ste_v1_build_eth_l3_ipv4_misc_init, + .build_eth_ipv6_l3_l4_init = &dr_ste_v1_build_eth_ipv6_l3_l4_init, + .build_mpls_init = &dr_ste_v1_build_mpls_init, + .build_tnl_gre_init = &dr_ste_v1_build_tnl_gre_init, + .build_tnl_mpls_init = &dr_ste_v1_build_tnl_mpls_init, + .build_tnl_mpls_over_udp_init = &dr_ste_v1_build_tnl_mpls_over_udp_init, + .build_tnl_mpls_over_gre_init = &dr_ste_v1_build_tnl_mpls_over_gre_init, + .build_icmp_init = &dr_ste_v1_build_icmp_init, + .build_general_purpose_init = &dr_ste_v1_build_general_purpose_init, + .build_eth_l4_misc_init = &dr_ste_v1_build_eth_l4_misc_init, + .build_tnl_vxlan_gpe_init = &dr_ste_v1_build_flex_parser_tnl_vxlan_gpe_init, + .build_tnl_geneve_init = &dr_ste_v1_build_flex_parser_tnl_geneve_init, + .build_tnl_geneve_tlv_opt_init = &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_init, + .build_tnl_geneve_tlv_opt_exist_init = + &dr_ste_v1_build_flex_parser_tnl_geneve_tlv_opt_exist_init, + .build_register_0_init = &dr_ste_v1_build_register_0_init, + .build_register_1_init = &dr_ste_v1_build_register_1_init, + .build_src_gvmi_qpn_init = &dr_ste_v1_build_src_gvmi_qpn_init, + .build_flex_parser_0_init = &dr_ste_v1_build_flex_parser_0_init, + .build_flex_parser_1_init = &dr_ste_v1_build_flex_parser_1_init, + .build_tnl_gtpu_init = &dr_ste_v1_build_flex_parser_tnl_gtpu_init, + .build_tnl_header_0_1_init = &dr_ste_v1_build_tnl_header_0_1_init, + .build_tnl_gtpu_flex_parser_0_init = &dr_ste_v1_build_tnl_gtpu_flex_parser_0_init, + .build_tnl_gtpu_flex_parser_1_init = &dr_ste_v1_build_tnl_gtpu_flex_parser_1_init, + + /* Getters and Setters */ + .ste_init = &dr_ste_v1_init, + .set_next_lu_type = &dr_ste_v1_set_next_lu_type, + .get_next_lu_type = &dr_ste_v1_get_next_lu_type, + .is_miss_addr_set = &dr_ste_v1_is_miss_addr_set, + .set_miss_addr = &dr_ste_v1_set_miss_addr, + .get_miss_addr = &dr_ste_v1_get_miss_addr, + .set_hit_addr = &dr_ste_v1_set_hit_addr, + .set_byte_mask = &dr_ste_v1_set_byte_mask, + .get_byte_mask = &dr_ste_v1_get_byte_mask, + + /* Actions */ + .actions_caps = DR_STE_CTX_ACTION_CAP_TX_POP | + DR_STE_CTX_ACTION_CAP_RX_PUSH | + DR_STE_CTX_ACTION_CAP_RX_ENCAP, + .set_actions_rx = &dr_ste_v1_set_actions_rx, + .set_actions_tx = &dr_ste_v1_set_actions_tx, + .modify_field_arr_sz = ARRAY_SIZE(dr_ste_v2_action_modify_field_arr), + .modify_field_arr = dr_ste_v2_action_modify_field_arr, + .set_action_set = &dr_ste_v1_set_action_set, + .set_action_add = &dr_ste_v1_set_action_add, + .set_action_copy = &dr_ste_v1_set_action_copy, + .set_action_decap_l3_list = &dr_ste_v1_set_action_decap_l3_list, + .alloc_modify_hdr_chunk = &dr_ste_v1_alloc_modify_hdr_ptrn_arg, + .dealloc_modify_hdr_chunk = &dr_ste_v1_free_modify_hdr_ptrn_arg, + + /* Send */ + .prepare_for_postsend = &dr_ste_v1_prepare_for_postsend, +}; + +struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx_v2(void) +{ + return &ste_ctx_v2; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_table.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_table.c new file mode 100644 index 00000000000000..69294a66fd7f0c --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_table.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies. */ + +#include "dr_types.h" + +static int dr_table_set_miss_action_nic(struct mlx5dr_domain *dmn, + struct mlx5dr_table_rx_tx *nic_tbl, + struct mlx5dr_action *action) +{ + struct mlx5dr_matcher_rx_tx *last_nic_matcher = NULL; + struct mlx5dr_htbl_connect_info info; + struct mlx5dr_ste_htbl *last_htbl; + struct mlx5dr_icm_chunk *chunk; + int ret; + + if (!list_empty(&nic_tbl->nic_matcher_list)) + last_nic_matcher = list_last_entry(&nic_tbl->nic_matcher_list, + struct mlx5dr_matcher_rx_tx, + list_node); + + if (last_nic_matcher) + last_htbl = last_nic_matcher->e_anchor; + else + last_htbl = nic_tbl->s_anchor; + + if (action) { + chunk = nic_tbl->nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX ? + action->dest_tbl->tbl->rx.s_anchor->chunk : + action->dest_tbl->tbl->tx.s_anchor->chunk; + nic_tbl->default_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(chunk); + } else { + nic_tbl->default_icm_addr = nic_tbl->nic_dmn->default_icm_addr; + } + + info.type = CONNECT_MISS; + info.miss_icm_addr = nic_tbl->default_icm_addr; + + ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_tbl->nic_dmn, + last_htbl, &info, true); + if (ret) + mlx5dr_dbg(dmn, "Failed to set NIC RX/TX miss action, ret %d\n", ret); + + return ret; +} + +int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl, + struct mlx5dr_action *action) +{ + int ret = -EOPNOTSUPP; + + if (action && action->action_type != DR_ACTION_TYP_FT) + return -EOPNOTSUPP; + + mlx5dr_domain_lock(tbl->dmn); + + if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX || + tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) { + ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->rx, action); + if (ret) + goto out; + } + + if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX || + tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) { + ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->tx, action); + if (ret) + goto out; + } + + if (ret) + goto out; + + /* Release old action */ + if (tbl->miss_action) + refcount_dec(&tbl->miss_action->refcount); + + /* Set new miss action */ + tbl->miss_action = action; + if (tbl->miss_action) + refcount_inc(&action->refcount); + +out: + mlx5dr_domain_unlock(tbl->dmn); + return ret; +} + +static void dr_table_uninit_nic(struct mlx5dr_table_rx_tx *nic_tbl) +{ + mlx5dr_htbl_put(nic_tbl->s_anchor); +} + +static void dr_table_uninit_fdb(struct mlx5dr_table *tbl) +{ + dr_table_uninit_nic(&tbl->rx); + dr_table_uninit_nic(&tbl->tx); +} + +static void dr_table_uninit(struct mlx5dr_table *tbl) +{ + mlx5dr_domain_lock(tbl->dmn); + + switch (tbl->dmn->type) { + case MLX5DR_DOMAIN_TYPE_NIC_RX: + dr_table_uninit_nic(&tbl->rx); + break; + case MLX5DR_DOMAIN_TYPE_NIC_TX: + dr_table_uninit_nic(&tbl->tx); + break; + case MLX5DR_DOMAIN_TYPE_FDB: + dr_table_uninit_fdb(tbl); + break; + default: + WARN_ON(true); + break; + } + + mlx5dr_domain_unlock(tbl->dmn); +} + +static int dr_table_init_nic(struct mlx5dr_domain *dmn, + struct mlx5dr_table_rx_tx *nic_tbl) +{ + struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; + struct mlx5dr_htbl_connect_info info; + int ret; + + INIT_LIST_HEAD(&nic_tbl->nic_matcher_list); + + nic_tbl->default_icm_addr = nic_dmn->default_icm_addr; + + nic_tbl->s_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, + DR_CHUNK_SIZE_1, + MLX5DR_STE_LU_TYPE_DONT_CARE, + 0); + if (!nic_tbl->s_anchor) { + mlx5dr_err(dmn, "Failed allocating htbl\n"); + return -ENOMEM; + } + + info.type = CONNECT_MISS; + info.miss_icm_addr = nic_dmn->default_icm_addr; + ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, + nic_tbl->s_anchor, + &info, true); + if (ret) { + mlx5dr_err(dmn, "Failed int and send htbl\n"); + goto free_s_anchor; + } + + mlx5dr_htbl_get(nic_tbl->s_anchor); + + return 0; + +free_s_anchor: + mlx5dr_ste_htbl_free(nic_tbl->s_anchor); + return ret; +} + +static int dr_table_init_fdb(struct mlx5dr_table *tbl) +{ + int ret; + + ret = dr_table_init_nic(tbl->dmn, &tbl->rx); + if (ret) + return ret; + + ret = dr_table_init_nic(tbl->dmn, &tbl->tx); + if (ret) + goto destroy_rx; + + return 0; + +destroy_rx: + dr_table_uninit_nic(&tbl->rx); + return ret; +} + +static int dr_table_init(struct mlx5dr_table *tbl) +{ + int ret = 0; + + INIT_LIST_HEAD(&tbl->matcher_list); + + mlx5dr_domain_lock(tbl->dmn); + + switch (tbl->dmn->type) { + case MLX5DR_DOMAIN_TYPE_NIC_RX: + tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_RX; + tbl->rx.nic_dmn = &tbl->dmn->info.rx; + ret = dr_table_init_nic(tbl->dmn, &tbl->rx); + break; + case MLX5DR_DOMAIN_TYPE_NIC_TX: + tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_TX; + tbl->tx.nic_dmn = &tbl->dmn->info.tx; + ret = dr_table_init_nic(tbl->dmn, &tbl->tx); + break; + case MLX5DR_DOMAIN_TYPE_FDB: + tbl->table_type = MLX5_FLOW_TABLE_TYPE_FDB; + tbl->rx.nic_dmn = &tbl->dmn->info.rx; + tbl->tx.nic_dmn = &tbl->dmn->info.tx; + ret = dr_table_init_fdb(tbl); + break; + default: + WARN_ON(true); + break; + } + + mlx5dr_domain_unlock(tbl->dmn); + + return ret; +} + +static int dr_table_destroy_sw_owned_tbl(struct mlx5dr_table *tbl) +{ + return mlx5dr_cmd_destroy_flow_table(tbl->dmn->mdev, + tbl->table_id, + tbl->table_type); +} + +static int dr_table_create_sw_owned_tbl(struct mlx5dr_table *tbl, u16 uid) +{ + bool en_encap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT); + bool en_decap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); + struct mlx5dr_cmd_create_flow_table_attr ft_attr = {}; + u64 icm_addr_rx = 0; + u64 icm_addr_tx = 0; + int ret; + + if (tbl->rx.s_anchor) + icm_addr_rx = mlx5dr_icm_pool_get_chunk_icm_addr(tbl->rx.s_anchor->chunk); + + if (tbl->tx.s_anchor) + icm_addr_tx = mlx5dr_icm_pool_get_chunk_icm_addr(tbl->tx.s_anchor->chunk); + + ft_attr.table_type = tbl->table_type; + ft_attr.icm_addr_rx = icm_addr_rx; + ft_attr.icm_addr_tx = icm_addr_tx; + ft_attr.level = tbl->dmn->info.caps.max_ft_level - 1; + ft_attr.sw_owner = true; + ft_attr.decap_en = en_decap; + ft_attr.reformat_en = en_encap; + ft_attr.uid = uid; + + ret = mlx5dr_cmd_create_flow_table(tbl->dmn->mdev, &ft_attr, + NULL, &tbl->table_id); + + return ret; +} + +struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_domain *dmn, u32 level, + u32 flags, u16 uid) +{ + struct mlx5dr_table *tbl; + int ret; + + refcount_inc(&dmn->refcount); + + tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); + if (!tbl) + goto dec_ref; + + tbl->dmn = dmn; + tbl->level = level; + tbl->flags = flags; + refcount_set(&tbl->refcount, 1); + + ret = dr_table_init(tbl); + if (ret) + goto free_tbl; + + ret = dr_table_create_sw_owned_tbl(tbl, uid); + if (ret) + goto uninit_tbl; + + INIT_LIST_HEAD(&tbl->dbg_node); + mlx5dr_dbg_tbl_add(tbl); + return tbl; + +uninit_tbl: + dr_table_uninit(tbl); +free_tbl: + kfree(tbl); +dec_ref: + refcount_dec(&dmn->refcount); + return NULL; +} + +int mlx5dr_table_destroy(struct mlx5dr_table *tbl) +{ + int ret; + + if (WARN_ON_ONCE(refcount_read(&tbl->refcount) > 1)) + return -EBUSY; + + mlx5dr_dbg_tbl_del(tbl); + ret = dr_table_destroy_sw_owned_tbl(tbl); + if (ret) + mlx5dr_err(tbl->dmn, "Failed to destroy sw owned table\n"); + + dr_table_uninit(tbl); + + if (tbl->miss_action) + refcount_dec(&tbl->miss_action->refcount); + + refcount_dec(&tbl->dmn->refcount); + kfree(tbl); + + return ret; +} + +u32 mlx5dr_table_get_id(struct mlx5dr_table *tbl) +{ + return tbl->table_id; +} + +struct mlx5dr_table *mlx5dr_table_get_from_fs_ft(struct mlx5_flow_table *ft) +{ + return ft->fs_dr_table.dr_table; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_types.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_types.h new file mode 100644 index 00000000000000..7618c6147f8665 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_types.h @@ -0,0 +1,1599 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2019, Mellanox Technologies */ + +#ifndef _DR_TYPES_ +#define _DR_TYPES_ + +#include +#include +#include "fs_core.h" +#include "wq.h" +#include "lib/mlx5.h" +#include "mlx5_ifc_dr.h" +#include "mlx5dr.h" +#include "dr_dbg.h" + +#define DR_RULE_MAX_STES 18 +#define DR_ACTION_MAX_STES 5 +#define DR_STE_SVLAN 0x1 +#define DR_STE_CVLAN 0x2 +#define DR_SZ_MATCH_PARAM (MLX5_ST_SZ_DW_MATCH_PARAM * 4) +#define DR_NUM_OF_FLEX_PARSERS 8 +#define DR_STE_MAX_FLEX_0_ID 3 +#define DR_STE_MAX_FLEX_1_ID 7 +#define DR_ACTION_CACHE_LINE_SIZE 64 + +#define mlx5dr_err(dmn, arg...) mlx5_core_err((dmn)->mdev, ##arg) +#define mlx5dr_info(dmn, arg...) mlx5_core_info((dmn)->mdev, ##arg) +#define mlx5dr_dbg(dmn, arg...) mlx5_core_dbg((dmn)->mdev, ##arg) + +struct mlx5dr_ptrn_mgr; +struct mlx5dr_arg_mgr; +struct mlx5dr_arg_obj; + +static inline bool dr_is_flex_parser_0_id(u8 parser_id) +{ + return parser_id <= DR_STE_MAX_FLEX_0_ID; +} + +static inline bool dr_is_flex_parser_1_id(u8 parser_id) +{ + return parser_id > DR_STE_MAX_FLEX_0_ID; +} + +enum mlx5dr_icm_chunk_size { + DR_CHUNK_SIZE_1, + DR_CHUNK_SIZE_MIN = DR_CHUNK_SIZE_1, /* keep updated when changing */ + DR_CHUNK_SIZE_2, + DR_CHUNK_SIZE_4, + DR_CHUNK_SIZE_8, + DR_CHUNK_SIZE_16, + DR_CHUNK_SIZE_32, + DR_CHUNK_SIZE_64, + DR_CHUNK_SIZE_128, + DR_CHUNK_SIZE_256, + DR_CHUNK_SIZE_512, + DR_CHUNK_SIZE_1K, + DR_CHUNK_SIZE_2K, + DR_CHUNK_SIZE_4K, + DR_CHUNK_SIZE_8K, + DR_CHUNK_SIZE_16K, + DR_CHUNK_SIZE_32K, + DR_CHUNK_SIZE_64K, + DR_CHUNK_SIZE_128K, + DR_CHUNK_SIZE_256K, + DR_CHUNK_SIZE_512K, + DR_CHUNK_SIZE_1024K, + DR_CHUNK_SIZE_2048K, + DR_CHUNK_SIZE_MAX, +}; + +enum mlx5dr_icm_type { + DR_ICM_TYPE_STE, + DR_ICM_TYPE_MODIFY_ACTION, + DR_ICM_TYPE_MODIFY_HDR_PTRN, + DR_ICM_TYPE_MAX, +}; + +static inline enum mlx5dr_icm_chunk_size +mlx5dr_icm_next_higher_chunk(enum mlx5dr_icm_chunk_size chunk) +{ + chunk += 2; + if (chunk < DR_CHUNK_SIZE_MAX) + return chunk; + + return DR_CHUNK_SIZE_MAX; +} + +enum { + DR_STE_SIZE = 64, + DR_STE_SIZE_CTRL = 32, + DR_STE_SIZE_MATCH_TAG = 32, + DR_STE_SIZE_TAG = 16, + DR_STE_SIZE_MASK = 16, + DR_STE_SIZE_REDUCED = DR_STE_SIZE - DR_STE_SIZE_MASK, +}; + +enum mlx5dr_ste_ctx_action_cap { + DR_STE_CTX_ACTION_CAP_NONE = 0, + DR_STE_CTX_ACTION_CAP_TX_POP = 1 << 0, + DR_STE_CTX_ACTION_CAP_RX_PUSH = 1 << 1, + DR_STE_CTX_ACTION_CAP_RX_ENCAP = 1 << 2, + DR_STE_CTX_ACTION_CAP_POP_MDFY = 1 << 3, +}; + +enum { + DR_MODIFY_ACTION_SIZE = 8, +}; + +enum mlx5dr_matcher_criteria { + DR_MATCHER_CRITERIA_EMPTY = 0, + DR_MATCHER_CRITERIA_OUTER = 1 << 0, + DR_MATCHER_CRITERIA_MISC = 1 << 1, + DR_MATCHER_CRITERIA_INNER = 1 << 2, + DR_MATCHER_CRITERIA_MISC2 = 1 << 3, + DR_MATCHER_CRITERIA_MISC3 = 1 << 4, + DR_MATCHER_CRITERIA_MISC4 = 1 << 5, + DR_MATCHER_CRITERIA_MISC5 = 1 << 6, + DR_MATCHER_CRITERIA_MAX = 1 << 7, +}; + +enum mlx5dr_action_type { + DR_ACTION_TYP_TNL_L2_TO_L2, + DR_ACTION_TYP_L2_TO_TNL_L2, + DR_ACTION_TYP_TNL_L3_TO_L2, + DR_ACTION_TYP_L2_TO_TNL_L3, + DR_ACTION_TYP_DROP, + DR_ACTION_TYP_QP, + DR_ACTION_TYP_FT, + DR_ACTION_TYP_CTR, + DR_ACTION_TYP_TAG, + DR_ACTION_TYP_MODIFY_HDR, + DR_ACTION_TYP_VPORT, + DR_ACTION_TYP_POP_VLAN, + DR_ACTION_TYP_PUSH_VLAN, + DR_ACTION_TYP_INSERT_HDR, + DR_ACTION_TYP_REMOVE_HDR, + DR_ACTION_TYP_SAMPLER, + DR_ACTION_TYP_ASO_FLOW_METER, + DR_ACTION_TYP_RANGE, + DR_ACTION_TYP_MAX, +}; + +enum mlx5dr_ipv { + DR_RULE_IPV4, + DR_RULE_IPV6, + DR_RULE_IPV_MAX, +}; + +struct mlx5dr_icm_pool; +struct mlx5dr_icm_chunk; +struct mlx5dr_icm_buddy_mem; +struct mlx5dr_ste_htbl; +struct mlx5dr_match_param; +struct mlx5dr_cmd_caps; +struct mlx5dr_rule_rx_tx; +struct mlx5dr_matcher_rx_tx; +struct mlx5dr_ste_ctx; +struct mlx5dr_send_info_pool; +struct mlx5dr_icm_hot_chunk; + +struct mlx5dr_ste { + /* refcount: indicates the num of rules that using this ste */ + u32 refcount; + + /* this ste is part of a rule, located in ste's chain */ + u8 ste_chain_location; + + /* attached to the miss_list head at each htbl entry */ + struct list_head miss_list_node; + + /* this ste is member of htbl */ + struct mlx5dr_ste_htbl *htbl; + + struct mlx5dr_ste_htbl *next_htbl; + + /* The rule this STE belongs to */ + struct mlx5dr_rule_rx_tx *rule_rx_tx; +}; + +struct mlx5dr_ste_htbl_ctrl { + /* total number of valid entries belonging to this hash table. This + * includes the non collision and collision entries + */ + unsigned int num_of_valid_entries; + + /* total number of collisions entries attached to this table */ + unsigned int num_of_collisions; +}; + +struct mlx5dr_ste_htbl { + u16 lu_type; + u16 byte_mask; + u32 refcount; + struct mlx5dr_icm_chunk *chunk; + struct mlx5dr_ste *pointing_ste; + struct mlx5dr_ste_htbl_ctrl ctrl; +}; + +struct mlx5dr_ste_send_info { + struct mlx5dr_ste *ste; + struct list_head send_list; + u16 size; + u16 offset; + u8 data_cont[DR_STE_SIZE]; + u8 *data; +}; + +void mlx5dr_send_fill_and_append_ste_send_info(struct mlx5dr_ste *ste, u16 size, + u16 offset, u8 *data, + struct mlx5dr_ste_send_info *ste_info, + struct list_head *send_list, + bool copy_data); + +struct mlx5dr_ste_build { + u8 inner:1; + u8 rx:1; + u8 vhca_id_valid:1; + struct mlx5dr_domain *dmn; + struct mlx5dr_cmd_caps *caps; + u16 lu_type; + u16 byte_mask; + u8 bit_mask[DR_STE_SIZE_MASK]; + int (*ste_build_tag_func)(struct mlx5dr_match_param *spec, + struct mlx5dr_ste_build *sb, + u8 *tag); +}; + +struct mlx5dr_ste_htbl * +mlx5dr_ste_htbl_alloc(struct mlx5dr_icm_pool *pool, + enum mlx5dr_icm_chunk_size chunk_size, + u16 lu_type, u16 byte_mask); + +int mlx5dr_ste_htbl_free(struct mlx5dr_ste_htbl *htbl); + +static inline void mlx5dr_htbl_put(struct mlx5dr_ste_htbl *htbl) +{ + htbl->refcount--; + if (!htbl->refcount) + mlx5dr_ste_htbl_free(htbl); +} + +static inline void mlx5dr_htbl_get(struct mlx5dr_ste_htbl *htbl) +{ + htbl->refcount++; +} + +/* STE utils */ +u32 mlx5dr_ste_calc_hash_index(u8 *hw_ste_p, struct mlx5dr_ste_htbl *htbl); +bool mlx5dr_ste_is_miss_addr_set(struct mlx5dr_ste_ctx *ste_ctx, u8 *hw_ste_p); +void mlx5dr_ste_set_miss_addr(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste, u64 miss_addr); +void mlx5dr_ste_set_hit_addr(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste, u64 icm_addr, u32 ht_size); +void mlx5dr_ste_set_hit_addr_by_next_htbl(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste, + struct mlx5dr_ste_htbl *next_htbl); +void mlx5dr_ste_set_bit_mask(u8 *hw_ste_p, u8 *bit_mask); +bool mlx5dr_ste_is_last_in_rule(struct mlx5dr_matcher_rx_tx *nic_matcher, + u8 ste_location); +u64 mlx5dr_ste_get_icm_addr(struct mlx5dr_ste *ste); +u64 mlx5dr_ste_get_mr_addr(struct mlx5dr_ste *ste); +struct list_head *mlx5dr_ste_get_miss_list(struct mlx5dr_ste *ste); + +#define MLX5DR_MAX_VLANS 2 +#define MLX5DR_INVALID_PATTERN_INDEX 0xffffffff + +struct mlx5dr_ste_actions_attr { + u32 modify_index; + u32 modify_pat_idx; + u16 modify_actions; + u8 *single_modify_action; + u32 decap_index; + u32 decap_pat_idx; + u16 decap_actions; + u8 decap_with_vlan:1; + u64 final_icm_addr; + u32 flow_tag; + u32 ctr_id; + u16 gvmi; + u16 hit_gvmi; + struct { + u32 id; + u32 size; + u8 param_0; + u8 param_1; + } reformat; + struct { + int count; + u32 headers[MLX5DR_MAX_VLANS]; + } vlans; + + struct { + u32 obj_id; + u32 offset; + u8 dest_reg_id; + u8 init_color; + } aso_flow_meter; + + struct { + u64 miss_icm_addr; + u32 definer_id; + u32 min; + u32 max; + } range; +}; + +void mlx5dr_ste_set_actions_rx(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_domain *dmn, + u8 *action_type_set, + u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes); +void mlx5dr_ste_set_actions_tx(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_domain *dmn, + u8 *action_type_set, + u8 *last_ste, + struct mlx5dr_ste_actions_attr *attr, + u32 *added_stes); + +void mlx5dr_ste_set_action_set(struct mlx5dr_ste_ctx *ste_ctx, + __be64 *hw_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data); +void mlx5dr_ste_set_action_add(struct mlx5dr_ste_ctx *ste_ctx, + __be64 *hw_action, + u8 hw_field, + u8 shifter, + u8 length, + u32 data); +void mlx5dr_ste_set_action_copy(struct mlx5dr_ste_ctx *ste_ctx, + __be64 *hw_action, + u8 dst_hw_field, + u8 dst_shifter, + u8 dst_len, + u8 src_hw_field, + u8 src_shifter); +int mlx5dr_ste_set_action_decap_l3_list(struct mlx5dr_ste_ctx *ste_ctx, + void *data, + u32 data_sz, + u8 *hw_action, + u32 hw_action_sz, + u16 *used_hw_action_num); +int mlx5dr_ste_alloc_modify_hdr(struct mlx5dr_action *action); +void mlx5dr_ste_free_modify_hdr(struct mlx5dr_action *action); + +const struct mlx5dr_ste_action_modify_field * +mlx5dr_ste_conv_modify_hdr_sw_field(struct mlx5dr_ste_ctx *ste_ctx, u16 sw_field); + +struct mlx5dr_ste_ctx *mlx5dr_ste_get_ctx(u8 version); +void mlx5dr_ste_free(struct mlx5dr_ste *ste, + struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher); +static inline void mlx5dr_ste_put(struct mlx5dr_ste *ste, + struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + ste->refcount--; + if (!ste->refcount) + mlx5dr_ste_free(ste, matcher, nic_matcher); +} + +/* initial as 0, increased only when ste appears in a new rule */ +static inline void mlx5dr_ste_get(struct mlx5dr_ste *ste) +{ + ste->refcount++; +} + +static inline bool mlx5dr_ste_is_not_used(struct mlx5dr_ste *ste) +{ + return !ste->refcount; +} + +bool mlx5dr_ste_equal_tag(void *src, void *dst); +int mlx5dr_ste_create_next_htbl(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_ste *ste, + u8 *cur_hw_ste, + enum mlx5dr_icm_chunk_size log_table_size); + +/* STE build functions */ +int mlx5dr_ste_build_pre_check(struct mlx5dr_domain *dmn, + u8 match_criteria, + struct mlx5dr_match_param *mask, + struct mlx5dr_match_param *value); +int mlx5dr_ste_build_ste_arr(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_match_param *value, + u8 *ste_arr); +void mlx5dr_ste_build_eth_l2_src_dst(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *builder, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_l3_ipv4_5_tuple(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_l3_ipv4_misc(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_l3_ipv6_dst(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_l3_ipv6_src(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_l2_src(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_l2_dst(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_l2_tnl(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_ipv6_l3_l4(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_eth_l4_misc(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_gre(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_mpls(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_mpls_over_gre(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_mpls_over_udp(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx); +void mlx5dr_ste_build_icmp(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_vxlan_gpe(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_geneve(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_geneve_tlv_opt(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_geneve_tlv_opt_exist(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_gtpu(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_gtpu_flex_parser_0(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_gtpu_flex_parser_1(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_cmd_caps *caps, + bool inner, bool rx); +void mlx5dr_ste_build_tnl_header_0_1(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_general_purpose(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_register_0(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_register_1(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_src_gvmi_qpn(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn, + bool inner, bool rx); +void mlx5dr_ste_build_flex_parser_0(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_flex_parser_1(struct mlx5dr_ste_ctx *ste_ctx, + struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); +void mlx5dr_ste_build_empty_always_hit(struct mlx5dr_ste_build *sb, bool rx); + +/* Actions utils */ +int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + struct mlx5dr_action *actions[], + u32 num_actions, + u8 *ste_arr, + u32 *new_hw_ste_arr_sz); + +struct mlx5dr_match_spec { + u32 smac_47_16; /* Source MAC address of incoming packet */ + /* Incoming packet Ethertype - this is the Ethertype + * following the last VLAN tag of the packet + */ + u32 smac_15_0:16; /* Source MAC address of incoming packet */ + u32 ethertype:16; + + u32 dmac_47_16; /* Destination MAC address of incoming packet */ + + u32 dmac_15_0:16; /* Destination MAC address of incoming packet */ + /* Priority of first VLAN tag in the incoming packet. + * Valid only when cvlan_tag==1 or svlan_tag==1 + */ + u32 first_prio:3; + /* CFI bit of first VLAN tag in the incoming packet. + * Valid only when cvlan_tag==1 or svlan_tag==1 + */ + u32 first_cfi:1; + /* VLAN ID of first VLAN tag in the incoming packet. + * Valid only when cvlan_tag==1 or svlan_tag==1 + */ + u32 first_vid:12; + + u32 ip_protocol:8; /* IP protocol */ + /* Differentiated Services Code Point derived from + * Traffic Class/TOS field of IPv6/v4 + */ + u32 ip_dscp:6; + /* Explicit Congestion Notification derived from + * Traffic Class/TOS field of IPv6/v4 + */ + u32 ip_ecn:2; + /* The first vlan in the packet is c-vlan (0x8100). + * cvlan_tag and svlan_tag cannot be set together + */ + u32 cvlan_tag:1; + /* The first vlan in the packet is s-vlan (0x8a88). + * cvlan_tag and svlan_tag cannot be set together + */ + u32 svlan_tag:1; + u32 frag:1; /* Packet is an IP fragment */ + u32 ip_version:4; /* IP version */ + /* TCP flags. ;Bit 0: FIN;Bit 1: SYN;Bit 2: RST;Bit 3: PSH;Bit 4: ACK; + * Bit 5: URG;Bit 6: ECE;Bit 7: CWR;Bit 8: NS + */ + u32 tcp_flags:9; + + /* TCP source port.;tcp and udp sport/dport are mutually exclusive */ + u32 tcp_sport:16; + /* TCP destination port. + * tcp and udp sport/dport are mutually exclusive + */ + u32 tcp_dport:16; + + u32 reserved_auto1:16; + u32 ipv4_ihl:4; + u32 reserved_auto2:4; + u32 ttl_hoplimit:8; + + /* UDP source port.;tcp and udp sport/dport are mutually exclusive */ + u32 udp_sport:16; + /* UDP destination port.;tcp and udp sport/dport are mutually exclusive */ + u32 udp_dport:16; + + /* IPv6 source address of incoming packets + * For IPv4 address use bits 31:0 (rest of the bits are reserved) + * This field should be qualified by an appropriate ethertype + */ + u32 src_ip_127_96; + /* IPv6 source address of incoming packets + * For IPv4 address use bits 31:0 (rest of the bits are reserved) + * This field should be qualified by an appropriate ethertype + */ + u32 src_ip_95_64; + /* IPv6 source address of incoming packets + * For IPv4 address use bits 31:0 (rest of the bits are reserved) + * This field should be qualified by an appropriate ethertype + */ + u32 src_ip_63_32; + /* IPv6 source address of incoming packets + * For IPv4 address use bits 31:0 (rest of the bits are reserved) + * This field should be qualified by an appropriate ethertype + */ + u32 src_ip_31_0; + /* IPv6 destination address of incoming packets + * For IPv4 address use bits 31:0 (rest of the bits are reserved) + * This field should be qualified by an appropriate ethertype + */ + u32 dst_ip_127_96; + /* IPv6 destination address of incoming packets + * For IPv4 address use bits 31:0 (rest of the bits are reserved) + * This field should be qualified by an appropriate ethertype + */ + u32 dst_ip_95_64; + /* IPv6 destination address of incoming packets + * For IPv4 address use bits 31:0 (rest of the bits are reserved) + * This field should be qualified by an appropriate ethertype + */ + u32 dst_ip_63_32; + /* IPv6 destination address of incoming packets + * For IPv4 address use bits 31:0 (rest of the bits are reserved) + * This field should be qualified by an appropriate ethertype + */ + u32 dst_ip_31_0; +}; + +struct mlx5dr_match_misc { + /* used with GRE, checksum exist when gre_c_present == 1 */ + u32 gre_c_present:1; + u32 reserved_auto1:1; + /* used with GRE, key exist when gre_k_present == 1 */ + u32 gre_k_present:1; + /* used with GRE, sequence number exist when gre_s_present == 1 */ + u32 gre_s_present:1; + u32 source_vhca_port:4; + u32 source_sqn:24; /* Source SQN */ + + u32 source_eswitch_owner_vhca_id:16; + /* Source port.;0xffff determines wire port */ + u32 source_port:16; + + /* Priority of second VLAN tag in the outer header of the incoming packet. + * Valid only when outer_second_cvlan_tag ==1 or outer_second_svlan_tag ==1 + */ + u32 outer_second_prio:3; + /* CFI bit of first VLAN tag in the outer header of the incoming packet. + * Valid only when outer_second_cvlan_tag ==1 or outer_second_svlan_tag ==1 + */ + u32 outer_second_cfi:1; + /* VLAN ID of first VLAN tag the outer header of the incoming packet. + * Valid only when outer_second_cvlan_tag ==1 or outer_second_svlan_tag ==1 + */ + u32 outer_second_vid:12; + /* Priority of second VLAN tag in the inner header of the incoming packet. + * Valid only when inner_second_cvlan_tag ==1 or inner_second_svlan_tag ==1 + */ + u32 inner_second_prio:3; + /* CFI bit of first VLAN tag in the inner header of the incoming packet. + * Valid only when inner_second_cvlan_tag ==1 or inner_second_svlan_tag ==1 + */ + u32 inner_second_cfi:1; + /* VLAN ID of first VLAN tag the inner header of the incoming packet. + * Valid only when inner_second_cvlan_tag ==1 or inner_second_svlan_tag ==1 + */ + u32 inner_second_vid:12; + + u32 outer_second_cvlan_tag:1; + u32 inner_second_cvlan_tag:1; + /* The second vlan in the outer header of the packet is c-vlan (0x8100). + * outer_second_cvlan_tag and outer_second_svlan_tag cannot be set together + */ + u32 outer_second_svlan_tag:1; + /* The second vlan in the inner header of the packet is c-vlan (0x8100). + * inner_second_cvlan_tag and inner_second_svlan_tag cannot be set together + */ + u32 inner_second_svlan_tag:1; + /* The second vlan in the outer header of the packet is s-vlan (0x8a88). + * outer_second_cvlan_tag and outer_second_svlan_tag cannot be set together + */ + u32 reserved_auto2:12; + /* The second vlan in the inner header of the packet is s-vlan (0x8a88). + * inner_second_cvlan_tag and inner_second_svlan_tag cannot be set together + */ + u32 gre_protocol:16; /* GRE Protocol (outer) */ + + u32 gre_key_h:24; /* GRE Key[31:8] (outer) */ + u32 gre_key_l:8; /* GRE Key [7:0] (outer) */ + + u32 vxlan_vni:24; /* VXLAN VNI (outer) */ + u32 reserved_auto3:8; + + u32 geneve_vni:24; /* GENEVE VNI field (outer) */ + u32 reserved_auto4:6; + u32 geneve_tlv_option_0_exist:1; + u32 geneve_oam:1; /* GENEVE OAM field (outer) */ + + u32 reserved_auto5:12; + u32 outer_ipv6_flow_label:20; /* Flow label of incoming IPv6 packet (outer) */ + + u32 reserved_auto6:12; + u32 inner_ipv6_flow_label:20; /* Flow label of incoming IPv6 packet (inner) */ + + u32 reserved_auto7:10; + u32 geneve_opt_len:6; /* GENEVE OptLen (outer) */ + u32 geneve_protocol_type:16; /* GENEVE protocol type (outer) */ + + u32 reserved_auto8:8; + u32 bth_dst_qp:24; /* Destination QP in BTH header */ + + u32 reserved_auto9; + u32 outer_esp_spi; + u32 reserved_auto10[3]; +}; + +struct mlx5dr_match_misc2 { + u32 outer_first_mpls_label:20; /* First MPLS LABEL (outer) */ + u32 outer_first_mpls_exp:3; /* First MPLS EXP (outer) */ + u32 outer_first_mpls_s_bos:1; /* First MPLS S_BOS (outer) */ + u32 outer_first_mpls_ttl:8; /* First MPLS TTL (outer) */ + + u32 inner_first_mpls_label:20; /* First MPLS LABEL (inner) */ + u32 inner_first_mpls_exp:3; /* First MPLS EXP (inner) */ + u32 inner_first_mpls_s_bos:1; /* First MPLS S_BOS (inner) */ + u32 inner_first_mpls_ttl:8; /* First MPLS TTL (inner) */ + + u32 outer_first_mpls_over_gre_label:20; /* last MPLS LABEL (outer) */ + u32 outer_first_mpls_over_gre_exp:3; /* last MPLS EXP (outer) */ + u32 outer_first_mpls_over_gre_s_bos:1; /* last MPLS S_BOS (outer) */ + u32 outer_first_mpls_over_gre_ttl:8; /* last MPLS TTL (outer) */ + + u32 outer_first_mpls_over_udp_label:20; /* last MPLS LABEL (outer) */ + u32 outer_first_mpls_over_udp_exp:3; /* last MPLS EXP (outer) */ + u32 outer_first_mpls_over_udp_s_bos:1; /* last MPLS S_BOS (outer) */ + u32 outer_first_mpls_over_udp_ttl:8; /* last MPLS TTL (outer) */ + + u32 metadata_reg_c_7; /* metadata_reg_c_7 */ + u32 metadata_reg_c_6; /* metadata_reg_c_6 */ + u32 metadata_reg_c_5; /* metadata_reg_c_5 */ + u32 metadata_reg_c_4; /* metadata_reg_c_4 */ + u32 metadata_reg_c_3; /* metadata_reg_c_3 */ + u32 metadata_reg_c_2; /* metadata_reg_c_2 */ + u32 metadata_reg_c_1; /* metadata_reg_c_1 */ + u32 metadata_reg_c_0; /* metadata_reg_c_0 */ + u32 metadata_reg_a; /* metadata_reg_a */ + u32 reserved_auto1[3]; +}; + +struct mlx5dr_match_misc3 { + u32 inner_tcp_seq_num; + u32 outer_tcp_seq_num; + u32 inner_tcp_ack_num; + u32 outer_tcp_ack_num; + + u32 reserved_auto1:8; + u32 outer_vxlan_gpe_vni:24; + + u32 outer_vxlan_gpe_next_protocol:8; + u32 outer_vxlan_gpe_flags:8; + u32 reserved_auto2:16; + + u32 icmpv4_header_data; + u32 icmpv6_header_data; + + u8 icmpv4_type; + u8 icmpv4_code; + u8 icmpv6_type; + u8 icmpv6_code; + + u32 geneve_tlv_option_0_data; + + u32 gtpu_teid; + + u8 gtpu_msg_type; + u8 gtpu_msg_flags; + u32 reserved_auto3:16; + + u32 gtpu_dw_2; + u32 gtpu_first_ext_dw_0; + u32 gtpu_dw_0; + u32 reserved_auto4; +}; + +struct mlx5dr_match_misc4 { + u32 prog_sample_field_value_0; + u32 prog_sample_field_id_0; + u32 prog_sample_field_value_1; + u32 prog_sample_field_id_1; + u32 prog_sample_field_value_2; + u32 prog_sample_field_id_2; + u32 prog_sample_field_value_3; + u32 prog_sample_field_id_3; + u32 reserved_auto1[8]; +}; + +struct mlx5dr_match_misc5 { + u32 macsec_tag_0; + u32 macsec_tag_1; + u32 macsec_tag_2; + u32 macsec_tag_3; + u32 tunnel_header_0; + u32 tunnel_header_1; + u32 tunnel_header_2; + u32 tunnel_header_3; +}; + +struct mlx5dr_match_param { + struct mlx5dr_match_spec outer; + struct mlx5dr_match_misc misc; + struct mlx5dr_match_spec inner; + struct mlx5dr_match_misc2 misc2; + struct mlx5dr_match_misc3 misc3; + struct mlx5dr_match_misc4 misc4; + struct mlx5dr_match_misc5 misc5; +}; + +#define DR_MASK_IS_ICMPV4_SET(_misc3) ((_misc3)->icmpv4_type || \ + (_misc3)->icmpv4_code || \ + (_misc3)->icmpv4_header_data) + +#define DR_MASK_IS_SRC_IP_SET(_spec) ((_spec)->src_ip_127_96 || \ + (_spec)->src_ip_95_64 || \ + (_spec)->src_ip_63_32 || \ + (_spec)->src_ip_31_0) + +#define DR_MASK_IS_DST_IP_SET(_spec) ((_spec)->dst_ip_127_96 || \ + (_spec)->dst_ip_95_64 || \ + (_spec)->dst_ip_63_32 || \ + (_spec)->dst_ip_31_0) + +struct mlx5dr_esw_caps { + u64 drop_icm_address_rx; + u64 drop_icm_address_tx; + u64 uplink_icm_address_rx; + u64 uplink_icm_address_tx; + u8 sw_owner:1; + u8 sw_owner_v2:1; +}; + +struct mlx5dr_cmd_vport_cap { + u16 vport_gvmi; + u16 vhca_gvmi; + u16 num; + u64 icm_address_rx; + u64 icm_address_tx; +}; + +struct mlx5dr_roce_cap { + u8 roce_en:1; + u8 fl_rc_qp_when_roce_disabled:1; + u8 fl_rc_qp_when_roce_enabled:1; +}; + +struct mlx5dr_vports { + struct mlx5dr_cmd_vport_cap esw_manager_caps; + struct mlx5dr_cmd_vport_cap uplink_caps; + struct xarray vports_caps_xa; +}; + +struct mlx5dr_cmd_caps { + u16 gvmi; + u64 nic_rx_drop_address; + u64 nic_tx_drop_address; + u64 nic_tx_allow_address; + u64 esw_rx_drop_address; + u64 esw_tx_drop_address; + u32 log_icm_size; + u64 hdr_modify_icm_addr; + u32 log_modify_pattern_icm_size; + u64 hdr_modify_pattern_icm_addr; + u32 flex_protocols; + u8 flex_parser_id_icmp_dw0; + u8 flex_parser_id_icmp_dw1; + u8 flex_parser_id_icmpv6_dw0; + u8 flex_parser_id_icmpv6_dw1; + u8 flex_parser_id_geneve_tlv_option_0; + u8 flex_parser_id_mpls_over_gre; + u8 flex_parser_id_mpls_over_udp; + u8 flex_parser_id_gtpu_dw_0; + u8 flex_parser_id_gtpu_teid; + u8 flex_parser_id_gtpu_dw_2; + u8 flex_parser_id_gtpu_first_ext_dw_0; + u8 flex_parser_ok_bits_supp; + u8 max_ft_level; + u16 roce_min_src_udp; + u8 sw_format_ver; + bool eswitch_manager; + bool rx_sw_owner; + bool tx_sw_owner; + bool fdb_sw_owner; + u8 rx_sw_owner_v2:1; + u8 tx_sw_owner_v2:1; + u8 fdb_sw_owner_v2:1; + struct mlx5dr_esw_caps esw_caps; + struct mlx5dr_vports vports; + bool prio_tag_required; + struct mlx5dr_roce_cap roce_caps; + u16 log_header_modify_argument_granularity; + u16 log_header_modify_argument_max_alloc; + bool support_modify_argument; + u8 is_ecpf:1; + u8 isolate_vl_tc:1; +}; + +enum mlx5dr_domain_nic_type { + DR_DOMAIN_NIC_TYPE_RX, + DR_DOMAIN_NIC_TYPE_TX, +}; + +struct mlx5dr_domain_rx_tx { + u64 drop_icm_addr; + u64 default_icm_addr; + enum mlx5dr_domain_nic_type type; + struct mutex mutex; /* protect rx/tx domain */ +}; + +struct mlx5dr_domain_info { + bool supp_sw_steering; + u32 max_inline_size; + u32 max_send_wr; + u32 max_log_sw_icm_sz; + u32 max_log_action_icm_sz; + u32 max_log_modify_hdr_pattern_icm_sz; + struct mlx5dr_domain_rx_tx rx; + struct mlx5dr_domain_rx_tx tx; + struct mlx5dr_cmd_caps caps; +}; + +struct mlx5dr_domain { + struct mlx5_core_dev *mdev; + u32 pdn; + struct mlx5_uars_page *uar; + enum mlx5dr_domain_type type; + refcount_t refcount; + struct mlx5dr_icm_pool *ste_icm_pool; + struct mlx5dr_icm_pool *action_icm_pool; + struct mlx5dr_send_info_pool *send_info_pool_rx; + struct mlx5dr_send_info_pool *send_info_pool_tx; + struct kmem_cache *chunks_kmem_cache; + struct kmem_cache *htbls_kmem_cache; + struct mlx5dr_ptrn_mgr *ptrn_mgr; + struct mlx5dr_arg_mgr *arg_mgr; + struct mlx5dr_send_ring *send_ring; + struct mlx5dr_domain_info info; + struct xarray csum_fts_xa; + struct mlx5dr_ste_ctx *ste_ctx; + struct list_head dbg_tbl_list; + struct mlx5dr_dbg_dump_info dump_info; + struct xarray definers_xa; + struct xarray peer_dmn_xa; + /* memory management statistics */ + u32 num_buddies[DR_ICM_TYPE_MAX]; +}; + +struct mlx5dr_table_rx_tx { + struct mlx5dr_ste_htbl *s_anchor; + struct mlx5dr_domain_rx_tx *nic_dmn; + u64 default_icm_addr; + struct list_head nic_matcher_list; +}; + +struct mlx5dr_table { + struct mlx5dr_domain *dmn; + struct mlx5dr_table_rx_tx rx; + struct mlx5dr_table_rx_tx tx; + u32 level; + u32 table_type; + u32 table_id; + u32 flags; + struct list_head matcher_list; + struct mlx5dr_action *miss_action; + refcount_t refcount; + struct list_head dbg_node; +}; + +struct mlx5dr_matcher_rx_tx { + struct mlx5dr_ste_htbl *s_htbl; + struct mlx5dr_ste_htbl *e_anchor; + struct mlx5dr_ste_build *ste_builder; + struct mlx5dr_ste_build ste_builder_arr[DR_RULE_IPV_MAX] + [DR_RULE_IPV_MAX] + [DR_RULE_MAX_STES]; + u8 num_of_builders; + u8 num_of_builders_arr[DR_RULE_IPV_MAX][DR_RULE_IPV_MAX]; + u64 default_icm_addr; + struct mlx5dr_table_rx_tx *nic_tbl; + u32 prio; + struct list_head list_node; + u32 rules; +}; + +struct mlx5dr_matcher { + struct mlx5dr_table *tbl; + struct mlx5dr_matcher_rx_tx rx; + struct mlx5dr_matcher_rx_tx tx; + struct list_head list_node; /* Used for both matchers and dbg managing */ + u32 prio; + struct mlx5dr_match_param mask; + u8 match_criteria; + refcount_t refcount; + struct list_head dbg_rule_list; +}; + +struct mlx5dr_ste_action_modify_field { + u16 hw_field; + u8 start; + u8 end; + u8 l3_type; + u8 l4_type; +}; + +struct mlx5dr_ptrn_obj { + struct mlx5dr_icm_chunk *chunk; + u8 *data; + u16 num_of_actions; + u32 index; + refcount_t refcount; + struct list_head list; +}; + +struct mlx5dr_arg_obj { + u32 obj_id; + u32 obj_offset; + struct list_head list_node; + u32 log_chunk_size; +}; + +struct mlx5dr_action_rewrite { + struct mlx5dr_domain *dmn; + struct mlx5dr_icm_chunk *chunk; + u8 *data; + u16 num_of_actions; + u32 index; + u8 single_action_opt:1; + u8 allow_rx:1; + u8 allow_tx:1; + u8 modify_ttl:1; + struct mlx5dr_ptrn_obj *ptrn; + struct mlx5dr_arg_obj *arg; +}; + +struct mlx5dr_action_reformat { + struct mlx5dr_domain *dmn; + u32 id; + u32 size; + u8 param_0; + u8 param_1; +}; + +struct mlx5dr_action_sampler { + struct mlx5dr_domain *dmn; + u64 rx_icm_addr; + u64 tx_icm_addr; + u32 sampler_id; +}; + +struct mlx5dr_action_dest_tbl { + u8 is_fw_tbl:1; + u8 is_wire_ft:1; + union { + struct mlx5dr_table *tbl; + struct { + struct mlx5dr_domain *dmn; + u32 id; + u32 group_id; + enum fs_flow_table_type type; + u64 rx_icm_addr; + u64 tx_icm_addr; + struct mlx5dr_action **ref_actions; + u32 num_of_ref_actions; + } fw_tbl; + }; +}; + +struct mlx5dr_action_range { + struct mlx5dr_domain *dmn; + struct mlx5dr_action *hit_tbl_action; + struct mlx5dr_action *miss_tbl_action; + u32 definer_id; + u32 min; + u32 max; +}; + +struct mlx5dr_action_ctr { + u32 ctr_id; + u32 offset; +}; + +struct mlx5dr_action_vport { + struct mlx5dr_domain *dmn; + struct mlx5dr_cmd_vport_cap *caps; +}; + +struct mlx5dr_action_push_vlan { + u32 vlan_hdr; /* tpid_pcp_dei_vid */ +}; + +struct mlx5dr_action_flow_tag { + u32 flow_tag; +}; + +struct mlx5dr_rule_action_member { + struct mlx5dr_action *action; + struct list_head list; +}; + +struct mlx5dr_action_aso_flow_meter { + struct mlx5dr_domain *dmn; + u32 obj_id; + u32 offset; + u8 dest_reg_id; + u8 init_color; +}; + +struct mlx5dr_action { + enum mlx5dr_action_type action_type; + refcount_t refcount; + + union { + void *data; + struct mlx5dr_action_rewrite *rewrite; + struct mlx5dr_action_reformat *reformat; + struct mlx5dr_action_sampler *sampler; + struct mlx5dr_action_dest_tbl *dest_tbl; + struct mlx5dr_action_ctr *ctr; + struct mlx5dr_action_vport *vport; + struct mlx5dr_action_push_vlan *push_vlan; + struct mlx5dr_action_flow_tag *flow_tag; + struct mlx5dr_action_aso_flow_meter *aso; + struct mlx5dr_action_range *range; + }; +}; + +enum mlx5dr_connect_type { + CONNECT_HIT = 1, + CONNECT_MISS = 2, +}; + +struct mlx5dr_htbl_connect_info { + enum mlx5dr_connect_type type; + union { + struct mlx5dr_ste_htbl *hit_next_htbl; + u64 miss_icm_addr; + }; +}; + +struct mlx5dr_rule_rx_tx { + struct mlx5dr_matcher_rx_tx *nic_matcher; + struct mlx5dr_ste *last_rule_ste; +}; + +struct mlx5dr_rule { + struct mlx5dr_matcher *matcher; + struct mlx5dr_rule_rx_tx rx; + struct mlx5dr_rule_rx_tx tx; + struct list_head rule_actions_list; + struct list_head dbg_node; + u32 flow_source; +}; + +void mlx5dr_rule_set_last_member(struct mlx5dr_rule_rx_tx *nic_rule, + struct mlx5dr_ste *ste, + bool force); +int mlx5dr_rule_get_reverse_rule_members(struct mlx5dr_ste **ste_arr, + struct mlx5dr_ste *curr_ste, + int *num_of_stes); + +struct mlx5dr_icm_chunk { + struct mlx5dr_icm_buddy_mem *buddy_mem; + + /* indicates the index of this chunk in the whole memory, + * used for deleting the chunk from the buddy + */ + unsigned int seg; + enum mlx5dr_icm_chunk_size size; + + /* Memory optimisation */ + struct mlx5dr_ste *ste_arr; + u8 *hw_ste_arr; + struct list_head *miss_list; +}; + +static inline void mlx5dr_domain_nic_lock(struct mlx5dr_domain_rx_tx *nic_dmn) +{ + mutex_lock(&nic_dmn->mutex); +} + +static inline void mlx5dr_domain_nic_unlock(struct mlx5dr_domain_rx_tx *nic_dmn) +{ + mutex_unlock(&nic_dmn->mutex); +} + +static inline void mlx5dr_domain_lock(struct mlx5dr_domain *dmn) +{ + mlx5dr_domain_nic_lock(&dmn->info.rx); + mlx5dr_domain_nic_lock(&dmn->info.tx); +} + +static inline void mlx5dr_domain_unlock(struct mlx5dr_domain *dmn) +{ + mlx5dr_domain_nic_unlock(&dmn->info.tx); + mlx5dr_domain_nic_unlock(&dmn->info.rx); +} + +int mlx5dr_matcher_add_to_tbl_nic(struct mlx5dr_domain *dmn, + struct mlx5dr_matcher_rx_tx *nic_matcher); +int mlx5dr_matcher_remove_from_tbl_nic(struct mlx5dr_domain *dmn, + struct mlx5dr_matcher_rx_tx *nic_matcher); + +int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher, + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv); + +u64 mlx5dr_icm_pool_get_chunk_mr_addr(struct mlx5dr_icm_chunk *chunk); +u32 mlx5dr_icm_pool_get_chunk_rkey(struct mlx5dr_icm_chunk *chunk); +u64 mlx5dr_icm_pool_get_chunk_icm_addr(struct mlx5dr_icm_chunk *chunk); +u32 mlx5dr_icm_pool_get_chunk_num_of_entries(struct mlx5dr_icm_chunk *chunk); +u32 mlx5dr_icm_pool_get_chunk_byte_size(struct mlx5dr_icm_chunk *chunk); +u8 *mlx5dr_ste_get_hw_ste(struct mlx5dr_ste *ste); + +struct mlx5dr_ste_htbl *mlx5dr_icm_pool_alloc_htbl(struct mlx5dr_icm_pool *pool); +void mlx5dr_icm_pool_free_htbl(struct mlx5dr_icm_pool *pool, struct mlx5dr_ste_htbl *htbl); + +static inline int +mlx5dr_icm_pool_dm_type_to_entry_size(enum mlx5dr_icm_type icm_type) +{ + if (icm_type == DR_ICM_TYPE_STE) + return DR_STE_SIZE; + + return DR_MODIFY_ACTION_SIZE; +} + +static inline u32 +mlx5dr_icm_pool_chunk_size_to_entries(enum mlx5dr_icm_chunk_size chunk_size) +{ + return 1 << chunk_size; +} + +static inline int +mlx5dr_icm_pool_chunk_size_to_byte(enum mlx5dr_icm_chunk_size chunk_size, + enum mlx5dr_icm_type icm_type) +{ + int num_of_entries; + int entry_size; + + entry_size = mlx5dr_icm_pool_dm_type_to_entry_size(icm_type); + num_of_entries = mlx5dr_icm_pool_chunk_size_to_entries(chunk_size); + + return entry_size * num_of_entries; +} + +static inline int +mlx5dr_ste_htbl_increase_threshold(struct mlx5dr_ste_htbl *htbl) +{ + int num_of_entries = + mlx5dr_icm_pool_chunk_size_to_entries(htbl->chunk->size); + + /* Threshold is 50%, one is added to table of size 1 */ + return (num_of_entries + 1) / 2; +} + +static inline bool +mlx5dr_ste_htbl_may_grow(struct mlx5dr_ste_htbl *htbl) +{ + if (htbl->chunk->size == DR_CHUNK_SIZE_MAX - 1 || !htbl->byte_mask) + return false; + + return true; +} + +struct mlx5dr_cmd_vport_cap * +mlx5dr_domain_get_vport_cap(struct mlx5dr_domain *dmn, u16 vport); + +struct mlx5dr_cmd_query_flow_table_details { + u8 status; + u8 level; + u64 sw_owner_icm_root_1; + u64 sw_owner_icm_root_0; +}; + +struct mlx5dr_cmd_create_flow_table_attr { + u32 table_type; + u16 uid; + u64 icm_addr_rx; + u64 icm_addr_tx; + u8 level; + bool sw_owner; + bool term_tbl; + bool decap_en; + bool reformat_en; +}; + +/* internal API functions */ +int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev, + struct mlx5dr_cmd_caps *caps); +int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, + bool other_vport, u16 vport_number, + u64 *icm_address_rx, + u64 *icm_address_tx); +int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, + bool other_vport, u16 vport_number, u16 *gvmi); +int mlx5dr_cmd_query_esw_caps(struct mlx5_core_dev *mdev, + struct mlx5dr_esw_caps *caps); +int mlx5dr_cmd_query_flow_sampler(struct mlx5_core_dev *dev, + u32 sampler_id, + u64 *rx_icm_addr, + u64 *tx_icm_addr); +int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev); +int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id, + u32 group_id, + u32 modify_header_id, + u16 vport_id); +int mlx5dr_cmd_del_flow_table_entry(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id); +int mlx5dr_cmd_alloc_modify_header(struct mlx5_core_dev *mdev, + u32 table_type, + u8 num_of_actions, + u64 *actions, + u32 *modify_header_id); +int mlx5dr_cmd_dealloc_modify_header(struct mlx5_core_dev *mdev, + u32 modify_header_id); +int mlx5dr_cmd_create_empty_flow_group(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id, + u32 *group_id); +int mlx5dr_cmd_destroy_flow_group(struct mlx5_core_dev *mdev, + u32 table_type, + u32 table_id, + u32 group_id); +int mlx5dr_cmd_create_flow_table(struct mlx5_core_dev *mdev, + struct mlx5dr_cmd_create_flow_table_attr *attr, + u64 *fdb_rx_icm_addr, + u32 *table_id); +int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev, + u32 table_id, + u32 table_type); +int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev, + enum fs_flow_table_type type, + u32 table_id, + struct mlx5dr_cmd_query_flow_table_details *output); +int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev, + enum mlx5_reformat_ctx_type rt, + u8 reformat_param_0, + u8 reformat_param_1, + size_t reformat_size, + void *reformat_data, + u32 *reformat_id); +void mlx5dr_cmd_destroy_reformat_ctx(struct mlx5_core_dev *mdev, + u32 reformat_id); +int mlx5dr_cmd_create_definer(struct mlx5_core_dev *mdev, + u16 format_id, + u8 *dw_selectors, + u8 *byte_selectors, + u8 *match_mask, + u32 *definer_id); +void mlx5dr_cmd_destroy_definer(struct mlx5_core_dev *mdev, + u32 definer_id); + +struct mlx5dr_cmd_gid_attr { + u8 gid[16]; + u8 mac[6]; + u32 roce_ver; +}; + +int mlx5dr_cmd_query_gid(struct mlx5_core_dev *mdev, u8 vhca_port_num, + u16 index, struct mlx5dr_cmd_gid_attr *attr); + +int mlx5dr_cmd_create_modify_header_arg(struct mlx5_core_dev *dev, + u16 log_obj_range, u32 pd, + u32 *obj_id); +void mlx5dr_cmd_destroy_modify_header_arg(struct mlx5_core_dev *dev, + u32 obj_id); + +int mlx5dr_definer_get(struct mlx5dr_domain *dmn, u16 format_id, + u8 *dw_selectors, u8 *byte_selectors, + u8 *match_mask, u32 *definer_id); +void mlx5dr_definer_put(struct mlx5dr_domain *dmn, u32 definer_id); + +struct mlx5dr_icm_pool *mlx5dr_icm_pool_create(struct mlx5dr_domain *dmn, + enum mlx5dr_icm_type icm_type); +void mlx5dr_icm_pool_destroy(struct mlx5dr_icm_pool *pool); + +struct mlx5dr_icm_chunk * +mlx5dr_icm_alloc_chunk(struct mlx5dr_icm_pool *pool, + enum mlx5dr_icm_chunk_size chunk_size); +void mlx5dr_icm_free_chunk(struct mlx5dr_icm_chunk *chunk); + +void mlx5dr_ste_prepare_for_postsend(struct mlx5dr_ste_ctx *ste_ctx, + u8 *hw_ste_p, u32 ste_size); +int mlx5dr_ste_htbl_init_and_postsend(struct mlx5dr_domain *dmn, + struct mlx5dr_domain_rx_tx *nic_dmn, + struct mlx5dr_ste_htbl *htbl, + struct mlx5dr_htbl_connect_info *connect_info, + bool update_hw_ste); +void mlx5dr_ste_set_formatted_ste(struct mlx5dr_ste_ctx *ste_ctx, + u16 gvmi, + enum mlx5dr_domain_nic_type nic_type, + struct mlx5dr_ste_htbl *htbl, + u8 *formatted_ste, + struct mlx5dr_htbl_connect_info *connect_info); +void mlx5dr_ste_copy_param(u8 match_criteria, + struct mlx5dr_match_param *set_param, + struct mlx5dr_match_parameters *mask, + bool clear); + +struct mlx5dr_qp { + struct mlx5_core_dev *mdev; + struct mlx5_wq_qp wq; + struct mlx5_uars_page *uar; + struct mlx5_wq_ctrl wq_ctrl; + u32 qpn; + struct { + unsigned int head; + unsigned int pc; + unsigned int cc; + unsigned int size; + unsigned int *wqe_head; + unsigned int wqe_cnt; + } sq; + struct { + unsigned int pc; + unsigned int cc; + unsigned int size; + unsigned int wqe_cnt; + } rq; + int max_inline_data; +}; + +struct mlx5dr_cq { + struct mlx5_core_dev *mdev; + struct mlx5_cqwq wq; + struct mlx5_wq_ctrl wq_ctrl; + struct mlx5_core_cq mcq; + struct mlx5dr_qp *qp; +}; + +struct mlx5dr_mr { + struct mlx5_core_dev *mdev; + u32 mkey; + dma_addr_t dma_addr; + void *addr; + size_t size; +}; + +struct mlx5dr_send_ring { + struct mlx5dr_cq *cq; + struct mlx5dr_qp *qp; + struct mlx5dr_mr *mr; + /* How much wqes are waiting for completion */ + u32 pending_wqe; + /* Signal request per this trash hold value */ + u16 signal_th; + /* Each post_send_size less than max_post_send_size */ + u32 max_post_send_size; + /* manage the send queue */ + u32 tx_head; + void *buf; + u32 buf_size; + u8 *sync_buff; + struct mlx5dr_mr *sync_mr; + spinlock_t lock; /* Protect the data path of the send ring */ + bool err_state; /* send_ring is not usable in err state */ +}; + +int mlx5dr_send_ring_alloc(struct mlx5dr_domain *dmn); +void mlx5dr_send_ring_free(struct mlx5dr_domain *dmn, + struct mlx5dr_send_ring *send_ring); +int mlx5dr_send_ring_force_drain(struct mlx5dr_domain *dmn); +int mlx5dr_send_postsend_ste(struct mlx5dr_domain *dmn, + struct mlx5dr_ste *ste, + u8 *data, + u16 size, + u16 offset); +int mlx5dr_send_postsend_htbl(struct mlx5dr_domain *dmn, + struct mlx5dr_ste_htbl *htbl, + u8 *formatted_ste, u8 *mask); +int mlx5dr_send_postsend_formatted_htbl(struct mlx5dr_domain *dmn, + struct mlx5dr_ste_htbl *htbl, + u8 *ste_init_data, + bool update_hw_ste); +int mlx5dr_send_postsend_action(struct mlx5dr_domain *dmn, + struct mlx5dr_action *action); +int mlx5dr_send_postsend_pattern(struct mlx5dr_domain *dmn, + struct mlx5dr_icm_chunk *chunk, + u16 num_of_actions, + u8 *data); +int mlx5dr_send_postsend_args(struct mlx5dr_domain *dmn, u64 arg_id, + u16 num_of_actions, u8 *actions_data); + +int mlx5dr_send_info_pool_create(struct mlx5dr_domain *dmn); +void mlx5dr_send_info_pool_destroy(struct mlx5dr_domain *dmn); +struct mlx5dr_ste_send_info *mlx5dr_send_info_alloc(struct mlx5dr_domain *dmn, + enum mlx5dr_domain_nic_type nic_type); +void mlx5dr_send_info_free(struct mlx5dr_ste_send_info *ste_send_info); + +struct mlx5dr_cmd_ft_info { + u32 id; + u16 vport; + enum fs_flow_table_type type; +}; + +struct mlx5dr_cmd_flow_destination_hw_info { + enum mlx5_flow_destination_type type; + union { + u32 tir_num; + u32 ft_num; + u32 ft_id; + u32 counter_id; + u32 sampler_id; + struct { + u16 num; + u16 vhca_id; + u32 reformat_id; + u8 flags; + } vport; + }; +}; + +struct mlx5dr_cmd_fte_info { + u32 dests_size; + u32 index; + struct mlx5_flow_context flow_context; + u32 *val; + struct mlx5_flow_act action; + struct mlx5dr_cmd_flow_destination_hw_info *dest_arr; + bool ignore_flow_level; +}; + +int mlx5dr_cmd_set_fte(struct mlx5_core_dev *dev, + int opmod, int modify_mask, + struct mlx5dr_cmd_ft_info *ft, + u32 group_id, + struct mlx5dr_cmd_fte_info *fte); + +bool mlx5dr_ste_supp_ttl_cs_recalc(struct mlx5dr_cmd_caps *caps); + +struct mlx5dr_fw_recalc_cs_ft { + u64 rx_icm_addr; + u32 table_id; + u32 group_id; + u32 modify_hdr_id; +}; + +struct mlx5dr_fw_recalc_cs_ft * +mlx5dr_fw_create_recalc_cs_ft(struct mlx5dr_domain *dmn, u16 vport_num); +void mlx5dr_fw_destroy_recalc_cs_ft(struct mlx5dr_domain *dmn, + struct mlx5dr_fw_recalc_cs_ft *recalc_cs_ft); +int mlx5dr_domain_get_recalc_cs_ft_addr(struct mlx5dr_domain *dmn, + u16 vport_num, + u64 *rx_icm_addr); +int mlx5dr_fw_create_md_tbl(struct mlx5dr_domain *dmn, + struct mlx5dr_cmd_flow_destination_hw_info *dest, + int num_dest, + bool reformat_req, + u32 *tbl_id, + u32 *group_id, + bool ignore_flow_level, + u32 flow_source); +void mlx5dr_fw_destroy_md_tbl(struct mlx5dr_domain *dmn, u32 tbl_id, + u32 group_id); + +static inline bool mlx5dr_is_fw_table(struct mlx5_flow_table *ft) +{ + return !ft->fs_dr_table.dr_table; +} + +static inline bool mlx5dr_supp_match_ranges(struct mlx5_core_dev *dev) +{ + return (MLX5_CAP_GEN(dev, steering_format_version) >= + MLX5_STEERING_FORMAT_CONNECTX_6DX) && + (MLX5_CAP_GEN_64(dev, match_definer_format_supported) & + (1ULL << MLX5_IFC_DEFINER_FORMAT_ID_SELECT)); +} + +bool mlx5dr_domain_is_support_ptrn_arg(struct mlx5dr_domain *dmn); +struct mlx5dr_ptrn_mgr *mlx5dr_ptrn_mgr_create(struct mlx5dr_domain *dmn); +void mlx5dr_ptrn_mgr_destroy(struct mlx5dr_ptrn_mgr *mgr); +struct mlx5dr_ptrn_obj *mlx5dr_ptrn_cache_get_pattern(struct mlx5dr_ptrn_mgr *mgr, + u16 num_of_actions, u8 *data); +void mlx5dr_ptrn_cache_put_pattern(struct mlx5dr_ptrn_mgr *mgr, + struct mlx5dr_ptrn_obj *pattern); +struct mlx5dr_arg_mgr *mlx5dr_arg_mgr_create(struct mlx5dr_domain *dmn); +void mlx5dr_arg_mgr_destroy(struct mlx5dr_arg_mgr *mgr); +struct mlx5dr_arg_obj *mlx5dr_arg_get_obj(struct mlx5dr_arg_mgr *mgr, + u16 num_of_actions, + u8 *data); +void mlx5dr_arg_put_obj(struct mlx5dr_arg_mgr *mgr, + struct mlx5dr_arg_obj *arg_obj); +u32 mlx5dr_arg_get_obj_id(struct mlx5dr_arg_obj *arg_obj); + +#endif /* _DR_TYPES_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.c new file mode 100644 index 00000000000000..4b349d4005e448 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.c @@ -0,0 +1,879 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2019 Mellanox Technologies */ + +#include +#include "mlx5_core.h" +#include "fs_core.h" +#include "fs_cmd.h" +#include "mlx5dr.h" +#include "fs_dr.h" +#include "dr_types.h" + +static int mlx5_cmd_dr_update_root_ft(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + u32 underlay_qpn, + bool disconnect) +{ + return mlx5_fs_cmd_get_fw_cmds()->update_root_ft(ns, ft, underlay_qpn, + disconnect); +} + +static int set_miss_action(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + struct mlx5_flow_table *next_ft) +{ + struct mlx5dr_action *old_miss_action; + struct mlx5dr_action *action = NULL; + struct mlx5dr_table *next_tbl; + int err; + + next_tbl = next_ft ? next_ft->fs_dr_table.dr_table : NULL; + if (next_tbl) { + action = mlx5dr_action_create_dest_table(next_tbl); + if (!action) + return -EINVAL; + } + old_miss_action = ft->fs_dr_table.miss_action; + err = mlx5dr_table_set_miss_action(ft->fs_dr_table.dr_table, action); + if (err && action) { + err = mlx5dr_action_destroy(action); + if (err) + mlx5_core_err(ns->dev, + "Failed to destroy action (%d)\n", err); + action = NULL; + } + ft->fs_dr_table.miss_action = action; + if (old_miss_action) { + err = mlx5dr_action_destroy(old_miss_action); + if (err) + mlx5_core_err(ns->dev, "Failed to destroy action (%d)\n", + err); + } + + return err; +} + +static int mlx5_cmd_dr_create_flow_table(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + struct mlx5_flow_table_attr *ft_attr, + struct mlx5_flow_table *next_ft) +{ + struct mlx5dr_table *tbl; + u32 flags; + int err; + + if (mlx5_fs_cmd_is_fw_term_table(ft)) + return mlx5_fs_cmd_get_fw_cmds()->create_flow_table(ns, ft, + ft_attr, + next_ft); + flags = ft->flags; + /* turn off encap/decap if not supported for sw-str by fw */ + if (!MLX5_CAP_FLOWTABLE(ns->dev, sw_owner_reformat_supported)) + flags = ft->flags & ~(MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | + MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); + + tbl = mlx5dr_table_create(ns->fs_dr_domain.dr_domain, ft->level, flags, + ft_attr->uid); + if (!tbl) { + mlx5_core_err(ns->dev, "Failed creating dr flow_table\n"); + return -EINVAL; + } + + ft->fs_dr_table.dr_table = tbl; + ft->id = mlx5dr_table_get_id(tbl); + + if (next_ft) { + err = set_miss_action(ns, ft, next_ft); + if (err) { + mlx5dr_table_destroy(tbl); + ft->fs_dr_table.dr_table = NULL; + return err; + } + } + + ft->max_fte = INT_MAX; + + return 0; +} + +static int mlx5_cmd_dr_destroy_flow_table(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft) +{ + struct mlx5dr_action *action = ft->fs_dr_table.miss_action; + int err; + + if (mlx5_fs_cmd_is_fw_term_table(ft)) + return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_table(ns, ft); + + err = mlx5dr_table_destroy(ft->fs_dr_table.dr_table); + if (err) { + mlx5_core_err(ns->dev, "Failed to destroy flow_table (%d)\n", + err); + return err; + } + if (action) { + err = mlx5dr_action_destroy(action); + if (err) { + mlx5_core_err(ns->dev, "Failed to destroy action(%d)\n", + err); + return err; + } + } + + return err; +} + +static int mlx5_cmd_dr_modify_flow_table(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + struct mlx5_flow_table *next_ft) +{ + if (mlx5_fs_cmd_is_fw_term_table(ft)) + return mlx5_fs_cmd_get_fw_cmds()->modify_flow_table(ns, ft, next_ft); + + return set_miss_action(ns, ft, next_ft); +} + +static int mlx5_cmd_dr_create_flow_group(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + u32 *in, + struct mlx5_flow_group *fg) +{ + struct mlx5dr_matcher *matcher; + u32 priority = MLX5_GET(create_flow_group_in, in, + start_flow_index); + u8 match_criteria_enable = MLX5_GET(create_flow_group_in, + in, + match_criteria_enable); + struct mlx5dr_match_parameters mask; + + if (mlx5_fs_cmd_is_fw_term_table(ft)) + return mlx5_fs_cmd_get_fw_cmds()->create_flow_group(ns, ft, in, + fg); + + mask.match_buf = MLX5_ADDR_OF(create_flow_group_in, + in, match_criteria); + mask.match_sz = sizeof(fg->mask.match_criteria); + + matcher = mlx5dr_matcher_create(ft->fs_dr_table.dr_table, + priority, + match_criteria_enable, + &mask); + if (!matcher) { + mlx5_core_err(ns->dev, "Failed creating matcher\n"); + return -EINVAL; + } + + fg->fs_dr_matcher.dr_matcher = matcher; + return 0; +} + +static int mlx5_cmd_dr_destroy_flow_group(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + struct mlx5_flow_group *fg) +{ + if (mlx5_fs_cmd_is_fw_term_table(ft)) + return mlx5_fs_cmd_get_fw_cmds()->destroy_flow_group(ns, ft, fg); + + return mlx5dr_matcher_destroy(fg->fs_dr_matcher.dr_matcher); +} + +static struct mlx5dr_action *create_vport_action(struct mlx5dr_domain *domain, + struct mlx5_flow_rule *dst) +{ + struct mlx5_flow_destination *dest_attr = &dst->dest_attr; + + return mlx5dr_action_create_dest_vport(domain, dest_attr->vport.num, + dest_attr->vport.flags & + MLX5_FLOW_DEST_VPORT_VHCA_ID, + dest_attr->vport.vhca_id); +} + +static struct mlx5dr_action *create_uplink_action(struct mlx5dr_domain *domain, + struct mlx5_flow_rule *dst) +{ + struct mlx5_flow_destination *dest_attr = &dst->dest_attr; + + return mlx5dr_action_create_dest_vport(domain, MLX5_VPORT_UPLINK, 1, + dest_attr->vport.vhca_id); +} + +static struct mlx5dr_action *create_ft_action(struct mlx5dr_domain *domain, + struct mlx5_flow_rule *dst) +{ + struct mlx5_flow_table *dest_ft = dst->dest_attr.ft; + struct mlx5dr_action *tbl_action; + + if (mlx5dr_is_fw_table(dest_ft)) + return mlx5dr_action_create_dest_flow_fw_table(domain, dest_ft); + + tbl_action = mlx5dr_action_create_dest_table(dest_ft->fs_dr_table.dr_table); + if (tbl_action) + tbl_action->dest_tbl->is_wire_ft = + dest_ft->flags & MLX5_FLOW_TABLE_UPLINK_VPORT ? 1 : 0; + + return tbl_action; +} + +static struct mlx5dr_action *create_range_action(struct mlx5dr_domain *domain, + struct mlx5_flow_rule *dst) +{ + return mlx5dr_action_create_dest_match_range(domain, + dst->dest_attr.range.field, + dst->dest_attr.range.hit_ft, + dst->dest_attr.range.miss_ft, + dst->dest_attr.range.min, + dst->dest_attr.range.max); +} + +static struct mlx5dr_action *create_action_push_vlan(struct mlx5dr_domain *domain, + struct mlx5_fs_vlan *vlan) +{ + u16 n_ethtype = vlan->ethtype; + u8 prio = vlan->prio; + u16 vid = vlan->vid; + u32 vlan_hdr; + + vlan_hdr = (u32)n_ethtype << 16 | (u32)(prio) << 12 | (u32)vid; + return mlx5dr_action_create_push_vlan(domain, htonl(vlan_hdr)); +} + +static bool contain_vport_reformat_action(struct mlx5_flow_rule *dst) +{ + return (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_VPORT || + dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_UPLINK) && + dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID; +} + +/* We want to support a rule with 32 destinations, which means we need to + * account for 32 destinations plus usually a counter plus one more action + * for a multi-destination flow table. + */ +#define MLX5_FLOW_CONTEXT_ACTION_MAX 34 +static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + struct mlx5_flow_group *group, + struct fs_fte *fte) +{ + struct mlx5dr_domain *domain = ns->fs_dr_domain.dr_domain; + struct mlx5dr_action_dest *term_actions; + struct mlx5_pkt_reformat *pkt_reformat; + struct mlx5dr_match_parameters params; + struct mlx5_core_dev *dev = ns->dev; + struct mlx5dr_action **fs_dr_actions; + struct mlx5dr_action *tmp_action; + struct mlx5dr_action **actions; + bool delay_encap_set = false; + struct mlx5dr_rule *rule; + struct mlx5_flow_rule *dst; + int fs_dr_num_actions = 0; + int num_term_actions = 0; + int num_actions = 0; + size_t match_sz; + int err = 0; + int i; + + if (mlx5_fs_cmd_is_fw_term_table(ft)) + return mlx5_fs_cmd_get_fw_cmds()->create_fte(ns, ft, group, fte); + + actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, sizeof(*actions), + GFP_KERNEL); + if (!actions) { + err = -ENOMEM; + goto out_err; + } + + fs_dr_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, + sizeof(*fs_dr_actions), GFP_KERNEL); + if (!fs_dr_actions) { + err = -ENOMEM; + goto free_actions_alloc; + } + + term_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, + sizeof(*term_actions), GFP_KERNEL); + if (!term_actions) { + err = -ENOMEM; + goto free_fs_dr_actions_alloc; + } + + match_sz = sizeof(fte->val); + + /* Drop reformat action bit if destination vport set with reformat */ + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { + list_for_each_entry(dst, &fte->node.children, node.list) { + if (!contain_vport_reformat_action(dst)) + continue; + + fte->act_dests.action.action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; + break; + } + } + + /* The order of the actions are must to be keep, only the following + * order is supported by SW steering: + * TX: modify header -> push vlan -> encap + * RX: decap -> pop vlan -> modify header + */ + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_DECAP) { + enum mlx5dr_action_reformat_type decap_type = + DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2; + + tmp_action = mlx5dr_action_create_packet_reformat(domain, + decap_type, + 0, 0, 0, + NULL); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT) { + bool is_decap; + + pkt_reformat = fte->act_dests.action.pkt_reformat; + if (pkt_reformat->owner == MLX5_FLOW_RESOURCE_OWNER_FW) { + err = -EINVAL; + mlx5dr_err(domain, "FW-owned reformat can't be used in SW rule\n"); + goto free_actions; + } + + is_decap = pkt_reformat->reformat_type == + MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2; + + if (is_decap) + actions[num_actions++] = + pkt_reformat->fs_dr_action.dr_action; + else + delay_encap_set = true; + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP) { + tmp_action = + mlx5dr_action_create_pop_vlan(); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP_2) { + tmp_action = + mlx5dr_action_create_pop_vlan(); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) { + struct mlx5_modify_hdr *modify_hdr = fte->act_dests.action.modify_hdr; + + actions[num_actions++] = modify_hdr->fs_dr_action.dr_action; + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH) { + tmp_action = create_action_push_vlan(domain, &fte->act_dests.action.vlan[0]); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2) { + tmp_action = create_action_push_vlan(domain, &fte->act_dests.action.vlan[1]); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + + if (delay_encap_set) + actions[num_actions++] = pkt_reformat->fs_dr_action.dr_action; + + /* The order of the actions below is not important */ + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_DROP) { + tmp_action = mlx5dr_action_create_drop(); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + term_actions[num_term_actions++].dest = tmp_action; + } + + if (fte->act_dests.flow_context.flow_tag) { + tmp_action = + mlx5dr_action_create_tag(fte->act_dests.flow_context.flow_tag); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) { + list_for_each_entry(dst, &fte->node.children, node.list) { + enum mlx5_flow_destination_type type = dst->dest_attr.type; + u32 id; + + if (fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || + num_term_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { + err = -EOPNOTSUPP; + goto free_actions; + } + + if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER) + continue; + + switch (type) { + case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE: + tmp_action = create_ft_action(domain, dst); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + term_actions[num_term_actions++].dest = tmp_action; + break; + case MLX5_FLOW_DESTINATION_TYPE_UPLINK: + case MLX5_FLOW_DESTINATION_TYPE_VPORT: + tmp_action = type == MLX5_FLOW_DESTINATION_TYPE_VPORT ? + create_vport_action(domain, dst) : + create_uplink_action(domain, dst); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + term_actions[num_term_actions].dest = tmp_action; + + if (dst->dest_attr.vport.flags & + MLX5_FLOW_DEST_VPORT_REFORMAT_ID) { + pkt_reformat = dst->dest_attr.vport.pkt_reformat; + term_actions[num_term_actions].reformat = + pkt_reformat->fs_dr_action.dr_action; + } + + num_term_actions++; + break; + case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM: + id = dst->dest_attr.ft_num; + tmp_action = mlx5dr_action_create_dest_table_num(domain, + id); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + term_actions[num_term_actions++].dest = tmp_action; + break; + case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER: + id = dst->dest_attr.sampler_id; + tmp_action = mlx5dr_action_create_flow_sampler(domain, + id); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + term_actions[num_term_actions++].dest = tmp_action; + break; + case MLX5_FLOW_DESTINATION_TYPE_RANGE: + tmp_action = create_range_action(domain, dst); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + term_actions[num_term_actions++].dest = tmp_action; + break; + default: + err = -EOPNOTSUPP; + goto free_actions; + } + } + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) { + list_for_each_entry(dst, &fte->node.children, node.list) { + u32 id; + + if (dst->dest_attr.type != + MLX5_FLOW_DESTINATION_TYPE_COUNTER) + continue; + + if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || + fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { + err = -EOPNOTSUPP; + goto free_actions; + } + + id = dst->dest_attr.counter_id; + tmp_action = + mlx5dr_action_create_flow_counter(id); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + } + + if (fte->act_dests.action.action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) { + struct mlx5_flow_act *action = &fte->act_dests.action; + + if (fte->act_dests.action.exe_aso.type != MLX5_EXE_ASO_FLOW_METER) { + err = -EOPNOTSUPP; + goto free_actions; + } + + tmp_action = + mlx5dr_action_create_aso(domain, + action->exe_aso.object_id, + action->exe_aso.return_reg_id, + action->exe_aso.type, + action->exe_aso.flow_meter.init_color, + action->exe_aso.flow_meter.meter_idx); + if (!tmp_action) { + err = -ENOMEM; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + + params.match_sz = match_sz; + params.match_buf = (u64 *)fte->val; + if (num_term_actions == 1) { + if (term_actions->reformat) { + if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { + err = -EOPNOTSUPP; + goto free_actions; + } + actions[num_actions++] = term_actions->reformat; + } + + if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { + err = -EOPNOTSUPP; + goto free_actions; + } + actions[num_actions++] = term_actions->dest; + } else if (num_term_actions > 1) { + bool ignore_flow_level = + !!(fte->act_dests.action.flags & FLOW_ACT_IGNORE_FLOW_LEVEL); + u32 flow_source = fte->act_dests.flow_context.flow_source; + + if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX || + fs_dr_num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) { + err = -EOPNOTSUPP; + goto free_actions; + } + tmp_action = mlx5dr_action_create_mult_dest_tbl(domain, + term_actions, + num_term_actions, + ignore_flow_level, + flow_source); + if (!tmp_action) { + err = -EOPNOTSUPP; + goto free_actions; + } + fs_dr_actions[fs_dr_num_actions++] = tmp_action; + actions[num_actions++] = tmp_action; + } + + rule = mlx5dr_rule_create(group->fs_dr_matcher.dr_matcher, + ¶ms, + num_actions, + actions, + fte->act_dests.flow_context.flow_source); + if (!rule) { + err = -EINVAL; + goto free_actions; + } + + kfree(term_actions); + kfree(actions); + + fte->fs_dr_rule.dr_rule = rule; + fte->fs_dr_rule.num_actions = fs_dr_num_actions; + fte->fs_dr_rule.dr_actions = fs_dr_actions; + + return 0; + +free_actions: + /* Free in reverse order to handle action dependencies */ + for (i = fs_dr_num_actions - 1; i >= 0; i--) + if (!IS_ERR_OR_NULL(fs_dr_actions[i])) + mlx5dr_action_destroy(fs_dr_actions[i]); + + kfree(term_actions); +free_fs_dr_actions_alloc: + kfree(fs_dr_actions); +free_actions_alloc: + kfree(actions); +out_err: + mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err); + return err; +} + +static int mlx5_cmd_dr_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns, + struct mlx5_pkt_reformat_params *params, + enum mlx5_flow_namespace_type namespace, + struct mlx5_pkt_reformat *pkt_reformat) +{ + struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain; + struct mlx5dr_action *action; + int dr_reformat; + + switch (params->type) { + case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: + case MLX5_REFORMAT_TYPE_L2_TO_NVGRE: + case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL: + dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2; + break; + case MLX5_REFORMAT_TYPE_L3_TUNNEL_TO_L2: + dr_reformat = DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2; + break; + case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL: + dr_reformat = DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3; + break; + case MLX5_REFORMAT_TYPE_INSERT_HDR: + dr_reformat = DR_ACTION_REFORMAT_TYP_INSERT_HDR; + break; + case MLX5_REFORMAT_TYPE_REMOVE_HDR: + dr_reformat = DR_ACTION_REFORMAT_TYP_REMOVE_HDR; + break; + default: + mlx5_core_err(ns->dev, "Packet-reformat not supported(%d)\n", + params->type); + return -EOPNOTSUPP; + } + + action = mlx5dr_action_create_packet_reformat(dr_domain, + dr_reformat, + params->param_0, + params->param_1, + params->size, + params->data); + if (!action) { + mlx5_core_err(ns->dev, "Failed allocating packet-reformat action\n"); + return -EINVAL; + } + + pkt_reformat->owner = MLX5_FLOW_RESOURCE_OWNER_SW; + pkt_reformat->fs_dr_action.dr_action = action; + + return 0; +} + +static void mlx5_cmd_dr_packet_reformat_dealloc(struct mlx5_flow_root_namespace *ns, + struct mlx5_pkt_reformat *pkt_reformat) +{ + mlx5dr_action_destroy(pkt_reformat->fs_dr_action.dr_action); +} + +static int mlx5_cmd_dr_modify_header_alloc(struct mlx5_flow_root_namespace *ns, + u8 namespace, u8 num_actions, + void *modify_actions, + struct mlx5_modify_hdr *modify_hdr) +{ + struct mlx5dr_domain *dr_domain = ns->fs_dr_domain.dr_domain; + struct mlx5dr_action *action; + size_t actions_sz; + + actions_sz = MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) * + num_actions; + action = mlx5dr_action_create_modify_header(dr_domain, 0, + actions_sz, + modify_actions); + if (!action) { + mlx5_core_err(ns->dev, "Failed allocating modify-header action\n"); + return -EINVAL; + } + + modify_hdr->owner = MLX5_FLOW_RESOURCE_OWNER_SW; + modify_hdr->fs_dr_action.dr_action = action; + + return 0; +} + +static void mlx5_cmd_dr_modify_header_dealloc(struct mlx5_flow_root_namespace *ns, + struct mlx5_modify_hdr *modify_hdr) +{ + mlx5dr_action_destroy(modify_hdr->fs_dr_action.dr_action); +} + +static int +mlx5_cmd_dr_destroy_match_definer(struct mlx5_flow_root_namespace *ns, + int definer_id) +{ + return -EOPNOTSUPP; +} + +static int mlx5_cmd_dr_create_match_definer(struct mlx5_flow_root_namespace *ns, + u16 format_id, u32 *match_mask) +{ + return -EOPNOTSUPP; +} + +static int mlx5_cmd_dr_delete_fte(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + struct fs_fte *fte) +{ + struct mlx5_fs_dr_rule *rule = &fte->fs_dr_rule; + int err; + int i; + + if (mlx5_fs_cmd_is_fw_term_table(ft)) + return mlx5_fs_cmd_get_fw_cmds()->delete_fte(ns, ft, fte); + + err = mlx5dr_rule_destroy(rule->dr_rule); + if (err) + return err; + + /* Free in reverse order to handle action dependencies */ + for (i = rule->num_actions - 1; i >= 0; i--) + if (!IS_ERR_OR_NULL(rule->dr_actions[i])) + mlx5dr_action_destroy(rule->dr_actions[i]); + + kfree(rule->dr_actions); + return 0; +} + +static int mlx5_cmd_dr_update_fte(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_table *ft, + struct mlx5_flow_group *group, + int modify_mask, + struct fs_fte *fte) +{ + struct fs_fte fte_tmp = {}; + int ret; + + if (mlx5_fs_cmd_is_fw_term_table(ft)) + return mlx5_fs_cmd_get_fw_cmds()->update_fte(ns, ft, group, modify_mask, fte); + + /* Backup current dr rule details */ + fte_tmp.fs_dr_rule = fte->fs_dr_rule; + memset(&fte->fs_dr_rule, 0, sizeof(struct mlx5_fs_dr_rule)); + + /* First add the new updated rule, then delete the old rule */ + ret = mlx5_cmd_dr_create_fte(ns, ft, group, fte); + if (ret) + goto restore_fte; + + ret = mlx5_cmd_dr_delete_fte(ns, ft, &fte_tmp); + WARN_ONCE(ret, "dr update fte duplicate rule deletion failed\n"); + return ret; + +restore_fte: + fte->fs_dr_rule = fte_tmp.fs_dr_rule; + return ret; +} + +static int mlx5_cmd_dr_set_peer(struct mlx5_flow_root_namespace *ns, + struct mlx5_flow_root_namespace *peer_ns, + u16 peer_vhca_id) +{ + struct mlx5dr_domain *peer_domain = NULL; + + if (peer_ns) + peer_domain = peer_ns->fs_dr_domain.dr_domain; + mlx5dr_domain_set_peer(ns->fs_dr_domain.dr_domain, + peer_domain, peer_vhca_id); + return 0; +} + +static int mlx5_cmd_dr_create_ns(struct mlx5_flow_root_namespace *ns) +{ + ns->fs_dr_domain.dr_domain = + mlx5dr_domain_create(ns->dev, + MLX5DR_DOMAIN_TYPE_FDB); + if (!ns->fs_dr_domain.dr_domain) { + mlx5_core_err(ns->dev, "Failed to create dr flow namespace\n"); + return -EOPNOTSUPP; + } + return 0; +} + +static int mlx5_cmd_dr_destroy_ns(struct mlx5_flow_root_namespace *ns) +{ + return mlx5dr_domain_destroy(ns->fs_dr_domain.dr_domain); +} + +static u32 mlx5_cmd_dr_get_capabilities(struct mlx5_flow_root_namespace *ns, + enum fs_flow_table_type ft_type) +{ + u32 steering_caps = MLX5_FLOW_STEERING_CAP_DUPLICATE_MATCH; + + if (ft_type != FS_FT_FDB || + MLX5_CAP_GEN(ns->dev, steering_format_version) == MLX5_STEERING_FORMAT_CONNECTX_5) + return steering_caps; + + steering_caps |= MLX5_FLOW_STEERING_CAP_VLAN_PUSH_ON_RX; + steering_caps |= MLX5_FLOW_STEERING_CAP_VLAN_POP_ON_TX; + + if (mlx5dr_supp_match_ranges(ns->dev)) + steering_caps |= MLX5_FLOW_STEERING_CAP_MATCH_RANGES; + + return steering_caps; +} + +int mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat) +{ + switch (pkt_reformat->reformat_type) { + case MLX5_REFORMAT_TYPE_L2_TO_VXLAN: + case MLX5_REFORMAT_TYPE_L2_TO_NVGRE: + case MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL: + case MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL: + case MLX5_REFORMAT_TYPE_INSERT_HDR: + return mlx5dr_action_get_pkt_reformat_id(pkt_reformat->fs_dr_action.dr_action); + } + return -EOPNOTSUPP; +} + +bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev) +{ + return mlx5dr_is_supported(dev); +} + +static const struct mlx5_flow_cmds mlx5_flow_cmds_dr = { + .create_flow_table = mlx5_cmd_dr_create_flow_table, + .destroy_flow_table = mlx5_cmd_dr_destroy_flow_table, + .modify_flow_table = mlx5_cmd_dr_modify_flow_table, + .create_flow_group = mlx5_cmd_dr_create_flow_group, + .destroy_flow_group = mlx5_cmd_dr_destroy_flow_group, + .create_fte = mlx5_cmd_dr_create_fte, + .update_fte = mlx5_cmd_dr_update_fte, + .delete_fte = mlx5_cmd_dr_delete_fte, + .update_root_ft = mlx5_cmd_dr_update_root_ft, + .packet_reformat_alloc = mlx5_cmd_dr_packet_reformat_alloc, + .packet_reformat_dealloc = mlx5_cmd_dr_packet_reformat_dealloc, + .modify_header_alloc = mlx5_cmd_dr_modify_header_alloc, + .modify_header_dealloc = mlx5_cmd_dr_modify_header_dealloc, + .create_match_definer = mlx5_cmd_dr_create_match_definer, + .destroy_match_definer = mlx5_cmd_dr_destroy_match_definer, + .set_peer = mlx5_cmd_dr_set_peer, + .create_ns = mlx5_cmd_dr_create_ns, + .destroy_ns = mlx5_cmd_dr_destroy_ns, + .get_capabilities = mlx5_cmd_dr_get_capabilities, +}; + +const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void) +{ + return &mlx5_flow_cmds_dr; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.h new file mode 100644 index 00000000000000..99a3b2eff6b8fd --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/fs_dr.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB + * Copyright (c) 2019 Mellanox Technologies + */ + +#ifndef _MLX5_FS_DR_ +#define _MLX5_FS_DR_ + +#include "mlx5dr.h" + +struct mlx5_flow_root_namespace; +struct fs_fte; + +struct mlx5_fs_dr_action { + struct mlx5dr_action *dr_action; +}; + +struct mlx5_fs_dr_rule { + struct mlx5dr_rule *dr_rule; + /* Only actions created by fs_dr */ + struct mlx5dr_action **dr_actions; + int num_actions; +}; + +struct mlx5_fs_dr_domain { + struct mlx5dr_domain *dr_domain; +}; + +struct mlx5_fs_dr_matcher { + struct mlx5dr_matcher *dr_matcher; +}; + +struct mlx5_fs_dr_table { + struct mlx5dr_table *dr_table; + struct mlx5dr_action *miss_action; +}; + +#ifdef CONFIG_MLX5_SW_STEERING + +bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev); + +int mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat); + +const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void); + +#else + +static inline const struct mlx5_flow_cmds *mlx5_fs_cmd_get_dr_cmds(void) +{ + return NULL; +} + +static inline u32 mlx5_fs_dr_action_get_pkt_reformat_id(struct mlx5_pkt_reformat *pkt_reformat) +{ + return 0; +} + +static inline bool mlx5_fs_dr_is_supported(struct mlx5_core_dev *dev) +{ + return false; +} + +#endif /* CONFIG_MLX5_SW_STEERING */ +#endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr.h new file mode 100644 index 00000000000000..fb078fa0f0cc83 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr.h @@ -0,0 +1,603 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2019, Mellanox Technologies */ + +#ifndef MLX5_IFC_DR_H +#define MLX5_IFC_DR_H + +enum { + MLX5DR_STE_LU_TYPE_DONT_CARE = 0x0f, +}; + +struct mlx5_ifc_ste_general_bits { + u8 entry_type[0x4]; + u8 reserved_at_4[0x4]; + u8 entry_sub_type[0x8]; + u8 byte_mask[0x10]; + + u8 next_table_base_63_48[0x10]; + u8 next_lu_type[0x8]; + u8 next_table_base_39_32_size[0x8]; + + u8 next_table_base_31_5_size[0x1b]; + u8 linear_hash_enable[0x1]; + u8 reserved_at_5c[0x2]; + u8 next_table_rank[0x2]; + + u8 reserved_at_60[0xa0]; + u8 tag_value[0x60]; + u8 bit_mask[0x60]; +}; + +struct mlx5_ifc_ste_sx_transmit_bits { + u8 entry_type[0x4]; + u8 reserved_at_4[0x4]; + u8 entry_sub_type[0x8]; + u8 byte_mask[0x10]; + + u8 next_table_base_63_48[0x10]; + u8 next_lu_type[0x8]; + u8 next_table_base_39_32_size[0x8]; + + u8 next_table_base_31_5_size[0x1b]; + u8 linear_hash_enable[0x1]; + u8 reserved_at_5c[0x2]; + u8 next_table_rank[0x2]; + + u8 sx_wire[0x1]; + u8 sx_func_lb[0x1]; + u8 sx_sniffer[0x1]; + u8 sx_wire_enable[0x1]; + u8 sx_func_lb_enable[0x1]; + u8 sx_sniffer_enable[0x1]; + u8 action_type[0x3]; + u8 reserved_at_69[0x1]; + u8 action_description[0x6]; + u8 gvmi[0x10]; + + u8 encap_pointer_vlan_data[0x20]; + + u8 loopback_syndome_en[0x8]; + u8 loopback_syndome[0x8]; + u8 counter_trigger[0x10]; + + u8 miss_address_63_48[0x10]; + u8 counter_trigger_23_16[0x8]; + u8 miss_address_39_32[0x8]; + + u8 miss_address_31_6[0x1a]; + u8 learning_point[0x1]; + u8 go_back[0x1]; + u8 match_polarity[0x1]; + u8 mask_mode[0x1]; + u8 miss_rank[0x2]; +}; + +struct mlx5_ifc_ste_rx_steering_mult_bits { + u8 entry_type[0x4]; + u8 reserved_at_4[0x4]; + u8 entry_sub_type[0x8]; + u8 byte_mask[0x10]; + + u8 next_table_base_63_48[0x10]; + u8 next_lu_type[0x8]; + u8 next_table_base_39_32_size[0x8]; + + u8 next_table_base_31_5_size[0x1b]; + u8 linear_hash_enable[0x1]; + u8 reserved_at_[0x2]; + u8 next_table_rank[0x2]; + + u8 member_count[0x10]; + u8 gvmi[0x10]; + + u8 qp_list_pointer[0x20]; + + u8 reserved_at_a0[0x1]; + u8 tunneling_action[0x3]; + u8 action_description[0x4]; + u8 reserved_at_a8[0x8]; + u8 counter_trigger_15_0[0x10]; + + u8 miss_address_63_48[0x10]; + u8 counter_trigger_23_16[0x08]; + u8 miss_address_39_32[0x8]; + + u8 miss_address_31_6[0x1a]; + u8 learning_point[0x1]; + u8 fail_on_error[0x1]; + u8 match_polarity[0x1]; + u8 mask_mode[0x1]; + u8 miss_rank[0x2]; +}; + +struct mlx5_ifc_ste_modify_packet_bits { + u8 entry_type[0x4]; + u8 reserved_at_4[0x4]; + u8 entry_sub_type[0x8]; + u8 byte_mask[0x10]; + + u8 next_table_base_63_48[0x10]; + u8 next_lu_type[0x8]; + u8 next_table_base_39_32_size[0x8]; + + u8 next_table_base_31_5_size[0x1b]; + u8 linear_hash_enable[0x1]; + u8 reserved_at_[0x2]; + u8 next_table_rank[0x2]; + + u8 number_of_re_write_actions[0x10]; + u8 gvmi[0x10]; + + u8 header_re_write_actions_pointer[0x20]; + + u8 reserved_at_a0[0x1]; + u8 tunneling_action[0x3]; + u8 action_description[0x4]; + u8 reserved_at_a8[0x8]; + u8 counter_trigger_15_0[0x10]; + + u8 miss_address_63_48[0x10]; + u8 counter_trigger_23_16[0x08]; + u8 miss_address_39_32[0x8]; + + u8 miss_address_31_6[0x1a]; + u8 learning_point[0x1]; + u8 fail_on_error[0x1]; + u8 match_polarity[0x1]; + u8 mask_mode[0x1]; + u8 miss_rank[0x2]; +}; + +struct mlx5_ifc_ste_eth_l2_src_bits { + u8 smac_47_16[0x20]; + + u8 smac_15_0[0x10]; + u8 l3_ethertype[0x10]; + + u8 qp_type[0x2]; + u8 ethertype_filter[0x1]; + u8 reserved_at_43[0x1]; + u8 sx_sniffer[0x1]; + u8 force_lb[0x1]; + u8 functional_lb[0x1]; + u8 port[0x1]; + u8 reserved_at_48[0x4]; + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 first_vlan_qualifier[0x2]; + u8 reserved_at_52[0x2]; + u8 first_vlan_id[0xc]; + + u8 ip_fragmented[0x1]; + u8 tcp_syn[0x1]; + u8 encp_type[0x2]; + u8 l3_type[0x2]; + u8 l4_type[0x2]; + u8 reserved_at_68[0x4]; + u8 second_priority[0x3]; + u8 second_cfi[0x1]; + u8 second_vlan_qualifier[0x2]; + u8 reserved_at_72[0x2]; + u8 second_vlan_id[0xc]; +}; + +struct mlx5_ifc_ste_eth_l2_dst_bits { + u8 dmac_47_16[0x20]; + + u8 dmac_15_0[0x10]; + u8 l3_ethertype[0x10]; + + u8 qp_type[0x2]; + u8 ethertype_filter[0x1]; + u8 reserved_at_43[0x1]; + u8 sx_sniffer[0x1]; + u8 force_lb[0x1]; + u8 functional_lb[0x1]; + u8 port[0x1]; + u8 reserved_at_48[0x4]; + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 first_vlan_qualifier[0x2]; + u8 reserved_at_52[0x2]; + u8 first_vlan_id[0xc]; + + u8 ip_fragmented[0x1]; + u8 tcp_syn[0x1]; + u8 encp_type[0x2]; + u8 l3_type[0x2]; + u8 l4_type[0x2]; + u8 reserved_at_68[0x4]; + u8 second_priority[0x3]; + u8 second_cfi[0x1]; + u8 second_vlan_qualifier[0x2]; + u8 reserved_at_72[0x2]; + u8 second_vlan_id[0xc]; +}; + +struct mlx5_ifc_ste_eth_l2_src_dst_bits { + u8 dmac_47_16[0x20]; + + u8 dmac_15_0[0x10]; + u8 smac_47_32[0x10]; + + u8 smac_31_0[0x20]; + + u8 sx_sniffer[0x1]; + u8 force_lb[0x1]; + u8 functional_lb[0x1]; + u8 port[0x1]; + u8 l3_type[0x2]; + u8 reserved_at_66[0x6]; + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 first_vlan_qualifier[0x2]; + u8 reserved_at_72[0x2]; + u8 first_vlan_id[0xc]; +}; + +struct mlx5_ifc_ste_eth_l3_ipv4_5_tuple_bits { + u8 destination_address[0x20]; + + u8 source_address[0x20]; + + u8 source_port[0x10]; + u8 destination_port[0x10]; + + u8 fragmented[0x1]; + u8 first_fragment[0x1]; + u8 reserved_at_62[0x2]; + u8 reserved_at_64[0x1]; + u8 ecn[0x2]; + u8 tcp_ns[0x1]; + u8 tcp_cwr[0x1]; + u8 tcp_ece[0x1]; + u8 tcp_urg[0x1]; + u8 tcp_ack[0x1]; + u8 tcp_psh[0x1]; + u8 tcp_rst[0x1]; + u8 tcp_syn[0x1]; + u8 tcp_fin[0x1]; + u8 dscp[0x6]; + u8 reserved_at_76[0x2]; + u8 protocol[0x8]; +}; + +struct mlx5_ifc_ste_eth_l3_ipv6_dst_bits { + u8 dst_ip_127_96[0x20]; + + u8 dst_ip_95_64[0x20]; + + u8 dst_ip_63_32[0x20]; + + u8 dst_ip_31_0[0x20]; +}; + +struct mlx5_ifc_ste_eth_l2_tnl_bits { + u8 dmac_47_16[0x20]; + + u8 dmac_15_0[0x10]; + u8 l3_ethertype[0x10]; + + u8 l2_tunneling_network_id[0x20]; + + u8 ip_fragmented[0x1]; + u8 tcp_syn[0x1]; + u8 encp_type[0x2]; + u8 l3_type[0x2]; + u8 l4_type[0x2]; + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 reserved_at_6c[0x3]; + u8 gre_key_flag[0x1]; + u8 first_vlan_qualifier[0x2]; + u8 reserved_at_72[0x2]; + u8 first_vlan_id[0xc]; +}; + +struct mlx5_ifc_ste_eth_l3_ipv6_src_bits { + u8 src_ip_127_96[0x20]; + + u8 src_ip_95_64[0x20]; + + u8 src_ip_63_32[0x20]; + + u8 src_ip_31_0[0x20]; +}; + +struct mlx5_ifc_ste_eth_l3_ipv4_misc_bits { + u8 version[0x4]; + u8 ihl[0x4]; + u8 reserved_at_8[0x8]; + u8 total_length[0x10]; + + u8 identification[0x10]; + u8 flags[0x3]; + u8 fragment_offset[0xd]; + + u8 time_to_live[0x8]; + u8 reserved_at_48[0x8]; + u8 checksum[0x10]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_ste_eth_l4_bits { + u8 fragmented[0x1]; + u8 first_fragment[0x1]; + u8 reserved_at_2[0x6]; + u8 protocol[0x8]; + u8 dst_port[0x10]; + + u8 ipv6_version[0x4]; + u8 reserved_at_24[0x1]; + u8 ecn[0x2]; + u8 tcp_ns[0x1]; + u8 tcp_cwr[0x1]; + u8 tcp_ece[0x1]; + u8 tcp_urg[0x1]; + u8 tcp_ack[0x1]; + u8 tcp_psh[0x1]; + u8 tcp_rst[0x1]; + u8 tcp_syn[0x1]; + u8 tcp_fin[0x1]; + u8 src_port[0x10]; + + u8 ipv6_payload_length[0x10]; + u8 ipv6_hop_limit[0x8]; + u8 dscp[0x6]; + u8 reserved_at_5e[0x2]; + + u8 tcp_data_offset[0x4]; + u8 reserved_at_64[0x8]; + u8 flow_label[0x14]; +}; + +struct mlx5_ifc_ste_eth_l4_misc_bits { + u8 checksum[0x10]; + u8 length[0x10]; + + u8 seq_num[0x20]; + + u8 ack_num[0x20]; + + u8 urgent_pointer[0x10]; + u8 window_size[0x10]; +}; + +struct mlx5_ifc_ste_mpls_bits { + u8 mpls0_label[0x14]; + u8 mpls0_exp[0x3]; + u8 mpls0_s_bos[0x1]; + u8 mpls0_ttl[0x8]; + + u8 mpls1_label[0x20]; + + u8 mpls2_label[0x20]; + + u8 reserved_at_60[0x16]; + u8 mpls4_s_bit[0x1]; + u8 mpls4_qualifier[0x1]; + u8 mpls3_s_bit[0x1]; + u8 mpls3_qualifier[0x1]; + u8 mpls2_s_bit[0x1]; + u8 mpls2_qualifier[0x1]; + u8 mpls1_s_bit[0x1]; + u8 mpls1_qualifier[0x1]; + u8 mpls0_s_bit[0x1]; + u8 mpls0_qualifier[0x1]; +}; + +struct mlx5_ifc_ste_register_0_bits { + u8 register_0_h[0x20]; + + u8 register_0_l[0x20]; + + u8 register_1_h[0x20]; + + u8 register_1_l[0x20]; +}; + +struct mlx5_ifc_ste_register_1_bits { + u8 register_2_h[0x20]; + + u8 register_2_l[0x20]; + + u8 register_3_h[0x20]; + + u8 register_3_l[0x20]; +}; + +struct mlx5_ifc_ste_gre_bits { + u8 gre_c_present[0x1]; + u8 reserved_at_30[0x1]; + u8 gre_k_present[0x1]; + u8 gre_s_present[0x1]; + u8 strict_src_route[0x1]; + u8 recur[0x3]; + u8 flags[0x5]; + u8 version[0x3]; + u8 gre_protocol[0x10]; + + u8 checksum[0x10]; + u8 offset[0x10]; + + u8 gre_key_h[0x18]; + u8 gre_key_l[0x8]; + + u8 seq_num[0x20]; +}; + +struct mlx5_ifc_ste_flex_parser_0_bits { + u8 flex_parser_3[0x20]; + + u8 flex_parser_2[0x20]; + + u8 flex_parser_1[0x20]; + + u8 flex_parser_0[0x20]; +}; + +struct mlx5_ifc_ste_flex_parser_1_bits { + u8 flex_parser_7[0x20]; + + u8 flex_parser_6[0x20]; + + u8 flex_parser_5[0x20]; + + u8 flex_parser_4[0x20]; +}; + +struct mlx5_ifc_ste_flex_parser_ok_bits { + u8 flex_parser_3[0x20]; + u8 flex_parser_2[0x20]; + u8 flex_parsers_ok[0x8]; + u8 reserved_at_48[0x18]; + u8 flex_parser_0[0x20]; +}; + +struct mlx5_ifc_ste_flex_parser_tnl_bits { + u8 flex_parser_tunneling_header_63_32[0x20]; + + u8 flex_parser_tunneling_header_31_0[0x20]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_ste_flex_parser_tnl_vxlan_gpe_bits { + u8 outer_vxlan_gpe_flags[0x8]; + u8 reserved_at_8[0x10]; + u8 outer_vxlan_gpe_next_protocol[0x8]; + + u8 outer_vxlan_gpe_vni[0x18]; + u8 reserved_at_38[0x8]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_ste_flex_parser_tnl_geneve_bits { + u8 reserved_at_0[0x2]; + u8 geneve_opt_len[0x6]; + u8 geneve_oam[0x1]; + u8 reserved_at_9[0x7]; + u8 geneve_protocol_type[0x10]; + + u8 geneve_vni[0x18]; + u8 reserved_at_38[0x8]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_ste_flex_parser_tnl_gtpu_bits { + u8 reserved_at_0[0x5]; + u8 gtpu_msg_flags[0x3]; + u8 gtpu_msg_type[0x8]; + u8 reserved_at_10[0x10]; + + u8 gtpu_teid[0x20]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_ste_tunnel_header_bits { + u8 tunnel_header_0[0x20]; + + u8 tunnel_header_1[0x20]; + + u8 reserved_at_40[0x40]; +}; + +struct mlx5_ifc_ste_general_purpose_bits { + u8 general_purpose_lookup_field[0x20]; + + u8 reserved_at_20[0x20]; + + u8 reserved_at_40[0x20]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_ste_src_gvmi_qp_bits { + u8 loopback_syndrome[0x8]; + u8 reserved_at_8[0x8]; + u8 source_gvmi[0x10]; + + u8 reserved_at_20[0x5]; + u8 force_lb[0x1]; + u8 functional_lb[0x1]; + u8 source_is_requestor[0x1]; + u8 source_qp[0x18]; + + u8 reserved_at_40[0x20]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_l2_hdr_bits { + u8 dmac_47_16[0x20]; + + u8 dmac_15_0[0x10]; + u8 smac_47_32[0x10]; + + u8 smac_31_0[0x20]; + + u8 ethertype[0x10]; + u8 vlan_type[0x10]; + + u8 vlan[0x10]; + u8 reserved_at_90[0x10]; +}; + +/* Both HW set and HW add share the same HW format with different opcodes */ +struct mlx5_ifc_dr_action_hw_set_bits { + u8 opcode[0x8]; + u8 destination_field_code[0x8]; + u8 reserved_at_10[0x2]; + u8 destination_left_shifter[0x6]; + u8 reserved_at_18[0x3]; + u8 destination_length[0x5]; + + u8 inline_data[0x20]; +}; + +struct mlx5_ifc_dr_action_hw_copy_bits { + u8 opcode[0x8]; + u8 destination_field_code[0x8]; + u8 reserved_at_10[0x2]; + u8 destination_left_shifter[0x6]; + u8 reserved_at_18[0x2]; + u8 destination_length[0x6]; + + u8 reserved_at_20[0x8]; + u8 source_field_code[0x8]; + u8 reserved_at_30[0x2]; + u8 source_left_shifter[0x6]; + u8 reserved_at_38[0x8]; +}; + +enum { + MLX5DR_ASO_FLOW_METER_NUM_PER_OBJ = 2, +}; + +struct mlx5_ifc_ste_aso_flow_meter_action_bits { + u8 reserved_at_0[0xc]; + u8 action[0x1]; + u8 initial_color[0x2]; + u8 line_id[0x1]; +}; + +struct mlx5_ifc_ste_double_action_aso_v1_bits { + u8 action_id[0x8]; + u8 aso_context_number[0x18]; + + u8 dest_reg_id[0x2]; + u8 change_ordering_tag[0x1]; + u8 aso_check_ordering[0x1]; + u8 aso_context_type[0x4]; + u8 reserved_at_28[0x8]; + union { + u8 aso_fields[0x10]; + struct mlx5_ifc_ste_aso_flow_meter_action_bits flow_meter; + }; +}; + +#endif /* MLX5_IFC_DR_H */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr_ste_v1.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr_ste_v1.h new file mode 100644 index 00000000000000..ca3b0f1453a72a --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5_ifc_dr_ste_v1.h @@ -0,0 +1,469 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. */ + +#ifndef MLX5_IFC_DR_STE_V1_H +#define MLX5_IFC_DR_STE_V1_H + +enum mlx5_ifc_ste_v1_modify_hdr_offset { + MLX5_MODIFY_HEADER_V1_QW_OFFSET = 0x20, +}; + +struct mlx5_ifc_ste_single_action_flow_tag_v1_bits { + u8 action_id[0x8]; + u8 flow_tag[0x18]; +}; + +struct mlx5_ifc_ste_single_action_modify_list_v1_bits { + u8 action_id[0x8]; + u8 num_of_modify_actions[0x8]; + u8 modify_actions_ptr[0x10]; +}; + +struct mlx5_ifc_ste_single_action_remove_header_v1_bits { + u8 action_id[0x8]; + u8 reserved_at_8[0x2]; + u8 start_anchor[0x6]; + u8 reserved_at_10[0x2]; + u8 end_anchor[0x6]; + u8 reserved_at_18[0x4]; + u8 decap[0x1]; + u8 vni_to_cqe[0x1]; + u8 qos_profile[0x2]; +}; + +struct mlx5_ifc_ste_single_action_remove_header_size_v1_bits { + u8 action_id[0x8]; + u8 reserved_at_8[0x2]; + u8 start_anchor[0x6]; + u8 outer_l4_remove[0x1]; + u8 reserved_at_11[0x1]; + u8 start_offset[0x7]; + u8 reserved_at_18[0x1]; + u8 remove_size[0x6]; +}; + +struct mlx5_ifc_ste_double_action_copy_v1_bits { + u8 action_id[0x8]; + u8 destination_dw_offset[0x8]; + u8 reserved_at_10[0x2]; + u8 destination_left_shifter[0x6]; + u8 reserved_at_17[0x2]; + u8 destination_length[0x6]; + + u8 reserved_at_20[0x8]; + u8 source_dw_offset[0x8]; + u8 reserved_at_30[0x2]; + u8 source_right_shifter[0x6]; + u8 reserved_at_38[0x8]; +}; + +struct mlx5_ifc_ste_double_action_set_v1_bits { + u8 action_id[0x8]; + u8 destination_dw_offset[0x8]; + u8 reserved_at_10[0x2]; + u8 destination_left_shifter[0x6]; + u8 reserved_at_18[0x2]; + u8 destination_length[0x6]; + + u8 inline_data[0x20]; +}; + +struct mlx5_ifc_ste_double_action_add_v1_bits { + u8 action_id[0x8]; + u8 destination_dw_offset[0x8]; + u8 reserved_at_10[0x2]; + u8 destination_left_shifter[0x6]; + u8 reserved_at_18[0x2]; + u8 destination_length[0x6]; + + u8 add_value[0x20]; +}; + +struct mlx5_ifc_ste_double_action_insert_with_inline_v1_bits { + u8 action_id[0x8]; + u8 reserved_at_8[0x2]; + u8 start_anchor[0x6]; + u8 start_offset[0x7]; + u8 reserved_at_17[0x9]; + + u8 inline_data[0x20]; +}; + +struct mlx5_ifc_ste_double_action_insert_with_ptr_v1_bits { + u8 action_id[0x8]; + u8 reserved_at_8[0x2]; + u8 start_anchor[0x6]; + u8 start_offset[0x7]; + u8 size[0x6]; + u8 attributes[0x3]; + + u8 pointer[0x20]; +}; + +struct mlx5_ifc_ste_double_action_accelerated_modify_action_list_v1_bits { + u8 action_id[0x8]; + u8 modify_actions_pattern_pointer[0x18]; + + u8 number_of_modify_actions[0x8]; + u8 modify_actions_argument_pointer[0x18]; +}; + +struct mlx5_ifc_ste_match_bwc_v1_bits { + u8 entry_format[0x8]; + u8 counter_id[0x18]; + + u8 miss_address_63_48[0x10]; + u8 match_definer_ctx_idx[0x8]; + u8 miss_address_39_32[0x8]; + + u8 miss_address_31_6[0x1a]; + u8 reserved_at_5a[0x1]; + u8 match_polarity[0x1]; + u8 reparse[0x1]; + u8 reserved_at_5d[0x3]; + + u8 next_table_base_63_48[0x10]; + u8 hash_definer_ctx_idx[0x8]; + u8 next_table_base_39_32_size[0x8]; + + u8 next_table_base_31_5_size[0x1b]; + u8 hash_type[0x2]; + u8 hash_after_actions[0x1]; + u8 reserved_at_9e[0x2]; + + u8 byte_mask[0x10]; + u8 next_entry_format[0x1]; + u8 mask_mode[0x1]; + u8 gvmi[0xe]; + + u8 action[0x40]; +}; + +struct mlx5_ifc_ste_mask_and_match_v1_bits { + u8 entry_format[0x8]; + u8 counter_id[0x18]; + + u8 miss_address_63_48[0x10]; + u8 match_definer_ctx_idx[0x8]; + u8 miss_address_39_32[0x8]; + + u8 miss_address_31_6[0x1a]; + u8 reserved_at_5a[0x1]; + u8 match_polarity[0x1]; + u8 reparse[0x1]; + u8 reserved_at_5d[0x3]; + + u8 next_table_base_63_48[0x10]; + u8 hash_definer_ctx_idx[0x8]; + u8 next_table_base_39_32_size[0x8]; + + u8 next_table_base_31_5_size[0x1b]; + u8 hash_type[0x2]; + u8 hash_after_actions[0x1]; + u8 reserved_at_9e[0x2]; + + u8 action[0x60]; +}; + +struct mlx5_ifc_ste_match_ranges_v1_bits { + u8 entry_format[0x8]; + u8 counter_id[0x18]; + + u8 miss_address_63_48[0x10]; + u8 match_definer_ctx_idx[0x8]; + u8 miss_address_39_32[0x8]; + + u8 miss_address_31_6[0x1a]; + u8 reserved_at_5a[0x1]; + u8 match_polarity[0x1]; + u8 reparse[0x1]; + u8 reserved_at_5d[0x3]; + + u8 next_table_base_63_48[0x10]; + u8 hash_definer_ctx_idx[0x8]; + u8 next_table_base_39_32_size[0x8]; + + u8 next_table_base_31_5_size[0x1b]; + u8 hash_type[0x2]; + u8 hash_after_actions[0x1]; + u8 reserved_at_9e[0x2]; + + u8 action[0x60]; + + u8 max_value_0[0x20]; + u8 min_value_0[0x20]; + u8 max_value_1[0x20]; + u8 min_value_1[0x20]; + u8 max_value_2[0x20]; + u8 min_value_2[0x20]; + u8 max_value_3[0x20]; + u8 min_value_3[0x20]; +}; + +struct mlx5_ifc_ste_eth_l2_src_v1_bits { + u8 reserved_at_0[0x1]; + u8 sx_sniffer[0x1]; + u8 functional_loopback[0x1]; + u8 ip_fragmented[0x1]; + u8 qp_type[0x2]; + u8 encapsulation_type[0x2]; + u8 port[0x2]; + u8 l3_type[0x2]; + u8 l4_type[0x2]; + u8 first_vlan_qualifier[0x2]; + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 first_vlan_id[0xc]; + + u8 smac_47_16[0x20]; + + u8 smac_15_0[0x10]; + u8 l3_ethertype[0x10]; + + u8 reserved_at_60[0x6]; + u8 tcp_syn[0x1]; + u8 reserved_at_67[0x3]; + u8 force_loopback[0x1]; + u8 l2_ok[0x1]; + u8 l3_ok[0x1]; + u8 l4_ok[0x1]; + u8 second_vlan_qualifier[0x2]; + + u8 second_priority[0x3]; + u8 second_cfi[0x1]; + u8 second_vlan_id[0xc]; +}; + +struct mlx5_ifc_ste_eth_l2_dst_v1_bits { + u8 reserved_at_0[0x1]; + u8 sx_sniffer[0x1]; + u8 functional_lb[0x1]; + u8 ip_fragmented[0x1]; + u8 qp_type[0x2]; + u8 encapsulation_type[0x2]; + u8 port[0x2]; + u8 l3_type[0x2]; + u8 l4_type[0x2]; + u8 first_vlan_qualifier[0x2]; + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 first_vlan_id[0xc]; + + u8 dmac_47_16[0x20]; + + u8 dmac_15_0[0x10]; + u8 l3_ethertype[0x10]; + + u8 reserved_at_60[0x6]; + u8 tcp_syn[0x1]; + u8 reserved_at_67[0x3]; + u8 force_lb[0x1]; + u8 l2_ok[0x1]; + u8 l3_ok[0x1]; + u8 l4_ok[0x1]; + u8 second_vlan_qualifier[0x2]; + u8 second_priority[0x3]; + u8 second_cfi[0x1]; + u8 second_vlan_id[0xc]; +}; + +struct mlx5_ifc_ste_eth_l2_src_dst_v1_bits { + u8 dmac_47_16[0x20]; + + u8 smac_47_16[0x20]; + + u8 dmac_15_0[0x10]; + u8 reserved_at_50[0x2]; + u8 functional_lb[0x1]; + u8 reserved_at_53[0x5]; + u8 port[0x2]; + u8 l3_type[0x2]; + u8 reserved_at_5c[0x2]; + u8 first_vlan_qualifier[0x2]; + + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 first_vlan_id[0xc]; + u8 smac_15_0[0x10]; +}; + +struct mlx5_ifc_ste_eth_l3_ipv4_5_tuple_v1_bits { + u8 source_address[0x20]; + + u8 destination_address[0x20]; + + u8 source_port[0x10]; + u8 destination_port[0x10]; + + u8 reserved_at_60[0x4]; + u8 l4_ok[0x1]; + u8 l3_ok[0x1]; + u8 fragmented[0x1]; + u8 tcp_ns[0x1]; + u8 tcp_cwr[0x1]; + u8 tcp_ece[0x1]; + u8 tcp_urg[0x1]; + u8 tcp_ack[0x1]; + u8 tcp_psh[0x1]; + u8 tcp_rst[0x1]; + u8 tcp_syn[0x1]; + u8 tcp_fin[0x1]; + u8 dscp[0x6]; + u8 ecn[0x2]; + u8 protocol[0x8]; +}; + +struct mlx5_ifc_ste_eth_l2_tnl_v1_bits { + u8 l2_tunneling_network_id[0x20]; + + u8 dmac_47_16[0x20]; + + u8 dmac_15_0[0x10]; + u8 l3_ethertype[0x10]; + + u8 reserved_at_60[0x3]; + u8 ip_fragmented[0x1]; + u8 reserved_at_64[0x2]; + u8 encp_type[0x2]; + u8 reserved_at_68[0x2]; + u8 l3_type[0x2]; + u8 l4_type[0x2]; + u8 first_vlan_qualifier[0x2]; + u8 first_priority[0x3]; + u8 first_cfi[0x1]; + u8 first_vlan_id[0xc]; +}; + +struct mlx5_ifc_ste_eth_l3_ipv4_misc_v1_bits { + u8 identification[0x10]; + u8 flags[0x3]; + u8 fragment_offset[0xd]; + + u8 total_length[0x10]; + u8 checksum[0x10]; + + u8 version[0x4]; + u8 ihl[0x4]; + u8 time_to_live[0x8]; + u8 reserved_at_50[0x10]; + + u8 reserved_at_60[0x1c]; + u8 voq_internal_prio[0x4]; +}; + +struct mlx5_ifc_ste_eth_l4_v1_bits { + u8 ipv6_version[0x4]; + u8 reserved_at_4[0x4]; + u8 dscp[0x6]; + u8 ecn[0x2]; + u8 ipv6_hop_limit[0x8]; + u8 protocol[0x8]; + + u8 src_port[0x10]; + u8 dst_port[0x10]; + + u8 first_fragment[0x1]; + u8 reserved_at_41[0xb]; + u8 flow_label[0x14]; + + u8 tcp_data_offset[0x4]; + u8 l4_ok[0x1]; + u8 l3_ok[0x1]; + u8 fragmented[0x1]; + u8 tcp_ns[0x1]; + u8 tcp_cwr[0x1]; + u8 tcp_ece[0x1]; + u8 tcp_urg[0x1]; + u8 tcp_ack[0x1]; + u8 tcp_psh[0x1]; + u8 tcp_rst[0x1]; + u8 tcp_syn[0x1]; + u8 tcp_fin[0x1]; + u8 ipv6_paylen[0x10]; +}; + +struct mlx5_ifc_ste_eth_l4_misc_v1_bits { + u8 window_size[0x10]; + u8 urgent_pointer[0x10]; + + u8 ack_num[0x20]; + + u8 seq_num[0x20]; + + u8 length[0x10]; + u8 checksum[0x10]; +}; + +struct mlx5_ifc_ste_mpls_v1_bits { + u8 reserved_at_0[0x15]; + u8 mpls_ok[0x1]; + u8 mpls4_s_bit[0x1]; + u8 mpls4_qualifier[0x1]; + u8 mpls3_s_bit[0x1]; + u8 mpls3_qualifier[0x1]; + u8 mpls2_s_bit[0x1]; + u8 mpls2_qualifier[0x1]; + u8 mpls1_s_bit[0x1]; + u8 mpls1_qualifier[0x1]; + u8 mpls0_s_bit[0x1]; + u8 mpls0_qualifier[0x1]; + + u8 mpls0_label[0x14]; + u8 mpls0_exp[0x3]; + u8 mpls0_s_bos[0x1]; + u8 mpls0_ttl[0x8]; + + u8 mpls1_label[0x20]; + + u8 mpls2_label[0x20]; +}; + +struct mlx5_ifc_ste_gre_v1_bits { + u8 gre_c_present[0x1]; + u8 reserved_at_1[0x1]; + u8 gre_k_present[0x1]; + u8 gre_s_present[0x1]; + u8 strict_src_route[0x1]; + u8 recur[0x3]; + u8 flags[0x5]; + u8 version[0x3]; + u8 gre_protocol[0x10]; + + u8 reserved_at_20[0x20]; + + u8 gre_key_h[0x18]; + u8 gre_key_l[0x8]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_ste_src_gvmi_qp_v1_bits { + u8 loopback_synd[0x8]; + u8 reserved_at_8[0x7]; + u8 functional_lb[0x1]; + u8 source_gvmi[0x10]; + + u8 force_lb[0x1]; + u8 reserved_at_21[0x1]; + u8 source_is_requestor[0x1]; + u8 reserved_at_23[0x5]; + u8 source_qp[0x18]; + + u8 reserved_at_40[0x20]; + + u8 reserved_at_60[0x20]; +}; + +struct mlx5_ifc_ste_icmp_v1_bits { + u8 icmp_payload_data[0x20]; + + u8 icmp_header_data[0x20]; + + u8 icmp_type[0x8]; + u8 icmp_code[0x8]; + u8 reserved_at_50[0x10]; + + u8 reserved_at_60[0x20]; +}; + +#endif /* MLX5_IFC_DR_STE_V1_H */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5dr.h new file mode 100644 index 00000000000000..3ac7dc67509fca --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/mlx5dr.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2019, Mellanox Technologies */ + +#ifndef _MLX5DR_H_ +#define _MLX5DR_H_ + +struct mlx5dr_domain; +struct mlx5dr_table; +struct mlx5dr_matcher; +struct mlx5dr_rule; +struct mlx5dr_action; + +enum mlx5dr_domain_type { + MLX5DR_DOMAIN_TYPE_NIC_RX, + MLX5DR_DOMAIN_TYPE_NIC_TX, + MLX5DR_DOMAIN_TYPE_FDB, +}; + +enum mlx5dr_domain_sync_flags { + MLX5DR_DOMAIN_SYNC_FLAGS_SW = 1 << 0, + MLX5DR_DOMAIN_SYNC_FLAGS_HW = 1 << 1, +}; + +enum mlx5dr_action_reformat_type { + DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2, + DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2, + DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2, + DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3, + DR_ACTION_REFORMAT_TYP_INSERT_HDR, + DR_ACTION_REFORMAT_TYP_REMOVE_HDR, +}; + +struct mlx5dr_match_parameters { + size_t match_sz; + u64 *match_buf; /* Device spec format */ +}; + +struct mlx5dr_action_dest { + struct mlx5dr_action *dest; + struct mlx5dr_action *reformat; +}; + +struct mlx5dr_domain * +mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type); + +int mlx5dr_domain_destroy(struct mlx5dr_domain *domain); + +int mlx5dr_domain_sync(struct mlx5dr_domain *domain, u32 flags); + +void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn, + struct mlx5dr_domain *peer_dmn, + u16 peer_vhca_id); + +struct mlx5dr_table * +mlx5dr_table_create(struct mlx5dr_domain *domain, u32 level, u32 flags, + u16 uid); + +struct mlx5dr_table * +mlx5dr_table_get_from_fs_ft(struct mlx5_flow_table *ft); + +int mlx5dr_table_destroy(struct mlx5dr_table *table); + +u32 mlx5dr_table_get_id(struct mlx5dr_table *table); + +struct mlx5dr_matcher * +mlx5dr_matcher_create(struct mlx5dr_table *table, + u32 priority, + u8 match_criteria_enable, + struct mlx5dr_match_parameters *mask); + +int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher); + +struct mlx5dr_rule * +mlx5dr_rule_create(struct mlx5dr_matcher *matcher, + struct mlx5dr_match_parameters *value, + size_t num_actions, + struct mlx5dr_action *actions[], + u32 flow_source); + +int mlx5dr_rule_destroy(struct mlx5dr_rule *rule); + +int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl, + struct mlx5dr_action *action); + +struct mlx5dr_action * +mlx5dr_action_create_dest_table_num(struct mlx5dr_domain *dmn, u32 table_num); + +struct mlx5dr_action * +mlx5dr_action_create_dest_table(struct mlx5dr_table *table); + +struct mlx5dr_action * +mlx5dr_action_create_dest_flow_fw_table(struct mlx5dr_domain *domain, + struct mlx5_flow_table *ft); + +struct mlx5dr_action * +mlx5dr_action_create_dest_vport(struct mlx5dr_domain *domain, + u16 vport, u8 vhca_id_valid, + u16 vhca_id); + +struct mlx5dr_action * +mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn, + struct mlx5dr_action_dest *dests, + u32 num_of_dests, + bool ignore_flow_level, + u32 flow_source); + +struct mlx5dr_action *mlx5dr_action_create_drop(void); + +struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value); + +struct mlx5dr_action * +mlx5dr_action_create_flow_sampler(struct mlx5dr_domain *dmn, u32 sampler_id); + +struct mlx5dr_action * +mlx5dr_action_create_flow_counter(u32 counter_id); + +struct mlx5dr_action * +mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn, + enum mlx5dr_action_reformat_type reformat_type, + u8 reformat_param_0, + u8 reformat_param_1, + size_t data_sz, + void *data); + +struct mlx5dr_action * +mlx5dr_action_create_modify_header(struct mlx5dr_domain *domain, + u32 flags, + size_t actions_sz, + __be64 actions[]); + +struct mlx5dr_action *mlx5dr_action_create_pop_vlan(void); + +struct mlx5dr_action * +mlx5dr_action_create_push_vlan(struct mlx5dr_domain *domain, __be32 vlan_hdr); + +struct mlx5dr_action * +mlx5dr_action_create_aso(struct mlx5dr_domain *dmn, + u32 obj_id, + u8 return_reg_id, + u8 aso_type, + u8 init_color, + u8 meter_id); + +struct mlx5dr_action * +mlx5dr_action_create_dest_match_range(struct mlx5dr_domain *dmn, + u32 field, + struct mlx5_flow_table *hit_ft, + struct mlx5_flow_table *miss_ft, + u32 min, + u32 max); + +int mlx5dr_action_destroy(struct mlx5dr_action *action); + +u32 mlx5dr_action_get_pkt_reformat_id(struct mlx5dr_action *action); + +static inline bool +mlx5dr_is_supported(struct mlx5_core_dev *dev) +{ + return MLX5_CAP_GEN(dev, roce) && + (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, sw_owner) || + (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, sw_owner_v2) && + (MLX5_CAP_GEN(dev, steering_format_version) <= + MLX5_STEERING_FORMAT_CONNECTX_7))); +} + +/* buddy functions & structure */ + +struct mlx5dr_icm_mr; + +struct mlx5dr_icm_buddy_mem { + unsigned long **bitmap; + unsigned int *num_free; + u32 max_order; + struct list_head list_node; + struct mlx5dr_icm_mr *icm_mr; + struct mlx5dr_icm_pool *pool; + + /* Amount of memory in used chunks - HW may be accessing this memory */ + u64 used_memory; + + /* Memory optimisation */ + struct mlx5dr_ste *ste_arr; + struct list_head *miss_list; + u8 *hw_ste_arr; +}; + +int mlx5dr_buddy_init(struct mlx5dr_icm_buddy_mem *buddy, + unsigned int max_order); +void mlx5dr_buddy_cleanup(struct mlx5dr_icm_buddy_mem *buddy); +int mlx5dr_buddy_alloc_mem(struct mlx5dr_icm_buddy_mem *buddy, + unsigned int order, + unsigned int *segment); +void mlx5dr_buddy_free_mem(struct mlx5dr_icm_buddy_mem *buddy, + unsigned int seg, unsigned int order); + +#endif /* _MLX5DR_H_ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h index e4ef1d24a3ada0..6debb8fd33ffdd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h @@ -244,7 +244,7 @@ static inline struct mlx5_cqe64 *mlx5_cqwq_get_cqe(struct mlx5_cqwq *wq) } static inline -struct mlx5_cqe64 *mlx5_cqwq_get_cqe_enahnced_comp(struct mlx5_cqwq *wq) +struct mlx5_cqe64 *mlx5_cqwq_get_cqe_enhanced_comp(struct mlx5_cqwq *wq) { u8 sw_validity_iteration_count = mlx5_cqwq_get_wrap_cnt(wq) & 0xff; u32 ci = mlx5_cqwq_get_ci(wq); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 385a56ac73481a..fb2e5b844c150d 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_gige_acpi_match); static struct platform_driver mlxbf_gige_driver = { .probe = mlxbf_gige_probe, - .remove_new = mlxbf_gige_remove, + .remove = mlxbf_gige_remove, .shutdown = mlxbf_gige_shutdown, .driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c index 947500f8ed7142..7aa1a462a1035b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c @@ -67,7 +67,7 @@ static bool mlxsw_afk_blocks_check(struct mlxsw_afk *mlxsw_afk) for (j = 0; j < block->instances_count; j++) { const struct mlxsw_afk_element_info *elinfo; - struct mlxsw_afk_element_inst *elinst; + const struct mlxsw_afk_element_inst *elinst; elinst = &block->instances[j]; elinfo = &mlxsw_afk_element_infos[elinst->element]; @@ -154,7 +154,7 @@ static void mlxsw_afk_picker_count_hits(struct mlxsw_afk *mlxsw_afk, const struct mlxsw_afk_block *block = &mlxsw_afk->blocks[i]; for (j = 0; j < block->instances_count; j++) { - struct mlxsw_afk_element_inst *elinst; + const struct mlxsw_afk_element_inst *elinst; elinst = &block->instances[j]; if (elinst->element == element) { @@ -386,7 +386,7 @@ mlxsw_afk_block_elinst_get(const struct mlxsw_afk_block *block, int i; for (i = 0; i < block->instances_count; i++) { - struct mlxsw_afk_element_inst *elinst; + const struct mlxsw_afk_element_inst *elinst; elinst = &block->instances[i]; if (elinst->element == element) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h index 98a05598178b3b..5aa1afb3f2ca81 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h @@ -117,7 +117,7 @@ struct mlxsw_afk_element_inst { /* element instance in actual block */ struct mlxsw_afk_block { u16 encoding; /* block ID */ - struct mlxsw_afk_element_inst *instances; + const struct mlxsw_afk_element_inst *instances; unsigned int instances_count; bool high_entropy; }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c index eaad7860560271..1850a975b38044 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c @@ -7,7 +7,7 @@ #include "item.h" #include "core_acl_flex_keys.h" -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = { MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x00, 2), MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x02, 4), MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3), @@ -15,7 +15,7 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_dmac[] = { MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = { MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x00, 2), MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x02, 4), MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 13, 3), @@ -23,27 +23,27 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac[] = { MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l2_smac_ex[] = { MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x02, 2), MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x04, 4), MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x0C, 0, 16), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_sip[] = { MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4), MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 16, 16), MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8), MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_dip[] = { MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x00, 4), MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 16, 16), MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8), MLXSW_AFK_ELEMENT_INST_U32(SRC_SYS_PORT, 0x0C, 0, 16), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x00, 4), MLXSW_AFK_ELEMENT_INST_U32(IP_ECN, 0x04, 4, 2), MLXSW_AFK_ELEMENT_INST_U32(IP_TTL_, 0x04, 24, 8), @@ -51,35 +51,35 @@ static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4[] = { MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x08, 8, 9), /* TCP_CONTROL+TCP_ECN */ }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_ex[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_ex[] = { MLXSW_AFK_ELEMENT_INST_U32(VID, 0x00, 0, 12), MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x08, 29, 3), MLXSW_AFK_ELEMENT_INST_U32(SRC_L4_PORT, 0x08, 0, 16), MLXSW_AFK_ELEMENT_INST_U32(DST_L4_PORT, 0x0C, 0, 16), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_dip[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_dip[] = { MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x00, 4), MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_ex1[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_ex1[] = { MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x00, 4), MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_64_95, 0x04, 4), MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x08, 0, 8), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip[] = { MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_32_63, 0x00, 4), MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip_ex[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_sip_ex[] = { MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_96_127, 0x00, 4), MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_64_95, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_packet_type[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_packet_type[] = { MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x00, 0, 16), }; @@ -124,90 +124,90 @@ const struct mlxsw_afk_ops mlxsw_sp1_afk_ops = { .clear_block = mlxsw_sp1_afk_clear_block, }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_0[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_0[] = { MLXSW_AFK_ELEMENT_INST_U32(FDB_MISS, 0x00, 3, 1), MLXSW_AFK_ELEMENT_INST_BUF(DMAC_0_31, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_1[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_1[] = { MLXSW_AFK_ELEMENT_INST_U32(FDB_MISS, 0x00, 3, 1), MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_2[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_2[] = { MLXSW_AFK_ELEMENT_INST_BUF(SMAC_32_47, 0x04, 2), MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x06, 2), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_3[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_3[] = { MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x00, 0, 3), MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12), MLXSW_AFK_ELEMENT_INST_BUF(DMAC_32_47, 0x06, 2), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_4[] = { MLXSW_AFK_ELEMENT_INST_U32(PCP, 0x00, 0, 3), MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12), MLXSW_AFK_ELEMENT_INST_U32(ETHERTYPE, 0x04, 0, 16), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5[] = { MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 16, 12), MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 8, -1, true), /* RX_ACL_SYSTEM_PORT */ }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_0[] = { MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_0_31, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1[] = { MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_2[] = { MLXSW_AFK_ELEMENT_INST_U32(IP_DSCP, 0x04, 0, 6), MLXSW_AFK_ELEMENT_INST_U32(IP_ECN, 0x04, 6, 2), MLXSW_AFK_ELEMENT_INST_U32(IP_TTL_, 0x04, 8, 8), MLXSW_AFK_ELEMENT_INST_U32(IP_PROTO, 0x04, 16, 8), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5[] = { MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER, 0x04, 20, 11, 0, true), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_0[] = { MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_0_3, 0x00, 0, 4), MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_32_63, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_1[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_1[] = { MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_4_7, 0x00, 0, 4), MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_64_95, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2[] = { MLXSW_AFK_ELEMENT_INST_EXT_U32(VIRT_ROUTER_MSB, 0x00, 0, 3, 0, true), MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_3[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_3[] = { MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_32_63, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_4[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_4[] = { MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_64_95, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_5[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_5[] = { MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_96_127, 0x04, 4), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_0[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_0[] = { MLXSW_AFK_ELEMENT_INST_U32(SRC_L4_PORT, 0x04, 16, 16), MLXSW_AFK_ELEMENT_INST_U32(DST_L4_PORT, 0x04, 0, 16), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_2[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_l4_2[] = { MLXSW_AFK_ELEMENT_INST_U32(TCP_FLAGS, 0x04, 16, 9), /* TCP_CONTROL + TCP_ECN */ MLXSW_AFK_ELEMENT_INST_U32(L4_PORT_RANGE, 0x04, 0, 16), }; @@ -319,16 +319,20 @@ const struct mlxsw_afk_ops mlxsw_sp2_afk_ops = { .clear_block = mlxsw_sp2_afk_clear_block, }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_mac_5b[] = { MLXSW_AFK_ELEMENT_INST_U32(VID, 0x04, 18, 12), MLXSW_AFK_ELEMENT_INST_EXT_U32(SRC_SYS_PORT, 0x04, 0, 9, -1, true), /* RX_ACL_SYSTEM_PORT */ }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_1b[] = { + MLXSW_AFK_ELEMENT_INST_BUF(SRC_IP_0_31, 0x04, 4), +}; + +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv4_5b[] = { MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER, 0x04, 20, 12), }; -static struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = { +static const struct mlxsw_afk_element_inst mlxsw_sp_afk_element_info_ipv6_2b[] = { MLXSW_AFK_ELEMENT_INST_U32(VIRT_ROUTER_MSB, 0x00, 0, 4), MLXSW_AFK_ELEMENT_INST_BUF(DST_IP_96_127, 0x04, 4), }; @@ -341,7 +345,7 @@ static const struct mlxsw_afk_block mlxsw_sp4_afk_blocks[] = { MLXSW_AFK_BLOCK(0x14, mlxsw_sp_afk_element_info_mac_4), MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x1A, mlxsw_sp_afk_element_info_mac_5b), MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x38, mlxsw_sp_afk_element_info_ipv4_0), - MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x39, mlxsw_sp_afk_element_info_ipv4_1), + MLXSW_AFK_BLOCK_HIGH_ENTROPY(0x3F, mlxsw_sp_afk_element_info_ipv4_1b), MLXSW_AFK_BLOCK(0x3A, mlxsw_sp_afk_element_info_ipv4_2), MLXSW_AFK_BLOCK(0x36, mlxsw_sp_afk_element_info_ipv4_5b), MLXSW_AFK_BLOCK(0x40, mlxsw_sp_afk_element_info_ipv6_0), diff --git a/drivers/net/ethernet/meta/Kconfig b/drivers/net/ethernet/meta/Kconfig index 85519690b83778..831921b9d4d5e2 100644 --- a/drivers/net/ethernet/meta/Kconfig +++ b/drivers/net/ethernet/meta/Kconfig @@ -23,6 +23,7 @@ config FBNIC depends on !S390 depends on MAX_SKB_FRAGS < 22 depends on PCI_MSI + depends on PTP_1588_CLOCK_OPTIONAL select NET_DEVLINK select PAGE_POOL select PHYLINK diff --git a/drivers/net/ethernet/meta/fbnic/Makefile b/drivers/net/ethernet/meta/fbnic/Makefile index ed4533a73c575f..239b2258ec6586 100644 --- a/drivers/net/ethernet/meta/fbnic/Makefile +++ b/drivers/net/ethernet/meta/fbnic/Makefile @@ -7,10 +7,13 @@ obj-$(CONFIG_FBNIC) += fbnic.o -fbnic-y := fbnic_devlink.o \ +fbnic-y := fbnic_csr.o \ + fbnic_debugfs.o \ + fbnic_devlink.o \ fbnic_ethtool.o \ fbnic_fw.o \ fbnic_hw_stats.o \ + fbnic_hwmon.o \ fbnic_irq.o \ fbnic_mac.o \ fbnic_netdev.o \ @@ -18,4 +21,5 @@ fbnic-y := fbnic_devlink.o \ fbnic_phylink.o \ fbnic_rpc.o \ fbnic_tlv.o \ - fbnic_txrx.o + fbnic_txrx.o \ + fbnic_time.o diff --git a/drivers/net/ethernet/meta/fbnic/fbnic.h b/drivers/net/ethernet/meta/fbnic/fbnic.h index 0f9e8d79461c63..706ae6104c8e2d 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -18,6 +19,8 @@ struct fbnic_dev { struct device *dev; struct net_device *netdev; + struct dentry *dbg_fbd; + struct device *hwmon; u32 __iomem *uc_addr0; u32 __iomem *uc_addr4; @@ -30,6 +33,7 @@ struct fbnic_dev { struct fbnic_fw_mbx mbx[FBNIC_IPC_MBX_INDICES]; struct fbnic_fw_cap fw_cap; + struct fbnic_fw_completion *cmpl_data; /* Lock protecting Tx Mailbox queue to prevent possible races */ spinlock_t fw_tx_lock; @@ -45,10 +49,21 @@ struct fbnic_dev { struct fbnic_act_tcam act_tcam[FBNIC_RPC_TCAM_ACT_NUM_ENTRIES]; struct fbnic_mac_addr mac_addr[FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES]; u8 mac_addr_boundary; + u8 tce_tcam_last; /* Number of TCQs/RCQs available on hardware */ u16 max_num_queues; + /* Lock protecting writes to @time_high, @time_offset of fbnic_netdev, + * and the HW time CSR machinery. + */ + spinlock_t time_lock; + /* Externally accessible PTP clock, may be NULL */ + struct ptp_clock *ptp; + struct ptp_clock_info ptp_info; + /* Last @time_high refresh time in jiffies (to catch stalls) */ + unsigned long last_read; + /* Local copy of hardware statistics */ struct fbnic_hw_stats hw_stats; }; @@ -127,6 +142,9 @@ void fbnic_devlink_unregister(struct fbnic_dev *fbd); int fbnic_fw_enable_mbx(struct fbnic_dev *fbd); void fbnic_fw_disable_mbx(struct fbnic_dev *fbd); +void fbnic_hwmon_register(struct fbnic_dev *fbd); +void fbnic_hwmon_unregister(struct fbnic_dev *fbd); + int fbnic_pcs_irq_enable(struct fbnic_dev *fbd); void fbnic_pcs_irq_disable(struct fbnic_dev *fbd); @@ -139,6 +157,14 @@ int fbnic_alloc_irqs(struct fbnic_dev *fbd); void fbnic_get_fw_ver_commit_str(struct fbnic_dev *fbd, char *fw_version, const size_t str_sz); +void fbnic_dbg_fbd_init(struct fbnic_dev *fbd); +void fbnic_dbg_fbd_exit(struct fbnic_dev *fbd); +void fbnic_dbg_init(void); +void fbnic_dbg_exit(void); + +void fbnic_csr_get_regs(struct fbnic_dev *fbd, u32 *data, u32 *regs_version); +int fbnic_csr_regs_len(struct fbnic_dev *fbd); + enum fbnic_boards { fbnic_board_asic }; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.c b/drivers/net/ethernet/meta/fbnic/fbnic_csr.c new file mode 100644 index 00000000000000..2118901b25e91c --- /dev/null +++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + +#include "fbnic.h" + +#define FBNIC_BOUNDS(section) { \ + .start = FBNIC_CSR_START_##section, \ + .end = FBNIC_CSR_END_##section + 1, \ +} + +struct fbnic_csr_bounds { + u32 start; + u32 end; +}; + +static const struct fbnic_csr_bounds fbnic_csr_sects[] = { + FBNIC_BOUNDS(INTR), + FBNIC_BOUNDS(INTR_CQ), + FBNIC_BOUNDS(QM_TX), + FBNIC_BOUNDS(QM_RX), + FBNIC_BOUNDS(TCE), + FBNIC_BOUNDS(TCE_RAM), + FBNIC_BOUNDS(TMI), + FBNIC_BOUNDS(PTP), + FBNIC_BOUNDS(RXB), + FBNIC_BOUNDS(RPC), + FBNIC_BOUNDS(FAB), + FBNIC_BOUNDS(MASTER), + FBNIC_BOUNDS(PCS), + FBNIC_BOUNDS(RSFEC), + FBNIC_BOUNDS(MAC_MAC), + FBNIC_BOUNDS(SIG), + FBNIC_BOUNDS(PUL_USER), + FBNIC_BOUNDS(QUEUE), + FBNIC_BOUNDS(RPC_RAM), +}; + +#define FBNIC_RPC_TCAM_ACT_DW_PER_ENTRY 14 +#define FBNIC_RPC_TCAM_ACT_NUM_ENTRIES 64 + +#define FBNIC_RPC_TCAM_MACDA_DW_PER_ENTRY 4 +#define FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES 32 + +#define FBNIC_RPC_TCAM_OUTER_IPSRC_DW_PER_ENTRY 9 +#define FBNIC_RPC_TCAM_OUTER_IPSRC_NUM_ENTRIES 8 + +#define FBNIC_RPC_TCAM_OUTER_IPDST_DW_PER_ENTRY 9 +#define FBNIC_RPC_TCAM_OUTER_IPDST_NUM_ENTRIES 8 + +#define FBNIC_RPC_TCAM_IPSRC_DW_PER_ENTRY 9 +#define FBNIC_RPC_TCAM_IPSRC_NUM_ENTRIES 8 + +#define FBNIC_RPC_TCAM_IPDST_DW_PER_ENTRY 9 +#define FBNIC_RPC_TCAM_IPDST_NUM_ENTRIES 8 + +#define FBNIC_RPC_RSS_TBL_DW_PER_ENTRY 2 +#define FBNIC_RPC_RSS_TBL_NUM_ENTRIES 256 + +static void fbnic_csr_get_regs_rpc_ram(struct fbnic_dev *fbd, u32 **data_p) +{ + u32 start = FBNIC_CSR_START_RPC_RAM; + u32 end = FBNIC_CSR_END_RPC_RAM; + u32 *data = *data_p; + u32 i, j; + + *(data++) = start; + *(data++) = end - 1; + + /* FBNIC_RPC_TCAM_ACT */ + for (i = 0; i < FBNIC_RPC_TCAM_ACT_NUM_ENTRIES; i++) { + for (j = 0; j < FBNIC_RPC_TCAM_ACT_DW_PER_ENTRY; j++) + *(data++) = rd32(fbd, FBNIC_RPC_TCAM_ACT(i, j)); + } + + /* FBNIC_RPC_TCAM_MACDA */ + for (i = 0; i < FBNIC_RPC_TCAM_MACDA_NUM_ENTRIES; i++) { + for (j = 0; j < FBNIC_RPC_TCAM_MACDA_DW_PER_ENTRY; j++) + *(data++) = rd32(fbd, FBNIC_RPC_TCAM_MACDA(i, j)); + } + + /* FBNIC_RPC_TCAM_OUTER_IPSRC */ + for (i = 0; i < FBNIC_RPC_TCAM_OUTER_IPSRC_NUM_ENTRIES; i++) { + for (j = 0; j < FBNIC_RPC_TCAM_OUTER_IPSRC_DW_PER_ENTRY; j++) + *(data++) = rd32(fbd, FBNIC_RPC_TCAM_OUTER_IPSRC(i, j)); + } + + /* FBNIC_RPC_TCAM_OUTER_IPDST */ + for (i = 0; i < FBNIC_RPC_TCAM_OUTER_IPDST_NUM_ENTRIES; i++) { + for (j = 0; j < FBNIC_RPC_TCAM_OUTER_IPDST_DW_PER_ENTRY; j++) + *(data++) = rd32(fbd, FBNIC_RPC_TCAM_OUTER_IPDST(i, j)); + } + + /* FBNIC_RPC_TCAM_IPSRC */ + for (i = 0; i < FBNIC_RPC_TCAM_IPSRC_NUM_ENTRIES; i++) { + for (j = 0; j < FBNIC_RPC_TCAM_IPSRC_DW_PER_ENTRY; j++) + *(data++) = rd32(fbd, FBNIC_RPC_TCAM_IPSRC(i, j)); + } + + /* FBNIC_RPC_TCAM_IPDST */ + for (i = 0; i < FBNIC_RPC_TCAM_IPDST_NUM_ENTRIES; i++) { + for (j = 0; j < FBNIC_RPC_TCAM_IPDST_DW_PER_ENTRY; j++) + *(data++) = rd32(fbd, FBNIC_RPC_TCAM_IPDST(i, j)); + } + + /* FBNIC_RPC_RSS_TBL */ + for (i = 0; i < FBNIC_RPC_RSS_TBL_NUM_ENTRIES; i++) { + for (j = 0; j < FBNIC_RPC_RSS_TBL_DW_PER_ENTRY; j++) + *(data++) = rd32(fbd, FBNIC_RPC_RSS_TBL(i, j)); + } + + *data_p = data; +} + +void fbnic_csr_get_regs(struct fbnic_dev *fbd, u32 *data, u32 *regs_version) +{ + const struct fbnic_csr_bounds *bound; + u32 *start = data; + int i, j; + + *regs_version = 1u; + + /* Skip RPC_RAM section which cannot be dumped linearly */ + for (i = 0, bound = fbnic_csr_sects; + i < ARRAY_SIZE(fbnic_csr_sects) - 1; i++, ++bound) { + *(data++) = bound->start; + *(data++) = bound->end - 1; + for (j = bound->start; j < bound->end; j++) + *(data++) = rd32(fbd, j); + } + + /* Dump the RPC_RAM as special case registers */ + fbnic_csr_get_regs_rpc_ram(fbd, &data); + + WARN_ON(data - start != fbnic_csr_regs_len(fbd)); +} + +int fbnic_csr_regs_len(struct fbnic_dev *fbd) +{ + int i, len = 0; + + /* Dump includes start and end information of each section + * which results in an offset of 2 + */ + for (i = 0; i < ARRAY_SIZE(fbnic_csr_sects); i++) + len += fbnic_csr_sects[i].end - fbnic_csr_sects[i].start + 2; + + return len; +} diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h index 21db509acbc157..02bb81b3c50632 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_csr.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_csr.h @@ -397,6 +397,14 @@ enum { #define FBNIC_TCE_DROP_CTRL_TTI_FRM_DROP_EN CSR_BIT(1) #define FBNIC_TCE_DROP_CTRL_TTI_TBI_DROP_EN CSR_BIT(2) +#define FBNIC_TCE_TCAM_IDX2DEST_MAP 0x0404A /* 0x10128 */ +#define FBNIC_TCE_TCAM_IDX2DEST_MAP_DEST_ID_0 CSR_GENMASK(3, 0) +enum { + FBNIC_TCE_TCAM_DEST_MAC = 1, + FBNIC_TCE_TCAM_DEST_BMC = 2, + FBNIC_TCE_TCAM_DEST_FW = 4, +}; + #define FBNIC_TCE_TXB_TX_BMC_Q_CTRL 0x0404B /* 0x1012c */ #define FBNIC_TCE_TXB_BMC_DWRR_CTRL 0x0404C /* 0x10130 */ #define FBNIC_TCE_TXB_BMC_DWRR_CTRL_QUANTUM0 CSR_GENMASK(7, 0) @@ -407,12 +415,62 @@ enum { #define FBNIC_TCE_TXB_BMC_DWRR_CTRL_EXT 0x0404F /* 0x1013c */ #define FBNIC_CSR_END_TCE 0x04050 /* CSR section delimiter */ +/* TCE RAM registers */ +#define FBNIC_CSR_START_TCE_RAM 0x04200 /* CSR section delimiter */ +#define FBNIC_TCE_RAM_TCAM(m, n) \ + (0x04200 + 0x8 * (n) + (m)) /* 0x10800 + 32*n + 4*m */ +#define FBNIC_TCE_RAM_TCAM_MASK CSR_GENMASK(15, 0) +#define FBNIC_TCE_RAM_TCAM_VALUE CSR_GENMASK(31, 16) +#define FBNIC_TCE_RAM_TCAM3(n) (0x04218 + (n)) /* 0x010860 + 4*n */ +#define FBNIC_TCE_RAM_TCAM3_DEST_MASK CSR_GENMASK(5, 3) +#define FBNIC_TCE_RAM_TCAM3_MCQ_MASK CSR_BIT(7) +#define FBNIC_TCE_RAM_TCAM3_VALIDATE CSR_BIT(31) +#define FBNIC_CSR_END_TCE_RAM 0x0421F /* CSR section delimiter */ + /* TMI registers */ #define FBNIC_CSR_START_TMI 0x04400 /* CSR section delimiter */ #define FBNIC_TMI_SOP_PROT_CTRL 0x04400 /* 0x11000 */ #define FBNIC_TMI_DROP_CTRL 0x04401 /* 0x11004 */ #define FBNIC_TMI_DROP_CTRL_EN CSR_BIT(0) #define FBNIC_CSR_END_TMI 0x0443f /* CSR section delimiter */ + +/* Precision Time Protocol Registers */ +#define FBNIC_CSR_START_PTP 0x04800 /* CSR section delimiter */ +#define FBNIC_PTP_REG_BASE 0x04800 /* 0x12000 */ + +#define FBNIC_PTP_CTRL 0x04800 /* 0x12000 */ +#define FBNIC_PTP_CTRL_EN CSR_BIT(0) +#define FBNIC_PTP_CTRL_MONO_EN CSR_BIT(4) +#define FBNIC_PTP_CTRL_TQS_OUT_EN CSR_BIT(8) +#define FBNIC_PTP_CTRL_MAC_OUT_IVAL CSR_GENMASK(16, 12) +#define FBNIC_PTP_CTRL_TICK_IVAL CSR_GENMASK(23, 20) + +#define FBNIC_PTP_ADJUST 0x04801 /* 0x12004 */ +#define FBNIC_PTP_ADJUST_INIT CSR_BIT(0) +#define FBNIC_PTP_ADJUST_SUB_NUDGE CSR_BIT(8) +#define FBNIC_PTP_ADJUST_ADD_NUDGE CSR_BIT(16) +#define FBNIC_PTP_ADJUST_ADDEND_SET CSR_BIT(24) + +#define FBNIC_PTP_INIT_HI 0x04802 /* 0x12008 */ +#define FBNIC_PTP_INIT_LO 0x04803 /* 0x1200c */ + +#define FBNIC_PTP_NUDGE_NS 0x04804 /* 0x12010 */ +#define FBNIC_PTP_NUDGE_SUBNS 0x04805 /* 0x12014 */ + +#define FBNIC_PTP_ADD_VAL_NS 0x04806 /* 0x12018 */ +#define FBNIC_PTP_ADD_VAL_NS_MASK CSR_GENMASK(15, 0) +#define FBNIC_PTP_ADD_VAL_SUBNS 0x04807 /* 0x1201c */ + +#define FBNIC_PTP_CTR_VAL_HI 0x04808 /* 0x12020 */ +#define FBNIC_PTP_CTR_VAL_LO 0x04809 /* 0x12024 */ + +#define FBNIC_PTP_MONO_PTP_CTR_HI 0x0480a /* 0x12028 */ +#define FBNIC_PTP_MONO_PTP_CTR_LO 0x0480b /* 0x1202c */ + +#define FBNIC_PTP_CDC_FIFO_STATUS 0x0480c /* 0x12030 */ +#define FBNIC_PTP_SPARE 0x0480d /* 0x12034 */ +#define FBNIC_CSR_END_PTP 0x0480d /* CSR section delimiter */ + /* Rx Buffer Registers */ #define FBNIC_CSR_START_RXB 0x08000 /* CSR section delimiter */ enum { @@ -548,6 +606,7 @@ enum { }; #define FBNIC_RPC_ACT_TBL0_DMA_HINT CSR_GENMASK(24, 16) +#define FBNIC_RPC_ACT_TBL0_TS_ENA CSR_BIT(28) #define FBNIC_RPC_ACT_TBL0_RSS_CTXT_ID CSR_BIT(30) #define FBNIC_RPC_ACT_TBL1_DEFAULT 0x0840b /* 0x2102c */ @@ -579,6 +638,16 @@ enum { FBNIC_RPC_RSS_KEY_DWORD_LEN * 32 - \ FBNIC_RPC_RSS_KEY_BIT_LEN) +#define FBNIC_RPC_CNTR_TCP_OPT_ERR 0x0849e /* 0x21278 */ +#define FBNIC_RPC_CNTR_UNKN_ETYPE 0x0849f /* 0x2127c */ +#define FBNIC_RPC_CNTR_IPV4_FRAG 0x084a0 /* 0x21280 */ +#define FBNIC_RPC_CNTR_IPV6_FRAG 0x084a1 /* 0x21284 */ +#define FBNIC_RPC_CNTR_IPV4_ESP 0x084a2 /* 0x21288 */ +#define FBNIC_RPC_CNTR_IPV6_ESP 0x084a3 /* 0x2128c */ +#define FBNIC_RPC_CNTR_UNKN_EXT_HDR 0x084a4 /* 0x21290 */ +#define FBNIC_RPC_CNTR_OUT_OF_HDR_ERR 0x084a5 /* 0x21294 */ +#define FBNIC_RPC_CNTR_OVR_SIZE_ERR 0x084a6 /* 0x21298 */ + #define FBNIC_RPC_TCAM_MACDA_VALIDATE 0x0852d /* 0x214b4 */ #define FBNIC_CSR_END_RPC 0x0856b /* CSR section delimiter */ @@ -606,6 +675,15 @@ enum { #define FBNIC_RPC_TCAM_MACDA_VALUE CSR_GENMASK(15, 0) #define FBNIC_RPC_TCAM_MACDA_MASK CSR_GENMASK(31, 16) +#define FBNIC_RPC_TCAM_OUTER_IPSRC(m, n)\ + (0x08c00 + 0x08 * (n) + (m)) /* 0x023000 + 32*n + 4*m */ +#define FBNIC_RPC_TCAM_OUTER_IPDST(m, n)\ + (0x08c48 + 0x08 * (n) + (m)) /* 0x023120 + 32*n + 4*m */ +#define FBNIC_RPC_TCAM_IPSRC(m, n)\ + (0x08c90 + 0x08 * (n) + (m)) /* 0x023240 + 32*n + 4*m */ +#define FBNIC_RPC_TCAM_IPDST(m, n)\ + (0x08cd8 + 0x08 * (n) + (m)) /* 0x023360 + 32*n + 4*m */ + #define FBNIC_RPC_RSS_TBL(n, m) \ (0x08d20 + 0x100 * (n) + (m)) /* 0x023480 + 1024*n + 4*m */ #define FBNIC_RPC_RSS_TBL_COUNT 2 @@ -624,6 +702,13 @@ enum { #define FBNIC_MASTER_SPARE_0 0x0C41B /* 0x3106c */ #define FBNIC_CSR_END_MASTER 0x0C452 /* CSR section delimiter */ +/* MAC PCS registers */ +#define FBNIC_CSR_START_PCS 0x10000 /* CSR section delimiter */ +#define FBNIC_CSR_END_PCS 0x10668 /* CSR section delimiter */ + +#define FBNIC_CSR_START_RSFEC 0x10800 /* CSR section delimiter */ +#define FBNIC_CSR_END_RSFEC 0x108c8 /* CSR section delimiter */ + /* MAC MAC registers (ASIC only) */ #define FBNIC_CSR_START_MAC_MAC 0x11000 /* CSR section delimiter */ #define FBNIC_MAC_COMMAND_CONFIG 0x11002 /* 0x44008 */ @@ -843,6 +928,43 @@ enum { #define FBNIC_MAX_QUEUES 128 #define FBNIC_CSR_END_QUEUE (0x40000 + 0x400 * FBNIC_MAX_QUEUES - 1) +/* PUL User Registers*/ +#define FBNIC_PUL_USER_OB_RD_TLP_CNT_31_0 \ + 0x3106e /* 0xc41b8 */ +#define FBNIC_PUL_USER_OB_RD_DWORD_CNT_31_0 \ + 0x31070 /* 0xc41c0 */ +#define FBNIC_PUL_USER_OB_RD_DWORD_CNT_63_32 \ + 0x31071 /* 0xc41c4 */ +#define FBNIC_PUL_USER_OB_WR_TLP_CNT_31_0 \ + 0x31072 /* 0xc41c8 */ +#define FBNIC_PUL_USER_OB_WR_TLP_CNT_63_32 \ + 0x31073 /* 0xc41cc */ +#define FBNIC_PUL_USER_OB_WR_DWORD_CNT_31_0 \ + 0x31074 /* 0xc41d0 */ +#define FBNIC_PUL_USER_OB_WR_DWORD_CNT_63_32 \ + 0x31075 /* 0xc41d4 */ +#define FBNIC_PUL_USER_OB_CPL_TLP_CNT_31_0 \ + 0x31076 /* 0xc41d8 */ +#define FBNIC_PUL_USER_OB_CPL_TLP_CNT_63_32 \ + 0x31077 /* 0xc41dc */ +#define FBNIC_PUL_USER_OB_CPL_DWORD_CNT_31_0 \ + 0x31078 /* 0xc41e0 */ +#define FBNIC_PUL_USER_OB_CPL_DWORD_CNT_63_32 \ + 0x31079 /* 0xc41e4 */ +#define FBNIC_PUL_USER_OB_RD_DBG_CNT_CPL_CRED_31_0 \ + 0x3107a /* 0xc41e8 */ +#define FBNIC_PUL_USER_OB_RD_DBG_CNT_CPL_CRED_63_32 \ + 0x3107b /* 0xc41ec */ +#define FBNIC_PUL_USER_OB_RD_DBG_CNT_TAG_31_0 \ + 0x3107c /* 0xc41f0 */ +#define FBNIC_PUL_USER_OB_RD_DBG_CNT_TAG_63_32 \ + 0x3107d /* 0xc41f4 */ +#define FBNIC_PUL_USER_OB_RD_DBG_CNT_NP_CRED_31_0 \ + 0x3107e /* 0xc41f8 */ +#define FBNIC_PUL_USER_OB_RD_DBG_CNT_NP_CRED_63_32 \ + 0x3107f /* 0xc41fc */ +#define FBNIC_CSR_END_PUL_USER 0x31080 /* CSR section delimiter */ + /* BAR 4 CSRs */ /* The IPC mailbox consists of 32 mailboxes, with each mailbox consisting diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c new file mode 100644 index 00000000000000..59951b5abdb787 --- /dev/null +++ b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include + +#include "fbnic.h" + +static struct dentry *fbnic_dbg_root; + +static int fbnic_dbg_pcie_stats_show(struct seq_file *s, void *v) +{ + struct fbnic_dev *fbd = s->private; + + rtnl_lock(); + fbnic_get_hw_stats(fbd); + + seq_printf(s, "ob_rd_tlp: %llu\n", fbd->hw_stats.pcie.ob_rd_tlp.value); + seq_printf(s, "ob_rd_dword: %llu\n", + fbd->hw_stats.pcie.ob_rd_dword.value); + seq_printf(s, "ob_wr_tlp: %llu\n", fbd->hw_stats.pcie.ob_wr_tlp.value); + seq_printf(s, "ob_wr_dword: %llu\n", + fbd->hw_stats.pcie.ob_wr_dword.value); + seq_printf(s, "ob_cpl_tlp: %llu\n", + fbd->hw_stats.pcie.ob_cpl_tlp.value); + seq_printf(s, "ob_cpl_dword: %llu\n", + fbd->hw_stats.pcie.ob_cpl_dword.value); + seq_printf(s, "ob_rd_no_tag: %llu\n", + fbd->hw_stats.pcie.ob_rd_no_tag.value); + seq_printf(s, "ob_rd_no_cpl_cred: %llu\n", + fbd->hw_stats.pcie.ob_rd_no_cpl_cred.value); + seq_printf(s, "ob_rd_no_np_cred: %llu\n", + fbd->hw_stats.pcie.ob_rd_no_np_cred.value); + rtnl_unlock(); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(fbnic_dbg_pcie_stats); + +void fbnic_dbg_fbd_init(struct fbnic_dev *fbd) +{ + struct pci_dev *pdev = to_pci_dev(fbd->dev); + const char *name = pci_name(pdev); + + fbd->dbg_fbd = debugfs_create_dir(name, fbnic_dbg_root); + debugfs_create_file("pcie_stats", 0400, fbd->dbg_fbd, fbd, + &fbnic_dbg_pcie_stats_fops); +} + +void fbnic_dbg_fbd_exit(struct fbnic_dev *fbd) +{ + debugfs_remove_recursive(fbd->dbg_fbd); + fbd->dbg_fbd = NULL; +} + +void fbnic_dbg_init(void) +{ + fbnic_dbg_root = debugfs_create_dir(fbnic_driver_name, NULL); +} + +void fbnic_dbg_exit(void) +{ + debugfs_remove_recursive(fbnic_dbg_root); + fbnic_dbg_root = NULL; +} diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c index 5d980e17894141..cc8ca94529ca10 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + #include #include #include @@ -6,6 +9,66 @@ #include "fbnic_netdev.h" #include "fbnic_tlv.h" +struct fbnic_stat { + u8 string[ETH_GSTRING_LEN]; + unsigned int size; + unsigned int offset; +}; + +#define FBNIC_STAT_FIELDS(type, name, stat) { \ + .string = name, \ + .size = sizeof_field(struct type, stat), \ + .offset = offsetof(struct type, stat), \ +} + +/* Hardware statistics not captured in rtnl_link_stats */ +#define FBNIC_HW_STAT(name, stat) \ + FBNIC_STAT_FIELDS(fbnic_hw_stats, name, stat) + +static const struct fbnic_stat fbnic_gstrings_hw_stats[] = { + /* RPC */ + FBNIC_HW_STAT("rpc_unkn_etype", rpc.unkn_etype), + FBNIC_HW_STAT("rpc_unkn_ext_hdr", rpc.unkn_ext_hdr), + FBNIC_HW_STAT("rpc_ipv4_frag", rpc.ipv4_frag), + FBNIC_HW_STAT("rpc_ipv6_frag", rpc.ipv6_frag), + FBNIC_HW_STAT("rpc_ipv4_esp", rpc.ipv4_esp), + FBNIC_HW_STAT("rpc_ipv6_esp", rpc.ipv6_esp), + FBNIC_HW_STAT("rpc_tcp_opt_err", rpc.tcp_opt_err), + FBNIC_HW_STAT("rpc_out_of_hdr_err", rpc.out_of_hdr_err), +}; + +#define FBNIC_HW_FIXED_STATS_LEN ARRAY_SIZE(fbnic_gstrings_hw_stats) +#define FBNIC_HW_STATS_LEN FBNIC_HW_FIXED_STATS_LEN + +static int +fbnic_get_ts_info(struct net_device *netdev, + struct kernel_ethtool_ts_info *tsinfo) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + tsinfo->phc_index = ptp_clock_index(fbn->fbd->ptp); + + tsinfo->so_timestamping = + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + tsinfo->tx_types = + BIT(HWTSTAMP_TX_OFF) | + BIT(HWTSTAMP_TX_ON); + + tsinfo->rx_filters = + BIT(HWTSTAMP_FILTER_NONE) | + BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) | + BIT(HWTSTAMP_FILTER_ALL); + + return 0; +} + static void fbnic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { @@ -22,6 +85,43 @@ static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter) *stat = counter->value; } +static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data) +{ + int i; + + switch (sset) { + case ETH_SS_STATS: + for (i = 0; i < FBNIC_HW_STATS_LEN; i++) + ethtool_puts(&data, fbnic_gstrings_hw_stats[i].string); + break; + } +} + +static int fbnic_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return FBNIC_HW_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void fbnic_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct fbnic_net *fbn = netdev_priv(dev); + const struct fbnic_stat *stat; + int i; + + fbnic_get_hw_stats(fbn->fbd); + + for (i = 0; i < FBNIC_HW_STATS_LEN; i++) { + stat = &fbnic_gstrings_hw_stats[i]; + data[i] = *(u64 *)((u8 *)&fbn->fbd->hw_stats + stat->offset); + } +} + static void fbnic_get_eth_mac_stats(struct net_device *netdev, struct ethtool_eth_mac_stats *eth_mac_stats) @@ -64,8 +164,53 @@ fbnic_get_eth_mac_stats(struct net_device *netdev, &mac_stats->eth_mac.FrameTooLongErrors); } +static void fbnic_get_ts_stats(struct net_device *netdev, + struct ethtool_ts_stats *ts_stats) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + u64 ts_packets, ts_lost; + struct fbnic_ring *ring; + unsigned int start; + int i; + + ts_stats->pkts = fbn->tx_stats.ts_packets; + ts_stats->lost = fbn->tx_stats.ts_lost; + for (i = 0; i < fbn->num_tx_queues; i++) { + ring = fbn->tx[i]; + do { + start = u64_stats_fetch_begin(&ring->stats.syncp); + ts_packets = ring->stats.ts_packets; + ts_lost = ring->stats.ts_lost; + } while (u64_stats_fetch_retry(&ring->stats.syncp, start)); + ts_stats->pkts += ts_packets; + ts_stats->lost += ts_lost; + } +} + +static void fbnic_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *data) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + fbnic_csr_get_regs(fbn->fbd, data, ®s->version); +} + +static int fbnic_get_regs_len(struct net_device *netdev) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + return fbnic_csr_regs_len(fbn->fbd) * sizeof(u32); +} + static const struct ethtool_ops fbnic_ethtool_ops = { .get_drvinfo = fbnic_get_drvinfo, + .get_regs_len = fbnic_get_regs_len, + .get_regs = fbnic_get_regs, + .get_strings = fbnic_get_strings, + .get_ethtool_stats = fbnic_get_ethtool_stats, + .get_sset_count = fbnic_get_sset_count, + .get_ts_info = fbnic_get_ts_info, + .get_ts_stats = fbnic_get_ts_stats, .get_eth_mac_stats = fbnic_get_eth_mac_stats, }; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h index 221faf8c67566c..7cd8841920e40e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.h @@ -44,6 +44,13 @@ struct fbnic_fw_cap { u8 link_fec; }; +struct fbnic_fw_completion { + struct { + s32 millivolts; + s32 millidegrees; + } tsene; +}; + void fbnic_mbx_init(struct fbnic_dev *fbd); void fbnic_mbx_clean(struct fbnic_dev *fbd); void fbnic_mbx_poll(struct fbnic_dev *fbd); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c index a0acc7606aa1aa..89ac6bc8c7fc3c 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.c @@ -1,5 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + #include "fbnic.h" +static void fbnic_hw_stat_rst32(struct fbnic_dev *fbd, u32 reg, + struct fbnic_stat_counter *stat) +{ + /* We do not touch the "value" field here. + * It gets zeroed out on fbd structure allocation. + * After that we want it to grow continuously + * through device resets and power state changes. + */ + stat->u.old_reg_value_32 = rd32(fbd, reg); +} + +static void fbnic_hw_stat_rd32(struct fbnic_dev *fbd, u32 reg, + struct fbnic_stat_counter *stat) +{ + u32 new_reg_value; + + new_reg_value = rd32(fbd, reg); + stat->value += new_reg_value - stat->u.old_reg_value_32; + stat->u.old_reg_value_32 = new_reg_value; +} + u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset) { u32 prev_upper, upper, lower, diff; @@ -25,3 +49,172 @@ u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset) */ return ((u64)upper << 32); } + +static void fbnic_hw_stat_rst64(struct fbnic_dev *fbd, u32 reg, s32 offset, + struct fbnic_stat_counter *stat) +{ + /* Record initial counter values and compute deltas from there to ensure + * stats start at 0 after reboot/reset. This avoids exposing absolute + * hardware counter values to userspace. + */ + stat->u.old_reg_value_64 = fbnic_stat_rd64(fbd, reg, offset); +} + +static void fbnic_hw_stat_rd64(struct fbnic_dev *fbd, u32 reg, s32 offset, + struct fbnic_stat_counter *stat) +{ + u64 new_reg_value; + + new_reg_value = fbnic_stat_rd64(fbd, reg, offset); + stat->value += new_reg_value - stat->u.old_reg_value_64; + stat->u.old_reg_value_64 = new_reg_value; +} + +static void fbnic_reset_rpc_stats(struct fbnic_dev *fbd, + struct fbnic_rpc_stats *rpc) +{ + fbnic_hw_stat_rst32(fbd, + FBNIC_RPC_CNTR_UNKN_ETYPE, + &rpc->unkn_etype); + fbnic_hw_stat_rst32(fbd, + FBNIC_RPC_CNTR_UNKN_EXT_HDR, + &rpc->unkn_ext_hdr); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp); + fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err); + fbnic_hw_stat_rst32(fbd, + FBNIC_RPC_CNTR_OUT_OF_HDR_ERR, + &rpc->out_of_hdr_err); + fbnic_hw_stat_rst32(fbd, + FBNIC_RPC_CNTR_OVR_SIZE_ERR, + &rpc->ovr_size_err); +} + +static void fbnic_get_rpc_stats32(struct fbnic_dev *fbd, + struct fbnic_rpc_stats *rpc) +{ + fbnic_hw_stat_rd32(fbd, + FBNIC_RPC_CNTR_UNKN_ETYPE, + &rpc->unkn_etype); + fbnic_hw_stat_rd32(fbd, + FBNIC_RPC_CNTR_UNKN_EXT_HDR, + &rpc->unkn_ext_hdr); + + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag); + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag); + + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp); + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp); + + fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err); + fbnic_hw_stat_rd32(fbd, + FBNIC_RPC_CNTR_OUT_OF_HDR_ERR, + &rpc->out_of_hdr_err); + fbnic_hw_stat_rd32(fbd, + FBNIC_RPC_CNTR_OVR_SIZE_ERR, + &rpc->ovr_size_err); +} + +static void fbnic_reset_pcie_stats_asic(struct fbnic_dev *fbd, + struct fbnic_pcie_stats *pcie) +{ + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_RD_TLP_CNT_31_0, + 1, + &pcie->ob_rd_tlp); + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_RD_DWORD_CNT_31_0, + 1, + &pcie->ob_rd_dword); + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_CPL_TLP_CNT_31_0, + 1, + &pcie->ob_cpl_tlp); + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_CPL_DWORD_CNT_31_0, + 1, + &pcie->ob_cpl_dword); + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_WR_TLP_CNT_31_0, + 1, + &pcie->ob_wr_tlp); + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_WR_DWORD_CNT_31_0, + 1, + &pcie->ob_wr_dword); + + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_RD_DBG_CNT_TAG_31_0, + 1, + &pcie->ob_rd_no_tag); + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_RD_DBG_CNT_CPL_CRED_31_0, + 1, + &pcie->ob_rd_no_cpl_cred); + fbnic_hw_stat_rst64(fbd, + FBNIC_PUL_USER_OB_RD_DBG_CNT_NP_CRED_31_0, + 1, + &pcie->ob_rd_no_np_cred); +} + +static void fbnic_get_pcie_stats_asic64(struct fbnic_dev *fbd, + struct fbnic_pcie_stats *pcie) +{ + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_RD_TLP_CNT_31_0, + 1, + &pcie->ob_rd_tlp); + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_RD_DWORD_CNT_31_0, + 1, + &pcie->ob_rd_dword); + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_WR_TLP_CNT_31_0, + 1, + &pcie->ob_wr_tlp); + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_WR_DWORD_CNT_31_0, + 1, + &pcie->ob_wr_dword); + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_CPL_TLP_CNT_31_0, + 1, + &pcie->ob_cpl_tlp); + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_CPL_DWORD_CNT_31_0, + 1, + &pcie->ob_cpl_dword); + + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_RD_DBG_CNT_TAG_31_0, + 1, + &pcie->ob_rd_no_tag); + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_RD_DBG_CNT_CPL_CRED_31_0, + 1, + &pcie->ob_rd_no_cpl_cred); + fbnic_hw_stat_rd64(fbd, + FBNIC_PUL_USER_OB_RD_DBG_CNT_NP_CRED_31_0, + 1, + &pcie->ob_rd_no_np_cred); +} + +void fbnic_reset_hw_stats(struct fbnic_dev *fbd) +{ + fbnic_reset_rpc_stats(fbd, &fbd->hw_stats.rpc); + fbnic_reset_pcie_stats_asic(fbd, &fbd->hw_stats.pcie); +} + +void fbnic_get_hw_stats32(struct fbnic_dev *fbd) +{ + fbnic_get_rpc_stats32(fbd, &fbd->hw_stats.rpc); +} + +void fbnic_get_hw_stats(struct fbnic_dev *fbd) +{ + fbnic_get_hw_stats32(fbd); + + fbnic_get_pcie_stats_asic64(fbd, &fbd->hw_stats.pcie); +} diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h index 30348904b51072..78df56b8774569 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_hw_stats.h @@ -1,3 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + +#ifndef _FBNIC_HW_STATS_H_ +#define _FBNIC_HW_STATS_H_ + #include #include "fbnic_csr.h" @@ -31,10 +37,32 @@ struct fbnic_mac_stats { struct fbnic_eth_mac_stats eth_mac; }; +struct fbnic_rpc_stats { + struct fbnic_stat_counter unkn_etype, unkn_ext_hdr; + struct fbnic_stat_counter ipv4_frag, ipv6_frag, ipv4_esp, ipv6_esp; + struct fbnic_stat_counter tcp_opt_err, out_of_hdr_err, ovr_size_err; +}; + +struct fbnic_pcie_stats { + struct fbnic_stat_counter ob_rd_tlp, ob_rd_dword; + struct fbnic_stat_counter ob_wr_tlp, ob_wr_dword; + struct fbnic_stat_counter ob_cpl_tlp, ob_cpl_dword; + + struct fbnic_stat_counter ob_rd_no_tag; + struct fbnic_stat_counter ob_rd_no_cpl_cred; + struct fbnic_stat_counter ob_rd_no_np_cred; +}; + struct fbnic_hw_stats { struct fbnic_mac_stats mac; + struct fbnic_rpc_stats rpc; + struct fbnic_pcie_stats pcie; }; u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset); +void fbnic_reset_hw_stats(struct fbnic_dev *fbd); +void fbnic_get_hw_stats32(struct fbnic_dev *fbd); void fbnic_get_hw_stats(struct fbnic_dev *fbd); + +#endif /* _FBNIC_HW_STATS_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c new file mode 100644 index 00000000000000..bcd1086e3768e1 --- /dev/null +++ b/drivers/net/ethernet/meta/fbnic/fbnic_hwmon.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + +#include + +#include "fbnic.h" +#include "fbnic_mac.h" + +static int fbnic_hwmon_sensor_id(enum hwmon_sensor_types type) +{ + if (type == hwmon_temp) + return FBNIC_SENSOR_TEMP; + if (type == hwmon_in) + return FBNIC_SENSOR_VOLTAGE; + + return -EOPNOTSUPP; +} + +static umode_t fbnic_hwmon_is_visible(const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type == hwmon_temp && attr == hwmon_temp_input) + return 0444; + if (type == hwmon_in && attr == hwmon_in_input) + return 0444; + + return 0; +} + +static int fbnic_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct fbnic_dev *fbd = dev_get_drvdata(dev); + const struct fbnic_mac *mac = fbd->mac; + int id; + + id = fbnic_hwmon_sensor_id(type); + return id < 0 ? id : mac->get_sensor(fbd, id, val); +} + +static const struct hwmon_ops fbnic_hwmon_ops = { + .is_visible = fbnic_hwmon_is_visible, + .read = fbnic_hwmon_read, +}; + +static const struct hwmon_channel_info *fbnic_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), + NULL +}; + +static const struct hwmon_chip_info fbnic_chip_info = { + .ops = &fbnic_hwmon_ops, + .info = fbnic_hwmon_info, +}; + +void fbnic_hwmon_register(struct fbnic_dev *fbd) +{ + if (!IS_REACHABLE(CONFIG_HWMON)) + return; + + fbd->hwmon = hwmon_device_register_with_info(fbd->dev, "fbnic", + fbd, &fbnic_chip_info, + NULL); + if (IS_ERR(fbd->hwmon)) { + dev_notice(fbd->dev, + "Failed to register hwmon device %pe\n", + fbd->hwmon); + fbd->hwmon = NULL; + } +} + +void fbnic_hwmon_unregister(struct fbnic_dev *fbd) +{ + if (!IS_REACHABLE(CONFIG_HWMON) || !fbd->hwmon) + return; + + hwmon_device_unregister(fbd->hwmon); + fbd->hwmon = NULL; +} diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c index 7b654d0a6dac66..80b82ff12c4d4f 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.c @@ -686,6 +686,27 @@ fbnic_mac_get_eth_mac_stats(struct fbnic_dev *fbd, bool reset, MAC_STAT_TX_BROADCAST); } +static int fbnic_mac_get_sensor_asic(struct fbnic_dev *fbd, int id, long *val) +{ + struct fbnic_fw_completion fw_cmpl; + s32 *sensor; + + switch (id) { + case FBNIC_SENSOR_TEMP: + sensor = &fw_cmpl.tsene.millidegrees; + break; + case FBNIC_SENSOR_VOLTAGE: + sensor = &fw_cmpl.tsene.millivolts; + break; + default: + return -EINVAL; + } + + *val = *sensor; + + return 0; +} + static const struct fbnic_mac fbnic_mac_asic = { .init_regs = fbnic_mac_init_regs, .pcs_enable = fbnic_pcs_enable_asic, @@ -695,6 +716,7 @@ static const struct fbnic_mac fbnic_mac_asic = { .get_eth_mac_stats = fbnic_mac_get_eth_mac_stats, .link_down = fbnic_mac_link_down_asic, .link_up = fbnic_mac_link_up_asic, + .get_sensor = fbnic_mac_get_sensor_asic, }; /** diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h index 476239a9d381e1..05a591653e0916 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_mac.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_mac.h @@ -47,6 +47,11 @@ enum { #define FBNIC_LINK_MODE_PAM4 (FBNIC_LINK_50R1) #define FBNIC_LINK_MODE_MASK (FBNIC_LINK_AUTO - 1) +enum fbnic_sensor_id { + FBNIC_SENSOR_TEMP, /* Temp in millidegrees Centigrade */ + FBNIC_SENSOR_VOLTAGE, /* Voltage in millivolts */ +}; + /* This structure defines the interface hooks for the MAC. The MAC hooks * will be configured as a const struct provided with a set of function * pointers. @@ -83,6 +88,8 @@ struct fbnic_mac { void (*link_down)(struct fbnic_dev *fbd); void (*link_up)(struct fbnic_dev *fbd, bool tx_pause, bool rx_pause); + + int (*get_sensor)(struct fbnic_dev *fbd, int id, long *val); }; int fbnic_mac_init(struct fbnic_dev *fbd); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c index a400616a24d416..fc7d80db5fa6d2 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c @@ -42,18 +42,24 @@ int __fbnic_open(struct fbnic_net *fbn) goto free_resources; } - err = fbnic_fw_init_heartbeat(fbd, false); + err = fbnic_time_start(fbn); if (err) goto release_ownership; + err = fbnic_fw_init_heartbeat(fbd, false); + if (err) + goto time_stop; + err = fbnic_pcs_irq_enable(fbd); if (err) - goto release_ownership; + goto time_stop; /* Pull the BMC config and initialize the RPC */ fbnic_bmc_rpc_init(fbd); fbnic_rss_reinit(fbd, fbn); return 0; +time_stop: + fbnic_time_stop(fbn); release_ownership: fbnic_fw_xmit_ownership_msg(fbn->fbd, false); free_resources: @@ -82,6 +88,7 @@ static int fbnic_stop(struct net_device *netdev) fbnic_down(fbn); fbnic_pcs_irq_disable(fbn->fbd); + fbnic_time_stop(fbn); fbnic_fw_xmit_ownership_msg(fbn->fbd, false); fbnic_free_resources(fbn); @@ -266,6 +273,7 @@ void __fbnic_set_rx_mode(struct net_device *netdev) /* Write updates to hardware */ fbnic_write_rules(fbd); fbnic_write_macda(fbd); + fbnic_write_tce_tcam(fbd); } static void fbnic_set_rx_mode(struct net_device *netdev) @@ -317,6 +325,84 @@ void fbnic_clear_rx_mode(struct net_device *netdev) __dev_mc_unsync(netdev, NULL); } +static int fbnic_hwtstamp_get(struct net_device *netdev, + struct kernel_hwtstamp_config *config) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + + *config = fbn->hwtstamp_config; + + return 0; +} + +static int fbnic_hwtstamp_set(struct net_device *netdev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) +{ + struct fbnic_net *fbn = netdev_priv(netdev); + int old_rx_filter; + + if (config->source != HWTSTAMP_SOURCE_NETDEV) + return -EOPNOTSUPP; + + if (!kernel_hwtstamp_config_changed(config, &fbn->hwtstamp_config)) + return 0; + + /* Upscale the filters */ + switch (config->rx_filter) { + case HWTSTAMP_FILTER_NONE: + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + break; + case HWTSTAMP_FILTER_NTP_ALL: + config->rx_filter = HWTSTAMP_FILTER_ALL; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + break; + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; + break; + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + break; + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + default: + return -ERANGE; + } + + /* Configure */ + old_rx_filter = fbn->hwtstamp_config.rx_filter; + memcpy(&fbn->hwtstamp_config, config, sizeof(*config)); + + if (old_rx_filter != config->rx_filter && netif_running(fbn->netdev)) { + fbnic_rss_reinit(fbn->fbd, fbn); + fbnic_write_rules(fbn->fbd); + } + + /* Save / report back filter configuration + * Note that our filter configuration is inexact. Instead of + * filtering for a specific UDP port or L2 Ethertype we are + * filtering in all UDP or all non-IP packets for timestamping. So + * if anything other than FILTER_ALL is requested we report + * FILTER_SOME indicating that we will be timestamping a few + * additional packets. + */ + if (config->rx_filter > HWTSTAMP_FILTER_ALL) + config->rx_filter = HWTSTAMP_FILTER_SOME; + + return 0; +} + static void fbnic_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64) { @@ -394,6 +480,8 @@ static const struct net_device_ops fbnic_netdev_ops = { .ndo_set_mac_address = fbnic_set_mac, .ndo_set_rx_mode = fbnic_set_rx_mode, .ndo_get_stats64 = fbnic_get_stats64, + .ndo_hwtstamp_get = fbnic_hwtstamp_get, + .ndo_hwtstamp_set = fbnic_hwtstamp_set, }; static void fbnic_get_queue_stats_rx(struct net_device *dev, int idx, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h index 6c27da09a6122b..b8417b30077887 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.h @@ -33,6 +33,15 @@ struct fbnic_net { u8 fec; u8 link_mode; + /* Cached top bits of the HW time counter for 40b -> 64b conversion */ + u32 time_high; + /* Protect readers of @time_offset, writers take @time_lock. */ + struct u64_stats_sync time_seq; + /* Offset in ns between free running NIC PHC and time set via PTP + * clock callbacks + */ + s64 time_offset; + u16 num_tx_queues; u16 num_rx_queues; @@ -45,6 +54,9 @@ struct fbnic_net { struct fbnic_queue_stats rx_stats; u64 link_down_events; + /* Time stampinn filter config */ + struct kernel_hwtstamp_config hwtstamp_config; + struct list_head napis; }; @@ -60,6 +72,12 @@ void fbnic_reset_queues(struct fbnic_net *fbn, unsigned int tx, unsigned int rx); void fbnic_set_ethtool_ops(struct net_device *dev); +int fbnic_ptp_setup(struct fbnic_dev *fbd); +void fbnic_ptp_destroy(struct fbnic_dev *fbd); +void fbnic_time_init(struct fbnic_net *fbn); +int fbnic_time_start(struct fbnic_net *fbn); +void fbnic_time_stop(struct fbnic_net *fbn); + void __fbnic_set_rx_mode(struct net_device *netdev); void fbnic_clear_rx_mode(struct net_device *netdev); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c index a4809fe0fc2496..32702dc4a06674 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_pci.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_pci.c @@ -9,6 +9,7 @@ #include "fbnic.h" #include "fbnic_drvinfo.h" +#include "fbnic_hw_stats.h" #include "fbnic_netdev.h" char fbnic_driver_name[] = DRV_NAME; @@ -198,6 +199,8 @@ static void fbnic_service_task(struct work_struct *work) rtnl_lock(); + fbnic_get_hw_stats32(fbd); + fbnic_fw_check_heartbeat(fbd); fbnic_health_check(fbd); @@ -288,6 +291,12 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } fbnic_devlink_register(fbd); + fbnic_dbg_fbd_init(fbd); + + /* Capture snapshot of hardware stats so netdev can calculate delta */ + fbnic_reset_hw_stats(fbd); + + fbnic_hwmon_register(fbd); if (!fbd->dsn) { dev_warn(&pdev->dev, "Reading serial number failed\n"); @@ -300,14 +309,20 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto init_failure_mode; } + err = fbnic_ptp_setup(fbd); + if (err) + goto ifm_free_netdev; + err = fbnic_netdev_register(netdev); if (err) { dev_err(&pdev->dev, "Netdev registration failed: %d\n", err); - goto ifm_free_netdev; + goto ifm_destroy_ptp; } return 0; +ifm_destroy_ptp: + fbnic_ptp_destroy(fbd); ifm_free_netdev: fbnic_netdev_free(fbd); init_failure_mode: @@ -319,7 +334,6 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) free_irqs: fbnic_free_irqs(fbd); free_fbd: - pci_disable_device(pdev); fbnic_devlink_free(fbd); return err; @@ -342,14 +356,16 @@ static void fbnic_remove(struct pci_dev *pdev) fbnic_netdev_unregister(netdev); cancel_delayed_work_sync(&fbd->service_task); + fbnic_ptp_destroy(fbd); fbnic_netdev_free(fbd); } + fbnic_hwmon_unregister(fbd); + fbnic_dbg_fbd_exit(fbd); fbnic_devlink_unregister(fbd); fbnic_fw_disable_mbx(fbd); fbnic_free_irqs(fbd); - pci_disable_device(pdev); fbnic_devlink_free(fbd); } @@ -542,9 +558,13 @@ static int __init fbnic_init_module(void) { int err; + fbnic_dbg_init(); + err = pci_register_driver(&fbnic_driver); - if (err) + if (err) { + fbnic_dbg_exit(); goto out; + } pr_info(DRV_SUMMARY " (%s)", fbnic_driver.name); out: @@ -560,5 +580,7 @@ module_init(fbnic_init_module); static void __exit fbnic_exit_module(void) { pci_unregister_driver(&fbnic_driver); + + fbnic_dbg_exit(); } module_exit(fbnic_exit_module); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c index c8aa29fc052b52..908c098cd59e71 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.c @@ -244,6 +244,12 @@ void fbnic_bmc_rpc_init(struct fbnic_dev *fbd) ((_ip) ? FBNIC_RPC_TCAM_ACT1_IP_VALID : 0) | \ ((_v6) ? FBNIC_RPC_TCAM_ACT1_IP_IS_V6 : 0)) +#define FBNIC_TSTAMP_MASK(_all, _udp, _ether) \ + (((_all) ? ((1u << FBNIC_NUM_HASH_OPT) - 1) : 0) | \ + ((_udp) ? (1u << FBNIC_UDP6_HASH_OPT) | \ + (1u << FBNIC_UDP4_HASH_OPT) : 0) | \ + ((_ether) ? (1u << FBNIC_ETHER_HASH_OPT) : 0)) + void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn) { static const u32 act1_value[FBNIC_NUM_HASH_OPT] = { @@ -255,6 +261,7 @@ void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn) FBNIC_ACT1_INIT(0, 0, 1, 0), /* IP4 */ 0 /* Ether */ }; + u32 tstamp_mask = 0; unsigned int i; /* To support scenarios where a BMC is present we must write the @@ -264,6 +271,28 @@ void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn) BUILD_BUG_ON(FBNIC_RSS_EN_NUM_UNICAST * 2 != FBNIC_RSS_EN_NUM_ENTRIES); BUILD_BUG_ON(ARRAY_SIZE(act1_value) != FBNIC_NUM_HASH_OPT); + /* Set timestamp mask with 1b per flow type */ + if (fbn->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) { + switch (fbn->hwtstamp_config.rx_filter) { + case HWTSTAMP_FILTER_ALL: + tstamp_mask = FBNIC_TSTAMP_MASK(1, 1, 1); + break; + case HWTSTAMP_FILTER_PTP_V2_EVENT: + tstamp_mask = FBNIC_TSTAMP_MASK(0, 1, 1); + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + tstamp_mask = FBNIC_TSTAMP_MASK(0, 1, 0); + break; + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + tstamp_mask = FBNIC_TSTAMP_MASK(0, 0, 1); + break; + default: + netdev_warn(fbn->netdev, "Unsupported hwtstamp_rx_filter\n"); + break; + } + } + /* Program RSS hash enable mask for host in action TCAM/table. */ for (i = fbnic_bmc_present(fbd) ? 0 : FBNIC_RSS_EN_NUM_UNICAST; i < FBNIC_RSS_EN_NUM_ENTRIES; i++) { @@ -287,6 +316,8 @@ void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn) if (!dest) dest = FBNIC_RPC_ACT_TBL0_DROP; + else if (tstamp_mask & (1u << flow_type)) + dest |= FBNIC_RPC_ACT_TBL0_TS_ENA; if (act1_value[flow_type] & FBNIC_RPC_TCAM_ACT1_L4_VALID) dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DMA_HINT, @@ -556,6 +587,116 @@ static void fbnic_clear_act_tcam(struct fbnic_dev *fbd, unsigned int idx) wr32(fbd, FBNIC_RPC_TCAM_ACT(idx, i), 0); } +static void fbnic_clear_tce_tcam_entry(struct fbnic_dev *fbd, unsigned int idx) +{ + int i; + + /* Invalidate entry and clear addr state info */ + for (i = 0; i <= FBNIC_TCE_TCAM_WORD_LEN; i++) + wr32(fbd, FBNIC_TCE_RAM_TCAM(idx, i), 0); +} + +static void fbnic_write_tce_tcam_dest(struct fbnic_dev *fbd, unsigned int idx, + struct fbnic_mac_addr *mac_addr) +{ + u32 dest = FBNIC_TCE_TCAM_DEST_BMC; + u32 idx2dest_map; + + if (is_multicast_ether_addr(mac_addr->value.addr8)) + dest |= FBNIC_TCE_TCAM_DEST_MAC; + + idx2dest_map = rd32(fbd, FBNIC_TCE_TCAM_IDX2DEST_MAP); + idx2dest_map &= ~(FBNIC_TCE_TCAM_IDX2DEST_MAP_DEST_ID_0 << (4 * idx)); + idx2dest_map |= dest << (4 * idx); + + wr32(fbd, FBNIC_TCE_TCAM_IDX2DEST_MAP, idx2dest_map); +} + +static void fbnic_write_tce_tcam_entry(struct fbnic_dev *fbd, unsigned int idx, + struct fbnic_mac_addr *mac_addr) +{ + __be16 *mask, *value; + int i; + + mask = &mac_addr->mask.addr16[FBNIC_TCE_TCAM_WORD_LEN - 1]; + value = &mac_addr->value.addr16[FBNIC_TCE_TCAM_WORD_LEN - 1]; + + for (i = 0; i < FBNIC_TCE_TCAM_WORD_LEN; i++) + wr32(fbd, FBNIC_TCE_RAM_TCAM(idx, i), + FIELD_PREP(FBNIC_TCE_RAM_TCAM_MASK, ntohs(*mask--)) | + FIELD_PREP(FBNIC_TCE_RAM_TCAM_VALUE, ntohs(*value--))); + + wrfl(fbd); + + wr32(fbd, FBNIC_TCE_RAM_TCAM3(idx), FBNIC_TCE_RAM_TCAM3_MCQ_MASK | + FBNIC_TCE_RAM_TCAM3_DEST_MASK | + FBNIC_TCE_RAM_TCAM3_VALIDATE); +} + +static void __fbnic_write_tce_tcam_rev(struct fbnic_dev *fbd) +{ + int tcam_idx = FBNIC_TCE_TCAM_NUM_ENTRIES; + int mac_idx; + + for (mac_idx = ARRAY_SIZE(fbd->mac_addr); mac_idx--;) { + struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[mac_idx]; + + /* Verify BMC bit is set */ + if (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) + continue; + + if (!tcam_idx) { + dev_err(fbd->dev, "TCE TCAM overflow\n"); + return; + } + + tcam_idx--; + fbnic_write_tce_tcam_dest(fbd, tcam_idx, mac_addr); + fbnic_write_tce_tcam_entry(fbd, tcam_idx, mac_addr); + } + + while (tcam_idx) + fbnic_clear_tce_tcam_entry(fbd, --tcam_idx); + + fbd->tce_tcam_last = tcam_idx; +} + +static void __fbnic_write_tce_tcam(struct fbnic_dev *fbd) +{ + int tcam_idx = 0; + int mac_idx; + + for (mac_idx = 0; mac_idx < ARRAY_SIZE(fbd->mac_addr); mac_idx++) { + struct fbnic_mac_addr *mac_addr = &fbd->mac_addr[mac_idx]; + + /* Verify BMC bit is set */ + if (!test_bit(FBNIC_MAC_ADDR_T_BMC, mac_addr->act_tcam)) + continue; + + if (tcam_idx == FBNIC_TCE_TCAM_NUM_ENTRIES) { + dev_err(fbd->dev, "TCE TCAM overflow\n"); + return; + } + + fbnic_write_tce_tcam_dest(fbd, tcam_idx, mac_addr); + fbnic_write_tce_tcam_entry(fbd, tcam_idx, mac_addr); + tcam_idx++; + } + + while (tcam_idx < FBNIC_TCE_TCAM_NUM_ENTRIES) + fbnic_clear_tce_tcam_entry(fbd, tcam_idx++); + + fbd->tce_tcam_last = tcam_idx; +} + +void fbnic_write_tce_tcam(struct fbnic_dev *fbd) +{ + if (fbd->tce_tcam_last) + __fbnic_write_tce_tcam_rev(fbd); + else + __fbnic_write_tce_tcam(fbd); +} + void fbnic_clear_rules(struct fbnic_dev *fbd) { u32 dest = FIELD_PREP(FBNIC_RPC_ACT_TBL0_DEST_MASK, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h index d62935f722a2c2..0d8285fa5b4540 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_rpc.h @@ -35,6 +35,9 @@ enum { #define FBNIC_RPC_TCAM_ACT_WORD_LEN 11 #define FBNIC_RPC_TCAM_ACT_NUM_ENTRIES 64 +#define FBNIC_TCE_TCAM_WORD_LEN 3 +#define FBNIC_TCE_TCAM_NUM_ENTRIES 8 + struct fbnic_mac_addr { union { unsigned char addr8[ETH_ALEN]; @@ -186,4 +189,5 @@ static inline int __fbnic_mc_unsync(struct fbnic_mac_addr *mac_addr) void fbnic_clear_rules(struct fbnic_dev *fbd); void fbnic_write_rules(struct fbnic_dev *fbd); +void fbnic_write_tce_tcam(struct fbnic_dev *fbd); #endif /* _FBNIC_RPC_H_ */ diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_time.c b/drivers/net/ethernet/meta/fbnic/fbnic_time.c new file mode 100644 index 00000000000000..39d99677b71ea7 --- /dev/null +++ b/drivers/net/ethernet/meta/fbnic/fbnic_time.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include +#include + +#include "fbnic.h" +#include "fbnic_csr.h" +#include "fbnic_netdev.h" + +/* FBNIC timing & PTP implementation + * Datapath uses truncated 40b timestamps for scheduling and event reporting. + * We need to promote those to full 64b, hence we periodically cache the top + * 32bit of the HW time counter. Since this makes our time reporting non-atomic + * we leave the HW clock free running and adjust time offsets in SW as needed. + * Time offset is 64bit - we need a seq counter for 32bit machines. + * Time offset and the cache of top bits are independent so we don't need + * a coherent snapshot of both - READ_ONCE()/WRITE_ONCE() + writer side lock + * are enough. + */ + +/* Period of refresh of top bits of timestamp, give ourselves a 8x margin. + * This should translate to once a minute. + * The use of nsecs_to_jiffies() should be safe for a <=40b nsec value. + */ +#define FBNIC_TS_HIGH_REFRESH_JIF nsecs_to_jiffies((1ULL << 40) / 16) + +static struct fbnic_dev *fbnic_from_ptp_info(struct ptp_clock_info *ptp) +{ + return container_of(ptp, struct fbnic_dev, ptp_info); +} + +/* This function is "slow" because we could try guessing which high part + * is correct based on low instead of re-reading, and skip reading @hi + * twice altogether if @lo is far enough from 0. + */ +static u64 __fbnic_time_get_slow(struct fbnic_dev *fbd) +{ + u32 hi, lo; + + lockdep_assert_held(&fbd->time_lock); + + do { + hi = fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_HI); + lo = fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_LO); + } while (hi != fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_HI)); + + return (u64)hi << 32 | lo; +} + +static void __fbnic_time_set_addend(struct fbnic_dev *fbd, u64 addend) +{ + lockdep_assert_held(&fbd->time_lock); + + fbnic_wr32(fbd, FBNIC_PTP_ADD_VAL_NS, + FIELD_PREP(FBNIC_PTP_ADD_VAL_NS_MASK, addend >> 32)); + fbnic_wr32(fbd, FBNIC_PTP_ADD_VAL_SUBNS, (u32)addend); +} + +static void fbnic_ptp_fresh_check(struct fbnic_dev *fbd) +{ + if (time_is_after_jiffies(fbd->last_read + + FBNIC_TS_HIGH_REFRESH_JIF * 3 / 2)) + return; + + dev_warn(fbd->dev, "NIC timestamp refresh stall, delayed by %lu sec\n", + (jiffies - fbd->last_read - FBNIC_TS_HIGH_REFRESH_JIF) / HZ); +} + +static void fbnic_ptp_refresh_time(struct fbnic_dev *fbd, struct fbnic_net *fbn) +{ + unsigned long flags; + u32 hi; + + spin_lock_irqsave(&fbd->time_lock, flags); + hi = fbnic_rd32(fbn->fbd, FBNIC_PTP_CTR_VAL_HI); + if (!fbnic_present(fbd)) + goto out; /* Don't bother handling, reset is pending */ + /* Let's keep high cached value a bit lower to avoid race with + * incoming timestamps. The logic in fbnic_ts40_to_ns() will + * take care of overflow in this case. It will make cached time + * ~1 minute lower and incoming timestamp will always be later + * then cached time. + */ + WRITE_ONCE(fbn->time_high, hi - 16); + fbd->last_read = jiffies; + out: + spin_unlock_irqrestore(&fbd->time_lock, flags); +} + +static long fbnic_ptp_do_aux_work(struct ptp_clock_info *ptp) +{ + struct fbnic_dev *fbd = fbnic_from_ptp_info(ptp); + struct fbnic_net *fbn; + + fbn = netdev_priv(fbd->netdev); + + fbnic_ptp_fresh_check(fbd); + fbnic_ptp_refresh_time(fbd, fbn); + + return FBNIC_TS_HIGH_REFRESH_JIF; +} + +static int fbnic_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct fbnic_dev *fbd = fbnic_from_ptp_info(ptp); + u64 addend, dclk_period; + unsigned long flags; + + /* d_clock is 600 MHz; which in Q16.32 fixed point ns is: */ + dclk_period = (((u64)1000000000) << 32) / FBNIC_CLOCK_FREQ; + addend = adjust_by_scaled_ppm(dclk_period, scaled_ppm); + + spin_lock_irqsave(&fbd->time_lock, flags); + __fbnic_time_set_addend(fbd, addend); + fbnic_wr32(fbd, FBNIC_PTP_ADJUST, FBNIC_PTP_ADJUST_ADDEND_SET); + + /* Flush, make sure FBNIC_PTP_ADD_VAL_* is stable for at least 4 clks */ + fbnic_rd32(fbd, FBNIC_PTP_SPARE); + spin_unlock_irqrestore(&fbd->time_lock, flags); + + return fbnic_present(fbd) ? 0 : -EIO; +} + +static int fbnic_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct fbnic_dev *fbd = fbnic_from_ptp_info(ptp); + struct fbnic_net *fbn; + unsigned long flags; + + fbn = netdev_priv(fbd->netdev); + + spin_lock_irqsave(&fbd->time_lock, flags); + u64_stats_update_begin(&fbn->time_seq); + WRITE_ONCE(fbn->time_offset, READ_ONCE(fbn->time_offset) + delta); + u64_stats_update_end(&fbn->time_seq); + spin_unlock_irqrestore(&fbd->time_lock, flags); + + return 0; +} + +static int +fbnic_ptp_gettimex64(struct ptp_clock_info *ptp, struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct fbnic_dev *fbd = fbnic_from_ptp_info(ptp); + struct fbnic_net *fbn; + unsigned long flags; + u64 time_ns; + u32 hi, lo; + + fbn = netdev_priv(fbd->netdev); + + spin_lock_irqsave(&fbd->time_lock, flags); + + do { + hi = fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_HI); + ptp_read_system_prets(sts); + lo = fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_LO); + ptp_read_system_postts(sts); + /* Similarly to comment above __fbnic_time_get_slow() + * - this can be optimized if needed. + */ + } while (hi != fbnic_rd32(fbd, FBNIC_PTP_CTR_VAL_HI)); + + time_ns = ((u64)hi << 32 | lo) + fbn->time_offset; + spin_unlock_irqrestore(&fbd->time_lock, flags); + + if (!fbnic_present(fbd)) + return -EIO; + + *ts = ns_to_timespec64(time_ns); + + return 0; +} + +static int +fbnic_ptp_settime64(struct ptp_clock_info *ptp, const struct timespec64 *ts) +{ + struct fbnic_dev *fbd = fbnic_from_ptp_info(ptp); + struct fbnic_net *fbn; + unsigned long flags; + u64 dev_ns, host_ns; + int ret; + + fbn = netdev_priv(fbd->netdev); + + host_ns = timespec64_to_ns(ts); + + spin_lock_irqsave(&fbd->time_lock, flags); + + dev_ns = __fbnic_time_get_slow(fbd); + + if (fbnic_present(fbd)) { + u64_stats_update_begin(&fbn->time_seq); + WRITE_ONCE(fbn->time_offset, host_ns - dev_ns); + u64_stats_update_end(&fbn->time_seq); + ret = 0; + } else { + ret = -EIO; + } + spin_unlock_irqrestore(&fbd->time_lock, flags); + + return ret; +} + +static const struct ptp_clock_info fbnic_ptp_info = { + .owner = THIS_MODULE, + /* 1,000,000,000 - 1 PPB to ensure increment is positive + * after max negative adjustment. + */ + .max_adj = 999999999, + .do_aux_work = fbnic_ptp_do_aux_work, + .adjfine = fbnic_ptp_adjfine, + .adjtime = fbnic_ptp_adjtime, + .gettimex64 = fbnic_ptp_gettimex64, + .settime64 = fbnic_ptp_settime64, +}; + +static void fbnic_ptp_reset(struct fbnic_dev *fbd) +{ + struct fbnic_net *fbn = netdev_priv(fbd->netdev); + u64 dclk_period; + + fbnic_wr32(fbd, FBNIC_PTP_CTRL, + FBNIC_PTP_CTRL_EN | + FIELD_PREP(FBNIC_PTP_CTRL_TICK_IVAL, 1)); + + /* d_clock is 600 MHz; which in Q16.32 fixed point ns is: */ + dclk_period = (((u64)1000000000) << 32) / FBNIC_CLOCK_FREQ; + + __fbnic_time_set_addend(fbd, dclk_period); + + fbnic_wr32(fbd, FBNIC_PTP_INIT_HI, 0); + fbnic_wr32(fbd, FBNIC_PTP_INIT_LO, 0); + + fbnic_wr32(fbd, FBNIC_PTP_ADJUST, FBNIC_PTP_ADJUST_INIT); + + fbnic_wr32(fbd, FBNIC_PTP_CTRL, + FBNIC_PTP_CTRL_EN | + FBNIC_PTP_CTRL_TQS_OUT_EN | + FIELD_PREP(FBNIC_PTP_CTRL_MAC_OUT_IVAL, 3) | + FIELD_PREP(FBNIC_PTP_CTRL_TICK_IVAL, 1)); + + fbnic_rd32(fbd, FBNIC_PTP_SPARE); + + fbn->time_offset = 0; + fbn->time_high = 0; +} + +void fbnic_time_init(struct fbnic_net *fbn) +{ + /* This is not really a statistic, but the lockng primitive fits + * our usecase perfectly, we need an atomic 8 bytes READ_ONCE() / + * WRITE_ONCE() behavior. + */ + u64_stats_init(&fbn->time_seq); +} + +int fbnic_time_start(struct fbnic_net *fbn) +{ + fbnic_ptp_refresh_time(fbn->fbd, fbn); + /* Assume that fbnic_ptp_do_aux_work() will never be called if not + * scheduled here + */ + return ptp_schedule_worker(fbn->fbd->ptp, FBNIC_TS_HIGH_REFRESH_JIF); +} + +void fbnic_time_stop(struct fbnic_net *fbn) +{ + ptp_cancel_worker_sync(fbn->fbd->ptp); + fbnic_ptp_fresh_check(fbn->fbd); +} + +int fbnic_ptp_setup(struct fbnic_dev *fbd) +{ + struct device *dev = fbd->dev; + unsigned long flags; + + spin_lock_init(&fbd->time_lock); + + spin_lock_irqsave(&fbd->time_lock, flags); /* Appease lockdep */ + fbnic_ptp_reset(fbd); + spin_unlock_irqrestore(&fbd->time_lock, flags); + + memcpy(&fbd->ptp_info, &fbnic_ptp_info, sizeof(fbnic_ptp_info)); + + fbd->ptp = ptp_clock_register(&fbd->ptp_info, dev); + if (IS_ERR(fbd->ptp)) + dev_err(dev, "Failed to register PTP: %pe\n", fbd->ptp); + + return PTR_ERR_OR_ZERO(fbd->ptp); +} + +void fbnic_ptp_destroy(struct fbnic_dev *fbd) +{ + if (!fbd->ptp) + return; + ptp_clock_unregister(fbd->ptp); +} diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 6a6d7e22f1a722..b5050fabe8fe82 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -12,9 +12,14 @@ #include "fbnic_netdev.h" #include "fbnic_txrx.h" +enum { + FBNIC_XMIT_CB_TS = 0x01, +}; + struct fbnic_xmit_cb { u32 bytecount; u8 desc_count; + u8 flags; int hw_head; }; @@ -43,6 +48,46 @@ static void fbnic_ring_wr32(struct fbnic_ring *ring, unsigned int csr, u32 val) writel(val, csr_base + csr); } +/** + * fbnic_ts40_to_ns() - convert descriptor timestamp to PHC time + * @fbn: netdev priv of the FB NIC + * @ts40: timestamp read from a descriptor + * + * Return: u64 value of PHC time in nanoseconds + * + * Convert truncated 40 bit device timestamp as read from a descriptor + * to the full PHC time in nanoseconds. + */ +static __maybe_unused u64 fbnic_ts40_to_ns(struct fbnic_net *fbn, u64 ts40) +{ + unsigned int s; + u64 time_ns; + s64 offset; + u8 ts_top; + u32 high; + + do { + s = u64_stats_fetch_begin(&fbn->time_seq); + offset = READ_ONCE(fbn->time_offset); + } while (u64_stats_fetch_retry(&fbn->time_seq, s)); + + high = READ_ONCE(fbn->time_high); + + /* Bits 63..40 from periodic clock reads, 39..0 from ts40 */ + time_ns = (u64)(high >> 8) << 40 | ts40; + + /* Compare bits 32-39 between periodic reads and ts40, + * see if HW clock may have wrapped since last read. We are sure + * that periodic reads are always at least ~1 minute behind, so + * this logic works perfectly fine. + */ + ts_top = ts40 >> 32; + if (ts_top < (u8)high && (u8)high - ts_top > U8_MAX / 2) + time_ns += 1ULL << 40; + + return time_ns + offset; +} + static unsigned int fbnic_desc_unused(struct fbnic_ring *ring) { return (ring->head - ring->tail - 1) & ring->size_mask; @@ -110,11 +155,32 @@ static void fbnic_unmap_page_twd(struct device *dev, __le64 *twd) #define FBNIC_TWD_TYPE(_type) \ cpu_to_le64(FIELD_PREP(FBNIC_TWD_TYPE_MASK, FBNIC_TWD_TYPE_##_type)) +static bool fbnic_tx_tstamp(struct sk_buff *skb) +{ + struct fbnic_net *fbn; + + if (!unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) + return false; + + fbn = netdev_priv(skb->dev); + if (fbn->hwtstamp_config.tx_type == HWTSTAMP_TX_OFF) + return false; + + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + FBNIC_XMIT_CB(skb)->flags |= FBNIC_XMIT_CB_TS; + FBNIC_XMIT_CB(skb)->hw_head = -1; + + return true; +} + static bool fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) { unsigned int l2len, i3len; + if (fbnic_tx_tstamp(skb)) + *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_TS); + if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) return false; @@ -205,6 +271,9 @@ fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) ring->tail = tail; + /* Record SW timestamp */ + skb_tx_timestamp(skb); + /* Verify there is room for another packet */ fbnic_maybe_stop_tx(skb->dev, ring, FBNIC_MAX_SKB_DESC); @@ -316,7 +385,7 @@ static void fbnic_clean_twq0(struct fbnic_napi_vector *nv, int napi_budget, struct fbnic_ring *ring, bool discard, unsigned int hw_head) { - u64 total_bytes = 0, total_packets = 0; + u64 total_bytes = 0, total_packets = 0, ts_lost = 0; unsigned int head = ring->head; struct netdev_queue *txq; unsigned int clean_desc; @@ -331,6 +400,13 @@ static void fbnic_clean_twq0(struct fbnic_napi_vector *nv, int napi_budget, if (desc_cnt > clean_desc) break; + if (unlikely(FBNIC_XMIT_CB(skb)->flags & FBNIC_XMIT_CB_TS)) { + FBNIC_XMIT_CB(skb)->hw_head = hw_head; + if (likely(!discard)) + break; + ts_lost++; + } + ring->tx_buf[head] = NULL; clean_desc -= desc_cnt; @@ -368,6 +444,7 @@ static void fbnic_clean_twq0(struct fbnic_napi_vector *nv, int napi_budget, if (unlikely(discard)) { u64_stats_update_begin(&ring->stats.syncp); ring->stats.dropped += total_packets; + ring->stats.ts_lost += ts_lost; u64_stats_update_end(&ring->stats.syncp); netdev_tx_completed_queue(txq, total_packets, total_bytes); @@ -384,6 +461,56 @@ static void fbnic_clean_twq0(struct fbnic_napi_vector *nv, int napi_budget, FBNIC_TX_DESC_WAKEUP); } +static void fbnic_clean_tsq(struct fbnic_napi_vector *nv, + struct fbnic_ring *ring, + u64 tcd, int *ts_head, int *head0) +{ + struct skb_shared_hwtstamps hwtstamp; + struct fbnic_net *fbn; + struct sk_buff *skb; + int head; + u64 ns; + + head = (*ts_head < 0) ? ring->head : *ts_head; + + do { + unsigned int desc_cnt; + + if (head == ring->tail) { + if (unlikely(net_ratelimit())) + netdev_err(nv->napi.dev, + "Tx timestamp without matching packet\n"); + return; + } + + skb = ring->tx_buf[head]; + desc_cnt = FBNIC_XMIT_CB(skb)->desc_count; + + head += desc_cnt; + head &= ring->size_mask; + } while (!(FBNIC_XMIT_CB(skb)->flags & FBNIC_XMIT_CB_TS)); + + fbn = netdev_priv(nv->napi.dev); + ns = fbnic_ts40_to_ns(fbn, FIELD_GET(FBNIC_TCD_TYPE1_TS_MASK, tcd)); + + memset(&hwtstamp, 0, sizeof(hwtstamp)); + hwtstamp.hwtstamp = ns_to_ktime(ns); + + *ts_head = head; + + FBNIC_XMIT_CB(skb)->flags &= ~FBNIC_XMIT_CB_TS; + if (*head0 < 0) { + head = FBNIC_XMIT_CB(skb)->hw_head; + if (head >= 0) + *head0 = head; + } + + skb_tstamp_tx(skb, &hwtstamp); + u64_stats_update_begin(&ring->stats.syncp); + ring->stats.ts_packets++; + u64_stats_update_end(&ring->stats.syncp); +} + static void fbnic_page_pool_init(struct fbnic_ring *ring, unsigned int idx, struct page *page) { @@ -417,10 +544,12 @@ static void fbnic_page_pool_drain(struct fbnic_ring *ring, unsigned int idx, } static void fbnic_clean_twq(struct fbnic_napi_vector *nv, int napi_budget, - struct fbnic_q_triad *qt, s32 head0) + struct fbnic_q_triad *qt, s32 ts_head, s32 head0) { if (head0 >= 0) fbnic_clean_twq0(nv, napi_budget, &qt->sub0, false, head0); + else if (ts_head >= 0) + fbnic_clean_twq0(nv, napi_budget, &qt->sub0, false, ts_head); } static void @@ -428,9 +557,9 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt, int napi_budget) { struct fbnic_ring *cmpl = &qt->cmpl; + s32 head0 = -1, ts_head = -1; __le64 *raw_tcd, done; u32 head = cmpl->head; - s32 head0 = -1; done = (head & (cmpl->size_mask + 1)) ? 0 : cpu_to_le64(FBNIC_TCD_DONE); raw_tcd = &cmpl->desc[head & cmpl->size_mask]; @@ -453,6 +582,12 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt, * they are skipped for now. */ break; + case FBNIC_TCD_TYPE_1: + if (WARN_ON_ONCE(tcd & FBNIC_TCD_TWQ1)) + break; + + fbnic_clean_tsq(nv, &qt->sub0, tcd, &ts_head, &head0); + break; default: break; } @@ -472,7 +607,7 @@ fbnic_clean_tcq(struct fbnic_napi_vector *nv, struct fbnic_q_triad *qt, } /* Unmap and free processed buffers */ - fbnic_clean_twq(nv, napi_budget, qt, head0); + fbnic_clean_twq(nv, napi_budget, qt, ts_head, head0); } static void fbnic_clean_bdq(struct fbnic_napi_vector *nv, int napi_budget, @@ -707,6 +842,10 @@ static struct sk_buff *fbnic_build_skb(struct fbnic_napi_vector *nv, /* Set MAC header specific fields */ skb->protocol = eth_type_trans(skb, nv->napi.dev); + /* Add timestamp if present */ + if (pkt->hwtstamp) + skb_hwtstamps(skb)->hwtstamp = pkt->hwtstamp; + return skb; } @@ -717,6 +856,23 @@ static enum pkt_hash_types fbnic_skb_hash_type(u64 rcd) PKT_HASH_TYPE_L2; } +static void fbnic_rx_tstamp(struct fbnic_napi_vector *nv, u64 rcd, + struct fbnic_pkt_buff *pkt) +{ + struct fbnic_net *fbn; + u64 ns, ts; + + if (!FIELD_GET(FBNIC_RCD_OPT_META_TS, rcd)) + return; + + fbn = netdev_priv(nv->napi.dev); + ts = FIELD_GET(FBNIC_RCD_OPT_META_TS_MASK, rcd); + ns = fbnic_ts40_to_ns(fbn, ts); + + /* Add timestamp to shared info */ + pkt->hwtstamp = ns_to_ktime(ns); +} + static void fbnic_populate_skb_fields(struct fbnic_napi_vector *nv, u64 rcd, struct sk_buff *skb, struct fbnic_q_triad *qt) @@ -781,6 +937,8 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv, if (FIELD_GET(FBNIC_RCD_OPT_META_TYPE_MASK, rcd)) break; + fbnic_rx_tstamp(nv, rcd, pkt); + /* We currently ignore the action table index */ break; case FBNIC_RCD_TYPE_META: @@ -907,6 +1065,8 @@ static void fbnic_aggregate_ring_tx_counters(struct fbnic_net *fbn, fbn->tx_stats.bytes += stats->bytes; fbn->tx_stats.packets += stats->packets; fbn->tx_stats.dropped += stats->dropped; + fbn->tx_stats.ts_lost += stats->ts_lost; + fbn->tx_stats.ts_packets += stats->ts_packets; } static void fbnic_remove_tx_ring(struct fbnic_net *fbn, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index 2f91f68d11d57c..8d626287c3f47e 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -47,6 +47,7 @@ struct fbnic_net; struct fbnic_pkt_buff { struct xdp_buff buff; + ktime_t hwtstamp; u32 data_truesize; u16 data_len; u16 nr_frags; @@ -56,6 +57,8 @@ struct fbnic_queue_stats { u64 packets; u64 bytes; u64 dropped; + u64 ts_packets; + u64 ts_lost; struct u64_stats_sync syncp; }; diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c index ddd87ef71caf78..c7b0b09c2b097d 100644 --- a/drivers/net/ethernet/micrel/ks8842.c +++ b/drivers/net/ethernet/micrel/ks8842.c @@ -1247,7 +1247,7 @@ static struct platform_driver ks8842_platform_driver = { .name = DRV_NAME, }, .probe = ks8842_probe, - .remove_new = ks8842_remove, + .remove = ks8842_remove, }; module_platform_driver(ks8842_platform_driver); diff --git a/drivers/net/ethernet/micrel/ks8851_common.c b/drivers/net/ethernet/micrel/ks8851_common.c index 7fa1820db9cce6..bb5138806c3ffd 100644 --- a/drivers/net/ethernet/micrel/ks8851_common.c +++ b/drivers/net/ethernet/micrel/ks8851_common.c @@ -215,22 +215,6 @@ static void ks8851_init_mac(struct ks8851_net *ks, struct device_node *np) ks8851_write_mac_addr(dev); } -/** - * ks8851_dbg_dumpkkt - dump initial packet contents to debug - * @ks: The device state - * @rxpkt: The data for the received packet - * - * Dump the initial data from the packet to dev_dbg(). - */ -static void ks8851_dbg_dumpkkt(struct ks8851_net *ks, u8 *rxpkt) -{ - netdev_dbg(ks->netdev, - "pkt %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n", - rxpkt[4], rxpkt[5], rxpkt[6], rxpkt[7], - rxpkt[8], rxpkt[9], rxpkt[10], rxpkt[11], - rxpkt[12], rxpkt[13], rxpkt[14], rxpkt[15]); -} - /** * ks8851_rx_pkts - receive packets from the host * @ks: The device information. @@ -296,8 +280,8 @@ static void ks8851_rx_pkts(struct ks8851_net *ks, struct sk_buff_head *rxq) ks->rdfifo(ks, rxpkt, rxalign + 8); - if (netif_msg_pktdata(ks)) - ks8851_dbg_dumpkkt(ks, rxpkt); + netif_dbg(ks, pktdata, ks->netdev, + "pkt %12ph\n", &rxpkt[4]); skb->protocol = eth_type_trans(skb, ks->netdev); __skb_queue_tail(rxq, skb); diff --git a/drivers/net/ethernet/micrel/ks8851_par.c b/drivers/net/ethernet/micrel/ks8851_par.c index 381b9cd285ebd0..78695be2570bfb 100644 --- a/drivers/net/ethernet/micrel/ks8851_par.c +++ b/drivers/net/ethernet/micrel/ks8851_par.c @@ -334,7 +334,7 @@ static struct platform_driver ks8851_driver = { .pm = &ks8851_pm_ops, }, .probe = ks8851_probe_par, - .remove_new = ks8851_remove_par, + .remove = ks8851_remove_par, }; module_platform_driver(ks8851_driver); diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index 534d4716d5f7d4..3234a960fcc30d 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -1285,7 +1285,7 @@ static void lan966x_remove(struct platform_device *pdev) static struct platform_driver lan966x_driver = { .probe = lan966x_probe, - .remove_new = lan966x_remove, + .remove = lan966x_remove, .driver = { .name = "lan966x-switch", .of_match_table = lan966x_match, diff --git a/drivers/net/ethernet/microchip/sparx5/Kconfig b/drivers/net/ethernet/microchip/sparx5/Kconfig index 3f04992eace6ab..35b057c9d0cb61 100644 --- a/drivers/net/ethernet/microchip/sparx5/Kconfig +++ b/drivers/net/ethernet/microchip/sparx5/Kconfig @@ -24,3 +24,9 @@ config SPARX5_DCB DSCP and PCP. If unsure, set to Y. + +config LAN969X_SWITCH + bool "Lan969x switch driver" + depends on SPARX5_SWITCH + help + This driver supports the lan969x family of network switch devices. diff --git a/drivers/net/ethernet/microchip/sparx5/Makefile b/drivers/net/ethernet/microchip/sparx5/Makefile index 288de95add188d..4bf2a885a9da47 100644 --- a/drivers/net/ethernet/microchip/sparx5/Makefile +++ b/drivers/net/ethernet/microchip/sparx5/Makefile @@ -11,11 +11,17 @@ sparx5-switch-y := sparx5_main.o sparx5_packet.o \ sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \ sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o \ sparx5_tc_matchall.o sparx5_pool.o sparx5_sdlb.o sparx5_police.o \ - sparx5_psfp.o sparx5_mirror.o + sparx5_psfp.o sparx5_mirror.o sparx5_regs.o sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o sparx5-switch-$(CONFIG_DEBUG_FS) += sparx5_vcap_debugfs.o +sparx5-switch-$(CONFIG_LAN969X_SWITCH) += lan969x/lan969x_regs.o \ + lan969x/lan969x.o \ + lan969x/lan969x_calendar.o \ + lan969x/lan969x_vcap_ag_api.o \ + lan969x/lan969x_vcap_impl.o + # Provide include files ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/fdma diff --git a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c new file mode 100644 index 00000000000000..c2afa2176b08f3 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip lan969x Switch driver + * + * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries. + */ + +#include "lan969x.h" + +#define LAN969X_SDLB_GRP_CNT 5 +#define LAN969X_HSCH_LEAK_GRP_CNT 4 + +static const struct sparx5_main_io_resource lan969x_main_iomap[] = { + { TARGET_CPU, 0xc0000, 0 }, /* 0xe00c0000 */ + { TARGET_FDMA, 0xc0400, 0 }, /* 0xe00c0400 */ + { TARGET_GCB, 0x2010000, 1 }, /* 0xe2010000 */ + { TARGET_QS, 0x2030000, 1 }, /* 0xe2030000 */ + { TARGET_PTP, 0x2040000, 1 }, /* 0xe2040000 */ + { TARGET_ANA_ACL, 0x2050000, 1 }, /* 0xe2050000 */ + { TARGET_LRN, 0x2060000, 1 }, /* 0xe2060000 */ + { TARGET_VCAP_SUPER, 0x2080000, 1 }, /* 0xe2080000 */ + { TARGET_QSYS, 0x20a0000, 1 }, /* 0xe20a0000 */ + { TARGET_QFWD, 0x20b0000, 1 }, /* 0xe20b0000 */ + { TARGET_XQS, 0x20c0000, 1 }, /* 0xe20c0000 */ + { TARGET_VCAP_ES2, 0x20d0000, 1 }, /* 0xe20d0000 */ + { TARGET_VCAP_ES0, 0x20e0000, 1 }, /* 0xe20e0000 */ + { TARGET_ANA_AC_POL, 0x2200000, 1 }, /* 0xe2200000 */ + { TARGET_QRES, 0x2280000, 1 }, /* 0xe2280000 */ + { TARGET_EACL, 0x22c0000, 1 }, /* 0xe22c0000 */ + { TARGET_ANA_CL, 0x2400000, 1 }, /* 0xe2400000 */ + { TARGET_ANA_L3, 0x2480000, 1 }, /* 0xe2480000 */ + { TARGET_ANA_AC_SDLB, 0x2500000, 1 }, /* 0xe2500000 */ + { TARGET_HSCH, 0x2580000, 1 }, /* 0xe2580000 */ + { TARGET_REW, 0x2600000, 1 }, /* 0xe2600000 */ + { TARGET_ANA_L2, 0x2800000, 1 }, /* 0xe2800000 */ + { TARGET_ANA_AC, 0x2900000, 1 }, /* 0xe2900000 */ + { TARGET_VOP, 0x2a00000, 1 }, /* 0xe2a00000 */ + { TARGET_DEV2G5, 0x3004000, 1 }, /* 0xe3004000 */ + { TARGET_DEV10G, 0x3008000, 1 }, /* 0xe3008000 */ + { TARGET_PCS10G_BR, 0x300c000, 1 }, /* 0xe300c000 */ + { TARGET_DEV2G5 + 1, 0x3010000, 1 }, /* 0xe3010000 */ + { TARGET_DEV2G5 + 2, 0x3014000, 1 }, /* 0xe3014000 */ + { TARGET_DEV2G5 + 3, 0x3018000, 1 }, /* 0xe3018000 */ + { TARGET_DEV2G5 + 4, 0x301c000, 1 }, /* 0xe301c000 */ + { TARGET_DEV10G + 1, 0x3020000, 1 }, /* 0xe3020000 */ + { TARGET_PCS10G_BR + 1, 0x3024000, 1 }, /* 0xe3024000 */ + { TARGET_DEV2G5 + 5, 0x3028000, 1 }, /* 0xe3028000 */ + { TARGET_DEV2G5 + 6, 0x302c000, 1 }, /* 0xe302c000 */ + { TARGET_DEV2G5 + 7, 0x3030000, 1 }, /* 0xe3030000 */ + { TARGET_DEV2G5 + 8, 0x3034000, 1 }, /* 0xe3034000 */ + { TARGET_DEV10G + 2, 0x3038000, 1 }, /* 0xe3038000 */ + { TARGET_PCS10G_BR + 2, 0x303c000, 1 }, /* 0xe303c000 */ + { TARGET_DEV2G5 + 9, 0x3040000, 1 }, /* 0xe3040000 */ + { TARGET_DEV5G, 0x3044000, 1 }, /* 0xe3044000 */ + { TARGET_PCS5G_BR, 0x3048000, 1 }, /* 0xe3048000 */ + { TARGET_DEV2G5 + 10, 0x304c000, 1 }, /* 0xe304c000 */ + { TARGET_DEV2G5 + 11, 0x3050000, 1 }, /* 0xe3050000 */ + { TARGET_DEV2G5 + 12, 0x3054000, 1 }, /* 0xe3054000 */ + { TARGET_DEV10G + 3, 0x3058000, 1 }, /* 0xe3058000 */ + { TARGET_PCS10G_BR + 3, 0x305c000, 1 }, /* 0xe305c000 */ + { TARGET_DEV2G5 + 13, 0x3060000, 1 }, /* 0xe3060000 */ + { TARGET_DEV5G + 1, 0x3064000, 1 }, /* 0xe3064000 */ + { TARGET_PCS5G_BR + 1, 0x3068000, 1 }, /* 0xe3068000 */ + { TARGET_DEV2G5 + 14, 0x306c000, 1 }, /* 0xe306c000 */ + { TARGET_DEV2G5 + 15, 0x3070000, 1 }, /* 0xe3070000 */ + { TARGET_DEV2G5 + 16, 0x3074000, 1 }, /* 0xe3074000 */ + { TARGET_DEV10G + 4, 0x3078000, 1 }, /* 0xe3078000 */ + { TARGET_PCS10G_BR + 4, 0x307c000, 1 }, /* 0xe307c000 */ + { TARGET_DEV2G5 + 17, 0x3080000, 1 }, /* 0xe3080000 */ + { TARGET_DEV5G + 2, 0x3084000, 1 }, /* 0xe3084000 */ + { TARGET_PCS5G_BR + 2, 0x3088000, 1 }, /* 0xe3088000 */ + { TARGET_DEV2G5 + 18, 0x308c000, 1 }, /* 0xe308c000 */ + { TARGET_DEV2G5 + 19, 0x3090000, 1 }, /* 0xe3090000 */ + { TARGET_DEV2G5 + 20, 0x3094000, 1 }, /* 0xe3094000 */ + { TARGET_DEV10G + 5, 0x3098000, 1 }, /* 0xe3098000 */ + { TARGET_PCS10G_BR + 5, 0x309c000, 1 }, /* 0xe309c000 */ + { TARGET_DEV2G5 + 21, 0x30a0000, 1 }, /* 0xe30a0000 */ + { TARGET_DEV5G + 3, 0x30a4000, 1 }, /* 0xe30a4000 */ + { TARGET_PCS5G_BR + 3, 0x30a8000, 1 }, /* 0xe30a8000 */ + { TARGET_DEV2G5 + 22, 0x30ac000, 1 }, /* 0xe30ac000 */ + { TARGET_DEV2G5 + 23, 0x30b0000, 1 }, /* 0xe30b0000 */ + { TARGET_DEV2G5 + 24, 0x30b4000, 1 }, /* 0xe30b4000 */ + { TARGET_DEV10G + 6, 0x30b8000, 1 }, /* 0xe30b8000 */ + { TARGET_PCS10G_BR + 6, 0x30bc000, 1 }, /* 0xe30bc000 */ + { TARGET_DEV2G5 + 25, 0x30c0000, 1 }, /* 0xe30c0000 */ + { TARGET_DEV10G + 7, 0x30c4000, 1 }, /* 0xe30c4000 */ + { TARGET_PCS10G_BR + 7, 0x30c8000, 1 }, /* 0xe30c8000 */ + { TARGET_DEV2G5 + 26, 0x30cc000, 1 }, /* 0xe30cc000 */ + { TARGET_DEV10G + 8, 0x30d0000, 1 }, /* 0xe30d0000 */ + { TARGET_PCS10G_BR + 8, 0x30d4000, 1 }, /* 0xe30d4000 */ + { TARGET_DEV2G5 + 27, 0x30d8000, 1 }, /* 0xe30d8000 */ + { TARGET_DEV10G + 9, 0x30dc000, 1 }, /* 0xe30dc000 */ + { TARGET_PCS10G_BR + 9, 0x30e0000, 1 }, /* 0xe30e0000 */ + { TARGET_DSM, 0x30ec000, 1 }, /* 0xe30ec000 */ + { TARGET_PORT_CONF, 0x30f0000, 1 }, /* 0xe30f0000 */ + { TARGET_ASM, 0x3200000, 1 }, /* 0xe3200000 */ +}; + +static struct sparx5_sdlb_group lan969x_sdlb_groups[LAN969X_SDLB_GRP_CNT] = { + { 1000000000, 8192 / 2, 64 }, /* 1 G */ + { 500000000, 8192 / 2, 64 }, /* 500 M */ + { 100000000, 8192 / 4, 64 }, /* 100 M */ + { 50000000, 8192 / 4, 64 }, /* 50 M */ + { 5000000, 8192 / 8, 64 }, /* 10 M */ +}; + +static u32 lan969x_hsch_max_group_rate[LAN969X_HSCH_LEAK_GRP_CNT] = { + 655355, 1048568, 6553550, 10485680 +}; + +static struct sparx5_sdlb_group *lan969x_get_sdlb_group(int idx) +{ + return &lan969x_sdlb_groups[idx]; +} + +static u32 lan969x_get_hsch_max_group_rate(int grp) +{ + return lan969x_hsch_max_group_rate[grp]; +} + +static u32 lan969x_get_dev_mode_bit(struct sparx5 *sparx5, int port) +{ + if (lan969x_port_is_2g5(port) || lan969x_port_is_5g(port)) + return port; + + /* 10G */ + switch (port) { + case 0: + return 12; + case 4: + return 13; + case 8: + return 14; + case 12: + return 0; + default: + return port; + } +} + +static u32 lan969x_port_dev_mapping(struct sparx5 *sparx5, int port) +{ + if (lan969x_port_is_5g(port)) { + switch (port) { + case 9: + return 0; + case 13: + return 1; + case 17: + return 2; + case 21: + return 3; + } + } + + if (lan969x_port_is_10g(port)) { + switch (port) { + case 0: + return 0; + case 4: + return 1; + case 8: + return 2; + case 12: + return 3; + case 16: + return 4; + case 20: + return 5; + case 24: + return 6; + case 25: + return 7; + case 26: + return 8; + case 27: + return 9; + } + } + + /* 2g5 port */ + return port; +} + +static int lan969x_port_mux_set(struct sparx5 *sparx5, struct sparx5_port *port, + struct sparx5_port_config *conf) +{ + u32 portno = port->portno; + u32 inst; + + if (port->conf.portmode == conf->portmode) + return 0; /* Nothing to do */ + + switch (conf->portmode) { + case PHY_INTERFACE_MODE_QSGMII: /* QSGMII: 4x2G5 devices. Mode Q' */ + inst = (portno - portno % 4) / 4; + spx5_rmw(BIT(inst), BIT(inst), sparx5, PORT_CONF_QSGMII_ENA); + break; + default: + break; + } + return 0; +} + +static irqreturn_t lan969x_ptp_irq_handler(int irq, void *args) +{ + int budget = SPARX5_MAX_PTP_ID; + struct sparx5 *sparx5 = args; + + while (budget--) { + struct sk_buff *skb, *skb_tmp, *skb_match = NULL; + struct skb_shared_hwtstamps shhwtstamps; + struct sparx5_port *port; + struct timespec64 ts; + unsigned long flags; + u32 val, id, txport; + u32 delay; + + val = spx5_rd(sparx5, PTP_TWOSTEP_CTRL); + + /* Check if a timestamp can be retrieved */ + if (!(val & PTP_TWOSTEP_CTRL_PTP_VLD)) + break; + + WARN_ON(val & PTP_TWOSTEP_CTRL_PTP_OVFL); + + if (!(val & PTP_TWOSTEP_CTRL_STAMP_TX)) + continue; + + /* Retrieve the ts Tx port */ + txport = PTP_TWOSTEP_CTRL_STAMP_PORT_GET(val); + + /* Retrieve its associated skb */ + port = sparx5->ports[txport]; + + /* Retrieve the delay */ + delay = spx5_rd(sparx5, PTP_TWOSTEP_STAMP_NSEC); + delay = PTP_TWOSTEP_STAMP_NSEC_NS_GET(delay); + + /* Get next timestamp from fifo, which needs to be the + * rx timestamp which represents the id of the frame + */ + spx5_rmw(PTP_TWOSTEP_CTRL_PTP_NXT_SET(1), + PTP_TWOSTEP_CTRL_PTP_NXT, + sparx5, PTP_TWOSTEP_CTRL); + + val = spx5_rd(sparx5, PTP_TWOSTEP_CTRL); + + /* Check if a timestamp can be retrieved */ + if (!(val & PTP_TWOSTEP_CTRL_PTP_VLD)) + break; + + /* Read RX timestamping to get the ID */ + id = spx5_rd(sparx5, PTP_TWOSTEP_STAMP_NSEC); + id <<= 8; + id |= spx5_rd(sparx5, PTP_TWOSTEP_STAMP_SUBNS); + + spin_lock_irqsave(&port->tx_skbs.lock, flags); + skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) { + if (SPARX5_SKB_CB(skb)->ts_id != id) + continue; + + __skb_unlink(skb, &port->tx_skbs); + skb_match = skb; + break; + } + spin_unlock_irqrestore(&port->tx_skbs.lock, flags); + + /* Next ts */ + spx5_rmw(PTP_TWOSTEP_CTRL_PTP_NXT_SET(1), + PTP_TWOSTEP_CTRL_PTP_NXT, + sparx5, PTP_TWOSTEP_CTRL); + + if (WARN_ON(!skb_match)) + continue; + + spin_lock_irqsave(&sparx5->ptp_ts_id_lock, flags); + sparx5->ptp_skbs--; + spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags); + + /* Get the h/w timestamp */ + sparx5_get_hwtimestamp(sparx5, &ts, delay); + + /* Set the timestamp in the skb */ + shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); + skb_tstamp_tx(skb_match, &shhwtstamps); + + dev_kfree_skb_any(skb_match); + } + + return IRQ_HANDLED; +} + +static const struct sparx5_regs lan969x_regs = { + .tsize = lan969x_tsize, + .gaddr = lan969x_gaddr, + .gcnt = lan969x_gcnt, + .gsize = lan969x_gsize, + .raddr = lan969x_raddr, + .rcnt = lan969x_rcnt, + .fpos = lan969x_fpos, + .fsize = lan969x_fsize, +}; + +static const struct sparx5_consts lan969x_consts = { + .n_ports = 30, + .n_ports_all = 35, + .n_hsch_l1_elems = 32, + .n_hsch_queues = 4, + .n_lb_groups = 5, + .n_pgids = 1054, /* (1024 + n_ports) */ + .n_sio_clks = 1, + .n_own_upsids = 1, + .n_auto_cals = 4, + .n_filters = 256, + .n_gates = 256, + .n_sdlbs = 496, + .n_dsm_cal_taxis = 5, + .buf_size = 1572864, + .qres_max_prio_idx = 315, + .qres_max_colour_idx = 323, + .tod_pin = 4, + .vcaps = lan969x_vcaps, + .vcap_stats = &lan969x_vcap_stats, + .vcaps_cfg = lan969x_vcap_inst_cfg, +}; + +static const struct sparx5_ops lan969x_ops = { + .is_port_2g5 = &lan969x_port_is_2g5, + .is_port_5g = &lan969x_port_is_5g, + .is_port_10g = &lan969x_port_is_10g, + .is_port_25g = &lan969x_port_is_25g, + .get_port_dev_index = &lan969x_port_dev_mapping, + .get_port_dev_bit = &lan969x_get_dev_mode_bit, + .get_hsch_max_group_rate = &lan969x_get_hsch_max_group_rate, + .get_sdlb_group = &lan969x_get_sdlb_group, + .set_port_mux = &lan969x_port_mux_set, + .ptp_irq_handler = &lan969x_ptp_irq_handler, + .dsm_calendar_calc = &lan969x_dsm_calendar_calc, +}; + +const struct sparx5_match_data lan969x_desc = { + .iomap = lan969x_main_iomap, + .iomap_size = ARRAY_SIZE(lan969x_main_iomap), + .ioranges = 2, + .regs = &lan969x_regs, + .consts = &lan969x_consts, + .ops = &lan969x_ops, +}; diff --git a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.h b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.h new file mode 100644 index 00000000000000..2489d0d32dfd1d --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Microchip lan969x Switch driver + * + * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries. + */ + +#ifndef __LAN969X_H__ +#define __LAN969X_H__ + +#include "../sparx5/sparx5_main.h" +#include "../sparx5/sparx5_regs.h" +#include "../sparx5/sparx5_vcap_impl.h" + +/* lan969x.c */ +extern const struct sparx5_match_data lan969x_desc; + +/* lan969x_vcap_ag_api.c */ +extern const struct vcap_statistics lan969x_vcap_stats; +extern const struct vcap_info lan969x_vcaps[]; + +/* lan969x_vcap_impl.c */ +extern const struct sparx5_vcap_inst lan969x_vcap_inst_cfg[]; + +/* lan969x_regs.c */ +extern const unsigned int lan969x_tsize[TSIZE_LAST]; +extern const unsigned int lan969x_raddr[RADDR_LAST]; +extern const unsigned int lan969x_rcnt[RCNT_LAST]; +extern const unsigned int lan969x_gaddr[GADDR_LAST]; +extern const unsigned int lan969x_gcnt[GCNT_LAST]; +extern const unsigned int lan969x_gsize[GSIZE_LAST]; +extern const unsigned int lan969x_fpos[FPOS_LAST]; +extern const unsigned int lan969x_fsize[FSIZE_LAST]; + +static inline bool lan969x_port_is_2g5(int portno) +{ + return portno == 1 || portno == 2 || portno == 3 || + portno == 5 || portno == 6 || portno == 7 || + portno == 10 || portno == 11 || portno == 14 || + portno == 15 || portno == 18 || portno == 19 || + portno == 22 || portno == 23; +} + +static inline bool lan969x_port_is_5g(int portno) +{ + return portno == 9 || portno == 13 || portno == 17 || + portno == 21; +} + +static inline bool lan969x_port_is_10g(int portno) +{ + return portno == 0 || portno == 4 || portno == 8 || + portno == 12 || portno == 16 || portno == 20 || + portno == 24 || portno == 25 || portno == 26 || + portno == 27; +} + +static inline bool lan969x_port_is_25g(int portno) +{ + return false; +} + +/* lan969x_calendar.c */ +int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi, + struct sparx5_calendar_data *data); +#endif diff --git a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_calendar.c b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_calendar.c new file mode 100644 index 00000000000000..e857640df185ee --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_calendar.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip lan969x Switch driver + * + * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries. + */ + +#include "lan969x.h" + +#define LAN969X_DSM_CAL_DEVS_PER_TAXI 10 +#define LAN969X_DSM_CAL_TAXIS 5 + +enum lan969x_dsm_cal_dev { + DSM_CAL_DEV_2G5, + DSM_CAL_DEV_5G, + DSM_CAL_DEV_10G, + DSM_CAL_DEV_OTHER, /* 1G or less */ + DSM_CAL_DEV_MAX +}; + +/* Each entry in the following struct defines properties for a given speed + * (10G, 5G, 2.5G, or 1G or less). + */ +struct lan969x_dsm_cal_dev_speed { + /* Number of devices that requires this speed. */ + u32 n_devs; + + /* Array of devices that requires this speed. */ + u32 devs[LAN969X_DSM_CAL_DEVS_PER_TAXI]; + + /* Number of slots required for one device running this speed. */ + u32 n_slots; + + /* Gap between two slots for one device running this speed. */ + u32 gap; +}; + +static u32 +lan969x_taxi_ports[LAN969X_DSM_CAL_TAXIS][LAN969X_DSM_CAL_DEVS_PER_TAXI] = { + { 0, 4, 1, 2, 3, 5, 6, 7, 28, 29 }, + { 8, 12, 9, 13, 10, 11, 14, 15, 99, 99 }, + { 16, 20, 17, 21, 18, 19, 22, 23, 99, 99 }, + { 24, 25, 99, 99, 99, 99, 99, 99, 99, 99 }, + { 26, 27, 99, 99, 99, 99, 99, 99, 99, 99 } +}; + +static int lan969x_dsm_cal_idx_get(u32 *calendar, u32 cal_len, u32 *cal_idx) +{ + if (*cal_idx >= cal_len) + return -EINVAL; + + do { + if (calendar[*cal_idx] == SPX5_DSM_CAL_EMPTY) + return 0; + + (*cal_idx)++; + } while (*cal_idx < cal_len); + + return -ENOENT; +} + +static enum lan969x_dsm_cal_dev lan969x_dsm_cal_get_dev(int speed) +{ + return (speed == 10000 ? DSM_CAL_DEV_10G : + speed == 5000 ? DSM_CAL_DEV_5G : + speed == 2500 ? DSM_CAL_DEV_2G5 : + DSM_CAL_DEV_OTHER); +} + +static int lan969x_dsm_cal_get_speed(enum lan969x_dsm_cal_dev dev) +{ + return (dev == DSM_CAL_DEV_10G ? 10000 : + dev == DSM_CAL_DEV_5G ? 5000 : + dev == DSM_CAL_DEV_2G5 ? 2500 : + 1000); +} + +int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi, + struct sparx5_calendar_data *data) +{ + struct lan969x_dsm_cal_dev_speed dev_speeds[DSM_CAL_DEV_MAX] = {}; + u32 cal_len, n_slots, taxi_bw, n_devs = 0, required_bw = 0; + struct lan969x_dsm_cal_dev_speed *speed; + int err; + + /* Maximum bandwidth for this taxi */ + taxi_bw = (128 * 1000000) / sparx5_clk_period(sparx5->coreclock); + + memcpy(data->taxi_ports, &lan969x_taxi_ports[taxi], + LAN969X_DSM_CAL_DEVS_PER_TAXI * sizeof(u32)); + + for (int i = 0; i < LAN969X_DSM_CAL_DEVS_PER_TAXI; i++) { + u32 portno = data->taxi_ports[i]; + enum sparx5_cal_bw bw; + + bw = sparx5_get_port_cal_speed(sparx5, portno); + + if (portno < sparx5->data->consts->n_ports_all) + data->taxi_speeds[i] = sparx5_cal_speed_to_value(bw); + else + data->taxi_speeds[i] = 0; + } + + /* Determine the different port types (10G, 5G, 2.5G, <= 1G) in the + * this taxi map. + */ + for (int i = 0; i < LAN969X_DSM_CAL_DEVS_PER_TAXI; i++) { + u32 taxi_speed = data->taxi_speeds[i]; + enum lan969x_dsm_cal_dev dev; + + if (taxi_speed == 0) + continue; + + required_bw += taxi_speed; + + dev = lan969x_dsm_cal_get_dev(taxi_speed); + speed = &dev_speeds[dev]; + speed->devs[speed->n_devs++] = i; + n_devs++; + } + + if (required_bw > taxi_bw) { + pr_err("Required bandwidth: %u is higher than total taxi bandwidth: %u", + required_bw, taxi_bw); + return -EINVAL; + } + + if (n_devs == 0) { + data->schedule[0] = SPX5_DSM_CAL_EMPTY; + return 0; + } + + cal_len = n_devs; + + /* Search for a calendar length that fits all active devices. */ + while (cal_len < SPX5_DSM_CAL_LEN) { + u32 bw_per_slot = taxi_bw / cal_len; + + n_slots = 0; + + for (int i = 0; i < DSM_CAL_DEV_MAX; i++) { + speed = &dev_speeds[i]; + + if (speed->n_devs == 0) + continue; + + required_bw = lan969x_dsm_cal_get_speed(i); + speed->n_slots = DIV_ROUND_UP(required_bw, bw_per_slot); + + if (speed->n_slots) + speed->gap = DIV_ROUND_UP(cal_len, + speed->n_slots); + else + speed->gap = 0; + + n_slots += speed->n_slots * speed->n_devs; + } + + if (n_slots <= cal_len) + break; /* Found a suitable calendar length. */ + + /* Not good enough yet. */ + cal_len = n_slots; + } + + if (cal_len > SPX5_DSM_CAL_LEN) { + pr_err("Invalid length: %u for taxi: %u", cal_len, taxi); + return -EINVAL; + } + + for (u32 i = 0; i < SPX5_DSM_CAL_LEN; i++) + data->schedule[i] = SPX5_DSM_CAL_EMPTY; + + /* Place the remaining devices */ + for (u32 i = 0; i < DSM_CAL_DEV_MAX; i++) { + speed = &dev_speeds[i]; + for (u32 dev = 0; dev < speed->n_devs; dev++) { + u32 idx = 0; + + for (n_slots = 0; n_slots < speed->n_slots; n_slots++) { + err = lan969x_dsm_cal_idx_get(data->schedule, + cal_len, &idx); + if (err) + return err; + data->schedule[idx] = speed->devs[dev]; + idx += speed->gap; + } + } + } + + return 0; +} diff --git a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_regs.c b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_regs.c new file mode 100644 index 00000000000000..ace4ba21eec433 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_regs.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip lan969x Switch driver + * + * Copyright (c) 2024 Microchip Technology Inc. + */ + +/* This file is autogenerated by cml-utils 2024-09-30 11:48:29 +0200. + * Commit ID: 9d07b8d19363f3cd3590ddb3f7a2e2768e16524b + */ + +#include "lan969x.h" + +const unsigned int lan969x_tsize[TSIZE_LAST] = { + [TC_DEV10G] = 10, + [TC_DEV2G5] = 28, + [TC_DEV5G] = 4, + [TC_PCS10G_BR] = 10, + [TC_PCS5G_BR] = 4, +}; + +const unsigned int lan969x_raddr[RADDR_LAST] = { + [RA_CPU_PROC_CTRL] = 160, + [RA_GCB_SOFT_RST] = 12, + [RA_GCB_HW_SGPIO_TO_SD_MAP_CFG] = 20, +}; + +const unsigned int lan969x_rcnt[RCNT_LAST] = { + [RC_ANA_AC_OWN_UPSID] = 1, + [RC_ANA_ACL_VCAP_S2_CFG] = 35, + [RC_ANA_ACL_OWN_UPSID] = 1, + [RC_ANA_CL_OWN_UPSID] = 1, + [RC_ANA_L2_OWN_UPSID] = 1, + [RC_ASM_PORT_CFG] = 32, + [RC_DSM_BUF_CFG] = 32, + [RC_DSM_DEV_TX_STOP_WM_CFG] = 32, + [RC_DSM_RX_PAUSE_CFG] = 32, + [RC_DSM_MAC_CFG] = 32, + [RC_DSM_MAC_ADDR_BASE_HIGH_CFG] = 30, + [RC_DSM_MAC_ADDR_BASE_LOW_CFG] = 30, + [RC_DSM_TAXI_CAL_CFG] = 6, + [RC_GCB_HW_SGPIO_TO_SD_MAP_CFG] = 30, + [RC_HSCH_PORT_MODE] = 35, + [RC_QFWD_SWITCH_PORT_MODE] = 35, + [RC_QSYS_PAUSE_CFG] = 35, + [RC_QSYS_ATOP] = 35, + [RC_QSYS_FWD_PRESSURE] = 35, + [RC_QSYS_CAL_AUTO] = 4, + [RC_REW_OWN_UPSID] = 1, + [RC_REW_RTAG_ETAG_CTRL] = 35, +}; + +const unsigned int lan969x_gaddr[GADDR_LAST] = { + [GA_ANA_AC_RAM_CTRL] = 202000, + [GA_ANA_AC_PS_COMMON] = 202880, + [GA_ANA_AC_MIRROR_PROBE] = 203232, + [GA_ANA_AC_SRC] = 201728, + [GA_ANA_AC_PGID] = 131072, + [GA_ANA_AC_TSN_SF] = 202028, + [GA_ANA_AC_TSN_SF_CFG] = 148480, + [GA_ANA_AC_TSN_SF_STATUS] = 147936, + [GA_ANA_AC_SG_ACCESS] = 202032, + [GA_ANA_AC_SG_CONFIG] = 202752, + [GA_ANA_AC_SG_STATUS] = 147952, + [GA_ANA_AC_SG_STATUS_STICKY] = 202044, + [GA_ANA_AC_STAT_GLOBAL_CFG_PORT] = 202048, + [GA_ANA_AC_STAT_CNT_CFG_PORT] = 204800, + [GA_ANA_AC_STAT_GLOBAL_CFG_ACL] = 202068, + [GA_ANA_ACL_COMMON] = 8192, + [GA_ANA_ACL_KEY_SEL] = 9204, + [GA_ANA_ACL_CNT_B] = 4096, + [GA_ANA_ACL_STICKY] = 10852, + [GA_ANA_AC_POL_POL_ALL_CFG] = 17504, + [GA_ANA_AC_POL_COMMON_BDLB] = 19464, + [GA_ANA_AC_POL_COMMON_BUM_SLB] = 19472, + [GA_ANA_AC_SDLB_LBGRP_TBL] = 31788, + [GA_ANA_CL_PORT] = 65536, + [GA_ANA_CL_COMMON] = 87040, + [GA_ANA_L2_COMMON] = 561928, + [GA_ANA_L3_COMMON] = 370752, + [GA_ANA_L3_VLAN_ARP_L3MC_STICKY] = 368580, + [GA_ASM_CFG] = 18304, + [GA_ASM_PFC_TIMER_CFG] = 15568, + [GA_ASM_LBK_WM_CFG] = 15596, + [GA_ASM_LBK_MISC_CFG] = 15608, + [GA_ASM_RAM_CTRL] = 15684, + [GA_EACL_ES2_KEY_SELECT_PROFILE] = 36864, + [GA_EACL_CNT_TBL] = 30720, + [GA_EACL_POL_CFG] = 38400, + [GA_EACL_ES2_STICKY] = 29072, + [GA_EACL_RAM_CTRL] = 29112, + [GA_GCB_SIO_CTRL] = 560, + [GA_HSCH_HSCH_DWRR] = 36480, + [GA_HSCH_HSCH_MISC] = 36608, + [GA_HSCH_HSCH_LEAK_LISTS] = 37256, + [GA_HSCH_SYSTEM] = 37384, + [GA_HSCH_MMGT] = 36260, + [GA_HSCH_TAS_CONFIG] = 37696, + [GA_PTP_PTP_CFG] = 512, + [GA_PTP_PTP_TOD_DOMAINS] = 528, + [GA_PTP_PHASE_DETECTOR_CTRL] = 628, + [GA_QSYS_CALCFG] = 2164, + [GA_QSYS_RAM_CTRL] = 2204, + [GA_REW_COMMON] = 98304, + [GA_REW_PORT] = 49152, + [GA_REW_VOE_PORT_LM_CNT] = 90112, + [GA_REW_RAM_CTRL] = 93992, + [GA_VOP_RAM_CTRL] = 16368, + [GA_XQS_SYSTEM] = 5744, + [GA_XQS_QLIMIT_SHR] = 6912, +}; + +const unsigned int lan969x_gcnt[GCNT_LAST] = { + [GC_ANA_AC_SRC] = 67, + [GC_ANA_AC_PGID] = 1054, + [GC_ANA_AC_TSN_SF_CFG] = 256, + [GC_ANA_AC_STAT_CNT_CFG_PORT] = 35, + [GC_ANA_ACL_KEY_SEL] = 99, + [GC_ANA_ACL_CNT_A] = 1024, + [GC_ANA_ACL_CNT_B] = 1024, + [GC_ANA_AC_SDLB_LBGRP_TBL] = 5, + [GC_ANA_AC_SDLB_LBSET_TBL] = 496, + [GC_ANA_CL_PORT] = 35, + [GC_ANA_L2_ISDX_LIMIT] = 256, + [GC_ANA_L2_ISDX] = 1024, + [GC_ANA_L3_VLAN] = 4608, + [GC_ASM_DEV_STATISTICS] = 30, + [GC_EACL_ES2_KEY_SELECT_PROFILE] = 68, + [GC_EACL_CNT_TBL] = 512, + [GC_GCB_SIO_CTRL] = 1, + [GC_HSCH_HSCH_CFG] = 1120, + [GC_HSCH_HSCH_DWRR] = 32, + [GC_PTP_PTP_PINS] = 8, + [GC_PTP_PHASE_DETECTOR_CTRL] = 8, + [GC_REW_PORT] = 35, + [GC_REW_VOE_PORT_LM_CNT] = 240, +}; + +const unsigned int lan969x_gsize[GSIZE_LAST] = { + [GW_ANA_AC_SRC] = 4, + [GW_ANA_L2_COMMON] = 712, + [GW_ASM_CFG] = 1092, + [GW_CPU_CPU_REGS] = 180, + [GW_DEV2G5_PHASE_DETECTOR_CTRL] = 12, + [GW_FDMA_FDMA] = 448, + [GW_GCB_CHIP_REGS] = 180, + [GW_HSCH_TAS_CONFIG] = 16, + [GW_PTP_PHASE_DETECTOR_CTRL] = 12, + [GW_QSYS_PAUSE_CFG] = 988, +}; + +const unsigned int lan969x_fpos[FPOS_LAST] = { + [FP_CPU_PROC_CTRL_AARCH64_MODE_ENA] = 7, + [FP_CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS] = 6, + [FP_CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS] = 5, + [FP_CPU_PROC_CTRL_BE_EXCEP_MODE] = 4, + [FP_CPU_PROC_CTRL_VINITHI] = 3, + [FP_CPU_PROC_CTRL_CFGTE] = 2, + [FP_CPU_PROC_CTRL_CP15S_DISABLE] = 1, + [FP_CPU_PROC_CTRL_PROC_CRYPTO_DISABLE] = 0, + [FP_CPU_PROC_CTRL_L2_FLUSH_REQ] = 8, + [FP_DEV2G5_PHAD_CTRL_PHAD_ENA] = 5, + [FP_DEV2G5_PHAD_CTRL_PHAD_FAILED] = 3, + [FP_FDMA_CH_CFG_CH_XTR_STATUS_MODE] = 5, + [FP_FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY] = 4, + [FP_FDMA_CH_CFG_CH_INJ_PORT] = 3, + [FP_PTP_PTP_PIN_CFG_PTP_PIN_ACTION] = 27, + [FP_PTP_PTP_PIN_CFG_PTP_PIN_SYNC] = 25, + [FP_PTP_PTP_PIN_CFG_PTP_PIN_INV_POL] = 24, + [FP_PTP_PHAD_CTRL_PHAD_ENA] = 5, + [FP_PTP_PHAD_CTRL_PHAD_FAILED] = 3, +}; + +const unsigned int lan969x_fsize[FSIZE_LAST] = { + [FW_ANA_AC_PROBE_PORT_CFG_PROBE_PORT_MASK] = 30, + [FW_ANA_AC_SRC_CFG_PORT_MASK] = 30, + [FW_ANA_AC_PGID_CFG_PORT_MASK] = 30, + [FW_ANA_AC_TSN_SF_PORT_NUM] = 7, + [FW_ANA_AC_TSN_SF_CFG_TSN_SGID] = 8, + [FW_ANA_AC_TSN_SF_STATUS_TSN_SFID] = 8, + [FW_ANA_AC_SG_ACCESS_CTRL_SGID] = 8, + [FW_ANA_AC_PORT_SGE_CFG_MASK] = 17, + [FW_ANA_AC_SDLB_XLB_START_LBSET_START] = 9, + [FW_ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT] = 3, + [FW_ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT] = 9, + [FW_ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT] = 9, + [FW_ANA_AC_SDLB_XLB_NEXT_LBGRP] = 3, + [FW_ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR] = 9, + [FW_ANA_L2_AUTO_LRN_CFG_AUTO_LRN_ENA] = 30, + [FW_ANA_L2_DLB_CFG_DLB_IDX] = 9, + [FW_ANA_L2_TSN_CFG_TSN_SFID] = 8, + [FW_ANA_L3_VLAN_MASK_CFG_VLAN_PORT_MASK] = 30, + [FW_FDMA_CH_CFG_CH_DCB_DB_CNT] = 2, + [FW_GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL] = 7, + [FW_HSCH_SE_CFG_SE_DWRR_CNT] = 5, + [FW_HSCH_SE_CONNECT_SE_LEAK_LINK] = 14, + [FW_HSCH_SE_DLB_SENSE_SE_DLB_DPORT] = 6, + [FW_HSCH_HSCH_CFG_CFG_CFG_SE_IDX] = 11, + [FW_HSCH_HSCH_LEAK_CFG_LEAK_FIRST] = 14, + [FW_HSCH_FLUSH_CTRL_FLUSH_PORT] = 6, + [FW_HSCH_FLUSH_CTRL_FLUSH_HIER] = 14, + [FW_LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW] = 13, + [FW_LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX] = 8, + [FW_LRN_AUTOAGE_CFG_2_NEXT_ROW] = 13, + [FW_PTP_PTP_PIN_INTR_INTR_PTP] = 8, + [FW_PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA] = 8, + [FW_PTP_PTP_INTR_IDENT_INTR_PTP_IDENT] = 8, + [FW_PTP_PTP_PIN_CFG_PTP_PIN_SELECT] = 3, + [FW_QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL] = 6, + [FW_QRES_RES_CFG_WM_HIGH] = 11, + [FW_QRES_RES_STAT_MAXUSE] = 19, + [FW_QRES_RES_STAT_CUR_INUSE] = 19, + [FW_QSYS_PAUSE_CFG_PAUSE_START] = 11, + [FW_QSYS_PAUSE_CFG_PAUSE_STOP] = 11, + [FW_QSYS_ATOP_ATOP] = 11, + [FW_QSYS_ATOP_TOT_CFG_ATOP_TOT] = 11, + [FW_REW_RTAG_ETAG_CTRL_IPE_TBL] = 6, + [FW_XQS_STAT_CFG_STAT_VIEW] = 10, + [FW_XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP] = 14, + [FW_XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP] = 14, + [FW_XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP] = 14, + [FW_XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM] = 14, +}; diff --git a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_vcap_ag_api.c b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_vcap_ag_api.c new file mode 100644 index 00000000000000..7acc5bcf337a24 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_vcap_ag_api.c @@ -0,0 +1,3843 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright (C) 2024 Microchip Technology Inc. and its subsidiaries. + * Microchip VCAP API + */ + +/* This file is autogenerated by cml-utils 2024-10-07 11:10:56 +0200. + * Commit ID: b5ddc8e244eb2481a9524f1ddc630a8b41e7c391 + */ + +#include +#include + +#include "lan969x.h" + +/* keyfields */ +static const struct vcap_field is0_normal_7tuple_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 2, + }, + [VCAP_KF_LOOKUP_GEN_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 10, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 16, + .width = 65, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 82, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGS] = { + .type = VCAP_FIELD_U32, + .offset = 83, + .width = 3, + }, + [VCAP_KF_8021Q_TPID0] = { + .type = VCAP_FIELD_U32, + .offset = 86, + .width = 3, + }, + [VCAP_KF_8021Q_PCP0] = { + .type = VCAP_FIELD_U32, + .offset = 89, + .width = 3, + }, + [VCAP_KF_8021Q_DEI0] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_8021Q_VID0] = { + .type = VCAP_FIELD_U32, + .offset = 93, + .width = 12, + }, + [VCAP_KF_8021Q_TPID1] = { + .type = VCAP_FIELD_U32, + .offset = 105, + .width = 3, + }, + [VCAP_KF_8021Q_PCP1] = { + .type = VCAP_FIELD_U32, + .offset = 108, + .width = 3, + }, + [VCAP_KF_8021Q_DEI1] = { + .type = VCAP_FIELD_BIT, + .offset = 111, + .width = 1, + }, + [VCAP_KF_8021Q_VID1] = { + .type = VCAP_FIELD_U32, + .offset = 112, + .width = 12, + }, + [VCAP_KF_8021Q_TPID2] = { + .type = VCAP_FIELD_U32, + .offset = 124, + .width = 3, + }, + [VCAP_KF_8021Q_PCP2] = { + .type = VCAP_FIELD_U32, + .offset = 127, + .width = 3, + }, + [VCAP_KF_8021Q_DEI2] = { + .type = VCAP_FIELD_BIT, + .offset = 130, + .width = 1, + }, + [VCAP_KF_8021Q_VID2] = { + .type = VCAP_FIELD_U32, + .offset = 131, + .width = 12, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 144, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 192, + .width = 48, + }, + [VCAP_KF_IP_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 240, + .width = 1, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 241, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 242, + .width = 16, + }, + [VCAP_KF_IP_SNAP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 258, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 259, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 260, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 262, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 263, + .width = 1, + }, + [VCAP_KF_L3_DSCP] = { + .type = VCAP_FIELD_U32, + .offset = 264, + .width = 6, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 270, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 398, + .width = 128, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 526, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 527, + .width = 1, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 528, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 544, + .width = 8, + }, +}; + +static const struct vcap_field is0_normal_5tuple_ip4_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 2, + }, + [VCAP_KF_LOOKUP_GEN_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 10, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 15, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 17, + .width = 65, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 82, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 83, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGS] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 3, + }, + [VCAP_KF_8021Q_TPID0] = { + .type = VCAP_FIELD_U32, + .offset = 87, + .width = 3, + }, + [VCAP_KF_8021Q_PCP0] = { + .type = VCAP_FIELD_U32, + .offset = 90, + .width = 3, + }, + [VCAP_KF_8021Q_DEI0] = { + .type = VCAP_FIELD_BIT, + .offset = 93, + .width = 1, + }, + [VCAP_KF_8021Q_VID0] = { + .type = VCAP_FIELD_U32, + .offset = 94, + .width = 12, + }, + [VCAP_KF_8021Q_TPID1] = { + .type = VCAP_FIELD_U32, + .offset = 106, + .width = 3, + }, + [VCAP_KF_8021Q_PCP1] = { + .type = VCAP_FIELD_U32, + .offset = 109, + .width = 3, + }, + [VCAP_KF_8021Q_DEI1] = { + .type = VCAP_FIELD_BIT, + .offset = 112, + .width = 1, + }, + [VCAP_KF_8021Q_VID1] = { + .type = VCAP_FIELD_U32, + .offset = 113, + .width = 12, + }, + [VCAP_KF_8021Q_TPID2] = { + .type = VCAP_FIELD_U32, + .offset = 125, + .width = 3, + }, + [VCAP_KF_8021Q_PCP2] = { + .type = VCAP_FIELD_U32, + .offset = 128, + .width = 3, + }, + [VCAP_KF_8021Q_DEI2] = { + .type = VCAP_FIELD_BIT, + .offset = 131, + .width = 1, + }, + [VCAP_KF_8021Q_VID2] = { + .type = VCAP_FIELD_U32, + .offset = 132, + .width = 12, + }, + [VCAP_KF_IP_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 145, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 146, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 147, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 149, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 150, + .width = 1, + }, + [VCAP_KF_L3_DSCP] = { + .type = VCAP_FIELD_U32, + .offset = 151, + .width = 6, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 157, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 189, + .width = 32, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 221, + .width = 8, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 229, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 230, + .width = 1, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 231, + .width = 8, + }, + [VCAP_KF_IP_PAYLOAD_5TUPLE] = { + .type = VCAP_FIELD_U32, + .offset = 239, + .width = 32, + }, +}; + +static const struct vcap_field is2_mac_etype_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 56, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 57, + .width = 10, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 67, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 80, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 81, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 89, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 137, + .width = 48, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 185, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 186, + .width = 16, + }, + [VCAP_KF_L2_PAYLOAD_ETYPE] = { + .type = VCAP_FIELD_U64, + .offset = 202, + .width = 64, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 266, + .width = 16, + }, + [VCAP_KF_OAM_CCM_CNTS_EQ0] = { + .type = VCAP_FIELD_BIT, + .offset = 282, + .width = 1, + }, + [VCAP_KF_OAM_Y1731_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 283, + .width = 1, + }, +}; + +static const struct vcap_field is2_arp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 56, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 57, + .width = 10, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 67, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 80, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 81, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 85, + .width = 48, + }, + [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 133, + .width = 1, + }, + [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 134, + .width = 1, + }, + [VCAP_KF_ARP_LEN_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 135, + .width = 1, + }, + [VCAP_KF_ARP_TGT_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 136, + .width = 1, + }, + [VCAP_KF_ARP_SENDER_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 137, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 138, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE] = { + .type = VCAP_FIELD_U32, + .offset = 139, + .width = 2, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 141, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 173, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 205, + .width = 1, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 206, + .width = 16, + }, +}; + +static const struct vcap_field is2_ip4_tcp_udp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 56, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 57, + .width = 10, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 67, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 80, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 81, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 90, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 93, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 95, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 103, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 135, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 167, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 168, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 169, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 185, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 201, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 217, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 219, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 220, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 221, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 222, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 223, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 224, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 225, + .width = 64, + }, +}; + +static const struct vcap_field is2_ip4_other_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 56, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 57, + .width = 10, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 67, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 80, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 81, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 90, + .width = 2, + }, + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 93, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 94, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 95, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 103, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 135, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 167, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 168, + .width = 8, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 176, + .width = 16, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U112, + .offset = 192, + .width = 96, + }, +}; + +static const struct vcap_field is2_ip6_std_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 4, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 5, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 32, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 52, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 53, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 54, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 56, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 57, + .width = 10, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 67, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 80, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 81, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 90, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 219, + .width = 8, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 227, + .width = 16, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U48, + .offset = 243, + .width = 40, + }, +}; + +static const struct vcap_field is2_ip_7tuple_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_KF_LOOKUP_PAG] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 8, + }, + [VCAP_KF_IF_IGR_PORT_MASK_L3] = { + .type = VCAP_FIELD_BIT, + .offset = 11, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 2, + }, + [VCAP_KF_IF_IGR_PORT_MASK] = { + .type = VCAP_FIELD_U72, + .offset = 18, + .width = 65, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 83, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 85, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 88, + .width = 10, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 98, + .width = 13, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 111, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 112, + .width = 3, + }, + [VCAP_KF_L2_FWD_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 115, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 118, + .width = 1, + }, + [VCAP_KF_L3_DST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 119, + .width = 1, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 120, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 168, + .width = 48, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 218, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 219, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 220, + .width = 8, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 228, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 356, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 484, + .width = 1, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 485, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 486, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 487, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 503, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 519, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 535, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 536, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 537, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 538, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 539, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 540, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 541, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 542, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 543, + .width = 64, + }, +}; + +static const struct vcap_field es0_isdx_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_KF_IF_EGR_PORT_NO] = { + .type = VCAP_FIELD_U32, + .offset = 1, + .width = 6, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 7, + .width = 13, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 20, + .width = 3, + }, + [VCAP_KF_8021Q_TPID] = { + .type = VCAP_FIELD_U32, + .offset = 23, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 26, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 27, + .width = 1, + }, + [VCAP_KF_PROT_ACTIVE] = { + .type = VCAP_FIELD_BIT, + .offset = 28, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 38, + .width = 10, + }, +}; + +static const struct vcap_field es2_mac_etype_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 10, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 26, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 28, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 76, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 77, + .width = 7, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 88, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 91, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 96, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 144, + .width = 48, + }, + [VCAP_KF_ETYPE_LEN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 192, + .width = 1, + }, + [VCAP_KF_ETYPE] = { + .type = VCAP_FIELD_U32, + .offset = 193, + .width = 16, + }, + [VCAP_KF_L2_PAYLOAD_ETYPE] = { + .type = VCAP_FIELD_U64, + .offset = 209, + .width = 64, + }, + [VCAP_KF_OAM_CCM_CNTS_EQ0] = { + .type = VCAP_FIELD_BIT, + .offset = 273, + .width = 1, + }, + [VCAP_KF_OAM_Y1731_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 274, + .width = 1, + }, +}; + +static const struct vcap_field es2_arp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 10, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 26, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 28, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 76, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 77, + .width = 7, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 88, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 91, + .width = 1, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 95, + .width = 48, + }, + [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 143, + .width = 1, + }, + [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 144, + .width = 1, + }, + [VCAP_KF_ARP_LEN_OK_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 145, + .width = 1, + }, + [VCAP_KF_ARP_TGT_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 146, + .width = 1, + }, + [VCAP_KF_ARP_SENDER_MATCH_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 147, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 148, + .width = 1, + }, + [VCAP_KF_ARP_OPCODE] = { + .type = VCAP_FIELD_U32, + .offset = 149, + .width = 2, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 151, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 183, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 215, + .width = 1, + }, +}; + +static const struct vcap_field es2_ip4_tcp_udp_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 10, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 26, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 28, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 76, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 77, + .width = 7, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 88, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 91, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 96, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 97, + .width = 2, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 99, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 100, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 101, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 109, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 141, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 173, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 174, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 175, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 191, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 207, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 223, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 224, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 225, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 226, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 227, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 228, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 229, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 230, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 231, + .width = 64, + }, +}; + +static const struct vcap_field es2_ip4_other_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 10, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 26, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 28, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 76, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 77, + .width = 7, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 88, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 91, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 96, + .width = 1, + }, + [VCAP_KF_L3_FRAGMENT_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 97, + .width = 2, + }, + [VCAP_KF_L3_OPTIONS_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 99, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 100, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 101, + .width = 8, + }, + [VCAP_KF_L3_IP4_DIP] = { + .type = VCAP_FIELD_U32, + .offset = 109, + .width = 32, + }, + [VCAP_KF_L3_IP4_SIP] = { + .type = VCAP_FIELD_U32, + .offset = 141, + .width = 32, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 173, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 174, + .width = 8, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U112, + .offset = 182, + .width = 96, + }, +}; + +static const struct vcap_field es2_ip_7tuple_keyfield[] = { + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 10, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 11, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 10, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 23, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 25, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 38, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 73, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 74, + .width = 7, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 81, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 85, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 88, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 89, + .width = 1, + }, + [VCAP_KF_L2_DMAC] = { + .type = VCAP_FIELD_U48, + .offset = 93, + .width = 48, + }, + [VCAP_KF_L2_SMAC] = { + .type = VCAP_FIELD_U48, + .offset = 141, + .width = 48, + }, + [VCAP_KF_IP4_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 191, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 192, + .width = 1, + }, + [VCAP_KF_L3_TOS] = { + .type = VCAP_FIELD_U32, + .offset = 193, + .width = 8, + }, + [VCAP_KF_L3_IP6_DIP] = { + .type = VCAP_FIELD_U128, + .offset = 201, + .width = 128, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 329, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 457, + .width = 1, + }, + [VCAP_KF_TCP_UDP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 458, + .width = 1, + }, + [VCAP_KF_TCP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 459, + .width = 1, + }, + [VCAP_KF_L4_DPORT] = { + .type = VCAP_FIELD_U32, + .offset = 460, + .width = 16, + }, + [VCAP_KF_L4_SPORT] = { + .type = VCAP_FIELD_U32, + .offset = 476, + .width = 16, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 492, + .width = 16, + }, + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 508, + .width = 1, + }, + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 509, + .width = 1, + }, + [VCAP_KF_L4_FIN] = { + .type = VCAP_FIELD_BIT, + .offset = 510, + .width = 1, + }, + [VCAP_KF_L4_SYN] = { + .type = VCAP_FIELD_BIT, + .offset = 511, + .width = 1, + }, + [VCAP_KF_L4_RST] = { + .type = VCAP_FIELD_BIT, + .offset = 512, + .width = 1, + }, + [VCAP_KF_L4_PSH] = { + .type = VCAP_FIELD_BIT, + .offset = 513, + .width = 1, + }, + [VCAP_KF_L4_ACK] = { + .type = VCAP_FIELD_BIT, + .offset = 514, + .width = 1, + }, + [VCAP_KF_L4_URG] = { + .type = VCAP_FIELD_BIT, + .offset = 515, + .width = 1, + }, + [VCAP_KF_L4_PAYLOAD] = { + .type = VCAP_FIELD_U64, + .offset = 516, + .width = 64, + }, +}; + +static const struct vcap_field es2_ip6_std_keyfield[] = { + [VCAP_KF_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 3, + }, + [VCAP_KF_LOOKUP_FIRST_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 3, + .width = 1, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 13, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 14, + .width = 1, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 10, + }, + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 26, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 28, + .width = 13, + }, + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 41, + .width = 3, + }, + [VCAP_KF_IF_EGR_PORT_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 44, + .width = 32, + }, + [VCAP_KF_IF_IGR_PORT_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 76, + .width = 1, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 77, + .width = 7, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 84, + .width = 3, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 87, + .width = 1, + }, + [VCAP_KF_COSID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 88, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 91, + .width = 1, + }, + [VCAP_KF_L3_RT_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 92, + .width = 1, + }, + [VCAP_KF_L3_TTL_GT0] = { + .type = VCAP_FIELD_BIT, + .offset = 96, + .width = 1, + }, + [VCAP_KF_L3_IP6_SIP] = { + .type = VCAP_FIELD_U128, + .offset = 97, + .width = 128, + }, + [VCAP_KF_L3_DIP_EQ_SIP_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 225, + .width = 1, + }, + [VCAP_KF_L3_IP_PROTO] = { + .type = VCAP_FIELD_U32, + .offset = 226, + .width = 8, + }, + [VCAP_KF_L4_RNG] = { + .type = VCAP_FIELD_U32, + .offset = 234, + .width = 16, + }, + [VCAP_KF_L3_PAYLOAD] = { + .type = VCAP_FIELD_U48, + .offset = 250, + .width = 40, + }, +}; + +/* keyfield_set */ +static const struct vcap_set is0_keyfield_set[] = { + [VCAP_KFS_NORMAL_7TUPLE] = { + .type_id = 0, + .sw_per_item = 12, + .sw_cnt = 1, + }, + [VCAP_KFS_NORMAL_5TUPLE_IP4] = { + .type_id = 2, + .sw_per_item = 6, + .sw_cnt = 2, + }, +}; + +static const struct vcap_set is2_keyfield_set[] = { + [VCAP_KFS_MAC_ETYPE] = { + .type_id = 0, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_ARP] = { + .type_id = 3, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_TCP_UDP] = { + .type_id = 4, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_OTHER] = { + .type_id = 5, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP6_STD] = { + .type_id = 6, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP_7TUPLE] = { + .type_id = 1, + .sw_per_item = 12, + .sw_cnt = 1, + }, +}; + +static const struct vcap_set es0_keyfield_set[] = { + [VCAP_KFS_ISDX] = { + .type_id = 0, + .sw_per_item = 1, + .sw_cnt = 1, + }, +}; + +static const struct vcap_set es2_keyfield_set[] = { + [VCAP_KFS_MAC_ETYPE] = { + .type_id = 0, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_ARP] = { + .type_id = 1, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_TCP_UDP] = { + .type_id = 2, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP4_OTHER] = { + .type_id = 3, + .sw_per_item = 6, + .sw_cnt = 2, + }, + [VCAP_KFS_IP_7TUPLE] = { + .type_id = -1, + .sw_per_item = 12, + .sw_cnt = 1, + }, + [VCAP_KFS_IP6_STD] = { + .type_id = 4, + .sw_per_item = 6, + .sw_cnt = 2, + }, +}; + +/* keyfield_set map */ +static const struct vcap_field *is0_keyfield_set_map[] = { + [VCAP_KFS_NORMAL_7TUPLE] = is0_normal_7tuple_keyfield, + [VCAP_KFS_NORMAL_5TUPLE_IP4] = is0_normal_5tuple_ip4_keyfield, +}; + +static const struct vcap_field *is2_keyfield_set_map[] = { + [VCAP_KFS_MAC_ETYPE] = is2_mac_etype_keyfield, + [VCAP_KFS_ARP] = is2_arp_keyfield, + [VCAP_KFS_IP4_TCP_UDP] = is2_ip4_tcp_udp_keyfield, + [VCAP_KFS_IP4_OTHER] = is2_ip4_other_keyfield, + [VCAP_KFS_IP6_STD] = is2_ip6_std_keyfield, + [VCAP_KFS_IP_7TUPLE] = is2_ip_7tuple_keyfield, +}; + +static const struct vcap_field *es0_keyfield_set_map[] = { + [VCAP_KFS_ISDX] = es0_isdx_keyfield, +}; + +static const struct vcap_field *es2_keyfield_set_map[] = { + [VCAP_KFS_MAC_ETYPE] = es2_mac_etype_keyfield, + [VCAP_KFS_ARP] = es2_arp_keyfield, + [VCAP_KFS_IP4_TCP_UDP] = es2_ip4_tcp_udp_keyfield, + [VCAP_KFS_IP4_OTHER] = es2_ip4_other_keyfield, + [VCAP_KFS_IP_7TUPLE] = es2_ip_7tuple_keyfield, + [VCAP_KFS_IP6_STD] = es2_ip6_std_keyfield, +}; + +/* keyfield_set map sizes */ +static int is0_keyfield_set_map_size[] = { + [VCAP_KFS_NORMAL_7TUPLE] = ARRAY_SIZE(is0_normal_7tuple_keyfield), + [VCAP_KFS_NORMAL_5TUPLE_IP4] = ARRAY_SIZE(is0_normal_5tuple_ip4_keyfield), +}; + +static int is2_keyfield_set_map_size[] = { + [VCAP_KFS_MAC_ETYPE] = ARRAY_SIZE(is2_mac_etype_keyfield), + [VCAP_KFS_ARP] = ARRAY_SIZE(is2_arp_keyfield), + [VCAP_KFS_IP4_TCP_UDP] = ARRAY_SIZE(is2_ip4_tcp_udp_keyfield), + [VCAP_KFS_IP4_OTHER] = ARRAY_SIZE(is2_ip4_other_keyfield), + [VCAP_KFS_IP6_STD] = ARRAY_SIZE(is2_ip6_std_keyfield), + [VCAP_KFS_IP_7TUPLE] = ARRAY_SIZE(is2_ip_7tuple_keyfield), +}; + +static int es0_keyfield_set_map_size[] = { + [VCAP_KFS_ISDX] = ARRAY_SIZE(es0_isdx_keyfield), +}; + +static int es2_keyfield_set_map_size[] = { + [VCAP_KFS_MAC_ETYPE] = ARRAY_SIZE(es2_mac_etype_keyfield), + [VCAP_KFS_ARP] = ARRAY_SIZE(es2_arp_keyfield), + [VCAP_KFS_IP4_TCP_UDP] = ARRAY_SIZE(es2_ip4_tcp_udp_keyfield), + [VCAP_KFS_IP4_OTHER] = ARRAY_SIZE(es2_ip4_other_keyfield), + [VCAP_KFS_IP_7TUPLE] = ARRAY_SIZE(es2_ip_7tuple_keyfield), + [VCAP_KFS_IP6_STD] = ARRAY_SIZE(es2_ip6_std_keyfield), +}; + +/* actionfields */ +static const struct vcap_field is0_classification_actionfield[] = { + [VCAP_AF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_DSCP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_DSCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 6, + }, + [VCAP_AF_QOS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_AF_QOS_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 3, + }, + [VCAP_AF_DP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 16, + .width = 1, + }, + [VCAP_AF_DP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 2, + }, + [VCAP_AF_DEI_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 19, + .width = 1, + }, + [VCAP_AF_DEI_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 20, + .width = 1, + }, + [VCAP_AF_PCP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 21, + .width = 1, + }, + [VCAP_AF_PCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 22, + .width = 3, + }, + [VCAP_AF_MAP_LOOKUP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 25, + .width = 2, + }, + [VCAP_AF_MAP_KEY] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 3, + }, + [VCAP_AF_MAP_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 30, + .width = 7, + }, + [VCAP_AF_CLS_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 37, + .width = 3, + }, + [VCAP_AF_VID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 43, + .width = 13, + }, + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 66, + .width = 1, + }, + [VCAP_AF_ISDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 67, + .width = 10, + }, + [VCAP_AF_PAG_OVERRIDE_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 107, + .width = 8, + }, + [VCAP_AF_PAG_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 115, + .width = 8, + }, + [VCAP_AF_NXT_IDX_CTRL] = { + .type = VCAP_FIELD_U32, + .offset = 167, + .width = 3, + }, + [VCAP_AF_NXT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 170, + .width = 10, + }, +}; + +static const struct vcap_field is0_full_actionfield[] = { + [VCAP_AF_DSCP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_DSCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 1, + .width = 6, + }, + [VCAP_AF_QOS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 11, + .width = 1, + }, + [VCAP_AF_QOS_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 3, + }, + [VCAP_AF_DP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_AF_DP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 16, + .width = 2, + }, + [VCAP_AF_DEI_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 18, + .width = 1, + }, + [VCAP_AF_DEI_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 19, + .width = 1, + }, + [VCAP_AF_PCP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 20, + .width = 1, + }, + [VCAP_AF_PCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 21, + .width = 3, + }, + [VCAP_AF_MAP_LOOKUP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 24, + .width = 2, + }, + [VCAP_AF_MAP_KEY] = { + .type = VCAP_FIELD_U32, + .offset = 26, + .width = 3, + }, + [VCAP_AF_MAP_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 7, + }, + [VCAP_AF_CLS_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 36, + .width = 3, + }, + [VCAP_AF_VID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 42, + .width = 13, + }, + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 65, + .width = 1, + }, + [VCAP_AF_ISDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 66, + .width = 10, + }, + [VCAP_AF_MASK_MODE] = { + .type = VCAP_FIELD_U32, + .offset = 76, + .width = 3, + }, + [VCAP_AF_PORT_MASK] = { + .type = VCAP_FIELD_U48, + .offset = 79, + .width = 37, + }, + [VCAP_AF_PAG_OVERRIDE_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 174, + .width = 8, + }, + [VCAP_AF_PAG_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 182, + .width = 8, + }, + [VCAP_AF_NXT_IDX_CTRL] = { + .type = VCAP_FIELD_U32, + .offset = 266, + .width = 3, + }, + [VCAP_AF_NXT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 269, + .width = 10, + }, +}; + +static const struct vcap_field is0_class_reduced_actionfield[] = { + [VCAP_AF_TYPE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_QOS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 5, + .width = 1, + }, + [VCAP_AF_QOS_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 6, + .width = 3, + }, + [VCAP_AF_DP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_AF_DP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 2, + }, + [VCAP_AF_MAP_LOOKUP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 12, + .width = 2, + }, + [VCAP_AF_MAP_KEY] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 3, + }, + [VCAP_AF_CLS_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 3, + }, + [VCAP_AF_VID_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 23, + .width = 13, + }, + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 46, + .width = 1, + }, + [VCAP_AF_ISDX_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 47, + .width = 10, + }, + [VCAP_AF_NXT_IDX_CTRL] = { + .type = VCAP_FIELD_U32, + .offset = 89, + .width = 3, + }, + [VCAP_AF_NXT_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 92, + .width = 10, + }, +}; + +static const struct vcap_field is2_base_type_actionfield[] = { + [VCAP_AF_PIPELINE_FORCE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_PIPELINE_PT] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 5, + }, + [VCAP_AF_HIT_ME_ONCE] = { + .type = VCAP_FIELD_BIT, + .offset = 7, + .width = 1, + }, + [VCAP_AF_INTR_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 8, + .width = 1, + }, + [VCAP_AF_CPU_COPY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 9, + .width = 1, + }, + [VCAP_AF_CPU_QUEUE_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 3, + }, + [VCAP_AF_LRN_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 15, + .width = 1, + }, + [VCAP_AF_RT_DIS] = { + .type = VCAP_FIELD_BIT, + .offset = 16, + .width = 1, + }, + [VCAP_AF_POLICE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 17, + .width = 1, + }, + [VCAP_AF_POLICE_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 5, + }, + [VCAP_AF_IGNORE_PIPELINE_CTRL] = { + .type = VCAP_FIELD_BIT, + .offset = 23, + .width = 1, + }, + [VCAP_AF_MASK_MODE] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 3, + }, + [VCAP_AF_PORT_MASK] = { + .type = VCAP_FIELD_U48, + .offset = 30, + .width = 37, + }, + [VCAP_AF_MIRROR_PROBE] = { + .type = VCAP_FIELD_U32, + .offset = 78, + .width = 2, + }, + [VCAP_AF_MATCH_ID] = { + .type = VCAP_FIELD_U32, + .offset = 131, + .width = 16, + }, + [VCAP_AF_MATCH_ID_MASK] = { + .type = VCAP_FIELD_U32, + .offset = 147, + .width = 16, + }, + [VCAP_AF_CNT_ID] = { + .type = VCAP_FIELD_U32, + .offset = 163, + .width = 10, + }, +}; + +static const struct vcap_field es0_es0_actionfield[] = { + [VCAP_AF_PUSH_OUTER_TAG] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_AF_PUSH_INNER_TAG] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_AF_TAG_A_TPID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 3, + }, + [VCAP_AF_TAG_A_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 6, + .width = 2, + }, + [VCAP_AF_TAG_A_PCP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 8, + .width = 3, + }, + [VCAP_AF_TAG_A_DEI_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 11, + .width = 3, + }, + [VCAP_AF_TAG_B_TPID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 14, + .width = 3, + }, + [VCAP_AF_TAG_B_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 2, + }, + [VCAP_AF_TAG_B_PCP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 19, + .width = 3, + }, + [VCAP_AF_TAG_B_DEI_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 22, + .width = 3, + }, + [VCAP_AF_TAG_C_TPID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 25, + .width = 3, + }, + [VCAP_AF_TAG_C_PCP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 28, + .width = 3, + }, + [VCAP_AF_TAG_C_DEI_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 31, + .width = 3, + }, + [VCAP_AF_VID_A_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 34, + .width = 12, + }, + [VCAP_AF_PCP_A_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 46, + .width = 3, + }, + [VCAP_AF_DEI_A_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 49, + .width = 1, + }, + [VCAP_AF_VID_B_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 50, + .width = 12, + }, + [VCAP_AF_PCP_B_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 62, + .width = 3, + }, + [VCAP_AF_DEI_B_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 65, + .width = 1, + }, + [VCAP_AF_VID_C_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 66, + .width = 12, + }, + [VCAP_AF_PCP_C_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 78, + .width = 3, + }, + [VCAP_AF_DEI_C_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 81, + .width = 1, + }, + [VCAP_AF_POP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 82, + .width = 2, + }, + [VCAP_AF_UNTAG_VID_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 84, + .width = 1, + }, + [VCAP_AF_PUSH_CUSTOMER_TAG] = { + .type = VCAP_FIELD_U32, + .offset = 85, + .width = 2, + }, + [VCAP_AF_TAG_C_VID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 87, + .width = 2, + }, + [VCAP_AF_DSCP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 127, + .width = 3, + }, + [VCAP_AF_DSCP_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 130, + .width = 6, + }, + [VCAP_AF_ESDX] = { + .type = VCAP_FIELD_U32, + .offset = 319, + .width = 10, + }, + [VCAP_AF_FWD_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 438, + .width = 2, + }, + [VCAP_AF_CPU_QU] = { + .type = VCAP_FIELD_U32, + .offset = 440, + .width = 3, + }, + [VCAP_AF_PIPELINE_PT] = { + .type = VCAP_FIELD_U32, + .offset = 443, + .width = 2, + }, + [VCAP_AF_PIPELINE_ACT] = { + .type = VCAP_FIELD_BIT, + .offset = 445, + .width = 1, + }, + [VCAP_AF_SWAP_MACS_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 454, + .width = 1, + }, + [VCAP_AF_LOOP_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 455, + .width = 1, + }, +}; + +static const struct vcap_field es2_base_type_actionfield[] = { + [VCAP_AF_HIT_ME_ONCE] = { + .type = VCAP_FIELD_BIT, + .offset = 0, + .width = 1, + }, + [VCAP_AF_INTR_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 1, + .width = 1, + }, + [VCAP_AF_FWD_MODE] = { + .type = VCAP_FIELD_U32, + .offset = 2, + .width = 2, + }, + [VCAP_AF_COPY_QUEUE_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 14, + }, + [VCAP_AF_COPY_PORT_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 18, + .width = 6, + }, + [VCAP_AF_MIRROR_PROBE_ID] = { + .type = VCAP_FIELD_U32, + .offset = 24, + .width = 2, + }, + [VCAP_AF_CPU_COPY_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 26, + .width = 1, + }, + [VCAP_AF_CPU_QUEUE_NUM] = { + .type = VCAP_FIELD_U32, + .offset = 27, + .width = 3, + }, + [VCAP_AF_POLICE_ENA] = { + .type = VCAP_FIELD_BIT, + .offset = 30, + .width = 1, + }, + [VCAP_AF_POLICE_REMARK] = { + .type = VCAP_FIELD_BIT, + .offset = 31, + .width = 1, + }, + [VCAP_AF_POLICE_IDX] = { + .type = VCAP_FIELD_U32, + .offset = 32, + .width = 5, + }, + [VCAP_AF_ES2_REW_CMD] = { + .type = VCAP_FIELD_U32, + .offset = 37, + .width = 3, + }, + [VCAP_AF_CNT_ID] = { + .type = VCAP_FIELD_U32, + .offset = 40, + .width = 9, + }, + [VCAP_AF_IGNORE_PIPELINE_CTRL] = { + .type = VCAP_FIELD_BIT, + .offset = 49, + .width = 1, + }, +}; + +/* actionfield_set */ +static const struct vcap_set is0_actionfield_set[] = { + [VCAP_AFS_CLASSIFICATION] = { + .type_id = 1, + .sw_per_item = 2, + .sw_cnt = 6, + }, + [VCAP_AFS_FULL] = { + .type_id = -1, + .sw_per_item = 3, + .sw_cnt = 4, + }, + [VCAP_AFS_CLASS_REDUCED] = { + .type_id = 1, + .sw_per_item = 1, + .sw_cnt = 12, + }, +}; + +static const struct vcap_set is2_actionfield_set[] = { + [VCAP_AFS_BASE_TYPE] = { + .type_id = -1, + .sw_per_item = 3, + .sw_cnt = 4, + }, +}; + +static const struct vcap_set es0_actionfield_set[] = { + [VCAP_AFS_ES0] = { + .type_id = -1, + .sw_per_item = 1, + .sw_cnt = 1, + }, +}; + +static const struct vcap_set es2_actionfield_set[] = { + [VCAP_AFS_BASE_TYPE] = { + .type_id = -1, + .sw_per_item = 3, + .sw_cnt = 4, + }, +}; + +/* actionfield_set map */ +static const struct vcap_field *is0_actionfield_set_map[] = { + [VCAP_AFS_CLASSIFICATION] = is0_classification_actionfield, + [VCAP_AFS_FULL] = is0_full_actionfield, + [VCAP_AFS_CLASS_REDUCED] = is0_class_reduced_actionfield, +}; + +static const struct vcap_field *is2_actionfield_set_map[] = { + [VCAP_AFS_BASE_TYPE] = is2_base_type_actionfield, +}; + +static const struct vcap_field *es0_actionfield_set_map[] = { + [VCAP_AFS_ES0] = es0_es0_actionfield, +}; + +static const struct vcap_field *es2_actionfield_set_map[] = { + [VCAP_AFS_BASE_TYPE] = es2_base_type_actionfield, +}; + +/* actionfield_set map size */ +static int is0_actionfield_set_map_size[] = { + [VCAP_AFS_CLASSIFICATION] = ARRAY_SIZE(is0_classification_actionfield), + [VCAP_AFS_FULL] = ARRAY_SIZE(is0_full_actionfield), + [VCAP_AFS_CLASS_REDUCED] = ARRAY_SIZE(is0_class_reduced_actionfield), +}; + +static int is2_actionfield_set_map_size[] = { + [VCAP_AFS_BASE_TYPE] = ARRAY_SIZE(is2_base_type_actionfield), +}; + +static int es0_actionfield_set_map_size[] = { + [VCAP_AFS_ES0] = ARRAY_SIZE(es0_es0_actionfield), +}; + +static int es2_actionfield_set_map_size[] = { + [VCAP_AFS_BASE_TYPE] = ARRAY_SIZE(es2_base_type_actionfield), +}; + +/* Type Groups */ +static const struct vcap_typegroup is0_x12_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 5, + .value = 16, + }, + { + .offset = 52, + .width = 1, + .value = 0, + }, + { + .offset = 104, + .width = 2, + .value = 0, + }, + { + .offset = 156, + .width = 3, + .value = 0, + }, + { + .offset = 208, + .width = 2, + .value = 0, + }, + { + .offset = 260, + .width = 1, + .value = 0, + }, + { + .offset = 312, + .width = 4, + .value = 0, + }, + { + .offset = 364, + .width = 1, + .value = 0, + }, + { + .offset = 416, + .width = 2, + .value = 0, + }, + { + .offset = 468, + .width = 3, + .value = 0, + }, + { + .offset = 520, + .width = 2, + .value = 0, + }, + { + .offset = 572, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x6_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 4, + .value = 8, + }, + { + .offset = 52, + .width = 1, + .value = 0, + }, + { + .offset = 104, + .width = 2, + .value = 0, + }, + { + .offset = 156, + .width = 3, + .value = 0, + }, + { + .offset = 208, + .width = 2, + .value = 0, + }, + { + .offset = 260, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x3_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup is0_x2_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup is0_x1_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup is2_x12_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 3, + .value = 4, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + { + .offset = 312, + .width = 2, + .value = 0, + }, + { + .offset = 468, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x6_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x3_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup is2_x1_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup es0_x1_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup es2_x12_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 3, + .value = 4, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + { + .offset = 312, + .width = 2, + .value = 0, + }, + { + .offset = 468, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup es2_x6_keyfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 156, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup es2_x3_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup es2_x1_keyfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup *is0_keyfield_set_typegroups[] = { + [12] = is0_x12_keyfield_set_typegroups, + [6] = is0_x6_keyfield_set_typegroups, + [3] = is0_x3_keyfield_set_typegroups, + [2] = is0_x2_keyfield_set_typegroups, + [1] = is0_x1_keyfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup *is2_keyfield_set_typegroups[] = { + [12] = is2_x12_keyfield_set_typegroups, + [6] = is2_x6_keyfield_set_typegroups, + [3] = is2_x3_keyfield_set_typegroups, + [1] = is2_x1_keyfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup *es0_keyfield_set_typegroups[] = { + [1] = es0_x1_keyfield_set_typegroups, + [2] = NULL, +}; + +static const struct vcap_typegroup *es2_keyfield_set_typegroups[] = { + [12] = es2_x12_keyfield_set_typegroups, + [6] = es2_x6_keyfield_set_typegroups, + [3] = es2_x3_keyfield_set_typegroups, + [1] = es2_x1_keyfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup is0_x3_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 3, + .value = 4, + }, + { + .offset = 103, + .width = 2, + .value = 0, + }, + { + .offset = 206, + .width = 2, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x2_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 103, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is0_x1_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 1, + .value = 1, + }, + {} +}; + +static const struct vcap_typegroup is2_x3_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 95, + .width = 1, + .value = 0, + }, + { + .offset = 190, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup is2_x1_actionfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup es0_x1_actionfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup es2_x3_actionfield_set_typegroups[] = { + { + .offset = 0, + .width = 2, + .value = 2, + }, + { + .offset = 19, + .width = 1, + .value = 0, + }, + { + .offset = 38, + .width = 1, + .value = 0, + }, + {} +}; + +static const struct vcap_typegroup es2_x1_actionfield_set_typegroups[] = { + {} +}; + +static const struct vcap_typegroup *is0_actionfield_set_typegroups[] = { + [3] = is0_x3_actionfield_set_typegroups, + [2] = is0_x2_actionfield_set_typegroups, + [1] = is0_x1_actionfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup *is2_actionfield_set_typegroups[] = { + [3] = is2_x3_actionfield_set_typegroups, + [1] = is2_x1_actionfield_set_typegroups, + [13] = NULL, +}; + +static const struct vcap_typegroup *es0_actionfield_set_typegroups[] = { + [1] = es0_x1_actionfield_set_typegroups, + [2] = NULL, +}; + +static const struct vcap_typegroup *es2_actionfield_set_typegroups[] = { + [3] = es2_x3_actionfield_set_typegroups, + [1] = es2_x1_actionfield_set_typegroups, + [13] = NULL, +}; + +/* Keyfieldset names */ +static const char * const vcap_keyfield_set_names[] = { + [VCAP_KFS_NO_VALUE] = "(None)", + [VCAP_KFS_ARP] = "VCAP_KFS_ARP", + [VCAP_KFS_ETAG] = "VCAP_KFS_ETAG", + [VCAP_KFS_IP4_OTHER] = "VCAP_KFS_IP4_OTHER", + [VCAP_KFS_IP4_TCP_UDP] = "VCAP_KFS_IP4_TCP_UDP", + [VCAP_KFS_IP4_VID] = "VCAP_KFS_IP4_VID", + [VCAP_KFS_IP6_OTHER] = "VCAP_KFS_IP6_OTHER", + [VCAP_KFS_IP6_STD] = "VCAP_KFS_IP6_STD", + [VCAP_KFS_IP6_TCP_UDP] = "VCAP_KFS_IP6_TCP_UDP", + [VCAP_KFS_IP6_VID] = "VCAP_KFS_IP6_VID", + [VCAP_KFS_IP_7TUPLE] = "VCAP_KFS_IP_7TUPLE", + [VCAP_KFS_ISDX] = "VCAP_KFS_ISDX", + [VCAP_KFS_LL_FULL] = "VCAP_KFS_LL_FULL", + [VCAP_KFS_MAC_ETYPE] = "VCAP_KFS_MAC_ETYPE", + [VCAP_KFS_MAC_LLC] = "VCAP_KFS_MAC_LLC", + [VCAP_KFS_MAC_SNAP] = "VCAP_KFS_MAC_SNAP", + [VCAP_KFS_NORMAL_5TUPLE_IP4] = "VCAP_KFS_NORMAL_5TUPLE_IP4", + [VCAP_KFS_NORMAL_7TUPLE] = "VCAP_KFS_NORMAL_7TUPLE", + [VCAP_KFS_OAM] = "VCAP_KFS_OAM", + [VCAP_KFS_PURE_5TUPLE_IP4] = "VCAP_KFS_PURE_5TUPLE_IP4", + [VCAP_KFS_SMAC_SIP4] = "VCAP_KFS_SMAC_SIP4", + [VCAP_KFS_SMAC_SIP6] = "VCAP_KFS_SMAC_SIP6", +}; + +/* Actionfieldset names */ +static const char * const vcap_actionfield_set_names[] = { + [VCAP_AFS_NO_VALUE] = "(None)", + [VCAP_AFS_BASE_TYPE] = "VCAP_AFS_BASE_TYPE", + [VCAP_AFS_CLASSIFICATION] = "VCAP_AFS_CLASSIFICATION", + [VCAP_AFS_CLASS_REDUCED] = "VCAP_AFS_CLASS_REDUCED", + [VCAP_AFS_ES0] = "VCAP_AFS_ES0", + [VCAP_AFS_FULL] = "VCAP_AFS_FULL", + [VCAP_AFS_SMAC_SIP] = "VCAP_AFS_SMAC_SIP", +}; + +/* Keyfield names */ +static const char * const vcap_keyfield_names[] = { + [VCAP_KF_NO_VALUE] = "(None)", + [VCAP_KF_8021BR_ECID_BASE] = "8021BR_ECID_BASE", + [VCAP_KF_8021BR_ECID_EXT] = "8021BR_ECID_EXT", + [VCAP_KF_8021BR_E_TAGGED] = "8021BR_E_TAGGED", + [VCAP_KF_8021BR_GRP] = "8021BR_GRP", + [VCAP_KF_8021BR_IGR_ECID_BASE] = "8021BR_IGR_ECID_BASE", + [VCAP_KF_8021BR_IGR_ECID_EXT] = "8021BR_IGR_ECID_EXT", + [VCAP_KF_8021Q_DEI0] = "8021Q_DEI0", + [VCAP_KF_8021Q_DEI1] = "8021Q_DEI1", + [VCAP_KF_8021Q_DEI2] = "8021Q_DEI2", + [VCAP_KF_8021Q_DEI_CLS] = "8021Q_DEI_CLS", + [VCAP_KF_8021Q_PCP0] = "8021Q_PCP0", + [VCAP_KF_8021Q_PCP1] = "8021Q_PCP1", + [VCAP_KF_8021Q_PCP2] = "8021Q_PCP2", + [VCAP_KF_8021Q_PCP_CLS] = "8021Q_PCP_CLS", + [VCAP_KF_8021Q_TPID] = "8021Q_TPID", + [VCAP_KF_8021Q_TPID0] = "8021Q_TPID0", + [VCAP_KF_8021Q_TPID1] = "8021Q_TPID1", + [VCAP_KF_8021Q_TPID2] = "8021Q_TPID2", + [VCAP_KF_8021Q_VID0] = "8021Q_VID0", + [VCAP_KF_8021Q_VID1] = "8021Q_VID1", + [VCAP_KF_8021Q_VID2] = "8021Q_VID2", + [VCAP_KF_8021Q_VID_CLS] = "8021Q_VID_CLS", + [VCAP_KF_8021Q_VLAN_TAGGED_IS] = "8021Q_VLAN_TAGGED_IS", + [VCAP_KF_8021Q_VLAN_TAGS] = "8021Q_VLAN_TAGS", + [VCAP_KF_ACL_GRP_ID] = "ACL_GRP_ID", + [VCAP_KF_ARP_ADDR_SPACE_OK_IS] = "ARP_ADDR_SPACE_OK_IS", + [VCAP_KF_ARP_LEN_OK_IS] = "ARP_LEN_OK_IS", + [VCAP_KF_ARP_OPCODE] = "ARP_OPCODE", + [VCAP_KF_ARP_OPCODE_UNKNOWN_IS] = "ARP_OPCODE_UNKNOWN_IS", + [VCAP_KF_ARP_PROTO_SPACE_OK_IS] = "ARP_PROTO_SPACE_OK_IS", + [VCAP_KF_ARP_SENDER_MATCH_IS] = "ARP_SENDER_MATCH_IS", + [VCAP_KF_ARP_TGT_MATCH_IS] = "ARP_TGT_MATCH_IS", + [VCAP_KF_COSID_CLS] = "COSID_CLS", + [VCAP_KF_ES0_ISDX_KEY_ENA] = "ES0_ISDX_KEY_ENA", + [VCAP_KF_ETYPE] = "ETYPE", + [VCAP_KF_ETYPE_LEN_IS] = "ETYPE_LEN_IS", + [VCAP_KF_HOST_MATCH] = "HOST_MATCH", + [VCAP_KF_IF_EGR_PORT_MASK] = "IF_EGR_PORT_MASK", + [VCAP_KF_IF_EGR_PORT_MASK_RNG] = "IF_EGR_PORT_MASK_RNG", + [VCAP_KF_IF_EGR_PORT_NO] = "IF_EGR_PORT_NO", + [VCAP_KF_IF_IGR_PORT] = "IF_IGR_PORT", + [VCAP_KF_IF_IGR_PORT_MASK] = "IF_IGR_PORT_MASK", + [VCAP_KF_IF_IGR_PORT_MASK_L3] = "IF_IGR_PORT_MASK_L3", + [VCAP_KF_IF_IGR_PORT_MASK_RNG] = "IF_IGR_PORT_MASK_RNG", + [VCAP_KF_IF_IGR_PORT_MASK_SEL] = "IF_IGR_PORT_MASK_SEL", + [VCAP_KF_IF_IGR_PORT_SEL] = "IF_IGR_PORT_SEL", + [VCAP_KF_IP4_IS] = "IP4_IS", + [VCAP_KF_IP_MC_IS] = "IP_MC_IS", + [VCAP_KF_IP_PAYLOAD_5TUPLE] = "IP_PAYLOAD_5TUPLE", + [VCAP_KF_IP_SNAP_IS] = "IP_SNAP_IS", + [VCAP_KF_ISDX_CLS] = "ISDX_CLS", + [VCAP_KF_ISDX_GT0_IS] = "ISDX_GT0_IS", + [VCAP_KF_L2_BC_IS] = "L2_BC_IS", + [VCAP_KF_L2_DMAC] = "L2_DMAC", + [VCAP_KF_L2_FRM_TYPE] = "L2_FRM_TYPE", + [VCAP_KF_L2_FWD_IS] = "L2_FWD_IS", + [VCAP_KF_L2_LLC] = "L2_LLC", + [VCAP_KF_L2_MC_IS] = "L2_MC_IS", + [VCAP_KF_L2_PAYLOAD0] = "L2_PAYLOAD0", + [VCAP_KF_L2_PAYLOAD1] = "L2_PAYLOAD1", + [VCAP_KF_L2_PAYLOAD2] = "L2_PAYLOAD2", + [VCAP_KF_L2_PAYLOAD_ETYPE] = "L2_PAYLOAD_ETYPE", + [VCAP_KF_L2_SMAC] = "L2_SMAC", + [VCAP_KF_L2_SNAP] = "L2_SNAP", + [VCAP_KF_L3_DIP_EQ_SIP_IS] = "L3_DIP_EQ_SIP_IS", + [VCAP_KF_L3_DPL_CLS] = "L3_DPL_CLS", + [VCAP_KF_L3_DSCP] = "L3_DSCP", + [VCAP_KF_L3_DST_IS] = "L3_DST_IS", + [VCAP_KF_L3_FRAGMENT] = "L3_FRAGMENT", + [VCAP_KF_L3_FRAGMENT_TYPE] = "L3_FRAGMENT_TYPE", + [VCAP_KF_L3_FRAG_INVLD_L4_LEN] = "L3_FRAG_INVLD_L4_LEN", + [VCAP_KF_L3_FRAG_OFS_GT0] = "L3_FRAG_OFS_GT0", + [VCAP_KF_L3_IP4_DIP] = "L3_IP4_DIP", + [VCAP_KF_L3_IP4_SIP] = "L3_IP4_SIP", + [VCAP_KF_L3_IP6_DIP] = "L3_IP6_DIP", + [VCAP_KF_L3_IP6_SIP] = "L3_IP6_SIP", + [VCAP_KF_L3_IP_PROTO] = "L3_IP_PROTO", + [VCAP_KF_L3_OPTIONS_IS] = "L3_OPTIONS_IS", + [VCAP_KF_L3_PAYLOAD] = "L3_PAYLOAD", + [VCAP_KF_L3_RT_IS] = "L3_RT_IS", + [VCAP_KF_L3_TOS] = "L3_TOS", + [VCAP_KF_L3_TTL_GT0] = "L3_TTL_GT0", + [VCAP_KF_L4_1588_DOM] = "L4_1588_DOM", + [VCAP_KF_L4_1588_VER] = "L4_1588_VER", + [VCAP_KF_L4_ACK] = "L4_ACK", + [VCAP_KF_L4_DPORT] = "L4_DPORT", + [VCAP_KF_L4_FIN] = "L4_FIN", + [VCAP_KF_L4_PAYLOAD] = "L4_PAYLOAD", + [VCAP_KF_L4_PSH] = "L4_PSH", + [VCAP_KF_L4_RNG] = "L4_RNG", + [VCAP_KF_L4_RST] = "L4_RST", + [VCAP_KF_L4_SEQUENCE_EQ0_IS] = "L4_SEQUENCE_EQ0_IS", + [VCAP_KF_L4_SPORT] = "L4_SPORT", + [VCAP_KF_L4_SPORT_EQ_DPORT_IS] = "L4_SPORT_EQ_DPORT_IS", + [VCAP_KF_L4_SYN] = "L4_SYN", + [VCAP_KF_L4_URG] = "L4_URG", + [VCAP_KF_LOOKUP_FIRST_IS] = "LOOKUP_FIRST_IS", + [VCAP_KF_LOOKUP_GEN_IDX] = "LOOKUP_GEN_IDX", + [VCAP_KF_LOOKUP_GEN_IDX_SEL] = "LOOKUP_GEN_IDX_SEL", + [VCAP_KF_LOOKUP_PAG] = "LOOKUP_PAG", + [VCAP_KF_MIRROR_PROBE] = "MIRROR_PROBE", + [VCAP_KF_OAM_CCM_CNTS_EQ0] = "OAM_CCM_CNTS_EQ0", + [VCAP_KF_OAM_DETECTED] = "OAM_DETECTED", + [VCAP_KF_OAM_FLAGS] = "OAM_FLAGS", + [VCAP_KF_OAM_MEL_FLAGS] = "OAM_MEL_FLAGS", + [VCAP_KF_OAM_MEPID] = "OAM_MEPID", + [VCAP_KF_OAM_OPCODE] = "OAM_OPCODE", + [VCAP_KF_OAM_VER] = "OAM_VER", + [VCAP_KF_OAM_Y1731_IS] = "OAM_Y1731_IS", + [VCAP_KF_PROT_ACTIVE] = "PROT_ACTIVE", + [VCAP_KF_TCP_IS] = "TCP_IS", + [VCAP_KF_TCP_UDP_IS] = "TCP_UDP_IS", + [VCAP_KF_TYPE] = "TYPE", +}; + +/* Actionfield names */ +static const char * const vcap_actionfield_names[] = { + [VCAP_AF_NO_VALUE] = "(None)", + [VCAP_AF_ACL_ID] = "ACL_ID", + [VCAP_AF_CLS_VID_SEL] = "CLS_VID_SEL", + [VCAP_AF_CNT_ID] = "CNT_ID", + [VCAP_AF_COPY_PORT_NUM] = "COPY_PORT_NUM", + [VCAP_AF_COPY_QUEUE_NUM] = "COPY_QUEUE_NUM", + [VCAP_AF_CPU_COPY_ENA] = "CPU_COPY_ENA", + [VCAP_AF_CPU_QU] = "CPU_QU", + [VCAP_AF_CPU_QUEUE_NUM] = "CPU_QUEUE_NUM", + [VCAP_AF_DEI_A_VAL] = "DEI_A_VAL", + [VCAP_AF_DEI_B_VAL] = "DEI_B_VAL", + [VCAP_AF_DEI_C_VAL] = "DEI_C_VAL", + [VCAP_AF_DEI_ENA] = "DEI_ENA", + [VCAP_AF_DEI_VAL] = "DEI_VAL", + [VCAP_AF_DP_ENA] = "DP_ENA", + [VCAP_AF_DP_VAL] = "DP_VAL", + [VCAP_AF_DSCP_ENA] = "DSCP_ENA", + [VCAP_AF_DSCP_SEL] = "DSCP_SEL", + [VCAP_AF_DSCP_VAL] = "DSCP_VAL", + [VCAP_AF_ES2_REW_CMD] = "ES2_REW_CMD", + [VCAP_AF_ESDX] = "ESDX", + [VCAP_AF_FWD_KILL_ENA] = "FWD_KILL_ENA", + [VCAP_AF_FWD_MODE] = "FWD_MODE", + [VCAP_AF_FWD_SEL] = "FWD_SEL", + [VCAP_AF_HIT_ME_ONCE] = "HIT_ME_ONCE", + [VCAP_AF_HOST_MATCH] = "HOST_MATCH", + [VCAP_AF_IGNORE_PIPELINE_CTRL] = "IGNORE_PIPELINE_CTRL", + [VCAP_AF_INTR_ENA] = "INTR_ENA", + [VCAP_AF_ISDX_ADD_REPLACE_SEL] = "ISDX_ADD_REPLACE_SEL", + [VCAP_AF_ISDX_ENA] = "ISDX_ENA", + [VCAP_AF_ISDX_VAL] = "ISDX_VAL", + [VCAP_AF_LOOP_ENA] = "LOOP_ENA", + [VCAP_AF_LRN_DIS] = "LRN_DIS", + [VCAP_AF_MAP_IDX] = "MAP_IDX", + [VCAP_AF_MAP_KEY] = "MAP_KEY", + [VCAP_AF_MAP_LOOKUP_SEL] = "MAP_LOOKUP_SEL", + [VCAP_AF_MASK_MODE] = "MASK_MODE", + [VCAP_AF_MATCH_ID] = "MATCH_ID", + [VCAP_AF_MATCH_ID_MASK] = "MATCH_ID_MASK", + [VCAP_AF_MIRROR_ENA] = "MIRROR_ENA", + [VCAP_AF_MIRROR_PROBE] = "MIRROR_PROBE", + [VCAP_AF_MIRROR_PROBE_ID] = "MIRROR_PROBE_ID", + [VCAP_AF_NXT_IDX] = "NXT_IDX", + [VCAP_AF_NXT_IDX_CTRL] = "NXT_IDX_CTRL", + [VCAP_AF_PAG_OVERRIDE_MASK] = "PAG_OVERRIDE_MASK", + [VCAP_AF_PAG_VAL] = "PAG_VAL", + [VCAP_AF_PCP_A_VAL] = "PCP_A_VAL", + [VCAP_AF_PCP_B_VAL] = "PCP_B_VAL", + [VCAP_AF_PCP_C_VAL] = "PCP_C_VAL", + [VCAP_AF_PCP_ENA] = "PCP_ENA", + [VCAP_AF_PCP_VAL] = "PCP_VAL", + [VCAP_AF_PIPELINE_ACT] = "PIPELINE_ACT", + [VCAP_AF_PIPELINE_FORCE_ENA] = "PIPELINE_FORCE_ENA", + [VCAP_AF_PIPELINE_PT] = "PIPELINE_PT", + [VCAP_AF_POLICE_ENA] = "POLICE_ENA", + [VCAP_AF_POLICE_IDX] = "POLICE_IDX", + [VCAP_AF_POLICE_REMARK] = "POLICE_REMARK", + [VCAP_AF_POLICE_VCAP_ONLY] = "POLICE_VCAP_ONLY", + [VCAP_AF_POP_VAL] = "POP_VAL", + [VCAP_AF_PORT_MASK] = "PORT_MASK", + [VCAP_AF_PUSH_CUSTOMER_TAG] = "PUSH_CUSTOMER_TAG", + [VCAP_AF_PUSH_INNER_TAG] = "PUSH_INNER_TAG", + [VCAP_AF_PUSH_OUTER_TAG] = "PUSH_OUTER_TAG", + [VCAP_AF_QOS_ENA] = "QOS_ENA", + [VCAP_AF_QOS_VAL] = "QOS_VAL", + [VCAP_AF_REW_OP] = "REW_OP", + [VCAP_AF_RT_DIS] = "RT_DIS", + [VCAP_AF_SWAP_MACS_ENA] = "SWAP_MACS_ENA", + [VCAP_AF_TAG_A_DEI_SEL] = "TAG_A_DEI_SEL", + [VCAP_AF_TAG_A_PCP_SEL] = "TAG_A_PCP_SEL", + [VCAP_AF_TAG_A_TPID_SEL] = "TAG_A_TPID_SEL", + [VCAP_AF_TAG_A_VID_SEL] = "TAG_A_VID_SEL", + [VCAP_AF_TAG_B_DEI_SEL] = "TAG_B_DEI_SEL", + [VCAP_AF_TAG_B_PCP_SEL] = "TAG_B_PCP_SEL", + [VCAP_AF_TAG_B_TPID_SEL] = "TAG_B_TPID_SEL", + [VCAP_AF_TAG_B_VID_SEL] = "TAG_B_VID_SEL", + [VCAP_AF_TAG_C_DEI_SEL] = "TAG_C_DEI_SEL", + [VCAP_AF_TAG_C_PCP_SEL] = "TAG_C_PCP_SEL", + [VCAP_AF_TAG_C_TPID_SEL] = "TAG_C_TPID_SEL", + [VCAP_AF_TAG_C_VID_SEL] = "TAG_C_VID_SEL", + [VCAP_AF_TYPE] = "TYPE", + [VCAP_AF_UNTAG_VID_ENA] = "UNTAG_VID_ENA", + [VCAP_AF_VID_A_VAL] = "VID_A_VAL", + [VCAP_AF_VID_B_VAL] = "VID_B_VAL", + [VCAP_AF_VID_C_VAL] = "VID_C_VAL", + [VCAP_AF_VID_VAL] = "VID_VAL", +}; + +/* VCAPs */ +const struct vcap_info lan969x_vcaps[] = { + [VCAP_TYPE_IS0] = { + .name = "is0", + .rows = 256, + .sw_count = 12, + .sw_width = 52, + .sticky_width = 1, + .act_width = 103, + .default_cnt = 70, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = is0_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(is0_keyfield_set), + .actionfield_set = is0_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(is0_actionfield_set), + .keyfield_set_map = is0_keyfield_set_map, + .keyfield_set_map_size = is0_keyfield_set_map_size, + .actionfield_set_map = is0_actionfield_set_map, + .actionfield_set_map_size = is0_actionfield_set_map_size, + .keyfield_set_typegroups = is0_keyfield_set_typegroups, + .actionfield_set_typegroups = is0_actionfield_set_typegroups, + }, + [VCAP_TYPE_IS2] = { + .name = "is2", + .rows = 256, + .sw_count = 12, + .sw_width = 52, + .sticky_width = 1, + .act_width = 103, + .default_cnt = 38, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = is2_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(is2_keyfield_set), + .actionfield_set = is2_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(is2_actionfield_set), + .keyfield_set_map = is2_keyfield_set_map, + .keyfield_set_map_size = is2_keyfield_set_map_size, + .actionfield_set_map = is2_actionfield_set_map, + .actionfield_set_map_size = is2_actionfield_set_map_size, + .keyfield_set_typegroups = is2_keyfield_set_typegroups, + .actionfield_set_typegroups = is2_actionfield_set_typegroups, + }, + [VCAP_TYPE_ES0] = { + .name = "es0", + .rows = 1536, + .sw_count = 1, + .sw_width = 51, + .sticky_width = 1, + .act_width = 469, + .default_cnt = 35, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = es0_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(es0_keyfield_set), + .actionfield_set = es0_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(es0_actionfield_set), + .keyfield_set_map = es0_keyfield_set_map, + .keyfield_set_map_size = es0_keyfield_set_map_size, + .actionfield_set_map = es0_actionfield_set_map, + .actionfield_set_map_size = es0_actionfield_set_map_size, + .keyfield_set_typegroups = es0_keyfield_set_typegroups, + .actionfield_set_typegroups = es0_actionfield_set_typegroups, + }, + [VCAP_TYPE_ES2] = { + .name = "es2", + .rows = 256, + .sw_count = 12, + .sw_width = 52, + .sticky_width = 1, + .act_width = 19, + .default_cnt = 39, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = es2_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(es2_keyfield_set), + .actionfield_set = es2_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(es2_actionfield_set), + .keyfield_set_map = es2_keyfield_set_map, + .keyfield_set_map_size = es2_keyfield_set_map_size, + .actionfield_set_map = es2_actionfield_set_map, + .actionfield_set_map_size = es2_actionfield_set_map_size, + .keyfield_set_typegroups = es2_keyfield_set_typegroups, + .actionfield_set_typegroups = es2_actionfield_set_typegroups, + }, +}; + +const struct vcap_statistics lan969x_vcap_stats = { + .name = "lan969x", + .count = 4, + .keyfield_set_names = vcap_keyfield_set_names, + .actionfield_set_names = vcap_actionfield_set_names, + .keyfield_names = vcap_keyfield_names, + .actionfield_names = vcap_actionfield_names, +}; diff --git a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_vcap_impl.c new file mode 100644 index 00000000000000..543a1f2bf6bd93 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_vcap_impl.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include "vcap_api.h" +#include "lan969x.h" + +const struct sparx5_vcap_inst lan969x_vcap_inst_cfg[] = { + { + .vtype = VCAP_TYPE_IS0, /* CLM-0 */ + .vinst = 0, + .map_id = 1, + .lookups = SPARX5_IS0_LOOKUPS, + .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3, + .first_cid = SPARX5_VCAP_CID_IS0_L0, + .last_cid = SPARX5_VCAP_CID_IS0_L2 - 1, + .blockno = 2, + .blocks = 1, + .ingress = true, + }, + { + .vtype = VCAP_TYPE_IS0, /* CLM-1 */ + .vinst = 1, + .map_id = 2, + .lookups = SPARX5_IS0_LOOKUPS, + .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3, + .first_cid = SPARX5_VCAP_CID_IS0_L2, + .last_cid = SPARX5_VCAP_CID_IS0_L4 - 1, + .blockno = 3, + .blocks = 1, + .ingress = true, + }, + { + .vtype = VCAP_TYPE_IS0, /* CLM-2 */ + .vinst = 2, + .map_id = 3, + .lookups = SPARX5_IS0_LOOKUPS, + .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3, + .first_cid = SPARX5_VCAP_CID_IS0_L4, + .last_cid = SPARX5_VCAP_CID_IS0_MAX, + .blockno = 4, + .blocks = 1, + .ingress = true, + }, + { + .vtype = VCAP_TYPE_IS2, /* IS2-0 */ + .vinst = 0, + .map_id = 4, + .lookups = SPARX5_IS2_LOOKUPS, + .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2, + .first_cid = SPARX5_VCAP_CID_IS2_L0, + .last_cid = SPARX5_VCAP_CID_IS2_L2 - 1, + .blockno = 0, + .blocks = 1, + .ingress = true, + }, + { + .vtype = VCAP_TYPE_IS2, /* IS2-1 */ + .vinst = 1, + .map_id = 5, + .lookups = SPARX5_IS2_LOOKUPS, + .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2, + .first_cid = SPARX5_VCAP_CID_IS2_L2, + .last_cid = SPARX5_VCAP_CID_IS2_MAX, + .blockno = 1, + .blocks = 1, + .ingress = true, + }, + { + .vtype = VCAP_TYPE_ES0, + .lookups = SPARX5_ES0_LOOKUPS, + .lookups_per_instance = SPARX5_ES0_LOOKUPS, + .first_cid = SPARX5_VCAP_CID_ES0_L0, + .last_cid = SPARX5_VCAP_CID_ES0_MAX, + .count = 1536, + .ingress = false, + }, + { + .vtype = VCAP_TYPE_ES2, + .lookups = SPARX5_ES2_LOOKUPS, + .lookups_per_instance = SPARX5_ES2_LOOKUPS, + .first_cid = SPARX5_VCAP_CID_ES2_L0, + .last_cid = SPARX5_VCAP_CID_ES2_MAX, + .count = 1024, + .ingress = false, + }, +}; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c b/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c index 76a8bb596aec1e..5c46d81de53006 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_calendar.c @@ -15,9 +15,6 @@ #define SPX5_CALBITS_PER_PORT 3 /* Bit per port in calendar register */ /* DSM calendar information */ -#define SPX5_DSM_CAL_LEN 64 -#define SPX5_DSM_CAL_EMPTY 0xFFFF -#define SPX5_DSM_CAL_MAX_DEVS_PER_TAXI 13 #define SPX5_DSM_CAL_TAXIS 8 #define SPX5_DSM_CAL_BW_LOSS 553 @@ -37,19 +34,6 @@ static u32 sparx5_taxi_ports[SPX5_DSM_CAL_TAXIS][SPX5_DSM_CAL_MAX_DEVS_PER_TAXI] {64, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}, }; -struct sparx5_calendar_data { - u32 schedule[SPX5_DSM_CAL_LEN]; - u32 avg_dist[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]; - u32 taxi_ports[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]; - u32 taxi_speeds[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]; - u32 dev_slots[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]; - u32 new_slots[SPX5_DSM_CAL_LEN]; - u32 temp_sched[SPX5_DSM_CAL_LEN]; - u32 indices[SPX5_DSM_CAL_LEN]; - u32 short_list[SPX5_DSM_CAL_LEN]; - u32 long_list[SPX5_DSM_CAL_LEN]; -}; - static u32 sparx5_target_bandwidth(struct sparx5 *sparx5) { switch (sparx5->target_ct) { @@ -68,27 +52,32 @@ static u32 sparx5_target_bandwidth(struct sparx5 *sparx5) case SPX5_TARGET_CT_7558: case SPX5_TARGET_CT_7558TSN: return 201000; + case SPX5_TARGET_CT_LAN9691VAO: + return 46000; + case SPX5_TARGET_CT_LAN9694RED: + case SPX5_TARGET_CT_LAN9694TSN: + case SPX5_TARGET_CT_LAN9694: + return 68000; + case SPX5_TARGET_CT_LAN9696RED: + case SPX5_TARGET_CT_LAN9696TSN: + case SPX5_TARGET_CT_LAN9692VAO: + case SPX5_TARGET_CT_LAN9696: + return 88000; + case SPX5_TARGET_CT_LAN9698RED: + case SPX5_TARGET_CT_LAN9698TSN: + case SPX5_TARGET_CT_LAN9693VAO: + case SPX5_TARGET_CT_LAN9698: + return 101000; default: return 0; } } -/* This is used in calendar configuration */ -enum sparx5_cal_bw { - SPX5_CAL_SPEED_NONE = 0, - SPX5_CAL_SPEED_1G = 1, - SPX5_CAL_SPEED_2G5 = 2, - SPX5_CAL_SPEED_5G = 3, - SPX5_CAL_SPEED_10G = 4, - SPX5_CAL_SPEED_25G = 5, - SPX5_CAL_SPEED_0G5 = 6, - SPX5_CAL_SPEED_12G5 = 7 -}; - static u32 sparx5_clk_to_bandwidth(enum sparx5_core_clockfreq cclock) { switch (cclock) { case SPX5_CORE_CLOCK_250MHZ: return 83000; /* 250000 / 3 */ + case SPX5_CORE_CLOCK_328MHZ: return 109375; /* 328000 / 3 */ case SPX5_CORE_CLOCK_500MHZ: return 166000; /* 500000 / 3 */ case SPX5_CORE_CLOCK_625MHZ: return 208000; /* 625000 / 3 */ default: return 0; @@ -96,7 +85,7 @@ static u32 sparx5_clk_to_bandwidth(enum sparx5_core_clockfreq cclock) return 0; } -static u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed) +u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed) { switch (speed) { case SPX5_CAL_SPEED_1G: return 1000; @@ -126,23 +115,28 @@ static u32 sparx5_bandwidth_to_calendar(u32 bw) } } -static enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, - u32 portno) +enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, u32 portno) { struct sparx5_port *port; - if (portno >= SPX5_PORTS) { + if (portno >= sparx5->data->consts->n_ports) { /* Internal ports */ - if (portno == SPX5_PORT_CPU_0 || portno == SPX5_PORT_CPU_1) { + if (portno == + sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_0) || + portno == + sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_1)) { /* Equals 1.25G */ return SPX5_CAL_SPEED_2G5; - } else if (portno == SPX5_PORT_VD0) { + } else if (portno == + sparx5_get_internal_port(sparx5, SPX5_PORT_VD0)) { /* IPMC only idle BW */ return SPX5_CAL_SPEED_NONE; - } else if (portno == SPX5_PORT_VD1) { + } else if (portno == + sparx5_get_internal_port(sparx5, SPX5_PORT_VD1)) { /* OAM only idle BW */ return SPX5_CAL_SPEED_NONE; - } else if (portno == SPX5_PORT_VD2) { + } else if (portno == + sparx5_get_internal_port(sparx5, SPX5_PORT_VD2)) { /* IPinIP gets only idle BW */ return SPX5_CAL_SPEED_NONE; } @@ -159,6 +153,7 @@ static enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, /* Auto configure the QSYS calendar based on port configuration */ int sparx5_config_auto_calendar(struct sparx5 *sparx5) { + const struct sparx5_consts *consts = sparx5->data->consts; u32 cal[7], value, idx, portno; u32 max_core_bw; u32 total_bw = 0, used_port_bw = 0; @@ -174,7 +169,7 @@ int sparx5_config_auto_calendar(struct sparx5 *sparx5) } /* Setup the calendar with the bandwidth to each port */ - for (portno = 0; portno < SPX5_PORTS_ALL; portno++) { + for (portno = 0; portno < consts->n_ports_all; portno++) { u64 reg, offset, this_bw; spd = sparx5_get_port_cal_speed(sparx5, portno); @@ -182,7 +177,7 @@ int sparx5_config_auto_calendar(struct sparx5 *sparx5) continue; this_bw = sparx5_cal_speed_to_value(spd); - if (portno < SPX5_PORTS) + if (portno < consts->n_ports) used_port_bw += this_bw; else /* Internal ports are granted half the value */ @@ -208,12 +203,13 @@ int sparx5_config_auto_calendar(struct sparx5 *sparx5) } /* Halt the calendar while changing it */ - spx5_rmw(QSYS_CAL_CTRL_CAL_MODE_SET(10), - QSYS_CAL_CTRL_CAL_MODE, - sparx5, QSYS_CAL_CTRL); + if (is_sparx5(sparx5)) + spx5_rmw(QSYS_CAL_CTRL_CAL_MODE_SET(10), + QSYS_CAL_CTRL_CAL_MODE, + sparx5, QSYS_CAL_CTRL); /* Assign port bandwidth to auto calendar */ - for (idx = 0; idx < ARRAY_SIZE(cal); idx++) + for (idx = 0; idx < consts->n_auto_cals; idx++) spx5_wr(cal[idx], sparx5, QSYS_CAL_AUTO(idx)); /* Increase grant rate of all ports to account for @@ -278,8 +274,8 @@ static u32 sparx5_dsm_cp_cal(u32 *sched) return SPX5_DSM_CAL_EMPTY; } -static int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi, - struct sparx5_calendar_data *data) +int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi, + struct sparx5_calendar_data *data) { bool slow_mode; u32 gcd, idx, sum, min, factor; @@ -304,7 +300,7 @@ static int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi, for (idx = 0; idx < SPX5_DSM_CAL_MAX_DEVS_PER_TAXI; idx++) { u32 portno = data->taxi_ports[idx]; - if (portno < SPX5_TAXI_PORT_MAX) { + if (portno < sparx5->data->consts->n_ports_all) { data->taxi_speeds[idx] = sparx5_cal_speed_to_value (sparx5_get_port_cal_speed(sparx5, portno)); } else { @@ -533,12 +529,23 @@ static int sparx5_dsm_calendar_check(struct sparx5 *sparx5, static int sparx5_dsm_calendar_update(struct sparx5 *sparx5, u32 taxi, struct sparx5_calendar_data *data) { - u32 idx; - u32 cal_len = sparx5_dsm_cal_len(data->schedule), len; + u32 cal_len = sparx5_dsm_cal_len(data->schedule), len, idx; + + if (!is_sparx5(sparx5)) { + u32 val, act; + + val = spx5_rd(sparx5, DSM_TAXI_CAL_CFG(taxi)); + act = DSM_TAXI_CAL_CFG_CAL_SEL_STAT_GET(val); - spx5_wr(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(1), - sparx5, - DSM_TAXI_CAL_CFG(taxi)); + spx5_rmw(DSM_TAXI_CAL_CFG_CAL_PGM_SEL_SET(!act), + DSM_TAXI_CAL_CFG_CAL_PGM_SEL, + sparx5, DSM_TAXI_CAL_CFG(taxi)); + } + + spx5_rmw(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(1), + DSM_TAXI_CAL_CFG_CAL_PGM_ENA, + sparx5, + DSM_TAXI_CAL_CFG(taxi)); for (idx = 0; idx < cal_len; idx++) { spx5_rmw(DSM_TAXI_CAL_CFG_CAL_IDX_SET(idx), DSM_TAXI_CAL_CFG_CAL_IDX, @@ -549,13 +556,21 @@ static int sparx5_dsm_calendar_update(struct sparx5 *sparx5, u32 taxi, sparx5, DSM_TAXI_CAL_CFG(taxi)); } - spx5_wr(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(0), - sparx5, - DSM_TAXI_CAL_CFG(taxi)); + spx5_rmw(DSM_TAXI_CAL_CFG_CAL_PGM_ENA_SET(0), + DSM_TAXI_CAL_CFG_CAL_PGM_ENA, + sparx5, + DSM_TAXI_CAL_CFG(taxi)); len = DSM_TAXI_CAL_CFG_CAL_CUR_LEN_GET(spx5_rd(sparx5, DSM_TAXI_CAL_CFG(taxi))); if (len != cal_len - 1) goto update_err; + + if (!is_sparx5(sparx5)) { + spx5_rmw(DSM_TAXI_CAL_CFG_CAL_SWITCH_SET(1), + DSM_TAXI_CAL_CFG_CAL_SWITCH, + sparx5, DSM_TAXI_CAL_CFG(taxi)); + } + return 0; update_err: dev_err(sparx5->dev, "Incorrect calendar length: %u\n", len); @@ -565,6 +580,7 @@ static int sparx5_dsm_calendar_update(struct sparx5 *sparx5, u32 taxi, /* Configure the DSM calendar based on port configuration */ int sparx5_config_dsm_calendar(struct sparx5 *sparx5) { + const struct sparx5_ops *ops = sparx5->data->ops; int taxi; struct sparx5_calendar_data *data; int err = 0; @@ -573,8 +589,8 @@ int sparx5_config_dsm_calendar(struct sparx5 *sparx5) if (!data) return -ENOMEM; - for (taxi = 0; taxi < SPX5_DSM_CAL_TAXIS; ++taxi) { - err = sparx5_dsm_calendar_calc(sparx5, taxi, data); + for (taxi = 0; taxi < sparx5->data->consts->n_dsm_cal_taxis; ++taxi) { + err = ops->dsm_calendar_calc(sparx5, taxi, data); if (err) { dev_err(sparx5->dev, "DSM calendar calculation failed\n"); goto cal_out; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c b/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c index 2d763664dcda18..10224ad63a788c 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c @@ -234,10 +234,11 @@ static int sparx5_dcb_ieee_dscp_setdel(struct net_device *dev, struct dcb_app *)) { struct sparx5_port *port = netdev_priv(dev); + struct sparx5 *sparx5 = port->sparx5; struct sparx5_port *port_itr; int err, i; - for (i = 0; i < SPX5_PORTS; i++) { + for (i = 0; i < sparx5->data->consts->n_ports; i++) { port_itr = port->sparx5->ports[i]; if (!port_itr) continue; @@ -386,7 +387,7 @@ int sparx5_dcb_init(struct sparx5 *sparx5) struct sparx5_port *port; int i; - for (i = 0; i < SPX5_PORTS; i++) { + for (i = 0; i < sparx5->data->consts->n_ports; i++) { port = sparx5->ports[i]; if (!port) continue; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c index d898a7238b4879..832f4ae57c83c1 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c @@ -505,8 +505,8 @@ static void sparx5_get_dev_misc_stats(u64 *portstats, void __iomem *inst, u32 static void sparx5_get_device_stats(struct sparx5 *sparx5, int portno) { u64 *portstats = &sparx5->stats[portno * sparx5->num_stats]; - u32 tinst = sparx5_port_dev_index(portno); - u32 dev = sparx5_to_high_dev(portno); + u32 tinst = sparx5_port_dev_index(sparx5, portno); + u32 dev = sparx5_to_high_dev(sparx5, portno); void __iomem *inst; inst = spx5_inst_get(sparx5, dev, tinst); @@ -819,8 +819,8 @@ static void sparx5_get_eth_phy_stats(struct net_device *ndev, portstats = &sparx5->stats[portno * sparx5->num_stats]; if (sparx5_is_baser(port->conf.portmode)) { - u32 tinst = sparx5_port_dev_index(portno); - u32 dev = sparx5_to_high_dev(portno); + u32 tinst = sparx5_port_dev_index(sparx5, portno); + u32 dev = sparx5_to_high_dev(sparx5, portno); inst = spx5_inst_get(sparx5, dev, tinst); sparx5_get_dev_phy_stats(portstats, inst, tinst); @@ -844,8 +844,8 @@ static void sparx5_get_eth_mac_stats(struct net_device *ndev, portstats = &sparx5->stats[portno * sparx5->num_stats]; if (sparx5_is_baser(port->conf.portmode)) { - u32 tinst = sparx5_port_dev_index(portno); - u32 dev = sparx5_to_high_dev(portno); + u32 tinst = sparx5_port_dev_index(sparx5, portno); + u32 dev = sparx5_to_high_dev(sparx5, portno); inst = spx5_inst_get(sparx5, dev, tinst); sparx5_get_dev_mac_stats(portstats, inst, tinst); @@ -912,8 +912,8 @@ static void sparx5_get_eth_mac_ctrl_stats(struct net_device *ndev, portstats = &sparx5->stats[portno * sparx5->num_stats]; if (sparx5_is_baser(port->conf.portmode)) { - u32 tinst = sparx5_port_dev_index(portno); - u32 dev = sparx5_to_high_dev(portno); + u32 tinst = sparx5_port_dev_index(sparx5, portno); + u32 dev = sparx5_to_high_dev(sparx5, portno); inst = spx5_inst_get(sparx5, dev, tinst); sparx5_get_dev_mac_ctrl_stats(portstats, inst, tinst); @@ -944,8 +944,8 @@ static void sparx5_get_eth_rmon_stats(struct net_device *ndev, portstats = &sparx5->stats[portno * sparx5->num_stats]; if (sparx5_is_baser(port->conf.portmode)) { - u32 tinst = sparx5_port_dev_index(portno); - u32 dev = sparx5_to_high_dev(portno); + u32 tinst = sparx5_port_dev_index(sparx5, portno); + u32 dev = sparx5_to_high_dev(sparx5, portno); inst = spx5_inst_get(sparx5, dev, tinst); sparx5_get_dev_rmon_stats(portstats, inst, tinst); @@ -1027,8 +1027,8 @@ static void sparx5_get_sset_data(struct net_device *ndev, portstats = &sparx5->stats[portno * sparx5->num_stats]; if (sparx5_is_baser(port->conf.portmode)) { - u32 tinst = sparx5_port_dev_index(portno); - u32 dev = sparx5_to_high_dev(portno); + u32 tinst = sparx5_port_dev_index(sparx5, portno); + u32 dev = sparx5_to_high_dev(sparx5, portno); inst = spx5_inst_get(sparx5, dev, tinst); sparx5_get_dev_misc_stats(portstats, inst, tinst); @@ -1122,7 +1122,7 @@ static void sparx5_update_stats(struct sparx5 *sparx5) { int idx; - for (idx = 0; idx < SPX5_PORTS; idx++) + for (idx = 0; idx < sparx5->data->consts->n_ports; idx++) if (sparx5->ports[idx]) sparx5_update_port_stats(sparx5, idx); } @@ -1189,7 +1189,7 @@ static int sparx5_get_ts_info(struct net_device *dev, struct sparx5 *sparx5 = port->sparx5; struct sparx5_phc *phc; - if (!sparx5->ptp) + if (!sparx5->ptp && is_sparx5(sparx5)) return ethtool_op_get_ts_info(dev, info); phc = &sparx5->phc[SPARX5_PHC_PORT]; @@ -1228,6 +1228,7 @@ const struct ethtool_ops sparx5_ethtool_ops = { int sparx_stats_init(struct sparx5 *sparx5) { + const struct sparx5_consts *consts = sparx5->data->consts; char queue_name[32]; int portno; @@ -1235,14 +1236,15 @@ int sparx_stats_init(struct sparx5 *sparx5) sparx5->num_stats = spx5_stats_count; sparx5->num_ethtool_stats = ARRAY_SIZE(sparx5_stats_layout); sparx5->stats = devm_kcalloc(sparx5->dev, - SPX5_PORTS_ALL * sparx5->num_stats, + consts->n_ports_all * + sparx5->num_stats, sizeof(u64), GFP_KERNEL); if (!sparx5->stats) return -ENOMEM; mutex_init(&sparx5->queue_stats_lock); sparx5_config_stats(sparx5); - for (portno = 0; portno < SPX5_PORTS; portno++) + for (portno = 0; portno < consts->n_ports; portno++) if (sparx5->ports[portno]) sparx5_config_port_stats(sparx5, portno); diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c index 61df874b762356..0027144a2af241 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c @@ -154,9 +154,11 @@ static bool sparx5_fdma_rx_get_frame(struct sparx5 *sparx5, struct sparx5_rx *rx skb = rx->skb[fdma->dcb_index][fdma->db_index]; skb_put(skb, fdma_db_len_get(db_hw)); /* Now do the normal processing of the skb */ - sparx5_ifh_parse((u32 *)skb->data, &fi); + sparx5_ifh_parse(sparx5, (u32 *)skb->data, &fi); /* Map to port netdev */ - port = fi.src_port < SPX5_PORTS ? sparx5->ports[fi.src_port] : NULL; + port = fi.src_port < sparx5->data->consts->n_ports ? + sparx5->ports[fi.src_port] : + NULL; if (!port || !port->ndev) { dev_err(sparx5->dev, "Data on inactive port %d\n", fi.src_port); sparx5_xtr_flush(sparx5, XTR_QUEUE); @@ -296,7 +298,7 @@ static void sparx5_fdma_rx_init(struct sparx5 *sparx5, fdma->ops.dataptr_cb = &sparx5_fdma_rx_dataptr_cb; fdma->ops.nextptr_cb = &fdma_nextptr_cb; /* Fetch a netdev for SKB and NAPI use, any will do */ - for (idx = 0; idx < SPX5_PORTS; ++idx) { + for (idx = 0; idx < sparx5->data->consts->n_ports; ++idx) { struct sparx5_port *port = sparx5->ports[idx]; if (port && port->ndev) { @@ -362,7 +364,9 @@ static void sparx5_fdma_injection_mode(struct sparx5 *sparx5) sparx5, QS_INJ_GRP_CFG(INJ_QUEUE)); /* CPU ports capture setup */ - for (portno = SPX5_PORT_CPU_0; portno <= SPX5_PORT_CPU_1; portno++) { + for (portno = sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_0); + portno <= sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_1); + portno++) { /* ASM CPU port: No preamble, IFH, enable padding */ spx5_wr(ASM_PORT_CFG_PAD_ENA_SET(1) | ASM_PORT_CFG_NO_PREAMBLE_ENA_SET(1) | diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c index 75868b3f548ec4..f5584244612cd9 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c @@ -80,15 +80,16 @@ static void sparx5_mact_select(struct sparx5 *sparx5, int sparx5_mact_learn(struct sparx5 *sparx5, int pgid, const unsigned char mac[ETH_ALEN], u16 vid) { + const struct sparx5_consts *consts = sparx5->data->consts; int addr, type, ret; - if (pgid < SPX5_PORTS) { + if (pgid < consts->n_ports) { type = MAC_ENTRY_ADDR_TYPE_UPSID_PN; addr = pgid % 32; addr += (pgid / 32) << 5; /* Add upsid */ } else { type = MAC_ENTRY_ADDR_TYPE_MC_IDX; - addr = pgid - SPX5_PORTS; + addr = pgid - consts->n_ports; } mutex_lock(&sparx5->lock); @@ -128,7 +129,8 @@ int sparx5_mc_sync(struct net_device *dev, const unsigned char *addr) struct sparx5_port *port = netdev_priv(dev); struct sparx5 *sparx5 = port->sparx5; - return sparx5_mact_learn(sparx5, PGID_CPU, addr, port->pvid); + return sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), + addr, port->pvid); } static int sparx5_mact_get(struct sparx5 *sparx5, @@ -371,7 +373,7 @@ static void sparx5_mact_handle_entry(struct sparx5 *sparx5, return; port = LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_GET(cfg2); - if (port >= SPX5_PORTS) + if (port >= sparx5->data->consts->n_ports) return; if (!test_bit(port, sparx5->bridge_mask)) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c index b64c814eac11e8..f61aa15beab7c6 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c @@ -24,13 +24,17 @@ #include #include +#include "lan969x/lan969x.h" /* for lan969x match data */ + #include "sparx5_main_regs.h" #include "sparx5_main.h" #include "sparx5_port.h" #include "sparx5_qos.h" +#include "sparx5_vcap_ag_api.h" +#include "sparx5_vcap_impl.h" + +const struct sparx5_regs *regs; -#define QLIM_WM(fraction) \ - ((SPX5_BUFFER_MEMORY / SPX5_BUFFER_CELL_SZ - 100) * (fraction) / 100) #define IO_RANGES 3 struct initial_port_config { @@ -45,12 +49,6 @@ struct sparx5_ram_config { u32 init_val; }; -struct sparx5_main_io_resource { - enum sparx5_target id; - phys_addr_t offset; - int range; -}; - static const struct sparx5_main_io_resource sparx5_main_iomap[] = { { TARGET_CPU, 0, 0 }, /* 0x600000000 */ { TARGET_FDMA, 0x80000, 0 }, /* 0x600080000 */ @@ -214,23 +212,79 @@ static const struct sparx5_main_io_resource sparx5_main_iomap[] = { { TARGET_VOP, 0x11a00000, 2 }, /* 0x611a00000 */ }; +bool is_sparx5(struct sparx5 *sparx5) +{ + switch (sparx5->target_ct) { + case SPX5_TARGET_CT_7546: + case SPX5_TARGET_CT_7549: + case SPX5_TARGET_CT_7552: + case SPX5_TARGET_CT_7556: + case SPX5_TARGET_CT_7558: + case SPX5_TARGET_CT_7546TSN: + case SPX5_TARGET_CT_7549TSN: + case SPX5_TARGET_CT_7552TSN: + case SPX5_TARGET_CT_7556TSN: + case SPX5_TARGET_CT_7558TSN: + return true; + default: + return false; + } +} + +static void sparx5_init_features(struct sparx5 *sparx5) +{ + switch (sparx5->target_ct) { + case SPX5_TARGET_CT_7546: + case SPX5_TARGET_CT_7549: + case SPX5_TARGET_CT_7552: + case SPX5_TARGET_CT_7556: + case SPX5_TARGET_CT_7558: + case SPX5_TARGET_CT_7546TSN: + case SPX5_TARGET_CT_7549TSN: + case SPX5_TARGET_CT_7552TSN: + case SPX5_TARGET_CT_7556TSN: + case SPX5_TARGET_CT_7558TSN: + case SPX5_TARGET_CT_LAN9691VAO: + case SPX5_TARGET_CT_LAN9694TSN: + case SPX5_TARGET_CT_LAN9694RED: + case SPX5_TARGET_CT_LAN9692VAO: + case SPX5_TARGET_CT_LAN9696TSN: + case SPX5_TARGET_CT_LAN9696RED: + case SPX5_TARGET_CT_LAN9693VAO: + case SPX5_TARGET_CT_LAN9698TSN: + case SPX5_TARGET_CT_LAN9698RED: + sparx5->features = (SPX5_FEATURE_PSFP | SPX5_FEATURE_PTP); + break; + default: + break; + } +} + +bool sparx5_has_feature(struct sparx5 *sparx5, enum sparx5_feature feature) +{ + return sparx5->features & feature; +} + static int sparx5_create_targets(struct sparx5 *sparx5) { + const struct sparx5_main_io_resource *iomap = sparx5->data->iomap; + int iomap_size = sparx5->data->iomap_size; + int ioranges = sparx5->data->ioranges; struct resource *iores[IO_RANGES]; void __iomem *iomem[IO_RANGES]; void __iomem *begin[IO_RANGES]; int range_id[IO_RANGES]; int idx, jdx; - for (idx = 0, jdx = 0; jdx < ARRAY_SIZE(sparx5_main_iomap); jdx++) { - const struct sparx5_main_io_resource *iomap = &sparx5_main_iomap[jdx]; + for (idx = 0, jdx = 0; jdx < iomap_size; jdx++) { + const struct sparx5_main_io_resource *io = &iomap[jdx]; - if (idx == iomap->range) { + if (idx == io->range) { range_id[idx] = jdx; idx++; } } - for (idx = 0; idx < IO_RANGES; idx++) { + for (idx = 0; idx < ioranges; idx++) { iores[idx] = platform_get_resource(sparx5->pdev, IORESOURCE_MEM, idx); if (!iores[idx]) { @@ -245,12 +299,12 @@ static int sparx5_create_targets(struct sparx5 *sparx5) iores[idx]->name); return -ENOMEM; } - begin[idx] = iomem[idx] - sparx5_main_iomap[range_id[idx]].offset; + begin[idx] = iomem[idx] - iomap[range_id[idx]].offset; } - for (jdx = 0; jdx < ARRAY_SIZE(sparx5_main_iomap); jdx++) { - const struct sparx5_main_io_resource *iomap = &sparx5_main_iomap[jdx]; + for (jdx = 0; jdx < iomap_size; jdx++) { + const struct sparx5_main_io_resource *io = &iomap[jdx]; - sparx5->regs[iomap->id] = begin[iomap->range] + iomap->offset; + sparx5->regs[io->id] = begin[io->range] + io->offset; } return 0; } @@ -459,56 +513,74 @@ static int sparx5_init_coreclock(struct sparx5 *sparx5) else if (sparx5->coreclock == SPX5_CORE_CLOCK_250MHZ) freq = 0; /* Not supported */ break; + case SPX5_TARGET_CT_LAN9694: + case SPX5_TARGET_CT_LAN9691VAO: + case SPX5_TARGET_CT_LAN9694TSN: + case SPX5_TARGET_CT_LAN9694RED: + case SPX5_TARGET_CT_LAN9696: + case SPX5_TARGET_CT_LAN9692VAO: + case SPX5_TARGET_CT_LAN9696TSN: + case SPX5_TARGET_CT_LAN9696RED: + case SPX5_TARGET_CT_LAN9698: + case SPX5_TARGET_CT_LAN9693VAO: + case SPX5_TARGET_CT_LAN9698TSN: + case SPX5_TARGET_CT_LAN9698RED: + freq = SPX5_CORE_CLOCK_328MHZ; + break; default: dev_err(sparx5->dev, "Target (%#04x) not supported\n", sparx5->target_ct); return -ENODEV; } - switch (freq) { - case SPX5_CORE_CLOCK_250MHZ: - clk_div = 10; - pol_upd_int = 312; - break; - case SPX5_CORE_CLOCK_500MHZ: - clk_div = 5; - pol_upd_int = 624; - break; - case SPX5_CORE_CLOCK_625MHZ: - clk_div = 4; - pol_upd_int = 780; - break; - default: - dev_err(sparx5->dev, "%d coreclock not supported on (%#04x)\n", - sparx5->coreclock, sparx5->target_ct); - return -EINVAL; + if (is_sparx5(sparx5)) { + switch (freq) { + case SPX5_CORE_CLOCK_250MHZ: + clk_div = 10; + pol_upd_int = 312; + break; + case SPX5_CORE_CLOCK_500MHZ: + clk_div = 5; + pol_upd_int = 624; + break; + case SPX5_CORE_CLOCK_625MHZ: + clk_div = 4; + pol_upd_int = 780; + break; + default: + dev_err(sparx5->dev, + "%d coreclock not supported on (%#04x)\n", + sparx5->coreclock, sparx5->target_ct); + return -EINVAL; + } + + /* Configure the LCPLL */ + spx5_rmw(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV_SET(clk_div) | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV_SET(0) | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR_SET(0) | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL_SET(0) | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA_SET(0) | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA_SET(1), + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA | + CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA, + sparx5, CLKGEN_LCPLL1_CORE_CLK_CFG); + } else { + pol_upd_int = 820; // SPX5_CORE_CLOCK_328MHZ } /* Update state with chosen frequency */ sparx5->coreclock = freq; - - /* Configure the LCPLL */ - spx5_rmw(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV_SET(clk_div) | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV_SET(0) | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR_SET(0) | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL_SET(0) | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA_SET(0) | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA_SET(1), - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA | - CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA, - sparx5, - CLKGEN_LCPLL1_CORE_CLK_CFG); - clk_period = sparx5_clk_period(freq); - spx5_rmw(HSCH_SYS_CLK_PER_100PS_SET(clk_period / 100), - HSCH_SYS_CLK_PER_100PS, - sparx5, - HSCH_SYS_CLK_PER); + if (is_sparx5(sparx5)) + spx5_rmw(HSCH_SYS_CLK_PER_100PS_SET(clk_period / 100), + HSCH_SYS_CLK_PER_100PS, + sparx5, + HSCH_SYS_CLK_PER); spx5_rmw(ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS_SET(clk_period / 100), ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS, @@ -525,7 +597,7 @@ static int sparx5_init_coreclock(struct sparx5 *sparx5) sparx5, LRN_AUTOAGE_CFG_1); - for (idx = 0; idx < 3; idx++) + for (idx = 0; idx < sparx5->data->consts->n_sio_clks; idx++) spx5_rmw(GCB_SIO_CLOCK_SYS_CLK_PERIOD_SET(clk_period / 100), GCB_SIO_CLOCK_SYS_CLK_PERIOD, sparx5, @@ -545,25 +617,36 @@ static int sparx5_init_coreclock(struct sparx5 *sparx5) return 0; } +static u32 qlim_wm(struct sparx5 *sparx5, int fraction) +{ + return (sparx5->data->consts->buf_size / SPX5_BUFFER_CELL_SZ - 100) * + fraction / 100; +} + static int sparx5_qlim_set(struct sparx5 *sparx5) { + const struct sparx5_consts *consts = sparx5->data->consts; u32 res, dp, prio; for (res = 0; res < 2; res++) { for (prio = 0; prio < 8; prio++) spx5_wr(0xFFF, sparx5, - QRES_RES_CFG(prio + 630 + res * 1024)); + QRES_RES_CFG(prio + + consts->qres_max_prio_idx + + res * 1024)); for (dp = 0; dp < 4; dp++) spx5_wr(0xFFF, sparx5, - QRES_RES_CFG(dp + 638 + res * 1024)); + QRES_RES_CFG(dp + + consts->qres_max_colour_idx + + res * 1024)); } /* Set 80,90,95,100% of memory size for top watermarks */ - spx5_wr(QLIM_WM(80), sparx5, XQS_QLIMIT_SHR_QLIM_CFG(0)); - spx5_wr(QLIM_WM(90), sparx5, XQS_QLIMIT_SHR_CTOP_CFG(0)); - spx5_wr(QLIM_WM(95), sparx5, XQS_QLIMIT_SHR_ATOP_CFG(0)); - spx5_wr(QLIM_WM(100), sparx5, XQS_QLIMIT_SHR_TOP_CFG(0)); + spx5_wr(qlim_wm(sparx5, 80), sparx5, XQS_QLIMIT_SHR_QLIM_CFG(0)); + spx5_wr(qlim_wm(sparx5, 90), sparx5, XQS_QLIMIT_SHR_CTOP_CFG(0)); + spx5_wr(qlim_wm(sparx5, 95), sparx5, XQS_QLIMIT_SHR_ATOP_CFG(0)); + spx5_wr(qlim_wm(sparx5, 100), sparx5, XQS_QLIMIT_SHR_TOP_CFG(0)); return 0; } @@ -585,7 +668,7 @@ static void sparx5_board_init(struct sparx5 *sparx5) GCB_HW_SGPIO_SD_CFG); /* Refer to LOS SGPIO */ - for (idx = 0; idx < SPX5_PORTS; idx++) + for (idx = 0; idx < sparx5->data->consts->n_ports; idx++) if (sparx5->ports[idx]) if (sparx5->ports[idx]->conf.sd_sgpio != ~0) spx5_wr(sparx5->ports[idx]->conf.sd_sgpio, @@ -596,12 +679,14 @@ static void sparx5_board_init(struct sparx5 *sparx5) static int sparx5_start(struct sparx5 *sparx5) { u8 broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const struct sparx5_consts *consts = sparx5->data->consts; + const struct sparx5_ops *ops = sparx5->data->ops; char queue_name[32]; u32 idx; int err; /* Setup own UPSIDs */ - for (idx = 0; idx < 3; idx++) { + for (idx = 0; idx < consts->n_own_upsids; idx++) { spx5_wr(idx, sparx5, ANA_AC_OWN_UPSID(idx)); spx5_wr(idx, sparx5, ANA_CL_OWN_UPSID(idx)); spx5_wr(idx, sparx5, ANA_L2_OWN_UPSID(idx)); @@ -609,7 +694,7 @@ static int sparx5_start(struct sparx5 *sparx5) } /* Enable CPU ports */ - for (idx = SPX5_PORTS; idx < SPX5_PORTS_ALL; idx++) + for (idx = consts->n_ports; idx < consts->n_ports_all; idx++) spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(1), QFWD_SWITCH_PORT_MODE_PORT_ENA, sparx5, @@ -619,13 +704,14 @@ static int sparx5_start(struct sparx5 *sparx5) sparx5_update_fwd(sparx5); /* CPU copy CPU pgids */ - spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1), - sparx5, ANA_AC_PGID_MISC_CFG(PGID_CPU)); - spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1), - sparx5, ANA_AC_PGID_MISC_CFG(PGID_BCAST)); + spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1), sparx5, + ANA_AC_PGID_MISC_CFG(sparx5_get_pgid(sparx5, PGID_CPU))); + spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1), sparx5, + ANA_AC_PGID_MISC_CFG(sparx5_get_pgid(sparx5, PGID_BCAST))); /* Recalc injected frame FCS */ - for (idx = SPX5_PORT_CPU_0; idx <= SPX5_PORT_CPU_1; idx++) + for (idx = sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_0); + idx <= sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_1); idx++) spx5_rmw(ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA_SET(1), ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA, sparx5, ANA_CL_FILTER_CTRL(idx)); @@ -640,7 +726,8 @@ static int sparx5_start(struct sparx5 *sparx5) sparx5_vlan_init(sparx5); /* Add host mode BC address (points only to CPU) */ - sparx5_mact_learn(sparx5, PGID_CPU, broadcast, NULL_VID); + sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), broadcast, + NULL_VID); /* Enable queue limitation watermarks */ sparx5_qlim_set(sparx5); @@ -691,14 +778,13 @@ static int sparx5_start(struct sparx5 *sparx5) /* Start Frame DMA with fallback to register based INJ/XTR */ err = -ENXIO; - if (sparx5->fdma_irq >= 0) { + if (sparx5->fdma_irq >= 0 && is_sparx5(sparx5)) { if (GCB_CHIP_ID_REV_ID_GET(sparx5->chip_id) > 0) - err = devm_request_threaded_irq(sparx5->dev, - sparx5->fdma_irq, - NULL, - sparx5_fdma_handler, - IRQF_ONESHOT, - "sparx5-fdma", sparx5); + err = devm_request_irq(sparx5->dev, + sparx5->fdma_irq, + sparx5_fdma_handler, + 0, + "sparx5-fdma", sparx5); if (!err) err = sparx5_fdma_start(sparx5); if (err) @@ -718,9 +804,10 @@ static int sparx5_start(struct sparx5 *sparx5) sparx5->xtr_irq = -ENXIO; } - if (sparx5->ptp_irq >= 0) { + if (sparx5->ptp_irq >= 0 && + sparx5_has_feature(sparx5, SPX5_FEATURE_PTP)) { err = devm_request_threaded_irq(sparx5->dev, sparx5->ptp_irq, - NULL, sparx5_ptp_irq_handler, + NULL, ops->ptp_irq_handler, IRQF_ONESHOT, "sparx5-ptp", sparx5); if (err) @@ -759,6 +846,12 @@ static int mchp_sparx5_probe(struct platform_device *pdev) sparx5->dev = &pdev->dev; spin_lock_init(&sparx5->tx_lock); + sparx5->data = device_get_match_data(sparx5->dev); + if (!sparx5->data) + return -EINVAL; + + regs = sparx5->data->regs; + /* Do switch core reset if available */ reset = devm_reset_control_get_optional_shared(&pdev->dev, "switch"); if (IS_ERR(reset)) @@ -856,6 +949,9 @@ static int mchp_sparx5_probe(struct platform_device *pdev) sparx5->target_ct = (enum spx5_target_chiptype) GCB_CHIP_ID_PART_ID_GET(sparx5->chip_id); + /* Initialize the features based on the target */ + sparx5_init_features(sparx5); + /* Initialize Switchcore and internal RAMs */ err = sparx5_init_switchcore(sparx5); if (err) { @@ -937,15 +1033,75 @@ static void mchp_sparx5_remove(struct platform_device *pdev) destroy_workqueue(sparx5->mact_queue); } +static const struct sparx5_regs sparx5_regs = { + .tsize = sparx5_tsize, + .gaddr = sparx5_gaddr, + .gcnt = sparx5_gcnt, + .gsize = sparx5_gsize, + .raddr = sparx5_raddr, + .rcnt = sparx5_rcnt, + .fpos = sparx5_fpos, + .fsize = sparx5_fsize, +}; + +static const struct sparx5_consts sparx5_consts = { + .n_ports = 65, + .n_ports_all = 70, + .n_hsch_l1_elems = 64, + .n_hsch_queues = 8, + .n_lb_groups = 10, + .n_pgids = 2113, /* (2048 + n_ports) */ + .n_sio_clks = 3, + .n_own_upsids = 3, + .n_auto_cals = 7, + .n_filters = 1024, + .n_gates = 1024, + .n_sdlbs = 4096, + .n_dsm_cal_taxis = 8, + .buf_size = 4194280, + .qres_max_prio_idx = 630, + .qres_max_colour_idx = 638, + .tod_pin = 4, + .vcaps = sparx5_vcaps, + .vcaps_cfg = sparx5_vcap_inst_cfg, + .vcap_stats = &sparx5_vcap_stats, +}; + +static const struct sparx5_ops sparx5_ops = { + .is_port_2g5 = &sparx5_port_is_2g5, + .is_port_5g = &sparx5_port_is_5g, + .is_port_10g = &sparx5_port_is_10g, + .is_port_25g = &sparx5_port_is_25g, + .get_port_dev_index = &sparx5_port_dev_mapping, + .get_port_dev_bit = &sparx5_port_dev_mapping, + .get_hsch_max_group_rate = &sparx5_get_hsch_max_group_rate, + .get_sdlb_group = &sparx5_get_sdlb_group, + .set_port_mux = &sparx5_port_mux_set, + .ptp_irq_handler = &sparx5_ptp_irq_handler, + .dsm_calendar_calc = &sparx5_dsm_calendar_calc, +}; + +static const struct sparx5_match_data sparx5_desc = { + .iomap = sparx5_main_iomap, + .iomap_size = ARRAY_SIZE(sparx5_main_iomap), + .ioranges = 3, + .regs = &sparx5_regs, + .consts = &sparx5_consts, + .ops = &sparx5_ops, +}; + static const struct of_device_id mchp_sparx5_match[] = { - { .compatible = "microchip,sparx5-switch" }, + { .compatible = "microchip,sparx5-switch", .data = &sparx5_desc }, +#ifdef CONFIG_LAN969X_SWITCH + { .compatible = "microchip,lan9691-switch", .data = &lan969x_desc }, +#endif { } }; MODULE_DEVICE_TABLE(of, mchp_sparx5_match); static struct platform_driver mchp_sparx5_driver = { .probe = mchp_sparx5_probe, - .remove_new = mchp_sparx5_remove, + .remove = mchp_sparx5_remove, .driver = { .name = "sparx5-switch", .of_match_table = mchp_sparx5_match, diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h index 3309060b1e4c6e..d5dd953b0a71d9 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h @@ -26,16 +26,28 @@ /* Target chip type */ enum spx5_target_chiptype { - SPX5_TARGET_CT_7546 = 0x7546, /* SparX-5-64 Enterprise */ - SPX5_TARGET_CT_7549 = 0x7549, /* SparX-5-90 Enterprise */ - SPX5_TARGET_CT_7552 = 0x7552, /* SparX-5-128 Enterprise */ - SPX5_TARGET_CT_7556 = 0x7556, /* SparX-5-160 Enterprise */ - SPX5_TARGET_CT_7558 = 0x7558, /* SparX-5-200 Enterprise */ - SPX5_TARGET_CT_7546TSN = 0x47546, /* SparX-5-64i Industrial */ - SPX5_TARGET_CT_7549TSN = 0x47549, /* SparX-5-90i Industrial */ - SPX5_TARGET_CT_7552TSN = 0x47552, /* SparX-5-128i Industrial */ - SPX5_TARGET_CT_7556TSN = 0x47556, /* SparX-5-160i Industrial */ - SPX5_TARGET_CT_7558TSN = 0x47558, /* SparX-5-200i Industrial */ + SPX5_TARGET_CT_7546 = 0x7546, /* SparX-5-64 Enterprise */ + SPX5_TARGET_CT_7549 = 0x7549, /* SparX-5-90 Enterprise */ + SPX5_TARGET_CT_7552 = 0x7552, /* SparX-5-128 Enterprise */ + SPX5_TARGET_CT_7556 = 0x7556, /* SparX-5-160 Enterprise */ + SPX5_TARGET_CT_7558 = 0x7558, /* SparX-5-200 Enterprise */ + SPX5_TARGET_CT_7546TSN = 0x47546, /* SparX-5-64i Industrial */ + SPX5_TARGET_CT_7549TSN = 0x47549, /* SparX-5-90i Industrial */ + SPX5_TARGET_CT_7552TSN = 0x47552, /* SparX-5-128i Industrial */ + SPX5_TARGET_CT_7556TSN = 0x47556, /* SparX-5-160i Industrial */ + SPX5_TARGET_CT_7558TSN = 0x47558, /* SparX-5-200i Industrial */ + SPX5_TARGET_CT_LAN9694 = 0x9694, /* lan969x-40 */ + SPX5_TARGET_CT_LAN9691VAO = 0x9691, /* lan969x-40-VAO */ + SPX5_TARGET_CT_LAN9694TSN = 0x9695, /* lan969x-40-TSN */ + SPX5_TARGET_CT_LAN9694RED = 0x969A, /* lan969x-40-RED */ + SPX5_TARGET_CT_LAN9696 = 0x9696, /* lan969x-60 */ + SPX5_TARGET_CT_LAN9692VAO = 0x9692, /* lan969x-65-VAO */ + SPX5_TARGET_CT_LAN9696TSN = 0x9697, /* lan969x-60-TSN */ + SPX5_TARGET_CT_LAN9696RED = 0x969B, /* lan969x-60-RED */ + SPX5_TARGET_CT_LAN9698 = 0x9698, /* lan969x-100 */ + SPX5_TARGET_CT_LAN9693VAO = 0x9693, /* lan969x-100-VAO */ + SPX5_TARGET_CT_LAN9698TSN = 0x9699, /* lan969x-100-TSN */ + SPX5_TARGET_CT_LAN9698RED = 0x969C, /* lan969x-100-RED */ }; enum sparx5_port_max_tags { @@ -51,25 +63,41 @@ enum sparx5_vlan_port_type { SPX5_VLAN_PORT_TYPE_S_CUSTOM /* S-port using custom type */ }; +/* This is used in calendar configuration */ +enum sparx5_cal_bw { + SPX5_CAL_SPEED_NONE = 0, + SPX5_CAL_SPEED_1G = 1, + SPX5_CAL_SPEED_2G5 = 2, + SPX5_CAL_SPEED_5G = 3, + SPX5_CAL_SPEED_10G = 4, + SPX5_CAL_SPEED_25G = 5, + SPX5_CAL_SPEED_0G5 = 6, + SPX5_CAL_SPEED_12G5 = 7 +}; + +enum sparx5_feature { + SPX5_FEATURE_PSFP = BIT(0), + SPX5_FEATURE_PTP = BIT(1), +}; + #define SPX5_PORTS 65 -#define SPX5_PORT_CPU (SPX5_PORTS) /* Next port is CPU port */ -#define SPX5_PORT_CPU_0 (SPX5_PORT_CPU + 0) /* CPU Port 65 */ -#define SPX5_PORT_CPU_1 (SPX5_PORT_CPU + 1) /* CPU Port 66 */ -#define SPX5_PORT_VD0 (SPX5_PORT_CPU + 2) /* VD0/Port 67 used for IPMC */ -#define SPX5_PORT_VD1 (SPX5_PORT_CPU + 3) /* VD1/Port 68 used for AFI/OAM */ -#define SPX5_PORT_VD2 (SPX5_PORT_CPU + 4) /* VD2/Port 69 used for IPinIP*/ -#define SPX5_PORTS_ALL (SPX5_PORT_CPU + 5) /* Total number of ports */ - -#define PGID_BASE SPX5_PORTS /* Starts after port PGIDs */ -#define PGID_UC_FLOOD (PGID_BASE + 0) -#define PGID_MC_FLOOD (PGID_BASE + 1) -#define PGID_IPV4_MC_DATA (PGID_BASE + 2) -#define PGID_IPV4_MC_CTRL (PGID_BASE + 3) -#define PGID_IPV6_MC_DATA (PGID_BASE + 4) -#define PGID_IPV6_MC_CTRL (PGID_BASE + 5) -#define PGID_BCAST (PGID_BASE + 6) -#define PGID_CPU (PGID_BASE + 7) -#define PGID_MCAST_START (PGID_BASE + 8) +#define SPX5_PORTS_ALL 70 /* Total number of ports */ + +#define SPX5_PORT_CPU_0 0 /* CPU Port 0 */ +#define SPX5_PORT_CPU_1 1 /* CPU Port 1 */ +#define SPX5_PORT_VD0 2 /* VD0/Port used for IPMC */ +#define SPX5_PORT_VD1 3 /* VD1/Port used for AFI/OAM */ +#define SPX5_PORT_VD2 4 /* VD2/Port used for IPinIP*/ + +#define PGID_UC_FLOOD 0 +#define PGID_MC_FLOOD 1 +#define PGID_IPV4_MC_DATA 2 +#define PGID_IPV4_MC_CTRL 3 +#define PGID_IPV6_MC_DATA 4 +#define PGID_IPV6_MC_CTRL 5 +#define PGID_BCAST 6 +#define PGID_CPU 7 +#define PGID_MCAST_START 8 #define PGID_TABLE_SIZE 3290 @@ -100,8 +128,27 @@ enum sparx5_vlan_port_type { #define IFH_PDU_TYPE_IPV4_UDP_PTP 0x6 #define IFH_PDU_TYPE_IPV6_UDP_PTP 0x7 +#define SPX5_DSM_CAL_LEN 64 +#define SPX5_DSM_CAL_MAX_DEVS_PER_TAXI 13 +#define SPX5_DSM_CAL_EMPTY 0xFFFF + +#define SPARX5_MAX_PTP_ID 512 + struct sparx5; +struct sparx5_calendar_data { + u32 schedule[SPX5_DSM_CAL_LEN]; + u32 avg_dist[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]; + u32 taxi_ports[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]; + u32 taxi_speeds[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]; + u32 dev_slots[SPX5_DSM_CAL_MAX_DEVS_PER_TAXI]; + u32 new_slots[SPX5_DSM_CAL_LEN]; + u32 temp_sched[SPX5_DSM_CAL_LEN]; + u32 indices[SPX5_DSM_CAL_LEN]; + u32 short_list[SPX5_DSM_CAL_LEN]; + u32 long_list[SPX5_DSM_CAL_LEN]; +}; + /* Frame DMA receive state: * For each DB, there is a SKB, and the skb data pointer is mapped in * the DB. Once a frame is received the skb is given to the upper layers @@ -177,6 +224,7 @@ struct sparx5_port { enum sparx5_core_clockfreq { SPX5_CORE_CLOCK_DEFAULT, /* Defaults to the highest supported frequency */ SPX5_CORE_CLOCK_250MHZ, /* 250MHZ core clock frequency */ + SPX5_CORE_CLOCK_328MHZ, /* 328MHZ core clock frequency */ SPX5_CORE_CLOCK_500MHZ, /* 500MHZ core clock frequency */ SPX5_CORE_CLOCK_625MHZ, /* 625MHZ core clock frequency */ }; @@ -226,11 +274,78 @@ struct sparx5_mall_entry { #define SPARX5_SKB_CB(skb) \ ((struct sparx5_skb_cb *)((skb)->cb)) +struct sparx5_regs { + const unsigned int *tsize; + const unsigned int *gaddr; + const unsigned int *gcnt; + const unsigned int *gsize; + const unsigned int *raddr; + const unsigned int *rcnt; + const unsigned int *fpos; + const unsigned int *fsize; +}; + +struct sparx5_consts { + u32 n_ports; /* Number of front ports */ + u32 n_ports_all; /* Number of front ports + internal ports */ + u32 n_hsch_l1_elems; /* Number of HSCH layer 1 elements */ + u32 n_hsch_queues; /* Number of HSCH queues */ + u32 n_lb_groups; /* Number of leacky bucket groupd */ + u32 n_pgids; /* Number of PGID's */ + u32 n_sio_clks; /* Number of serial IO clocks */ + u32 n_own_upsids; /* Number of own UPSID's */ + u32 n_auto_cals; /* Number of auto calendars */ + u32 n_filters; /* Number of PSFP filters */ + u32 n_gates; /* Number of PSFP gates */ + u32 n_sdlbs; /* Number of service dual leaky buckets */ + u32 n_dsm_cal_taxis; /* Number of DSM calendar taxis */ + u32 buf_size; /* Amount of QLIM watermark memory */ + u32 qres_max_prio_idx; /* Maximum QRES prio index */ + u32 qres_max_colour_idx; /* Maximum QRES colour index */ + u32 tod_pin; /* PTP TOD pin */ + const struct sparx5_vcap_inst *vcaps_cfg; + const struct vcap_info *vcaps; + const struct vcap_statistics *vcap_stats; +}; + +struct sparx5_ops { + bool (*is_port_2g5)(int portno); + bool (*is_port_5g)(int portno); + bool (*is_port_10g)(int portno); + bool (*is_port_25g)(int portno); + u32 (*get_port_dev_index)(struct sparx5 *sparx5, int port); + u32 (*get_port_dev_bit)(struct sparx5 *sparx5, int port); + u32 (*get_hsch_max_group_rate)(int grp); + struct sparx5_sdlb_group *(*get_sdlb_group)(int idx); + int (*set_port_mux)(struct sparx5 *sparx5, struct sparx5_port *port, + struct sparx5_port_config *conf); + + irqreturn_t (*ptp_irq_handler)(int irq, void *args); + int (*dsm_calendar_calc)(struct sparx5 *sparx5, u32 taxi, + struct sparx5_calendar_data *data); +}; + +struct sparx5_main_io_resource { + enum sparx5_target id; + phys_addr_t offset; + int range; +}; + +struct sparx5_match_data { + const struct sparx5_regs *regs; + const struct sparx5_consts *consts; + const struct sparx5_ops *ops; + const struct sparx5_main_io_resource *iomap; + int ioranges; + int iomap_size; +}; + struct sparx5 { struct platform_device *pdev; struct device *dev; u32 chip_id; enum spx5_target_chiptype target_ct; + u32 features; void __iomem *regs[NUM_TARGETS]; int port_count; struct mutex lock; /* MAC reg lock */ @@ -293,8 +408,13 @@ struct sparx5 { struct list_head mall_entries; /* Common root for debugfs */ struct dentry *debugfs_root; + const struct sparx5_match_data *data; }; +/* sparx5_main.c */ +bool is_sparx5(struct sparx5 *sparx5); +bool sparx5_has_feature(struct sparx5 *sparx5, enum sparx5_feature feature); + /* sparx5_switchdev.c */ int sparx5_register_notifier_blocks(struct sparx5 *sparx5); void sparx5_unregister_notifier_blocks(struct sparx5 *sparx5); @@ -306,7 +426,7 @@ struct frame_info { }; void sparx5_xtr_flush(struct sparx5 *sparx5, u8 grp); -void sparx5_ifh_parse(u32 *ifh, struct frame_info *info); +void sparx5_ifh_parse(struct sparx5 *sparx5, u32 *ifh, struct frame_info *info); irqreturn_t sparx5_xtr_handler(int irq, void *_priv); netdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev); int sparx5_manual_injection_mode(struct sparx5 *sparx5); @@ -355,6 +475,11 @@ void sparx5_vlan_port_apply(struct sparx5 *sparx5, struct sparx5_port *port); /* sparx5_calendar.c */ int sparx5_config_auto_calendar(struct sparx5 *sparx5); int sparx5_config_dsm_calendar(struct sparx5 *sparx5); +int sparx5_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi, + struct sparx5_calendar_data *data); +u32 sparx5_cal_speed_to_value(enum sparx5_cal_bw speed); +enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, u32 portno); + /* sparx5_ethtool.c */ void sparx5_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats); @@ -371,11 +496,14 @@ static inline int sparx5_dcb_init(struct sparx5 *sparx5) #endif /* sparx5_netdev.c */ -void sparx5_set_port_ifh_timestamp(void *ifh_hdr, u64 timestamp); +void sparx5_set_port_ifh_timestamp(struct sparx5 *sparx5, void *ifh_hdr, + u64 timestamp); void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op); -void sparx5_set_port_ifh_pdu_type(void *ifh_hdr, u32 pdu_type); -void sparx5_set_port_ifh_pdu_w16_offset(void *ifh_hdr, u32 pdu_w16_offset); -void sparx5_set_port_ifh(void *ifh_hdr, u16 portno); +void sparx5_set_port_ifh_pdu_type(struct sparx5 *sparx5, void *ifh_hdr, + u32 pdu_type); +void sparx5_set_port_ifh_pdu_w16_offset(struct sparx5 *sparx5, void *ifh_hdr, + u32 pdu_w16_offset); +void sparx5_set_port_ifh(struct sparx5 *sparx5, void *ifh_hdr, u16 portno); bool sparx5_netdevice_check(const struct net_device *dev); struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno); int sparx5_register_netdevs(struct sparx5 *sparx5); @@ -398,6 +526,9 @@ void sparx5_ptp_txtstamp_release(struct sparx5_port *port, struct sk_buff *skb); irqreturn_t sparx5_ptp_irq_handler(int irq, void *args); int sparx5_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); +void sparx5_get_hwtimestamp(struct sparx5 *sparx5, + struct timespec64 *ts, + u32 nsec); /* sparx5_vcap_impl.c */ int sparx5_vcap_init(struct sparx5 *sparx5); @@ -413,6 +544,7 @@ enum sparx5_pgid_type { void sparx5_pgid_init(struct sparx5 *spx5); int sparx5_pgid_alloc_mcast(struct sparx5 *spx5, u16 *idx); int sparx5_pgid_free(struct sparx5 *spx5, u16 idx); +int sparx5_get_pgid(struct sparx5 *sparx5, int pgid); /* sparx5_pool.c */ struct sparx5_pool_entry { @@ -426,6 +558,11 @@ int sparx5_pool_get(struct sparx5_pool_entry *pool, int size, u32 *id); int sparx5_pool_get_with_idx(struct sparx5_pool_entry *pool, int size, u32 idx, u32 *id); +/* sparx5_port.c */ +int sparx5_port_mux_set(struct sparx5 *sparx5, struct sparx5_port *port, + struct sparx5_port_config *conf); +int sparx5_get_internal_port(struct sparx5 *sparx5, int port); + /* sparx5_sdlb.c */ #define SPX5_SDLB_PUP_TOKEN_DISABLE 0x1FFF #define SPX5_SDLB_PUP_TOKEN_MAX (SPX5_SDLB_PUP_TOKEN_DISABLE - 1) @@ -444,10 +581,11 @@ struct sparx5_sdlb_group { }; extern struct sparx5_sdlb_group sdlb_groups[SPX5_SDLB_GROUP_CNT]; +struct sparx5_sdlb_group *sparx5_get_sdlb_group(int idx); int sparx5_sdlb_pup_token_get(struct sparx5 *sparx5, u32 pup_interval, u64 rate); -int sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5); +u64 sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5); int sparx5_sdlb_group_get_by_rate(struct sparx5 *sparx5, u32 rate, u32 burst); int sparx5_sdlb_group_get_by_index(struct sparx5 *sparx5, u32 idx, u32 *group); @@ -549,6 +687,8 @@ static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock) switch (cclock) { case SPX5_CORE_CLOCK_250MHZ: return 4000; + case SPX5_CORE_CLOCK_328MHZ: + return 3048; case SPX5_CORE_CLOCK_500MHZ: return 2000; case SPX5_CORE_CLOCK_625MHZ: diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h index 22acc1f3380ca2..561344f1906273 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0+ * Microchip Sparx5 Switch driver * - * Copyright (c) 2021 Microchip Technology Inc. + * Copyright (c) 2024 Microchip Technology Inc. */ -/* This file is autogenerated by cml-utils 2023-02-10 11:18:53 +0100. - * Commit ID: c30fb4bf0281cd4a7133bdab6682f9e43c872ada +/* This file is autogenerated by cml-utils 2024-10-04 10:40:40 +0200. + * Commit ID: 9d07b8d19363f3cd3590ddb3f7a2e2768e16524b */ #ifndef _SPARX5_MAIN_REGS_H_ @@ -15,6 +15,8 @@ #include #include +#include "sparx5_regs.h" + enum sparx5_target { TARGET_ANA_AC = 1, TARGET_ANA_ACL = 2, @@ -52,14 +54,27 @@ enum sparx5_target { TARGET_VCAP_SUPER = 326, TARGET_VOP = 327, TARGET_XQS = 331, - NUM_TARGETS = 332 + NUM_TARGETS = 517 }; +/* sparx5_main.c + * + * This is used by the register macros to access chip differences (if any) in: + * target size, register address, register count, group address, group count, + * group size, field position and field size. + */ +extern const struct sparx5_regs *regs; + +/* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ +#define spx5_field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) +#define spx5_field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) + #define __REG(...) __VA_ARGS__ -/* ANA_AC:RAM_CTRL:RAM_INIT */ -#define ANA_AC_RAM_INIT __REG(TARGET_ANA_AC,\ - 0, 1, 839108, 0, 1, 4, 0, 0, 1, 4) +/* ANA_AC:RAM_CTRL:RAM_INIT */ +#define ANA_AC_RAM_INIT \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_RAM_CTRL], 0, 1, 4, 0,\ + 0, 1, 4) #define ANA_AC_RAM_INIT_RAM_INIT BIT(1) #define ANA_AC_RAM_INIT_RAM_INIT_SET(x)\ @@ -73,9 +88,10 @@ enum sparx5_target { #define ANA_AC_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(ANA_AC_RAM_INIT_RAM_CFG_HOOK, x) -/* ANA_AC:PS_COMMON:OWN_UPSID */ -#define ANA_AC_OWN_UPSID(r) __REG(TARGET_ANA_AC,\ - 0, 1, 894472, 0, 1, 352, 52, r, 3, 4) +/* ANA_AC:PS_COMMON:OWN_UPSID */ +#define ANA_AC_OWN_UPSID(r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_PS_COMMON], 0, 1, 352,\ + 52, r, regs->rcnt[RC_ANA_AC_OWN_UPSID], 4) #define ANA_AC_OWN_UPSID_OWN_UPSID GENMASK(4, 0) #define ANA_AC_OWN_UPSID_OWN_UPSID_SET(x)\ @@ -83,75 +99,86 @@ enum sparx5_target { #define ANA_AC_OWN_UPSID_OWN_UPSID_GET(x)\ FIELD_GET(ANA_AC_OWN_UPSID_OWN_UPSID, x) -/* ANA_AC:MIRROR_PROBE:PROBE_CFG */ -#define ANA_AC_PROBE_CFG(g) \ - __REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 0, 0, 1, 4) +/* ANA_AC:MIRROR_PROBE:PROBE_CFG */ +#define ANA_AC_PROBE_CFG(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_MIRROR_PROBE], g, 3, \ + 32, 0, 0, 1, 4) -#define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD GENMASK(31, 27) +#define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD GENMASK(31, 27) #define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD_SET(x)\ FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD, x) #define ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD_GET(x)\ FIELD_GET(ANA_AC_PROBE_CFG_PROBE_RX_CPU_AND_VD, x) -#define ANA_AC_PROBE_CFG_PROBE_CPU_SET GENMASK(26, 19) +#define ANA_AC_PROBE_CFG_PROBE_CPU_SET GENMASK(26, 19) #define ANA_AC_PROBE_CFG_PROBE_CPU_SET_SET(x)\ FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_CPU_SET, x) #define ANA_AC_PROBE_CFG_PROBE_CPU_SET_GET(x)\ FIELD_GET(ANA_AC_PROBE_CFG_PROBE_CPU_SET, x) -#define ANA_AC_PROBE_CFG_PROBE_VID GENMASK(18, 6) +#define ANA_AC_PROBE_CFG_PROBE_VID GENMASK(18, 6) #define ANA_AC_PROBE_CFG_PROBE_VID_SET(x)\ FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_VID, x) #define ANA_AC_PROBE_CFG_PROBE_VID_GET(x)\ FIELD_GET(ANA_AC_PROBE_CFG_PROBE_VID, x) -#define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE GENMASK(5, 4) +#define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE GENMASK(5, 4) #define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE_SET(x)\ FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_VLAN_MODE, x) #define ANA_AC_PROBE_CFG_PROBE_VLAN_MODE_GET(x)\ FIELD_GET(ANA_AC_PROBE_CFG_PROBE_VLAN_MODE, x) -#define ANA_AC_PROBE_CFG_PROBE_MAC_MODE GENMASK(3, 2) +#define ANA_AC_PROBE_CFG_PROBE_MAC_MODE GENMASK(3, 2) #define ANA_AC_PROBE_CFG_PROBE_MAC_MODE_SET(x)\ FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_MAC_MODE, x) #define ANA_AC_PROBE_CFG_PROBE_MAC_MODE_GET(x)\ FIELD_GET(ANA_AC_PROBE_CFG_PROBE_MAC_MODE, x) -#define ANA_AC_PROBE_CFG_PROBE_DIRECTION GENMASK(1, 0) +#define ANA_AC_PROBE_CFG_PROBE_DIRECTION GENMASK(1, 0) #define ANA_AC_PROBE_CFG_PROBE_DIRECTION_SET(x)\ FIELD_PREP(ANA_AC_PROBE_CFG_PROBE_DIRECTION, x) #define ANA_AC_PROBE_CFG_PROBE_DIRECTION_GET(x)\ FIELD_GET(ANA_AC_PROBE_CFG_PROBE_DIRECTION, x) -/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG */ -#define ANA_AC_PROBE_PORT_CFG(g) \ - __REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 8, 0, 1, 4) +/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG */ +#define ANA_AC_PROBE_PORT_CFG(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_MIRROR_PROBE], g, 3, \ + 32, 8, 0, 1, 4) -/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG1 */ -#define ANA_AC_PROBE_PORT_CFG1(g) \ - __REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 12, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG1 */ +#define ANA_AC_PROBE_PORT_CFG1(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_MIRROR_PROBE], g, 3, \ + 32, 12, 0, 1, 4) -/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG2 */ -#define ANA_AC_PROBE_PORT_CFG2(g) \ - __REG(TARGET_ANA_AC, 0, 1, 893696, g, 3, 32, 16, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_AC:MIRROR_PROBE:PROBE_PORT_CFG2 */ +#define ANA_AC_PROBE_PORT_CFG2(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_MIRROR_PROBE], g, 3, \ + 32, 16, 0, 1, 4) -#define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2 BIT(0) +#define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2 BIT(0) #define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2_SET(x)\ FIELD_PREP(ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2, x) #define ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2_GET(x)\ FIELD_GET(ANA_AC_PROBE_PORT_CFG2_PROBE_PORT_MASK2, x) -/* ANA_AC:SRC:SRC_CFG */ -#define ANA_AC_SRC_CFG(g) __REG(TARGET_ANA_AC,\ - 0, 1, 849920, g, 102, 16, 0, 0, 1, 4) +/* ANA_AC:SRC:SRC_CFG */ +#define ANA_AC_SRC_CFG(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SRC], g, \ + regs->gcnt[GC_ANA_AC_SRC], regs->gsize[GW_ANA_AC_SRC], 0, 0, 1, 4) -/* ANA_AC:SRC:SRC_CFG1 */ -#define ANA_AC_SRC_CFG1(g) __REG(TARGET_ANA_AC,\ - 0, 1, 849920, g, 102, 16, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_AC:SRC:SRC_CFG1 */ +#define ANA_AC_SRC_CFG1(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SRC], g, \ + regs->gcnt[GC_ANA_AC_SRC], regs->gsize[GW_ANA_AC_SRC], 4, 0, 1, 4) -/* ANA_AC:SRC:SRC_CFG2 */ -#define ANA_AC_SRC_CFG2(g) __REG(TARGET_ANA_AC,\ - 0, 1, 849920, g, 102, 16, 8, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_AC:SRC:SRC_CFG2 */ +#define ANA_AC_SRC_CFG2(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SRC], g, \ + regs->gcnt[GC_ANA_AC_SRC], regs->gsize[GW_ANA_AC_SRC], 8, 0, 1, 4) #define ANA_AC_SRC_CFG2_PORT_MASK2 BIT(0) #define ANA_AC_SRC_CFG2_PORT_MASK2_SET(x)\ @@ -159,17 +186,22 @@ enum sparx5_target { #define ANA_AC_SRC_CFG2_PORT_MASK2_GET(x)\ FIELD_GET(ANA_AC_SRC_CFG2_PORT_MASK2, x) -/* ANA_AC:PGID:PGID_CFG */ -#define ANA_AC_PGID_CFG(g) __REG(TARGET_ANA_AC,\ - 0, 1, 786432, g, 3290, 16, 0, 0, 1, 4) +/* ANA_AC:PGID:PGID_CFG */ +#define ANA_AC_PGID_CFG(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_PGID], g, \ + regs->gcnt[GC_ANA_AC_PGID], 16, 0, 0, 1, 4) -/* ANA_AC:PGID:PGID_CFG1 */ -#define ANA_AC_PGID_CFG1(g) __REG(TARGET_ANA_AC,\ - 0, 1, 786432, g, 3290, 16, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_AC:PGID:PGID_CFG1 */ +#define ANA_AC_PGID_CFG1(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_PGID], g, \ + regs->gcnt[GC_ANA_AC_PGID], 16, 4, 0, 1, 4) -/* ANA_AC:PGID:PGID_CFG2 */ -#define ANA_AC_PGID_CFG2(g) __REG(TARGET_ANA_AC,\ - 0, 1, 786432, g, 3290, 16, 8, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_AC:PGID:PGID_CFG2 */ +#define ANA_AC_PGID_CFG2(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_PGID], g, \ + regs->gcnt[GC_ANA_AC_PGID], 16, 8, 0, 1, 4) #define ANA_AC_PGID_CFG2_PORT_MASK2 BIT(0) #define ANA_AC_PGID_CFG2_PORT_MASK2_SET(x)\ @@ -177,9 +209,10 @@ enum sparx5_target { #define ANA_AC_PGID_CFG2_PORT_MASK2_GET(x)\ FIELD_GET(ANA_AC_PGID_CFG2_PORT_MASK2, x) -/* ANA_AC:PGID:PGID_MISC_CFG */ -#define ANA_AC_PGID_MISC_CFG(g) __REG(TARGET_ANA_AC,\ - 0, 1, 786432, g, 3290, 16, 12, 0, 1, 4) +/* ANA_AC:PGID:PGID_MISC_CFG */ +#define ANA_AC_PGID_MISC_CFG(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_PGID], g, \ + regs->gcnt[GC_ANA_AC_PGID], 16, 12, 0, 1, 4) #define ANA_AC_PGID_MISC_CFG_PGID_CPU_QU GENMASK(6, 4) #define ANA_AC_PGID_MISC_CFG_PGID_CPU_QU_SET(x)\ @@ -199,9 +232,10 @@ enum sparx5_target { #define ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_GET(x)\ FIELD_GET(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, x) -/* ANA_AC:TSN_SF:TSN_SF */ -#define ANA_AC_TSN_SF __REG(TARGET_ANA_AC,\ - 0, 1, 839136, 0, 1, 4, 0, 0, 1, 4) +/* ANA_AC:TSN_SF:TSN_SF */ +#define ANA_AC_TSN_SF \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_TSN_SF], 0, 1, 4, 0, \ + 0, 1, 4) #define ANA_AC_TSN_SF_TSN_STREAM_BLOCK_OVERSIZE_STICKY BIT(9) #define ANA_AC_TSN_SF_TSN_STREAM_BLOCK_OVERSIZE_STICKY_SET(x)\ @@ -209,21 +243,24 @@ enum sparx5_target { #define ANA_AC_TSN_SF_TSN_STREAM_BLOCK_OVERSIZE_STICKY_GET(x)\ FIELD_GET(ANA_AC_TSN_SF_TSN_STREAM_BLOCK_OVERSIZE_STICKY, x) -#define ANA_AC_TSN_SF_PORT_NUM GENMASK(8, 0) +#define ANA_AC_TSN_SF_PORT_NUM\ + GENMASK(regs->fsize[FW_ANA_AC_TSN_SF_PORT_NUM] + 0 - 1, 0) #define ANA_AC_TSN_SF_PORT_NUM_SET(x)\ - FIELD_PREP(ANA_AC_TSN_SF_PORT_NUM, x) + spx5_field_prep(ANA_AC_TSN_SF_PORT_NUM, x) #define ANA_AC_TSN_SF_PORT_NUM_GET(x)\ - FIELD_GET(ANA_AC_TSN_SF_PORT_NUM, x) + spx5_field_get(ANA_AC_TSN_SF_PORT_NUM, x) -/* ANA_AC:TSN_SF_CFG:TSN_SF_CFG */ -#define ANA_AC_TSN_SF_CFG(g) __REG(TARGET_ANA_AC,\ - 0, 1, 839680, g, 1024, 4, 0, 0, 1, 4) +/* ANA_AC:TSN_SF_CFG:TSN_SF_CFG */ +#define ANA_AC_TSN_SF_CFG(g) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_TSN_SF_CFG], g, \ + regs->gcnt[GC_ANA_AC_TSN_SF_CFG], 4, 0, 0, 1, 4) -#define ANA_AC_TSN_SF_CFG_TSN_SGID GENMASK(25, 16) +#define ANA_AC_TSN_SF_CFG_TSN_SGID\ + GENMASK(regs->fsize[FW_ANA_AC_TSN_SF_CFG_TSN_SGID] + 16 - 1, 16) #define ANA_AC_TSN_SF_CFG_TSN_SGID_SET(x)\ - FIELD_PREP(ANA_AC_TSN_SF_CFG_TSN_SGID, x) + spx5_field_prep(ANA_AC_TSN_SF_CFG_TSN_SGID, x) #define ANA_AC_TSN_SF_CFG_TSN_SGID_GET(x)\ - FIELD_GET(ANA_AC_TSN_SF_CFG_TSN_SGID, x) + spx5_field_get(ANA_AC_TSN_SF_CFG_TSN_SGID, x) #define ANA_AC_TSN_SF_CFG_TSN_MAX_SDU GENMASK(15, 2) #define ANA_AC_TSN_SF_CFG_TSN_MAX_SDU_SET(x)\ @@ -243,9 +280,10 @@ enum sparx5_target { #define ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_STATE_GET(x)\ FIELD_GET(ANA_AC_TSN_SF_CFG_BLOCK_OVERSIZE_STATE, x) -/* ANA_AC:TSN_SF_STATUS:TSN_SF_STATUS */ -#define ANA_AC_TSN_SF_STATUS __REG(TARGET_ANA_AC,\ - 0, 1, 839072, 0, 1, 16, 0, 0, 1, 4) +/* ANA_AC:TSN_SF_STATUS:TSN_SF_STATUS */ +#define ANA_AC_TSN_SF_STATUS \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_TSN_SF_STATUS], 0, 1, \ + 16, 0, 0, 1, 4) #define ANA_AC_TSN_SF_STATUS_FRM_LEN GENMASK(25, 12) #define ANA_AC_TSN_SF_STATUS_FRM_LEN_SET(x)\ @@ -259,11 +297,12 @@ enum sparx5_target { #define ANA_AC_TSN_SF_STATUS_DLB_DROP_GET(x)\ FIELD_GET(ANA_AC_TSN_SF_STATUS_DLB_DROP, x) -#define ANA_AC_TSN_SF_STATUS_TSN_SFID GENMASK(10, 1) +#define ANA_AC_TSN_SF_STATUS_TSN_SFID\ + GENMASK(regs->fsize[FW_ANA_AC_TSN_SF_STATUS_TSN_SFID] + 1 - 1, 1) #define ANA_AC_TSN_SF_STATUS_TSN_SFID_SET(x)\ - FIELD_PREP(ANA_AC_TSN_SF_STATUS_TSN_SFID, x) + spx5_field_prep(ANA_AC_TSN_SF_STATUS_TSN_SFID, x) #define ANA_AC_TSN_SF_STATUS_TSN_SFID_GET(x)\ - FIELD_GET(ANA_AC_TSN_SF_STATUS_TSN_SFID, x) + spx5_field_get(ANA_AC_TSN_SF_STATUS_TSN_SFID, x) #define ANA_AC_TSN_SF_STATUS_TSTAMP_VLD BIT(0) #define ANA_AC_TSN_SF_STATUS_TSTAMP_VLD_SET(x)\ @@ -271,15 +310,17 @@ enum sparx5_target { #define ANA_AC_TSN_SF_STATUS_TSTAMP_VLD_GET(x)\ FIELD_GET(ANA_AC_TSN_SF_STATUS_TSTAMP_VLD, x) -/* ANA_AC:SG_ACCESS:SG_ACCESS_CTRL */ -#define ANA_AC_SG_ACCESS_CTRL __REG(TARGET_ANA_AC,\ - 0, 1, 839140, 0, 1, 12, 0, 0, 1, 4) +/* ANA_AC:SG_ACCESS:SG_ACCESS_CTRL */ +#define ANA_AC_SG_ACCESS_CTRL \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_ACCESS], 0, 1, 12, \ + 0, 0, 1, 4) -#define ANA_AC_SG_ACCESS_CTRL_SGID GENMASK(9, 0) +#define ANA_AC_SG_ACCESS_CTRL_SGID\ + GENMASK(regs->fsize[FW_ANA_AC_SG_ACCESS_CTRL_SGID] + 0 - 1, 0) #define ANA_AC_SG_ACCESS_CTRL_SGID_SET(x)\ - FIELD_PREP(ANA_AC_SG_ACCESS_CTRL_SGID, x) + spx5_field_prep(ANA_AC_SG_ACCESS_CTRL_SGID, x) #define ANA_AC_SG_ACCESS_CTRL_SGID_GET(x)\ - FIELD_GET(ANA_AC_SG_ACCESS_CTRL_SGID, x) + spx5_field_get(ANA_AC_SG_ACCESS_CTRL_SGID, x) #define ANA_AC_SG_ACCESS_CTRL_CONFIG_CHANGE BIT(28) #define ANA_AC_SG_ACCESS_CTRL_CONFIG_CHANGE_SET(x)\ @@ -287,9 +328,10 @@ enum sparx5_target { #define ANA_AC_SG_ACCESS_CTRL_CONFIG_CHANGE_GET(x)\ FIELD_GET(ANA_AC_SG_ACCESS_CTRL_CONFIG_CHANGE, x) -/* ANA_AC:SG_ACCESS:SG_CYCLETIME_UPDATE_PERIOD */ -#define ANA_AC_SG_CYCLETIME_UPDATE_PERIOD __REG(TARGET_ANA_AC,\ - 0, 1, 839140, 0, 1, 12, 8, 0, 1, 4) +/* ANA_AC:SG_ACCESS:SG_CYCLETIME_UPDATE_PERIOD */ +#define ANA_AC_SG_CYCLETIME_UPDATE_PERIOD \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_ACCESS], 0, 1, 12, \ + 8, 0, 1, 4) #define ANA_AC_SG_CYCLETIME_UPDATE_PERIOD_SG_CT_CLKS GENMASK(15, 0) #define ANA_AC_SG_CYCLETIME_UPDATE_PERIOD_SG_CT_CLKS_SET(x)\ @@ -303,17 +345,20 @@ enum sparx5_target { #define ANA_AC_SG_CYCLETIME_UPDATE_PERIOD_SG_CT_UPDATE_ENA_GET(x)\ FIELD_GET(ANA_AC_SG_CYCLETIME_UPDATE_PERIOD_SG_CT_UPDATE_ENA, x) -/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_1 */ -#define ANA_AC_SG_CONFIG_REG_1 __REG(TARGET_ANA_AC,\ - 0, 1, 851584, 0, 1, 128, 48, 0, 1, 4) +/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_1 */ +#define ANA_AC_SG_CONFIG_REG_1 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_CONFIG], 0, 1, 128,\ + 48, 0, 1, 4) -/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_2 */ -#define ANA_AC_SG_CONFIG_REG_2 __REG(TARGET_ANA_AC,\ - 0, 1, 851584, 0, 1, 128, 52, 0, 1, 4) +/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_2 */ +#define ANA_AC_SG_CONFIG_REG_2 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_CONFIG], 0, 1, 128,\ + 52, 0, 1, 4) -/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_3 */ -#define ANA_AC_SG_CONFIG_REG_3 __REG(TARGET_ANA_AC,\ - 0, 1, 851584, 0, 1, 128, 56, 0, 1, 4) +/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_3 */ +#define ANA_AC_SG_CONFIG_REG_3 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_CONFIG], 0, 1, 128,\ + 56, 0, 1, 4) #define ANA_AC_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB GENMASK(15, 0) #define ANA_AC_SG_CONFIG_REG_3_BASE_TIME_SEC_MSB_SET(x)\ @@ -369,17 +414,20 @@ enum sparx5_target { #define ANA_AC_SG_CONFIG_REG_3_OCTETS_EXCEEDED_GET(x)\ FIELD_GET(ANA_AC_SG_CONFIG_REG_3_OCTETS_EXCEEDED, x) -/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_4 */ -#define ANA_AC_SG_CONFIG_REG_4 __REG(TARGET_ANA_AC,\ - 0, 1, 851584, 0, 1, 128, 60, 0, 1, 4) +/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_4 */ +#define ANA_AC_SG_CONFIG_REG_4 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_CONFIG], 0, 1, 128,\ + 60, 0, 1, 4) -/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_5 */ -#define ANA_AC_SG_CONFIG_REG_5 __REG(TARGET_ANA_AC,\ - 0, 1, 851584, 0, 1, 128, 64, 0, 1, 4) +/* ANA_AC:SG_CONFIG:SG_CONFIG_REG_5 */ +#define ANA_AC_SG_CONFIG_REG_5 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_CONFIG], 0, 1, 128,\ + 64, 0, 1, 4) -/* ANA_AC:SG_CONFIG:SG_GCL_GS_CONFIG */ -#define ANA_AC_SG_GCL_GS_CONFIG(r) __REG(TARGET_ANA_AC,\ - 0, 1, 851584, 0, 1, 128, 0, r, 4, 4) +/* ANA_AC:SG_CONFIG:SG_GCL_GS_CONFIG */ +#define ANA_AC_SG_GCL_GS_CONFIG(r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_CONFIG], 0, 1, 128,\ + 0, r, 4, 4) #define ANA_AC_SG_GCL_GS_CONFIG_IPS GENMASK(3, 0) #define ANA_AC_SG_GCL_GS_CONFIG_IPS_SET(x)\ @@ -393,25 +441,30 @@ enum sparx5_target { #define ANA_AC_SG_GCL_GS_CONFIG_GATE_STATE_GET(x)\ FIELD_GET(ANA_AC_SG_GCL_GS_CONFIG_GATE_STATE, x) -/* ANA_AC:SG_CONFIG:SG_GCL_TI_CONFIG */ -#define ANA_AC_SG_GCL_TI_CONFIG(r) __REG(TARGET_ANA_AC,\ - 0, 1, 851584, 0, 1, 128, 16, r, 4, 4) +/* ANA_AC:SG_CONFIG:SG_GCL_TI_CONFIG */ +#define ANA_AC_SG_GCL_TI_CONFIG(r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_CONFIG], 0, 1, 128,\ + 16, r, 4, 4) -/* ANA_AC:SG_CONFIG:SG_GCL_OCT_CONFIG */ -#define ANA_AC_SG_GCL_OCT_CONFIG(r) __REG(TARGET_ANA_AC,\ - 0, 1, 851584, 0, 1, 128, 32, r, 4, 4) +/* ANA_AC:SG_CONFIG:SG_GCL_OCT_CONFIG */ +#define ANA_AC_SG_GCL_OCT_CONFIG(r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_CONFIG], 0, 1, 128,\ + 32, r, 4, 4) -/* ANA_AC:SG_STATUS:SG_STATUS_REG_1 */ -#define ANA_AC_SG_STATUS_REG_1 __REG(TARGET_ANA_AC,\ - 0, 1, 839088, 0, 1, 16, 0, 0, 1, 4) +/* ANA_AC:SG_STATUS:SG_STATUS_REG_1 */ +#define ANA_AC_SG_STATUS_REG_1 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_STATUS], 0, 1, 16, \ + 0, 0, 1, 4) -/* ANA_AC:SG_STATUS:SG_STATUS_REG_2 */ -#define ANA_AC_SG_STATUS_REG_2 __REG(TARGET_ANA_AC,\ - 0, 1, 839088, 0, 1, 16, 4, 0, 1, 4) +/* ANA_AC:SG_STATUS:SG_STATUS_REG_2 */ +#define ANA_AC_SG_STATUS_REG_2 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_STATUS], 0, 1, 16, \ + 4, 0, 1, 4) -/* ANA_AC:SG_STATUS:SG_STATUS_REG_3 */ -#define ANA_AC_SG_STATUS_REG_3 __REG(TARGET_ANA_AC,\ - 0, 1, 839088, 0, 1, 16, 8, 0, 1, 4) +/* ANA_AC:SG_STATUS:SG_STATUS_REG_3 */ +#define ANA_AC_SG_STATUS_REG_3 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_STATUS], 0, 1, 16, \ + 8, 0, 1, 4) #define ANA_AC_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB GENMASK(15, 0) #define ANA_AC_SG_STATUS_REG_3_CFG_CHG_TIME_SEC_MSB_SET(x)\ @@ -443,23 +496,27 @@ enum sparx5_target { #define ANA_AC_SG_STATUS_REG_3_GCL_OCTET_INDEX_GET(x)\ FIELD_GET(ANA_AC_SG_STATUS_REG_3_GCL_OCTET_INDEX, x) -/* ANA_AC:SG_STATUS:SG_STATUS_REG_4 */ -#define ANA_AC_SG_STATUS_REG_4 __REG(TARGET_ANA_AC,\ - 0, 1, 839088, 0, 1, 16, 12, 0, 1, 4) +/* ANA_AC:SG_STATUS:SG_STATUS_REG_4 */ +#define ANA_AC_SG_STATUS_REG_4 \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_SG_STATUS], 0, 1, 16, \ + 12, 0, 1, 4) -/* ANA_AC:STAT_GLOBAL_CFG_PORT:STAT_GLOBAL_EVENT_MASK */ -#define ANA_AC_PORT_SGE_CFG(r) __REG(TARGET_ANA_AC,\ - 0, 1, 851552, 0, 1, 20, 0, r, 4, 4) +/* ANA_AC:STAT_GLOBAL_CFG_PORT:STAT_GLOBAL_EVENT_MASK */ +#define ANA_AC_PORT_SGE_CFG(r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_STAT_GLOBAL_CFG_PORT],\ + 0, 1, 20, 0, r, 4, 4) -#define ANA_AC_PORT_SGE_CFG_MASK GENMASK(15, 0) +#define ANA_AC_PORT_SGE_CFG_MASK\ + GENMASK(regs->fsize[FW_ANA_AC_PORT_SGE_CFG_MASK] + 0 - 1, 0) #define ANA_AC_PORT_SGE_CFG_MASK_SET(x)\ - FIELD_PREP(ANA_AC_PORT_SGE_CFG_MASK, x) + spx5_field_prep(ANA_AC_PORT_SGE_CFG_MASK, x) #define ANA_AC_PORT_SGE_CFG_MASK_GET(x)\ - FIELD_GET(ANA_AC_PORT_SGE_CFG_MASK, x) + spx5_field_get(ANA_AC_PORT_SGE_CFG_MASK, x) -/* ANA_AC:STAT_GLOBAL_CFG_PORT:STAT_RESET */ -#define ANA_AC_STAT_RESET __REG(TARGET_ANA_AC,\ - 0, 1, 851552, 0, 1, 20, 16, 0, 1, 4) +/* ANA_AC:STAT_GLOBAL_CFG_PORT:STAT_RESET */ +#define ANA_AC_STAT_RESET \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_STAT_GLOBAL_CFG_PORT],\ + 0, 1, 20, 16, 0, 1, 4) #define ANA_AC_STAT_RESET_RESET BIT(0) #define ANA_AC_STAT_RESET_RESET_SET(x)\ @@ -467,9 +524,10 @@ enum sparx5_target { #define ANA_AC_STAT_RESET_RESET_GET(x)\ FIELD_GET(ANA_AC_STAT_RESET_RESET, x) -/* ANA_AC:STAT_CNT_CFG_PORT:STAT_CFG */ -#define ANA_AC_PORT_STAT_CFG(g, r) __REG(TARGET_ANA_AC,\ - 0, 1, 843776, g, 70, 64, 4, r, 4, 4) +/* ANA_AC:STAT_CNT_CFG_PORT:STAT_CFG */ +#define ANA_AC_PORT_STAT_CFG(g, r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_STAT_CNT_CFG_PORT], g,\ + regs->gcnt[GC_ANA_AC_STAT_CNT_CFG_PORT], 64, 4, r, 4, 4) #define ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK GENMASK(11, 4) #define ANA_AC_PORT_STAT_CFG_CFG_PRIO_MASK_SET(x)\ @@ -489,13 +547,15 @@ enum sparx5_target { #define ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE_GET(x)\ FIELD_GET(ANA_AC_PORT_STAT_CFG_CFG_CNT_BYTE, x) -/* ANA_AC:STAT_CNT_CFG_PORT:STAT_LSB_CNT */ -#define ANA_AC_PORT_STAT_LSB_CNT(g, r) __REG(TARGET_ANA_AC,\ - 0, 1, 843776, g, 70, 64, 20, r, 4, 4) +/* ANA_AC:STAT_CNT_CFG_PORT:STAT_LSB_CNT */ +#define ANA_AC_PORT_STAT_LSB_CNT(g, r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_STAT_CNT_CFG_PORT], g,\ + regs->gcnt[GC_ANA_AC_STAT_CNT_CFG_PORT], 64, 20, r, 4, 4) -/* ANA_AC:STAT_GLOBAL_CFG_ACL:GLOBAL_CNT_FRM_TYPE_CFG */ -#define ANA_AC_ACL_GLOBAL_CNT_FRM_TYPE_CFG(r) __REG(TARGET_ANA_AC,\ - 0, 1, 893792, 0, 1, 24, 0, r, 2, 4) +/* ANA_AC:STAT_GLOBAL_CFG_ACL:GLOBAL_CNT_FRM_TYPE_CFG */ +#define ANA_AC_ACL_GLOBAL_CNT_FRM_TYPE_CFG(r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_STAT_GLOBAL_CFG_ACL], \ + 0, 1, 24, 0, r, 2, 4) #define ANA_AC_ACL_GLOBAL_CNT_FRM_TYPE_CFG_GLOBAL_CFG_CNT_FRM_TYPE GENMASK(2, 0) #define ANA_AC_ACL_GLOBAL_CNT_FRM_TYPE_CFG_GLOBAL_CFG_CNT_FRM_TYPE_SET(x)\ @@ -503,9 +563,10 @@ enum sparx5_target { #define ANA_AC_ACL_GLOBAL_CNT_FRM_TYPE_CFG_GLOBAL_CFG_CNT_FRM_TYPE_GET(x)\ FIELD_GET(ANA_AC_ACL_GLOBAL_CNT_FRM_TYPE_CFG_GLOBAL_CFG_CNT_FRM_TYPE, x) -/* ANA_AC:STAT_GLOBAL_CFG_ACL:STAT_GLOBAL_CFG */ -#define ANA_AC_ACL_STAT_GLOBAL_CFG(r) __REG(TARGET_ANA_AC,\ - 0, 1, 893792, 0, 1, 24, 8, r, 2, 4) +/* ANA_AC:STAT_GLOBAL_CFG_ACL:STAT_GLOBAL_CFG */ +#define ANA_AC_ACL_STAT_GLOBAL_CFG(r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_STAT_GLOBAL_CFG_ACL], \ + 0, 1, 24, 8, r, 2, 4) #define ANA_AC_ACL_STAT_GLOBAL_CFG_GLOBAL_CFG_CNT_BYTE BIT(0) #define ANA_AC_ACL_STAT_GLOBAL_CFG_GLOBAL_CFG_CNT_BYTE_SET(x)\ @@ -513,9 +574,10 @@ enum sparx5_target { #define ANA_AC_ACL_STAT_GLOBAL_CFG_GLOBAL_CFG_CNT_BYTE_GET(x)\ FIELD_GET(ANA_AC_ACL_STAT_GLOBAL_CFG_GLOBAL_CFG_CNT_BYTE, x) -/* ANA_AC:STAT_GLOBAL_CFG_ACL:STAT_GLOBAL_EVENT_MASK */ -#define ANA_AC_ACL_STAT_GLOBAL_EVENT_MASK(r) __REG(TARGET_ANA_AC,\ - 0, 1, 893792, 0, 1, 24, 16, r, 2, 4) +/* ANA_AC:STAT_GLOBAL_CFG_ACL:STAT_GLOBAL_EVENT_MASK */ +#define ANA_AC_ACL_STAT_GLOBAL_EVENT_MASK(r) \ + __REG(TARGET_ANA_AC, 0, 1, regs->gaddr[GA_ANA_AC_STAT_GLOBAL_CFG_ACL], \ + 0, 1, 24, 16, r, 2, 4) #define ANA_AC_ACL_STAT_GLOBAL_EVENT_MASK_GLOBAL_EVENT_MASK GENMASK(3, 0) #define ANA_AC_ACL_STAT_GLOBAL_EVENT_MASK_GLOBAL_EVENT_MASK_SET(x)\ @@ -523,9 +585,10 @@ enum sparx5_target { #define ANA_AC_ACL_STAT_GLOBAL_EVENT_MASK_GLOBAL_EVENT_MASK_GET(x)\ FIELD_GET(ANA_AC_ACL_STAT_GLOBAL_EVENT_MASK_GLOBAL_EVENT_MASK, x) -/* ANA_ACL:COMMON:VCAP_S2_CFG */ -#define ANA_ACL_VCAP_S2_CFG(r) __REG(TARGET_ANA_ACL,\ - 0, 1, 32768, 0, 1, 592, 0, r, 70, 4) +/* ANA_ACL:COMMON:VCAP_S2_CFG */ +#define ANA_ACL_VCAP_S2_CFG(r) \ + __REG(TARGET_ANA_ACL, 0, 1, regs->gaddr[GA_ANA_ACL_COMMON], 0, 1, 592, \ + 0, r, regs->rcnt[RC_ANA_ACL_VCAP_S2_CFG], 4) #define ANA_ACL_VCAP_S2_CFG_SEC_ROUTE_HANDLING_ENA BIT(28) #define ANA_ACL_VCAP_S2_CFG_SEC_ROUTE_HANDLING_ENA_SET(x)\ @@ -611,9 +674,10 @@ enum sparx5_target { #define ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(x)\ FIELD_GET(ANA_ACL_VCAP_S2_CFG_SEC_ENA, x) -/* ANA_ACL:COMMON:SWAP_IP_CTRL */ -#define ANA_ACL_SWAP_IP_CTRL __REG(TARGET_ANA_ACL,\ - 0, 1, 32768, 0, 1, 592, 412, 0, 1, 4) +/* ANA_ACL:COMMON:SWAP_IP_CTRL */ +#define ANA_ACL_SWAP_IP_CTRL \ + __REG(TARGET_ANA_ACL, 0, 1, regs->gaddr[GA_ANA_ACL_COMMON], 0, 1, 592, \ + 412, 0, 1, 4) #define ANA_ACL_SWAP_IP_CTRL_DMAC_REPL_OFFSET_VAL GENMASK(23, 18) #define ANA_ACL_SWAP_IP_CTRL_DMAC_REPL_OFFSET_VAL_SET(x)\ @@ -645,9 +709,10 @@ enum sparx5_target { #define ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_ENA_GET(x)\ FIELD_GET(ANA_ACL_SWAP_IP_CTRL_IP_SWAP_IP4_TTL_ENA, x) -/* ANA_ACL:COMMON:VCAP_S2_RLEG_STAT */ -#define ANA_ACL_VCAP_S2_RLEG_STAT(r) __REG(TARGET_ANA_ACL,\ - 0, 1, 32768, 0, 1, 592, 424, r, 4, 4) +/* ANA_ACL:COMMON:VCAP_S2_RLEG_STAT */ +#define ANA_ACL_VCAP_S2_RLEG_STAT(r) \ + __REG(TARGET_ANA_ACL, 0, 1, regs->gaddr[GA_ANA_ACL_COMMON], 0, 1, 592, \ + 424, r, 4, 4) #define ANA_ACL_VCAP_S2_RLEG_STAT_IRLEG_STAT_MASK GENMASK(12, 6) #define ANA_ACL_VCAP_S2_RLEG_STAT_IRLEG_STAT_MASK_SET(x)\ @@ -661,9 +726,10 @@ enum sparx5_target { #define ANA_ACL_VCAP_S2_RLEG_STAT_ERLEG_STAT_MASK_GET(x)\ FIELD_GET(ANA_ACL_VCAP_S2_RLEG_STAT_ERLEG_STAT_MASK, x) -/* ANA_ACL:COMMON:VCAP_S2_FRAGMENT_CFG */ -#define ANA_ACL_VCAP_S2_FRAGMENT_CFG __REG(TARGET_ANA_ACL,\ - 0, 1, 32768, 0, 1, 592, 440, 0, 1, 4) +/* ANA_ACL:COMMON:VCAP_S2_FRAGMENT_CFG */ +#define ANA_ACL_VCAP_S2_FRAGMENT_CFG \ + __REG(TARGET_ANA_ACL, 0, 1, regs->gaddr[GA_ANA_ACL_COMMON], 0, 1, 592, \ + 440, 0, 1, 4) #define ANA_ACL_VCAP_S2_FRAGMENT_CFG_L4_MIN_LEN GENMASK(9, 5) #define ANA_ACL_VCAP_S2_FRAGMENT_CFG_L4_MIN_LEN_SET(x)\ @@ -683,9 +749,10 @@ enum sparx5_target { #define ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES_GET(x)\ FIELD_GET(ANA_ACL_VCAP_S2_FRAGMENT_CFG_FRAGMENT_OFFSET_THRES, x) -/* ANA_ACL:COMMON:OWN_UPSID */ -#define ANA_ACL_OWN_UPSID(r) __REG(TARGET_ANA_ACL,\ - 0, 1, 32768, 0, 1, 592, 580, r, 3, 4) +/* ANA_ACL:COMMON:OWN_UPSID */ +#define ANA_ACL_OWN_UPSID(r) \ + __REG(TARGET_ANA_ACL, 0, 1, regs->gaddr[GA_ANA_ACL_COMMON], 0, 1, 592, \ + 580, r, regs->rcnt[RC_ANA_ACL_OWN_UPSID], 4) #define ANA_ACL_OWN_UPSID_OWN_UPSID GENMASK(4, 0) #define ANA_ACL_OWN_UPSID_OWN_UPSID_SET(x)\ @@ -693,9 +760,10 @@ enum sparx5_target { #define ANA_ACL_OWN_UPSID_OWN_UPSID_GET(x)\ FIELD_GET(ANA_ACL_OWN_UPSID_OWN_UPSID, x) -/* ANA_ACL:KEY_SEL:VCAP_S2_KEY_SEL */ -#define ANA_ACL_VCAP_S2_KEY_SEL(g, r) __REG(TARGET_ANA_ACL,\ - 0, 1, 34200, g, 134, 16, 0, r, 4, 4) +/* ANA_ACL:KEY_SEL:VCAP_S2_KEY_SEL */ +#define ANA_ACL_VCAP_S2_KEY_SEL(g, r) \ + __REG(TARGET_ANA_ACL, 0, 1, regs->gaddr[GA_ANA_ACL_KEY_SEL], g, \ + regs->gcnt[GC_ANA_ACL_KEY_SEL], 16, 0, r, 4, 4) #define ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA BIT(13) #define ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(x)\ @@ -745,17 +813,20 @@ enum sparx5_target { #define ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(x)\ FIELD_GET(ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL, x) -/* ANA_ACL:CNT_A:CNT_A */ -#define ANA_ACL_CNT_A(g) __REG(TARGET_ANA_ACL,\ - 0, 1, 0, g, 4096, 4, 0, 0, 1, 4) +/* ANA_ACL:CNT_A:CNT_A */ +#define ANA_ACL_CNT_A(g) \ + __REG(TARGET_ANA_ACL, 0, 1, 0, g, regs->gcnt[GC_ANA_ACL_CNT_A], 4, 0, \ + 0, 1, 4) -/* ANA_ACL:CNT_B:CNT_B */ -#define ANA_ACL_CNT_B(g) __REG(TARGET_ANA_ACL,\ - 0, 1, 16384, g, 4096, 4, 0, 0, 1, 4) +/* ANA_ACL:CNT_B:CNT_B */ +#define ANA_ACL_CNT_B(g) \ + __REG(TARGET_ANA_ACL, 0, 1, regs->gaddr[GA_ANA_ACL_CNT_B], g, \ + regs->gcnt[GC_ANA_ACL_CNT_B], 4, 0, 0, 1, 4) -/* ANA_ACL:STICKY:SEC_LOOKUP_STICKY */ -#define ANA_ACL_SEC_LOOKUP_STICKY(r) __REG(TARGET_ANA_ACL,\ - 0, 1, 36408, 0, 1, 16, 0, r, 4, 4) +/* ANA_ACL:STICKY:SEC_LOOKUP_STICKY */ +#define ANA_ACL_SEC_LOOKUP_STICKY(r) \ + __REG(TARGET_ANA_ACL, 0, 1, regs->gaddr[GA_ANA_ACL_STICKY], 0, 1, 16, \ + 0, r, 4, 4) #define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY BIT(17) #define ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY_SET(x)\ @@ -865,9 +936,10 @@ enum sparx5_target { #define ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(x)\ FIELD_GET(ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY, x) -/* ANA_AC_POL:POL_ALL_CFG:POL_UPD_INT_CFG */ -#define ANA_AC_POL_POL_UPD_INT_CFG __REG(TARGET_ANA_AC_POL,\ - 0, 1, 75968, 0, 1, 1160, 1148, 0, 1, 4) +/* ANA_AC_POL:POL_ALL_CFG:POL_UPD_INT_CFG */ +#define ANA_AC_POL_POL_UPD_INT_CFG \ + __REG(TARGET_ANA_AC_POL, 0, 1, regs->gaddr[GA_ANA_AC_POL_POL_ALL_CFG], \ + 0, 1, 1160, 1148, 0, 1, 4) #define ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT GENMASK(9, 0) #define ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT_SET(x)\ @@ -875,9 +947,10 @@ enum sparx5_target { #define ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT_GET(x)\ FIELD_GET(ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT, x) -/* ANA_AC_POL:COMMON_BDLB:DLB_CTRL */ -#define ANA_AC_POL_BDLB_DLB_CTRL __REG(TARGET_ANA_AC_POL,\ - 0, 1, 79048, 0, 1, 8, 0, 0, 1, 4) +/* ANA_AC_POL:COMMON_BDLB:DLB_CTRL */ +#define ANA_AC_POL_BDLB_DLB_CTRL \ + __REG(TARGET_ANA_AC_POL, 0, 1, regs->gaddr[GA_ANA_AC_POL_COMMON_BDLB], \ + 0, 1, 8, 0, 0, 1, 4) #define ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS GENMASK(26, 19) #define ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS_SET(x)\ @@ -903,9 +976,10 @@ enum sparx5_target { #define ANA_AC_POL_BDLB_DLB_CTRL_DLB_ADD_ENA_GET(x)\ FIELD_GET(ANA_AC_POL_BDLB_DLB_CTRL_DLB_ADD_ENA, x) -/* ANA_AC_POL:COMMON_BUM_SLB:DLB_CTRL */ -#define ANA_AC_POL_SLB_DLB_CTRL __REG(TARGET_ANA_AC_POL,\ - 0, 1, 79056, 0, 1, 20, 0, 0, 1, 4) +/* ANA_AC_POL:COMMON_BUM_SLB:DLB_CTRL */ +#define ANA_AC_POL_SLB_DLB_CTRL \ + __REG(TARGET_ANA_AC_POL, 0, 1, \ + regs->gaddr[GA_ANA_AC_POL_COMMON_BUM_SLB], 0, 1, 20, 0, 0, 1, 4) #define ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS GENMASK(26, 19) #define ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS_SET(x)\ @@ -931,19 +1005,22 @@ enum sparx5_target { #define ANA_AC_POL_SLB_DLB_CTRL_DLB_ADD_ENA_GET(x)\ FIELD_GET(ANA_AC_POL_SLB_DLB_CTRL_DLB_ADD_ENA, x) -/* ANA_AC_SDLB:LBGRP_TBL:XLB_START */ -#define ANA_AC_SDLB_XLB_START(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 295468, g, 10, 24, 0, 0, 1, 4) +/* ANA_AC_SDLB:LBGRP_TBL:XLB_START */ +#define ANA_AC_SDLB_XLB_START(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, regs->gaddr[GA_ANA_AC_SDLB_LBGRP_TBL], \ + g, regs->gcnt[GC_ANA_AC_SDLB_LBGRP_TBL], 24, 0, 0, 1, 4) -#define ANA_AC_SDLB_XLB_START_LBSET_START GENMASK(12, 0) +#define ANA_AC_SDLB_XLB_START_LBSET_START\ + GENMASK(regs->fsize[FW_ANA_AC_SDLB_XLB_START_LBSET_START] + 0 - 1, 0) #define ANA_AC_SDLB_XLB_START_LBSET_START_SET(x)\ - FIELD_PREP(ANA_AC_SDLB_XLB_START_LBSET_START, x) + spx5_field_prep(ANA_AC_SDLB_XLB_START_LBSET_START, x) #define ANA_AC_SDLB_XLB_START_LBSET_START_GET(x)\ - FIELD_GET(ANA_AC_SDLB_XLB_START_LBSET_START, x) + spx5_field_get(ANA_AC_SDLB_XLB_START_LBSET_START, x) -/* ANA_AC_SDLB:LBGRP_TBL:PUP_INTERVAL */ -#define ANA_AC_SDLB_PUP_INTERVAL(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 295468, g, 10, 24, 4, 0, 1, 4) +/* ANA_AC_SDLB:LBGRP_TBL:PUP_INTERVAL */ +#define ANA_AC_SDLB_PUP_INTERVAL(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, regs->gaddr[GA_ANA_AC_SDLB_LBGRP_TBL], \ + g, regs->gcnt[GC_ANA_AC_SDLB_LBGRP_TBL], 24, 4, 0, 1, 4) #define ANA_AC_SDLB_PUP_INTERVAL_PUP_INTERVAL GENMASK(19, 0) #define ANA_AC_SDLB_PUP_INTERVAL_PUP_INTERVAL_SET(x)\ @@ -951,9 +1028,10 @@ enum sparx5_target { #define ANA_AC_SDLB_PUP_INTERVAL_PUP_INTERVAL_GET(x)\ FIELD_GET(ANA_AC_SDLB_PUP_INTERVAL_PUP_INTERVAL, x) -/* ANA_AC_SDLB:LBGRP_TBL:PUP_CTRL */ -#define ANA_AC_SDLB_PUP_CTRL(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 295468, g, 10, 24, 8, 0, 1, 4) +/* ANA_AC_SDLB:LBGRP_TBL:PUP_CTRL */ +#define ANA_AC_SDLB_PUP_CTRL(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, regs->gaddr[GA_ANA_AC_SDLB_LBGRP_TBL], \ + g, regs->gcnt[GC_ANA_AC_SDLB_LBGRP_TBL], 24, 8, 0, 1, 4) #define ANA_AC_SDLB_PUP_CTRL_PUP_LB_DT GENMASK(18, 0) #define ANA_AC_SDLB_PUP_CTRL_PUP_LB_DT_SET(x)\ @@ -967,19 +1045,22 @@ enum sparx5_target { #define ANA_AC_SDLB_PUP_CTRL_PUP_ENA_GET(x)\ FIELD_GET(ANA_AC_SDLB_PUP_CTRL_PUP_ENA, x) -/* ANA_AC_SDLB:LBGRP_TBL:LBGRP_MISC */ -#define ANA_AC_SDLB_LBGRP_MISC(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 295468, g, 10, 24, 12, 0, 1, 4) +/* ANA_AC_SDLB:LBGRP_TBL:LBGRP_MISC */ +#define ANA_AC_SDLB_LBGRP_MISC(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, regs->gaddr[GA_ANA_AC_SDLB_LBGRP_TBL], \ + g, regs->gcnt[GC_ANA_AC_SDLB_LBGRP_TBL], 24, 12, 0, 1, 4) -#define ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT GENMASK(12, 8) +#define ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT\ + GENMASK(regs->fsize[FW_ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT] + 8 - 1, 8) #define ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT_SET(x)\ - FIELD_PREP(ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT, x) + spx5_field_prep(ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT, x) #define ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT_GET(x)\ - FIELD_GET(ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT, x) + spx5_field_get(ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT, x) -/* ANA_AC_SDLB:LBGRP_TBL:FRM_RATE_TOKENS */ -#define ANA_AC_SDLB_FRM_RATE_TOKENS(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 295468, g, 10, 24, 16, 0, 1, 4) +/* ANA_AC_SDLB:LBGRP_TBL:FRM_RATE_TOKENS */ +#define ANA_AC_SDLB_FRM_RATE_TOKENS(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, regs->gaddr[GA_ANA_AC_SDLB_LBGRP_TBL], \ + g, regs->gcnt[GC_ANA_AC_SDLB_LBGRP_TBL], 24, 16, 0, 1, 4) #define ANA_AC_SDLB_FRM_RATE_TOKENS_FRM_RATE_TOKENS GENMASK(12, 0) #define ANA_AC_SDLB_FRM_RATE_TOKENS_FRM_RATE_TOKENS_SET(x)\ @@ -987,9 +1068,10 @@ enum sparx5_target { #define ANA_AC_SDLB_FRM_RATE_TOKENS_FRM_RATE_TOKENS_GET(x)\ FIELD_GET(ANA_AC_SDLB_FRM_RATE_TOKENS_FRM_RATE_TOKENS, x) -/* ANA_AC_SDLB:LBGRP_TBL:LBGRP_STATE_TBL */ -#define ANA_AC_SDLB_LBGRP_STATE_TBL(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 295468, g, 10, 24, 20, 0, 1, 4) +/* ANA_AC_SDLB:LBGRP_TBL:LBGRP_STATE_TBL */ +#define ANA_AC_SDLB_LBGRP_STATE_TBL(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, regs->gaddr[GA_ANA_AC_SDLB_LBGRP_TBL], \ + g, regs->gcnt[GC_ANA_AC_SDLB_LBGRP_TBL], 24, 20, 0, 1, 4) #define ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_ONGOING BIT(0) #define ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_ONGOING_SET(x)\ @@ -1003,15 +1085,17 @@ enum sparx5_target { #define ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_WAIT_ACK_GET(x)\ FIELD_GET(ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_WAIT_ACK, x) -#define ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT GENMASK(28, 16) +#define ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT\ + GENMASK(regs->fsize[FW_ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT] + 16 - 1, 16) #define ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT_SET(x)\ - FIELD_PREP(ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT, x) + spx5_field_prep(ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT, x) #define ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT_GET(x)\ - FIELD_GET(ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT, x) + spx5_field_get(ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT, x) -/* ANA_AC_SDLB:LBSET_TBL:PUP_TOKENS */ -#define ANA_AC_SDLB_PUP_TOKENS(g, r) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 0, g, 4616, 64, 0, r, 2, 4) +/* ANA_AC_SDLB:LBSET_TBL:PUP_TOKENS */ +#define ANA_AC_SDLB_PUP_TOKENS(g, r) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, 0, g, \ + regs->gcnt[GC_ANA_AC_SDLB_LBSET_TBL], 64, 0, r, 2, 4) #define ANA_AC_SDLB_PUP_TOKENS_PUP_TOKENS GENMASK(12, 0) #define ANA_AC_SDLB_PUP_TOKENS_PUP_TOKENS_SET(x)\ @@ -1019,9 +1103,10 @@ enum sparx5_target { #define ANA_AC_SDLB_PUP_TOKENS_PUP_TOKENS_GET(x)\ FIELD_GET(ANA_AC_SDLB_PUP_TOKENS_PUP_TOKENS, x) -/* ANA_AC_SDLB:LBSET_TBL:THRES */ -#define ANA_AC_SDLB_THRES(g, r) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 0, g, 4616, 64, 8, r, 2, 4) +/* ANA_AC_SDLB:LBSET_TBL:THRES */ +#define ANA_AC_SDLB_THRES(g, r) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, 0, g, \ + regs->gcnt[GC_ANA_AC_SDLB_LBSET_TBL], 64, 8, r, 2, 4) #define ANA_AC_SDLB_THRES_THRES GENMASK(9, 0) #define ANA_AC_SDLB_THRES_THRES_SET(x)\ @@ -1035,25 +1120,29 @@ enum sparx5_target { #define ANA_AC_SDLB_THRES_THRES_HYS_GET(x)\ FIELD_GET(ANA_AC_SDLB_THRES_THRES_HYS, x) -/* ANA_AC_SDLB:LBSET_TBL:XLB_NEXT */ -#define ANA_AC_SDLB_XLB_NEXT(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 0, g, 4616, 64, 16, 0, 1, 4) +/* ANA_AC_SDLB:LBSET_TBL:XLB_NEXT */ +#define ANA_AC_SDLB_XLB_NEXT(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, 0, g, \ + regs->gcnt[GC_ANA_AC_SDLB_LBSET_TBL], 64, 16, 0, 1, 4) -#define ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT GENMASK(12, 0) +#define ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT\ + GENMASK(regs->fsize[FW_ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT] + 0 - 1, 0) #define ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT_SET(x)\ - FIELD_PREP(ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT, x) + spx5_field_prep(ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT, x) #define ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT_GET(x)\ - FIELD_GET(ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT, x) + spx5_field_get(ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT, x) -#define ANA_AC_SDLB_XLB_NEXT_LBGRP GENMASK(27, 24) +#define ANA_AC_SDLB_XLB_NEXT_LBGRP\ + GENMASK(regs->fsize[FW_ANA_AC_SDLB_XLB_NEXT_LBGRP] + 24 - 1, 24) #define ANA_AC_SDLB_XLB_NEXT_LBGRP_SET(x)\ - FIELD_PREP(ANA_AC_SDLB_XLB_NEXT_LBGRP, x) + spx5_field_prep(ANA_AC_SDLB_XLB_NEXT_LBGRP, x) #define ANA_AC_SDLB_XLB_NEXT_LBGRP_GET(x)\ - FIELD_GET(ANA_AC_SDLB_XLB_NEXT_LBGRP, x) + spx5_field_get(ANA_AC_SDLB_XLB_NEXT_LBGRP, x) -/* ANA_AC_SDLB:LBSET_TBL:INH_CTRL */ -#define ANA_AC_SDLB_INH_CTRL(g, r) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 0, g, 4616, 64, 20, r, 2, 4) +/* ANA_AC_SDLB:LBSET_TBL:INH_CTRL */ +#define ANA_AC_SDLB_INH_CTRL(g, r) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, 0, g, \ + regs->gcnt[GC_ANA_AC_SDLB_LBSET_TBL], 64, 20, r, 2, 4) #define ANA_AC_SDLB_INH_CTRL_PUP_TOKENS_MAX GENMASK(12, 0) #define ANA_AC_SDLB_INH_CTRL_PUP_TOKENS_MAX_SET(x)\ @@ -1073,19 +1162,22 @@ enum sparx5_target { #define ANA_AC_SDLB_INH_CTRL_INH_LB_GET(x)\ FIELD_GET(ANA_AC_SDLB_INH_CTRL_INH_LB, x) -/* ANA_AC_SDLB:LBSET_TBL:INH_LBSET_ADDR */ -#define ANA_AC_SDLB_INH_LBSET_ADDR(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 0, g, 4616, 64, 28, 0, 1, 4) +/* ANA_AC_SDLB:LBSET_TBL:INH_LBSET_ADDR */ +#define ANA_AC_SDLB_INH_LBSET_ADDR(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, 0, g, \ + regs->gcnt[GC_ANA_AC_SDLB_LBSET_TBL], 64, 28, 0, 1, 4) -#define ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR GENMASK(12, 0) +#define ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR\ + GENMASK(regs->fsize[FW_ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR] + 0 - 1, 0) #define ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR_SET(x)\ - FIELD_PREP(ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR, x) + spx5_field_prep(ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR, x) #define ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR_GET(x)\ - FIELD_GET(ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR, x) + spx5_field_get(ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR, x) -/* ANA_AC_SDLB:LBSET_TBL:DLB_MISC */ -#define ANA_AC_SDLB_DLB_MISC(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 0, g, 4616, 64, 32, 0, 1, 4) +/* ANA_AC_SDLB:LBSET_TBL:DLB_MISC */ +#define ANA_AC_SDLB_DLB_MISC(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, 0, g, \ + regs->gcnt[GC_ANA_AC_SDLB_LBSET_TBL], 64, 32, 0, 1, 4) #define ANA_AC_SDLB_DLB_MISC_DLB_FRM_RATE_ENA BIT(0) #define ANA_AC_SDLB_DLB_MISC_DLB_FRM_RATE_ENA_SET(x)\ @@ -1105,9 +1197,10 @@ enum sparx5_target { #define ANA_AC_SDLB_DLB_MISC_DLB_FRM_ADJ_GET(x)\ FIELD_GET(ANA_AC_SDLB_DLB_MISC_DLB_FRM_ADJ, x) -/* ANA_AC_SDLB:LBSET_TBL:DLB_CFG */ -#define ANA_AC_SDLB_DLB_CFG(g) __REG(TARGET_ANA_AC_SDLB,\ - 0, 1, 0, g, 4616, 64, 36, 0, 1, 4) +/* ANA_AC_SDLB:LBSET_TBL:DLB_CFG */ +#define ANA_AC_SDLB_DLB_CFG(g) \ + __REG(TARGET_ANA_AC_SDLB, 0, 1, 0, g, \ + regs->gcnt[GC_ANA_AC_SDLB_LBSET_TBL], 64, 36, 0, 1, 4) #define ANA_AC_SDLB_DLB_CFG_DROP_ON_YELLOW_ENA BIT(11) #define ANA_AC_SDLB_DLB_CFG_DROP_ON_YELLOW_ENA_SET(x)\ @@ -1157,9 +1250,10 @@ enum sparx5_target { #define ANA_AC_SDLB_DLB_CFG_TRAFFIC_TYPE_MASK_GET(x)\ FIELD_GET(ANA_AC_SDLB_DLB_CFG_TRAFFIC_TYPE_MASK, x) -/* ANA_CL:PORT:FILTER_CTRL */ -#define ANA_CL_FILTER_CTRL(g) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 4, 0, 1, 4) +/* ANA_CL:PORT:FILTER_CTRL */ +#define ANA_CL_FILTER_CTRL(g) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 4, 0, 1, 4) #define ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS BIT(2) #define ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS_SET(x)\ @@ -1179,9 +1273,10 @@ enum sparx5_target { #define ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA_GET(x)\ FIELD_GET(ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA, x) -/* ANA_CL:PORT:VLAN_FILTER_CTRL */ -#define ANA_CL_VLAN_FILTER_CTRL(g, r) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 8, r, 3, 4) +/* ANA_CL:PORT:VLAN_FILTER_CTRL */ +#define ANA_CL_VLAN_FILTER_CTRL(g, r) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 8, r, 3, 4) #define ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA BIT(10) #define ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(x)\ @@ -1249,9 +1344,10 @@ enum sparx5_target { #define ANA_CL_VLAN_FILTER_CTRL_CUST3_STAG_DIS_GET(x)\ FIELD_GET(ANA_CL_VLAN_FILTER_CTRL_CUST3_STAG_DIS, x) -/* ANA_CL:PORT:ETAG_FILTER_CTRL */ -#define ANA_CL_ETAG_FILTER_CTRL(g) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 20, 0, 1, 4) +/* ANA_CL:PORT:ETAG_FILTER_CTRL */ +#define ANA_CL_ETAG_FILTER_CTRL(g) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 20, 0, 1, 4) #define ANA_CL_ETAG_FILTER_CTRL_ETAG_REQUIRED_ENA BIT(1) #define ANA_CL_ETAG_FILTER_CTRL_ETAG_REQUIRED_ENA_SET(x)\ @@ -1265,9 +1361,10 @@ enum sparx5_target { #define ANA_CL_ETAG_FILTER_CTRL_ETAG_DIS_GET(x)\ FIELD_GET(ANA_CL_ETAG_FILTER_CTRL_ETAG_DIS, x) -/* ANA_CL:PORT:VLAN_CTRL */ -#define ANA_CL_VLAN_CTRL(g) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 32, 0, 1, 4) +/* ANA_CL:PORT:VLAN_CTRL */ +#define ANA_CL_VLAN_CTRL(g) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 32, 0, 1, 4) #define ANA_CL_VLAN_CTRL_PORT_VOE_TPID_AWARE_DIS GENMASK(30, 26) #define ANA_CL_VLAN_CTRL_PORT_VOE_TPID_AWARE_DIS_SET(x)\ @@ -1335,9 +1432,10 @@ enum sparx5_target { #define ANA_CL_VLAN_CTRL_PORT_VID_GET(x)\ FIELD_GET(ANA_CL_VLAN_CTRL_PORT_VID, x) -/* ANA_CL:PORT:VLAN_CTRL_2 */ -#define ANA_CL_VLAN_CTRL_2(g) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 36, 0, 1, 4) +/* ANA_CL:PORT:VLAN_CTRL_2 */ +#define ANA_CL_VLAN_CTRL_2(g) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 36, 0, 1, 4) #define ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT GENMASK(1, 0) #define ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT_SET(x)\ @@ -1345,9 +1443,10 @@ enum sparx5_target { #define ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT_GET(x)\ FIELD_GET(ANA_CL_VLAN_CTRL_2_VLAN_PUSH_CNT, x) -/* ANA_CL:PORT:PCP_DEI_MAP_CFG */ -#define ANA_CL_PCP_DEI_MAP_CFG(g, r) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 108, r, 16, 4) +/* ANA_CL:PORT:PCP_DEI_MAP_CFG */ +#define ANA_CL_PCP_DEI_MAP_CFG(g, r) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 108, r, 16, 4) #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL GENMASK(4, 3) #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_DP_VAL_SET(x)\ @@ -1361,9 +1460,10 @@ enum sparx5_target { #define ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL_GET(x)\ FIELD_GET(ANA_CL_PCP_DEI_MAP_CFG_PCP_DEI_QOS_VAL, x) -/* ANA_CL:PORT:QOS_CFG */ -#define ANA_CL_QOS_CFG(g) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 172, 0, 1, 4) +/* ANA_CL:PORT:QOS_CFG */ +#define ANA_CL_QOS_CFG(g) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 172, 0, 1, 4) #define ANA_CL_QOS_CFG_DEFAULT_COSID_ENA BIT(17) #define ANA_CL_QOS_CFG_DEFAULT_COSID_ENA_SET(x)\ @@ -1437,13 +1537,15 @@ enum sparx5_target { #define ANA_CL_QOS_CFG_DEFAULT_QOS_VAL_GET(x)\ FIELD_GET(ANA_CL_QOS_CFG_DEFAULT_QOS_VAL, x) -/* ANA_CL:PORT:CAPTURE_BPDU_CFG */ -#define ANA_CL_CAPTURE_BPDU_CFG(g) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 196, 0, 1, 4) +/* ANA_CL:PORT:CAPTURE_BPDU_CFG */ +#define ANA_CL_CAPTURE_BPDU_CFG(g) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 196, 0, 1, 4) -/* ANA_CL:PORT:ADV_CL_CFG_2 */ -#define ANA_CL_ADV_CL_CFG_2(g, r) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 200, r, 6, 4) +/* ANA_CL:PORT:ADV_CL_CFG_2 */ +#define ANA_CL_ADV_CL_CFG_2(g, r) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 200, r, 6, 4) #define ANA_CL_ADV_CL_CFG_2_USE_CL_TCI0_ENA BIT(1) #define ANA_CL_ADV_CL_CFG_2_USE_CL_TCI0_ENA_SET(x)\ @@ -1457,9 +1559,10 @@ enum sparx5_target { #define ANA_CL_ADV_CL_CFG_2_USE_CL_DSCP_ENA_GET(x)\ FIELD_GET(ANA_CL_ADV_CL_CFG_2_USE_CL_DSCP_ENA, x) -/* ANA_CL:PORT:ADV_CL_CFG */ -#define ANA_CL_ADV_CL_CFG(g, r) __REG(TARGET_ANA_CL,\ - 0, 1, 131072, g, 70, 512, 224, r, 6, 4) +/* ANA_CL:PORT:ADV_CL_CFG */ +#define ANA_CL_ADV_CL_CFG(g, r) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_PORT], g, \ + regs->gcnt[GC_ANA_CL_PORT], 512, 224, r, 6, 4) #define ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL GENMASK(30, 26) #define ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL_SET(x)\ @@ -1503,9 +1606,10 @@ enum sparx5_target { #define ANA_CL_ADV_CL_CFG_LOOKUP_ENA_GET(x)\ FIELD_GET(ANA_CL_ADV_CL_CFG_LOOKUP_ENA, x) -/* ANA_CL:COMMON:OWN_UPSID */ -#define ANA_CL_OWN_UPSID(r) __REG(TARGET_ANA_CL,\ - 0, 1, 166912, 0, 1, 756, 0, r, 3, 4) +/* ANA_CL:COMMON:OWN_UPSID */ +#define ANA_CL_OWN_UPSID(r) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_COMMON], 0, 1, 756, 0,\ + r, regs->rcnt[RC_ANA_CL_OWN_UPSID], 4) #define ANA_CL_OWN_UPSID_OWN_UPSID GENMASK(4, 0) #define ANA_CL_OWN_UPSID_OWN_UPSID_SET(x)\ @@ -1513,9 +1617,10 @@ enum sparx5_target { #define ANA_CL_OWN_UPSID_OWN_UPSID_GET(x)\ FIELD_GET(ANA_CL_OWN_UPSID_OWN_UPSID, x) -/* ANA_CL:COMMON:DSCP_CFG */ -#define ANA_CL_DSCP_CFG(r) __REG(TARGET_ANA_CL,\ - 0, 1, 166912, 0, 1, 756, 256, r, 64, 4) +/* ANA_CL:COMMON:DSCP_CFG */ +#define ANA_CL_DSCP_CFG(r) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_COMMON], 0, 1, 756, \ + 256, r, 64, 4) #define ANA_CL_DSCP_CFG_DSCP_TRANSLATE_VAL GENMASK(12, 7) #define ANA_CL_DSCP_CFG_DSCP_TRANSLATE_VAL_SET(x)\ @@ -1547,9 +1652,10 @@ enum sparx5_target { #define ANA_CL_DSCP_CFG_DSCP_TRUST_ENA_GET(x)\ FIELD_GET(ANA_CL_DSCP_CFG_DSCP_TRUST_ENA, x) -/* ANA_CL:COMMON:QOS_MAP_CFG */ -#define ANA_CL_QOS_MAP_CFG(r) __REG(TARGET_ANA_CL,\ - 0, 1, 166912, 0, 1, 756, 512, r, 32, 4) +/* ANA_CL:COMMON:QOS_MAP_CFG */ +#define ANA_CL_QOS_MAP_CFG(r) \ + __REG(TARGET_ANA_CL, 0, 1, regs->gaddr[GA_ANA_CL_COMMON], 0, 1, 756, \ + 512, r, 32, 4) #define ANA_CL_QOS_MAP_CFG_DSCP_REWR_VAL GENMASK(9, 4) #define ANA_CL_QOS_MAP_CFG_DSCP_REWR_VAL_SET(x)\ @@ -1557,9 +1663,10 @@ enum sparx5_target { #define ANA_CL_QOS_MAP_CFG_DSCP_REWR_VAL_GET(x)\ FIELD_GET(ANA_CL_QOS_MAP_CFG_DSCP_REWR_VAL, x) -/* ANA_L2:COMMON:FWD_CFG */ -#define ANA_L2_FWD_CFG __REG(TARGET_ANA_L2,\ - 0, 1, 566024, 0, 1, 700, 0, 0, 1, 4) +/* ANA_L2:COMMON:FWD_CFG */ +#define ANA_L2_FWD_CFG \ + __REG(TARGET_ANA_L2, 0, 1, regs->gaddr[GA_ANA_L2_COMMON], 0, 1, \ + regs->gsize[GW_ANA_L2_COMMON], 0, 0, 1, 4) #define ANA_L2_FWD_CFG_MAC_TBL_SPLIT_SEL GENMASK(21, 20) #define ANA_L2_FWD_CFG_MAC_TBL_SPLIT_SEL_SET(x)\ @@ -1633,17 +1740,22 @@ enum sparx5_target { #define ANA_L2_FWD_CFG_FWD_ENA_GET(x)\ FIELD_GET(ANA_L2_FWD_CFG_FWD_ENA, x) -/* ANA_L2:COMMON:AUTO_LRN_CFG */ -#define ANA_L2_AUTO_LRN_CFG __REG(TARGET_ANA_L2,\ - 0, 1, 566024, 0, 1, 700, 24, 0, 1, 4) +/* ANA_L2:COMMON:AUTO_LRN_CFG */ +#define ANA_L2_AUTO_LRN_CFG \ + __REG(TARGET_ANA_L2, 0, 1, regs->gaddr[GA_ANA_L2_COMMON], 0, 1, \ + regs->gsize[GW_ANA_L2_COMMON], 24, 0, 1, 4) -/* ANA_L2:COMMON:AUTO_LRN_CFG1 */ -#define ANA_L2_AUTO_LRN_CFG1 __REG(TARGET_ANA_L2,\ - 0, 1, 566024, 0, 1, 700, 28, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_L2:COMMON:AUTO_LRN_CFG1 */ +#define ANA_L2_AUTO_LRN_CFG1 \ + __REG(TARGET_ANA_L2, 0, 1, regs->gaddr[GA_ANA_L2_COMMON], 0, 1, \ + regs->gsize[GW_ANA_L2_COMMON], 28, 0, 1, 4) -/* ANA_L2:COMMON:AUTO_LRN_CFG2 */ -#define ANA_L2_AUTO_LRN_CFG2 __REG(TARGET_ANA_L2,\ - 0, 1, 566024, 0, 1, 700, 32, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_L2:COMMON:AUTO_LRN_CFG2 */ +#define ANA_L2_AUTO_LRN_CFG2 \ + __REG(TARGET_ANA_L2, 0, 1, regs->gaddr[GA_ANA_L2_COMMON], 0, 1, \ + regs->gsize[GW_ANA_L2_COMMON], 32, 0, 1, 4) #define ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2 BIT(0) #define ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2_SET(x)\ @@ -1651,9 +1763,11 @@ enum sparx5_target { #define ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2_GET(x)\ FIELD_GET(ANA_L2_AUTO_LRN_CFG2_AUTO_LRN_ENA2, x) -/* ANA_L2:COMMON:OWN_UPSID */ -#define ANA_L2_OWN_UPSID(r) __REG(TARGET_ANA_L2,\ - 0, 1, 566024, 0, 1, 700, 672, r, 3, 4) +/* ANA_L2:COMMON:OWN_UPSID */ +#define ANA_L2_OWN_UPSID(r) \ + __REG(TARGET_ANA_L2, 0, 1, regs->gaddr[GA_ANA_L2_COMMON], 0, 1, \ + regs->gsize[GW_ANA_L2_COMMON], 672, r, \ + regs->rcnt[RC_ANA_L2_OWN_UPSID], 4) #define ANA_L2_OWN_UPSID_OWN_UPSID GENMASK(4, 0) #define ANA_L2_OWN_UPSID_OWN_UPSID_SET(x)\ @@ -1661,29 +1775,34 @@ enum sparx5_target { #define ANA_L2_OWN_UPSID_OWN_UPSID_GET(x)\ FIELD_GET(ANA_L2_OWN_UPSID_OWN_UPSID, x) -/* ANA_L2:ISDX:DLB_CFG */ -#define ANA_L2_DLB_CFG(g) __REG(TARGET_ANA_L2,\ - 0, 1, 0, g, 4096, 128, 56, 0, 1, 4) +/* ANA_L2:ISDX:DLB_CFG */ +#define ANA_L2_DLB_CFG(g) \ + __REG(TARGET_ANA_L2, 0, 1, 0, g, regs->gcnt[GC_ANA_L2_ISDX], 128, 56, \ + 0, 1, 4) -#define ANA_L2_DLB_CFG_DLB_IDX GENMASK(12, 0) +#define ANA_L2_DLB_CFG_DLB_IDX\ + GENMASK(regs->fsize[FW_ANA_L2_DLB_CFG_DLB_IDX] + 0 - 1, 0) #define ANA_L2_DLB_CFG_DLB_IDX_SET(x)\ - FIELD_PREP(ANA_L2_DLB_CFG_DLB_IDX, x) + spx5_field_prep(ANA_L2_DLB_CFG_DLB_IDX, x) #define ANA_L2_DLB_CFG_DLB_IDX_GET(x)\ - FIELD_GET(ANA_L2_DLB_CFG_DLB_IDX, x) + spx5_field_get(ANA_L2_DLB_CFG_DLB_IDX, x) -/* ANA_L2:ISDX:TSN_CFG */ -#define ANA_L2_TSN_CFG(g) __REG(TARGET_ANA_L2,\ - 0, 1, 0, g, 4096, 128, 100, 0, 1, 4) +/* ANA_L2:ISDX:TSN_CFG */ +#define ANA_L2_TSN_CFG(g) \ + __REG(TARGET_ANA_L2, 0, 1, 0, g, regs->gcnt[GC_ANA_L2_ISDX], 128, 100, \ + 0, 1, 4) -#define ANA_L2_TSN_CFG_TSN_SFID GENMASK(9, 0) +#define ANA_L2_TSN_CFG_TSN_SFID\ + GENMASK(regs->fsize[FW_ANA_L2_TSN_CFG_TSN_SFID] + 0 - 1, 0) #define ANA_L2_TSN_CFG_TSN_SFID_SET(x)\ - FIELD_PREP(ANA_L2_TSN_CFG_TSN_SFID, x) + spx5_field_prep(ANA_L2_TSN_CFG_TSN_SFID, x) #define ANA_L2_TSN_CFG_TSN_SFID_GET(x)\ - FIELD_GET(ANA_L2_TSN_CFG_TSN_SFID, x) + spx5_field_get(ANA_L2_TSN_CFG_TSN_SFID, x) -/* ANA_L3:COMMON:VLAN_CTRL */ -#define ANA_L3_VLAN_CTRL __REG(TARGET_ANA_L3,\ - 0, 1, 493632, 0, 1, 184, 4, 0, 1, 4) +/* ANA_L3:COMMON:VLAN_CTRL */ +#define ANA_L3_VLAN_CTRL \ + __REG(TARGET_ANA_L3, 0, 1, regs->gaddr[GA_ANA_L3_COMMON], 0, 1, 184, 4,\ + 0, 1, 4) #define ANA_L3_VLAN_CTRL_VLAN_ENA BIT(0) #define ANA_L3_VLAN_CTRL_VLAN_ENA_SET(x)\ @@ -1691,9 +1810,10 @@ enum sparx5_target { #define ANA_L3_VLAN_CTRL_VLAN_ENA_GET(x)\ FIELD_GET(ANA_L3_VLAN_CTRL_VLAN_ENA, x) -/* ANA_L3:VLAN:VLAN_CFG */ -#define ANA_L3_VLAN_CFG(g) __REG(TARGET_ANA_L3,\ - 0, 1, 0, g, 5120, 64, 8, 0, 1, 4) +/* ANA_L3:VLAN:VLAN_CFG */ +#define ANA_L3_VLAN_CFG(g) \ + __REG(TARGET_ANA_L3, 0, 1, 0, g, regs->gcnt[GC_ANA_L3_VLAN], 64, 8, 0, \ + 1, 4) #define ANA_L3_VLAN_CFG_VLAN_MSTP_PTR GENMASK(30, 24) #define ANA_L3_VLAN_CFG_VLAN_MSTP_PTR_SET(x)\ @@ -1749,17 +1869,22 @@ enum sparx5_target { #define ANA_L3_VLAN_CFG_VLAN_MIRROR_ENA_GET(x)\ FIELD_GET(ANA_L3_VLAN_CFG_VLAN_MIRROR_ENA, x) -/* ANA_L3:VLAN:VLAN_MASK_CFG */ -#define ANA_L3_VLAN_MASK_CFG(g) __REG(TARGET_ANA_L3,\ - 0, 1, 0, g, 5120, 64, 16, 0, 1, 4) +/* ANA_L3:VLAN:VLAN_MASK_CFG */ +#define ANA_L3_VLAN_MASK_CFG(g) \ + __REG(TARGET_ANA_L3, 0, 1, 0, g, regs->gcnt[GC_ANA_L3_VLAN], 64, 16, 0,\ + 1, 4) -/* ANA_L3:VLAN:VLAN_MASK_CFG1 */ -#define ANA_L3_VLAN_MASK_CFG1(g) __REG(TARGET_ANA_L3,\ - 0, 1, 0, g, 5120, 64, 20, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_L3:VLAN:VLAN_MASK_CFG1 */ +#define ANA_L3_VLAN_MASK_CFG1(g) \ + __REG(TARGET_ANA_L3, 0, 1, 0, g, regs->gcnt[GC_ANA_L3_VLAN], 64, 20, 0,\ + 1, 4) -/* ANA_L3:VLAN:VLAN_MASK_CFG2 */ -#define ANA_L3_VLAN_MASK_CFG2(g) __REG(TARGET_ANA_L3,\ - 0, 1, 0, g, 5120, 64, 24, 0, 1, 4) +/* SPARX5 ONLY */ +/* ANA_L3:VLAN:VLAN_MASK_CFG2 */ +#define ANA_L3_VLAN_MASK_CFG2(g) \ + __REG(TARGET_ANA_L3, 0, 1, 0, g, regs->gcnt[GC_ANA_L3_VLAN], 64, 24, 0,\ + 1, 4) #define ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2 BIT(0) #define ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2_SET(x)\ @@ -1767,365 +1892,455 @@ enum sparx5_target { #define ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2_GET(x)\ FIELD_GET(ANA_L3_VLAN_MASK_CFG2_VLAN_PORT_MASK2, x) -/* ASM:DEV_STATISTICS:RX_IN_BYTES_CNT */ -#define ASM_RX_IN_BYTES_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 0, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_SYMBOL_ERR_CNT */ -#define ASM_RX_SYMBOL_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 4, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_PAUSE_CNT */ -#define ASM_RX_PAUSE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 8, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_UNSUP_OPCODE_CNT */ -#define ASM_RX_UNSUP_OPCODE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 12, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_OK_BYTES_CNT */ -#define ASM_RX_OK_BYTES_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 16, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_BAD_BYTES_CNT */ -#define ASM_RX_BAD_BYTES_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 20, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_UC_CNT */ -#define ASM_RX_UC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 24, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_MC_CNT */ -#define ASM_RX_MC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 28, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_BC_CNT */ -#define ASM_RX_BC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 32, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_CRC_ERR_CNT */ -#define ASM_RX_CRC_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 36, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_UNDERSIZE_CNT */ -#define ASM_RX_UNDERSIZE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 40, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_FRAGMENTS_CNT */ -#define ASM_RX_FRAGMENTS_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 44, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_IN_RANGE_LEN_ERR_CNT */ -#define ASM_RX_IN_RANGE_LEN_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 48, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_OUT_OF_RANGE_LEN_ERR_CNT */ -#define ASM_RX_OUT_OF_RANGE_LEN_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 52, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_OVERSIZE_CNT */ -#define ASM_RX_OVERSIZE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 56, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_JABBERS_CNT */ -#define ASM_RX_JABBERS_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 60, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_SIZE64_CNT */ -#define ASM_RX_SIZE64_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 64, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_SIZE65TO127_CNT */ -#define ASM_RX_SIZE65TO127_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 68, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_SIZE128TO255_CNT */ -#define ASM_RX_SIZE128TO255_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 72, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_SIZE256TO511_CNT */ -#define ASM_RX_SIZE256TO511_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 76, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_SIZE512TO1023_CNT */ -#define ASM_RX_SIZE512TO1023_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 80, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_SIZE1024TO1518_CNT */ -#define ASM_RX_SIZE1024TO1518_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 84, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_SIZE1519TOMAX_CNT */ -#define ASM_RX_SIZE1519TOMAX_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 88, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_IPG_SHRINK_CNT */ -#define ASM_RX_IPG_SHRINK_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 92, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_OUT_BYTES_CNT */ -#define ASM_TX_OUT_BYTES_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 96, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_PAUSE_CNT */ -#define ASM_TX_PAUSE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 100, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_OK_BYTES_CNT */ -#define ASM_TX_OK_BYTES_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 104, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_UC_CNT */ -#define ASM_TX_UC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 108, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_MC_CNT */ -#define ASM_TX_MC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 112, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_BC_CNT */ -#define ASM_TX_BC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 116, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_SIZE64_CNT */ -#define ASM_TX_SIZE64_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 120, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_SIZE65TO127_CNT */ -#define ASM_TX_SIZE65TO127_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 124, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_SIZE128TO255_CNT */ -#define ASM_TX_SIZE128TO255_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 128, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_SIZE256TO511_CNT */ -#define ASM_TX_SIZE256TO511_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 132, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_SIZE512TO1023_CNT */ -#define ASM_TX_SIZE512TO1023_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 136, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_SIZE1024TO1518_CNT */ -#define ASM_TX_SIZE1024TO1518_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 140, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_SIZE1519TOMAX_CNT */ -#define ASM_TX_SIZE1519TOMAX_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 144, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_ALIGNMENT_LOST_CNT */ -#define ASM_RX_ALIGNMENT_LOST_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 148, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_TAGGED_FRMS_CNT */ -#define ASM_RX_TAGGED_FRMS_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 152, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_UNTAGGED_FRMS_CNT */ -#define ASM_RX_UNTAGGED_FRMS_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 156, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_TAGGED_FRMS_CNT */ -#define ASM_TX_TAGGED_FRMS_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 160, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_UNTAGGED_FRMS_CNT */ -#define ASM_TX_UNTAGGED_FRMS_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 164, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_SYMBOL_ERR_CNT */ -#define ASM_PMAC_RX_SYMBOL_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 168, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_PAUSE_CNT */ -#define ASM_PMAC_RX_PAUSE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 172, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_UNSUP_OPCODE_CNT */ -#define ASM_PMAC_RX_UNSUP_OPCODE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 176, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_OK_BYTES_CNT */ -#define ASM_PMAC_RX_OK_BYTES_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 180, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_BAD_BYTES_CNT */ -#define ASM_PMAC_RX_BAD_BYTES_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 184, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_UC_CNT */ -#define ASM_PMAC_RX_UC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 188, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_MC_CNT */ -#define ASM_PMAC_RX_MC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 192, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_BC_CNT */ -#define ASM_PMAC_RX_BC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 196, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_CRC_ERR_CNT */ -#define ASM_PMAC_RX_CRC_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 200, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_UNDERSIZE_CNT */ -#define ASM_PMAC_RX_UNDERSIZE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 204, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_FRAGMENTS_CNT */ -#define ASM_PMAC_RX_FRAGMENTS_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 208, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_IN_RANGE_LEN_ERR_CNT */ -#define ASM_PMAC_RX_IN_RANGE_LEN_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 212, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT */ -#define ASM_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 216, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_OVERSIZE_CNT */ -#define ASM_PMAC_RX_OVERSIZE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 220, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_JABBERS_CNT */ -#define ASM_PMAC_RX_JABBERS_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 224, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_SIZE64_CNT */ -#define ASM_PMAC_RX_SIZE64_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 228, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_SIZE65TO127_CNT */ -#define ASM_PMAC_RX_SIZE65TO127_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 232, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_SIZE128TO255_CNT */ -#define ASM_PMAC_RX_SIZE128TO255_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 236, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_SIZE256TO511_CNT */ -#define ASM_PMAC_RX_SIZE256TO511_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 240, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_SIZE512TO1023_CNT */ -#define ASM_PMAC_RX_SIZE512TO1023_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 244, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_SIZE1024TO1518_CNT */ -#define ASM_PMAC_RX_SIZE1024TO1518_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 248, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_SIZE1519TOMAX_CNT */ -#define ASM_PMAC_RX_SIZE1519TOMAX_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 252, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_PAUSE_CNT */ -#define ASM_PMAC_TX_PAUSE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 256, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_OK_BYTES_CNT */ -#define ASM_PMAC_TX_OK_BYTES_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 260, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_UC_CNT */ -#define ASM_PMAC_TX_UC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 264, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_MC_CNT */ -#define ASM_PMAC_TX_MC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 268, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_BC_CNT */ -#define ASM_PMAC_TX_BC_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 272, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_SIZE64_CNT */ -#define ASM_PMAC_TX_SIZE64_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 276, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_SIZE65TO127_CNT */ -#define ASM_PMAC_TX_SIZE65TO127_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 280, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_SIZE128TO255_CNT */ -#define ASM_PMAC_TX_SIZE128TO255_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 284, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_SIZE256TO511_CNT */ -#define ASM_PMAC_TX_SIZE256TO511_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 288, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_SIZE512TO1023_CNT */ -#define ASM_PMAC_TX_SIZE512TO1023_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 292, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_SIZE1024TO1518_CNT */ -#define ASM_PMAC_TX_SIZE1024TO1518_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 296, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_TX_SIZE1519TOMAX_CNT */ -#define ASM_PMAC_TX_SIZE1519TOMAX_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 300, 0, 1, 4) - -/* ASM:DEV_STATISTICS:PMAC_RX_ALIGNMENT_LOST_CNT */ -#define ASM_PMAC_RX_ALIGNMENT_LOST_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 304, 0, 1, 4) - -/* ASM:DEV_STATISTICS:MM_RX_ASSEMBLY_ERR_CNT */ -#define ASM_MM_RX_ASSEMBLY_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 308, 0, 1, 4) - -/* ASM:DEV_STATISTICS:MM_RX_SMD_ERR_CNT */ -#define ASM_MM_RX_SMD_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 312, 0, 1, 4) - -/* ASM:DEV_STATISTICS:MM_RX_ASSEMBLY_OK_CNT */ -#define ASM_MM_RX_ASSEMBLY_OK_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 316, 0, 1, 4) - -/* ASM:DEV_STATISTICS:MM_RX_MERGE_FRAG_CNT */ -#define ASM_MM_RX_MERGE_FRAG_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 320, 0, 1, 4) - -/* ASM:DEV_STATISTICS:MM_TX_PFRAGMENT_CNT */ -#define ASM_MM_TX_PFRAGMENT_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 324, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_MULTI_COLL_CNT */ -#define ASM_TX_MULTI_COLL_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 328, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_LATE_COLL_CNT */ -#define ASM_TX_LATE_COLL_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 332, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_XCOLL_CNT */ -#define ASM_TX_XCOLL_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 336, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_DEFER_CNT */ -#define ASM_TX_DEFER_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 340, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_XDEFER_CNT */ -#define ASM_TX_XDEFER_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 344, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_BACKOFF1_CNT */ -#define ASM_TX_BACKOFF1_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 348, 0, 1, 4) - -/* ASM:DEV_STATISTICS:TX_CSENSE_CNT */ -#define ASM_TX_CSENSE_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 352, 0, 1, 4) - -/* ASM:DEV_STATISTICS:RX_IN_BYTES_MSB_CNT */ -#define ASM_RX_IN_BYTES_MSB_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 356, 0, 1, 4) +/* ASM:DEV_STATISTICS:RX_IN_BYTES_CNT */ +#define ASM_RX_IN_BYTES_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 0, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_SYMBOL_ERR_CNT */ +#define ASM_RX_SYMBOL_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 4, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_PAUSE_CNT */ +#define ASM_RX_PAUSE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 8, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_UNSUP_OPCODE_CNT */ +#define ASM_RX_UNSUP_OPCODE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 12, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_OK_BYTES_CNT */ +#define ASM_RX_OK_BYTES_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 16, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_BAD_BYTES_CNT */ +#define ASM_RX_BAD_BYTES_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 20, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_UC_CNT */ +#define ASM_RX_UC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 24, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_MC_CNT */ +#define ASM_RX_MC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 28, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_BC_CNT */ +#define ASM_RX_BC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 32, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_CRC_ERR_CNT */ +#define ASM_RX_CRC_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 36, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_UNDERSIZE_CNT */ +#define ASM_RX_UNDERSIZE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 40, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_FRAGMENTS_CNT */ +#define ASM_RX_FRAGMENTS_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 44, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_IN_RANGE_LEN_ERR_CNT */ +#define ASM_RX_IN_RANGE_LEN_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 48, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_OUT_OF_RANGE_LEN_ERR_CNT */ +#define ASM_RX_OUT_OF_RANGE_LEN_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 52, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_OVERSIZE_CNT */ +#define ASM_RX_OVERSIZE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 56, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_JABBERS_CNT */ +#define ASM_RX_JABBERS_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 60, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_SIZE64_CNT */ +#define ASM_RX_SIZE64_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 64, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_SIZE65TO127_CNT */ +#define ASM_RX_SIZE65TO127_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 68, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_SIZE128TO255_CNT */ +#define ASM_RX_SIZE128TO255_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 72, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_SIZE256TO511_CNT */ +#define ASM_RX_SIZE256TO511_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 76, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_SIZE512TO1023_CNT */ +#define ASM_RX_SIZE512TO1023_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 80, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_SIZE1024TO1518_CNT */ +#define ASM_RX_SIZE1024TO1518_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 84, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_SIZE1519TOMAX_CNT */ +#define ASM_RX_SIZE1519TOMAX_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 88, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_IPG_SHRINK_CNT */ +#define ASM_RX_IPG_SHRINK_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 92, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_OUT_BYTES_CNT */ +#define ASM_TX_OUT_BYTES_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 96, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_PAUSE_CNT */ +#define ASM_TX_PAUSE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 100, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_OK_BYTES_CNT */ +#define ASM_TX_OK_BYTES_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 104, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_UC_CNT */ +#define ASM_TX_UC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 108, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_MC_CNT */ +#define ASM_TX_MC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 112, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_BC_CNT */ +#define ASM_TX_BC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 116, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_SIZE64_CNT */ +#define ASM_TX_SIZE64_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 120, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_SIZE65TO127_CNT */ +#define ASM_TX_SIZE65TO127_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 124, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_SIZE128TO255_CNT */ +#define ASM_TX_SIZE128TO255_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 128, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_SIZE256TO511_CNT */ +#define ASM_TX_SIZE256TO511_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 132, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_SIZE512TO1023_CNT */ +#define ASM_TX_SIZE512TO1023_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 136, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_SIZE1024TO1518_CNT */ +#define ASM_TX_SIZE1024TO1518_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 140, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_SIZE1519TOMAX_CNT */ +#define ASM_TX_SIZE1519TOMAX_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 144, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_ALIGNMENT_LOST_CNT */ +#define ASM_RX_ALIGNMENT_LOST_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 148, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_TAGGED_FRMS_CNT */ +#define ASM_RX_TAGGED_FRMS_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 152, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_UNTAGGED_FRMS_CNT */ +#define ASM_RX_UNTAGGED_FRMS_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 156, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_TAGGED_FRMS_CNT */ +#define ASM_TX_TAGGED_FRMS_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 160, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_UNTAGGED_FRMS_CNT */ +#define ASM_TX_UNTAGGED_FRMS_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 164, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_SYMBOL_ERR_CNT */ +#define ASM_PMAC_RX_SYMBOL_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 168, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_PAUSE_CNT */ +#define ASM_PMAC_RX_PAUSE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 172, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_UNSUP_OPCODE_CNT */ +#define ASM_PMAC_RX_UNSUP_OPCODE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 176, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_OK_BYTES_CNT */ +#define ASM_PMAC_RX_OK_BYTES_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 180, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_BAD_BYTES_CNT */ +#define ASM_PMAC_RX_BAD_BYTES_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 184, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_UC_CNT */ +#define ASM_PMAC_RX_UC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 188, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_MC_CNT */ +#define ASM_PMAC_RX_MC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 192, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_BC_CNT */ +#define ASM_PMAC_RX_BC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 196, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_CRC_ERR_CNT */ +#define ASM_PMAC_RX_CRC_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 200, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_UNDERSIZE_CNT */ +#define ASM_PMAC_RX_UNDERSIZE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 204, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_FRAGMENTS_CNT */ +#define ASM_PMAC_RX_FRAGMENTS_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 208, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_IN_RANGE_LEN_ERR_CNT */ +#define ASM_PMAC_RX_IN_RANGE_LEN_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 212, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT */ +#define ASM_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 216, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_OVERSIZE_CNT */ +#define ASM_PMAC_RX_OVERSIZE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 220, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_JABBERS_CNT */ +#define ASM_PMAC_RX_JABBERS_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 224, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_SIZE64_CNT */ +#define ASM_PMAC_RX_SIZE64_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 228, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_SIZE65TO127_CNT */ +#define ASM_PMAC_RX_SIZE65TO127_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 232, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_SIZE128TO255_CNT */ +#define ASM_PMAC_RX_SIZE128TO255_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 236, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_SIZE256TO511_CNT */ +#define ASM_PMAC_RX_SIZE256TO511_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 240, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_SIZE512TO1023_CNT */ +#define ASM_PMAC_RX_SIZE512TO1023_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 244, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_SIZE1024TO1518_CNT */ +#define ASM_PMAC_RX_SIZE1024TO1518_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 248, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_SIZE1519TOMAX_CNT */ +#define ASM_PMAC_RX_SIZE1519TOMAX_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 252, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_PAUSE_CNT */ +#define ASM_PMAC_TX_PAUSE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 256, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_OK_BYTES_CNT */ +#define ASM_PMAC_TX_OK_BYTES_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 260, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_UC_CNT */ +#define ASM_PMAC_TX_UC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 264, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_MC_CNT */ +#define ASM_PMAC_TX_MC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 268, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_BC_CNT */ +#define ASM_PMAC_TX_BC_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 272, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_SIZE64_CNT */ +#define ASM_PMAC_TX_SIZE64_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 276, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_SIZE65TO127_CNT */ +#define ASM_PMAC_TX_SIZE65TO127_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 280, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_SIZE128TO255_CNT */ +#define ASM_PMAC_TX_SIZE128TO255_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 284, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_SIZE256TO511_CNT */ +#define ASM_PMAC_TX_SIZE256TO511_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 288, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_SIZE512TO1023_CNT */ +#define ASM_PMAC_TX_SIZE512TO1023_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 292, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_SIZE1024TO1518_CNT */ +#define ASM_PMAC_TX_SIZE1024TO1518_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 296, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_TX_SIZE1519TOMAX_CNT */ +#define ASM_PMAC_TX_SIZE1519TOMAX_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 300, 0, 1, 4) + +/* ASM:DEV_STATISTICS:PMAC_RX_ALIGNMENT_LOST_CNT */ +#define ASM_PMAC_RX_ALIGNMENT_LOST_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 304, 0, 1, 4) + +/* ASM:DEV_STATISTICS:MM_RX_ASSEMBLY_ERR_CNT */ +#define ASM_MM_RX_ASSEMBLY_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 308, 0, 1, 4) + +/* ASM:DEV_STATISTICS:MM_RX_SMD_ERR_CNT */ +#define ASM_MM_RX_SMD_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 312, 0, 1, 4) + +/* ASM:DEV_STATISTICS:MM_RX_ASSEMBLY_OK_CNT */ +#define ASM_MM_RX_ASSEMBLY_OK_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 316, 0, 1, 4) + +/* ASM:DEV_STATISTICS:MM_RX_MERGE_FRAG_CNT */ +#define ASM_MM_RX_MERGE_FRAG_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 320, 0, 1, 4) + +/* ASM:DEV_STATISTICS:MM_TX_PFRAGMENT_CNT */ +#define ASM_MM_TX_PFRAGMENT_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 324, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_MULTI_COLL_CNT */ +#define ASM_TX_MULTI_COLL_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 328, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_LATE_COLL_CNT */ +#define ASM_TX_LATE_COLL_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 332, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_XCOLL_CNT */ +#define ASM_TX_XCOLL_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 336, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_DEFER_CNT */ +#define ASM_TX_DEFER_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 340, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_XDEFER_CNT */ +#define ASM_TX_XDEFER_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 344, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_BACKOFF1_CNT */ +#define ASM_TX_BACKOFF1_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 348, 0, 1, 4) + +/* ASM:DEV_STATISTICS:TX_CSENSE_CNT */ +#define ASM_TX_CSENSE_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 352, 0, 1, 4) + +/* ASM:DEV_STATISTICS:RX_IN_BYTES_MSB_CNT */ +#define ASM_RX_IN_BYTES_MSB_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 356, 0, 1, 4) #define ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT GENMASK(3, 0) #define ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT_SET(x)\ @@ -2133,9 +2348,10 @@ enum sparx5_target { #define ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT_GET(x)\ FIELD_GET(ASM_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT, x) -/* ASM:DEV_STATISTICS:RX_OK_BYTES_MSB_CNT */ -#define ASM_RX_OK_BYTES_MSB_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 360, 0, 1, 4) +/* ASM:DEV_STATISTICS:RX_OK_BYTES_MSB_CNT */ +#define ASM_RX_OK_BYTES_MSB_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 360, 0, 1, 4) #define ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT GENMASK(3, 0) #define ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT_SET(x)\ @@ -2143,9 +2359,10 @@ enum sparx5_target { #define ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT_GET(x)\ FIELD_GET(ASM_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT, x) -/* ASM:DEV_STATISTICS:PMAC_RX_OK_BYTES_MSB_CNT */ -#define ASM_PMAC_RX_OK_BYTES_MSB_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 364, 0, 1, 4) +/* ASM:DEV_STATISTICS:PMAC_RX_OK_BYTES_MSB_CNT */ +#define ASM_PMAC_RX_OK_BYTES_MSB_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 364, 0, 1, 4) #define ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT GENMASK(3, 0) #define ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT_SET(x)\ @@ -2153,9 +2370,10 @@ enum sparx5_target { #define ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT_GET(x)\ FIELD_GET(ASM_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT, x) -/* ASM:DEV_STATISTICS:RX_BAD_BYTES_MSB_CNT */ -#define ASM_RX_BAD_BYTES_MSB_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 368, 0, 1, 4) +/* ASM:DEV_STATISTICS:RX_BAD_BYTES_MSB_CNT */ +#define ASM_RX_BAD_BYTES_MSB_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 368, 0, 1, 4) #define ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT GENMASK(3, 0) #define ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT_SET(x)\ @@ -2163,9 +2381,10 @@ enum sparx5_target { #define ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT_GET(x)\ FIELD_GET(ASM_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT, x) -/* ASM:DEV_STATISTICS:PMAC_RX_BAD_BYTES_MSB_CNT */ -#define ASM_PMAC_RX_BAD_BYTES_MSB_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 372, 0, 1, 4) +/* ASM:DEV_STATISTICS:PMAC_RX_BAD_BYTES_MSB_CNT */ +#define ASM_PMAC_RX_BAD_BYTES_MSB_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 372, 0, 1, 4) #define ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT GENMASK(3, 0) #define ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT_SET(x)\ @@ -2173,9 +2392,10 @@ enum sparx5_target { #define ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT_GET(x)\ FIELD_GET(ASM_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT, x) -/* ASM:DEV_STATISTICS:TX_OUT_BYTES_MSB_CNT */ -#define ASM_TX_OUT_BYTES_MSB_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 376, 0, 1, 4) +/* ASM:DEV_STATISTICS:TX_OUT_BYTES_MSB_CNT */ +#define ASM_TX_OUT_BYTES_MSB_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 376, 0, 1, 4) #define ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT GENMASK(3, 0) #define ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT_SET(x)\ @@ -2183,9 +2403,10 @@ enum sparx5_target { #define ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT_GET(x)\ FIELD_GET(ASM_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT, x) -/* ASM:DEV_STATISTICS:TX_OK_BYTES_MSB_CNT */ -#define ASM_TX_OK_BYTES_MSB_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 380, 0, 1, 4) +/* ASM:DEV_STATISTICS:TX_OK_BYTES_MSB_CNT */ +#define ASM_TX_OK_BYTES_MSB_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 380, 0, 1, 4) #define ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT GENMASK(3, 0) #define ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT_SET(x)\ @@ -2193,9 +2414,10 @@ enum sparx5_target { #define ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT_GET(x)\ FIELD_GET(ASM_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT, x) -/* ASM:DEV_STATISTICS:PMAC_TX_OK_BYTES_MSB_CNT */ -#define ASM_PMAC_TX_OK_BYTES_MSB_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 384, 0, 1, 4) +/* ASM:DEV_STATISTICS:PMAC_TX_OK_BYTES_MSB_CNT */ +#define ASM_PMAC_TX_OK_BYTES_MSB_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 384, 0, 1, 4) #define ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT GENMASK(3, 0) #define ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT_SET(x)\ @@ -2203,13 +2425,15 @@ enum sparx5_target { #define ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT_GET(x)\ FIELD_GET(ASM_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT, x) -/* ASM:DEV_STATISTICS:RX_SYNC_LOST_ERR_CNT */ -#define ASM_RX_SYNC_LOST_ERR_CNT(g) __REG(TARGET_ASM,\ - 0, 1, 0, g, 65, 512, 388, 0, 1, 4) +/* ASM:DEV_STATISTICS:RX_SYNC_LOST_ERR_CNT */ +#define ASM_RX_SYNC_LOST_ERR_CNT(g) \ + __REG(TARGET_ASM, 0, 1, 0, g, regs->gcnt[GC_ASM_DEV_STATISTICS], 512, \ + 388, 0, 1, 4) -/* ASM:CFG:STAT_CFG */ -#define ASM_STAT_CFG __REG(TARGET_ASM,\ - 0, 1, 33280, 0, 1, 1088, 0, 0, 1, 4) +/* ASM:CFG:STAT_CFG */ +#define ASM_STAT_CFG \ + __REG(TARGET_ASM, 0, 1, regs->gaddr[GA_ASM_CFG], 0, 1, \ + regs->gsize[GW_ASM_CFG], 0, 0, 1, 4) #define ASM_STAT_CFG_STAT_CNT_CLR_SHOT BIT(0) #define ASM_STAT_CFG_STAT_CNT_CLR_SHOT_SET(x)\ @@ -2217,9 +2441,10 @@ enum sparx5_target { #define ASM_STAT_CFG_STAT_CNT_CLR_SHOT_GET(x)\ FIELD_GET(ASM_STAT_CFG_STAT_CNT_CLR_SHOT, x) -/* ASM:CFG:PORT_CFG */ -#define ASM_PORT_CFG(r) __REG(TARGET_ASM,\ - 0, 1, 33280, 0, 1, 1088, 540, r, 67, 4) +/* ASM:CFG:PORT_CFG */ +#define ASM_PORT_CFG(r) \ + __REG(TARGET_ASM, 0, 1, regs->gaddr[GA_ASM_CFG], 0, 1, \ + regs->gsize[GW_ASM_CFG], 540, r, regs->rcnt[RC_ASM_PORT_CFG], 4) #define ASM_PORT_CFG_CSC_STAT_DIS BIT(12) #define ASM_PORT_CFG_CSC_STAT_DIS_SET(x)\ @@ -2287,9 +2512,10 @@ enum sparx5_target { #define ASM_PORT_CFG_PFRM_FLUSH_GET(x)\ FIELD_GET(ASM_PORT_CFG_PFRM_FLUSH, x) -/* ASM:RAM_CTRL:RAM_INIT */ -#define ASM_RAM_INIT __REG(TARGET_ASM,\ - 0, 1, 34832, 0, 1, 4, 0, 0, 1, 4) +/* ASM:RAM_CTRL:RAM_INIT */ +#define ASM_RAM_INIT \ + __REG(TARGET_ASM, 0, 1, regs->gaddr[GA_ASM_RAM_CTRL], 0, 1, 4, 0, 0, 1,\ + 4) #define ASM_RAM_INIT_RAM_INIT BIT(1) #define ASM_RAM_INIT_RAM_INIT_SET(x)\ @@ -2303,9 +2529,10 @@ enum sparx5_target { #define ASM_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(ASM_RAM_INIT_RAM_CFG_HOOK, x) -/* CLKGEN:LCPLL1:LCPLL1_CORE_CLK_CFG */ -#define CLKGEN_LCPLL1_CORE_CLK_CFG __REG(TARGET_CLKGEN,\ - 0, 1, 12, 0, 1, 36, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* CLKGEN:LCPLL1:LCPLL1_CORE_CLK_CFG */ +#define CLKGEN_LCPLL1_CORE_CLK_CFG \ + __REG(TARGET_CLKGEN, 0, 1, 12, 0, 1, 36, 0, 0, 1, 4) #define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV GENMASK(7, 0) #define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV_SET(x)\ @@ -2343,91 +2570,144 @@ enum sparx5_target { #define CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA_GET(x)\ FIELD_GET(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA, x) -/* CPU:CPU_REGS:PROC_CTRL */ -#define CPU_PROC_CTRL __REG(TARGET_CPU,\ - 0, 1, 0, 0, 1, 204, 176, 0, 1, 4) +/* CPU:CPU_REGS:PROC_CTRL */ +#define CPU_PROC_CTRL \ + __REG(TARGET_CPU, 0, 1, 0, 0, 1, regs->gsize[GW_CPU_CPU_REGS], \ + regs->raddr[RA_CPU_PROC_CTRL], 0, 1, 4) -#define CPU_PROC_CTRL_AARCH64_MODE_ENA BIT(12) +#define CPU_PROC_CTRL_AARCH64_MODE_ENA\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_AARCH64_MODE_ENA]) #define CPU_PROC_CTRL_AARCH64_MODE_ENA_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_AARCH64_MODE_ENA, x) + spx5_field_prep(CPU_PROC_CTRL_AARCH64_MODE_ENA, x) #define CPU_PROC_CTRL_AARCH64_MODE_ENA_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_AARCH64_MODE_ENA, x) + spx5_field_get(CPU_PROC_CTRL_AARCH64_MODE_ENA, x) -#define CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS BIT(11) +#define CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS]) #define CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS, x) + spx5_field_prep(CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS, x) #define CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS, x) + spx5_field_get(CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS, x) -#define CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS BIT(10) +#define CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS]) #define CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS, x) + spx5_field_prep(CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS, x) #define CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS, x) + spx5_field_get(CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS, x) -#define CPU_PROC_CTRL_BE_EXCEP_MODE BIT(9) +#define CPU_PROC_CTRL_BE_EXCEP_MODE\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_BE_EXCEP_MODE]) #define CPU_PROC_CTRL_BE_EXCEP_MODE_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_BE_EXCEP_MODE, x) + spx5_field_prep(CPU_PROC_CTRL_BE_EXCEP_MODE, x) #define CPU_PROC_CTRL_BE_EXCEP_MODE_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_BE_EXCEP_MODE, x) + spx5_field_get(CPU_PROC_CTRL_BE_EXCEP_MODE, x) -#define CPU_PROC_CTRL_VINITHI BIT(8) +#define CPU_PROC_CTRL_VINITHI\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_VINITHI]) #define CPU_PROC_CTRL_VINITHI_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_VINITHI, x) + spx5_field_prep(CPU_PROC_CTRL_VINITHI, x) #define CPU_PROC_CTRL_VINITHI_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_VINITHI, x) + spx5_field_get(CPU_PROC_CTRL_VINITHI, x) -#define CPU_PROC_CTRL_CFGTE BIT(7) +#define CPU_PROC_CTRL_CFGTE\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_CFGTE]) #define CPU_PROC_CTRL_CFGTE_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_CFGTE, x) + spx5_field_prep(CPU_PROC_CTRL_CFGTE, x) #define CPU_PROC_CTRL_CFGTE_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_CFGTE, x) + spx5_field_get(CPU_PROC_CTRL_CFGTE, x) -#define CPU_PROC_CTRL_CP15S_DISABLE BIT(6) +#define CPU_PROC_CTRL_CP15S_DISABLE\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_CP15S_DISABLE]) #define CPU_PROC_CTRL_CP15S_DISABLE_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_CP15S_DISABLE, x) + spx5_field_prep(CPU_PROC_CTRL_CP15S_DISABLE, x) #define CPU_PROC_CTRL_CP15S_DISABLE_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_CP15S_DISABLE, x) + spx5_field_get(CPU_PROC_CTRL_CP15S_DISABLE, x) -#define CPU_PROC_CTRL_PROC_CRYPTO_DISABLE BIT(5) +#define CPU_PROC_CTRL_PROC_CRYPTO_DISABLE\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_PROC_CRYPTO_DISABLE]) #define CPU_PROC_CTRL_PROC_CRYPTO_DISABLE_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_PROC_CRYPTO_DISABLE, x) + spx5_field_prep(CPU_PROC_CTRL_PROC_CRYPTO_DISABLE, x) #define CPU_PROC_CTRL_PROC_CRYPTO_DISABLE_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_PROC_CRYPTO_DISABLE, x) + spx5_field_get(CPU_PROC_CTRL_PROC_CRYPTO_DISABLE, x) +/* SPARX5 ONLY */ #define CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA BIT(4) #define CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA_SET(x)\ FIELD_PREP(CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA, x) #define CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA_GET(x)\ FIELD_GET(CPU_PROC_CTRL_ACP_CACHE_FORCE_ENA, x) +/* SPARX5 ONLY */ #define CPU_PROC_CTRL_ACP_AWCACHE BIT(3) #define CPU_PROC_CTRL_ACP_AWCACHE_SET(x)\ FIELD_PREP(CPU_PROC_CTRL_ACP_AWCACHE, x) #define CPU_PROC_CTRL_ACP_AWCACHE_GET(x)\ FIELD_GET(CPU_PROC_CTRL_ACP_AWCACHE, x) +/* SPARX5 ONLY */ #define CPU_PROC_CTRL_ACP_ARCACHE BIT(2) #define CPU_PROC_CTRL_ACP_ARCACHE_SET(x)\ FIELD_PREP(CPU_PROC_CTRL_ACP_ARCACHE, x) #define CPU_PROC_CTRL_ACP_ARCACHE_GET(x)\ FIELD_GET(CPU_PROC_CTRL_ACP_ARCACHE, x) -#define CPU_PROC_CTRL_L2_FLUSH_REQ BIT(1) +#define CPU_PROC_CTRL_L2_FLUSH_REQ\ + BIT(regs->fpos[FP_CPU_PROC_CTRL_L2_FLUSH_REQ]) #define CPU_PROC_CTRL_L2_FLUSH_REQ_SET(x)\ - FIELD_PREP(CPU_PROC_CTRL_L2_FLUSH_REQ, x) + spx5_field_prep(CPU_PROC_CTRL_L2_FLUSH_REQ, x) #define CPU_PROC_CTRL_L2_FLUSH_REQ_GET(x)\ - FIELD_GET(CPU_PROC_CTRL_L2_FLUSH_REQ, x) + spx5_field_get(CPU_PROC_CTRL_L2_FLUSH_REQ, x) +/* SPARX5 ONLY */ #define CPU_PROC_CTRL_ACP_DISABLE BIT(0) #define CPU_PROC_CTRL_ACP_DISABLE_SET(x)\ FIELD_PREP(CPU_PROC_CTRL_ACP_DISABLE, x) #define CPU_PROC_CTRL_ACP_DISABLE_GET(x)\ FIELD_GET(CPU_PROC_CTRL_ACP_DISABLE, x) -/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */ -#define DEV10G_MAC_ENA_CFG(t) __REG(TARGET_DEV10G,\ - t, 12, 0, 0, 1, 60, 0, 0, 1, 4) +/* DEV1G:PHASE_DETECTOR_CTRL:PHAD_CTRL */ +#define DEV2G5_PHAD_CTRL(t, g) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 200, g, 2, \ + regs->gsize[GW_DEV2G5_PHASE_DETECTOR_CTRL], 0, 0, 1, 4) + +#define DEV2G5_PHAD_CTRL_PHAD_ENA\ + BIT(regs->fpos[FP_DEV2G5_PHAD_CTRL_PHAD_ENA]) +#define DEV2G5_PHAD_CTRL_PHAD_ENA_SET(x)\ + spx5_field_prep(DEV2G5_PHAD_CTRL_PHAD_ENA, x) +#define DEV2G5_PHAD_CTRL_PHAD_ENA_GET(x)\ + spx5_field_get(DEV2G5_PHAD_CTRL_PHAD_ENA, x) + +/* LAN969X ONLY */ +#define DEV2G5_PHAD_CTRL_DIV_CFG GENMASK(11, 9) +#define DEV2G5_PHAD_CTRL_DIV_CFG_SET(x)\ + FIELD_PREP(DEV2G5_PHAD_CTRL_DIV_CFG, x) +#define DEV2G5_PHAD_CTRL_DIV_CFG_GET(x)\ + FIELD_GET(DEV2G5_PHAD_CTRL_DIV_CFG, x) + +/* DEV1G:PHASE_DETECTOR_CTRL:PHAD_CTRL */ +#define DEV2G5_PHAD_CTRL(t, g) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 200, g, 2, \ + regs->gsize[GW_DEV2G5_PHASE_DETECTOR_CTRL], 0, 0, 1, 4) + +#define DEV2G5_PHAD_CTRL_PHAD_ENA\ + BIT(regs->fpos[FP_DEV2G5_PHAD_CTRL_PHAD_ENA]) +#define DEV2G5_PHAD_CTRL_PHAD_ENA_SET(x)\ + spx5_field_prep(DEV2G5_PHAD_CTRL_PHAD_ENA, x) +#define DEV2G5_PHAD_CTRL_PHAD_ENA_GET(x)\ + spx5_field_get(DEV2G5_PHAD_CTRL_PHAD_ENA, x) + +/* LAN969X ONLY */ +#define DEV2G5_PHAD_CTRL_DIV_CFG GENMASK(11, 9) +#define DEV2G5_PHAD_CTRL_DIV_CFG_SET(x)\ + FIELD_PREP(DEV2G5_PHAD_CTRL_DIV_CFG, x) +#define DEV2G5_PHAD_CTRL_DIV_CFG_GET(x)\ + FIELD_GET(DEV2G5_PHAD_CTRL_DIV_CFG, x) + +/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */ +#define DEV10G_MAC_ENA_CFG(t) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 0, 0, 1, 60, 0, 0, 1, \ + 4) #define DEV10G_MAC_ENA_CFG_RX_ENA BIT(4) #define DEV10G_MAC_ENA_CFG_RX_ENA_SET(x)\ @@ -2441,9 +2721,10 @@ enum sparx5_target { #define DEV10G_MAC_ENA_CFG_TX_ENA_GET(x)\ FIELD_GET(DEV10G_MAC_ENA_CFG_TX_ENA, x) -/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */ -#define DEV10G_MAC_MAXLEN_CFG(t) __REG(TARGET_DEV10G,\ - t, 12, 0, 0, 1, 60, 8, 0, 1, 4) +/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */ +#define DEV10G_MAC_MAXLEN_CFG(t) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 0, 0, 1, 60, 8, 0, 1, \ + 4) #define DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK BIT(16) #define DEV10G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_SET(x)\ @@ -2457,9 +2738,10 @@ enum sparx5_target { #define DEV10G_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\ FIELD_GET(DEV10G_MAC_MAXLEN_CFG_MAX_LEN, x) -/* DEV10G:MAC_CFG_STATUS:MAC_NUM_TAGS_CFG */ -#define DEV10G_MAC_NUM_TAGS_CFG(t) __REG(TARGET_DEV10G,\ - t, 12, 0, 0, 1, 60, 12, 0, 1, 4) +/* DEV10G:MAC_CFG_STATUS:MAC_NUM_TAGS_CFG */ +#define DEV10G_MAC_NUM_TAGS_CFG(t) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 0, 0, 1, 60, 12, 0, 1, \ + 4) #define DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS GENMASK(1, 0) #define DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS_SET(x)\ @@ -2467,9 +2749,10 @@ enum sparx5_target { #define DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS_GET(x)\ FIELD_GET(DEV10G_MAC_NUM_TAGS_CFG_NUM_TAGS, x) -/* DEV10G:MAC_CFG_STATUS:MAC_TAGS_CFG */ -#define DEV10G_MAC_TAGS_CFG(t, r) __REG(TARGET_DEV10G,\ - t, 12, 0, 0, 1, 60, 16, r, 3, 4) +/* DEV10G:MAC_CFG_STATUS:MAC_TAGS_CFG */ +#define DEV10G_MAC_TAGS_CFG(t, r) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 0, 0, 1, 60, 16, r, 3, \ + 4) #define DEV10G_MAC_TAGS_CFG_TAG_ID GENMASK(31, 16) #define DEV10G_MAC_TAGS_CFG_TAG_ID_SET(x)\ @@ -2483,9 +2766,10 @@ enum sparx5_target { #define DEV10G_MAC_TAGS_CFG_TAG_ENA_GET(x)\ FIELD_GET(DEV10G_MAC_TAGS_CFG_TAG_ENA, x) -/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */ -#define DEV10G_MAC_ADV_CHK_CFG(t) __REG(TARGET_DEV10G,\ - t, 12, 0, 0, 1, 60, 28, 0, 1, 4) +/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */ +#define DEV10G_MAC_ADV_CHK_CFG(t) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 0, 0, 1, 60, 28, 0, 1, \ + 4) #define DEV10G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA BIT(24) #define DEV10G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_SET(x)\ @@ -2529,9 +2813,10 @@ enum sparx5_target { #define DEV10G_MAC_ADV_CHK_CFG_INR_ERR_ENA_GET(x)\ FIELD_GET(DEV10G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x) -/* DEV10G:MAC_CFG_STATUS:MAC_TX_MONITOR_STICKY */ -#define DEV10G_MAC_TX_MONITOR_STICKY(t) __REG(TARGET_DEV10G,\ - t, 12, 0, 0, 1, 60, 48, 0, 1, 4) +/* DEV10G:MAC_CFG_STATUS:MAC_TX_MONITOR_STICKY */ +#define DEV10G_MAC_TX_MONITOR_STICKY(t) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 0, 0, 1, 60, 48, 0, 1, \ + 4) #define DEV10G_MAC_TX_MONITOR_STICKY_LOCAL_ERR_STATE_STICKY BIT(4) #define DEV10G_MAC_TX_MONITOR_STICKY_LOCAL_ERR_STATE_STICKY_SET(x)\ @@ -2563,9 +2848,10 @@ enum sparx5_target { #define DEV10G_MAC_TX_MONITOR_STICKY_DIS_STATE_STICKY_GET(x)\ FIELD_GET(DEV10G_MAC_TX_MONITOR_STICKY_DIS_STATE_STICKY, x) -/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */ -#define DEV10G_DEV_RST_CTRL(t) __REG(TARGET_DEV10G,\ - t, 12, 436, 0, 1, 52, 0, 0, 1, 4) +/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */ +#define DEV10G_DEV_RST_CTRL(t) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 436, 0, 1, 52, 0, 0, 1,\ + 4) #define DEV10G_DEV_RST_CTRL_PARDET_MODE_ENA BIT(28) #define DEV10G_DEV_RST_CTRL_PARDET_MODE_ENA_SET(x)\ @@ -2621,9 +2907,15 @@ enum sparx5_target { #define DEV10G_DEV_RST_CTRL_MAC_RX_RST_GET(x)\ FIELD_GET(DEV10G_DEV_RST_CTRL_MAC_RX_RST, x) -/* DEV10G:PCS25G_CFG_STATUS:PCS25G_CFG */ -#define DEV10G_PCS25G_CFG(t) __REG(TARGET_DEV10G,\ - t, 12, 488, 0, 1, 32, 0, 0, 1, 4) +/* DEV10G:DEV_CFG_STATUS:PTP_STAMPER_CFG */ +#define DEV10G_PTP_STAMPER_CFG(t) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 436, 0, 1, 52, 20, 0, \ + 1, 4) + +/* DEV10G:PCS25G_CFG_STATUS:PCS25G_CFG */ +#define DEV10G_PCS25G_CFG(t) \ + __REG(TARGET_DEV10G, t, regs->tsize[TC_DEV10G], 488, 0, 1, 32, 0, 0, 1,\ + 4) #define DEV10G_PCS25G_CFG_PCS25G_ENA BIT(0) #define DEV10G_PCS25G_CFG_PCS25G_ENA_SET(x)\ @@ -2631,9 +2923,10 @@ enum sparx5_target { #define DEV10G_PCS25G_CFG_PCS25G_ENA_GET(x)\ FIELD_GET(DEV10G_PCS25G_CFG_PCS25G_ENA, x) -/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */ -#define DEV25G_MAC_ENA_CFG(t) __REG(TARGET_DEV25G,\ - t, 8, 0, 0, 1, 60, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */ +#define DEV25G_MAC_ENA_CFG(t) \ + __REG(TARGET_DEV25G, t, 8, 0, 0, 1, 60, 0, 0, 1, 4) #define DEV25G_MAC_ENA_CFG_RX_ENA BIT(4) #define DEV25G_MAC_ENA_CFG_RX_ENA_SET(x)\ @@ -2647,9 +2940,10 @@ enum sparx5_target { #define DEV25G_MAC_ENA_CFG_TX_ENA_GET(x)\ FIELD_GET(DEV25G_MAC_ENA_CFG_TX_ENA, x) -/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */ -#define DEV25G_MAC_MAXLEN_CFG(t) __REG(TARGET_DEV25G,\ - t, 8, 0, 0, 1, 60, 8, 0, 1, 4) +/* SPARX5 ONLY */ +/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */ +#define DEV25G_MAC_MAXLEN_CFG(t) \ + __REG(TARGET_DEV25G, t, 8, 0, 0, 1, 60, 8, 0, 1, 4) #define DEV25G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK BIT(16) #define DEV25G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_SET(x)\ @@ -2663,9 +2957,10 @@ enum sparx5_target { #define DEV25G_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\ FIELD_GET(DEV25G_MAC_MAXLEN_CFG_MAX_LEN, x) -/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */ -#define DEV25G_MAC_ADV_CHK_CFG(t) __REG(TARGET_DEV25G,\ - t, 8, 0, 0, 1, 60, 28, 0, 1, 4) +/* SPARX5 ONLY */ +/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */ +#define DEV25G_MAC_ADV_CHK_CFG(t) \ + __REG(TARGET_DEV25G, t, 8, 0, 0, 1, 60, 28, 0, 1, 4) #define DEV25G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA BIT(24) #define DEV25G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_SET(x)\ @@ -2709,9 +3004,10 @@ enum sparx5_target { #define DEV25G_MAC_ADV_CHK_CFG_INR_ERR_ENA_GET(x)\ FIELD_GET(DEV25G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x) -/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */ -#define DEV25G_DEV_RST_CTRL(t) __REG(TARGET_DEV25G,\ - t, 8, 436, 0, 1, 52, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */ +#define DEV25G_DEV_RST_CTRL(t) \ + __REG(TARGET_DEV25G, t, 8, 436, 0, 1, 52, 0, 0, 1, 4) #define DEV25G_DEV_RST_CTRL_PARDET_MODE_ENA BIT(28) #define DEV25G_DEV_RST_CTRL_PARDET_MODE_ENA_SET(x)\ @@ -2767,9 +3063,10 @@ enum sparx5_target { #define DEV25G_DEV_RST_CTRL_MAC_RX_RST_GET(x)\ FIELD_GET(DEV25G_DEV_RST_CTRL_MAC_RX_RST, x) -/* DEV10G:PCS25G_CFG_STATUS:PCS25G_CFG */ -#define DEV25G_PCS25G_CFG(t) __REG(TARGET_DEV25G,\ - t, 8, 488, 0, 1, 32, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* DEV10G:PCS25G_CFG_STATUS:PCS25G_CFG */ +#define DEV25G_PCS25G_CFG(t) \ + __REG(TARGET_DEV25G, t, 8, 488, 0, 1, 32, 0, 0, 1, 4) #define DEV25G_PCS25G_CFG_PCS25G_ENA BIT(0) #define DEV25G_PCS25G_CFG_PCS25G_ENA_SET(x)\ @@ -2777,9 +3074,10 @@ enum sparx5_target { #define DEV25G_PCS25G_CFG_PCS25G_ENA_GET(x)\ FIELD_GET(DEV25G_PCS25G_CFG_PCS25G_ENA, x) -/* DEV10G:PCS25G_CFG_STATUS:PCS25G_SD_CFG */ -#define DEV25G_PCS25G_SD_CFG(t) __REG(TARGET_DEV25G,\ - t, 8, 488, 0, 1, 32, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* DEV10G:PCS25G_CFG_STATUS:PCS25G_SD_CFG */ +#define DEV25G_PCS25G_SD_CFG(t) \ + __REG(TARGET_DEV25G, t, 8, 488, 0, 1, 32, 4, 0, 1, 4) #define DEV25G_PCS25G_SD_CFG_SD_SEL BIT(8) #define DEV25G_PCS25G_SD_CFG_SD_SEL_SET(x)\ @@ -2799,9 +3097,10 @@ enum sparx5_target { #define DEV25G_PCS25G_SD_CFG_SD_ENA_GET(x)\ FIELD_GET(DEV25G_PCS25G_SD_CFG_SD_ENA, x) -/* DEV1G:DEV_CFG_STATUS:DEV_RST_CTRL */ -#define DEV2G5_DEV_RST_CTRL(t) __REG(TARGET_DEV2G5,\ - t, 65, 0, 0, 1, 36, 0, 0, 1, 4) +/* DEV1G:DEV_CFG_STATUS:DEV_RST_CTRL */ +#define DEV2G5_DEV_RST_CTRL(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 0, 0, 1, 36, 0, 0, 1, \ + 4) #define DEV2G5_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS BIT(23) #define DEV2G5_DEV_RST_CTRL_USXGMII_OSET_FILTER_DIS_SET(x)\ @@ -2851,9 +3150,10 @@ enum sparx5_target { #define DEV2G5_DEV_RST_CTRL_MAC_RX_RST_GET(x)\ FIELD_GET(DEV2G5_DEV_RST_CTRL_MAC_RX_RST, x) -/* DEV1G:MAC_CFG_STATUS:MAC_ENA_CFG */ -#define DEV2G5_MAC_ENA_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 52, 0, 1, 36, 0, 0, 1, 4) +/* DEV1G:MAC_CFG_STATUS:MAC_ENA_CFG */ +#define DEV2G5_MAC_ENA_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 52, 0, 1, 36, 0, 0, 1, \ + 4) #define DEV2G5_MAC_ENA_CFG_RX_ENA BIT(4) #define DEV2G5_MAC_ENA_CFG_RX_ENA_SET(x)\ @@ -2867,9 +3167,10 @@ enum sparx5_target { #define DEV2G5_MAC_ENA_CFG_TX_ENA_GET(x)\ FIELD_GET(DEV2G5_MAC_ENA_CFG_TX_ENA, x) -/* DEV1G:MAC_CFG_STATUS:MAC_MODE_CFG */ -#define DEV2G5_MAC_MODE_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 52, 0, 1, 36, 4, 0, 1, 4) +/* DEV1G:MAC_CFG_STATUS:MAC_MODE_CFG */ +#define DEV2G5_MAC_MODE_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 52, 0, 1, 36, 4, 0, 1, \ + 4) #define DEV2G5_MAC_MODE_CFG_FC_WORD_SYNC_ENA BIT(8) #define DEV2G5_MAC_MODE_CFG_FC_WORD_SYNC_ENA_SET(x)\ @@ -2889,9 +3190,10 @@ enum sparx5_target { #define DEV2G5_MAC_MODE_CFG_FDX_ENA_GET(x)\ FIELD_GET(DEV2G5_MAC_MODE_CFG_FDX_ENA, x) -/* DEV1G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */ -#define DEV2G5_MAC_MAXLEN_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 52, 0, 1, 36, 8, 0, 1, 4) +/* DEV1G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */ +#define DEV2G5_MAC_MAXLEN_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 52, 0, 1, 36, 8, 0, 1, \ + 4) #define DEV2G5_MAC_MAXLEN_CFG_MAX_LEN GENMASK(15, 0) #define DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\ @@ -2899,9 +3201,10 @@ enum sparx5_target { #define DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\ FIELD_GET(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN, x) -/* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG */ -#define DEV2G5_MAC_TAGS_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 52, 0, 1, 36, 12, 0, 1, 4) +/* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG */ +#define DEV2G5_MAC_TAGS_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 52, 0, 1, 36, 12, 0, 1,\ + 4) #define DEV2G5_MAC_TAGS_CFG_TAG_ID GENMASK(31, 16) #define DEV2G5_MAC_TAGS_CFG_TAG_ID_SET(x)\ @@ -2927,9 +3230,10 @@ enum sparx5_target { #define DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA_GET(x)\ FIELD_GET(DEV2G5_MAC_TAGS_CFG_VLAN_AWR_ENA, x) -/* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG2 */ -#define DEV2G5_MAC_TAGS_CFG2(t) __REG(TARGET_DEV2G5,\ - t, 65, 52, 0, 1, 36, 16, 0, 1, 4) +/* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG2 */ +#define DEV2G5_MAC_TAGS_CFG2(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 52, 0, 1, 36, 16, 0, 1,\ + 4) #define DEV2G5_MAC_TAGS_CFG2_TAG_ID3 GENMASK(31, 16) #define DEV2G5_MAC_TAGS_CFG2_TAG_ID3_SET(x)\ @@ -2943,9 +3247,10 @@ enum sparx5_target { #define DEV2G5_MAC_TAGS_CFG2_TAG_ID2_GET(x)\ FIELD_GET(DEV2G5_MAC_TAGS_CFG2_TAG_ID2, x) -/* DEV1G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */ -#define DEV2G5_MAC_ADV_CHK_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 52, 0, 1, 36, 20, 0, 1, 4) +/* DEV1G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */ +#define DEV2G5_MAC_ADV_CHK_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 52, 0, 1, 36, 20, 0, 1,\ + 4) #define DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA BIT(0) #define DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA_SET(x)\ @@ -2953,9 +3258,10 @@ enum sparx5_target { #define DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA_GET(x)\ FIELD_GET(DEV2G5_MAC_ADV_CHK_CFG_LEN_DROP_ENA, x) -/* DEV1G:MAC_CFG_STATUS:MAC_IFG_CFG */ -#define DEV2G5_MAC_IFG_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 52, 0, 1, 36, 24, 0, 1, 4) +/* DEV1G:MAC_CFG_STATUS:MAC_IFG_CFG */ +#define DEV2G5_MAC_IFG_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 52, 0, 1, 36, 24, 0, 1,\ + 4) #define DEV2G5_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK BIT(17) #define DEV2G5_MAC_IFG_CFG_RESTORE_OLD_IPG_CHECK_SET(x)\ @@ -2981,9 +3287,10 @@ enum sparx5_target { #define DEV2G5_MAC_IFG_CFG_RX_IFG1_GET(x)\ FIELD_GET(DEV2G5_MAC_IFG_CFG_RX_IFG1, x) -/* DEV1G:MAC_CFG_STATUS:MAC_HDX_CFG */ -#define DEV2G5_MAC_HDX_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 52, 0, 1, 36, 28, 0, 1, 4) +/* DEV1G:MAC_CFG_STATUS:MAC_HDX_CFG */ +#define DEV2G5_MAC_HDX_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 52, 0, 1, 36, 28, 0, 1,\ + 4) #define DEV2G5_MAC_HDX_CFG_BYPASS_COL_SYNC BIT(26) #define DEV2G5_MAC_HDX_CFG_BYPASS_COL_SYNC_SET(x)\ @@ -3015,9 +3322,10 @@ enum sparx5_target { #define DEV2G5_MAC_HDX_CFG_LATE_COL_POS_GET(x)\ FIELD_GET(DEV2G5_MAC_HDX_CFG_LATE_COL_POS, x) -/* DEV1G:PCS1G_CFG_STATUS:PCS1G_CFG */ -#define DEV2G5_PCS1G_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 88, 0, 1, 68, 0, 0, 1, 4) +/* DEV1G:PCS1G_CFG_STATUS:PCS1G_CFG */ +#define DEV2G5_PCS1G_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 88, 0, 1, 68, 0, 0, 1, \ + 4) #define DEV2G5_PCS1G_CFG_LINK_STATUS_TYPE BIT(4) #define DEV2G5_PCS1G_CFG_LINK_STATUS_TYPE_SET(x)\ @@ -3037,9 +3345,10 @@ enum sparx5_target { #define DEV2G5_PCS1G_CFG_PCS_ENA_GET(x)\ FIELD_GET(DEV2G5_PCS1G_CFG_PCS_ENA, x) -/* DEV1G:PCS1G_CFG_STATUS:PCS1G_MODE_CFG */ -#define DEV2G5_PCS1G_MODE_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 88, 0, 1, 68, 4, 0, 1, 4) +/* DEV1G:PCS1G_CFG_STATUS:PCS1G_MODE_CFG */ +#define DEV2G5_PCS1G_MODE_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 88, 0, 1, 68, 4, 0, 1, \ + 4) #define DEV2G5_PCS1G_MODE_CFG_UNIDIR_MODE_ENA BIT(4) #define DEV2G5_PCS1G_MODE_CFG_UNIDIR_MODE_ENA_SET(x)\ @@ -3059,9 +3368,10 @@ enum sparx5_target { #define DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA_GET(x)\ FIELD_GET(DEV2G5_PCS1G_MODE_CFG_SGMII_MODE_ENA, x) -/* DEV1G:PCS1G_CFG_STATUS:PCS1G_SD_CFG */ -#define DEV2G5_PCS1G_SD_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 88, 0, 1, 68, 8, 0, 1, 4) +/* DEV1G:PCS1G_CFG_STATUS:PCS1G_SD_CFG */ +#define DEV2G5_PCS1G_SD_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 88, 0, 1, 68, 8, 0, 1, \ + 4) #define DEV2G5_PCS1G_SD_CFG_SD_SEL BIT(8) #define DEV2G5_PCS1G_SD_CFG_SD_SEL_SET(x)\ @@ -3081,9 +3391,10 @@ enum sparx5_target { #define DEV2G5_PCS1G_SD_CFG_SD_ENA_GET(x)\ FIELD_GET(DEV2G5_PCS1G_SD_CFG_SD_ENA, x) -/* DEV1G:PCS1G_CFG_STATUS:PCS1G_ANEG_CFG */ -#define DEV2G5_PCS1G_ANEG_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 88, 0, 1, 68, 12, 0, 1, 4) +/* DEV1G:PCS1G_CFG_STATUS:PCS1G_ANEG_CFG */ +#define DEV2G5_PCS1G_ANEG_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 88, 0, 1, 68, 12, 0, 1,\ + 4) #define DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY GENMASK(31, 16) #define DEV2G5_PCS1G_ANEG_CFG_ADV_ABILITY_SET(x)\ @@ -3109,9 +3420,10 @@ enum sparx5_target { #define DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA_GET(x)\ FIELD_GET(DEV2G5_PCS1G_ANEG_CFG_ANEG_ENA, x) -/* DEV1G:PCS1G_CFG_STATUS:PCS1G_LB_CFG */ -#define DEV2G5_PCS1G_LB_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 88, 0, 1, 68, 20, 0, 1, 4) +/* DEV1G:PCS1G_CFG_STATUS:PCS1G_LB_CFG */ +#define DEV2G5_PCS1G_LB_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 88, 0, 1, 68, 20, 0, 1,\ + 4) #define DEV2G5_PCS1G_LB_CFG_RA_ENA BIT(4) #define DEV2G5_PCS1G_LB_CFG_RA_ENA_SET(x)\ @@ -3131,9 +3443,10 @@ enum sparx5_target { #define DEV2G5_PCS1G_LB_CFG_TBI_HOST_LB_ENA_GET(x)\ FIELD_GET(DEV2G5_PCS1G_LB_CFG_TBI_HOST_LB_ENA, x) -/* DEV1G:PCS1G_CFG_STATUS:PCS1G_ANEG_STATUS */ -#define DEV2G5_PCS1G_ANEG_STATUS(t) __REG(TARGET_DEV2G5,\ - t, 65, 88, 0, 1, 68, 32, 0, 1, 4) +/* DEV1G:PCS1G_CFG_STATUS:PCS1G_ANEG_STATUS */ +#define DEV2G5_PCS1G_ANEG_STATUS(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 88, 0, 1, 68, 32, 0, 1,\ + 4) #define DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY GENMASK(31, 16) #define DEV2G5_PCS1G_ANEG_STATUS_LP_ADV_ABILITY_SET(x)\ @@ -3159,9 +3472,10 @@ enum sparx5_target { #define DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE_GET(x)\ FIELD_GET(DEV2G5_PCS1G_ANEG_STATUS_ANEG_COMPLETE, x) -/* DEV1G:PCS1G_CFG_STATUS:PCS1G_LINK_STATUS */ -#define DEV2G5_PCS1G_LINK_STATUS(t) __REG(TARGET_DEV2G5,\ - t, 65, 88, 0, 1, 68, 40, 0, 1, 4) +/* DEV1G:PCS1G_CFG_STATUS:PCS1G_LINK_STATUS */ +#define DEV2G5_PCS1G_LINK_STATUS(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 88, 0, 1, 68, 40, 0, 1,\ + 4) #define DEV2G5_PCS1G_LINK_STATUS_DELAY_VAR GENMASK(15, 12) #define DEV2G5_PCS1G_LINK_STATUS_DELAY_VAR_SET(x)\ @@ -3187,9 +3501,10 @@ enum sparx5_target { #define DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS_GET(x)\ FIELD_GET(DEV2G5_PCS1G_LINK_STATUS_SYNC_STATUS, x) -/* DEV1G:PCS1G_CFG_STATUS:PCS1G_STICKY */ -#define DEV2G5_PCS1G_STICKY(t) __REG(TARGET_DEV2G5,\ - t, 65, 88, 0, 1, 68, 48, 0, 1, 4) +/* DEV1G:PCS1G_CFG_STATUS:PCS1G_STICKY */ +#define DEV2G5_PCS1G_STICKY(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 88, 0, 1, 68, 48, 0, 1,\ + 4) #define DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY BIT(4) #define DEV2G5_PCS1G_STICKY_LINK_DOWN_STICKY_SET(x)\ @@ -3203,9 +3518,10 @@ enum sparx5_target { #define DEV2G5_PCS1G_STICKY_OUT_OF_SYNC_STICKY_GET(x)\ FIELD_GET(DEV2G5_PCS1G_STICKY_OUT_OF_SYNC_STICKY, x) -/* DEV1G:PCS_FX100_CONFIGURATION:PCS_FX100_CFG */ -#define DEV2G5_PCS_FX100_CFG(t) __REG(TARGET_DEV2G5,\ - t, 65, 164, 0, 1, 4, 0, 0, 1, 4) +/* DEV1G:PCS_FX100_CONFIGURATION:PCS_FX100_CFG */ +#define DEV2G5_PCS_FX100_CFG(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 164, 0, 1, 4, 0, 0, 1, \ + 4) #define DEV2G5_PCS_FX100_CFG_SD_SEL BIT(26) #define DEV2G5_PCS_FX100_CFG_SD_SEL_SET(x)\ @@ -3285,9 +3601,10 @@ enum sparx5_target { #define DEV2G5_PCS_FX100_CFG_PCS_ENA_GET(x)\ FIELD_GET(DEV2G5_PCS_FX100_CFG_PCS_ENA, x) -/* DEV1G:PCS_FX100_STATUS:PCS_FX100_STATUS */ -#define DEV2G5_PCS_FX100_STATUS(t) __REG(TARGET_DEV2G5,\ - t, 65, 168, 0, 1, 4, 0, 0, 1, 4) +/* DEV1G:PCS_FX100_STATUS:PCS_FX100_STATUS */ +#define DEV2G5_PCS_FX100_STATUS(t) \ + __REG(TARGET_DEV2G5, t, regs->tsize[TC_DEV2G5], 168, 0, 1, 4, 0, 0, 1, \ + 4) #define DEV2G5_PCS_FX100_STATUS_EDGE_POS_PTP GENMASK(11, 8) #define DEV2G5_PCS_FX100_STATUS_EDGE_POS_PTP_SET(x)\ @@ -3337,9 +3654,9 @@ enum sparx5_target { #define DEV2G5_PCS_FX100_STATUS_SYNC_STATUS_GET(x)\ FIELD_GET(DEV2G5_PCS_FX100_STATUS_SYNC_STATUS, x) -/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */ -#define DEV5G_MAC_ENA_CFG(t) __REG(TARGET_DEV5G,\ - t, 13, 0, 0, 1, 60, 0, 0, 1, 4) +/* DEV10G:MAC_CFG_STATUS:MAC_ENA_CFG */ +#define DEV5G_MAC_ENA_CFG(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 0, 0, 1, 60, 0, 0, 1, 4) #define DEV5G_MAC_ENA_CFG_RX_ENA BIT(4) #define DEV5G_MAC_ENA_CFG_RX_ENA_SET(x)\ @@ -3353,9 +3670,9 @@ enum sparx5_target { #define DEV5G_MAC_ENA_CFG_TX_ENA_GET(x)\ FIELD_GET(DEV5G_MAC_ENA_CFG_TX_ENA, x) -/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */ -#define DEV5G_MAC_MAXLEN_CFG(t) __REG(TARGET_DEV5G,\ - t, 13, 0, 0, 1, 60, 8, 0, 1, 4) +/* DEV10G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */ +#define DEV5G_MAC_MAXLEN_CFG(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 0, 0, 1, 60, 8, 0, 1, 4) #define DEV5G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK BIT(16) #define DEV5G_MAC_MAXLEN_CFG_MAX_LEN_TAG_CHK_SET(x)\ @@ -3369,9 +3686,10 @@ enum sparx5_target { #define DEV5G_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\ FIELD_GET(DEV5G_MAC_MAXLEN_CFG_MAX_LEN, x) -/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */ -#define DEV5G_MAC_ADV_CHK_CFG(t) __REG(TARGET_DEV5G,\ - t, 13, 0, 0, 1, 60, 28, 0, 1, 4) +/* DEV10G:MAC_CFG_STATUS:MAC_ADV_CHK_CFG */ +#define DEV5G_MAC_ADV_CHK_CFG(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 0, 0, 1, 60, 28, 0, 1, \ + 4) #define DEV5G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA BIT(24) #define DEV5G_MAC_ADV_CHK_CFG_EXT_EOP_CHK_ENA_SET(x)\ @@ -3415,325 +3733,405 @@ enum sparx5_target { #define DEV5G_MAC_ADV_CHK_CFG_INR_ERR_ENA_GET(x)\ FIELD_GET(DEV5G_MAC_ADV_CHK_CFG_INR_ERR_ENA, x) -/* DEV10G:DEV_STATISTICS_32BIT:RX_SYMBOL_ERR_CNT */ -#define DEV5G_RX_SYMBOL_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 0, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_PAUSE_CNT */ -#define DEV5G_RX_PAUSE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 4, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_UNSUP_OPCODE_CNT */ -#define DEV5G_RX_UNSUP_OPCODE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 8, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_UC_CNT */ -#define DEV5G_RX_UC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 12, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_MC_CNT */ -#define DEV5G_RX_MC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 16, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_BC_CNT */ -#define DEV5G_RX_BC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 20, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_CRC_ERR_CNT */ -#define DEV5G_RX_CRC_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 24, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_UNDERSIZE_CNT */ -#define DEV5G_RX_UNDERSIZE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 28, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_FRAGMENTS_CNT */ -#define DEV5G_RX_FRAGMENTS_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 32, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_IN_RANGE_LEN_ERR_CNT */ -#define DEV5G_RX_IN_RANGE_LEN_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 36, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_OUT_OF_RANGE_LEN_ERR_CNT */ -#define DEV5G_RX_OUT_OF_RANGE_LEN_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 40, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_OVERSIZE_CNT */ -#define DEV5G_RX_OVERSIZE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 44, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_JABBERS_CNT */ -#define DEV5G_RX_JABBERS_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 48, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE64_CNT */ -#define DEV5G_RX_SIZE64_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 52, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE65TO127_CNT */ -#define DEV5G_RX_SIZE65TO127_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 56, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE128TO255_CNT */ -#define DEV5G_RX_SIZE128TO255_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 60, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE256TO511_CNT */ -#define DEV5G_RX_SIZE256TO511_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 64, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE512TO1023_CNT */ -#define DEV5G_RX_SIZE512TO1023_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 68, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE1024TO1518_CNT */ -#define DEV5G_RX_SIZE1024TO1518_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 72, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE1519TOMAX_CNT */ -#define DEV5G_RX_SIZE1519TOMAX_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 76, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_IPG_SHRINK_CNT */ -#define DEV5G_RX_IPG_SHRINK_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 80, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_PAUSE_CNT */ -#define DEV5G_TX_PAUSE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 84, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_UC_CNT */ -#define DEV5G_TX_UC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 88, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_MC_CNT */ -#define DEV5G_TX_MC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 92, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_BC_CNT */ -#define DEV5G_TX_BC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 96, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE64_CNT */ -#define DEV5G_TX_SIZE64_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 100, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE65TO127_CNT */ -#define DEV5G_TX_SIZE65TO127_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 104, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE128TO255_CNT */ -#define DEV5G_TX_SIZE128TO255_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 108, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE256TO511_CNT */ -#define DEV5G_TX_SIZE256TO511_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 112, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE512TO1023_CNT */ -#define DEV5G_TX_SIZE512TO1023_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 116, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE1024TO1518_CNT */ -#define DEV5G_TX_SIZE1024TO1518_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 120, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE1519TOMAX_CNT */ -#define DEV5G_TX_SIZE1519TOMAX_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 124, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_ALIGNMENT_LOST_CNT */ -#define DEV5G_RX_ALIGNMENT_LOST_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 128, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_TAGGED_FRMS_CNT */ -#define DEV5G_RX_TAGGED_FRMS_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 132, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_UNTAGGED_FRMS_CNT */ -#define DEV5G_RX_UNTAGGED_FRMS_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 136, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_TAGGED_FRMS_CNT */ -#define DEV5G_TX_TAGGED_FRMS_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 140, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:TX_UNTAGGED_FRMS_CNT */ -#define DEV5G_TX_UNTAGGED_FRMS_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 144, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SYMBOL_ERR_CNT */ -#define DEV5G_PMAC_RX_SYMBOL_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 148, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_PAUSE_CNT */ -#define DEV5G_PMAC_RX_PAUSE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 152, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UNSUP_OPCODE_CNT */ -#define DEV5G_PMAC_RX_UNSUP_OPCODE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 156, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UC_CNT */ -#define DEV5G_PMAC_RX_UC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 160, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_MC_CNT */ -#define DEV5G_PMAC_RX_MC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 164, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_BC_CNT */ -#define DEV5G_PMAC_RX_BC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 168, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_CRC_ERR_CNT */ -#define DEV5G_PMAC_RX_CRC_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 172, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UNDERSIZE_CNT */ -#define DEV5G_PMAC_RX_UNDERSIZE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 176, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_FRAGMENTS_CNT */ -#define DEV5G_PMAC_RX_FRAGMENTS_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 180, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_IN_RANGE_LEN_ERR_CNT */ -#define DEV5G_PMAC_RX_IN_RANGE_LEN_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 184, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT */ -#define DEV5G_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 188, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_OVERSIZE_CNT */ -#define DEV5G_PMAC_RX_OVERSIZE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 192, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_JABBERS_CNT */ -#define DEV5G_PMAC_RX_JABBERS_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 196, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE64_CNT */ -#define DEV5G_PMAC_RX_SIZE64_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 200, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE65TO127_CNT */ -#define DEV5G_PMAC_RX_SIZE65TO127_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 204, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE128TO255_CNT */ -#define DEV5G_PMAC_RX_SIZE128TO255_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 208, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE256TO511_CNT */ -#define DEV5G_PMAC_RX_SIZE256TO511_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 212, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE512TO1023_CNT */ -#define DEV5G_PMAC_RX_SIZE512TO1023_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 216, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE1024TO1518_CNT */ -#define DEV5G_PMAC_RX_SIZE1024TO1518_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 220, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE1519TOMAX_CNT */ -#define DEV5G_PMAC_RX_SIZE1519TOMAX_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 224, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_PAUSE_CNT */ -#define DEV5G_PMAC_TX_PAUSE_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 228, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_UC_CNT */ -#define DEV5G_PMAC_TX_UC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 232, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_MC_CNT */ -#define DEV5G_PMAC_TX_MC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 236, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_BC_CNT */ -#define DEV5G_PMAC_TX_BC_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 240, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE64_CNT */ -#define DEV5G_PMAC_TX_SIZE64_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 244, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE65TO127_CNT */ -#define DEV5G_PMAC_TX_SIZE65TO127_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 248, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE128TO255_CNT */ -#define DEV5G_PMAC_TX_SIZE128TO255_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 252, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE256TO511_CNT */ -#define DEV5G_PMAC_TX_SIZE256TO511_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 256, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE512TO1023_CNT */ -#define DEV5G_PMAC_TX_SIZE512TO1023_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 260, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE1024TO1518_CNT */ -#define DEV5G_PMAC_TX_SIZE1024TO1518_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 264, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE1519TOMAX_CNT */ -#define DEV5G_PMAC_TX_SIZE1519TOMAX_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 268, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_ALIGNMENT_LOST_CNT */ -#define DEV5G_PMAC_RX_ALIGNMENT_LOST_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 272, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_ASSEMBLY_ERR_CNT */ -#define DEV5G_MM_RX_ASSEMBLY_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 276, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_SMD_ERR_CNT */ -#define DEV5G_MM_RX_SMD_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 280, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_ASSEMBLY_OK_CNT */ -#define DEV5G_MM_RX_ASSEMBLY_OK_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 284, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_MERGE_FRAG_CNT */ -#define DEV5G_MM_RX_MERGE_FRAG_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 288, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:MM_TX_PFRAGMENT_CNT */ -#define DEV5G_MM_TX_PFRAGMENT_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 292, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_HIH_CKSM_ERR_CNT */ -#define DEV5G_RX_HIH_CKSM_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 296, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:RX_XGMII_PROT_ERR_CNT */ -#define DEV5G_RX_XGMII_PROT_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 300, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_HIH_CKSM_ERR_CNT */ -#define DEV5G_PMAC_RX_HIH_CKSM_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 304, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_XGMII_PROT_ERR_CNT */ -#define DEV5G_PMAC_RX_XGMII_PROT_ERR_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 60, 0, 1, 312, 308, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_40BIT:RX_IN_BYTES_CNT */ -#define DEV5G_RX_IN_BYTES_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 0, 0, 1, 4) - -/* DEV10G:DEV_STATISTICS_40BIT:RX_IN_BYTES_MSB_CNT */ -#define DEV5G_RX_IN_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 4, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_32BIT:RX_SYMBOL_ERR_CNT */ +#define DEV5G_RX_SYMBOL_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 0, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_PAUSE_CNT */ +#define DEV5G_RX_PAUSE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 4, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_UNSUP_OPCODE_CNT */ +#define DEV5G_RX_UNSUP_OPCODE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 8, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_UC_CNT */ +#define DEV5G_RX_UC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 12, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_MC_CNT */ +#define DEV5G_RX_MC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 16, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_BC_CNT */ +#define DEV5G_RX_BC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 20, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_CRC_ERR_CNT */ +#define DEV5G_RX_CRC_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 24, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_UNDERSIZE_CNT */ +#define DEV5G_RX_UNDERSIZE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 28, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_FRAGMENTS_CNT */ +#define DEV5G_RX_FRAGMENTS_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 32, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_IN_RANGE_LEN_ERR_CNT */ +#define DEV5G_RX_IN_RANGE_LEN_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 36, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_OUT_OF_RANGE_LEN_ERR_CNT */ +#define DEV5G_RX_OUT_OF_RANGE_LEN_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 40, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_OVERSIZE_CNT */ +#define DEV5G_RX_OVERSIZE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 44, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_JABBERS_CNT */ +#define DEV5G_RX_JABBERS_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 48, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE64_CNT */ +#define DEV5G_RX_SIZE64_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 52, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE65TO127_CNT */ +#define DEV5G_RX_SIZE65TO127_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 56, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE128TO255_CNT */ +#define DEV5G_RX_SIZE128TO255_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 60, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE256TO511_CNT */ +#define DEV5G_RX_SIZE256TO511_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 64, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE512TO1023_CNT */ +#define DEV5G_RX_SIZE512TO1023_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 68, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE1024TO1518_CNT */ +#define DEV5G_RX_SIZE1024TO1518_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 72, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_SIZE1519TOMAX_CNT */ +#define DEV5G_RX_SIZE1519TOMAX_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 76, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_IPG_SHRINK_CNT */ +#define DEV5G_RX_IPG_SHRINK_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 80, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_PAUSE_CNT */ +#define DEV5G_TX_PAUSE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 84, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_UC_CNT */ +#define DEV5G_TX_UC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 88, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_MC_CNT */ +#define DEV5G_TX_MC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 92, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_BC_CNT */ +#define DEV5G_TX_BC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 96, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE64_CNT */ +#define DEV5G_TX_SIZE64_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 100, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE65TO127_CNT */ +#define DEV5G_TX_SIZE65TO127_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 104, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE128TO255_CNT */ +#define DEV5G_TX_SIZE128TO255_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 108, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE256TO511_CNT */ +#define DEV5G_TX_SIZE256TO511_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 112, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE512TO1023_CNT */ +#define DEV5G_TX_SIZE512TO1023_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 116, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE1024TO1518_CNT */ +#define DEV5G_TX_SIZE1024TO1518_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 120, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_SIZE1519TOMAX_CNT */ +#define DEV5G_TX_SIZE1519TOMAX_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 124, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_ALIGNMENT_LOST_CNT */ +#define DEV5G_RX_ALIGNMENT_LOST_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 128, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_TAGGED_FRMS_CNT */ +#define DEV5G_RX_TAGGED_FRMS_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 132, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_UNTAGGED_FRMS_CNT */ +#define DEV5G_RX_UNTAGGED_FRMS_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 136, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_TAGGED_FRMS_CNT */ +#define DEV5G_TX_TAGGED_FRMS_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 140, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:TX_UNTAGGED_FRMS_CNT */ +#define DEV5G_TX_UNTAGGED_FRMS_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 144, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SYMBOL_ERR_CNT */ +#define DEV5G_PMAC_RX_SYMBOL_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 148, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_PAUSE_CNT */ +#define DEV5G_PMAC_RX_PAUSE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 152, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UNSUP_OPCODE_CNT */ +#define DEV5G_PMAC_RX_UNSUP_OPCODE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 156, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UC_CNT */ +#define DEV5G_PMAC_RX_UC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 160, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_MC_CNT */ +#define DEV5G_PMAC_RX_MC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 164, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_BC_CNT */ +#define DEV5G_PMAC_RX_BC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 168, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_CRC_ERR_CNT */ +#define DEV5G_PMAC_RX_CRC_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 172, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_UNDERSIZE_CNT */ +#define DEV5G_PMAC_RX_UNDERSIZE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 176, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_FRAGMENTS_CNT */ +#define DEV5G_PMAC_RX_FRAGMENTS_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 180, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_IN_RANGE_LEN_ERR_CNT */ +#define DEV5G_PMAC_RX_IN_RANGE_LEN_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 184, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT */ +#define DEV5G_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 188, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_OVERSIZE_CNT */ +#define DEV5G_PMAC_RX_OVERSIZE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 192, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_JABBERS_CNT */ +#define DEV5G_PMAC_RX_JABBERS_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 196, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE64_CNT */ +#define DEV5G_PMAC_RX_SIZE64_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 200, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE65TO127_CNT */ +#define DEV5G_PMAC_RX_SIZE65TO127_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 204, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE128TO255_CNT */ +#define DEV5G_PMAC_RX_SIZE128TO255_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 208, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE256TO511_CNT */ +#define DEV5G_PMAC_RX_SIZE256TO511_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 212, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE512TO1023_CNT */ +#define DEV5G_PMAC_RX_SIZE512TO1023_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 216, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE1024TO1518_CNT */ +#define DEV5G_PMAC_RX_SIZE1024TO1518_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 220, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_SIZE1519TOMAX_CNT */ +#define DEV5G_PMAC_RX_SIZE1519TOMAX_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 224, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_PAUSE_CNT */ +#define DEV5G_PMAC_TX_PAUSE_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 228, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_UC_CNT */ +#define DEV5G_PMAC_TX_UC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 232, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_MC_CNT */ +#define DEV5G_PMAC_TX_MC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 236, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_BC_CNT */ +#define DEV5G_PMAC_TX_BC_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 240, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE64_CNT */ +#define DEV5G_PMAC_TX_SIZE64_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 244, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE65TO127_CNT */ +#define DEV5G_PMAC_TX_SIZE65TO127_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 248, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE128TO255_CNT */ +#define DEV5G_PMAC_TX_SIZE128TO255_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 252, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE256TO511_CNT */ +#define DEV5G_PMAC_TX_SIZE256TO511_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 256, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE512TO1023_CNT */ +#define DEV5G_PMAC_TX_SIZE512TO1023_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 260, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE1024TO1518_CNT */ +#define DEV5G_PMAC_TX_SIZE1024TO1518_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 264, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_TX_SIZE1519TOMAX_CNT */ +#define DEV5G_PMAC_TX_SIZE1519TOMAX_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 268, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_ALIGNMENT_LOST_CNT */ +#define DEV5G_PMAC_RX_ALIGNMENT_LOST_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 272, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_ASSEMBLY_ERR_CNT */ +#define DEV5G_MM_RX_ASSEMBLY_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 276, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_SMD_ERR_CNT */ +#define DEV5G_MM_RX_SMD_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 280, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_ASSEMBLY_OK_CNT */ +#define DEV5G_MM_RX_ASSEMBLY_OK_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 284, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:MM_RX_MERGE_FRAG_CNT */ +#define DEV5G_MM_RX_MERGE_FRAG_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 288, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:MM_TX_PFRAGMENT_CNT */ +#define DEV5G_MM_TX_PFRAGMENT_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 292, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_HIH_CKSM_ERR_CNT */ +#define DEV5G_RX_HIH_CKSM_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 296, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:RX_XGMII_PROT_ERR_CNT */ +#define DEV5G_RX_XGMII_PROT_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 300, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_HIH_CKSM_ERR_CNT */ +#define DEV5G_PMAC_RX_HIH_CKSM_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 304, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_32BIT:PMAC_RX_XGMII_PROT_ERR_CNT */ +#define DEV5G_PMAC_RX_XGMII_PROT_ERR_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 60, 0, 1, 312, 308, 0, 1,\ + 4) + +/* DEV10G:DEV_STATISTICS_40BIT:RX_IN_BYTES_CNT */ +#define DEV5G_RX_IN_BYTES_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 0, 0, 1, \ + 4) + +/* DEV10G:DEV_STATISTICS_40BIT:RX_IN_BYTES_MSB_CNT */ +#define DEV5G_RX_IN_BYTES_MSB_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 4, 0, 1, \ + 4) #define DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT GENMASK(7, 0) #define DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT_SET(x)\ @@ -3741,13 +4139,15 @@ enum sparx5_target { #define DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT_GET(x)\ FIELD_GET(DEV5G_RX_IN_BYTES_MSB_CNT_RX_IN_BYTES_MSB_CNT, x) -/* DEV10G:DEV_STATISTICS_40BIT:RX_OK_BYTES_CNT */ -#define DEV5G_RX_OK_BYTES_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 8, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:RX_OK_BYTES_CNT */ +#define DEV5G_RX_OK_BYTES_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 8, 0, 1, \ + 4) -/* DEV10G:DEV_STATISTICS_40BIT:RX_OK_BYTES_MSB_CNT */ -#define DEV5G_RX_OK_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 12, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:RX_OK_BYTES_MSB_CNT */ +#define DEV5G_RX_OK_BYTES_MSB_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 12, 0, 1, \ + 4) #define DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT GENMASK(7, 0) #define DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT_SET(x)\ @@ -3755,13 +4155,15 @@ enum sparx5_target { #define DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT_GET(x)\ FIELD_GET(DEV5G_RX_OK_BYTES_MSB_CNT_RX_OK_BYTES_MSB_CNT, x) -/* DEV10G:DEV_STATISTICS_40BIT:RX_BAD_BYTES_CNT */ -#define DEV5G_RX_BAD_BYTES_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 16, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:RX_BAD_BYTES_CNT */ +#define DEV5G_RX_BAD_BYTES_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 16, 0, 1, \ + 4) -/* DEV10G:DEV_STATISTICS_40BIT:RX_BAD_BYTES_MSB_CNT */ -#define DEV5G_RX_BAD_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 20, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:RX_BAD_BYTES_MSB_CNT */ +#define DEV5G_RX_BAD_BYTES_MSB_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 20, 0, 1, \ + 4) #define DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT GENMASK(7, 0) #define DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT_SET(x)\ @@ -3769,13 +4171,15 @@ enum sparx5_target { #define DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT_GET(x)\ FIELD_GET(DEV5G_RX_BAD_BYTES_MSB_CNT_RX_BAD_BYTES_MSB_CNT, x) -/* DEV10G:DEV_STATISTICS_40BIT:TX_OUT_BYTES_CNT */ -#define DEV5G_TX_OUT_BYTES_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 24, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:TX_OUT_BYTES_CNT */ +#define DEV5G_TX_OUT_BYTES_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 24, 0, 1, \ + 4) -/* DEV10G:DEV_STATISTICS_40BIT:TX_OUT_BYTES_MSB_CNT */ -#define DEV5G_TX_OUT_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 28, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:TX_OUT_BYTES_MSB_CNT */ +#define DEV5G_TX_OUT_BYTES_MSB_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 28, 0, 1, \ + 4) #define DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT GENMASK(7, 0) #define DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT_SET(x)\ @@ -3783,13 +4187,15 @@ enum sparx5_target { #define DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT_GET(x)\ FIELD_GET(DEV5G_TX_OUT_BYTES_MSB_CNT_TX_OUT_BYTES_MSB_CNT, x) -/* DEV10G:DEV_STATISTICS_40BIT:TX_OK_BYTES_CNT */ -#define DEV5G_TX_OK_BYTES_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 32, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:TX_OK_BYTES_CNT */ +#define DEV5G_TX_OK_BYTES_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 32, 0, 1, \ + 4) -/* DEV10G:DEV_STATISTICS_40BIT:TX_OK_BYTES_MSB_CNT */ -#define DEV5G_TX_OK_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 36, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:TX_OK_BYTES_MSB_CNT */ +#define DEV5G_TX_OK_BYTES_MSB_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 36, 0, 1, \ + 4) #define DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT GENMASK(7, 0) #define DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT_SET(x)\ @@ -3797,13 +4203,15 @@ enum sparx5_target { #define DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT_GET(x)\ FIELD_GET(DEV5G_TX_OK_BYTES_MSB_CNT_TX_OK_BYTES_MSB_CNT, x) -/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_OK_BYTES_CNT */ -#define DEV5G_PMAC_RX_OK_BYTES_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 40, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_OK_BYTES_CNT */ +#define DEV5G_PMAC_RX_OK_BYTES_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 40, 0, 1, \ + 4) -/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_OK_BYTES_MSB_CNT */ -#define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 44, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_OK_BYTES_MSB_CNT */ +#define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 44, 0, 1, \ + 4) #define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT GENMASK(7, 0) #define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT_SET(x)\ @@ -3811,13 +4219,15 @@ enum sparx5_target { #define DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT_GET(x)\ FIELD_GET(DEV5G_PMAC_RX_OK_BYTES_MSB_CNT_PMAC_RX_OK_BYTES_MSB_CNT, x) -/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_BAD_BYTES_CNT */ -#define DEV5G_PMAC_RX_BAD_BYTES_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 48, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_BAD_BYTES_CNT */ +#define DEV5G_PMAC_RX_BAD_BYTES_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 48, 0, 1, \ + 4) -/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_BAD_BYTES_MSB_CNT */ -#define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 52, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:PMAC_RX_BAD_BYTES_MSB_CNT */ +#define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 52, 0, 1, \ + 4) #define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT GENMASK(7, 0) #define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT_SET(x)\ @@ -3825,13 +4235,15 @@ enum sparx5_target { #define DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT_GET(x)\ FIELD_GET(DEV5G_PMAC_RX_BAD_BYTES_MSB_CNT_PMAC_RX_BAD_BYTES_MSB_CNT, x) -/* DEV10G:DEV_STATISTICS_40BIT:PMAC_TX_OK_BYTES_CNT */ -#define DEV5G_PMAC_TX_OK_BYTES_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 56, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:PMAC_TX_OK_BYTES_CNT */ +#define DEV5G_PMAC_TX_OK_BYTES_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 56, 0, 1, \ + 4) -/* DEV10G:DEV_STATISTICS_40BIT:PMAC_TX_OK_BYTES_MSB_CNT */ -#define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT(t) __REG(TARGET_DEV5G,\ - t, 13, 372, 0, 1, 64, 60, 0, 1, 4) +/* DEV10G:DEV_STATISTICS_40BIT:PMAC_TX_OK_BYTES_MSB_CNT */ +#define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 372, 0, 1, 64, 60, 0, 1, \ + 4) #define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT GENMASK(7, 0) #define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT_SET(x)\ @@ -3839,9 +4251,10 @@ enum sparx5_target { #define DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT_GET(x)\ FIELD_GET(DEV5G_PMAC_TX_OK_BYTES_MSB_CNT_PMAC_TX_OK_BYTES_MSB_CNT, x) -/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */ -#define DEV5G_DEV_RST_CTRL(t) __REG(TARGET_DEV5G,\ - t, 13, 436, 0, 1, 52, 0, 0, 1, 4) +/* DEV10G:DEV_CFG_STATUS:DEV_RST_CTRL */ +#define DEV5G_DEV_RST_CTRL(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 436, 0, 1, 52, 0, 0, 1, \ + 4) #define DEV5G_DEV_RST_CTRL_PARDET_MODE_ENA BIT(28) #define DEV5G_DEV_RST_CTRL_PARDET_MODE_ENA_SET(x)\ @@ -3897,9 +4310,14 @@ enum sparx5_target { #define DEV5G_DEV_RST_CTRL_MAC_RX_RST_GET(x)\ FIELD_GET(DEV5G_DEV_RST_CTRL_MAC_RX_RST, x) -/* DSM:RAM_CTRL:RAM_INIT */ -#define DSM_RAM_INIT __REG(TARGET_DSM,\ - 0, 1, 0, 0, 1, 4, 0, 0, 1, 4) +/* DEV10G:DEV_CFG_STATUS:PTP_STAMPER_CFG */ +#define DEV5G_PTP_STAMPER_CFG(t) \ + __REG(TARGET_DEV5G, t, regs->tsize[TC_DEV5G], 436, 0, 1, 52, 20, 0, 1, \ + 4) + +/* DSM:RAM_CTRL:RAM_INIT */ +#define DSM_RAM_INIT \ + __REG(TARGET_DSM, 0, 1, 0, 0, 1, 4, 0, 0, 1, 4) #define DSM_RAM_INIT_RAM_INIT BIT(1) #define DSM_RAM_INIT_RAM_INIT_SET(x)\ @@ -3913,9 +4331,10 @@ enum sparx5_target { #define DSM_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(DSM_RAM_INIT_RAM_CFG_HOOK, x) -/* DSM:CFG:BUF_CFG */ -#define DSM_BUF_CFG(r) __REG(TARGET_DSM,\ - 0, 1, 20, 0, 1, 3528, 0, r, 67, 4) +/* DSM:CFG:BUF_CFG */ +#define DSM_BUF_CFG(r) \ + __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 0, r, \ + regs->rcnt[RC_DSM_BUF_CFG], 4) #define DSM_BUF_CFG_CSC_STAT_DIS BIT(13) #define DSM_BUF_CFG_CSC_STAT_DIS_SET(x)\ @@ -3941,9 +4360,10 @@ enum sparx5_target { #define DSM_BUF_CFG_UNDERFLOW_WATCHDOG_TIMEOUT_GET(x)\ FIELD_GET(DSM_BUF_CFG_UNDERFLOW_WATCHDOG_TIMEOUT, x) -/* DSM:CFG:DEV_TX_STOP_WM_CFG */ -#define DSM_DEV_TX_STOP_WM_CFG(r) __REG(TARGET_DSM,\ - 0, 1, 20, 0, 1, 3528, 1360, r, 67, 4) +/* DSM:CFG:DEV_TX_STOP_WM_CFG */ +#define DSM_DEV_TX_STOP_WM_CFG(r) \ + __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 1360, r, \ + regs->rcnt[RC_DSM_DEV_TX_STOP_WM_CFG], 4) #define DSM_DEV_TX_STOP_WM_CFG_FAST_STARTUP_ENA BIT(9) #define DSM_DEV_TX_STOP_WM_CFG_FAST_STARTUP_ENA_SET(x)\ @@ -3969,9 +4389,10 @@ enum sparx5_target { #define DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR_GET(x)\ FIELD_GET(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_CNT_CLR, x) -/* DSM:CFG:RX_PAUSE_CFG */ -#define DSM_RX_PAUSE_CFG(r) __REG(TARGET_DSM,\ - 0, 1, 20, 0, 1, 3528, 1628, r, 67, 4) +/* DSM:CFG:RX_PAUSE_CFG */ +#define DSM_RX_PAUSE_CFG(r) \ + __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 1628, r, \ + regs->rcnt[RC_DSM_RX_PAUSE_CFG], 4) #define DSM_RX_PAUSE_CFG_RX_PAUSE_EN BIT(1) #define DSM_RX_PAUSE_CFG_RX_PAUSE_EN_SET(x)\ @@ -3985,9 +4406,10 @@ enum sparx5_target { #define DSM_RX_PAUSE_CFG_FC_OBEY_LOCAL_GET(x)\ FIELD_GET(DSM_RX_PAUSE_CFG_FC_OBEY_LOCAL, x) -/* DSM:CFG:MAC_CFG */ -#define DSM_MAC_CFG(r) __REG(TARGET_DSM,\ - 0, 1, 20, 0, 1, 3528, 2432, r, 67, 4) +/* DSM:CFG:MAC_CFG */ +#define DSM_MAC_CFG(r) \ + __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 2432, r, \ + regs->rcnt[RC_DSM_MAC_CFG], 4) #define DSM_MAC_CFG_TX_PAUSE_VAL GENMASK(31, 16) #define DSM_MAC_CFG_TX_PAUSE_VAL_SET(x)\ @@ -4013,9 +4435,10 @@ enum sparx5_target { #define DSM_MAC_CFG_TX_PAUSE_XON_XOFF_GET(x)\ FIELD_GET(DSM_MAC_CFG_TX_PAUSE_XON_XOFF, x) -/* DSM:CFG:MAC_ADDR_BASE_HIGH_CFG */ -#define DSM_MAC_ADDR_BASE_HIGH_CFG(r) __REG(TARGET_DSM,\ - 0, 1, 20, 0, 1, 3528, 2700, r, 65, 4) +/* DSM:CFG:MAC_ADDR_BASE_HIGH_CFG */ +#define DSM_MAC_ADDR_BASE_HIGH_CFG(r) \ + __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 2700, r, \ + regs->rcnt[RC_DSM_MAC_ADDR_BASE_HIGH_CFG], 4) #define DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH GENMASK(23, 0) #define DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH_SET(x)\ @@ -4023,9 +4446,10 @@ enum sparx5_target { #define DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH_GET(x)\ FIELD_GET(DSM_MAC_ADDR_BASE_HIGH_CFG_MAC_ADDR_HIGH, x) -/* DSM:CFG:MAC_ADDR_BASE_LOW_CFG */ -#define DSM_MAC_ADDR_BASE_LOW_CFG(r) __REG(TARGET_DSM,\ - 0, 1, 20, 0, 1, 3528, 2960, r, 65, 4) +/* DSM:CFG:MAC_ADDR_BASE_LOW_CFG */ +#define DSM_MAC_ADDR_BASE_LOW_CFG(r) \ + __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 2960, r, \ + regs->rcnt[RC_DSM_MAC_ADDR_BASE_LOW_CFG], 4) #define DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW GENMASK(23, 0) #define DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW_SET(x)\ @@ -4033,9 +4457,10 @@ enum sparx5_target { #define DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW_GET(x)\ FIELD_GET(DSM_MAC_ADDR_BASE_LOW_CFG_MAC_ADDR_LOW, x) -/* DSM:CFG:TAXI_CAL_CFG */ -#define DSM_TAXI_CAL_CFG(r) __REG(TARGET_DSM,\ - 0, 1, 20, 0, 1, 3528, 3224, r, 9, 4) +/* DSM:CFG:TAXI_CAL_CFG */ +#define DSM_TAXI_CAL_CFG(r) \ + __REG(TARGET_DSM, 0, 1, 20, 0, 1, 3528, 3224, r, \ + regs->rcnt[RC_DSM_TAXI_CAL_CFG], 4) #define DSM_TAXI_CAL_CFG_CAL_IDX GENMASK(20, 15) #define DSM_TAXI_CAL_CFG_CAL_IDX_SET(x)\ @@ -4067,9 +4492,31 @@ enum sparx5_target { #define DSM_TAXI_CAL_CFG_CAL_PGM_ENA_GET(x)\ FIELD_GET(DSM_TAXI_CAL_CFG_CAL_PGM_ENA, x) -/* EACL:ES2_KEY_SELECT_PROFILE:VCAP_ES2_KEY_SEL */ -#define EACL_VCAP_ES2_KEY_SEL(g, r) __REG(TARGET_EACL,\ - 0, 1, 149504, g, 138, 8, 0, r, 2, 4) +/* LAN969X ONLY */ +#define DSM_TAXI_CAL_CFG_CAL_SEL_STAT BIT(23) +#define DSM_TAXI_CAL_CFG_CAL_SEL_STAT_SET(x)\ + FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_SEL_STAT, x) +#define DSM_TAXI_CAL_CFG_CAL_SEL_STAT_GET(x)\ + FIELD_GET(DSM_TAXI_CAL_CFG_CAL_SEL_STAT, x) + +/* LAN969X ONLY */ +#define DSM_TAXI_CAL_CFG_CAL_SWITCH BIT(22) +#define DSM_TAXI_CAL_CFG_CAL_SWITCH_SET(x)\ + FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_SWITCH, x) +#define DSM_TAXI_CAL_CFG_CAL_SWITCH_GET(x)\ + FIELD_GET(DSM_TAXI_CAL_CFG_CAL_SWITCH, x) + +/* LAN969X ONLY */ +#define DSM_TAXI_CAL_CFG_CAL_PGM_SEL BIT(21) +#define DSM_TAXI_CAL_CFG_CAL_PGM_SEL_SET(x)\ + FIELD_PREP(DSM_TAXI_CAL_CFG_CAL_PGM_SEL, x) +#define DSM_TAXI_CAL_CFG_CAL_PGM_SEL_GET(x)\ + FIELD_GET(DSM_TAXI_CAL_CFG_CAL_PGM_SEL, x) + +/* EACL:ES2_KEY_SELECT_PROFILE:VCAP_ES2_KEY_SEL */ +#define EACL_VCAP_ES2_KEY_SEL(g, r) \ + __REG(TARGET_EACL, 0, 1, regs->gaddr[GA_EACL_ES2_KEY_SELECT_PROFILE], \ + g, regs->gcnt[GC_EACL_ES2_KEY_SELECT_PROFILE], 8, 0, r, 2, 4) #define EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL GENMASK(7, 5) #define EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_SET(x)\ @@ -4095,13 +4542,15 @@ enum sparx5_target { #define EACL_VCAP_ES2_KEY_SEL_KEY_ENA_GET(x)\ FIELD_GET(EACL_VCAP_ES2_KEY_SEL_KEY_ENA, x) -/* EACL:CNT_TBL:ES2_CNT */ -#define EACL_ES2_CNT(g) __REG(TARGET_EACL,\ - 0, 1, 122880, g, 2048, 4, 0, 0, 1, 4) +/* EACL:CNT_TBL:ES2_CNT */ +#define EACL_ES2_CNT(g) \ + __REG(TARGET_EACL, 0, 1, regs->gaddr[GA_EACL_CNT_TBL], g, \ + regs->gcnt[GC_EACL_CNT_TBL], 4, 0, 0, 1, 4) -/* EACL:POL_CFG:POL_EACL_CFG */ -#define EACL_POL_EACL_CFG __REG(TARGET_EACL,\ - 0, 1, 150608, 0, 1, 780, 768, 0, 1, 4) +/* EACL:POL_CFG:POL_EACL_CFG */ +#define EACL_POL_EACL_CFG \ + __REG(TARGET_EACL, 0, 1, regs->gaddr[GA_EACL_POL_CFG], 0, 1, 780, 768, \ + 0, 1, 4) #define EACL_POL_EACL_CFG_EACL_CNT_MARKED_AS_DROPPED BIT(5) #define EACL_POL_EACL_CFG_EACL_CNT_MARKED_AS_DROPPED_SET(x)\ @@ -4139,9 +4588,10 @@ enum sparx5_target { #define EACL_POL_EACL_CFG_EACL_FORCE_INIT_GET(x)\ FIELD_GET(EACL_POL_EACL_CFG_EACL_FORCE_INIT, x) -/* EACL:ES2_STICKY:SEC_LOOKUP_STICKY */ -#define EACL_SEC_LOOKUP_STICKY(r) __REG(TARGET_EACL,\ - 0, 1, 118696, 0, 1, 8, 0, r, 2, 4) +/* EACL:ES2_STICKY:SEC_LOOKUP_STICKY */ +#define EACL_SEC_LOOKUP_STICKY(r) \ + __REG(TARGET_EACL, 0, 1, regs->gaddr[GA_EACL_ES2_STICKY], 0, 1, 8, 0, \ + r, 2, 4) #define EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY BIT(7) #define EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_SET(x)\ @@ -4191,9 +4641,10 @@ enum sparx5_target { #define EACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(x)\ FIELD_GET(EACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY, x) -/* EACL:RAM_CTRL:RAM_INIT */ -#define EACL_RAM_INIT __REG(TARGET_EACL,\ - 0, 1, 118736, 0, 1, 4, 0, 0, 1, 4) +/* EACL:RAM_CTRL:RAM_INIT */ +#define EACL_RAM_INIT \ + __REG(TARGET_EACL, 0, 1, regs->gaddr[GA_EACL_RAM_CTRL], 0, 1, 4, 0, 0, \ + 1, 4) #define EACL_RAM_INIT_RAM_INIT BIT(1) #define EACL_RAM_INIT_RAM_INIT_SET(x)\ @@ -4207,9 +4658,10 @@ enum sparx5_target { #define EACL_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(EACL_RAM_INIT_RAM_CFG_HOOK, x) -/* FDMA:FDMA:FDMA_CH_ACTIVATE */ -#define FDMA_CH_ACTIVATE __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 0, 0, 1, 4) +/* FDMA:FDMA:FDMA_CH_ACTIVATE */ +#define FDMA_CH_ACTIVATE \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 0, 0, 1, \ + 4) #define FDMA_CH_ACTIVATE_CH_ACTIVATE GENMASK(7, 0) #define FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(x)\ @@ -4217,9 +4669,10 @@ enum sparx5_target { #define FDMA_CH_ACTIVATE_CH_ACTIVATE_GET(x)\ FIELD_GET(FDMA_CH_ACTIVATE_CH_ACTIVATE, x) -/* FDMA:FDMA:FDMA_CH_RELOAD */ -#define FDMA_CH_RELOAD __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 4, 0, 1, 4) +/* FDMA:FDMA:FDMA_CH_RELOAD */ +#define FDMA_CH_RELOAD \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 4, 0, 1, \ + 4) #define FDMA_CH_RELOAD_CH_RELOAD GENMASK(7, 0) #define FDMA_CH_RELOAD_CH_RELOAD_SET(x)\ @@ -4227,9 +4680,10 @@ enum sparx5_target { #define FDMA_CH_RELOAD_CH_RELOAD_GET(x)\ FIELD_GET(FDMA_CH_RELOAD_CH_RELOAD, x) -/* FDMA:FDMA:FDMA_CH_DISABLE */ -#define FDMA_CH_DISABLE __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 8, 0, 1, 4) +/* FDMA:FDMA:FDMA_CH_DISABLE */ +#define FDMA_CH_DISABLE \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 8, 0, 1, \ + 4) #define FDMA_CH_DISABLE_CH_DISABLE GENMASK(7, 0) #define FDMA_CH_DISABLE_CH_DISABLE_SET(x)\ @@ -4237,49 +4691,58 @@ enum sparx5_target { #define FDMA_CH_DISABLE_CH_DISABLE_GET(x)\ FIELD_GET(FDMA_CH_DISABLE_CH_DISABLE, x) -/* FDMA:FDMA:FDMA_DCB_LLP */ -#define FDMA_DCB_LLP(r) __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 52, r, 8, 4) - -/* FDMA:FDMA:FDMA_DCB_LLP1 */ -#define FDMA_DCB_LLP1(r) __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 84, r, 8, 4) - -/* FDMA:FDMA:FDMA_DCB_LLP_PREV */ -#define FDMA_DCB_LLP_PREV(r) __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 116, r, 8, 4) - -/* FDMA:FDMA:FDMA_DCB_LLP_PREV1 */ -#define FDMA_DCB_LLP_PREV1(r) __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 148, r, 8, 4) - -/* FDMA:FDMA:FDMA_CH_CFG */ -#define FDMA_CH_CFG(r) __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 224, r, 8, 4) - -#define FDMA_CH_CFG_CH_XTR_STATUS_MODE BIT(7) +/* FDMA:FDMA:FDMA_DCB_LLP */ +#define FDMA_DCB_LLP(r) \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 52, r, 8, \ + 4) + +/* FDMA:FDMA:FDMA_DCB_LLP1 */ +#define FDMA_DCB_LLP1(r) \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 84, r, 8, \ + 4) + +/* FDMA:FDMA:FDMA_DCB_LLP_PREV */ +#define FDMA_DCB_LLP_PREV(r) \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 116, r, 8,\ + 4) + +/* FDMA:FDMA:FDMA_DCB_LLP_PREV1 */ +#define FDMA_DCB_LLP_PREV1(r) \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 148, r, 8,\ + 4) + +/* FDMA:FDMA:FDMA_CH_CFG */ +#define FDMA_CH_CFG(r) \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 224, r, 8,\ + 4) + +#define FDMA_CH_CFG_CH_XTR_STATUS_MODE\ + BIT(regs->fpos[FP_FDMA_CH_CFG_CH_XTR_STATUS_MODE]) #define FDMA_CH_CFG_CH_XTR_STATUS_MODE_SET(x)\ - FIELD_PREP(FDMA_CH_CFG_CH_XTR_STATUS_MODE, x) + spx5_field_prep(FDMA_CH_CFG_CH_XTR_STATUS_MODE, x) #define FDMA_CH_CFG_CH_XTR_STATUS_MODE_GET(x)\ - FIELD_GET(FDMA_CH_CFG_CH_XTR_STATUS_MODE, x) + spx5_field_get(FDMA_CH_CFG_CH_XTR_STATUS_MODE, x) -#define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY BIT(6) +#define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY\ + BIT(regs->fpos[FP_FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY]) #define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(x)\ - FIELD_PREP(FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, x) + spx5_field_prep(FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, x) #define FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_GET(x)\ - FIELD_GET(FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, x) + spx5_field_get(FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, x) -#define FDMA_CH_CFG_CH_INJ_PORT BIT(5) +#define FDMA_CH_CFG_CH_INJ_PORT\ + BIT(regs->fpos[FP_FDMA_CH_CFG_CH_INJ_PORT]) #define FDMA_CH_CFG_CH_INJ_PORT_SET(x)\ - FIELD_PREP(FDMA_CH_CFG_CH_INJ_PORT, x) + spx5_field_prep(FDMA_CH_CFG_CH_INJ_PORT, x) #define FDMA_CH_CFG_CH_INJ_PORT_GET(x)\ - FIELD_GET(FDMA_CH_CFG_CH_INJ_PORT, x) + spx5_field_get(FDMA_CH_CFG_CH_INJ_PORT, x) -#define FDMA_CH_CFG_CH_DCB_DB_CNT GENMASK(4, 1) +#define FDMA_CH_CFG_CH_DCB_DB_CNT\ + GENMASK(regs->fsize[FW_FDMA_CH_CFG_CH_DCB_DB_CNT] + 1 - 1, 1) #define FDMA_CH_CFG_CH_DCB_DB_CNT_SET(x)\ - FIELD_PREP(FDMA_CH_CFG_CH_DCB_DB_CNT, x) + spx5_field_prep(FDMA_CH_CFG_CH_DCB_DB_CNT, x) #define FDMA_CH_CFG_CH_DCB_DB_CNT_GET(x)\ - FIELD_GET(FDMA_CH_CFG_CH_DCB_DB_CNT, x) + spx5_field_get(FDMA_CH_CFG_CH_DCB_DB_CNT, x) #define FDMA_CH_CFG_CH_MEM BIT(0) #define FDMA_CH_CFG_CH_MEM_SET(x)\ @@ -4287,9 +4750,10 @@ enum sparx5_target { #define FDMA_CH_CFG_CH_MEM_GET(x)\ FIELD_GET(FDMA_CH_CFG_CH_MEM, x) -/* FDMA:FDMA:FDMA_CH_TRANSLATE */ -#define FDMA_CH_TRANSLATE(r) __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 256, r, 8, 4) +/* FDMA:FDMA:FDMA_CH_TRANSLATE */ +#define FDMA_CH_TRANSLATE(r) \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 256, r, 8,\ + 4) #define FDMA_CH_TRANSLATE_OFFSET GENMASK(15, 0) #define FDMA_CH_TRANSLATE_OFFSET_SET(x)\ @@ -4297,9 +4761,10 @@ enum sparx5_target { #define FDMA_CH_TRANSLATE_OFFSET_GET(x)\ FIELD_GET(FDMA_CH_TRANSLATE_OFFSET, x) -/* FDMA:FDMA:FDMA_XTR_CFG */ -#define FDMA_XTR_CFG __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 364, 0, 1, 4) +/* FDMA:FDMA:FDMA_XTR_CFG */ +#define FDMA_XTR_CFG \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 364, 0, 1,\ + 4) #define FDMA_XTR_CFG_XTR_FIFO_WM GENMASK(15, 11) #define FDMA_XTR_CFG_XTR_FIFO_WM_SET(x)\ @@ -4313,9 +4778,10 @@ enum sparx5_target { #define FDMA_XTR_CFG_XTR_ARB_SAT_GET(x)\ FIELD_GET(FDMA_XTR_CFG_XTR_ARB_SAT, x) -/* FDMA:FDMA:FDMA_PORT_CTRL */ -#define FDMA_PORT_CTRL(r) __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 376, r, 2, 4) +/* FDMA:FDMA:FDMA_PORT_CTRL */ +#define FDMA_PORT_CTRL(r) \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 376, r, 2,\ + 4) #define FDMA_PORT_CTRL_INJ_STOP BIT(4) #define FDMA_PORT_CTRL_INJ_STOP_SET(x)\ @@ -4347,9 +4813,10 @@ enum sparx5_target { #define FDMA_PORT_CTRL_XTR_BUF_RST_GET(x)\ FIELD_GET(FDMA_PORT_CTRL_XTR_BUF_RST, x) -/* FDMA:FDMA:FDMA_INTR_DCB */ -#define FDMA_INTR_DCB __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 384, 0, 1, 4) +/* FDMA:FDMA:FDMA_INTR_DCB */ +#define FDMA_INTR_DCB \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 384, 0, 1,\ + 4) #define FDMA_INTR_DCB_INTR_DCB GENMASK(7, 0) #define FDMA_INTR_DCB_INTR_DCB_SET(x)\ @@ -4357,9 +4824,10 @@ enum sparx5_target { #define FDMA_INTR_DCB_INTR_DCB_GET(x)\ FIELD_GET(FDMA_INTR_DCB_INTR_DCB, x) -/* FDMA:FDMA:FDMA_INTR_DCB_ENA */ -#define FDMA_INTR_DCB_ENA __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 388, 0, 1, 4) +/* FDMA:FDMA:FDMA_INTR_DCB_ENA */ +#define FDMA_INTR_DCB_ENA \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 388, 0, 1,\ + 4) #define FDMA_INTR_DCB_ENA_INTR_DCB_ENA GENMASK(7, 0) #define FDMA_INTR_DCB_ENA_INTR_DCB_ENA_SET(x)\ @@ -4367,9 +4835,10 @@ enum sparx5_target { #define FDMA_INTR_DCB_ENA_INTR_DCB_ENA_GET(x)\ FIELD_GET(FDMA_INTR_DCB_ENA_INTR_DCB_ENA, x) -/* FDMA:FDMA:FDMA_INTR_DB */ -#define FDMA_INTR_DB __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 392, 0, 1, 4) +/* FDMA:FDMA:FDMA_INTR_DB */ +#define FDMA_INTR_DB \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 392, 0, 1,\ + 4) #define FDMA_INTR_DB_INTR_DB GENMASK(7, 0) #define FDMA_INTR_DB_INTR_DB_SET(x)\ @@ -4377,9 +4846,10 @@ enum sparx5_target { #define FDMA_INTR_DB_INTR_DB_GET(x)\ FIELD_GET(FDMA_INTR_DB_INTR_DB, x) -/* FDMA:FDMA:FDMA_INTR_DB_ENA */ -#define FDMA_INTR_DB_ENA __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 396, 0, 1, 4) +/* FDMA:FDMA:FDMA_INTR_DB_ENA */ +#define FDMA_INTR_DB_ENA \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 396, 0, 1,\ + 4) #define FDMA_INTR_DB_ENA_INTR_DB_ENA GENMASK(7, 0) #define FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(x)\ @@ -4387,9 +4857,10 @@ enum sparx5_target { #define FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(x)\ FIELD_GET(FDMA_INTR_DB_ENA_INTR_DB_ENA, x) -/* FDMA:FDMA:FDMA_INTR_ERR */ -#define FDMA_INTR_ERR __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 400, 0, 1, 4) +/* FDMA:FDMA:FDMA_INTR_ERR */ +#define FDMA_INTR_ERR \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 400, 0, 1,\ + 4) #define FDMA_INTR_ERR_INTR_PORT_ERR GENMASK(9, 8) #define FDMA_INTR_ERR_INTR_PORT_ERR_SET(x)\ @@ -4403,9 +4874,10 @@ enum sparx5_target { #define FDMA_INTR_ERR_INTR_CH_ERR_GET(x)\ FIELD_GET(FDMA_INTR_ERR_INTR_CH_ERR, x) -/* FDMA:FDMA:FDMA_ERRORS */ -#define FDMA_ERRORS __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 412, 0, 1, 4) +/* FDMA:FDMA:FDMA_ERRORS */ +#define FDMA_ERRORS \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 412, 0, 1,\ + 4) #define FDMA_ERRORS_ERR_XTR_WR GENMASK(31, 30) #define FDMA_ERRORS_ERR_XTR_WR_SET(x)\ @@ -4455,9 +4927,10 @@ enum sparx5_target { #define FDMA_ERRORS_ERR_CH_WR_GET(x)\ FIELD_GET(FDMA_ERRORS_ERR_CH_WR, x) -/* FDMA:FDMA:FDMA_ERRORS_2 */ -#define FDMA_ERRORS_2 __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 416, 0, 1, 4) +/* FDMA:FDMA:FDMA_ERRORS_2 */ +#define FDMA_ERRORS_2 \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 416, 0, 1,\ + 4) #define FDMA_ERRORS_2_ERR_XTR_FRAG GENMASK(1, 0) #define FDMA_ERRORS_2_ERR_XTR_FRAG_SET(x)\ @@ -4465,9 +4938,10 @@ enum sparx5_target { #define FDMA_ERRORS_2_ERR_XTR_FRAG_GET(x)\ FIELD_GET(FDMA_ERRORS_2_ERR_XTR_FRAG, x) -/* FDMA:FDMA:FDMA_CTRL */ -#define FDMA_CTRL __REG(TARGET_FDMA,\ - 0, 1, 8, 0, 1, 428, 424, 0, 1, 4) +/* FDMA:FDMA:FDMA_CTRL */ +#define FDMA_CTRL \ + __REG(TARGET_FDMA, 0, 1, 8, 0, 1, regs->gsize[GW_FDMA_FDMA], 424, 0, 1,\ + 4) #define FDMA_CTRL_NRESET BIT(0) #define FDMA_CTRL_NRESET_SET(x)\ @@ -4475,9 +4949,10 @@ enum sparx5_target { #define FDMA_CTRL_NRESET_GET(x)\ FIELD_GET(FDMA_CTRL_NRESET, x) -/* DEVCPU_GCB:CHIP_REGS:CHIP_ID */ -#define GCB_CHIP_ID __REG(TARGET_GCB,\ - 0, 1, 0, 0, 1, 424, 0, 0, 1, 4) +/* DEVCPU_GCB:CHIP_REGS:CHIP_ID */ +#define GCB_CHIP_ID \ + __REG(TARGET_GCB, 0, 1, 0, 0, 1, regs->gsize[GW_GCB_CHIP_REGS], 0, 0, \ + 1, 4) #define GCB_CHIP_ID_REV_ID GENMASK(31, 28) #define GCB_CHIP_ID_REV_ID_SET(x)\ @@ -4503,10 +4978,12 @@ enum sparx5_target { #define GCB_CHIP_ID_ONE_GET(x)\ FIELD_GET(GCB_CHIP_ID_ONE, x) -/* DEVCPU_GCB:CHIP_REGS:SOFT_RST */ -#define GCB_SOFT_RST __REG(TARGET_GCB,\ - 0, 1, 0, 0, 1, 424, 8, 0, 1, 4) +/* DEVCPU_GCB:CHIP_REGS:SOFT_RST */ +#define GCB_SOFT_RST \ + __REG(TARGET_GCB, 0, 1, 0, 0, 1, regs->gsize[GW_GCB_CHIP_REGS], \ + regs->raddr[RA_GCB_SOFT_RST], 0, 1, 4) +/* SPARX5 ONLY */ #define GCB_SOFT_RST_SOFT_NON_CFG_RST BIT(2) #define GCB_SOFT_RST_SOFT_NON_CFG_RST_SET(x)\ FIELD_PREP(GCB_SOFT_RST_SOFT_NON_CFG_RST, x) @@ -4525,9 +5002,11 @@ enum sparx5_target { #define GCB_SOFT_RST_SOFT_CHIP_RST_GET(x)\ FIELD_GET(GCB_SOFT_RST_SOFT_CHIP_RST, x) -/* DEVCPU_GCB:CHIP_REGS:HW_SGPIO_SD_CFG */ -#define GCB_HW_SGPIO_SD_CFG __REG(TARGET_GCB,\ - 0, 1, 0, 0, 1, 424, 20, 0, 1, 4) +/* SPARX5 ONLY */ +/* DEVCPU_GCB:CHIP_REGS:HW_SGPIO_SD_CFG */ +#define GCB_HW_SGPIO_SD_CFG \ + __REG(TARGET_GCB, 0, 1, 0, 0, 1, regs->gsize[GW_GCB_CHIP_REGS], 20, 0, \ + 1, 4) #define GCB_HW_SGPIO_SD_CFG_SD_HIGH_ENA BIT(1) #define GCB_HW_SGPIO_SD_CFG_SD_HIGH_ENA_SET(x)\ @@ -4541,19 +5020,23 @@ enum sparx5_target { #define GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL_GET(x)\ FIELD_GET(GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL, x) -/* DEVCPU_GCB:CHIP_REGS:HW_SGPIO_TO_SD_MAP_CFG */ -#define GCB_HW_SGPIO_TO_SD_MAP_CFG(r) __REG(TARGET_GCB,\ - 0, 1, 0, 0, 1, 424, 24, r, 65, 4) +/* DEVCPU_GCB:CHIP_REGS:HW_SGPIO_TO_SD_MAP_CFG */ +#define GCB_HW_SGPIO_TO_SD_MAP_CFG(r) \ + __REG(TARGET_GCB, 0, 1, 0, 0, 1, regs->gsize[GW_GCB_CHIP_REGS], \ + regs->raddr[RA_GCB_HW_SGPIO_TO_SD_MAP_CFG], r, \ + regs->rcnt[RC_GCB_HW_SGPIO_TO_SD_MAP_CFG], 4) -#define GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL GENMASK(8, 0) +#define GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL\ + GENMASK(regs->fsize[FW_GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL] + 0 - 1, 0) #define GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL_SET(x)\ - FIELD_PREP(GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL, x) + spx5_field_prep(GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL, x) #define GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL_GET(x)\ - FIELD_GET(GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL, x) + spx5_field_get(GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL, x) -/* DEVCPU_GCB:SIO_CTRL:SIO_CLOCK */ -#define GCB_SIO_CLOCK(g) __REG(TARGET_GCB,\ - 0, 1, 876, g, 3, 280, 20, 0, 1, 4) +/* DEVCPU_GCB:SIO_CTRL:SIO_CLOCK */ +#define GCB_SIO_CLOCK(g) \ + __REG(TARGET_GCB, 0, 1, regs->gaddr[GA_GCB_SIO_CTRL], g, \ + regs->gcnt[GC_GCB_SIO_CTRL], 280, 20, 0, 1, 4) #define GCB_SIO_CLOCK_SIO_CLK_FREQ GENMASK(19, 8) #define GCB_SIO_CLOCK_SIO_CLK_FREQ_SET(x)\ @@ -4567,9 +5050,10 @@ enum sparx5_target { #define GCB_SIO_CLOCK_SYS_CLK_PERIOD_GET(x)\ FIELD_GET(GCB_SIO_CLOCK_SYS_CLK_PERIOD, x) -/* HSCH:HSCH_CFG:CIR_CFG */ -#define HSCH_CIR_CFG(g) __REG(TARGET_HSCH,\ - 0, 1, 0, g, 5040, 32, 0, 0, 1, 4) +/* HSCH:HSCH_CFG:CIR_CFG */ +#define HSCH_CIR_CFG(g) \ + __REG(TARGET_HSCH, 0, 1, 0, g, regs->gcnt[GC_HSCH_HSCH_CFG], 32, 0, 0, \ + 1, 4) #define HSCH_CIR_CFG_CIR_RATE GENMASK(22, 6) #define HSCH_CIR_CFG_CIR_RATE_SET(x)\ @@ -4583,9 +5067,10 @@ enum sparx5_target { #define HSCH_CIR_CFG_CIR_BURST_GET(x)\ FIELD_GET(HSCH_CIR_CFG_CIR_BURST, x) -/* HSCH:HSCH_CFG:EIR_CFG */ -#define HSCH_EIR_CFG(g) __REG(TARGET_HSCH,\ - 0, 1, 0, g, 5040, 32, 4, 0, 1, 4) +/* HSCH:HSCH_CFG:EIR_CFG */ +#define HSCH_EIR_CFG(g) \ + __REG(TARGET_HSCH, 0, 1, 0, g, regs->gcnt[GC_HSCH_HSCH_CFG], 32, 4, 0, \ + 1, 4) #define HSCH_EIR_CFG_EIR_RATE GENMASK(22, 6) #define HSCH_EIR_CFG_EIR_RATE_SET(x)\ @@ -4599,15 +5084,17 @@ enum sparx5_target { #define HSCH_EIR_CFG_EIR_BURST_GET(x)\ FIELD_GET(HSCH_EIR_CFG_EIR_BURST, x) -/* HSCH:HSCH_CFG:SE_CFG */ -#define HSCH_SE_CFG(g) __REG(TARGET_HSCH,\ - 0, 1, 0, g, 5040, 32, 8, 0, 1, 4) +/* HSCH:HSCH_CFG:SE_CFG */ +#define HSCH_SE_CFG(g) \ + __REG(TARGET_HSCH, 0, 1, 0, g, regs->gcnt[GC_HSCH_HSCH_CFG], 32, 8, 0, \ + 1, 4) -#define HSCH_SE_CFG_SE_DWRR_CNT GENMASK(12, 6) +#define HSCH_SE_CFG_SE_DWRR_CNT\ + GENMASK(regs->fsize[FW_HSCH_SE_CFG_SE_DWRR_CNT] + 6 - 1, 6) #define HSCH_SE_CFG_SE_DWRR_CNT_SET(x)\ - FIELD_PREP(HSCH_SE_CFG_SE_DWRR_CNT, x) + spx5_field_prep(HSCH_SE_CFG_SE_DWRR_CNT, x) #define HSCH_SE_CFG_SE_DWRR_CNT_GET(x)\ - FIELD_GET(HSCH_SE_CFG_SE_DWRR_CNT, x) + spx5_field_get(HSCH_SE_CFG_SE_DWRR_CNT, x) #define HSCH_SE_CFG_SE_AVB_ENA BIT(5) #define HSCH_SE_CFG_SE_AVB_ENA_SET(x)\ @@ -4633,19 +5120,22 @@ enum sparx5_target { #define HSCH_SE_CFG_SE_STOP_GET(x)\ FIELD_GET(HSCH_SE_CFG_SE_STOP, x) -/* HSCH:HSCH_CFG:SE_CONNECT */ -#define HSCH_SE_CONNECT(g) __REG(TARGET_HSCH,\ - 0, 1, 0, g, 5040, 32, 12, 0, 1, 4) +/* HSCH:HSCH_CFG:SE_CONNECT */ +#define HSCH_SE_CONNECT(g) \ + __REG(TARGET_HSCH, 0, 1, 0, g, regs->gcnt[GC_HSCH_HSCH_CFG], 32, 12, 0,\ + 1, 4) -#define HSCH_SE_CONNECT_SE_LEAK_LINK GENMASK(15, 0) +#define HSCH_SE_CONNECT_SE_LEAK_LINK\ + GENMASK(regs->fsize[FW_HSCH_SE_CONNECT_SE_LEAK_LINK] + 0 - 1, 0) #define HSCH_SE_CONNECT_SE_LEAK_LINK_SET(x)\ - FIELD_PREP(HSCH_SE_CONNECT_SE_LEAK_LINK, x) + spx5_field_prep(HSCH_SE_CONNECT_SE_LEAK_LINK, x) #define HSCH_SE_CONNECT_SE_LEAK_LINK_GET(x)\ - FIELD_GET(HSCH_SE_CONNECT_SE_LEAK_LINK, x) + spx5_field_get(HSCH_SE_CONNECT_SE_LEAK_LINK, x) -/* HSCH:HSCH_CFG:SE_DLB_SENSE */ -#define HSCH_SE_DLB_SENSE(g) __REG(TARGET_HSCH,\ - 0, 1, 0, g, 5040, 32, 16, 0, 1, 4) +/* HSCH:HSCH_CFG:SE_DLB_SENSE */ +#define HSCH_SE_DLB_SENSE(g) \ + __REG(TARGET_HSCH, 0, 1, 0, g, regs->gcnt[GC_HSCH_HSCH_CFG], 32, 16, 0,\ + 1, 4) #define HSCH_SE_DLB_SENSE_SE_DLB_PRIO GENMASK(12, 10) #define HSCH_SE_DLB_SENSE_SE_DLB_PRIO_SET(x)\ @@ -4653,11 +5143,12 @@ enum sparx5_target { #define HSCH_SE_DLB_SENSE_SE_DLB_PRIO_GET(x)\ FIELD_GET(HSCH_SE_DLB_SENSE_SE_DLB_PRIO, x) -#define HSCH_SE_DLB_SENSE_SE_DLB_DPORT GENMASK(9, 3) +#define HSCH_SE_DLB_SENSE_SE_DLB_DPORT\ + GENMASK(regs->fsize[FW_HSCH_SE_DLB_SENSE_SE_DLB_DPORT] + 3 - 1, 3) #define HSCH_SE_DLB_SENSE_SE_DLB_DPORT_SET(x)\ - FIELD_PREP(HSCH_SE_DLB_SENSE_SE_DLB_DPORT, x) + spx5_field_prep(HSCH_SE_DLB_SENSE_SE_DLB_DPORT, x) #define HSCH_SE_DLB_SENSE_SE_DLB_DPORT_GET(x)\ - FIELD_GET(HSCH_SE_DLB_SENSE_SE_DLB_DPORT, x) + spx5_field_get(HSCH_SE_DLB_SENSE_SE_DLB_DPORT, x) #define HSCH_SE_DLB_SENSE_SE_DLB_SE_ENA BIT(2) #define HSCH_SE_DLB_SENSE_SE_DLB_SE_ENA_SET(x)\ @@ -4677,9 +5168,10 @@ enum sparx5_target { #define HSCH_SE_DLB_SENSE_SE_DLB_DPORT_ENA_GET(x)\ FIELD_GET(HSCH_SE_DLB_SENSE_SE_DLB_DPORT_ENA, x) -/* HSCH:HSCH_DWRR:DWRR_ENTRY */ -#define HSCH_DWRR_ENTRY(g) __REG(TARGET_HSCH,\ - 0, 1, 162816, g, 72, 4, 0, 0, 1, 4) +/* HSCH:HSCH_DWRR:DWRR_ENTRY */ +#define HSCH_DWRR_ENTRY(g) \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_HSCH_DWRR], g, \ + regs->gcnt[GC_HSCH_HSCH_DWRR], 4, 0, 0, 1, 4) #define HSCH_DWRR_ENTRY_DWRR_COST GENMASK(24, 20) #define HSCH_DWRR_ENTRY_DWRR_COST_SET(x)\ @@ -4693,15 +5185,17 @@ enum sparx5_target { #define HSCH_DWRR_ENTRY_DWRR_BALANCE_GET(x)\ FIELD_GET(HSCH_DWRR_ENTRY_DWRR_BALANCE, x) -/* HSCH:HSCH_MISC:HSCH_CFG_CFG */ -#define HSCH_HSCH_CFG_CFG __REG(TARGET_HSCH,\ - 0, 1, 163104, 0, 1, 648, 284, 0, 1, 4) +/* HSCH:HSCH_MISC:HSCH_CFG_CFG */ +#define HSCH_HSCH_CFG_CFG \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_HSCH_MISC], 0, 1, 648, \ + 284, 0, 1, 4) -#define HSCH_HSCH_CFG_CFG_CFG_SE_IDX GENMASK(26, 14) +#define HSCH_HSCH_CFG_CFG_CFG_SE_IDX\ + GENMASK(regs->fsize[FW_HSCH_HSCH_CFG_CFG_CFG_SE_IDX] + 14 - 1, 14) #define HSCH_HSCH_CFG_CFG_CFG_SE_IDX_SET(x)\ - FIELD_PREP(HSCH_HSCH_CFG_CFG_CFG_SE_IDX, x) + spx5_field_prep(HSCH_HSCH_CFG_CFG_CFG_SE_IDX, x) #define HSCH_HSCH_CFG_CFG_CFG_SE_IDX_GET(x)\ - FIELD_GET(HSCH_HSCH_CFG_CFG_CFG_SE_IDX, x) + spx5_field_get(HSCH_HSCH_CFG_CFG_CFG_SE_IDX, x) #define HSCH_HSCH_CFG_CFG_HSCH_LAYER GENMASK(13, 12) #define HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(x)\ @@ -4715,9 +5209,11 @@ enum sparx5_target { #define HSCH_HSCH_CFG_CFG_CSR_GRANT_GET(x)\ FIELD_GET(HSCH_HSCH_CFG_CFG_CSR_GRANT, x) -/* HSCH:HSCH_MISC:SYS_CLK_PER */ -#define HSCH_SYS_CLK_PER __REG(TARGET_HSCH,\ - 0, 1, 163104, 0, 1, 648, 640, 0, 1, 4) +/* SPARX5 ONLY */ +/* HSCH:HSCH_MISC:SYS_CLK_PER */ +#define HSCH_SYS_CLK_PER \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_HSCH_MISC], 0, 1, 648, \ + 640, 0, 1, 4) #define HSCH_SYS_CLK_PER_100PS GENMASK(7, 0) #define HSCH_SYS_CLK_PER_100PS_SET(x)\ @@ -4725,9 +5221,10 @@ enum sparx5_target { #define HSCH_SYS_CLK_PER_100PS_GET(x)\ FIELD_GET(HSCH_SYS_CLK_PER_100PS, x) -/* HSCH:HSCH_LEAK_LISTS:HSCH_TIMER_CFG */ -#define HSCH_HSCH_TIMER_CFG(g, r) __REG(TARGET_HSCH,\ - 0, 1, 161664, g, 4, 32, 0, r, 4, 4) +/* HSCH:HSCH_LEAK_LISTS:HSCH_TIMER_CFG */ +#define HSCH_HSCH_TIMER_CFG(g, r) \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_HSCH_LEAK_LISTS], g, 4, \ + 32, 0, r, 4, 4) #define HSCH_HSCH_TIMER_CFG_LEAK_TIME GENMASK(17, 0) #define HSCH_HSCH_TIMER_CFG_LEAK_TIME_SET(x)\ @@ -4735,15 +5232,17 @@ enum sparx5_target { #define HSCH_HSCH_TIMER_CFG_LEAK_TIME_GET(x)\ FIELD_GET(HSCH_HSCH_TIMER_CFG_LEAK_TIME, x) -/* HSCH:HSCH_LEAK_LISTS:HSCH_LEAK_CFG */ -#define HSCH_HSCH_LEAK_CFG(g, r) __REG(TARGET_HSCH,\ - 0, 1, 161664, g, 4, 32, 16, r, 4, 4) +/* HSCH:HSCH_LEAK_LISTS:HSCH_LEAK_CFG */ +#define HSCH_HSCH_LEAK_CFG(g, r) \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_HSCH_LEAK_LISTS], g, 4, \ + 32, 16, r, 4, 4) -#define HSCH_HSCH_LEAK_CFG_LEAK_FIRST GENMASK(16, 1) +#define HSCH_HSCH_LEAK_CFG_LEAK_FIRST\ + GENMASK(regs->fsize[FW_HSCH_HSCH_LEAK_CFG_LEAK_FIRST] + 1 - 1, 1) #define HSCH_HSCH_LEAK_CFG_LEAK_FIRST_SET(x)\ - FIELD_PREP(HSCH_HSCH_LEAK_CFG_LEAK_FIRST, x) + spx5_field_prep(HSCH_HSCH_LEAK_CFG_LEAK_FIRST, x) #define HSCH_HSCH_LEAK_CFG_LEAK_FIRST_GET(x)\ - FIELD_GET(HSCH_HSCH_LEAK_CFG_LEAK_FIRST, x) + spx5_field_get(HSCH_HSCH_LEAK_CFG_LEAK_FIRST, x) #define HSCH_HSCH_LEAK_CFG_LEAK_ERR BIT(0) #define HSCH_HSCH_LEAK_CFG_LEAK_ERR_SET(x)\ @@ -4751,9 +5250,10 @@ enum sparx5_target { #define HSCH_HSCH_LEAK_CFG_LEAK_ERR_GET(x)\ FIELD_GET(HSCH_HSCH_LEAK_CFG_LEAK_ERR, x) -/* HSCH:SYSTEM:FLUSH_CTRL */ -#define HSCH_FLUSH_CTRL __REG(TARGET_HSCH,\ - 0, 1, 184000, 0, 1, 312, 4, 0, 1, 4) +/* HSCH:SYSTEM:FLUSH_CTRL */ +#define HSCH_FLUSH_CTRL \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_SYSTEM], 0, 1, 312, 4, 0, \ + 1, 4) #define HSCH_FLUSH_CTRL_FLUSH_ENA BIT(27) #define HSCH_FLUSH_CTRL_FLUSH_ENA_SET(x)\ @@ -4773,11 +5273,12 @@ enum sparx5_target { #define HSCH_FLUSH_CTRL_FLUSH_DST_GET(x)\ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_DST, x) -#define HSCH_FLUSH_CTRL_FLUSH_PORT GENMASK(24, 18) +#define HSCH_FLUSH_CTRL_FLUSH_PORT\ + GENMASK(regs->fsize[FW_HSCH_FLUSH_CTRL_FLUSH_PORT] + 18 - 1, 18) #define HSCH_FLUSH_CTRL_FLUSH_PORT_SET(x)\ - FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_PORT, x) + spx5_field_prep(HSCH_FLUSH_CTRL_FLUSH_PORT, x) #define HSCH_FLUSH_CTRL_FLUSH_PORT_GET(x)\ - FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_PORT, x) + spx5_field_get(HSCH_FLUSH_CTRL_FLUSH_PORT, x) #define HSCH_FLUSH_CTRL_FLUSH_QUEUE BIT(17) #define HSCH_FLUSH_CTRL_FLUSH_QUEUE_SET(x)\ @@ -4791,15 +5292,17 @@ enum sparx5_target { #define HSCH_FLUSH_CTRL_FLUSH_SE_GET(x)\ FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_SE, x) -#define HSCH_FLUSH_CTRL_FLUSH_HIER GENMASK(15, 0) +#define HSCH_FLUSH_CTRL_FLUSH_HIER\ + GENMASK(regs->fsize[FW_HSCH_FLUSH_CTRL_FLUSH_HIER] + 0 - 1, 0) #define HSCH_FLUSH_CTRL_FLUSH_HIER_SET(x)\ - FIELD_PREP(HSCH_FLUSH_CTRL_FLUSH_HIER, x) + spx5_field_prep(HSCH_FLUSH_CTRL_FLUSH_HIER, x) #define HSCH_FLUSH_CTRL_FLUSH_HIER_GET(x)\ - FIELD_GET(HSCH_FLUSH_CTRL_FLUSH_HIER, x) + spx5_field_get(HSCH_FLUSH_CTRL_FLUSH_HIER, x) -/* HSCH:SYSTEM:PORT_MODE */ -#define HSCH_PORT_MODE(r) __REG(TARGET_HSCH,\ - 0, 1, 184000, 0, 1, 312, 8, r, 70, 4) +/* HSCH:SYSTEM:PORT_MODE */ +#define HSCH_PORT_MODE(r) \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_SYSTEM], 0, 1, 312, 8, r, \ + regs->rcnt[RC_HSCH_PORT_MODE], 4) #define HSCH_PORT_MODE_DEQUEUE_DIS BIT(4) #define HSCH_PORT_MODE_DEQUEUE_DIS_SET(x)\ @@ -4831,9 +5334,10 @@ enum sparx5_target { #define HSCH_PORT_MODE_CPU_PRIO_MODE_GET(x)\ FIELD_GET(HSCH_PORT_MODE_CPU_PRIO_MODE, x) -/* HSCH:SYSTEM:OUTB_SHARE_ENA */ -#define HSCH_OUTB_SHARE_ENA(r) __REG(TARGET_HSCH,\ - 0, 1, 184000, 0, 1, 312, 288, r, 5, 4) +/* HSCH:SYSTEM:OUTB_SHARE_ENA */ +#define HSCH_OUTB_SHARE_ENA(r) \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_SYSTEM], 0, 1, 312, 288, \ + r, 5, 4) #define HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA GENMASK(7, 0) #define HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA_SET(x)\ @@ -4841,9 +5345,10 @@ enum sparx5_target { #define HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA_GET(x)\ FIELD_GET(HSCH_OUTB_SHARE_ENA_OUTB_SHARE_ENA, x) -/* HSCH:MMGT:RESET_CFG */ -#define HSCH_RESET_CFG __REG(TARGET_HSCH,\ - 0, 1, 162368, 0, 1, 16, 8, 0, 1, 4) +/* HSCH:MMGT:RESET_CFG */ +#define HSCH_RESET_CFG \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_MMGT], 0, 1, 16, 8, 0, 1, \ + 4) #define HSCH_RESET_CFG_CORE_ENA BIT(0) #define HSCH_RESET_CFG_CORE_ENA_SET(x)\ @@ -4851,9 +5356,10 @@ enum sparx5_target { #define HSCH_RESET_CFG_CORE_ENA_GET(x)\ FIELD_GET(HSCH_RESET_CFG_CORE_ENA, x) -/* HSCH:TAS_CONFIG:TAS_STATEMACHINE_CFG */ -#define HSCH_TAS_STATEMACHINE_CFG __REG(TARGET_HSCH,\ - 0, 1, 162384, 0, 1, 12, 8, 0, 1, 4) +/* HSCH:TAS_CONFIG:TAS_STATEMACHINE_CFG */ +#define HSCH_TAS_STATEMACHINE_CFG \ + __REG(TARGET_HSCH, 0, 1, regs->gaddr[GA_HSCH_TAS_CONFIG], 0, 1, \ + regs->gsize[GW_HSCH_TAS_CONFIG], 8, 0, 1, 4) #define HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY GENMASK(7, 0) #define HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_SET(x)\ @@ -4861,9 +5367,9 @@ enum sparx5_target { #define HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_GET(x)\ FIELD_GET(HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY, x) -/* LRN:COMMON:COMMON_ACCESS_CTRL */ -#define LRN_COMMON_ACCESS_CTRL __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 0, 0, 1, 4) +/* LRN:COMMON:COMMON_ACCESS_CTRL */ +#define LRN_COMMON_ACCESS_CTRL \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 0, 0, 1, 4) #define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_COL GENMASK(21, 20) #define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_COL_SET(x)\ @@ -4877,11 +5383,12 @@ enum sparx5_target { #define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_TYPE_GET(x)\ FIELD_GET(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_TYPE, x) -#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW GENMASK(18, 5) +#define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW\ + GENMASK(regs->fsize[FW_LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW] + 5 - 1, 5) #define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW_SET(x)\ - FIELD_PREP(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW, x) + spx5_field_prep(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW, x) #define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW_GET(x)\ - FIELD_GET(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW, x) + spx5_field_get(LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW, x) #define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD GENMASK(4, 1) #define LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_CMD_SET(x)\ @@ -4895,9 +5402,9 @@ enum sparx5_target { #define LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT_GET(x)\ FIELD_GET(LRN_COMMON_ACCESS_CTRL_MAC_TABLE_ACCESS_SHOT, x) -/* LRN:COMMON:MAC_ACCESS_CFG_0 */ -#define LRN_MAC_ACCESS_CFG_0 __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 4, 0, 1, 4) +/* LRN:COMMON:MAC_ACCESS_CFG_0 */ +#define LRN_MAC_ACCESS_CFG_0 \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 4, 0, 1, 4) #define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_FID GENMASK(28, 16) #define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_FID_SET(x)\ @@ -4911,13 +5418,13 @@ enum sparx5_target { #define LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_MAC_MSB_GET(x)\ FIELD_GET(LRN_MAC_ACCESS_CFG_0_MAC_ENTRY_MAC_MSB, x) -/* LRN:COMMON:MAC_ACCESS_CFG_1 */ -#define LRN_MAC_ACCESS_CFG_1 __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 8, 0, 1, 4) +/* LRN:COMMON:MAC_ACCESS_CFG_1 */ +#define LRN_MAC_ACCESS_CFG_1 \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 8, 0, 1, 4) -/* LRN:COMMON:MAC_ACCESS_CFG_2 */ -#define LRN_MAC_ACCESS_CFG_2 __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 12, 0, 1, 4) +/* LRN:COMMON:MAC_ACCESS_CFG_2 */ +#define LRN_MAC_ACCESS_CFG_2 \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 12, 0, 1, 4) #define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_SRC_KILL_FWD BIT(28) #define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_SRC_KILL_FWD_SET(x)\ @@ -4991,19 +5498,20 @@ enum sparx5_target { #define LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR_GET(x)\ FIELD_GET(LRN_MAC_ACCESS_CFG_2_MAC_ENTRY_ADDR, x) -/* LRN:COMMON:MAC_ACCESS_CFG_3 */ -#define LRN_MAC_ACCESS_CFG_3 __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 16, 0, 1, 4) +/* LRN:COMMON:MAC_ACCESS_CFG_3 */ +#define LRN_MAC_ACCESS_CFG_3 \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 16, 0, 1, 4) -#define LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX GENMASK(10, 0) +#define LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX\ + GENMASK(regs->fsize[FW_LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX] + 0 - 1, 0) #define LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX_SET(x)\ - FIELD_PREP(LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX, x) + spx5_field_prep(LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX, x) #define LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX_GET(x)\ - FIELD_GET(LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX, x) + spx5_field_get(LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX, x) -/* LRN:COMMON:SCAN_NEXT_CFG */ -#define LRN_SCAN_NEXT_CFG __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 20, 0, 1, 4) +/* LRN:COMMON:SCAN_NEXT_CFG */ +#define LRN_SCAN_NEXT_CFG \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 20, 0, 1, 4) #define LRN_SCAN_NEXT_CFG_SCAN_AGE_FLAG_UPDATE_SEL GENMASK(21, 19) #define LRN_SCAN_NEXT_CFG_SCAN_AGE_FLAG_UPDATE_SEL_SET(x)\ @@ -5095,9 +5603,9 @@ enum sparx5_target { #define LRN_SCAN_NEXT_CFG_ADDR_FILTER_ENA_GET(x)\ FIELD_GET(LRN_SCAN_NEXT_CFG_ADDR_FILTER_ENA, x) -/* LRN:COMMON:SCAN_NEXT_CFG_1 */ -#define LRN_SCAN_NEXT_CFG_1 __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 24, 0, 1, 4) +/* LRN:COMMON:SCAN_NEXT_CFG_1 */ +#define LRN_SCAN_NEXT_CFG_1 \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 24, 0, 1, 4) #define LRN_SCAN_NEXT_CFG_1_PORT_MOVE_NEW_ADDR GENMASK(30, 16) #define LRN_SCAN_NEXT_CFG_1_PORT_MOVE_NEW_ADDR_SET(x)\ @@ -5111,9 +5619,9 @@ enum sparx5_target { #define LRN_SCAN_NEXT_CFG_1_SCAN_ENTRY_ADDR_MASK_GET(x)\ FIELD_GET(LRN_SCAN_NEXT_CFG_1_SCAN_ENTRY_ADDR_MASK, x) -/* LRN:COMMON:AUTOAGE_CFG */ -#define LRN_AUTOAGE_CFG(r) __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 36, r, 4, 4) +/* LRN:COMMON:AUTOAGE_CFG */ +#define LRN_AUTOAGE_CFG(r) \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 36, r, 4, 4) #define LRN_AUTOAGE_CFG_UNIT_SIZE GENMASK(29, 28) #define LRN_AUTOAGE_CFG_UNIT_SIZE_SET(x)\ @@ -5127,9 +5635,9 @@ enum sparx5_target { #define LRN_AUTOAGE_CFG_PERIOD_VAL_GET(x)\ FIELD_GET(LRN_AUTOAGE_CFG_PERIOD_VAL, x) -/* LRN:COMMON:AUTOAGE_CFG_1 */ -#define LRN_AUTOAGE_CFG_1 __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 52, 0, 1, 4) +/* LRN:COMMON:AUTOAGE_CFG_1 */ +#define LRN_AUTOAGE_CFG_1 \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 52, 0, 1, 4) #define LRN_AUTOAGE_CFG_1_PAUSE_AUTO_AGE_ENA BIT(25) #define LRN_AUTOAGE_CFG_1_PAUSE_AUTO_AGE_ENA_SET(x)\ @@ -5173,15 +5681,16 @@ enum sparx5_target { #define LRN_AUTOAGE_CFG_1_FORCE_IDLE_ENA_GET(x)\ FIELD_GET(LRN_AUTOAGE_CFG_1_FORCE_IDLE_ENA, x) -/* LRN:COMMON:AUTOAGE_CFG_2 */ -#define LRN_AUTOAGE_CFG_2 __REG(TARGET_LRN,\ - 0, 1, 0, 0, 1, 72, 56, 0, 1, 4) +/* LRN:COMMON:AUTOAGE_CFG_2 */ +#define LRN_AUTOAGE_CFG_2 \ + __REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 56, 0, 1, 4) -#define LRN_AUTOAGE_CFG_2_NEXT_ROW GENMASK(17, 4) +#define LRN_AUTOAGE_CFG_2_NEXT_ROW\ + GENMASK(regs->fsize[FW_LRN_AUTOAGE_CFG_2_NEXT_ROW] + 4 - 1, 4) #define LRN_AUTOAGE_CFG_2_NEXT_ROW_SET(x)\ - FIELD_PREP(LRN_AUTOAGE_CFG_2_NEXT_ROW, x) + spx5_field_prep(LRN_AUTOAGE_CFG_2_NEXT_ROW, x) #define LRN_AUTOAGE_CFG_2_NEXT_ROW_GET(x)\ - FIELD_GET(LRN_AUTOAGE_CFG_2_NEXT_ROW, x) + spx5_field_get(LRN_AUTOAGE_CFG_2_NEXT_ROW, x) #define LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS GENMASK(3, 0) #define LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS_SET(x)\ @@ -5189,9 +5698,10 @@ enum sparx5_target { #define LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS_GET(x)\ FIELD_GET(LRN_AUTOAGE_CFG_2_SCAN_ONGOING_STATUS, x) -/* PCIE_DM_EP:PF0_ATU_CAP:IATU_REGION_CTRL_2_OFF_OUTBOUND_0 */ -#define PCEP_RCTRL_2_OUT_0 __REG(TARGET_PCEP,\ - 0, 1, 3145728, 0, 1, 130852, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCIE_DM_EP:PF0_ATU_CAP:IATU_REGION_CTRL_2_OFF_OUTBOUND_0 */ +#define PCEP_RCTRL_2_OUT_0 \ + __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 4, 0, 1, 4) #define PCEP_RCTRL_2_OUT_0_MSG_CODE GENMASK(7, 0) #define PCEP_RCTRL_2_OUT_0_MSG_CODE_SET(x)\ @@ -5253,9 +5763,10 @@ enum sparx5_target { #define PCEP_RCTRL_2_OUT_0_REGION_EN_GET(x)\ FIELD_GET(PCEP_RCTRL_2_OUT_0_REGION_EN, x) -/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0 */ -#define PCEP_ADDR_LWR_OUT_0 __REG(TARGET_PCEP,\ - 0, 1, 3145728, 0, 1, 130852, 8, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0 */ +#define PCEP_ADDR_LWR_OUT_0 \ + __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 8, 0, 1, 4) #define PCEP_ADDR_LWR_OUT_0_LWR_BASE_HW GENMASK(15, 0) #define PCEP_ADDR_LWR_OUT_0_LWR_BASE_HW_SET(x)\ @@ -5269,13 +5780,15 @@ enum sparx5_target { #define PCEP_ADDR_LWR_OUT_0_LWR_BASE_RW_GET(x)\ FIELD_GET(PCEP_ADDR_LWR_OUT_0_LWR_BASE_RW, x) -/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0 */ -#define PCEP_ADDR_UPR_OUT_0 __REG(TARGET_PCEP,\ - 0, 1, 3145728, 0, 1, 130852, 12, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0 */ +#define PCEP_ADDR_UPR_OUT_0 \ + __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 12, 0, 1, 4) -/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LIMIT_ADDR_OFF_OUTBOUND_0 */ -#define PCEP_ADDR_LIM_OUT_0 __REG(TARGET_PCEP,\ - 0, 1, 3145728, 0, 1, 130852, 16, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LIMIT_ADDR_OFF_OUTBOUND_0 */ +#define PCEP_ADDR_LIM_OUT_0 \ + __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 16, 0, 1, 4) #define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_HW GENMASK(15, 0) #define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_HW_SET(x)\ @@ -5289,17 +5802,20 @@ enum sparx5_target { #define PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_RW_GET(x)\ FIELD_GET(PCEP_ADDR_LIM_OUT_0_LIMIT_ADDR_RW, x) -/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0 */ -#define PCEP_ADDR_LWR_TGT_OUT_0 __REG(TARGET_PCEP,\ - 0, 1, 3145728, 0, 1, 130852, 20, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCIE_DM_EP:PF0_ATU_CAP:IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0 */ +#define PCEP_ADDR_LWR_TGT_OUT_0 \ + __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 20, 0, 1, 4) -/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0 */ -#define PCEP_ADDR_UPR_TGT_OUT_0 __REG(TARGET_PCEP,\ - 0, 1, 3145728, 0, 1, 130852, 24, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0 */ +#define PCEP_ADDR_UPR_TGT_OUT_0 \ + __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 24, 0, 1, 4) -/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPR_LIMIT_ADDR_OFF_OUTBOUND_0 */ -#define PCEP_ADDR_UPR_LIM_OUT_0 __REG(TARGET_PCEP,\ - 0, 1, 3145728, 0, 1, 130852, 32, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCIE_DM_EP:PF0_ATU_CAP:IATU_UPPR_LIMIT_ADDR_OFF_OUTBOUND_0 */ +#define PCEP_ADDR_UPR_LIM_OUT_0 \ + __REG(TARGET_PCEP, 0, 1, 3145728, 0, 1, 130852, 32, 0, 1, 4) #define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_RW GENMASK(1, 0) #define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_RW_SET(x)\ @@ -5313,9 +5829,10 @@ enum sparx5_target { #define PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_HW_GET(x)\ FIELD_GET(PCEP_ADDR_UPR_LIM_OUT_0_UPPR_LIMIT_ADDR_HW, x) -/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */ -#define PCS10G_BR_PCS_CFG(t) __REG(TARGET_PCS10G_BR,\ - t, 12, 0, 0, 1, 56, 0, 0, 1, 4) +/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */ +#define PCS10G_BR_PCS_CFG(t) \ + __REG(TARGET_PCS10G_BR, t, regs->tsize[TC_PCS10G_BR], 0, 0, 1, 56, 0, \ + 0, 1, 4) #define PCS10G_BR_PCS_CFG_PCS_ENA BIT(31) #define PCS10G_BR_PCS_CFG_PCS_ENA_SET(x)\ @@ -5389,9 +5906,10 @@ enum sparx5_target { #define PCS10G_BR_PCS_CFG_TX_SCR_DISABLE_GET(x)\ FIELD_GET(PCS10G_BR_PCS_CFG_TX_SCR_DISABLE, x) -/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */ -#define PCS10G_BR_PCS_SD_CFG(t) __REG(TARGET_PCS10G_BR,\ - t, 12, 0, 0, 1, 56, 4, 0, 1, 4) +/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */ +#define PCS10G_BR_PCS_SD_CFG(t) \ + __REG(TARGET_PCS10G_BR, t, regs->tsize[TC_PCS10G_BR], 0, 0, 1, 56, 4, \ + 0, 1, 4) #define PCS10G_BR_PCS_SD_CFG_SD_SEL BIT(8) #define PCS10G_BR_PCS_SD_CFG_SD_SEL_SET(x)\ @@ -5411,9 +5929,10 @@ enum sparx5_target { #define PCS10G_BR_PCS_SD_CFG_SD_ENA_GET(x)\ FIELD_GET(PCS10G_BR_PCS_SD_CFG_SD_ENA, x) -/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */ -#define PCS25G_BR_PCS_CFG(t) __REG(TARGET_PCS25G_BR,\ - t, 8, 0, 0, 1, 56, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */ +#define PCS25G_BR_PCS_CFG(t) \ + __REG(TARGET_PCS25G_BR, t, 8, 0, 0, 1, 56, 0, 0, 1, 4) #define PCS25G_BR_PCS_CFG_PCS_ENA BIT(31) #define PCS25G_BR_PCS_CFG_PCS_ENA_SET(x)\ @@ -5487,9 +6006,10 @@ enum sparx5_target { #define PCS25G_BR_PCS_CFG_TX_SCR_DISABLE_GET(x)\ FIELD_GET(PCS25G_BR_PCS_CFG_TX_SCR_DISABLE, x) -/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */ -#define PCS25G_BR_PCS_SD_CFG(t) __REG(TARGET_PCS25G_BR,\ - t, 8, 0, 0, 1, 56, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */ +#define PCS25G_BR_PCS_SD_CFG(t) \ + __REG(TARGET_PCS25G_BR, t, 8, 0, 0, 1, 56, 4, 0, 1, 4) #define PCS25G_BR_PCS_SD_CFG_SD_SEL BIT(8) #define PCS25G_BR_PCS_SD_CFG_SD_SEL_SET(x)\ @@ -5509,9 +6029,10 @@ enum sparx5_target { #define PCS25G_BR_PCS_SD_CFG_SD_ENA_GET(x)\ FIELD_GET(PCS25G_BR_PCS_SD_CFG_SD_ENA, x) -/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */ -#define PCS5G_BR_PCS_CFG(t) __REG(TARGET_PCS5G_BR,\ - t, 13, 0, 0, 1, 56, 0, 0, 1, 4) +/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_CFG */ +#define PCS5G_BR_PCS_CFG(t) \ + __REG(TARGET_PCS5G_BR, t, regs->tsize[TC_PCS5G_BR], 0, 0, 1, 56, 0, 0, \ + 1, 4) #define PCS5G_BR_PCS_CFG_PCS_ENA BIT(31) #define PCS5G_BR_PCS_CFG_PCS_ENA_SET(x)\ @@ -5585,9 +6106,10 @@ enum sparx5_target { #define PCS5G_BR_PCS_CFG_TX_SCR_DISABLE_GET(x)\ FIELD_GET(PCS5G_BR_PCS_CFG_TX_SCR_DISABLE, x) -/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */ -#define PCS5G_BR_PCS_SD_CFG(t) __REG(TARGET_PCS5G_BR,\ - t, 13, 0, 0, 1, 56, 4, 0, 1, 4) +/* PCS_10GBASE_R:PCS_10GBR_CFG:PCS_SD_CFG */ +#define PCS5G_BR_PCS_SD_CFG(t) \ + __REG(TARGET_PCS5G_BR, t, regs->tsize[TC_PCS5G_BR], 0, 0, 1, 56, 4, 0, \ + 1, 4) #define PCS5G_BR_PCS_SD_CFG_SD_SEL BIT(8) #define PCS5G_BR_PCS_SD_CFG_SD_SEL_SET(x)\ @@ -5607,58 +6129,67 @@ enum sparx5_target { #define PCS5G_BR_PCS_SD_CFG_SD_ENA_GET(x)\ FIELD_GET(PCS5G_BR_PCS_SD_CFG_SD_ENA, x) -/* PORT_CONF:HW_CFG:DEV5G_MODES */ -#define PORT_CONF_DEV5G_MODES __REG(TARGET_PORT_CONF,\ - 0, 1, 0, 0, 1, 24, 0, 0, 1, 4) +/* PORT_CONF:HW_CFG:DEV5G_MODES */ +#define PORT_CONF_DEV5G_MODES \ + __REG(TARGET_PORT_CONF, 0, 1, 0, 0, 1, 24, 0, 0, 1, 4) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE BIT(0) #define PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D0_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE BIT(1) #define PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D1_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE BIT(2) #define PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D2_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE BIT(3) #define PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D3_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE BIT(4) #define PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D4_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE BIT(5) #define PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D5_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE BIT(6) #define PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D6_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE BIT(7) #define PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D7_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D8_MODE BIT(8) #define PORT_CONF_DEV5G_MODES_DEV5G_D8_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D8_MODE, x) @@ -5671,27 +6202,30 @@ enum sparx5_target { #define PORT_CONF_DEV5G_MODES_DEV5G_D9_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D9_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE BIT(10) #define PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D10_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE BIT(11) #define PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D11_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE BIT(12) #define PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE, x) #define PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV5G_MODES_DEV5G_D64_MODE, x) -/* PORT_CONF:HW_CFG:DEV10G_MODES */ -#define PORT_CONF_DEV10G_MODES __REG(TARGET_PORT_CONF,\ - 0, 1, 0, 0, 1, 24, 4, 0, 1, 4) +/* PORT_CONF:HW_CFG:DEV10G_MODES */ +#define PORT_CONF_DEV10G_MODES \ + __REG(TARGET_PORT_CONF, 0, 1, 0, 0, 1, 24, 4, 0, 1, 4) #define PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE BIT(0) #define PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE_SET(x)\ @@ -5699,75 +6233,87 @@ enum sparx5_target { #define PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D12_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE BIT(1) #define PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D13_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE BIT(2) #define PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D14_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE BIT(3) #define PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D15_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE BIT(4) #define PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D48_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE BIT(5) #define PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D49_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE BIT(6) #define PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D50_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE BIT(7) #define PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D51_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE BIT(8) #define PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D52_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE BIT(9) #define PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D53_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE BIT(10) #define PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D54_MODE, x) +/* SPARX5 ONLY */ #define PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE BIT(11) #define PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE_SET(x)\ FIELD_PREP(PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE, x) #define PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV10G_MODES_DEV10G_D55_MODE, x) -/* PORT_CONF:HW_CFG:DEV25G_MODES */ -#define PORT_CONF_DEV25G_MODES __REG(TARGET_PORT_CONF,\ - 0, 1, 0, 0, 1, 24, 8, 0, 1, 4) +/* SPARX5 ONLY */ +/* PORT_CONF:HW_CFG:DEV25G_MODES */ +#define PORT_CONF_DEV25G_MODES \ + __REG(TARGET_PORT_CONF, 0, 1, 0, 0, 1, 24, 8, 0, 1, 4) #define PORT_CONF_DEV25G_MODES_DEV25G_D56_MODE BIT(0) #define PORT_CONF_DEV25G_MODES_DEV25G_D56_MODE_SET(x)\ @@ -5817,9 +6363,9 @@ enum sparx5_target { #define PORT_CONF_DEV25G_MODES_DEV25G_D63_MODE_GET(x)\ FIELD_GET(PORT_CONF_DEV25G_MODES_DEV25G_D63_MODE, x) -/* PORT_CONF:HW_CFG:QSGMII_ENA */ -#define PORT_CONF_QSGMII_ENA __REG(TARGET_PORT_CONF,\ - 0, 1, 0, 0, 1, 24, 12, 0, 1, 4) +/* PORT_CONF:HW_CFG:QSGMII_ENA */ +#define PORT_CONF_QSGMII_ENA \ + __REG(TARGET_PORT_CONF, 0, 1, 0, 0, 1, 24, 12, 0, 1, 4) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_0 BIT(0) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_0_SET(x)\ @@ -5857,45 +6403,52 @@ enum sparx5_target { #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_5_GET(x)\ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_5, x) +/* SPARX5 ONLY */ #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_6 BIT(6) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_6_SET(x)\ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_6, x) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_6_GET(x)\ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_6, x) +/* SPARX5 ONLY */ #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_7 BIT(7) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_7_SET(x)\ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_7, x) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_7_GET(x)\ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_7, x) +/* SPARX5 ONLY */ #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_8 BIT(8) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_8_SET(x)\ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_8, x) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_8_GET(x)\ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_8, x) +/* SPARX5 ONLY */ #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_9 BIT(9) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_9_SET(x)\ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_9, x) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_9_GET(x)\ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_9, x) +/* SPARX5 ONLY */ #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_10 BIT(10) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_10_SET(x)\ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_10, x) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_10_GET(x)\ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_10, x) +/* SPARX5 ONLY */ #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_11 BIT(11) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_11_SET(x)\ FIELD_PREP(PORT_CONF_QSGMII_ENA_QSGMII_ENA_11, x) #define PORT_CONF_QSGMII_ENA_QSGMII_ENA_11_GET(x)\ FIELD_GET(PORT_CONF_QSGMII_ENA_QSGMII_ENA_11, x) -/* PORT_CONF:USGMII_CFG_STAT:USGMII_CFG */ -#define PORT_CONF_USGMII_CFG(g) __REG(TARGET_PORT_CONF,\ - 0, 1, 72, g, 6, 8, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* PORT_CONF:USGMII_CFG_STAT:USGMII_CFG */ +#define PORT_CONF_USGMII_CFG(g) \ + __REG(TARGET_PORT_CONF, 0, 1, 72, g, 6, 8, 0, 0, 1, 4) #define PORT_CONF_USGMII_CFG_BYPASS_SCRAM BIT(9) #define PORT_CONF_USGMII_CFG_BYPASS_SCRAM_SET(x)\ @@ -5939,39 +6492,46 @@ enum sparx5_target { #define PORT_CONF_USGMII_CFG_QUAD_MODE_GET(x)\ FIELD_GET(PORT_CONF_USGMII_CFG_QUAD_MODE, x) -/* DEVCPU_PTP:PTP_CFG:PTP_PIN_INTR */ -#define PTP_PTP_PIN_INTR __REG(TARGET_PTP,\ - 0, 1, 320, 0, 1, 16, 0, 0, 1, 4) +/* DEVCPU_PTP:PTP_CFG:PTP_PIN_INTR */ +#define PTP_PTP_PIN_INTR \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_CFG], 0, 1, 16, 0, 0, 1,\ + 4) -#define PTP_PTP_PIN_INTR_INTR_PTP GENMASK(4, 0) +#define PTP_PTP_PIN_INTR_INTR_PTP\ + GENMASK(regs->fsize[FW_PTP_PTP_PIN_INTR_INTR_PTP] + 0 - 1, 0) #define PTP_PTP_PIN_INTR_INTR_PTP_SET(x)\ - FIELD_PREP(PTP_PTP_PIN_INTR_INTR_PTP, x) + spx5_field_prep(PTP_PTP_PIN_INTR_INTR_PTP, x) #define PTP_PTP_PIN_INTR_INTR_PTP_GET(x)\ - FIELD_GET(PTP_PTP_PIN_INTR_INTR_PTP, x) + spx5_field_get(PTP_PTP_PIN_INTR_INTR_PTP, x) -/* DEVCPU_PTP:PTP_CFG:PTP_PIN_INTR_ENA */ -#define PTP_PTP_PIN_INTR_ENA __REG(TARGET_PTP,\ - 0, 1, 320, 0, 1, 16, 4, 0, 1, 4) +/* DEVCPU_PTP:PTP_CFG:PTP_PIN_INTR_ENA */ +#define PTP_PTP_PIN_INTR_ENA \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_CFG], 0, 1, 16, 4, 0, 1,\ + 4) -#define PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA GENMASK(4, 0) +#define PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA\ + GENMASK(regs->fsize[FW_PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA] + 0 - 1, 0) #define PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA_SET(x)\ - FIELD_PREP(PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA, x) + spx5_field_prep(PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA, x) #define PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA_GET(x)\ - FIELD_GET(PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA, x) + spx5_field_get(PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA, x) -/* DEVCPU_PTP:PTP_CFG:PTP_INTR_IDENT */ -#define PTP_PTP_INTR_IDENT __REG(TARGET_PTP,\ - 0, 1, 320, 0, 1, 16, 8, 0, 1, 4) +/* DEVCPU_PTP:PTP_CFG:PTP_INTR_IDENT */ +#define PTP_PTP_INTR_IDENT \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_CFG], 0, 1, 16, 8, 0, 1,\ + 4) -#define PTP_PTP_INTR_IDENT_INTR_PTP_IDENT GENMASK(4, 0) +#define PTP_PTP_INTR_IDENT_INTR_PTP_IDENT\ + GENMASK(regs->fsize[FW_PTP_PTP_INTR_IDENT_INTR_PTP_IDENT] + 0 - 1, 0) #define PTP_PTP_INTR_IDENT_INTR_PTP_IDENT_SET(x)\ - FIELD_PREP(PTP_PTP_INTR_IDENT_INTR_PTP_IDENT, x) + spx5_field_prep(PTP_PTP_INTR_IDENT_INTR_PTP_IDENT, x) #define PTP_PTP_INTR_IDENT_INTR_PTP_IDENT_GET(x)\ - FIELD_GET(PTP_PTP_INTR_IDENT_INTR_PTP_IDENT, x) + spx5_field_get(PTP_PTP_INTR_IDENT_INTR_PTP_IDENT, x) -/* DEVCPU_PTP:PTP_CFG:PTP_DOM_CFG */ -#define PTP_PTP_DOM_CFG __REG(TARGET_PTP,\ - 0, 1, 320, 0, 1, 16, 12, 0, 1, 4) +/* DEVCPU_PTP:PTP_CFG:PTP_DOM_CFG */ +#define PTP_PTP_DOM_CFG \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_CFG], 0, 1, 16, 12, 0, \ + 1, 4) #define PTP_PTP_DOM_CFG_PTP_ENA GENMASK(11, 9) #define PTP_PTP_DOM_CFG_PTP_ENA_SET(x)\ @@ -5997,13 +6557,15 @@ enum sparx5_target { #define PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_GET(x)\ FIELD_GET(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS, x) -/* DEVCPU_PTP:PTP_TOD_DOMAINS:CLK_PER_CFG */ -#define PTP_CLK_PER_CFG(g, r) __REG(TARGET_PTP,\ - 0, 1, 336, g, 3, 28, 0, r, 2, 4) +/* DEVCPU_PTP:PTP_TOD_DOMAINS:CLK_PER_CFG */ +#define PTP_CLK_PER_CFG(g, r) \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_TOD_DOMAINS], g, 3, 28, \ + 0, r, 2, 4) -/* DEVCPU_PTP:PTP_TOD_DOMAINS:PTP_CUR_NSEC */ -#define PTP_PTP_CUR_NSEC(g) __REG(TARGET_PTP,\ - 0, 1, 336, g, 3, 28, 8, 0, 1, 4) +/* DEVCPU_PTP:PTP_TOD_DOMAINS:PTP_CUR_NSEC */ +#define PTP_PTP_CUR_NSEC(g) \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_TOD_DOMAINS], g, 3, 28, \ + 8, 0, 1, 4) #define PTP_PTP_CUR_NSEC_PTP_CUR_NSEC GENMASK(29, 0) #define PTP_PTP_CUR_NSEC_PTP_CUR_NSEC_SET(x)\ @@ -6011,9 +6573,10 @@ enum sparx5_target { #define PTP_PTP_CUR_NSEC_PTP_CUR_NSEC_GET(x)\ FIELD_GET(PTP_PTP_CUR_NSEC_PTP_CUR_NSEC, x) -/* DEVCPU_PTP:PTP_TOD_DOMAINS:PTP_CUR_NSEC_FRAC */ -#define PTP_PTP_CUR_NSEC_FRAC(g) __REG(TARGET_PTP,\ - 0, 1, 336, g, 3, 28, 12, 0, 1, 4) +/* DEVCPU_PTP:PTP_TOD_DOMAINS:PTP_CUR_NSEC_FRAC */ +#define PTP_PTP_CUR_NSEC_FRAC(g) \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_TOD_DOMAINS], g, 3, 28, \ + 12, 0, 1, 4) #define PTP_PTP_CUR_NSEC_FRAC_PTP_CUR_NSEC_FRAC GENMASK(7, 0) #define PTP_PTP_CUR_NSEC_FRAC_PTP_CUR_NSEC_FRAC_SET(x)\ @@ -6021,13 +6584,15 @@ enum sparx5_target { #define PTP_PTP_CUR_NSEC_FRAC_PTP_CUR_NSEC_FRAC_GET(x)\ FIELD_GET(PTP_PTP_CUR_NSEC_FRAC_PTP_CUR_NSEC_FRAC, x) -/* DEVCPU_PTP:PTP_TOD_DOMAINS:PTP_CUR_SEC_LSB */ -#define PTP_PTP_CUR_SEC_LSB(g) __REG(TARGET_PTP,\ - 0, 1, 336, g, 3, 28, 16, 0, 1, 4) +/* DEVCPU_PTP:PTP_TOD_DOMAINS:PTP_CUR_SEC_LSB */ +#define PTP_PTP_CUR_SEC_LSB(g) \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_TOD_DOMAINS], g, 3, 28, \ + 16, 0, 1, 4) -/* DEVCPU_PTP:PTP_TOD_DOMAINS:PTP_CUR_SEC_MSB */ -#define PTP_PTP_CUR_SEC_MSB(g) __REG(TARGET_PTP,\ - 0, 1, 336, g, 3, 28, 20, 0, 1, 4) +/* DEVCPU_PTP:PTP_TOD_DOMAINS:PTP_CUR_SEC_MSB */ +#define PTP_PTP_CUR_SEC_MSB(g) \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_TOD_DOMAINS], g, 3, 28, \ + 20, 0, 1, 4) #define PTP_PTP_CUR_SEC_MSB_PTP_CUR_SEC_MSB GENMASK(15, 0) #define PTP_PTP_CUR_SEC_MSB_PTP_CUR_SEC_MSB_SET(x)\ @@ -6035,37 +6600,43 @@ enum sparx5_target { #define PTP_PTP_CUR_SEC_MSB_PTP_CUR_SEC_MSB_GET(x)\ FIELD_GET(PTP_PTP_CUR_SEC_MSB_PTP_CUR_SEC_MSB, x) -/* DEVCPU_PTP:PTP_TOD_DOMAINS:NTP_CUR_NSEC */ -#define PTP_NTP_CUR_NSEC(g) __REG(TARGET_PTP,\ - 0, 1, 336, g, 3, 28, 24, 0, 1, 4) +/* DEVCPU_PTP:PTP_TOD_DOMAINS:NTP_CUR_NSEC */ +#define PTP_NTP_CUR_NSEC(g) \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PTP_TOD_DOMAINS], g, 3, 28, \ + 24, 0, 1, 4) -/* DEVCPU_PTP:PTP_PINS:PTP_PIN_CFG */ -#define PTP_PTP_PIN_CFG(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 0, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:PTP_PIN_CFG */ +#define PTP_PTP_PIN_CFG(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 0, 0, 1,\ + 4) -#define PTP_PTP_PIN_CFG_PTP_PIN_ACTION GENMASK(28, 26) +#define PTP_PTP_PIN_CFG_PTP_PIN_ACTION\ + GENMASK(regs->fpos[FP_PTP_PTP_PIN_CFG_PTP_PIN_ACTION] + 2, regs->fpos[FP_PTP_PTP_PIN_CFG_PTP_PIN_ACTION]) #define PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(x)\ - FIELD_PREP(PTP_PTP_PIN_CFG_PTP_PIN_ACTION, x) + spx5_field_prep(PTP_PTP_PIN_CFG_PTP_PIN_ACTION, x) #define PTP_PTP_PIN_CFG_PTP_PIN_ACTION_GET(x)\ - FIELD_GET(PTP_PTP_PIN_CFG_PTP_PIN_ACTION, x) + spx5_field_get(PTP_PTP_PIN_CFG_PTP_PIN_ACTION, x) -#define PTP_PTP_PIN_CFG_PTP_PIN_SYNC GENMASK(25, 24) +#define PTP_PTP_PIN_CFG_PTP_PIN_SYNC\ + GENMASK(regs->fpos[FP_PTP_PTP_PIN_CFG_PTP_PIN_SYNC] + 1, regs->fpos[FP_PTP_PTP_PIN_CFG_PTP_PIN_SYNC]) #define PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(x)\ - FIELD_PREP(PTP_PTP_PIN_CFG_PTP_PIN_SYNC, x) + spx5_field_prep(PTP_PTP_PIN_CFG_PTP_PIN_SYNC, x) #define PTP_PTP_PIN_CFG_PTP_PIN_SYNC_GET(x)\ - FIELD_GET(PTP_PTP_PIN_CFG_PTP_PIN_SYNC, x) + spx5_field_get(PTP_PTP_PIN_CFG_PTP_PIN_SYNC, x) -#define PTP_PTP_PIN_CFG_PTP_PIN_INV_POL BIT(23) +#define PTP_PTP_PIN_CFG_PTP_PIN_INV_POL\ + BIT(regs->fpos[FP_PTP_PTP_PIN_CFG_PTP_PIN_INV_POL]) #define PTP_PTP_PIN_CFG_PTP_PIN_INV_POL_SET(x)\ - FIELD_PREP(PTP_PTP_PIN_CFG_PTP_PIN_INV_POL, x) + spx5_field_prep(PTP_PTP_PIN_CFG_PTP_PIN_INV_POL, x) #define PTP_PTP_PIN_CFG_PTP_PIN_INV_POL_GET(x)\ - FIELD_GET(PTP_PTP_PIN_CFG_PTP_PIN_INV_POL, x) + spx5_field_get(PTP_PTP_PIN_CFG_PTP_PIN_INV_POL, x) -#define PTP_PTP_PIN_CFG_PTP_PIN_SELECT GENMASK(22, 21) +#define PTP_PTP_PIN_CFG_PTP_PIN_SELECT\ + GENMASK(regs->fsize[FW_PTP_PTP_PIN_CFG_PTP_PIN_SELECT] + 21 - 1, 21) #define PTP_PTP_PIN_CFG_PTP_PIN_SELECT_SET(x)\ - FIELD_PREP(PTP_PTP_PIN_CFG_PTP_PIN_SELECT, x) + spx5_field_prep(PTP_PTP_PIN_CFG_PTP_PIN_SELECT, x) #define PTP_PTP_PIN_CFG_PTP_PIN_SELECT_GET(x)\ - FIELD_GET(PTP_PTP_PIN_CFG_PTP_PIN_SELECT, x) + spx5_field_get(PTP_PTP_PIN_CFG_PTP_PIN_SELECT, x) #define PTP_PTP_PIN_CFG_PTP_CLK_SELECT GENMASK(20, 18) #define PTP_PTP_PIN_CFG_PTP_CLK_SELECT_SET(x)\ @@ -6097,9 +6668,10 @@ enum sparx5_target { #define PTP_PTP_PIN_CFG_PTP_PIN_OUTP_OFS_GET(x)\ FIELD_GET(PTP_PTP_PIN_CFG_PTP_PIN_OUTP_OFS, x) -/* DEVCPU_PTP:PTP_PINS:PTP_TOD_SEC_MSB */ -#define PTP_PTP_TOD_SEC_MSB(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 4, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:PTP_TOD_SEC_MSB */ +#define PTP_PTP_TOD_SEC_MSB(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 4, 0, 1,\ + 4) #define PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB GENMASK(15, 0) #define PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB_SET(x)\ @@ -6107,13 +6679,15 @@ enum sparx5_target { #define PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB_GET(x)\ FIELD_GET(PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB, x) -/* DEVCPU_PTP:PTP_PINS:PTP_TOD_SEC_LSB */ -#define PTP_PTP_TOD_SEC_LSB(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 8, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:PTP_TOD_SEC_LSB */ +#define PTP_PTP_TOD_SEC_LSB(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 8, 0, 1,\ + 4) -/* DEVCPU_PTP:PTP_PINS:PTP_TOD_NSEC */ -#define PTP_PTP_TOD_NSEC(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 12, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:PTP_TOD_NSEC */ +#define PTP_PTP_TOD_NSEC(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 12, 0, \ + 1, 4) #define PTP_PTP_TOD_NSEC_PTP_TOD_NSEC GENMASK(29, 0) #define PTP_PTP_TOD_NSEC_PTP_TOD_NSEC_SET(x)\ @@ -6121,9 +6695,10 @@ enum sparx5_target { #define PTP_PTP_TOD_NSEC_PTP_TOD_NSEC_GET(x)\ FIELD_GET(PTP_PTP_TOD_NSEC_PTP_TOD_NSEC, x) -/* DEVCPU_PTP:PTP_PINS:PTP_TOD_NSEC_FRAC */ -#define PTP_PTP_TOD_NSEC_FRAC(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 16, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:PTP_TOD_NSEC_FRAC */ +#define PTP_PTP_TOD_NSEC_FRAC(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 16, 0, \ + 1, 4) #define PTP_PTP_TOD_NSEC_FRAC_PTP_TOD_NSEC_FRAC GENMASK(7, 0) #define PTP_PTP_TOD_NSEC_FRAC_PTP_TOD_NSEC_FRAC_SET(x)\ @@ -6131,13 +6706,15 @@ enum sparx5_target { #define PTP_PTP_TOD_NSEC_FRAC_PTP_TOD_NSEC_FRAC_GET(x)\ FIELD_GET(PTP_PTP_TOD_NSEC_FRAC_PTP_TOD_NSEC_FRAC, x) -/* DEVCPU_PTP:PTP_PINS:NTP_NSEC */ -#define PTP_NTP_NSEC(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 20, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:NTP_NSEC */ +#define PTP_NTP_NSEC(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 20, 0, \ + 1, 4) -/* DEVCPU_PTP:PTP_PINS:PIN_WF_HIGH_PERIOD */ -#define PTP_PIN_WF_HIGH_PERIOD(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 24, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:PIN_WF_HIGH_PERIOD */ +#define PTP_PIN_WF_HIGH_PERIOD(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 24, 0, \ + 1, 4) #define PTP_PIN_WF_HIGH_PERIOD_PIN_WFH GENMASK(29, 0) #define PTP_PIN_WF_HIGH_PERIOD_PIN_WFH_SET(x)\ @@ -6145,9 +6722,10 @@ enum sparx5_target { #define PTP_PIN_WF_HIGH_PERIOD_PIN_WFH_GET(x)\ FIELD_GET(PTP_PIN_WF_HIGH_PERIOD_PIN_WFH, x) -/* DEVCPU_PTP:PTP_PINS:PIN_WF_LOW_PERIOD */ -#define PTP_PIN_WF_LOW_PERIOD(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 28, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:PIN_WF_LOW_PERIOD */ +#define PTP_PIN_WF_LOW_PERIOD(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 28, 0, \ + 1, 4) #define PTP_PIN_WF_LOW_PERIOD_PIN_WFL GENMASK(29, 0) #define PTP_PIN_WF_LOW_PERIOD_PIN_WFL_SET(x)\ @@ -6155,9 +6733,10 @@ enum sparx5_target { #define PTP_PIN_WF_LOW_PERIOD_PIN_WFL_GET(x)\ FIELD_GET(PTP_PIN_WF_LOW_PERIOD_PIN_WFL, x) -/* DEVCPU_PTP:PTP_PINS:PIN_IOBOUNCH_DELAY */ -#define PTP_PIN_IOBOUNCH_DELAY(g) __REG(TARGET_PTP,\ - 0, 1, 0, g, 5, 64, 32, 0, 1, 4) +/* DEVCPU_PTP:PTP_PINS:PIN_IOBOUNCH_DELAY */ +#define PTP_PIN_IOBOUNCH_DELAY(g) \ + __REG(TARGET_PTP, 0, 1, 0, g, regs->gcnt[GC_PTP_PTP_PINS], 64, 32, 0, \ + 1, 4) #define PTP_PIN_IOBOUNCH_DELAY_PIN_IOBOUNCH_VAL GENMASK(18, 3) #define PTP_PIN_IOBOUNCH_DELAY_PIN_IOBOUNCH_VAL_SET(x)\ @@ -6171,22 +6750,27 @@ enum sparx5_target { #define PTP_PIN_IOBOUNCH_DELAY_PIN_IOBOUNCH_CFG_GET(x)\ FIELD_GET(PTP_PIN_IOBOUNCH_DELAY_PIN_IOBOUNCH_CFG, x) -/* DEVCPU_PTP:PHASE_DETECTOR_CTRL:PHAD_CTRL */ -#define PTP_PHAD_CTRL(g) __REG(TARGET_PTP,\ - 0, 1, 420, g, 5, 8, 0, 0, 1, 4) +/* DEVCPU_PTP:PHASE_DETECTOR_CTRL:PHAD_CTRL */ +#define PTP_PHAD_CTRL(g) \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PHASE_DETECTOR_CTRL], g, \ + regs->gcnt[GC_PTP_PHASE_DETECTOR_CTRL], \ + regs->gsize[GW_PTP_PHASE_DETECTOR_CTRL], 0, 0, 1, 4) -#define PTP_PHAD_CTRL_PHAD_ENA BIT(7) +#define PTP_PHAD_CTRL_PHAD_ENA\ + BIT(regs->fpos[FP_PTP_PHAD_CTRL_PHAD_ENA]) #define PTP_PHAD_CTRL_PHAD_ENA_SET(x)\ - FIELD_PREP(PTP_PHAD_CTRL_PHAD_ENA, x) + spx5_field_prep(PTP_PHAD_CTRL_PHAD_ENA, x) #define PTP_PHAD_CTRL_PHAD_ENA_GET(x)\ - FIELD_GET(PTP_PHAD_CTRL_PHAD_ENA, x) + spx5_field_get(PTP_PHAD_CTRL_PHAD_ENA, x) -#define PTP_PHAD_CTRL_PHAD_FAILED BIT(6) +#define PTP_PHAD_CTRL_PHAD_FAILED\ + BIT(regs->fpos[FP_PTP_PHAD_CTRL_PHAD_FAILED]) #define PTP_PHAD_CTRL_PHAD_FAILED_SET(x)\ - FIELD_PREP(PTP_PHAD_CTRL_PHAD_FAILED, x) + spx5_field_prep(PTP_PHAD_CTRL_PHAD_FAILED, x) #define PTP_PHAD_CTRL_PHAD_FAILED_GET(x)\ - FIELD_GET(PTP_PHAD_CTRL_PHAD_FAILED, x) + spx5_field_get(PTP_PHAD_CTRL_PHAD_FAILED, x) +/* SPARX5 ONLY */ #define PTP_PHAD_CTRL_REDUCED_RES GENMASK(5, 3) #define PTP_PHAD_CTRL_REDUCED_RES_SET(x)\ FIELD_PREP(PTP_PHAD_CTRL_REDUCED_RES, x) @@ -6199,13 +6783,79 @@ enum sparx5_target { #define PTP_PHAD_CTRL_LOCK_ACC_GET(x)\ FIELD_GET(PTP_PHAD_CTRL_LOCK_ACC, x) -/* DEVCPU_PTP:PHASE_DETECTOR_CTRL:PHAD_CYC_STAT */ -#define PTP_PHAD_CYC_STAT(g) __REG(TARGET_PTP,\ - 0, 1, 420, g, 5, 8, 4, 0, 1, 4) - -/* QFWD:SYSTEM:SWITCH_PORT_MODE */ -#define QFWD_SWITCH_PORT_MODE(r) __REG(TARGET_QFWD,\ - 0, 1, 0, 0, 1, 340, 0, r, 70, 4) +/* DEVCPU_PTP:PHASE_DETECTOR_CTRL:PHAD_CYC_STAT */ +#define PTP_PHAD_CYC_STAT(g) \ + __REG(TARGET_PTP, 0, 1, regs->gaddr[GA_PTP_PHASE_DETECTOR_CTRL], g, \ + regs->gcnt[GC_PTP_PHASE_DETECTOR_CTRL], \ + regs->gsize[GW_PTP_PHASE_DETECTOR_CTRL], 4, 0, 1, 4) + +/* LAN969X ONLY */ +/* DEVCPU_PTP:PTP_TS_FIFO:PTP_TWOSTEP_CTRL */ +#define PTP_TWOSTEP_CTRL \ + __REG(TARGET_PTP, 0, 1, 612, 0, 1, 16, 0, 0, 1, 4) + +#define PTP_TWOSTEP_CTRL_PTP_OVWR_ENA BIT(12) +#define PTP_TWOSTEP_CTRL_PTP_OVWR_ENA_SET(x)\ + FIELD_PREP(PTP_TWOSTEP_CTRL_PTP_OVWR_ENA, x) +#define PTP_TWOSTEP_CTRL_PTP_OVWR_ENA_GET(x)\ + FIELD_GET(PTP_TWOSTEP_CTRL_PTP_OVWR_ENA, x) + +#define PTP_TWOSTEP_CTRL_PTP_NXT BIT(11) +#define PTP_TWOSTEP_CTRL_PTP_NXT_SET(x)\ + FIELD_PREP(PTP_TWOSTEP_CTRL_PTP_NXT, x) +#define PTP_TWOSTEP_CTRL_PTP_NXT_GET(x)\ + FIELD_GET(PTP_TWOSTEP_CTRL_PTP_NXT, x) + +#define PTP_TWOSTEP_CTRL_PTP_VLD BIT(10) +#define PTP_TWOSTEP_CTRL_PTP_VLD_SET(x)\ + FIELD_PREP(PTP_TWOSTEP_CTRL_PTP_VLD, x) +#define PTP_TWOSTEP_CTRL_PTP_VLD_GET(x)\ + FIELD_GET(PTP_TWOSTEP_CTRL_PTP_VLD, x) + +#define PTP_TWOSTEP_CTRL_STAMP_TX BIT(9) +#define PTP_TWOSTEP_CTRL_STAMP_TX_SET(x)\ + FIELD_PREP(PTP_TWOSTEP_CTRL_STAMP_TX, x) +#define PTP_TWOSTEP_CTRL_STAMP_TX_GET(x)\ + FIELD_GET(PTP_TWOSTEP_CTRL_STAMP_TX, x) + +#define PTP_TWOSTEP_CTRL_STAMP_PORT GENMASK(8, 1) +#define PTP_TWOSTEP_CTRL_STAMP_PORT_SET(x)\ + FIELD_PREP(PTP_TWOSTEP_CTRL_STAMP_PORT, x) +#define PTP_TWOSTEP_CTRL_STAMP_PORT_GET(x)\ + FIELD_GET(PTP_TWOSTEP_CTRL_STAMP_PORT, x) + +#define PTP_TWOSTEP_CTRL_PTP_OVFL BIT(0) +#define PTP_TWOSTEP_CTRL_PTP_OVFL_SET(x)\ + FIELD_PREP(PTP_TWOSTEP_CTRL_PTP_OVFL, x) +#define PTP_TWOSTEP_CTRL_PTP_OVFL_GET(x)\ + FIELD_GET(PTP_TWOSTEP_CTRL_PTP_OVFL, x) + +/* LAN969X ONLY */ +/* DEVCPU_PTP:PTP_TS_FIFO:PTP_TWOSTEP_STAMP_NSEC */ +#define PTP_TWOSTEP_STAMP_NSEC \ + __REG(TARGET_PTP, 0, 1, 612, 0, 1, 16, 4, 0, 1, 4) + +#define PTP_TWOSTEP_STAMP_NSEC_NS GENMASK(29, 0) +#define PTP_TWOSTEP_STAMP_NSEC_NS_SET(x)\ + FIELD_PREP(PTP_TWOSTEP_STAMP_NSEC_NS, x) +#define PTP_TWOSTEP_STAMP_NSEC_NS_GET(x)\ + FIELD_GET(PTP_TWOSTEP_STAMP_NSEC_NS, x) + +/* LAN969X ONLY */ +/* DEVCPU_PTP:PTP_TS_FIFO:PTP_TWOSTEP_STAMP_SUBNS */ +#define PTP_TWOSTEP_STAMP_SUBNS \ + __REG(TARGET_PTP, 0, 1, 612, 0, 1, 16, 8, 0, 1, 4) + +#define PTP_TWOSTEP_STAMP_SUBNS_NS GENMASK(7, 0) +#define PTP_TWOSTEP_STAMP_SUBNS_NS_SET(x)\ + FIELD_PREP(PTP_TWOSTEP_STAMP_SUBNS_NS, x) +#define PTP_TWOSTEP_STAMP_SUBNS_NS_GET(x)\ + FIELD_GET(PTP_TWOSTEP_STAMP_SUBNS_NS, x) + +/* QFWD:SYSTEM:SWITCH_PORT_MODE */ +#define QFWD_SWITCH_PORT_MODE(r) \ + __REG(TARGET_QFWD, 0, 1, 0, 0, 1, 340, 0, r, \ + regs->rcnt[RC_QFWD_SWITCH_PORT_MODE], 4) #define QFWD_SWITCH_PORT_MODE_PORT_ENA BIT(19) #define QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(x)\ @@ -6261,49 +6911,53 @@ enum sparx5_target { #define QFWD_SWITCH_PORT_MODE_LEARNALL_MORE_GET(x)\ FIELD_GET(QFWD_SWITCH_PORT_MODE_LEARNALL_MORE, x) -/* QFWD:SYSTEM:FRAME_COPY_CFG */ -#define QFWD_FRAME_COPY_CFG(r)\ +/* QFWD:SYSTEM:FRAME_COPY_CFG */ +#define QFWD_FRAME_COPY_CFG(r) \ __REG(TARGET_QFWD, 0, 1, 0, 0, 1, 340, 284, r, 12, 4) -#define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL GENMASK(12, 6) +#define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL\ + GENMASK(regs->fsize[FW_QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL] + 6 - 1, 6) #define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_SET(x)\ - FIELD_PREP(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, x) + spx5_field_prep(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, x) #define QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL_GET(x)\ - FIELD_GET(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, x) + spx5_field_get(QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, x) -/* QRES:RES_CTRL:RES_CFG */ -#define QRES_RES_CFG(g) __REG(TARGET_QRES,\ - 0, 1, 0, g, 5120, 16, 0, 0, 1, 4) +/* QRES:RES_CTRL:RES_CFG */ +#define QRES_RES_CFG(g) \ + __REG(TARGET_QRES, 0, 1, 0, g, 5120, 16, 0, 0, 1, 4) -#define QRES_RES_CFG_WM_HIGH GENMASK(11, 0) +#define QRES_RES_CFG_WM_HIGH\ + GENMASK(regs->fsize[FW_QRES_RES_CFG_WM_HIGH] + 0 - 1, 0) #define QRES_RES_CFG_WM_HIGH_SET(x)\ - FIELD_PREP(QRES_RES_CFG_WM_HIGH, x) + spx5_field_prep(QRES_RES_CFG_WM_HIGH, x) #define QRES_RES_CFG_WM_HIGH_GET(x)\ - FIELD_GET(QRES_RES_CFG_WM_HIGH, x) + spx5_field_get(QRES_RES_CFG_WM_HIGH, x) -/* QRES:RES_CTRL:RES_STAT */ -#define QRES_RES_STAT(g) __REG(TARGET_QRES,\ - 0, 1, 0, g, 5120, 16, 4, 0, 1, 4) +/* QRES:RES_CTRL:RES_STAT */ +#define QRES_RES_STAT(g) \ + __REG(TARGET_QRES, 0, 1, 0, g, 5120, 16, 4, 0, 1, 4) -#define QRES_RES_STAT_MAXUSE GENMASK(20, 0) +#define QRES_RES_STAT_MAXUSE\ + GENMASK(regs->fsize[FW_QRES_RES_STAT_MAXUSE] + 0 - 1, 0) #define QRES_RES_STAT_MAXUSE_SET(x)\ - FIELD_PREP(QRES_RES_STAT_MAXUSE, x) + spx5_field_prep(QRES_RES_STAT_MAXUSE, x) #define QRES_RES_STAT_MAXUSE_GET(x)\ - FIELD_GET(QRES_RES_STAT_MAXUSE, x) + spx5_field_get(QRES_RES_STAT_MAXUSE, x) -/* QRES:RES_CTRL:RES_STAT_CUR */ -#define QRES_RES_STAT_CUR(g) __REG(TARGET_QRES,\ - 0, 1, 0, g, 5120, 16, 8, 0, 1, 4) +/* QRES:RES_CTRL:RES_STAT_CUR */ +#define QRES_RES_STAT_CUR(g) \ + __REG(TARGET_QRES, 0, 1, 0, g, 5120, 16, 8, 0, 1, 4) -#define QRES_RES_STAT_CUR_INUSE GENMASK(20, 0) +#define QRES_RES_STAT_CUR_INUSE\ + GENMASK(regs->fsize[FW_QRES_RES_STAT_CUR_INUSE] + 0 - 1, 0) #define QRES_RES_STAT_CUR_INUSE_SET(x)\ - FIELD_PREP(QRES_RES_STAT_CUR_INUSE, x) + spx5_field_prep(QRES_RES_STAT_CUR_INUSE, x) #define QRES_RES_STAT_CUR_INUSE_GET(x)\ - FIELD_GET(QRES_RES_STAT_CUR_INUSE, x) + spx5_field_get(QRES_RES_STAT_CUR_INUSE, x) -/* DEVCPU_QS:XTR:XTR_GRP_CFG */ -#define QS_XTR_GRP_CFG(r) __REG(TARGET_QS,\ - 0, 1, 0, 0, 1, 36, 0, r, 2, 4) +/* DEVCPU_QS:XTR:XTR_GRP_CFG */ +#define QS_XTR_GRP_CFG(r) \ + __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 0, r, 2, 4) #define QS_XTR_GRP_CFG_MODE GENMASK(3, 2) #define QS_XTR_GRP_CFG_MODE_SET(x)\ @@ -6323,13 +6977,13 @@ enum sparx5_target { #define QS_XTR_GRP_CFG_BYTE_SWAP_GET(x)\ FIELD_GET(QS_XTR_GRP_CFG_BYTE_SWAP, x) -/* DEVCPU_QS:XTR:XTR_RD */ -#define QS_XTR_RD(r) __REG(TARGET_QS,\ - 0, 1, 0, 0, 1, 36, 8, r, 2, 4) +/* DEVCPU_QS:XTR:XTR_RD */ +#define QS_XTR_RD(r) \ + __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 8, r, 2, 4) -/* DEVCPU_QS:XTR:XTR_FLUSH */ -#define QS_XTR_FLUSH __REG(TARGET_QS,\ - 0, 1, 0, 0, 1, 36, 24, 0, 1, 4) +/* DEVCPU_QS:XTR:XTR_FLUSH */ +#define QS_XTR_FLUSH \ + __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 24, 0, 1, 4) #define QS_XTR_FLUSH_FLUSH GENMASK(1, 0) #define QS_XTR_FLUSH_FLUSH_SET(x)\ @@ -6337,9 +6991,9 @@ enum sparx5_target { #define QS_XTR_FLUSH_FLUSH_GET(x)\ FIELD_GET(QS_XTR_FLUSH_FLUSH, x) -/* DEVCPU_QS:XTR:XTR_DATA_PRESENT */ -#define QS_XTR_DATA_PRESENT __REG(TARGET_QS,\ - 0, 1, 0, 0, 1, 36, 28, 0, 1, 4) +/* DEVCPU_QS:XTR:XTR_DATA_PRESENT */ +#define QS_XTR_DATA_PRESENT \ + __REG(TARGET_QS, 0, 1, 0, 0, 1, 36, 28, 0, 1, 4) #define QS_XTR_DATA_PRESENT_DATA_PRESENT GENMASK(1, 0) #define QS_XTR_DATA_PRESENT_DATA_PRESENT_SET(x)\ @@ -6347,9 +7001,9 @@ enum sparx5_target { #define QS_XTR_DATA_PRESENT_DATA_PRESENT_GET(x)\ FIELD_GET(QS_XTR_DATA_PRESENT_DATA_PRESENT, x) -/* DEVCPU_QS:INJ:INJ_GRP_CFG */ -#define QS_INJ_GRP_CFG(r) __REG(TARGET_QS,\ - 0, 1, 36, 0, 1, 40, 0, r, 2, 4) +/* DEVCPU_QS:INJ:INJ_GRP_CFG */ +#define QS_INJ_GRP_CFG(r) \ + __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 0, r, 2, 4) #define QS_INJ_GRP_CFG_MODE GENMASK(3, 2) #define QS_INJ_GRP_CFG_MODE_SET(x)\ @@ -6363,13 +7017,13 @@ enum sparx5_target { #define QS_INJ_GRP_CFG_BYTE_SWAP_GET(x)\ FIELD_GET(QS_INJ_GRP_CFG_BYTE_SWAP, x) -/* DEVCPU_QS:INJ:INJ_WR */ -#define QS_INJ_WR(r) __REG(TARGET_QS,\ - 0, 1, 36, 0, 1, 40, 8, r, 2, 4) +/* DEVCPU_QS:INJ:INJ_WR */ +#define QS_INJ_WR(r) \ + __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 8, r, 2, 4) -/* DEVCPU_QS:INJ:INJ_CTRL */ -#define QS_INJ_CTRL(r) __REG(TARGET_QS,\ - 0, 1, 36, 0, 1, 40, 16, r, 2, 4) +/* DEVCPU_QS:INJ:INJ_CTRL */ +#define QS_INJ_CTRL(r) \ + __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 16, r, 2, 4) #define QS_INJ_CTRL_GAP_SIZE GENMASK(24, 21) #define QS_INJ_CTRL_GAP_SIZE_SET(x)\ @@ -6401,9 +7055,9 @@ enum sparx5_target { #define QS_INJ_CTRL_VLD_BYTES_GET(x)\ FIELD_GET(QS_INJ_CTRL_VLD_BYTES, x) -/* DEVCPU_QS:INJ:INJ_STATUS */ -#define QS_INJ_STATUS __REG(TARGET_QS,\ - 0, 1, 36, 0, 1, 40, 24, 0, 1, 4) +/* DEVCPU_QS:INJ:INJ_STATUS */ +#define QS_INJ_STATUS \ + __REG(TARGET_QS, 0, 1, 36, 0, 1, 40, 24, 0, 1, 4) #define QS_INJ_STATUS_WMARK_REACHED GENMASK(5, 4) #define QS_INJ_STATUS_WMARK_REACHED_SET(x)\ @@ -6423,21 +7077,24 @@ enum sparx5_target { #define QS_INJ_STATUS_INJ_IN_PROGRESS_GET(x)\ FIELD_GET(QS_INJ_STATUS_INJ_IN_PROGRESS, x) -/* QSYS:PAUSE_CFG:PAUSE_CFG */ -#define QSYS_PAUSE_CFG(r) __REG(TARGET_QSYS,\ - 0, 1, 544, 0, 1, 1128, 0, r, 70, 4) +/* QSYS:PAUSE_CFG:PAUSE_CFG */ +#define QSYS_PAUSE_CFG(r) \ + __REG(TARGET_QSYS, 0, 1, 544, 0, 1, regs->gsize[GW_QSYS_PAUSE_CFG], 0, \ + r, regs->rcnt[RC_QSYS_PAUSE_CFG], 4) -#define QSYS_PAUSE_CFG_PAUSE_START GENMASK(25, 14) +#define QSYS_PAUSE_CFG_PAUSE_START\ + GENMASK(regs->fsize[FW_QSYS_PAUSE_CFG_PAUSE_START] + 14 - 1, 14) #define QSYS_PAUSE_CFG_PAUSE_START_SET(x)\ - FIELD_PREP(QSYS_PAUSE_CFG_PAUSE_START, x) + spx5_field_prep(QSYS_PAUSE_CFG_PAUSE_START, x) #define QSYS_PAUSE_CFG_PAUSE_START_GET(x)\ - FIELD_GET(QSYS_PAUSE_CFG_PAUSE_START, x) + spx5_field_get(QSYS_PAUSE_CFG_PAUSE_START, x) -#define QSYS_PAUSE_CFG_PAUSE_STOP GENMASK(13, 2) +#define QSYS_PAUSE_CFG_PAUSE_STOP\ + GENMASK(regs->fsize[FW_QSYS_PAUSE_CFG_PAUSE_STOP] + 2 - 1, 2) #define QSYS_PAUSE_CFG_PAUSE_STOP_SET(x)\ - FIELD_PREP(QSYS_PAUSE_CFG_PAUSE_STOP, x) + spx5_field_prep(QSYS_PAUSE_CFG_PAUSE_STOP, x) #define QSYS_PAUSE_CFG_PAUSE_STOP_GET(x)\ - FIELD_GET(QSYS_PAUSE_CFG_PAUSE_STOP, x) + spx5_field_get(QSYS_PAUSE_CFG_PAUSE_STOP, x) #define QSYS_PAUSE_CFG_PAUSE_ENA BIT(1) #define QSYS_PAUSE_CFG_PAUSE_ENA_SET(x)\ @@ -6451,19 +7108,22 @@ enum sparx5_target { #define QSYS_PAUSE_CFG_AGGRESSIVE_TAILDROP_ENA_GET(x)\ FIELD_GET(QSYS_PAUSE_CFG_AGGRESSIVE_TAILDROP_ENA, x) -/* QSYS:PAUSE_CFG:ATOP */ -#define QSYS_ATOP(r) __REG(TARGET_QSYS,\ - 0, 1, 544, 0, 1, 1128, 284, r, 70, 4) +/* QSYS:PAUSE_CFG:ATOP */ +#define QSYS_ATOP(r) \ + __REG(TARGET_QSYS, 0, 1, 544, 0, 1, regs->gsize[GW_QSYS_PAUSE_CFG], \ + 284, r, regs->rcnt[RC_QSYS_ATOP], 4) -#define QSYS_ATOP_ATOP GENMASK(11, 0) +#define QSYS_ATOP_ATOP\ + GENMASK(regs->fsize[FW_QSYS_ATOP_ATOP] + 0 - 1, 0) #define QSYS_ATOP_ATOP_SET(x)\ - FIELD_PREP(QSYS_ATOP_ATOP, x) + spx5_field_prep(QSYS_ATOP_ATOP, x) #define QSYS_ATOP_ATOP_GET(x)\ - FIELD_GET(QSYS_ATOP_ATOP, x) + spx5_field_get(QSYS_ATOP_ATOP, x) -/* QSYS:PAUSE_CFG:FWD_PRESSURE */ -#define QSYS_FWD_PRESSURE(r) __REG(TARGET_QSYS,\ - 0, 1, 544, 0, 1, 1128, 564, r, 70, 4) +/* QSYS:PAUSE_CFG:FWD_PRESSURE */ +#define QSYS_FWD_PRESSURE(r) \ + __REG(TARGET_QSYS, 0, 1, 544, 0, 1, regs->gsize[GW_QSYS_PAUSE_CFG], \ + 564, r, regs->rcnt[RC_QSYS_FWD_PRESSURE], 4) #define QSYS_FWD_PRESSURE_FWD_PRESSURE GENMASK(11, 1) #define QSYS_FWD_PRESSURE_FWD_PRESSURE_SET(x)\ @@ -6477,19 +7137,22 @@ enum sparx5_target { #define QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS_GET(x)\ FIELD_GET(QSYS_FWD_PRESSURE_FWD_PRESSURE_DIS, x) -/* QSYS:PAUSE_CFG:ATOP_TOT_CFG */ -#define QSYS_ATOP_TOT_CFG __REG(TARGET_QSYS,\ - 0, 1, 544, 0, 1, 1128, 844, 0, 1, 4) +/* QSYS:PAUSE_CFG:ATOP_TOT_CFG */ +#define QSYS_ATOP_TOT_CFG \ + __REG(TARGET_QSYS, 0, 1, 544, 0, 1, regs->gsize[GW_QSYS_PAUSE_CFG], \ + 844, 0, 1, 4) -#define QSYS_ATOP_TOT_CFG_ATOP_TOT GENMASK(11, 0) +#define QSYS_ATOP_TOT_CFG_ATOP_TOT\ + GENMASK(regs->fsize[FW_QSYS_ATOP_TOT_CFG_ATOP_TOT] + 0 - 1, 0) #define QSYS_ATOP_TOT_CFG_ATOP_TOT_SET(x)\ - FIELD_PREP(QSYS_ATOP_TOT_CFG_ATOP_TOT, x) + spx5_field_prep(QSYS_ATOP_TOT_CFG_ATOP_TOT, x) #define QSYS_ATOP_TOT_CFG_ATOP_TOT_GET(x)\ - FIELD_GET(QSYS_ATOP_TOT_CFG_ATOP_TOT, x) + spx5_field_get(QSYS_ATOP_TOT_CFG_ATOP_TOT, x) -/* QSYS:CALCFG:CAL_AUTO */ -#define QSYS_CAL_AUTO(r) __REG(TARGET_QSYS,\ - 0, 1, 2304, 0, 1, 40, 0, r, 7, 4) +/* QSYS:CALCFG:CAL_AUTO */ +#define QSYS_CAL_AUTO(r) \ + __REG(TARGET_QSYS, 0, 1, regs->gaddr[GA_QSYS_CALCFG], 0, 1, 40, 0, r, \ + regs->rcnt[RC_QSYS_CAL_AUTO], 4) #define QSYS_CAL_AUTO_CAL_AUTO GENMASK(29, 0) #define QSYS_CAL_AUTO_CAL_AUTO_SET(x)\ @@ -6497,9 +7160,10 @@ enum sparx5_target { #define QSYS_CAL_AUTO_CAL_AUTO_GET(x)\ FIELD_GET(QSYS_CAL_AUTO_CAL_AUTO, x) -/* QSYS:CALCFG:CAL_CTRL */ -#define QSYS_CAL_CTRL __REG(TARGET_QSYS,\ - 0, 1, 2304, 0, 1, 40, 36, 0, 1, 4) +/* QSYS:CALCFG:CAL_CTRL */ +#define QSYS_CAL_CTRL \ + __REG(TARGET_QSYS, 0, 1, regs->gaddr[GA_QSYS_CALCFG], 0, 1, 40, 36, 0, \ + 1, 4) #define QSYS_CAL_CTRL_CAL_MODE GENMASK(14, 11) #define QSYS_CAL_CTRL_CAL_MODE_SET(x)\ @@ -6519,9 +7183,10 @@ enum sparx5_target { #define QSYS_CAL_CTRL_CAL_AUTO_ERROR_GET(x)\ FIELD_GET(QSYS_CAL_CTRL_CAL_AUTO_ERROR, x) -/* QSYS:RAM_CTRL:RAM_INIT */ -#define QSYS_RAM_INIT __REG(TARGET_QSYS,\ - 0, 1, 2344, 0, 1, 4, 0, 0, 1, 4) +/* QSYS:RAM_CTRL:RAM_INIT */ +#define QSYS_RAM_INIT \ + __REG(TARGET_QSYS, 0, 1, regs->gaddr[GA_QSYS_RAM_CTRL], 0, 1, 4, 0, 0, \ + 1, 4) #define QSYS_RAM_INIT_RAM_INIT BIT(1) #define QSYS_RAM_INIT_RAM_INIT_SET(x)\ @@ -6535,9 +7200,10 @@ enum sparx5_target { #define QSYS_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(QSYS_RAM_INIT_RAM_CFG_HOOK, x) -/* REW:COMMON:OWN_UPSID */ -#define REW_OWN_UPSID(r) __REG(TARGET_REW,\ - 0, 1, 387264, 0, 1, 1232, 0, r, 3, 4) +/* REW:COMMON:OWN_UPSID */ +#define REW_OWN_UPSID(r) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_COMMON], 0, 1, 1232, 0, r, \ + regs->rcnt[RC_REW_OWN_UPSID], 4) #define REW_OWN_UPSID_OWN_UPSID GENMASK(4, 0) #define REW_OWN_UPSID_OWN_UPSID_SET(x)\ @@ -6545,15 +7211,17 @@ enum sparx5_target { #define REW_OWN_UPSID_OWN_UPSID_GET(x)\ FIELD_GET(REW_OWN_UPSID_OWN_UPSID, x) -/* REW:COMMON:RTAG_ETAG_CTRL */ -#define REW_RTAG_ETAG_CTRL(r) __REG(TARGET_REW,\ - 0, 1, 387264, 0, 1, 1232, 560, r, 70, 4) +/* REW:COMMON:RTAG_ETAG_CTRL */ +#define REW_RTAG_ETAG_CTRL(r) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_COMMON], 0, 1, 1232, 560, r,\ + regs->rcnt[RC_REW_RTAG_ETAG_CTRL], 4) -#define REW_RTAG_ETAG_CTRL_IPE_TBL GENMASK(9, 3) +#define REW_RTAG_ETAG_CTRL_IPE_TBL\ + GENMASK(regs->fsize[FW_REW_RTAG_ETAG_CTRL_IPE_TBL] + 3 - 1, 3) #define REW_RTAG_ETAG_CTRL_IPE_TBL_SET(x)\ - FIELD_PREP(REW_RTAG_ETAG_CTRL_IPE_TBL, x) + spx5_field_prep(REW_RTAG_ETAG_CTRL_IPE_TBL, x) #define REW_RTAG_ETAG_CTRL_IPE_TBL_GET(x)\ - FIELD_GET(REW_RTAG_ETAG_CTRL_IPE_TBL, x) + spx5_field_get(REW_RTAG_ETAG_CTRL_IPE_TBL, x) #define REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA GENMASK(2, 1) #define REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_SET(x)\ @@ -6567,9 +7235,10 @@ enum sparx5_target { #define REW_RTAG_ETAG_CTRL_KEEP_ETAG_GET(x)\ FIELD_GET(REW_RTAG_ETAG_CTRL_KEEP_ETAG, x) -/* REW:COMMON:ES0_CTRL */ -#define REW_ES0_CTRL __REG(TARGET_REW,\ - 0, 1, 387264, 0, 1, 1232, 852, 0, 1, 4) +/* REW:COMMON:ES0_CTRL */ +#define REW_ES0_CTRL \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_COMMON], 0, 1, 1232, 852, 0,\ + 1, 4) #define REW_ES0_CTRL_ES0_BY_RT_FWD BIT(5) #define REW_ES0_CTRL_ES0_BY_RT_FWD_SET(x)\ @@ -6607,9 +7276,10 @@ enum sparx5_target { #define REW_ES0_CTRL_ES0_LU_ENA_GET(x)\ FIELD_GET(REW_ES0_CTRL_ES0_LU_ENA, x) -/* REW:PORT:PORT_VLAN_CFG */ -#define REW_PORT_VLAN_CFG(g) __REG(TARGET_REW,\ - 0, 1, 360448, g, 70, 256, 0, 0, 1, 4) +/* REW:PORT:PORT_VLAN_CFG */ +#define REW_PORT_VLAN_CFG(g) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_PORT], g, \ + regs->gcnt[GC_REW_PORT], 256, 0, 0, 1, 4) #define REW_PORT_VLAN_CFG_PORT_PCP GENMASK(15, 13) #define REW_PORT_VLAN_CFG_PORT_PCP_SET(x)\ @@ -6629,9 +7299,10 @@ enum sparx5_target { #define REW_PORT_VLAN_CFG_PORT_VID_GET(x)\ FIELD_GET(REW_PORT_VLAN_CFG_PORT_VID, x) -/* REW:PORT:PCP_MAP_DE0 */ -#define REW_PCP_MAP_DE0(g, r) __REG(TARGET_REW,\ - 0, 1, 360448, g, 70, 256, 4, r, 8, 4) +/* REW:PORT:PCP_MAP_DE0 */ +#define REW_PCP_MAP_DE0(g, r) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_PORT], g, \ + regs->gcnt[GC_REW_PORT], 256, 4, r, 8, 4) #define REW_PCP_MAP_DE0_PCP_DE0 GENMASK(2, 0) #define REW_PCP_MAP_DE0_PCP_DE0_SET(x)\ @@ -6639,9 +7310,10 @@ enum sparx5_target { #define REW_PCP_MAP_DE0_PCP_DE0_GET(x)\ FIELD_GET(REW_PCP_MAP_DE0_PCP_DE0, x) -/* REW:PORT:PCP_MAP_DE1 */ -#define REW_PCP_MAP_DE1(g, r) __REG(TARGET_REW,\ - 0, 1, 360448, g, 70, 256, 36, r, 8, 4) +/* REW:PORT:PCP_MAP_DE1 */ +#define REW_PCP_MAP_DE1(g, r) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_PORT], g, \ + regs->gcnt[GC_REW_PORT], 256, 36, r, 8, 4) #define REW_PCP_MAP_DE1_PCP_DE1 GENMASK(2, 0) #define REW_PCP_MAP_DE1_PCP_DE1_SET(x)\ @@ -6649,9 +7321,10 @@ enum sparx5_target { #define REW_PCP_MAP_DE1_PCP_DE1_GET(x)\ FIELD_GET(REW_PCP_MAP_DE1_PCP_DE1, x) -/* REW:PORT:DEI_MAP_DE0 */ -#define REW_DEI_MAP_DE0(g, r) __REG(TARGET_REW,\ - 0, 1, 360448, g, 70, 256, 68, r, 8, 4) +/* REW:PORT:DEI_MAP_DE0 */ +#define REW_DEI_MAP_DE0(g, r) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_PORT], g, \ + regs->gcnt[GC_REW_PORT], 256, 68, r, 8, 4) #define REW_DEI_MAP_DE0_DEI_DE0 BIT(0) #define REW_DEI_MAP_DE0_DEI_DE0_SET(x)\ @@ -6659,9 +7332,10 @@ enum sparx5_target { #define REW_DEI_MAP_DE0_DEI_DE0_GET(x)\ FIELD_GET(REW_DEI_MAP_DE0_DEI_DE0, x) -/* REW:PORT:DEI_MAP_DE1 */ -#define REW_DEI_MAP_DE1(g, r) __REG(TARGET_REW,\ - 0, 1, 360448, g, 70, 256, 100, r, 8, 4) +/* REW:PORT:DEI_MAP_DE1 */ +#define REW_DEI_MAP_DE1(g, r) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_PORT], g, \ + regs->gcnt[GC_REW_PORT], 256, 100, r, 8, 4) #define REW_DEI_MAP_DE1_DEI_DE1 BIT(0) #define REW_DEI_MAP_DE1_DEI_DE1_SET(x)\ @@ -6669,9 +7343,10 @@ enum sparx5_target { #define REW_DEI_MAP_DE1_DEI_DE1_GET(x)\ FIELD_GET(REW_DEI_MAP_DE1_DEI_DE1, x) -/* REW:PORT:TAG_CTRL */ -#define REW_TAG_CTRL(g) __REG(TARGET_REW,\ - 0, 1, 360448, g, 70, 256, 132, 0, 1, 4) +/* REW:PORT:TAG_CTRL */ +#define REW_TAG_CTRL(g) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_PORT], g, \ + regs->gcnt[GC_REW_PORT], 256, 132, 0, 1, 4) #define REW_TAG_CTRL_TAG_CFG_OBEY_WAS_TAGGED BIT(13) #define REW_TAG_CTRL_TAG_CFG_OBEY_WAS_TAGGED_SET(x)\ @@ -6709,9 +7384,10 @@ enum sparx5_target { #define REW_TAG_CTRL_TAG_DEI_CFG_GET(x)\ FIELD_GET(REW_TAG_CTRL_TAG_DEI_CFG, x) -/* REW:PORT:DSCP_MAP */ -#define REW_DSCP_MAP(g) __REG(TARGET_REW,\ - 0, 1, 360448, g, 70, 256, 136, 0, 1, 4) +/* REW:PORT:DSCP_MAP */ +#define REW_DSCP_MAP(g) \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_PORT], g, \ + regs->gcnt[GC_REW_PORT], 256, 136, 0, 1, 4) #define REW_DSCP_MAP_DSCP_UPDATE_ENA BIT(1) #define REW_DSCP_MAP_DSCP_UPDATE_ENA_SET(x)\ @@ -6725,9 +7401,10 @@ enum sparx5_target { #define REW_DSCP_MAP_DSCP_REMAP_ENA_GET(x)\ FIELD_GET(REW_DSCP_MAP_DSCP_REMAP_ENA, x) -/* REW:PTP_CTRL:PTP_TWOSTEP_CTRL */ -#define REW_PTP_TWOSTEP_CTRL __REG(TARGET_REW,\ - 0, 1, 378368, 0, 1, 40, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* REW:PTP_CTRL:PTP_TWOSTEP_CTRL */ +#define REW_PTP_TWOSTEP_CTRL \ + __REG(TARGET_REW, 0, 1, 378368, 0, 1, 40, 0, 0, 1, 4) #define REW_PTP_TWOSTEP_CTRL_PTP_OVWR_ENA BIT(12) #define REW_PTP_TWOSTEP_CTRL_PTP_OVWR_ENA_SET(x)\ @@ -6765,9 +7442,10 @@ enum sparx5_target { #define REW_PTP_TWOSTEP_CTRL_PTP_OVFL_GET(x)\ FIELD_GET(REW_PTP_TWOSTEP_CTRL_PTP_OVFL, x) -/* REW:PTP_CTRL:PTP_TWOSTEP_STAMP */ -#define REW_PTP_TWOSTEP_STAMP __REG(TARGET_REW,\ - 0, 1, 378368, 0, 1, 40, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* REW:PTP_CTRL:PTP_TWOSTEP_STAMP */ +#define REW_PTP_TWOSTEP_STAMP \ + __REG(TARGET_REW, 0, 1, 378368, 0, 1, 40, 4, 0, 1, 4) #define REW_PTP_TWOSTEP_STAMP_STAMP_NSEC GENMASK(29, 0) #define REW_PTP_TWOSTEP_STAMP_STAMP_NSEC_SET(x)\ @@ -6775,9 +7453,10 @@ enum sparx5_target { #define REW_PTP_TWOSTEP_STAMP_STAMP_NSEC_GET(x)\ FIELD_GET(REW_PTP_TWOSTEP_STAMP_STAMP_NSEC, x) -/* REW:PTP_CTRL:PTP_TWOSTEP_STAMP_SUBNS */ -#define REW_PTP_TWOSTEP_STAMP_SUBNS __REG(TARGET_REW,\ - 0, 1, 378368, 0, 1, 40, 8, 0, 1, 4) +/* SPARX5 ONLY */ +/* REW:PTP_CTRL:PTP_TWOSTEP_STAMP_SUBNS */ +#define REW_PTP_TWOSTEP_STAMP_SUBNS \ + __REG(TARGET_REW, 0, 1, 378368, 0, 1, 40, 8, 0, 1, 4) #define REW_PTP_TWOSTEP_STAMP_SUBNS_STAMP_SUB_NSEC GENMASK(7, 0) #define REW_PTP_TWOSTEP_STAMP_SUBNS_STAMP_SUB_NSEC_SET(x)\ @@ -6785,17 +7464,20 @@ enum sparx5_target { #define REW_PTP_TWOSTEP_STAMP_SUBNS_STAMP_SUB_NSEC_GET(x)\ FIELD_GET(REW_PTP_TWOSTEP_STAMP_SUBNS_STAMP_SUB_NSEC, x) -/* REW:PTP_CTRL:PTP_RSRV_NOT_ZERO */ -#define REW_PTP_RSRV_NOT_ZERO __REG(TARGET_REW,\ - 0, 1, 378368, 0, 1, 40, 12, 0, 1, 4) +/* SPARX5 ONLY */ +/* REW:PTP_CTRL:PTP_RSRV_NOT_ZERO */ +#define REW_PTP_RSRV_NOT_ZERO \ + __REG(TARGET_REW, 0, 1, 378368, 0, 1, 40, 12, 0, 1, 4) -/* REW:PTP_CTRL:PTP_RSRV_NOT_ZERO1 */ -#define REW_PTP_RSRV_NOT_ZERO1 __REG(TARGET_REW,\ - 0, 1, 378368, 0, 1, 40, 16, 0, 1, 4) +/* SPARX5 ONLY */ +/* REW:PTP_CTRL:PTP_RSRV_NOT_ZERO1 */ +#define REW_PTP_RSRV_NOT_ZERO1 \ + __REG(TARGET_REW, 0, 1, 378368, 0, 1, 40, 16, 0, 1, 4) -/* REW:PTP_CTRL:PTP_RSRV_NOT_ZERO2 */ -#define REW_PTP_RSRV_NOT_ZERO2 __REG(TARGET_REW,\ - 0, 1, 378368, 0, 1, 40, 20, 0, 1, 4) +/* SPARX5 ONLY */ +/* REW:PTP_CTRL:PTP_RSRV_NOT_ZERO2 */ +#define REW_PTP_RSRV_NOT_ZERO2 \ + __REG(TARGET_REW, 0, 1, 378368, 0, 1, 40, 20, 0, 1, 4) #define REW_PTP_RSRV_NOT_ZERO2_PTP_RSRV_NOT_ZERO2 GENMASK(5, 0) #define REW_PTP_RSRV_NOT_ZERO2_PTP_RSRV_NOT_ZERO2_SET(x)\ @@ -6803,9 +7485,10 @@ enum sparx5_target { #define REW_PTP_RSRV_NOT_ZERO2_PTP_RSRV_NOT_ZERO2_GET(x)\ FIELD_GET(REW_PTP_RSRV_NOT_ZERO2_PTP_RSRV_NOT_ZERO2, x) -/* REW:PTP_CTRL:PTP_GEN_STAMP_FMT */ -#define REW_PTP_GEN_STAMP_FMT(r) __REG(TARGET_REW,\ - 0, 1, 378368, 0, 1, 40, 24, r, 4, 4) +/* SPARX5 ONLY */ +/* REW:PTP_CTRL:PTP_GEN_STAMP_FMT */ +#define REW_PTP_GEN_STAMP_FMT(r) \ + __REG(TARGET_REW, 0, 1, 378368, 0, 1, 40, 24, r, 4, 4) #define REW_PTP_GEN_STAMP_FMT_RT_OFS GENMASK(6, 2) #define REW_PTP_GEN_STAMP_FMT_RT_OFS_SET(x)\ @@ -6819,9 +7502,10 @@ enum sparx5_target { #define REW_PTP_GEN_STAMP_FMT_RT_FMT_GET(x)\ FIELD_GET(REW_PTP_GEN_STAMP_FMT_RT_FMT, x) -/* REW:RAM_CTRL:RAM_INIT */ -#define REW_RAM_INIT __REG(TARGET_REW,\ - 0, 1, 378696, 0, 1, 4, 0, 0, 1, 4) +/* REW:RAM_CTRL:RAM_INIT */ +#define REW_RAM_INIT \ + __REG(TARGET_REW, 0, 1, regs->gaddr[GA_REW_RAM_CTRL], 0, 1, 4, 0, 0, 1,\ + 4) #define REW_RAM_INIT_RAM_INIT BIT(1) #define REW_RAM_INIT_RAM_INIT_SET(x)\ @@ -6835,9 +7519,9 @@ enum sparx5_target { #define REW_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(REW_RAM_INIT_RAM_CFG_HOOK, x) -/* VCAP_ES0:VCAP_CORE_CFG:VCAP_UPDATE_CTRL */ -#define VCAP_ES0_CTRL __REG(TARGET_VCAP_ES0,\ - 0, 1, 0, 0, 1, 8, 0, 0, 1, 4) +/* VCAP_ES0:VCAP_CORE_CFG:VCAP_UPDATE_CTRL */ +#define VCAP_ES0_CTRL \ + __REG(TARGET_VCAP_ES0, 0, 1, 0, 0, 1, 8, 0, 0, 1, 4) #define VCAP_ES0_CTRL_UPDATE_CMD GENMASK(24, 22) #define VCAP_ES0_CTRL_UPDATE_CMD_SET(x)\ @@ -6887,9 +7571,9 @@ enum sparx5_target { #define VCAP_ES0_CTRL_MV_TRAFFIC_IGN_GET(x)\ FIELD_GET(VCAP_ES0_CTRL_MV_TRAFFIC_IGN, x) -/* VCAP_ES0:VCAP_CORE_CFG:VCAP_MV_CFG */ -#define VCAP_ES0_CFG __REG(TARGET_VCAP_ES0,\ - 0, 1, 0, 0, 1, 8, 4, 0, 1, 4) +/* VCAP_ES0:VCAP_CORE_CFG:VCAP_MV_CFG */ +#define VCAP_ES0_CFG \ + __REG(TARGET_VCAP_ES0, 0, 1, 0, 0, 1, 8, 4, 0, 1, 4) #define VCAP_ES0_CFG_MV_NUM_POS GENMASK(31, 16) #define VCAP_ES0_CFG_MV_NUM_POS_SET(x)\ @@ -6903,33 +7587,33 @@ enum sparx5_target { #define VCAP_ES0_CFG_MV_SIZE_GET(x)\ FIELD_GET(VCAP_ES0_CFG_MV_SIZE, x) -/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_ENTRY_DAT */ -#define VCAP_ES0_VCAP_ENTRY_DAT(r) __REG(TARGET_VCAP_ES0,\ - 0, 1, 8, 0, 1, 904, 0, r, 64, 4) +/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_ENTRY_DAT */ +#define VCAP_ES0_VCAP_ENTRY_DAT(r) \ + __REG(TARGET_VCAP_ES0, 0, 1, 8, 0, 1, 904, 0, r, 64, 4) -/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_MASK_DAT */ -#define VCAP_ES0_VCAP_MASK_DAT(r) __REG(TARGET_VCAP_ES0,\ - 0, 1, 8, 0, 1, 904, 256, r, 64, 4) +/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_MASK_DAT */ +#define VCAP_ES0_VCAP_MASK_DAT(r) \ + __REG(TARGET_VCAP_ES0, 0, 1, 8, 0, 1, 904, 256, r, 64, 4) -/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_ACTION_DAT */ -#define VCAP_ES0_VCAP_ACTION_DAT(r) __REG(TARGET_VCAP_ES0,\ - 0, 1, 8, 0, 1, 904, 512, r, 64, 4) +/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_ACTION_DAT */ +#define VCAP_ES0_VCAP_ACTION_DAT(r) \ + __REG(TARGET_VCAP_ES0, 0, 1, 8, 0, 1, 904, 512, r, 64, 4) -/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_CNT_DAT */ -#define VCAP_ES0_VCAP_CNT_DAT(r) __REG(TARGET_VCAP_ES0,\ - 0, 1, 8, 0, 1, 904, 768, r, 32, 4) +/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_CNT_DAT */ +#define VCAP_ES0_VCAP_CNT_DAT(r) \ + __REG(TARGET_VCAP_ES0, 0, 1, 8, 0, 1, 904, 768, r, 32, 4) -/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_CNT_FW_DAT */ -#define VCAP_ES0_VCAP_CNT_FW_DAT __REG(TARGET_VCAP_ES0,\ - 0, 1, 8, 0, 1, 904, 896, 0, 1, 4) +/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_CNT_FW_DAT */ +#define VCAP_ES0_VCAP_CNT_FW_DAT \ + __REG(TARGET_VCAP_ES0, 0, 1, 8, 0, 1, 904, 896, 0, 1, 4) -/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_TG_DAT */ -#define VCAP_ES0_VCAP_TG_DAT __REG(TARGET_VCAP_ES0,\ - 0, 1, 8, 0, 1, 904, 900, 0, 1, 4) +/* VCAP_ES0:VCAP_CORE_CACHE:VCAP_TG_DAT */ +#define VCAP_ES0_VCAP_TG_DAT \ + __REG(TARGET_VCAP_ES0, 0, 1, 8, 0, 1, 904, 900, 0, 1, 4) -/* VCAP_ES0:VCAP_CORE_MAP:VCAP_CORE_IDX */ -#define VCAP_ES0_IDX __REG(TARGET_VCAP_ES0,\ - 0, 1, 912, 0, 1, 8, 0, 0, 1, 4) +/* VCAP_ES0:VCAP_CORE_MAP:VCAP_CORE_IDX */ +#define VCAP_ES0_IDX \ + __REG(TARGET_VCAP_ES0, 0, 1, 912, 0, 1, 8, 0, 0, 1, 4) #define VCAP_ES0_IDX_CORE_IDX GENMASK(3, 0) #define VCAP_ES0_IDX_CORE_IDX_SET(x)\ @@ -6937,9 +7621,9 @@ enum sparx5_target { #define VCAP_ES0_IDX_CORE_IDX_GET(x)\ FIELD_GET(VCAP_ES0_IDX_CORE_IDX, x) -/* VCAP_ES0:VCAP_CORE_MAP:VCAP_CORE_MAP */ -#define VCAP_ES0_MAP __REG(TARGET_VCAP_ES0,\ - 0, 1, 912, 0, 1, 8, 4, 0, 1, 4) +/* VCAP_ES0:VCAP_CORE_MAP:VCAP_CORE_MAP */ +#define VCAP_ES0_MAP \ + __REG(TARGET_VCAP_ES0, 0, 1, 912, 0, 1, 8, 4, 0, 1, 4) #define VCAP_ES0_MAP_CORE_MAP GENMASK(2, 0) #define VCAP_ES0_MAP_CORE_MAP_SET(x)\ @@ -6947,9 +7631,9 @@ enum sparx5_target { #define VCAP_ES0_MAP_CORE_MAP_GET(x)\ FIELD_GET(VCAP_ES0_MAP_CORE_MAP, x) -/* VCAP_ES0:VCAP_CORE_STICKY:VCAP_STICKY */ -#define VCAP_ES0_VCAP_STICKY __REG(TARGET_VCAP_ES0,\ - 0, 1, 920, 0, 1, 4, 0, 0, 1, 4) +/* VCAP_ES0:VCAP_CORE_STICKY:VCAP_STICKY */ +#define VCAP_ES0_VCAP_STICKY \ + __REG(TARGET_VCAP_ES0, 0, 1, 920, 0, 1, 4, 0, 0, 1, 4) #define VCAP_ES0_VCAP_STICKY_VCAP_ROW_DELETED_STICKY BIT(0) #define VCAP_ES0_VCAP_STICKY_VCAP_ROW_DELETED_STICKY_SET(x)\ @@ -6957,49 +7641,49 @@ enum sparx5_target { #define VCAP_ES0_VCAP_STICKY_VCAP_ROW_DELETED_STICKY_GET(x)\ FIELD_GET(VCAP_ES0_VCAP_STICKY_VCAP_ROW_DELETED_STICKY, x) -/* VCAP_ES0:VCAP_CONST:VCAP_VER */ -#define VCAP_ES0_VCAP_VER __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 0, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:VCAP_VER */ +#define VCAP_ES0_VCAP_VER \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 0, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:ENTRY_WIDTH */ -#define VCAP_ES0_ENTRY_WIDTH __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 4, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:ENTRY_WIDTH */ +#define VCAP_ES0_ENTRY_WIDTH \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 4, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:ENTRY_CNT */ -#define VCAP_ES0_ENTRY_CNT __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 8, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:ENTRY_CNT */ +#define VCAP_ES0_ENTRY_CNT \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 8, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:ENTRY_SWCNT */ -#define VCAP_ES0_ENTRY_SWCNT __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 12, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:ENTRY_SWCNT */ +#define VCAP_ES0_ENTRY_SWCNT \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 12, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:ENTRY_TG_WIDTH */ -#define VCAP_ES0_ENTRY_TG_WIDTH __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 16, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:ENTRY_TG_WIDTH */ +#define VCAP_ES0_ENTRY_TG_WIDTH \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 16, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:ACTION_DEF_CNT */ -#define VCAP_ES0_ACTION_DEF_CNT __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 20, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:ACTION_DEF_CNT */ +#define VCAP_ES0_ACTION_DEF_CNT \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 20, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:ACTION_WIDTH */ -#define VCAP_ES0_ACTION_WIDTH __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 24, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:ACTION_WIDTH */ +#define VCAP_ES0_ACTION_WIDTH \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 24, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:CNT_WIDTH */ -#define VCAP_ES0_CNT_WIDTH __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 28, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:CNT_WIDTH */ +#define VCAP_ES0_CNT_WIDTH \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 28, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:CORE_CNT */ -#define VCAP_ES0_CORE_CNT __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 32, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:CORE_CNT */ +#define VCAP_ES0_CORE_CNT \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 32, 0, 1, 4) -/* VCAP_ES0:VCAP_CONST:IF_CNT */ -#define VCAP_ES0_IF_CNT __REG(TARGET_VCAP_ES0,\ - 0, 1, 924, 0, 1, 40, 36, 0, 1, 4) +/* VCAP_ES0:VCAP_CONST:IF_CNT */ +#define VCAP_ES0_IF_CNT \ + __REG(TARGET_VCAP_ES0, 0, 1, 924, 0, 1, 40, 36, 0, 1, 4) -/* VCAP_ES2:VCAP_CORE_CFG:VCAP_UPDATE_CTRL */ -#define VCAP_ES2_CTRL __REG(TARGET_VCAP_ES2,\ - 0, 1, 0, 0, 1, 8, 0, 0, 1, 4) +/* VCAP_ES2:VCAP_CORE_CFG:VCAP_UPDATE_CTRL */ +#define VCAP_ES2_CTRL \ + __REG(TARGET_VCAP_ES2, 0, 1, 0, 0, 1, 8, 0, 0, 1, 4) #define VCAP_ES2_CTRL_UPDATE_CMD GENMASK(24, 22) #define VCAP_ES2_CTRL_UPDATE_CMD_SET(x)\ @@ -7049,9 +7733,9 @@ enum sparx5_target { #define VCAP_ES2_CTRL_MV_TRAFFIC_IGN_GET(x)\ FIELD_GET(VCAP_ES2_CTRL_MV_TRAFFIC_IGN, x) -/* VCAP_ES2:VCAP_CORE_CFG:VCAP_MV_CFG */ -#define VCAP_ES2_CFG __REG(TARGET_VCAP_ES2,\ - 0, 1, 0, 0, 1, 8, 4, 0, 1, 4) +/* VCAP_ES2:VCAP_CORE_CFG:VCAP_MV_CFG */ +#define VCAP_ES2_CFG \ + __REG(TARGET_VCAP_ES2, 0, 1, 0, 0, 1, 8, 4, 0, 1, 4) #define VCAP_ES2_CFG_MV_NUM_POS GENMASK(31, 16) #define VCAP_ES2_CFG_MV_NUM_POS_SET(x)\ @@ -7065,33 +7749,33 @@ enum sparx5_target { #define VCAP_ES2_CFG_MV_SIZE_GET(x)\ FIELD_GET(VCAP_ES2_CFG_MV_SIZE, x) -/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_ENTRY_DAT */ -#define VCAP_ES2_VCAP_ENTRY_DAT(r) __REG(TARGET_VCAP_ES2,\ - 0, 1, 8, 0, 1, 904, 0, r, 64, 4) +/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_ENTRY_DAT */ +#define VCAP_ES2_VCAP_ENTRY_DAT(r) \ + __REG(TARGET_VCAP_ES2, 0, 1, 8, 0, 1, 904, 0, r, 64, 4) -/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_MASK_DAT */ -#define VCAP_ES2_VCAP_MASK_DAT(r) __REG(TARGET_VCAP_ES2,\ - 0, 1, 8, 0, 1, 904, 256, r, 64, 4) +/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_MASK_DAT */ +#define VCAP_ES2_VCAP_MASK_DAT(r) \ + __REG(TARGET_VCAP_ES2, 0, 1, 8, 0, 1, 904, 256, r, 64, 4) -/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_ACTION_DAT */ -#define VCAP_ES2_VCAP_ACTION_DAT(r) __REG(TARGET_VCAP_ES2,\ - 0, 1, 8, 0, 1, 904, 512, r, 64, 4) +/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_ACTION_DAT */ +#define VCAP_ES2_VCAP_ACTION_DAT(r) \ + __REG(TARGET_VCAP_ES2, 0, 1, 8, 0, 1, 904, 512, r, 64, 4) -/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_CNT_DAT */ -#define VCAP_ES2_VCAP_CNT_DAT(r) __REG(TARGET_VCAP_ES2,\ - 0, 1, 8, 0, 1, 904, 768, r, 32, 4) +/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_CNT_DAT */ +#define VCAP_ES2_VCAP_CNT_DAT(r) \ + __REG(TARGET_VCAP_ES2, 0, 1, 8, 0, 1, 904, 768, r, 32, 4) -/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_CNT_FW_DAT */ -#define VCAP_ES2_VCAP_CNT_FW_DAT __REG(TARGET_VCAP_ES2,\ - 0, 1, 8, 0, 1, 904, 896, 0, 1, 4) +/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_CNT_FW_DAT */ +#define VCAP_ES2_VCAP_CNT_FW_DAT \ + __REG(TARGET_VCAP_ES2, 0, 1, 8, 0, 1, 904, 896, 0, 1, 4) -/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_TG_DAT */ -#define VCAP_ES2_VCAP_TG_DAT __REG(TARGET_VCAP_ES2,\ - 0, 1, 8, 0, 1, 904, 900, 0, 1, 4) +/* VCAP_ES2:VCAP_CORE_CACHE:VCAP_TG_DAT */ +#define VCAP_ES2_VCAP_TG_DAT \ + __REG(TARGET_VCAP_ES2, 0, 1, 8, 0, 1, 904, 900, 0, 1, 4) -/* VCAP_ES2:VCAP_CORE_MAP:VCAP_CORE_IDX */ -#define VCAP_ES2_IDX __REG(TARGET_VCAP_ES2,\ - 0, 1, 912, 0, 1, 8, 0, 0, 1, 4) +/* VCAP_ES2:VCAP_CORE_MAP:VCAP_CORE_IDX */ +#define VCAP_ES2_IDX \ + __REG(TARGET_VCAP_ES2, 0, 1, 912, 0, 1, 8, 0, 0, 1, 4) #define VCAP_ES2_IDX_CORE_IDX GENMASK(3, 0) #define VCAP_ES2_IDX_CORE_IDX_SET(x)\ @@ -7099,9 +7783,9 @@ enum sparx5_target { #define VCAP_ES2_IDX_CORE_IDX_GET(x)\ FIELD_GET(VCAP_ES2_IDX_CORE_IDX, x) -/* VCAP_ES2:VCAP_CORE_MAP:VCAP_CORE_MAP */ -#define VCAP_ES2_MAP __REG(TARGET_VCAP_ES2,\ - 0, 1, 912, 0, 1, 8, 4, 0, 1, 4) +/* VCAP_ES2:VCAP_CORE_MAP:VCAP_CORE_MAP */ +#define VCAP_ES2_MAP \ + __REG(TARGET_VCAP_ES2, 0, 1, 912, 0, 1, 8, 4, 0, 1, 4) #define VCAP_ES2_MAP_CORE_MAP GENMASK(2, 0) #define VCAP_ES2_MAP_CORE_MAP_SET(x)\ @@ -7109,9 +7793,9 @@ enum sparx5_target { #define VCAP_ES2_MAP_CORE_MAP_GET(x)\ FIELD_GET(VCAP_ES2_MAP_CORE_MAP, x) -/* VCAP_ES2:VCAP_CORE_STICKY:VCAP_STICKY */ -#define VCAP_ES2_VCAP_STICKY __REG(TARGET_VCAP_ES2,\ - 0, 1, 920, 0, 1, 4, 0, 0, 1, 4) +/* VCAP_ES2:VCAP_CORE_STICKY:VCAP_STICKY */ +#define VCAP_ES2_VCAP_STICKY \ + __REG(TARGET_VCAP_ES2, 0, 1, 920, 0, 1, 4, 0, 0, 1, 4) #define VCAP_ES2_VCAP_STICKY_VCAP_ROW_DELETED_STICKY BIT(0) #define VCAP_ES2_VCAP_STICKY_VCAP_ROW_DELETED_STICKY_SET(x)\ @@ -7119,49 +7803,49 @@ enum sparx5_target { #define VCAP_ES2_VCAP_STICKY_VCAP_ROW_DELETED_STICKY_GET(x)\ FIELD_GET(VCAP_ES2_VCAP_STICKY_VCAP_ROW_DELETED_STICKY, x) -/* VCAP_ES2:VCAP_CONST:VCAP_VER */ -#define VCAP_ES2_VCAP_VER __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 0, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:VCAP_VER */ +#define VCAP_ES2_VCAP_VER \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 0, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:ENTRY_WIDTH */ -#define VCAP_ES2_ENTRY_WIDTH __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 4, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:ENTRY_WIDTH */ +#define VCAP_ES2_ENTRY_WIDTH \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 4, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:ENTRY_CNT */ -#define VCAP_ES2_ENTRY_CNT __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 8, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:ENTRY_CNT */ +#define VCAP_ES2_ENTRY_CNT \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 8, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:ENTRY_SWCNT */ -#define VCAP_ES2_ENTRY_SWCNT __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 12, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:ENTRY_SWCNT */ +#define VCAP_ES2_ENTRY_SWCNT \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 12, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:ENTRY_TG_WIDTH */ -#define VCAP_ES2_ENTRY_TG_WIDTH __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 16, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:ENTRY_TG_WIDTH */ +#define VCAP_ES2_ENTRY_TG_WIDTH \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 16, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:ACTION_DEF_CNT */ -#define VCAP_ES2_ACTION_DEF_CNT __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 20, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:ACTION_DEF_CNT */ +#define VCAP_ES2_ACTION_DEF_CNT \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 20, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:ACTION_WIDTH */ -#define VCAP_ES2_ACTION_WIDTH __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 24, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:ACTION_WIDTH */ +#define VCAP_ES2_ACTION_WIDTH \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 24, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:CNT_WIDTH */ -#define VCAP_ES2_CNT_WIDTH __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 28, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:CNT_WIDTH */ +#define VCAP_ES2_CNT_WIDTH \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 28, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:CORE_CNT */ -#define VCAP_ES2_CORE_CNT __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 32, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:CORE_CNT */ +#define VCAP_ES2_CORE_CNT \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 32, 0, 1, 4) -/* VCAP_ES2:VCAP_CONST:IF_CNT */ -#define VCAP_ES2_IF_CNT __REG(TARGET_VCAP_ES2,\ - 0, 1, 924, 0, 1, 40, 36, 0, 1, 4) +/* VCAP_ES2:VCAP_CONST:IF_CNT */ +#define VCAP_ES2_IF_CNT \ + __REG(TARGET_VCAP_ES2, 0, 1, 924, 0, 1, 40, 36, 0, 1, 4) -/* VCAP_SUPER:VCAP_CORE_CFG:VCAP_UPDATE_CTRL */ -#define VCAP_SUPER_CTRL __REG(TARGET_VCAP_SUPER,\ - 0, 1, 0, 0, 1, 8, 0, 0, 1, 4) +/* VCAP_SUPER:VCAP_CORE_CFG:VCAP_UPDATE_CTRL */ +#define VCAP_SUPER_CTRL \ + __REG(TARGET_VCAP_SUPER, 0, 1, 0, 0, 1, 8, 0, 0, 1, 4) #define VCAP_SUPER_CTRL_UPDATE_CMD GENMASK(24, 22) #define VCAP_SUPER_CTRL_UPDATE_CMD_SET(x)\ @@ -7211,9 +7895,9 @@ enum sparx5_target { #define VCAP_SUPER_CTRL_MV_TRAFFIC_IGN_GET(x)\ FIELD_GET(VCAP_SUPER_CTRL_MV_TRAFFIC_IGN, x) -/* VCAP_SUPER:VCAP_CORE_CFG:VCAP_MV_CFG */ -#define VCAP_SUPER_CFG __REG(TARGET_VCAP_SUPER,\ - 0, 1, 0, 0, 1, 8, 4, 0, 1, 4) +/* VCAP_SUPER:VCAP_CORE_CFG:VCAP_MV_CFG */ +#define VCAP_SUPER_CFG \ + __REG(TARGET_VCAP_SUPER, 0, 1, 0, 0, 1, 8, 4, 0, 1, 4) #define VCAP_SUPER_CFG_MV_NUM_POS GENMASK(31, 16) #define VCAP_SUPER_CFG_MV_NUM_POS_SET(x)\ @@ -7227,33 +7911,33 @@ enum sparx5_target { #define VCAP_SUPER_CFG_MV_SIZE_GET(x)\ FIELD_GET(VCAP_SUPER_CFG_MV_SIZE, x) -/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_ENTRY_DAT */ -#define VCAP_SUPER_VCAP_ENTRY_DAT(r) __REG(TARGET_VCAP_SUPER,\ - 0, 1, 8, 0, 1, 904, 0, r, 64, 4) +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_ENTRY_DAT */ +#define VCAP_SUPER_VCAP_ENTRY_DAT(r) \ + __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 0, r, 64, 4) -/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_MASK_DAT */ -#define VCAP_SUPER_VCAP_MASK_DAT(r) __REG(TARGET_VCAP_SUPER,\ - 0, 1, 8, 0, 1, 904, 256, r, 64, 4) +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_MASK_DAT */ +#define VCAP_SUPER_VCAP_MASK_DAT(r) \ + __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 256, r, 64, 4) -/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_ACTION_DAT */ -#define VCAP_SUPER_VCAP_ACTION_DAT(r) __REG(TARGET_VCAP_SUPER,\ - 0, 1, 8, 0, 1, 904, 512, r, 64, 4) +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_ACTION_DAT */ +#define VCAP_SUPER_VCAP_ACTION_DAT(r) \ + __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 512, r, 64, 4) -/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_CNT_DAT */ -#define VCAP_SUPER_VCAP_CNT_DAT(r) __REG(TARGET_VCAP_SUPER,\ - 0, 1, 8, 0, 1, 904, 768, r, 32, 4) +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_CNT_DAT */ +#define VCAP_SUPER_VCAP_CNT_DAT(r) \ + __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 768, r, 32, 4) -/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_CNT_FW_DAT */ -#define VCAP_SUPER_VCAP_CNT_FW_DAT __REG(TARGET_VCAP_SUPER,\ - 0, 1, 8, 0, 1, 904, 896, 0, 1, 4) +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_CNT_FW_DAT */ +#define VCAP_SUPER_VCAP_CNT_FW_DAT \ + __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 896, 0, 1, 4) -/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_TG_DAT */ -#define VCAP_SUPER_VCAP_TG_DAT __REG(TARGET_VCAP_SUPER,\ - 0, 1, 8, 0, 1, 904, 900, 0, 1, 4) +/* VCAP_SUPER:VCAP_CORE_CACHE:VCAP_TG_DAT */ +#define VCAP_SUPER_VCAP_TG_DAT \ + __REG(TARGET_VCAP_SUPER, 0, 1, 8, 0, 1, 904, 900, 0, 1, 4) -/* VCAP_SUPER:VCAP_CORE_MAP:VCAP_CORE_IDX */ -#define VCAP_SUPER_IDX __REG(TARGET_VCAP_SUPER,\ - 0, 1, 912, 0, 1, 8, 0, 0, 1, 4) +/* VCAP_SUPER:VCAP_CORE_MAP:VCAP_CORE_IDX */ +#define VCAP_SUPER_IDX \ + __REG(TARGET_VCAP_SUPER, 0, 1, 912, 0, 1, 8, 0, 0, 1, 4) #define VCAP_SUPER_IDX_CORE_IDX GENMASK(3, 0) #define VCAP_SUPER_IDX_CORE_IDX_SET(x)\ @@ -7261,9 +7945,9 @@ enum sparx5_target { #define VCAP_SUPER_IDX_CORE_IDX_GET(x)\ FIELD_GET(VCAP_SUPER_IDX_CORE_IDX, x) -/* VCAP_SUPER:VCAP_CORE_MAP:VCAP_CORE_MAP */ -#define VCAP_SUPER_MAP __REG(TARGET_VCAP_SUPER,\ - 0, 1, 912, 0, 1, 8, 4, 0, 1, 4) +/* VCAP_SUPER:VCAP_CORE_MAP:VCAP_CORE_MAP */ +#define VCAP_SUPER_MAP \ + __REG(TARGET_VCAP_SUPER, 0, 1, 912, 0, 1, 8, 4, 0, 1, 4) #define VCAP_SUPER_MAP_CORE_MAP GENMASK(2, 0) #define VCAP_SUPER_MAP_CORE_MAP_SET(x)\ @@ -7271,49 +7955,49 @@ enum sparx5_target { #define VCAP_SUPER_MAP_CORE_MAP_GET(x)\ FIELD_GET(VCAP_SUPER_MAP_CORE_MAP, x) -/* VCAP_SUPER:VCAP_CONST:VCAP_VER */ -#define VCAP_SUPER_VCAP_VER __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 0, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:VCAP_VER */ +#define VCAP_SUPER_VCAP_VER \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 0, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:ENTRY_WIDTH */ -#define VCAP_SUPER_ENTRY_WIDTH __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 4, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:ENTRY_WIDTH */ +#define VCAP_SUPER_ENTRY_WIDTH \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 4, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:ENTRY_CNT */ -#define VCAP_SUPER_ENTRY_CNT __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 8, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:ENTRY_CNT */ +#define VCAP_SUPER_ENTRY_CNT \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 8, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:ENTRY_SWCNT */ -#define VCAP_SUPER_ENTRY_SWCNT __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 12, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:ENTRY_SWCNT */ +#define VCAP_SUPER_ENTRY_SWCNT \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 12, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:ENTRY_TG_WIDTH */ -#define VCAP_SUPER_ENTRY_TG_WIDTH __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 16, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:ENTRY_TG_WIDTH */ +#define VCAP_SUPER_ENTRY_TG_WIDTH \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 16, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:ACTION_DEF_CNT */ -#define VCAP_SUPER_ACTION_DEF_CNT __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 20, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:ACTION_DEF_CNT */ +#define VCAP_SUPER_ACTION_DEF_CNT \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 20, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:ACTION_WIDTH */ -#define VCAP_SUPER_ACTION_WIDTH __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 24, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:ACTION_WIDTH */ +#define VCAP_SUPER_ACTION_WIDTH \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 24, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:CNT_WIDTH */ -#define VCAP_SUPER_CNT_WIDTH __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 28, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:CNT_WIDTH */ +#define VCAP_SUPER_CNT_WIDTH \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 28, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:CORE_CNT */ -#define VCAP_SUPER_CORE_CNT __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 32, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:CORE_CNT */ +#define VCAP_SUPER_CORE_CNT \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 32, 0, 1, 4) -/* VCAP_SUPER:VCAP_CONST:IF_CNT */ -#define VCAP_SUPER_IF_CNT __REG(TARGET_VCAP_SUPER,\ - 0, 1, 924, 0, 1, 40, 36, 0, 1, 4) +/* VCAP_SUPER:VCAP_CONST:IF_CNT */ +#define VCAP_SUPER_IF_CNT \ + __REG(TARGET_VCAP_SUPER, 0, 1, 924, 0, 1, 40, 36, 0, 1, 4) -/* VCAP_SUPER:RAM_CTRL:RAM_INIT */ -#define VCAP_SUPER_RAM_INIT __REG(TARGET_VCAP_SUPER,\ - 0, 1, 1120, 0, 1, 4, 0, 0, 1, 4) +/* VCAP_SUPER:RAM_CTRL:RAM_INIT */ +#define VCAP_SUPER_RAM_INIT \ + __REG(TARGET_VCAP_SUPER, 0, 1, 1120, 0, 1, 4, 0, 0, 1, 4) #define VCAP_SUPER_RAM_INIT_RAM_INIT BIT(1) #define VCAP_SUPER_RAM_INIT_RAM_INIT_SET(x)\ @@ -7327,9 +8011,10 @@ enum sparx5_target { #define VCAP_SUPER_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(VCAP_SUPER_RAM_INIT_RAM_CFG_HOOK, x) -/* VOP:RAM_CTRL:RAM_INIT */ -#define VOP_RAM_INIT __REG(TARGET_VOP,\ - 0, 1, 279176, 0, 1, 4, 0, 0, 1, 4) +/* VOP:RAM_CTRL:RAM_INIT */ +#define VOP_RAM_INIT \ + __REG(TARGET_VOP, 0, 1, regs->gaddr[GA_VOP_RAM_CTRL], 0, 1, 4, 0, 0, 1,\ + 4) #define VOP_RAM_INIT_RAM_INIT BIT(1) #define VOP_RAM_INIT_RAM_INIT_SET(x)\ @@ -7343,9 +8028,10 @@ enum sparx5_target { #define VOP_RAM_INIT_RAM_CFG_HOOK_GET(x)\ FIELD_GET(VOP_RAM_INIT_RAM_CFG_HOOK, x) -/* XQS:SYSTEM:STAT_CFG */ -#define XQS_STAT_CFG __REG(TARGET_XQS,\ - 0, 1, 6768, 0, 1, 872, 860, 0, 1, 4) +/* XQS:SYSTEM:STAT_CFG */ +#define XQS_STAT_CFG \ + __REG(TARGET_XQS, 0, 1, regs->gaddr[GA_XQS_SYSTEM], 0, 1, 872, 860, 0, \ + 1, 4) #define XQS_STAT_CFG_STAT_CLEAR_SHOT GENMASK(21, 18) #define XQS_STAT_CFG_STAT_CLEAR_SHOT_SET(x)\ @@ -7353,11 +8039,12 @@ enum sparx5_target { #define XQS_STAT_CFG_STAT_CLEAR_SHOT_GET(x)\ FIELD_GET(XQS_STAT_CFG_STAT_CLEAR_SHOT, x) -#define XQS_STAT_CFG_STAT_VIEW GENMASK(17, 5) +#define XQS_STAT_CFG_STAT_VIEW\ + GENMASK(regs->fsize[FW_XQS_STAT_CFG_STAT_VIEW] + 5 - 1, 5) #define XQS_STAT_CFG_STAT_VIEW_SET(x)\ - FIELD_PREP(XQS_STAT_CFG_STAT_VIEW, x) + spx5_field_prep(XQS_STAT_CFG_STAT_VIEW, x) #define XQS_STAT_CFG_STAT_VIEW_GET(x)\ - FIELD_GET(XQS_STAT_CFG_STAT_VIEW, x) + spx5_field_get(XQS_STAT_CFG_STAT_VIEW, x) #define XQS_STAT_CFG_STAT_SRV_PKT_ONLY BIT(4) #define XQS_STAT_CFG_STAT_SRV_PKT_ONLY_SET(x)\ @@ -7371,48 +8058,56 @@ enum sparx5_target { #define XQS_STAT_CFG_STAT_WRAP_DIS_GET(x)\ FIELD_GET(XQS_STAT_CFG_STAT_WRAP_DIS, x) -/* XQS:QLIMIT_SHR:QLIMIT_SHR_TOP_CFG */ -#define XQS_QLIMIT_SHR_TOP_CFG(g) __REG(TARGET_XQS,\ - 0, 1, 7936, g, 4, 48, 0, 0, 1, 4) +/* XQS:QLIMIT_SHR:QLIMIT_SHR_TOP_CFG */ +#define XQS_QLIMIT_SHR_TOP_CFG(g) \ + __REG(TARGET_XQS, 0, 1, regs->gaddr[GA_XQS_QLIMIT_SHR], g, 4, 48, 0, 0,\ + 1, 4) -#define XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP GENMASK(14, 0) +#define XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP\ + GENMASK(regs->fsize[FW_XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP] + 0 - 1, 0) #define XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP_SET(x)\ - FIELD_PREP(XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP, x) + spx5_field_prep(XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP, x) #define XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP_GET(x)\ - FIELD_GET(XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP, x) + spx5_field_get(XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP, x) -/* XQS:QLIMIT_SHR:QLIMIT_SHR_ATOP_CFG */ -#define XQS_QLIMIT_SHR_ATOP_CFG(g) __REG(TARGET_XQS,\ - 0, 1, 7936, g, 4, 48, 4, 0, 1, 4) +/* XQS:QLIMIT_SHR:QLIMIT_SHR_ATOP_CFG */ +#define XQS_QLIMIT_SHR_ATOP_CFG(g) \ + __REG(TARGET_XQS, 0, 1, regs->gaddr[GA_XQS_QLIMIT_SHR], g, 4, 48, 4, 0,\ + 1, 4) -#define XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP GENMASK(14, 0) +#define XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP\ + GENMASK(regs->fsize[FW_XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP] + 0 - 1, 0) #define XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP_SET(x)\ - FIELD_PREP(XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP, x) + spx5_field_prep(XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP, x) #define XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP_GET(x)\ - FIELD_GET(XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP, x) + spx5_field_get(XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP, x) -/* XQS:QLIMIT_SHR:QLIMIT_SHR_CTOP_CFG */ -#define XQS_QLIMIT_SHR_CTOP_CFG(g) __REG(TARGET_XQS,\ - 0, 1, 7936, g, 4, 48, 8, 0, 1, 4) +/* XQS:QLIMIT_SHR:QLIMIT_SHR_CTOP_CFG */ +#define XQS_QLIMIT_SHR_CTOP_CFG(g) \ + __REG(TARGET_XQS, 0, 1, regs->gaddr[GA_XQS_QLIMIT_SHR], g, 4, 48, 8, 0,\ + 1, 4) -#define XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP GENMASK(14, 0) +#define XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP\ + GENMASK(regs->fsize[FW_XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP] + 0 - 1, 0) #define XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP_SET(x)\ - FIELD_PREP(XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP, x) + spx5_field_prep(XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP, x) #define XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP_GET(x)\ - FIELD_GET(XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP, x) + spx5_field_get(XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP, x) -/* XQS:QLIMIT_SHR:QLIMIT_SHR_QLIM_CFG */ -#define XQS_QLIMIT_SHR_QLIM_CFG(g) __REG(TARGET_XQS,\ - 0, 1, 7936, g, 4, 48, 12, 0, 1, 4) +/* XQS:QLIMIT_SHR:QLIMIT_SHR_QLIM_CFG */ +#define XQS_QLIMIT_SHR_QLIM_CFG(g) \ + __REG(TARGET_XQS, 0, 1, regs->gaddr[GA_XQS_QLIMIT_SHR], g, 4, 48, 12, \ + 0, 1, 4) -#define XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM GENMASK(14, 0) +#define XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM\ + GENMASK(regs->fsize[FW_XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM] + 0 - 1, 0) #define XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM_SET(x)\ - FIELD_PREP(XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM, x) + spx5_field_prep(XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM, x) #define XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM_GET(x)\ - FIELD_GET(XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM, x) + spx5_field_get(XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM, x) -/* XQS:STAT:CNT */ -#define XQS_CNT(g) __REG(TARGET_XQS,\ - 0, 1, 0, g, 1024, 4, 0, 0, 1, 4) +/* XQS:STAT:CNT */ +#define XQS_CNT(g) \ + __REG(TARGET_XQS, 0, 1, 0, g, 1024, 4, 0, 0, 1, 4) #endif /* _SPARX5_MAIN_REGS_H_ */ diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c b/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c index 459a53676ae964..76097761fa9776 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mirror.c @@ -12,7 +12,6 @@ #define SPX5_MIRROR_DISABLED 0 #define SPX5_MIRROR_EGRESS 1 #define SPX5_MIRROR_INGRESS 2 -#define SPX5_MIRROR_MONITOR_PORT_DEFAULT 65 #define SPX5_QFWD_MP_OFFSET 9 /* Mirror port offset in the QFWD register */ /* Convert from bool ingress/egress to mirror direction */ @@ -24,8 +23,14 @@ static u32 sparx5_mirror_to_dir(bool ingress) /* Get ports belonging to this mirror */ static u64 sparx5_mirror_port_get(struct sparx5 *sparx5, u32 idx) { - return (u64)spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG1(idx)) << 32 | - spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG(idx)); + u64 val; + + val = spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG(idx)); + + if (is_sparx5(sparx5)) + val |= (u64)spx5_rd(sparx5, ANA_AC_PROBE_PORT_CFG1(idx)) << 32; + + return val; } /* Add port to mirror (only front ports) */ @@ -194,7 +199,7 @@ void sparx5_mirror_del(struct sparx5_mall_entry *entry) sparx5_mirror_monitor_set(sparx5, mirror_idx, - SPX5_MIRROR_MONITOR_PORT_DEFAULT); + sparx5->data->consts->n_ports); } void sparx5_mirror_stats(struct sparx5_mall_entry *entry, diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c index 705a004b324fdf..1d34af78166a3e 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c @@ -55,7 +55,7 @@ static void __ifh_encode_bitfield(void *ifh, u64 value, u32 pos, u32 width) ifh_hdr[byte - 5] |= (u8)((encode & 0xFF0000000000) >> 40); } -void sparx5_set_port_ifh(void *ifh_hdr, u16 portno) +void sparx5_set_port_ifh(struct sparx5 *sparx5, void *ifh_hdr, u16 portno) { /* VSTAX.RSV = 1. MSBit must be 1 */ ifh_encode_bitfield(ifh_hdr, 1, VSTAX + 79, 1); @@ -64,15 +64,16 @@ void sparx5_set_port_ifh(void *ifh_hdr, u16 portno) /* MISC.CPU_MASK/DPORT = Destination port */ ifh_encode_bitfield(ifh_hdr, portno, 29, 8); /* MISC.PIPELINE_PT */ - ifh_encode_bitfield(ifh_hdr, 16, 37, 5); + ifh_encode_bitfield(ifh_hdr, is_sparx5(sparx5) ? 16 : 17, 37, 5); /* MISC.PIPELINE_ACT */ ifh_encode_bitfield(ifh_hdr, 1, 42, 3); /* FWD.SRC_PORT = CPU */ - ifh_encode_bitfield(ifh_hdr, SPX5_PORT_CPU, 46, 7); + ifh_encode_bitfield(ifh_hdr, sparx5_get_pgid(sparx5, SPX5_PORT_CPU_0), + 46, is_sparx5(sparx5) ? 7 : 6); /* FWD.SFLOW_ID (disable SFlow sampling) */ - ifh_encode_bitfield(ifh_hdr, 124, 57, 7); + ifh_encode_bitfield(ifh_hdr, 124, is_sparx5(sparx5) ? 57 : 56, 7); /* FWD.UPDATE_FCS = Enable. Enforce update of FCS. */ - ifh_encode_bitfield(ifh_hdr, 1, 67, 1); + ifh_encode_bitfield(ifh_hdr, 1, is_sparx5(sparx5) ? 67 : 66, 1); } void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op) @@ -80,19 +81,25 @@ void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op) ifh_encode_bitfield(ifh_hdr, rew_op, VSTAX + 32, 10); } -void sparx5_set_port_ifh_pdu_type(void *ifh_hdr, u32 pdu_type) +void sparx5_set_port_ifh_pdu_type(struct sparx5 *sparx5, void *ifh_hdr, + u32 pdu_type) { - ifh_encode_bitfield(ifh_hdr, pdu_type, 191, 4); + ifh_encode_bitfield(ifh_hdr, pdu_type, is_sparx5(sparx5) ? 191 : 190, + 4); } -void sparx5_set_port_ifh_pdu_w16_offset(void *ifh_hdr, u32 pdu_w16_offset) +void sparx5_set_port_ifh_pdu_w16_offset(struct sparx5 *sparx5, void *ifh_hdr, + u32 pdu_w16_offset) { - ifh_encode_bitfield(ifh_hdr, pdu_w16_offset, 195, 6); + ifh_encode_bitfield(ifh_hdr, pdu_w16_offset, + is_sparx5(sparx5) ? 195 : 194, 6); } -void sparx5_set_port_ifh_timestamp(void *ifh_hdr, u64 timestamp) +void sparx5_set_port_ifh_timestamp(struct sparx5 *sparx5, void *ifh_hdr, + u64 timestamp) { - ifh_encode_bitfield(ifh_hdr, timestamp, 232, 40); + ifh_encode_bitfield(ifh_hdr, timestamp, 232, + is_sparx5(sparx5) ? 40 : 38); } static int sparx5_port_open(struct net_device *ndev) @@ -190,7 +197,8 @@ static int sparx5_set_mac_address(struct net_device *dev, void *p) sparx5_mact_forget(sparx5, dev->dev_addr, port->pvid); /* Add new */ - sparx5_mact_learn(sparx5, PGID_CPU, addr->sa_data, port->pvid); + sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), + addr->sa_data, port->pvid); /* Record the address */ eth_hw_addr_set(dev, addr->sa_data); @@ -290,7 +298,7 @@ int sparx5_register_netdevs(struct sparx5 *sparx5) int portno; int err; - for (portno = 0; portno < SPX5_PORTS; portno++) + for (portno = 0; portno < sparx5->data->consts->n_ports; portno++) if (sparx5->ports[portno]) { err = register_netdev(sparx5->ports[portno]->ndev); if (err) { @@ -309,7 +317,7 @@ void sparx5_destroy_netdevs(struct sparx5 *sparx5) struct sparx5_port *port; int portno; - for (portno = 0; portno < SPX5_PORTS; portno++) { + for (portno = 0; portno < sparx5->data->consts->n_ports; portno++) { port = sparx5->ports[portno]; if (port && port->phylink) { /* Disconnect the phy */ @@ -327,8 +335,7 @@ void sparx5_unregister_netdevs(struct sparx5 *sparx5) { int portno; - for (portno = 0; portno < SPX5_PORTS; portno++) + for (portno = 0; portno < sparx5->data->consts->n_ports; portno++) if (sparx5->ports[portno]) unregister_netdev(sparx5->ports[portno]->ndev); } - diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c index 70427643f777c0..b6f635d85820f5 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c @@ -32,7 +32,7 @@ void sparx5_xtr_flush(struct sparx5 *sparx5, u8 grp) spx5_wr(0, sparx5, QS_XTR_FLUSH); } -void sparx5_ifh_parse(u32 *ifh, struct frame_info *info) +void sparx5_ifh_parse(struct sparx5 *sparx5, u32 *ifh, struct frame_info *info) { u8 *xtr_hdr = (u8 *)ifh; @@ -43,7 +43,8 @@ void sparx5_ifh_parse(u32 *ifh, struct frame_info *info) ((u32)xtr_hdr[29] << 8) | ((u32)xtr_hdr[30] << 0); fwd = (fwd >> 5); - info->src_port = FIELD_GET(GENMASK(7, 1), fwd); + info->src_port = spx5_field_get(GENMASK(is_sparx5(sparx5) ? 7 : 6, 1), + fwd); /* * Bit 270-271 are occasionally unexpectedly set by the hardware, @@ -72,10 +73,10 @@ static void sparx5_xtr_grp(struct sparx5 *sparx5, u8 grp, bool byte_swap) ifh[i] = spx5_rd(sparx5, QS_XTR_RD(grp)); /* Decode IFH (what's needed) */ - sparx5_ifh_parse(ifh, &fi); + sparx5_ifh_parse(sparx5, ifh, &fi); /* Map to port netdev */ - port = fi.src_port < SPX5_PORTS ? + port = fi.src_port < sparx5->data->consts->n_ports ? sparx5->ports[fi.src_port] : NULL; if (!port || !port->ndev) { dev_err(sparx5->dev, "Data on inactive port %d\n", fi.src_port); @@ -235,16 +236,19 @@ netdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev) netdev_tx_t ret; memset(ifh, 0, IFH_LEN * 4); - sparx5_set_port_ifh(ifh, port->portno); + sparx5_set_port_ifh(sparx5, ifh, port->portno); if (sparx5->ptp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { if (sparx5_ptp_txtstamp_request(port, skb) < 0) return NETDEV_TX_BUSY; sparx5_set_port_ifh_rew_op(ifh, SPARX5_SKB_CB(skb)->rew_op); - sparx5_set_port_ifh_pdu_type(ifh, SPARX5_SKB_CB(skb)->pdu_type); - sparx5_set_port_ifh_pdu_w16_offset(ifh, SPARX5_SKB_CB(skb)->pdu_w16_offset); - sparx5_set_port_ifh_timestamp(ifh, SPARX5_SKB_CB(skb)->ts_id); + sparx5_set_port_ifh_pdu_type(sparx5, ifh, + SPARX5_SKB_CB(skb)->pdu_type); + sparx5_set_port_ifh_pdu_w16_offset(sparx5, ifh, + SPARX5_SKB_CB(skb)->pdu_w16_offset); + sparx5_set_port_ifh_timestamp(sparx5, ifh, + SPARX5_SKB_CB(skb)->ts_id); } skb_tx_timestamp(skb); @@ -317,7 +321,9 @@ int sparx5_manual_injection_mode(struct sparx5 *sparx5) sparx5, QS_INJ_GRP_CFG(INJ_QUEUE)); /* CPU ports capture setup */ - for (portno = SPX5_PORT_CPU_0; portno <= SPX5_PORT_CPU_1; portno++) { + for (portno = sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_0); + portno <= sparx5_get_internal_port(sparx5, SPX5_PORT_CPU_1); + portno++) { /* ASM CPU port: No preamble, IFH, enable padding */ spx5_wr(ASM_PORT_CFG_PAD_ENA_SET(1) | ASM_PORT_CFG_NO_PREAMBLE_ENA_SET(1) | diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_pgid.c b/drivers/net/ethernet/microchip/sparx5/sparx5_pgid.c index af8b435009f4de..eae819fa9486fe 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_pgid.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_pgid.c @@ -5,13 +5,13 @@ void sparx5_pgid_init(struct sparx5 *spx5) { int i; - for (i = 0; i < PGID_TABLE_SIZE; i++) + for (i = 0; i < spx5->data->consts->n_pgids; i++) spx5->pgid_map[i] = SPX5_PGID_FREE; /* Reserved for unicast, flood control, broadcast, and CPU. * These cannot be freed. */ - for (i = 0; i <= PGID_CPU; i++) + for (i = 0; i <= sparx5_get_pgid(spx5, PGID_CPU); i++) spx5->pgid_map[i] = SPX5_PGID_RESERVED; } @@ -22,7 +22,8 @@ int sparx5_pgid_alloc_mcast(struct sparx5 *spx5, u16 *idx) /* The multicast area starts at index 65, but the first 7 * are reserved for flood masks and CPU. Start alloc after that. */ - for (i = PGID_MCAST_START; i < PGID_TABLE_SIZE; i++) { + for (i = sparx5_get_pgid(spx5, PGID_MCAST_START); + i < spx5->data->consts->n_pgids; i++) { if (spx5->pgid_map[i] == SPX5_PGID_FREE) { spx5->pgid_map[i] = SPX5_PGID_MULTICAST; *idx = i; @@ -35,7 +36,8 @@ int sparx5_pgid_alloc_mcast(struct sparx5 *spx5, u16 *idx) int sparx5_pgid_free(struct sparx5 *spx5, u16 idx) { - if (idx <= PGID_CPU || idx >= PGID_TABLE_SIZE) + if (idx <= sparx5_get_pgid(spx5, PGID_CPU) || + idx >= spx5->data->consts->n_pgids) return -EINVAL; if (spx5->pgid_map[idx] == SPX5_PGID_FREE) @@ -44,3 +46,8 @@ int sparx5_pgid_free(struct sparx5 *spx5, u16 idx) spx5->pgid_map[idx] = SPX5_PGID_FREE; return 0; } + +int sparx5_get_pgid(struct sparx5 *sparx5, int pgid) +{ + return sparx5->data->consts->n_ports + pgid; +} diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_police.c b/drivers/net/ethernet/microchip/sparx5/sparx5_police.c index 8ada5cee134216..c88820e83812c1 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_police.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_police.c @@ -11,10 +11,11 @@ static int sparx5_policer_service_conf_set(struct sparx5 *sparx5, struct sparx5_policer *pol) { u32 idx, pup_tokens, max_pup_tokens, burst, thres; + const struct sparx5_ops *ops = sparx5->data->ops; struct sparx5_sdlb_group *g; u64 rate; - g = &sdlb_groups[pol->group]; + g = ops->get_sdlb_group(pol->group); idx = pol->idx; rate = pol->rate * 1000; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c index 062e486c002cf6..f9d1a6bb9bfffd 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c @@ -132,8 +132,8 @@ static int sparx5_get_sfi_status(struct sparx5 *sparx5, return -EINVAL; } - dev = sparx5_to_high_dev(portno); - tinst = sparx5_port_dev_index(portno); + dev = sparx5_to_high_dev(sparx5, portno); + tinst = sparx5_port_dev_index(sparx5, portno); inst = spx5_inst_get(sparx5, dev, tinst); value = spx5_inst_rd(inst, DEV10G_MAC_TX_MONITOR_STICKY(0)); @@ -213,11 +213,13 @@ static int sparx5_port_verify_speed(struct sparx5 *sparx5, struct sparx5_port *port, struct sparx5_port_config *conf) { - if ((sparx5_port_is_2g5(port->portno) && + const struct sparx5_ops *ops = sparx5->data->ops; + + if ((ops->is_port_2g5(port->portno) && conf->speed > SPEED_2500) || - (sparx5_port_is_5g(port->portno) && + (ops->is_port_5g(port->portno) && conf->speed > SPEED_5000) || - (sparx5_port_is_10g(port->portno) && + (ops->is_port_10g(port->portno) && conf->speed > SPEED_10000)) return sparx5_port_error(port, conf, SPX5_PERR_SPEED); @@ -226,14 +228,14 @@ static int sparx5_port_verify_speed(struct sparx5 *sparx5, return -EINVAL; case PHY_INTERFACE_MODE_1000BASEX: if (conf->speed != SPEED_1000 || - sparx5_port_is_2g5(port->portno)) + ops->is_port_2g5(port->portno)) return sparx5_port_error(port, conf, SPX5_PERR_SPEED); - if (sparx5_port_is_2g5(port->portno)) + if (ops->is_port_2g5(port->portno)) return sparx5_port_error(port, conf, SPX5_PERR_IFTYPE); break; case PHY_INTERFACE_MODE_2500BASEX: if (conf->speed != SPEED_2500 || - sparx5_port_is_2g5(port->portno)) + ops->is_port_2g5(port->portno)) return sparx5_port_error(port, conf, SPX5_PERR_SPEED); break; case PHY_INTERFACE_MODE_QSGMII: @@ -316,10 +318,11 @@ static int sparx5_port_flush_poll(struct sparx5 *sparx5, u32 portno) static int sparx5_port_disable(struct sparx5 *sparx5, struct sparx5_port *port, bool high_spd_dev) { u32 tinst = high_spd_dev ? - sparx5_port_dev_index(port->portno) : port->portno; + sparx5_port_dev_index(sparx5, port->portno) : port->portno; u32 dev = high_spd_dev ? - sparx5_to_high_dev(port->portno) : TARGET_DEV2G5; + sparx5_to_high_dev(sparx5, port->portno) : TARGET_DEV2G5; void __iomem *devinst = spx5_inst_get(sparx5, dev, tinst); + const struct sparx5_ops *ops = sparx5->data->ops; u32 spd = port->conf.speed; u32 spd_prm; int err; @@ -427,7 +430,7 @@ static int sparx5_port_disable(struct sparx5 *sparx5, struct sparx5_port *port, HSCH_FLUSH_CTRL); if (high_spd_dev) { - u32 pcs = sparx5_to_pcs_dev(port->portno); + u32 pcs = sparx5_to_pcs_dev(sparx5, port->portno); void __iomem *pcsinst = spx5_inst_get(sparx5, pcs, tinst); /* 12: Disable 5G/10G/25 BaseR PCS */ @@ -436,7 +439,7 @@ static int sparx5_port_disable(struct sparx5 *sparx5, struct sparx5_port *port, pcsinst, PCS10G_BR_PCS_CFG(0)); - if (sparx5_port_is_25g(port->portno)) + if (ops->is_port_25g(port->portno)) /* Disable 25G PCS */ spx5_rmw(DEV25G_PCS25G_CFG_PCS25G_ENA_SET(0), DEV25G_PCS25G_CFG_PCS25G_ENA, @@ -473,6 +476,9 @@ static int sparx5_port_fifo_sz(struct sparx5 *sparx5, u32 mac_width = 8; u32 addition = 0; + if (!is_sparx5(sparx5)) + return 0; + switch (speed) { case SPEED_25000: return 0; @@ -513,9 +519,8 @@ static int sparx5_port_fifo_sz(struct sparx5 *sparx5, /* Configure port muxing: * QSGMII: 4x2G5 devices */ -static int sparx5_port_mux_set(struct sparx5 *sparx5, - struct sparx5_port *port, - struct sparx5_port_config *conf) +int sparx5_port_mux_set(struct sparx5 *sparx5, struct sparx5_port *port, + struct sparx5_port_config *conf) { u32 portno = port->portno; u32 inst; @@ -558,9 +563,10 @@ static int sparx5_port_max_tags_set(struct sparx5 *sparx5, bool dtag = max_tags == SPX5_PORT_MAX_TAGS_TWO; enum sparx5_vlan_port_type vlan_type = port->vlan_type; bool dotag = max_tags != SPX5_PORT_MAX_TAGS_NONE; - u32 dev = sparx5_to_high_dev(port->portno); - u32 tinst = sparx5_port_dev_index(port->portno); + u32 dev = sparx5_to_high_dev(sparx5, port->portno); + u32 tinst = sparx5_port_dev_index(sparx5, port->portno); void __iomem *inst = spx5_inst_get(sparx5, dev, tinst); + const struct sparx5_ops *ops = sparx5->data->ops; u32 etype; etype = (vlan_type == SPX5_VLAN_PORT_TYPE_S_CUSTOM ? @@ -575,7 +581,7 @@ static int sparx5_port_max_tags_set(struct sparx5 *sparx5, sparx5, DEV2G5_MAC_TAGS_CFG(port->portno)); - if (sparx5_port_is_2g5(port->portno)) + if (ops->is_port_2g5(port->portno)) return 0; spx5_inst_rmw(DEV10G_MAC_TAGS_CFG_TAG_ID_SET(etype) | @@ -789,9 +795,9 @@ static int sparx5_port_pcs_high_set(struct sparx5 *sparx5, struct sparx5_port_config *conf) { u32 clk_spd = conf->portmode == PHY_INTERFACE_MODE_5GBASER ? 1 : 0; - u32 pix = sparx5_port_dev_index(port->portno); - u32 dev = sparx5_to_high_dev(port->portno); - u32 pcs = sparx5_to_pcs_dev(port->portno); + u32 pix = sparx5_port_dev_index(sparx5, port->portno); + u32 dev = sparx5_to_high_dev(sparx5, port->portno); + u32 pcs = sparx5_to_pcs_dev(sparx5, port->portno); void __iomem *devinst; void __iomem *pcsinst; int err; @@ -843,19 +849,22 @@ static int sparx5_port_pcs_high_set(struct sparx5 *sparx5, /* Switch between 1G/2500 and 5G/10G/25G devices */ static void sparx5_dev_switch(struct sparx5 *sparx5, int port, bool hsd) { - int bt_indx = BIT(sparx5_port_dev_index(port)); + const struct sparx5_ops *ops = sparx5->data->ops; + int bt_indx; + + bt_indx = BIT(ops->get_port_dev_bit(sparx5, port)); - if (sparx5_port_is_5g(port)) { + if (ops->is_port_5g(port)) { spx5_rmw(hsd ? 0 : bt_indx, bt_indx, sparx5, PORT_CONF_DEV5G_MODES); - } else if (sparx5_port_is_10g(port)) { + } else if (ops->is_port_10g(port)) { spx5_rmw(hsd ? 0 : bt_indx, bt_indx, sparx5, PORT_CONF_DEV10G_MODES); - } else if (sparx5_port_is_25g(port)) { + } else if (ops->is_port_25g(port)) { spx5_rmw(hsd ? 0 : bt_indx, bt_indx, sparx5, @@ -915,6 +924,20 @@ static int sparx5_port_config_low_set(struct sparx5 *sparx5, sparx5, DEV2G5_DEV_RST_CTRL(port->portno)); + /* Enable PHAD_CTRL for better timestamping */ + if (!is_sparx5(sparx5)) { + for (int i = 0; i < 2; ++i) { + /* Divide the port clock by three for the two + * phase detection registers. + */ + spx5_rmw(DEV2G5_PHAD_CTRL_DIV_CFG_SET(3) | + DEV2G5_PHAD_CTRL_PHAD_ENA_SET(1), + DEV2G5_PHAD_CTRL_DIV_CFG | + DEV2G5_PHAD_CTRL_PHAD_ENA, + sparx5, DEV2G5_PHAD_CTRL(port->portno, i)); + } + } + return 0; } @@ -972,6 +995,7 @@ int sparx5_port_config(struct sparx5 *sparx5, struct sparx5_port_config *conf) { bool high_speed_dev = sparx5_is_baser(conf->portmode); + const struct sparx5_ops *ops = sparx5->data->ops; int err, urgency, stop_wm; err = sparx5_port_verify_speed(sparx5, port, conf); @@ -987,6 +1011,13 @@ int sparx5_port_config(struct sparx5 *sparx5, if (err) return err; + if (!is_sparx5(sparx5) && ops->is_port_10g(port->portno) && + conf->speed < SPEED_10000) + spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA_SET(1), + DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA, + sparx5, + DSM_DEV_TX_STOP_WM_CFG(port->portno)); + /* Set the DSM stop watermark */ stop_wm = sparx5_port_fifo_sz(sparx5, port->portno, conf->speed); spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV_TX_STOP_WM_SET(stop_wm), @@ -1016,9 +1047,10 @@ int sparx5_port_init(struct sparx5 *sparx5, { u32 pause_start = sparx5_wm_enc(6 * (ETH_MAXLEN / SPX5_BUFFER_CELL_SZ)); u32 atop = sparx5_wm_enc(20 * (ETH_MAXLEN / SPX5_BUFFER_CELL_SZ)); - u32 devhigh = sparx5_to_high_dev(port->portno); - u32 pix = sparx5_port_dev_index(port->portno); - u32 pcs = sparx5_to_pcs_dev(port->portno); + const struct sparx5_ops *ops = sparx5->data->ops; + u32 devhigh = sparx5_to_high_dev(sparx5, port->portno); + u32 pix = sparx5_port_dev_index(sparx5, port->portno); + u32 pcs = sparx5_to_pcs_dev(sparx5, port->portno); bool sd_pol = port->signd_active_high; bool sd_sel = !port->signd_internal; bool sd_ena = port->signd_enable; @@ -1031,7 +1063,7 @@ int sparx5_port_init(struct sparx5 *sparx5, pcsinst = spx5_inst_get(sparx5, pcs, pix); /* Set the mux port mode */ - err = sparx5_port_mux_set(sparx5, port, conf); + err = ops->set_port_mux(sparx5, port, conf); if (err) return err; @@ -1082,7 +1114,7 @@ int sparx5_port_init(struct sparx5 *sparx5, if (err) return err; - if (!sparx5_port_is_2g5(port->portno)) + if (!ops->is_port_2g5(port->portno)) /* Enable shadow device */ spx5_rmw(DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA_SET(1), DSM_DEV_TX_STOP_WM_CFG_DEV10G_SHADOW_ENA, @@ -1105,7 +1137,7 @@ int sparx5_port_init(struct sparx5 *sparx5, sparx5, DEV2G5_MAC_IFG_CFG(port->portno)); - if (sparx5_port_is_2g5(port->portno)) + if (ops->is_port_2g5(port->portno)) return 0; /* Low speed device only - return */ /* Now setup the high speed device */ @@ -1119,7 +1151,7 @@ int sparx5_port_init(struct sparx5 *sparx5, spx5_inst_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN), DEV10G_MAC_MAXLEN_CFG_MAX_LEN, devinst, - DEV10G_MAC_ENA_CFG(0)); + DEV10G_MAC_MAXLEN_CFG(0)); /* Handle Signal Detect in 10G PCS */ spx5_inst_wr(PCS10G_BR_PCS_SD_CFG_SD_POL_SET(sd_pol) | @@ -1128,7 +1160,7 @@ int sparx5_port_init(struct sparx5 *sparx5, pcsinst, PCS10G_BR_PCS_SD_CFG(0)); - if (sparx5_port_is_25g(port->portno)) { + if (ops->is_port_25g(port->portno)) { /* Handle Signal Detect in 25G PCS */ spx5_wr(DEV25G_PCS25G_SD_CFG_SD_POL_SET(sd_pol) | DEV25G_PCS25G_SD_CFG_SD_SEL_SET(sd_sel) | @@ -1137,6 +1169,27 @@ int sparx5_port_init(struct sparx5 *sparx5, DEV25G_PCS25G_SD_CFG(pix)); } + if (!is_sparx5(sparx5)) { + void __iomem *inst; + u32 dev, tinst; + + if (ops->is_port_10g(port->portno)) { + dev = sparx5_to_high_dev(sparx5, port->portno); + tinst = sparx5_port_dev_index(sparx5, port->portno); + inst = spx5_inst_get(sparx5, dev, tinst); + + spx5_inst_wr(5, inst, + DEV10G_PTP_STAMPER_CFG(port->portno)); + } else if (ops->is_port_5g(port->portno)) { + dev = sparx5_to_high_dev(sparx5, port->portno); + tinst = sparx5_port_dev_index(sparx5, port->portno); + inst = spx5_inst_get(sparx5, dev, tinst); + + spx5_inst_wr(5, inst, + DEV5G_PTP_STAMPER_CFG(port->portno)); + } + } + return 0; } @@ -1345,3 +1398,8 @@ int sparx5_port_qos_default_set(const struct sparx5_port *port, return 0; } + +int sparx5_get_internal_port(struct sparx5 *sparx5, int port) +{ + return sparx5->data->consts->n_ports + port; +} diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.h b/drivers/net/ethernet/microchip/sparx5/sparx5_port.h index 607c4ff1df6b58..9b9bcc6834bcb8 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.h @@ -40,25 +40,29 @@ static inline bool sparx5_port_is_25g(int portno) return portno >= 56 && portno <= 63; } -static inline u32 sparx5_to_high_dev(int port) +static inline u32 sparx5_to_high_dev(struct sparx5 *sparx5, int port) { - if (sparx5_port_is_5g(port)) + const struct sparx5_ops *ops = sparx5->data->ops; + + if (ops->is_port_5g(port)) return TARGET_DEV5G; - if (sparx5_port_is_10g(port)) + if (ops->is_port_10g(port)) return TARGET_DEV10G; return TARGET_DEV25G; } -static inline u32 sparx5_to_pcs_dev(int port) +static inline u32 sparx5_to_pcs_dev(struct sparx5 *sparx5, int port) { - if (sparx5_port_is_5g(port)) + const struct sparx5_ops *ops = sparx5->data->ops; + + if (ops->is_port_5g(port)) return TARGET_PCS5G_BR; - if (sparx5_port_is_10g(port)) + if (ops->is_port_10g(port)) return TARGET_PCS10G_BR; return TARGET_PCS25G_BR; } -static inline int sparx5_port_dev_index(int port) +static inline u32 sparx5_port_dev_mapping(struct sparx5 *sparx5, int port) { if (sparx5_port_is_2g5(port)) return port; @@ -70,6 +74,11 @@ static inline int sparx5_port_dev_index(int port) return (port - 56); } +static inline u32 sparx5_port_dev_index(struct sparx5 *sparx5, int port) +{ + return sparx5->data->ops->get_port_dev_index(sparx5, port); +} + int sparx5_port_init(struct sparx5 *sparx5, struct sparx5_port *spx5_port, struct sparx5_port_config *conf); diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c index 8dee1ab1fa7540..cd4f42c3f7ebff 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_psfp.c @@ -20,36 +20,40 @@ static struct sparx5_pool_entry sparx5_psfp_sg_pool[SPX5_PSFP_SG_CNT]; /* Pool of available stream filters */ static struct sparx5_pool_entry sparx5_psfp_sf_pool[SPX5_PSFP_SF_CNT]; -static int sparx5_psfp_sf_get(u32 *id) +static int sparx5_psfp_sf_get(struct sparx5 *sparx5, u32 *id) { - return sparx5_pool_get(sparx5_psfp_sf_pool, SPX5_PSFP_SF_CNT, id); + return sparx5_pool_get(sparx5_psfp_sf_pool, + sparx5->data->consts->n_filters, id); } -static int sparx5_psfp_sf_put(u32 id) +static int sparx5_psfp_sf_put(struct sparx5 *sparx5, u32 id) { - return sparx5_pool_put(sparx5_psfp_sf_pool, SPX5_PSFP_SF_CNT, id); + return sparx5_pool_put(sparx5_psfp_sf_pool, + sparx5->data->consts->n_filters, id); } -static int sparx5_psfp_sg_get(u32 idx, u32 *id) +static int sparx5_psfp_sg_get(struct sparx5 *sparx5, u32 idx, u32 *id) { - return sparx5_pool_get_with_idx(sparx5_psfp_sg_pool, SPX5_PSFP_SG_CNT, - idx, id); + return sparx5_pool_get_with_idx(sparx5_psfp_sg_pool, + sparx5->data->consts->n_gates, idx, id); } -static int sparx5_psfp_sg_put(u32 id) +static int sparx5_psfp_sg_put(struct sparx5 *sparx5, u32 id) { - return sparx5_pool_put(sparx5_psfp_sg_pool, SPX5_PSFP_SG_CNT, id); + return sparx5_pool_put(sparx5_psfp_sg_pool, + sparx5->data->consts->n_gates, id); } -static int sparx5_psfp_fm_get(u32 idx, u32 *id) +static int sparx5_psfp_fm_get(struct sparx5 *sparx5, u32 idx, u32 *id) { - return sparx5_pool_get_with_idx(sparx5_psfp_fm_pool, SPX5_SDLB_CNT, idx, - id); + return sparx5_pool_get_with_idx(sparx5_psfp_fm_pool, + sparx5->data->consts->n_sdlbs, idx, id); } -static int sparx5_psfp_fm_put(u32 id) +static int sparx5_psfp_fm_put(struct sparx5 *sparx5, u32 id) { - return sparx5_pool_put(sparx5_psfp_fm_pool, SPX5_SDLB_CNT, id); + return sparx5_pool_put(sparx5_psfp_fm_pool, + sparx5->data->consts->n_sdlbs, id); } u32 sparx5_psfp_isdx_get_sf(struct sparx5 *sparx5, u32 isdx) @@ -205,7 +209,7 @@ int sparx5_psfp_sf_add(struct sparx5 *sparx5, const struct sparx5_psfp_sf *sf, { int ret; - ret = sparx5_psfp_sf_get(id); + ret = sparx5_psfp_sf_get(sparx5, id); if (ret < 0) return ret; @@ -220,7 +224,7 @@ int sparx5_psfp_sf_del(struct sparx5 *sparx5, u32 id) sparx5_psfp_sf_set(sparx5, id, &sf); - return sparx5_psfp_sf_put(id); + return sparx5_psfp_sf_put(sparx5, id); } int sparx5_psfp_sg_add(struct sparx5 *sparx5, u32 uidx, @@ -229,7 +233,7 @@ int sparx5_psfp_sg_add(struct sparx5 *sparx5, u32 uidx, ktime_t basetime; int ret; - ret = sparx5_psfp_sg_get(uidx, id); + ret = sparx5_psfp_sg_get(sparx5, uidx, id); if (ret < 0) return ret; /* Was already in use, no need to reconfigure */ @@ -253,7 +257,7 @@ int sparx5_psfp_sg_del(struct sparx5 *sparx5, u32 id) const struct sparx5_psfp_sg sg = { 0 }; int ret; - ret = sparx5_psfp_sg_put(id); + ret = sparx5_psfp_sg_put(sparx5, id); if (ret < 0) return ret; /* Stream gate still in use ? */ @@ -270,7 +274,7 @@ int sparx5_psfp_fm_add(struct sparx5 *sparx5, u32 uidx, int ret; /* Get flow meter */ - ret = sparx5_psfp_fm_get(uidx, &fm->pol.idx); + ret = sparx5_psfp_fm_get(sparx5, uidx, &fm->pol.idx); if (ret < 0) return ret; /* Was already in use, no need to reconfigure */ @@ -303,7 +307,7 @@ int sparx5_psfp_fm_del(struct sparx5 *sparx5, u32 id) if (ret < 0) return ret; - ret = sparx5_psfp_fm_put(id); + ret = sparx5_psfp_fm_put(sparx5, id); if (ret < 0) return ret; /* Do not reset flow-meter if still in use. */ @@ -315,11 +319,12 @@ int sparx5_psfp_fm_del(struct sparx5 *sparx5, u32 id) void sparx5_psfp_init(struct sparx5 *sparx5) { + const struct sparx5_ops *ops = sparx5->data->ops; const struct sparx5_sdlb_group *group; int i; - for (i = 0; i < SPX5_SDLB_GROUP_CNT; i++) { - group = &sdlb_groups[i]; + for (i = 0; i < sparx5->data->consts->n_lb_groups; i++) { + group = ops->get_sdlb_group(i); sparx5_sdlb_group_init(sparx5, group->max_rate, group->min_burst, group->frame_size, i); } diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c index 5a932460db5819..2f168700f63c11 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c @@ -11,8 +11,6 @@ #include "sparx5_main_regs.h" #include "sparx5_main.h" -#define SPARX5_MAX_PTP_ID 512 - #define TOD_ACC_PIN 0x4 enum { @@ -38,6 +36,9 @@ static u64 sparx5_ptp_get_1ppm(struct sparx5 *sparx5) case SPX5_CORE_CLOCK_250MHZ: res = 2301339409586; break; + case SPX5_CORE_CLOCK_328MHZ: + res = 1756832768924; + break; case SPX5_CORE_CLOCK_500MHZ: res = 1150669704793; break; @@ -60,6 +61,9 @@ static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5) case SPX5_CORE_CLOCK_250MHZ: res = 0x1FF0000000000000; break; + case SPX5_CORE_CLOCK_328MHZ: + res = 0x18604697DD0F9B5B; + break; case SPX5_CORE_CLOCK_500MHZ: res = 0x0FF8000000000000; break; @@ -269,11 +273,12 @@ void sparx5_ptp_txtstamp_release(struct sparx5_port *port, spin_unlock_irqrestore(&sparx5->ptp_ts_id_lock, flags); } -static void sparx5_get_hwtimestamp(struct sparx5 *sparx5, - struct timespec64 *ts, - u32 nsec) +void sparx5_get_hwtimestamp(struct sparx5 *sparx5, + struct timespec64 *ts, + u32 nsec) { /* Read current PTP time to get seconds */ + const struct sparx5_consts *consts = sparx5->data->consts; unsigned long flags; u32 curr_nsec; @@ -285,10 +290,10 @@ static void sparx5_get_hwtimestamp(struct sparx5 *sparx5, PTP_PTP_PIN_CFG_PTP_PIN_ACTION | PTP_PTP_PIN_CFG_PTP_PIN_DOM | PTP_PTP_PIN_CFG_PTP_PIN_SYNC, - sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); + sparx5, PTP_PTP_PIN_CFG(consts->tod_pin)); - ts->tv_sec = spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN)); - curr_nsec = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); + ts->tv_sec = spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(consts->tod_pin)); + curr_nsec = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(consts->tod_pin)); ts->tv_nsec = nsec; @@ -440,8 +445,11 @@ static int sparx5_ptp_settime64(struct ptp_clock_info *ptp, { struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info); struct sparx5 *sparx5 = phc->sparx5; + const struct sparx5_consts *consts; unsigned long flags; + consts = sparx5->data->consts; + spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); /* Must be in IDLE mode before the time can be loaded */ @@ -451,14 +459,14 @@ static int sparx5_ptp_settime64(struct ptp_clock_info *ptp, PTP_PTP_PIN_CFG_PTP_PIN_ACTION | PTP_PTP_PIN_CFG_PTP_PIN_DOM | PTP_PTP_PIN_CFG_PTP_PIN_SYNC, - sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); + sparx5, PTP_PTP_PIN_CFG(consts->tod_pin)); /* Set new value */ spx5_wr(PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB_SET(upper_32_bits(ts->tv_sec)), - sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN)); + sparx5, PTP_PTP_TOD_SEC_MSB(consts->tod_pin)); spx5_wr(lower_32_bits(ts->tv_sec), - sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN)); - spx5_wr(ts->tv_nsec, sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); + sparx5, PTP_PTP_TOD_SEC_LSB(consts->tod_pin)); + spx5_wr(ts->tv_nsec, sparx5, PTP_PTP_TOD_NSEC(consts->tod_pin)); /* Apply new values */ spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_LOAD) | @@ -467,7 +475,7 @@ static int sparx5_ptp_settime64(struct ptp_clock_info *ptp, PTP_PTP_PIN_CFG_PTP_PIN_ACTION | PTP_PTP_PIN_CFG_PTP_PIN_DOM | PTP_PTP_PIN_CFG_PTP_PIN_SYNC, - sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); + sparx5, PTP_PTP_PIN_CFG(consts->tod_pin)); spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); @@ -478,10 +486,13 @@ int sparx5_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) { struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info); struct sparx5 *sparx5 = phc->sparx5; + const struct sparx5_consts *consts; unsigned long flags; time64_t s; s64 ns; + consts = sparx5->data->consts; + spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_SAVE) | @@ -490,12 +501,12 @@ int sparx5_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) PTP_PTP_PIN_CFG_PTP_PIN_ACTION | PTP_PTP_PIN_CFG_PTP_PIN_DOM | PTP_PTP_PIN_CFG_PTP_PIN_SYNC, - sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); + sparx5, PTP_PTP_PIN_CFG(consts->tod_pin)); - s = spx5_rd(sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN)); + s = spx5_rd(sparx5, PTP_PTP_TOD_SEC_MSB(consts->tod_pin)); s <<= 32; - s |= spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN)); - ns = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); + s |= spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(consts->tod_pin)); + ns = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(consts->tod_pin)); ns &= PTP_PTP_TOD_NSEC_PTP_TOD_NSEC; spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); @@ -515,6 +526,9 @@ static int sparx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info); struct sparx5 *sparx5 = phc->sparx5; + const struct sparx5_consts *consts; + + consts = sparx5->data->consts; if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) { unsigned long flags; @@ -528,10 +542,10 @@ static int sparx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) PTP_PTP_PIN_CFG_PTP_PIN_ACTION | PTP_PTP_PIN_CFG_PTP_PIN_DOM | PTP_PTP_PIN_CFG_PTP_PIN_SYNC, - sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); + sparx5, PTP_PTP_PIN_CFG(consts->tod_pin)); spx5_wr(PTP_PTP_TOD_NSEC_PTP_TOD_NSEC_SET(delta), - sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); + sparx5, PTP_PTP_TOD_NSEC(consts->tod_pin)); /* Adjust time with the value of PTP_TOD_NSEC */ spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_DELTA) | @@ -540,7 +554,7 @@ static int sparx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) PTP_PTP_PIN_CFG_PTP_PIN_ACTION | PTP_PTP_PIN_CFG_PTP_PIN_DOM | PTP_PTP_PIN_CFG_PTP_PIN_SYNC, - sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); + sparx5, PTP_PTP_PIN_CFG(consts->tod_pin)); spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); } else { @@ -630,7 +644,7 @@ int sparx5_ptp_init(struct sparx5 *sparx5) /* Enable master counters */ spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0x7), sparx5, PTP_PTP_DOM_CFG); - for (i = 0; i < SPX5_PORTS; i++) { + for (i = 0; i < sparx5->data->consts->n_ports; i++) { port = sparx5->ports[i]; if (!port) continue; @@ -646,7 +660,7 @@ void sparx5_ptp_deinit(struct sparx5 *sparx5) struct sparx5_port *port; int i; - for (i = 0; i < SPX5_PORTS; i++) { + for (i = 0; i < sparx5->data->consts->n_ports; i++) { port = sparx5->ports[i]; if (!port) continue; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c index 5f34febaee6b8a..e580670f3992b0 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.c @@ -74,6 +74,11 @@ static const u32 spx5_hsch_max_group_rate[SPX5_HSCH_LEAK_GRP_CNT] = { 26214200 /* 26.214 Gbps */ }; +u32 sparx5_get_hsch_max_group_rate(int grp) +{ + return spx5_hsch_max_group_rate[grp]; +} + static struct sparx5_layer layers[SPX5_HSCH_LAYER_CNT]; static u32 sparx5_lg_get_leak_time(struct sparx5 *sparx5, u32 layer, u32 group) @@ -362,9 +367,10 @@ static u32 sparx5_weight_to_hw_cost(u32 weight_min, u32 weight) static int sparx5_dwrr_conf_set(struct sparx5_port *port, struct sparx5_dwrr *dwrr) { + u32 layer = is_sparx5(port->sparx5) ? 2 : 1; int i; - spx5_rmw(HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(2) | + spx5_rmw(HSCH_HSCH_CFG_CFG_HSCH_LAYER_SET(layer) | HSCH_HSCH_CFG_CFG_CFG_SE_IDX_SET(port->portno), HSCH_HSCH_CFG_CFG_HSCH_LAYER | HSCH_HSCH_CFG_CFG_CFG_SE_IDX, port->sparx5, HSCH_HSCH_CFG_CFG); @@ -385,6 +391,7 @@ static int sparx5_dwrr_conf_set(struct sparx5_port *port, static int sparx5_leak_groups_init(struct sparx5 *sparx5) { + const struct sparx5_ops *ops = sparx5->data->ops; struct sparx5_layer *layer; u32 sys_clk_per_100ps; struct sparx5_lg *lg; @@ -397,7 +404,7 @@ static int sparx5_leak_groups_init(struct sparx5 *sparx5) layer = &layers[i]; for (ii = 0; ii < SPX5_HSCH_LEAK_GRP_CNT; ii++) { lg = &layer->leak_groups[ii]; - lg->max_rate = spx5_hsch_max_group_rate[ii]; + lg->max_rate = ops->get_hsch_max_group_rate(i); /* Calculate the leak time in us, to serve a maximum * rate of 'max_rate' for this group diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h index ced35033a6c5dd..1231a80335d7b1 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_qos.h @@ -79,4 +79,6 @@ int sparx5_tc_ets_add(struct sparx5_port *port, int sparx5_tc_ets_del(struct sparx5_port *port); +u32 sparx5_get_hsch_max_group_rate(int grp); + #endif /* __SPARX5_QOS_H__ */ diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c new file mode 100644 index 00000000000000..220e81b714d414 --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Microchip Sparx5 Switch driver + * + * Copyright (c) 2024 Microchip Technology Inc. + */ + +/* This file is autogenerated by cml-utils 2024-09-30 11:48:29 +0200. + * Commit ID: 9d07b8d19363f3cd3590ddb3f7a2e2768e16524b + */ + +#include "sparx5_regs.h" + +const unsigned int sparx5_tsize[TSIZE_LAST] = { + [TC_DEV10G] = 12, + [TC_DEV2G5] = 65, + [TC_DEV5G] = 13, + [TC_PCS10G_BR] = 12, + [TC_PCS5G_BR] = 13, +}; + +const unsigned int sparx5_raddr[RADDR_LAST] = { + [RA_CPU_PROC_CTRL] = 176, + [RA_GCB_SOFT_RST] = 8, + [RA_GCB_HW_SGPIO_TO_SD_MAP_CFG] = 24, +}; + +const unsigned int sparx5_rcnt[RCNT_LAST] = { + [RC_ANA_AC_OWN_UPSID] = 3, + [RC_ANA_ACL_VCAP_S2_CFG] = 70, + [RC_ANA_ACL_OWN_UPSID] = 3, + [RC_ANA_CL_OWN_UPSID] = 3, + [RC_ANA_L2_OWN_UPSID] = 3, + [RC_ASM_PORT_CFG] = 67, + [RC_DSM_BUF_CFG] = 67, + [RC_DSM_DEV_TX_STOP_WM_CFG] = 67, + [RC_DSM_RX_PAUSE_CFG] = 67, + [RC_DSM_MAC_CFG] = 67, + [RC_DSM_MAC_ADDR_BASE_HIGH_CFG] = 65, + [RC_DSM_MAC_ADDR_BASE_LOW_CFG] = 65, + [RC_DSM_TAXI_CAL_CFG] = 9, + [RC_GCB_HW_SGPIO_TO_SD_MAP_CFG] = 65, + [RC_HSCH_PORT_MODE] = 70, + [RC_QFWD_SWITCH_PORT_MODE] = 70, + [RC_QSYS_PAUSE_CFG] = 70, + [RC_QSYS_ATOP] = 70, + [RC_QSYS_FWD_PRESSURE] = 70, + [RC_QSYS_CAL_AUTO] = 7, + [RC_REW_OWN_UPSID] = 3, + [RC_REW_RTAG_ETAG_CTRL] = 70, +}; + +const unsigned int sparx5_gaddr[GADDR_LAST] = { + [GA_ANA_AC_RAM_CTRL] = 839108, + [GA_ANA_AC_PS_COMMON] = 894472, + [GA_ANA_AC_MIRROR_PROBE] = 893696, + [GA_ANA_AC_SRC] = 849920, + [GA_ANA_AC_PGID] = 786432, + [GA_ANA_AC_TSN_SF] = 839136, + [GA_ANA_AC_TSN_SF_CFG] = 839680, + [GA_ANA_AC_TSN_SF_STATUS] = 839072, + [GA_ANA_AC_SG_ACCESS] = 839140, + [GA_ANA_AC_SG_CONFIG] = 851584, + [GA_ANA_AC_SG_STATUS] = 839088, + [GA_ANA_AC_SG_STATUS_STICKY] = 839152, + [GA_ANA_AC_STAT_GLOBAL_CFG_PORT] = 851552, + [GA_ANA_AC_STAT_CNT_CFG_PORT] = 843776, + [GA_ANA_AC_STAT_GLOBAL_CFG_ACL] = 893792, + [GA_ANA_ACL_COMMON] = 32768, + [GA_ANA_ACL_KEY_SEL] = 34200, + [GA_ANA_ACL_CNT_B] = 16384, + [GA_ANA_ACL_STICKY] = 36408, + [GA_ANA_AC_POL_POL_ALL_CFG] = 75968, + [GA_ANA_AC_POL_COMMON_BDLB] = 79048, + [GA_ANA_AC_POL_COMMON_BUM_SLB] = 79056, + [GA_ANA_AC_SDLB_LBGRP_TBL] = 295468, + [GA_ANA_CL_PORT] = 131072, + [GA_ANA_CL_COMMON] = 166912, + [GA_ANA_L2_COMMON] = 566024, + [GA_ANA_L3_COMMON] = 493632, + [GA_ANA_L3_VLAN_ARP_L3MC_STICKY] = 491460, + [GA_ASM_CFG] = 33280, + [GA_ASM_PFC_TIMER_CFG] = 34716, + [GA_ASM_LBK_WM_CFG] = 34744, + [GA_ASM_LBK_MISC_CFG] = 34756, + [GA_ASM_RAM_CTRL] = 34832, + [GA_EACL_ES2_KEY_SELECT_PROFILE] = 149504, + [GA_EACL_CNT_TBL] = 122880, + [GA_EACL_POL_CFG] = 150608, + [GA_EACL_ES2_STICKY] = 118696, + [GA_EACL_RAM_CTRL] = 118736, + [GA_GCB_SIO_CTRL] = 876, + [GA_HSCH_HSCH_DWRR] = 162816, + [GA_HSCH_HSCH_MISC] = 163104, + [GA_HSCH_HSCH_LEAK_LISTS] = 161664, + [GA_HSCH_SYSTEM] = 184000, + [GA_HSCH_MMGT] = 162368, + [GA_HSCH_TAS_CONFIG] = 162384, + [GA_PTP_PTP_CFG] = 320, + [GA_PTP_PTP_TOD_DOMAINS] = 336, + [GA_PTP_PHASE_DETECTOR_CTRL] = 420, + [GA_QSYS_CALCFG] = 2304, + [GA_QSYS_RAM_CTRL] = 2344, + [GA_REW_COMMON] = 387264, + [GA_REW_PORT] = 360448, + [GA_REW_VOE_PORT_LM_CNT] = 393216, + [GA_REW_RAM_CTRL] = 378696, + [GA_VOP_RAM_CTRL] = 279176, + [GA_XQS_SYSTEM] = 6768, + [GA_XQS_QLIMIT_SHR] = 7936, +}; + +const unsigned int sparx5_gcnt[GCNT_LAST] = { + [GC_ANA_AC_SRC] = 102, + [GC_ANA_AC_PGID] = 3290, + [GC_ANA_AC_TSN_SF_CFG] = 1024, + [GC_ANA_AC_STAT_CNT_CFG_PORT] = 70, + [GC_ANA_ACL_KEY_SEL] = 134, + [GC_ANA_ACL_CNT_A] = 4096, + [GC_ANA_ACL_CNT_B] = 4096, + [GC_ANA_AC_SDLB_LBGRP_TBL] = 10, + [GC_ANA_AC_SDLB_LBSET_TBL] = 4616, + [GC_ANA_CL_PORT] = 70, + [GC_ANA_L2_ISDX_LIMIT] = 1536, + [GC_ANA_L2_ISDX] = 4096, + [GC_ANA_L3_VLAN] = 5120, + [GC_ASM_DEV_STATISTICS] = 65, + [GC_EACL_ES2_KEY_SELECT_PROFILE] = 138, + [GC_EACL_CNT_TBL] = 2048, + [GC_GCB_SIO_CTRL] = 3, + [GC_HSCH_HSCH_CFG] = 5040, + [GC_HSCH_HSCH_DWRR] = 72, + [GC_PTP_PTP_PINS] = 5, + [GC_PTP_PHASE_DETECTOR_CTRL] = 5, + [GC_REW_PORT] = 70, + [GC_REW_VOE_PORT_LM_CNT] = 520, +}; + +const unsigned int sparx5_gsize[GSIZE_LAST] = { + [GW_ANA_AC_SRC] = 16, + [GW_ANA_L2_COMMON] = 700, + [GW_ASM_CFG] = 1088, + [GW_CPU_CPU_REGS] = 204, + [GW_DEV2G5_PHASE_DETECTOR_CTRL] = 8, + [GW_FDMA_FDMA] = 428, + [GW_GCB_CHIP_REGS] = 424, + [GW_HSCH_TAS_CONFIG] = 12, + [GW_PTP_PHASE_DETECTOR_CTRL] = 8, + [GW_QSYS_PAUSE_CFG] = 1128, +}; + +const unsigned int sparx5_fpos[FPOS_LAST] = { + [FP_CPU_PROC_CTRL_AARCH64_MODE_ENA] = 12, + [FP_CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS] = 11, + [FP_CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS] = 10, + [FP_CPU_PROC_CTRL_BE_EXCEP_MODE] = 9, + [FP_CPU_PROC_CTRL_VINITHI] = 8, + [FP_CPU_PROC_CTRL_CFGTE] = 7, + [FP_CPU_PROC_CTRL_CP15S_DISABLE] = 6, + [FP_CPU_PROC_CTRL_PROC_CRYPTO_DISABLE] = 5, + [FP_CPU_PROC_CTRL_L2_FLUSH_REQ] = 1, + [FP_DEV2G5_PHAD_CTRL_PHAD_ENA] = 7, + [FP_DEV2G5_PHAD_CTRL_PHAD_FAILED] = 6, + [FP_FDMA_CH_CFG_CH_XTR_STATUS_MODE] = 7, + [FP_FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY] = 6, + [FP_FDMA_CH_CFG_CH_INJ_PORT] = 5, + [FP_PTP_PTP_PIN_CFG_PTP_PIN_ACTION] = 26, + [FP_PTP_PTP_PIN_CFG_PTP_PIN_SYNC] = 24, + [FP_PTP_PTP_PIN_CFG_PTP_PIN_INV_POL] = 23, + [FP_PTP_PHAD_CTRL_PHAD_ENA] = 7, + [FP_PTP_PHAD_CTRL_PHAD_FAILED] = 6, +}; + +const unsigned int sparx5_fsize[FSIZE_LAST] = { + [FW_ANA_AC_PROBE_PORT_CFG_PROBE_PORT_MASK] = 32, + [FW_ANA_AC_SRC_CFG_PORT_MASK] = 32, + [FW_ANA_AC_PGID_CFG_PORT_MASK] = 32, + [FW_ANA_AC_TSN_SF_PORT_NUM] = 9, + [FW_ANA_AC_TSN_SF_CFG_TSN_SGID] = 10, + [FW_ANA_AC_TSN_SF_STATUS_TSN_SFID] = 10, + [FW_ANA_AC_SG_ACCESS_CTRL_SGID] = 10, + [FW_ANA_AC_PORT_SGE_CFG_MASK] = 16, + [FW_ANA_AC_SDLB_XLB_START_LBSET_START] = 13, + [FW_ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT] = 5, + [FW_ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT] = 13, + [FW_ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT] = 13, + [FW_ANA_AC_SDLB_XLB_NEXT_LBGRP] = 4, + [FW_ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR] = 13, + [FW_ANA_L2_AUTO_LRN_CFG_AUTO_LRN_ENA] = 32, + [FW_ANA_L2_DLB_CFG_DLB_IDX] = 13, + [FW_ANA_L2_TSN_CFG_TSN_SFID] = 10, + [FW_ANA_L3_VLAN_MASK_CFG_VLAN_PORT_MASK] = 32, + [FW_FDMA_CH_CFG_CH_DCB_DB_CNT] = 4, + [FW_GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL] = 9, + [FW_HSCH_SE_CFG_SE_DWRR_CNT] = 7, + [FW_HSCH_SE_CONNECT_SE_LEAK_LINK] = 16, + [FW_HSCH_SE_DLB_SENSE_SE_DLB_DPORT] = 7, + [FW_HSCH_HSCH_CFG_CFG_CFG_SE_IDX] = 13, + [FW_HSCH_HSCH_LEAK_CFG_LEAK_FIRST] = 16, + [FW_HSCH_FLUSH_CTRL_FLUSH_PORT] = 7, + [FW_HSCH_FLUSH_CTRL_FLUSH_HIER] = 16, + [FW_LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW] = 14, + [FW_LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX] = 11, + [FW_LRN_AUTOAGE_CFG_2_NEXT_ROW] = 14, + [FW_PTP_PTP_PIN_INTR_INTR_PTP] = 5, + [FW_PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA] = 5, + [FW_PTP_PTP_INTR_IDENT_INTR_PTP_IDENT] = 5, + [FW_PTP_PTP_PIN_CFG_PTP_PIN_SELECT] = 2, + [FW_QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL] = 7, + [FW_QRES_RES_CFG_WM_HIGH] = 12, + [FW_QRES_RES_STAT_MAXUSE] = 21, + [FW_QRES_RES_STAT_CUR_INUSE] = 21, + [FW_QSYS_PAUSE_CFG_PAUSE_START] = 12, + [FW_QSYS_PAUSE_CFG_PAUSE_STOP] = 12, + [FW_QSYS_ATOP_ATOP] = 12, + [FW_QSYS_ATOP_TOT_CFG_ATOP_TOT] = 12, + [FW_REW_RTAG_ETAG_CTRL_IPE_TBL] = 7, + [FW_XQS_STAT_CFG_STAT_VIEW] = 13, + [FW_XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP] = 15, + [FW_XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP] = 15, + [FW_XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP] = 15, + [FW_XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM] = 15, +}; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h new file mode 100644 index 00000000000000..ea28130c2341bb --- /dev/null +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_regs.h @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Microchip Sparx5 Switch driver + * + * Copyright (c) 2024 Microchip Technology Inc. + */ + +/* This file is autogenerated by cml-utils 2024-09-30 11:48:29 +0200. + * Commit ID: 9d07b8d19363f3cd3590ddb3f7a2e2768e16524b + */ + +#ifndef _SPARX5_REGS_H_ +#define _SPARX5_REGS_H_ + +/* These enumerated values are used to index the platform specific structs + * containing the addresses, counts, size and positions, of register groups, + * registers and fields. + */ + +enum sparx5_tsize_enum { + TC_DEV10G, + TC_DEV2G5, + TC_DEV5G, + TC_PCS10G_BR, + TC_PCS5G_BR, + TSIZE_LAST, +}; + +enum sparx5_raddr_enum { + RA_CPU_PROC_CTRL, + RA_GCB_SOFT_RST, + RA_GCB_HW_SGPIO_TO_SD_MAP_CFG, + RADDR_LAST, +}; + +enum sparx5_rcnt_enum { + RC_ANA_AC_OWN_UPSID, + RC_ANA_ACL_VCAP_S2_CFG, + RC_ANA_ACL_OWN_UPSID, + RC_ANA_CL_OWN_UPSID, + RC_ANA_L2_OWN_UPSID, + RC_ASM_PORT_CFG, + RC_DSM_BUF_CFG, + RC_DSM_DEV_TX_STOP_WM_CFG, + RC_DSM_RX_PAUSE_CFG, + RC_DSM_MAC_CFG, + RC_DSM_MAC_ADDR_BASE_HIGH_CFG, + RC_DSM_MAC_ADDR_BASE_LOW_CFG, + RC_DSM_TAXI_CAL_CFG, + RC_GCB_HW_SGPIO_TO_SD_MAP_CFG, + RC_HSCH_PORT_MODE, + RC_QFWD_SWITCH_PORT_MODE, + RC_QSYS_PAUSE_CFG, + RC_QSYS_ATOP, + RC_QSYS_FWD_PRESSURE, + RC_QSYS_CAL_AUTO, + RC_REW_OWN_UPSID, + RC_REW_RTAG_ETAG_CTRL, + RCNT_LAST, +}; + +enum sparx5_gaddr_enum { + GA_ANA_AC_RAM_CTRL, + GA_ANA_AC_PS_COMMON, + GA_ANA_AC_MIRROR_PROBE, + GA_ANA_AC_SRC, + GA_ANA_AC_PGID, + GA_ANA_AC_TSN_SF, + GA_ANA_AC_TSN_SF_CFG, + GA_ANA_AC_TSN_SF_STATUS, + GA_ANA_AC_SG_ACCESS, + GA_ANA_AC_SG_CONFIG, + GA_ANA_AC_SG_STATUS, + GA_ANA_AC_SG_STATUS_STICKY, + GA_ANA_AC_STAT_GLOBAL_CFG_PORT, + GA_ANA_AC_STAT_CNT_CFG_PORT, + GA_ANA_AC_STAT_GLOBAL_CFG_ACL, + GA_ANA_ACL_COMMON, + GA_ANA_ACL_KEY_SEL, + GA_ANA_ACL_CNT_B, + GA_ANA_ACL_STICKY, + GA_ANA_AC_POL_POL_ALL_CFG, + GA_ANA_AC_POL_COMMON_BDLB, + GA_ANA_AC_POL_COMMON_BUM_SLB, + GA_ANA_AC_SDLB_LBGRP_TBL, + GA_ANA_CL_PORT, + GA_ANA_CL_COMMON, + GA_ANA_L2_COMMON, + GA_ANA_L3_COMMON, + GA_ANA_L3_VLAN_ARP_L3MC_STICKY, + GA_ASM_CFG, + GA_ASM_PFC_TIMER_CFG, + GA_ASM_LBK_WM_CFG, + GA_ASM_LBK_MISC_CFG, + GA_ASM_RAM_CTRL, + GA_EACL_ES2_KEY_SELECT_PROFILE, + GA_EACL_CNT_TBL, + GA_EACL_POL_CFG, + GA_EACL_ES2_STICKY, + GA_EACL_RAM_CTRL, + GA_GCB_SIO_CTRL, + GA_HSCH_HSCH_DWRR, + GA_HSCH_HSCH_MISC, + GA_HSCH_HSCH_LEAK_LISTS, + GA_HSCH_SYSTEM, + GA_HSCH_MMGT, + GA_HSCH_TAS_CONFIG, + GA_PTP_PTP_CFG, + GA_PTP_PTP_TOD_DOMAINS, + GA_PTP_PHASE_DETECTOR_CTRL, + GA_QSYS_CALCFG, + GA_QSYS_RAM_CTRL, + GA_REW_COMMON, + GA_REW_PORT, + GA_REW_VOE_PORT_LM_CNT, + GA_REW_RAM_CTRL, + GA_VOP_RAM_CTRL, + GA_XQS_SYSTEM, + GA_XQS_QLIMIT_SHR, + GADDR_LAST, +}; + +enum sparx5_gcnt_enum { + GC_ANA_AC_SRC, + GC_ANA_AC_PGID, + GC_ANA_AC_TSN_SF_CFG, + GC_ANA_AC_STAT_CNT_CFG_PORT, + GC_ANA_ACL_KEY_SEL, + GC_ANA_ACL_CNT_A, + GC_ANA_ACL_CNT_B, + GC_ANA_AC_SDLB_LBGRP_TBL, + GC_ANA_AC_SDLB_LBSET_TBL, + GC_ANA_CL_PORT, + GC_ANA_L2_ISDX_LIMIT, + GC_ANA_L2_ISDX, + GC_ANA_L3_VLAN, + GC_ASM_DEV_STATISTICS, + GC_EACL_ES2_KEY_SELECT_PROFILE, + GC_EACL_CNT_TBL, + GC_GCB_SIO_CTRL, + GC_HSCH_HSCH_CFG, + GC_HSCH_HSCH_DWRR, + GC_PTP_PTP_PINS, + GC_PTP_PHASE_DETECTOR_CTRL, + GC_REW_PORT, + GC_REW_VOE_PORT_LM_CNT, + GCNT_LAST, +}; + +enum sparx5_gsize_enum { + GW_ANA_AC_SRC, + GW_ANA_L2_COMMON, + GW_ASM_CFG, + GW_CPU_CPU_REGS, + GW_DEV2G5_PHASE_DETECTOR_CTRL, + GW_FDMA_FDMA, + GW_GCB_CHIP_REGS, + GW_HSCH_TAS_CONFIG, + GW_PTP_PHASE_DETECTOR_CTRL, + GW_QSYS_PAUSE_CFG, + GSIZE_LAST, +}; + +enum sparx5_fpos_enum { + FP_CPU_PROC_CTRL_AARCH64_MODE_ENA, + FP_CPU_PROC_CTRL_L2_RST_INVALIDATE_DIS, + FP_CPU_PROC_CTRL_L1_RST_INVALIDATE_DIS, + FP_CPU_PROC_CTRL_BE_EXCEP_MODE, + FP_CPU_PROC_CTRL_VINITHI, + FP_CPU_PROC_CTRL_CFGTE, + FP_CPU_PROC_CTRL_CP15S_DISABLE, + FP_CPU_PROC_CTRL_PROC_CRYPTO_DISABLE, + FP_CPU_PROC_CTRL_L2_FLUSH_REQ, + FP_DEV2G5_PHAD_CTRL_PHAD_ENA, + FP_DEV2G5_PHAD_CTRL_PHAD_FAILED, + FP_FDMA_CH_CFG_CH_XTR_STATUS_MODE, + FP_FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY, + FP_FDMA_CH_CFG_CH_INJ_PORT, + FP_PTP_PTP_PIN_CFG_PTP_PIN_ACTION, + FP_PTP_PTP_PIN_CFG_PTP_PIN_SYNC, + FP_PTP_PTP_PIN_CFG_PTP_PIN_INV_POL, + FP_PTP_PHAD_CTRL_PHAD_ENA, + FP_PTP_PHAD_CTRL_PHAD_FAILED, + FPOS_LAST, +}; + +enum sparx5_fsize_enum { + FW_ANA_AC_PROBE_PORT_CFG_PROBE_PORT_MASK, + FW_ANA_AC_SRC_CFG_PORT_MASK, + FW_ANA_AC_PGID_CFG_PORT_MASK, + FW_ANA_AC_TSN_SF_PORT_NUM, + FW_ANA_AC_TSN_SF_CFG_TSN_SGID, + FW_ANA_AC_TSN_SF_STATUS_TSN_SFID, + FW_ANA_AC_SG_ACCESS_CTRL_SGID, + FW_ANA_AC_PORT_SGE_CFG_MASK, + FW_ANA_AC_SDLB_XLB_START_LBSET_START, + FW_ANA_AC_SDLB_LBGRP_MISC_THRES_SHIFT, + FW_ANA_AC_SDLB_LBGRP_STATE_TBL_PUP_LBSET_NEXT, + FW_ANA_AC_SDLB_XLB_NEXT_LBSET_NEXT, + FW_ANA_AC_SDLB_XLB_NEXT_LBGRP, + FW_ANA_AC_SDLB_INH_LBSET_ADDR_INH_LBSET_ADDR, + FW_ANA_L2_AUTO_LRN_CFG_AUTO_LRN_ENA, + FW_ANA_L2_DLB_CFG_DLB_IDX, + FW_ANA_L2_TSN_CFG_TSN_SFID, + FW_ANA_L3_VLAN_MASK_CFG_VLAN_PORT_MASK, + FW_FDMA_CH_CFG_CH_DCB_DB_CNT, + FW_GCB_HW_SGPIO_TO_SD_MAP_CFG_SGPIO_TO_SD_SEL, + FW_HSCH_SE_CFG_SE_DWRR_CNT, + FW_HSCH_SE_CONNECT_SE_LEAK_LINK, + FW_HSCH_SE_DLB_SENSE_SE_DLB_DPORT, + FW_HSCH_HSCH_CFG_CFG_CFG_SE_IDX, + FW_HSCH_HSCH_LEAK_CFG_LEAK_FIRST, + FW_HSCH_FLUSH_CTRL_FLUSH_PORT, + FW_HSCH_FLUSH_CTRL_FLUSH_HIER, + FW_LRN_COMMON_ACCESS_CTRL_CPU_ACCESS_DIRECT_ROW, + FW_LRN_MAC_ACCESS_CFG_3_MAC_ENTRY_ISDX_LIMIT_IDX, + FW_LRN_AUTOAGE_CFG_2_NEXT_ROW, + FW_PTP_PTP_PIN_INTR_INTR_PTP, + FW_PTP_PTP_PIN_INTR_ENA_INTR_PTP_ENA, + FW_PTP_PTP_INTR_IDENT_INTR_PTP_IDENT, + FW_PTP_PTP_PIN_CFG_PTP_PIN_SELECT, + FW_QFWD_FRAME_COPY_CFG_FRMC_PORT_VAL, + FW_QRES_RES_CFG_WM_HIGH, + FW_QRES_RES_STAT_MAXUSE, + FW_QRES_RES_STAT_CUR_INUSE, + FW_QSYS_PAUSE_CFG_PAUSE_START, + FW_QSYS_PAUSE_CFG_PAUSE_STOP, + FW_QSYS_ATOP_ATOP, + FW_QSYS_ATOP_TOT_CFG_ATOP_TOT, + FW_REW_RTAG_ETAG_CTRL_IPE_TBL, + FW_XQS_STAT_CFG_STAT_VIEW, + FW_XQS_QLIMIT_SHR_TOP_CFG_QLIMIT_SHR_TOP, + FW_XQS_QLIMIT_SHR_ATOP_CFG_QLIMIT_SHR_ATOP, + FW_XQS_QLIMIT_SHR_CTOP_CFG_QLIMIT_SHR_CTOP, + FW_XQS_QLIMIT_SHR_QLIM_CFG_QLIMIT_SHR_QLIM, + FSIZE_LAST, +}; + +extern const unsigned int sparx5_tsize[TSIZE_LAST]; +extern const unsigned int sparx5_raddr[RADDR_LAST]; +extern const unsigned int sparx5_rcnt[RCNT_LAST]; +extern const unsigned int sparx5_gaddr[GADDR_LAST]; +extern const unsigned int sparx5_gcnt[GCNT_LAST]; +extern const unsigned int sparx5_gsize[GSIZE_LAST]; +extern const unsigned int sparx5_fpos[FPOS_LAST]; +extern const unsigned int sparx5_fsize[FSIZE_LAST]; + +#endif /* _SPARX5_REGS_H_ */ diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c b/drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c index f5267218caeb65..98a3f44c569c98 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_sdlb.c @@ -20,17 +20,18 @@ struct sparx5_sdlb_group sdlb_groups[SPX5_SDLB_GROUP_CNT] = { { 5000000ULL, 8192 / 8, 64 } /* 5 M */ }; -int sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5) +struct sparx5_sdlb_group *sparx5_get_sdlb_group(int idx) +{ + return &sdlb_groups[idx]; +} + +u64 sparx5_sdlb_clk_hz_get(struct sparx5 *sparx5) { - u32 clk_per_100ps; u64 clk_hz; - clk_per_100ps = HSCH_SYS_CLK_PER_100PS_GET(spx5_rd(sparx5, - HSCH_SYS_CLK_PER)); - if (!clk_per_100ps) - clk_per_100ps = SPX5_CLK_PER_100PS_DEFAULT; + clk_hz = (10 * 1000 * 1000) / + (sparx5_clk_period(sparx5->coreclock) / 100); - clk_hz = (10 * 1000 * 1000) / clk_per_100ps; return clk_hz *= 1000; } @@ -178,14 +179,15 @@ static int sparx5_sdlb_group_get_count(struct sparx5 *sparx5, u32 group) int sparx5_sdlb_group_get_by_rate(struct sparx5 *sparx5, u32 rate, u32 burst) { + const struct sparx5_ops *ops = sparx5->data->ops; const struct sparx5_sdlb_group *group; u64 rate_bps; int i, count; rate_bps = rate * 1000; - for (i = SPX5_SDLB_GROUP_CNT - 1; i >= 0; i--) { - group = &sdlb_groups[i]; + for (i = sparx5->data->consts->n_lb_groups - 1; i >= 0; i--) { + group = ops->get_sdlb_group(i); count = sparx5_sdlb_group_get_count(sparx5, i); @@ -208,7 +210,7 @@ int sparx5_sdlb_group_get_by_index(struct sparx5 *sparx5, u32 idx, u32 *group) u32 itr, next; int i; - for (i = 0; i < SPX5_SDLB_GROUP_CNT; i++) { + for (i = 0; i < sparx5->data->consts->n_lb_groups; i++) { if (sparx5_sdlb_group_is_empty(sparx5, i)) continue; @@ -303,11 +305,12 @@ int sparx5_sdlb_group_del(struct sparx5 *sparx5, u32 group, u32 idx) void sparx5_sdlb_group_init(struct sparx5 *sparx5, u64 max_rate, u32 min_burst, u32 frame_size, u32 idx) { + const struct sparx5_ops *ops = sparx5->data->ops; u32 thres_shift, mask = 0x01, power = 0; struct sparx5_sdlb_group *group; u64 max_token; - group = &sdlb_groups[idx]; + group = ops->get_sdlb_group(idx); /* Number of positions to right-shift LB's threshold value. */ while ((min_burst & mask) == 0) { diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c index 0b4abc3eb53de9..bc9ecb9392cd35 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c @@ -32,24 +32,34 @@ static int sparx5_port_attr_pre_bridge_flags(struct sparx5_port *port, static void sparx5_port_update_mcast_ip_flood(struct sparx5_port *port, bool flood_flag) { bool should_flood = flood_flag || port->is_mrouter; + struct sparx5 *sparx5 = port->sparx5; int pgid; - for (pgid = PGID_IPV4_MC_DATA; pgid <= PGID_IPV6_MC_CTRL; pgid++) + for (pgid = sparx5_get_pgid(sparx5, PGID_IPV4_MC_DATA); + pgid <= sparx5_get_pgid(sparx5, PGID_IPV6_MC_CTRL); pgid++) sparx5_pgid_update_mask(port, pgid, should_flood); } static void sparx5_port_attr_bridge_flags(struct sparx5_port *port, struct switchdev_brport_flags flags) { + struct sparx5 *sparx5 = port->sparx5; + if (flags.mask & BR_MCAST_FLOOD) { - sparx5_pgid_update_mask(port, PGID_MC_FLOOD, !!(flags.val & BR_MCAST_FLOOD)); + sparx5_pgid_update_mask(port, + sparx5_get_pgid(sparx5, PGID_MC_FLOOD), + !!(flags.val & BR_MCAST_FLOOD)); sparx5_port_update_mcast_ip_flood(port, !!(flags.val & BR_MCAST_FLOOD)); } if (flags.mask & BR_FLOOD) - sparx5_pgid_update_mask(port, PGID_UC_FLOOD, !!(flags.val & BR_FLOOD)); + sparx5_pgid_update_mask(port, + sparx5_get_pgid(sparx5, PGID_UC_FLOOD), + !!(flags.val & BR_FLOOD)); if (flags.mask & BR_BCAST_FLOOD) - sparx5_pgid_update_mask(port, PGID_BCAST, !!(flags.val & BR_BCAST_FLOOD)); + sparx5_pgid_update_mask(port, + sparx5_get_pgid(sparx5, PGID_BCAST), + !!(flags.val & BR_BCAST_FLOOD)); } static void sparx5_attr_stp_state_set(struct sparx5_port *port, @@ -219,7 +229,8 @@ static void sparx5_port_bridge_leave(struct sparx5_port *port, port->vid = NULL_VID; /* Forward frames to CPU */ - sparx5_mact_learn(sparx5, PGID_CPU, port->ndev->dev_addr, 0); + sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), + port->ndev->dev_addr, 0); /* Port enters in host more therefore restore mc list */ __dev_mc_sync(port->ndev, sparx5_mc_sync, sparx5_mc_unsync); @@ -254,7 +265,8 @@ static int sparx5_port_add_addr(struct net_device *dev, bool up) u16 vid = port->pvid; if (up) - sparx5_mact_learn(sparx5, PGID_CPU, port->ndev->dev_addr, vid); + sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), + port->ndev->dev_addr, vid); else sparx5_mact_forget(sparx5, port->ndev->dev_addr, vid); @@ -330,7 +342,8 @@ static void sparx5_switchdev_bridge_fdb_event_work(struct work_struct *work) switch (switchdev_work->event) { case SWITCHDEV_FDB_ADD_TO_DEVICE: if (host_addr) - sparx5_add_mact_entry(sparx5, dev, PGID_CPU, + sparx5_add_mact_entry(sparx5, dev, + sparx5_get_pgid(sparx5, PGID_CPU), fdb_info->addr, vid); else sparx5_add_mact_entry(sparx5, port->ndev, port->portno, @@ -418,8 +431,8 @@ static int sparx5_handle_port_vlan_add(struct net_device *dev, switchdev_blocking_nb); /* Flood broadcast to CPU */ - sparx5_mact_learn(sparx5, PGID_BCAST, dev->broadcast, - v->vid); + sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_BCAST), + dev->broadcast, v->vid); return 0; } @@ -547,7 +560,7 @@ static int sparx5_handle_port_mdb_add(struct net_device *dev, /* Add any mrouter ports to the new entry */ if (is_new && ether_addr_is_ip_mcast(v->addr)) - for (i = 0; i < SPX5_PORTS; i++) + for (i = 0; i < spx5->data->consts->n_ports; i++) if (spx5->ports[i] && spx5->ports[i]->is_mrouter) sparx5_pgid_update_mask(spx5->ports[i], entry->pgid_idx, diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c index e80f3166db7d31..28b2514c833077 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc.c @@ -60,8 +60,8 @@ static int sparx5_tc_setup_block(struct net_device *ndev, cb, ndev, ndev, false); } -static void sparx5_tc_get_layer_and_idx(u32 parent, u32 portno, u32 *layer, - u32 *idx) +static void sparx5_tc_get_layer_and_idx(struct sparx5 *sparx5, u32 parent, + u32 portno, u32 *layer, u32 *idx) { if (parent == TC_H_ROOT) { *layer = 2; @@ -90,8 +90,8 @@ static int sparx5_tc_setup_qdisc_tbf(struct net_device *ndev, struct sparx5_port *port = netdev_priv(ndev); u32 layer, se_idx; - sparx5_tc_get_layer_and_idx(qopt->parent, port->portno, &layer, - &se_idx); + sparx5_tc_get_layer_and_idx(port->sparx5, qopt->parent, port->portno, + &layer, &se_idx); switch (qopt->command) { case TC_TBF_REPLACE: diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c index 8d67d9f24c76bf..4dc1ebd5d510dc 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_tc_flower.c @@ -785,7 +785,9 @@ static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5, * allocate a stream gate that is always open. */ if (sg_idx < 0) { - sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN); + /* Always-open stream gate is always the last */ + sg_idx = sparx5_pool_idx_to_id(sparx5->data->consts->n_gates - + 1); sg->ipv = 0; /* Disabled */ sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT; sg->num_entries = 1; @@ -1282,6 +1284,11 @@ static int sparx5_tc_flower_replace(struct net_device *ndev, /* Setup PSFP */ if (tc_sg_idx >= 0 || tc_pol_idx >= 0) { + if (!sparx5_has_feature(sparx5, SPX5_FEATURE_PSFP)) { + err = -EOPNOTSUPP; + goto out; + } + err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx, tc_pol_idx, &sg, &fm, &sf); if (err) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h index 7d106f1276fe55..e68f5639a40a54 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_ag_api.h @@ -10,6 +10,8 @@ #ifndef __SPARX5_VCAP_AG_API_H__ #define __SPARX5_VCAP_AG_API_H__ +#include "vcap_api.h" + /* VCAPs */ extern const struct vcap_info sparx5_vcaps[]; extern const struct vcap_statistics sparx5_vcap_stats; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c index 967c8621c25051..25066ddb8d4d66 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -17,7 +17,6 @@ #define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */ #define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */ -#define SPARX5_IS2_LOOKUPS 4 #define VCAP_IS2_KEYSEL(_ena, _noneth, _v4_mc, _v4_uc, _v6_mc, _v6_uc, _arp) \ (ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(_ena) | \ ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(_noneth) | \ @@ -27,7 +26,6 @@ ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \ ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp)) -#define SPARX5_IS0_LOOKUPS 6 #define VCAP_IS0_KEYSEL(_ena, _etype, _ipv4, _ipv6, _mpls_uc, _mpls_mc, _mlbs) \ (ANA_CL_ADV_CL_CFG_LOOKUP_ENA_SET(_ena) | \ ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL_SET(_etype) | \ @@ -37,31 +35,17 @@ ANA_CL_ADV_CL_CFG_MPLS_MC_CLM_KEY_SEL_SET(_mpls_mc) | \ ANA_CL_ADV_CL_CFG_MLBS_CLM_KEY_SEL_SET(_mlbs)) -#define SPARX5_ES0_LOOKUPS 1 #define VCAP_ES0_KEYSEL(_key) (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_SET(_key)) #define SPARX5_STAT_ESDX_GRN_PKTS 0x300 #define SPARX5_STAT_ESDX_YEL_PKTS 0x301 -#define SPARX5_ES2_LOOKUPS 2 #define VCAP_ES2_KEYSEL(_ena, _arp, _ipv4, _ipv6) \ (EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(_ena) | \ EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_SET(_arp) | \ EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_SET(_ipv4) | \ EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_SET(_ipv6)) -static struct sparx5_vcap_inst { - enum vcap_type vtype; /* type of vcap */ - int vinst; /* instance number within the same type */ - int lookups; /* number of lookups in this vcap type */ - int lookups_per_instance; /* number of lookups in this instance */ - int first_cid; /* first chain id in this vcap */ - int last_cid; /* last chain id in this vcap */ - int count; /* number of available addresses, not in super vcap */ - int map_id; /* id in the super vcap block mapping (if applicable) */ - int blockno; /* starting block in super vcap (if applicable) */ - int blocks; /* number of blocks in super vcap (if applicable) */ - bool ingress; /* is vcap in the ingress path */ -} sparx5_vcap_inst_cfg[] = { +const struct sparx5_vcap_inst sparx5_vcap_inst_cfg[] = { { .vtype = VCAP_TYPE_IS0, /* CLM-0 */ .vinst = 0, @@ -1793,6 +1777,7 @@ void sparx5_vcap_set_port_keyset(struct net_device *ndev, static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno, lookup; u32 keysel; @@ -1804,7 +1789,7 @@ static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5, VCAP_IS0_PS_MPLS_FOLLOW_ETYPE, VCAP_IS0_PS_MLBS_FOLLOW_ETYPE); for (lookup = 0; lookup < admin->lookups; ++lookup) { - for (portno = 0; portno < SPX5_PORTS; ++portno) { + for (portno = 0; portno < consts->n_ports; ++portno) { spx5_wr(keysel, sparx5, ANA_CL_ADV_CL_CFG(portno, lookup)); spx5_rmw(ANA_CL_ADV_CL_CFG_LOOKUP_ENA, @@ -1819,6 +1804,7 @@ static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5, static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno, lookup; u32 keysel; @@ -1829,13 +1815,13 @@ static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5, VCAP_IS2_PS_IPV6_UC_IP_7TUPLE, VCAP_IS2_PS_ARP_ARP); for (lookup = 0; lookup < admin->lookups; ++lookup) { - for (portno = 0; portno < SPX5_PORTS; ++portno) { + for (portno = 0; portno < consts->n_ports; ++portno) { spx5_wr(keysel, sparx5, ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); } } /* IS2 lookups are in bit 0:3 */ - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), ANA_ACL_VCAP_S2_CFG_SEC_ENA, sparx5, @@ -1846,11 +1832,12 @@ static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5, static void sparx5_vcap_es0_port_key_selection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno; u32 keysel; keysel = VCAP_ES0_KEYSEL(VCAP_ES0_PS_FORCE_ISDX_LOOKUPS); - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(keysel, REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA, sparx5, REW_RTAG_ETAG_CTRL(portno)); @@ -1862,6 +1849,7 @@ static void sparx5_vcap_es0_port_key_selection(struct sparx5 *sparx5, static void sparx5_vcap_es2_port_key_selection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno, lookup; u32 keysel; @@ -1869,7 +1857,7 @@ static void sparx5_vcap_es2_port_key_selection(struct sparx5 *sparx5, VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER, VCAP_ES2_PS_IPV6_IP_7TUPLE); for (lookup = 0; lookup < admin->lookups; ++lookup) - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_wr(keysel, sparx5, EACL_VCAP_ES2_KEY_SEL(portno, lookup)); } @@ -1901,19 +1889,20 @@ static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5, static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5, struct vcap_admin *admin) { + const struct sparx5_consts *consts = sparx5->data->consts; int portno, lookup; switch (admin->vtype) { case VCAP_TYPE_IS0: for (lookup = 0; lookup < admin->lookups; ++lookup) - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(ANA_CL_ADV_CL_CFG_LOOKUP_ENA_SET(0), ANA_CL_ADV_CL_CFG_LOOKUP_ENA, sparx5, ANA_CL_ADV_CL_CFG(portno, lookup)); break; case VCAP_TYPE_IS2: - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), ANA_ACL_VCAP_S2_CFG_SEC_ENA, sparx5, @@ -1925,7 +1914,7 @@ static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5, break; case VCAP_TYPE_ES2: for (lookup = 0; lookup < admin->lookups; ++lookup) - for (portno = 0; portno < SPX5_PORTS; ++portno) + for (portno = 0; portno < consts->n_ports; ++portno) spx5_rmw(EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(0), EACL_VCAP_ES2_KEY_SEL_KEY_ENA, sparx5, @@ -2042,6 +2031,7 @@ static void sparx5_vcap_block_alloc(struct sparx5 *sparx5, /* Allocate a vcap control and vcap instances and configure the system */ int sparx5_vcap_init(struct sparx5 *sparx5) { + const struct sparx5_consts *consts = sparx5->data->consts; const struct sparx5_vcap_inst *cfg; struct vcap_control *ctrl; struct vcap_admin *admin; @@ -2063,14 +2053,14 @@ int sparx5_vcap_init(struct sparx5 *sparx5) sparx5->vcap_ctrl = ctrl; /* select the sparx5 VCAP model */ - ctrl->vcaps = sparx5_vcaps; - ctrl->stats = &sparx5_vcap_stats; + ctrl->vcaps = consts->vcaps; + ctrl->stats = consts->vcap_stats; /* Setup callbacks to allow the API to use the VCAP HW */ ctrl->ops = &sparx5_vcap_ops; INIT_LIST_HEAD(&ctrl->list); for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) { - cfg = &sparx5_vcap_inst_cfg[idx]; + cfg = &consts->vcaps_cfg[idx]; admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg); if (IS_ERR(admin)) { err = PTR_ERR(admin); @@ -2085,7 +2075,7 @@ int sparx5_vcap_init(struct sparx5 *sparx5) list_add_tail(&admin->list, &ctrl->list); } dir = vcap_debugfs(sparx5->dev, sparx5->debugfs_root, ctrl); - for (idx = 0; idx < SPX5_PORTS; ++idx) + for (idx = 0; idx < consts->n_ports; ++idx) if (sparx5->ports[idx]) vcap_port_debugfs(sparx5->dev, dir, ctrl, sparx5->ports[idx]->ndev); diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h index 2684d9199b05aa..d0a42406bf26c1 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.h @@ -16,6 +16,11 @@ #include "vcap_api.h" #include "vcap_api_client.h" +#define SPARX5_IS2_LOOKUPS 4 +#define SPARX5_IS0_LOOKUPS 6 +#define SPARX5_ES0_LOOKUPS 1 +#define SPARX5_ES2_LOOKUPS 2 + #define SPARX5_VCAP_CID_IS0_L0 VCAP_CID_INGRESS_L0 /* IS0/CLM lookup 0 */ #define SPARX5_VCAP_CID_IS0_L1 VCAP_CID_INGRESS_L1 /* IS0/CLM lookup 1 */ #define SPARX5_VCAP_CID_IS0_L2 VCAP_CID_INGRESS_L2 /* IS0/CLM lookup 2 */ @@ -40,6 +45,22 @@ #define SPARX5_VCAP_CID_ES2_MAX \ (VCAP_CID_EGRESS_STAGE2_L1 + VCAP_CID_LOOKUP_SIZE - 1) /* ES2 Max */ +struct sparx5_vcap_inst { + enum vcap_type vtype; /* type of vcap */ + int vinst; /* instance number within the same type */ + int lookups; /* number of lookups in this vcap type */ + int lookups_per_instance; /* number of lookups in this instance */ + int first_cid; /* first chain id in this vcap */ + int last_cid; /* last chain id in this vcap */ + int count; /* number of available addresses, not in super vcap */ + int map_id; /* id in the super vcap block mapping (if applicable) */ + int blockno; /* starting block in super vcap (if applicable) */ + int blocks; /* number of blocks in super vcap (if applicable) */ + bool ingress; /* is vcap in the ingress path */ +}; + +extern const struct sparx5_vcap_inst sparx5_vcap_inst_cfg[]; + /* IS0 port keyset selection control */ /* IS0 ethernet, IPv4, IPv6 traffic type keyset generation */ diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c index ac001ae59a3856..d42097aa60a0e4 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c @@ -16,8 +16,10 @@ static int sparx5_vlant_set_mask(struct sparx5 *sparx5, u16 vid) /* Output mask to respective registers */ spx5_wr(mask[0], sparx5, ANA_L3_VLAN_MASK_CFG(vid)); - spx5_wr(mask[1], sparx5, ANA_L3_VLAN_MASK_CFG1(vid)); - spx5_wr(mask[2], sparx5, ANA_L3_VLAN_MASK_CFG2(vid)); + if (is_sparx5(sparx5)) { + spx5_wr(mask[1], sparx5, ANA_L3_VLAN_MASK_CFG1(vid)); + spx5_wr(mask[2], sparx5, ANA_L3_VLAN_MASK_CFG2(vid)); + } return 0; } @@ -141,15 +143,19 @@ void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable) void sparx5_pgid_clear(struct sparx5 *spx5, int pgid) { spx5_wr(0, spx5, ANA_AC_PGID_CFG(pgid)); - spx5_wr(0, spx5, ANA_AC_PGID_CFG1(pgid)); - spx5_wr(0, spx5, ANA_AC_PGID_CFG2(pgid)); + if (is_sparx5(spx5)) { + spx5_wr(0, spx5, ANA_AC_PGID_CFG1(pgid)); + spx5_wr(0, spx5, ANA_AC_PGID_CFG2(pgid)); + } } void sparx5_pgid_read_mask(struct sparx5 *spx5, int pgid, u32 portmask[3]) { portmask[0] = spx5_rd(spx5, ANA_AC_PGID_CFG(pgid)); - portmask[1] = spx5_rd(spx5, ANA_AC_PGID_CFG1(pgid)); - portmask[2] = spx5_rd(spx5, ANA_AC_PGID_CFG2(pgid)); + if (is_sparx5(spx5)) { + portmask[1] = spx5_rd(spx5, ANA_AC_PGID_CFG1(pgid)); + portmask[2] = spx5_rd(spx5, ANA_AC_PGID_CFG2(pgid)); + } } void sparx5_update_fwd(struct sparx5 *sparx5) @@ -162,26 +168,33 @@ void sparx5_update_fwd(struct sparx5 *sparx5) bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS); /* Update flood masks */ - for (port = PGID_UC_FLOOD; port <= PGID_BCAST; port++) { + for (port = sparx5_get_pgid(sparx5, PGID_UC_FLOOD); + port <= sparx5_get_pgid(sparx5, PGID_BCAST); port++) { spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port)); - spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port)); - spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port)); + if (is_sparx5(sparx5)) { + spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port)); + spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port)); + } } /* Update SRC masks */ - for (port = 0; port < SPX5_PORTS; port++) { + for (port = 0; port < sparx5->data->consts->n_ports; port++) { if (test_bit(port, sparx5->bridge_fwd_mask)) { /* Allow to send to all bridged but self */ bitmap_copy(workmask, sparx5->bridge_fwd_mask, SPX5_PORTS); clear_bit(port, workmask); bitmap_to_arr32(mask, workmask, SPX5_PORTS); spx5_wr(mask[0], sparx5, ANA_AC_SRC_CFG(port)); - spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port)); - spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port)); + if (is_sparx5(sparx5)) { + spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port)); + spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port)); + } } else { spx5_wr(0, sparx5, ANA_AC_SRC_CFG(port)); - spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port)); - spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port)); + if (is_sparx5(sparx5)) { + spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port)); + spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port)); + } } } @@ -192,8 +205,10 @@ void sparx5_update_fwd(struct sparx5 *sparx5) /* Apply learning mask */ spx5_wr(mask[0], sparx5, ANA_L2_AUTO_LRN_CFG); - spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1); - spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2); + if (is_sparx5(sparx5)) { + spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1); + spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2); + } } void sparx5_vlan_port_apply(struct sparx5 *sparx5, diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c index 7251121ab196e3..16eb3de60eb6df 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c @@ -366,12 +366,13 @@ static void vcap_api_iterator_init_test(struct kunit *test) struct vcap_typegroup typegroups[] = { { .offset = 0, .width = 2, .value = 2, }, { .offset = 156, .width = 1, .value = 0, }, - { .offset = 0, .width = 0, .value = 0, }, + { } }; struct vcap_typegroup typegroups2[] = { { .offset = 0, .width = 3, .value = 4, }, { .offset = 49, .width = 2, .value = 0, }, { .offset = 98, .width = 2, .value = 0, }, + { } }; vcap_iter_init(&iter, 52, typegroups, 86); @@ -399,6 +400,7 @@ static void vcap_api_iterator_next_test(struct kunit *test) { .offset = 147, .width = 3, .value = 0, }, { .offset = 196, .width = 2, .value = 0, }, { .offset = 245, .width = 1, .value = 0, }, + { } }; int idx; @@ -433,7 +435,7 @@ static void vcap_api_encode_typegroups_test(struct kunit *test) { .offset = 147, .width = 3, .value = 5, }, { .offset = 196, .width = 2, .value = 2, }, { .offset = 245, .width = 5, .value = 27, }, - { .offset = 0, .width = 0, .value = 0, }, + { } }; vcap_encode_typegroups(stream, 49, typegroups, false); @@ -463,6 +465,7 @@ static void vcap_api_encode_bit_test(struct kunit *test) { .offset = 147, .width = 3, .value = 5, }, { .offset = 196, .width = 2, .value = 2, }, { .offset = 245, .width = 1, .value = 0, }, + { } }; vcap_iter_init(&iter, 49, typegroups, 44); @@ -489,7 +492,7 @@ static void vcap_api_encode_field_test(struct kunit *test) { .offset = 147, .width = 3, .value = 5, }, { .offset = 196, .width = 2, .value = 2, }, { .offset = 245, .width = 5, .value = 27, }, - { .offset = 0, .width = 0, .value = 0, }, + { } }; struct vcap_field rf = { .type = VCAP_FIELD_U32, @@ -538,7 +541,7 @@ static void vcap_api_encode_short_field_test(struct kunit *test) { .offset = 0, .width = 3, .value = 7, }, { .offset = 21, .width = 2, .value = 3, }, { .offset = 42, .width = 1, .value = 1, }, - { .offset = 0, .width = 0, .value = 0, }, + { } }; struct vcap_field rf = { .type = VCAP_FIELD_U32, @@ -608,7 +611,7 @@ static void vcap_api_encode_keyfield_test(struct kunit *test) struct vcap_typegroup tgt[] = { { .offset = 0, .width = 2, .value = 2, }, { .offset = 156, .width = 1, .value = 1, }, - { .offset = 0, .width = 0, .value = 0, }, + { } }; vcap_test_api_init(&admin); @@ -671,7 +674,7 @@ static void vcap_api_encode_max_keyfield_test(struct kunit *test) struct vcap_typegroup tgt[] = { { .offset = 0, .width = 2, .value = 2, }, { .offset = 156, .width = 1, .value = 1, }, - { .offset = 0, .width = 0, .value = 0, }, + { } }; u32 keyres[] = { 0x928e8a84, @@ -732,7 +735,7 @@ static void vcap_api_encode_actionfield_test(struct kunit *test) { .offset = 0, .width = 2, .value = 2, }, { .offset = 21, .width = 1, .value = 1, }, { .offset = 42, .width = 1, .value = 0, }, - { .offset = 0, .width = 0, .value = 0, }, + { } }; vcap_encode_actionfield(&rule, &caf, &rf, tgt); diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c index ca4ed58f1206dd..2dc0c6ad54be22 100644 --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Copyright (c) 2021, Microsoft Corporation. */ +#include #include #include #include @@ -8,6 +9,8 @@ #include +struct dentry *mana_debugfs_root; + static u32 mana_gd_r32(struct gdma_context *g, u64 offset) { return readl(g->bar0_va + offset); @@ -174,7 +177,7 @@ int mana_gd_send_request(struct gdma_context *gc, u32 req_len, const void *req, return mana_hwc_send_request(hwc, req_len, req, resp_len, resp); } -EXPORT_SYMBOL_NS(mana_gd_send_request, NET_MANA); +EXPORT_SYMBOL_NS(mana_gd_send_request, "NET_MANA"); int mana_gd_alloc_memory(struct gdma_context *gc, unsigned int length, struct gdma_mem_info *gmi) @@ -713,7 +716,7 @@ int mana_gd_destroy_dma_region(struct gdma_context *gc, u64 dma_region_handle) return 0; } -EXPORT_SYMBOL_NS(mana_gd_destroy_dma_region, NET_MANA); +EXPORT_SYMBOL_NS(mana_gd_destroy_dma_region, "NET_MANA"); static int mana_gd_create_dma_region(struct gdma_dev *gd, struct gdma_mem_info *gmi) @@ -817,7 +820,7 @@ int mana_gd_create_mana_eq(struct gdma_dev *gd, kfree(queue); return err; } -EXPORT_SYMBOL_NS(mana_gd_create_mana_eq, NET_MANA); +EXPORT_SYMBOL_NS(mana_gd_create_mana_eq, "NET_MANA"); int mana_gd_create_mana_wq_cq(struct gdma_dev *gd, const struct gdma_queue_spec *spec, @@ -894,7 +897,7 @@ void mana_gd_destroy_queue(struct gdma_context *gc, struct gdma_queue *queue) mana_gd_free_memory(gmi); kfree(queue); } -EXPORT_SYMBOL_NS(mana_gd_destroy_queue, NET_MANA); +EXPORT_SYMBOL_NS(mana_gd_destroy_queue, "NET_MANA"); int mana_gd_verify_vf_version(struct pci_dev *pdev) { @@ -971,7 +974,7 @@ int mana_gd_register_device(struct gdma_dev *gd) return 0; } -EXPORT_SYMBOL_NS(mana_gd_register_device, NET_MANA); +EXPORT_SYMBOL_NS(mana_gd_register_device, "NET_MANA"); int mana_gd_deregister_device(struct gdma_dev *gd) { @@ -1002,7 +1005,7 @@ int mana_gd_deregister_device(struct gdma_dev *gd) return err; } -EXPORT_SYMBOL_NS(mana_gd_deregister_device, NET_MANA); +EXPORT_SYMBOL_NS(mana_gd_deregister_device, "NET_MANA"); u32 mana_gd_wq_avail_space(struct gdma_queue *wq) { @@ -1315,7 +1318,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) GFP_KERNEL); if (!gc->irq_contexts) { err = -ENOMEM; - goto free_irq_vector; + goto free_irq_array; } for (i = 0; i < nvec; i++) { @@ -1372,6 +1375,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) gc->max_num_msix = nvec; gc->num_msix_usable = nvec; cpus_read_unlock(); + kfree(irqs); return 0; free_irq: @@ -1384,8 +1388,9 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) } kfree(gc->irq_contexts); - kfree(irqs); gc->irq_contexts = NULL; +free_irq_array: + kfree(irqs); free_irq_vector: cpus_read_unlock(); pci_free_irq_vectors(pdev); @@ -1516,6 +1521,12 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) gc->bar0_va = bar0_va; gc->dev = &pdev->dev; + if (gc->is_pf) + gc->mana_pci_debugfs = debugfs_create_dir("0", mana_debugfs_root); + else + gc->mana_pci_debugfs = debugfs_create_dir(pci_slot_name(pdev->slot), + mana_debugfs_root); + err = mana_gd_setup(pdev); if (err) goto unmap_bar; @@ -1529,6 +1540,13 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) cleanup_gd: mana_gd_cleanup(pdev); unmap_bar: + /* + * at this point we know that the other debugfs child dir/files + * are either not yet created or are already cleaned up. + * The pci debugfs folder clean-up now, will only be cleaning up + * adapter-MTU file and apc->mana_pci_debugfs folder. + */ + debugfs_remove_recursive(gc->mana_pci_debugfs); pci_iounmap(pdev, bar0_va); free_gc: pci_set_drvdata(pdev, NULL); @@ -1549,6 +1567,8 @@ static void mana_gd_remove(struct pci_dev *pdev) mana_gd_cleanup(pdev); + debugfs_remove_recursive(gc->mana_pci_debugfs); + pci_iounmap(pdev, gc->bar0_va); vfree(gc); @@ -1600,6 +1620,8 @@ static void mana_gd_shutdown(struct pci_dev *pdev) mana_gd_cleanup(pdev); + debugfs_remove_recursive(gc->mana_pci_debugfs); + pci_disable_device(pdev); } @@ -1619,7 +1641,28 @@ static struct pci_driver mana_driver = { .shutdown = mana_gd_shutdown, }; -module_pci_driver(mana_driver); +static int __init mana_driver_init(void) +{ + int err; + + mana_debugfs_root = debugfs_create_dir("mana", NULL); + + err = pci_register_driver(&mana_driver); + if (err) + debugfs_remove(mana_debugfs_root); + + return err; +} + +static void __exit mana_driver_exit(void) +{ + debugfs_remove(mana_debugfs_root); + + pci_unregister_driver(&mana_driver); +} + +module_init(mana_driver_init); +module_exit(mana_driver_exit); MODULE_DEVICE_TABLE(pci, mana_id_table); diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index c47266d1c7c279..aa1e47233fe50c 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -3,6 +3,7 @@ #include +#include #include #include #include @@ -30,6 +31,21 @@ static void mana_adev_idx_free(int idx) ida_free(&mana_adev_ida, idx); } +static ssize_t mana_dbg_q_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos) +{ + struct gdma_queue *gdma_q = filp->private_data; + + return simple_read_from_buffer(buf, count, pos, gdma_q->queue_mem_ptr, + gdma_q->queue_size); +} + +static const struct file_operations mana_dbg_q_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = mana_dbg_q_read, +}; + /* Microsoft Azure Network Adapter (MANA) functions */ static int mana_open(struct net_device *ndev) @@ -721,6 +737,13 @@ static const struct net_device_ops mana_devops = { static void mana_cleanup_port_context(struct mana_port_context *apc) { + /* + * at this point all dir/files under the vport directory + * are already cleaned up. + * We are sure the apc->mana_port_debugfs remove will not + * cause any freed memory access issues + */ + debugfs_remove(apc->mana_port_debugfs); kfree(apc->rxqs); apc->rxqs = NULL; } @@ -943,6 +966,8 @@ static int mana_query_device_cfg(struct mana_context *ac, u32 proto_major_ver, else gc->adapter_mtu = ETH_FRAME_LEN; + debugfs_create_u16("adapter-MTU", 0400, gc->mana_pci_debugfs, &gc->adapter_mtu); + return 0; } @@ -997,7 +1022,7 @@ void mana_uncfg_vport(struct mana_port_context *apc) WARN_ON(apc->vport_use_count < 0); mutex_unlock(&apc->vport_mutex); } -EXPORT_SYMBOL_NS(mana_uncfg_vport, NET_MANA); +EXPORT_SYMBOL_NS(mana_uncfg_vport, "NET_MANA"); int mana_cfg_vport(struct mana_port_context *apc, u32 protection_dom_id, u32 doorbell_pg_id) @@ -1067,7 +1092,7 @@ int mana_cfg_vport(struct mana_port_context *apc, u32 protection_dom_id, return err; } -EXPORT_SYMBOL_NS(mana_cfg_vport, NET_MANA); +EXPORT_SYMBOL_NS(mana_cfg_vport, "NET_MANA"); static int mana_cfg_vport_steering(struct mana_port_context *apc, enum TRI_STATE rx, @@ -1189,7 +1214,7 @@ int mana_create_wq_obj(struct mana_port_context *apc, out: return err; } -EXPORT_SYMBOL_NS(mana_create_wq_obj, NET_MANA); +EXPORT_SYMBOL_NS(mana_create_wq_obj, "NET_MANA"); void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type, mana_handle_t wq_obj) @@ -1217,7 +1242,7 @@ void mana_destroy_wq_obj(struct mana_port_context *apc, u32 wq_type, netdev_err(ndev, "Failed to destroy WQ object: %d, 0x%x\n", err, resp.hdr.status); } -EXPORT_SYMBOL_NS(mana_destroy_wq_obj, NET_MANA); +EXPORT_SYMBOL_NS(mana_destroy_wq_obj, "NET_MANA"); static void mana_destroy_eq(struct mana_context *ac) { @@ -1228,6 +1253,8 @@ static void mana_destroy_eq(struct mana_context *ac) if (!ac->eqs) return; + debugfs_remove_recursive(ac->mana_eqs_debugfs); + for (i = 0; i < gc->max_num_queues; i++) { eq = ac->eqs[i].eq; if (!eq) @@ -1240,6 +1267,18 @@ static void mana_destroy_eq(struct mana_context *ac) ac->eqs = NULL; } +static void mana_create_eq_debugfs(struct mana_context *ac, int i) +{ + struct mana_eq eq = ac->eqs[i]; + char eqnum[32]; + + sprintf(eqnum, "eq%d", i); + eq.mana_eq_debugfs = debugfs_create_dir(eqnum, ac->mana_eqs_debugfs); + debugfs_create_u32("head", 0400, eq.mana_eq_debugfs, &eq.eq->head); + debugfs_create_u32("tail", 0400, eq.mana_eq_debugfs, &eq.eq->tail); + debugfs_create_file("eq_dump", 0400, eq.mana_eq_debugfs, eq.eq, &mana_dbg_q_fops); +} + static int mana_create_eq(struct mana_context *ac) { struct gdma_dev *gd = ac->gdma_dev; @@ -1260,11 +1299,14 @@ static int mana_create_eq(struct mana_context *ac) spec.eq.context = ac->eqs; spec.eq.log2_throttle_limit = LOG2_EQ_THROTTLE; + ac->mana_eqs_debugfs = debugfs_create_dir("EQs", gc->mana_pci_debugfs); + for (i = 0; i < gc->max_num_queues; i++) { spec.eq.msix_index = (i + 1) % gc->num_msix_usable; err = mana_gd_create_mana_eq(gd, &spec, &ac->eqs[i].eq); if (err) goto out; + mana_create_eq_debugfs(ac, i); } return 0; @@ -1871,6 +1913,8 @@ static void mana_destroy_txq(struct mana_port_context *apc) return; for (i = 0; i < apc->num_queues; i++) { + debugfs_remove_recursive(apc->tx_qp[i].mana_tx_debugfs); + napi = &apc->tx_qp[i].tx_cq.napi; if (apc->tx_qp[i].txq.napi_initialized) { napi_synchronize(napi); @@ -1889,6 +1933,31 @@ static void mana_destroy_txq(struct mana_port_context *apc) apc->tx_qp = NULL; } +static void mana_create_txq_debugfs(struct mana_port_context *apc, int idx) +{ + struct mana_tx_qp *tx_qp = &apc->tx_qp[idx]; + char qnum[32]; + + sprintf(qnum, "TX-%d", idx); + tx_qp->mana_tx_debugfs = debugfs_create_dir(qnum, apc->mana_port_debugfs); + debugfs_create_u32("sq_head", 0400, tx_qp->mana_tx_debugfs, + &tx_qp->txq.gdma_sq->head); + debugfs_create_u32("sq_tail", 0400, tx_qp->mana_tx_debugfs, + &tx_qp->txq.gdma_sq->tail); + debugfs_create_u32("sq_pend_skb_qlen", 0400, tx_qp->mana_tx_debugfs, + &tx_qp->txq.pending_skbs.qlen); + debugfs_create_u32("cq_head", 0400, tx_qp->mana_tx_debugfs, + &tx_qp->tx_cq.gdma_cq->head); + debugfs_create_u32("cq_tail", 0400, tx_qp->mana_tx_debugfs, + &tx_qp->tx_cq.gdma_cq->tail); + debugfs_create_u32("cq_budget", 0400, tx_qp->mana_tx_debugfs, + &tx_qp->tx_cq.budget); + debugfs_create_file("txq_dump", 0400, tx_qp->mana_tx_debugfs, + tx_qp->txq.gdma_sq, &mana_dbg_q_fops); + debugfs_create_file("cq_dump", 0400, tx_qp->mana_tx_debugfs, + tx_qp->tx_cq.gdma_cq, &mana_dbg_q_fops); +} + static int mana_create_txq(struct mana_port_context *apc, struct net_device *net) { @@ -2000,6 +2069,8 @@ static int mana_create_txq(struct mana_port_context *apc, gc->cq_table[cq->gdma_id] = cq->gdma_cq; + mana_create_txq_debugfs(apc, i); + netif_napi_add_tx(net, &cq->napi, mana_poll); napi_enable(&cq->napi); txq->napi_initialized = true; @@ -2027,6 +2098,8 @@ static void mana_destroy_rxq(struct mana_port_context *apc, if (!rxq) return; + debugfs_remove_recursive(rxq->mana_rx_debugfs); + napi = &rxq->rx_cq.napi; if (napi_initialized) { @@ -2308,6 +2381,28 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc, return NULL; } +static void mana_create_rxq_debugfs(struct mana_port_context *apc, int idx) +{ + struct mana_rxq *rxq; + char qnum[32]; + + rxq = apc->rxqs[idx]; + + sprintf(qnum, "RX-%d", idx); + rxq->mana_rx_debugfs = debugfs_create_dir(qnum, apc->mana_port_debugfs); + debugfs_create_u32("rq_head", 0400, rxq->mana_rx_debugfs, &rxq->gdma_rq->head); + debugfs_create_u32("rq_tail", 0400, rxq->mana_rx_debugfs, &rxq->gdma_rq->tail); + debugfs_create_u32("rq_nbuf", 0400, rxq->mana_rx_debugfs, &rxq->num_rx_buf); + debugfs_create_u32("cq_head", 0400, rxq->mana_rx_debugfs, + &rxq->rx_cq.gdma_cq->head); + debugfs_create_u32("cq_tail", 0400, rxq->mana_rx_debugfs, + &rxq->rx_cq.gdma_cq->tail); + debugfs_create_u32("cq_budget", 0400, rxq->mana_rx_debugfs, &rxq->rx_cq.budget); + debugfs_create_file("rxq_dump", 0400, rxq->mana_rx_debugfs, rxq->gdma_rq, &mana_dbg_q_fops); + debugfs_create_file("cq_dump", 0400, rxq->mana_rx_debugfs, rxq->rx_cq.gdma_cq, + &mana_dbg_q_fops); +} + static int mana_add_rx_queues(struct mana_port_context *apc, struct net_device *ndev) { @@ -2326,6 +2421,8 @@ static int mana_add_rx_queues(struct mana_port_context *apc, u64_stats_init(&rxq->stats.syncp); apc->rxqs[i] = rxq; + + mana_create_rxq_debugfs(apc, i); } apc->default_rxobj = apc->rxqs[0]->rxobj; @@ -2439,6 +2536,7 @@ void mana_query_gf_stats(struct mana_port_context *apc) mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_GF_STAT, sizeof(req), sizeof(resp)); + req.hdr.resp.msg_version = GDMA_MESSAGE_V2; req.req_stats = STATISTICS_FLAGS_RX_DISCARDS_NO_WQE | STATISTICS_FLAGS_RX_ERRORS_VPORT_DISABLED | STATISTICS_FLAGS_HC_RX_BYTES | @@ -2518,14 +2616,19 @@ void mana_query_gf_stats(struct mana_port_context *apc) static int mana_init_port(struct net_device *ndev) { struct mana_port_context *apc = netdev_priv(ndev); + struct gdma_dev *gd = apc->ac->gdma_dev; u32 max_txq, max_rxq, max_queues; int port_idx = apc->port_idx; + struct gdma_context *gc; + char vport[32]; int err; err = mana_init_port_context(apc); if (err) return err; + gc = gd->gdma_context; + err = mana_query_vport_cfg(apc, port_idx, &max_txq, &max_rxq, &apc->indir_table_sz); if (err) { @@ -2542,7 +2645,8 @@ static int mana_init_port(struct net_device *ndev) apc->num_queues = apc->max_queues; eth_hw_addr_set(ndev, apc->mac_addr); - + sprintf(vport, "vport%d", port_idx); + apc->mana_port_debugfs = debugfs_create_dir(vport, gc->mana_pci_debugfs); return 0; reset_apc: @@ -3044,4 +3148,4 @@ struct net_device *mana_get_primary_netdev_rcu(struct mana_context *ac, u32 port return ndev; } -EXPORT_SYMBOL_NS(mana_get_primary_netdev_rcu, NET_MANA); +EXPORT_SYMBOL_NS(mana_get_primary_netdev_rcu, "NET_MANA"); diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c index dc386437753846..c419626073f5f5 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c +++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c @@ -91,53 +91,34 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data) { struct mana_port_context *apc = netdev_priv(ndev); unsigned int num_queues = apc->num_queues; - u8 *p = data; int i; if (stringset != ETH_SS_STATS) return; - for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++) { - memcpy(p, mana_eth_stats[i].name, ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } + for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++) + ethtool_puts(&data, mana_eth_stats[i].name); for (i = 0; i < num_queues; i++) { - sprintf(p, "rx_%d_packets", i); - p += ETH_GSTRING_LEN; - sprintf(p, "rx_%d_bytes", i); - p += ETH_GSTRING_LEN; - sprintf(p, "rx_%d_xdp_drop", i); - p += ETH_GSTRING_LEN; - sprintf(p, "rx_%d_xdp_tx", i); - p += ETH_GSTRING_LEN; - sprintf(p, "rx_%d_xdp_redirect", i); - p += ETH_GSTRING_LEN; + ethtool_sprintf(&data, "rx_%d_packets", i); + ethtool_sprintf(&data, "rx_%d_bytes", i); + ethtool_sprintf(&data, "rx_%d_xdp_drop", i); + ethtool_sprintf(&data, "rx_%d_xdp_tx", i); + ethtool_sprintf(&data, "rx_%d_xdp_redirect", i); } for (i = 0; i < num_queues; i++) { - sprintf(p, "tx_%d_packets", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_bytes", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_xdp_xmit", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_tso_packets", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_tso_bytes", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_tso_inner_packets", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_tso_inner_bytes", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_long_pkt_fmt", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_short_pkt_fmt", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_csum_partial", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_%d_mana_map_err", i); - p += ETH_GSTRING_LEN; + ethtool_sprintf(&data, "tx_%d_packets", i); + ethtool_sprintf(&data, "tx_%d_bytes", i); + ethtool_sprintf(&data, "tx_%d_xdp_xmit", i); + ethtool_sprintf(&data, "tx_%d_tso_packets", i); + ethtool_sprintf(&data, "tx_%d_tso_bytes", i); + ethtool_sprintf(&data, "tx_%d_tso_inner_packets", i); + ethtool_sprintf(&data, "tx_%d_tso_inner_bytes", i); + ethtool_sprintf(&data, "tx_%d_long_pkt_fmt", i); + ethtool_sprintf(&data, "tx_%d_short_pkt_fmt", i); + ethtool_sprintf(&data, "tx_%d_csum_partial", i); + ethtool_sprintf(&data, "tx_%d_mana_map_err", i); } } @@ -443,6 +424,15 @@ static int mana_set_ringparam(struct net_device *ndev, return err; } +static int mana_get_link_ksettings(struct net_device *ndev, + struct ethtool_link_ksettings *cmd) +{ + cmd->base.duplex = DUPLEX_FULL; + cmd->base.port = PORT_OTHER; + + return 0; +} + const struct ethtool_ops mana_ethtool_ops = { .get_ethtool_stats = mana_get_ethtool_stats, .get_sset_count = mana_get_sset_count, @@ -456,4 +446,6 @@ const struct ethtool_ops mana_ethtool_ops = { .set_channels = mana_set_channels, .get_ringparam = mana_get_ringparam, .set_ringparam = mana_set_ringparam, + .get_link_ksettings = mana_get_link_ksettings, + .get_link = ethtool_op_get_link, }; diff --git a/drivers/net/ethernet/moxa/moxart_ether.c b/drivers/net/ethernet/moxa/moxart_ether.c index 96dc69e7141fbd..8bd60168624ac6 100644 --- a/drivers/net/ethernet/moxa/moxart_ether.c +++ b/drivers/net/ethernet/moxa/moxart_ether.c @@ -576,7 +576,7 @@ MODULE_DEVICE_TABLE(of, moxart_mac_match); static struct platform_driver moxart_mac_driver = { .probe = moxart_mac_probe, - .remove_new = moxart_remove, + .remove = moxart_remove, .driver = { .name = "moxart-ethernet", .of_match_table = moxart_mac_match, diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 3d72aa7b130503..ef93df52088710 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1432,7 +1432,7 @@ void ocelot_ifh_set_basic(void *ifh, struct ocelot *ocelot, int port, memset(ifh, 0, OCELOT_TAG_LEN); ocelot_ifh_set_bypass(ifh, 1); - ocelot_ifh_set_src(ifh, BIT_ULL(ocelot->num_phys_ports)); + ocelot_ifh_set_src(ifh, ocelot->num_phys_ports); ocelot_ifh_set_dest(ifh, BIT_ULL(port)); ocelot_ifh_set_qos_class(ifh, qos_class); ocelot_ifh_set_tag_type(ifh, tag_type); diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index a057ec3dab974b..986b1f150e3b3d 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -228,6 +228,32 @@ ocelot_flower_parse_egress_vlan_modify(struct ocelot_vcap_filter *filter, return 0; } +static int +ocelot_flower_parse_egress_port(struct ocelot *ocelot, struct flow_cls_offload *f, + const struct flow_action_entry *a, bool mirror, + struct netlink_ext_ack *extack) +{ + const char *act_string = mirror ? "mirror" : "redirect"; + int egress_port = ocelot->ops->netdev_to_port(a->dev); + enum flow_action_id offloadable_act_id; + + offloadable_act_id = mirror ? FLOW_ACTION_MIRRED : FLOW_ACTION_REDIRECT; + + /* Mirroring towards foreign interfaces is handled in software */ + if (egress_port < 0 || a->id != offloadable_act_id) { + if (f->common.skip_sw) { + NL_SET_ERR_MSG_FMT(extack, + "Can only %s to %s if filter also runs in software", + act_string, egress_port < 0 ? + "CPU" : "ingress of ocelot port"); + return -EOPNOTSUPP; + } + egress_port = ocelot->num_phys_ports; + } + + return egress_port; +} + static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, bool ingress, struct flow_cls_offload *f, struct ocelot_vcap_filter *filter) @@ -356,6 +382,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, filter->type = OCELOT_VCAP_FILTER_OFFLOAD; break; case FLOW_ACTION_REDIRECT: + case FLOW_ACTION_REDIRECT_INGRESS: if (filter->block_id != VCAP_IS2) { NL_SET_ERR_MSG_MOD(extack, "Redirect action can only be offloaded to VCAP IS2"); @@ -366,17 +393,19 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, "Last action must be GOTO"); return -EOPNOTSUPP; } - egress_port = ocelot->ops->netdev_to_port(a->dev); - if (egress_port < 0) { - NL_SET_ERR_MSG_MOD(extack, - "Destination not an ocelot port"); - return -EOPNOTSUPP; - } + + egress_port = ocelot_flower_parse_egress_port(ocelot, f, + a, false, + extack); + if (egress_port < 0) + return egress_port; + filter->action.mask_mode = OCELOT_MASK_MODE_REDIRECT; filter->action.port_mask = BIT(egress_port); filter->type = OCELOT_VCAP_FILTER_OFFLOAD; break; case FLOW_ACTION_MIRRED: + case FLOW_ACTION_MIRRED_INGRESS: if (filter->block_id != VCAP_IS2) { NL_SET_ERR_MSG_MOD(extack, "Mirror action can only be offloaded to VCAP IS2"); @@ -387,12 +416,13 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, "Last action must be GOTO"); return -EOPNOTSUPP; } - egress_port = ocelot->ops->netdev_to_port(a->dev); - if (egress_port < 0) { - NL_SET_ERR_MSG_MOD(extack, - "Destination not an ocelot port"); - return -EOPNOTSUPP; - } + + egress_port = ocelot_flower_parse_egress_port(ocelot, f, + a, true, + extack); + if (egress_port < 0) + return egress_port; + filter->egress_port.value = egress_port; filter->action.mirror_ena = true; filter->type = OCELOT_VCAP_FILTER_OFFLOAD; diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c index 7c9540a7172514..558e03301aa8ed 100644 --- a/drivers/net/ethernet/mscc/ocelot_net.c +++ b/drivers/net/ethernet/mscc/ocelot_net.c @@ -730,7 +730,7 @@ static void ocelot_get_stats64(struct net_device *dev, static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, - u16 vid, u16 flags, + u16 vid, u16 flags, bool *notified, struct netlink_ext_ack *extack) { struct ocelot_port_private *priv = netdev_priv(dev); @@ -744,7 +744,7 @@ static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - struct netlink_ext_ack *extack) + bool *notified, struct netlink_ext_ack *extack) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot_port *ocelot_port = &priv->port; diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c index e172638b060102..808ce8e68d3937 100644 --- a/drivers/net/ethernet/mscc/ocelot_ptp.c +++ b/drivers/net/ethernet/mscc/ocelot_ptp.c @@ -14,6 +14,8 @@ #include #include "ocelot.h" +#define OCELOT_PTP_TX_TSTAMP_TIMEOUT (5 * HZ) + int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts) { struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info); @@ -495,6 +497,28 @@ static int ocelot_traps_to_ptp_rx_filter(unsigned int proto) return HWTSTAMP_FILTER_NONE; } +static int ocelot_ptp_tx_type_to_cmd(int tx_type, int *ptp_cmd) +{ + switch (tx_type) { + case HWTSTAMP_TX_ON: + *ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; + break; + case HWTSTAMP_TX_ONESTEP_SYNC: + /* IFH_REW_OP_ONE_STEP_PTP updates the correctionField, + * what we need to update is the originTimestamp. + */ + *ptp_cmd = IFH_REW_OP_ORIGIN_PTP; + break; + case HWTSTAMP_TX_OFF: + *ptp_cmd = 0; + break; + default: + return -ERANGE; + } + + return 0; +} + int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr) { struct ocelot_port *ocelot_port = ocelot->ports[port]; @@ -521,30 +545,19 @@ EXPORT_SYMBOL(ocelot_hwstamp_get); int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr) { struct ocelot_port *ocelot_port = ocelot->ports[port]; + int ptp_cmd, old_ptp_cmd = ocelot_port->ptp_cmd; bool l2 = false, l4 = false; struct hwtstamp_config cfg; + bool old_l2, old_l4; int err; if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) return -EFAULT; /* Tx type sanity check */ - switch (cfg.tx_type) { - case HWTSTAMP_TX_ON: - ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; - break; - case HWTSTAMP_TX_ONESTEP_SYNC: - /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we - * need to update the origin time. - */ - ocelot_port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP; - break; - case HWTSTAMP_TX_OFF: - ocelot_port->ptp_cmd = 0; - break; - default: - return -ERANGE; - } + err = ocelot_ptp_tx_type_to_cmd(cfg.tx_type, &ptp_cmd); + if (err) + return err; switch (cfg.rx_filter) { case HWTSTAMP_FILTER_NONE: @@ -569,13 +582,27 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr) return -ERANGE; } + old_l2 = ocelot_port->trap_proto & OCELOT_PROTO_PTP_L2; + old_l4 = ocelot_port->trap_proto & OCELOT_PROTO_PTP_L4; + err = ocelot_setup_ptp_traps(ocelot, port, l2, l4); if (err) return err; + ocelot_port->ptp_cmd = ptp_cmd; + cfg.rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; + if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg))) { + err = -EFAULT; + goto out_restore_ptp_traps; + } + + return 0; +out_restore_ptp_traps: + ocelot_setup_ptp_traps(ocelot, port, old_l2, old_l4); + ocelot_port->ptp_cmd = old_ptp_cmd; + return err; } EXPORT_SYMBOL(ocelot_hwstamp_set); @@ -603,34 +630,87 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port, } EXPORT_SYMBOL(ocelot_get_ts_info); -static int ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port, - struct sk_buff *clone) +static struct sk_buff *ocelot_port_dequeue_ptp_tx_skb(struct ocelot *ocelot, + int port, u8 ts_id, + u32 seqid) { struct ocelot_port *ocelot_port = ocelot->ports[port]; - unsigned long flags; + struct sk_buff *skb, *skb_tmp, *skb_match = NULL; + struct ptp_header *hdr; - spin_lock_irqsave(&ocelot->ts_id_lock, flags); + spin_lock(&ocelot->ts_id_lock); - if (ocelot_port->ptp_skbs_in_flight == OCELOT_MAX_PTP_ID || - ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) { - spin_unlock_irqrestore(&ocelot->ts_id_lock, flags); - return -EBUSY; + skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) { + if (OCELOT_SKB_CB(skb)->ts_id != ts_id) + continue; + + /* Check that the timestamp ID is for the expected PTP + * sequenceId. We don't have to test ptp_parse_header() against + * NULL, because we've pre-validated the packet's ptp_class. + */ + hdr = ptp_parse_header(skb, OCELOT_SKB_CB(skb)->ptp_class); + if (seqid != ntohs(hdr->sequence_id)) + continue; + + __skb_unlink(skb, &ocelot_port->tx_skbs); + ocelot->ptp_skbs_in_flight--; + skb_match = skb; + break; } - skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS; - /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */ - OCELOT_SKB_CB(clone)->ts_id = ocelot_port->ts_id; + spin_unlock(&ocelot->ts_id_lock); - ocelot_port->ts_id++; - if (ocelot_port->ts_id == OCELOT_MAX_PTP_ID) - ocelot_port->ts_id = 0; + return skb_match; +} + +static int ocelot_port_queue_ptp_tx_skb(struct ocelot *ocelot, int port, + struct sk_buff *clone) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + DECLARE_BITMAP(ts_id_in_flight, OCELOT_MAX_PTP_ID); + struct sk_buff *skb, *skb_tmp; + unsigned long n; + + spin_lock(&ocelot->ts_id_lock); + + /* To get a better chance of acquiring a timestamp ID, first flush the + * stale packets still waiting in the TX timestamping queue. They are + * probably lost. + */ + skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) { + if (time_before(OCELOT_SKB_CB(skb)->ptp_tx_time + + OCELOT_PTP_TX_TSTAMP_TIMEOUT, jiffies)) { + dev_warn_ratelimited(ocelot->dev, + "port %d invalidating stale timestamp ID %u which seems lost\n", + port, OCELOT_SKB_CB(skb)->ts_id); + __skb_unlink(skb, &ocelot_port->tx_skbs); + kfree_skb(skb); + ocelot->ptp_skbs_in_flight--; + } else { + __set_bit(OCELOT_SKB_CB(skb)->ts_id, ts_id_in_flight); + } + } + + if (ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) { + spin_unlock(&ocelot->ts_id_lock); + return -EBUSY; + } + + n = find_first_zero_bit(ts_id_in_flight, OCELOT_MAX_PTP_ID); + if (n == OCELOT_MAX_PTP_ID) { + spin_unlock(&ocelot->ts_id_lock); + return -EBUSY; + } - ocelot_port->ptp_skbs_in_flight++; + /* Found an available timestamp ID, use it */ + OCELOT_SKB_CB(clone)->ts_id = n; + OCELOT_SKB_CB(clone)->ptp_tx_time = jiffies; ocelot->ptp_skbs_in_flight++; + __skb_queue_tail(&ocelot_port->tx_skbs, clone); - skb_queue_tail(&ocelot_port->tx_skbs, clone); + spin_unlock(&ocelot->ts_id_lock); - spin_unlock_irqrestore(&ocelot->ts_id_lock, flags); + dev_dbg_ratelimited(ocelot->dev, "port %d timestamp id %lu\n", port, n); return 0; } @@ -687,10 +767,14 @@ int ocelot_port_txtstamp_request(struct ocelot *ocelot, int port, if (!(*clone)) return -ENOMEM; - err = ocelot_port_add_txtstamp_skb(ocelot, port, *clone); - if (err) + /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */ + err = ocelot_port_queue_ptp_tx_skb(ocelot, port, *clone); + if (err) { + kfree_skb(*clone); return err; + } + skb_shinfo(*clone)->tx_flags |= SKBTX_IN_PROGRESS; OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd; OCELOT_SKB_CB(*clone)->ptp_class = ptp_class; } @@ -726,28 +810,15 @@ static void ocelot_get_hwtimestamp(struct ocelot *ocelot, spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); } -static bool ocelot_validate_ptp_skb(struct sk_buff *clone, u16 seqid) -{ - struct ptp_header *hdr; - - hdr = ptp_parse_header(clone, OCELOT_SKB_CB(clone)->ptp_class); - if (WARN_ON(!hdr)) - return false; - - return seqid == ntohs(hdr->sequence_id); -} - void ocelot_get_txtstamp(struct ocelot *ocelot) { int budget = OCELOT_PTP_QUEUE_SZ; while (budget--) { - struct sk_buff *skb, *skb_tmp, *skb_match = NULL; struct skb_shared_hwtstamps shhwtstamps; u32 val, id, seqid, txport; - struct ocelot_port *port; + struct sk_buff *skb_match; struct timespec64 ts; - unsigned long flags; val = ocelot_read(ocelot, SYS_PTP_STATUS); @@ -762,36 +833,14 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val); seqid = SYS_PTP_STATUS_PTP_MESS_SEQ_ID(val); - port = ocelot->ports[txport]; - - spin_lock(&ocelot->ts_id_lock); - port->ptp_skbs_in_flight--; - ocelot->ptp_skbs_in_flight--; - spin_unlock(&ocelot->ts_id_lock); - /* Retrieve its associated skb */ -try_again: - spin_lock_irqsave(&port->tx_skbs.lock, flags); - - skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) { - if (OCELOT_SKB_CB(skb)->ts_id != id) - continue; - __skb_unlink(skb, &port->tx_skbs); - skb_match = skb; - break; - } - - spin_unlock_irqrestore(&port->tx_skbs.lock, flags); - - if (WARN_ON(!skb_match)) - continue; - - if (!ocelot_validate_ptp_skb(skb_match, seqid)) { - dev_err_ratelimited(ocelot->dev, - "port %d received stale TX timestamp for seqid %d, discarding\n", - txport, seqid); - dev_kfree_skb_any(skb); - goto try_again; + skb_match = ocelot_port_dequeue_ptp_tx_skb(ocelot, txport, id, + seqid); + if (!skb_match) { + dev_warn_ratelimited(ocelot->dev, + "port %d received TX timestamp (seqid %d, ts id %u) for packet previously declared stale\n", + txport, seqid, id); + goto next_ts; } /* Get the h/w timestamp */ @@ -802,7 +851,7 @@ void ocelot_get_txtstamp(struct ocelot *ocelot) shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); skb_complete_tx_timestamp(skb_match, &shhwtstamps); - /* Next ts */ +next_ts: ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT); } } diff --git a/drivers/net/ethernet/mscc/ocelot_vsc7514.c b/drivers/net/ethernet/mscc/ocelot_vsc7514.c index c09dd2e3343cba..055b55651a49fd 100644 --- a/drivers/net/ethernet/mscc/ocelot_vsc7514.c +++ b/drivers/net/ethernet/mscc/ocelot_vsc7514.c @@ -416,7 +416,7 @@ static void mscc_ocelot_remove(struct platform_device *pdev) static struct platform_driver mscc_ocelot_driver = { .probe = mscc_ocelot_probe, - .remove_new = mscc_ocelot_remove, + .remove = mscc_ocelot_remove, .driver = { .name = "ocelot-switch", .of_match_table = mscc_ocelot_match, diff --git a/drivers/net/ethernet/natsemi/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c index 2b6e097df28f49..6d29d2e1fa7c30 100644 --- a/drivers/net/ethernet/natsemi/jazzsonic.c +++ b/drivers/net/ethernet/natsemi/jazzsonic.c @@ -241,7 +241,7 @@ static void jazz_sonic_device_remove(struct platform_device *pdev) static struct platform_driver jazz_sonic_driver = { .probe = jazz_sonic_probe, - .remove_new = jazz_sonic_device_remove, + .remove = jazz_sonic_device_remove, .driver = { .name = jazz_sonic_string, }, diff --git a/drivers/net/ethernet/natsemi/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c index 2fc63860dbdbd7..a740e24a975967 100644 --- a/drivers/net/ethernet/natsemi/macsonic.c +++ b/drivers/net/ethernet/natsemi/macsonic.c @@ -545,7 +545,7 @@ static void mac_sonic_platform_remove(struct platform_device *pdev) static struct platform_driver mac_sonic_platform_driver = { .probe = mac_sonic_platform_probe, - .remove_new = mac_sonic_platform_remove, + .remove = mac_sonic_platform_remove, .driver = { .name = "macsonic", }, diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c index 998586872599b3..bea969dfa536d7 100644 --- a/drivers/net/ethernet/natsemi/ns83820.c +++ b/drivers/net/ethernet/natsemi/ns83820.c @@ -2090,7 +2090,7 @@ static int ns83820_init_one(struct pci_dev *pci_dev, */ /* Ramit : 1024 DMA is not a good idea, it ends up banging * some DELL and COMPAQ SMP systems - * Turn on ALP, only we are accpeting Jumbo Packets */ + * Turn on ALP, only we are accepting Jumbo Packets */ writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD | RXCFG_STRIPCRC //| RXCFG_ALP diff --git a/drivers/net/ethernet/natsemi/xtsonic.c b/drivers/net/ethernet/natsemi/xtsonic.c index 8943e72443108d..c01a4cb5dc0f6c 100644 --- a/drivers/net/ethernet/natsemi/xtsonic.c +++ b/drivers/net/ethernet/natsemi/xtsonic.c @@ -264,7 +264,7 @@ static void xtsonic_device_remove(struct platform_device *pdev) static struct platform_driver xtsonic_driver = { .probe = xtsonic_probe, - .remove_new = xtsonic_device_remove, + .remove = xtsonic_device_remove, .driver = { .name = xtsonic_string, }, diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index f235e76e4ce9a0..f8016dc25e0abc 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -8523,7 +8523,7 @@ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, * @pdev: Pointer to PCI device * * Restart the card from scratch, as if from a cold-boot. - * At this point, the card has exprienced a hard reset, + * At this point, the card has experienced a hard reset, * followed by fixups by BIOS, and has its config space * set up identically to what it was at cold boot. */ diff --git a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c index d215efc6cad0c2..f1c6c47564b176 100644 --- a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c +++ b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c @@ -1179,7 +1179,7 @@ int nfp_nfd3_poll(struct napi_struct *napi, int budget) } while (u64_stats_fetch_retry(&r_vec->rx_sync, start)); dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample); - net_dim(&r_vec->rx_dim, dim_sample); + net_dim(&r_vec->rx_dim, &dim_sample); } if (r_vec->nfp_net->tx_coalesce_adapt_on && r_vec->tx_ring) { @@ -1194,7 +1194,7 @@ int nfp_nfd3_poll(struct napi_struct *napi, int budget) } while (u64_stats_fetch_retry(&r_vec->tx_sync, start)); dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample); - net_dim(&r_vec->tx_dim, dim_sample); + net_dim(&r_vec->tx_dim, &dim_sample); } return pkts_polled; diff --git a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c index dae5af7d1845ba..ebeb6ab4465c6f 100644 --- a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c +++ b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c @@ -1289,7 +1289,7 @@ int nfp_nfdk_poll(struct napi_struct *napi, int budget) } while (u64_stats_fetch_retry(&r_vec->rx_sync, start)); dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample); - net_dim(&r_vec->rx_dim, dim_sample); + net_dim(&r_vec->rx_dim, &dim_sample); } if (r_vec->nfp_net->tx_coalesce_adapt_on && r_vec->tx_ring) { @@ -1304,7 +1304,7 @@ int nfp_nfdk_poll(struct napi_struct *napi, int budget) } while (u64_stats_fetch_retry(&r_vec->tx_sync, start)); dim_update_sample(r_vec->event_ctr, pkts, bytes, &dim_sample); - net_dim(&r_vec->tx_dim, dim_sample); + net_dim(&r_vec->tx_dim, &dim_sample); } return pkts_polled; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 6e0929af0f725b..98e098c09c0348 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -829,7 +829,7 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, return err; } - irq_set_affinity_hint(r_vec->irq_vector, &r_vec->affinity_mask); + irq_update_affinity_hint(r_vec->irq_vector, &r_vec->affinity_mask); nn_dbg(nn, "RV%02d: irq=%03d/%03d\n", idx, r_vec->irq_vector, r_vec->irq_entry); @@ -840,7 +840,7 @@ nfp_net_prepare_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, static void nfp_net_cleanup_vector(struct nfp_net *nn, struct nfp_net_r_vector *r_vec) { - irq_set_affinity_hint(r_vec->irq_vector, NULL); + irq_update_affinity_hint(r_vec->irq_vector, NULL); nfp_net_napi_del(&nn->dp, r_vec); free_irq(r_vec->irq_vector, r_vec); } diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c index 2aa4ad9cf96e89..230d5ff99dd7e1 100644 --- a/drivers/net/ethernet/ni/nixge.c +++ b/drivers/net/ethernet/ni/nixge.c @@ -1415,7 +1415,7 @@ static void nixge_remove(struct platform_device *pdev) static struct platform_driver nixge_driver = { .probe = nixge_probe, - .remove_new = nixge_remove, + .remove = nixge_remove, .driver = { .name = "nixge", .of_match_table = nixge_dt_ids, diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index dd3e58a1319c9f..8b9a3e3bba30fd 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1503,7 +1503,7 @@ MODULE_DEVICE_TABLE(of, lpc_eth_match); static struct platform_driver lpc_eth_driver = { .probe = lpc_eth_drv_probe, - .remove_new = lpc_eth_drv_remove, + .remove = lpc_eth_drv_remove, #ifdef CONFIG_PM .suspend = lpc_eth_drv_suspend, .resume = lpc_eth_drv_resume, diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index f9c0dcd965c2e7..db200e4ec284d7 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -113,6 +113,7 @@ struct oa_tc6 { struct mii_bus *mdiobus; struct spi_device *spi; struct mutex spi_ctrl_lock; /* Protects spi control transfer */ + spinlock_t tx_skb_lock; /* Protects tx skb handling */ void *spi_ctrl_tx_buf; void *spi_ctrl_rx_buf; void *spi_data_tx_buf; @@ -1004,8 +1005,10 @@ static u16 oa_tc6_prepare_spi_tx_buf_for_tx_skbs(struct oa_tc6 *tc6) for (used_tx_credits = 0; used_tx_credits < tc6->tx_credits; used_tx_credits++) { if (!tc6->ongoing_tx_skb) { + spin_lock_bh(&tc6->tx_skb_lock); tc6->ongoing_tx_skb = tc6->waiting_tx_skb; tc6->waiting_tx_skb = NULL; + spin_unlock_bh(&tc6->tx_skb_lock); } if (!tc6->ongoing_tx_skb) break; @@ -1111,8 +1114,9 @@ static int oa_tc6_spi_thread_handler(void *data) /* This kthread will be waken up if there is a tx skb or mac-phy * interrupt to perform spi transfer with tx chunks. */ - wait_event_interruptible(tc6->spi_wq, tc6->waiting_tx_skb || - tc6->int_flag || + wait_event_interruptible(tc6->spi_wq, tc6->int_flag || + (tc6->waiting_tx_skb && + tc6->tx_credits) || kthread_should_stop()); if (kthread_should_stop()) @@ -1209,7 +1213,9 @@ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb) return NETDEV_TX_OK; } + spin_lock_bh(&tc6->tx_skb_lock); tc6->waiting_tx_skb = skb; + spin_unlock_bh(&tc6->tx_skb_lock); /* Wake spi kthread to perform spi transfer */ wake_up_interruptible(&tc6->spi_wq); @@ -1239,6 +1245,7 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev) tc6->netdev = netdev; SET_NETDEV_DEV(netdev, &spi->dev); mutex_init(&tc6->spi_ctrl_lock); + spin_lock_init(&tc6->tx_skb_lock); /* Set the SPI controller to pump at realtime priority */ tc6->spi->rt = true; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index 9e42d599840ded..57edcde9e6f8c6 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -277,7 +277,10 @@ void ionic_dev_teardown(struct ionic *ionic) idev->phy_cmb_pages = 0; idev->cmb_npages = 0; - destroy_workqueue(ionic->wq); + if (ionic->wq) { + destroy_workqueue(ionic->wq); + ionic->wq = NULL; + } mutex_destroy(&idev->cmb_inuse_lock); } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index dda22fa4448cff..9b7f78b6cdb1e3 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -961,8 +961,8 @@ static int ionic_get_module_eeprom(struct net_device *netdev, len = min_t(u32, sizeof(xcvr->sprom), ee->len); do { - memcpy(data, xcvr->sprom, len); - memcpy(tbuf, xcvr->sprom, len); + memcpy(data, &xcvr->sprom[ee->offset], len); + memcpy(tbuf, &xcvr->sprom[ee->offset], len); /* Let's make sure we got a consistent copy */ if (!memcmp(data, tbuf, len)) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 40496587b2b318..3d3f936779f7d9 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -3869,8 +3869,8 @@ int ionic_lif_register(struct ionic_lif *lif) /* only register LIF0 for now */ err = register_netdev(lif->netdev); if (err) { - dev_err(lif->ionic->dev, "Cannot register net device, aborting\n"); - ionic_lif_unregister_phc(lif); + dev_err(lif->ionic->dev, "Cannot register net device: %d, aborting\n", err); + ionic_lif_unregister(lif); return err; } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 0eeda7e502db26..2ac59564ded188 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -928,7 +928,7 @@ static void ionic_dim_update(struct ionic_qcq *qcq, int napi_mode) dim_update_sample(qcq->cq.bound_intr->rearm_count, pkts, bytes, &dim_sample); - net_dim(&qcq->dim, dim_sample); + net_dim(&qcq->dim, &dim_sample); } int ionic_tx_napi(struct napi_struct *napi, int budget) diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c index 8c4cb910e09b16..e7d8999049e176 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c @@ -648,18 +648,18 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, static void netxen_nic_get_strings(struct net_device *dev, u32 stringset, u8 *data) { - int index; + const char *str; + int i; switch (stringset) { case ETH_SS_TEST: - memcpy(data, *netxen_nic_gstrings_test, - NETXEN_NIC_TEST_LEN * ETH_GSTRING_LEN); + for (i = 0; i < NETXEN_NIC_TEST_LEN; i++) + ethtool_puts(&data, netxen_nic_gstrings_test[i]); break; case ETH_SS_STATS: - for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) { - memcpy(data + index * ETH_GSTRING_LEN, - netxen_nic_gstrings_stats[index].stat_string, - ETH_GSTRING_LEN); + for (i = 0; i < NETXEN_NIC_STATS_LEN; i++) { + str = netxen_nic_gstrings_stats[i].stat_string; + ethtool_puts(&data, str); } break; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_debug.c b/drivers/net/ethernet/qlogic/qed/qed_debug.c index f67be4b8ad4351..464a72afb75894 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_debug.c +++ b/drivers/net/ethernet/qlogic/qed/qed_debug.c @@ -2873,6 +2873,7 @@ static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn, false, SPLIT_TYPE_NONE, 0); } + cond_resched(); } return offset; diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c index 6263f847b6b926..9e5f0dbc8a0765 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_hw.c +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c @@ -596,6 +596,7 @@ static int qed_dmae_operation_wait(struct qed_hwfn *p_hwfn) barrier(); while (*p_hwfn->dmae_info.p_completion_word != DMAE_COMPLETION_VAL) { udelay(DMAE_MIN_WAIT_TIME); + cond_resched(); if (++wait_cnt > wait_cnt_limit) { DP_NOTICE(p_hwfn->cdev, "Timed-out waiting for operation to complete. Completion word is 0x%08x expected 0x%08x.\n", diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 16e6bd4661433f..c7f497c36f66ce 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -459,12 +459,11 @@ static void qed_mcp_print_cpu_info(struct qed_hwfn *p_hwfn, static int _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, - struct qed_mcp_mb_params *p_mb_params, - u32 max_retries, u32 usecs) + struct qed_mcp_mb_params *p_mb_params) { - u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); struct qed_mcp_cmd_elem *p_cmd_elem; u16 seq_num; + u32 cnt = 0; int rc = 0; /* Wait until the mailbox is non-occupied */ @@ -488,12 +487,13 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) - msleep(msecs); + usleep_range(QED_MCP_RESP_ITER_US, + QED_MCP_RESP_ITER_US * 2); else - udelay(usecs); - } while (++cnt < max_retries); + udelay(QED_MCP_RESP_ITER_US); + } while (++cnt < QED_DRV_MB_MAX_RETRIES); - if (cnt >= max_retries) { + if (cnt >= QED_DRV_MB_MAX_RETRIES) { DP_NOTICE(p_hwfn, "The MFW mailbox is occupied by an uncompleted command. Failed to send command 0x%08x [param 0x%08x].\n", p_mb_params->cmd, p_mb_params->param); @@ -520,9 +520,10 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, */ if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) - msleep(msecs); + usleep_range(QED_MCP_RESP_ITER_US, + QED_MCP_RESP_ITER_US * 2); else - udelay(usecs); + udelay(QED_MCP_RESP_ITER_US); spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); @@ -536,9 +537,9 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, goto err; spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); - } while (++cnt < max_retries); + } while (++cnt < QED_DRV_MB_MAX_RETRIES); - if (cnt >= max_retries) { + if (cnt >= QED_DRV_MB_MAX_RETRIES) { DP_NOTICE(p_hwfn, "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", p_mb_params->cmd, p_mb_params->param); @@ -564,7 +565,8 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", p_mb_params->mcp_resp, p_mb_params->mcp_param, - (cnt * usecs) / 1000, (cnt * usecs) % 1000); + (cnt * QED_MCP_RESP_ITER_US) / 1000, + (cnt * QED_MCP_RESP_ITER_US) % 1000); /* Clear the sequence number from the MFW response */ p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; @@ -581,8 +583,6 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, struct qed_mcp_mb_params *p_mb_params) { size_t union_data_size = sizeof(union drv_union_data); - u32 max_retries = QED_DRV_MB_MAX_RETRIES; - u32 usecs = QED_MCP_RESP_ITER_US; /* MCP not initialized */ if (!qed_mcp_is_init(p_hwfn)) { @@ -606,13 +606,7 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, return -EINVAL; } - if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { - max_retries = DIV_ROUND_UP(max_retries, 1000); - usecs *= 1000; - } - - return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, - usecs); + return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params); } static int _qed_mcp_cmd(struct qed_hwfn *p_hwfn, @@ -3085,20 +3079,13 @@ int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) DRV_MB_PARAM_NVM_LEN_OFFSET), &resp, &resp_param, &read_len, - (u32 *)(p_buf + offset), false); + (u32 *)(p_buf + offset), true); if (rc || (resp != FW_MSG_CODE_NVM_OK)) { DP_NOTICE(cdev, "MCP command rc = %d\n", rc); break; } - /* This can be a lengthy process, and it's possible scheduler - * isn't preemptible. Sleep a bit to prevent CPU hogging. - */ - if (bytes_left % 0x1000 < - (bytes_left - read_len) % 0x1000) - usleep_range(1000, 2000); - offset += read_len; bytes_left -= read_len; } @@ -3314,7 +3301,9 @@ int qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn, if (rc) return rc; - if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) + if (((rsp & FW_MSG_CODE_MASK) == FW_MSG_CODE_UNSUPPORTED)) + rc = -EOPNOTSUPP; + else if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) rc = -EINVAL; return rc; @@ -3369,6 +3358,7 @@ int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn) p_ptt, &nvm_info.num_images); if (rc == -EOPNOTSUPP) { DP_INFO(p_hwfn, "DRV_MSG_CODE_BIST_TEST is not supported\n"); + nvm_info.num_images = 0; goto out; } else if (rc || !nvm_info.num_images) { DP_ERR(p_hwfn, "Failed getting number of images\n"); diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 97b059be1041e7..e50e1df0a433e4 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -272,16 +272,14 @@ static void qede_get_strings_stats_txq(struct qede_dev *edev, { int i; - for (i = 0; i < QEDE_NUM_TQSTATS; i++) { + for (i = 0; i < QEDE_NUM_TQSTATS; i++) if (txq->is_xdp) - sprintf(*buf, "%d [XDP]: %s", - QEDE_TXQ_XDP_TO_IDX(edev, txq), - qede_tqstats_arr[i].string); + ethtool_sprintf(buf, "%d [XDP]: %s", + QEDE_TXQ_XDP_TO_IDX(edev, txq), + qede_tqstats_arr[i].string); else - sprintf(*buf, "%d_%d: %s", txq->index, txq->cos, - qede_tqstats_arr[i].string); - *buf += ETH_GSTRING_LEN; - } + ethtool_sprintf(buf, "%d_%d: %s", txq->index, txq->cos, + qede_tqstats_arr[i].string); } static void qede_get_strings_stats_rxq(struct qede_dev *edev, @@ -289,11 +287,9 @@ static void qede_get_strings_stats_rxq(struct qede_dev *edev, { int i; - for (i = 0; i < QEDE_NUM_RQSTATS; i++) { - sprintf(*buf, "%d: %s", rxq->rxq_id, - qede_rqstats_arr[i].string); - *buf += ETH_GSTRING_LEN; - } + for (i = 0; i < QEDE_NUM_RQSTATS; i++) + ethtool_sprintf(buf, "%d: %s", rxq->rxq_id, + qede_rqstats_arr[i].string); } static bool qede_is_irrelevant_stat(struct qede_dev *edev, int stat_index) @@ -331,26 +327,26 @@ static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf) for (i = 0; i < QEDE_NUM_STATS; i++) { if (qede_is_irrelevant_stat(edev, i)) continue; - strcpy(buf, qede_stats_arr[i].string); - buf += ETH_GSTRING_LEN; + ethtool_puts(&buf, qede_stats_arr[i].string); } } static void qede_get_strings(struct net_device *dev, u32 stringset, u8 *buf) { struct qede_dev *edev = netdev_priv(dev); + int i; switch (stringset) { case ETH_SS_STATS: qede_get_strings_stats(edev, buf); break; case ETH_SS_PRIV_FLAGS: - memcpy(buf, qede_private_arr, - ETH_GSTRING_LEN * QEDE_PRI_FLAG_LEN); + for (i = 0; i < QEDE_PRI_FLAG_LEN; i++) + ethtool_puts(&buf, qede_private_arr[i]); break; case ETH_SS_TEST: - memcpy(buf, qede_tests_str_arr, - ETH_GSTRING_LEN * QEDE_ETHTOOL_TEST_MAX); + for (i = 0; i < QEDE_ETHTOOL_TEST_MAX; i++) + ethtool_puts(&buf, qede_tests_str_arr[i]); break; default: DP_VERBOSE(edev, QED_MSG_DEBUG, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index c1436e1554de33..17450e05c437b1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -1196,60 +1196,56 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data) { struct qlcnic_adapter *adapter = netdev_priv(dev); int index, i, num_stats; + const char *str; switch (stringset) { case ETH_SS_TEST: - memcpy(data, *qlcnic_gstrings_test, - QLCNIC_TEST_LEN * ETH_GSTRING_LEN); + for (i = 0; i < QLCNIC_TEST_LEN; i++) + ethtool_puts(&data, qlcnic_gstrings_test[i]); break; case ETH_SS_STATS: num_stats = ARRAY_SIZE(qlcnic_tx_queue_stats_strings); - for (i = 0; i < adapter->drv_tx_rings; i++) { + for (i = 0; i < adapter->drv_tx_rings; i++) for (index = 0; index < num_stats; index++) { - sprintf(data, "tx_queue_%d %s", i, - qlcnic_tx_queue_stats_strings[index]); - data += ETH_GSTRING_LEN; + str = qlcnic_tx_queue_stats_strings[index]; + ethtool_sprintf(&data, "tx_queue_%d %s", i, + str); } - } - for (index = 0; index < QLCNIC_STATS_LEN; index++) { - memcpy(data + index * ETH_GSTRING_LEN, - qlcnic_gstrings_stats[index].stat_string, - ETH_GSTRING_LEN); + for (i = 0; i < QLCNIC_STATS_LEN; i++) { + str = qlcnic_gstrings_stats[i].stat_string; + ethtool_puts(&data, str); } if (qlcnic_83xx_check(adapter)) { num_stats = ARRAY_SIZE(qlcnic_83xx_tx_stats_strings); - for (i = 0; i < num_stats; i++, index++) - memcpy(data + index * ETH_GSTRING_LEN, - qlcnic_83xx_tx_stats_strings[i], - ETH_GSTRING_LEN); + for (i = 0; i < num_stats; i++) { + str = qlcnic_83xx_tx_stats_strings[i]; + ethtool_puts(&data, str); + } num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings); - for (i = 0; i < num_stats; i++, index++) - memcpy(data + index * ETH_GSTRING_LEN, - qlcnic_83xx_mac_stats_strings[i], - ETH_GSTRING_LEN); + for (i = 0; i < num_stats; i++) { + str = qlcnic_83xx_mac_stats_strings[i]; + ethtool_puts(&data, str); + } num_stats = ARRAY_SIZE(qlcnic_83xx_rx_stats_strings); - for (i = 0; i < num_stats; i++, index++) - memcpy(data + index * ETH_GSTRING_LEN, - qlcnic_83xx_rx_stats_strings[i], - ETH_GSTRING_LEN); + for (i = 0; i < num_stats; i++) { + str = qlcnic_83xx_rx_stats_strings[i]; + ethtool_puts(&data, str); + } return; } else { num_stats = ARRAY_SIZE(qlcnic_83xx_mac_stats_strings); - for (i = 0; i < num_stats; i++, index++) - memcpy(data + index * ETH_GSTRING_LEN, - qlcnic_83xx_mac_stats_strings[i], - ETH_GSTRING_LEN); + for (i = 0; i < num_stats; i++) { + str = qlcnic_83xx_mac_stats_strings[i]; + ethtool_puts(&data, str); + } } if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) return; num_stats = ARRAY_SIZE(qlcnic_device_gstrings_stats); - for (i = 0; i < num_stats; index++, i++) { - memcpy(data + index * ETH_GSTRING_LEN, - qlcnic_device_gstrings_stats[i], - ETH_GSTRING_LEN); - } + for (i = 0; i < num_stats; i++) + ethtool_puts(&data, qlcnic_device_gstrings_stats[i]); } } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index b3588a1ebc25f4..eb69121df726cb 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -367,7 +367,7 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *netdev, - const unsigned char *addr, u16 vid, + const unsigned char *addr, u16 vid, bool *notified, struct netlink_ext_ack *extack) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -394,7 +394,7 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *netdev, const unsigned char *addr, u16 vid, u16 flags, - struct netlink_ext_ack *extack) + bool *notified, struct netlink_ext_ack *extack) { struct qlcnic_adapter *adapter = netdev_priv(netdev); int err = 0; diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c index e4bc18009d0879..a508ebc4b206f9 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c @@ -293,6 +293,11 @@ static struct sgmii_ops qdf2400_ops = { }; #endif +struct emac_match_data { + struct sgmii_ops **sgmii_ops; + struct device *target_device; +}; + static int emac_sgmii_acpi_match(struct device *dev, void *data) { #ifdef CONFIG_ACPI @@ -303,7 +308,7 @@ static int emac_sgmii_acpi_match(struct device *dev, void *data) {} }; const struct acpi_device_id *id = acpi_match_device(match_table, dev); - struct sgmii_ops **ops = data; + struct emac_match_data *match_data = data; if (id) { acpi_handle handle = ACPI_HANDLE(dev); @@ -324,10 +329,12 @@ static int emac_sgmii_acpi_match(struct device *dev, void *data) switch (hrv) { case 1: - *ops = &qdf2432_ops; + *match_data->sgmii_ops = &qdf2432_ops; + match_data->target_device = dev; return 1; case 2: - *ops = &qdf2400_ops; + *match_data->sgmii_ops = &qdf2400_ops; + match_data->target_device = dev; return 1; } } @@ -356,16 +363,21 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt) int ret; if (has_acpi_companion(&pdev->dev)) { + struct emac_match_data match_data = { + .sgmii_ops = &phy->sgmii_ops, + .target_device = NULL, + }; struct device *dev; - dev = device_find_child(&pdev->dev, &phy->sgmii_ops, - emac_sgmii_acpi_match); + device_for_each_child(&pdev->dev, &match_data, emac_sgmii_acpi_match); + dev = match_data.target_device; if (!dev) { dev_warn(&pdev->dev, "cannot find internal phy node\n"); return 0; } + get_device(dev); sgmii_pdev = to_platform_device(dev); } else { const struct of_device_id *match; diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index 99d4647bf245df..699a8afc214a48 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -760,7 +760,7 @@ static void emac_shutdown(struct platform_device *pdev) static struct platform_driver emac_platform_driver = { .probe = emac_probe, - .remove_new = emac_remove, + .remove = emac_remove, .driver = { .name = "qcom-emac", .of_match_table = emac_dt_match, diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c index ad06da0fdaa04a..13deb3da4a6425 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.c +++ b/drivers/net/ethernet/qualcomm/qca_debug.c @@ -98,8 +98,8 @@ qcaspi_info_show(struct seq_file *s, void *what) seq_printf(s, "IRQ : %d\n", qca->spi_dev->irq); - seq_printf(s, "INTR : %lx\n", - qca->intr); + seq_printf(s, "FLAGS : %lx\n", + qca->flags); seq_printf(s, "SPI max speed : %lu\n", (unsigned long)qca->spi_dev->max_speed_hz); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 8f7ce6b51a1c9b..38a779f4b866ca 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -35,7 +35,8 @@ #define MAX_DMA_BURST_LEN 5000 -#define SPI_INTR 0 +#define SPI_INTR 0 +#define SPI_RESET 1 /* Modules parameters */ #define QCASPI_CLK_SPEED_MIN 1000000 @@ -53,7 +54,7 @@ MODULE_PARM_DESC(qcaspi_burst_len, "Number of data bytes per burst. Use 1-5000." #define QCASPI_PLUGGABLE_MIN 0 #define QCASPI_PLUGGABLE_MAX 1 -static int qcaspi_pluggable = QCASPI_PLUGGABLE_MIN; +static int qcaspi_pluggable = QCASPI_PLUGGABLE_MAX; module_param(qcaspi_pluggable, int, 0); MODULE_PARM_DESC(qcaspi_pluggable, "Pluggable SPI connection (yes/no)."); @@ -495,7 +496,7 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) if (qca->sync == QCASPI_SYNC_READY) qca->stats.bad_signature++; - qca->sync = QCASPI_SYNC_UNKNOWN; + set_bit(SPI_RESET, &qca->flags); netdev_dbg(qca->net_dev, "sync: got CPU on, but signature was invalid, restart\n"); return; } else { @@ -505,12 +506,17 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) if (wrbuf_space != QCASPI_HW_BUF_LEN) { netdev_dbg(qca->net_dev, "sync: got CPU on, but wrbuf not empty. reset!\n"); qca->sync = QCASPI_SYNC_UNKNOWN; + qca->stats.buf_avail_err++; } else { netdev_dbg(qca->net_dev, "sync: got CPU on, now in sync\n"); qca->sync = QCASPI_SYNC_READY; return; } } + } else { + /* Handle reset only on QCASPI_EVENT_UPDATE */ + if (test_and_clear_bit(SPI_RESET, &qca->flags)) + qca->sync = QCASPI_SYNC_UNKNOWN; } switch (qca->sync) { @@ -521,7 +527,7 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); if (signature != QCASPI_GOOD_SIGNATURE) { - qca->sync = QCASPI_SYNC_UNKNOWN; + set_bit(SPI_RESET, &qca->flags); qca->stats.bad_signature++; netdev_dbg(qca->net_dev, "sync: bad signature, restart\n"); /* don't reset right away */ @@ -552,7 +558,7 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) qca->reset_count); if (qca->reset_count >= QCASPI_RESET_TIMEOUT) { /* reset did not seem to take place, try again */ - qca->sync = QCASPI_SYNC_UNKNOWN; + set_bit(SPI_RESET, &qca->flags); qca->stats.reset_timeout++; netdev_dbg(qca->net_dev, "sync: reset timeout, restarting process.\n"); } @@ -581,14 +587,14 @@ qcaspi_spi_thread(void *data) continue; } - if (!test_bit(SPI_INTR, &qca->intr) && + if (!qca->flags && !qca->txr.skb[qca->txr.head]) schedule(); set_current_state(TASK_RUNNING); netdev_dbg(qca->net_dev, "have work to do. int: %lu, tx_skb: %p\n", - qca->intr, + qca->flags, qca->txr.skb[qca->txr.head]); qcaspi_qca7k_sync(qca, QCASPI_EVENT_UPDATE); @@ -602,7 +608,7 @@ qcaspi_spi_thread(void *data) msleep(QCASPI_QCA7K_REBOOT_TIME_MS); } - if (test_and_clear_bit(SPI_INTR, &qca->intr)) { + if (test_and_clear_bit(SPI_INTR, &qca->flags)) { start_spi_intr_handling(qca, &intr_cause); if (intr_cause & SPI_INT_CPU_ON) { @@ -627,7 +633,7 @@ qcaspi_spi_thread(void *data) /* restart sync */ netdev_dbg(qca->net_dev, "===> rdbuf error!\n"); qca->stats.read_buf_err++; - qca->sync = QCASPI_SYNC_UNKNOWN; + set_bit(SPI_RESET, &qca->flags); continue; } @@ -635,7 +641,7 @@ qcaspi_spi_thread(void *data) /* restart sync */ netdev_dbg(qca->net_dev, "===> wrbuf error!\n"); qca->stats.write_buf_err++; - qca->sync = QCASPI_SYNC_UNKNOWN; + set_bit(SPI_RESET, &qca->flags); continue; } @@ -664,7 +670,7 @@ qcaspi_intr_handler(int irq, void *data) { struct qcaspi *qca = data; - set_bit(SPI_INTR, &qca->intr); + set_bit(SPI_INTR, &qca->flags); if (qca->spi_thread) wake_up_process(qca->spi_thread); @@ -680,7 +686,7 @@ qcaspi_netdev_open(struct net_device *dev) if (!qca) return -EINVAL; - set_bit(SPI_INTR, &qca->intr); + set_bit(SPI_INTR, &qca->flags); qca->sync = QCASPI_SYNC_UNKNOWN; qcafrm_fsm_init_spi(&qca->frm_handle); @@ -799,7 +805,7 @@ qcaspi_netdev_tx_timeout(struct net_device *dev, unsigned int txqueue) jiffies, jiffies - dev_trans_start(dev)); qca->net_dev->stats.tx_errors++; /* Trigger tx queue flush and QCA7000 reset */ - qca->sync = QCASPI_SYNC_UNKNOWN; + set_bit(SPI_RESET, &qca->flags); if (qca->spi_thread) wake_up_process(qca->spi_thread); @@ -812,7 +818,6 @@ qcaspi_netdev_init(struct net_device *dev) dev->mtu = QCAFRM_MAX_MTU; dev->type = ARPHRD_ETHER; - qca->clkspeed = qcaspi_clkspeed; qca->burst_len = qcaspi_burst_len; qca->spi_thread = NULL; qca->buffer_size = (QCAFRM_MAX_MTU + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN + @@ -903,17 +908,15 @@ qca_spi_probe(struct spi_device *spi) legacy_mode = of_property_read_bool(spi->dev.of_node, "qca,legacy-mode"); - if (qcaspi_clkspeed == 0) { - if (spi->max_speed_hz) - qcaspi_clkspeed = spi->max_speed_hz; - else - qcaspi_clkspeed = QCASPI_CLK_SPEED; - } + if (qcaspi_clkspeed) + spi->max_speed_hz = qcaspi_clkspeed; + else if (!spi->max_speed_hz) + spi->max_speed_hz = QCASPI_CLK_SPEED; - if ((qcaspi_clkspeed < QCASPI_CLK_SPEED_MIN) || - (qcaspi_clkspeed > QCASPI_CLK_SPEED_MAX)) { - dev_err(&spi->dev, "Invalid clkspeed: %d\n", - qcaspi_clkspeed); + if (spi->max_speed_hz < QCASPI_CLK_SPEED_MIN || + spi->max_speed_hz > QCASPI_CLK_SPEED_MAX) { + dev_err(&spi->dev, "Invalid clkspeed: %u\n", + spi->max_speed_hz); return -EINVAL; } @@ -938,14 +941,13 @@ qca_spi_probe(struct spi_device *spi) return -EINVAL; } - dev_info(&spi->dev, "ver=%s, clkspeed=%d, burst_len=%d, pluggable=%d\n", + dev_info(&spi->dev, "ver=%s, clkspeed=%u, burst_len=%d, pluggable=%d\n", QCASPI_DRV_VERSION, - qcaspi_clkspeed, + spi->max_speed_hz, qcaspi_burst_len, qcaspi_pluggable); spi->mode = SPI_MODE_3; - spi->max_speed_hz = qcaspi_clkspeed; if (spi_setup(spi) < 0) { dev_err(&spi->dev, "Unable to setup SPI device\n"); return -EFAULT; diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index 8f4808695e8206..90b290f94c273c 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -81,7 +81,7 @@ struct qcaspi { struct qcafrm_handle frm_handle; struct sk_buff *rx_skb; - unsigned long intr; + unsigned long flags; u16 reset_count; #ifdef CONFIG_DEBUG_FS @@ -89,7 +89,6 @@ struct qcaspi { #endif /* user configurable options */ - u32 clkspeed; u8 legacy_mode; u16 burst_len; }; diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index e2db944e6fa8bd..be4c9622618d84 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -68,6 +68,7 @@ enum mac_version { /* support for RTL_GIGA_MAC_VER_60 has been removed */ RTL_GIGA_MAC_VER_61, RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, RTL_GIGA_MAC_VER_65, RTL_GIGA_MAC_VER_66, RTL_GIGA_MAC_NONE diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c index ed6e721b15552b..bf055078a855d8 100644 --- a/drivers/net/ethernet/realtek/r8169_firmware.c +++ b/drivers/net/ethernet/realtek/r8169_firmware.c @@ -215,7 +215,7 @@ int rtl_fw_request_firmware(struct rtl_fw *rtl_fw) { int rc; - rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); + rc = firmware_request_nowarn(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); if (rc < 0) goto out; @@ -227,7 +227,7 @@ int rtl_fw_request_firmware(struct rtl_fw *rtl_fw) return 0; out: - dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n", - rtl_fw->fw_name, rc); + dev_warn(rtl_fw->dev, "Unable to load firmware %s (%d)\n", + rtl_fw->fw_name, rc); return rc; } diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 713a89bb21e93b..739707a7b40fb9 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ #define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw" #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" +#define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" @@ -138,6 +140,7 @@ static const struct { [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3}, /* reserve 62 for CFG_METHOD_4 in the vendor driver */ [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, [RTL_GIGA_MAC_VER_65] = {"RTL8126A", FIRMWARE_8126A_2}, [RTL_GIGA_MAC_VER_66] = {"RTL8126A", FIRMWARE_8126A_3}, }; @@ -344,6 +347,8 @@ enum rtl8125_registers { TxPoll_8125 = 0x90, LEDSEL3 = 0x96, MAC0_BKP = 0x19e0, + RSS_CTRL_8125 = 0x4500, + Q_NUM_CTRL_8125 = 0x4800, EEE_TXIDLE_TIMER_8125 = 0x6048, }; @@ -617,7 +622,6 @@ struct rtl8169_tc_offsets { }; enum rtl_flag { - RTL_FLAG_TASK_ENABLED = 0, RTL_FLAG_TASK_RESET_PENDING, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, RTL_FLAG_TASK_TX_TIMEOUT, @@ -658,13 +662,9 @@ struct rtl8169_private { struct work_struct work; } wk; - raw_spinlock_t config25_lock; raw_spinlock_t mac_ocp_lock; struct mutex led_lock; /* serialize LED ctrl RMW access */ - raw_spinlock_t cfg9346_usage_lock; - int cfg9346_usage_count; - unsigned supports_gmii:1; unsigned aspm_manageable:1; unsigned dash_enabled:1; @@ -707,6 +707,7 @@ MODULE_FIRMWARE(FIRMWARE_8168FP_3); MODULE_FIRMWARE(FIRMWARE_8107E_2); MODULE_FIRMWARE(FIRMWARE_8125A_3); MODULE_FIRMWARE(FIRMWARE_8125B_2); +MODULE_FIRMWARE(FIRMWARE_8125D_1); MODULE_FIRMWARE(FIRMWARE_8126A_2); MODULE_FIRMWARE(FIRMWARE_8126A_3); @@ -717,22 +718,12 @@ static inline struct device *tp_to_dev(struct rtl8169_private *tp) static void rtl_lock_config_regs(struct rtl8169_private *tp) { - unsigned long flags; - - raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); - if (!--tp->cfg9346_usage_count) - RTL_W8(tp, Cfg9346, Cfg9346_Lock); - raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); + RTL_W8(tp, Cfg9346, Cfg9346_Lock); } static void rtl_unlock_config_regs(struct rtl8169_private *tp) { - unsigned long flags; - - raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); - if (!tp->cfg9346_usage_count++) - RTL_W8(tp, Cfg9346, Cfg9346_Unlock); - raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); + RTL_W8(tp, Cfg9346, Cfg9346_Unlock); } static void rtl_pci_commit(struct rtl8169_private *tp) @@ -743,24 +734,32 @@ static void rtl_pci_commit(struct rtl8169_private *tp) static void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set) { - unsigned long flags; u8 val; - raw_spin_lock_irqsave(&tp->config25_lock, flags); val = RTL_R8(tp, Config2); RTL_W8(tp, Config2, (val & ~clear) | set); - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); } static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) { - unsigned long flags; u8 val; - raw_spin_lock_irqsave(&tp->config25_lock, flags); val = RTL_R8(tp, Config5); RTL_W8(tp, Config5, (val & ~clear) | set); - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); +} + +static void r8169_mod_reg8_cond(struct rtl8169_private *tp, int reg, + u8 bits, bool cond) +{ + u8 val, old_val; + + old_val = RTL_R8(tp, reg); + if (cond) + val = old_val | bits; + else + val = old_val & ~bits; + if (val != old_val) + RTL_W8(tp, reg, val); } static bool rtl_is_8125(struct rtl8169_private *tp) @@ -1346,40 +1345,19 @@ static void rtl8168ep_stop_cmac(struct rtl8169_private *tp) RTL_W8(tp, IBCR0, RTL_R8(tp, IBCR0) & ~0x01); } -static void rtl_dash_loop_wait(struct rtl8169_private *tp, - const struct rtl_cond *c, - unsigned long usecs, int n, bool high) -{ - if (!tp->dash_enabled) - return; - rtl_loop_wait(tp, c, usecs, n, high); -} - -static void rtl_dash_loop_wait_high(struct rtl8169_private *tp, - const struct rtl_cond *c, - unsigned long d, int n) -{ - rtl_dash_loop_wait(tp, c, d, n, true); -} - -static void rtl_dash_loop_wait_low(struct rtl8169_private *tp, - const struct rtl_cond *c, - unsigned long d, int n) -{ - rtl_dash_loop_wait(tp, c, d, n, false); -} - static void rtl8168dp_driver_start(struct rtl8169_private *tp) { r8168dp_oob_notify(tp, OOB_CMD_DRIVER_START); - rtl_dash_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); } static void rtl8168ep_driver_start(struct rtl8169_private *tp) { r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_START); r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); - rtl_dash_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); + if (tp->dash_enabled) + rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); } static void rtl8168_driver_start(struct rtl8169_private *tp) @@ -1393,7 +1371,8 @@ static void rtl8168_driver_start(struct rtl8169_private *tp) static void rtl8168dp_driver_stop(struct rtl8169_private *tp) { r8168dp_oob_notify(tp, OOB_CMD_DRIVER_STOP); - rtl_dash_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); } static void rtl8168ep_driver_stop(struct rtl8169_private *tp) @@ -1401,7 +1380,8 @@ static void rtl8168ep_driver_stop(struct rtl8169_private *tp) rtl8168ep_stop_cmac(tp); r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP); r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); - rtl_dash_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); } static void rtl8168_driver_stop(struct rtl8169_private *tp) @@ -1451,19 +1431,11 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable) { - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: - case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: - case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: - if (enable) - RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN); - else - RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | D3_NO_PLL_DOWN); - break; - default: - break; - } + if (tp->mac_version >= RTL_GIGA_MAC_VER_25 && + tp->mac_version != RTL_GIGA_MAC_VER_28 && + tp->mac_version != RTL_GIGA_MAC_VER_31 && + tp->mac_version != RTL_GIGA_MAC_VER_38) + r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable); } static void rtl_reset_packet_filter(struct rtl8169_private *tp) @@ -1572,61 +1544,40 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) { - static const struct { - u32 opt; - u16 reg; - u8 mask; - } cfg[] = { - { WAKE_PHY, Config3, LinkUp }, - { WAKE_UCAST, Config5, UWF }, - { WAKE_BCAST, Config5, BWF }, - { WAKE_MCAST, Config5, MWF }, - { WAKE_ANY, Config5, LanWake }, - { WAKE_MAGIC, Config3, MagicPacket } - }; - unsigned int i, tmp = ARRAY_SIZE(cfg); - unsigned long flags; - u8 options; - rtl_unlock_config_regs(tp); if (rtl_is_8168evl_up(tp)) { - tmp--; if (wolopts & WAKE_MAGIC) rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2); else rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2); } else if (rtl_is_8125(tp)) { - tmp--; if (wolopts & WAKE_MAGIC) r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0)); else r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); + } else { + r8169_mod_reg8_cond(tp, Config3, MagicPacket, + wolopts & WAKE_MAGIC); } - 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); - } - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); + r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY); + if (rtl_is_8125(tp)) + r8168_mac_ocp_modify(tp, 0xe0c6, 0x3f, + wolopts & WAKE_PHY ? 0x13 : 0); + r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST); + r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST); + r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST); + r8169_mod_reg8_cond(tp, Config5, LanWake, wolopts); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: - options = RTL_R8(tp, Config1) & ~PMEnable; - if (wolopts) - options |= PMEnable; - RTL_W8(tp, Config1, options); + r8169_mod_reg8_cond(tp, Config1, PMEnable, wolopts); break; case RTL_GIGA_MAC_VER_34: case RTL_GIGA_MAC_VER_37: case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_66: - if (wolopts) - rtl_mod_config2(tp, 0, PME_SIGNAL); - else - rtl_mod_config2(tp, PME_SIGNAL, 0); + r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); break; default: break; @@ -2098,10 +2049,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) tp->tx_lpi_timer = timer_val; r8168_mac_ocp_write(tp, 0xe048, timer_val); break; - case RTL_GIGA_MAC_VER_61: - case RTL_GIGA_MAC_VER_63: - case RTL_GIGA_MAC_VER_65: - case RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_66: tp->tx_lpi_timer = timer_val; RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); break; @@ -2160,6 +2108,19 @@ static void rtl8169_get_ringparam(struct net_device *dev, data->tx_pending = NUM_TX_DESC; } +static void rtl8169_get_pause_stats(struct net_device *dev, + struct ethtool_pause_stats *pause_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (!rtl_is_8125(tp)) + return; + + rtl8169_update_counters(tp); + pause_stats->tx_pause_frames = le32_to_cpu(tp->counters->tx_pause_on); + pause_stats->rx_pause_frames = le32_to_cpu(tp->counters->rx_pause_on); +} + static void rtl8169_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *data) { @@ -2186,6 +2147,69 @@ static int rtl8169_set_pauseparam(struct net_device *dev, return 0; } +static void rtl8169_get_eth_mac_stats(struct net_device *dev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl8169_update_counters(tp); + + mac_stats->FramesTransmittedOK = + le64_to_cpu(tp->counters->tx_packets); + mac_stats->SingleCollisionFrames = + le32_to_cpu(tp->counters->tx_one_collision); + mac_stats->MultipleCollisionFrames = + le32_to_cpu(tp->counters->tx_multi_collision); + mac_stats->FramesReceivedOK = + le64_to_cpu(tp->counters->rx_packets); + mac_stats->AlignmentErrors = + le16_to_cpu(tp->counters->align_errors); + mac_stats->FramesLostDueToIntMACXmitError = + le64_to_cpu(tp->counters->tx_errors); + mac_stats->BroadcastFramesReceivedOK = + le64_to_cpu(tp->counters->rx_broadcast); + mac_stats->MulticastFramesReceivedOK = + le32_to_cpu(tp->counters->rx_multicast); + + if (!rtl_is_8125(tp)) + return; + + mac_stats->AlignmentErrors = + le32_to_cpu(tp->counters->align_errors32); + mac_stats->OctetsTransmittedOK = + le64_to_cpu(tp->counters->tx_octets); + mac_stats->LateCollisions = + le32_to_cpu(tp->counters->tx_late_collision); + mac_stats->FramesAbortedDueToXSColls = + le32_to_cpu(tp->counters->tx_aborted32); + mac_stats->OctetsReceivedOK = + le64_to_cpu(tp->counters->rx_octets); + mac_stats->FramesLostDueToIntMACRcvError = + le32_to_cpu(tp->counters->rx_mac_error); + mac_stats->MulticastFramesXmittedOK = + le64_to_cpu(tp->counters->tx_multicast64); + mac_stats->BroadcastFramesXmittedOK = + le64_to_cpu(tp->counters->tx_broadcast64); + mac_stats->MulticastFramesReceivedOK = + le64_to_cpu(tp->counters->rx_multicast64); + mac_stats->FrameTooLongErrors = + le32_to_cpu(tp->counters->rx_frame_too_long); +} + +static void rtl8169_get_eth_ctrl_stats(struct net_device *dev, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (!rtl_is_8125(tp)) + return; + + rtl8169_update_counters(tp); + + ctrl_stats->UnsupportedOpcodesReceived = + le32_to_cpu(tp->counters->rx_unknown_opcode); +} + static const struct ethtool_ops rtl8169_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES, @@ -2207,8 +2231,11 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, .get_ringparam = rtl8169_get_ringparam, + .get_pause_stats = rtl8169_get_pause_stats, .get_pauseparam = rtl8169_get_pauseparam, .set_pauseparam = rtl8169_set_pauseparam, + .get_eth_mac_stats = rtl8169_get_eth_mac_stats, + .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats, }; static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) @@ -2233,6 +2260,9 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_66 }, { 0x7cf, 0x649, RTL_GIGA_MAC_VER_65 }, + /* 8125D family. */ + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, + /* 8125B family. */ { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 }, @@ -2423,11 +2453,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp) static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag) { - if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) - return; - set_bit(flag, tp->wk.flags); - schedule_work(&tp->wk.work); + if (!schedule_work(&tp->wk.work)) + clear_bit(flag, tp->wk.flags); } static void rtl8169_init_phy(struct rtl8169_private *tp) @@ -2500,9 +2528,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); break; - case RTL_GIGA_MAC_VER_63: - case RTL_GIGA_MAC_VER_65: - case RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_66: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | RX_PAUSE_SLOT_ON); break; @@ -2517,86 +2543,31 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp) tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0; } -static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1); -} - -static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1); -} - -static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); -} - -static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); -} - -static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, MaxTxPacketSize, 0x24); - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01); -} - -static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, MaxTxPacketSize, 0x3f); - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); -} - -static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0)); -} - -static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); -} - static void rtl_jumbo_config(struct rtl8169_private *tp) { bool jumbo = tp->dev->mtu > ETH_DATA_LEN; int readrq = 4096; + if (jumbo && tp->mac_version >= RTL_GIGA_MAC_VER_17 && + tp->mac_version <= RTL_GIGA_MAC_VER_26) + readrq = 512; + rtl_unlock_config_regs(tp); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_17: - if (jumbo) { - readrq = 512; - r8168b_1_hw_jumbo_enable(tp); - } else { - r8168b_1_hw_jumbo_disable(tp); - } + r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); break; case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26: - if (jumbo) { - readrq = 512; - r8168c_hw_jumbo_enable(tp); - } else { - r8168c_hw_jumbo_disable(tp); - } + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); + r8169_mod_reg8_cond(tp, Config4, Jumbo_En1, jumbo); break; case RTL_GIGA_MAC_VER_28: - if (jumbo) - r8168dp_hw_jumbo_enable(tp); - else - r8168dp_hw_jumbo_disable(tp); + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); break; case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33: - if (jumbo) - r8168e_hw_jumbo_enable(tp); - else - r8168e_hw_jumbo_disable(tp); + RTL_W8(tp, MaxTxPacketSize, jumbo ? 0x24 : 0x3f); + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); + r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); break; default: break; @@ -3707,8 +3678,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) rtl_pcie_state_l2l3_disable(tp); RTL_W16(tp, 0x382, 0x221b); - RTL_W8(tp, 0x4500, 0); - RTL_W16(tp, 0x4800, 0); + RTL_W32(tp, RSS_CTRL_8125, 0); + RTL_W16(tp, Q_NUM_CTRL_8125, 0); /* disable UPS */ r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000); @@ -3814,6 +3785,12 @@ static void rtl_hw_start_8125b(struct rtl8169_private *tp) rtl_hw_start_8125_common(tp); } +static void rtl_hw_start_8125d(struct rtl8169_private *tp) +{ + rtl_set_def_aspm_entry_latency(tp); + rtl_hw_start_8125_common(tp); +} + static void rtl_hw_start_8126a(struct rtl8169_private *tp) { rtl_set_def_aspm_entry_latency(tp); @@ -3862,6 +3839,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117, [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8126a, [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8126a, }; @@ -3879,6 +3857,7 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) /* disable interrupt coalescing */ switch (tp->mac_version) { case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_64: for (i = 0xa00; i < 0xb00; i += 4) RTL_W32(tp, i, 0); break; @@ -3893,6 +3872,9 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) break; } + /* enable extended tally counter */ + r8168_mac_ocp_modify(tp, 0xea84, 0, BIT(1) | BIT(0)); + rtl_hw_config(tp); } @@ -4233,8 +4215,8 @@ static unsigned int rtl8125_quirk_udp_padto(struct rtl8169_private *tp, { unsigned int padto = 0, len = skb->len; - if (rtl_is_8125(tp) && len < 128 + RTL_MIN_PATCH_LEN && - rtl_skb_is_udp(skb) && skb_transport_header_was_set(skb)) { + if (len < 128 + RTL_MIN_PATCH_LEN && rtl_skb_is_udp(skb) && + skb_transport_header_was_set(skb)) { unsigned int trans_data_len = skb_tail_pointer(skb) - skb_transport_header(skb); @@ -4258,9 +4240,15 @@ static unsigned int rtl8125_quirk_udp_padto(struct rtl8169_private *tp, static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp, struct sk_buff *skb) { - unsigned int padto; + unsigned int padto = 0; - padto = rtl8125_quirk_udp_padto(tp, skb); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: + padto = rtl8125_quirk_udp_padto(tp, skb); + break; + default: + break; + } switch (tp->mac_version) { case RTL_GIGA_MAC_VER_34: @@ -4712,11 +4700,6 @@ static void rtl_task(struct work_struct *work) container_of(work, struct rtl8169_private, wk.work); int ret; - rtnl_lock(); - - if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) - goto out_unlock; - if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { /* if chip isn't accessible, reset bus to revive it */ if (RTL_R32(tp, TxConfig) == ~0) { @@ -4724,7 +4707,7 @@ static void rtl_task(struct work_struct *work) if (ret < 0) { netdev_err(tp->dev, "Can't reset secondary PCI bus, detach NIC\n"); netif_device_detach(tp->dev); - goto out_unlock; + return; } } @@ -4743,8 +4726,6 @@ static void rtl_task(struct work_struct *work) } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { rtl_reset_work(tp); } -out_unlock: - rtnl_unlock(); } static int rtl8169_poll(struct napi_struct *napi, int budget) @@ -4771,11 +4752,7 @@ static void r8169_phylink_handler(struct net_device *ndev) if (netif_carrier_ok(ndev)) { rtl_link_chg_patch(tp); pm_request_resume(d); - netif_wake_queue(tp->dev); } else { - /* In few cases rx is broken after link-down otherwise */ - if (rtl_is_8125(tp)) - rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE); pm_runtime_idle(d); } @@ -4806,6 +4783,7 @@ static int r8169_phy_connect(struct rtl8169_private *tp) static void rtl8169_down(struct rtl8169_private *tp) { + disable_work_sync(&tp->wk.work); /* Clear all task flags */ bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); @@ -4834,7 +4812,7 @@ static void rtl8169_up(struct rtl8169_private *tp) phy_resume(tp->phydev); rtl8169_init_phy(tp); napi_enable(&tp->napi); - set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + enable_work(&tp->wk.work); rtl_reset_work(tp); phy_start(tp->phydev); @@ -4851,8 +4829,6 @@ static int rtl8169_close(struct net_device *dev) rtl8169_down(tp); rtl8169_rx_clear(tp); - cancel_work(&tp->wk.work); - free_irq(tp->irq, tp); phy_disconnect(tp->phydev); @@ -5085,7 +5061,7 @@ static void rtl_remove_one(struct pci_dev *pdev) if (pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); - cancel_work_sync(&tp->wk.work); + disable_work_sync(&tp->wk.work); if (IS_ENABLED(CONFIG_R8169_LEDS)) r8169_remove_leds(tp->leds); @@ -5252,6 +5228,12 @@ static int r8169_mdio_register(struct rtl8169_private *tp) phy_support_eee(tp->phydev); phy_support_asym_pause(tp->phydev); + /* mimic behavior of r8125/r8126 vendor drivers */ + if (tp->mac_version == RTL_GIGA_MAC_VER_61) + phy_set_eee_broken(tp->phydev, + ETHTOOL_LINK_MODE_2500baseT_Full_BIT); + phy_set_eee_broken(tp->phydev, ETHTOOL_LINK_MODE_5000baseT_Full_BIT); + /* PHY will be woken up in rtl_open() */ phy_suspend(tp->phydev); @@ -5365,6 +5347,43 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp) return false; } +static umode_t r8169_hwmon_is_visible(const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + return 0444; +} + +static int r8169_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct rtl8169_private *tp = dev_get_drvdata(dev); + int val_raw; + + val_raw = phy_read_paged(tp->phydev, 0xbd8, 0x12) & 0x3ff; + if (val_raw >= 512) + val_raw -= 1024; + + *val = 1000 * val_raw / 2; + + return 0; +} + +static const struct hwmon_ops r8169_hwmon_ops = { + .is_visible = r8169_hwmon_is_visible, + .read = r8169_hwmon_read, +}; + +static const struct hwmon_channel_info * const r8169_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_chip_info r8169_hwmon_chip_info = { + .ops = &r8169_hwmon_ops, + .info = r8169_hwmon_info, +}; + static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct rtl8169_private *tp; @@ -5386,8 +5405,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; tp->ocp_base = OCP_STD_PHY_BASE; - raw_spin_lock_init(&tp->cfg9346_usage_lock); - raw_spin_lock_init(&tp->config25_lock); raw_spin_lock_init(&tp->mac_ocp_lock); mutex_init(&tp->led_lock); @@ -5462,6 +5479,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->irq = pci_irq_vector(pdev, 0); INIT_WORK(&tp->wk.work, rtl_task); + disable_work(&tp->wk.work); rtl_init_mac_address(tp); @@ -5487,11 +5505,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->features |= dev->hw_features; - /* There has been a number of reports that using SG/TSO results in - * tx timeouts. However for a lot of people SG/TSO works fine. - * Therefore disable both features by default, but allow users to - * enable them. Use at own risk! - */ if (rtl_chip_supports_csum_v2(tp)) { dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V2); @@ -5502,6 +5515,17 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V1); } + /* There has been a number of reports that using SG/TSO results in + * tx timeouts. However for a lot of people SG/TSO works fine. + * It's not fully clear which chip versions are affected. Vendor + * drivers enable SG/TSO for certain chip versions per default, + * let's mimic this here. On other chip versions users can + * use ethtool to enable SG/TSO, use at own risk! + */ + if (tp->mac_version >= RTL_GIGA_MAC_VER_46 && + tp->mac_version != RTL_GIGA_MAC_VER_61) + dev->features |= dev->hw_features; + dev->hw_features |= NETIF_F_RXALL; dev->hw_features |= NETIF_F_RXFCS; @@ -5539,6 +5563,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; + /* The temperature sensor is available from RTl8125B */ + if (IS_REACHABLE(CONFIG_HWMON) && tp->mac_version >= RTL_GIGA_MAC_VER_63) + /* ignore errors */ + devm_hwmon_device_register_with_info(&pdev->dev, "nic_temp", tp, + &r8169_hwmon_chip_info, + NULL); rc = register_netdev(dev); if (rc) return rc; diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index cf29b120848269..5307c6ff4e2523 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -89,20 +89,17 @@ static void rtl8168h_config_eee_phy(struct phy_device *phydev) phy_modify_paged(phydev, 0xa42, 0x14, 0x0000, 0x0080); } -static void rtl8125a_config_eee_phy(struct phy_device *phydev) +static void rtl8125_common_config_eee_phy(struct phy_device *phydev) { - rtl8168h_config_eee_phy(phydev); - - phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); + phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); + phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); } -static void rtl8125b_config_eee_phy(struct phy_device *phydev) +static void rtl8125_config_eee_phy(struct phy_device *phydev) { - phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); - phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); - phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); - phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); + rtl8168g_config_eee_phy(phydev); + rtl8125_common_config_eee_phy(phydev); } static void rtl8169s_hw_phy_config(struct rtl8169_private *tp, @@ -1061,15 +1058,15 @@ static void rtl8125a_2_hw_phy_config(struct rtl8169_private *tp, rtl8168g_enable_gphy_10m(phydev); rtl8168g_disable_aldps(phydev); - rtl8125a_config_eee_phy(phydev); + rtl8125_config_eee_phy(phydev); } static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); - phy_modify_paged(phydev, 0xa44, 0x11, 0x0000, 0x0800); phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090); phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001); @@ -1101,13 +1098,27 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, rtl8125_legacy_force_mode(phydev); rtl8168g_disable_aldps(phydev); - rtl8125b_config_eee_phy(phydev); + rtl8125_config_eee_phy(phydev); +} + +static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) +{ + r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_config_eee_phy(phydev); } static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_common_config_eee_phy(phydev); } void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, @@ -1160,6 +1171,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config, [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, [RTL_GIGA_MAC_VER_65] = rtl8126a_hw_phy_config, [RTL_GIGA_MAC_VER_66] = rtl8126a_hw_phy_config, }; diff --git a/drivers/net/ethernet/realtek/rtase/rtase.h b/drivers/net/ethernet/realtek/rtase/rtase.h index 583c33930f886f..dbc3f92eebc480 100644 --- a/drivers/net/ethernet/realtek/rtase/rtase.h +++ b/drivers/net/ethernet/realtek/rtase/rtase.h @@ -9,7 +9,10 @@ #ifndef RTASE_H #define RTASE_H -#define RTASE_HW_VER_MASK 0x7C800000 +#define RTASE_HW_VER_MASK 0x7C800000 +#define RTASE_HW_VER_906X_7XA 0x00800000 +#define RTASE_HW_VER_906X_7XC 0x04000000 +#define RTASE_HW_VER_907XD_V1 0x04800000 #define RTASE_RX_DMA_BURST_256 4 #define RTASE_TX_DMA_BURST_UNLIMITED 7 @@ -170,7 +173,7 @@ enum rtase_registers { RTASE_INT_MITI_TX = 0x0A00, RTASE_INT_MITI_RX = 0x0A80, - RTASE_VLAN_ENTRY_0 = 0xAC80, + RTASE_VLAN_ENTRY_0 = 0xAC80, }; enum rtase_desc_status_bit { @@ -327,6 +330,8 @@ struct rtase_private { u16 int_nums; u16 tx_int_mit; u16 rx_int_mit; + + u32 hw_ver; }; #define RTASE_LSO_64K 64000 diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c index f8777b7663d35d..de7f11232593fa 100644 --- a/drivers/net/ethernet/realtek/rtase/rtase_main.c +++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c @@ -1714,10 +1714,21 @@ static int rtase_get_settings(struct net_device *dev, struct ethtool_link_ksettings *cmd) { u32 supported = SUPPORTED_MII | SUPPORTED_Pause | SUPPORTED_Asym_Pause; + const struct rtase_private *tp = netdev_priv(dev); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, supported); - cmd->base.speed = SPEED_5000; + + switch (tp->hw_ver) { + case RTASE_HW_VER_906X_7XA: + case RTASE_HW_VER_906X_7XC: + cmd->base.speed = SPEED_5000; + break; + case RTASE_HW_VER_907XD_V1: + cmd->base.speed = SPEED_10000; + break; + } + cmd->base.duplex = DUPLEX_FULL; cmd->base.port = PORT_MII; cmd->base.autoneg = AUTONEG_DISABLE; @@ -1972,20 +1983,21 @@ static void rtase_init_software_variable(struct pci_dev *pdev, tp->dev->max_mtu = RTASE_MAX_JUMBO_SIZE; } -static bool rtase_check_mac_version_valid(struct rtase_private *tp) +static int rtase_check_mac_version_valid(struct rtase_private *tp) { - u32 hw_ver = rtase_r32(tp, RTASE_TX_CONFIG_0) & RTASE_HW_VER_MASK; - bool known_ver = false; + int ret = -ENODEV; + + tp->hw_ver = rtase_r32(tp, RTASE_TX_CONFIG_0) & RTASE_HW_VER_MASK; - switch (hw_ver) { - case 0x00800000: - case 0x04000000: - case 0x04800000: - known_ver = true; + switch (tp->hw_ver) { + case RTASE_HW_VER_906X_7XA: + case RTASE_HW_VER_906X_7XC: + case RTASE_HW_VER_907XD_V1: + ret = 0; break; } - return known_ver; + return ret; } static int rtase_init_board(struct pci_dev *pdev, struct net_device **dev_out, @@ -2105,9 +2117,13 @@ static int rtase_init_one(struct pci_dev *pdev, tp->pdev = pdev; /* identify chip attached to board */ - if (!rtase_check_mac_version_valid(tp)) - return dev_err_probe(&pdev->dev, -ENODEV, - "unknown chip version, contact rtase maintainers (see MAINTAINERS file)\n"); + ret = rtase_check_mac_version_valid(tp); + if (ret != 0) { + dev_err(&pdev->dev, + "unknown chip version: 0x%08x, contact rtase maintainers (see MAINTAINERS file)\n", + tp->hw_ver); + goto err_out_release_board; + } rtase_init_software_variable(pdev, tp); rtase_init_hardware(tp); @@ -2115,7 +2131,7 @@ static int rtase_init_one(struct pci_dev *pdev, ret = rtase_alloc_interrupt(pdev, tp); if (ret < 0) { dev_err(&pdev->dev, "unable to alloc MSIX/MSI\n"); - goto err_out_1; + goto err_out_del_napi; } rtase_init_netdev_ops(dev); @@ -2148,7 +2164,7 @@ static int rtase_init_one(struct pci_dev *pdev, GFP_KERNEL); if (!tp->tally_vaddr) { ret = -ENOMEM; - goto err_out; + goto err_out_free_dma; } rtase_tally_counter_clear(tp); @@ -2159,13 +2175,13 @@ static int rtase_init_one(struct pci_dev *pdev, ret = register_netdev(dev); if (ret != 0) - goto err_out; + goto err_out_free_dma; netdev_dbg(dev, "%pM, IRQ %d\n", dev->dev_addr, dev->irq); return 0; -err_out: +err_out_free_dma: if (tp->tally_vaddr) { dma_free_coherent(&pdev->dev, sizeof(*tp->tally_vaddr), @@ -2175,12 +2191,13 @@ static int rtase_init_one(struct pci_dev *pdev, tp->tally_vaddr = NULL; } -err_out_1: +err_out_del_napi: for (i = 0; i < tp->int_nums; i++) { ivec = &tp->int_vector[i]; netif_napi_del(&ivec->napi); } +err_out_release_board: rtase_release_board(pdev, dev, ioaddr); return ret; diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index a7de5cf6b31743..7b48060c250b4b 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -998,6 +998,8 @@ enum CSR1_BIT { CSR1_TDHD = 0x08000000, }; +#define CSR1_CSUM_ENABLE (CSR1_TTCP4 | CSR1_TUDP4 | CSR1_TTCP6 | CSR1_TUDP6) + enum CSR2_BIT { CSR2_RIP4 = 0x00000001, CSR2_RTCP4 = 0x00000010, @@ -1012,6 +1014,9 @@ enum CSR2_BIT { CSR2_RDHD = 0x08000000, }; +#define CSR2_CSUM_ENABLE (CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4 | \ + CSR2_RTCP6 | CSR2_RUDP6 | CSR2_RICMP6) + #define DBAT_ENTRY_NUM 22 #define RX_QUEUE_OFFSET 4 #define NUM_RX_QUEUE 2 @@ -1050,6 +1055,7 @@ struct ravb_hw_info { size_t gstrings_size; netdev_features_t net_hw_features; netdev_features_t net_features; + netdev_features_t vlan_features; int stats_len; u32 tccr_mask; u32 tx_max_frame_size; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 907af4651c5534..ac0f093f647a52 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -504,11 +504,10 @@ static void ravb_csum_init_gbeth(struct net_device *ndev) ndev->features &= ~NETIF_F_RXCSUM; } else { if (tx_enable) - ravb_write(ndev, CSR1_TIP4 | CSR1_TTCP4 | CSR1_TUDP4, CSR1); + ravb_write(ndev, CSR1_CSUM_ENABLE, CSR1); if (rx_enable) - ravb_write(ndev, CSR2_RIP4 | CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4, - CSR2); + ravb_write(ndev, CSR2_CSUM_ENABLE, CSR2); } done: @@ -750,38 +749,34 @@ static void ravb_get_tx_tstamp(struct net_device *ndev) static void ravb_rx_csum_gbeth(struct sk_buff *skb) { struct skb_shared_info *shinfo = skb_shinfo(skb); - __wsum csum_ip_hdr, csum_proto; - skb_frag_t *last_frag; - u8 *hw_csum; + size_t csum_len; + u16 *hw_csum; - /* The hardware checksum status is contained in sizeof(__sum16) * 2 = 4 - * bytes appended to packet data. First 2 bytes is ip header checksum - * and last 2 bytes is protocol checksum. + /* The hardware checksum status is contained in 4 bytes appended to + * packet data. + * + * For ipv4, the first 2 bytes are the ip header checksum status. We can + * ignore this as it will always be re-checked in inet_gro_receive(). + * + * The last 2 bytes are the protocol checksum status which will be zero + * if the checksum has been validated. */ - if (unlikely(skb->len < sizeof(__sum16) * 2)) + csum_len = sizeof(*hw_csum) * 2; + if (unlikely(skb->len < csum_len)) return; if (skb_is_nonlinear(skb)) { - last_frag = &shinfo->frags[shinfo->nr_frags - 1]; - hw_csum = skb_frag_address(last_frag) + - skb_frag_size(last_frag); + skb_frag_t *last_frag = &shinfo->frags[shinfo->nr_frags - 1]; + + hw_csum = (u16 *)(skb_frag_address(last_frag) + + skb_frag_size(last_frag)); + skb_frag_size_sub(last_frag, csum_len); } else { - hw_csum = skb_tail_pointer(skb); + hw_csum = (u16 *)skb_tail_pointer(skb); + skb_trim(skb, skb->len - csum_len); } - hw_csum -= sizeof(__sum16); - csum_proto = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum)); - - hw_csum -= sizeof(__sum16); - csum_ip_hdr = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum)); - - if (skb_is_nonlinear(skb)) - skb_frag_size_sub(last_frag, 2 * sizeof(__sum16)); - else - skb_trim(skb, skb->len - 2 * sizeof(__sum16)); - - /* TODO: IPV6 Rx checksum */ - if (skb->protocol == htons(ETH_P_IP) && !csum_ip_hdr && !csum_proto) + if (!get_unaligned(--hw_csum)) skb->ip_summed = CHECKSUM_UNNECESSARY; } @@ -2067,32 +2062,44 @@ static void ravb_tx_timeout_work(struct work_struct *work) static bool ravb_can_tx_csum_gbeth(struct sk_buff *skb) { - struct iphdr *ip = ip_hdr(skb); + u16 net_protocol = ntohs(skb->protocol); + u8 inner_protocol; - /* TODO: Need to add support for VLAN tag 802.1Q */ - if (skb_vlan_tag_present(skb)) - return false; + /* GbEth IP can calculate the checksum if: + * - there are zero or one VLAN headers with TPID=0x8100 + * - the network protocol is IPv4 or IPv6 + * - the transport protocol is TCP, UDP or ICMP + * - the packet is not fragmented + */ - /* TODO: Need to add hardware checksum for IPv6 */ - if (skb->protocol != htons(ETH_P_IP)) - return false; + if (net_protocol == ETH_P_8021Q) { + struct vlan_hdr vhdr, *vh; - switch (ip->protocol) { - case IPPROTO_TCP: - break; - case IPPROTO_UDP: - /* If the checksum value in the UDP header field is 0, TOE does - * not calculate checksum for UDP part of this frame as it is - * optional function as per standards. - */ - if (udp_hdr(skb)->check == 0) + vh = skb_header_pointer(skb, ETH_HLEN, sizeof(vhdr), &vhdr); + if (!vh) return false; + + net_protocol = ntohs(vh->h_vlan_encapsulated_proto); + } + + switch (net_protocol) { + case ETH_P_IP: + inner_protocol = ip_hdr(skb)->protocol; + break; + case ETH_P_IPV6: + inner_protocol = ipv6_hdr(skb)->nexthdr; break; default: return false; } - return true; + switch (inner_protocol) { + case IPPROTO_TCP: + case IPPROTO_UDP: + return true; + default: + return false; + } } /* Packet transmit function for Ethernet AVB */ @@ -2530,7 +2537,7 @@ static int ravb_set_features_gbeth(struct net_device *ndev, spin_lock_irqsave(&priv->lock, flags); if (changed & NETIF_F_RXCSUM) { if (features & NETIF_F_RXCSUM) - val = CSR2_RIP4 | CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4; + val = CSR2_CSUM_ENABLE; else val = 0; @@ -2541,7 +2548,7 @@ static int ravb_set_features_gbeth(struct net_device *ndev, if (changed & NETIF_F_HW_CSUM) { if (features & NETIF_F_HW_CSUM) - val = CSR1_TIP4 | CSR1_TTCP4 | CSR1_TUDP4; + val = CSR1_CSUM_ENABLE; else val = 0; @@ -2778,6 +2785,7 @@ static const struct ravb_hw_info gbeth_hw_info = { .gstrings_size = sizeof(ravb_gstrings_stats_gbeth), .net_hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM, .net_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM, + .vlan_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats_gbeth), .tccr_mask = TCCR_TSRQ0, .tx_max_frame_size = 1522, @@ -2920,6 +2928,7 @@ static int ravb_probe(struct platform_device *pdev) ndev->features = info->net_features; ndev->hw_features = info->net_hw_features; + ndev->vlan_features = info->vlan_features; error = reset_control_deassert(rstc); if (error) @@ -3290,7 +3299,7 @@ static const struct dev_pm_ops ravb_dev_pm_ops = { static struct platform_driver ravb_driver = { .probe = ravb_probe, - .remove_new = ravb_remove, + .remove = ravb_remove, .driver = { .name = "ravb", .pm = pm_ptr(&ravb_dev_pm_ops), diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index b80aa27a7214d4..9ac6e2aad18f62 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -547,7 +547,6 @@ static int rswitch_gwca_ts_queue_alloc(struct rswitch_private *priv) desc = &gq->ts_ring[gq->ring_size]; desc->desc.die_dt = DT_LINKFIX; rswitch_desc_set_dptr(&desc->desc, gq->ring_dma); - INIT_LIST_HEAD(&priv->gwca.ts_info_list); return 0; } @@ -862,13 +861,10 @@ static void rswitch_tx_free(struct net_device *ndev) struct rswitch_ext_desc *desc; struct sk_buff *skb; - for (; rswitch_get_num_cur_queues(gq) > 0; - gq->dirty = rswitch_next_queue_index(gq, false, 1)) { - desc = &gq->tx_ring[gq->dirty]; - if ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY) - break; - + desc = &gq->tx_ring[gq->dirty]; + while ((desc->desc.die_dt & DT_MASK) == DT_FEMPTY) { dma_rmb(); + skb = gq->skbs[gq->dirty]; if (skb) { rdev->ndev->stats.tx_packets++; @@ -879,7 +875,10 @@ static void rswitch_tx_free(struct net_device *ndev) dev_kfree_skb_any(gq->skbs[gq->dirty]); gq->skbs[gq->dirty] = NULL; } + desc->desc.die_dt = DT_EEMPTY; + gq->dirty = rswitch_next_queue_index(gq, false, 1); + desc = &gq->tx_ring[gq->dirty]; } } @@ -908,8 +907,10 @@ static int rswitch_poll(struct napi_struct *napi, int budget) if (napi_complete_done(napi, budget - quota)) { spin_lock_irqsave(&priv->lock, flags); - rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true); - rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true); + if (test_bit(rdev->port, priv->opened_ports)) { + rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true); + rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true); + } spin_unlock_irqrestore(&priv->lock, flags); } @@ -1001,9 +1002,10 @@ static int rswitch_gwca_request_irqs(struct rswitch_private *priv) static void rswitch_ts(struct rswitch_private *priv) { struct rswitch_gwca_queue *gq = &priv->gwca.ts_queue; - struct rswitch_gwca_ts_info *ts_info, *ts_info2; struct skb_shared_hwtstamps shhwtstamps; struct rswitch_ts_desc *desc; + struct rswitch_device *rdev; + struct sk_buff *ts_skb; struct timespec64 ts; unsigned int num; u32 tag, port; @@ -1013,23 +1015,28 @@ static void rswitch_ts(struct rswitch_private *priv) dma_rmb(); port = TS_DESC_DPN(__le32_to_cpu(desc->desc.dptrl)); - tag = TS_DESC_TSUN(__le32_to_cpu(desc->desc.dptrl)); - - list_for_each_entry_safe(ts_info, ts_info2, &priv->gwca.ts_info_list, list) { - if (!(ts_info->port == port && ts_info->tag == tag)) - continue; - - memset(&shhwtstamps, 0, sizeof(shhwtstamps)); - ts.tv_sec = __le32_to_cpu(desc->ts_sec); - ts.tv_nsec = __le32_to_cpu(desc->ts_nsec & cpu_to_le32(0x3fffffff)); - shhwtstamps.hwtstamp = timespec64_to_ktime(ts); - skb_tstamp_tx(ts_info->skb, &shhwtstamps); - dev_consume_skb_irq(ts_info->skb); - list_del(&ts_info->list); - kfree(ts_info); - break; - } + if (unlikely(port >= RSWITCH_NUM_PORTS)) + goto next; + rdev = priv->rdev[port]; + tag = TS_DESC_TSUN(__le32_to_cpu(desc->desc.dptrl)); + if (unlikely(tag >= TS_TAGS_PER_PORT)) + goto next; + ts_skb = xchg(&rdev->ts_skb[tag], NULL); + smp_mb(); /* order rdev->ts_skb[] read before bitmap update */ + clear_bit(tag, rdev->ts_skb_used); + + if (unlikely(!ts_skb)) + goto next; + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + ts.tv_sec = __le32_to_cpu(desc->ts_sec); + ts.tv_nsec = __le32_to_cpu(desc->ts_nsec & cpu_to_le32(0x3fffffff)); + shhwtstamps.hwtstamp = timespec64_to_ktime(ts); + skb_tstamp_tx(ts_skb, &shhwtstamps); + dev_consume_skb_irq(ts_skb); + +next: gq->cur = rswitch_next_queue_index(gq, true, 1); desc = &gq->ts_ring[gq->cur]; } @@ -1114,25 +1121,40 @@ static int rswitch_etha_wait_link_verification(struct rswitch_etha *etha) static void rswitch_rmac_setting(struct rswitch_etha *etha, const u8 *mac) { - u32 val; + u32 pis, lsc; rswitch_etha_write_mac_address(etha, mac); + switch (etha->phy_interface) { + case PHY_INTERFACE_MODE_SGMII: + pis = MPIC_PIS_GMII; + break; + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_5GBASER: + pis = MPIC_PIS_XGMII; + break; + default: + pis = FIELD_GET(MPIC_PIS, ioread32(etha->addr + MPIC)); + break; + } + switch (etha->speed) { case 100: - val = MPIC_LSC_100M; + lsc = MPIC_LSC_100M; break; case 1000: - val = MPIC_LSC_1G; + lsc = MPIC_LSC_1G; break; case 2500: - val = MPIC_LSC_2_5G; + lsc = MPIC_LSC_2_5G; break; default: - return; + lsc = FIELD_GET(MPIC_LSC, ioread32(etha->addr + MPIC)); + break; } - iowrite32(MPIC_PIS_GMII | val, etha->addr + MPIC); + rswitch_modify(etha->addr, MPIC, MPIC_PIS | MPIC_LSC, + FIELD_PREP(MPIC_PIS, pis) | FIELD_PREP(MPIC_LSC, lsc)); } static void rswitch_etha_enable_mii(struct rswitch_etha *etha) @@ -1538,20 +1560,20 @@ static int rswitch_open(struct net_device *ndev) struct rswitch_device *rdev = netdev_priv(ndev); unsigned long flags; - phy_start(ndev->phydev); + if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) + iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE); napi_enable(&rdev->napi); - netif_start_queue(ndev); spin_lock_irqsave(&rdev->priv->lock, flags); + bitmap_set(rdev->priv->opened_ports, rdev->port, 1); rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, true); rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, true); spin_unlock_irqrestore(&rdev->priv->lock, flags); - if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) - iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE); + phy_start(ndev->phydev); - bitmap_set(rdev->priv->opened_ports, rdev->port, 1); + netif_start_queue(ndev); return 0; }; @@ -1559,31 +1581,34 @@ static int rswitch_open(struct net_device *ndev) static int rswitch_stop(struct net_device *ndev) { struct rswitch_device *rdev = netdev_priv(ndev); - struct rswitch_gwca_ts_info *ts_info, *ts_info2; + struct sk_buff *ts_skb; unsigned long flags; + unsigned int tag; netif_tx_stop_all_queues(ndev); - bitmap_clear(rdev->priv->opened_ports, rdev->port, 1); - - if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) - iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDID); - list_for_each_entry_safe(ts_info, ts_info2, &rdev->priv->gwca.ts_info_list, list) { - if (ts_info->port != rdev->port) - continue; - dev_kfree_skb_irq(ts_info->skb); - list_del(&ts_info->list); - kfree(ts_info); - } + phy_stop(ndev->phydev); spin_lock_irqsave(&rdev->priv->lock, flags); rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false); rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false); + bitmap_clear(rdev->priv->opened_ports, rdev->port, 1); spin_unlock_irqrestore(&rdev->priv->lock, flags); - phy_stop(ndev->phydev); napi_disable(&rdev->napi); + if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) + iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDID); + + for (tag = find_first_bit(rdev->ts_skb_used, TS_TAGS_PER_PORT); + tag < TS_TAGS_PER_PORT; + tag = find_next_bit(rdev->ts_skb_used, TS_TAGS_PER_PORT, tag + 1)) { + ts_skb = xchg(&rdev->ts_skb[tag], NULL); + clear_bit(tag, rdev->ts_skb_used); + if (ts_skb) + dev_kfree_skb(ts_skb); + } + return 0; }; @@ -1594,20 +1619,17 @@ static bool rswitch_ext_desc_set_info1(struct rswitch_device *rdev, desc->info1 = cpu_to_le64(INFO1_DV(BIT(rdev->etha->index)) | INFO1_IPV(GWCA_IPV_NUM) | INFO1_FMT); if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { - struct rswitch_gwca_ts_info *ts_info; + unsigned int tag; - ts_info = kzalloc(sizeof(*ts_info), GFP_ATOMIC); - if (!ts_info) + tag = find_first_zero_bit(rdev->ts_skb_used, TS_TAGS_PER_PORT); + if (tag == TS_TAGS_PER_PORT) return false; + smp_mb(); /* order bitmap read before rdev->ts_skb[] write */ + rdev->ts_skb[tag] = skb_get(skb); + set_bit(tag, rdev->ts_skb_used); skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - rdev->ts_tag++; - desc->info1 |= cpu_to_le64(INFO1_TSUN(rdev->ts_tag) | INFO1_TXC); - - ts_info->skb = skb_get(skb); - ts_info->port = rdev->port; - ts_info->tag = rdev->ts_tag; - list_add_tail(&ts_info->list, &rdev->priv->gwca.ts_info_list); + desc->info1 |= cpu_to_le64(INFO1_TSUN(tag) | INFO1_TXC); skb_tx_timestamp(skb); } @@ -1681,8 +1703,11 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd if (dma_mapping_error(ndev->dev.parent, dma_addr_orig)) goto err_kfree; - gq->skbs[gq->cur] = skb; - gq->unmap_addrs[gq->cur] = dma_addr_orig; + /* Stored the skb at the last descriptor to avoid skb free before hardware completes send */ + gq->skbs[(gq->cur + nr_desc - 1) % gq->ring_size] = skb; + gq->unmap_addrs[(gq->cur + nr_desc - 1) % gq->ring_size] = dma_addr_orig; + + dma_wmb(); /* DT_FSTART should be set at last. So, this is reverse order. */ for (i = nr_desc; i-- > 0; ) { @@ -1694,14 +1719,13 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd goto err_unmap; } - wmb(); /* gq->cur must be incremented after die_dt was set */ - gq->cur = rswitch_next_queue_index(gq, true, nr_desc); rswitch_modify(rdev->addr, GWTRC(gq->index), 0, BIT(gq->index % 32)); return ret; err_unmap: + gq->skbs[(gq->cur + nr_desc - 1) % gq->ring_size] = NULL; dma_unmap_single(ndev->dev.parent, dma_addr_orig, skb->len, DMA_TO_DEVICE); err_kfree: @@ -1889,7 +1913,6 @@ static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index rdev->np_port = rswitch_get_port_node(rdev); rdev->disabled = !rdev->np_port; err = of_get_ethdev_address(rdev->np_port, ndev); - of_node_put(rdev->np_port); if (err) { if (is_valid_ether_addr(rdev->etha->mac_addr)) eth_hw_addr_set(ndev, rdev->etha->mac_addr); @@ -1919,6 +1942,7 @@ static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index out_rxdmac: out_get_params: + of_node_put(rdev->np_port); netif_napi_del(&rdev->napi); free_netdev(ndev); @@ -1932,6 +1956,7 @@ static void rswitch_device_free(struct rswitch_private *priv, unsigned int index rswitch_txdmac_free(ndev); rswitch_rxdmac_free(ndev); + of_node_put(rdev->np_port); netif_napi_del(&rdev->napi); free_netdev(ndev); } @@ -2188,7 +2213,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(renesas_eth_sw_pm_ops, renesas_eth_sw_suspend, static struct platform_driver renesas_eth_sw_driver_platform = { .probe = renesas_eth_sw_probe, - .remove_new = renesas_eth_sw_remove, + .remove = renesas_eth_sw_remove, .driver = { .name = "renesas_eth_sw", .pm = pm_sleep_ptr(&renesas_eth_sw_pm_ops), diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 72e3ff596d3183..d8d4ed7d7f8b6a 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -724,13 +724,13 @@ enum rswitch_etha_mode { #define EAVCC_VEM_SC_TAG (0x3 << 16) -#define MPIC_PIS_MII 0x00 -#define MPIC_PIS_GMII 0x02 -#define MPIC_PIS_XGMII 0x04 -#define MPIC_LSC_SHIFT 3 -#define MPIC_LSC_100M (1 << MPIC_LSC_SHIFT) -#define MPIC_LSC_1G (2 << MPIC_LSC_SHIFT) -#define MPIC_LSC_2_5G (3 << MPIC_LSC_SHIFT) +#define MPIC_PIS GENMASK(2, 0) +#define MPIC_PIS_GMII 2 +#define MPIC_PIS_XGMII 4 +#define MPIC_LSC GENMASK(5, 3) +#define MPIC_LSC_100M 1 +#define MPIC_LSC_1G 2 +#define MPIC_LSC_2_5G 3 #define MDIO_READ_C45 0x03 #define MDIO_WRITE_C45 0x01 @@ -972,14 +972,6 @@ struct rswitch_gwca_queue { }; }; -struct rswitch_gwca_ts_info { - struct sk_buff *skb; - struct list_head list; - - int port; - u8 tag; -}; - #define RSWITCH_NUM_IRQ_REGS (RSWITCH_MAX_NUM_QUEUES / BITS_PER_TYPE(u32)) struct rswitch_gwca { unsigned int index; @@ -989,7 +981,6 @@ struct rswitch_gwca { struct rswitch_gwca_queue *queues; int num_queues; struct rswitch_gwca_queue ts_queue; - struct list_head ts_info_list; DECLARE_BITMAP(used, RSWITCH_MAX_NUM_QUEUES); u32 tx_irq_bits[RSWITCH_NUM_IRQ_REGS]; u32 rx_irq_bits[RSWITCH_NUM_IRQ_REGS]; @@ -997,6 +988,7 @@ struct rswitch_gwca { }; #define NUM_QUEUES_PER_NDEV 2 +#define TS_TAGS_PER_PORT 256 struct rswitch_device { struct rswitch_private *priv; struct net_device *ndev; @@ -1004,7 +996,8 @@ struct rswitch_device { void __iomem *addr; struct rswitch_gwca_queue *tx_queue; struct rswitch_gwca_queue *rx_queue; - u8 ts_tag; + struct sk_buff *ts_skb[TS_TAGS_PER_PORT]; + DECLARE_BITMAP(ts_skb_used, TS_TAGS_PER_PORT); bool disabled; int port; diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 7a25903e35c305..8887b89210093b 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3560,7 +3560,7 @@ MODULE_DEVICE_TABLE(platform, sh_eth_id_table); static struct platform_driver sh_eth_driver = { .probe = sh_eth_drv_probe, - .remove_new = sh_eth_drv_remove, + .remove = sh_eth_drv_remove, .id_table = sh_eth_id_table, .driver = { .name = CARDNAME, diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 84fa911c78db55..fe0bf1d3217af2 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2502,7 +2502,7 @@ static void rocker_carrier_init(const struct rocker_port *rocker_port) u64 link_status = rocker_read64(rocker, PORT_PHYS_LINK_STATUS); bool link_up; - link_up = link_status & (1 << rocker_port->pport); + link_up = link_status & (1ULL << rocker_port->pport); if (link_up) netif_carrier_on(rocker_port->dev); else diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c index e6e130dbe1deb8..2eccc761750733 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c @@ -224,7 +224,7 @@ MODULE_DEVICE_TABLE(of, sxgbe_dt_ids); static struct platform_driver sxgbe_platform_driver = { .probe = sxgbe_platform_probe, - .remove_new = sxgbe_platform_remove, + .remove = sxgbe_platform_remove, .driver = { .name = SXGBE_RESOURCE_NAME, .pm = &sxgbe_platform_pm_ops, diff --git a/drivers/net/ethernet/seeq/sgiseeq.c b/drivers/net/ethernet/seeq/sgiseeq.c index 76356dadf233a9..7967a0ee320b7c 100644 --- a/drivers/net/ethernet/seeq/sgiseeq.c +++ b/drivers/net/ethernet/seeq/sgiseeq.c @@ -832,7 +832,7 @@ static void sgiseeq_remove(struct platform_device *pdev) static struct platform_driver sgiseeq_driver = { .probe = sgiseeq_probe, - .remove_new = sgiseeq_remove, + .remove = sgiseeq_remove, .driver = { .name = "sgiseeq", } diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index de131fc5fa0bbc..452009ed7a4356 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -1751,7 +1751,7 @@ static void efx_ef10_get_stat_mask(struct efx_nic *efx, unsigned long *mask) #endif } -static size_t efx_ef10_describe_stats(struct efx_nic *efx, u8 *names) +static size_t efx_ef10_describe_stats(struct efx_nic *efx, u8 **names) { DECLARE_BITMAP(mask, EF10_STAT_COUNT); diff --git a/drivers/net/ethernet/sfc/ef100_ethtool.c b/drivers/net/ethernet/sfc/ef100_ethtool.c index 5c2551369812cb..6c3b74000d3b6a 100644 --- a/drivers/net/ethernet/sfc/ef100_ethtool.c +++ b/drivers/net/ethernet/sfc/ef100_ethtool.c @@ -59,6 +59,7 @@ const struct ethtool_ops ef100_ethtool_ops = { .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, .get_rxfh_key_size = efx_ethtool_get_rxfh_key_size, .rxfh_per_ctx_key = true, + .cap_rss_rxnfc_adds = true, .rxfh_priv_size = sizeof(struct efx_rss_context_priv), .get_rxfh = efx_ethtool_get_rxfh, .set_rxfh = efx_ethtool_set_rxfh, diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c index 6da06931187d68..62e674d6ff60c7 100644 --- a/drivers/net/ethernet/sfc/ef100_nic.c +++ b/drivers/net/ethernet/sfc/ef100_nic.c @@ -583,7 +583,7 @@ static const struct efx_hw_stat_desc ef100_stat_desc[EF100_STAT_COUNT] = { EFX_GENERIC_SW_STAT(rx_noskb_drops), }; -static size_t ef100_describe_stats(struct efx_nic *efx, u8 *names) +static size_t ef100_describe_stats(struct efx_nic *efx, u8 **names) { DECLARE_BITMAP(mask, EF100_STAT_COUNT) = {}; diff --git a/drivers/net/ethernet/sfc/ef100_rx.c b/drivers/net/ethernet/sfc/ef100_rx.c index 83d9db71d7d7e8..44dc75feb1629e 100644 --- a/drivers/net/ethernet/sfc/ef100_rx.c +++ b/drivers/net/ethernet/sfc/ef100_rx.c @@ -134,6 +134,9 @@ void __ef100_rx_packet(struct efx_channel *channel) goto free_rx_buffer; } + ++rx_queue->rx_packets; + rx_queue->rx_bytes += rx_buf->len; + efx_rx_packet_gro(channel, rx_buf, channel->rx_pkt_n_frags, eh, csum); goto out; @@ -149,8 +152,6 @@ static void ef100_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index) struct efx_channel *channel = efx_rx_queue_channel(rx_queue); struct efx_nic *efx = rx_queue->efx; - ++rx_queue->rx_packets; - netif_vdbg(efx, rx_status, efx->net_dev, "RX queue %d received id %x\n", efx_rx_queue_index(rx_queue), index); diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 36b3b57e20558a..650136dfc642fd 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -22,6 +22,7 @@ #include "net_driver.h" #include #include +#include #include "efx.h" #include "efx_common.h" #include "efx_channels.h" @@ -417,14 +418,6 @@ unsigned int efx_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs) return usecs * 1000 / efx->timer_quantum_ns; } -unsigned int efx_ticks_to_usecs(struct efx_nic *efx, unsigned int ticks) -{ - /* We must round up when converting ticks to microseconds - * because we round down when converting the other way. - */ - return DIV_ROUND_UP(ticks * efx->timer_quantum_ns, 1000); -} - /* Set interrupt moderation parameters */ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, unsigned int rx_usecs, bool rx_adaptive, @@ -626,6 +619,113 @@ static const struct net_device_ops efx_netdev_ops = { .ndo_bpf = efx_xdp }; +static void efx_get_queue_stats_rx(struct net_device *net_dev, int idx, + struct netdev_queue_stats_rx *stats) +{ + struct efx_nic *efx = efx_netdev_priv(net_dev); + struct efx_rx_queue *rx_queue; + struct efx_channel *channel; + + channel = efx_get_channel(efx, idx); + rx_queue = efx_channel_get_rx_queue(channel); + /* Count only packets since last time datapath was started */ + stats->packets = rx_queue->rx_packets - rx_queue->old_rx_packets; + stats->bytes = rx_queue->rx_bytes - rx_queue->old_rx_bytes; + stats->hw_drops = efx_get_queue_stat_rx_hw_drops(channel) - + channel->old_n_rx_hw_drops; + stats->hw_drop_overruns = channel->n_rx_nodesc_trunc - + channel->old_n_rx_hw_drop_overruns; +} + +static void efx_get_queue_stats_tx(struct net_device *net_dev, int idx, + struct netdev_queue_stats_tx *stats) +{ + struct efx_nic *efx = efx_netdev_priv(net_dev); + struct efx_tx_queue *tx_queue; + struct efx_channel *channel; + + channel = efx_get_tx_channel(efx, idx); + stats->packets = 0; + stats->bytes = 0; + stats->hw_gso_packets = 0; + stats->hw_gso_wire_packets = 0; + efx_for_each_channel_tx_queue(tx_queue, channel) { + stats->packets += tx_queue->complete_packets - + tx_queue->old_complete_packets; + stats->bytes += tx_queue->complete_bytes - + tx_queue->old_complete_bytes; + /* Note that, unlike stats->packets and stats->bytes, + * these count TXes enqueued, rather than completed, + * which may not be what users expect. + */ + stats->hw_gso_packets += tx_queue->tso_bursts - + tx_queue->old_tso_bursts; + stats->hw_gso_wire_packets += tx_queue->tso_packets - + tx_queue->old_tso_packets; + } +} + +static void efx_get_base_stats(struct net_device *net_dev, + struct netdev_queue_stats_rx *rx, + struct netdev_queue_stats_tx *tx) +{ + struct efx_nic *efx = efx_netdev_priv(net_dev); + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + struct efx_channel *channel; + + rx->packets = 0; + rx->bytes = 0; + rx->hw_drops = 0; + rx->hw_drop_overruns = 0; + tx->packets = 0; + tx->bytes = 0; + tx->hw_gso_packets = 0; + tx->hw_gso_wire_packets = 0; + + /* Count all packets on non-core queues, and packets before last + * datapath start on core queues. + */ + efx_for_each_channel(channel, efx) { + rx_queue = efx_channel_get_rx_queue(channel); + if (channel->channel >= net_dev->real_num_rx_queues) { + rx->packets += rx_queue->rx_packets; + rx->bytes += rx_queue->rx_bytes; + rx->hw_drops += efx_get_queue_stat_rx_hw_drops(channel); + rx->hw_drop_overruns += channel->n_rx_nodesc_trunc; + } else { + rx->packets += rx_queue->old_rx_packets; + rx->bytes += rx_queue->old_rx_bytes; + rx->hw_drops += channel->old_n_rx_hw_drops; + rx->hw_drop_overruns += channel->old_n_rx_hw_drop_overruns; + } + efx_for_each_channel_tx_queue(tx_queue, channel) { + if (channel->channel < efx->tx_channel_offset || + channel->channel >= efx->tx_channel_offset + + net_dev->real_num_tx_queues) { + tx->packets += tx_queue->complete_packets; + tx->bytes += tx_queue->complete_bytes; + tx->hw_gso_packets += tx_queue->tso_bursts; + tx->hw_gso_wire_packets += tx_queue->tso_packets; + } else { + tx->packets += tx_queue->old_complete_packets; + tx->bytes += tx_queue->old_complete_bytes; + tx->hw_gso_packets += tx_queue->old_tso_bursts; + tx->hw_gso_wire_packets += tx_queue->old_tso_packets; + } + /* Include XDP TX in device-wide stats */ + tx->packets += tx_queue->complete_xdp_packets; + tx->bytes += tx_queue->complete_xdp_bytes; + } + } +} + +static const struct netdev_stat_ops efx_stat_ops = { + .get_queue_stats_rx = efx_get_queue_stats_rx, + .get_queue_stats_tx = efx_get_queue_stats_tx, + .get_base_stats = efx_get_base_stats, +}; + static int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog) { struct bpf_prog *old_prog; @@ -716,6 +816,7 @@ static int efx_register_netdev(struct efx_nic *efx) net_dev->watchdog_timeo = 5 * HZ; net_dev->irq = efx->pci_dev->irq; net_dev->netdev_ops = &efx_netdev_ops; + net_dev->stat_ops = &efx_stat_ops; if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) net_dev->priv_flags |= IFF_UNICAST_FLT; net_dev->ethtool_ops = &efx_ethtool_ops; diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 7a6cab883d66dc..45e1916866256a 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -168,7 +168,6 @@ extern const struct ethtool_ops efx_ethtool_ops; /* Global */ unsigned int efx_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs); -unsigned int efx_ticks_to_usecs(struct efx_nic *efx, unsigned int ticks); int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, unsigned int rx_usecs, bool rx_adaptive, bool rx_may_override_tx); diff --git a/drivers/net/ethernet/sfc/efx_channels.c b/drivers/net/ethernet/sfc/efx_channels.c index f1723a6fb082b4..06b4f52713ef3f 100644 --- a/drivers/net/ethernet/sfc/efx_channels.c +++ b/drivers/net/ethernet/sfc/efx_channels.c @@ -1100,6 +1100,10 @@ void efx_start_channels(struct efx_nic *efx) atomic_inc(&efx->active_queues); } + /* reset per-queue stats */ + channel->old_n_rx_hw_drops = efx_get_queue_stat_rx_hw_drops(channel); + channel->old_n_rx_hw_drop_overruns = channel->n_rx_nodesc_trunc; + efx_for_each_channel_rx_queue(rx_queue, channel) { efx_init_rx_queue(rx_queue); atomic_inc(&efx->active_queues); @@ -1209,6 +1213,8 @@ static int efx_process_channel(struct efx_channel *channel, int budget) tx_queue->pkts_compl, tx_queue->bytes_compl); } + tx_queue->complete_packets += tx_queue->pkts_compl; + tx_queue->complete_bytes += tx_queue->bytes_compl; } /* Receive any packets we queued up */ diff --git a/drivers/net/ethernet/sfc/efx_channels.h b/drivers/net/ethernet/sfc/efx_channels.h index 46b702648721e5..547cf94014a31f 100644 --- a/drivers/net/ethernet/sfc/efx_channels.h +++ b/drivers/net/ethernet/sfc/efx_channels.h @@ -43,6 +43,13 @@ struct efx_channel *efx_copy_channel(const struct efx_channel *old_channel); void efx_start_channels(struct efx_nic *efx); void efx_stop_channels(struct efx_nic *efx); +static inline u64 efx_get_queue_stat_rx_hw_drops(struct efx_channel *channel) +{ + return channel->n_rx_eth_crc_err + channel->n_rx_frm_trunc + + channel->n_rx_overlength + channel->n_rx_nodesc_trunc + + channel->n_rx_mport_bad; +} + void efx_init_napi_channel(struct efx_channel *channel); void efx_init_napi(struct efx_nic *efx); void efx_fini_napi_channel(struct efx_channel *channel); diff --git a/drivers/net/ethernet/sfc/efx_common.c b/drivers/net/ethernet/sfc/efx_common.c index 13cf647051af05..c88ec3e2483621 100644 --- a/drivers/net/ethernet/sfc/efx_common.c +++ b/drivers/net/ethernet/sfc/efx_common.c @@ -635,22 +635,6 @@ int __efx_reconfigure_port(struct efx_nic *efx) return rc; } -/* Reinitialise the MAC to pick up new PHY settings, even if the port is - * disabled. - */ -int efx_reconfigure_port(struct efx_nic *efx) -{ - int rc; - - EFX_ASSERT_RESET_SERIALISED(efx); - - mutex_lock(&efx->mac_lock); - rc = __efx_reconfigure_port(efx); - mutex_unlock(&efx->mac_lock); - - return rc; -} - /************************************************************************** * * Device reset and suspend diff --git a/drivers/net/ethernet/sfc/efx_common.h b/drivers/net/ethernet/sfc/efx_common.h index 2c54dac3e66245..19a8ca530969b7 100644 --- a/drivers/net/ethernet/sfc/efx_common.h +++ b/drivers/net/ethernet/sfc/efx_common.h @@ -40,7 +40,6 @@ void efx_destroy_reset_workqueue(void); void efx_start_monitor(struct efx_nic *efx); int __efx_reconfigure_port(struct efx_nic *efx); -int efx_reconfigure_port(struct efx_nic *efx); #define EFX_ASSERT_RESET_SERIALISED(efx) \ do { \ diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index bb1930818beba4..83d715544f7fb2 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -263,6 +263,7 @@ const struct ethtool_ops efx_ethtool_ops = { .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, .get_rxfh_key_size = efx_ethtool_get_rxfh_key_size, .rxfh_per_ctx_key = true, + .cap_rss_rxnfc_adds = true, .rxfh_priv_size = sizeof(struct efx_rss_context_priv), .get_rxfh = efx_ethtool_get_rxfh, .set_rxfh = efx_ethtool_set_rxfh, diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c index 6ded44b860522b..2d734496733fad 100644 --- a/drivers/net/ethernet/sfc/ethtool_common.c +++ b/drivers/net/ethernet/sfc/ethtool_common.c @@ -75,7 +75,6 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { EFX_ETHTOOL_UINT_TXQ_STAT(pio_packets), EFX_ETHTOOL_UINT_TXQ_STAT(cb_packets), EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset), - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_inner_ip_hdr_chksum_err), @@ -83,8 +82,8 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_outer_ip_hdr_chksum_err), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_outer_tcp_udp_chksum_err), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_eth_crc_err), - EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_overlength), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_events), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_packets), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_drops), @@ -396,7 +395,7 @@ int efx_ethtool_fill_self_tests(struct efx_nic *efx, return n; } -static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) +static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 **strings) { size_t n_stats = 0; struct efx_channel *channel; @@ -404,24 +403,22 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) efx_for_each_channel(channel, efx) { if (efx_channel_has_tx_queues(channel)) { n_stats++; - if (strings != NULL) { - snprintf(strings, ETH_GSTRING_LEN, - "tx-%u.tx_packets", - channel->tx_queue[0].queue / - EFX_MAX_TXQ_PER_CHANNEL); + if (!strings) + continue; - strings += ETH_GSTRING_LEN; - } + ethtool_sprintf(strings, "tx-%u.tx_packets", + channel->tx_queue[0].queue / + EFX_MAX_TXQ_PER_CHANNEL); } } efx_for_each_channel(channel, efx) { if (efx_channel_has_rx_queue(channel)) { n_stats++; - if (strings != NULL) { - snprintf(strings, ETH_GSTRING_LEN, - "rx-%d.rx_packets", channel->channel); - strings += ETH_GSTRING_LEN; - } + if (!strings) + continue; + + ethtool_sprintf(strings, "rx-%d.rx_packets", + channel->channel); } } if (efx->xdp_tx_queue_count && efx->xdp_tx_queues) { @@ -429,11 +426,11 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) for (xdp = 0; xdp < efx->xdp_tx_queue_count; xdp++) { n_stats++; - if (strings) { - snprintf(strings, ETH_GSTRING_LEN, - "tx-xdp-cpu-%hu.tx_packets", xdp); - strings += ETH_GSTRING_LEN; - } + if (!strings) + continue; + + ethtool_sprintf(strings, "tx-xdp-cpu-%hu.tx_packets", + xdp); } } @@ -465,15 +462,11 @@ void efx_ethtool_get_strings(struct net_device *net_dev, switch (string_set) { case ETH_SS_STATS: - strings += (efx->type->describe_stats(efx, strings) * - ETH_GSTRING_LEN); + efx->type->describe_stats(efx, &strings); for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++) - strscpy(strings + i * ETH_GSTRING_LEN, - efx_sw_stat_desc[i].name, ETH_GSTRING_LEN); - strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN; - strings += (efx_describe_per_queue_stats(efx, strings) * - ETH_GSTRING_LEN); - efx_ptp_describe_stats(efx, strings); + ethtool_puts(&strings, efx_sw_stat_desc[i].name); + efx_describe_per_queue_stats(efx, &strings); + efx_ptp_describe_stats(efx, &strings); break; case ETH_SS_TEST: efx_ethtool_fill_self_tests(efx, NULL, strings, NULL); diff --git a/drivers/net/ethernet/sfc/falcon/efx.c b/drivers/net/ethernet/sfc/falcon/efx.c index 8925745f1c17f7..b07f7e4e287775 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.c +++ b/drivers/net/ethernet/sfc/falcon/efx.c @@ -1886,14 +1886,6 @@ unsigned int ef4_usecs_to_ticks(struct ef4_nic *efx, unsigned int usecs) return usecs * 1000 / efx->timer_quantum_ns; } -unsigned int ef4_ticks_to_usecs(struct ef4_nic *efx, unsigned int ticks) -{ - /* We must round up when converting ticks to microseconds - * because we round down when converting the other way. - */ - return DIV_ROUND_UP(ticks * efx->timer_quantum_ns, 1000); -} - /* Set interrupt moderation parameters */ int ef4_init_irq_moderation(struct ef4_nic *efx, unsigned int tx_usecs, unsigned int rx_usecs, bool rx_adaptive, diff --git a/drivers/net/ethernet/sfc/falcon/efx.h b/drivers/net/ethernet/sfc/falcon/efx.h index d3b4646545fae8..52508f2c8cb26d 100644 --- a/drivers/net/ethernet/sfc/falcon/efx.h +++ b/drivers/net/ethernet/sfc/falcon/efx.h @@ -198,7 +198,6 @@ int ef4_try_recovery(struct ef4_nic *efx); /* Global */ void ef4_schedule_reset(struct ef4_nic *efx, enum reset_type type); unsigned int ef4_usecs_to_ticks(struct ef4_nic *efx, unsigned int usecs); -unsigned int ef4_ticks_to_usecs(struct ef4_nic *efx, unsigned int ticks); int ef4_init_irq_moderation(struct ef4_nic *efx, unsigned int tx_usecs, unsigned int rx_usecs, bool rx_adaptive, bool rx_may_override_tx); diff --git a/drivers/net/ethernet/sfc/falcon/ethtool.c b/drivers/net/ethernet/sfc/falcon/ethtool.c index f4db683b80f7ce..04766448a54585 100644 --- a/drivers/net/ethernet/sfc/falcon/ethtool.c +++ b/drivers/net/ethernet/sfc/falcon/ethtool.c @@ -353,7 +353,7 @@ static int ef4_ethtool_fill_self_tests(struct ef4_nic *efx, return n; } -static size_t ef4_describe_per_queue_stats(struct ef4_nic *efx, u8 *strings) +static size_t ef4_describe_per_queue_stats(struct ef4_nic *efx, u8 **strings) { size_t n_stats = 0; struct ef4_channel *channel; @@ -361,24 +361,22 @@ static size_t ef4_describe_per_queue_stats(struct ef4_nic *efx, u8 *strings) ef4_for_each_channel(channel, efx) { if (ef4_channel_has_tx_queues(channel)) { n_stats++; - if (strings != NULL) { - snprintf(strings, ETH_GSTRING_LEN, - "tx-%u.tx_packets", - channel->tx_queue[0].queue / - EF4_TXQ_TYPES); + if (!strings) + continue; - strings += ETH_GSTRING_LEN; - } + ethtool_sprintf(strings, "tx-%u.tx_packets", + channel->tx_queue[0].queue / + EF4_TXQ_TYPES); } } ef4_for_each_channel(channel, efx) { if (ef4_channel_has_rx_queue(channel)) { n_stats++; - if (strings != NULL) { - snprintf(strings, ETH_GSTRING_LEN, - "rx-%d.rx_packets", channel->channel); - strings += ETH_GSTRING_LEN; - } + if (!strings) + continue; + + ethtool_sprintf(strings, "rx-%d.rx_packets", + channel->channel); } } return n_stats; @@ -409,14 +407,10 @@ static void ef4_ethtool_get_strings(struct net_device *net_dev, switch (string_set) { case ETH_SS_STATS: - strings += (efx->type->describe_stats(efx, strings) * - ETH_GSTRING_LEN); + efx->type->describe_stats(efx, &strings); for (i = 0; i < EF4_ETHTOOL_SW_STAT_COUNT; i++) - strscpy(strings + i * ETH_GSTRING_LEN, - ef4_sw_stat_desc[i].name, ETH_GSTRING_LEN); - strings += EF4_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN; - strings += (ef4_describe_per_queue_stats(efx, strings) * - ETH_GSTRING_LEN); + ethtool_puts(&strings, ef4_sw_stat_desc[i].name); + ef4_describe_per_queue_stats(efx, &strings); break; case ETH_SS_TEST: ef4_ethtool_fill_self_tests(efx, NULL, strings, NULL); diff --git a/drivers/net/ethernet/sfc/falcon/falcon.c b/drivers/net/ethernet/sfc/falcon/falcon.c index 36114ce88034cb..4af56333ea49ab 100644 --- a/drivers/net/ethernet/sfc/falcon/falcon.c +++ b/drivers/net/ethernet/sfc/falcon/falcon.c @@ -2564,7 +2564,7 @@ static void falcon_remove_nic(struct ef4_nic *efx) efx->nic_data = NULL; } -static size_t falcon_describe_nic_stats(struct ef4_nic *efx, u8 *names) +static size_t falcon_describe_nic_stats(struct ef4_nic *efx, u8 **names) { return ef4_nic_describe_stats(falcon_stat_desc, FALCON_STAT_COUNT, falcon_stat_mask, names); diff --git a/drivers/net/ethernet/sfc/falcon/farch.c b/drivers/net/ethernet/sfc/falcon/farch.c index c64623c2e80c9b..01017c41338ebe 100644 --- a/drivers/net/ethernet/sfc/falcon/farch.c +++ b/drivers/net/ethernet/sfc/falcon/farch.c @@ -1631,28 +1631,6 @@ void ef4_farch_rx_push_indir_table(struct ef4_nic *efx) } } -/* Looks at available SRAM resources and works out how many queues we - * can support, and where things like descriptor caches should live. - * - * SRAM is split up as follows: - * 0 buftbl entries for channels - * efx->vf_buftbl_base buftbl entries for SR-IOV - * efx->rx_dc_base RX descriptor caches - * efx->tx_dc_base TX descriptor caches - */ -void ef4_farch_dimension_resources(struct ef4_nic *efx, unsigned sram_lim_qw) -{ - unsigned vi_count; - - /* Account for the buffer table entries backing the datapath channels - * and the descriptor caches for those channels. - */ - vi_count = max(efx->n_channels, efx->n_tx_channels * EF4_TXQ_TYPES); - - efx->tx_dc_base = sram_lim_qw - vi_count * TX_DC_ENTRIES; - efx->rx_dc_base = efx->tx_dc_base - vi_count * RX_DC_ENTRIES; -} - u32 ef4_farch_fpga_ver(struct ef4_nic *efx) { ef4_oword_t altera_build; diff --git a/drivers/net/ethernet/sfc/falcon/net_driver.h b/drivers/net/ethernet/sfc/falcon/net_driver.h index a2c7139f2b323f..7ab0db44720da7 100644 --- a/drivers/net/ethernet/sfc/falcon/net_driver.h +++ b/drivers/net/ethernet/sfc/falcon/net_driver.h @@ -1057,7 +1057,7 @@ struct ef4_nic_type { void (*finish_flush)(struct ef4_nic *efx); void (*prepare_flr)(struct ef4_nic *efx); void (*finish_flr)(struct ef4_nic *efx); - size_t (*describe_stats)(struct ef4_nic *efx, u8 *names); + size_t (*describe_stats)(struct ef4_nic *efx, u8 **names); size_t (*update_stats)(struct ef4_nic *efx, u64 *full_stats, struct rtnl_link_stats64 *core_stats); void (*start_stats)(struct ef4_nic *efx); diff --git a/drivers/net/ethernet/sfc/falcon/nic.c b/drivers/net/ethernet/sfc/falcon/nic.c index 78c851b5a56f21..a6304686bc900f 100644 --- a/drivers/net/ethernet/sfc/falcon/nic.c +++ b/drivers/net/ethernet/sfc/falcon/nic.c @@ -444,18 +444,15 @@ void ef4_nic_get_regs(struct ef4_nic *efx, void *buf) * bits in the first @count bits of @mask for which a name is defined. */ size_t ef4_nic_describe_stats(const struct ef4_hw_stat_desc *desc, size_t count, - const unsigned long *mask, u8 *names) + const unsigned long *mask, u8 **names) { size_t visible = 0; size_t index; for_each_set_bit(index, mask, count) { if (desc[index].name) { - if (names) { - strscpy(names, desc[index].name, - ETH_GSTRING_LEN); - names += ETH_GSTRING_LEN; - } + if (names) + ethtool_puts(names, desc[index].name); ++visible; } } @@ -511,14 +508,3 @@ void ef4_nic_update_stats(const struct ef4_hw_stat_desc *desc, size_t count, } } } - -void ef4_nic_fix_nodesc_drop_stat(struct ef4_nic *efx, u64 *rx_nodesc_drops) -{ - /* if down, or this is the first update after coming up */ - if (!(efx->net_dev->flags & IFF_UP) || !efx->rx_nodesc_drops_prev_state) - efx->rx_nodesc_drops_while_down += - *rx_nodesc_drops - efx->rx_nodesc_drops_total; - efx->rx_nodesc_drops_total = *rx_nodesc_drops; - efx->rx_nodesc_drops_prev_state = !!(efx->net_dev->flags & IFF_UP); - *rx_nodesc_drops -= efx->rx_nodesc_drops_while_down; -} diff --git a/drivers/net/ethernet/sfc/falcon/nic.h b/drivers/net/ethernet/sfc/falcon/nic.h index ada6e036fd9728..bc6ef937d0fe58 100644 --- a/drivers/net/ethernet/sfc/falcon/nic.h +++ b/drivers/net/ethernet/sfc/falcon/nic.h @@ -477,7 +477,6 @@ void ef4_farch_finish_flr(struct ef4_nic *efx); void falcon_start_nic_stats(struct ef4_nic *efx); void falcon_stop_nic_stats(struct ef4_nic *efx); int falcon_reset_xaui(struct ef4_nic *efx); -void ef4_farch_dimension_resources(struct ef4_nic *efx, unsigned sram_lim_qw); void ef4_farch_init_common(struct ef4_nic *efx); void ef4_farch_rx_push_indir_table(struct ef4_nic *efx); @@ -498,14 +497,10 @@ size_t ef4_nic_get_regs_len(struct ef4_nic *efx); void ef4_nic_get_regs(struct ef4_nic *efx, void *buf); size_t ef4_nic_describe_stats(const struct ef4_hw_stat_desc *desc, size_t count, - const unsigned long *mask, u8 *names); + const unsigned long *mask, u8 **names); void ef4_nic_update_stats(const struct ef4_hw_stat_desc *desc, size_t count, const unsigned long *mask, u64 *stats, const void *dma_buf, bool accumulate); -void ef4_nic_fix_nodesc_drop_stat(struct ef4_nic *efx, u64 *stat); - -#define EF4_MAX_FLUSH_TIME 5000 - void ef4_farch_generate_event(struct ef4_nic *efx, unsigned int evq, ef4_qword_t *event); diff --git a/drivers/net/ethernet/sfc/falcon/tx.c b/drivers/net/ethernet/sfc/falcon/tx.c index b9369483758cd6..e6e80b039ca212 100644 --- a/drivers/net/ethernet/sfc/falcon/tx.c +++ b/drivers/net/ethernet/sfc/falcon/tx.c @@ -40,14 +40,6 @@ static inline u8 *ef4_tx_get_copy_buffer(struct ef4_tx_queue *tx_queue, return (u8 *)page_buf->addr + offset; } -u8 *ef4_tx_get_copy_buffer_limited(struct ef4_tx_queue *tx_queue, - struct ef4_tx_buffer *buffer, size_t len) -{ - if (len > EF4_TX_CB_SIZE) - return NULL; - return ef4_tx_get_copy_buffer(tx_queue, buffer); -} - static void ef4_dequeue_buffer(struct ef4_tx_queue *tx_queue, struct ef4_tx_buffer *buffer, unsigned int *pkts_compl, diff --git a/drivers/net/ethernet/sfc/falcon/tx.h b/drivers/net/ethernet/sfc/falcon/tx.h index 2a88c59cbbbe5e..868ed8a861abba 100644 --- a/drivers/net/ethernet/sfc/falcon/tx.h +++ b/drivers/net/ethernet/sfc/falcon/tx.h @@ -15,9 +15,6 @@ unsigned int ef4_tx_limit_len(struct ef4_tx_queue *tx_queue, dma_addr_t dma_addr, unsigned int len); -u8 *ef4_tx_get_copy_buffer_limited(struct ef4_tx_queue *tx_queue, - struct ef4_tx_buffer *buffer, size_t len); - int ef4_enqueue_skb_tso(struct ef4_tx_queue *tx_queue, struct sk_buff *skb, bool *data_mapped); diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c index 10709d828a636d..50f097487b140b 100644 --- a/drivers/net/ethernet/sfc/mae.c +++ b/drivers/net/ethernet/sfc/mae.c @@ -76,17 +76,6 @@ void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out) *out = EFX_DWORD_VAL(mport); } -void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out) -{ - efx_dword_t mport; - - EFX_POPULATE_DWORD_3(mport, - MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC, - MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER, - MAE_MPORT_SELECTOR_FUNC_VF_ID, vf_id); - *out = EFX_DWORD_VAL(mport); -} - /* Constructs an mport selector from an mport ID, because they're not the same */ void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out) { diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h index 8df30bc4f3ba73..db79912c86d8ce 100644 --- a/drivers/net/ethernet/sfc/mae.h +++ b/drivers/net/ethernet/sfc/mae.h @@ -23,7 +23,6 @@ int efx_mae_free_mport(struct efx_nic *efx, u32 id); void efx_mae_mport_wire(struct efx_nic *efx, u32 *out); void efx_mae_mport_uplink(struct efx_nic *efx, u32 *out); -void efx_mae_mport_vf(struct efx_nic *efx, u32 vf_id, u32 *out); void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out); int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id); diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 76578502226ed5..d461b1a6ce810d 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1051,15 +1051,6 @@ efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd, cookie, false); } -int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd, - const efx_dword_t *inbuf, size_t inlen, - size_t outlen, efx_mcdi_async_completer *complete, - unsigned long cookie) -{ - return _efx_mcdi_rpc_async(efx, cmd, inbuf, inlen, outlen, complete, - cookie, true); -} - int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, efx_dword_t *outbuf, size_t outlen, size_t *outlen_actual) @@ -1068,14 +1059,6 @@ int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, outlen_actual, false, NULL, NULL); } -int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen, - efx_dword_t *outbuf, size_t outlen, - size_t *outlen_actual) -{ - return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen, - outlen_actual, true, NULL, NULL); -} - void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd, size_t inlen, efx_dword_t *outbuf, size_t outlen, int rc) @@ -1982,33 +1965,6 @@ efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out) } -int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out) -{ - MCDI_DECLARE_BUF(outbuf, MC_CMD_WOL_FILTER_GET_OUT_LEN); - size_t outlen; - int rc; - - rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0, - outbuf, sizeof(outbuf), &outlen); - if (rc) - goto fail; - - if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) { - rc = -EIO; - goto fail; - } - - *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID); - - return 0; - -fail: - *id_out = -1; - netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); - return rc; -} - - int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id) { MCDI_DECLARE_BUF(inbuf, MC_CMD_WOL_FILTER_REMOVE_IN_LEN); @@ -2021,38 +1977,6 @@ int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id) return rc; } -int efx_mcdi_flush_rxqs(struct efx_nic *efx) -{ - struct efx_channel *channel; - struct efx_rx_queue *rx_queue; - MCDI_DECLARE_BUF(inbuf, - MC_CMD_FLUSH_RX_QUEUES_IN_LEN(EFX_MAX_CHANNELS)); - int rc, count; - - BUILD_BUG_ON(EFX_MAX_CHANNELS > - MC_CMD_FLUSH_RX_QUEUES_IN_QID_OFST_MAXNUM); - - count = 0; - efx_for_each_channel(channel, efx) { - efx_for_each_channel_rx_queue(rx_queue, channel) { - if (rx_queue->flush_pending) { - rx_queue->flush_pending = false; - atomic_dec(&efx->rxq_flush_pending); - MCDI_SET_ARRAY_DWORD( - inbuf, FLUSH_RX_QUEUES_IN_QID_OFST, - count, efx_rx_queue_index(rx_queue)); - count++; - } - } - } - - rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, inbuf, - MC_CMD_FLUSH_RX_QUEUES_IN_LEN(count), NULL, 0, NULL); - WARN_ON(rc < 0); - - return rc; -} - int efx_mcdi_wol_filter_reset(struct efx_nic *efx) { int rc; diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index ea612c61987426..cdb17d7c147fcd 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h @@ -155,9 +155,6 @@ int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd, int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, efx_dword_t *outbuf, size_t outlen, size_t *outlen_actual); -int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, - size_t inlen, efx_dword_t *outbuf, - size_t outlen, size_t *outlen_actual); typedef void efx_mcdi_async_completer(struct efx_nic *efx, unsigned long cookie, int rc, @@ -167,11 +164,6 @@ int efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd, const efx_dword_t *inbuf, size_t inlen, size_t outlen, efx_mcdi_async_completer *complete, unsigned long cookie); -int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd, - const efx_dword_t *inbuf, size_t inlen, - size_t outlen, - efx_mcdi_async_completer *complete, - unsigned long cookie); void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd, size_t inlen, efx_dword_t *outbuf, @@ -410,10 +402,8 @@ int efx_mcdi_handle_assertion(struct efx_nic *efx); int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out); -int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); int efx_mcdi_wol_filter_reset(struct efx_nic *efx); -int efx_mcdi_flush_rxqs(struct efx_nic *efx); void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev); void efx_mcdi_mac_start_stats(struct efx_nic *efx); void efx_mcdi_mac_stop_stats(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index b85c51cbe7f977..620ba6ef3514bd 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -193,6 +193,12 @@ struct efx_tx_buffer { * @initialised: Has hardware queue been initialised? * @timestamping: Is timestamping enabled for this channel? * @xdp_tx: Is this an XDP tx queue? + * @old_complete_packets: Value of @complete_packets as of last + * efx_init_tx_queue() + * @old_complete_bytes: Value of @complete_bytes as of last + * efx_init_tx_queue() + * @old_tso_bursts: Value of @tso_bursts as of last efx_init_tx_queue() + * @old_tso_packets: Value of @tso_packets as of last efx_init_tx_queue() * @read_count: Current read pointer. * This is the number of buffers that have been removed from both rings. * @old_write_count: The value of @write_count when last checked. @@ -202,6 +208,20 @@ struct efx_tx_buffer { * avoid cache-line ping-pong between the xmit path and the * completion path. * @merge_events: Number of TX merged completion events + * @bytes_compl: Number of bytes completed during this NAPI poll + * (efx_process_channel()). For BQL. + * @pkts_compl: Number of packets completed during this NAPI poll. + * @complete_packets: Number of packets completed since this struct was + * created. Only counts SKB packets, not XDP TX (it accumulates + * the same values that are reported to BQL). + * @complete_bytes: Number of bytes completed since this struct was + * created. For TSO, counts the superframe size, not the sizes of + * generated frames on the wire (i.e. the headers are only counted + * once) + * @complete_xdp_packets: Number of XDP TX packets completed since this + * struct was created. + * @complete_xdp_bytes: Number of XDP TX bytes completed since this + * struct was created. * @completed_timestamp_major: Top part of the most recent tx timestamp. * @completed_timestamp_minor: Low part of the most recent tx timestamp. * @insert_count: Current insert pointer @@ -232,6 +252,7 @@ struct efx_tx_buffer { * @xmit_pending: Are any packets waiting to be pushed to the NIC * @cb_packets: Number of times the TX copybreak feature has been used * @notify_count: Count of notified descriptors to the NIC + * @tx_packets: Number of packets sent since this struct was created * @empty_read_count: If the completion path has seen the queue as empty * and the transmission path has not yet checked this, the value of * @read_count bitwise-added to %EFX_EMPTY_COUNT_VALID; otherwise 0. @@ -255,6 +276,10 @@ struct efx_tx_queue { bool initialised; bool timestamping; bool xdp_tx; + unsigned long old_complete_packets; + unsigned long old_complete_bytes; + unsigned int old_tso_bursts; + unsigned int old_tso_packets; /* Members used mainly on the completion path */ unsigned int read_count ____cacheline_aligned_in_smp; @@ -262,6 +287,10 @@ struct efx_tx_queue { unsigned int merge_events; unsigned int bytes_compl; unsigned int pkts_compl; + unsigned long complete_packets; + unsigned long complete_bytes; + unsigned long complete_xdp_packets; + unsigned long complete_xdp_bytes; u32 completed_timestamp_major; u32 completed_timestamp_minor; @@ -370,6 +399,10 @@ struct efx_rx_page_state { * @recycle_count: RX buffer recycle counter. * @slow_fill: Timer used to defer efx_nic_generate_fill_event(). * @grant_work: workitem used to grant credits to the MAE if @grant_credits + * @rx_packets: Number of packets received since this struct was created + * @rx_bytes: Number of bytes received since this struct was created + * @old_rx_packets: Value of @rx_packets as of last efx_init_rx_queue() + * @old_rx_bytes: Value of @rx_bytes as of last efx_init_rx_queue() * @xdp_rxq_info: XDP specific RX queue information. * @xdp_rxq_info_valid: Is xdp_rxq_info valid data?. */ @@ -406,6 +439,9 @@ struct efx_rx_queue { struct work_struct grant_work; /* Statistics to supplement MAC stats */ unsigned long rx_packets; + unsigned long rx_bytes; + unsigned long old_rx_packets; + unsigned long old_rx_bytes; struct xdp_rxq_info xdp_rxq_info; bool xdp_rxq_info_valid; }; @@ -451,10 +487,8 @@ enum efx_sync_events_state { * @filter_work: Work item for efx_filter_rfs_expire() * @rps_flow_id: Flow IDs of filters allocated for accelerated RFS, * indexed by filter ID - * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors - * @n_rx_mcast_mismatch: Count of unmatched multicast frames * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors * @n_rx_overlength: Count of RX_OVERLENGTH errors * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun @@ -468,6 +502,10 @@ enum efx_sync_events_state { * @n_rx_xdp_redirect: Count of RX packets redirected to a different NIC by XDP * @n_rx_mport_bad: Count of RX packets dropped because their ingress mport was * not recognised + * @old_n_rx_hw_drops: Count of all RX packets dropped for any reason as of last + * efx_start_channels() + * @old_n_rx_hw_drop_overruns: Value of @n_rx_nodesc_trunc as of last + * efx_start_channels() * @rx_pkt_n_frags: Number of fragments in next packet to be delivered by * __efx_rx_packet(), or zero if there is none * @rx_pkt_index: Ring index of first buffer for next packet to be delivered @@ -511,7 +549,6 @@ struct efx_channel { u32 *rps_flow_id; #endif - unsigned int n_rx_tobe_disc; unsigned int n_rx_ip_hdr_chksum_err; unsigned int n_rx_tcp_udp_chksum_err; unsigned int n_rx_outer_ip_hdr_chksum_err; @@ -519,7 +556,6 @@ struct efx_channel { unsigned int n_rx_inner_ip_hdr_chksum_err; unsigned int n_rx_inner_tcp_udp_chksum_err; unsigned int n_rx_eth_crc_err; - unsigned int n_rx_mcast_mismatch; unsigned int n_rx_frm_trunc; unsigned int n_rx_overlength; unsigned int n_skbuff_leaks; @@ -532,6 +568,9 @@ struct efx_channel { unsigned int n_rx_xdp_redirect; unsigned int n_rx_mport_bad; + unsigned int old_n_rx_hw_drops; + unsigned int old_n_rx_hw_drop_overruns; + unsigned int rx_pkt_n_frags; unsigned int rx_pkt_index; @@ -1369,7 +1408,7 @@ struct efx_nic_type { int (*fini_dmaq)(struct efx_nic *efx); void (*prepare_flr)(struct efx_nic *efx); void (*finish_flr)(struct efx_nic *efx); - size_t (*describe_stats)(struct efx_nic *efx, u8 *names); + size_t (*describe_stats)(struct efx_nic *efx, u8 **names); size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats, struct rtnl_link_stats64 *core_stats); size_t (*update_stats_atomic)(struct efx_nic *efx, u64 *full_stats, diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index a33ed473cc8af8..80aa5e9c732ae0 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -299,18 +299,15 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf) * bits in the first @count bits of @mask for which a name is defined. */ size_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count, - const unsigned long *mask, u8 *names) + const unsigned long *mask, u8 **names) { size_t visible = 0; size_t index; for_each_set_bit(index, mask, count) { if (desc[index].name) { - if (names) { - strscpy(names, desc[index].name, - ETH_GSTRING_LEN); - names += ETH_GSTRING_LEN; - } + if (names) + ethtool_puts(names, desc[index].name); ++visible; } } diff --git a/drivers/net/ethernet/sfc/nic_common.h b/drivers/net/ethernet/sfc/nic_common.h index 7ec4ac7b7ff5c5..821d91efda1954 100644 --- a/drivers/net/ethernet/sfc/nic_common.h +++ b/drivers/net/ethernet/sfc/nic_common.h @@ -241,7 +241,7 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf); #define EFX_MC_STATS_GENERATION_INVALID ((__force __le64)(-1)) size_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count, - const unsigned long *mask, u8 *names); + const unsigned long *mask, u8 **names); int efx_nic_copy_stats(struct efx_nic *efx, __le64 *dest); void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count, const unsigned long *mask, u64 *stats, diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index aaacdcfa54ae11..4c7222bf26bec8 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -399,7 +399,7 @@ static const unsigned long efx_ptp_stat_mask[] = { [0 ... BITS_TO_LONGS(PTP_STAT_COUNT) - 1] = ~0UL, }; -size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 *strings) +size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 **strings) { if (!efx->ptp_data) return 0; @@ -1800,11 +1800,6 @@ int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb) return NETDEV_TX_OK; } -int efx_ptp_get_mode(struct efx_nic *efx) -{ - return efx->ptp_data->mode; -} - int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, unsigned int new_mode) { diff --git a/drivers/net/ethernet/sfc/ptp.h b/drivers/net/ethernet/sfc/ptp.h index 6946203499ef1e..cb9b077921e84f 100644 --- a/drivers/net/ethernet/sfc/ptp.h +++ b/drivers/net/ethernet/sfc/ptp.h @@ -26,12 +26,11 @@ int efx_ptp_get_ts_config(struct efx_nic *efx, void efx_ptp_get_ts_info(struct efx_nic *efx, struct kernel_ethtool_ts_info *ts_info); bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); -int efx_ptp_get_mode(struct efx_nic *efx); int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, unsigned int new_mode); int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev); -size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 *strings); +size_t efx_ptp_describe_stats(struct efx_nic *efx, u8 **strings); size_t efx_ptp_update_stats(struct efx_nic *efx, u64 *stats); void efx_time_sync_event(struct efx_channel *channel, efx_qword_t *ev); void __efx_rx_skb_attach_timestamp(struct efx_channel *channel, diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index f77a2d3ef37eca..ffca82207e4736 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -125,8 +125,6 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index, struct efx_channel *channel = efx_rx_queue_channel(rx_queue); struct efx_rx_buffer *rx_buf; - rx_queue->rx_packets++; - rx_buf = efx_rx_buffer(rx_queue, index); rx_buf->flags |= flags; @@ -394,6 +392,9 @@ void __efx_rx_packet(struct efx_channel *channel) goto out; } + rx_queue->rx_packets++; + rx_queue->rx_bytes += rx_buf->len; + if (!efx_do_xdp(efx, channel, rx_buf, &eh)) goto out; diff --git a/drivers/net/ethernet/sfc/rx_common.c b/drivers/net/ethernet/sfc/rx_common.c index 0b7dc75c40f927..ab358fe13e1df0 100644 --- a/drivers/net/ethernet/sfc/rx_common.c +++ b/drivers/net/ethernet/sfc/rx_common.c @@ -241,6 +241,9 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) rx_queue->page_recycle_failed = 0; rx_queue->page_recycle_full = 0; + rx_queue->old_rx_packets = rx_queue->rx_packets; + rx_queue->old_rx_bytes = rx_queue->rx_bytes; + /* Initialise limit fields */ max_fill = efx->rxq_entries - EFX_RXD_HEAD_ROOM; max_trigger = diff --git a/drivers/net/ethernet/sfc/siena/ethtool_common.c b/drivers/net/ethernet/sfc/siena/ethtool_common.c index 075fef64de680c..eeee676fdca7d1 100644 --- a/drivers/net/ethernet/sfc/siena/ethtool_common.c +++ b/drivers/net/ethernet/sfc/siena/ethtool_common.c @@ -395,7 +395,7 @@ void efx_siena_ethtool_self_test(struct net_device *net_dev, test->flags |= ETH_TEST_FL_FAILED; } -static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) +static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 **strings) { size_t n_stats = 0; struct efx_channel *channel; @@ -403,24 +403,22 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) efx_for_each_channel(channel, efx) { if (efx_channel_has_tx_queues(channel)) { n_stats++; - if (strings != NULL) { - snprintf(strings, ETH_GSTRING_LEN, - "tx-%u.tx_packets", - channel->tx_queue[0].queue / - EFX_MAX_TXQ_PER_CHANNEL); + if (!strings) + continue; - strings += ETH_GSTRING_LEN; - } + ethtool_sprintf(strings, "tx-%u.tx_packets", + channel->tx_queue[0].queue / + EFX_MAX_TXQ_PER_CHANNEL); } } efx_for_each_channel(channel, efx) { if (efx_channel_has_rx_queue(channel)) { n_stats++; - if (strings != NULL) { - snprintf(strings, ETH_GSTRING_LEN, - "rx-%d.rx_packets", channel->channel); - strings += ETH_GSTRING_LEN; - } + if (!strings) + continue; + + ethtool_sprintf(strings, "rx-%d.rx_packets", + channel->channel); } } if (efx->xdp_tx_queue_count && efx->xdp_tx_queues) { @@ -428,11 +426,11 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) for (xdp = 0; xdp < efx->xdp_tx_queue_count; xdp++) { n_stats++; - if (strings) { - snprintf(strings, ETH_GSTRING_LEN, - "tx-xdp-cpu-%hu.tx_packets", xdp); - strings += ETH_GSTRING_LEN; - } + if (!strings) + continue; + + ethtool_sprintf(strings, "tx-xdp-cpu-%hu.tx_packets", + xdp); } } @@ -464,15 +462,11 @@ void efx_siena_ethtool_get_strings(struct net_device *net_dev, switch (string_set) { case ETH_SS_STATS: - strings += (efx->type->describe_stats(efx, strings) * - ETH_GSTRING_LEN); + efx->type->describe_stats(efx, &strings); for (i = 0; i < EFX_ETHTOOL_SW_STAT_COUNT; i++) - strscpy(strings + i * ETH_GSTRING_LEN, - efx_sw_stat_desc[i].name, ETH_GSTRING_LEN); - strings += EFX_ETHTOOL_SW_STAT_COUNT * ETH_GSTRING_LEN; - strings += (efx_describe_per_queue_stats(efx, strings) * - ETH_GSTRING_LEN); - efx_siena_ptp_describe_stats(efx, strings); + ethtool_puts(&strings, efx_sw_stat_desc[i].name); + efx_describe_per_queue_stats(efx, &strings); + efx_siena_ptp_describe_stats(efx, &strings); break; case ETH_SS_TEST: efx_ethtool_fill_self_tests(efx, NULL, strings, NULL); diff --git a/drivers/net/ethernet/sfc/siena/net_driver.h b/drivers/net/ethernet/sfc/siena/net_driver.h index 3fa7c652ae9b7c..9785eff10607be 100644 --- a/drivers/net/ethernet/sfc/siena/net_driver.h +++ b/drivers/net/ethernet/sfc/siena/net_driver.h @@ -1307,7 +1307,7 @@ struct efx_nic_type { void (*finish_flush)(struct efx_nic *efx); void (*prepare_flr)(struct efx_nic *efx); void (*finish_flr)(struct efx_nic *efx); - size_t (*describe_stats)(struct efx_nic *efx, u8 *names); + size_t (*describe_stats)(struct efx_nic *efx, u8 **names); size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats, struct rtnl_link_stats64 *core_stats); size_t (*update_stats_atomic)(struct efx_nic *efx, u64 *full_stats, diff --git a/drivers/net/ethernet/sfc/siena/nic.c b/drivers/net/ethernet/sfc/siena/nic.c index 0ea0433a62301b..32fce70085e330 100644 --- a/drivers/net/ethernet/sfc/siena/nic.c +++ b/drivers/net/ethernet/sfc/siena/nic.c @@ -449,20 +449,20 @@ void efx_siena_get_regs(struct efx_nic *efx, void *buf) * Returns the number of visible statistics, i.e. the number of set * bits in the first @count bits of @mask for which a name is defined. */ -size_t efx_siena_describe_stats(const struct efx_hw_stat_desc *desc, size_t count, - const unsigned long *mask, u8 *names) +size_t efx_siena_describe_stats(const struct efx_hw_stat_desc *desc, + size_t count, const unsigned long *mask, + u8 **names) { size_t visible = 0; size_t index; for_each_set_bit(index, mask, count) { if (desc[index].name) { - if (names) { - strscpy(names, desc[index].name, - ETH_GSTRING_LEN); - names += ETH_GSTRING_LEN; - } ++visible; + if (!names) + continue; + + ethtool_puts(names, desc[index].name); } } diff --git a/drivers/net/ethernet/sfc/siena/nic_common.h b/drivers/net/ethernet/sfc/siena/nic_common.h index 3af0405eeaa44b..b7fbe198008d6a 100644 --- a/drivers/net/ethernet/sfc/siena/nic_common.h +++ b/drivers/net/ethernet/sfc/siena/nic_common.h @@ -239,8 +239,9 @@ void efx_siena_get_regs(struct efx_nic *efx, void *buf); #define EFX_MC_STATS_GENERATION_INVALID ((__force __le64)(-1)) -size_t efx_siena_describe_stats(const struct efx_hw_stat_desc *desc, size_t count, - const unsigned long *mask, u8 *names); +size_t efx_siena_describe_stats(const struct efx_hw_stat_desc *desc, + size_t count, const unsigned long *mask, + u8 **names); void efx_siena_update_stats(const struct efx_hw_stat_desc *desc, size_t count, const unsigned long *mask, u64 *stats, const void *dma_buf, bool accumulate); diff --git a/drivers/net/ethernet/sfc/siena/ptp.c b/drivers/net/ethernet/sfc/siena/ptp.c index 85005196b4c506..062c77c9207749 100644 --- a/drivers/net/ethernet/sfc/siena/ptp.c +++ b/drivers/net/ethernet/sfc/siena/ptp.c @@ -393,7 +393,7 @@ static const unsigned long efx_ptp_stat_mask[] = { [0 ... BITS_TO_LONGS(PTP_STAT_COUNT) - 1] = ~0UL, }; -size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 *strings) +size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 **strings) { if (!efx->ptp_data) return 0; diff --git a/drivers/net/ethernet/sfc/siena/ptp.h b/drivers/net/ethernet/sfc/siena/ptp.h index b6133e7c56088b..54840036ab6728 100644 --- a/drivers/net/ethernet/sfc/siena/ptp.h +++ b/drivers/net/ethernet/sfc/siena/ptp.h @@ -28,7 +28,7 @@ int efx_siena_ptp_change_mode(struct efx_nic *efx, bool enable_wanted, unsigned int new_mode); int efx_siena_ptp_tx(struct efx_nic *efx, struct sk_buff *skb); void efx_siena_ptp_event(struct efx_nic *efx, efx_qword_t *ev); -size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 *strings); +size_t efx_siena_ptp_describe_stats(struct efx_nic *efx, u8 **strings); size_t efx_siena_ptp_update_stats(struct efx_nic *efx, u64 *stats); void efx_siena_time_sync_event(struct efx_channel *channel, efx_qword_t *ev); void __efx_siena_rx_skb_attach_timestamp(struct efx_channel *channel, diff --git a/drivers/net/ethernet/sfc/siena/siena.c b/drivers/net/ethernet/sfc/siena/siena.c index ca33dc08e555f2..49f0c8a1a90aba 100644 --- a/drivers/net/ethernet/sfc/siena/siena.c +++ b/drivers/net/ethernet/sfc/siena/siena.c @@ -545,7 +545,7 @@ static const unsigned long siena_stat_mask[] = { [0 ... BITS_TO_LONGS(SIENA_STAT_COUNT) - 1] = ~0UL, }; -static size_t siena_describe_nic_stats(struct efx_nic *efx, u8 *names) +static size_t siena_describe_nic_stats(struct efx_nic *efx, u8 **names) { return efx_siena_describe_stats(siena_stat_desc, SIENA_STAT_COUNT, siena_stat_mask, names); diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index fe2d476028e722..4dff19b6ef17b6 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -49,14 +49,6 @@ static inline u8 *efx_tx_get_copy_buffer(struct efx_tx_queue *tx_queue, return (u8 *)page_buf->addr + offset; } -u8 *efx_tx_get_copy_buffer_limited(struct efx_tx_queue *tx_queue, - struct efx_tx_buffer *buffer, size_t len) -{ - if (len > EFX_TX_CB_SIZE) - return NULL; - return efx_tx_get_copy_buffer(tx_queue, buffer); -} - static void efx_tx_maybe_stop_queue(struct efx_tx_queue *txq1) { /* We need to consider all queues that the net core sees as one */ @@ -553,6 +545,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, void efx_xmit_done_single(struct efx_tx_queue *tx_queue) { + unsigned int xdp_pkts_compl = 0, xdp_bytes_compl = 0; unsigned int pkts_compl = 0, bytes_compl = 0; unsigned int efv_pkts_compl = 0; unsigned int read_ptr; @@ -577,7 +570,8 @@ void efx_xmit_done_single(struct efx_tx_queue *tx_queue) if (buffer->flags & EFX_TX_BUF_SKB) finished = true; efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl, - &efv_pkts_compl); + &efv_pkts_compl, &xdp_pkts_compl, + &xdp_bytes_compl); ++tx_queue->read_count; read_ptr = tx_queue->read_count & tx_queue->ptr_mask; @@ -585,6 +579,8 @@ void efx_xmit_done_single(struct efx_tx_queue *tx_queue) tx_queue->pkts_compl += pkts_compl; tx_queue->bytes_compl += bytes_compl; + tx_queue->complete_xdp_packets += xdp_pkts_compl; + tx_queue->complete_xdp_bytes += xdp_bytes_compl; EFX_WARN_ON_PARANOID(pkts_compl + efv_pkts_compl != 1); diff --git a/drivers/net/ethernet/sfc/tx.h b/drivers/net/ethernet/sfc/tx.h index f2c4d2f89919d2..f882749af8c32a 100644 --- a/drivers/net/ethernet/sfc/tx.h +++ b/drivers/net/ethernet/sfc/tx.h @@ -15,9 +15,6 @@ unsigned int efx_tx_limit_len(struct efx_tx_queue *tx_queue, dma_addr_t dma_addr, unsigned int len); -u8 *efx_tx_get_copy_buffer_limited(struct efx_tx_queue *tx_queue, - struct efx_tx_buffer *buffer, size_t len); - /* What TXQ type will satisfy the checksum offloads required for this skb? */ static inline unsigned int efx_tx_csum_type_skb(struct sk_buff *skb) { diff --git a/drivers/net/ethernet/sfc/tx_common.c b/drivers/net/ethernet/sfc/tx_common.c index 2adb132b2f7e46..a22a0d634ffc42 100644 --- a/drivers/net/ethernet/sfc/tx_common.c +++ b/drivers/net/ethernet/sfc/tx_common.c @@ -86,6 +86,11 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) tx_queue->completed_timestamp_major = 0; tx_queue->completed_timestamp_minor = 0; + tx_queue->old_complete_packets = tx_queue->complete_packets; + tx_queue->old_complete_bytes = tx_queue->complete_bytes; + tx_queue->old_tso_bursts = tx_queue->tso_bursts; + tx_queue->old_tso_packets = tx_queue->tso_packets; + tx_queue->xdp_tx = efx_channel_is_xdp_tx(tx_queue->channel); tx_queue->tso_version = 0; @@ -109,12 +114,14 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) /* Free any buffers left in the ring */ while (tx_queue->read_count != tx_queue->write_count) { + unsigned int xdp_pkts_compl = 0, xdp_bytes_compl = 0; unsigned int pkts_compl = 0, bytes_compl = 0; unsigned int efv_pkts_compl = 0; buffer = &tx_queue->buffer[tx_queue->read_count & tx_queue->ptr_mask]; efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl, - &efv_pkts_compl); + &efv_pkts_compl, &xdp_pkts_compl, + &xdp_bytes_compl); ++tx_queue->read_count; } @@ -150,7 +157,9 @@ void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, struct efx_tx_buffer *buffer, unsigned int *pkts_compl, unsigned int *bytes_compl, - unsigned int *efv_pkts_compl) + unsigned int *efv_pkts_compl, + unsigned int *xdp_pkts, + unsigned int *xdp_bytes) { if (buffer->unmap_len) { struct device *dma_dev = &tx_queue->efx->pci_dev->dev; @@ -195,6 +204,10 @@ void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, tx_queue->queue, tx_queue->read_count); } else if (buffer->flags & EFX_TX_BUF_XDP) { xdp_return_frame_rx_napi(buffer->xdpf); + if (xdp_pkts) + (*xdp_pkts)++; + if (xdp_bytes) + (*xdp_bytes) += buffer->xdpf->len; } buffer->len = 0; @@ -210,7 +223,9 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, unsigned int index, unsigned int *pkts_compl, unsigned int *bytes_compl, - unsigned int *efv_pkts_compl) + unsigned int *efv_pkts_compl, + unsigned int *xdp_pkts, + unsigned int *xdp_bytes) { struct efx_nic *efx = tx_queue->efx; unsigned int stop_index, read_ptr; @@ -230,7 +245,7 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue, } efx_dequeue_buffer(tx_queue, buffer, pkts_compl, bytes_compl, - efv_pkts_compl); + efv_pkts_compl, xdp_pkts, xdp_bytes); ++tx_queue->read_count; read_ptr = tx_queue->read_count & tx_queue->ptr_mask; @@ -253,15 +268,18 @@ void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue) int efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) { unsigned int fill_level, pkts_compl = 0, bytes_compl = 0; + unsigned int xdp_pkts_compl = 0, xdp_bytes_compl = 0; unsigned int efv_pkts_compl = 0; struct efx_nic *efx = tx_queue->efx; EFX_WARN_ON_ONCE_PARANOID(index > tx_queue->ptr_mask); efx_dequeue_buffers(tx_queue, index, &pkts_compl, &bytes_compl, - &efv_pkts_compl); + &efv_pkts_compl, &xdp_pkts_compl, &xdp_bytes_compl); tx_queue->pkts_compl += pkts_compl; tx_queue->bytes_compl += bytes_compl; + tx_queue->complete_xdp_packets += xdp_pkts_compl; + tx_queue->complete_xdp_bytes += xdp_bytes_compl; if (pkts_compl + efv_pkts_compl > 1) ++tx_queue->merge_events; @@ -290,6 +308,8 @@ int efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) void efx_enqueue_unwind(struct efx_tx_queue *tx_queue, unsigned int insert_count) { + unsigned int xdp_bytes_compl = 0; + unsigned int xdp_pkts_compl = 0; unsigned int efv_pkts_compl = 0; struct efx_tx_buffer *buffer; unsigned int bytes_compl = 0; @@ -300,7 +320,8 @@ void efx_enqueue_unwind(struct efx_tx_queue *tx_queue, --tx_queue->insert_count; buffer = __efx_tx_queue_get_insert_buffer(tx_queue); efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl, - &efv_pkts_compl); + &efv_pkts_compl, &xdp_pkts_compl, + &xdp_bytes_compl); } } diff --git a/drivers/net/ethernet/sfc/tx_common.h b/drivers/net/ethernet/sfc/tx_common.h index 1e9f42938aac92..039eefafba23af 100644 --- a/drivers/net/ethernet/sfc/tx_common.h +++ b/drivers/net/ethernet/sfc/tx_common.h @@ -20,7 +20,9 @@ void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, struct efx_tx_buffer *buffer, unsigned int *pkts_compl, unsigned int *bytes_compl, - unsigned int *efv_pkts_compl); + unsigned int *efv_pkts_compl, + unsigned int *xdp_pkts, + unsigned int *xdp_bytes); static inline bool efx_tx_buffer_in_use(struct efx_tx_buffer *buffer) { diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 98d0b561a0572b..4535579018c93f 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -1273,7 +1273,7 @@ static void ioc3_set_multicast_list(struct net_device *dev) static struct platform_driver ioc3eth_driver = { .probe = ioc3eth_probe, - .remove_new = ioc3eth_remove, + .remove = ioc3eth_remove, .driver = { .name = "ioc3-eth", } diff --git a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c index 18b6f93d875e1f..f7c3a5a766b7fe 100644 --- a/drivers/net/ethernet/sgi/meth.c +++ b/drivers/net/ethernet/sgi/meth.c @@ -864,7 +864,7 @@ static void meth_remove(struct platform_device *pdev) static struct platform_driver meth_driver = { .probe = meth_probe, - .remove_new = meth_remove, + .remove = meth_remove, .driver = { .name = "meth", } diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index a5e23e2da90f44..9d1a83a5fa7e5d 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2475,7 +2475,7 @@ static const struct dev_pm_ops smc_drv_pm_ops = { static struct platform_driver smc_driver = { .probe = smc_drv_probe, - .remove_new = smc_drv_remove, + .remove = smc_drv_remove, .driver = { .name = CARDNAME, .pm = &smc_drv_pm_ops, diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 74f1ccc9645992..f539813878f537 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -2667,7 +2667,7 @@ MODULE_DEVICE_TABLE(acpi, smsc911x_acpi_match); static struct platform_driver smsc911x_driver = { .probe = smsc911x_drv_probe, - .remove_new = smsc911x_drv_remove, + .remove = smsc911x_drv_remove, .driver = { .name = SMSC_CHIPNAME, .pm = SMSC911X_PM_OPS, diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index 5ab8b81b84e6f6..dc99821c6226fb 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -2211,7 +2211,7 @@ MODULE_DEVICE_TABLE(acpi, netsec_acpi_ids); static struct platform_driver netsec_driver = { .probe = netsec_probe, - .remove_new = netsec_remove, + .remove = netsec_remove, .driver = { .name = "netsec", .pm = &netsec_pm_ops, diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c index eed24e67c5a674..66b3549636f8de 100644 --- a/drivers/net/ethernet/socionext/sni_ave.c +++ b/drivers/net/ethernet/socionext/sni_ave.c @@ -1974,7 +1974,7 @@ MODULE_DEVICE_TABLE(of, of_ave_match); static struct platform_driver ave_driver = { .probe = ave_probe, - .remove_new = ave_remove, + .remove = ave_remove, .driver = { .name = "ave", .pm = AVE_PM_OPS, diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 05cc07b8f48c03..6658536a4e1710 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -228,6 +228,16 @@ config DWMAC_SUN8I stmmac device driver. This driver is used for H3/A83T/A64 EMAC ethernet controller. +config DWMAC_THEAD + tristate "T-HEAD dwmac support" + depends on OF && (ARCH_THEAD || COMPILE_TEST) + help + Support for ethernet controllers on T-HEAD RISC-V SoCs + + This selects the T-HEAD platform specific glue layer support for + the stmmac device driver. This driver is used for T-HEAD TH1520 + ethernet controller. + config DWMAC_IMX8 tristate "NXP IMX8 DWMAC support" default ARCH_MXC diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index c2f0e91f6bf83d..2389fd26134465 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \ dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \ stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \ - stmmac_xdp.o stmmac_est.o \ + stmmac_xdp.o stmmac_est.o stmmac_fpe.o \ $(stmmac-y) stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o @@ -28,6 +28,7 @@ obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o +obj-$(CONFIG_DWMAC_THEAD) += dwmac-thead.o obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o obj-$(CONFIG_DWMAC_LOONGSON1) += dwmac-loongson1.o diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 684489156dcee7..1367fa5c9b8ea3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -549,8 +549,12 @@ extern const struct stmmac_desc_ops ndesc_ops; struct mac_device_info; extern const struct stmmac_hwtimestamp stmmac_ptp; +extern const struct stmmac_hwtimestamp dwmac1000_ptp; extern const struct stmmac_mode_ops dwmac4_ring_mode_ops; +extern const struct ptp_clock_info stmmac_ptp_clock_ops; +extern const struct ptp_clock_info dwmac1000_ptp_clock_ops; + struct mac_link { u32 caps; u32 speed_mask; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c index 643ee6d8d4dd5a..ef99ef3f1ab479 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c @@ -135,7 +135,7 @@ MODULE_DEVICE_TABLE(of, anarion_dwmac_match); static struct platform_driver anarion_dwmac_driver = { .probe = anarion_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "anarion-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c index ec924c6c76c6c1..83290e707df53c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c @@ -479,7 +479,7 @@ MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match); static struct platform_driver dwc_eth_dwmac_driver = { .probe = dwc_eth_dwmac_probe, - .remove_new = dwc_eth_dwmac_remove, + .remove = dwc_eth_dwmac_remove, .driver = { .name = "dwc-eth-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index 598eff926815a4..b9218c07eb6b8f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -56,6 +56,7 @@ static const struct of_device_id dwmac_generic_match[] = { { .compatible = "snps,dwmac-3.610"}, { .compatible = "snps,dwmac-3.70a"}, { .compatible = "snps,dwmac-3.710"}, + { .compatible = "snps,dwmac-3.72a"}, { .compatible = "snps,dwmac-4.00"}, { .compatible = "snps,dwmac-4.10a"}, { .compatible = "snps,dwmac"}, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c index 6b65420e11b5c5..641f3cd019a3c9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c @@ -422,7 +422,7 @@ MODULE_DEVICE_TABLE(of, imx_dwmac_match); static struct platform_driver imx_dwmac_driver = { .probe = imx_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "imx-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c index 19c93b998fb316..066783d6642288 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c @@ -370,7 +370,7 @@ MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches); static struct platform_driver ingenic_mac_driver = { .probe = ingenic_mac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "ingenic-mac", .pm = pm_ptr(&ingenic_mac_pm_ops), diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c index 9739bc9867c514..d94f0a150e934a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c @@ -97,35 +97,38 @@ static int intel_eth_plat_probe(struct platform_device *pdev) dwmac->dev = &pdev->dev; dwmac->tx_clk = NULL; + /* + * This cannot return NULL at this point because the driver’s + * compatibility with the device has already been validated in + * platform_match(). + */ dwmac->data = device_get_match_data(&pdev->dev); - if (dwmac->data) { - if (dwmac->data->fix_mac_speed) - plat_dat->fix_mac_speed = dwmac->data->fix_mac_speed; - - /* Enable TX clock */ - if (dwmac->data->tx_clk_en) { - dwmac->tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); - if (IS_ERR(dwmac->tx_clk)) - return PTR_ERR(dwmac->tx_clk); + if (dwmac->data->fix_mac_speed) + plat_dat->fix_mac_speed = dwmac->data->fix_mac_speed; + + /* Enable TX clock */ + if (dwmac->data->tx_clk_en) { + dwmac->tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); + if (IS_ERR(dwmac->tx_clk)) + return PTR_ERR(dwmac->tx_clk); + + ret = clk_prepare_enable(dwmac->tx_clk); + if (ret) { + dev_err(&pdev->dev, + "Failed to enable tx_clk\n"); + return ret; + } - ret = clk_prepare_enable(dwmac->tx_clk); + /* Check and configure TX clock rate */ + rate = clk_get_rate(dwmac->tx_clk); + if (dwmac->data->tx_clk_rate && + rate != dwmac->data->tx_clk_rate) { + rate = dwmac->data->tx_clk_rate; + ret = clk_set_rate(dwmac->tx_clk, rate); if (ret) { dev_err(&pdev->dev, - "Failed to enable tx_clk\n"); - return ret; - } - - /* Check and configure TX clock rate */ - rate = clk_get_rate(dwmac->tx_clk); - if (dwmac->data->tx_clk_rate && - rate != dwmac->data->tx_clk_rate) { - rate = dwmac->data->tx_clk_rate; - ret = clk_set_rate(dwmac->tx_clk, rate); - if (ret) { - dev_err(&pdev->dev, - "Failed to set tx_clk\n"); - goto err_tx_clk_disable; - } + "Failed to set tx_clk\n"); + goto err_tx_clk_disable; } } @@ -176,7 +179,7 @@ static void intel_eth_plat_remove(struct platform_device *pdev) static struct platform_driver intel_eth_plat_driver = { .probe = intel_eth_plat_probe, - .remove_new = intel_eth_plat_remove, + .remove = intel_eth_plat_remove, .driver = { .name = "intel-eth-plat", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c index 83ad7c7935e31e..48acba5eb178e7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c @@ -451,7 +451,7 @@ static struct phylink_pcs *intel_mgbe_select_pcs(struct stmmac_priv *priv, * should always be an XPCS. The original code would always * return this if present. */ - return &priv->hw->xpcs->pcs; + return xpcs_to_phylink_pcs(priv->hw->xpcs); } static int intel_mgbe_common_data(struct pci_dev *pdev, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 4ba15873d5b1af..61227dcf56dc68 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -499,7 +499,7 @@ MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match); static struct platform_driver ipq806x_gmac_dwmac_driver = { .probe = ipq806x_gmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "ipq806x-gmac-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c index 4c810d8f5bea4d..22653ffd2a0488 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c @@ -72,7 +72,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match); static struct platform_driver lpc18xx_dwmac_driver = { .probe = lpc18xx_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "lpc18xx-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c index 001857c294fba1..c9636832a570a2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c @@ -699,7 +699,7 @@ MODULE_DEVICE_TABLE(of, mediatek_dwmac_match); static struct platform_driver mediatek_dwmac_driver = { .probe = mediatek_dwmac_probe, - .remove_new = mediatek_dwmac_remove, + .remove = mediatek_dwmac_remove, .driver = { .name = "dwmac-mediatek", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c index a16bfa9089ea76..5469fa1b429e31 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c @@ -78,7 +78,7 @@ MODULE_DEVICE_TABLE(of, meson6_dwmac_match); static struct platform_driver meson6_dwmac_driver = { .probe = meson6_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "meson6-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index b23944aa344e18..9c2d62d133ade6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, meson8b_dwmac_match); static struct platform_driver meson8b_dwmac_driver = { .probe = meson8b_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "meson8b-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 50073bdade46e4..8cb374668b74ce 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -2073,7 +2073,7 @@ MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match); static struct platform_driver rk_gmac_dwmac_driver = { .probe = rk_gmac_probe, - .remove_new = rk_gmac_remove, + .remove = rk_gmac_remove, .driver = { .name = "rk_gmac-dwmac", .pm = &rk_gmac_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c index 59a7bd560f9617..13634965bc19a1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c @@ -80,7 +80,7 @@ MODULE_DEVICE_TABLE(of, rzn1_dwmac_match); static struct platform_driver rzn1_dwmac_driver = { .probe = rzn1_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "rzn1-dwmac", .of_match_table = rzn1_dwmac_match, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index fdb4c773ec98ab..16020b72dec837 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -485,6 +485,9 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) plat_dat->pcs_init = socfpga_dwmac_pcs_init; plat_dat->pcs_exit = socfpga_dwmac_pcs_exit; plat_dat->select_pcs = socfpga_dwmac_select_pcs; + plat_dat->has_gmac = true; + + plat_dat->riwt_off = 1; ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) @@ -582,7 +585,7 @@ MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); static struct platform_driver socfpga_dwmac_driver = { .probe = socfpga_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "socfpga-dwmac", .pm = &socfpga_dwmac_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c index 4e1076faee0cd7..421666279dd381 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c @@ -176,7 +176,7 @@ MODULE_DEVICE_TABLE(of, starfive_dwmac_match); static struct platform_driver starfive_dwmac_driver = { .probe = starfive_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "starfive-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index 4445cddc4cbed9..a6ff02d905a991 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -358,7 +358,7 @@ MODULE_DEVICE_TABLE(of, sti_dwmac_match); static struct platform_driver sti_dwmac_driver = { .probe = sti_dwmac_probe, - .remove_new = sti_dwmac_remove, + .remove = sti_dwmac_remove, .driver = { .name = "sti-dwmac", .pm = &sti_dwmac_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index c1732955a697ed..1e8bac665cc9bc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -675,7 +675,7 @@ MODULE_DEVICE_TABLE(of, stm32_dwmac_match); static struct platform_driver stm32_dwmac_driver = { .probe = stm32_dwmac_probe, - .remove_new = stm32_dwmac_remove, + .remove = stm32_dwmac_remove, .driver = { .name = "stm32-dwmac", .pm = &stm32_dwmac_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index 4a0ae92b3055c2..4b7b2582a1201d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -1343,7 +1343,7 @@ MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); static struct platform_driver sun8i_dwmac_driver = { .probe = sun8i_dwmac_probe, - .remove_new = sun8i_dwmac_remove, + .remove = sun8i_dwmac_remove, .shutdown = sun8i_dwmac_shutdown, .driver = { .name = "dwmac-sun8i", diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index 2653a9f0958c96..9ae318436c4a72 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -172,7 +172,7 @@ MODULE_DEVICE_TABLE(of, sun7i_dwmac_match); static struct platform_driver sun7i_dwmac_driver = { .probe = sun7i_gmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "sun7i-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c index 6fdd94c8919ec2..3827997d21328e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c @@ -381,7 +381,7 @@ static SIMPLE_DEV_PM_OPS(tegra_mgbe_pm_ops, tegra_mgbe_suspend, tegra_mgbe_resum static struct platform_driver tegra_mgbe_driver = { .probe = tegra_mgbe_probe, - .remove_new = tegra_mgbe_remove, + .remove = tegra_mgbe_remove, .driver = { .name = "tegra-mgbe", .pm = &tegra_mgbe_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c new file mode 100644 index 00000000000000..dce84ed184e9a1 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * T-HEAD DWMAC platform driver + * + * Copyright (C) 2021 Alibaba Group Holding Limited. + * Copyright (C) 2023 Jisheng Zhang + * + */ + +#include +#include +#include +#include +#include +#include + +#include "stmmac_platform.h" + +#define GMAC_CLK_EN 0x00 +#define GMAC_TX_CLK_EN BIT(1) +#define GMAC_TX_CLK_N_EN BIT(2) +#define GMAC_TX_CLK_OUT_EN BIT(3) +#define GMAC_RX_CLK_EN BIT(4) +#define GMAC_RX_CLK_N_EN BIT(5) +#define GMAC_EPHY_REF_CLK_EN BIT(6) +#define GMAC_RXCLK_DELAY_CTRL 0x04 +#define GMAC_RXCLK_BYPASS BIT(15) +#define GMAC_RXCLK_INVERT BIT(14) +#define GMAC_RXCLK_DELAY GENMASK(4, 0) +#define GMAC_TXCLK_DELAY_CTRL 0x08 +#define GMAC_TXCLK_BYPASS BIT(15) +#define GMAC_TXCLK_INVERT BIT(14) +#define GMAC_TXCLK_DELAY GENMASK(4, 0) +#define GMAC_PLLCLK_DIV 0x0c +#define GMAC_PLLCLK_DIV_EN BIT(31) +#define GMAC_PLLCLK_DIV_NUM GENMASK(7, 0) +#define GMAC_GTXCLK_SEL 0x18 +#define GMAC_GTXCLK_SEL_PLL BIT(0) +#define GMAC_INTF_CTRL 0x1c +#define PHY_INTF_MASK BIT(0) +#define PHY_INTF_RGMII FIELD_PREP(PHY_INTF_MASK, 1) +#define PHY_INTF_MII_GMII FIELD_PREP(PHY_INTF_MASK, 0) +#define GMAC_TXCLK_OEN 0x20 +#define TXCLK_DIR_MASK BIT(0) +#define TXCLK_DIR_OUTPUT FIELD_PREP(TXCLK_DIR_MASK, 0) +#define TXCLK_DIR_INPUT FIELD_PREP(TXCLK_DIR_MASK, 1) + +#define GMAC_GMII_RGMII_RATE 125000000 +#define GMAC_MII_RATE 25000000 + +struct thead_dwmac { + struct plat_stmmacenet_data *plat; + void __iomem *apb_base; + struct device *dev; +}; + +static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat) +{ + struct thead_dwmac *dwmac = plat->bsp_priv; + u32 phyif; + + switch (plat->mac_interface) { + case PHY_INTERFACE_MODE_MII: + phyif = PHY_INTF_MII_GMII; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + phyif = PHY_INTF_RGMII; + break; + default: + dev_err(dwmac->dev, "unsupported phy interface %d\n", + plat->mac_interface); + return -EINVAL; + } + + writel(phyif, dwmac->apb_base + GMAC_INTF_CTRL); + return 0; +} + +static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) +{ + struct thead_dwmac *dwmac = plat->bsp_priv; + u32 txclk_dir; + + switch (plat->mac_interface) { + case PHY_INTERFACE_MODE_MII: + txclk_dir = TXCLK_DIR_INPUT; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + txclk_dir = TXCLK_DIR_OUTPUT; + break; + default: + dev_err(dwmac->dev, "unsupported phy interface %d\n", + plat->mac_interface); + return -EINVAL; + } + + writel(txclk_dir, dwmac->apb_base + GMAC_TXCLK_OEN); + return 0; +} + +static void thead_dwmac_fix_speed(void *priv, unsigned int speed, unsigned int mode) +{ + struct plat_stmmacenet_data *plat; + struct thead_dwmac *dwmac = priv; + unsigned long rate; + u32 div, reg; + + plat = dwmac->plat; + + switch (plat->mac_interface) { + /* For MII, rxc/txc is provided by phy */ + case PHY_INTERFACE_MODE_MII: + return; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + rate = clk_get_rate(plat->stmmac_clk); + if (!rate || rate % GMAC_GMII_RGMII_RATE != 0 || + rate % GMAC_MII_RATE != 0) { + dev_err(dwmac->dev, "invalid gmac rate %ld\n", rate); + return; + } + + writel(0, dwmac->apb_base + GMAC_PLLCLK_DIV); + + switch (speed) { + case SPEED_1000: + div = rate / GMAC_GMII_RGMII_RATE; + break; + case SPEED_100: + div = rate / GMAC_MII_RATE; + break; + case SPEED_10: + div = rate * 10 / GMAC_MII_RATE; + break; + default: + dev_err(dwmac->dev, "invalid speed %u\n", speed); + return; + } + + reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) | + FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div); + writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV); + break; + default: + dev_err(dwmac->dev, "unsupported phy interface %d\n", + plat->mac_interface); + return; + } +} + +static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) +{ + struct thead_dwmac *dwmac = plat->bsp_priv; + u32 reg; + + switch (plat->mac_interface) { + case PHY_INTERFACE_MODE_MII: + reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN; + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + /* use pll */ + writel(GMAC_GTXCLK_SEL_PLL, dwmac->apb_base + GMAC_GTXCLK_SEL); + reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN | + GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN; + break; + + default: + dev_err(dwmac->dev, "unsupported phy interface %d\n", + plat->mac_interface); + return -EINVAL; + } + + writel(reg, dwmac->apb_base + GMAC_CLK_EN); + return 0; +} + +static int thead_dwmac_init(struct platform_device *pdev, void *priv) +{ + struct thead_dwmac *dwmac = priv; + unsigned int reg; + int ret; + + ret = thead_dwmac_set_phy_if(dwmac->plat); + if (ret) + return ret; + + ret = thead_dwmac_set_txclk_dir(dwmac->plat); + if (ret) + return ret; + + reg = readl(dwmac->apb_base + GMAC_RXCLK_DELAY_CTRL); + reg &= ~(GMAC_RXCLK_DELAY); + reg |= FIELD_PREP(GMAC_RXCLK_DELAY, 0); + writel(reg, dwmac->apb_base + GMAC_RXCLK_DELAY_CTRL); + + reg = readl(dwmac->apb_base + GMAC_TXCLK_DELAY_CTRL); + reg &= ~(GMAC_TXCLK_DELAY); + reg |= FIELD_PREP(GMAC_TXCLK_DELAY, 0); + writel(reg, dwmac->apb_base + GMAC_TXCLK_DELAY_CTRL); + + return thead_dwmac_enable_clk(dwmac->plat); +} + +static int thead_dwmac_probe(struct platform_device *pdev) +{ + struct stmmac_resources stmmac_res; + struct plat_stmmacenet_data *plat; + struct thead_dwmac *dwmac; + void __iomem *apb; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to get resources\n"); + + plat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); + if (IS_ERR(plat)) + return dev_err_probe(&pdev->dev, PTR_ERR(plat), + "dt configuration failed\n"); + + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) + return -ENOMEM; + + apb = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(apb)) + return dev_err_probe(&pdev->dev, PTR_ERR(apb), + "failed to remap gmac apb registers\n"); + + dwmac->dev = &pdev->dev; + dwmac->plat = plat; + dwmac->apb_base = apb; + plat->bsp_priv = dwmac; + plat->fix_mac_speed = thead_dwmac_fix_speed; + plat->init = thead_dwmac_init; + + return devm_stmmac_pltfr_probe(pdev, plat, &stmmac_res); +} + +static const struct of_device_id thead_dwmac_match[] = { + { .compatible = "thead,th1520-gmac" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, thead_dwmac_match); + +static struct platform_driver thead_dwmac_driver = { + .probe = thead_dwmac_probe, + .driver = { + .name = "thead-dwmac", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = thead_dwmac_match, + }, +}; +module_platform_driver(thead_dwmac_driver); + +MODULE_AUTHOR("Jisheng Zhang "); +MODULE_AUTHOR("Drew Fustini "); +MODULE_DESCRIPTION("T-HEAD DWMAC platform driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c index a5a5cfa989c6e7..eccf7f53746783 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c @@ -268,7 +268,7 @@ MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match); static struct platform_driver visconti_eth_dwmac_driver = { .probe = visconti_eth_dwmac_probe, - .remove_new = visconti_eth_dwmac_remove, + .remove = visconti_eth_dwmac_remove, .driver = { .name = "visconti-eth-dwmac", .of_match_table = visconti_eth_dwmac_match, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index 4296ddda8aaa6c..600fea8f712fd6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -329,5 +329,17 @@ enum rtc_control { #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 #define GMAC_EXTHASH_BASE 0x500 +/* PTP and timestamping registers */ + +#define GMAC3_X_ATSNS GENMASK(19, 16) +#define GMAC3_X_ATSNS_SHIFT 16 + +#define GMAC_PTP_TCR_ATSFC BIT(24) +#define GMAC_PTP_TCR_ATSEN0 BIT(25) + +#define GMAC3_X_TIMESTAMP_STATUS 0x28 +#define GMAC_PTP_ATNR 0x30 +#define GMAC_PTP_ATSR 0x34 + extern const struct stmmac_dma_ops dwmac1000_dma_ops; #endif /* __DWMAC1000_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index d413d76a893680..96bcda0856ec62 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -18,6 +18,7 @@ #include #include "stmmac.h" #include "stmmac_pcs.h" +#include "stmmac_ptp.h" #include "dwmac1000.h" static void dwmac1000_core_init(struct mac_device_info *hw, @@ -551,3 +552,103 @@ int dwmac1000_setup(struct stmmac_priv *priv) return 0; } + +/* DWMAC 1000 HW Timestaming ops */ + +void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time) +{ + u64 ns; + + ns = readl(ptpaddr + GMAC_PTP_ATNR); + ns += readl(ptpaddr + GMAC_PTP_ATSR) * NSEC_PER_SEC; + + *ptp_time = ns; +} + +void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv) +{ + struct ptp_clock_event event; + u32 ts_status, num_snapshot; + unsigned long flags; + u64 ptp_time; + int i; + + /* Clears the timestamp interrupt */ + ts_status = readl(priv->ptpaddr + GMAC3_X_TIMESTAMP_STATUS); + + if (!(priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN)) + return; + + num_snapshot = (ts_status & GMAC3_X_ATSNS) >> GMAC3_X_ATSNS_SHIFT; + + for (i = 0; i < num_snapshot; i++) { + read_lock_irqsave(&priv->ptp_lock, flags); + stmmac_get_ptptime(priv, priv->ptpaddr, &ptp_time); + read_unlock_irqrestore(&priv->ptp_lock, flags); + + event.type = PTP_CLOCK_EXTTS; + event.index = 0; + event.timestamp = ptp_time; + ptp_clock_event(priv->ptp_clock, &event); + } +} + +/* DWMAC 1000 ptp_clock_info ops */ + +static void dwmac1000_timestamp_interrupt_cfg(struct stmmac_priv *priv, bool en) +{ + void __iomem *ioaddr = priv->ioaddr; + + u32 intr_mask = readl(ioaddr + GMAC_INT_MASK); + + if (en) + intr_mask &= ~GMAC_INT_DISABLE_TIMESTAMP; + else + intr_mask |= GMAC_INT_DISABLE_TIMESTAMP; + + writel(intr_mask, ioaddr + GMAC_INT_MASK); +} + +int dwmac1000_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct stmmac_priv *priv = + container_of(ptp, struct stmmac_priv, ptp_clock_ops); + void __iomem *ptpaddr = priv->ptpaddr; + int ret = -EOPNOTSUPP; + u32 tcr_val; + + switch (rq->type) { + case PTP_CLK_REQ_EXTTS: + mutex_lock(&priv->aux_ts_lock); + tcr_val = readl(ptpaddr + PTP_TCR); + + if (on) { + tcr_val |= GMAC_PTP_TCR_ATSEN0; + tcr_val |= GMAC_PTP_TCR_ATSFC; + priv->plat->flags |= STMMAC_FLAG_EXT_SNAPSHOT_EN; + } else { + tcr_val &= ~GMAC_PTP_TCR_ATSEN0; + priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN; + } + + netdev_dbg(priv->dev, "Auxiliary Snapshot %s.\n", + on ? "enabled" : "disabled"); + writel(tcr_val, ptpaddr + PTP_TCR); + + /* wait for auxts fifo clear to finish */ + ret = readl_poll_timeout(ptpaddr + PTP_TCR, tcr_val, + !(tcr_val & GMAC_PTP_TCR_ATSFC), + 10, 10000); + + mutex_unlock(&priv->aux_ts_lock); + + dwmac1000_timestamp_interrupt_cfg(priv, on); + break; + + default: + break; + } + + return ret; +} diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index 93a78fd0737b6c..184d41a306af08 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -44,6 +44,7 @@ #define GMAC_MDIO_DATA 0x00000204 #define GMAC_GPIO_STATUS 0x0000020C #define GMAC_ARP_ADDR 0x00000210 +#define GMAC_EXT_CFG1 0x00000238 #define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8) #define GMAC_ADDR_LOW(reg) (0x304 + reg * 8) #define GMAC_L3L4_CTRL(reg) (0x900 + (reg) * 0x30) @@ -68,7 +69,6 @@ #define GMAC_RXQCTRL_TACPQE BIT(21) #define GMAC_RXQCTRL_TACPQE_SHIFT 21 #define GMAC_RXQCTRL_FPRQ GENMASK(26, 24) -#define GMAC_RXQCTRL_FPRQ_SHIFT 24 /* MAC Packet Filtering */ #define GMAC_PACKET_FILTER_PR BIT(0) @@ -284,6 +284,10 @@ enum power_event { #define GMAC_HW_FEAT_DVLAN BIT(5) #define GMAC_HW_FEAT_NRVF GENMASK(2, 0) +/* MAC extended config 1 */ +#define GMAC_CONFIG1_SAVE_EN BIT(24) +#define GMAC_CONFIG1_SPLM(v) FIELD_PREP(GENMASK(9, 8), v) + /* GMAC GPIO Status reg */ #define GMAC_GPO0 BIT(16) #define GMAC_GPO1 BIT(17) @@ -389,8 +393,8 @@ static inline u32 mtl_chanx_base_addr(const struct dwmac4_addrs *addrs, #define MTL_OP_MODE_EHFC BIT(7) -#define MTL_OP_MODE_RTC_MASK 0x18 -#define MTL_OP_MODE_RTC_SHIFT 3 +#define MTL_OP_MODE_RTC_MASK GENMASK(1, 0) +#define MTL_OP_MODE_RTC_SHIFT 0 #define MTL_OP_MODE_RTC_32 (1 << MTL_OP_MODE_RTC_SHIFT) #define MTL_OP_MODE_RTC_64 0 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index e65a65666cc1de..c25781874aa78a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -16,6 +16,7 @@ #include #include #include "stmmac.h" +#include "stmmac_fpe.h" #include "stmmac_pcs.h" #include "dwmac4.h" #include "dwmac5.h" @@ -1261,11 +1262,6 @@ const struct stmmac_ops dwmac410_ops = { .set_arp_offload = dwmac4_set_arp_offload, .config_l3_filter = dwmac4_config_l3_filter, .config_l4_filter = dwmac4_config_l4_filter, - .fpe_configure = dwmac5_fpe_configure, - .fpe_send_mpacket = dwmac5_fpe_send_mpacket, - .fpe_irq_status = dwmac5_fpe_irq_status, - .fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size, - .fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size, .fpe_map_preemption_class = dwmac5_fpe_map_preemption_class, .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, @@ -1316,11 +1312,6 @@ const struct stmmac_ops dwmac510_ops = { .set_arp_offload = dwmac4_set_arp_offload, .config_l3_filter = dwmac4_config_l3_filter, .config_l4_filter = dwmac4_config_l4_filter, - .fpe_configure = dwmac5_fpe_configure, - .fpe_send_mpacket = dwmac5_fpe_send_mpacket, - .fpe_irq_status = dwmac5_fpe_irq_status, - .fpe_get_add_frag_size = dwmac5_fpe_get_add_frag_size, - .fpe_set_add_frag_size = dwmac5_fpe_set_add_frag_size, .fpe_map_preemption_class = dwmac5_fpe_map_preemption_class, .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index e99401bcc1f84b..a5fb31eb0192f2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -118,6 +118,8 @@ static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x, x->ipv4_pkt_rcvd++; if (rdes1 & RDES1_IPV6_HEADER) x->ipv6_pkt_rcvd++; + if (rdes1 & RDES1_IP_PAYLOAD_ERROR) + x->ip_payload_err++; if (message_type == RDES_EXT_NO_PTP) x->no_ptp_rx_msg_type_ext++; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h index 6da070ccd73746..1ce6f43d545ae6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h @@ -95,7 +95,7 @@ #define RDES1_IPV4_HEADER BIT(4) #define RDES1_IPV6_HEADER BIT(5) #define RDES1_IP_CSUM_BYPASSED BIT(6) -#define RDES1_IP_CSUM_ERROR BIT(7) +#define RDES1_IP_PAYLOAD_ERROR BIT(7) #define RDES1_PTP_MSG_TYPE_MASK GENMASK(11, 8) #define RDES1_PTP_PACKET_TYPE BIT(12) #define RDES1_PTP_VER BIT(13) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 77b35abc6f6fa4..0cb84a0041a463 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -274,7 +274,7 @@ static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv, } else { pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode); mtl_rx_op &= ~MTL_OP_MODE_RSF; - mtl_rx_op &= MTL_OP_MODE_RTC_MASK; + mtl_rx_op &= ~MTL_OP_MODE_RTC_MASK; if (mode <= 32) mtl_rx_op |= MTL_OP_MODE_RTC_32; else if (mode <= 64) @@ -343,7 +343,7 @@ static void dwmac4_dma_tx_chan_op_mode(struct stmmac_priv *priv, } else { pr_debug("GMAC: disabling TX SF (threshold %d)\n", mode); mtl_tx_op &= ~MTL_OP_MODE_TSF; - mtl_tx_op &= MTL_OP_MODE_TTC_MASK; + mtl_tx_op &= ~MTL_OP_MODE_TTC_MASK; /* Set the transmit threshold */ if (mode <= 32) mtl_tx_op |= MTL_OP_MODE_TTC_32; @@ -534,6 +534,11 @@ static void dwmac4_enable_sph(struct stmmac_priv *priv, void __iomem *ioaddr, value |= GMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */ writel(value, ioaddr + GMAC_EXT_CONFIG); + value = readl(ioaddr + GMAC_EXT_CFG1); + value |= GMAC_CONFIG1_SPLM(1); /* Split mode set to L2OFST */ + value |= GMAC_CONFIG1_SAVE_EN; /* Enable Split AV mode */ + writel(value, ioaddr + GMAC_EXT_CFG1); + value = readl(ioaddr + DMA_CHAN_CONTROL(dwmac4_addrs, chan)); if (en) value |= DMA_CONTROL_SPH; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c index 0d185e54eb7e24..57c03d49177447 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c @@ -185,8 +185,6 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, x->rx_buf_unav_irq++; if (unlikely(intr_status & DMA_CHAN_STATUS_RPS)) x->rx_process_stopped_irq++; - if (unlikely(intr_status & DMA_CHAN_STATUS_RWT)) - x->rx_watchdog_irq++; if (unlikely(intr_status & DMA_CHAN_STATUS_ETI)) x->tx_early_irq++; if (unlikely(intr_status & DMA_CHAN_STATUS_TPS)) { @@ -198,6 +196,10 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, ret = tx_hard_error; } } + + if (unlikely(intr_status & DMA_CHAN_STATUS_RWT)) + x->rx_watchdog_irq++; + /* TX/RX NORMAL interrupts */ if (likely(intr_status & DMA_CHAN_STATUS_RI)) { u64_stats_update_begin(&stats->syncp); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c index 08add508db8441..1c431b918719e2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c @@ -572,153 +572,3 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, writel(val, ioaddr + MAC_PPS_CONTROL); return 0; } - -void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, - u32 num_txq, u32 num_rxq, - bool tx_enable, bool pmac_enable) -{ - u32 value; - - if (tx_enable) { - cfg->fpe_csr = EFPE; - value = readl(ioaddr + GMAC_RXQ_CTRL1); - value &= ~GMAC_RXQCTRL_FPRQ; - value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT; - writel(value, ioaddr + GMAC_RXQ_CTRL1); - } else { - cfg->fpe_csr = 0; - } - writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS); - - value = readl(ioaddr + GMAC_INT_EN); - - if (pmac_enable) { - if (!(value & GMAC_INT_FPE_EN)) { - /* Dummy read to clear any pending masked interrupts */ - readl(ioaddr + MAC_FPE_CTRL_STS); - - value |= GMAC_INT_FPE_EN; - } - } else { - value &= ~GMAC_INT_FPE_EN; - } - - writel(value, ioaddr + GMAC_INT_EN); -} - -int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev) -{ - u32 value; - int status; - - status = FPE_EVENT_UNKNOWN; - - /* Reads from the MAC_FPE_CTRL_STS register should only be performed - * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read" - */ - value = readl(ioaddr + MAC_FPE_CTRL_STS); - - if (value & TRSP) { - status |= FPE_EVENT_TRSP; - netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n"); - } - - if (value & TVER) { - status |= FPE_EVENT_TVER; - netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n"); - } - - if (value & RRSP) { - status |= FPE_EVENT_RRSP; - netdev_dbg(dev, "FPE: Respond mPacket is received\n"); - } - - if (value & RVER) { - status |= FPE_EVENT_RVER; - netdev_dbg(dev, "FPE: Verify mPacket is received\n"); - } - - return status; -} - -void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, - enum stmmac_mpacket_type type) -{ - u32 value = cfg->fpe_csr; - - if (type == MPACKET_VERIFY) - value |= SVER; - else if (type == MPACKET_RESPONSE) - value |= SRSP; - - writel(value, ioaddr + MAC_FPE_CTRL_STS); -} - -int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr) -{ - return FIELD_GET(DWMAC5_ADD_FRAG_SZ, readl(ioaddr + MTL_FPE_CTRL_STS)); -} - -void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size) -{ - u32 value; - - value = readl(ioaddr + MTL_FPE_CTRL_STS); - writel(u32_replace_bits(value, add_frag_size, DWMAC5_ADD_FRAG_SZ), - ioaddr + MTL_FPE_CTRL_STS); -} - -#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping" -#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]" - -int dwmac5_fpe_map_preemption_class(struct net_device *ndev, - struct netlink_ext_ack *extack, u32 pclass) -{ - u32 val, offset, count, queue_weight, preemptible_txqs = 0; - struct stmmac_priv *priv = netdev_priv(ndev); - u32 num_tc = ndev->num_tc; - - if (!pclass) - goto update_mapping; - - /* DWMAC CORE4+ can not program TC:TXQ mapping to hardware. - * - * Synopsys Databook: - * "The number of Tx DMA channels is equal to the number of Tx queues, - * and is direct one-to-one mapping." - */ - for (u32 tc = 0; tc < num_tc; tc++) { - count = ndev->tc_to_txq[tc].count; - offset = ndev->tc_to_txq[tc].offset; - - if (pclass & BIT(tc)) - preemptible_txqs |= GENMASK(offset + count - 1, offset); - - /* This is 1:1 mapping, go to next TC */ - if (count == 1) - continue; - - if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) { - NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG); - return -EINVAL; - } - - queue_weight = priv->plat->tx_queues_cfg[offset].weight; - - for (u32 i = 1; i < count; i++) { - if (priv->plat->tx_queues_cfg[offset + i].weight != - queue_weight) { - NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG, - queue_weight, tc); - return -EINVAL; - } - } - } - -update_mapping: - val = readl(priv->ioaddr + MTL_FPE_CTRL_STS); - writel(u32_replace_bits(val, preemptible_txqs, DWMAC5_PREEMPTION_CLASS), - priv->ioaddr + MTL_FPE_CTRL_STS); - - return 0; -} diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h index 6c6eb6790e836a..00b151b3b6887e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h @@ -11,15 +11,6 @@ #define PRTYEN BIT(1) #define TMOUTEN BIT(0) -#define MAC_FPE_CTRL_STS 0x00000234 -#define TRSP BIT(19) -#define TVER BIT(18) -#define RRSP BIT(17) -#define RVER BIT(16) -#define SRSP BIT(2) -#define SVER BIT(1) -#define EFPE BIT(0) - #define MAC_PPS_CONTROL 0x00000b70 #define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1) #define PPS_MINIDX(x) ((x) * 8) @@ -39,12 +30,6 @@ #define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10)) #define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10)) -#define MTL_FPE_CTRL_STS 0x00000c90 -/* Preemption Classification */ -#define DWMAC5_PREEMPTION_CLASS GENMASK(15, 8) -/* Additional Fragment Size of preempted frames */ -#define DWMAC5_ADD_FRAG_SZ GENMASK(1, 0) - #define MTL_RXP_CONTROL_STATUS 0x00000ca0 #define RXPI BIT(31) #define NPE GENMASK(23, 16) @@ -108,16 +93,5 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries, int dwmac5_flex_pps_config(void __iomem *ioaddr, int index, struct stmmac_pps_cfg *cfg, bool enable, u32 sub_second_inc, u32 systime_flags); -void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, - u32 num_txq, u32 num_rxq, - bool tx_enable, bool pmac_enable); -void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, - struct stmmac_fpe_cfg *cfg, - enum stmmac_mpacket_type type); -int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev); -int dwmac5_fpe_get_add_frag_size(const void __iomem *ioaddr); -void dwmac5_fpe_set_add_frag_size(void __iomem *ioaddr, u32 add_frag_size); -int dwmac5_fpe_map_preemption_class(struct net_device *ndev, - struct netlink_ext_ack *extack, u32 pclass); #endif /* __DWMAC5_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index 6a2c7d22df1eb8..a04a790036927f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -84,8 +84,7 @@ #define XGMAC_MCBCQEN BIT(15) #define XGMAC_MCBCQ GENMASK(11, 8) #define XGMAC_MCBCQ_SHIFT 8 -#define XGMAC_RQ GENMASK(7, 4) -#define XGMAC_RQ_SHIFT 4 +#define XGMAC_FPRQ GENMASK(7, 4) #define XGMAC_UPQ GENMASK(3, 0) #define XGMAC_UPQ_SHIFT 0 #define XGMAC_RXQ_CTRL2 0x000000a8 @@ -96,6 +95,7 @@ #define XGMAC_LPIIS BIT(5) #define XGMAC_PMTIS BIT(4) #define XGMAC_INT_EN 0x000000b4 +#define XGMAC_FPEIE BIT(15) #define XGMAC_TSIE BIT(12) #define XGMAC_LPIIE BIT(5) #define XGMAC_PMTIE BIT(4) @@ -193,8 +193,6 @@ #define XGMAC_MDIO_ADDR 0x00000200 #define XGMAC_MDIO_DATA 0x00000204 #define XGMAC_MDIO_C22P 0x00000220 -#define XGMAC_FPE_CTRL_STS 0x00000280 -#define XGMAC_EFPE BIT(0) #define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8) #define XGMAC_ADDR_MAX 32 #define XGMAC_AE BIT(31) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index f519d43738b080..9a60a6e8f6331e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -8,6 +8,7 @@ #include #include #include "stmmac.h" +#include "stmmac_fpe.h" #include "stmmac_ptp.h" #include "dwxlgmac2.h" #include "dwxgmac2.h" @@ -1504,32 +1505,6 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en, writel(value, ioaddr + XGMAC_RX_CONFIG); } -static void dwxgmac3_fpe_configure(void __iomem *ioaddr, - struct stmmac_fpe_cfg *cfg, - u32 num_txq, u32 num_rxq, - bool tx_enable, bool pmac_enable) -{ - u32 value; - - if (!tx_enable) { - value = readl(ioaddr + XGMAC_FPE_CTRL_STS); - - value &= ~XGMAC_EFPE; - - writel(value, ioaddr + XGMAC_FPE_CTRL_STS); - return; - } - - value = readl(ioaddr + XGMAC_RXQ_CTRL1); - value &= ~XGMAC_RQ; - value |= (num_rxq - 1) << XGMAC_RQ_SHIFT; - writel(value, ioaddr + XGMAC_RXQ_CTRL1); - - value = readl(ioaddr + XGMAC_FPE_CTRL_STS); - value |= XGMAC_EFPE; - writel(value, ioaddr + XGMAC_FPE_CTRL_STS); -} - const struct stmmac_ops dwxgmac210_ops = { .core_init = dwxgmac2_core_init, .set_mac = dwxgmac2_set_mac, @@ -1570,7 +1545,7 @@ const struct stmmac_ops dwxgmac210_ops = { .config_l3_filter = dwxgmac2_config_l3_filter, .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, - .fpe_configure = dwxgmac3_fpe_configure, + .fpe_map_preemption_class = dwxgmac3_fpe_map_preemption_class, }; static void dwxlgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode, @@ -1627,7 +1602,7 @@ const struct stmmac_ops dwxlgmac2_ops = { .config_l3_filter = dwxgmac2_config_l3_filter, .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, - .fpe_configure = dwxgmac3_fpe_configure, + .fpe_map_preemption_class = dwxgmac3_fpe_map_preemption_class, }; int dwxgmac2_setup(struct stmmac_priv *priv) diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 88cce28b2f9805..a72d336a835080 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -6,6 +6,7 @@ #include "common.h" #include "stmmac.h" +#include "stmmac_fpe.h" #include "stmmac_ptp.h" #include "stmmac_est.h" @@ -112,6 +113,7 @@ static const struct stmmac_hwif_entry { const void *dma; const void *mac; const void *hwtimestamp; + const void *ptp; const void *mode; const void *tc; const void *mmc; @@ -132,7 +134,8 @@ static const struct stmmac_hwif_entry { .desc = NULL, .dma = &dwmac100_dma_ops, .mac = &dwmac100_ops, - .hwtimestamp = &stmmac_ptp, + .hwtimestamp = &dwmac1000_ptp, + .ptp = &dwmac1000_ptp_clock_ops, .mode = NULL, .tc = NULL, .mmc = &dwmac_mmc_ops, @@ -150,7 +153,8 @@ static const struct stmmac_hwif_entry { .desc = NULL, .dma = &dwmac1000_dma_ops, .mac = &dwmac1000_ops, - .hwtimestamp = &stmmac_ptp, + .hwtimestamp = &dwmac1000_ptp, + .ptp = &dwmac1000_ptp_clock_ops, .mode = NULL, .tc = NULL, .mmc = &dwmac_mmc_ops, @@ -170,6 +174,7 @@ static const struct stmmac_hwif_entry { .dma = &dwmac4_dma_ops, .mac = &dwmac4_ops, .hwtimestamp = &stmmac_ptp, + .ptp = &stmmac_ptp_clock_ops, .mode = NULL, .tc = &dwmac4_tc_ops, .mmc = &dwmac_mmc_ops, @@ -185,11 +190,13 @@ static const struct stmmac_hwif_entry { .ptp_off = PTP_GMAC4_OFFSET, .mmc_off = MMC_GMAC4_OFFSET, .est_off = EST_GMAC4_OFFSET, + .fpe_reg = &dwmac5_fpe_reg, }, .desc = &dwmac4_desc_ops, .dma = &dwmac4_dma_ops, .mac = &dwmac410_ops, .hwtimestamp = &stmmac_ptp, + .ptp = &stmmac_ptp_clock_ops, .mode = &dwmac4_ring_mode_ops, .tc = &dwmac510_tc_ops, .mmc = &dwmac_mmc_ops, @@ -205,11 +212,13 @@ static const struct stmmac_hwif_entry { .ptp_off = PTP_GMAC4_OFFSET, .mmc_off = MMC_GMAC4_OFFSET, .est_off = EST_GMAC4_OFFSET, + .fpe_reg = &dwmac5_fpe_reg, }, .desc = &dwmac4_desc_ops, .dma = &dwmac410_dma_ops, .mac = &dwmac410_ops, .hwtimestamp = &stmmac_ptp, + .ptp = &stmmac_ptp_clock_ops, .mode = &dwmac4_ring_mode_ops, .tc = &dwmac510_tc_ops, .mmc = &dwmac_mmc_ops, @@ -225,11 +234,13 @@ static const struct stmmac_hwif_entry { .ptp_off = PTP_GMAC4_OFFSET, .mmc_off = MMC_GMAC4_OFFSET, .est_off = EST_GMAC4_OFFSET, + .fpe_reg = &dwmac5_fpe_reg, }, .desc = &dwmac4_desc_ops, .dma = &dwmac410_dma_ops, .mac = &dwmac510_ops, .hwtimestamp = &stmmac_ptp, + .ptp = &stmmac_ptp_clock_ops, .mode = &dwmac4_ring_mode_ops, .tc = &dwmac510_tc_ops, .mmc = &dwmac_mmc_ops, @@ -246,11 +257,13 @@ static const struct stmmac_hwif_entry { .ptp_off = PTP_XGMAC_OFFSET, .mmc_off = MMC_XGMAC_OFFSET, .est_off = EST_XGMAC_OFFSET, + .fpe_reg = &dwxgmac3_fpe_reg, }, .desc = &dwxgmac210_desc_ops, .dma = &dwxgmac210_dma_ops, .mac = &dwxgmac210_ops, .hwtimestamp = &stmmac_ptp, + .ptp = &stmmac_ptp_clock_ops, .mode = NULL, .tc = &dwxgmac_tc_ops, .mmc = &dwxgmac_mmc_ops, @@ -267,11 +280,13 @@ static const struct stmmac_hwif_entry { .ptp_off = PTP_XGMAC_OFFSET, .mmc_off = MMC_XGMAC_OFFSET, .est_off = EST_XGMAC_OFFSET, + .fpe_reg = &dwxgmac3_fpe_reg, }, .desc = &dwxgmac210_desc_ops, .dma = &dwxgmac210_dma_ops, .mac = &dwxlgmac2_ops, .hwtimestamp = &stmmac_ptp, + .ptp = &stmmac_ptp_clock_ops, .mode = NULL, .tc = &dwxgmac_tc_ops, .mmc = &dwxgmac_mmc_ops, @@ -353,8 +368,11 @@ int stmmac_hwif_init(struct stmmac_priv *priv) mac->est = mac->est ? : entry->est; priv->hw = mac; + priv->fpe_cfg.reg = entry->regs.fpe_reg; priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off; priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off; + memcpy(&priv->ptp_clock_ops, entry->ptp, + sizeof(struct ptp_clock_info)); if (entry->est) priv->estaddr = priv->ioaddr + entry->regs.est_off; diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index d5a9f01ecac53f..64f8ed67dcc4ab 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -420,15 +420,6 @@ struct stmmac_ops { bool en, bool udp, bool sa, bool inv, u32 match); void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr); - void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg, - u32 num_txq, u32 num_rxq, - bool tx_enable, bool pmac_enable); - void (*fpe_send_mpacket)(void __iomem *ioaddr, - struct stmmac_fpe_cfg *cfg, - enum stmmac_mpacket_type type); - int (*fpe_irq_status)(void __iomem *ioaddr, struct net_device *dev); - int (*fpe_get_add_frag_size)(const void __iomem *ioaddr); - void (*fpe_set_add_frag_size)(void __iomem *ioaddr, u32 add_frag_size); int (*fpe_map_preemption_class)(struct net_device *ndev, struct netlink_ext_ack *extack, u32 pclass); @@ -530,16 +521,6 @@ struct stmmac_ops { stmmac_do_callback(__priv, mac, config_l4_filter, __args) #define stmmac_set_arp_offload(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, set_arp_offload, __args) -#define stmmac_fpe_configure(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, fpe_configure, __args) -#define stmmac_fpe_send_mpacket(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, fpe_send_mpacket, __args) -#define stmmac_fpe_irq_status(__priv, __args...) \ - stmmac_do_callback(__priv, mac, fpe_irq_status, __args) -#define stmmac_fpe_get_add_frag_size(__priv, __args...) \ - stmmac_do_callback(__priv, mac, fpe_get_add_frag_size, __args) -#define stmmac_fpe_set_add_frag_size(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, fpe_set_add_frag_size, __args) #define stmmac_fpe_map_preemption_class(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args) @@ -678,6 +659,7 @@ struct stmmac_est_ops { stmmac_do_void_callback(__priv, est, irq_status, __args) struct stmmac_regs_off { + const struct stmmac_fpe_reg *fpe_reg; u32 ptp_off; u32 mmc_off; u32 est_off; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index ea135203ff2e60..1d86439b8a14f9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -146,21 +146,13 @@ struct stmmac_channel { u32 index; }; -/* FPE link-partner hand-shaking mPacket type */ -enum stmmac_mpacket_type { - MPACKET_VERIFY = 0, - MPACKET_RESPONSE = 1, -}; - -#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3 -#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128 - struct stmmac_fpe_cfg { /* Serialize access to MAC Merge state between ethtool requests * and link state updates. */ spinlock_t lock; + const struct stmmac_fpe_reg *reg; u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */ enum ethtool_mm_verify_status status; @@ -420,7 +412,6 @@ bool stmmac_eee_init(struct stmmac_priv *priv); int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt); int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size); int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled); -void stmmac_fpe_apply(struct stmmac_priv *priv); static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 2a37592a628101..1d77389ce95332 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -17,9 +17,9 @@ #include #include "stmmac.h" +#include "stmmac_fpe.h" #include "dwmac_dma.h" #include "dwxgmac2.h" -#include "dwmac5.h" #define REG_SPACE_SIZE 0x1060 #define GMAC4_REG_SPACE_SIZE 0x116C @@ -1271,7 +1271,7 @@ static int stmmac_get_mm(struct net_device *ndev, unsigned long flags; u32 frag_size; - if (!priv->dma_cap.fpesel) + if (!stmmac_fpe_supported(priv)) return -EOPNOTSUPP; spin_lock_irqsave(&priv->fpe_cfg.lock, flags); @@ -1294,7 +1294,7 @@ static int stmmac_get_mm(struct net_device *ndev, else state->tx_active = false; - frag_size = stmmac_fpe_get_add_frag_size(priv, priv->ioaddr); + frag_size = stmmac_fpe_get_add_frag_size(priv); state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(frag_size); spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags); @@ -1329,7 +1329,7 @@ static int stmmac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, if (!cfg->verify_enabled) fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; - stmmac_fpe_set_add_frag_size(priv, priv->ioaddr, frag_size); + stmmac_fpe_set_add_frag_size(priv, frag_size); stmmac_fpe_apply(priv); spin_unlock_irqrestore(&fpe_cfg->lock, flags); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c new file mode 100644 index 00000000000000..3a4bee029c7f65 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Furong Xu <0x1207@gmail.com> + * stmmac FPE(802.3 Qbu) handling + */ +#include "stmmac.h" +#include "stmmac_fpe.h" +#include "dwmac4.h" +#include "dwmac5.h" +#include "dwxgmac2.h" + +#define GMAC5_MAC_FPE_CTRL_STS 0x00000234 +#define XGMAC_MAC_FPE_CTRL_STS 0x00000280 + +#define GMAC5_MTL_FPE_CTRL_STS 0x00000c90 +#define XGMAC_MTL_FPE_CTRL_STS 0x00001090 +/* Preemption Classification */ +#define FPE_MTL_PREEMPTION_CLASS GENMASK(15, 8) +/* Additional Fragment Size of preempted frames */ +#define FPE_MTL_ADD_FRAG_SZ GENMASK(1, 0) + +#define STMMAC_MAC_FPE_CTRL_STS_TRSP BIT(19) +#define STMMAC_MAC_FPE_CTRL_STS_TVER BIT(18) +#define STMMAC_MAC_FPE_CTRL_STS_RRSP BIT(17) +#define STMMAC_MAC_FPE_CTRL_STS_RVER BIT(16) +#define STMMAC_MAC_FPE_CTRL_STS_SRSP BIT(2) +#define STMMAC_MAC_FPE_CTRL_STS_SVER BIT(1) +#define STMMAC_MAC_FPE_CTRL_STS_EFPE BIT(0) + +/* FPE link-partner hand-shaking mPacket type */ +enum stmmac_mpacket_type { + MPACKET_VERIFY = 0, + MPACKET_RESPONSE = 1, +}; + +struct stmmac_fpe_reg { + const u32 mac_fpe_reg; /* offset of MAC_FPE_CTRL_STS */ + const u32 mtl_fpe_reg; /* offset of MTL_FPE_CTRL_STS */ + const u32 rxq_ctrl1_reg; /* offset of MAC_RxQ_Ctrl1 */ + const u32 fprq_mask; /* Frame Preemption Residue Queue */ + const u32 int_en_reg; /* offset of MAC_Interrupt_Enable */ + const u32 int_en_bit; /* Frame Preemption Interrupt Enable */ +}; + +bool stmmac_fpe_supported(struct stmmac_priv *priv) +{ + return priv->dma_cap.fpesel && priv->fpe_cfg.reg && + priv->hw->mac->fpe_map_preemption_class; +} + +static void stmmac_fpe_configure(struct stmmac_priv *priv, bool tx_enable, + bool pmac_enable) +{ + struct stmmac_fpe_cfg *cfg = &priv->fpe_cfg; + const struct stmmac_fpe_reg *reg = cfg->reg; + u32 num_rxq = priv->plat->rx_queues_to_use; + void __iomem *ioaddr = priv->ioaddr; + u32 value; + + if (tx_enable) { + cfg->fpe_csr = STMMAC_MAC_FPE_CTRL_STS_EFPE; + value = readl(ioaddr + reg->rxq_ctrl1_reg); + value &= ~reg->fprq_mask; + /* Keep this SHIFT, FIELD_PREP() expects a constant mask :-/ */ + value |= (num_rxq - 1) << __ffs(reg->fprq_mask); + writel(value, ioaddr + reg->rxq_ctrl1_reg); + } else { + cfg->fpe_csr = 0; + } + writel(cfg->fpe_csr, ioaddr + reg->mac_fpe_reg); + + value = readl(ioaddr + reg->int_en_reg); + + if (pmac_enable) { + if (!(value & reg->int_en_bit)) { + /* Dummy read to clear any pending masked interrupts */ + readl(ioaddr + reg->mac_fpe_reg); + + value |= reg->int_en_bit; + } + } else { + value &= ~reg->int_en_bit; + } + + writel(value, ioaddr + reg->int_en_reg); +} + +static void stmmac_fpe_send_mpacket(struct stmmac_priv *priv, + enum stmmac_mpacket_type type) +{ + const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg; + void __iomem *ioaddr = priv->ioaddr; + u32 value = priv->fpe_cfg.fpe_csr; + + if (type == MPACKET_VERIFY) + value |= STMMAC_MAC_FPE_CTRL_STS_SVER; + else if (type == MPACKET_RESPONSE) + value |= STMMAC_MAC_FPE_CTRL_STS_SRSP; + + writel(value, ioaddr + reg->mac_fpe_reg); +} + +static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status) +{ + struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; + + /* This is interrupt context, just spin_lock() */ + spin_lock(&fpe_cfg->lock); + + if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN) + goto unlock_out; + + /* LP has sent verify mPacket */ + if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER) + stmmac_fpe_send_mpacket(priv, MPACKET_RESPONSE); + + /* Local has sent verify mPacket */ + if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER && + fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING; + + /* LP has sent response mPacket */ + if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP && + fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING) + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED; + +unlock_out: + spin_unlock(&fpe_cfg->lock); +} + +void stmmac_fpe_irq_status(struct stmmac_priv *priv) +{ + const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg; + void __iomem *ioaddr = priv->ioaddr; + struct net_device *dev = priv->dev; + int status = FPE_EVENT_UNKNOWN; + u32 value; + + /* Reads from the MAC_FPE_CTRL_STS register should only be performed + * here, since the status flags of MAC_FPE_CTRL_STS are "clear on read" + */ + value = readl(ioaddr + reg->mac_fpe_reg); + + if (value & STMMAC_MAC_FPE_CTRL_STS_TRSP) { + status |= FPE_EVENT_TRSP; + netdev_dbg(dev, "FPE: Respond mPacket is transmitted\n"); + } + + if (value & STMMAC_MAC_FPE_CTRL_STS_TVER) { + status |= FPE_EVENT_TVER; + netdev_dbg(dev, "FPE: Verify mPacket is transmitted\n"); + } + + if (value & STMMAC_MAC_FPE_CTRL_STS_RRSP) { + status |= FPE_EVENT_RRSP; + netdev_dbg(dev, "FPE: Respond mPacket is received\n"); + } + + if (value & STMMAC_MAC_FPE_CTRL_STS_RVER) { + status |= FPE_EVENT_RVER; + netdev_dbg(dev, "FPE: Verify mPacket is received\n"); + } + + stmmac_fpe_event_status(priv, status); +} + +/** + * stmmac_fpe_verify_timer - Timer for MAC Merge verification + * @t: timer_list struct containing private info + * + * Verify the MAC Merge capability in the local TX direction, by + * transmitting Verify mPackets up to 3 times. Wait until link + * partner responds with a Response mPacket, otherwise fail. + */ +static void stmmac_fpe_verify_timer(struct timer_list *t) +{ + struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer); + struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv, + fpe_cfg); + unsigned long flags; + bool rearm = false; + + spin_lock_irqsave(&fpe_cfg->lock, flags); + + switch (fpe_cfg->status) { + case ETHTOOL_MM_VERIFY_STATUS_INITIAL: + case ETHTOOL_MM_VERIFY_STATUS_VERIFYING: + if (fpe_cfg->verify_retries != 0) { + stmmac_fpe_send_mpacket(priv, MPACKET_VERIFY); + rearm = true; + } else { + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED; + } + + fpe_cfg->verify_retries--; + break; + + case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED: + stmmac_fpe_configure(priv, true, true); + break; + + default: + break; + } + + if (rearm) { + mod_timer(&fpe_cfg->verify_timer, + jiffies + msecs_to_jiffies(fpe_cfg->verify_time)); + } + + spin_unlock_irqrestore(&fpe_cfg->lock, flags); +} + +static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg) +{ + if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled && + fpe_cfg->verify_enabled && + fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED && + fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) { + timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0); + mod_timer(&fpe_cfg->verify_timer, jiffies); + } +} + +void stmmac_fpe_init(struct stmmac_priv *priv) +{ + priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES; + priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS; + priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; + timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0); + spin_lock_init(&priv->fpe_cfg.lock); + + if ((!priv->fpe_cfg.reg || !priv->hw->mac->fpe_map_preemption_class) && + priv->dma_cap.fpesel) + dev_info(priv->device, "FPE is not supported by driver.\n"); +} + +void stmmac_fpe_apply(struct stmmac_priv *priv) +{ + struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; + + /* If verification is disabled, configure FPE right away. + * Otherwise let the timer code do it. + */ + if (!fpe_cfg->verify_enabled) { + stmmac_fpe_configure(priv, fpe_cfg->tx_enabled, + fpe_cfg->pmac_enabled); + } else { + fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL; + fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES; + + if (netif_running(priv->dev)) + stmmac_fpe_verify_timer_arm(fpe_cfg); + } +} + +void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up) +{ + struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; + unsigned long flags; + + timer_shutdown_sync(&fpe_cfg->verify_timer); + + spin_lock_irqsave(&fpe_cfg->lock, flags); + + if (is_up && fpe_cfg->pmac_enabled) { + /* VERIFY process requires pmac enabled when NIC comes up */ + stmmac_fpe_configure(priv, false, true); + + /* New link => maybe new partner => new verification process */ + stmmac_fpe_apply(priv); + } else { + /* No link => turn off EFPE */ + stmmac_fpe_configure(priv, false, false); + } + + spin_unlock_irqrestore(&fpe_cfg->lock, flags); +} + +int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv) +{ + const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg; + void __iomem *ioaddr = priv->ioaddr; + + return FIELD_GET(FPE_MTL_ADD_FRAG_SZ, readl(ioaddr + reg->mtl_fpe_reg)); +} + +void stmmac_fpe_set_add_frag_size(struct stmmac_priv *priv, u32 add_frag_size) +{ + const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg; + void __iomem *ioaddr = priv->ioaddr; + u32 value; + + value = readl(ioaddr + reg->mtl_fpe_reg); + writel(u32_replace_bits(value, add_frag_size, FPE_MTL_ADD_FRAG_SZ), + ioaddr + reg->mtl_fpe_reg); +} + +#define ALG_ERR_MSG "TX algorithm SP is not suitable for one-to-many mapping" +#define WEIGHT_ERR_MSG "TXQ weight %u differs across other TXQs in TC: [%u]" + +int dwmac5_fpe_map_preemption_class(struct net_device *ndev, + struct netlink_ext_ack *extack, u32 pclass) +{ + u32 val, offset, count, queue_weight, preemptible_txqs = 0; + struct stmmac_priv *priv = netdev_priv(ndev); + int num_tc = netdev_get_num_tc(ndev); + + if (!pclass) + goto update_mapping; + + /* DWMAC CORE4+ can not program TC:TXQ mapping to hardware. + * + * Synopsys Databook: + * "The number of Tx DMA channels is equal to the number of Tx queues, + * and is direct one-to-one mapping." + */ + for (u32 tc = 0; tc < num_tc; tc++) { + count = ndev->tc_to_txq[tc].count; + offset = ndev->tc_to_txq[tc].offset; + + if (pclass & BIT(tc)) + preemptible_txqs |= GENMASK(offset + count - 1, offset); + + /* This is 1:1 mapping, go to next TC */ + if (count == 1) + continue; + + if (priv->plat->tx_sched_algorithm == MTL_TX_ALGORITHM_SP) { + NL_SET_ERR_MSG_MOD(extack, ALG_ERR_MSG); + return -EINVAL; + } + + queue_weight = priv->plat->tx_queues_cfg[offset].weight; + + for (u32 i = 1; i < count; i++) { + if (priv->plat->tx_queues_cfg[offset + i].weight != + queue_weight) { + NL_SET_ERR_MSG_FMT_MOD(extack, WEIGHT_ERR_MSG, + queue_weight, tc); + return -EINVAL; + } + } + } + +update_mapping: + val = readl(priv->ioaddr + GMAC5_MTL_FPE_CTRL_STS); + writel(u32_replace_bits(val, preemptible_txqs, FPE_MTL_PREEMPTION_CLASS), + priv->ioaddr + GMAC5_MTL_FPE_CTRL_STS); + + return 0; +} + +int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev, + struct netlink_ext_ack *extack, u32 pclass) +{ + u32 val, offset, count, preemptible_txqs = 0; + struct stmmac_priv *priv = netdev_priv(ndev); + int num_tc = netdev_get_num_tc(ndev); + + if (!num_tc) { + /* Restore default TC:Queue mapping */ + for (u32 i = 0; i < priv->plat->tx_queues_to_use; i++) { + val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i)); + writel(u32_replace_bits(val, i, XGMAC_Q2TCMAP), + priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i)); + } + } + + /* Synopsys Databook: + * "All Queues within a traffic class are selected in a round robin + * fashion (when packets are available) when the traffic class is + * selected by the scheduler for packet transmission. This is true for + * any of the scheduling algorithms." + */ + for (u32 tc = 0; tc < num_tc; tc++) { + count = ndev->tc_to_txq[tc].count; + offset = ndev->tc_to_txq[tc].offset; + + if (pclass & BIT(tc)) + preemptible_txqs |= GENMASK(offset + count - 1, offset); + + for (u32 i = 0; i < count; i++) { + val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i)); + writel(u32_replace_bits(val, tc, XGMAC_Q2TCMAP), + priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i)); + } + } + + val = readl(priv->ioaddr + XGMAC_MTL_FPE_CTRL_STS); + writel(u32_replace_bits(val, preemptible_txqs, FPE_MTL_PREEMPTION_CLASS), + priv->ioaddr + XGMAC_MTL_FPE_CTRL_STS); + + return 0; +} + +const struct stmmac_fpe_reg dwmac5_fpe_reg = { + .mac_fpe_reg = GMAC5_MAC_FPE_CTRL_STS, + .mtl_fpe_reg = GMAC5_MTL_FPE_CTRL_STS, + .rxq_ctrl1_reg = GMAC_RXQ_CTRL1, + .fprq_mask = GMAC_RXQCTRL_FPRQ, + .int_en_reg = GMAC_INT_EN, + .int_en_bit = GMAC_INT_FPE_EN, +}; + +const struct stmmac_fpe_reg dwxgmac3_fpe_reg = { + .mac_fpe_reg = XGMAC_MAC_FPE_CTRL_STS, + .mtl_fpe_reg = XGMAC_MTL_FPE_CTRL_STS, + .rxq_ctrl1_reg = XGMAC_RXQ_CTRL1, + .fprq_mask = XGMAC_FPRQ, + .int_en_reg = XGMAC_INT_EN, + .int_en_bit = XGMAC_FPEIE, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h new file mode 100644 index 00000000000000..b884eac7142d02 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Furong Xu <0x1207@gmail.com> + * stmmac FPE(802.3 Qbu) handling + */ +#ifndef _STMMAC_FPE_H_ +#define _STMMAC_FPE_H_ + +#include +#include + +#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3 +#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128 + +struct stmmac_priv; + +void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up); +bool stmmac_fpe_supported(struct stmmac_priv *priv); +void stmmac_fpe_init(struct stmmac_priv *priv); +void stmmac_fpe_apply(struct stmmac_priv *priv); +void stmmac_fpe_irq_status(struct stmmac_priv *priv); +int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv); +void stmmac_fpe_set_add_frag_size(struct stmmac_priv *priv, u32 add_frag_size); + +int dwmac5_fpe_map_preemption_class(struct net_device *ndev, + struct netlink_ext_ack *extack, u32 pclass); +int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev, + struct netlink_ext_ack *extack, u32 pclass); + +extern const struct stmmac_fpe_reg dwmac5_fpe_reg; +extern const struct stmmac_fpe_reg dwxgmac3_fpe_reg; + +#endif diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c index 5ef52ef2698fbe..0f59aa98260404 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c @@ -18,9 +18,22 @@ #include "dwmac4.h" #include "stmmac.h" +#define STMMAC_HWTS_CFG_MASK (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | \ + PTP_TCR_TSINIT | PTP_TCR_TSUPDT | \ + PTP_TCR_TSCTRLSSR | PTP_TCR_SNAPTYPSEL_1 | \ + PTP_TCR_TSIPV4ENA | PTP_TCR_TSIPV6ENA | \ + PTP_TCR_TSEVNTENA | PTP_TCR_TSMSTRENA | \ + PTP_TCR_TSVER2ENA | PTP_TCR_TSIPENA | \ + PTP_TCR_TSTRIG | PTP_TCR_TSENALL) + static void config_hw_tstamping(void __iomem *ioaddr, u32 data) { - writel(data, ioaddr + PTP_TCR); + u32 regval = readl(ioaddr + PTP_TCR); + + regval &= ~STMMAC_HWTS_CFG_MASK; + regval |= data; + + writel(regval, ioaddr + PTP_TCR); } static void config_sub_second_increment(void __iomem *ioaddr, @@ -269,3 +282,14 @@ const struct stmmac_hwtimestamp stmmac_ptp = { .timestamp_interrupt = timestamp_interrupt, .hwtstamp_correct_latency = hwtstamp_correct_latency, }; + +const struct stmmac_hwtimestamp dwmac1000_ptp = { + .config_hw_tstamping = config_hw_tstamping, + .init_systime = init_systime, + .config_sub_second_increment = config_sub_second_increment, + .config_addend = config_addend, + .adjust_systime = adjust_systime, + .get_systime = get_systime, + .get_ptptime = dwmac1000_get_ptptime, + .timestamp_interrupt = dwmac1000_timestamp_interrupt, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 7bf275f127c9d7..c81ea8cdfe6eb8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -43,6 +43,7 @@ #include #include #include "stmmac_ptp.h" +#include "stmmac_fpe.h" #include "stmmac.h" #include "stmmac_xdp.h" #include @@ -966,35 +967,6 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, /* Nothing to do, xpcs_config() handles everything */ } -static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up) -{ - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; - unsigned long flags; - - timer_shutdown_sync(&fpe_cfg->verify_timer); - - spin_lock_irqsave(&fpe_cfg->lock, flags); - - if (is_up && fpe_cfg->pmac_enabled) { - /* VERIFY process requires pmac enabled when NIC comes up */ - stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg, - priv->plat->tx_queues_to_use, - priv->plat->rx_queues_to_use, - false, true); - - /* New link => maybe new partner => new verification process */ - stmmac_fpe_apply(priv); - } else { - /* No link => turn off EFPE */ - stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg, - priv->plat->tx_queues_to_use, - priv->plat->rx_queues_to_use, - false, false); - } - - spin_unlock_irqrestore(&fpe_cfg->lock, flags); -} - static void stmmac_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { @@ -1006,7 +978,7 @@ static void stmmac_mac_link_down(struct phylink_config *config, priv->eee_enabled = stmmac_eee_init(priv); stmmac_set_eee_pls(priv, priv->hw, false); - if (priv->dma_cap.fpesel) + if (stmmac_fpe_supported(priv)) stmmac_fpe_link_state_handle(priv, false); } @@ -1120,7 +1092,7 @@ static void stmmac_mac_link_up(struct phylink_config *config, stmmac_set_eee_pls(priv, priv->hw, true); } - if (priv->dma_cap.fpesel) + if (stmmac_fpe_supported(priv)) stmmac_fpe_link_state_handle(priv, true); if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY) @@ -1205,6 +1177,9 @@ static int stmmac_init_phy(struct net_device *dev) return -ENODEV; } + if (priv->dma_cap.eee) + phy_support_eee(phydev); + ret = phylink_connect_phy(priv->phylink, phydev); } else { fwnode_handle_put(phy_fwnode); @@ -4069,7 +4044,7 @@ static int stmmac_release(struct net_device *dev) stmmac_release_ptp(priv); - if (priv->dma_cap.fpesel) + if (stmmac_fpe_supported(priv)) timer_shutdown_sync(&priv->fpe_cfg.verify_timer); pm_runtime_put(priv->device); @@ -4217,8 +4192,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) struct stmmac_txq_stats *txq_stats; struct stmmac_tx_queue *tx_q; u32 pay_len, mss, queue; + dma_addr_t tso_des, des; u8 proto_hdr_len, hdr; - dma_addr_t des; bool set_ic; int i; @@ -4314,14 +4289,15 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) /* If needed take extra descriptors to fill the remaining payload */ tmp_pay_len = pay_len - TSO_MAX_BUFF_SIZE; + tso_des = des; } else { stmmac_set_desc_addr(priv, first, des); tmp_pay_len = pay_len; - des += proto_hdr_len; + tso_des = des + proto_hdr_len; pay_len = 0; } - stmmac_tso_allocator(priv, des, tmp_pay_len, (nfrags == 0), queue); + stmmac_tso_allocator(priv, tso_des, tmp_pay_len, (nfrags == 0), queue); /* In case two or more DMA transmit descriptors are allocated for this * non-paged SKB data, the DMA buffer address should be saved to @@ -5966,35 +5942,6 @@ static int stmmac_set_features(struct net_device *netdev, return 0; } -static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status) -{ - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; - - /* This is interrupt context, just spin_lock() */ - spin_lock(&fpe_cfg->lock); - - if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN) - goto unlock_out; - - /* LP has sent verify mPacket */ - if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER) - stmmac_fpe_send_mpacket(priv, priv->ioaddr, fpe_cfg, - MPACKET_RESPONSE); - - /* Local has sent verify mPacket */ - if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER && - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING; - - /* LP has sent response mPacket */ - if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP && - fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING) - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED; - -unlock_out: - spin_unlock(&fpe_cfg->lock); -} - static void stmmac_common_interrupt(struct stmmac_priv *priv) { u32 rx_cnt = priv->plat->rx_queues_to_use; @@ -6013,12 +5960,8 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) stmmac_est_irq_status(priv, priv, priv->dev, &priv->xstats, tx_cnt); - if (priv->dma_cap.fpesel) { - int status = stmmac_fpe_irq_status(priv, priv->ioaddr, - priv->dev); - - stmmac_fpe_event_status(priv, status); - } + if (stmmac_fpe_supported(priv)) + stmmac_fpe_irq_status(priv); /* To handle GMAC own interrupts */ if ((priv->plat->has_gmac) || xmac) { @@ -7350,90 +7293,6 @@ int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size) return ret; } -/** - * stmmac_fpe_verify_timer - Timer for MAC Merge verification - * @t: timer_list struct containing private info - * - * Verify the MAC Merge capability in the local TX direction, by - * transmitting Verify mPackets up to 3 times. Wait until link - * partner responds with a Response mPacket, otherwise fail. - */ -static void stmmac_fpe_verify_timer(struct timer_list *t) -{ - struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer); - struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv, - fpe_cfg); - unsigned long flags; - bool rearm = false; - - spin_lock_irqsave(&fpe_cfg->lock, flags); - - switch (fpe_cfg->status) { - case ETHTOOL_MM_VERIFY_STATUS_INITIAL: - case ETHTOOL_MM_VERIFY_STATUS_VERIFYING: - if (fpe_cfg->verify_retries != 0) { - stmmac_fpe_send_mpacket(priv, priv->ioaddr, - fpe_cfg, MPACKET_VERIFY); - rearm = true; - } else { - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED; - } - - fpe_cfg->verify_retries--; - break; - - case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED: - stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg, - priv->plat->tx_queues_to_use, - priv->plat->rx_queues_to_use, - true, true); - break; - - default: - break; - } - - if (rearm) { - mod_timer(&fpe_cfg->verify_timer, - jiffies + msecs_to_jiffies(fpe_cfg->verify_time)); - } - - spin_unlock_irqrestore(&fpe_cfg->lock, flags); -} - -static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg) -{ - if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled && - fpe_cfg->verify_enabled && - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED && - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) { - timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0); - mod_timer(&fpe_cfg->verify_timer, jiffies); - } -} - -void stmmac_fpe_apply(struct stmmac_priv *priv) -{ - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; - - /* If verification is disabled, configure FPE right away. - * Otherwise let the timer code do it. - */ - if (!fpe_cfg->verify_enabled) { - stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg, - priv->plat->tx_queues_to_use, - priv->plat->rx_queues_to_use, - fpe_cfg->tx_enabled, - fpe_cfg->pmac_enabled); - } else { - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL; - fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES; - - if (netif_running(priv->dev)) - stmmac_fpe_verify_timer_arm(fpe_cfg); - } -} - static int stmmac_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp) { const struct stmmac_xdp_buff *ctx = (void *)_ctx; @@ -7712,11 +7571,7 @@ int stmmac_dvr_probe(struct device *device, mutex_init(&priv->lock); - priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES; - priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS; - priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; - timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0); - spin_lock_init(&priv->fpe_cfg.lock); + stmmac_fpe_init(priv); /* If a specific clk_csr value is passed from the platform * this means that the CSR Clock Range selection cannot be @@ -7891,7 +7746,7 @@ int stmmac_suspend(struct device *dev) } rtnl_unlock(); - if (priv->dma_cap.fpesel) + if (stmmac_fpe_supported(priv)) timer_shutdown_sync(&priv->fpe_cfg.verify_timer); priv->speed = SPEED_UNKNOWN; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 03f90676b3ad8c..0c7d81ddd4406d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -500,23 +500,22 @@ int stmmac_pcs_setup(struct net_device *ndev) struct fwnode_handle *devnode, *pcsnode; struct dw_xpcs *xpcs = NULL; struct stmmac_priv *priv; - int addr, mode, ret; + int addr, ret; priv = netdev_priv(ndev); - mode = priv->plat->phy_interface; devnode = priv->plat->port_node; if (priv->plat->pcs_init) { ret = priv->plat->pcs_init(priv); } else if (fwnode_property_present(devnode, "pcs-handle")) { pcsnode = fwnode_find_reference(devnode, "pcs-handle", 0); - xpcs = xpcs_create_fwnode(pcsnode, mode); + xpcs = xpcs_create_fwnode(pcsnode); fwnode_handle_put(pcsnode); ret = PTR_ERR_OR_ZERO(xpcs); } else if (priv->plat->mdio_bus_data && priv->plat->mdio_bus_data->pcs_mask) { addr = ffs(priv->plat->mdio_bus_data->pcs_mask) - 1; - xpcs = xpcs_create_mdiodev(priv->mii, addr, mode); + xpcs = xpcs_create_mdiodev(priv->mii, addr); ret = PTR_ERR_OR_ZERO(xpcs); } else { return 0; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index ad868e8d195d59..3ac32444e49220 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -522,6 +522,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) if (of_device_is_compatible(np, "st,spear600-gmac") || of_device_is_compatible(np, "snps,dwmac-3.50a") || of_device_is_compatible(np, "snps,dwmac-3.70a") || + of_device_is_compatible(np, "snps,dwmac-3.72a") || of_device_is_compatible(np, "snps,dwmac")) { /* Note that the max-frame-size parameter as defined in the * ePAPR v1.1 spec is defined as max-frame-size, it's diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index a6b1de9a251dd4..429b2d357813c8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -9,7 +9,6 @@ *******************************************************************************/ #include "stmmac.h" #include "stmmac_ptp.h" -#include "dwmac4.h" /** * stmmac_adjust_freq @@ -265,7 +264,7 @@ static int stmmac_getcrosststamp(struct ptp_clock_info *ptp, } /* structure describing a PTP hardware clock */ -static struct ptp_clock_info stmmac_ptp_clock_ops = { +const struct ptp_clock_info stmmac_ptp_clock_ops = { .owner = THIS_MODULE, .name = "stmmac ptp", .max_adj = 62500000, @@ -282,6 +281,24 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = { .getcrosststamp = stmmac_getcrosststamp, }; +/* structure describing a PTP hardware clock */ +const struct ptp_clock_info dwmac1000_ptp_clock_ops = { + .owner = THIS_MODULE, + .name = "stmmac ptp", + .max_adj = 62500000, + .n_alarm = 0, + .n_ext_ts = 1, + .n_per_out = 0, + .n_pins = 0, + .pps = 0, + .adjfine = stmmac_adjust_freq, + .adjtime = stmmac_adjust_time, + .gettime64 = stmmac_get_time, + .settime64 = stmmac_set_time, + .enable = dwmac1000_ptp_enable, + .getcrosststamp = stmmac_getcrosststamp, +}; + /** * stmmac_ptp_register * @priv: driver private structure @@ -298,20 +315,25 @@ void stmmac_ptp_register(struct stmmac_priv *priv) priv->pps[i].available = true; } - if (priv->plat->ptp_max_adj) - stmmac_ptp_clock_ops.max_adj = priv->plat->ptp_max_adj; - /* Calculate the clock domain crossing (CDC) error if necessary */ priv->plat->cdc_error_adj = 0; if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate) priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate; - stmmac_ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num; - stmmac_ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n; + /* Update the ptp clock parameters based on feature discovery, when + * available + */ + if (priv->dma_cap.pps_out_num) + priv->ptp_clock_ops.n_per_out = priv->dma_cap.pps_out_num; + + if (priv->dma_cap.aux_snapshot_n) + priv->ptp_clock_ops.n_ext_ts = priv->dma_cap.aux_snapshot_n; + + if (priv->plat->ptp_max_adj) + priv->ptp_clock_ops.max_adj = priv->plat->ptp_max_adj; rwlock_init(&priv->ptp_lock); mutex_init(&priv->aux_ts_lock); - priv->ptp_clock_ops = stmmac_ptp_clock_ops; priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops, priv->device); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h index fce3fba2ffd240..4cc70480ce0f0d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h @@ -94,4 +94,14 @@ enum aux_snapshot { AUX_SNAPSHOT3 = 0x80, }; +struct ptp_clock_info; +struct ptp_clock_request; +struct stmmac_priv; + +int dwmac1000_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on); + +void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time); +void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv); + #endif /* __STMMAC_PTP_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 75ad2da1a37f1a..6a79e6a111ed90 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -1290,8 +1290,8 @@ const struct stmmac_tc_ops dwxgmac_tc_ops = { .setup_cls_u32 = tc_setup_cls_u32, .setup_cbs = tc_setup_cbs, .setup_cls = tc_setup_cls, - .setup_taprio = tc_setup_taprio_without_fpe, + .setup_taprio = tc_setup_taprio, .setup_etf = tc_setup_etf, .query_caps = tc_query_caps, - .setup_mqprio = tc_setup_mqprio_unimplemented, + .setup_mqprio = tc_setup_dwmac510_mqprio, }; diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 41a27ae58cedf6..df6d35d41b976a 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -10182,7 +10182,7 @@ static struct platform_driver niu_of_driver = { .of_match_table = niu_match, }, .probe = niu_of_probe, - .remove_new = niu_of_remove, + .remove = niu_of_remove, }; #endif /* CONFIG_SPARC64 */ diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c index 16c86b13c185c7..bbb3a6ca19ed6a 100644 --- a/drivers/net/ethernet/sun/sunbmac.c +++ b/drivers/net/ethernet/sun/sunbmac.c @@ -1272,7 +1272,7 @@ static struct platform_driver bigmac_sbus_driver = { .of_match_table = bigmac_sbus_match, }, .probe = bigmac_sbus_probe, - .remove_new = bigmac_sbus_remove, + .remove = bigmac_sbus_remove, }; module_platform_driver(bigmac_sbus_driver); diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c index aedd13c9422505..2920341b14a063 100644 --- a/drivers/net/ethernet/sun/sunqe.c +++ b/drivers/net/ethernet/sun/sunqe.c @@ -965,7 +965,7 @@ static struct platform_driver qec_sbus_driver = { .of_match_table = qec_sbus_match, }, .probe = qec_sbus_probe, - .remove_new = qec_sbus_remove, + .remove = qec_sbus_remove, }; static int __init qec_init(void) diff --git a/drivers/net/ethernet/sunplus/spl2sw_driver.c b/drivers/net/ethernet/sunplus/spl2sw_driver.c index 391a1bc7f44639..721d8ed3f30205 100644 --- a/drivers/net/ethernet/sunplus/spl2sw_driver.c +++ b/drivers/net/ethernet/sunplus/spl2sw_driver.c @@ -549,7 +549,7 @@ MODULE_DEVICE_TABLE(of, spl2sw_of_match); static struct platform_driver spl2sw_driver = { .probe = spl2sw_probe, - .remove_new = spl2sw_remove, + .remove = spl2sw_remove, .driver = { .name = "sp7021_emac", .of_match_table = spl2sw_of_match, diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index ba6db61dd227c4..14e1df721f2e80 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -71,6 +71,8 @@ #define AM65_CPSW_PORT_REG_RX_PRI_MAP 0x020 #define AM65_CPSW_PORT_REG_RX_MAXLEN 0x024 +#define AM65_CPSW_PORTN_REG_CTL 0x004 +#define AM65_CPSW_PORTN_REG_DSCP_MAP 0x120 #define AM65_CPSW_PORTN_REG_SA_L 0x308 #define AM65_CPSW_PORTN_REG_SA_H 0x30c #define AM65_CPSW_PORTN_REG_TS_CTL 0x310 @@ -94,6 +96,10 @@ /* AM65_CPSW_PORT_REG_PRI_CTL */ #define AM65_CPSW_PORT_REG_PRI_CTL_RX_PTYPE_RROBIN BIT(8) +/* AM65_CPSW_PN_REG_CTL */ +#define AM65_CPSW_PN_REG_CTL_DSCP_IPV4_EN BIT(1) +#define AM65_CPSW_PN_REG_CTL_DSCP_IPV6_EN BIT(2) + /* AM65_CPSW_PN_TS_CTL register fields */ #define AM65_CPSW_PN_TS_CTL_TX_ANX_F_EN BIT(4) #define AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN BIT(5) @@ -176,6 +182,99 @@ static void am65_cpsw_port_set_sl_mac(struct am65_cpsw_port *slave, writel(mac_lo, slave->port_base + AM65_CPSW_PORTN_REG_SA_L); } +#define AM65_CPSW_DSCP_MAX GENMASK(5, 0) +#define AM65_CPSW_PRI_MAX GENMASK(2, 0) +#define AM65_CPSW_DSCP_PRI_PER_REG 8 +#define AM65_CPSW_DSCP_PRI_SIZE 4 /* in bits */ +static int am65_cpsw_port_set_dscp_map(struct am65_cpsw_port *slave, u8 dscp, u8 pri) +{ + int reg_ofs; + int bit_ofs; + u32 val; + + if (dscp > AM65_CPSW_DSCP_MAX) + return -EINVAL; + + if (pri > AM65_CPSW_PRI_MAX) + return -EINVAL; + + /* 32-bit register offset to this dscp */ + reg_ofs = (dscp / AM65_CPSW_DSCP_PRI_PER_REG) * 4; + /* bit field offset to this dscp */ + bit_ofs = AM65_CPSW_DSCP_PRI_SIZE * (dscp % AM65_CPSW_DSCP_PRI_PER_REG); + + val = readl(slave->port_base + AM65_CPSW_PORTN_REG_DSCP_MAP + reg_ofs); + val &= ~(AM65_CPSW_PRI_MAX << bit_ofs); /* clear */ + val |= pri << bit_ofs; /* set */ + writel(val, slave->port_base + AM65_CPSW_PORTN_REG_DSCP_MAP + reg_ofs); + + return 0; +} + +static void am65_cpsw_port_enable_dscp_map(struct am65_cpsw_port *slave) +{ + int dscp, pri; + u32 val; + + /* Default DSCP to User Priority mapping as per: + * https://datatracker.ietf.org/doc/html/rfc8325#section-4.3 + * and + * https://datatracker.ietf.org/doc/html/rfc8622#section-11 + */ + for (dscp = 0; dscp <= AM65_CPSW_DSCP_MAX; dscp++) { + switch (dscp) { + case 56: /* CS7 */ + case 48: /* CS6 */ + pri = 7; + break; + case 46: /* EF */ + case 44: /* VA */ + pri = 6; + break; + case 40: /* CS5 */ + pri = 5; + break; + case 34: /* AF41 */ + case 36: /* AF42 */ + case 38: /* AF43 */ + case 32: /* CS4 */ + case 26: /* AF31 */ + case 28: /* AF32 */ + case 30: /* AF33 */ + case 24: /* CS3 */ + pri = 4; + break; + case 18: /* AF21 */ + case 20: /* AF22 */ + case 22: /* AF23 */ + pri = 3; + break; + case 16: /* CS2 */ + case 10: /* AF11 */ + case 12: /* AF12 */ + case 14: /* AF13 */ + case 0: /* DF */ + pri = 0; + break; + case 8: /* CS1 */ + case 1: /* LE */ + pri = 1; + break; + default: + pri = 0; + break; + } + + am65_cpsw_port_set_dscp_map(slave, dscp, pri); + } + + /* enable port IPV4 and IPV6 DSCP for this port */ + val = readl(slave->port_base + AM65_CPSW_PORTN_REG_CTL); + val |= AM65_CPSW_PN_REG_CTL_DSCP_IPV4_EN | + AM65_CPSW_PN_REG_CTL_DSCP_IPV6_EN; + writel(val, slave->port_base + AM65_CPSW_PORTN_REG_CTL); +} + static void am65_cpsw_sl_ctl_reset(struct am65_cpsw_port *port) { cpsw_sl_reset(port->slave.mac_sl, 100); @@ -916,6 +1015,7 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev) common->usage_count++; am65_cpsw_port_set_sl_mac(port, ndev->dev_addr); + am65_cpsw_port_enable_dscp_map(port); if (common->is_emac_mode) am65_cpsw_init_port_emac_ale(port); @@ -1026,9 +1126,7 @@ static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow, int cpu, int *len) { struct am65_cpsw_common *common = flow->common; - struct am65_cpsw_ndev_priv *ndev_priv; struct net_device *ndev = port->ndev; - struct am65_cpsw_ndev_stats *stats; int ret = AM65_CPSW_XDP_CONSUMED; struct am65_cpsw_tx_chn *tx_chn; struct netdev_queue *netif_txq; @@ -1046,9 +1144,6 @@ static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow, /* XDP prog might have changed packet data and boundaries */ *len = xdp->data_end - xdp->data; - ndev_priv = netdev_priv(ndev); - stats = this_cpu_ptr(ndev_priv->stats); - switch (act) { case XDP_PASS: ret = AM65_CPSW_XDP_PASS; @@ -1068,20 +1163,14 @@ static int am65_cpsw_run_xdp(struct am65_cpsw_rx_flow *flow, if (err) goto drop; - u64_stats_update_begin(&stats->syncp); - stats->rx_bytes += *len; - stats->rx_packets++; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_tx_add(ndev, 1, *len); ret = AM65_CPSW_XDP_CONSUMED; goto out; case XDP_REDIRECT: if (unlikely(xdp_do_redirect(ndev, xdp, prog))) goto drop; - u64_stats_update_begin(&stats->syncp); - stats->rx_bytes += *len; - stats->rx_packets++; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_rx_add(ndev, *len); ret = AM65_CPSW_XDP_REDIRECT; goto out; default: @@ -1142,7 +1231,6 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow, u32 buf_dma_len, pkt_len, port_id = 0, csum_info; struct am65_cpsw_common *common = flow->common; struct am65_cpsw_ndev_priv *ndev_priv; - struct am65_cpsw_ndev_stats *stats; struct cppi5_host_desc_t *desc_rx; struct device *dev = common->dev; struct am65_cpsw_swdata *swdata; @@ -1225,12 +1313,7 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow, am65_cpsw_nuss_rx_csum(skb, csum_info); napi_gro_receive(&flow->napi_rx, skb); - stats = this_cpu_ptr(ndev_priv->stats); - - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += pkt_len; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_rx_add(ndev, pkt_len); allocate: new_page = page_pool_dev_alloc_pages(flow->page_pool); @@ -1311,10 +1394,7 @@ static struct sk_buff * am65_cpsw_nuss_tx_compl_packet_skb(struct am65_cpsw_tx_chn *tx_chn, dma_addr_t desc_dma) { - struct am65_cpsw_ndev_priv *ndev_priv; - struct am65_cpsw_ndev_stats *stats; struct cppi5_host_desc_t *desc_tx; - struct net_device *ndev; struct sk_buff *skb; void **swdata; @@ -1324,16 +1404,9 @@ am65_cpsw_nuss_tx_compl_packet_skb(struct am65_cpsw_tx_chn *tx_chn, skb = *(swdata); am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); - ndev = skb->dev; - am65_cpts_tx_timestamp(tx_chn->common->cpts, skb); - ndev_priv = netdev_priv(ndev); - stats = this_cpu_ptr(ndev_priv->stats); - u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += skb->len; - u64_stats_update_end(&stats->syncp); + dev_sw_netstats_tx_add(skb->dev, 1, skb->len); return skb; } @@ -1344,8 +1417,6 @@ am65_cpsw_nuss_tx_compl_packet_xdp(struct am65_cpsw_common *common, dma_addr_t desc_dma, struct net_device **ndev) { - struct am65_cpsw_ndev_priv *ndev_priv; - struct am65_cpsw_ndev_stats *stats; struct cppi5_host_desc_t *desc_tx; struct am65_cpsw_port *port; struct xdp_frame *xdpf; @@ -1359,15 +1430,9 @@ am65_cpsw_nuss_tx_compl_packet_xdp(struct am65_cpsw_common *common, am65_cpsw_nuss_xmit_free(tx_chn, desc_tx); port = am65_common_get_port(common, port_id); + dev_sw_netstats_tx_add(port->ndev, 1, xdpf->len); *ndev = port->ndev; - ndev_priv = netdev_priv(*ndev); - stats = this_cpu_ptr(ndev_priv->stats); - u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += xdpf->len; - u64_stats_update_end(&stats->syncp); - return xdpf; } @@ -1889,31 +1954,7 @@ static int am65_cpsw_nuss_ndo_slave_ioctl(struct net_device *ndev, static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) { - struct am65_cpsw_ndev_priv *ndev_priv = netdev_priv(dev); - unsigned int start; - int cpu; - - for_each_possible_cpu(cpu) { - struct am65_cpsw_ndev_stats *cpu_stats; - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; - - cpu_stats = per_cpu_ptr(ndev_priv->stats, cpu); - do { - start = u64_stats_fetch_begin(&cpu_stats->syncp); - rx_packets = cpu_stats->rx_packets; - rx_bytes = cpu_stats->rx_bytes; - tx_packets = cpu_stats->tx_packets; - tx_bytes = cpu_stats->tx_bytes; - } while (u64_stats_fetch_retry(&cpu_stats->syncp, start)); - - stats->rx_packets += rx_packets; - stats->rx_bytes += rx_bytes; - stats->tx_packets += tx_packets; - stats->tx_bytes += tx_bytes; - } + dev_fetch_sw_netstats(stats, dev->tstats); stats->rx_errors = dev->stats.rx_errors; stats->rx_dropped = dev->stats.rx_dropped; @@ -2699,13 +2740,6 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common) return ret; } -static void am65_cpsw_pcpu_stats_free(void *data) -{ - struct am65_cpsw_ndev_stats __percpu *stats = data; - - free_percpu(stats); -} - static void am65_cpsw_nuss_phylink_cleanup(struct am65_cpsw_common *common) { struct am65_cpsw_port *port; @@ -2725,7 +2759,6 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx) struct device *dev = common->dev; struct am65_cpsw_port *port; struct phylink *phylink; - int ret; port = &common->ports[port_idx]; @@ -2818,21 +2851,13 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx) if (common->pdata.quirks & AM65_CPSW_QUIRK_I2027_NO_TX_CSUM) port->ndev->features &= ~NETIF_F_HW_CSUM; - ndev_priv->stats = netdev_alloc_pcpu_stats(struct am65_cpsw_ndev_stats); - if (!ndev_priv->stats) - return -ENOMEM; - - ret = devm_add_action_or_reset(dev, am65_cpsw_pcpu_stats_free, - ndev_priv->stats); - if (ret) - dev_err(dev, "failed to add percpu stat free action %d\n", ret); - + port->ndev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; port->xdp_prog = NULL; if (!common->dma_ndev) common->dma_ndev = port->ndev; - return ret; + return 0; } static int am65_cpsw_nuss_init_ndevs(struct am65_cpsw_common *common) @@ -3437,7 +3462,8 @@ static const struct am65_cpsw_pdata j7200_cpswxg_pdata = { .quirks = 0, .ale_dev_id = "am64-cpswxg", .fdqring_mode = K3_RINGACC_RING_MODE_RING, - .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII), + .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | + BIT(PHY_INTERFACE_MODE_USXGMII), }; static const struct am65_cpsw_pdata j721e_cpswxg_pdata = { @@ -3489,7 +3515,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) struct resource *res; struct clk *clk; int ale_entries; - u64 id_temp; + __be64 id_temp; int ret, i; common = devm_kzalloc(dev, sizeof(struct am65_cpsw_common), GFP_KERNEL); @@ -3762,7 +3788,7 @@ static struct platform_driver am65_cpsw_nuss_driver = { .pm = &am65_cpsw_nuss_dev_pm_ops, }, .probe = am65_cpsw_nuss_probe, - .remove_new = am65_cpsw_nuss_remove, + .remove = am65_cpsw_nuss_remove, }; module_platform_driver(am65_cpsw_nuss_driver); diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h index 92a27ba4c601eb..e7832a5cf3ccdf 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h @@ -184,18 +184,9 @@ struct am65_cpsw_common { u32 *ale_context; }; -struct am65_cpsw_ndev_stats { - u64 tx_packets; - u64 tx_bytes; - u64 rx_packets; - u64 rx_bytes; - struct u64_stats_sync syncp; -}; - struct am65_cpsw_ndev_priv { u32 msg_enable; struct am65_cpsw_port *port; - struct am65_cpsw_ndev_stats __percpu *stats; bool offload_fwd_mark; /* Serialize access to MAC Merge state between ethtool requests * and link state updates diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index c0a5abd8d9a8e6..4ef8cf6ea135a6 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -1802,7 +1802,7 @@ static struct platform_driver cpsw_driver = { .of_match_table = cpsw_of_mtable, }, .probe = cpsw_probe, - .remove_new = cpsw_remove, + .remove = cpsw_remove, }; module_platform_driver(cpsw_driver); diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 8d02d2b2142937..52e4e350b73435 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -162,27 +162,39 @@ static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits, ale_entry[idx] |= (value << start); } -#define DEFINE_ALE_FIELD(name, start, bits) \ +#define DEFINE_ALE_FIELD_GET(name, start, bits) \ static inline int cpsw_ale_get_##name(u32 *ale_entry) \ { \ return cpsw_ale_get_field(ale_entry, start, bits); \ -} \ +} + +#define DEFINE_ALE_FIELD_SET(name, start, bits) \ static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \ { \ cpsw_ale_set_field(ale_entry, start, bits, value); \ } -#define DEFINE_ALE_FIELD1(name, start) \ +#define DEFINE_ALE_FIELD(name, start, bits) \ +DEFINE_ALE_FIELD_GET(name, start, bits) \ +DEFINE_ALE_FIELD_SET(name, start, bits) + +#define DEFINE_ALE_FIELD1_GET(name, start) \ static inline int cpsw_ale_get_##name(u32 *ale_entry, u32 bits) \ { \ return cpsw_ale_get_field(ale_entry, start, bits); \ -} \ +} + +#define DEFINE_ALE_FIELD1_SET(name, start) \ static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value, \ u32 bits) \ { \ cpsw_ale_set_field(ale_entry, start, bits, value); \ } +#define DEFINE_ALE_FIELD1(name, start) \ +DEFINE_ALE_FIELD1_GET(name, start) \ +DEFINE_ALE_FIELD1_SET(name, start) + enum { ALE_ENT_VID_MEMBER_LIST = 0, ALE_ENT_VID_UNREG_MCAST_MSK, @@ -238,14 +250,14 @@ static const struct ale_entry_fld vlan_entry_k3_cpswxg[] = { DEFINE_ALE_FIELD(entry_type, 60, 2) DEFINE_ALE_FIELD(vlan_id, 48, 12) -DEFINE_ALE_FIELD(mcast_state, 62, 2) +DEFINE_ALE_FIELD_SET(mcast_state, 62, 2) DEFINE_ALE_FIELD1(port_mask, 66) DEFINE_ALE_FIELD(super, 65, 1) DEFINE_ALE_FIELD(ucast_type, 62, 2) -DEFINE_ALE_FIELD1(port_num, 66) -DEFINE_ALE_FIELD(blocked, 65, 1) -DEFINE_ALE_FIELD(secure, 64, 1) -DEFINE_ALE_FIELD(mcast, 40, 1) +DEFINE_ALE_FIELD1_SET(port_num, 66) +DEFINE_ALE_FIELD_SET(blocked, 65, 1) +DEFINE_ALE_FIELD_SET(secure, 64, 1) +DEFINE_ALE_FIELD_GET(mcast, 40, 1) #define NU_VLAN_UNREG_MCAST_IDX 1 @@ -1692,26 +1704,34 @@ static void cpsw_ale_policer_reset(struct cpsw_ale *ale) void cpsw_ale_classifier_setup_default(struct cpsw_ale *ale, int num_rx_ch) { int pri, idx; - /* IEEE802.1D-2004, Standard for Local and metropolitan area networks - * Table G-2 - Traffic type acronyms - * Table G-3 - Defining traffic types - * User priority values 1 and 2 effectively communicate a lower - * priority than 0. In the below table 0 is assigned to higher priority - * thread than 1 and 2 wherever possible. - * The below table maps which thread the user priority needs to be + + /* Reference: + * IEEE802.1Q-2014, Standard for Local and metropolitan area networks + * Table I-2 - Traffic type acronyms + * Table I-3 - Defining traffic types + * Section I.4 Traffic types and priority values, states: + * "0 is thus used both for default priority and for Best Effort, and + * Background is associated with a priority value of 1. This means + * that the value 1 effectively communicates a lower priority than 0." + * + * In the table below, Priority Code Point (PCP) 0 is assigned + * to a higher priority thread than PCP 1 wherever possible. + * The table maps which thread the PCP traffic needs to be * sent to for a given number of threads (RX channels). Upper threads * have higher priority. * e.g. if number of threads is 8 then user priority 0 will map to - * pri_thread_map[8-1][0] i.e. thread 2 + * pri_thread_map[8-1][0] i.e. thread 1 */ - int pri_thread_map[8][8] = { { 0, 0, 0, 0, 0, 0, 0, 0, }, + + int pri_thread_map[8][8] = { /* BK,BE,EE,CA,VI,VO,IC,NC */ + { 0, 0, 0, 0, 0, 0, 0, 0, }, { 0, 0, 0, 0, 1, 1, 1, 1, }, { 0, 0, 0, 0, 1, 1, 2, 2, }, - { 1, 0, 0, 1, 2, 2, 3, 3, }, - { 1, 0, 0, 1, 2, 3, 4, 4, }, - { 1, 0, 0, 2, 3, 4, 5, 5, }, - { 1, 0, 0, 2, 3, 4, 5, 6, }, - { 2, 0, 1, 3, 4, 5, 6, 7, } }; + { 0, 0, 1, 1, 2, 2, 3, 3, }, + { 0, 0, 1, 1, 2, 2, 3, 4, }, + { 1, 0, 2, 2, 3, 3, 4, 5, }, + { 1, 0, 2, 3, 4, 4, 5, 6, }, + { 1, 0, 2, 3, 4, 5, 6, 7 } }; cpsw_ale_policer_reset(ale); diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c index 557cc71b9dd22c..a98bcc5eb5663d 100644 --- a/drivers/net/ethernet/ti/cpsw_new.c +++ b/drivers/net/ethernet/ti/cpsw_new.c @@ -2127,7 +2127,7 @@ static struct platform_driver cpsw_driver = { .of_match_table = cpsw_of_mtable, }, .probe = cpsw_probe, - .remove_new = cpsw_remove, + .remove = cpsw_remove, }; module_platform_driver(cpsw_driver); diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index b0950a318c4233..ed8116fb05e9bc 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -2070,7 +2070,7 @@ static struct platform_driver davinci_emac_driver = { .of_match_table = davinci_emac_of_match, }, .probe = davinci_emac_probe, - .remove_new = davinci_emac_remove, + .remove = davinci_emac_remove, }; /** diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c index 8e07d4a1b6ba45..68507126be8e42 100644 --- a/drivers/net/ethernet/ti/davinci_mdio.c +++ b/drivers/net/ethernet/ti/davinci_mdio.c @@ -760,7 +760,7 @@ static struct platform_driver davinci_mdio_driver = { .of_match_table = of_match_ptr(davinci_mdio_of_mtable), }, .probe = davinci_mdio_probe, - .remove_new = davinci_mdio_remove, + .remove = davinci_mdio_remove, }; static int __init davinci_mdio_init(void) diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c index fe2fd1bfc904db..c568c84a032b69 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c @@ -817,6 +817,47 @@ static netdev_features_t emac_ndo_fix_features(struct net_device *ndev, return features; } +static int emac_ndo_vlan_rx_add_vid(struct net_device *ndev, + __be16 proto, u16 vid) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + int untag_mask = 0; + int port_mask; + + if (prueth->is_hsr_offload_mode) { + port_mask = BIT(PRUETH_PORT_HOST) | BIT(emac->port_id); + untag_mask = 0; + + netdev_dbg(emac->ndev, "VID add vid:%u port_mask:%X untag_mask %X\n", + vid, port_mask, untag_mask); + + icssg_vtbl_modify(emac, vid, port_mask, untag_mask, true); + icssg_set_pvid(emac->prueth, vid, emac->port_id); + } + return 0; +} + +static int emac_ndo_vlan_rx_del_vid(struct net_device *ndev, + __be16 proto, u16 vid) +{ + struct prueth_emac *emac = netdev_priv(ndev); + struct prueth *prueth = emac->prueth; + int untag_mask = 0; + int port_mask; + + if (prueth->is_hsr_offload_mode) { + port_mask = BIT(PRUETH_PORT_HOST); + untag_mask = 0; + + netdev_dbg(emac->ndev, "VID del vid:%u port_mask:%X untag_mask %X\n", + vid, port_mask, untag_mask); + + icssg_vtbl_modify(emac, vid, port_mask, untag_mask, false); + } + return 0; +} + static const struct net_device_ops emac_netdev_ops = { .ndo_open = emac_ndo_open, .ndo_stop = emac_ndo_stop, @@ -829,6 +870,8 @@ static const struct net_device_ops emac_netdev_ops = { .ndo_get_stats64 = icssg_ndo_get_stats64, .ndo_get_phys_port_name = icssg_ndo_get_phys_port_name, .ndo_fix_features = emac_ndo_fix_features, + .ndo_vlan_rx_add_vid = emac_ndo_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = emac_ndo_vlan_rx_del_vid, }; static int prueth_netdev_init(struct prueth *prueth, @@ -956,7 +999,7 @@ static int prueth_netdev_init(struct prueth *prueth, ndev->netdev_ops = &emac_netdev_ops; ndev->ethtool_ops = &icssg_ethtool_ops; ndev->hw_features = NETIF_F_SG; - ndev->features = ndev->hw_features; + ndev->features = ndev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER; ndev->hw_features |= NETIF_PRUETH_HSR_OFFLOAD_FEATURES; netif_napi_add(ndev, &emac->napi_rx, icssg_napi_rx_poll); @@ -1655,7 +1698,7 @@ MODULE_DEVICE_TABLE(of, prueth_dt_match); static struct platform_driver prueth_driver = { .probe = prueth_probe, - .remove_new = prueth_remove, + .remove = prueth_remove, .driver = { .name = "icssg-prueth", .of_match_table = prueth_dt_match, diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c b/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c index 292f04d29f4f7b..5024f0647a0d30 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c @@ -1215,7 +1215,7 @@ MODULE_DEVICE_TABLE(of, prueth_dt_match); static struct platform_driver prueth_driver = { .probe = prueth_probe, - .remove_new = prueth_remove, + .remove = prueth_remove, .driver = { .name = "icssg-prueth-sr1", .of_match_table = prueth_dt_match, diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index 11b90e1da0c635..857820657bac51 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -2270,7 +2270,7 @@ static struct platform_driver netcp_driver = { .of_match_table = of_match, }, .probe = netcp_probe, - .remove_new = netcp_remove, + .remove = netcp_remove, }; module_platform_driver(netcp_driver); diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c index 44488c153ea25f..4fbe4b7cd12a18 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c +++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.c @@ -2566,7 +2566,6 @@ static void gelic_wl_setup_netdev_ops(struct net_device *netdev) netdev->ethtool_ops = &gelic_wl_ethtool_ops; netdev->netdev_ops = &gelic_wl_netdevice_ops; - netdev->wireless_data = &wl->wireless_data; netdev->wireless_handlers = &gelic_wl_wext_handler_def; } diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h index 1f203d1ae8dbdf..dbabf538e10a7b 100644 --- a/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h +++ b/drivers/net/ethernet/toshiba/ps3_gelic_wireless.h @@ -276,7 +276,6 @@ struct gelic_wl_info { u8 active_bssid[ETH_ALEN]; /* associated bssid */ unsigned int essid_len; - struct iw_public_data wireless_data; struct iw_statistics iwstat; }; diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c index 554aff7c8f3ba3..c6957e3b7f0ff6 100644 --- a/drivers/net/ethernet/tundra/tsi108_eth.c +++ b/drivers/net/ethernet/tundra/tsi108_eth.c @@ -1676,7 +1676,7 @@ static void tsi108_ether_remove(struct platform_device *pdev) static struct platform_driver tsi_eth_driver = { .probe = tsi108_init_one, - .remove_new = tsi108_ether_remove, + .remove = tsi108_ether_remove, .driver = { .name = "tsi-ethernet", }, diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index e80c0294880184..894911f3d5603c 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -2570,7 +2570,7 @@ static struct pci_driver rhine_driver_pci = { static struct platform_driver rhine_driver_platform = { .probe = rhine_init_one_platform, - .remove_new = rhine_remove_one_platform, + .remove = rhine_remove_one_platform, .driver = { .name = DRV_NAME, .of_match_table = rhine_of_tbl, diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c index 55fff4d0d38012..dd4a07c97eeeb1 100644 --- a/drivers/net/ethernet/via/via-velocity.c +++ b/drivers/net/ethernet/via/via-velocity.c @@ -3247,7 +3247,7 @@ static struct pci_driver velocity_pci_driver = { static struct platform_driver velocity_platform_driver = { .probe = velocity_platform_probe, - .remove_new = velocity_platform_remove, + .remove = velocity_platform_remove, .driver = { .name = "via-velocity", .of_match_table = velocity_of_ids, diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c index a4cf682dca650e..0ee73a265545c3 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c @@ -72,14 +72,6 @@ int txgbe_request_queue_irqs(struct wx *wx) return err; } -static int txgbe_request_gpio_irq(struct txgbe *txgbe) -{ - txgbe->gpio_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); - return request_threaded_irq(txgbe->gpio_irq, NULL, - txgbe_gpio_irq_handler, - IRQF_ONESHOT, "txgbe-gpio-irq", txgbe); -} - static int txgbe_request_link_irq(struct txgbe *txgbe) { txgbe->link_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); @@ -149,11 +141,6 @@ static irqreturn_t txgbe_misc_irq_thread_fn(int irq, void *data) u32 eicr; eicr = wx_misc_isb(wx, WX_ISB_MISC); - if (eicr & TXGBE_PX_MISC_GPIO) { - sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); - handle_nested_irq(sub_irq); - nhandled++; - } if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | TXGBE_PX_MISC_ETH_AN)) { sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); @@ -179,7 +166,6 @@ static void txgbe_del_irq_domain(struct txgbe *txgbe) void txgbe_free_misc_irq(struct txgbe *txgbe) { - free_irq(txgbe->gpio_irq, txgbe); free_irq(txgbe->link_irq, txgbe); free_irq(txgbe->misc.irq, txgbe); txgbe_del_irq_domain(txgbe); @@ -191,7 +177,7 @@ int txgbe_setup_misc_irq(struct txgbe *txgbe) struct wx *wx = txgbe->wx; int hwirq, err; - txgbe->misc.nirqs = 2; + txgbe->misc.nirqs = 1; txgbe->misc.domain = irq_domain_add_simple(NULL, txgbe->misc.nirqs, 0, &txgbe_misc_irq_domain_ops, txgbe); if (!txgbe->misc.domain) @@ -216,20 +202,14 @@ int txgbe_setup_misc_irq(struct txgbe *txgbe) if (err) goto del_misc_irq; - err = txgbe_request_gpio_irq(txgbe); - if (err) - goto free_msic_irq; - err = txgbe_request_link_irq(txgbe); if (err) - goto free_gpio_irq; + goto free_msic_irq; wx->misc_irq_domain = true; return 0; -free_gpio_irq: - free_irq(txgbe->gpio_irq, txgbe); free_msic_irq: free_irq(txgbe->misc.irq, txgbe); del_misc_irq: diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 93180225a6f14c..f7745026803643 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -82,7 +82,6 @@ static void txgbe_up_complete(struct wx *wx) { struct net_device *netdev = wx->netdev; - txgbe_reinit_gpio_intr(wx); wx_control_hw(wx, true); wx_configure_vectors(wx); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 67b61afdde96ce..1ae68f94dd4905 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -122,7 +122,7 @@ static int txgbe_pcs_write(struct mii_bus *bus, int addr, int devnum, int regnum static int txgbe_mdio_pcs_init(struct txgbe *txgbe) { struct mii_bus *mii_bus; - struct dw_xpcs *xpcs; + struct phylink_pcs *pcs; struct pci_dev *pdev; struct wx *wx; int ret = 0; @@ -147,11 +147,11 @@ static int txgbe_mdio_pcs_init(struct txgbe *txgbe) if (ret) return ret; - xpcs = xpcs_create_mdiodev(mii_bus, 0, PHY_INTERFACE_MODE_10GBASER); - if (IS_ERR(xpcs)) - return PTR_ERR(xpcs); + pcs = xpcs_create_pcs_mdiodev(mii_bus, 0); + if (IS_ERR(pcs)) + return PTR_ERR(pcs); - txgbe->xpcs = xpcs; + txgbe->pcs = pcs; return 0; } @@ -162,8 +162,8 @@ static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *confi struct wx *wx = phylink_to_wx(config); struct txgbe *txgbe = wx->priv; - if (interface == PHY_INTERFACE_MODE_10GBASER) - return &txgbe->xpcs->pcs; + if (wx->media_type != sp_media_copper) + return txgbe->pcs; return NULL; } @@ -302,7 +302,7 @@ irqreturn_t txgbe_link_irq_handler(int irq, void *data) status = rd32(wx, TXGBE_CFG_PORT_ST); up = !!(status & TXGBE_CFG_PORT_ST_LINK_UP); - phylink_pcs_change(&txgbe->xpcs->pcs, up); + phylink_pcs_change(txgbe->pcs, up); return IRQ_HANDLED; } @@ -358,169 +358,8 @@ static int txgbe_gpio_direction_out(struct gpio_chip *chip, unsigned int offset, return 0; } -static void txgbe_gpio_irq_ack(struct irq_data *d) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - irq_hw_number_t hwirq = irqd_to_hwirq(d); - struct wx *wx = gpiochip_get_data(gc); - unsigned long flags; - - raw_spin_lock_irqsave(&wx->gpio_lock, flags); - wr32(wx, WX_GPIO_EOI, BIT(hwirq)); - raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); -} - -static void txgbe_gpio_irq_mask(struct irq_data *d) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - irq_hw_number_t hwirq = irqd_to_hwirq(d); - struct wx *wx = gpiochip_get_data(gc); - unsigned long flags; - - gpiochip_disable_irq(gc, hwirq); - - raw_spin_lock_irqsave(&wx->gpio_lock, flags); - wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), BIT(hwirq)); - raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); -} - -static void txgbe_gpio_irq_unmask(struct irq_data *d) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - irq_hw_number_t hwirq = irqd_to_hwirq(d); - struct wx *wx = gpiochip_get_data(gc); - unsigned long flags; - - gpiochip_enable_irq(gc, hwirq); - - raw_spin_lock_irqsave(&wx->gpio_lock, flags); - wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), 0); - raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); -} - -static void txgbe_toggle_trigger(struct gpio_chip *gc, unsigned int offset) -{ - struct wx *wx = gpiochip_get_data(gc); - u32 pol, val; - - pol = rd32(wx, WX_GPIO_POLARITY); - val = rd32(wx, WX_GPIO_EXT); - - if (val & BIT(offset)) - pol &= ~BIT(offset); - else - pol |= BIT(offset); - - wr32(wx, WX_GPIO_POLARITY, pol); -} - -static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - irq_hw_number_t hwirq = irqd_to_hwirq(d); - struct wx *wx = gpiochip_get_data(gc); - u32 level, polarity, mask; - unsigned long flags; - - mask = BIT(hwirq); - - if (type & IRQ_TYPE_LEVEL_MASK) { - level = 0; - irq_set_handler_locked(d, handle_level_irq); - } else { - level = mask; - irq_set_handler_locked(d, handle_edge_irq); - } - - if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) - polarity = mask; - else - polarity = 0; - - raw_spin_lock_irqsave(&wx->gpio_lock, flags); - - wr32m(wx, WX_GPIO_INTEN, mask, mask); - wr32m(wx, WX_GPIO_INTTYPE_LEVEL, mask, level); - if (type == IRQ_TYPE_EDGE_BOTH) - txgbe_toggle_trigger(gc, hwirq); - else - wr32m(wx, WX_GPIO_POLARITY, mask, polarity); - - raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); - - return 0; -} - -static const struct irq_chip txgbe_gpio_irq_chip = { - .name = "txgbe-gpio-irq", - .irq_ack = txgbe_gpio_irq_ack, - .irq_mask = txgbe_gpio_irq_mask, - .irq_unmask = txgbe_gpio_irq_unmask, - .irq_set_type = txgbe_gpio_set_type, - .flags = IRQCHIP_IMMUTABLE, - GPIOCHIP_IRQ_RESOURCE_HELPERS, -}; - -irqreturn_t txgbe_gpio_irq_handler(int irq, void *data) -{ - struct txgbe *txgbe = data; - struct wx *wx = txgbe->wx; - irq_hw_number_t hwirq; - unsigned long gpioirq; - struct gpio_chip *gc; - unsigned long flags; - - gpioirq = rd32(wx, WX_GPIO_INTSTATUS); - - gc = txgbe->gpio; - for_each_set_bit(hwirq, &gpioirq, gc->ngpio) { - int gpio = irq_find_mapping(gc->irq.domain, hwirq); - struct irq_data *d = irq_get_irq_data(gpio); - u32 irq_type = irq_get_trigger_type(gpio); - - txgbe_gpio_irq_ack(d); - handle_nested_irq(gpio); - - if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { - raw_spin_lock_irqsave(&wx->gpio_lock, flags); - txgbe_toggle_trigger(gc, hwirq); - raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); - } - } - - return IRQ_HANDLED; -} - -void txgbe_reinit_gpio_intr(struct wx *wx) -{ - struct txgbe *txgbe = wx->priv; - irq_hw_number_t hwirq; - unsigned long gpioirq; - struct gpio_chip *gc; - unsigned long flags; - - /* for gpio interrupt pending before irq enable */ - gpioirq = rd32(wx, WX_GPIO_INTSTATUS); - - gc = txgbe->gpio; - for_each_set_bit(hwirq, &gpioirq, gc->ngpio) { - int gpio = irq_find_mapping(gc->irq.domain, hwirq); - struct irq_data *d = irq_get_irq_data(gpio); - u32 irq_type = irq_get_trigger_type(gpio); - - txgbe_gpio_irq_ack(d); - - if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { - raw_spin_lock_irqsave(&wx->gpio_lock, flags); - txgbe_toggle_trigger(gc, hwirq); - raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); - } - } -} - static int txgbe_gpio_init(struct txgbe *txgbe) { - struct gpio_irq_chip *girq; struct gpio_chip *gc; struct device *dev; struct wx *wx; @@ -550,11 +389,6 @@ static int txgbe_gpio_init(struct txgbe *txgbe) gc->direction_input = txgbe_gpio_direction_in; gc->direction_output = txgbe_gpio_direction_out; - girq = &gc->irq; - gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip); - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_bad_irq; - ret = devm_gpiochip_add_data(dev, gc, wx); if (ret) return ret; @@ -578,7 +412,7 @@ static int txgbe_clock_register(struct txgbe *txgbe) if (IS_ERR(clk)) return PTR_ERR(clk); - clock = clkdev_create(clk, NULL, clk_name); + clock = clkdev_create(clk, NULL, "%s", clk_name); if (!clock) { clk_unregister(clk); return -ENOMEM; @@ -778,7 +612,7 @@ int txgbe_init_phy(struct txgbe *txgbe) err_destroy_phylink: phylink_destroy(wx->phylink); err_destroy_xpcs: - xpcs_destroy(txgbe->xpcs); + xpcs_destroy_pcs(txgbe->pcs); err_unregister_swnode: software_node_unregister_node_group(txgbe->nodes.group); @@ -798,6 +632,6 @@ void txgbe_remove_phy(struct txgbe *txgbe) clkdev_drop(txgbe->clock); clk_unregister(txgbe->clk); phylink_destroy(txgbe->wx->phylink); - xpcs_destroy(txgbe->xpcs); + xpcs_destroy_pcs(txgbe->pcs); software_node_unregister_node_group(txgbe->nodes.group); } diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h index 8a026d804fe24c..3938985355ed6c 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h @@ -4,8 +4,6 @@ #ifndef _TXGBE_PHY_H_ #define _TXGBE_PHY_H_ -irqreturn_t txgbe_gpio_irq_handler(int irq, void *data); -void txgbe_reinit_gpio_intr(struct wx *wx); irqreturn_t txgbe_link_irq_handler(int irq, void *data); int txgbe_init_phy(struct txgbe *txgbe); void txgbe_remove_phy(struct txgbe *txgbe); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 959102c4c3797e..629a13e96b8597 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -75,8 +75,7 @@ #define TXGBE_PX_MISC_IEN_MASK \ (TXGBE_PX_MISC_ETH_LKDN | TXGBE_PX_MISC_DEV_RST | \ TXGBE_PX_MISC_ETH_EVENT | TXGBE_PX_MISC_ETH_LK | \ - TXGBE_PX_MISC_ETH_AN | TXGBE_PX_MISC_INT_ERR | \ - TXGBE_PX_MISC_GPIO) + TXGBE_PX_MISC_ETH_AN | TXGBE_PX_MISC_INT_ERR) /* Port cfg registers */ #define TXGBE_CFG_PORT_ST 0x14404 @@ -313,8 +312,7 @@ struct txgbe_nodes { }; enum txgbe_misc_irqs { - TXGBE_IRQ_GPIO = 0, - TXGBE_IRQ_LINK, + TXGBE_IRQ_LINK = 0, TXGBE_IRQ_MAX }; @@ -329,13 +327,12 @@ struct txgbe { struct wx *wx; struct txgbe_nodes nodes; struct txgbe_irq misc; - struct dw_xpcs *xpcs; + struct phylink_pcs *pcs; struct platform_device *sfp_dev; struct platform_device *i2c_dev; struct clk_lookup *clock; struct clk *clk; struct gpio_chip *gpio; - unsigned int gpio_irq; unsigned int link_irq; /* flow director */ diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c index b26fd15c25aece..b77f096eaf9951 100644 --- a/drivers/net/ethernet/wiznet/w5100.c +++ b/drivers/net/ethernet/wiznet/w5100.c @@ -1271,6 +1271,6 @@ static struct platform_driver w5100_mmio_driver = { .pm = &w5100_pm_ops, }, .probe = w5100_mmio_probe, - .remove_new = w5100_mmio_remove, + .remove = w5100_mmio_remove, }; module_platform_driver(w5100_mmio_driver); diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c index f165616f36fe51..3e711dea3b2c89 100644 --- a/drivers/net/ethernet/wiznet/w5300.c +++ b/drivers/net/ethernet/wiznet/w5300.c @@ -681,7 +681,7 @@ static struct platform_driver w5300_driver = { .pm = &w5300_pm_ops, }, .probe = w5300_probe, - .remove_new = w5300_remove, + .remove = w5300_remove, }; module_platform_driver(w5300_driver); diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 1072e2210aed32..edb36ff07a0c6f 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -1649,7 +1649,7 @@ MODULE_DEVICE_TABLE(of, temac_of_match); static struct platform_driver temac_driver = { .probe = temac_probe, - .remove_new = temac_remove, + .remove = temac_remove, .driver = { .name = "xilinx_temac", .of_match_table = temac_of_match, diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 1fcbcaa85ebdb4..0f4b02fe6f8568 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -2999,7 +2999,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(axienet_pm_ops, static struct platform_driver axienet_driver = { .probe = axienet_probe, - .remove_new = axienet_remove, + .remove = axienet_remove, .shutdown = axienet_shutdown, .driver = { .name = "xilinx_axienet", diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 940452d0a4d2a5..ecf47107146dc7 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -7,6 +7,7 @@ * Copyright (c) 2007 - 2013 Xilinx, Inc. */ +#include #include #include #include @@ -1091,13 +1092,14 @@ static int xemaclite_of_probe(struct platform_device *ofdev) struct net_device *ndev = NULL; struct net_local *lp = NULL; struct device *dev = &ofdev->dev; + struct clk *clkin; int rc = 0; dev_info(dev, "Device Tree Probing\n"); /* Create an ethernet device instance */ - ndev = alloc_etherdev(sizeof(struct net_local)); + ndev = devm_alloc_etherdev(dev, sizeof(struct net_local)); if (!ndev) return -ENOMEM; @@ -1110,15 +1112,13 @@ static int xemaclite_of_probe(struct platform_device *ofdev) /* Get IRQ for the device */ rc = platform_get_irq(ofdev, 0); if (rc < 0) - goto error; + return rc; ndev->irq = rc; lp->base_addr = devm_platform_get_and_ioremap_resource(ofdev, 0, &res); - if (IS_ERR(lp->base_addr)) { - rc = PTR_ERR(lp->base_addr); - goto error; - } + if (IS_ERR(lp->base_addr)) + return PTR_ERR(lp->base_addr); ndev->mem_start = res->start; ndev->mem_end = res->end; @@ -1129,6 +1129,11 @@ static int xemaclite_of_probe(struct platform_device *ofdev) lp->tx_ping_pong = get_bool(ofdev, "xlnx,tx-ping-pong"); lp->rx_ping_pong = get_bool(ofdev, "xlnx,rx-ping-pong"); + clkin = devm_clk_get_optional_enabled(&ofdev->dev, NULL); + if (IS_ERR(clkin)) + return dev_err_probe(&ofdev->dev, PTR_ERR(clkin), + "Failed to get and enable clock from Device Tree\n"); + rc = of_get_ethdev_address(ofdev->dev.of_node, ndev); if (rc) { dev_warn(dev, "No MAC address found, using random\n"); @@ -1167,8 +1172,6 @@ static int xemaclite_of_probe(struct platform_device *ofdev) put_node: of_node_put(lp->phy_node); -error: - free_netdev(ndev); return rc; } @@ -1197,8 +1200,6 @@ static void xemaclite_of_remove(struct platform_device *of_dev) of_node_put(lp->phy_node); lp->phy_node = NULL; - - free_netdev(ndev); } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1257,7 +1258,7 @@ static struct platform_driver xemaclite_of_driver = { .of_match_table = xemaclite_of_match, }, .probe = xemaclite_of_probe, - .remove_new = xemaclite_of_remove, + .remove = xemaclite_of_remove, }; module_platform_driver(xemaclite_of_driver); diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index aef316278eb456..a2ab1c1508221a 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -1619,7 +1619,7 @@ static struct platform_driver ixp4xx_eth_driver = { .of_match_table = of_match_ptr(ixp4xx_eth_of_match), }, .probe = ixp4xx_eth_probe, - .remove_new = ixp4xx_eth_remove, + .remove = ixp4xx_eth_remove, }; module_platform_driver(ixp4xx_eth_driver); diff --git a/drivers/net/fjes/fjes_ethtool.c b/drivers/net/fjes/fjes_ethtool.c index 19c99529566b3d..70c53f33d85702 100644 --- a/drivers/net/fjes/fjes_ethtool.c +++ b/drivers/net/fjes/fjes_ethtool.c @@ -87,49 +87,31 @@ static void fjes_get_strings(struct net_device *netdev, { struct fjes_adapter *adapter = netdev_priv(netdev); struct fjes_hw *hw = &adapter->hw; - u8 *p = data; int i; - switch (stringset) { - case ETH_SS_STATS: - for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) { - memcpy(p, fjes_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; - } - for (i = 0; i < hw->max_epid; i++) { - if (i == hw->my_epid) - continue; - sprintf(p, "ep%u_com_regist_buf_exec", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_com_unregist_buf_exec", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_send_intr_rx", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_send_intr_unshare", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_send_intr_zoneupdate", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_recv_intr_rx", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_recv_intr_unshare", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_recv_intr_stop", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_recv_intr_zoneupdate", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_tx_buffer_full", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_tx_dropped_not_shared", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_tx_dropped_ver_mismatch", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_tx_dropped_buf_size_mismatch", i); - p += ETH_GSTRING_LEN; - sprintf(p, "ep%u_tx_dropped_vlanid_mismatch", i); - p += ETH_GSTRING_LEN; - } - break; + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) + ethtool_puts(&data, fjes_gstrings_stats[i].stat_string); + + for (i = 0; i < hw->max_epid; i++) { + if (i == hw->my_epid) + continue; + ethtool_sprintf(&data, "ep%u_com_regist_buf_exec", i); + ethtool_sprintf(&data, "ep%u_com_unregist_buf_exec", i); + ethtool_sprintf(&data, "ep%u_send_intr_rx", i); + ethtool_sprintf(&data, "ep%u_send_intr_unshare", i); + ethtool_sprintf(&data, "ep%u_send_intr_zoneupdate", i); + ethtool_sprintf(&data, "ep%u_recv_intr_rx", i); + ethtool_sprintf(&data, "ep%u_recv_intr_unshare", i); + ethtool_sprintf(&data, "ep%u_recv_intr_stop", i); + ethtool_sprintf(&data, "ep%u_recv_intr_zoneupdate", i); + ethtool_sprintf(&data, "ep%u_tx_buffer_full", i); + ethtool_sprintf(&data, "ep%u_tx_dropped_not_shared", i); + ethtool_sprintf(&data, "ep%u_tx_dropped_ver_mismatch", i); + ethtool_sprintf(&data, "ep%u_tx_dropped_buf_size_mismatch", i); + ethtool_sprintf(&data, "ep%u_tx_dropped_vlanid_mismatch", i); } } diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index fad5b65644645d..4a4ed2ccf72ff2 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -1466,7 +1466,7 @@ static struct platform_driver fjes_driver = { .name = DRV_NAME, }, .probe = fjes_probe, - .remove_new = fjes_remove, + .remove = fjes_remove, }; static acpi_status diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 7f611c74eb629b..bc658bc6088546 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -827,7 +827,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, __be16 sport; int err; - if (!skb_vlan_inet_prepare(skb, inner_proto_inherit)) + if (skb_vlan_inet_prepare(skb, inner_proto_inherit)) return -EINVAL; if (!gs4) @@ -895,7 +895,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, if (geneve->cfg.df == GENEVE_DF_SET) { df = htons(IP_DF); } else if (geneve->cfg.df == GENEVE_DF_INHERIT) { - struct ethhdr *eth = eth_hdr(skb); + struct ethhdr *eth = skb_eth_hdr(skb); if (ntohs(eth->h_proto) == ETH_P_IPV6) { df = htons(IP_DF); @@ -937,7 +937,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, __be16 sport; int err; - if (!skb_vlan_inet_prepare(skb, inner_proto_inherit)) + if (skb_vlan_inet_prepare(skb, inner_proto_inherit)) return -EINVAL; if (!gs6) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 70f981887518aa..89a996ad8cd016 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -1491,10 +1491,8 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, } gtp->role = role; - if (!data[IFLA_GTP_RESTART_COUNT]) - gtp->restart_count = 0; - else - gtp->restart_count = nla_get_u8(data[IFLA_GTP_RESTART_COUNT]); + gtp->restart_count = nla_get_u8_default(data[IFLA_GTP_RESTART_COUNT], + 0); gtp->net = src_net; @@ -1829,10 +1827,7 @@ static struct pdp_ctx *gtp_pdp_add(struct gtp_dev *gtp, struct sock *sk, version = nla_get_u32(info->attrs[GTPA_VERSION]); - if (info->attrs[GTPA_FAMILY]) - family = nla_get_u8(info->attrs[GTPA_FAMILY]); - else - family = AF_INET; + family = nla_get_u8_default(info->attrs[GTPA_FAMILY], AF_INET); #if !IS_ENABLED(CONFIG_IPV6) if (family == AF_INET6) @@ -2069,10 +2064,7 @@ static struct pdp_ctx *gtp_find_pdp_by_link(struct net *net, struct gtp_dev *gtp; int family; - if (nla[GTPA_FAMILY]) - family = nla_get_u8(nla[GTPA_FAMILY]); - else - family = AF_INET; + family = nla_get_u8_default(nla[GTPA_FAMILY], AF_INET); gtp = gtp_find_dev(net, nla); if (!gtp) diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 646f605e358f2b..799f8ece7824f2 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c @@ -373,6 +373,7 @@ static enum uart ser12_check_uart(unsigned int iobase) static int ser12_open(struct net_device *dev) { + const unsigned int nr_irqs = irq_get_nr_irqs(); struct baycom_state *bc = netdev_priv(dev); enum uart u; diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index a9184a78650b09..c71e522492898e 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1460,6 +1460,7 @@ scc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern static void z8530_init(void) { + const unsigned int nr_irqs = irq_get_nr_irqs(); struct scc_channel *scc; int chip, k; unsigned long flags; @@ -1735,7 +1736,7 @@ static int scc_net_siocdevprivate(struct net_device *dev, if (hwcfg.irq == 2) hwcfg.irq = 9; - if (hwcfg.irq < 0 || hwcfg.irq >= nr_irqs) + if (hwcfg.irq < 0 || hwcfg.irq >= irq_get_nr_irqs()) return -EINVAL; if (!Ivec[hwcfg.irq].used && hwcfg.irq) @@ -2117,6 +2118,7 @@ static int __init scc_init_driver (void) static void __exit scc_cleanup_driver(void) { + const unsigned int nr_irqs = irq_get_nr_irqs(); io_port ctrl; int k; struct scc_channel *scc; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 2b6ec979a62f21..9afb08dbc350a3 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -712,8 +712,13 @@ void netvsc_device_remove(struct hv_device *device) for (i = 0; i < net_device->num_chn; i++) { /* See also vmbus_reset_channel_cb(). */ /* only disable enabled NAPI channel */ - if (i < ndev->real_num_rx_queues) + if (i < ndev->real_num_rx_queues) { + netif_queue_set_napi(ndev, i, NETDEV_QUEUE_TYPE_TX, + NULL); + netif_queue_set_napi(ndev, i, NETDEV_QUEUE_TYPE_RX, + NULL); napi_disable(&net_device->chan_table[i].napi); + } netif_napi_del(&net_device->chan_table[i].napi); } @@ -1787,6 +1792,10 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, netdev_dbg(ndev, "hv_netvsc channel opened successfully\n"); napi_enable(&net_device->chan_table[0].napi); + netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX, + &net_device->chan_table[0].napi); + netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX, + &net_device->chan_table[0].napi); /* Connect with the NetVsp */ ret = netvsc_connect_vsp(device, net_device, device_info); @@ -1805,6 +1814,8 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device, close: RCU_INIT_POINTER(net_device_ctx->nvdev, NULL); + netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_TX, NULL); + netif_queue_set_napi(ndev, 0, NETDEV_QUEUE_TYPE_RX, NULL); napi_disable(&net_device->chan_table[0].napi); /* Now, we can close the channel safely */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 23180f7b67b6aa..d6c4abfc3a28b0 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1557,7 +1557,7 @@ static void netvsc_get_ethtool_stats(struct net_device *dev, data[i++] = xdp_tx; } - pcpu_sum = kvmalloc_array(num_possible_cpus(), + pcpu_sum = kvmalloc_array(nr_cpu_ids, sizeof(struct netvsc_ethtool_pcpu_stats), GFP_KERNEL); if (!pcpu_sum) diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index ecc2128ca9b72a..c0ceeef4fcd810 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1269,10 +1269,15 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) ret = vmbus_open(new_sc, netvsc_ring_bytes, netvsc_ring_bytes, NULL, 0, netvsc_channel_cb, nvchan); - if (ret == 0) + if (ret == 0) { napi_enable(&nvchan->napi); - else + netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_RX, + &nvchan->napi); + netif_queue_set_napi(ndev, chn_index, NETDEV_QUEUE_TYPE_TX, + &nvchan->napi); + } else { netdev_notice(ndev, "sub channel open failed: %d\n", ret); + } if (atomic_inc_return(&nvscdev->open_chn) == nvscdev->num_chn) wake_up(&nvscdev->subchan_open); diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 2930141d7dd2d3..e11d8eda85ea11 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -235,7 +235,7 @@ static struct platform_device *ieee802154fake_dev; static struct platform_driver ieee802154fake_driver = { .probe = fakelb_probe, - .remove_new = fakelb_remove, + .remove = fakelb_remove, .driver = { .name = "ieee802154fakelb", }, diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c index 2c2483bbe780aa..1cab20b5a885cf 100644 --- a/drivers/net/ieee802154/mac802154_hwsim.c +++ b/drivers/net/ieee802154/mac802154_hwsim.c @@ -1047,7 +1047,7 @@ static void hwsim_remove(struct platform_device *pdev) static struct platform_driver mac802154hwsim_driver = { .probe = hwsim_probe, - .remove_new = hwsim_remove, + .remove = hwsim_remove, .driver = { .name = "mac802154_hwsim", }, diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 2c1b5def4a0bc4..67424888ff0aad 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -426,22 +426,21 @@ static int __init ifb_init_module(void) { int i, err; - down_write(&pernet_ops_rwsem); - rtnl_lock(); - err = __rtnl_link_register(&ifb_link_ops); + err = rtnl_link_register(&ifb_link_ops); if (err < 0) - goto out; + return err; + + rtnl_net_lock(&init_net); for (i = 0; i < numifbs && !err; i++) { err = ifb_init_one(i); cond_resched(); } - if (err) - __rtnl_link_unregister(&ifb_link_ops); -out: - rtnl_unlock(); - up_write(&pernet_ops_rwsem); + rtnl_net_unlock(&init_net); + + if (err) + rtnl_link_unregister(&ifb_link_ops); return err; } diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 5f3dd5a2dcf46c..f25f6e2cf58cc3 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -1012,7 +1012,7 @@ static const struct attribute_group *ipa_attribute_groups[] = { static struct platform_driver ipa_driver = { .probe = ipa_probe, - .remove_new = ipa_remove, + .remove = ipa_remove, .shutdown = ipa_remove, .driver = { .name = "ipa", diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index b1afcb8740de12..fd591ddb3884df 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -3,6 +3,7 @@ */ #include +#include #include "ipvlan.h" @@ -422,7 +423,7 @@ static noinline_for_stack int ipvlan_process_v4_outbound(struct sk_buff *skb) int err, ret = NET_XMIT_DROP; struct flowi4 fl4 = { .flowi4_oif = dev->ifindex, - .flowi4_tos = ip4h->tos & INET_DSCP_MASK, + .flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip4h)), .flowi4_flags = FLOWI_FLAG_ANYSRC, .flowi4_mark = skb->mark, .daddr = ip4h->daddr, diff --git a/drivers/net/ipvlan/ipvlan_l3s.c b/drivers/net/ipvlan/ipvlan_l3s.c index d5b05e8032199a..b4ef386bdb1ba5 100644 --- a/drivers/net/ipvlan/ipvlan_l3s.c +++ b/drivers/net/ipvlan/ipvlan_l3s.c @@ -2,6 +2,8 @@ /* Copyright (c) 2014 Mahesh Bandewar */ +#include + #include "ipvlan.h" static unsigned int ipvlan_netid __read_mostly; @@ -48,11 +50,11 @@ static struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, switch (proto) { case AF_INET: { - struct iphdr *ip4h = ip_hdr(skb); + const struct iphdr *ip4h = ip_hdr(skb); int err; err = ip_route_input_noref(skb, ip4h->daddr, ip4h->saddr, - ip4h->tos, sdev); + ip4h_dscp(ip4h), sdev); if (unlikely(err)) goto out; break; diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index ee215928257387..1bc1e5993f56e0 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -2621,6 +2621,17 @@ static void macsec_set_head_tail_room(struct net_device *dev) dev->needed_tailroom = real_dev->needed_tailroom + needed_tailroom; } +static void macsec_inherit_tso_max(struct net_device *dev) +{ + struct macsec_dev *macsec = macsec_priv(dev); + + /* if macsec is offloaded, we need to follow the lower + * device's capabilities. otherwise, we can ignore them. + */ + if (macsec_is_offloaded(macsec)) + netif_inherit_tso_max(dev, macsec->real_dev); +} + static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload) { enum macsec_offload prev_offload; @@ -2666,6 +2677,10 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off macsec_set_head_tail_room(dev); macsec->insert_tx_tag = macsec_needs_tx_tag(macsec, ops); + macsec_inherit_tso_max(dev); + + netdev_update_features(dev); + return ret; } @@ -3521,6 +3536,10 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb, #define MACSEC_FEATURES \ (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST) +#define MACSEC_OFFLOAD_FEATURES \ + (MACSEC_FEATURES | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES | \ + NETIF_F_LRO | NETIF_F_RXHASH | NETIF_F_CSUM_MASK | NETIF_F_RXCSUM) + static int macsec_dev_init(struct net_device *dev) { struct macsec_dev *macsec = macsec_priv(dev); @@ -3531,7 +3550,12 @@ static int macsec_dev_init(struct net_device *dev) if (err) return err; - dev->features = real_dev->features & MACSEC_FEATURES; + macsec_inherit_tso_max(dev); + + dev->hw_features = real_dev->hw_features & MACSEC_OFFLOAD_FEATURES; + dev->hw_features |= NETIF_F_GSO_SOFTWARE; + + dev->features = real_dev->features & MACSEC_OFFLOAD_FEATURES; dev->features |= NETIF_F_GSO_SOFTWARE; dev->lltx = true; dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; @@ -3561,8 +3585,12 @@ static netdev_features_t macsec_fix_features(struct net_device *dev, { struct macsec_dev *macsec = macsec_priv(dev); struct net_device *real_dev = macsec->real_dev; + netdev_features_t mask; + + mask = macsec_is_offloaded(macsec) ? MACSEC_OFFLOAD_FEATURES + : MACSEC_FEATURES; - features &= (real_dev->features & MACSEC_FEATURES) | + features &= (real_dev->features & mask) | NETIF_F_GSO_SOFTWARE | NETIF_F_SOFT_FEATURES; return features; @@ -4299,9 +4327,9 @@ static int macsec_validate_attr(struct nlattr *tb[], struct nlattr *data[], } } - es = data[IFLA_MACSEC_ES] ? nla_get_u8(data[IFLA_MACSEC_ES]) : false; - sci = data[IFLA_MACSEC_INC_SCI] ? nla_get_u8(data[IFLA_MACSEC_INC_SCI]) : false; - scb = data[IFLA_MACSEC_SCB] ? nla_get_u8(data[IFLA_MACSEC_SCB]) : false; + es = nla_get_u8_default(data[IFLA_MACSEC_ES], false); + sci = nla_get_u8_default(data[IFLA_MACSEC_INC_SCI], false); + scb = nla_get_u8_default(data[IFLA_MACSEC_SCB], false); if ((sci && (scb || es)) || (scb && es)) return -EINVAL; @@ -4428,31 +4456,26 @@ static int macsec_notify(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *real_dev = netdev_notifier_info_to_dev(ptr); + struct macsec_rxh_data *rxd; + struct macsec_dev *m, *n; LIST_HEAD(head); if (!is_macsec_master(real_dev)) return NOTIFY_DONE; + rxd = macsec_data_rtnl(real_dev); + switch (event) { case NETDEV_DOWN: case NETDEV_UP: - case NETDEV_CHANGE: { - struct macsec_dev *m, *n; - struct macsec_rxh_data *rxd; - - rxd = macsec_data_rtnl(real_dev); + case NETDEV_CHANGE: list_for_each_entry_safe(m, n, &rxd->secys, secys) { struct net_device *dev = m->secy.netdev; netif_stacked_transfer_operstate(real_dev, dev); } break; - } - case NETDEV_UNREGISTER: { - struct macsec_dev *m, *n; - struct macsec_rxh_data *rxd; - - rxd = macsec_data_rtnl(real_dev); + case NETDEV_UNREGISTER: list_for_each_entry_safe(m, n, &rxd->secys, secys) { macsec_common_dellink(m->secy.netdev, &head); } @@ -4462,12 +4485,7 @@ static int macsec_notify(struct notifier_block *this, unsigned long event, unregister_netdevice_many(&head); break; - } - case NETDEV_CHANGEMTU: { - struct macsec_dev *m; - struct macsec_rxh_data *rxd; - - rxd = macsec_data_rtnl(real_dev); + case NETDEV_CHANGEMTU: list_for_each_entry(m, &rxd->secys, secys) { struct net_device *dev = m->secy.netdev; unsigned int mtu = real_dev->mtu - (m->secy.icv_len + @@ -4476,7 +4494,13 @@ static int macsec_notify(struct notifier_block *this, unsigned long event, if (dev->mtu > mtu) dev_set_mtu(dev, mtu); } - } + break; + case NETDEV_FEAT_CHANGE: + list_for_each_entry(m, &rxd->secys, secys) { + macsec_inherit_tso_max(m->secy.netdev); + netdev_update_features(m->secy.netdev); + } + break; } return NOTIFY_OK; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index cf18e66de142c9..fed4fe2a4748f8 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1024,7 +1024,7 @@ static int macvlan_vlan_rx_kill_vid(struct net_device *dev, static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, - u16 flags, + u16 flags, bool *notified, struct netlink_ext_ack *extack) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -1049,7 +1049,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, u16 vid, + const unsigned char *addr, u16 vid, bool *notified, struct netlink_ext_ack *extack) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -1117,7 +1117,7 @@ static void macvlan_dev_poll_controller(struct net_device *dev) return; } -static int macvlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo) +static int macvlan_dev_netpoll_setup(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); struct net_device *real_dev = vlan->lowerdev; diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c index e70fb66879941f..d2b3f5a5914188 100644 --- a/drivers/net/mctp/mctp-i2c.c +++ b/drivers/net/mctp/mctp-i2c.c @@ -880,7 +880,8 @@ static int mctp_i2c_add_netdev(struct mctp_i2c_client *mcli, goto err; } - rc = mctp_register_netdev(ndev, &mctp_i2c_mctp_ops); + rc = mctp_register_netdev(ndev, &mctp_i2c_mctp_ops, + MCTP_PHYS_BINDING_SMBUS); if (rc < 0) { dev_err(&mcli->client->dev, "register netdev \"%s\" failed %d\n", diff --git a/drivers/net/mctp/mctp-i3c.c b/drivers/net/mctp/mctp-i3c.c index 1bc87a0626860f..9adad59b867672 100644 --- a/drivers/net/mctp/mctp-i3c.c +++ b/drivers/net/mctp/mctp-i3c.c @@ -607,7 +607,7 @@ __must_hold(&busdevs_lock) goto err_free_uninit; } - rc = mctp_register_netdev(ndev, NULL); + rc = mctp_register_netdev(ndev, NULL, MCTP_PHYS_BINDING_I3C); if (rc < 0) { dev_warn(&ndev->dev, "netdev register failed: %d\n", rc); goto err_free_netdev; diff --git a/drivers/net/mctp/mctp-serial.c b/drivers/net/mctp/mctp-serial.c index e63720ec32384b..26c9a33fd63648 100644 --- a/drivers/net/mctp/mctp-serial.c +++ b/drivers/net/mctp/mctp-serial.c @@ -23,6 +23,7 @@ #include #include +#include #include #define MCTP_SERIAL_MTU 68 /* base mtu (64) + mctp header */ @@ -470,7 +471,7 @@ static int mctp_serial_open(struct tty_struct *tty) spin_lock_init(&dev->lock); INIT_WORK(&dev->tx_work, mctp_serial_tx_work); - rc = register_netdev(ndev); + rc = mctp_register_netdev(ndev, NULL, MCTP_PHYS_BINDING_SERIAL); if (rc) goto free_netdev; @@ -492,7 +493,7 @@ static void mctp_serial_close(struct tty_struct *tty) struct mctp_serial *dev = tty->disc_data; int idx = dev->idx; - unregister_netdev(dev->netdev); + mctp_unregister_netdev(dev->netdev); ida_free(&mctp_serial_ida, idx); } diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c index e08c90ac0c6efa..f67a4d4005e7f7 100644 --- a/drivers/net/mdio.c +++ b/drivers/net/mdio.c @@ -166,178 +166,6 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr) return result; } -/** - * mdio45_ethtool_gset_npage - get settings for ETHTOOL_GSET - * @mdio: MDIO interface - * @ecmd: Ethtool request structure - * @npage_adv: Modes currently advertised on next pages - * @npage_lpa: Modes advertised by link partner on next pages - * - * The @ecmd parameter is expected to have been cleared before calling - * mdio45_ethtool_gset_npage(). - * - * Since the CSRs for auto-negotiation using next pages are not fully - * standardised, this function does not attempt to decode them. The - * caller must pass them in. - */ -void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, - struct ethtool_cmd *ecmd, - u32 npage_adv, u32 npage_lpa) -{ - int reg; - u32 speed; - - BUILD_BUG_ON(MDIO_SUPPORTS_C22 != ETH_MDIO_SUPPORTS_C22); - BUILD_BUG_ON(MDIO_SUPPORTS_C45 != ETH_MDIO_SUPPORTS_C45); - - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = mdio->prtad; - ecmd->mdio_support = - mdio->mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22); - - reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, - MDIO_CTRL2); - switch (reg & MDIO_PMA_CTRL2_TYPE) { - case MDIO_PMA_CTRL2_10GBT: - case MDIO_PMA_CTRL2_1000BT: - case MDIO_PMA_CTRL2_100BTX: - case MDIO_PMA_CTRL2_10BT: - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP; - reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, - MDIO_SPEED); - if (reg & MDIO_SPEED_10G) - ecmd->supported |= SUPPORTED_10000baseT_Full; - if (reg & MDIO_PMA_SPEED_1000) - ecmd->supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_1000baseT_Half); - if (reg & MDIO_PMA_SPEED_100) - ecmd->supported |= (SUPPORTED_100baseT_Full | - SUPPORTED_100baseT_Half); - if (reg & MDIO_PMA_SPEED_10) - ecmd->supported |= (SUPPORTED_10baseT_Full | - SUPPORTED_10baseT_Half); - ecmd->advertising = ADVERTISED_TP; - break; - - case MDIO_PMA_CTRL2_10GBCX4: - ecmd->port = PORT_OTHER; - ecmd->supported = 0; - ecmd->advertising = 0; - break; - - case MDIO_PMA_CTRL2_10GBKX4: - case MDIO_PMA_CTRL2_10GBKR: - case MDIO_PMA_CTRL2_1000BKX: - ecmd->port = PORT_OTHER; - ecmd->supported = SUPPORTED_Backplane; - reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, - MDIO_PMA_EXTABLE); - if (reg & MDIO_PMA_EXTABLE_10GBKX4) - ecmd->supported |= SUPPORTED_10000baseKX4_Full; - if (reg & MDIO_PMA_EXTABLE_10GBKR) - ecmd->supported |= SUPPORTED_10000baseKR_Full; - if (reg & MDIO_PMA_EXTABLE_1000BKX) - ecmd->supported |= SUPPORTED_1000baseKX_Full; - reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, - MDIO_PMA_10GBR_FECABLE); - if (reg & MDIO_PMA_10GBR_FECABLE_ABLE) - ecmd->supported |= SUPPORTED_10000baseR_FEC; - ecmd->advertising = ADVERTISED_Backplane; - break; - - /* All the other defined modes are flavours of optical */ - default: - ecmd->port = PORT_FIBRE; - ecmd->supported = SUPPORTED_FIBRE; - ecmd->advertising = ADVERTISED_FIBRE; - break; - } - - if (mdio->mmds & MDIO_DEVS_AN) { - ecmd->supported |= SUPPORTED_Autoneg; - reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_AN, - MDIO_CTRL1); - if (reg & MDIO_AN_CTRL1_ENABLE) { - ecmd->autoneg = AUTONEG_ENABLE; - ecmd->advertising |= - ADVERTISED_Autoneg | - mdio45_get_an(mdio, MDIO_AN_ADVERTISE) | - npage_adv; - } else { - ecmd->autoneg = AUTONEG_DISABLE; - } - } else { - ecmd->autoneg = AUTONEG_DISABLE; - } - - if (ecmd->autoneg) { - u32 modes = 0; - int an_stat = mdio->mdio_read(mdio->dev, mdio->prtad, - MDIO_MMD_AN, MDIO_STAT1); - - /* If AN is complete and successful, report best common - * mode, otherwise report best advertised mode. */ - if (an_stat & MDIO_AN_STAT1_COMPLETE) { - ecmd->lp_advertising = - mdio45_get_an(mdio, MDIO_AN_LPA) | npage_lpa; - if (an_stat & MDIO_AN_STAT1_LPABLE) - ecmd->lp_advertising |= ADVERTISED_Autoneg; - modes = ecmd->advertising & ecmd->lp_advertising; - } - if ((modes & ~ADVERTISED_Autoneg) == 0) - modes = ecmd->advertising; - - if (modes & (ADVERTISED_10000baseT_Full | - ADVERTISED_10000baseKX4_Full | - ADVERTISED_10000baseKR_Full)) { - speed = SPEED_10000; - ecmd->duplex = DUPLEX_FULL; - } else if (modes & (ADVERTISED_1000baseT_Full | - ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseKX_Full)) { - speed = SPEED_1000; - ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half); - } else if (modes & (ADVERTISED_100baseT_Full | - ADVERTISED_100baseT_Half)) { - speed = SPEED_100; - ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full); - } else { - speed = SPEED_10; - ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full); - } - } else { - /* Report forced settings */ - reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, - MDIO_CTRL1); - speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) - * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10)); - ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX || - speed == SPEED_10000); - } - - ethtool_cmd_speed_set(ecmd, speed); - - /* 10GBASE-T MDI/MDI-X */ - if (ecmd->port == PORT_TP - && (ethtool_cmd_speed(ecmd) == SPEED_10000)) { - switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD, - MDIO_PMA_10GBT_SWAPPOL)) { - case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX: - ecmd->eth_tp_mdix = ETH_TP_MDI; - break; - case 0: - ecmd->eth_tp_mdix = ETH_TP_MDI_X; - break; - default: - /* It's complicated... */ - ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID; - break; - } - } -} -EXPORT_SYMBOL(mdio45_ethtool_gset_npage); - /** * mdio45_ethtool_ksettings_get_npage - get settings for ETHTOOL_GLINKSETTINGS * @mdio: MDIO interface diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c index b156493d708415..aea0f03575689a 100644 --- a/drivers/net/mdio/fwnode_mdio.c +++ b/drivers/net/mdio/fwnode_mdio.c @@ -40,6 +40,7 @@ fwnode_find_pse_control(struct fwnode_handle *fwnode) static struct mii_timestamper * fwnode_find_mii_timestamper(struct fwnode_handle *fwnode) { + struct mii_timestamper *mii_ts; struct of_phandle_args arg; int err; @@ -53,10 +54,16 @@ fwnode_find_mii_timestamper(struct fwnode_handle *fwnode) else if (err) return ERR_PTR(err); - if (arg.args_count != 1) - return ERR_PTR(-EINVAL); + if (arg.args_count != 1) { + mii_ts = ERR_PTR(-EINVAL); + goto put_node; + } + + mii_ts = register_mii_timestamper(arg.np, arg.args[0]); - return register_mii_timestamper(arg.np, arg.args[0]); +put_node: + of_node_put(arg.np); + return mii_ts; } int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio, diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c index c2170650415cdb..e55be6dc9ae70f 100644 --- a/drivers/net/mdio/mdio-aspeed.c +++ b/drivers/net/mdio/mdio-aspeed.c @@ -198,7 +198,7 @@ static struct platform_driver aspeed_mdio_driver = { .of_match_table = aspeed_mdio_of_match, }, .probe = aspeed_mdio_probe, - .remove_new = aspeed_mdio_remove, + .remove = aspeed_mdio_remove, }; module_platform_driver(aspeed_mdio_driver); diff --git a/drivers/net/mdio/mdio-bcm-iproc.c b/drivers/net/mdio/mdio-bcm-iproc.c index 5a2d26c6afdc27..91690b496793c0 100644 --- a/drivers/net/mdio/mdio-bcm-iproc.c +++ b/drivers/net/mdio/mdio-bcm-iproc.c @@ -208,7 +208,7 @@ static struct platform_driver iproc_mdio_driver = { #endif }, .probe = iproc_mdio_probe, - .remove_new = iproc_mdio_remove, + .remove = iproc_mdio_remove, }; module_platform_driver(iproc_mdio_driver); diff --git a/drivers/net/mdio/mdio-bcm-unimac.c b/drivers/net/mdio/mdio-bcm-unimac.c index b7bc70586ee0a4..074d96328f41ad 100644 --- a/drivers/net/mdio/mdio-bcm-unimac.c +++ b/drivers/net/mdio/mdio-bcm-unimac.c @@ -355,7 +355,7 @@ static struct platform_driver unimac_mdio_driver = { .pm = &unimac_mdio_pm_ops, }, .probe = unimac_mdio_probe, - .remove_new = unimac_mdio_remove, + .remove = unimac_mdio_remove, }; module_platform_driver(unimac_mdio_driver); diff --git a/drivers/net/mdio/mdio-gpio.c b/drivers/net/mdio/mdio-gpio.c index 82088741debd9c..1cfd538b5105d9 100644 --- a/drivers/net/mdio/mdio-gpio.c +++ b/drivers/net/mdio/mdio-gpio.c @@ -207,7 +207,7 @@ MODULE_DEVICE_TABLE(of, mdio_gpio_of_match); static struct platform_driver mdio_gpio_driver = { .probe = mdio_gpio_probe, - .remove_new = mdio_gpio_remove, + .remove = mdio_gpio_remove, .driver = { .name = "mdio-gpio", .of_match_table = mdio_gpio_of_match, diff --git a/drivers/net/mdio/mdio-hisi-femac.c b/drivers/net/mdio/mdio-hisi-femac.c index 6703f626ee833b..d78a1dc36cfd58 100644 --- a/drivers/net/mdio/mdio-hisi-femac.c +++ b/drivers/net/mdio/mdio-hisi-femac.c @@ -136,7 +136,7 @@ MODULE_DEVICE_TABLE(of, hisi_femac_mdio_dt_ids); static struct platform_driver hisi_femac_mdio_driver = { .probe = hisi_femac_mdio_probe, - .remove_new = hisi_femac_mdio_remove, + .remove = hisi_femac_mdio_remove, .driver = { .name = "hisi-femac-mdio", .of_match_table = hisi_femac_mdio_dt_ids, diff --git a/drivers/net/mdio/mdio-ipq4019.c b/drivers/net/mdio/mdio-ipq4019.c index 9d8f43b28aac5b..d9a94df482d9f5 100644 --- a/drivers/net/mdio/mdio-ipq4019.c +++ b/drivers/net/mdio/mdio-ipq4019.c @@ -352,8 +352,11 @@ static int ipq4019_mdio_probe(struct platform_device *pdev) /* The platform resource is provided on the chipset IPQ5018 */ /* This resource is optional */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res) + if (res) { priv->eth_ldo_rdy = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->eth_ldo_rdy)) + return PTR_ERR(priv->eth_ldo_rdy); + } bus->name = "ipq4019_mdio"; bus->read = ipq4019_mdio_read_c22; @@ -391,7 +394,7 @@ MODULE_DEVICE_TABLE(of, ipq4019_mdio_dt_ids); static struct platform_driver ipq4019_mdio_driver = { .probe = ipq4019_mdio_probe, - .remove_new = ipq4019_mdio_remove, + .remove = ipq4019_mdio_remove, .driver = { .name = "ipq4019-mdio", .of_match_table = ipq4019_mdio_dt_ids, diff --git a/drivers/net/mdio/mdio-ipq8064.c b/drivers/net/mdio/mdio-ipq8064.c index f71b6e1c66e428..6253a9ab8b699f 100644 --- a/drivers/net/mdio/mdio-ipq8064.c +++ b/drivers/net/mdio/mdio-ipq8064.c @@ -162,7 +162,7 @@ MODULE_DEVICE_TABLE(of, ipq8064_mdio_dt_ids); static struct platform_driver ipq8064_mdio_driver = { .probe = ipq8064_mdio_probe, - .remove_new = ipq8064_mdio_remove, + .remove = ipq8064_mdio_remove, .driver = { .name = "ipq8064-mdio", .of_match_table = ipq8064_mdio_dt_ids, diff --git a/drivers/net/mdio/mdio-moxart.c b/drivers/net/mdio/mdio-moxart.c index d35af8cd7c4d46..9853be6f0f22b4 100644 --- a/drivers/net/mdio/mdio-moxart.c +++ b/drivers/net/mdio/mdio-moxart.c @@ -171,7 +171,7 @@ MODULE_DEVICE_TABLE(of, moxart_mdio_dt_ids); static struct platform_driver moxart_mdio_driver = { .probe = moxart_mdio_probe, - .remove_new = moxart_mdio_remove, + .remove = moxart_mdio_remove, .driver = { .name = "moxart-mdio", .of_match_table = moxart_mdio_dt_ids, diff --git a/drivers/net/mdio/mdio-mscc-miim.c b/drivers/net/mdio/mdio-mscc-miim.c index 62c47e0dd14240..944efd33da6dc2 100644 --- a/drivers/net/mdio/mdio-mscc-miim.c +++ b/drivers/net/mdio/mdio-mscc-miim.c @@ -377,7 +377,7 @@ MODULE_DEVICE_TABLE(of, mscc_miim_match); static struct platform_driver mscc_miim_driver = { .probe = mscc_miim_probe, - .remove_new = mscc_miim_remove, + .remove = mscc_miim_remove, .driver = { .name = "mscc-miim", .of_match_table = mscc_miim_match, diff --git a/drivers/net/mdio/mdio-mux-bcm-iproc.c b/drivers/net/mdio/mdio-mux-bcm-iproc.c index 1ce7d67ba72ef2..8ba0917a930a00 100644 --- a/drivers/net/mdio/mdio-mux-bcm-iproc.c +++ b/drivers/net/mdio/mdio-mux-bcm-iproc.c @@ -342,7 +342,7 @@ static struct platform_driver mdiomux_iproc_driver = { .pm = &mdio_mux_iproc_pm_ops, }, .probe = mdio_mux_iproc_probe, - .remove_new = mdio_mux_iproc_remove, + .remove = mdio_mux_iproc_remove, }; module_platform_driver(mdiomux_iproc_driver); diff --git a/drivers/net/mdio/mdio-mux-bcm6368.c b/drivers/net/mdio/mdio-mux-bcm6368.c index 1b77e0e3e6e1f9..476f8b72d02051 100644 --- a/drivers/net/mdio/mdio-mux-bcm6368.c +++ b/drivers/net/mdio/mdio-mux-bcm6368.c @@ -173,7 +173,7 @@ static struct platform_driver bcm6368_mdiomux_driver = { .of_match_table = bcm6368_mdiomux_ids, }, .probe = bcm6368_mdiomux_probe, - .remove_new = bcm6368_mdiomux_remove, + .remove = bcm6368_mdiomux_remove, }; module_platform_driver(bcm6368_mdiomux_driver); diff --git a/drivers/net/mdio/mdio-mux-gpio.c b/drivers/net/mdio/mdio-mux-gpio.c index 38fb031f897931..ef77bd1abae984 100644 --- a/drivers/net/mdio/mdio-mux-gpio.c +++ b/drivers/net/mdio/mdio-mux-gpio.c @@ -86,7 +86,7 @@ static struct platform_driver mdio_mux_gpio_driver = { .of_match_table = mdio_mux_gpio_match, }, .probe = mdio_mux_gpio_probe, - .remove_new = mdio_mux_gpio_remove, + .remove = mdio_mux_gpio_remove, }; module_platform_driver(mdio_mux_gpio_driver); diff --git a/drivers/net/mdio/mdio-mux-meson-g12a.c b/drivers/net/mdio/mdio-mux-meson-g12a.c index 754b0f2cf15b95..08d6a6c93fb8bf 100644 --- a/drivers/net/mdio/mdio-mux-meson-g12a.c +++ b/drivers/net/mdio/mdio-mux-meson-g12a.c @@ -348,7 +348,7 @@ static void g12a_mdio_mux_remove(struct platform_device *pdev) static struct platform_driver g12a_mdio_mux_driver = { .probe = g12a_mdio_mux_probe, - .remove_new = g12a_mdio_mux_remove, + .remove = g12a_mdio_mux_remove, .driver = { .name = "g12a-mdio_mux", .of_match_table = g12a_mdio_mux_match, diff --git a/drivers/net/mdio/mdio-mux-meson-gxl.c b/drivers/net/mdio/mdio-mux-meson-gxl.c index 89554021b5ccc4..00c66240136b10 100644 --- a/drivers/net/mdio/mdio-mux-meson-gxl.c +++ b/drivers/net/mdio/mdio-mux-meson-gxl.c @@ -149,7 +149,7 @@ static void gxl_mdio_mux_remove(struct platform_device *pdev) static struct platform_driver gxl_mdio_mux_driver = { .probe = gxl_mdio_mux_probe, - .remove_new = gxl_mdio_mux_remove, + .remove = gxl_mdio_mux_remove, .driver = { .name = "gxl-mdio-mux", .of_match_table = gxl_mdio_mux_match, diff --git a/drivers/net/mdio/mdio-mux-mmioreg.c b/drivers/net/mdio/mdio-mux-mmioreg.c index b70e6d1ad42944..9c4b1efd0d53c9 100644 --- a/drivers/net/mdio/mdio-mux-mmioreg.c +++ b/drivers/net/mdio/mdio-mux-mmioreg.c @@ -180,7 +180,7 @@ static struct platform_driver mdio_mux_mmioreg_driver = { .of_match_table = mdio_mux_mmioreg_match, }, .probe = mdio_mux_mmioreg_probe, - .remove_new = mdio_mux_mmioreg_remove, + .remove = mdio_mux_mmioreg_remove, }; module_platform_driver(mdio_mux_mmioreg_driver); diff --git a/drivers/net/mdio/mdio-mux-multiplexer.c b/drivers/net/mdio/mdio-mux-multiplexer.c index 569b1338319184..8e11960fc539d1 100644 --- a/drivers/net/mdio/mdio-mux-multiplexer.c +++ b/drivers/net/mdio/mdio-mux-multiplexer.c @@ -107,7 +107,7 @@ static struct platform_driver mdio_mux_multiplexer_driver = { .of_match_table = mdio_mux_multiplexer_match, }, .probe = mdio_mux_multiplexer_probe, - .remove_new = mdio_mux_multiplexer_remove, + .remove = mdio_mux_multiplexer_remove, }; module_platform_driver(mdio_mux_multiplexer_driver); diff --git a/drivers/net/mdio/mdio-octeon.c b/drivers/net/mdio/mdio-octeon.c index 037a38cfed56a6..2beb83154d39c7 100644 --- a/drivers/net/mdio/mdio-octeon.c +++ b/drivers/net/mdio/mdio-octeon.c @@ -104,7 +104,7 @@ static struct platform_driver octeon_mdiobus_driver = { .of_match_table = octeon_mdiobus_match, }, .probe = octeon_mdiobus_probe, - .remove_new = octeon_mdiobus_remove, + .remove = octeon_mdiobus_remove, }; module_platform_driver(octeon_mdiobus_driver); diff --git a/drivers/net/mdio/mdio-sun4i.c b/drivers/net/mdio/mdio-sun4i.c index 4511bcc73b3671..ad1edadc5a082e 100644 --- a/drivers/net/mdio/mdio-sun4i.c +++ b/drivers/net/mdio/mdio-sun4i.c @@ -164,7 +164,7 @@ MODULE_DEVICE_TABLE(of, sun4i_mdio_dt_ids); static struct platform_driver sun4i_mdio_driver = { .probe = sun4i_mdio_probe, - .remove_new = sun4i_mdio_remove, + .remove = sun4i_mdio_remove, .driver = { .name = "sun4i-mdio", .of_match_table = sun4i_mdio_dt_ids, diff --git a/drivers/net/mdio/mdio-thunder.c b/drivers/net/mdio/mdio-thunder.c index 6067d96b2b7bf0..1e1aa72b1eff80 100644 --- a/drivers/net/mdio/mdio-thunder.c +++ b/drivers/net/mdio/mdio-thunder.c @@ -23,7 +23,6 @@ static int thunder_mdiobus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct device_node *node; - struct fwnode_handle *fwn; struct thunder_mdiobus_nexus *nexus; int err; int i; @@ -54,7 +53,7 @@ static int thunder_mdiobus_pci_probe(struct pci_dev *pdev, } i = 0; - device_for_each_child_node(&pdev->dev, fwn) { + device_for_each_child_node_scoped(&pdev->dev, fwn) { struct resource r; struct mii_bus *mii_bus; struct cavium_mdiobus *bus; @@ -106,7 +105,6 @@ static int thunder_mdiobus_pci_probe(struct pci_dev *pdev, if (i >= ARRAY_SIZE(nexus->buses)) break; } - fwnode_handle_put(fwn); return 0; err_release_regions: diff --git a/drivers/net/mdio/mdio-xgene.c b/drivers/net/mdio/mdio-xgene.c index 2772a309854369..a8f91a4b7fed09 100644 --- a/drivers/net/mdio/mdio-xgene.c +++ b/drivers/net/mdio/mdio-xgene.c @@ -441,7 +441,7 @@ static struct platform_driver xgene_mdio_driver = { .acpi_match_table = ACPI_PTR(xgene_mdio_acpi_match), }, .probe = xgene_mdio_probe, - .remove_new = xgene_mdio_remove, + .remove = xgene_mdio_remove, }; module_platform_driver(xgene_mdio_driver); diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index de20928f740211..4ea44a2f48f7b1 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -1058,102 +1058,105 @@ static struct notifier_block netconsole_netdev_notifier = { .notifier_call = netconsole_netdev_event, }; -/** - * send_ext_msg_udp - send extended log message to target - * @nt: target to send message to - * @msg: extended log message to send - * @msg_len: length of message - * - * Transfer extended log @msg to @nt. If @msg is longer than - * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with - * ncfrag header field added to identify them. - */ -static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg, - int msg_len) +static void send_msg_no_fragmentation(struct netconsole_target *nt, + const char *msg, + int msg_len, + int release_len) { static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */ - const char *header, *body; - int offset = 0; - int header_len, body_len; - const char *msg_ready = msg; + const char *userdata = NULL; const char *release; - int release_len = 0; - int userdata_len = 0; - char *userdata = NULL; #ifdef CONFIG_NETCONSOLE_DYNAMIC userdata = nt->userdata_complete; - userdata_len = nt->userdata_length; #endif - if (nt->release) { + if (release_len) { release = init_utsname()->release; - release_len = strlen(release) + 1; + + scnprintf(buf, MAX_PRINT_CHUNK, "%s,%s", release, msg); + msg_len += release_len; + } else { + memcpy(buf, msg, msg_len); } - if (msg_len + release_len + userdata_len <= MAX_PRINT_CHUNK) { - /* No fragmentation needed */ - if (nt->release) { - scnprintf(buf, MAX_PRINT_CHUNK, "%s,%s", release, msg); - msg_len += release_len; - } else { - memcpy(buf, msg, msg_len); - } + if (userdata) + msg_len += scnprintf(&buf[msg_len], + MAX_PRINT_CHUNK - msg_len, + "%s", userdata); - if (userdata) - msg_len += scnprintf(&buf[msg_len], - MAX_PRINT_CHUNK - msg_len, - "%s", userdata); + netpoll_send_udp(&nt->np, buf, msg_len); +} - msg_ready = buf; - netpoll_send_udp(&nt->np, msg_ready, msg_len); - return; - } +static void append_release(char *buf) +{ + const char *release; - /* need to insert extra header fields, detect header and body */ - header = msg; - body = memchr(msg, ';', msg_len); - if (WARN_ON_ONCE(!body)) - return; + release = init_utsname()->release; + scnprintf(buf, MAX_PRINT_CHUNK, "%s,", release); +} - header_len = body - header; - body_len = msg_len - header_len - 1; - body++; +static void send_fragmented_body(struct netconsole_target *nt, char *buf, + const char *msgbody, int header_len, + int msgbody_len) +{ + const char *userdata = NULL; + int body_len, offset = 0; + int userdata_len = 0; - /* - * Transfer multiple chunks with the following extra header. - * "ncfrag=/" +#ifdef CONFIG_NETCONSOLE_DYNAMIC + userdata = nt->userdata_complete; + userdata_len = nt->userdata_length; +#endif + + /* body_len represents the number of bytes that will be sent. This is + * bigger than MAX_PRINT_CHUNK, thus, it will be split in multiple + * packets */ - if (nt->release) - scnprintf(buf, MAX_PRINT_CHUNK, "%s,", release); - memcpy(buf + release_len, header, header_len); - header_len += release_len; + body_len = msgbody_len + userdata_len; - while (offset < body_len + userdata_len) { + /* In each iteration of the while loop below, we send a packet + * containing the header and a portion of the body. The body is + * composed of two parts: msgbody and userdata. We keep track of how + * many bytes have been sent so far using the offset variable, which + * ranges from 0 to the total length of the body. + */ + while (offset < body_len) { int this_header = header_len; + bool msgbody_written = false; int this_offset = 0; int this_chunk = 0; this_header += scnprintf(buf + this_header, - sizeof(buf) - this_header, + MAX_PRINT_CHUNK - this_header, ",ncfrag=%d/%d;", offset, - body_len + userdata_len); + body_len); - /* Not all body data has been written yet */ - if (offset < body_len) { - this_chunk = min(body_len - offset, + /* Not all msgbody data has been written yet */ + if (offset < msgbody_len) { + this_chunk = min(msgbody_len - offset, MAX_PRINT_CHUNK - this_header); if (WARN_ON_ONCE(this_chunk <= 0)) return; - memcpy(buf + this_header, body + offset, this_chunk); + memcpy(buf + this_header, msgbody + offset, this_chunk); this_offset += this_chunk; } - /* Body is fully written and there is pending userdata to write, - * append userdata in this chunk + + /* msgbody was finally written, either in the previous + * messages and/or in the current buf. Time to write + * the userdata. */ - if (offset + this_offset >= body_len && - offset + this_offset < userdata_len + body_len) { - int sent_userdata = (offset + this_offset) - body_len; + msgbody_written |= offset + this_offset >= msgbody_len; + + /* Msg body is fully written and there is pending userdata to + * write, append userdata in this chunk + */ + if (msgbody_written && offset + this_offset < body_len) { + /* Track how much user data was already sent. First + * time here, sent_userdata is zero + */ + int sent_userdata = (offset + this_offset) - msgbody_len; + /* offset of bytes used in current buf */ int preceding_bytes = this_chunk + this_header; if (WARN_ON_ONCE(sent_userdata < 0)) @@ -1180,6 +1183,70 @@ static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg, } } +static void send_msg_fragmented(struct netconsole_target *nt, + const char *msg, + int msg_len, + int release_len) +{ + static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */ + int header_len, msgbody_len; + const char *msgbody; + + /* need to insert extra header fields, detect header and msgbody */ + msgbody = memchr(msg, ';', msg_len); + if (WARN_ON_ONCE(!msgbody)) + return; + + header_len = msgbody - msg; + msgbody_len = msg_len - header_len - 1; + msgbody++; + + /* + * Transfer multiple chunks with the following extra header. + * "ncfrag=/" + */ + if (release_len) + append_release(buf); + + /* Copy the header into the buffer */ + memcpy(buf + release_len, msg, header_len); + header_len += release_len; + + /* for now on, the header will be persisted, and the msgbody + * will be replaced + */ + send_fragmented_body(nt, buf, msgbody, header_len, msgbody_len); +} + +/** + * send_ext_msg_udp - send extended log message to target + * @nt: target to send message to + * @msg: extended log message to send + * @msg_len: length of message + * + * Transfer extended log @msg to @nt. If @msg is longer than + * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with + * ncfrag header field added to identify them. + */ +static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg, + int msg_len) +{ + int userdata_len = 0; + int release_len = 0; + +#ifdef CONFIG_NETCONSOLE_DYNAMIC + userdata_len = nt->userdata_length; +#endif + + if (nt->release) + release_len = strlen(init_utsname()->release) + 1; + + if (msg_len + release_len + userdata_len <= MAX_PRINT_CHUNK) + return send_msg_no_fragmentation(nt, msg, msg_len, release_len); + + return send_msg_fragmented(nt, msg, msg_len, release_len); +} + static void write_ext_msg(struct console *con, const char *msg, unsigned int len) { diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c index 1436905bc10614..5fe1eaef99b5bc 100644 --- a/drivers/net/netdevsim/ethtool.c +++ b/drivers/net/netdevsim/ethtool.c @@ -103,8 +103,10 @@ nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch) struct netdevsim *ns = netdev_priv(dev); int err; + mutex_lock(&dev->lock); err = netif_set_real_num_queues(dev, ch->combined_count, ch->combined_count); + mutex_unlock(&dev->lock); if (err) return err; diff --git a/drivers/net/netdevsim/health.c b/drivers/net/netdevsim/health.c index 70e8bdf34be900..688f05316b5e10 100644 --- a/drivers/net/netdevsim/health.c +++ b/drivers/net/netdevsim/health.c @@ -149,6 +149,8 @@ static ssize_t nsim_dev_health_break_write(struct file *file, char *break_msg; int err; + if (count == 0 || count > PAGE_SIZE) + return -EINVAL; break_msg = memdup_user_nul(data, count); if (IS_ERR(break_msg)) return PTR_ERR(break_msg); diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c index f0d58092e7e961..88187dd4eb2d40 100644 --- a/drivers/net/netdevsim/ipsec.c +++ b/drivers/net/netdevsim/ipsec.c @@ -39,10 +39,14 @@ static ssize_t nsim_dbg_netdev_ops_read(struct file *filp, if (!sap->used) continue; - p += scnprintf(p, bufsize - (p - buf), - "sa[%i] %cx ipaddr=0x%08x %08x %08x %08x\n", - i, (sap->rx ? 'r' : 't'), sap->ipaddr[0], - sap->ipaddr[1], sap->ipaddr[2], sap->ipaddr[3]); + if (sap->xs->props.family == AF_INET6) + p += scnprintf(p, bufsize - (p - buf), + "sa[%i] %cx ipaddr=%pI6c\n", + i, (sap->rx ? 'r' : 't'), &sap->ipaddr); + else + p += scnprintf(p, bufsize - (p - buf), + "sa[%i] %cx ipaddr=%pI4\n", + i, (sap->rx ? 'r' : 't'), &sap->ipaddr[3]); p += scnprintf(p, bufsize - (p - buf), "sa[%i] spi=0x%08x proto=0x%x salt=0x%08x crypt=%d\n", i, be32_to_cpu(sap->xs->id.spi), @@ -176,14 +180,13 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs, return ret; } - if (xs->xso.dir == XFRM_DEV_OFFLOAD_IN) { + if (xs->xso.dir == XFRM_DEV_OFFLOAD_IN) sa.rx = true; - if (xs->props.family == AF_INET6) - memcpy(sa.ipaddr, &xs->id.daddr.a6, 16); - else - memcpy(&sa.ipaddr[3], &xs->id.daddr.a4, 4); - } + if (xs->props.family == AF_INET6) + memcpy(sa.ipaddr, &xs->id.daddr.a6, 16); + else + memcpy(&sa.ipaddr[3], &xs->id.daddr.a4, 4); /* the preparations worked, so save the info */ memcpy(&ipsec->sa[sa_idx], &sa, sizeof(sa)); diff --git a/drivers/net/netdevsim/macsec.c b/drivers/net/netdevsim/macsec.c index aa007b1e4b785e..bdc8020d588e0d 100644 --- a/drivers/net/netdevsim/macsec.c +++ b/drivers/net/netdevsim/macsec.c @@ -46,7 +46,7 @@ static int nsim_macsec_add_secy(struct macsec_context *ctx) return -ENOSPC; } - netdev_dbg(ctx->netdev, "%s: adding new secy with sci %08llx at index %d\n", + netdev_dbg(ctx->netdev, "%s: adding new secy with sci %016llx at index %d\n", __func__, sci_to_cpu(ctx->secy->sci), idx); ns->macsec.nsim_secy[idx].used = true; ns->macsec.nsim_secy[idx].nsim_rxsc_count = 0; @@ -63,12 +63,12 @@ static int nsim_macsec_upd_secy(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: updating secy with sci %08llx at index %d\n", + netdev_dbg(ctx->netdev, "%s: updating secy with sci %016llx at index %d\n", __func__, sci_to_cpu(ctx->secy->sci), idx); return 0; @@ -81,12 +81,12 @@ static int nsim_macsec_del_secy(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: removing SecY with SCI %08llx at index %d\n", + netdev_dbg(ctx->netdev, "%s: removing SecY with SCI %016llx at index %d\n", __func__, sci_to_cpu(ctx->secy->sci), idx); ns->macsec.nsim_secy[idx].used = false; @@ -104,7 +104,7 @@ static int nsim_macsec_add_rxsc(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } @@ -122,7 +122,7 @@ static int nsim_macsec_add_rxsc(struct macsec_context *ctx) netdev_err(ctx->netdev, "%s: nsim_rxsc_count not full but all RXSCs used\n", __func__); - netdev_dbg(ctx->netdev, "%s: adding new rxsc with sci %08llx at index %d\n", + netdev_dbg(ctx->netdev, "%s: adding new rxsc with sci %016llx at index %d\n", __func__, sci_to_cpu(ctx->rx_sc->sci), idx); secy->nsim_rxsc[idx].used = true; secy->nsim_rxsc[idx].sci = ctx->rx_sc->sci; @@ -139,7 +139,7 @@ static int nsim_macsec_upd_rxsc(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } @@ -147,12 +147,12 @@ static int nsim_macsec_upd_rxsc(struct macsec_context *ctx) idx = nsim_macsec_find_rxsc(secy, ctx->rx_sc->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in RXSC table\n", __func__, sci_to_cpu(ctx->rx_sc->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: updating RXSC with sci %08llx at index %d\n", + netdev_dbg(ctx->netdev, "%s: updating RXSC with sci %016llx at index %d\n", __func__, sci_to_cpu(ctx->rx_sc->sci), idx); return 0; @@ -166,7 +166,7 @@ static int nsim_macsec_del_rxsc(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } @@ -174,12 +174,12 @@ static int nsim_macsec_del_rxsc(struct macsec_context *ctx) idx = nsim_macsec_find_rxsc(secy, ctx->rx_sc->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in RXSC table\n", __func__, sci_to_cpu(ctx->rx_sc->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: removing RXSC with sci %08llx at index %d\n", + netdev_dbg(ctx->netdev, "%s: removing RXSC with sci %016llx at index %d\n", __func__, sci_to_cpu(ctx->rx_sc->sci), idx); secy->nsim_rxsc[idx].used = false; @@ -197,7 +197,7 @@ static int nsim_macsec_add_rxsa(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } @@ -205,12 +205,12 @@ static int nsim_macsec_add_rxsa(struct macsec_context *ctx) idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in RXSC table\n", __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n", + netdev_dbg(ctx->netdev, "%s: RXSC with sci %016llx, AN %u\n", __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num); return 0; @@ -224,7 +224,7 @@ static int nsim_macsec_upd_rxsa(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } @@ -232,12 +232,12 @@ static int nsim_macsec_upd_rxsa(struct macsec_context *ctx) idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in RXSC table\n", __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n", + netdev_dbg(ctx->netdev, "%s: RXSC with sci %016llx, AN %u\n", __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num); return 0; @@ -251,7 +251,7 @@ static int nsim_macsec_del_rxsa(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } @@ -259,12 +259,12 @@ static int nsim_macsec_del_rxsa(struct macsec_context *ctx) idx = nsim_macsec_find_rxsc(secy, ctx->sa.rx_sa->sc->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in RXSC table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in RXSC table\n", __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: RXSC with sci %08llx, AN %u\n", + netdev_dbg(ctx->netdev, "%s: RXSC with sci %016llx, AN %u\n", __func__, sci_to_cpu(ctx->sa.rx_sa->sc->sci), ctx->sa.assoc_num); return 0; @@ -277,12 +277,12 @@ static int nsim_macsec_add_txsa(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n", + netdev_dbg(ctx->netdev, "%s: SECY with sci %016llx, AN %u\n", __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num); return 0; @@ -295,12 +295,12 @@ static int nsim_macsec_upd_txsa(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n", + netdev_dbg(ctx->netdev, "%s: SECY with sci %016llx, AN %u\n", __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num); return 0; @@ -313,12 +313,12 @@ static int nsim_macsec_del_txsa(struct macsec_context *ctx) idx = nsim_macsec_find_secy(ns, ctx->secy->sci); if (idx < 0) { - netdev_err(ctx->netdev, "%s: sci %08llx not found in secy table\n", + netdev_err(ctx->netdev, "%s: sci %016llx not found in secy table\n", __func__, sci_to_cpu(ctx->secy->sci)); return -ENOENT; } - netdev_dbg(ctx->netdev, "%s: SECY with sci %08llx, AN %u\n", + netdev_dbg(ctx->netdev, "%s: SECY with sci %016llx, AN %u\n", __func__, sci_to_cpu(ctx->secy->sci), ctx->sa.assoc_num); return 0; diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 017a6102be0a22..e068a9761c094e 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -475,6 +476,43 @@ static int nsim_stop(struct net_device *dev) return 0; } +static int nsim_shaper_set(struct net_shaper_binding *binding, + const struct net_shaper *shaper, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static int nsim_shaper_del(struct net_shaper_binding *binding, + const struct net_shaper_handle *handle, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static int nsim_shaper_group(struct net_shaper_binding *binding, + int leaves_count, + const struct net_shaper *leaves, + const struct net_shaper *root, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static void nsim_shaper_cap(struct net_shaper_binding *binding, + enum net_shaper_scope scope, + unsigned long *flags) +{ + *flags = ULONG_MAX; +} + +static const struct net_shaper_ops nsim_shaper_ops = { + .set = nsim_shaper_set, + .delete = nsim_shaper_del, + .group = nsim_shaper_group, + .capabilities = nsim_shaper_cap, +}; + static const struct net_device_ops nsim_netdev_ops = { .ndo_start_xmit = nsim_start_xmit, .ndo_set_rx_mode = nsim_set_rx_mode, @@ -496,6 +534,7 @@ static const struct net_device_ops nsim_netdev_ops = { .ndo_bpf = nsim_bpf, .ndo_open = nsim_open, .ndo_stop = nsim_stop, + .net_shaper_ops = &nsim_shaper_ops, }; static const struct net_device_ops nsim_vf_netdev_ops = { @@ -596,10 +635,10 @@ nsim_pp_hold_write(struct file *file, const char __user *data, page_pool_put_full_page(ns->page->pp, ns->page, false); ns->page = NULL; } - rtnl_unlock(); exit: - return count; + rtnl_unlock(); + return ret; } static const struct file_operations nsim_pp_hold_fops = { @@ -624,7 +663,11 @@ static void nsim_setup(struct net_device *dev) NETIF_F_FRAGLIST | NETIF_F_HW_CSUM | NETIF_F_TSO; - dev->hw_features |= NETIF_F_HW_TC; + dev->hw_features |= NETIF_F_HW_TC | + NETIF_F_SG | + NETIF_F_FRAGLIST | + NETIF_F_HW_CSUM | + NETIF_F_TSO; dev->max_mtu = ETH_MAX_MTU; dev->xdp_features = NETDEV_XDP_ACT_HW_OFFLOAD; } diff --git a/drivers/net/netkit.c b/drivers/net/netkit.c index 059269557d9264..c1d881dc6409a4 100644 --- a/drivers/net/netkit.c +++ b/drivers/net/netkit.c @@ -20,6 +20,7 @@ struct netkit { struct net_device __rcu *peer; struct bpf_mprog_entry __rcu *active; enum netkit_action policy; + enum netkit_scrub scrub; struct bpf_mprog_bundle bundle; /* Needed in slow-path */ @@ -50,12 +51,24 @@ netkit_run(const struct bpf_mprog_entry *entry, struct sk_buff *skb, return ret; } -static void netkit_prep_forward(struct sk_buff *skb, bool xnet) +static void netkit_xnet(struct sk_buff *skb) { - skb_scrub_packet(skb, xnet); skb->priority = 0; + skb->mark = 0; +} + +static void netkit_prep_forward(struct sk_buff *skb, + bool xnet, bool xnet_scrub) +{ + skb_scrub_packet(skb, false); nf_skip_egress(skb, true); skb_reset_mac_header(skb); + if (!xnet) + return; + ipvs_reset(skb); + skb_clear_tstamp(skb); + if (xnet_scrub) + netkit_xnet(skb); } static struct netkit *netkit_priv(const struct net_device *dev) @@ -80,7 +93,8 @@ static netdev_tx_t netkit_xmit(struct sk_buff *skb, struct net_device *dev) !pskb_may_pull(skb, ETH_HLEN) || skb_orphan_frags(skb, GFP_ATOMIC))) goto drop; - netkit_prep_forward(skb, !net_eq(dev_net(dev), dev_net(peer))); + netkit_prep_forward(skb, !net_eq(dev_net(dev), dev_net(peer)), + nk->scrub); eth_skb_pkt_type(skb, peer); skb->dev = peer; entry = rcu_dereference(nk->active); @@ -297,20 +311,6 @@ static int netkit_check_policy(int policy, struct nlattr *tb, } } -static int netkit_check_mode(int mode, struct nlattr *tb, - struct netlink_ext_ack *extack) -{ - switch (mode) { - case NETKIT_L2: - case NETKIT_L3: - return 0; - default: - NL_SET_ERR_MSG_ATTR(extack, tb, - "Provided device mode can only be L2 or L3"); - return -EINVAL; - } -} - static int netkit_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { @@ -327,52 +327,47 @@ static int netkit_validate(struct nlattr *tb[], struct nlattr *data[], static struct rtnl_link_ops netkit_link_ops; -static int netkit_new_link(struct net *src_net, struct net_device *dev, +static int netkit_new_link(struct net *peer_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { struct nlattr *peer_tb[IFLA_MAX + 1], **tbp = tb, *attr; - enum netkit_action default_prim = NETKIT_PASS; - enum netkit_action default_peer = NETKIT_PASS; + enum netkit_action policy_prim = NETKIT_PASS; + enum netkit_action policy_peer = NETKIT_PASS; + enum netkit_scrub scrub_prim = NETKIT_SCRUB_DEFAULT; + enum netkit_scrub scrub_peer = NETKIT_SCRUB_DEFAULT; enum netkit_mode mode = NETKIT_L3; unsigned char ifname_assign_type; struct ifinfomsg *ifmp = NULL; struct net_device *peer; char ifname[IFNAMSIZ]; struct netkit *nk; - struct net *net; int err; if (data) { - if (data[IFLA_NETKIT_MODE]) { - attr = data[IFLA_NETKIT_MODE]; - mode = nla_get_u32(attr); - err = netkit_check_mode(mode, attr, extack); - if (err < 0) - return err; - } + if (data[IFLA_NETKIT_MODE]) + mode = nla_get_u32(data[IFLA_NETKIT_MODE]); if (data[IFLA_NETKIT_PEER_INFO]) { attr = data[IFLA_NETKIT_PEER_INFO]; ifmp = nla_data(attr); - err = rtnl_nla_parse_ifinfomsg(peer_tb, attr, extack); - if (err < 0) - return err; - err = netkit_validate(peer_tb, NULL, extack); - if (err < 0) - return err; + rtnl_nla_parse_ifinfomsg(peer_tb, attr, extack); tbp = peer_tb; } + if (data[IFLA_NETKIT_SCRUB]) + scrub_prim = nla_get_u32(data[IFLA_NETKIT_SCRUB]); + if (data[IFLA_NETKIT_PEER_SCRUB]) + scrub_peer = nla_get_u32(data[IFLA_NETKIT_PEER_SCRUB]); if (data[IFLA_NETKIT_POLICY]) { attr = data[IFLA_NETKIT_POLICY]; - default_prim = nla_get_u32(attr); - err = netkit_check_policy(default_prim, attr, extack); + policy_prim = nla_get_u32(attr); + err = netkit_check_policy(policy_prim, attr, extack); if (err < 0) return err; } if (data[IFLA_NETKIT_PEER_POLICY]) { attr = data[IFLA_NETKIT_PEER_POLICY]; - default_peer = nla_get_u32(attr); - err = netkit_check_policy(default_peer, attr, extack); + policy_peer = nla_get_u32(attr); + err = netkit_check_policy(policy_peer, attr, extack); if (err < 0) return err; } @@ -389,16 +384,10 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev, (tb[IFLA_ADDRESS] || tbp[IFLA_ADDRESS])) return -EOPNOTSUPP; - net = rtnl_link_get_net(src_net, tbp); - if (IS_ERR(net)) - return PTR_ERR(net); - - peer = rtnl_create_link(net, ifname, ifname_assign_type, + peer = rtnl_create_link(peer_net, ifname, ifname_assign_type, &netkit_link_ops, tbp, extack); - if (IS_ERR(peer)) { - put_net(net); + if (IS_ERR(peer)) return PTR_ERR(peer); - } netif_inherit_tso_max(peer, dev); @@ -409,12 +398,12 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev, nk = netkit_priv(peer); nk->primary = false; - nk->policy = default_peer; + nk->policy = policy_peer; + nk->scrub = scrub_peer; nk->mode = mode; bpf_mprog_bundle_init(&nk->bundle); err = register_netdevice(peer); - put_net(net); if (err < 0) goto err_register_peer; netif_carrier_off(peer); @@ -434,7 +423,8 @@ static int netkit_new_link(struct net *src_net, struct net_device *dev, nk = netkit_priv(dev); nk->primary = true; - nk->policy = default_prim; + nk->policy = policy_prim; + nk->scrub = scrub_prim; nk->mode = mode; bpf_mprog_bundle_init(&nk->bundle); @@ -874,6 +864,18 @@ static int netkit_change_link(struct net_device *dev, struct nlattr *tb[], return -EACCES; } + if (data[IFLA_NETKIT_SCRUB]) { + NL_SET_ERR_MSG_ATTR(extack, data[IFLA_NETKIT_SCRUB], + "netkit scrubbing cannot be changed after device creation"); + return -EACCES; + } + + if (data[IFLA_NETKIT_PEER_SCRUB]) { + NL_SET_ERR_MSG_ATTR(extack, data[IFLA_NETKIT_PEER_SCRUB], + "netkit scrubbing cannot be changed after device creation"); + return -EACCES; + } + if (data[IFLA_NETKIT_PEER_INFO]) { NL_SET_ERR_MSG_ATTR(extack, data[IFLA_NETKIT_PEER_INFO], "netkit peer info cannot be changed after device creation"); @@ -908,8 +910,10 @@ static size_t netkit_get_size(const struct net_device *dev) { return nla_total_size(sizeof(u32)) + /* IFLA_NETKIT_POLICY */ nla_total_size(sizeof(u32)) + /* IFLA_NETKIT_PEER_POLICY */ - nla_total_size(sizeof(u8)) + /* IFLA_NETKIT_PRIMARY */ + nla_total_size(sizeof(u32)) + /* IFLA_NETKIT_SCRUB */ + nla_total_size(sizeof(u32)) + /* IFLA_NETKIT_PEER_SCRUB */ nla_total_size(sizeof(u32)) + /* IFLA_NETKIT_MODE */ + nla_total_size(sizeof(u8)) + /* IFLA_NETKIT_PRIMARY */ 0; } @@ -924,11 +928,15 @@ static int netkit_fill_info(struct sk_buff *skb, const struct net_device *dev) return -EMSGSIZE; if (nla_put_u32(skb, IFLA_NETKIT_MODE, nk->mode)) return -EMSGSIZE; + if (nla_put_u32(skb, IFLA_NETKIT_SCRUB, nk->scrub)) + return -EMSGSIZE; if (peer) { nk = netkit_priv(peer); if (nla_put_u32(skb, IFLA_NETKIT_PEER_POLICY, nk->policy)) return -EMSGSIZE; + if (nla_put_u32(skb, IFLA_NETKIT_PEER_SCRUB, nk->scrub)) + return -EMSGSIZE; } return 0; @@ -936,9 +944,11 @@ static int netkit_fill_info(struct sk_buff *skb, const struct net_device *dev) static const struct nla_policy netkit_policy[IFLA_NETKIT_MAX + 1] = { [IFLA_NETKIT_PEER_INFO] = { .len = sizeof(struct ifinfomsg) }, + [IFLA_NETKIT_MODE] = NLA_POLICY_MAX(NLA_U32, NETKIT_L3), [IFLA_NETKIT_POLICY] = { .type = NLA_U32 }, - [IFLA_NETKIT_MODE] = { .type = NLA_U32 }, [IFLA_NETKIT_PEER_POLICY] = { .type = NLA_U32 }, + [IFLA_NETKIT_SCRUB] = NLA_POLICY_MAX(NLA_U32, NETKIT_SCRUB_DEFAULT), + [IFLA_NETKIT_PEER_SCRUB] = NLA_POLICY_MAX(NLA_U32, NETKIT_SCRUB_DEFAULT), [IFLA_NETKIT_PRIMARY] = { .type = NLA_REJECT, .reject_message = "Primary attribute is read-only" }, }; @@ -955,6 +965,7 @@ static struct rtnl_link_ops netkit_link_ops = { .fill_info = netkit_fill_info, .policy = netkit_policy, .validate = netkit_validate, + .peer_type = IFLA_NETKIT_PEER_INFO, .maxtype = IFLA_NETKIT_MAX, }; diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c index d0a722d43368f7..61944574d087d4 100644 --- a/drivers/net/pcs/pcs-rzn1-miic.c +++ b/drivers/net/pcs/pcs-rzn1-miic.c @@ -552,7 +552,7 @@ static struct platform_driver miic_driver = { .of_match_table = miic_of_mtable, }, .probe = miic_probe, - .remove_new = miic_remove, + .remove = miic_remove, }; module_platform_driver(miic_driver); diff --git a/drivers/net/pcs/pcs-xpcs-nxp.c b/drivers/net/pcs/pcs-xpcs-nxp.c index d16fc58cd48d3d..e8efe94cf4ec7d 100644 --- a/drivers/net/pcs/pcs-xpcs-nxp.c +++ b/drivers/net/pcs/pcs-xpcs-nxp.c @@ -152,26 +152,18 @@ static int nxp_sja1110_pma_config(struct dw_xpcs *xpcs, /* Enable TX and RX PLLs and circuits. * Release reset of PMA to enable data flow to/from PCS. */ - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE); - if (ret < 0) - return ret; - - val = ret & ~(SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD | - SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN | - SJA1110_RESET_SER | SJA1110_RESET_DES); - val |= SJA1110_RXPKDETEN | SJA1110_RCVEN; - - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE, val); + ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE, + SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD | + SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN | + SJA1110_RESET_SER | SJA1110_RESET_DES | + SJA1110_RXPKDETEN | SJA1110_RCVEN, + SJA1110_RXPKDETEN | SJA1110_RCVEN); if (ret < 0) return ret; /* Program continuous-time linear equalizer (CTLE) settings. */ - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE, - rx_cdr_ctle); - if (ret < 0) - return ret; - - return 0; + return xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE, + rx_cdr_ctle); } int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs) diff --git a/drivers/net/pcs/pcs-xpcs-wx.c b/drivers/net/pcs/pcs-xpcs-wx.c index 5f5cd3596cb846..fc52f7aa5f5965 100644 --- a/drivers/net/pcs/pcs-xpcs-wx.c +++ b/drivers/net/pcs/pcs-xpcs-wx.c @@ -46,25 +46,23 @@ #define TXGBE_VCO_CAL_LD0 0x72 #define TXGBE_VCO_CAL_REF0 0x76 -static int txgbe_read_pma(struct dw_xpcs *xpcs, int reg) +static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val) { - return xpcs_read(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg); + return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val); } -static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val) +static int txgbe_modify_pma(struct dw_xpcs *xpcs, int reg, u16 mask, u16 set) { - return xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val); + return xpcs_modify(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, mask, + set); } static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs) { - int val; - txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21); txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0); - val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1); - val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL); - txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val); + txgbe_modify_pma(xpcs, TXGBE_TX_GENCTL1, TXGBE_TX_GENCTL1_VBOOST_LVL, + FIELD_PREP(TXGBE_TX_GENCTL1_VBOOST_LVL, 0x5)); txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL | TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF)); txgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549); @@ -78,38 +76,29 @@ static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs) txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(5)); - val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL); - val &= ~TXGBE_RX_EQ_ATTN_LVL0; - txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val); + txgbe_modify_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, TXGBE_RX_EQ_ATTN_LVL0, 0); txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE); - val = txgbe_read_pma(xpcs, TXGBE_AFE_DFE_ENABLE); - val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0); - txgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, val); - val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_CTL4); - val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0; - txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, val); + txgbe_modify_pma(xpcs, TXGBE_AFE_DFE_ENABLE, + TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0, 0); + txgbe_modify_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_ADAPT0, + 0); } static void txgbe_pma_config_1g(struct dw_xpcs *xpcs) { - int val; - - val = txgbe_read_pma(xpcs, TXGBE_TX_GENCTL1); - val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTL1_VBOOST_LVL); - val &= ~TXGBE_TX_GENCTL1_VBOOST_EN0; - txgbe_write_pma(xpcs, TXGBE_TX_GENCTL1, val); + txgbe_modify_pma(xpcs, TXGBE_TX_GENCTL1, + TXGBE_TX_GENCTL1_VBOOST_LVL | + TXGBE_TX_GENCTL1_VBOOST_EN0, + FIELD_PREP(TXGBE_TX_GENCTL1_VBOOST_LVL, 0x5)); txgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL | TXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF)); txgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) | TXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6)); - val = txgbe_read_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL); - val &= ~TXGBE_RX_EQ_ATTN_LVL0; - txgbe_write_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, val); + txgbe_modify_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, TXGBE_RX_EQ_ATTN_LVL0, 0); txgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0); - val = txgbe_read_pma(xpcs, TXGBE_RX_GEN_CTL3); - val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0); - txgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL3, val); + txgbe_modify_pma(xpcs, TXGBE_RX_GEN_CTL3, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0, + FIELD_PREP(TXGBE_RX_GEN_CTL3_LOS_TRSHLD0, 0x4)); txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20); txgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46); @@ -172,7 +161,7 @@ static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs) int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface) { - int val, ret; + int ret; switch (interface) { case PHY_INTERFACE_MODE_10GBASER: @@ -194,9 +183,8 @@ int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface) if (interface == PHY_INTERFACE_MODE_10GBASER) { xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR); - val = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1); - val |= MDIO_CTRL1_SPEED10G; - xpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, val); + xpcs_modify(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, + MDIO_CTRL1_SPEED10G, MDIO_CTRL1_SPEED10G); txgbe_pma_config_10gbaser(xpcs); } else { xpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX); diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 82463f9d50c85c..7246a910728d13 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -107,49 +107,9 @@ static const int xpcs_2500basex_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; -static const phy_interface_t xpcs_usxgmii_interfaces[] = { - PHY_INTERFACE_MODE_USXGMII, -}; - -static const phy_interface_t xpcs_10gkr_interfaces[] = { - PHY_INTERFACE_MODE_10GKR, -}; - -static const phy_interface_t xpcs_xlgmii_interfaces[] = { - PHY_INTERFACE_MODE_XLGMII, -}; - -static const phy_interface_t xpcs_10gbaser_interfaces[] = { - PHY_INTERFACE_MODE_10GBASER, -}; - -static const phy_interface_t xpcs_sgmii_interfaces[] = { - PHY_INTERFACE_MODE_SGMII, -}; - -static const phy_interface_t xpcs_1000basex_interfaces[] = { - PHY_INTERFACE_MODE_1000BASEX, -}; - -static const phy_interface_t xpcs_2500basex_interfaces[] = { - PHY_INTERFACE_MODE_2500BASEX, -}; - -enum { - DW_XPCS_USXGMII, - DW_XPCS_10GKR, - DW_XPCS_XLGMII, - DW_XPCS_10GBASER, - DW_XPCS_SGMII, - DW_XPCS_1000BASEX, - DW_XPCS_2500BASEX, - DW_XPCS_INTERFACE_MAX, -}; - struct dw_xpcs_compat { + phy_interface_t interface; const int *supported; - const phy_interface_t *interface; - int num_interfaces; int an_mode; int (*pma_config)(struct dw_xpcs *xpcs); }; @@ -161,26 +121,28 @@ struct dw_xpcs_desc { }; static const struct dw_xpcs_compat * -xpcs_find_compat(const struct dw_xpcs_desc *desc, phy_interface_t interface) +xpcs_find_compat(struct dw_xpcs *xpcs, phy_interface_t interface) { - int i, j; + const struct dw_xpcs_compat *compat; - for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) { - const struct dw_xpcs_compat *compat = &desc->compat[i]; - - for (j = 0; j < compat->num_interfaces; j++) - if (compat->interface[j] == interface) - return compat; - } + for (compat = xpcs->desc->compat; compat->supported; compat++) + if (compat->interface == interface) + return compat; return NULL; } +struct phylink_pcs *xpcs_to_phylink_pcs(struct dw_xpcs *xpcs) +{ + return &xpcs->pcs; +} +EXPORT_SYMBOL_GPL(xpcs_to_phylink_pcs); + int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface) { const struct dw_xpcs_compat *compat; - compat = xpcs_find_compat(xpcs->desc, interface); + compat = xpcs_find_compat(xpcs, interface); if (!compat) return -ENODEV; @@ -213,6 +175,11 @@ int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val) return mdiodev_c45_write(xpcs->mdiodev, dev, reg, val); } +int xpcs_modify(struct dw_xpcs *xpcs, int dev, u32 reg, u16 mask, u16 set) +{ + return mdiodev_c45_modify(xpcs->mdiodev, dev, reg, mask, set); +} + static int xpcs_modify_changed(struct dw_xpcs *xpcs, int dev, u32 reg, u16 mask, u16 set) { @@ -230,6 +197,12 @@ static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg, return xpcs_write(xpcs, dev, DW_VENDOR | reg, val); } +static int xpcs_modify_vendor(struct dw_xpcs *xpcs, int dev, int reg, u16 mask, + u16 set) +{ + return xpcs_modify(xpcs, dev, DW_VENDOR | reg, mask, set); +} + int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg) { return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg); @@ -240,20 +213,22 @@ int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val) return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val); } +static int xpcs_modify_vpcs(struct dw_xpcs *xpcs, int reg, u16 mask, u16 val) +{ + return xpcs_modify_vendor(xpcs, MDIO_MMD_PCS, reg, mask, val); +} + static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev) { - /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ - unsigned int retries = 12; - int ret; + int ret, val; - do { - msleep(50); - ret = xpcs_read(xpcs, dev, MDIO_CTRL1); - if (ret < 0) - return ret; - } while (ret & MDIO_CTRL1_RESET && --retries); + ret = read_poll_timeout(xpcs_read, val, + val < 0 || !(val & BMCR_RESET), + 50000, 600000, true, xpcs, dev, MII_BMCR); + if (val < 0) + ret = val; - return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0; + return ret; } static int xpcs_soft_reset(struct dw_xpcs *xpcs, @@ -275,7 +250,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs, return -EINVAL; } - ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET); + ret = xpcs_write(xpcs, dev, MII_BMCR, BMCR_RESET); if (ret < 0) return ret; @@ -336,7 +311,7 @@ static int xpcs_read_fault_c73(struct dw_xpcs *xpcs, return 0; } -static void xpcs_config_usxgmii(struct dw_xpcs *xpcs, int speed) +static void xpcs_link_up_usxgmii(struct dw_xpcs *xpcs, int speed) { int ret, speed_sel; @@ -364,37 +339,25 @@ static void xpcs_config_usxgmii(struct dw_xpcs *xpcs, int speed) return; } - ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1); - if (ret < 0) - goto out; - - ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_EN); - if (ret < 0) - goto out; - - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1); - if (ret < 0) - goto out; - - ret &= ~DW_USXGMII_SS_MASK; - ret |= speed_sel | DW_USXGMII_FULL; - - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret); + ret = xpcs_modify_vpcs(xpcs, MDIO_CTRL1, DW_USXGMII_EN, DW_USXGMII_EN); if (ret < 0) goto out; - ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1); + ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, DW_USXGMII_SS_MASK, + speed_sel | DW_USXGMII_FULL); if (ret < 0) goto out; - ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST); + ret = xpcs_modify_vpcs(xpcs, MDIO_CTRL1, DW_USXGMII_RST, + DW_USXGMII_RST); if (ret < 0) goto out; return; out: - pr_err("%s: XPCS access returned %pe\n", __func__, ERR_PTR(ret)); + dev_err(&xpcs->mdiodev->dev, "%s: XPCS access returned %pe\n", + __func__, ERR_PTR(ret)); } static int _xpcs_config_aneg_c73(struct dw_xpcs *xpcs, @@ -451,13 +414,9 @@ static int xpcs_config_aneg_c73(struct dw_xpcs *xpcs, if (ret < 0) return ret; - ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_CTRL1); - if (ret < 0) - return ret; - - ret |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART; - - return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret); + return xpcs_modify(xpcs, MDIO_MMD_AN, MDIO_CTRL1, + MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART, + MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART); } static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs, @@ -592,7 +551,7 @@ static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, int i; xpcs = phylink_pcs_to_xpcs(pcs); - compat = xpcs_find_compat(xpcs->desc, state->interface); + compat = xpcs_find_compat(xpcs, state->interface); if (!compat) return -EINVAL; @@ -610,62 +569,72 @@ static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported, void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces) { - int i, j; - - for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) { - const struct dw_xpcs_compat *compat = &xpcs->desc->compat[i]; + const struct dw_xpcs_compat *compat; - for (j = 0; j < compat->num_interfaces; j++) - __set_bit(compat->interface[j], interfaces); - } + for (compat = xpcs->desc->compat; compat->supported; compat++) + __set_bit(compat->interface, interfaces); } EXPORT_SYMBOL_GPL(xpcs_get_interfaces); int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable) { + u16 mask, val; int ret; - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0); - if (ret < 0) - return ret; + mask = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN | + DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN | + DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL | + DW_VR_MII_EEE_MULT_FACT_100NS; - if (enable) { - /* Enable EEE */ - ret = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN | + if (enable) + val = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN | DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN | DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL | - mult_fact_100ns << DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT; - } else { - ret &= ~(DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN | - DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN | - DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL | - DW_VR_MII_EEE_MULT_FACT_100NS); - } + FIELD_PREP(DW_VR_MII_EEE_MULT_FACT_100NS, + mult_fact_100ns); + else + val = 0; - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, ret); + ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, mask, + val); if (ret < 0) return ret; - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1); - if (ret < 0) - return ret; + return xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, + DW_VR_MII_EEE_TRN_LPI, + enable ? DW_VR_MII_EEE_TRN_LPI : 0); +} +EXPORT_SYMBOL_GPL(xpcs_config_eee); - if (enable) - ret |= DW_VR_MII_EEE_TRN_LPI; - else - ret &= ~DW_VR_MII_EEE_TRN_LPI; +static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface) +{ + struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); + const struct dw_xpcs_compat *compat; + int ret; + + if (!xpcs->need_reset) + return; - return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, ret); + compat = xpcs_find_compat(xpcs, interface); + if (!compat) { + dev_err(&xpcs->mdiodev->dev, "unsupported interface %s\n", + phy_modes(interface)); + return; + } + + ret = xpcs_soft_reset(xpcs, compat); + if (ret) + dev_err(&xpcs->mdiodev->dev, "soft reset failed: %pe\n", + ERR_PTR(ret)); + + xpcs->need_reset = false; } -EXPORT_SYMBOL_GPL(xpcs_config_eee); static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int neg_mode) { int ret, mdio_ctrl, tx_conf; - - if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) - xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1); + u16 mask, val; /* For AN for C37 SGMII mode, the settings are :- * 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case @@ -677,63 +646,60 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, * speed/duplex mode change by HW after SGMII AN complete) * 5) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 1b (Enable SGMII AN) * + * Note that VR_MII_MMD_CTRL is MII_BMCR. + * * Note: Since it is MAC side SGMII, there is no need to set * SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from * PHY about the link state change after C28 AN is completed * between PHY and Link Partner. There is also no need to * trigger AN restart for MAC-side SGMII. */ - mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL); + mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR); if (mdio_ctrl < 0) return mdio_ctrl; - if (mdio_ctrl & AN_CL37_EN) { - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, - mdio_ctrl & ~AN_CL37_EN); + if (mdio_ctrl & BMCR_ANENABLE) { + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR, + mdio_ctrl & ~BMCR_ANENABLE); if (ret < 0) return ret; } - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL); - if (ret < 0) - return ret; + mask = DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK; + val = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK, + DW_VR_MII_PCS_MODE_C37_SGMII); - ret &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK); - ret |= (DW_VR_MII_PCS_MODE_C37_SGMII << - DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT & - DW_VR_MII_PCS_MODE_MASK); if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) { - ret |= DW_VR_MII_AN_CTRL_8BIT; + mask |= DW_VR_MII_AN_CTRL_8BIT; + val |= DW_VR_MII_AN_CTRL_8BIT; /* Hardware requires it to be PHY side SGMII */ tx_conf = DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII; } else { tx_conf = DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII; } - ret |= tx_conf << DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT & - DW_VR_MII_TX_CONFIG_MASK; - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret); - if (ret < 0) - return ret; - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1); + val |= FIELD_PREP(DW_VR_MII_TX_CONFIG_MASK, tx_conf); + + ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, mask, val); if (ret < 0) return ret; + mask = DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) - ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; - else - ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; + val = DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; - if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) - ret |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL; + if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) { + mask |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL; + val |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL; + } - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret); + ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, mask, val); if (ret < 0) return ret; if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, - mdio_ctrl | AN_CL37_EN); + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR, + mdio_ctrl | BMCR_ANENABLE); return ret; } @@ -745,34 +711,36 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, phy_interface_t interface = PHY_INTERFACE_MODE_1000BASEX; int ret, mdio_ctrl, adv; bool changed = 0; - - if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) - xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_CL37_BP | DW_EN_VSMMD1); + u16 mask, val; /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must * be disabled first:- * 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 00b (1000BASE-X C37) + * + * Note that VR_MII_MMD_CTRL is MII_BMCR. */ - mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL); + mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR); if (mdio_ctrl < 0) return mdio_ctrl; - if (mdio_ctrl & AN_CL37_EN) { - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, - mdio_ctrl & ~AN_CL37_EN); + if (mdio_ctrl & BMCR_ANENABLE) { + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR, + mdio_ctrl & ~BMCR_ANENABLE); if (ret < 0) return ret; } - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL); - if (ret < 0) - return ret; + mask = DW_VR_MII_PCS_MODE_MASK; + val = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK, + DW_VR_MII_PCS_MODE_C37_1000BASEX); + + if (!xpcs->pcs.poll) { + mask |= DW_VR_MII_AN_INTR_EN; + val |= DW_VR_MII_AN_INTR_EN; + } - ret &= ~DW_VR_MII_PCS_MODE_MASK; - if (!xpcs->pcs.poll) - ret |= DW_VR_MII_AN_INTR_EN; - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret); + ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, mask, val); if (ret < 0) return ret; @@ -796,8 +764,8 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, return ret; if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, - mdio_ctrl | AN_CL37_EN); + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR, + mdio_ctrl | BMCR_ANENABLE); if (ret < 0) return ret; } @@ -809,31 +777,26 @@ static int xpcs_config_2500basex(struct dw_xpcs *xpcs) { int ret; - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1); - if (ret < 0) - return ret; - ret |= DW_VR_MII_DIG_CTRL1_2G5_EN; - ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret); + ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, + DW_VR_MII_DIG_CTRL1_2G5_EN | + DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW, + DW_VR_MII_DIG_CTRL1_2G5_EN); if (ret < 0) return ret; - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL); - if (ret < 0) - return ret; - ret &= ~AN_CL37_EN; - ret |= SGMII_SPEED_SS6; - ret &= ~SGMII_SPEED_SS13; - return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret); + return xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, + BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_SPEED100, + BMCR_SPEED1000); } -int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, - const unsigned long *advertising, unsigned int neg_mode) +static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, + const unsigned long *advertising, + unsigned int neg_mode) { const struct dw_xpcs_compat *compat; int ret; - compat = xpcs_find_compat(xpcs->desc, interface); + compat = xpcs_find_compat(xpcs, interface); if (!compat) return -ENODEV; @@ -841,6 +804,14 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, ret = txgbe_xpcs_switch_mode(xpcs, interface); if (ret) return ret; + + /* Wangxun devices need backplane CL37 AN enabled for + * SGMII and 1000base-X + */ + if (interface == PHY_INTERFACE_MODE_SGMII || + interface == PHY_INTERFACE_MODE_1000BASEX) + xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, + DW_CL37_BP | DW_EN_VSMMD1); } switch (compat->an_mode) { @@ -881,7 +852,6 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, return 0; } -EXPORT_SYMBOL_GPL(xpcs_do_config); static int xpcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, @@ -989,8 +959,7 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, state->link = true; - speed_value = (ret & DW_VR_MII_AN_STS_C37_ANSGM_SP) >> - DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT; + speed_value = FIELD_GET(DW_VR_MII_AN_STS_C37_ANSGM_SP, ret); if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000) state->speed = SPEED_1000; else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100) @@ -1007,14 +976,14 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, state->link = true; - speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1); + speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR); if (speed < 0) return speed; - speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6; - if (speed == SGMII_SPEED_SS6) + speed &= BMCR_SPEED100 | BMCR_SPEED1000; + if (speed == BMCR_SPEED1000) state->speed = SPEED_1000; - else if (speed == SGMII_SPEED_SS13) + else if (speed == BMCR_SPEED100) state->speed = SPEED_100; else if (speed == 0) state->speed = SPEED_10; @@ -1023,9 +992,9 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs, if (duplex < 0) return duplex; - if (duplex & DW_FULL_DUPLEX) + if (duplex & ADVERTISE_1000XFULL) state->duplex = DUPLEX_FULL; - else if (duplex & DW_HALF_DUPLEX) + else if (duplex & ADVERTISE_1000XHALF) state->duplex = DUPLEX_HALF; xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0); @@ -1074,13 +1043,13 @@ static int xpcs_get_state_2500basex(struct dw_xpcs *xpcs, { int ret; - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_STS); + ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMSR); if (ret < 0) { state->link = 0; return ret; } - state->link = !!(ret & DW_VR_MII_MMD_STS_LINK_STS); + state->link = !!(ret & BMSR_LSTATUS); if (!state->link) return 0; @@ -1098,7 +1067,7 @@ static void xpcs_get_state(struct phylink_pcs *pcs, const struct dw_xpcs_compat *compat; int ret; - compat = xpcs_find_compat(xpcs->desc, state->interface); + compat = xpcs_find_compat(xpcs, state->interface); if (!compat) return; @@ -1108,108 +1077,94 @@ static void xpcs_get_state(struct phylink_pcs *pcs, break; case DW_AN_C73: ret = xpcs_get_state_c73(xpcs, state, compat); - if (ret) { - pr_err("xpcs_get_state_c73 returned %pe\n", - ERR_PTR(ret)); - return; - } + if (ret) + dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n", + "xpcs_get_state_c73", ERR_PTR(ret)); break; case DW_AN_C37_SGMII: ret = xpcs_get_state_c37_sgmii(xpcs, state); - if (ret) { - pr_err("xpcs_get_state_c37_sgmii returned %pe\n", - ERR_PTR(ret)); - } + if (ret) + dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n", + "xpcs_get_state_c37_sgmii", ERR_PTR(ret)); break; case DW_AN_C37_1000BASEX: ret = xpcs_get_state_c37_1000basex(xpcs, state); - if (ret) { - pr_err("xpcs_get_state_c37_1000basex returned %pe\n", - ERR_PTR(ret)); - } + if (ret) + dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n", + "xpcs_get_state_c37_1000basex", ERR_PTR(ret)); break; case DW_2500BASEX: ret = xpcs_get_state_2500basex(xpcs, state); - if (ret) { - pr_err("xpcs_get_state_2500basex returned %pe\n", - ERR_PTR(ret)); - } + if (ret) + dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n", + "xpcs_get_state_2500basex", ERR_PTR(ret)); break; default: return; } } -static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int neg_mode, - int speed, int duplex) +static void xpcs_link_up_sgmii_1000basex(struct dw_xpcs *xpcs, + unsigned int neg_mode, + phy_interface_t interface, + int speed, int duplex) { - int val, ret; + int ret; if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) return; - val = mii_bmcr_encode_fixed(speed, duplex); - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val); - if (ret) - pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret)); -} - -static void xpcs_link_up_1000basex(struct dw_xpcs *xpcs, unsigned int neg_mode, - int speed, int duplex) -{ - int val, ret; - - if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) - return; + if (interface == PHY_INTERFACE_MODE_1000BASEX) { + if (speed != SPEED_1000) { + dev_err(&xpcs->mdiodev->dev, + "%s: speed %dMbps not supported\n", + __func__, speed); + return; + } - switch (speed) { - case SPEED_1000: - val = BMCR_SPEED1000; - break; - case SPEED_100: - case SPEED_10: - default: - pr_err("%s: speed = %d\n", __func__, speed); - return; + if (duplex != DUPLEX_FULL) + dev_err(&xpcs->mdiodev->dev, + "%s: half duplex not supported\n", + __func__); } - if (duplex == DUPLEX_FULL) - val |= BMCR_FULLDPLX; - else - pr_err("%s: half duplex not supported\n", __func__); - - ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val); + ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR, + mii_bmcr_encode_fixed(speed, duplex)); if (ret) - pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret)); + dev_err(&xpcs->mdiodev->dev, "%s: xpcs_write returned %pe\n", + __func__, ERR_PTR(ret)); } -void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, - phy_interface_t interface, int speed, int duplex) +static void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, int speed, int duplex) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); - if (interface == PHY_INTERFACE_MODE_USXGMII) - return xpcs_config_usxgmii(xpcs, speed); - if (interface == PHY_INTERFACE_MODE_SGMII) - return xpcs_link_up_sgmii(xpcs, neg_mode, speed, duplex); - if (interface == PHY_INTERFACE_MODE_1000BASEX) - return xpcs_link_up_1000basex(xpcs, neg_mode, speed, duplex); + switch (interface) { + case PHY_INTERFACE_MODE_USXGMII: + xpcs_link_up_usxgmii(xpcs, speed); + break; + + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + xpcs_link_up_sgmii_1000basex(xpcs, neg_mode, interface, speed, + duplex); + break; + + default: + break; + } } -EXPORT_SYMBOL_GPL(xpcs_link_up); static void xpcs_an_restart(struct phylink_pcs *pcs) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); - int ret; - ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1); - if (ret >= 0) { - ret |= BMCR_ANRESTART; - xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret); - } + xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, BMCR_ANRESTART, + BMCR_ANRESTART); } -static int xpcs_get_id(struct dw_xpcs *xpcs) +static int xpcs_read_ids(struct dw_xpcs *xpcs) { int ret; u32 id; @@ -1275,76 +1230,62 @@ static int xpcs_get_id(struct dw_xpcs *xpcs) return 0; } -static const struct dw_xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { - [DW_XPCS_USXGMII] = { +static const struct dw_xpcs_compat synopsys_xpcs_compat[] = { + { + .interface = PHY_INTERFACE_MODE_USXGMII, .supported = xpcs_usxgmii_features, - .interface = xpcs_usxgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_usxgmii_interfaces), .an_mode = DW_AN_C73, - }, - [DW_XPCS_10GKR] = { + }, { + .interface = PHY_INTERFACE_MODE_10GKR, .supported = xpcs_10gkr_features, - .interface = xpcs_10gkr_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_10gkr_interfaces), .an_mode = DW_AN_C73, - }, - [DW_XPCS_XLGMII] = { + }, { + .interface = PHY_INTERFACE_MODE_XLGMII, .supported = xpcs_xlgmii_features, - .interface = xpcs_xlgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces), .an_mode = DW_AN_C73, - }, - [DW_XPCS_10GBASER] = { + }, { + .interface = PHY_INTERFACE_MODE_10GBASER, .supported = xpcs_10gbaser_features, - .interface = xpcs_10gbaser_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_10gbaser_interfaces), .an_mode = DW_10GBASER, - }, - [DW_XPCS_SGMII] = { + }, { + .interface = PHY_INTERFACE_MODE_SGMII, .supported = xpcs_sgmii_features, - .interface = xpcs_sgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, - }, - [DW_XPCS_1000BASEX] = { + }, { + .interface = PHY_INTERFACE_MODE_1000BASEX, .supported = xpcs_1000basex_features, - .interface = xpcs_1000basex_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_1000basex_interfaces), .an_mode = DW_AN_C37_1000BASEX, - }, - [DW_XPCS_2500BASEX] = { + }, { + .interface = PHY_INTERFACE_MODE_2500BASEX, .supported = xpcs_2500basex_features, - .interface = xpcs_2500basex_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces), .an_mode = DW_2500BASEX, - }, + }, { + } }; -static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { - [DW_XPCS_SGMII] = { +static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[] = { + { + .interface = PHY_INTERFACE_MODE_SGMII, .supported = xpcs_sgmii_features, - .interface = xpcs_sgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, .pma_config = nxp_sja1105_sgmii_pma_config, - }, + }, { + } }; -static const struct dw_xpcs_compat nxp_sja1110_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { - [DW_XPCS_SGMII] = { +static const struct dw_xpcs_compat nxp_sja1110_xpcs_compat[] = { + { + .interface = PHY_INTERFACE_MODE_SGMII, .supported = xpcs_sgmii_features, - .interface = xpcs_sgmii_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces), .an_mode = DW_AN_C37_SGMII, .pma_config = nxp_sja1110_sgmii_pma_config, - }, - [DW_XPCS_2500BASEX] = { + }, { + .interface = PHY_INTERFACE_MODE_2500BASEX, .supported = xpcs_2500basex_features, - .interface = xpcs_2500basex_interfaces, - .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces), .an_mode = DW_2500BASEX, .pma_config = nxp_sja1110_2500basex_pma_config, - }, + }, { + } }; static const struct dw_xpcs_desc xpcs_desc_list[] = { @@ -1365,12 +1306,33 @@ static const struct dw_xpcs_desc xpcs_desc_list[] = { static const struct phylink_pcs_ops xpcs_phylink_ops = { .pcs_validate = xpcs_validate, + .pcs_pre_config = xpcs_pre_config, .pcs_config = xpcs_config, .pcs_get_state = xpcs_get_state, .pcs_an_restart = xpcs_an_restart, .pcs_link_up = xpcs_link_up, }; +static int xpcs_identify(struct dw_xpcs *xpcs) +{ + int i, ret; + + ret = xpcs_read_ids(xpcs); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(xpcs_desc_list); i++) { + const struct dw_xpcs_desc *entry = &xpcs_desc_list[i]; + + if ((xpcs->info.pcs & entry->mask) == entry->id) { + xpcs->desc = entry; + return 0; + } + } + + return -ENODEV; +} + static struct dw_xpcs *xpcs_create_data(struct mdio_device *mdiodev) { struct dw_xpcs *xpcs; @@ -1427,7 +1389,6 @@ static void xpcs_clear_clks(struct dw_xpcs *xpcs) static int xpcs_init_id(struct dw_xpcs *xpcs) { const struct dw_xpcs_info *info; - int i, ret; info = dev_get_platdata(&xpcs->mdiodev->dev); if (!info) { @@ -1437,45 +1398,10 @@ static int xpcs_init_id(struct dw_xpcs *xpcs) xpcs->info = *info; } - ret = xpcs_get_id(xpcs); - if (ret < 0) - return ret; - - for (i = 0; i < ARRAY_SIZE(xpcs_desc_list); i++) { - const struct dw_xpcs_desc *desc = &xpcs_desc_list[i]; - - if ((xpcs->info.pcs & desc->mask) != desc->id) - continue; - - xpcs->desc = desc; - - break; - } - - if (!xpcs->desc) - return -ENODEV; - - return 0; + return xpcs_identify(xpcs); } -static int xpcs_init_iface(struct dw_xpcs *xpcs, phy_interface_t interface) -{ - const struct dw_xpcs_compat *compat; - - compat = xpcs_find_compat(xpcs->desc, interface); - if (!compat) - return -EINVAL; - - if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) { - xpcs->pcs.poll = false; - return 0; - } - - return xpcs_soft_reset(xpcs, compat); -} - -static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, - phy_interface_t interface) +static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev) { struct dw_xpcs *xpcs; int ret; @@ -1492,9 +1418,10 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, if (ret) goto out_clear_clks; - ret = xpcs_init_iface(xpcs, interface); - if (ret) - goto out_clear_clks; + if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) + xpcs->pcs.poll = false; + else + xpcs->need_reset = true; return xpcs; @@ -1511,14 +1438,12 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, * xpcs_create_mdiodev() - create a DW xPCS instance with the MDIO @addr * @bus: pointer to the MDIO-bus descriptor for the device to be looked at * @addr: device MDIO-bus ID - * @interface: requested PHY interface * * Return: a pointer to the DW XPCS handle if successful, otherwise -ENODEV if * the PCS device couldn't be found on the bus and other negative errno related * to the data allocation and MDIO-bus communications. */ -struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr, - phy_interface_t interface) +struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr) { struct mdio_device *mdiodev; struct dw_xpcs *xpcs; @@ -1527,7 +1452,7 @@ struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr, if (IS_ERR(mdiodev)) return ERR_CAST(mdiodev); - xpcs = xpcs_create(mdiodev, interface); + xpcs = xpcs_create(mdiodev); /* xpcs_create() has taken a refcount on the mdiodev if it was * successful. If xpcs_create() fails, this will free the mdio @@ -1541,10 +1466,21 @@ struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr, } EXPORT_SYMBOL_GPL(xpcs_create_mdiodev); +struct phylink_pcs *xpcs_create_pcs_mdiodev(struct mii_bus *bus, int addr) +{ + struct dw_xpcs *xpcs; + + xpcs = xpcs_create_mdiodev(bus, addr); + if (IS_ERR(xpcs)) + return ERR_CAST(xpcs); + + return &xpcs->pcs; +} +EXPORT_SYMBOL_GPL(xpcs_create_pcs_mdiodev); + /** * xpcs_create_fwnode() - Create a DW xPCS instance from @fwnode * @fwnode: fwnode handle poining to the DW XPCS device - * @interface: requested PHY interface * * Return: a pointer to the DW XPCS handle if successful, otherwise -ENODEV if * the fwnode device is unavailable or the PCS device couldn't be found on the @@ -1552,8 +1488,7 @@ EXPORT_SYMBOL_GPL(xpcs_create_mdiodev); * other negative errno related to the data allocations and MDIO-bus * communications. */ -struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode, - phy_interface_t interface) +struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode) { struct mdio_device *mdiodev; struct dw_xpcs *xpcs; @@ -1565,7 +1500,7 @@ struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode, if (!mdiodev) return ERR_PTR(-EPROBE_DEFER); - xpcs = xpcs_create(mdiodev, interface); + xpcs = xpcs_create(mdiodev); /* xpcs_create() has taken a refcount on the mdiodev if it was * successful. If xpcs_create() fails, this will free the mdio @@ -1590,5 +1525,11 @@ void xpcs_destroy(struct dw_xpcs *xpcs) } EXPORT_SYMBOL_GPL(xpcs_destroy); +void xpcs_destroy_pcs(struct phylink_pcs *pcs) +{ + xpcs_destroy(phylink_pcs_to_xpcs(pcs)); +} +EXPORT_SYMBOL_GPL(xpcs_destroy_pcs); + MODULE_DESCRIPTION("Synopsys DesignWare XPCS library"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h index fa05adfae22048..adc5a0b3c88317 100644 --- a/drivers/net/pcs/pcs-xpcs.h +++ b/drivers/net/pcs/pcs-xpcs.h @@ -54,14 +54,9 @@ /* Clause 37 Defines */ /* VR MII MMD registers offsets */ -#define DW_VR_MII_MMD_CTRL 0x0000 -#define DW_VR_MII_MMD_STS 0x0001 -#define DW_VR_MII_MMD_STS_LINK_STS BIT(2) #define DW_VR_MII_DIG_CTRL1 0x8000 #define DW_VR_MII_AN_CTRL 0x8001 #define DW_VR_MII_AN_INTR_STS 0x8002 -/* Enable 2.5G Mode */ -#define DW_VR_MII_DIG_CTRL1_2G5_EN BIT(2) /* EEE Mode Control Register */ #define DW_VR_MII_EEE_MCTRL0 0x8006 #define DW_VR_MII_EEE_MCTRL1 0x800b @@ -69,6 +64,7 @@ /* VR_MII_DIG_CTRL1 */ #define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9) +#define DW_VR_MII_DIG_CTRL1_2G5_EN BIT(2) #define DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL BIT(0) /* VR_MII_DIG_CTRL2 */ @@ -77,11 +73,9 @@ /* VR_MII_AN_CTRL */ #define DW_VR_MII_AN_CTRL_8BIT BIT(8) -#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3 #define DW_VR_MII_TX_CONFIG_MASK BIT(3) #define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1 #define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0 -#define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT 1 #define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1) #define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0 #define DW_VR_MII_PCS_MODE_C37_SGMII 0x2 @@ -90,22 +84,12 @@ /* VR_MII_AN_INTR_STS */ #define DW_VR_MII_AN_STS_C37_ANCMPLT_INTR BIT(0) #define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1) -#define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2 #define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2) #define DW_VR_MII_C37_ANSGM_SP_10 0x0 #define DW_VR_MII_C37_ANSGM_SP_100 0x1 #define DW_VR_MII_C37_ANSGM_SP_1000 0x2 #define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4) -/* SR MII MMD Control defines */ -#define AN_CL37_EN BIT(12) /* Enable Clause 37 auto-nego */ -#define SGMII_SPEED_SS13 BIT(13) /* SGMII speed along with SS6 */ -#define SGMII_SPEED_SS6 BIT(6) /* SGMII speed along with SS13 */ - -/* SR MII MMD AN Advertisement defines */ -#define DW_HALF_DUPLEX BIT(6) -#define DW_FULL_DUPLEX BIT(5) - /* VR MII EEE Control 0 defines */ #define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */ #define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */ @@ -114,7 +98,6 @@ #define DW_VR_MII_EEE_TX_EN_CTRL BIT(4) /* Tx Control Enable */ #define DW_VR_MII_EEE_RX_EN_CTRL BIT(7) /* Rx Control Enable */ -#define DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT 8 #define DW_VR_MII_EEE_MULT_FACT_100NS GENMASK(11, 8) /* VR MII EEE Control 1 defines */ @@ -123,8 +106,27 @@ #define DW_XPCS_INFO_DECLARE(_name, _pcs, _pma) \ static const struct dw_xpcs_info _name = { .pcs = _pcs, .pma = _pma } +struct dw_xpcs_desc; + +enum dw_xpcs_clock { + DW_XPCS_CORE_CLK, + DW_XPCS_PAD_CLK, + DW_XPCS_NUM_CLKS, +}; + +struct dw_xpcs { + struct dw_xpcs_info info; + const struct dw_xpcs_desc *desc; + struct mdio_device *mdiodev; + struct clk_bulk_data clks[DW_XPCS_NUM_CLKS]; + struct phylink_pcs pcs; + phy_interface_t interface; + bool need_reset; +}; + int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg); int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val); +int xpcs_modify(struct dw_xpcs *xpcs, int dev, u32 reg, u16 mask, u16 set); int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg); int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val); int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 01b235b3bb7e80..15828f4710a944 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -266,22 +266,7 @@ config MAXLINEAR_GPHY Support for the Maxlinear GPY115, GPY211, GPY212, GPY215, GPY241, GPY245 PHYs. -config MEDIATEK_GE_PHY - tristate "MediaTek Gigabit Ethernet PHYs" - help - Supports the MediaTek Gigabit Ethernet PHYs. - -config MEDIATEK_GE_SOC_PHY - tristate "MediaTek SoC Ethernet PHYs" - depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST - depends on NVMEM_MTK_EFUSE - help - Supports MediaTek SoC built-in Gigabit Ethernet PHYs. - - Include support for built-in Ethernet PHYs which are present in - the MT7981 and MT7988 SoCs. These PHYs need calibration data - present in the SoCs efuse and will dynamically calibrate VCM - (common-mode voltage) during startup. +source "drivers/net/phy/mediatek/Kconfig" config MICREL_PHY tristate "Micrel PHYs" @@ -292,8 +277,8 @@ config MICREL_PHY config MICROCHIP_T1S_PHY tristate "Microchip 10BASE-T1S Ethernet PHYs" help - Currently supports the LAN8670/1/2 Rev.B1 and LAN8650/1 Rev.B0 Internal - PHYs. + Currently supports the LAN8670/1/2 Rev.B1/C1/C2 and + LAN8650/1 Rev.B0/B1 Internal PHYs. config MICROCHIP_PHY tristate "Microchip PHYs" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 90f886844381d0..e6145153e837fb 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -74,8 +74,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o obj-$(CONFIG_MARVELL_88Q2XXX_PHY) += marvell-88q2xxx.o obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o -obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o -obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o +obj-y += mediatek/ obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c index 2e1a46e121d9d0..a2a862bae2ed1e 100644 --- a/drivers/net/phy/adin.c +++ b/drivers/net/phy/adin.c @@ -801,10 +801,8 @@ static void adin_get_strings(struct phy_device *phydev, u8 *data) { int i; - for (i = 0; i < ARRAY_SIZE(adin_hw_stats); i++) { - strscpy(&data[i * ETH_GSTRING_LEN], - adin_hw_stats[i].string, ETH_GSTRING_LEN); - } + for (i = 0; i < ARRAY_SIZE(adin_hw_stats); i++) + ethtool_puts(&data, adin_hw_stats[i].string); } static int adin_read_mmd_stat_regs(struct phy_device *phydev, diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h index 2465345081f8af..0c78bfabace51f 100644 --- a/drivers/net/phy/aquantia/aquantia.h +++ b/drivers/net/phy/aquantia/aquantia.h @@ -177,6 +177,7 @@ static const struct aqr107_hw_stat aqr107_hw_stats[] = { struct aqr107_priv { u64 sgmii_stats[AQR107_SGMII_STAT_SZ]; unsigned long leds_active_low; + unsigned long leds_active_high; }; #if IS_REACHABLE(CONFIG_HWMON) diff --git a/drivers/net/phy/aquantia/aquantia_leds.c b/drivers/net/phy/aquantia/aquantia_leds.c index 201c8df93fad94..951f46104eff04 100644 --- a/drivers/net/phy/aquantia/aquantia_leds.c +++ b/drivers/net/phy/aquantia/aquantia_leds.c @@ -121,13 +121,13 @@ int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable { return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index), VEND1_GLOBAL_LED_DRIVE_VDD, - enable ? VEND1_GLOBAL_LED_DRIVE_VDD : 0); + enable ? 0 : VEND1_GLOBAL_LED_DRIVE_VDD); } int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes) { + bool force_active_low = false, force_active_high = false; struct aqr107_priv *priv = phydev->priv; - bool active_low = false; u32 mode; if (index >= AQR_MAX_LEDS) @@ -136,7 +136,10 @@ int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { switch (mode) { case PHY_LED_ACTIVE_LOW: - active_low = true; + force_active_low = true; + break; + case PHY_LED_ACTIVE_HIGH: + force_active_high = true; break; default: return -EINVAL; @@ -144,8 +147,14 @@ int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long } /* Save LED driver vdd state to restore on SW reset */ - if (active_low) + if (force_active_low) priv->leds_active_low |= BIT(index); - return aqr_phy_led_active_low_set(phydev, index, active_low); + if (force_active_high) + priv->leds_active_high |= BIT(index); + + if (force_active_high || force_active_low) + return aqr_phy_led_active_low_set(phydev, index, force_active_low); + + return -EINVAL; } diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index c33a5ef34ba032..bb56a66d2a48fa 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "aquantia.h" @@ -41,6 +42,7 @@ #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_XAUI 4 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII 6 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_RXAUI 7 +#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OFF 9 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII 10 #define MDIO_AN_VEND_PROV 0xc400 @@ -52,6 +54,12 @@ #define MDIO_AN_VEND_PROV_DOWNSHIFT_MASK GENMASK(3, 0) #define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4 +#define MDIO_AN_RESVD_VEND_PROV 0xc410 +#define MDIO_AN_RESVD_VEND_PROV_MDIX_AUTO 0 +#define MDIO_AN_RESVD_VEND_PROV_MDIX_MDI 1 +#define MDIO_AN_RESVD_VEND_PROV_MDIX_MDIX 2 +#define MDIO_AN_RESVD_VEND_PROV_MDIX_MASK GENMASK(1, 0) + #define MDIO_AN_TX_VEND_STATUS1 0xc800 #define MDIO_AN_TX_VEND_STATUS1_RATE_MASK GENMASK(3, 1) #define MDIO_AN_TX_VEND_STATUS1_10BASET 0 @@ -62,6 +70,9 @@ #define MDIO_AN_TX_VEND_STATUS1_5000BASET 5 #define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX BIT(0) +#define MDIO_AN_RESVD_VEND_STATUS1 0xc810 +#define MDIO_AN_RESVD_VEND_STATUS1_MDIX BIT(8) + #define MDIO_AN_TX_VEND_INT_STATUS1 0xcc00 #define MDIO_AN_TX_VEND_INT_STATUS1_DOWNSHIFT BIT(1) @@ -71,6 +82,11 @@ #define MDIO_AN_TX_VEND_INT_MASK2 0xd401 #define MDIO_AN_TX_VEND_INT_MASK2_LINK BIT(0) +#define PMAPMD_RSVD_VEND_PROV 0xe400 +#define PMAPMD_RSVD_VEND_PROV_MDI_CONF GENMASK(1, 0) +#define PMAPMD_RSVD_VEND_PROV_MDI_REVERSE BIT(0) +#define PMAPMD_RSVD_VEND_PROV_MDI_FORCE BIT(1) + #define MDIO_AN_RX_LP_STAT1 0xe820 #define MDIO_AN_RX_LP_STAT1_1000BASET_FULL BIT(15) #define MDIO_AN_RX_LP_STAT1_1000BASET_HALF BIT(14) @@ -148,12 +164,40 @@ static void aqr107_get_stats(struct phy_device *phydev, } } +static int aqr_set_mdix(struct phy_device *phydev, int mdix) +{ + u16 val = 0; + + switch (mdix) { + case ETH_TP_MDI: + val = MDIO_AN_RESVD_VEND_PROV_MDIX_MDI; + break; + case ETH_TP_MDI_X: + val = MDIO_AN_RESVD_VEND_PROV_MDIX_MDIX; + break; + case ETH_TP_MDI_AUTO: + case ETH_TP_MDI_INVALID: + default: + val = MDIO_AN_RESVD_VEND_PROV_MDIX_AUTO; + break; + } + + return phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_RESVD_VEND_PROV, + MDIO_AN_RESVD_VEND_PROV_MDIX_MASK, val); +} + static int aqr_config_aneg(struct phy_device *phydev) { bool changed = false; u16 reg; int ret; + ret = aqr_set_mdix(phydev, phydev->mdix_ctrl); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + if (phydev->autoneg == AUTONEG_DISABLE) return genphy_c45_pma_setup_forced(phydev); @@ -271,6 +315,21 @@ static int aqr_read_status(struct phy_device *phydev) val & MDIO_AN_RX_LP_STAT1_1000BASET_HALF); } + val = genphy_c45_aneg_done(phydev); + if (val < 0) + return val; + if (val) { + val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_RESVD_VEND_STATUS1); + if (val < 0) + return val; + if (val & MDIO_AN_RESVD_VEND_STATUS1_MDIX) + phydev->mdix = ETH_TP_MDI_X; + else + phydev->mdix = ETH_TP_MDI; + } else { + phydev->mdix = ETH_TP_MDI_INVALID; + } + return genphy_c45_read_status(phydev); } @@ -342,9 +401,19 @@ static int aqr107_read_status(struct phy_device *phydev) if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE) return 0; - val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS); - if (val < 0) - return val; + /** + * The status register is not immediately correct on line side link up. + * Poll periodically until it reflects the correct ON state. + * Only return fail for read error, timeout defaults to OFF state. + */ + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PHYXS, + MDIO_PHYXS_VEND_IF_STATUS, val, + (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val) != + MDIO_PHYXS_VEND_IF_STATUS_TYPE_OFF), + AQR107_OP_IN_PROG_SLEEP, + AQR107_OP_IN_PROG_TIMEOUT, false); + if (ret && ret != -ETIMEDOUT) + return ret; switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) { case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR: @@ -371,7 +440,9 @@ static int aqr107_read_status(struct phy_device *phydev) case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII: phydev->interface = PHY_INTERFACE_MODE_2500BASEX; break; + case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OFF: default: + phydev->link = false; phydev->interface = PHY_INTERFACE_MODE_NA; break; } @@ -485,10 +556,33 @@ static void aqr107_chip_info(struct phy_device *phydev) fw_major, fw_minor, build_id, prov_id); } +static int aqr107_config_mdi(struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + u32 mdi_conf; + int ret; + + ret = of_property_read_u32(np, "marvell,mdi-cfg-order", &mdi_conf); + + /* Do nothing in case property "marvell,mdi-cfg-order" is not present */ + if (ret == -EINVAL || ret == -ENOSYS) + return 0; + + if (ret) + return ret; + + if (mdi_conf & ~PMAPMD_RSVD_VEND_PROV_MDI_REVERSE) + return -EINVAL; + + return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, PMAPMD_RSVD_VEND_PROV, + PMAPMD_RSVD_VEND_PROV_MDI_CONF, + mdi_conf | PMAPMD_RSVD_VEND_PROV_MDI_FORCE); +} + static int aqr107_config_init(struct phy_device *phydev) { struct aqr107_priv *priv = phydev->priv; - u32 led_active_low; + u32 led_idx; int ret; /* Check that the PHY interface type is compatible */ @@ -514,9 +608,19 @@ static int aqr107_config_init(struct phy_device *phydev) if (ret) return ret; + ret = aqr107_config_mdi(phydev); + if (ret) + return ret; + /* Restore LED polarity state after reset */ - for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) { - ret = aqr_phy_led_active_low_set(phydev, led_active_low, true); + for_each_set_bit(led_idx, &priv->leds_active_low, AQR_MAX_LEDS) { + ret = aqr_phy_led_active_low_set(phydev, led_idx, true); + if (ret) + return ret; + } + + for_each_set_bit(led_idx, &priv->leds_active_high, AQR_MAX_LEDS) { + ret = aqr_phy_led_active_low_set(phydev, led_idx, false); if (ret) return ret; } diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index 6c52f7dda514b3..5198d66dbbc048 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -523,8 +523,7 @@ void bcm_phy_get_strings(struct phy_device *phydev, u8 *data) unsigned int i; for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++) - strscpy(data + i * ETH_GSTRING_LEN, - bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN); + ethtool_puts(&data, bcm_phy_hw_stats[i].string); } EXPORT_SYMBOL_GPL(bcm_phy_get_strings); @@ -1137,7 +1136,7 @@ int bcm_config_lre_aneg(struct phy_device *phydev, bool changed) { int err; - if (genphy_config_eee_advert(phydev)) + if (genphy_c45_an_config_eee_aneg(phydev) > 0) changed = true; err = bcm_setup_lre_master_slave(phydev); diff --git a/drivers/net/phy/dp83822.c b/drivers/net/phy/dp83822.c index 3ab64e04a01c9c..cf8b6d0bfaa981 100644 --- a/drivers/net/phy/dp83822.c +++ b/drivers/net/phy/dp83822.c @@ -506,7 +506,7 @@ static int dp83822_config_init(struct phy_device *phydev) return dp83822_config_wol(phydev, &dp83822->wol); } -static int dp83826_config_rmii_mode(struct phy_device *phydev) +static int dp8382x_config_rmii_mode(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; const char *of_val; @@ -544,7 +544,7 @@ static int dp83826_config_init(struct phy_device *phydev) if (ret) return ret; - ret = dp83826_config_rmii_mode(phydev); + ret = dp8382x_config_rmii_mode(phydev); if (ret) return ret; } else { @@ -585,9 +585,14 @@ static int dp83826_config_init(struct phy_device *phydev) return dp83822_config_wol(phydev, &dp83822->wol); } -static int dp8382x_config_init(struct phy_device *phydev) +static int dp83825_config_init(struct phy_device *phydev) { struct dp83822_private *dp83822 = phydev->priv; + int ret; + + ret = dp8382x_config_rmii_mode(phydev); + if (ret) + return ret; return dp83822_config_wol(phydev, &dp83822->wol); } @@ -782,14 +787,14 @@ static int dp83822_resume(struct phy_device *phydev) .resume = dp83822_resume, \ } -#define DP83826_PHY_DRIVER(_id, _name) \ +#define DP83825_PHY_DRIVER(_id, _name) \ { \ PHY_ID_MATCH_MODEL(_id), \ .name = (_name), \ /* PHY_BASIC_FEATURES */ \ - .probe = dp83826_probe, \ + .probe = dp8382x_probe, \ .soft_reset = dp83822_phy_reset, \ - .config_init = dp83826_config_init, \ + .config_init = dp83825_config_init, \ .get_wol = dp83822_get_wol, \ .set_wol = dp83822_set_wol, \ .config_intr = dp83822_config_intr, \ @@ -798,14 +803,14 @@ static int dp83822_resume(struct phy_device *phydev) .resume = dp83822_resume, \ } -#define DP8382X_PHY_DRIVER(_id, _name) \ +#define DP83826_PHY_DRIVER(_id, _name) \ { \ PHY_ID_MATCH_MODEL(_id), \ .name = (_name), \ /* PHY_BASIC_FEATURES */ \ - .probe = dp8382x_probe, \ + .probe = dp83826_probe, \ .soft_reset = dp83822_phy_reset, \ - .config_init = dp8382x_config_init, \ + .config_init = dp83826_config_init, \ .get_wol = dp83822_get_wol, \ .set_wol = dp83822_set_wol, \ .config_intr = dp83822_config_intr, \ @@ -816,12 +821,12 @@ static int dp83822_resume(struct phy_device *phydev) static struct phy_driver dp83822_driver[] = { DP83822_PHY_DRIVER(DP83822_PHY_ID, "TI DP83822"), - DP8382X_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"), + DP83825_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"), + DP83825_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"), + DP83825_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"), + DP83825_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"), DP83826_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"), DP83826_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"), - DP8382X_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"), - DP8382X_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"), - DP8382X_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"), }; module_phy_driver(dp83822_driver); diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 5f056d7db83eed..b6b38caf9c0ed0 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -153,19 +153,32 @@ struct dp83869_private { int mode; }; +static int dp83869_config_aneg(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = phydev->priv; + + if (dp83869->mode != DP83869_RGMII_1000_BASE) + return genphy_config_aneg(phydev); + + return genphy_c37_config_aneg(phydev); +} + static int dp83869_read_status(struct phy_device *phydev) { struct dp83869_private *dp83869 = phydev->priv; + bool changed; int ret; + if (dp83869->mode == DP83869_RGMII_1000_BASE) + return genphy_c37_read_status(phydev, &changed); + ret = genphy_read_status(phydev); if (ret) return ret; - if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { + if (dp83869->mode == DP83869_RGMII_100_BASE) { if (phydev->link) { - if (dp83869->mode == DP83869_RGMII_100_BASE) - phydev->speed = SPEED_100; + phydev->speed = SPEED_100; } else { phydev->speed = SPEED_UNKNOWN; phydev->duplex = DUPLEX_UNKNOWN; @@ -898,6 +911,7 @@ static int dp83869_phy_reset(struct phy_device *phydev) .soft_reset = dp83869_phy_reset, \ .config_intr = dp83869_config_intr, \ .handle_interrupt = dp83869_handle_interrupt, \ + .config_aneg = dp83869_config_aneg, \ .read_status = dp83869_read_status, \ .get_tunable = dp83869_get_tunable, \ .set_tunable = dp83869_set_tunable, \ diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index a00a667454a9b2..ee438b71a0b455 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -540,8 +540,7 @@ static void ip101g_get_strings(struct phy_device *phydev, u8 *data) int i; for (i = 0; i < ARRAY_SIZE(ip101g_hw_stats); i++) - strscpy(data + i * ETH_GSTRING_LEN, - ip101g_hw_stats[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, ip101g_hw_stats[i].name); } static u64 ip101g_get_stat(struct phy_device *phydev, int i) diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c index 3c032868ef0498..e6ed2413e514c7 100644 --- a/drivers/net/phy/intel-xway.c +++ b/drivers/net/phy/intel-xway.c @@ -151,6 +151,13 @@ #define XWAY_MMD_LED3H 0x01E8 #define XWAY_MMD_LED3L 0x01E9 +#define XWAY_GPHY_MAX_LEDS 3 +#define XWAY_GPHY_LED_INV(idx) BIT(12 + (idx)) +#define XWAY_GPHY_LED_EN(idx) BIT(8 + (idx)) +#define XWAY_GPHY_LED_DA(idx) BIT(idx) +#define XWAY_MMD_LEDxH(idx) (XWAY_MMD_LED0H + 2 * (idx)) +#define XWAY_MMD_LEDxL(idx) (XWAY_MMD_LED0L + 2 * (idx)) + #define PHY_ID_PHY11G_1_3 0x030260D1 #define PHY_ID_PHY22F_1_3 0x030260E1 #define PHY_ID_PHY11G_1_4 0xD565A400 @@ -229,20 +236,12 @@ static int xway_gphy_rgmii_init(struct phy_device *phydev) XWAY_MDIO_MIICTRL_TXSKEW_MASK, val); } -static int xway_gphy_config_init(struct phy_device *phydev) +static int xway_gphy_init_leds(struct phy_device *phydev) { int err; u32 ledxh; u32 ledxl; - /* Mask all interrupts */ - err = phy_write(phydev, XWAY_MDIO_IMASK, 0); - if (err) - return err; - - /* Clear all pending interrupts */ - phy_read(phydev, XWAY_MDIO_ISTAT); - /* Ensure that integrated led function is enabled for all leds */ err = phy_write(phydev, XWAY_MDIO_LED, XWAY_MDIO_LED_LED0_EN | @@ -276,6 +275,26 @@ static int xway_gphy_config_init(struct phy_device *phydev) phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2H, ledxh); phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LED2L, ledxl); + return 0; +} + +static int xway_gphy_config_init(struct phy_device *phydev) +{ + struct device_node *np = phydev->mdio.dev.of_node; + int err; + + /* Mask all interrupts */ + err = phy_write(phydev, XWAY_MDIO_IMASK, 0); + if (err) + return err; + + /* Use default LED configuration if 'leds' node isn't defined */ + if (!of_get_child_by_name(np, "leds")) + xway_gphy_init_leds(phydev); + + /* Clear all pending interrupts */ + phy_read(phydev, XWAY_MDIO_ISTAT); + err = xway_gphy_rgmii_init(phydev); if (err) return err; @@ -347,6 +366,172 @@ static irqreturn_t xway_gphy_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } +static int xway_gphy_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + int ret; + + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + /* clear EN and set manual LED state */ + ret = phy_modify(phydev, XWAY_MDIO_LED, + ((value == LED_OFF) ? XWAY_GPHY_LED_EN(index) : 0) | + XWAY_GPHY_LED_DA(index), + (value == LED_OFF) ? 0 : XWAY_GPHY_LED_DA(index)); + if (ret) + return ret; + + /* clear HW LED setup */ + if (value == LED_OFF) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), 0); + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), 0); + } else { + return 0; + } +} + +static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX)); + +static int xway_gphy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + /* activity triggers are not possible without combination with a link + * trigger. + */ + if (rules & (BIT(TRIGGER_NETDEV_RX) | BIT(TRIGGER_NETDEV_TX)) && + !(rules & (BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000)))) + return -EOPNOTSUPP; + + /* All other combinations of the supported triggers are allowed */ + if (rules & ~supported_triggers) + return -EOPNOTSUPP; + + return 0; +} + +static int xway_gphy_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int lval, hval; + + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + hval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index)); + if (hval < 0) + return hval; + + lval = phy_read_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index)); + if (lval < 0) + return lval; + + if (hval & XWAY_MMD_LEDxH_CON_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); + + if (hval & XWAY_MMD_LEDxH_CON_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); + + if (hval & XWAY_MMD_LEDxH_CON_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); + + if ((hval & XWAY_MMD_LEDxH_CON_LINK10) && + (hval & XWAY_MMD_LEDxH_CON_LINK100) && + (hval & XWAY_MMD_LEDxH_CON_LINK1000)) + *rules |= BIT(TRIGGER_NETDEV_LINK); + + if (lval & XWAY_MMD_LEDxL_PULSE_TXACT) + *rules |= BIT(TRIGGER_NETDEV_TX); + + if (lval & XWAY_MMD_LEDxL_PULSE_RXACT) + *rules |= BIT(TRIGGER_NETDEV_RX); + + return 0; +} + +static int xway_gphy_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 hval = 0, lval = 0; + int ret; + + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_10)) + hval |= XWAY_MMD_LEDxH_CON_LINK10; + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_100)) + hval |= XWAY_MMD_LEDxH_CON_LINK100; + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_1000)) + hval |= XWAY_MMD_LEDxH_CON_LINK1000; + + if (rules & BIT(TRIGGER_NETDEV_TX)) + lval |= XWAY_MMD_LEDxL_PULSE_TXACT; + + if (rules & BIT(TRIGGER_NETDEV_RX)) + lval |= XWAY_MMD_LEDxL_PULSE_RXACT; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxH(index), hval); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, XWAY_MMD_LEDxL(index), lval); + if (ret) + return ret; + + return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_EN(index)); +} + +static int xway_gphy_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + bool force_active_low = false, force_active_high = false; + u32 mode; + + if (index >= XWAY_GPHY_MAX_LEDS) + return -EINVAL; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + force_active_low = true; + break; + case PHY_LED_ACTIVE_HIGH: + force_active_high = true; + break; + default: + return -EINVAL; + } + } + + if (force_active_low) + return phy_set_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); + + if (force_active_high) + return phy_clear_bits(phydev, XWAY_MDIO_LED, XWAY_GPHY_LED_INV(index)); + + return -EINVAL; +} + static struct phy_driver xway_gphy[] = { { .phy_id = PHY_ID_PHY11G_1_3, @@ -359,6 +544,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_1_3, .phy_id_mask = 0xffffffff, @@ -370,6 +560,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY11G_1_4, .phy_id_mask = 0xffffffff, @@ -381,6 +576,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_1_4, .phy_id_mask = 0xffffffff, @@ -392,6 +592,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY11G_1_5, .phy_id_mask = 0xffffffff, @@ -402,6 +607,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_1_5, .phy_id_mask = 0xffffffff, @@ -412,6 +622,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY11G_VR9_1_1, .phy_id_mask = 0xffffffff, @@ -422,6 +637,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_VR9_1_1, .phy_id_mask = 0xffffffff, @@ -432,6 +652,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY11G_VR9_1_2, .phy_id_mask = 0xffffffff, @@ -442,6 +667,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, { .phy_id = PHY_ID_PHY22F_VR9_1_2, .phy_id_mask = 0xffffffff, @@ -452,6 +682,11 @@ static struct phy_driver xway_gphy[] = { .config_intr = xway_gphy_config_intr, .suspend = genphy_suspend, .resume = genphy_resume, + .led_brightness_set = xway_gphy_led_brightness_set, + .led_hw_is_supported = xway_gphy_led_hw_is_supported, + .led_hw_control_get = xway_gphy_led_hw_control_get, + .led_hw_control_set = xway_gphy_led_hw_control_set, + .led_polarity_set = xway_gphy_led_polarity_set, }, }; module_phy_driver(xway_gphy); diff --git a/drivers/net/phy/marvell-88q2xxx.c b/drivers/net/phy/marvell-88q2xxx.c index c812f16eaa3a88..5107f58338aff4 100644 --- a/drivers/net/phy/marvell-88q2xxx.c +++ b/drivers/net/phy/marvell-88q2xxx.c @@ -101,6 +101,22 @@ struct mmd_val { u16 val; }; +static const struct mmd_val mv88q2110_init_seq0[] = { + { MDIO_MMD_PCS, 0xffe4, 0x07b5 }, + { MDIO_MMD_PCS, 0xffe4, 0x06b6 }, +}; + +static const struct mmd_val mv88q2110_init_seq1[] = { + { MDIO_MMD_PCS, 0xffde, 0x402f }, + { MDIO_MMD_PCS, 0xfe34, 0x4040 }, + { MDIO_MMD_PCS, 0xfe2a, 0x3c1d }, + { MDIO_MMD_PCS, 0xfe34, 0x0040 }, + { MDIO_MMD_AN, 0x8032, 0x0064 }, + { MDIO_MMD_AN, 0x8031, 0x0a01 }, + { MDIO_MMD_AN, 0x8031, 0x0c01 }, + { MDIO_MMD_PCS, 0xffdb, 0x0010 }, +}; + static const struct mmd_val mv88q222x_revb0_init_seq0[] = { { MDIO_MMD_PCS, 0x8033, 0x6801 }, { MDIO_MMD_AN, MDIO_AN_T1_CTRL, 0x0 }, @@ -174,20 +190,54 @@ static const struct mmd_val mv88q222x_revb1_revb2_init_seq1[] = { { MDIO_MMD_PCS, 0xfe11, 0x1105 }, }; +static int mv88q2xxx_write_mmd_vals(struct phy_device *phydev, + const struct mmd_val *vals, size_t len) +{ + int ret; + + for (; len; vals++, len--) { + ret = phy_write_mmd(phydev, vals->devad, vals->regnum, + vals->val); + if (ret < 0) + return ret; + } + + return 0; +} + static int mv88q2xxx_soft_reset(struct phy_device *phydev) { int ret; int val; - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, - MDIO_PCS_1000BT1_CTRL, MDIO_PCS_1000BT1_CTRL_RESET); + /* Enable RESET of DCL */ + if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) { + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x48); + if (ret < 0) + return ret; + } + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_CTRL, + MDIO_PCS_1000BT1_CTRL_RESET); if (ret < 0) return ret; - return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS, - MDIO_PCS_1000BT1_CTRL, val, - !(val & MDIO_PCS_1000BT1_CTRL_RESET), - 50000, 600000, true); + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PCS, + MDIO_PCS_1000BT1_CTRL, val, + !(val & MDIO_PCS_1000BT1_CTRL_RESET), + 50000, 600000, true); + if (ret < 0) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xffe4, 0xc); + if (ret < 0) + return ret; + + /* Disable RESET of DCL */ + if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) + return phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x58); + + return 0; } static int mv88q2xxx_read_link_gbit(struct phy_device *phydev) @@ -390,15 +440,6 @@ static int mv88q2xxx_get_features(struct phy_device *phydev) if (ret) return ret; - /* The PHY signalizes it supports autonegotiation. Unfortunately, so - * far it was not possible to get a link even when following the init - * sequence provided by Marvell. Disable it for now until a proper - * workaround is found or a new PHY revision is released. - */ - if (phydev->drv->phy_id == MARVELL_PHY_ID_88Q2110) - linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - phydev->supported); - return 0; } @@ -705,60 +746,37 @@ static int mv88q2xxx_probe(struct phy_device *phydev) return mv88q2xxx_hwmon_probe(phydev); } -static int mv88q222x_soft_reset(struct phy_device *phydev) +static int mv88q2110_config_init(struct phy_device *phydev) { int ret; - /* Enable RESET of DCL */ - if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) { - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x48); - if (ret < 0) - return ret; - } - - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_1000BT1_CTRL, - MDIO_PCS_1000BT1_CTRL_RESET); + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q2110_init_seq0, + ARRAY_SIZE(mv88q2110_init_seq0)); if (ret < 0) return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, 0xffe4, 0xc); + usleep_range(5000, 10000); + + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q2110_init_seq1, + ARRAY_SIZE(mv88q2110_init_seq1)); if (ret < 0) return ret; - /* Disable RESET of DCL */ - if (phydev->autoneg == AUTONEG_ENABLE || phydev->speed == SPEED_1000) - return phy_write_mmd(phydev, MDIO_MMD_PCS, 0xfe1b, 0x58); - - return 0; -} - -static int mv88q222x_write_mmd_vals(struct phy_device *phydev, - const struct mmd_val *vals, size_t len) -{ - int ret; - - for (; len; vals++, len--) { - ret = phy_write_mmd(phydev, vals->devad, vals->regnum, - vals->val); - if (ret < 0) - return ret; - } - - return 0; + return mv88q2xxx_config_init(phydev); } static int mv88q222x_revb0_config_init(struct phy_device *phydev) { int ret; - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb0_init_seq0, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb0_init_seq0, ARRAY_SIZE(mv88q222x_revb0_init_seq0)); if (ret < 0) return ret; usleep_range(5000, 10000); - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb0_init_seq1, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb0_init_seq1, ARRAY_SIZE(mv88q222x_revb0_init_seq1)); if (ret < 0) return ret; @@ -772,17 +790,17 @@ static int mv88q222x_revb1_revb2_config_init(struct phy_device *phydev) int ret; if (is_rev_b1) - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb1_init_seq0, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb1_init_seq0, ARRAY_SIZE(mv88q222x_revb1_init_seq0)); else - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb2_init_seq0, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb2_init_seq0, ARRAY_SIZE(mv88q222x_revb2_init_seq0)); if (ret < 0) return ret; usleep_range(3000, 5000); - ret = mv88q222x_write_mmd_vals(phydev, mv88q222x_revb1_revb2_init_seq1, + ret = mv88q2xxx_write_mmd_vals(phydev, mv88q222x_revb1_revb2_init_seq1, ARRAY_SIZE(mv88q222x_revb1_revb2_init_seq1)); if (ret < 0) return ret; @@ -888,7 +906,7 @@ static struct phy_driver mv88q2xxx_driver[] = { .name = "mv88q2110", .get_features = mv88q2xxx_get_features, .config_aneg = mv88q2xxx_config_aneg, - .config_init = mv88q2xxx_config_init, + .config_init = mv88q2110_config_init, .read_status = mv88q2xxx_read_status, .soft_reset = mv88q2xxx_soft_reset, .set_loopback = genphy_c45_loopback, @@ -906,7 +924,7 @@ static struct phy_driver mv88q2xxx_driver[] = { .aneg_done = genphy_c45_aneg_done, .config_init = mv88q222x_config_init, .read_status = mv88q2xxx_read_status, - .soft_reset = mv88q222x_soft_reset, + .soft_reset = mv88q2xxx_soft_reset, .config_intr = mv88q2xxx_config_intr, .handle_interrupt = mv88q2xxx_handle_interrupt, .set_loopback = genphy_c45_loopback, diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 9964bf3dea2fb2..cd50cd6a7f75c1 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -176,6 +176,7 @@ #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 #define MII_M1011_PHY_STATUS_LINK 0x0400 +#define MII_M1011_PHY_STATUS_MDIX BIT(6) #define MII_88E3016_PHY_SPEC_CTRL 0x10 #define MII_88E3016_DISABLE_SCRAMBLER 0x0200 @@ -1722,6 +1723,19 @@ static int marvell_read_status_page(struct phy_device *phydev, int page) phydev->duplex = DUPLEX_UNKNOWN; phydev->port = fiber ? PORT_FIBRE : PORT_TP; + if (fiber) { + phydev->mdix = ETH_TP_MDI_INVALID; + } else { + /* The MDI-X state is set regardless of Autoneg being enabled + * and reflects forced MDI-X state as well as auto resolution + */ + if (status & MII_M1011_PHY_STATUS_RESOLVED) + phydev->mdix = status & MII_M1011_PHY_STATUS_MDIX ? + ETH_TP_MDI_X : ETH_TP_MDI; + else + phydev->mdix = ETH_TP_MDI_INVALID; + } + if (phydev->autoneg == AUTONEG_ENABLE) err = marvell_read_status_page_an(phydev, fiber, status); else @@ -2006,10 +2020,8 @@ static void marvell_get_strings(struct phy_device *phydev, u8 *data) int count = marvell_get_sset_count(phydev); int i; - for (i = 0; i < count; i++) { - strscpy(data + i * ETH_GSTRING_LEN, - marvell_hw_stats[i].string, ETH_GSTRING_LEN); - } + for (i = 0; i < count; i++) + ethtool_puts(&data, marvell_hw_stats[i].string); } static void marvell_get_strings_simple(struct phy_device *phydev, u8 *data) @@ -2017,10 +2029,8 @@ static void marvell_get_strings_simple(struct phy_device *phydev, u8 *data) int count = marvell_get_sset_count_simple(phydev); int i; - for (i = 0; i < count; i++) { - strscpy(data + i * ETH_GSTRING_LEN, - marvell_hw_stats_simple[i].string, ETH_GSTRING_LEN); - } + for (i = 0; i < count; i++) + ethtool_puts(&data, marvell_hw_stats_simple[i].string); } static u64 marvell_get_stat(struct phy_device *phydev, int i) diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c deleted file mode 100644 index f4f9412d0cd7e2..00000000000000 --- a/drivers/net/phy/mediatek-ge-soc.c +++ /dev/null @@ -1,1555 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -#include -#include -#include -#include -#include -#include -#include -#include - -#define MTK_GPHY_ID_MT7981 0x03a29461 -#define MTK_GPHY_ID_MT7988 0x03a29481 - -#define MTK_EXT_PAGE_ACCESS 0x1f -#define MTK_PHY_PAGE_STANDARD 0x0000 -#define MTK_PHY_PAGE_EXTENDED_3 0x0003 - -#define MTK_PHY_LPI_REG_14 0x14 -#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0) - -#define MTK_PHY_LPI_REG_1c 0x1c -#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8) - -#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 -#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 - -#define ANALOG_INTERNAL_OPERATION_MAX_US 20 -#define TXRESERVE_MIN 0 -#define TXRESERVE_MAX 7 - -#define MTK_PHY_ANARG_RG 0x10 -#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8) - -/* Registers on MDIO_MMD_VEND1 */ -#define MTK_PHY_TXVLD_DA_RG 0x12 -#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10) -#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0) - -#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16 -#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10) -#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0) - -#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17 -#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0) - -#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18 -#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0) - -#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19 -#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0) - -#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20 -#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0) - -#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21 -#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0) - -#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22 -#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0) - -#define MTK_PHY_RXADC_CTRL_RG7 0xc6 -#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) - -#define MTK_PHY_RXADC_CTRL_RG9 0xc8 -#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12) -#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8) -#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4) -#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0) - -#define MTK_PHY_LDO_OUTPUT_V 0xd7 - -#define MTK_PHY_RG_ANA_CAL_RG0 0xdb -#define MTK_PHY_RG_CAL_CKINV BIT(12) -#define MTK_PHY_RG_ANA_CALEN BIT(8) -#define MTK_PHY_RG_ZCALEN_A BIT(0) - -#define MTK_PHY_RG_ANA_CAL_RG1 0xdc -#define MTK_PHY_RG_ZCALEN_B BIT(12) -#define MTK_PHY_RG_ZCALEN_C BIT(8) -#define MTK_PHY_RG_ZCALEN_D BIT(4) -#define MTK_PHY_RG_TXVOS_CALEN BIT(0) - -#define MTK_PHY_RG_ANA_CAL_RG5 0xe0 -#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8) - -#define MTK_PHY_RG_TX_FILTER 0xfe - -#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120 -#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8) -#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0) - -#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122 -#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0) - -#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144 -#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5) - -#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172 -#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8) -#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0) - -#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173 -#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8) -#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) - -#define MTK_PHY_RG_AD_CAL_COMP 0x17a -#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) - -#define MTK_PHY_RG_AD_CAL_CLK 0x17b -#define MTK_PHY_DA_CAL_CLK BIT(0) - -#define MTK_PHY_RG_AD_CALIN 0x17c -#define MTK_PHY_DA_CALIN_FLAG BIT(0) - -#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d -#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0) - -#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e -#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0) - -#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f -#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0) - -#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180 -#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0) - -#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181 -#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0) - -#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182 -#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0) - -#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183 -#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0) - -#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184 -#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0) - -#define MTK_PHY_RG_DEV1E_REG19b 0x19b -#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8) - -#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a -#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b -#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c -#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d -#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e -#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f -#define MTK_PHY_RG_LP_IIR2_K4_L 0x230 -#define MTK_PHY_RG_LP_IIR2_K4_U 0x231 -#define MTK_PHY_RG_LP_IIR2_K5_L 0x232 -#define MTK_PHY_RG_LP_IIR2_K5_U 0x233 - -#define MTK_PHY_RG_DEV1E_REG234 0x234 -#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0) -#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4) -#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12) - -#define MTK_PHY_RG_LPF_CNT_VAL 0x235 - -#define MTK_PHY_RG_DEV1E_REG238 0x238 -#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0) -#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12) - -#define MTK_PHY_RG_DEV1E_REG239 0x239 -#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0) -#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12) - -#define MTK_PHY_RG_DEV1E_REG27C 0x27c -#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8) -#define MTK_PHY_RG_DEV1E_REG27D 0x27d -#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0) - -#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7 -#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0) -#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8) - -#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1 -#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0) -#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8) -#define MTK_PHY_LPI_TR_READY BIT(9) -#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10) - -#define MTK_PHY_RG_DEV1E_REG323 0x323 -#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0) -#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4) - -#define MTK_PHY_RG_DEV1E_REG324 0x324 -#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0) -#define MTK_PHY_SMI_DET_MAX_EN BIT(8) - -#define MTK_PHY_RG_DEV1E_REG326 0x326 -#define MTK_PHY_LPI_MODE_SD_ON BIT(0) -#define MTK_PHY_RESET_RANDUPD_CNT BIT(1) -#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2) -#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4) -#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5) - -#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502 -#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503 - -#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d -#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e -#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f -#define MTK_PHY_DA_TX_R50_PAIR_D 0x540 - -/* Registers on MDIO_MMD_VEND2 */ -#define MTK_PHY_LED0_ON_CTRL 0x24 -#define MTK_PHY_LED1_ON_CTRL 0x26 -#define MTK_PHY_LED_ON_MASK GENMASK(6, 0) -#define MTK_PHY_LED_ON_LINK1000 BIT(0) -#define MTK_PHY_LED_ON_LINK100 BIT(1) -#define MTK_PHY_LED_ON_LINK10 BIT(2) -#define MTK_PHY_LED_ON_LINK (MTK_PHY_LED_ON_LINK10 |\ - MTK_PHY_LED_ON_LINK100 |\ - MTK_PHY_LED_ON_LINK1000) -#define MTK_PHY_LED_ON_LINKDOWN BIT(3) -#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */ -#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */ -#define MTK_PHY_LED_ON_FORCE_ON BIT(6) -#define MTK_PHY_LED_ON_POLARITY BIT(14) -#define MTK_PHY_LED_ON_ENABLE BIT(15) - -#define MTK_PHY_LED0_BLINK_CTRL 0x25 -#define MTK_PHY_LED1_BLINK_CTRL 0x27 -#define MTK_PHY_LED_BLINK_1000TX BIT(0) -#define MTK_PHY_LED_BLINK_1000RX BIT(1) -#define MTK_PHY_LED_BLINK_100TX BIT(2) -#define MTK_PHY_LED_BLINK_100RX BIT(3) -#define MTK_PHY_LED_BLINK_10TX BIT(4) -#define MTK_PHY_LED_BLINK_10RX BIT(5) -#define MTK_PHY_LED_BLINK_RX (MTK_PHY_LED_BLINK_10RX |\ - MTK_PHY_LED_BLINK_100RX |\ - MTK_PHY_LED_BLINK_1000RX) -#define MTK_PHY_LED_BLINK_TX (MTK_PHY_LED_BLINK_10TX |\ - MTK_PHY_LED_BLINK_100TX |\ - MTK_PHY_LED_BLINK_1000TX) -#define MTK_PHY_LED_BLINK_COLLISION BIT(6) -#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7) -#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) -#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9) - -#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1) - -#define MTK_PHY_RG_BG_RASEL 0x115 -#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0) - -/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */ -#define RG_GPIO_MISC_TPBANK0 0x6f0 -#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8) - -/* These macro privides efuse parsing for internal phy. */ -#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0)) -#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0)) -#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0)) -#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0)) -#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0)) - -#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0)) -#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0)) -#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0)) - -#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0)) - -#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0)) -#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0)) - -enum { - NO_PAIR, - PAIR_A, - PAIR_B, - PAIR_C, - PAIR_D, -}; - -enum calibration_mode { - EFUSE_K, - SW_K -}; - -enum CAL_ITEM { - REXT, - TX_OFFSET, - TX_AMP, - TX_R50, - TX_VCM -}; - -enum CAL_MODE { - EFUSE_M, - SW_M -}; - -#define MTK_PHY_LED_STATE_FORCE_ON 0 -#define MTK_PHY_LED_STATE_FORCE_BLINK 1 -#define MTK_PHY_LED_STATE_NETDEV 2 - -struct mtk_socphy_priv { - unsigned long led_state; -}; - -struct mtk_socphy_shared { - u32 boottrap; - struct mtk_socphy_priv priv[4]; -}; - -static int mtk_socphy_read_page(struct phy_device *phydev) -{ - return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); -} - -static int mtk_socphy_write_page(struct phy_device *phydev, int page) -{ - return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); -} - -/* One calibration cycle consists of: - * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high - * until AD_CAL_COMP is ready to output calibration result. - * 2.Wait until DA_CAL_CLK is available. - * 3.Fetch AD_CAL_COMP_OUT. - */ -static int cal_cycle(struct phy_device *phydev, int devad, - u32 regnum, u16 mask, u16 cal_val) -{ - int reg_val; - int ret; - - phy_modify_mmd(phydev, devad, regnum, - mask, cal_val); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, - MTK_PHY_DA_CALIN_FLAG); - - ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_AD_CAL_CLK, reg_val, - reg_val & MTK_PHY_DA_CAL_CLK, 500, - ANALOG_INTERNAL_OPERATION_MAX_US, false); - if (ret) { - phydev_err(phydev, "Calibration cycle timeout\n"); - return ret; - } - - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, - MTK_PHY_DA_CALIN_FLAG); - ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >> - MTK_PHY_AD_CAL_COMP_OUT_SHIFT; - phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); - - return ret; -} - -static int rext_fill_result(struct phy_device *phydev, u16 *buf) -{ - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL, - MTK_PHY_RG_BG_RASEL_MASK, buf[1]); - - return 0; -} - -static int rext_cal_efuse(struct phy_device *phydev, u32 *buf) -{ - u16 rext_cal_val[2]; - - rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]); - rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]); - rext_fill_result(phydev, rext_cal_val); - - return 0; -} - -static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf) -{ - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, - MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, - MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, - MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, - MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]); - - return 0; -} - -static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) -{ - u16 tx_offset_cal_val[4]; - - tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]); - tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]); - tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]); - tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]); - - tx_offset_fill_result(phydev, tx_offset_cal_val); - - return 0; -} - -static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) -{ - int i; - int bias[16] = {}; - const int vals_9461[16] = { 7, 1, 4, 7, - 7, 1, 4, 7, - 7, 1, 4, 7, - 7, 1, 4, 7 }; - const int vals_9481[16] = { 10, 6, 6, 10, - 10, 6, 6, 10, - 10, 6, 6, 10, - 10, 6, 6, 10 }; - switch (phydev->drv->phy_id) { - case MTK_GPHY_ID_MT7981: - /* We add some calibration to efuse values - * due to board level influence. - * GBE: +7, TBT: +1, HBT: +4, TST: +7 - */ - memcpy(bias, (const void *)vals_9461, sizeof(bias)); - break; - case MTK_GPHY_ID_MT7988: - memcpy(bias, (const void *)vals_9481, sizeof(bias)); - break; - } - - /* Prevent overflow */ - for (i = 0; i < 12; i++) { - if (buf[i >> 2] + bias[i] > 63) { - buf[i >> 2] = 63; - bias[i] = 0; - } - } - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, - MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, - MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, - MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, - MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]); - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, - MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, - MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, - MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, - MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]); - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, - MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, - MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, - MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, - MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]); - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, - MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, - MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, - MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, - MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]); - - return 0; -} - -static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf) -{ - u16 tx_amp_cal_val[4]; - - tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]); - tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]); - tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]); - tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]); - tx_amp_fill_result(phydev, tx_amp_cal_val); - - return 0; -} - -static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val, - u8 txg_calen_x) -{ - int bias = 0; - u16 reg, val; - - if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988) - bias = -1; - - val = clamp_val(bias + tx_r50_cal_val, 0, 63); - - switch (txg_calen_x) { - case PAIR_A: - reg = MTK_PHY_DA_TX_R50_PAIR_A; - break; - case PAIR_B: - reg = MTK_PHY_DA_TX_R50_PAIR_B; - break; - case PAIR_C: - reg = MTK_PHY_DA_TX_R50_PAIR_C; - break; - case PAIR_D: - reg = MTK_PHY_DA_TX_R50_PAIR_D; - break; - default: - return -EINVAL; - } - - phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8); - - return 0; -} - -static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf, - u8 txg_calen_x) -{ - u16 tx_r50_cal_val; - - switch (txg_calen_x) { - case PAIR_A: - tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]); - break; - case PAIR_B: - tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]); - break; - case PAIR_C: - tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]); - break; - case PAIR_D: - tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]); - break; - default: - return -EINVAL; - } - tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); - - return 0; -} - -static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) -{ - u8 lower_idx, upper_idx, txreserve_val; - u8 lower_ret, upper_ret; - int ret; - - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_ANA_CALEN); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_CAL_CKINV); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_TXVOS_CALEN); - - switch (rg_txreserve_x) { - case PAIR_A: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DASN_DAC_IN0_A, - MTK_PHY_DASN_DAC_IN0_A_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DASN_DAC_IN1_A, - MTK_PHY_DASN_DAC_IN1_A_MASK); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_ZCALEN_A); - break; - case PAIR_B: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DASN_DAC_IN0_B, - MTK_PHY_DASN_DAC_IN0_B_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DASN_DAC_IN1_B, - MTK_PHY_DASN_DAC_IN1_B_MASK); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_ZCALEN_B); - break; - case PAIR_C: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DASN_DAC_IN0_C, - MTK_PHY_DASN_DAC_IN0_C_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DASN_DAC_IN1_C, - MTK_PHY_DASN_DAC_IN1_C_MASK); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_ZCALEN_C); - break; - case PAIR_D: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DASN_DAC_IN0_D, - MTK_PHY_DASN_DAC_IN0_D_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DASN_DAC_IN1_D, - MTK_PHY_DASN_DAC_IN1_D_MASK); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_ZCALEN_D); - break; - default: - ret = -EINVAL; - goto restore; - } - - lower_idx = TXRESERVE_MIN; - upper_idx = TXRESERVE_MAX; - - phydev_dbg(phydev, "Start TX-VCM SW cal.\n"); - while ((upper_idx - lower_idx) > 1) { - txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2); - ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | - MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | - MTK_PHY_DA_RX_PSBN_LP_MASK, - txreserve_val << 12 | txreserve_val << 8 | - txreserve_val << 4 | txreserve_val); - if (ret == 1) { - upper_idx = txreserve_val; - upper_ret = ret; - } else if (ret == 0) { - lower_idx = txreserve_val; - lower_ret = ret; - } else { - goto restore; - } - } - - if (lower_idx == TXRESERVE_MIN) { - lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, - MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | - MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | - MTK_PHY_DA_RX_PSBN_LP_MASK, - lower_idx << 12 | lower_idx << 8 | - lower_idx << 4 | lower_idx); - ret = lower_ret; - } else if (upper_idx == TXRESERVE_MAX) { - upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, - MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | - MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | - MTK_PHY_DA_RX_PSBN_LP_MASK, - upper_idx << 12 | upper_idx << 8 | - upper_idx << 4 | upper_idx); - ret = upper_ret; - } - if (ret < 0) - goto restore; - - /* We calibrate TX-VCM in different logic. Check upper index and then - * lower index. If this calibration is valid, apply lower index's result. - */ - ret = upper_ret - lower_ret; - if (ret == 1) { - ret = 0; - /* Make sure we use upper_idx in our calibration system */ - cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | - MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | - MTK_PHY_DA_RX_PSBN_LP_MASK, - upper_idx << 12 | upper_idx << 8 | - upper_idx << 4 | upper_idx); - phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx); - } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && - lower_ret == 1) { - ret = 0; - cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | - MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | - MTK_PHY_DA_RX_PSBN_LP_MASK, - lower_idx << 12 | lower_idx << 8 | - lower_idx << 4 | lower_idx); - phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n", - lower_idx); - } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && - lower_ret == 0) { - ret = 0; - phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n", - upper_idx); - } else { - ret = -EINVAL; - } - -restore: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_ANA_CALEN); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_TXVOS_CALEN); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_ZCALEN_A); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | - MTK_PHY_RG_ZCALEN_D); - - return ret; -} - -static void mt798x_phy_common_finetune(struct phy_device *phydev) -{ - phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */ - __phy_write(phydev, 0x11, 0xc71); - __phy_write(phydev, 0x12, 0xc); - __phy_write(phydev, 0x10, 0x8fae); - - /* EnabRandUpdTrig = 1 */ - __phy_write(phydev, 0x11, 0x2f00); - __phy_write(phydev, 0x12, 0xe); - __phy_write(phydev, 0x10, 0x8fb0); - - /* NormMseLoThresh = 85 */ - __phy_write(phydev, 0x11, 0x55a0); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x83aa); - - /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */ - __phy_write(phydev, 0x11, 0x240); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x9680); - - /* TrFreeze = 0 (mt7988 default) */ - __phy_write(phydev, 0x11, 0x0); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x9686); - - /* SSTrKp100 = 5 */ - /* SSTrKf100 = 6 */ - /* SSTrKp1000Mas = 5 */ - /* SSTrKf1000Mas = 6 */ - /* SSTrKp1000Slv = 5 */ - /* SSTrKf1000Slv = 6 */ - __phy_write(phydev, 0x11, 0xbaef); - __phy_write(phydev, 0x12, 0x2e); - __phy_write(phydev, 0x10, 0x968c); - phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); -} - -static void mt7981_phy_finetune(struct phy_device *phydev) -{ - u16 val[8] = { 0x01ce, 0x01c1, - 0x020f, 0x0202, - 0x03d0, 0x03c0, - 0x0013, 0x0005 }; - int i, k; - - /* 100M eye finetune: - * Keep middle level of TX MLT3 shapper as default. - * Only change TX MLT3 overshoot level here. - */ - for (k = 0, i = 1; i < 12; i++) { - if (i % 3 == 0) - continue; - phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]); - } - - phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - /* ResetSyncOffset = 6 */ - __phy_write(phydev, 0x11, 0x600); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x8fc0); - - /* VgaDecRate = 1 */ - __phy_write(phydev, 0x11, 0x4c2a); - __phy_write(phydev, 0x12, 0x3e); - __phy_write(phydev, 0x10, 0x8fa4); - - /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, - * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 - */ - __phy_write(phydev, 0x11, 0xd10a); - __phy_write(phydev, 0x12, 0x34); - __phy_write(phydev, 0x10, 0x8f82); - - /* VcoSlicerThreshBitsHigh */ - __phy_write(phydev, 0x11, 0x5555); - __phy_write(phydev, 0x12, 0x55); - __phy_write(phydev, 0x10, 0x8ec0); - phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); - - /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */ - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, - MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, - BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); - - /* rg_tr_lpf_cnt_val = 512 */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); - - /* IIR2 related */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); - - /* FFE peaking */ - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, - MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, - MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); - - /* Disable LDO pump */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0); - /* Adjust LDO output voltage */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222); -} - -static void mt7988_phy_finetune(struct phy_device *phydev) -{ - u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182, - 0x020d, 0x0206, 0x0384, 0x03d0, - 0x03c6, 0x030a, 0x0011, 0x0005 }; - int i; - - /* Set default MLT3 shaper first */ - for (i = 0; i < 12; i++) - phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]); - - /* TCT finetune */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); - - phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - /* ResetSyncOffset = 5 */ - __phy_write(phydev, 0x11, 0x500); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x8fc0); - - /* VgaDecRate is 1 at default on mt7988 */ - - /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7, - * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7 - */ - __phy_write(phydev, 0x11, 0xb90a); - __phy_write(phydev, 0x12, 0x6f); - __phy_write(phydev, 0x10, 0x8f82); - - /* RemAckCntLimitCtrl = 1 */ - __phy_write(phydev, 0x11, 0xfbba); - __phy_write(phydev, 0x12, 0xc3); - __phy_write(phydev, 0x10, 0x87f8); - - phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); - - /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */ - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, - MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, - BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa)); - - /* rg_tr_lpf_cnt_val = 1023 */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff); -} - -static void mt798x_phy_eee(struct phy_device *phydev) -{ - phy_modify_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120, - MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK | - MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, - FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) | - FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14)); - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, - MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, - FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, - 0xff)); - - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_TESTMUX_ADC_CTRL, - MTK_PHY_RG_TXEN_DIG_MASK); - - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY); - - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN); - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238, - MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK | - MTK_PHY_LPI_SLV_SEND_TX_EN, - FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120)); - - /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */ - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239, - MTK_PHY_LPI_TXPCS_LOC_RCV); - - /* This also fixes some IoT issues, such as CH340 */ - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7, - MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK, - FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) | - FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13)); - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1, - MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK, - FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK, - 0x33) | - MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY | - MTK_PHY_LPI_VCO_EEE_STG0_EN); - - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323, - MTK_PHY_EEE_WAKE_MAS_INT_DC | - MTK_PHY_EEE_WAKE_SLV_INT_DC); - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324, - MTK_PHY_SMI_DETCNT_MAX_MASK, - FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) | - MTK_PHY_SMI_DET_MAX_EN); - - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326, - MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT | - MTK_PHY_TREC_UPDATE_ENAB_CLR | - MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF | - MTK_PHY_TR_READY_SKIP_AFE_WAKEUP); - - phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - /* Regsigdet_sel_1000 = 0 */ - __phy_write(phydev, 0x11, 0xb); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x9690); - - /* REG_EEE_st2TrKf1000 = 2 */ - __phy_write(phydev, 0x11, 0x114f); - __phy_write(phydev, 0x12, 0x2); - __phy_write(phydev, 0x10, 0x969a); - - /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */ - __phy_write(phydev, 0x11, 0x3028); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x969e); - - /* RegEEE_slv_wake_int_timer_tar = 8 */ - __phy_write(phydev, 0x11, 0x5010); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x96a0); - - /* RegEEE_trfreeze_timer2 = 586 */ - __phy_write(phydev, 0x11, 0x24a); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x96a8); - - /* RegEEE100Stg1_tar = 16 */ - __phy_write(phydev, 0x11, 0x3210); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x96b8); - - /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */ - __phy_write(phydev, 0x11, 0x1463); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x96ca); - - /* DfeTailEnableVgaThresh1000 = 27 */ - __phy_write(phydev, 0x11, 0x36); - __phy_write(phydev, 0x12, 0x0); - __phy_write(phydev, 0x10, 0x8f80); - phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); - - phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3); - __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK, - FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c)); - - __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK, - FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc)); - phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); - - phy_modify_mmd(phydev, MDIO_MMD_VEND1, - MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, - MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, - FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff)); -} - -static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item, - u8 start_pair, u8 end_pair) -{ - u8 pair_n; - int ret; - - for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { - /* TX_OFFSET & TX_AMP have no SW calibration. */ - switch (cal_item) { - case TX_VCM: - ret = tx_vcm_cal_sw(phydev, pair_n); - break; - default: - return -EINVAL; - } - if (ret) - return ret; - } - return 0; -} - -static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item, - u8 start_pair, u8 end_pair, u32 *buf) -{ - u8 pair_n; - int ret; - - for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { - /* TX_VCM has no efuse calibration. */ - switch (cal_item) { - case REXT: - ret = rext_cal_efuse(phydev, buf); - break; - case TX_OFFSET: - ret = tx_offset_cal_efuse(phydev, buf); - break; - case TX_AMP: - ret = tx_amp_cal_efuse(phydev, buf); - break; - case TX_R50: - ret = tx_r50_cal_efuse(phydev, buf, pair_n); - break; - default: - return -EINVAL; - } - if (ret) - return ret; - } - - return 0; -} - -static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item, - enum CAL_MODE cal_mode, u8 start_pair, - u8 end_pair, u32 *buf) -{ - int ret; - - switch (cal_mode) { - case EFUSE_M: - ret = cal_efuse(phydev, cal_item, start_pair, - end_pair, buf); - break; - case SW_M: - ret = cal_sw(phydev, cal_item, start_pair, end_pair); - break; - default: - return -EINVAL; - } - - if (ret) { - phydev_err(phydev, "cal %d failed\n", cal_item); - return -EIO; - } - - return 0; -} - -static int mt798x_phy_calibration(struct phy_device *phydev) -{ - int ret = 0; - u32 *buf; - size_t len; - struct nvmem_cell *cell; - - cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); - if (IS_ERR(cell)) { - if (PTR_ERR(cell) == -EPROBE_DEFER) - return PTR_ERR(cell); - return 0; - } - - buf = (u32 *)nvmem_cell_read(cell, &len); - if (IS_ERR(buf)) - return PTR_ERR(buf); - nvmem_cell_put(cell); - - if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) { - phydev_err(phydev, "invalid efuse data\n"); - ret = -EINVAL; - goto out; - } - - ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf); - if (ret) - goto out; - ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf); - if (ret) - goto out; - ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf); - if (ret) - goto out; - ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf); - if (ret) - goto out; - ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf); - if (ret) - goto out; - -out: - kfree(buf); - return ret; -} - -static int mt798x_phy_config_init(struct phy_device *phydev) -{ - switch (phydev->drv->phy_id) { - case MTK_GPHY_ID_MT7981: - mt7981_phy_finetune(phydev); - break; - case MTK_GPHY_ID_MT7988: - mt7988_phy_finetune(phydev); - break; - } - - mt798x_phy_common_finetune(phydev); - mt798x_phy_eee(phydev); - - return mt798x_phy_calibration(phydev); -} - -static int mt798x_phy_hw_led_on_set(struct phy_device *phydev, u8 index, - bool on) -{ - unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); - struct mtk_socphy_priv *priv = phydev->priv; - bool changed; - - if (on) - changed = !test_and_set_bit(bit_on, &priv->led_state); - else - changed = !!test_and_clear_bit(bit_on, &priv->led_state); - - changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV + - (index ? 16 : 0), &priv->led_state); - if (changed) - return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, - MTK_PHY_LED_ON_MASK, - on ? MTK_PHY_LED_ON_FORCE_ON : 0); - else - return 0; -} - -static int mt798x_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, - bool blinking) -{ - unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0); - struct mtk_socphy_priv *priv = phydev->priv; - bool changed; - - if (blinking) - changed = !test_and_set_bit(bit_blink, &priv->led_state); - else - changed = !!test_and_clear_bit(bit_blink, &priv->led_state); - - changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV + - (index ? 16 : 0), &priv->led_state); - if (changed) - return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_BLINK_CTRL : MTK_PHY_LED0_BLINK_CTRL, - blinking ? MTK_PHY_LED_BLINK_FORCE_BLINK : 0); - else - return 0; -} - -static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index, - unsigned long *delay_on, - unsigned long *delay_off) -{ - bool blinking = false; - int err = 0; - - if (index > 1) - return -EINVAL; - - if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) { - blinking = true; - *delay_on = 50; - *delay_off = 50; - } - - err = mt798x_phy_hw_led_blink_set(phydev, index, blinking); - if (err) - return err; - - return mt798x_phy_hw_led_on_set(phydev, index, false); -} - -static int mt798x_phy_led_brightness_set(struct phy_device *phydev, - u8 index, enum led_brightness value) -{ - int err; - - err = mt798x_phy_hw_led_blink_set(phydev, index, false); - if (err) - return err; - - return mt798x_phy_hw_led_on_set(phydev, index, (value != LED_OFF)); -} - -static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_FULL_DUPLEX) | - BIT(TRIGGER_NETDEV_HALF_DUPLEX) | - BIT(TRIGGER_NETDEV_LINK) | - BIT(TRIGGER_NETDEV_LINK_10) | - BIT(TRIGGER_NETDEV_LINK_100) | - BIT(TRIGGER_NETDEV_LINK_1000) | - BIT(TRIGGER_NETDEV_RX) | - BIT(TRIGGER_NETDEV_TX)); - -static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, - unsigned long rules) -{ - if (index > 1) - return -EINVAL; - - /* All combinations of the supported triggers are allowed */ - if (rules & ~supported_triggers) - return -EOPNOTSUPP; - - return 0; -}; - -static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index, - unsigned long *rules) -{ - unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + (index ? 16 : 0); - unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); - unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); - struct mtk_socphy_priv *priv = phydev->priv; - int on, blink; - - if (index > 1) - return -EINVAL; - - on = phy_read_mmd(phydev, MDIO_MMD_VEND2, - index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL); - - if (on < 0) - return -EIO; - - blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, - index ? MTK_PHY_LED1_BLINK_CTRL : - MTK_PHY_LED0_BLINK_CTRL); - if (blink < 0) - return -EIO; - - if ((on & (MTK_PHY_LED_ON_LINK | MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | - MTK_PHY_LED_ON_LINKDOWN)) || - (blink & (MTK_PHY_LED_BLINK_RX | MTK_PHY_LED_BLINK_TX))) - set_bit(bit_netdev, &priv->led_state); - else - clear_bit(bit_netdev, &priv->led_state); - - if (on & MTK_PHY_LED_ON_FORCE_ON) - set_bit(bit_on, &priv->led_state); - else - clear_bit(bit_on, &priv->led_state); - - if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK) - set_bit(bit_blink, &priv->led_state); - else - clear_bit(bit_blink, &priv->led_state); - - if (!rules) - return 0; - - if (on & MTK_PHY_LED_ON_LINK) - *rules |= BIT(TRIGGER_NETDEV_LINK); - - if (on & MTK_PHY_LED_ON_LINK10) - *rules |= BIT(TRIGGER_NETDEV_LINK_10); - - if (on & MTK_PHY_LED_ON_LINK100) - *rules |= BIT(TRIGGER_NETDEV_LINK_100); - - if (on & MTK_PHY_LED_ON_LINK1000) - *rules |= BIT(TRIGGER_NETDEV_LINK_1000); - - if (on & MTK_PHY_LED_ON_FDX) - *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); - - if (on & MTK_PHY_LED_ON_HDX) - *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); - - if (blink & MTK_PHY_LED_BLINK_RX) - *rules |= BIT(TRIGGER_NETDEV_RX); - - if (blink & MTK_PHY_LED_BLINK_TX) - *rules |= BIT(TRIGGER_NETDEV_TX); - - return 0; -}; - -static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index, - unsigned long rules) -{ - unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); - struct mtk_socphy_priv *priv = phydev->priv; - u16 on = 0, blink = 0; - int ret; - - if (index > 1) - return -EINVAL; - - if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) - on |= MTK_PHY_LED_ON_FDX; - - if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) - on |= MTK_PHY_LED_ON_HDX; - - if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) - on |= MTK_PHY_LED_ON_LINK10; - - if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) - on |= MTK_PHY_LED_ON_LINK100; - - if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) - on |= MTK_PHY_LED_ON_LINK1000; - - if (rules & BIT(TRIGGER_NETDEV_RX)) { - blink |= (on & MTK_PHY_LED_ON_LINK) ? - (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10RX : 0) | - ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100RX : 0) | - ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000RX : 0)) : - MTK_PHY_LED_BLINK_RX; - } - - if (rules & BIT(TRIGGER_NETDEV_TX)) { - blink |= (on & MTK_PHY_LED_ON_LINK) ? - (((on & MTK_PHY_LED_ON_LINK10) ? MTK_PHY_LED_BLINK_10TX : 0) | - ((on & MTK_PHY_LED_ON_LINK100) ? MTK_PHY_LED_BLINK_100TX : 0) | - ((on & MTK_PHY_LED_ON_LINK1000) ? MTK_PHY_LED_BLINK_1000TX : 0)) : - MTK_PHY_LED_BLINK_TX; - } - - if (blink || on) - set_bit(bit_netdev, &priv->led_state); - else - clear_bit(bit_netdev, &priv->led_state); - - ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_ON_CTRL : - MTK_PHY_LED0_ON_CTRL, - MTK_PHY_LED_ON_FDX | - MTK_PHY_LED_ON_HDX | - MTK_PHY_LED_ON_LINK, - on); - - if (ret) - return ret; - - return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_BLINK_CTRL : - MTK_PHY_LED0_BLINK_CTRL, blink); -}; - -static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num) -{ - struct mtk_socphy_shared *priv = phydev->shared->priv; - u32 polarities; - - if (led_num == 0) - polarities = ~(priv->boottrap); - else - polarities = MTK_PHY_LED1_DEFAULT_POLARITIES; - - if (polarities & BIT(phydev->mdio.addr)) - return true; - - return false; -} - -static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev) -{ - struct pinctrl *pinctrl; - int index; - - /* Setup LED polarity according to bootstrap use of LED pins */ - for (index = 0; index < 2; ++index) - phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? - MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, - MTK_PHY_LED_ON_POLARITY, - mt7988_phy_led_get_polarity(phydev, index) ? - MTK_PHY_LED_ON_POLARITY : 0); - - /* Only now setup pinctrl to avoid bogus blinking */ - pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led"); - if (IS_ERR(pinctrl)) - dev_err(&phydev->mdio.bus->dev, "Failed to setup PHY LED pinctrl\n"); - - return 0; -} - -static int mt7988_phy_probe_shared(struct phy_device *phydev) -{ - struct device_node *np = dev_of_node(&phydev->mdio.bus->dev); - struct mtk_socphy_shared *shared = phydev->shared->priv; - struct regmap *regmap; - u32 reg; - int ret; - - /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B, - * LED_C and LED_D respectively. At the same time those pins are used to - * bootstrap configuration of the reference clock source (LED_A), - * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D). - * In practise this is done using a LED and a resistor pulling the pin - * either to GND or to VIO. - * The detected value at boot time is accessible at run-time using the - * TPBANK0 register located in the gpio base of the pinctrl, in order - * to read it here it needs to be referenced by a phandle called - * 'mediatek,pio' in the MDIO bus hosting the PHY. - * The 4 bits in TPBANK0 are kept as package shared data and are used to - * set LED polarity for each of the LED0. - */ - regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio"); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®); - if (ret) - return ret; - - shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg); - - return 0; -} - -static void mt798x_phy_leds_state_init(struct phy_device *phydev) -{ - int i; - - for (i = 0; i < 2; ++i) - mt798x_phy_led_hw_control_get(phydev, i, NULL); -} - -static int mt7988_phy_probe(struct phy_device *phydev) -{ - struct mtk_socphy_shared *shared; - struct mtk_socphy_priv *priv; - int err; - - if (phydev->mdio.addr > 3) - return -EINVAL; - - err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0, - sizeof(struct mtk_socphy_shared)); - if (err) - return err; - - if (phy_package_probe_once(phydev)) { - err = mt7988_phy_probe_shared(phydev); - if (err) - return err; - } - - shared = phydev->shared->priv; - priv = &shared->priv[phydev->mdio.addr]; - - phydev->priv = priv; - - mt798x_phy_leds_state_init(phydev); - - err = mt7988_phy_fix_leds_polarities(phydev); - if (err) - return err; - - /* Disable TX power saving at probing to: - * 1. Meet common mode compliance test criteria - * 2. Make sure that TX-VCM calibration works fine - */ - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, - MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); - - return mt798x_phy_calibration(phydev); -} - -static int mt7981_phy_probe(struct phy_device *phydev) -{ - struct mtk_socphy_priv *priv; - - priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv), - GFP_KERNEL); - if (!priv) - return -ENOMEM; - - phydev->priv = priv; - - mt798x_phy_leds_state_init(phydev); - - return mt798x_phy_calibration(phydev); -} - -static struct phy_driver mtk_socphy_driver[] = { - { - PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981), - .name = "MediaTek MT7981 PHY", - .config_init = mt798x_phy_config_init, - .config_intr = genphy_no_config_intr, - .handle_interrupt = genphy_handle_interrupt_no_ack, - .probe = mt7981_phy_probe, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_page = mtk_socphy_read_page, - .write_page = mtk_socphy_write_page, - .led_blink_set = mt798x_phy_led_blink_set, - .led_brightness_set = mt798x_phy_led_brightness_set, - .led_hw_is_supported = mt798x_phy_led_hw_is_supported, - .led_hw_control_set = mt798x_phy_led_hw_control_set, - .led_hw_control_get = mt798x_phy_led_hw_control_get, - }, - { - PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988), - .name = "MediaTek MT7988 PHY", - .config_init = mt798x_phy_config_init, - .config_intr = genphy_no_config_intr, - .handle_interrupt = genphy_handle_interrupt_no_ack, - .probe = mt7988_phy_probe, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_page = mtk_socphy_read_page, - .write_page = mtk_socphy_write_page, - .led_blink_set = mt798x_phy_led_blink_set, - .led_brightness_set = mt798x_phy_led_brightness_set, - .led_hw_is_supported = mt798x_phy_led_hw_is_supported, - .led_hw_control_set = mt798x_phy_led_hw_control_set, - .led_hw_control_get = mt798x_phy_led_hw_control_get, - }, -}; - -module_phy_driver(mtk_socphy_driver); - -static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { - { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, - { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, - { } -}; - -MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver"); -MODULE_AUTHOR("Daniel Golle "); -MODULE_AUTHOR("SkyLake Huang "); -MODULE_LICENSE("GPL"); - -MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl); diff --git a/drivers/net/phy/mediatek-ge.c b/drivers/net/phy/mediatek-ge.c deleted file mode 100644 index 54ea64a37ab3a1..00000000000000 --- a/drivers/net/phy/mediatek-ge.c +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -#include -#include -#include - -#define MTK_EXT_PAGE_ACCESS 0x1f -#define MTK_PHY_PAGE_STANDARD 0x0000 -#define MTK_PHY_PAGE_EXTENDED 0x0001 -#define MTK_PHY_PAGE_EXTENDED_2 0x0002 -#define MTK_PHY_PAGE_EXTENDED_3 0x0003 -#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 -#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 - -static int mtk_gephy_read_page(struct phy_device *phydev) -{ - return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); -} - -static int mtk_gephy_write_page(struct phy_device *phydev, int page) -{ - return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); -} - -static void mtk_gephy_config_init(struct phy_device *phydev) -{ - /* Enable HW auto downshift */ - phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4)); - - /* Increase SlvDPSready time */ - phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - __phy_write(phydev, 0x10, 0xafae); - __phy_write(phydev, 0x12, 0x2f); - __phy_write(phydev, 0x10, 0x8fae); - phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); - - /* Adjust 100_mse_threshold */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff); - - /* Disable mcc */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300); -} - -static int mt7530_phy_config_init(struct phy_device *phydev) -{ - mtk_gephy_config_init(phydev); - - /* Increase post_update_timer */ - phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b); - - return 0; -} - -static int mt7531_phy_config_init(struct phy_device *phydev) -{ - mtk_gephy_config_init(phydev); - - /* PHY link down power saving enable */ - phy_set_bits(phydev, 0x17, BIT(4)); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300); - - /* Set TX Pair delay selection */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404); - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404); - - return 0; -} - -static struct phy_driver mtk_gephy_driver[] = { - { - PHY_ID_MATCH_EXACT(0x03a29412), - .name = "MediaTek MT7530 PHY", - .config_init = mt7530_phy_config_init, - /* Interrupts are handled by the switch, not the PHY - * itself. - */ - .config_intr = genphy_no_config_intr, - .handle_interrupt = genphy_handle_interrupt_no_ack, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, - }, - { - PHY_ID_MATCH_EXACT(0x03a29441), - .name = "MediaTek MT7531 PHY", - .config_init = mt7531_phy_config_init, - /* Interrupts are handled by the switch, not the PHY - * itself. - */ - .config_intr = genphy_no_config_intr, - .handle_interrupt = genphy_handle_interrupt_no_ack, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, - }, -}; - -module_phy_driver(mtk_gephy_driver); - -static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { - { PHY_ID_MATCH_EXACT(0x03a29441) }, - { PHY_ID_MATCH_EXACT(0x03a29412) }, - { } -}; - -MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver"); -MODULE_AUTHOR("DENG, Qingfang "); -MODULE_LICENSE("GPL"); - -MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl); diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig new file mode 100644 index 00000000000000..2a8ac5aed0f893 --- /dev/null +++ b/drivers/net/phy/mediatek/Kconfig @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-only +config MTK_NET_PHYLIB + tristate + +config MEDIATEK_GE_PHY + tristate "MediaTek Gigabit Ethernet PHYs" + select MTK_NET_PHYLIB + help + Supports the MediaTek non-built-in Gigabit Ethernet PHYs. + + Non-built-in Gigabit Ethernet PHYs include mt7530/mt7531. + You may find mt7530 inside mt7621. This driver shares some + common operations with MediaTek SoC built-in Gigabit + Ethernet PHYs. + +config MEDIATEK_GE_SOC_PHY + tristate "MediaTek SoC Ethernet PHYs" + depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST + depends on NVMEM_MTK_EFUSE + select MTK_NET_PHYLIB + help + Supports MediaTek SoC built-in Gigabit Ethernet PHYs. + + Include support for built-in Ethernet PHYs which are present in + the MT7981 and MT7988 SoCs. These PHYs need calibration data + present in the SoCs efuse and will dynamically calibrate VCM + (common-mode voltage) during startup. diff --git a/drivers/net/phy/mediatek/Makefile b/drivers/net/phy/mediatek/Makefile new file mode 100644 index 00000000000000..814879d0abe5de --- /dev/null +++ b/drivers/net/phy/mediatek/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_MTK_NET_PHYLIB) += mtk-phy-lib.o +obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-ge.o +obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mtk-ge-soc.o diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c new file mode 100644 index 00000000000000..38dc898eaf7bf0 --- /dev/null +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -0,0 +1,1370 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk.h" + +#define MTK_GPHY_ID_MT7981 0x03a29461 +#define MTK_GPHY_ID_MT7988 0x03a29481 + +#define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_STANDARD 0x0000 +#define MTK_PHY_PAGE_EXTENDED_3 0x0003 + +#define MTK_PHY_LPI_REG_14 0x14 +#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0) + +#define MTK_PHY_LPI_REG_1c 0x1c +#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8) + +#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 +#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + +#define ANALOG_INTERNAL_OPERATION_MAX_US 20 +#define TXRESERVE_MIN 0 +#define TXRESERVE_MAX 7 + +#define MTK_PHY_ANARG_RG 0x10 +#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8) + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_TXVLD_DA_RG 0x12 +#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10) +#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16 +#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10) +#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17 +#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18 +#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19 +#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20 +#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21 +#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22 +#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_RXADC_CTRL_RG7 0xc6 +#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) + +#define MTK_PHY_RXADC_CTRL_RG9 0xc8 +#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12) +#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8) +#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4) +#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0) + +#define MTK_PHY_LDO_OUTPUT_V 0xd7 + +#define MTK_PHY_RG_ANA_CAL_RG0 0xdb +#define MTK_PHY_RG_CAL_CKINV BIT(12) +#define MTK_PHY_RG_ANA_CALEN BIT(8) +#define MTK_PHY_RG_ZCALEN_A BIT(0) + +#define MTK_PHY_RG_ANA_CAL_RG1 0xdc +#define MTK_PHY_RG_ZCALEN_B BIT(12) +#define MTK_PHY_RG_ZCALEN_C BIT(8) +#define MTK_PHY_RG_ZCALEN_D BIT(4) +#define MTK_PHY_RG_TXVOS_CALEN BIT(0) + +#define MTK_PHY_RG_ANA_CAL_RG5 0xe0 +#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8) + +#define MTK_PHY_RG_TX_FILTER 0xfe + +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120 +#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8) +#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0) + +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122 +#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0) + +#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144 +#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5) + +#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172 +#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8) +#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0) + +#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173 +#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8) +#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) + +#define MTK_PHY_RG_AD_CAL_COMP 0x17a +#define MTK_PHY_AD_CAL_COMP_OUT_MASK GENMASK(8, 8) + +#define MTK_PHY_RG_AD_CAL_CLK 0x17b +#define MTK_PHY_DA_CAL_CLK BIT(0) + +#define MTK_PHY_RG_AD_CALIN 0x17c +#define MTK_PHY_DA_CALIN_FLAG BIT(0) + +#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d +#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e +#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f +#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180 +#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181 +#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182 +#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183 +#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184 +#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DEV1E_REG19b 0x19b +#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8) + +#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a +#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b +#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c +#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d +#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e +#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f +#define MTK_PHY_RG_LP_IIR2_K4_L 0x230 +#define MTK_PHY_RG_LP_IIR2_K4_U 0x231 +#define MTK_PHY_RG_LP_IIR2_K5_L 0x232 +#define MTK_PHY_RG_LP_IIR2_K5_U 0x233 + +#define MTK_PHY_RG_DEV1E_REG234 0x234 +#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0) +#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4) +#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12) + +#define MTK_PHY_RG_LPF_CNT_VAL 0x235 + +#define MTK_PHY_RG_DEV1E_REG238 0x238 +#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0) +#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12) + +#define MTK_PHY_RG_DEV1E_REG239 0x239 +#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0) +#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12) + +#define MTK_PHY_RG_DEV1E_REG27C 0x27c +#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8) +#define MTK_PHY_RG_DEV1E_REG27D 0x27d +#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0) + +#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7 +#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0) +#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8) + +#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1 +#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0) +#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8) +#define MTK_PHY_LPI_TR_READY BIT(9) +#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10) + +#define MTK_PHY_RG_DEV1E_REG323 0x323 +#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0) +#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4) + +#define MTK_PHY_RG_DEV1E_REG324 0x324 +#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0) +#define MTK_PHY_SMI_DET_MAX_EN BIT(8) + +#define MTK_PHY_RG_DEV1E_REG326 0x326 +#define MTK_PHY_LPI_MODE_SD_ON BIT(0) +#define MTK_PHY_RESET_RANDUPD_CNT BIT(1) +#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2) +#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4) +#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5) + +#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502 +#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503 + +#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d +#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e +#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f +#define MTK_PHY_DA_TX_R50_PAIR_D 0x540 + +/* Registers on MDIO_MMD_VEND2 */ +#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1) + +#define MTK_PHY_RG_BG_RASEL 0x115 +#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0) + +/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */ +#define RG_GPIO_MISC_TPBANK0 0x6f0 +#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8) + +/* These macro privides efuse parsing for internal phy. */ +#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0)) + +#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0)) + +#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0)) + +#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0)) +#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0)) + +enum { + NO_PAIR, + PAIR_A, + PAIR_B, + PAIR_C, + PAIR_D, +}; + +enum calibration_mode { + EFUSE_K, + SW_K +}; + +enum CAL_ITEM { + REXT, + TX_OFFSET, + TX_AMP, + TX_R50, + TX_VCM +}; + +enum CAL_MODE { + EFUSE_M, + SW_M +}; + +struct mtk_socphy_shared { + u32 boottrap; + struct mtk_socphy_priv priv[4]; +}; + +/* One calibration cycle consists of: + * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high + * until AD_CAL_COMP is ready to output calibration result. + * 2.Wait until DA_CAL_CLK is available. + * 3.Fetch AD_CAL_COMP_OUT. + */ +static int cal_cycle(struct phy_device *phydev, int devad, + u32 regnum, u16 mask, u16 cal_val) +{ + int reg_val; + int ret; + + phy_modify_mmd(phydev, devad, regnum, + mask, cal_val); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); + + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_AD_CAL_CLK, reg_val, + reg_val & MTK_PHY_DA_CAL_CLK, 500, + ANALOG_INTERNAL_OPERATION_MAX_US, + false); + if (ret) { + phydev_err(phydev, "Calibration cycle timeout\n"); + return ret; + } + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP); + if (ret < 0) + return ret; + ret = FIELD_GET(MTK_PHY_AD_CAL_COMP_OUT_MASK, ret); + phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); + + return ret; +} + +static int rext_fill_result(struct phy_device *phydev, u16 *buf) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, + MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL, + MTK_PHY_RG_BG_RASEL_MASK, buf[1]); + + return 0; +} + +static int rext_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 rext_cal_val[2]; + + rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]); + rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]); + rext_fill_result(phydev, rext_cal_val); + + return 0; +} + +static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, + MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, + MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, + MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, + MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]); + + return 0; +} + +static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 tx_offset_cal_val[4]; + + tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]); + tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]); + tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]); + tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]); + + tx_offset_fill_result(phydev, tx_offset_cal_val); + + return 0; +} + +static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) +{ + const int vals_9481[16] = { 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10 }; + const int vals_9461[16] = { 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7 }; + int bias[16] = {}; + int i; + + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + /* We add some calibration to efuse values + * due to board level influence. + * GBE: +7, TBT: +1, HBT: +4, TST: +7 + */ + memcpy(bias, (const void *)vals_9461, sizeof(bias)); + break; + case MTK_GPHY_ID_MT7988: + memcpy(bias, (const void *)vals_9481, sizeof(bias)); + break; + } + + /* Prevent overflow */ + for (i = 0; i < 12; i++) { + if (buf[i >> 2] + bias[i] > 63) { + buf[i >> 2] = 63; + bias[i] = 0; + } + } + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, + MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, + buf[0] + bias[0])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, + MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, + buf[0] + bias[1])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, + MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, + buf[0] + bias[2])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, + MTK_PHY_DA_TX_I2MPB_A_TST_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_A_TST_MASK, + buf[0] + bias[3])); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, + MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, + buf[1] + bias[4])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, + MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, + buf[1] + bias[5])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, + MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, + buf[1] + bias[6])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, + MTK_PHY_DA_TX_I2MPB_B_TST_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_B_TST_MASK, + buf[1] + bias[7])); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, + MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, + buf[2] + bias[8])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, + MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, + buf[2] + bias[9])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, + MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, + buf[2] + bias[10])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, + MTK_PHY_DA_TX_I2MPB_C_TST_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_C_TST_MASK, + buf[2] + bias[11])); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, + MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, + buf[3] + bias[12])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, + MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, + buf[3] + bias[13])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, + MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, + buf[3] + bias[14])); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, + MTK_PHY_DA_TX_I2MPB_D_TST_MASK, + FIELD_PREP(MTK_PHY_DA_TX_I2MPB_D_TST_MASK, + buf[3] + bias[15])); + + return 0; +} + +static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 tx_amp_cal_val[4]; + + tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]); + tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]); + tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]); + tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]); + tx_amp_fill_result(phydev, tx_amp_cal_val); + + return 0; +} + +static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val, + u8 txg_calen_x) +{ + int bias = 0; + u16 reg, val; + + if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988) + bias = -1; + + val = clamp_val(bias + tx_r50_cal_val, 0, 63); + + switch (txg_calen_x) { + case PAIR_A: + reg = MTK_PHY_DA_TX_R50_PAIR_A; + break; + case PAIR_B: + reg = MTK_PHY_DA_TX_R50_PAIR_B; + break; + case PAIR_C: + reg = MTK_PHY_DA_TX_R50_PAIR_C; + break; + case PAIR_D: + reg = MTK_PHY_DA_TX_R50_PAIR_D; + break; + default: + return -EINVAL; + } + + phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8); + + return 0; +} + +static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf, + u8 txg_calen_x) +{ + u16 tx_r50_cal_val; + + switch (txg_calen_x) { + case PAIR_A: + tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]); + break; + case PAIR_B: + tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]); + break; + case PAIR_C: + tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]); + break; + case PAIR_D: + tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]); + break; + default: + return -EINVAL; + } + tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); + + return 0; +} + +static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) +{ + u8 lower_idx, upper_idx, txreserve_val; + u8 lower_ret, upper_ret; + int ret; + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ANA_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_CAL_CKINV); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_TXVOS_CALEN); + + switch (rg_txreserve_x) { + case PAIR_A: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_A, + MTK_PHY_DASN_DAC_IN0_A_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_A, + MTK_PHY_DASN_DAC_IN1_A_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ZCALEN_A); + break; + case PAIR_B: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_B, + MTK_PHY_DASN_DAC_IN0_B_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_B, + MTK_PHY_DASN_DAC_IN1_B_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_B); + break; + case PAIR_C: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_C, + MTK_PHY_DASN_DAC_IN0_C_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_C, + MTK_PHY_DASN_DAC_IN1_C_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_C); + break; + case PAIR_D: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_D, + MTK_PHY_DASN_DAC_IN0_D_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_D, + MTK_PHY_DASN_DAC_IN1_D_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_D); + break; + default: + ret = -EINVAL; + goto restore; + } + + lower_idx = TXRESERVE_MIN; + upper_idx = TXRESERVE_MAX; + + phydev_dbg(phydev, "Start TX-VCM SW cal.\n"); + while ((upper_idx - lower_idx) > 1) { + txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2); + ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + txreserve_val << 12 | txreserve_val << 8 | + txreserve_val << 4 | txreserve_val); + if (ret == 1) { + upper_idx = txreserve_val; + upper_ret = ret; + } else if (ret == 0) { + lower_idx = txreserve_val; + lower_ret = ret; + } else { + goto restore; + } + } + + if (lower_idx == TXRESERVE_MIN) { + lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, + MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + lower_idx << 12 | lower_idx << 8 | + lower_idx << 4 | lower_idx); + ret = lower_ret; + } else if (upper_idx == TXRESERVE_MAX) { + upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, + MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + upper_idx << 12 | upper_idx << 8 | + upper_idx << 4 | upper_idx); + ret = upper_ret; + } + if (ret < 0) + goto restore; + + /* We calibrate TX-VCM in different logic. Check upper index and then + * lower index. If this calibration is valid, apply lower index's + * result. + */ + ret = upper_ret - lower_ret; + if (ret == 1) { + ret = 0; + /* Make sure we use upper_idx in our calibration system */ + cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + upper_idx << 12 | upper_idx << 8 | + upper_idx << 4 | upper_idx); + phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx); + } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && + lower_ret == 1) { + ret = 0; + cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + lower_idx << 12 | lower_idx << 8 | + lower_idx << 4 | lower_idx); + phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n", + lower_idx); + } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && + lower_ret == 0) { + ret = 0; + phydev_warn(phydev, + "TX-VCM SW cal result at high margin 0x%x\n", + upper_idx); + } else { + ret = -EINVAL; + } + +restore: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ANA_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_TXVOS_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ZCALEN_A); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | + MTK_PHY_RG_ZCALEN_D); + + return ret; +} + +static void mt798x_phy_common_finetune(struct phy_device *phydev) +{ + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */ + __phy_write(phydev, 0x11, 0xc71); + __phy_write(phydev, 0x12, 0xc); + __phy_write(phydev, 0x10, 0x8fae); + + /* EnabRandUpdTrig = 1 */ + __phy_write(phydev, 0x11, 0x2f00); + __phy_write(phydev, 0x12, 0xe); + __phy_write(phydev, 0x10, 0x8fb0); + + /* NormMseLoThresh = 85 */ + __phy_write(phydev, 0x11, 0x55a0); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x83aa); + + /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */ + __phy_write(phydev, 0x11, 0x240); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9680); + + /* TrFreeze = 0 (mt7988 default) */ + __phy_write(phydev, 0x11, 0x0); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9686); + + /* SSTrKp100 = 5 */ + /* SSTrKf100 = 6 */ + /* SSTrKp1000Mas = 5 */ + /* SSTrKf1000Mas = 6 */ + /* SSTrKp1000Slv = 5 */ + /* SSTrKf1000Slv = 6 */ + __phy_write(phydev, 0x11, 0xbaef); + __phy_write(phydev, 0x12, 0x2e); + __phy_write(phydev, 0x10, 0x968c); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); +} + +static void mt7981_phy_finetune(struct phy_device *phydev) +{ + u16 val[8] = { 0x01ce, 0x01c1, + 0x020f, 0x0202, + 0x03d0, 0x03c0, + 0x0013, 0x0005 }; + int i, k; + + /* 100M eye finetune: + * Keep middle level of TX MLT3 shapper as default. + * Only change TX MLT3 overshoot level here. + */ + for (k = 0, i = 1; i < 12; i++) { + if (i % 3 == 0) + continue; + phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]); + } + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* ResetSyncOffset = 6 */ + __phy_write(phydev, 0x11, 0x600); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8fc0); + + /* VgaDecRate = 1 */ + __phy_write(phydev, 0x11, 0x4c2a); + __phy_write(phydev, 0x12, 0x3e); + __phy_write(phydev, 0x10, 0x8fa4); + + /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, + * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 + */ + __phy_write(phydev, 0x11, 0xd10a); + __phy_write(phydev, 0x12, 0x34); + __phy_write(phydev, 0x10, 0x8f82); + + /* VcoSlicerThreshBitsHigh */ + __phy_write(phydev, 0x11, 0x5555); + __phy_write(phydev, 0x12, 0x55); + __phy_write(phydev, 0x10, 0x8ec0); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, + MTK_PHY_TR_OPEN_LOOP_EN_MASK | + MTK_PHY_LPF_X_AVERAGE_MASK, + BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); + + /* rg_tr_lpf_cnt_val = 512 */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); + + /* IIR2 related */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); + + /* FFE peaking */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, + MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, + MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); + + /* Disable LDO pump */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0); + /* Adjust LDO output voltage */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222); +} + +static void mt7988_phy_finetune(struct phy_device *phydev) +{ + u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182, + 0x020d, 0x0206, 0x0384, 0x03d0, + 0x03c6, 0x030a, 0x0011, 0x0005 }; + int i; + + /* Set default MLT3 shaper first */ + for (i = 0; i < 12; i++) + phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]); + + /* TCT finetune */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* ResetSyncOffset = 5 */ + __phy_write(phydev, 0x11, 0x500); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8fc0); + + /* VgaDecRate is 1 at default on mt7988 */ + + /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7, + * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7 + */ + __phy_write(phydev, 0x11, 0xb90a); + __phy_write(phydev, 0x12, 0x6f); + __phy_write(phydev, 0x10, 0x8f82); + + /* RemAckCntLimitCtrl = 1 */ + __phy_write(phydev, 0x11, 0xfbba); + __phy_write(phydev, 0x12, 0xc3); + __phy_write(phydev, 0x10, 0x87f8); + + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, + MTK_PHY_TR_OPEN_LOOP_EN_MASK | + MTK_PHY_LPF_X_AVERAGE_MASK, + BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa)); + + /* rg_tr_lpf_cnt_val = 1023 */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff); +} + +static void mt798x_phy_eee(struct phy_device *phydev) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120, + MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK | + MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) | + FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, + MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + 0xff)); + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_TESTMUX_ADC_CTRL, + MTK_PHY_RG_TXEN_DIG_MASK); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY); + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238, + MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK | + MTK_PHY_LPI_SLV_SEND_TX_EN, + FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120)); + + /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */ + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239, + MTK_PHY_LPI_TXPCS_LOC_RCV); + + /* This also fixes some IoT issues, such as CH340 */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7, + MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK, + FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) | + FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1, + MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK, + FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK, + 0x33) | + MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY | + MTK_PHY_LPI_VCO_EEE_STG0_EN); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323, + MTK_PHY_EEE_WAKE_MAS_INT_DC | + MTK_PHY_EEE_WAKE_SLV_INT_DC); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324, + MTK_PHY_SMI_DETCNT_MAX_MASK, + FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) | + MTK_PHY_SMI_DET_MAX_EN); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326, + MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT | + MTK_PHY_TREC_UPDATE_ENAB_CLR | + MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF | + MTK_PHY_TR_READY_SKIP_AFE_WAKEUP); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* Regsigdet_sel_1000 = 0 */ + __phy_write(phydev, 0x11, 0xb); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9690); + + /* REG_EEE_st2TrKf1000 = 2 */ + __phy_write(phydev, 0x11, 0x114f); + __phy_write(phydev, 0x12, 0x2); + __phy_write(phydev, 0x10, 0x969a); + + /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */ + __phy_write(phydev, 0x11, 0x3028); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x969e); + + /* RegEEE_slv_wake_int_timer_tar = 8 */ + __phy_write(phydev, 0x11, 0x5010); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96a0); + + /* RegEEE_trfreeze_timer2 = 586 */ + __phy_write(phydev, 0x11, 0x24a); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96a8); + + /* RegEEE100Stg1_tar = 16 */ + __phy_write(phydev, 0x11, 0x3210); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96b8); + + /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */ + __phy_write(phydev, 0x11, 0x1463); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96ca); + + /* DfeTailEnableVgaThresh1000 = 27 */ + __phy_write(phydev, 0x11, 0x36); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8f80); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3); + __phy_modify(phydev, MTK_PHY_LPI_REG_14, + MTK_PHY_LPI_WAKE_TIMER_1000_MASK, + FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c)); + + __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK, + FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, + MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + 0xff)); +} + +static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item, + u8 start_pair, u8 end_pair) +{ + u8 pair_n; + int ret; + + for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { + /* TX_OFFSET & TX_AMP have no SW calibration. */ + switch (cal_item) { + case TX_VCM: + ret = tx_vcm_cal_sw(phydev, pair_n); + break; + default: + return -EINVAL; + } + if (ret) + return ret; + } + return 0; +} + +static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item, + u8 start_pair, u8 end_pair, u32 *buf) +{ + u8 pair_n; + int ret; + + for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { + /* TX_VCM has no efuse calibration. */ + switch (cal_item) { + case REXT: + ret = rext_cal_efuse(phydev, buf); + break; + case TX_OFFSET: + ret = tx_offset_cal_efuse(phydev, buf); + break; + case TX_AMP: + ret = tx_amp_cal_efuse(phydev, buf); + break; + case TX_R50: + ret = tx_r50_cal_efuse(phydev, buf, pair_n); + break; + default: + return -EINVAL; + } + if (ret) + return ret; + } + + return 0; +} + +static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item, + enum CAL_MODE cal_mode, u8 start_pair, + u8 end_pair, u32 *buf) +{ + int ret; + + switch (cal_mode) { + case EFUSE_M: + ret = cal_efuse(phydev, cal_item, start_pair, + end_pair, buf); + break; + case SW_M: + ret = cal_sw(phydev, cal_item, start_pair, end_pair); + break; + default: + return -EINVAL; + } + + if (ret) { + phydev_err(phydev, "cal %d failed\n", cal_item); + return -EIO; + } + + return 0; +} + +static int mt798x_phy_calibration(struct phy_device *phydev) +{ + struct nvmem_cell *cell; + int ret = 0; + size_t len; + u32 *buf; + + cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); + if (IS_ERR(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) + return PTR_ERR(cell); + return 0; + } + + buf = (u32 *)nvmem_cell_read(cell, &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + nvmem_cell_put(cell); + + if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) { + phydev_err(phydev, "invalid efuse data\n"); + ret = -EINVAL; + goto out; + } + + ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf); + if (ret) + goto out; + +out: + kfree(buf); + return ret; +} + +static int mt798x_phy_config_init(struct phy_device *phydev) +{ + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + mt7981_phy_finetune(phydev); + break; + case MTK_GPHY_ID_MT7988: + mt7988_phy_finetune(phydev); + break; + } + + mt798x_phy_common_finetune(phydev); + mt798x_phy_eee(phydev); + + return mt798x_phy_calibration(phydev); +} + +static int mt798x_phy_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *delay_on, + unsigned long *delay_off) +{ + bool blinking = false; + int err; + + err = mtk_phy_led_num_dly_cfg(index, delay_on, delay_off, &blinking); + if (err < 0) + return err; + + err = mtk_phy_hw_led_blink_set(phydev, index, blinking); + if (err) + return err; + + return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK, + false); +} + +static int mt798x_phy_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + int err; + + err = mtk_phy_hw_led_blink_set(phydev, index, false); + if (err) + return err; + + return mtk_phy_hw_led_on_set(phydev, index, MTK_GPHY_LED_ON_MASK, + (value != LED_OFF)); +} + +static const unsigned long supported_triggers = + BIT(TRIGGER_NETDEV_FULL_DUPLEX) | + BIT(TRIGGER_NETDEV_HALF_DUPLEX) | + BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX); + +static int mt798x_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + return mtk_phy_led_hw_is_supported(phydev, index, rules, + supported_triggers); +} + +static int mt798x_phy_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + return mtk_phy_led_hw_ctrl_get(phydev, index, rules, + MTK_GPHY_LED_ON_SET, + MTK_GPHY_LED_RX_BLINK_SET, + MTK_GPHY_LED_TX_BLINK_SET); +}; + +static int mt798x_phy_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + return mtk_phy_led_hw_ctrl_set(phydev, index, rules, + MTK_GPHY_LED_ON_SET, + MTK_GPHY_LED_RX_BLINK_SET, + MTK_GPHY_LED_TX_BLINK_SET); +}; + +static bool mt7988_phy_led_get_polarity(struct phy_device *phydev, int led_num) +{ + struct mtk_socphy_shared *priv = phydev->shared->priv; + u32 polarities; + + if (led_num == 0) + polarities = ~(priv->boottrap); + else + polarities = MTK_PHY_LED1_DEFAULT_POLARITIES; + + if (polarities & BIT(phydev->mdio.addr)) + return true; + + return false; +} + +static int mt7988_phy_fix_leds_polarities(struct phy_device *phydev) +{ + struct pinctrl *pinctrl; + int index; + + /* Setup LED polarity according to bootstrap use of LED pins */ + for (index = 0; index < 2; ++index) + phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_POLARITY, + mt7988_phy_led_get_polarity(phydev, index) ? + MTK_PHY_LED_ON_POLARITY : 0); + + /* Only now setup pinctrl to avoid bogus blinking */ + pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led"); + if (IS_ERR(pinctrl)) + dev_err(&phydev->mdio.bus->dev, + "Failed to setup PHY LED pinctrl\n"); + + return 0; +} + +static int mt7988_phy_probe_shared(struct phy_device *phydev) +{ + struct device_node *np = dev_of_node(&phydev->mdio.bus->dev); + struct mtk_socphy_shared *shared = phydev->shared->priv; + struct regmap *regmap; + u32 reg; + int ret; + + /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B, + * LED_C and LED_D respectively. At the same time those pins are used to + * bootstrap configuration of the reference clock source (LED_A), + * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D). + * In practice this is done using a LED and a resistor pulling the pin + * either to GND or to VIO. + * The detected value at boot time is accessible at run-time using the + * TPBANK0 register located in the gpio base of the pinctrl, in order + * to read it here it needs to be referenced by a phandle called + * 'mediatek,pio' in the MDIO bus hosting the PHY. + * The 4 bits in TPBANK0 are kept as package shared data and are used to + * set LED polarity for each of the LED0. + */ + regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio"); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®); + if (ret) + return ret; + + shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg); + + return 0; +} + +static int mt7988_phy_probe(struct phy_device *phydev) +{ + struct mtk_socphy_shared *shared; + struct mtk_socphy_priv *priv; + int err; + + if (phydev->mdio.addr > 3) + return -EINVAL; + + err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0, + sizeof(struct mtk_socphy_shared)); + if (err) + return err; + + if (phy_package_probe_once(phydev)) { + err = mt7988_phy_probe_shared(phydev); + if (err) + return err; + } + + shared = phydev->shared->priv; + priv = &shared->priv[phydev->mdio.addr]; + + phydev->priv = priv; + + mtk_phy_leds_state_init(phydev); + + err = mt7988_phy_fix_leds_polarities(phydev); + if (err) + return err; + + /* Disable TX power saving at probing to: + * 1. Meet common mode compliance test criteria + * 2. Make sure that TX-VCM calibration works fine + */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, + MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); + + return mt798x_phy_calibration(phydev); +} + +static int mt7981_phy_probe(struct phy_device *phydev) +{ + struct mtk_socphy_priv *priv; + + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(struct mtk_socphy_priv), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + mtk_phy_leds_state_init(phydev); + + return mt798x_phy_calibration(phydev); +} + +static struct phy_driver mtk_socphy_driver[] = { + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981), + .name = "MediaTek MT7981 PHY", + .config_init = mt798x_phy_config_init, + .config_intr = genphy_no_config_intr, + .handle_interrupt = genphy_handle_interrupt_no_ack, + .probe = mt7981_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, + .led_blink_set = mt798x_phy_led_blink_set, + .led_brightness_set = mt798x_phy_led_brightness_set, + .led_hw_is_supported = mt798x_phy_led_hw_is_supported, + .led_hw_control_set = mt798x_phy_led_hw_control_set, + .led_hw_control_get = mt798x_phy_led_hw_control_get, + }, + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988), + .name = "MediaTek MT7988 PHY", + .config_init = mt798x_phy_config_init, + .config_intr = genphy_no_config_intr, + .handle_interrupt = genphy_handle_interrupt_no_ack, + .probe = mt7988_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, + .led_blink_set = mt798x_phy_led_blink_set, + .led_brightness_set = mt798x_phy_led_brightness_set, + .led_hw_is_supported = mt798x_phy_led_hw_is_supported, + .led_hw_control_set = mt798x_phy_led_hw_control_set, + .led_hw_control_get = mt798x_phy_led_hw_control_get, + }, +}; + +module_phy_driver(mtk_socphy_driver); + +static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, + { } +}; + +MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver"); +MODULE_AUTHOR("Daniel Golle "); +MODULE_AUTHOR("SkyLake Huang "); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl); diff --git a/drivers/net/phy/mediatek/mtk-ge.c b/drivers/net/phy/mediatek/mtk-ge.c new file mode 100644 index 00000000000000..ed2617bc20f493 --- /dev/null +++ b/drivers/net/phy/mediatek/mtk-ge.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include +#include +#include + +#include "mtk.h" + +#define MTK_GPHY_ID_MT7530 0x03a29412 +#define MTK_GPHY_ID_MT7531 0x03a29441 + +#define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_STANDARD 0x0000 +#define MTK_PHY_PAGE_EXTENDED 0x0001 +#define MTK_PHY_PAGE_EXTENDED_2 0x0002 +#define MTK_PHY_PAGE_EXTENDED_3 0x0003 +#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 +#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + +static void mtk_gephy_config_init(struct phy_device *phydev) +{ + /* Enable HW auto downshift */ + phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4)); + + /* Increase SlvDPSready time */ + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + __phy_write(phydev, 0x10, 0xafae); + __phy_write(phydev, 0x12, 0x2f); + __phy_write(phydev, 0x10, 0x8fae); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* Adjust 100_mse_threshold */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff); + + /* Disable mcc */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300); +} + +static int mt7530_phy_config_init(struct phy_device *phydev) +{ + mtk_gephy_config_init(phydev); + + /* Increase post_update_timer */ + phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b); + + return 0; +} + +static int mt7531_phy_config_init(struct phy_device *phydev) +{ + mtk_gephy_config_init(phydev); + + /* PHY link down power saving enable */ + phy_set_bits(phydev, 0x17, BIT(4)); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300); + + /* Set TX Pair delay selection */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404); + phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404); + + return 0; +} + +static struct phy_driver mtk_gephy_driver[] = { + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530), + .name = "MediaTek MT7530 PHY", + .config_init = mt7530_phy_config_init, + /* Interrupts are handled by the switch, not the PHY + * itself. + */ + .config_intr = genphy_no_config_intr, + .handle_interrupt = genphy_handle_interrupt_no_ack, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, + }, + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531), + .name = "MediaTek MT7531 PHY", + .config_init = mt7531_phy_config_init, + /* Interrupts are handled by the switch, not the PHY + * itself. + */ + .config_intr = genphy_no_config_intr, + .handle_interrupt = genphy_handle_interrupt_no_ack, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, + }, +}; + +module_phy_driver(mtk_gephy_driver); + +static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7530) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7531) }, + { } +}; + +MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver"); +MODULE_AUTHOR("DENG, Qingfang "); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl); diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c new file mode 100644 index 00000000000000..98a09d670e9ca5 --- /dev/null +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include + +#include "mtk.h" + +int mtk_phy_read_page(struct phy_device *phydev) +{ + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +} +EXPORT_SYMBOL_GPL(mtk_phy_read_page); + +int mtk_phy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); +} +EXPORT_SYMBOL_GPL(mtk_phy_write_page); + +int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules, + unsigned long supported_triggers) +{ + if (index > 1) + return -EINVAL; + + /* All combinations of the supported triggers are allowed */ + if (rules & ~supported_triggers) + return -EOPNOTSUPP; + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported); + +int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, + unsigned long *rules, u16 on_set, + u16 rx_blink_set, u16 tx_blink_set) +{ + unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + + (index ? 16 : 0); + unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); + unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + int on, blink; + + if (index > 1) + return -EINVAL; + + on = phy_read_mmd(phydev, MDIO_MMD_VEND2, + index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL); + + if (on < 0) + return -EIO; + + blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, + index ? MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL); + if (blink < 0) + return -EIO; + + if ((on & (on_set | MTK_PHY_LED_ON_FDX | + MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) || + (blink & (rx_blink_set | tx_blink_set))) + set_bit(bit_netdev, &priv->led_state); + else + clear_bit(bit_netdev, &priv->led_state); + + if (on & MTK_PHY_LED_ON_FORCE_ON) + set_bit(bit_on, &priv->led_state); + else + clear_bit(bit_on, &priv->led_state); + + if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK) + set_bit(bit_blink, &priv->led_state); + else + clear_bit(bit_blink, &priv->led_state); + + if (!rules) + return 0; + + if (on & on_set) + *rules |= BIT(TRIGGER_NETDEV_LINK); + + if (on & MTK_PHY_LED_ON_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); + + if (on & MTK_PHY_LED_ON_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); + + if (on & MTK_PHY_LED_ON_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); + + if (on & MTK_PHY_LED_ON_LINK2500) + *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + + if (on & MTK_PHY_LED_ON_FDX) + *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); + + if (on & MTK_PHY_LED_ON_HDX) + *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); + + if (blink & rx_blink_set) + *rules |= BIT(TRIGGER_NETDEV_RX); + + if (blink & tx_blink_set) + *rules |= BIT(TRIGGER_NETDEV_TX); + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get); + +int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, + unsigned long rules, u16 on_set, + u16 rx_blink_set, u16 tx_blink_set) +{ + unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + u16 on = 0, blink = 0; + int ret; + + if (index > 1) + return -EINVAL; + + if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) + on |= MTK_PHY_LED_ON_FDX; + + if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) + on |= MTK_PHY_LED_ON_HDX; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK10; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK100; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK1000; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK2500; + + if (rules & BIT(TRIGGER_NETDEV_RX)) { + if (on & on_set) { + if (on & MTK_PHY_LED_ON_LINK10) + blink |= MTK_PHY_LED_BLINK_10RX; + if (on & MTK_PHY_LED_ON_LINK100) + blink |= MTK_PHY_LED_BLINK_100RX; + if (on & MTK_PHY_LED_ON_LINK1000) + blink |= MTK_PHY_LED_BLINK_1000RX; + if (on & MTK_PHY_LED_ON_LINK2500) + blink |= MTK_PHY_LED_BLINK_2500RX; + } else { + blink |= rx_blink_set; + } + } + + if (rules & BIT(TRIGGER_NETDEV_TX)) { + if (on & on_set) { + if (on & MTK_PHY_LED_ON_LINK10) + blink |= MTK_PHY_LED_BLINK_10TX; + if (on & MTK_PHY_LED_ON_LINK100) + blink |= MTK_PHY_LED_BLINK_100TX; + if (on & MTK_PHY_LED_ON_LINK1000) + blink |= MTK_PHY_LED_BLINK_1000TX; + if (on & MTK_PHY_LED_ON_LINK2500) + blink |= MTK_PHY_LED_BLINK_2500TX; + } else { + blink |= tx_blink_set; + } + } + + if (blink || on) + set_bit(bit_netdev, &priv->led_state); + else + clear_bit(bit_netdev, &priv->led_state); + + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set, + on); + + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL, blink); +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set); + +int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on, + unsigned long *delay_off, bool *blinking) +{ + if (index > 1) + return -EINVAL; + + if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) { + *blinking = true; + *delay_on = 50; + *delay_off = 50; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg); + +int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index, + u16 led_on_mask, bool on) +{ + unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + bool changed; + + if (on) + changed = !test_and_set_bit(bit_on, &priv->led_state); + else + changed = !!test_and_clear_bit(bit_on, &priv->led_state); + + changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV + + (index ? 16 : 0), &priv->led_state); + if (changed) + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_ON_CTRL : + MTK_PHY_LED0_ON_CTRL, + led_on_mask, + on ? MTK_PHY_LED_ON_FORCE_ON : 0); + else + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set); + +int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, bool blinking) +{ + unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + + (index ? 16 : 0); + struct mtk_socphy_priv *priv = phydev->priv; + bool changed; + + if (blinking) + changed = !test_and_set_bit(bit_blink, &priv->led_state); + else + changed = !!test_and_clear_bit(bit_blink, &priv->led_state); + + changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV + + (index ? 16 : 0), &priv->led_state); + if (changed) + return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL, + blinking ? + MTK_PHY_LED_BLINK_FORCE_BLINK : 0); + else + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set); + +void mtk_phy_leds_state_init(struct phy_device *phydev) +{ + int i; + + for (i = 0; i < 2; ++i) + phydev->drv->led_hw_control_get(phydev, i, NULL); +} +EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init); + +MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common"); +MODULE_AUTHOR("Sky Huang "); +MODULE_AUTHOR("Daniel Golle "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/mediatek/mtk.h b/drivers/net/phy/mediatek/mtk.h new file mode 100644 index 00000000000000..63d9fe179b8fd9 --- /dev/null +++ b/drivers/net/phy/mediatek/mtk.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Common definition for Mediatek Ethernet PHYs + * Author: SkyLake Huang + * Copyright (c) 2024 MediaTek Inc. + */ + +#ifndef _MTK_EPHY_H_ +#define _MTK_EPHY_H_ + +#define MTK_EXT_PAGE_ACCESS 0x1f + +/* Registers on MDIO_MMD_VEND2 */ +#define MTK_PHY_LED0_ON_CTRL 0x24 +#define MTK_PHY_LED1_ON_CTRL 0x26 +#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0) +#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0) +#define MTK_PHY_LED_ON_LINK1000 BIT(0) +#define MTK_PHY_LED_ON_LINK100 BIT(1) +#define MTK_PHY_LED_ON_LINK10 BIT(2) +#define MTK_PHY_LED_ON_LINKDOWN BIT(3) +#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */ +#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */ +#define MTK_PHY_LED_ON_FORCE_ON BIT(6) +#define MTK_PHY_LED_ON_LINK2500 BIT(7) +#define MTK_PHY_LED_ON_POLARITY BIT(14) +#define MTK_PHY_LED_ON_ENABLE BIT(15) + +#define MTK_PHY_LED0_BLINK_CTRL 0x25 +#define MTK_PHY_LED1_BLINK_CTRL 0x27 +#define MTK_PHY_LED_BLINK_1000TX BIT(0) +#define MTK_PHY_LED_BLINK_1000RX BIT(1) +#define MTK_PHY_LED_BLINK_100TX BIT(2) +#define MTK_PHY_LED_BLINK_100RX BIT(3) +#define MTK_PHY_LED_BLINK_10TX BIT(4) +#define MTK_PHY_LED_BLINK_10RX BIT(5) +#define MTK_PHY_LED_BLINK_COLLISION BIT(6) +#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7) +#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) +#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9) +#define MTK_PHY_LED_BLINK_2500TX BIT(10) +#define MTK_PHY_LED_BLINK_2500RX BIT(11) + +#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \ + MTK_PHY_LED_ON_LINK100 | \ + MTK_PHY_LED_ON_LINK10) +#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ + MTK_PHY_LED_BLINK_100RX | \ + MTK_PHY_LED_BLINK_10RX) +#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ + MTK_PHY_LED_BLINK_100RX | \ + MTK_PHY_LED_BLINK_10RX) + +#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \ + MTK_GPHY_LED_ON_SET) +#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ + MTK_GPHY_LED_RX_BLINK_SET) +#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ + MTK_GPHY_LED_TX_BLINK_SET) + +#define MTK_PHY_LED_STATE_FORCE_ON 0 +#define MTK_PHY_LED_STATE_FORCE_BLINK 1 +#define MTK_PHY_LED_STATE_NETDEV 2 + +struct mtk_socphy_priv { + unsigned long led_state; +}; + +int mtk_phy_read_page(struct phy_device *phydev); +int mtk_phy_write_page(struct phy_device *phydev, int page); + +int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules, + unsigned long supported_triggers); +int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, + unsigned long rules, u16 on_set, + u16 rx_blink_set, u16 tx_blink_set); +int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, + unsigned long *rules, u16 on_set, + u16 rx_blink_set, u16 tx_blink_set); +int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on, + unsigned long *delay_off, bool *blinking); +int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index, + u16 led_on_mask, bool on); +int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, + bool blinking); +void mtk_phy_leds_state_init(struct phy_device *phydev); + +#endif /* _MTK_EPHY_H_ */ diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 65b0a3115e14cd..3ef5088406740c 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -2004,7 +2004,7 @@ static int ksz9477_config_init(struct phy_device *phydev) * in this switch shall be regarded as broken. */ if (phydev->dev_flags & MICREL_NO_EEE) - phydev->eee_broken_modes = -1; + linkmode_fill(phydev->eee_broken_modes); return kszphy_config_init(phydev); } @@ -2018,10 +2018,8 @@ static void kszphy_get_strings(struct phy_device *phydev, u8 *data) { int i; - for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) { - strscpy(data + i * ETH_GSTRING_LEN, - kszphy_hw_stats[i].string, ETH_GSTRING_LEN); - } + for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) + ethtool_puts(&data, kszphy_hw_stats[i].string); } static u64 kszphy_get_stat(struct phy_device *phydev, int i) diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c index d3273bc0da4a1f..691969a4910f2b 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c @@ -351,6 +351,22 @@ static int lan88xx_config_aneg(struct phy_device *phydev) static void lan88xx_link_change_notify(struct phy_device *phydev) { int temp; + int ret; + + /* Reset PHY to ensure MII_LPA provides up-to-date information. This + * issue is reproducible only after parallel detection, as described + * in IEEE 802.3-2022, Section 28.2.3.1 ("Parallel detection function"), + * where the link partner does not support auto-negotiation. + */ + if (phydev->state == PHY_NOLINK) { + ret = phy_init_hw(phydev); + if (ret < 0) + goto link_change_notify_failed; + + ret = _phy_start_aneg(phydev); + if (ret < 0) + goto link_change_notify_failed; + } /* At forced 100 F/H mode, chip may fail to set mode correctly * when cable is switched between long(~50+m) and short one. @@ -377,6 +393,11 @@ static void lan88xx_link_change_notify(struct phy_device *phydev) temp |= LAN88XX_INT_MASK_MDINTPIN_EN_; phy_write(phydev, LAN88XX_INT_MASK, temp); } + + return; + +link_change_notify_failed: + phydev_err(phydev, "Link change process failed %pe\n", ERR_PTR(ret)); } /** diff --git a/drivers/net/phy/microchip_t1.c b/drivers/net/phy/microchip_t1.c index a5ef8fe5070467..b17bf6708003e0 100644 --- a/drivers/net/phy/microchip_t1.c +++ b/drivers/net/phy/microchip_t1.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -226,6 +227,47 @@ #define MICROCHIP_CABLE_MAX_TIME_DIFF \ (MICROCHIP_CABLE_MIN_TIME_DIFF + MICROCHIP_CABLE_TIME_MARGIN) +#define LAN887X_INT_STS 0xf000 +#define LAN887X_INT_MSK 0xf001 +#define LAN887X_INT_MSK_T1_PHY_INT_MSK BIT(2) +#define LAN887X_INT_MSK_LINK_UP_MSK BIT(1) +#define LAN887X_INT_MSK_LINK_DOWN_MSK BIT(0) + +#define LAN887X_MX_CHIP_TOP_LINK_MSK (LAN887X_INT_MSK_LINK_UP_MSK |\ + LAN887X_INT_MSK_LINK_DOWN_MSK) + +#define LAN887X_MX_CHIP_TOP_ALL_MSK (LAN887X_INT_MSK_T1_PHY_INT_MSK |\ + LAN887X_MX_CHIP_TOP_LINK_MSK) + +#define LAN887X_COEFF_PWR_DN_CONFIG_100 0x0404 +#define LAN887X_COEFF_PWR_DN_CONFIG_100_V 0x16d6 +#define LAN887X_SQI_CONFIG_100 0x042e +#define LAN887X_SQI_CONFIG_100_V 0x9572 +#define LAN887X_SQI_MSE_100 0x483 + +#define LAN887X_POKE_PEEK_100 0x040d +#define LAN887X_POKE_PEEK_100_EN BIT(0) + +#define LAN887X_COEFF_MOD_CONFIG 0x080d +#define LAN887X_COEFF_MOD_CONFIG_DCQ_COEFF_EN BIT(8) + +#define LAN887X_DCQ_SQI_STATUS 0x08b2 + +/* SQI raw samples count */ +#define SQI_SAMPLES 200 + +/* Samples percentage considered for SQI calculation */ +#define SQI_INLINERS_PERCENT 60 + +/* Samples count considered for SQI calculation */ +#define SQI_INLIERS_NUM (SQI_SAMPLES * SQI_INLINERS_PERCENT / 100) + +/* Start offset of samples */ +#define SQI_INLIERS_START ((SQI_SAMPLES - SQI_INLIERS_NUM) / 2) + +/* End offset of samples */ +#define SQI_INLIERS_END (SQI_INLIERS_START + SQI_INLIERS_NUM) + #define DRIVER_AUTHOR "Nisar Sayed " #define DRIVER_DESC "Microchip LAN87XX/LAN937x/LAN887x T1 PHY driver" @@ -1474,6 +1516,49 @@ static void lan887x_get_strings(struct phy_device *phydev, u8 *data) ethtool_puts(&data, lan887x_hw_stats[i].string); } +static int lan887x_config_intr(struct phy_device *phydev) +{ + int rc; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Clear the interrupt status before enabling interrupts */ + rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_INT_STS); + if (rc < 0) + return rc; + + /* Unmask for enabling interrupt */ + rc = phy_write_mmd(phydev, MDIO_MMD_VEND1, LAN887X_INT_MSK, + (u16)~LAN887X_MX_CHIP_TOP_ALL_MSK); + } else { + rc = phy_write_mmd(phydev, MDIO_MMD_VEND1, LAN887X_INT_MSK, + GENMASK(15, 0)); + if (rc < 0) + return rc; + + rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_INT_STS); + } + + return rc < 0 ? rc : 0; +} + +static irqreturn_t lan887x_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_INT_STS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (irq_status & LAN887X_MX_CHIP_TOP_LINK_MSK) { + phy_trigger_machine(phydev); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + static int lan887x_cd_reset(struct phy_device *phydev, enum cable_diag_state cd_done) { @@ -1504,6 +1589,10 @@ static int lan887x_cd_reset(struct phy_device *phydev, if (rc < 0) return rc; + rc = lan887x_config_intr(phydev); + if (rc < 0) + return rc; + rc = lan887x_phy_reconfig(phydev); if (rc < 0) return rc; @@ -1830,6 +1919,145 @@ static int lan887x_cable_test_get_status(struct phy_device *phydev, return lan887x_cable_test_report(phydev); } +/* Compare block to sort in ascending order */ +static int sqi_compare(const void *a, const void *b) +{ + return *(u16 *)a - *(u16 *)b; +} + +static int lan887x_get_sqi_100M(struct phy_device *phydev) +{ + u16 rawtable[SQI_SAMPLES]; + u32 sqiavg = 0; + u8 sqinum = 0; + int rc, i; + + /* Configuration of SQI 100M */ + rc = phy_write_mmd(phydev, MDIO_MMD_VEND1, + LAN887X_COEFF_PWR_DN_CONFIG_100, + LAN887X_COEFF_PWR_DN_CONFIG_100_V); + if (rc < 0) + return rc; + + rc = phy_write_mmd(phydev, MDIO_MMD_VEND1, LAN887X_SQI_CONFIG_100, + LAN887X_SQI_CONFIG_100_V); + if (rc < 0) + return rc; + + rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_SQI_CONFIG_100); + if (rc != LAN887X_SQI_CONFIG_100_V) + return -EINVAL; + + rc = phy_modify_mmd(phydev, MDIO_MMD_VEND1, LAN887X_POKE_PEEK_100, + LAN887X_POKE_PEEK_100_EN, + LAN887X_POKE_PEEK_100_EN); + if (rc < 0) + return rc; + + /* Required before reading register + * otherwise it will return high value + */ + msleep(50); + + /* Link check before raw readings */ + rc = genphy_c45_read_link(phydev); + if (rc < 0) + return rc; + + if (!phydev->link) + return -ENETDOWN; + + /* Get 200 SQI raw readings */ + for (i = 0; i < SQI_SAMPLES; i++) { + rc = phy_write_mmd(phydev, MDIO_MMD_VEND1, + LAN887X_POKE_PEEK_100, + LAN887X_POKE_PEEK_100_EN); + if (rc < 0) + return rc; + + rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, + LAN887X_SQI_MSE_100); + if (rc < 0) + return rc; + + rawtable[i] = (u16)rc; + } + + /* Link check after raw readings */ + rc = genphy_c45_read_link(phydev); + if (rc < 0) + return rc; + + if (!phydev->link) + return -ENETDOWN; + + /* Sort SQI raw readings in ascending order */ + sort(rawtable, SQI_SAMPLES, sizeof(u16), sqi_compare, NULL); + + /* Keep inliers and discard outliers */ + for (i = SQI_INLIERS_START; i < SQI_INLIERS_END; i++) + sqiavg += rawtable[i]; + + /* Handle invalid samples */ + if (sqiavg != 0) { + /* Get SQI average */ + sqiavg /= SQI_INLIERS_NUM; + + if (sqiavg < 75) + sqinum = 7; + else if (sqiavg < 94) + sqinum = 6; + else if (sqiavg < 119) + sqinum = 5; + else if (sqiavg < 150) + sqinum = 4; + else if (sqiavg < 189) + sqinum = 3; + else if (sqiavg < 237) + sqinum = 2; + else if (sqiavg < 299) + sqinum = 1; + else + sqinum = 0; + } + + return sqinum; +} + +static int lan887x_get_sqi(struct phy_device *phydev) +{ + int rc, val; + + if (phydev->speed != SPEED_1000 && + phydev->speed != SPEED_100) + return -ENETDOWN; + + if (phydev->speed == SPEED_100) + return lan887x_get_sqi_100M(phydev); + + /* Writing DCQ_COEFF_EN to trigger a SQI read */ + rc = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + LAN887X_COEFF_MOD_CONFIG, + LAN887X_COEFF_MOD_CONFIG_DCQ_COEFF_EN); + if (rc < 0) + return rc; + + /* Wait for DCQ done */ + rc = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + LAN887X_COEFF_MOD_CONFIG, val, ((val & + LAN887X_COEFF_MOD_CONFIG_DCQ_COEFF_EN) != + LAN887X_COEFF_MOD_CONFIG_DCQ_COEFF_EN), + 10, 200, true); + if (rc < 0) + return rc; + + rc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_DCQ_SQI_STATUS); + if (rc < 0) + return rc; + + return FIELD_GET(T1_DCQ_SQI_MSK, rc); +} + static struct phy_driver microchip_t1_phy_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX), @@ -1881,6 +2109,11 @@ static struct phy_driver microchip_t1_phy_driver[] = { .read_status = genphy_c45_read_status, .cable_test_start = lan887x_cable_test_start, .cable_test_get_status = lan887x_cable_test_get_status, + .config_intr = lan887x_config_intr, + .handle_interrupt = lan887x_handle_interrupt, + .get_sqi = lan887x_get_sqi, + .get_sqi_max = lan87xx_get_sqi_max, + .set_loopback = genphy_c45_loopback, } }; diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c index 3614839a8e5191..75d291154b4cdb 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -3,8 +3,8 @@ * Driver for Microchip 10BASE-T1S PHYs * * Support: Microchip Phys: - * lan8670/1/2 Rev.B1 - * lan8650/1 Rev.B0 Internal PHYs + * lan8670/1/2 Rev.B1/C1/C2 + * lan8650/1 Rev.B0/B1 Internal PHYs */ #include @@ -12,7 +12,10 @@ #include #define PHY_ID_LAN867X_REVB1 0x0007C162 -#define PHY_ID_LAN865X_REVB0 0x0007C1B3 +#define PHY_ID_LAN867X_REVC1 0x0007C164 +#define PHY_ID_LAN867X_REVC2 0x0007C165 +/* Both Rev.B0 and B1 clause 22 PHYID's are same due to B1 chip limitation */ +#define PHY_ID_LAN865X_REVB 0x0007C1B3 #define LAN867X_REG_STS2 0x0019 @@ -23,6 +26,12 @@ #define LAN865X_REG_CFGPARAM_CTRL 0x00DA #define LAN865X_REG_STS2 0x0019 +/* Collision Detector Control 0 Register */ +#define LAN86XX_REG_COL_DET_CTRL0 0x0087 +#define COL_DET_CTRL0_ENABLE_BIT_MASK BIT(15) +#define COL_DET_ENABLE BIT(15) +#define COL_DET_DISABLE 0x0000 + #define LAN865X_CFGPARAM_READ_ENABLE BIT(1) /* The arrays below are pulled from the following table from AN1699 @@ -59,29 +68,45 @@ static const u16 lan867x_revb1_fixup_masks[12] = { 0x0600, 0x7F00, 0x2000, 0xFFFF, }; -/* LAN865x Rev.B0 configuration parameters from AN1760 */ -static const u32 lan865x_revb0_fixup_registers[28] = { - 0x0091, 0x0081, 0x0043, 0x0044, - 0x0045, 0x0053, 0x0054, 0x0055, - 0x0040, 0x0050, 0x00D0, 0x00E9, - 0x00F5, 0x00F4, 0x00F8, 0x00F9, +/* LAN865x Rev.B0/B1 configuration parameters from AN1760 + * As per the Configuration Application Note AN1760 published in the below link, + * https://www.microchip.com/en-us/application-notes/an1760 + * Revision F (DS60001760G - June 2024) + */ +static const u32 lan865x_revb_fixup_registers[17] = { + 0x00D0, 0x00E0, 0x00E9, 0x00F5, + 0x00F4, 0x00F8, 0x00F9, 0x0081, + 0x0091, 0x0043, 0x0044, 0x0045, + 0x0053, 0x0054, 0x0055, 0x0040, + 0x0050, +}; + +static const u16 lan865x_revb_fixup_values[17] = { + 0x3F31, 0xC000, 0x9E50, 0x1CF8, + 0xC020, 0xB900, 0x4E53, 0x0080, + 0x9660, 0x00FF, 0xFFFF, 0x0000, + 0x00FF, 0xFFFF, 0x0000, 0x0002, + 0x0002, +}; + +static const u16 lan865x_revb_fixup_cfg_regs[2] = { + 0x0084, 0x008A, +}; + +static const u32 lan865x_revb_sqi_fixup_regs[12] = { 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, }; -static const u16 lan865x_revb0_fixup_values[28] = { - 0x9660, 0x00C0, 0x00FF, 0xFFFF, - 0x0000, 0x00FF, 0xFFFF, 0x0000, - 0x0002, 0x0002, 0x5F21, 0x9E50, - 0x1CF8, 0xC020, 0x9B00, 0x4E53, +static const u16 lan865x_revb_sqi_fixup_values[12] = { 0x0103, 0x0910, 0x1D26, 0x002A, 0x0103, 0x070D, 0x1720, 0x0027, 0x0509, 0x0E13, 0x1C25, 0x002B, }; -static const u16 lan865x_revb0_fixup_cfg_regs[5] = { - 0x0084, 0x008A, 0x00AD, 0x00AE, 0x00AF +static const u16 lan865x_revb_sqi_fixup_cfg_regs[3] = { + 0x00AD, 0x00AE, 0x00AF, }; /* Pulled from AN1760 describing 'indirect read' @@ -92,7 +117,7 @@ static const u16 lan865x_revb0_fixup_cfg_regs[5] = { * * 0x4 refers to memory map selector 4, which maps to MDIO_MMD_VEND2 */ -static int lan865x_revb0_indirect_read(struct phy_device *phydev, u16 addr) +static int lan865x_revb_indirect_read(struct phy_device *phydev, u16 addr) { int ret; @@ -112,15 +137,18 @@ static int lan865x_revb0_indirect_read(struct phy_device *phydev, u16 addr) /* This is pulled straight from AN1760 from 'calculation of offset 1' & * 'calculation of offset 2' */ -static int lan865x_generate_cfg_offsets(struct phy_device *phydev, s8 offsets[2]) +static int lan865x_generate_cfg_offsets(struct phy_device *phydev, s8 offsets[]) { const u16 fixup_regs[2] = {0x0004, 0x0008}; int ret; for (int i = 0; i < ARRAY_SIZE(fixup_regs); i++) { - ret = lan865x_revb0_indirect_read(phydev, fixup_regs[i]); + ret = lan865x_revb_indirect_read(phydev, fixup_regs[i]); if (ret < 0) return ret; + + /* 5-bit signed value, sign extend */ + ret &= GENMASK(4, 0); if (ret & BIT(4)) offsets[i] = ret | 0xE0; else @@ -130,13 +158,15 @@ static int lan865x_generate_cfg_offsets(struct phy_device *phydev, s8 offsets[2] return 0; } -static int lan865x_read_cfg_params(struct phy_device *phydev, u16 cfg_params[]) +static int lan865x_read_cfg_params(struct phy_device *phydev, + const u16 cfg_regs[], u16 cfg_params[], + u8 count) { int ret; - for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs); i++) { + for (int i = 0; i < count; i++) { ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, - lan865x_revb0_fixup_cfg_regs[i]); + cfg_regs[i]); if (ret < 0) return ret; cfg_params[i] = (u16)ret; @@ -145,13 +175,14 @@ static int lan865x_read_cfg_params(struct phy_device *phydev, u16 cfg_params[]) return 0; } -static int lan865x_write_cfg_params(struct phy_device *phydev, u16 cfg_params[]) +static int lan865x_write_cfg_params(struct phy_device *phydev, + const u16 cfg_regs[], u16 cfg_params[], + u8 count) { int ret; - for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs); i++) { - ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, - lan865x_revb0_fixup_cfg_regs[i], + for (int i = 0; i < count; i++) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, cfg_regs[i], cfg_params[i]); if (ret) return ret; @@ -160,60 +191,90 @@ static int lan865x_write_cfg_params(struct phy_device *phydev, u16 cfg_params[]) return 0; } -static int lan865x_setup_cfgparam(struct phy_device *phydev) +static int lan865x_setup_cfgparam(struct phy_device *phydev, s8 offsets[]) { - u16 cfg_params[ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs)]; - u16 cfg_results[5]; - s8 offsets[2]; + u16 cfg_results[ARRAY_SIZE(lan865x_revb_fixup_cfg_regs)]; + u16 cfg_params[ARRAY_SIZE(lan865x_revb_fixup_cfg_regs)]; int ret; - ret = lan865x_generate_cfg_offsets(phydev, offsets); + ret = lan865x_read_cfg_params(phydev, lan865x_revb_fixup_cfg_regs, + cfg_params, ARRAY_SIZE(cfg_params)); if (ret) return ret; - ret = lan865x_read_cfg_params(phydev, cfg_params); + cfg_results[0] = FIELD_PREP(GENMASK(15, 10), 9 + offsets[0]) | + FIELD_PREP(GENMASK(9, 4), 14 + offsets[0]) | + 0x03; + cfg_results[1] = FIELD_PREP(GENMASK(15, 10), 40 + offsets[1]); + + return lan865x_write_cfg_params(phydev, lan865x_revb_fixup_cfg_regs, + cfg_results, ARRAY_SIZE(cfg_results)); +} + +static int lan865x_setup_sqi_cfgparam(struct phy_device *phydev, s8 offsets[]) +{ + u16 cfg_results[ARRAY_SIZE(lan865x_revb_sqi_fixup_cfg_regs)]; + u16 cfg_params[ARRAY_SIZE(lan865x_revb_sqi_fixup_cfg_regs)]; + int ret; + + ret = lan865x_read_cfg_params(phydev, lan865x_revb_sqi_fixup_cfg_regs, + cfg_params, ARRAY_SIZE(cfg_params)); if (ret) return ret; - cfg_results[0] = (cfg_params[0] & 0x000F) | - FIELD_PREP(GENMASK(15, 10), 9 + offsets[0]) | - FIELD_PREP(GENMASK(15, 4), 14 + offsets[0]); - cfg_results[1] = (cfg_params[1] & 0x03FF) | - FIELD_PREP(GENMASK(15, 10), 40 + offsets[1]); - cfg_results[2] = (cfg_params[2] & 0xC0C0) | - FIELD_PREP(GENMASK(15, 8), 5 + offsets[0]) | - (9 + offsets[0]); - cfg_results[3] = (cfg_params[3] & 0xC0C0) | - FIELD_PREP(GENMASK(15, 8), 9 + offsets[0]) | - (14 + offsets[0]); - cfg_results[4] = (cfg_params[4] & 0xC0C0) | - FIELD_PREP(GENMASK(15, 8), 17 + offsets[0]) | - (22 + offsets[0]); - - return lan865x_write_cfg_params(phydev, cfg_results); + cfg_results[0] = FIELD_PREP(GENMASK(13, 8), 5 + offsets[0]) | + (9 + offsets[0]); + cfg_results[1] = FIELD_PREP(GENMASK(13, 8), 9 + offsets[0]) | + (14 + offsets[0]); + cfg_results[2] = FIELD_PREP(GENMASK(13, 8), 17 + offsets[0]) | + (22 + offsets[0]); + + return lan865x_write_cfg_params(phydev, lan865x_revb_sqi_fixup_cfg_regs, + cfg_results, ARRAY_SIZE(cfg_results)); } -static int lan865x_revb0_config_init(struct phy_device *phydev) +static int lan865x_revb_config_init(struct phy_device *phydev) { + s8 offsets[2]; int ret; /* Reference to AN1760 * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8650-1-Configuration-60001760.pdf */ - for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_registers); i++) { + ret = lan865x_generate_cfg_offsets(phydev, offsets); + if (ret) + return ret; + + for (int i = 0; i < ARRAY_SIZE(lan865x_revb_fixup_registers); i++) { ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, - lan865x_revb0_fixup_registers[i], - lan865x_revb0_fixup_values[i]); + lan865x_revb_fixup_registers[i], + lan865x_revb_fixup_values[i]); if (ret) return ret; + + if (i == 1) { + ret = lan865x_setup_cfgparam(phydev, offsets); + if (ret) + return ret; + } } - /* Function to calculate and write the configuration parameters in the - * 0x0084, 0x008A, 0x00AD, 0x00AE and 0x00AF registers (from AN1760) - */ - return lan865x_setup_cfgparam(phydev); + + ret = lan865x_setup_sqi_cfgparam(phydev, offsets); + if (ret) + return ret; + + for (int i = 0; i < ARRAY_SIZE(lan865x_revb_sqi_fixup_regs); i++) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + lan865x_revb_sqi_fixup_regs[i], + lan865x_revb_sqi_fixup_values[i]); + if (ret) + return ret; + } + + return 0; } -static int lan867x_revb1_config_init(struct phy_device *phydev) +static int lan867x_check_reset_complete(struct phy_device *phydev) { int err; @@ -235,6 +296,69 @@ static int lan867x_revb1_config_init(struct phy_device *phydev) } } + return 0; +} + +static int lan867x_revc_config_init(struct phy_device *phydev) +{ + s8 offsets[2]; + int ret; + + ret = lan867x_check_reset_complete(phydev); + if (ret) + return ret; + + ret = lan865x_generate_cfg_offsets(phydev, offsets); + if (ret) + return ret; + + /* LAN867x Rev.C1/C2 configuration settings are equal to the first 9 + * configuration settings and all the sqi fixup settings from LAN865x + * Rev.B0/B1. So the same fixup registers and values from LAN865x + * Rev.B0/B1 are used for LAN867x Rev.C1/C2 to avoid duplication. + * Refer the below links for the comparison. + * https://www.microchip.com/en-us/application-notes/an1760 + * Revision F (DS60001760G - June 2024) + * https://www.microchip.com/en-us/application-notes/an1699 + * Revision E (DS60001699F - June 2024) + */ + for (int i = 0; i < 9; i++) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + lan865x_revb_fixup_registers[i], + lan865x_revb_fixup_values[i]); + if (ret) + return ret; + + if (i == 1) { + ret = lan865x_setup_cfgparam(phydev, offsets); + if (ret) + return ret; + } + } + + ret = lan865x_setup_sqi_cfgparam(phydev, offsets); + if (ret) + return ret; + + for (int i = 0; i < ARRAY_SIZE(lan865x_revb_sqi_fixup_regs); i++) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + lan865x_revb_sqi_fixup_regs[i], + lan865x_revb_sqi_fixup_values[i]); + if (ret) + return ret; + } + + return 0; +} + +static int lan867x_revb1_config_init(struct phy_device *phydev) +{ + int err; + + err = lan867x_check_reset_complete(phydev); + if (err) + return err; + /* Reference to AN1699 * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8670-1-2-config-60001699.pdf * AN1699 says Read, Modify, Write, but the Write is not required if the @@ -253,6 +377,36 @@ static int lan867x_revb1_config_init(struct phy_device *phydev) return 0; } +/* As per LAN8650/1 Rev.B0/B1 AN1760 (Revision F (DS60001760G - June 2024)) and + * LAN8670/1/2 Rev.C1/C2 AN1699 (Revision E (DS60001699F - June 2024)), under + * normal operation, the device should be operated in PLCA mode. Disabling + * collision detection is recommended to allow the device to operate in noisy + * environments or when reflections and other inherent transmission line + * distortion cause poor signal quality. Collision detection must be re-enabled + * if the device is configured to operate in CSMA/CD mode. + * + * AN1760: https://www.microchip.com/en-us/application-notes/an1760 + * AN1699: https://www.microchip.com/en-us/application-notes/an1699 + */ +static int lan86xx_plca_set_cfg(struct phy_device *phydev, + const struct phy_plca_cfg *plca_cfg) +{ + int ret; + + ret = genphy_c45_plca_set_cfg(phydev, plca_cfg); + if (ret) + return ret; + + if (plca_cfg->enabled) + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, + LAN86XX_REG_COL_DET_CTRL0, + COL_DET_CTRL0_ENABLE_BIT_MASK, + COL_DET_DISABLE); + + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LAN86XX_REG_COL_DET_CTRL0, + COL_DET_CTRL0_ENABLE_BIT_MASK, COL_DET_ENABLE); +} + static int lan86xx_read_status(struct phy_device *phydev) { /* The phy has some limitations, namely: @@ -308,15 +462,35 @@ static struct phy_driver microchip_t1s_driver[] = { .get_plca_status = genphy_c45_plca_get_status, }, { - PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0), - .name = "LAN865X Rev.B0 Internal Phy", + PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVC1), + .name = "LAN867X Rev.C1", .features = PHY_BASIC_T1S_P2MP_FEATURES, - .config_init = lan865x_revb0_config_init, + .config_init = lan867x_revc_config_init, + .read_status = lan86xx_read_status, + .get_plca_cfg = genphy_c45_plca_get_cfg, + .set_plca_cfg = lan86xx_plca_set_cfg, + .get_plca_status = genphy_c45_plca_get_status, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVC2), + .name = "LAN867X Rev.C2", + .features = PHY_BASIC_T1S_P2MP_FEATURES, + .config_init = lan867x_revc_config_init, + .read_status = lan86xx_read_status, + .get_plca_cfg = genphy_c45_plca_get_cfg, + .set_plca_cfg = lan86xx_plca_set_cfg, + .get_plca_status = genphy_c45_plca_get_status, + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB), + .name = "LAN865X Rev.B0/B1 Internal Phy", + .features = PHY_BASIC_T1S_P2MP_FEATURES, + .config_init = lan865x_revb_config_init, .read_status = lan86xx_read_status, .read_mmd = lan865x_phy_read_mmd, .write_mmd = lan865x_phy_write_mmd, .get_plca_cfg = genphy_c45_plca_get_cfg, - .set_plca_cfg = genphy_c45_plca_set_cfg, + .set_plca_cfg = lan86xx_plca_set_cfg, .get_plca_status = genphy_c45_plca_get_status, }, }; @@ -325,7 +499,9 @@ module_phy_driver(microchip_t1s_driver); static struct mdio_device_id __maybe_unused tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) }, - { PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0) }, + { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVC1) }, + { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVC2) }, + { PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB) }, { } }; diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index 6f74ce0ab1aad8..bee381200ab85c 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -139,8 +139,7 @@ static void vsc85xx_get_strings(struct phy_device *phydev, u8 *data) return; for (i = 0; i < priv->nstats; i++) - strscpy(data + i * ETH_GSTRING_LEN, priv->hw_stats[i].string, - ETH_GSTRING_LEN); + ethtool_puts(&data, priv->hw_stats[i].string); } static u64 vsc85xx_get_stat(struct phy_device *phydev, int i) diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index e5f8ac4b4604bd..a8ccf257c10943 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -38,6 +38,7 @@ #define PHY_MIISTAT 0x18 /* MII state */ #define PHY_IMASK 0x19 /* interrupt mask */ #define PHY_ISTAT 0x1A /* interrupt status */ +#define PHY_LED 0x1B /* LEDs */ #define PHY_FWV 0x1E /* firmware version */ #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0) @@ -61,6 +62,11 @@ PHY_IMASK_ADSC | \ PHY_IMASK_ANC) +#define GPY_MAX_LEDS 4 +#define PHY_LED_POLARITY(idx) BIT(12 + (idx)) +#define PHY_LED_HWCONTROL(idx) BIT(8 + (idx)) +#define PHY_LED_ON(idx) BIT(idx) + #define PHY_FWV_REL_MASK BIT(15) #define PHY_FWV_MAJOR_MASK GENMASK(11, 8) #define PHY_FWV_MINOR_MASK GENMASK(7, 0) @@ -72,6 +78,23 @@ #define PHY_MDI_MDI_X_CD 0x1 #define PHY_MDI_MDI_X_CROSS 0x0 +/* LED */ +#define VSPEC1_LED(idx) (1 + (idx)) +#define VSPEC1_LED_BLINKS GENMASK(15, 12) +#define VSPEC1_LED_PULSE GENMASK(11, 8) +#define VSPEC1_LED_CON GENMASK(7, 4) +#define VSPEC1_LED_BLINKF GENMASK(3, 0) + +#define VSPEC1_LED_LINK10 BIT(0) +#define VSPEC1_LED_LINK100 BIT(1) +#define VSPEC1_LED_LINK1000 BIT(2) +#define VSPEC1_LED_LINK2500 BIT(3) + +#define VSPEC1_LED_TXACT BIT(0) +#define VSPEC1_LED_RXACT BIT(1) +#define VSPEC1_LED_COL BIT(2) +#define VSPEC1_LED_NO_CON BIT(3) + /* SGMII */ #define VSPEC1_SGMII_CTRL 0x08 #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */ @@ -835,6 +858,165 @@ static int gpy115_loopback(struct phy_device *phydev, bool enable) return genphy_soft_reset(phydev); } +static int gpy_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + int ret; + + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + /* clear HWCONTROL and set manual LED state */ + ret = phy_modify(phydev, PHY_LED, + ((value == LED_OFF) ? PHY_LED_HWCONTROL(index) : 0) | + PHY_LED_ON(index), + (value == LED_OFF) ? 0 : PHY_LED_ON(index)); + if (ret) + return ret; + + /* ToDo: set PWM brightness */ + + /* clear HW LED setup */ + if (value == LED_OFF) + return phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), 0); + else + return 0; +} + +static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) | + BIT(TRIGGER_NETDEV_LINK_10) | + BIT(TRIGGER_NETDEV_LINK_100) | + BIT(TRIGGER_NETDEV_LINK_1000) | + BIT(TRIGGER_NETDEV_LINK_2500) | + BIT(TRIGGER_NETDEV_RX) | + BIT(TRIGGER_NETDEV_TX)); + +static int gpy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + /* All combinations of the supported triggers are allowed */ + if (rules & ~supported_triggers) + return -EOPNOTSUPP; + + return 0; +} + +static int gpy_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + int val; + + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + val = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index)); + if (val < 0) + return val; + + if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); + + if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); + + if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); + + if (FIELD_GET(VSPEC1_LED_CON, val) & VSPEC1_LED_LINK2500) + *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + + if (FIELD_GET(VSPEC1_LED_CON, val) == (VSPEC1_LED_LINK10 | + VSPEC1_LED_LINK100 | + VSPEC1_LED_LINK1000 | + VSPEC1_LED_LINK2500)) + *rules |= BIT(TRIGGER_NETDEV_LINK); + + if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_TXACT) + *rules |= BIT(TRIGGER_NETDEV_TX); + + if (FIELD_GET(VSPEC1_LED_PULSE, val) & VSPEC1_LED_RXACT) + *rules |= BIT(TRIGGER_NETDEV_RX); + + return 0; +} + +static int gpy_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 val = 0; + int ret; + + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_10)) + val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK10); + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_100)) + val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK100); + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_1000)) + val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK1000); + + if (rules & BIT(TRIGGER_NETDEV_LINK) || + rules & BIT(TRIGGER_NETDEV_LINK_2500)) + val |= FIELD_PREP(VSPEC1_LED_CON, VSPEC1_LED_LINK2500); + + if (rules & BIT(TRIGGER_NETDEV_TX)) + val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_TXACT); + + if (rules & BIT(TRIGGER_NETDEV_RX)) + val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_RXACT); + + /* allow RX/TX pulse without link indication */ + if ((rules & BIT(TRIGGER_NETDEV_TX) || rules & BIT(TRIGGER_NETDEV_RX)) && + !(val & VSPEC1_LED_CON)) + val |= FIELD_PREP(VSPEC1_LED_PULSE, VSPEC1_LED_NO_CON) | VSPEC1_LED_CON; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(index), val); + if (ret) + return ret; + + return phy_set_bits(phydev, PHY_LED, PHY_LED_HWCONTROL(index)); +} + +static int gpy_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + bool force_active_low = false, force_active_high = false; + u32 mode; + + if (index >= GPY_MAX_LEDS) + return -EINVAL; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + force_active_low = true; + break; + case PHY_LED_ACTIVE_HIGH: + force_active_high = true; + break; + default: + return -EINVAL; + } + } + + if (force_active_low) + return phy_set_bits(phydev, PHY_LED, PHY_LED_POLARITY(index)); + + if (force_active_high) + return phy_clear_bits(phydev, PHY_LED, PHY_LED_POLARITY(index)); + + return -EINVAL; +} + static struct phy_driver gpy_drivers[] = { { PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx), @@ -852,6 +1034,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { .phy_id = PHY_ID_GPY115B, @@ -870,6 +1057,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy115_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY115C), @@ -887,6 +1079,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy115_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { .phy_id = PHY_ID_GPY211B, @@ -905,6 +1102,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY211C), @@ -922,6 +1124,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { .phy_id = PHY_ID_GPY212B, @@ -940,6 +1147,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY212C), @@ -957,6 +1169,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { .phy_id = PHY_ID_GPY215B, @@ -975,6 +1192,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY215C), @@ -992,6 +1214,11 @@ static struct phy_driver gpy_drivers[] = { .set_wol = gpy_set_wol, .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, }, { PHY_ID_MATCH_MODEL(PHY_ID_GPY241B), diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index 5af5ade4fc6418..ade544bc007d25 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -185,6 +186,8 @@ #define NXP_C45_SKB_CB(skb) ((struct nxp_c45_skb_cb *)(skb)->cb) +#define TJA11XX_REVERSE_MODE BIT(0) + struct nxp_c45_phy; struct nxp_c45_skb_cb { @@ -1137,13 +1140,11 @@ static void nxp_c45_get_strings(struct phy_device *phydev, u8 *data) for (i = 0; i < count; i++) { if (i < ARRAY_SIZE(common_hw_stats)) { - strscpy(data + i * ETH_GSTRING_LEN, - common_hw_stats[i].name, ETH_GSTRING_LEN); + ethtool_puts(&data, common_hw_stats[i].name); continue; } idx = i - ARRAY_SIZE(common_hw_stats); - strscpy(data + i * ETH_GSTRING_LEN, - phy_data->stats[idx].name, ETH_GSTRING_LEN); + ethtool_puts(&data, phy_data->stats[idx].name); } } @@ -1510,6 +1511,8 @@ static int nxp_c45_get_delays(struct phy_device *phydev) static int nxp_c45_set_phy_mode(struct phy_device *phydev) { + struct nxp_c45_phy *priv = phydev->priv; + u16 basic_config; int ret; ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_ABILITIES); @@ -1561,8 +1564,15 @@ static int nxp_c45_set_phy_mode(struct phy_device *phydev) phydev_err(phydev, "rmii mode not supported\n"); return -EINVAL; } + + basic_config = MII_BASIC_CONFIG_RMII; + + /* This is not PHY_INTERFACE_MODE_REVRMII */ + if (priv->flags & TJA11XX_REVERSE_MODE) + basic_config |= MII_BASIC_CONFIG_REV; + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, - MII_BASIC_CONFIG_RMII); + basic_config); break; case PHY_INTERFACE_MODE_SGMII: if (!(ret & SGMII_ABILITY)) { @@ -1623,6 +1633,20 @@ static int nxp_c45_get_features(struct phy_device *phydev) return genphy_c45_pma_read_abilities(phydev); } +static int nxp_c45_parse_dt(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + struct nxp_c45_phy *priv = phydev->priv; + + if (!IS_ENABLED(CONFIG_OF_MDIO)) + return 0; + + if (of_property_read_bool(node, "nxp,rmii-refclk-out")) + priv->flags |= TJA11XX_REVERSE_MODE; + + return 0; +} + static int nxp_c45_probe(struct phy_device *phydev) { struct nxp_c45_phy *priv; @@ -1642,6 +1666,8 @@ static int nxp_c45_probe(struct phy_device *phydev) phydev->priv = priv; + nxp_c45_parse_dt(phydev); + mutex_init(&priv->ptp_lock); phy_abilities = phy_read_mmd(phydev, MDIO_MMD_VEND1, diff --git a/drivers/net/phy/nxp-c45-tja11xx.h b/drivers/net/phy/nxp-c45-tja11xx.h index f364fca68f0bed..8b5fc383752bcf 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.h +++ b/drivers/net/phy/nxp-c45-tja11xx.h @@ -28,6 +28,7 @@ struct nxp_c45_phy { int extts_index; bool extts; struct nxp_c45_macsec *macsec; + u32 flags; }; #if IS_ENABLED(CONFIG_MACSEC) diff --git a/drivers/net/phy/nxp-cbtx.c b/drivers/net/phy/nxp-cbtx.c index 145703f0a406e1..3d25491043a3c1 100644 --- a/drivers/net/phy/nxp-cbtx.c +++ b/drivers/net/phy/nxp-cbtx.c @@ -182,7 +182,7 @@ static int cbtx_get_sset_count(struct phy_device *phydev) static void cbtx_get_strings(struct phy_device *phydev, u8 *data) { - strncpy(data, "100btx_rx_err", ETH_GSTRING_LEN); + ethtool_puts(&data, "100btx_rx_err"); } static void cbtx_get_stats(struct phy_device *phydev, diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 5695935fdce97e..944ae98ad11060 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -680,17 +680,16 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_mdix); * @phydev: target phy_device struct * @adv: the linkmode advertisement settings */ -int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv) +static int genphy_c45_write_eee_adv(struct phy_device *phydev, + unsigned long *adv) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp); int val, changed = 0; - if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) { - val = linkmode_to_mii_eee_cap1_t(adv); + linkmode_andnot(tmp, adv, phydev->eee_broken_modes); - /* In eee_broken_modes are stored MDIO_AN_EEE_ADV specific raw - * register values. - */ - val &= ~phydev->eee_broken_modes; + if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP1_FEATURES)) { + val = linkmode_to_mii_eee_cap1_t(tmp); /* IEEE 802.3-2018 45.2.7.13 EEE advertisement 1 * (Register 7.60) @@ -708,7 +707,7 @@ int genphy_c45_write_eee_adv(struct phy_device *phydev, unsigned long *adv) } if (linkmode_intersects(phydev->supported_eee, PHY_EEE_CAP2_FEATURES)) { - val = linkmode_to_mii_eee_cap2_t(adv); + val = linkmode_to_mii_eee_cap2_t(tmp); /* IEEE 802.3-2022 45.2.7.16 EEE advertisement 2 * (Register 7.62) @@ -942,7 +941,7 @@ EXPORT_SYMBOL_GPL(genphy_c45_read_eee_abilities); */ int genphy_c45_an_config_eee_aneg(struct phy_device *phydev) { - if (!phydev->eee_enabled) { + if (!phydev->eee_cfg.eee_enabled) { __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {}; return genphy_c45_write_eee_adv(phydev, adv); @@ -950,6 +949,7 @@ int genphy_c45_an_config_eee_aneg(struct phy_device *phydev) return genphy_c45_write_eee_adv(phydev, phydev->advertising_eee); } +EXPORT_SYMBOL_GPL(genphy_c45_an_config_eee_aneg); /** * genphy_c45_pma_baset1_read_abilities - read supported baset1 link modes from PMA @@ -1521,20 +1521,17 @@ EXPORT_SYMBOL(genphy_c45_eee_is_active); int genphy_c45_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data) { - __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {}; - __ETHTOOL_DECLARE_LINK_MODE_MASK(lp) = {}; bool is_enabled; int ret; - ret = genphy_c45_eee_is_active(phydev, adv, lp, &is_enabled); + ret = genphy_c45_eee_is_active(phydev, data->advertised, + data->lp_advertised, &is_enabled); if (ret < 0) return ret; data->eee_enabled = is_enabled; - data->eee_active = ret; + data->eee_active = phydev->eee_active; linkmode_copy(data->supported, phydev->supported_eee); - linkmode_copy(data->advertised, adv); - linkmode_copy(data->lp_advertised, lp); return 0; } @@ -1568,15 +1565,12 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, phydev_warn(phydev, "At least some EEE link modes are not supported.\n"); return -EINVAL; } - } else { - adv = phydev->supported_eee; + linkmode_copy(phydev->advertising_eee, adv); + } else if (linkmode_empty(phydev->advertising_eee)) { + phy_advertise_eee_all(phydev); } - - linkmode_copy(phydev->advertising_eee, adv); } - phydev->eee_enabled = data->eee_enabled; - ret = genphy_c45_an_config_eee_aneg(phydev); if (ret > 0) { ret = phy_restart_aneg(phydev); diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 1f98b6a96c1535..6bf3ec985f3d34 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -388,28 +388,58 @@ void of_set_phy_supported(struct phy_device *phydev) void of_set_phy_eee_broken(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; - u32 broken = 0; + unsigned long *modes = phydev->eee_broken_modes; - if (!IS_ENABLED(CONFIG_OF_MDIO)) + if (!IS_ENABLED(CONFIG_OF_MDIO) || !node) return; - if (!node) - return; + linkmode_zero(modes); if (of_property_read_bool(node, "eee-broken-100tx")) - broken |= MDIO_EEE_100TX; + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, modes); if (of_property_read_bool(node, "eee-broken-1000t")) - broken |= MDIO_EEE_1000T; + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, modes); if (of_property_read_bool(node, "eee-broken-10gt")) - broken |= MDIO_EEE_10GT; + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, modes); if (of_property_read_bool(node, "eee-broken-1000kx")) - broken |= MDIO_EEE_1000KX; + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, modes); if (of_property_read_bool(node, "eee-broken-10gkx4")) - broken |= MDIO_EEE_10GKX4; + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, modes); if (of_property_read_bool(node, "eee-broken-10gkr")) - broken |= MDIO_EEE_10GKR; + linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, modes); +} + +/** + * of_set_phy_timing_role - Set the master/slave mode of the PHY + * + * @phydev: The phy_device struct + * + * Set master/slave configuration of the PHY based on the device tree. + */ +void of_set_phy_timing_role(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + const char *master; + + if (!IS_ENABLED(CONFIG_OF_MDIO)) + return; + + if (!node) + return; + + if (of_property_read_string(node, "timing-role", &master)) + return; - phydev->eee_broken_modes = broken; + if (strcmp(master, "forced-master") == 0) + phydev->master_slave_set = MASTER_SLAVE_CFG_MASTER_FORCE; + else if (strcmp(master, "forced-slave") == 0) + phydev->master_slave_set = MASTER_SLAVE_CFG_SLAVE_FORCE; + else if (strcmp(master, "preferred-master") == 0) + phydev->master_slave_set = MASTER_SLAVE_CFG_MASTER_PREFERRED; + else if (strcmp(master, "preferred-slave") == 0) + phydev->master_slave_set = MASTER_SLAVE_CFG_SLAVE_PREFERRED; + else + phydev_warn(phydev, "Unknown master-slave mode %s\n", master); } /** diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 4f3e742907cb62..0d20b534122b24 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -990,14 +990,14 @@ static int phy_check_link_status(struct phy_device *phydev) phydev->state = PHY_RUNNING; err = genphy_c45_eee_is_active(phydev, NULL, NULL, NULL); - if (err <= 0) - phydev->enable_tx_lpi = false; - else - phydev->enable_tx_lpi = phydev->eee_cfg.tx_lpi_enabled; + phydev->eee_active = err > 0; + phydev->enable_tx_lpi = phydev->eee_cfg.tx_lpi_enabled && + phydev->eee_active; phy_link_up(phydev); } else if (!phydev->link && phydev->state != PHY_NOLINK) { phydev->state = PHY_NOLINK; + phydev->eee_active = false; phydev->enable_tx_lpi = false; phy_link_down(phydev); } @@ -1672,7 +1672,7 @@ EXPORT_SYMBOL(phy_ethtool_get_eee); * phy_ethtool_set_eee_noneg - Adjusts MAC LPI configuration without PHY * renegotiation * @phydev: pointer to the target PHY device structure - * @data: pointer to the ethtool_keee structure containing the new EEE settings + * @old_cfg: pointer to the eee_config structure containing the old EEE settings * * This function updates the Energy Efficient Ethernet (EEE) configuration * for cases where only the MAC's Low Power Idle (LPI) configuration changes, @@ -1683,18 +1683,23 @@ EXPORT_SYMBOL(phy_ethtool_get_eee); * configuration. */ static void phy_ethtool_set_eee_noneg(struct phy_device *phydev, - struct ethtool_keee *data) + const struct eee_config *old_cfg) { - if (phydev->eee_cfg.tx_lpi_enabled != data->tx_lpi_enabled || - phydev->eee_cfg.tx_lpi_timer != data->tx_lpi_timer) { - eee_to_eeecfg(&phydev->eee_cfg, data); - phydev->enable_tx_lpi = eeecfg_mac_can_tx_lpi(&phydev->eee_cfg); - if (phydev->link) { - phydev->link = false; - phy_link_down(phydev); - phydev->link = true; - phy_link_up(phydev); - } + bool enable_tx_lpi; + + if (!phydev->link) + return; + + enable_tx_lpi = phydev->eee_cfg.tx_lpi_enabled && phydev->eee_active; + + if (phydev->enable_tx_lpi != enable_tx_lpi || + phydev->eee_cfg.tx_lpi_timer != old_cfg->tx_lpi_timer) { + phydev->enable_tx_lpi = false; + phydev->link = false; + phy_link_down(phydev); + phydev->enable_tx_lpi = enable_tx_lpi; + phydev->link = true; + phy_link_up(phydev); } } @@ -1707,18 +1712,23 @@ static void phy_ethtool_set_eee_noneg(struct phy_device *phydev, */ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *data) { + struct eee_config old_cfg; int ret; if (!phydev->drv) return -EIO; mutex_lock(&phydev->lock); + + old_cfg = phydev->eee_cfg; + eee_to_eeecfg(&phydev->eee_cfg, data); + ret = genphy_c45_ethtool_set_eee(phydev, data); - if (ret >= 0) { - if (ret == 0) - phy_ethtool_set_eee_noneg(phydev, data); - eee_to_eeecfg(&phydev->eee_cfg, data); - } + if (ret == 0) + phy_ethtool_set_eee_noneg(phydev, &old_cfg); + else if (ret < 0) + phydev->eee_cfg = old_cfg; + mutex_unlock(&phydev->lock); return ret < 0 ? ret : 0; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 499797646580e3..b26bb33cd1d482 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -2239,29 +2239,6 @@ static int genphy_c37_config_advert(struct phy_device *phydev) adv); } -/** - * genphy_config_eee_advert - disable unwanted eee mode advertisement - * @phydev: target phy_device struct - * - * Description: Writes MDIO_AN_EEE_ADV after disabling unsupported energy - * efficent ethernet modes. Returns 0 if the PHY's advertisement hasn't - * changed, and 1 if it has changed. - */ -int genphy_config_eee_advert(struct phy_device *phydev) -{ - int err; - - /* Nothing to disable */ - if (!phydev->eee_broken_modes) - return 0; - - err = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, - phydev->eee_broken_modes, 0); - /* If the call failed, we assume that EEE is not supported */ - return err < 0 ? 0 : err; -} -EXPORT_SYMBOL(genphy_config_eee_advert); - /** * genphy_setup_forced - configures/forces speed/duplex from @phydev * @phydev: target phy_device struct @@ -3358,11 +3335,17 @@ static int of_phy_led(struct phy_device *phydev, if (index > U8_MAX) return -EINVAL; + if (of_property_read_bool(led, "active-high")) + set_bit(PHY_LED_ACTIVE_HIGH, &modes); if (of_property_read_bool(led, "active-low")) set_bit(PHY_LED_ACTIVE_LOW, &modes); if (of_property_read_bool(led, "inactive-high-impedance")) set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes); + if (WARN_ON(modes & BIT(PHY_LED_ACTIVE_LOW) && + modes & BIT(PHY_LED_ACTIVE_HIGH))) + return -EINVAL; + if (modes) { /* Return error if asked to set polarity modes but not supported */ if (!phydev->drv->led_polarity_set) @@ -3421,6 +3404,16 @@ static int of_phy_leds(struct phy_device *phydev) if (!leds) return 0; + /* Check if the PHY driver have at least an OP to + * set the LEDs. + */ + if (!(phydev->drv->led_brightness_set || + phydev->drv->led_blink_set || + phydev->drv->led_hw_control_set)) { + phydev_dbg(phydev, "ignoring leds node defined with no PHY driver support\n"); + goto exit; + } + for_each_available_child_of_node_scoped(leds, led) { err = of_phy_led(phydev, led); if (err) { @@ -3430,6 +3423,7 @@ static int of_phy_leds(struct phy_device *phydev) } } +exit: of_node_put(leds); return 0; } @@ -3595,12 +3589,12 @@ static int phy_probe(struct device *dev) /* There is no "enabled" flag. If PHY is advertising, assume it is * kind of enabled. */ - phydev->eee_enabled = !linkmode_empty(phydev->advertising_eee); + phydev->eee_cfg.eee_enabled = !linkmode_empty(phydev->advertising_eee); /* Some PHYs may advertise, by default, not support EEE modes. So, * we need to clean them. */ - if (phydev->eee_enabled) + if (phydev->eee_cfg.eee_enabled) linkmode_and(phydev->advertising_eee, phydev->supported_eee, phydev->advertising_eee); @@ -3609,6 +3603,9 @@ static int phy_probe(struct device *dev) */ of_set_phy_eee_broken(phydev); + /* Get master/slave strap overrides */ + of_set_phy_timing_role(phydev); + /* The Pause Frame bits indicate that the PHY can support passing * pause frames. During autonegotiation, the PHYs will determine if * they should allow pause frames to pass. The MAC driver should then diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 3e9957b6aa1489..30a654e9835233 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -79,7 +79,6 @@ struct phylink { unsigned int pcs_state; bool link_failed; - bool using_mac_select_pcs; struct sfp_bus *sfp_bus; bool sfp_may_have_phy; @@ -599,15 +598,8 @@ static unsigned long phylink_get_capabilities(phy_interface_t interface, * max speed at full duplex. */ if (mac_capabilities & - phylink_cap_from_speed_duplex(max_speed, DUPLEX_FULL)) { - /* Although a duplex-matching phy might exist, we - * conservatively remove these modes because the MAC - * will not be aware of the half-duplex nature of the - * link. - */ + phylink_cap_from_speed_duplex(max_speed, DUPLEX_FULL)) matched_caps = GENMASK(__fls(caps), __fls(MAC_10HD)); - matched_caps &= ~(MAC_1000HD | MAC_100HD | MAC_10HD); - } break; } case RATE_MATCH_CRS: @@ -656,17 +648,15 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl, unsigned long *supported, struct phylink_link_state *state) { + struct phylink_pcs *pcs = NULL; unsigned long capabilities; - struct phylink_pcs *pcs; int ret; /* Get the PCS for this interface mode */ - if (pl->using_mac_select_pcs) { + if (pl->mac_ops->mac_select_pcs) { pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); if (IS_ERR(pcs)) return PTR_ERR(pcs); - } else { - pcs = pl->pcs; } if (pcs) { @@ -774,8 +764,8 @@ static int phylink_validate(struct phylink *pl, unsigned long *supported, static int phylink_parse_fixedlink(struct phylink *pl, const struct fwnode_handle *fwnode) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; struct fwnode_handle *fixed_node; - bool pause, asym_pause, autoneg; const struct phy_setting *s; struct gpio_desc *desc; u32 speed; @@ -848,22 +838,15 @@ static int phylink_parse_fixedlink(struct phylink *pl, linkmode_copy(pl->link_config.advertising, pl->supported); phylink_validate(pl, pl->supported, &pl->link_config); - pause = phylink_test(pl->supported, Pause); - asym_pause = phylink_test(pl->supported, Asym_Pause); - autoneg = phylink_test(pl->supported, Autoneg); s = phy_lookup_setting(pl->link_config.speed, pl->link_config.duplex, pl->supported, true); - linkmode_zero(pl->supported); - phylink_set(pl->supported, MII); - - if (pause) - phylink_set(pl->supported, Pause); - if (asym_pause) - phylink_set(pl->supported, Asym_Pause); + linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, mask); + linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, mask); + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mask); + linkmode_and(pl->supported, pl->supported, mask); - if (autoneg) - phylink_set(pl->supported, Autoneg); + phylink_set(pl->supported, MII); if (s) { __set_bit(s->bit, pl->supported); @@ -1182,7 +1165,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, state->interface, state->advertising); - if (pl->using_mac_select_pcs) { + if (pl->mac_ops->mac_select_pcs) { pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); if (IS_ERR(pcs)) { phylink_err(pl, @@ -1191,7 +1174,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, return; } - pcs_changed = pcs && pl->pcs != pcs; + pcs_changed = pl->pcs != pcs; } phylink_pcs_poll_stop(pl); @@ -1480,76 +1463,66 @@ static void phylink_resolve(struct work_struct *w) } else if (pl->link_failed) { link_state.link = false; retrigger = true; + } else if (pl->cur_link_an_mode == MLO_AN_FIXED) { + phylink_get_fixed_state(pl, &link_state); + mac_config = link_state.link; + } else if (pl->cur_link_an_mode == MLO_AN_PHY) { + link_state = pl->phy_state; + mac_config = link_state.link; } else { - switch (pl->cur_link_an_mode) { - case MLO_AN_PHY: - link_state = pl->phy_state; - phylink_apply_manual_flow(pl, &link_state); - mac_config = link_state.link; - break; + phylink_mac_pcs_get_state(pl, &link_state); - case MLO_AN_FIXED: - phylink_get_fixed_state(pl, &link_state); - mac_config = link_state.link; - break; + /* The PCS may have a latching link-fail indicator. If the link + * was up, bring the link down and re-trigger the resolve. + * Otherwise, re-read the PCS state to get the current status + * of the link. + */ + if (!link_state.link) { + if (cur_link_state) + retrigger = true; + else + phylink_mac_pcs_get_state(pl, &link_state); + } - case MLO_AN_INBAND: - phylink_mac_pcs_get_state(pl, &link_state); + /* If we have a phy, the "up" state is the union of both the + * PHY and the MAC + */ + if (pl->phydev) + link_state.link &= pl->phy_state.link; - /* The PCS may have a latching link-fail indicator. - * If the link was up, bring the link down and - * re-trigger the resolve. Otherwise, re-read the - * PCS state to get the current status of the link. + /* Only update if the PHY link is up */ + if (pl->phydev && pl->phy_state.link) { + /* If the interface has changed, force a link down + * event if the link isn't already down, and re-resolve. */ - if (!link_state.link) { - if (cur_link_state) - retrigger = true; - else - phylink_mac_pcs_get_state(pl, - &link_state); + if (link_state.interface != pl->phy_state.interface) { + retrigger = true; + link_state.link = false; } - /* If we have a phy, the "up" state is the union of - * both the PHY and the MAC + link_state.interface = pl->phy_state.interface; + + /* If we are doing rate matching, then the link + * speed/duplex comes from the PHY */ - if (pl->phydev) - link_state.link &= pl->phy_state.link; - - /* Only update if the PHY link is up */ - if (pl->phydev && pl->phy_state.link) { - /* If the interface has changed, force a - * link down event if the link isn't already - * down, and re-resolve. - */ - if (link_state.interface != - pl->phy_state.interface) { - retrigger = true; - link_state.link = false; - } - link_state.interface = pl->phy_state.interface; - - /* If we are doing rate matching, then the - * link speed/duplex comes from the PHY - */ - if (pl->phy_state.rate_matching) { - link_state.rate_matching = - pl->phy_state.rate_matching; - link_state.speed = pl->phy_state.speed; - link_state.duplex = - pl->phy_state.duplex; - } - - /* If we have a PHY, we need to update with - * the PHY flow control bits. - */ - link_state.pause = pl->phy_state.pause; - mac_config = true; + if (pl->phy_state.rate_matching) { + link_state.rate_matching = + pl->phy_state.rate_matching; + link_state.speed = pl->phy_state.speed; + link_state.duplex = pl->phy_state.duplex; } - phylink_apply_manual_flow(pl, &link_state); - break; + + /* If we have a PHY, we need to update with the PHY + * flow control bits. + */ + link_state.pause = pl->phy_state.pause; + mac_config = true; } } + if (pl->cur_link_an_mode != MLO_AN_FIXED) + phylink_apply_manual_flow(pl, &link_state); + if (mac_config) { if (link_state.interface != pl->link_config.interface) { /* The interface has changed, force the link down and @@ -1698,7 +1671,6 @@ struct phylink *phylink_create(struct phylink_config *config, phy_interface_t iface, const struct phylink_mac_ops *mac_ops) { - bool using_mac_select_pcs = false; struct phylink *pl; int ret; @@ -1709,11 +1681,6 @@ struct phylink *phylink_create(struct phylink_config *config, return ERR_PTR(-EINVAL); } - if (mac_ops->mac_select_pcs && - mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) != - ERR_PTR(-EOPNOTSUPP)) - using_mac_select_pcs = true; - pl = kzalloc(sizeof(*pl), GFP_KERNEL); if (!pl) return ERR_PTR(-ENOMEM); @@ -1732,7 +1699,6 @@ struct phylink *phylink_create(struct phylink_config *config, return ERR_PTR(-EINVAL); } - pl->using_mac_select_pcs = using_mac_select_pcs; pl->phy_state.interface = iface; pl->link_interface = iface; if (iface == PHY_INTERFACE_MODE_MOCA) @@ -2434,6 +2400,32 @@ int phylink_ethtool_set_wol(struct phylink *pl, struct ethtool_wolinfo *wol) } EXPORT_SYMBOL_GPL(phylink_ethtool_set_wol); +static phy_interface_t phylink_sfp_select_interface(struct phylink *pl, + const unsigned long *link_modes) +{ + phy_interface_t interface; + + interface = sfp_select_interface(pl->sfp_bus, link_modes); + if (interface == PHY_INTERFACE_MODE_NA) { + phylink_err(pl, + "selection of interface failed, advertisement %*pb\n", + __ETHTOOL_LINK_MODE_MASK_NBITS, + link_modes); + return interface; + } + + if (!test_bit(interface, pl->config->supported_interfaces)) { + phylink_err(pl, + "selection of interface failed, SFP selected %s (%u) but MAC supports %*pbl\n", + phy_modes(interface), interface, + (int)PHY_INTERFACE_MODE_MAX, + pl->config->supported_interfaces); + return PHY_INTERFACE_MODE_NA; + } + + return interface; +} + static void phylink_merge_link_mode(unsigned long *dst, const unsigned long *b) { __ETHTOOL_DECLARE_LINK_MODE_MASK(mask); @@ -2616,15 +2608,10 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, * link can be configured correctly. */ if (pl->sfp_bus) { - config.interface = sfp_select_interface(pl->sfp_bus, + config.interface = phylink_sfp_select_interface(pl, config.advertising); - if (config.interface == PHY_INTERFACE_MODE_NA) { - phylink_err(pl, - "selection of interface failed, advertisement %*pb\n", - __ETHTOOL_LINK_MODE_MASK_NBITS, - config.advertising); + if (config.interface == PHY_INTERFACE_MODE_NA) return -EINVAL; - } /* Revalidate with the selected interface */ linkmode_copy(support, pl->supported); @@ -3229,10 +3216,8 @@ static void phylink_sfp_set_config(struct phylink *pl, u8 mode, static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, struct phy_device *phy) { - __ETHTOOL_DECLARE_LINK_MODE_MASK(support1); __ETHTOOL_DECLARE_LINK_MODE_MASK(support); struct phylink_link_state config; - phy_interface_t iface; int ret; linkmode_copy(support, phy->supported); @@ -3253,24 +3238,21 @@ static int phylink_sfp_config_phy(struct phylink *pl, u8 mode, return ret; } - iface = sfp_select_interface(pl->sfp_bus, config.advertising); - if (iface == PHY_INTERFACE_MODE_NA) { - phylink_err(pl, - "selection of interface failed, advertisement %*pb\n", - __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising); + config.interface = phylink_sfp_select_interface(pl, config.advertising); + if (config.interface == PHY_INTERFACE_MODE_NA) return -EINVAL; - } - config.interface = iface; - linkmode_copy(support1, support); - ret = phylink_validate(pl, support1, &config); - if (ret) { - phylink_err(pl, - "validation of %s/%s with support %*pb failed: %pe\n", - phylink_an_mode_str(mode), - phy_modes(config.interface), - __ETHTOOL_LINK_MODE_MASK_NBITS, support, - ERR_PTR(ret)); + /* Attach the PHY so that the PHY is present when we do the major + * configuration step. + */ + ret = phylink_attach_phy(pl, phy, config.interface); + if (ret < 0) + return ret; + + /* This will validate the configuration for us. */ + ret = phylink_bringup_phy(pl, phy, config.interface); + if (ret < 0) { + phy_detach(phy); return ret; } @@ -3428,9 +3410,7 @@ static bool phylink_phy_no_inband(struct phy_device *phy) static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) { struct phylink *pl = upstream; - phy_interface_t interface; u8 mode; - int ret; /* * This is the new way of dealing with flow control for PHYs, @@ -3451,20 +3431,7 @@ static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) pl->config->supported_interfaces); /* Do the initial configuration */ - ret = phylink_sfp_config_phy(pl, mode, phy); - if (ret < 0) - return ret; - - interface = pl->link_config.interface; - ret = phylink_attach_phy(pl, phy, interface); - if (ret < 0) - return ret; - - ret = phylink_bringup_phy(pl, phy, interface); - if (ret) - phy_detach(phy); - - return ret; + return phylink_sfp_config_phy(pl, mode, phy); } static void phylink_sfp_disconnect_phy(void *upstream, diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c index a05d0df6fa16b8..7a5039920b9f4c 100644 --- a/drivers/net/phy/qcom/qca83xx.c +++ b/drivers/net/phy/qcom/qca83xx.c @@ -42,10 +42,8 @@ static void qca83xx_get_strings(struct phy_device *phydev, u8 *data) { int i; - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) { - strscpy(data + i * ETH_GSTRING_LEN, - qca83xx_hw_stats[i].string, ETH_GSTRING_LEN); - } + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) + ethtool_puts(&data, qca83xx_hw_stats[i].string); } static u64 qca83xx_get_stat(struct phy_device *phydev, int i) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 166f6a7283731e..f65d7f1f348e73 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -80,18 +80,22 @@ #define RTL822X_VND2_GANLPAR 0xa414 -#define RTL822X_VND2_PHYSR 0xa434 - #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) #define RTL9000A_GINMR 0x14 #define RTL9000A_GINMR_LINK_STATUS BIT(4) -#define RTLGEN_SPEED_MASK 0x0630 +#define RTL_VND2_PHYSR 0xa434 +#define RTL_VND2_PHYSR_DUPLEX BIT(3) +#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4) +#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9) +#define RTL_VND2_PHYSR_MASTER BIT(11) +#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH) #define RTL_GENERIC_PHYID 0x001cc800 #define RTL_8211FVD_PHYID 0x001cc878 +#define RTL_8221B 0x001cc840 #define RTL_8221B_VB_CG 0x001cc849 #define RTL_8221B_VN_CG 0x001cc84a #define RTL_8251B 0x001cc862 @@ -660,9 +664,18 @@ static int rtl8366rb_config_init(struct phy_device *phydev) } /* get actual speed to cover the downshift case */ -static void rtlgen_decode_speed(struct phy_device *phydev, int val) +static void rtlgen_decode_physr(struct phy_device *phydev, int val) { - switch (val & RTLGEN_SPEED_MASK) { + /* bit 3 + * 0: Half Duplex + * 1: Full Duplex + */ + if (val & RTL_VND2_PHYSR_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + switch (val & RTL_VND2_PHYSR_SPEED_MASK) { case 0x0000: phydev->speed = SPEED_10; break; @@ -684,6 +697,19 @@ static void rtlgen_decode_speed(struct phy_device *phydev, int val) default: break; } + + /* bit 11 + * 0: Slave Mode + * 1: Master Mode + */ + if (phydev->speed >= 1000) { + if (val & RTL_VND2_PHYSR_MASTER) + phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; + else + phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; + } else { + phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED; + } } static int rtlgen_read_status(struct phy_device *phydev) @@ -701,7 +727,7 @@ static int rtlgen_read_status(struct phy_device *phydev) if (val < 0) return val; - rtlgen_decode_speed(phydev, val); + rtlgen_decode_physr(phydev, val); return 0; } @@ -924,17 +950,25 @@ static void rtl822xb_update_interface(struct phy_device *phydev) static int rtl822x_read_status(struct phy_device *phydev) { - if (phydev->autoneg == AUTONEG_ENABLE) { - int lpadv = phy_read_paged(phydev, 0xa5d, 0x13); + int lpadv, ret; - if (lpadv < 0) - return lpadv; + ret = rtlgen_read_status(phydev); + if (ret < 0) + return ret; - mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, - lpadv); + if (phydev->autoneg == AUTONEG_DISABLE || + !phydev->autoneg_complete) { + mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0); + return 0; } - return rtlgen_read_status(phydev); + lpadv = phy_read_paged(phydev, 0xa5d, 0x13); + if (lpadv < 0) + return lpadv; + + mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); + + return 0; } static int rtl822xb_read_status(struct phy_device *phydev) @@ -993,6 +1027,10 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) if (ret < 0) return ret; + if (phydev->autoneg == AUTONEG_DISABLE || + !genphy_c45_aneg_done(phydev)) + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0); + /* Vendor register as C45 has no standardized support for 1000BaseT */ if (phydev->autoneg == AUTONEG_ENABLE) { val = phy_read_mmd(phydev, MDIO_MMD_VEND2, @@ -1007,11 +1045,11 @@ static int rtl822x_c45_read_status(struct phy_device *phydev) return 0; /* Read actual speed from vendor register. */ - val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_PHYSR); + val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR); if (val < 0) return val; - rtlgen_decode_speed(phydev, val); + rtlgen_decode_physr(phydev, val); return 0; } @@ -1040,6 +1078,23 @@ static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) return val >= 0 && val & MDIO_PMA_SPEED_2_5G; } +/* On internal PHY's MMD reads over C22 always return 0. + * Check a MMD register which is known to be non-zero. + */ +static bool rtlgen_supports_mmd(struct phy_device *phydev) +{ + int val; + + phy_lock_mdio_bus(phydev); + __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS); + __phy_write(phydev, MII_MMD_DATA, MDIO_PCS_EEE_ABLE); + __phy_write(phydev, MII_MMD_CTRL, MDIO_MMD_PCS | MII_MMD_CTRL_NOINCR); + val = __phy_read(phydev, MII_MMD_DATA); + phy_unlock_mdio_bus(phydev); + + return val > 0; +} + static int rtlgen_match_phy_device(struct phy_device *phydev) { return phydev->phy_id == RTL_GENERIC_PHYID && @@ -1049,7 +1104,8 @@ static int rtlgen_match_phy_device(struct phy_device *phydev) static int rtl8226_match_phy_device(struct phy_device *phydev) { return phydev->phy_id == RTL_GENERIC_PHYID && - rtlgen_supports_2_5gbps(phydev); + rtlgen_supports_2_5gbps(phydev) && + rtlgen_supports_mmd(phydev); } static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, @@ -1061,6 +1117,11 @@ static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id, return !is_c45 && (id == phydev->phy_id); } +static int rtl8221b_match_phy_device(struct phy_device *phydev) +{ + return phydev->phy_id == RTL_8221B && rtlgen_supports_mmd(phydev); +} + static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev) { return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false); @@ -1081,9 +1142,22 @@ static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev) return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true); } -static int rtl8251b_c22_match_phy_device(struct phy_device *phydev) +static int rtl_internal_nbaset_match_phy_device(struct phy_device *phydev) { - return rtlgen_is_c45_match(phydev, RTL_8251B, false); + if (phydev->is_c45) + return false; + + switch (phydev->phy_id) { + case RTL_GENERIC_PHYID: + case RTL_8221B: + case RTL_8251B: + case 0x001cc841: + break; + default: + return false; + } + + return rtlgen_supports_2_5gbps(phydev) && !rtlgen_supports_mmd(phydev); } static int rtl8251b_c45_match_phy_device(struct phy_device *phydev) @@ -1345,10 +1419,8 @@ static struct phy_driver realtek_drvs[] = { .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, - .read_mmd = rtl822x_read_mmd, - .write_mmd = rtl822x_write_mmd, }, { - PHY_ID_MATCH_EXACT(0x001cc840), + .match_phy_device = rtl8221b_match_phy_device, .name = "RTL8226B_RTL8221B 2.5Gbps PHY", .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, @@ -1359,8 +1431,6 @@ static struct phy_driver realtek_drvs[] = { .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, - .read_mmd = rtl822x_read_mmd, - .write_mmd = rtl822x_write_mmd, }, { PHY_ID_MATCH_EXACT(0x001cc838), .name = "RTL8226-CG 2.5Gbps PHY", @@ -1438,8 +1508,9 @@ static struct phy_driver realtek_drvs[] = { .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, }, { - .match_phy_device = rtl8251b_c22_match_phy_device, - .name = "RTL8126A-internal 5Gbps PHY", + .match_phy_device = rtl_internal_nbaset_match_phy_device, + .name = "Realtek Internal NBASE-T PHY", + .flags = PHY_IS_INTERNAL, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index a5684ef5884bda..7dbcbf0a4ee26a 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -466,7 +466,8 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, static const struct sfp_quirk sfp_quirks[] = { // Alcatel Lucent G-010S-P can operate at 2500base-X, but incorrectly // report 2500MBd NRZ in their EEPROM - SFP_QUIRK_M("ALCATELLUCENT", "G010SP", sfp_quirk_2500basex), + SFP_QUIRK("ALCATELLUCENT", "G010SP", sfp_quirk_2500basex, + sfp_fixup_ignore_tx_fault), // Alcatel Lucent G-010S-A can operate at 2500base-X, but report 3.2GBd // NRZ in their EEPROM @@ -3146,7 +3147,7 @@ static void sfp_shutdown(struct platform_device *pdev) static struct platform_driver sfp_driver = { .probe = sfp_probe, - .remove_new = sfp_remove, + .remove = sfp_remove, .shutdown = sfp_shutdown, .driver = { .name = "sfp", diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 150aea7c9c3675..e1853599d9baae 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -627,12 +627,13 @@ int smsc_phy_probe(struct phy_device *phydev) phydev->priv = priv; /* Make clk optional to keep DTB backward compatibility. */ - refclk = devm_clk_get_optional_enabled(dev, NULL); + refclk = devm_clk_get_optional_enabled_with_rate(dev, NULL, + 50 * 1000 * 1000); if (IS_ERR(refclk)) return dev_err_probe(dev, PTR_ERR(refclk), "Failed to request clock\n"); - return clk_set_rate(refclk, 50 * 1000 * 1000); + return 0; } EXPORT_SYMBOL_GPL(smsc_phy_probe); diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c index 18191d5a8bd4d3..c7690adec8db72 100644 --- a/drivers/net/team/team_core.c +++ b/drivers/net/team/team_core.c @@ -983,7 +983,8 @@ static void team_port_disable(struct team *team, #define TEAM_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \ - NETIF_F_HIGHDMA | NETIF_F_LRO) + NETIF_F_HIGHDMA | NETIF_F_LRO | \ + NETIF_F_GSO_ENCAP_ALL) #define TEAM_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ NETIF_F_RXCSUM | NETIF_F_GSO_SOFTWARE) @@ -991,14 +992,19 @@ static void team_port_disable(struct team *team, static void __team_compute_features(struct team *team) { struct team_port *port; - netdev_features_t vlan_features = TEAM_VLAN_FEATURES & - NETIF_F_ALL_FOR_ALL; + netdev_features_t vlan_features = TEAM_VLAN_FEATURES; netdev_features_t enc_features = TEAM_ENC_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM; rcu_read_lock(); + if (list_empty(&team->port_list)) + goto done; + + vlan_features = netdev_base_features(vlan_features); + enc_features = netdev_base_features(enc_features); + list_for_each_entry_rcu(port, &team->port_list, list) { vlan_features = netdev_increment_features(vlan_features, port->dev->vlan_features, @@ -1008,11 +1014,11 @@ static void __team_compute_features(struct team *team) port->dev->hw_enc_features, TEAM_ENC_FEATURES); - dst_release_flag &= port->dev->priv_flags; if (port->dev->hard_header_len > max_hard_header_len) max_hard_header_len = port->dev->hard_header_len; } +done: rcu_read_unlock(); team->dev->vlan_features = vlan_features; @@ -1946,8 +1952,7 @@ static void team_netpoll_cleanup(struct net_device *dev) mutex_unlock(&team->lock); } -static int team_netpoll_setup(struct net_device *dev, - struct netpoll_info *npifo) +static int team_netpoll_setup(struct net_device *dev) { struct team *team = netdev_priv(dev); struct team_port *port; @@ -2012,8 +2017,7 @@ static netdev_features_t team_fix_features(struct net_device *dev, netdev_features_t mask; mask = features; - features &= ~NETIF_F_ONE_FOR_ALL; - features |= NETIF_F_ALL_FOR_ALL; + features = netdev_base_features(features); rcu_read_lock(); list_for_each_entry_rcu(port, &team->port_list, list) { diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 9a0f6eb3201661..e816aaba8e5f2e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -71,7 +71,7 @@ #include #include #include -#include +#include #include #include #include @@ -1481,7 +1481,7 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, skb->truesize += skb->data_len; for (i = 1; i < it->nr_segs; i++) { - const struct iovec *iov = iter_iov(it); + const struct iovec *iov = iter_iov(it) + i; size_t fragsz = iov->iov_len; struct page *page; void *frag; diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 8adf77e3557e7a..531b1b6a37d190 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1652,13 +1652,13 @@ static int lan78xx_set_wol(struct net_device *netdev, struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); int ret; + if (wol->wolopts & ~WAKE_ALL) + return -EINVAL; + ret = usb_autopm_get_interface(dev->intf); if (ret < 0) return ret; - if (wol->wolopts & ~WAKE_ALL) - return -EINVAL; - pdata->wol = wol->wolopts; device_set_wakeup_enable(&dev->udev->dev, (bool)wol->wolopts); @@ -2380,6 +2380,7 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) if (dev->chipid == ID_REV_CHIP_ID_7801_) { if (phy_is_pseudo_fixed_link(phydev)) { fixed_phy_unregister(phydev); + phy_device_free(phydev); } else { phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0); @@ -4246,8 +4247,10 @@ static void lan78xx_disconnect(struct usb_interface *intf) phy_disconnect(net->phydev); - if (phy_is_pseudo_fixed_link(phydev)) + if (phy_is_pseudo_fixed_link(phydev)) { fixed_phy_unregister(phydev); + phy_device_free(phydev); + } usb_scuttle_anchored_urbs(&dev->deferred); @@ -4414,29 +4417,30 @@ static int lan78xx_probe(struct usb_interface *intf, period = ep_intr->desc.bInterval; maxp = usb_maxpacket(dev->udev, dev->pipe_intr); - buf = kmalloc(maxp, GFP_KERNEL); - if (!buf) { + + dev->urb_intr = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->urb_intr) { ret = -ENOMEM; goto out5; } - dev->urb_intr = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->urb_intr) { + buf = kmalloc(maxp, GFP_KERNEL); + if (!buf) { ret = -ENOMEM; - goto out6; - } else { - usb_fill_int_urb(dev->urb_intr, dev->udev, - dev->pipe_intr, buf, maxp, - intr_complete, dev, period); - dev->urb_intr->transfer_flags |= URB_FREE_BUFFER; + goto free_urbs; } + usb_fill_int_urb(dev->urb_intr, dev->udev, + dev->pipe_intr, buf, maxp, + intr_complete, dev, period); + dev->urb_intr->transfer_flags |= URB_FREE_BUFFER; + dev->maxpacket = usb_maxpacket(dev->udev, dev->pipe_out); /* Reject broken descriptors. */ if (dev->maxpacket == 0) { ret = -ENODEV; - goto out6; + goto free_urbs; } /* driver requires remote-wakeup capability during autosuspend. */ @@ -4444,7 +4448,7 @@ static int lan78xx_probe(struct usb_interface *intf, ret = lan78xx_phy_init(dev); if (ret < 0) - goto out7; + goto free_urbs; ret = register_netdev(netdev); if (ret != 0) { @@ -4466,10 +4470,8 @@ static int lan78xx_probe(struct usb_interface *intf, out8: phy_disconnect(netdev->phydev); -out7: +free_urbs: usb_free_urb(dev->urb_intr); -out6: - kfree(buf); out5: lan78xx_unbind(dev, intf); out4: diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 0c011d8f5d4db2..e9208a8d2bfa61 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1365,6 +1365,9 @@ static const struct usb_device_id products[] = { {QMI_QUIRK_SET_DTR(0x1bc7, 0x10a0, 0)}, /* Telit FN920C04 */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x10a4, 0)}, /* Telit FN920C04 */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x10a9, 0)}, /* Telit FN920C04 */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x10c0, 0)}, /* Telit FE910C04 */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x10c4, 0)}, /* Telit FE910C04 */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x10c8, 0)}, /* Telit FE910C04 */ {QMI_FIXED_INTF(0x1bc7, 0x1100, 3)}, /* Telit ME910 */ {QMI_FIXED_INTF(0x1bc7, 0x1101, 3)}, /* Telit ME910 dual modem */ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ @@ -1426,6 +1429,7 @@ static const struct usb_device_id products[] = { {QMI_QUIRK_SET_DTR(0x2c7c, 0x0195, 4)}, /* Quectel EG95 */ {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ {QMI_QUIRK_SET_DTR(0x2c7c, 0x030e, 4)}, /* Quectel EM05GV2 */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0316, 3)}, /* Quectel RG255C */ {QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */ {QMI_QUIRK_SET_DTR(0x2cb7, 0x0112, 0)}, /* Fibocom FG132 */ {QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */ diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c index cb7d2f798fb436..091bc2aca7e8e7 100644 --- a/drivers/net/usb/sr9700.c +++ b/drivers/net/usb/sr9700.c @@ -177,9 +177,9 @@ static int sr9700_get_eeprom(struct net_device *netdev, static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc) { struct usbnet *dev = netdev_priv(netdev); - __le16 res; + int err, res; + __le16 word; int rc = 0; - int err; if (phy_id) { netdev_dbg(netdev, "Only internal phy supported\n"); @@ -197,14 +197,14 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc) if (value & NSR_LINKST) rc = 1; } - err = sr_share_read_word(dev, 1, loc, &res); + err = sr_share_read_word(dev, 1, loc, &word); if (err < 0) return err; if (rc == 1) - res = le16_to_cpu(res) | BMSR_LSTATUS; + res = le16_to_cpu(word) | BMSR_LSTATUS; else - res = le16_to_cpu(res) & ~BMSR_LSTATUS; + res = le16_to_cpu(word) & ~BMSR_LSTATUS; netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", phy_id, loc, res); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 18148e068aa006..07ebb800edf170 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1765,7 +1765,7 @@ static int veth_init_queues(struct net_device *dev, struct nlattr *tb[]) return 0; } -static int veth_newlink(struct net *src_net, struct net_device *dev, +static int veth_newlink(struct net *peer_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { @@ -1776,24 +1776,15 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; unsigned char name_assign_type; struct ifinfomsg *ifmp; - struct net *net; /* * create and register peer first */ - if (data != NULL && data[VETH_INFO_PEER] != NULL) { - struct nlattr *nla_peer; + if (data && data[VETH_INFO_PEER]) { + struct nlattr *nla_peer = data[VETH_INFO_PEER]; - nla_peer = data[VETH_INFO_PEER]; ifmp = nla_data(nla_peer); - err = rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack); - if (err < 0) - return err; - - err = veth_validate(peer_tb, NULL, extack); - if (err < 0) - return err; - + rtnl_nla_parse_ifinfomsg(peer_tb, nla_peer, extack); tbp = peer_tb; } else { ifmp = NULL; @@ -1808,16 +1799,10 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, name_assign_type = NET_NAME_ENUM; } - net = rtnl_link_get_net(src_net, tbp); - if (IS_ERR(net)) - return PTR_ERR(net); - - peer = rtnl_create_link(net, ifname, name_assign_type, + peer = rtnl_create_link(peer_net, ifname, name_assign_type, &veth_link_ops, tbp, extack); - if (IS_ERR(peer)) { - put_net(net); + if (IS_ERR(peer)) return PTR_ERR(peer); - } if (!ifmp || !tbp[IFLA_ADDRESS]) eth_hw_addr_random(peer); @@ -1828,8 +1813,6 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, netif_inherit_tso_max(peer, dev); err = register_netdevice(peer); - put_net(net); - net = NULL; if (err < 0) goto err_register_peer; @@ -1952,6 +1935,7 @@ static struct rtnl_link_ops veth_link_ops = { .newlink = veth_newlink, .dellink = veth_dellink, .policy = veth_policy, + .peer_type = VETH_INFO_PEER, .maxtype = VETH_INFO_MAX, .get_link_net = veth_get_link_net, .get_num_tx_queues = veth_get_num_queues, diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 53a038fcbe991d..7646ddd9bef70c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -45,9 +45,6 @@ module_param(napi_tx, bool, 0644); #define VIRTIO_XDP_TX BIT(0) #define VIRTIO_XDP_REDIR BIT(1) -#define VIRTIO_XDP_FLAG BIT(0) -#define VIRTIO_ORPHAN_FLAG BIT(1) - /* RX packet size EWMA. The average packet size is used to determine the packet * buffer size when refilling RX rings. As the entire RX ring may be refilled * at once, the weight is chosen so that the EWMA will be insensitive to short- @@ -86,6 +83,7 @@ struct virtnet_sq_free_stats { u64 bytes; u64 napi_packets; u64 napi_bytes; + u64 xsk; }; struct virtnet_sq_stats { @@ -298,6 +296,10 @@ struct send_queue { /* Record whether sq is in reset state. */ bool reset; + + struct xsk_buff_pool *xsk_pool; + + dma_addr_t xsk_hdr_dma_addr; }; /* Internal representation of a receive virtqueue */ @@ -356,9 +358,6 @@ struct receive_queue { struct xdp_rxq_info xsk_rxq_info; struct xdp_buff **xsk_buffs; - - /* Do dma by self */ - bool do_dma; }; /* This structure can contain rss message with maximum settings for indirection table and keysize @@ -501,7 +500,10 @@ struct virtio_net_common_hdr { }; }; +static struct virtio_net_common_hdr xsk_hdr; + static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf); +static void virtnet_sq_free_unused_buf_done(struct virtqueue *vq); static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp, struct net_device *dev, unsigned int *xdp_xmit, @@ -512,6 +514,14 @@ static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb, struct sk_buff *curr_skb, struct page *page, void *buf, int len, int truesize); +static void virtnet_xsk_completed(struct send_queue *sq, int num); + +enum virtnet_xmit_type { + VIRTNET_XMIT_TYPE_SKB, + VIRTNET_XMIT_TYPE_SKB_ORPHAN, + VIRTNET_XMIT_TYPE_XDP, + VIRTNET_XMIT_TYPE_XSK, +}; static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size) { @@ -532,67 +542,99 @@ static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss) kfree(rss->indirection_table); } -static bool is_xdp_frame(void *ptr) -{ - return (unsigned long)ptr & VIRTIO_XDP_FLAG; -} +/* We use the last two bits of the pointer to distinguish the xmit type. */ +#define VIRTNET_XMIT_TYPE_MASK (BIT(0) | BIT(1)) + +#define VIRTIO_XSK_FLAG_OFFSET 2 -static void *xdp_to_ptr(struct xdp_frame *ptr) +static enum virtnet_xmit_type virtnet_xmit_ptr_unpack(void **ptr) { - return (void *)((unsigned long)ptr | VIRTIO_XDP_FLAG); + unsigned long p = (unsigned long)*ptr; + + *ptr = (void *)(p & ~VIRTNET_XMIT_TYPE_MASK); + + return p & VIRTNET_XMIT_TYPE_MASK; } -static struct xdp_frame *ptr_to_xdp(void *ptr) +static void *virtnet_xmit_ptr_pack(void *ptr, enum virtnet_xmit_type type) { - return (struct xdp_frame *)((unsigned long)ptr & ~VIRTIO_XDP_FLAG); + return (void *)((unsigned long)ptr | type); } -static bool is_orphan_skb(void *ptr) +static int virtnet_add_outbuf(struct send_queue *sq, int num, void *data, + enum virtnet_xmit_type type) { - return (unsigned long)ptr & VIRTIO_ORPHAN_FLAG; + return virtqueue_add_outbuf(sq->vq, sq->sg, num, + virtnet_xmit_ptr_pack(data, type), + GFP_ATOMIC); } -static void *skb_to_ptr(struct sk_buff *skb, bool orphan) +static u32 virtnet_ptr_to_xsk_buff_len(void *ptr) { - return (void *)((unsigned long)skb | (orphan ? VIRTIO_ORPHAN_FLAG : 0)); + return ((unsigned long)ptr) >> VIRTIO_XSK_FLAG_OFFSET; } -static struct sk_buff *ptr_to_skb(void *ptr) +static void sg_fill_dma(struct scatterlist *sg, dma_addr_t addr, u32 len) { - return (struct sk_buff *)((unsigned long)ptr & ~VIRTIO_ORPHAN_FLAG); + sg_dma_address(sg) = addr; + sg_dma_len(sg) = len; } static void __free_old_xmit(struct send_queue *sq, struct netdev_queue *txq, bool in_napi, struct virtnet_sq_free_stats *stats) { + struct xdp_frame *frame; + struct sk_buff *skb; unsigned int len; void *ptr; while ((ptr = virtqueue_get_buf(sq->vq, &len)) != NULL) { - if (!is_xdp_frame(ptr)) { - struct sk_buff *skb = ptr_to_skb(ptr); + switch (virtnet_xmit_ptr_unpack(&ptr)) { + case VIRTNET_XMIT_TYPE_SKB: + skb = ptr; pr_debug("Sent skb %p\n", skb); + stats->napi_packets++; + stats->napi_bytes += skb->len; + napi_consume_skb(skb, in_napi); + break; - if (is_orphan_skb(ptr)) { - stats->packets++; - stats->bytes += skb->len; - } else { - stats->napi_packets++; - stats->napi_bytes += skb->len; - } + case VIRTNET_XMIT_TYPE_SKB_ORPHAN: + skb = ptr; + + stats->packets++; + stats->bytes += skb->len; napi_consume_skb(skb, in_napi); - } else { - struct xdp_frame *frame = ptr_to_xdp(ptr); + break; + + case VIRTNET_XMIT_TYPE_XDP: + frame = ptr; stats->packets++; stats->bytes += xdp_get_frame_len(frame); xdp_return_frame(frame); + break; + + case VIRTNET_XMIT_TYPE_XSK: + stats->bytes += virtnet_ptr_to_xsk_buff_len(ptr); + stats->xsk++; + break; } } netdev_tx_completed_queue(txq, stats->napi_packets, stats->napi_bytes); } +static void virtnet_free_old_xmit(struct send_queue *sq, + struct netdev_queue *txq, + bool in_napi, + struct virtnet_sq_free_stats *stats) +{ + __free_old_xmit(sq, txq, in_napi, stats); + + if (stats->xsk) + virtnet_xsk_completed(sq, stats->xsk); +} + /* Converting between virtqueue no. and kernel tx/rx queue no. * 0:rx0 1:tx0 2:rx1 3:tx1 ... 2N:rxN 2N+1:txN 2N+2:cvq */ @@ -876,11 +918,14 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi, static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len) { + struct virtnet_info *vi = rq->vq->vdev->priv; struct page *page = virt_to_head_page(buf); struct virtnet_rq_dma *dma; void *head; int offset; + BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs); + head = page_address(page); dma = head; @@ -905,10 +950,13 @@ static void virtnet_rq_unmap(struct receive_queue *rq, void *buf, u32 len) static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx) { + struct virtnet_info *vi = rq->vq->vdev->priv; void *buf; + BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs); + buf = virtqueue_get_buf_ctx(rq->vq, len, ctx); - if (buf && rq->do_dma) + if (buf) virtnet_rq_unmap(rq, buf, *len); return buf; @@ -916,15 +964,13 @@ static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx) static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len) { + struct virtnet_info *vi = rq->vq->vdev->priv; struct virtnet_rq_dma *dma; dma_addr_t addr; u32 offset; void *head; - if (!rq->do_dma) { - sg_init_one(rq->sg, buf, len); - return; - } + BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs); head = page_address(rq->alloc_frag.page); @@ -935,60 +981,57 @@ static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len) addr = dma->addr - sizeof(*dma) + offset; sg_init_table(rq->sg, 1); - rq->sg[0].dma_address = addr; - rq->sg[0].length = len; + sg_fill_dma(rq->sg, addr, len); } static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp) { struct page_frag *alloc_frag = &rq->alloc_frag; + struct virtnet_info *vi = rq->vq->vdev->priv; struct virtnet_rq_dma *dma; void *buf, *head; dma_addr_t addr; - if (unlikely(!skb_page_frag_refill(size, alloc_frag, gfp))) - return NULL; + BUG_ON(vi->big_packets && !vi->mergeable_rx_bufs); head = page_address(alloc_frag->page); - if (rq->do_dma) { - dma = head; - - /* new pages */ - if (!alloc_frag->offset) { - if (rq->last_dma) { - /* Now, the new page is allocated, the last dma - * will not be used. So the dma can be unmapped - * if the ref is 0. - */ - virtnet_rq_unmap(rq, rq->last_dma, 0); - rq->last_dma = NULL; - } + dma = head; - dma->len = alloc_frag->size - sizeof(*dma); + /* new pages */ + if (!alloc_frag->offset) { + if (rq->last_dma) { + /* Now, the new page is allocated, the last dma + * will not be used. So the dma can be unmapped + * if the ref is 0. + */ + virtnet_rq_unmap(rq, rq->last_dma, 0); + rq->last_dma = NULL; + } - addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1, - dma->len, DMA_FROM_DEVICE, 0); - if (virtqueue_dma_mapping_error(rq->vq, addr)) - return NULL; + dma->len = alloc_frag->size - sizeof(*dma); - dma->addr = addr; - dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr); + addr = virtqueue_dma_map_single_attrs(rq->vq, dma + 1, + dma->len, DMA_FROM_DEVICE, 0); + if (virtqueue_dma_mapping_error(rq->vq, addr)) + return NULL; - /* Add a reference to dma to prevent the entire dma from - * being released during error handling. This reference - * will be freed after the pages are no longer used. - */ - get_page(alloc_frag->page); - dma->ref = 1; - alloc_frag->offset = sizeof(*dma); + dma->addr = addr; + dma->need_sync = virtqueue_dma_need_sync(rq->vq, addr); - rq->last_dma = dma; - } + /* Add a reference to dma to prevent the entire dma from + * being released during error handling. This reference + * will be freed after the pages are no longer used. + */ + get_page(alloc_frag->page); + dma->ref = 1; + alloc_frag->offset = sizeof(*dma); - ++dma->ref; + rq->last_dma = dma; } + ++dma->ref; + buf = head + alloc_frag->offset; get_page(alloc_frag->page); @@ -1010,7 +1053,7 @@ static void virtnet_rq_unmap_free_buf(struct virtqueue *vq, void *buf) return; } - if (rq->do_dma) + if (!vi->big_packets || vi->mergeable_rx_bufs) virtnet_rq_unmap(rq, buf, 0); virtnet_rq_free_buf(vi, rq, buf); @@ -1021,7 +1064,7 @@ static void free_old_xmit(struct send_queue *sq, struct netdev_queue *txq, { struct virtnet_sq_free_stats stats = {0}; - __free_old_xmit(sq, txq, in_napi, &stats); + virtnet_free_old_xmit(sq, txq, in_napi, &stats); /* Avoid overhead when no packets have been processed * happens when called speculatively from start_xmit. @@ -1088,12 +1131,6 @@ static void check_sq_full_and_disable(struct virtnet_info *vi, } } -static void sg_fill_dma(struct scatterlist *sg, dma_addr_t addr, u32 len) -{ - sg->dma_address = addr; - sg->length = len; -} - static struct xdp_buff *buf_to_xdp(struct virtnet_info *vi, struct receive_queue *rq, void *buf, u32 len) { @@ -1374,7 +1411,8 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue sg_init_table(rq->sg, 1); sg_fill_dma(rq->sg, addr, len); - err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, xsk_buffs[i], gfp); + err = virtqueue_add_inbuf_premapped(rq->vq, rq->sg, 1, + xsk_buffs[i], NULL, gfp); if (err) goto err; } @@ -1388,6 +1426,120 @@ static int virtnet_add_recvbuf_xsk(struct virtnet_info *vi, struct receive_queue return err; } +static void *virtnet_xsk_to_ptr(u32 len) +{ + unsigned long p; + + p = len << VIRTIO_XSK_FLAG_OFFSET; + + return virtnet_xmit_ptr_pack((void *)p, VIRTNET_XMIT_TYPE_XSK); +} + +static int virtnet_xsk_xmit_one(struct send_queue *sq, + struct xsk_buff_pool *pool, + struct xdp_desc *desc) +{ + struct virtnet_info *vi; + dma_addr_t addr; + + vi = sq->vq->vdev->priv; + + addr = xsk_buff_raw_get_dma(pool, desc->addr); + xsk_buff_raw_dma_sync_for_device(pool, addr, desc->len); + + sg_init_table(sq->sg, 2); + sg_fill_dma(sq->sg, sq->xsk_hdr_dma_addr, vi->hdr_len); + sg_fill_dma(sq->sg + 1, addr, desc->len); + + return virtqueue_add_outbuf_premapped(sq->vq, sq->sg, 2, + virtnet_xsk_to_ptr(desc->len), + GFP_ATOMIC); +} + +static int virtnet_xsk_xmit_batch(struct send_queue *sq, + struct xsk_buff_pool *pool, + unsigned int budget, + u64 *kicks) +{ + struct xdp_desc *descs = pool->tx_descs; + bool kick = false; + u32 nb_pkts, i; + int err; + + budget = min_t(u32, budget, sq->vq->num_free); + + nb_pkts = xsk_tx_peek_release_desc_batch(pool, budget); + if (!nb_pkts) + return 0; + + for (i = 0; i < nb_pkts; i++) { + err = virtnet_xsk_xmit_one(sq, pool, &descs[i]); + if (unlikely(err)) { + xsk_tx_completed(sq->xsk_pool, nb_pkts - i); + break; + } + + kick = true; + } + + if (kick && virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) + (*kicks)++; + + return i; +} + +static bool virtnet_xsk_xmit(struct send_queue *sq, struct xsk_buff_pool *pool, + int budget) +{ + struct virtnet_info *vi = sq->vq->vdev->priv; + struct virtnet_sq_free_stats stats = {}; + struct net_device *dev = vi->dev; + u64 kicks = 0; + int sent; + + /* Avoid to wakeup napi meanless, so call __free_old_xmit instead of + * free_old_xmit(). + */ + __free_old_xmit(sq, netdev_get_tx_queue(dev, sq - vi->sq), true, &stats); + + if (stats.xsk) + xsk_tx_completed(sq->xsk_pool, stats.xsk); + + sent = virtnet_xsk_xmit_batch(sq, pool, budget, &kicks); + + if (!is_xdp_raw_buffer_queue(vi, sq - vi->sq)) + check_sq_full_and_disable(vi, vi->dev, sq); + + if (sent) { + struct netdev_queue *txq; + + txq = netdev_get_tx_queue(vi->dev, sq - vi->sq); + txq_trans_cond_update(txq); + } + + u64_stats_update_begin(&sq->stats.syncp); + u64_stats_add(&sq->stats.packets, stats.packets); + u64_stats_add(&sq->stats.bytes, stats.bytes); + u64_stats_add(&sq->stats.kicks, kicks); + u64_stats_add(&sq->stats.xdp_tx, sent); + u64_stats_update_end(&sq->stats.syncp); + + if (xsk_uses_need_wakeup(pool)) + xsk_set_tx_need_wakeup(pool); + + return sent; +} + +static void xsk_wakeup(struct send_queue *sq) +{ + if (napi_if_scheduled_mark_missed(&sq->napi)) + return; + + local_bh_disable(); + virtqueue_napi_schedule(&sq->napi, sq->vq); + local_bh_enable(); +} + static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag) { struct virtnet_info *vi = netdev_priv(dev); @@ -1401,14 +1553,19 @@ static int virtnet_xsk_wakeup(struct net_device *dev, u32 qid, u32 flag) sq = &vi->sq[qid]; - if (napi_if_scheduled_mark_missed(&sq->napi)) - return 0; + xsk_wakeup(sq); + return 0; +} - local_bh_disable(); - virtqueue_napi_schedule(&sq->napi, sq->vq); - local_bh_enable(); +static void virtnet_xsk_completed(struct send_queue *sq, int num) +{ + xsk_tx_completed(sq->xsk_pool, num); - return 0; + /* If this is called by rx poll, start_xmit and xdp xmit we should + * wakeup the tx napi to consume the xsk tx queue, because the tx + * interrupt may not be triggered. + */ + xsk_wakeup(sq); } static int __virtnet_xdp_xmit_one(struct virtnet_info *vi, @@ -1451,8 +1608,7 @@ static int __virtnet_xdp_xmit_one(struct virtnet_info *vi, skb_frag_size(frag), skb_frag_off(frag)); } - err = virtqueue_add_outbuf(sq->vq, sq->sg, nr_frags + 1, - xdp_to_ptr(xdpf), GFP_ATOMIC); + err = virtnet_add_outbuf(sq, nr_frags + 1, xdpf, VIRTNET_XMIT_TYPE_XDP); if (unlikely(err)) return -ENOSPC; /* Caller handle free/refcnt */ @@ -1525,8 +1681,8 @@ static int virtnet_xdp_xmit(struct net_device *dev, } /* Free up any pending old buffers before queueing new ones. */ - __free_old_xmit(sq, netdev_get_tx_queue(dev, sq - vi->sq), - false, &stats); + virtnet_free_old_xmit(sq, netdev_get_tx_queue(dev, sq - vi->sq), + false, &stats); for (i = 0; i < n; i++) { struct xdp_frame *xdpf = frames[i]; @@ -2443,6 +2599,9 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, len = SKB_DATA_ALIGN(len) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + if (unlikely(!skb_page_frag_refill(len, &rq->alloc_frag, gfp))) + return -ENOMEM; + buf = virtnet_rq_alloc(rq, len, gfp); if (unlikely(!buf)) return -ENOMEM; @@ -2451,10 +2610,9 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, virtnet_rq_init_one_sg(rq, buf, vi->hdr_len + GOOD_PACKET_LEN); - err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp); + err = virtqueue_add_inbuf_premapped(rq->vq, rq->sg, 1, buf, ctx, gfp); if (err < 0) { - if (rq->do_dma) - virtnet_rq_unmap(rq, buf, 0); + virtnet_rq_unmap(rq, buf, 0); put_page(virt_to_head_page(buf)); } @@ -2545,6 +2703,12 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, */ len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len, room); + if (unlikely(!skb_page_frag_refill(len + room, alloc_frag, gfp))) + return -ENOMEM; + + if (!alloc_frag->offset && len + room + sizeof(struct virtnet_rq_dma) > alloc_frag->size) + len -= sizeof(struct virtnet_rq_dma); + buf = virtnet_rq_alloc(rq, len + room, gfp); if (unlikely(!buf)) return -ENOMEM; @@ -2566,10 +2730,9 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, virtnet_rq_init_one_sg(rq, buf, len); ctx = mergeable_len_to_ctx(len + room, headroom); - err = virtqueue_add_inbuf_ctx(rq->vq, rq->sg, 1, buf, ctx, gfp); + err = virtqueue_add_inbuf_premapped(rq->vq, rq->sg, 1, buf, ctx, gfp); if (err < 0) { - if (rq->do_dma) - virtnet_rq_unmap(rq, buf, 0); + virtnet_rq_unmap(rq, buf, 0); put_page(virt_to_head_page(buf)); } @@ -2726,7 +2889,7 @@ static int virtnet_receive_packets(struct virtnet_info *vi, } } else { while (packets < budget && - (buf = virtnet_rq_get_buf(rq, &len, NULL)) != NULL) { + (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) { receive_buf(vi, rq, buf, len, NULL, xdp_xmit, stats); packets++; } @@ -2824,7 +2987,7 @@ static void virtnet_rx_dim_update(struct virtnet_info *vi, struct receive_queue u64_stats_read(&rq->stats.bytes), &cur_sample); - net_dim(&rq->dim, cur_sample); + net_dim(&rq->dim, &cur_sample); rq->packets_in_napi = 0; } @@ -2892,7 +3055,6 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index) if (err < 0) goto err_xdp_reg_mem_model; - netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, qp_index)); 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); @@ -2976,7 +3138,7 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) struct virtnet_info *vi = sq->vq->vdev->priv; unsigned int index = vq2txq(sq->vq); struct netdev_queue *txq; - int opaque; + int opaque, xsk_done = 0; bool done; if (unlikely(is_xdp_raw_buffer_queue(vi, index))) { @@ -2988,7 +3150,11 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) txq = netdev_get_tx_queue(vi->dev, index); __netif_tx_lock(txq, raw_smp_processor_id()); virtqueue_disable_cb(sq->vq); - free_old_xmit(sq, txq, !!budget); + + if (sq->xsk_pool) + xsk_done = virtnet_xsk_xmit(sq, sq->xsk_pool, budget); + else + free_old_xmit(sq, txq, !!budget); if (sq->vq->num_free >= 2 + MAX_SKB_FRAGS) { if (netif_tx_queue_stopped(txq)) { @@ -2999,6 +3165,11 @@ static int virtnet_poll_tx(struct napi_struct *napi, int budget) netif_tx_wake_queue(txq); } + if (xsk_done >= budget) { + __netif_tx_unlock(txq); + return budget; + } + opaque = virtqueue_enable_cb_prepare(sq->vq); done = napi_complete_done(napi, 0); @@ -3066,8 +3237,9 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan) return num_sg; num_sg++; } - return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, - skb_to_ptr(skb, orphan), GFP_ATOMIC); + + return virtnet_add_outbuf(sq, num_sg, skb, + orphan ? VIRTNET_XMIT_TYPE_SKB_ORPHAN : VIRTNET_XMIT_TYPE_SKB); } static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -3160,7 +3332,7 @@ static int virtnet_rx_resize(struct virtnet_info *vi, virtnet_rx_pause(vi, rq); - err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf); + err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf, NULL); if (err) netdev_err(vi->dev, "resize rx fail: rx queue index: %d err: %d\n", qindex, err); @@ -3223,7 +3395,8 @@ static int virtnet_tx_resize(struct virtnet_info *vi, struct send_queue *sq, virtnet_tx_pause(vi, sq); - err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf); + err = virtqueue_resize(sq->vq, ring_num, virtnet_sq_free_unused_buf, + virtnet_sq_free_unused_buf_done); if (err) netdev_err(vi->dev, "resize tx fail: tx queue index: %d err: %d\n", qindex, err); @@ -5072,7 +5245,7 @@ static int virtnet_set_coalesce(struct net_device *dev, struct netlink_ext_ack *extack) { struct virtnet_info *vi = netdev_priv(dev); - int ret, queue_number, napi_weight; + int ret, queue_number, napi_weight, i; bool update_napi = false; /* Can't change NAPI weight if the link is up */ @@ -5101,6 +5274,14 @@ static int virtnet_set_coalesce(struct net_device *dev, return ret; if (update_napi) { + /* xsk xmit depends on the tx napi. So if xsk is active, + * prevent modifications to tx napi. + */ + for (i = queue_number; i < vi->max_queue_pairs; i++) { + if (vi->sq[i].xsk_pool) + return -EBUSY; + } + for (; queue_number < vi->max_queue_pairs; queue_number++) vi->sq[queue_number].napi.weight = napi_weight; } @@ -5530,7 +5711,7 @@ static int virtnet_rq_bind_xsk_pool(struct virtnet_info *vi, struct receive_queu virtnet_rx_pause(vi, rq); - err = virtqueue_reset(rq->vq, virtnet_rq_unmap_free_buf); + err = virtqueue_reset(rq->vq, virtnet_rq_unmap_free_buf, NULL); if (err) { netdev_err(vi->dev, "reset rx fail: rx queue index: %d err: %d\n", qindex, err); @@ -5549,6 +5730,30 @@ static int virtnet_rq_bind_xsk_pool(struct virtnet_info *vi, struct receive_queu return err; } +static int virtnet_sq_bind_xsk_pool(struct virtnet_info *vi, + struct send_queue *sq, + struct xsk_buff_pool *pool) +{ + int err, qindex; + + qindex = sq - vi->sq; + + virtnet_tx_pause(vi, sq); + + err = virtqueue_reset(sq->vq, virtnet_sq_free_unused_buf, + virtnet_sq_free_unused_buf_done); + if (err) { + netdev_err(vi->dev, "reset tx fail: tx queue index: %d err: %d\n", qindex, err); + pool = NULL; + } + + sq->xsk_pool = pool; + + virtnet_tx_resume(vi, sq); + + return err; +} + static int virtnet_xsk_pool_enable(struct net_device *dev, struct xsk_buff_pool *pool, u16 qid) @@ -5557,6 +5762,7 @@ static int virtnet_xsk_pool_enable(struct net_device *dev, struct receive_queue *rq; struct device *dma_dev; struct send_queue *sq; + dma_addr_t hdr_dma; int err, size; if (vi->hdr_len > xsk_pool_get_headroom(pool)) @@ -5594,6 +5800,11 @@ static int virtnet_xsk_pool_enable(struct net_device *dev, if (!rq->xsk_buffs) return -ENOMEM; + hdr_dma = virtqueue_dma_map_single_attrs(sq->vq, &xsk_hdr, vi->hdr_len, + DMA_TO_DEVICE, 0); + if (virtqueue_dma_mapping_error(sq->vq, hdr_dma)) + return -ENOMEM; + err = xsk_pool_dma_map(pool, dma_dev, 0); if (err) goto err_xsk_map; @@ -5602,11 +5813,24 @@ static int virtnet_xsk_pool_enable(struct net_device *dev, if (err) goto err_rq; + err = virtnet_sq_bind_xsk_pool(vi, sq, pool); + if (err) + goto err_sq; + + /* Now, we do not support tx offload(such as tx csum), so all the tx + * virtnet hdr is zero. So all the tx packets can share a single hdr. + */ + sq->xsk_hdr_dma_addr = hdr_dma; + return 0; +err_sq: + virtnet_rq_bind_xsk_pool(vi, rq, NULL); err_rq: xsk_pool_dma_unmap(pool, 0); err_xsk_map: + virtqueue_dma_unmap_single_attrs(rq->vq, hdr_dma, vi->hdr_len, + DMA_TO_DEVICE, 0); return err; } @@ -5615,19 +5839,24 @@ static int virtnet_xsk_pool_disable(struct net_device *dev, u16 qid) struct virtnet_info *vi = netdev_priv(dev); struct xsk_buff_pool *pool; struct receive_queue *rq; + struct send_queue *sq; int err; if (qid >= vi->curr_queue_pairs) return -EINVAL; + sq = &vi->sq[qid]; rq = &vi->rq[qid]; pool = rq->xsk_pool; err = virtnet_rq_bind_xsk_pool(vi, rq, NULL); + err |= virtnet_sq_bind_xsk_pool(vi, sq, NULL); xsk_pool_dma_unmap(pool, 0); + virtqueue_dma_unmap_single_attrs(sq->vq, sq->xsk_hdr_dma_addr, + vi->hdr_len, DMA_TO_DEVICE, 0); kvfree(rq->xsk_buffs); return err; @@ -5977,7 +6206,7 @@ static void free_receive_page_frags(struct virtnet_info *vi) int i; for (i = 0; i < vi->max_queue_pairs; i++) if (vi->rq[i].alloc_frag.page) { - if (vi->rq[i].do_dma && vi->rq[i].last_dma) + if (vi->rq[i].last_dma) virtnet_rq_unmap(&vi->rq[i], vi->rq[i].last_dma, 0); put_page(vi->rq[i].alloc_frag.page); } @@ -5985,10 +6214,34 @@ static void free_receive_page_frags(struct virtnet_info *vi) static void virtnet_sq_free_unused_buf(struct virtqueue *vq, void *buf) { - if (!is_xdp_frame(buf)) + struct virtnet_info *vi = vq->vdev->priv; + struct send_queue *sq; + int i = vq2txq(vq); + + sq = &vi->sq[i]; + + switch (virtnet_xmit_ptr_unpack(&buf)) { + case VIRTNET_XMIT_TYPE_SKB: + case VIRTNET_XMIT_TYPE_SKB_ORPHAN: dev_kfree_skb(buf); - else - xdp_return_frame(ptr_to_xdp(buf)); + break; + + case VIRTNET_XMIT_TYPE_XDP: + xdp_return_frame(buf); + break; + + case VIRTNET_XMIT_TYPE_XSK: + xsk_tx_completed(sq->xsk_pool, 1); + break; + } +} + +static void virtnet_sq_free_unused_buf_done(struct virtqueue *vq) +{ + struct virtnet_info *vi = vq->vdev->priv; + int i = vq2txq(vq); + + netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, i)); } static void free_unused_bufs(struct virtnet_info *vi) @@ -6436,7 +6689,8 @@ static int virtnet_probe(struct virtio_device *vdev) dev->hw_features |= NETIF_F_GRO_HW; dev->vlan_features = dev->features; - dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT; + dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_XSK_ZEROCOPY; /* MTU range: 68 - 65535 */ dev->min_mtu = MIN_MTU; @@ -6722,11 +6976,20 @@ static int virtnet_probe(struct virtio_device *vdev) static void remove_vq_common(struct virtnet_info *vi) { + int i; + virtio_reset_device(vi->vdev); /* Free unused buffers in both send and recv, if any. */ free_unused_bufs(vi); + /* + * Rule of thumb is netdev_tx_reset_queue() should follow any + * skb freeing not followed by netdev_tx_completed_queue() + */ + for (i = 0; i < vi->max_queue_pairs; i++) + netdev_tx_reset_queue(netdev_get_tx_queue(vi->dev, i)); + free_receive_bufs(vi); free_receive_page_frags(vi); diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index b70654c7ad34ea..6793fa09f9d1ad 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -201,6 +201,14 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue) adapter->link_speed = ret >> 16; if (ret & 1) { /* Link is up. */ + /* + * From vmxnet3 v9, the hypervisor reports the speed in Gbps. + * Convert the speed to Mbps before rporting it to the kernel. + * Max link speed supported is 10000G. + */ + if (VMXNET3_VERSION_GE_9(adapter) && + adapter->link_speed < 10000) + adapter->link_speed = adapter->link_speed * 1000; netdev_info(adapter->netdev, "NIC Link is Up %d Mbps\n", adapter->link_speed); netif_carrier_on(adapter->netdev); diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 4087f72f0d2be8..67d25f4f94efff 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -521,7 +521,7 @@ static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb, /* needed to match OIF rule */ fl4.flowi4_l3mdev = vrf_dev->ifindex; fl4.flowi4_iif = LOOPBACK_IFINDEX; - fl4.flowi4_tos = ip4h->tos & INET_DSCP_MASK; + fl4.flowi4_tos = inet_dscp_to_dsfield(ip4h_dscp(ip4h)); fl4.flowi4_flags = FLOWI_FLAG_ANYSRC; fl4.flowi4_proto = ip4h->protocol; fl4.daddr = ip4h->daddr; diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 6e9a3795846aa3..9ea63059d52d75 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -1232,10 +1232,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, *ifindex = 0; } - if (tb[NDA_NH_ID]) - *nhid = nla_get_u32(tb[NDA_NH_ID]); - else - *nhid = 0; + *nhid = nla_get_u32_default(tb[NDA_NH_ID], 0); return 0; } @@ -1244,7 +1241,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid, u16 flags, - struct netlink_ext_ack *extack) + bool *notified, struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan = netdev_priv(dev); /* struct net *net = dev_net(vxlan->dev); */ @@ -1280,6 +1277,9 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], nhid, true, extack); spin_unlock_bh(&vxlan->hash_lock[hash_index]); + if (!err) + *notified = true; + return err; } @@ -1319,7 +1319,7 @@ int __vxlan_fdb_delete(struct vxlan_dev *vxlan, /* Delete entry (via netlink) */ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, - const unsigned char *addr, u16 vid, + const unsigned char *addr, u16 vid, bool *notified, struct netlink_ext_ack *extack) { struct vxlan_dev *vxlan = netdev_priv(dev); @@ -1341,6 +1341,9 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], true); spin_unlock_bh(&vxlan->hash_lock[hash_index]); + if (!err) + *notified = true; + return err; } @@ -1435,11 +1438,11 @@ static int vxlan_fdb_get(struct sk_buff *skb, /* Watch incoming packets to learn mapping between Ethernet address * and Tunnel endpoint. - * Return true if packet is bogus and should be dropped. */ -static bool vxlan_snoop(struct net_device *dev, - union vxlan_addr *src_ip, const u8 *src_mac, - u32 src_ifindex, __be32 vni) +static enum skb_drop_reason vxlan_snoop(struct net_device *dev, + union vxlan_addr *src_ip, + const u8 *src_mac, u32 src_ifindex, + __be32 vni) { struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_fdb *f; @@ -1447,7 +1450,7 @@ static bool vxlan_snoop(struct net_device *dev, /* Ignore packets from invalid src-address */ if (!is_valid_ether_addr(src_mac)) - return true; + return SKB_DROP_REASON_MAC_INVALID_SOURCE; #if IS_ENABLED(CONFIG_IPV6) if (src_ip->sa.sa_family == AF_INET6 && @@ -1461,15 +1464,15 @@ static bool vxlan_snoop(struct net_device *dev, if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip) && rdst->remote_ifindex == ifindex)) - return false; + return SKB_NOT_DROPPED_YET; /* Don't migrate static entries, drop packets */ if (f->state & (NUD_PERMANENT | NUD_NOARP)) - return true; + return SKB_DROP_REASON_VXLAN_ENTRY_EXISTS; /* Don't override an fdb with nexthop with a learnt entry */ if (rcu_access_pointer(f->nh)) - return true; + return SKB_DROP_REASON_VXLAN_ENTRY_EXISTS; if (net_ratelimit()) netdev_info(dev, @@ -1497,7 +1500,7 @@ static bool vxlan_snoop(struct net_device *dev, spin_unlock(&vxlan->hash_lock[hash_index]); } - return false; + return SKB_NOT_DROPPED_YET; } static bool __vxlan_sock_release_prep(struct vxlan_sock *vs) @@ -1551,9 +1554,11 @@ static void vxlan_sock_release(struct vxlan_dev *vxlan) #endif } -static bool vxlan_remcsum(struct vxlanhdr *unparsed, - struct sk_buff *skb, u32 vxflags) +static enum skb_drop_reason vxlan_remcsum(struct vxlanhdr *unparsed, + struct sk_buff *skb, + u32 vxflags) { + enum skb_drop_reason reason; size_t start, offset; if (!(unparsed->vx_flags & VXLAN_HF_RCO) || skb->remcsum_offload) @@ -1562,15 +1567,17 @@ static bool vxlan_remcsum(struct vxlanhdr *unparsed, start = vxlan_rco_start(unparsed->vx_vni); offset = start + vxlan_rco_offset(unparsed->vx_vni); - if (!pskb_may_pull(skb, offset + sizeof(u16))) - return false; + reason = pskb_may_pull_reason(skb, offset + sizeof(u16)); + if (reason) + return reason; skb_remcsum_process(skb, (void *)(vxlan_hdr(skb) + 1), start, offset, !!(vxflags & VXLAN_F_REMCSUM_NOPARTIAL)); out: unparsed->vx_flags &= ~VXLAN_HF_RCO; unparsed->vx_vni &= VXLAN_VNI_MASK; - return true; + + return SKB_NOT_DROPPED_YET; } static void vxlan_parse_gbp_hdr(struct vxlanhdr *unparsed, @@ -1604,9 +1611,9 @@ static void vxlan_parse_gbp_hdr(struct vxlanhdr *unparsed, unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS; } -static bool vxlan_set_mac(struct vxlan_dev *vxlan, - struct vxlan_sock *vs, - struct sk_buff *skb, __be32 vni) +static enum skb_drop_reason vxlan_set_mac(struct vxlan_dev *vxlan, + struct vxlan_sock *vs, + struct sk_buff *skb, __be32 vni) { union vxlan_addr saddr; u32 ifindex = skb->dev->ifindex; @@ -1617,7 +1624,7 @@ static bool vxlan_set_mac(struct vxlan_dev *vxlan, /* Ignore packet loops (and multicast echo) */ if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) - return false; + return SKB_DROP_REASON_LOCAL_MAC; /* Get address from the outer IP header */ if (vxlan_get_sk_family(vs) == AF_INET) { @@ -1630,11 +1637,11 @@ static bool vxlan_set_mac(struct vxlan_dev *vxlan, #endif } - if ((vxlan->cfg.flags & VXLAN_F_LEARN) && - vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, ifindex, vni)) - return false; + if (!(vxlan->cfg.flags & VXLAN_F_LEARN)) + return SKB_NOT_DROPPED_YET; - return true; + return vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source, + ifindex, vni); } static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph, @@ -1671,13 +1678,15 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) struct vxlan_metadata _md; struct vxlan_metadata *md = &_md; __be16 protocol = htons(ETH_P_TEB); + enum skb_drop_reason reason; bool raw_proto = false; void *oiph; __be32 vni = 0; int nh; /* Need UDP and VXLAN header to be present */ - if (!pskb_may_pull(skb, VXLAN_HLEN)) + reason = pskb_may_pull_reason(skb, VXLAN_HLEN); + if (reason) goto drop; unparsed = *vxlan_hdr(skb); @@ -1686,6 +1695,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n", ntohl(vxlan_hdr(skb)->vx_flags), ntohl(vxlan_hdr(skb)->vx_vni)); + reason = SKB_DROP_REASON_VXLAN_INVALID_HDR; /* Return non vxlan pkt */ goto drop; } @@ -1699,8 +1709,10 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) vni = vxlan_vni(vxlan_hdr(skb)->vx_vni); vxlan = vxlan_vs_find_vni(vs, skb->dev->ifindex, vni, &vninode); - if (!vxlan) + if (!vxlan) { + reason = SKB_DROP_REASON_VXLAN_VNI_NOT_FOUND; goto drop; + } /* For backwards compatibility, only allow reserved fields to be * used by VXLAN extensions if explicitly requested. @@ -1713,12 +1725,16 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) } if (__iptunnel_pull_header(skb, VXLAN_HLEN, protocol, raw_proto, - !net_eq(vxlan->net, dev_net(vxlan->dev)))) + !net_eq(vxlan->net, dev_net(vxlan->dev)))) { + reason = SKB_DROP_REASON_NOMEM; goto drop; + } - if (vs->flags & VXLAN_F_REMCSUM_RX) - if (unlikely(!vxlan_remcsum(&unparsed, skb, vs->flags))) + if (vs->flags & VXLAN_F_REMCSUM_RX) { + reason = vxlan_remcsum(&unparsed, skb, vs->flags); + if (unlikely(reason)) goto drop; + } if (vxlan_collect_metadata(vs)) { IP_TUNNEL_DECLARE_FLAGS(flags) = { }; @@ -1728,8 +1744,10 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) tun_dst = udp_tun_rx_dst(skb, vxlan_get_sk_family(vs), flags, key32_to_tunnel_id(vni), sizeof(*md)); - if (!tun_dst) + if (!tun_dst) { + reason = SKB_DROP_REASON_NOMEM; goto drop; + } md = ip_tunnel_info_opts(&tun_dst->u.tun_info); @@ -1753,11 +1771,13 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) * is more robust and provides a little more security in * adding extensions to VXLAN. */ + reason = SKB_DROP_REASON_VXLAN_INVALID_HDR; goto drop; } if (!raw_proto) { - if (!vxlan_set_mac(vxlan, vs, skb, vni)) + reason = vxlan_set_mac(vxlan, vs, skb, vni); + if (reason) goto drop; } else { skb_reset_mac_header(skb); @@ -1773,7 +1793,8 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) skb_reset_network_header(skb); - if (!pskb_inet_may_pull(skb)) { + reason = pskb_inet_may_pull_reason(skb); + if (reason) { DEV_STATS_INC(vxlan->dev, rx_length_errors); DEV_STATS_INC(vxlan->dev, rx_errors); vxlan_vnifilter_count(vxlan, vni, vninode, @@ -1785,6 +1806,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) oiph = skb->head + nh; if (!vxlan_ecn_decapsulate(vs, oiph, skb)) { + reason = SKB_DROP_REASON_IP_TUNNEL_ECN; DEV_STATS_INC(vxlan->dev, rx_frame_errors); DEV_STATS_INC(vxlan->dev, rx_errors); vxlan_vnifilter_count(vxlan, vni, vninode, @@ -1799,6 +1821,7 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) dev_core_stats_rx_dropped_inc(vxlan->dev); vxlan_vnifilter_count(vxlan, vni, vninode, VXLAN_VNI_STATS_RX_DROPS, 0); + reason = SKB_DROP_REASON_DEV_READY; goto drop; } @@ -1811,8 +1834,9 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb) return 0; drop: + reason = reason ?: SKB_DROP_REASON_NOT_SPECIFIED; /* Consume bad packet */ - kfree_skb(skb); + kfree_skb_reason(skb, reason); return 0; } @@ -2268,7 +2292,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, rcu_read_lock(); dev = skb->dev; if (unlikely(!(dev->flags & IFF_UP))) { - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY); goto drop; } @@ -2319,7 +2343,7 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, DEV_STATS_INC(dev, tx_errors); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0); - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_VNI_NOT_FOUND); return -ENOENT; } @@ -2352,13 +2376,16 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, bool use_cache; bool udp_sum = false; bool xnet = !net_eq(vxlan->net, dev_net(vxlan->dev)); + enum skb_drop_reason reason; bool no_eth_encap; __be32 vni = 0; no_eth_encap = flags & VXLAN_F_GPE && skb->protocol != htons(ETH_P_TEB); - if (!skb_vlan_inet_prepare(skb, no_eth_encap)) + reason = skb_vlan_inet_prepare(skb, no_eth_encap); + if (reason) goto drop; + reason = SKB_DROP_REASON_NOT_SPECIFIED; old_iph = ip_hdr(skb); info = skb_tunnel_info(skb); @@ -2462,6 +2489,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos, use_cache ? dst_cache : NULL); if (IS_ERR(rt)) { err = PTR_ERR(rt); + reason = SKB_DROP_REASON_IP_OUTNOROUTES; goto tx_error; } @@ -2513,8 +2541,10 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), vni, md, flags, udp_sum); - if (err < 0) + if (err < 0) { + reason = SKB_DROP_REASON_NOMEM; goto tx_error; + } udp_tunnel_xmit_skb(rt, sock4->sock->sk, skb, saddr, pkey->u.ipv4.dst, tos, ttl, df, @@ -2534,6 +2564,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, if (IS_ERR(ndst)) { err = PTR_ERR(ndst); ndst = NULL; + reason = SKB_DROP_REASON_IP_OUTNOROUTES; goto tx_error; } @@ -2574,8 +2605,10 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, skb_scrub_packet(skb, xnet); err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), vni, md, flags, udp_sum); - if (err < 0) + if (err < 0) { + reason = SKB_DROP_REASON_NOMEM; goto tx_error; + } udp_tunnel6_xmit_skb(ndst, sock6->sock->sk, skb, dev, &saddr, &pkey->u.ipv6.dst, tos, ttl, @@ -2590,7 +2623,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, drop: dev_core_stats_tx_dropped_inc(dev); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); - dev_kfree_skb(skb); + kfree_skb_reason(skb, reason); return; tx_error: @@ -2602,7 +2635,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dst_release(ndst); DEV_STATS_INC(dev, tx_errors); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0); - kfree_skb(skb); + kfree_skb_reason(skb, reason); } static void vxlan_xmit_nh(struct sk_buff *skb, struct net_device *dev, @@ -2708,7 +2741,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) if (info && info->mode & IP_TUNNEL_INFO_TX) vxlan_xmit_one(skb, dev, vni, NULL, false); else - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_TUNNEL_TXINFO); return NETDEV_TX_OK; } } @@ -2771,7 +2804,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) dev_core_stats_tx_dropped_inc(dev); vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_DROPS, 0); - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_NO_REMOTE); return NETDEV_TX_OK; } } @@ -2794,7 +2827,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) if (fdst) vxlan_xmit_one(skb, dev, vni, fdst, did_rsc); else - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_NO_REMOTE); } return NETDEV_TX_OK; diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c index 60eb95a06d551c..8735891ee1286b 100644 --- a/drivers/net/vxlan/vxlan_mdb.c +++ b/drivers/net/vxlan/vxlan_mdb.c @@ -284,7 +284,7 @@ int vxlan_mdb_dump(struct net_device *dev, struct sk_buff *skb, ASSERT_RTNL(); - NL_ASSERT_DUMP_CTX_FITS(struct vxlan_mdb_dump_ctx); + NL_ASSERT_CTX_FITS(struct vxlan_mdb_dump_ctx); nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, RTM_NEWMDB, sizeof(*bpm), @@ -1712,7 +1712,7 @@ netdev_tx_t vxlan_mdb_xmit(struct vxlan_dev *vxlan, vxlan_xmit_one(skb, vxlan->dev, src_vni, rcu_dereference(fremote->rd), false); else - kfree_skb(skb); + kfree_skb_reason(skb, SKB_DROP_REASON_VXLAN_NO_REMOTE); return NETDEV_TX_OK; } diff --git a/drivers/net/wan/framer/pef2256/pef2256.c b/drivers/net/wan/framer/pef2256/pef2256.c index 413a3c1d15bbe8..1e4c8e85d598d2 100644 --- a/drivers/net/wan/framer/pef2256/pef2256.c +++ b/drivers/net/wan/framer/pef2256/pef2256.c @@ -863,7 +863,7 @@ static struct platform_driver pef2256_driver = { .of_match_table = pef2256_id_table, }, .probe = pef2256_probe, - .remove_new = pef2256_remove, + .remove = pef2256_remove, }; module_platform_driver(pef2256_driver); diff --git a/drivers/net/wan/fsl_qmc_hdlc.c b/drivers/net/wan/fsl_qmc_hdlc.c index 8fcfbde31a1c66..8976dea8e17e2c 100644 --- a/drivers/net/wan/fsl_qmc_hdlc.c +++ b/drivers/net/wan/fsl_qmc_hdlc.c @@ -799,7 +799,7 @@ static struct platform_driver qmc_hdlc_driver = { .of_match_table = qmc_hdlc_id_table, }, .probe = qmc_hdlc_probe, - .remove_new = qmc_hdlc_remove, + .remove = qmc_hdlc_remove, }; module_platform_driver(qmc_hdlc_driver); diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 605e70f7baace4..f999798a561271 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -1290,7 +1290,7 @@ MODULE_DEVICE_TABLE(of, fsl_ucc_hdlc_of_match); static struct platform_driver ucc_hdlc_driver = { .probe = ucc_hdlc_probe, - .remove_new = ucc_hdlc_remove, + .remove = ucc_hdlc_remove, .driver = { .name = DRV_NAME, .pm = HDLC_PM_OPS, diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 931c5ca79ea5e4..720c5dc889ea32 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -1534,7 +1534,7 @@ static void ixp4xx_hss_remove(struct platform_device *pdev) static struct platform_driver ixp4xx_hss_driver = { .driver.name = DRV_NAME, .probe = ixp4xx_hss_probe, - .remove_new = ixp4xx_hss_remove, + .remove = ixp4xx_hss_remove, }; module_platform_driver(ixp4xx_hss_driver); diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c index 45e9b908dbfb05..6cf173a008e782 100644 --- a/drivers/net/wireguard/device.c +++ b/drivers/net/wireguard/device.c @@ -302,7 +302,8 @@ static void wg_setup(struct net_device *dev) /* We need to keep the dst around in case of icmp replies. */ netif_keep_dst(dev); - memset(wg, 0, sizeof(*wg)); + netif_set_tso_max_size(dev, GSO_MAX_SIZE); + wg->dev = dev; } diff --git a/drivers/net/wireguard/selftest/allowedips.c b/drivers/net/wireguard/selftest/allowedips.c index 3d1f64ff2e1225..25de7058701a2f 100644 --- a/drivers/net/wireguard/selftest/allowedips.c +++ b/drivers/net/wireguard/selftest/allowedips.c @@ -383,7 +383,6 @@ static __init bool randomized_test(void) for (i = 0; i < NUM_QUERIES; ++i) { get_random_bytes(ip, 4); if (lookup(t.root4, 32, ip) != horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) { - horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip); pr_err("allowedips random v4 self-test: FAIL\n"); goto free; } diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index f0441b3d7dcb40..db9f9ebcb62d20 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -837,12 +837,12 @@ static void ath10k_ahb_remove(struct platform_device *pdev) } static struct platform_driver ath10k_ahb_driver = { - .driver = { - .name = "ath10k_ahb", + .driver = { + .name = "ath10k_ahb", .of_match_table = ath10k_ahb_of_match, }, - .probe = ath10k_ahb_probe, - .remove_new = ath10k_ahb_remove, + .probe = ath10k_ahb_probe, + .remove = ath10k_ahb_remove, }; int ath10k_ahb_init(void) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 646e1737d4c47c..c61b95a928dac1 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6369,7 +6369,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; struct cfg80211_scan_request *req = &hw_req->req; - struct wmi_start_scan_arg arg; + struct wmi_start_scan_arg *arg = NULL; int ret = 0; int i; u32 scan_timeout; @@ -6402,56 +6402,61 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, if (ret) goto exit; - memset(&arg, 0, sizeof(arg)); - ath10k_wmi_start_scan_init(ar, &arg); - arg.vdev_id = arvif->vdev_id; - arg.scan_id = ATH10K_SCAN_ID; + arg = kzalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) { + ret = -ENOMEM; + goto exit; + } + + ath10k_wmi_start_scan_init(ar, arg); + arg->vdev_id = arvif->vdev_id; + arg->scan_id = ATH10K_SCAN_ID; if (req->ie_len) { - arg.ie_len = req->ie_len; - memcpy(arg.ie, req->ie, arg.ie_len); + arg->ie_len = req->ie_len; + memcpy(arg->ie, req->ie, arg->ie_len); } if (req->n_ssids) { - arg.n_ssids = req->n_ssids; - for (i = 0; i < arg.n_ssids; i++) { - arg.ssids[i].len = req->ssids[i].ssid_len; - arg.ssids[i].ssid = req->ssids[i].ssid; + arg->n_ssids = req->n_ssids; + for (i = 0; i < arg->n_ssids; i++) { + arg->ssids[i].len = req->ssids[i].ssid_len; + arg->ssids[i].ssid = req->ssids[i].ssid; } } else { - arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; + arg->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; } if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) { - arg.scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ; - ether_addr_copy(arg.mac_addr.addr, req->mac_addr); - ether_addr_copy(arg.mac_mask.addr, req->mac_addr_mask); + arg->scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ; + ether_addr_copy(arg->mac_addr.addr, req->mac_addr); + ether_addr_copy(arg->mac_mask.addr, req->mac_addr_mask); } if (req->n_channels) { - arg.n_channels = req->n_channels; - for (i = 0; i < arg.n_channels; i++) - arg.channels[i] = req->channels[i]->center_freq; + arg->n_channels = req->n_channels; + for (i = 0; i < arg->n_channels; i++) + arg->channels[i] = req->channels[i]->center_freq; } /* if duration is set, default dwell times will be overwritten */ if (req->duration) { - arg.dwell_time_active = req->duration; - arg.dwell_time_passive = req->duration; - arg.burst_duration_ms = req->duration; + arg->dwell_time_active = req->duration; + arg->dwell_time_passive = req->duration; + arg->burst_duration_ms = req->duration; - scan_timeout = min_t(u32, arg.max_rest_time * - (arg.n_channels - 1) + (req->duration + + scan_timeout = min_t(u32, arg->max_rest_time * + (arg->n_channels - 1) + (req->duration + ATH10K_SCAN_CHANNEL_SWITCH_WMI_EVT_OVERHEAD) * - arg.n_channels, arg.max_scan_time); + arg->n_channels, arg->max_scan_time); } else { - scan_timeout = arg.max_scan_time; + scan_timeout = arg->max_scan_time; } /* Add a 200ms margin to account for event/command processing */ scan_timeout += 200; - ret = ath10k_start_scan(ar, &arg); + ret = ath10k_start_scan(ar, arg); if (ret) { ath10k_warn(ar, "failed to start hw scan: %d\n", ret); spin_lock_bh(&ar->data_lock); @@ -6463,6 +6468,8 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, msecs_to_jiffies(scan_timeout)); exit: + kfree(arg); + mutex_unlock(&ar->conf_mutex); return ret; } @@ -7899,7 +7906,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; - struct wmi_start_scan_arg arg; + struct wmi_start_scan_arg *arg = NULL; int ret = 0; u32 scan_time_msec; @@ -7936,20 +7943,25 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2; - memset(&arg, 0, sizeof(arg)); - ath10k_wmi_start_scan_init(ar, &arg); - arg.vdev_id = arvif->vdev_id; - arg.scan_id = ATH10K_SCAN_ID; - arg.n_channels = 1; - arg.channels[0] = chan->center_freq; - arg.dwell_time_active = scan_time_msec; - arg.dwell_time_passive = scan_time_msec; - arg.max_scan_time = scan_time_msec; - arg.scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; - arg.scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; - arg.burst_duration_ms = duration; - - ret = ath10k_start_scan(ar, &arg); + arg = kzalloc(sizeof(*arg), GFP_KERNEL); + if (!arg) { + ret = -ENOMEM; + goto exit; + } + + ath10k_wmi_start_scan_init(ar, arg); + arg->vdev_id = arvif->vdev_id; + arg->scan_id = ATH10K_SCAN_ID; + arg->n_channels = 1; + arg->channels[0] = chan->center_freq; + arg->dwell_time_active = scan_time_msec; + arg->dwell_time_passive = scan_time_msec; + arg->max_scan_time = scan_time_msec; + arg->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; + arg->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; + arg->burst_duration_ms = duration; + + ret = ath10k_start_scan(ar, arg); if (ret) { ath10k_warn(ar, "failed to start roc scan: %d\n", ret); spin_lock_bh(&ar->data_lock); @@ -7975,6 +7987,8 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ret = 0; exit: + kfree(arg); + mutex_unlock(&ar->conf_mutex); return ret; } @@ -8507,9 +8521,10 @@ static int ath10k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, static void ath10k_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct ath10k *ar = hw->priv; struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; struct ath10k_vif *arvif = (void *)vif->drv_priv; @@ -9121,7 +9136,7 @@ static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss1[ {6, {2633, 2925}, {1215, 1350}, {585, 650} }, {7, {2925, 3250}, {1350, 1500}, {650, 722} }, {8, {3510, 3900}, {1620, 1800}, {780, 867} }, - {9, {3900, 4333}, {1800, 2000}, {780, 867} } + {9, {3900, 4333}, {1800, 2000}, {865, 960} } }; /*MCS parameters with Nss = 2 */ @@ -9136,7 +9151,7 @@ static const struct ath10k_index_vht_data_rate_type supported_vht_mcs_rate_nss2[ {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, - {9, {7800, 8667}, {3600, 4000}, {1560, 1733} } + {9, {7800, 8667}, {3600, 4000}, {1730, 1920} } }; static void ath10k_mac_get_rate_flags_ht(struct ath10k *ar, u32 rate, u8 nss, u8 mcs, @@ -9450,7 +9465,7 @@ static const struct ieee80211_ops ath10k_ops = { .reconfig_complete = ath10k_reconfig_complete, .get_survey = ath10k_get_survey, .set_bitrate_mask = ath10k_mac_op_set_bitrate_mask, - .sta_rc_update = ath10k_sta_rc_update, + .link_sta_rc_update = ath10k_sta_rc_update, .offset_tsf = ath10k_offset_tsf, .ampdu_action = ath10k_ampdu_action, .get_et_sset_count = ath10k_debug_get_et_sset_count, diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 08a6f36a6be9cb..6805357ee29e6d 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -3,7 +3,7 @@ * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc. * Copyright (c) 2016-2017 Erik Stromdahl - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2648,9 +2648,9 @@ static void ath10k_sdio_remove(struct sdio_func *func) netif_napi_del(&ar->napi); - ath10k_core_destroy(ar); - destroy_workqueue(ar_sdio->workqueue); + + ath10k_core_destroy(ar); } static const struct sdio_device_id ath10k_sdio_devices[] = { diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 0fe47d51013c7c..d436a874cd5af4 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1885,11 +1885,11 @@ static void ath10k_snoc_shutdown(struct platform_device *pdev) } static struct platform_driver ath10k_snoc_driver = { - .probe = ath10k_snoc_probe, - .remove_new = ath10k_snoc_remove, + .probe = ath10k_snoc_probe, + .remove = ath10k_snoc_remove, .shutdown = ath10k_snoc_shutdown, .driver = { - .name = "ath10k_snoc", + .name = "ath10k_snoc", .of_match_table = ath10k_snoc_dt_match, }, }; diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 97b12f51ef28c0..f2fc04596d4817 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1000,18 +1000,18 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab) if (!ab->hw_params.fixed_fw_mem) return 0; - ret = ath11k_ahb_setup_msa_resources(ab); - if (ret) { - ath11k_err(ab, "failed to setup msa resources\n"); - return ret; - } - node = of_get_child_by_name(host_dev->of_node, "wifi-firmware"); if (!node) { ab_ahb->fw.use_tz = true; return 0; } + ret = ath11k_ahb_setup_msa_resources(ab); + if (ret) { + ath11k_err(ab, "failed to setup msa resources\n"); + return ret; + } + info.fwnode = &node->fwnode; info.parent = host_dev; info.name = node->name; @@ -1313,12 +1313,12 @@ static void ath11k_ahb_shutdown(struct platform_device *pdev) } static struct platform_driver ath11k_ahb_driver = { - .driver = { - .name = "ath11k", + .driver = { + .name = "ath11k", .of_match_table = ath11k_ahb_of_match, }, - .probe = ath11k_ahb_probe, - .remove_new = ath11k_ahb_remove, + .probe = ath11k_ahb_probe, + .remove = ath11k_ahb_remove, .shutdown = ath11k_ahb_shutdown, }; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index ccf4ad35fdc335..be67382c00f6df 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -616,7 +616,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = false, .supports_rssi_stats = true, - .fw_wmi_diag_event = false, + .fw_wmi_diag_event = true, .current_cc_support = true, .dbr_debug_support = false, .global_reset = false, diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index f02599bd1c36b1..61f4b6dd53807f 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1351,6 +1351,7 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab) ath11k_hal_free_cont_rdp(ab); ath11k_hal_free_cont_wrp(ab); kfree(hal->srng_config); + hal->srng_config = NULL; } EXPORT_SYMBOL(ath11k_hal_srng_deinit); diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f8068d2e848c33..e6acbff067496a 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -5079,9 +5079,10 @@ static void ath11k_mac_op_sta_set_4addr(struct ieee80211_hw *hw, static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct ath11k *ar = hw->priv; struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); @@ -9708,7 +9709,7 @@ static const struct ieee80211_ops ath11k_ops = { .sta_state = ath11k_mac_op_sta_state, .sta_set_4addr = ath11k_mac_op_sta_set_4addr, .sta_set_txpwr = ath11k_mac_op_sta_set_txpwr, - .sta_rc_update = ath11k_mac_op_sta_rc_update, + .link_sta_rc_update = ath11k_mac_op_sta_rc_update, .conf_tx = ath11k_mac_op_conf_tx, .set_antenna = ath11k_mac_op_set_antenna, .get_antenna = ath11k_mac_op_get_antenna, diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index f477afd325deaf..7a22483b35cd98 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2180,6 +2180,9 @@ static int ath11k_qmi_request_device_info(struct ath11k_base *ab) ab->mem = bar_addr_va; ab->mem_len = resp.bar_size; + if (!ab->hw_params.ce_remap) + ab->mem_ce = ab->mem; + return 0; out: return ret; diff --git a/drivers/net/wireless/ath/ath11k/wow.c b/drivers/net/wireless/ath/ath11k/wow.c index 99d8ba45a75ba6..827085a926b27a 100644 --- a/drivers/net/wireless/ath/ath11k/wow.c +++ b/drivers/net/wireless/ath/ath11k/wow.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -155,6 +155,7 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new, u8 hdr_8023_bit_mask[ETH_HLEN] = {}; u8 hdr_80211_pattern[WOW_HDR_LEN] = {}; u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {}; + u8 bytemask[WOW_MAX_PATTERN_SIZE] = {}; int total_len = old->pkt_offset + old->pattern_len; int hdr_80211_end_offset; @@ -172,11 +173,17 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new, struct rfc1042_hdr *new_rfc_mask = (struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len); int rfc_len = sizeof(*new_rfc_pattern); + int i; + + /* convert bitmask to bytemask */ + for (i = 0; i < old->pattern_len; i++) + if (old->mask[i / 8] & BIT(i % 8)) + bytemask[i] = 0xff; memcpy(hdr_8023_pattern + old->pkt_offset, old->pattern, ETH_HLEN - old->pkt_offset); memcpy(hdr_8023_bit_mask + old->pkt_offset, - old->mask, ETH_HLEN - old->pkt_offset); + bytemask, ETH_HLEN - old->pkt_offset); /* Copy destination address */ memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN); @@ -232,7 +239,7 @@ static void ath11k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new, (void *)old->pattern + ETH_HLEN - old->pkt_offset, total_len - ETH_HLEN); memcpy((u8 *)new->mask + new->pattern_len, - (void *)old->mask + ETH_HLEN - old->pkt_offset, + bytemask + ETH_HLEN - old->pkt_offset, total_len - ETH_HLEN); new->pattern_len += total_len - ETH_HLEN; @@ -393,35 +400,31 @@ static int ath11k_vif_wow_set_wakeups(struct ath11k_vif *arvif, } for (i = 0; i < wowlan->n_patterns; i++) { - u8 bitmask[WOW_MAX_PATTERN_SIZE] = {}; u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {}; u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {}; struct cfg80211_pkt_pattern new_pattern = {}; - struct cfg80211_pkt_pattern old_pattern = patterns[i]; - int j; new_pattern.pattern = ath_pattern; new_pattern.mask = ath_bitmask; if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE) continue; - /* convert bytemask to bitmask */ - for (j = 0; j < patterns[i].pattern_len; j++) - if (patterns[i].mask[j / 8] & BIT(j % 8)) - bitmask[j] = 0xff; - old_pattern.mask = bitmask; if (ar->wmi->wmi_ab->wlan_resource_config.rx_decap_mode == ATH11K_HW_TXRX_NATIVE_WIFI) { if (patterns[i].pkt_offset < ETH_HLEN) { - u8 pattern_ext[WOW_MAX_PATTERN_SIZE] = {}; - - memcpy(pattern_ext, old_pattern.pattern, - old_pattern.pattern_len); - old_pattern.pattern = pattern_ext; ath11k_wow_convert_8023_to_80211(&new_pattern, - &old_pattern); + &patterns[i]); } else { - new_pattern = old_pattern; + int j; + + new_pattern = patterns[i]; + new_pattern.mask = ath_bitmask; + + /* convert bitmask to bytemask */ + for (j = 0; j < patterns[i].pattern_len; j++) + if (patterns[i].mask[j / 8] & BIT(j % 8)) + ath_bitmask[j] = 0xff; + new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN; } } diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig index f64e7c32221612..52a1bb19e3dad1 100644 --- a/drivers/net/wireless/ath/ath12k/Kconfig +++ b/drivers/net/wireless/ath/ath12k/Kconfig @@ -42,3 +42,13 @@ config ATH12K_TRACING If unsure, say Y to make it easier to debug problems. But if you want optimal performance choose N. + +config ATH12K_COREDUMP + bool "ath12k coredump" + depends on ATH12K + select WANT_DEV_COREDUMP + help + Enable ath12k coredump collection + + If unsure, say Y to make it easier to debug problems. But if + dump collection not required choose N. diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index 5a1ed20d730e85..b5bb3e2599cd0e 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -27,6 +27,7 @@ ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o ath12k-$(CONFIG_ACPI) += acpi.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o ath12k-$(CONFIG_PM) += wow.o +ath12k-$(CONFIG_ATH12K_COREDUMP) += coredump.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h index 857bc5f9e946a9..1a14b9fb86b885 100644 --- a/drivers/net/wireless/ath/ath12k/ce.h +++ b/drivers/net/wireless/ath/ath12k/ce.h @@ -148,7 +148,7 @@ struct ath12k_ce_pipe { void (*send_cb)(struct ath12k_ce_pipe *pipe); void (*recv_cb)(struct ath12k_base *ab, struct sk_buff *skb); - struct tasklet_struct intr_tq; + struct work_struct intr_wq; struct ath12k_ce_ring *src_ring; struct ath12k_ce_ring *dest_ring; struct ath12k_ce_ring *status_ring; diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 51252e8bc1ae99..c57322221e1d03 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -1004,7 +1004,7 @@ void ath12k_core_halt(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ar->num_created_vdevs = 0; ar->allocated_vdev_map = 0; @@ -1078,6 +1078,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) if (!ah || ah->state == ATH12K_HW_STATE_OFF) continue; + wiphy_lock(ah->hw->wiphy); mutex_lock(&ah->hw_mutex); switch (ah->state) { @@ -1086,10 +1087,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) for (j = 0; j < ah->num_radio; j++) { ar = &ah->radio[j]; - - mutex_lock(&ar->conf_mutex); ath12k_core_halt(ar); - mutex_unlock(&ar->conf_mutex); } break; @@ -1110,6 +1108,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) } mutex_unlock(&ah->hw_mutex); + wiphy_unlock(ah->hw->wiphy); } complete(&ab->driver_recovery); @@ -1188,6 +1187,7 @@ static void ath12k_core_reset(struct work_struct *work) ab->is_reset = true; atomic_set(&ab->recovery_count, 0); + ath12k_coredump_collect(ab); ath12k_core_pre_reconfigure_recovery(ab); ath12k_core_post_reconfigure_recovery(ab); @@ -1312,6 +1312,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, INIT_WORK(&ab->restart_work, ath12k_core_restart); INIT_WORK(&ab->reset_work, ath12k_core_reset); INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work); + INIT_WORK(&ab->dump_work, ath12k_coredump_upload); timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 7f2e9a9b40977d..3bf31ee5b9fa47 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -30,6 +30,7 @@ #include "acpi.h" #include "wow.h" #include "debugfs_htt_stats.h" +#include "coredump.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -94,6 +95,14 @@ static inline enum wme_ac ath12k_tid_to_ac(u32 tid) WME_AC_VO); } +static inline u64 ath12k_le32hilo_to_u64(__le32 hi, __le32 lo) +{ + u64 hi64 = le32_to_cpu(hi); + u64 lo64 = le32_to_cpu(lo); + + return (hi64 << 32) | lo64; +} + enum ath12k_skb_flags { ATH12K_SKB_HW_80211_ENCAP = BIT(0), ATH12K_SKB_CIPHER_SET = BIT(1), @@ -220,8 +229,9 @@ struct ath12k_tx_conf { }; struct ath12k_key_conf { - bool changed; enum set_key_cmd cmd; + struct list_head list; + struct ieee80211_sta *sta; struct ieee80211_key_conf *key; }; @@ -238,10 +248,8 @@ struct ath12k_rekey_data { bool enable_offload; }; -struct ath12k_vif { +struct ath12k_link_vif { u32 vdev_id; - enum wmi_vdev_type vdev_type; - enum wmi_vdev_subtype vdev_subtype; u32 beacon_interval; u32 dtim_period; u16 ast_hash; @@ -251,13 +259,38 @@ struct ath12k_vif { u8 search_type; struct ath12k *ar; - struct ieee80211_vif *vif; int bank_id; u8 vdev_id_check_en; struct wmi_wmm_params_all_arg wmm_params; struct list_head list; + + bool is_created; + bool is_started; + bool is_up; + u8 bssid[ETH_ALEN]; + struct cfg80211_bitrate_mask bitrate_mask; + struct delayed_work connection_loss_work; + int num_legacy_stations; + int rtscts_prot_mode; + int txpower; + bool rsnie_present; + bool wpaie_present; + struct ieee80211_chanctx_conf chanctx; + u8 vdev_stats_id; + u32 punct_bitmap; + u8 link_id; + struct ath12k_vif *ahvif; + struct ath12k_rekey_data rekey_data; +}; + +struct ath12k_vif { + enum wmi_vdev_type vdev_type; + enum wmi_vdev_subtype vdev_subtype; + struct ieee80211_vif *vif; + struct ath12k_hw *ah; + union { struct { u32 uapsd; @@ -275,25 +308,16 @@ struct ath12k_vif { } ap; } u; - bool is_created; - bool is_started; - bool is_up; u32 aid; - u8 bssid[ETH_ALEN]; - struct cfg80211_bitrate_mask bitrate_mask; - struct delayed_work connection_loss_work; - int num_legacy_stations; - int rtscts_prot_mode; - int txpower; - bool rsnie_present; - bool wpaie_present; u32 key_cipher; u8 tx_encap_type; - u8 vdev_stats_id; - u32 punct_bitmap; bool ps; - struct ath12k_vif_cache *cache; - struct ath12k_rekey_data rekey_data; + + struct ath12k_link_vif deflink; + struct ath12k_link_vif __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + struct ath12k_vif_cache *cache[IEEE80211_MLD_MAX_NUM_LINKS]; + /* indicates bitmap of link vif created in FW */ + u16 links_map; /* Must be last - ends in a flexible-array member. * @@ -306,7 +330,7 @@ struct ath12k_vif { struct ath12k_vif_iter { u32 vdev_id; struct ath12k *ar; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; }; #define HAL_AST_IDX_INVALID 0xFFFF @@ -441,27 +465,36 @@ struct ath12k_wbm_tx_stats { u64 wbm_tx_comp_stats[HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX]; }; -struct ath12k_sta { - struct ath12k_vif *arvif; +struct ath12k_link_sta { + struct ath12k_link_vif *arvif; + struct ath12k_sta *ahsta; /* the following are protected by ar->data_lock */ u32 changed; /* IEEE80211_RC_* */ u32 bw; u32 nss; u32 smps; - enum hal_pn_type pn_type; - struct work_struct update_wk; + struct wiphy_work update_wk; struct rate_info txrate; struct rate_info last_txrate; u64 rx_duration; u64 tx_duration; u8 rssi_comb; + u8 link_id; struct ath12k_rx_peer_stats *rx_stats; struct ath12k_wbm_tx_stats *wbm_tx_stats; u32 bw_prev; }; +struct ath12k_sta { + enum hal_pn_type pn_type; + struct ath12k_link_sta deflink; + struct ath12k_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; + /* indicates bitmap of link sta created in FW */ + u16 links_map; +}; + #define ATH12K_MIN_5G_FREQ 4150 #define ATH12K_MIN_6G_FREQ 5925 #define ATH12K_MAX_6G_FREQ 7115 @@ -561,13 +594,9 @@ struct ath12k { u32 chan_tx_pwr; u32 num_stations; u32 max_num_stations; - bool monitor_present; - /* To synchronize concurrent synchronous mac80211 callback operations, - * concurrent debugfs configuration and concurrent FW statistics events. - */ - struct mutex conf_mutex; + /* protects the radio specific data like debug stats, ppdu_stats_info stats, - * vdev_stop_status info, scan data, ath12k_sta info, ath12k_vif info, + * vdev_stop_status info, scan data, ath12k_sta info, ath12k_link_vif info, * channel context data, survey info, test mode data. */ spinlock_t data_lock; @@ -666,6 +695,7 @@ struct ath12k_hw { enum ath12k_hw_state state; bool regd_updated; bool use_6ghz_regd; + u8 num_radio; /* Keep last */ @@ -782,6 +812,10 @@ struct ath12k_base { /* HW channel counters frequency value in hertz common to all MACs */ u32 cc_freq_hz; + struct ath12k_dump_file_data *dump_data; + size_t ath12k_coredump_len; + struct work_struct dump_work; + struct ath12k_htc htc; struct ath12k_dp dp; @@ -1024,16 +1058,26 @@ static inline struct ath12k_skb_rxcb *ATH12K_SKB_RXCB(struct sk_buff *skb) return (struct ath12k_skb_rxcb *)skb->cb; } -static inline struct ath12k_vif *ath12k_vif_to_arvif(struct ieee80211_vif *vif) +static inline struct ath12k_vif *ath12k_vif_to_ahvif(struct ieee80211_vif *vif) { return (struct ath12k_vif *)vif->drv_priv; } -static inline struct ath12k_sta *ath12k_sta_to_arsta(struct ieee80211_sta *sta) +static inline struct ath12k_sta *ath12k_sta_to_ahsta(struct ieee80211_sta *sta) { return (struct ath12k_sta *)sta->drv_priv; } +static inline struct ieee80211_sta *ath12k_ahsta_to_sta(struct ath12k_sta *ahsta) +{ + return container_of((void *)ahsta, struct ieee80211_sta, drv_priv); +} + +static inline struct ieee80211_vif *ath12k_ahvif_to_vif(struct ath12k_vif *ahvif) +{ + return container_of((void *)ahvif, struct ieee80211_vif, drv_priv); +} + static inline struct ath12k *ath12k_ab_to_ar(struct ath12k_base *ab, int mac_id) { diff --git a/drivers/net/wireless/ath/ath12k/coredump.c b/drivers/net/wireless/ath/ath12k/coredump.c new file mode 100644 index 00000000000000..72d675d15e6483 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/coredump.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include +#include "hif.h" +#include "coredump.h" +#include "debug.h" + +enum +ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type(enum ath12k_qmi_target_mem type) +{ + enum ath12k_fw_crash_dump_type dump_type; + + switch (type) { + case HOST_DDR_REGION_TYPE: + dump_type = FW_CRASH_DUMP_REMOTE_MEM_DATA; + break; + case M3_DUMP_REGION_TYPE: + dump_type = FW_CRASH_DUMP_M3_DUMP; + break; + case PAGEABLE_MEM_REGION_TYPE: + dump_type = FW_CRASH_DUMP_PAGEABLE_DATA; + break; + case BDF_MEM_REGION_TYPE: + case CALDB_MEM_REGION_TYPE: + dump_type = FW_CRASH_DUMP_NONE; + break; + default: + dump_type = FW_CRASH_DUMP_TYPE_MAX; + break; + } + + return dump_type; +} + +void ath12k_coredump_upload(struct work_struct *work) +{ + struct ath12k_base *ab = container_of(work, struct ath12k_base, dump_work); + + ath12k_info(ab, "Uploading coredump\n"); + /* dev_coredumpv() takes ownership of the buffer */ + dev_coredumpv(ab->dev, ab->dump_data, ab->ath12k_coredump_len, GFP_KERNEL); + ab->dump_data = NULL; +} + +void ath12k_coredump_collect(struct ath12k_base *ab) +{ + ath12k_hif_coredump_download(ab); +} diff --git a/drivers/net/wireless/ath/ath12k/coredump.h b/drivers/net/wireless/ath/ath12k/coredump.h new file mode 100644 index 00000000000000..5d6003b1c12dc0 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/coredump.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef _ATH12K_COREDUMP_H_ +#define _ATH12K_COREDUMP_H_ + +#define ATH12K_FW_CRASH_DUMP_V2 2 + +enum ath12k_fw_crash_dump_type { + FW_CRASH_DUMP_PAGING_DATA, + FW_CRASH_DUMP_RDDM_DATA, + FW_CRASH_DUMP_REMOTE_MEM_DATA, + FW_CRASH_DUMP_PAGEABLE_DATA, + FW_CRASH_DUMP_M3_DUMP, + FW_CRASH_DUMP_NONE, + + /* keep last */ + FW_CRASH_DUMP_TYPE_MAX, +}; + +#define COREDUMP_TLV_HDR_SIZE 8 + +struct ath12k_tlv_dump_data { + /* see ath11k_fw_crash_dump_type above */ + __le32 type; + + /* in bytes */ + __le32 tlv_len; + + /* pad to 32-bit boundaries as needed */ + u8 tlv_data[]; +} __packed; + +struct ath12k_dump_file_data { + /* "ATH12K-FW-DUMP" */ + char df_magic[16]; + /* total dump len in bytes */ + __le32 len; + /* file dump version */ + __le32 version; + /* pci device id */ + __le32 chip_id; + /* qrtr instance id */ + __le32 qrtr_id; + /* pci domain id */ + __le32 bus_id; + guid_t guid; + /* time-of-day stamp */ + __le64 tv_sec; + /* time-of-day stamp, nano-seconds */ + __le64 tv_nsec; + /* room for growth w/out changing binary format */ + u8 unused[128]; + u8 data[]; +} __packed; + +#ifdef CONFIG_ATH12K_COREDUMP +enum ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type + (enum ath12k_qmi_target_mem type); +void ath12k_coredump_upload(struct work_struct *work); +void ath12k_coredump_collect(struct ath12k_base *ab); +#else +static inline enum ath12k_fw_crash_dump_type ath12k_coredump_get_dump_type + (enum ath12k_qmi_target_mem type) +{ + return FW_CRASH_DUMP_TYPE_MAX; +} + +static inline void ath12k_coredump_upload(struct work_struct *work) +{ +} + +static inline void ath12k_coredump_collect(struct ath12k_base *ab) +{ +} +#endif + +#endif diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 2a977c36af0095..d4b32d1a431c0d 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -15,14 +15,14 @@ static ssize_t ath12k_write_simulate_radar(struct file *file, struct ath12k *ar = file->private_data; int ret; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); ret = ath12k_wmi_simulate_radar(ar); if (ret) goto exit; ret = count; exit: - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index f1b7e74aefe426..c9980c0193d1d7 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -12,8 +12,8 @@ #include "dp_rx.h" static u32 -print_array_to_buf(u8 *buf, u32 offset, const char *header, - const __le32 *array, u32 array_len, const char *footer) +print_array_to_buf_index(u8 *buf, u32 offset, const char *header, u32 stats_index, + const __le32 *array, u32 array_len, const char *footer) { int index = 0; u8 i; @@ -26,7 +26,7 @@ print_array_to_buf(u8 *buf, u32 offset, const char *header, for (i = 0; i < array_len; i++) { index += scnprintf(buf + offset + index, (ATH12K_HTT_STATS_BUF_SIZE - offset) - index, - " %u:%u,", i, le32_to_cpu(array[i])); + " %u:%u,", stats_index++, le32_to_cpu(array[i])); } /* To overwrite the last trailing comma */ index--; @@ -40,6 +40,54 @@ print_array_to_buf(u8 *buf, u32 offset, const char *header, return index; } +static u32 +print_array_to_buf(u8 *buf, u32 offset, const char *header, + const __le32 *array, u32 array_len, const char *footer) +{ + return print_array_to_buf_index(buf, offset, header, 0, array, array_len, + footer); +} + +static const char *ath12k_htt_be_tx_rx_ru_size_to_str(u8 ru_size) +{ + switch (ru_size) { + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_26: + return "26"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52: + return "52"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52_26: + return "52+26"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106: + return "106"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106_26: + return "106+26"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_242: + return "242"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484: + return "484"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484_242: + return "484+242"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996: + return "996"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484: + return "996+484"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484_242: + return "996+484+242"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2: + return "996x2"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2_484: + return "996x2+484"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3: + return "996x3"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3_484: + return "996x3+484"; + case ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x4: + return "996x4"; + default: + return "unknown"; + } +} + static void htt_print_tx_pdev_stats_cmn_tlv(const void *tag_buf, u16 tag_len, struct debug_htt_stats_req *stats_req) @@ -1447,6 +1495,1207 @@ ath12k_htt_print_tx_de_compl_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_tx_selfgen_cmn_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_cmn_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_CMN_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "su_bar = %u\n", + le32_to_cpu(htt_stats_buf->su_bar)); + len += scnprintf(buf + len, buf_len - len, "rts = %u\n", + le32_to_cpu(htt_stats_buf->rts)); + len += scnprintf(buf + len, buf_len - len, "cts2self = %u\n", + le32_to_cpu(htt_stats_buf->cts2self)); + len += scnprintf(buf + len, buf_len - len, "qos_null = %u\n", + le32_to_cpu(htt_stats_buf->qos_null)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_1 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_1)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_2 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_2)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_3 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_3)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_4 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_4)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_5 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_5)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_6 = %u\n", + le32_to_cpu(htt_stats_buf->delayed_bar_6)); + len += scnprintf(buf + len, buf_len - len, "delayed_bar_7 = %u\n\n", + le32_to_cpu(htt_stats_buf->delayed_bar_7)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ac_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_ac_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->ac_su_ndpa)); + len += scnprintf(buf + len, buf_len - len, "ac_su_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->ac_su_ndp)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndpa)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndp)); + len += print_array_to_buf_index(buf, len, "ac_mu_mimo_brpollX_tried = ", 1, + htt_stats_buf->ac_mu_mimo_brpoll, + ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ax_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_ax_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->ax_su_ndpa)); + len += scnprintf(buf + len, buf_len - len, "ax_su_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->ax_su_ndp)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndpa)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndp)); + len += print_array_to_buf_index(buf, len, "ax_mu_mimo_brpollX_tried = ", 1, + htt_stats_buf->ax_mu_mimo_brpoll, + ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS, "\n"); + len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger = %u\n", + le32_to_cpu(htt_stats_buf->ax_basic_trigger)); + len += scnprintf(buf + len, buf_len - len, "ax_ulmumimo_total_trigger = %u\n", + le32_to_cpu(htt_stats_buf->ax_ulmumimo_trigger)); + len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger = %u\n", + le32_to_cpu(htt_stats_buf->ax_bsr_trigger)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_bar_trigger)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger = %u\n\n", + le32_to_cpu(htt_stats_buf->ax_mu_rts_trigger)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_be_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_be_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_BE_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_queued = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndpa_queued)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndpa)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndp_queued = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndp_queued)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndp)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_queued = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_queued)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_tried = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_queued = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_queued)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_tried = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp)); + len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_queued = ", 1, + htt_stats_buf->be_mu_mimo_brpoll_queued, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1, + "\n"); + len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_tried = ", 1, + htt_stats_buf->be_mu_mimo_brpoll, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1, + "\n"); + len += print_array_to_buf(buf, len, "be_ul_mumimo_trigger = ", + htt_stats_buf->be_ul_mumimo_trigger, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n"); + len += scnprintf(buf + len, buf_len - len, "be_basic_trigger = %u\n", + le32_to_cpu(htt_stats_buf->be_basic_trigger)); + len += scnprintf(buf + len, buf_len - len, "be_ulmumimo_total_trigger = %u\n", + le32_to_cpu(htt_stats_buf->be_ulmumimo_trigger)); + len += scnprintf(buf + len, buf_len - len, "be_bsr_trigger = %u\n", + le32_to_cpu(htt_stats_buf->be_bsr_trigger)); + len += scnprintf(buf + len, buf_len - len, "be_mu_bar_trigger = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_bar_trigger)); + len += scnprintf(buf + len, buf_len - len, "be_mu_rts_trigger = %u\n\n", + le32_to_cpu(htt_stats_buf->be_mu_rts_trigger)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ac_err_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_ac_err_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AC_ERR_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ac_su_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_su_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "ac_su_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_su_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp1_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp1_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp2_err = %u\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp2_err)); + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_brp3_err = %u\n\n", + le32_to_cpu(htt_stats_buf->ac_mu_mimo_brp3_err)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ax_err_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_ax_err_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_AX_ERR_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "ax_su_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_su_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "ax_su_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_su_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_mimo_ndp_err)); + len += print_array_to_buf_index(buf, len, "ax_mu_mimo_brpX_err", 1, + htt_stats_buf->ax_mu_mimo_brp_err, + ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1, + "\n"); + len += scnprintf(buf + len, buf_len - len, "ax_basic_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_basic_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "ax_ulmumimo_total_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_ulmumimo_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "ax_bsr_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_bsr_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_bar_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->ax_mu_bar_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "ax_mu_rts_trigger_err = %u\n\n", + le32_to_cpu(htt_stats_buf->ax_mu_rts_trigger_err)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_be_err_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_selfgen_be_err_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_SELFGEN_BE_ERR_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "be_su_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndp_flushed = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndp_flushed)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "be_su_ndpa_flushed = %u\n", + le32_to_cpu(htt_stats_buf->be_su_ndpa_flushed)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_err = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_err)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndpa_flushed = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndpa_flushed)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_err = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_err)); + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_ndp_flushed = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_mimo_ndp_flushed)); + len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpX_err", 1, + htt_stats_buf->be_mu_mimo_brp_err, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1, + "\n"); + len += print_array_to_buf_index(buf, len, "be_mu_mimo_brpollX_flushed", 1, + htt_stats_buf->be_mu_mimo_brpoll_flushed, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1, + "\n"); + len += print_array_to_buf(buf, len, "be_mu_mimo_num_cbf_rcvd_on_brp_err", + htt_stats_buf->be_mu_mimo_brp_err_num_cbf_rxd, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_ul_mumimo_trigger_err", + htt_stats_buf->be_ul_mumimo_trigger_err, + ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS, "\n"); + len += scnprintf(buf + len, buf_len - len, "be_basic_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->be_basic_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "be_ulmumimo_total_trig_err = %u\n", + le32_to_cpu(htt_stats_buf->be_ulmumimo_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "be_bsr_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->be_bsr_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "be_mu_bar_trigger_err = %u\n", + le32_to_cpu(htt_stats_buf->be_mu_bar_trigger_err)); + len += scnprintf(buf + len, buf_len - len, "be_mu_rts_trigger_err = %u\n\n", + le32_to_cpu(htt_stats_buf->be_mu_rts_trigger_err)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ac_sched_status_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats) +{ + const struct ath12k_htt_tx_selfgen_ac_sched_status_stats_tlv *htt_stats_buf = + tag_buf; + u8 *buf = stats->buf; + u32 len = stats->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_SELFGEN_AC_SCHED_STATUS_STATS_TLV:\n"); + len += print_array_to_buf(buf, len, "ac_su_ndpa_sch_status", + htt_stats_buf->ac_su_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_su_ndp_sch_status", + htt_stats_buf->ac_su_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_ndpa_sch_status", + htt_stats_buf->ac_mu_mimo_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_ndp_sch_status", + htt_stats_buf->ac_mu_mimo_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_brp_sch_status", + htt_stats_buf->ac_mu_mimo_brp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ac_su_ndp_sch_flag_err", + htt_stats_buf->ac_su_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_ndp_sch_flag_err", + htt_stats_buf->ac_mu_mimo_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ac_mu_mimo_brp_sch_flag_err", + htt_stats_buf->ac_mu_mimo_brp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n"); + + stats->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_ax_sched_status_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats) +{ + const struct ath12k_htt_tx_selfgen_ax_sched_status_stats_tlv *htt_stats_buf = + tag_buf; + u8 *buf = stats->buf; + u32 len = stats->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_SELFGEN_AX_SCHED_STATUS_STATS_TLV:\n"); + len += print_array_to_buf(buf, len, "ax_su_ndpa_sch_status", + htt_stats_buf->ax_su_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_su_ndp_sch_status", + htt_stats_buf->ax_su_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_mimo_ndpa_sch_status", + htt_stats_buf->ax_mu_mimo_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_mimo_ndp_sch_status", + htt_stats_buf->ax_mu_mimo_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_brp_sch_status", + htt_stats_buf->ax_mu_brp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_bar_sch_status", + htt_stats_buf->ax_mu_bar_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_basic_trig_sch_status", + htt_stats_buf->ax_basic_trig_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_su_ndp_sch_flag_err", + htt_stats_buf->ax_su_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_mimo_ndp_sch_flag_err", + htt_stats_buf->ax_mu_mimo_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_brp_sch_flag_err", + htt_stats_buf->ax_mu_brp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_mu_bar_sch_flag_err", + htt_stats_buf->ax_mu_bar_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_basic_trig_sch_flag_err", + htt_stats_buf->ax_basic_trig_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "ax_ulmumimo_trig_sch_status", + htt_stats_buf->ax_ulmumimo_trig_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "ax_ulmumimo_trig_sch_flag_err", + htt_stats_buf->ax_ulmumimo_trig_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n"); + + stats->buf_len = len; +} + +static void +ath12k_htt_print_tx_selfgen_be_sched_status_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats) +{ + const struct ath12k_htt_tx_selfgen_be_sched_status_stats_tlv *htt_stats_buf = + tag_buf; + u8 *buf = stats->buf; + u32 len = stats->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_SELFGEN_BE_SCHED_STATUS_STATS_TLV:\n"); + len += print_array_to_buf(buf, len, "be_su_ndpa_sch_status", + htt_stats_buf->be_su_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_su_ndp_sch_status", + htt_stats_buf->be_su_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_mimo_ndpa_sch_status", + htt_stats_buf->be_mu_mimo_ndpa_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_mimo_ndp_sch_status", + htt_stats_buf->be_mu_mimo_ndp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_brp_sch_status", + htt_stats_buf->be_mu_brp_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_bar_sch_status", + htt_stats_buf->be_mu_bar_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_basic_trig_sch_status", + htt_stats_buf->be_basic_trig_sch_status, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_su_ndp_sch_flag_err", + htt_stats_buf->be_su_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_mimo_ndp_sch_flag_err", + htt_stats_buf->be_mu_mimo_ndp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_brp_sch_flag_err", + htt_stats_buf->be_mu_brp_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_mu_bar_sch_flag_err", + htt_stats_buf->be_mu_bar_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_basic_trig_sch_flag_err", + htt_stats_buf->be_basic_trig_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n"); + len += print_array_to_buf(buf, len, "be_basic_trig_sch_flag_err", + htt_stats_buf->be_basic_trig_sch_flag_err, + ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS, "\n"); + len += print_array_to_buf(buf, len, "be_ulmumimo_trig_sch_flag_err", + htt_stats_buf->be_ulmumimo_trig_sch_flag_err, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS, "\n\n"); + + stats->buf_len = len; +} + +static void +ath12k_htt_print_stats_string_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_string_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u8 i; + u16 index = 0; + u32 datum; + char data[ATH12K_HTT_MAX_STRING_LEN] = {0}; + + tag_len = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_STRING_TLV:\n"); + for (i = 0; i < tag_len; i++) { + datum = __le32_to_cpu(htt_stats_buf->data[i]); + index += scnprintf(&data[index], ATH12K_HTT_MAX_STRING_LEN - index, + "%.*s", 4, (char *)&datum); + if (index >= ATH12K_HTT_MAX_STRING_LEN) + break; + } + len += scnprintf(buf + len, buf_len - len, "data = %s\n\n", data); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sring_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sring_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + u32 avail_words; + u32 head_tail_ptr; + u32 sring_stat; + u32 tail_ptr; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__ring_id__arena__ep); + avail_words = __le32_to_cpu(htt_stats_buf->num_avail_words__num_valid_words); + head_tail_ptr = __le32_to_cpu(htt_stats_buf->head_ptr__tail_ptr); + sring_stat = __le32_to_cpu(htt_stats_buf->consumer_empty__producer_full); + tail_ptr = __le32_to_cpu(htt_stats_buf->prefetch_count__internal_tail_ptr); + + len += scnprintf(buf + len, buf_len - len, "HTT_SRING_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "ring_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_RING_ID)); + len += scnprintf(buf + len, buf_len - len, "arena = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_ARENA)); + len += scnprintf(buf + len, buf_len - len, "ep = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_SRING_STATS_EP)); + len += scnprintf(buf + len, buf_len - len, "base_addr_lsb = 0x%x\n", + le32_to_cpu(htt_stats_buf->base_addr_lsb)); + len += scnprintf(buf + len, buf_len - len, "base_addr_msb = 0x%x\n", + le32_to_cpu(htt_stats_buf->base_addr_msb)); + len += scnprintf(buf + len, buf_len - len, "ring_size = %u\n", + le32_to_cpu(htt_stats_buf->ring_size)); + len += scnprintf(buf + len, buf_len - len, "elem_size = %u\n", + le32_to_cpu(htt_stats_buf->elem_size)); + len += scnprintf(buf + len, buf_len - len, "num_avail_words = %u\n", + u32_get_bits(avail_words, + ATH12K_HTT_SRING_STATS_NUM_AVAIL_WORDS)); + len += scnprintf(buf + len, buf_len - len, "num_valid_words = %u\n", + u32_get_bits(avail_words, + ATH12K_HTT_SRING_STATS_NUM_VALID_WORDS)); + len += scnprintf(buf + len, buf_len - len, "head_ptr = %u\n", + u32_get_bits(head_tail_ptr, ATH12K_HTT_SRING_STATS_HEAD_PTR)); + len += scnprintf(buf + len, buf_len - len, "tail_ptr = %u\n", + u32_get_bits(head_tail_ptr, ATH12K_HTT_SRING_STATS_TAIL_PTR)); + len += scnprintf(buf + len, buf_len - len, "consumer_empty = %u\n", + u32_get_bits(sring_stat, + ATH12K_HTT_SRING_STATS_CONSUMER_EMPTY)); + len += scnprintf(buf + len, buf_len - len, "producer_full = %u\n", + u32_get_bits(head_tail_ptr, + ATH12K_HTT_SRING_STATS_PRODUCER_FULL)); + len += scnprintf(buf + len, buf_len - len, "prefetch_count = %u\n", + u32_get_bits(tail_ptr, ATH12K_HTT_SRING_STATS_PREFETCH_COUNT)); + len += scnprintf(buf + len, buf_len - len, "internal_tail_ptr = %u\n\n", + u32_get_bits(tail_ptr, + ATH12K_HTT_SRING_STATS_INTERNAL_TAIL_PTR)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sfm_cmn_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sfm_cmn_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = __le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CMN_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "buf_total = %u\n", + le32_to_cpu(htt_stats_buf->buf_total)); + len += scnprintf(buf + len, buf_len - len, "mem_empty = %u\n", + le32_to_cpu(htt_stats_buf->mem_empty)); + len += scnprintf(buf + len, buf_len - len, "deallocate_bufs = %u\n", + le32_to_cpu(htt_stats_buf->deallocate_bufs)); + len += scnprintf(buf + len, buf_len - len, "num_records = %u\n\n", + le32_to_cpu(htt_stats_buf->num_records)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sfm_client_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sfm_client_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "client_id = %u\n", + le32_to_cpu(htt_stats_buf->client_id)); + len += scnprintf(buf + len, buf_len - len, "buf_min = %u\n", + le32_to_cpu(htt_stats_buf->buf_min)); + len += scnprintf(buf + len, buf_len - len, "buf_max = %u\n", + le32_to_cpu(htt_stats_buf->buf_max)); + len += scnprintf(buf + len, buf_len - len, "buf_busy = %u\n", + le32_to_cpu(htt_stats_buf->buf_busy)); + len += scnprintf(buf + len, buf_len - len, "buf_alloc = %u\n", + le32_to_cpu(htt_stats_buf->buf_alloc)); + len += scnprintf(buf + len, buf_len - len, "buf_avail = %u\n", + le32_to_cpu(htt_stats_buf->buf_avail)); + len += scnprintf(buf + len, buf_len - len, "num_users = %u\n\n", + le32_to_cpu(htt_stats_buf->num_users)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_sfm_client_user_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_sfm_client_user_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u16 num_elems = tag_len >> 2; + + len += scnprintf(buf + len, buf_len - len, "HTT_SFM_CLIENT_USER_TLV:\n"); + len += print_array_to_buf(buf, len, "dwords_used_by_user_n", + htt_stats_buf->dwords_used_by_user_n, + num_elems, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_mu_mimo_sch_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_mu_mimo_sch_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u8 i; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_MU_MIMO_SCH_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_posted = %u\n", + le32_to_cpu(htt_stats_buf->mu_mimo_sch_posted)); + len += scnprintf(buf + len, buf_len - len, "mu_mimo_sch_failed = %u\n", + le32_to_cpu(htt_stats_buf->mu_mimo_sch_failed)); + len += scnprintf(buf + len, buf_len - len, "mu_mimo_ppdu_posted = %u\n", + le32_to_cpu(htt_stats_buf->mu_mimo_ppdu_posted)); + len += scnprintf(buf + len, buf_len - len, + "\nac_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0, + le32_to_cpu(htt_stats_buf->ac_mu_mimo_per_grp_sz[0])); + for (i = 1; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_sch_posted_per_group_index %u ", i); + len += scnprintf(buf + len, buf_len - len, + "(TOTAL STREAMS = %u) = %u\n", i + 1, + le32_to_cpu(htt_stats_buf->ac_mu_mimo_per_grp_sz[i])); + } + + for (i = 0; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_sch_posted_per_group_index %u ", + i + ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS); + len += scnprintf(buf + len, buf_len - len, + "(TOTAL STREAMS = %u) = %u\n", + i + ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS + 1, + le32_to_cpu(htt_stats_buf->ac_mu_mimo_grp_sz_ext[i])); + } + + len += scnprintf(buf + len, buf_len - len, + "\nax_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0, + le32_to_cpu(htt_stats_buf->ax_mu_mimo_per_grp_sz[0])); + for (i = 1; i < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_sch_posted_per_group_index %u ", i); + len += scnprintf(buf + len, buf_len - len, + "(TOTAL STREAMS = %u) = %u\n", i + 1, + le32_to_cpu(htt_stats_buf->ax_mu_mimo_per_grp_sz[i])); + } + + len += scnprintf(buf + len, buf_len - len, + "\nbe_mu_mimo_sch_posted_per_group_index %u (SU) = %u\n", 0, + le32_to_cpu(htt_stats_buf->be_mu_mimo_per_grp_sz[0])); + for (i = 1; i < ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "be_mu_mimo_sch_posted_per_group_index %u ", i); + len += scnprintf(buf + len, buf_len - len, + "(TOTAL STREAMS = %u) = %u\n", i + 1, + le32_to_cpu(htt_stats_buf->be_mu_mimo_per_grp_sz[i])); + } + + len += scnprintf(buf + len, buf_len - len, "\n11ac MU_MIMO SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, "ac_mu_mimo_sch_nusers_"); + len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ac_mu_mimo_sch_nusers[i])); + } + + len += scnprintf(buf + len, buf_len - len, "\n11ax MU_MIMO SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, "ax_mu_mimo_sch_nusers_"); + len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_mu_mimo_sch_nusers[i])); + } + + len += scnprintf(buf + len, buf_len - len, "\n11be MU_MIMO SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, "be_mu_mimo_sch_nusers_"); + len += scnprintf(buf + len, buf_len - len, "%u = %u\n", i, + le32_to_cpu(htt_stats_buf->be_mu_mimo_sch_nusers[i])); + } + + len += scnprintf(buf + len, buf_len - len, "\n11ax OFDMA SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_OFDMA_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ax_ofdma_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ofdma_sch_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_ofdma_basic_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_ofdma_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_ofdma_bsr_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_ofdma_bsr_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_ofdma_bar_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_ofdma_bar_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_ofdma_brp_sch_nusers_%u = %u\n\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_ofdma_brp_nusers[i])); + } + + len += scnprintf(buf + len, buf_len - len, "11ax UL MUMIMO SCH STATS:\n"); + for (i = 0; i < ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS; i++) { + len += scnprintf(buf + len, buf_len - len, + "ax_ul_mumimo_basic_sch_nusers_%u = %u\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_mumimo_nusers[i])); + len += scnprintf(buf + len, buf_len - len, + "ax_ul_mumimo_brp_sch_nusers_%u = %u\n\n", i, + le32_to_cpu(htt_stats_buf->ax_ul_mumimo_brp_nusers[i])); + } + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_mumimo_grp_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_mumimo_grp_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + int j; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_TX_PDEV_MUMIMO_GRP_STATS:\n"); + len += print_array_to_buf(buf, len, + "dl_mumimo_grp_tputs_observed (per bin = 300 mbps)", + htt_stats_buf->dl_mumimo_grp_tputs, + ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS, "\n"); + len += print_array_to_buf(buf, len, "dl_mumimo_grp eligible", + htt_stats_buf->dl_mumimo_grp_eligible, + ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n"); + len += print_array_to_buf(buf, len, "dl_mumimo_grp_ineligible", + htt_stats_buf->dl_mumimo_grp_ineligible, + ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n"); + len += scnprintf(buf + len, buf_len - len, "dl_mumimo_grp_invalid:\n"); + for (j = 0; j < ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ; j++) { + len += scnprintf(buf + len, buf_len - len, "grp_id = %u", j); + len += print_array_to_buf(buf, len, "", + htt_stats_buf->dl_mumimo_grp_invalid, + ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE, + "\n"); + } + + len += print_array_to_buf(buf, len, "ul_mumimo_grp_best_grp_size", + htt_stats_buf->ul_mumimo_grp_best_grp_size, + ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ, "\n"); + len += print_array_to_buf_index(buf, len, "ul_mumimo_grp_best_num_usrs = ", 1, + htt_stats_buf->ul_mumimo_grp_best_usrs, + ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS, "\n"); + len += print_array_to_buf(buf, len, + "ul_mumimo_grp_tputs_observed (per bin = 300 mbps)", + htt_stats_buf->ul_mumimo_grp_tputs, + ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_mpdu_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 user_index; + u32 tx_sched_mode; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + user_index = __le32_to_cpu(htt_stats_buf->user_index); + tx_sched_mode = __le32_to_cpu(htt_stats_buf->tx_sched_mode); + + if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC) { + if (!user_index) + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_MU_MIMO_AC_MPDU_STATS:\n"); + + if (user_index < ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS) { + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdus_queued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_queued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdus_tried_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_tried_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdus_failed_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_failed_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdus_requeued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_requeued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_err_no_ba_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->err_no_ba_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_mpdu_underrun_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdu_underrun_usr)); + len += scnprintf(buf + len, buf_len - len, + "ac_mu_mimo_ampdu_underrun_usr_%u = %u\n\n", + user_index, + le32_to_cpu(htt_stats_buf->ampdu_underrun_usr)); + } + } + + if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX) { + if (!user_index) + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_MU_MIMO_AX_MPDU_STATS:\n"); + + if (user_index < ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS) { + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdus_queued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_queued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdus_tried_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_tried_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdus_failed_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_failed_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdus_requeued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_requeued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_err_no_ba_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->err_no_ba_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_mpdu_underrun_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdu_underrun_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_mimo_ampdu_underrun_usr_%u = %u\n\n", + user_index, + le32_to_cpu(htt_stats_buf->ampdu_underrun_usr)); + } + } + + if (tx_sched_mode == ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX) { + if (!user_index) + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_AX_MU_OFDMA_MPDU_STATS:\n"); + + if (user_index < ATH12K_HTT_TX_NUM_OFDMA_USER_STATS) { + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdus_queued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_queued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdus_tried_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_tried_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdus_failed_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_failed_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdus_requeued_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdus_requeued_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_err_no_ba_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->err_no_ba_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_mpdu_underrun_usr_%u = %u\n", + user_index, + le32_to_cpu(htt_stats_buf->mpdu_underrun_usr)); + len += scnprintf(buf + len, buf_len - len, + "ax_mu_ofdma_ampdu_underrun_usr_%u = %u\n\n", + user_index, + le32_to_cpu(htt_stats_buf->ampdu_underrun_usr)); + } + } + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_cca_stats_hist_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_cca_stats_hist_v1_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_CCA_STATS_HIST_TLV :\n"); + len += scnprintf(buf + len, buf_len - len, "chan_num = %u\n", + le32_to_cpu(htt_stats_buf->chan_num)); + len += scnprintf(buf + len, buf_len - len, "num_records = %u\n", + le32_to_cpu(htt_stats_buf->num_records)); + len += scnprintf(buf + len, buf_len - len, "valid_cca_counters_bitmap = 0x%x\n", + le32_to_cpu(htt_stats_buf->valid_cca_counters_bitmap)); + len += scnprintf(buf + len, buf_len - len, "collection_interval = %u\n\n", + le32_to_cpu(htt_stats_buf->collection_interval)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_stats_cca_counters_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_stats_cca_counters_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_PDEV_STATS_CCA_COUNTERS_TLV:(in usec)\n"); + len += scnprintf(buf + len, buf_len - len, "tx_frame_usec = %u\n", + le32_to_cpu(htt_stats_buf->tx_frame_usec)); + len += scnprintf(buf + len, buf_len - len, "rx_frame_usec = %u\n", + le32_to_cpu(htt_stats_buf->rx_frame_usec)); + len += scnprintf(buf + len, buf_len - len, "rx_clear_usec = %u\n", + le32_to_cpu(htt_stats_buf->rx_clear_usec)); + len += scnprintf(buf + len, buf_len - len, "my_rx_frame_usec = %u\n", + le32_to_cpu(htt_stats_buf->my_rx_frame_usec)); + len += scnprintf(buf + len, buf_len - len, "usec_cnt = %u\n", + le32_to_cpu(htt_stats_buf->usec_cnt)); + len += scnprintf(buf + len, buf_len - len, "med_rx_idle_usec = %u\n", + le32_to_cpu(htt_stats_buf->med_rx_idle_usec)); + len += scnprintf(buf + len, buf_len - len, "med_tx_idle_global_usec = %u\n", + le32_to_cpu(htt_stats_buf->med_tx_idle_global_usec)); + len += scnprintf(buf + len, buf_len - len, "cca_obss_usec = %u\n\n", + le32_to_cpu(htt_stats_buf->cca_obss_usec)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_obss_pd_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_obss_pd_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u8 i; + static const char *access_cat_names[ATH12K_HTT_NUM_AC_WMM] = {"best effort", + "background", + "video", "voice"}; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_OBSS_PD_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "num_spatial_reuse_tx = %u\n", + le32_to_cpu(htt_stats_buf->num_sr_tx_transmissions)); + len += scnprintf(buf + len, buf_len - len, + "num_spatial_reuse_opportunities = %u\n", + le32_to_cpu(htt_stats_buf->num_spatial_reuse_opportunities)); + len += scnprintf(buf + len, buf_len - len, "num_non_srg_opportunities = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_opportunities)); + len += scnprintf(buf + len, buf_len - len, "num_non_srg_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_ppdu_tried)); + len += scnprintf(buf + len, buf_len - len, "num_non_srg_ppdu_success = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_ppdu_success)); + len += scnprintf(buf + len, buf_len - len, "num_srg_opportunities = %u\n", + le32_to_cpu(htt_stats_buf->num_srg_opportunities)); + len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_srg_ppdu_tried)); + len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_success = %u\n", + le32_to_cpu(htt_stats_buf->num_srg_ppdu_success)); + len += scnprintf(buf + len, buf_len - len, "num_psr_opportunities = %u\n", + le32_to_cpu(htt_stats_buf->num_psr_opportunities)); + len += scnprintf(buf + len, buf_len - len, "num_psr_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_psr_ppdu_tried)); + len += scnprintf(buf + len, buf_len - len, "num_psr_ppdu_success = %u\n", + le32_to_cpu(htt_stats_buf->num_psr_ppdu_success)); + len += scnprintf(buf + len, buf_len - len, "min_duration_check_flush_cnt = %u\n", + le32_to_cpu(htt_stats_buf->num_obss_min_dur_check_flush_cnt)); + len += scnprintf(buf + len, buf_len - len, "sr_ppdu_abort_flush_cnt = %u\n\n", + le32_to_cpu(htt_stats_buf->num_sr_ppdu_abort_flush_cnt)); + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_OBSS_PD_PER_AC_STATS:\n"); + for (i = 0; i < ATH12K_HTT_NUM_AC_WMM; i++) { + len += scnprintf(buf + len, buf_len - len, "Access Category %u (%s)\n", + i, access_cat_names[i]); + len += scnprintf(buf + len, buf_len - len, + "num_non_srg_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_tried_per_ac[i])); + len += scnprintf(buf + len, buf_len - len, + "num_non_srg_ppdu_success = %u\n", + le32_to_cpu(htt_stats_buf->num_non_srg_success_ac[i])); + len += scnprintf(buf + len, buf_len - len, "num_srg_ppdu_tried = %u\n", + le32_to_cpu(htt_stats_buf->num_srg_tried_per_ac[i])); + len += scnprintf(buf + len, buf_len - len, + "num_srg_ppdu_success = %u\n\n", + le32_to_cpu(htt_stats_buf->num_srg_success_per_ac[i])); + } + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_dmac_reset_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_dmac_reset_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u64 time; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_DMAC_RESET_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "reset_count = %u\n", + le32_to_cpu(htt_stats_buf->reset_count)); + time = ath12k_le32hilo_to_u64(htt_stats_buf->reset_time_hi_ms, + htt_stats_buf->reset_time_lo_ms); + len += scnprintf(buf + len, buf_len - len, "reset_time_ms = %llu\n", time); + + time = ath12k_le32hilo_to_u64(htt_stats_buf->disengage_time_hi_ms, + htt_stats_buf->disengage_time_lo_ms); + len += scnprintf(buf + len, buf_len - len, "disengage_time_ms = %llu\n", time); + + time = ath12k_le32hilo_to_u64(htt_stats_buf->engage_time_hi_ms, + htt_stats_buf->engage_time_lo_ms); + len += scnprintf(buf + len, buf_len - len, "engage_time_ms = %llu\n", time); + + len += scnprintf(buf + len, buf_len - len, "disengage_count = %u\n", + le32_to_cpu(htt_stats_buf->disengage_count)); + len += scnprintf(buf + len, buf_len - len, "engage_count = %u\n", + le32_to_cpu(htt_stats_buf->engage_count)); + len += scnprintf(buf + len, buf_len - len, "drain_dest_ring_mask = 0x%x\n\n", + le32_to_cpu(htt_stats_buf->drain_dest_ring_mask)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_sched_algo_ofdma_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_sched_algo_ofdma_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_SCHED_ALGO_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += print_array_to_buf(buf, len, "rate_based_dlofdma_enabled_count", + htt_stats_buf->rate_based_dlofdma_enabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "rate_based_dlofdma_disabled_count", + htt_stats_buf->rate_based_dlofdma_disabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "rate_based_dlofdma_probing_count", + htt_stats_buf->rate_based_dlofdma_disabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "rate_based_dlofdma_monitoring_count", + htt_stats_buf->rate_based_dlofdma_monitor_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_enabled_count", + htt_stats_buf->chan_acc_lat_based_dlofdma_enabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_disabled_count", + htt_stats_buf->chan_acc_lat_based_dlofdma_disabled_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "chan_acc_lat_based_dlofdma_monitoring_count", + htt_stats_buf->chan_acc_lat_based_dlofdma_monitor_cnt, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "downgrade_to_dl_su_ru_alloc_fail", + htt_stats_buf->downgrade_to_dl_su_ru_alloc_fail, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "candidate_list_single_user_disable_ofdma", + htt_stats_buf->candidate_list_single_user_disable_ofdma, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "dl_cand_list_dropped_high_ul_qos_weight", + htt_stats_buf->dl_cand_list_dropped_high_ul_qos_weight, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "ax_dlofdma_disabled_due_to_pipelining", + htt_stats_buf->ax_dlofdma_disabled_due_to_pipelining, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "dlofdma_disabled_su_only_eligible", + htt_stats_buf->dlofdma_disabled_su_only_eligible, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "dlofdma_disabled_consec_no_mpdus_tried", + htt_stats_buf->dlofdma_disabled_consec_no_mpdus_tried, + ATH12K_HTT_NUM_AC_WMM, "\n"); + len += print_array_to_buf(buf, len, "dlofdma_disabled_consec_no_mpdus_success", + htt_stats_buf->dlofdma_disabled_consec_no_mpdus_success, + ATH12K_HTT_NUM_AC_WMM, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_tx_pdev_rate_stats_be_ofdma_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_pdev_rate_stats_be_ofdma_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 mac_id_word; + u8 i; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, + "HTT_TX_PDEV_RATE_STATS_BE_OFDMA_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "be_ofdma_tx_ldpc = %u\n", + le32_to_cpu(htt_stats_buf->be_ofdma_tx_ldpc)); + len += print_array_to_buf(buf, len, "be_ofdma_tx_mcs", + htt_stats_buf->be_ofdma_tx_mcs, + ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS, "\n"); + len += print_array_to_buf(buf, len, "be_ofdma_eht_sig_mcs", + htt_stats_buf->be_ofdma_eht_sig_mcs, + ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS, "\n"); + len += scnprintf(buf + len, buf_len - len, "be_ofdma_tx_ru_size = "); + for (i = 0; i < ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS; i++) + len += scnprintf(buf + len, buf_len - len, " %s:%u ", + ath12k_htt_be_tx_rx_ru_size_to_str(i), + le32_to_cpu(htt_stats_buf->be_ofdma_tx_ru_size[i])); + len += scnprintf(buf + len, buf_len - len, "\n"); + len += print_array_to_buf_index(buf, len, "be_ofdma_tx_nss = ", 1, + htt_stats_buf->be_ofdma_tx_nss, + ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS, + "\n"); + len += print_array_to_buf(buf, len, "be_ofdma_tx_bw", + htt_stats_buf->be_ofdma_tx_bw, + ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS, "\n"); + for (i = 0; i < ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS; i++) { + len += scnprintf(buf + len, buf_len - len, + "be_ofdma_tx_gi[%u]", i); + len += print_array_to_buf(buf, len, "", htt_stats_buf->gi[i], + ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS, "\n"); + } + len += scnprintf(buf + len, buf_len - len, "\n"); + + stats_req->buf_len = len; +} + static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *tag_buf, void *user_data) @@ -1552,6 +2801,83 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_TX_DE_COMPL_STATS_TAG: ath12k_htt_print_tx_de_compl_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_TX_SELFGEN_CMN_STATS_TAG: + ath12k_htt_print_tx_selfgen_cmn_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AC_STATS_TAG: + ath12k_htt_print_tx_selfgen_ac_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AX_STATS_TAG: + ath12k_htt_print_tx_selfgen_ax_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_BE_STATS_TAG: + ath12k_htt_print_tx_selfgen_be_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AC_ERR_STATS_TAG: + ath12k_htt_print_tx_selfgen_ac_err_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AX_ERR_STATS_TAG: + ath12k_htt_print_tx_selfgen_ax_err_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG: + ath12k_htt_print_tx_selfgen_be_err_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_SELFGEN_AC_SCHED_STATUS_STATS_TAG: + ath12k_htt_print_tx_selfgen_ac_sched_status_stats_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_TX_SELFGEN_AX_SCHED_STATUS_STATS_TAG: + ath12k_htt_print_tx_selfgen_ax_sched_status_stats_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG: + ath12k_htt_print_tx_selfgen_be_sched_status_stats_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_STRING_TAG: + ath12k_htt_print_stats_string_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SRING_STATS_TAG: + ath12k_htt_print_sring_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SFM_CMN_TAG: + ath12k_htt_print_sfm_cmn_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SFM_CLIENT_TAG: + ath12k_htt_print_sfm_client_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_SFM_CLIENT_USER_TAG: + ath12k_htt_print_sfm_client_user_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG: + ath12k_htt_print_tx_pdev_mu_mimo_sch_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_MUMIMO_GRP_STATS_TAG: + ath12k_htt_print_tx_pdev_mumimo_grp_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_MPDU_STATS_TAG: + ath12k_htt_print_tx_pdev_mu_mimo_mpdu_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_CCA_1SEC_HIST_TAG: + case HTT_STATS_PDEV_CCA_100MSEC_HIST_TAG: + case HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG: + ath12k_htt_print_pdev_cca_stats_hist_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_CCA_COUNTERS_TAG: + ath12k_htt_print_pdev_stats_cca_counters_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_OBSS_PD_TAG: + ath12k_htt_print_pdev_obss_pd_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_DMAC_RESET_STATS_TAG: + ath12k_htt_print_dmac_reset_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG: + ath12k_htt_print_pdev_sched_algo_ofdma_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG: + ath12k_htt_print_tx_pdev_rate_stats_be_ofdma_tlv(tag_buf, len, stats_req); + break; default: break; } @@ -1627,9 +2953,9 @@ static ssize_t ath12k_read_htt_stats_type(struct file *file, char buf[32]; size_t len; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); type = ar->debug.htt_stats.type; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); len = scnprintf(buf, sizeof(buf), "%u\n", type); @@ -1662,7 +2988,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file, type >= ATH12K_DBG_HTT_NUM_EXT_STATS) return -EINVAL; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); ar->debug.htt_stats.type = type; ar->debug.htt_stats.cfg_param[0] = cfg_param[0]; @@ -1670,7 +2996,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file, ar->debug.htt_stats.cfg_param[2] = cfg_param[2]; ar->debug.htt_stats.cfg_param[3] = cfg_param[3]; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return count; } @@ -1691,7 +3017,7 @@ static int ath12k_debugfs_htt_stats_req(struct ath12k *ar) int ret, pdev_id; struct htt_ext_stats_cfg_params cfg_params = { 0 }; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); init_completion(&stats_req->htt_stats_rcvd); @@ -1741,7 +3067,7 @@ static int ath12k_open_htt_stats(struct inode *inode, if (type == ATH12K_DBG_HTT_EXT_STATS_RESET) return -EPERM; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); if (ah->state != ATH12K_HW_STATE_ON) { ret = -ENETDOWN; @@ -1776,14 +3102,14 @@ static int ath12k_open_htt_stats(struct inode *inode, file->private_data = stats_req; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return 0; out: kfree(stats_req); ar->debug.htt_stats.stats_req = NULL; err_unlock: - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return ret; } @@ -1793,10 +3119,10 @@ static int ath12k_release_htt_stats(struct inode *inode, { struct ath12k *ar = inode->i_private; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); kfree(file->private_data); ar->debug.htt_stats.stats_req = NULL; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return 0; } @@ -1840,7 +3166,7 @@ static ssize_t ath12k_write_htt_stats_reset(struct file *file, type == ATH12K_DBG_HTT_EXT_STATS_RESET) return -E2BIG; - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); cfg_params.cfg0 = HTT_STAT_DEFAULT_RESET_START_OFFSET; param_pos = (type >> 5) + 1; @@ -1866,12 +3192,12 @@ static ssize_t ath12k_write_htt_stats_reset(struct file *file, 0ULL); if (ret) { ath12k_warn(ar->ab, "failed to send htt stats request: %d\n", ret); - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return ret; } ar->debug.htt_stats.reset = type; - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); return count; } diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index d52b26b23e6539..ac86cab234ecb7 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -123,12 +123,21 @@ struct ath12k_htt_extd_stats_msg { /* htt_dbg_ext_stats_type */ enum ath12k_dbg_htt_ext_stats_type { - ATH12K_DBG_HTT_EXT_STATS_RESET = 0, - ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1, - ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4, - ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5, - ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6, - ATH12K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8, + ATH12K_DBG_HTT_EXT_STATS_RESET = 0, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4, + ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6, + ATH12K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8, + ATH12K_DBG_HTT_EXT_STATS_TX_SELFGEN_INFO = 12, + ATH12K_DBG_HTT_EXT_STATS_SRNG_INFO = 15, + ATH12K_DBG_HTT_EXT_STATS_SFM_INFO = 16, + ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_MU = 17, + ATH12K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19, + ATH12K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23, + ATH12K_DBG_HTT_EXT_STATS_SOC_ERROR = 45, + ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49, + ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, @@ -139,6 +148,7 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_PDEV_UNDERRUN_TAG = 1, HTT_STATS_TX_PDEV_SIFS_TAG = 2, HTT_STATS_TX_PDEV_FLUSH_TAG = 3, + HTT_STATS_STRING_TAG = 5, HTT_STATS_TX_TQM_GEN_MPDU_TAG = 11, HTT_STATS_TX_TQM_LIST_MPDU_TAG = 12, HTT_STATS_TX_TQM_LIST_MPDU_CNT_TAG = 13, @@ -151,22 +161,47 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_DE_ENQUEUE_PACKETS_TAG = 21, HTT_STATS_TX_DE_ENQUEUE_DISCARD_TAG = 22, HTT_STATS_TX_DE_CMN_TAG = 23, + HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG = 25, + HTT_STATS_SFM_CMN_TAG = 26, + HTT_STATS_SRING_STATS_TAG = 27, HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG = 36, HTT_STATS_TX_SCHED_CMN_TAG = 37, HTT_STATS_SCHED_TXQ_CMD_POSTED_TAG = 39, + HTT_STATS_SFM_CLIENT_USER_TAG = 41, + HTT_STATS_SFM_CLIENT_TAG = 42, HTT_STATS_TX_TQM_ERROR_STATS_TAG = 43, HTT_STATS_SCHED_TXQ_CMD_REAPED_TAG = 44, + HTT_STATS_TX_SELFGEN_AC_ERR_STATS_TAG = 46, + HTT_STATS_TX_SELFGEN_CMN_STATS_TAG = 47, + HTT_STATS_TX_SELFGEN_AC_STATS_TAG = 48, + HTT_STATS_TX_SELFGEN_AX_STATS_TAG = 49, + HTT_STATS_TX_SELFGEN_AX_ERR_STATS_TAG = 50, HTT_STATS_HW_INTR_MISC_TAG = 54, HTT_STATS_HW_PDEV_ERRS_TAG = 56, HTT_STATS_TX_DE_COMPL_STATS_TAG = 65, HTT_STATS_WHAL_TX_TAG = 66, HTT_STATS_TX_PDEV_SIFS_HIST_TAG = 67, + HTT_STATS_PDEV_CCA_1SEC_HIST_TAG = 70, + HTT_STATS_PDEV_CCA_100MSEC_HIST_TAG = 71, + HTT_STATS_PDEV_CCA_STAT_CUMULATIVE_TAG = 72, + HTT_STATS_PDEV_CCA_COUNTERS_TAG = 73, + HTT_STATS_TX_PDEV_MPDU_STATS_TAG = 74, HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG = 86, HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG = 87, + HTT_STATS_PDEV_OBSS_PD_TAG = 88, HTT_STATS_HW_WAR_TAG = 89, HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG = 100, HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG = 102, + HTT_STATS_TX_SELFGEN_AC_SCHED_STATUS_STATS_TAG = 111, + HTT_STATS_TX_SELFGEN_AX_SCHED_STATUS_STATS_TAG = 112, HTT_STATS_MU_PPDU_DIST_TAG = 129, + HTT_STATS_TX_PDEV_MUMIMO_GRP_STATS_TAG = 130, + HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG = 135, + HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG = 137, + HTT_STATS_TX_SELFGEN_BE_STATS_TAG = 138, + HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG = 139, + HTT_STATS_DMAC_RESET_STATS_TAG = 155, + HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG = 165, HTT_STATS_MAX_TAG, }; @@ -690,4 +725,401 @@ struct ath12k_htt_tx_de_compl_stats_tlv { __le32 tqm_bypass_frame; } __packed; +enum ath12k_htt_tx_mumimo_grp_invalid_reason_code_stats { + ATH12K_HTT_TX_MUMIMO_GRP_VALID, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_NUM_MU_USERS_EXCEEDED_MU_MAX_USERS, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_SCHED_ALGO_NOT_MU_COMPATIBLE_GID, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_NON_PRIMARY_GRP, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_ZERO_CANDIDATES, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MORE_CANDIDATES, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_SIZE_EXCEED_NSS, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_INELIGIBLE, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_GROUP_EFF_MU_TPUT_OMBPS, + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MAX_REASON_CODE, +}; + +#define ATH12K_HTT_NUM_AC_WMM 0x4 +#define ATH12K_HTT_MAX_NUM_SBT_INTR 4 +#define ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS 4 +#define ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS 8 +#define ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS 8 +#define ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS 7 +#define ATH12K_HTT_TX_NUM_OFDMA_USER_STATS 74 +#define ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS 8 +#define ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ 8 +#define ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS 10 + +#define ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE \ + ATH12K_HTT_TX_MUMIMO_GRP_INVALID_MAX_REASON_CODE +#define ATH12K_HTT_TX_NUM_MUMIMO_GRP_INVALID_WORDS \ + (ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ * ATH12K_HTT_STATS_MAX_INVALID_REASON_CODE) + +struct ath12k_htt_tx_selfgen_cmn_stats_tlv { + __le32 mac_id__word; + __le32 su_bar; + __le32 rts; + __le32 cts2self; + __le32 qos_null; + __le32 delayed_bar_1; + __le32 delayed_bar_2; + __le32 delayed_bar_3; + __le32 delayed_bar_4; + __le32 delayed_bar_5; + __le32 delayed_bar_6; + __le32 delayed_bar_7; +} __packed; + +struct ath12k_htt_tx_selfgen_ac_stats_tlv { + __le32 ac_su_ndpa; + __le32 ac_su_ndp; + __le32 ac_mu_mimo_ndpa; + __le32 ac_mu_mimo_ndp; + __le32 ac_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS - 1]; +} __packed; + +struct ath12k_htt_tx_selfgen_ax_stats_tlv { + __le32 ax_su_ndpa; + __le32 ax_su_ndp; + __le32 ax_mu_mimo_ndpa; + __le32 ax_mu_mimo_ndp; + __le32 ax_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1]; + __le32 ax_basic_trigger; + __le32 ax_bsr_trigger; + __le32 ax_mu_bar_trigger; + __le32 ax_mu_rts_trigger; + __le32 ax_ulmumimo_trigger; +} __packed; + +struct ath12k_htt_tx_selfgen_be_stats_tlv { + __le32 be_su_ndpa; + __le32 be_su_ndp; + __le32 be_mu_mimo_ndpa; + __le32 be_mu_mimo_ndp; + __le32 be_mu_mimo_brpoll[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1]; + __le32 be_basic_trigger; + __le32 be_bsr_trigger; + __le32 be_mu_bar_trigger; + __le32 be_mu_rts_trigger; + __le32 be_ulmumimo_trigger; + __le32 be_su_ndpa_queued; + __le32 be_su_ndp_queued; + __le32 be_mu_mimo_ndpa_queued; + __le32 be_mu_mimo_ndp_queued; + __le32 be_mu_mimo_brpoll_queued[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1]; + __le32 be_ul_mumimo_trigger[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; +} __packed; + +struct ath12k_htt_tx_selfgen_ac_err_stats_tlv { + __le32 ac_su_ndp_err; + __le32 ac_su_ndpa_err; + __le32 ac_mu_mimo_ndpa_err; + __le32 ac_mu_mimo_ndp_err; + __le32 ac_mu_mimo_brp1_err; + __le32 ac_mu_mimo_brp2_err; + __le32 ac_mu_mimo_brp3_err; +} __packed; + +struct ath12k_htt_tx_selfgen_ax_err_stats_tlv { + __le32 ax_su_ndp_err; + __le32 ax_su_ndpa_err; + __le32 ax_mu_mimo_ndpa_err; + __le32 ax_mu_mimo_ndp_err; + __le32 ax_mu_mimo_brp_err[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS - 1]; + __le32 ax_basic_trigger_err; + __le32 ax_bsr_trigger_err; + __le32 ax_mu_bar_trigger_err; + __le32 ax_mu_rts_trigger_err; + __le32 ax_ulmumimo_trigger_err; +} __packed; + +struct ath12k_htt_tx_selfgen_be_err_stats_tlv { + __le32 be_su_ndp_err; + __le32 be_su_ndpa_err; + __le32 be_mu_mimo_ndpa_err; + __le32 be_mu_mimo_ndp_err; + __le32 be_mu_mimo_brp_err[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1]; + __le32 be_basic_trigger_err; + __le32 be_bsr_trigger_err; + __le32 be_mu_bar_trigger_err; + __le32 be_mu_rts_trigger_err; + __le32 be_ulmumimo_trigger_err; + __le32 be_mu_mimo_brp_err_num_cbf_rxd[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; + __le32 be_su_ndpa_flushed; + __le32 be_su_ndp_flushed; + __le32 be_mu_mimo_ndpa_flushed; + __le32 be_mu_mimo_ndp_flushed; + __le32 be_mu_mimo_brpoll_flushed[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS - 1]; + __le32 be_ul_mumimo_trigger_err[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; +} __packed; + +enum ath12k_htt_tx_selfgen_sch_tsflag_error_stats { + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_FLUSH_RCVD_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_FILT_SCHED_CMD_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_MISMATCH_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_CBF_MIMO_CTRL_MISMATCH_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_CBF_BW_MISMATCH_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RETRY_COUNT_FAIL_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_RESP_TOO_LATE_RECEIVED_ERR, + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_SIFS_STALL_NO_NEXT_CMD_ERR, + + ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS +}; + +struct ath12k_htt_tx_selfgen_ac_sched_status_stats_tlv { + __le32 ac_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ac_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ac_mu_mimo_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ac_mu_mimo_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; +} __packed; + +struct ath12k_htt_tx_selfgen_ax_sched_status_stats_tlv { + __le32 ax_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_mu_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_mu_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_mu_bar_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_mu_bar_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_basic_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_basic_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 ax_ulmumimo_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 ax_ulmumimo_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; +} __packed; + +struct ath12k_htt_tx_selfgen_be_sched_status_stats_tlv { + __le32 be_su_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_su_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_su_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_mu_mimo_ndpa_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_mu_mimo_ndp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_mu_mimo_ndp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_mu_brp_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_mu_brp_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_mu_bar_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_mu_bar_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_basic_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_basic_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; + __le32 be_ulmumimo_trig_sch_status[ATH12K_HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + __le32 be_ulmumimo_trig_sch_flag_err[ATH12K_HTT_TX_SELFGEN_SCH_TSFLAG_ERR_STATS]; +} __packed; + +struct ath12k_htt_stats_string_tlv { + DECLARE_FLEX_ARRAY(__le32, data); +} __packed; + +#define ATH12K_HTT_SRING_STATS_MAC_ID GENMASK(7, 0) +#define ATH12K_HTT_SRING_STATS_RING_ID GENMASK(15, 8) +#define ATH12K_HTT_SRING_STATS_ARENA GENMASK(23, 16) +#define ATH12K_HTT_SRING_STATS_EP BIT(24) +#define ATH12K_HTT_SRING_STATS_NUM_AVAIL_WORDS GENMASK(15, 0) +#define ATH12K_HTT_SRING_STATS_NUM_VALID_WORDS GENMASK(31, 16) +#define ATH12K_HTT_SRING_STATS_HEAD_PTR GENMASK(15, 0) +#define ATH12K_HTT_SRING_STATS_TAIL_PTR GENMASK(31, 16) +#define ATH12K_HTT_SRING_STATS_CONSUMER_EMPTY GENMASK(15, 0) +#define ATH12K_HTT_SRING_STATS_PRODUCER_FULL GENMASK(31, 16) +#define ATH12K_HTT_SRING_STATS_PREFETCH_COUNT GENMASK(15, 0) +#define ATH12K_HTT_SRING_STATS_INTERNAL_TAIL_PTR GENMASK(31, 16) + +struct ath12k_htt_sring_stats_tlv { + __le32 mac_id__ring_id__arena__ep; + __le32 base_addr_lsb; + __le32 base_addr_msb; + __le32 ring_size; + __le32 elem_size; + __le32 num_avail_words__num_valid_words; + __le32 head_ptr__tail_ptr; + __le32 consumer_empty__producer_full; + __le32 prefetch_count__internal_tail_ptr; +} __packed; + +struct ath12k_htt_sfm_cmn_tlv { + __le32 mac_id__word; + __le32 buf_total; + __le32 mem_empty; + __le32 deallocate_bufs; + __le32 num_records; +} __packed; + +struct ath12k_htt_sfm_client_tlv { + __le32 client_id; + __le32 buf_min; + __le32 buf_max; + __le32 buf_busy; + __le32 buf_alloc; + __le32 buf_avail; + __le32 num_users; +} __packed; + +struct ath12k_htt_sfm_client_user_tlv { + DECLARE_FLEX_ARRAY(__le32, dwords_used_by_user_n); +} __packed; + +struct ath12k_htt_tx_pdev_mu_mimo_sch_stats_tlv { + __le32 mu_mimo_sch_posted; + __le32 mu_mimo_sch_failed; + __le32 mu_mimo_ppdu_posted; + __le32 ac_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS]; + __le32 ax_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS]; + __le32 ax_ofdma_sch_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_ofdma_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_ofdma_bsr_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_ofdma_bar_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_ofdma_brp_nusers[ATH12K_HTT_TX_NUM_OFDMA_USER_STATS]; + __le32 ax_ul_mumimo_nusers[ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS]; + __le32 ax_ul_mumimo_brp_nusers[ATH12K_HTT_TX_NUM_UL_MUMIMO_USER_STATS]; + __le32 ac_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS]; + __le32 ax_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS]; + __le32 be_mu_mimo_sch_nusers[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; + __le32 be_mu_mimo_per_grp_sz[ATH12K_HTT_TX_NUM_BE_MUMIMO_USER_STATS]; + __le32 ac_mu_mimo_grp_sz_ext[ATH12K_HTT_TX_NUM_AC_MUMIMO_USER_STATS]; +} __packed; + +struct ath12k_htt_tx_pdev_mumimo_grp_stats_tlv { + __le32 dl_mumimo_grp_best_grp_size[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ]; + __le32 dl_mumimo_grp_best_num_usrs[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS]; + __le32 dl_mumimo_grp_eligible[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ]; + __le32 dl_mumimo_grp_ineligible[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ]; + __le32 dl_mumimo_grp_invalid[ATH12K_HTT_TX_NUM_MUMIMO_GRP_INVALID_WORDS]; + __le32 dl_mumimo_grp_tputs[ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS]; + __le32 ul_mumimo_grp_best_grp_size[ATH12K_HTT_STATS_NUM_MAX_MUMIMO_SZ]; + __le32 ul_mumimo_grp_best_usrs[ATH12K_HTT_TX_NUM_AX_MUMIMO_USER_STATS]; + __le32 ul_mumimo_grp_tputs[ATH12K_HTT_STATS_MUMIMO_TPUT_NUM_BINS]; +} __packed; + +enum ath12k_htt_stats_tx_sched_modes { + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AC = 0, + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_AX, + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_AX, + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_OFDMA_BE, + ATH12K_HTT_STATS_TX_SCHED_MODE_MU_MIMO_BE +}; + +struct ath12k_htt_tx_pdev_mpdu_stats_tlv { + __le32 mpdus_queued_usr; + __le32 mpdus_tried_usr; + __le32 mpdus_failed_usr; + __le32 mpdus_requeued_usr; + __le32 err_no_ba_usr; + __le32 mpdu_underrun_usr; + __le32 ampdu_underrun_usr; + __le32 user_index; + __le32 tx_sched_mode; +} __packed; + +struct ath12k_htt_pdev_stats_cca_counters_tlv { + __le32 tx_frame_usec; + __le32 rx_frame_usec; + __le32 rx_clear_usec; + __le32 my_rx_frame_usec; + __le32 usec_cnt; + __le32 med_rx_idle_usec; + __le32 med_tx_idle_global_usec; + __le32 cca_obss_usec; +} __packed; + +struct ath12k_htt_pdev_cca_stats_hist_v1_tlv { + __le32 chan_num; + __le32 num_records; + __le32 valid_cca_counters_bitmap; + __le32 collection_interval; +} __packed; + +struct ath12k_htt_pdev_obss_pd_stats_tlv { + __le32 num_obss_tx_ppdu_success; + __le32 num_obss_tx_ppdu_failure; + __le32 num_sr_tx_transmissions; + __le32 num_spatial_reuse_opportunities; + __le32 num_non_srg_opportunities; + __le32 num_non_srg_ppdu_tried; + __le32 num_non_srg_ppdu_success; + __le32 num_srg_opportunities; + __le32 num_srg_ppdu_tried; + __le32 num_srg_ppdu_success; + __le32 num_psr_opportunities; + __le32 num_psr_ppdu_tried; + __le32 num_psr_ppdu_success; + __le32 num_non_srg_tried_per_ac[ATH12K_HTT_NUM_AC_WMM]; + __le32 num_non_srg_success_ac[ATH12K_HTT_NUM_AC_WMM]; + __le32 num_srg_tried_per_ac[ATH12K_HTT_NUM_AC_WMM]; + __le32 num_srg_success_per_ac[ATH12K_HTT_NUM_AC_WMM]; + __le32 num_obss_min_dur_check_flush_cnt; + __le32 num_sr_ppdu_abort_flush_cnt; +} __packed; + +struct ath12k_htt_dmac_reset_stats_tlv { + __le32 reset_count; + __le32 reset_time_lo_ms; + __le32 reset_time_hi_ms; + __le32 disengage_time_lo_ms; + __le32 disengage_time_hi_ms; + __le32 engage_time_lo_ms; + __le32 engage_time_hi_ms; + __le32 disengage_count; + __le32 engage_count; + __le32 drain_dest_ring_mask; +} __packed; + +struct ath12k_htt_pdev_sched_algo_ofdma_stats_tlv { + __le32 mac_id__word; + __le32 rate_based_dlofdma_enabled_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 rate_based_dlofdma_disabled_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 rate_based_dlofdma_probing_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 rate_based_dlofdma_monitor_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 chan_acc_lat_based_dlofdma_enabled_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 chan_acc_lat_based_dlofdma_disabled_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 chan_acc_lat_based_dlofdma_monitor_cnt[ATH12K_HTT_NUM_AC_WMM]; + __le32 downgrade_to_dl_su_ru_alloc_fail[ATH12K_HTT_NUM_AC_WMM]; + __le32 candidate_list_single_user_disable_ofdma[ATH12K_HTT_NUM_AC_WMM]; + __le32 dl_cand_list_dropped_high_ul_qos_weight[ATH12K_HTT_NUM_AC_WMM]; + __le32 ax_dlofdma_disabled_due_to_pipelining[ATH12K_HTT_NUM_AC_WMM]; + __le32 dlofdma_disabled_su_only_eligible[ATH12K_HTT_NUM_AC_WMM]; + __le32 dlofdma_disabled_consec_no_mpdus_tried[ATH12K_HTT_NUM_AC_WMM]; + __le32 dlofdma_disabled_consec_no_mpdus_success[ATH12K_HTT_NUM_AC_WMM]; +} __packed; + +enum ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE { + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_26, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_52_26, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_106_26, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_242, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_484_242, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996_484_242, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x2_484, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x3_484, + ATH12K_HTT_TX_RX_PDEV_STATS_BE_RU_SIZE_996x4, + ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS, +}; + +#define ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS 8 +#define ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS 16 +#define ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS 5 +#define ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS 4 +#define ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS 4 + +struct ath12k_htt_tx_pdev_rate_stats_be_ofdma_tlv { + __le32 mac_id__word; + __le32 be_ofdma_tx_ldpc; + __le32 be_ofdma_tx_mcs[ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS]; + __le32 be_ofdma_tx_nss[ATH12K_HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; + __le32 be_ofdma_tx_bw[ATH12K_HTT_TX_PDEV_NUM_BE_BW_CNTRS]; + __le32 gi[ATH12K_HTT_TX_PDEV_NUM_GI_CNTRS][ATH12K_HTT_TX_PDEV_NUM_BE_MCS_CNTRS]; + __le32 be_ofdma_tx_ru_size[ATH12K_HTT_TX_RX_PDEV_NUM_BE_RU_SIZE_CNTRS]; + __le32 be_ofdma_eht_sig_mcs[ATH12K_HTT_TX_PDEV_NUM_EHT_SIG_MCS_CNTRS]; +} __packed; + #endif diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 61aa78d8bd8c8f..c99e9ceb1a6e8c 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -327,20 +327,22 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring, } static -u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif *arvif) +u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, + struct ath12k_link_vif *arvif) { u32 bank_config = 0; + struct ath12k_vif *ahvif = arvif->ahvif; /* Only valid for raw frames with HW crypto enabled. * With SW crypto, mac80211 sets key per packet */ - if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && + if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) bank_config |= - u32_encode_bits(ath12k_dp_tx_get_encrypt_type(arvif->key_cipher), + u32_encode_bits(ath12k_dp_tx_get_encrypt_type(ahvif->key_cipher), HAL_TX_BANK_CONFIG_ENCRYPT_TYPE); - bank_config |= u32_encode_bits(arvif->tx_encap_type, + bank_config |= u32_encode_bits(ahvif->tx_encap_type, HAL_TX_BANK_CONFIG_ENCAP_TYPE); bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_SRC_BUFFER_SWAP) | u32_encode_bits(0, HAL_TX_BANK_CONFIG_LINK_META_SWAP) | @@ -355,7 +357,7 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif HAL_TX_ADDRY_EN), HAL_TX_BANK_CONFIG_ADDRY_EN); - bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(arvif->vif) ? 3 : 0, + bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(ahvif->vif) ? 3 : 0, HAL_TX_BANK_CONFIG_MESH_EN) | u32_encode_bits(arvif->vdev_id_check_en, HAL_TX_BANK_CONFIG_VDEV_ID_CHECK_EN); @@ -365,7 +367,8 @@ u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab, struct ath12k_vif return bank_config; } -static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab, struct ath12k_vif *arvif, +static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab, + struct ath12k_link_vif *arvif, struct ath12k_dp *dp) { int bank_id = DP_INVALID_BANK_ID; @@ -1099,9 +1102,9 @@ int ath12k_dp_htt_connect(struct ath12k_dp *dp) return 0; } -static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif) +static void ath12k_dp_update_vdev_search(struct ath12k_link_vif *arvif) { - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_STA: /* TODO: Verify the search type and flags since ast hash * is not part of peer mapv3 @@ -1120,7 +1123,7 @@ static void ath12k_dp_update_vdev_search(struct ath12k_vif *arvif) } } -void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif) +void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif) { struct ath12k_base *ab = ar->ab; @@ -1162,7 +1165,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) spin_lock_bh(&dp->rx_desc_lock); for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - desc_info = dp->spt_info->rxbaddr[i]; + desc_info = dp->rxbaddr[i]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { if (!desc_info[j].in_use) { @@ -1181,11 +1184,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) } for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - if (!dp->spt_info->rxbaddr[i]) + if (!dp->rxbaddr[i]) continue; - kfree(dp->spt_info->rxbaddr[i]); - dp->spt_info->rxbaddr[i] = NULL; + kfree(dp->rxbaddr[i]); + dp->rxbaddr[i] = NULL; } spin_unlock_bh(&dp->rx_desc_lock); @@ -1202,10 +1205,16 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) if (!skb) continue; - skb_cb = ATH12K_SKB_CB(skb); - ar = skb_cb->ar; - if (atomic_dec_and_test(&ar->dp.num_tx_pending)) - wake_up(&ar->dp.tx_empty_waitq); + /* if we are unregistering, hw would've been destroyed and + * ar is no longer valid. + */ + if (!(test_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags))) { + skb_cb = ATH12K_SKB_CB(skb); + ar = skb_cb->ar; + + if (atomic_dec_and_test(&ar->dp.num_tx_pending)) + wake_up(&ar->dp.tx_empty_waitq); + } dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr, skb->len, DMA_TO_DEVICE); @@ -1220,11 +1229,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) { tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; - if (!dp->spt_info->txbaddr[tx_spt_page]) + if (!dp->txbaddr[tx_spt_page]) continue; - kfree(dp->spt_info->txbaddr[tx_spt_page]); - dp->spt_info->txbaddr[tx_spt_page] = NULL; + kfree(dp->txbaddr[tx_spt_page]); + dp->txbaddr[tx_spt_page] = NULL; } spin_unlock_bh(&dp->tx_desc_lock[pool_id]); @@ -1241,6 +1250,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) } kfree(dp->spt_info); + dp->spt_info = NULL; } static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab) @@ -1276,8 +1286,10 @@ void ath12k_dp_free(struct ath12k_base *ab) ath12k_dp_rx_reo_cmd_list_cleanup(ab); - for (i = 0; i < ab->hw_params->max_tx_ring; i++) + for (i = 0; i < ab->hw_params->max_tx_ring; i++) { kfree(dp->tx_ring[i].tx_status); + dp->tx_ring[i].tx_status = NULL; + } ath12k_dp_rx_free(ab); /* Deinit any SOC level resource */ @@ -1415,7 +1427,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i; cookie_ppt_idx = dp->rx_ppt_base + ppt_idx; - dp->spt_info->rxbaddr[i] = &rx_descs[0]; + dp->rxbaddr[i] = &rx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(cookie_ppt_idx, j); @@ -1445,7 +1457,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page; - dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0]; + dp->txbaddr[tx_spt_page] = &tx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j); diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 2fb18b83b3eec4..2e05fc19410e89 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -16,6 +16,7 @@ struct ath12k_base; struct ath12k_peer; struct ath12k_dp; struct ath12k_vif; +struct ath12k_link_vif; struct hal_tcl_status_ring; struct ath12k_ext_irq_grp; @@ -300,8 +301,6 @@ struct ath12k_tx_desc_info { struct ath12k_spt_info { dma_addr_t paddr; u64 *vaddr; - struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES]; - struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES]; }; struct ath12k_reo_queue_ref { @@ -352,6 +351,8 @@ struct ath12k_dp { struct ath12k_spt_info *spt_info; u32 num_spt_pages; u32 rx_ppt_base; + struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES]; + struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES]; struct list_head rx_desc_free_list; /* protects the free desc list */ spinlock_t rx_desc_lock; @@ -1799,7 +1800,7 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, struct ath12k_ext_irq_grp *irq_grp, int budget); int ath12k_dp_htt_connect(struct ath12k_dp *dp); -void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif); +void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif); void ath12k_dp_free(struct ath12k_base *ab); int ath12k_dp_alloc(struct ath12k_base *ab); void ath12k_dp_cc_config(struct ath12k_base *ab); diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 5c6749bc4039d2..494984133a9196 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -26,15 +26,12 @@ ath12k_dp_mon_rx_populate_byte_count(const struct hal_rx_ppdu_end_user_stats *st void *ppduinfo, struct hal_rx_user_status *rx_user_status) { - u32 mpdu_ok_byte_count = __le32_to_cpu(stats->mpdu_ok_cnt); - u32 mpdu_err_byte_count = __le32_to_cpu(stats->mpdu_err_cnt); - rx_user_status->mpdu_ok_byte_count = - u32_get_bits(mpdu_ok_byte_count, - HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_OK_BYTE_COUNT); + le32_get_bits(stats->info7, + HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT); rx_user_status->mpdu_err_byte_count = - u32_get_bits(mpdu_err_byte_count, - HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_ERR_BYTE_COUNT); + le32_get_bits(stats->info8, + HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT); } static void @@ -593,12 +590,20 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, struct hal_rx_ppdu_start *ppdu_start = (struct hal_rx_ppdu_start *)tlv_data; + u64 ppdu_ts = ath12k_le32hilo_to_u64(ppdu_start->ppdu_start_ts_63_32, + ppdu_start->ppdu_start_ts_31_0); + info[0] = __le32_to_cpu(ppdu_start->info0); - ppdu_info->ppdu_id = - u32_get_bits(info[0], HAL_RX_PPDU_START_INFO0_PPDU_ID); - ppdu_info->chan_num = __le32_to_cpu(ppdu_start->chan_num); - ppdu_info->ppdu_ts = __le32_to_cpu(ppdu_start->ppdu_start_ts); + ppdu_info->ppdu_id = u32_get_bits(info[0], + HAL_RX_PPDU_START_INFO0_PPDU_ID); + + info[1] = __le32_to_cpu(ppdu_start->info1); + ppdu_info->chan_num = u32_get_bits(info[1], + HAL_RX_PPDU_START_INFO1_CHAN_NUM); + ppdu_info->freq = u32_get_bits(info[1], + HAL_RX_PPDU_START_INFO1_CHAN_FREQ); + ppdu_info->ppdu_ts = ppdu_ts; if (ppdu_info->ppdu_id != ppdu_info->last_ppdu_id) { ppdu_info->last_ppdu_id = ppdu_info->ppdu_id; @@ -726,33 +731,20 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, case HAL_PHYRX_RSSI_LEGACY: { struct hal_rx_phyrx_rssi_legacy_info *rssi = (struct hal_rx_phyrx_rssi_legacy_info *)tlv_data; - u32 reception_type = 0; - u32 rssi_legacy_info = __le32_to_cpu(rssi->rsvd[0]); info[0] = __le32_to_cpu(rssi->info0); + info[1] = __le32_to_cpu(rssi->info1); /* TODO: Please note that the combined rssi will not be accurate * in MU case. Rssi in MU needs to be retrieved from * PHYRX_OTHER_RECEIVE_INFO TLV. */ ppdu_info->rssi_comb = - u32_get_bits(info[0], - HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB); - reception_type = - u32_get_bits(rssi_legacy_info, - HAL_RX_PHYRX_RSSI_LEGACY_INFO_RSVD1_RECEPTION); - - switch (reception_type) { - case HAL_RECEPTION_TYPE_ULOFMDA: - ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_OFDMA; - break; - case HAL_RECEPTION_TYPE_ULMIMO: - ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_MU_MIMO; - break; - default: - ppdu_info->reception_type = HAL_RX_RECEPTION_TYPE_SU; - break; - } + u32_get_bits(info[1], + HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB); + + ppdu_info->bw = u32_get_bits(info[0], + HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW); break; } case HAL_RXPCU_PPDU_END_INFO: { @@ -860,27 +852,29 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab, return HAL_RX_MON_STATUS_PPDU_NOT_DONE; } -static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar, struct sk_buff *msdu) +static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar, + struct sk_buff *head_msdu, + struct sk_buff *tail_msdu) { u32 rx_pkt_offset, l2_hdr_offset; rx_pkt_offset = ar->ab->hal.hal_desc_sz; - l2_hdr_offset = ath12k_dp_rx_h_l3pad(ar->ab, - (struct hal_rx_desc *)msdu->data); - skb_pull(msdu, rx_pkt_offset + l2_hdr_offset); + l2_hdr_offset = + ath12k_dp_rx_h_l3pad(ar->ab, (struct hal_rx_desc *)tail_msdu->data); + skb_pull(head_msdu, rx_pkt_offset + l2_hdr_offset); } static struct sk_buff * -ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, - u32 mac_id, struct sk_buff *head_msdu, +ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, u32 mac_id, + struct sk_buff *head_msdu, struct sk_buff *tail_msdu, struct ieee80211_rx_status *rxs, bool *fcs_err) { struct ath12k_base *ab = ar->ab; - struct sk_buff *msdu, *mpdu_buf, *prev_buf; - struct hal_rx_desc *rx_desc; + struct sk_buff *msdu, *mpdu_buf, *prev_buf, *head_frag_list; + struct hal_rx_desc *rx_desc, *tail_rx_desc; u8 *hdr_desc, *dest, decap_format; struct ieee80211_hdr_3addr *wh; - u32 err_bitmap; + u32 err_bitmap, frag_list_sum_len = 0; mpdu_buf = NULL; @@ -888,24 +882,30 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, goto err_merge_fail; rx_desc = (struct hal_rx_desc *)head_msdu->data; - err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, rx_desc); + tail_rx_desc = (struct hal_rx_desc *)tail_msdu->data; + err_bitmap = ath12k_dp_rx_h_mpdu_err(ab, tail_rx_desc); if (err_bitmap & HAL_RX_MPDU_ERR_FCS) *fcs_err = true; - decap_format = ath12k_dp_rx_h_decap_type(ab, rx_desc); + decap_format = ath12k_dp_rx_h_decap_type(ab, tail_rx_desc); - ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs); + ath12k_dp_rx_h_ppdu(ar, tail_rx_desc, rxs); if (decap_format == DP_RX_DECAP_TYPE_RAW) { - ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu); + ath12k_dp_mon_rx_msdus_set_payload(ar, head_msdu, tail_msdu); prev_buf = head_msdu; msdu = head_msdu->next; + head_frag_list = NULL; while (msdu) { - ath12k_dp_mon_rx_msdus_set_payload(ar, msdu); + ath12k_dp_mon_rx_msdus_set_payload(ar, msdu, tail_msdu); + + if (!head_frag_list) + head_frag_list = msdu; + frag_list_sum_len += msdu->len; prev_buf = msdu; msdu = msdu->next; } @@ -913,6 +913,12 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, prev_buf->next = NULL; skb_trim(prev_buf, prev_buf->len - HAL_RX_FCS_LEN); + if (head_frag_list) { + skb_shinfo(head_msdu)->frag_list = head_frag_list; + head_msdu->data_len = frag_list_sum_len; + head_msdu->len += head_msdu->data_len; + head_msdu->next = NULL; + } } else if (decap_format == DP_RX_DECAP_TYPE_NATIVE_WIFI) { u8 qos_pkt = 0; @@ -929,7 +935,7 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, msdu = head_msdu; while (msdu) { - ath12k_dp_mon_rx_msdus_set_payload(ar, msdu); + ath12k_dp_mon_rx_msdus_set_payload(ar, msdu, tail_msdu); if (qos_pkt) { dest = skb_push(msdu, sizeof(__le16)); if (!dest) @@ -1135,7 +1141,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct } static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id, - struct sk_buff *head_msdu, + struct sk_buff *head_msdu, struct sk_buff *tail_msdu, struct hal_rx_mon_ppdu_info *ppduinfo, struct napi_struct *napi) { @@ -1144,7 +1150,8 @@ static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id, struct ieee80211_rx_status *rxs = &dp->rx_status; bool fcs_err = false; - mon_skb = ath12k_dp_mon_rx_merg_msdus(ar, mac_id, head_msdu, + mon_skb = ath12k_dp_mon_rx_merg_msdus(ar, mac_id, + head_msdu, tail_msdu, rxs, &fcs_err); if (!mon_skb) goto mon_deliver_fail; @@ -1252,7 +1259,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar, if (head_msdu && tail_msdu) { ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu, - ppdu_info, napi); + tail_msdu, ppdu_info, napi); } kfree(mon_mpdu); @@ -1948,15 +1955,16 @@ ath12k_dp_mon_tx_process_ppdu_info(struct ath12k *ar, int mac_id, struct dp_mon_tx_ppdu_info *tx_ppdu_info) { struct dp_mon_mpdu *tmp, *mon_mpdu; - struct sk_buff *head_msdu; + struct sk_buff *head_msdu, *tail_msdu; list_for_each_entry_safe(mon_mpdu, tmp, &tx_ppdu_info->dp_tx_mon_mpdu_list, list) { list_del(&mon_mpdu->list); head_msdu = mon_mpdu->head; + tail_msdu = mon_mpdu->tail; if (head_msdu) - ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu, + ath12k_dp_mon_rx_deliver(ar, mac_id, head_msdu, tail_msdu, &tx_ppdu_info->rx_status, napi); kfree(mon_mpdu); @@ -2165,7 +2173,7 @@ ath12k_dp_mon_rx_update_peer_rate_table_stats(struct ath12k_rx_peer_stats *rx_st } static void ath12k_dp_mon_rx_update_peer_su_stats(struct ath12k *ar, - struct ath12k_sta *arsta, + struct ath12k_link_sta *arsta, struct hal_rx_mon_ppdu_info *ppdu_info) { struct ath12k_rx_peer_stats *rx_stats = arsta->rx_stats; @@ -2321,7 +2329,8 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar, struct hal_rx_mon_ppdu_info *ppdu_info, u32 uid) { - struct ath12k_sta *arsta = NULL; + struct ath12k_sta *ahsta; + struct ath12k_link_sta *arsta; struct ath12k_rx_peer_stats *rx_stats = NULL; struct hal_rx_user_status *user_stats = &ppdu_info->userstats[uid]; struct ath12k_peer *peer; @@ -2338,7 +2347,8 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar, return; } - arsta = ath12k_sta_to_arsta(peer->sta); + ahsta = ath12k_sta_to_ahsta(peer->sta); + arsta = &ahsta->deflink; rx_stats = arsta->rx_stats; if (!rx_stats) @@ -2445,7 +2455,8 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id, struct dp_srng *mon_dst_ring; struct hal_srng *srng; struct dp_rxdma_mon_ring *buf_ring; - struct ath12k_sta *arsta = NULL; + struct ath12k_sta *ahsta = NULL; + struct ath12k_link_sta *arsta; struct ath12k_peer *peer; u64 cookie; int num_buffs_reaped = 0, srng_id, buf_id; @@ -2514,7 +2525,8 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id, } if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_SU) { - arsta = ath12k_sta_to_arsta(peer->sta); + ahsta = ath12k_sta_to_ahsta(peer->sta); + arsta = &ahsta->deflink; ath12k_dp_mon_rx_update_peer_su_stats(ar, arsta, ppdu_info); } else if ((ppdu_info->fc_valid) && diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 91e3393f7b5f40..9ae579e5055729 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1041,13 +1041,14 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar, struct ieee80211_ampdu_params *params) { struct ath12k_base *ab = ar->ab; - struct ath12k_sta *arsta = ath12k_sta_to_arsta(params->sta); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta); + struct ath12k_link_sta *arsta = &ahsta->deflink; int vdev_id = arsta->arvif->vdev_id; int ret; ret = ath12k_dp_rx_peer_tid_setup(ar, params->sta->addr, vdev_id, params->tid, params->buf_size, - params->ssn, arsta->pn_type); + params->ssn, arsta->ahsta->pn_type); if (ret) ath12k_warn(ab, "failed to setup rx tid %d\n", ret); @@ -1059,7 +1060,8 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar, { struct ath12k_base *ab = ar->ab; struct ath12k_peer *peer; - struct ath12k_sta *arsta = ath12k_sta_to_arsta(params->sta); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta); + struct ath12k_link_sta *arsta = &ahsta->deflink; int vdev_id = arsta->arvif->vdev_id; bool active; int ret; @@ -1091,7 +1093,7 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar, return ret; } -int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif, +int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif, const u8 *peer_addr, enum set_key_cmd key_cmd, struct ieee80211_key_conf *key) @@ -1313,7 +1315,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, struct ath12k_base *ab = ar->ab; struct ath12k_peer *peer; struct ieee80211_sta *sta; - struct ath12k_sta *arsta; + struct ath12k_sta *ahsta; + struct ath12k_link_sta *arsta; struct htt_ppdu_stats_user_rate *user_rate; struct ath12k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats; struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user]; @@ -1394,7 +1397,8 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, } sta = peer->sta; - arsta = ath12k_sta_to_arsta(sta); + ahsta = ath12k_sta_to_ahsta(sta); + arsta = &ahsta->deflink; memset(&arsta->txrate, 0, sizeof(arsta->txrate)); diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index eb1f92559179bb..bfd4f814553e76 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -88,7 +88,7 @@ int ath12k_dp_rx_ampdu_start(struct ath12k *ar, struct ieee80211_ampdu_params *params); int ath12k_dp_rx_ampdu_stop(struct ath12k *ar, struct ieee80211_ampdu_params *params); -int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_vif *arvif, +int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif, const u8 *peer_addr, enum set_key_cmd key_cmd, struct ieee80211_key_conf *key); diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 44406e0b4a342f..a8d341a6df01ea 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -10,7 +10,7 @@ #include "hw.h" static enum hal_tcl_encap_type -ath12k_dp_tx_get_encap_type(struct ath12k_vif *arvif, struct sk_buff *skb) +ath12k_dp_tx_get_encap_type(struct ath12k_link_vif *arvif, struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath12k_base *ab = arvif->ar->ab; @@ -216,7 +216,7 @@ static int ath12k_dp_tx_align_payload(struct ath12k_base *ab, return ret; } -int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, +int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, struct sk_buff *skb) { struct ath12k_base *ab = ar->ab; @@ -230,6 +230,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, struct sk_buff *skb_ext_desc; struct hal_srng *tcl_ring; struct ieee80211_hdr *hdr = (void *)skb->data; + struct ath12k_vif *ahvif = arvif->ahvif; struct dp_tx_ring *tx_ring; u8 pool_id; u8 hal_ring_id; @@ -274,7 +275,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, ti.bank_id = arvif->bank_id; ti.meta_data_flags = arvif->tcl_metadata; - if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && + if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) { if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) { ti.encrypt_type = @@ -376,7 +377,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, ti.desc_id = tx_desc->desc_id; ti.data_len = skb->len; skb_cb->paddr = ti.paddr; - skb_cb->vif = arvif->vif; + skb_cb->vif = ahvif->vif; skb_cb->ar = ar; if (msdu_ext_desc) { diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.h b/drivers/net/wireless/ath/ath12k/dp_tx.h index 55ff8cc721e37f..46dce23501f385 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.h +++ b/drivers/net/wireless/ath/ath12k/dp_tx.h @@ -16,7 +16,7 @@ struct ath12k_dp_htt_wbm_tx_status { }; int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab); -int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, +int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, struct sk_buff *skb); void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id); diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index ca04bfae8bdccc..fd98fac16dd5fa 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -385,13 +385,13 @@ static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) { return le32_get_bits(desc->u.qcn9274.msdu_end.info12, - RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP); + RX_MSDU_END_INFO12_MIMO_SS_BITMAP); } static u8 ath12k_hw_qcn9274_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) { return le16_get_bits(desc->u.qcn9274.msdu_end.info5, - RX_MSDU_END_QCN9274_INFO5_TID); + RX_MSDU_END_INFO5_TID); } static u16 ath12k_hw_qcn9274_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) @@ -846,13 +846,13 @@ static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type(struct hal_rx_desc static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) { return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, - RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP); + RX_MSDU_END_INFO12_MIMO_SS_BITMAP); } static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) { return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, - RX_MSDU_END_QCN9274_INFO5_TID); + RX_MSDU_END_INFO5_TID); } static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) @@ -1198,7 +1198,7 @@ static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) { return le32_get_bits(desc->u.wcn7850.msdu_end.info12, - RX_MSDU_END_WCN7850_INFO12_MIMO_SS_BITMAP); + RX_MSDU_END_INFO12_MIMO_SS_BITMAP); } static u8 ath12k_hw_wcn7850_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) @@ -1216,7 +1216,7 @@ static void ath12k_hw_wcn7850_rx_desc_copy_end_tlv(struct hal_rx_desc *fdesc, struct hal_rx_desc *ldesc) { memcpy(&fdesc->u.wcn7850.msdu_end, &ldesc->u.wcn7850.msdu_end, - sizeof(struct rx_msdu_end_wcn7850)); + sizeof(struct rx_msdu_end_qcn9274)); } static u32 ath12k_hw_wcn7850_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc) diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h index 095216eabc01dc..2de7b0eba9f274 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HAL_RX_H @@ -156,6 +156,7 @@ struct hal_rx_mon_ppdu_info { u32 preamble_type; u32 mpdu_len; u16 chan_num; + u16 freq; u16 tcp_msdu_count; u16 tcp_ack_msdu_count; u16 udp_msdu_count; @@ -232,21 +233,25 @@ struct hal_rx_mon_ppdu_info { u8 medium_prot_type; }; -#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0) +#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0) +#define HAL_RX_PPDU_START_INFO1_CHAN_NUM GENMASK(15, 0) +#define HAL_RX_PPDU_START_INFO1_CHAN_FREQ GENMASK(31, 16) struct hal_rx_ppdu_start { __le32 info0; - __le32 chan_num; - __le32 ppdu_start_ts; + __le32 info1; + __le32 ppdu_start_ts_31_0; + __le32 ppdu_start_ts_63_32; + __le32 rsvd[2]; } __packed; -#define HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR GENMASK(25, 16) +#define HAL_RX_PPDU_END_USER_STATS_INFO0_MPDU_CNT_FCS_ERR GENMASK(26, 16) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK GENMASK(8, 0) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID BIT(9) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_QOS_CTRL_VALID BIT(10) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_HT_CTRL_VALID BIT(11) -#define HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE GENMASK(23, 20) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_MPDU_CNT_FCS_OK GENMASK(10, 0) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_FC_VALID BIT(11) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_QOS_CTRL_VALID BIT(12) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_HT_CTRL_VALID BIT(13) +#define HAL_RX_PPDU_END_USER_STATS_INFO1_PKT_TYPE GENMASK(24, 21) #define HAL_RX_PPDU_END_USER_STATS_INFO2_AST_INDEX GENMASK(15, 0) #define HAL_RX_PPDU_END_USER_STATS_INFO2_FRAME_CTRL GENMASK(31, 16) @@ -262,8 +267,8 @@ struct hal_rx_ppdu_start { #define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_BITMAP GENMASK(15, 0) #define HAL_RX_PPDU_END_USER_STATS_INFO6_TID_EOSP_BITMAP GENMASK(31, 16) -#define HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_OK_BYTE_COUNT GENMASK(24, 0) -#define HAL_RX_PPDU_END_USER_STATS_MPDU_DELIM_ERR_BYTE_COUNT GENMASK(24, 0) +#define HAL_RX_PPDU_END_USER_STATS_INFO7_MPDU_OK_BYTE_COUNT GENMASK(24, 0) +#define HAL_RX_PPDU_END_USER_STATS_INFO8_MPDU_ERR_BYTE_COUNT GENMASK(24, 0) struct hal_rx_ppdu_end_user_stats { __le32 rsvd0[2]; @@ -278,9 +283,9 @@ struct hal_rx_ppdu_end_user_stats { __le32 usr_resp_ref; __le32 info6; __le32 rsvd3[4]; - __le32 mpdu_ok_cnt; + __le32 info7; __le32 rsvd4; - __le32 mpdu_err_cnt; + __le32 info8; __le32 rsvd5[2]; __le32 usr_resp_ref_ext; __le32 rsvd6; @@ -436,23 +441,27 @@ enum hal_rx_ul_reception_type { HAL_RECEPTION_TYPE_FRAMELESS }; -#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RSSI_COMB GENMASK(15, 8) -#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_RSVD1_RECEPTION GENMASK(3, 0) +#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RECEPTION GENMASK(3, 0) +#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW GENMASK(7, 5) +#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8) struct hal_rx_phyrx_rssi_legacy_info { - __le32 rsvd[35]; __le32 info0; + __le32 rsvd0[39]; + __le32 info1; + __le32 rsvd1; } __packed; -#define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16) -#define HAL_RX_MPDU_START_INFO1_PEERID GENMASK(31, 16) -#define HAL_RX_MPDU_START_INFO2_MPDU_LEN GENMASK(13, 0) +#define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16) +#define HAL_RX_MPDU_START_INFO1_PEERID GENMASK(31, 16) +#define HAL_RX_MPDU_START_INFO2_MPDU_LEN GENMASK(13, 0) struct hal_rx_mpdu_start { + __le32 rsvd0[9]; __le32 info0; __le32 info1; - __le32 rsvd1[11]; + __le32 rsvd1[2]; __le32 info2; - __le32 rsvd2[9]; + __le32 rsvd2[16]; } __packed; #define HAL_RX_PPDU_END_DURATION GENMASK(23, 0) diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h index 0e53ec269fa4f2..e8840fab6061c7 100644 --- a/drivers/net/wireless/ath/ath12k/hif.h +++ b/drivers/net/wireless/ath/ath12k/hif.h @@ -31,6 +31,7 @@ struct ath12k_hif_ops { void (*ce_irq_disable)(struct ath12k_base *ab); void (*get_ce_msi_idx)(struct ath12k_base *ab, u32 ce_id, u32 *msi_idx); int (*panic_handler)(struct ath12k_base *ab); + void (*coredump_download)(struct ath12k_base *ab); }; static inline int ath12k_hif_map_service_to_pipe(struct ath12k_base *ab, u16 service_id, @@ -156,4 +157,9 @@ static inline int ath12k_hif_panic_handler(struct ath12k_base *ab) return ab->hif.ops->panic_handler(ab); } +static inline void ath12k_hif_coredump_download(struct ath12k_base *ab) +{ + if (ab->hif.ops->coredump_download) + ab->hif.ops->coredump_download(ab); +} #endif /* ATH12K_HIF_H */ diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index ec1bda95e555dd..b7b583fadb5ac1 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -913,7 +913,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_cfg = 0, .rfkill_on_level = 0, - .rddm_size = 0, + .rddm_size = 0x600000, .def_num_link = 0, .max_mlo_peer = 256, @@ -1069,7 +1069,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_cfg = 0, .rfkill_on_level = 0, - .rddm_size = 0, + .rddm_size = 0x600000, .def_num_link = 0, .max_mlo_peer = 256, diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 137394c364603b..d493ec812055f8 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -250,10 +250,10 @@ static const u32 ath12k_smps_map[] = { }; static int ath12k_start_vdev_delay(struct ath12k *ar, - struct ath12k_vif *arvif); + struct ath12k_link_vif *arvif); static void ath12k_mac_stop(struct ath12k *ar); -static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif); -static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif); +static int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif); +static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ath12k_link_vif *arvif); static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode) { @@ -476,18 +476,25 @@ static u8 ath12k_parse_mpdudensity(u8 mpdudensity) } } -static int ath12k_mac_vif_chan(struct ieee80211_vif *vif, - struct cfg80211_chan_def *def) +static int ath12k_mac_vif_link_chan(struct ieee80211_vif *vif, u8 link_id, + struct cfg80211_chan_def *def) { + struct ieee80211_bss_conf *link_conf; struct ieee80211_chanctx_conf *conf; rcu_read_lock(); - conf = rcu_dereference(vif->bss_conf.chanctx_conf); + link_conf = rcu_dereference(vif->link_conf[link_id]); + + if (!link_conf) { + rcu_read_unlock(); + return -ENOLINK; + } + + conf = rcu_dereference(link_conf->chanctx_conf); if (!conf) { rcu_read_unlock(); return -ENOENT; } - *def = conf->def; rcu_read_unlock(); @@ -539,18 +546,33 @@ static void ath12k_get_arvif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct ath12k_vif_iter *arvif_iter = data; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + unsigned long links_map = ahvif->links_map; + struct ath12k_link_vif *arvif; + u8 link_id; + + for_each_set_bit(link_id, &links_map, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = rcu_dereference(ahvif->link[link_id]); + + if (WARN_ON(!arvif)) + continue; - if (arvif->vdev_id == arvif_iter->vdev_id && - arvif->ar == arvif_iter->ar) - arvif_iter->arvif = arvif; + if (arvif->vdev_id == arvif_iter->vdev_id && + arvif->ar == arvif_iter->ar) { + arvif_iter->arvif = arvif; + break; + } + } } -struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) +struct ath12k_link_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) { struct ath12k_vif_iter arvif_iter = {}; u32 flags; + /* To use the arvif returned, caller must have held rcu read lock. + */ + WARN_ON(!rcu_read_lock_any_held()); arvif_iter.vdev_id = vdev_id; arvif_iter.ar = ar; @@ -567,12 +589,12 @@ struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) return arvif_iter.arvif; } -struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, - u32 vdev_id) +struct ath12k_link_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, + u32 vdev_id) { int i; struct ath12k_pdev *pdev; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; for (i = 0; i < ab->num_radios; i++) { pdev = rcu_dereference(ab->pdevs_active[i]); @@ -658,7 +680,8 @@ static struct ath12k *ath12k_get_ar_by_ctx(struct ieee80211_hw *hw, static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; struct ath12k_hw *ah = ath12k_hw_to_ah(hw); /* If there is one pdev within ah, then we return @@ -673,11 +696,12 @@ static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, return NULL; } -static struct ath12k_vif *ath12k_mac_get_vif_up(struct ath12k *ar) +static struct ath12k_link_vif *ath12k_mac_get_vif_up(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - lockdep_assert_held(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) { if (arvif->is_up) return arvif; @@ -705,17 +729,17 @@ static bool ath12k_mac_band_match(enum nl80211_band band1, enum WMI_HOST_WLAN_BA return false; } -static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_vif *arvif) +static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif *vif = arvif->ahvif->vif; struct cfg80211_chan_def def; enum nl80211_band band; u8 pdev_id = ab->fw_pdev[0].pdev_id; int i; - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return pdev_id; band = def.chan->band; @@ -730,7 +754,7 @@ static u8 ath12k_mac_get_target_pdev_id_from_vif(struct ath12k_vif *arvif) u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; struct ath12k_base *ab = ar->ab; if (!ab->hw_params->single_pdev_only) @@ -770,11 +794,11 @@ static void ath12k_pdev_caps_update(struct ath12k *ar) static int ath12k_mac_txpower_recalc(struct ath12k *ar) { struct ath12k_pdev *pdev = ar->pdev; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret, txpower = -1; u32 param; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { if (arvif->txpower <= 0) @@ -824,13 +848,13 @@ static int ath12k_mac_txpower_recalc(struct ath12k *ar) return ret; } -static int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif) +static int ath12k_recalc_rtscts_prot(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; u32 vdev_param, rts_cts; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); vdev_param = WMI_VDEV_PARAM_ENABLE_RTSCTS; @@ -863,7 +887,7 @@ static int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif) return ret; } -static int ath12k_mac_set_kickout(struct ath12k_vif *arvif) +static int ath12k_mac_set_kickout(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; u32 param; @@ -913,11 +937,14 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar) struct ath12k_peer *peer, *tmp; struct ath12k_base *ab = ar->ab; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); spin_lock_bh(&ab->base_lock); list_for_each_entry_safe(peer, tmp, &ab->peers, list) { - ath12k_dp_rx_peer_tid_cleanup(ar, peer); + /* Skip Rx TID cleanup for self peer */ + if (peer->sta) + ath12k_dp_rx_peer_tid_cleanup(ar, peer); + list_del(&peer->list); kfree(peer); } @@ -929,7 +956,7 @@ void ath12k_mac_peer_cleanup_all(struct ath12k *ar) static int ath12k_mac_vdev_setup_sync(struct ath12k *ar) { - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) return -ESHUTDOWN; @@ -971,7 +998,7 @@ static int ath12k_mac_monitor_vdev_start(struct ath12k *ar, int vdev_id, struct ath12k_wmi_vdev_up_params params = {}; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); channel = chandef->chan; arg.vdev_id = vdev_id; @@ -1034,7 +1061,7 @@ static int ath12k_mac_monitor_vdev_stop(struct ath12k *ar) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->vdev_setup_done); @@ -1064,9 +1091,8 @@ static int ath12k_mac_monitor_vdev_create(struct ath12k *ar) struct ath12k_wmi_vdev_create_arg arg = {}; int bit, ret; u8 tmp_addr[6]; - u16 nss; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (ar->monitor_vdev_created) return 0; @@ -1104,19 +1130,6 @@ static int ath12k_mac_monitor_vdev_create(struct ath12k *ar) return ret; } - nss = hweight32(ar->cfg_tx_chainmask) ? : 1; - ret = ath12k_wmi_vdev_set_param_cmd(ar, ar->monitor_vdev_id, - WMI_VDEV_PARAM_NSS, nss); - if (ret) { - ath12k_warn(ar->ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n", - ar->monitor_vdev_id, ar->cfg_tx_chainmask, nss, ret); - return ret; - } - - ret = ath12k_mac_txpower_recalc(ar); - if (ret) - return ret; - ar->allocated_vdev_map |= 1LL << ar->monitor_vdev_id; ar->ab->free_vdev_map &= ~(1LL << ar->monitor_vdev_id); ar->num_created_vdevs++; @@ -1132,7 +1145,7 @@ static int ath12k_mac_monitor_vdev_delete(struct ath12k *ar) int ret; unsigned long time_left; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!ar->monitor_vdev_created) return 0; @@ -1178,7 +1191,7 @@ static int ath12k_mac_monitor_start(struct ath12k *ar) struct cfg80211_chan_def *chandef = NULL; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (ar->monitor_started) return 0; @@ -1208,7 +1221,7 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!ar->monitor_started) return 0; @@ -1226,12 +1239,13 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) return ret; } -static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) +static int ath12k_mac_vdev_stop(struct ath12k_link_vif *arvif) { + struct ath12k_vif *ahvif = arvif->ahvif; struct ath12k *ar = arvif->ar; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->vdev_setup_done); @@ -1253,7 +1267,7 @@ static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) ar->num_started_vdevs--; ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", - arvif->vif->addr, arvif->vdev_id); + ahvif->vif->addr, arvif->vdev_id); if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); @@ -1272,36 +1286,33 @@ static int ath12k_mac_config(struct ath12k *ar, u32 changed) struct ieee80211_conf *conf = &hw->conf; int ret = 0; - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { ar->monitor_conf_enabled = conf->flags & IEEE80211_CONF_MONITOR; if (ar->monitor_conf_enabled) { if (ar->monitor_vdev_created) - goto exit; + return ret; ret = ath12k_mac_monitor_vdev_create(ar); if (ret) - goto exit; + return ret; ret = ath12k_mac_monitor_start(ar); if (ret) goto err_mon_del; } else { if (!ar->monitor_vdev_created) - goto exit; + return ret; ret = ath12k_mac_monitor_stop(ar); if (ret) - goto exit; + return ret; ath12k_mac_monitor_vdev_delete(ar); } } -exit: - mutex_unlock(&ar->conf_mutex); return ret; err_mon_del: ath12k_mac_monitor_vdev_delete(ar); - mutex_unlock(&ar->conf_mutex); return ret; } @@ -1311,6 +1322,8 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) struct ath12k *ar; int ret; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_ah_to_ar(ah, 0); ret = ath12k_mac_config(ar, changed); @@ -1321,7 +1334,7 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) return ret; } -static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_vif *arvif, +static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_link_vif *arvif, struct sk_buff *bcn) { struct ath12k *ar = arvif->ar; @@ -1378,7 +1391,7 @@ static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, return 0; } -static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *bcn, +static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_buff *bcn, u8 bssid_index, bool *nontx_profile_found) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data; @@ -1470,19 +1483,22 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_vif *arvif, struct sk_buff *b } } -static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif) +static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_link_vif *arvif) { - struct ieee80211_bss_conf *bss_conf = &arvif->vif->bss_conf; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_bss_conf *bss_conf = &ahvif->vif->bss_conf; struct ath12k_wmi_bcn_tmpl_ema_arg ema_args; struct ieee80211_ema_beacons *beacons; - struct ath12k_vif *tx_arvif; + struct ath12k_link_vif *tx_arvif; bool nontx_profile_found = false; + struct ath12k_vif *tx_ahvif; int ret = 0; u8 i; - tx_arvif = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif); + tx_ahvif = ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif); + tx_arvif = &tx_ahvif->deflink; beacons = ieee80211_beacon_get_template_ema_list(ath12k_ar_to_hw(tx_arvif->ar), - tx_arvif->vif, 0); + tx_ahvif->vif, 0); if (!beacons || !beacons->cnt) { ath12k_warn(arvif->ar->ab, "failed to get ema beacon templates from mac80211\n"); @@ -1520,22 +1536,25 @@ static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_vif *arvif) return ret; } -static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) +static int ath12k_mac_setup_bcn_tmpl(struct ath12k_link_vif *arvif) { - struct ath12k_vif *tx_arvif = arvif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); + struct ath12k_link_vif *tx_arvif = arvif; struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; + struct ath12k_vif *tx_ahvif = ahvif; bool nontx_profile_found = false; struct sk_buff *bcn; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + if (ahvif->vdev_type != WMI_VDEV_TYPE_AP) return 0; if (vif->mbssid_tx_vif) { - tx_arvif = ath12k_vif_to_arvif(vif->mbssid_tx_vif); + tx_ahvif = ath12k_vif_to_ahvif(vif->mbssid_tx_vif); + tx_arvif = &tx_ahvif->deflink; if (tx_arvif != arvif && arvif->is_up) return 0; @@ -1543,7 +1562,7 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) return ath12k_mac_setup_bcn_tmpl_ema(arvif); } - bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_arvif->vif, + bcn = ieee80211_beacon_get_template(ath12k_ar_to_hw(tx_arvif->ar), tx_ahvif->vif, &offs, 0); if (!bcn) { ath12k_warn(ab, "failed to get beacon template from mac80211\n"); @@ -1554,14 +1573,14 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) ath12k_mac_set_arvif_ies(arvif, bcn, 0, NULL); } else { ath12k_mac_set_arvif_ies(arvif, bcn, - arvif->vif->bss_conf.bssid_index, + ahvif->vif->bss_conf.bssid_index, &nontx_profile_found); if (!nontx_profile_found) ath12k_warn(ab, "nontransmitted profile not found in beacon template\n"); } - if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) { + if (ahvif->vif->type == NL80211_IFTYPE_AP && ahvif->vif->p2p) { ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn); if (ret) { ath12k_warn(ab, "failed to setup P2P GO bcn ie: %d\n", @@ -1595,14 +1614,15 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) return ret; } -static void ath12k_control_beaconing(struct ath12k_vif *arvif, +static void ath12k_control_beaconing(struct ath12k_link_vif *arvif, struct ieee80211_bss_conf *info) { struct ath12k_wmi_vdev_up_params params = {}; + struct ath12k_vif *ahvif = arvif->ahvif; struct ath12k *ar = arvif->ar; int ret; - lockdep_assert_held(&arvif->ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(arvif->ar)->wiphy); if (!info->enable_beacon) { ret = ath12k_wmi_vdev_down(ar, arvif->vdev_id); @@ -1622,15 +1642,19 @@ static void ath12k_control_beaconing(struct ath12k_vif *arvif, return; } - arvif->aid = 0; + ahvif->aid = 0; ether_addr_copy(arvif->bssid, info->bssid); params.vdev_id = arvif->vdev_id; - params.aid = arvif->aid; + params.aid = ahvif->aid; params.bssid = arvif->bssid; - if (arvif->vif->mbssid_tx_vif) { - params.tx_bssid = ath12k_vif_to_arvif(arvif->vif->mbssid_tx_vif)->bssid; + if (ahvif->vif->mbssid_tx_vif) { + struct ath12k_vif *tx_ahvif = + ath12k_vif_to_ahvif(ahvif->vif->mbssid_tx_vif); + struct ath12k_link_vif *tx_arvif = &tx_ahvif->deflink; + + params.tx_bssid = tx_arvif->bssid; params.nontx_profile_idx = info->bssid_index; params.nontx_profile_cnt = 1 << info->bssid_indicator; } @@ -1651,7 +1675,8 @@ static void ath12k_mac_handle_beacon_iter(void *data, u8 *mac, { struct sk_buff *skb = data; struct ieee80211_mgmt *mgmt = (void *)skb->data; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; if (vif->type != NL80211_IFTYPE_STATION) return; @@ -1674,7 +1699,8 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { u32 *vdev_id = data; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; struct ath12k *ar = arvif->ar; struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); @@ -1705,9 +1731,9 @@ void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id) static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work) { - struct ath12k_vif *arvif = container_of(work, struct ath12k_vif, - connection_loss_work.work); - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_link_vif *arvif = container_of(work, struct ath12k_link_vif, + connection_loss_work.work); + struct ieee80211_vif *vif = arvif->ahvif->vif; if (!arvif->is_up) return; @@ -1716,15 +1742,16 @@ static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work) } static void ath12k_peer_assoc_h_basic(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); u32 aid; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); if (vif->type == NL80211_IFTYPE_STATION) aid = vif->cfg.aid; @@ -1742,21 +1769,22 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar, } static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ieee80211_bss_conf *info = &vif->bss_conf; struct cfg80211_chan_def def; struct cfg80211_bss *bss; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); const u8 *rsnie = NULL; const u8 *wpaie = NULL; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; bss = cfg80211_get_bss(hw->wiphy, def.chan, info->bssid, NULL, 0, @@ -1804,11 +1832,12 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, } static void ath12k_peer_assoc_h_rates(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates; struct cfg80211_chan_def def; const struct ieee80211_supported_band *sband; @@ -1819,9 +1848,9 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar, u8 rate; int i; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; band = def.chan->band; @@ -1867,12 +1896,13 @@ ath12k_peer_assoc_h_vht_masked(const u16 *vht_mcs_mask) } static void ath12k_peer_assoc_h_ht(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_chan_def def; enum nl80211_band band; const u8 *ht_mcs_mask; @@ -1880,9 +1910,9 @@ static void ath12k_peer_assoc_h_ht(struct ath12k *ar, u8 max_nss; u32 stbc; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; if (!ht_cap->ht_supported) @@ -2028,12 +2058,13 @@ ath12k_peer_assoc_h_vht_limit(u16 tx_mcs_set, } static void ath12k_peer_assoc_h_vht(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_chan_def def; enum nl80211_band band; const u16 *vht_mcs_mask; @@ -2042,7 +2073,9 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, u8 max_nss, vht_mcs; int i; - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; if (!vht_cap->vht_supported) @@ -2123,10 +2156,12 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, } static void ath12k_peer_assoc_h_he(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; int i; u8 ampdu_factor, max_nss; @@ -2278,16 +2313,18 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, } static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; struct cfg80211_chan_def def; enum nl80211_band band; u8 ampdu_factor, mpdu_density; - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; band = def.chan->band; @@ -2347,9 +2384,10 @@ static int ath12k_get_smps_from_capa(const struct ieee80211_sta_ht_cap *ht_cap, return 0; } -static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, +static void ath12k_peer_assoc_h_smps(struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_he_6ghz_capa *he_6ghz_capa = &sta->deflink.he_6ghz_capa; const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; int smps; @@ -2376,13 +2414,13 @@ static void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, } static void ath12k_peer_assoc_h_qos(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_AP: if (sta->wme) { /* TODO: Check WME vs QoS */ @@ -2412,15 +2450,16 @@ static void ath12k_peer_assoc_h_qos(struct ath12k *ar, } static int ath12k_peer_assoc_qos_ap(struct ath12k *ar, - struct ath12k_vif *arvif, - struct ieee80211_sta *sta) + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k_wmi_ap_ps_arg arg; u32 max_sp; u32 uapsd; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); arg.vdev_id = arvif->vdev_id; @@ -2574,18 +2613,22 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_eht(struct ath12k *ar, } static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_chan_def def; enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; enum wmi_phy_mode phymode = MODE_UNKNOWN; - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; band = def.chan->band; @@ -2719,17 +2762,19 @@ static void ath12k_mac_set_eht_ppe_threshold(const u8 *ppe_thres, } static void ath12k_peer_assoc_h_eht(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); const struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap; const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; const struct ieee80211_eht_mcs_nss_supp_20mhz_only *bw_20; const struct ieee80211_eht_mcs_nss_supp_bw *bw; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); u32 *rx_mcs, *tx_mcs; + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + if (!sta->deflink.he_cap.has_he || !eht_cap->has_eht) return; @@ -2802,34 +2847,34 @@ static void ath12k_peer_assoc_h_eht(struct ath12k *ar, } static void ath12k_peer_assoc_prepare(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ath12k_wmi_peer_assoc_arg *arg, bool reassoc) { - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); memset(arg, 0, sizeof(*arg)); reinit_completion(&ar->peer_assoc_done); arg->peer_new_assoc = !reassoc; - ath12k_peer_assoc_h_basic(ar, vif, sta, arg); - ath12k_peer_assoc_h_crypto(ar, vif, sta, arg); - ath12k_peer_assoc_h_rates(ar, vif, sta, arg); - ath12k_peer_assoc_h_ht(ar, vif, sta, arg); - ath12k_peer_assoc_h_vht(ar, vif, sta, arg); - ath12k_peer_assoc_h_he(ar, vif, sta, arg); - ath12k_peer_assoc_h_he_6ghz(ar, vif, sta, arg); - ath12k_peer_assoc_h_eht(ar, vif, sta, arg); - ath12k_peer_assoc_h_qos(ar, vif, sta, arg); - ath12k_peer_assoc_h_phymode(ar, vif, sta, arg); - ath12k_peer_assoc_h_smps(sta, arg); + ath12k_peer_assoc_h_basic(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_crypto(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_rates(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_ht(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_vht(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_he(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_he_6ghz(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_eht(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_qos(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_phymode(ar, arvif, arsta, arg); + ath12k_peer_assoc_h_smps(arsta, arg); /* TODO: amsdu_disable req? */ } -static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, +static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_link_vif *arvif, const u8 *addr, const struct ieee80211_sta_ht_cap *ht_cap, const struct ieee80211_he_6ghz_capa *he_6ghz_capa) @@ -2849,21 +2894,24 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, } static void ath12k_bss_assoc(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_wmi_peer_assoc_arg peer_arg; + struct ath12k_link_sta *arsta; struct ieee80211_sta *ap_sta; + struct ath12k_sta *ahsta; struct ath12k_peer *peer; bool is_auth = false; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n", - arvif->vdev_id, arvif->bssid, arvif->aid); + arvif->vdev_id, arvif->bssid, ahvif->aid); rcu_read_lock(); @@ -2875,7 +2923,15 @@ static void ath12k_bss_assoc(struct ath12k *ar, return; } - ath12k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false); + ahsta = ath12k_sta_to_ahsta(ap_sta); + arsta = &ahsta->deflink; + + if (WARN_ON(!arsta)) { + rcu_read_unlock(); + return; + } + + ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, false); rcu_read_unlock(); @@ -2903,11 +2959,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, WARN_ON(arvif->is_up); - arvif->aid = vif->cfg.aid; + ahvif->aid = vif->cfg.aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); params.vdev_id = arvif->vdev_id; - params.aid = arvif->aid; + params.aid = ahvif->aid; params.bssid = arvif->bssid; ret = ath12k_wmi_vdev_up(ar, ¶ms); if (ret) { @@ -2949,11 +3005,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, } static void ath12k_bss_disassoc(struct ath12k *ar, - struct ath12k_vif *arvif) + struct ath12k_link_vif *arvif) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n", arvif->vdev_id, arvif->bssid); @@ -2996,10 +3052,10 @@ static u32 ath12k_mac_get_rate_hw_value(int bitrate) } static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, - struct ieee80211_vif *vif, + struct ath12k_link_vif *arvif, struct cfg80211_chan_def *def) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); const struct ieee80211_supported_band *sband; u8 basic_rate_idx; @@ -3008,7 +3064,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, u16 bitrate; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); sband = hw->wiphy->bands[def->chan->band]; basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; @@ -3033,9 +3089,19 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, ath12k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret); } -static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, +static int +ath12k_mac_op_change_vif_links(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u16 old_links, u16 new_links, + struct ieee80211_bss_conf *ol[IEEE80211_MLD_MAX_NUM_LINKS]) +{ + return 0; +} + +static int ath12k_mac_fils_discovery(struct ath12k_link_vif *arvif, struct ieee80211_bss_conf *info) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ath12k *ar = arvif->ar; struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct sk_buff *tmpl; @@ -3046,7 +3112,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, if (info->fils_discovery.max_interval) { interval = info->fils_discovery.max_interval; - tmpl = ieee80211_get_fils_discovery_tmpl(hw, arvif->vif); + tmpl = ieee80211_get_fils_discovery_tmpl(hw, vif); if (tmpl) ret = ath12k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id, tmpl); @@ -3054,8 +3120,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, unsol_bcast_probe_resp_enabled = 1; interval = info->unsol_bcast_probe_resp_interval; - tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, - arvif->vif); + tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif); if (tmpl) ret = ath12k_wmi_probe_resp_tmpl(ar, arvif->vdev_id, tmpl); @@ -3080,10 +3145,44 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, return ret; } -static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) +static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 changed) +{ + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + unsigned long links = ahvif->links_map; + struct ath12k_link_vif *arvif; + struct ath12k *ar; + u8 link_id; + + lockdep_assert_wiphy(hw->wiphy); + + if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { + ahvif->u.ap.ssid_len = vif->cfg.ssid_len; + if (vif->cfg.ssid_len) + memcpy(ahvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); + } + + if (changed & BSS_CHANGED_ASSOC) { + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || !arvif->ar) + continue; + + ar = arvif->ar; + + if (vif->cfg.assoc) + ath12k_bss_assoc(ar, arvif, &vif->bss_conf); + else + ath12k_bss_disassoc(ar, arvif); + } + } +} + +static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; - struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif *vif = arvif->ahvif->vif; struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf; enum wmi_sta_powersave_param param; enum wmi_sta_ps_mode psmode; @@ -3091,12 +3190,12 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) int timeout; bool enable_ps; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (vif->type != NL80211_IFTYPE_STATION) return; - enable_ps = arvif->ps; + enable_ps = arvif->ahvif->ps; if (enable_ps) { psmode = WMI_STA_PS_MODE_ENABLED; param = WMI_STA_PS_PARAM_INACTIVITY_TIME; @@ -3128,11 +3227,12 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) } static void ath12k_mac_bss_info_changed(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct ieee80211_bss_conf *info, u64 changed) { - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ieee80211_vif_cfg *vif_cfg = &vif->cfg; struct cfg80211_chan_def def; u32 param_id, param_value; @@ -3146,7 +3246,7 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, u8 rateidx; u32 rate; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (changed & BSS_CHANGED_BEACON_INT) { arvif->beacon_interval = info->beacon_int; @@ -3202,10 +3302,10 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, if (changed & BSS_CHANGED_SSID && vif->type == NL80211_IFTYPE_AP) { - arvif->u.ap.ssid_len = vif->cfg.ssid_len; + ahvif->u.ap.ssid_len = vif->cfg.ssid_len; if (vif->cfg.ssid_len) - memcpy(arvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); - arvif->u.ap.hidden_ssid = info->hidden_ssid; + memcpy(ahvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); + ahvif->u.ap.hidden_ssid = info->hidden_ssid; } if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) @@ -3316,7 +3416,7 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, } if (changed & BSS_CHANGED_MCAST_RATE && - !ath12k_mac_vif_chan(arvif->vif, &def)) { + !ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)) { band = def.chan->band; mcast_rate = vif->bss_conf.mcast_rate[band]; @@ -3360,8 +3460,8 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, } if (changed & BSS_CHANGED_BASIC_RATES && - !ath12k_mac_vif_chan(arvif->vif, &def)) - ath12k_recalculate_mgmt_rate(ar, vif, &def); + !ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)) + ath12k_recalculate_mgmt_rate(ar, arvif, &def); if (changed & BSS_CHANGED_TWT) { if (info->twt_requester || info->twt_responder) @@ -3406,53 +3506,177 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, if (changed & BSS_CHANGED_PS && ar->ab->hw_params->supports_sta_ps) { - arvif->ps = vif_cfg->ps; + ahvif->ps = vif_cfg->ps; ath12k_mac_vif_setup_ps(arvif); } } -static struct ath12k_vif_cache *ath12k_arvif_get_cache(struct ath12k_vif *arvif) +static struct ath12k_vif_cache *ath12k_ahvif_get_link_cache(struct ath12k_vif *ahvif, + u8 link_id) +{ + if (!ahvif->cache[link_id]) { + ahvif->cache[link_id] = kzalloc(sizeof(*ahvif->cache[0]), GFP_KERNEL); + if (ahvif->cache[link_id]) + INIT_LIST_HEAD(&ahvif->cache[link_id]->key_conf.list); + } + + return ahvif->cache[link_id]; +} + +static void ath12k_ahvif_put_link_key_cache(struct ath12k_vif_cache *cache) { - if (!arvif->cache) - arvif->cache = kzalloc(sizeof(*arvif->cache), GFP_KERNEL); + struct ath12k_key_conf *key_conf, *tmp; - return arvif->cache; + if (!cache || list_empty(&cache->key_conf.list)) + return; + list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) { + list_del(&key_conf->list); + kfree(key_conf); + } } -static void ath12k_arvif_put_cache(struct ath12k_vif *arvif) +static void ath12k_ahvif_put_link_cache(struct ath12k_vif *ahvif, u8 link_id) { - kfree(arvif->cache); - arvif->cache = NULL; + ath12k_ahvif_put_link_key_cache(ahvif->cache[link_id]); + kfree(ahvif->cache[link_id]); + ahvif->cache[link_id] = NULL; } -static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u64 changed) +static void ath12k_mac_op_link_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u64 changed) { struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_vif_cache *cache; + struct ath12k_link_vif *arvif; + u8 link_id = info->link_id; - ar = ath12k_get_ar_by_vif(hw, vif); + lockdep_assert_wiphy(hw->wiphy); + + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); /* if the vdev is not created on a certain radio, * cache the info to be updated later on vdev creation */ - if (!ar) { - cache = ath12k_arvif_get_cache(arvif); + if (!arvif || !arvif->is_created) { + cache = ath12k_ahvif_get_link_cache(ahvif, link_id); if (!cache) return; - arvif->cache->bss_conf_changed |= changed; + + cache->bss_conf_changed |= changed; + return; } - mutex_lock(&ar->conf_mutex); + ar = arvif->ar; ath12k_mac_bss_info_changed(ar, arvif, info, changed); +} + +static struct ath12k_link_vif *ath12k_mac_assign_link_vif(struct ath12k_hw *ah, + struct ieee80211_vif *vif, + u8 link_id) +{ + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + int i; + + lockdep_assert_wiphy(ah->hw->wiphy); + + arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]); + if (arvif) + return arvif; + + if (!vif->valid_links) { + /* Use deflink for Non-ML VIFs and mark the link id as 0 + */ + link_id = 0; + arvif = &ahvif->deflink; + } else { + /* If this is the first link arvif being created for an ML VIF + * use the preallocated deflink memory + */ + if (!ahvif->links_map) { + arvif = &ahvif->deflink; + } else { + arvif = (struct ath12k_link_vif *) + kzalloc(sizeof(struct ath12k_link_vif), GFP_KERNEL); + if (!arvif) + return NULL; + } + } + + arvif->ahvif = ahvif; + arvif->link_id = link_id; + ahvif->links_map |= BIT(link_id); + + INIT_LIST_HEAD(&arvif->list); + INIT_DELAYED_WORK(&arvif->connection_loss_work, + ath12k_mac_vif_sta_connection_loss_work); + + for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { + arvif->bitrate_mask.control[i].legacy = 0xffffffff; + memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].ht_mcs)); + memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].vht_mcs)); + } + + /* Allocate Default Queue now and reassign during actual vdev create */ + vif->cab_queue = ATH12K_HW_DEFAULT_QUEUE; + for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++) + vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE; - mutex_unlock(&ar->conf_mutex); + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; + + rcu_assign_pointer(ahvif->link[arvif->link_id], arvif); + ahvif->links_map |= BIT(link_id); + synchronize_rcu(); + return arvif; +} + +static void ath12k_mac_unassign_link_vif(struct ath12k_link_vif *arvif) +{ + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k_hw *ah = ahvif->ah; + + lockdep_assert_wiphy(ah->hw->wiphy); + + rcu_assign_pointer(ahvif->link[arvif->link_id], NULL); + synchronize_rcu(); + ahvif->links_map &= ~BIT(arvif->link_id); + + if (arvif != &ahvif->deflink) + kfree(arvif); + else + memset(arvif, 0, sizeof(*arvif)); +} + +static void ath12k_mac_remove_link_interface(struct ieee80211_hw *hw, + struct ath12k_link_vif *arvif) +{ + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k_hw *ah = hw->priv; + struct ath12k *ar = arvif->ar; + int ret; + + lockdep_assert_wiphy(ah->hw->wiphy); + + cancel_delayed_work_sync(&arvif->connection_loss_work); + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac remove link interface (vdev %d link id %d)", + arvif->vdev_id, arvif->link_id); + + if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) { + ret = ath12k_peer_delete(ar, arvif->vdev_id, arvif->bssid); + if (ret) + ath12k_warn(ar->ab, "failed to submit AP self-peer removal on vdev %d link id %d: %d", + arvif->vdev_id, arvif->link_id, ret); + } + ath12k_mac_vdev_delete(ar, arvif); } static struct ath12k* @@ -3541,7 +3765,7 @@ static int ath12k_scan_stop(struct ath12k *ar) }; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); /* TODO: Fill other STOP Params */ arg.pdev_id = ar->pdev->pdev_id; @@ -3581,7 +3805,7 @@ static void ath12k_scan_abort(struct ath12k *ar) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); spin_lock_bh(&ar->data_lock); @@ -3616,9 +3840,9 @@ static void ath12k_scan_timeout_work(struct work_struct *work) struct ath12k *ar = container_of(work, struct ath12k, scan.timeout.work); - mutex_lock(&ar->conf_mutex); + wiphy_lock(ath12k_ar_to_hw(ar)->wiphy); ath12k_scan_abort(ar); - mutex_unlock(&ar->conf_mutex); + wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); } static int ath12k_start_scan(struct ath12k *ar, @@ -3626,7 +3850,7 @@ static int ath12k_start_scan(struct ath12k *ar, { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ret = ath12k_wmi_send_scan_start_cmd(ar, arg); if (ret) @@ -3655,24 +3879,50 @@ static int ath12k_start_scan(struct ath12k *ar, return 0; } +static u8 +ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar) +{ + struct ath12k_link_vif *arvif; + struct ath12k_hw *ah = ahvif->ah; + unsigned long links = ahvif->links_map; + u8 link_id; + + lockdep_assert_wiphy(ah->hw->wiphy); + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]); + + if (!arvif || !arvif->is_created) + continue; + + if (ar == arvif->ar) + return link_id; + } + + /* input ar is not assigned to any of the links, use link id + * 0 for scan vdev creation. + */ + return 0; +} + static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar, *prev_ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar; + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; struct cfg80211_scan_request *req = &hw_req->req; struct ath12k_wmi_scan_req_arg *arg = NULL; + u8 link_id; int ret; int i; bool create = true; - if (ah->num_radio == 1) { - WARN_ON(!arvif->is_created); - ar = ath12k_ah_to_ar(ah, 0); - goto scan; - } + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; /* Since the targeted scan device could depend on the frequency * requested in the hw_req, select the corresponding radio @@ -3681,6 +3931,13 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, if (!ar) return -EINVAL; + /* check if any of the links of ML VIF is already started on + * radio(ar) correpsondig to given scan frequency and use it, + * if not use deflink(link 0) for scan purpose. + */ + link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar); + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + /* If the vif is already assigned to a specific vdev of an ar, * check whether its already started, vdev which is started * are not allowed to switch to a new radio. @@ -3698,31 +3955,24 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, return -EINVAL; if (ar != arvif->ar) { - /* backup the previously used ar ptr, since the vdev delete - * would assign the arvif->ar to NULL after the call - */ - prev_ar = arvif->ar; - mutex_lock(&prev_ar->conf_mutex); - ret = ath12k_mac_vdev_delete(prev_ar, vif); - mutex_unlock(&prev_ar->conf_mutex); - if (ret) - ath12k_warn(prev_ar->ab, - "unable to delete scan vdev %d\n", ret); + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } else { create = false; } } if (create) { - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_vdev_create(ar, vif); - mutex_unlock(&ar->conf_mutex); + /* Previous arvif would've been cleared in radio switch block + * above, assign arvif again for create. + */ + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + + ret = ath12k_mac_vdev_create(ar, arvif); if (ret) { ath12k_warn(ar->ab, "unable to create scan vdev %d\n", ret); return -EINVAL; } } -scan: - mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); switch (ar->scan.state) { @@ -3805,30 +4055,31 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, kfree(arg); } - mutex_unlock(&ar->conf_mutex); - return ret; } static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; struct ath12k *ar; + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + if (!arvif->is_created) return; ar = arvif->ar; - mutex_lock(&ar->conf_mutex); ath12k_scan_abort(ar); - mutex_unlock(&ar->conf_mutex); cancel_delayed_work_sync(&ar->scan.timeout); } -static int ath12k_install_key(struct ath12k_vif *arvif, +static int ath12k_install_key(struct ath12k_link_vif *arvif, struct ieee80211_key_conf *key, enum set_key_cmd cmd, const u8 *macaddr, u32 flags) @@ -3843,8 +4094,10 @@ static int ath12k_install_key(struct ath12k_vif *arvif, .key_flags = flags, .macaddr = macaddr, }; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); - lockdep_assert_held(&arvif->ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->install_key_done); @@ -3895,13 +4148,13 @@ static int ath12k_install_key(struct ath12k_vif *arvif, if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ)) return -ETIMEDOUT; - if (ether_addr_equal(macaddr, arvif->vif->addr)) - arvif->key_cipher = key->cipher; + if (ether_addr_equal(macaddr, vif->addr)) + ahvif->key_cipher = key->cipher; return ar->install_key_status ? -EINVAL : 0; } -static int ath12k_clear_peer_keys(struct ath12k_vif *arvif, +static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif, const u8 *addr) { struct ath12k *ar = arvif->ar; @@ -3912,7 +4165,7 @@ static int ath12k_clear_peer_keys(struct ath12k_vif *arvif, int i; u32 flags = 0; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); spin_lock_bh(&ab->base_lock); peer = ath12k_peer_find(ab, arvif->vdev_id, addr); @@ -3944,25 +4197,31 @@ static int ath12k_clear_peer_keys(struct ath12k_vif *arvif, } static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, struct ieee80211_key_conf *key) { + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); + struct ieee80211_sta *sta = NULL; struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_peer *peer; - struct ath12k_sta *arsta; + struct ath12k_sta *ahsta; const u8 *peer_addr; - int ret = 0; + int ret; u32 flags = 0; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + if (arsta) + sta = ath12k_ahsta_to_sta(arsta->ahsta); if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) return 1; if (sta) peer_addr = sta->addr; - else if (arvif->vdev_type == WMI_VDEV_TYPE_STA) + else if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) peer_addr = vif->bss_conf.bssid; else peer_addr = vif->addr; @@ -3970,7 +4229,7 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, key->hw_key_idx = key->keyidx; /* the peer should not disappear in mid-way (unless FW goes awry) since - * we already hold conf_mutex. we just make sure its there now. + * we already hold wiphy lock. we just make sure its there now. */ spin_lock_bh(&ab->base_lock); peer = ath12k_peer_find(ab, arvif->vdev_id, peer_addr); @@ -3980,14 +4239,13 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, if (cmd == SET_KEY) { ath12k_warn(ab, "cannot install key for non-existent peer %pM\n", peer_addr); - ret = -EOPNOTSUPP; - goto exit; - } else { - /* if the peer doesn't exist there is no key to disable - * anymore - */ - goto exit; + return -EOPNOTSUPP; } + + /* if the peer doesn't exist there is no key to disable + * anymore + */ + return 0; } if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) @@ -3998,13 +4256,13 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, ret = ath12k_install_key(arvif, key, cmd, peer_addr, flags); if (ret) { ath12k_warn(ab, "ath12k_install_key failed (%d)\n", ret); - goto exit; + return ret; } ret = ath12k_dp_rx_peer_pn_replay_config(arvif, peer_addr, cmd, key); if (ret) { ath12k_warn(ab, "failed to offload PN replay detection %d\n", ret); - goto exit; + return ret; } spin_lock_bh(&ab->base_lock); @@ -4029,7 +4287,7 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, ath12k_warn(ab, "peer %pM disappeared!\n", peer_addr); if (sta) { - arsta = ath12k_sta_to_arsta(sta); + ahsta = ath12k_sta_to_ahsta(sta); switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: @@ -4038,61 +4296,138 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: if (cmd == SET_KEY) - arsta->pn_type = HAL_PN_TYPE_WPA; + ahsta->pn_type = HAL_PN_TYPE_WPA; else - arsta->pn_type = HAL_PN_TYPE_NONE; + ahsta->pn_type = HAL_PN_TYPE_NONE; break; default: - arsta->pn_type = HAL_PN_TYPE_NONE; + ahsta->pn_type = HAL_PN_TYPE_NONE; break; } } spin_unlock_bh(&ab->base_lock); -exit: - return ret; + return 0; +} + +static int ath12k_mac_update_key_cache(struct ath12k_vif_cache *cache, + enum set_key_cmd cmd, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct ath12k_key_conf *key_conf = NULL, *tmp; + + if (cmd == SET_KEY) { + key_conf = kzalloc(sizeof(*key_conf), GFP_KERNEL); + + if (!key_conf) + return -ENOMEM; + + key_conf->cmd = cmd; + key_conf->sta = sta; + key_conf->key = key; + list_add_tail(&key_conf->list, + &cache->key_conf.list); + } + if (list_empty(&cache->key_conf.list)) + return 0; + list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) { + if (key_conf->key == key) { + /* DEL key for an old SET key which driver hasn't flushed yet. + */ + list_del(&key_conf->list); + kfree(key_conf); + break; + } + } + return 0; } static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + struct ath12k_link_sta *arsta = NULL; struct ath12k_vif_cache *cache; - struct ath12k *ar; + struct ath12k_sta *ahsta; + unsigned long links; + u8 link_id; int ret; + lockdep_assert_wiphy(hw->wiphy); + /* BIP needs to be done in software */ if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || - key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) + key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) { return 1; + } if (key->keyidx > WMI_MAX_KEY_INDEX) return -ENOSPC; - ar = ath12k_get_ar_by_vif(hw, vif); - if (!ar) { - /* ar is expected to be valid when sta ptr is available */ - if (sta) { - WARN_ON_ONCE(1); - return -EINVAL; + if (sta) { + ahsta = ath12k_sta_to_ahsta(sta); + /* For an ML STA Pairwise key is same for all associated link Stations, + * hence do set key for all link STAs which are active. + */ + if (sta->mlo) { + links = ahsta->links_map; + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(hw->wiphy, + ahvif->link[link_id]); + arsta = wiphy_dereference(hw->wiphy, + ahsta->link[link_id]); + + if (WARN_ON(!arvif || !arsta)) + /* arvif and arsta are expected to be valid when + * STA is present. + */ + continue; + + ret = ath12k_mac_set_key(arvif->ar, cmd, arvif, + arsta, key); + if (ret) + break; + } + } else { + arsta = &ahsta->deflink; + arvif = arsta->arvif; + if (WARN_ON(!arvif)) { + ret = -EINVAL; + goto out; + } + + ret = ath12k_mac_set_key(arvif->ar, cmd, arvif, arsta, key); + } + } else { + if (key->link_id >= 0 && key->link_id < IEEE80211_MLD_MAX_NUM_LINKS) { + link_id = key->link_id; + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + } else { + link_id = 0; + arvif = &ahvif->deflink; } - cache = ath12k_arvif_get_cache(arvif); - if (!cache) - return -ENOSPC; - cache->key_conf.cmd = cmd; - cache->key_conf.key = key; - cache->key_conf.changed = true; - return 0; + if (!arvif || !arvif->is_created) { + cache = ath12k_ahvif_get_link_cache(ahvif, link_id); + if (!cache) + return -ENOSPC; + + ret = ath12k_mac_update_key_cache(cache, cmd, sta, key); + + return ret; + } + + ret = ath12k_mac_set_key(arvif->ar, cmd, arvif, NULL, key); } - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_set_key(ar, cmd, vif, sta, key); - mutex_unlock(&ar->conf_mutex); +out: + return ret; } @@ -4111,17 +4446,18 @@ ath12k_mac_bitrate_mask_num_vht_rates(struct ath12k *ar, } static int -ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_vif *arvif, - struct ieee80211_sta *sta, +ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, const struct cfg80211_bitrate_mask *mask, enum nl80211_band band) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k *ar = arvif->ar; u8 vht_rate, nss; u32 rate_code; int ret, i; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); nss = 0; @@ -4157,11 +4493,12 @@ ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_vif *arvif, } static int ath12k_station_assoc(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, bool reassoc) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k_wmi_peer_assoc_arg peer_arg; int ret; struct cfg80211_chan_def def; @@ -4169,15 +4506,15 @@ static int ath12k_station_assoc(struct ath12k *ar, struct cfg80211_bitrate_mask *mask; u8 num_vht_rates; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return -EPERM; band = def.chan->band; mask = &arvif->bitrate_mask; - ath12k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc); + ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, reassoc); if (peer_arg.peer_nss < 1) { ath12k_warn(ar->ab, @@ -4205,7 +4542,7 @@ static int ath12k_station_assoc(struct ath12k *ar, * Note that all other rates and NSS will be disabled for this peer. */ if (sta->deflink.vht_cap.vht_supported && num_vht_rates == 1) { - ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, + ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, band); if (ret) return ret; @@ -4234,7 +4571,7 @@ static int ath12k_station_assoc(struct ath12k *ar, } if (sta->wme && sta->uapsd_queues) { - ret = ath12k_peer_assoc_qos_ap(ar, arvif, sta); + ret = ath12k_peer_assoc_qos_ap(ar, arvif, arsta); if (ret) { ath12k_warn(ar->ab, "failed to set qos params for STA %pM for vdev %i: %d\n", sta->addr, arvif->vdev_id, ret); @@ -4246,13 +4583,13 @@ static int ath12k_station_assoc(struct ath12k *ar, } static int ath12k_station_disassoc(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!sta->wme) { arvif->num_legacy_stations--; @@ -4270,11 +4607,10 @@ static int ath12k_station_disassoc(struct ath12k *ar, return 0; } -static void ath12k_sta_rc_update_wk(struct work_struct *wk) +static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) { struct ath12k *ar; - struct ath12k_vif *arvif; - struct ath12k_sta *arsta; + struct ath12k_link_vif *arvif; struct ieee80211_sta *sta; struct cfg80211_chan_def def; enum nl80211_band band; @@ -4285,13 +4621,18 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) const struct cfg80211_bitrate_mask *mask; struct ath12k_wmi_peer_assoc_arg peer_arg; enum wmi_phy_mode peer_phymode; + struct ath12k_link_sta *arsta; + struct ieee80211_vif *vif; - arsta = container_of(wk, struct ath12k_sta, update_wk); - sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); + lockdep_assert_wiphy(wiphy); + + arsta = container_of(wk, struct ath12k_link_sta, update_wk); + sta = ath12k_ahsta_to_sta(arsta->ahsta); arvif = arsta->arvif; + vif = ath12k_ahvif_to_vif(arvif->ahvif); ar = arvif->ar; - if (WARN_ON(ath12k_mac_vif_chan(arvif->vif, &def))) + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) return; band = def.chan->band; @@ -4310,14 +4651,12 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) spin_unlock_bh(&ar->data_lock); - mutex_lock(&ar->conf_mutex); - nss = max_t(u32, 1, nss); nss = min(nss, max(ath12k_mac_max_ht_nss(ht_mcs_mask), ath12k_mac_max_vht_nss(vht_mcs_mask))); if (changed & IEEE80211_RC_BW_CHANGED) { - ath12k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg); + ath12k_peer_assoc_h_phymode(ar, arvif, arsta, &peer_arg); peer_phymode = peer_arg.peer_phymode; if (bw > bw_prev) { @@ -4334,7 +4673,7 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) if (err) { ath12k_warn(ar->ab, "failed to update STA %pM to peer phymode %d: %d\n", sta->addr, peer_phymode, err); - goto err_rc_bw_changed; + return; } err = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, WMI_PEER_CHWIDTH, @@ -4355,7 +4694,7 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) if (err) { ath12k_warn(ar->ab, "failed to update STA %pM peer to bandwidth %d: %d\n", sta->addr, bw, err); - goto err_rc_bw_changed; + return; } err = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, WMI_PEER_PHYMODE, @@ -4405,14 +4744,14 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) * across HT/VHT and for multiple VHT MCS support. */ if (sta->deflink.vht_cap.vht_supported && num_vht_rates == 1) { - ath12k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, + ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, band); } else { /* If the peer is non-VHT or no fixed VHT rate * is provided in the new bitrate mask we set the * other rates using peer_assoc command. */ - ath12k_peer_assoc_prepare(ar, arvif->vif, sta, + ath12k_peer_assoc_prepare(ar, arvif, arsta, &peer_arg, true); err = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg); @@ -4425,18 +4764,17 @@ static void ath12k_sta_rc_update_wk(struct work_struct *wk) sta->addr, arvif->vdev_id); } } -err_rc_bw_changed: - mutex_unlock(&ar->conf_mutex); } -static int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif, - struct ieee80211_sta *sta) +static int ath12k_mac_inc_num_stations(struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k *ar = arvif->ar; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) + if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) return 0; if (ar->num_stations >= ar->max_num_stations) @@ -4447,38 +4785,38 @@ static int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif, return 0; } -static void ath12k_mac_dec_num_stations(struct ath12k_vif *arvif, - struct ieee80211_sta *sta) +static void ath12k_mac_dec_num_stations(struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k *ar = arvif->ar; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) + if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) return; ar->num_stations--; } static int ath12k_mac_station_add(struct ath12k *ar, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta) { struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); struct ath12k_wmi_peer_create_arg peer_param; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - ret = ath12k_mac_inc_num_stations(arvif, sta); + ret = ath12k_mac_inc_num_stations(arvif, arsta); if (ret) { ath12k_warn(ab, "refusing to associate station: too many connected already (%d)\n", ar->max_num_stations); goto exit; } - arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); if (!arsta->rx_stats) { ret = -ENOMEM; @@ -4519,7 +4857,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, if (ab->hw_params->vdev_start_delay && !arvif->is_started && - arvif->vdev_type != WMI_VDEV_TYPE_AP) { + arvif->ahvif->vdev_type != WMI_VDEV_TYPE_AP) { ret = ath12k_start_vdev_delay(ar, arvif); if (ret) { ath12k_warn(ab, "failed to delay vdev start: %d\n", ret); @@ -4532,7 +4870,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, free_peer: ath12k_peer_delete(ar, arvif->vdev_id, sta->addr); dec_num_station: - ath12k_mac_dec_num_stations(arvif, sta); + ath12k_mac_dec_num_stations(arvif, arsta); exit: return ret; } @@ -4574,16 +4912,18 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); + struct ath12k_link_vif *arvif; + struct ath12k_link_sta *arsta; struct ath12k_peer *peer; int ret = 0; - /* cancel must be done outside the mutex to avoid deadlock */ - if ((old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST)) - cancel_work_sync(&arsta->update_wk); + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + arsta = &ahsta->deflink; ar = ath12k_get_ar_by_vif(hw, vif); if (!ar) { @@ -4591,21 +4931,28 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, return -EINVAL; } - mutex_lock(&ar->conf_mutex); - if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) { memset(arsta, 0, sizeof(*arsta)); + rcu_assign_pointer(ahsta->link[0], arsta); + /* TODO use appropriate link id once MLO support is added */ + arsta->link_id = ATH12K_DEFAULT_LINK_ID; + ahsta->links_map = BIT(arsta->link_id); + arsta->ahsta = ahsta; arsta->arvif = arvif; - INIT_WORK(&arsta->update_wk, ath12k_sta_rc_update_wk); + wiphy_work_init(&arsta->update_wk, ath12k_sta_rc_update_wk); + + synchronize_rcu(); - ret = ath12k_mac_station_add(ar, vif, sta); + ret = ath12k_mac_station_add(ar, arvif, arsta); if (ret) ath12k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n", sta->addr, arvif->vdev_id); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { - if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { + wiphy_work_cancel(hw->wiphy, &arsta->update_wk); + + if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) { ath12k_bss_disassoc(ar, arvif); ret = ath12k_mac_vdev_stop(arvif); if (ret) @@ -4622,7 +4969,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n", sta->addr, arvif->vdev_id); - ath12k_mac_dec_num_stations(arvif, sta); + ath12k_mac_dec_num_stations(arvif, arsta); spin_lock_bh(&ar->ab->base_lock); peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); if (peer && peer->sta == sta) { @@ -4637,12 +4984,20 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, kfree(arsta->rx_stats); arsta->rx_stats = NULL; + + if (arsta->link_id < IEEE80211_MLD_MAX_NUM_LINKS) { + rcu_assign_pointer(ahsta->link[arsta->link_id], NULL); + synchronize_rcu(); + ahsta->links_map &= ~(BIT(arsta->link_id)); + arsta->link_id = ATH12K_INVALID_LINK_ID; + arsta->ahsta = NULL; + } } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT || vif->type == NL80211_IFTYPE_ADHOC)) { - ret = ath12k_station_assoc(ar, vif, sta, false); + ret = ath12k_station_assoc(ar, arvif, arsta, false); if (ret) ath12k_warn(ar->ab, "Failed to associate station: %pM\n", sta->addr); @@ -4686,14 +5041,12 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_MESH_POINT || vif->type == NL80211_IFTYPE_ADHOC)) { - ret = ath12k_station_disassoc(ar, vif, sta); + ret = ath12k_station_disassoc(ar, arvif, arsta); if (ret) ath12k_warn(ar->ab, "Failed to disassociate station: %pM\n", sta->addr); } - mutex_unlock(&ar->conf_mutex); - return ret; } @@ -4703,25 +5056,32 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; int ret; s16 txpwr; + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) { txpwr = 0; } else { txpwr = sta->deflink.txpwr.power; - if (!txpwr) - return -EINVAL; + if (!txpwr) { + ret = -EINVAL; + goto out; + } } - if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) - return -EINVAL; + if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) { + ret = -EINVAL; + goto out; + } ar = ath12k_ah_to_ar(ah, 0); - mutex_lock(&ar->conf_mutex); - ret = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, WMI_PEER_USE_FIXED_PWR, txpwr); if (ret) { @@ -4731,20 +5091,26 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, } out: - mutex_unlock(&ar->conf_mutex); return ret; } static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct ath12k *ar; - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_sta *arsta; + struct ath12k_link_vif *arvif; struct ath12k_peer *peer; u32 bw, smps; + /* TODO: use proper link id once link sta specific rc update support is + * available in mac80211. + */ + u8 link_id = ATH12K_DEFAULT_LINK_ID; ar = ath12k_get_ar_by_vif(hw, vif); if (!ar) { @@ -4752,11 +5118,27 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, return; } + rcu_read_lock(); + arvif = rcu_dereference(ahvif->link[link_id]); + if (!arvif) { + ath12k_warn(ar->ab, "mac sta rc update failed to fetch link vif on link id %u for peer %pM\n", + link_id, sta->addr); + rcu_read_unlock(); + return; + } + arsta = rcu_dereference(ahsta->link[link_id]); + if (!arsta) { + rcu_read_unlock(); + ath12k_warn(ar->ab, "mac sta rc update failed to fetch link sta on link id %u for peer %pM\n", + link_id, sta->addr); + return; + } spin_lock_bh(&ar->ab->base_lock); peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); if (!peer) { spin_unlock_bh(&ar->ab->base_lock); + rcu_read_unlock(); ath12k_warn(ar->ab, "mac sta rc update failed to find peer %pM on vdev %i\n", sta->addr, arvif->vdev_id); return; @@ -4808,17 +5190,20 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); - ieee80211_queue_work(hw, &arsta->update_wk); + wiphy_work_queue(hw->wiphy, &arsta->update_wk); + + rcu_read_unlock(); } -static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif, +static int ath12k_conf_tx_uapsd(struct ath12k_link_vif *arvif, u16 ac, bool enable) { struct ath12k *ar = arvif->ar; + struct ath12k_vif *ahvif = arvif->ahvif; u32 value; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA) return 0; switch (ac) { @@ -4841,19 +5226,19 @@ static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif, } if (enable) - arvif->u.sta.uapsd |= value; + ahvif->u.sta.uapsd |= value; else - arvif->u.sta.uapsd &= ~value; + ahvif->u.sta.uapsd &= ~value; ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, WMI_STA_PS_PARAM_UAPSD, - arvif->u.sta.uapsd); + ahvif->u.sta.uapsd); if (ret) { ath12k_warn(ar->ab, "could not set uapsd params %d\n", ret); goto exit; } - if (arvif->u.sta.uapsd) + if (ahvif->u.sta.uapsd) value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; else value = WMI_STA_PS_RX_WAKE_POLICY_WAKE; @@ -4868,8 +5253,7 @@ static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif, return ret; } -static int ath12k_mac_conf_tx(struct ath12k_vif *arvif, - unsigned int link_id, u16 ac, +static int ath12k_mac_conf_tx(struct ath12k_link_vif *arvif, u16 ac, const struct ieee80211_tx_queue_params *params) { struct wmi_wmm_params_arg *p = NULL; @@ -4877,7 +5261,7 @@ static int ath12k_mac_conf_tx(struct ath12k_vif *arvif, struct ath12k_base *ab = ar->ab; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); switch (ac) { case IEEE80211_AC_VO: @@ -4926,26 +5310,30 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { - struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_vif_cache *cache = arvif->cache; + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + struct ath12k_vif_cache *cache; int ret; - ar = ath12k_get_ar_by_vif(hw, vif); - if (!ar) { - /* cache the info and apply after vdev is created */ - cache = ath12k_arvif_get_cache(arvif); + lockdep_assert_wiphy(hw->wiphy); + + if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) + return -EINVAL; + + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || !arvif->is_created) { + cache = ath12k_ahvif_get_link_cache(ahvif, link_id); if (!cache) return -ENOSPC; + cache->tx_conf.changed = true; cache->tx_conf.ac = ac; cache->tx_conf.tx_queue_params = *params; + return 0; } - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_conf_tx(arvif, link_id, ac, params); - mutex_unlock(&ar->conf_mutex); + ret = ath12k_mac_conf_tx(arvif, ac, params); return ret; } @@ -5016,10 +5404,11 @@ ath12k_create_ht_cap(struct ath12k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask return ht_cap; } -static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif) +static int ath12k_mac_set_txbf_conf(struct ath12k_link_vif *arvif) { u32 value = 0; struct ath12k *ar = arvif->ar; + struct ath12k_vif *ahvif = arvif->ahvif; int nsts; int sound_dim; u32 vht_cap = ar->pdev->cap.vht_cap; @@ -5047,7 +5436,7 @@ static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif) value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) && - arvif->vdev_type == WMI_VDEV_TYPE_AP) + ahvif->vdev_type == WMI_VDEV_TYPE_AP) value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER; } @@ -5055,7 +5444,7 @@ static int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif) value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && - arvif->vdev_type == WMI_VDEV_TYPE_STA) + ahvif->vdev_type == WMI_VDEV_TYPE_STA) value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE; } @@ -5612,7 +6001,7 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) struct ath12k_hw *ah = ath12k_ar_to_ah(ar); int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (ath12k_check_chain_mask(ar, tx_ant, true)) return -EINVAL; @@ -5716,7 +6105,7 @@ static int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx) return 0; } -static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_vif *arvif, +static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arvif, struct sk_buff *skb) { struct ath12k_base *ab = ar->ab; @@ -5784,7 +6173,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) { struct ath12k *ar = container_of(work, struct ath12k, wmi_mgmt_tx_work); struct ath12k_skb_cb *skb_cb; - struct ath12k_vif *arvif; + struct ath12k_vif *ahvif; + struct ath12k_link_vif *arvif; struct sk_buff *skb; int ret; @@ -5796,8 +6186,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) continue; } - arvif = ath12k_vif_to_arvif(skb_cb->vif); - + ahvif = ath12k_vif_to_ahvif(skb_cb->vif); + arvif = &ahvif->deflink; if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) { ret = ath12k_mac_mgmt_tx_wmi(ar, arvif, skb); if (ret) { @@ -5852,18 +6242,18 @@ static void ath12k_mac_add_p2p_noa_ie(struct ath12k *ar, struct sk_buff *skb, bool is_prb_rsp) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); if (likely(!is_prb_rsp)) return; spin_lock_bh(&ar->data_lock); - if (arvif->u.ap.noa_data && - !pskb_expand_head(skb, 0, arvif->u.ap.noa_len, + if (ahvif->u.ap.noa_data && + !pskb_expand_head(skb, 0, ahvif->u.ap.noa_len, GFP_ATOMIC)) - skb_put_data(skb, arvif->u.ap.noa_data, - arvif->u.ap.noa_len); + skb_put_data(skb, ahvif->u.ap.noa_data, + ahvif->u.ap.noa_len); spin_unlock_bh(&ar->data_lock); } @@ -5875,7 +6265,8 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; struct ath12k *ar = arvif->ar; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_key_conf *key = info->control.hw_key; @@ -5939,8 +6330,7 @@ static int ath12k_mac_start(struct ath12k *ar) int ret; lockdep_assert_held(&ah->hw_mutex); - - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 1, pdev->pdev_id); @@ -6025,14 +6415,11 @@ static int ath12k_mac_start(struct ath12k *ar) } } - mutex_unlock(&ar->conf_mutex); - rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], &ab->pdevs[ar->pdev_idx]); return 0; err: - mutex_unlock(&ar->conf_mutex); return ret; } @@ -6052,6 +6439,8 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) struct ath12k *ar; int ret, i; + lockdep_assert_wiphy(hw->wiphy); + ath12k_drain_tx(ah); guard(mutex)(&ah->hw_mutex); @@ -6158,15 +6547,14 @@ static void ath12k_mac_stop(struct ath12k *ar) int ret; lockdep_assert_held(&ah->hw_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - mutex_lock(&ar->conf_mutex); ret = ath12k_mac_config_mon_status_default(ar, false); if (ret && (ret != -EOPNOTSUPP)) ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n", ret); clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); - mutex_unlock(&ar->conf_mutex); cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); @@ -6192,6 +6580,8 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend) struct ath12k *ar; int i; + lockdep_assert_wiphy(hw->wiphy); + ath12k_drain_tx(ah); mutex_lock(&ah->hw_mutex); @@ -6205,7 +6595,7 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend) } static u8 -ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) +ath12k_mac_get_vdev_stats_id(struct ath12k_link_vif *arvif) { struct ath12k_base *ab = arvif->ar->ab; u8 vdev_stats_id = 0; @@ -6227,19 +6617,22 @@ ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) return vdev_stats_id; } -static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif, +static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_link_vif *arvif, u32 *flags, u32 *tx_vdev_id) { - struct ieee80211_vif *tx_vif = arvif->vif->mbssid_tx_vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *tx_vif = ahvif->vif->mbssid_tx_vif; struct ath12k *ar = arvif->ar; - struct ath12k_vif *tx_arvif; + struct ath12k_link_vif *tx_arvif; + struct ath12k_vif *tx_ahvif; if (!tx_vif) return 0; - tx_arvif = ath12k_vif_to_arvif(tx_vif); + tx_ahvif = ath12k_vif_to_ahvif(tx_vif); + tx_arvif = &tx_ahvif->deflink; - if (arvif->vif->bss_conf.nontransmitted) { + if (ahvif->vif->bss_conf.nontransmitted) { if (ar->ah->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy) return -EINVAL; @@ -6251,22 +6644,23 @@ static int ath12k_mac_setup_vdev_params_mbssid(struct ath12k_vif *arvif, return -EINVAL; } - if (arvif->vif->bss_conf.ema_ap) + if (ahvif->vif->bss_conf.ema_ap) *flags |= WMI_VDEV_MBSSID_FLAGS_EMA_MODE; return 0; } -static int ath12k_mac_setup_vdev_create_arg(struct ath12k_vif *arvif, +static int ath12k_mac_setup_vdev_create_arg(struct ath12k_link_vif *arvif, struct ath12k_wmi_vdev_create_arg *arg) { struct ath12k *ar = arvif->ar; struct ath12k_pdev *pdev = ar->pdev; + struct ath12k_vif *ahvif = arvif->ahvif; int ret; arg->if_id = arvif->vdev_id; - arg->type = arvif->vdev_type; - arg->subtype = arvif->vdev_subtype; + arg->type = ahvif->vdev_type; + arg->subtype = ahvif->vdev_subtype; arg->pdev_id = pdev->pdev_id; arg->mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP; @@ -6333,14 +6727,15 @@ ath12k_mac_prepare_he_mode(struct ath12k_pdev *pdev, u32 viftype) } static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, - struct ath12k_vif *arvif) + struct ath12k_link_vif *arvif) { u32 param_id, param_value; struct ath12k_base *ab = ar->ab; + struct ath12k_vif *ahvif = arvif->ahvif; int ret; param_id = WMI_VDEV_PARAM_SET_HEMU_MODE; - param_value = ath12k_mac_prepare_he_mode(ar->pdev, arvif->vif->type); + param_value = ath12k_mac_prepare_he_mode(ar->pdev, ahvif->vif->type); ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param_id, param_value); if (ret) { @@ -6363,9 +6758,10 @@ static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, return ret; } -static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) +static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif) { - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; u32 param_id, param_value; @@ -6378,14 +6774,14 @@ static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) IEEE80211_OFFLOAD_DECAP_ENABLED); if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) - arvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET; + ahvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET; else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) - arvif->tx_encap_type = ATH12K_HW_TXRX_RAW; + ahvif->tx_encap_type = ATH12K_HW_TXRX_RAW; else - arvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI; + ahvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, arvif->tx_encap_type); + param_id, ahvif->tx_encap_type); if (ret) { ath12k_warn(ab, "failed to set vdev %d tx encap mode: %d\n", arvif->vdev_id, ret); @@ -6412,57 +6808,86 @@ static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + unsigned long links; + int link_id; - ath12k_mac_update_vif_offload(arvif); + lockdep_assert_wiphy(hw->wiphy); + + if (vif->valid_links) { + links = vif->valid_links; + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!(arvif && arvif->ar)) + continue; + + ath12k_mac_update_vif_offload(arvif); + } + + return; + } + + ath12k_mac_update_vif_offload(&ahvif->deflink); } -static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) +int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) { struct ath12k_hw *ah = ar->ah; struct ath12k_base *ab = ar->ab; struct ieee80211_hw *hw = ah->hw; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k_wmi_vdev_create_arg vdev_arg = {0}; struct ath12k_wmi_peer_create_arg peer_param; + struct ieee80211_bss_conf *link_conf; u32 param_id, param_value; u16 nss; int i; int ret, vdev_id; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); + + link_conf = wiphy_dereference(hw->wiphy, vif->link_conf[arvif->link_id]); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in vdev create for vif %pM link %u\n", + vif->addr, arvif->link_id); + return -ENOLINK; + } + + memcpy(arvif->bssid, link_conf->addr, ETH_ALEN); arvif->ar = ar; vdev_id = __ffs64(ab->free_vdev_map); arvif->vdev_id = vdev_id; - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; switch (vif->type) { case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: - arvif->vdev_type = WMI_VDEV_TYPE_STA; + ahvif->vdev_type = WMI_VDEV_TYPE_STA; if (vif->p2p) - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; break; case NL80211_IFTYPE_MESH_POINT: - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; fallthrough; case NL80211_IFTYPE_AP: - arvif->vdev_type = WMI_VDEV_TYPE_AP; + ahvif->vdev_type = WMI_VDEV_TYPE_AP; if (vif->p2p) - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; break; case NL80211_IFTYPE_MONITOR: - arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; + ahvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ar->monitor_vdev_id = vdev_id; break; case NL80211_IFTYPE_P2P_DEVICE: - arvif->vdev_type = WMI_VDEV_TYPE_STA; - arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + ahvif->vdev_type = WMI_VDEV_TYPE_STA; + ahvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; break; default: WARN_ON(1); @@ -6470,7 +6895,7 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) } ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev create id %d type %d subtype %d map %llx\n", - arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, + arvif->vdev_id, ahvif->vdev_type, ahvif->vdev_subtype, ab->free_vdev_map); vif->cab_queue = arvif->vdev_id % (ATH12K_HW_MAX_QUEUES - 1); @@ -6484,11 +6909,11 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) goto err; } - ret = ath12k_wmi_vdev_create(ar, vif->addr, &vdev_arg); + ret = ath12k_wmi_vdev_create(ar, arvif->bssid, &vdev_arg); if (ret) { ath12k_warn(ab, "failed to create WMI vdev %d: %d\n", arvif->vdev_id, ret); - goto err; + return ret; } ar->num_created_vdevs++; @@ -6513,10 +6938,10 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) goto err_vdev_del; } - switch (arvif->vdev_type) { + switch (ahvif->vdev_type) { case WMI_VDEV_TYPE_AP: peer_param.vdev_id = arvif->vdev_id; - peer_param.peer_addr = vif->addr; + peer_param.peer_addr = arvif->bssid; peer_param.peer_type = WMI_PEER_TYPE_DEFAULT; ret = ath12k_peer_create(ar, arvif, NULL, &peer_param); if (ret) { @@ -6589,29 +7014,28 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) } ath12k_dp_vdev_tx_attach(ar, arvif); - if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled) ath12k_mac_monitor_vdev_create(ar); - arvif->ar = ar; return ret; err_peer_del: - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) { reinit_completion(&ar->peer_delete_done); - ret = ath12k_wmi_send_peer_delete_cmd(ar, vif->addr, + ret = ath12k_wmi_send_peer_delete_cmd(ar, arvif->bssid, arvif->vdev_id); if (ret) { ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", - arvif->vdev_id, vif->addr); + arvif->vdev_id, arvif->bssid); goto err; } ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id, - vif->addr); + arvif->bssid); if (ret) - goto err; + /* KVALO: why not goto err? */ + return ret; ar->num_peers--; } @@ -6633,21 +7057,56 @@ static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) return ret; } -static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ieee80211_vif *vif) +static void ath12k_mac_vif_flush_key_cache(struct ath12k_link_vif *arvif) +{ + struct ath12k_key_conf *key_conf, *tmp; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k_hw *ah = ahvif->ah; + struct ath12k_sta *ahsta; + struct ath12k_link_sta *arsta; + struct ath12k_vif_cache *cache = ahvif->cache[arvif->link_id]; + int ret; + + lockdep_assert_wiphy(ah->hw->wiphy); + + list_for_each_entry_safe(key_conf, tmp, &cache->key_conf.list, list) { + arsta = NULL; + if (key_conf->sta) { + ahsta = ath12k_sta_to_ahsta(key_conf->sta); + arsta = wiphy_dereference(ah->hw->wiphy, + ahsta->link[arvif->link_id]); + if (!arsta) + goto free_cache; + } + + ret = ath12k_mac_set_key(arvif->ar, key_conf->cmd, + arvif, arsta, + key_conf->key); + if (ret) + ath12k_warn(arvif->ar->ab, "unable to apply set key param to vdev %d ret %d\n", + arvif->vdev_id, ret); +free_cache: + list_del(&key_conf->list); + kfree(key_conf); + } +} + +static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ath12k_link_vif *arvif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_vif_cache *cache = arvif->cache; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); + struct ath12k_vif_cache *cache = ahvif->cache[arvif->link_id]; struct ath12k_base *ab = ar->ab; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!cache) return; if (cache->tx_conf.changed) { - ret = ath12k_mac_conf_tx(arvif, 0, cache->tx_conf.ac, + ret = ath12k_mac_conf_tx(arvif, cache->tx_conf.ac, &cache->tx_conf.tx_queue_params); if (ret) ath12k_warn(ab, @@ -6660,26 +7119,25 @@ static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ieee80211_vif cache->bss_conf_changed); } - if (cache->key_conf.changed) { - ret = ath12k_mac_set_key(ar, cache->key_conf.cmd, vif, NULL, - cache->key_conf.key); - if (ret) - ath12k_warn(ab, "unable to apply set key param to vdev %d ret %d\n", - arvif->vdev_id, ret); - } - ath12k_arvif_put_cache(arvif); + if (!list_empty(&cache->key_conf.list)) + ath12k_mac_vif_flush_key_cache(arvif); + + ath12k_ahvif_put_link_cache(ahvif, arvif->link_id); } static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, + struct ath12k_link_vif *arvif, struct ieee80211_chanctx_conf *ctx) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ath12k_hw *ah = hw->priv; - struct ath12k *ar, *prev_ar; + struct ath12k *ar; struct ath12k_base *ab; + u8 link_id = arvif->link_id; int ret; + lockdep_assert_wiphy(hw->wiphy); + if (ah->num_radio == 1) ar = ah->radio; else if (ctx) @@ -6708,27 +7166,20 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, if (WARN_ON(arvif->is_started)) return NULL; - /* backup the previously used ar ptr since arvif->ar would - * be set to NULL after vdev delete is done - */ - prev_ar = arvif->ar; - mutex_lock(&prev_ar->conf_mutex); - ret = ath12k_mac_vdev_delete(prev_ar, vif); - - if (ret) - ath12k_warn(prev_ar->ab, "unable to delete vdev %d\n", - ret); - mutex_unlock(&prev_ar->conf_mutex); + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } } ab = ar->ab; - mutex_lock(&ar->conf_mutex); - if (arvif->is_created) goto flush; + /* Assign arvif again here since previous radio switch block + * would've unassigned and cleared it. + */ + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); if (vif->type == NL80211_IFTYPE_AP && ar->num_peers > (ar->max_num_peers - 1)) { ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n"); @@ -6741,7 +7192,7 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, goto unlock; } - ret = ath12k_mac_vdev_create(ar, vif); + ret = ath12k_mac_vdev_create(ar, arvif); if (ret) { ath12k_warn(ab, "failed to create vdev %pM ret %d", vif->addr, ret); goto unlock; @@ -6752,21 +7203,27 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, * add_interface(), Apply any parameters for the vdev which were received * after add_interface, corresponding to this vif. */ - ath12k_mac_vif_cache_flush(ar, vif); + ath12k_mac_vif_cache_flush(ar, arvif); unlock: - mutex_unlock(&ar->conf_mutex); return arvif->ar; } static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; int i; - memset(arvif, 0, sizeof(*arvif)); + lockdep_assert_wiphy(hw->wiphy); - arvif->vif = vif; + memset(ahvif, 0, sizeof(*ahvif)); + + ahvif->ah = ah; + ahvif->vif = vif; + arvif = &ahvif->deflink; + arvif->ahvif = ahvif; INIT_LIST_HEAD(&arvif->list); INIT_DELAYED_WORK(&arvif->connection_loss_work, @@ -6786,13 +7243,14 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE; vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; - - /* For single radio wiphy(i.e ah->num_radio is 1), create the vdev - * during add_interface itself, for multi radio wiphy, defer the vdev - * creation until channel_assign to determine the radio on which the - * vdev needs to be created + /* For non-ml vifs, vif->addr is the actual vdev address but for + * ML vif link(link BSSID) address is the vdev address and it can be a + * different one from vif->addr (i.e ML address). + * Defer vdev creation until assign_chanctx or hw_scan is initiated as driver + * will not know if this interface is an ML vif at this point. */ - ath12k_mac_assign_vif_to_vdev(hw, vif, NULL); + ath12k_mac_assign_vif_to_vdev(hw, arvif, NULL); + return 0; } @@ -6821,14 +7279,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif } } -static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif) +static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ath12k_link_vif *arvif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); struct ath12k_base *ab = ar->ab; unsigned long time_left; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + reinit_completion(&ar->vdev_delete_done); ret = ath12k_wmi_vdev_delete(ar, arvif->vdev_id); @@ -6849,7 +7309,7 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif) ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); ar->num_created_vdevs--; - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ar->monitor_vdev_id = -1; ar->monitor_vdev_created = false; } else if (ar->monitor_vdev_created && !ar->monitor_started) { @@ -6865,7 +7325,7 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif) spin_unlock_bh(&ar->data_lock); ath12k_peer_cleanup(ar, arvif->vdev_id); - ath12k_arvif_put_cache(arvif); + ath12k_ahvif_put_link_cache(ahvif, arvif->link_id); idr_for_each(&ar->txmgmt_idr, ath12k_mac_vif_txmgmt_idr_remove, vif); @@ -6886,39 +7346,24 @@ static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif) static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_base *ab; - struct ath12k *ar; - int ret; + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + u8 link_id; - if (!arvif->is_created) { + lockdep_assert_wiphy(hw->wiphy); + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { /* if we cached some config but never received assign chanctx, * free the allocated cache. */ - ath12k_arvif_put_cache(arvif); - return; - } - - ar = arvif->ar; - ab = ar->ab; - - cancel_delayed_work_sync(&arvif->connection_loss_work); - - mutex_lock(&ar->conf_mutex); - - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n", - arvif->vdev_id); + ath12k_ahvif_put_link_cache(ahvif, link_id); + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || !arvif->is_created) + continue; - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { - ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr); - if (ret) - ath12k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n", - arvif->vdev_id, ret); + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } - - ath12k_mac_vdev_delete(ar, vif); - - mutex_unlock(&ar->conf_mutex); } /* FIXME: Has to be verified. */ @@ -6937,7 +7382,7 @@ static void ath12k_mac_configure_filter(struct ath12k *ar, bool reset_flag; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ar->filter_flags = total_flags; @@ -6962,14 +7407,12 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - ar = ath12k_ah_to_ar(ah, 0); + lockdep_assert_wiphy(hw->wiphy); - mutex_lock(&ar->conf_mutex); + ar = ath12k_ah_to_ar(ah, 0); *total_flags &= SUPPORTED_FILTERS; ath12k_mac_configure_filter(ar, *total_flags); - - mutex_unlock(&ar->conf_mutex); } static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) @@ -6979,11 +7422,11 @@ static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 * struct ath12k *ar; int i; + lockdep_assert_wiphy(hw->wiphy); + for_each_ar(ah, ar, i) { - mutex_lock(&ar->conf_mutex); antennas_rx = max_t(u32, antennas_rx, ar->cfg_rx_chainmask); antennas_tx = max_t(u32, antennas_tx, ar->cfg_tx_chainmask); - mutex_unlock(&ar->conf_mutex); } *tx_ant = antennas_tx; @@ -6999,10 +7442,10 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx int ret = 0; int i; + lockdep_assert_wiphy(hw->wiphy); + for_each_ar(ah, ar, i) { - mutex_lock(&ar->conf_mutex); ret = __ath12k_set_antenna(ar, tx_ant, rx_ant); - mutex_unlock(&ar->conf_mutex); if (ret) break; } @@ -7010,13 +7453,13 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx return ret; } -static int ath12k_mac_ampdu_action(struct ath12k_vif *arvif, +static int ath12k_mac_ampdu_action(struct ath12k_link_vif *arvif, struct ieee80211_ampdu_params *params) { struct ath12k *ar = arvif->ar; int ret = -EINVAL; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); switch (params->action) { case IEEE80211_AMPDU_RX_START: @@ -7046,19 +7489,20 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; int ret = -EINVAL; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_vif(hw, vif); if (!ar) return -EINVAL; ar = ath12k_ah_to_ar(ah, 0); + arvif = &ahvif->deflink; - mutex_lock(&ar->conf_mutex); ret = ath12k_mac_ampdu_action(arvif, params); - mutex_unlock(&ar->conf_mutex); - if (ret) ath12k_warn(ar->ab, "pdev idx %d unable to perform ampdu action %d ret %d\n", ar->pdev_idx, params->action, ret); @@ -7072,6 +7516,8 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ath12k *ar; struct ath12k_base *ab; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_ctx(hw, ctx); if (!ar) return -EINVAL; @@ -7082,8 +7528,6 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, "mac chanctx add freq %u width %d ptr %p\n", ctx->def.chan->center_freq, ctx->def.width, ctx); - mutex_lock(&ar->conf_mutex); - spin_lock_bh(&ar->data_lock); /* TODO: In case of multiple channel context, populate rx_channel from * Rx PPDU desc information. @@ -7091,8 +7535,6 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, ar->rx_channel = ctx->def.chan; spin_unlock_bh(&ar->data_lock); - mutex_unlock(&ar->conf_mutex); - return 0; } @@ -7102,6 +7544,8 @@ static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw, struct ath12k *ar; struct ath12k_base *ab; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_ctx(hw, ctx); if (!ar) return; @@ -7112,16 +7556,12 @@ static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw, "mac chanctx remove freq %u width %d ptr %p\n", ctx->def.chan->center_freq, ctx->def.width, ctx); - mutex_lock(&ar->conf_mutex); - spin_lock_bh(&ar->data_lock); /* TODO: In case of there is one more channel context left, populate * rx_channel with the channel of that remaining channel context. */ ar->rx_channel = NULL; spin_unlock_bh(&ar->data_lock); - - mutex_unlock(&ar->conf_mutex); } static enum wmi_phy_mode @@ -7188,7 +7628,7 @@ ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar, } static int -ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, +ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, struct ieee80211_chanctx_conf *ctx, bool restart) { @@ -7196,10 +7636,11 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, struct ath12k_base *ab = ar->ab; struct wmi_vdev_start_req_arg arg = {}; const struct cfg80211_chan_def *chandef = &ctx->def; - int he_support = arvif->vif->bss_conf.he_support; + struct ath12k_vif *ahvif = arvif->ahvif; + int he_support = ahvif->vif->bss_conf.he_support; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->vdev_setup_done); @@ -7215,7 +7656,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, arg.mode = ath12k_mac_check_down_grade_phy_mode(ar, arg.mode, chandef->chan->band, - arvif->vif->type); + ahvif->vif->type); arg.min_power = 0; arg.max_power = chandef->chan->max_power * 2; arg.max_reg_power = chandef->chan->max_reg_power * 2; @@ -7235,10 +7676,10 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, return ret; } - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { - arg.ssid = arvif->u.ap.ssid; - arg.ssid_len = arvif->u.ap.ssid_len; - arg.hidden_ssid = arvif->u.ap.hidden_ssid; + if (ahvif->vdev_type == WMI_VDEV_TYPE_AP) { + arg.ssid = ahvif->u.ap.ssid; + arg.ssid_len = ahvif->u.ap.ssid_len; + arg.hidden_ssid = ahvif->u.ap.hidden_ssid; /* For now allow DFS for AP mode */ arg.chan_radar = !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); @@ -7285,7 +7726,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, ar->num_started_vdevs++; ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM started, vdev_id %d\n", - arvif->vif->addr, arvif->vdev_id); + ahvif->vif->addr, arvif->vdev_id); /* Enable CAC Flag in the driver by checking the channel DFS cac time, * i.e dfs_cac_ms value which will be valid only for radar channels @@ -7294,7 +7735,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, * during CAC. */ /* TODO: Set the flag for other interface types as required */ - if (arvif->vdev_type == WMI_VDEV_TYPE_AP && + if (arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP && chandef->chan->dfs_cac_ms && chandef->chan->dfs_state == NL80211_DFS_USABLE) { set_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); @@ -7311,13 +7752,13 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, return 0; } -static int ath12k_mac_vdev_start(struct ath12k_vif *arvif, +static int ath12k_mac_vdev_start(struct ath12k_link_vif *arvif, struct ieee80211_chanctx_conf *ctx) { return ath12k_mac_vdev_start_restart(arvif, ctx, false); } -static int ath12k_mac_vdev_restart(struct ath12k_vif *arvif, +static int ath12k_mac_vdev_restart(struct ath12k_link_vif *arvif, struct ieee80211_chanctx_conf *ctx) { return ath12k_mac_vdev_start_restart(arvif, ctx, true); @@ -7335,8 +7776,13 @@ static void ath12k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_mac_change_chanctx_arg *arg = data; + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(ahvif->ah->hw->wiphy); + + arvif = &ahvif->deflink; if (arvif->ar != arg->ar) return; @@ -7351,9 +7797,14 @@ static void ath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_mac_change_chanctx_arg *arg = data; struct ieee80211_chanctx_conf *ctx; + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(ahvif->ah->hw->wiphy); + + arvif = &ahvif->deflink; if (arvif->ar != arg->ar) return; @@ -7397,13 +7848,13 @@ static u32 ath12k_mac_nlwidth_to_wmiwidth(enum nl80211_chan_width width) } static int ath12k_mac_update_peer_puncturing_width(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct cfg80211_chan_def def) { u32 param_id, param_value; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA) return 0; param_id = WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP; @@ -7429,17 +7880,19 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, { struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_base *ab = ar->ab; + struct ath12k_link_vif *arvif; struct ieee80211_vif *vif; - struct ath12k_vif *arvif; + struct ath12k_vif *ahvif; int ret; int i; bool monitor_vif = false; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); for (i = 0; i < n_vifs; i++) { vif = vifs[i].vif; - arvif = ath12k_vif_to_arvif(vif); + ahvif = ath12k_vif_to_ahvif(vif); + arvif = &ahvif->deflink; if (vif->type == NL80211_IFTYPE_MONITOR) monitor_vif = true; @@ -7489,10 +7942,14 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, memset(¶ms, 0, sizeof(params)); params.vdev_id = arvif->vdev_id; - params.aid = arvif->aid; + params.aid = ahvif->aid; params.bssid = arvif->bssid; if (vif->mbssid_tx_vif) { - params.tx_bssid = ath12k_vif_to_arvif(vif->mbssid_tx_vif)->bssid; + struct ath12k_vif *ahvif = + ath12k_vif_to_ahvif(vif->mbssid_tx_vif); + struct ath12k_link_vif *arvif = &ahvif->deflink; + + params.tx_bssid = arvif->bssid; params.nontx_profile_idx = vif->bss_conf.bssid_index; params.nontx_profile_cnt = 1 << vif->bss_conf.bssid_indicator; } @@ -7528,7 +7985,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar, struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx, .ar = ar }; struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_NORMAL, @@ -7558,14 +8015,14 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, struct ath12k *ar; struct ath12k_base *ab; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_ctx(hw, ctx); if (!ar) return; ab = ar->ab; - mutex_lock(&ar->conf_mutex); - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx change freq %u width %d ptr %p changed %x\n", ctx->def.chan->center_freq, ctx->def.width, ctx, changed); @@ -7574,7 +8031,7 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, * switch_vif_chanctx(). */ if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) - goto unlock; + return; if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH || changed & IEEE80211_CHANCTX_CHANGE_RADAR || @@ -7582,16 +8039,14 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, ath12k_mac_update_active_vif_chan(ar, ctx); /* TODO: Recalc radar detection */ - -unlock: - mutex_unlock(&ar->conf_mutex); } static int ath12k_start_vdev_delay(struct ath12k *ar, - struct ath12k_vif *arvif) + struct ath12k_link_vif *arvif) { struct ath12k_base *ab = ar->ab; - struct ieee80211_vif *vif = arvif->vif; + struct ath12k_vif *ahvif = arvif->ahvif; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); int ret; if (WARN_ON(arvif->is_started)) @@ -7605,7 +8060,7 @@ static int ath12k_start_vdev_delay(struct ath12k *ar, return ret; } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath12k_monitor_vdev_up(ar, arvif->vdev_id); if (ret) { ath12k_warn(ab, "failed put monitor up: %d\n", ret); @@ -7625,24 +8080,37 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + u8 link_id = link_conf->link_id; + struct ath12k_link_vif *arvif; int ret; + lockdep_assert_wiphy(hw->wiphy); + /* For multi radio wiphy, the vdev was not created during add_interface * create now since we have a channel ctx now to assign to a specific ar/fw */ - ar = ath12k_mac_assign_vif_to_vdev(hw, vif, ctx); - if (!ar) { + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + if (!arvif) { WARN_ON(1); + return -ENOMEM; + } + + if (!arvif->is_started) { + ar = ath12k_mac_assign_vif_to_vdev(hw, arvif, ctx); + if (!ar) + return -EINVAL; + } else { + ath12k_warn(arvif->ar->ab, "failed to assign chanctx for vif %pM link id %u link vif is already started", + vif->addr, link_id); return -EINVAL; } ab = ar->ab; - mutex_lock(&ar->conf_mutex); - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx assign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); @@ -7651,8 +8119,8 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, /* for some targets bss peer must be created before vdev_start */ if (ab->hw_params->vdev_start_delay && - arvif->vdev_type != WMI_VDEV_TYPE_AP && - arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && + ahvif->vdev_type != WMI_VDEV_TYPE_AP && + ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR && !ath12k_peer_exist_by_vdev_id(ab, arvif->vdev_id)) { memcpy(&arvif->chanctx, ctx, sizeof(*ctx)); ret = 0; @@ -7664,10 +8132,11 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath12k_mac_monitor_start(ar); if (ret) goto out; + arvif->is_started = true; goto out; } @@ -7680,7 +8149,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, goto out; } - if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created) + if (ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created) ath12k_mac_monitor_start(ar); arvif->is_started = true; @@ -7688,8 +8157,6 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, /* TODO: Setup ps and cts/rts protection */ out: - mutex_unlock(&ar->conf_mutex); - return ret; } @@ -7701,9 +8168,15 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, { struct ath12k *ar; struct ath12k_base *ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; + u8 link_id = link_conf->link_id; int ret; + lockdep_assert_wiphy(hw->wiphy); + + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + /* The vif is expected to be attached to an ar's VDEV. * We leave the vif/vdev in this function as is * and not delete the vdev symmetric to assign_vif_chanctx() @@ -7711,32 +8184,28 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, * remove_interface() or when there is a change in channel * that moves the vif to a new ar */ - if (!arvif->is_created) + if (!arvif || !arvif->is_created) return; ar = arvif->ar; ab = ar->ab; - mutex_lock(&ar->conf_mutex); - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx unassign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); WARN_ON(!arvif->is_started); - if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath12k_mac_monitor_stop(ar); - if (ret) { - mutex_unlock(&ar->conf_mutex); + if (ret) return; - } arvif->is_started = false; } - if (arvif->vdev_type != WMI_VDEV_TYPE_STA && - arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA && + ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { ath12k_bss_disassoc(ar, arvif); ret = ath12k_mac_vdev_stop(arvif); if (ret) @@ -7745,11 +8214,12 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, } arvif->is_started = false; - if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && + if (ahvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->num_started_vdevs == 1 && ar->monitor_vdev_created) ath12k_mac_monitor_stop(ar); - mutex_unlock(&ar->conf_mutex); + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } static int @@ -7760,35 +8230,32 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, { struct ath12k *ar; + lockdep_assert_wiphy(hw->wiphy); + ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx); if (!ar) return -EINVAL; - mutex_lock(&ar->conf_mutex); - /* Switching channels across radio is not allowed */ - if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) { - mutex_unlock(&ar->conf_mutex); + if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) return -EINVAL; - } ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac chanctx switch n_vifs %d mode %d\n", n_vifs, mode); ath12k_mac_update_vif_chan(ar, vifs, n_vifs); - mutex_unlock(&ar->conf_mutex); - return 0; } static int ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret = 0; - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + list_for_each_entry(arvif, &ar->arvifs, list) { ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "setting mac vdev %d param %d value %d\n", param, arvif->vdev_id, value); @@ -7801,7 +8268,7 @@ ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value) break; } } - mutex_unlock(&ar->conf_mutex); + return ret; } @@ -7814,6 +8281,8 @@ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) struct ath12k *ar; int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret = 0, i; + lockdep_assert_wiphy(hw->wiphy); + /* Currently we set the rts threshold value to all the vifs across * all radios of the single wiphy. * TODO Once support for vif specific RTS threshold in mac80211 is @@ -7843,6 +8312,9 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) * supported. This effectively prevents mac80211 from doing frame * fragmentation in software. */ + + lockdep_assert_wiphy(hw->wiphy); + return -EOPNOTSUPP; } @@ -7887,6 +8359,8 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v struct ath12k *ar; int i; + lockdep_assert_wiphy(hw->wiphy); + if (drop) return; @@ -8020,14 +8494,14 @@ ath12k_mac_get_single_legacy_rate(struct ath12k *ar, return 0; } -static int ath12k_mac_set_fixed_rate_params(struct ath12k_vif *arvif, +static int ath12k_mac_set_fixed_rate_params(struct ath12k_link_vif *arvif, u32 rate, u8 nss, u8 sgi, u8 ldpc) { struct ath12k *ar = arvif->ar; u32 vdev_param; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n", arvif->vdev_id, rate, nss, sgi); @@ -8099,8 +8573,9 @@ ath12k_mac_vht_mcs_range_present(struct ath12k *ar, static void ath12k_mac_set_bitrate_mask_iter(void *data, struct ieee80211_sta *sta) { - struct ath12k_vif *arvif = data; - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); + struct ath12k_link_vif *arvif = data; + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + struct ath12k_link_sta *arsta = &ahsta->deflink; struct ath12k *ar = arvif->ar; if (arsta->arvif != arvif) @@ -8110,14 +8585,15 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data, arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED; spin_unlock_bh(&ar->data_lock); - ieee80211_queue_work(ath12k_ar_to_hw(ar), &arsta->update_wk); + wiphy_work_queue(ath12k_ar_to_hw(ar)->wiphy, &arsta->update_wk); } static void ath12k_mac_disable_peer_fixed_rate(void *data, struct ieee80211_sta *sta) { - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); - struct ath12k_vif *arvif = data; + struct ath12k_link_vif *arvif = data; + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + struct ath12k_link_sta *arsta = &ahsta->deflink; struct ath12k *ar = arvif->ar; int ret; @@ -8139,9 +8615,10 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct cfg80211_bitrate_mask *mask) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_link_vif *arvif; struct cfg80211_chan_def def; - struct ath12k *ar = arvif->ar; + struct ath12k *ar; enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; @@ -8153,8 +8630,15 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, int ret; int num_rates; - if (ath12k_mac_vif_chan(vif, &def)) - return -EPERM; + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + + ar = arvif->ar; + if (ath12k_mac_vif_link_chan(vif, arvif->link_id, &def)) { + ret = -EPERM; + goto out; + } band = def.chan->band; ht_mcs_mask = mask->control[band].ht_mcs; @@ -8183,9 +8667,9 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto out; } - ieee80211_iterate_stations_atomic(hw, - ath12k_mac_disable_peer_fixed_rate, - arvif); + ieee80211_iterate_stations_mtx(hw, + ath12k_mac_disable_peer_fixed_rate, + arvif); } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask, &single_nss)) { rate = WMI_FIXED_RATE_NONE; @@ -8226,34 +8710,25 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, */ ath12k_warn(ar->ab, "Setting more than one MCS Value in bitrate mask not supported\n"); - ret = -EINVAL; - goto out; + return -EINVAL; } - ieee80211_iterate_stations_atomic(hw, - ath12k_mac_disable_peer_fixed_rate, - arvif); - - mutex_lock(&ar->conf_mutex); + ieee80211_iterate_stations_mtx(hw, + ath12k_mac_disable_peer_fixed_rate, + arvif); arvif->bitrate_mask = *mask; - ieee80211_iterate_stations_atomic(hw, - ath12k_mac_set_bitrate_mask_iter, - arvif); - - mutex_unlock(&ar->conf_mutex); + ieee80211_iterate_stations_mtx(hw, + ath12k_mac_set_bitrate_mask_iter, + arvif); } - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); if (ret) { ath12k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n", arvif->vdev_id, ret); } - mutex_unlock(&ar->conf_mutex); - out: return ret; } @@ -8265,9 +8740,12 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; - struct ath12k_vif *arvif; + struct ath12k_vif *ahvif; + struct ath12k_link_vif *arvif; int recovery_count, i; + lockdep_assert_wiphy(hw->wiphy); + if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; @@ -8280,8 +8758,6 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ieee80211_wake_queues(hw); for_each_ar(ah, ar, i) { - mutex_lock(&ar->conf_mutex); - ab = ar->ab; ath12k_warn(ar->ab, "pdev %d successfully recovered\n", @@ -8306,11 +8782,12 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, } list_for_each_entry(arvif, &ar->arvifs, list) { + ahvif = arvif->ahvif; ath12k_dbg(ab, ATH12K_DBG_BOOT, "reconfig cipher %d up %d vdev type %d\n", - arvif->key_cipher, + ahvif->key_cipher, arvif->is_up, - arvif->vdev_type); + ahvif->vdev_type); /* After trigger disconnect, then upper layer will * trigger connect again, then the PN number of @@ -8318,16 +8795,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, * side, hence PN number mismatch will not happen. */ if (arvif->is_up && - arvif->vdev_type == WMI_VDEV_TYPE_STA && - arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { - ieee80211_hw_restart_disconnect(arvif->vif); + ahvif->vdev_type == WMI_VDEV_TYPE_STA && + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { + ieee80211_hw_restart_disconnect(ahvif->vif); ath12k_dbg(ab, ATH12K_DBG_BOOT, "restart disconnect\n"); } } - - mutex_unlock(&ar->conf_mutex); } } @@ -8338,7 +8813,7 @@ ath12k_mac_update_bss_chan_survey(struct ath12k *ar, int ret; enum wmi_bss_chan_info_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (!test_bit(WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64, ar->ab->wmi_ab.svc_map) || ar->rx_channel != channel) @@ -8370,6 +8845,8 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, struct ieee80211_supported_band *sband; struct survey_info *ar_survey; + lockdep_assert_wiphy(hw->wiphy); + if (idx >= ATH12K_NUM_CHANS) return -ENOENT; @@ -8403,8 +8880,6 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, ar_survey = &ar->survey[idx]; - mutex_lock(&ar->conf_mutex); - ath12k_mac_update_bss_chan_survey(ar, &sband->channels[idx]); spin_lock_bh(&ar->data_lock); @@ -8416,7 +8891,6 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, if (ar->rx_channel == survey->channel) survey->filled |= SURVEY_INFO_IN_USE; - mutex_unlock(&ar->conf_mutex); return 0; } @@ -8425,7 +8899,12 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct station_info *sinfo) { - struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); + struct ath12k_link_sta *arsta; + + lockdep_assert_wiphy(hw->wiphy); + + arsta = &ahsta->deflink; sinfo->rx_duration = arsta->rx_duration; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); @@ -8462,7 +8941,7 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, ar = ath12k_ah_to_ar(ah, 0); - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); spin_lock_bh(&ar->data_lock); ar->scan.roc_notify = false; @@ -8470,8 +8949,6 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, ath12k_scan_abort(ar); - mutex_unlock(&ar->conf_mutex); - cancel_delayed_work_sync(&ar->scan.timeout); return 0; @@ -8483,24 +8960,31 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, int duration, enum ieee80211_roc_type type) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k_wmi_scan_req_arg arg; - struct ath12k *ar, *prev_ar; + struct ath12k_link_vif *arvif; + struct ath12k *ar; u32 scan_time_msec; bool create = true; + u8 link_id; int ret; - if (ah->num_radio == 1) { - WARN_ON(!arvif->is_created); - ar = ath12k_ah_to_ar(ah, 0); - goto scan; - } + lockdep_assert_wiphy(hw->wiphy); ar = ath12k_mac_select_scan_device(hw, vif, chan->center_freq); - if (!ar) - return -EINVAL; + if (!ar) { + ret = -EINVAL; + goto exit; + } + /* check if any of the links of ML VIF is already started on + * radio(ar) correpsondig to given scan frequency and use it, + * if not use deflink(link 0) for scan purpose. + */ + + link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar); + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); /* If the vif is already assigned to a specific vdev of an ar, * check whether its already started, vdev which is started * are not allowed to switch to a new radio. @@ -8511,44 +8995,35 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, * always on the same band for the vif */ if (arvif->is_created) { - if (WARN_ON(!arvif->ar)) - return -EINVAL; + if (WARN_ON(!arvif->ar)) { + ret = -EINVAL; + goto exit; + } - if (ar != arvif->ar && arvif->is_started) - return -EBUSY; + if (ar != arvif->ar && arvif->is_started) { + ret = -EBUSY; + goto exit; + } if (ar != arvif->ar) { - /* backup the previously used ar ptr, since the vdev delete - * would assign the arvif->ar to NULL after the call - */ - prev_ar = arvif->ar; - mutex_lock(&prev_ar->conf_mutex); - ret = ath12k_mac_vdev_delete(prev_ar, vif); - mutex_unlock(&prev_ar->conf_mutex); - if (ret) { - ath12k_warn(prev_ar->ab, - "unable to delete scan vdev for roc: %d\n", - ret); - return ret; - } + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); } else { create = false; } } if (create) { - mutex_lock(&ar->conf_mutex); - ret = ath12k_mac_vdev_create(ar, vif); - mutex_unlock(&ar->conf_mutex); + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); + + ret = ath12k_mac_vdev_create(ar, arvif); if (ret) { ath12k_warn(ar->ab, "unable to create scan vdev for roc: %d\n", ret); - return -EINVAL; + goto exit; } } -scan: - mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); switch (ar->scan.state) { @@ -8623,9 +9098,8 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, free_chan_list: kfree(arg.chan_list); -exit: - mutex_unlock(&ar->conf_mutex); +exit: return ret; } @@ -8633,16 +9107,20 @@ static void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *data) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_rekey_data *rekey_data = &arvif->rekey_data; + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ath12k_rekey_data *rekey_data; struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar = ath12k_ah_to_ar(ah, 0); + struct ath12k_link_vif *arvif; + + lockdep_assert_wiphy(hw->wiphy); + + arvif = &ahvif->deflink; + rekey_data = &arvif->rekey_data; ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set rekey data vdev %d\n", arvif->vdev_id); - mutex_lock(&ar->conf_mutex); - memcpy(rekey_data->kck, data->kck, NL80211_KCK_LEN); memcpy(rekey_data->kek, data->kek, NL80211_KEK_LEN); @@ -8659,8 +9137,6 @@ static void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw, rekey_data->kck, NL80211_KEK_LEN); ath12k_dbg_dump(ar->ab, ATH12K_DBG_MAC, "replay ctr", NULL, &rekey_data->replay_ctr, sizeof(rekey_data->replay_ctr)); - - mutex_unlock(&ar->conf_mutex); } static const struct ieee80211_ops ath12k_ops = { @@ -8673,7 +9149,9 @@ static const struct ieee80211_ops ath12k_ops = { .remove_interface = ath12k_mac_op_remove_interface, .update_vif_offload = ath12k_mac_op_update_vif_offload, .config = ath12k_mac_op_config, - .bss_info_changed = ath12k_mac_op_bss_info_changed, + .link_info_changed = ath12k_mac_op_link_info_changed, + .vif_cfg_changed = ath12k_mac_op_vif_cfg_changed, + .change_vif_links = ath12k_mac_op_change_vif_links, .configure_filter = ath12k_mac_op_configure_filter, .hw_scan = ath12k_mac_op_hw_scan, .cancel_hw_scan = ath12k_mac_op_cancel_hw_scan, @@ -8681,7 +9159,7 @@ static const struct ieee80211_ops ath12k_ops = { .set_rekey_data = ath12k_mac_op_set_rekey_data, .sta_state = ath12k_mac_op_sta_state, .sta_set_txpwr = ath12k_mac_op_sta_set_txpwr, - .sta_rc_update = ath12k_mac_op_sta_rc_update, + .link_sta_rc_update = ath12k_mac_op_sta_rc_update, .conf_tx = ath12k_mac_op_conf_tx, .set_antenna = ath12k_mac_op_set_antenna, .get_antenna = ath12k_mac_op_get_antenna, @@ -9320,7 +9798,7 @@ static void ath12k_mac_setup(struct ath12k *ar) spin_lock_init(&ar->data_lock); INIT_LIST_HEAD(&ar->arvifs); INIT_LIST_HEAD(&ar->ppdu_stats_info); - mutex_init(&ar->conf_mutex); + init_completion(&ar->vdev_setup_done); init_completion(&ar->vdev_delete_done); init_completion(&ar->peer_assoc_done); @@ -9501,7 +9979,7 @@ int ath12k_mac_allocate(struct ath12k_base *ab) return ret; } -int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, +int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval) { @@ -9509,9 +9987,9 @@ int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, struct ath12k *ar = arvif->ar; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA) return 0; if (!test_bit(WMI_TLV_SERVICE_STA_KEEP_ALIVE, ar->ab->wmi_ab.svc_map)) diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 5efbb6822628f7..d382337ba64986 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -41,6 +41,9 @@ struct ath12k_generic_iter { #define ATH12K_TX_POWER_MAX_VAL 70 #define ATH12K_TX_POWER_MIN_VAL 0 +#define ATH12K_DEFAULT_LINK_ID 0 +#define ATH12K_INVALID_LINK_ID 255 + enum ath12k_supported_bw { ATH12K_BW_20 = 0, ATH12K_BW_40 = 1, @@ -65,9 +68,9 @@ u8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, void __ath12k_mac_scan_finish(struct ath12k *ar); void ath12k_mac_scan_finish(struct ath12k *ar); -struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id); -struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, - u32 vdev_id); +struct ath12k_link_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id); +struct ath12k_link_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, + u32 vdev_id); struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id); struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id); @@ -82,7 +85,7 @@ int ath12k_mac_rfkill_config(struct ath12k *ar); int ath12k_mac_wait_tx_complete(struct ath12k *ar); void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb); void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id); -int ath12k_mac_vif_set_keepalive(struct ath12k_vif *arvif, +int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval); u8 ath12k_mac_get_target_pdev_id(struct ath12k *ar); diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index df96b0f91f54c1..2f6d14382ed70c 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -649,3 +649,8 @@ void ath12k_mhi_resume(struct ath12k_pci *ab_pci) { ath12k_mhi_set_state(ab_pci, ATH12K_MHI_RESUME); } + +void ath12k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic) +{ + mhi_download_rddm_image(mhi_ctrl, in_panic); +} diff --git a/drivers/net/wireless/ath/ath12k/mhi.h b/drivers/net/wireless/ath/ath12k/mhi.h index 9362ad1958c3a7..7358b8477536a6 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.h +++ b/drivers/net/wireless/ath/ath12k/mhi.h @@ -43,5 +43,5 @@ void ath12k_mhi_clear_vector(struct ath12k_base *ab); void ath12k_mhi_suspend(struct ath12k_pci *ar_pci); void ath12k_mhi_resume(struct ath12k_pci *ar_pci); - +void ath12k_mhi_coredump(struct mhi_controller *mhi_ctrl, bool in_panic); #endif diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c index 3a851ee15b2f17..84cccf7d91e72b 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.c +++ b/drivers/net/wireless/ath/ath12k/p2p.c @@ -69,20 +69,20 @@ static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info return len; } -static void ath12k_p2p_noa_ie_assign(struct ath12k_vif *arvif, void *ie, +static void ath12k_p2p_noa_ie_assign(struct ath12k_link_vif *arvif, void *ie, size_t len) { struct ath12k *ar = arvif->ar; lockdep_assert_held(&ar->data_lock); - kfree(arvif->u.ap.noa_data); + kfree(arvif->ahvif->u.ap.noa_data); - arvif->u.ap.noa_data = ie; - arvif->u.ap.noa_len = len; + arvif->ahvif->u.ap.noa_data = ie; + arvif->ahvif->u.ap.noa_len = len; } -static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif, +static void __ath12k_p2p_noa_update(struct ath12k_link_vif *arvif, const struct ath12k_wmi_p2p_noa_info *noa) { struct ath12k *ar = arvif->ar; @@ -105,7 +105,7 @@ static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif, ath12k_p2p_noa_ie_assign(arvif, ie, len); } -void ath12k_p2p_noa_update(struct ath12k_vif *arvif, +void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif, const struct ath12k_wmi_p2p_noa_info *noa) { struct ath12k *ar = arvif->ar; @@ -118,9 +118,12 @@ void ath12k_p2p_noa_update(struct ath12k_vif *arvif, static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_p2p_noa_arg *arg = data; + struct ath12k_link_vif *arvif; + WARN_ON(!rcu_read_lock_any_held()); + arvif = &ahvif->deflink; if (arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id) return; diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h index b2eec51a9900be..03ee877e6d6b72 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.h +++ b/drivers/net/wireless/ath/ath12k/p2p.h @@ -16,7 +16,7 @@ struct ath12k_p2p_noa_arg { const struct ath12k_wmi_p2p_noa_info *noa; }; -void ath12k_p2p_noa_update(struct ath12k_vif *arvif, +void ath12k_p2p_noa_update(struct ath12k_link_vif *arvif, const struct ath12k_wmi_p2p_noa_info *noa); void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, const struct ath12k_wmi_p2p_noa_info *noa); diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index bd269aa1740bcd..cf907550e6a4af 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "pci.h" #include "core.h" @@ -425,9 +427,9 @@ static void ath12k_pci_sync_ce_irqs(struct ath12k_base *ab) } } -static void ath12k_pci_ce_tasklet(struct tasklet_struct *t) +static void ath12k_pci_ce_workqueue(struct work_struct *work) { - struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); + struct ath12k_ce_pipe *ce_pipe = from_work(ce_pipe, work, intr_wq); int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); @@ -449,7 +451,7 @@ static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg) disable_irq_nosync(ab->irq_num[irq_idx]); - tasklet_schedule(&ce_pipe->intr_tq); + queue_work(system_bh_wq, &ce_pipe->intr_wq); return IRQ_HANDLED; } @@ -675,7 +677,7 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab) irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i; - tasklet_setup(&ce_pipe->intr_tq, ath12k_pci_ce_tasklet); + INIT_WORK(&ce_pipe->intr_wq, ath12k_pci_ce_workqueue); ret = request_irq(irq, ath12k_pci_ce_interrupt_handler, ab_pci->irq_flags, irq_name[irq_idx], @@ -962,7 +964,7 @@ static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci) PCI_EXP_LNKCTL_ASPMC); } -static void ath12k_pci_kill_tasklets(struct ath12k_base *ab) +static void ath12k_pci_cancel_workqueue(struct ath12k_base *ab) { int i; @@ -972,7 +974,7 @@ static void ath12k_pci_kill_tasklets(struct ath12k_base *ab) if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue; - tasklet_kill(&ce_pipe->intr_tq); + cancel_work_sync(&ce_pipe->intr_wq); } } @@ -980,7 +982,7 @@ static void ath12k_pci_ce_irq_disable_sync(struct ath12k_base *ab) { ath12k_pci_ce_irqs_disable(ab); ath12k_pci_sync_ce_irqs(ab); - ath12k_pci_kill_tasklets(ab); + ath12k_pci_cancel_workqueue(ab); } int ath12k_pci_map_service_to_pipe(struct ath12k_base *ab, u16 service_id, @@ -1259,6 +1261,186 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value) ab_pci->pci_ops->release(ab); } +#ifdef CONFIG_ATH12K_COREDUMP +static int ath12k_pci_coredump_calculate_size(struct ath12k_base *ab, u32 *dump_seg_sz) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl; + struct image_info *rddm_img, *fw_img; + struct ath12k_tlv_dump_data *dump_tlv; + enum ath12k_fw_crash_dump_type mem_type; + u32 len = 0, rddm_tlv_sz = 0, paging_tlv_sz = 0; + struct ath12k_dump_file_data *file_data; + int i; + + rddm_img = mhi_ctrl->rddm_image; + if (!rddm_img) { + ath12k_err(ab, "No RDDM dump found\n"); + return 0; + } + + fw_img = mhi_ctrl->fbc_image; + + for (i = 0; i < fw_img->entries ; i++) { + if (!fw_img->mhi_buf[i].buf) + continue; + + paging_tlv_sz += fw_img->mhi_buf[i].len; + } + dump_seg_sz[FW_CRASH_DUMP_PAGING_DATA] = paging_tlv_sz; + + for (i = 0; i < rddm_img->entries; i++) { + if (!rddm_img->mhi_buf[i].buf) + continue; + + rddm_tlv_sz += rddm_img->mhi_buf[i].len; + } + dump_seg_sz[FW_CRASH_DUMP_RDDM_DATA] = rddm_tlv_sz; + + for (i = 0; i < ab->qmi.mem_seg_count; i++) { + mem_type = ath12k_coredump_get_dump_type(ab->qmi.target_mem[i].type); + + if (mem_type == FW_CRASH_DUMP_NONE) + continue; + + if (mem_type == FW_CRASH_DUMP_TYPE_MAX) { + ath12k_dbg(ab, ATH12K_DBG_PCI, + "target mem region type %d not supported", + ab->qmi.target_mem[i].type); + continue; + } + + if (!ab->qmi.target_mem[i].paddr) + continue; + + dump_seg_sz[mem_type] += ab->qmi.target_mem[i].size; + } + + for (i = 0; i < FW_CRASH_DUMP_TYPE_MAX; i++) { + if (!dump_seg_sz[i]) + continue; + + len += sizeof(*dump_tlv) + dump_seg_sz[i]; + } + + if (len) + len += sizeof(*file_data); + + return len; +} + +static void ath12k_pci_coredump_download(struct ath12k_base *ab) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl; + struct image_info *rddm_img, *fw_img; + struct timespec64 timestamp; + int i, len, mem_idx; + enum ath12k_fw_crash_dump_type mem_type; + struct ath12k_dump_file_data *file_data; + struct ath12k_tlv_dump_data *dump_tlv; + size_t hdr_len = sizeof(*file_data); + void *buf; + u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = { 0 }; + + ath12k_mhi_coredump(mhi_ctrl, false); + + len = ath12k_pci_coredump_calculate_size(ab, dump_seg_sz); + if (!len) { + ath12k_warn(ab, "No crash dump data found for devcoredump"); + return; + } + + rddm_img = mhi_ctrl->rddm_image; + fw_img = mhi_ctrl->fbc_image; + + /* dev_coredumpv() requires vmalloc data */ + buf = vzalloc(len); + if (!buf) + return; + + ab->dump_data = buf; + ab->ath12k_coredump_len = len; + file_data = ab->dump_data; + strscpy(file_data->df_magic, "ATH12K-FW-DUMP", sizeof(file_data->df_magic)); + file_data->len = cpu_to_le32(len); + file_data->version = cpu_to_le32(ATH12K_FW_CRASH_DUMP_V2); + file_data->chip_id = cpu_to_le32(ab_pci->dev_id); + file_data->qrtr_id = cpu_to_le32(ab_pci->ab->qmi.service_ins_id); + file_data->bus_id = cpu_to_le32(pci_domain_nr(ab_pci->pdev->bus)); + guid_gen(&file_data->guid); + ktime_get_real_ts64(×tamp); + file_data->tv_sec = cpu_to_le64(timestamp.tv_sec); + file_data->tv_nsec = cpu_to_le64(timestamp.tv_nsec); + buf += hdr_len; + dump_tlv = buf; + dump_tlv->type = cpu_to_le32(FW_CRASH_DUMP_PAGING_DATA); + dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[FW_CRASH_DUMP_PAGING_DATA]); + buf += COREDUMP_TLV_HDR_SIZE; + + /* append all segments together as they are all part of a single contiguous + * block of memory + */ + for (i = 0; i < fw_img->entries ; i++) { + if (!fw_img->mhi_buf[i].buf) + continue; + + memcpy_fromio(buf, (void const __iomem *)fw_img->mhi_buf[i].buf, + fw_img->mhi_buf[i].len); + buf += fw_img->mhi_buf[i].len; + } + + dump_tlv = buf; + dump_tlv->type = cpu_to_le32(FW_CRASH_DUMP_RDDM_DATA); + dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[FW_CRASH_DUMP_RDDM_DATA]); + buf += COREDUMP_TLV_HDR_SIZE; + + /* append all segments together as they are all part of a single contiguous + * block of memory + */ + for (i = 0; i < rddm_img->entries; i++) { + if (!rddm_img->mhi_buf[i].buf) + continue; + + memcpy_fromio(buf, (void const __iomem *)rddm_img->mhi_buf[i].buf, + rddm_img->mhi_buf[i].len); + buf += rddm_img->mhi_buf[i].len; + } + + mem_idx = FW_CRASH_DUMP_REMOTE_MEM_DATA; + for (; mem_idx < FW_CRASH_DUMP_TYPE_MAX; mem_idx++) { + if (!dump_seg_sz[mem_idx] || mem_idx == FW_CRASH_DUMP_NONE) + continue; + + dump_tlv = buf; + dump_tlv->type = cpu_to_le32(mem_idx); + dump_tlv->tlv_len = cpu_to_le32(dump_seg_sz[mem_idx]); + buf += COREDUMP_TLV_HDR_SIZE; + + for (i = 0; i < ab->qmi.mem_seg_count; i++) { + mem_type = ath12k_coredump_get_dump_type + (ab->qmi.target_mem[i].type); + + if (mem_type != mem_idx) + continue; + + if (!ab->qmi.target_mem[i].paddr) { + ath12k_dbg(ab, ATH12K_DBG_PCI, + "Skipping mem region type %d", + ab->qmi.target_mem[i].type); + continue; + } + + memcpy_fromio(buf, ab->qmi.target_mem[i].v.ioaddr, + ab->qmi.target_mem[i].size); + buf += ab->qmi.target_mem[i].size; + } + } + + queue_work(ab->workqueue, &ab->dump_work); +} +#endif + int ath12k_pci_power_up(struct ath12k_base *ab) { struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); @@ -1329,6 +1511,9 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = { .ce_irq_disable = ath12k_pci_hif_ce_irq_disable, .get_ce_msi_idx = ath12k_pci_get_ce_msi_idx, .panic_handler = ath12k_pci_panic_handler, +#ifdef CONFIG_ATH12K_COREDUMP + .coredump_download = ath12k_pci_coredump_download, +#endif }; static @@ -1538,6 +1723,7 @@ static void ath12k_pci_remove(struct pci_dev *pdev) set_bit(ATH12K_FLAG_UNREGISTERING, &ab->dev_flags); cancel_work_sync(&ab->reset_work); + cancel_work_sync(&ab->dump_work); ath12k_core_deinit(ab); qmi_fail: diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c index 19c0626fbff1f2..7a62665b8af937 100644 --- a/drivers/net/wireless/ath/ath12k/peer.c +++ b/drivers/net/wireless/ath/ath12k/peer.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -186,7 +186,7 @@ void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id) struct ath12k_peer *peer, *tmp; struct ath12k_base *ab = ar->ab; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); spin_lock_bh(&ab->base_lock); list_for_each_entry_safe(peer, tmp, &ab->peers, list) { @@ -235,7 +235,7 @@ int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr) { int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); reinit_completion(&ar->peer_delete_done); @@ -261,14 +261,15 @@ static int ath12k_wait_for_peer_created(struct ath12k *ar, int vdev_id, const u8 return ath12k_wait_for_peer_common(ar->ab, vdev_id, addr, true); } -int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif, +int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ieee80211_sta *sta, struct ath12k_wmi_peer_create_arg *arg) { + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ath12k_peer *peer; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); if (ar->num_peers > (ar->max_num_peers - 1)) { ath12k_warn(ar->ab, @@ -326,7 +327,7 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif, peer->pdev_idx = ar->pdev_idx; peer->sta = sta; - if (arvif->vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION) { arvif->ast_hash = peer->ast_hash; arvif->ast_idx = peer->hw_peer_id; } diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h index 7b3500b5c8c20e..b955f0cdf59895 100644 --- a/drivers/net/wireless/ath/ath12k/peer.h +++ b/drivers/net/wireless/ath/ath12k/peer.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_PEER_H @@ -59,7 +59,7 @@ struct ath12k_peer *ath12k_peer_find_by_addr(struct ath12k_base *ab, struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab, int peer_id); void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id); int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr); -int ath12k_peer_create(struct ath12k *ar, struct ath12k_vif *arvif, +int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ieee80211_sta *sta, struct ath12k_wmi_peer_create_arg *arg); int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id, diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index a0db6702a189e8..10366bbe999999 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.h @@ -684,18 +684,17 @@ enum rx_msdu_start_reception_type { #define RX_MSDU_END_INFO5_SA_IDX_TIMEOUT BIT(0) #define RX_MSDU_END_INFO5_DA_IDX_TIMEOUT BIT(1) +#define RX_MSDU_END_INFO5_TO_DS BIT(2) +#define RX_MSDU_END_INFO5_TID GENMASK(6, 3) #define RX_MSDU_END_INFO5_SA_IS_VALID BIT(7) #define RX_MSDU_END_INFO5_DA_IS_VALID BIT(8) #define RX_MSDU_END_INFO5_DA_IS_MCBC BIT(9) #define RX_MSDU_END_INFO5_L3_HDR_PADDING GENMASK(11, 10) #define RX_MSDU_END_INFO5_FIRST_MSDU BIT(12) #define RX_MSDU_END_INFO5_LAST_MSDU BIT(13) +#define RX_MSDU_END_INFO5_FROM_DS BIT(14) #define RX_MSDU_END_INFO5_IP_CHKSUM_FAIL_COPY BIT(15) -#define RX_MSDU_END_QCN9274_INFO5_TO_DS BIT(2) -#define RX_MSDU_END_QCN9274_INFO5_TID GENMASK(6, 3) -#define RX_MSDU_END_QCN9274_INFO5_FROM_DS BIT(14) - #define RX_MSDU_END_INFO6_MSDU_DROP BIT(0) #define RX_MSDU_END_INFO6_REO_DEST_IND GENMASK(5, 1) #define RX_MSDU_END_INFO6_FLOW_IDX GENMASK(25, 6) @@ -709,14 +708,14 @@ enum rx_msdu_start_reception_type { #define RX_MSDU_END_INFO7_FLOW_AGGR_CONTN BIT(8) #define RX_MSDU_END_INFO7_FISA_TIMEOUT BIT(9) -#define RX_MSDU_END_QCN9274_INFO7_TCPUDP_CSUM_FAIL_CPY BIT(10) -#define RX_MSDU_END_QCN9274_INFO7_MSDU_LIMIT_ERROR BIT(11) -#define RX_MSDU_END_QCN9274_INFO7_FLOW_IDX_TIMEOUT BIT(12) -#define RX_MSDU_END_QCN9274_INFO7_FLOW_IDX_INVALID BIT(13) -#define RX_MSDU_END_QCN9274_INFO7_CCE_MATCH BIT(14) -#define RX_MSDU_END_QCN9274_INFO7_AMSDU_PARSER_ERR BIT(15) +#define RX_MSDU_END_INFO7_TCPUDP_CSUM_FAIL_CPY BIT(10) +#define RX_MSDU_END_INFO7_MSDU_LIMIT_ERROR BIT(11) +#define RX_MSDU_END_INFO7_FLOW_IDX_TIMEOUT BIT(12) +#define RX_MSDU_END_INFO7_FLOW_IDX_INVALID BIT(13) +#define RX_MSDU_END_INFO7_CCE_MATCH BIT(14) +#define RX_MSDU_END_INFO7_AMSDU_PARSER_ERR BIT(15) -#define RX_MSDU_END_QCN9274_INFO8_KEY_ID GENMASK(7, 0) +#define RX_MSDU_END_INFO8_KEY_ID GENMASK(7, 0) #define RX_MSDU_END_INFO9_SERVICE_CODE GENMASK(14, 6) #define RX_MSDU_END_INFO9_PRIORITY_VALID BIT(15) @@ -758,8 +757,8 @@ enum rx_msdu_start_reception_type { #define RX_MSDU_END_INFO12_RECV_BW GENMASK(20, 18) #define RX_MSDU_END_INFO12_RECEPTION_TYPE GENMASK(23, 21) -#define RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP GENMASK(30, 24) -#define RX_MSDU_END_QCN9274_INFO12_MIMO_DONE_COPY BIT(31) +#define RX_MSDU_END_INFO12_MIMO_SS_BITMAP GENMASK(30, 24) +#define RX_MSDU_END_INFO12_MIMO_DONE_COPY BIT(31) #define RX_MSDU_END_INFO13_FIRST_MPDU BIT(0) #define RX_MSDU_END_INFO13_MCAST_BCAST BIT(2) @@ -791,7 +790,7 @@ enum rx_msdu_start_reception_type { #define RX_MSDU_END_INFO13_UNDECRYPT_FRAME_ERR BIT(30) #define RX_MSDU_END_INFO13_FCS_ERR BIT(31) -#define RX_MSDU_END_QCN9274_INFO13_WIFI_PARSER_ERR BIT(15) +#define RX_MSDU_END_INFO13_WIFI_PARSER_ERR BIT(15) #define RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE GENMASK(12, 10) #define RX_MSDU_END_INFO14_RX_BITMAP_NOT_UPDED BIT(13) @@ -889,65 +888,6 @@ struct rx_msdu_end_qcn9274_compact { __le32 info14; } __packed; -/* These macro definitions are only used for WCN7850 */ -#define RX_MSDU_END_WCN7850_INFO2_KEY_ID BIT(7, 0) - -#define RX_MSDU_END_WCN7850_INFO5_MSDU_LIMIT_ERR BIT(2) -#define RX_MSDU_END_WCN7850_INFO5_IDX_TIMEOUT BIT(3) -#define RX_MSDU_END_WCN7850_INFO5_IDX_INVALID BIT(4) -#define RX_MSDU_END_WCN7850_INFO5_WIFI_PARSE_ERR BIT(5) -#define RX_MSDU_END_WCN7850_INFO5_AMSDU_PARSER_ERR BIT(6) -#define RX_MSDU_END_WCN7850_INFO5_TCPUDP_CSUM_FAIL_CPY BIT(14) - -#define RX_MSDU_END_WCN7850_INFO12_MIMO_SS_BITMAP GENMASK(31, 24) - -#define RX_MSDU_END_WCN7850_INFO13_FRAGMENT_FLAG BIT(13) -#define RX_MSDU_END_WCN7850_INFO13_CCE_MATCH BIT(15) - -struct rx_msdu_end_wcn7850 { - __le16 info0; - __le16 phy_ppdu_id; - __le16 ip_hdr_cksum; - __le16 info1; - __le16 info2; - __le16 cumulative_l3_checksum; - __le32 rule_indication0; - __le32 rule_indication1; - __le16 info3; - __le16 l3_type; - __le32 ipv6_options_crc; - __le32 tcp_seq_num; - __le32 tcp_ack_num; - __le16 info4; - __le16 window_size; - __le16 tcp_udp_chksum; - __le16 info5; - __le16 sa_idx; - __le16 da_idx_or_sw_peer_id; - __le32 info6; - __le32 fse_metadata; - __le16 cce_metadata; - __le16 sa_sw_peer_id; - __le16 info7; - __le16 rsvd0; - __le16 cumulative_l4_checksum; - __le16 cumulative_ip_length; - __le32 info9; - __le32 info10; - __le32 info11; - __le32 toeplitz_hash_2_or_4; - __le32 flow_id_toeplitz; - __le32 info12; - __le32 ppdu_start_timestamp_31_0; - __le32 ppdu_start_timestamp_63_32; - __le32 phy_meta_data; - __le16 vlan_ctag_ci; - __le16 vlan_stag_ci; - __le32 rsvd[3]; - __le32 info13; - __le32 info14; -} __packed; - /* rx_msdu_end * * rxpcu_mpdu_filter_in_category @@ -1578,7 +1518,7 @@ struct rx_pkt_hdr_tlv { struct hal_rx_desc_wcn7850 { __le64 msdu_end_tag; - struct rx_msdu_end_wcn7850 msdu_end; + struct rx_msdu_end_qcn9274 msdu_end; u8 rx_padding0[RX_BE_PADDING0_BYTES]; __le64 mpdu_start_tag; struct rx_mpdu_start_qcn9274 mpdu_start; diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 2cd3ff9b0164c8..dced2aa9ba1a3e 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6687,7 +6687,8 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab, const u32 *vdev_ids) { int i; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; + struct ath12k_vif *ahvif; /* Finish CSA once the switch count becomes NULL */ if (ev->current_switch_count) @@ -6702,9 +6703,10 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab, vdev_ids[i]); continue; } + ahvif = arvif->ahvif; - if (arvif->is_up && arvif->vif->bss_conf.csa_active) - ieee80211_csa_finish(arvif->vif, 0); + if (arvif->is_up && ahvif->vif->bss_conf.csa_active) + ieee80211_csa_finish(ahvif->vif, 0); } rcu_read_unlock(); } @@ -7098,7 +7100,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, struct sk_buff *skb) { const struct wmi_gtk_offload_status_event *ev; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; __be64 replay_ctr_be; u64 replay_ctr; const void **tb; @@ -7136,7 +7138,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab, /* supplicant expects big-endian replay counter */ replay_ctr_be = cpu_to_be64(replay_ctr); - ieee80211_gtk_rekey_notify(arvif->vif, arvif->bssid, + ieee80211_gtk_rekey_notify(arvif->ahvif->vif, arvif->bssid, (void *)&replay_ctr_be, GFP_ATOMIC); rcu_read_unlock(); @@ -7284,9 +7286,11 @@ static int ath12k_connect_pdev_htc_service(struct ath12k_base *ab, u32 pdev_idx) { int status; - u32 svc_id[] = { ATH12K_HTC_SVC_ID_WMI_CONTROL, - ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1, - ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2 }; + static const u32 svc_id[] = { + ATH12K_HTC_SVC_ID_WMI_CONTROL, + ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1, + ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2 + }; struct ath12k_htc_svc_conn_req conn_req = {}; struct ath12k_htc_svc_conn_resp conn_resp = {}; @@ -7372,13 +7376,13 @@ ath12k_wmi_send_unit_test_cmd(struct ath12k *ar, int ath12k_wmi_simulate_radar(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; u32 dfs_args[DFS_MAX_TEST_ARGS]; struct wmi_unit_test_cmd wmi_ut; bool arvif_found = false; list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) { + if (arvif->is_started && arvif->ahvif->vdev_type == WMI_VDEV_TYPE_AP) { arvif_found = true; break; } @@ -7940,7 +7944,7 @@ static void ath12k_wmi_fill_arp_offload(struct ath12k *ar, } int ath12k_wmi_arp_ns_offload(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct wmi_arp_ns_offload_arg *offload, bool enable) { @@ -7989,7 +7993,7 @@ int ath12k_wmi_arp_ns_offload(struct ath12k *ar, } int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, - struct ath12k_vif *arvif, bool enable) + struct ath12k_link_vif *arvif, bool enable) { struct ath12k_rekey_data *rekey_data = &arvif->rekey_data; struct wmi_gtk_rekey_offload_cmd *cmd; @@ -8026,7 +8030,7 @@ int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, } int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, - struct ath12k_vif *arvif) + struct ath12k_link_vif *arvif) { struct wmi_gtk_rekey_offload_cmd *cmd; struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 6a913f9b831580..6f55dbdf629dbe 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -24,7 +24,7 @@ struct ath12k_base; struct ath12k; -struct ath12k_vif; +struct ath12k_link_vif; /* There is no signed version of __le32, so for a temporary solution come * up with our own version. The idea is from fs/ntfs/endian.h. @@ -5627,13 +5627,13 @@ int ath12k_wmi_wow_config_pno(struct ath12k *ar, u32 vdev_id, int ath12k_wmi_hw_data_filter_cmd(struct ath12k *ar, struct wmi_hw_data_filter_arg *arg); int ath12k_wmi_arp_ns_offload(struct ath12k *ar, - struct ath12k_vif *arvif, + struct ath12k_link_vif *arvif, struct wmi_arp_ns_offload_arg *offload, bool enable); int ath12k_wmi_gtk_rekey_offload(struct ath12k *ar, - struct ath12k_vif *arvif, bool enable); + struct ath12k_link_vif *arvif, bool enable); int ath12k_wmi_gtk_rekey_getinfo(struct ath12k *ar, - struct ath12k_vif *arvif); + struct ath12k_link_vif *arvif); int ath12k_wmi_sta_keepalive(struct ath12k *ar, const struct wmi_sta_keepalive_arg *arg); diff --git a/drivers/net/wireless/ath/ath12k/wow.c b/drivers/net/wireless/ath/ath12k/wow.c index 9b8684abbe40ae..9e1c0bfd212f5d 100644 --- a/drivers/net/wireless/ath/ath12k/wow.c +++ b/drivers/net/wireless/ath/ath12k/wow.c @@ -29,11 +29,11 @@ static const struct wiphy_wowlan_support ath12k_wowlan_support = { .max_pkt_offset = WOW_MAX_PKT_OFFSET, }; -static inline bool ath12k_wow_is_p2p_vdev(struct ath12k_vif *arvif) +static inline bool ath12k_wow_is_p2p_vdev(struct ath12k_vif *ahvif) { - return (arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_DEVICE || - arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_CLIENT || - arvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_GO); + return (ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_DEVICE || + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_CLIENT || + ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_P2P_GO); } int ath12k_wow_enable(struct ath12k *ar) @@ -101,7 +101,7 @@ int ath12k_wow_wakeup(struct ath12k *ar) return 0; } -static int ath12k_wow_vif_cleanup(struct ath12k_vif *arvif) +static int ath12k_wow_vif_cleanup(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; int i, ret; @@ -129,10 +129,10 @@ static int ath12k_wow_vif_cleanup(struct ath12k_vif *arvif) static int ath12k_wow_cleanup(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { ret = ath12k_wow_vif_cleanup(arvif); @@ -191,7 +191,7 @@ ath12k_wow_convert_8023_to_80211(struct ath12k *ar, memcpy(bytemask, eth_bytemask, eth_pat_len); pat_len = eth_pat_len; - } else if (eth_pkt_ofs + eth_pat_len < prot_ofs) { + } else if (size_add(eth_pkt_ofs, eth_pat_len) < prot_ofs) { memcpy(pat, eth_pat, ETH_ALEN - eth_pkt_ofs); memcpy(bytemask, eth_bytemask, ETH_ALEN - eth_pkt_ofs); @@ -354,7 +354,7 @@ ath12k_wow_pno_check_and_convert(struct ath12k *ar, u32 vdev_id, return 0; } -static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif, +static int ath12k_wow_vif_set_wakeups(struct ath12k_link_vif *arvif, struct cfg80211_wowlan *wowlan) { const struct cfg80211_pkt_pattern *patterns = wowlan->patterns; @@ -364,7 +364,7 @@ static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif, int ret, i, j; /* Setup requested WOW features */ - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_IBSS: __set_bit(WOW_BEACON_EVENT, &wow_mask); fallthrough; @@ -473,13 +473,13 @@ static int ath12k_wow_vif_set_wakeups(struct ath12k_vif *arvif, static int ath12k_wow_set_wakeups(struct ath12k *ar, struct cfg80211_wowlan *wowlan) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (ath12k_wow_is_p2p_vdev(arvif)) + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) continue; ret = ath12k_wow_vif_set_wakeups(arvif, wowlan); if (ret) { @@ -518,11 +518,11 @@ static int ath12k_wow_vdev_clean_nlo(struct ath12k *ar, u32 vdev_id) return ret; } -static int ath12k_wow_vif_clean_nlo(struct ath12k_vif *arvif) +static int ath12k_wow_vif_clean_nlo(struct ath12k_link_vif *arvif) { struct ath12k *ar = arvif->ar; - switch (arvif->vdev_type) { + switch (arvif->ahvif->vdev_type) { case WMI_VDEV_TYPE_STA: return ath12k_wow_vdev_clean_nlo(ar, arvif->vdev_id); default: @@ -532,13 +532,13 @@ static int ath12k_wow_vif_clean_nlo(struct ath12k_vif *arvif) static int ath12k_wow_nlo_cleanup(struct ath12k *ar) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (ath12k_wow_is_p2p_vdev(arvif)) + if (ath12k_wow_is_p2p_vdev(arvif->ahvif)) continue; ret = ath12k_wow_vif_clean_nlo(arvif); @@ -555,13 +555,13 @@ static int ath12k_wow_nlo_cleanup(struct ath12k *ar) static int ath12k_wow_set_hw_filter(struct ath12k *ar) { struct wmi_hw_data_filter_arg arg; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA) continue; arg.vdev_id = arvif->vdev_id; @@ -581,13 +581,13 @@ static int ath12k_wow_set_hw_filter(struct ath12k *ar) static int ath12k_wow_clear_hw_filter(struct ath12k *ar) { struct wmi_hw_data_filter_arg arg; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA) continue; arg.vdev_id = arvif->vdev_id; @@ -626,10 +626,10 @@ static void ath12k_wow_generate_ns_mc_addr(struct ath12k_base *ab, } } -static void ath12k_wow_prepare_ns_offload(struct ath12k_vif *arvif, +static void ath12k_wow_prepare_ns_offload(struct ath12k_link_vif *arvif, struct wmi_arp_ns_offload_arg *offload) { - struct net_device *ndev = ieee80211_vif_to_wdev(arvif->vif)->netdev; + struct net_device *ndev = ieee80211_vif_to_wdev(arvif->ahvif->vif)->netdev; struct ath12k_base *ab = arvif->ar->ab; struct inet6_ifaddr *ifa6; struct ifacaddr6 *ifaca6; @@ -710,10 +710,10 @@ static void ath12k_wow_prepare_ns_offload(struct ath12k_vif *arvif, ath12k_wow_generate_ns_mc_addr(ab, offload); } -static void ath12k_wow_prepare_arp_offload(struct ath12k_vif *arvif, +static void ath12k_wow_prepare_arp_offload(struct ath12k_link_vif *arvif, struct wmi_arp_ns_offload_arg *offload) { - struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif *vif = arvif->ahvif->vif; struct ieee80211_vif_cfg vif_cfg = vif->cfg; struct ath12k_base *ab = arvif->ar->ab; u32 ipv4_cnt; @@ -732,22 +732,25 @@ static void ath12k_wow_prepare_arp_offload(struct ath12k_vif *arvif, static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) { struct wmi_arp_ns_offload_arg *offload; - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; + struct ath12k_vif *ahvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); offload = kmalloc(sizeof(*offload), GFP_KERNEL); if (!offload) return -ENOMEM; list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + ahvif = arvif->ahvif; + + if (ahvif->vdev_type != WMI_VDEV_TYPE_STA) continue; memset(offload, 0, sizeof(*offload)); - memcpy(offload->mac_addr, arvif->vif->addr, ETH_ALEN); + memcpy(offload->mac_addr, ahvif->vif->addr, ETH_ALEN); ath12k_wow_prepare_ns_offload(arvif, offload); ath12k_wow_prepare_arp_offload(arvif, offload); @@ -766,13 +769,13 @@ static int ath12k_wow_arp_ns_offload(struct ath12k *ar, bool enable) static int ath12k_gtk_rekey_offload(struct ath12k *ar, bool enable) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->vdev_type != WMI_VDEV_TYPE_STA || + if (arvif->ahvif->vdev_type != WMI_VDEV_TYPE_STA || !arvif->is_up || !arvif->rekey_data.enable_offload) continue; @@ -824,10 +827,10 @@ static int ath12k_wow_set_keepalive(struct ath12k *ar, enum wmi_sta_keepalive_method method, u32 interval) { - struct ath12k_vif *arvif; + struct ath12k_link_vif *arvif; int ret; - lockdep_assert_held(&ar->conf_mutex); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); list_for_each_entry(arvif, &ar->arvifs, list) { ret = ath12k_mac_vif_set_keepalive(arvif, method, interval); @@ -845,7 +848,7 @@ int ath12k_wow_op_suspend(struct ieee80211_hw *hw, struct ath12k *ar = ath12k_ah_to_ar(ah, 0); int ret; - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); ret = ath12k_wow_cleanup(ar); if (ret) { @@ -913,7 +916,6 @@ int ath12k_wow_op_suspend(struct ieee80211_hw *hw, ath12k_wow_cleanup(ar); exit: - mutex_unlock(&ar->conf_mutex); return ret ? 1 : 0; } @@ -922,9 +924,9 @@ void ath12k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar = ath12k_ah_to_ar(ah, 0); - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); + device_set_wakeup_enable(ar->ab->dev, enabled); - mutex_unlock(&ar->conf_mutex); } int ath12k_wow_op_resume(struct ieee80211_hw *hw) @@ -933,7 +935,7 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw) struct ath12k *ar = ath12k_ah_to_ar(ah, 0); int ret; - mutex_lock(&ar->conf_mutex); + lockdep_assert_wiphy(hw->wiphy); ret = ath12k_hif_resume(ar->ab); if (ret) { @@ -995,7 +997,6 @@ int ath12k_wow_op_resume(struct ieee80211_hw *hw) } } - mutex_unlock(&ar->conf_mutex); return ret; } diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index f27308ccb2f15e..cb3e891ee1bd12 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -218,10 +218,10 @@ static void ath_ahb_remove(struct platform_device *pdev) } static struct platform_driver ath_ahb_driver = { - .probe = ath_ahb_probe, - .remove_new = ath_ahb_remove, - .driver = { - .name = "ar231x-wmac", + .probe = ath_ahb_probe, + .remove = ath_ahb_remove, + .driver = { + .name = "ar231x-wmac", }, }; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index b51fce5ae26020..f5ca2fe0d07490 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -46,6 +46,8 @@ static const struct pci_device_id ath5k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */ { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */ { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */ + { PCI_VDEVICE(ATHEROS, 0xff16) }, /* Gigaset SX76[23] AR241[34]A */ + { PCI_VDEVICE(ATHEROS, 0xff1a) }, /* Arcadyan ARV45XX AR2417 */ { PCI_VDEVICE(ATHEROS, 0xff1b) }, /* AR5BXB63 */ { 0 } }; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index b4fcfb72991c1c..68384159870be5 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1249,7 +1249,7 @@ struct wmi_rssi_threshold_params_cmd { /* highest of upper */ a_sle16 thresh_above6_val; - /* lowest of bellow */ + /* lowest of below */ a_sle16 thresh_below1_val; a_sle16 thresh_below2_val; @@ -1257,7 +1257,7 @@ struct wmi_rssi_threshold_params_cmd { a_sle16 thresh_below4_val; a_sle16 thresh_below5_val; - /* highest of bellow */ + /* highest of below */ a_sle16 thresh_below6_val; /* "alpha" */ @@ -1287,13 +1287,13 @@ struct wmi_snr_threshold_params_cmd { /* highest of upper */ u8 thresh_above4_val; - /* lowest of bellow */ + /* lowest of below */ u8 thresh_below1_val; u8 thresh_below2_val; u8 thresh_below3_val; - /* highest of bellow */ + /* highest of below */ u8 thresh_below4_val; u8 reserved[3]; diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 1a6697b6e3b41f..d4805e02b92704 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -158,12 +158,12 @@ static void ath_ahb_remove(struct platform_device *pdev) } static struct platform_driver ath_ahb_driver = { - .probe = ath_ahb_probe, - .remove_new = ath_ahb_remove, - .driver = { - .name = "ath9k", + .probe = ath_ahb_probe, + .remove = ath_ahb_remove, + .driver = { + .name = "ath9k", }, - .id_table = ath9k_platform_id_table, + .id_table = ath9k_platform_id_table, }; MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_aic.c b/drivers/net/wireless/ath/ath9k/ar9003_aic.c index d0f1e8bcc846b5..45a7ca660f47a1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_aic.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_aic.c @@ -409,13 +409,11 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah) sram.valid = true; sram.rot_dir_att_db = - min(max(rot_dir_path_att_db, - (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB), - ATH_AIC_MAX_ROT_DIR_ATT_DB); + clamp(rot_dir_path_att_db, (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB, + ATH_AIC_MAX_ROT_DIR_ATT_DB); sram.rot_quad_att_db = - min(max(rot_quad_path_att_db, - (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB), - ATH_AIC_MAX_ROT_QUAD_ATT_DB); + clamp(rot_quad_path_att_db, (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB, + ATH_AIC_MAX_ROT_QUAD_ATT_DB); aic->aic_sram[i] = (SM(sram.vga_dir_sign, AR_PHY_AIC_SRAM_VGA_DIR_SIGN) | diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c index 004ca5f536bec5..fe1013a3a58800 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 9b393a8f7c3ae8..ad3a3fda1b9c9c 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -16,7 +16,6 @@ #include #include -#include #include "hw.h" enum ath_bt_mode { @@ -115,23 +114,14 @@ static void ath9k_hw_btcoex_pin_init(struct ath_hw *ah, u8 wlanactive_gpio, u8 btactive_gpio, u8 btpriority_gpio) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - struct ath9k_platform_data *pdata = ah->dev->platform_data; if (btcoex_hw->scheme != ATH_BTCOEX_CFG_2WIRE && btcoex_hw->scheme != ATH_BTCOEX_CFG_3WIRE) return; - /* bt priority GPIO will be ignored by 2 wire scheme */ - if (pdata && (pdata->bt_active_pin || pdata->bt_priority_pin || - pdata->wlan_active_pin)) { - btcoex_hw->btactive_gpio = pdata->bt_active_pin; - btcoex_hw->wlanactive_gpio = pdata->wlan_active_pin; - btcoex_hw->btpriority_gpio = pdata->bt_priority_pin; - } else { - btcoex_hw->btactive_gpio = btactive_gpio; - btcoex_hw->wlanactive_gpio = wlanactive_gpio; - btcoex_hw->btpriority_gpio = btpriority_gpio; - } + btcoex_hw->btactive_gpio = btactive_gpio; + btcoex_hw->wlanactive_gpio = wlanactive_gpio; + btcoex_hw->btpriority_gpio = btpriority_gpio; } void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index efb7889142d472..df58dc02e104fe 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -15,7 +15,6 @@ */ #include "hw.h" -#include void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) { @@ -119,14 +118,6 @@ static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size, return true; } -static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata, - off_t offset, u16 *data) -{ - return ath9k_hw_nvram_read_array(pdata->eeprom_data, - ARRAY_SIZE(pdata->eeprom_data), - offset, data); -} - static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob, off_t offset, u16 *data) { @@ -146,15 +137,12 @@ static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset, bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_platform_data *pdata = ah->dev->platform_data; bool ret; if (ah->nvmem_blob) ret = ath9k_hw_nvram_read_nvmem(ah, off, data); else if (ah->eeprom_blob) ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data); - else if (pdata && !pdata->use_eeprom) - ret = ath9k_hw_nvram_read_pdata(pdata, off, data); else ret = common->bus_ops->eeprom_read(common, off, data); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 8a03bcc2789e88..57094bd45d98b0 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1357,8 +1357,10 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, static void ath9k_htc_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, + u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv; if (!(changed & IEEE80211_RC_SUPP_RATES_CHANGED)) @@ -1883,7 +1885,7 @@ struct ieee80211_ops ath9k_htc_ops = { .sta_add = ath9k_htc_sta_add, .sta_remove = ath9k_htc_sta_remove, .conf_tx = ath9k_htc_conf_tx, - .sta_rc_update = ath9k_htc_sta_rc_update, + .link_sta_rc_update = ath9k_htc_sta_rc_update, .bss_info_changed = ath9k_htc_bss_info_changed, .set_key = ath9k_htc_set_key, .get_tsf = ath9k_htc_get_tsf, diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index eb631fd3336d8d..b5257b2b4aa527 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -294,6 +294,9 @@ int htc_connect_service(struct htc_target *target, return -ETIMEDOUT; } + if (target->conn_rsp_epid < 0 || target->conn_rsp_epid >= ENDPOINT_MAX) + return -EINVAL; + *conn_rsp_epid = target->conn_rsp_epid; return 0; err: diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c3a6368bfc68ab..e2bef099adb30a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -490,7 +490,7 @@ static void ath9k_hw_init_macaddr(struct ath_hw *ah) u16 eeval; static const u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW }; - /* MAC address may already be loaded via ath9k_platform_data */ + /* MAC address may already be loaded via NVMEM */ if (is_valid_ether_addr(common->macaddr)) return; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 7fad7e75af6a37..f9e77c4624d99c 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -583,8 +582,8 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) /* nvmem cell might not be defined, or the nvmem * subsystem isn't included. In this case, follow - * the established "just return 0;" convention of - * ath9k_init_platform to say: + * the established "just return 0;" convention + * to say: * "All good. Nothing to see here. Please go on." */ if (err == -ENOENT || err == -EOPNOTSUPP) @@ -620,49 +619,6 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) return 0; } -static int ath9k_init_platform(struct ath_softc *sc) -{ - struct ath9k_platform_data *pdata = sc->dev->platform_data; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int ret; - - if (!pdata) - return 0; - - if (!pdata->use_eeprom) { - ah->ah_flags &= ~AH_USE_EEPROM; - ah->gpio_mask = pdata->gpio_mask; - ah->gpio_val = pdata->gpio_val; - ah->led_pin = pdata->led_pin; - ah->is_clk_25mhz = pdata->is_clk_25mhz; - ah->get_mac_revision = pdata->get_mac_revision; - ah->external_reset = pdata->external_reset; - ah->disable_2ghz = pdata->disable_2ghz; - ah->disable_5ghz = pdata->disable_5ghz; - - if (!pdata->endian_check) - ah->ah_flags |= AH_NO_EEP_SWAP; - } - - if (pdata->eeprom_name) { - ret = ath9k_eeprom_request(sc, pdata->eeprom_name); - if (ret) - return ret; - } - - if (pdata->led_active_high) - ah->config.led_active_high = true; - - if (pdata->tx_gain_buffalo) - ah->config.tx_gain_buffalo = true; - - if (pdata->macaddr) - ether_addr_copy(common->macaddr, pdata->macaddr); - - return 0; -} - static int ath9k_of_init(struct ath_softc *sc) { struct device_node *np = sc->dev->of_node; @@ -748,10 +704,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, */ ath9k_init_pcoem_platform(sc); - ret = ath9k_init_platform(sc); - if (ret) - return ret; - ret = ath9k_of_init(sc); if (ret) return ret; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 408776562a7e56..8557d4826a46e4 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1679,10 +1679,10 @@ static const struct of_device_id wcn36xx_of_match[] = { MODULE_DEVICE_TABLE(of, wcn36xx_of_match); static struct platform_driver wcn36xx_driver = { - .probe = wcn36xx_probe, - .remove_new = wcn36xx_remove, - .driver = { - .name = "wcn36xx", + .probe = wcn36xx_probe, + .remove = wcn36xx_remove, + .driver = { + .name = "wcn36xx", .of_match_table = wcn36xx_of_match, }, }; diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index bccc27de848da5..7ee79593cd23dc 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -167,7 +167,7 @@ struct wcn36xx_vif { * @dpu_desc_index: DPU descriptor index is returned from HW after config_sta * call and is used in TX BD. * @bss_sta_index: STA index is returned from HW after config_bss call and is - * used in both SMD channel and TX BD. See table bellow when it is used. + * used in both SMD channel and TX BD. See table below when it is used. * @bss_dpu_desc_index: DPU descriptor index is returned from HW after * config_bss call and is used in TX BD. * ______________________________________________ diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index e8f1d30a8d73c5..a1a0a9223e74ac 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1493,6 +1493,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, } static int wil_cfg80211_set_channel(struct wiphy *wiphy, + struct net_device *dev, struct cfg80211_chan_def *chandef) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c index 4f0c1e1a8e605d..1e1c79b18c5bcd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c @@ -22,7 +22,7 @@ static void __exit brcmf_bca_exit(void) MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Broadcom AP chipsets"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_IMPORT_NS(BRCMFMAC); +MODULE_IMPORT_NS("BRCMFMAC"); module_init(brcmf_bca_init); module_exit(brcmf_bca_exit); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index d35262335eaf79..42d991d9f8cb48 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -770,7 +770,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE, sdiodev->settings->bus.sdio.txglomsz); - nents += (nents >> 4) + 1; + nents *= 2; WARN_ON(nents > sdiodev->max_segment_count); @@ -947,8 +947,8 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) /* try to attach to the target device */ sdiodev->bus = brcmf_sdio_probe(sdiodev); - if (!sdiodev->bus) { - ret = -ENODEV; + if (IS_ERR(sdiodev->bus)) { + ret = PTR_ERR(sdiodev->bus); goto out; } brcmf_sdiod_host_fixup(sdiodev->func2->card->host); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 349aa3439502cb..297a7c738c0161 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -7820,13 +7820,6 @@ s32 brcmf_cfg80211_down(struct net_device *ndev) return err; } -enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp) -{ - struct wireless_dev *wdev = &ifp->vif->wdev; - - return wdev->iftype; -} - bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index dc3a6a537507d1..2abae8894614b6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -443,7 +443,6 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); s32 brcmf_cfg80211_up(struct net_device *ndev); s32 brcmf_cfg80211_down(struct net_device *ndev); struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings); -enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp); struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, enum nl80211_iftype type); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index b24faae35873dc..cfcf01eb0daa54 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -561,7 +561,8 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, if (!found) { /* No platform data for this device, try OF and DMI data */ brcmf_dmi_probe(settings, chip, chiprev); - brcmf_of_probe(dev, bus_type, settings); + if (brcmf_of_probe(dev, bus_type, settings) == -EPROBE_DEFER) + return ERR_PTR(-EPROBE_DEFER); brcmf_acpi_probe(dev, bus_type, settings); } return settings; @@ -593,7 +594,7 @@ static void brcmf_common_pd_remove(struct platform_device *pdev) } static struct platform_driver brcmf_pd = { - .remove_new = brcmf_common_pd_remove, + .remove = brcmf_common_pd_remove, .driver = { .name = BRCMFMAC_PDATA_NAME, } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 39226b9c0fa834..d53839f855d726 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -14,7 +14,7 @@ #include "fweh.h" #if IS_MODULE(CONFIG_BRCMFMAC) -#define BRCMF_EXPORT_SYMBOL_GPL(__sym) EXPORT_SYMBOL_NS_GPL(__sym, BRCMFMAC) +#define BRCMF_EXPORT_SYMBOL_GPL(__sym) EXPORT_SYMBOL_NS_GPL(__sym, "BRCMFMAC") #else #define BRCMF_EXPORT_SYMBOL_GPL(__sym) #endif diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c index 90d06cda03a2f0..ce5fcfd42a7ea0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c @@ -22,7 +22,7 @@ static void __exit brcmf_cyw_exit(void) MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Cypress/Infineon chipsets"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_IMPORT_NS(BRCMFMAC); +MODULE_IMPORT_NS("BRCMFMAC"); module_init(brcmf_cyw_init); module_exit(brcmf_cyw_exit); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index fe4f657561056c..c1f18e2fe540d3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "debug.h" @@ -65,12 +66,13 @@ static int brcmf_of_get_country_codes(struct device *dev, return 0; } -void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings) +int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + struct brcmf_mp_device *settings) { struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio; struct device_node *root, *np = dev->of_node; struct of_phandle_args oirq; + struct clk *clk; const char *prop; int irq; int err; @@ -106,16 +108,21 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, board_type = devm_kstrdup(dev, tmp, GFP_KERNEL); if (!board_type) { of_node_put(root); - return; + return 0; } strreplace(board_type, '/', '-'); settings->board_type = board_type; - - of_node_put(root); } + of_node_put(root); + + clk = devm_clk_get_optional_enabled_with_rate(dev, "lpo", 32768); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + brcmf_dbg(INFO, "%s LPO clock\n", clk ? "enable" : "no"); if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) - return; + return 0; err = brcmf_of_get_country_codes(dev, settings); if (err) @@ -124,23 +131,25 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, of_get_mac_address(np, settings->mac); if (bus_type != BRCMF_BUSTYPE_SDIO) - return; + return 0; if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0) sdio->drive_strength = val; /* make sure there are interrupts defined in the node */ if (of_irq_parse_one(np, 0, &oirq)) - return; + return 0; irq = irq_create_of_mapping(&oirq); if (!irq) { brcmf_err("interrupt could not be mapped\n"); - return; + return 0; } - irqf = irqd_get_trigger_type(irq_get_irq_data(irq)); + irqf = irq_get_trigger_type(irq); sdio->oob_irq_supported = true; sdio->oob_irq_nr = irq; sdio->oob_irq_flags = irqf; + + return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h index 10bf52253337e7..ae124c73fc3b7c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h @@ -3,11 +3,12 @@ * Copyright (c) 2014 Broadcom Corporation */ #ifdef CONFIG_OF -void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings); +int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + struct brcmf_mp_device *settings); #else -static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, - struct brcmf_mp_device *settings) +static int brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, + struct brcmf_mp_device *settings) { + return 0; } #endif /* CONFIG_OF */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 5dee54819fbdfb..e4395b1f8c11e8 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -66,6 +66,7 @@ BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie"); BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); +BRCMF_FW_CLM_DEF(43752, "brcmfmac43752-pcie"); BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie"); @@ -104,6 +105,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43664_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_43666_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), + BRCMF_FW_ENTRY(BRCM_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752), BRCMF_FW_ENTRY(BRCM_CC_4377_CHIP_ID, 0xFFFFFFFF, 4377B3), /* revision ID 4 */ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0x0000000F, 4378B1), /* revision ID 3 */ BRCMF_FW_ENTRY(BRCM_CC_4378_CHIP_ID, 0xFFFFFFE0, 4378B3), /* revision ID 5 */ @@ -353,6 +355,7 @@ struct brcmf_pciedev_info { u16 value); struct brcmf_mp_device *settings; struct brcmf_otp_params otp; + bool fwseed; #ifdef DEBUG u32 console_interval; bool console_active; @@ -1715,14 +1718,14 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo, memcpy_toio(devinfo->tcm + address, nvram, nvram_len); brcmf_fw_nvram_free(nvram); - if (devinfo->otp.valid) { + if (devinfo->fwseed) { size_t rand_len = BRCMF_RANDOM_SEED_LENGTH; struct brcmf_random_seed_footer footer = { .length = cpu_to_le32(rand_len), .magic = cpu_to_le32(BRCMF_RANDOM_SEED_MAGIC), }; - /* Some Apple chips/firmwares expect a buffer of random + /* Some chips/firmwares expect a buffer of random * data to be present before NVRAM */ brcmf_dbg(PCIE, "Download random seed\n"); @@ -2394,6 +2397,37 @@ static void brcmf_pcie_debugfs_create(struct device *dev) } #endif +struct brcmf_pcie_drvdata { + enum brcmf_fwvendor vendor; + bool fw_seed; +}; + +enum { + BRCMF_DRVDATA_CYW, + BRCMF_DRVDATA_BCA, + BRCMF_DRVDATA_WCC, + BRCMF_DRVDATA_WCC_SEED, +}; + +static const struct brcmf_pcie_drvdata drvdata[] = { + [BRCMF_DRVDATA_CYW] = { + .vendor = BRCMF_FWVENDOR_CYW, + .fw_seed = false, + }, + [BRCMF_DRVDATA_BCA] = { + .vendor = BRCMF_FWVENDOR_BCA, + .fw_seed = false, + }, + [BRCMF_DRVDATA_WCC] = { + .vendor = BRCMF_FWVENDOR_WCC, + .fw_seed = false, + }, + [BRCMF_DRVDATA_WCC_SEED] = { + .vendor = BRCMF_FWVENDOR_WCC, + .fw_seed = true, + }, +}; + /* Forward declaration for pci_match_id() call */ static const struct pci_device_id brcmf_pcie_devid_table[]; @@ -2452,6 +2486,9 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = -ENOMEM; goto fail; } + ret = PTR_ERR_OR_ZERO(devinfo->settings); + if (ret < 0) + goto fail; bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (!bus) { @@ -2472,9 +2509,10 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) bus->bus_priv.pcie = pcie_bus_dev; bus->ops = &brcmf_pcie_bus_ops; bus->proto_type = BRCMF_PROTO_MSGBUF; - bus->fwvid = id->driver_data; bus->chip = devinfo->coreid; bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot); + bus->fwvid = drvdata[id->driver_data].vendor; + devinfo->fwseed = drvdata[id->driver_data].fw_seed; dev_set_drvdata(&pdev->dev, bus); ret = brcmf_alloc(&devinfo->pdev->dev, devinfo->settings); @@ -2660,14 +2698,14 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = { BRCM_PCIE_VENDOR_ID_BROADCOM, (dev_id), \ PCI_ANY_ID, PCI_ANY_ID, \ PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \ - BRCMF_FWVENDOR_ ## fw_vend \ + BRCMF_DRVDATA_ ## fw_vend \ } #define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev, fw_vend) \ { \ BRCM_PCIE_VENDOR_ID_BROADCOM, (dev_id), \ (subvend), (subdev), \ PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, \ - BRCMF_FWVENDOR_ ## fw_vend \ + BRCMF_DRVDATA_ ## fw_vend \ } static const struct pci_device_id brcmf_pcie_devid_table[] = { @@ -2695,9 +2733,10 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID, BCA), BRCMF_PCIE_DEVICE(BRCM_PCIE_4371_DEVICE_ID, WCC), BRCMF_PCIE_DEVICE(BRCM_PCIE_43596_DEVICE_ID, CYW), - BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC), - BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC), - BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4377_DEVICE_ID, WCC_SEED), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC_SEED), + BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC_SEED), + BRCMF_PCIE_DEVICE(BRCM_PCIE_43752_DEVICE_ID, WCC_SEED), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 7b936668c1b66d..b1727f35217bc6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -3943,7 +3943,7 @@ static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = { .write32 = brcmf_sdio_buscore_write32, }; -static bool +static int brcmf_sdio_probe_attach(struct brcmf_sdio *bus) { struct brcmf_sdio_dev *sdiodev; @@ -3953,6 +3953,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) u32 reg_val; u32 drivestrength; u32 enum_base; + int ret = -EBADE; sdiodev = bus->sdiodev; sdio_claim_host(sdiodev->func1); @@ -4001,8 +4002,9 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) BRCMF_BUSTYPE_SDIO, bus->ci->chip, bus->ci->chiprev); - if (!sdiodev->settings) { + if (IS_ERR_OR_NULL(sdiodev->settings)) { brcmf_err("Failed to get device parameters\n"); + ret = PTR_ERR_OR_ZERO(sdiodev->settings); goto fail; } /* platform specific configuration: @@ -4071,7 +4073,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) /* allocate header buffer */ bus->hdrbuf = kzalloc(MAX_HDR_READ + bus->head_align, GFP_KERNEL); if (!bus->hdrbuf) - return false; + return -ENOMEM; /* Locate an appropriately-aligned portion of hdrbuf */ bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], bus->head_align); @@ -4082,11 +4084,11 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus) if (bus->poll) bus->pollrate = 1; - return true; + return 0; fail: sdio_release_host(sdiodev->func1); - return false; + return ret; } static int @@ -4451,8 +4453,10 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) /* Allocate private bus interface state */ bus = kzalloc(sizeof(*bus), GFP_ATOMIC); - if (!bus) + if (!bus) { + ret = -ENOMEM; goto fail; + } bus->sdiodev = sdiodev; sdiodev->bus = bus; @@ -4467,6 +4471,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) dev_name(&sdiodev->func1->dev)); if (!wq) { brcmf_err("insufficient memory to create txworkqueue\n"); + ret = -ENOMEM; goto fail; } brcmf_sdiod_freezer_count(sdiodev); @@ -4474,7 +4479,8 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) bus->brcmf_wq = wq; /* attempt to attach to the dongle */ - if (!(brcmf_sdio_probe_attach(bus))) { + ret = brcmf_sdio_probe_attach(bus); + if (ret < 0) { brcmf_err("brcmf_sdio_probe_attach failed\n"); goto fail; } @@ -4546,7 +4552,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) fail: brcmf_sdio_remove(bus); - return NULL; + return ERR_PTR(ret); } /* Detach and free everything */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 8afbf529c74503..2821c27f317ee0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1272,6 +1272,9 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo, ret = -ENOMEM; goto fail; } + ret = PTR_ERR_OR_ZERO(devinfo->settings); + if (ret < 0) + goto fail; if (!brcmf_usb_dlneeded(devinfo)) { ret = brcmf_alloc(devinfo->dev, devinfo->settings); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c index b66135e3cff476..cfe01ca63ba63b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c @@ -22,7 +22,7 @@ static void __exit brcmf_wcc_exit(void) MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Broadcom mobility chipsets"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_IMPORT_NS(BRCMFMAC); +MODULE_IMPORT_NS("BRCMFMAC"); module_init(brcmf_wcc_init); module_exit(brcmf_wcc_exit); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c index 6d776ef6ff54eb..81df41c7fbb5b1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c @@ -56,11 +56,6 @@ void brcms_debugfs_detach(struct brcms_pub *drvr) debugfs_remove_recursive(drvr->dbgfs_dir); } -struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr) -{ - return drvr->dbgfs_dir; -} - static int brcms_debugfs_hardware_read(struct seq_file *s, void *data) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h index 56898e6d789d74..d30a9fa30f1b0a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.h @@ -70,7 +70,6 @@ void brcms_debugfs_init(void); void brcms_debugfs_exit(void); void brcms_debugfs_attach(struct brcms_pub *drvr); void brcms_debugfs_detach(struct brcms_pub *drvr); -struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr); void brcms_debugfs_create_files(struct brcms_pub *drvr); #endif /* _BRCMS_DEBUG_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c index bd480239368a4b..80c35027787a1e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c @@ -1426,15 +1426,6 @@ int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, return -ENOSPC; } -void dma_txflush(struct dma_pub *pub) -{ - struct dma_info *di = container_of(pub, struct dma_info, dma); - struct brcms_ampdu_session *session = &di->ampdu_session; - - if (!skb_queue_empty(&session->skb_list)) - ampdu_finalize(di); -} - int dma_txpending(struct dma_pub *pub) { struct dma_info *di = container_of(pub, struct dma_info, dma); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h index ff5b80b0904636..7905fd08172185 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.h @@ -88,7 +88,6 @@ bool dma_txreset(struct dma_pub *pub); void dma_txinit(struct dma_pub *pub); int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub, struct sk_buff *p0); -void dma_txflush(struct dma_pub *pub); int dma_txpending(struct dma_pub *pub); void dma_kick_tx(struct dma_pub *pub); void dma_txsuspend(struct dma_pub *pub); diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index 44684bf1b9acc6..c1e22c589d85eb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -52,6 +52,7 @@ #define BRCM_CC_43664_CHIP_ID 43664 #define BRCM_CC_43666_CHIP_ID 43666 #define BRCM_CC_4371_CHIP_ID 0x4371 +#define BRCM_CC_43752_CHIP_ID 43752 #define BRCM_CC_4377_CHIP_ID 0x4377 #define BRCM_CC_4378_CHIP_ID 0x4378 #define BRCM_CC_4387_CHIP_ID 0x4387 @@ -94,6 +95,7 @@ #define BRCM_PCIE_4366_5G_DEVICE_ID 0x43c5 #define BRCM_PCIE_4371_DEVICE_ID 0x440d #define BRCM_PCIE_43596_DEVICE_ID 0x4415 +#define BRCM_PCIE_43752_DEVICE_ID 0x449d #define BRCM_PCIE_4377_DEVICE_ID 0x4488 #define BRCM_PCIE_4378_DEVICE_ID 0x4425 #define BRCM_PCIE_4387_DEVICE_ID 0x4433 diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig index 1650d5865aa027..b92df91adb3a49 100644 --- a/drivers/net/wireless/intel/ipw2x00/Kconfig +++ b/drivers/net/wireless/intel/ipw2x00/Kconfig @@ -7,10 +7,8 @@ config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" depends on PCI && CFG80211 select WIRELESS_EXT - select WEXT_SPY select WEXT_PRIV select FW_LOADER - select LIB80211 select LIBIPW help A driver for the Intel PRO/Wireless 2100 Network @@ -67,12 +65,9 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" depends on PCI && CFG80211 - select CFG80211_WEXT_EXPORT select WIRELESS_EXT - select WEXT_SPY select WEXT_PRIV select FW_LOADER - select LIB80211 select LIBIPW help A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network @@ -158,14 +153,10 @@ config LIBIPW tristate depends on PCI && CFG80211 select WIRELESS_EXT - select WEXT_SPY select CRYPTO select CRYPTO_MICHAEL_MIC + select CRYPTO_LIB_ARC4 select CRC32 - select LIB80211 - select LIB80211_CRYPT_WEP - select LIB80211_CRYPT_TKIP - select LIB80211_CRYPT_CCMP help This option enables the hardware independent IEEE 802.11 networking stack. This component is deprecated in favor of the diff --git a/drivers/net/wireless/intel/ipw2x00/Makefile b/drivers/net/wireless/intel/ipw2x00/Makefile index e1ec50359dffc8..91e6091c4ebf11 100644 --- a/drivers/net/wireless/intel/ipw2x00/Makefile +++ b/drivers/net/wireless/intel/ipw2x00/Makefile @@ -12,4 +12,9 @@ libipw-objs := \ libipw_tx.o \ libipw_rx.o \ libipw_wx.o \ - libipw_geo.o + libipw_geo.o \ + libipw_spy.o \ + libipw_crypto.o \ + libipw_crypto_ccmp.o \ + libipw_crypto_tkip.o \ + libipw_crypto_wep.o diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index fe75941c584d15..215814861cbda5 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -148,9 +148,6 @@ that only one external action is invoked at a time. #include #include #include - -#include - #include "ipw2100.h" #include "ipw.h" @@ -6025,8 +6022,6 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, dev->netdev_ops = &ipw2100_netdev_ops; dev->ethtool_ops = &ipw2100_ethtool_ops; dev->wireless_handlers = &ipw2100_wx_handler_def; - priv->wireless_data.libipw = priv->ieee; - dev->wireless_data = &priv->wireless_data; dev->watchdog_timeo = 3 * HZ; dev->irq = 0; dev->min_mtu = 68; @@ -7571,7 +7566,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, struct ipw2100_priv *priv = libipw_priv(dev); struct libipw_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -7663,7 +7658,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, { struct ipw2100_priv *priv = libipw_priv(dev); struct libipw_device *ieee = priv->ieee; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; struct iw_param *param = &wrqu->param; switch (param->flags & IW_AUTH_INDEX) { diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h index b34085ade3aa18..6f81f509b9cbf7 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.h @@ -554,8 +554,6 @@ struct ipw2100_priv { struct net_device *net_dev; struct iw_statistics wstats; - struct iw_public_data wireless_data; - struct tasklet_struct irq_tasklet; struct delayed_work reset_work; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index eed9ef17bc2934..be1d971b3d32da 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -6463,6 +6463,14 @@ static int ipw_set_rsn_capa(struct ipw_priv *priv, * WE-18 support */ +static int ipw_wx_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + strcpy(wrqu->name, "IEEE 802.11"); + return 0; +} + /* SIOCSIWGENIE */ static int ipw_wx_set_genie(struct net_device *dev, struct iw_request_info *info, @@ -6549,7 +6557,7 @@ static int ipw_wx_set_auth(struct net_device *dev, struct ipw_priv *priv = libipw_priv(dev); struct libipw_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -6648,7 +6656,7 @@ static int ipw_wx_get_auth(struct net_device *dev, { struct ipw_priv *priv = libipw_priv(dev); struct libipw_device *ieee = priv->ieee; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; struct iw_param *param = &wrqu->param; switch (param->flags & IW_AUTH_INDEX) { @@ -9826,7 +9834,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, /* Rebase the WE IOCTLs to zero for the handler array */ static iw_handler ipw_wx_handlers[] = { - IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname), + IW_HANDLER(SIOCGIWNAME, ipw_wx_get_name), IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq), IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq), IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode), @@ -9856,10 +9864,10 @@ static iw_handler ipw_wx_handlers[] = { IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode), IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power), IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power), - IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), - IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), - IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), - IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), + IW_HANDLER(SIOCSIWSPY, ipw_wx_set_spy), + IW_HANDLER(SIOCGIWSPY, ipw_wx_get_spy), + IW_HANDLER(SIOCSIWTHRSPY, ipw_wx_set_thrspy), + IW_HANDLER(SIOCGIWTHRSPY, ipw_wx_get_thrspy), IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie), IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie), IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme), @@ -11636,8 +11644,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, priv->ieee->worst_rssi = -85; net_dev->netdev_ops = &ipw_netdev_ops; - priv->wireless_data.spy_data = &priv->ieee->spy_data; - net_dev->wireless_data = &priv->wireless_data; + priv->ieee->spy_enabled = true; net_dev->wireless_handlers = &ipw_wx_handler_def; net_dev->ethtool_ops = &ipw_ethtool_ops; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h index 226286cb7eb822..19310fd0d8eb33 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.h @@ -31,8 +31,6 @@ #include #include #include - -#include #include #define DRV_NAME "ipw2200" @@ -1276,8 +1274,6 @@ struct ipw_priv { struct iw_statistics wstats; - struct iw_public_data wireless_data; - int user_requested_scan; u8 direct_scan_ssid[IW_ESSID_MAX_SIZE]; u8 direct_scan_ssid_len; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h index bad080d33c07fc..3c20353e5a4123 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw.h +++ b/drivers/net/wireless/intel/ipw2x00/libipw.h @@ -25,8 +25,6 @@ #include /* ARRAY_SIZE */ #include #include - -#include #include #define LIBIPW_VERSION "git-1.1.13" @@ -699,6 +697,76 @@ struct libipw_geo { struct libipw_channel a[LIBIPW_52GHZ_CHANNELS]; }; +#define NUM_WEP_KEYS 4 + +enum { + IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0), +}; + +struct module; + +struct libipw_crypto_ops { + const char *name; + struct list_head list; + + /* init new crypto context (e.g., allocate private data space, + * select IV, etc.); returns NULL on failure or pointer to allocated + * private data on success */ + void *(*init) (int keyidx); + + /* deinitialize crypto context and free allocated private data */ + void (*deinit) (void *priv); + + /* encrypt/decrypt return < 0 on error or >= 0 on success. The return + * value from decrypt_mpdu is passed as the keyidx value for + * decrypt_msdu. skb must have enough head and tail room for the + * encryption; if not, error will be returned; these functions are + * called for all MPDUs (i.e., fragments). + */ + int (*encrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_mpdu) (struct sk_buff * skb, int hdr_len, void *priv); + + /* These functions are called for full MSDUs, i.e. full frames. + * These can be NULL if full MSDU operations are not needed. */ + int (*encrypt_msdu) (struct sk_buff * skb, int hdr_len, void *priv); + int (*decrypt_msdu) (struct sk_buff * skb, int keyidx, int hdr_len, + void *priv); + + int (*set_key) (void *key, int len, u8 * seq, void *priv); + int (*get_key) (void *key, int len, u8 * seq, void *priv); + + /* procfs handler for printing out key information and possible + * statistics */ + void (*print_stats) (struct seq_file *m, void *priv); + + /* Crypto specific flag get/set for configuration settings */ + unsigned long (*get_flags) (void *priv); + unsigned long (*set_flags) (unsigned long flags, void *priv); + + /* maximum number of bytes added by encryption; encrypt buf is + * allocated with extra_prefix_len bytes, copy of in_buf, and + * extra_postfix_len; encrypt need not use all this space, but + * the result must start at the beginning of the buffer and correct + * length must be returned */ + int extra_mpdu_prefix_len, extra_mpdu_postfix_len; + int extra_msdu_prefix_len, extra_msdu_postfix_len; + + struct module *owner; +}; + +struct libipw_crypt_info { + char *name; + /* Most clients will already have a lock, + so just point to that. */ + spinlock_t *lock; + + struct libipw_crypt_data *crypt[NUM_WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct list_head crypt_deinit_list; + struct timer_list crypt_deinit_timer; + int crypt_quiesced; +}; + struct libipw_device { struct net_device *dev; struct wireless_dev wdev; @@ -720,6 +788,7 @@ struct libipw_device { int iw_mode; /* operating mode (IW_MODE_*) */ struct iw_spy_data spy_data; /* iwspy support */ + bool spy_enabled; spinlock_t lock; @@ -751,7 +820,7 @@ struct libipw_device { size_t wpa_ie_len; u8 *wpa_ie; - struct lib80211_crypt_info crypt_info; + struct libipw_crypt_info crypt_info; int bcrx_sta_key; /* use individual keys to override default keys even * with RX of broad/multicast frames */ @@ -988,4 +1057,43 @@ static inline int libipw_get_scans(struct libipw_device *ieee) return ieee->scans; } +struct libipw_crypt_data { + struct list_head list; /* delayed deletion list */ + const struct libipw_crypto_ops *ops; + void *priv; + atomic_t refcnt; +}; + +int libipw_crypt_info_init(struct libipw_crypt_info *info, char *name, + spinlock_t *lock); +void libipw_crypt_info_free(struct libipw_crypt_info *info); +int libipw_register_crypto_ops(const struct libipw_crypto_ops *ops); +int libipw_unregister_crypto_ops(const struct libipw_crypto_ops *ops); +const struct libipw_crypto_ops *libipw_get_crypto_ops(const char *name); +void libipw_crypt_delayed_deinit(struct libipw_crypt_info *info, + struct libipw_crypt_data **crypt); + +/* must be called in the listed order */ +int libipw_crypto_init(void); +int libipw_crypto_ccmp_init(void); +int libipw_crypto_tkip_init(void); +int libipw_crypto_wep_init(void); + +void libipw_crypto_wep_exit(void); +void libipw_crypto_tkip_exit(void); +void libipw_crypto_ccmp_exit(void); +void libipw_crypto_exit(void); + + +int ipw_wx_set_spy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +int ipw_wx_get_spy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +int ipw_wx_set_thrspy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +int ipw_wx_get_thrspy(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); +void libipw_spy_update(struct net_device *dev, unsigned char *address, + struct iw_quality *wstats); + #endif /* LIBIPW_H */ diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c new file mode 100644 index 00000000000000..32639e0e843094 --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * libipw -- common bits for IPW drivers + * + * Copyright(c) 2008 John W. Linville + * + * Portions copied from old ieee80211 component, w/ original copyright + * notices below: + * + * Host AP crypto routines + * + * Copyright (c) 2002-2003, Jouni Malinen + * Portions Copyright (C) 2004, Intel Corporation + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include "libipw.h" + +struct libipw_crypto_alg { + struct list_head list; + const struct libipw_crypto_ops *ops; +}; + +static LIST_HEAD(libipw_crypto_algs); +static DEFINE_SPINLOCK(libipw_crypto_lock); + +static void libipw_crypt_deinit_entries(struct libipw_crypt_info *info, + int force); +static void libipw_crypt_quiescing(struct libipw_crypt_info *info); +static void libipw_crypt_deinit_handler(struct timer_list *t); + +int libipw_crypt_info_init(struct libipw_crypt_info *info, char *name, + spinlock_t *lock) +{ + memset(info, 0, sizeof(*info)); + + info->name = name; + info->lock = lock; + + INIT_LIST_HEAD(&info->crypt_deinit_list); + timer_setup(&info->crypt_deinit_timer, libipw_crypt_deinit_handler, + 0); + + return 0; +} +EXPORT_SYMBOL(libipw_crypt_info_init); + +void libipw_crypt_info_free(struct libipw_crypt_info *info) +{ + int i; + + libipw_crypt_quiescing(info); + del_timer_sync(&info->crypt_deinit_timer); + libipw_crypt_deinit_entries(info, 1); + + for (i = 0; i < NUM_WEP_KEYS; i++) { + struct libipw_crypt_data *crypt = info->crypt[i]; + if (crypt) { + if (crypt->ops) { + crypt->ops->deinit(crypt->priv); + module_put(crypt->ops->owner); + } + kfree(crypt); + info->crypt[i] = NULL; + } + } +} +EXPORT_SYMBOL(libipw_crypt_info_free); + +static void libipw_crypt_deinit_entries(struct libipw_crypt_info *info, + int force) +{ + struct libipw_crypt_data *entry, *next; + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) { + if (atomic_read(&entry->refcnt) != 0 && !force) + continue; + + list_del(&entry->list); + + if (entry->ops) { + entry->ops->deinit(entry->priv); + module_put(entry->ops->owner); + } + kfree(entry); + } + spin_unlock_irqrestore(info->lock, flags); +} + +/* After this, crypt_deinit_list won't accept new members */ +static void libipw_crypt_quiescing(struct libipw_crypt_info *info) +{ + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + info->crypt_quiesced = 1; + spin_unlock_irqrestore(info->lock, flags); +} + +static void libipw_crypt_deinit_handler(struct timer_list *t) +{ + struct libipw_crypt_info *info = from_timer(info, t, + crypt_deinit_timer); + unsigned long flags; + + libipw_crypt_deinit_entries(info, 0); + + spin_lock_irqsave(info->lock, flags); + if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) { + printk(KERN_DEBUG "%s: entries remaining in delayed crypt " + "deletion list\n", info->name); + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + spin_unlock_irqrestore(info->lock, flags); +} + +void libipw_crypt_delayed_deinit(struct libipw_crypt_info *info, + struct libipw_crypt_data **crypt) +{ + struct libipw_crypt_data *tmp; + unsigned long flags; + + if (*crypt == NULL) + return; + + tmp = *crypt; + *crypt = NULL; + + /* must not run ops->deinit() while there may be pending encrypt or + * decrypt operations. Use a list of delayed deinits to avoid needing + * locking. */ + + spin_lock_irqsave(info->lock, flags); + if (!info->crypt_quiesced) { + list_add(&tmp->list, &info->crypt_deinit_list); + if (!timer_pending(&info->crypt_deinit_timer)) { + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + } + spin_unlock_irqrestore(info->lock, flags); +} +EXPORT_SYMBOL(libipw_crypt_delayed_deinit); + +int libipw_register_crypto_ops(const struct libipw_crypto_ops *ops) +{ + unsigned long flags; + struct libipw_crypto_alg *alg; + + alg = kzalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) + return -ENOMEM; + + alg->ops = ops; + + spin_lock_irqsave(&libipw_crypto_lock, flags); + list_add(&alg->list, &libipw_crypto_algs); + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + + printk(KERN_DEBUG "libipw_crypt: registered algorithm '%s'\n", + ops->name); + + return 0; +} +EXPORT_SYMBOL(libipw_register_crypto_ops); + +int libipw_unregister_crypto_ops(const struct libipw_crypto_ops *ops) +{ + struct libipw_crypto_alg *alg; + unsigned long flags; + + spin_lock_irqsave(&libipw_crypto_lock, flags); + list_for_each_entry(alg, &libipw_crypto_algs, list) { + if (alg->ops == ops) + goto found; + } + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + return -EINVAL; + + found: + printk(KERN_DEBUG "libipw_crypt: unregistered algorithm '%s'\n", + ops->name); + list_del(&alg->list); + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + kfree(alg); + return 0; +} +EXPORT_SYMBOL(libipw_unregister_crypto_ops); + +const struct libipw_crypto_ops *libipw_get_crypto_ops(const char *name) +{ + struct libipw_crypto_alg *alg; + unsigned long flags; + + spin_lock_irqsave(&libipw_crypto_lock, flags); + list_for_each_entry(alg, &libipw_crypto_algs, list) { + if (strcmp(alg->ops->name, name) == 0) + goto found; + } + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + return NULL; + + found: + spin_unlock_irqrestore(&libipw_crypto_lock, flags); + return alg->ops; +} +EXPORT_SYMBOL(libipw_get_crypto_ops); + +static void *libipw_crypt_null_init(int keyidx) +{ + return (void *)1; +} + +static void libipw_crypt_null_deinit(void *priv) +{ +} + +static const struct libipw_crypto_ops libipw_crypt_null = { + .name = "NULL", + .init = libipw_crypt_null_init, + .deinit = libipw_crypt_null_deinit, + .owner = THIS_MODULE, +}; + +int __init libipw_crypto_init(void) +{ + return libipw_register_crypto_ops(&libipw_crypt_null); +} + +void libipw_crypto_exit(void) +{ + libipw_unregister_crypto_ops(&libipw_crypt_null); + BUG_ON(!list_empty(&libipw_crypto_algs)); +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c new file mode 100644 index 00000000000000..bf900d8c8ad331 --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_ccmp.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * libipw crypt: host-based CCMP encryption implementation for libipw + * + * Copyright (c) 2003-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libipw.h" + +#define AES_BLOCK_LEN 16 +#define CCMP_HDR_LEN 8 +#define CCMP_MIC_LEN 8 +#define CCMP_TK_LEN 16 +#define CCMP_PN_LEN 6 + +struct libipw_ccmp_data { + u8 key[CCMP_TK_LEN]; + int key_set; + + u8 tx_pn[CCMP_PN_LEN]; + u8 rx_pn[CCMP_PN_LEN]; + + u32 dot11RSNAStatsCCMPFormatErrors; + u32 dot11RSNAStatsCCMPReplays; + u32 dot11RSNAStatsCCMPDecryptErrors; + + int key_idx; + + struct crypto_aead *tfm; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 tx_aad[2 * AES_BLOCK_LEN]; + u8 rx_aad[2 * AES_BLOCK_LEN]; +}; + +static void *libipw_ccmp_init(int key_idx) +{ + struct libipw_ccmp_data *priv; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + priv->key_idx = key_idx; + + priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(priv->tfm)) { + priv->tfm = NULL; + goto fail; + } + + return priv; + + fail: + if (priv) { + if (priv->tfm) + crypto_free_aead(priv->tfm); + kfree(priv); + } + + return NULL; +} + +static void libipw_ccmp_deinit(void *priv) +{ + struct libipw_ccmp_data *_priv = priv; + if (_priv && _priv->tfm) + crypto_free_aead(_priv->tfm); + kfree(priv); +} + +static int ccmp_init_iv_and_aad(const struct ieee80211_hdr *hdr, + const u8 *pn, u8 *iv, u8 *aad) +{ + u8 *pos, qc = 0; + size_t aad_len; + int a4_included, qc_included; + + a4_included = ieee80211_has_a4(hdr->frame_control); + qc_included = ieee80211_is_data_qos(hdr->frame_control); + + aad_len = 22; + if (a4_included) + aad_len += 6; + if (qc_included) { + pos = (u8 *) & hdr->addr4; + if (a4_included) + pos += 6; + qc = *pos & 0x0f; + aad_len += 2; + } + + /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC + * mode authentication are not allowed to collide, yet both are derived + * from the same vector. We only set L := 1 here to indicate that the + * data size can be represented in (L+1) bytes. The CCM layer will take + * care of storing the data length in the top (L+1) bytes and setting + * and clearing the other bits as is required to derive the two IVs. + */ + iv[0] = 0x1; + + /* Nonce: QC | A2 | PN */ + iv[1] = qc; + memcpy(iv + 2, hdr->addr2, ETH_ALEN); + memcpy(iv + 8, pn, CCMP_PN_LEN); + + /* AAD: + * FC with bits 4..6 and 11..13 masked to zero; 14 is always one + * A1 | A2 | A3 + * SC with bits 4..15 (seq#) masked to zero + * A4 (if present) + * QC (if present) + */ + pos = (u8 *) hdr; + aad[0] = pos[0] & 0x8f; + aad[1] = pos[1] & 0xc7; + memcpy(aad + 2, &hdr->addrs, 3 * ETH_ALEN); + pos = (u8 *) & hdr->seq_ctrl; + aad[20] = pos[0] & 0x0f; + aad[21] = 0; /* all bits masked */ + memset(aad + 22, 0, 8); + if (a4_included) + memcpy(aad + 22, hdr->addr4, ETH_ALEN); + if (qc_included) { + aad[a4_included ? 28 : 22] = qc; + /* rest of QC masked */ + } + return aad_len; +} + +static int libipw_ccmp_hdr(struct sk_buff *skb, int hdr_len, + u8 *aeskey, int keylen, void *priv) +{ + struct libipw_ccmp_data *key = priv; + int i; + u8 *pos; + + if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len) + return -1; + + if (aeskey != NULL && keylen >= CCMP_TK_LEN) + memcpy(aeskey, key->key, CCMP_TK_LEN); + + pos = skb_push(skb, CCMP_HDR_LEN); + memmove(pos, pos + CCMP_HDR_LEN, hdr_len); + pos += hdr_len; + + i = CCMP_PN_LEN - 1; + while (i >= 0) { + key->tx_pn[i]++; + if (key->tx_pn[i] != 0) + break; + i--; + } + + *pos++ = key->tx_pn[5]; + *pos++ = key->tx_pn[4]; + *pos++ = 0; + *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ; + *pos++ = key->tx_pn[3]; + *pos++ = key->tx_pn[2]; + *pos++ = key->tx_pn[1]; + *pos++ = key->tx_pn[0]; + + return CCMP_HDR_LEN; +} + +static int libipw_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_ccmp_data *key = priv; + struct ieee80211_hdr *hdr; + struct aead_request *req; + struct scatterlist sg[2]; + u8 *aad = key->tx_aad; + u8 iv[AES_BLOCK_LEN]; + int len, data_len, aad_len; + int ret; + + if (skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len) + return -1; + + data_len = skb->len - hdr_len; + len = libipw_ccmp_hdr(skb, hdr_len, NULL, 0, priv); + if (len < 0) + return -1; + + req = aead_request_alloc(key->tfm, GFP_ATOMIC); + if (!req) + return -ENOMEM; + + hdr = (struct ieee80211_hdr *)skb->data; + aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad); + + skb_put(skb, CCMP_MIC_LEN); + + sg_init_table(sg, 2); + sg_set_buf(&sg[0], aad, aad_len); + sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN, + data_len + CCMP_MIC_LEN); + + aead_request_set_callback(req, 0, NULL, NULL); + aead_request_set_ad(req, aad_len); + aead_request_set_crypt(req, sg, sg, data_len, iv); + + ret = crypto_aead_encrypt(req); + aead_request_free(req); + + return ret; +} + +/* + * deal with seq counter wrapping correctly. + * refer to timer_after() for jiffies wrapping handling + */ +static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o) +{ + u32 iv32_n, iv16_n; + u32 iv32_o, iv16_o; + + iv32_n = (pn_n[0] << 24) | (pn_n[1] << 16) | (pn_n[2] << 8) | pn_n[3]; + iv16_n = (pn_n[4] << 8) | pn_n[5]; + + iv32_o = (pn_o[0] << 24) | (pn_o[1] << 16) | (pn_o[2] << 8) | pn_o[3]; + iv16_o = (pn_o[4] << 8) | pn_o[5]; + + if ((s32)iv32_n - (s32)iv32_o < 0 || + (iv32_n == iv32_o && iv16_n <= iv16_o)) + return 1; + return 0; +} + +static int libipw_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_ccmp_data *key = priv; + u8 keyidx, *pos; + struct ieee80211_hdr *hdr; + struct aead_request *req; + struct scatterlist sg[2]; + u8 *aad = key->rx_aad; + u8 iv[AES_BLOCK_LEN]; + u8 pn[6]; + int aad_len, ret; + size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN; + + if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { + key->dot11RSNAStatsCCMPFormatErrors++; + return -1; + } + + hdr = (struct ieee80211_hdr *)skb->data; + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + net_dbg_ratelimited("CCMP: received packet without ExtIV flag from %pM\n", + hdr->addr2); + key->dot11RSNAStatsCCMPFormatErrors++; + return -2; + } + keyidx >>= 6; + if (key->key_idx != keyidx) { + net_dbg_ratelimited("CCMP: RX tkey->key_idx=%d frame keyidx=%d\n", + key->key_idx, keyidx); + return -6; + } + if (!key->key_set) { + net_dbg_ratelimited("CCMP: received packet from %pM with keyid=%d that does not have a configured key\n", + hdr->addr2, keyidx); + return -3; + } + + pn[0] = pos[7]; + pn[1] = pos[6]; + pn[2] = pos[5]; + pn[3] = pos[4]; + pn[4] = pos[1]; + pn[5] = pos[0]; + pos += 8; + + if (ccmp_replay_check(pn, key->rx_pn)) { +#ifdef CONFIG_LIBIPW_DEBUG + net_dbg_ratelimited("CCMP: replay detected: STA=%pM previous PN %02x%02x%02x%02x%02x%02x received PN %02x%02x%02x%02x%02x%02x\n", + hdr->addr2, + key->rx_pn[0], key->rx_pn[1], key->rx_pn[2], + key->rx_pn[3], key->rx_pn[4], key->rx_pn[5], + pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); +#endif + key->dot11RSNAStatsCCMPReplays++; + return -4; + } + + req = aead_request_alloc(key->tfm, GFP_ATOMIC); + if (!req) + return -ENOMEM; + + aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad); + + sg_init_table(sg, 2); + sg_set_buf(&sg[0], aad, aad_len); + sg_set_buf(&sg[1], pos, data_len); + + aead_request_set_callback(req, 0, NULL, NULL); + aead_request_set_ad(req, aad_len); + aead_request_set_crypt(req, sg, sg, data_len, iv); + + ret = crypto_aead_decrypt(req); + aead_request_free(req); + + if (ret) { + net_dbg_ratelimited("CCMP: decrypt failed: STA=%pM (%d)\n", + hdr->addr2, ret); + key->dot11RSNAStatsCCMPDecryptErrors++; + return -5; + } + + memcpy(key->rx_pn, pn, CCMP_PN_LEN); + + /* Remove hdr and MIC */ + memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, CCMP_HDR_LEN); + skb_trim(skb, skb->len - CCMP_MIC_LEN); + + return keyidx; +} + +static int libipw_ccmp_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_ccmp_data *data = priv; + int keyidx; + struct crypto_aead *tfm = data->tfm; + + keyidx = data->key_idx; + memset(data, 0, sizeof(*data)); + data->key_idx = keyidx; + data->tfm = tfm; + if (len == CCMP_TK_LEN) { + memcpy(data->key, key, CCMP_TK_LEN); + data->key_set = 1; + if (seq) { + data->rx_pn[0] = seq[5]; + data->rx_pn[1] = seq[4]; + data->rx_pn[2] = seq[3]; + data->rx_pn[3] = seq[2]; + data->rx_pn[4] = seq[1]; + 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)) + return -1; + } else if (len == 0) + data->key_set = 0; + else + return -1; + + return 0; +} + +static int libipw_ccmp_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_ccmp_data *data = priv; + + if (len < CCMP_TK_LEN) + return -1; + + if (!data->key_set) + return 0; + memcpy(key, data->key, CCMP_TK_LEN); + + if (seq) { + seq[0] = data->tx_pn[5]; + seq[1] = data->tx_pn[4]; + seq[2] = data->tx_pn[3]; + seq[3] = data->tx_pn[2]; + seq[4] = data->tx_pn[1]; + seq[5] = data->tx_pn[0]; + } + + return CCMP_TK_LEN; +} + +static void libipw_ccmp_print_stats(struct seq_file *m, void *priv) +{ + struct libipw_ccmp_data *ccmp = priv; + + seq_printf(m, + "key[%d] alg=CCMP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "format_errors=%d replays=%d decrypt_errors=%d\n", + ccmp->key_idx, ccmp->key_set, + ccmp->tx_pn[0], ccmp->tx_pn[1], ccmp->tx_pn[2], + ccmp->tx_pn[3], ccmp->tx_pn[4], ccmp->tx_pn[5], + ccmp->rx_pn[0], ccmp->rx_pn[1], ccmp->rx_pn[2], + ccmp->rx_pn[3], ccmp->rx_pn[4], ccmp->rx_pn[5], + ccmp->dot11RSNAStatsCCMPFormatErrors, + ccmp->dot11RSNAStatsCCMPReplays, + ccmp->dot11RSNAStatsCCMPDecryptErrors); +} + +static const struct libipw_crypto_ops libipw_crypt_ccmp = { + .name = "CCMP", + .init = libipw_ccmp_init, + .deinit = libipw_ccmp_deinit, + .encrypt_mpdu = libipw_ccmp_encrypt, + .decrypt_mpdu = libipw_ccmp_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = libipw_ccmp_set_key, + .get_key = libipw_ccmp_get_key, + .print_stats = libipw_ccmp_print_stats, + .extra_mpdu_prefix_len = CCMP_HDR_LEN, + .extra_mpdu_postfix_len = CCMP_MIC_LEN, + .owner = THIS_MODULE, +}; + +int __init libipw_crypto_ccmp_init(void) +{ + return libipw_register_crypto_ops(&libipw_crypt_ccmp); +} + +void libipw_crypto_ccmp_exit(void) +{ + libipw_unregister_crypto_ops(&libipw_crypt_ccmp); +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c new file mode 100644 index 00000000000000..32288697da4f53 --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c @@ -0,0 +1,728 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * libipw crypt: host-based TKIP encryption implementation for libipw + * + * Copyright (c) 2003-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libipw.h" + +#define TKIP_HDR_LEN 8 + +struct libipw_tkip_data { +#define TKIP_KEY_LEN 32 + u8 key[TKIP_KEY_LEN]; + int key_set; + + u32 tx_iv32; + u16 tx_iv16; + u16 tx_ttak[5]; + int tx_phase1_done; + + u32 rx_iv32; + u16 rx_iv16; + u16 rx_ttak[5]; + int rx_phase1_done; + u32 rx_iv32_new; + u16 rx_iv16_new; + + u32 dot11RSNAStatsTKIPReplays; + u32 dot11RSNAStatsTKIPICVErrors; + u32 dot11RSNAStatsTKIPLocalMICFailures; + + int key_idx; + + struct arc4_ctx rx_ctx_arc4; + struct arc4_ctx tx_ctx_arc4; + struct crypto_shash *rx_tfm_michael; + struct crypto_shash *tx_tfm_michael; + + /* scratch buffers for virt_to_page() (crypto API) */ + u8 rx_hdr[16], tx_hdr[16]; + + unsigned long flags; +}; + +static unsigned long libipw_tkip_set_flags(unsigned long flags, void *priv) +{ + struct libipw_tkip_data *_priv = priv; + unsigned long old_flags = _priv->flags; + _priv->flags = flags; + return old_flags; +} + +static unsigned long libipw_tkip_get_flags(void *priv) +{ + struct libipw_tkip_data *_priv = priv; + return _priv->flags; +} + +static void *libipw_tkip_init(int key_idx) +{ + struct libipw_tkip_data *priv; + + if (fips_enabled) + return NULL; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + goto fail; + + priv->key_idx = key_idx; + + priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0); + if (IS_ERR(priv->tx_tfm_michael)) { + priv->tx_tfm_michael = NULL; + goto fail; + } + + priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0); + if (IS_ERR(priv->rx_tfm_michael)) { + priv->rx_tfm_michael = NULL; + goto fail; + } + + return priv; + + fail: + if (priv) { + crypto_free_shash(priv->tx_tfm_michael); + crypto_free_shash(priv->rx_tfm_michael); + kfree(priv); + } + + return NULL; +} + +static void libipw_tkip_deinit(void *priv) +{ + struct libipw_tkip_data *_priv = priv; + if (_priv) { + crypto_free_shash(_priv->tx_tfm_michael); + crypto_free_shash(_priv->rx_tfm_michael); + } + kfree_sensitive(priv); +} + +static inline u16 RotR1(u16 val) +{ + return (val >> 1) | (val << 15); +} + +static inline u8 Lo8(u16 val) +{ + return val & 0xff; +} + +static inline u8 Hi8(u16 val) +{ + return val >> 8; +} + +static inline u16 Lo16(u32 val) +{ + return val & 0xffff; +} + +static inline u16 Hi16(u32 val) +{ + return val >> 16; +} + +static inline u16 Mk16(u8 hi, u8 lo) +{ + return lo | (((u16) hi) << 8); +} + +static inline u16 Mk16_le(__le16 * v) +{ + return le16_to_cpu(*v); +} + +static const u16 Sbox[256] = { + 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, + 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, + 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, + 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, + 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, + 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, + 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, + 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, + 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, + 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, + 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, + 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, + 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, + 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, + 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, + 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, + 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, + 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, + 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, + 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, + 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, + 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, + 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, + 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, + 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, + 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, + 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, + 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, + 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, + 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, + 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, + 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, +}; + +static inline u16 _S_(u16 v) +{ + u16 t = Sbox[Hi8(v)]; + return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); +} + +#define PHASE1_LOOP_COUNT 8 + +static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA, + u32 IV32) +{ + int i, j; + + /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ + TTAK[0] = Lo16(IV32); + TTAK[1] = Hi16(IV32); + TTAK[2] = Mk16(TA[1], TA[0]); + TTAK[3] = Mk16(TA[3], TA[2]); + TTAK[4] = Mk16(TA[5], TA[4]); + + for (i = 0; i < PHASE1_LOOP_COUNT; i++) { + j = 2 * (i & 1); + TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); + TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); + TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); + TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); + TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; + } +} + +static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK, + u16 IV16) +{ + /* Make temporary area overlap WEP seed so that the final copy can be + * avoided on little endian hosts. */ + u16 *PPK = (u16 *) & WEPSeed[4]; + + /* Step 1 - make copy of TTAK and bring in TSC */ + PPK[0] = TTAK[0]; + PPK[1] = TTAK[1]; + PPK[2] = TTAK[2]; + PPK[3] = TTAK[3]; + PPK[4] = TTAK[4]; + PPK[5] = TTAK[4] + IV16; + + /* Step 2 - 96-bit bijective mixing using S-box */ + PPK[0] += _S_(PPK[5] ^ Mk16_le((__le16 *) & TK[0])); + PPK[1] += _S_(PPK[0] ^ Mk16_le((__le16 *) & TK[2])); + PPK[2] += _S_(PPK[1] ^ Mk16_le((__le16 *) & TK[4])); + PPK[3] += _S_(PPK[2] ^ Mk16_le((__le16 *) & TK[6])); + PPK[4] += _S_(PPK[3] ^ Mk16_le((__le16 *) & TK[8])); + PPK[5] += _S_(PPK[4] ^ Mk16_le((__le16 *) & TK[10])); + + PPK[0] += RotR1(PPK[5] ^ Mk16_le((__le16 *) & TK[12])); + PPK[1] += RotR1(PPK[0] ^ Mk16_le((__le16 *) & TK[14])); + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + + /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value + * WEPSeed[0..2] is transmitted as WEP IV */ + WEPSeed[0] = Hi8(IV16); + WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; + WEPSeed[2] = Lo8(IV16); + WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((__le16 *) & TK[0])) >> 1); + +#ifdef __BIG_ENDIAN + { + int i; + for (i = 0; i < 6; i++) + PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); + } +#endif +} + +static int libipw_tkip_hdr(struct sk_buff *skb, int hdr_len, + u8 * rc4key, int keylen, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + u8 *pos; + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)skb->data; + + if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len) + return -1; + + if (rc4key == NULL || keylen < 16) + return -1; + + if (!tkey->tx_phase1_done) { + tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, + tkey->tx_iv32); + tkey->tx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); + + pos = skb_push(skb, TKIP_HDR_LEN); + memmove(pos, pos + TKIP_HDR_LEN, hdr_len); + pos += hdr_len; + + *pos++ = *rc4key; + *pos++ = *(rc4key + 1); + *pos++ = *(rc4key + 2); + *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ; + *pos++ = tkey->tx_iv32 & 0xff; + *pos++ = (tkey->tx_iv32 >> 8) & 0xff; + *pos++ = (tkey->tx_iv32 >> 16) & 0xff; + *pos++ = (tkey->tx_iv32 >> 24) & 0xff; + + tkey->tx_iv16++; + if (tkey->tx_iv16 == 0) { + tkey->tx_phase1_done = 0; + tkey->tx_iv32++; + } + + return TKIP_HDR_LEN; +} + +static int libipw_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + int len; + u8 rc4key[16], *pos, *icv; + u32 crc; + + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + net_dbg_ratelimited("TKIP countermeasures: dropped TX packet to %pM\n", + hdr->addr1); + return -1; + } + + if (skb_tailroom(skb) < 4 || skb->len < hdr_len) + return -1; + + len = skb->len - hdr_len; + pos = skb->data + hdr_len; + + if ((libipw_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) + return -1; + + crc = ~crc32_le(~0, pos, len); + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16); + arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4); + + return 0; +} + +/* + * deal with seq counter wrapping correctly. + * refer to timer_after() for jiffies wrapping handling + */ +static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n, + u32 iv32_o, u16 iv16_o) +{ + if ((s32)iv32_n - (s32)iv32_o < 0 || + (iv32_n == iv32_o && iv16_n <= iv16_o)) + return 1; + return 0; +} + +static int libipw_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + u8 rc4key[16]; + u8 keyidx, *pos; + u32 iv32; + u16 iv16; + struct ieee80211_hdr *hdr; + u8 icv[4]; + u32 crc; + int plen; + + hdr = (struct ieee80211_hdr *)skb->data; + + if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { + net_dbg_ratelimited("TKIP countermeasures: dropped received packet from %pM\n", + hdr->addr2); + return -1; + } + + if (skb->len < hdr_len + TKIP_HDR_LEN + 4) + return -1; + + pos = skb->data + hdr_len; + keyidx = pos[3]; + if (!(keyidx & (1 << 5))) { + net_dbg_ratelimited("TKIP: received packet without ExtIV flag from %pM\n", + hdr->addr2); + return -2; + } + keyidx >>= 6; + if (tkey->key_idx != keyidx) { + net_dbg_ratelimited("TKIP: RX tkey->key_idx=%d frame keyidx=%d\n", + tkey->key_idx, keyidx); + return -6; + } + if (!tkey->key_set) { + net_dbg_ratelimited("TKIP: received packet from %pM with keyid=%d that does not have a configured key\n", + hdr->addr2, keyidx); + return -3; + } + iv16 = (pos[0] << 8) | pos[2]; + iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); + pos += TKIP_HDR_LEN; + + if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { +#ifdef CONFIG_LIBIPW_DEBUG + net_dbg_ratelimited("TKIP: replay detected: STA=%pM previous TSC %08x%04x received TSC %08x%04x\n", + hdr->addr2, tkey->rx_iv32, tkey->rx_iv16, + iv32, iv16); +#endif + tkey->dot11RSNAStatsTKIPReplays++; + return -4; + } + + if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { + tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); + tkey->rx_phase1_done = 1; + } + tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); + + plen = skb->len - hdr_len - 12; + + arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16); + arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4); + + crc = ~crc32_le(~0, pos, plen); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + if (iv32 != tkey->rx_iv32) { + /* Previously cached Phase1 result was already lost, so + * it needs to be recalculated for the next packet. */ + tkey->rx_phase1_done = 0; + } +#ifdef CONFIG_LIBIPW_DEBUG + net_dbg_ratelimited("TKIP: ICV error detected: STA=%pM\n", + hdr->addr2); +#endif + tkey->dot11RSNAStatsTKIPICVErrors++; + return -5; + } + + /* Update real counters only after Michael MIC verification has + * completed */ + tkey->rx_iv32_new = iv32; + tkey->rx_iv16_new = iv16; + + /* Remove IV and ICV */ + memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len); + skb_pull(skb, TKIP_HDR_LEN); + skb_trim(skb, skb->len - 4); + + return keyidx; +} + +static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr, + u8 *data, size_t data_len, u8 *mic) +{ + SHASH_DESC_ON_STACK(desc, tfm_michael); + int err; + + if (tfm_michael == NULL) { + pr_warn("%s(): tfm_michael == NULL\n", __func__); + return -1; + } + + desc->tfm = tfm_michael; + + if (crypto_shash_setkey(tfm_michael, key, 8)) + return -1; + + err = crypto_shash_init(desc); + if (err) + goto out; + err = crypto_shash_update(desc, hdr, 16); + if (err) + goto out; + err = crypto_shash_update(desc, data, data_len); + if (err) + goto out; + err = crypto_shash_final(desc, mic); + +out: + shash_desc_zero(desc); + return err; +} + +static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) +{ + struct ieee80211_hdr *hdr11; + + hdr11 = (struct ieee80211_hdr *)skb->data; + + switch (le16_to_cpu(hdr11->frame_control) & + (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ + break; + default: + memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ + memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ + break; + } + + if (ieee80211_is_data_qos(hdr11->frame_control)) { + hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11))) + & IEEE80211_QOS_CTL_TID_MASK; + } else + hdr[12] = 0; /* priority */ + + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + +static int libipw_michael_mic_add(struct sk_buff *skb, int hdr_len, + void *priv) +{ + struct libipw_tkip_data *tkey = priv; + u8 *pos; + + if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { + printk(KERN_DEBUG "Invalid packet for Michael MIC add " + "(tailroom=%d hdr_len=%d skb->len=%d)\n", + skb_tailroom(skb), hdr_len, skb->len); + return -1; + } + + michael_mic_hdr(skb, tkey->tx_hdr); + pos = skb_put(skb, 8); + if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) + return -1; + + return 0; +} + +static void libipw_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr *hdr, + int keyidx) +{ + union iwreq_data wrqu; + struct iw_michaelmicfailure ev; + + /* TODO: needed parameters: count, keyid, key type, TSC */ + memset(&ev, 0, sizeof(ev)); + ev.flags = keyidx & IW_MICFAILURE_KEY_ID; + if (hdr->addr1[0] & 0x01) + ev.flags |= IW_MICFAILURE_GROUP; + else + ev.flags |= IW_MICFAILURE_PAIRWISE; + ev.src_addr.sa_family = ARPHRD_ETHER; + memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(ev); + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); +} + +static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx, + int hdr_len, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + u8 mic[8]; + + if (!tkey->key_set) + return -1; + + michael_mic_hdr(skb, tkey->rx_hdr); + if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, + skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) + return -1; + if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { + struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *)skb->data; + printk(KERN_DEBUG "%s: Michael MIC verification failed for " + "MSDU from %pM keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", hdr->addr2, + keyidx); + if (skb->dev) + libipw_michael_mic_failure(skb->dev, hdr, keyidx); + tkey->dot11RSNAStatsTKIPLocalMICFailures++; + return -1; + } + + /* Update TSC counters for RX now that the packet verification has + * completed. */ + tkey->rx_iv32 = tkey->rx_iv32_new; + tkey->rx_iv16 = tkey->rx_iv16_new; + + skb_trim(skb, skb->len - 8); + + return 0; +} + +static int libipw_tkip_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + int keyidx; + struct crypto_shash *tfm = tkey->tx_tfm_michael; + struct arc4_ctx *tfm2 = &tkey->tx_ctx_arc4; + struct crypto_shash *tfm3 = tkey->rx_tfm_michael; + struct arc4_ctx *tfm4 = &tkey->rx_ctx_arc4; + + keyidx = tkey->key_idx; + memset(tkey, 0, sizeof(*tkey)); + tkey->key_idx = keyidx; + tkey->tx_tfm_michael = tfm; + tkey->tx_ctx_arc4 = *tfm2; + tkey->rx_tfm_michael = tfm3; + tkey->rx_ctx_arc4 = *tfm4; + if (len == TKIP_KEY_LEN) { + memcpy(tkey->key, key, TKIP_KEY_LEN); + tkey->key_set = 1; + tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ + if (seq) { + tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | + (seq[3] << 8) | seq[2]; + tkey->rx_iv16 = (seq[1] << 8) | seq[0]; + } + } else if (len == 0) + tkey->key_set = 0; + else + return -1; + + return 0; +} + +static int libipw_tkip_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_tkip_data *tkey = priv; + + if (len < TKIP_KEY_LEN) + return -1; + + if (!tkey->key_set) + return 0; + memcpy(key, tkey->key, TKIP_KEY_LEN); + + if (seq) { + /* + * Not clear if this should return the value as is + * or - as the code previously seemed to partially + * have been written as - subtract one from it. It + * was working this way for a long time so leave it. + */ + seq[0] = tkey->tx_iv16; + seq[1] = tkey->tx_iv16 >> 8; + seq[2] = tkey->tx_iv32; + seq[3] = tkey->tx_iv32 >> 8; + seq[4] = tkey->tx_iv32 >> 16; + seq[5] = tkey->tx_iv32 >> 24; + } + + return TKIP_KEY_LEN; +} + +static void libipw_tkip_print_stats(struct seq_file *m, void *priv) +{ + struct libipw_tkip_data *tkip = priv; + seq_printf(m, + "key[%d] alg=TKIP key_set=%d " + "tx_pn=%02x%02x%02x%02x%02x%02x " + "rx_pn=%02x%02x%02x%02x%02x%02x " + "replays=%d icv_errors=%d local_mic_failures=%d\n", + tkip->key_idx, tkip->key_set, + (tkip->tx_iv32 >> 24) & 0xff, + (tkip->tx_iv32 >> 16) & 0xff, + (tkip->tx_iv32 >> 8) & 0xff, + tkip->tx_iv32 & 0xff, + (tkip->tx_iv16 >> 8) & 0xff, + tkip->tx_iv16 & 0xff, + (tkip->rx_iv32 >> 24) & 0xff, + (tkip->rx_iv32 >> 16) & 0xff, + (tkip->rx_iv32 >> 8) & 0xff, + tkip->rx_iv32 & 0xff, + (tkip->rx_iv16 >> 8) & 0xff, + tkip->rx_iv16 & 0xff, + tkip->dot11RSNAStatsTKIPReplays, + tkip->dot11RSNAStatsTKIPICVErrors, + tkip->dot11RSNAStatsTKIPLocalMICFailures); +} + +static const struct libipw_crypto_ops libipw_crypt_tkip = { + .name = "TKIP", + .init = libipw_tkip_init, + .deinit = libipw_tkip_deinit, + .encrypt_mpdu = libipw_tkip_encrypt, + .decrypt_mpdu = libipw_tkip_decrypt, + .encrypt_msdu = libipw_michael_mic_add, + .decrypt_msdu = libipw_michael_mic_verify, + .set_key = libipw_tkip_set_key, + .get_key = libipw_tkip_get_key, + .print_stats = libipw_tkip_print_stats, + .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .extra_msdu_postfix_len = 8, /* MIC */ + .get_flags = libipw_tkip_get_flags, + .set_flags = libipw_tkip_set_flags, + .owner = THIS_MODULE, +}; + +int __init libipw_crypto_tkip_init(void) +{ + return libipw_register_crypto_ops(&libipw_crypt_tkip); +} + +void libipw_crypto_tkip_exit(void) +{ + libipw_unregister_crypto_ops(&libipw_crypt_tkip); +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c new file mode 100644 index 00000000000000..c3a4ccb9de17d4 --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_wep.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * libipw crypt: host-based WEP encryption implementation for libipw + * + * Copyright (c) 2002-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libipw.h" + +struct libipw_wep_data { + u32 iv; +#define WEP_KEY_LEN 13 + u8 key[WEP_KEY_LEN + 1]; + u8 key_len; + u8 key_idx; + struct arc4_ctx tx_ctx; + struct arc4_ctx rx_ctx; +}; + +static void *libipw_wep_init(int keyidx) +{ + struct libipw_wep_data *priv; + + if (fips_enabled) + return NULL; + + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); + if (priv == NULL) + return NULL; + priv->key_idx = keyidx; + + /* start WEP IV from a random value */ + get_random_bytes(&priv->iv, 4); + + return priv; +} + +static void libipw_wep_deinit(void *priv) +{ + kfree_sensitive(priv); +} + +/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ +static int libipw_wep_build_iv(struct sk_buff *skb, int hdr_len, + u8 *key, int keylen, void *priv) +{ + struct libipw_wep_data *wep = priv; + u32 klen; + u8 *pos; + + if (skb_headroom(skb) < 4 || skb->len < hdr_len) + return -1; + + pos = skb_push(skb, 4); + memmove(pos, pos + 4, hdr_len); + pos += hdr_len; + + klen = 3 + wep->key_len; + + wep->iv++; + + /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key + * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) + * can be used to speedup attacks, so avoid using them. */ + if ((wep->iv & 0xff00) == 0xff00) { + u8 B = (wep->iv >> 16) & 0xff; + if (B >= 3 && B < klen) + wep->iv += 0x0100; + } + + /* Prepend 24-bit IV to RC4 key and TX frame */ + *pos++ = (wep->iv >> 16) & 0xff; + *pos++ = (wep->iv >> 8) & 0xff; + *pos++ = wep->iv & 0xff; + *pos++ = wep->key_idx << 6; + + return 0; +} + +/* Perform WEP encryption on given skb that has at least 4 bytes of headroom + * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, + * so the payload length increases with 8 bytes. + * + * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) + */ +static int libipw_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_wep_data *wep = priv; + u32 crc, klen, len; + u8 *pos, *icv; + u8 key[WEP_KEY_LEN + 3]; + + /* other checks are in libipw_wep_build_iv */ + if (skb_tailroom(skb) < 4) + return -1; + + /* add the IV to the frame */ + if (libipw_wep_build_iv(skb, hdr_len, NULL, 0, priv)) + return -1; + + /* Copy the IV into the first 3 bytes of the key */ + skb_copy_from_linear_data_offset(skb, hdr_len, key, 3); + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + len = skb->len - hdr_len - 4; + pos = skb->data + hdr_len + 4; + klen = 3 + wep->key_len; + + /* Append little-endian CRC32 over only the data and encrypt it to produce ICV */ + crc = ~crc32_le(~0, pos, len); + icv = skb_put(skb, 4); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + + arc4_setkey(&wep->tx_ctx, key, klen); + arc4_crypt(&wep->tx_ctx, pos, pos, len + 4); + + return 0; +} + +/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of + * the frame: IV (4 bytes), encrypted payload (including SNAP header), + * ICV (4 bytes). len includes both IV and ICV. + * + * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on + * failure. If frame is OK, IV and ICV will be removed. + */ +static int libipw_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +{ + struct libipw_wep_data *wep = priv; + u32 crc, klen, plen; + u8 key[WEP_KEY_LEN + 3]; + u8 keyidx, *pos, icv[4]; + + if (skb->len < hdr_len + 8) + return -1; + + pos = skb->data + hdr_len; + key[0] = *pos++; + key[1] = *pos++; + key[2] = *pos++; + keyidx = *pos++ >> 6; + if (keyidx != wep->key_idx) + return -1; + + klen = 3 + wep->key_len; + + /* Copy rest of the WEP key (the secret part) */ + memcpy(key + 3, wep->key, wep->key_len); + + /* Apply RC4 to data and compute CRC32 over decrypted data */ + plen = skb->len - hdr_len - 8; + + arc4_setkey(&wep->rx_ctx, key, klen); + arc4_crypt(&wep->rx_ctx, pos, pos, plen + 4); + + crc = ~crc32_le(~0, pos, plen); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + if (memcmp(icv, pos + plen, 4) != 0) { + /* ICV mismatch - drop frame */ + return -2; + } + + /* Remove IV and ICV */ + memmove(skb->data + 4, skb->data, hdr_len); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + + return 0; +} + +static int libipw_wep_set_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_wep_data *wep = priv; + + if (len < 0 || len > WEP_KEY_LEN) + return -1; + + memcpy(wep->key, key, len); + wep->key_len = len; + + return 0; +} + +static int libipw_wep_get_key(void *key, int len, u8 * seq, void *priv) +{ + struct libipw_wep_data *wep = priv; + + if (len < wep->key_len) + return -1; + + memcpy(key, wep->key, wep->key_len); + + return wep->key_len; +} + +static void libipw_wep_print_stats(struct seq_file *m, void *priv) +{ + struct libipw_wep_data *wep = priv; + seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); +} + +static const struct libipw_crypto_ops libipw_crypt_wep = { + .name = "WEP", + .init = libipw_wep_init, + .deinit = libipw_wep_deinit, + .encrypt_mpdu = libipw_wep_encrypt, + .decrypt_mpdu = libipw_wep_decrypt, + .encrypt_msdu = NULL, + .decrypt_msdu = NULL, + .set_key = libipw_wep_set_key, + .get_key = libipw_wep_get_key, + .print_stats = libipw_wep_print_stats, + .extra_mpdu_prefix_len = 4, /* IV */ + .extra_mpdu_postfix_len = 4, /* ICV */ + .owner = THIS_MODULE, +}; + +int __init libipw_crypto_wep_init(void) +{ + return libipw_register_crypto_ops(&libipw_crypt_wep); +} + +void __exit libipw_crypto_wep_exit(void) +{ + libipw_unregister_crypto_ops(&libipw_crypt_wep); +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c index 43bab92a4148f2..0a16127bfd68d3 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c @@ -169,7 +169,7 @@ struct net_device *alloc_libipw(int sizeof_priv, int monitor) spin_lock_init(&ieee->lock); - lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock); + libipw_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock); ieee->wpa_enabled = 0; ieee->drop_unencrypted = 0; @@ -191,7 +191,7 @@ void free_libipw(struct net_device *dev, int monitor) { struct libipw_device *ieee = netdev_priv(dev); - lib80211_crypt_info_free(&ieee->crypt_info); + libipw_crypt_info_free(&ieee->crypt_info); libipw_networks_free(ieee); @@ -251,6 +251,7 @@ static const struct proc_ops debug_level_proc_ops = { static int __init libipw_init(void) { + int err; #ifdef CONFIG_LIBIPW_DEBUG struct proc_dir_entry *e; @@ -273,7 +274,33 @@ static int __init libipw_init(void) printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); + err = libipw_crypto_init(); + if (err) + goto remove_debugfs; + err = libipw_crypto_ccmp_init(); + if (err) + goto uninit_crypto; + err = libipw_crypto_tkip_init(); + if (err) + goto uninit_crypto_ccmp; + err = libipw_crypto_wep_init(); + if (err) + goto uninit_crypto_tkip; + return 0; +uninit_crypto_tkip: + libipw_crypto_tkip_exit(); +uninit_crypto_ccmp: + libipw_crypto_ccmp_exit(); +uninit_crypto: + libipw_crypto_exit(); +remove_debugfs: +#ifdef CONFIG_LIBIPW_DEBUG + remove_proc_entry("debug_level", libipw_proc); + remove_proc_entry(DRV_PROCNAME, init_net.proc_net); + libipw_proc = NULL; +#endif + return err; } static void __exit libipw_exit(void) @@ -285,6 +312,11 @@ static void __exit libipw_exit(void) libipw_proc = NULL; } #endif /* CONFIG_LIBIPW_DEBUG */ + + libipw_crypto_ccmp_exit(); + libipw_crypto_tkip_exit(); + libipw_crypto_wep_exit(); + libipw_crypto_exit(); } #ifdef CONFIG_LIBIPW_DEBUG diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index 48d6870bbf4e25..dc4e91f58bb4a6 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -27,9 +27,6 @@ #include #include #include - -#include - #include "libipw.h" static void libipw_monitor_rx(struct libipw_device *ieee, @@ -266,7 +263,7 @@ static int libipw_is_eapol_frame(struct libipw_device *ieee, /* Called only as a tasklet (software IRQ), by libipw_rx */ static int libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb, - struct lib80211_crypt_data *crypt) + struct libipw_crypt_data *crypt) { struct libipw_hdr_3addr *hdr; int res, hdrlen; @@ -298,7 +295,7 @@ libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb, static int libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee, struct sk_buff *skb, int keyidx, - struct lib80211_crypt_data *crypt) + struct libipw_crypt_data *crypt) { struct libipw_hdr_3addr *hdr; int res, hdrlen; @@ -345,7 +342,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, #endif u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct lib80211_crypt_data *crypt = NULL; + struct libipw_crypt_data *crypt = NULL; int keyidx = 0; int can_be_decrypted = 0; @@ -396,7 +393,7 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, wstats.updated |= IW_QUAL_QUAL_INVALID; /* Update spy records */ - wireless_spy_update(ieee->dev, hdr->addr2, &wstats); + libipw_spy_update(ieee->dev, hdr->addr2, &wstats); } #endif /* IW_WIRELESS_SPY */ #endif /* CONFIG_WIRELESS_EXT */ @@ -870,8 +867,8 @@ void libipw_rx_any(struct libipw_device *ieee, switch (ieee->iw_mode) { case IW_MODE_ADHOC: /* our BSS and not from/to DS */ - if (ether_addr_equal(hdr->addr3, ieee->bssid)) - if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) { + if (ether_addr_equal(hdr->addr3, ieee->bssid) && + ((fc & (IEEE80211_FCTL_TODS + IEEE80211_FCTL_FROMDS)) == 0)) { /* promisc: get all */ if (ieee->dev->flags & IFF_PROMISC) is_packet_for_us = 1; @@ -885,8 +882,8 @@ void libipw_rx_any(struct libipw_device *ieee, break; case IW_MODE_INFRA: /* our BSS (== from our AP) and from DS */ - if (ether_addr_equal(hdr->addr2, ieee->bssid)) - if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) { + if (ether_addr_equal(hdr->addr2, ieee->bssid) && + ((fc & (IEEE80211_FCTL_TODS + IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS)) { /* promisc: get all */ if (ieee->dev->flags & IFF_PROMISC) is_packet_for_us = 1; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_spy.c b/drivers/net/wireless/intel/ipw2x00/libipw_spy.c new file mode 100644 index 00000000000000..ba876e92f7f6ac --- /dev/null +++ b/drivers/net/wireless/intel/ipw2x00/libipw_spy.c @@ -0,0 +1,233 @@ +/* + * This file implement the Wireless Extensions spy API. + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ + +#include +#include +#include +#include +#include +#include +#include +#include "libipw.h" + +static struct iw_spy_data *get_spydata(struct net_device *dev) +{ + struct libipw_device *ieee = netdev_priv(dev); + + if (ieee->spy_enabled) + return &ieee->spy_data; + return NULL; +} + +int ipw_wx_set_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Disable spy collection while we copy the addresses. + * While we copy addresses, any call to libipw_spy_update() + * will NOP. This is OK, as anyway the addresses are changing. */ + spydata->spy_number = 0; + + /* We want to operate without locking, because libipw_spy_update() + * most likely will happen in the interrupt handler, and therefore + * have its own locking constraints and needs performance. + * The rtnl_lock() make sure we don't race with the other iw_handlers. + * This make sure libipw_spy_update() "see" that the spy list + * is temporarily disabled. */ + smp_wmb(); + + /* Are there are addresses to copy? */ + if (wrqu->data.length > 0) { + int i; + + /* Copy addresses */ + for (i = 0; i < wrqu->data.length; i++) + memcpy(spydata->spy_address[i], address[i].sa_data, + ETH_ALEN); + /* Reset stats */ + memset(spydata->spy_stat, 0, + sizeof(struct iw_quality) * IW_MAX_SPY); + } + + /* Make sure above is updated before re-enabling */ + smp_wmb(); + + /* Enable addresses */ + spydata->spy_number = wrqu->data.length; + + return 0; +} +EXPORT_SYMBOL(ipw_wx_set_spy); + +int ipw_wx_get_spy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct sockaddr * address = (struct sockaddr *) extra; + int i; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + wrqu->data.length = spydata->spy_number; + + /* Copy addresses. */ + for (i = 0; i < spydata->spy_number; i++) { + memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); + address[i].sa_family = AF_UNIX; + } + /* Copy stats to the user buffer (just after). */ + if (spydata->spy_number > 0) + memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), + spydata->spy_stat, + sizeof(struct iw_quality) * spydata->spy_number); + /* Reset updated flags. */ + for (i = 0; i < spydata->spy_number; i++) + spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; + return 0; +} +EXPORT_SYMBOL(ipw_wx_get_spy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : set spy threshold + */ +int ipw_wx_set_thrspy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + spydata->spy_thr_low = threshold->low; + spydata->spy_thr_high = threshold->high; + + /* Clear flag */ + memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); + + return 0; +} +EXPORT_SYMBOL(ipw_wx_set_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Standard Wireless Handler : get spy threshold + */ +int ipw_wx_get_thrspy(struct net_device * dev, + struct iw_request_info * info, + union iwreq_data * wrqu, + char * extra) +{ + struct iw_spy_data * spydata = get_spydata(dev); + struct iw_thrspy * threshold = (struct iw_thrspy *) extra; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return -EOPNOTSUPP; + + /* Just do it */ + threshold->low = spydata->spy_thr_low; + threshold->high = spydata->spy_thr_high; + + return 0; +} +EXPORT_SYMBOL(ipw_wx_get_thrspy); + +/*------------------------------------------------------------------*/ +/* + * Prepare and send a Spy Threshold event + */ +static void iw_send_thrspy_event(struct net_device * dev, + struct iw_spy_data * spydata, + unsigned char * address, + struct iw_quality * wstats) +{ + union iwreq_data wrqu; + struct iw_thrspy threshold; + + /* Init */ + wrqu.data.length = 1; + wrqu.data.flags = 0; + /* Copy address */ + memcpy(threshold.addr.sa_data, address, ETH_ALEN); + threshold.addr.sa_family = ARPHRD_ETHER; + /* Copy stats */ + threshold.qual = *wstats; + /* Copy also thresholds */ + threshold.low = spydata->spy_thr_low; + threshold.high = spydata->spy_thr_high; + + /* Send event to user space */ + wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); +} + +/* ---------------------------------------------------------------- */ +/* + * Call for the driver to update the spy data. + * For now, the spy data is a simple array. As the size of the array is + * small, this is good enough. If we wanted to support larger number of + * spy addresses, we should use something more efficient... + */ +void libipw_spy_update(struct net_device * dev, + unsigned char * address, + struct iw_quality * wstats) +{ + struct iw_spy_data * spydata = get_spydata(dev); + int i; + int match = -1; + + /* Make sure driver is not buggy or using the old API */ + if (!spydata) + return; + + /* Update all records that match */ + for (i = 0; i < spydata->spy_number; i++) + if (ether_addr_equal(address, spydata->spy_address[i])) { + memcpy(&(spydata->spy_stat[i]), wstats, + sizeof(struct iw_quality)); + match = i; + } + + /* Generate an event if we cross the spy threshold. + * To avoid event storms, we have a simple hysteresis : we generate + * event only when we go under the low threshold or above the + * high threshold. */ + if (match >= 0) { + if (spydata->spy_thr_under[match]) { + if (wstats->level > spydata->spy_thr_high.level) { + spydata->spy_thr_under[match] = 0; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } else { + if (wstats->level < spydata->spy_thr_low.level) { + spydata->spy_thr_under[match] = 1; + iw_send_thrspy_event(dev, spydata, + address, wstats); + } + } + } +} diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index e22a6732a4c3f2..80edaa3dea9c88 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -138,7 +138,7 @@ static int libipw_copy_snap(u8 * data, __be16 h_proto) static int libipw_encrypt_fragment(struct libipw_device *ieee, struct sk_buff *frag, int hdr_len) { - struct lib80211_crypt_data *crypt = + struct libipw_crypt_data *crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; int res; @@ -255,7 +255,7 @@ netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev) .qos_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; - struct lib80211_crypt_data *crypt; + struct libipw_crypt_data *crypt; int priority = skb->priority; int snapped = 0; diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c index dbc7153d0a3d07..db71d81b0d4f2e 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c @@ -21,10 +21,7 @@ #include #include #include - -#include #include - #include "libipw.h" static const char *libipw_modes[] = { @@ -303,7 +300,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee, .flags = 0 }; int i, key, key_provided, len; - struct lib80211_crypt_data **crypt; + struct libipw_crypt_data **crypt; int host_crypto = ieee->host_encrypt || ieee->host_decrypt; LIBIPW_DEBUG_WX("SET_ENCODE\n"); @@ -328,7 +325,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee, if (key_provided && *crypt) { LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n", key); - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt); } else LIBIPW_DEBUG_WX("Disabling encryption.\n"); @@ -338,7 +335,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee, if (ieee->crypt_info.crypt[i] != NULL) { if (key_provided) break; - lib80211_crypt_delayed_deinit(&ieee->crypt_info, + libipw_crypt_delayed_deinit(&ieee->crypt_info, &ieee->crypt_info.crypt[i]); } } @@ -361,21 +358,21 @@ int libipw_wx_set_encode(struct libipw_device *ieee, strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm * on this key */ - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt); } if (*crypt == NULL && host_crypto) { - struct lib80211_crypt_data *new_crypt; + struct libipw_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), + new_crypt = kzalloc(sizeof(struct libipw_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; - new_crypt->ops = lib80211_get_crypto_ops("WEP"); + new_crypt->ops = libipw_get_crypto_ops("WEP"); if (!new_crypt->ops) { - request_module("lib80211_crypt_wep"); - new_crypt->ops = lib80211_get_crypto_ops("WEP"); + request_module("libipw_crypt_wep"); + new_crypt->ops = libipw_get_crypto_ops("WEP"); } if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) @@ -386,7 +383,7 @@ int libipw_wx_set_encode(struct libipw_device *ieee, new_crypt = NULL; printk(KERN_WARNING "%s: could not initialize WEP: " - "load module lib80211_crypt_wep\n", dev->name); + "load module libipw_crypt_wep\n", dev->name); return -EOPNOTSUPP; } *crypt = new_crypt; @@ -509,8 +506,8 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, int i, idx, ret = 0; int group_key = 0; const char *alg, *module; - const struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; + const struct libipw_crypto_ops *ops; + struct libipw_crypt_data **crypt; struct libipw_security sec = { .flags = 0, @@ -541,7 +538,7 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, if ((encoding->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE) { if (*crypt) - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt); for (i = 0; i < WEP_KEYS; i++) if (ieee->crypt_info.crypt[i] != NULL) @@ -567,15 +564,15 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, switch (ext->alg) { case IW_ENCODE_ALG_WEP: alg = "WEP"; - module = "lib80211_crypt_wep"; + module = "libipw_crypt_wep"; break; case IW_ENCODE_ALG_TKIP: alg = "TKIP"; - module = "lib80211_crypt_tkip"; + module = "libipw_crypt_tkip"; break; case IW_ENCODE_ALG_CCMP: alg = "CCMP"; - module = "lib80211_crypt_ccmp"; + module = "libipw_crypt_ccmp"; break; default: LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -584,10 +581,10 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, goto done; } - ops = lib80211_get_crypto_ops(alg); + ops = libipw_get_crypto_ops(alg); if (ops == NULL) { request_module(module); - ops = lib80211_get_crypto_ops(alg); + ops = libipw_get_crypto_ops(alg); } if (ops == NULL) { LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -597,9 +594,9 @@ int libipw_wx_set_encodeext(struct libipw_device *ieee, } if (*crypt == NULL || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; + struct libipw_crypt_data *new_crypt; - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); + libipw_crypt_delayed_deinit(&ieee->crypt_info, crypt); new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); if (new_crypt == NULL) { diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c index 14d2331ee6cb97..b0656b143f77a2 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.c +++ b/drivers/net/wireless/intel/iwlegacy/3945.c @@ -566,7 +566,7 @@ il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR) || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { D_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status); - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + return; } /* Convert 3945's rssi indicator to dBm */ diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index fcccde7bb65922..05c4af41bdb960 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -664,7 +664,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb) if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { D_RX("Bad CRC or FIFO: 0x%08X.\n", le32_to_cpu(rx_pkt_status)); - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + return; } /* This will be used in several places later */ diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index fa1be8c54d3c1a..cd1fe8490ae56c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,10 +10,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 93 +#define IWL_BZ_UCODE_API_MAX 94 /* Lowest firmware API version supported */ -#define IWL_BZ_UCODE_API_MIN 90 +#define IWL_BZ_UCODE_API_MIN 92 /* NVM versions */ #define IWL_BZ_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index f1dd1c29f3054d..fc5e6e44c6aafd 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,10 +10,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 93 +#define IWL_SC_UCODE_API_MAX 94 /* Lowest firmware API version supported */ -#define IWL_SC_UCODE_API_MIN 90 +#define IWL_SC_UCODE_API_MIN 92 /* NVM versions */ #define IWL_SC_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index e0b14be25b0238..769b75c3fa5b91 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -48,7 +48,7 @@ #define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IWLWIFI); +MODULE_IMPORT_NS("IWLWIFI"); /* Please keep this array *SORTED* by hex value. * Access is done through binary search. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h index 2397fdc37fc516..9b942c4aabd936 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h @@ -56,8 +56,6 @@ struct iwl_binding_cmd { } __packed; /* BINDING_CMD_API_S_VER_2 */ #define IWL_BINDING_CMD_SIZE_V1 sizeof(struct iwl_binding_cmd_v1) -#define IWL_LMAC_24G_INDEX 0 -#define IWL_LMAC_5G_INDEX 1 /* The maximal number of fragments in the FW's schedule session */ #define IWL_MVM_MAX_QUOTA 128 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h index 1fa5678c1cd6b7..a9fa5f054ce08e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h @@ -40,4 +40,7 @@ enum iwl_ctxt_action { FW_CTXT_ACTION_REMOVE, }; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ +#define IWL_LMAC_24G_INDEX 0 +#define IWL_LMAC_5G_INDEX 1 + #endif /* __iwl_fw_api_context_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index ffee7927cf26c9..c2362bc786b28f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -368,7 +368,7 @@ enum iwl_wowlan_flags { }; /** - * struct iwl_wowlan_config_cmd - WoWLAN configuration (versions 5 and 6) + * struct iwl_wowlan_config_cmd_v6 - WoWLAN configuration (versions 5 and 6) * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters * @non_qos_seq: non-QoS sequence counter to use next. * Reserved if the struct has version >= 6. @@ -380,7 +380,7 @@ enum iwl_wowlan_flags { * @sta_id: station ID for wowlan. * @reserved: reserved */ -struct iwl_wowlan_config_cmd { +struct iwl_wowlan_config_cmd_v6 { __le32 wakeup_filter; __le16 non_qos_seq; __le16 qos_seq[8]; @@ -390,7 +390,27 @@ struct iwl_wowlan_config_cmd { u8 flags; u8 sta_id; u8 reserved; -} __packed; /* WOWLAN_CONFIG_API_S_VER_5 */ +} __packed; /* WOWLAN_CONFIG_API_S_VER_6 */ + +/** + * struct iwl_wowlan_config_cmd - WoWLAN configuration + * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters + * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down + * @is_11n_connection: indicates HT connection + * @offloading_tid: TID reserved for firmware use + * @flags: extra flags, see &enum iwl_wowlan_flags + * @sta_id: station ID for wowlan. + * @reserved: reserved + */ +struct iwl_wowlan_config_cmd { + __le32 wakeup_filter; + u8 wowlan_ba_teardown_tids; + u8 is_11n_connection; + u8 offloading_tid; + u8 flags; + u8 sta_id; + u8 reserved[3]; +} __packed; /* WOWLAN_CONFIG_API_S_VER_7 */ #define IWL_NUM_RSC 16 #define WOWLAN_KEY_MAX_SIZE 32 @@ -890,7 +910,7 @@ struct iwl_wowlan_mlo_gtk { } __packed; /* WOWLAN_MLO_GTK_KEY_API_S_VER_1 */ /** - * struct iwl_wowlan_info_notif - WoWLAN information notification + * struct iwl_wowlan_info_notif_v4 - WoWLAN information notification * @gtk: GTK data * @igtk: IGTK data * @bigtk: BIGTK data @@ -910,7 +930,7 @@ struct iwl_wowlan_mlo_gtk { * @reserved2: reserved * @mlo_gtks: array of GTKs of size num_mlo_link_keys for version >= 4 */ -struct iwl_wowlan_info_notif { +struct iwl_wowlan_info_notif_v4 { struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; @@ -929,6 +949,45 @@ struct iwl_wowlan_info_notif { struct iwl_wowlan_mlo_gtk mlo_gtks[]; } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */ +/** + * struct iwl_wowlan_info_notif - WoWLAN information notification + * @gtk: GTK data + * @igtk: IGTK data + * @bigtk: BIGTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched patterns + * @qos_seq_ctr: QoS sequence counters to use next + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @tid_tear_down: bit mask of tids whose BA sessions were closed + * in suspend state + * @station_id: station id + * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs + * following this notif + * @tid_offloaded_tx: tid used by the firmware to transmit data packets + * while in wowlan + * @mlo_gtks: array of GTKs of size num_mlo_link_keys + */ +struct iwl_wowlan_info_notif { + struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 qos_seq_ctr; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + u8 tid_tear_down; + u8 station_id; + u8 num_mlo_link_keys; + u8 tid_offloaded_tx; + struct iwl_wowlan_mlo_gtk mlo_gtks[]; +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */ + /** * struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification * @wake_packet_length: wakeup packet length diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 30a54c7fa0016a..b8dff139aa05fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -616,6 +616,9 @@ struct iwl_tof_range_req_ap_entry_v2 { * continue with the session and will provide the LMR feedback. * @IWL_INITIATOR_AP_FLAGS_TEST_INCORRECT_SAC: send an incorrect SAC in the * first NDP exchange. This is used for testing. + * @IWL_INITIATOR_AP_FLAGS_TEST_BAD_SLTF: use incorrect secure LTF tx key. This + * is used for testing. Only supported from version 15 of the range request + * command. */ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_ASAP = BIT(1), @@ -633,6 +636,7 @@ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_PMF = BIT(14), IWL_INITIATOR_AP_FLAGS_TERMINATE_ON_LMR_FEEDBACK = BIT(15), IWL_INITIATOR_AP_FLAGS_TEST_INCORRECT_SAC = BIT(16), + IWL_INITIATOR_AP_FLAGS_TEST_BAD_SLTF = BIT(17), }; /** @@ -767,7 +771,7 @@ enum iwl_location_cipher { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -814,7 +818,7 @@ struct iwl_tof_range_req_ap_entry_v6 { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -827,10 +831,10 @@ struct iwl_tof_range_req_ap_entry_v6 { * &IWL_INITIATOR_AP_FLAGS_TB is set. * @rx_pn: the next expected PN for protected management frames Rx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @tx_pn: the next PN to use for protected management frames Tx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. */ struct iwl_tof_range_req_ap_entry_v7 { __le32 initiator_ap_flags; @@ -872,7 +876,7 @@ struct iwl_tof_range_req_ap_entry_v7 { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -885,10 +889,10 @@ struct iwl_tof_range_req_ap_entry_v7 { * &IWL_INITIATOR_AP_FLAGS_TB is set. * @rx_pn: the next expected PN for protected management frames Rx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @tx_pn: the next PN to use for protected management frames Tx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. * bits 0 - 2: max LTF repetitions * bits 3 - 5: max number of spatial streams @@ -946,7 +950,7 @@ struct iwl_tof_range_req_ap_entry_v8 { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -961,10 +965,10 @@ struct iwl_tof_range_req_ap_entry_v8 { * &IWL_INITIATOR_AP_FLAGS_TB or &IWL_INITIATOR_AP_FLAGS_NON_TB is set. * @rx_pn: the next expected PN for protected management frames Rx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @tx_pn: the next PN to use for protected management frames Tx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. * bits 0 - 2: max LTF repetitions * bits 3 - 5: max number of spatial streams @@ -1029,7 +1033,7 @@ struct iwl_tof_range_req_ap_entry_v9 { * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of * the number of measurement iterations (min 2^0 = 1, max 2^14) * @sta_id: the station id of the AP. Only relevant when associated to the AP, - * otherwise should be set to &IWL_MVM_INVALID_STA. + * otherwise should be set to &IWL_INVALID_STA. * @cipher: pairwise cipher suite for secured measurement. * &enum iwl_location_cipher. * @hltk: HLTK to be used for secured 11az measurement @@ -1042,10 +1046,10 @@ struct iwl_tof_range_req_ap_entry_v9 { * &IWL_INITIATOR_AP_FLAGS_TB is set. * @rx_pn: the next expected PN for protected management frames Rx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @tx_pn: the next PN to use for protected management frames Tx. LE byte * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id - * is set to &IWL_MVM_INVALID_STA. + * is set to &IWL_INVALID_STA. * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. * bits 0 - 2: max LTF repetitions * bits 3 - 5: max number of spatial streams diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index c46e24fc6a1e46..b23d5fc4bbe64e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -382,6 +382,8 @@ struct iwl_mac_config_cmd { * @LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwl_link_ctx_cfg_cmd::puncture_mask. * This flag can be set only if the MAC that this link relates to has * eht_support set to true. No longer used since _VER_3 of this command. + * @LINK_CONTEXT_MODIFY_BANDWIDTH: Covers iwl_link_ctx_cfg_cmd::modify_bandwidth. + * Request RX OMI to the AP to modify bandwidth of this link. * @LINK_CONTEXT_MODIFY_ALL: set all above flags */ enum iwl_link_ctx_modify_flags { @@ -393,6 +395,7 @@ enum iwl_link_ctx_modify_flags { LINK_CONTEXT_MODIFY_HE_PARAMS = BIT(5), LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE = BIT(6), LINK_CONTEXT_MODIFY_EHT_PARAMS = BIT(7), + LINK_CONTEXT_MODIFY_BANDWIDTH = BIT(8), LINK_CONTEXT_MODIFY_ALL = 0xff, }; /* LINK_CONTEXT_MODIFY_MASK_E_VER_1 */ @@ -433,6 +436,22 @@ enum iwl_link_ctx_flags { LINK_FLG_NDP_FEEDBACK_ENABLED = BIT(3), }; /* LINK_CONTEXT_FLAG_E_VER_1 */ +/** + * enum iwl_link_modify_bandwidth - link modify (RX OMI) bandwidth + * @IWL_LINK_MODIFY_BW_20: request 20 MHz + * @IWL_LINK_MODIFY_BW_40: request 40 MHz + * @IWL_LINK_MODIFY_BW_80: request 80 MHz + * @IWL_LINK_MODIFY_BW_160: request 160 MHz + * @IWL_LINK_MODIFY_BW_320: request 320 MHz + */ +enum iwl_link_modify_bandwidth { + IWL_LINK_MODIFY_BW_20, + IWL_LINK_MODIFY_BW_40, + IWL_LINK_MODIFY_BW_80, + IWL_LINK_MODIFY_BW_160, + IWL_LINK_MODIFY_BW_320, +}; + /** * struct iwl_link_config_cmd - command structure to configure the LINK context * in MLD API @@ -457,6 +476,8 @@ enum iwl_link_ctx_flags { * @block_tx: tell the firmware that this link can't Tx. This should be used * only when a link is de-activated because of CSA with mode = 1. * Available since version 5. + * @modify_bandwidth: bandwidth request value for RX OMI (see also + * %LINK_CONTEXT_MODIFY_BANDWIDTH), from &enum iwl_link_modify_bandwidth. * @reserved1: in version 2, listen_lmac became reserved * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM @@ -500,10 +521,11 @@ struct iwl_link_config_cmd { __le32 modify_mask; __le32 active; union { - __le32 listen_lmac; + __le32 listen_lmac; /* only _VER_1 */ struct { - u8 block_tx; - u8 reserved1[3]; + u8 block_tx; /* since _VER_5 */ + u8 modify_bandwidth; /* since _VER_6 */ + u8 reserved1[2]; }; }; __le32 cck_rates; @@ -524,7 +546,7 @@ struct iwl_link_config_cmd { __le16 puncture_mask; /* removed in _VER_3 */ __le16 frame_time_rts_th; __le32 flags; - __le32 flags_mask; + __le32 flags_mask; /* removed in _VER_6 */ /* The below fields are for multi-bssid */ u8 ref_bssid_addr[6]; __le16 reserved_for_ref_bssid_addr; @@ -535,7 +557,7 @@ struct iwl_link_config_cmd { u8 ibss_bssid_addr[6]; __le16 reserved_for_ibss_bssid_addr; __le32 reserved3[8]; -} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5 */ +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5, _VER_6 */ /* Currently FW supports link ids in the range 0-3 and can have * at most two active links for each vif. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 977ca4ac166d8c..26301c0b06a1f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -17,7 +17,7 @@ #define NUM_MAC_INDEX_CDB (NUM_MAC_INDEX_DRIVER + 2) #define IWL_STATION_COUNT_MAX 16 -#define IWL_MVM_INVALID_STA 0xFF +#define IWL_INVALID_STA 0xFF enum iwl_ac { AC_BK, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 98d56e778d99ec..f4803b55adb917 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2019, 2021-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2019, 2021-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -327,18 +327,19 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt); void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt, u32 timepoint, u32 timepoint_data); +bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id); void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt); void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt); -#define IWL_FW_CHECK_FAILED(_obj, _fmt, ...) \ - IWL_ERR_LIMIT(_obj, _fmt, __VA_ARGS__) +#define IWL_FW_CHECK_FAILED(_obj, ...) \ + IWL_ERR_LIMIT(_obj, __VA_ARGS__) #define IWL_FW_CHECK(_obj, _cond, _fmt, ...) \ ({ \ bool __cond = (_cond); \ \ if (unlikely(__cond)) \ - IWL_FW_CHECK_FAILED(_obj, _fmt, __VA_ARGS__); \ + IWL_FW_CHECK_FAILED(_obj, _fmt, ##__VA_ARGS__); \ \ unlikely(__cond); \ }) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index 8f107ceec40767..8e0c85a1240d75 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -530,3 +530,28 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) } } IWL_EXPORT_SYMBOL(iwl_fwrt_dump_error_logs); + +bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id) +{ + struct error_table_start { + /* cf. struct iwl_error_event_table */ + u32 valid; + __le32 err_id; + } err_info = {}; + int ret; + + if (!base) + return false; + + ret = iwl_trans_read_mem_bytes(trans, base, + &err_info, sizeof(err_info)); + + if (ret) + return true; + + if (err_info.valid && err_id) + *err_id = le32_to_cpu(err_info.err_id); + + return !!err_info.valid; +} +IWL_EXPORT_SYMBOL(iwl_fwrt_read_err_table); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 6a1d31892417b4..854957bdf79dcd 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -85,7 +85,7 @@ void iwl_drv_stop(struct iwl_drv *drv); * everything is built-in, then we can avoid that. */ #ifdef CONFIG_IWLWIFI_OPMODE_MODULAR -#define IWL_EXPORT_SYMBOL(sym) EXPORT_SYMBOL_NS_GPL(sym, IWLWIFI) +#define IWL_EXPORT_SYMBOL(sym) EXPORT_SYMBOL_NS_GPL(sym, "IWLWIFI") #else #define IWL_EXPORT_SYMBOL(sym) #endif diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index e95ffe3035473c..c70da7281551a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1074,12 +1074,13 @@ int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs, void iwl_trans_debugfs_cleanup(struct iwl_trans *trans); #endif -#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \ - do { \ - if (__builtin_constant_p(bufsize)) \ - BUILD_BUG_ON((bufsize) % sizeof(u32)); \ - iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\ - } while (0) +#define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \ + ({ \ + if (__builtin_constant_p(bufsize)) \ + BUILD_BUG_ON((bufsize) % sizeof(u32)); \ + iwl_trans_read_mem(trans, addr, buf, \ + (bufsize) / sizeof(u32)); \ + }) int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr, u64 src_addr, u32 byte_cnt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index b607961970e970..36726ea4b822a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -689,7 +689,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * Rssi update while not associated - can happen since the statistics * are handled asynchronously */ - if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA) + if (mvmvif->deflink.ap_sta_id == IWL_INVALID_STA) return; /* No BT - reports should be disabled */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index ddf484027d4fe6..776600ddaea6e5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -17,7 +17,9 @@ #define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC 30 #define IWL_MVM_TPT_COUNT_WINDOW_SEC 5 #define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS 5 -#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH 11 +#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH 15 +#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED 11 +#define IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH -72 #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) @@ -57,7 +59,6 @@ #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1 #define IWL_MVM_TOF_IS_RESPONDER 0 -#define IWL_MVM_HW_CSUM_DISABLE 0 #define IWL_MVM_ADWELL_ENABLE 1 #define IWL_MVM_ADWELL_MAX_BUDGET 0 #define IWL_MVM_TCM_LOAD_MEDIUM_THRESH 10 /* percentage */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 244ca8cab9d1a2..f85c01e04ebf66 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -922,7 +922,7 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm) static int iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, struct cfg80211_wowlan *wowlan, - struct iwl_wowlan_config_cmd *wowlan_config_cmd, + struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, struct ieee80211_sta *ap_sta) { @@ -948,7 +948,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); } - iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); + if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 7) + iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); if (wowlan->disconnect) wowlan_config_cmd->wakeup_filter |= @@ -1122,7 +1123,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, static int iwl_mvm_wowlan_config(struct iwl_mvm *mvm, struct cfg80211_wowlan *wowlan, - struct iwl_wowlan_config_cmd *wowlan_config_cmd, + struct iwl_wowlan_config_cmd_v6 *wowlan_config_cmd_v6, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, struct iwl_mvm_vif_link_info *mvm_link, struct ieee80211_sta *ap_sta) @@ -1131,7 +1132,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - mvm->offload_tid = wowlan_config_cmd->offloading_tid; + mvm->offload_tid = wowlan_config_cmd_v6->offloading_tid; if (!unified_image) { ret = iwl_mvm_switch_to_d3(mvm); @@ -1147,9 +1148,26 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, if (ret) return ret; - ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, - sizeof(*wowlan_config_cmd), - wowlan_config_cmd); + if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) > 6) { + struct iwl_wowlan_config_cmd wowlan_config_cmd = { + .wakeup_filter = wowlan_config_cmd_v6->wakeup_filter, + .wowlan_ba_teardown_tids = + wowlan_config_cmd_v6->wowlan_ba_teardown_tids, + .is_11n_connection = + wowlan_config_cmd_v6->is_11n_connection, + .offloading_tid = wowlan_config_cmd_v6->offloading_tid, + .flags = wowlan_config_cmd_v6->flags, + .sta_id = wowlan_config_cmd_v6->sta_id, + }; + + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, + sizeof(wowlan_config_cmd), + &wowlan_config_cmd); + } else { + ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, 0, + sizeof(*wowlan_config_cmd_v6), + wowlan_config_cmd_v6); + } if (ret) return ret; @@ -1288,7 +1306,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, goto out_noreset; } - if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) { + if (mvm_link->ap_sta_id == IWL_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) { ret = 1; @@ -1302,7 +1320,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvm->net_detect = true; } else { - struct iwl_wowlan_config_cmd wowlan_config_cmd = { + struct iwl_wowlan_config_cmd_v6 wowlan_config_cmd = { .offloading_tid = 0, }; @@ -1425,6 +1443,7 @@ struct iwl_wowlan_status_data { u16 non_qos_seq_ctr; u16 qos_seq_ctr[8]; u8 tid_tear_down; + u8 tid_offloaded_tx; struct { /* including RX MIC key for TKIP */ @@ -2474,7 +2493,64 @@ static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, struct iwl_wowlan_info_notif *data, struct iwl_wowlan_status_data *status, - u32 len, bool has_mlo_keys) + u32 len) +{ + u32 expected_len = sizeof(*data) + + data->num_mlo_link_keys * sizeof(status->mlo_keys[0]); + + if (!data) { + IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n"); + status = NULL; + return; + } + + if (len < expected_len) { + IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); + status = NULL; + return; + } + + if (mvm->fast_resume) + return; + + iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc); + iwl_mvm_convert_gtk_v3(status, data->gtk); + iwl_mvm_convert_igtk(status, &data->igtk[0]); + iwl_mvm_convert_bigtk(status, data->bigtk); + status->replay_ctr = le64_to_cpu(data->replay_ctr); + status->pattern_number = le16_to_cpu(data->pattern_number); + status->tid_offloaded_tx = data->tid_offloaded_tx; + if (IWL_FW_CHECK(mvm, + data->tid_offloaded_tx >= + ARRAY_SIZE(status->qos_seq_ctr), + "tid_offloaded_tx is out of bound %d\n", + data->tid_offloaded_tx)) + data->tid_offloaded_tx = 0; + status->qos_seq_ctr[data->tid_offloaded_tx] = + le16_to_cpu(data->qos_seq_ctr); + status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons); + status->num_of_gtk_rekeys = + le32_to_cpu(data->num_of_gtk_rekeys); + status->received_beacons = le32_to_cpu(data->received_beacons); + status->tid_tear_down = data->tid_tear_down; + + if (data->num_mlo_link_keys) { + status->num_mlo_keys = data->num_mlo_link_keys; + if (IWL_FW_CHECK(mvm, + status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, + "Too many mlo keys: %d, max %d\n", + status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) + status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; + memcpy(status->mlo_keys, data->mlo_gtks, + status->num_mlo_keys * sizeof(status->mlo_keys[0])); + } +} + +static void +iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm, + struct iwl_wowlan_info_notif_v4 *data, + struct iwl_wowlan_status_data *status, + u32 len, bool has_mlo_keys) { u32 i; u32 expected_len = sizeof(*data); @@ -2746,6 +2822,10 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int link_id = vif->active_links ? __ffs(vif->active_links) : 0; struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id]; + int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw, + PROT_OFFLOAD_GROUP, + WOWLAN_INFO_NOTIFICATION, + IWL_FW_CMD_VER_UNKNOWN); if (WARN_ON(!mvm_link)) goto out_unlock; @@ -2760,11 +2840,14 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, if (!mvm_ap_sta) goto out_unlock; - for (i = 0; i < IWL_MAX_TID_COUNT; i++) { - u16 seq = status->qos_seq_ctr[i]; - /* firmware stores last-used value, we store next value */ - seq += 0x10; - mvm_ap_sta->tid_data[i].seq_number = seq; + /* firmware stores last-used value, we store next value */ + if (wowlan_info_ver >= 5) { + mvm_ap_sta->tid_data[status->tid_offloaded_tx].seq_number = + status->qos_seq_ctr[status->tid_offloaded_tx] + 0x10; + } else { + for (i = 0; i < IWL_MAX_TID_COUNT; i++) + mvm_ap_sta->tid_data[i].seq_number = + status->qos_seq_ctr[i] + 0x10; } if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { @@ -3026,34 +3109,15 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, ieee80211_resume_disconnect(vif); } -static bool iwl_mvm_rt_status(struct iwl_trans *trans, u32 base, u32 *err_id) -{ - struct error_table_start { - /* cf. struct iwl_error_event_table */ - u32 valid; - __le32 err_id; - } err_info; - - if (!base) - return false; - - iwl_trans_read_mem_bytes(trans, base, - &err_info, sizeof(err_info)); - if (err_info.valid && err_id) - *err_id = le32_to_cpu(err_info.err_id); - - return !!err_info.valid; -} - static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { u32 err_id; /* check for lmac1 error */ - if (iwl_mvm_rt_status(mvm->trans, - mvm->trans->dbg.lmac_error_event_table[0], - &err_id)) { + if (iwl_fwrt_read_err_table(mvm->trans, + mvm->trans->dbg.lmac_error_event_table[0], + &err_id)) { if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) { struct cfg80211_wowlan_wakeup wakeup = { .rfkill_release = true, @@ -3065,13 +3129,15 @@ static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm, } /* check if we have lmac2 set and check for error */ - if (iwl_mvm_rt_status(mvm->trans, - mvm->trans->dbg.lmac_error_event_table[1], NULL)) + if (iwl_fwrt_read_err_table(mvm->trans, + mvm->trans->dbg.lmac_error_event_table[1], + NULL)) return true; /* check for umac error */ - if (iwl_mvm_rt_status(mvm->trans, - mvm->trans->dbg.umac_error_event_table, NULL)) + if (iwl_fwrt_read_err_table(mvm->trans, + mvm->trans->dbg.umac_error_event_table, + NULL)) return true; return false; @@ -3092,7 +3158,7 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm, /* if FW uses status notification, status shouldn't be NULL here */ if (!d3_data->status) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA : + u8 sta_id = mvm->net_detect ? IWL_INVALID_STA : mvmvif->deflink.ap_sta_id; /* bug - FW with MLO has status notification */ @@ -3264,13 +3330,19 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, d3_data->status, len); + } else if (wowlan_info_ver < 5) { + struct iwl_wowlan_info_notif_v4 *notif = + (void *)pkt->data; + + iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif, + d3_data->status, len, + wowlan_info_ver > 3); } else { struct iwl_wowlan_info_notif *notif = (void *)pkt->data; iwl_mvm_parse_wowlan_info_notif(mvm, notif, - d3_data->status, len, - wowlan_info_ver > 3); + d3_data->status, len); } d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO; @@ -3612,8 +3684,6 @@ void iwl_mvm_fast_suspend(struct iwl_mvm *mvm) IWL_ERR(mvm, "fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret); - WARN_ON(iwl_mvm_power_update_mac(mvm)); - ret = iwl_trans_d3_suspend(mvm->trans, false, false); if (ret) IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret); @@ -3635,22 +3705,31 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm) iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); if (iwl_mvm_check_rt_status(mvm, NULL)) { + IWL_ERR(mvm, + "iwl_mvm_check_rt_status failed, device is gone during suspend\n"); set_bit(STATUS_FW_ERROR, &mvm->trans->status); iwl_mvm_dump_nic_error_log(mvm); iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL); iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, false, 0); - return -ENODEV; + mvm->trans->state = IWL_TRANS_NO_FW; + ret = -ENODEV; + + goto out; } ret = iwl_mvm_d3_notif_wait(mvm, &d3_data); + + if (ret) { + IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret); + mvm->trans->state = IWL_TRANS_NO_FW; + } + +out: clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; mvm->fast_resume = false; - if (ret) - IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret); - return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 25f07e00db4297..fbe4e4a5085206 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -221,7 +221,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file, mvmvif->deflink.queue_params[i].uapsd); if (vif->type == NL80211_IFTYPE_STATION && - ap_sta_id != IWL_MVM_INVALID_STA) { + ap_sta_id != IWL_INVALID_STA) { struct iwl_mvm_sta *mvm_sta; mvm_sta = iwl_mvm_sta_from_staid_protected(mvm, ap_sta_id); @@ -463,11 +463,13 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, - size_t count, loff_t *ppos) +static ssize_t +iwl_dbgfs_low_latency_write_handle(struct wiphy *wiphy, struct file *file, + char *buf, size_t count, void *data) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct ieee80211_vif *vif = data; u8 value; int ret; @@ -484,12 +486,28 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, return count; } -static ssize_t -iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf, - size_t count, loff_t *ppos) +static ssize_t iwl_dbgfs_low_latency_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) { + struct ieee80211_vif *vif = file->private_data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; + char buf[10] = {}; + + return wiphy_locked_debugfs_write(mvm->hw->wiphy, file, + buf, sizeof(buf), user_buf, count, + iwl_dbgfs_low_latency_write_handle, + vif); +} + +static ssize_t +iwl_dbgfs_low_latency_force_write_handle(struct wiphy *wiphy, struct file *file, + char *buf, size_t count, void *data) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct ieee80211_vif *vif = data; u8 value; int ret; @@ -517,6 +535,22 @@ iwl_dbgfs_low_latency_force_write(struct ieee80211_vif *vif, char *buf, return count; } +static ssize_t +iwl_dbgfs_low_latency_force_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[10] = {}; + + return wiphy_locked_debugfs_write(mvm->hw->wiphy, file, + buf, sizeof(buf), user_buf, count, + iwl_dbgfs_low_latency_force_write_handle, + vif); +} + static ssize_t iwl_dbgfs_low_latency_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -831,8 +865,20 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params); MVM_DEBUGFS_READ_FILE_OPS(tx_pwr_lmt); MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32); MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(low_latency_force, 10); + +static const struct file_operations iwl_dbgfs_low_latency_ops = { + .write = iwl_dbgfs_low_latency_write, + .read = iwl_dbgfs_low_latency_read, + .open = simple_open, + .llseek = generic_file_llseek, +}; + +static const struct file_operations iwl_dbgfs_low_latency_force_ops = { + .write = iwl_dbgfs_low_latency_force_write, + .open = simple_open, + .llseek = generic_file_llseek, +}; + MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 55245f913286b9..b26141c30c61c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -559,12 +559,12 @@ static int iwl_mvm_ftm_set_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, #ifdef CONFIG_IWLWIFI_DEBUGFS if (mvmvif->ftm_unprotected) { - *sta_id = IWL_MVM_INVALID_STA; + *sta_id = IWL_INVALID_STA; *flags &= ~cpu_to_le32(IWL_INITIATOR_AP_FLAGS_PMF); } #endif } else { - *sta_id = IWL_MVM_INVALID_STA; + *sta_id = IWL_INVALID_STA; } return 0; @@ -1063,6 +1063,8 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_FW_CMD_VER_UNKNOWN); switch (cmd_ver) { + case 15: + /* Version 15 has the same struct as 14 */ case 14: err = iwl_mvm_ftm_start_v14(mvm, vif, req); break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index e4caa362f597b0..e6e468e81ab3a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -131,7 +131,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (cmd_ver == 10) { + if (cmd_ver >= 10) { cmd.band = iwl_mvm_phy_band_from_nl80211(chandef->chan->band); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index f30b0fc8eca97d..5ea684802ad174 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1401,6 +1401,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) int ret, i; struct ieee80211_supported_band *sband = NULL; + lockdep_assert_wiphy(mvm->hw->wiphy); lockdep_assert_held(&mvm->mutex); ret = iwl_trans_start_hw(mvm->trans); @@ -1484,7 +1485,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) for (i = 0; i < IWL_FW_MAX_LINK_ID + 1; i++) RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL); - mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; + mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA; /* reset quota debouncing buffer - 0xff will yield invalid data */ memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); @@ -1620,6 +1621,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) { int ret, i; + lockdep_assert_wiphy(mvm->hw->wiphy); lockdep_assert_held(&mvm->mutex); ret = iwl_trans_start_hw(mvm->trans); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 2b06521680020c..272da41567efd5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -12,6 +12,7 @@ HOW(BLOCKED_FW) \ HOW(BLOCKED_NON_BSS) \ HOW(BLOCKED_ROC) \ + HOW(BLOCKED_TMP_NON_BSS) \ HOW(EXIT_MISSED_BEACON) \ HOW(EXIT_LOW_RSSI) \ HOW(EXIT_COEX) \ @@ -360,7 +361,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, send_cmd: cmd.modify_mask = cpu_to_le32(changes); cmd.flags = cpu_to_le32(flags); - cmd.flags_mask = cpu_to_le32(flags_mask); + if (cmd_ver < 6) + cmd.flags_mask = cpu_to_le32(flags_mask); cmd.spec_link_id = link_conf->link_id; if (cmd_ver < 2) cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); @@ -1165,3 +1167,14 @@ void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (!mvmvif->esr_disable_reason) iwl_mvm_esr_unblocked(mvm, vif); } + +void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link) +{ + link->bcast_sta.sta_id = IWL_INVALID_STA; + link->mcast_sta.sta_id = IWL_INVALID_STA; + link->ap_sta_id = IWL_INVALID_STA; + + for (int r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++) + link->smps_requests[r] = + IEEE80211_SMPS_AUTOMATIC; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index a7a10e716e6517..51ee62ae70fbc9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -216,7 +216,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) .preferred_tsf = NUM_TSF_IDS, .found_vif = false, }; - int ret, i; + int ret; lockdep_assert_held(&mvm->mutex); @@ -298,9 +298,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif->time_event_data.id = TE_MAX; mvmvif->roc_activity = ROC_NUM_ACTIVITIES; - mvmvif->deflink.bcast_sta.sta_id = IWL_MVM_INVALID_STA; - mvmvif->deflink.mcast_sta.sta_id = IWL_MVM_INVALID_STA; - mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA; + iwl_mvm_init_link(&mvmvif->deflink); /* No need to allocate data queues to P2P Device MAC and NAN.*/ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) @@ -316,9 +314,6 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif->deflink.cab_queue = IWL_MVM_DQA_GCAST_QUEUE; } - for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) - mvmvif->deflink.smps_requests[i] = IEEE80211_SMPS_AUTOMATIC; - return 0; exit_fail: @@ -1605,6 +1600,7 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, 0); u8 new_notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, MISSED_BEACONS_NOTIF, 0); + struct ieee80211_bss_conf *bss_conf; /* If the firmware uses the new notification (from MAC_CONF_GROUP), * refer to that notification's version. @@ -1617,9 +1613,9 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, /* before version four the ID in the notification refers to mac ID */ if (notif_ver < 4) { vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false); + bss_conf = &vif->bss_conf; } else { - struct ieee80211_bss_conf *bss_conf = - iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, false); + bss_conf = iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, false); if (!bss_conf) return; @@ -1664,6 +1660,8 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, rx_missed_bcon, rx_missed_bcon_since_rx); } } else if (link_id >= 0 && hweight16(vif->active_links) > 1) { + u32 bss_param_ch_cnt_link_id = + bss_conf->bss_param_ch_cnt_link_id; u32 scnd_lnk_bcn_lost = 0; if (notif_ver >= 5 && @@ -1677,10 +1675,14 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, /* Exit EMLSR if we lost more than * IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH on any link. + * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED + * and the link's bss_param_ch_count has changed. */ if ((rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS && scnd_lnk_bcn_lost >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) || - rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH) + rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH || + (bss_param_ch_cnt_link_id != link_id && + rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED)) iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_MISSED_BEACON, iwl_mvm_get_primary_link(vif)); @@ -1689,6 +1691,9 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, ieee80211_beacon_loss(vif); else ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC); + + /* try to switch links, no-op if we don't have MLO */ + iwl_mvm_int_mlo_scan(mvm, vif); } iwl_dbg_tlv_time_point(&mvm->fwrt, @@ -1967,7 +1972,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, if (csa_err_mask & (CS_ERR_COUNT_ERROR | CS_ERR_LONG_DELAY_AFTER_CS | CS_ERR_TX_BLOCK_TIMER_EXPIRED)) - ieee80211_channel_switch_disconnect(vif, true); + ieee80211_channel_switch_disconnect(vif); rcu_read_unlock(); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 80b9a115245fe8..07778d55878bce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1109,7 +1109,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE; for_each_mvm_vif_valid_link(mvmvif, link_id) { - mvmvif->link[link_id]->ap_sta_id = IWL_MVM_INVALID_STA; + mvmvif->link[link_id]->ap_sta_id = IWL_INVALID_STA; mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; mvmvif->link[link_id]->phy_ctxt = NULL; mvmvif->link[link_id]->active = 0; @@ -1237,6 +1237,7 @@ int __iwl_mvm_mac_start(struct iwl_mvm *mvm) fast_resume = mvm->fast_resume; if (fast_resume) { + iwl_mvm_mei_device_state(mvm, true); ret = iwl_mvm_fast_resume(mvm); if (ret) { iwl_mvm_stop_device(mvm); @@ -1344,6 +1345,8 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) * of packets the FW sent out, so we must reconnect. */ iwl_mvm_teardown_tdls_peers(mvm); + + IWL_INFO(mvm, "restart completed\n"); } void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, @@ -1377,10 +1380,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm, bool suspend) iwl_mvm_rm_aux_sta(mvm); if (suspend && - mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { iwl_mvm_fast_suspend(mvm); - else + /* From this point on, we won't touch the device */ + iwl_mvm_mei_device_state(mvm, false); + } else { iwl_mvm_stop_device(mvm); + } iwl_mvm_async_handlers_purge(mvm); /* async_handlers_list is empty and will stay empty: HW is stopped */ @@ -1474,15 +1480,16 @@ struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) return NULL; } -int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, + struct ieee80211_bss_conf *link_conf, s16 tx_power) { u32 cmd_id = REDUCE_TX_POWER_CMD; + u32 mac_id = iwl_mvm_vif_from_mac80211(link_conf->vif)->id; int len; struct iwl_dev_tx_power_cmd_v3_v8 cmd = { .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), - .common.mac_context_id = - cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), + .common.mac_context_id = cpu_to_le32(mac_id), }; struct iwl_dev_tx_power_cmd cmd_v9_v10; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 3); @@ -1495,8 +1502,7 @@ int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (cmd_ver > 8) { /* Those fields sit on the same place for v9 and v10 */ cmd_v9_v10.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC); - cmd_v9_v10.common.mac_context_id = - cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id); + cmd_v9_v10.common.mac_context_id = cpu_to_le32(mac_id); cmd_v9_v10.common.pwr_restriction = cpu_to_le16(u_tx_power); cmd_data = &cmd_v9_v10; } @@ -1739,6 +1745,21 @@ static void iwl_mvm_unblock_esr_tpt(struct wiphy *wiphy, struct wiphy_work *wk) iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT); } +static void iwl_mvm_unblock_esr_tmp_non_bss(struct wiphy *wiphy, + struct wiphy_work *wk) +{ + struct iwl_mvm_vif *mvmvif = + container_of(wk, struct iwl_mvm_vif, + unblock_esr_tmp_non_bss_wk.work); + struct iwl_mvm *mvm = mvmvif->mvm; + struct ieee80211_vif *vif = + container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); + + mutex_lock(&mvm->mutex); + iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); + mutex_unlock(&mvm->mutex); +} + void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) { lockdep_assert_held(&mvm->mutex); @@ -1757,6 +1778,9 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) wiphy_work_init(&mvmvif->unblock_esr_tpt_wk, iwl_mvm_unblock_esr_tpt); + + wiphy_delayed_work_init(&mvmvif->unblock_esr_tmp_non_bss_wk, + iwl_mvm_unblock_esr_tmp_non_bss); } static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, @@ -1907,6 +1931,8 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, &mvmvif->mlo_int_scan_wk); wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); + wiphy_delayed_work_cancel(mvm->hw->wiphy, + &mvmvif->unblock_esr_tmp_non_bss_wk); cancel_delayed_work_sync(&mvmvif->csa_work); } @@ -2929,7 +2955,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_MVM_SMPS_REQ_PROT, IEEE80211_SMPS_DYNAMIC, 0); } - } else if (mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { + } else if (mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) { iwl_mvm_mei_host_disassociated(mvm); /* * If update fails - SF might be running in associated @@ -2965,7 +2991,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, IWL_ERR(mvm, "failed to remove AP station\n"); - mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA; + mvmvif->deflink.ap_sta_id = IWL_INVALID_STA; } /* remove quota for this interface */ @@ -3311,7 +3337,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_TXPOWER) { IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n", bss_conf->txpower); - iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower); + iwl_mvm_set_tx_power(mvm, bss_conf, bss_conf->txpower); } } @@ -3422,7 +3448,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, */ break; case STA_NOTIFY_AWAKE: - if (WARN_ON(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON(mvmsta->deflink.sta_id == IWL_INVALID_STA)) break; if (txqs) @@ -3502,6 +3528,8 @@ void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); unsigned int link_id; + lockdep_assert_wiphy(mvm->hw->wiphy); + /* * This is called before mac80211 does RCU synchronisation, * so here we already invalidate our internal RCU-protected @@ -4083,6 +4111,8 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, &mvmvif->mlo_int_scan_wk); wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); + wiphy_delayed_work_cancel(mvm->hw->wiphy, + &mvmvif->unblock_esr_tmp_non_bss_wk); /* No need for the periodic statistics anymore */ if (ieee80211_vif_is_mld(vif) && mvmvif->esr_active) @@ -4244,8 +4274,9 @@ int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) } void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); if (changed & (IEEE80211_RC_BW_CHANGED | @@ -5075,7 +5106,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | IEEE80211_CHANCTX_CHANGE_RX_CHAINS | IEEE80211_CHANCTX_CHANGE_RADAR | - IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)), + IEEE80211_CHANCTX_CHANGE_MIN_DEF)), "Cannot change PHY. Ref=%d, changed=0x%X\n", phy_ctxt->ref, changed)) return; @@ -5083,7 +5114,7 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, guard(mvm)(mvm); /* we are only changing the min_width, may be a noop */ - if (changed == IEEE80211_CHANCTX_CHANGE_MIN_WIDTH) { + if (changed == IEEE80211_CHANCTX_CHANGE_MIN_DEF) { if (phy_ctxt->width == def->width) return; @@ -6570,7 +6601,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, - .sta_rc_update = iwl_mvm_sta_rc_update, + .link_sta_rc_update = iwl_mvm_sta_rc_update, .conf_tx = iwl_mvm_mac_conf_tx, .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index 455f5f41750642..ef0be44207e1ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -396,7 +396,7 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm, u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0); if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION || - link->ap_sta_id == IWL_MVM_INVALID_STA)) + link->ap_sta_id == IWL_INVALID_STA)) return; if (!sec_key_ver) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index e252f0dcea2057..b807046144c040 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -339,33 +339,20 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, if (ret) goto out; - /* Initialize rate control for the AP station, since we might be - * doing a link switch here - we cannot initialize it before since - * this needs the phy context assigned (and in FW?), and we cannot - * do it later because it needs to be initialized as soon as we're - * able to TX on the link, i.e. when active. + /* + * if link switching (link not active yet) we'll activate it in + * firmware later on link-info change, which mac80211 guarantees + * for link switch after the stations are set up */ - if (mvmvif->ap_sta) { - struct ieee80211_link_sta *link_sta; - - rcu_read_lock(); - link_sta = rcu_dereference(mvmvif->ap_sta->link[link_id]); - - if (!WARN_ON_ONCE(!link_sta)) - iwl_mvm_rs_rate_init(mvm, vif, mvmvif->ap_sta, - link_conf, link_sta, - phy_ctxt->channel->band); - rcu_read_unlock(); + if (ieee80211_vif_link_active(vif, link_conf->link_id)) { + ret = iwl_mvm_link_changed(mvm, vif, link_conf, + LINK_CONTEXT_MODIFY_ACTIVE | + LINK_CONTEXT_MODIFY_RATES_INFO, + true); + if (ret) + goto out; } - /* then activate */ - ret = iwl_mvm_link_changed(mvm, vif, link_conf, - LINK_CONTEXT_MODIFY_ACTIVE | - LINK_CONTEXT_MODIFY_RATES_INFO, - true); - if (ret) - goto out; - if (vif->type == NL80211_IFTYPE_STATION) iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif, link_conf, @@ -783,6 +770,11 @@ iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, if (WARN_ON_ONCE(!mvmvif->link[link_conf->link_id])) return; + /* not yet marked active in vif means during link switch */ + if (!ieee80211_vif_link_active(vif, link_conf->link_id) && + vif->cfg.assoc && mvmvif->link[link_conf->link_id]->phy_ctxt) + link_changes |= LINK_CONTEXT_MODIFY_ACTIVE; + has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax; has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be; @@ -832,7 +824,7 @@ static bool iwl_mvm_mld_vif_have_valid_ap_sta(struct iwl_mvm_vif *mvmvif) int i; for_each_mvm_vif_valid_link(mvmvif, i) { - if (mvmvif->link[i]->ap_sta_id != IWL_MVM_INVALID_STA) + if (mvmvif->link[i]->ap_sta_id != IWL_INVALID_STA) return true; } @@ -859,7 +851,7 @@ static void iwl_mvm_mld_vif_delete_all_stas(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to remove AP station\n"); - link->ap_sta_id = IWL_MVM_INVALID_STA; + link->ap_sta_id = IWL_INVALID_STA; } } @@ -1046,7 +1038,7 @@ static void iwl_mvm_mld_link_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_TXPOWER) { IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n", link_conf->txpower); - iwl_mvm_set_tx_power(mvm, vif, link_conf->txpower); + iwl_mvm_set_tx_power(mvm, link_conf, link_conf->txpower); } } @@ -1177,8 +1169,6 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, int err, i; for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { - int r; - if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) break; @@ -1190,14 +1180,8 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, goto free; } - new_link[i]->bcast_sta.sta_id = IWL_MVM_INVALID_STA; - new_link[i]->mcast_sta.sta_id = IWL_MVM_INVALID_STA; - new_link[i]->ap_sta_id = IWL_MVM_INVALID_STA; new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; - - for (r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++) - new_link[i]->smps_requests[r] = - IEEE80211_SMPS_AUTOMATIC; + iwl_mvm_init_link(new_link[i]); } mutex_lock(&mvm->mutex); @@ -1388,6 +1372,36 @@ iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw, return ret; } +#define IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT (5 * HZ) + +static void iwl_mvm_mld_prep_add_interface(struct ieee80211_hw *hw, + enum nl80211_iftype type) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); + struct iwl_mvm_vif *mvmvif; + int ret; + + IWL_DEBUG_MAC80211(mvm, "prep_add_interface: type=%u\n", + type); + + if (IS_ERR_OR_NULL(bss_vif) || + !(type == NL80211_IFTYPE_AP || + type == NL80211_IFTYPE_P2P_GO || + type == NL80211_IFTYPE_P2P_CLIENT)) + return; + + mvmvif = iwl_mvm_vif_from_mac80211(bss_vif); + ret = iwl_mvm_block_esr_sync(mvm, bss_vif, + IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); + if (ret) + return; + + wiphy_delayed_work_queue(mvmvif->mvm->hw->wiphy, + &mvmvif->unblock_esr_tmp_non_bss_wk, + IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT); +} + const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .tx = iwl_mvm_mac_tx, .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, @@ -1413,7 +1427,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, - .sta_rc_update = iwl_mvm_sta_rc_update, + .link_sta_rc_update = iwl_mvm_sta_rc_update, .conf_tx = iwl_mvm_mld_mac_conf_tx, .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, @@ -1484,4 +1498,5 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .change_sta_links = iwl_mvm_mld_change_sta_links, .can_activate_links = iwl_mvm_mld_can_activate_links, .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm, + .prep_add_interface = iwl_mvm_mld_prep_add_interface, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index 28a9d90ad1cd11..01983960401131 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -146,7 +146,7 @@ int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout : mvm->trans->trans_cfg->base_params->wd_timeout; - if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA)) return -ENOSPC; if (sta->type == STATION_TYPE_AUX) @@ -346,7 +346,7 @@ static int iwl_mvm_mld_rm_int_sta(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(int_sta->sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(int_sta->sta_id == IWL_INVALID_STA)) return -EINVAL; if (flush) @@ -521,6 +521,9 @@ void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm, unsigned int link_id, bool is_in_fw) { + lockdep_assert_wiphy(mvm->hw->wiphy); + lockdep_assert_held(&mvm->mutex); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id], is_in_fw ? ERR_PTR(-EINVAL) : NULL); RCU_INIT_POINTER(mvm->fw_id_to_link_sta[mvm_sta_link->sta_id], NULL); @@ -559,7 +562,10 @@ static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm, u32 sta_id = iwl_mvm_find_free_sta_id(mvm, ieee80211_vif_type_p2p(vif)); - if (sta_id == IWL_MVM_INVALID_STA) + lockdep_assert_wiphy(mvm->hw->wiphy); + lockdep_assert_held(&mvm->mutex); + + if (sta_id == IWL_INVALID_STA) return -ENOSPC; if (rcu_access_pointer(sta->link[link_id]) == &sta->deflink) { @@ -612,10 +618,10 @@ static void iwl_mvm_mld_set_ap_sta_id(struct ieee80211_sta *sta, struct iwl_mvm_link_sta *sta_link) { if (!sta->tdls) { - WARN_ON(vif_link->ap_sta_id != IWL_MVM_INVALID_STA); + WARN_ON(vif_link->ap_sta_id != IWL_INVALID_STA); vif_link->ap_sta_id = sta_link->sta_id; } else { - WARN_ON(vif_link->ap_sta_id == IWL_MVM_INVALID_STA); + WARN_ON(vif_link->ap_sta_id == IWL_INVALID_STA); } } @@ -631,6 +637,9 @@ static int iwl_mvm_alloc_sta_after_restart(struct iwl_mvm *mvm, int ret = -EINVAL; int sta_id; + lockdep_assert_wiphy(mvm->hw->wiphy); + lockdep_assert_held(&mvm->mutex); + /* First add an empty station since allocating a queue requires * a valid station. Since we need a link_id to allocate a station, * pick up the first valid one. @@ -686,7 +695,7 @@ int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, spin_lock_init(&mvm_sta->lock); - ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_MVM_INVALID_STA, + ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_INVALID_STA, STATION_TYPE_PEER); } else { ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta); @@ -858,9 +867,10 @@ int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id) { int ret; + lockdep_assert_wiphy(mvm->hw->wiphy); lockdep_assert_held(&mvm->mutex); - if (WARN_ON(sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON(sta_id == IWL_INVALID_STA)) return 0; ret = iwl_mvm_mld_rm_sta_from_fw(mvm, sta_id); @@ -1064,6 +1074,7 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, unsigned int link_id; int ret; + lockdep_assert_wiphy(mvm->hw->wiphy); lockdep_assert_held(&mvm->mutex); for_each_set_bit(link_id, &old_links_long, @@ -1109,7 +1120,7 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, goto err; if (vif->type == NL80211_IFTYPE_STATION) - mvm_vif_link->ap_sta_id = IWL_MVM_INVALID_STA; + mvm_vif_link->ap_sta_id = IWL_INVALID_STA; iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id, false); @@ -1182,6 +1193,9 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, link_sta_added_to_fw |= BIT(link_id); iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link); + + iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta, + link_conf->chanreq.oper.chan->band); } if (sta_mask_added) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ef07cff203b0d4..2ad615293c75a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -361,6 +361,9 @@ struct iwl_mvm_vif_link_info { * @IWL_MVM_ESR_BLOCKED_NON_BSS: An active non-BSS interface's link is * preventing EMLSR * @IWL_MVM_ESR_BLOCKED_ROC: remain-on-channel is preventing EMLSR + * @IWL_MVM_ESR_BLOCKED_TMP_NON_BSS: An expected active non-BSS interface's link + * is preventing EMLSR. This is a temporary blocking that is set when there + * is an indication that a non-BSS interface is to be added. * @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons * @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR * due to low RSSI. @@ -379,6 +382,7 @@ enum iwl_mvm_esr_state { IWL_MVM_ESR_BLOCKED_FW = 0x8, IWL_MVM_ESR_BLOCKED_NON_BSS = 0x10, IWL_MVM_ESR_BLOCKED_ROC = 0x20, + IWL_MVM_ESR_BLOCKED_TMP_NON_BSS = 0x40, IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000, IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000, IWL_MVM_ESR_EXIT_COEX = 0x40000, @@ -452,6 +456,8 @@ struct iwl_mvm_esr_exit { * @prevent_esr_done_wk: work that should be done when esr prevention ends. * @mlo_int_scan_wk: work for the internal MLO scan. * @unblock_esr_tpt_wk: work for unblocking EMLSR when tpt is high enough. + * @unblock_esr_tmp_non_bss_wk: work for removing the + * IWL_MVM_ESR_BLOCKED_TMP_NON_BSS blocking for EMLSR. * @roc_activity: currently running ROC activity for this vif (or * ROC_NUM_ACTIVITIES if no activity is running). * @session_prot_connection_loss: the connection was lost due to session @@ -588,6 +594,7 @@ struct iwl_mvm_vif { struct wiphy_delayed_work prevent_esr_done_wk; struct wiphy_delayed_work mlo_int_scan_wk; struct wiphy_work unblock_esr_tpt_wk; + struct wiphy_delayed_work unblock_esr_tmp_non_bss_wk; struct iwl_mvm_vif_link_info deflink; struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -773,7 +780,6 @@ struct iwl_mvm_tcm { * @head_sn: reorder window head sn * @num_stored: number of mpdus stored in the buffer * @queue: queue of this reorder buffer - * @last_amsdu: track last ASMDU SN for duplication detection * @valid: reordering is valid for this queue * @lock: protect reorder buffer internal state */ @@ -781,7 +787,6 @@ struct iwl_mvm_reorder_buffer { u16 head_sn; u16 num_stored; int queue; - u16 last_amsdu; bool valid; spinlock_t lock; } ____cacheline_aligned_in_smp; @@ -1077,6 +1082,7 @@ struct iwl_mvm { /* data related to data path */ struct iwl_rx_phy_info last_phy_info; struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_STATION_COUNT_MAX]; + /* note: fw_id_to_link_sta must be protected by wiphy and mvm mutexes */ struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX]; u8 rx_ba_sessions; @@ -1584,8 +1590,7 @@ static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm) static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm) { return fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CSUM_SUPPORT) && - !IWL_MVM_HW_CSUM_DISABLE; + IWL_UCODE_TLV_CAPA_CSUM_SUPPORT); } static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm) @@ -2100,6 +2105,7 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band); /* Links */ +void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link); int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -2327,7 +2333,7 @@ static inline int iwl_mvm_fast_resume(struct iwl_mvm *mvm) } #endif void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, - struct iwl_wowlan_config_cmd *cmd); + struct iwl_wowlan_config_cmd_v6 *cmd); int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool disable_offloading, @@ -2914,7 +2920,7 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, bool more_data); int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value); void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed); + struct ieee80211_link_sta *link_sta, u32 changed); void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_prep_tx_info *info); @@ -2982,7 +2988,8 @@ void iwl_mvm_abort_pmsr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bool iwl_mvm_have_links_same_channel(struct iwl_mvm_vif *vif1, struct iwl_mvm_vif *vif2); bool iwl_mvm_vif_is_active(struct iwl_mvm_vif *mvmvif); -int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, +int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, + struct ieee80211_bss_conf *bss_conf, s16 tx_power); int iwl_mvm_set_hw_timestamp(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index 1eb21fe861e5fd..15d4369678a2a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -10,7 +10,7 @@ #include "mvm.h" void iwl_mvm_set_wowlan_qos_seq(struct iwl_mvm_sta *mvm_ap_sta, - struct iwl_wowlan_config_cmd *cmd) + struct iwl_wowlan_config_cmd_v6 *cmd) { int i; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 4dd4a9d5c71fc7..30fcc733395eb3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -34,7 +34,7 @@ #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IWLWIFI); +MODULE_IMPORT_NS("IWLWIFI"); static const struct iwl_op_mode_ops iwl_mvm_ops; static const struct iwl_op_mode_ops iwl_mvm_ops_mq; @@ -1505,8 +1505,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->scan_cmd_size = scan_size; /* invalidate ids to prevent accidental removal of sta_id 0 */ - mvm->aux_sta.sta_id = IWL_MVM_INVALID_STA; - mvm->snif_sta.sta_id = IWL_MVM_INVALID_STA; + mvm->aux_sta.sta_id = IWL_INVALID_STA; + mvm->snif_sta.sta_id = IWL_INVALID_STA; /* Set EBS as successful as long as not stated otherwise by the FW. */ mvm->last_ebs_successful = true; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 05715e5af6ab3a..de5ac000272e2d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -440,12 +440,6 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (!mvmsta) { - IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", - notif->sta_id); - goto out; - } - flags = le32_to_cpu(notif->flags); mvm_link_sta = rcu_dereference(mvmsta->link[link_sta->link_id]); @@ -615,11 +609,8 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, int cmd_ver; int ret; - /* Enable external EHT LTF only for GL device and if there's - * mutual support by AP and client - */ - if (CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && - sband_eht_cap && + /* Enable extra EHT LTF if there's mutual support by AP and client */ + if (sband_eht_cap && sband_eht_cap->eht_cap_elem.phy_cap_info[5] & IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF && link_sta->eht_cap.has_eht && diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 1a0b5f8d43390e..9e72db9bab4014 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -560,7 +560,8 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig, struct iwl_mvm_vif_link_info *link_info, struct ieee80211_bss_conf *bss_conf) { - struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(vif)->mvm; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; int thold = bss_conf->cqm_rssi_thold; int hyst = bss_conf->cqm_rssi_hyst; int last_event; @@ -625,6 +626,13 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig, if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) return; + /* We're not in EMLSR and our signal is bad, try to switch link maybe */ + if (sig < IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH && !mvmvif->esr_active) { + iwl_mvm_int_mlo_scan(mvm, vif); + return; + } + + /* We are in EMLSR, check if we need to exit */ exit_esr_thresh = iwl_mvm_get_esr_rssi_thresh(mvm, &bss_conf->chanreq.oper, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 65f8933c34b420..a2f16bfaec4413 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -773,9 +773,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, return false; } - rcu_read_lock(); sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1); - rcu_read_unlock(); if (IWL_FW_CHECK(mvm, tid != baid_data->tid || @@ -814,7 +812,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { if (!amsdu || last_subframe) buffer->head_sn = nssn; - /* No need to update AMSDU last SN - we are moving the head */ + spin_unlock_bh(&buffer->lock); return false; } @@ -831,7 +829,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, if (!amsdu || last_subframe) buffer->head_sn = ieee80211_sn_inc(buffer->head_sn); - /* No need to update AMSDU last SN - we are moving the head */ spin_unlock_bh(&buffer->lock); return false; } @@ -841,9 +838,6 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, __skb_queue_tail(&entries[index].frames, skb); buffer->num_stored++; - if (amsdu) - buffer->last_amsdu = sn; - /* * We cannot trust NSSN for AMSDU sub-frames that are not the last. * The reason is that NSSN advances on the first sub-frame, and may diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index ddcbd80a49fb2b..376b9b12fa6239 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -3597,7 +3597,8 @@ static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, IWL_DEBUG_SCAN(mvm, "Starting Internal MLO scan: n_channels=%zu\n", n_channels); - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) + if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) || + hweight16(vif->valid_links) == 1) return -EINVAL; size = struct_size(req, channels, n_channels); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b6c99cd6d9e5df..cd74c181c2606e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -47,7 +47,7 @@ int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm, enum nl80211_iftype iftype) lockdep_is_held(&mvm->mutex))) return sta_id; } - return IWL_MVM_INVALID_STA; + return IWL_INVALID_STA; } /* Calculate the ampdu density and max size */ @@ -1216,7 +1216,7 @@ static bool iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm, * can be unshared and finding one (and only one) that can be * reused. * This function is also invoked as a sort of clean-up task, - * in which case @alloc_for_sta is IWL_MVM_INVALID_STA. + * in which case @alloc_for_sta is IWL_INVALID_STA. * * Returns the queue number, or -ENOSPC. */ @@ -1309,7 +1309,7 @@ static int iwl_mvm_inactivity_check(struct iwl_mvm *mvm, u8 alloc_for_sta) rcu_read_unlock(); - if (free_queue >= 0 && alloc_for_sta != IWL_MVM_INVALID_STA) { + if (free_queue >= 0 && alloc_for_sta != IWL_INVALID_STA) { ret = iwl_mvm_free_inactive_queue(mvm, free_queue, queue_owner, alloc_for_sta); if (ret) @@ -1522,7 +1522,7 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) mutex_lock(&mvm->mutex); - iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); + iwl_mvm_inactivity_check(mvm, IWL_INVALID_STA); while (!list_empty(&mvm->add_stream_txqs)) { struct iwl_mvm_txq *mvmtxq; @@ -1580,7 +1580,7 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm, return 0; /* run the general cleanup/unsharing of queues */ - iwl_mvm_inactivity_check(mvm, IWL_MVM_INVALID_STA); + iwl_mvm_inactivity_check(mvm, IWL_INVALID_STA); /* Make sure we have free resources for this STA */ if (vif_type == NL80211_IFTYPE_STATION && !sta->tdls && @@ -1756,7 +1756,7 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * this function */ if (!mvm->mld_api_is_used) { - if (WARN_ON(sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON(sta_id == IWL_INVALID_STA)) return -EINVAL; mvm_sta->deflink.sta_id = sta_id; @@ -1865,7 +1865,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, else sta_id = mvm_sta->deflink.sta_id; - if (sta_id == IWL_MVM_INVALID_STA) + if (sta_id == IWL_INVALID_STA) return -ENOSPC; spin_lock_init(&mvm_sta->lock); @@ -1903,10 +1903,10 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, if (vif->type == NL80211_IFTYPE_STATION) { if (!sta->tdls) { - WARN_ON(mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA); + WARN_ON(mvmvif->deflink.ap_sta_id != IWL_INVALID_STA); mvmvif->deflink.ap_sta_id = sta_id; } else { - WARN_ON(mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA); + WARN_ON(mvmvif->deflink.ap_sta_id == IWL_INVALID_STA); } } @@ -2095,7 +2095,7 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_sec_key_remove_ap(mvm, vif, mvm_link, 0); /* unassoc - go ahead - remove the AP STA now */ - mvm_link->ap_sta_id = IWL_MVM_INVALID_STA; + mvm_link->ap_sta_id = IWL_INVALID_STA; } /* @@ -2103,7 +2103,7 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * before the STA is removed. */ if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == sta_id)) { - mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; + mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA; cancel_delayed_work(&mvm->tdls_cs.dwork); } @@ -2170,9 +2170,9 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, u8 type) { if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || - sta->sta_id == IWL_MVM_INVALID_STA) { + sta->sta_id == IWL_INVALID_STA) { sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); - if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA)) return -ENOSPC; } @@ -2188,7 +2188,7 @@ void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) { RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL); memset(sta, 0, sizeof(struct iwl_mvm_int_sta)); - sta->sta_id = IWL_MVM_INVALID_STA; + sta->sta_id = IWL_INVALID_STA; } static void iwl_mvm_enable_aux_snif_queue(struct iwl_mvm *mvm, u16 queue, @@ -2306,7 +2306,7 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(mvm->snif_sta.sta_id == IWL_INVALID_STA)) return -EINVAL; iwl_mvm_disable_txq(mvm, NULL, mvm->snif_sta.sta_id, @@ -2324,7 +2324,7 @@ int iwl_mvm_rm_aux_sta(struct iwl_mvm *mvm) lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(mvm->aux_sta.sta_id == IWL_INVALID_STA)) return -EINVAL; iwl_mvm_disable_txq(mvm, NULL, mvm->aux_sta.sta_id, @@ -2389,7 +2389,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (vif->type == NL80211_IFTYPE_ADHOC) baddr = vif->bss_conf.bssid; - if (WARN_ON_ONCE(bsta->sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(bsta->sta_id == IWL_INVALID_STA)) return -ENOSPC; ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr, @@ -2644,7 +2644,7 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, u32 status; /* This is a valid situation for GTK removal */ - if (sta_id == IWL_MVM_INVALID_STA) + if (sta_id == IWL_INVALID_STA) return 0; key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & @@ -3514,7 +3514,7 @@ static struct iwl_mvm_sta *iwl_mvm_get_key_sta(struct iwl_mvm *mvm, * station ID, then use AP's station ID. */ if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { + mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) { u8 sta_id = mvmvif->deflink.ap_sta_id; sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id], @@ -3569,7 +3569,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm, int api_ver = iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA_KEY, new_api ? 2 : 1); - if (sta_id == IWL_MVM_INVALID_STA) + if (sta_id == IWL_INVALID_STA) return -EINVAL; keyidx = (key->keyidx << STA_KEY_FLG_KEYID_POS) & @@ -3728,7 +3728,7 @@ static int iwl_mvm_send_sta_igtk(struct iwl_mvm *mvm, if (remove_key) { /* This is a valid situation for IGTK */ - if (sta_id == IWL_MVM_INVALID_STA) + if (sta_id == IWL_INVALID_STA) return 0; igtk_cmd.ctrl_flags |= cpu_to_le32(STA_KEY_NOT_VALID); @@ -3795,7 +3795,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm, return sta->addr; if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->deflink.ap_sta_id != IWL_MVM_INVALID_STA) { + mvmvif->deflink.ap_sta_id != IWL_INVALID_STA) { 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)); @@ -3865,7 +3865,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); struct iwl_mvm_sta *mvm_sta; - u8 sta_id = IWL_MVM_INVALID_STA; + u8 sta_id = IWL_INVALID_STA; int ret; static const u8 __maybe_unused zero_addr[ETH_ALEN] = {0}; @@ -3966,7 +3966,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); struct iwl_mvm_sta *mvm_sta; - u8 sta_id = IWL_MVM_INVALID_STA; + u8 sta_id = IWL_INVALID_STA; int ret, i; lockdep_assert_held(&mvm->mutex); @@ -4273,7 +4273,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, return; /* Need to block/unblock also multicast station */ - if (mvmvif->deflink.mcast_sta.sta_id != IWL_MVM_INVALID_STA) + if (mvmvif->deflink.mcast_sta.sta_id != IWL_INVALID_STA) iwl_mvm_int_sta_modify_disable_tx(mvm, mvmvif, &mvmvif->deflink.mcast_sta, disable); @@ -4282,7 +4282,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, * Only unblock the broadcast station (FW blocks it for immediate * quiet, not the driver) */ - if (!disable && mvmvif->deflink.bcast_sta.sta_id != IWL_MVM_INVALID_STA) + if (!disable && mvmvif->deflink.bcast_sta.sta_id != IWL_INVALID_STA) iwl_mvm_int_sta_modify_disable_tx(mvm, mvmvif, &mvmvif->deflink.bcast_sta, disable); @@ -4328,7 +4328,10 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, unsigned int wdg_timeout = iwl_mvm_get_wd_timeout(mvm, vif); bool mld = iwl_mvm_has_mld_api(mvm->fw); - u32 type = mld ? STATION_TYPE_PEER : IWL_STA_LINK; + u32 type = IWL_STA_LINK; + + if (mld) + type = STATION_TYPE_PEER; ret = iwl_mvm_allocate_int_sta(mvm, sta, 0, NL80211_IFTYPE_UNSPECIFIED, type); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index 3d25ff5cd7e8ab..65927ebbabb7c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -196,7 +196,7 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, mvm->tdls_cs.peer.sent_timestamp = iwl_mvm_get_systime(mvm); if (state == IWL_MVM_TDLS_SW_IDLE) - mvm->tdls_cs.cur_sta_id = IWL_MVM_INVALID_STA; + mvm->tdls_cs.cur_sta_id = IWL_INVALID_STA; } void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) @@ -250,7 +250,7 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, /* get the existing peer if it's there */ if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE && - mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) { + mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) { struct ieee80211_sta *sta = rcu_dereference_protected( mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id], lockdep_is_held(&mvm->mutex)); @@ -465,7 +465,7 @@ void iwl_mvm_tdls_ch_switch_work(struct work_struct *work) iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); /* station might be gone, in that case do nothing */ - if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) + if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA) return; sta = rcu_dereference_protected( @@ -512,7 +512,7 @@ iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw, sta->addr, chandef->chan->center_freq, chandef->width); /* we only support a single peer for channel switching */ - if (mvm->tdls_cs.peer.sta_id != IWL_MVM_INVALID_STA) { + if (mvm->tdls_cs.peer.sta_id != IWL_INVALID_STA) { IWL_DEBUG_TDLS(mvm, "Existing peer. Can't start switch with %pM\n", sta->addr); @@ -566,7 +566,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr); /* we only support a single peer for channel switching */ - if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) { + if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA) { IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr); goto out; } @@ -587,7 +587,7 @@ void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE) wait_for_phy = true; - mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; + mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA; dev_kfree_skb(mvm->tdls_cs.peer.skb); mvm->tdls_cs.peer.skb = NULL; @@ -630,7 +630,7 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE && params->status != 0 && mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT && - mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) { + mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) { struct ieee80211_sta *cur_sta; /* make sure it's the same peer */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c b/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c index 47b8e7b64ead46..1dc57e02219130 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c @@ -8,7 +8,7 @@ #include "../mvm.h" #include -MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); static struct wiphy wiphy = { .mtx = __MUTEX_INITIALIZER(wiphy.mtx), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/tests/scan.c index d3b6a57c3ebe79..7a3275199ace2e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tests/scan.c @@ -8,7 +8,7 @@ #include "../mvm.h" #include -MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); static const struct acs_average_db_case { const char *desc; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ca026b5256ce33..c9867d26361b6a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1213,7 +1213,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc)) return -1; - if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_INVALID_STA)) return -1; if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->deflink.he_cap.has_he) @@ -1357,7 +1357,7 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb, mvmsta = iwl_mvm_sta_from_mac80211(sta); - if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA)) + if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_INVALID_STA)) return -1; memcpy(&info, skb->cb, sizeof(info)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 1d1364d03f028d..dd890dcd1505f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -261,7 +261,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq) .data = { lq, }, }; - if (WARN_ON(lq->sta_id == IWL_MVM_INVALID_STA || + if (WARN_ON(lq->sta_id == IWL_INVALID_STA || iwl_mvm_has_tlc_offload(mvm))) return -EINVAL; @@ -679,10 +679,8 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm) mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bss_iface_iterator, &bss_iter_data); - if (bss_iter_data.error) { - IWL_ERR(mvm, "More than one managed interface active!\n"); + if (bss_iter_data.error) return ERR_PTR(-EINVAL); - } return bss_iter_data.vif; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 3b9943eb69341e..86f1d87a909c5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1643,6 +1643,8 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, out: if (*status == IWL_D3_STATUS_ALIVE) ret = iwl_pcie_d3_handshake(trans, false); + else + trans->state = IWL_TRANS_NO_FW; return ret; } @@ -3533,7 +3535,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, struct iwl_trans_pcie *trans_pcie, **priv; struct iwl_trans *trans; int ret, addr_size; - void __iomem * const *table; u32 bar0; /* reassign our BAR 0 if invalid due to possible runtime PM races */ @@ -3659,22 +3660,15 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, } } - ret = pcim_iomap_regions_request_all(pdev, BIT(0), DRV_NAME); + ret = pcim_request_all_regions(pdev, DRV_NAME); if (ret) { - dev_err(&pdev->dev, "pcim_iomap_regions_request_all failed\n"); - goto out_no_pci; - } - - table = pcim_iomap_table(pdev); - if (!table) { - dev_err(&pdev->dev, "pcim_iomap_table failed\n"); - ret = -ENOMEM; + dev_err(&pdev->dev, "Requesting all PCI BARs failed.\n"); goto out_no_pci; } - trans_pcie->hw_base = table[0]; + trans_pcie->hw_base = pcim_iomap(pdev, 0, 0); if (!trans_pcie->hw_base) { - dev_err(&pdev->dev, "couldn't find IO mem in first BAR\n"); + dev_err(&pdev->dev, "Could not ioremap PCI BAR 0.\n"); ret = -ENODEV; goto out_no_pci; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 9fe050f0ddc160..1ef14340953c3f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2351,6 +2351,10 @@ void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, txq_write_ptr = txq->write_ptr; spin_unlock(&txq->lock); + /* There is nothing to do if we are flushing an empty queue */ + if (is_flush && txq_write_ptr == txq_read_ptr) + goto out; + read_ptr = iwl_txq_get_cmd_index(txq, txq_read_ptr); if (!test_bit(txq_id, trans_pcie->txqs.queue_used)) { diff --git a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c index 7361b6d0cdb8e5..d0bda23c628aa6 100644 --- a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c +++ b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c @@ -9,7 +9,7 @@ #include "iwl-drv.h" #include "iwl-config.h" -MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *di) { diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index d33a994906a7bb..27f44a9f0bc1f9 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -624,7 +624,7 @@ static int p54spi_probe(struct spi_device *spi) gpio_direction_input(p54spi_gpio_irq); ret = request_irq(gpio_to_irq(p54spi_gpio_irq), - p54spi_interrupt, 0, "p54spi", + p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi", priv->spi); if (ret < 0) { dev_err(&priv->spi->dev, "request_irq() failed"); @@ -633,8 +633,6 @@ static int p54spi_probe(struct spi_device *spi) irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING); - disable_irq(gpio_to_irq(p54spi_gpio_irq)); - INIT_WORK(&priv->work, p54spi_work); init_completion(&priv->fw_comp); INIT_LIST_HEAD(&priv->tx_pending); diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig index 36b234bc5be805..caf8bc231b2e79 100644 --- a/drivers/net/wireless/marvell/libertas/Kconfig +++ b/drivers/net/wireless/marvell/libertas/Kconfig @@ -3,7 +3,6 @@ config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on USB || MMC || SPI depends on CFG80211 - select LIB80211 select FW_LOADER help A library for Marvell Libertas 8xxx devices. diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index afe9bcd3ad46d7..2e2c193716d96a 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -486,6 +486,7 @@ static int lbs_add_wps_enrollee_tlv(u8 *tlv, const u8 *ie, size_t ie_len) */ static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy, + struct net_device *dev, struct cfg80211_chan_def *chandef) { struct lbs_private *priv = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/marvell/libertas/mesh.h b/drivers/net/wireless/marvell/libertas/mesh.h index 44c4cd0230a820..e37db10e82a996 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.h +++ b/drivers/net/wireless/marvell/libertas/mesh.h @@ -7,7 +7,6 @@ #include -#include #include "host.h" #include "dev.h" diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 1cff001bdc5145..b30ed321c6251a 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -938,8 +938,10 @@ void mwifiex_process_assoc_resp(struct mwifiex_adapter *adapter) assoc_resp.links[0].bss = priv->req_bss; assoc_resp.buf = priv->assoc_rsp_buf; assoc_resp.len = priv->assoc_rsp_size; + wiphy_lock(priv->wdev.wiphy); cfg80211_rx_assoc_resp(priv->netdev, &assoc_resp); + wiphy_unlock(priv->wdev.wiphy); priv->assoc_rsp_size = 0; } } diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index d03129d5d24e3d..4a96281792cc1a 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -875,7 +875,7 @@ struct mwifiex_ietypes_chanstats { struct mwifiex_ie_types_wildcard_ssid_params { struct mwifiex_ie_types_header header; u8 max_ssid_length; - u8 ssid[1]; + u8 ssid[]; } __packed; #define TSF_DATA_SIZE 8 diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index 516159b721d34e..74747d3a379a90 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -8,7 +8,7 @@ #ifndef _MWIFIEX_IOCTL_H_ #define _MWIFIEX_IOCTL_H_ -#include +#define NUM_WEP_KEYS 4 enum { MWIFIEX_SCAN_TYPE_UNCHANGED = 0, diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index 6d8f1d1d7ca4e9..5a1a0287c1d58b 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -663,7 +663,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, bool enable_data = true; u16 cap_info, status_code, aid; const u8 *ie_ptr; - struct ieee80211_ht_operation *assoc_resp_ht_oper; if (!priv->attempted_bss_desc) { mwifiex_dbg(priv->adapter, ERROR, @@ -779,14 +778,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer, priv->assoc_rsp_size - sizeof(struct ieee_types_assoc_rsp)); - if (ie_ptr) { - assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr - + sizeof(struct ieee_types_header)); - priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param; - priv->ht_param_present = true; - } else { - priv->ht_param_present = false; - } + + priv->ht_param_present = ie_ptr ? true : false; mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: curr_pkt_filter is %#x\n", diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 96d1f6039fbca3..855019fe548582 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1679,7 +1679,8 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter) } ret = devm_request_irq(dev, adapter->irq_wakeup, - mwifiex_irq_wakeup_handler, IRQF_TRIGGER_LOW, + mwifiex_irq_wakeup_handler, + IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN, "wifi_wake", adapter); if (ret) { dev_err(dev, "Failed to request irq_wakeup %d (%d)\n", @@ -1687,7 +1688,6 @@ static void mwifiex_probe_of(struct mwifiex_adapter *adapter) goto err_exit; } - disable_irq(adapter->irq_wakeup); if (device_init_wakeup(dev, true)) { dev_err(dev, "fail to init wakeup for mwifiex\n"); goto err_exit; diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 566adce3413cb6..0674dcf7a53745 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -574,7 +573,6 @@ struct mwifiex_private { u16 listen_interval; u16 atim_window; u8 adhoc_channel; - u8 adhoc_is_link_sensed; u8 adhoc_state; struct mwifiex_802_11_security sec_info; struct mwifiex_wep_key wep_key[NUM_WEP_KEYS]; @@ -683,7 +681,6 @@ struct mwifiex_private { struct mwifiex_ds_mem_rw mem_rw; struct sk_buff_head bypass_txq; struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX]; - u8 assoc_resp_ht_param; bool ht_param_present; }; @@ -802,7 +799,6 @@ struct mwifiex_auto_tdls_peer { unsigned long rssi_jiffies; u8 failure_count; u8 do_discover; - u8 do_setup; }; #define MWIFIEX_TYPE_AGGR_DATA_V2 11 diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index b5f3821a6a8f21..400348abeee549 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -177,17 +177,14 @@ void mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code, priv->is_data_rate_auto = true; priv->data_rate = 0; - priv->assoc_resp_ht_param = 0; priv->ht_param_present = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data) mwifiex_hist_data_reset(priv); - if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { + if (priv->bss_mode == NL80211_IFTYPE_ADHOC) priv->adhoc_state = ADHOC_IDLE; - priv->adhoc_is_link_sensed = false; - } /* * Memorize the previous SSID and BSSID so @@ -843,7 +840,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_ADHOC_BCN_LOST: mwifiex_dbg(adapter, EVENT, "event: ADHOC_BCN_LOST\n"); - priv->adhoc_is_link_sensed = false; mwifiex_clean_txrx(priv); mwifiex_stop_net_dev_queue(priv->netdev, adapter); if (netif_carrier_ok(priv->netdev)) diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index d3cba6895f8ce4..e06a0622973e72 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -351,8 +351,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, goto done; } - priv->adhoc_is_link_sensed = false; - ret = mwifiex_check_network_compatibility(priv, bss_desc); mwifiex_stop_net_dev_queue(priv->netdev, adapter); diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index 7823e67694e888..0a5f340876c3b0 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -1306,7 +1306,6 @@ int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb) peer->mac_addr, NL80211_TDLS_SETUP, 0, GFP_ATOMIC); - peer->do_setup = false; priv->check_tdls_tx = false; } else if (peer->failure_count < MWIFIEX_TDLS_MAX_FAIL_COUNT && @@ -1465,7 +1464,6 @@ void mwifiex_check_auto_tdls(struct timer_list *t) tdls_peer->failure_count < MWIFIEX_TDLS_MAX_FAIL_COUNT) { priv->check_tdls_tx = true; - tdls_peer->do_setup = true; mwifiex_dbg(priv->adapter, INFO, "check TDLS with peer=%pM\t" "rssi=%d\n", tdls_peer->mac_addr, diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 42c04bf858da37..1f1f6280a0f251 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -494,7 +494,9 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv, } } + wiphy_lock(priv->wdev.wiphy); cfg80211_rx_mlme_mgmt(priv->netdev, skb->data, pkt_len); + wiphy_unlock(priv->wdev.wiphy); } if (priv->adapter->host_mlme_enabled && diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c index ec02148a7f1f74..08590aa68356f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c @@ -71,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2); struct platform_driver mt76_wmac_driver = { .probe = mt76_wmac_probe, - .remove_new = mt76_wmac_remove, + .remove = mt76_wmac_remove, .driver = { .name = "mt76_wmac", .of_match_table = of_wmac_match, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c index 12e3e4a91d2748..06a0f2a141e8c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c @@ -63,7 +63,7 @@ struct platform_driver mt7622_wmac_driver = { .of_match_table = mt7622_wmac_of_match, }, .probe = mt7622_wmac_probe, - .remove_new = mt7622_wmac_remove, + .remove = mt7622_wmac_remove, }; MODULE_FIRMWARE(MT7622_FIRMWARE_N9); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index d75e8dea1fbdc8..c6f498fc81ffdc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -1163,9 +1163,10 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta) static void mt7915_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = phy->dev; struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; @@ -1709,7 +1710,7 @@ const struct ieee80211_ops mt7915_ops = { .stop_ap = mt7915_stop_ap, .sta_state = mt76_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, - .sta_rc_update = mt7915_sta_rc_update, + .link_sta_rc_update = mt7915_sta_rc_update, .set_key = mt7915_set_key, .ampdu_action = mt7915_ampdu_action, .set_rts_threshold = mt7915_set_rts_threshold, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index 90a6f61d10892b..c823a7554a3ac6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -1303,7 +1303,7 @@ struct platform_driver mt798x_wmac_driver = { .of_match_table = mt798x_wmac_of_match, }, .probe = mt798x_wmac_probe, - .remove_new = mt798x_wmac_remove, + .remove = mt798x_wmac_remove, }; MODULE_FIRMWARE(MT7986_FIRMWARE_WA); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 39f071ece35e6e..2b34ae5e0cb57b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -1060,9 +1060,10 @@ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) static void mt7996_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct mt7996_phy *phy = mt7996_hw_phy(hw); struct mt7996_dev *dev = phy->dev; @@ -1472,7 +1473,7 @@ const struct ieee80211_ops mt7996_ops = { .sta_add = mt7996_sta_add, .sta_remove = mt7996_sta_remove, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, - .sta_rc_update = mt7996_sta_rc_update, + .link_sta_rc_update = mt7996_sta_rc_update, .set_key = mt7996_set_key, .ampdu_action = mt7996_ampdu_action, .set_rts_threshold = mt7996_set_rts_threshold, diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index eb37b228d54ea0..e96736cc7259b9 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -231,6 +231,7 @@ struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) } static int set_channel(struct wiphy *wiphy, + struct net_device *dev, struct cfg80211_chan_def *chandef) { struct wilc *wl = wiphy_priv(wiphy); @@ -1424,7 +1425,7 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev, struct wilc_vif *vif = netdev_priv(dev); int ret; - ret = set_channel(wiphy, &settings->chandef); + ret = set_channel(wiphy, dev, &settings->chandef); if (ret != 0) netdev_err(dev, "Error in setting channel\n"); @@ -1757,57 +1758,10 @@ void wlan_deinit_locks(struct wilc *wilc) cleanup_srcu_struct(&wilc->srcu); } -int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, - const struct wilc_hif_func *ops) -{ - struct wilc *wl; - int ret, i; - - wl = wilc_create_wiphy(dev); - if (!wl) - return -EINVAL; - - wlan_init_locks(wl); - - ret = wilc_wlan_cfg_init(wl); - if (ret) - goto free_wl; - - *wilc = wl; - wl->io_type = io_type; - wl->hif_func = ops; - - for (i = 0; i < NQUEUES; i++) - INIT_LIST_HEAD(&wl->txq[i].txq_head.list); - - INIT_LIST_HEAD(&wl->rxq_head.list); - INIT_LIST_HEAD(&wl->vif_list); - - wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, - wiphy_name(wl->wiphy)); - if (!wl->hif_workqueue) { - ret = -ENOMEM; - goto free_cfg; - } - - return 0; - -free_cfg: - wilc_wlan_cfg_deinit(wl); - -free_wl: - wlan_deinit_locks(wl); - wiphy_unregister(wl->wiphy); - wiphy_free(wl->wiphy); - return ret; -} -EXPORT_SYMBOL_GPL(wilc_cfg80211_init); - -struct wilc *wilc_create_wiphy(struct device *dev) +static struct wilc *wilc_create_wiphy(struct device *dev) { struct wiphy *wiphy; struct wilc *wl; - int ret; wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl)); if (!wiphy) @@ -1850,17 +1804,66 @@ struct wilc *wilc_create_wiphy(struct device *dev) BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT); wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - wiphy->features |= NL80211_FEATURE_SAE; set_wiphy_dev(wiphy, dev); wl->wiphy = wiphy; - ret = wiphy_register(wiphy); - if (ret) { - wiphy_free(wiphy); - return NULL; - } return wl; } +int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, + const struct wilc_hif_func *ops) +{ + struct wilc *wl; + int ret, i; + + wl = wilc_create_wiphy(dev); + if (!wl) + return -EINVAL; + + wlan_init_locks(wl); + + ret = wilc_wlan_cfg_init(wl); + if (ret) + goto free_wl; + + *wilc = wl; + wl->io_type = io_type; + wl->hif_func = ops; + + for (i = 0; i < NQUEUES; i++) + INIT_LIST_HEAD(&wl->txq[i].txq_head.list); + + INIT_LIST_HEAD(&wl->rxq_head.list); + INIT_LIST_HEAD(&wl->vif_list); + + wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, + wiphy_name(wl->wiphy)); + if (!wl->hif_workqueue) { + ret = -ENOMEM; + goto free_cfg; + } + + return 0; + +free_cfg: + wilc_wlan_cfg_deinit(wl); + +free_wl: + wlan_deinit_locks(wl); + wiphy_free(wl->wiphy); + return ret; +} +EXPORT_SYMBOL_GPL(wilc_cfg80211_init); + +int wilc_cfg80211_register(struct wilc *wilc) +{ + /* WPA3/SAE supported only on WILC1000 */ + if (is_wilc1000(wilc->chipid)) + wilc->wiphy->features |= NL80211_FEATURE_SAE; + + return wiphy_register(wilc->wiphy); +} +EXPORT_SYMBOL_GPL(wilc_cfg80211_register); + int wilc_init_host_int(struct net_device *net) { int ret; diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.h b/drivers/net/wireless/microchip/wilc1000/cfg80211.h index 8c65951cfaf964..2dc9c1c42d6096 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.h +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.h @@ -10,7 +10,7 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, const struct wilc_hif_func *ops); -struct wilc *wilc_create_wiphy(struct device *dev); +int wilc_cfg80211_register(struct wilc *wilc); void wilc_deinit_host_int(struct net_device *net); int wilc_init_host_int(struct net_device *net); void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 9ecf3fb29b558f..7e84fc0fd91188 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -23,6 +23,12 @@ #define __WILC1000_FW(api) WILC1000_FW_PREFIX #api ".bin" #define WILC1000_FW(api) __WILC1000_FW(api) +#define WILC3000_API_VER 1 + +#define WILC3000_FW_PREFIX "atmel/wilc3000_wifi_firmware-" +#define __WILC3000_FW(api) WILC3000_FW_PREFIX #api ".bin" +#define WILC3000_FW(api) __WILC3000_FW(api) + static irqreturn_t isr_uh_routine(int irq, void *user_data) { struct wilc *wilc = user_data; @@ -195,20 +201,24 @@ static int wilc_wlan_get_firmware(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; - int chip_id; const struct firmware *wilc_fw; + char *firmware; int ret; - chip_id = wilc_get_chipid(wilc, false); + if (is_wilc1000(wilc->chipid)) + firmware = WILC1000_FW(WILC1000_API_VER); + else if (is_wilc3000(wilc->chipid)) + firmware = WILC3000_FW(WILC3000_API_VER); + else + return -EINVAL; - netdev_info(dev, "ChipID [%x] loading firmware [%s]\n", chip_id, - WILC1000_FW(WILC1000_API_VER)); + netdev_info(dev, "WILC%d loading firmware [%s]\n", + is_wilc1000(wilc->chipid) ? 1000 : 3000, + firmware); - ret = request_firmware(&wilc_fw, WILC1000_FW(WILC1000_API_VER), - wilc->dev); + ret = request_firmware(&wilc_fw, firmware, wilc->dev); if (ret != 0) { - netdev_err(dev, "%s - firmware not available\n", - WILC1000_FW(WILC1000_API_VER)); + netdev_err(dev, "%s - firmware not available\n", firmware); return -EINVAL; } wilc->firmware = wilc_fw; @@ -233,7 +243,7 @@ static int wilc_start_firmware(struct net_device *dev) return 0; } -static int wilc1000_firmware_download(struct net_device *dev) +static int wilc_firmware_download(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; @@ -528,7 +538,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif) if (ret) goto fail_irq_enable; - ret = wilc1000_firmware_download(dev); + ret = wilc_firmware_download(dev); if (ret) goto fail_irq_enable; @@ -608,6 +618,9 @@ static int wilc_mac_open(struct net_device *ndev) return ret; } + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype, + vif->idx); + netdev_dbg(ndev, "Mac address: %pM\n", ndev->dev_addr); ret = wilc_set_mac_address(vif, ndev->dev_addr); if (ret) { @@ -618,9 +631,6 @@ static int wilc_mac_open(struct net_device *ndev) return ret; } - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype, - vif->idx); - mgmt_regs.interface_stypes = vif->mgmt_reg_stypes; /* so we detect a change */ vif->mgmt_reg_stypes = 0; @@ -1014,3 +1024,4 @@ EXPORT_SYMBOL_GPL(wilc_netdev_ifc_init); MODULE_DESCRIPTION("Atmel WILC1000 core wireless driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER)); +MODULE_FIRMWARE(WILC3000_FW(WILC3000_API_VER)); diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c index b4da05d5a498a0..5262c8846c13df 100644 --- a/drivers/net/wireless/microchip/wilc1000/sdio.c +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -182,6 +182,14 @@ static int wilc_sdio_probe(struct sdio_func *func, wilc_sdio_init(wilc, false); + ret = wilc_get_chipid(wilc); + if (ret) + goto dispose_irq; + + ret = wilc_cfg80211_register(wilc); + if (ret) + goto dispose_irq; + ret = wilc_load_mac_from_nv(wilc); if (ret) { pr_err("Can not retrieve MAC address from chip\n"); @@ -667,7 +675,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume) struct wilc_sdio *sdio_priv = wilc->bus_data; struct sdio_cmd52 cmd; int loop, ret; - u32 chipid; /** * function 0 csa enable @@ -756,18 +763,6 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume) return ret; } - /** - * make sure can read back chip id correctly - **/ - if (!resume) { - ret = wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid); - if (ret) { - dev_err(&func->dev, "Fail cmd read chip id...\n"); - return ret; - } - dev_err(&func->dev, "chipid (%08x)\n", chipid); - } - sdio_priv->isinit = true; return 0; } @@ -815,13 +810,19 @@ static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status) cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG; } else { cmd.function = 0; - cmd.address = WILC_SDIO_IRQ_FLAG_REG; + cmd.address = is_wilc1000(wilc->chipid) ? + WILC1000_SDIO_IRQ_FLAG_REG : + WILC3000_SDIO_IRQ_FLAG_REG; } cmd.raw = 0; cmd.read_write = 0; cmd.data = 0; wilc_sdio_cmd52(wilc, &cmd); irq_flags = cmd.data; + + if (sdio_priv->irq_gpio) + irq_flags &= is_wilc1000(wilc->chipid) ? 0x1f : 0x0f; + tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data); if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags)) @@ -843,22 +844,56 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val) if (sdio_priv->irq_gpio) reg = val & (BIT(MAX_NUM_INT) - 1); - /* select VMM table 0 */ - if (val & SEL_VMM_TBL0) - reg |= BIT(5); - /* select VMM table 1 */ - if (val & SEL_VMM_TBL1) - reg |= BIT(6); - /* enable VMM */ - if (val & EN_VMM) - reg |= BIT(7); + if (is_wilc1000(wilc->chipid)) { + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(5); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(6); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(7); + } else { + if (sdio_priv->irq_gpio && reg) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC3000_SDIO_IRQ_FLAG_REG; + cmd.data = reg; + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set 0xfe data (%d) ...\n", + __LINE__); + return ret; + } + } + + reg = 0; + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(0); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(1); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(2); + } + if (reg) { struct sdio_cmd52 cmd; cmd.read_write = 1; cmd.function = 0; cmd.raw = 0; - cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG; + cmd.address = is_wilc1000(wilc->chipid) ? + WILC1000_SDIO_IRQ_CLEAR_FLAG_REG : + WILC3000_SDIO_VMM_TBL_CTRL_REG; cmd.data = reg; ret = wilc_sdio_cmd52(wilc, &cmd); @@ -979,17 +1014,15 @@ static int wilc_sdio_suspend(struct device *dev) if (!IS_ERR(wilc->rtc_clk)) clk_disable_unprepare(wilc->rtc_clk); - host_sleep_notify(wilc); - - wilc_sdio_disable_interrupt(wilc); - - ret = wilc_sdio_reset(wilc); + ret = host_sleep_notify(wilc); if (ret) { - dev_err(&func->dev, "Fail reset sdio\n"); + clk_prepare_enable(wilc->rtc_clk); return ret; } - return 0; + wilc_sdio_disable_interrupt(wilc); + + return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); } static int wilc_sdio_resume(struct device *dev) @@ -1008,9 +1041,7 @@ static int wilc_sdio_resume(struct device *dev) wilc_sdio_init(wilc, true); wilc_sdio_enable_interrupt(wilc); - host_wakeup_notify(wilc); - - return 0; + return host_wakeup_notify(wilc); } static const struct of_device_id wilc_of_match[] = { diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c index 05b577b1068ea3..ce2a9cdd6aa787 100644 --- a/drivers/net/wireless/microchip/wilc1000/spi.c +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -245,7 +245,11 @@ static int wilc_bus_probe(struct spi_device *spi) if (ret) goto power_down; - ret = wilc_validate_chipid(wilc); + ret = wilc_get_chipid(wilc); + if (ret) + goto power_down; + + ret = wilc_cfg80211_register(wilc); if (ret) goto power_down; @@ -1229,7 +1233,7 @@ static int wilc_validate_chipid(struct wilc *wilc) dev_err(&spi->dev, "Fail cmd read chip id...\n"); return ret; } - if (!is_wilc1000(chipid)) { + if (!is_wilc1000(chipid) && !is_wilc3000(chipid)) { dev_err(&spi->dev, "Unknown chip id 0x%x\n", chipid); return -ENODEV; } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 533939e71534a0..9d80adc45d6be1 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -12,20 +12,6 @@ #define WAKE_UP_TRIAL_RETRY 10000 -static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire) -{ - mutex_lock(&wilc->hif_cs); - if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) - chip_wakeup(wilc); -} - -static inline void release_bus(struct wilc *wilc, enum bus_release release) -{ - if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode) - chip_allow_sleep(wilc); - mutex_unlock(&wilc->hif_cs); -} - static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num, struct txq_entry_t *tqe) { @@ -555,7 +541,7 @@ static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc) return rqe; } -void chip_allow_sleep(struct wilc *wilc) +static int chip_allow_sleep_wilc1000(struct wilc *wilc) { u32 reg = 0; const struct wilc_hif_func *hif_func = wilc->hif_func; @@ -584,7 +570,7 @@ void chip_allow_sleep(struct wilc *wilc) while (--trials) { ret = hif_func->hif_read_reg(wilc, to_host_from_fw_reg, ®); if (ret) - return; + return ret; if ((reg & to_host_from_fw_bit) == 0) break; } @@ -594,28 +580,62 @@ void chip_allow_sleep(struct wilc *wilc) /* Clear bit 1 */ ret = hif_func->hif_read_reg(wilc, wakeup_reg, ®); if (ret) - return; + return ret; if (reg & wakeup_bit) { reg &= ~wakeup_bit; ret = hif_func->hif_write_reg(wilc, wakeup_reg, reg); if (ret) - return; + return ret; } ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, ®); if (ret) - return; + return ret; if (reg & from_host_to_fw_bit) { reg &= ~from_host_to_fw_bit; ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, reg); if (ret) - return; + return ret; + } + return 0; +} + +static int chip_allow_sleep_wilc3000(struct wilc *wilc) +{ + u32 reg = 0; + int ret; + const struct wilc_hif_func *hif_func = wilc->hif_func; + + if (wilc->io_type == WILC_HIF_SDIO) { + ret = hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, ®); + if (ret) + return ret; + ret = hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, + reg & ~WILC_SDIO_WAKEUP_BIT); + if (ret) + return ret; + } else { + ret = hif_func->hif_read_reg(wilc, WILC_SPI_WAKEUP_REG, ®); + if (ret) + return ret; + ret = hif_func->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG, + reg & ~WILC_SPI_WAKEUP_BIT); + if (ret) + return ret; } + return 0; +} + +static int chip_allow_sleep(struct wilc *wilc) +{ + if (is_wilc1000(wilc->chipid)) + return chip_allow_sleep_wilc1000(wilc); + else + return chip_allow_sleep_wilc3000(wilc); } -EXPORT_SYMBOL_GPL(chip_allow_sleep); -void chip_wakeup(struct wilc *wilc) +static int chip_wakeup_wilc1000(struct wilc *wilc) { u32 ret = 0; u32 clk_status_val = 0, trials = 0; @@ -627,15 +647,15 @@ void chip_wakeup(struct wilc *wilc) if (wilc->io_type == WILC_HIF_SDIO) { wakeup_reg = WILC_SDIO_WAKEUP_REG; wakeup_bit = WILC_SDIO_WAKEUP_BIT; - clk_status_reg = WILC_SDIO_CLK_STATUS_REG; - clk_status_bit = WILC_SDIO_CLK_STATUS_BIT; + clk_status_reg = WILC1000_SDIO_CLK_STATUS_REG; + clk_status_bit = WILC1000_SDIO_CLK_STATUS_BIT; from_host_to_fw_reg = WILC_SDIO_HOST_TO_FW_REG; from_host_to_fw_bit = WILC_SDIO_HOST_TO_FW_BIT; } else { wakeup_reg = WILC_SPI_WAKEUP_REG; wakeup_bit = WILC_SPI_WAKEUP_BIT; - clk_status_reg = WILC_SPI_CLK_STATUS_REG; - clk_status_bit = WILC_SPI_CLK_STATUS_BIT; + clk_status_reg = WILC1000_SPI_CLK_STATUS_REG; + clk_status_bit = WILC1000_SPI_CLK_STATUS_BIT; from_host_to_fw_reg = WILC_SPI_HOST_TO_FW_REG; from_host_to_fw_bit = WILC_SPI_HOST_TO_FW_BIT; } @@ -644,20 +664,20 @@ void chip_wakeup(struct wilc *wilc) ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, from_host_to_fw_bit); if (ret) - return; + return ret; /* Set wake-up bit */ ret = hif_func->hif_write_reg(wilc, wakeup_reg, wakeup_bit); if (ret) - return; + return ret; while (trials < WAKE_UP_TRIAL_RETRY) { ret = hif_func->hif_read_reg(wilc, clk_status_reg, &clk_status_val); if (ret) { pr_err("Bus error %d %x\n", ret, clk_status_val); - return; + return ret; } if (clk_status_val & clk_status_bit) break; @@ -666,29 +686,135 @@ void chip_wakeup(struct wilc *wilc) } if (trials >= WAKE_UP_TRIAL_RETRY) { pr_err("Failed to wake-up the chip\n"); - return; + return -ETIMEDOUT; } /* Sometimes spi fail to read clock regs after reading * writing clockless registers */ if (wilc->io_type == WILC_HIF_SPI) wilc->hif_func->hif_reset(wilc); + + return 0; } -EXPORT_SYMBOL_GPL(chip_wakeup); -void host_wakeup_notify(struct wilc *wilc) +static int chip_wakeup_wilc3000(struct wilc *wilc) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); - wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + u32 wakeup_reg_val, clk_status_reg_val, trials = 0; + u32 wakeup_reg, wakeup_bit; + u32 clk_status_reg, clk_status_bit; + int wake_seq_trials = 5; + const struct wilc_hif_func *hif_func = wilc->hif_func; + + if (wilc->io_type == WILC_HIF_SDIO) { + wakeup_reg = WILC_SDIO_WAKEUP_REG; + wakeup_bit = WILC_SDIO_WAKEUP_BIT; + clk_status_reg = WILC3000_SDIO_CLK_STATUS_REG; + clk_status_bit = WILC3000_SDIO_CLK_STATUS_BIT; + } else { + wakeup_reg = WILC_SPI_WAKEUP_REG; + wakeup_bit = WILC_SPI_WAKEUP_BIT; + clk_status_reg = WILC3000_SPI_CLK_STATUS_REG; + clk_status_bit = WILC3000_SPI_CLK_STATUS_BIT; + } + + hif_func->hif_read_reg(wilc, wakeup_reg, &wakeup_reg_val); + do { + hif_func->hif_write_reg(wilc, wakeup_reg, wakeup_reg_val | + wakeup_bit); + /* Check the clock status */ + hif_func->hif_read_reg(wilc, clk_status_reg, + &clk_status_reg_val); + + /* In case of clocks off, wait 1ms, and check it again. + * if still off, wait for another 1ms, for a total wait of 3ms. + * If still off, redo the wake up sequence + */ + while ((clk_status_reg_val & clk_status_bit) == 0 && + (++trials % 4) != 0) { + /* Wait for the chip to stabilize*/ + usleep_range(1000, 1100); + + /* Make sure chip is awake. This is an extra step that + * can be removed later to avoid the bus access + * overhead + */ + hif_func->hif_read_reg(wilc, clk_status_reg, + &clk_status_reg_val); + } + /* in case of failure, Reset the wakeup bit to introduce a new + * edge on the next loop + */ + if ((clk_status_reg_val & clk_status_bit) == 0) { + hif_func->hif_write_reg(wilc, wakeup_reg, + wakeup_reg_val & (~wakeup_bit)); + /* added wait before wakeup sequence retry */ + usleep_range(200, 300); + } + } while ((clk_status_reg_val & clk_status_bit) == 0 && wake_seq_trials-- > 0); + if (!wake_seq_trials) + dev_err(wilc->dev, "clocks still OFF. Wake up failed\n"); + + return 0; +} + +static int chip_wakeup(struct wilc *wilc) +{ + if (is_wilc1000(wilc->chipid)) + return chip_wakeup_wilc1000(wilc); + else + return chip_wakeup_wilc3000(wilc); +} + +static inline int acquire_bus(struct wilc *wilc, enum bus_acquire acquire) +{ + int ret = 0; + + mutex_lock(&wilc->hif_cs); + if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP && wilc->power_save_mode) { + ret = chip_wakeup(wilc); + if (ret) + mutex_unlock(&wilc->hif_cs); + } + + return ret; +} + +static inline int release_bus(struct wilc *wilc, enum bus_release release) +{ + int ret = 0; + + if (release == WILC_BUS_RELEASE_ALLOW_SLEEP && wilc->power_save_mode) + ret = chip_allow_sleep(wilc); + mutex_unlock(&wilc->hif_cs); + + return ret; +} + +int host_wakeup_notify(struct wilc *wilc) +{ + int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + + if (ret) + return ret; + + wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ? + WILC1000_CORTUS_INTERRUPT_2 : + WILC3000_CORTUS_INTERRUPT_2, 1); + return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); } EXPORT_SYMBOL_GPL(host_wakeup_notify); -void host_sleep_notify(struct wilc *wilc) +int host_sleep_notify(struct wilc *wilc) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); - wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + int ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + + if (ret) + return ret; + + wilc->hif_func->hif_write_reg(wilc, is_wilc1000(wilc->chipid) ? + WILC1000_CORTUS_INTERRUPT_1 : + WILC3000_CORTUS_INTERRUPT_1, 1); + return release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); } EXPORT_SYMBOL_GPL(host_sleep_notify); @@ -715,6 +841,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) int srcu_idx; u8 *txb = wilc->tx_buffer; struct wilc_vif *vif; + int rv; if (wilc->quit) goto out_update_cnt; @@ -785,7 +912,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) goto out_unlock; vmm_table[i] = 0x0; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto out_unlock; + counter = 0; func = wilc->hif_func; do { @@ -818,19 +948,45 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) if (ret) break; - ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); - if (ret) - break; + if (is_wilc1000(wilc->chipid)) { + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); + if (ret) + break; - do { - ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + do { + ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + if (ret) + break; + if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) { + entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + break; + } + } while (--timeout); + } else { + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0); if (ret) break; - if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) { - entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + + /* interrupt firmware */ + ret = func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, 1); + if (ret) break; - } - } while (--timeout); + + do { + ret = func->hif_read_reg(wilc, WILC_CORTUS_INTERRUPT_BASE, ®); + if (ret) + break; + if (reg == 0) { + /* Get the entries */ + ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + if (ret) + break; + + entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + break; + } + } while (--timeout); + } if (timeout <= 0) { ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0); break; @@ -860,7 +1016,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) goto out_release_bus; } - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (ret) + goto out_unlock; offset = 0; i = 0; @@ -922,7 +1080,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) for (i = 0; i < NQUEUES; i++) wilc->txq[i].fw.count += ac_pkt_num_to_chip[i]; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto out_unlock; ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM); if (ret) @@ -931,7 +1091,9 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) ret = func->hif_block_tx_ext(wilc, 0, txb, offset); out_release_bus: - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (!ret && rv) + ret = rv; out_unlock: mutex_unlock(&wilc->txq_add_to_head_cs); @@ -1060,8 +1222,14 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) void wilc_handle_isr(struct wilc *wilc) { u32 int_status; + int ret; + + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) { + dev_err_ratelimited(wilc->dev, "Cannot acquire bus\n"); + return; + } - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); wilc->hif_func->hif_read_int(wilc, &int_status); if (int_status & DATA_INT_EXT) @@ -1070,7 +1238,9 @@ void wilc_handle_isr(struct wilc *wilc) if (!(int_status & (ALL_INT_EXT))) wilc_unknown_isr_ext(wilc); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + ret = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (ret) + dev_err_ratelimited(wilc->dev, "Cannot release bus\n"); } EXPORT_SYMBOL_GPL(wilc_handle_isr); @@ -1082,6 +1252,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u8 *dma_buffer; int ret = 0; u32 reg = 0; + int rv; blksz = BIT(12); @@ -1092,7 +1263,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, offset = 0; pr_debug("%s: Downloading firmware size = %d\n", __func__, buffer_size); - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); reg &= ~BIT(10); @@ -1101,11 +1274,17 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, if (reg & BIT(10)) pr_err("%s: Failed to reset\n", __func__); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + ret = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (ret) + goto fail; + do { addr = get_unaligned_le32(&buffer[offset]); size = get_unaligned_le32(&buffer[offset + 4]); - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + goto fail; + offset += 8; while (((int)size) && (offset < buffer_size)) { if (size <= blksz) @@ -1123,7 +1302,9 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, offset += size2; size -= size2; } - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + if (!ret && rv) + ret = rv; if (ret) { pr_err("%s Bus error\n", __func__); @@ -1142,7 +1323,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, int wilc_wlan_start(struct wilc *wilc) { u32 reg = 0; - int ret; + int ret, rv; u32 chipid; if (wilc->io_type == WILC_HIF_SDIO) { @@ -1151,7 +1332,10 @@ int wilc_wlan_start(struct wilc *wilc) } else if (wilc->io_type == WILC_HIF_SPI) { reg = 1; } - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + if (ret) + return ret; + ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg); if (ret) goto release; @@ -1160,6 +1344,9 @@ int wilc_wlan_start(struct wilc *wilc) if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num) reg |= WILC_HAVE_SDIO_IRQ_GPIO; + if (is_wilc3000(wilc->chipid)) + reg |= WILC_HAVE_SLEEP_CLK_SRC_RTC; + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg); if (ret) goto release; @@ -1182,16 +1369,18 @@ int wilc_wlan_start(struct wilc *wilc) wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); release: - release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + return ret ? ret : rv; } int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) { u32 reg = 0; - int ret; + int ret, rv; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, ®); if (ret) @@ -1227,9 +1416,9 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) ret = 0; release: /* host comm is disabled - we can't issue sleep command anymore: */ - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); - return ret; + return ret ? ret : rv; } void wilc_wlan_cleanup(struct net_device *dev) @@ -1402,19 +1591,56 @@ int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, return ret; } +int wilc_get_chipid(struct wilc *wilc) +{ + u32 chipid = 0; + u32 rfrevid = 0; + + if (wilc->chipid == 0) { + wilc->hif_func->hif_read_reg(wilc, WILC3000_CHIP_ID, &chipid); + if (!is_wilc3000(chipid)) { + wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); + wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID, + &rfrevid); + + if (!is_wilc1000(chipid)) { + wilc->chipid = 0; + return -EINVAL; + } + if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ + if (rfrevid != 0x1) + chipid = WILC_1000_BASE_ID_2A_REV1; + } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ + if (rfrevid == 0x4) + chipid = WILC_1000_BASE_ID_2B_REV1; + else if (rfrevid != 0x3) + chipid = WILC_1000_BASE_ID_2B_REV2; + } + } + + wilc->chipid = chipid; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wilc_get_chipid); + static int init_chip(struct net_device *dev) { - u32 chipid; u32 reg; - int ret = 0; + int ret, rv; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; - acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; - chipid = wilc_get_chipid(wilc, true); + ret = wilc_get_chipid(wilc); + if (ret) + goto release; - if ((chipid & 0xfff) != 0xa0) { + if ((wilc->chipid & 0xfff) != 0xa0) { ret = wilc->hif_func->hif_read_reg(wilc, WILC_CORTUS_RESET_MUX_SEL, ®); @@ -1439,46 +1665,35 @@ static int init_chip(struct net_device *dev) } } -release: - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); - - return ret; -} - -u32 wilc_get_chipid(struct wilc *wilc, bool update) -{ - u32 chipid = 0; - u32 rfrevid = 0; - - if (wilc->chipid == 0 || update) { - wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); - wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID, - &rfrevid); - if (!is_wilc1000(chipid)) { - wilc->chipid = 0; - return wilc->chipid; - } - if (chipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ - if (rfrevid != 0x1) - chipid = WILC_1000_BASE_ID_2A_REV1; - } else if (chipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ - if (rfrevid == 0x4) - chipid = WILC_1000_BASE_ID_2B_REV1; - else if (rfrevid != 0x3) - chipid = WILC_1000_BASE_ID_2B_REV2; + if (is_wilc3000(wilc->chipid)) { + ret = wilc->hif_func->hif_read_reg(wilc, WILC3000_BOOTROM_STATUS, ®); + if (ret) { + netdev_err(dev, "failed to read WILC3000 BootROM status register\n"); + goto release; } - wilc->chipid = chipid; + ret = wilc->hif_func->hif_write_reg(wilc, WILC3000_CORTUS_BOOT_REGISTER_2, + WILC_CORTUS_BOOT_FROM_IRAM); + if (ret) { + netdev_err(dev, "failed to write WILC3000 Boot register\n"); + goto release; + } } - return wilc->chipid; + +release: + rv = release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + + return ret ? ret : rv; } int wilc_load_mac_from_nv(struct wilc *wl) { - int ret = -EINVAL; + int ret, rv; unsigned int i; - acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP); + ret = acquire_bus(wl, WILC_BUS_ACQUIRE_AND_WAKEUP); + if (ret) + return ret; for (i = 0; i < WILC_NVMEM_MAX_NUM_BANK; i++) { int bank_offset = get_bank_offset_from_bank_index(i); @@ -1517,14 +1732,14 @@ int wilc_load_mac_from_nv(struct wilc *wl) break; } - release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP); - return ret; + rv = release_bus(wl, WILC_BUS_RELEASE_ALLOW_SLEEP); + return ret ? ret : rv; } EXPORT_SYMBOL_GPL(wilc_load_mac_from_nv); int wilc_wlan_init(struct net_device *dev) { - int ret = 0; + int ret = 0, rv; struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc; @@ -1533,11 +1748,26 @@ int wilc_wlan_init(struct net_device *dev) wilc->quit = 0; if (!wilc->hif_func->hif_is_init(wilc)) { - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + ret = acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + if (ret) + return ret; + ret = wilc->hif_func->hif_init(wilc, false); - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (!ret) + ret = wilc_get_chipid(wilc); + rv = release_bus(wilc, WILC_BUS_RELEASE_ONLY); + if (!ret && rv) + ret = rv; if (ret) goto fail; + + if (!is_wilc1000(wilc->chipid) && !is_wilc3000(wilc->chipid)) { + netdev_err(dev, "Unsupported chipid: %x\n", wilc->chipid); + ret = -EINVAL; + goto fail; + } + + netdev_dbg(dev, "chipid (%08x)\n", wilc->chipid); } if (!wilc->vmm_table) diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h index dd2fb3c2f06a23..b9e7f9222eadde 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -96,8 +96,14 @@ #define WILC_SPI_WAKEUP_REG 0x1 #define WILC_SPI_WAKEUP_BIT BIT(1) -#define WILC_SPI_CLK_STATUS_REG 0x0f -#define WILC_SPI_CLK_STATUS_BIT BIT(2) +/* WILC1000 specific */ +#define WILC1000_SPI_CLK_STATUS_REG 0x0f +#define WILC1000_SPI_CLK_STATUS_BIT BIT(2) + +/* WILC3000 specific */ +#define WILC3000_SPI_CLK_STATUS_REG 0x13 +#define WILC3000_SPI_CLK_STATUS_BIT BIT(2) + #define WILC_SPI_HOST_TO_FW_REG 0x0b #define WILC_SPI_HOST_TO_FW_BIT BIT(0) @@ -123,14 +129,24 @@ #define WILC_SDIO_WAKEUP_REG 0xf0 #define WILC_SDIO_WAKEUP_BIT BIT(0) -#define WILC_SDIO_CLK_STATUS_REG 0xf1 -#define WILC_SDIO_CLK_STATUS_BIT BIT(0) +/* WILC1000 */ +#define WILC1000_SDIO_CLK_STATUS_REG 0xf1 +#define WILC1000_SDIO_CLK_STATUS_BIT BIT(0) + +#define WILC1000_SDIO_IRQ_FLAG_REG 0xf7 +#define WILC1000_SDIO_IRQ_CLEAR_FLAG_REG 0xf8 + +/* WILC3000 specific */ +#define WILC3000_SDIO_CLK_STATUS_REG 0xf0 /* clk & wakeup are on same reg */ +#define WILC3000_SDIO_CLK_STATUS_BIT BIT(4) + +#define WILC3000_SDIO_VMM_TBL_CTRL_REG 0xf1 +#define WILC3000_SDIO_IRQ_FLAG_REG 0xfe +/* Common vendor specific CCCR register */ #define WILC_SDIO_INTERRUPT_DATA_SZ_REG 0xf2 /* Read size (2 bytes) */ #define WILC_SDIO_VMM_TBL_CTRL_REG 0xf6 -#define WILC_SDIO_IRQ_FLAG_REG 0xf7 -#define WILC_SDIO_IRQ_CLEAR_FLAG_REG 0xf8 #define WILC_SDIO_HOST_TO_FW_REG 0xfa #define WILC_SDIO_HOST_TO_FW_BIT BIT(0) @@ -172,8 +188,11 @@ #define WILC_HAVE_USE_IRQ_AS_HOST_WAKE BIT(8) #define WILC_CORTUS_INTERRUPT_BASE 0x10A8 -#define WILC_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4) -#define WILC_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8) +#define WILC1000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4) +#define WILC3000_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x14) + +#define WILC1000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8) +#define WILC3000_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x18) /* tx control register 1 to 4 for RX */ #define WILC_REG_4_TO_1_RX 0x1e1c @@ -183,6 +202,9 @@ #define WILC_CORTUS_RESET_MUX_SEL 0x1118 #define WILC_CORTUS_BOOT_REGISTER 0xc0000 +#define WILC3000_BOOTROM_STATUS 0x207ac +#define WILC3000_CORTUS_BOOT_REGISTER_2 0x4f0000 +#define WILC3000_CHIP_ID 0x3b0000 #define WILC_CORTUS_BOOT_FROM_IRAM 0x71 @@ -195,6 +217,8 @@ #define WILC_1000_BASE_ID_2B_REV1 (WILC_1000_BASE_ID_2B + 1) #define WILC_1000_BASE_ID_2B_REV2 (WILC_1000_BASE_ID_2B + 2) +#define WILC_3000_BASE_ID 0x300000 + #define WILC_CHIP_REV_FIELD GENMASK(11, 0) /******************************************** @@ -413,6 +437,11 @@ static inline bool is_wilc1000(u32 id) return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID; } +static inline bool is_wilc3000(u32 id) +{ + return (id & (~WILC_CHIP_REV_FIELD)) == WILC_3000_BASE_ID; +} + int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u32 buffer_size); int wilc_wlan_start(struct wilc *wilc); @@ -436,13 +465,11 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev); void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size); bool wilc_wfi_mgmt_frame_rx(struct wilc_vif *vif, u8 *buff, u32 size); -void host_wakeup_notify(struct wilc *wilc); -void host_sleep_notify(struct wilc *wilc); -void chip_allow_sleep(struct wilc *wilc); -void chip_wakeup(struct wilc *wilc); +int host_wakeup_notify(struct wilc *wilc); +int host_sleep_notify(struct wilc *wilc); int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, u32 count); int wilc_wlan_init(struct net_device *dev); -u32 wilc_get_chipid(struct wilc *wilc, bool update); +int wilc_get_chipid(struct wilc *wilc); int wilc_load_mac_from_nv(struct wilc *wilc); #endif diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 9540ad6196d727..956c5763662f6c 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -257,7 +257,7 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, cmd->beacon_interval = cpu_to_le16(s->beacon_interval); cmd->hidden_ssid = qlink_hidden_ssid_nl2q(s->hidden_ssid); cmd->inactivity_timeout = cpu_to_le16(s->inactivity_timeout); - cmd->smps_mode = s->smps_mode; + cmd->smps_mode = NL80211_SMPS_OFF; cmd->p2p_ctwindow = s->p2p_ctwindow; cmd->p2p_opp_ps = s->p2p_opp_ps; cmd->pbss = s->pbss; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index b204a24074ab22..b375a4751580d0 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 3bb81bcff0ac8b..60c2a12e9d5e96 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -3607,7 +3607,7 @@ static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 52, 0x0C); rt2800_rfcsr_write(rt2x00dev, 54, 0xF8); if (rf->channel <= 50) { - rt2800_rfcsr_write(rt2x00dev, 55, 0x06), + rt2800_rfcsr_write(rt2x00dev, 55, 0x06); rt2800_rfcsr_write(rt2x00dev, 56, 0xD3); } else if (rf->channel >= 52) { rt2800_rfcsr_write(rt2x00dev, 55, 0x04); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c index 8fd22c69855fa4..a6d50149e0c3eb 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c @@ -823,8 +823,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone); INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone); - hrtimer_init(&rt2x00dev->txstatus_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index 7891c988dd5f03..f95898f68d68a5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -5058,10 +5058,12 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changed & BSS_CHANGED_BEACON_ENABLED) { - if (bss_conf->enable_beacon) + if (bss_conf->enable_beacon) { rtl8xxxu_start_tx_beacon(priv); - else + schedule_delayed_work(&priv->update_beacon_work, 0); + } else { rtl8xxxu_stop_tx_beacon(priv); + } } if (changed & BSS_CHANGED_BEACON) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 039bbedb41c245..379193b2442879 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -3409,17 +3409,6 @@ void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) } } -void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist) -{ - struct rtl_priv *rtlpriv = btcoexist->adapter; - - rtl_dbg(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, - "[BTCoex], *****************Coex DM Reset****************\n"); - - halbtc8723b1ant_init_hw_config(btcoexist, false, false); - halbtc8723b1ant_init_coex_dm(btcoexist); -} - void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h index 9d41e11388ade2..a4506d838dc74e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.h @@ -197,7 +197,6 @@ void ex_btc8723b1ant_rf_status_notify(struct btc_coexist *btcoexist, u8 type); void ex_btc8723b1ant_halt_notify(struct btc_coexist *btcoexist); void ex_btc8723b1ant_pnp_notify(struct btc_coexist *btcoexist, u8 pnpstate); -void ex_btc8723b1ant_coex_dm_reset(struct btc_coexist *btcoexist); void ex_btc8723b1ant_periodical(struct btc_coexist *btcoexist); void ex_btc8723b1ant_display_coex_info(struct btc_coexist *btcoexist, struct seq_file *m); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index be4c0e60d44d19..478cca33e5e315 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -1708,19 +1708,6 @@ void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, halbtc_normal_low_power(btcoexist); } -void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - - if (IS_HARDWARE_TYPE_8821(btcoexist->adapter)) { - } else if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { - if (btcoexist->board_info.btdm_ant_num == 1) - ex_btc8723b1ant_rf_status_notify(btcoexist, type); - } else if (IS_HARDWARE_TYPE_8192E(btcoexist->adapter)) { - } -} - void exhalbtc_halt_notify(struct btc_coexist *btcoexist) { if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -1768,31 +1755,6 @@ void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state) } } -void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist) -{ - struct rtl_priv *rtlpriv = btcoexist->adapter; - - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - btcoexist->statistics.cnt_coex_dm_switch++; - - halbtc_leave_low_power(btcoexist); - - if (IS_HARDWARE_TYPE_8723B(btcoexist->adapter)) { - if (btcoexist->board_info.btdm_ant_num == 1) { - btcoexist->stop_coex_dm = true; - ex_btc8723b1ant_coex_dm_reset(btcoexist); - exhalbtc_set_ant_num(rtlpriv, - BT_COEX_ANT_TYPE_DETECTED, 2); - ex_btc8723b2ant_init_hwconfig(btcoexist); - ex_btc8723b2ant_init_coex_dm(btcoexist); - btcoexist->stop_coex_dm = false; - } - } - - halbtc_normal_low_power(btcoexist); -} - void exhalbtc_periodical(struct btc_coexist *btcoexist) { if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -1820,29 +1782,6 @@ void exhalbtc_periodical(struct btc_coexist *btcoexist) halbtc_normal_low_power(btcoexist); } -void exhalbtc_dbg_control(struct btc_coexist *btcoexist, - u8 code, u8 len, u8 *data) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - btcoexist->statistics.cnt_dbg_ctrl++; - - halbtc_leave_low_power(btcoexist); - - halbtc_normal_low_power(btcoexist); -} - -void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq, - u32 offset, u32 span, u32 seconds) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; -} - -void exhalbtc_stack_update_profile_info(void) -{ -} - void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi) { if (!halbtc_is_bt_coexist_available(btcoexist)) @@ -1851,24 +1790,6 @@ void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi) btcoexist->stack_info.min_bt_rssi = bt_rssi; } -void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - - btcoexist->stack_info.hci_version = hci_version; -} - -void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist, - u16 bt_hci_version, u16 bt_patch_version) -{ - if (!halbtc_is_bt_coexist_available(btcoexist)) - return; - - btcoexist->bt_info.bt_real_fw_ver = bt_patch_version; - btcoexist->bt_info.bt_hci_ver = bt_hci_version; -} - void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type) { switch (chip_type) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index a96a995dd85073..d8d88a98980601 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -763,19 +763,9 @@ void exhalbtc_mediastatus_notify(struct btc_coexist *btcoexist, void exhalbtc_special_packet_notify(struct btc_coexist *btcoexist, u8 pkt_type); void exhalbtc_bt_info_notify(struct btc_coexist *btcoexist, u8 *tmp_buf, u8 length); -void exhalbtc_rf_status_notify(struct btc_coexist *btcoexist, u8 type); void exhalbtc_halt_notify(struct btc_coexist *btcoexist); void exhalbtc_pnp_notify(struct btc_coexist *btcoexist, u8 pnp_state); -void exhalbtc_coex_dm_switch(struct btc_coexist *btcoexist); void exhalbtc_periodical(struct btc_coexist *btcoexist); -void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len, - u8 *data); -void exhalbtc_antenna_detection(struct btc_coexist *btcoexist, u32 cent_freq, - u32 offset, u32 span, u32 seconds); -void exhalbtc_stack_update_profile_info(void); -void exhalbtc_set_hci_version(struct btc_coexist *btcoexist, u16 hci_version); -void exhalbtc_set_bt_patch_version(struct btc_coexist *btcoexist, - u16 bt_hci_version, u16 bt_patch_version); void exhalbtc_update_min_bt_rssi(struct btc_coexist *btcoexist, s8 bt_rssi); void exhalbtc_set_bt_exist(struct btc_coexist *btcoexist, bool bt_exist); void exhalbtc_set_chip_type(struct btc_coexist *btcoexist, u8 chip_type); diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index 82cf5fb5175fef..6518e77b89f578 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -162,10 +162,19 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 max_attempts = 10000; u32 value32; u8 readbyte; u16 retry; + /* + * In case of USB devices, transfer speeds are limited, hence + * efuse I/O reads could be (way) slower. So, decrease (a lot) + * the read attempts in case of failures. + */ + if (rtlpriv->rtlhal.interface == INTF_USB) + max_attempts = 10; + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, (_offset & 0xff)); readbyte = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 2); @@ -178,7 +187,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) retry = 0; value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); - while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { + while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < max_attempts)) { value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]); retry++; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 1b144fbd4d26c2..048744166a920f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -350,7 +350,8 @@ MODULE_AUTHOR("lizhaoming "); MODULE_AUTHOR("Realtek WlanFAE "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 8723E 802.11n PCI wireless"); -MODULE_FIRMWARE("rtlwifi/rtl8723efw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723fw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8723fw_B.bin"); module_param_named(swenc, rtl8723e_mod_params.sw_crypto, bool, 0444); module_param_named(debug_level, rtl8723e_mod_params.debug_level, int, 0644); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 0e77de1baaf878..bcfc53af4c1a11 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -2040,31 +2040,33 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - int params[] = {RTL8723BE_EEPROM_ID, EEPROM_VID, EEPROM_DID, - EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, - EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, - COUNTRY_CODE_WORLD_WIDE_13}; + static const int params[] = { + RTL8723BE_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13 + }; u8 *hwinfo; int i; bool is_toshiba_smid1 = false; bool is_toshiba_smid2 = false; bool is_samsung_smid = false; bool is_lenovo_smid = false; - u16 toshiba_smid1[] = { + static const u16 toshiba_smid1[] = { 0x6151, 0x6152, 0x6154, 0x6155, 0x6177, 0x6178, 0x6179, 0x6180, 0x7151, 0x7152, 0x7154, 0x7155, 0x7177, 0x7178, 0x7179, 0x7180, 0x8151, 0x8152, 0x8154, 0x8155, 0x8181, 0x8182, 0x8184, 0x8185, 0x9151, 0x9152, 0x9154, 0x9155, 0x9181, 0x9182, 0x9184, 0x9185 }; - u16 toshiba_smid2[] = { + static const u16 toshiba_smid2[] = { 0x6181, 0x6184, 0x6185, 0x7181, 0x7182, 0x7184, 0x7185, 0x8181, 0x8182, 0x8184, 0x8185, 0x9181, 0x9182, 0x9184, 0x9185 }; - u16 samsung_smid[] = { + static const u16 samsung_smid[] = { 0x6191, 0x6192, 0x6193, 0x7191, 0x7192, 0x7193, 0x8191, 0x8192, 0x8193, 0x9191, 0x9192, 0x9193 }; - u16 lenovo_smid[] = { + static const u16 lenovo_smid[] = { 0x8195, 0x9195, 0x7194, 0x8200, 0x8201, 0x8202, 0x9199, 0x9200 }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index a65503c5ae5aa4..b5266e5604167b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -407,6 +407,9 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 8821ae 802.11ac PCI wireless"); MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin"); MODULE_FIRMWARE("rtlwifi/rtl8821aefw_29.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8821aefw_wowlan.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8812aefw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8812aefw_wowlan.bin"); module_param_named(swenc, rtl8821ae_mod_params.sw_crypto, bool, 0444); module_param_named(debug_level, rtl8821ae_mod_params.debug_level, int, 0644); diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig index 02b0d698413bec..733b3e58da5119 100644 --- a/drivers/net/wireless/realtek/rtw88/Kconfig +++ b/drivers/net/wireless/realtek/rtw88/Kconfig @@ -43,6 +43,17 @@ config RTW88_8723D config RTW88_8821C tristate +config RTW88_88XXA + tristate + +config RTW88_8821A + tristate + select RTW88_88XXA + +config RTW88_8812A + tristate + select RTW88_88XXA + config RTW88_8822BE tristate "Realtek 8822BE PCI wireless network adapter" depends on PCI @@ -189,6 +200,28 @@ config RTW88_8821CU 802.11ac USB wireless network adapter +config RTW88_8821AU + tristate "Realtek 8821AU/8811AU USB wireless network adapter" + depends on USB + select RTW88_CORE + select RTW88_USB + select RTW88_8821A + help + Select this option will enable support for 8821AU and 8811AU chipset + + 802.11ac USB wireless network adapter + +config RTW88_8812AU + tristate "Realtek 8812AU USB wireless network adapter" + depends on USB + select RTW88_CORE + select RTW88_USB + select RTW88_8812A + help + Select this option will enable support for 8812AU chipset + + 802.11ac USB wireless network adapter + config RTW88_DEBUG bool "Realtek rtw88 debug support" depends on RTW88_CORE diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 8f47359b438079..f0b49f5a8a5a88 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -77,6 +77,21 @@ rtw88_8821cs-objs := rtw8821cs.o obj-$(CONFIG_RTW88_8821CU) += rtw88_8821cu.o rtw88_8821cu-objs := rtw8821cu.o +obj-$(CONFIG_RTW88_88XXA) += rtw88_88xxa.o +rtw88_88xxa-objs := rtw88xxa.o + +obj-$(CONFIG_RTW88_8821A) += rtw88_8821a.o +rtw88_8821a-objs := rtw8821a.o rtw8821a_table.o + +obj-$(CONFIG_RTW88_8812A) += rtw88_8812a.o +rtw88_8812a-objs := rtw8812a.o rtw8812a_table.o + +obj-$(CONFIG_RTW88_8821AU) += rtw88_8821au.o +rtw88_8821au-objs := rtw8821au.o + +obj-$(CONFIG_RTW88_8812AU) += rtw88_8812au.o +rtw88_8812au-objs := rtw8812au.o + obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o rtw88_pci-objs := pci.o diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index a99776af56c27f..c929db1e53ca63 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -446,7 +446,7 @@ static void rtw_coex_check_rfk(struct rtw_dev *rtwdev) } } -static void rtw_coex_query_bt_info(struct rtw_dev *rtwdev) +void rtw_coex_query_bt_info(struct rtw_dev *rtwdev) { struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex_stat *coex_stat = &coex->stat; @@ -494,11 +494,29 @@ static void rtw_coex_monitor_bt_enable(struct rtw_dev *rtwdev) struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_coex_dm *coex_dm = &coex->dm; bool bt_disabled = false; + bool bt_active = true; u16 score_board; if (chip->scbd_support) { score_board = rtw_coex_read_scbd(rtwdev); bt_disabled = !(score_board & COEX_SCBD_ONOFF); + } else { + if (coex_stat->hi_pri_tx == 0 && coex_stat->hi_pri_rx == 0 && + coex_stat->lo_pri_tx == 0 && coex_stat->lo_pri_rx == 0) + bt_active = false; + + if (coex_stat->hi_pri_tx == 0xffff && coex_stat->hi_pri_rx == 0xffff && + coex_stat->lo_pri_tx == 0xffff && coex_stat->lo_pri_rx == 0xffff) + bt_active = false; + + if (bt_active) { + coex_stat->bt_disable_cnt = 0; + bt_disabled = false; + } else { + coex_stat->bt_disable_cnt++; + if (coex_stat->bt_disable_cnt >= 10) + bt_disabled = true; + } } if (coex_stat->bt_disabled != bt_disabled) { @@ -950,12 +968,18 @@ static void rtw_coex_coex_ctrl_owner(struct rtw_dev *rtwdev, bool wifi_control) static void rtw_coex_set_gnt_bt(struct rtw_dev *rtwdev, u8 state) { + if (!rtwdev->chip->ltecoex_addr) + return; + rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0xc000, state); rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0c00, state); } static void rtw_coex_set_gnt_wl(struct rtw_dev *rtwdev, u8 state) { + if (!rtwdev->chip->ltecoex_addr) + return; + rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x3000, state); rtw_coex_write_indirect_reg(rtwdev, LTE_COEX_CTRL, 0x0300, state); } @@ -2747,16 +2771,19 @@ void rtw_coex_power_on_setting(struct rtw_dev *rtwdev) rtw_write8(rtwdev, 0xff1a, 0x0); rtw_coex_set_gnt_debug(rtwdev); } +EXPORT_SYMBOL(rtw_coex_power_on_setting); void rtw_coex_power_off_setting(struct rtw_dev *rtwdev) { rtw_write16(rtwdev, REG_WIFI_BT_INFO, BIT_BT_INT_EN); } +EXPORT_SYMBOL(rtw_coex_power_off_setting); void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only) { __rtw_coex_init_hw_config(rtwdev, wifi_only); } +EXPORT_SYMBOL(rtw_coex_init_hw_config); void rtw_coex_ips_notify(struct rtw_dev *rtwdev, u8 type) { @@ -3904,7 +3931,7 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m) u8 sys_lte; u16 score_board_WB, score_board_BW; u32 wl_reg_6c0, wl_reg_6c4, wl_reg_6c8, wl_reg_778, wl_reg_6cc; - u32 lte_coex, bt_coex; + u32 lte_coex = 0, bt_coex = 0; int i; score_board_BW = rtw_coex_read_scbd(rtwdev); @@ -3916,8 +3943,10 @@ void rtw_coex_display_coex_info(struct rtw_dev *rtwdev, struct seq_file *m) wl_reg_778 = rtw_read8(rtwdev, REG_BT_STAT_CTRL); sys_lte = rtw_read8(rtwdev, 0x73); - lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38); - bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54); + if (rtwdev->chip->ltecoex_addr) { + lte_coex = rtw_coex_read_indirect_reg(rtwdev, 0x38); + bt_coex = rtw_coex_read_indirect_reg(rtwdev, 0x54); + } if (!coex_stat->wl_under_ips && (!coex_stat->wl_under_lps || coex_stat->wl_force_lps_ctrl) && diff --git a/drivers/net/wireless/realtek/rtw88/coex.h b/drivers/net/wireless/realtek/rtw88/coex.h index 57cf29da9ea4e3..c398be8391f7b0 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.h +++ b/drivers/net/wireless/realtek/rtw88/coex.h @@ -384,6 +384,7 @@ u32 rtw_coex_read_indirect_reg(struct rtw_dev *rtwdev, u16 addr); void rtw_coex_write_indirect_reg(struct rtw_dev *rtwdev, u16 addr, u32 mask, u32 val); void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set); +void rtw_coex_query_bt_info(struct rtw_dev *rtwdev); void rtw_coex_bt_relink_work(struct work_struct *work); void rtw_coex_bt_reenable_work(struct work_struct *work); @@ -419,4 +420,14 @@ static inline bool rtw_coex_disabled(struct rtw_dev *rtwdev) return coex_stat->bt_disabled; } +static inline void rtw_coex_active_query_bt_info(struct rtw_dev *rtwdev) +{ + /* The RTL8821AU firmware doesn't send C2H_BT_INFO by itself + * when bluetooth headphones are disconnected, so we have to + * ask for it regularly. + */ + if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A && rtwdev->efuse.btcoex) + rtw_coex_query_bt_info(rtwdev); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index c26a6905fd15ad..364ec0436d0fe8 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -308,7 +308,7 @@ static int rtw_debugfs_get_rsvd_page(struct seq_file *m, void *v) { struct rtw_debugfs_priv *debugfs_priv = m->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; - u8 page_size = rtwdev->chip->page_size; + u16 page_size = rtwdev->chip->page_size; u32 buf_size = debugfs_priv->rsvd_page.page_num * page_size; u32 offset = debugfs_priv->rsvd_page.page_offset * page_size; u8 *buf; diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index b9b0114e253b43..e6e9946fbf44e4 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -139,25 +139,30 @@ static u16 get_max_amsdu_len(u32 bit_rate) struct rtw_fw_iter_ra_data { struct rtw_dev *rtwdev; u8 *payload; + u8 length; }; static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta) { struct rtw_fw_iter_ra_data *ra_data = data; + struct rtw_c2h_ra_rpt *ra_rpt = (struct rtw_c2h_ra_rpt *)ra_data->payload; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; u8 mac_id, rate, sgi, bw; u8 mcs, nss; u32 bit_rate; - mac_id = GET_RA_REPORT_MACID(ra_data->payload); + mac_id = ra_rpt->mac_id; if (si->mac_id != mac_id) return; si->ra_report.txrate.flags = 0; - rate = GET_RA_REPORT_RATE(ra_data->payload); - sgi = GET_RA_REPORT_SGI(ra_data->payload); - bw = GET_RA_REPORT_BW(ra_data->payload); + rate = u8_get_bits(ra_rpt->rate_sgi, RTW_C2H_RA_RPT_RATE); + sgi = u8_get_bits(ra_rpt->rate_sgi, RTW_C2H_RA_RPT_SGI); + if (ra_data->length >= offsetofend(typeof(*ra_rpt), bw)) + bw = ra_rpt->bw; + else + bw = si->bw_mode; if (rate < DESC_RATEMCS0) { si->ra_report.txrate.legacy = rtw_desc_to_bitrate(rate); @@ -197,14 +202,18 @@ static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta) static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, u8 length) { + struct rtw_c2h_ra_rpt *ra_rpt = (struct rtw_c2h_ra_rpt *)payload; struct rtw_fw_iter_ra_data ra_data; - if (WARN(length < 7, "invalid ra report c2h length\n")) + if (WARN(length < rtwdev->chip->c2h_ra_report_size, + "invalid ra report c2h length %d\n", length)) return; - rtwdev->dm_info.tx_rate = GET_RA_REPORT_RATE(payload); + rtwdev->dm_info.tx_rate = u8_get_bits(ra_rpt->rate_sgi, + RTW_C2H_RA_RPT_RATE); ra_data.rtwdev = rtwdev; ra_data.payload = payload; + ra_data.length = length; rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data); } @@ -267,7 +276,7 @@ static void rtw_fw_scan_result(struct rtw_dev *rtwdev, u8 *payload, static void rtw_fw_adaptivity_result(struct rtw_dev *rtwdev, u8 *payload, u8 length) { - struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th; + const struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th; struct rtw_c2h_adaptivity *result = (struct rtw_c2h_adaptivity *)payload; rtw_dbg(rtwdev, RTW_DBG_ADAPTIVITY, @@ -1281,16 +1290,16 @@ static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb, rtw_tx_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb, type); pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, chip->tx_pkt_desc_sz); - rtw_tx_fill_tx_desc(&pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, &pkt_info, skb); } -static inline u8 rtw_len_to_page(unsigned int len, u8 page_size) +static inline u8 rtw_len_to_page(unsigned int len, u16 page_size) { return DIV_ROUND_UP(len, page_size); } -static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u8 page_size, - u8 page_margin, u32 page, u8 *buf, +static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u16 page_size, + u16 page_margin, u32 page, u8 *buf, struct rtw_rsvd_page *rsvd_pkt) { struct sk_buff *skb = rsvd_pkt->skb; @@ -1592,13 +1601,13 @@ static int __rtw_build_rsvd_page_from_vifs(struct rtw_dev *rtwdev) static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, u32 *size) { - struct ieee80211_hw *hw = rtwdev->hw; const struct rtw_chip_info *chip = rtwdev->chip; - struct sk_buff *iter; + struct ieee80211_hw *hw = rtwdev->hw; struct rtw_rsvd_page *rsvd_pkt; - u32 page = 0; + struct sk_buff *iter; + u16 page_size, page_margin, tx_desc_sz; u8 total_page = 0; - u8 page_size, page_margin, tx_desc_sz; + u32 page = 0; u8 *buf; int ret; @@ -2004,12 +2013,13 @@ static int _rtw_hw_scan_update_probe_req(struct rtw_dev *rtwdev, u8 num_probes, { const struct rtw_chip_info *chip = rtwdev->chip; struct sk_buff *skb, *tmp; - u8 page_offset = 1, *buf, page_size = chip->page_size; u16 pg_addr = rtwdev->fifo.rsvd_h2c_info_addr, loc; - u16 buf_offset = page_size * page_offset; u8 tx_desc_sz = chip->tx_pkt_desc_sz; - u8 page_cnt, pages; + u16 page_size = chip->page_size; + u8 page_offset = 1, *buf; + u16 buf_offset = page_size * page_offset; unsigned int pkt_len; + u8 page_cnt, pages; int ret; if (rtw_fw_feature_ext_check(&rtwdev->fw, FW_FEATURE_EXT_OLD_PAGE_NUM)) diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index e999c24e463447..404de1b0c407b4 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -85,6 +85,19 @@ struct rtw_c2h_adaptivity { u8 option; } __packed; +struct rtw_c2h_ra_rpt { + u8 rate_sgi; + u8 mac_id; + u8 byte2; + u8 status; + u8 byte4; + u8 ra_ratio; + u8 bw; +} __packed; + +#define RTW_C2H_RA_RPT_RATE GENMASK(6, 0) +#define RTW_C2H_RA_RPT_SGI BIT(7) + struct rtw_h2c_register { u32 w0; u32 w1; @@ -364,10 +377,6 @@ struct rtw_fw_hdr_legacy { #define GET_CHAN_SWITCH_CENTRAL_CH(c2h_payload) (c2h_payload[2]) #define GET_CHAN_SWITCH_ID(c2h_payload) (c2h_payload[3]) #define GET_CHAN_SWITCH_STATUS(c2h_payload) (c2h_payload[4]) -#define GET_RA_REPORT_RATE(c2h_payload) (c2h_payload[0] & 0x7f) -#define GET_RA_REPORT_SGI(c2h_payload) ((c2h_payload[0] & 0x80) >> 7) -#define GET_RA_REPORT_BW(c2h_payload) (c2h_payload[6]) -#define GET_RA_REPORT_MACID(c2h_payload) (c2h_payload[1]) #define GET_BCN_FILTER_NOTIFY_TYPE(c2h_payload) (c2h_payload[1] & 0xf) #define GET_BCN_FILTER_NOTIFY_EVENT(c2h_payload) (c2h_payload[1] & 0x10) diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 564f5988ee82a7..cae9cca6dca3d8 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -227,8 +227,8 @@ static int rtw_sub_pwr_seq_parser(struct rtw_dev *rtwdev, u8 intf_mask, return 0; } -static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, - const struct rtw_pwr_seq_cmd **cmd_seq) +int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd * const *cmd_seq) { u8 cut_mask; u8 intf_mask; @@ -267,11 +267,12 @@ static int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, return 0; } +EXPORT_SYMBOL(rtw_pwr_seq_parser); static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) { const struct rtw_chip_info *chip = rtwdev->chip; - const struct rtw_pwr_seq_cmd **pwr_seq; + const struct rtw_pwr_seq_cmd * const *pwr_seq; u32 imr = 0; u8 rpwm; bool cur_pwr; @@ -994,6 +995,7 @@ int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) return 0; } +EXPORT_SYMBOL(rtw_download_firmware); static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) { @@ -1127,7 +1129,7 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev) return 0; } -static int set_trx_fifo_info(struct rtw_dev *rtwdev) +int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_fifo_conf *fifo = &rtwdev->fifo; @@ -1136,7 +1138,7 @@ static int set_trx_fifo_info(struct rtw_dev *rtwdev) /* config rsvd page num */ fifo->rsvd_drv_pg_num = chip->rsvd_drv_pg_num; - fifo->txff_pg_num = chip->txff_size >> 7; + fifo->txff_pg_num = chip->txff_size / chip->page_size; if (rtw_chip_wcpu_11n(rtwdev)) fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num; else @@ -1179,6 +1181,7 @@ static int set_trx_fifo_info(struct rtw_dev *rtwdev) return 0; } +EXPORT_SYMBOL(rtw_set_trx_fifo_info); static int __priority_queue_cfg(struct rtw_dev *rtwdev, const struct rtw_page_table *pg_tbl, @@ -1256,7 +1259,7 @@ static int priority_queue_cfg(struct rtw_dev *rtwdev) u16 pubq_num; int ret; - ret = set_trx_fifo_info(rtwdev); + ret = rtw_set_trx_fifo_info(rtwdev); if (ret) return ret; diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h index 58c3dccc14bb51..6905e27473721a 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.h +++ b/drivers/net/wireless/realtek/rtw88/mac.h @@ -30,11 +30,14 @@ void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, u8 primary_ch_idx); +int rtw_pwr_seq_parser(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd * const *cmd_seq); int rtw_mac_power_on(struct rtw_dev *rtwdev); void rtw_mac_power_off(struct rtw_dev *rtwdev); int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); int rtw_mac_init(struct rtw_dev *rtwdev); void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); +int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev); int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size); static inline void rtw_mac_flush_all_queues(struct rtw_dev *rtwdev, bool drop) diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index b39e90fb66b41d..026fbf4ad9cce9 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -928,8 +928,10 @@ static int rtw_ops_set_sar_specs(struct ieee80211_hw *hw, static void rtw_ops_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, + u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct rtw_dev *rtwdev = hw->priv; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; @@ -973,7 +975,7 @@ const struct ieee80211_ops rtw_ops = { .reconfig_complete = rtw_reconfig_complete, .hw_scan = rtw_ops_hw_scan, .cancel_hw_scan = rtw_ops_cancel_hw_scan, - .sta_rc_update = rtw_ops_sta_rc_update, + .link_sta_rc_update = rtw_ops_sta_rc_update, .set_sar_specs = rtw_ops_set_sar_specs, #ifdef CONFIG_PM .suspend = rtw_ops_suspend, diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index bbdef38c7e341c..e91530ed05a077 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -202,6 +202,21 @@ static void rtw_vif_watch_dog_iter(void *data, struct ieee80211_vif *vif) rtwvif->stats.rx_cnt = 0; } +static void rtw_sw_beacon_loss_check(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif, int received_beacons) +{ + int watchdog_delay = 2000000 / 1024; /* TU */ + int beacon_int, expected_beacons; + + if (rtw_fw_feature_check(&rtwdev->fw, FW_FEATURE_BCN_FILTER) || !rtwvif) + return; + + beacon_int = rtwvif_to_vif(rtwvif)->bss_conf.beacon_int; + expected_beacons = DIV_ROUND_UP(watchdog_delay, beacon_int); + + rtwdev->beacon_loss = received_beacons < expected_beacons / 2; +} + /* process TX/RX statistics periodically for hardware, * the information helps hardware to enhance performance */ @@ -212,6 +227,7 @@ static void rtw_watch_dog_work(struct work_struct *work) struct rtw_traffic_stats *stats = &rtwdev->stats; struct rtw_watch_dog_iter_data data = {}; bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + int received_beacons = rtwdev->dm_info.cur_pkt_count.num_bcn_pkt; u32 tx_unicast_mbps, rx_unicast_mbps; bool ps_active; @@ -258,6 +274,7 @@ static void rtw_watch_dog_work(struct work_struct *work) rtw_leave_lps(rtwdev); rtw_coex_wl_status_check(rtwdev); rtw_coex_query_bt_hid_list(rtwdev); + rtw_coex_active_query_bt_info(rtwdev); rtw_phy_dynamic_mechanism(rtwdev); @@ -270,6 +287,8 @@ static void rtw_watch_dog_work(struct work_struct *work) */ rtw_iterate_vifs(rtwdev, rtw_vif_watch_dog_iter, &data); + rtw_sw_beacon_loss_check(rtwdev, data.rtwvif, received_beacons); + /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter * lps, because fw does not handle the overlapped beacon interval @@ -1309,7 +1328,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, rtw_fw_send_ra_info(rtwdev, si, reset_ra_mask); } -static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) +int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_fw_state *fw; @@ -1329,6 +1348,7 @@ static int rtw_wait_firmware_completion(struct rtw_dev *rtwdev) return ret; } +EXPORT_SYMBOL(rtw_wait_firmware_completion); static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) @@ -1350,7 +1370,7 @@ static enum rtw_lps_deep_mode rtw_update_lps_deep_mode(struct rtw_dev *rtwdev, return LPS_DEEP_MODE_NONE; } -static int rtw_power_on(struct rtw_dev *rtwdev) +int rtw_power_on(struct rtw_dev *rtwdev) { const struct rtw_chip_info *chip = rtwdev->chip; struct rtw_fw_state *fw = &rtwdev->fw; @@ -1413,6 +1433,7 @@ static int rtw_power_on(struct rtw_dev *rtwdev) err: return ret; } +EXPORT_SYMBOL(rtw_power_on); void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start) { @@ -1485,7 +1506,7 @@ int rtw_core_start(struct rtw_dev *rtwdev) { int ret; - ret = rtw_power_on(rtwdev); + ret = rtwdev->chip->ops->power_on(rtwdev); if (ret) return ret; @@ -1505,12 +1526,13 @@ int rtw_core_start(struct rtw_dev *rtwdev) return 0; } -static void rtw_power_off(struct rtw_dev *rtwdev) +void rtw_power_off(struct rtw_dev *rtwdev) { rtw_hci_stop(rtwdev); rtw_coex_power_off_setting(rtwdev); rtw_mac_power_off(rtwdev); } +EXPORT_SYMBOL(rtw_power_off); void rtw_core_stop(struct rtw_dev *rtwdev) { @@ -1535,7 +1557,7 @@ void rtw_core_stop(struct rtw_dev *rtwdev) mutex_lock(&rtwdev->mutex); - rtw_power_off(rtwdev); + rtwdev->chip->ops->power_off(rtwdev); } static void rtw_init_ht_cap(struct rtw_dev *rtwdev, @@ -1917,6 +1939,9 @@ static int rtw_dump_hw_feature(struct rtw_dev *rtwdev) u8 bw; int i; + if (!rtwdev->chip->hw_feature_report) + return 0; + id = rtw_read8(rtwdev, REG_C2HEVT); if (id != C2H_HW_FEATURE_REPORT) { rtw_err(rtwdev, "failed to read hw feature report\n"); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 945117afe1438b..cd09fb6f7b8b33 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -189,6 +189,8 @@ enum rtw_chip_type { RTW_CHIP_TYPE_8723D, RTW_CHIP_TYPE_8821C, RTW_CHIP_TYPE_8703B, + RTW_CHIP_TYPE_8821A, + RTW_CHIP_TYPE_8812A, }; enum rtw_tx_queue_type { @@ -841,6 +843,8 @@ struct rtw_regd { }; struct rtw_chip_ops { + int (*power_on)(struct rtw_dev *rtwdev); + void (*power_off)(struct rtw_dev *rtwdev); int (*mac_init)(struct rtw_dev *rtwdev); int (*dump_fw_crash)(struct rtw_dev *rtwdev); void (*shutdown)(struct rtw_dev *rtwdev); @@ -848,9 +852,8 @@ struct rtw_chip_ops { void (*phy_set_param)(struct rtw_dev *rtwdev); void (*set_channel)(struct rtw_dev *rtwdev, u8 channel, u8 bandwidth, u8 primary_chan_idx); - void (*query_rx_desc)(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status); + void (*query_phy_status)(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat); u32 (*read_rf)(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, u32 addr, u32 mask); bool (*write_rf)(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, @@ -1096,17 +1099,20 @@ enum rtw_rfe_fem { struct rtw_rfe_def { const struct rtw_table *phy_pg_tbl; const struct rtw_table *txpwr_lmt_tbl; + const struct rtw_pwr_track_tbl *pwr_track_tbl; const struct rtw_table *agc_btg_tbl; }; -#define RTW_DEF_RFE(chip, bb_pg, pwrlmt) { \ +#define RTW_DEF_RFE(chip, bb_pg, pwrlmt, track) { \ .phy_pg_tbl = &rtw ## chip ## _bb_pg_type ## bb_pg ## _tbl, \ .txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \ + .pwr_track_tbl = &rtw ## chip ## _pwr_track_type ## track ## _tbl, \ } -#define RTW_DEF_RFE_EXT(chip, bb_pg, pwrlmt, btg) { \ +#define RTW_DEF_RFE_EXT(chip, bb_pg, pwrlmt, track, btg) { \ .phy_pg_tbl = &rtw ## chip ## _bb_pg_type ## bb_pg ## _tbl, \ .txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \ + .pwr_track_tbl = &rtw ## chip ## _pwr_track_type ## track ## _tbl, \ .agc_btg_tbl = &rtw ## chip ## _agc_btg_type ## btg ## _tbl, \ } @@ -1167,7 +1173,7 @@ enum rtw_fwcd_item { /* hardware configuration for each IC */ struct rtw_chip_info { - struct rtw_chip_ops *ops; + const struct rtw_chip_ops *ops; u8 id; const char *fw_name; @@ -1184,7 +1190,7 @@ struct rtw_chip_info { u32 fw_rxff_size; u16 rsvd_drv_pg_num; u8 band; - u8 page_size; + u16 page_size; u8 csi_buf_pg_num; u8 dig_max; u8 dig_min; @@ -1199,6 +1205,9 @@ struct rtw_chip_info { const struct rtw_fwcd_segs *fwcd_segs; u8 usb_tx_agg_desc_num; + bool hw_feature_report; + u8 c2h_ra_report_size; + bool old_datarate_fb_limit; u8 default_1ss_tx_path; @@ -1209,8 +1218,8 @@ struct rtw_chip_info { /* init values */ u8 sys_func_en; - const struct rtw_pwr_seq_cmd **pwr_on_seq; - const struct rtw_pwr_seq_cmd **pwr_off_seq; + const struct rtw_pwr_seq_cmd * const *pwr_on_seq; + const struct rtw_pwr_seq_cmd * const *pwr_off_seq; const struct rtw_rqpn *rqpn_table; const struct rtw_prioq_addrs *prioq_addrs; const struct rtw_page_table *page_table; @@ -1237,12 +1246,11 @@ struct rtw_chip_info { u16 dpd_ratemask; u8 iqk_threshold; u8 lck_threshold; - const struct rtw_pwr_track_tbl *pwr_track_tbl; u8 bfer_su_max_num; u8 bfer_mu_max_num; - struct rtw_hw_reg_offset *edcca_th; + const struct rtw_hw_reg_offset *edcca_th; s8 l2h_th_ini_cs; s8 l2h_th_ini_ad; @@ -1486,6 +1494,7 @@ struct rtw_coex_stat { u8 bt_hid_slot; u8 bt_a2dp_bitpool; u8 bt_iqk_state; + u8 bt_disable_cnt; u16 wl_beacon_interval; u8 wl_noisy_level; @@ -1709,7 +1718,7 @@ struct rtw_dm_info { bool pwr_trk_init_trigger; struct ewma_thermal avg_thermal[RTW_RF_PATH_MAX]; s8 txagc_remnant_cck; - s8 txagc_remnant_ofdm; + s8 txagc_remnant_ofdm[RTW_RF_PATH_MAX]; u8 rx_cck_agc_report_type; /* backup dack results for each path and I/Q */ @@ -1832,6 +1841,20 @@ struct rtw_phy_cond { #define BRANCH_ENDIF 3 }; +struct rtw_phy_cond2 { +#ifdef __LITTLE_ENDIAN + u8 type_glna; + u8 type_gpa; + u8 type_alna; + u8 type_apa; +#else + u8 type_apa; + u8 type_alna; + u8 type_gpa; + u8 type_glna; +#endif +}; + struct rtw_fifo_conf { /* tx fifo information */ u16 rsvd_boundary; @@ -1913,6 +1936,7 @@ struct rtw_hal { u8 oem_id; u8 pkg_type; struct rtw_phy_cond phy_cond; + struct rtw_phy_cond2 phy_cond2; bool rfe_btg; u8 ps_mode; @@ -1935,6 +1959,7 @@ struct rtw_hal { u32 antenna_rx; u8 bfee_sts_cap; bool txrx_1ss; + bool cck_high_power; /* protect tx power section */ struct mutex tx_power_mutex; @@ -2190,6 +2215,7 @@ void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, bool hw_scan); int rtw_core_start(struct rtw_dev *rtwdev); +void rtw_power_off(struct rtw_dev *rtwdev); void rtw_core_stop(struct rtw_dev *rtwdev); int rtw_chip_info_setup(struct rtw_dev *rtwdev); int rtw_core_init(struct rtw_dev *rtwdev); @@ -2204,6 +2230,8 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, bool fw_exist); void rtw_fw_recovery(struct rtw_dev *rtwdev); +int rtw_wait_firmware_completion(struct rtw_dev *rtwdev); +int rtw_power_on(struct rtw_dev *rtwdev); void rtw_core_fw_scan_notify(struct rtw_dev *rtwdev, bool start); int rtw_dump_fw(struct rtw_dev *rtwdev, const u32 ocp_src, u32 size, u32 fwcd_item); diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 0b9b8807af2cb0..0ecaefc4c83dde 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -824,7 +824,7 @@ static int rtw_pci_tx_write_data(struct rtw_dev *rtwdev, pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, tx_pkt_desc_sz); pkt_info->qsel = rtw_pci_get_tx_qsel(skb, queue); - rtw_tx_fill_tx_desc(pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb); dma = dma_map_single(&rtwpci->pdev->dev, skb->data, skb->len, DMA_TO_DEVICE); if (dma_mapping_error(&rtwpci->pdev->dev, dma)) @@ -1065,7 +1065,7 @@ static u32 rtw_pci_rx_napi(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci, dma_sync_single_for_cpu(rtwdev->dev, dma, RTK_PCI_RX_BUF_SIZE, DMA_FROM_DEVICE); rx_desc = skb->data; - chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status); + rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status); /* offset from rx_desc to payload */ pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 37ef80c9091dba..8ed20c89d21638 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -18,7 +18,10 @@ struct phy_cfg_pair { }; union phy_table_tile { - struct rtw_phy_cond cond; + struct { + struct rtw_phy_cond cond; + struct rtw_phy_cond2 cond2; + } __packed; struct phy_cfg_pair cfg; }; @@ -123,7 +126,7 @@ static void rtw_phy_cck_pd_init(struct rtw_dev *rtwdev) void rtw_phy_set_edcca_th(struct rtw_dev *rtwdev, u8 l2h, u8 h2l) { - struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th; + const struct rtw_hw_reg_offset *edcca_th = rtwdev->chip->edcca_th; rtw_write32_mask(rtwdev, edcca_th[EDCCA_TH_L2H_IDX].hw_reg.addr, @@ -527,6 +530,13 @@ static void rtw_phy_dig(struct rtw_dev *rtwdev) */ rtw_phy_dig_recorder(dm_info, cur_igi, fa_cnt); + /* Mitigate beacon loss and connectivity issues, mainly (only?) + * in the 5 GHz band + */ + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A && rtwdev->beacon_loss && + linked && dm_info->total_fa_cnt < DIG_PERF_FA_TH_EXTRA_HIGH) + cur_igi = DIG_CVRG_MIN; + if (cur_igi != pre_igi) rtw_phy_dig_write(rtwdev, cur_igi); } @@ -1041,7 +1051,8 @@ void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg) { struct rtw_hal *hal = &rtwdev->hal; struct rtw_efuse *efuse = &rtwdev->efuse; - struct rtw_phy_cond cond = {0}; + struct rtw_phy_cond cond = {}; + struct rtw_phy_cond2 cond2 = {}; cond.cut = hal->cut_version ? hal->cut_version : 15; cond.pkg = pkg ? pkg : 15; @@ -1061,15 +1072,34 @@ void rtw_phy_setup_phy_cond(struct rtw_dev *rtwdev, u32 pkg) break; } + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A || + rtwdev->chip->id == RTW_CHIP_TYPE_8821A) { + cond.rfe = 0; + cond.rfe |= efuse->ext_lna_2g; + cond.rfe |= efuse->ext_pa_2g << 1; + cond.rfe |= efuse->ext_lna_5g << 2; + cond.rfe |= efuse->ext_pa_5g << 3; + cond.rfe |= efuse->btcoex << 4; + + cond2.type_alna = efuse->alna_type; + cond2.type_glna = efuse->glna_type; + cond2.type_apa = efuse->apa_type; + cond2.type_gpa = efuse->gpa_type; + } + hal->phy_cond = cond; + hal->phy_cond2 = cond2; - rtw_dbg(rtwdev, RTW_DBG_PHY, "phy cond=0x%08x\n", *((u32 *)&hal->phy_cond)); + rtw_dbg(rtwdev, RTW_DBG_PHY, "phy cond=0x%08x cond2=0x%08x\n", + *((u32 *)&hal->phy_cond), *((u32 *)&hal->phy_cond2)); } -static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond) +static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond, + struct rtw_phy_cond2 cond2) { struct rtw_hal *hal = &rtwdev->hal; struct rtw_phy_cond drv_cond = hal->phy_cond; + struct rtw_phy_cond2 drv_cond2 = hal->phy_cond2; if (cond.cut && cond.cut != drv_cond.cut) return false; @@ -1080,8 +1110,29 @@ static bool check_positive(struct rtw_dev *rtwdev, struct rtw_phy_cond cond) if (cond.intf && cond.intf != drv_cond.intf) return false; - if (cond.rfe != drv_cond.rfe) - return false; + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A || + rtwdev->chip->id == RTW_CHIP_TYPE_8821A) { + if (!(cond.rfe & 0x0f)) + return true; + + if ((cond.rfe & drv_cond.rfe) != cond.rfe) + return false; + + if ((cond.rfe & BIT(0)) && cond2.type_glna != drv_cond2.type_glna) + return false; + + if ((cond.rfe & BIT(1)) && cond2.type_gpa != drv_cond2.type_gpa) + return false; + + if ((cond.rfe & BIT(2)) && cond2.type_alna != drv_cond2.type_alna) + return false; + + if ((cond.rfe & BIT(3)) && cond2.type_apa != drv_cond2.type_apa) + return false; + } else { + if (cond.rfe != drv_cond.rfe) + return false; + } return true; } @@ -1090,7 +1141,8 @@ void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl) { const union phy_table_tile *p = tbl->data; const union phy_table_tile *end = p + tbl->size / 2; - struct rtw_phy_cond pos_cond = {0}; + struct rtw_phy_cond pos_cond = {}; + struct rtw_phy_cond2 pos_cond2 = {}; bool is_matched = true, is_skipped = false; BUILD_BUG_ON(sizeof(union phy_table_tile) != sizeof(struct phy_cfg_pair)); @@ -1109,11 +1161,12 @@ void rtw_parse_tbl_phy_cond(struct rtw_dev *rtwdev, const struct rtw_table *tbl) case BRANCH_ELIF: default: pos_cond = p->cond; + pos_cond2 = p->cond2; break; } } else if (p->cond.neg) { if (!is_skipped) { - if (check_positive(rtwdev, pos_cond)) { + if (check_positive(rtwdev, pos_cond, pos_cond2)) { is_matched = true; is_skipped = true; } else { @@ -1470,10 +1523,8 @@ static void rtw_phy_store_tx_power_by_rate(struct rtw_dev *rtwdev, rate = rates[i]; if (band == PHY_BAND_2G) hal->tx_pwr_by_rate_offset_2g[rfpath][rate] = offset; - else if (band == PHY_BAND_5G) - hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset; else - continue; + hal->tx_pwr_by_rate_offset_5g[rfpath][rate] = offset; } } @@ -2125,8 +2176,8 @@ void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, *limit = rtw_phy_get_tx_power_limit(rtwdev, band, bw, path, rate, ch, regd); - *remnant = (rate <= DESC_RATE11M ? dm_info->txagc_remnant_cck : - dm_info->txagc_remnant_ofdm); + *remnant = rate <= DESC_RATE11M ? dm_info->txagc_remnant_cck : + dm_info->txagc_remnant_ofdm[path]; *sar = rtw_phy_get_tx_power_sar(rtwdev, hal->sar_band, path, rate); } @@ -2340,7 +2391,8 @@ void rtw_phy_init_tx_power(struct rtw_dev *rtwdev) void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, struct rtw_swing_table *swing_table) { - const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl; + const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev); + const struct rtw_pwr_track_tbl *tbl = rfe_def->pwr_track_tbl; u8 channel = rtwdev->hal.current_channel; if (IS_CH_2G_BAND(channel)) { diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 4d9b8668e8b047..e4d506cf9c331e 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -9,6 +9,7 @@ #define BIT_FEN_EN_25_1 BIT(13) #define BIT_FEN_ELDR BIT(12) #define BIT_FEN_CPUEN BIT(2) +#define BIT_FEN_USBA BIT(2) #define BIT_FEN_BB_GLB_RST BIT(1) #define BIT_FEN_BB_RSTB BIT(0) #define BIT_R_DIS_PRST BIT(6) @@ -16,6 +17,10 @@ #define REG_SYS_PW_CTRL 0x0004 #define BIT_PFM_WOWL BIT(3) #define BIT_APFM_OFFMAC BIT(9) +#define REG_APS_FSMCO 0x0004 +#define APS_FSMCO_MAC_ENABLE BIT(8) +#define APS_FSMCO_MAC_OFF BIT(9) +#define APS_FSMCO_HW_POWERDOWN BIT(15) #define REG_SYS_CLK_CTRL 0x0008 #define BIT_CPU_CLK_EN BIT(14) @@ -58,6 +63,8 @@ #define BIT_SHIFT_LDO25_VOLTAGE 4 #define BIT_LDO25_EN BIT(7) +#define REG_ACLK_MON 0x3e + #define REG_GPIO_MUXCFG 0x0040 #define BIT_FSPI_EN BIT(19) #define BIT_EN_SIC BIT(12) @@ -90,6 +97,8 @@ #define BIT_USB_SUS_DIS BIT(8) #define BIT_SDIO_PAD_E5 BIT(18) +#define REG_RF_B_CTRL 0x76 + #define REG_AFE_CTRL_4 0x0078 #define BIT_CK320M_AFE_EN BIT(4) #define BIT_EN_SYN BIT(15) @@ -134,6 +143,11 @@ #define REG_PMC_DBG_CTRL1 0xa8 #define BITS_PMC_BT_IQK_STS GENMASK(22, 21) +#define REG_HIMR0 0xb0 +#define REG_HISR0 0xb4 +#define REG_HIMR1 0xb8 +#define REG_HISR1 0xbc + #define REG_PAD_CTRL2 0x00C4 #define BIT_RSM_EN_V1 BIT(16) #define BIT_NO_PDN_CHIPOFF_V1 BIT(17) @@ -185,6 +199,15 @@ #define MAC_TRX_ENABLE (BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | \ BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | \ BIT_MACTXEN | BIT_MACRXEN) +#define REG_PBP 0x104 +#define PBP_RX_MASK 0x0f +#define PBP_TX_MASK 0xf0 +#define PBP_64 0x0 +#define PBP_128 0x1 +#define PBP_256 0x2 +#define PBP_512 0x3 +#define PBP_1024 0x4 + #define BIT_SHIFT_TXDMA_VOQ_MAP 4 #define BIT_MASK_TXDMA_VOQ_MAP 0x3 #define BIT_TXDMA_VOQ_MAP(x) \ @@ -256,6 +279,8 @@ #define REG_HMEBOX1 0x01D4 #define REG_HMEBOX2 0x01D8 #define REG_HMEBOX3 0x01DC +#define REG_LLT_INIT 0x01E0 +#define BIT_LLT_WRITE_ACCESS BIT(30) #define REG_HMEBOX0_EX 0x01F0 #define REG_HMEBOX1_EX 0x01F4 #define REG_HMEBOX2_EX 0x01F8 @@ -298,6 +323,7 @@ #define REG_AUTO_LLT 0x0224 #define BIT_AUTO_INIT_LLT BIT(16) +#define REG_DWBCN1_CTRL 0x0228 #define REG_RQPN_CTRL_1 0x0228 #define REG_RQPN_CTRL_2 0x022C #define BIT_LD_RQPN BIT(31) @@ -329,6 +355,7 @@ #define BIT_DMA_BURST_SIZE_1024 0 #define REG_RXPKTNUM 0x02B0 +#define REG_EARLY_MODE_CONTROL 0x02BC #define REG_INT_MIG 0x0304 #define REG_HCI_MIX_CFG 0x03FC @@ -336,6 +363,7 @@ #define REG_BCNQ_INFO 0x0418 #define BIT_MGQ_CPU_EMPTY BIT(24) +#define REG_TXPKT_EMPTY 0x041A #define REG_FWHW_TXQ_CTRL 0x0420 #define BIT_EN_BCNQ_DL BIT(22) #define BIT_EN_WR_FREE_TAIL BIT(20) @@ -362,10 +390,12 @@ #define REG_AMPDU_MAX_TIME_V1 0x0455 #define REG_BCNQ1_BDNY_V1 0x0456 #define REG_AMPDU_MAX_TIME 0x0456 +#define REG_AMPDU_MAX_LENGTH 0x0458 #define REG_WMAC_LBK_BF_HD 0x045D #define REG_TX_HANG_CTRL 0x045E #define BIT_EN_GNT_BT_AWAKE BIT(3) #define BIT_EN_EOF_V1 BIT(2) +#define REG_FAST_EDCA_CTRL 0x0460 #define REG_DATA_SC 0x0483 #define REG_ARFR2_V1 0x048C #define REG_ARFRH2_V1 0x0490 @@ -390,6 +420,8 @@ #define REG_PRECNT_CTRL 0x04E5 #define BIT_BTCCA_CTRL (BIT(0) | BIT(1)) #define BIT_EN_PRECNT BIT(11) +#define REG_TX_RPT_CTRL 0x04EC +#define REG_TX_RPT_TIME 0x04F0 #define REG_DUMMY_PAGE4_V1 0x04FC #define REG_EDCA_VO_PARAM 0x0500 @@ -400,6 +432,7 @@ #define BIT_MASK_CWMAX GENMASK(15, 12) #define BIT_MASK_CWMIN GENMASK(11, 8) #define BIT_MASK_AIFS GENMASK(7, 0) +#define REG_BCNTCFG 0x0510 #define REG_PIFS 0x0512 #define REG_SIFS 0x0514 #define BIT_SHIFT_SIFS_OFDM_CTX 8 @@ -526,6 +559,8 @@ #define REG_BT_COEX_V2 0x0762 #define BIT_GNT_BT_POLARITY BIT(12) #define BIT_LTE_COEX_EN BIT(7) +#define REG_GNT_BT 0x0765 +#define BIT_PTA_SW_CTL GENMASK(4, 3) #define REG_BT_COEX_ENH_INTR_CTRL 0x76E #define BIT_R_GRANTALL_WLMASK BIT(3) #define BIT_STATIS_BT_EN BIT(2) @@ -543,14 +578,43 @@ #define REG_FPGA0_RFMOD 0x0800 #define BIT_CCKEN BIT(24) #define BIT_OFDMEN BIT(25) +#define REG_CCK_RPT_FORMAT 0x0804 +#define BIT_CCK_RPT_FORMAT BIT(16) +#define REG_RXPSEL 0x0808 +#define BIT_RX_PSEL_RST (BIT(28) | BIT(29)) +#define REG_TXPSEL 0x080C #define REG_RX_GAIN_EN 0x081c +#define REG_CCASEL 0x082C +#define REG_PDMFTH 0x0830 +#define REG_BWINDICATION 0x0834 +#define REG_CCA2ND 0x0838 +#define REG_L1PKTH 0x0848 +#define REG_CLKTRK 0x0860 +#define REG_ADCCLK 0x08AC +#define REG_HSSI_READ 0x08B0 +#define REG_FPGA0_XCD_RF_PARA 0x08B4 +#define REG_RX_MCS_LIMIT 0x08BC +#define REG_ADC160 0x08C4 +#define REG_ANTSEL_SW 0x0900 +#define REG_DAC_RSTB 0x090c +#define REG_SINGLE_TONE_CONT_TX 0x0914 #define REG_RFE_CTRL_E 0x0974 #define REG_2ND_CCA_CTRL 0x0976 +#define REG_IQK_COM00 0x0978 +#define REG_IQK_COM32 0x097c +#define REG_IQK_COM64 0x0980 +#define REG_IQK_COM96 0x0984 + +#define REG_FAS 0x09a4 +#define REG_RXSB 0x0a00 +#define REG_CCK_RX 0x0a04 +#define REG_CCK_PD_TH 0x0a0a #define REG_CCK0_FAREPORT 0xa2c #define BIT_CCK0_2RX BIT(18) #define BIT_CCK0_MRC BIT(22) +#define REG_FA_CCK 0x0a5c #define REG_DIS_DPD 0x0a70 #define DIS_DPD_MASK GENMASK(9, 0) @@ -566,13 +630,109 @@ #define DIS_DPD_RATEVHT2SS_MCS1 BIT(9) #define DIS_DPD_RATEALL GENMASK(9, 0) +#define REG_CNTRST 0x0b58 + +#define REG_3WIRE_SWA 0x0c00 +#define REG_RX_IQC_AB_A 0x0c10 +#define REG_TXSCALE_A 0x0c1c +#define BB_SWING_MASK GENMASK(31, 21) +#define REG_TX_AGC_A_CCK_11_CCK_1 0xc20 +#define REG_TX_AGC_A_OFDM18_OFDM6 0xc24 +#define REG_TX_AGC_A_OFDM54_OFDM24 0xc28 +#define REG_TX_AGC_A_MCS3_MCS0 0xc2c +#define REG_TX_AGC_A_MCS7_MCS4 0xc30 +#define REG_TX_AGC_A_MCS11_MCS8 0xc34 +#define REG_TX_AGC_A_MCS15_MCS12 0xc38 +#define REG_TX_AGC_A_NSS1_INDEX3_NSS1_INDEX0 0xc3c +#define REG_TX_AGC_A_NSS1_INDEX7_NSS1_INDEX4 0xc40 +#define REG_TX_AGC_A_NSS2_INDEX1_NSS1_INDEX8 0xc44 +#define REG_TX_AGC_A_NSS2_INDEX5_NSS2_INDEX2 0xc48 +#define REG_TX_AGC_A_NSS2_INDEX9_NSS2_INDEX6 0xc4c +#define REG_RXIGI_A 0x0c50 +#define REG_TX_PWR_TRAINING_A 0x0c54 +#define REG_CK_MONHA 0x0c5c +#define REG_AFE_PWR1_A 0x0c60 +#define REG_AFE_PWR2_A 0x0c64 +#define REG_RX_WAIT_CCA_TX_CCK_RFON_A 0x0c68 +#define REG_OFDM0_XA_TX_IQ_IMBALANCE 0x0c80 +#define REG_OFDM0_A_TX_AFE 0x0c84 +#define REG_OFDM0_XB_TX_IQ_IMBALANCE 0x0c88 +#define REG_TSSI_TRK_SW 0x0c8c +#define REG_LSSI_WRITE_A 0x0c90 +#define REG_PREDISTA 0x0c90 +#define REG_TXAGCIDX 0x0c94 + +#define REG_RFE_PINMUX_A 0x0cb0 +#define REG_RFE_INV_A 0x0cb4 #define REG_RFE_CTRL8 0x0cb4 #define BIT_MASK_RFE_SEL89 GENMASK(7, 0) +#define PTA_CTRL_PIN 0x66 +#define DPDT_CTRL_PIN 0x77 +#define RFE_INV_MASK 0x3ff00000 +#define REG_RFECTL_A 0x0cb8 #define REG_RFE_INV8 0x0cbd #define BIT_MASK_RFE_INV89 GENMASK(1, 0) #define REG_RFE_INV16 0x0cbe #define BIT_RFE_BUF_EN BIT(3) +#define REG_IQK_DPD_CFG 0x0cc4 +#define REG_CFG_PMPD 0x0cc8 +#define REG_IQC_Y 0x0ccc +#define REG_IQC_X 0x0cd4 +#define REG_INTPO_SETA 0x0ce8 + +#define REG_IQKA_END 0x0d00 +#define REG_PI_READ_A 0x0d04 +#define REG_SI_READ_A 0x0d08 +#define REG_IQKB_END 0x0d40 +#define REG_PI_READ_B 0x0d44 +#define REG_SI_READ_B 0x0d48 + +#define REG_3WIRE_SWB 0x0e00 +#define REG_RX_IQC_AB_B 0x0e10 +#define REG_TXSCALE_B 0x0e1c +#define REG_TX_AGC_B_CCK_11_CCK_1 0xe20 +#define REG_TX_AGC_B_OFDM18_OFDM6 0xe24 +#define REG_TX_AGC_B_OFDM54_OFDM24 0xe28 +#define REG_TX_AGC_B_MCS3_MCS0 0xe2c +#define REG_TX_AGC_B_MCS7_MCS4 0xe30 +#define REG_TX_AGC_B_MCS11_MCS8 0xe34 +#define REG_TX_AGC_B_MCS15_MCS12 0xe38 +#define REG_TX_AGC_B_NSS1_INDEX3_NSS1_INDEX0 0xe3c +#define REG_TX_AGC_B_NSS1_INDEX7_NSS1_INDEX4 0xe40 +#define REG_TX_AGC_B_NSS2_INDEX1_NSS1_INDEX8 0xe44 +#define REG_TX_AGC_B_NSS2_INDEX5_NSS2_INDEX2 0xe48 +#define REG_TX_AGC_B_NSS2_INDEX9_NSS2_INDEX6 0xe4c +#define REG_RXIGI_B 0x0e50 +#define REG_TX_PWR_TRAINING_B 0x0e54 +#define REG_CK_MONHB 0x0e5c +#define REG_AFE_PWR1_B 0x0e60 +#define REG_AFE_PWR2_B 0x0e64 +#define REG_RX_WAIT_CCA_TX_CCK_RFON_B 0x0e68 +#define REG_TXTONEB 0x0e80 +#define REG_RXTONEB 0x0e84 +#define REG_TXPITMB 0x0e88 +#define REG_RXPITMB 0x0e8c +#define REG_LSSI_WRITE_B 0x0e90 +#define REG_PREDISTB 0x0e90 +#define REG_INIDLYB 0x0e94 +#define REG_RFE_PINMUX_B 0x0eb0 +#define REG_RFE_INV_B 0x0eb4 +#define REG_RFECTL_B 0x0eb8 +#define REG_BPBDB 0x0ec4 +#define REG_PHYTXONB 0x0ec8 +#define REG_IQKYB 0x0ecc +#define REG_IQKXB 0x0ed4 +#define REG_INTPO_SETB 0x0ee8 + +#define REG_CRC_CCK 0x0f04 +#define REG_CCA_OFDM 0x0f08 +#define REG_CRC_VHT 0x0f0c +#define REG_CRC_HT 0x0f10 +#define REG_CRC_OFDM 0x0f14 +#define REG_FA_OFDM 0x0f48 +#define REG_CCA_CCK 0x0fcc + #define REG_ANAPARSW_MAC_0 0x1010 #define BIT_CF_L_V2 GENMASK(29, 28) @@ -709,6 +869,10 @@ #define REG_IGN_GNTBT4 0x4160 +#define REG_USB_MOD 0xf008 +#define REG_USB3_RXITV 0xf050 +#define REG_USB_HRPWM 0xfe58 + #define RF_MODE 0x00 #define RF_MODOPT 0x01 #define RF_WLINT 0x01 @@ -716,7 +880,13 @@ #define RF_DTXLOK 0x08 #define RF_CFGCH 0x18 #define BIT_BAND GENMASK(18, 16) +#define RF18_BAND_MASK (BIT(16) | BIT(9) | BIT(8)) +#define RF18_CHANNEL_MASK (MASKBYTE0) +#define RF18_RFSI_MASK (BIT(18) | BIT(17)) #define RF_RCK 0x1d +#define RF_MODE_TABLE_ADDR 0x30 +#define RF_MODE_TABLE_DATA0 0x31 +#define RF_MODE_TABLE_DATA1 0x32 #define RF_LUTWA 0x33 #define RF_LUTWD1 0x3e #define RF_LUTWD0 0x3f @@ -725,10 +895,14 @@ #define RF_T_METER 0x42 #define RF_BSPAD 0x54 #define RF_GAINTX 0x56 +#define RF_TXMOD 0x58 #define RF_TXATANK 0x64 +#define RF_TXA_PREPAD 0x65 #define RF_TRXIQ 0x66 #define RF_RXIQGEN 0x8d +#define RF_RXBB2 0x8f #define RF_SYN_PFD 0xb0 +#define RF_LCK 0xb4 #define RF_XTALX2 0xb8 #define RF_SYN_CTRL 0xbb #define RF_MALSEL 0xbe diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c index 222608de33cdec..a19b94d022ee64 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c @@ -29,9 +29,6 @@ #define TBTT_PROHIBIT_HOLD_TIME 0x80 #define TBTT_PROHIBIT_HOLD_TIME_STOP_BCN 0x64 -/* raw pkt_stat->drv_info_sz is in unit of 8-bytes */ -#define RX_DRV_INFO_SZ_UNIT_8703B 8 - #define TRANS_SEQ_END \ 0xFFFF, \ RTW_PWR_CUT_ALL_MSK, \ @@ -481,14 +478,14 @@ static const struct rtw_pwr_seq_cmd trans_act_to_lps_8703b[] = { {TRANS_SEQ_END}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8703b[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8703b[] = { trans_pre_enable_8703b, trans_carddis_to_cardemu_8703b, trans_cardemu_to_act_8703b, NULL }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8703b[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8703b[] = { trans_act_to_lps_8703b, trans_act_to_reset_mcu_8703b, trans_act_to_cardemu_8703b, @@ -496,11 +493,6 @@ static const struct rtw_pwr_seq_cmd *card_disable_flow_8703b[] = { NULL }; -static const struct rtw_rfe_def rtw8703b_rfe_defs[] = { - [0] = { .phy_pg_tbl = &rtw8703b_bb_pg_tbl, - .txpwr_lmt_tbl = &rtw8703b_txpwr_lmt_tbl,}, -}; - static const struct rtw_page_table page_table_8703b[] = { {12, 2, 2, 0, 1}, {12, 2, 2, 0, 1}, @@ -640,7 +632,7 @@ static void rtw8703b_pwrtrack_init(struct rtw_dev *rtwdev) dm_info->pwr_trk_init_trigger = true; dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; dm_info->txagc_remnant_cck = 0; - dm_info->txagc_remnant_ofdm = 0; + dm_info->txagc_remnant_ofdm[RF_PATH_A] = 0; } static void rtw8703b_phy_set_param(struct rtw_dev *rtwdev) @@ -1032,57 +1024,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, query_phy_status_ofdm(rtwdev, phy_status, pkt_stat); } -static void rtw8703b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = 0; - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - pkt_stat->drv_info_sz *= RX_DRV_INFO_SZ_UNIT_8703B; - - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - - pkt_stat->bw = GET_RX_DESC_BW(rx_desc); - - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); - - /* Rtl8723cs driver checks for size < 14 or size > 8192 and - * simply drops the packet. Maybe this should go into - * rtw_rx_fill_rx_status()? - */ - if (pkt_stat->pkt_len == 0) { - rx_status->flag |= RX_FLAG_NO_PSDU; - rtw_dbg(rtwdev, RTW_DBG_RX, "zero length packet"); - } -} - #define ADDA_ON_VAL_8703B 0x03c00014 static @@ -1643,7 +1584,7 @@ static void rtw8703b_pwrtrack_set_ofdm_pwr(struct rtw_dev *rtwdev, s8 swing_idx, { struct rtw_dm_info *dm_info = &rtwdev->dm_info; - dm_info->txagc_remnant_ofdm = txagc_idx; + dm_info->txagc_remnant_ofdm[RF_PATH_A] = txagc_idx; /* Only path A is calibrated for rtl8703b */ rtw8703b_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_A); @@ -1872,6 +1813,12 @@ static const struct rtw_pwr_track_tbl rtw8703b_rtw_pwr_track_tbl = { .pwrtrk_xtal_p = rtw8703b_pwrtrk_xtal_p, }; +static const struct rtw_rfe_def rtw8703b_rfe_defs[] = { + [0] = { .phy_pg_tbl = &rtw8703b_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8703b_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8703b_rtw_pwr_track_tbl, }, +}; + /* Shared-Antenna Coex Table */ static const struct coex_table_para table_sant_8703b[] = { {0xffffffff, 0xffffffff}, /* case-0 */ @@ -1941,14 +1888,16 @@ static const struct coex_tdma_para tdma_sant_8703b[] = { { {0x61, 0x08, 0x03, 0x11, 0x11} }, }; -static struct rtw_chip_ops rtw8703b_ops = { +static const struct rtw_chip_ops rtw8703b_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .mac_init = rtw8723x_mac_init, .dump_fw_crash = NULL, .shutdown = NULL, .read_efuse = rtw8703b_read_efuse, .phy_set_param = rtw8703b_phy_set_param, .set_channel = rtw8703b_set_channel, - .query_rx_desc = rtw8703b_query_rx_desc, + .query_phy_status = query_phy_status, .read_rf = rtw_phy_read_rf_sipi, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8723x_set_tx_power_index, @@ -2014,6 +1963,9 @@ const struct rtw_chip_info rtw8703b_hw_spec = { .max_power_index = 0x3f, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .usb_tx_agg_desc_num = 1, /* Not sure if this chip has USB interface */ + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = true, .path_div_supported = false, .ht_supported = true, @@ -2046,7 +1998,6 @@ const struct rtw_chip_info rtw8703b_hw_spec = { .rfe_defs_size = ARRAY_SIZE(rtw8703b_rfe_defs), .iqk_threshold = 8, - .pwr_track_tbl = &rtw8703b_rtw_pwr_track_tbl, /* WOWLAN firmware exists, but not implemented yet */ .wow_fw_name = "rtw88/rtw8703b_wow_fw.bin", diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 3fba4054d45f49..eeca31bf71f166 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -79,7 +79,7 @@ static void rtw8723d_pwrtrack_init(struct rtw_dev *rtwdev) dm_info->pwr_trk_init_trigger = true; dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; dm_info->txagc_remnant_cck = 0; - dm_info->txagc_remnant_ofdm = 0; + dm_info->txagc_remnant_ofdm[RF_PATH_A] = 0; } static void rtw8723d_phy_set_param(struct rtw_dev *rtwdev) @@ -227,47 +227,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, } } -static void rtw8723d_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = 0; - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - /* drv_info_sz is in unit of 8-bytes */ - pkt_stat->drv_info_sz *= 8; - - /* c2h cmd pkt's rx/phy status is not interested */ - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); -} - static bool rtw8723d_check_spur_ov_thres(struct rtw_dev *rtwdev, u8 channel, u32 thres) { @@ -1306,7 +1265,7 @@ static void rtw8723d_pwrtrack_set_ofdm_pwr(struct rtw_dev *rtwdev, s8 swing_idx, { struct rtw_dm_info *dm_info = &rtwdev->dm_info; - dm_info->txagc_remnant_ofdm = txagc_idx; + dm_info->txagc_remnant_ofdm[RF_PATH_A] = txagc_idx; rtw8723d_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_A); rtw8723d_set_iqk_matrix(rtwdev, swing_idx, RF_PATH_B); @@ -1430,10 +1389,12 @@ static void rtw8723d_pwr_track(struct rtw_dev *rtwdev) dm_info->pwr_trk_triggered = false; } -static struct rtw_chip_ops rtw8723d_ops = { +static const struct rtw_chip_ops rtw8723d_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .phy_set_param = rtw8723d_phy_set_param, .read_efuse = rtw8723x_read_efuse, - .query_rx_desc = rtw8723d_query_rx_desc, + .query_phy_status = query_phy_status, .set_channel = rtw8723d_set_channel, .mac_init = rtw8723x_mac_init, .shutdown = rtw8723d_shutdown, @@ -1788,7 +1749,7 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8723d[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8723d[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8723d[] = { trans_carddis_to_cardemu_8723d, trans_cardemu_to_act_8723d, NULL @@ -2004,7 +1965,7 @@ static const struct rtw_pwr_seq_cmd trans_act_to_post_carddis_8723d[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8723d[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8723d[] = { trans_act_to_lps_8723d, trans_act_to_pre_carddis_8723d, trans_act_to_cardemu_8723d, @@ -2059,11 +2020,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8723d = { .n_gen1_para = ARRAY_SIZE(pcie_gen1_param_8723d), }; -static const struct rtw_rfe_def rtw8723d_rfe_defs[] = { - [0] = { .phy_pg_tbl = &rtw8723d_bb_pg_tbl, - .txpwr_lmt_tbl = &rtw8723d_txpwr_lmt_tbl,}, -}; - static const u8 rtw8723d_pwrtrk_2gb_n[] = { 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10 @@ -2127,6 +2083,12 @@ static const struct rtw_pwr_track_tbl rtw8723d_rtw_pwr_track_tbl = { .pwrtrk_xtal_n = rtw8723d_pwrtrk_xtal_n, }; +static const struct rtw_rfe_def rtw8723d_rfe_defs[] = { + [0] = { .phy_pg_tbl = &rtw8723d_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8723d_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, }, +}; + static const struct rtw_reg_domain coex_info_hw_regs_8723d[] = { {0x948, MASKDWORD, RTW_REG_DOMAIN_MAC32}, {0x67, BIT(7), RTW_REG_DOMAIN_MAC8}, @@ -2172,6 +2134,9 @@ const struct rtw_chip_info rtw8723d_hw_spec = { .page_size = TX_PAGE_SIZE, .dig_min = 0x20, .usb_tx_agg_desc_num = 1, + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = true, .ht_supported = true, .vht_supported = false, .lps_deep_mode_supported = 0, @@ -2195,7 +2160,6 @@ const struct rtw_chip_info rtw8723d_hw_spec = { .rfe_defs = rtw8723d_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8723d_rfe_defs), .rx_ldpc = false, - .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, .iqk_threshold = 8, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.c b/drivers/net/wireless/realtek/rtw88/rtw8723x.c index 0d0b6c2cb9aa19..69f73cb5b4cd5b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723x.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.c @@ -595,7 +595,8 @@ void __rtw8723x_pwrtrack_set_xtal(struct rtw_dev *rtwdev, u8 therm_path, u8 delta) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; - const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl; + const struct rtw_rfe_def *rfe_def = rtw_get_rfe_def(rtwdev); + const struct rtw_pwr_track_tbl *tbl = rfe_def->pwr_track_tbl; const s8 *pwrtrk_xtal; s8 xtal_cap; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c new file mode 100644 index 00000000000000..482edd31823d08 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -0,0 +1,1102 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "main.h" +#include "coex.h" +#include "phy.h" +#include "reg.h" +#include "rtw88xxa.h" +#include "rtw8812a.h" +#include "rtw8812a_table.h" +#include "tx.h" + +static void rtw8812a_power_off(struct rtw_dev *rtwdev) +{ + rtw88xxa_power_off(rtwdev, enter_lps_flow_8812a); +} + +static s8 rtw8812a_cck_rx_pwr(u8 lna_idx, u8 vga_idx) +{ + s8 rx_pwr_all = 0; + + switch (lna_idx) { + case 7: + if (vga_idx <= 27) + rx_pwr_all = -94 + 2 * (27 - vga_idx); + else + rx_pwr_all = -94; + break; + case 6: + rx_pwr_all = -42 + 2 * (2 - vga_idx); + break; + case 5: + rx_pwr_all = -36 + 2 * (7 - vga_idx); + break; + case 4: + rx_pwr_all = -30 + 2 * (7 - vga_idx); + break; + case 3: + rx_pwr_all = -18 + 2 * (7 - vga_idx); + break; + case 2: + rx_pwr_all = 2 * (5 - vga_idx); + break; + case 1: + rx_pwr_all = 14 - 2 * vga_idx; + break; + case 0: + rx_pwr_all = 20 - 2 * vga_idx; + break; + default: + break; + } + + return rx_pwr_all; +} + +static void rtw8812a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat) +{ + rtw88xxa_query_phy_status(rtwdev, phy_status, pkt_stat, + rtw8812a_cck_rx_pwr); + + if (pkt_stat->rate >= DESC_RATE6M) + return; + + if (rtwdev->hal.cck_high_power) + return; + + if (pkt_stat->rssi >= 80) + pkt_stat->rssi = ((pkt_stat->rssi - 80) << 1) + + ((pkt_stat->rssi - 80) >> 1) + 80; + else if (pkt_stat->rssi <= 78 && pkt_stat->rssi >= 20) + pkt_stat->rssi += 3; +} + +static void rtw8812a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) +{ +} + +static void rtw8812a_do_lck(struct rtw_dev *rtwdev) +{ + u32 cont_tx, lc_cal, i; + + cont_tx = rtw_read32_mask(rtwdev, REG_SINGLE_TONE_CONT_TX, 0x70000); + + lc_cal = rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK); + + if (!cont_tx) + rtw_write8(rtwdev, REG_TXPAUSE, 0xff); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_LCK, BIT(14), 1); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x08000, 1); + + mdelay(150); + + for (i = 0; i < 5; i++) { + if (rtw_read_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x08000) != 1) + break; + + mdelay(10); + } + + if (i == 5) + rtw_dbg(rtwdev, RTW_DBG_RFK, "LCK timed out\n"); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_LCK, BIT(14), 0); + + if (!cont_tx) + rtw_write8(rtwdev, REG_TXPAUSE, 0); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, RFREG_MASK, lc_cal); +} + +static void rtw8812a_iqk_backup_rf(struct rtw_dev *rtwdev, u32 *rfa_backup, + u32 *rfb_backup, const u32 *backup_rf_reg, + u32 rf_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Save RF Parameters */ + for (i = 0; i < rf_num; i++) { + rfa_backup[i] = rtw_read_rf(rtwdev, RF_PATH_A, + backup_rf_reg[i], MASKDWORD); + rfb_backup[i] = rtw_read_rf(rtwdev, RF_PATH_B, + backup_rf_reg[i], MASKDWORD); + } +} + +static void rtw8812a_iqk_restore_rf(struct rtw_dev *rtwdev, + enum rtw_rf_path path, + const u32 *backup_rf_reg, + u32 *RF_backup, u32 rf_reg_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + for (i = 0; i < rf_reg_num; i++) + rtw_write_rf(rtwdev, path, backup_rf_reg[i], + RFREG_MASK, RF_backup[i]); + + rtw_write_rf(rtwdev, path, RF_LUTWE, RFREG_MASK, 0); +} + +static void rtw8812a_iqk_restore_afe(struct rtw_dev *rtwdev, u32 *afe_backup, + const u32 *backup_afe_reg, u32 afe_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Reload AFE Parameters */ + for (i = 0; i < afe_num; i++) + rtw_write32(rtwdev, backup_afe_reg[i], afe_backup[i]); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x0); + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x0); + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x0); + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000); + rtw_write32_mask(rtwdev, REG_LSSI_WRITE_A, BIT(7), 1); + rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(18), 1); + rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(29), 1); + rtw_write32_mask(rtwdev, REG_CFG_PMPD, BIT(29), 1); + + rtw_write32(rtwdev, REG_TXTONEB, 0x0); + rtw_write32(rtwdev, REG_RXTONEB, 0x0); + rtw_write32(rtwdev, REG_TXPITMB, 0x0); + rtw_write32(rtwdev, REG_RXPITMB, 0x3c000000); + rtw_write32_mask(rtwdev, REG_LSSI_WRITE_B, BIT(7), 1); + rtw_write32_mask(rtwdev, REG_BPBDB, BIT(18), 1); + rtw_write32_mask(rtwdev, REG_BPBDB, BIT(29), 1); + rtw_write32_mask(rtwdev, REG_PHYTXONB, BIT(29), 1); +} + +static void rtw8812a_iqk_rx_fill(struct rtw_dev *rtwdev, enum rtw_rf_path path, + unsigned int rx_x, unsigned int rx_y) +{ + switch (path) { + case RF_PATH_A: + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + if (rx_x >> 1 >= 0x112 || + (rx_y >> 1 >= 0x12 && rx_y >> 1 <= 0x3ee)) { + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x000003ff, 0x100); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x03ff0000, 0); + } else { + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x000003ff, rx_x >> 1); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x03ff0000, rx_y >> 1); + } + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x = %x;;rx_y = %x ====>fill to IQC\n", + rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff); + rtw_dbg(rtwdev, RTW_DBG_RFK, "0xc10 = %x ====>fill to IQC\n", + rtw_read32(rtwdev, REG_RX_IQC_AB_A)); + break; + case RF_PATH_B: + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + if (rx_x >> 1 >= 0x112 || + (rx_y >> 1 >= 0x12 && rx_y >> 1 <= 0x3ee)) { + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B, + 0x000003ff, 0x100); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B, + 0x03ff0000, 0); + } else { + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B, + 0x000003ff, rx_x >> 1); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_B, + 0x03ff0000, rx_y >> 1); + } + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x = %x;;rx_y = %x ====>fill to IQC\n", + rx_x >> 1 & 0x000003ff, rx_y >> 1 & 0x000003ff); + rtw_dbg(rtwdev, RTW_DBG_RFK, "0xe10 = %x====>fill to IQC\n", + rtw_read32(rtwdev, REG_RX_IQC_AB_B)); + break; + default: + break; + } +} + +static void rtw8812a_iqk_tx_fill(struct rtw_dev *rtwdev, enum rtw_rf_path path, + unsigned int tx_x, unsigned int tx_y) +{ + switch (path) { + case RF_PATH_A: + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_PREDISTA, BIT(7), 0x1); + rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(18), 0x1); + rtw_write32_mask(rtwdev, REG_IQK_DPD_CFG, BIT(29), 0x1); + rtw_write32_mask(rtwdev, REG_CFG_PMPD, BIT(29), 0x1); + rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, tx_y); + rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, tx_x); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x = %x;;tx_y = %x =====> fill to IQC\n", + tx_x & 0x000007ff, tx_y & 0x000007ff); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "0xcd4 = %x;;0xccc = %x ====>fill to IQC\n", + rtw_read32_mask(rtwdev, REG_IQC_X, 0x000007ff), + rtw_read32_mask(rtwdev, REG_IQC_Y, 0x000007ff)); + break; + case RF_PATH_B: + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_PREDISTB, BIT(7), 0x1); + rtw_write32_mask(rtwdev, REG_BPBDB, BIT(18), 0x1); + rtw_write32_mask(rtwdev, REG_BPBDB, BIT(29), 0x1); + rtw_write32_mask(rtwdev, REG_PHYTXONB, BIT(29), 0x1); + rtw_write32_mask(rtwdev, REG_IQKYB, 0x000007ff, tx_y); + rtw_write32_mask(rtwdev, REG_IQKXB, 0x000007ff, tx_x); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x = %x;;tx_y = %x =====> fill to IQC\n", + tx_x & 0x000007ff, tx_y & 0x000007ff); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "0xed4 = %x;;0xecc = %x ====>fill to IQC\n", + rtw_read32_mask(rtwdev, REG_IQKXB, 0x000007ff), + rtw_read32_mask(rtwdev, REG_IQKYB, 0x000007ff)); + break; + default: + break; + } +} + +static void rtw8812a_iqk(struct rtw_dev *rtwdev) +{ + int tx_x0_temp[10], tx_y0_temp[10], tx_x1_temp[10], tx_y1_temp[10]; + int rx_x0_temp[10], rx_y0_temp[10], rx_x1_temp[10], rx_y1_temp[10]; + bool iqk0_ready = false, tx0_finish = false, rx0_finish = false; + bool iqk1_ready = false, tx1_finish = false, rx1_finish = false; + u8 tx0_avg = 0, tx1_avg = 0, rx0_avg = 0, rx1_avg = 0; + int tx_x0 = 0, tx_y0 = 0, tx_x1 = 0, tx_y1 = 0; + int rx_x0 = 0, rx_y0 = 0, rx_x1 = 0, rx_y1 = 0; + struct rtw_efuse *efuse = &rtwdev->efuse; + bool tx0_fail = true, rx0_fail = true; + bool tx1_fail = true, rx1_fail = true; + u8 cal0_retry, cal1_retry; + u8 delay_count; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* ========path-A AFE all on======== */ + /* Port 0 DAC/ADC on */ + rtw_write32(rtwdev, REG_AFE_PWR1_A, 0x77777777); + rtw_write32(rtwdev, REG_AFE_PWR2_A, 0x77777777); + + /* Port 1 DAC/ADC on */ + rtw_write32(rtwdev, REG_AFE_PWR1_B, 0x77777777); + rtw_write32(rtwdev, REG_AFE_PWR2_B, 0x77777777); + + rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_A, 0x19791979); + rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_B, 0x19791979); + + /* hardware 3-wire off */ + rtw_write32_mask(rtwdev, REG_3WIRE_SWA, 0xf, 0x4); + rtw_write32_mask(rtwdev, REG_3WIRE_SWB, 0xf, 0x4); + + /* DAC/ADC sampling rate (160 MHz) */ + rtw_write32_mask(rtwdev, REG_CK_MONHA, GENMASK(26, 24), 0x7); + rtw_write32_mask(rtwdev, REG_CK_MONHB, GENMASK(26, 24), 0x7); + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + /* ====== path A TX IQK RF setting ====== */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80002); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x20000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x3fffd); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xfe83f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d5); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001); + + /* ====== path B TX IQK RF setting ====== */ + rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x80002); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_ADDR, RFREG_MASK, 0x20000); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA0, RFREG_MASK, 0x3fffd); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA1, RFREG_MASK, 0xfe83f); + rtw_write_rf(rtwdev, RF_PATH_B, RF_TXA_PREPAD, RFREG_MASK, 0x931d5); + rtw_write_rf(rtwdev, RF_PATH_B, RF_RXBB2, RFREG_MASK, 0x8a001); + + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1); + rtw_write32_mask(rtwdev, REG_INIDLYB, BIT(0), 0x1); + rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000); /* TX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000); /* RX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM96, 0x00462910); /* [0]:AGC_en, [15]:idac_K_Mask */ + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + if (efuse->ext_pa_5g) { + if (efuse->rfe_option == 1) { + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403e3); + rtw_write32(rtwdev, REG_TXPITMB, 0x821403e3); + } else { + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403f7); + rtw_write32(rtwdev, REG_TXPITMB, 0x821403f7); + } + } else { + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x821403f1); + rtw_write32(rtwdev, REG_TXPITMB, 0x821403f1); + } + + if (rtwdev->hal.current_band_type == RTW_BAND_5G) { + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x68163e96); + rtw_write32(rtwdev, REG_RXPITMB, 0x68163e96); + } else { + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28163e96); + rtw_write32(rtwdev, REG_RXPITMB, 0x28163e96); + + if (efuse->rfe_option == 3) { + if (efuse->ext_pa_2g) + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403e3); + else + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403f7); + } + } + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10); + rtw_write32(rtwdev, REG_INTPO_SETA, 0x00000000); + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_TXTONEB, 0x18008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_RXTONEB, 0x38008c10); + rtw_write32(rtwdev, REG_INTPO_SETB, 0x00000000); + + cal0_retry = 0; + cal1_retry = 0; + while (1) { + /* one shot */ + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00100000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00000000); + + for (delay_count = 0; delay_count < 20; delay_count++) { + if (!tx0_finish) + iqk0_ready = rtw_read32_mask(rtwdev, + REG_IQKA_END, + BIT(10)); + if (!tx1_finish) + iqk1_ready = rtw_read32_mask(rtwdev, + REG_IQKB_END, + BIT(10)); + if (iqk0_ready && iqk1_ready) + break; + + mdelay(1); + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "TX delay_count = %d\n", + delay_count); + + if (delay_count < 20) { /* If 20ms No Result, then cal_retry++ */ + /* ============TXIQK Check============== */ + tx0_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(12)); + tx1_fail = rtw_read32_mask(rtwdev, REG_IQKB_END, BIT(12)); + + if (!(tx0_fail || tx0_finish)) { + rtw_write32(rtwdev, REG_RFECTL_A, 0x02000000); + tx_x0_temp[tx0_avg] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x04000000); + tx_y0_temp[tx0_avg] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x0[%d] = %x ;; tx_y0[%d] = %x\n", + tx0_avg, tx_x0_temp[tx0_avg], + tx0_avg, tx_y0_temp[tx0_avg]); + + tx_x0_temp[tx0_avg] <<= 21; + tx_y0_temp[tx0_avg] <<= 21; + + tx0_avg++; + } else { + cal0_retry++; + if (cal0_retry == 10) + break; + } + + if (!(tx1_fail || tx1_finish)) { + rtw_write32(rtwdev, REG_RFECTL_B, 0x02000000); + tx_x1_temp[tx1_avg] = rtw_read32_mask(rtwdev, + REG_IQKB_END, + 0x07ff0000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x04000000); + tx_y1_temp[tx1_avg] = rtw_read32_mask(rtwdev, + REG_IQKB_END, + 0x07ff0000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x1[%d] = %x ;; tx_y1[%d] = %x\n", + tx1_avg, tx_x1_temp[tx1_avg], + tx1_avg, tx_y1_temp[tx1_avg]); + + tx_x1_temp[tx1_avg] <<= 21; + tx_y1_temp[tx1_avg] <<= 21; + + tx1_avg++; + } else { + cal1_retry++; + if (cal1_retry == 10) + break; + } + } else { + cal0_retry++; + cal1_retry++; + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "delay 20ms TX IQK Not Ready!!!!!\n"); + + if (cal0_retry == 10) + break; + } + + if (tx0_avg >= 2) + tx0_finish = rtw88xxa_iqk_finish(tx0_avg, 4, + tx_x0_temp, tx_y0_temp, &tx_x0, &tx_y0, + false, false); + + if (tx1_avg >= 2) + tx1_finish = rtw88xxa_iqk_finish(tx1_avg, 4, + tx_x1_temp, tx_y1_temp, &tx_x1, &tx_y1, + false, false); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx0_average = %d, tx1_average = %d\n", + tx0_avg, tx1_avg); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx0_finish = %d, tx1_finish = %d\n", + tx0_finish, tx1_finish); + + if (tx0_finish && tx1_finish) + break; + + if ((cal0_retry + tx0_avg) >= 10 || + (cal1_retry + tx1_avg) >= 10) + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "TXA_cal_retry = %d\n", cal0_retry); + rtw_dbg(rtwdev, RTW_DBG_RFK, "TXB_cal_retry = %d\n", cal1_retry); + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + /* Load LOK */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXMOD, 0x7fe00, + rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, 0xffc00)); + rtw_write_rf(rtwdev, RF_PATH_B, RF_TXMOD, 0x7fe00, + rtw_read_rf(rtwdev, RF_PATH_B, RF_DTXLOK, 0xffc00)); + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + if (tx0_finish) { + /* ====== path A RX IQK RF setting====== */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x30000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x3f7ff); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xfe7bf); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x88001); + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d1); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000); + } + if (tx1_finish) { + /* ====== path B RX IQK RF setting====== */ + rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x30000); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x3f7ff); + rtw_write_rf(rtwdev, RF_PATH_B, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xfe7bf); + rtw_write_rf(rtwdev, RF_PATH_B, RF_RXBB2, RFREG_MASK, 0x88001); + rtw_write_rf(rtwdev, RF_PATH_B, RF_TXA_PREPAD, RFREG_MASK, 0x931d1); + rtw_write_rf(rtwdev, RF_PATH_B, RF_LUTWE, RFREG_MASK, 0x00000); + } + + rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x0); + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + + if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE) + rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a911); + else + rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a890); + + if (efuse->rfe_option == 1) { + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777717); + rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777717); + rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077); + } else { + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777717); + rtw_write32(rtwdev, REG_RFE_INV_A, 0x02000077); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777717); + rtw_write32(rtwdev, REG_RFE_INV_B, 0x02000077); + } + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + if (tx0_finish) { + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x38008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x18008c10); + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x82140119); + } + if (tx1_finish) { + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_TXTONEB, 0x38008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_RXTONEB, 0x18008c10); + rtw_write32(rtwdev, REG_TXPITMB, 0x82140119); + } + + cal0_retry = 0; + cal1_retry = 0; + while (1) { + /* one shot */ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + if (tx0_finish) { + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000, + tx_x0 & 0x000007ff); + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF, + tx_y0 & 0x000007ff); + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + if (efuse->rfe_option == 1) + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28161500); + else + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28160cc0); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00300000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + mdelay(5); + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + } + + if (tx1_finish) { + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000, + tx_x1 & 0x000007ff); + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF, + tx_y1 & 0x000007ff); + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + if (efuse->rfe_option == 1) + rtw_write32(rtwdev, REG_RXPITMB, 0x28161500); + else + rtw_write32(rtwdev, REG_RXPITMB, 0x28160ca0); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00300000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00100000); + mdelay(5); + rtw_write32(rtwdev, REG_RXPITMB, 0x3c000000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x00000000); + } + + for (delay_count = 0; delay_count < 20; delay_count++) { + if (!rx0_finish && tx0_finish) + iqk0_ready = rtw_read32_mask(rtwdev, + REG_IQKA_END, + BIT(10)); + if (!rx1_finish && tx1_finish) + iqk1_ready = rtw_read32_mask(rtwdev, + REG_IQKB_END, + BIT(10)); + if (iqk0_ready && iqk1_ready) + break; + + mdelay(1); + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "RX delay_count = %d\n", + delay_count); + + if (delay_count < 20) { /* If 20ms No Result, then cal_retry++ */ + /* ============RXIQK Check============== */ + rx0_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(11)); + rx1_fail = rtw_read32_mask(rtwdev, REG_IQKB_END, BIT(11)); + + if (!(rx0_fail || rx0_finish) && tx0_finish) { + rtw_write32(rtwdev, REG_RFECTL_A, 0x06000000); + rx_x0_temp[rx0_avg] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x08000000); + rx_y0_temp[rx0_avg] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x0[%d] = %x ;; rx_y0[%d] = %x\n", + rx0_avg, rx_x0_temp[rx0_avg], + rx0_avg, rx_y0_temp[rx0_avg]); + + rx_x0_temp[rx0_avg] <<= 21; + rx_y0_temp[rx0_avg] <<= 21; + + rx0_avg++; + } else { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "1. RXA_cal_retry = %d\n", cal0_retry); + + cal0_retry++; + if (cal0_retry == 10) + break; + } + + if (!(rx1_fail || rx1_finish) && tx1_finish) { + rtw_write32(rtwdev, REG_RFECTL_B, 0x06000000); + rx_x1_temp[rx1_avg] = rtw_read32_mask(rtwdev, + REG_IQKB_END, + 0x07ff0000); + rtw_write32(rtwdev, REG_RFECTL_B, 0x08000000); + rx_y1_temp[rx1_avg] = rtw_read32_mask(rtwdev, + REG_IQKB_END, + 0x07ff0000); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x1[%d] = %x ;; rx_y1[%d] = %x\n", + rx1_avg, rx_x1_temp[rx1_avg], + rx1_avg, rx_y1_temp[rx1_avg]); + + rx_x1_temp[rx1_avg] <<= 21; + rx_y1_temp[rx1_avg] <<= 21; + + rx1_avg++; + } else { + cal1_retry++; + if (cal1_retry == 10) + break; + } + } else { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "2. RXA_cal_retry = %d\n", cal0_retry); + + cal0_retry++; + cal1_retry++; + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "delay 20ms RX IQK Not Ready!!!!!\n"); + + if (cal0_retry == 10) + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "3. RXA_cal_retry = %d\n", + cal0_retry); + + if (rx0_avg >= 2) + rx0_finish = rtw88xxa_iqk_finish(rx0_avg, 4, + rx_x0_temp, rx_y0_temp, + &rx_x0, &rx_y0, + true, false); + + if (rx1_avg >= 2) + rx1_finish = rtw88xxa_iqk_finish(rx1_avg, 4, + rx_x1_temp, rx_y1_temp, + &rx_x1, &rx_y1, + true, false); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx0_average = %d, rx1_average = %d\n", + rx0_avg, rx1_avg); + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx0_finish = %d, rx1_finish = %d\n", + rx0_finish, rx1_finish); + + if ((rx0_finish || !tx0_finish) && (rx1_finish || !tx1_finish)) + break; + + if ((cal0_retry + rx0_avg) >= 10 || + (cal1_retry + rx1_avg) >= 10 || + rx0_avg == 3 || rx1_avg == 3) + break; + } + + rtw_dbg(rtwdev, RTW_DBG_RFK, "RXA_cal_retry = %d\n", cal0_retry); + rtw_dbg(rtwdev, RTW_DBG_RFK, "RXB_cal_retry = %d\n", cal1_retry); + + /* FillIQK Result */ + rtw_dbg(rtwdev, RTW_DBG_RFK, "========Path_A =======\n"); + + if (tx0_finish) + rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_A, tx_x0, tx_y0); + else + rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_A, 0x200, 0x0); + + if (rx0_finish) + rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_A, rx_x0, rx_y0); + else + rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_A, 0x200, 0x0); + + rtw_dbg(rtwdev, RTW_DBG_RFK, "========Path_B =======\n"); + + if (tx1_finish) + rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_B, tx_x1, tx_y1); + else + rtw8812a_iqk_tx_fill(rtwdev, RF_PATH_B, 0x200, 0x0); + + if (rx1_finish) + rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_B, rx_x1, rx_y1); + else + rtw8812a_iqk_rx_fill(rtwdev, RF_PATH_B, 0x200, 0x0); +} + +#define MACBB_REG_NUM_8812A 9 +#define AFE_REG_NUM_8812A 12 +#define RF_REG_NUM_8812A 3 + +static void rtw8812a_do_iqk(struct rtw_dev *rtwdev) +{ + static const u32 backup_macbb_reg[MACBB_REG_NUM_8812A] = { + 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0xe00, 0x838, 0x82c + }; + static const u32 backup_afe_reg[AFE_REG_NUM_8812A] = { + 0xc5c, 0xc60, 0xc64, 0xc68, 0xcb0, 0xcb4, + 0xe5c, 0xe60, 0xe64, 0xe68, 0xeb0, 0xeb4 + }; + static const u32 backup_rf_reg[RF_REG_NUM_8812A] = { + 0x65, 0x8f, 0x0 + }; + u32 macbb_backup[MACBB_REG_NUM_8812A] = {}; + u32 afe_backup[AFE_REG_NUM_8812A] = {}; + u32 rfa_backup[RF_REG_NUM_8812A] = {}; + u32 rfb_backup[RF_REG_NUM_8812A] = {}; + u32 reg_cb8, reg_eb8; + + rtw88xxa_iqk_backup_mac_bb(rtwdev, macbb_backup, + backup_macbb_reg, MACBB_REG_NUM_8812A); + + rtw_write32_set(rtwdev, REG_CCASEL, BIT(31)); + reg_cb8 = rtw_read32(rtwdev, REG_RFECTL_A); + reg_eb8 = rtw_read32(rtwdev, REG_RFECTL_B); + rtw_write32_clr(rtwdev, REG_CCASEL, BIT(31)); + + rtw88xxa_iqk_backup_afe(rtwdev, afe_backup, + backup_afe_reg, AFE_REG_NUM_8812A); + rtw8812a_iqk_backup_rf(rtwdev, rfa_backup, rfb_backup, + backup_rf_reg, RF_REG_NUM_8812A); + + rtw88xxa_iqk_configure_mac(rtwdev); + + rtw8812a_iqk(rtwdev); + + rtw8812a_iqk_restore_rf(rtwdev, RF_PATH_A, backup_rf_reg, + rfa_backup, RF_REG_NUM_8812A); + rtw8812a_iqk_restore_rf(rtwdev, RF_PATH_B, backup_rf_reg, + rfb_backup, RF_REG_NUM_8812A); + + rtw8812a_iqk_restore_afe(rtwdev, afe_backup, + backup_afe_reg, AFE_REG_NUM_8812A); + + rtw_write32_set(rtwdev, REG_CCASEL, BIT(31)); + rtw_write32(rtwdev, REG_RFECTL_A, reg_cb8); + rtw_write32(rtwdev, REG_RFECTL_B, reg_eb8); + rtw_write32_clr(rtwdev, REG_CCASEL, BIT(31)); + + rtw88xxa_iqk_restore_mac_bb(rtwdev, macbb_backup, + backup_macbb_reg, MACBB_REG_NUM_8812A); +} + +static void rtw8812a_phy_calibration(struct rtw_dev *rtwdev) +{ + u8 channel = rtwdev->hal.current_channel; + + rtw8812a_do_iqk(rtwdev); + + /* The official driver wants to do this after connecting + * but before first writing a new igi (phydm_get_new_igi). + * Here seems close enough. + */ + if (channel >= 36 && channel <= 64) + rtw_load_table(rtwdev, &rtw8812a_agc_diff_lb_tbl); + else if (channel >= 100) + rtw_load_table(rtwdev, &rtw8812a_agc_diff_hb_tbl); +} + +static void rtw8812a_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + if (!dm_info->pwr_trk_triggered) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, + GENMASK(17, 16), 0x03); + dm_info->pwr_trk_triggered = true; + return; + } + + rtw88xxa_phy_pwrtrack(rtwdev, rtw8812a_do_lck, rtw8812a_do_iqk); + dm_info->pwr_trk_triggered = false; +} + +static void rtw8812a_fill_txdesc_checksum(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + u8 *txdesc) +{ + fill_txdesc_checksum_common(txdesc, 16); +} + +static void rtw8812a_coex_cfg_init(struct rtw_dev *rtwdev) +{ +} + +static void rtw8812a_coex_cfg_gnt_fix(struct rtw_dev *rtwdev) +{ +} + +static void rtw8821a_coex_cfg_rfe_type(struct rtw_dev *rtwdev) +{ +} + +static void rtw8821a_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr) +{ +} + +static void rtw8821a_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) +{ +} + +static const struct rtw_chip_ops rtw8812a_ops = { + .power_on = rtw88xxa_power_on, + .power_off = rtw8812a_power_off, + .phy_set_param = NULL, + .read_efuse = rtw88xxa_read_efuse, + .query_phy_status = rtw8812a_query_phy_status, + .set_channel = rtw88xxa_set_channel, + .mac_init = NULL, + .read_rf = rtw88xxa_phy_read_rf, + .write_rf = rtw_phy_write_rf_reg_sipi, + .set_antenna = NULL, + .set_tx_power_index = rtw88xxa_set_tx_power_index, + .cfg_ldo25 = rtw8812a_cfg_ldo25, + .efuse_grant = rtw88xxa_efuse_grant, + .false_alarm_statistics = rtw88xxa_false_alarm_statistics, + .phy_calibration = rtw8812a_phy_calibration, + .cck_pd_set = rtw88xxa_phy_cck_pd_set, + .pwr_track = rtw8812a_pwr_track, + .config_bfee = NULL, + .set_gid_table = NULL, + .cfg_csi_rate = NULL, + .fill_txdesc_checksum = rtw8812a_fill_txdesc_checksum, + .coex_set_init = rtw8812a_coex_cfg_init, + .coex_set_ant_switch = NULL, + .coex_set_gnt_fix = rtw8812a_coex_cfg_gnt_fix, + .coex_set_gnt_debug = NULL, + .coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type, + .coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power, + .coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain, +}; + +static const struct rtw_page_table page_table_8812a[] = { + /* hq_num, nq_num, lq_num, exq_num, gapq_num */ + {0, 0, 0, 0, 0}, /* SDIO */ + {0, 0, 0, 0, 0}, /* PCI */ + {16, 0, 0, 0, 1}, /* 2 bulk out endpoints */ + {16, 0, 16, 0, 1}, /* 3 bulk out endpoints */ + {16, 0, 16, 0, 1}, /* 4 bulk out endpoints */ +}; + +static const struct rtw_rqpn rqpn_table_8812a[] = { + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH, + RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, +}; + +static const struct rtw_prioq_addrs prioq_addrs_8812a = { + .prio[RTW_DMA_MAPPING_EXTRA] = { + .rsvd = REG_RQPN_NPQ + 2, .avail = REG_RQPN_NPQ + 3, + }, + .prio[RTW_DMA_MAPPING_LOW] = { + .rsvd = REG_RQPN + 1, .avail = REG_FIFOPAGE_CTRL_2 + 1, + }, + .prio[RTW_DMA_MAPPING_NORMAL] = { + .rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1, + }, + .prio[RTW_DMA_MAPPING_HIGH] = { + .rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2, + }, + .wsize = false, +}; + +static const struct rtw_hw_reg rtw8812a_dig[] = { + [0] = { .addr = REG_RXIGI_A, .mask = 0x7f }, + [1] = { .addr = REG_RXIGI_B, .mask = 0x7f }, +}; + +static const struct rtw_rfe_def rtw8812a_rfe_defs[] = { + [0] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8812a_rtw_pwr_track_tbl, }, + [1] = { .phy_pg_tbl = &rtw8812a_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8812a_rtw_pwr_track_tbl, }, + [3] = { .phy_pg_tbl = &rtw8812a_bb_pg_rfe3_tbl, + .txpwr_lmt_tbl = &rtw8812a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8812a_rtw_pwr_track_rfe3_tbl, }, +}; + +static const u8 wl_rssi_step_8812a[] = {101, 45, 101, 40}; +static const u8 bt_rssi_step_8812a[] = {101, 101, 101, 101}; + +static const struct coex_rf_para rf_para_tx_8812a[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {8, 17, true, 4}, + {7, 18, true, 4}, + {6, 19, true, 4}, + {5, 20, true, 4} +}; + +static const struct coex_rf_para rf_para_rx_8812a[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {3, 24, true, 5}, + {2, 26, true, 5}, + {1, 27, true, 5}, + {0, 28, true, 5} +}; + +static_assert(ARRAY_SIZE(rf_para_tx_8812a) == ARRAY_SIZE(rf_para_rx_8812a)); + +const struct rtw_chip_info rtw8812a_hw_spec = { + .ops = &rtw8812a_ops, + .id = RTW_CHIP_TYPE_8812A, + .fw_name = "rtw88/rtw8812a_fw.bin", + .wlan_cpu = RTW_WCPU_11N, + .tx_pkt_desc_sz = 40, + .tx_buf_desc_sz = 16, + .rx_pkt_desc_sz = 24, + .rx_buf_desc_sz = 8, + .phy_efuse_size = 512, + .log_efuse_size = 512, + .ptct_efuse_size = 96 + 1, /* TODO or just 18? */ + .txff_size = 131072, + .rxff_size = 16128, + .rsvd_drv_pg_num = 9, + .txgi_factor = 1, + .is_pwr_by_rate_dec = true, + .max_power_index = 0x3f, + .csi_buf_pg_num = 0, + .band = RTW_BAND_2G | RTW_BAND_5G, + .page_size = 512, + .dig_min = 0x20, + .ht_supported = true, + .vht_supported = true, + .lps_deep_mode_supported = 0, + .sys_func_en = 0xFD, + .pwr_on_seq = card_enable_flow_8812a, + .pwr_off_seq = card_disable_flow_8812a, + .page_table = page_table_8812a, + .rqpn_table = rqpn_table_8812a, + .prioq_addrs = &prioq_addrs_8812a, + .intf_table = NULL, + .dig = rtw8812a_dig, + .rf_sipi_addr = {REG_LSSI_WRITE_A, REG_LSSI_WRITE_B}, + .ltecoex_addr = NULL, + .mac_tbl = &rtw8812a_mac_tbl, + .agc_tbl = &rtw8812a_agc_tbl, + .bb_tbl = &rtw8812a_bb_tbl, + .rf_tbl = {&rtw8812a_rf_a_tbl, &rtw8812a_rf_b_tbl}, + .rfe_defs = rtw8812a_rfe_defs, + .rfe_defs_size = ARRAY_SIZE(rtw8812a_rfe_defs), + .rx_ldpc = false, + .hw_feature_report = false, + .c2h_ra_report_size = 4, + .old_datarate_fb_limit = true, + .usb_tx_agg_desc_num = 1, + .iqk_threshold = 8, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, + + .coex_para_ver = 0, /* no coex code in 8812au driver */ + .bt_desired_ver = 0, + .scbd_support = false, + .new_scbd10_def = false, + .ble_hid_profile_support = false, + .wl_mimo_ps_support = false, + .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, + .bt_rssi_type = COEX_BTRSSI_RATIO, + .ant_isolation = 15, + .rssi_tolerance = 2, + .wl_rssi_step = wl_rssi_step_8812a, + .bt_rssi_step = bt_rssi_step_8812a, + .table_sant_num = 0, + .table_sant = NULL, + .table_nsant_num = 0, + .table_nsant = NULL, + .tdma_sant_num = 0, + .tdma_sant = NULL, + .tdma_nsant_num = 0, + .tdma_nsant = NULL, + .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8812a), + .wl_rf_para_tx = rf_para_tx_8812a, + .wl_rf_para_rx = rf_para_rx_8812a, + .bt_afh_span_bw20 = 0x20, + .bt_afh_span_bw40 = 0x30, + .afh_5g_num = 0, + .afh_5g = NULL, + .coex_info_hw_regs_num = 0, + .coex_info_hw_regs = NULL, +}; +EXPORT_SYMBOL(rtw8812a_hw_spec); + +MODULE_FIRMWARE("rtw88/rtw8812a_fw.bin"); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8812a driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.h b/drivers/net/wireless/realtek/rtw88/rtw8812a.h new file mode 100644 index 00000000000000..82dab59e341da3 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW8812A_H__ +#define __RTW8812A_H__ + +extern const struct rtw_chip_info rtw8812a_hw_spec; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c new file mode 100644 index 00000000000000..048efbbd49ed76 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.c @@ -0,0 +1,2812 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "main.h" +#include "phy.h" +#include "rtw8812a_table.h" + +static const u32 rtw8812a_mac[] = { + 0x010, 0x0000000C, + 0x80000200, 0x00000000, 0x40000000, 0x00000000, + 0x011, 0x00000066, + 0xA0000000, 0x00000000, + 0x011, 0x0000005A, + 0xB0000000, 0x00000000, + 0x025, 0x0000000F, + 0x072, 0x00000000, + 0x420, 0x00000080, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000002, + 0x435, 0x00000003, + 0x436, 0x00000005, + 0x437, 0x00000007, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43A, 0x00000000, + 0x43B, 0x00000001, + 0x43C, 0x00000002, + 0x43D, 0x00000003, + 0x43E, 0x00000005, + 0x43F, 0x00000007, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000010, + 0x445, 0x00000000, + 0x446, 0x00000000, + 0x447, 0x00000000, + 0x448, 0x00000000, + 0x449, 0x000000F0, + 0x44A, 0x0000000F, + 0x44B, 0x0000003E, + 0x44C, 0x00000010, + 0x44D, 0x00000000, + 0x44E, 0x00000000, + 0x44F, 0x00000000, + 0x450, 0x00000000, + 0x451, 0x000000F0, + 0x452, 0x0000000F, + 0x453, 0x00000000, + 0x45B, 0x00000080, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55C, 0x00000050, + 0x55D, 0x000000FF, + 0x604, 0x00000009, + 0x605, 0x00000030, + 0x607, 0x00000003, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x638, 0x00000050, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000080, + 0x642, 0x00000040, + 0x643, 0x00000000, + 0x652, 0x000000C8, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + 0x718, 0x00000040, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_mac, rtw_phy_cfg_mac); + +static const u32 rtw8812a_agc[] = { + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFC000001, + 0x81C, 0xFB020001, + 0x81C, 0xFA040001, + 0x81C, 0xF9060001, + 0x81C, 0xF8080001, + 0x81C, 0xF70A0001, + 0x81C, 0xF60C0001, + 0x81C, 0xF50E0001, + 0x81C, 0xF4100001, + 0x81C, 0xF3120001, + 0x81C, 0xF2140001, + 0x81C, 0xF1160001, + 0x81C, 0xF0180001, + 0x81C, 0xEF1A0001, + 0x81C, 0xEE1C0001, + 0x81C, 0xED1E0001, + 0x81C, 0xEC200001, + 0x81C, 0xEB220001, + 0x81C, 0xEA240001, + 0x81C, 0xCD260001, + 0x81C, 0xCC280001, + 0x81C, 0xCB2A0001, + 0x81C, 0xCA2C0001, + 0x81C, 0xC92E0001, + 0x81C, 0xC8300001, + 0x81C, 0xA6320001, + 0x81C, 0xA5340001, + 0x81C, 0xA4360001, + 0x81C, 0xA3380001, + 0x81C, 0xA23A0001, + 0x81C, 0x883C0001, + 0x81C, 0x873E0001, + 0x81C, 0x86400001, + 0x81C, 0x85420001, + 0x81C, 0x84440001, + 0x81C, 0x83460001, + 0x81C, 0x82480001, + 0x81C, 0x814A0001, + 0x81C, 0x484C0001, + 0x81C, 0x474E0001, + 0x81C, 0x46500001, + 0x81C, 0x45520001, + 0x81C, 0x44540001, + 0x81C, 0x43560001, + 0x81C, 0x42580001, + 0x81C, 0x415A0001, + 0x81C, 0x255C0001, + 0x81C, 0x245E0001, + 0x81C, 0x23600001, + 0x81C, 0x22620001, + 0x81C, 0x21640001, + 0x81C, 0x21660001, + 0x81C, 0x21680001, + 0x81C, 0x216A0001, + 0x81C, 0x216C0001, + 0x81C, 0x216E0001, + 0x81C, 0x21700001, + 0x81C, 0x21720001, + 0x81C, 0x21740001, + 0x81C, 0x21760001, + 0x81C, 0x21780001, + 0x81C, 0x217A0001, + 0x81C, 0x217C0001, + 0x81C, 0x217E0001, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x81C, 0xF9000001, + 0x81C, 0xF8020001, + 0x81C, 0xF7040001, + 0x81C, 0xF6060001, + 0x81C, 0xF5080001, + 0x81C, 0xF40A0001, + 0x81C, 0xF30C0001, + 0x81C, 0xF20E0001, + 0x81C, 0xF1100001, + 0x81C, 0xF0120001, + 0x81C, 0xEF140001, + 0x81C, 0xEE160001, + 0x81C, 0xED180001, + 0x81C, 0xEC1A0001, + 0x81C, 0xEB1C0001, + 0x81C, 0xEA1E0001, + 0x81C, 0xCD200001, + 0x81C, 0xCC220001, + 0x81C, 0xCB240001, + 0x81C, 0xCA260001, + 0x81C, 0xC9280001, + 0x81C, 0xC82A0001, + 0x81C, 0xC72C0001, + 0x81C, 0xC62E0001, + 0x81C, 0xA5300001, + 0x81C, 0xA4320001, + 0x81C, 0xA3340001, + 0x81C, 0xA2360001, + 0x81C, 0x88380001, + 0x81C, 0x873A0001, + 0x81C, 0x863C0001, + 0x81C, 0x853E0001, + 0x81C, 0x84400001, + 0x81C, 0x83420001, + 0x81C, 0x82440001, + 0x81C, 0x81460001, + 0x81C, 0x48480001, + 0x81C, 0x474A0001, + 0x81C, 0x464C0001, + 0x81C, 0x454E0001, + 0x81C, 0x44500001, + 0x81C, 0x43520001, + 0x81C, 0x42540001, + 0x81C, 0x41560001, + 0x81C, 0x25580001, + 0x81C, 0x245A0001, + 0x81C, 0x235C0001, + 0x81C, 0x225E0001, + 0x81C, 0x21600001, + 0x81C, 0x21620001, + 0x81C, 0x21640001, + 0x81C, 0x21660001, + 0x81C, 0x21680001, + 0x81C, 0x216A0001, + 0x81C, 0x236C0001, + 0x81C, 0x226E0001, + 0x81C, 0x21700001, + 0x81C, 0x21720001, + 0x81C, 0x21740001, + 0x81C, 0x21760001, + 0x81C, 0x21780001, + 0x81C, 0x217A0001, + 0x81C, 0x217C0001, + 0x81C, 0x217E0001, + 0xA0000000, 0x00000000, + 0x81C, 0xFF000001, + 0x81C, 0xFF020001, + 0x81C, 0xFF040001, + 0x81C, 0xFF060001, + 0x81C, 0xFF080001, + 0x81C, 0xFE0A0001, + 0x81C, 0xFD0C0001, + 0x81C, 0xFC0E0001, + 0x81C, 0xFB100001, + 0x81C, 0xFA120001, + 0x81C, 0xF9140001, + 0x81C, 0xF8160001, + 0x81C, 0xF7180001, + 0x81C, 0xF61A0001, + 0x81C, 0xF51C0001, + 0x81C, 0xF41E0001, + 0x81C, 0xF3200001, + 0x81C, 0xF2220001, + 0x81C, 0xF1240001, + 0x81C, 0xF0260001, + 0x81C, 0xEF280001, + 0x81C, 0xEE2A0001, + 0x81C, 0xED2C0001, + 0x81C, 0xEC2E0001, + 0x81C, 0xEB300001, + 0x81C, 0xEA320001, + 0x81C, 0xE9340001, + 0x81C, 0xE8360001, + 0x81C, 0xE7380001, + 0x81C, 0xE63A0001, + 0x81C, 0xE53C0001, + 0x81C, 0xC73E0001, + 0x81C, 0xC6400001, + 0x81C, 0xC5420001, + 0x81C, 0xC4440001, + 0x81C, 0xC3460001, + 0x81C, 0xC2480001, + 0x81C, 0xC14A0001, + 0x81C, 0xA74C0001, + 0x81C, 0xA64E0001, + 0x81C, 0xA5500001, + 0x81C, 0xA4520001, + 0x81C, 0xA3540001, + 0x81C, 0xA2560001, + 0x81C, 0xA1580001, + 0x81C, 0x675A0001, + 0x81C, 0x665C0001, + 0x81C, 0x655E0001, + 0x81C, 0x64600001, + 0x81C, 0x63620001, + 0x81C, 0x48640001, + 0x81C, 0x47660001, + 0x81C, 0x46680001, + 0x81C, 0x456A0001, + 0x81C, 0x446C0001, + 0x81C, 0x436E0001, + 0x81C, 0x42700001, + 0x81C, 0x41720001, + 0x81C, 0x41740001, + 0x81C, 0x41760001, + 0x81C, 0x41780001, + 0x81C, 0x417A0001, + 0x81C, 0x417C0001, + 0x81C, 0x417E0001, + 0xB0000000, 0x00000000, + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFC800001, + 0x81C, 0xFB820001, + 0x81C, 0xFA840001, + 0x81C, 0xF9860001, + 0x81C, 0xF8880001, + 0x81C, 0xF78A0001, + 0x81C, 0xF68C0001, + 0x81C, 0xF58E0001, + 0x81C, 0xF4900001, + 0x81C, 0xF3920001, + 0x81C, 0xF2940001, + 0x81C, 0xF1960001, + 0x81C, 0xF0980001, + 0x81C, 0xEF9A0001, + 0x81C, 0xEE9C0001, + 0x81C, 0xED9E0001, + 0x81C, 0xECA00001, + 0x81C, 0xEBA20001, + 0x81C, 0xEAA40001, + 0x81C, 0xE9A60001, + 0x81C, 0xE8A80001, + 0x81C, 0xE7AA0001, + 0x81C, 0xE6AC0001, + 0x81C, 0xE5AE0001, + 0x81C, 0xE4B00001, + 0x81C, 0xE3B20001, + 0x81C, 0xA8B40001, + 0x81C, 0xA7B60001, + 0x81C, 0xA6B80001, + 0x81C, 0xA5BA0001, + 0x81C, 0xA4BC0001, + 0x81C, 0xA3BE0001, + 0x81C, 0xA2C00001, + 0x81C, 0xA1C20001, + 0x81C, 0x68C40001, + 0x81C, 0x67C60001, + 0x81C, 0x66C80001, + 0x81C, 0x65CA0001, + 0x81C, 0x64CC0001, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0x81C, 0x01E80001, + 0x81C, 0x01EA0001, + 0x81C, 0x01EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xA0000000, 0x00000000, + 0x81C, 0xFF800001, + 0x81C, 0xFF820001, + 0x81C, 0xFF840001, + 0x81C, 0xFE860001, + 0x81C, 0xFD880001, + 0x81C, 0xFC8A0001, + 0x81C, 0xFB8C0001, + 0x81C, 0xFA8E0001, + 0x81C, 0xF9900001, + 0x81C, 0xF8920001, + 0x81C, 0xF7940001, + 0x81C, 0xF6960001, + 0x81C, 0xF5980001, + 0x81C, 0xF49A0001, + 0x81C, 0xF39C0001, + 0x81C, 0xF29E0001, + 0x81C, 0xF1A00001, + 0x81C, 0xF0A20001, + 0x81C, 0xEFA40001, + 0x81C, 0xEEA60001, + 0x81C, 0xEDA80001, + 0x81C, 0xECAA0001, + 0x81C, 0xEBAC0001, + 0x81C, 0xEAAE0001, + 0x81C, 0xE9B00001, + 0x81C, 0xE8B20001, + 0x81C, 0xE7B40001, + 0x81C, 0xE6B60001, + 0x81C, 0xE5B80001, + 0x81C, 0xE4BA0001, + 0x81C, 0xE3BC0001, + 0x81C, 0xA8BE0001, + 0x81C, 0xA7C00001, + 0x81C, 0xA6C20001, + 0x81C, 0xA5C40001, + 0x81C, 0xA4C60001, + 0x81C, 0xA3C80001, + 0x81C, 0xA2CA0001, + 0x81C, 0xA1CC0001, + 0x81C, 0x68CE0001, + 0x81C, 0x67D00001, + 0x81C, 0x66D20001, + 0x81C, 0x65D40001, + 0x81C, 0x64D60001, + 0x81C, 0x47D80001, + 0x81C, 0x46DA0001, + 0x81C, 0x45DC0001, + 0x81C, 0x44DE0001, + 0x81C, 0x43E00001, + 0x81C, 0x42E20001, + 0x81C, 0x08E40001, + 0x81C, 0x07E60001, + 0x81C, 0x06E80001, + 0x81C, 0x05EA0001, + 0x81C, 0x04EC0001, + 0x81C, 0x03EE0001, + 0x81C, 0x02F00001, + 0x81C, 0x01F20001, + 0x81C, 0x01F40001, + 0x81C, 0x01F60001, + 0x81C, 0x01F80001, + 0x81C, 0x01FA0001, + 0x81C, 0x01FC0001, + 0x81C, 0x01FE0001, + 0xB0000000, 0x00000000, + 0xC50, 0x00000022, + 0xC50, 0x00000020, + 0xE50, 0x00000022, + 0xE50, 0x00000020, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_agc, rtw_phy_cfg_agc); + +static const u32 rtw8812a_agc_diff_lb[] = { + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0x47CE0001, + 0x81C, 0x46D00001, + 0x81C, 0x45D20001, + 0x81C, 0x44D40001, + 0x81C, 0x43D60001, + 0x81C, 0x42D80001, + 0x81C, 0x08DA0001, + 0x81C, 0x07DC0001, + 0x81C, 0x06DE0001, + 0x81C, 0x05E00001, + 0x81C, 0x04E20001, + 0x81C, 0x03E40001, + 0x81C, 0x02E60001, + 0xA0000000, 0x00000000, + 0x81C, 0x47D80001, + 0x81C, 0x46DA0001, + 0x81C, 0x45DC0001, + 0x81C, 0x44DE0001, + 0x81C, 0x43E00001, + 0x81C, 0x42E20001, + 0x81C, 0x08E40001, + 0x81C, 0x07E60001, + 0x81C, 0x06E80001, + 0x81C, 0x05EA0001, + 0x81C, 0x04EC0001, + 0x81C, 0x03EE0001, + 0x81C, 0x02F00001, + 0xB0000000, 0x00000000, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_agc_diff_lb, rtw_phy_cfg_agc); + +static const u32 rtw8812a_agc_diff_hb[] = { + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0x45CE0001, + 0x81C, 0x44D00001, + 0x81C, 0x43D20001, + 0x81C, 0x42D40001, + 0x81C, 0x08D60001, + 0x81C, 0x07D80001, + 0x81C, 0x06DA0001, + 0x81C, 0x05DC0001, + 0x81C, 0x04DE0001, + 0x81C, 0x03E00001, + 0x81C, 0x02E20001, + 0x81C, 0x01E40001, + 0x81C, 0x01E60001, + 0xA0000000, 0x00000000, + 0x81C, 0x45D80001, + 0x81C, 0x44DA0001, + 0x81C, 0x43DC0001, + 0x81C, 0x42DE0001, + 0x81C, 0x08E00001, + 0x81C, 0x07E20001, + 0x81C, 0x06E40001, + 0x81C, 0x05E60001, + 0x81C, 0x04E80001, + 0x81C, 0x03EA0001, + 0x81C, 0x02EC0001, + 0x81C, 0x01EE0001, + 0x81C, 0x01F00001, + 0xB0000000, 0x00000000, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_agc_diff_hb, rtw_phy_cfg_agc); + +static const u32 rtw8812a_bb[] = { + 0x800, 0x8020D010, + 0x804, 0x080112E0, + 0x808, 0x0E028233, + 0x80C, 0x12131113, + 0x810, 0x20101263, + 0x814, 0x020C3D10, + 0x818, 0x03A00385, + 0x820, 0x00000000, + 0x824, 0x00030FE0, + 0x828, 0x00000000, + 0x82C, 0x002083DD, + 0x830, 0x2EAAEEB8, + 0x834, 0x0037A706, + 0x838, 0x06C89B44, + 0x83C, 0x0000095B, + 0x840, 0xC0000001, + 0x844, 0x40003CDE, + 0x848, 0x6210FF8B, + 0x84C, 0x6CFDFFB8, + 0x850, 0x28874706, + 0x854, 0x0001520C, + 0x858, 0x8060E000, + 0x85C, 0x74210168, + 0x860, 0x6929C321, + 0x864, 0x79727432, + 0x868, 0x8CA7A314, + 0x86C, 0x338C2878, + 0x870, 0x03333333, + 0x874, 0x31602C2E, + 0x878, 0x00003152, + 0x87C, 0x000FC000, + 0x8A0, 0x00000013, + 0x8A4, 0x7F7F7F7F, + 0x8A8, 0xA202033E, + 0x8AC, 0x0FF0FA0A, + 0x8B0, 0x00000600, + 0x8B4, 0x000FC080, + 0x8B8, 0x6C10D7FF, + 0x8BC, 0x4CA520A3, + 0x8C0, 0x27F00020, + 0x8C4, 0x00000000, + 0x8C8, 0x00012D69, + 0x8CC, 0x08248492, + 0x8D0, 0x0000B800, + 0x8DC, 0x00000000, + 0x8D4, 0x940008A0, + 0x8D8, 0x290B5612, + 0x8F8, 0x400002C0, + 0x8FC, 0x00000000, + 0x900, 0x00000701, + 0x90C, 0x00000000, + 0x910, 0x0000FC00, + 0x914, 0x00000404, + 0x918, 0x1C1028C0, + 0x91C, 0x64B11A1C, + 0x920, 0xE0767233, + 0x924, 0x055AA500, + 0x928, 0x00000004, + 0x92C, 0xFFFE0000, + 0x930, 0xFFFFFFFE, + 0x934, 0x001FFFFF, + 0x960, 0x00000000, + 0x964, 0x00000000, + 0x968, 0x00000000, + 0x96C, 0x00000000, + 0x970, 0x801FFFFF, + 0x978, 0x00000000, + 0x97C, 0x00000000, + 0x980, 0x00000000, + 0x984, 0x00000000, + 0x988, 0x00000000, + 0x990, 0x27100000, + 0x994, 0xFFFF0100, + 0x998, 0xFFFFFF5C, + 0x99C, 0xFFFFFFFF, + 0x9A0, 0x000000FF, + 0x9A4, 0x00080080, + 0x9A8, 0x00000000, + 0x9AC, 0x00000000, + 0x9B0, 0x81081008, + 0x9B4, 0x00000000, + 0x9B8, 0x01081008, + 0x9BC, 0x01081008, + 0x9D0, 0x00000000, + 0x9D4, 0x00000000, + 0x9D8, 0x00000000, + 0x9DC, 0x00000000, + 0x9E4, 0x00000003, + 0x9E8, 0x000002D5, + 0xA00, 0x00D047C8, + 0xA04, 0x01FF000C, + 0xA08, 0x8C838300, + 0xA0C, 0x2E7F000F, + 0xA10, 0x9500BB78, + 0xA14, 0x11144028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1217, + 0xA28, 0x00000305, + 0xA2C, 0x00900000, + 0xA70, 0x101FFF00, + 0xA74, 0x00000008, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x218075B2, + 0xA84, 0x001F8C80, + 0xB00, 0x03100000, + 0xB04, 0x0000B000, + 0xB08, 0xAE0201EB, + 0xB0C, 0x01003207, + 0xB10, 0x00009807, + 0xB14, 0x01000000, + 0xB18, 0x00000002, + 0xB1C, 0x00000002, + 0xB20, 0x0000001F, + 0xB24, 0x03020100, + 0xB28, 0x07060504, + 0xB2C, 0x0B0A0908, + 0xB30, 0x0F0E0D0C, + 0xB34, 0x13121110, + 0xB38, 0x17161514, + 0xB3C, 0x0000003A, + 0xB40, 0x00000000, + 0xB44, 0x00000000, + 0xB48, 0x13000032, + 0xB4C, 0x48080000, + 0xB50, 0x00000000, + 0xB54, 0x00000000, + 0xB58, 0x00000000, + 0xB5C, 0x00000000, + 0xC00, 0x00000007, + 0xC04, 0x00042020, + 0xC08, 0x80410231, + 0xC0C, 0x00000000, + 0xC10, 0x00000100, + 0xC14, 0x01000000, + 0xC1C, 0x40000003, + 0xC20, 0x12121212, + 0xC24, 0x12121212, + 0xC28, 0x12121212, + 0xC2C, 0x12121212, + 0xC30, 0x12121212, + 0xC34, 0x12121212, + 0xC38, 0x12121212, + 0xC3C, 0x12121212, + 0xC40, 0x12121212, + 0xC44, 0x12121212, + 0xC48, 0x12121212, + 0xC4C, 0x12121212, + 0xC50, 0x00000020, + 0xC54, 0x0008121C, + 0xC58, 0x30000C1C, + 0xC5C, 0x00000058, + 0xC60, 0x34344443, + 0xC64, 0x07003333, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000002, 0x00000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000004, 0x00000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000001, 0x00000000, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0xC68, 0x59791979, + 0xA0000000, 0x00000000, + 0xC68, 0x59799979, + 0xB0000000, 0x00000000, + 0xC6C, 0x59795979, + 0xC70, 0x19795979, + 0xC74, 0x19795979, + 0xC78, 0x19791979, + 0xC7C, 0x19791979, + 0xC80, 0x19791979, + 0xC84, 0x19791979, + 0xC94, 0x0100005C, + 0xC98, 0x00000000, + 0xC9C, 0x00000000, + 0xCA0, 0x00000029, + 0xCA4, 0x08040201, + 0xCA8, 0x80402010, + 0xCB0, 0x77547777, + 0xCB4, 0x00000077, + 0xCB8, 0x00508242, + 0xE00, 0x00000007, + 0xE04, 0x00042020, + 0xE08, 0x80410231, + 0xE0C, 0x00000000, + 0xE10, 0x00000100, + 0xE14, 0x01000000, + 0xE1C, 0x40000003, + 0xE20, 0x12121212, + 0xE24, 0x12121212, + 0xE28, 0x12121212, + 0xE2C, 0x12121212, + 0xE30, 0x12121212, + 0xE34, 0x12121212, + 0xE38, 0x12121212, + 0xE3C, 0x12121212, + 0xE40, 0x12121212, + 0xE44, 0x12121212, + 0xE48, 0x12121212, + 0xE4C, 0x12121212, + 0xE50, 0x00000020, + 0xE54, 0x0008121C, + 0xE58, 0x30000C1C, + 0xE5C, 0x00000058, + 0xE60, 0x34344443, + 0xE64, 0x07003333, + 0xE68, 0x59791979, + 0xE6C, 0x59795979, + 0xE70, 0x19795979, + 0xE74, 0x19795979, + 0xE78, 0x19791979, + 0xE7C, 0x19791979, + 0xE80, 0x19791979, + 0xE84, 0x19791979, + 0xE94, 0x0100005C, + 0xE98, 0x00000000, + 0xE9C, 0x00000000, + 0xEA0, 0x00000029, + 0xEA4, 0x08040201, + 0xEA8, 0x80402010, + 0xEB0, 0x77547777, + 0xEB4, 0x00000077, + 0xEB8, 0x00508242, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8812a_bb, rtw_phy_cfg_bb); + +static const struct rtw_phy_pg_cfg_pair rtw8812a_bb_pg[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x42424444, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x30323638, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x28303236, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x38404242, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283034, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x28303236, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x42422426, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30343840, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x42424444, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x30323638, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x28303236, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x38404242, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283034, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x28303236, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x42422426, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30343840, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x42424444, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x30323640, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x40424444, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x28303236, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x38404242, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x26283034, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x40424444, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x28303236, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x42422426, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x30343840, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x42424444, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x30323640, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x40424444, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x28303236, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x38404242, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x26283034, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x40424444, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x28303236, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x42422426, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x30343840, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, +}; + +RTW_DECL_TABLE_BB_PG(rtw8812a_bb_pg); + +static const struct rtw_phy_pg_cfg_pair rtw8812a_bb_pg_rfe3[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x34343434, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x32323232, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303232, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x32323232, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x28303232, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x32323232, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x32323232, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x28303232, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x32322426, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x32323232, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x24262830, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x34343434, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x32323232, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303232, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x32323232, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x28303232, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x32323232, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x32323232, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x28303232, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x32322426, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x32323232, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x32323232, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x28303232, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32323232, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x32323232, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32323232, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x32322222, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303232, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x22222426, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x32323232, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x28303232, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32323232, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x32323232, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32323232, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x32322222, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303232, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x22222426, }, +}; + +RTW_DECL_TABLE_BB_PG(rtw8812a_bb_pg_rfe3); + +static const u32 rtw8812a_rf_a[] = { + 0x000, 0x00010000, + 0x018, 0x0001712A, + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x01E, 0x00080000, + 0x089, 0x00000080, + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x086, 0x00014B3A, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x086, 0x00014B3A, + 0xA0000000, 0x00000000, + 0x086, 0x00014B38, + 0xB0000000, 0x00000000, + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x08B, 0x00080180, + 0xA0000000, 0x00000000, + 0x08B, 0x00087180, + 0xB0000000, 0x00000000, + 0x0B1, 0x0001FC1A, + 0x0B3, 0x000F0810, + 0x0B4, 0x0001A78D, + 0x0BA, 0x00086180, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0xA0000000, 0x00000000, + 0x03B, 0x00038A58, + 0x03B, 0x00037A58, + 0x03B, 0x0002A590, + 0x03B, 0x00027A50, + 0x03B, 0x00018248, + 0x03B, 0x00010240, + 0x03B, 0x00008240, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000100, + 0x80000002, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A4EE, + 0x034, 0x00009076, + 0x034, 0x00008073, + 0x034, 0x00007070, + 0x034, 0x0000606D, + 0x034, 0x0000506A, + 0x034, 0x00004049, + 0x034, 0x00003046, + 0x034, 0x00002028, + 0x034, 0x00001025, + 0x034, 0x00000022, + 0xA0000000, 0x00000000, + 0x034, 0x0000ADF4, + 0x034, 0x00009DF1, + 0x034, 0x00008DEE, + 0x034, 0x00007DEB, + 0x034, 0x00006DE8, + 0x034, 0x00005DE5, + 0x034, 0x00004DE2, + 0x034, 0x00003CE6, + 0x034, 0x000024E7, + 0x034, 0x000014E4, + 0x034, 0x000004E1, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000192, + 0x035, 0x00008192, + 0x035, 0x00010192, + 0x036, 0x00000024, + 0x036, 0x00008024, + 0x036, 0x00010024, + 0x036, 0x00018024, + 0x0EF, 0x00000000, + 0x051, 0x00000C21, + 0x052, 0x000006D9, + 0x053, 0x000FC649, + 0x054, 0x0000017E, + 0x0EF, 0x00000002, + 0x008, 0x00008400, + 0x018, 0x0001712A, + 0x0EF, 0x00001000, + 0x03A, 0x00000080, + 0x03B, 0x0003A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0003202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0002B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00023070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0001B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00012085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0000A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00002080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x0007A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0007202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0006B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00063070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0005B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00052085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0004A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00042080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x000BA02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x000B202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x000AB064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x000A3070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0009B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00092085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0008A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00082080, + 0x03C, 0x00010000, + 0x0EF, 0x00001100, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x0004604D, + 0x034, 0x0004504A, + 0x034, 0x00044047, + 0x034, 0x00043044, + 0x034, 0x00042007, + 0x034, 0x00041004, + 0x034, 0x00040001, + 0xA0000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045DE6, + 0x034, 0x00044DE3, + 0x034, 0x000438C8, + 0x034, 0x000428C5, + 0x034, 0x000418C2, + 0x034, 0x000408C0, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0B4, + 0x034, 0x000290B1, + 0x034, 0x00028072, + 0x034, 0x0002706F, + 0x034, 0x0002604F, + 0x034, 0x0002504C, + 0x034, 0x00024049, + 0x034, 0x00023046, + 0x034, 0x00022009, + 0x034, 0x00021006, + 0x034, 0x00020003, + 0xA0000000, 0x00000000, + 0x034, 0x0002ADF5, + 0x034, 0x00029DF2, + 0x034, 0x00028DEF, + 0x034, 0x00027DEC, + 0x034, 0x00026DE9, + 0x034, 0x00025DE6, + 0x034, 0x00024DE3, + 0x034, 0x000238C8, + 0x034, 0x000228C5, + 0x034, 0x000218C2, + 0x034, 0x000208C0, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x0000604D, + 0x034, 0x0000504A, + 0x034, 0x00004047, + 0x034, 0x00003044, + 0x034, 0x00002007, + 0x034, 0x00001004, + 0x034, 0x00000001, + 0xA0000000, 0x00000000, + 0x034, 0x0000AFF7, + 0x034, 0x00009DF7, + 0x034, 0x00008DF4, + 0x034, 0x00007DF1, + 0x034, 0x00006DEE, + 0x034, 0x00005DEB, + 0x034, 0x00004DE8, + 0x034, 0x000038CC, + 0x034, 0x000028C9, + 0x034, 0x000018C6, + 0x034, 0x000008C3, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001D4, + 0x035, 0x000081D4, + 0x035, 0x000101D4, + 0x035, 0x000201B4, + 0x035, 0x000281B4, + 0x035, 0x000301B4, + 0x035, 0x000401B4, + 0x035, 0x000481B4, + 0x035, 0x000501B4, + 0xA0000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x00000188, + 0x035, 0x00008147, + 0x035, 0x00010147, + 0x035, 0x000201D7, + 0x035, 0x000281D7, + 0x035, 0x000301D7, + 0x035, 0x000401D8, + 0x035, 0x000481D8, + 0x035, 0x000501D8, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00004BFB, + 0x036, 0x0000CBFB, + 0x036, 0x00014BFB, + 0x036, 0x0001CBFB, + 0x036, 0x00024F4B, + 0x036, 0x0002CF4B, + 0x036, 0x00034F4B, + 0x036, 0x0003CF4B, + 0x036, 0x00044F4B, + 0x036, 0x0004CF4B, + 0x036, 0x00054F4B, + 0x036, 0x0005CF4B, + 0xA0000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00084EB4, + 0x036, 0x0008CC35, + 0x036, 0x00094C35, + 0x036, 0x0009CC35, + 0x036, 0x000A4C35, + 0x036, 0x000ACC35, + 0x036, 0x000B4C35, + 0x036, 0x000BCC35, + 0x036, 0x000C4C34, + 0x036, 0x000CCC35, + 0x036, 0x000D4C35, + 0x036, 0x000DCC35, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x03C, 0x000002CC, + 0x03C, 0x00000522, + 0x03C, 0x00000902, + 0xA0000000, 0x00000000, + 0x03C, 0x000002A8, + 0x03C, 0x000005A2, + 0x03C, 0x00000880, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0x0DF, 0x00000080, + 0x01F, 0x00000064, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D1, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x061, 0x000FDD43, + 0x062, 0x00038F4B, + 0x063, 0x00032117, + 0x064, 0x000194AC, + 0x065, 0x000931D2, + 0xA0000000, 0x00000000, + 0x061, 0x000E5D53, + 0x062, 0x00038FCD, + 0x063, 0x000114EB, + 0x064, 0x000196AC, + 0x065, 0x000911D7, + 0xB0000000, 0x00000000, + 0x008, 0x00008400, + 0x01C, 0x000739D2, + 0x0B4, 0x0001E78D, + 0x018, 0x0001F12A, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x0B4, 0x0001A78D, + 0x018, 0x0001712A, +}; + +RTW_DECL_TABLE_RF_RADIO(rtw8812a_rf_a, A); + +static const u32 rtw8812a_rf_b[] = { + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x089, 0x00000080, + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x086, 0x00014B3A, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x086, 0x00014B3A, + 0xA0000000, 0x00000000, + 0x086, 0x00014B38, + 0xB0000000, 0x00000000, + 0x80000004, 0x00000000, 0x40000000, 0x00000000, + 0x08B, 0x00080180, + 0xA0000000, 0x00000000, + 0x08B, 0x00087180, + 0xB0000000, 0x00000000, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0x80000001, 0x00000000, 0x40000000, 0x00000000, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0x90000001, 0x00000005, 0x40000000, 0x00000000, + 0x03B, 0x0003F218, + 0x03B, 0x00030A58, + 0x03B, 0x0002FA58, + 0x03B, 0x00022590, + 0x03B, 0x0001FA50, + 0x03B, 0x00010248, + 0x03B, 0x00008240, + 0xA0000000, 0x00000000, + 0x03B, 0x00038A58, + 0x03B, 0x00037A58, + 0x03B, 0x0002A590, + 0x03B, 0x00027A50, + 0x03B, 0x00018248, + 0x03B, 0x00010240, + 0x03B, 0x00008240, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000100, + 0x80000002, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A4EE, + 0x034, 0x00009076, + 0x034, 0x00008073, + 0x034, 0x00007070, + 0x034, 0x0000606D, + 0x034, 0x0000506A, + 0x034, 0x00004049, + 0x034, 0x00003046, + 0x034, 0x00002028, + 0x034, 0x00001025, + 0x034, 0x00000022, + 0xA0000000, 0x00000000, + 0x034, 0x0000ADF4, + 0x034, 0x00009DF1, + 0x034, 0x00008DEE, + 0x034, 0x00007DEB, + 0x034, 0x00006DE8, + 0x034, 0x00005DE5, + 0x034, 0x00004DE2, + 0x034, 0x00003CE6, + 0x034, 0x000024E7, + 0x034, 0x000014E4, + 0x034, 0x000004E1, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000192, + 0x035, 0x00008192, + 0x035, 0x00010192, + 0x036, 0x00000024, + 0x036, 0x00008024, + 0x036, 0x00010024, + 0x036, 0x00018024, + 0x0EF, 0x00000000, + 0x051, 0x00000C21, + 0x052, 0x000006D9, + 0x053, 0x000FC649, + 0x054, 0x0000017E, + 0x0EF, 0x00000002, + 0x008, 0x00008400, + 0x018, 0x0001712A, + 0x0EF, 0x00001000, + 0x03A, 0x00000080, + 0x03B, 0x0003A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0003202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0002B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00023070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0001B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00012085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0000A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00002080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x0007A02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x0007202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x0006B064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x00063070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0005B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00052085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0004A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00042080, + 0x03C, 0x00010000, + 0x03A, 0x00000080, + 0x03B, 0x000BA02C, + 0x03C, 0x00004000, + 0x03A, 0x00000400, + 0x03B, 0x000B202C, + 0x03C, 0x00010000, + 0x03A, 0x000000A0, + 0x03B, 0x000AB064, + 0x03C, 0x00004000, + 0x03A, 0x000000D8, + 0x03B, 0x000A3070, + 0x03C, 0x00004000, + 0x03A, 0x00000468, + 0x03B, 0x0009B870, + 0x03C, 0x00010000, + 0x03A, 0x00000098, + 0x03B, 0x00092085, + 0x03C, 0x000E4000, + 0x03A, 0x00000418, + 0x03B, 0x0008A080, + 0x03C, 0x000F0000, + 0x03A, 0x00000418, + 0x03B, 0x00082080, + 0x03C, 0x00010000, + 0x0EF, 0x00001100, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0B2, + 0x034, 0x000490AF, + 0x034, 0x00048070, + 0x034, 0x0004706D, + 0x034, 0x00046050, + 0x034, 0x0004504D, + 0x034, 0x0004404A, + 0x034, 0x00043047, + 0x034, 0x0004200A, + 0x034, 0x00041007, + 0x034, 0x00040004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0B1, + 0x034, 0x000490AE, + 0x034, 0x0004806F, + 0x034, 0x0004706C, + 0x034, 0x0004604C, + 0x034, 0x00045049, + 0x034, 0x00044046, + 0x034, 0x00043043, + 0x034, 0x00042006, + 0x034, 0x00041003, + 0x034, 0x00040000, + 0xA0000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045DE6, + 0x034, 0x00044DE3, + 0x034, 0x000438C8, + 0x034, 0x000428C5, + 0x034, 0x000418C2, + 0x034, 0x000408C0, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0B2, + 0x034, 0x000290AF, + 0x034, 0x00028070, + 0x034, 0x0002706D, + 0x034, 0x00026050, + 0x034, 0x0002504D, + 0x034, 0x0002404A, + 0x034, 0x00023047, + 0x034, 0x0002200A, + 0x034, 0x00021007, + 0x034, 0x00020004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0B3, + 0x034, 0x000290B0, + 0x034, 0x00028071, + 0x034, 0x0002706E, + 0x034, 0x0002604E, + 0x034, 0x0002504B, + 0x034, 0x00024048, + 0x034, 0x00023045, + 0x034, 0x00022008, + 0x034, 0x00021005, + 0x034, 0x00020002, + 0xA0000000, 0x00000000, + 0x034, 0x0002ADF5, + 0x034, 0x00029DF2, + 0x034, 0x00028DEF, + 0x034, 0x00027DEC, + 0x034, 0x00026DE9, + 0x034, 0x00025DE6, + 0x034, 0x00024DE3, + 0x034, 0x000238C8, + 0x034, 0x000228C5, + 0x034, 0x000218C2, + 0x034, 0x000208C0, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0B2, + 0x034, 0x000090AF, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x00006050, + 0x034, 0x0000504D, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x0000200A, + 0x034, 0x00001007, + 0x034, 0x00000004, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0B3, + 0x034, 0x000090B0, + 0x034, 0x00008070, + 0x034, 0x0000706D, + 0x034, 0x0000604D, + 0x034, 0x0000504A, + 0x034, 0x00004047, + 0x034, 0x00003044, + 0x034, 0x00002007, + 0x034, 0x00001004, + 0x034, 0x00000001, + 0xA0000000, 0x00000000, + 0x034, 0x0000AFF7, + 0x034, 0x00009DF7, + 0x034, 0x00008DF4, + 0x034, 0x00007DF1, + 0x034, 0x00006DEE, + 0x034, 0x00005DEB, + 0x034, 0x00004DE8, + 0x034, 0x000038CC, + 0x034, 0x000028C9, + 0x034, 0x000018C6, + 0x034, 0x000008C3, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x000001C5, + 0x035, 0x000081C5, + 0x035, 0x000101C5, + 0x035, 0x00020174, + 0x035, 0x00028174, + 0x035, 0x00030174, + 0x035, 0x00040185, + 0x035, 0x00048185, + 0x035, 0x00050185, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x035, 0x00000188, + 0x035, 0x00008147, + 0x035, 0x00010147, + 0x035, 0x000201D7, + 0x035, 0x000281D7, + 0x035, 0x000301D7, + 0x035, 0x000401D8, + 0x035, 0x000481D8, + 0x035, 0x000501D8, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00005B8B, + 0x036, 0x0000DB8B, + 0x036, 0x00015B8B, + 0x036, 0x0001DB8B, + 0x036, 0x000262DB, + 0x036, 0x0002E2DB, + 0x036, 0x000362DB, + 0x036, 0x0003E2DB, + 0x036, 0x0004553B, + 0x036, 0x0004D53B, + 0x036, 0x0005553B, + 0x036, 0x0005D53B, + 0xA0000000, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x036, 0x00084EB4, + 0x036, 0x0008CC35, + 0x036, 0x00094C35, + 0x036, 0x0009CC35, + 0x036, 0x000A4C35, + 0x036, 0x000ACC35, + 0x036, 0x000B4C35, + 0x036, 0x000BCC35, + 0x036, 0x000C4C34, + 0x036, 0x000CCC35, + 0x036, 0x000D4C35, + 0x036, 0x000DCC35, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x03C, 0x000002DC, + 0x03C, 0x00000524, + 0x03C, 0x00000902, + 0xA0000000, 0x00000000, + 0x03C, 0x000002A8, + 0x03C, 0x000005A2, + 0x03C, 0x00000880, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0x0DF, 0x00000080, + 0x80000008, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0x90000008, 0x05000000, 0x40000000, 0x00000000, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D2, + 0x90000002, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EAC43, + 0x062, 0x00038F47, + 0x063, 0x00031157, + 0x064, 0x0001C4AC, + 0x065, 0x000931D1, + 0xA0000000, 0x00000000, + 0x061, 0x000E5D53, + 0x062, 0x00038FCD, + 0x063, 0x000114EB, + 0x064, 0x000196AC, + 0x065, 0x000911D7, + 0xB0000000, 0x00000000, + 0x008, 0x00008400, +}; + +RTW_DECL_TABLE_RF_RADIO(rtw8812a_rf_b, B); + +static const struct rtw_txpwr_lmt_cfg_pair rtw8812a_txpwr_lmt[] = { + { 0, 0, 0, 0, 1, 36, }, + { 2, 0, 0, 0, 1, 32, }, + { 1, 0, 0, 0, 1, 32, }, + { 0, 0, 0, 0, 2, 36, }, + { 2, 0, 0, 0, 2, 32, }, + { 1, 0, 0, 0, 2, 32, }, + { 0, 0, 0, 0, 3, 36, }, + { 2, 0, 0, 0, 3, 32, }, + { 1, 0, 0, 0, 3, 32, }, + { 0, 0, 0, 0, 4, 36, }, + { 2, 0, 0, 0, 4, 32, }, + { 1, 0, 0, 0, 4, 32, }, + { 0, 0, 0, 0, 5, 36, }, + { 2, 0, 0, 0, 5, 32, }, + { 1, 0, 0, 0, 5, 32, }, + { 0, 0, 0, 0, 6, 36, }, + { 2, 0, 0, 0, 6, 32, }, + { 1, 0, 0, 0, 6, 32, }, + { 0, 0, 0, 0, 7, 36, }, + { 2, 0, 0, 0, 7, 32, }, + { 1, 0, 0, 0, 7, 32, }, + { 0, 0, 0, 0, 8, 36, }, + { 2, 0, 0, 0, 8, 32, }, + { 1, 0, 0, 0, 8, 32, }, + { 0, 0, 0, 0, 9, 36, }, + { 2, 0, 0, 0, 9, 32, }, + { 1, 0, 0, 0, 9, 32, }, + { 0, 0, 0, 0, 10, 36, }, + { 2, 0, 0, 0, 10, 32, }, + { 1, 0, 0, 0, 10, 32, }, + { 0, 0, 0, 0, 11, 36, }, + { 2, 0, 0, 0, 11, 32, }, + { 1, 0, 0, 0, 11, 32, }, + { 0, 0, 0, 0, 12, 63, }, + { 2, 0, 0, 0, 12, 32, }, + { 1, 0, 0, 0, 12, 32, }, + { 0, 0, 0, 0, 13, 63, }, + { 2, 0, 0, 0, 13, 32, }, + { 1, 0, 0, 0, 13, 32, }, + { 0, 0, 0, 0, 14, 63, }, + { 2, 0, 0, 0, 14, 63, }, + { 1, 0, 0, 0, 14, 32, }, + { 0, 0, 0, 1, 1, 34, }, + { 2, 0, 0, 1, 1, 32, }, + { 1, 0, 0, 1, 1, 32, }, + { 0, 0, 0, 1, 2, 36, }, + { 2, 0, 0, 1, 2, 32, }, + { 1, 0, 0, 1, 2, 32, }, + { 0, 0, 0, 1, 3, 36, }, + { 2, 0, 0, 1, 3, 32, }, + { 1, 0, 0, 1, 3, 32, }, + { 0, 0, 0, 1, 4, 36, }, + { 2, 0, 0, 1, 4, 32, }, + { 1, 0, 0, 1, 4, 32, }, + { 0, 0, 0, 1, 5, 36, }, + { 2, 0, 0, 1, 5, 32, }, + { 1, 0, 0, 1, 5, 32, }, + { 0, 0, 0, 1, 6, 36, }, + { 2, 0, 0, 1, 6, 32, }, + { 1, 0, 0, 1, 6, 32, }, + { 0, 0, 0, 1, 7, 36, }, + { 2, 0, 0, 1, 7, 32, }, + { 1, 0, 0, 1, 7, 32, }, + { 0, 0, 0, 1, 8, 36, }, + { 2, 0, 0, 1, 8, 32, }, + { 1, 0, 0, 1, 8, 32, }, + { 0, 0, 0, 1, 9, 36, }, + { 2, 0, 0, 1, 9, 32, }, + { 1, 0, 0, 1, 9, 32, }, + { 0, 0, 0, 1, 10, 36, }, + { 2, 0, 0, 1, 10, 32, }, + { 1, 0, 0, 1, 10, 32, }, + { 0, 0, 0, 1, 11, 32, }, + { 2, 0, 0, 1, 11, 32, }, + { 1, 0, 0, 1, 11, 32, }, + { 0, 0, 0, 1, 12, 63, }, + { 2, 0, 0, 1, 12, 32, }, + { 1, 0, 0, 1, 12, 32, }, + { 0, 0, 0, 1, 13, 63, }, + { 2, 0, 0, 1, 13, 32, }, + { 1, 0, 0, 1, 13, 32, }, + { 0, 0, 0, 1, 14, 63, }, + { 2, 0, 0, 1, 14, 63, }, + { 1, 0, 0, 1, 14, 63, }, + { 0, 0, 0, 2, 1, 34, }, + { 2, 0, 0, 2, 1, 32, }, + { 1, 0, 0, 2, 1, 32, }, + { 0, 0, 0, 2, 2, 36, }, + { 2, 0, 0, 2, 2, 32, }, + { 1, 0, 0, 2, 2, 32, }, + { 0, 0, 0, 2, 3, 36, }, + { 2, 0, 0, 2, 3, 32, }, + { 1, 0, 0, 2, 3, 32, }, + { 0, 0, 0, 2, 4, 36, }, + { 2, 0, 0, 2, 4, 32, }, + { 1, 0, 0, 2, 4, 32, }, + { 0, 0, 0, 2, 5, 36, }, + { 2, 0, 0, 2, 5, 32, }, + { 1, 0, 0, 2, 5, 32, }, + { 0, 0, 0, 2, 6, 36, }, + { 2, 0, 0, 2, 6, 32, }, + { 1, 0, 0, 2, 6, 32, }, + { 0, 0, 0, 2, 7, 36, }, + { 2, 0, 0, 2, 7, 32, }, + { 1, 0, 0, 2, 7, 32, }, + { 0, 0, 0, 2, 8, 36, }, + { 2, 0, 0, 2, 8, 32, }, + { 1, 0, 0, 2, 8, 32, }, + { 0, 0, 0, 2, 9, 36, }, + { 2, 0, 0, 2, 9, 32, }, + { 1, 0, 0, 2, 9, 32, }, + { 0, 0, 0, 2, 10, 36, }, + { 2, 0, 0, 2, 10, 32, }, + { 1, 0, 0, 2, 10, 32, }, + { 0, 0, 0, 2, 11, 32, }, + { 2, 0, 0, 2, 11, 32, }, + { 1, 0, 0, 2, 11, 32, }, + { 0, 0, 0, 2, 12, 63, }, + { 2, 0, 0, 2, 12, 32, }, + { 1, 0, 0, 2, 12, 32, }, + { 0, 0, 0, 2, 13, 63, }, + { 2, 0, 0, 2, 13, 32, }, + { 1, 0, 0, 2, 13, 32, }, + { 0, 0, 0, 2, 14, 63, }, + { 2, 0, 0, 2, 14, 63, }, + { 1, 0, 0, 2, 14, 63, }, + { 0, 0, 0, 3, 1, 32, }, + { 2, 0, 0, 3, 1, 32, }, + { 1, 0, 0, 3, 1, 32, }, + { 0, 0, 0, 3, 2, 34, }, + { 2, 0, 0, 3, 2, 32, }, + { 1, 0, 0, 3, 2, 32, }, + { 0, 0, 0, 3, 3, 34, }, + { 2, 0, 0, 3, 3, 32, }, + { 1, 0, 0, 3, 3, 32, }, + { 0, 0, 0, 3, 4, 34, }, + { 2, 0, 0, 3, 4, 32, }, + { 1, 0, 0, 3, 4, 32, }, + { 0, 0, 0, 3, 5, 34, }, + { 2, 0, 0, 3, 5, 32, }, + { 1, 0, 0, 3, 5, 32, }, + { 0, 0, 0, 3, 6, 34, }, + { 2, 0, 0, 3, 6, 32, }, + { 1, 0, 0, 3, 6, 32, }, + { 0, 0, 0, 3, 7, 34, }, + { 2, 0, 0, 3, 7, 32, }, + { 1, 0, 0, 3, 7, 32, }, + { 0, 0, 0, 3, 8, 34, }, + { 2, 0, 0, 3, 8, 32, }, + { 1, 0, 0, 3, 8, 32, }, + { 0, 0, 0, 3, 9, 34, }, + { 2, 0, 0, 3, 9, 32, }, + { 1, 0, 0, 3, 9, 32, }, + { 0, 0, 0, 3, 10, 34, }, + { 2, 0, 0, 3, 10, 32, }, + { 1, 0, 0, 3, 10, 32, }, + { 0, 0, 0, 3, 11, 30, }, + { 2, 0, 0, 3, 11, 32, }, + { 1, 0, 0, 3, 11, 32, }, + { 0, 0, 0, 3, 12, 63, }, + { 2, 0, 0, 3, 12, 32, }, + { 1, 0, 0, 3, 12, 32, }, + { 0, 0, 0, 3, 13, 63, }, + { 2, 0, 0, 3, 13, 32, }, + { 1, 0, 0, 3, 13, 32, }, + { 0, 0, 0, 3, 14, 63, }, + { 2, 0, 0, 3, 14, 63, }, + { 1, 0, 0, 3, 14, 63, }, + { 0, 0, 1, 2, 1, 63, }, + { 2, 0, 1, 2, 1, 63, }, + { 1, 0, 1, 2, 1, 63, }, + { 0, 0, 1, 2, 2, 63, }, + { 2, 0, 1, 2, 2, 63, }, + { 1, 0, 1, 2, 2, 63, }, + { 0, 0, 1, 2, 3, 32, }, + { 2, 0, 1, 2, 3, 32, }, + { 1, 0, 1, 2, 3, 32, }, + { 0, 0, 1, 2, 4, 36, }, + { 2, 0, 1, 2, 4, 32, }, + { 1, 0, 1, 2, 4, 32, }, + { 0, 0, 1, 2, 5, 36, }, + { 2, 0, 1, 2, 5, 32, }, + { 1, 0, 1, 2, 5, 32, }, + { 0, 0, 1, 2, 6, 36, }, + { 2, 0, 1, 2, 6, 32, }, + { 1, 0, 1, 2, 6, 32, }, + { 0, 0, 1, 2, 7, 36, }, + { 2, 0, 1, 2, 7, 32, }, + { 1, 0, 1, 2, 7, 32, }, + { 0, 0, 1, 2, 8, 36, }, + { 2, 0, 1, 2, 8, 32, }, + { 1, 0, 1, 2, 8, 32, }, + { 0, 0, 1, 2, 9, 36, }, + { 2, 0, 1, 2, 9, 32, }, + { 1, 0, 1, 2, 9, 32, }, + { 0, 0, 1, 2, 10, 36, }, + { 2, 0, 1, 2, 10, 32, }, + { 1, 0, 1, 2, 10, 32, }, + { 0, 0, 1, 2, 11, 32, }, + { 2, 0, 1, 2, 11, 32, }, + { 1, 0, 1, 2, 11, 32, }, + { 0, 0, 1, 2, 12, 63, }, + { 2, 0, 1, 2, 12, 32, }, + { 1, 0, 1, 2, 12, 32, }, + { 0, 0, 1, 2, 13, 63, }, + { 2, 0, 1, 2, 13, 32, }, + { 1, 0, 1, 2, 13, 32, }, + { 0, 0, 1, 2, 14, 63, }, + { 2, 0, 1, 2, 14, 63, }, + { 1, 0, 1, 2, 14, 63, }, + { 0, 0, 1, 3, 1, 63, }, + { 2, 0, 1, 3, 1, 63, }, + { 1, 0, 1, 3, 1, 63, }, + { 0, 0, 1, 3, 2, 63, }, + { 2, 0, 1, 3, 2, 63, }, + { 1, 0, 1, 3, 2, 63, }, + { 0, 0, 1, 3, 3, 30, }, + { 2, 0, 1, 3, 3, 30, }, + { 1, 0, 1, 3, 3, 30, }, + { 0, 0, 1, 3, 4, 34, }, + { 2, 0, 1, 3, 4, 30, }, + { 1, 0, 1, 3, 4, 30, }, + { 0, 0, 1, 3, 5, 34, }, + { 2, 0, 1, 3, 5, 30, }, + { 1, 0, 1, 3, 5, 30, }, + { 0, 0, 1, 3, 6, 34, }, + { 2, 0, 1, 3, 6, 30, }, + { 1, 0, 1, 3, 6, 30, }, + { 0, 0, 1, 3, 7, 34, }, + { 2, 0, 1, 3, 7, 30, }, + { 1, 0, 1, 3, 7, 30, }, + { 0, 0, 1, 3, 8, 34, }, + { 2, 0, 1, 3, 8, 30, }, + { 1, 0, 1, 3, 8, 30, }, + { 0, 0, 1, 3, 9, 34, }, + { 2, 0, 1, 3, 9, 30, }, + { 1, 0, 1, 3, 9, 30, }, + { 0, 0, 1, 3, 10, 34, }, + { 2, 0, 1, 3, 10, 30, }, + { 1, 0, 1, 3, 10, 30, }, + { 0, 0, 1, 3, 11, 30, }, + { 2, 0, 1, 3, 11, 30, }, + { 1, 0, 1, 3, 11, 30, }, + { 0, 0, 1, 3, 12, 63, }, + { 2, 0, 1, 3, 12, 32, }, + { 1, 0, 1, 3, 12, 32, }, + { 0, 0, 1, 3, 13, 63, }, + { 2, 0, 1, 3, 13, 32, }, + { 1, 0, 1, 3, 13, 32, }, + { 0, 0, 1, 3, 14, 63, }, + { 2, 0, 1, 3, 14, 63, }, + { 1, 0, 1, 3, 14, 63, }, + { 0, 1, 0, 1, 36, 30, }, + { 2, 1, 0, 1, 36, 32, }, + { 1, 1, 0, 1, 36, 32, }, + { 0, 1, 0, 1, 40, 30, }, + { 2, 1, 0, 1, 40, 32, }, + { 1, 1, 0, 1, 40, 32, }, + { 0, 1, 0, 1, 44, 30, }, + { 2, 1, 0, 1, 44, 32, }, + { 1, 1, 0, 1, 44, 32, }, + { 0, 1, 0, 1, 48, 30, }, + { 2, 1, 0, 1, 48, 32, }, + { 1, 1, 0, 1, 48, 32, }, + { 0, 1, 0, 1, 52, 36, }, + { 2, 1, 0, 1, 52, 32, }, + { 1, 1, 0, 1, 52, 32, }, + { 0, 1, 0, 1, 56, 34, }, + { 2, 1, 0, 1, 56, 32, }, + { 1, 1, 0, 1, 56, 32, }, + { 0, 1, 0, 1, 60, 32, }, + { 2, 1, 0, 1, 60, 32, }, + { 1, 1, 0, 1, 60, 32, }, + { 0, 1, 0, 1, 64, 28, }, + { 2, 1, 0, 1, 64, 32, }, + { 1, 1, 0, 1, 64, 32, }, + { 0, 1, 0, 1, 100, 30, }, + { 2, 1, 0, 1, 100, 32, }, + { 1, 1, 0, 1, 100, 32, }, + { 0, 1, 0, 1, 104, 30, }, + { 2, 1, 0, 1, 104, 32, }, + { 1, 1, 0, 1, 104, 32, }, + { 0, 1, 0, 1, 108, 32, }, + { 2, 1, 0, 1, 108, 32, }, + { 1, 1, 0, 1, 108, 32, }, + { 0, 1, 0, 1, 112, 34, }, + { 2, 1, 0, 1, 112, 32, }, + { 1, 1, 0, 1, 112, 32, }, + { 0, 1, 0, 1, 116, 34, }, + { 2, 1, 0, 1, 116, 32, }, + { 1, 1, 0, 1, 116, 32, }, + { 0, 1, 0, 1, 120, 36, }, + { 2, 1, 0, 1, 120, 32, }, + { 1, 1, 0, 1, 120, 32, }, + { 0, 1, 0, 1, 124, 34, }, + { 2, 1, 0, 1, 124, 32, }, + { 1, 1, 0, 1, 124, 32, }, + { 0, 1, 0, 1, 128, 32, }, + { 2, 1, 0, 1, 128, 32, }, + { 1, 1, 0, 1, 128, 32, }, + { 0, 1, 0, 1, 132, 30, }, + { 2, 1, 0, 1, 132, 32, }, + { 1, 1, 0, 1, 132, 32, }, + { 0, 1, 0, 1, 136, 30, }, + { 2, 1, 0, 1, 136, 32, }, + { 1, 1, 0, 1, 136, 32, }, + { 0, 1, 0, 1, 140, 28, }, + { 2, 1, 0, 1, 140, 32, }, + { 1, 1, 0, 1, 140, 32, }, + { 0, 1, 0, 1, 149, 36, }, + { 2, 1, 0, 1, 149, 32, }, + { 1, 1, 0, 1, 149, 63, }, + { 0, 1, 0, 1, 153, 36, }, + { 2, 1, 0, 1, 153, 32, }, + { 1, 1, 0, 1, 153, 63, }, + { 0, 1, 0, 1, 157, 36, }, + { 2, 1, 0, 1, 157, 32, }, + { 1, 1, 0, 1, 157, 63, }, + { 0, 1, 0, 1, 161, 36, }, + { 2, 1, 0, 1, 161, 32, }, + { 1, 1, 0, 1, 161, 63, }, + { 0, 1, 0, 1, 165, 36, }, + { 2, 1, 0, 1, 165, 32, }, + { 1, 1, 0, 1, 165, 63, }, + { 0, 1, 0, 2, 36, 30, }, + { 2, 1, 0, 2, 36, 32, }, + { 1, 1, 0, 2, 36, 32, }, + { 0, 1, 0, 2, 40, 30, }, + { 2, 1, 0, 2, 40, 32, }, + { 1, 1, 0, 2, 40, 32, }, + { 0, 1, 0, 2, 44, 30, }, + { 2, 1, 0, 2, 44, 32, }, + { 1, 1, 0, 2, 44, 32, }, + { 0, 1, 0, 2, 48, 30, }, + { 2, 1, 0, 2, 48, 32, }, + { 1, 1, 0, 2, 48, 32, }, + { 0, 1, 0, 2, 52, 36, }, + { 2, 1, 0, 2, 52, 32, }, + { 1, 1, 0, 2, 52, 32, }, + { 0, 1, 0, 2, 56, 34, }, + { 2, 1, 0, 2, 56, 32, }, + { 1, 1, 0, 2, 56, 32, }, + { 0, 1, 0, 2, 60, 32, }, + { 2, 1, 0, 2, 60, 32, }, + { 1, 1, 0, 2, 60, 32, }, + { 0, 1, 0, 2, 64, 28, }, + { 2, 1, 0, 2, 64, 32, }, + { 1, 1, 0, 2, 64, 32, }, + { 0, 1, 0, 2, 100, 30, }, + { 2, 1, 0, 2, 100, 32, }, + { 1, 1, 0, 2, 100, 32, }, + { 0, 1, 0, 2, 104, 30, }, + { 2, 1, 0, 2, 104, 32, }, + { 1, 1, 0, 2, 104, 32, }, + { 0, 1, 0, 2, 108, 32, }, + { 2, 1, 0, 2, 108, 32, }, + { 1, 1, 0, 2, 108, 32, }, + { 0, 1, 0, 2, 112, 34, }, + { 2, 1, 0, 2, 112, 32, }, + { 1, 1, 0, 2, 112, 32, }, + { 0, 1, 0, 2, 116, 34, }, + { 2, 1, 0, 2, 116, 32, }, + { 1, 1, 0, 2, 116, 32, }, + { 0, 1, 0, 2, 120, 36, }, + { 2, 1, 0, 2, 120, 32, }, + { 1, 1, 0, 2, 120, 32, }, + { 0, 1, 0, 2, 124, 34, }, + { 2, 1, 0, 2, 124, 32, }, + { 1, 1, 0, 2, 124, 32, }, + { 0, 1, 0, 2, 128, 32, }, + { 2, 1, 0, 2, 128, 32, }, + { 1, 1, 0, 2, 128, 32, }, + { 0, 1, 0, 2, 132, 30, }, + { 2, 1, 0, 2, 132, 32, }, + { 1, 1, 0, 2, 132, 32, }, + { 0, 1, 0, 2, 136, 30, }, + { 2, 1, 0, 2, 136, 32, }, + { 1, 1, 0, 2, 136, 32, }, + { 0, 1, 0, 2, 140, 28, }, + { 2, 1, 0, 2, 140, 32, }, + { 1, 1, 0, 2, 140, 32, }, + { 0, 1, 0, 2, 149, 36, }, + { 2, 1, 0, 2, 149, 32, }, + { 1, 1, 0, 2, 149, 63, }, + { 0, 1, 0, 2, 153, 36, }, + { 2, 1, 0, 2, 153, 32, }, + { 1, 1, 0, 2, 153, 63, }, + { 0, 1, 0, 2, 157, 36, }, + { 2, 1, 0, 2, 157, 32, }, + { 1, 1, 0, 2, 157, 63, }, + { 0, 1, 0, 2, 161, 36, }, + { 2, 1, 0, 2, 161, 32, }, + { 1, 1, 0, 2, 161, 63, }, + { 0, 1, 0, 2, 165, 36, }, + { 2, 1, 0, 2, 165, 32, }, + { 1, 1, 0, 2, 165, 63, }, + { 0, 1, 0, 3, 36, 28, }, + { 2, 1, 0, 3, 36, 30, }, + { 1, 1, 0, 3, 36, 30, }, + { 0, 1, 0, 3, 40, 28, }, + { 2, 1, 0, 3, 40, 30, }, + { 1, 1, 0, 3, 40, 30, }, + { 0, 1, 0, 3, 44, 28, }, + { 2, 1, 0, 3, 44, 30, }, + { 1, 1, 0, 3, 44, 30, }, + { 0, 1, 0, 3, 48, 28, }, + { 2, 1, 0, 3, 48, 30, }, + { 1, 1, 0, 3, 48, 30, }, + { 0, 1, 0, 3, 52, 34, }, + { 2, 1, 0, 3, 52, 30, }, + { 1, 1, 0, 3, 52, 30, }, + { 0, 1, 0, 3, 56, 32, }, + { 2, 1, 0, 3, 56, 30, }, + { 1, 1, 0, 3, 56, 30, }, + { 0, 1, 0, 3, 60, 30, }, + { 2, 1, 0, 3, 60, 30, }, + { 1, 1, 0, 3, 60, 30, }, + { 0, 1, 0, 3, 64, 26, }, + { 2, 1, 0, 3, 64, 30, }, + { 1, 1, 0, 3, 64, 30, }, + { 0, 1, 0, 3, 100, 28, }, + { 2, 1, 0, 3, 100, 30, }, + { 1, 1, 0, 3, 100, 30, }, + { 0, 1, 0, 3, 104, 28, }, + { 2, 1, 0, 3, 104, 30, }, + { 1, 1, 0, 3, 104, 30, }, + { 0, 1, 0, 3, 108, 30, }, + { 2, 1, 0, 3, 108, 30, }, + { 1, 1, 0, 3, 108, 30, }, + { 0, 1, 0, 3, 112, 32, }, + { 2, 1, 0, 3, 112, 30, }, + { 1, 1, 0, 3, 112, 30, }, + { 0, 1, 0, 3, 116, 32, }, + { 2, 1, 0, 3, 116, 30, }, + { 1, 1, 0, 3, 116, 30, }, + { 0, 1, 0, 3, 120, 34, }, + { 2, 1, 0, 3, 120, 30, }, + { 1, 1, 0, 3, 120, 30, }, + { 0, 1, 0, 3, 124, 32, }, + { 2, 1, 0, 3, 124, 30, }, + { 1, 1, 0, 3, 124, 30, }, + { 0, 1, 0, 3, 128, 30, }, + { 2, 1, 0, 3, 128, 30, }, + { 1, 1, 0, 3, 128, 30, }, + { 0, 1, 0, 3, 132, 28, }, + { 2, 1, 0, 3, 132, 30, }, + { 1, 1, 0, 3, 132, 30, }, + { 0, 1, 0, 3, 136, 28, }, + { 2, 1, 0, 3, 136, 30, }, + { 1, 1, 0, 3, 136, 30, }, + { 0, 1, 0, 3, 140, 26, }, + { 2, 1, 0, 3, 140, 30, }, + { 1, 1, 0, 3, 140, 30, }, + { 0, 1, 0, 3, 149, 34, }, + { 2, 1, 0, 3, 149, 30, }, + { 1, 1, 0, 3, 149, 63, }, + { 0, 1, 0, 3, 153, 34, }, + { 2, 1, 0, 3, 153, 30, }, + { 1, 1, 0, 3, 153, 63, }, + { 0, 1, 0, 3, 157, 34, }, + { 2, 1, 0, 3, 157, 30, }, + { 1, 1, 0, 3, 157, 63, }, + { 0, 1, 0, 3, 161, 34, }, + { 2, 1, 0, 3, 161, 30, }, + { 1, 1, 0, 3, 161, 63, }, + { 0, 1, 0, 3, 165, 34, }, + { 2, 1, 0, 3, 165, 30, }, + { 1, 1, 0, 3, 165, 63, }, + { 0, 1, 1, 2, 38, 30, }, + { 2, 1, 1, 2, 38, 32, }, + { 1, 1, 1, 2, 38, 32, }, + { 0, 1, 1, 2, 46, 30, }, + { 2, 1, 1, 2, 46, 32, }, + { 1, 1, 1, 2, 46, 32, }, + { 0, 1, 1, 2, 54, 32, }, + { 2, 1, 1, 2, 54, 32, }, + { 1, 1, 1, 2, 54, 32, }, + { 0, 1, 1, 2, 62, 32, }, + { 2, 1, 1, 2, 62, 32, }, + { 1, 1, 1, 2, 62, 32, }, + { 0, 1, 1, 2, 102, 28, }, + { 2, 1, 1, 2, 102, 32, }, + { 1, 1, 1, 2, 102, 32, }, + { 0, 1, 1, 2, 110, 32, }, + { 2, 1, 1, 2, 110, 32, }, + { 1, 1, 1, 2, 110, 32, }, + { 0, 1, 1, 2, 118, 36, }, + { 2, 1, 1, 2, 118, 32, }, + { 1, 1, 1, 2, 118, 32, }, + { 0, 1, 1, 2, 126, 34, }, + { 2, 1, 1, 2, 126, 32, }, + { 1, 1, 1, 2, 126, 32, }, + { 0, 1, 1, 2, 134, 32, }, + { 2, 1, 1, 2, 134, 32, }, + { 1, 1, 1, 2, 134, 32, }, + { 0, 1, 1, 2, 151, 36, }, + { 2, 1, 1, 2, 151, 32, }, + { 1, 1, 1, 2, 151, 63, }, + { 0, 1, 1, 2, 159, 36, }, + { 2, 1, 1, 2, 159, 32, }, + { 1, 1, 1, 2, 159, 63, }, + { 0, 1, 1, 3, 38, 28, }, + { 2, 1, 1, 3, 38, 30, }, + { 1, 1, 1, 3, 38, 30, }, + { 0, 1, 1, 3, 46, 28, }, + { 2, 1, 1, 3, 46, 30, }, + { 1, 1, 1, 3, 46, 30, }, + { 0, 1, 1, 3, 54, 30, }, + { 2, 1, 1, 3, 54, 30, }, + { 1, 1, 1, 3, 54, 30, }, + { 0, 1, 1, 3, 62, 30, }, + { 2, 1, 1, 3, 62, 30, }, + { 1, 1, 1, 3, 62, 30, }, + { 0, 1, 1, 3, 102, 26, }, + { 2, 1, 1, 3, 102, 30, }, + { 1, 1, 1, 3, 102, 30, }, + { 0, 1, 1, 3, 110, 30, }, + { 2, 1, 1, 3, 110, 30, }, + { 1, 1, 1, 3, 110, 30, }, + { 0, 1, 1, 3, 118, 34, }, + { 2, 1, 1, 3, 118, 30, }, + { 1, 1, 1, 3, 118, 30, }, + { 0, 1, 1, 3, 126, 32, }, + { 2, 1, 1, 3, 126, 30, }, + { 1, 1, 1, 3, 126, 30, }, + { 0, 1, 1, 3, 134, 30, }, + { 2, 1, 1, 3, 134, 30, }, + { 1, 1, 1, 3, 134, 30, }, + { 0, 1, 1, 3, 151, 34, }, + { 2, 1, 1, 3, 151, 30, }, + { 1, 1, 1, 3, 151, 63, }, + { 0, 1, 1, 3, 159, 34, }, + { 2, 1, 1, 3, 159, 30, }, + { 1, 1, 1, 3, 159, 63, }, + { 0, 1, 2, 4, 42, 30, }, + { 2, 1, 2, 4, 42, 32, }, + { 1, 1, 2, 4, 42, 32, }, + { 0, 1, 2, 4, 58, 28, }, + { 2, 1, 2, 4, 58, 32, }, + { 1, 1, 2, 4, 58, 32, }, + { 0, 1, 2, 4, 106, 30, }, + { 2, 1, 2, 4, 106, 32, }, + { 1, 1, 2, 4, 106, 32, }, + { 0, 1, 2, 4, 122, 34, }, + { 2, 1, 2, 4, 122, 32, }, + { 1, 1, 2, 4, 122, 32, }, + { 0, 1, 2, 4, 155, 36, }, + { 2, 1, 2, 4, 155, 32, }, + { 1, 1, 2, 4, 155, 63, }, + { 0, 1, 2, 5, 42, 28, }, + { 2, 1, 2, 5, 42, 30, }, + { 1, 1, 2, 5, 42, 30, }, + { 0, 1, 2, 5, 58, 26, }, + { 2, 1, 2, 5, 58, 30, }, + { 1, 1, 2, 5, 58, 30, }, + { 0, 1, 2, 5, 106, 28, }, + { 2, 1, 2, 5, 106, 30, }, + { 1, 1, 2, 5, 106, 30, }, + { 0, 1, 2, 5, 122, 32, }, + { 2, 1, 2, 5, 122, 30, }, + { 1, 1, 2, 5, 122, 30, }, + { 0, 1, 2, 5, 155, 34, }, + { 2, 1, 2, 5, 155, 30, }, + { 1, 1, 2, 5, 155, 63, }, +}; + +RTW_DECL_TABLE_TXPWR_LMT(rtw8812a_txpwr_lmt); + +static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8812a[] = { + {0x0012, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0014, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x80, 0}, + {0x0015, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x01, 0}, + {0x0023, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x10, 0}, + {0x0046, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0043, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), 0}, + {0x0003, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), BIT(2)}, + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x0024, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0028, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), BIT(3)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8812a[] = { + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), 0}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(7), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(0), 0}, + {0x0024, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0028, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_act_to_lps_8812a[] = { + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0xFF}, + {0x0522, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x7F}, + {0x05F8, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05F9, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05FA, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05FB, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x0c00, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0x0e00, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0100, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x03}, + {0x0101, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0553, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), BIT(5)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8812a[] = { + {0x0c00, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0x0e00, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0007, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x2A}, + {0x0008, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x02, 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8812a[] = { + {0x0003, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), 0}, + {0x0080, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x05}, + {0x0042, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xF0, 0xcc}, + {0x0042, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xF0, 0xEC}, + {0x0043, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x07}, + {0x0045, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0046, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0xff}, + {0x0047, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x0014, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x80, BIT(7)}, + {0x0015, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x01, BIT(0)}, + {0x0012, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x01, 0}, + {0x0023, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x10, BIT(4)}, + {0x0008, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0x02, 0}, + {0x0007, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x20}, + {0x001f, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0076, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), BIT(3)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +const struct rtw_pwr_seq_cmd * const card_enable_flow_8812a[] = { + trans_carddis_to_cardemu_8812a, + trans_cardemu_to_act_8812a, + NULL +}; + +const struct rtw_pwr_seq_cmd * const enter_lps_flow_8812a[] = { + trans_act_to_lps_8812a, + NULL +}; + +const struct rtw_pwr_seq_cmd * const card_disable_flow_8812a[] = { + trans_act_to_cardemu_8812a, + trans_cardemu_to_carddis_8812a, + NULL +}; + +static const u8 rtw8812a_pwrtrk_5gb_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 14, 14, 14, 14, 14}, + {0, 1, 1, 2, 2, 3, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 14, 14, 14, 14, 14}, + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 10, 10, 11, 11, 12, 12, 13, + 13, 14, 14, 15, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8812a_pwrtrk_5gb_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +static const u8 rtw8812a_pwrtrk_5ga_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 15, 15, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 15, 15, 15, 15, 15}, + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 15, 15, 15, 15, 15}, +}; + +static const u8 rtw8812a_pwrtrk_5ga_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 12, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +static const u8 rtw8812a_pwrtrk_2gb_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_2gb_p[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const u8 rtw8812a_pwrtrk_2ga_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10 +}; + +static const u8 rtw8812a_pwrtrk_2ga_p[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const u8 rtw8812a_pwrtrk_2g_cck_b_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_2g_cck_b_p[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static const u8 rtw8812a_pwrtrk_2g_cck_a_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 10, 10, 10 +}; + +static const u8 rtw8812a_pwrtrk_2g_cck_a_p[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[0] = rtw8812a_pwrtrk_5gb_n[0], + .pwrtrk_5gb_n[1] = rtw8812a_pwrtrk_5gb_n[1], + .pwrtrk_5gb_n[2] = rtw8812a_pwrtrk_5gb_n[2], + .pwrtrk_5gb_p[0] = rtw8812a_pwrtrk_5gb_p[0], + .pwrtrk_5gb_p[1] = rtw8812a_pwrtrk_5gb_p[1], + .pwrtrk_5gb_p[2] = rtw8812a_pwrtrk_5gb_p[2], + .pwrtrk_5ga_n[0] = rtw8812a_pwrtrk_5ga_n[0], + .pwrtrk_5ga_n[1] = rtw8812a_pwrtrk_5ga_n[1], + .pwrtrk_5ga_n[2] = rtw8812a_pwrtrk_5ga_n[2], + .pwrtrk_5ga_p[0] = rtw8812a_pwrtrk_5ga_p[0], + .pwrtrk_5ga_p[1] = rtw8812a_pwrtrk_5ga_p[1], + .pwrtrk_5ga_p[2] = rtw8812a_pwrtrk_5ga_p[2], + .pwrtrk_2gb_n = rtw8812a_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8812a_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8812a_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8812a_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8812a_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8812a_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8812a_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8812a_pwrtrk_2g_cck_a_p, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_5gb_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, + 13, 14, 15, 16, 16, 17, 17, 18, 18}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, + 12, 14, 13, 13, 14, 14, 14, 15, 15}, + {0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 14, 15, 15, 16, 16}, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_5gb_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_5ga_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, + 13, 14, 15, 16, 16, 17, 17, 18, 18}, + {0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12, + 12, 13, 13, 14, 15, 16, 16, 17, 17}, + {0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, + 13, 14, 14, 15, 15, 16, 17, 18, 18}, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_5ga_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, + {0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11}, +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2gb_n[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, + 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2gb_p[] = { + 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 8, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2ga_n[] = { + 0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2ga_p[] = { + 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_b_n[] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, + 7, 7, 8, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_b_p[] = { + 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 8, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_a_n[] = { + 0, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15 +}; + +static const u8 rtw8812a_pwrtrk_rfe3_2g_cck_a_p[] = { + 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11 +}; + +const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_rfe3_tbl = { + .pwrtrk_5gb_n[0] = rtw8812a_pwrtrk_rfe3_5gb_n[0], + .pwrtrk_5gb_n[1] = rtw8812a_pwrtrk_rfe3_5gb_n[1], + .pwrtrk_5gb_n[2] = rtw8812a_pwrtrk_rfe3_5gb_n[2], + .pwrtrk_5gb_p[0] = rtw8812a_pwrtrk_rfe3_5gb_p[0], + .pwrtrk_5gb_p[1] = rtw8812a_pwrtrk_rfe3_5gb_p[1], + .pwrtrk_5gb_p[2] = rtw8812a_pwrtrk_rfe3_5gb_p[2], + .pwrtrk_5ga_n[0] = rtw8812a_pwrtrk_rfe3_5ga_n[0], + .pwrtrk_5ga_n[1] = rtw8812a_pwrtrk_rfe3_5ga_n[1], + .pwrtrk_5ga_n[2] = rtw8812a_pwrtrk_rfe3_5ga_n[2], + .pwrtrk_5ga_p[0] = rtw8812a_pwrtrk_rfe3_5ga_p[0], + .pwrtrk_5ga_p[1] = rtw8812a_pwrtrk_rfe3_5ga_p[1], + .pwrtrk_5ga_p[2] = rtw8812a_pwrtrk_rfe3_5ga_p[2], + .pwrtrk_2gb_n = rtw8812a_pwrtrk_rfe3_2gb_n, + .pwrtrk_2gb_p = rtw8812a_pwrtrk_rfe3_2gb_p, + .pwrtrk_2ga_n = rtw8812a_pwrtrk_rfe3_2ga_n, + .pwrtrk_2ga_p = rtw8812a_pwrtrk_rfe3_2ga_p, + .pwrtrk_2g_cckb_n = rtw8812a_pwrtrk_rfe3_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8812a_pwrtrk_rfe3_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8812a_pwrtrk_rfe3_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8812a_pwrtrk_rfe3_2g_cck_a_p, +}; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h new file mode 100644 index 00000000000000..f7ab5e4cf0596c --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a_table.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW8812A_TABLE_H__ +#define __RTW8812A_TABLE_H__ + +extern const struct rtw_table rtw8812a_mac_tbl; +extern const struct rtw_table rtw8812a_agc_tbl; +extern const struct rtw_table rtw8812a_agc_diff_lb_tbl; +extern const struct rtw_table rtw8812a_agc_diff_hb_tbl; +extern const struct rtw_table rtw8812a_bb_tbl; +extern const struct rtw_table rtw8812a_bb_pg_tbl; +extern const struct rtw_table rtw8812a_bb_pg_rfe3_tbl; +extern const struct rtw_table rtw8812a_rf_a_tbl; +extern const struct rtw_table rtw8812a_rf_b_tbl; +extern const struct rtw_table rtw8812a_txpwr_lmt_tbl; + +extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8812a[]; +extern const struct rtw_pwr_seq_cmd * const enter_lps_flow_8812a[]; +extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8812a[]; + +extern const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_tbl; +extern const struct rtw_pwr_track_tbl rtw8812a_rtw_pwr_track_rfe3_tbl; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812au.c b/drivers/net/wireless/realtek/rtw88/rtw8812au.c new file mode 100644 index 00000000000000..4da69590a42345 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8812au.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include +#include +#include "main.h" +#include "rtw8812a.h" +#include "usb.h" + +static const struct usb_device_id rtw_8812au_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x2604, 0x0012, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8812a_hw_spec) }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8812au_id_table); + +static struct usb_driver rtw_8812au_driver = { + .name = "rtw_8812au", + .id_table = rtw_8812au_id_table, + .probe = rtw_usb_probe, + .disconnect = rtw_usb_disconnect, +}; +module_usb_driver(rtw_8812au_driver); + +MODULE_AUTHOR("Bitterblue Smith "); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8812au driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c new file mode 100644 index 00000000000000..db242c9ad68f56 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -0,0 +1,1197 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "main.h" +#include "coex.h" +#include "phy.h" +#include "reg.h" +#include "rtw88xxa.h" +#include "rtw8821a.h" +#include "rtw8821a_table.h" +#include "tx.h" + +static void rtw8821a_power_off(struct rtw_dev *rtwdev) +{ + rtw88xxa_power_off(rtwdev, enter_lps_flow_8821a); +} + +static s8 rtw8821a_cck_rx_pwr(u8 lna_idx, u8 vga_idx) +{ + static const s8 lna_gain_table[] = {15, -1, -17, 0, -30, -38}; + s8 rx_pwr_all = 0; + s8 lna_gain; + + switch (lna_idx) { + case 5: + case 4: + case 2: + case 1: + case 0: + lna_gain = lna_gain_table[lna_idx]; + rx_pwr_all = lna_gain - 2 * vga_idx; + break; + default: + break; + } + + return rx_pwr_all; +} + +static void rtw8821a_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat) +{ + rtw88xxa_query_phy_status(rtwdev, phy_status, pkt_stat, + rtw8821a_cck_rx_pwr); +} + +static void rtw8821a_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) +{ +} + +#define CAL_NUM_8821A 3 +#define MACBB_REG_NUM_8821A 8 +#define AFE_REG_NUM_8821A 4 +#define RF_REG_NUM_8821A 3 + +static void rtw8821a_iqk_backup_rf(struct rtw_dev *rtwdev, u32 *rfa_backup, + const u32 *backup_rf_reg, u32 rf_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Save RF Parameters */ + for (i = 0; i < rf_num; i++) + rfa_backup[i] = rtw_read_rf(rtwdev, RF_PATH_A, + backup_rf_reg[i], MASKDWORD); +} + +static void rtw8821a_iqk_restore_rf(struct rtw_dev *rtwdev, + const u32 *backup_rf_reg, + u32 *RF_backup, u32 rf_reg_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + for (i = 0; i < rf_reg_num; i++) + rtw_write_rf(rtwdev, RF_PATH_A, backup_rf_reg[i], + RFREG_MASK, RF_backup[i]); +} + +static void rtw8821a_iqk_restore_afe(struct rtw_dev *rtwdev, u32 *afe_backup, + const u32 *backup_afe_reg, u32 afe_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Reload AFE Parameters */ + for (i = 0; i < afe_num; i++) + rtw_write32(rtwdev, backup_afe_reg[i], afe_backup[i]); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x0); + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x0); + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x0); + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x3c000000); + rtw_write32(rtwdev, REG_LSSI_WRITE_A, 0x00000080); + rtw_write32(rtwdev, REG_TXAGCIDX, 0x00000000); + rtw_write32(rtwdev, REG_IQK_DPD_CFG, 0x20040000); + rtw_write32(rtwdev, REG_CFG_PMPD, 0x20000000); + rtw_write32(rtwdev, REG_RFECTL_A, 0x0); +} + +static void rtw8821a_iqk_rx_fill(struct rtw_dev *rtwdev, + unsigned int rx_x, unsigned int rx_y) +{ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x000003ff, rx_x >> 1); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x03ff0000, (rx_y >> 1) & 0x3ff); +} + +static void rtw8821a_iqk_tx_fill(struct rtw_dev *rtwdev, + unsigned int tx_x, unsigned int tx_y) +{ + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + rtw_write32(rtwdev, REG_LSSI_WRITE_A, 0x00000080); + rtw_write32(rtwdev, REG_IQK_DPD_CFG, 0x20040000); + rtw_write32(rtwdev, REG_CFG_PMPD, 0x20000000); + rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, tx_y); + rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, tx_x); +} + +static void rtw8821a_iqk_tx_vdf_true(struct rtw_dev *rtwdev, u32 cal, + bool *tx0iqkok, + int tx_x0[CAL_NUM_8821A], + int tx_y0[CAL_NUM_8821A]) +{ + u32 cal_retry, delay_count, iqk_ready, tx_fail; + int tx_dt[3], vdf_y[3], vdf_x[3]; + int k; + + for (k = 0; k < 3; k++) { + switch (k) { + case 0: + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, + 0x18008c38); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c38); + rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x0); + break; + case 1: + rtw_write32_mask(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, + BIT(28), 0x0); + rtw_write32_mask(rtwdev, REG_OFDM0_A_TX_AFE, + BIT(28), 0x0); + rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x0); + break; + case 2: + rtw_dbg(rtwdev, RTW_DBG_RFK, + "vdf_y[1] = %x vdf_y[0] = %x\n", + vdf_y[1] >> 21 & 0x00007ff, + vdf_y[0] >> 21 & 0x00007ff); + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "vdf_x[1] = %x vdf_x[0] = %x\n", + vdf_x[1] >> 21 & 0x00007ff, + vdf_x[0] >> 21 & 0x00007ff); + + tx_dt[cal] = (vdf_y[1] >> 20) - (vdf_y[0] >> 20); + tx_dt[cal] = (16 * tx_dt[cal]) * 10000 / 15708; + tx_dt[cal] = (tx_dt[cal] >> 1) + (tx_dt[cal] & BIT(0)); + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, + 0x18008c20); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c20); + rtw_write32_mask(rtwdev, REG_INTPO_SETA, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_INTPO_SETA, 0x3fff0000, + tx_dt[cal] & 0x00003fff); + break; + } + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + + for (cal_retry = 0; cal_retry < 10; cal_retry++) { + /* one shot */ + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + + for (delay_count = 0; delay_count < 20; delay_count++) { + iqk_ready = rtw_read32_mask(rtwdev, + REG_IQKA_END, + BIT(10)); + + /* Originally: if (~iqk_ready || delay_count > 20) + * that looks like a typo so make it more explicit + */ + iqk_ready = true; + + if (iqk_ready) + break; + + mdelay(1); + } + + if (delay_count < 20) { + /* ============TXIQK Check============== */ + tx_fail = rtw_read32_mask(rtwdev, + REG_IQKA_END, + BIT(12)); + + /* Originally: if (~tx_fail) { + * It looks like a typo, so make it more explicit. + */ + tx_fail = false; + + if (!tx_fail) { + rtw_write32(rtwdev, REG_RFECTL_A, + 0x02000000); + vdf_x[k] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + vdf_x[k] <<= 21; + + rtw_write32(rtwdev, REG_RFECTL_A, + 0x04000000); + vdf_y[k] = rtw_read32_mask(rtwdev, + REG_IQKA_END, + 0x07ff0000); + vdf_y[k] <<= 21; + + *tx0iqkok = true; + break; + } + + rtw_write32_mask(rtwdev, REG_IQC_Y, + 0x000007ff, 0x0); + rtw_write32_mask(rtwdev, REG_IQC_X, + 0x000007ff, 0x200); + } + + *tx0iqkok = false; + } + } + + if (k == 3) { + tx_x0[cal] = vdf_x[k - 1]; + tx_y0[cal] = vdf_y[k - 1]; + } +} + +static void rtw8821a_iqk_tx_vdf_false(struct rtw_dev *rtwdev, u32 cal, + bool *tx0iqkok, + int tx_x0[CAL_NUM_8821A], + int tx_y0[CAL_NUM_8821A]) +{ + u32 cal_retry, delay_count, iqk_ready, tx_fail; + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + + for (cal_retry = 0; cal_retry < 10; cal_retry++) { + /* one shot */ + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + + for (delay_count = 0; delay_count < 20; delay_count++) { + iqk_ready = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(10)); + + /* Originally: if (~iqk_ready || delay_count > 20) + * that looks like a typo so make it more explicit + */ + iqk_ready = true; + + if (iqk_ready) + break; + + mdelay(1); + } + + if (delay_count < 20) { + /* ============TXIQK Check============== */ + tx_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(12)); + + /* Originally: if (~tx_fail) { + * It looks like a typo, so make it more explicit. + */ + tx_fail = false; + + if (!tx_fail) { + rtw_write32(rtwdev, REG_RFECTL_A, 0x02000000); + tx_x0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END, + 0x07ff0000); + tx_x0[cal] <<= 21; + + rtw_write32(rtwdev, REG_RFECTL_A, 0x04000000); + tx_y0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END, + 0x07ff0000); + tx_y0[cal] <<= 21; + + *tx0iqkok = true; + break; + } + + rtw_write32_mask(rtwdev, REG_IQC_Y, 0x000007ff, 0x0); + rtw_write32_mask(rtwdev, REG_IQC_X, 0x000007ff, 0x200); + } + + *tx0iqkok = false; + } +} + +static void rtw8821a_iqk_rx(struct rtw_dev *rtwdev, u32 cal, bool *rx0iqkok, + int rx_x0[CAL_NUM_8821A], + int rx_y0[CAL_NUM_8821A]) +{ + u32 cal_retry, delay_count, iqk_ready, rx_fail; + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + + for (cal_retry = 0; cal_retry < 10; cal_retry++) { + /* one shot */ + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + + for (delay_count = 0; delay_count < 20; delay_count++) { + iqk_ready = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(10)); + + /* Originally: if (~iqk_ready || delay_count > 20) + * that looks like a typo so make it more explicit + */ + iqk_ready = true; + + if (iqk_ready) + break; + + mdelay(1); + } + + if (delay_count < 20) { + /* ============RXIQK Check============== */ + rx_fail = rtw_read32_mask(rtwdev, REG_IQKA_END, BIT(11)); + if (!rx_fail) { + rtw_write32(rtwdev, REG_RFECTL_A, 0x06000000); + rx_x0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END, + 0x07ff0000); + rx_x0[cal] <<= 21; + + rtw_write32(rtwdev, REG_RFECTL_A, 0x08000000); + rx_y0[cal] = rtw_read32_mask(rtwdev, REG_IQKA_END, + 0x07ff0000); + rx_y0[cal] <<= 21; + + *rx0iqkok = true; + break; + } + + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x000003ff, 0x200 >> 1); + rtw_write32_mask(rtwdev, REG_RX_IQC_AB_A, + 0x03ff0000, 0x0 >> 1); + } + + *rx0iqkok = false; + } +} + +static void rtw8821a_iqk(struct rtw_dev *rtwdev) +{ + int tx_average = 0, rx_average = 0, rx_iqk_loop = 0; + const struct rtw_efuse *efuse = &rtwdev->efuse; + int tx_x = 0, tx_y = 0, rx_x = 0, rx_y = 0; + const struct rtw_hal *hal = &rtwdev->hal; + bool tx0iqkok = false, rx0iqkok = false; + int rx_x_temp = 0, rx_y_temp = 0; + int rx_x0[2][CAL_NUM_8821A]; + int rx_y0[2][CAL_NUM_8821A]; + int tx_x0[CAL_NUM_8821A]; + int tx_y0[CAL_NUM_8821A]; + bool rx_finish1 = false; + bool rx_finish2 = false; + bool vdf_enable; + u32 cal; + int i; + + rtw_dbg(rtwdev, RTW_DBG_RFK, + "band_width = %d, ext_pa = %d, ext_pa_5g = %d\n", + hal->current_band_width, efuse->ext_pa_2g, efuse->ext_pa_5g); + + vdf_enable = hal->current_band_width == RTW_CHANNEL_WIDTH_80; + + for (cal = 0; cal < CAL_NUM_8821A; cal++) { + /* path-A LOK */ + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* ========path-A AFE all on======== */ + /* Port 0 DAC/ADC on */ + rtw_write32(rtwdev, REG_AFE_PWR1_A, 0x77777777); + rtw_write32(rtwdev, REG_AFE_PWR2_A, 0x77777777); + + rtw_write32(rtwdev, REG_RX_WAIT_CCA_TX_CCK_RFON_A, 0x19791979); + + /* hardware 3-wire off */ + rtw_write32_mask(rtwdev, REG_3WIRE_SWA, 0xf, 0x4); + + /* LOK setting */ + + /* 1. DAC/ADC sampling rate (160 MHz) */ + rtw_write32_mask(rtwdev, REG_CK_MONHA, GENMASK(26, 24), 0x7); + + /* 2. LoK RF setting (at BW = 20M) */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80002); + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, 0x00c00, 0x3); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x20000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x0003f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xf3fc3); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, + 0x931d5); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001); + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1); + /* TX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000); + /* RX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000); + /* [0]:AGC_en, [15]:idac_K_Mask */ + rtw_write32(rtwdev, REG_IQK_COM96, 0x00462910); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + if (efuse->ext_pa_5g) + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403f7); + else + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403f4); + + if (hal->current_band_type == RTW_BAND_5G) + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x68163e96); + else + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28163e96); + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x18008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x38008c10); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00100000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xfa000000); + rtw_write32(rtwdev, REG_IQK_COM64, 0xf8000000); + + mdelay(10); + rtw_write32(rtwdev, REG_RFECTL_A, 0x00000000); + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXMOD, 0x7fe00, + rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, 0xffc00)); + + if (hal->current_band_width == RTW_CHANNEL_WIDTH_40) + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, + RF18_BW_MASK, 0x1); + else if (hal->current_band_width == RTW_CHANNEL_WIDTH_80) + rtw_write_rf(rtwdev, RF_PATH_A, RF_CFGCH, + RF18_BW_MASK, 0x0); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + /* 3. TX RF setting */ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x20000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x0003f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xf3fc3); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d5); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x8a001); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000); + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + rtw_write32_mask(rtwdev, REG_TXAGCIDX, BIT(0), 0x1); + /* TX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM00, 0x29002000); + /* RX (X,Y) */ + rtw_write32(rtwdev, REG_IQK_COM32, 0xa9002000); + /* [0]:AGC_en, [15]:idac_K_Mask */ + rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a910); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + if (efuse->ext_pa_5g) + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403f7); + else + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, + 0x821403e3); + + if (hal->current_band_type == RTW_BAND_5G) + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x40163e96); + else + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x00163e96); + + if (vdf_enable) + rtw8821a_iqk_tx_vdf_true(rtwdev, cal, &tx0iqkok, + tx_x0, tx_y0); + else + rtw8821a_iqk_tx_vdf_false(rtwdev, cal, &tx0iqkok, + tx_x0, tx_y0); + + if (!tx0iqkok) + break; /* TXK fail, Don't do RXK */ + + /* ====== RX IQK ====== */ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + /* 1. RX RF setting */ + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x80000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_ADDR, RFREG_MASK, + 0x30000); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA0, RFREG_MASK, + 0x0002f); + rtw_write_rf(rtwdev, RF_PATH_A, RF_MODE_TABLE_DATA1, RFREG_MASK, + 0xfffbb); + rtw_write_rf(rtwdev, RF_PATH_A, RF_RXBB2, RFREG_MASK, 0x88001); + rtw_write_rf(rtwdev, RF_PATH_A, RF_TXA_PREPAD, RFREG_MASK, 0x931d8); + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTWE, RFREG_MASK, 0x00000); + + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x03FF8000, + (tx_x0[cal] >> 21) & 0x000007ff); + rtw_write32_mask(rtwdev, REG_IQK_COM00, 0x000007FF, + (tx_y0[cal] >> 21) & 0x000007ff); + rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_IQK_COM00, BIT(31), 0x0); + rtw_write32(rtwdev, REG_DAC_RSTB, 0x00008000); + rtw_write32(rtwdev, REG_IQK_COM96, 0x0046a911); + + /* [31] = 1 --> Page C1 */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x1); + + /* TX_Tone_idx[9:0], TxK_Mask[29] TX_Tone = 16 */ + rtw_write32(rtwdev, REG_OFDM0_XA_TX_IQ_IMBALANCE, 0x38008c10); + /* RX_Tone_idx[9:0], RxK_Mask[29] */ + rtw_write32(rtwdev, REG_OFDM0_A_TX_AFE, 0x18008c10); + rtw_write32(rtwdev, REG_OFDM0_XB_TX_IQ_IMBALANCE, 0x02140119); + + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE) + rx_iqk_loop = 2; /* for 2% fail; */ + else + rx_iqk_loop = 1; + + for (i = 0; i < rx_iqk_loop; i++) { + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE && i == 0) + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28161100); /* Good */ + else + rtw_write32(rtwdev, REG_TSSI_TRK_SW, 0x28160d00); + + rtw8821a_iqk_rx(rtwdev, cal, &rx0iqkok, + rx_x0[i], rx_y0[i]); + } + + if (tx0iqkok) + tx_average++; + if (rx0iqkok) + rx_average++; + } + + /* FillIQK Result */ + + if (tx_average == 0) + return; + + for (i = 0; i < tx_average; i++) + rtw_dbg(rtwdev, RTW_DBG_RFK, + "tx_x0[%d] = %x ;; tx_y0[%d] = %x\n", + i, (tx_x0[i] >> 21) & 0x000007ff, + i, (tx_y0[i] >> 21) & 0x000007ff); + + if (rtw88xxa_iqk_finish(tx_average, 3, tx_x0, tx_y0, + &tx_x, &tx_y, true, true)) + rtw8821a_iqk_tx_fill(rtwdev, tx_x, tx_y); + else + rtw8821a_iqk_tx_fill(rtwdev, 0x200, 0x0); + + if (rx_average == 0) + return; + + for (i = 0; i < rx_average; i++) { + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x0[0][%d] = %x ;; rx_y0[0][%d] = %x\n", + i, (rx_x0[0][i] >> 21) & 0x000007ff, + i, (rx_y0[0][i] >> 21) & 0x000007ff); + + if (rx_iqk_loop == 2) + rtw_dbg(rtwdev, RTW_DBG_RFK, + "rx_x0[1][%d] = %x ;; rx_y0[1][%d] = %x\n", + i, (rx_x0[1][i] >> 21) & 0x000007ff, + i, (rx_y0[1][i] >> 21) & 0x000007ff); + } + + rx_finish1 = rtw88xxa_iqk_finish(rx_average, 4, rx_x0[0], rx_y0[0], + &rx_x_temp, &rx_y_temp, true, true); + + if (rx_finish1) { + rx_x = rx_x_temp; + rx_y = rx_y_temp; + } + + if (rx_iqk_loop == 2) { + rx_finish2 = rtw88xxa_iqk_finish(rx_average, 4, + rx_x0[1], rx_y0[1], + &rx_x, &rx_y, true, true); + + if (rx_finish1 && rx_finish2) { + rx_x = (rx_x + rx_x_temp) / 2; + rx_y = (rx_y + rx_y_temp) / 2; + } + } + + if (rx_finish1 || rx_finish2) + rtw8821a_iqk_rx_fill(rtwdev, rx_x, rx_y); + else + rtw8821a_iqk_rx_fill(rtwdev, 0x200, 0x0); +} + +static void rtw8821a_do_iqk(struct rtw_dev *rtwdev) +{ + static const u32 backup_macbb_reg[MACBB_REG_NUM_8821A] = { + 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0x838, 0x82c + }; + static const u32 backup_afe_reg[AFE_REG_NUM_8821A] = { + 0xc5c, 0xc60, 0xc64, 0xc68 + }; + static const u32 backup_rf_reg[RF_REG_NUM_8821A] = { + 0x65, 0x8f, 0x0 + }; + u32 macbb_backup[MACBB_REG_NUM_8821A]; + u32 afe_backup[AFE_REG_NUM_8821A]; + u32 rfa_backup[RF_REG_NUM_8821A]; + + rtw88xxa_iqk_backup_mac_bb(rtwdev, macbb_backup, + backup_macbb_reg, MACBB_REG_NUM_8821A); + rtw88xxa_iqk_backup_afe(rtwdev, afe_backup, + backup_afe_reg, AFE_REG_NUM_8821A); + rtw8821a_iqk_backup_rf(rtwdev, rfa_backup, + backup_rf_reg, RF_REG_NUM_8821A); + + rtw88xxa_iqk_configure_mac(rtwdev); + + rtw8821a_iqk(rtwdev); + + rtw8821a_iqk_restore_rf(rtwdev, backup_rf_reg, + rfa_backup, RF_REG_NUM_8821A); + rtw8821a_iqk_restore_afe(rtwdev, afe_backup, + backup_afe_reg, AFE_REG_NUM_8821A); + rtw88xxa_iqk_restore_mac_bb(rtwdev, macbb_backup, + backup_macbb_reg, MACBB_REG_NUM_8821A); +} + +static void rtw8821a_phy_calibration(struct rtw_dev *rtwdev) +{ + rtw8821a_do_iqk(rtwdev); +} + +static void rtw8821a_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + if (!dm_info->pwr_trk_triggered) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, + GENMASK(17, 16), 0x03); + dm_info->pwr_trk_triggered = true; + return; + } + + rtw88xxa_phy_pwrtrack(rtwdev, NULL, rtw8821a_do_iqk); + dm_info->pwr_trk_triggered = false; +} + +static void rtw8821a_fill_txdesc_checksum(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + u8 *txdesc) +{ + fill_txdesc_checksum_common(txdesc, 16); +} + +static void rtw8821a_coex_cfg_init(struct rtw_dev *rtwdev) +{ + u8 val8; + + /* BT report packet sample rate */ + rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, BIT_MASK_SAMPLE_RATE, 0x5); + + val8 = BIT_STATIS_BT_EN; + if (rtwdev->efuse.share_ant) + val8 |= BIT_R_GRANTALL_WLMASK; + rtw_write8(rtwdev, REG_BT_COEX_ENH_INTR_CTRL, val8); + + /* enable BT counter statistics */ + rtw_write8(rtwdev, REG_BT_STAT_CTRL, 0x3); + + /* enable PTA */ + rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN); +} + +static void rtw8821a_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, + u8 pos_type) +{ + bool share_ant = rtwdev->efuse.share_ant; + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + u32 phase = coex_dm->cur_ant_pos_type; + + if (!rtwdev->efuse.btcoex) + return; + + switch (phase) { + case COEX_SET_ANT_POWERON: + case COEX_SET_ANT_INIT: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, + share_ant ? PTA_CTRL_PIN : DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1); + break; + case COEX_SET_ANT_WONLY: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_clr(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1); + break; + case COEX_SET_ANT_2G: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_clr(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, + share_ant ? PTA_CTRL_PIN : DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, 0x1); + break; + case COEX_SET_ANT_5G: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, + share_ant ? 0x2 : 0x1); + break; + case COEX_SET_ANT_WOFF: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_set(rtwdev, REG_GNT_BT, BIT_PTA_SW_CTL); + + rtw_write8(rtwdev, REG_RFE_CTRL8, DPDT_CTRL_PIN); + rtw_write32_mask(rtwdev, REG_RFE_CTRL8, 0x30000000, + share_ant ? 0x2 : 0x1); + break; + default: + rtw_warn(rtwdev, "%s: not handling phase %d\n", + __func__, phase); + break; + } +} + +static void rtw8821a_coex_cfg_gnt_fix(struct rtw_dev *rtwdev) +{ +} + +static void rtw8821a_coex_cfg_gnt_debug(struct rtw_dev *rtwdev) +{ +} + +static void rtw8821a_coex_cfg_rfe_type(struct rtw_dev *rtwdev) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_rfe *coex_rfe = &coex->rfe; + + coex_rfe->ant_switch_exist = true; +} + +static void rtw8821a_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + struct rtw_efuse *efuse = &rtwdev->efuse; + bool share_ant = efuse->share_ant; + + if (share_ant) + return; + + if (wl_pwr == coex_dm->cur_wl_pwr_lvl) + return; + + coex_dm->cur_wl_pwr_lvl = wl_pwr; +} + +static void rtw8821a_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) +{ +} + +static const struct rtw_chip_ops rtw8821a_ops = { + .power_on = rtw88xxa_power_on, + .power_off = rtw8821a_power_off, + .phy_set_param = NULL, + .read_efuse = rtw88xxa_read_efuse, + .query_phy_status = rtw8821a_query_phy_status, + .set_channel = rtw88xxa_set_channel, + .mac_init = NULL, + .read_rf = rtw88xxa_phy_read_rf, + .write_rf = rtw_phy_write_rf_reg_sipi, + .set_antenna = NULL, + .set_tx_power_index = rtw88xxa_set_tx_power_index, + .cfg_ldo25 = rtw8821a_cfg_ldo25, + .efuse_grant = rtw88xxa_efuse_grant, + .false_alarm_statistics = rtw88xxa_false_alarm_statistics, + .phy_calibration = rtw8821a_phy_calibration, + .cck_pd_set = rtw88xxa_phy_cck_pd_set, + .pwr_track = rtw8821a_pwr_track, + .config_bfee = NULL, + .set_gid_table = NULL, + .cfg_csi_rate = NULL, + .fill_txdesc_checksum = rtw8821a_fill_txdesc_checksum, + .coex_set_init = rtw8821a_coex_cfg_init, + .coex_set_ant_switch = rtw8821a_coex_cfg_ant_switch, + .coex_set_gnt_fix = rtw8821a_coex_cfg_gnt_fix, + .coex_set_gnt_debug = rtw8821a_coex_cfg_gnt_debug, + .coex_set_rfe_type = rtw8821a_coex_cfg_rfe_type, + .coex_set_wl_tx_power = rtw8821a_coex_cfg_wl_tx_power, + .coex_set_wl_rx_gain = rtw8821a_coex_cfg_wl_rx_gain, +}; + +static const struct rtw_page_table page_table_8821a[] = { + /* hq_num, nq_num, lq_num, exq_num, gapq_num */ + {0, 0, 0, 0, 0}, /* SDIO */ + {0, 0, 0, 0, 0}, /* PCI */ + {8, 0, 0, 0, 1}, /* 2 bulk out endpoints */ + {8, 0, 8, 0, 1}, /* 3 bulk out endpoints */ + {8, 0, 8, 4, 1}, /* 4 bulk out endpoints */ +}; + +static const struct rtw_rqpn rqpn_table_8821a[] = { + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH, + RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, +}; + +static const struct rtw_prioq_addrs prioq_addrs_8821a = { + .prio[RTW_DMA_MAPPING_EXTRA] = { + .rsvd = REG_RQPN_NPQ + 2, .avail = REG_RQPN_NPQ + 3, + }, + .prio[RTW_DMA_MAPPING_LOW] = { + .rsvd = REG_RQPN + 1, .avail = REG_FIFOPAGE_CTRL_2 + 1, + }, + .prio[RTW_DMA_MAPPING_NORMAL] = { + .rsvd = REG_RQPN_NPQ, .avail = REG_RQPN_NPQ + 1, + }, + .prio[RTW_DMA_MAPPING_HIGH] = { + .rsvd = REG_RQPN, .avail = REG_FIFOPAGE_CTRL_2, + }, + .wsize = false, +}; + +static const struct rtw_hw_reg rtw8821a_dig[] = { + [0] = { .addr = REG_RXIGI_A, .mask = 0x7f }, +}; + +static const struct rtw_rfe_def rtw8821a_rfe_defs[] = { + [0] = { .phy_pg_tbl = &rtw8821a_bb_pg_tbl, + .txpwr_lmt_tbl = &rtw8821a_txpwr_lmt_tbl, + .pwr_track_tbl = &rtw8821a_rtw_pwr_track_tbl, }, +}; + +/* TODO */ +/* rssi in percentage % (dbm = % - 100) */ +static const u8 wl_rssi_step_8821a[] = {101, 45, 101, 40}; +static const u8 bt_rssi_step_8821a[] = {101, 101, 101, 101}; + +/* table_sant_8821a, table_nsant_8821a, tdma_sant_8821a, and tdma_nsant_8821a + * are copied from rtw8821c.c because the 8821au driver's tables are not + * compatible with the coex code in rtw88. + * + * tdma case 112 (A2DP) byte 0 had to be modified from 0x61 to 0x51, + * otherwise the firmware gets confused after pausing the music: + * rtw_8821au 1-2:1.2: [BTCoex], Bt_info[1], len=7, data=[81 00 0a 01 00 00] + * - 81 means PAN (personal area network) when it should be 4x (A2DP) + * The music is not smooth with the PAN algorithm. + */ + +/* Shared-Antenna Coex Table */ +static const struct coex_table_para table_sant_8821a[] = { + {0x55555555, 0x55555555}, /* case-0 */ + {0x55555555, 0x55555555}, + {0x66555555, 0x66555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xfafafafa, 0xfafafafa}, /* case-5 */ + {0x6a5a5555, 0xaaaaaaaa}, + {0x6a5a56aa, 0x6a5a56aa}, + {0x6a5a5a5a, 0x6a5a5a5a}, + {0x66555555, 0x5a5a5a5a}, + {0x66555555, 0x6a5a5a5a}, /* case-10 */ + {0x66555555, 0xaaaaaaaa}, + {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0x6aaa6aaa}, + {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0xaaaaaaaa}, /* case-15 */ + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x6afa5afa}, + {0xaaffffaa, 0xfafafafa}, + {0xaa5555aa, 0x5a5a5a5a}, + {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */ + {0xaa5555aa, 0xaaaaaaaa}, + {0xffffffff, 0x55555555}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x5a5a5aaa}, /* case-25 */ + {0x55555555, 0x5a5a5a5a}, + {0x55555555, 0xaaaaaaaa}, + {0x66555555, 0x6a5a6a5a}, + {0x66556655, 0x66556655}, + {0x66556aaa, 0x6a5a6aaa}, /* case-30 */ + {0xffffffff, 0x5aaa5aaa}, + {0x56555555, 0x5a5a5aaa} +}; + +/* Non-Shared-Antenna Coex Table */ +static const struct coex_table_para table_nsant_8821a[] = { + {0xffffffff, 0xffffffff}, /* case-100 */ + {0xffff55ff, 0xfafafafa}, + {0x66555555, 0x66555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xffffffff, 0xffffffff}, /* case-105 */ + {0x5afa5afa, 0x5afa5afa}, + {0x55555555, 0xfafafafa}, + {0x66555555, 0xfafafafa}, + {0x66555555, 0x5a5a5a5a}, + {0x66555555, 0x6a5a5a5a}, /* case-110 */ + {0x66555555, 0xaaaaaaaa}, + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0xaaaaaaaa}, + {0xffff55ff, 0xffff55ff}, /* case-115 */ + {0xaaffffaa, 0x5afa5afa}, + {0xaaffffaa, 0xaaaaaaaa}, + {0xffffffff, 0xfafafafa}, + {0xffff55ff, 0xfafafafa}, + {0xffffffff, 0xaaaaaaaa}, /* case-120 */ + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0x5afa5afa}, + {0x55ff55ff, 0x55ff55ff} +}; + +/* Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_sant_8821a[] = { + { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */ + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, + { {0x61, 0x35, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, /* case-5 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x35, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */ + { {0x61, 0x08, 0x03, 0x11, 0x15} }, + { {0x61, 0x08, 0x03, 0x10, 0x14} }, + { {0x51, 0x08, 0x03, 0x10, 0x54} }, + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x11, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */ + { {0x51, 0x4a, 0x03, 0x10, 0x50} }, + { {0x51, 0x08, 0x03, 0x30, 0x54} }, + { {0x55, 0x08, 0x03, 0x10, 0x54} }, + { {0x65, 0x10, 0x03, 0x11, 0x10} }, + { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */ + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x61, 0x08, 0x03, 0x11, 0x11} } +}; + +/* Non-Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_nsant_8821a[] = { + { {0x00, 0x00, 0x00, 0x40, 0x00} }, /* case-100 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, + { {0x61, 0x25, 0x03, 0x11, 0x11} }, + { {0x61, 0x35, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */ + { {0x61, 0x10, 0x03, 0x11, 0x11} }, + { {0x51, 0x08, 0x03, 0x10, 0x14} }, /* a2dp high rssi */ + { {0x51, 0x08, 0x03, 0x10, 0x54} }, /* a2dp not high rssi */ + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x10, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, /* case-120 */ + { {0x51, 0x10, 0x03, 0x10, 0x50} } +}; + +/* TODO */ +static const struct coex_rf_para rf_para_tx_8821a[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {8, 17, true, 4}, + {7, 18, true, 4}, + {6, 19, true, 4}, + {5, 20, true, 4} +}; + +static const struct coex_rf_para rf_para_rx_8821a[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {3, 24, true, 5}, + {2, 26, true, 5}, + {1, 27, true, 5}, + {0, 28, true, 5} +}; + +static_assert(ARRAY_SIZE(rf_para_tx_8821a) == ARRAY_SIZE(rf_para_rx_8821a)); + +static const struct coex_5g_afh_map afh_5g_8821a[] = { {0, 0, 0} }; + +static const struct rtw_reg_domain coex_info_hw_regs_8821a[] = { + {0xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0xCBA, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x430, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x434, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x42a, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0x426, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x45e, BIT(3), RTW_REG_DOMAIN_MAC8}, + {0x454, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x4c, BIT(24) | BIT(23), RTW_REG_DOMAIN_MAC32}, + {0x64, BIT(0), RTW_REG_DOMAIN_MAC8}, + {0x4c6, BIT(4), RTW_REG_DOMAIN_MAC8}, + {0x40, BIT(5), RTW_REG_DOMAIN_MAC8}, + {0x1, RFREG_MASK, RTW_REG_DOMAIN_RF_A}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x550, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x522, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x953, BIT(1), RTW_REG_DOMAIN_MAC8}, + {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, +}; + +const struct rtw_chip_info rtw8821a_hw_spec = { + .ops = &rtw8821a_ops, + .id = RTW_CHIP_TYPE_8821A, + .fw_name = "rtw88/rtw8821a_fw.bin", + .wlan_cpu = RTW_WCPU_11N, + .tx_pkt_desc_sz = 40, + .tx_buf_desc_sz = 16, + .rx_pkt_desc_sz = 24, + .rx_buf_desc_sz = 8, + .phy_efuse_size = 512, + .log_efuse_size = 512, + .ptct_efuse_size = 96 + 1, /* TODO or just 18? */ + .txff_size = 65536, + .rxff_size = 16128, + .rsvd_drv_pg_num = 8, + .txgi_factor = 1, + .is_pwr_by_rate_dec = true, + .max_power_index = 0x3f, + .csi_buf_pg_num = 0, + .band = RTW_BAND_2G | RTW_BAND_5G, + .page_size = 256, + .dig_min = 0x20, + .ht_supported = true, + .vht_supported = true, + .lps_deep_mode_supported = 0, + .sys_func_en = 0xFD, + .pwr_on_seq = card_enable_flow_8821a, + .pwr_off_seq = card_disable_flow_8821a, + .page_table = page_table_8821a, + .rqpn_table = rqpn_table_8821a, + .prioq_addrs = &prioq_addrs_8821a, + .intf_table = NULL, + .dig = rtw8821a_dig, + .rf_sipi_addr = {REG_LSSI_WRITE_A, REG_LSSI_WRITE_B}, + .ltecoex_addr = NULL, + .mac_tbl = &rtw8821a_mac_tbl, + .agc_tbl = &rtw8821a_agc_tbl, + .bb_tbl = &rtw8821a_bb_tbl, + .rf_tbl = {&rtw8821a_rf_a_tbl}, + .rfe_defs = rtw8821a_rfe_defs, + .rfe_defs_size = ARRAY_SIZE(rtw8821a_rfe_defs), + .rx_ldpc = false, + .hw_feature_report = false, + .c2h_ra_report_size = 4, + .old_datarate_fb_limit = true, + .usb_tx_agg_desc_num = 6, + .iqk_threshold = 8, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .max_scan_ie_len = IEEE80211_MAX_DATA_LEN, + + .coex_para_ver = 20190509, /* glcoex_ver_date_8821a_1ant */ + .bt_desired_ver = 0x62, /* But for 2 ant it's 0x5c */ + .scbd_support = false, + .new_scbd10_def = false, + .ble_hid_profile_support = false, + .wl_mimo_ps_support = false, + .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, + .bt_rssi_type = COEX_BTRSSI_RATIO, + .ant_isolation = 10, + .rssi_tolerance = 2, + .wl_rssi_step = wl_rssi_step_8821a, + .bt_rssi_step = bt_rssi_step_8821a, + .table_sant_num = ARRAY_SIZE(table_sant_8821a), + .table_sant = table_sant_8821a, + .table_nsant_num = ARRAY_SIZE(table_nsant_8821a), + .table_nsant = table_nsant_8821a, + .tdma_sant_num = ARRAY_SIZE(tdma_sant_8821a), + .tdma_sant = tdma_sant_8821a, + .tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8821a), + .tdma_nsant = tdma_nsant_8821a, + .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8821a), + .wl_rf_para_tx = rf_para_tx_8821a, + .wl_rf_para_rx = rf_para_rx_8821a, + .bt_afh_span_bw20 = 0x20, + .bt_afh_span_bw40 = 0x30, + .afh_5g_num = ARRAY_SIZE(afh_5g_8821a), + .afh_5g = afh_5g_8821a, + + .coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8821a), + .coex_info_hw_regs = coex_info_hw_regs_8821a, +}; +EXPORT_SYMBOL(rtw8821a_hw_spec); + +MODULE_FIRMWARE("rtw88/rtw8821a_fw.bin"); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.h b/drivers/net/wireless/realtek/rtw88/rtw8821a.h new file mode 100644 index 00000000000000..1b2e548f72343a --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW8821A_H__ +#define __RTW8821A_H__ + +extern const struct rtw_chip_info rtw8821a_hw_spec; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c new file mode 100644 index 00000000000000..c8fd8e331f69c5 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.c @@ -0,0 +1,2350 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include "main.h" +#include "phy.h" +#include "rtw8821a_table.h" + +static const u32 rtw8821a_mac[] = { + 0x421, 0x0000000F, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000007, + 0x437, 0x00000008, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000007, + 0x43F, 0x00000008, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000010, + 0x445, 0x00000000, + 0x446, 0x00000000, + 0x447, 0x00000000, + 0x448, 0x00000000, + 0x449, 0x000000F0, + 0x44A, 0x0000000F, + 0x44B, 0x0000003E, + 0x44C, 0x00000010, + 0x44D, 0x00000000, + 0x44E, 0x00000000, + 0x44F, 0x00000000, + 0x450, 0x00000000, + 0x451, 0x000000F0, + 0x452, 0x0000000F, + 0x453, 0x00000000, + 0x456, 0x0000005E, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x4C8, 0x0000003F, + 0x4C9, 0x000000FF, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55C, 0x00000050, + 0x55D, 0x000000FF, + 0x605, 0x00000030, + 0x607, 0x00000007, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x638, 0x00000050, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000040, + 0x642, 0x00000040, + 0x643, 0x00000000, + 0x652, 0x000000C8, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + 0x718, 0x00000040, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821a_mac, rtw_phy_cfg_mac); + +static const u32 rtw8821a_agc[] = { + 0x81C, 0xBF000001, + 0x81C, 0xBF020001, + 0x81C, 0xBF040001, + 0x81C, 0xBF060001, + 0x81C, 0xBE080001, + 0x81C, 0xBD0A0001, + 0x81C, 0xBC0C0001, + 0x81C, 0xBA0E0001, + 0x81C, 0xB9100001, + 0x81C, 0xB8120001, + 0x81C, 0xB7140001, + 0x81C, 0xB6160001, + 0x81C, 0xB5180001, + 0x81C, 0xB41A0001, + 0x81C, 0xB31C0001, + 0x81C, 0xB21E0001, + 0x81C, 0xB1200001, + 0x81C, 0xB0220001, + 0x81C, 0xAF240001, + 0x81C, 0xAE260001, + 0x81C, 0xAD280001, + 0x81C, 0xAC2A0001, + 0x81C, 0xAB2C0001, + 0x81C, 0xAA2E0001, + 0x81C, 0xA9300001, + 0x81C, 0xA8320001, + 0x81C, 0xA7340001, + 0x81C, 0xA6360001, + 0x81C, 0xA5380001, + 0x81C, 0xA43A0001, + 0x81C, 0x683C0001, + 0x81C, 0x673E0001, + 0x81C, 0x66400001, + 0x81C, 0x65420001, + 0x81C, 0x64440001, + 0x81C, 0x63460001, + 0x81C, 0x62480001, + 0x81C, 0x614A0001, + 0x81C, 0x474C0001, + 0x81C, 0x464E0001, + 0x81C, 0x45500001, + 0x81C, 0x44520001, + 0x81C, 0x43540001, + 0x81C, 0x42560001, + 0x81C, 0x41580001, + 0x81C, 0x285A0001, + 0x81C, 0x275C0001, + 0x81C, 0x265E0001, + 0x81C, 0x25600001, + 0x81C, 0x24620001, + 0x81C, 0x0A640001, + 0x81C, 0x09660001, + 0x81C, 0x08680001, + 0x81C, 0x076A0001, + 0x81C, 0x066C0001, + 0x81C, 0x056E0001, + 0x81C, 0x04700001, + 0x81C, 0x03720001, + 0x81C, 0x02740001, + 0x81C, 0x01760001, + 0x81C, 0x01780001, + 0x81C, 0x017A0001, + 0x81C, 0x017C0001, + 0x81C, 0x017E0001, + 0x8000020c, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000101, + 0x81C, 0xFA020101, + 0x81C, 0xF9040101, + 0x81C, 0xF8060101, + 0x81C, 0xF7080101, + 0x81C, 0xF60A0101, + 0x81C, 0xF50C0101, + 0x81C, 0xF40E0101, + 0x81C, 0xF3100101, + 0x81C, 0xF2120101, + 0x81C, 0xF1140101, + 0x81C, 0xF0160101, + 0x81C, 0xEF180101, + 0x81C, 0xEE1A0101, + 0x81C, 0xED1C0101, + 0x81C, 0xEC1E0101, + 0x81C, 0xEB200101, + 0x81C, 0xEA220101, + 0x81C, 0xE9240101, + 0x81C, 0xE8260101, + 0x81C, 0xE7280101, + 0x81C, 0xE62A0101, + 0x81C, 0xE52C0101, + 0x81C, 0xE42E0101, + 0x81C, 0xE3300101, + 0x81C, 0xA5320101, + 0x81C, 0xA4340101, + 0x81C, 0xA3360101, + 0x81C, 0x87380101, + 0x81C, 0x863A0101, + 0x81C, 0x853C0101, + 0x81C, 0x843E0101, + 0x81C, 0x69400101, + 0x81C, 0x68420101, + 0x81C, 0x67440101, + 0x81C, 0x66460101, + 0x81C, 0x49480101, + 0x81C, 0x484A0101, + 0x81C, 0x474C0101, + 0x81C, 0x2A4E0101, + 0x81C, 0x29500101, + 0x81C, 0x28520101, + 0x81C, 0x27540101, + 0x81C, 0x26560101, + 0x81C, 0x25580101, + 0x81C, 0x245A0101, + 0x81C, 0x235C0101, + 0x81C, 0x055E0101, + 0x81C, 0x04600101, + 0x81C, 0x03620101, + 0x81C, 0x02640101, + 0x81C, 0x01660101, + 0x81C, 0x01680101, + 0x81C, 0x016A0101, + 0x81C, 0x016C0101, + 0x81C, 0x016E0101, + 0x81C, 0x01700101, + 0x81C, 0x01720101, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000101, + 0x81C, 0xFA020101, + 0x81C, 0xF9040101, + 0x81C, 0xF8060101, + 0x81C, 0xF7080101, + 0x81C, 0xF60A0101, + 0x81C, 0xF50C0101, + 0x81C, 0xF40E0101, + 0x81C, 0xF3100101, + 0x81C, 0xF2120101, + 0x81C, 0xF1140101, + 0x81C, 0xF0160101, + 0x81C, 0xEF180101, + 0x81C, 0xEE1A0101, + 0x81C, 0xED1C0101, + 0x81C, 0xEC1E0101, + 0x81C, 0xEB200101, + 0x81C, 0xEA220101, + 0x81C, 0xE9240101, + 0x81C, 0xE8260101, + 0x81C, 0xE7280101, + 0x81C, 0xE62A0101, + 0x81C, 0xE52C0101, + 0x81C, 0xE42E0101, + 0x81C, 0xE3300101, + 0x81C, 0xA5320101, + 0x81C, 0xA4340101, + 0x81C, 0xA3360101, + 0x81C, 0x87380101, + 0x81C, 0x863A0101, + 0x81C, 0x853C0101, + 0x81C, 0x843E0101, + 0x81C, 0x69400101, + 0x81C, 0x68420101, + 0x81C, 0x67440101, + 0x81C, 0x66460101, + 0x81C, 0x49480101, + 0x81C, 0x484A0101, + 0x81C, 0x474C0101, + 0x81C, 0x2A4E0101, + 0x81C, 0x29500101, + 0x81C, 0x28520101, + 0x81C, 0x27540101, + 0x81C, 0x26560101, + 0x81C, 0x25580101, + 0x81C, 0x245A0101, + 0x81C, 0x235C0101, + 0x81C, 0x055E0101, + 0x81C, 0x04600101, + 0x81C, 0x03620101, + 0x81C, 0x02640101, + 0x81C, 0x01660101, + 0x81C, 0x01680101, + 0x81C, 0x016A0101, + 0x81C, 0x016C0101, + 0x81C, 0x016E0101, + 0x81C, 0x01700101, + 0x81C, 0x01720101, + 0xA0000000, 0x00000000, + 0x81C, 0xFF000101, + 0x81C, 0xFF020101, + 0x81C, 0xFE040101, + 0x81C, 0xFD060101, + 0x81C, 0xFC080101, + 0x81C, 0xFD0A0101, + 0x81C, 0xFC0C0101, + 0x81C, 0xFB0E0101, + 0x81C, 0xFA100101, + 0x81C, 0xF9120101, + 0x81C, 0xF8140101, + 0x81C, 0xF7160101, + 0x81C, 0xF6180101, + 0x81C, 0xF51A0101, + 0x81C, 0xF41C0101, + 0x81C, 0xF31E0101, + 0x81C, 0xF2200101, + 0x81C, 0xF1220101, + 0x81C, 0xF0240101, + 0x81C, 0xEF260101, + 0x81C, 0xEE280101, + 0x81C, 0xED2A0101, + 0x81C, 0xEC2C0101, + 0x81C, 0xEB2E0101, + 0x81C, 0xEA300101, + 0x81C, 0xE9320101, + 0x81C, 0xE8340101, + 0x81C, 0xE7360101, + 0x81C, 0xE6380101, + 0x81C, 0xE53A0101, + 0x81C, 0xE43C0101, + 0x81C, 0xE33E0101, + 0x81C, 0xA5400101, + 0x81C, 0xA4420101, + 0x81C, 0xA3440101, + 0x81C, 0x87460101, + 0x81C, 0x86480101, + 0x81C, 0x854A0101, + 0x81C, 0x844C0101, + 0x81C, 0x694E0101, + 0x81C, 0x68500101, + 0x81C, 0x67520101, + 0x81C, 0x66540101, + 0x81C, 0x49560101, + 0x81C, 0x48580101, + 0x81C, 0x475A0101, + 0x81C, 0x2A5C0101, + 0x81C, 0x295E0101, + 0x81C, 0x28600101, + 0x81C, 0x27620101, + 0x81C, 0x26640101, + 0x81C, 0x25660101, + 0x81C, 0x24680101, + 0x81C, 0x236A0101, + 0x81C, 0x056C0101, + 0x81C, 0x046E0101, + 0x81C, 0x03700101, + 0x81C, 0x02720101, + 0xB0000000, 0x00000000, + 0x81C, 0x01740101, + 0x81C, 0x01760101, + 0x81C, 0x01780101, + 0x81C, 0x017A0101, + 0x81C, 0x017C0101, + 0x81C, 0x017E0101, + 0xC50, 0x00000022, + 0xC50, 0x00000020, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821a_agc, rtw_phy_cfg_agc); + +static const u32 rtw8821a_bb[] = { + 0x800, 0x0020D090, + 0x804, 0x080112E0, + 0x808, 0x0E028211, + 0x80C, 0x92131111, + 0x810, 0x20101261, + 0x814, 0x020C3D10, + 0x818, 0x03A00385, + 0x820, 0x00000000, + 0x824, 0x00030FE0, + 0x828, 0x00000000, + 0x82C, 0x002081DD, + 0x830, 0x2AAAEEC8, + 0x834, 0x0037A706, + 0x838, 0x06489B44, + 0x83C, 0x0000095B, + 0x840, 0xC0000001, + 0x844, 0x40003CDE, + 0x848, 0x62103F8B, + 0x84C, 0x6CFDFFB8, + 0x850, 0x28874706, + 0x854, 0x0001520C, + 0x858, 0x8060E000, + 0x85C, 0x74210168, + 0x860, 0x6929C321, + 0x864, 0x79727432, + 0x868, 0x8CA7A314, + 0x86C, 0x888C2878, + 0x870, 0x08888888, + 0x874, 0x31612C2E, + 0x878, 0x00000152, + 0x87C, 0x000FD000, + 0x8A0, 0x00000013, + 0x8A4, 0x7F7F7F7F, + 0x8A8, 0xA2000338, + 0x8AC, 0x0FF0FA0A, + 0x8B4, 0x000FC080, + 0x8B8, 0x6C10D7FF, + 0x8BC, 0x0CA52090, + 0x8C0, 0x1BF00020, + 0x8C4, 0x00000000, + 0x8C8, 0x00013169, + 0x8CC, 0x08248492, + 0x8D4, 0x940008A0, + 0x8D8, 0x290B5612, + 0x8F8, 0x400002C0, + 0x8FC, 0x00000000, + 0x900, 0x00000700, + 0x90C, 0x00000000, + 0x910, 0x0000FC00, + 0x914, 0x00000404, + 0x918, 0x1C1028C0, + 0x91C, 0x64B11A1C, + 0x920, 0xE0767233, + 0x924, 0x055AA500, + 0x928, 0x00000004, + 0x92C, 0xFFFE0000, + 0x930, 0xFFFFFFFE, + 0x934, 0x001FFFFF, + 0x960, 0x00000000, + 0x964, 0x00000000, + 0x968, 0x00000000, + 0x96C, 0x00000000, + 0x970, 0x801FFFFF, + 0x974, 0x000003FF, + 0x978, 0x00000000, + 0x97C, 0x00000000, + 0x980, 0x00000000, + 0x984, 0x00000000, + 0x988, 0x00000000, + 0x990, 0x27100000, + 0x994, 0xFFFF0100, + 0x998, 0xFFFFFF5C, + 0x99C, 0xFFFFFFFF, + 0x9A0, 0x000000FF, + 0x9A4, 0x00480080, + 0x9A8, 0x00000000, + 0x9AC, 0x00000000, + 0x9B0, 0x81081008, + 0x9B4, 0x01081008, + 0x9B8, 0x01081008, + 0x9BC, 0x01081008, + 0x9D0, 0x00000000, + 0x9D4, 0x00000000, + 0x9D8, 0x00000000, + 0x9DC, 0x00000000, + 0x9E0, 0x00005D00, + 0x9E4, 0x00000003, + 0x9E8, 0x00000001, + 0xA00, 0x00D047C8, + 0xA04, 0x01FF800C, + 0xA08, 0x8C8A8300, + 0xA0C, 0x2E68000F, + 0xA10, 0x9500BB78, + 0xA14, 0x11144028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1317, + 0xA28, 0x00000204, + 0xA2C, 0x00900000, + 0xA70, 0x101FFF00, + 0xA74, 0x00000008, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x21805490, + 0xA84, 0x001F0000, + 0XB00, 0x03100040, + 0XB04, 0x0000B000, + 0XB08, 0xAE0201EB, + 0XB0C, 0x01003207, + 0XB10, 0x00009807, + 0XB14, 0x01000000, + 0XB18, 0x00000002, + 0XB1C, 0x00000002, + 0XB20, 0x0000001F, + 0XB24, 0x03020100, + 0XB28, 0x07060504, + 0XB2C, 0x0B0A0908, + 0XB30, 0x0F0E0D0C, + 0XB34, 0x13121110, + 0XB38, 0x17161514, + 0XB3C, 0x0000003A, + 0XB40, 0x00000000, + 0XB44, 0x00000000, + 0XB48, 0x13000032, + 0XB4C, 0x48080000, + 0XB50, 0x00000000, + 0XB54, 0x00000000, + 0XB58, 0x00000000, + 0XB5C, 0x00000000, + 0xC00, 0x00000007, + 0xC04, 0x00042020, + 0xC08, 0x80410231, + 0xC0C, 0x00000000, + 0xC10, 0x00000100, + 0xC14, 0x01000000, + 0xC1C, 0x40000003, + 0xC20, 0x2C2C2C2C, + 0xC24, 0x30303030, + 0xC28, 0x30303030, + 0xC2C, 0x2C2C2C2C, + 0xC30, 0x2C2C2C2C, + 0xC34, 0x2C2C2C2C, + 0xC38, 0x2C2C2C2C, + 0xC3C, 0x2A2A2A2A, + 0xC40, 0x2A2A2A2A, + 0xC44, 0x2A2A2A2A, + 0xC48, 0x2A2A2A2A, + 0xC4C, 0x2A2A2A2A, + 0xC50, 0x00000020, + 0xC54, 0x001C1208, + 0xC58, 0x30000C1C, + 0xC5C, 0x00000058, + 0xC60, 0x34344443, + 0xC64, 0x07003333, + 0xC68, 0x19791979, + 0xC6C, 0x19791979, + 0xC70, 0x19791979, + 0xC74, 0x19791979, + 0xC78, 0x19791979, + 0xC7C, 0x19791979, + 0xC80, 0x19791979, + 0xC84, 0x19791979, + 0xC94, 0x0100005C, + 0xC98, 0x00000000, + 0xC9C, 0x00000000, + 0xCA0, 0x00000029, + 0xCA4, 0x08040201, + 0xCA8, 0x80402010, + 0xCB0, 0x77775747, + 0xCB4, 0x10000077, + 0xCB8, 0x00508240, +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821a_bb, rtw_phy_cfg_bb); + +static const struct rtw_phy_pg_cfg_pair rtw8821a_bb_pg[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36363838, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363838, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 0, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x34343636, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343636, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343636, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0x0000ffff, 0x00002022, }, +}; + +RTW_DECL_TABLE_BB_PG(rtw8821a_bb_pg); + +static const u32 rtw8821a_rf_a[] = { + 0x018, 0x0001712A, + 0x056, 0x00051CF2, + 0x066, 0x00040000, + 0x000, 0x00010000, + 0x01E, 0x00080000, + 0x082, 0x00000830, + 0x083, 0x00021800, + 0x084, 0x00028000, + 0x085, 0x00048000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x086, 0x0009483A, + 0xA0000000, 0x00000000, + 0x086, 0x00094838, + 0xB0000000, 0x00000000, + 0x087, 0x00044980, + 0x088, 0x00048000, + 0x089, 0x0000D480, + 0x08A, 0x00042240, + 0x08B, 0x000F0380, + 0x08C, 0x00090000, + 0x08D, 0x00022852, + 0x08E, 0x00065540, + 0x08F, 0x00088001, + 0x0EF, 0x00020000, + 0x03E, 0x00000380, + 0x03F, 0x00090018, + 0x03E, 0x00020380, + 0x03F, 0x000A0018, + 0x03E, 0x00040308, + 0x03F, 0x000A0018, + 0x03E, 0x00060018, + 0x03F, 0x000A0018, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x089, 0x00000080, + 0x08B, 0x00080180, + 0x0EF, 0x00001000, + 0x03A, 0x00000244, + 0x03B, 0x00038027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x00030113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x00028027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x00027027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0001F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00017F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00008027, + 0x03C, 0x000CA000, + 0x03A, 0x00000244, + 0x03B, 0x00078027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x00070113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x00068027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x00067027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0005F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00057F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00048027, + 0x03C, 0x000CA000, + 0x03A, 0x00000244, + 0x03B, 0x000B8027, + 0x03C, 0x00082000, + 0x03A, 0x00000244, + 0x03B, 0x000B0113, + 0x03C, 0x00082000, + 0x03A, 0x0000014C, + 0x03B, 0x000A8027, + 0x03C, 0x00082000, + 0x03A, 0x000000CC, + 0x03B, 0x000A7027, + 0x03C, 0x00042000, + 0x03A, 0x0000014C, + 0x03B, 0x0009F913, + 0x03C, 0x00042000, + 0x03A, 0x0000010C, + 0x03B, 0x00097F10, + 0x03C, 0x00012000, + 0x03A, 0x000000D0, + 0x03B, 0x00088027, + 0x03C, 0x000CA000, + 0x0EF, 0x00000000, + 0x0EF, 0x00001100, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0F3, + 0x034, 0x000490B1, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0F3, + 0x034, 0x000490B1, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, + 0xA0000000, 0x00000000, + 0x034, 0x0004ADF7, + 0x034, 0x00049DF3, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000480AE, + 0x034, 0x000470AB, + 0x034, 0x0004608B, + 0x034, 0x00045069, + 0x034, 0x00044048, + 0x034, 0x00043045, + 0x034, 0x00042026, + 0x034, 0x00041023, + 0x034, 0x00040002, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000480AE, + 0x034, 0x000470AB, + 0x034, 0x0004608B, + 0x034, 0x00045069, + 0x034, 0x00044048, + 0x034, 0x00043045, + 0x034, 0x00042026, + 0x034, 0x00041023, + 0x034, 0x00040002, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, + 0x034, 0x00045CE9, + 0x034, 0x00044CE6, + 0x034, 0x000438C6, + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, + 0xA0000000, 0x00000000, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, + 0x034, 0x00045CCB, + 0x034, 0x0004488D, + 0x034, 0x0004348D, + 0x034, 0x0004248A, + 0x034, 0x0004108D, + 0x034, 0x0004008A, + 0xB0000000, 0x00000000, + 0x80000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002ADF4, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0F3, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0F3, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002ADF4, + 0xA0000000, 0x00000000, + 0x034, 0x0002ADF7, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF4, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF4, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF1, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000290F0, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000290F0, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF1, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF4, + 0xA0000000, 0x00000000, + 0x034, 0x00029DF2, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000280AF, + 0x034, 0x000270AC, + 0x034, 0x0002608B, + 0x034, 0x00025069, + 0x034, 0x00024048, + 0x034, 0x00023045, + 0x034, 0x00022026, + 0x034, 0x00021023, + 0x034, 0x00020002, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000280AF, + 0x034, 0x000270AC, + 0x034, 0x0002608B, + 0x034, 0x00025069, + 0x034, 0x00024048, + 0x034, 0x00023045, + 0x034, 0x00022026, + 0x034, 0x00021023, + 0x034, 0x00020002, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, + 0x034, 0x00025CEC, + 0x034, 0x00024CE9, + 0x034, 0x000238CA, + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, + 0xA0000000, 0x00000000, + 0x034, 0x00028DEE, + 0x034, 0x00027DEB, + 0x034, 0x00026CCD, + 0x034, 0x00025CCA, + 0x034, 0x0002488C, + 0x034, 0x0002384C, + 0x034, 0x00022849, + 0x034, 0x00021449, + 0x034, 0x0002004D, + 0xB0000000, 0x00000000, + 0x8000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0D7, + 0x034, 0x000090D3, + 0x034, 0x000080B1, + 0x034, 0x000070AE, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0D7, + 0x034, 0x000090D3, + 0x034, 0x000080B1, + 0x034, 0x000070AE, + 0xA0000000, 0x00000000, + 0x034, 0x0000ADF7, + 0x034, 0x00009DF4, + 0x034, 0x00008DF1, + 0x034, 0x00007DEE, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000608D, + 0x034, 0x0000506B, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x00002044, + 0x034, 0x00001025, + 0x034, 0x00000004, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000608D, + 0x034, 0x0000506B, + 0x034, 0x0000404A, + 0x034, 0x00003047, + 0x034, 0x00002044, + 0x034, 0x00001025, + 0x034, 0x00000004, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, + 0x034, 0x000038CA, + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, + 0xA0000000, 0x00000000, + 0x034, 0x00006DCD, + 0x034, 0x00005CCD, + 0x034, 0x00004CCA, + 0x034, 0x0000388C, + 0x034, 0x00002888, + 0x034, 0x00001488, + 0x034, 0x00000486, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000128, + 0x035, 0x00008128, + 0x035, 0x00010128, + 0x035, 0x000201C8, + 0x035, 0x000281C8, + 0x035, 0x000301C8, + 0x035, 0x000401C8, + 0x035, 0x000481C8, + 0x035, 0x000501C8, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000145, + 0x035, 0x00008145, + 0x035, 0x00010145, + 0x035, 0x00020196, + 0x035, 0x00028196, + 0x035, 0x00030196, + 0x035, 0x000401C7, + 0x035, 0x000481C7, + 0x035, 0x000501C7, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000128, + 0x035, 0x00008128, + 0x035, 0x00010128, + 0x035, 0x000201C8, + 0x035, 0x000281C8, + 0x035, 0x000301C8, + 0x035, 0x000401C8, + 0x035, 0x000481C8, + 0x035, 0x000501C8, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, + 0x035, 0x00020188, + 0x035, 0x00028188, + 0x035, 0x00030188, + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, + 0xA0000000, 0x00000000, + 0x035, 0x00000145, + 0x035, 0x00008145, + 0x035, 0x00010145, + 0x035, 0x00020196, + 0x035, 0x00028196, + 0x035, 0x00030196, + 0x035, 0x000401C7, + 0x035, 0x000481C7, + 0x035, 0x000501C7, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x000063B5, + 0x036, 0x0000E3B5, + 0x036, 0x000163B5, + 0x036, 0x0001E3B5, + 0x036, 0x000263B5, + 0x036, 0x0002E3B5, + 0x036, 0x000363B5, + 0x036, 0x0003E3B5, + 0x036, 0x000463B5, + 0x036, 0x0004E3B5, + 0x036, 0x000563B5, + 0x036, 0x0005E3B5, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x000056B3, + 0x036, 0x0000D6B3, + 0x036, 0x000156B3, + 0x036, 0x0001D6B3, + 0x036, 0x00026634, + 0x036, 0x0002E634, + 0x036, 0x00036634, + 0x036, 0x0003E634, + 0x036, 0x000467B4, + 0x036, 0x0004E7B4, + 0x036, 0x000567B4, + 0x036, 0x0005E7B4, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x000063B5, + 0x036, 0x0000E3B5, + 0x036, 0x000163B5, + 0x036, 0x0001E3B5, + 0x036, 0x000263B5, + 0x036, 0x0002E3B5, + 0x036, 0x000363B5, + 0x036, 0x0003E3B5, + 0x036, 0x000463B5, + 0x036, 0x0004E3B5, + 0x036, 0x000563B5, + 0x036, 0x0005E3B5, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, + 0x036, 0x0009D733, + 0x036, 0x000A64B4, + 0x036, 0x000AE4B4, + 0x036, 0x000B64B4, + 0x036, 0x000BE4B4, + 0x036, 0x000C64B4, + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, + 0xA0000000, 0x00000000, + 0x036, 0x000056B3, + 0x036, 0x0000D6B3, + 0x036, 0x000156B3, + 0x036, 0x0001D6B3, + 0x036, 0x00026634, + 0x036, 0x0002E634, + 0x036, 0x00036634, + 0x036, 0x0003E634, + 0x036, 0x000467B4, + 0x036, 0x0004E7B4, + 0x036, 0x000567B4, + 0x036, 0x0005E7B4, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001B6, + 0x03C, 0x00000492, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x0000022A, + 0x03C, 0x00000594, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001B6, + 0x03C, 0x00000492, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, + 0xA0000000, 0x00000000, + 0x03C, 0x0000022A, + 0x03C, 0x00000594, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000820, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000820, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, + 0xA0000000, 0x00000000, + 0x03C, 0x00000900, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x00002000, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x00002000, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x00002000, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x00002000, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, + 0xA0000000, 0x00000000, + 0x008, 0x00002000, + 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0DF, 0x000000C0, + 0x01F, 0x00000064, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, + 0xA0000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EFD83, + 0x062, 0x00093FCC, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EAD53, + 0x062, 0x00093BC4, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000EFD83, + 0x062, 0x00093FCC, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, + 0xA0000000, 0x00000000, + 0x061, 0x000EAD53, + 0x062, 0x00093BC4, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110EB, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110EB, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, + 0xA0000000, 0x00000000, + 0x063, 0x000714E9, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C67C, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, + 0xA0000000, 0x00000000, + 0x064, 0x0001C67C, + 0xB0000000, 0x00000000, + 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00091016, + 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00091016, + 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093016, + 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093015, + 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093015, + 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093016, + 0xA0000000, 0x00000000, + 0x065, 0x00091016, + 0xB0000000, 0x00000000, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0x03B, 0x0003824B, + 0x03B, 0x0003024B, + 0x03B, 0x0002844B, + 0x03B, 0x00020F4B, + 0x03B, 0x00018F4B, + 0x03B, 0x000104B2, + 0x03B, 0x00008049, + 0x03B, 0x00000148, + 0x03B, 0x0007824B, + 0x03B, 0x0007024B, + 0x03B, 0x0006824B, + 0x03B, 0x00060F4B, + 0x03B, 0x00058F4B, + 0x03B, 0x000504B2, + 0x03B, 0x00048049, + 0x03B, 0x00040148, + 0x0EF, 0x00000000, + 0x0EF, 0x00000100, + 0x034, 0x0000ADF3, + 0x034, 0x00009DF0, + 0x034, 0x00008D70, + 0x034, 0x00007D6D, + 0x034, 0x00006CEE, + 0x034, 0x00005CCC, + 0x034, 0x000044EC, + 0x034, 0x000034AC, + 0x034, 0x0000246D, + 0x034, 0x0000106F, + 0x034, 0x0000006C, + 0x0EF, 0x00000000, + 0x0ED, 0x00000010, + 0x044, 0x0000ADF2, + 0x044, 0x00009DEF, + 0x044, 0x00008DEC, + 0x044, 0x00007DE9, + 0x044, 0x00006CEC, + 0x044, 0x00005CE9, + 0x044, 0x000044EC, + 0x044, 0x000034E9, + 0x044, 0x0000246C, + 0x044, 0x00001469, + 0x044, 0x0000006C, + 0x0ED, 0x00000000, + 0x0ED, 0x00000001, + 0x040, 0x00038DA7, + 0x040, 0x000300C2, + 0x040, 0x000288E2, + 0x040, 0x000200B8, + 0x040, 0x000188A5, + 0x040, 0x00010FBC, + 0x040, 0x00008F71, + 0x040, 0x00000240, + 0x0ED, 0x00000000, + 0x0EF, 0x000020A2, + 0x0DF, 0x00000080, + 0x035, 0x00000120, + 0x035, 0x00008120, + 0x035, 0x00010120, + 0x036, 0x00000085, + 0x036, 0x00008085, + 0x036, 0x00010085, + 0x036, 0x00018085, + 0x0EF, 0x00000000, + 0x051, 0x00000C31, + 0x052, 0x00000622, + 0x053, 0x000FC70B, + 0x054, 0x0000017E, + 0x056, 0x00051DF3, + 0x051, 0x00000C01, + 0x052, 0x000006D6, + 0x053, 0x000FC649, + 0x070, 0x00049661, + 0x071, 0x0007843E, + 0x072, 0x00000382, + 0x074, 0x00051400, + 0x035, 0x00000160, + 0x035, 0x00008160, + 0x035, 0x00010160, + 0x036, 0x00000124, + 0x036, 0x00008124, + 0x036, 0x00010124, + 0x036, 0x00018124, + 0x0ED, 0x0000000C, + 0x045, 0x00000140, + 0x045, 0x00008140, + 0x045, 0x00010140, + 0x046, 0x00000124, + 0x046, 0x00008124, + 0x046, 0x00010124, + 0x046, 0x00018124, + 0x0DF, 0x00000088, + 0x0B3, 0x000F0E18, + 0x0B4, 0x0001214C, + 0x0B7, 0x0003000C, + 0x01C, 0x000539D2, + 0x0C4, 0x000AFE00, + 0x018, 0x0001F12A, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x018, 0x0001712A, +}; + +RTW_DECL_TABLE_RF_RADIO(rtw8821a_rf_a, A); + +static const struct rtw_txpwr_lmt_cfg_pair rtw8821a_txpwr_lmt[] = { + { 0, 0, 0, 0, 1, 32, }, + { 2, 0, 0, 0, 1, 28, }, + { 1, 0, 0, 0, 1, 32, }, + { 0, 0, 0, 0, 2, 32, }, + { 2, 0, 0, 0, 2, 28, }, + { 1, 0, 0, 0, 2, 32, }, + { 0, 0, 0, 0, 3, 36, }, + { 2, 0, 0, 0, 3, 28, }, + { 1, 0, 0, 0, 3, 32, }, + { 0, 0, 0, 0, 4, 36, }, + { 2, 0, 0, 0, 4, 28, }, + { 1, 0, 0, 0, 4, 32, }, + { 0, 0, 0, 0, 5, 36, }, + { 2, 0, 0, 0, 5, 28, }, + { 1, 0, 0, 0, 5, 32, }, + { 0, 0, 0, 0, 6, 36, }, + { 2, 0, 0, 0, 6, 28, }, + { 1, 0, 0, 0, 6, 32, }, + { 0, 0, 0, 0, 7, 36, }, + { 2, 0, 0, 0, 7, 28, }, + { 1, 0, 0, 0, 7, 32, }, + { 0, 0, 0, 0, 8, 36, }, + { 2, 0, 0, 0, 8, 28, }, + { 1, 0, 0, 0, 8, 32, }, + { 0, 0, 0, 0, 9, 32, }, + { 2, 0, 0, 0, 9, 28, }, + { 1, 0, 0, 0, 9, 32, }, + { 0, 0, 0, 0, 10, 32, }, + { 2, 0, 0, 0, 10, 28, }, + { 1, 0, 0, 0, 10, 32, }, + { 0, 0, 0, 0, 11, 32, }, + { 2, 0, 0, 0, 11, 28, }, + { 1, 0, 0, 0, 11, 32, }, + { 0, 0, 0, 0, 12, 28, }, + { 2, 0, 0, 0, 12, 28, }, + { 1, 0, 0, 0, 12, 32, }, + { 0, 0, 0, 0, 13, 26, }, + { 2, 0, 0, 0, 13, 28, }, + { 1, 0, 0, 0, 13, 32, }, + { 0, 0, 0, 0, 14, 63, }, + { 2, 0, 0, 0, 14, 63, }, + { 1, 0, 0, 0, 14, 32, }, + { 0, 0, 0, 1, 1, 30, }, + { 2, 0, 0, 1, 1, 30, }, + { 1, 0, 0, 1, 1, 32, }, + { 0, 0, 0, 1, 2, 30, }, + { 2, 0, 0, 1, 2, 32, }, + { 1, 0, 0, 1, 2, 32, }, + { 0, 0, 0, 1, 3, 32, }, + { 2, 0, 0, 1, 3, 32, }, + { 1, 0, 0, 1, 3, 32, }, + { 0, 0, 0, 1, 4, 32, }, + { 2, 0, 0, 1, 4, 32, }, + { 1, 0, 0, 1, 4, 32, }, + { 0, 0, 0, 1, 5, 32, }, + { 2, 0, 0, 1, 5, 32, }, + { 1, 0, 0, 1, 5, 32, }, + { 0, 0, 0, 1, 6, 32, }, + { 2, 0, 0, 1, 6, 32, }, + { 1, 0, 0, 1, 6, 32, }, + { 0, 0, 0, 1, 7, 32, }, + { 2, 0, 0, 1, 7, 32, }, + { 1, 0, 0, 1, 7, 32, }, + { 0, 0, 0, 1, 8, 32, }, + { 2, 0, 0, 1, 8, 32, }, + { 1, 0, 0, 1, 8, 32, }, + { 0, 0, 0, 1, 9, 30, }, + { 2, 0, 0, 1, 9, 32, }, + { 1, 0, 0, 1, 9, 32, }, + { 0, 0, 0, 1, 10, 30, }, + { 2, 0, 0, 1, 10, 32, }, + { 1, 0, 0, 1, 10, 32, }, + { 0, 0, 0, 1, 11, 30, }, + { 2, 0, 0, 1, 11, 32, }, + { 1, 0, 0, 1, 11, 32, }, + { 0, 0, 0, 1, 12, 26, }, + { 2, 0, 0, 1, 12, 32, }, + { 1, 0, 0, 1, 12, 32, }, + { 0, 0, 0, 1, 13, 24, }, + { 2, 0, 0, 1, 13, 30, }, + { 1, 0, 0, 1, 13, 32, }, + { 0, 0, 0, 1, 14, 63, }, + { 2, 0, 0, 1, 14, 63, }, + { 1, 0, 0, 1, 14, 63, }, + { 0, 0, 0, 2, 1, 26, }, + { 2, 0, 0, 2, 1, 26, }, + { 1, 0, 0, 2, 1, 32, }, + { 0, 0, 0, 2, 2, 26, }, + { 2, 0, 0, 2, 2, 32, }, + { 1, 0, 0, 2, 2, 32, }, + { 0, 0, 0, 2, 3, 32, }, + { 2, 0, 0, 2, 3, 32, }, + { 1, 0, 0, 2, 3, 32, }, + { 0, 0, 0, 2, 4, 32, }, + { 2, 0, 0, 2, 4, 32, }, + { 1, 0, 0, 2, 4, 32, }, + { 0, 0, 0, 2, 5, 32, }, + { 2, 0, 0, 2, 5, 32, }, + { 1, 0, 0, 2, 5, 32, }, + { 0, 0, 0, 2, 6, 32, }, + { 2, 0, 0, 2, 6, 32, }, + { 1, 0, 0, 2, 6, 32, }, + { 0, 0, 0, 2, 7, 32, }, + { 2, 0, 0, 2, 7, 32, }, + { 1, 0, 0, 2, 7, 32, }, + { 0, 0, 0, 2, 8, 32, }, + { 2, 0, 0, 2, 8, 32, }, + { 1, 0, 0, 2, 8, 32, }, + { 0, 0, 0, 2, 9, 26, }, + { 2, 0, 0, 2, 9, 32, }, + { 1, 0, 0, 2, 9, 32, }, + { 0, 0, 0, 2, 10, 26, }, + { 2, 0, 0, 2, 10, 32, }, + { 1, 0, 0, 2, 10, 32, }, + { 0, 0, 0, 2, 11, 26, }, + { 2, 0, 0, 2, 11, 32, }, + { 1, 0, 0, 2, 11, 32, }, + { 0, 0, 0, 2, 12, 26, }, + { 2, 0, 0, 2, 12, 32, }, + { 1, 0, 0, 2, 12, 32, }, + { 0, 0, 0, 2, 13, 24, }, + { 2, 0, 0, 2, 13, 26, }, + { 1, 0, 0, 2, 13, 32, }, + { 0, 0, 0, 2, 14, 63, }, + { 2, 0, 0, 2, 14, 63, }, + { 1, 0, 0, 2, 14, 63, }, + { 0, 0, 0, 3, 1, 30, }, + { 2, 0, 0, 3, 1, 32, }, + { 1, 0, 0, 3, 1, 32, }, + { 0, 0, 0, 3, 2, 32, }, + { 2, 0, 0, 3, 2, 32, }, + { 1, 0, 0, 3, 2, 32, }, + { 0, 0, 0, 3, 3, 32, }, + { 2, 0, 0, 3, 3, 32, }, + { 1, 0, 0, 3, 3, 32, }, + { 0, 0, 0, 3, 4, 32, }, + { 2, 0, 0, 3, 4, 32, }, + { 1, 0, 0, 3, 4, 32, }, + { 0, 0, 0, 3, 5, 32, }, + { 2, 0, 0, 3, 5, 32, }, + { 1, 0, 0, 3, 5, 32, }, + { 0, 0, 0, 3, 6, 32, }, + { 2, 0, 0, 3, 6, 32, }, + { 1, 0, 0, 3, 6, 32, }, + { 0, 0, 0, 3, 7, 32, }, + { 2, 0, 0, 3, 7, 32, }, + { 1, 0, 0, 3, 7, 32, }, + { 0, 0, 0, 3, 8, 32, }, + { 2, 0, 0, 3, 8, 32, }, + { 1, 0, 0, 3, 8, 32, }, + { 0, 0, 0, 3, 9, 32, }, + { 2, 0, 0, 3, 9, 32, }, + { 1, 0, 0, 3, 9, 32, }, + { 0, 0, 0, 3, 10, 32, }, + { 2, 0, 0, 3, 10, 32, }, + { 1, 0, 0, 3, 10, 32, }, + { 0, 0, 0, 3, 11, 30, }, + { 2, 0, 0, 3, 11, 32, }, + { 1, 0, 0, 3, 11, 32, }, + { 0, 0, 0, 3, 12, 63, }, + { 2, 0, 0, 3, 12, 32, }, + { 1, 0, 0, 3, 12, 32, }, + { 0, 0, 0, 3, 13, 63, }, + { 2, 0, 0, 3, 13, 32, }, + { 1, 0, 0, 3, 13, 32, }, + { 0, 0, 0, 3, 14, 63, }, + { 2, 0, 0, 3, 14, 63, }, + { 1, 0, 0, 3, 14, 63, }, + { 0, 0, 1, 2, 1, 63, }, + { 2, 0, 1, 2, 1, 63, }, + { 1, 0, 1, 2, 1, 63, }, + { 0, 0, 1, 2, 2, 63, }, + { 2, 0, 1, 2, 2, 63, }, + { 1, 0, 1, 2, 2, 63, }, + { 0, 0, 1, 2, 3, 26, }, + { 2, 0, 1, 2, 3, 26, }, + { 1, 0, 1, 2, 3, 32, }, + { 0, 0, 1, 2, 4, 26, }, + { 2, 0, 1, 2, 4, 32, }, + { 1, 0, 1, 2, 4, 32, }, + { 0, 0, 1, 2, 5, 26, }, + { 2, 0, 1, 2, 5, 32, }, + { 1, 0, 1, 2, 5, 32, }, + { 0, 0, 1, 2, 6, 32, }, + { 2, 0, 1, 2, 6, 32, }, + { 1, 0, 1, 2, 6, 32, }, + { 0, 0, 1, 2, 7, 32, }, + { 2, 0, 1, 2, 7, 32, }, + { 1, 0, 1, 2, 7, 32, }, + { 0, 0, 1, 2, 8, 32, }, + { 2, 0, 1, 2, 8, 32, }, + { 1, 0, 1, 2, 8, 32, }, + { 0, 0, 1, 2, 9, 26, }, + { 2, 0, 1, 2, 9, 32, }, + { 1, 0, 1, 2, 9, 32, }, + { 0, 0, 1, 2, 10, 24, }, + { 2, 0, 1, 2, 10, 32, }, + { 1, 0, 1, 2, 10, 32, }, + { 0, 0, 1, 2, 11, 22, }, + { 2, 0, 1, 2, 11, 26, }, + { 1, 0, 1, 2, 11, 32, }, + { 0, 0, 1, 2, 12, 63, }, + { 2, 0, 1, 2, 12, 63, }, + { 1, 0, 1, 2, 12, 63, }, + { 0, 0, 1, 2, 13, 63, }, + { 2, 0, 1, 2, 13, 63, }, + { 1, 0, 1, 2, 13, 63, }, + { 0, 0, 1, 2, 14, 63, }, + { 2, 0, 1, 2, 14, 63, }, + { 1, 0, 1, 2, 14, 63, }, + { 0, 0, 1, 3, 1, 63, }, + { 2, 0, 1, 3, 1, 63, }, + { 1, 0, 1, 3, 1, 63, }, + { 0, 0, 1, 3, 2, 63, }, + { 2, 0, 1, 3, 2, 63, }, + { 1, 0, 1, 3, 2, 63, }, + { 0, 0, 1, 3, 3, 30, }, + { 2, 0, 1, 3, 3, 30, }, + { 1, 0, 1, 3, 3, 30, }, + { 0, 0, 1, 3, 4, 32, }, + { 2, 0, 1, 3, 4, 30, }, + { 1, 0, 1, 3, 4, 30, }, + { 0, 0, 1, 3, 5, 32, }, + { 2, 0, 1, 3, 5, 30, }, + { 1, 0, 1, 3, 5, 30, }, + { 0, 0, 1, 3, 6, 32, }, + { 2, 0, 1, 3, 6, 30, }, + { 1, 0, 1, 3, 6, 30, }, + { 0, 0, 1, 3, 7, 32, }, + { 2, 0, 1, 3, 7, 30, }, + { 1, 0, 1, 3, 7, 30, }, + { 0, 0, 1, 3, 8, 32, }, + { 2, 0, 1, 3, 8, 30, }, + { 1, 0, 1, 3, 8, 30, }, + { 0, 0, 1, 3, 9, 32, }, + { 2, 0, 1, 3, 9, 30, }, + { 1, 0, 1, 3, 9, 30, }, + { 0, 0, 1, 3, 10, 32, }, + { 2, 0, 1, 3, 10, 30, }, + { 1, 0, 1, 3, 10, 30, }, + { 0, 0, 1, 3, 11, 30, }, + { 2, 0, 1, 3, 11, 30, }, + { 1, 0, 1, 3, 11, 30, }, + { 0, 0, 1, 3, 12, 63, }, + { 2, 0, 1, 3, 12, 32, }, + { 1, 0, 1, 3, 12, 32, }, + { 0, 0, 1, 3, 13, 63, }, + { 2, 0, 1, 3, 13, 32, }, + { 1, 0, 1, 3, 13, 32, }, + { 0, 0, 1, 3, 14, 63, }, + { 2, 0, 1, 3, 14, 63, }, + { 1, 0, 1, 3, 14, 63, }, + { 0, 1, 0, 1, 36, 32, }, + { 2, 1, 0, 1, 36, 30, }, + { 1, 1, 0, 1, 36, 30, }, + { 0, 1, 0, 1, 40, 32, }, + { 2, 1, 0, 1, 40, 30, }, + { 1, 1, 0, 1, 40, 30, }, + { 0, 1, 0, 1, 44, 32, }, + { 2, 1, 0, 1, 44, 30, }, + { 1, 1, 0, 1, 44, 30, }, + { 0, 1, 0, 1, 48, 32, }, + { 2, 1, 0, 1, 48, 30, }, + { 1, 1, 0, 1, 48, 30, }, + { 0, 1, 0, 1, 52, 32, }, + { 2, 1, 0, 1, 52, 30, }, + { 1, 1, 0, 1, 52, 30, }, + { 0, 1, 0, 1, 56, 32, }, + { 2, 1, 0, 1, 56, 30, }, + { 1, 1, 0, 1, 56, 30, }, + { 0, 1, 0, 1, 60, 32, }, + { 2, 1, 0, 1, 60, 30, }, + { 1, 1, 0, 1, 60, 30, }, + { 0, 1, 0, 1, 64, 32, }, + { 2, 1, 0, 1, 64, 30, }, + { 1, 1, 0, 1, 64, 30, }, + { 0, 1, 0, 1, 100, 32, }, + { 2, 1, 0, 1, 100, 30, }, + { 1, 1, 0, 1, 100, 30, }, + { 0, 1, 0, 1, 104, 32, }, + { 2, 1, 0, 1, 104, 30, }, + { 1, 1, 0, 1, 104, 30, }, + { 0, 1, 0, 1, 108, 32, }, + { 2, 1, 0, 1, 108, 30, }, + { 1, 1, 0, 1, 108, 30, }, + { 0, 1, 0, 1, 112, 32, }, + { 2, 1, 0, 1, 112, 30, }, + { 1, 1, 0, 1, 112, 30, }, + { 0, 1, 0, 1, 116, 32, }, + { 2, 1, 0, 1, 116, 30, }, + { 1, 1, 0, 1, 116, 30, }, + { 0, 1, 0, 1, 120, 32, }, + { 2, 1, 0, 1, 120, 30, }, + { 1, 1, 0, 1, 120, 30, }, + { 0, 1, 0, 1, 124, 32, }, + { 2, 1, 0, 1, 124, 30, }, + { 1, 1, 0, 1, 124, 30, }, + { 0, 1, 0, 1, 128, 32, }, + { 2, 1, 0, 1, 128, 30, }, + { 1, 1, 0, 1, 128, 30, }, + { 0, 1, 0, 1, 132, 32, }, + { 2, 1, 0, 1, 132, 30, }, + { 1, 1, 0, 1, 132, 30, }, + { 0, 1, 0, 1, 136, 32, }, + { 2, 1, 0, 1, 136, 30, }, + { 1, 1, 0, 1, 136, 30, }, + { 0, 1, 0, 1, 140, 32, }, + { 2, 1, 0, 1, 140, 30, }, + { 1, 1, 0, 1, 140, 30, }, + { 0, 1, 0, 1, 149, 32, }, + { 2, 1, 0, 1, 149, 30, }, + { 1, 1, 0, 1, 149, 63, }, + { 0, 1, 0, 1, 153, 32, }, + { 2, 1, 0, 1, 153, 30, }, + { 1, 1, 0, 1, 153, 63, }, + { 0, 1, 0, 1, 157, 32, }, + { 2, 1, 0, 1, 157, 30, }, + { 1, 1, 0, 1, 157, 63, }, + { 0, 1, 0, 1, 161, 32, }, + { 2, 1, 0, 1, 161, 30, }, + { 1, 1, 0, 1, 161, 63, }, + { 0, 1, 0, 1, 165, 32, }, + { 2, 1, 0, 1, 165, 30, }, + { 1, 1, 0, 1, 165, 63, }, + { 0, 1, 0, 2, 36, 32, }, + { 2, 1, 0, 2, 36, 30, }, + { 1, 1, 0, 2, 36, 30, }, + { 0, 1, 0, 2, 40, 32, }, + { 2, 1, 0, 2, 40, 30, }, + { 1, 1, 0, 2, 40, 30, }, + { 0, 1, 0, 2, 44, 32, }, + { 2, 1, 0, 2, 44, 30, }, + { 1, 1, 0, 2, 44, 30, }, + { 0, 1, 0, 2, 48, 32, }, + { 2, 1, 0, 2, 48, 30, }, + { 1, 1, 0, 2, 48, 30, }, + { 0, 1, 0, 2, 52, 32, }, + { 2, 1, 0, 2, 52, 30, }, + { 1, 1, 0, 2, 52, 30, }, + { 0, 1, 0, 2, 56, 32, }, + { 2, 1, 0, 2, 56, 30, }, + { 1, 1, 0, 2, 56, 30, }, + { 0, 1, 0, 2, 60, 32, }, + { 2, 1, 0, 2, 60, 30, }, + { 1, 1, 0, 2, 60, 30, }, + { 0, 1, 0, 2, 64, 32, }, + { 2, 1, 0, 2, 64, 30, }, + { 1, 1, 0, 2, 64, 30, }, + { 0, 1, 0, 2, 100, 32, }, + { 2, 1, 0, 2, 100, 30, }, + { 1, 1, 0, 2, 100, 30, }, + { 0, 1, 0, 2, 104, 32, }, + { 2, 1, 0, 2, 104, 30, }, + { 1, 1, 0, 2, 104, 30, }, + { 0, 1, 0, 2, 108, 32, }, + { 2, 1, 0, 2, 108, 30, }, + { 1, 1, 0, 2, 108, 30, }, + { 0, 1, 0, 2, 112, 32, }, + { 2, 1, 0, 2, 112, 30, }, + { 1, 1, 0, 2, 112, 30, }, + { 0, 1, 0, 2, 116, 32, }, + { 2, 1, 0, 2, 116, 30, }, + { 1, 1, 0, 2, 116, 30, }, + { 0, 1, 0, 2, 120, 32, }, + { 2, 1, 0, 2, 120, 30, }, + { 1, 1, 0, 2, 120, 30, }, + { 0, 1, 0, 2, 124, 32, }, + { 2, 1, 0, 2, 124, 30, }, + { 1, 1, 0, 2, 124, 30, }, + { 0, 1, 0, 2, 128, 32, }, + { 2, 1, 0, 2, 128, 30, }, + { 1, 1, 0, 2, 128, 30, }, + { 0, 1, 0, 2, 132, 32, }, + { 2, 1, 0, 2, 132, 30, }, + { 1, 1, 0, 2, 132, 30, }, + { 0, 1, 0, 2, 136, 32, }, + { 2, 1, 0, 2, 136, 30, }, + { 1, 1, 0, 2, 136, 30, }, + { 0, 1, 0, 2, 140, 32, }, + { 2, 1, 0, 2, 140, 30, }, + { 1, 1, 0, 2, 140, 30, }, + { 0, 1, 0, 2, 149, 32, }, + { 2, 1, 0, 2, 149, 30, }, + { 1, 1, 0, 2, 149, 63, }, + { 0, 1, 0, 2, 153, 32, }, + { 2, 1, 0, 2, 153, 30, }, + { 1, 1, 0, 2, 153, 63, }, + { 0, 1, 0, 2, 157, 32, }, + { 2, 1, 0, 2, 157, 30, }, + { 1, 1, 0, 2, 157, 63, }, + { 0, 1, 0, 2, 161, 32, }, + { 2, 1, 0, 2, 161, 30, }, + { 1, 1, 0, 2, 161, 63, }, + { 0, 1, 0, 2, 165, 32, }, + { 2, 1, 0, 2, 165, 30, }, + { 1, 1, 0, 2, 165, 63, }, + { 0, 1, 0, 3, 36, 28, }, + { 2, 1, 0, 3, 36, 30, }, + { 1, 1, 0, 3, 36, 30, }, + { 0, 1, 0, 3, 40, 28, }, + { 2, 1, 0, 3, 40, 30, }, + { 1, 1, 0, 3, 40, 30, }, + { 0, 1, 0, 3, 44, 28, }, + { 2, 1, 0, 3, 44, 30, }, + { 1, 1, 0, 3, 44, 30, }, + { 0, 1, 0, 3, 48, 28, }, + { 2, 1, 0, 3, 48, 30, }, + { 1, 1, 0, 3, 48, 30, }, + { 0, 1, 0, 3, 52, 34, }, + { 2, 1, 0, 3, 52, 30, }, + { 1, 1, 0, 3, 52, 30, }, + { 0, 1, 0, 3, 56, 32, }, + { 2, 1, 0, 3, 56, 30, }, + { 1, 1, 0, 3, 56, 30, }, + { 0, 1, 0, 3, 60, 30, }, + { 2, 1, 0, 3, 60, 30, }, + { 1, 1, 0, 3, 60, 30, }, + { 0, 1, 0, 3, 64, 26, }, + { 2, 1, 0, 3, 64, 30, }, + { 1, 1, 0, 3, 64, 30, }, + { 0, 1, 0, 3, 100, 28, }, + { 2, 1, 0, 3, 100, 30, }, + { 1, 1, 0, 3, 100, 30, }, + { 0, 1, 0, 3, 104, 28, }, + { 2, 1, 0, 3, 104, 30, }, + { 1, 1, 0, 3, 104, 30, }, + { 0, 1, 0, 3, 108, 30, }, + { 2, 1, 0, 3, 108, 30, }, + { 1, 1, 0, 3, 108, 30, }, + { 0, 1, 0, 3, 112, 32, }, + { 2, 1, 0, 3, 112, 30, }, + { 1, 1, 0, 3, 112, 30, }, + { 0, 1, 0, 3, 116, 32, }, + { 2, 1, 0, 3, 116, 30, }, + { 1, 1, 0, 3, 116, 30, }, + { 0, 1, 0, 3, 120, 34, }, + { 2, 1, 0, 3, 120, 30, }, + { 1, 1, 0, 3, 120, 30, }, + { 0, 1, 0, 3, 124, 32, }, + { 2, 1, 0, 3, 124, 30, }, + { 1, 1, 0, 3, 124, 30, }, + { 0, 1, 0, 3, 128, 30, }, + { 2, 1, 0, 3, 128, 30, }, + { 1, 1, 0, 3, 128, 30, }, + { 0, 1, 0, 3, 132, 28, }, + { 2, 1, 0, 3, 132, 30, }, + { 1, 1, 0, 3, 132, 30, }, + { 0, 1, 0, 3, 136, 28, }, + { 2, 1, 0, 3, 136, 30, }, + { 1, 1, 0, 3, 136, 30, }, + { 0, 1, 0, 3, 140, 26, }, + { 2, 1, 0, 3, 140, 30, }, + { 1, 1, 0, 3, 140, 30, }, + { 0, 1, 0, 3, 149, 34, }, + { 2, 1, 0, 3, 149, 30, }, + { 1, 1, 0, 3, 149, 63, }, + { 0, 1, 0, 3, 153, 34, }, + { 2, 1, 0, 3, 153, 30, }, + { 1, 1, 0, 3, 153, 63, }, + { 0, 1, 0, 3, 157, 34, }, + { 2, 1, 0, 3, 157, 30, }, + { 1, 1, 0, 3, 157, 63, }, + { 0, 1, 0, 3, 161, 34, }, + { 2, 1, 0, 3, 161, 30, }, + { 1, 1, 0, 3, 161, 63, }, + { 0, 1, 0, 3, 165, 34, }, + { 2, 1, 0, 3, 165, 30, }, + { 1, 1, 0, 3, 165, 63, }, + { 0, 1, 1, 2, 38, 26, }, + { 2, 1, 1, 2, 38, 30, }, + { 1, 1, 1, 2, 38, 30, }, + { 0, 1, 1, 2, 46, 32, }, + { 2, 1, 1, 2, 46, 30, }, + { 1, 1, 1, 2, 46, 30, }, + { 0, 1, 1, 2, 54, 32, }, + { 2, 1, 1, 2, 54, 30, }, + { 1, 1, 1, 2, 54, 30, }, + { 0, 1, 1, 2, 62, 24, }, + { 2, 1, 1, 2, 62, 30, }, + { 1, 1, 1, 2, 62, 30, }, + { 0, 1, 1, 2, 102, 24, }, + { 2, 1, 1, 2, 102, 30, }, + { 1, 1, 1, 2, 102, 30, }, + { 0, 1, 1, 2, 110, 32, }, + { 2, 1, 1, 2, 110, 30, }, + { 1, 1, 1, 2, 110, 30, }, + { 0, 1, 1, 2, 118, 32, }, + { 2, 1, 1, 2, 118, 30, }, + { 1, 1, 1, 2, 118, 30, }, + { 0, 1, 1, 2, 126, 32, }, + { 2, 1, 1, 2, 126, 30, }, + { 1, 1, 1, 2, 126, 30, }, + { 0, 1, 1, 2, 134, 32, }, + { 2, 1, 1, 2, 134, 30, }, + { 1, 1, 1, 2, 134, 30, }, + { 0, 1, 1, 2, 151, 30, }, + { 2, 1, 1, 2, 151, 30, }, + { 1, 1, 1, 2, 151, 63, }, + { 0, 1, 1, 2, 159, 32, }, + { 2, 1, 1, 2, 159, 30, }, + { 1, 1, 1, 2, 159, 63, }, + { 0, 1, 1, 3, 38, 28, }, + { 2, 1, 1, 3, 38, 30, }, + { 1, 1, 1, 3, 38, 30, }, + { 0, 1, 1, 3, 46, 28, }, + { 2, 1, 1, 3, 46, 30, }, + { 1, 1, 1, 3, 46, 30, }, + { 0, 1, 1, 3, 54, 30, }, + { 2, 1, 1, 3, 54, 30, }, + { 1, 1, 1, 3, 54, 30, }, + { 0, 1, 1, 3, 62, 30, }, + { 2, 1, 1, 3, 62, 30, }, + { 1, 1, 1, 3, 62, 30, }, + { 0, 1, 1, 3, 102, 26, }, + { 2, 1, 1, 3, 102, 30, }, + { 1, 1, 1, 3, 102, 30, }, + { 0, 1, 1, 3, 110, 30, }, + { 2, 1, 1, 3, 110, 30, }, + { 1, 1, 1, 3, 110, 30, }, + { 0, 1, 1, 3, 118, 34, }, + { 2, 1, 1, 3, 118, 30, }, + { 1, 1, 1, 3, 118, 30, }, + { 0, 1, 1, 3, 126, 32, }, + { 2, 1, 1, 3, 126, 30, }, + { 1, 1, 1, 3, 126, 30, }, + { 0, 1, 1, 3, 134, 30, }, + { 2, 1, 1, 3, 134, 30, }, + { 1, 1, 1, 3, 134, 30, }, + { 0, 1, 1, 3, 151, 34, }, + { 2, 1, 1, 3, 151, 30, }, + { 1, 1, 1, 3, 151, 63, }, + { 0, 1, 1, 3, 159, 34, }, + { 2, 1, 1, 3, 159, 30, }, + { 1, 1, 1, 3, 159, 63, }, + { 0, 1, 2, 4, 42, 22, }, + { 2, 1, 2, 4, 42, 30, }, + { 1, 1, 2, 4, 42, 30, }, + { 0, 1, 2, 4, 58, 20, }, + { 2, 1, 2, 4, 58, 30, }, + { 1, 1, 2, 4, 58, 30, }, + { 0, 1, 2, 4, 106, 20, }, + { 2, 1, 2, 4, 106, 30, }, + { 1, 1, 2, 4, 106, 30, }, + { 0, 1, 2, 4, 122, 20, }, + { 2, 1, 2, 4, 122, 30, }, + { 1, 1, 2, 4, 122, 30, }, + { 0, 1, 2, 4, 155, 28, }, + { 2, 1, 2, 4, 155, 30, }, + { 1, 1, 2, 4, 155, 63, }, + { 0, 1, 2, 5, 42, 28, }, + { 2, 1, 2, 5, 42, 30, }, + { 1, 1, 2, 5, 42, 30, }, + { 0, 1, 2, 5, 58, 26, }, + { 2, 1, 2, 5, 58, 30, }, + { 1, 1, 2, 5, 58, 30, }, + { 0, 1, 2, 5, 106, 28, }, + { 2, 1, 2, 5, 106, 30, }, + { 1, 1, 2, 5, 106, 30, }, + { 0, 1, 2, 5, 122, 32, }, + { 2, 1, 2, 5, 122, 30, }, + { 1, 1, 2, 5, 122, 30, }, + { 0, 1, 2, 5, 155, 34, }, + { 2, 1, 2, 5, 155, 30, }, + { 1, 1, 2, 5, 155, 63, }, +}; + +RTW_DECL_TABLE_TXPWR_LMT(rtw8821a_txpwr_lmt); + +static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821a[] = { + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, + {0x004A, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), 0}, + {0x0023, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4), 0}, + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821a[] = { + {0x0020, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4), 0}, + {0x0001, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 1, RTW_PWR_DELAY_MS}, + {0x0000, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4) | BIT(3) | BIT(2), 0}, + {0x0075, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, + {0x0075, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(7), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4) | BIT(3), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(0), 0}, + {0x004F, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5) | BIT(4), BIT(5) | BIT(4)}, + {0x0025, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(6), 0}, + {0x0049, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0063, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0062, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0058, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x005A, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x002E, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x82}, + {0x0010, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(6), BIT(6)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_act_to_lps_8821a[] = { + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0xFF}, + {0x0522, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0xFF}, + {0x05F8, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05F9, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05FA, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x05FB, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, 0xFF, 0}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 0, RTW_PWR_DELAY_US}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0100, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x03}, + {0x0101, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0093, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0553, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), BIT(5)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821a[] = { + {0x001F, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x004F, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0049, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), 0}, + {0x0000, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), BIT(5)}, + {0x0020, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821a[] = { + {0x0007, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x20}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), BIT(2)}, + {0x004A, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 1}, + {0x0023, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4), BIT(4)}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_POLLING, BIT(1), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +const struct rtw_pwr_seq_cmd * const card_enable_flow_8821a[] = { + trans_carddis_to_cardemu_8821a, + trans_cardemu_to_act_8821a, + NULL +}; + +const struct rtw_pwr_seq_cmd * const enter_lps_flow_8821a[] = { + trans_act_to_lps_8821a, + NULL +}; + +const struct rtw_pwr_seq_cmd * const card_disable_flow_8821a[] = { + trans_act_to_cardemu_8821a, + trans_cardemu_to_carddis_8821a, + NULL +}; + +static const u8 rtw8821a_pwrtrk_5gb_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8821a_pwrtrk_5gb_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8821a_pwrtrk_5ga_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8821a_pwrtrk_5ga_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, + {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16}, +}; + +static const u8 rtw8821a_pwrtrk_2gb_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10 +}; + +static const u8 rtw8821a_pwrtrk_2gb_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12 +}; + +static const u8 rtw8821a_pwrtrk_2ga_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10 +}; + +static const u8 rtw8821a_pwrtrk_2ga_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12 +}; + +static const u8 rtw8821a_pwrtrk_2g_cck_b_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10 +}; + +static const u8 rtw8821a_pwrtrk_2g_cck_b_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12 +}; + +static const u8 rtw8821a_pwrtrk_2g_cck_a_n[] = { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10 +}; + +static const u8 rtw8821a_pwrtrk_2g_cck_a_p[] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12 +}; + +const struct rtw_pwr_track_tbl rtw8821a_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[0] = rtw8821a_pwrtrk_5gb_n[0], + .pwrtrk_5gb_n[1] = rtw8821a_pwrtrk_5gb_n[1], + .pwrtrk_5gb_n[2] = rtw8821a_pwrtrk_5gb_n[2], + .pwrtrk_5gb_p[0] = rtw8821a_pwrtrk_5gb_p[0], + .pwrtrk_5gb_p[1] = rtw8821a_pwrtrk_5gb_p[1], + .pwrtrk_5gb_p[2] = rtw8821a_pwrtrk_5gb_p[2], + .pwrtrk_5ga_n[0] = rtw8821a_pwrtrk_5ga_n[0], + .pwrtrk_5ga_n[1] = rtw8821a_pwrtrk_5ga_n[1], + .pwrtrk_5ga_n[2] = rtw8821a_pwrtrk_5ga_n[2], + .pwrtrk_5ga_p[0] = rtw8821a_pwrtrk_5ga_p[0], + .pwrtrk_5ga_p[1] = rtw8821a_pwrtrk_5ga_p[1], + .pwrtrk_5ga_p[2] = rtw8821a_pwrtrk_5ga_p[2], + .pwrtrk_2gb_n = rtw8821a_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8821a_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8821a_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8821a_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8821a_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8821a_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8821a_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8821a_pwrtrk_2g_cck_a_p, +}; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h new file mode 100644 index 00000000000000..90379ac7a8178b --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a_table.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW8821A_TABLE_H__ +#define __RTW8821A_TABLE_H__ + +extern const struct rtw_table rtw8821a_mac_tbl; +extern const struct rtw_table rtw8821a_agc_tbl; +extern const struct rtw_table rtw8821a_bb_tbl; +extern const struct rtw_table rtw8821a_bb_pg_tbl; +extern const struct rtw_table rtw8821a_rf_a_tbl; +extern const struct rtw_table rtw8821a_txpwr_lmt_tbl; + +extern const struct rtw_pwr_seq_cmd * const card_enable_flow_8821a[]; +extern const struct rtw_pwr_seq_cmd * const enter_lps_flow_8821a[]; +extern const struct rtw_pwr_seq_cmd * const card_disable_flow_8821a[]; + +extern const struct rtw_pwr_track_tbl rtw8821a_rtw_pwr_track_tbl; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821au.c b/drivers/net/wireless/realtek/rtw88/rtw8821au.c new file mode 100644 index 00000000000000..730018773e1c30 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821au.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include +#include +#include "main.h" +#include "rtw8821a.h" +#include "usb.h" + +static const struct usb_device_id rtw_8821au_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x011e, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&(rtw8821a_hw_spec) }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8821au_id_table); + +static struct usb_driver rtw_8821au_driver = { + .name = "rtw_8821au", + .id_table = rtw_8821au_id_table, + .probe = rtw_usb_probe, + .disconnect = rtw_usb_disconnect, +}; +module_usb_driver(rtw_8821au_driver); + +MODULE_AUTHOR("Bitterblue Smith "); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821au/8811au driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index 526e8de77b3e82..0270225b9c20bc 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -679,47 +679,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, } } -static void rtw8821c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc); - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - /* drv_info_sz is in unit of 8-bytes */ - pkt_stat->drv_info_sz *= 8; - - /* c2h cmd pkt's rx/phy status is not interested */ - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); -} - static void rtw8821c_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) { @@ -1254,7 +1213,7 @@ static void rtw8821c_fill_txdesc_checksum(struct rtw_dev *rtwdev, fill_txdesc_checksum_common(txdesc, 16); } -static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { +static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { {0x0086, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_SDIO_MSK, @@ -1292,7 +1251,7 @@ static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = { +static const struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = { {0x0020, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, @@ -1396,7 +1355,7 @@ static struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = { +static const struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = { {0x0093, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_ALL_MSK, @@ -1454,7 +1413,7 @@ static struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = { +static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = { {0x0007, RTW_PWR_CUT_ALL_MSK, RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, @@ -1567,13 +1526,13 @@ static struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8821c[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8821c[] = { trans_carddis_to_cardemu_8821c, trans_cardemu_to_act_8821c, NULL }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8821c[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8821c[] = { trans_act_to_cardemu_8821c, trans_cardemu_to_carddis_8821c, NULL @@ -1622,14 +1581,7 @@ static const struct rtw_intf_phy_para_table phy_para_table_8821c = { .n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8821c), }; -static const struct rtw_rfe_def rtw8821c_rfe_defs[] = { - [0] = RTW_DEF_RFE(8821c, 0, 0), - [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), - [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), - [6] = RTW_DEF_RFE(8821c, 0, 0), -}; - -static struct rtw_hw_reg rtw8821c_dig[] = { +static const struct rtw_hw_reg rtw8821c_dig[] = { [0] = { .addr = 0xc50, .mask = 0x7f }, }; @@ -1639,7 +1591,7 @@ static const struct rtw_ltecoex_addr rtw8821c_ltecoex_addr = { .rdata = LTECOEX_READ_DATA, }; -static struct rtw_page_table page_table_8821c[] = { +static const struct rtw_page_table page_table_8821c[] = { /* not sure what [0] stands for */ {16, 16, 16, 14, 1}, {16, 16, 16, 14, 1}, @@ -1648,7 +1600,7 @@ static struct rtw_page_table page_table_8821c[] = { {16, 16, 16, 14, 1}, }; -static struct rtw_rqpn rqpn_table_8821c[] = { +static const struct rtw_rqpn rqpn_table_8821c[] = { /* not sure what [0] stands for */ {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, @@ -1667,7 +1619,7 @@ static struct rtw_rqpn rqpn_table_8821c[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; -static struct rtw_prioq_addrs prioq_addrs_8821c = { +static const struct rtw_prioq_addrs prioq_addrs_8821c = { .prio[RTW_DMA_MAPPING_EXTRA] = { .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, }, @@ -1683,10 +1635,12 @@ static struct rtw_prioq_addrs prioq_addrs_8821c = { .wsize = true, }; -static struct rtw_chip_ops rtw8821c_ops = { +static const struct rtw_chip_ops rtw8821c_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .phy_set_param = rtw8821c_phy_set_param, .read_efuse = rtw8821c_read_efuse, - .query_rx_desc = rtw8821c_query_rx_desc, + .query_phy_status = query_phy_status, .set_channel = rtw8821c_set_channel, .mac_init = rtw8821c_mac_init, .read_rf = rtw_phy_read_rf, @@ -1938,7 +1892,7 @@ static const u8 rtw8821c_pwrtrk_2g_cck_a_p[] = { 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9 }; -static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = { +static const struct rtw_pwr_track_tbl rtw8821c_pwr_track_type0_tbl = { .pwrtrk_5gb_n[0] = rtw8821c_pwrtrk_5gb_n[0], .pwrtrk_5gb_n[1] = rtw8821c_pwrtrk_5gb_n[1], .pwrtrk_5gb_n[2] = rtw8821c_pwrtrk_5gb_n[2], @@ -1961,6 +1915,13 @@ static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = { .pwrtrk_2g_ccka_p = rtw8821c_pwrtrk_2g_cck_a_p, }; +static const struct rtw_rfe_def rtw8821c_rfe_defs[] = { + [0] = RTW_DEF_RFE(8821c, 0, 0, 0), + [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 0, 2), + [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 0, 2), + [6] = RTW_DEF_RFE(8821c, 0, 0, 0), +}; + static const struct rtw_reg_domain coex_info_hw_regs_8821c[] = { {0xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32}, {0xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32}, @@ -2009,6 +1970,9 @@ const struct rtw_chip_info rtw8821c_hw_spec = { .page_size = TX_PAGE_SIZE, .dig_min = 0x1c, .usb_tx_agg_desc_num = 3, + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = false, .ht_supported = true, .vht_supported = true, .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), @@ -2030,7 +1994,6 @@ const struct rtw_chip_info rtw8821c_hw_spec = { .rfe_defs = rtw8821c_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8821c_rfe_defs), .rx_ldpc = false, - .pwr_track_tbl = &rtw8821c_rtw_pwr_track_tbl, .iqk_threshold = 8, .bfer_su_max_num = 2, .bfer_mu_max_num = 1, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h index 91ed921407bbe7..7a33ebd612eda6 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h @@ -214,19 +214,10 @@ extern const struct rtw_chip_info rtw8821c_hw_spec; #define BIT_FEN_EN BIT(26) #define REG_INIRTS_RATE_SEL 0x0480 #define REG_HTSTFWT 0x800 -#define REG_RXPSEL 0x808 -#define BIT_RX_PSEL_RST (BIT(28) | BIT(29)) -#define REG_TXPSEL 0x80c #define REG_RXCCAMSK 0x814 -#define REG_CCASEL 0x82c -#define REG_PDMFTH 0x830 -#define REG_CCA2ND 0x838 #define REG_L1WT 0x83c #define REG_L1PKWT 0x840 #define REG_MRC 0x850 -#define REG_CLKTRK 0x860 -#define REG_ADCCLK 0x8ac -#define REG_ADC160 0x8c4 #define REG_ADC40 0x8c8 #define REG_CHFIR 0x8f0 #define REG_CDDTXP 0x93c @@ -234,14 +225,11 @@ extern const struct rtw_chip_info rtw8821c_hw_spec; #define REG_ACBB0 0x948 #define REG_ACBBRXFIR 0x94c #define REG_ACGG2TBL 0x958 -#define REG_FAS 0x9a4 -#define REG_RXSB 0xa00 #define REG_ADCINI 0xa04 #define REG_PWRTH 0xa08 #define REG_CCA_FLTR 0xa20 #define REG_TXSF2 0xa24 #define REG_TXSF6 0xa28 -#define REG_FA_CCK 0xa5c #define REG_RXDESC 0xa2c #define REG_ENTXCCK 0xa80 #define BTG_LNA 0xfc84 @@ -252,12 +240,8 @@ extern const struct rtw_chip_info rtw8821c_hw_spec; #define REG_PWRTH2 0xaa8 #define REG_CSRATIO 0xaaa #define REG_TXFILTER 0xaac -#define REG_CNTRST 0xb58 #define REG_AGCTR_A 0xc08 -#define REG_TXSCALE_A 0xc1c #define REG_TXDFIR 0xc20 -#define REG_RXIGI_A 0xc50 -#define REG_TXAGCIDX 0xc94 #define REG_TRSW 0xca0 #define REG_RFESEL0 0xcb0 #define REG_RFESEL8 0xcb4 @@ -269,14 +253,6 @@ extern const struct rtw_chip_info rtw8821c_hw_spec; #define B_WLA_SWITCH BIT(23) #define REG_RFEINV 0xcbc #define REG_AGCTR_B 0xe08 -#define REG_RXIGI_B 0xe50 -#define REG_CRC_CCK 0xf04 -#define REG_CRC_OFDM 0xf14 -#define REG_CRC_HT 0xf10 -#define REG_CRC_VHT 0xf0c -#define REG_CCA_OFDM 0xf08 -#define REG_FA_OFDM 0xf48 -#define REG_CCA_CCK 0xfcc #define REG_DMEM_CTRL 0x1080 #define BIT_WL_RST BIT(16) #define REG_ANTWT 0x1904 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 6edb17aea90e0e..739809f4cab557 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -934,47 +934,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, } } -static void rtw8822b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc); - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - /* drv_info_sz is in unit of 8-bytes */ - pkt_stat->drv_info_sz *= 8; - - /* c2h cmd pkt's rx/phy status is not interested */ - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); -} - static void rtw8822b_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) { @@ -1978,13 +1937,13 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822b[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8822b[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8822b[] = { trans_carddis_to_cardemu_8822b, trans_cardemu_to_act_8822b, NULL }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8822b[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8822b[] = { trans_act_to_cardemu_8822b, trans_cardemu_to_carddis_8822b, NULL @@ -2113,12 +2072,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8822b = { .n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8822b), }; -static const struct rtw_rfe_def rtw8822b_rfe_defs[] = { - [2] = RTW_DEF_RFE(8822b, 2, 2), - [3] = RTW_DEF_RFE(8822b, 3, 0), - [5] = RTW_DEF_RFE(8822b, 5, 5), -}; - static const struct rtw_hw_reg rtw8822b_dig[] = { [0] = { .addr = 0xc50, .mask = 0x7f }, [1] = { .addr = 0xe50, .mask = 0x7f }, @@ -2156,7 +2109,7 @@ static const struct rtw_rqpn rqpn_table_8822b[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; -static struct rtw_prioq_addrs prioq_addrs_8822b = { +static const struct rtw_prioq_addrs prioq_addrs_8822b = { .prio[RTW_DMA_MAPPING_EXTRA] = { .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, }, @@ -2172,10 +2125,12 @@ static struct rtw_prioq_addrs prioq_addrs_8822b = { .wsize = true, }; -static struct rtw_chip_ops rtw8822b_ops = { +static const struct rtw_chip_ops rtw8822b_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .phy_set_param = rtw8822b_phy_set_param, .read_efuse = rtw8822b_read_efuse, - .query_rx_desc = rtw8822b_query_rx_desc, + .query_phy_status = query_phy_status, .set_channel = rtw8822b_set_channel, .mac_init = rtw8822b_mac_init, .read_rf = rtw_phy_read_rf, @@ -2471,7 +2426,7 @@ static const u8 rtw8822b_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = { 10, 11, 11, 12, 12, 13, 13, 14, 14, 15 }; -static const struct rtw_pwr_track_tbl rtw8822b_rtw_pwr_track_tbl = { +static const struct rtw_pwr_track_tbl rtw8822b_pwr_track_type0_tbl = { .pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1], .pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2], .pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3], @@ -2494,6 +2449,12 @@ static const struct rtw_pwr_track_tbl rtw8822b_rtw_pwr_track_tbl = { .pwrtrk_2g_ccka_p = rtw8822b_pwrtrk_2g_cck_a_p, }; +static const struct rtw_rfe_def rtw8822b_rfe_defs[] = { + [2] = RTW_DEF_RFE(8822b, 2, 2, 0), + [3] = RTW_DEF_RFE(8822b, 3, 0, 0), + [5] = RTW_DEF_RFE(8822b, 5, 5, 0), +}; + static const struct rtw_reg_domain coex_info_hw_regs_8822b[] = { {0xcb0, MASKDWORD, RTW_REG_DOMAIN_MAC32}, {0xcb4, MASKDWORD, RTW_REG_DOMAIN_MAC32}, @@ -2521,7 +2482,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8822b[] = { {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, }; -static struct rtw_hw_reg_offset rtw8822b_edcca_th[] = { +static const struct rtw_hw_reg_offset rtw8822b_edcca_th[] = { [EDCCA_TH_L2H_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE0}, .offset = 0}, [EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0}, }; @@ -2550,6 +2511,9 @@ const struct rtw_chip_info rtw8822b_hw_spec = { .page_size = TX_PAGE_SIZE, .dig_min = 0x1c, .usb_tx_agg_desc_num = 3, + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = false, .ht_supported = true, .vht_supported = true, .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), @@ -2571,7 +2535,6 @@ const struct rtw_chip_info rtw8822b_hw_spec = { .rf_tbl = {&rtw8822b_rf_a_tbl, &rtw8822b_rf_b_tbl}, .rfe_defs = rtw8822b_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8822b_rfe_defs), - .pwr_track_tbl = &rtw8822b_rtw_pwr_track_tbl, .iqk_threshold = 8, .bfer_su_max_num = 2, .bfer_mu_max_num = 1, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.h b/drivers/net/wireless/realtek/rtw88/rtw8822b.h index cf85e63966a1c7..0514958fb57c36 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h @@ -151,21 +151,12 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) #define RTW8822B_EDCCA_MAX 0x7f #define RTW8822B_EDCCA_SRC_DEF 1 #define REG_HTSTFWT 0x800 -#define REG_RXPSEL 0x808 -#define BIT_RX_PSEL_RST (BIT(28) | BIT(29)) -#define REG_TXPSEL 0x80c #define REG_RXCCAMSK 0x814 -#define REG_CCASEL 0x82c -#define REG_PDMFTH 0x830 -#define REG_CCA2ND 0x838 #define REG_L1WT 0x83c #define REG_L1PKWT 0x840 #define REG_MRC 0x850 -#define REG_CLKTRK 0x860 #define REG_EDCCA_POW_MA 0x8a0 #define BIT_MA_LEVEL GENMASK(1, 0) -#define REG_ADCCLK 0x8ac -#define REG_ADC160 0x8c4 #define REG_ADC40 0x8c8 #define REG_EDCCA_DECISION 0x8dc #define BIT_EDCCA_OPTION BIT(5) @@ -176,7 +167,6 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) #define REG_ACBB0 0x948 #define REG_ACBBRXFIR 0x94c #define REG_ACGG2TBL 0x958 -#define REG_RXSB 0xa00 #define REG_ADCINI 0xa04 #define REG_TXSF2 0xa24 #define REG_TXSF6 0xa28 @@ -184,14 +174,12 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) #define REG_ENTXCCK 0xa80 #define REG_AGCTR_A 0xc08 #define REG_TXDFIR 0xc20 -#define REG_RXIGI_A 0xc50 #define REG_TRSW 0xca0 #define REG_RFESEL0 0xcb0 #define REG_RFESEL8 0xcb4 #define REG_RFECTL 0xcb8 #define REG_RFEINV 0xcbc #define REG_AGCTR_B 0xe08 -#define REG_RXIGI_B 0xe50 #define REG_ANTWT 0x1904 #define REG_IQKFAILMSK 0x1bf0 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 1dbe1cdbc3fd45..af6b76937f1dc5 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -2690,48 +2690,6 @@ static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, } } -static void rtw8822c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hdr *hdr; - u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; - u8 *phy_status = NULL; - - memset(pkt_stat, 0, sizeof(*pkt_stat)); - - pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); - pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); - pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && - GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; - pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); - pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); - pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); - pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); - pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); - pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); - pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc); - pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); - - /* drv_info_sz is in unit of 8-bytes */ - pkt_stat->drv_info_sz *= 8; - - /* c2h cmd pkt's rx/phy status is not interested */ - if (pkt_stat->is_c2h) - return; - - hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + - pkt_stat->drv_info_sz); - pkt_stat->hdr = hdr; - if (pkt_stat->phy_status) { - phy_status = rx_desc + desc_sz + pkt_stat->shift; - query_phy_status(rtwdev, phy_status, pkt_stat); - } - - rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); -} - static void rtw8822c_set_write_tx_power_ref(struct rtw_dev *rtwdev, u8 *tx_pwr_ref_cck, u8 *tx_pwr_ref_ofdm) @@ -4874,13 +4832,13 @@ static const struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8822c[] = { RTW_PWR_CMD_END, 0, 0}, }; -static const struct rtw_pwr_seq_cmd *card_enable_flow_8822c[] = { +static const struct rtw_pwr_seq_cmd * const card_enable_flow_8822c[] = { trans_carddis_to_cardemu_8822c, trans_cardemu_to_act_8822c, NULL }; -static const struct rtw_pwr_seq_cmd *card_disable_flow_8822c[] = { +static const struct rtw_pwr_seq_cmd * const card_disable_flow_8822c[] = { trans_act_to_cardemu_8822c, trans_cardemu_to_carddis_8822c, NULL @@ -4925,16 +4883,6 @@ static const struct rtw_intf_phy_para_table phy_para_table_8822c = { .n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8822c), }; -static const struct rtw_rfe_def rtw8822c_rfe_defs[] = { - [0] = RTW_DEF_RFE(8822c, 0, 0), - [1] = RTW_DEF_RFE(8822c, 0, 0), - [2] = RTW_DEF_RFE(8822c, 0, 0), - [3] = RTW_DEF_RFE(8822c, 0, 0), - [4] = RTW_DEF_RFE(8822c, 0, 0), - [5] = RTW_DEF_RFE(8822c, 0, 5), - [6] = RTW_DEF_RFE(8822c, 0, 0), -}; - static const struct rtw_hw_reg rtw8822c_dig[] = { [0] = { .addr = 0x1d70, .mask = 0x7f }, [1] = { .addr = 0x1d70, .mask = 0x7f00 }, @@ -4972,7 +4920,7 @@ static const struct rtw_rqpn rqpn_table_8822c[] = { RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, }; -static struct rtw_prioq_addrs prioq_addrs_8822c = { +static const struct rtw_prioq_addrs prioq_addrs_8822c = { .prio[RTW_DMA_MAPPING_EXTRA] = { .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, }, @@ -4988,10 +4936,12 @@ static struct rtw_prioq_addrs prioq_addrs_8822c = { .wsize = true, }; -static struct rtw_chip_ops rtw8822c_ops = { +static const struct rtw_chip_ops rtw8822c_ops = { + .power_on = rtw_power_on, + .power_off = rtw_power_off, .phy_set_param = rtw8822c_phy_set_param, .read_efuse = rtw8822c_read_efuse, - .query_rx_desc = rtw8822c_query_rx_desc, + .query_phy_status = query_phy_status, .set_channel = rtw8822c_set_channel, .mac_init = rtw8822c_mac_init, .dump_fw_crash = rtw8822c_dump_fw_crash, @@ -5278,7 +5228,7 @@ static const u8 rtw8822c_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = { 18, 18, 19, 20, 21, 22, 23, 24, 24, 25 }; -static const struct rtw_pwr_track_tbl rtw8822c_rtw_pwr_track_tbl = { +static const struct rtw_pwr_track_tbl rtw8822c_pwr_track_type0_tbl = { .pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1], .pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2], .pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3], @@ -5301,7 +5251,17 @@ static const struct rtw_pwr_track_tbl rtw8822c_rtw_pwr_track_tbl = { .pwrtrk_2g_ccka_p = rtw8822c_pwrtrk_2g_cck_a_p, }; -static struct rtw_hw_reg_offset rtw8822c_edcca_th[] = { +static const struct rtw_rfe_def rtw8822c_rfe_defs[] = { + [0] = RTW_DEF_RFE(8822c, 0, 0, 0), + [1] = RTW_DEF_RFE(8822c, 0, 0, 0), + [2] = RTW_DEF_RFE(8822c, 0, 0, 0), + [3] = RTW_DEF_RFE(8822c, 0, 0, 0), + [4] = RTW_DEF_RFE(8822c, 0, 0, 0), + [5] = RTW_DEF_RFE(8822c, 0, 5, 0), + [6] = RTW_DEF_RFE(8822c, 0, 0, 0), +}; + +static const struct rtw_hw_reg_offset rtw8822c_edcca_th[] = { [EDCCA_TH_L2H_IDX] = { {.addr = 0x84c, .mask = MASKBYTE2}, .offset = 0x80 }, @@ -5371,6 +5331,9 @@ const struct rtw_chip_info rtw8822c_hw_spec = { .page_size = TX_PAGE_SIZE, .dig_min = 0x20, .usb_tx_agg_desc_num = 3, + .hw_feature_report = true, + .c2h_ra_report_size = 7, + .old_datarate_fb_limit = false, .default_1ss_tx_path = BB_PATH_A, .path_div_supported = true, .ht_supported = true, @@ -5397,7 +5360,6 @@ const struct rtw_chip_info rtw8822c_hw_spec = { .rfe_defs_size = ARRAY_SIZE(rtw8822c_rfe_defs), .en_dis_dpd = true, .dpd_ratemask = DIS_DPD_RATEALL, - .pwr_track_tbl = &rtw8822c_rtw_pwr_track_tbl, .iqk_threshold = 8, .lck_threshold = 8, .bfer_su_max_num = 2, diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.c b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c new file mode 100644 index 00000000000000..71e61b9c0becfa --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.c @@ -0,0 +1,1989 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2024 Realtek Corporation + */ + +#include +#include "main.h" +#include "coex.h" +#include "phy.h" +#include "rtw88xxa.h" +#include "mac.h" +#include "reg.h" +#include "sec.h" +#include "debug.h" +#include "bf.h" +#include "efuse.h" +#include "usb.h" + +void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on) +{ + if (on) { + rtw_write8(rtwdev, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); + + rtw_write16_set(rtwdev, REG_SYS_FUNC_EN, BIT_FEN_ELDR); + rtw_write16_set(rtwdev, REG_SYS_CLKR, + BIT_LOADER_CLK_EN | BIT_ANA8M); + } else { + rtw_write8(rtwdev, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); + } +} +EXPORT_SYMBOL(rtw88xxa_efuse_grant); + +static void rtw8812a_read_amplifier_type(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + + efuse->ext_pa_2g = (efuse->pa_type_2g & BIT(5)) && + (efuse->pa_type_2g & BIT(4)); + efuse->ext_lna_2g = (efuse->lna_type_2g & BIT(7)) && + (efuse->lna_type_2g & BIT(3)); + + efuse->ext_pa_5g = (efuse->pa_type_5g & BIT(1)) && + (efuse->pa_type_5g & BIT(0)); + efuse->ext_lna_5g = (efuse->lna_type_5g & BIT(7)) && + (efuse->lna_type_5g & BIT(3)); + + /* For rtw_phy_cond2: */ + if (efuse->ext_pa_2g) { + u8 ext_type_pa_2g_a = u8_get_bits(efuse->lna_type_2g, BIT(2)); + u8 ext_type_pa_2g_b = u8_get_bits(efuse->lna_type_2g, BIT(6)); + + efuse->gpa_type = (ext_type_pa_2g_b << 2) | ext_type_pa_2g_a; + } + + if (efuse->ext_pa_5g) { + u8 ext_type_pa_5g_a = u8_get_bits(efuse->lna_type_5g, BIT(2)); + u8 ext_type_pa_5g_b = u8_get_bits(efuse->lna_type_5g, BIT(6)); + + efuse->apa_type = (ext_type_pa_5g_b << 2) | ext_type_pa_5g_a; + } + + if (efuse->ext_lna_2g) { + u8 ext_type_lna_2g_a = u8_get_bits(efuse->lna_type_2g, + BIT(1) | BIT(0)); + u8 ext_type_lna_2g_b = u8_get_bits(efuse->lna_type_2g, + BIT(5) | BIT(4)); + + efuse->glna_type = (ext_type_lna_2g_b << 2) | ext_type_lna_2g_a; + } + + if (efuse->ext_lna_5g) { + u8 ext_type_lna_5g_a = u8_get_bits(efuse->lna_type_5g, + BIT(1) | BIT(0)); + u8 ext_type_lna_5g_b = u8_get_bits(efuse->lna_type_5g, + BIT(5) | BIT(4)); + + efuse->alna_type = (ext_type_lna_5g_b << 2) | ext_type_lna_5g_a; + } +} + +static void rtw8812a_read_rfe_type(struct rtw_dev *rtwdev, + struct rtw88xxa_efuse *map) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + + if (map->rfe_option == 0xff) { + if (rtwdev->hci.type == RTW_HCI_TYPE_USB) + efuse->rfe_option = 0; + else if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE) + efuse->rfe_option = 2; + else + efuse->rfe_option = 4; + } else if (map->rfe_option & BIT(7)) { + if (efuse->ext_lna_5g) { + if (efuse->ext_pa_5g) { + if (efuse->ext_lna_2g && efuse->ext_pa_2g) + efuse->rfe_option = 3; + else + efuse->rfe_option = 0; + } else { + efuse->rfe_option = 2; + } + } else { + efuse->rfe_option = 4; + } + } else { + efuse->rfe_option = map->rfe_option & 0x3f; + + /* Due to other customer already use incorrect EFUSE map for + * their product. We need to add workaround to prevent to + * modify spec and notify all customer to revise the IC 0xca + * content. + */ + if (efuse->rfe_option == 4 && + (efuse->ext_pa_5g || efuse->ext_pa_2g || + efuse->ext_lna_5g || efuse->ext_lna_2g)) { + if (rtwdev->hci.type == RTW_HCI_TYPE_USB) + efuse->rfe_option = 0; + else if (rtwdev->hci.type == RTW_HCI_TYPE_PCIE) + efuse->rfe_option = 2; + } + } +} + +static void rtw88xxa_read_usb_type(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_hal *hal = &rtwdev->hal; + u8 antenna = 0; + u8 wmode = 0; + u8 val8, i; + + efuse->hw_cap.bw = BIT(RTW_CHANNEL_WIDTH_20) | + BIT(RTW_CHANNEL_WIDTH_40) | + BIT(RTW_CHANNEL_WIDTH_80); + efuse->hw_cap.ptcl = EFUSE_HW_CAP_PTCL_VHT; + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) + efuse->hw_cap.nss = 1; + else + efuse->hw_cap.nss = 2; + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) + goto print_hw_cap; + + for (i = 0; i < 2; i++) { + rtw_read8_physical_efuse(rtwdev, 1019 - i, &val8); + + antenna = u8_get_bits(val8, GENMASK(7, 5)); + if (antenna) + break; + antenna = u8_get_bits(val8, GENMASK(3, 1)); + if (antenna) + break; + } + + for (i = 0; i < 2; i++) { + rtw_read8_physical_efuse(rtwdev, 1021 - i, &val8); + + wmode = u8_get_bits(val8, GENMASK(3, 2)); + if (wmode) + break; + } + + if (antenna == 1) { + rtw_info(rtwdev, "This RTL8812AU says it is 1T1R.\n"); + + efuse->hw_cap.nss = 1; + hal->rf_type = RF_1T1R; + hal->rf_path_num = 1; + hal->rf_phy_num = 1; + hal->antenna_tx = BB_PATH_A; + hal->antenna_rx = BB_PATH_A; + } else { + /* Override rtw_chip_parameter_setup(). It detects 8812au as 1T1R. */ + efuse->hw_cap.nss = 2; + hal->rf_type = RF_2T2R; + hal->rf_path_num = 2; + hal->rf_phy_num = 2; + hal->antenna_tx = BB_PATH_AB; + hal->antenna_rx = BB_PATH_AB; + + if (antenna == 2 && wmode == 2) { + rtw_info(rtwdev, "This RTL8812AU says it can't do VHT.\n"); + + /* Can't be EFUSE_HW_CAP_IGNORE and can't be + * EFUSE_HW_CAP_PTCL_VHT, so make it 1. + */ + efuse->hw_cap.ptcl = 1; + efuse->hw_cap.bw &= ~BIT(RTW_CHANNEL_WIDTH_80); + } + } + +print_hw_cap: + rtw_dbg(rtwdev, RTW_DBG_EFUSE, + "hw cap: hci=0x%02x, bw=0x%02x, ptcl=0x%02x, ant_num=%d, nss=%d\n", + efuse->hw_cap.hci, efuse->hw_cap.bw, efuse->hw_cap.ptcl, + efuse->hw_cap.ant_num, efuse->hw_cap.nss); +} + +int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw88xxa_efuse *map; + int i; + + if (chip->id == RTW_CHIP_TYPE_8812A) + rtwdev->hal.cut_version += 1; + + if (rtw_dbg_is_enabled(rtwdev, RTW_DBG_EFUSE)) + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, + log_map, chip->log_efuse_size, true); + + map = (struct rtw88xxa_efuse *)log_map; + + efuse->rf_board_option = map->rf_board_option; + efuse->crystal_cap = map->xtal_k; + if (efuse->crystal_cap == 0xff) + efuse->crystal_cap = 0x20; + efuse->pa_type_2g = map->pa_type; + efuse->pa_type_5g = map->pa_type; + efuse->lna_type_2g = map->lna_type_2g; + efuse->lna_type_5g = map->lna_type_5g; + if (chip->id == RTW_CHIP_TYPE_8812A) { + rtw8812a_read_amplifier_type(rtwdev); + rtw8812a_read_rfe_type(rtwdev, map); + + efuse->usb_mode_switch = u8_get_bits(map->usb_mode, BIT(1)); + } + efuse->channel_plan = map->channel_plan; + efuse->country_code[0] = map->country_code[0]; + efuse->country_code[1] = map->country_code[1]; + efuse->bt_setting = map->rf_bt_setting; + efuse->regd = map->rf_board_option & 0x7; + efuse->thermal_meter[0] = map->thermal_meter; + efuse->thermal_meter[1] = map->thermal_meter; + efuse->thermal_meter_k = map->thermal_meter; + efuse->tx_bb_swing_setting_2g = map->tx_bb_swing_setting_2g; + efuse->tx_bb_swing_setting_5g = map->tx_bb_swing_setting_5g; + + rtw88xxa_read_usb_type(rtwdev); + + if (chip->id == RTW_CHIP_TYPE_8821A) + efuse->btcoex = rtw_read32_mask(rtwdev, REG_WL_BT_PWR_CTRL, + BIT_BT_FUNC_EN); + else + efuse->btcoex = (map->rf_board_option & 0xe0) == 0x20; + efuse->share_ant = !!(efuse->bt_setting & BIT(0)); + + /* No antenna diversity because it's disabled in the vendor driver */ + efuse->ant_div_cfg = 0; + + efuse->ant_div_type = map->rf_antenna_option; + if (efuse->ant_div_type == 0xff) + efuse->ant_div_type = 0x3; + + for (i = 0; i < 4; i++) + efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i]; + + switch (rtw_hci_type(rtwdev)) { + case RTW_HCI_TYPE_USB: + if (chip->id == RTW_CHIP_TYPE_8821A) + ether_addr_copy(efuse->addr, map->rtw8821au.mac_addr); + else + ether_addr_copy(efuse->addr, map->rtw8812au.mac_addr); + break; + case RTW_HCI_TYPE_PCIE: + case RTW_HCI_TYPE_SDIO: + default: + /* unsupported now */ + return -EOPNOTSUPP; + } + + return 0; +} +EXPORT_SYMBOL(rtw88xxa_read_efuse); + +static void rtw88xxa_reset_8051(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + u8 val8; + + /* Reset MCU IO Wrapper */ + rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1)); + if (chip->id == RTW_CHIP_TYPE_8812A) + rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT(3)); + else + rtw_write8_clr(rtwdev, REG_RSV_CTRL + 1, BIT(0)); + + val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN + 1); + rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, val8 & ~BIT(2)); + + /* Enable MCU IO Wrapper */ + rtw_write8_clr(rtwdev, REG_RSV_CTRL, BIT(1)); + if (chip->id == RTW_CHIP_TYPE_8812A) + rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT(3)); + else + rtw_write8_set(rtwdev, REG_RSV_CTRL + 1, BIT(0)); + + rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, val8 | BIT(2)); +} + +/* A lightweight deinit function */ +static void rtw88xxau_hw_reset(struct rtw_dev *rtwdev) +{ + u8 val8; + + if (!(rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_RAM_DL_SEL)) + return; + + rtw88xxa_reset_8051(rtwdev); + rtw_write8(rtwdev, REG_MCUFW_CTRL, 0x00); + + /* before BB reset should do clock gated */ + rtw_write32_set(rtwdev, REG_FPGA0_XCD_RF_PARA, BIT(6)); + + /* reset BB */ + rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN, BIT(0) | BIT(1)); + + /* reset RF */ + rtw_write8(rtwdev, REG_RF_CTRL, 0); + + /* reset TRX path */ + rtw_write16(rtwdev, REG_CR, 0); + + /* reset MAC, reg0x5[1], auto FSM off */ + rtw_write8_set(rtwdev, REG_APS_FSMCO + 1, APS_FSMCO_MAC_OFF >> 8); + + /* check if reg0x5[1] auto cleared */ + if (read_poll_timeout_atomic(rtw_read8, val8, + !(val8 & (APS_FSMCO_MAC_OFF >> 8)), + 1, 5000, false, + rtwdev, REG_APS_FSMCO + 1)) + rtw_err(rtwdev, "%s: timed out waiting for 0x5[1]\n", __func__); + + /* reg0x5[0], auto FSM on */ + val8 |= APS_FSMCO_MAC_ENABLE >> 8; + rtw_write8(rtwdev, REG_APS_FSMCO + 1, val8); + + rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT(4) | BIT(7)); + rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, BIT(4) | BIT(7)); +} + +static int rtw88xxau_init_power_on(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + u16 val16; + int ret; + + ret = rtw_pwr_seq_parser(rtwdev, chip->pwr_on_seq); + if (ret) { + rtw_err(rtwdev, "power on flow failed\n"); + return ret; + } + + rtw_write16(rtwdev, REG_CR, 0); + val16 = BIT_HCI_TXDMA_EN | BIT_HCI_RXDMA_EN | BIT_TXDMA_EN | + BIT_RXDMA_EN | BIT_PROTOCOL_EN | BIT_SCHEDULE_EN | + BIT_MAC_SEC_EN | BIT_32K_CAL_TMR_EN; + rtw_write16_set(rtwdev, REG_CR, val16); + + if (chip->id == RTW_CHIP_TYPE_8821A) { + if (rtw_read8(rtwdev, REG_SYS_CFG1 + 3) & BIT(0)) + rtw_write8_set(rtwdev, REG_LDO_SWR_CTRL, BIT(6)); + } + + return ret; +} + +static int rtw88xxa_llt_write(struct rtw_dev *rtwdev, u32 address, u32 data) +{ + u32 value = BIT_LLT_WRITE_ACCESS | (address << 8) | data; + int count = 0; + + rtw_write32(rtwdev, REG_LLT_INIT, value); + + do { + if (!rtw_read32_mask(rtwdev, REG_LLT_INIT, BIT(31) | BIT(30))) + break; + + if (count > 20) { + rtw_err(rtwdev, "Failed to poll write LLT done at %d!\n", + address); + return -EBUSY; + } + } while (++count); + + return 0; +} + +static int rtw88xxa_llt_init(struct rtw_dev *rtwdev, u32 boundary) +{ + u32 last_entry = 255; + int status = 0; + u32 i; + + for (i = 0; i < boundary - 1; i++) { + status = rtw88xxa_llt_write(rtwdev, i, i + 1); + if (status) + return status; + } + + status = rtw88xxa_llt_write(rtwdev, boundary - 1, 0xFF); + if (status) + return status; + + for (i = boundary; i < last_entry; i++) { + status = rtw88xxa_llt_write(rtwdev, i, i + 1); + if (status) + return status; + } + + status = rtw88xxa_llt_write(rtwdev, last_entry, boundary); + + return status; +} + +static void rtw88xxau_init_queue_reserved_page(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_fifo_conf *fifo = &rtwdev->fifo; + const struct rtw_page_table *pg_tbl = NULL; + u16 pubq_num; + u32 val32; + + switch (rtw_hci_type(rtwdev)) { + case RTW_HCI_TYPE_PCIE: + pg_tbl = &chip->page_table[1]; + break; + case RTW_HCI_TYPE_USB: + if (rtwdev->hci.bulkout_num == 2) + pg_tbl = &chip->page_table[2]; + else if (rtwdev->hci.bulkout_num == 3) + pg_tbl = &chip->page_table[3]; + else if (rtwdev->hci.bulkout_num == 4) + pg_tbl = &chip->page_table[4]; + break; + case RTW_HCI_TYPE_SDIO: + pg_tbl = &chip->page_table[0]; + break; + default: + break; + } + + pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - + pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; + + val32 = BIT_RQPN_NE(pg_tbl->nq_num, pg_tbl->exq_num); + rtw_write32(rtwdev, REG_RQPN_NPQ, val32); + + val32 = BIT_RQPN_HLP(pg_tbl->hq_num, pg_tbl->lq_num, pubq_num); + rtw_write32(rtwdev, REG_RQPN, val32); +} + +static void rtw88xxau_init_tx_buffer_boundary(struct rtw_dev *rtwdev) +{ + struct rtw_fifo_conf *fifo = &rtwdev->fifo; + + rtw_write8(rtwdev, REG_BCNQ_BDNY, fifo->rsvd_boundary); + rtw_write8(rtwdev, REG_MGQ_BDNY, fifo->rsvd_boundary); + rtw_write8(rtwdev, REG_WMAC_LBK_BF_HD, fifo->rsvd_boundary); + rtw_write8(rtwdev, REG_TRXFF_BNDY, fifo->rsvd_boundary); + rtw_write8(rtwdev, REG_DWBCN0_CTRL + 1, fifo->rsvd_boundary); +} + +static int rtw88xxau_init_queue_priority(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + u8 bulkout_num = rtwdev->hci.bulkout_num; + const struct rtw_rqpn *rqpn = NULL; + u16 txdma_pq_map; + + switch (rtw_hci_type(rtwdev)) { + case RTW_HCI_TYPE_PCIE: + rqpn = &chip->rqpn_table[1]; + break; + case RTW_HCI_TYPE_USB: + if (bulkout_num == 2) + rqpn = &chip->rqpn_table[2]; + else if (bulkout_num == 3) + rqpn = &chip->rqpn_table[3]; + else if (bulkout_num == 4) + rqpn = &chip->rqpn_table[4]; + else + return -EINVAL; + break; + case RTW_HCI_TYPE_SDIO: + rqpn = &chip->rqpn_table[0]; + break; + default: + return -EINVAL; + } + + rtwdev->fifo.rqpn = rqpn; + + txdma_pq_map = rtw_read16(rtwdev, REG_TXDMA_PQ_MAP) & 0x7; + txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi); + txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg); + txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk); + txdma_pq_map |= BIT_TXDMA_BEQ_MAP(rqpn->dma_map_be); + txdma_pq_map |= BIT_TXDMA_VIQ_MAP(rqpn->dma_map_vi); + txdma_pq_map |= BIT_TXDMA_VOQ_MAP(rqpn->dma_map_vo); + rtw_write16(rtwdev, REG_TXDMA_PQ_MAP, txdma_pq_map); + + /* Packet in Hi Queue Tx immediately (No constraint for ATIM Period). */ + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB && bulkout_num == 4) + rtw_write8(rtwdev, REG_HIQ_NO_LMT_EN, 0xff); + + return 0; +} + +static void rtw88xxa_init_wmac_setting(struct rtw_dev *rtwdev) +{ + rtw_write16(rtwdev, REG_RXFLTMAP0, 0xffff); + rtw_write16(rtwdev, REG_RXFLTMAP1, 0x0400); + rtw_write16(rtwdev, REG_RXFLTMAP2, 0xffff); + + rtw_write32(rtwdev, REG_MAR, 0xffffffff); + rtw_write32(rtwdev, REG_MAR + 4, 0xffffffff); +} + +static void rtw88xxa_init_adaptive_ctrl(struct rtw_dev *rtwdev) +{ + rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, 0xffff1); + rtw_write16(rtwdev, REG_RETRY_LIMIT, 0x3030); +} + +static void rtw88xxa_init_edca(struct rtw_dev *rtwdev) +{ + rtw_write16(rtwdev, REG_SPEC_SIFS, 0x100a); + rtw_write16(rtwdev, REG_MAC_SPEC_SIFS, 0x100a); + + rtw_write16(rtwdev, REG_SIFS, 0x100a); + rtw_write16(rtwdev, REG_SIFS + 2, 0x100a); + + rtw_write32(rtwdev, REG_EDCA_BE_PARAM, 0x005EA42B); + rtw_write32(rtwdev, REG_EDCA_BK_PARAM, 0x0000A44F); + rtw_write32(rtwdev, REG_EDCA_VI_PARAM, 0x005EA324); + rtw_write32(rtwdev, REG_EDCA_VO_PARAM, 0x002FA226); + + rtw_write8(rtwdev, REG_USTIME_TSF, 0x50); + rtw_write8(rtwdev, REG_USTIME_EDCA, 0x50); +} + +static void rtw88xxau_tx_aggregation(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + + rtw_write32_mask(rtwdev, REG_DWBCN0_CTRL, 0xf0, + chip->usb_tx_agg_desc_num); + + if (chip->id == RTW_CHIP_TYPE_8821A) + rtw_write8(rtwdev, REG_DWBCN1_CTRL, + chip->usb_tx_agg_desc_num << 1); +} + +static void rtw88xxa_init_beacon_parameters(struct rtw_dev *rtwdev) +{ + u16 val16; + + val16 = (BIT_DIS_TSF_UDT << 8) | BIT_DIS_TSF_UDT; + if (rtwdev->efuse.btcoex) + val16 |= BIT_EN_BCN_FUNCTION; + rtw_write16(rtwdev, REG_BCN_CTRL, val16); + + rtw_write32_mask(rtwdev, REG_TBTT_PROHIBIT, 0xfffff, WLAN_TBTT_TIME); + rtw_write8(rtwdev, REG_DRVERLYINT, 0x05); + rtw_write8(rtwdev, REG_BCNDMATIM, WLAN_BCN_DMA_TIME); + rtw_write16(rtwdev, REG_BCNTCFG, 0x4413); +} + +static void rtw88xxa_phy_bb_config(struct rtw_dev *rtwdev) +{ + u8 val8, crystal_cap; + + /* power on BB/RF domain */ + val8 = rtw_read8(rtwdev, REG_SYS_FUNC_EN); + val8 |= BIT_FEN_USBA; + rtw_write8(rtwdev, REG_SYS_FUNC_EN, val8); + + /* toggle BB reset */ + val8 |= BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST; + rtw_write8(rtwdev, REG_SYS_FUNC_EN, val8); + + rtw_write8(rtwdev, REG_RF_CTRL, + BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB); + rtw_write8(rtwdev, REG_RF_B_CTRL, + BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB); + + rtw_load_table(rtwdev, rtwdev->chip->bb_tbl); + rtw_load_table(rtwdev, rtwdev->chip->agc_tbl); + + crystal_cap = rtwdev->efuse.crystal_cap & 0x3F; + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) + rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x7FF80000, + crystal_cap | (crystal_cap << 6)); + else + rtw_write32_mask(rtwdev, REG_AFE_CTRL3, 0x00FFF000, + crystal_cap | (crystal_cap << 6)); +} + +static void rtw88xxa_phy_rf_config(struct rtw_dev *rtwdev) +{ + u8 rf_path; + + for (rf_path = 0; rf_path < rtwdev->hal.rf_path_num; rf_path++) + rtw_load_table(rtwdev, rtwdev->chip->rf_tbl[rf_path]); +} + +static void rtw8812a_config_1t(struct rtw_dev *rtwdev) +{ + /* BB OFDM RX Path_A */ + rtw_write32_mask(rtwdev, REG_RXPSEL, 0xff, 0x11); + + /* BB OFDM TX Path_A */ + rtw_write32_mask(rtwdev, REG_TXPSEL, MASKLWORD, 0x1111); + + /* BB CCK R/Rx Path_A */ + rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0c000000, 0x0); + + /* MCS support */ + rtw_write32_mask(rtwdev, REG_RX_MCS_LIMIT, 0xc0000060, 0x4); + + /* RF Path_B HSSI OFF */ + rtw_write32_mask(rtwdev, REG_3WIRE_SWB, 0xf, 0x4); + + /* RF Path_B Power Down */ + rtw_write32_mask(rtwdev, REG_LSSI_WRITE_B, MASKDWORD, 0); + + /* ADDA Path_B OFF */ + rtw_write32_mask(rtwdev, REG_AFE_PWR1_B, MASKDWORD, 0); + rtw_write32_mask(rtwdev, REG_AFE_PWR2_B, MASKDWORD, 0); +} + +static const u32 rtw88xxa_txscale_tbl[] = { + 0x081, 0x088, 0x090, 0x099, 0x0a2, 0x0ac, 0x0b6, 0x0c0, 0x0cc, 0x0d8, + 0x0e5, 0x0f2, 0x101, 0x110, 0x120, 0x131, 0x143, 0x156, 0x16a, 0x180, + 0x197, 0x1af, 0x1c8, 0x1e3, 0x200, 0x21e, 0x23e, 0x261, 0x285, 0x2ab, + 0x2d3, 0x2fe, 0x32b, 0x35c, 0x38e, 0x3c4, 0x3fe +}; + +static u32 rtw88xxa_get_bb_swing(struct rtw_dev *rtwdev, u8 band, u8 path) +{ + static const u32 swing2setting[4] = {0x200, 0x16a, 0x101, 0x0b6}; + struct rtw_efuse *efuse = &rtwdev->efuse; + u8 tx_bb_swing; + + if (band == RTW_BAND_2G) + tx_bb_swing = efuse->tx_bb_swing_setting_2g; + else + tx_bb_swing = efuse->tx_bb_swing_setting_5g; + + if (path == RF_PATH_B) + tx_bb_swing >>= 2; + tx_bb_swing &= 0x3; + + return swing2setting[tx_bb_swing]; +} + +static u8 rtw88xxa_get_swing_index(struct rtw_dev *rtwdev) +{ + u32 swing, table_value; + u8 i; + + swing = rtw88xxa_get_bb_swing(rtwdev, rtwdev->hal.current_band_type, + RF_PATH_A); + + for (i = 0; i < ARRAY_SIZE(rtw88xxa_txscale_tbl); i++) { + table_value = rtw88xxa_txscale_tbl[i]; + if (swing == table_value) + return i; + } + + return 24; +} + +static void rtw88xxa_pwrtrack_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 path; + + dm_info->default_ofdm_index = rtw88xxa_get_swing_index(rtwdev); + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8821A) + dm_info->default_cck_index = 0; + else + dm_info->default_cck_index = 24; + + for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) { + ewma_thermal_init(&dm_info->avg_thermal[path]); + dm_info->delta_power_index[path] = 0; + dm_info->delta_power_index_last[path] = 0; + } + + dm_info->pwr_trk_triggered = false; + dm_info->pwr_trk_init_trigger = true; + dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; +} + +void rtw88xxa_power_off(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd *const *enter_lps_flow) +{ + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); + enum usb_device_speed speed = rtwusb->udev->speed; + u16 ori_fsmc0; + u8 reg_cr; + + reg_cr = rtw_read8(rtwdev, REG_CR); + + /* Already powered off */ + if (reg_cr == 0 || reg_cr == 0xEA) + return; + + rtw_hci_stop(rtwdev); + + if (!rtwdev->efuse.btcoex) + rtw_write16_clr(rtwdev, REG_GPIO_MUXCFG, BIT_EN_SIC); + + /* set Reg 0xf008[3:4] to 2'11 to enable U1/U2 Mode in USB3.0. */ + if (speed == USB_SPEED_SUPER) + rtw_write8_set(rtwdev, REG_USB_MOD, 0x18); + + rtw_write32(rtwdev, REG_HISR0, 0xffffffff); + rtw_write32(rtwdev, REG_HISR1, 0xffffffff); + rtw_write32(rtwdev, REG_HIMR0, 0); + rtw_write32(rtwdev, REG_HIMR1, 0); + + if (rtwdev->efuse.btcoex) + rtw_coex_power_off_setting(rtwdev); + + ori_fsmc0 = rtw_read16(rtwdev, REG_APS_FSMCO); + rtw_write16(rtwdev, REG_APS_FSMCO, ori_fsmc0 & ~APS_FSMCO_HW_POWERDOWN); + + /* Stop Tx Report Timer. */ + rtw_write8_clr(rtwdev, REG_TX_RPT_CTRL, BIT(1)); + + /* Stop Rx */ + rtw_write8(rtwdev, REG_CR, 0); + + rtw_pwr_seq_parser(rtwdev, enter_lps_flow); + + if (rtw_read8(rtwdev, REG_MCUFW_CTRL) & BIT_RAM_DL_SEL) + rtw88xxa_reset_8051(rtwdev); + + rtw_write8_clr(rtwdev, REG_SYS_FUNC_EN + 1, BIT(2)); + rtw_write8(rtwdev, REG_MCUFW_CTRL, 0); + + rtw_pwr_seq_parser(rtwdev, rtwdev->chip->pwr_off_seq); + + if (ori_fsmc0 & APS_FSMCO_HW_POWERDOWN) + rtw_write16_set(rtwdev, REG_APS_FSMCO, APS_FSMCO_HW_POWERDOWN); + + clear_bit(RTW_FLAG_POWERON, rtwdev->flags); +} +EXPORT_SYMBOL(rtw88xxa_power_off); + +static void rtw88xxa_set_channel_bb_swing(struct rtw_dev *rtwdev, u8 band) +{ + rtw_write32_mask(rtwdev, REG_TXSCALE_A, BB_SWING_MASK, + rtw88xxa_get_bb_swing(rtwdev, band, RF_PATH_A)); + rtw_write32_mask(rtwdev, REG_TXSCALE_B, BB_SWING_MASK, + rtw88xxa_get_bb_swing(rtwdev, band, RF_PATH_B)); + rtw88xxa_pwrtrack_init(rtwdev); +} + +static void rtw8821a_set_ext_band_switch(struct rtw_dev *rtwdev, u8 band) +{ + rtw_write32_mask(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN, 0); + rtw_write32_mask(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL, 1); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0xf, 7); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0xf0, 7); + + if (band == RTW_BAND_2G) + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(29) | BIT(28), 1); + else + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(29) | BIT(28), 2); +} + +static void rtw8821a_phy_set_rfe_reg_24g(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + + /* Turn off RF PA and LNA */ + + /* 0xCB0[15:12] = 0x7 (LNA_On)*/ + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF000, 0x7); + /* 0xCB0[7:4] = 0x7 (PAPE_A)*/ + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF0, 0x7); + + if (efuse->ext_lna_2g) { + /* Turn on 2.4G External LNA */ + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 1); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x2); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x2); + } else { + /* Bypass 2.4G External LNA */ + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 0); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x7); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x7); + } +} + +static void rtw8821a_phy_set_rfe_reg_5g(struct rtw_dev *rtwdev) +{ + /* Turn ON RF PA and LNA */ + + /* 0xCB0[15:12] = 0x7 (LNA_On)*/ + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF000, 0x5); + /* 0xCB0[7:4] = 0x7 (PAPE_A)*/ + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xF0, 0x4); + + /* Bypass 2.4G External LNA */ + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(20), 0); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, BIT(22), 0); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(2, 0), 0x7); + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, GENMASK(10, 8), 0x7); +} + +static void rtw8812a_phy_set_rfe_reg_24g(struct rtw_dev *rtwdev) +{ + switch (rtwdev->efuse.rfe_option) { + case 0: + case 2: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + break; + case 1: + if (rtwdev->efuse.btcoex) { + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xffffff, 0x777777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0x33f00000, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + } else { + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + } + break; + case 3: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x54337770); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x54337770); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_ANTSEL_SW, 0x00000303, 0x1); + break; + case 4: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77777777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x001); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x001); + break; + case 5: + rtw_write8(rtwdev, REG_RFE_PINMUX_A + 2, 0x77); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77777777); + rtw_write8_clr(rtwdev, REG_RFE_INV_A + 3, BIT(0)); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + break; + case 6: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x07772770); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x07772770); + rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077); + rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077); + break; + default: + break; + } +} + +static void rtw8812a_phy_set_rfe_reg_5g(struct rtw_dev *rtwdev) +{ + switch (rtwdev->efuse.rfe_option) { + case 0: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + break; + case 1: + if (rtwdev->efuse.btcoex) { + rtw_write32_mask(rtwdev, REG_RFE_PINMUX_A, 0xffffff, 0x337717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, 0x33f00000, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + } else { + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337717); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x000); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x000); + } + break; + case 2: + case 4: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x77337777); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337777); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + break; + case 3: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x54337717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x54337717); + rtw_write32_mask(rtwdev, REG_RFE_INV_A, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + rtw_write32_mask(rtwdev, REG_ANTSEL_SW, 0x00000303, 0x1); + break; + case 5: + rtw_write8(rtwdev, REG_RFE_PINMUX_A + 2, 0x33); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x77337777); + rtw_write8_set(rtwdev, REG_RFE_INV_A + 3, BIT(0)); + rtw_write32_mask(rtwdev, REG_RFE_INV_B, RFE_INV_MASK, 0x010); + break; + case 6: + rtw_write32(rtwdev, REG_RFE_PINMUX_A, 0x07737717); + rtw_write32(rtwdev, REG_RFE_PINMUX_B, 0x07737717); + rtw_write32(rtwdev, REG_RFE_INV_A, 0x00000077); + rtw_write32(rtwdev, REG_RFE_INV_B, 0x00000077); + break; + default: + break; + } +} + +static void rtw88xxa_switch_band(struct rtw_dev *rtwdev, u8 new_band, u8 bw) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + u16 basic_rates, reg_41a; + + /* 8811au one antenna module doesn't support antenna div, so driver must + * control antenna band, otherwise one of the band will have issue + */ + if (chip->id == RTW_CHIP_TYPE_8821A && !rtwdev->efuse.btcoex && + rtwdev->efuse.ant_div_cfg == 0) + rtw8821a_set_ext_band_switch(rtwdev, new_band); + + if (new_band == RTW_BAND_2G) { + rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST); + + if (chip->id == RTW_CHIP_TYPE_8821A) { + rtw8821a_phy_set_rfe_reg_24g(rtwdev); + + rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 0); + } else { + rtw_write32_mask(rtwdev, REG_BWINDICATION, 0x3, 0x1); + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(17, 13), 0x17); + + if (bw == RTW_CHANNEL_WIDTH_20 && + rtwdev->hal.rf_type == RF_1T1R && + !rtwdev->efuse.ext_lna_2g) + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x02); + else + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x04); + + rtw_write32_mask(rtwdev, REG_CCASEL, 0x3, 0); + + rtw8812a_phy_set_rfe_reg_24g(rtwdev); + } + + rtw_write32_mask(rtwdev, REG_TXPSEL, 0xf0, 0x1); + rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0f000000, 0x1); + + basic_rates = BIT(DESC_RATE1M) | BIT(DESC_RATE2M) | + BIT(DESC_RATE5_5M) | BIT(DESC_RATE11M) | + BIT(DESC_RATE6M) | BIT(DESC_RATE12M) | + BIT(DESC_RATE24M); + rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, basic_rates); + + rtw_write8_clr(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN); + } else { /* RTW_BAND_5G */ + if (chip->id == RTW_CHIP_TYPE_8821A) + rtw8821a_phy_set_rfe_reg_5g(rtwdev); + + rtw_write8_set(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN); + + read_poll_timeout_atomic(rtw_read16, reg_41a, (reg_41a & 0x30) == 0x30, + 50, 2500, false, rtwdev, REG_TXPKT_EMPTY); + + rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST); + + if (chip->id == RTW_CHIP_TYPE_8821A) { + rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 1); + } else { + rtw_write32_mask(rtwdev, REG_BWINDICATION, 0x3, 0x2); + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(17, 13), 0x15); + rtw_write32_mask(rtwdev, REG_PDMFTH, GENMASK(3, 1), 0x04); + + rtw_write32_mask(rtwdev, REG_CCASEL, 0x3, 1); + + rtw8812a_phy_set_rfe_reg_5g(rtwdev); + } + + rtw_write32_mask(rtwdev, REG_TXPSEL, 0xf0, 0); + rtw_write32_mask(rtwdev, REG_CCK_RX, 0x0f000000, 0xf); + + basic_rates = BIT(DESC_RATE6M) | BIT(DESC_RATE12M) | + BIT(DESC_RATE24M); + rtw_write32_mask(rtwdev, REG_RRSR, 0xfffff, basic_rates); + } + + rtw88xxa_set_channel_bb_swing(rtwdev, new_band); +} + +int rtw88xxa_power_on(struct rtw_dev *rtwdev) +{ + struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); + const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_hal *hal = &rtwdev->hal; + int ret; + + if (test_bit(RTW_FLAG_POWERON, rtwdev->flags)) + return 0; + + /* Override rtw_chip_efuse_info_setup() */ + if (chip->id == RTW_CHIP_TYPE_8821A) + efuse->btcoex = rtw_read32_mask(rtwdev, REG_WL_BT_PWR_CTRL, + BIT_BT_FUNC_EN); + + /* Override rtw_chip_efuse_info_setup() */ + if (chip->id == RTW_CHIP_TYPE_8812A) + rtw8812a_read_amplifier_type(rtwdev); + + ret = rtw_hci_setup(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to setup hci\n"); + goto err; + } + + /* Revise for U2/U3 switch we can not update RF-A/B reset. + * Reset after MAC power on to prevent RF R/W error. + * Is it a right method? + */ + if (chip->id == RTW_CHIP_TYPE_8812A) { + rtw_write8(rtwdev, REG_RF_CTRL, 5); + rtw_write8(rtwdev, REG_RF_CTRL, 7); + rtw_write8(rtwdev, REG_RF_B_CTRL, 5); + rtw_write8(rtwdev, REG_RF_B_CTRL, 7); + } + + /* If HW didn't go through a complete de-initial procedure, + * it probably occurs some problem for double initial + * procedure. + */ + rtw88xxau_hw_reset(rtwdev); + + ret = rtw88xxau_init_power_on(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to power on\n"); + goto err; + } + + ret = rtw_set_trx_fifo_info(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to set trx fifo info\n"); + goto err; + } + + ret = rtw88xxa_llt_init(rtwdev, rtwdev->fifo.rsvd_boundary); + if (ret) { + rtw_err(rtwdev, "failed to init llt\n"); + goto err; + } + + rtw_write32_set(rtwdev, REG_TXDMA_OFFSET_CHK, BIT_DROP_DATA_EN); + + ret = rtw_wait_firmware_completion(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to wait firmware completion\n"); + goto err_off; + } + + ret = rtw_download_firmware(rtwdev, &rtwdev->fw); + if (ret) { + rtw_err(rtwdev, "failed to download firmware\n"); + goto err_off; + } + + rtw_write8(rtwdev, REG_HMETFR, 0xf); + + rtw_load_table(rtwdev, chip->mac_tbl); + + rtw88xxau_init_queue_reserved_page(rtwdev); + rtw88xxau_init_tx_buffer_boundary(rtwdev); + rtw88xxau_init_queue_priority(rtwdev); + + rtw_write16(rtwdev, REG_TRXFF_BNDY + 2, + chip->rxff_size - REPORT_BUF - 1); + + if (chip->id == RTW_CHIP_TYPE_8812A) + rtw_write8(rtwdev, REG_PBP, + u8_encode_bits(PBP_512, PBP_TX_MASK) | + u8_encode_bits(PBP_64, PBP_RX_MASK)); + + rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE); + + rtw_write32(rtwdev, REG_HIMR0, 0); + rtw_write32(rtwdev, REG_HIMR1, 0); + + rtw_write32_mask(rtwdev, REG_CR, 0x30000, 0x2); + + rtw88xxa_init_wmac_setting(rtwdev); + rtw88xxa_init_adaptive_ctrl(rtwdev); + rtw88xxa_init_edca(rtwdev); + + rtw_write8_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7)); + rtw_write8(rtwdev, REG_ACKTO, 0x80); + + rtw88xxau_tx_aggregation(rtwdev); + + rtw88xxa_init_beacon_parameters(rtwdev); + rtw_write8(rtwdev, REG_BCN_MAX_ERR, 0xff); + + rtw_hci_interface_cfg(rtwdev); + + /* usb3 rx interval */ + rtw_write8(rtwdev, REG_USB3_RXITV, 0x01); + + /* burst length=4, set 0x3400 for burst length=2 */ + rtw_write16(rtwdev, REG_RXDMA_STATUS, 0x7400); + rtw_write8(rtwdev, REG_RXDMA_STATUS + 1, 0xf5); + + /* 0x456 = 0x70, sugguested by Zhilin */ + if (chip->id == RTW_CHIP_TYPE_8821A) + rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0x5e); + else + rtw_write8(rtwdev, REG_AMPDU_MAX_TIME, 0x70); + + rtw_write32(rtwdev, REG_AMPDU_MAX_LENGTH, 0xffffffff); + rtw_write8(rtwdev, REG_USTIME_TSF, 0x50); + rtw_write8(rtwdev, REG_USTIME_EDCA, 0x50); + + if (rtwusb->udev->speed == USB_SPEED_SUPER) + /* Disable U1/U2 Mode to avoid 2.5G spur in USB3.0. */ + rtw_write8_clr(rtwdev, REG_USB_MOD, BIT(4) | BIT(3)); + + rtw_write8_set(rtwdev, REG_SINGLE_AMPDU_CTRL, BIT_EN_SINGLE_APMDU); + + /* for VHT packet length 11K */ + rtw_write8(rtwdev, REG_RX_PKT_LIMIT, 0x18); + + rtw_write8(rtwdev, REG_PIFS, 0x00); + + if (chip->id == RTW_CHIP_TYPE_8821A) { + /* 0x0a0a too small, it can't pass AC logo. change to 0x1f1f */ + rtw_write16(rtwdev, REG_MAX_AGGR_NUM, 0x1f1f); + rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL, 0x80); + rtw_write32(rtwdev, REG_FAST_EDCA_CTRL, 0x03087777); + } else { + rtw_write16(rtwdev, REG_MAX_AGGR_NUM, 0x1f1f); + rtw_write8_clr(rtwdev, REG_FWHW_TXQ_CTRL, BIT(7)); + } + + /* to prevent mac is reseted by bus. */ + rtw_write8_set(rtwdev, REG_RSV_CTRL, BIT(5) | BIT(6)); + + /* ARFB table 9 for 11ac 5G 2SS */ + rtw_write32(rtwdev, REG_ARFR0, 0x00000010); + rtw_write32(rtwdev, REG_ARFRH0, 0xfffff000); + + /* ARFB table 10 for 11ac 5G 1SS */ + rtw_write32(rtwdev, REG_ARFR1_V1, 0x00000010); + rtw_write32(rtwdev, REG_ARFRH1_V1, 0x003ff000); + + /* ARFB table 11 for 11ac 24G 1SS */ + rtw_write32(rtwdev, REG_ARFR2_V1, 0x00000015); + rtw_write32(rtwdev, REG_ARFRH2_V1, 0x003ff000); + + /* ARFB table 12 for 11ac 24G 2SS */ + rtw_write32(rtwdev, REG_ARFR3_V1, 0x00000015); + rtw_write32(rtwdev, REG_ARFRH3_V1, 0xffcff000); + + rtw_write8_set(rtwdev, REG_CR, BIT_MACTXEN | BIT_MACRXEN); + + rtw88xxa_phy_bb_config(rtwdev); + rtw88xxa_phy_rf_config(rtwdev); + + if (chip->id == RTW_CHIP_TYPE_8812A && hal->rf_path_num == 1) + rtw8812a_config_1t(rtwdev); + + rtw88xxa_switch_band(rtwdev, RTW_BAND_2G, RTW_CHANNEL_WIDTH_20); + + rtw_write32(rtwdev, RTW_SEC_CMD_REG, BIT(31) | BIT(30)); + + rtw_write8(rtwdev, REG_HWSEQ_CTRL, 0xff); + rtw_write32(rtwdev, REG_BAR_MODE_CTRL, 0x0201ffff); + rtw_write8(rtwdev, REG_NAV_CTRL + 2, 0); + + rtw_write8_clr(rtwdev, REG_GPIO_MUXCFG, BIT(5)); + + rtw_phy_init(rtwdev); + + rtw88xxa_pwrtrack_init(rtwdev); + + /* 0x4c6[3] 1: RTS BW = Data BW + * 0: RTS BW depends on CCA / secondary CCA result. + */ + rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT(3)); + + /* enable Tx report. */ + rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, 0x0f); + + /* Pretx_en, for WEP/TKIP SEC */ + rtw_write8(rtwdev, REG_EARLY_MODE_CONTROL + 3, 0x01); + + rtw_write16(rtwdev, REG_TX_RPT_TIME, 0x3df0); + + /* Reset USB mode switch setting */ + rtw_write8(rtwdev, REG_SYS_SDIO_CTRL, 0x0); + rtw_write8(rtwdev, REG_ACLK_MON, 0x0); + + rtw_write8(rtwdev, REG_USB_HRPWM, 0); + + /* ack for xmit mgmt frames. */ + rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL, BIT(12)); + + hal->cck_high_power = rtw_read32_mask(rtwdev, REG_CCK_RPT_FORMAT, + BIT_CCK_RPT_FORMAT); + + ret = rtw_hci_start(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to start hci\n"); + goto err_off; + } + + if (efuse->btcoex) { + rtw_coex_power_on_setting(rtwdev); + rtw_coex_init_hw_config(rtwdev, false); + } + + set_bit(RTW_FLAG_POWERON, rtwdev->flags); + + return 0; + +err_off: + chip->ops->power_off(rtwdev); + +err: + return ret; +} +EXPORT_SYMBOL(rtw88xxa_power_on); + +u32 rtw88xxa_phy_read_rf(struct rtw_dev *rtwdev, + enum rtw_rf_path rf_path, u32 addr, u32 mask) +{ + static const u32 pi_addr[2] = { REG_3WIRE_SWA, REG_3WIRE_SWB }; + static const u32 read_addr[2][2] = { + { REG_SI_READ_A, REG_SI_READ_B }, + { REG_PI_READ_A, REG_PI_READ_B } + }; + const struct rtw_chip_info *chip = rtwdev->chip; + const struct rtw_hal *hal = &rtwdev->hal; + bool set_cca, pi_mode; + u32 val; + + if (rf_path >= hal->rf_phy_num) { + rtw_err(rtwdev, "unsupported rf path (%d)\n", rf_path); + return INV_RF_DATA; + } + + /* CCA off to avoid reading the wrong value. + * Toggling CCA would affect RF 0x0, skip it. + */ + set_cca = addr != 0x0 && chip->id == RTW_CHIP_TYPE_8812A && + hal->cut_version != RTW_CHIP_VER_CUT_C; + + if (set_cca) + rtw_write32_set(rtwdev, REG_CCA2ND, BIT(3)); + + addr &= 0xff; + + pi_mode = rtw_read32_mask(rtwdev, pi_addr[rf_path], 0x4); + + rtw_write32_mask(rtwdev, REG_HSSI_READ, MASKBYTE0, addr); + + if (chip->id == RTW_CHIP_TYPE_8821A || + hal->cut_version == RTW_CHIP_VER_CUT_C) + udelay(20); + + val = rtw_read32_mask(rtwdev, read_addr[pi_mode][rf_path], mask); + + /* CCA on */ + if (set_cca) + rtw_write32_clr(rtwdev, REG_CCA2ND, BIT(3)); + + return val; +} +EXPORT_SYMBOL(rtw88xxa_phy_read_rf); + +static void rtw8812a_phy_fix_spur(struct rtw_dev *rtwdev, u8 channel, u8 bw) +{ + /* C cut Item12 ADC FIFO CLOCK */ + if (rtwdev->hal.cut_version == RTW_CHIP_VER_CUT_C) { + if (bw == RTW_CHANNEL_WIDTH_40 && channel == 11) + rtw_write32_mask(rtwdev, REG_ADCCLK, 0xC00, 0x3); + else + rtw_write32_mask(rtwdev, REG_ADCCLK, 0xC00, 0x2); + + /* A workaround to resolve 2480Mhz spur by setting ADC clock + * as 160M. + */ + if (bw == RTW_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14)) { + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x3); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1); + } else if (bw == RTW_CHANNEL_WIDTH_40 && channel == 11) { + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1); + } else if (bw != RTW_CHANNEL_WIDTH_80) { + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x2); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0); + } + } else { + /* A workaround to resolve 2480Mhz spur by setting ADC clock + * as 160M. + */ + if (bw == RTW_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14)) + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x3); + else if (channel <= 14) /* 2.4G only */ + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x300, 0x2); + } +} + +static void rtw88xxa_switch_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw) +{ + struct rtw_hal *hal = &rtwdev->hal; + u32 fc_area, rf_mod_ag; + u8 path; + + switch (channel) { + case 36 ... 48: + fc_area = 0x494; + break; + case 50 ... 64: + fc_area = 0x453; + break; + case 100 ... 116: + fc_area = 0x452; + break; + default: + if (channel >= 118) + fc_area = 0x412; + else + fc_area = 0x96a; + break; + } + + rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, fc_area); + + for (path = 0; path < hal->rf_path_num; path++) { + switch (channel) { + case 36 ... 64: + rf_mod_ag = 0x101; + break; + case 100 ... 140: + rf_mod_ag = 0x301; + break; + default: + if (channel > 140) + rf_mod_ag = 0x501; + else + rf_mod_ag = 0x000; + break; + } + + rtw_write_rf(rtwdev, path, RF_CFGCH, + RF18_RFSI_MASK | RF18_BAND_MASK, rf_mod_ag); + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) + rtw8812a_phy_fix_spur(rtwdev, channel, bw); + + rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_CHANNEL_MASK, channel); + } +} + +static void rtw88xxa_set_reg_bw(struct rtw_dev *rtwdev, u8 bw) +{ + u16 val16 = rtw_read16(rtwdev, REG_WMAC_TRXPTCL_CTL); + + val16 &= ~BIT_RFMOD; + if (bw == RTW_CHANNEL_WIDTH_80) + val16 |= BIT_RFMOD_80M; + else if (bw == RTW_CHANNEL_WIDTH_40) + val16 |= BIT_RFMOD_40M; + + rtw_write16(rtwdev, REG_WMAC_TRXPTCL_CTL, val16); +} + +static void rtw88xxa_post_set_bw_mode(struct rtw_dev *rtwdev, u8 channel, + u8 bw, u8 primary_chan_idx) +{ + struct rtw_hal *hal = &rtwdev->hal; + u8 txsc40 = 0, txsc20, txsc; + u8 reg_837, l1pkval; + + rtw88xxa_set_reg_bw(rtwdev, bw); + + txsc20 = primary_chan_idx; + if (bw == RTW_CHANNEL_WIDTH_80) { + if (txsc20 == RTW_SC_20_UPPER || txsc20 == RTW_SC_20_UPMOST) + txsc40 = RTW_SC_40_UPPER; + else + txsc40 = RTW_SC_40_LOWER; + } + + txsc = BIT_TXSC_20M(txsc20) | BIT_TXSC_40M(txsc40); + rtw_write8(rtwdev, REG_DATA_SC, txsc); + + reg_837 = rtw_read8(rtwdev, REG_BWINDICATION + 3); + + switch (bw) { + default: + case RTW_CHANNEL_WIDTH_20: + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300200); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0); + + if (hal->rf_type == RF_2T2R) + rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, 7); + else + rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, 8); + + break; + case RTW_CHANNEL_WIDTH_40: + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300201); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0); + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x3C, txsc); + rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf0000000, txsc); + + if (reg_837 & BIT(2)) { + l1pkval = 6; + } else { + if (hal->rf_type == RF_2T2R) + l1pkval = 7; + else + l1pkval = 8; + } + + rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, l1pkval); + + if (txsc == RTW_SC_20_UPPER) + rtw_write32_set(rtwdev, REG_RXSB, BIT(4)); + else + rtw_write32_clr(rtwdev, REG_RXSB, BIT(4)); + + break; + case RTW_CHANNEL_WIDTH_80: + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x003003C3, 0x00300202); + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 1); + rtw_write32_mask(rtwdev, REG_ADCCLK, 0x3C, txsc); + rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf0000000, txsc); + + if (reg_837 & BIT(2)) { + l1pkval = 5; + } else { + if (hal->rf_type == RF_2T2R) + l1pkval = 6; + else + l1pkval = 7; + } + + rtw_write32_mask(rtwdev, REG_L1PKTH, 0x03C00000, l1pkval); + + break; + } +} + +static void rtw88xxa_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) +{ + u8 path; + + for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) { + switch (bw) { + case RTW_CHANNEL_WIDTH_5: + case RTW_CHANNEL_WIDTH_10: + case RTW_CHANNEL_WIDTH_20: + default: + rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 3); + break; + case RTW_CHANNEL_WIDTH_40: + rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 1); + break; + case RTW_CHANNEL_WIDTH_80: + rtw_write_rf(rtwdev, path, RF_CFGCH, RF18_BW_MASK, 0); + break; + } + } +} + +void rtw88xxa_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw, + u8 primary_chan_idx) +{ + u8 old_band, new_band; + + if (rtw_read8(rtwdev, REG_CCK_CHECK) & BIT_CHECK_CCK_EN) + old_band = RTW_BAND_5G; + else + old_band = RTW_BAND_2G; + + if (channel > 14) + new_band = RTW_BAND_5G; + else + new_band = RTW_BAND_2G; + + if (new_band != old_band) + rtw88xxa_switch_band(rtwdev, new_band, bw); + + rtw88xxa_switch_channel(rtwdev, channel, bw); + + rtw88xxa_post_set_bw_mode(rtwdev, channel, bw, primary_chan_idx); + + if (rtwdev->chip->id == RTW_CHIP_TYPE_8812A) + rtw8812a_phy_fix_spur(rtwdev, channel, bw); + + rtw88xxa_set_channel_rf(rtwdev, channel, bw); +} +EXPORT_SYMBOL(rtw88xxa_set_channel); + +void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat, + s8 (*cck_rx_pwr)(u8 lna_idx, u8 vga_idx)) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_jaguar_phy_status_rpt *rpt; + u8 gain[RTW_RF_PATH_MAX], rssi, i; + s8 rx_pwr_db, power_a, power_b; + const s8 min_rx_power = -120; + u8 lna_idx, vga_idx; + + rpt = (struct rtw_jaguar_phy_status_rpt *)phy_status; + + if (pkt_stat->rate <= DESC_RATE11M) { + lna_idx = le32_get_bits(rpt->w1, RTW_JGRPHY_W1_AGC_RPT_LNA_IDX); + vga_idx = le32_get_bits(rpt->w1, RTW_JGRPHY_W1_AGC_RPT_VGA_IDX); + + rx_pwr_db = cck_rx_pwr(lna_idx, vga_idx); + + pkt_stat->rx_power[RF_PATH_A] = rx_pwr_db; + pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1); + dm_info->rssi[RF_PATH_A] = pkt_stat->rssi; + pkt_stat->bw = RTW_CHANNEL_WIDTH_20; + pkt_stat->signal_power = rx_pwr_db; + } else { /* OFDM rate */ + gain[RF_PATH_A] = le32_get_bits(rpt->w0, RTW_JGRPHY_W0_GAIN_A); + gain[RF_PATH_B] = le32_get_bits(rpt->w0, RTW_JGRPHY_W0_GAIN_B); + + for (i = RF_PATH_A; i < rtwdev->hal.rf_path_num; i++) { + pkt_stat->rx_power[i] = gain[i] - 110; + rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[i], 1); + dm_info->rssi[i] = rssi; + } + + pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, + rtwdev->hal.rf_path_num); + + power_a = pkt_stat->rx_power[RF_PATH_A]; + power_b = pkt_stat->rx_power[RF_PATH_B]; + if (rtwdev->hal.rf_path_num == 1) + power_b = power_a; + + pkt_stat->signal_power = max3(power_a, power_b, min_rx_power); + } +} +EXPORT_SYMBOL(rtw88xxa_query_phy_status); + +static void +rtw88xxa_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, + u8 rs, u32 *phy_pwr_idx) +{ + static const u32 offset_txagc[2] = { + REG_TX_AGC_A_CCK_11_CCK_1, REG_TX_AGC_B_CCK_11_CCK_1 + }; + u8 rate, rate_idx, pwr_index, shift; + struct rtw_hal *hal = &rtwdev->hal; + bool write_1ss_mcs9; + u32 mask; + int j; + + for (j = 0; j < rtw_rate_size[rs]; j++) { + rate = rtw_rate_section[rs][j]; + + pwr_index = hal->tx_pwr_tbl[path][rate]; + + shift = rate & 0x3; + *phy_pwr_idx |= ((u32)pwr_index << (shift * 8)); + + write_1ss_mcs9 = rate == DESC_RATEVHT1SS_MCS9 && + hal->rf_path_num == 1; + + if (write_1ss_mcs9) + mask = MASKLWORD; + else + mask = MASKDWORD; + + if (shift == 0x3 || write_1ss_mcs9) { + rate_idx = rate & 0xfc; + if (rate >= DESC_RATEVHT1SS_MCS0) + rate_idx -= 0x10; + + rtw_write32_mask(rtwdev, offset_txagc[path] + rate_idx, + mask, *phy_pwr_idx); + + *phy_pwr_idx = 0; + } + } +} + +static void rtw88xxa_tx_power_training(struct rtw_dev *rtwdev, u8 bw, + u8 channel, u8 path) +{ + static const u32 write_offset[] = { + REG_TX_PWR_TRAINING_A, REG_TX_PWR_TRAINING_B, + }; + u32 power_level, write_data; + u8 i; + + power_level = rtwdev->hal.tx_pwr_tbl[path][DESC_RATEMCS7]; + write_data = 0; + + for (i = 0; i < 3; i++) { + if (i == 0) + power_level -= 10; + else if (i == 1) + power_level -= 8; + else + power_level -= 6; + + write_data |= max_t(u32, power_level, 2) << (i * 8); + } + + rtw_write32_mask(rtwdev, write_offset[path], 0xffffff, write_data); +} + +void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev) +{ + struct rtw_hal *hal = &rtwdev->hal; + u32 phy_pwr_idx = 0; + int rs, path; + + for (path = 0; path < hal->rf_path_num; path++) { + for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) { + if (hal->rf_path_num == 1 && + (rs == RTW_RATE_SECTION_HT_2S || + rs == RTW_RATE_SECTION_VHT_2S)) + continue; + + if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags) && + rs > RTW_RATE_SECTION_OFDM) + continue; + + if (hal->current_band_type == RTW_BAND_5G && + rs == RTW_RATE_SECTION_CCK) + continue; + + rtw88xxa_set_tx_power_index_by_rate(rtwdev, path, rs, + &phy_pwr_idx); + } + + rtw88xxa_tx_power_training(rtwdev, hal->current_band_width, + hal->current_channel, path); + } +} +EXPORT_SYMBOL(rtw88xxa_set_tx_power_index); + +void rtw88xxa_false_alarm_statistics(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u32 cck_fa_cnt, ofdm_fa_cnt; + u32 crc32_cnt, cca32_cnt; + u32 cck_enable; + + cck_enable = rtw_read32(rtwdev, REG_RXPSEL) & BIT(28); + cck_fa_cnt = rtw_read16(rtwdev, REG_FA_CCK); + ofdm_fa_cnt = rtw_read16(rtwdev, REG_FA_OFDM); + + dm_info->cck_fa_cnt = cck_fa_cnt; + dm_info->ofdm_fa_cnt = ofdm_fa_cnt; + dm_info->total_fa_cnt = ofdm_fa_cnt; + if (cck_enable) + dm_info->total_fa_cnt += cck_fa_cnt; + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_CCK); + dm_info->cck_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD); + dm_info->cck_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_OFDM); + dm_info->ofdm_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD); + dm_info->ofdm_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_HT); + dm_info->ht_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD); + dm_info->ht_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_VHT); + dm_info->vht_ok_cnt = u32_get_bits(crc32_cnt, MASKLWORD); + dm_info->vht_err_cnt = u32_get_bits(crc32_cnt, MASKHWORD); + + cca32_cnt = rtw_read32(rtwdev, REG_CCA_OFDM); + dm_info->ofdm_cca_cnt = u32_get_bits(cca32_cnt, MASKHWORD); + dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt; + if (cck_enable) { + cca32_cnt = rtw_read32(rtwdev, REG_CCA_CCK); + dm_info->cck_cca_cnt = u32_get_bits(cca32_cnt, MASKLWORD); + dm_info->total_cca_cnt += dm_info->cck_cca_cnt; + } + + rtw_write32_set(rtwdev, REG_FAS, BIT(17)); + rtw_write32_clr(rtwdev, REG_FAS, BIT(17)); + rtw_write32_clr(rtwdev, REG_CCK0_FAREPORT, BIT(15)); + rtw_write32_set(rtwdev, REG_CCK0_FAREPORT, BIT(15)); + rtw_write32_set(rtwdev, REG_CNTRST, BIT(0)); + rtw_write32_clr(rtwdev, REG_CNTRST, BIT(0)); +} +EXPORT_SYMBOL(rtw88xxa_false_alarm_statistics); + +void rtw88xxa_iqk_backup_mac_bb(struct rtw_dev *rtwdev, + u32 *macbb_backup, + const u32 *backup_macbb_reg, + u32 macbb_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* save MACBB default value */ + for (i = 0; i < macbb_num; i++) + macbb_backup[i] = rtw_read32(rtwdev, backup_macbb_reg[i]); +} +EXPORT_SYMBOL(rtw88xxa_iqk_backup_mac_bb); + +void rtw88xxa_iqk_backup_afe(struct rtw_dev *rtwdev, u32 *afe_backup, + const u32 *backup_afe_reg, u32 afe_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Save AFE Parameters */ + for (i = 0; i < afe_num; i++) + afe_backup[i] = rtw_read32(rtwdev, backup_afe_reg[i]); +} +EXPORT_SYMBOL(rtw88xxa_iqk_backup_afe); + +void rtw88xxa_iqk_restore_mac_bb(struct rtw_dev *rtwdev, + u32 *macbb_backup, + const u32 *backup_macbb_reg, + u32 macbb_num) +{ + u32 i; + + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + /* Reload MacBB Parameters */ + for (i = 0; i < macbb_num; i++) + rtw_write32(rtwdev, backup_macbb_reg[i], macbb_backup[i]); +} +EXPORT_SYMBOL(rtw88xxa_iqk_restore_mac_bb); + +void rtw88xxa_iqk_configure_mac(struct rtw_dev *rtwdev) +{ + /* [31] = 0 --> Page C */ + rtw_write32_mask(rtwdev, REG_CCASEL, BIT(31), 0x0); + + rtw_write8(rtwdev, REG_TXPAUSE, 0x3f); + rtw_write32_mask(rtwdev, REG_BCN_CTRL, + (BIT_EN_BCN_FUNCTION << 8) | BIT_EN_BCN_FUNCTION, 0x0); + + /* RX ante off */ + rtw_write8(rtwdev, REG_RXPSEL, 0x00); + + /* CCA off */ + rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf, 0xc); + + /* CCK RX path off */ + rtw_write8(rtwdev, REG_CCK_RX + 3, 0xf); +} +EXPORT_SYMBOL(rtw88xxa_iqk_configure_mac); + +bool rtw88xxa_iqk_finish(int average, int threshold, + int *x_temp, int *y_temp, int *x, int *y, + bool break_inner, bool break_outer) +{ + bool finish = false; + int i, ii, dx, dy; + + for (i = 0; i < average; i++) { + for (ii = i + 1; ii < average; ii++) { + dx = abs_diff(x_temp[i] >> 21, x_temp[ii] >> 21); + dy = abs_diff(y_temp[i] >> 21, y_temp[ii] >> 21); + + if (dx < threshold && dy < threshold) { + *x = ((x_temp[i] >> 21) + (x_temp[ii] >> 21)); + *y = ((y_temp[i] >> 21) + (y_temp[ii] >> 21)); + + *x /= 2; + *y /= 2; + + finish = true; + + if (break_inner) + break; + } + } + + if (finish && break_outer) + break; + } + + return finish; +} +EXPORT_SYMBOL(rtw88xxa_iqk_finish); + +static void rtw88xxa_pwrtrack_set(struct rtw_dev *rtwdev, u8 tx_rate, u8 path) +{ + static const u32 reg_txscale[2] = { REG_TXSCALE_A, REG_TXSCALE_B }; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 cck_swing_idx, ofdm_swing_idx; + u8 pwr_tracking_limit; + + switch (tx_rate) { + case DESC_RATE1M ... DESC_RATE11M: + pwr_tracking_limit = 32; + break; + case DESC_RATE6M ... DESC_RATE48M: + case DESC_RATEMCS3 ... DESC_RATEMCS4: + case DESC_RATEMCS11 ... DESC_RATEMCS12: + case DESC_RATEVHT1SS_MCS3 ... DESC_RATEVHT1SS_MCS4: + case DESC_RATEVHT2SS_MCS3 ... DESC_RATEVHT2SS_MCS4: + pwr_tracking_limit = 30; + break; + case DESC_RATE54M: + case DESC_RATEMCS5 ... DESC_RATEMCS7: + case DESC_RATEMCS13 ... DESC_RATEMCS15: + case DESC_RATEVHT1SS_MCS5 ... DESC_RATEVHT1SS_MCS6: + case DESC_RATEVHT2SS_MCS5 ... DESC_RATEVHT2SS_MCS6: + pwr_tracking_limit = 28; + break; + case DESC_RATEMCS0 ... DESC_RATEMCS2: + case DESC_RATEMCS8 ... DESC_RATEMCS10: + case DESC_RATEVHT1SS_MCS0 ... DESC_RATEVHT1SS_MCS2: + case DESC_RATEVHT2SS_MCS0 ... DESC_RATEVHT2SS_MCS2: + pwr_tracking_limit = 34; + break; + case DESC_RATEVHT1SS_MCS7: + case DESC_RATEVHT2SS_MCS7: + pwr_tracking_limit = 26; + break; + default: + case DESC_RATEVHT1SS_MCS8: + case DESC_RATEVHT2SS_MCS8: + pwr_tracking_limit = 24; + break; + case DESC_RATEVHT1SS_MCS9: + case DESC_RATEVHT2SS_MCS9: + pwr_tracking_limit = 22; + break; + } + + cck_swing_idx = dm_info->delta_power_index[path] + dm_info->default_cck_index; + ofdm_swing_idx = dm_info->delta_power_index[path] + dm_info->default_ofdm_index; + + if (ofdm_swing_idx > pwr_tracking_limit) { + if (path == RF_PATH_A) + dm_info->txagc_remnant_cck = cck_swing_idx - pwr_tracking_limit; + dm_info->txagc_remnant_ofdm[path] = ofdm_swing_idx - pwr_tracking_limit; + + ofdm_swing_idx = pwr_tracking_limit; + } else if (ofdm_swing_idx == 0) { + if (path == RF_PATH_A) + dm_info->txagc_remnant_cck = cck_swing_idx; + dm_info->txagc_remnant_ofdm[path] = ofdm_swing_idx; + } else { + if (path == RF_PATH_A) + dm_info->txagc_remnant_cck = 0; + dm_info->txagc_remnant_ofdm[path] = 0; + } + + rtw_write32_mask(rtwdev, reg_txscale[path], GENMASK(31, 21), + rtw88xxa_txscale_tbl[ofdm_swing_idx]); +} + +void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev, + void (*do_lck)(struct rtw_dev *rtwdev), + void (*do_iqk)(struct rtw_dev *rtwdev)) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_hal *hal = &rtwdev->hal; + struct rtw_swing_table swing_table; + s8 remnant_pre[RTW_RF_PATH_MAX]; + u8 thermal_value, delta, path; + bool need_iqk; + + rtw_phy_config_swing_table(rtwdev, &swing_table); + + if (rtwdev->efuse.thermal_meter[0] == 0xff) { + pr_err_once("efuse thermal meter is 0xff\n"); + return; + } + + thermal_value = rtw_read_rf(rtwdev, RF_PATH_A, RF_T_METER, 0xfc00); + + rtw_phy_pwrtrack_avg(rtwdev, thermal_value, RF_PATH_A); + + need_iqk = rtw_phy_pwrtrack_need_iqk(rtwdev); + + if (need_iqk && do_lck) + do_lck(rtwdev); + + if (dm_info->pwr_trk_init_trigger) + dm_info->pwr_trk_init_trigger = false; + else if (!rtw_phy_pwrtrack_thermal_changed(rtwdev, thermal_value, + RF_PATH_A)) + goto iqk; + + delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A); + + for (path = RF_PATH_A; path < hal->rf_path_num; path++) { + remnant_pre[path] = dm_info->txagc_remnant_ofdm[path]; + + dm_info->delta_power_index[path] = + rtw_phy_pwrtrack_get_pwridx(rtwdev, &swing_table, path, + RF_PATH_A, delta); + + if (dm_info->delta_power_index[path] != + dm_info->delta_power_index_last[path]) { + dm_info->delta_power_index_last[path] = + dm_info->delta_power_index[path]; + + rtw88xxa_pwrtrack_set(rtwdev, dm_info->tx_rate, path); + } + } + + for (path = RF_PATH_A; path < hal->rf_path_num; path++) { + if (remnant_pre[path] != dm_info->txagc_remnant_ofdm[path]) { + rtw_phy_set_tx_power_level(rtwdev, + hal->current_channel); + break; + } + } + +iqk: + if (need_iqk) + do_iqk(rtwdev); +} +EXPORT_SYMBOL(rtw88xxa_phy_pwrtrack); + +void rtw88xxa_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl) +{ + static const u8 pd[CCK_PD_LV_MAX] = {0x40, 0x83, 0xcd, 0xdd, 0xed}; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + /* Override rtw_phy_cck_pd_lv_link(). It implements something + * like type 2/3/4. We need type 1 here. + */ + if (rtw_is_assoc(rtwdev)) { + if (dm_info->min_rssi > 60) { + new_lvl = CCK_PD_LV3; + } else if (dm_info->min_rssi > 35) { + new_lvl = CCK_PD_LV2; + } else if (dm_info->min_rssi > 20) { + if (dm_info->cck_fa_avg > 500) + new_lvl = CCK_PD_LV2; + else if (dm_info->cck_fa_avg < 250) + new_lvl = CCK_PD_LV1; + else + return; + } else { + new_lvl = CCK_PD_LV1; + } + } + + rtw_dbg(rtwdev, RTW_DBG_PHY, "lv: (%d) -> (%d)\n", + dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A], new_lvl); + + if (dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] == new_lvl) + return; + + dm_info->cck_fa_avg = CCK_FA_AVG_RESET; + dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] = new_lvl; + + rtw_write8(rtwdev, REG_CCK_PD_TH, pd[new_lvl]); +} +EXPORT_SYMBOL(rtw88xxa_phy_cck_pd_set); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821a/8811a/8812a common code"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw88xxa.h b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h new file mode 100644 index 00000000000000..09a45c1a412954 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw88xxa.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2024 Realtek Corporation + */ + +#ifndef __RTW88XXA_H__ +#define __RTW88XXA_H__ + +#include +#include "reg.h" + +struct rtw8821au_efuse { + u8 res4[48]; /* 0xd0 */ + u8 vid[2]; /* 0x100 */ + u8 pid[2]; + u8 res8[3]; + u8 mac_addr[ETH_ALEN]; /* 0x107 */ + u8 res9[243]; +} __packed; + +struct rtw8812au_efuse { + u8 vid[2]; /* 0xd0 */ + u8 pid[2]; /* 0xd2 */ + u8 res0[3]; + u8 mac_addr[ETH_ALEN]; /* 0xd7 */ + u8 res1[291]; +} __packed; + +struct rtw88xxa_efuse { + __le16 rtl_id; + u8 res0[6]; /* 0x02 */ + u8 usb_mode; /* 0x08 */ + u8 res1[7]; /* 0x09 */ + + /* power index for four RF paths */ + struct rtw_txpwr_idx txpwr_idx_table[4]; + + u8 channel_plan; /* 0xb8 */ + u8 xtal_k; + u8 thermal_meter; + u8 iqk_lck; + u8 pa_type; /* 0xbc */ + u8 lna_type_2g; /* 0xbd */ + u8 res2; + u8 lna_type_5g; /* 0xbf */ + u8 res3; + u8 rf_board_option; /* 0xc1 */ + u8 rf_feature_option; + u8 rf_bt_setting; + u8 eeprom_version; + u8 eeprom_customer_id; /* 0xc5 */ + u8 tx_bb_swing_setting_2g; + u8 tx_bb_swing_setting_5g; + u8 tx_pwr_calibrate_rate; + u8 rf_antenna_option; /* 0xc9 */ + u8 rfe_option; + u8 country_code[2]; + u8 res4[3]; + union { + struct rtw8821au_efuse rtw8821au; + struct rtw8812au_efuse rtw8812au; + }; +} __packed; + +static_assert(sizeof(struct rtw88xxa_efuse) == 512); + +#define WLAN_BCN_DMA_TIME 0x02 +#define WLAN_TBTT_PROHIBIT 0x04 +#define WLAN_TBTT_HOLD_TIME 0x064 +#define WLAN_TBTT_TIME (WLAN_TBTT_PROHIBIT |\ + (WLAN_TBTT_HOLD_TIME << BIT_SHIFT_TBTT_HOLD_TIME_AP)) + +struct rtw_jaguar_phy_status_rpt { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; +} __packed; + +#define RTW_JGRPHY_W0_GAIN_A GENMASK(6, 0) +#define RTW_JGRPHY_W0_TRSW_A BIT(7) +#define RTW_JGRPHY_W0_GAIN_B GENMASK(14, 8) +#define RTW_JGRPHY_W0_TRSW_B BIT(15) +#define RTW_JGRPHY_W0_CHL_NUM GENMASK(25, 16) +#define RTW_JGRPHY_W0_SUB_CHNL GENMASK(29, 26) +#define RTW_JGRPHY_W0_R_RFMOD GENMASK(31, 30) + +/* CCK: */ +#define RTW_JGRPHY_W1_SIG_QUAL GENMASK(7, 0) +#define RTW_JGRPHY_W1_AGC_RPT_VGA_IDX GENMASK(12, 8) +#define RTW_JGRPHY_W1_AGC_RPT_LNA_IDX GENMASK(15, 13) +#define RTW_JGRPHY_W1_BB_POWER GENMASK(23, 16) +/* OFDM: */ +#define RTW_JGRPHY_W1_PWDB_ALL GENMASK(7, 0) +#define RTW_JGRPHY_W1_CFO_SHORT_A GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W1_CFO_SHORT_B GENMASK(23, 16) /* s8 */ +#define RTW_JGRPHY_W1_BT_RF_CH_MSB GENMASK(31, 30) + +#define RTW_JGRPHY_W2_ANT_DIV_SW_A BIT(0) +#define RTW_JGRPHY_W2_ANT_DIV_SW_B BIT(1) +#define RTW_JGRPHY_W2_BT_RF_CH_LSB GENMASK(7, 2) +#define RTW_JGRPHY_W2_CFO_TAIL_A GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W2_CFO_TAIL_B GENMASK(23, 16) /* s8 */ +#define RTW_JGRPHY_W2_PCTS_MSK_RPT_0 GENMASK(31, 24) + +#define RTW_JGRPHY_W3_PCTS_MSK_RPT_1 GENMASK(7, 0) +/* Stream 1 and 2 RX EVM: */ +#define RTW_JGRPHY_W3_RXEVM_1 GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W3_RXEVM_2 GENMASK(23, 16) /* s8 */ +#define RTW_JGRPHY_W3_RXSNR_A GENMASK(31, 24) /* s8 */ + +#define RTW_JGRPHY_W4_RXSNR_B GENMASK(7, 0) /* s8 */ +#define RTW_JGRPHY_W4_PCTS_MSK_RPT_2 GENMASK(21, 8) +#define RTW_JGRPHY_W4_PCTS_RPT_VALID BIT(22) +#define RTW_JGRPHY_W4_RXEVM_3 GENMASK(31, 24) /* s8 */ + +#define RTW_JGRPHY_W5_RXEVM_4 GENMASK(7, 0) /* s8 */ +/* 8812a, stream 1 and 2 CSI: */ +#define RTW_JGRPHY_W5_CSI_CURRENT_1 GENMASK(15, 8) +#define RTW_JGRPHY_W5_CSI_CURRENT_2 GENMASK(23, 16) +/* 8814a: */ +#define RTW_JGRPHY_W5_RXSNR_C GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W5_RXSNR_D GENMASK(23, 16) /* s8 */ +#define RTW_JGRPHY_W5_GAIN_C GENMASK(30, 24) +#define RTW_JGRPHY_W5_TRSW_C BIT(31) + +#define RTW_JGRPHY_W6_GAIN_D GENMASK(6, 0) +#define RTW_JGRPHY_W6_TRSW_D BIT(7) +#define RTW_JGRPHY_W6_SIGEVM GENMASK(15, 8) /* s8 */ +#define RTW_JGRPHY_W6_ANTIDX_ANTC GENMASK(18, 16) +#define RTW_JGRPHY_W6_ANTIDX_ANTD GENMASK(21, 19) +#define RTW_JGRPHY_W6_DPDT_CTRL_KEEP BIT(22) +#define RTW_JGRPHY_W6_GNT_BT_KEEP BIT(23) +#define RTW_JGRPHY_W6_ANTIDX_ANTA GENMASK(26, 24) +#define RTW_JGRPHY_W6_ANTIDX_ANTB GENMASK(29, 27) +#define RTW_JGRPHY_W6_HW_ANTSW_OCCUR GENMASK(31, 30) + +#define RF18_BW_MASK (BIT(11) | BIT(10)) + +void rtw88xxa_efuse_grant(struct rtw_dev *rtwdev, bool on); +int rtw88xxa_read_efuse(struct rtw_dev *rtwdev, u8 *log_map); +void rtw88xxa_power_off(struct rtw_dev *rtwdev, + const struct rtw_pwr_seq_cmd *const *enter_lps_flow); +int rtw88xxa_power_on(struct rtw_dev *rtwdev); +u32 rtw88xxa_phy_read_rf(struct rtw_dev *rtwdev, + enum rtw_rf_path rf_path, u32 addr, u32 mask); +void rtw88xxa_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw, + u8 primary_chan_idx); +void rtw88xxa_query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat, + s8 (*cck_rx_pwr)(u8 lna_idx, u8 vga_idx)); +void rtw88xxa_set_tx_power_index(struct rtw_dev *rtwdev); +void rtw88xxa_false_alarm_statistics(struct rtw_dev *rtwdev); +void rtw88xxa_iqk_backup_mac_bb(struct rtw_dev *rtwdev, + u32 *macbb_backup, + const u32 *backup_macbb_reg, + u32 macbb_num); +void rtw88xxa_iqk_backup_afe(struct rtw_dev *rtwdev, u32 *afe_backup, + const u32 *backup_afe_reg, u32 afe_num); +void rtw88xxa_iqk_restore_mac_bb(struct rtw_dev *rtwdev, + u32 *macbb_backup, + const u32 *backup_macbb_reg, + u32 macbb_num); +void rtw88xxa_iqk_configure_mac(struct rtw_dev *rtwdev); +bool rtw88xxa_iqk_finish(int average, int threshold, + int *x_temp, int *y_temp, int *x, int *y, + bool break_inner, bool break_outer); +void rtw88xxa_phy_pwrtrack(struct rtw_dev *rtwdev, + void (*do_lck)(struct rtw_dev *rtwdev), + void (*do_iqk)(struct rtw_dev *rtwdev)); +void rtw88xxa_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl); + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c index 66f9419588cf3a..90fc8a5fa89e7d 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -187,11 +187,10 @@ void rtw_update_rx_freq_from_ie(struct rtw_dev *rtwdev, struct sk_buff *skb, } EXPORT_SYMBOL(rtw_update_rx_freq_from_ie); -void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *rx_status, - u8 *phy_status) +static void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rx_status) { struct ieee80211_hw *hw = rtwdev->hw; u8 path; @@ -235,12 +234,75 @@ void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, else rx_status->bw = RATE_INFO_BW_20; - rx_status->signal = pkt_stat->signal_power; - for (path = 0; path < rtwdev->hal.rf_path_num; path++) { - rx_status->chains |= BIT(path); - rx_status->chain_signal[path] = pkt_stat->rx_power[path]; + if (pkt_stat->phy_status) { + rx_status->signal = pkt_stat->signal_power; + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { + rx_status->chains |= BIT(path); + rx_status->chain_signal[path] = pkt_stat->rx_power[path]; + } + } else { + rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; } rtw_rx_addr_match(rtwdev, pkt_stat, hdr); + + /* Rtl8723cs driver checks for size < 14 or size > 8192 and + * simply drops the packet. + */ + if (rtwdev->chip->id == RTW_CHIP_TYPE_8703B && pkt_stat->pkt_len == 0) { + rx_status->flag |= RX_FLAG_NO_PSDU; + rtw_dbg(rtwdev, RTW_DBG_RX, "zero length packet"); + } +} + +void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_rx_status *rx_status) +{ + u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; + struct rtw_rx_desc *rx_desc = rx_desc8; + struct ieee80211_hdr *hdr; + u32 enc_type, swdec; + void *phy_status; + + memset(pkt_stat, 0, sizeof(*pkt_stat)); + + pkt_stat->pkt_len = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_PKT_LEN); + pkt_stat->crc_err = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_CRC32); + pkt_stat->icv_err = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_ICV_ERR); + pkt_stat->drv_info_sz = le32_get_bits(rx_desc->w0, + RTW_RX_DESC_W0_DRV_INFO_SIZE); + enc_type = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_ENC_TYPE); + pkt_stat->shift = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_SHIFT); + pkt_stat->phy_status = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_PHYST); + swdec = le32_get_bits(rx_desc->w0, RTW_RX_DESC_W0_SWDEC); + pkt_stat->decrypted = !swdec && enc_type != RX_DESC_ENC_NONE; + + pkt_stat->cam_id = le32_get_bits(rx_desc->w1, RTW_RX_DESC_W1_MACID); + + pkt_stat->is_c2h = le32_get_bits(rx_desc->w2, RTW_RX_DESC_W2_C2H); + pkt_stat->ppdu_cnt = le32_get_bits(rx_desc->w2, RTW_RX_DESC_W2_PPDU_CNT); + + pkt_stat->rate = le32_get_bits(rx_desc->w3, RTW_RX_DESC_W3_RX_RATE); + + pkt_stat->bw = le32_get_bits(rx_desc->w4, RTW_RX_DESC_W4_BW); + + pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL); + + /* drv_info_sz is in unit of 8-bytes */ + pkt_stat->drv_info_sz *= 8; + + /* c2h cmd pkt's rx/phy status is not interested */ + if (pkt_stat->is_c2h) + return; + + phy_status = rx_desc8 + desc_sz + pkt_stat->shift; + hdr = phy_status + pkt_stat->drv_info_sz; + pkt_stat->hdr = hdr; + + if (pkt_stat->phy_status) + rtwdev->chip->ops->query_phy_status(rtwdev, phy_status, pkt_stat); + + rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status); } -EXPORT_SYMBOL(rtw_rx_fill_rx_status); +EXPORT_SYMBOL(rtw_rx_query_rx_desc); diff --git a/drivers/net/wireless/realtek/rtw88/rx.h b/drivers/net/wireless/realtek/rtw88/rx.h index 9f001911298777..6b7dee245c0ab7 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.h +++ b/drivers/net/wireless/realtek/rtw88/rx.h @@ -14,42 +14,40 @@ enum rtw_rx_desc_enc { RX_DESC_ENC_WEP104 = 5, }; -#define GET_RX_DESC_PHYST(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(26)) -#define GET_RX_DESC_ICV_ERR(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(15)) -#define GET_RX_DESC_CRC32(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(14)) -#define GET_RX_DESC_SWDEC(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(27)) -#define GET_RX_DESC_C2H(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x02), BIT(28)) -#define GET_RX_DESC_PKT_LEN(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(13, 0)) -#define GET_RX_DESC_DRV_INFO_SIZE(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(19, 16)) -#define GET_RX_DESC_SHIFT(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(25, 24)) -#define GET_RX_DESC_ENC_TYPE(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(22, 20)) -#define GET_RX_DESC_RX_RATE(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x03), GENMASK(6, 0)) -#define GET_RX_DESC_MACID(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x01), GENMASK(6, 0)) -#define GET_RX_DESC_PPDU_CNT(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x02), GENMASK(30, 29)) -#define GET_RX_DESC_TSFL(rxdesc) \ - le32_get_bits(*((__le32 *)(rxdesc) + 0x05), GENMASK(31, 0)) -#define GET_RX_DESC_BW(rxdesc) \ - (le32_get_bits(*((__le32 *)(rxdesc) + 0x04), GENMASK(5, 4))) +struct rtw_rx_desc { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; +} __packed; + +#define RTW_RX_DESC_W0_PKT_LEN GENMASK(13, 0) +#define RTW_RX_DESC_W0_CRC32 BIT(14) +#define RTW_RX_DESC_W0_ICV_ERR BIT(15) +#define RTW_RX_DESC_W0_DRV_INFO_SIZE GENMASK(19, 16) +#define RTW_RX_DESC_W0_ENC_TYPE GENMASK(22, 20) +#define RTW_RX_DESC_W0_SHIFT GENMASK(25, 24) +#define RTW_RX_DESC_W0_PHYST BIT(26) +#define RTW_RX_DESC_W0_SWDEC BIT(27) + +#define RTW_RX_DESC_W1_MACID GENMASK(6, 0) + +#define RTW_RX_DESC_W2_C2H BIT(28) +#define RTW_RX_DESC_W2_PPDU_CNT GENMASK(30, 29) + +#define RTW_RX_DESC_W3_RX_RATE GENMASK(6, 0) + +#define RTW_RX_DESC_W4_BW GENMASK(5, 4) + +#define RTW_RX_DESC_W5_TSFL GENMASK(31, 0) void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, struct sk_buff *skb); -void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, - struct rtw_rx_pkt_stat *pkt_stat, - struct ieee80211_hdr *hdr, - struct ieee80211_rx_status *rx_status, - u8 *phy_status); +void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_rx_status *rx_status); void rtw_update_rx_freq_from_ie(struct rtw_dev *rtwdev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status, struct rtw_rx_pkt_stat *pkt_stat); diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index 21d0754dd7f6ac..799230eb5f16ff 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -864,7 +864,7 @@ static void rtw_sdio_tx_skb_prepare(struct rtw_dev *rtwdev, pkt_info->qsel = rtw_sdio_get_tx_qsel(rtwdev, skb, queue); - rtw_tx_fill_tx_desc(pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb); rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, pkt_desc); } @@ -981,8 +981,7 @@ static void rtw_sdio_rxfifo_recv(struct rtw_dev *rtwdev, u32 rx_len) while (true) { rx_desc = skb->data; - chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, - &rx_status); + rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, &rx_status); pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + pkt_stat.shift; @@ -1297,12 +1296,12 @@ static void rtw_sdio_deinit_tx(struct rtw_dev *rtwdev) struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv; int i; - for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) - skb_queue_purge(&rtwsdio->tx_queue[i]); - flush_workqueue(rtwsdio->txwq); destroy_workqueue(rtwsdio->txwq); kfree(rtwsdio->tx_handler_data); + + for (i = 0; i < RTK_MAX_TX_QUEUE_NUM; i++) + ieee80211_purge_tx_queue(rtwdev->hw, &rtwsdio->tx_queue[i]); } int rtw_sdio_probe(struct sdio_func *sdio_func, diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index dae7ca14886507..6ed470dd6f221a 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -32,7 +32,8 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, } } -void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) +void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) { struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; bool more_data = false; @@ -67,6 +68,9 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) tx_desc->w4 = le32_encode_bits(pkt_info->rate, RTW_TX_DESC_W4_DATARATE); + if (rtwdev->chip->old_datarate_fb_limit) + tx_desc->w4 |= le32_encode_bits(0x1f, RTW_TX_DESC_W4_DATARATE_FB_LIMIT); + tx_desc->w5 = le32_encode_bits(pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) | le32_encode_bits(pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) | le32_encode_bits(pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) | diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 3d544fd7f60f51..d34cdeca16f192 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -44,6 +44,7 @@ struct rtw_tx_desc { #define RTW_TX_DESC_W3_NAVUSEHDR BIT(15) #define RTW_TX_DESC_W3_MAX_AGG_NUM GENMASK(21, 17) #define RTW_TX_DESC_W4_DATARATE GENMASK(6, 0) +#define RTW_TX_DESC_W4_DATARATE_FB_LIMIT GENMASK(12, 8) #define RTW_TX_DESC_W4_RTSRATE GENMASK(28, 24) #define RTW_TX_DESC_W5_DATA_SHORT BIT(4) #define RTW_TX_DESC_W5_DATA_BW GENMASK(6, 5) @@ -94,7 +95,8 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, struct ieee80211_sta *sta, struct sk_buff *skb); -void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb); +void rtw_tx_fill_tx_desc(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb); void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn); void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src); void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index b17a429bcd2994..8d6db68246f1dc 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -423,10 +423,11 @@ static void rtw_usb_tx_handler(struct work_struct *work) static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb) { + struct rtw_dev *rtwdev = rtwusb->rtwdev; int i; for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) - skb_queue_purge(&rtwusb->tx_queue[i]); + ieee80211_purge_tx_queue(rtwdev->hw, &rtwusb->tx_queue[i]); } static void rtw_usb_write_port_complete(struct urb *urb) @@ -457,7 +458,7 @@ static int rtw_usb_write_data(struct rtw_dev *rtwdev, skb_put_data(skb, buf, size); skb_push(skb, chip->tx_pkt_desc_sz); memset(skb->data, 0, chip->tx_pkt_desc_sz); - rtw_tx_fill_tx_desc(pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb); rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); ret = rtw_usb_write_port(rtwdev, qsel, skb, @@ -477,6 +478,7 @@ static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, pkt_info.tx_pkt_size = size; pkt_info.qsel = TX_DESC_QSEL_BEACON; pkt_info.offset = chip->tx_pkt_desc_sz; + pkt_info.ls = true; return rtw_usb_write_data(rtwdev, &pkt_info, buf); } @@ -524,7 +526,7 @@ static int rtw_usb_tx_write(struct rtw_dev *rtwdev, pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, chip->tx_pkt_desc_sz); ep = qsel_to_ep(rtwusb, pkt_info->qsel); - rtw_tx_fill_tx_desc(pkt_info, skb); + rtw_tx_fill_tx_desc(rtwdev, pkt_info, skb); rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); tx_data = rtw_usb_get_tx_data(skb); tx_data->sn = pkt_info->sn; @@ -570,8 +572,8 @@ static void rtw_usb_rx_handler(struct work_struct *work) do { rx_desc = skb->data; - chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, - &rx_status); + rtw_rx_query_rx_desc(rtwdev, rx_desc, &pkt_stat, + &rx_status); pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + pkt_stat.shift; @@ -888,9 +890,9 @@ static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev) { struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); - rtw_usb_tx_queue_purge(rtwusb); flush_workqueue(rtwusb->txwq); destroy_workqueue(rtwusb->txwq); + rtw_usb_tx_queue_purge(rtwusb); } static int rtw_usb_intf_init(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index 4476fc7e53db74..8ef59994c0dbd9 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -211,25 +211,17 @@ static int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam, return 0; } -static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - const struct rtw89_sec_cam_entry *sec_cam, - bool inform_fw) +static int __rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + const struct rtw89_sec_cam_entry *sec_cam, + bool inform_fw) { - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); - struct rtw89_vif *rtwvif; struct rtw89_addr_cam_entry *addr_cam; unsigned int i; int ret = 0; - if (!vif) { - rtw89_err(rtwdev, "No iface for deleting sec cam\n"); - return -EINVAL; - } - - rtwvif = (struct rtw89_vif *)vif->drv_priv; - addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + addr_cam = rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); for_each_set_bit(i, addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM) { if (addr_cam->sec_ent[i] != sec_cam->sec_cam_idx) @@ -239,11 +231,11 @@ static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, } if (inform_fw) { - ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link); if (ret) rtw89_err(rtwdev, "failed to update dctl cam del key: %d\n", ret); - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret); } @@ -251,25 +243,17 @@ static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, return ret; } -static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - struct rtw89_sec_cam_entry *sec_cam) +static int __rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct ieee80211_key_conf *key, + struct rtw89_sec_cam_entry *sec_cam) { - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); - struct rtw89_vif *rtwvif; struct rtw89_addr_cam_entry *addr_cam; u8 key_idx = 0; int ret; - if (!vif) { - rtw89_err(rtwdev, "No iface for adding sec cam\n"); - return -EINVAL; - } - - rtwvif = (struct rtw89_vif *)vif->drv_priv; - addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + addr_cam = rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || key->cipher == WLAN_CIPHER_SUITE_WEP104) @@ -285,13 +269,13 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, addr_cam->sec_ent_keyid[key_idx] = key->keyidx; addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx; set_bit(key_idx, addr_cam->sec_cam_map); - ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n", ret); return ret; } - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n", ret); @@ -302,6 +286,92 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, return 0; } +static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + const struct rtw89_sec_cam_entry *sec_cam, + bool inform_fw) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_sta_link *rtwsta_link; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + int ret; + + if (!vif) { + rtw89_err(rtwdev, "No iface for deleting sec cam\n"); + return -EINVAL; + } + + rtwvif = vif_to_rtwvif(vif); + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + rtwsta_link = rtwsta ? rtwsta->links[link_id] : NULL; + if (rtwsta && !rtwsta_link) + continue; + + ret = __rtw89_cam_detach_sec_cam(rtwdev, rtwvif_link, rtwsta_link, + sec_cam, inform_fw); + if (ret) + return ret; + } + + return 0; +} + +static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + struct rtw89_sec_cam_entry *sec_cam) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_sta_link *rtwsta_link; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + int key_link_id; + int ret; + + if (!vif) { + rtw89_err(rtwdev, "No iface for adding sec cam\n"); + return -EINVAL; + } + + rtwvif = vif_to_rtwvif(vif); + + key_link_id = ieee80211_vif_is_mld(vif) ? key->link_id : 0; + if (key_link_id >= 0) { + rtwvif_link = rtwvif->links[key_link_id]; + rtwsta_link = rtwsta ? rtwsta->links[key_link_id] : NULL; + + if (!rtwvif_link || (rtwsta && !rtwsta_link)) { + rtw89_err(rtwdev, "No drv link for adding sec cam\n"); + return -ENOLINK; + } + + return __rtw89_cam_attach_sec_cam(rtwdev, rtwvif_link, + rtwsta_link, key, sec_cam); + } + + /* key_link_id < 0: MLD pairwise key */ + if (!rtwsta) { + rtw89_err(rtwdev, "No sta for adding MLD pairwise sec cam\n"); + return -EINVAL; + } + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = __rtw89_cam_attach_sec_cam(rtwdev, rtwvif_link, + rtwsta_link, key, sec_cam); + if (ret) + return ret; + } + + return 0; +} + static int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -485,10 +555,10 @@ void rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev, clear_bit(bssid_cam->bssid_cam_idx, cam_info->bssid_cam_map); } -void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam; - struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; + struct rtw89_addr_cam_entry *addr_cam = &rtwvif_link->addr_cam; + struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam; rtw89_cam_deinit_addr_cam(rtwdev, addr_cam); rtw89_cam_deinit_bssid_cam(rtwdev, bssid_cam); @@ -593,7 +663,7 @@ static int rtw89_cam_get_avail_bssid_cam(struct rtw89_dev *rtwdev, } int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct rtw89_bssid_cam_entry *bssid_cam, const u8 *bssid) { @@ -613,7 +683,7 @@ int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, } bssid_cam->bssid_cam_idx = bssid_cam_idx; - bssid_cam->phy_idx = rtwvif->phy_idx; + bssid_cam->phy_idx = rtwvif_link->phy_idx; bssid_cam->len = BSSID_CAM_ENT_SIZE; bssid_cam->offset = 0; bssid_cam->valid = true; @@ -622,20 +692,21 @@ int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, return 0; } -void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; + struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam; - ether_addr_copy(bssid_cam->bssid, rtwvif->bssid); + ether_addr_copy(bssid_cam->bssid, rtwvif_link->bssid); } -int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - struct rtw89_addr_cam_entry *addr_cam = &rtwvif->addr_cam; - struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; + struct rtw89_addr_cam_entry *addr_cam = &rtwvif_link->addr_cam; + struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam; int ret; - ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, rtwvif->bssid); + ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif_link, bssid_cam, + rtwvif_link->bssid); if (ret) { rtw89_err(rtwdev, "failed to init bssid cam\n"); return ret; @@ -651,19 +722,27 @@ int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) } int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, u8 *cmd) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, u8 *cmd) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta); - u8 bss_color = vif->bss_conf.he_bss_color.color; + struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif_link, + rtwsta_link); + struct ieee80211_bss_conf *bss_conf; + u8 bss_color; u8 bss_mask; - if (vif->bss_conf.nontransmitted) + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + bss_color = bss_conf->he_bss_color.color; + + if (bss_conf->nontransmitted) bss_mask = RTW89_BSSID_MATCH_5_BYTES; else bss_mask = RTW89_BSSID_MATCH_ALL; + rcu_read_unlock(); + FWCMD_SET_ADDR_BSSID_IDX(cmd, bssid_cam->bssid_cam_idx); FWCMD_SET_ADDR_BSSID_OFFSET(cmd, bssid_cam->offset); FWCMD_SET_ADDR_BSSID_LEN(cmd, bssid_cam->len); @@ -694,19 +773,30 @@ static u8 rtw89_cam_addr_hash(u8 start, const u8 *addr) } void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr, u8 *cmd) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); - struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta); - const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif->mac_addr; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_addr_cam_entry *addr_cam = + rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); + struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link); + struct ieee80211_link_sta *link_sta; + const u8 *sma = scan_mac_addr ? scan_mac_addr : rtwvif_link->mac_addr; u8 sma_hash, tma_hash, addr_msk_start; u8 sma_start = 0; u8 tma_start = 0; - u8 *tma = sta ? sta->addr : rtwvif->bssid; + const u8 *tma; + + rcu_read_lock(); + + if (sta) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + tma = link_sta->addr; + } else { + tma = rtwvif_link->bssid; + } if (addr_cam->addr_mask != 0) { addr_msk_start = __ffs(addr_cam->addr_mask); @@ -723,10 +813,10 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_LEN(cmd, addr_cam->len); FWCMD_SET_ADDR_VALID(cmd, addr_cam->valid); - FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif->net_type); - FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif->bcn_hit_cond); - FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif->hit_rule); - FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif->phy_idx); + FWCMD_SET_ADDR_NET_TYPE(cmd, rtwvif_link->net_type); + FWCMD_SET_ADDR_BCN_HIT_COND(cmd, rtwvif_link->bcn_hit_cond); + FWCMD_SET_ADDR_HIT_RULE(cmd, rtwvif_link->hit_rule); + FWCMD_SET_ADDR_BB_SEL(cmd, rtwvif_link->phy_idx); FWCMD_SET_ADDR_ADDR_MASK(cmd, addr_cam->addr_mask); FWCMD_SET_ADDR_MASK_SEL(cmd, addr_cam->mask_sel); FWCMD_SET_ADDR_SMA_HASH(cmd, sma_hash); @@ -748,20 +838,21 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_TMA4(cmd, tma[4]); FWCMD_SET_ADDR_TMA5(cmd, tma[5]); - FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif->port); - FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif->port); - FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif->trigger); - FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif->lsig_txop); - FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif->tgt_ind); - FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif->frm_tgt_ind); - FWCMD_SET_ADDR_MACID(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id); - if (rtwvif->net_type == RTW89_NET_TYPE_INFRA) + FWCMD_SET_ADDR_PORT_INT(cmd, rtwvif_link->port); + FWCMD_SET_ADDR_TSF_SYNC(cmd, rtwvif_link->port); + FWCMD_SET_ADDR_TF_TRS(cmd, rtwvif_link->trigger); + FWCMD_SET_ADDR_LSIG_TXOP(cmd, rtwvif_link->lsig_txop); + FWCMD_SET_ADDR_TGT_IND(cmd, rtwvif_link->tgt_ind); + FWCMD_SET_ADDR_FRM_TGT_IND(cmd, rtwvif_link->frm_tgt_ind); + FWCMD_SET_ADDR_MACID(cmd, rtwsta_link ? rtwsta_link->mac_id : + rtwvif_link->mac_id); + if (rtwvif_link->net_type == RTW89_NET_TYPE_INFRA) FWCMD_SET_ADDR_AID12(cmd, vif->cfg.aid & 0xfff); - else if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + else if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) FWCMD_SET_ADDR_AID12(cmd, sta ? sta->aid & 0xfff : 0); - FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif->wowlan_pattern); - FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif->wowlan_uc); - FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif->wowlan_magic); + FWCMD_SET_ADDR_WOL_PATTERN(cmd, rtwvif_link->wowlan_pattern); + FWCMD_SET_ADDR_WOL_UC(cmd, rtwvif_link->wowlan_uc); + FWCMD_SET_ADDR_WOL_MAGIC(cmd, rtwvif_link->wowlan_magic); FWCMD_SET_ADDR_WAPI(cmd, addr_cam->wapi); FWCMD_SET_ADDR_SEC_ENT_MODE(cmd, addr_cam->sec_ent_mode); FWCMD_SET_ADDR_SEC_ENT0_KEYID(cmd, addr_cam->sec_ent_keyid[0]); @@ -780,18 +871,22 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, FWCMD_SET_ADDR_SEC_ENT4(cmd, addr_cam->sec_ent[4]); FWCMD_SET_ADDR_SEC_ENT5(cmd, addr_cam->sec_ent[5]); FWCMD_SET_ADDR_SEC_ENT6(cmd, addr_cam->sec_ent[6]); + + rcu_read_unlock(); } void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v1 *h2c) { - struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + struct rtw89_addr_cam_entry *addr_cam = + rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv; - h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id, + h2c->c0 = le32_encode_bits(rtwsta_link ? rtwsta_link->mac_id : + rtwvif_link->mac_id, DCTLINFO_V1_C0_MACID) | le32_encode_bits(1, DCTLINFO_V1_C0_OP); @@ -862,18 +957,28 @@ void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, } void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v2 *h2c) { - struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link); + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif_link->rtwvif); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_addr_cam_entry *addr_cam = + rtw89_get_addr_cam_of(rtwvif_link, rtwsta_link); + bool is_mld = sta ? sta->mlo : ieee80211_vif_is_mld(vif); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv; + u8 *mld_sma, *mld_tma, *mld_bssid; - h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id, + h2c->c0 = le32_encode_bits(rtwsta_link ? rtwsta_link->mac_id : + rtwvif_link->mac_id, DCTLINFO_V2_C0_MACID) | le32_encode_bits(1, DCTLINFO_V2_C0_OP); + h2c->w2 = le32_encode_bits(is_mld, DCTLINFO_V2_W2_IS_MLD); + h2c->m2 = cpu_to_le32(DCTLINFO_V2_W2_IS_MLD); + h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0], DCTLINFO_V2_W4_SEC_ENT0_KEYID) | le32_encode_bits(addr_cam->sec_ent_keyid[1], @@ -939,4 +1044,47 @@ void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, DCTLINFO_V2_W4_SEC_KEY_ID); h2c->m4 |= cpu_to_le32(DCTLINFO_V2_W4_SEC_KEY_ID); } + + if (!is_mld) + return; + + if (rtwvif_link->net_type == RTW89_NET_TYPE_INFRA) { + mld_sma = rtwvif->mac_addr; + mld_tma = vif->cfg.ap_addr; + mld_bssid = vif->cfg.ap_addr; + } else if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE && sta) { + mld_sma = rtwvif->mac_addr; + mld_tma = sta->addr; + mld_bssid = rtwvif->mac_addr; + } else { + return; + } + + h2c->w8 = le32_encode_bits(mld_sma[0], DCTLINFO_V2_W8_MLD_SMA_0) | + le32_encode_bits(mld_sma[1], DCTLINFO_V2_W8_MLD_SMA_1) | + le32_encode_bits(mld_sma[2], DCTLINFO_V2_W8_MLD_SMA_2) | + le32_encode_bits(mld_sma[3], DCTLINFO_V2_W8_MLD_SMA_3); + h2c->m8 = cpu_to_le32(DCTLINFO_V2_W8_ALL); + + h2c->w9 = le32_encode_bits(mld_sma[4], DCTLINFO_V2_W9_MLD_SMA_4) | + le32_encode_bits(mld_sma[5], DCTLINFO_V2_W9_MLD_SMA_5) | + le32_encode_bits(mld_tma[0], DCTLINFO_V2_W9_MLD_TMA_0) | + le32_encode_bits(mld_tma[1], DCTLINFO_V2_W9_MLD_TMA_1); + h2c->m9 = cpu_to_le32(DCTLINFO_V2_W9_ALL); + + h2c->w10 = le32_encode_bits(mld_tma[2], DCTLINFO_V2_W10_MLD_TMA_2) | + le32_encode_bits(mld_tma[3], DCTLINFO_V2_W10_MLD_TMA_3) | + le32_encode_bits(mld_tma[4], DCTLINFO_V2_W10_MLD_TMA_4) | + le32_encode_bits(mld_tma[5], DCTLINFO_V2_W10_MLD_TMA_5); + h2c->m10 = cpu_to_le32(DCTLINFO_V2_W10_ALL); + + h2c->w11 = le32_encode_bits(mld_bssid[0], DCTLINFO_V2_W11_MLD_BSSID_0) | + le32_encode_bits(mld_bssid[1], DCTLINFO_V2_W11_MLD_BSSID_1) | + le32_encode_bits(mld_bssid[2], DCTLINFO_V2_W11_MLD_BSSID_2) | + le32_encode_bits(mld_bssid[3], DCTLINFO_V2_W11_MLD_BSSID_3); + h2c->m11 = cpu_to_le32(DCTLINFO_V2_W11_ALL); + + h2c->w12 = le32_encode_bits(mld_bssid[4], DCTLINFO_V2_W12_MLD_BSSID_4) | + le32_encode_bits(mld_bssid[5], DCTLINFO_V2_W12_MLD_BSSID_5); + h2c->m12 = cpu_to_le32(DCTLINFO_V2_W12_ALL); } diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h index 5d7b624c2dd428..3134ebf0882586 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.h +++ b/drivers/net/wireless/realtek/rtw89/cam.h @@ -514,46 +514,58 @@ struct rtw89_h2c_dctlinfo_ud_v2 { #define DCTLINFO_V2_W7_SEC_ENT7 GENMASK(23, 16) #define DCTLINFO_V2_W7_SEC_ENT8 GENMASK(31, 24) #define DCTLINFO_V2_W7_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W8_MLD_SMA_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W8_MLD_SMA_0 GENMASK(7, 0) +#define DCTLINFO_V2_W8_MLD_SMA_1 GENMASK(15, 8) +#define DCTLINFO_V2_W8_MLD_SMA_2 GENMASK(23, 16) +#define DCTLINFO_V2_W8_MLD_SMA_3 GENMASK(31, 24) #define DCTLINFO_V2_W8_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W9_MLD_SMA_H_V1 GENMASK(15, 0) -#define DCTLINFO_V2_W9_MLD_TMA_L_V1 GENMASK(31, 16) +#define DCTLINFO_V2_W9_MLD_SMA_4 GENMASK(7, 0) +#define DCTLINFO_V2_W9_MLD_SMA_5 GENMASK(15, 8) +#define DCTLINFO_V2_W9_MLD_TMA_0 GENMASK(23, 16) +#define DCTLINFO_V2_W9_MLD_TMA_1 GENMASK(31, 24) #define DCTLINFO_V2_W9_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W10_MLD_TMA_H_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W10_MLD_TMA_2 GENMASK(7, 0) +#define DCTLINFO_V2_W10_MLD_TMA_3 GENMASK(15, 8) +#define DCTLINFO_V2_W10_MLD_TMA_4 GENMASK(23, 16) +#define DCTLINFO_V2_W10_MLD_TMA_5 GENMASK(31, 24) #define DCTLINFO_V2_W10_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W11_MLD_TA_BSSID_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W11_MLD_BSSID_0 GENMASK(7, 0) +#define DCTLINFO_V2_W11_MLD_BSSID_1 GENMASK(15, 8) +#define DCTLINFO_V2_W11_MLD_BSSID_2 GENMASK(23, 16) +#define DCTLINFO_V2_W11_MLD_BSSID_3 GENMASK(31, 24) #define DCTLINFO_V2_W11_ALL GENMASK(31, 0) -#define DCTLINFO_V2_W12_MLD_TA_BSSID_H_V1 GENMASK(15, 0) +#define DCTLINFO_V2_W12_MLD_BSSID_4 GENMASK(7, 0) +#define DCTLINFO_V2_W12_MLD_BSSID_5 GENMASK(15, 8) #define DCTLINFO_V2_W12_ALL GENMASK(15, 0) -int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); -void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); +int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); +void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, struct rtw89_addr_cam_entry *addr_cam, const struct rtw89_bssid_cam_entry *bssid_cam); void rtw89_cam_deinit_addr_cam(struct rtw89_dev *rtwdev, struct rtw89_addr_cam_entry *addr_cam); int rtw89_cam_init_bssid_cam(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct rtw89_bssid_cam_entry *bssid_cam, const u8 *bssid); void rtw89_cam_deinit_bssid_cam(struct rtw89_dev *rtwdev, struct rtw89_bssid_cam_entry *bssid_cam); void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *vif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *vif, + struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr, u8 *cmd); void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v1 *h2c); void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, struct rtw89_h2c_dctlinfo_ud_v2 *h2c); int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, u8 *cmd); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, u8 *cmd); int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -564,6 +576,6 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev, struct ieee80211_key_conf *key, bool inform_fw); void rtw89_cam_bssid_changed(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); void rtw89_cam_reset_keys(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 7070c85e2c2883..fb9449930c40aa 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -10,6 +10,10 @@ #include "ps.h" #include "util.h" +static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx idx1, + enum rtw89_chanctx_idx idx2); + static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band, u8 center_chan) { @@ -226,14 +230,30 @@ static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev) void rtw89_entity_init(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; hal->entity_pause = false; bitmap_zero(hal->entity_map, NUM_OF_RTW89_CHANCTX); bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); atomic_set(&hal->roc_chanctx_idx, RTW89_CHANCTX_IDLE); + + INIT_LIST_HEAD(&mgnt->active_list); + rtw89_config_default_chandef(rtwdev); } +static bool rtw89_vif_is_active_role(struct rtw89_vif *rtwvif) +{ + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + if (rtwvif_link->chanctx_assigned) + return true; + + return false; +} + static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, struct rtw89_entity_weight *w) { @@ -255,11 +275,147 @@ static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, } rtw89_for_each_rtwvif(rtwdev, rtwvif) { - if (rtwvif->chanctx_assigned) + if (rtw89_vif_is_active_role(rtwvif)) w->active_roles++; } } +static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_vif_link *cur; + + if (unlikely(!rtwvif_link->chanctx_assigned)) + return; + + cur = rtw89_vif_get_link_inst(rtwvif, 0); + if (!cur || !cur->chanctx_assigned) + return; + + if (cur == rtwvif_link) + return; + + rtw89_swap_chanctx(rtwdev, rtwvif_link->chanctx_idx, cur->chanctx_idx); +} + +const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, + const char *caller_message, + u8 link_index) +{ + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; + enum rtw89_chanctx_idx chanctx_idx; + enum rtw89_chanctx_idx roc_idx; + enum rtw89_entity_mode mode; + u8 role_index; + + lockdep_assert_held(&rtwdev->mutex); + + if (unlikely(link_index >= __RTW89_MLD_MAX_LINK_NUM)) { + WARN(1, "link index %u is invalid (max link inst num: %d)\n", + link_index, __RTW89_MLD_MAX_LINK_NUM); + goto dflt; + } + + mode = rtw89_get_entity_mode(rtwdev); + switch (mode) { + case RTW89_ENTITY_MODE_SCC_OR_SMLD: + case RTW89_ENTITY_MODE_MCC: + role_index = 0; + break; + case RTW89_ENTITY_MODE_MCC_PREPARE: + role_index = 1; + break; + default: + WARN(1, "Invalid ent mode: %d\n", mode); + goto dflt; + } + + chanctx_idx = mgnt->chanctx_tbl[role_index][link_index]; + if (chanctx_idx == RTW89_CHANCTX_IDLE) + goto dflt; + + roc_idx = atomic_read(&hal->roc_chanctx_idx); + if (roc_idx != RTW89_CHANCTX_IDLE) { + /* ROC is ongoing (given ROC runs on RTW89_ROC_BY_LINK_INDEX). + * If @link_index is the same as RTW89_ROC_BY_LINK_INDEX, get + * the ongoing ROC chanctx. + */ + if (link_index == RTW89_ROC_BY_LINK_INDEX) + chanctx_idx = roc_idx; + } + + return rtw89_chan_get(rtwdev, chanctx_idx); + +dflt: + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "%s (%s): prefetch NULL on link index %u\n", + __func__, caller_message ?: "", link_index); + + return rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); +} +EXPORT_SYMBOL(__rtw89_mgnt_chan_get); + +static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; + struct rtw89_vif_link *link; + struct rtw89_vif *role; + u8 pos = 0; + int i, j; + + lockdep_assert_held(&rtwdev->mutex); + + for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) + mgnt->active_roles[i] = NULL; + + for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) { + for (j = 0; j < __RTW89_MLD_MAX_LINK_NUM; j++) + mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE; + } + + /* To be consistent with legacy behavior, expect the first active role + * which uses RTW89_CHANCTX_0 to put at position 0, and make its first + * link instance take RTW89_CHANCTX_0. (normalizing) + */ + list_for_each_entry(role, &mgnt->active_list, mgnt_entry) { + for (i = 0; i < role->links_inst_valid_num; i++) { + link = rtw89_vif_get_link_inst(role, i); + if (!link || !link->chanctx_assigned) + continue; + + if (link->chanctx_idx == RTW89_CHANCTX_0) { + rtw89_normalize_link_chanctx(rtwdev, link); + + list_del(&role->mgnt_entry); + list_add(&role->mgnt_entry, &mgnt->active_list); + break; + } + } + } + + list_for_each_entry(role, &mgnt->active_list, mgnt_entry) { + if (unlikely(pos >= RTW89_MAX_INTERFACE_NUM)) { + rtw89_warn(rtwdev, + "%s: active roles are over max iface num\n", + __func__); + break; + } + + for (i = 0; i < role->links_inst_valid_num; i++) { + link = rtw89_vif_get_link_inst(role, i); + if (!link || !link->chanctx_assigned) + continue; + + mgnt->chanctx_tbl[pos][i] = link->chanctx_idx; + } + + mgnt->active_roles[pos++] = role; + } +} + enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) { DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_CHANCTX) = {}; @@ -286,9 +442,14 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) set_bit(RTW89_CHANCTX_0, recalc_map); fallthrough; case 1: - mode = RTW89_ENTITY_MODE_SCC; + mode = RTW89_ENTITY_MODE_SCC_OR_SMLD; break; case 2 ... NUM_OF_RTW89_CHANCTX: + if (w.active_roles == 1) { + mode = RTW89_ENTITY_MODE_SCC_OR_SMLD; + break; + } + if (w.active_roles != NUM_OF_RTW89_MCC_ROLES) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, "unhandled ent: %d chanctxs %d roles\n", @@ -315,6 +476,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) rtw89_assign_entity_chan(rtwdev, idx, &chan); } + rtw89_entity_recalc_mgnt_roles(rtwdev); + if (hal->entity_pause) return rtw89_get_entity_mode(rtwdev); @@ -387,9 +550,9 @@ int rtw89_iterate_mcc_roles(struct rtw89_dev *rtwdev, static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role, u64 tsf) { - struct rtw89_vif *rtwvif = role->rtwvif; + struct rtw89_vif_link *rtwvif_link = role->rtwvif_link; u32 bcn_intvl_us = ieee80211_tu_to_usec(role->beacon_interval); - u64 sync_tsf = READ_ONCE(rtwvif->sync_bcn_tsf); + u64 sync_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); u32 remainder; if (tsf < sync_tsf) { @@ -413,8 +576,8 @@ static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux int ret; req.group = mcc->group; - req.macid_x = ref->rtwvif->mac_id; - req.macid_y = aux->rtwvif->mac_id; + req.macid_x = ref->rtwvif_link->mac_id; + req.macid_y = aux->rtwvif_link->mac_id; ret = rtw89_fw_h2c_mcc_req_tsf(rtwdev, &req, &rpt); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, @@ -440,10 +603,10 @@ static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES); arg.num = 2; - arg.infos[0].band = ref->rtwvif->mac_idx; - arg.infos[0].port = ref->rtwvif->port; - arg.infos[1].band = aux->rtwvif->mac_idx; - arg.infos[1].port = aux->rtwvif->port; + arg.infos[0].band = ref->rtwvif_link->mac_idx; + arg.infos[0].port = ref->rtwvif_link->port; + arg.infos[1].band = aux->rtwvif_link->mac_idx; + arg.infos[1].port = aux->rtwvif_link->port; ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, &arg, &rpt); if (ret) { @@ -522,23 +685,31 @@ u32 rtw89_mcc_role_fw_macid_bitmap_to_u32(struct rtw89_mcc_role *mcc_role) static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_mcc_role *mcc_role = data; - struct rtw89_vif *target = mcc_role->rtwvif; + struct rtw89_vif *target = mcc_role->rtwvif_link->rtwvif; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_sta_link *rtwsta_link; if (rtwvif != target) return; - rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta->mac_id); + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) { + rtw89_err(rtwdev, "mcc sta macid: find no link on HW-0\n"); + return; + } + + rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta_link->mac_id); } static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *mcc_role) { - struct rtw89_vif *rtwvif = mcc_role->rtwvif; + struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link; - rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif->mac_id); + rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif_link->mac_id); ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_mcc_role_macid_sta_iter, mcc_role); @@ -564,8 +735,9 @@ static void rtw89_mcc_fill_role_policy(struct rtw89_dev *rtwdev, static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *mcc_role) { - struct ieee80211_vif *vif = rtwvif_to_vif(mcc_role->rtwvif); + struct rtw89_vif_link *rtwvif_link = mcc_role->rtwvif_link; struct ieee80211_p2p_noa_desc *noa_desc; + struct ieee80211_bss_conf *bss_conf; u32 bcn_intvl_us = ieee80211_tu_to_usec(mcc_role->beacon_interval); u32 max_toa_us, max_tob_us, max_dur_us; u32 start_time, interval, duration; @@ -576,13 +748,18 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev, if (!mcc_role->is_go && !mcc_role->is_gc) return; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + /* find the first periodic NoA */ for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) { - noa_desc = &vif->bss_conf.p2p_noa_attr.desc[i]; + noa_desc = &bss_conf->p2p_noa_attr.desc[i]; if (noa_desc->count == 255) goto fill; } + rcu_read_unlock(); return; fill: @@ -590,6 +767,8 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev, interval = le32_to_cpu(noa_desc->interval); duration = le32_to_cpu(noa_desc->duration); + rcu_read_unlock(); + if (interval != bcn_intvl_us) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC role limit: mismatch interval: %d vs. %d\n", @@ -597,7 +776,7 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev, return; } - ret = rtw89_mac_port_get_tsf(rtwdev, mcc_role->rtwvif, &tsf); + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret); return; @@ -632,15 +811,21 @@ static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev, } static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct rtw89_mcc_role *role) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf; const struct rtw89_chan *chan; memset(role, 0, sizeof(*role)); - role->rtwvif = rtwvif; - role->beacon_interval = vif->bss_conf.beacon_int; + role->rtwvif_link = rtwvif_link; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + role->beacon_interval = bss_conf->beacon_int; + + rcu_read_unlock(); if (!role->beacon_interval) { rtw89_warn(rtwdev, @@ -650,10 +835,10 @@ static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev, role->duration = role->beacon_interval / 2; - chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); role->is_2ghz = chan->band_type == RTW89_BAND_2G; - role->is_go = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_GO; - role->is_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; + role->is_go = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_GO; + role->is_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; rtw89_mcc_fill_role_macid_bitmap(rtwdev, role); rtw89_mcc_fill_role_policy(rtwdev, role); @@ -678,10 +863,11 @@ static void rtw89_mcc_fill_bt_role(struct rtw89_dev *rtwdev) } struct rtw89_mcc_fill_role_selector { - struct rtw89_vif *bind_vif[NUM_OF_RTW89_CHANCTX]; + struct rtw89_vif_link *bind_vif[NUM_OF_RTW89_CHANCTX]; }; static_assert((u8)NUM_OF_RTW89_CHANCTX >= NUM_OF_RTW89_MCC_ROLES); +static_assert(RTW89_MAX_INTERFACE_NUM >= NUM_OF_RTW89_MCC_ROLES); static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *mcc_role, @@ -689,7 +875,7 @@ static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev, void *data) { struct rtw89_mcc_fill_role_selector *sel = data; - struct rtw89_vif *role_vif = sel->bind_vif[ordered_idx]; + struct rtw89_vif_link *role_vif = sel->bind_vif[ordered_idx]; int ret; if (!role_vif) { @@ -711,22 +897,26 @@ static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev, static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev) { + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; struct rtw89_mcc_fill_role_selector sel = {}; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; int ret; + int i; - rtw89_for_each_rtwvif(rtwdev, rtwvif) { - if (!rtwvif->chanctx_assigned) - continue; + for (i = 0; i < NUM_OF_RTW89_MCC_ROLES; i++) { + rtwvif = mgnt->active_roles[i]; + if (!rtwvif) + break; - if (sel.bind_vif[rtwvif->chanctx_idx]) { - rtw89_warn(rtwdev, - "MCC skip extra vif on chanctx[%d]\n", - rtwvif->mac_id, rtwvif->chanctx_idx); + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "mcc fill roles: find no link on HW-0\n"); continue; } - sel.bind_vif[rtwvif->chanctx_idx] = rtwvif; + sel.bind_vif[i] = rtwvif_link; } ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel); @@ -754,13 +944,13 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, memset(&pattern->courtesy, 0, sizeof(pattern->courtesy)); if (pattern->tob_aux <= 0 || pattern->toa_aux <= 0) { - pattern->courtesy.macid_tgt = aux->rtwvif->mac_id; - pattern->courtesy.macid_src = ref->rtwvif->mac_id; + pattern->courtesy.macid_tgt = aux->rtwvif_link->mac_id; + pattern->courtesy.macid_src = ref->rtwvif_link->mac_id; pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT; pattern->courtesy.enable = true; } else if (pattern->tob_ref <= 0 || pattern->toa_ref <= 0) { - pattern->courtesy.macid_tgt = ref->rtwvif->mac_id; - pattern->courtesy.macid_src = aux->rtwvif->mac_id; + pattern->courtesy.macid_tgt = ref->rtwvif_link->mac_id; + pattern->courtesy.macid_src = aux->rtwvif_link->mac_id; pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT; pattern->courtesy.enable = true; } @@ -1263,7 +1453,7 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev, u64 tsf_src; int ret; - ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif, &tsf_src); + ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif_link, &tsf_src); if (ret) { rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret); return; @@ -1280,12 +1470,12 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev, div_u64_rem(tbtt_tgt, bcn_intvl_src_us, &remainder); tsf_ofst_tgt = bcn_intvl_src_us - remainder; - config->sync.macid_tgt = tgt->rtwvif->mac_id; - config->sync.band_tgt = tgt->rtwvif->mac_idx; - config->sync.port_tgt = tgt->rtwvif->port; - config->sync.macid_src = src->rtwvif->mac_id; - config->sync.band_src = src->rtwvif->mac_idx; - config->sync.port_src = src->rtwvif->port; + config->sync.macid_tgt = tgt->rtwvif_link->mac_id; + config->sync.band_tgt = tgt->rtwvif_link->mac_idx; + config->sync.port_tgt = tgt->rtwvif_link->port; + config->sync.macid_src = src->rtwvif_link->mac_id; + config->sync.band_src = src->rtwvif_link->mac_idx; + config->sync.port_src = src->rtwvif_link->port; config->sync.offset = tsf_ofst_tgt / 1024; config->sync.enable = true; @@ -1294,7 +1484,7 @@ static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev, config->sync.macid_tgt, config->sync.macid_src, config->sync.offset); - rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif, src->rtwvif, + rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif_link, src->rtwvif_link, config->sync.offset); } @@ -1305,13 +1495,13 @@ static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev) struct rtw89_mcc_config *config = &mcc->config; u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval); u32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref); - struct rtw89_vif *rtwvif = ref->rtwvif; + struct rtw89_vif_link *rtwvif_link = ref->rtwvif_link; u64 tsf, start_tsf; u32 cur_tbtt_ofst; u64 min_time; int ret; - ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, &tsf); + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret); return ret; @@ -1390,13 +1580,13 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro const struct rtw89_chan *chan; int ret; - chan = rtw89_chan_get(rtwdev, role->rtwvif->chanctx_idx); + chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx); req.central_ch_seg0 = chan->channel; req.primary_ch = chan->primary_channel; req.bandwidth = chan->band_width; req.ch_band_type = chan->band_type; - req.macid = role->rtwvif->mac_id; + req.macid = role->rtwvif_link->mac_id; req.group = mcc->group; req.c2h_rpt = policy->c2h_rpt; req.tx_null_early = policy->tx_null_early; @@ -1421,7 +1611,7 @@ static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ro } ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group, - role->rtwvif->mac_id, + role->rtwvif_link->mac_id, role->macid_bitmap); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, @@ -1448,7 +1638,7 @@ void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role, slot_arg->duration = role->duration; slot_arg->role_num = 1; - chan = rtw89_chan_get(rtwdev, role->rtwvif->chanctx_idx); + chan = rtw89_chan_get(rtwdev, role->rtwvif_link->chanctx_idx); slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI; slot_arg->roles[0].is_master = role == ref; @@ -1458,7 +1648,7 @@ void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role, slot_arg->roles[0].primary_ch = chan->primary_channel; slot_arg->roles[0].en_tx_null = !policy->dis_tx_null; slot_arg->roles[0].null_early = policy->tx_null_early; - slot_arg->roles[0].macid = role->rtwvif->mac_id; + slot_arg->roles[0].macid = role->rtwvif_link->mac_id; slot_arg->roles[0].macid_main_bitmap = rtw89_mcc_role_fw_macid_bitmap_to_u32(role); } @@ -1569,7 +1759,7 @@ static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace) } } - req.macid = ref->rtwvif->mac_id; + req.macid = ref->rtwvif_link->mac_id; req.tsf_high = config->start_tsf >> 32; req.tsf_low = config->start_tsf; @@ -1598,7 +1788,7 @@ static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev, if (!courtesy->enable) return; - if (courtesy->macid_src == ref->rtwvif->mac_id) { + if (courtesy->macid_src == ref->rtwvif_link->mac_id) { slot_arg_src = &arg->slots[ref->slot_idx]; slot_idx_tgt = aux->slot_idx; } else { @@ -1717,9 +1907,9 @@ static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_chang struct rtw89_fw_mcc_duration req = { .group = mcc->group, .btc_in_group = false, - .start_macid = ref->rtwvif->mac_id, - .macid_x = ref->rtwvif->mac_id, - .macid_y = aux->rtwvif->mac_id, + .start_macid = ref->rtwvif_link->mac_id, + .macid_x = ref->rtwvif_link->mac_id, + .macid_y = aux->rtwvif_link->mac_id, .duration_x = ref->duration, .duration_y = aux->duration, .start_tsf_high = config->start_tsf >> 32, @@ -1813,18 +2003,18 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) struct ieee80211_p2p_noa_desc noa_desc = {}; u64 start_time = config->start_tsf; u32 interval = config->mcc_interval; - struct rtw89_vif *rtwvif_go; + struct rtw89_vif_link *rtwvif_go; u32 duration; if (mcc->mode != RTW89_MCC_MODE_GO_STA) return; if (ref->is_go) { - rtwvif_go = ref->rtwvif; + rtwvif_go = ref->rtwvif_link; start_time += ieee80211_tu_to_usec(ref->duration); duration = config->mcc_interval - ref->duration; } else if (aux->is_go) { - rtwvif_go = aux->rtwvif; + rtwvif_go = aux->rtwvif_link; start_time += ieee80211_tu_to_usec(pattern->tob_ref) + ieee80211_tu_to_usec(config->beacon_offset) + ieee80211_tu_to_usec(pattern->toa_aux); @@ -1865,9 +2055,9 @@ static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev) return; if (ref->is_go) - rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif, true); + rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, true); else if (aux->is_go) - rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif, true); + rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, true); rtw89_mcc_handle_beacon_noa(rtwdev, true); } @@ -1882,9 +2072,9 @@ static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev) return; if (ref->is_go) - rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif, false); + rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif_link, false); else if (aux->is_go) - rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif, false); + rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif_link, false); rtw89_mcc_handle_beacon_noa(rtwdev, false); } @@ -1942,7 +2132,7 @@ struct rtw89_mcc_stop_sel { static void rtw89_mcc_stop_sel_fill(struct rtw89_mcc_stop_sel *sel, const struct rtw89_mcc_role *mcc_role) { - sel->mac_id = mcc_role->rtwvif->mac_id; + sel->mac_id = mcc_role->rtwvif_link->mac_id; sel->slot_idx = mcc_role->slot_idx; } @@ -1953,7 +2143,7 @@ static int rtw89_mcc_stop_sel_iterator(struct rtw89_dev *rtwdev, { struct rtw89_mcc_stop_sel *sel = data; - if (!mcc_role->rtwvif->chanctx_assigned) + if (!mcc_role->rtwvif_link->chanctx_assigned) return 0; rtw89_mcc_stop_sel_fill(sel, mcc_role); @@ -2081,7 +2271,7 @@ static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev, int ret; ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group, - upd->rtwvif->mac_id, + upd->rtwvif_link->mac_id, upd->macid_bitmap); if (ret) { rtw89_debug(rtwdev, RTW89_DBG_CHAN, @@ -2106,7 +2296,7 @@ static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev, int i; arg.sch_idx = mcc->group; - arg.macid = upd->rtwvif->mac_id; + arg.macid = upd->rtwvif_link->mac_id; for (i = 0; i < 32; i++) { if (add & BIT(i)) { @@ -2144,7 +2334,7 @@ static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev, void *data) { struct rtw89_mcc_role upd = { - .rtwvif = mcc_role->rtwvif, + .rtwvif_link = mcc_role->rtwvif_link, }; int ret; @@ -2370,6 +2560,24 @@ void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev) rtw89_queue_chanctx_work(rtwdev); } +static void __rtw89_swap_chanctx(struct rtw89_vif *rtwvif, + enum rtw89_chanctx_idx idx1, + enum rtw89_chanctx_idx idx2) +{ + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + if (!rtwvif_link->chanctx_assigned) + continue; + + if (rtwvif_link->chanctx_idx == idx1) + rtwvif_link->chanctx_idx = idx2; + else if (rtwvif_link->chanctx_idx == idx2) + rtwvif_link->chanctx_idx = idx1; + } +} + static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx1, enum rtw89_chanctx_idx idx2) @@ -2386,14 +2594,8 @@ static void rtw89_swap_chanctx(struct rtw89_dev *rtwdev, swap(hal->chanctx[idx1], hal->chanctx[idx2]); - rtw89_for_each_rtwvif(rtwdev, rtwvif) { - if (!rtwvif->chanctx_assigned) - continue; - if (rtwvif->chanctx_idx == idx1) - rtwvif->chanctx_idx = idx2; - else if (rtwvif->chanctx_idx == idx2) - rtwvif->chanctx_idx = idx1; - } + rtw89_for_each_rtwvif(rtwdev, rtwvif) + __rtw89_swap_chanctx(rtwvif, idx1, idx2); cur = atomic_read(&hal->roc_chanctx_idx); if (cur == idx1) @@ -2444,16 +2646,22 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, } int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx) { struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; struct rtw89_entity_weight w = {}; - rtwvif->chanctx_idx = cfg->idx; - rtwvif->chanctx_assigned = true; + rtwvif_link->chanctx_idx = cfg->idx; + rtwvif_link->chanctx_assigned = true; cfg->ref_count++; + if (list_empty(&rtwvif->mgnt_entry)) + list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list); + if (cfg->idx == RTW89_CHANCTX_0) goto out; @@ -2469,20 +2677,24 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, } void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx) { struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_hal *hal = &rtwdev->hal; enum rtw89_chanctx_idx roll; enum rtw89_entity_mode cur; enum rtw89_entity_mode new; int ret; - rtwvif->chanctx_idx = RTW89_CHANCTX_0; - rtwvif->chanctx_assigned = false; + rtwvif_link->chanctx_idx = RTW89_CHANCTX_0; + rtwvif_link->chanctx_assigned = false; cfg->ref_count--; + if (!rtw89_vif_is_active_role(rtwvif)) + list_del_init(&rtwvif->mgnt_entry); + if (cfg->ref_count != 0) goto out; diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index c6d31984e57536..2eb31dff208310 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -43,18 +43,21 @@ struct rtw89_entity_weight { unsigned int active_roles; }; -static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev) +static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) { struct rtw89_hal *hal = &rtwdev->hal; - return READ_ONCE(hal->entity_active); + return READ_ONCE(hal->entity_active[phy_idx]); } -static inline void rtw89_set_entity_state(struct rtw89_dev *rtwdev, bool active) +static inline void rtw89_set_entity_state(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + bool active) { struct rtw89_hal *hal = &rtwdev->hal; - WRITE_ONCE(hal->entity_active, active); + WRITE_ONCE(hal->entity_active[phy_idx], active); } static inline @@ -98,6 +101,14 @@ void rtw89_chanctx_track(struct rtw89_dev *rtwdev); void rtw89_chanctx_pause(struct rtw89_dev *rtwdev, enum rtw89_chanctx_pause_reasons rsn); void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev); + +const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, + const char *caller_message, + u8 link_index); + +#define rtw89_mgnt_chan_get(rtwdev, link_index) \ + __rtw89_mgnt_chan_get(rtwdev, __func__, link_index) + int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx); void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, @@ -106,10 +117,10 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx, u32 changed); int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx); void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx); #endif diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 8d27374db83ca0..68316d44b20430 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -125,6 +125,9 @@ static const u32 cxtbl[] = { 0xfafaaafa, /* 23 */ 0xfafffaff, /* 24 */ 0xea6a5a5a, /* 25 */ + 0xfaff5aff, /* 26 */ + 0xffffdfff, /* 27 */ + 0xe6555555, /* 28 */ }; static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { @@ -134,77 +137,88 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, - .fwevntrptl = 1, .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, + .max_role_num = 6, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0), .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, - .fwevntrptl = 1, .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_type = 1, .info_buf = 1800, + .max_role_num = 6, }, {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, + .max_role_num = 6, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, + .max_role_num = 6, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, + .max_role_num = 6, }, {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1280, + .max_role_num = 5, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1024, + .max_role_num = 5, }, /* keep it to be the last as default entry */ @@ -213,7 +227,8 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1, .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, - .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5, + .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1024, + .max_role_num = 5, }, }; @@ -224,7 +239,7 @@ static const union rtw89_btc_wl_state_map btc_scanning_map = { .scan = 1, .connecting = 1, .roaming = 1, - .transacting = 1, + .dbccing = 1, ._4way = 1, }, }; @@ -2492,6 +2507,8 @@ static void btc_fw_set_monreg(struct rtw89_dev *rtwdev) if (ver->fcxmreg == 7) { sz = struct_size(v7, regs, n); v7 = kmalloc(sz, GFP_KERNEL); + if (!v7) + return; v7->type = RPT_EN_MREG; v7->fver = ver->fcxmreg; v7->len = n; @@ -2506,6 +2523,8 @@ static void btc_fw_set_monreg(struct rtw89_dev *rtwdev) } else { sz = struct_size(v1, regs, n); v1 = kmalloc(sz, GFP_KERNEL); + if (!v1) + return; v1->fver = ver->fcxmreg; v1->reg_num = n; memcpy(v1->regs, chip->mon_reg, flex_array_size(v1, regs, n)); @@ -3017,7 +3036,7 @@ static void _update_btc_state_map(struct rtw89_dev *rtwdev) struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; if (wl->status.map.connecting || wl->status.map._4way || - wl->status.map.roaming) { + wl->status.map.roaming || wl->status.map.dbccing) { cx->state_map = BTC_WLINKING; } else if (wl->status.map.scan) { /* wl scan */ if (bt_linfo->status.map.inq_pag) @@ -3680,6 +3699,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_fbtc_tdma *t = &dm->tdma; struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &btc->cx.wl.role_info_v1; + struct rtw89_btc_bt_a2dp_desc *a2dp = &btc->cx.bt.link_info.a2dp_desc; struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt.link_info.hid_desc; struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt.link_info.hfp_desc; struct rtw89_btc_wl_info *wl = &btc->cx.wl; @@ -3721,8 +3741,6 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) tbl_w1 = cxtbl[16]; } - btc->bt_req_en = false; - switch (type) { case BTC_CXP_USERDEF0: btc->update_policy_force = true; @@ -3744,6 +3762,10 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) case BTC_CXP_OFF_WL: _slot_set_tbl(btc, CXST_OFF, cxtbl[1]); break; + case BTC_CXP_OFF_WL2: + _slot_set_tbl(btc, CXST_OFF, cxtbl[1]); + _slot_set_type(btc, CXST_OFF, SLOT_ISO); + break; case BTC_CXP_OFF_EQ0: _slot_set_tbl(btc, CXST_OFF, cxtbl[0]); _slot_set_type(btc, CXST_OFF, SLOT_ISO); @@ -3757,6 +3779,12 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) case BTC_CXP_OFF_EQ3: _slot_set_tbl(btc, CXST_OFF, cxtbl[24]); break; + case BTC_CXP_OFF_EQ4: + _slot_set_tbl(btc, CXST_OFF, cxtbl[26]); + break; + case BTC_CXP_OFF_EQ5: + _slot_set_tbl(btc, CXST_OFF, cxtbl[27]); + break; case BTC_CXP_OFF_BWB0: _slot_set_tbl(btc, CXST_OFF, cxtbl[5]); break; @@ -3788,7 +3816,6 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) } break; case BTC_CXP_OFFE: /* TDMA off + beacon protect + Ext_control */ - btc->bt_req_en = true; _write_scbd(rtwdev, BTC_WSCB_TDMA, true); *t = t_def[CXTD_OFF_EXT]; @@ -3831,9 +3858,12 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype); break; case BTC_CXP_OFFE_2GBWMIXB: - _slot_set(btc, CXST_E2G, 0, 0x55555555, SLOT_MIX); + if (a2dp->exist) + _slot_set(btc, CXST_E2G, 0, cxtbl[2], SLOT_MIX); + else + _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_MIX); _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, - cpu_to_le32(0x55555555), s_def[CXST_EBT].cxtype); + s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); break; case BTC_CXP_OFFE_WL: /* for 4-way */ _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_MIX); @@ -3842,6 +3872,8 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) default: break; } + _slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur, + s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype); _slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur, s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype); break; @@ -4246,6 +4278,7 @@ static void _set_ant_v0(struct rtw89_dev *rtwdev, bool force_exec, _set_bt_plut(rtwdev, BTC_PHY_ALL, BTC_PLT_NONE, BTC_PLT_NONE); break; case BTC_ANT_WRFK: + case BTC_ANT_WRFK2: rtw89_chip_cfg_ctrl_path(rtwdev, BTC_CTRL_BY_WL); _set_gnt(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO); _set_bt_plut(rtwdev, phy_map, BTC_PLT_NONE, BTC_PLT_NONE); @@ -4623,12 +4656,21 @@ static void _action_bt_a2dpsink(struct rtw89_dev *rtwdev) static void _action_bt_pan(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info; + struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc; + struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc; _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G); switch (btc->cx.state_map) { case BTC_WBUSY_BNOSCAN: /* wl-busy + bt-PAN */ - _set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN); + if (a2dp.active || !pan.exist) { + btc->dm.slot_dur[CXST_W1] = 80; + btc->dm.slot_dur[CXST_B1] = 20; + _set_policy(rtwdev, BTC_CXP_PFIX_TDW1B1, BTC_ACT_BT_PAN); + } else { + _set_policy(rtwdev, BTC_CXP_PFIX_TD5050, BTC_ACT_BT_PAN); + } break; case BTC_WBUSY_BSCAN: /* wl-busy + bt-inq + bt-PAN */ _set_policy(rtwdev, BTC_CXP_PFIX_TD3070, BTC_ACT_BT_PAN); @@ -4814,8 +4856,16 @@ static void _action_wl_rfk(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): band = %d\n", __func__, rfk.band); - _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK); - _set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK); + btc->dm.tdma_instant_excute = 1; + + if (rfk.state == BTC_WRFK_ONESHOT_START || + btc->ant_type == BTC_ANT_SHARED) { + _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK2); + _set_policy(rtwdev, BTC_CXP_OFF_WL2, BTC_ACT_WL_RFK); + } else { + _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WRFK); + _set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_WL_RFK); + } } static void _set_btg_ctrl(struct rtw89_dev *rtwdev) @@ -4855,6 +4905,8 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) if (rtwdev->dbcc_en) { if (ver->fwlrole == 0) { + wl_rinfo.dbcc_2g_phy = RTW89_PHY_MAX; + for (i = 0; i < RTW89_PHY_MAX; i++) { if (wl_dinfo->real_band[i] == RTW89_BAND_2G) wl_rinfo.dbcc_2g_phy = i; @@ -4989,18 +5041,16 @@ struct rtw89_txtime_data { bool reenable; }; -static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) +static void __rtw89_tx_time_iter(struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct rtw89_txtime_data *iter_data) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_txtime_data *iter_data = - (struct rtw89_txtime_data *)data; struct rtw89_dev *rtwdev = iter_data->rtwdev; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_wl_info *wl = &cx->wl; struct rtw89_btc_wl_link_info *plink = NULL; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u32 tx_time = iter_data->tx_time; u8 tx_retry = iter_data->tx_retry; u16 enable = iter_data->enable; @@ -5023,8 +5073,8 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) /* backup the original tx time before tx-limit on */ if (reenable) { - rtw89_mac_get_tx_time(rtwdev, rtwsta, &plink->tx_time); - rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta, &plink->tx_retry); + rtw89_mac_get_tx_time(rtwdev, rtwsta_link, &plink->tx_time); + rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta_link, &plink->tx_retry); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reenable, tx_time=%d tx_retry= %d\n", __func__, plink->tx_time, plink->tx_retry); @@ -5032,22 +5082,37 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) /* restore the original tx time if no tx-limit */ if (!enable) { - rtw89_mac_set_tx_time(rtwdev, rtwsta, true, plink->tx_time); - rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, true, + rtw89_mac_set_tx_time(rtwdev, rtwsta_link, true, plink->tx_time); + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, true, plink->tx_retry); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): restore, tx_time=%d tx_retry= %d\n", __func__, plink->tx_time, plink->tx_retry); } else { - rtw89_mac_set_tx_time(rtwdev, rtwsta, false, tx_time); - rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta, false, tx_retry); + rtw89_mac_set_tx_time(rtwdev, rtwsta_link, false, tx_time); + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, tx_retry); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): set, tx_time=%d tx_retry= %d\n", __func__, tx_time, tx_retry); } } +static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_txtime_data *iter_data = + (struct rtw89_txtime_data *)data; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + __rtw89_tx_time_iter(rtwvif_link, rtwsta_link, iter_data); + } +} + static void _set_wl_tx_limit(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -5231,8 +5296,14 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) struct rtw89_btc_bt_hid_desc hid = bt_linfo->hid_desc; struct rtw89_btc_bt_a2dp_desc a2dp = bt_linfo->a2dp_desc; struct rtw89_btc_bt_pan_desc pan = bt_linfo->pan_desc; + struct rtw89_btc_dm *dm = &btc->dm; u8 profile_map = 0; + if (dm->freerun_chk) { + _action_freerun(rtwdev); + return; + } + if (bt_linfo->hfp_desc.exist) profile_map |= BTC_BT_HFP; @@ -5247,30 +5318,20 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) switch (profile_map) { case BTC_BT_NOPROFILE: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); - else if (pan.active) + if (pan.active) _action_bt_pan(rtwdev); else _action_bt_idle(rtwdev); break; case BTC_BT_HFP: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); - else - _action_bt_hfp(rtwdev); + _action_bt_hfp(rtwdev); break; case BTC_BT_HFP | BTC_BT_HID: case BTC_BT_HID: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); - else - _action_bt_hid(rtwdev); + _action_bt_hid(rtwdev); break; case BTC_BT_A2DP: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); - else if (a2dp.sink) + if (a2dp.sink) _action_bt_a2dpsink(rtwdev); else if (bt_linfo->multi_link.now && !hid.pair_cnt) _action_bt_a2dp_pan(rtwdev); @@ -5283,13 +5344,18 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) case BTC_BT_A2DP | BTC_BT_HFP: case BTC_BT_A2DP | BTC_BT_HID: case BTC_BT_A2DP | BTC_BT_HFP | BTC_BT_HID: - if (_check_freerun(rtwdev)) - _action_freerun(rtwdev); + if (a2dp.sink) + _action_bt_a2dpsink(rtwdev); + else if (pan.active) + _action_bt_a2dp_pan_hid(rtwdev); else _action_bt_a2dp_hid(rtwdev); break; case BTC_BT_A2DP | BTC_BT_PAN: - _action_bt_a2dp_pan(rtwdev); + if (a2dp.sink) + _action_bt_a2dpsink(rtwdev); + else + _action_bt_a2dp_pan(rtwdev); break; case BTC_BT_PAN | BTC_BT_HFP: case BTC_BT_PAN | BTC_BT_HID: @@ -5299,7 +5365,10 @@ static void _action_by_bt(struct rtw89_dev *rtwdev) case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HID: case BTC_BT_A2DP | BTC_BT_PAN | BTC_BT_HFP: default: - _action_bt_a2dp_pan_hid(rtwdev); + if (a2dp.sink) + _action_bt_a2dpsink(rtwdev); + else + _action_bt_a2dp_pan_hid(rtwdev); break; } } @@ -5319,7 +5388,7 @@ static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev) policy_type = BTC_CXP_OFFE_WL; else if (btc->cx.wl.status.val & btc_scanning_map.val) policy_type = BTC_CXP_OFFE_2GBWMIXB; - else if (btc->cx.bt.link_info.profile_cnt.now == 0) + else if (btc->cx.bt.link_info.status.map.connect == 0) policy_type = BTC_CXP_OFFE_2GISOB; else policy_type = BTC_CXP_OFFE_2GBWISOB; @@ -6893,6 +6962,8 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) bt->scan_rx_low_pri = false; igno_bt = false; + dm->freerun_chk = _check_freerun(rtwdev); /* check if meet freerun */ + if (always_freerun) { _action_freerun(rtwdev); igno_bt = true; @@ -6931,18 +7002,9 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason) goto exit; } - if (cx->state_map == BTC_WLINKING) { - if (mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_2G_STA || - mode == BTC_WLINK_5G) { - _action_wl_scan(rtwdev); - bt->scan_rx_low_pri = false; - goto exit; - } - } - - if (wl->status.map.scan) { + if (wl->status.val & btc_scanning_map.val) { _action_wl_scan(rtwdev); - bt->scan_rx_low_pri = false; + bt->scan_rx_low_pri = true; goto exit; } @@ -7178,10 +7240,6 @@ void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band) btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++; - wl->scan_info.band[phy_idx] = band; - wl->scan_info.phy_map |= BIT(phy_idx); - _fw_set_drv_info(rtwdev, CXDRVINFO_SCAN); - if (rtwdev->dbcc_en) { wl->dbcc_info.scan_band[phy_idx] = band; _update_dbcc_band(rtwdev, phy_idx); @@ -7376,13 +7434,7 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) "[BTC], %s(): bt_info[2]=0x%02x\n", __func__, bt->raw_info[2]); - /* reset to mo-connect before update */ - b->status.val = BTC_BLINK_NOCONNECT; b->profile_cnt.last = b->profile_cnt.now; - b->relink.last = b->relink.now; - a2dp->exist_last = a2dp->exist; - b->multi_link.last = b->multi_link.now; - bt->inq_pag.last = bt->inq_pag.now; b->profile_cnt.now = 0; hid->type = 0; @@ -7401,7 +7453,8 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) b->profile_cnt.now += (u8)hid->exist; a2dp->exist = btinfo.lb2.a2dp; b->profile_cnt.now += (u8)a2dp->exist; - pan->active = btinfo.lb2.pan; + pan->exist = btinfo.lb2.pan; + b->profile_cnt.now += (u8)pan->exist; btc->dm.trx_info.bt_profile = u32_get_bits(btinfo.val, BT_PROFILE_PROTOCOL_MASK); /* parse raw info low-Byte3 */ @@ -7425,8 +7478,14 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) /* parse raw info high-Byte1 */ btinfo.val = bt->raw_info[BTC_BTINFO_H1]; b->status.map.ble_connect = btinfo.hb1.ble_connect; - if (btinfo.hb1.ble_connect) - hid->type |= (hid->exist ? BTC_HID_BLE : BTC_HID_RCU); + if (btinfo.hb1.ble_connect) { + if (hid->exist) + hid->type |= BTC_HID_BLE; + else if (btinfo.hb1.voice) + hid->type |= BTC_HID_RCU_VOICE; + else + hid->type |= BTC_HID_RCU; + } cx->cnt_bt[BTC_BCNT_REINIT] += !!(btinfo.hb1.reinit && !bt->reinit); bt->reinit = btinfo.hb1.reinit; @@ -7438,7 +7497,6 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) if (bt->igno_wl && !cx->wl.status.map.rf_off) _set_bt_ignore_wlan_act(rtwdev, false); - hid->type |= (btinfo.hb1.voice ? BTC_HID_RCU_VOICE : 0); bt->ble_scan_en = btinfo.hb1.ble_scan; cx->cnt_bt[BTC_BCNT_ROLESW] += !!(btinfo.hb1.role_sw && !b->role_sw); @@ -7448,8 +7506,7 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) /* parse raw info high-Byte2 */ btinfo.val = bt->raw_info[BTC_BTINFO_H2]; - pan->exist = btinfo.hb2.pan_active; - b->profile_cnt.now += (u8)pan->exist; + pan->active = !!btinfo.hb2.pan_active; cx->cnt_bt[BTC_BCNT_AFH] += !!(btinfo.hb2.afh_update && !b->afh_update); b->afh_update = btinfo.hb2.afh_update; @@ -7457,8 +7514,9 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) b->slave_role = btinfo.hb2.slave; hid->slot_info = btinfo.hb2.hid_slot; hid->pair_cnt = btinfo.hb2.hid_cnt; - hid->type |= (hid->slot_info == BTC_HID_218 ? - BTC_HID_218 : BTC_HID_418); + if (!b->status.map.ble_connect || hid->pair_cnt > 1) + hid->type |= (hid->slot_info == BTC_HID_218 ? + BTC_HID_218 : BTC_HID_418); /* parse raw info high-Byte3 */ btinfo.val = bt->raw_info[BTC_BTINFO_H3]; a2dp->bitpool = btinfo.hb3.a2dp_bitpool; @@ -7481,13 +7539,16 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) _run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO); } -void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, enum btc_role_state state) +void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + enum btc_role_state state) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); + rtwvif_link->chanctx_idx); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct ieee80211_bss_conf *bss_conf; + struct ieee80211_link_sta *link_sta; struct rtw89_btc *btc = &rtwdev->btc; const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; @@ -7495,51 +7556,59 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif struct rtw89_btc_wl_link_info *wlinfo = NULL; u8 mode = 0, rlink_id, link_mode_ori, pta_req_mac_ori, wa_type; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], role is STA=%d\n", vif->type == NL80211_IFTYPE_STATION); - rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif->port); + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], port=%d\n", rtwvif_link->port); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], band=%d ch=%d bw=%d\n", chan->band_type, chan->channel, chan->band_width); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], associated=%d\n", state == BTC_ROLE_MSTS_STA_CONN_END); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], bcn_period=%d dtim_period=%d\n", - vif->bss_conf.beacon_int, vif->bss_conf.dtim_period); + bss_conf->beacon_int, bss_conf->dtim_period); + + if (rtwsta_link) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); - if (rtwsta) { rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA mac_id=%d\n", - rtwsta->mac_id); + rtwsta_link->mac_id); rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], STA support HE=%d VHT=%d HT=%d\n", - sta->deflink.he_cap.has_he, - sta->deflink.vht_cap.vht_supported, - sta->deflink.ht_cap.ht_supported); - if (sta->deflink.he_cap.has_he) + link_sta->he_cap.has_he, + link_sta->vht_cap.vht_supported, + link_sta->ht_cap.ht_supported); + if (link_sta->he_cap.has_he) mode |= BIT(BTC_WL_MODE_HE); - if (sta->deflink.vht_cap.vht_supported) + if (link_sta->vht_cap.vht_supported) mode |= BIT(BTC_WL_MODE_VHT); - if (sta->deflink.ht_cap.ht_supported) + if (link_sta->ht_cap.ht_supported) mode |= BIT(BTC_WL_MODE_HT); r.mode = mode; } - if (rtwvif->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX) + if (rtwvif_link->wifi_role >= RTW89_WIFI_ROLE_MLME_MAX) { + rcu_read_unlock(); return; + } rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC], wifi_role=%d\n", rtwvif->wifi_role); + "[BTC], wifi_role=%d\n", rtwvif_link->wifi_role); - r.role = rtwvif->wifi_role; - r.phy = rtwvif->phy_idx; - r.pid = rtwvif->port; + r.role = rtwvif_link->wifi_role; + r.phy = rtwvif_link->phy_idx; + r.pid = rtwvif_link->port; r.active = true; r.connected = MLME_LINKED; - r.bcn_period = vif->bss_conf.beacon_int; - r.dtim_period = vif->bss_conf.dtim_period; + r.bcn_period = bss_conf->beacon_int; + r.dtim_period = bss_conf->dtim_period; r.band = chan->band_type; r.ch = chan->channel; r.bw = chan->band_width; @@ -7547,10 +7616,12 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif r.chdef.center_ch = chan->channel; r.chdef.bw = chan->band_width; r.chdef.chan = chan->primary_channel; - ether_addr_copy(r.mac_addr, rtwvif->mac_addr); + ether_addr_copy(r.mac_addr, rtwvif_link->mac_addr); - if (rtwsta && vif->type == NL80211_IFTYPE_STATION) - r.mac_id = rtwsta->mac_id; + rcu_read_unlock(); + + if (rtwsta_link && vif->type == NL80211_IFTYPE_STATION) + r.mac_id = rtwsta_link->mac_id; btc->dm.cnt_notify[BTC_NCNT_ROLE_INFO]++; @@ -7781,26 +7852,26 @@ struct rtw89_btc_wl_sta_iter_data { bool is_traffic_change; }; -static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) +static +void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct rtw89_btc_wl_sta_iter_data *iter_data) { - struct rtw89_btc_wl_sta_iter_data *iter_data = - (struct rtw89_btc_wl_sta_iter_data *)data; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_dev *rtwdev = iter_data->rtwdev; struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_link_info *link_info = NULL; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; struct rtw89_traffic_stats *link_info_t = NULL; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_traffic_stats *stats = &rtwvif->stats; const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc_wl_role_info *r; struct rtw89_btc_wl_role_info_v1 *r1; u32 last_tx_rate, last_rx_rate; u16 last_tx_lvl, last_rx_lvl; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u8 rssi; u8 busy = 0; u8 dir = 0; @@ -7808,11 +7879,11 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) u8 i = 0; bool is_sta_change = false, is_traffic_change = false; - rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR; + rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR; rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi); link_info = &wl->link_info[port]; - link_info->stat.traffic = rtwvif->stats; + link_info->stat.traffic = *stats; link_info_t = &link_info->stat.traffic; if (link_info->connected == MLME_NO_LINK) { @@ -7860,19 +7931,19 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) iter_data->busy_all |= busy; iter_data->dir_all |= BIT(dir); - if (rtwsta->rx_hw_rate <= RTW89_HW_RATE_CCK2 && + if (rtwsta_link->rx_hw_rate <= RTW89_HW_RATE_CCK2 && last_rx_rate > RTW89_HW_RATE_CCK2 && link_info_t->rx_tfc_lv > RTW89_TFC_IDLE) link_info->rx_rate_drop_cnt++; - if (last_tx_rate != rtwsta->ra_report.hw_rate || - last_rx_rate != rtwsta->rx_hw_rate || + if (last_tx_rate != rtwsta_link->ra_report.hw_rate || + last_rx_rate != rtwsta_link->rx_hw_rate || last_tx_lvl != link_info_t->tx_tfc_lv || last_rx_lvl != link_info_t->rx_tfc_lv) is_traffic_change = true; - link_info_t->tx_rate = rtwsta->ra_report.hw_rate; - link_info_t->rx_rate = rtwsta->rx_hw_rate; + link_info_t->tx_rate = rtwsta_link->ra_report.hw_rate; + link_info_t->rx_rate = rtwsta_link->rx_hw_rate; if (link_info->role == RTW89_WIFI_ROLE_STATION || link_info->role == RTW89_WIFI_ROLE_P2P_CLIENT) { @@ -7884,19 +7955,19 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) r = &wl->role_info; r->active_role[port].tx_lvl = stats->tx_tfc_lv; r->active_role[port].rx_lvl = stats->rx_tfc_lv; - r->active_role[port].tx_rate = rtwsta->ra_report.hw_rate; - r->active_role[port].rx_rate = rtwsta->rx_hw_rate; + r->active_role[port].tx_rate = rtwsta_link->ra_report.hw_rate; + r->active_role[port].rx_rate = rtwsta_link->rx_hw_rate; } else if (ver->fwlrole == 1) { r1 = &wl->role_info_v1; r1->active_role_v1[port].tx_lvl = stats->tx_tfc_lv; r1->active_role_v1[port].rx_lvl = stats->rx_tfc_lv; - r1->active_role_v1[port].tx_rate = rtwsta->ra_report.hw_rate; - r1->active_role_v1[port].rx_rate = rtwsta->rx_hw_rate; + r1->active_role_v1[port].tx_rate = rtwsta_link->ra_report.hw_rate; + r1->active_role_v1[port].rx_rate = rtwsta_link->rx_hw_rate; } else if (ver->fwlrole == 2) { dm->trx_info.tx_lvl = stats->tx_tfc_lv; dm->trx_info.rx_lvl = stats->rx_tfc_lv; - dm->trx_info.tx_rate = rtwsta->ra_report.hw_rate; - dm->trx_info.rx_rate = rtwsta->rx_hw_rate; + dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate; + dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate; } dm->trx_info.tx_tp = link_info_t->tx_throughput; @@ -7916,6 +7987,21 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) iter_data->is_traffic_change = true; } +static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_btc_wl_sta_iter_data *iter_data = + (struct rtw89_btc_wl_sta_iter_data *)data; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + __rtw89_btc_ntfy_wl_sta_iter(rtwvif_link, rtwsta_link, iter_data); + } +} + #define BTC_NHM_CHK_INTVL 20 void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev) @@ -7965,6 +8051,53 @@ void rtw89_btc_ntfy_wl_sta(struct rtw89_dev *rtwdev) } } +static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func) +{ + struct rtw89_btc *btc = &rtwdev->btc; + const struct rtw89_btc_ver *ver = btc->ver; + + switch (func) { + case BTF_EVNT_RPT: + case BTF_EVNT_BT_INFO: + case BTF_EVNT_BT_SCBD: + case BTF_EVNT_BT_REG: + case BTF_EVNT_CX_RUNINFO: + case BTF_EVNT_BT_PSD: + return func; + case BTF_EVNT_BT_DEV_INFO: + if (ver->fwc2hfunc == 0) + return BTF_EVNT_BUF_OVERFLOW; + else + return BTF_EVNT_BT_DEV_INFO; + case BTF_EVNT_BT_LEAUDIO_INFO: + if (ver->fwc2hfunc == 0) + return BTF_EVNT_C2H_LOOPBACK; + else if (ver->fwc2hfunc == 1) + return BTF_EVNT_BUF_OVERFLOW; + else if (ver->fwc2hfunc == 2) + return func; + else + return BTF_EVNT_MAX; + case BTF_EVNT_BUF_OVERFLOW: + if (ver->fwc2hfunc == 0) + return BTF_EVNT_MAX; + else if (ver->fwc2hfunc == 1) + return BTF_EVNT_C2H_LOOPBACK; + else if (ver->fwc2hfunc == 2) + return func; + else + return BTF_EVNT_MAX; + case BTF_EVNT_C2H_LOOPBACK: + if (ver->fwc2hfunc == 2) + return func; + else + return BTF_EVNT_MAX; + case BTF_EVNT_MAX: + default: + return BTF_EVNT_MAX; + } +} + void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func) { @@ -7981,9 +8114,13 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (class != BTFC_FW_EVENT) return; + func = rtw89_btc_c2h_get_index_by_ver(rtwdev, func); + switch (func) { - case BTF_EVNT_RPT: case BTF_EVNT_BUF_OVERFLOW: + pfwinfo->event[func]++; + break; + case BTF_EVNT_RPT: pfwinfo->event[func]++; /* Don't need rtw89_leave_ps_mode() */ btc_fw_event(rtwdev, func, buf, len); diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index de53b56632f7c6..dbdb56e063ef03 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -271,8 +271,10 @@ void rtw89_btc_ntfy_eapol_packet_work(struct work_struct *work); void rtw89_btc_ntfy_arp_packet_work(struct work_struct *work); void rtw89_btc_ntfy_dhcp_packet_work(struct work_struct *work); void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work); -void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, enum btc_role_state state); +void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + enum btc_role_state state); void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_state); void rtw89_btc_ntfy_wl_rfk(struct rtw89_dev *rtwdev, u8 phy_map, enum btc_wl_rfk_type type, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 4553810634c66b..e5b2968c1431f2 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -192,13 +192,13 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = { { .limits = rtw89_iface_limits, .n_limits = ARRAY_SIZE(rtw89_iface_limits), - .max_interfaces = 2, + .max_interfaces = RTW89_MAX_INTERFACE_NUM, .num_different_channels = 1, }, { .limits = rtw89_iface_limits_mcc, .n_limits = ARRAY_SIZE(rtw89_iface_limits_mcc), - .max_interfaces = 2, + .max_interfaces = RTW89_MAX_INTERFACE_NUM, .num_different_channels = 2, }, }; @@ -341,83 +341,47 @@ void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef, rtw89_chan_create(chan, center_chan, channel->hw_value, band, bandwidth); } -void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev) +static void __rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) { - struct rtw89_hal *hal = &rtwdev->hal; const struct rtw89_chip_info *chip = rtwdev->chip; - const struct rtw89_chan *chan; - enum rtw89_chanctx_idx chanctx_idx; - enum rtw89_chanctx_idx roc_idx; - enum rtw89_phy_idx phy_idx; - enum rtw89_entity_mode mode; bool entity_active; - entity_active = rtw89_get_entity_state(rtwdev); + entity_active = rtw89_get_entity_state(rtwdev, phy_idx); if (!entity_active) return; - mode = rtw89_get_entity_mode(rtwdev); - switch (mode) { - case RTW89_ENTITY_MODE_SCC: - case RTW89_ENTITY_MODE_MCC: - chanctx_idx = RTW89_CHANCTX_0; - break; - case RTW89_ENTITY_MODE_MCC_PREPARE: - chanctx_idx = RTW89_CHANCTX_1; - break; - default: - WARN(1, "Invalid ent mode: %d\n", mode); - return; - } + chip->ops->set_txpwr(rtwdev, chan, phy_idx); +} - roc_idx = atomic_read(&hal->roc_chanctx_idx); - if (roc_idx != RTW89_CHANCTX_IDLE) - chanctx_idx = roc_idx; +void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chan *chan; - phy_idx = RTW89_PHY_0; - chan = rtw89_chan_get(rtwdev, chanctx_idx); - chip->ops->set_txpwr(rtwdev, chan, phy_idx); + chan = rtw89_mgnt_chan_get(rtwdev, 0); + __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_0); + + if (!rtwdev->support_mlo) + return; + + chan = rtw89_mgnt_chan_get(rtwdev, 1); + __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_1); } -int rtw89_set_channel(struct rtw89_dev *rtwdev) +static void __rtw89_set_channel(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_mac_idx mac_idx, + enum rtw89_phy_idx phy_idx) { - struct rtw89_hal *hal = &rtwdev->hal; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_chan_rcd *chan_rcd; - const struct rtw89_chan *chan; - enum rtw89_chanctx_idx chanctx_idx; - enum rtw89_chanctx_idx roc_idx; - enum rtw89_mac_idx mac_idx; - enum rtw89_phy_idx phy_idx; struct rtw89_channel_help_params bak; - enum rtw89_entity_mode mode; bool entity_active; - entity_active = rtw89_get_entity_state(rtwdev); - - mode = rtw89_entity_recalc(rtwdev); - switch (mode) { - case RTW89_ENTITY_MODE_SCC: - case RTW89_ENTITY_MODE_MCC: - chanctx_idx = RTW89_CHANCTX_0; - break; - case RTW89_ENTITY_MODE_MCC_PREPARE: - chanctx_idx = RTW89_CHANCTX_1; - break; - default: - WARN(1, "Invalid ent mode: %d\n", mode); - return -EINVAL; - } - - roc_idx = atomic_read(&hal->roc_chanctx_idx); - if (roc_idx != RTW89_CHANCTX_IDLE) - chanctx_idx = roc_idx; + entity_active = rtw89_get_entity_state(rtwdev, phy_idx); - mac_idx = RTW89_MAC_0; - phy_idx = RTW89_PHY_0; - - chan = rtw89_chan_get(rtwdev, chanctx_idx); - chan_rcd = rtw89_chan_rcd_get(rtwdev, chanctx_idx); + chan_rcd = rtw89_chan_rcd_get_by_chan(chan); rtw89_chip_set_channel_prepare(rtwdev, &bak, chan, mac_idx, phy_idx); @@ -432,17 +396,30 @@ int rtw89_set_channel(struct rtw89_dev *rtwdev) rtw89_chip_rfk_band_changed(rtwdev, phy_idx, chan); } - rtw89_set_entity_state(rtwdev, true); - return 0; + rtw89_set_entity_state(rtwdev, phy_idx, true); } -void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_chan *chan) +int rtw89_set_channel(struct rtw89_dev *rtwdev) { - const struct cfg80211_chan_def *chandef; + const struct rtw89_chan *chan; + enum rtw89_entity_mode mode; + + mode = rtw89_entity_recalc(rtwdev); + if (mode < 0 || mode >= NUM_OF_RTW89_ENTITY_MODE) { + WARN(1, "Invalid ent mode: %d\n", mode); + return -EINVAL; + } + + chan = rtw89_mgnt_chan_get(rtwdev, 0); + __rtw89_set_channel(rtwdev, chan, RTW89_MAC_0, RTW89_PHY_0); + + if (!rtwdev->support_mlo) + return 0; + + chan = rtw89_mgnt_chan_get(rtwdev, 1); + __rtw89_set_channel(rtwdev, chan, RTW89_MAC_1, RTW89_PHY_1); - chandef = rtw89_chandef_get(rtwdev, rtwvif->chanctx_idx); - rtw89_get_channel_params(chandef, chan); + return 0; } static enum rtw89_core_tx_type @@ -463,8 +440,9 @@ rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req, enum btc_pkt_type pkt_type) { - struct ieee80211_sta *sta = tx_req->sta; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct ieee80211_link_sta *link_sta; struct sk_buff *skb = tx_req->skb; struct rtw89_sta *rtwsta; u8 ampdu_num; @@ -478,21 +456,26 @@ rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev, if (!(IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU)) return; - if (!sta) { + if (!rtwsta_link) { rtw89_warn(rtwdev, "cannot set ampdu info without sta\n"); return; } tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; - rtwsta = (struct rtw89_sta *)sta->drv_priv; + rtwsta = rtwsta_link->rtwsta; + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); ampdu_num = (u8)((rtwsta->ampdu_params[tid].agg_num ? rtwsta->ampdu_params[tid].agg_num : - 4 << sta->deflink.ht_cap.ampdu_factor) - 1); + 4 << link_sta->ht_cap.ampdu_factor) - 1); desc_info->agg_en = true; - desc_info->ampdu_density = sta->deflink.ht_cap.ampdu_density; + desc_info->ampdu_density = link_sta->ht_cap.ampdu_density; desc_info->ampdu_num = ampdu_num; + + rcu_read_unlock(); } static void @@ -569,9 +552,13 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan) { struct sk_buff *skb = tx_req->skb; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = tx_info->control.vif; + struct ieee80211_bss_conf *bss_conf; u16 lowest_rate; + u16 rate; if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE || (vif && vif->p2p)) @@ -581,25 +568,35 @@ static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev, else lowest_rate = RTW89_HW_RATE_OFDM6; - if (!vif || !vif->bss_conf.basic_rates || !tx_req->sta) + if (!rtwvif_link) return lowest_rate; - return __ffs(vif->bss_conf.basic_rates) + lowest_rate; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + if (!bss_conf->basic_rates || !rtwsta_link) { + rate = lowest_rate; + goto out; + } + + rate = __ffs(bss_conf->basic_rates) + lowest_rate; + +out: + rcu_read_unlock(); + + return rate; } static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { - struct ieee80211_vif *vif = tx_req->vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_sta *rtwsta; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; - if (!sta) - return rtwvif->mac_id; + if (!rtwsta_link) + return rtwvif_link->mac_id; - rtwsta = (struct rtw89_sta *)sta->drv_priv; - return rtwsta->mac_id; + return rtwsta_link->mac_id; } static void rtw89_core_tx_update_llc_hdr(struct rtw89_dev *rtwdev, @@ -618,11 +615,10 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { const struct rtw89_chip_info *chip = rtwdev->chip; - struct ieee80211_vif *vif = tx_req->vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); struct sk_buff *skb = tx_req->skb; u8 qsel, ch_dma; @@ -631,7 +627,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, desc_info->qsel = qsel; desc_info->ch_dma = ch_dma; - desc_info->port = desc_info->hiq ? rtwvif->port : 0; + desc_info->port = desc_info->hiq ? rtwvif_link->port : 0; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); desc_info->hw_ssn_sel = RTW89_MGMT_HW_SSN_SEL; desc_info->hw_seq_mode = RTW89_MGMT_HW_SEQ_MODE; @@ -701,18 +697,28 @@ __rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req, enum btc_pkt_type pkt_type) { - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct sk_buff *skb = tx_req->skb; struct ieee80211_hdr *hdr = (void *)skb->data; + struct ieee80211_link_sta *link_sta; __le16 fc = hdr->frame_control; /* AP IOT issue with EAPoL, ARP and DHCP */ if (pkt_type < PACKET_MAX) return false; - if (!sta || !sta->deflink.he_cap.has_he) + if (!rtwsta_link) + return false; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + if (!link_sta->he_cap.has_he) { + rcu_read_unlock(); return false; + } + + rcu_read_unlock(); if (!ieee80211_is_data_qos(fc)) return false; @@ -720,7 +726,7 @@ __rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev, if (skb_headroom(skb) < IEEE80211_HT_CTL_LEN) return false; - if (rtwsta && rtwsta->ra_report.might_fallback_legacy) + if (rtwsta_link && rtwsta_link->ra_report.might_fallback_legacy) return false; return true; @@ -730,8 +736,7 @@ static void __rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct sk_buff *skb = tx_req->skb; struct ieee80211_hdr *hdr = (void *)skb->data; __le16 fc = hdr->frame_control; @@ -747,7 +752,7 @@ __rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev, hdr = data; htc = data + hdr_len; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_ORDER); - *htc = rtwsta->htc_template ? rtwsta->htc_template : + *htc = rtwsta_link->htc_template ? rtwsta_link->htc_template : le32_encode_bits(RTW89_HTC_VARIANT_HE, RTW89_HTC_MASK_VARIANT) | le32_encode_bits(RTW89_HTC_VARIANT_HE_CID_CAS, RTW89_HTC_MASK_CTL_ID); @@ -761,8 +766,7 @@ rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev, enum btc_pkt_type pkt_type) { struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; - struct ieee80211_vif *vif = tx_req->vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; if (!__rtw89_core_tx_check_he_qos_htc(rtwdev, tx_req, pkt_type)) goto desc_bk; @@ -773,23 +777,25 @@ rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev, desc_info->a_ctrl_bsr = true; desc_bk: - if (!rtwvif || rtwvif->last_a_ctrl == desc_info->a_ctrl_bsr) + if (!rtwvif_link || rtwvif_link->last_a_ctrl == desc_info->a_ctrl_bsr) return; - rtwvif->last_a_ctrl = desc_info->a_ctrl_bsr; + rtwvif_link->last_a_ctrl = desc_info->a_ctrl_bsr; desc_info->bk = true; } static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { - struct ieee80211_vif *vif = tx_req->vif; - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern; - enum rtw89_chanctx_idx idx = rtwvif->chanctx_idx; + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern; + enum rtw89_chanctx_idx idx = rtwvif_link->chanctx_idx; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, idx); + struct ieee80211_link_sta *link_sta; u16 lowest_rate; + u16 rate; if (rate_pattern->enable) return rate_pattern->rate; @@ -801,20 +807,31 @@ static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev, else lowest_rate = RTW89_HW_RATE_OFDM6; - if (!sta || !sta->deflink.supp_rates[chan->band_type]) + if (!rtwsta_link) return lowest_rate; - return __ffs(sta->deflink.supp_rates[chan->band_type]) + lowest_rate; + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + if (!link_sta->supp_rates[chan->band_type]) { + rate = lowest_rate; + goto out; + } + + rate = __ffs(link_sta->supp_rates[chan->band_type]) + lowest_rate; + +out: + rcu_read_unlock(); + + return rate; } static void rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { - struct ieee80211_vif *vif = tx_req->vif; - struct ieee80211_sta *sta = tx_req->sta; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_vif_link *rtwvif_link = tx_req->rtwvif_link; + struct rtw89_sta_link *rtwsta_link = tx_req->rtwsta_link; struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; struct sk_buff *skb = tx_req->skb; u8 tid, tid_indicate; @@ -829,10 +846,10 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, desc_info->tid_indicate = tid_indicate; desc_info->qsel = qsel; desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req); - desc_info->port = desc_info->hiq ? rtwvif->port : 0; - desc_info->er_cap = rtwsta ? rtwsta->er_cap : false; - desc_info->stbc = rtwsta ? rtwsta->ra.stbc_cap : false; - desc_info->ldpc = rtwsta ? rtwsta->ra.ldpc_cap : false; + desc_info->port = desc_info->hiq ? rtwvif_link->port : 0; + desc_info->er_cap = rtwsta_link ? rtwsta_link->er_cap : false; + desc_info->stbc = rtwsta_link ? rtwsta_link->ra.stbc_cap : false; + desc_info->ldpc = rtwsta_link ? rtwsta_link->ra.ldpc_cap : false; /* enable wd_info for AMPDU */ desc_info->en_wd_info = true; @@ -907,8 +924,10 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, struct sk_buff *skb = tx_req->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (void *)skb->data; + struct rtw89_addr_cam_entry *addr_cam; enum rtw89_core_tx_type tx_type; enum btc_pkt_type pkt_type; + bool upd_wlan_hdr = false; bool is_bmc; u16 seq; @@ -916,6 +935,11 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, if (tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD) { tx_type = rtw89_core_get_tx_type(rtwdev, skb); tx_req->tx_type = tx_type; + + addr_cam = rtw89_get_addr_cam_of(tx_req->rtwvif_link, + tx_req->rtwsta_link); + if (addr_cam->valid) + upd_wlan_hdr = true; } is_bmc = (is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1)); @@ -925,6 +949,7 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, desc_info->is_bmc = is_bmc; desc_info->wd_page = true; desc_info->hiq = info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM; + desc_info->upd_wlan_hdr = upd_wlan_hdr; switch (tx_req->tx_type) { case RTW89_CORE_TX_TYPE_MGMT: @@ -1027,13 +1052,34 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev, int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel) { + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); struct rtw89_core_tx_request tx_req = {0}; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_sta_link *rtwsta_link = NULL; + struct rtw89_vif_link *rtwvif_link; int ret; + /* By default, driver writes tx via the link on HW-0. And then, + * according to links' status, HW can change tx to another link. + */ + + if (rtwsta) { + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) { + rtw89_err(rtwdev, "tx: find no sta link on HW-0\n"); + return -ENOLINK; + } + } + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "tx: find no vif link on HW-0\n"); + return -ENOLINK; + } + tx_req.skb = skb; - tx_req.sta = sta; - tx_req.vif = vif; + tx_req.rtwvif_link = rtwvif_link; + tx_req.rtwsta_link = rtwsta_link; rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true); rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true); @@ -1302,6 +1348,13 @@ static __le32 rtw89_build_txwd_body5_v2(struct rtw89_tx_desc_info *desc_info) return cpu_to_le32(dword); } +static __le32 rtw89_build_txwd_body6_v2(struct rtw89_tx_desc_info *desc_info) +{ + u32 dword = FIELD_PREP(BE_TXD_BODY6_UPD_WLAN_HDR, desc_info->upd_wlan_hdr); + + return cpu_to_le32(dword); +} + static __le32 rtw89_build_txwd_body7_v2(struct rtw89_tx_desc_info *desc_info) { u32 dword = FIELD_PREP(BE_TXD_BODY7_USERATE_SEL, desc_info->use_rate) | @@ -1365,6 +1418,7 @@ void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev, txwd_body->dword4 = rtw89_build_txwd_body4_v2(desc_info); txwd_body->dword5 = rtw89_build_txwd_body5_v2(desc_info); } + txwd_body->dword6 = rtw89_build_txwd_body6_v2(desc_info); txwd_body->dword7 = rtw89_build_txwd_body7_v2(desc_info); if (!desc_info->en_wd_info) @@ -1514,16 +1568,24 @@ static u8 rtw89_get_data_rate_nss(struct rtw89_dev *rtwdev, u16 data_rate) static void rtw89_core_rx_process_phy_ppdu_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; struct rtw89_rx_phy_ppdu *phy_ppdu = (struct rtw89_rx_phy_ppdu *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct rtw89_dev *rtwdev = rtwsta->rtwdev; struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_sta_link *rtwsta_link; u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; u8 ant_pos = U8_MAX; u8 evm_pos = 0; int i; - if (rtwsta->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self) + /* FIXME: For single link, taking link on HW-0 here is okay. But, when + * enabling multiple active links, we should determine the right link. + */ + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) + return; + + if (rtwsta_link->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self) return; if (hal->ant_diversity && hal->antenna_rx) { @@ -1531,22 +1593,24 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, evm_pos = ant_pos; } - ewma_rssi_add(&rtwsta->avg_rssi, phy_ppdu->rssi_avg); + ewma_rssi_add(&rtwsta_link->avg_rssi, phy_ppdu->rssi_avg); if (ant_pos < ant_num) { - ewma_rssi_add(&rtwsta->rssi[ant_pos], phy_ppdu->rssi[0]); + ewma_rssi_add(&rtwsta_link->rssi[ant_pos], phy_ppdu->rssi[0]); } else { for (i = 0; i < rtwdev->chip->rf_path_num; i++) - ewma_rssi_add(&rtwsta->rssi[i], phy_ppdu->rssi[i]); + ewma_rssi_add(&rtwsta_link->rssi[i], phy_ppdu->rssi[i]); } if (phy_ppdu->ofdm.has && (phy_ppdu->has_data || phy_ppdu->has_bcn)) { - ewma_snr_add(&rtwsta->avg_snr, phy_ppdu->ofdm.avg_snr); + ewma_snr_add(&rtwsta_link->avg_snr, phy_ppdu->ofdm.avg_snr); if (rtw89_get_data_rate_nss(rtwdev, phy_ppdu->rate) == 1) { - ewma_evm_add(&rtwsta->evm_1ss, phy_ppdu->ofdm.evm_min); + ewma_evm_add(&rtwsta_link->evm_1ss, phy_ppdu->ofdm.evm_min); } else { - ewma_evm_add(&rtwsta->evm_min[evm_pos], phy_ppdu->ofdm.evm_min); - ewma_evm_add(&rtwsta->evm_max[evm_pos], phy_ppdu->ofdm.evm_max); + ewma_evm_add(&rtwsta_link->evm_min[evm_pos], + phy_ppdu->ofdm.evm_min); + ewma_evm_add(&rtwsta_link->evm_max[evm_pos], + phy_ppdu->ofdm.evm_max); } } } @@ -1795,32 +1859,58 @@ static void rtw89_core_rx_process_phy_sts(struct rtw89_dev *rtwdev, phy_ppdu); } -static u8 rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev *rtwdev, - u8 desc_info_gi, - bool rx_status, bool eht) +static u8 rtw89_rxdesc_to_nl_he_gi(struct rtw89_dev *rtwdev, + u8 desc_info_gi, + bool rx_status) { switch (desc_info_gi) { case RTW89_GILTF_SGI_4XHE08: case RTW89_GILTF_2XHE08: case RTW89_GILTF_1XHE08: - return eht ? NL80211_RATE_INFO_EHT_GI_0_8 : - NL80211_RATE_INFO_HE_GI_0_8; + return NL80211_RATE_INFO_HE_GI_0_8; case RTW89_GILTF_2XHE16: case RTW89_GILTF_1XHE16: - return eht ? NL80211_RATE_INFO_EHT_GI_1_6 : - NL80211_RATE_INFO_HE_GI_1_6; + return NL80211_RATE_INFO_HE_GI_1_6; case RTW89_GILTF_LGI_4XHE32: - return eht ? NL80211_RATE_INFO_EHT_GI_3_2 : - NL80211_RATE_INFO_HE_GI_3_2; + return NL80211_RATE_INFO_HE_GI_3_2; default: rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info_gi); if (rx_status) - return eht ? NL80211_RATE_INFO_EHT_GI_3_2 : - NL80211_RATE_INFO_HE_GI_3_2; + return NL80211_RATE_INFO_HE_GI_3_2; return U8_MAX; } } +static u8 rtw89_rxdesc_to_nl_eht_gi(struct rtw89_dev *rtwdev, + u8 desc_info_gi, + bool rx_status) +{ + switch (desc_info_gi) { + case RTW89_GILTF_SGI_4XHE08: + case RTW89_GILTF_2XHE08: + case RTW89_GILTF_1XHE08: + return NL80211_RATE_INFO_EHT_GI_0_8; + case RTW89_GILTF_2XHE16: + case RTW89_GILTF_1XHE16: + return NL80211_RATE_INFO_EHT_GI_1_6; + case RTW89_GILTF_LGI_4XHE32: + return NL80211_RATE_INFO_EHT_GI_3_2; + default: + rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info_gi); + if (rx_status) + return NL80211_RATE_INFO_EHT_GI_3_2; + return U8_MAX; + } +} + +static u8 rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev *rtwdev, + u8 desc_info_gi, + bool rx_status, bool eht) +{ + return eht ? rtw89_rxdesc_to_nl_eht_gi(rtwdev, desc_info_gi, rx_status) : + rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info_gi, rx_status); +} + static bool rtw89_check_rx_statu_gi_match(struct ieee80211_rx_status *status, u8 gi_ltf, bool eht) @@ -1876,17 +1966,19 @@ struct rtw89_vif_rx_stats_iter_data { }; static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf, struct sk_buff *skb) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct ieee80211_trigger *tf = (struct ieee80211_trigger *)skb->data; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; u8 *pos, *end, type, tf_bw; u16 aid, tf_rua; - if (!ether_addr_equal(vif->bss_conf.bssid, tf->ta) || - rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION || - rtwvif->net_type == RTW89_NET_TYPE_NO_LINK) + if (!ether_addr_equal(bss_conf->bssid, tf->ta) || + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION || + rtwvif_link->net_type == RTW89_NET_TYPE_NO_LINK) return; type = le64_get_bits(tf->common_info, IEEE80211_TRIGGER_TYPE_MASK); @@ -1915,7 +2007,7 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev, rtwdev->stats.rx_tf_acc++; if (tf_bw == IEEE80211_TRIGGER_ULBW_160_80P80MHZ && rua <= NL80211_RATE_INFO_HE_RU_ALLOC_106) - rtwvif->pwr_diff_en = true; + rtwvif_link->pwr_diff_en = true; break; } @@ -1986,7 +2078,7 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev, ieee80211_queue_work(rtwdev->hw, &rtwdev->cancel_6ghz_probe_work); } -static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif, +static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif_link *rtwvif_link, struct ieee80211_hdr *hdr, size_t len) { struct ieee80211_mgmt *mgmt = (typeof(mgmt))hdr; @@ -1994,20 +2086,22 @@ static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif, if (len < offsetof(typeof(*mgmt), u.beacon.variable)) return; - WRITE_ONCE(rtwvif->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp)); + WRITE_ONCE(rtwvif_link->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp)); } static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_vif_rx_stats_iter_data *iter_data = data; struct rtw89_dev *rtwdev = iter_data->rtwdev; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat; struct rtw89_rx_desc_info *desc_info = iter_data->desc_info; struct sk_buff *skb = iter_data->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct rtw89_rx_phy_ppdu *phy_ppdu = iter_data->phy_ppdu; + struct ieee80211_bss_conf *bss_conf; + struct rtw89_vif_link *rtwvif_link; const u8 *bssid = iter_data->bssid; if (rtwdev->scanning && @@ -2015,33 +2109,49 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, ieee80211_is_probe_resp(hdr->frame_control))) rtw89_core_cancel_6ghz_probe_tx(rtwdev, skb); - if (!vif->bss_conf.bssid) - return; + rcu_read_lock(); + + /* FIXME: For single link, taking link on HW-0 here is okay. But, when + * enabling multiple active links, we should determine the right link. + */ + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) + goto out; + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + if (!bss_conf->bssid) + goto out; if (ieee80211_is_trigger(hdr->frame_control)) { - rtw89_stats_trigger_frame(rtwdev, vif, skb); - return; + rtw89_stats_trigger_frame(rtwdev, rtwvif_link, bss_conf, skb); + goto out; } - if (!ether_addr_equal(vif->bss_conf.bssid, bssid)) - return; + if (!ether_addr_equal(bss_conf->bssid, bssid)) + goto out; if (ieee80211_is_beacon(hdr->frame_control)) { if (vif->type == NL80211_IFTYPE_STATION && !test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) { - rtw89_vif_sync_bcn_tsf(rtwvif, hdr, skb->len); + rtw89_vif_sync_bcn_tsf(rtwvif_link, hdr, skb->len); rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu); } pkt_stat->beacon_nr++; + + if (phy_ppdu) + ewma_rssi_add(&rtwdev->phystat.bcn_rssi, phy_ppdu->rssi_avg); } - if (!ether_addr_equal(vif->addr, hdr->addr1)) - return; + if (!ether_addr_equal(bss_conf->addr, hdr->addr1)) + goto out; if (desc_info->data_rate < RTW89_HW_RATE_NR) pkt_stat->rx_rate_cnt[desc_info->data_rate]++; rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false); + +out: + rcu_read_unlock(); } static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev, @@ -2432,15 +2542,23 @@ void rtw89_core_stats_sta_rx_status_iter(void *data, struct ieee80211_sta *sta) struct rtw89_core_iter_rx_status *iter_data = (struct rtw89_core_iter_rx_status *)data; struct ieee80211_rx_status *rx_status = iter_data->rx_status; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; struct rtw89_rx_desc_info *desc_info = iter_data->desc_info; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; u8 mac_id = iter_data->mac_id; - if (mac_id != rtwsta->mac_id) + /* FIXME: For single link, taking link on HW-0 here is okay. But, when + * enabling multiple active links, we should determine the right link. + */ + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) return; - rtwsta->rx_status = *rx_status; - rtwsta->rx_hw_rate = desc_info->data_rate; + if (mac_id != rtwsta_link->mac_id) + return; + + rtwsta_link->rx_status = *rx_status; + rtwsta_link->rx_hw_rate = desc_info->data_rate; } static void rtw89_core_stats_sta_rx_status(struct rtw89_dev *rtwdev, @@ -2546,6 +2664,10 @@ static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + /* FIXME: Fix __rtw89_enter_ps_mode() to consider MLO cases. */ + if (rtwdev->support_mlo) + return RTW89_PS_MODE_NONE; + if (rtw89_disable_ps_mode || !chip->ps_mode_supported || RTW89_CHK_FW_FEATURE(NO_DEEP_PS, &rtwdev->fw)) return RTW89_PS_MODE_NONE; @@ -2658,7 +2780,7 @@ static void rtw89_core_ba_work(struct work_struct *work) list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->ba_list, list) { struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq); struct ieee80211_sta *sta = txq->sta; - struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); u8 tid = txq->tid; if (!sta) { @@ -2686,8 +2808,8 @@ static void rtw89_core_ba_work(struct work_struct *work) spin_unlock_bh(&rtwdev->ba_lock); } -static void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta) +void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta) { struct rtw89_txq *rtwtxq, *tmp; @@ -2701,8 +2823,8 @@ static void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev, spin_unlock_bh(&rtwdev->ba_lock); } -static void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta) +void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta) { struct rtw89_txq *rtwtxq, *tmp; @@ -2718,10 +2840,10 @@ static void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev, spin_unlock_bh(&rtwdev->ba_lock); } -static void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta) +void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct sk_buff *skb, *tmp; skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) { @@ -2762,7 +2884,7 @@ static void rtw89_core_txq_check_agg(struct rtw89_dev *rtwdev, struct ieee80211_hw *hw = rtwdev->hw; struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq); struct ieee80211_sta *sta = txq->sta; - struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); if (test_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags)) return; @@ -2838,10 +2960,19 @@ static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev, bool *sched_txq, bool *reinvoke) { struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; - struct ieee80211_sta *sta = txq->sta; - struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(txq->sta); + struct rtw89_sta_link *rtwsta_link; + + if (!rtwsta) + return false; + + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) { + rtw89_err(rtwdev, "agg wait: find no link on HW-0\n"); + return false; + } - if (!sta || rtwsta->max_agg_wait <= 0) + if (rtwsta_link->max_agg_wait <= 0) return false; if (rtwdev->stats.tx_tfc_lv <= RTW89_TFC_MID) @@ -2855,7 +2986,7 @@ static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev, return false; } - if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta->max_agg_wait) { + if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta_link->max_agg_wait) { *reinvoke = true; rtwtxq->wait_cnt++; return true; @@ -2879,7 +3010,7 @@ static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac, bool *reinv ieee80211_txq_schedule_start(hw, ac); while ((txq = ieee80211_next_txq(hw, ac))) { rtwtxq = (struct rtw89_txq *)txq->drv_priv; - rtwvif = (struct rtw89_vif *)txq->vif->drv_priv; + rtwvif = vif_to_rtwvif(txq->vif); if (rtwvif->offchan) { ieee80211_return_txq(hw, txq, true); @@ -2955,16 +3086,23 @@ static void rtw89_forbid_ba_work(struct work_struct *w) static void rtw89_core_sta_pending_tx_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_vif *rtwvif_target = data, *rtwvif = rtwsta->rtwvif; - struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_vif_link *target = data; + struct rtw89_vif_link *rtwvif_link; struct sk_buff *skb, *tmp; + unsigned int link_id; int qsel, ret; - if (rtwvif->chanctx_idx != rtwvif_target->chanctx_idx) - return; + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + if (rtwvif_link->chanctx_idx == target->chanctx_idx) + goto bottom; + return; + +bottom: if (skb_queue_len(&rtwsta->roc_queue) == 0) return; @@ -2982,17 +3120,17 @@ static void rtw89_core_sta_pending_tx_iter(void *data, } static void rtw89_core_handle_sta_pending_tx(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_core_sta_pending_tx_iter, - rtwvif); + rtwvif_link); } static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool qos, bool ps) + struct rtw89_vif_link *rtwvif_link, bool qos, bool ps) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; struct sk_buff *skb; @@ -3002,7 +3140,7 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, return 0; rcu_read_lock(); - sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + sta = ieee80211_find_sta(vif, vif->cfg.ap_addr); if (!sta) { ret = -EINVAL; goto out; @@ -3040,31 +3178,49 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_roc *roc = &rtwvif->roc; + struct rtw89_vif_link *rtwvif_link; struct cfg80211_chan_def roc_chan; - struct rtw89_vif *tmp; + struct rtw89_vif *tmp_vif; + u32 reg; int ret; lockdep_assert_held(&rtwdev->mutex); rtw89_leave_ips_by_hwflags(rtwdev); rtw89_leave_lps(rtwdev); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, RTW89_ROC_BY_LINK_INDEX); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "roc start: find no link on HW-%u\n", + RTW89_ROC_BY_LINK_INDEX); + return; + } + rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC); - ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, true); + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, "roc send null-1 failed: %d\n", ret); - rtw89_for_each_rtwvif(rtwdev, tmp) - if (tmp->chanctx_idx == rtwvif->chanctx_idx) - tmp->offchan = true; + rtw89_for_each_rtwvif(rtwdev, tmp_vif) { + struct rtw89_vif_link *tmp_link; + unsigned int link_id; + + rtw89_vif_for_each_link(tmp_vif, tmp_link, link_id) { + if (tmp_link->chanctx_idx == rtwvif_link->chanctx_idx) { + tmp_vif->offchan = true; + break; + } + } + } cfg80211_chandef_create(&roc_chan, &roc->chan, NL80211_CHAN_NO_HT); - rtw89_config_roc_chandef(rtwdev, rtwvif->chanctx_idx, &roc_chan); + rtw89_config_roc_chandef(rtwdev, rtwvif_link->chanctx_idx, &roc_chan); rtw89_set_channel(rtwdev); - rtw89_write32_clr(rtwdev, - rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), - B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH); + + reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx); + rtw89_write32_clr(rtwdev, reg, B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH); ieee80211_ready_on_channel(hw); cancel_delayed_work(&rtwvif->roc.roc_work); @@ -3077,7 +3233,9 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_roc *roc = &rtwvif->roc; - struct rtw89_vif *tmp; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *tmp_vif; + u32 reg; int ret; lockdep_assert_held(&rtwdev->mutex); @@ -3087,24 +3245,28 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_leave_ips_by_hwflags(rtwdev); rtw89_leave_lps(rtwdev); - rtw89_write32_mask(rtwdev, - rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), - B_AX_RX_FLTR_CFG_MASK, - rtwdev->hal.rx_fltr); + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, RTW89_ROC_BY_LINK_INDEX); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "roc end: find no link on HW-%u\n", + RTW89_ROC_BY_LINK_INDEX); + return; + } + + reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr); roc->state = RTW89_ROC_IDLE; - rtw89_config_roc_chandef(rtwdev, rtwvif->chanctx_idx, NULL); + rtw89_config_roc_chandef(rtwdev, rtwvif_link->chanctx_idx, NULL); rtw89_chanctx_proceed(rtwdev); - ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, false); + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, "roc send null-0 failed: %d\n", ret); - rtw89_for_each_rtwvif(rtwdev, tmp) - if (tmp->chanctx_idx == rtwvif->chanctx_idx) - tmp->offchan = false; + rtw89_for_each_rtwvif(rtwdev, tmp_vif) + tmp_vif->offchan = false; - rtw89_core_handle_sta_pending_tx(rtwdev, rtwvif); + rtw89_core_handle_sta_pending_tx(rtwdev, rtwvif_link); queue_work(rtwdev->txq_wq, &rtwdev->txq_work); if (hw->conf.flags & IEEE80211_CONF_IDLE) @@ -3188,39 +3350,52 @@ static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; bool tfc_changed; tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats); + rtw89_for_each_rtwvif(rtwdev, rtwvif) { rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats); - rtw89_fw_h2c_tp_offload(rtwdev, rtwvif); + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_fw_h2c_tp_offload(rtwdev, rtwvif_link); } return tfc_changed; } -static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - if ((rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION && - rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) || - rtwvif->tdls_peer) - return; - - if (rtwvif->offchan) + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) return; - if (rtwvif->stats.tx_tfc_lv == RTW89_TFC_IDLE && - rtwvif->stats.rx_tfc_lv == RTW89_TFC_IDLE) - rtw89_enter_lps(rtwdev, rtwvif, true); + rtw89_enter_lps(rtwdev, rtwvif_link, true); } static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; - rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_vif_enter_lps(rtwdev, rtwvif); + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + if (rtwvif->tdls_peer) + continue; + if (rtwvif->offchan) + continue; + + if (rtwvif->stats.tx_tfc_lv != RTW89_TFC_IDLE || + rtwvif->stats.rx_tfc_lv != RTW89_TFC_IDLE) + continue; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_vif_enter_lps(rtwdev, rtwvif_link); + } } static void rtw89_core_rfk_track(struct rtw89_dev *rtwdev) @@ -3234,14 +3409,16 @@ static void rtw89_core_rfk_track(struct rtw89_dev *rtwdev) rtw89_chip_rfk_track(rtwdev); } -void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_P2P_PS_CHANGE); else - rtw89_process_p2p_ps(rtwdev, vif); + rtw89_process_p2p_ps(rtwdev, rtwvif_link, bss_conf); } void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev, @@ -3326,7 +3503,8 @@ void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits) } int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx) + struct rtw89_sta_link *rtwsta_link, u8 tid, + u8 *cam_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_cam_info *cam_info = &rtwdev->cam_info; @@ -3363,7 +3541,7 @@ int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev, } entry->tid = tid; - list_add_tail(&entry->list, &rtwsta->ba_cam_list); + list_add_tail(&entry->list, &rtwsta_link->ba_cam_list); *cam_idx = idx; @@ -3371,7 +3549,8 @@ int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev, } int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx) + struct rtw89_sta_link *rtwsta_link, u8 tid, + u8 *cam_idx) { struct rtw89_cam_info *cam_info = &rtwdev->cam_info; struct rtw89_ba_cam_entry *entry = NULL, *tmp; @@ -3379,7 +3558,7 @@ int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, lockdep_assert_held(&rtwdev->mutex); - list_for_each_entry_safe(entry, tmp, &rtwsta->ba_cam_list, list) { + list_for_each_entry_safe(entry, tmp, &rtwsta_link->ba_cam_list, list) { if (entry->tid != tid) continue; @@ -3396,24 +3575,25 @@ int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, #define RTW89_TYPE_MAPPING(_type) \ case NL80211_IFTYPE_ ## _type: \ - rtwvif->wifi_role = RTW89_WIFI_ROLE_ ## _type; \ + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_ ## _type; \ break -void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc) +void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_bss_conf *bss_conf; switch (vif->type) { case NL80211_IFTYPE_STATION: if (vif->p2p) - rtwvif->wifi_role = RTW89_WIFI_ROLE_P2P_CLIENT; + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_P2P_CLIENT; else - rtwvif->wifi_role = RTW89_WIFI_ROLE_STATION; + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_STATION; break; case NL80211_IFTYPE_AP: if (vif->p2p) - rtwvif->wifi_role = RTW89_WIFI_ROLE_P2P_GO; + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_P2P_GO; else - rtwvif->wifi_role = RTW89_WIFI_ROLE_AP; + rtwvif_link->wifi_role = RTW89_WIFI_ROLE_AP; break; RTW89_TYPE_MAPPING(ADHOC); RTW89_TYPE_MAPPING(MONITOR); @@ -3426,23 +3606,27 @@ void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc) switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - rtwvif->net_type = RTW89_NET_TYPE_AP_MODE; - rtwvif->self_role = RTW89_SELF_ROLE_AP; + rtwvif_link->net_type = RTW89_NET_TYPE_AP_MODE; + rtwvif_link->self_role = RTW89_SELF_ROLE_AP; break; case NL80211_IFTYPE_ADHOC: - rtwvif->net_type = RTW89_NET_TYPE_AD_HOC; - rtwvif->self_role = RTW89_SELF_ROLE_CLIENT; + rtwvif_link->net_type = RTW89_NET_TYPE_AD_HOC; + rtwvif_link->self_role = RTW89_SELF_ROLE_CLIENT; break; case NL80211_IFTYPE_STATION: if (assoc) { - rtwvif->net_type = RTW89_NET_TYPE_INFRA; - rtwvif->trigger = vif->bss_conf.he_support; + rtwvif_link->net_type = RTW89_NET_TYPE_INFRA; + + rcu_read_lock(); + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + rtwvif_link->trigger = bss_conf->he_support; + rcu_read_unlock(); } else { - rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; - rtwvif->trigger = false; + rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK; + rtwvif_link->trigger = false; } - rtwvif->self_role = RTW89_SELF_ROLE_CLIENT; - rtwvif->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL; + rtwvif_link->self_role = RTW89_SELF_ROLE_CLIENT; + rtwvif_link->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL; break; case NL80211_IFTYPE_MONITOR: break; @@ -3452,137 +3636,110 @@ void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc) } } -int rtw89_core_sta_add(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); struct rtw89_hal *hal = &rtwdev->hal; u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; int i; int ret; - rtwsta->rtwdev = rtwdev; - rtwsta->rtwvif = rtwvif; - rtwsta->prev_rssi = 0; - INIT_LIST_HEAD(&rtwsta->ba_cam_list); - skb_queue_head_init(&rtwsta->roc_queue); - - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) - rtw89_core_txq_init(rtwdev, sta->txq[i]); - - ewma_rssi_init(&rtwsta->avg_rssi); - ewma_snr_init(&rtwsta->avg_snr); - ewma_evm_init(&rtwsta->evm_1ss); + rtwsta_link->prev_rssi = 0; + INIT_LIST_HEAD(&rtwsta_link->ba_cam_list); + ewma_rssi_init(&rtwsta_link->avg_rssi); + ewma_snr_init(&rtwsta_link->avg_snr); + ewma_evm_init(&rtwsta_link->evm_1ss); for (i = 0; i < ant_num; i++) { - ewma_rssi_init(&rtwsta->rssi[i]); - ewma_evm_init(&rtwsta->evm_min[i]); - ewma_evm_init(&rtwsta->evm_max[i]); + ewma_rssi_init(&rtwsta_link->rssi[i]); + ewma_evm_init(&rtwsta_link->evm_min[i]); + ewma_evm_init(&rtwsta_link->evm_max[i]); } if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - /* for station mode, assign the mac_id from itself */ - rtwsta->mac_id = rtwvif->mac_id; - /* must do rtw89_reg_6ghz_recalc() before rfk channel */ - ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true); + ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, true); if (ret) return ret; - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_CONN_START); - rtw89_chip_rfk_channel(rtwdev, rtwvif); + rtw89_chip_rfk_channel(rtwdev, rtwvif_link); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { - rtwsta->mac_id = rtw89_acquire_mac_id(rtwdev); - if (rtwsta->mac_id == RTW89_MAX_MAC_ID_NUM) - return -ENOSPC; - - ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta->mac_id, false); + ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta_link->mac_id, false); if (ret) { - rtw89_release_mac_id(rtwdev, rtwsta->mac_id); rtw89_warn(rtwdev, "failed to send h2c macid pause\n"); return ret; } - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link, RTW89_ROLE_CREATE); if (ret) { - rtw89_release_mac_id(rtwdev, rtwsta->mac_id); rtw89_warn(rtwdev, "failed to send h2c role info\n"); return ret; } - ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) return ret; - ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) return ret; - - rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); } return 0; } -int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); if (vif->type == NL80211_IFTYPE_STATION) - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, false); - - rtwdev->total_sta_assoc--; - if (sta->tdls) - rtwvif->tdls_peer--; - rtwsta->disassoc = true; + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, false); return 0; } -int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_disconnect(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); int ret; - rtw89_mac_bf_monitor_calc(rtwdev, sta, true); - rtw89_mac_bf_disassoc(rtwdev, vif, sta); - rtw89_core_free_sta_pending_ba(rtwdev, sta); - rtw89_core_free_sta_pending_forbid_ba(rtwdev, sta); - rtw89_core_free_sta_pending_roc_tx(rtwdev, sta); + rtw89_mac_bf_monitor_calc(rtwdev, rtwsta_link, true); + rtw89_mac_bf_disassoc(rtwdev, rtwvif_link, rtwsta_link); if (vif->type == NL80211_IFTYPE_AP || sta->tdls) - rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam); + rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta_link->addr_cam); if (sta->tdls) - rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam); + rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta_link->bssid_cam); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - rtw89_vif_type_mapping(vif, false); - rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, true); + rtw89_vif_type_mapping(rtwvif_link, false); + rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif_link, true); } - ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cmac table\n"); return ret; } - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, true); + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, true); if (ret) { rtw89_warn(rtwdev, "failed to send h2c join info\n"); return ret; } /* update cam aid mac_id net_type */ - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; @@ -3591,106 +3748,114 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, return ret; } -int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta); + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); + struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif_link, + rtwsta_link); const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); int ret; if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { if (sta->tdls) { - ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, sta->addr); + struct ieee80211_link_sta *link_sta; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif_link, bssid_cam, + link_sta->addr); if (ret) { rtw89_warn(rtwdev, "failed to send h2c init bssid cam for TDLS\n"); + rcu_read_unlock(); return ret; } + + rcu_read_unlock(); } - ret = rtw89_cam_init_addr_cam(rtwdev, &rtwsta->addr_cam, bssid_cam); + ret = rtw89_cam_init_addr_cam(rtwdev, &rtwsta_link->addr_cam, bssid_cam); if (ret) { rtw89_warn(rtwdev, "failed to send h2c init addr cam\n"); return ret; } } - ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cmac table\n"); return ret; } - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, false); + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, false); if (ret) { rtw89_warn(rtwdev, "failed to send h2c join info\n"); return ret; } /* update cam aid mac_id net_type */ - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; } - rtwdev->total_sta_assoc++; - if (sta->tdls) - rtwvif->tdls_peer++; - rtw89_phy_ra_assoc(rtwdev, sta); - rtw89_mac_bf_assoc(rtwdev, vif, sta); - rtw89_mac_bf_monitor_calc(rtwdev, sta, false); + rtw89_phy_ra_assoc(rtwdev, rtwsta_link); + rtw89_mac_bf_assoc(rtwdev, rtwvif_link, rtwsta_link); + rtw89_mac_bf_monitor_calc(rtwdev, rtwsta_link, false); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ieee80211_bss_conf *bss_conf; + + rcu_read_lock(); + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); if (bss_conf->he_support && !(bss_conf->he_oper.params & IEEE80211_HE_OPERATION_ER_SU_DISABLE)) - rtwsta->er_cap = true; + rtwsta_link->er_cap = true; - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, + rcu_read_unlock(); + + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_CONN_END); - rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template, chan); - rtw89_phy_ul_tb_assoc(rtwdev, rtwvif); + rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta_link->htc_template, chan); + rtw89_phy_ul_tb_assoc(rtwdev, rtwvif_link); - ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id); + ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id); if (ret) { rtw89_warn(rtwdev, "failed to send h2c general packet\n"); return ret; } - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); } return ret; } -int rtw89_core_sta_remove(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + const struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); int ret; if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { - rtw89_reg_6ghz_recalc(rtwdev, rtwvif, false); - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, + rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, false); + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_DIS_CONN); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { - rtw89_release_mac_id(rtwdev, rtwsta->mac_id); - - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link, RTW89_ROLE_REMOVE); if (ret) { rtw89_warn(rtwdev, "failed to send h2c role info\n"); return ret; } - - rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); } return 0; @@ -4152,15 +4317,16 @@ static void rtw89_core_ppdu_sts_init(struct rtw89_dev *rtwdev) void rtw89_core_update_beacon_work(struct work_struct *work) { struct rtw89_dev *rtwdev; - struct rtw89_vif *rtwvif = container_of(work, struct rtw89_vif, - update_beacon_work); + struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link, + update_beacon_work); - if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE) + if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE) return; - rtwdev = rtwvif->rtwdev; + rtwdev = rtwvif_link->rtwvif->rtwdev; + mutex_lock(&rtwdev->mutex); - rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); mutex_unlock(&rtwdev->mutex); } @@ -4266,8 +4432,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) rtw89_phy_dm_init(rtwdev); - rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); - rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); + rtw89_mac_cfg_ppdu_status_bands(rtwdev, true); + rtw89_mac_update_rts_threshold(rtwdev); rtw89_tas_reset(rtwdev); @@ -4355,6 +4521,168 @@ void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id) clear_bit(mac_id, rtwdev->mac_id_map); } +void rtw89_init_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + u8 mac_id, u8 port) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 support_link_num = chip->support_link_num; + u8 support_mld_num = 0; + unsigned int link_id; + u8 index; + + bitmap_zero(rtwvif->links_inst_map, __RTW89_MLD_MAX_LINK_NUM); + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) + rtwvif->links[link_id] = NULL; + + rtwvif->rtwdev = rtwdev; + + if (rtwdev->support_mlo) { + rtwvif->links_inst_valid_num = support_link_num; + support_mld_num = chip->support_macid_num / support_link_num; + } else { + rtwvif->links_inst_valid_num = 1; + } + + for (index = 0; index < rtwvif->links_inst_valid_num; index++) { + struct rtw89_vif_link *inst = &rtwvif->links_inst[index]; + + inst->rtwvif = rtwvif; + inst->mac_id = mac_id + index * support_mld_num; + inst->mac_idx = RTW89_MAC_0 + index; + inst->phy_idx = RTW89_PHY_0 + index; + + /* multi-link use the same port id on different HW bands */ + inst->port = port; + } +} + +void rtw89_init_sta(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, u8 mac_id) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 support_link_num = chip->support_link_num; + u8 support_mld_num = 0; + unsigned int link_id; + u8 index; + + bitmap_zero(rtwsta->links_inst_map, __RTW89_MLD_MAX_LINK_NUM); + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) + rtwsta->links[link_id] = NULL; + + rtwsta->rtwdev = rtwdev; + rtwsta->rtwvif = rtwvif; + + if (rtwdev->support_mlo) { + rtwsta->links_inst_valid_num = support_link_num; + support_mld_num = chip->support_macid_num / support_link_num; + } else { + rtwsta->links_inst_valid_num = 1; + } + + for (index = 0; index < rtwsta->links_inst_valid_num; index++) { + struct rtw89_sta_link *inst = &rtwsta->links_inst[index]; + + inst->rtwvif_link = &rtwvif->links_inst[index]; + + inst->rtwsta = rtwsta; + inst->mac_id = mac_id + index * support_mld_num; + } +} + +struct rtw89_vif_link *rtw89_vif_set_link(struct rtw89_vif *rtwvif, + unsigned int link_id) +{ + struct rtw89_vif_link *rtwvif_link = rtwvif->links[link_id]; + u8 index; + int ret; + + if (rtwvif_link) + return rtwvif_link; + + index = find_first_zero_bit(rtwvif->links_inst_map, + rtwvif->links_inst_valid_num); + if (index == rtwvif->links_inst_valid_num) { + ret = -EBUSY; + goto err; + } + + rtwvif_link = &rtwvif->links_inst[index]; + rtwvif_link->link_id = link_id; + + set_bit(index, rtwvif->links_inst_map); + rtwvif->links[link_id] = rtwvif_link; + return rtwvif_link; + +err: + rtw89_err(rtwvif->rtwdev, "vif (link_id %u) failed to set link: %d\n", + link_id, ret); + return NULL; +} + +void rtw89_vif_unset_link(struct rtw89_vif *rtwvif, unsigned int link_id) +{ + struct rtw89_vif_link **container = &rtwvif->links[link_id]; + struct rtw89_vif_link *link = *container; + u8 index; + + if (!link) + return; + + index = rtw89_vif_link_inst_get_index(link); + clear_bit(index, rtwvif->links_inst_map); + *container = NULL; +} + +struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta, + unsigned int link_id) +{ + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_vif_link *rtwvif_link = rtwvif->links[link_id]; + struct rtw89_sta_link *rtwsta_link = rtwsta->links[link_id]; + u8 index; + int ret; + + if (rtwsta_link) + return rtwsta_link; + + if (!rtwvif_link) { + ret = -ENOLINK; + goto err; + } + + index = rtw89_vif_link_inst_get_index(rtwvif_link); + if (test_bit(index, rtwsta->links_inst_map)) { + ret = -EBUSY; + goto err; + } + + rtwsta_link = &rtwsta->links_inst[index]; + rtwsta_link->link_id = link_id; + + set_bit(index, rtwsta->links_inst_map); + rtwsta->links[link_id] = rtwsta_link; + return rtwsta_link; + +err: + rtw89_err(rtwsta->rtwdev, "sta (link_id %u) failed to set link: %d\n", + link_id, ret); + return NULL; +} + +void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id) +{ + struct rtw89_sta_link **container = &rtwsta->links[link_id]; + struct rtw89_sta_link *link = *container; + u8 index; + + if (!link) + return; + + index = rtw89_sta_link_inst_get_index(link); + clear_bit(index, rtwsta->links_inst_map); + *container = NULL; +} + int rtw89_core_init(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -4444,39 +4772,45 @@ void rtw89_core_deinit(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_core_deinit); -void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, const u8 *mac_addr, bool hw_scan) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); rtwdev->scanning = true; rtw89_leave_lps(rtwdev); if (hw_scan) rtw89_leave_ips_by_hwflags(rtwdev); - ether_addr_copy(rtwvif->mac_addr, mac_addr); - rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, chan->band_type); - rtw89_chip_rfk_scan(rtwdev, rtwvif, true); + ether_addr_copy(rtwvif_link->mac_addr, mac_addr); + rtw89_btc_ntfy_scan_start(rtwdev, rtwvif_link->phy_idx, chan->band_type); + rtw89_chip_rfk_scan(rtwdev, rtwvif_link, true); rtw89_hci_recalc_int_mit(rtwdev); rtw89_phy_config_edcca(rtwdev, true); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, mac_addr); + rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, mac_addr); } void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, bool hw_scan) + struct rtw89_vif_link *rtwvif_link, bool hw_scan) { - struct rtw89_vif *rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL; + struct ieee80211_bss_conf *bss_conf; - if (!rtwvif) + if (!rtwvif_link) return; - ether_addr_copy(rtwvif->mac_addr, vif->addr); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ether_addr_copy(rtwvif_link->mac_addr, bss_conf->addr); + + rcu_read_unlock(); + + rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); - rtw89_chip_rfk_scan(rtwdev, rtwvif, false); - rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0); + rtw89_chip_rfk_scan(rtwdev, rtwvif_link, false); + rtw89_btc_ntfy_scan_finish(rtwdev, rtwvif_link->phy_idx); rtw89_phy_config_edcca(rtwdev, false); rtwdev->scanning = false; @@ -4513,11 +4847,20 @@ static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev) static void rtw89_core_setup_phycap(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; + rtwdev->hal.support_cckpd = !(rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv <= CHIP_CBV) && !(rtwdev->chip->chip_id == RTL8852B && rtwdev->hal.cv <= CHIP_CAV); rtwdev->hal.support_igi = rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv <= CHIP_CBV; + + if (test_bit(RTW89_QUIRK_THERMAL_PROT_120C, rtwdev->quirks)) + rtwdev->hal.thermal_prot_th = chip->thermal_th[1]; + else if (test_bit(RTW89_QUIRK_THERMAL_PROT_110C, rtwdev->quirks)) + rtwdev->hal.thermal_prot_th = chip->thermal_th[0]; + else + rtwdev->hal.thermal_prot_th = 0; } static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev) @@ -4688,17 +5031,39 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_chip_info_setup); +void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct rtw89_chip_info *chip = rtwdev->chip; + struct ieee80211_bss_conf *bss_conf; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + if (!bss_conf->he_support || !vif->cfg.assoc) { + rcu_read_unlock(); + return; + } + + rcu_read_unlock(); + + if (chip->ops->set_txpwr_ul_tb_offset) + chip->ops->set_txpwr_ul_tb_offset(rtwdev, 0, rtwvif_link->mac_idx); +} + static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + u8 n = rtwdev->support_mlo ? chip->support_link_num : 1; struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_hal *hal = &rtwdev->hal; int ret; int tx_headroom = IEEE80211_HT_CTL_LEN; - hw->vif_data_size = sizeof(struct rtw89_vif); - hw->sta_data_size = sizeof(struct rtw89_sta); + hw->vif_data_size = struct_size_t(struct rtw89_vif, links_inst, n); + hw->sta_data_size = struct_size_t(struct rtw89_sta, links_inst, n); hw->txq_data_size = sizeof(struct rtw89_txq); hw->chanctx_data_size = sizeof(struct rtw89_chanctx_cfg); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 4ed9034fdb4641..5ad32eacd0d50c 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -829,6 +829,8 @@ enum rtw89_phy_idx { RTW89_PHY_MAX }; +#define __RTW89_MLD_MAX_LINK_NUM 2 + enum rtw89_chanctx_idx { RTW89_CHANCTX_0 = 0, RTW89_CHANCTX_1 = 1, @@ -1160,14 +1162,15 @@ struct rtw89_tx_desc_info { bool er_cap; bool stbc; bool ldpc; + bool upd_wlan_hdr; }; struct rtw89_core_tx_request { enum rtw89_core_tx_type tx_type; struct sk_buff *skb; - struct ieee80211_vif *vif; - struct ieee80211_sta *sta; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; struct rtw89_tx_desc_info desc_info; }; @@ -1350,7 +1353,6 @@ struct rtw89_btc_wl_smap { u32 connecting: 1; u32 roaming: 1; u32 dbccing: 1; - u32 transacting: 1; u32 _4way: 1; u32 rf_off: 1; u32 lps: 2; @@ -2937,6 +2939,7 @@ struct rtw89_btc_dm { u8 wl_pre_agc: 2; u8 wl_lna2: 1; + u8 freerun_chk: 1; u8 wl_pre_agc_rb: 2; u8 bt_select: 2; /* 0:s0, 1:s1, 2:s0 & s1, refer to enum btc_bt_index */ u8 slot_req_more: 1; @@ -2975,6 +2978,8 @@ enum rtw89_btc_btf_fw_event { BTF_EVNT_BT_REG = 3, BTF_EVNT_CX_RUNINFO = 4, BTF_EVNT_BT_PSD = 5, + BTF_EVNT_BT_DEV_INFO = 6, /* fwc2hfunc > 0 */ + BTF_EVNT_BT_LEAUDIO_INFO = 7, /* fwc2hfunc > 1 */ BTF_EVNT_BUF_OVERFLOW, BTF_EVNT_C2H_LOOPBACK, BTF_EVNT_MAX, @@ -3141,6 +3146,7 @@ struct rtw89_btc_ver { u8 fcxinit; u8 fwevntrptl; + u8 fwc2hfunc; u8 drvinfo_type; u16 info_buf; u8 max_role_num; @@ -3354,12 +3360,13 @@ struct rtw89_sec_cam_entry { u8 key[32]; }; -struct rtw89_sta { +struct rtw89_sta_link { + struct rtw89_sta *rtwsta; + unsigned int link_id; + u8 mac_id; - bool disassoc; bool er_cap; - struct rtw89_dev *rtwdev; - struct rtw89_vif *rtwvif; + struct rtw89_vif_link *rtwvif_link; struct rtw89_ra_info ra; struct rtw89_ra_report ra_report; int max_agg_wait; @@ -3370,15 +3377,12 @@ struct rtw89_sta { struct ewma_evm evm_1ss; struct ewma_evm evm_min[RF_PATH_MAX]; struct ewma_evm evm_max[RF_PATH_MAX]; - struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS]; - DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS); struct ieee80211_rx_status rx_status; u16 rx_hw_rate; __le32 htc_template; struct rtw89_addr_cam_entry addr_cam; /* AP mode or TDLS peer only */ struct rtw89_bssid_cam_entry bssid_cam; /* TDLS peer only */ struct list_head ba_cam_list; - struct sk_buff_head roc_queue; bool use_cfg_mask; struct cfg80211_bitrate_mask mask; @@ -3424,6 +3428,8 @@ enum rtw89_roc_state { RTW89_ROC_MGMT, }; +#define RTW89_ROC_BY_LINK_INDEX 0 + struct rtw89_roc { struct ieee80211_channel chan; struct delayed_work roc_work; @@ -3460,10 +3466,10 @@ struct rtw89_p2p_noa_setter { u8 noa_index; }; -struct rtw89_vif { - struct list_head list; - struct rtw89_dev *rtwdev; - struct rtw89_roc roc; +struct rtw89_vif_link { + struct rtw89_vif *rtwvif; + unsigned int link_id; + bool chanctx_assigned; /* only valid when running with chanctx_ops */ enum rtw89_chanctx_idx chanctx_idx; enum rtw89_reg_6ghz_power reg_6ghz_power; @@ -3473,7 +3479,6 @@ struct rtw89_vif { u8 port; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - __be32 ip_addr; u8 phy_idx; u8 mac_idx; u8 net_type; @@ -3484,7 +3489,6 @@ struct rtw89_vif { u8 hit_rule; u8 last_noa_nr; u64 sync_bcn_tsf; - bool offchan; bool trigger; bool lsig_txop; u8 tgt_ind; @@ -3498,15 +3502,11 @@ struct rtw89_vif { bool pre_pwr_diff_en; bool pwr_diff_en; u8 def_tri_idx; - u32 tdls_peer; struct work_struct update_beacon_work; struct rtw89_addr_cam_entry addr_cam; struct rtw89_bssid_cam_entry bssid_cam; struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS]; - struct rtw89_traffic_stats stats; struct rtw89_phy_rate_pattern rate_pattern; - struct cfg80211_scan_request *scan_req; - struct ieee80211_scan_ies *scan_ies; struct list_head general_pkt_list; struct rtw89_p2p_noa_setter p2p_noa; }; @@ -3599,11 +3599,11 @@ struct rtw89_chip_ops { void (*rfk_hw_init)(struct rtw89_dev *rtwdev); void (*rfk_init)(struct rtw89_dev *rtwdev); void (*rfk_init_late)(struct rtw89_dev *rtwdev); - void (*rfk_channel)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); + void (*rfk_channel)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void (*rfk_band_changed)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan); - void (*rfk_scan)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + void (*rfk_scan)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool start); void (*rfk_track)(struct rtw89_dev *rtwdev); void (*power_trim)(struct rtw89_dev *rtwdev); @@ -3646,23 +3646,25 @@ struct rtw89_chip_ops { u32 *tx_en, enum rtw89_sch_tx_sel sel); int (*resume_sch_tx)(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en); int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_default_cmac_tbl)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_assoc_cmac_tbl)(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_ampdu_cmac_tbl)(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*h2c_update_beacon)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); - int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link); + int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params); void (*btc_set_rfe)(struct rtw89_dev *rtwdev); @@ -4245,6 +4247,7 @@ struct rtw89_chip_info { u8 wde_qempty_acq_grpnum; u8 wde_qempty_mgq_grpsel; u32 rf_base_addr[2]; + u8 thermal_th[2]; u8 support_macid_num; u8 support_link_num; u8 support_chanctx_num; @@ -4445,6 +4448,8 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_SCAN_OFFLOAD_BE_V0, RTW89_FW_FEATURE_WOW_REASON_V1, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, + RTW89_FW_FEATURE_RFK_RXDCK_V0, + RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, }; struct rtw89_fw_suit { @@ -4511,11 +4516,14 @@ enum rtw89_fw_mss_dev_type { }; struct rtw89_fw_secure { - bool secure_boot; + bool secure_boot: 1; + bool can_mss_v1: 1; + bool can_mss_v0: 1; u32 sb_sel_mgn; u8 mss_dev_type; u8 mss_cust_idx; u8 mss_key_num; + u8 mss_idx; /* v0 */ }; struct rtw89_fw_info { @@ -4561,7 +4569,7 @@ enum rtw89_sar_subband { RTW89_SAR_2GHZ_SUBBAND, RTW89_SAR_5GHZ_SUBBAND_1_2, /* U-NII-1 and U-NII-2 */ RTW89_SAR_5GHZ_SUBBAND_2_E, /* U-NII-2-Extended */ - RTW89_SAR_5GHZ_SUBBAND_3, /* U-NII-3 */ + RTW89_SAR_5GHZ_SUBBAND_3_4, /* U-NII-3 and U-NII-4 */ RTW89_SAR_6GHZ_SUBBAND_5_L, /* U-NII-5 lower part */ RTW89_SAR_6GHZ_SUBBAND_5_H, /* U-NII-5 higher part */ RTW89_SAR_6GHZ_SUBBAND_6, /* U-NII-6 */ @@ -4623,7 +4631,7 @@ enum rtw89_chanctx_changes { }; enum rtw89_entity_mode { - RTW89_ENTITY_MODE_SCC, + RTW89_ENTITY_MODE_SCC_OR_SMLD, RTW89_ENTITY_MODE_MCC_PREPARE, RTW89_ENTITY_MODE_MCC, @@ -4632,6 +4640,16 @@ enum rtw89_entity_mode { RTW89_ENTITY_MODE_UNHANDLED = -ESRCH, }; +#define RTW89_MAX_INTERFACE_NUM 2 + +/* only valid when running with chanctx_ops */ +struct rtw89_entity_mgnt { + struct list_head active_list; + struct rtw89_vif *active_roles[RTW89_MAX_INTERFACE_NUM]; + enum rtw89_chanctx_idx chanctx_tbl[RTW89_MAX_INTERFACE_NUM] + [__RTW89_MLD_MAX_LINK_NUM]; +}; + struct rtw89_chanctx { struct cfg80211_chan_def chandef; struct rtw89_chan chan; @@ -4650,8 +4668,12 @@ struct rtw89_edcca_bak { enum rtw89_dm_type { RTW89_DM_DYNAMIC_EDCCA, + RTW89_DM_THERMAL_PROTECT, }; +#define RTW89_THERMAL_PROT_LV_MAX 5 +#define RTW89_THERMAL_PROT_STEP 19 /* -19% for each level */ + struct rtw89_hal { u32 rx_fltr; u8 cv; @@ -4672,12 +4694,16 @@ struct rtw89_hal { struct rtw89_chanctx chanctx[NUM_OF_RTW89_CHANCTX]; struct cfg80211_chan_def roc_chandef; - bool entity_active; + bool entity_active[RTW89_PHY_MAX]; bool entity_pause; enum rtw89_entity_mode entity_mode; + struct rtw89_entity_mgnt entity_mgnt; struct rtw89_edcca_bak edcca_bak; u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */ + + u8 thermal_prot_th; + u8 thermal_prot_lv; /* 0 ~ RTW89_THERMAL_PROT_LV_MAX */ }; #define RTW89_MAX_MAC_ID_NUM 128 @@ -4710,10 +4736,22 @@ enum rtw89_flags { enum rtw89_quirks { RTW89_QUIRK_PCI_BER, + RTW89_QUIRK_THERMAL_PROT_120C, + RTW89_QUIRK_THERMAL_PROT_110C, NUM_OF_RTW89_QUIRKS, }; +enum rtw89_custid { + RTW89_CUSTID_NONE, + RTW89_CUSTID_ACER, + RTW89_CUSTID_AMD, + RTW89_CUSTID_ASUS, + RTW89_CUSTID_DELL, + RTW89_CUSTID_HP, + RTW89_CUSTID_LENOVO, +}; + enum rtw89_pkt_drop_sel { RTW89_PKT_DROP_SEL_MACID_BE_ONCE, RTW89_PKT_DROP_SEL_MACID_BK_ONCE, @@ -4750,6 +4788,8 @@ DECLARE_EWMA(thermal, 4, 4); struct rtw89_phy_stat { struct ewma_thermal avg_thermal[RF_PATH_MAX]; + u8 last_thermal_max; + struct ewma_rssi bcn_rssi; struct rtw89_pkt_stat cur_pkt_stat; struct rtw89_pkt_stat last_pkt_stat; }; @@ -4791,13 +4831,17 @@ enum rtw89_rfk_chs_nrs { RTW89_RFK_CHS_NR = __RTW89_RFK_CHS_NR_V1, }; -struct rtw89_rfk_mcc_info { +struct rtw89_rfk_mcc_info_data { u8 ch[RTW89_RFK_CHS_NR]; u8 band[RTW89_RFK_CHS_NR]; u8 bw[RTW89_RFK_CHS_NR]; u8 table_idx; }; +struct rtw89_rfk_mcc_info { + struct rtw89_rfk_mcc_info_data data[2]; +}; + #define RTW89_IQK_CHS_NR 2 #define RTW89_IQK_PATH_NR 4 @@ -4902,6 +4946,7 @@ struct rtw89_agc_gaincode_set { #define IGI_RSSI_TH_NUM 5 #define FA_TH_NUM 4 +#define TIA_LNA_OP1DB_NUM 8 #define LNA_GAIN_NUM 7 #define TIA_GAIN_NUM 2 struct rtw89_dig_info { @@ -5196,7 +5241,7 @@ struct rtw89_early_h2c { }; struct rtw89_hw_scan_info { - struct ieee80211_vif *scanning_vif; + struct rtw89_vif_link *scanning_vif; struct list_head pkt_list[NUM_NL80211_BANDS]; struct rtw89_chan op_chan; bool abort; @@ -5371,7 +5416,7 @@ struct rtw89_wow_aoac_report { }; struct rtw89_wow_param { - struct ieee80211_vif *wow_vif; + struct rtw89_vif_link *rtwvif_link; DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM); struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM]; struct rtw89_wow_key_info key_info; @@ -5408,7 +5453,7 @@ struct rtw89_mcc_policy { }; struct rtw89_mcc_role { - struct rtw89_vif *rtwvif; + struct rtw89_vif_link *rtwvif_link; struct rtw89_mcc_policy policy; struct rtw89_mcc_limit limit; @@ -5509,6 +5554,7 @@ struct rtw89_dev { struct rtw89_efuse efuse; struct rtw89_traffic_stats stats; struct rtw89_rfe_data *rfe_data; + enum rtw89_custid custid; /* ensures exclusive access from mac80211 callbacks */ struct mutex mutex; @@ -5608,6 +5654,122 @@ struct rtw89_dev { u8 priv[] __aligned(sizeof(void *)); }; +struct rtw89_vif { + struct rtw89_dev *rtwdev; + struct list_head list; + struct list_head mgnt_entry; + + u8 mac_addr[ETH_ALEN]; + __be32 ip_addr; + + struct rtw89_traffic_stats stats; + u32 tdls_peer; + + struct ieee80211_scan_ies *scan_ies; + struct cfg80211_scan_request *scan_req; + + struct rtw89_roc roc; + bool offchan; + + u8 links_inst_valid_num; + DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM); + struct rtw89_vif_link *links[IEEE80211_MLD_MAX_NUM_LINKS]; + struct rtw89_vif_link links_inst[] __counted_by(links_inst_valid_num); +}; + +static inline bool rtw89_vif_assign_link_is_valid(struct rtw89_vif_link **rtwvif_link, + const struct rtw89_vif *rtwvif, + unsigned int link_id) +{ + *rtwvif_link = rtwvif->links[link_id]; + return !!*rtwvif_link; +} + +#define rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) \ + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) \ + if (rtw89_vif_assign_link_is_valid(&(rtwvif_link), rtwvif, link_id)) + +struct rtw89_sta { + struct rtw89_dev *rtwdev; + struct rtw89_vif *rtwvif; + + bool disassoc; + + struct sk_buff_head roc_queue; + + struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS]; + DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS); + + u8 links_inst_valid_num; + DECLARE_BITMAP(links_inst_map, __RTW89_MLD_MAX_LINK_NUM); + struct rtw89_sta_link *links[IEEE80211_MLD_MAX_NUM_LINKS]; + struct rtw89_sta_link links_inst[] __counted_by(links_inst_valid_num); +}; + +static inline bool rtw89_sta_assign_link_is_valid(struct rtw89_sta_link **rtwsta_link, + const struct rtw89_sta *rtwsta, + unsigned int link_id) +{ + *rtwsta_link = rtwsta->links[link_id]; + return !!*rtwsta_link; +} + +#define rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) \ + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) \ + if (rtw89_sta_assign_link_is_valid(&(rtwsta_link), rtwsta, link_id)) + +static inline u8 rtw89_vif_get_main_macid(struct rtw89_vif *rtwvif) +{ + /* const after init, so no need to check if active first */ + return rtwvif->links_inst[0].mac_id; +} + +static inline u8 rtw89_vif_get_main_port(struct rtw89_vif *rtwvif) +{ + /* const after init, so no need to check if active first */ + return rtwvif->links_inst[0].port; +} + +static inline struct rtw89_vif_link * +rtw89_vif_get_link_inst(struct rtw89_vif *rtwvif, u8 index) +{ + if (index >= rtwvif->links_inst_valid_num || + !test_bit(index, rtwvif->links_inst_map)) + return NULL; + return &rtwvif->links_inst[index]; +} + +static inline +u8 rtw89_vif_link_inst_get_index(struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + + return rtwvif_link - rtwvif->links_inst; +} + +static inline u8 rtw89_sta_get_main_macid(struct rtw89_sta *rtwsta) +{ + /* const after init, so no need to check if active first */ + return rtwsta->links_inst[0].mac_id; +} + +static inline struct rtw89_sta_link * +rtw89_sta_get_link_inst(struct rtw89_sta *rtwsta, u8 index) +{ + if (index >= rtwsta->links_inst_valid_num || + !test_bit(index, rtwsta->links_inst_map)) + return NULL; + return &rtwsta->links_inst[index]; +} + +static inline +u8 rtw89_sta_link_inst_get_index(struct rtw89_sta_link *rtwsta_link) +{ + struct rtw89_sta *rtwsta = rtwsta_link->rtwsta; + + return rtwsta_link - rtwsta->links_inst; +} + static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { @@ -5972,9 +6134,26 @@ static inline struct ieee80211_vif *rtwvif_to_vif_safe(struct rtw89_vif *rtwvif) return rtwvif ? rtwvif_to_vif(rtwvif) : NULL; } +static inline +struct ieee80211_vif *rtwvif_link_to_vif(struct rtw89_vif_link *rtwvif_link) +{ + return rtwvif_to_vif(rtwvif_link->rtwvif); +} + +static inline +struct ieee80211_vif *rtwvif_link_to_vif_safe(struct rtw89_vif_link *rtwvif_link) +{ + return rtwvif_link ? rtwvif_link_to_vif(rtwvif_link) : NULL; +} + +static inline struct rtw89_vif *vif_to_rtwvif(struct ieee80211_vif *vif) +{ + return (struct rtw89_vif *)vif->drv_priv; +} + static inline struct rtw89_vif *vif_to_rtwvif_safe(struct ieee80211_vif *vif) { - return vif ? (struct rtw89_vif *)vif->drv_priv : NULL; + return vif ? vif_to_rtwvif(vif) : NULL; } static inline struct ieee80211_sta *rtwsta_to_sta(struct rtw89_sta *rtwsta) @@ -5989,11 +6168,88 @@ static inline struct ieee80211_sta *rtwsta_to_sta_safe(struct rtw89_sta *rtwsta) return rtwsta ? rtwsta_to_sta(rtwsta) : NULL; } +static inline +struct ieee80211_sta *rtwsta_link_to_sta(struct rtw89_sta_link *rtwsta_link) +{ + return rtwsta_to_sta(rtwsta_link->rtwsta); +} + +static inline +struct ieee80211_sta *rtwsta_link_to_sta_safe(struct rtw89_sta_link *rtwsta_link) +{ + return rtwsta_link ? rtwsta_link_to_sta(rtwsta_link) : NULL; +} + +static inline struct rtw89_sta *sta_to_rtwsta(struct ieee80211_sta *sta) +{ + return (struct rtw89_sta *)sta->drv_priv; +} + static inline struct rtw89_sta *sta_to_rtwsta_safe(struct ieee80211_sta *sta) { - return sta ? (struct rtw89_sta *)sta->drv_priv : NULL; + return sta ? sta_to_rtwsta(sta) : NULL; +} + +static inline struct ieee80211_bss_conf * +__rtw89_vif_rcu_dereference_link(struct rtw89_vif_link *rtwvif_link, bool *nolink) +{ + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct ieee80211_bss_conf *bss_conf; + + bss_conf = rcu_dereference(vif->link_conf[rtwvif_link->link_id]); + if (unlikely(!bss_conf)) { + *nolink = true; + return &vif->bss_conf; + } + + *nolink = false; + return bss_conf; +} + +#define rtw89_vif_rcu_dereference_link(rtwvif_link, assert) \ +({ \ + typeof(rtwvif_link) p = rtwvif_link; \ + struct ieee80211_bss_conf *bss_conf; \ + bool nolink; \ + \ + bss_conf = __rtw89_vif_rcu_dereference_link(p, &nolink); \ + if (unlikely(nolink) && (assert)) \ + rtw89_err(p->rtwvif->rtwdev, \ + "%s: cannot find exact bss_conf for link_id %u\n",\ + __func__, p->link_id); \ + bss_conf; \ +}) + +static inline struct ieee80211_link_sta * +__rtw89_sta_rcu_dereference_link(struct rtw89_sta_link *rtwsta_link, bool *nolink) +{ + struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); + struct ieee80211_link_sta *link_sta; + + link_sta = rcu_dereference(sta->link[rtwsta_link->link_id]); + if (unlikely(!link_sta)) { + *nolink = true; + return &sta->deflink; + } + + *nolink = false; + return link_sta; } +#define rtw89_sta_rcu_dereference_link(rtwsta_link, assert) \ +({ \ + typeof(rtwsta_link) p = rtwsta_link; \ + struct ieee80211_link_sta *link_sta; \ + bool nolink; \ + \ + link_sta = __rtw89_sta_rcu_dereference_link(p, &nolink); \ + if (unlikely(nolink) && (assert)) \ + rtw89_err(p->rtwsta->rtwdev, \ + "%s: cannot find exact link_sta for link_id %u\n",\ + __func__, p->link_id); \ + link_sta; \ +}) + static inline u8 rtw89_hw_to_rate_info_bw(enum rtw89_bandwidth hw_bw) { if (hw_bw == RTW89_CHANNEL_WIDTH_160) @@ -6078,29 +6334,29 @@ enum nl80211_he_ru_alloc rtw89_he_rua_to_ru_alloc(u16 rua) } static inline -struct rtw89_addr_cam_entry *rtw89_get_addr_cam_of(struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) +struct rtw89_addr_cam_entry *rtw89_get_addr_cam_of(struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - if (rtwsta) { - struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); + if (rtwsta_link) { + struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) - return &rtwsta->addr_cam; + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) + return &rtwsta_link->addr_cam; } - return &rtwvif->addr_cam; + return &rtwvif_link->addr_cam; } static inline -struct rtw89_bssid_cam_entry *rtw89_get_bssid_cam_of(struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) +struct rtw89_bssid_cam_entry *rtw89_get_bssid_cam_of(struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - if (rtwsta) { - struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); + if (rtwsta_link) { + struct ieee80211_sta *sta = rtwsta_link_to_sta(rtwsta_link); if (sta->tdls) - return &rtwsta->bssid_cam; + return &rtwsta_link->bssid_cam; } - return &rtwvif->bssid_cam; + return &rtwvif_link->bssid_cam; } static inline @@ -6156,14 +6412,22 @@ const struct rtw89_chan_rcd *rtw89_chan_rcd_get(struct rtw89_dev *rtwdev, return &hal->chanctx[idx].rcd; } +static inline +const struct rtw89_chan_rcd *rtw89_chan_rcd_get_by_chan(const struct rtw89_chan *chan) +{ + const struct rtw89_chanctx *chanctx = + container_of_const(chan, struct rtw89_chanctx, chan); + + return &chanctx->rcd; +} + static inline const struct rtw89_chan *rtw89_scan_chan_get(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; - if (rtwvif) - return rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); + if (rtwvif_link) + return rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); else return rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); } @@ -6240,12 +6504,12 @@ static inline void rtw89_chip_rfk_init_late(struct rtw89_dev *rtwdev) } static inline void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->ops->rfk_channel) - chip->ops->rfk_channel(rtwdev, rtwvif); + chip->ops->rfk_channel(rtwdev, rtwvif_link); } static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev, @@ -6259,12 +6523,12 @@ static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev, } static inline void rtw89_chip_rfk_scan(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool start) + struct rtw89_vif_link *rtwvif_link, bool start) { const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->ops->rfk_scan) - chip->ops->rfk_scan(rtwdev, rtwvif, start); + chip->ops->rfk_scan(rtwdev, rtwvif_link, start); } static inline void rtw89_chip_rfk_track(struct rtw89_dev *rtwdev) @@ -6279,8 +6543,12 @@ static inline void rtw89_chip_set_txpwr_ctrl(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; - if (chip->ops->set_txpwr_ctrl) - chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_0); + if (!chip->ops->set_txpwr_ctrl) + return; + + chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_0); + if (rtwdev->dbcc_en) + chip->ops->set_txpwr_ctrl(rtwdev, RTW89_PHY_1); } static inline void rtw89_chip_power_trim(struct rtw89_dev *rtwdev) @@ -6291,8 +6559,8 @@ static inline void rtw89_chip_power_trim(struct rtw89_dev *rtwdev) chip->ops->power_trim(rtwdev); } -static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx phy_idx) +static inline void __rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -6300,6 +6568,13 @@ static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev, chip->ops->init_txpwr_unit(rtwdev, phy_idx); } +static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev) +{ + __rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0); + if (rtwdev->dbcc_en) + __rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_1); +} + static inline u8 rtw89_chip_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) { @@ -6347,20 +6622,6 @@ static inline void rtw89_chip_cfg_txrx_path(struct rtw89_dev *rtwdev) chip->ops->cfg_txrx_path(rtwdev); } -static inline -void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif) -{ - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - const struct rtw89_chip_info *chip = rtwdev->chip; - - if (!vif->bss_conf.he_support || !vif->cfg.assoc) - return; - - if (chip->ops->set_txpwr_ul_tb_offset) - chip->ops->set_txpwr_ul_tb_offset(rtwdev, 0, rtwvif->mac_idx); -} - static inline void rtw89_chip_digital_pwr_comp(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -6457,14 +6718,14 @@ int rtw89_chip_resume_sch_tx(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en) static inline int rtw89_chip_h2c_dctl_sec_cam(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; if (!chip->ops->h2c_dctl_sec_cam) return 0; - return chip->ops->h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + return chip->ops->h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link); } static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) @@ -6479,13 +6740,14 @@ static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) return hdr->addr3; } -static inline bool rtw89_sta_has_beamformer_cap(struct ieee80211_sta *sta) +static inline +bool rtw89_sta_has_beamformer_cap(struct ieee80211_link_sta *link_sta) { - if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) || - (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] & + if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) || + (link_sta->he_cap.he_cap_elem.phy_cap_info[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) || - (sta->deflink.he_cap.he_cap_elem.phy_cap_info[4] & + (link_sta->he_cap.he_cap_elem.phy_cap_info[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) return true; return false; @@ -6605,21 +6867,21 @@ void rtw89_core_napi_start(struct rtw89_dev *rtwdev); void rtw89_core_napi_stop(struct rtw89_dev *rtwdev); int rtw89_core_napi_init(struct rtw89_dev *rtwdev); void rtw89_core_napi_deinit(struct rtw89_dev *rtwdev); -int rtw89_core_sta_add(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int rtw89_core_sta_remove(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); +int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); +int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); +int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); +int rtw89_core_sta_link_disconnect(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); +int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); void rtw89_core_set_tid_config(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, struct cfg80211_tid_config *tid_config); @@ -6635,22 +6897,40 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device, void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev); u8 rtw89_acquire_mac_id(struct rtw89_dev *rtwdev); void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id); +void rtw89_init_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + u8 mac_id, u8 port); +void rtw89_init_sta(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, u8 mac_id); +struct rtw89_vif_link *rtw89_vif_set_link(struct rtw89_vif *rtwvif, + unsigned int link_id); +void rtw89_vif_unset_link(struct rtw89_vif *rtwvif, unsigned int link_id); +struct rtw89_sta_link *rtw89_sta_set_link(struct rtw89_sta *rtwsta, + unsigned int link_id); +void rtw89_sta_unset_link(struct rtw89_sta *rtwsta, unsigned int link_id); void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev); void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef); void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef, struct rtw89_chan *chan); int rtw89_set_channel(struct rtw89_dev *rtwdev); -void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_chan *chan); u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size); void rtw89_core_release_bit_map(unsigned long *addr, u8 bit); void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits); int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx); + struct rtw89_sta_link *rtwsta_link, u8 tid, + u8 *cam_idx); int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx); -void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc); + struct rtw89_sta_link *rtwsta_link, u8 tid, + u8 *cam_idx); +void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta); +void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta); +void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta); +void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc); int rtw89_chip_info_setup(struct rtw89_dev *rtwdev); +void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate); int rtw89_regd_setup(struct rtw89_dev *rtwdev); int rtw89_regd_init(struct rtw89_dev *rtwdev, @@ -6667,13 +6947,15 @@ void rtw89_core_update_beacon_work(struct work_struct *work); void rtw89_roc_work(struct work_struct *work); void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); -void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, const u8 *mac_addr, bool hw_scan); void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, bool hw_scan); -int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool hw_scan); +int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool active); -void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf); void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event); #endif diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 29f85210f91964..6abd88fa80baf7 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3506,7 +3506,9 @@ static ssize_t rtw89_debug_priv_fw_log_manual_set(struct file *filp, return count; } -static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) +static void rtw89_sta_link_info_get_iter(struct seq_file *m, + struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) { static const char * const he_gi_str[] = { [NL80211_RATE_INFO_HE_GI_0_8] = "0.8", @@ -3518,20 +3520,26 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) [NL80211_RATE_INFO_EHT_GI_1_6] = "1.6", [NL80211_RATE_INFO_EHT_GI_3_2] = "3.2", }; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rate_info *rate = &rtwsta->ra_report.txrate; - struct ieee80211_rx_status *status = &rtwsta->rx_status; - struct seq_file *m = (struct seq_file *)data; - struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rate_info *rate = &rtwsta_link->ra_report.txrate; + struct ieee80211_rx_status *status = &rtwsta_link->rx_status; struct rtw89_hal *hal = &rtwdev->hal; u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; bool ant_asterisk = hal->tx_path_diversity || hal->ant_diversity; + struct ieee80211_link_sta *link_sta; u8 evm_min, evm_max, evm_1ss; + u16 max_rc_amsdu_len; u8 rssi; u8 snr; int i; - seq_printf(m, "TX rate [%d]: ", rtwsta->mac_id); + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + max_rc_amsdu_len = link_sta->agg.max_rc_amsdu_len; + + rcu_read_unlock(); + + seq_printf(m, "TX rate [%u, %u]: ", rtwsta_link->mac_id, rtwsta_link->link_id); if (rate->flags & RATE_INFO_FLAGS_MCS) seq_printf(m, "HT MCS-%d%s", rate->mcs, @@ -3549,13 +3557,13 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) eht_gi_str[rate->eht_gi] : "N/A"); else seq_printf(m, "Legacy %d", rate->legacy); - seq_printf(m, "%s", rtwsta->ra_report.might_fallback_legacy ? " FB_G" : ""); + seq_printf(m, "%s", rtwsta_link->ra_report.might_fallback_legacy ? " FB_G" : ""); seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(rate->bw)); - seq_printf(m, "\t(hw_rate=0x%x)", rtwsta->ra_report.hw_rate); - seq_printf(m, "\t==> agg_wait=%d (%d)\n", rtwsta->max_agg_wait, - sta->deflink.agg.max_rc_amsdu_len); + seq_printf(m, " (hw_rate=0x%x)", rtwsta_link->ra_report.hw_rate); + seq_printf(m, " ==> agg_wait=%d (%d)\n", rtwsta_link->max_agg_wait, + max_rc_amsdu_len); - seq_printf(m, "RX rate [%d]: ", rtwsta->mac_id); + seq_printf(m, "RX rate [%u, %u]: ", rtwsta_link->mac_id, rtwsta_link->link_id); switch (status->encoding) { case RX_ENC_LEGACY: @@ -3582,24 +3590,24 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) break; } seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(status->bw)); - seq_printf(m, "\t(hw_rate=0x%x)\n", rtwsta->rx_hw_rate); + seq_printf(m, " (hw_rate=0x%x)\n", rtwsta_link->rx_hw_rate); - rssi = ewma_rssi_read(&rtwsta->avg_rssi); + rssi = ewma_rssi_read(&rtwsta_link->avg_rssi); seq_printf(m, "RSSI: %d dBm (raw=%d, prev=%d) [", - RTW89_RSSI_RAW_TO_DBM(rssi), rssi, rtwsta->prev_rssi); + RTW89_RSSI_RAW_TO_DBM(rssi), rssi, rtwsta_link->prev_rssi); for (i = 0; i < ant_num; i++) { - rssi = ewma_rssi_read(&rtwsta->rssi[i]); + rssi = ewma_rssi_read(&rtwsta_link->rssi[i]); seq_printf(m, "%d%s%s", RTW89_RSSI_RAW_TO_DBM(rssi), ant_asterisk && (hal->antenna_tx & BIT(i)) ? "*" : "", i + 1 == ant_num ? "" : ", "); } seq_puts(m, "]\n"); - evm_1ss = ewma_evm_read(&rtwsta->evm_1ss); + evm_1ss = ewma_evm_read(&rtwsta_link->evm_1ss); seq_printf(m, "EVM: [%2u.%02u, ", evm_1ss >> 2, (evm_1ss & 0x3) * 25); for (i = 0; i < (hal->ant_diversity ? 2 : 1); i++) { - evm_min = ewma_evm_read(&rtwsta->evm_min[i]); - evm_max = ewma_evm_read(&rtwsta->evm_max[i]); + evm_min = ewma_evm_read(&rtwsta_link->evm_min[i]); + evm_max = ewma_evm_read(&rtwsta_link->evm_max[i]); seq_printf(m, "%s(%2u.%02u, %2u.%02u)", i == 0 ? "" : " ", evm_min >> 2, (evm_min & 0x3) * 25, @@ -3607,10 +3615,22 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) } seq_puts(m, "]\t"); - snr = ewma_snr_read(&rtwsta->avg_snr); + snr = ewma_snr_read(&rtwsta_link->avg_snr); seq_printf(m, "SNR: %u\n", snr); } +static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) +{ + struct seq_file *m = (struct seq_file *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) + rtw89_sta_link_info_get_iter(m, rtwdev, rtwsta_link); +} + static void rtw89_debug_append_rx_rate(struct seq_file *m, struct rtw89_pkt_stat *pkt_stat, enum rtw89_hw_rate first_rate, int len) @@ -3652,14 +3672,22 @@ static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v) struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_rx_rate_cnt_info *info; + struct rtw89_hal *hal = &rtwdev->hal; enum rtw89_hw_rate first_rate; + u8 rssi; int i; - seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d), RX: %u [%u] Mbps (lv: %d)\n", - stats->tx_throughput, stats->tx_throughput_raw, stats->tx_tfc_lv, + rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi); + + seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d", + stats->tx_throughput, stats->tx_throughput_raw, stats->tx_tfc_lv); + if (hal->thermal_prot_lv) + seq_printf(m, ", duty: %d%%", + 100 - hal->thermal_prot_lv * RTW89_THERMAL_PROT_STEP); + seq_printf(m, "), RX: %u [%u] Mbps (lv: %d)\n", stats->rx_throughput, stats->rx_throughput_raw, stats->rx_tfc_lv); - seq_printf(m, "Beacon: %u, TF: %u\n", pkt_stat->beacon_nr, - stats->rx_tf_periodic); + seq_printf(m, "Beacon: %u (%d dBm), TF: %u\n", pkt_stat->beacon_nr, + RTW89_RSSI_RAW_TO_DBM(rssi), stats->rx_tf_periodic); seq_printf(m, "Avg packet length: TX=%u, RX=%u\n", stats->tx_avg_len, stats->rx_avg_len); @@ -3737,28 +3765,41 @@ static void rtw89_dump_pkt_offload(struct seq_file *m, struct list_head *pkt_lis seq_puts(m, "\n"); } +static void rtw89_vif_link_ids_get(struct seq_file *m, u8 *mac, + struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif_link->bssid_cam; + + seq_printf(m, " [%u] %pM\n", rtwvif_link->mac_id, rtwvif_link->mac_addr); + seq_printf(m, "\tlink_id=%u\n", rtwvif_link->link_id); + seq_printf(m, "\tbssid_cam_idx=%u\n", bssid_cam->bssid_cam_idx); + rtw89_dump_addr_cam(m, rtwdev, &rtwvif_link->addr_cam); + rtw89_dump_pkt_offload(m, &rtwvif_link->general_pkt_list, + "\tpkt_ofld[GENERAL]: "); +} + static void rtw89_vif_ids_get_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_dev *rtwdev = rtwvif->rtwdev; struct seq_file *m = (struct seq_file *)data; - struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; - seq_printf(m, "VIF [%d] %pM\n", rtwvif->mac_id, rtwvif->mac_addr); - seq_printf(m, "\tbssid_cam_idx=%u\n", bssid_cam->bssid_cam_idx); - rtw89_dump_addr_cam(m, rtwdev, &rtwvif->addr_cam); - rtw89_dump_pkt_offload(m, &rtwvif->general_pkt_list, "\tpkt_ofld[GENERAL]: "); + seq_printf(m, "VIF %pM\n", rtwvif->mac_addr); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_vif_link_ids_get(m, mac, rtwdev, rtwvif_link); } -static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_sta *rtwsta) +static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = rtwsta->rtwvif; - struct rtw89_dev *rtwdev = rtwvif->rtwdev; struct rtw89_ba_cam_entry *entry; bool first = true; - list_for_each_entry(entry, &rtwsta->ba_cam_list, list) { + list_for_each_entry(entry, &rtwsta_link->ba_cam_list, list) { if (first) { seq_puts(m, "\tba_cam "); first = false; @@ -3771,16 +3812,36 @@ static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_sta *rtwsta) seq_puts(m, "\n"); } +static void rtw89_sta_link_ids_get(struct seq_file *m, + struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) +{ + struct ieee80211_link_sta *link_sta; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + seq_printf(m, " [%u] %pM\n", rtwsta_link->mac_id, link_sta->addr); + + rcu_read_unlock(); + + seq_printf(m, "\tlink_id=%u\n", rtwsta_link->link_id); + rtw89_dump_addr_cam(m, rtwdev, &rtwsta_link->addr_cam); + rtw89_dump_ba_cam(m, rtwdev, rtwsta_link); +} + static void rtw89_sta_ids_get_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_dev *rtwdev = rtwsta->rtwdev; struct seq_file *m = (struct seq_file *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; - seq_printf(m, "STA [%d] %pM %s\n", rtwsta->mac_id, sta->addr, - sta->tdls ? "(TDLS)" : ""); - rtw89_dump_addr_cam(m, rtwdev, &rtwsta->addr_cam); - rtw89_dump_ba_cam(m, rtwsta); + seq_printf(m, "STA %pM %s\n", sta->addr, sta->tdls ? "(TDLS)" : ""); + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) + rtw89_sta_link_ids_get(m, rtwdev, rtwsta_link); } static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v) @@ -3830,6 +3891,7 @@ static const struct rtw89_disabled_dm_info { const char *name; } rtw89_disabled_dm_infos[] = { DM_INFO(DYNAMIC_EDCCA), + DM_INFO(THERMAL_PROTECT), }; static int diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index e1236079a84a1a..6c6c763510af6b 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -11,11 +11,38 @@ #define EF_CV_MASK GENMASK(7, 4) #define EF_CV_INV 15 +#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0) +#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4) +#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0) +#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6) + +#define EFUSE_EXTERNALPN_ADDR_AX 0x5EC +#define EFUSE_CUSTOMER_ADDR_AX 0x5ED +#define EFUSE_SERIALNUM_ADDR_AX 0x5ED + +#define EFUSE_B1_EXTERNALPN_MASK GENMASK(7, 0) +#define EFUSE_B2_CUSTOMER_MASK GENMASK(3, 0) +#define EFUSE_B2_SERIALNUM_MASK GENMASK(6, 4) + +#define OTP_KEY_INFO_NUM 2 + +static const u8 otp_key_info_externalPN[OTP_KEY_INFO_NUM] = {0x0, 0x0}; +static const u8 otp_key_info_customer[OTP_KEY_INFO_NUM] = {0x0, 0x1}; +static const u8 otp_key_info_serialNum[OTP_KEY_INFO_NUM] = {0x0, 0x1}; + enum rtw89_efuse_bank { RTW89_EFUSE_BANK_WIFI, RTW89_EFUSE_BANK_BT, }; +enum rtw89_efuse_mss_dev_type { + MSS_DEV_TYPE_FWSEC_DEF = 0xF, + MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC, + MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA, + MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9, + MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6, +}; + static int rtw89_switch_efuse_bank(struct rtw89_dev *rtwdev, enum rtw89_efuse_bank bank) { @@ -354,3 +381,126 @@ int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *ecv) return 0; } EXPORT_SYMBOL(rtw89_read_efuse_ver); + +static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type) +{ + switch (mss_dev_type) { + case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX: + mss_dev_type = 0x0; + break; + case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB: + mss_dev_type = 0x1; + break; + case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB: + mss_dev_type = 0x2; + break; + case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX: + mss_dev_type = 0x3; + break; + case MSS_DEV_TYPE_FWSEC_DEF: + mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF; + break; + default: + rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type); + mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV; + break; + } + + return mss_dev_type; +} + +int rtw89_efuse_recognize_mss_info_v1(struct rtw89_dev *rtwdev, u8 b1, u8 b2) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u8 mss_dev_type; + + if (chip->chip_id == RTL8852B && b1 == 0xFF && b2 == 0x6E) { + mss_dev_type = MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB; + sec->mss_cust_idx = 0; + sec->mss_key_num = 0; + + goto mss_dev_type; + } + + mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK); + sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) | + u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4); + sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK); + +mss_dev_type: + sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type); + if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) { + rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type); + return -ENOENT; + } + + sec->can_mss_v1 = true; + + return 0; +} + +static +int rtw89_efuse_recognize_mss_index_v0(struct rtw89_dev *rtwdev, u8 b1, u8 b2) +{ + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u8 externalPN; + u8 serialNum; + u8 customer; + u8 i; + + externalPN = 0xFF - u8_get_bits(b1, EFUSE_B1_EXTERNALPN_MASK); + customer = 0xF - u8_get_bits(b2, EFUSE_B2_CUSTOMER_MASK); + serialNum = 0x7 - u8_get_bits(b2, EFUSE_B2_SERIALNUM_MASK); + + for (i = 0; i < OTP_KEY_INFO_NUM; i++) { + if (externalPN == otp_key_info_externalPN[i] && + customer == otp_key_info_customer[i] && + serialNum == otp_key_info_serialNum[i]) { + sec->mss_idx = i; + sec->can_mss_v0 = true; + return 0; + } + } + + return -ENOENT; +} + +int rtw89_efuse_read_fw_secure_ax(struct rtw89_dev *rtwdev) +{ + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + u32 sec_addr = EFUSE_EXTERNALPN_ADDR_AX; + u32 sec_size = 2; + u8 sec_map[2]; + u8 b1, b2; + int ret; + + ret = rtw89_dump_physical_efuse_map(rtwdev, sec_map, + sec_addr, sec_size, false); + if (ret) { + rtw89_warn(rtwdev, "failed to dump secsel map\n"); + return ret; + } + + b1 = sec_map[0]; + b2 = sec_map[1]; + + if (b1 == 0xFF && b2 == 0xFF) + return 0; + + rtw89_efuse_recognize_mss_index_v0(rtwdev, b1, b2); + rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2); + if (!sec->can_mss_v1 && !sec->can_mss_v0) + goto out; + + sec->secure_boot = true; + +out: + rtw89_debug(rtwdev, RTW89_DBG_FW, + "MSS secure_boot=%d(%d/%d) dev_type=%d cust_idx=%d key_num=%d mss_index=%d\n", + sec->secure_boot, sec->can_mss_v0, sec->can_mss_v1, + sec->mss_dev_type, sec->mss_cust_idx, + sec->mss_key_num, sec->mss_idx); + + return 0; +} diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index 72416f56a07136..a96fc104479104 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -23,6 +23,8 @@ int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev); int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev); int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle); int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); +int rtw89_efuse_recognize_mss_info_v1(struct rtw89_dev *rtwdev, u8 b1, u8 b2); +int rtw89_efuse_read_fw_secure_ax(struct rtw89_dev *rtwdev); int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c index 0be26d5fdf7cf6..64768923b0f0a8 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse_be.c +++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c @@ -8,11 +8,7 @@ #include "reg.h" #define EFUSE_EXTERNALPN_ADDR_BE 0x1580 -#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0) -#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4) #define EFUSE_SERIALNUM_ADDR_BE 0x1581 -#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0) -#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6) #define EFUSE_SB_CRYP_SEL_ADDR 0x1582 #define EFUSE_SB_CRYP_SEL_SIZE 2 #define EFUSE_SB_CRYP_SEL_DEFAULT 0xFFFF @@ -20,14 +16,6 @@ #define EFUSE_SEC_BE_START 0x1580 #define EFUSE_SEC_BE_SIZE 4 -enum rtw89_efuse_mss_dev_type { - MSS_DEV_TYPE_FWSEC_DEF = 0xF, - MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC, - MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA, - MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9, - MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6, -}; - static const u32 sb_sel_mgn[SB_SEL_MGN_MAX_SIZE] = { 0x8000100, 0xC000180 }; @@ -477,33 +465,6 @@ static u16 get_sb_cryp_sel_idx(u16 sb_cryp_sel) return sb_cryp_sel_v + low_bit; } -static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type) -{ - switch (mss_dev_type) { - case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX: - mss_dev_type = 0x0; - break; - case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB: - mss_dev_type = 0x1; - break; - case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB: - mss_dev_type = 0x2; - break; - case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX: - mss_dev_type = 0x3; - break; - case MSS_DEV_TYPE_FWSEC_DEF: - mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF; - break; - default: - rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type); - mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV; - break; - } - - return mss_dev_type; -} - int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) { struct rtw89_fw_secure *sec = &rtwdev->fw.sec; @@ -511,7 +472,6 @@ int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) u32 sec_size = EFUSE_SEC_BE_SIZE; u16 sb_cryp_sel, sb_cryp_sel_idx; u8 sec_map[EFUSE_SEC_BE_SIZE]; - u8 mss_dev_type; u8 b1, b2; int ret; @@ -538,16 +498,9 @@ int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) b1 = sec_map[EFUSE_EXTERNALPN_ADDR_BE - sec_addr]; b2 = sec_map[EFUSE_SERIALNUM_ADDR_BE - sec_addr]; - mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK); - sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) | - u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4); - sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK); - - sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type); - if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) { - rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type); + ret = rtw89_efuse_recognize_mss_info_v1(rtwdev, b1, b2); + if (ret) goto out; - } sec->secure_boot = true; @@ -559,4 +512,3 @@ int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev) return 0; } -EXPORT_SYMBOL(rtw89_efuse_read_fw_secure_be); diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index d9b0e7ebe619a3..2191c037d72e40 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -56,6 +56,11 @@ static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb); static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_wait_info *wait, unsigned int cond); +static int __parse_security_section(struct rtw89_dev *rtwdev, + struct rtw89_fw_bin_info *info, + struct rtw89_fw_hdr_section_info *section_info, + const void *content, + u32 *mssc_len); static struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len, bool header) @@ -124,13 +129,16 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le struct rtw89_fw_bin_info *info) { const struct rtw89_fw_hdr *fw_hdr = (const struct rtw89_fw_hdr *)fw; + const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_fw_hdr_section_info *section_info; + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; const struct rtw89_fw_dynhdr_hdr *fwdynhdr; const struct rtw89_fw_hdr_section *section; const u8 *fw_end = fw + len; const u8 *bin; u32 base_hdr_len; - u32 mssc_len = 0; + u32 mssc_len; + int ret; u32 i; if (!info) @@ -139,6 +147,7 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM); base_hdr_len = struct_size(fw_hdr, sections, info->section_num); info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR); + info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_W7_IDMEM_SHARE_MODE); if (info->dynamic_hdr_en) { info->hdr_len = le32_get_bits(fw_hdr->w3, FW_HDR_W3_LEN); @@ -161,26 +170,47 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le section = &fw_hdr->sections[i]; section_info->type = le32_get_bits(section->w1, FWSECTION_HDR_W1_SECTIONTYPE); - if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { - section_info->mssc = - le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC); - mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; - } else { - section_info->mssc = 0; - } - section_info->len = le32_get_bits(section->w1, FWSECTION_HDR_W1_SEC_SIZE); + if (le32_get_bits(section->w1, FWSECTION_HDR_W1_CHECKSUM)) section_info->len += FWDL_SECTION_CHKSUM_LEN; section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_W1_REDL); section_info->dladdr = le32_get_bits(section->w0, FWSECTION_HDR_W0_DL_ADDR) & 0x1fffffff; section_info->addr = bin; - bin += section_info->len; + + if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { + section_info->mssc = + le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC); + + ret = __parse_security_section(rtwdev, info, section_info, + bin, &mssc_len); + if (ret) + return ret; + + if (sec->secure_boot && chip->chip_id == RTL8852B) + section_info->len_override = 960; + } else { + section_info->mssc = 0; + mssc_len = 0; + } + + rtw89_debug(rtwdev, RTW89_DBG_FW, + "section[%d] type=%d len=0x%-6x mssc=%d mssc_len=%d addr=%tx\n", + i, section_info->type, section_info->len, + section_info->mssc, mssc_len, bin - fw); + rtw89_debug(rtwdev, RTW89_DBG_FW, + " ignore=%d key_addr=%p (0x%tx) key_len=%d key_idx=%d\n", + section_info->ignore, section_info->key_addr, + section_info->key_addr ? + section_info->key_addr - section_info->addr : 0, + section_info->key_len, section_info->key_idx); + + bin += section_info->len + mssc_len; section_info++; } - if (fw_end != bin + mssc_len) { + if (fw_end != bin) { rtw89_err(rtwdev, "[ERR]fw bin size\n"); return -EINVAL; } @@ -235,7 +265,6 @@ static int __get_mssc_key_idx(struct rtw89_dev *rtwdev, static int __parse_formatted_mssc(struct rtw89_dev *rtwdev, struct rtw89_fw_bin_info *info, struct rtw89_fw_hdr_section_info *section_info, - const struct rtw89_fw_hdr_section_v1 *section, const void *content, u32 *mssc_len) { @@ -318,18 +347,15 @@ static int __parse_formatted_mssc(struct rtw89_dev *rtwdev, static int __parse_security_section(struct rtw89_dev *rtwdev, struct rtw89_fw_bin_info *info, struct rtw89_fw_hdr_section_info *section_info, - const struct rtw89_fw_hdr_section_v1 *section, const void *content, u32 *mssc_len) { + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; int ret; - section_info->mssc = - le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC); - - if (section_info->mssc == FORMATTED_MSSC) { + if ((section_info->mssc & FORMATTED_MSSC_MASK) == FORMATTED_MSSC) { ret = __parse_formatted_mssc(rtwdev, info, section_info, - section, content, mssc_len); + content, mssc_len); if (ret) return -EINVAL; } else { @@ -337,6 +363,14 @@ static int __parse_security_section(struct rtw89_dev *rtwdev, if (info->dsp_checksum) *mssc_len += section_info->mssc * FWDL_SECURITY_CHKSUM_LEN; + if (sec->secure_boot) { + if (sec->mss_idx >= section_info->mssc) + return -EFAULT; + section_info->key_addr = content + section_info->len + + sec->mss_idx * FWDL_SECURITY_SIGLEN; + section_info->key_len = FWDL_SECURITY_SIGLEN; + } + info->secure_section_exist = true; } @@ -361,6 +395,7 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le info->dsp_checksum = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_DSP_CHKSUM); base_hdr_len = struct_size(fw_hdr, sections, info->section_num); info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_DYN_HDR); + info->idmem_share_mode = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_IDMEM_SHARE_MODE); if (info->dynamic_hdr_en) { info->hdr_len = le32_get_bits(fw_hdr->w5, FW_HDR_V1_W5_HDR_SIZE); @@ -394,8 +429,11 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le section_info->addr = bin; if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { + section_info->mssc = + le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC); + ret = __parse_security_section(rtwdev, info, section_info, - section, bin, &mssc_len); + bin, &mssc_len); if (ret) return ret; } else { @@ -665,11 +703,13 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 37, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 38, 0, NO_PACKET_DROP), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), + __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER), @@ -687,6 +727,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 12, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, RFK_PRE_NOTIFY_V0), + __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 42, 0, RFK_RXDCK_V0), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -1152,9 +1193,24 @@ static u32 __rtw89_fw_download_tweak_hdr_v0(struct rtw89_dev *rtwdev, struct rtw89_fw_bin_info *info, struct rtw89_fw_hdr *fw_hdr) { + struct rtw89_fw_hdr_section_info *section_info; + struct rtw89_fw_hdr_section *section; + int i; + le32p_replace_bits(&fw_hdr->w7, FWDL_SECTION_PER_PKT_LEN, FW_HDR_W7_PART_SIZE); + for (i = 0; i < info->section_num; i++) { + section_info = &info->section_info[i]; + + if (!section_info->len_override) + continue; + + section = &fw_hdr->sections[i]; + le32p_replace_bits(§ion->w1, section_info->len_override, + FWSECTION_HDR_W1_SEC_SIZE); + } + return 0; } @@ -1283,10 +1339,20 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev, if (info->ignore) return 0; + if (info->len_override) { + if (info->len_override > info->len) + rtw89_warn(rtwdev, "override length %u larger than original %u\n", + info->len_override, info->len); + else + residue_len = info->len_override; + } + if (info->key_addr && info->key_len) { - if (info->len > FWDL_SECTION_PER_PKT_LEN || info->len < info->key_len) - rtw89_warn(rtwdev, "ignore to copy key data because of len %d, %d, %d\n", - info->len, FWDL_SECTION_PER_PKT_LEN, info->key_len); + if (residue_len > FWDL_SECTION_PER_PKT_LEN || info->len < info->key_len) + rtw89_warn(rtwdev, + "ignore to copy key data because of len %d, %d, %d, %d\n", + info->len, FWDL_SECTION_PER_PKT_LEN, + info->key_len, residue_len); else copy_key = true; } @@ -1422,6 +1488,8 @@ static int rtw89_fw_download_suit(struct rtw89_dev *rtwdev, return ret; } + rtw89_fwdl_secure_idmem_share_mode(rtwdev, info.idmem_share_mode); + if (rtwdev->chip->chip_id == RTL8922A && (fw_suit->type == RTW89_FW_NORMAL || fw_suit->type == RTW89_FW_WOWLAN)) rtw89_write32(rtwdev, R_BE_SECURE_BOOT_MALLOC_INFO, 0x20248000); @@ -1741,8 +1809,8 @@ void rtw89_fw_log_dump(struct rtw89_dev *rtwdev, u8 *buf, u32 len) } #define H2C_CAM_LEN 60 -int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, const u8 *scan_mac_addr) +int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr) { struct sk_buff *skb; int ret; @@ -1753,8 +1821,9 @@ int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, return -ENOMEM; } skb_put(skb, H2C_CAM_LEN); - rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif, rtwsta, scan_mac_addr, skb->data); - rtw89_cam_fill_bssid_cam_info(rtwdev, rtwvif, rtwsta, skb->data); + rtw89_cam_fill_addr_cam_info(rtwdev, rtwvif_link, rtwsta_link, scan_mac_addr, + skb->data); + rtw89_cam_fill_bssid_cam_info(rtwdev, rtwvif_link, rtwsta_link, skb->data); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -1776,8 +1845,8 @@ int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, } int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { struct rtw89_h2c_dctlinfo_ud_v1 *h2c; u32 len = sizeof(*h2c); @@ -1792,7 +1861,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_dctlinfo_ud_v1 *)skb->data; - rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif, rtwsta, h2c); + rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif_link, rtwsta_link, h2c); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -1815,8 +1884,8 @@ int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1); int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { struct rtw89_h2c_dctlinfo_ud_v2 *h2c; u32 len = sizeof(*h2c); @@ -1831,7 +1900,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data; - rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif, rtwsta, h2c); + rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif_link, rtwsta_link, h2c); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -1854,10 +1923,10 @@ int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2); int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; struct rtw89_h2c_dctlinfo_ud_v2 *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -1908,21 +1977,24 @@ int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v2); -int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params) { const struct rtw89_chip_info *chip = rtwdev->chip; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_h2c_ba_cam *h2c; - u8 macid = rtwsta->mac_id; + u8 macid = rtwsta_link->mac_id; u32 len = sizeof(*h2c); struct sk_buff *skb; u8 entry_idx; int ret; ret = valid ? - rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) : - rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx); + rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta_link, params->tid, + &entry_idx) : + rtw89_core_release_sta_ba_entry(rtwdev, rtwsta_link, params->tid, + &entry_idx); if (ret) { /* it still works even if we don't have static BA CAM, because * hardware can create dynamic BA CAM automatically. @@ -1960,7 +2032,8 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, if (chip->bacam_ver == RTW89_BACAM_V0_EXT) { h2c->w1 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W1_STD_EN) | - le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BA_CAM_W1_BAND); + le32_encode_bits(rtwvif_link->mac_idx, + RTW89_H2C_BA_CAM_W1_BAND); } end: @@ -2039,13 +2112,14 @@ void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev) } } -int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params) { const struct rtw89_chip_info *chip = rtwdev->chip; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_h2c_ba_cam_v1 *h2c; - u8 macid = rtwsta->mac_id; + u8 macid = rtwsta_link->mac_id; u32 len = sizeof(*h2c); struct sk_buff *skb; u8 entry_idx; @@ -2053,8 +2127,10 @@ int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, int ret; ret = valid ? - rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) : - rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx); + rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta_link, params->tid, + &entry_idx) : + rtw89_core_release_sta_ba_entry(rtwdev, rtwsta_link, params->tid, + &entry_idx); if (ret) { /* it still works even if we don't have static BA CAM, because * hardware can create dynamic BA CAM automatically. @@ -2092,7 +2168,8 @@ int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, entry_idx += chip->bacam_dynamic_num; /* std entry right after dynamic ones */ h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK) | le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W1_STD_ENTRY_EN) | - le32_encode_bits(!!rtwvif->mac_idx, RTW89_H2C_BA_CAM_V1_W1_BAND_SEL); + le32_encode_bits(!!rtwvif_link->mac_idx, + RTW89_H2C_BA_CAM_V1_W1_BAND_SEL); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -2197,15 +2274,14 @@ int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable) } static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { static const u8 gtkbody[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E, 0x01, 0x03, 0x00, 0x5F, 0x02, 0x03}; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_eapol_2_of_2 *eapol_pkt; + struct ieee80211_bss_conf *bss_conf; struct ieee80211_hdr_3addr *hdr; struct sk_buff *skb; u8 key_des_ver; @@ -2227,10 +2303,17 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS | IEEE80211_FCTL_PROTECTED); + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ether_addr_copy(hdr->addr1, bss_conf->bssid); - ether_addr_copy(hdr->addr2, vif->addr); + ether_addr_copy(hdr->addr2, bss_conf->addr); ether_addr_copy(hdr->addr3, bss_conf->bssid); + rcu_read_unlock(); + skb_put_zero(skb, sec_hdr_len); eapol_pkt = skb_put_zero(skb, sizeof(*eapol_pkt)); @@ -2241,11 +2324,10 @@ static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev, } static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); + struct ieee80211_bss_conf *bss_conf; struct ieee80211_hdr_3addr *hdr; struct rtw89_sa_query *sa_query; struct sk_buff *skb; @@ -2258,10 +2340,17 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION | IEEE80211_FCTL_PROTECTED); + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ether_addr_copy(hdr->addr1, bss_conf->bssid); - ether_addr_copy(hdr->addr2, vif->addr); + ether_addr_copy(hdr->addr2, bss_conf->addr); ether_addr_copy(hdr->addr3, bss_conf->bssid); + rcu_read_unlock(); + skb_put_zero(skb, sec_hdr_len); sa_query = skb_put_zero(skb, sizeof(*sa_query)); @@ -2272,8 +2361,9 @@ static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev, } static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct ieee80211_hdr_3addr *hdr; @@ -2295,9 +2385,9 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS); hdr->frame_control = fc; - ether_addr_copy(hdr->addr1, rtwvif->bssid); - ether_addr_copy(hdr->addr2, rtwvif->mac_addr); - ether_addr_copy(hdr->addr3, rtwvif->bssid); + ether_addr_copy(hdr->addr1, rtwvif_link->bssid); + ether_addr_copy(hdr->addr2, rtwvif_link->mac_addr); + ether_addr_copy(hdr->addr3, rtwvif_link->bssid); skb_put_zero(skb, sec_hdr_len); @@ -2312,18 +2402,18 @@ static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev, arp_hdr->ar_pln = 4; arp_hdr->ar_op = htons(ARPOP_REPLY); - ether_addr_copy(arp_skb->sender_hw, rtwvif->mac_addr); + ether_addr_copy(arp_skb->sender_hw, rtwvif_link->mac_addr); arp_skb->sender_ip = rtwvif->ip_addr; return skb; } static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, enum rtw89_fw_pkt_ofld_type type, u8 *id) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_pktofld_info *info; struct sk_buff *skb; int ret; @@ -2346,13 +2436,13 @@ static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, true); break; case RTW89_PKT_OFLD_TYPE_EAPOL_KEY: - skb = rtw89_eapol_get(rtwdev, rtwvif); + skb = rtw89_eapol_get(rtwdev, rtwvif_link); break; case RTW89_PKT_OFLD_TYPE_SA_QUERY: - skb = rtw89_sa_query_get(rtwdev, rtwvif); + skb = rtw89_sa_query_get(rtwdev, rtwvif_link); break; case RTW89_PKT_OFLD_TYPE_ARP_RSP: - skb = rtw89_arp_response_get(rtwdev, rtwvif); + skb = rtw89_arp_response_get(rtwdev, rtwvif_link); break; default: goto err; @@ -2367,7 +2457,7 @@ static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, if (ret) goto err; - list_add_tail(&info->list, &rtwvif->general_pkt_list); + list_add_tail(&info->list, &rtwvif_link->general_pkt_list); *id = info->id; return 0; @@ -2377,9 +2467,10 @@ static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev, } void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool notify_fw) + struct rtw89_vif_link *rtwvif_link, + bool notify_fw) { - struct list_head *pkt_list = &rtwvif->general_pkt_list; + struct list_head *pkt_list = &rtwvif_link->general_pkt_list; struct rtw89_pktofld_info *info, *tmp; list_for_each_entry_safe(info, tmp, pkt_list, list) { @@ -2394,16 +2485,20 @@ void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, notify_fw); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif_link, + notify_fw); } #define H2C_GENERAL_PKT_LEN 6 #define H2C_GENERAL_PKT_ID_UND 0xff int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u8 macid) + struct rtw89_vif_link *rtwvif_link, u8 macid) { u8 pkt_id_ps_poll = H2C_GENERAL_PKT_ID_UND; u8 pkt_id_null = H2C_GENERAL_PKT_ID_UND; @@ -2411,11 +2506,11 @@ int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct sk_buff *skb; int ret; - rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_PS_POLL, &pkt_id_ps_poll); - rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id_null); - rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_QOS_NULL, &pkt_id_qos_null); skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_GENERAL_PKT_LEN); @@ -2478,7 +2573,7 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_PS, - H2C_FUNC_MAC_LPS_PARM, 0, 1, + H2C_FUNC_MAC_LPS_PARM, 0, !lps_param->psmode, H2C_LPS_PARM_LEN); ret = rtw89_h2c_tx(rtwdev, skb, false); @@ -2494,10 +2589,10 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, return ret; } -int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_h2c_lps_ch_info *h2c; u32 len = sizeof(*h2c); @@ -2546,13 +2641,14 @@ int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) } #define H2C_P2P_ACT_LEN 20 -int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf, struct ieee80211_p2p_noa_desc *desc, u8 act, u8 noa_id) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - bool p2p_type_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; - u8 ctwindow_oppps = vif->bss_conf.p2p_noa_attr.oppps_ctwindow; + bool p2p_type_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; + u8 ctwindow_oppps = bss_conf->p2p_noa_attr.oppps_ctwindow; struct sk_buff *skb; u8 *cmd; int ret; @@ -2565,7 +2661,7 @@ int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, skb_put(skb, H2C_P2P_ACT_LEN); cmd = skb->data; - RTW89_SET_FWCMD_P2P_MACID(cmd, rtwvif->mac_id); + RTW89_SET_FWCMD_P2P_MACID(cmd, rtwvif_link->mac_id); RTW89_SET_FWCMD_P2P_P2PID(cmd, 0); RTW89_SET_FWCMD_P2P_NOAID(cmd, noa_id); RTW89_SET_FWCMD_P2P_ACT(cmd, act); @@ -2622,11 +2718,11 @@ static void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev, #define H2C_CMC_TBL_LEN 68 int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; - u8 macid = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 macid = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; struct sk_buff *skb; int ret; @@ -2648,7 +2744,7 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, } SET_CMC_TBL_DOPPLER_CTRL(skb->data, 0); SET_CMC_TBL_TXPWR_TOLERENCE(skb->data, 0); - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) SET_CMC_TBL_DATA_DCM(skb->data, 0); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -2671,10 +2767,10 @@ int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl); int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; struct rtw89_h2c_cctlinfo_ud_g7 *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -2755,24 +2851,25 @@ int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7); static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, u8 *pads) + struct ieee80211_link_sta *link_sta, + u8 *pads) { bool ppe_th; u8 ppe16, ppe8; - u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; - u8 ppe_thres_hdr = sta->deflink.he_cap.ppe_thres[0]; + u8 nss = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1; + u8 ppe_thres_hdr = link_sta->he_cap.ppe_thres[0]; u8 ru_bitmap; u8 n, idx, sh; u16 ppe; int i; ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, - sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]); + link_sta->he_cap.he_cap_elem.phy_cap_info[6]); if (!ppe_th) { u8 pad; pad = FIELD_GET(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK, - sta->deflink.he_cap.he_cap_elem.phy_cap_info[9]); + link_sta->he_cap.he_cap_elem.phy_cap_info[9]); for (i = 0; i < RTW89_PPE_BW_NUM; i++) pads[i] = pad; @@ -2794,7 +2891,7 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, sh = n & 7; n += IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2; - ppe = le16_to_cpu(*((__le16 *)&sta->deflink.he_cap.ppe_thres[idx])); + ppe = le16_to_cpu(*((__le16 *)&link_sta->he_cap.ppe_thres[idx])); ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; sh += IEEE80211_PPE_THRES_INFO_PPET_SIZE; ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; @@ -2809,23 +2906,35 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, } int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); const struct rtw89_chip_info *chip = rtwdev->chip; - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); + struct ieee80211_link_sta *link_sta; struct sk_buff *skb; u8 pads[RTW89_PPE_BW_NUM]; - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; u16 lowest_rate; int ret; memset(pads, 0, sizeof(pads)); - if (sta && sta->deflink.he_cap.has_he) - __get_sta_he_pkt_padding(rtwdev, sta, pads); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); + return -ENOMEM; + } + + rcu_read_lock(); + + if (rtwsta_link) + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (rtwsta_link && link_sta->he_cap.has_he) + __get_sta_he_pkt_padding(rtwdev, link_sta, pads); if (vif->p2p) lowest_rate = RTW89_HW_RATE_OFDM6; @@ -2834,11 +2943,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, else lowest_rate = RTW89_HW_RATE_OFDM6; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); - if (!skb) { - rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); - return -ENOMEM; - } skb_put(skb, H2C_CMC_TBL_LEN); SET_CTRL_INFO_MACID(skb->data, mac_id); SET_CTRL_INFO_OPERATION(skb->data, 1); @@ -2851,7 +2955,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, SET_CMC_TBL_ULDL(skb->data, 1); else SET_CMC_TBL_ULDL(skb->data, 0); - SET_CMC_TBL_MULTI_PORT_ID(skb->data, rtwvif->port); + SET_CMC_TBL_MULTI_PORT_ID(skb->data, rtwvif_link->port); if (chip->h2c_cctl_func_id == H2C_FUNC_MAC_CCTLINFO_UD_V1) { SET_CMC_TBL_NOMINAL_PKT_PADDING_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_20]); SET_CMC_TBL_NOMINAL_PKT_PADDING40_V1(skb->data, pads[RTW89_CHANNEL_WIDTH_40]); @@ -2863,12 +2967,14 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, SET_CMC_TBL_NOMINAL_PKT_PADDING80(skb->data, pads[RTW89_CHANNEL_WIDTH_80]); SET_CMC_TBL_NOMINAL_PKT_PADDING160(skb->data, pads[RTW89_CHANNEL_WIDTH_160]); } - if (sta) + if (rtwsta_link) SET_CMC_TBL_BSR_QUEUE_SIZE_FORMAT(skb->data, - sta->deflink.he_cap.has_he); - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + link_sta->he_cap.has_he); + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) SET_CMC_TBL_DATA_DCM(skb->data, 0); + rcu_read_unlock(); + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, chip->h2c_cctl_func_id, 0, 1, @@ -2889,9 +2995,10 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl); static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, u8 *pads) + struct ieee80211_link_sta *link_sta, + u8 *pads) { - u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; + u8 nss = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1; u16 ppe_thres_hdr; u8 ppe16, ppe8; u8 n, idx, sh; @@ -2900,12 +3007,12 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, u16 ppe; int i; - ppe_th = !!u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], + ppe_th = !!u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5], IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT); if (!ppe_th) { u8 pad; - pad = u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], + pad = u8_get_bits(link_sta->eht_cap.eht_cap_elem.phy_cap_info[5], IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); for (i = 0; i < RTW89_PPE_BW_NUM; i++) @@ -2914,7 +3021,7 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, return; } - ppe_thres_hdr = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres); + ppe_thres_hdr = get_unaligned_le16(link_sta->eht_cap.eht_ppe_thres); ru_bitmap = u16_get_bits(ppe_thres_hdr, IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); n = hweight8(ru_bitmap); @@ -2931,7 +3038,7 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, sh = n & 7; n += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2; - ppe = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres + idx); + ppe = get_unaligned_le16(link_sta->eht_cap.eht_ppe_thres + idx); ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; sh += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE; ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; @@ -2946,14 +3053,15 @@ static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, } int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + struct ieee80211_bss_conf *bss_conf; + struct ieee80211_link_sta *link_sta; u8 pads[RTW89_PPE_BW_NUM]; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -2961,11 +3069,24 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, int ret; memset(pads, 0, sizeof(pads)); - if (sta) { - if (sta->deflink.eht_cap.has_eht) - __get_sta_eht_pkt_padding(rtwdev, sta, pads); - else if (sta->deflink.he_cap.has_he) - __get_sta_he_pkt_padding(rtwdev, sta, pads); + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n"); + return -ENOMEM; + } + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + + if (rtwsta_link) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->eht_cap.has_eht) + __get_sta_eht_pkt_padding(rtwdev, link_sta, pads); + else if (link_sta->he_cap.has_he) + __get_sta_he_pkt_padding(rtwdev, link_sta, pads); } if (vif->p2p) @@ -2975,11 +3096,6 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, else lowest_rate = RTW89_HW_RATE_OFDM6; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); - if (!skb) { - rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n"); - return -ENOMEM; - } skb_put(skb, len); h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; @@ -3000,16 +3116,16 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, h2c->w3 = le32_encode_bits(0, CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL); h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL); - h2c->w4 = le32_encode_bits(rtwvif->port, CCTLINFO_G7_W4_MULTI_PORT_ID); + h2c->w4 = le32_encode_bits(rtwvif_link->port, CCTLINFO_G7_W4_MULTI_PORT_ID); h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_MULTI_PORT_ID); - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) { + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) { h2c->w4 |= le32_encode_bits(0, CCTLINFO_G7_W4_DATA_DCM); h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_DATA_DCM); } - if (vif->bss_conf.eht_support) { - u16 punct = vif->bss_conf.chanreq.oper.punctured; + if (bss_conf->eht_support) { + u16 punct = bss_conf->chanreq.oper.punctured; h2c->w4 |= le32_encode_bits(~punct, CCTLINFO_G7_W4_ACT_SUBCH_CBW); @@ -3036,12 +3152,14 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, CCTLINFO_G7_W6_ULDL); h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ULDL); - if (sta) { - h2c->w8 = le32_encode_bits(sta->deflink.he_cap.has_he, + if (rtwsta_link) { + h2c->w8 = le32_encode_bits(link_sta->he_cap.has_he, CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT); h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT); } + rcu_read_unlock(); + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, @@ -3062,10 +3180,10 @@ int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7); int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = rtwsta_link->rtwsta; struct rtw89_h2c_cctlinfo_ud_g7 *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -3102,7 +3220,7 @@ int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, else if (agg_num > 0x200 && agg_num <= 0x400) ba_bmap = 5; - h2c->c0 = le32_encode_bits(rtwsta->mac_id, CCTLINFO_G7_C0_MACID) | + h2c->c0 = le32_encode_bits(rtwsta_link->mac_id, CCTLINFO_G7_C0_MACID) | le32_encode_bits(1, CCTLINFO_G7_C0_OP); h2c->w3 = le32_encode_bits(ba_bmap, CCTLINFO_G7_W3_BA_BMAP); @@ -3128,7 +3246,7 @@ int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_g7); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta) + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; struct sk_buff *skb; @@ -3140,15 +3258,15 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, return -ENOMEM; } skb_put(skb, H2C_CMC_TBL_LEN); - SET_CTRL_INFO_MACID(skb->data, rtwsta->mac_id); + SET_CTRL_INFO_MACID(skb->data, rtwsta_link->mac_id); SET_CTRL_INFO_OPERATION(skb->data, 1); - if (rtwsta->cctl_tx_time) { + if (rtwsta_link->cctl_tx_time) { SET_CMC_TBL_AMPDU_TIME_SEL(skb->data, 1); - SET_CMC_TBL_AMPDU_MAX_TIME(skb->data, rtwsta->ampdu_max_time); + SET_CMC_TBL_AMPDU_MAX_TIME(skb->data, rtwsta_link->ampdu_max_time); } - if (rtwsta->cctl_tx_retry_limit) { + if (rtwsta_link->cctl_tx_retry_limit) { SET_CMC_TBL_DATA_TXCNT_LMT_SEL(skb->data, 1); - SET_CMC_TBL_DATA_TX_CNT_LMT(skb->data, rtwsta->data_tx_cnt_lmt); + SET_CMC_TBL_DATA_TX_CNT_LMT(skb->data, rtwsta_link->data_tx_cnt_lmt); } rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -3170,7 +3288,7 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, } int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta) + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; struct sk_buff *skb; @@ -3185,7 +3303,7 @@ int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, return -ENOMEM; } skb_put(skb, H2C_CMC_TBL_LEN); - SET_CTRL_INFO_MACID(skb->data, rtwsta->mac_id); + SET_CTRL_INFO_MACID(skb->data, rtwsta_link->mac_id); SET_CTRL_INFO_OPERATION(skb->data, 1); __rtw89_fw_h2c_set_tx_path(rtwdev, skb); @@ -3209,11 +3327,11 @@ int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, } int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + rtwvif_link->chanctx_idx); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_h2c_bcn_upd *h2c; struct sk_buff *skb_beacon; struct ieee80211_hdr *hdr; @@ -3240,7 +3358,7 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, return -ENOMEM; } - noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data); + noa_len = rtw89_p2p_noa_fetch(rtwvif_link, &noa_data); if (noa_len && (noa_len <= skb_tailroom(skb_beacon) || pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) { @@ -3260,11 +3378,11 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_bcn_upd *)skb->data; - h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_W0_PORT) | + h2c->w0 = le32_encode_bits(rtwvif_link->port, RTW89_H2C_BCN_UPD_W0_PORT) | le32_encode_bits(0, RTW89_H2C_BCN_UPD_W0_MBSSID) | - le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) | + le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) | le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_W0_GRP_IE_OFST); - h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) | + h2c->w1 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) | le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_W1_SSN_SEL) | le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_W1_SSN_MODE) | le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_W1_RATE); @@ -3289,10 +3407,10 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon); int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_h2c_bcn_upd_be *h2c; struct sk_buff *skb_beacon; struct ieee80211_hdr *hdr; @@ -3319,7 +3437,7 @@ int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, return -ENOMEM; } - noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data); + noa_len = rtw89_p2p_noa_fetch(rtwvif_link, &noa_data); if (noa_len && (noa_len <= skb_tailroom(skb_beacon) || pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) { @@ -3339,11 +3457,11 @@ int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_bcn_upd_be *)skb->data; - h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) | + h2c->w0 = le32_encode_bits(rtwvif_link->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) | le32_encode_bits(0, RTW89_H2C_BCN_UPD_BE_W0_MBSSID) | - le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) | + le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) | le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_BE_W0_GRP_IE_OFST); - h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) | + h2c->w1 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) | le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_BE_W1_SSN_SEL) | le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_BE_W1_SSN_MODE) | le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_BE_W1_RATE); @@ -3373,22 +3491,22 @@ EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be); #define H2C_ROLE_MAINTAIN_LEN 4 int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, enum rtw89_upd_mode upd_mode) { struct sk_buff *skb; - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; u8 self_role; int ret; - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) { - if (rtwsta) + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) { + if (rtwsta_link) self_role = RTW89_SELF_ROLE_AP_CLIENT; else - self_role = rtwvif->self_role; + self_role = rtwvif_link->self_role; } else { - self_role = rtwvif->self_role; + self_role = rtwvif_link->self_role; } skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_ROLE_MAINTAIN_LEN); @@ -3400,7 +3518,7 @@ int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, SET_FWROLE_MAINTAIN_MACID(skb->data, mac_id); SET_FWROLE_MAINTAIN_SELF_ROLE(skb->data, self_role); SET_FWROLE_MAINTAIN_UPD_MODE(skb->data, upd_mode); - SET_FWROLE_MAINTAIN_WIFI_ROLE(skb->data, rtwvif->wifi_role); + SET_FWROLE_MAINTAIN_WIFI_ROLE(skb->data, rtwvif_link->wifi_role); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT, @@ -3421,39 +3539,53 @@ int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, } static enum rtw89_fw_sta_type -rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) +rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf; + struct ieee80211_link_sta *link_sta; + enum rtw89_fw_sta_type type; - if (!sta) + rcu_read_lock(); + + if (!rtwsta_link) goto by_vif; - if (sta->deflink.eht_cap.has_eht) - return RTW89_FW_BE_STA; - else if (sta->deflink.he_cap.has_he) - return RTW89_FW_AX_STA; + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->eht_cap.has_eht) + type = RTW89_FW_BE_STA; + else if (link_sta->he_cap.has_he) + type = RTW89_FW_AX_STA; else - return RTW89_FW_N_AC_STA; + type = RTW89_FW_N_AC_STA; + + goto out; by_vif: - if (vif->bss_conf.eht_support) - return RTW89_FW_BE_STA; - else if (vif->bss_conf.he_support) - return RTW89_FW_AX_STA; + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + + if (bss_conf->eht_support) + type = RTW89_FW_BE_STA; + else if (bss_conf->he_support) + type = RTW89_FW_AX_STA; else - return RTW89_FW_N_AC_STA; + type = RTW89_FW_N_AC_STA; + +out: + rcu_read_unlock(); + + return type; } -int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, bool dis_conn) +int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool dis_conn) { struct sk_buff *skb; - u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; - u8 self_role = rtwvif->self_role; + u8 mac_id = rtwsta_link ? rtwsta_link->mac_id : rtwvif_link->mac_id; + u8 self_role = rtwvif_link->self_role; enum rtw89_fw_sta_type sta_type; - u8 net_type = rtwvif->net_type; + u8 net_type = rtwvif_link->net_type; struct rtw89_h2c_join_v1 *h2c_v1; struct rtw89_h2c_join *h2c; u32 len = sizeof(*h2c); @@ -3465,7 +3597,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, format_v1 = true; } - if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta) { + if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta_link) { self_role = RTW89_SELF_ROLE_AP_CLIENT; net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type; } @@ -3480,16 +3612,17 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_JOININFO_W0_MACID) | le32_encode_bits(dis_conn, RTW89_H2C_JOININFO_W0_OP) | - le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_JOININFO_W0_BAND) | - le32_encode_bits(rtwvif->wmm, RTW89_H2C_JOININFO_W0_WMM) | - le32_encode_bits(rtwvif->trigger, RTW89_H2C_JOININFO_W0_TGR) | + le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_JOININFO_W0_BAND) | + le32_encode_bits(rtwvif_link->wmm, RTW89_H2C_JOININFO_W0_WMM) | + le32_encode_bits(rtwvif_link->trigger, RTW89_H2C_JOININFO_W0_TGR) | le32_encode_bits(0, RTW89_H2C_JOININFO_W0_ISHESTA) | le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DLBW) | le32_encode_bits(0, RTW89_H2C_JOININFO_W0_TF_MAC_PAD) | le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DL_T_PE) | - le32_encode_bits(rtwvif->port, RTW89_H2C_JOININFO_W0_PORT_ID) | + le32_encode_bits(rtwvif_link->port, RTW89_H2C_JOININFO_W0_PORT_ID) | le32_encode_bits(net_type, RTW89_H2C_JOININFO_W0_NET_TYPE) | - le32_encode_bits(rtwvif->wifi_role, RTW89_H2C_JOININFO_W0_WIFI_ROLE) | + le32_encode_bits(rtwvif_link->wifi_role, + RTW89_H2C_JOININFO_W0_WIFI_ROLE) | le32_encode_bits(self_role, RTW89_H2C_JOININFO_W0_SELF_ROLE); if (!format_v1) @@ -3497,7 +3630,7 @@ int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, h2c_v1 = (struct rtw89_h2c_join_v1 *)skb->data; - sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif, rtwsta); + sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif_link, rtwsta_link); h2c_v1->w1 = le32_encode_bits(sta_type, RTW89_H2C_JOININFO_W1_STA_TYPE); h2c_v1->w2 = 0; @@ -3618,7 +3751,7 @@ int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, } #define H2C_EDCA_LEN 12 -int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u8 ac, u32 val) { struct sk_buff *skb; @@ -3631,7 +3764,7 @@ int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, } skb_put(skb, H2C_EDCA_LEN); RTW89_SET_EDCA_SEL(skb->data, 0); - RTW89_SET_EDCA_BAND(skb->data, rtwvif->mac_idx); + RTW89_SET_EDCA_BAND(skb->data, rtwvif_link->mac_idx); RTW89_SET_EDCA_WMM(skb->data, 0); RTW89_SET_EDCA_AC(skb->data, ac); RTW89_SET_EDCA_PARAM(skb->data, val); @@ -3655,7 +3788,8 @@ int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, } #define H2C_TSF32_TOGL_LEN 4 -int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool en) { struct sk_buff *skb; @@ -3671,9 +3805,9 @@ int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif skb_put(skb, H2C_TSF32_TOGL_LEN); cmd = skb->data; - RTW89_SET_FWCMD_TSF32_TOGL_BAND(cmd, rtwvif->mac_idx); + RTW89_SET_FWCMD_TSF32_TOGL_BAND(cmd, rtwvif_link->mac_idx); RTW89_SET_FWCMD_TSF32_TOGL_EN(cmd, en); - RTW89_SET_FWCMD_TSF32_TOGL_PORT(cmd, rtwvif->port); + RTW89_SET_FWCMD_TSF32_TOGL_PORT(cmd, rtwvif_link->port); RTW89_SET_FWCMD_TSF32_TOGL_EARLY(cmd, early_us); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -3726,12 +3860,57 @@ int rtw89_fw_h2c_set_ofld_cfg(struct rtw89_dev *rtwdev) return ret; } +int rtw89_fw_h2c_tx_duty(struct rtw89_dev *rtwdev, u8 lv) +{ + struct rtw89_h2c_tx_duty *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 pause, active; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c tx duty\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_tx_duty *)skb->data; + + static_assert(RTW89_THERMAL_PROT_LV_MAX * RTW89_THERMAL_PROT_STEP < 100); + + if (lv == 0 || lv > RTW89_THERMAL_PROT_LV_MAX) { + h2c->w1 = le32_encode_bits(1, RTW89_H2C_TX_DUTY_W1_STOP); + } else { + active = 100 - lv * RTW89_THERMAL_PROT_STEP; + pause = 100 - active; + + h2c->w0 = le32_encode_bits(pause, RTW89_H2C_TX_DUTY_W0_PAUSE_INTVL_MASK) | + le32_encode_bits(active, RTW89_H2C_TX_DUTY_W0_TX_INTVL_MASK); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, + H2C_FUNC_TX_DUTY, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, + struct rtw89_vif_link *rtwvif_link, bool connect) { - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); - struct ieee80211_bss_conf *bss_conf = vif ? &vif->bss_conf : NULL; + struct ieee80211_bss_conf *bss_conf; s32 thold = RTW89_DEFAULT_CQM_THOLD; u32 hyst = RTW89_DEFAULT_CQM_HYST; struct rtw89_h2c_bcnfltr *h2c; @@ -3742,9 +3921,20 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, if (!RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) return -EINVAL; - if (!rtwvif || !bss_conf || rtwvif->net_type != RTW89_NET_TYPE_INFRA) + if (!rtwvif_link || rtwvif_link->net_type != RTW89_NET_TYPE_INFRA) return -EINVAL; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, false); + + if (bss_conf->cqm_rssi_hyst) + hyst = bss_conf->cqm_rssi_hyst; + if (bss_conf->cqm_rssi_thold) + thold = bss_conf->cqm_rssi_thold; + + rcu_read_unlock(); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c bcn filter\n"); @@ -3754,11 +3944,6 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_bcnfltr *)skb->data; - if (bss_conf->cqm_rssi_hyst) - hyst = bss_conf->cqm_rssi_hyst; - if (bss_conf->cqm_rssi_thold) - thold = bss_conf->cqm_rssi_thold; - h2c->w0 = le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_RSSI) | le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_BCN) | le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_EN) | @@ -3768,7 +3953,7 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, le32_encode_bits(hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) | le32_encode_bits(thold + MAX_RSSI, RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD) | - le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID); + le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, @@ -3833,15 +4018,16 @@ int rtw89_fw_h2c_rssi_offload(struct rtw89_dev *rtwdev, return ret; } -int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_traffic_stats *stats = &rtwvif->stats; struct rtw89_h2c_ofld *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - if (rtwvif->net_type != RTW89_NET_TYPE_INFRA) + if (rtwvif_link->net_type != RTW89_NET_TYPE_INFRA) return -EINVAL; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); @@ -3853,7 +4039,7 @@ int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) skb_put(skb, len); h2c = (struct rtw89_h2c_ofld *)skb->data; - h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_OFLD_W0_MAC_ID) | + h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_OFLD_W0_MAC_ID) | le32_encode_bits(stats->tx_throughput, RTW89_H2C_OFLD_W0_TX_TP) | le32_encode_bits(stats->rx_throughput, RTW89_H2C_OFLD_W0_RX_TP); @@ -4688,6 +4874,7 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, return 0; } +static int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, struct list_head *chan_list) { @@ -4759,8 +4946,10 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, return 0; } +static int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, - struct list_head *chan_list) + struct list_head *chan_list, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_h2c_chinfo_elem_be *elem; @@ -4785,7 +4974,8 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, h2c->ch_num = ch_num; h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */ - h2c->arg = u8_encode_bits(RTW89_PHY_0, RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK); + h2c->arg = u8_encode_bits(rtwvif_link->mac_idx, + RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK); list_for_each_entry(ch_info, chan_list, list) { elem = (struct rtw89_h2c_chinfo_elem_be *)skb_put(skb, sizeof(*elem)); @@ -4858,7 +5048,7 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, #define RTW89_SCAN_DELAY_TSF_UNIT 104800 int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool wowlan) { struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; @@ -4880,19 +5070,19 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, h2c = (struct rtw89_h2c_scanofld *)skb->data; if (option->delay) { - ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, &tsf); + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "NLO failed to get port tsf: %d\n", ret); scan_mode = RTW89_SCAN_IMMEDIATE; } else { scan_mode = RTW89_SCAN_DELAY; - tsf += option->delay * RTW89_SCAN_DELAY_TSF_UNIT; + tsf += (u64)option->delay * RTW89_SCAN_DELAY_TSF_UNIT; } } - h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_W0_MACID) | - le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_W0_PORT_ID) | - le32_encode_bits(RTW89_PHY_0, RTW89_H2C_SCANOFLD_W0_BAND) | + h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_SCANOFLD_W0_MACID) | + le32_encode_bits(rtwvif_link->port, RTW89_H2C_SCANOFLD_W0_PORT_ID) | + le32_encode_bits(rtwvif_link->mac_idx, RTW89_H2C_SCANOFLD_W0_BAND) | le32_encode_bits(option->enable, RTW89_H2C_SCANOFLD_W0_OPERATION); h2c->w1 = le32_encode_bits(true, RTW89_H2C_SCANOFLD_W1_NOTIFY_END) | @@ -4963,9 +5153,10 @@ static void rtw89_scan_get_6g_disabled_chan(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool wowlan) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct cfg80211_scan_request *req = rtwvif->scan_req; @@ -5016,8 +5207,8 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, le32_encode_bits(option->repeat, RTW89_H2C_SCANOFLD_BE_W0_REPEAT) | le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_NOTIFY_END) | le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_LEARN_CH) | - le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_BE_W0_MACID) | - le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_BE_W0_PORT) | + le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_SCANOFLD_BE_W0_MACID) | + le32_encode_bits(rtwvif_link->port, RTW89_H2C_SCANOFLD_BE_W0_PORT) | le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_W0_BAND); h2c->w1 = le32_encode_bits(option->num_macc_role, RTW89_H2C_SCANOFLD_BE_W1_NUM_MACC_ROLE) | @@ -5082,11 +5273,11 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, for (i = 0; i < option->num_opch; i++) { opch = ptr; - opch->w0 = le32_encode_bits(rtwvif->mac_id, + opch->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) | le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) | - le32_encode_bits(rtwvif->port, + le32_encode_bits(rtwvif_link->port, RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) | le32_encode_bits(RTW89_SCAN_OPMODE_INTV, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) | @@ -5180,7 +5371,7 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_fw_h2c_rf_get_mccch *mccch; struct sk_buff *skb; int ret; @@ -5227,7 +5418,7 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; struct rtw89_fw_h2c_rfk_pre_info_v0 *h2c_v0; struct rtw89_fw_h2c_rfk_pre_info *h2c; - u8 tbl_sel = rfk_mcc->table_idx; + u8 tbl_sel[NUM_OF_RTW89_FW_RFK_PATH]; u32 len = sizeof(*h2c); struct sk_buff *skb; u8 ver = U8_MAX; @@ -5251,19 +5442,24 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, h2c->common.mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR); + BUILD_BUG_ON(ARRAY_SIZE(rfk_mcc->data) < NUM_OF_RTW89_FW_RFK_PATH); for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) { for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { h2c->common.dbcc.ch[path][tbl] = - cpu_to_le32(rfk_mcc->ch[tbl]); + cpu_to_le32(rfk_mcc->data[path].ch[tbl]); h2c->common.dbcc.band[path][tbl] = - cpu_to_le32(rfk_mcc->band[tbl]); + cpu_to_le32(rfk_mcc->data[path].band[tbl]); } } for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) { - h2c->common.tbl.cur_ch[path] = cpu_to_le32(rfk_mcc->ch[tbl_sel]); - h2c->common.tbl.cur_band[path] = cpu_to_le32(rfk_mcc->band[tbl_sel]); + tbl_sel[path] = rfk_mcc->data[path].table_idx; + + h2c->common.tbl.cur_ch[path] = + cpu_to_le32(rfk_mcc->data[path].ch[tbl_sel[path]]); + h2c->common.tbl.cur_band[path] = + cpu_to_le32(rfk_mcc->data[path].band[tbl_sel[path]]); } h2c->common.phy_idx = cpu_to_le32(phy_idx); @@ -5271,9 +5467,9 @@ int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, if (ver == 0) { /* RFK_PRE_NOTIFY_V0 */ h2c_v0 = (struct rtw89_fw_h2c_rfk_pre_info_v0 *)skb->data; - h2c_v0->cur_band = cpu_to_le32(rfk_mcc->band[tbl_sel]); - h2c_v0->cur_bw = cpu_to_le32(rfk_mcc->bw[tbl_sel]); - h2c_v0->cur_center_ch = cpu_to_le32(rfk_mcc->ch[tbl_sel]); + h2c_v0->cur_band = cpu_to_le32(rfk_mcc->data[0].band[tbl_sel[0]]); + h2c_v0->cur_bw = cpu_to_le32(rfk_mcc->data[0].bw[tbl_sel[0]]); + h2c_v0->cur_center_ch = cpu_to_le32(rfk_mcc->data[0].ch[tbl_sel[0]]); val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1); h2c_v0->ktbl_sel0 = cpu_to_le32(val32); @@ -5518,30 +5714,44 @@ int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, } int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, - const struct rtw89_chan *chan) + const struct rtw89_chan *chan, bool is_chl_k) { + struct rtw89_h2c_rf_rxdck_v0 *v0; struct rtw89_h2c_rf_rxdck *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; + int ver = -1; int ret; + if (RTW89_CHK_FW_FEATURE(RFK_RXDCK_V0, &rtwdev->fw)) { + len = sizeof(*v0); + ver = 0; + } + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c RF RXDCK\n"); return -ENOMEM; } skb_put(skb, len); - h2c = (struct rtw89_h2c_rf_rxdck *)skb->data; + v0 = (struct rtw89_h2c_rf_rxdck_v0 *)skb->data; + + v0->len = len; + v0->phy = phy_idx; + v0->is_afe = false; + v0->kpath = RF_AB; + v0->cur_band = chan->band_type; + v0->cur_bw = chan->band_width; + v0->cur_ch = chan->channel; + v0->rxdck_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK); + + if (ver == 0) + goto hdr; - h2c->len = len; - h2c->phy = phy_idx; - h2c->is_afe = false; - h2c->kpath = RF_AB; - h2c->cur_band = chan->band_type; - h2c->cur_bw = chan->band_width; - h2c->cur_ch = chan->channel; - h2c->rxdck_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK); + h2c = (struct rtw89_h2c_rf_rxdck *)skb->data; + h2c->is_chl_k = is_chl_k; +hdr: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, H2C_FUNC_RFK_RXDCK_OFFLOAD, 0, 0, len); @@ -5871,12 +6081,10 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev) } static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct cfg80211_scan_request *req, struct rtw89_pktofld_info *info, enum nl80211_band band, u8 ssid_idx) { - struct cfg80211_scan_request *req = rtwvif->scan_req; - if (band != NL80211_BAND_6GHZ) return false; @@ -5892,11 +6100,13 @@ static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev, } static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct sk_buff *skb, u8 ssid_idx) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct ieee80211_scan_ies *ies = rtwvif->scan_ies; + struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_pktofld_info *info; struct sk_buff *new; int ret = 0; @@ -5921,8 +6131,7 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev, goto out; } - rtw89_is_6ghz_wildcard_probe_req(rtwdev, rtwvif, info, band, - ssid_idx); + rtw89_is_6ghz_wildcard_probe_req(rtwdev, req, info, band, ssid_idx); ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new); if (ret) { @@ -5939,22 +6148,23 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev, } static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct sk_buff *skb; u8 num = req->n_ssids, i; int ret; for (i = 0; i < num; i++) { - skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr, + skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, req->ssids[i].ssid, req->ssids[i].ssid_len, req->ie_len); if (!skb) return -ENOMEM; - ret = rtw89_append_probe_req_ie(rtwdev, rtwvif, skb, i); + ret = rtw89_append_probe_req_ie(rtwdev, rtwvif_link, skb, i); kfree_skb(skb); if (ret) @@ -5965,13 +6175,12 @@ static int rtw89_hw_scan_update_probe_req(struct rtw89_dev *rtwdev, } static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev, + struct ieee80211_scan_ies *ies, struct cfg80211_scan_request *req, struct rtw89_mac_chinfo *ch_info) { - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; struct list_head *pkt_list = rtwdev->scan_info.pkt_list; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); - struct ieee80211_scan_ies *ies = rtwvif->scan_ies; struct cfg80211_scan_6ghz_params *params; struct rtw89_pktofld_info *info, *tmp; struct ieee80211_hdr *hdr; @@ -6000,8 +6209,11 @@ static int rtw89_update_6ghz_rnr_chan(struct rtw89_dev *rtwdev, if (found) continue; - skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr, + skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, NULL, 0, req->ie_len); + if (!skb) + return -ENOMEM; + skb_put_data(skb, ies->ies[NL80211_BAND_6GHZ], ies->len[NL80211_BAND_6GHZ]); skb_put_data(skb, ies->common_ies, ies->common_ie_len); hdr = (struct ieee80211_hdr *)skb->data; @@ -6090,8 +6302,9 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, struct rtw89_mac_chinfo *ch_info) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct ieee80211_scan_ies *ies = rtwvif->scan_ies; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_chan *op = &rtwdev->scan_info.op_chan; struct rtw89_pktofld_info *info; @@ -6117,7 +6330,7 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, } } - ret = rtw89_update_6ghz_rnr_chan(rtwdev, req, ch_info); + ret = rtw89_update_6ghz_rnr_chan(rtwdev, ies, req, ch_info); if (ret) rtw89_warn(rtwdev, "RNR fails: %d\n", ret); @@ -6155,8 +6368,10 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type, ch_info->period = max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME); ch_info->dwell_time = RTW89_DWELL_TIME; + ch_info->pause_data = true; break; case RTW89_CHAN_ACTIVE: + ch_info->pause_data = true; break; default: rtw89_err(rtwdev, "Channel type out of bound\n"); @@ -6207,8 +6422,8 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, struct rtw89_mac_chinfo_be *ch_info) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_pktofld_info *info; u8 band, probe_count = 0, i; @@ -6255,8 +6470,10 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, ch_info->period = max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME); ch_info->dwell_time = RTW89_DWELL_TIME; + ch_info->pause_data = true; break; case RTW89_CHAN_ACTIVE: + ch_info->pause_data = true; break; default: rtw89_warn(rtwdev, "Channel type out of bound\n"); @@ -6265,7 +6482,7 @@ static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, } int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; @@ -6315,8 +6532,9 @@ int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, } int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected) + struct rtw89_vif_link *rtwvif_link, bool connected) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_mac_chinfo *ch_info, *tmp; struct ieee80211_channel *channel; @@ -6392,7 +6610,7 @@ int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, } int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; @@ -6432,7 +6650,8 @@ int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev, list_add_tail(&ch_info->list, &chan_list); } - ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list); + ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list, + rtwvif_link); out: list_for_each_entry_safe(ch_info, tmp, &chan_list, list) { @@ -6444,8 +6663,9 @@ int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev, } int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected) + struct rtw89_vif_link *rtwvif_link, bool connected) { + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_mac_chinfo_be *ch_info, *tmp; struct ieee80211_channel *channel; @@ -6491,7 +6711,8 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, } rtwdev->scan_info.last_chan_idx = idx; - ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list); + ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list, + rtwvif_link); out: list_for_each_entry_safe(ch_info, tmp, &chan_list, list) { @@ -6503,79 +6724,88 @@ int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, } static int rtw89_hw_scan_prehandle(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected) + struct rtw89_vif_link *rtwvif_link, bool connected) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; int ret; - ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif); + ret = rtw89_hw_scan_update_probe_req(rtwdev, rtwvif_link); if (ret) { rtw89_err(rtwdev, "Update probe request failed\n"); goto out; } - ret = mac->add_chan_list(rtwdev, rtwvif, connected); + ret = mac->add_chan_list(rtwdev, rtwvif_link, connected); out: return ret; } -void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, struct ieee80211_scan_request *scan_req) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct cfg80211_scan_request *req = &scan_req->req; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, + rtwvif_link->chanctx_idx); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; u32 rx_fltr = rtwdev->hal.rx_fltr; u8 mac_addr[ETH_ALEN]; + u32 reg; + + /* clone op and keep it during scan */ + rtwdev->scan_info.op_chan = *chan; - rtw89_get_channel(rtwdev, rtwvif, &rtwdev->scan_info.op_chan); - rtwdev->scan_info.scanning_vif = vif; + rtwdev->scan_info.scanning_vif = rtwvif_link; rtwdev->scan_info.last_chan_idx = 0; rtwdev->scan_info.abort = false; rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_req = req; ieee80211_stop_queues(rtwdev->hw); - rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, false); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, false); if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) get_random_mask_addr(mac_addr, req->mac_addr, req->mac_addr_mask); else - ether_addr_copy(mac_addr, vif->addr); - rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, true); + ether_addr_copy(mac_addr, rtwvif_link->mac_addr); + rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, true); rx_fltr &= ~B_AX_A_BCN_CHK_EN; rx_fltr &= ~B_AX_A_BC; rx_fltr &= ~B_AX_A_A1_MATCH; - rtw89_write32_mask(rtwdev, - rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), - B_AX_RX_FLTR_CFG_MASK, - rx_fltr); + + reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rx_fltr); rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_HW_SCAN); } -void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool aborted) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct cfg80211_scan_info info = { .aborted = aborted, }; + struct rtw89_vif *rtwvif; + u32 reg; - if (!vif) + if (!rtwvif_link) return; - rtw89_write32_mask(rtwdev, - rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), - B_AX_RX_FLTR_CFG_MASK, - rtwdev->hal.rx_fltr); + rtw89_chanctx_proceed(rtwdev); + + rtwvif = rtwvif_link->rtwvif; - rtw89_core_scan_complete(rtwdev, vif, true); + reg = rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, rtwvif_link->mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rtwdev->hal.rx_fltr); + + rtw89_core_scan_complete(rtwdev, rtwvif_link, true); ieee80211_scan_completed(rtwdev->hw, &info); ieee80211_wake_queues(rtwdev->hw); - rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, true); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, true); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); rtw89_release_pkt_list(rtwdev); @@ -6584,18 +6814,17 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, scan_info->last_chan_idx = 0; scan_info->scanning_vif = NULL; scan_info->abort = false; - - rtw89_chanctx_proceed(rtwdev); } -void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; int ret; scan_info->abort = true; - ret = rtw89_hw_scan_offload(rtwdev, vif, false); + ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, false); if (ret) rtw89_warn(rtwdev, "rtw89_hw_scan_offload failed ret %d\n", ret); @@ -6604,40 +6833,43 @@ void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) * RTW89_SCAN_END_SCAN_NOTIFY, so that ieee80211_stop() can flush scan * work properly. */ - rtw89_hw_scan_complete(rtwdev, vif, true); + rtw89_hw_scan_complete(rtwdev, rtwvif_link, true); } static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; rtw89_for_each_rtwvif(rtwdev, rtwvif) { - /* This variable implies connected or during attempt to connect */ - if (!is_zero_ether_addr(rtwvif->bssid)) - return true; + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + /* This variable implies connected or during attempt to connect */ + if (!is_zero_ether_addr(rtwvif_link->bssid)) + return true; + } } return false; } -int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_scan_option opt = {0}; - struct rtw89_vif *rtwvif; bool connected; int ret = 0; - rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL; - if (!rtwvif) + if (!rtwvif_link) return -EINVAL; connected = rtw89_is_any_vif_connected_or_connecting(rtwdev); opt.enable = enable; opt.target_ch_mode = connected; if (enable) { - ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif, connected); + ret = rtw89_hw_scan_prehandle(rtwdev, rtwvif_link, connected); if (ret) goto out; } @@ -6645,14 +6877,14 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { opt.operation = enable ? RTW89_SCAN_OP_START : RTW89_SCAN_OP_STOP; opt.scan_mode = RTW89_SCAN_MODE_SA; - opt.band = RTW89_PHY_0; + opt.band = rtwvif_link->mac_idx; opt.num_macc_role = 0; opt.mlo_mode = rtwdev->mlo_dbcc_mode; opt.num_opch = connected ? 1 : 0; opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; } - ret = mac->scan_offload(rtwdev, &opt, rtwvif, false); + ret = mac->scan_offload(rtwdev, &opt, rtwvif_link, false); out: return ret; } @@ -6758,7 +6990,7 @@ int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, } #define H2C_KEEP_ALIVE_LEN 4 -int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct sk_buff *skb; @@ -6766,7 +6998,7 @@ int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, int ret; if (enable) { - ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id); if (ret) @@ -6784,7 +7016,7 @@ int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, RTW89_SET_KEEP_ALIVE_ENABLE(skb->data, enable); RTW89_SET_KEEP_ALIVE_PKT_NULL_ID(skb->data, pkt_id); RTW89_SET_KEEP_ALIVE_PERIOD(skb->data, 5); - RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif->mac_id); + RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif_link->mac_id); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, @@ -6806,7 +7038,7 @@ int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, return ret; } -int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_h2c_arp_offload *h2c; @@ -6816,7 +7048,7 @@ int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, int ret; if (enable) { - ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_ARP_RSP, &pkt_id); if (ret) @@ -6834,7 +7066,7 @@ int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, h2c->w0 = le32_encode_bits(enable, RTW89_H2C_ARP_OFFLOAD_W0_ENABLE) | le32_encode_bits(0, RTW89_H2C_ARP_OFFLOAD_W0_ACTION) | - le32_encode_bits(rtwvif->mac_id, RTW89_H2C_ARP_OFFLOAD_W0_MACID) | + le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_ARP_OFFLOAD_W0_MACID) | le32_encode_bits(pkt_id, RTW89_H2C_ARP_OFFLOAD_W0_PKT_ID); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, @@ -6859,11 +7091,11 @@ int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, #define H2C_DISCONNECT_DETECT_LEN 8 int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable) + struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct sk_buff *skb; - u8 macid = rtwvif->mac_id; + u8 macid = rtwvif_link->mac_id; int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DISCONNECT_DETECT_LEN); @@ -6902,7 +7134,7 @@ int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, return ret; } -int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; @@ -6923,7 +7155,7 @@ int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, h2c->w0 = le32_encode_bits(enable, RTW89_H2C_NLO_W0_ENABLE) | le32_encode_bits(enable, RTW89_H2C_NLO_W0_IGNORE_CIPHER) | - le32_encode_bits(rtwvif->mac_id, RTW89_H2C_NLO_W0_MACID); + le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_NLO_W0_MACID); if (enable) { h2c->nlo_cnt = nd_config->n_match_sets; @@ -6953,12 +7185,12 @@ int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, return ret; } -int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_h2c_wow_global *h2c; - u8 macid = rtwvif->mac_id; + u8 macid = rtwvif_link->mac_id; u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; @@ -7002,12 +7234,12 @@ int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, #define H2C_WAKEUP_CTRL_LEN 4 int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct sk_buff *skb; - u8 macid = rtwvif->mac_id; + u8 macid = rtwvif_link->mac_id; int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WAKEUP_CTRL_LEN); @@ -7100,13 +7332,13 @@ int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, } int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_gtk_info *gtk_info = &rtw_wow->gtk_info; struct rtw89_h2c_wow_gtk_ofld *h2c; - u8 macid = rtwvif->mac_id; + u8 macid = rtwvif_link->mac_id; u32 len = sizeof(*h2c); u8 pkt_id_sa_query = 0; struct sk_buff *skb; @@ -7128,14 +7360,14 @@ int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, if (!enable) goto hdr; - ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_EAPOL_KEY, &pkt_id_eapol); if (ret) goto fail; if (gtk_info->igtk_keyid) { - ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif, + ret = rtw89_fw_h2c_add_general_pkt(rtwdev, rtwvif_link, RTW89_PKT_OFLD_TYPE_SA_QUERY, &pkt_id_sa_query); if (ret) @@ -7173,7 +7405,7 @@ int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, return ret; } -int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable) { struct rtw89_wait_info *wait = &rtwdev->mac.ps_wait; @@ -7189,7 +7421,7 @@ int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, skb_put(skb, len); h2c = (struct rtw89_h2c_fwips *)skb->data; - h2c->w0 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_FW_IPS_W0_MACID) | + h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_FW_IPS_W0_MACID) | le32_encode_bits(enable, RTW89_H2C_FW_IPS_W0_ENABLE); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index ad47e77d740b25..efa63d44482106 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -261,6 +261,7 @@ struct rtw89_fw_hdr_section_info { u8 redl; const u8 *addr; u32 len; + u32 len_override; u32 dladdr; u32 mssc; u8 type; @@ -275,6 +276,7 @@ struct rtw89_fw_bin_info { u32 hdr_len; bool dynamic_hdr_en; u32 dynamic_hdr_len; + u8 idmem_share_mode; bool dsp_checksum; bool secure_section_exist; struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM]; @@ -563,6 +565,7 @@ struct rtw89_fw_hdr { #define FW_HDR_W6_SEC_NUM GENMASK(15, 8) #define FW_HDR_W7_PART_SIZE GENMASK(15, 0) #define FW_HDR_W7_DYN_HDR BIT(16) +#define FW_HDR_W7_IDMEM_SHARE_MODE GENMASK(21, 18) #define FW_HDR_W7_CMD_VERSERION GENMASK(31, 24) struct rtw89_fw_hdr_section_v1 { @@ -580,6 +583,7 @@ struct rtw89_fw_hdr_section_v1 { #define FWSECTION_HDR_V1_W1_REDL BIT(29) #define FWSECTION_HDR_V1_W2_MSSC GENMASK(7, 0) #define FORMATTED_MSSC 0xFF +#define FORMATTED_MSSC_MASK GENMASK(7, 0) #define FWSECTION_HDR_V1_W2_BBMCU_IDX GENMASK(27, 24) struct rtw89_fw_hdr_v1 { @@ -615,6 +619,7 @@ struct rtw89_fw_hdr_v1 { #define FW_HDR_V1_W6_DSP_CHKSUM BIT(24) #define FW_HDR_V1_W7_PART_SIZE GENMASK(15, 0) #define FW_HDR_V1_W7_DYN_HDR BIT(16) +#define FW_HDR_V1_W7_IDMEM_SHARE_MODE GENMASK(21, 18) enum rtw89_fw_mss_pool_rmp_tbl_type { MSS_POOL_RMP_TBL_BITMASK = 0x0, @@ -3689,6 +3694,13 @@ struct rtw89_c2h_pkt_ofld_rsp { #define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_OP GENMASK(10, 8) #define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_LEN GENMASK(31, 16) +struct rtw89_c2h_tx_duty_rpt { + struct rtw89_c2h_hdr c2h_hdr; + __le32 w2; +} __packed; + +#define RTW89_C2H_TX_DUTY_RPT_W2_TIMER_ERR GENMASK(2, 0) + struct rtw89_c2h_wow_aoac_report { struct rtw89_c2h_hdr c2h_hdr; u8 rpt_ver; @@ -3713,6 +3725,15 @@ struct rtw89_c2h_wow_aoac_report { #define RTW89_C2H_WOW_AOAC_RPT_REKEY_IDX BIT(0) +struct rtw89_h2c_tx_duty { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_TX_DUTY_W0_PAUSE_INTVL_MASK GENMASK(15, 0) +#define RTW89_H2C_TX_DUTY_W0_TX_INTVL_MASK GENMASK(31, 16) +#define RTW89_H2C_TX_DUTY_W1_STOP BIT(0) + struct rtw89_h2c_bcnfltr { __le32 w0; } __packed; @@ -4071,6 +4092,7 @@ enum rtw89_fw_ofld_h2c_func { H2C_FUNC_OFLD_CFG = 0x14, H2C_FUNC_ADD_SCANOFLD_CH = 0x16, H2C_FUNC_SCANOFLD = 0x17, + H2C_FUNC_TX_DUTY = 0x18, H2C_FUNC_PKT_DROP = 0x1b, H2C_FUNC_CFG_BCNFLTR = 0x1e, H2C_FUNC_OFLD_RSSI = 0x1f, @@ -4286,7 +4308,7 @@ struct rtw89_h2c_rf_dack { __le32 type; } __packed; -struct rtw89_h2c_rf_rxdck { +struct rtw89_h2c_rf_rxdck_v0 { u8 len; u8 phy; u8 is_afe; @@ -4297,6 +4319,11 @@ struct rtw89_h2c_rf_rxdck { u8 rxdck_dbg_en; } __packed; +struct rtw89_h2c_rf_rxdck { + struct rtw89_h2c_rf_rxdck_v0 v0; + u8 is_chl_k; +} __packed; + enum rtw89_rf_log_type { RTW89_RF_RUN_LOG = 0, RTW89_RF_RPT_LOG = 1, @@ -4313,6 +4340,42 @@ struct rtw89_c2h_rf_run_log { __le32 arg[4]; } __packed; +struct rtw89_c2h_rf_iqk_rpt_log { + bool iqk_tx_fail[2]; + bool iqk_rx_fail[2]; + bool is_iqk_init; + bool is_reload; + bool is_wb_txiqk[2]; + bool is_wb_rxiqk[2]; + bool is_nbiqk; + bool txiqk_en; + bool rxiqk_en; + bool lok_en; + bool iqk_xym_en; + bool iqk_sram_en; + bool iqk_fft_en; + bool is_fw_iqk; + bool is_iqk_enable; + bool iqk_cfir_en; + bool thermal_rek_en; + u8 iqk_band[2]; + u8 iqk_ch[2]; + u8 iqk_bw[2]; + u8 iqk_times; + u8 version; + u8 phy; + u8 fwk_status; + u8 rsvd; + __le32 reload_cnt; + __le32 iqk_fail_cnt; + __le32 lok_idac[2]; + __le32 lok_vbuf[2]; + __le32 rftxgain[2][4]; + __le32 rfrxgain[2][4]; + __le32 tx_xym[2][4]; + __le32 rx_xym[2][4]; +} __packed; + struct rtw89_c2h_rf_dpk_rpt_log { u8 ver; u8 idx[2]; @@ -4334,19 +4397,25 @@ struct rtw89_c2h_rf_dpk_rpt_log { struct rtw89_c2h_rf_dack_rpt_log { u8 fwdack_ver; - u8 fwdack_rpt_ver; + u8 fwdack_info_ver; u8 msbk_d[2][2][16]; u8 dadck_d[2][2]; u8 cdack_d[2][2][2]; - __le16 addck2_d[2][2][2]; + u8 addck2_hd[2][2][2]; + u8 addck2_ld[2][2][2]; u8 adgaink_d[2][2]; - __le16 biask_d[2][2]; + u8 biask_hd[2][2]; + u8 biask_ld[2][2]; u8 addck_timeout; u8 cdack_timeout; u8 dadck_timeout; u8 msbk_timeout; u8 adgaink_timeout; + u8 wbadcdck_timeout; + u8 drck_timeout; u8 dack_fail; + u8 wbdck_d[2]; + u8 rck_d; } __packed; struct rtw89_c2h_rf_rxdck_rpt_log { @@ -4357,6 +4426,14 @@ struct rtw89_c2h_rf_rxdck_rpt_log { u8 timeout[2]; } __packed; +struct rtw89_c2h_rf_tssi_rpt_log { + s8 alignment_power[2][2][4]; + u8 alignment_power_cw_h[2][2][4]; + u8 alignment_power_cw_l[2][2][4]; + u8 tssi_alimk_state[2][2]; + u8 default_txagc_offset[2][2]; +} __packed; + struct rtw89_c2h_rf_txgapk_rpt_log { __le32 r0x8010[2]; __le32 chk_cnt; @@ -4404,59 +4481,60 @@ void rtw89_h2c_pkt_set_hdr(struct rtw89_dev *rtwdev, struct sk_buff *skb, u8 type, u8 cat, u8 class, u8 func, bool rack, bool dack, u32 len); int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta); + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta); + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); -int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif, - struct rtw89_sta *rtwsta, const u8 *scan_mac_addr); + struct rtw89_vif_link *rtwvif_link); +int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif, + struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr); int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta); + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct work_struct *work); int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, enum rtw89_upd_mode upd_mode); -int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta, bool dis_conn); +int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool dis_conn); int rtw89_fw_h2c_notify_dbcc(struct rtw89_dev *rtwdev, bool en); int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, bool pause); -int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u8 ac, u32 val); int rtw89_fw_h2c_set_ofld_cfg(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_tx_duty(struct rtw89_dev *rtwdev, u8 lv); int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, + struct rtw89_vif_link *rtwvif_link, bool connect); int rtw89_fw_h2c_rssi_offload(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu); -int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +int rtw89_fw_h2c_tp_offload(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_ra(struct rtw89_dev *rtwdev, struct rtw89_ra_info *ra, bool csi); int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type); @@ -4472,17 +4550,13 @@ int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id); int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, struct sk_buff *skb_ofld); -int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, - struct list_head *chan_list); -int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, - struct list_head *chan_list); int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, struct rtw89_scan_option *opt, - struct rtw89_vif *vif, + struct rtw89_vif_link *vif, bool wowlan); int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, struct rtw89_scan_option *opt, - struct rtw89_vif *vif, + struct rtw89_vif_link *vif, bool wowlan); int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, @@ -4501,21 +4575,26 @@ int rtw89_fw_h2c_rf_txgapk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan); int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, - const struct rtw89_chan *chan); + const struct rtw89_chan *chan, bool is_chl_k); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack); int rtw89_fw_h2c_raw(struct rtw89_dev *rtwdev, const u8 *buf, u16 len); void rtw89_fw_send_all_early_h2c(struct rtw89_dev *rtwdev); void rtw89_fw_free_all_early_h2c(struct rtw89_dev *rtwdev); -int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u8 macid); void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool notify_fw); + struct rtw89_vif_link *rtwvif_link, + bool notify_fw); void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw); -int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params); -int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, bool valid, struct ieee80211_ampdu_params *params); void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, @@ -4524,8 +4603,8 @@ int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param); int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); -int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link); +int rtw89_fw_h2c_fwips(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); struct sk_buff *rtw89_fw_h2c_alloc_skb_with_hdr(struct rtw89_dev *rtwdev, u32 len); struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len); @@ -4534,49 +4613,56 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev, struct rtw89_mac_c2h_info *c2h_info); int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable); void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev); -void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_scan_request *req); -void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_scan_request *scan_req); +void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool aborted); -int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool enable); -void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); int rtw89_hw_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected); + struct rtw89_vif_link *rtwvif_link, bool connected); int rtw89_pno_scan_add_chan_list_ax(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected); + struct rtw89_vif_link *rtwvif_link, bool connected); int rtw89_pno_scan_add_chan_list_be(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, const struct rtw89_pkt_drop_params *params); -int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, +int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf, struct ieee80211_p2p_noa_desc *desc, u8 act, u8 noa_id); -int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool en); -int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable); -int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable); +int rtw89_fw_h2c_cfg_pno(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); -int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_arp_offload(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable); + struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable); -int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable); +int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable); + struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, struct rtw89_wow_cam_info *cam_info); int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool enable); int rtw89_fw_h2c_wow_request_aoac(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_add_mcc(struct rtw89_dev *rtwdev, @@ -4621,51 +4707,73 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) } static inline int rtw89_chip_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; - return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); + return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); } static inline int rtw89_chip_h2c_default_dmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_sta *rtwsta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->ops->h2c_default_dmac_tbl) - return chip->ops->h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta); + return chip->ops->h2c_default_dmac_tbl(rtwdev, rtwvif_link, rtwsta_link); return 0; } static inline int rtw89_chip_h2c_update_beacon(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chip_info *chip = rtwdev->chip; - return chip->ops->h2c_update_beacon(rtwdev, rtwvif); + return chip->ops->h2c_update_beacon(rtwdev, rtwvif_link); } static inline int rtw89_chip_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; - return chip->ops->h2c_assoc_cmac_tbl(rtwdev, vif, sta); + return chip->ops->h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); } -static inline int rtw89_chip_h2c_ampdu_cmac_tbl(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +static inline +int rtw89_chip_h2c_ampdu_link_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_chip_info *chip = rtwdev->chip; if (chip->ops->h2c_ampdu_cmac_tbl) - return chip->ops->h2c_ampdu_cmac_tbl(rtwdev, vif, sta); + return chip->ops->h2c_ampdu_cmac_tbl(rtwdev, rtwvif_link, + rtwsta_link); + + return 0; +} + +static inline int rtw89_chip_h2c_ampdu_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = rtw89_chip_h2c_ampdu_link_cmac_tbl(rtwdev, rtwvif_link, + rtwsta_link); + if (ret) + return ret; + } return 0; } @@ -4675,8 +4783,20 @@ int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) { const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = chip->ops->h2c_ba_cam(rtwdev, rtwvif_link, rtwsta_link, + valid, params); + if (ret) + return ret; + } - return chip->ops->h2c_ba_cam(rtwdev, rtwsta, valid, params); + return 0; } /* must consider compatibility; don't insert new in the mid */ diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index c70a23a763b0ee..7907b84d204b39 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1444,6 +1444,7 @@ void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev) static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) { #define PWR_ACT 1 + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_pwr_cfg * const *cfg_seq; int (*cfg_func)(struct rtw89_dev *rtwdev); @@ -1472,6 +1473,9 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) return ret; if (on) { + if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) + mac->efuse_read_fw_secure(rtwdev); + set_bit(RTW89_FLAG_POWERON, rtwdev->flags); set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags); set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags); @@ -1483,7 +1487,8 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags); clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_PWR_MAJOR); - rtw89_set_entity_state(rtwdev, false); + rtw89_set_entity_state(rtwdev, RTW89_PHY_0, false); + rtw89_set_entity_state(rtwdev, RTW89_PHY_1, false); } return 0; @@ -3995,9 +4000,10 @@ int rtw89_mac_init(struct rtw89_dev *rtwdev) static void rtw89_mac_dmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid) { + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; u8 i; - if (rtwdev->chip->chip_gen != RTW89_CHIP_AX) + if (rtwdev->chip->chip_gen != RTW89_CHIP_AX || sec->secure_boot) return; for (i = 0; i < 4; i++) { @@ -4009,7 +4015,9 @@ static void rtw89_mac_dmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid) static void rtw89_mac_cmac_tbl_init(struct rtw89_dev *rtwdev, u8 macid) { - if (rtwdev->chip->chip_gen != RTW89_CHIP_AX) + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + + if (rtwdev->chip->chip_gen != RTW89_CHIP_AX || sec->secure_boot) return; rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, @@ -4076,17 +4084,17 @@ static const struct rtw89_port_reg rtw89_port_base_ax = { }; static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u8 type) + struct rtw89_vif_link *rtwvif_link, u8 type) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif->port); + u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif_link->port); u32 reg_info, reg_ctrl; u32 val; int ret; - reg_info = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg_info, rtwvif->mac_idx); - reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg, rtwvif->mac_idx); + reg_info = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg_info, rtwvif_link->mac_idx); + reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, p->ptcl_dbg, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg_ctrl, B_AX_PTCL_DBG_SEL_MASK, type); rtw89_write32_set(rtwdev, reg_ctrl, B_AX_PTCL_DBG_EN); @@ -4098,26 +4106,32 @@ static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev, rtw89_warn(rtwdev, "Polling beacon packet empty fail\n"); } -static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_set(rtwdev, p->bcn_drop_all, BIT(rtwvif->port)); - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, 1); - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, 0); - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 0); - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK, 2); - rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK, 1); - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_space, B_AX_BCN_SPACE_MASK, 1); - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); - - rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM0); - if (rtwvif->port == RTW89_PORT_0) - rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM1); - - rtw89_write32_clr(rtwdev, p->bcn_drop_all, BIT(rtwvif->port)); - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TBTT_PROHIB_EN); + rtw89_write32_set(rtwdev, p->bcn_drop_all, BIT(rtwvif_link->port)); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, + 1); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, + 0); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, + 0); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_early, B_AX_BCNERLY_MASK, 2); + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_early, + B_AX_TBTTERLY_MASK, 1); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_space, + B_AX_BCN_SPACE_MASK, 1); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_BCNTX_EN); + + rtw89_mac_check_packet_ctrl(rtwdev, rtwvif_link, AX_PTCL_DBG_BCNQ_NUM0); + if (rtwvif_link->port == RTW89_PORT_0) + rtw89_mac_check_packet_ctrl(rtwdev, rtwvif_link, AX_PTCL_DBG_BCNQ_NUM1); + + rtw89_write32_clr(rtwdev, p->bcn_drop_all, BIT(rtwvif_link->port)); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_TBTT_PROHIB_EN); fsleep(2000); } @@ -4131,286 +4145,329 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvi #define BCN_ERLY_SET_DLY (10 * 2) static void rtw89_mac_port_cfg_func_sw(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); const struct rtw89_chip_info *chip = rtwdev->chip; + struct ieee80211_bss_conf *bss_conf; bool need_backup = false; u32 backup_val; + u16 beacon_int; - if (!rtw89_read32_port_mask(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN)) + if (!rtw89_read32_port_mask(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN)) return; - if (chip->chip_id == RTL8852A && rtwvif->port != RTW89_PORT_0) { + if (chip->chip_id == RTL8852A && rtwvif_link->port != RTW89_PORT_0) { need_backup = true; - backup_val = rtw89_read32_port(rtwdev, rtwvif, p->tbtt_prohib); + backup_val = rtw89_read32_port(rtwdev, rtwvif_link, p->tbtt_prohib); } - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) - rtw89_mac_bcn_drop(rtwdev, rtwvif); + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) + rtw89_mac_bcn_drop(rtwdev, rtwvif_link); if (chip->chip_id == RTL8852A) { - rtw89_write32_port_clr(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK); - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 1); - rtw89_write16_port_clr(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK); - rtw89_write16_port_clr(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->tbtt_prohib, + B_AX_TBTT_SETUP_MASK); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, + B_AX_TBTT_HOLD_MASK, 1); + rtw89_write16_port_clr(rtwdev, rtwvif_link, p->tbtt_early, + B_AX_TBTTERLY_MASK); + rtw89_write16_port_clr(rtwdev, rtwvif_link, p->bcn_early, + B_AX_BCNERLY_MASK); } - msleep(vif->bss_conf.beacon_int + 1); - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN | + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + beacon_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + msleep(beacon_int + 1); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN | B_AX_BRK_SETUP); - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSFTR_RST); - rtw89_write32_port(rtwdev, rtwvif, p->bcn_cnt_tmr, 0); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSFTR_RST); + rtw89_write32_port(rtwdev, rtwvif_link, p->bcn_cnt_tmr, 0); if (need_backup) - rtw89_write32_port(rtwdev, rtwvif, p->tbtt_prohib, backup_val); + rtw89_write32_port(rtwdev, rtwvif_link, p->tbtt_prohib, backup_val); } static void rtw89_mac_port_cfg_tx_rpt(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TXBCN_RPT_EN); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, + B_AX_TXBCN_RPT_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TXBCN_RPT_EN); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, + B_AX_TXBCN_RPT_EN); } static void rtw89_mac_port_cfg_rx_rpt(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_RXBCN_RPT_EN); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, + B_AX_RXBCN_RPT_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_RXBCN_RPT_EN); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, + B_AX_RXBCN_RPT_EN); } static void rtw89_mac_port_cfg_net_type(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->port_cfg, B_AX_NET_TYPE_MASK, - rtwvif->net_type); + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->port_cfg, B_AX_NET_TYPE_MASK, + rtwvif_link->net_type); } static void rtw89_mac_port_cfg_bcn_prct(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - bool en = rtwvif->net_type != RTW89_NET_TYPE_NO_LINK; + bool en = rtwvif_link->net_type != RTW89_NET_TYPE_NO_LINK; u32 bits = B_AX_TBTT_PROHIB_EN | B_AX_BRK_SETUP; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, bits); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, bits); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, bits); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, bits); } static void rtw89_mac_port_cfg_rx_sw(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + bool en = rtwvif_link->net_type == RTW89_NET_TYPE_INFRA || + rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC; u32 bit = B_AX_RX_BSSID_FIT_EN; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, bit); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, bit); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, bit); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, bit); } void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSF_UDT_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_TSF_UDT_EN); } static void rtw89_mac_port_cfg_rx_sync_by_nettype(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + bool en = rtwvif_link->net_type == RTW89_NET_TYPE_INFRA || + rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC; - rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, en); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, en); } static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (en) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_BCNTX_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN); + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_BCNTX_EN); } static void rtw89_mac_port_cfg_tx_sw_by_nettype(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - bool en = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + bool en = rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || + rtwvif_link->net_type == RTW89_NET_TYPE_AD_HOC; - rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en); + rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); } void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; rtw89_for_each_rtwvif(rtwdev, rtwvif) - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) - rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) + rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); } static void rtw89_mac_port_cfg_bcn_intv(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - u16 bcn_int = vif->bss_conf.beacon_int ? vif->bss_conf.beacon_int : BCN_INTERVAL; + struct ieee80211_bss_conf *bss_conf; + u16 bcn_int; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (bss_conf->beacon_int) + bcn_int = bss_conf->beacon_int; + else + bcn_int = BCN_INTERVAL; - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_space, B_AX_BCN_SPACE_MASK, + rcu_read_unlock(); + + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_space, B_AX_BCN_SPACE_MASK, bcn_int); } static void rtw89_mac_port_cfg_hiq_win(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { - u8 win = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE ? 16 : 0; + u8 win = rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE ? 16 : 0; const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u32 reg; - reg = rtw89_mac_reg_by_idx(rtwdev, p->hiq_win[port], rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, p->hiq_win[port], rtwvif_link->mac_idx); rtw89_write8(rtwdev, reg, win); } static void rtw89_mac_port_cfg_hiq_dtim(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf; + u8 dtim_period; u32 addr; - addr = rtw89_mac_reg_by_idx(rtwdev, p->md_tsft, rtwvif->mac_idx); + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + dtim_period = bss_conf->dtim_period; + + rcu_read_unlock(); + + addr = rtw89_mac_reg_by_idx(rtwdev, p->md_tsft, rtwvif_link->mac_idx); rtw89_write8_set(rtwdev, addr, B_AX_UPD_HGQMD | B_AX_UPD_TIMIE); - rtw89_write16_port_mask(rtwdev, rtwvif, p->dtim_ctrl, B_AX_DTIM_NUM_MASK, - vif->bss_conf.dtim_period); + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->dtim_ctrl, B_AX_DTIM_NUM_MASK, + dtim_period); } static void rtw89_mac_port_cfg_bcn_setup_time(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, BCN_SETUP_DEF); } static void rtw89_mac_port_cfg_bcn_hold_time(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, BCN_HOLD_DEF); } static void rtw89_mac_port_cfg_bcn_mask_area(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_area, + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, BCN_MASK_DEF); } static void rtw89_mac_port_cfg_tbtt_early(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_early, + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_early, B_AX_TBTTERLY_MASK, TBTT_ERLY_DEF); } static void rtw89_mac_port_cfg_bss_color(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); static const u32 masks[RTW89_PORT_NUM] = { B_AX_BSS_COLOB_AX_PORT_0_MASK, B_AX_BSS_COLOB_AX_PORT_1_MASK, B_AX_BSS_COLOB_AX_PORT_2_MASK, B_AX_BSS_COLOB_AX_PORT_3_MASK, B_AX_BSS_COLOB_AX_PORT_4_MASK, }; - u8 port = rtwvif->port; + struct ieee80211_bss_conf *bss_conf; + u8 port = rtwvif_link->port; u32 reg_base; u32 reg; u8 bss_color; - bss_color = vif->bss_conf.he_bss_color.color; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + bss_color = bss_conf->he_bss_color.color; + + rcu_read_unlock(); + reg_base = port >= 4 ? p->bss_color + 4 : p->bss_color; - reg = rtw89_mac_reg_by_idx(rtwdev, reg_base, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, reg_base, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, masks[port], bss_color); } static void rtw89_mac_port_cfg_mbssid(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u32 reg; - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) return; if (port == 0) { - reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid, rtwvif_link->mac_idx); rtw89_write32_clr(rtwdev, reg, B_AX_P0MB_ALL_MASK); } } static void rtw89_mac_port_cfg_hiq_drop(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; u32 reg; u32 val; - reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid_drop, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, p->mbssid_drop, rtwvif_link->mac_idx); val = rtw89_read32(rtwdev, reg); val &= ~FIELD_PREP(B_AX_PORT_DROP_4_0_MASK, BIT(port)); if (port == 0) @@ -4419,31 +4476,31 @@ static void rtw89_mac_port_cfg_hiq_drop(struct rtw89_dev *rtwdev, } static void rtw89_mac_port_cfg_func_en(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool enable) + struct rtw89_vif_link *rtwvif_link, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; if (enable) - rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, + rtw89_write32_port_set(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN); else - rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, + rtw89_write32_port_clr(rtwdev, rtwvif_link, p->port_cfg, B_AX_PORT_FUNC_EN); } static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK, + rtw89_write32_port_mask(rtwdev, rtwvif_link, p->bcn_early, B_AX_BCNERLY_MASK, BCN_ERLY_DEF); } static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; @@ -4452,20 +4509,20 @@ static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev, if (rtwdev->chip->chip_id != RTL8852C) return; - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT && - rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION) + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION) return; val = FIELD_PREP(B_AX_TBTT_SHIFT_OFST_MAG, 1) | B_AX_TBTT_SHIFT_OFST_SIGN; - rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_shift, + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift, B_AX_TBTT_SHIFT_OFST_MASK, val); } void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_vif *rtwvif_src, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_vif_link *rtwvif_src, u16 offset_tu) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -4473,8 +4530,8 @@ void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, u32 val, reg; val = RTW89_PORT_OFFSET_TU_TO_32US(offset_tu); - reg = rtw89_mac_reg_by_idx(rtwdev, p->tsf_sync + rtwvif->port * 4, - rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, p->tsf_sync + rtwvif_link->port * 4, + rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_SRC, rtwvif_src->port); rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_OFFSET_VAL, val); @@ -4482,16 +4539,16 @@ void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, } static void rtw89_mac_port_tsf_sync_rand(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_vif *rtwvif_src, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_vif_link *rtwvif_src, u8 offset, int *n_offset) { - if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif == rtwvif_src) + if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif_link == rtwvif_src) return; /* adjust offset randomly to avoid beacon conflict */ offset = offset - offset / 4 + get_random_u32() % (offset / 2); - rtw89_mac_port_tsf_sync(rtwdev, rtwvif, rtwvif_src, + rtw89_mac_port_tsf_sync(rtwdev, rtwvif_link, rtwvif_src, (*n_offset) * offset); (*n_offset)++; @@ -4499,15 +4556,19 @@ static void rtw89_mac_port_tsf_sync_rand(struct rtw89_dev *rtwdev, static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev) { - struct rtw89_vif *src = NULL, *tmp; + struct rtw89_vif_link *src = NULL, *tmp; u8 offset = 100, vif_aps = 0; + struct rtw89_vif *rtwvif; + unsigned int link_id; int n_offset = 1; - rtw89_for_each_rtwvif(rtwdev, tmp) { - if (!src || tmp->net_type == RTW89_NET_TYPE_INFRA) - src = tmp; - if (tmp->net_type == RTW89_NET_TYPE_AP_MODE) - vif_aps++; + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + rtw89_vif_for_each_link(rtwvif, tmp, link_id) { + if (!src || tmp->net_type == RTW89_NET_TYPE_INFRA) + src = tmp; + if (tmp->net_type == RTW89_NET_TYPE_AP_MODE) + vif_aps++; + } } if (vif_aps == 0) @@ -4515,104 +4576,106 @@ static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev) offset /= (vif_aps + 1); - rtw89_for_each_rtwvif(rtwdev, tmp) - rtw89_mac_port_tsf_sync_rand(rtwdev, tmp, src, offset, &n_offset); + rtw89_for_each_rtwvif(rtwdev, rtwvif) + rtw89_vif_for_each_link(rtwvif, tmp, link_id) + rtw89_mac_port_tsf_sync_rand(rtwdev, tmp, src, offset, + &n_offset); } -int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { int ret; - ret = rtw89_mac_port_update(rtwdev, rtwvif); + ret = rtw89_mac_port_update(rtwdev, rtwvif_link); if (ret) return ret; - rtw89_mac_dmac_tbl_init(rtwdev, rtwvif->mac_id); - rtw89_mac_cmac_tbl_init(rtwdev, rtwvif->mac_id); + rtw89_mac_dmac_tbl_init(rtwdev, rtwvif_link->mac_id); + rtw89_mac_cmac_tbl_init(rtwdev, rtwvif_link->mac_id); - ret = rtw89_mac_set_macid_pause(rtwdev, rtwvif->mac_id, false); + ret = rtw89_mac_set_macid_pause(rtwdev, rtwvif_link->mac_id, false); if (ret) return ret; - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_CREATE); + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_CREATE); if (ret) return ret; - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true); if (ret) return ret; - ret = rtw89_cam_init(rtwdev, rtwvif); + ret = rtw89_cam_init(rtwdev, rtwvif_link); if (ret) return ret; - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); if (ret) return ret; - ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, NULL); + ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif_link, NULL); if (ret) return ret; - ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, NULL); + ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif_link, NULL); if (ret) return ret; return 0; } -int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { int ret; - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_REMOVE); + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_REMOVE); if (ret) return ret; - rtw89_cam_deinit(rtwdev, rtwvif); + rtw89_cam_deinit(rtwdev, rtwvif_link); - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); if (ret) return ret; return 0; } -int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - u8 port = rtwvif->port; + u8 port = rtwvif_link->port; if (port >= RTW89_PORT_NUM) return -EINVAL; - rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif); - rtw89_mac_port_cfg_tx_rpt(rtwdev, rtwvif, false); - rtw89_mac_port_cfg_rx_rpt(rtwdev, rtwvif, false); - rtw89_mac_port_cfg_net_type(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif); - rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif); - rtw89_mac_port_cfg_rx_sync_by_nettype(rtwdev, rtwvif); - rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif); - rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif); - rtw89_mac_port_cfg_hiq_dtim(rtwdev, rtwvif); - rtw89_mac_port_cfg_hiq_drop(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_setup_time(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif); - rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif); - rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif); - rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif); - rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif); - rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif); - rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, true); + rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tx_rpt(rtwdev, rtwvif_link, false); + rtw89_mac_port_cfg_rx_rpt(rtwdev, rtwvif_link, false); + rtw89_mac_port_cfg_net_type(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_rx_sync_by_nettype(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_hiq_dtim(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_hiq_drop(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_setup_time(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_func_en(rtwdev, rtwvif_link, true); rtw89_mac_port_tsf_resync_all(rtwdev); fsleep(BCN_ERLY_SET_DLY); - rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif); + rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif_link); return 0; } -int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u64 *tsf) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -4620,12 +4683,12 @@ int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 tsf_low, tsf_high; int ret; - ret = rtw89_mac_check_mac_en(rtwdev, rtwvif->mac_idx, RTW89_CMAC_SEL); + ret = rtw89_mac_check_mac_en(rtwdev, rtwvif_link->mac_idx, RTW89_CMAC_SEL); if (ret) return ret; - tsf_low = rtw89_read32_port(rtwdev, rtwvif, p->tsftr_l); - tsf_high = rtw89_read32_port(rtwdev, rtwvif, p->tsftr_h); + tsf_low = rtw89_read32_port(rtwdev, rtwvif_link, p->tsftr_l); + tsf_high = rtw89_read32_port(rtwdev, rtwvif_link, p->tsftr_h); *tsf = (u64)tsf_high << 32 | tsf_low; return 0; @@ -4651,65 +4714,57 @@ static void rtw89_mac_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy, } void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif) + struct rtw89_vif_link *rtwvif_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct ieee80211_hw *hw = rtwdev->hw; + struct ieee80211_bss_conf *bss_conf; + struct cfg80211_chan_def oper; bool tolerated = true; u32 reg; - if (!vif->bss_conf.he_support || vif->type != NL80211_IFTYPE_STATION) + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->he_support || vif->type != NL80211_IFTYPE_STATION) { + rcu_read_unlock(); return; + } - if (!(vif->bss_conf.chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR)) + oper = bss_conf->chanreq.oper; + if (!(oper.chan->flags & IEEE80211_CHAN_RADAR)) { + rcu_read_unlock(); return; + } - cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chanreq.oper, + rcu_read_unlock(); + + cfg80211_bss_iter(hw->wiphy, &oper, rtw89_mac_check_he_obss_narrow_bw_ru_iter, &tolerated); reg = rtw89_mac_reg_by_idx(rtwdev, mac->narrow_bw_ru_dis.addr, - rtwvif->mac_idx); + rtwvif_link->mac_idx); if (tolerated) rtw89_write32_clr(rtwdev, reg, mac->narrow_bw_ru_dis.mask); else rtw89_write32_set(rtwdev, reg, mac->narrow_bw_ru_dis.mask); } -void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif); + rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif_link); } -int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - int ret; - - rtwvif->mac_id = rtw89_acquire_mac_id(rtwdev); - if (rtwvif->mac_id == RTW89_MAX_MAC_ID_NUM) - return -ENOSPC; - - ret = rtw89_mac_vif_init(rtwdev, rtwvif); - if (ret) - goto release_mac_id; - - return 0; - -release_mac_id: - rtw89_release_mac_id(rtwdev, rtwvif->mac_id); - - return ret; + return rtw89_mac_vif_init(rtwdev, rtwvif_link); } -int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - int ret; - - ret = rtw89_mac_vif_deinit(rtwdev, rtwvif); - rtw89_release_mac_id(rtwdev, rtwvif->mac_id); - - return ret; + return rtw89_mac_vif_deinit(rtwdev, rtwvif_link); } static void @@ -4730,8 +4785,8 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, { const struct rtw89_c2h_scanofld *c2h = (const struct rtw89_c2h_scanofld *)skb->data; - struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); + struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + struct rtw89_vif *rtwvif; struct rtw89_chan new; u8 reason, status, tx_fail, band, actual_period, expect_period; u32 last_chan = rtwdev->scan_info.last_chan_idx, report_tsf; @@ -4739,9 +4794,11 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, u16 chan; int ret; - if (!rtwvif) + if (!rtwvif_link) return; + rtwvif = rtwvif_link->rtwvif; + tx_fail = le32_get_bits(c2h->w5, RTW89_C2H_SCANOFLD_W5_TX_FAIL); status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); chan = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_PRI_CH); @@ -4781,28 +4838,28 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (rtwdev->scan_info.abort) return; - if (rtwvif && rtwvif->scan_req && + if (rtwvif_link && rtwvif->scan_req && last_chan < rtwvif->scan_req->n_channels) { - ret = rtw89_hw_scan_offload(rtwdev, vif, true); + ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true); if (ret) { - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwvif_link); rtw89_warn(rtwdev, "HW scan failed: %d\n", ret); } } else { - rtw89_hw_scan_complete(rtwdev, vif, false); + rtw89_hw_scan_complete(rtwdev, rtwvif_link, false); } break; case RTW89_SCAN_ENTER_OP_NOTIFY: case RTW89_SCAN_ENTER_CH_NOTIFY: if (rtw89_is_op_chan(rtwdev, band, chan)) { - rtw89_assign_entity_chan(rtwdev, rtwvif->chanctx_idx, + rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, &rtwdev->scan_info.op_chan); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); ieee80211_wake_queues(rtwdev->hw); } else { rtw89_chan_create(&new, chan, chan, band, RTW89_CHANNEL_WIDTH_20); - rtw89_assign_entity_chan(rtwdev, rtwvif->chanctx_idx, + rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, &new); } break; @@ -4812,10 +4869,11 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, } static void -rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct sk_buff *skb) { - struct ieee80211_vif *vif = rtwvif_to_vif_safe(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; enum nl80211_cqm_rssi_threshold_event nl_event; const struct rtw89_c2h_mac_bcnfltr_rpt *c2h = (const struct rtw89_c2h_mac_bcnfltr_rpt *)skb->data; @@ -4827,7 +4885,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, event = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_EVENT); mac_id = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_MACID); - if (mac_id != rtwvif->mac_id) + if (mac_id != rtwvif_link->mac_id) return; rtw89_debug(rtwdev, RTW89_DBG_FW, @@ -4839,7 +4897,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, if (!rtwdev->scanning && !rtwvif->offchan) ieee80211_connection_loss(vif); else - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); return; case RTW89_BCN_FLTR_NOTIFY: nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; @@ -4863,10 +4921,13 @@ static void rtw89_mac_c2h_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_bcn_fltr_rpt(rtwdev, rtwvif, c2h); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_bcn_fltr_rpt(rtwdev, rtwvif_link, c2h); } static void @@ -4974,6 +5035,18 @@ rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, rtw89_complete_cond(wait, cond, &data); } +static void +rtw89_mac_c2h_tx_duty_rpt(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len) +{ + struct rtw89_c2h_tx_duty_rpt *c2h = + (struct rtw89_c2h_tx_duty_rpt *)skb_c2h->data; + u8 err; + + err = le32_get_bits(c2h->w2, RTW89_C2H_TX_DUTY_RPT_W2_TIMER_ERR); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "C2H TX duty rpt with err=%d\n", err); +} + static void rtw89_mac_c2h_tsf32_toggle_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) @@ -5300,6 +5373,7 @@ void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_BCN_RESEND] = NULL, [RTW89_MAC_C2H_FUNC_MACID_PAUSE] = rtw89_mac_c2h_macid_pause, [RTW89_MAC_C2H_FUNC_SCANOFLD_RSP] = rtw89_mac_c2h_scanofld_rsp, + [RTW89_MAC_C2H_FUNC_TX_DUTY_RPT] = rtw89_mac_c2h_tx_duty_rpt, [RTW89_MAC_C2H_FUNC_TSF32_TOGL_RPT] = rtw89_mac_c2h_tsf32_toggle_rpt, [RTW89_MAC_C2H_FUNC_BCNFLTR_RPT] = rtw89_mac_c2h_bcn_fltr_rpt, }; @@ -5490,7 +5564,8 @@ int rtw89_mac_cfg_ppdu_status_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool enab return 0; } -void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx) +static +void __rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx) { #define MAC_AX_TIME_TH_SH 5 #define MAC_AX_LEN_TH_SH 4 @@ -5520,6 +5595,13 @@ void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx) rtw89_write16_mask(rtwdev, reg, B_AX_RTS_LEN_TH_MASK, len_th); } +void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev) +{ + __rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); + if (rtwdev->dbcc_en) + __rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_1); +} + void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop) { bool empty; @@ -5931,15 +6013,15 @@ static int rtw89_mac_init_bfee_ax(struct rtw89_dev *rtwdev, u8 mac_idx) } static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - u8 mac_idx = rtwvif->mac_idx; u8 nc = 1, nr = 3, ng = 0, cb = 1, cs = 1, ldpc_en = 1, stbc_en = 1; - u8 port_sel = rtwvif->port; + struct ieee80211_link_sta *link_sta; + u8 mac_idx = rtwvif_link->mac_idx; + u8 port_sel = rtwvif_link->port; u8 sound_dim = 3, t; - u8 *phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info; + u8 *phy_cap; u32 reg; u16 val; int ret; @@ -5948,6 +6030,11 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev, if (ret) return ret; + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info; + if ((phy_cap[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) || (phy_cap[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) { ldpc_en &= !!(phy_cap[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD); @@ -5956,17 +6043,19 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev, phy_cap[5]); sound_dim = min(sound_dim, t); } - if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { - ldpc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); - stbc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK); + if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { + ldpc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); + stbc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK); t = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK, - sta->deflink.vht_cap.cap); + link_sta->vht_cap.cap); sound_dim = min(sound_dim, t); } nc = min(nc, sound_dim); nr = min(nr, sound_dim); + rcu_read_unlock(); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); rtw89_write32_set(rtwdev, reg, B_AX_BFMEE_BFPARAM_SEL); @@ -5989,34 +6078,41 @@ static int rtw89_mac_set_csi_para_reg_ax(struct rtw89_dev *rtwdev, } static int rtw89_mac_csi_rrsc_ax(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; u32 rrsc = BIT(RTW89_MAC_BF_RRSC_6M) | BIT(RTW89_MAC_BF_RRSC_24M); + struct ieee80211_link_sta *link_sta; + u8 mac_idx = rtwvif_link->mac_idx; u32 reg; - u8 mac_idx = rtwvif->mac_idx; int ret; ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) return ret; - if (sta->deflink.he_cap.has_he) { + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->he_cap.has_he) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_HE_MSC0) | BIT(RTW89_MAC_BF_RRSC_HE_MSC3) | BIT(RTW89_MAC_BF_RRSC_HE_MSC5)); } - if (sta->deflink.vht_cap.vht_supported) { + if (link_sta->vht_cap.vht_supported) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_VHT_MSC0) | BIT(RTW89_MAC_BF_RRSC_VHT_MSC3) | BIT(RTW89_MAC_BF_RRSC_VHT_MSC5)); } - if (sta->deflink.ht_cap.ht_supported) { + if (link_sta->ht_cap.ht_supported) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_HT_MSC0) | BIT(RTW89_MAC_BF_RRSC_HT_MSC3) | BIT(RTW89_MAC_BF_RRSC_HT_MSC5)); } + + rcu_read_unlock(); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); rtw89_write32_set(rtwdev, reg, B_AX_BFMEE_BFPARAM_SEL); rtw89_write32_clr(rtwdev, reg, B_AX_BFMEE_CSI_FORCE_RETE_EN); @@ -6028,35 +6124,53 @@ static int rtw89_mac_csi_rrsc_ax(struct rtw89_dev *rtwdev, } static void rtw89_mac_bf_assoc_ax(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta; + bool has_beamformer_cap; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + has_beamformer_cap = rtw89_sta_has_beamformer_cap(link_sta); - if (rtw89_sta_has_beamformer_cap(sta)) { + rcu_read_unlock(); + + if (has_beamformer_cap) { rtw89_debug(rtwdev, RTW89_DBG_BF, "initialize bfee for new association\n"); - rtw89_mac_init_bfee_ax(rtwdev, rtwvif->mac_idx); - rtw89_mac_set_csi_para_reg_ax(rtwdev, vif, sta); - rtw89_mac_csi_rrsc_ax(rtwdev, vif, sta); + rtw89_mac_init_bfee_ax(rtwdev, rtwvif_link->mac_idx); + rtw89_mac_set_csi_para_reg_ax(rtwdev, rtwvif_link, rtwsta_link); + rtw89_mac_csi_rrsc_ax(rtwdev, rtwvif_link, rtwsta_link); } } -void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - - rtw89_mac_bfee_ctrl(rtwdev, rtwvif->mac_idx, false); + rtw89_mac_bfee_ctrl(rtwdev, rtwvif_link->mac_idx, false); } void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; - u8 mac_idx = rtwvif->mac_idx; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + u8 mac_idx; __le32 *p; + rtwvif_link = rtwvif->links[conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, conf->link_id); + return; + } + + mac_idx = rtwvif_link->mac_idx; + rtw89_debug(rtwdev, RTW89_DBG_BF, "update bf GID table\n"); p = (__le32 *)conf->mu_group.membership; @@ -6080,7 +6194,7 @@ void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif * struct rtw89_mac_bf_monitor_iter_data { struct rtw89_dev *rtwdev; - struct ieee80211_sta *down_sta; + struct rtw89_sta_link *down_rtwsta_link; int count; }; @@ -6089,23 +6203,41 @@ void rtw89_mac_bf_monitor_calc_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_mac_bf_monitor_iter_data *iter_data = (struct rtw89_mac_bf_monitor_iter_data *)data; - struct ieee80211_sta *down_sta = iter_data->down_sta; + struct rtw89_sta_link *down_rtwsta_link = iter_data->down_rtwsta_link; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct ieee80211_link_sta *link_sta; + struct rtw89_sta_link *rtwsta_link; + bool has_beamformer_cap = false; int *count = &iter_data->count; + unsigned int link_id; - if (down_sta == sta) - return; + rcu_read_lock(); - if (rtw89_sta_has_beamformer_cap(sta)) + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + if (rtwsta_link == down_rtwsta_link) + continue; + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + if (rtw89_sta_has_beamformer_cap(link_sta)) { + has_beamformer_cap = true; + break; + } + } + + if (has_beamformer_cap) (*count)++; + + rcu_read_unlock(); } void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, bool disconnect) + struct rtw89_sta_link *rtwsta_link, + bool disconnect) { struct rtw89_mac_bf_monitor_iter_data data; data.rtwdev = rtwdev; - data.down_sta = disconnect ? sta : NULL; + data.down_rtwsta_link = disconnect ? rtwsta_link : NULL; data.count = 0; ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_mac_bf_monitor_calc_iter, @@ -6121,10 +6253,12 @@ void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev, void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) { struct rtw89_traffic_stats *stats = &rtwdev->stats; - struct rtw89_vif *rtwvif; + struct rtw89_vif_link *rtwvif_link; bool en = stats->tx_tfc_lv <= stats->rx_tfc_lv; bool old = test_bit(RTW89_FLAG_BFEE_EN, rtwdev->flags); + struct rtw89_vif *rtwvif; bool keep_timer = true; + unsigned int link_id; bool old_keep_timer; old_keep_timer = test_bit(RTW89_FLAG_BFEE_TIMER_KEEP, rtwdev->flags); @@ -6134,30 +6268,32 @@ void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) if (keep_timer != old_keep_timer) { rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_bfee_standby_timer(rtwdev, rtwvif->mac_idx, - keep_timer); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_bfee_standby_timer(rtwdev, rtwvif_link->mac_idx, + keep_timer); } if (en == old) return; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_bfee_ctrl(rtwdev, rtwvif->mac_idx, en); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_bfee_ctrl(rtwdev, rtwvif_link->mac_idx, en); } static int -__rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +__rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, u32 tx_time) { #define MAC_AX_DFLT_TX_TIME 5280 - u8 mac_idx = rtwsta->rtwvif->mac_idx; + u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx; u32 max_tx_time = tx_time == 0 ? MAC_AX_DFLT_TX_TIME : tx_time; u32 reg; int ret = 0; - if (rtwsta->cctl_tx_time) { - rtwsta->ampdu_max_time = (max_tx_time - 512) >> 9; - ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta); + if (rtwsta_link->cctl_tx_time) { + rtwsta_link->ampdu_max_time = (max_tx_time - 512) >> 9; + ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link); } else { ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) { @@ -6173,31 +6309,31 @@ __rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, return ret; } -int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, bool resume, u32 tx_time) { int ret = 0; if (!resume) { - rtwsta->cctl_tx_time = true; - ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta, tx_time); + rtwsta_link->cctl_tx_time = true; + ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta_link, tx_time); } else { - ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta, tx_time); - rtwsta->cctl_tx_time = false; + ret = __rtw89_mac_set_tx_time(rtwdev, rtwsta_link, tx_time); + rtwsta_link->cctl_tx_time = false; } return ret; } -int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, u32 *tx_time) { - u8 mac_idx = rtwsta->rtwvif->mac_idx; + u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx; u32 reg; int ret = 0; - if (rtwsta->cctl_tx_time) { - *tx_time = (rtwsta->ampdu_max_time + 1) << 9; + if (rtwsta_link->cctl_tx_time) { + *tx_time = (rtwsta_link->ampdu_max_time + 1) << 9; } else { ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) { @@ -6213,33 +6349,33 @@ int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, } int rtw89_mac_set_tx_retry_limit(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, + struct rtw89_sta_link *rtwsta_link, bool resume, u8 tx_retry) { int ret = 0; - rtwsta->data_tx_cnt_lmt = tx_retry; + rtwsta_link->data_tx_cnt_lmt = tx_retry; if (!resume) { - rtwsta->cctl_tx_retry_limit = true; - ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta); + rtwsta_link->cctl_tx_retry_limit = true; + ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link); } else { - ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta); - rtwsta->cctl_tx_retry_limit = false; + ret = rtw89_fw_h2c_txtime_cmac_tbl(rtwdev, rtwsta_link); + rtwsta_link->cctl_tx_retry_limit = false; } return ret; } int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 *tx_retry) + struct rtw89_sta_link *rtwsta_link, u8 *tx_retry) { - u8 mac_idx = rtwsta->rtwvif->mac_idx; + u8 mac_idx = rtwsta_link->rtwvif_link->mac_idx; u32 reg; int ret = 0; - if (rtwsta->cctl_tx_retry_limit) { - *tx_retry = rtwsta->data_tx_cnt_lmt; + if (rtwsta_link->cctl_tx_retry_limit) { + *tx_retry = rtwsta_link->data_tx_cnt_lmt; } else { ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) { @@ -6255,10 +6391,10 @@ int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev, } int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en) + struct rtw89_vif_link *rtwvif_link, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; - u8 mac_idx = rtwvif->mac_idx; + u8 mac_idx = rtwvif_link->mac_idx; u16 set = mac->muedca_ctrl.mask; u32 reg; u32 ret; @@ -6326,7 +6462,9 @@ int rtw89_mac_read_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 *val) } static -void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) +void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { static const enum rtw89_pkt_drop_sel sels[] = { RTW89_PKT_DROP_SEL_MACID_BE_ONCE, @@ -6334,15 +6472,14 @@ void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) RTW89_PKT_DROP_SEL_MACID_VI_ONCE, RTW89_PKT_DROP_SEL_MACID_VO_ONCE, }; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_pkt_drop_params params = {0}; int i; - params.mac_band = RTW89_MAC_0; - params.macid = rtwsta->mac_id; - params.port = rtwvif->port; + params.mac_band = rtwvif_link->mac_idx; + params.macid = rtwsta_link->mac_id; + params.port = rtwvif_link->port; params.mbssid = 0; - params.tf_trs = rtwvif->trigger; + params.tf_trs = rtwvif_link->trigger; for (i = 0; i < ARRAY_SIZE(sels); i++) { params.sel = sels[i]; @@ -6352,15 +6489,21 @@ void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) static void rtw89_mac_pkt_drop_vif_iter(void *data, struct ieee80211_sta *sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct rtw89_vif *rtwvif = rtwsta->rtwvif; - struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; struct rtw89_vif *target = data; + unsigned int link_id; if (rtwvif != target) return; - rtw89_mac_pkt_drop_sta(rtwdev, rtwsta); + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + rtw89_mac_pkt_drop_sta(rtwdev, rtwvif_link, rtwsta_link); + } } void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) @@ -6398,6 +6541,9 @@ int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable) struct rtw89_mac_c2h_info c2h_info = {}; u32 ret; + if (RTW89_CHK_FW_FEATURE(NO_WOW_CPU_IO_RX, &rtwdev->fw)) + return 0; + h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_WOW_CPUIO_RX_CTRL; h2c_info.content_len = sizeof(h2c_info.u.hdr); h2c_info.u.hdr.w0 = u32_encode_bits(wow_enable, RTW89_H2CREG_WOW_CPUIO_RX_CTRL_EN); @@ -6434,6 +6580,9 @@ static int rtw89_wow_config_mac_ax(struct rtw89_dev *rtwdev, bool enable_wow) rtw89_write32(rtwdev, R_AX_TF_FWD, 0); rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0); + if (RTW89_CHK_FW_FEATURE(NO_WOW_CPU_IO_RX, &rtwdev->fw)) + return 0; + if (chip->chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) rtw89_write8(rtwdev, R_BE_DBG_WOW_READY, WOWLAN_NOT_READY); else @@ -6475,6 +6624,20 @@ int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev, rtwdev, R_AX_WCPU_FW_CTRL); } +static +void rtw89_fwdl_secure_idmem_share_mode_ax(struct rtw89_dev *rtwdev, u8 mode) +{ + struct rtw89_fw_secure *sec = &rtwdev->fw.sec; + + if (!sec->secure_boot) + return; + + rtw89_write32_mask(rtwdev, R_AX_WCPU_FW_CTRL, + B_AX_IDMEM_SHARE_MODE_RECORD_MASK, mode); + rtw89_write32_set(rtwdev, R_AX_WCPU_FW_CTRL, + B_AX_IDMEM_SHARE_MODE_RECORD_VALID); +} + const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .band1_offset = RTW89_MAC_AX_BAND_REG_OFFSET, .filter_model_addr = R_AX_FILTER_MODEL_ADDR, @@ -6528,9 +6691,11 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax, .fwdl_get_status = rtw89_fw_get_rdy_ax, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_ax, + .fwdl_secure_idmem_share_mode = rtw89_fwdl_secure_idmem_share_mode_ax, .parse_efuse_map = rtw89_parse_efuse_map_ax, .parse_phycap_map = rtw89_parse_phycap_map_ax, .cnv_efuse_state = rtw89_cnv_efuse_state_ax, + .efuse_read_fw_secure = rtw89_efuse_read_fw_secure_ax, .cfg_plt = rtw89_mac_cfg_plt_ax, .get_plt_cnt = rtw89_mac_get_plt_cnt_ax, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 67c2a45071244d..18579c02054845 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -391,6 +391,7 @@ enum rtw89_mac_c2h_ofld_func { RTW89_MAC_C2H_FUNC_MACID_PAUSE, RTW89_MAC_C2H_FUNC_TSF32_TOGL_RPT = 0x6, RTW89_MAC_C2H_FUNC_SCANOFLD_RSP = 0x9, + RTW89_MAC_C2H_FUNC_TX_DUTY_RPT = 0xa, RTW89_MAC_C2H_FUNC_BCNFLTR_RPT = 0xd, RTW89_MAC_C2H_FUNC_OFLD_MAX, }; @@ -951,8 +952,9 @@ struct rtw89_mac_gen_def { void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev); void (*dle_func_en)(struct rtw89_dev *rtwdev, bool enable); void (*dle_clk_en)(struct rtw89_dev *rtwdev, bool enable); - void (*bf_assoc)(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + void (*bf_assoc)(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); int (*typ_fltr_opt)(struct rtw89_dev *rtwdev, enum rtw89_machdr_frame_type type, @@ -983,9 +985,11 @@ struct rtw89_mac_gen_def { bool dlfw, bool include_bb); u8 (*fwdl_get_status)(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type); int (*fwdl_check_path_ready)(struct rtw89_dev *rtwdev, bool h2c_or_fwdl); + void (*fwdl_secure_idmem_share_mode)(struct rtw89_dev *rtwdev, u8 mode); int (*parse_efuse_map)(struct rtw89_dev *rtwdev); int (*parse_phycap_map)(struct rtw89_dev *rtwdev); int (*cnv_efuse_state)(struct rtw89_dev *rtwdev, bool idle); + int (*efuse_read_fw_secure)(struct rtw89_dev *rtwdev); int (*cfg_plt)(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_plt *plt); u16 (*get_plt_cnt)(struct rtw89_dev *rtwdev, u8 band); @@ -1004,12 +1008,12 @@ struct rtw89_mac_gen_def { bool (*is_txq_empty)(struct rtw89_dev *rtwdev); int (*add_chan_list)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool connected); + struct rtw89_vif_link *rtwvif_link, bool connected); int (*add_chan_list_pno)(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); int (*scan_offload)(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, bool wowlan); int (*wow_config_mac)(struct rtw89_dev *rtwdev, bool enable_wow); @@ -1033,81 +1037,89 @@ u32 rtw89_mac_reg_by_port(struct rtw89_dev *rtwdev, u32 base, u8 port, u8 mac_id } static inline u32 -rtw89_read32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base) +rtw89_read32_port(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); return rtw89_read32(rtwdev, reg); } static inline u32 -rtw89_read32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_read32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 mask) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); return rtw89_read32_mask(rtwdev, reg, mask); } static inline void -rtw89_write32_port(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u32 base, +rtw89_write32_port(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 data) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write32(rtwdev, reg, data); } static inline void -rtw89_write32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write32_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 mask, u32 data) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, mask, data); } static inline void -rtw89_write16_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write16_port_mask(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 mask, u16 data) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write16_mask(rtwdev, reg, mask, data); } static inline void -rtw89_write32_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write32_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 bit) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write32_clr(rtwdev, reg, bit); } static inline void -rtw89_write16_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write16_port_clr(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u16 bit) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write16_clr(rtwdev, reg, bit); } static inline void -rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u32 base, u32 bit) { u32 reg; - reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif->port, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_port(rtwdev, base, rtwvif_link->port, + rtwvif_link->mac_idx); rtw89_write32_set(rtwdev, reg, bit); } @@ -1139,21 +1151,21 @@ int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_qempty *qempty); void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev, enum mac_ax_err_info err); -int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); -int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); +int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, - struct rtw89_vif *rtwvif_src, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_vif_link *rtwvif_src, u16 offset_tu); -int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, u64 *tsf); void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en); + struct rtw89_vif_link *rtwvif_link, bool en); void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif); -void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); + struct rtw89_vif_link *rtwvif_link); +void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en); -int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); +int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif); int rtw89_mac_enable_bb_rf(struct rtw89_dev *rtwdev); int rtw89_mac_disable_bb_rf(struct rtw89_dev *rtwdev); @@ -1213,7 +1225,22 @@ int rtw89_mac_cfg_ppdu_status(struct rtw89_dev *rtwdev, u8 mac_idx, bool enable) return mac->cfg_ppdu_status(rtwdev, mac_idx, enable); } -void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev, u8 mac_idx); +static inline +int rtw89_mac_cfg_ppdu_status_bands(struct rtw89_dev *rtwdev, bool enable) +{ + int ret; + + ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, enable); + if (ret) + return ret; + + if (!rtwdev->dbcc_en) + return 0; + + return rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_1, enable); +} + +void rtw89_mac_update_rts_threshold(struct rtw89_dev *rtwdev); void rtw89_mac_flush_txq(struct rtw89_dev *rtwdev, u32 queues, bool drop); int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex *coex); int rtw89_mac_coex_init_v1(struct rtw89_dev *rtwdev, @@ -1251,27 +1278,30 @@ void rtw89_mac_power_mode_change(struct rtw89_dev *rtwdev, bool enter); void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev); static inline -void rtw89_mac_bf_assoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +void rtw89_mac_bf_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; if (mac->bf_assoc) - mac->bf_assoc(rtwdev, vif, sta); + mac->bf_assoc(rtwdev, rtwvif_link, rtwsta_link); } -void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); +void rtw89_mac_bf_disassoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link); void rtw89_mac_bf_set_gid_table(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf); void rtw89_mac_bf_monitor_calc(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, bool disconnect); + struct rtw89_sta_link *rtwsta_link, + bool disconnect); void _rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev); void rtw89_mac_bfee_ctrl(struct rtw89_dev *rtwdev, u8 mac_idx, bool en); -int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); -int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); +int rtw89_mac_vif_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool en); + struct rtw89_vif_link *rtwvif_link, bool en); int rtw89_mac_set_macid_pause(struct rtw89_dev *rtwdev, u8 macid, bool pause); static inline void rtw89_mac_bf_monitor_track(struct rtw89_dev *rtwdev) @@ -1376,15 +1406,15 @@ static inline bool rtw89_mac_get_power_state(struct rtw89_dev *rtwdev) return !!val; } -int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, bool resume, u32 tx_time); -int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link, u32 *tx_time); int rtw89_mac_set_tx_retry_limit(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, + struct rtw89_sta_link *rtwsta_link, bool resume, u8 tx_retry); int rtw89_mac_get_tx_retry_limit(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, u8 *tx_retry); + struct rtw89_sta_link *rtwsta_link, u8 *tx_retry); enum rtw89_mac_xtal_si_offset { XTAL0 = 0x0, @@ -1466,4 +1496,14 @@ int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_rsvd_qt_cfg *cfg); int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable); +static inline +void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + + if (!mac->fwdl_secure_idmem_share_mode) + return; + + return mac->fwdl_secure_idmem_share_mode(rtwdev, mode); +} #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 48ad0d0f76bff4..619d2d3771d52f 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -23,13 +23,13 @@ static void rtw89_ops_tx(struct ieee80211_hw *hw, struct rtw89_dev *rtwdev = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); struct ieee80211_sta *sta = control->sta; u32 flags = IEEE80211_SKB_CB(skb)->flags; int ret, qsel; if (rtwvif->offchan && !(flags & IEEE80211_TX_CTL_TX_OFFCHAN) && sta) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); rtw89_debug(rtwdev, RTW89_DBG_TXRX, "ops_tx during offchan\n"); skb_queue_tail(&rtwsta->roc_queue, skb); @@ -105,11 +105,61 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) return 0; } +static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct ieee80211_bss_conf *bss_conf; + int ret; + + rtw89_leave_ps_mode(rtwdev); + + rtw89_vif_type_mapping(rtwvif_link, false); + + INIT_WORK(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work); + INIT_LIST_HEAD(&rtwvif_link->general_pkt_list); + + rtwvif_link->hit_rule = 0; + rtwvif_link->bcn_hit_cond = 0; + rtwvif_link->chanctx_assigned = false; + rtwvif_link->chanctx_idx = RTW89_CHANCTX_0; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ether_addr_copy(rtwvif_link->mac_addr, bss_conf->addr); + + rcu_read_unlock(); + + ret = rtw89_mac_add_vif(rtwdev, rtwvif_link); + if (ret) + return ret; + + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, NULL, BTC_ROLE_START); + return 0; +} + +static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + mutex_unlock(&rtwdev->mutex); + cancel_work_sync(&rtwvif_link->update_beacon_work); + mutex_lock(&rtwdev->mutex); + + rtw89_leave_ps_mode(rtwdev); + + rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, NULL, BTC_ROLE_STOP); + + rtw89_mac_remove_vif(rtwdev, rtwvif_link); +} + static int rtw89_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + u8 mac_id, port; int ret = 0; rtw89_debug(rtwdev, RTW89_DBG_STATE, "add vif %pM type %d, p2p %d\n", @@ -123,49 +173,58 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw, vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | IEEE80211_VIF_SUPPORTS_CQM_RSSI; - rtwvif->rtwdev = rtwdev; - rtwvif->roc.state = RTW89_ROC_IDLE; - rtwvif->offchan = false; + mac_id = rtw89_acquire_mac_id(rtwdev); + if (mac_id == RTW89_MAX_MAC_ID_NUM) { + ret = -ENOSPC; + goto err; + } + + port = rtw89_core_acquire_bit_map(rtwdev->hw_port, RTW89_PORT_NUM); + if (port == RTW89_PORT_NUM) { + ret = -ENOSPC; + goto release_macid; + } + + rtw89_init_vif(rtwdev, rtwvif, mac_id, port); + + rtw89_core_txq_init(rtwdev, vif->txq); + if (!rtw89_rtwvif_in_list(rtwdev, rtwvif)) list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); - INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work); + INIT_LIST_HEAD(&rtwvif->mgnt_entry); + + ether_addr_copy(rtwvif->mac_addr, vif->addr); + + rtwvif->offchan = false; + rtwvif->roc.state = RTW89_ROC_IDLE; INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work); - rtw89_leave_ps_mode(rtwdev); rtw89_traffic_stats_init(rtwdev, &rtwvif->stats); - rtw89_vif_type_mapping(vif, false); - rtwvif->port = rtw89_core_acquire_bit_map(rtwdev->hw_port, - RTW89_PORT_NUM); - if (rtwvif->port == RTW89_PORT_NUM) { - ret = -ENOSPC; - list_del_init(&rtwvif->list); - goto out; - } - rtwvif->bcn_hit_cond = 0; - rtwvif->mac_idx = RTW89_MAC_0; - rtwvif->phy_idx = RTW89_PHY_0; - rtwvif->chanctx_idx = RTW89_CHANCTX_0; - rtwvif->chanctx_assigned = false; - rtwvif->hit_rule = 0; - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; - ether_addr_copy(rtwvif->mac_addr, vif->addr); - INIT_LIST_HEAD(&rtwvif->general_pkt_list); - - ret = rtw89_mac_add_vif(rtwdev, rtwvif); - if (ret) { - rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); - list_del_init(&rtwvif->list); - goto out; + rtwvif_link = rtw89_vif_set_link(rtwvif, 0); + if (!rtwvif_link) { + ret = -EINVAL; + goto release_port; } - rtw89_core_txq_init(rtwdev, vif->txq); - - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_START); + ret = __rtw89_ops_add_iface_link(rtwdev, rtwvif_link); + if (ret) + goto unset_link; rtw89_recalc_lps(rtwdev); -out: + + mutex_unlock(&rtwdev->mutex); + return 0; + +unset_link: + rtw89_vif_unset_link(rtwvif, 0); +release_port: + list_del_init(&rtwvif->list); + rtw89_core_release_bit_map(rtwdev->hw_port, port); +release_macid: + rtw89_release_mac_id(rtwdev, mac_id); +err: mutex_unlock(&rtwdev->mutex); return ret; @@ -175,20 +234,35 @@ static void rtw89_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + u8 macid = rtw89_vif_get_main_macid(rtwvif); + u8 port = rtw89_vif_get_main_port(rtwvif); + struct rtw89_vif_link *rtwvif_link; rtw89_debug(rtwdev, RTW89_DBG_STATE, "remove vif %pM type %d p2p %d\n", vif->addr, vif->type, vif->p2p); - cancel_work_sync(&rtwvif->update_beacon_work); cancel_delayed_work_sync(&rtwvif->roc.roc_work); mutex_lock(&rtwdev->mutex); - rtw89_leave_ps_mode(rtwdev); - rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_STOP); - rtw89_mac_remove_vif(rtwdev, rtwvif); - rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); + + rtwvif_link = rtwvif->links[0]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, 0); + goto bottom; + } + + __rtw89_ops_remove_iface_link(rtwdev, rtwvif_link); + + rtw89_vif_unset_link(rtwvif, 0); + +bottom: list_del_init(&rtwvif->list); + rtw89_core_release_bit_map(rtwdev->hw_port, port); + rtw89_release_mac_id(rtwdev, macid); + rtw89_recalc_lps(rtwdev); rtw89_enter_ips_by_hwflags(rtwdev); @@ -311,24 +385,30 @@ static const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = { }; static u8 rtw89_aifsn_to_aifs(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u8 aifsn) + struct rtw89_vif_link *rtwvif_link, u8 aifsn) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); + struct ieee80211_bss_conf *bss_conf; u8 slot_time; u8 sifs; - slot_time = vif->bss_conf.use_short_slot ? 9 : 20; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + slot_time = bss_conf->use_short_slot ? 9 : 20; + + rcu_read_unlock(); + sifs = chan->band_type == RTW89_BAND_2G ? 10 : 16; return aifsn * slot_time + sifs; } static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u16 ac) + struct rtw89_vif_link *rtwvif_link, u16 ac) { - struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; + struct ieee80211_tx_queue_params *params = &rtwvif_link->tx_params[ac]; u32 val; u8 ecw_max, ecw_min; u8 aifs; @@ -336,12 +416,12 @@ static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev, /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ ecw_max = ilog2(params->cw_max + 1); ecw_min = ilog2(params->cw_min + 1); - aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif, params->aifs); + aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif_link, params->aifs); val = FIELD_PREP(FW_EDCA_PARAM_TXOPLMT_MSK, params->txop) | FIELD_PREP(FW_EDCA_PARAM_CWMAX_MSK, ecw_max) | FIELD_PREP(FW_EDCA_PARAM_CWMIN_MSK, ecw_min) | FIELD_PREP(FW_EDCA_PARAM_AIFS_MSK, aifs); - rtw89_fw_h2c_set_edca(rtwdev, rtwvif, ac_to_fw_idx[ac], val); + rtw89_fw_h2c_set_edca(rtwdev, rtwvif_link, ac_to_fw_idx[ac], val); } #define R_MUEDCA_ACS_PARAM(acs) {R_AX_MUEDCA_ ## acs ## _PARAM_0, \ @@ -355,9 +435,9 @@ static const u32 ac_to_mu_edca_param[IEEE80211_NUM_ACS][RTW89_CHIP_GEN_NUM] = { }; static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u16 ac) + struct rtw89_vif_link *rtwvif_link, u16 ac) { - struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; + struct ieee80211_tx_queue_params *params = &rtwvif_link->tx_params[ac]; struct ieee80211_he_mu_edca_param_ac_rec *mu_edca; int gen = rtwdev->chip->chip_gen; u8 aifs, aifsn; @@ -370,32 +450,199 @@ static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, mu_edca = ¶ms->mu_edca_param_rec; aifsn = FIELD_GET(GENMASK(3, 0), mu_edca->aifsn); - aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif, aifsn) : 0; + aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif_link, aifsn) : 0; timer_32us = mu_edca->mu_edca_timer << 8; val = FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_TIMER_MASK, timer_32us) | FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_CW_MASK, mu_edca->ecw_min_max) | FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_AIFS_MASK, aifs); - reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac][gen], rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac][gen], + rtwvif_link->mac_idx); rtw89_write32(rtwdev, reg, val); - rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, true); + rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif_link, true); } static void __rtw89_conf_tx(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, u16 ac) + struct rtw89_vif_link *rtwvif_link, u16 ac) { - ____rtw89_conf_tx_edca(rtwdev, rtwvif, ac); - ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif, ac); + ____rtw89_conf_tx_edca(rtwdev, rtwvif_link, ac); + ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif_link, ac); } static void rtw89_conf_tx(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { u16 ac; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - __rtw89_conf_tx(rtwdev, rtwvif, ac); + __rtw89_conf_tx(rtwdev, rtwvif_link, ac); +} + +static int __rtw89_ops_sta_add(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + bool acquire_macid = false; + u8 macid; + int ret; + int i; + + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { + /* for station mode, assign the mac_id from itself */ + macid = rtw89_vif_get_main_macid(rtwvif); + } else { + macid = rtw89_acquire_mac_id(rtwdev); + if (macid == RTW89_MAX_MAC_ID_NUM) + return -ENOSPC; + + acquire_macid = true; + } + + rtw89_init_sta(rtwdev, rtwvif, rtwsta, macid); + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + rtw89_core_txq_init(rtwdev, sta->txq[i]); + + skb_queue_head_init(&rtwsta->roc_queue); + + rtwsta_link = rtw89_sta_set_link(rtwsta, sta->deflink.link_id); + if (!rtwsta_link) { + ret = -EINVAL; + goto err; + } + + rtwvif_link = rtwsta_link->rtwvif_link; + + ret = rtw89_core_sta_link_add(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + goto unset_link; + + if (vif->type == NL80211_IFTYPE_AP || sta->tdls) + rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); + + return 0; + +unset_link: + rtw89_sta_unset_link(rtwsta, sta->deflink.link_id); +err: + if (acquire_macid) + rtw89_release_mac_id(rtwdev, macid); + + return ret; +} + +static int __rtw89_ops_sta_assoc(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + bool station_mode) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + + if (station_mode) + rtw89_vif_type_mapping(rtwvif_link, true); + + ret = rtw89_core_sta_link_assoc(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + return ret; + } + + rtwdev->total_sta_assoc++; + if (sta->tdls) + rtwvif->tdls_peer++; + + return 0; +} + +static int __rtw89_ops_sta_disassoc(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = rtw89_core_sta_link_disassoc(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + return ret; + } + + rtwsta->disassoc = true; + + rtwdev->total_sta_assoc--; + if (sta->tdls) + rtwvif->tdls_peer--; + + return 0; +} + +static int __rtw89_ops_sta_disconnect(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_core_free_sta_pending_ba(rtwdev, sta); + rtw89_core_free_sta_pending_forbid_ba(rtwdev, sta); + rtw89_core_free_sta_pending_roc_tx(rtwdev, sta); + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = rtw89_core_sta_link_disconnect(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + return ret; + } + + return 0; +} + +static int __rtw89_ops_sta_remove(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + u8 macid = rtw89_sta_get_main_macid(rtwsta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + int ret; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + ret = rtw89_core_sta_link_remove(rtwdev, rtwvif_link, rtwsta_link); + if (ret) + return ret; + + rtw89_sta_unset_link(rtwsta, link_id); + } + + if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { + rtw89_release_mac_id(rtwdev, macid); + rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); + } + + return 0; } static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, @@ -412,16 +659,34 @@ static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, return; } - rtw89_vif_type_mapping(vif, true); + __rtw89_ops_sta_assoc(rtwdev, vif, sta, true); +} + +static void __rtw89_ops_bss_link_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + rtw89_phy_set_bss_color(rtwdev, rtwvif_link); + rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, rtwvif_link); + rtw89_mac_port_update(rtwdev, rtwvif_link); + rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, rtwvif_link); +} + +static void __rtw89_ops_bss_assoc(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; - rtw89_core_sta_assoc(rtwdev, vif, sta); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + __rtw89_ops_bss_link_assoc(rtwdev, rtwvif_link); } static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 changed) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); @@ -429,10 +694,7 @@ static void rtw89_ops_vif_cfg_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (vif->cfg.assoc) { rtw89_station_mode_sta_assoc(rtwdev, vif); - rtw89_phy_set_bss_color(rtwdev, vif); - rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); - rtw89_mac_port_update(rtwdev, rtwvif); - rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, vif); + __rtw89_ops_bss_assoc(rtwdev, vif); rtw89_queue_chanctx_work(rtwdev); } else { @@ -459,39 +721,49 @@ static void rtw89_ops_link_info_changed(struct ieee80211_hw *hw, u64 changed) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); + rtwvif_link = rtwvif->links[conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, conf->link_id); + goto out; + } + if (changed & BSS_CHANGED_BSSID) { - ether_addr_copy(rtwvif->bssid, conf->bssid); - rtw89_cam_bssid_changed(rtwdev, rtwvif); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); - WRITE_ONCE(rtwvif->sync_bcn_tsf, 0); + ether_addr_copy(rtwvif_link->bssid, conf->bssid); + rtw89_cam_bssid_changed(rtwdev, rtwvif_link); + rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); + WRITE_ONCE(rtwvif_link->sync_bcn_tsf, 0); } if (changed & BSS_CHANGED_BEACON) - rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); if (changed & BSS_CHANGED_ERP_SLOT) - rtw89_conf_tx(rtwdev, rtwvif); + rtw89_conf_tx(rtwdev, rtwvif_link); if (changed & BSS_CHANGED_HE_BSS_COLOR) - rtw89_phy_set_bss_color(rtwdev, vif); + rtw89_phy_set_bss_color(rtwdev, rtwvif_link); if (changed & BSS_CHANGED_MU_GROUPS) rtw89_mac_bf_set_gid_table(rtwdev, vif, conf); if (changed & BSS_CHANGED_P2P_PS) - rtw89_core_update_p2p_ps(rtwdev, vif); + rtw89_core_update_p2p_ps(rtwdev, rtwvif_link, conf); if (changed & BSS_CHANGED_CQM) - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); if (changed & BSS_CHANGED_TPE) - rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true); + rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, true); +out: mutex_unlock(&rtwdev->mutex); } @@ -500,12 +772,21 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; const struct rtw89_chan *chan; mutex_lock(&rtwdev->mutex); - chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + goto out; + } + + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); if (chan->band_type == RTW89_BAND_6G) { mutex_unlock(&rtwdev->mutex); return -EOPNOTSUPP; @@ -514,16 +795,18 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, if (rtwdev->scanning) rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); - ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); - rtw89_cam_bssid_changed(rtwdev, rtwvif); - rtw89_mac_port_update(rtwdev, rtwvif); - rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); - rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_TYPE_CHANGE); - rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); - rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); - rtw89_chip_rfk_channel(rtwdev, rtwvif); + ether_addr_copy(rtwvif_link->bssid, link_conf->bssid); + rtw89_cam_bssid_changed(rtwdev, rtwvif_link); + rtw89_mac_port_update(rtwdev, rtwvif_link); + rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, NULL); + rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, NULL, RTW89_ROLE_TYPE_CHANGE); + rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true); + rtw89_fw_h2c_cam(rtwdev, rtwvif_link, NULL, NULL); + rtw89_chip_rfk_channel(rtwdev, rtwvif_link); rtw89_queue_chanctx_work(rtwdev); + +out: mutex_unlock(&rtwdev->mutex); return 0; @@ -534,12 +817,24 @@ void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); - rtw89_mac_stop_ap(rtwdev, rtwvif); - rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); - rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); + + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + goto out; + } + + rtw89_mac_stop_ap(rtwdev, rtwvif_link); + rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, NULL); + rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, NULL, true); + +out: mutex_unlock(&rtwdev->mutex); } @@ -547,10 +842,13 @@ static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; - ieee80211_queue_work(rtwdev->hw, &rtwvif->update_beacon_work); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + ieee80211_queue_work(rtwdev->hw, &rtwvif_link->update_beacon_work); return 0; } @@ -561,15 +859,29 @@ static int rtw89_ops_conf_tx(struct ieee80211_hw *hw, const struct ieee80211_tx_queue_params *params) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + int ret = 0; mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); - rtwvif->tx_params[ac] = *params; - __rtw89_conf_tx(rtwdev, rtwvif, ac); + + rtwvif_link = rtwvif->links[link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_id); + ret = -ENOLINK; + goto out; + } + + rtwvif_link->tx_params[ac] = *params; + __rtw89_conf_tx(rtwdev, rtwvif_link, ac); + +out: mutex_unlock(&rtwdev->mutex); - return 0; + return ret; } static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, @@ -582,26 +894,26 @@ static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) - return rtw89_core_sta_add(rtwdev, vif, sta); + return __rtw89_ops_sta_add(rtwdev, vif, sta); if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) return 0; /* defer to bss_info_changed to have vif info */ - return rtw89_core_sta_assoc(rtwdev, vif, sta); + return __rtw89_ops_sta_assoc(rtwdev, vif, sta, false); } if (old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTH) - return rtw89_core_sta_disassoc(rtwdev, vif, sta); + return __rtw89_ops_sta_disassoc(rtwdev, vif, sta); if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_NONE) - return rtw89_core_sta_disconnect(rtwdev, vif, sta); + return __rtw89_ops_sta_disconnect(rtwdev, vif, sta); if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) - return rtw89_core_sta_remove(rtwdev, vif, sta); + return __rtw89_ops_sta_remove(rtwdev, vif, sta); return 0; } @@ -667,7 +979,8 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, { struct rtw89_dev *rtwdev = hw->priv; struct ieee80211_sta *sta = params->sta; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); u16 tid = params->tid; struct ieee80211_txq *txq = sta->txq[tid]; struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; @@ -681,7 +994,7 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); clear_bit(tid, rtwsta->ampdu_map); - rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); + rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta); mutex_unlock(&rtwdev->mutex); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; @@ -692,7 +1005,7 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, rtwsta->ampdu_params[tid].amsdu = params->amsdu; set_bit(tid, rtwsta->ampdu_map); rtw89_leave_ps_mode(rtwdev); - rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); + rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, rtwvif, rtwsta); mutex_unlock(&rtwdev->mutex); break; case IEEE80211_AMPDU_RX_START: @@ -720,7 +1033,7 @@ static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&rtwdev->mutex); rtw89_leave_ps_mode(rtwdev); if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) - rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); + rtw89_mac_update_rts_threshold(rtwdev); mutex_unlock(&rtwdev->mutex); return 0; @@ -731,9 +1044,14 @@ static void rtw89_ops_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct station_info *sinfo) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; - sinfo->txrate = rtwsta->ra_report.txrate; + rtwsta_link = rtw89_sta_get_link_inst(rtwsta, 0); + if (unlikely(!rtwsta_link)) + return; + + sinfo->txrate = rtwsta_link->ra_report.txrate; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } @@ -743,7 +1061,7 @@ void __rtw89_drop_packets(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) struct rtw89_vif *rtwvif; if (vif) { - rtwvif = (struct rtw89_vif *)vif->drv_priv; + rtwvif = vif_to_rtwvif(vif); rtw89_mac_pkt_drop_vif(rtwdev, rtwvif); } else { rtw89_for_each_rtwvif(rtwdev, rtwvif) @@ -777,14 +1095,20 @@ struct rtw89_iter_bitrate_mask_data { static void rtw89_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_iter_bitrate_mask_data *br_data = data; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif); + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; if (vif != br_data->vif || vif->p2p) return; - rtwsta->use_cfg_mask = true; - rtwsta->mask = *br_data->mask; + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwsta_link->use_cfg_mask = true; + rtwsta_link->mask = *br_data->mask; + } + rtw89_phy_ra_update_sta(br_data->rtwdev, sta, IEEE80211_RC_SUPP_RATES_CHANGED); } @@ -854,10 +1178,20 @@ static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, const u8 *mac_addr) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); - rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, false); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "sw scan start: find no link on HW-0\n"); + goto out; + } + + rtw89_core_scan_start(rtwdev, rtwvif_link, mac_addr, false); + +out: mutex_unlock(&rtwdev->mutex); } @@ -865,9 +1199,20 @@ static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); - rtw89_core_scan_complete(rtwdev, vif, false); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "sw scan complete: find no link on HW-0\n"); + goto out; + } + + rtw89_core_scan_complete(rtwdev, rtwvif_link, false); + +out: mutex_unlock(&rtwdev->mutex); } @@ -884,22 +1229,35 @@ static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *req) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); - int ret = 0; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + int ret; if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) return 1; - if (rtwdev->scanning || rtwvif->offchan) - return -EBUSY; - mutex_lock(&rtwdev->mutex); - rtw89_hw_scan_start(rtwdev, vif, req); - ret = rtw89_hw_scan_offload(rtwdev, vif, true); + + if (rtwdev->scanning || rtwvif->offchan) { + ret = -EBUSY; + goto out; + } + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "hw scan: find no link on HW-0\n"); + ret = -ENOLINK; + goto out; + } + + rtw89_hw_scan_start(rtwdev, rtwvif_link, req); + ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true); if (ret) { - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwvif_link); rtw89_err(rtwdev, "HW scan failed with status: %d\n", ret); } + +out: mutex_unlock(&rtwdev->mutex); return ret; @@ -909,6 +1267,8 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) return; @@ -917,14 +1277,25 @@ static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw, return; mutex_lock(&rtwdev->mutex); - rtw89_hw_scan_abort(rtwdev, vif); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "cancel hw scan: find no link on HW-0\n"); + goto out; + } + + rtw89_hw_scan_abort(rtwdev, rtwvif_link); + +out: mutex_unlock(&rtwdev->mutex); } static void rtw89_ops_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u32 changed) + struct ieee80211_link_sta *link_sta, + u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct rtw89_dev *rtwdev = hw->priv; rtw89_phy_ra_update_sta(rtwdev, sta, changed); @@ -970,11 +1341,24 @@ static int rtw89_ops_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; int ret; mutex_lock(&rtwdev->mutex); - ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif, ctx); + + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + ret = -ENOLINK; + goto out; + } + + ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, ctx); + +out: mutex_unlock(&rtwdev->mutex); return ret; @@ -986,10 +1370,21 @@ static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct rtw89_dev *rtwdev = hw->priv; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; mutex_lock(&rtwdev->mutex); - rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif, ctx); + + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + mutex_unlock(&rtwdev->mutex); + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + return; + } + + rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, ctx); mutex_unlock(&rtwdev->mutex); } @@ -1003,7 +1398,7 @@ static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct rtw89_roc *roc = &rtwvif->roc; - if (!vif) + if (!rtwvif) return -EINVAL; mutex_lock(&rtwdev->mutex); @@ -1053,8 +1448,8 @@ static int rtw89_ops_cancel_remain_on_channel(struct ieee80211_hw *hw, static void rtw89_set_tid_config_iter(void *data, struct ieee80211_sta *sta) { struct cfg80211_tid_config *tid_config = data; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_dev *rtwdev = rtwsta->rtwvif->rtwdev; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; rtw89_core_set_tid_config(rtwdev, sta, tid_config); } @@ -1203,7 +1598,7 @@ const struct ieee80211_ops rtw89_ops = { .remain_on_channel = rtw89_ops_remain_on_channel, .cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel, .set_sar_specs = rtw89_ops_set_sar_specs, - .sta_rc_update = rtw89_ops_sta_rc_update, + .link_sta_rc_update = rtw89_ops_sta_rc_update, .set_tid_config = rtw89_ops_set_tid_config, #ifdef CONFIG_PM .suspend = rtw89_ops_suspend, diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 31f0a5225b115e..f7a396c8a3cd50 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -773,7 +773,7 @@ static int dmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx) return ret; } - ret = rtw89_mac_preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode); + ret = rtw89_mac_preload_init(rtwdev, mac_idx, rtwdev->mac.qta_mode); if (ret) { rtw89_err(rtwdev, "[ERR]preload init %d\n", ret); return ret; @@ -2091,13 +2091,13 @@ static int rtw89_mac_init_bfee_be(struct rtw89_dev *rtwdev, u8 mac_idx) } static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; u8 nc = 1, nr = 3, ng = 0, cb = 1, cs = 1, ldpc_en = 1, stbc_en = 1; - u8 mac_idx = rtwvif->mac_idx; - u8 port_sel = rtwvif->port; + struct ieee80211_link_sta *link_sta; + u8 mac_idx = rtwvif_link->mac_idx; + u8 port_sel = rtwvif_link->port; u8 sound_dim = 3, t; u8 *phy_cap; u32 reg; @@ -2108,7 +2108,10 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, if (ret) return ret; - phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info; + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info; if ((phy_cap[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) || (phy_cap[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER)) { @@ -2119,11 +2122,11 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, sound_dim = min(sound_dim, t); } - if ((sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { - ldpc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); - stbc_en &= !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK); - t = u32_get_bits(sta->deflink.vht_cap.cap, + if ((link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) || + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { + ldpc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC); + stbc_en &= !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK); + t = u32_get_bits(link_sta->vht_cap.cap, IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); sound_dim = min(sound_dim, t); } @@ -2131,6 +2134,8 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, nc = min(nc, sound_dim); nr = min(nr, sound_dim); + rcu_read_unlock(); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); rtw89_write32_set(rtwdev, reg, B_BE_BFMEE_BFPARAM_SEL); @@ -2155,12 +2160,12 @@ static int rtw89_mac_set_csi_para_reg_be(struct rtw89_dev *rtwdev, } static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; u32 rrsc = BIT(RTW89_MAC_BF_RRSC_6M) | BIT(RTW89_MAC_BF_RRSC_24M); - u8 mac_idx = rtwvif->mac_idx; + struct ieee80211_link_sta *link_sta; + u8 mac_idx = rtwvif_link->mac_idx; int ret; u32 reg; @@ -2168,22 +2173,28 @@ static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev, if (ret) return ret; - if (sta->deflink.he_cap.has_he) { + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + + if (link_sta->he_cap.has_he) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_HE_MSC0) | BIT(RTW89_MAC_BF_RRSC_HE_MSC3) | BIT(RTW89_MAC_BF_RRSC_HE_MSC5)); } - if (sta->deflink.vht_cap.vht_supported) { + if (link_sta->vht_cap.vht_supported) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_VHT_MSC0) | BIT(RTW89_MAC_BF_RRSC_VHT_MSC3) | BIT(RTW89_MAC_BF_RRSC_VHT_MSC5)); } - if (sta->deflink.ht_cap.ht_supported) { + if (link_sta->ht_cap.ht_supported) { rrsc |= (BIT(RTW89_MAC_BF_RRSC_HT_MSC0) | BIT(RTW89_MAC_BF_RRSC_HT_MSC3) | BIT(RTW89_MAC_BF_RRSC_HT_MSC5)); } + rcu_read_unlock(); + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_CSI_CTRL_0, mac_idx); rtw89_write32_set(rtwdev, reg, B_BE_BFMEE_BFPARAM_SEL); rtw89_write32_clr(rtwdev, reg, B_BE_BFMEE_CSI_FORCE_RETE_EN); @@ -2195,17 +2206,25 @@ static int rtw89_mac_csi_rrsc_be(struct rtw89_dev *rtwdev, } static void rtw89_mac_bf_assoc_be(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct ieee80211_link_sta *link_sta; + bool has_beamformer_cap; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + has_beamformer_cap = rtw89_sta_has_beamformer_cap(link_sta); + + rcu_read_unlock(); - if (rtw89_sta_has_beamformer_cap(sta)) { + if (has_beamformer_cap) { rtw89_debug(rtwdev, RTW89_DBG_BF, "initialize bfee for new association\n"); - rtw89_mac_init_bfee_be(rtwdev, rtwvif->mac_idx); - rtw89_mac_set_csi_para_reg_be(rtwdev, vif, sta); - rtw89_mac_csi_rrsc_be(rtwdev, vif, sta); + rtw89_mac_init_bfee_be(rtwdev, rtwvif_link->mac_idx); + rtw89_mac_set_csi_para_reg_be(rtwdev, rtwvif_link, rtwsta_link); + rtw89_mac_csi_rrsc_be(rtwdev, rtwvif_link, rtwsta_link); } } @@ -2581,9 +2600,11 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be, .fwdl_get_status = fwdl_get_status_be, .fwdl_check_path_ready = rtw89_fwdl_check_path_ready_be, + .fwdl_secure_idmem_share_mode = NULL, .parse_efuse_map = rtw89_parse_efuse_map_be, .parse_phycap_map = rtw89_parse_phycap_map_be, .cnv_efuse_state = rtw89_cnv_efuse_state_be, + .efuse_read_fw_secure = rtw89_efuse_read_fw_secure_be, .cfg_plt = rtw89_mac_cfg_plt_be, .get_plt_cnt = rtw89_mac_get_plt_cnt_be, diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 5aef7fa378788c..f923bec03d410f 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -2358,13 +2358,15 @@ static int rtw89_pci_deglitch_setting(struct rtw89_dev *rtwdev) return 0; } -static void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev) +static void rtw89_pci_disable_eq_ax(struct rtw89_dev *rtwdev) { u16 g1_oobs, g2_oobs; u32 backup_aspm; u32 phy_offset; + u16 offset_cal; u16 oobs_val; int ret; + u8 gen; if (rtwdev->chip->chip_id != RTL8852C) return; @@ -2400,6 +2402,28 @@ static void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev) rtw89_write16_set(rtwdev, R_RAC_DIRECT_OFFSET_G2 + RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL); + /* offset K */ + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_G1 : + R_RAC_DIRECT_OFFSET_G2; + + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT, + B_PCIE_BIT_RD_SEL); + } + + offset_cal = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_G1 + + RAC_ANA1F * RAC_MULT, OFFSET_CAL_MASK); + + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_G1 : + R_RAC_DIRECT_OFFSET_G2; + + rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA0B * RAC_MULT, + MANUAL_LVL_MASK, offset_cal); + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT, + OFFSET_CAL_MODE); + } + out: rtw89_write32(rtwdev, R_AX_PCIE_MIX_CFG_V1, backup_aspm); } @@ -2647,9 +2671,10 @@ static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev) static int rtw89_pci_poll_txdma_ch_idle_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; - u32 ret, check, dma_busy; u32 dma_busy1 = info->dma_busy1.addr; u32 dma_busy2 = info->dma_busy2_reg; + u32 check, dma_busy; + int ret; check = info->dma_busy1.mask; @@ -2674,8 +2699,9 @@ static int rtw89_pci_poll_txdma_ch_idle_ax(struct rtw89_dev *rtwdev) static int rtw89_pci_poll_rxdma_ch_idle_ax(struct rtw89_dev *rtwdev) { const struct rtw89_pci_info *info = rtwdev->pci_info; - u32 ret, check, dma_busy; u32 dma_busy3 = info->dma_busy3_reg; + u32 check, dma_busy; + int ret; check = B_AX_RXQ_BUSY | B_AX_RPQ_BUSY; @@ -3758,19 +3784,16 @@ static void rtw89_pci_free_irq(struct rtw89_dev *rtwdev, pci_free_irq_vectors(pdev); } -static u16 gray_code_to_bin(u16 gray_code, u32 bit_num) +static u16 gray_code_to_bin(u16 gray_code) { - u16 bin = 0, gray_bit; - u32 bit_idx; + u16 binary = gray_code; - for (bit_idx = 0; bit_idx < bit_num; bit_idx++) { - gray_bit = (gray_code >> bit_idx) & 0x1; - if (bit_num - bit_idx > 1) - gray_bit ^= (gray_code >> (bit_idx + 1)) & 0x1; - bin |= (gray_bit << bit_idx); + while (gray_code) { + gray_code >>= 1; + binary ^= gray_code; } - return bin; + return binary; } static int rtw89_pci_filter_out(struct rtw89_dev *rtwdev) @@ -3806,7 +3829,7 @@ static int rtw89_pci_filter_out(struct rtw89_dev *rtwdev) val16 = rtw89_read16_mask(rtwdev, phy_offset + RAC_ANA1F * RAC_MULT, FILTER_OUT_EQ_MASK); - val16 = gray_code_to_bin(val16, hweight16(val16)); + val16 = gray_code_to_bin(val16); filter_out_val = rtw89_read16(rtwdev, phy_offset + RAC_ANA24 * RAC_MULT); filter_out_val &= ~REG_FILTER_OUT_MASK; @@ -4188,6 +4211,36 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) return work_done; } +static +void rtw89_check_pci_ssid_quirks(struct rtw89_dev *rtwdev, + struct pci_dev *pdev, + const struct rtw89_pci_ssid_quirk *ssid_quirks) +{ + int i; + + if (!ssid_quirks) + return; + + for (i = 0; i < 200; i++, ssid_quirks++) { + if (ssid_quirks->vendor == 0 && ssid_quirks->device == 0) + break; + + if (ssid_quirks->vendor != pdev->vendor || + ssid_quirks->device != pdev->device || + ssid_quirks->subsystem_vendor != pdev->subsystem_vendor || + ssid_quirks->subsystem_device != pdev->subsystem_device) + continue; + + bitmap_or(rtwdev->quirks, rtwdev->quirks, &ssid_quirks->bitmap, + NUM_OF_RTW89_QUIRKS); + rtwdev->custid = ssid_quirks->custid; + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_HCI, "quirks=%*ph custid=%d\n", + (int)sizeof(rtwdev->quirks), rtwdev->quirks, rtwdev->custid); +} + static int __maybe_unused rtw89_pci_suspend(struct device *dev) { struct ieee80211_hw *hw = dev_get_drvdata(dev); @@ -4222,6 +4275,17 @@ static void rtw89_pci_l2_hci_ldo(struct rtw89_dev *rtwdev) RTW89_PCIE_BIT_CFG_RST_MSTATE); } +void rtw89_pci_basic_cfg(struct rtw89_dev *rtwdev, bool resume) +{ + if (resume) + rtw89_pci_cfg_dac(rtwdev); + + rtw89_pci_disable_eq(rtwdev); + rtw89_pci_filter_out(rtwdev); + rtw89_pci_link_cfg(rtwdev); + rtw89_pci_l1ss_cfg(rtwdev); +} + static int __maybe_unused rtw89_pci_resume(struct device *dev) { struct ieee80211_hw *hw = dev_get_drvdata(dev); @@ -4243,11 +4307,8 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) B_AX_SEL_REQ_ENTR_L1); } rtw89_pci_l2_hci_ldo(rtwdev); - rtw89_pci_disable_eq(rtwdev); - rtw89_pci_cfg_dac(rtwdev); - rtw89_pci_filter_out(rtwdev); - rtw89_pci_link_cfg(rtwdev); - rtw89_pci_l1ss_cfg(rtwdev); + + rtw89_pci_basic_cfg(rtwdev, true); return 0; } @@ -4280,6 +4341,8 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .aspm_set = rtw89_pci_aspm_set_ax, .clkreq_set = rtw89_pci_clkreq_set_ax, .l1ss_set = rtw89_pci_l1ss_set_ax, + + .disable_eq = rtw89_pci_disable_eq_ax, }; EXPORT_SYMBOL(rtw89_pci_gen_ax); @@ -4352,6 +4415,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) rtwdev->hci.cpwm_addr = pci_info->cpwm_addr; rtw89_check_quirks(rtwdev, info->quirks); + rtw89_check_pci_ssid_quirks(rtwdev, pdev, pci_info->ssid_quirks); SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev); @@ -4379,10 +4443,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_clear_resource; } - rtw89_pci_disable_eq(rtwdev); - rtw89_pci_filter_out(rtwdev); - rtw89_pci_link_cfg(rtwdev); - rtw89_pci_l1ss_cfg(rtwdev); + rtw89_pci_basic_cfg(rtwdev, false); ret = rtw89_core_napi_init(rtwdev); if (ret) { diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 48c3ab735db2a7..b68e2d82eea90d 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -18,11 +18,16 @@ #define BAC_OOBS_SEL BIT(4) #define RAC_ANA0A 0x0A #define B_BAC_EQ_SEL BIT(5) +#define RAC_ANA0B 0x0B +#define MANUAL_LVL_MASK GENMASK(8, 5) #define RAC_ANA0C 0x0C #define B_PCIE_BIT_PSAVE BIT(15) #define RAC_ANA0D 0x0D +#define OFFSET_CAL_MODE BIT(13) #define BAC_RX_TEST_EN BIT(6) #define RAC_ANA10 0x10 +#define ADDR_SEL_MASK GENMASK(9, 4) +#define ADDR_SEL_VAL 0x3C #define ADDR_SEL_PINOUT_DIS_VAL 0x3C4 #define B_PCIE_BIT_PINOUT_DIS BIT(3) #define RAC_REG_REV2 0x1B @@ -38,6 +43,7 @@ #define RAC_ANA1E_G2_VAL 0x6EEA #define RAC_ANA1F 0x1F #define OOBS_LEVEL_MASK GENMASK(12, 8) +#define OFFSET_CAL_MASK GENMASK(7, 4) #define RAC_ANA24 0x24 #define B_AX_DEGLITCH GENMASK(11, 8) #define RAC_ANA26 0x26 @@ -134,6 +140,11 @@ #define REG_FILTER_OUT_MASK GENMASK(6, 2) #define RAC_MULT 2 +#define R_RAC_DIRECT_OFFSET_BE_LANE0_G1 0x3800 +#define R_RAC_DIRECT_OFFSET_BE_LANE1_G1 0x3880 +#define R_RAC_DIRECT_OFFSET_BE_LANE0_G2 0x3900 +#define R_RAC_DIRECT_OFFSET_BE_LANE1_G2 0x3980 + #define RTW89_PCI_WR_RETRY_CNT 20 /* Interrupts */ @@ -299,6 +310,7 @@ #define B_BE_L1SS_TIMEOUT_CTRL BIT(18) #define B_BE_ASPM_CTRL_L1 BIT(17) #define B_BE_ASPM_CTRL_L0 BIT(16) +#define B_BE_RTK_ASPM_CTRL_MASK GENMASK(17, 16) #define B_BE_XFER_PENDING_FW BIT(11) #define B_BE_XFER_PENDING BIT(10) #define B_BE_REQ_EXIT_L1 BIT(9) @@ -1276,6 +1288,21 @@ struct rtw89_pci_gen_def { void (*aspm_set)(struct rtw89_dev *rtwdev, bool enable); void (*clkreq_set)(struct rtw89_dev *rtwdev, bool enable); void (*l1ss_set)(struct rtw89_dev *rtwdev, bool enable); + + void (*disable_eq)(struct rtw89_dev *rtwdev); +}; + +#define RTW89_PCI_SSID(v, d, ssv, ssd, cust) \ + .vendor = v, .device = d, .subsystem_vendor = ssv, .subsystem_device = ssd, \ + .custid = RTW89_CUSTID_ ##cust + +struct rtw89_pci_ssid_quirk { + unsigned short vendor; + unsigned short device; + unsigned short subsystem_vendor; + unsigned short subsystem_device; + enum rtw89_custid custid; + unsigned long bitmap; /* bitmap of rtw89_quirks */ }; struct rtw89_pci_info { @@ -1331,6 +1358,8 @@ struct rtw89_pci_info { void (*recognize_intrs)(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); + + const struct rtw89_pci_ssid_quirk *ssid_quirks; }; struct rtw89_pci_tx_data { @@ -1600,6 +1629,7 @@ struct pci_device_id; int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtw89_pci_remove(struct pci_dev *pdev); +void rtw89_pci_basic_cfg(struct rtw89_dev *rtwdev, bool resume); void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev); int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en); int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en); @@ -1766,4 +1796,13 @@ static inline int rtw89_pci_poll_txdma_ch_idle(struct rtw89_dev *rtwdev) return gen_def->poll_txdma_ch_idle(rtwdev); } + +static inline void rtw89_pci_disable_eq(struct rtw89_dev *rtwdev) +{ + const struct rtw89_pci_info *info = rtwdev->pci_info; + const struct rtw89_pci_gen_def *gen_def = info->gen_def; + + gen_def->disable_eq(rtwdev); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 7cc32822296528..34154506f5d467 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -550,6 +550,79 @@ static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev) return 0; } +static void rtw89_pci_disable_eq_be(struct rtw89_dev *rtwdev) +{ + u32 backup_aspm, phy_offset; + u16 oobs_val, offset_cal; + u16 g1_oobs, g2_oobs; + u8 gen; + + if (rtwdev->chip->chip_id != RTL8922A) + return; + + g1_oobs = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 + + RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL); + g2_oobs = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G2 + + RAC_ANA09 * RAC_MULT, BAC_OOBS_SEL); + if (g1_oobs && g2_oobs) + return; + + backup_aspm = rtw89_read32(rtwdev, R_BE_PCIE_MIX_CFG); + rtw89_write32_clr(rtwdev, R_BE_PCIE_MIX_CFG, B_BE_RTK_ASPM_CTRL_MASK); + + /* offset K */ + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 : + R_RAC_DIRECT_OFFSET_BE_LANE0_G2; + + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT, + B_PCIE_BIT_RD_SEL); + } + + offset_cal = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 + + RAC_ANA1F * RAC_MULT, OFFSET_CAL_MASK); + + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 : + R_RAC_DIRECT_OFFSET_BE_LANE0_G2; + + rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA0B * RAC_MULT, + MANUAL_LVL_MASK, offset_cal); + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT, + OFFSET_CAL_MODE); + } + + /* OOBS */ + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 : + R_RAC_DIRECT_OFFSET_BE_LANE0_G2; + + rtw89_write16_set(rtwdev, phy_offset + RAC_ANA0D * RAC_MULT, + BAC_RX_TEST_EN); + rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT, + ADDR_SEL_MASK, ADDR_SEL_VAL); + rtw89_write16_clr(rtwdev, phy_offset + RAC_ANA10 * RAC_MULT, + B_PCIE_BIT_PINOUT_DIS); + rtw89_write16_set(rtwdev, phy_offset + RAC_ANA19 * RAC_MULT, + B_PCIE_BIT_RD_SEL); + } + + oobs_val = rtw89_read16_mask(rtwdev, R_RAC_DIRECT_OFFSET_BE_LANE0_G1 + + RAC_ANA1F * RAC_MULT, OOBS_LEVEL_MASK); + + for (gen = 1; gen <= 2; gen++) { + phy_offset = gen == 1 ? R_RAC_DIRECT_OFFSET_BE_LANE0_G1 : + R_RAC_DIRECT_OFFSET_BE_LANE0_G2; + + rtw89_write16_mask(rtwdev, phy_offset + RAC_ANA03 * RAC_MULT, + OOBS_SEN_MASK, oobs_val); + rtw89_write16_set(rtwdev, phy_offset + RAC_ANA09 * RAC_MULT, + BAC_OOBS_SEL); + } + + rtw89_write32(rtwdev, R_BE_PCIE_MIX_CFG, backup_aspm); +} + static int __maybe_unused rtw89_pci_suspend_be(struct device *dev) { struct ieee80211_hw *hw = dev_get_drvdata(dev); @@ -584,6 +657,8 @@ static int __maybe_unused rtw89_pci_resume_be(struct device *dev) rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN); rtw89_write32_set(rtwdev, R_BE_REG_PL1_MASK, B_BE_SER_PM_MASTER_IMR); + rtw89_pci_basic_cfg(rtwdev, true); + return 0; } @@ -614,5 +689,7 @@ const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .aspm_set = rtw89_pci_aspm_set_be, .clkreq_set = rtw89_pci_clkreq_set_be, .l1ss_set = rtw89_pci_l1ss_set_be, + + .disable_eq = rtw89_pci_disable_eq_be, }; EXPORT_SYMBOL(rtw89_pci_gen_be); diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index c7165e757842be..f24aca663cf008 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -75,12 +75,12 @@ static u64 get_mcs_ra_mask(u16 mcs_map, u8 highest_mcs, u8 gap) return ra_mask; } -static u64 get_he_ra_mask(struct ieee80211_sta *sta) +static u64 get_he_ra_mask(struct ieee80211_link_sta *link_sta) { - struct ieee80211_sta_he_cap cap = sta->deflink.he_cap; + struct ieee80211_sta_he_cap cap = link_sta->he_cap; u16 mcs_map; - switch (sta->deflink.bandwidth) { + switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_160: if (cap.he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) @@ -118,14 +118,14 @@ static u64 get_eht_mcs_ra_mask(u8 *max_nss, u8 start_mcs, u8 n_nss) return mask; } -static u64 get_eht_ra_mask(struct ieee80211_sta *sta) +static u64 get_eht_ra_mask(struct ieee80211_link_sta *link_sta) { - struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; struct ieee80211_eht_mcs_nss_supp_20mhz_only *mcs_nss_20mhz; struct ieee80211_eht_mcs_nss_supp_bw *mcs_nss; - u8 *he_phy_cap = sta->deflink.he_cap.he_cap_elem.phy_cap_info; + u8 *he_phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info; - switch (sta->deflink.bandwidth) { + switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_320: mcs_nss = &eht_cap->eht_mcs_nss_supp.bw._320; /* MCS 9, 11, 13 */ @@ -195,15 +195,16 @@ static u64 rtw89_phy_ra_mask_recover(u64 ra_mask, u64 ra_mask_bak) return ra_mask; } -static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link, + struct ieee80211_link_sta *link_sta, const struct rtw89_chan *chan) { - struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta); - struct cfg80211_bitrate_mask *mask = &rtwsta->mask; + struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask; enum nl80211_band band; u64 cfg_mask; - if (!rtwsta->use_cfg_mask) + if (!rtwsta_link->use_cfg_mask) return -1; switch (chan->band_type) { @@ -227,17 +228,17 @@ static u64 rtw89_phy_ra_mask_cfg(struct rtw89_dev *rtwdev, struct rtw89_sta *rtw return -1; } - if (sta->deflink.he_cap.has_he) { + if (link_sta->he_cap.has_he) { cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[0], RA_MASK_HE_1SS_RATES); cfg_mask |= u64_encode_bits(mask->control[band].he_mcs[1], RA_MASK_HE_2SS_RATES); - } else if (sta->deflink.vht_cap.vht_supported) { + } else if (link_sta->vht_cap.vht_supported) { cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0], RA_MASK_VHT_1SS_RATES); cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1], RA_MASK_VHT_2SS_RATES); - } else if (sta->deflink.ht_cap.ht_supported) { + } else if (link_sta->ht_cap.ht_supported) { cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0], RA_MASK_HT_1SS_RATES); cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1], @@ -261,17 +262,17 @@ rtw89_ra_mask_eht_rates[4] = {RA_MASK_EHT_1SS_RATES, RA_MASK_EHT_2SS_RATES, RA_MASK_EHT_3SS_RATES, RA_MASK_EHT_4SS_RATES}; static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev, - struct rtw89_sta *rtwsta, + struct rtw89_sta_link *rtwsta_link, const struct rtw89_chan *chan, bool *fix_giltf_en, u8 *fix_giltf) { - struct cfg80211_bitrate_mask *mask = &rtwsta->mask; + struct cfg80211_bitrate_mask *mask = &rtwsta_link->mask; u8 band = chan->band_type; enum nl80211_band nl_band = rtw89_hw_to_nl80211_band(band); u8 he_gi = mask->control[nl_band].he_gi; u8 he_ltf = mask->control[nl_band].he_ltf; - if (!rtwsta->use_cfg_mask) + if (!rtwsta_link->use_cfg_mask) return; if (he_ltf == 2 && he_gi == 2) { @@ -295,17 +296,17 @@ static void rtw89_phy_ra_gi_ltf(struct rtw89_dev *rtwdev, } static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, - struct ieee80211_sta *sta, bool csi) + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + struct ieee80211_link_sta *link_sta, + bool p2p, bool csi) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; - struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern; - struct rtw89_ra_info *ra = &rtwsta->ra; + struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif_link->rate_pattern; + struct rtw89_ra_info *ra = &rtwsta_link->ra; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); - struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif); + rtwvif_link->chanctx_idx); const u64 *high_rate_masks = rtw89_ra_mask_ht_rates; - u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi); + u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi); u64 ra_mask = 0; u64 ra_mask_bak; u8 mode = 0; @@ -320,65 +321,65 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, memset(ra, 0, sizeof(*ra)); /* Set the ra mask from sta's capability */ - if (sta->deflink.eht_cap.has_eht) { + if (link_sta->eht_cap.has_eht) { mode |= RTW89_RA_MODE_EHT; - ra_mask |= get_eht_ra_mask(sta); + ra_mask |= get_eht_ra_mask(link_sta); high_rate_masks = rtw89_ra_mask_eht_rates; - } else if (sta->deflink.he_cap.has_he) { + } else if (link_sta->he_cap.has_he) { mode |= RTW89_RA_MODE_HE; csi_mode = RTW89_RA_RPT_MODE_HE; - ra_mask |= get_he_ra_mask(sta); + ra_mask |= get_he_ra_mask(link_sta); high_rate_masks = rtw89_ra_mask_he_rates; - if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[2] & + if (link_sta->he_cap.he_cap_elem.phy_cap_info[2] & IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) stbc_en = 1; - if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[1] & + if (link_sta->he_cap.he_cap_elem.phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) ldpc_en = 1; - rtw89_phy_ra_gi_ltf(rtwdev, rtwsta, chan, &fix_giltf_en, &fix_giltf); - } else if (sta->deflink.vht_cap.vht_supported) { - u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); + rtw89_phy_ra_gi_ltf(rtwdev, rtwsta_link, chan, &fix_giltf_en, &fix_giltf); + } else if (link_sta->vht_cap.vht_supported) { + u16 mcs_map = le16_to_cpu(link_sta->vht_cap.vht_mcs.rx_mcs_map); mode |= RTW89_RA_MODE_VHT; csi_mode = RTW89_RA_RPT_MODE_VHT; /* MCS9 (non-20MHz), MCS8, MCS7 */ - if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) + if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20) ra_mask |= get_mcs_ra_mask(mcs_map, 8, 1); else ra_mask |= get_mcs_ra_mask(mcs_map, 9, 1); high_rate_masks = rtw89_ra_mask_vht_rates; - if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) + if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) stbc_en = 1; - if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) + if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) ldpc_en = 1; - } else if (sta->deflink.ht_cap.ht_supported) { + } else if (link_sta->ht_cap.ht_supported) { mode |= RTW89_RA_MODE_HT; csi_mode = RTW89_RA_RPT_MODE_HT; - ra_mask |= ((u64)sta->deflink.ht_cap.mcs.rx_mask[3] << 48) | - ((u64)sta->deflink.ht_cap.mcs.rx_mask[2] << 36) | - ((u64)sta->deflink.ht_cap.mcs.rx_mask[1] << 24) | - ((u64)sta->deflink.ht_cap.mcs.rx_mask[0] << 12); + ra_mask |= ((u64)link_sta->ht_cap.mcs.rx_mask[3] << 48) | + ((u64)link_sta->ht_cap.mcs.rx_mask[2] << 36) | + ((u64)link_sta->ht_cap.mcs.rx_mask[1] << 24) | + ((u64)link_sta->ht_cap.mcs.rx_mask[0] << 12); high_rate_masks = rtw89_ra_mask_ht_rates; - if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) + if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC) stbc_en = 1; - if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) + if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) ldpc_en = 1; } switch (chan->band_type) { case RTW89_BAND_2G: - ra_mask |= sta->deflink.supp_rates[NL80211_BAND_2GHZ]; - if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xf) + ra_mask |= link_sta->supp_rates[NL80211_BAND_2GHZ]; + if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xf) mode |= RTW89_RA_MODE_CCK; - if (sta->deflink.supp_rates[NL80211_BAND_2GHZ] & 0xff0) + if (link_sta->supp_rates[NL80211_BAND_2GHZ] & 0xff0) mode |= RTW89_RA_MODE_OFDM; break; case RTW89_BAND_5G: - ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_5GHZ] << 4; + ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_5GHZ] << 4; mode |= RTW89_RA_MODE_OFDM; break; case RTW89_BAND_6G: - ra_mask |= (u64)sta->deflink.supp_rates[NL80211_BAND_6GHZ] << 4; + ra_mask |= (u64)link_sta->supp_rates[NL80211_BAND_6GHZ] << 4; mode |= RTW89_RA_MODE_OFDM; break; default: @@ -405,48 +406,48 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, ra_mask &= rtw89_phy_ra_mask_rssi(rtwdev, rssi, 0); ra_mask = rtw89_phy_ra_mask_recover(ra_mask, ra_mask_bak); - ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta, chan); + ra_mask &= rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan); - switch (sta->deflink.bandwidth) { + switch (link_sta->bandwidth) { case IEEE80211_STA_RX_BW_160: bw_mode = RTW89_CHANNEL_WIDTH_160; - sgi = sta->deflink.vht_cap.vht_supported && - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); + sgi = link_sta->vht_cap.vht_supported && + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160); break; case IEEE80211_STA_RX_BW_80: bw_mode = RTW89_CHANNEL_WIDTH_80; - sgi = sta->deflink.vht_cap.vht_supported && - (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); + sgi = link_sta->vht_cap.vht_supported && + (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); break; case IEEE80211_STA_RX_BW_40: bw_mode = RTW89_CHANNEL_WIDTH_40; - sgi = sta->deflink.ht_cap.ht_supported && - (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40); + sgi = link_sta->ht_cap.ht_supported && + (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); break; default: bw_mode = RTW89_CHANNEL_WIDTH_20; - sgi = sta->deflink.ht_cap.ht_supported && - (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20); + sgi = link_sta->ht_cap.ht_supported && + (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); break; } - if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[3] & + if (link_sta->he_cap.he_cap_elem.phy_cap_info[3] & IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM) ra->dcm_cap = 1; - if (rate_pattern->enable && !vif->p2p) { - ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta, chan); + if (rate_pattern->enable && !p2p) { + ra_mask = rtw89_phy_ra_mask_cfg(rtwdev, rtwsta_link, link_sta, chan); ra_mask &= rate_pattern->ra_mask; mode = rate_pattern->ra_mode; } ra->bw_cap = bw_mode; - ra->er_cap = rtwsta->er_cap; + ra->er_cap = rtwsta_link->er_cap; ra->mode_ctrl = mode; - ra->macid = rtwsta->mac_id; + ra->macid = rtwsta_link->mac_id; ra->stbc_cap = stbc_en; ra->ldpc_cap = ldpc_en; - ra->ss_num = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; + ra->ss_num = min(link_sta->rx_nss, rtwdev->hal.tx_nss) - 1; ra->en_sgi = sgi; ra->ra_mask = ra_mask; ra->fix_giltf_en = fix_giltf_en; @@ -458,20 +459,29 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, ra->fixed_csi_rate_en = false; ra->ra_csi_rate_en = true; ra->cr_tbl_sel = false; - ra->band_num = rtwvif->phy_idx; + ra->band_num = rtwvif_link->phy_idx; ra->csi_bw = bw_mode; ra->csi_gi_ltf = RTW89_GILTF_LGI_4XHE32; ra->csi_mcs_ss_idx = 5; ra->csi_mode = csi_mode; } -void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, - u32 changed) +static void __rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_sta_link *rtwsta_link, + u32 changed) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_ra_info *ra = &rtwsta->ra; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_ra_info *ra = &rtwsta_link->ra; + struct ieee80211_link_sta *link_sta; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link, + link_sta, vif->p2p, false); - rtw89_phy_ra_sta_update(rtwdev, sta, false); + rcu_read_unlock(); if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) ra->upd_mask = 1; @@ -489,6 +499,20 @@ void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta rtw89_fw_h2c_ra(rtwdev, ra, false); } +void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, + u32 changed) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + __rtw89_phy_ra_update_sta(rtwdev, rtwvif_link, rtwsta_link, changed); + } +} + static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next, u16 rate_base, u64 ra_mask, u8 ra_mode, u32 rate_ctrl, u32 ctrl_skip, bool force) @@ -523,15 +547,15 @@ static bool __check_rate_pattern(struct rtw89_phy_rate_pattern *next, [RTW89_CHIP_BE] = RTW89_HW_RATE_V1_ ## rate, \ } -void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif, - const struct cfg80211_bitrate_mask *mask) +static +void __rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + const struct cfg80211_bitrate_mask *mask) { struct ieee80211_supported_band *sband; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_phy_rate_pattern next_pattern = {0}; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); static const u16 hw_rate_he[][RTW89_CHIP_GEN_NUM] = { RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS1_MCS0), RTW89_HW_RATE_BY_CHIP_GEN(HE_NSS2_MCS0), @@ -600,7 +624,7 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, if (!next_pattern.enable) goto out; - rtwvif->rate_pattern = next_pattern; + rtwvif_link->rate_pattern = next_pattern; rtw89_debug(rtwdev, RTW89_DBG_RA, "configure pattern: rate 0x%x, mask 0x%llx, mode 0x%x\n", next_pattern.rate, @@ -609,10 +633,22 @@ void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, return; out: - rtwvif->rate_pattern.enable = false; + rtwvif_link->rate_pattern.enable = false; rtw89_debug(rtwdev, RTW89_DBG_RA, "unset rate pattern\n"); } +void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + __rtw89_phy_rate_pattern_vif(rtwdev, rtwvif_link, mask); +} + static void rtw89_phy_ra_update_sta_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_dev *rtwdev = (struct rtw89_dev *)data; @@ -627,14 +663,24 @@ void rtw89_phy_ra_update(struct rtw89_dev *rtwdev) rtwdev); } -void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta) +void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_ra_info *ra = &rtwsta->ra; - u8 rssi = ewma_rssi_read(&rtwsta->avg_rssi) >> RSSI_FACTOR; - bool csi = rtw89_sta_has_beamformer_cap(sta); + struct rtw89_vif_link *rtwvif_link = rtwsta_link->rtwvif_link; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_ra_info *ra = &rtwsta_link->ra; + u8 rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR; + struct ieee80211_link_sta *link_sta; + bool csi; + + rcu_read_lock(); + + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, true); + csi = rtw89_sta_has_beamformer_cap(link_sta); - rtw89_phy_ra_sta_update(rtwdev, sta, csi); + rtw89_phy_ra_sta_update(rtwdev, rtwvif_link, rtwsta_link, + link_sta, vif->p2p, csi); + + rcu_read_unlock(); if (rssi > 40) ra->init_rate_lv = 1; @@ -1068,14 +1114,21 @@ static bool rtw89_chip_rf_v1(struct rtw89_dev *rtwdev) return rtwdev->chip->ops->write_rf == rtw89_phy_write_rf_v1; } -static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev, - enum rtw89_phy_idx phy_idx) +static void __rtw89_phy_bb_reset(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; chip->ops->bb_reset(rtwdev, phy_idx); } +static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev) +{ + __rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0); + if (rtwdev->dbcc_en) + __rtw89_phy_bb_reset(rtwdev, RTW89_PHY_1); +} + static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg, enum rtw89_rf_path rf_path, @@ -1621,13 +1674,15 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev) if (rtwdev->dbcc_en) rtw89_phy_init_reg(rtwdev, bb_table, rtw89_phy_config_bb_reg, (void *)RTW89_PHY_1); - rtw89_chip_init_txpwr_unit(rtwdev, RTW89_PHY_0); + + rtw89_chip_init_txpwr_unit(rtwdev); bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table; if (bb_gain_table) rtw89_phy_init_reg(rtwdev, bb_gain_table, chip->phy_def->config_bb_gain, NULL); - rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0); + + rtw89_phy_bb_reset(rtwdev); } static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev) @@ -1747,6 +1802,24 @@ void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, } EXPORT_SYMBOL(rtw89_phy_write32_idx); +void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits, + enum rtw89_phy_idx phy_idx) +{ + if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1) + addr += rtw89_phy0_phy1_offset(rtwdev, addr); + rtw89_phy_write32_set(rtwdev, addr, bits); +} +EXPORT_SYMBOL(rtw89_phy_write32_idx_set); + +void rtw89_phy_write32_idx_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bits, + enum rtw89_phy_idx phy_idx) +{ + if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1) + addr += rtw89_phy0_phy1_offset(rtwdev, addr); + rtw89_phy_write32_clr(rtwdev, addr, bits); +} +EXPORT_SYMBOL(rtw89_phy_write32_idx_clr); + u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, enum rtw89_phy_idx phy_idx) { @@ -2553,14 +2626,14 @@ struct rtw89_phy_iter_ra_data { struct sk_buff *c2h; }; -static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) +static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link, + struct ieee80211_link_sta *link_sta, + struct rtw89_phy_iter_ra_data *ra_data) { - struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data; struct rtw89_dev *rtwdev = ra_data->rtwdev; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; const struct rtw89_c2h_ra_rpt *c2h = (const struct rtw89_c2h_ra_rpt *)ra_data->c2h->data; - struct rtw89_ra_report *ra_report = &rtwsta->ra_report; + struct rtw89_ra_report *ra_report = &rtwsta_link->ra_report; const struct rtw89_chip_info *chip = rtwdev->chip; bool format_v1 = chip->chip_gen == RTW89_CHIP_BE; u8 mode, rate, bw, giltf, mac_id; @@ -2570,7 +2643,7 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) u8 t; mac_id = le32_get_bits(c2h->w2, RTW89_C2H_RA_RPT_W2_MACID); - if (mac_id != rtwsta->mac_id) + if (mac_id != rtwsta_link->mac_id) return; rate = le32_get_bits(c2h->w3, RTW89_C2H_RA_RPT_W3_MCSNSS); @@ -2661,8 +2734,26 @@ static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) u16_encode_bits(mode, RTW89_HW_RATE_MASK_MOD) | u16_encode_bits(rate, RTW89_HW_RATE_MASK_VAL); ra_report->might_fallback_legacy = mcs <= 2; - sta->deflink.agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report); - rtwsta->max_agg_wait = sta->deflink.agg.max_rc_amsdu_len / 1500 - 1; + link_sta->agg.max_rc_amsdu_len = get_max_amsdu_len(rtwdev, ra_report); + rtwsta_link->max_agg_wait = link_sta->agg.max_rc_amsdu_len / 1500 - 1; +} + +static void rtw89_phy_c2h_ra_rpt_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_phy_iter_ra_data *ra_data = (struct rtw89_phy_iter_ra_data *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; + + rcu_read_lock(); + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + link_sta = rtw89_sta_rcu_dereference_link(rtwsta_link, false); + __rtw89_phy_c2h_ra_rpt_iter(rtwsta_link, link_sta, ra_data); + } + + rcu_read_unlock(); } static void @@ -2692,9 +2783,85 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, struct rtw89_c2h_rf_txgapk_rpt_log *txgapk; struct rtw89_c2h_rf_rxdck_rpt_log *rxdck; struct rtw89_c2h_rf_dack_rpt_log *dack; + struct rtw89_c2h_rf_tssi_rpt_log *tssi; struct rtw89_c2h_rf_dpk_rpt_log *dpk; + struct rtw89_c2h_rf_iqk_rpt_log *iqk; + int i, j, k; switch (func) { + case RTW89_PHY_C2H_RFK_LOG_FUNC_IQK: + if (len != sizeof(*iqk)) + goto out; + + iqk = content; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_iqk_init = %x\n", iqk->is_iqk_init); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_reload = %x\n", iqk->is_reload); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_nbiqk = %x\n", iqk->is_nbiqk); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->txiqk_en = %x\n", iqk->txiqk_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->rxiqk_en = %x\n", iqk->rxiqk_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->lok_en = %x\n", iqk->lok_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->iqk_xym_en = %x\n", iqk->iqk_xym_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->iqk_sram_en = %x\n", iqk->iqk_sram_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->iqk_fft_en = %x\n", iqk->iqk_fft_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_fw_iqk = %x\n", iqk->is_fw_iqk); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->is_iqk_enable = %x\n", iqk->is_iqk_enable); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->iqk_cfir_en = %x\n", iqk->iqk_cfir_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->thermal_rek_en = %x\n", iqk->thermal_rek_en); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->version = %x\n", iqk->version); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->phy = %x\n", iqk->phy); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->fwk_status = %x\n", iqk->fwk_status); + + for (i = 0; i < 2; i++) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] ======== Path %x ========\n", i); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_band[%d] = %x\n", + i, iqk->iqk_band[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_ch[%d] = %x\n", + i, iqk->iqk_ch[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_bw[%d] = %x\n", + i, iqk->iqk_bw[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_idac[%d] = %x\n", + i, le32_to_cpu(iqk->lok_idac[i])); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_vbuf[%d] = %x\n", + i, le32_to_cpu(iqk->lok_vbuf[i])); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_tx_fail[%d] = %x\n", + i, iqk->iqk_tx_fail[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_rx_fail[%d] = %x\n", + i, iqk->iqk_rx_fail[i]); + for (j = 0; j < 4; j++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->rftxgain[%d][%d] = %x\n", + i, j, le32_to_cpu(iqk->rftxgain[i][j])); + for (j = 0; j < 4; j++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->tx_xym[%d][%d] = %x\n", + i, j, le32_to_cpu(iqk->tx_xym[i][j])); + for (j = 0; j < 4; j++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->rfrxgain[%d][%d] = %x\n", + i, j, le32_to_cpu(iqk->rfrxgain[i][j])); + for (j = 0; j < 4; j++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK] iqk->rx_xym[%d][%d] = %x\n", + i, j, le32_to_cpu(iqk->rx_xym[i][j])); + } + return; case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK: if (len != sizeof(*dpk)) goto out; @@ -2716,8 +2883,23 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, dack = content; - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]ver=0x%x 0x%x\n", - dack->fwdack_ver, dack->fwdack_rpt_ver); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]FWDACK SUMMARY!!!!!\n"); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]FWDACK ver = 0x%x, FWDACK rpt_ver = 0x%x, driver rpt_ver = 0x%x\n", + dack->fwdack_ver, dack->fwdack_info_ver, 0x2); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]timeout code = [0x%x 0x%x 0x%x 0x%x 0x%x]\n", + dack->addck_timeout, dack->cdack_timeout, dack->dadck_timeout, + dack->adgaink_timeout, dack->msbk_timeout); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]DACK fail = 0x%x\n", dack->dack_fail); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S0 WBADCK = [0x%x]\n", dack->wbdck_d[0]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]S1 WBADCK = [0x%x]\n", dack->wbdck_d[1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]DRCK = [0x%x]\n", dack->rck_d); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK ic = [0x%x, 0x%x]\n", dack->cdack_d[0][0][0], dack->cdack_d[0][0][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK qc = [0x%x, 0x%x]\n", @@ -2728,13 +2910,17 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, dack->cdack_d[1][1][0], dack->cdack_d[1][1][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK ic = [0x%x, 0x%x]\n", - dack->addck2_d[0][0][0], dack->addck2_d[0][0][1]); + ((u32)dack->addck2_hd[0][0][0] << 8) | dack->addck2_ld[0][0][0], + ((u32)dack->addck2_hd[0][0][1] << 8) | dack->addck2_ld[0][0][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK qc = [0x%x, 0x%x]\n", - dack->addck2_d[0][1][0], dack->addck2_d[0][1][1]); + ((u32)dack->addck2_hd[0][1][0] << 8) | dack->addck2_ld[0][1][0], + ((u32)dack->addck2_hd[0][1][1] << 8) | dack->addck2_ld[0][1][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK ic = [0x%x, 0x%x]\n", - dack->addck2_d[1][0][0], dack->addck2_d[1][0][1]); + ((u32)dack->addck2_hd[1][0][0] << 8) | dack->addck2_ld[1][0][0], + ((u32)dack->addck2_hd[1][0][1] << 8) | dack->addck2_ld[1][0][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK qc = [0x%x, 0x%x]\n", - dack->addck2_d[1][1][0], dack->addck2_d[1][1][1]); + ((u32)dack->addck2_hd[1][1][0] << 8) | dack->addck2_ld[1][1][0], + ((u32)dack->addck2_hd[1][1][1] << 8) | dack->addck2_ld[1][1][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_GAINK ic = 0x%x, qc = 0x%x\n", dack->adgaink_d[0][0], dack->adgaink_d[0][1]); @@ -2747,18 +2933,29 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, dack->dadck_d[1][0], dack->dadck_d[1][1]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 biask iqc = 0x%x\n", - dack->biask_d[0][0]); + ((u32)dack->biask_hd[0][0] << 8) | dack->biask_ld[0][0]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 biask iqc = 0x%x\n", - dack->biask_d[1][0]); - - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic: %*ph\n", - (int)sizeof(dack->msbk_d[0][0]), dack->msbk_d[0][0]); - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc: %*ph\n", - (int)sizeof(dack->msbk_d[0][1]), dack->msbk_d[0][1]); - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic: %*ph\n", - (int)sizeof(dack->msbk_d[1][0]), dack->msbk_d[1][0]); - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc: %*ph\n", - (int)sizeof(dack->msbk_d[1][1]), dack->msbk_d[1][1]); + ((u32)dack->biask_hd[1][0] << 8) | dack->biask_ld[1][0]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic:\n"); + for (i = 0; i < 0x10; i++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", + dack->msbk_d[0][0][i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc:\n"); + for (i = 0; i < 0x10; i++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", + dack->msbk_d[0][1][i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic:\n"); + for (i = 0; i < 0x10; i++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", + dack->msbk_d[1][0][i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc:\n"); + for (i = 0; i < 0x10; i++) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", + dack->msbk_d[1][1][i]); return; case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK: if (len != sizeof(*rxdck)) @@ -2770,6 +2967,39 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, rxdck->ver, rxdck->band, rxdck->bw, rxdck->ch, rxdck->timeout); return; + case RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI: + if (len != sizeof(*tssi)) + goto out; + + tssi = content; + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 4; k++) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] alignment_power_cw_h[%d][%d][%d]=%d\n", + i, j, k, tssi->alignment_power_cw_h[i][j][k]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] alignment_power_cw_l[%d][%d][%d]=%d\n", + i, j, k, tssi->alignment_power_cw_l[i][j][k]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] alignment_power[%d][%d][%d]=%d\n", + i, j, k, tssi->alignment_power[i][j][k]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] alignment_power_cw[%d][%d][%d]=%d\n", + i, j, k, + (tssi->alignment_power_cw_h[i][j][k] << 8) + + tssi->alignment_power_cw_l[i][j][k]); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] tssi_alimk_state[%d][%d]=%d\n", + i, j, tssi->tssi_alimk_state[i][j]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI] default_txagc_offset[%d]=%d\n", + j, tssi->default_txagc_offset[0][j]); + } + } + return; case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK: if (len != sizeof(*txgapk)) goto out; @@ -3171,13 +3401,13 @@ EXPORT_SYMBOL(rtw89_phy_rfk_dack_and_wait); int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, - unsigned int ms) + bool is_chl_k, unsigned int ms) { int ret; rtw89_phy_rfk_report_prep(rtwdev); - ret = rtw89_fw_h2c_rf_rxdck(rtwdev, phy_idx, chan); + ret = rtw89_fw_h2c_rf_rxdck(rtwdev, phy_idx, chan, is_chl_k); if (ret) return ret; @@ -4290,33 +4520,33 @@ void rtw89_phy_cfo_parse(struct rtw89_dev *rtwdev, s16 cfo_val, cfo->packet_count++; } -void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, - rtwvif->chanctx_idx); + rtwvif_link->chanctx_idx); struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info; if (!chip->ul_tb_waveform_ctrl) return; - rtwvif->def_tri_idx = + rtwvif_link->def_tri_idx = rtw89_phy_read32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG); if (chip->chip_id == RTL8852B && rtwdev->hal.cv > CHIP_CBV) - rtwvif->dyn_tb_bedge_en = false; + rtwvif_link->dyn_tb_bedge_en = false; else if (chan->band_type >= RTW89_BAND_5G && chan->band_width >= RTW89_CHANNEL_WIDTH_40) - rtwvif->dyn_tb_bedge_en = true; + rtwvif_link->dyn_tb_bedge_en = true; else - rtwvif->dyn_tb_bedge_en = false; + rtwvif_link->dyn_tb_bedge_en = false; rtw89_debug(rtwdev, RTW89_DBG_UL_TB, "[ULTB] def_if_bandedge=%d, def_tri_idx=%d\n", - ul_tb_info->def_if_bandedge, rtwvif->def_tri_idx); + ul_tb_info->def_if_bandedge, rtwvif_link->def_tri_idx); rtw89_debug(rtwdev, RTW89_DBG_UL_TB, "[ULTB] dyn_tb_begde_en=%d, dyn_tb_tri_en=%d\n", - rtwvif->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en); + rtwvif_link->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en); } struct rtw89_phy_ul_tb_check_data { @@ -4338,7 +4568,7 @@ struct rtw89_phy_power_diff { }; static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { static const struct rtw89_phy_power_diff table[2] = { {0x0, 0x0, 0x0, 0x0, 0xf4, 0x3, 0x3}, @@ -4350,13 +4580,13 @@ static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev, if (!rtwdev->chip->ul_tb_pwr_diff) return; - if (rtwvif->pwr_diff_en == rtwvif->pre_pwr_diff_en) { - rtwvif->pwr_diff_en = false; + if (rtwvif_link->pwr_diff_en == rtwvif_link->pre_pwr_diff_en) { + rtwvif_link->pwr_diff_en = false; return; } - rtwvif->pre_pwr_diff_en = rtwvif->pwr_diff_en; - param = &table[rtwvif->pwr_diff_en]; + rtwvif_link->pre_pwr_diff_en = rtwvif_link->pwr_diff_en; + param = &table[rtwvif_link->pwr_diff_en]; rtw89_phy_write32_mask(rtwdev, R_Q_MATRIX_00, B_Q_MATRIX_00_REAL, param->q_00); @@ -4365,32 +4595,32 @@ static void rtw89_phy_ofdma_power_diff(struct rtw89_dev *rtwdev, rtw89_phy_write32_mask(rtwdev, R_CUSTOMIZE_Q_MATRIX, B_CUSTOMIZE_Q_MATRIX_EN, param->q_matrix_en); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_1T, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_NORM_BW160, param->ultb_1t_norm_160); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PWR_UL_TB_2T, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_NORM_BW160, param->ultb_2t_norm_160); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM1, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM1, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_PATH_COM1_NORM_1STS, param->com1_norm_1sts); - reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM2, rtwvif->mac_idx); + reg = rtw89_mac_reg_by_idx(rtwdev, R_AX_PATH_COM2, rtwvif_link->mac_idx); rtw89_write32_mask(rtwdev, reg, B_AX_PATH_COM2_RESP_1STS_PATH, param->com2_resp_1sts_path); } static void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct rtw89_phy_ul_tb_check_data *ul_tb_data) { struct rtw89_traffic_stats *stats = &rtwdev->stats; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION) + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION) return; if (!vif->cfg.assoc) @@ -4403,11 +4633,11 @@ void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev, ul_tb_data->low_tf_client = true; ul_tb_data->valid = true; - ul_tb_data->def_tri_idx = rtwvif->def_tri_idx; - ul_tb_data->dyn_tb_bedge_en = rtwvif->dyn_tb_bedge_en; + ul_tb_data->def_tri_idx = rtwvif_link->def_tri_idx; + ul_tb_data->dyn_tb_bedge_en = rtwvif_link->dyn_tb_bedge_en; } - rtw89_phy_ofdma_power_diff(rtwdev, rtwvif); + rtw89_phy_ofdma_power_diff(rtwdev, rtwvif_link); } static void rtw89_phy_ul_tb_waveform_ctrl(struct rtw89_dev *rtwdev, @@ -4453,7 +4683,9 @@ void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_phy_ul_tb_check_data ul_tb_data = {}; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; if (!chip->ul_tb_waveform_ctrl && !chip->ul_tb_pwr_diff) return; @@ -4462,7 +4694,8 @@ void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev) return; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif, &ul_tb_data); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif_link, &ul_tb_data); if (!ul_tb_data.valid) return; @@ -4603,11 +4836,36 @@ static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev) rtw89_phy_antdiv_reg_init(rtwdev); } +static void rtw89_phy_thermal_protect(struct rtw89_dev *rtwdev) +{ + struct rtw89_phy_stat *phystat = &rtwdev->phystat; + struct rtw89_hal *hal = &rtwdev->hal; + u8 th_max = phystat->last_thermal_max; + u8 lv = hal->thermal_prot_lv; + + if (!hal->thermal_prot_th || + (hal->disabled_dm_bitmap & BIT(RTW89_DM_THERMAL_PROTECT))) + return; + + if (th_max > hal->thermal_prot_th && lv < RTW89_THERMAL_PROT_LV_MAX) + lv++; + else if (th_max < hal->thermal_prot_th - 2 && lv > 0) + lv--; + else + return; + + hal->thermal_prot_lv = lv; + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "thermal protection lv=%d\n", lv); + + rtw89_fw_h2c_tx_duty(rtwdev, hal->thermal_prot_lv); +} + static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev) { struct rtw89_phy_stat *phystat = &rtwdev->phystat; + u8 th, th_max = 0; int i; - u8 th; for (i = 0; i < rtwdev->chip->rf_path_num; i++) { th = rtw89_chip_get_thermal(rtwdev, i); @@ -4617,7 +4875,11 @@ static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, "path(%d) thermal cur=%u avg=%ld", i, th, ewma_thermal_read(&phystat->avg_thermal[i])); + + th_max = max(th_max, th); } + + phystat->last_thermal_max = th_max; } struct rtw89_phy_iter_rssi_data { @@ -4626,30 +4888,42 @@ struct rtw89_phy_iter_rssi_data { bool rssi_changed; }; -static void rtw89_phy_stat_rssi_update_iter(void *data, - struct ieee80211_sta *sta) +static +void __rtw89_phy_stat_rssi_update_iter(struct rtw89_sta_link *rtwsta_link, + struct rtw89_phy_iter_rssi_data *rssi_data) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_phy_iter_rssi_data *rssi_data = - (struct rtw89_phy_iter_rssi_data *)data; struct rtw89_phy_ch_info *ch_info = rssi_data->ch_info; unsigned long rssi_curr; - rssi_curr = ewma_rssi_read(&rtwsta->avg_rssi); + rssi_curr = ewma_rssi_read(&rtwsta_link->avg_rssi); if (rssi_curr < ch_info->rssi_min) { ch_info->rssi_min = rssi_curr; - ch_info->rssi_min_macid = rtwsta->mac_id; + ch_info->rssi_min_macid = rtwsta_link->mac_id; } - if (rtwsta->prev_rssi == 0) { - rtwsta->prev_rssi = rssi_curr; - } else if (abs((int)rtwsta->prev_rssi - (int)rssi_curr) > (3 << RSSI_FACTOR)) { - rtwsta->prev_rssi = rssi_curr; + if (rtwsta_link->prev_rssi == 0) { + rtwsta_link->prev_rssi = rssi_curr; + } else if (abs((int)rtwsta_link->prev_rssi - (int)rssi_curr) > + (3 << RSSI_FACTOR)) { + rtwsta_link->prev_rssi = rssi_curr; rssi_data->rssi_changed = true; } } +static void rtw89_phy_stat_rssi_update_iter(void *data, + struct ieee80211_sta *sta) +{ + struct rtw89_phy_iter_rssi_data *rssi_data = + (struct rtw89_phy_iter_rssi_data *)data; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) + __rtw89_phy_stat_rssi_update_iter(rtwsta_link, rssi_data); +} + static void rtw89_phy_stat_rssi_update(struct rtw89_dev *rtwdev) { struct rtw89_phy_iter_rssi_data rssi_data = {0}; @@ -4676,6 +4950,10 @@ static void rtw89_phy_stat_init(struct rtw89_dev *rtwdev) memset(&phystat->cur_pkt_stat, 0, sizeof(phystat->cur_pkt_stat)); memset(&phystat->last_pkt_stat, 0, sizeof(phystat->last_pkt_stat)); + + ewma_rssi_init(&phystat->bcn_rssi); + + rtwdev->hal.thermal_prot_lv = 0; } void rtw89_phy_stat_track(struct rtw89_dev *rtwdev) @@ -4683,6 +4961,7 @@ void rtw89_phy_stat_track(struct rtw89_dev *rtwdev) struct rtw89_phy_stat *phystat = &rtwdev->phystat; rtw89_phy_stat_thermal_update(rtwdev); + rtw89_phy_thermal_protect(rtwdev); rtw89_phy_stat_rssi_update(rtwdev); phystat->last_pkt_stat = phystat->cur_pkt_stat; @@ -5188,7 +5467,8 @@ static u32 rtw89_phy_get_ie_bitmap_addr(enum rtw89_phy_status_bitmap ie_page) } static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev, - enum rtw89_phy_status_bitmap ie_page) + enum rtw89_phy_status_bitmap ie_page, + enum rtw89_phy_idx phy_idx) { u32 addr; @@ -5197,12 +5477,12 @@ static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev, addr = rtw89_phy_get_ie_bitmap_addr(ie_page); - return rtw89_phy_read32(rtwdev, addr); + return rtw89_phy_read32_idx(rtwdev, addr, MASKDWORD, phy_idx); } static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, enum rtw89_phy_status_bitmap ie_page, - u32 val) + u32 val, enum rtw89_phy_idx phy_idx) { const struct rtw89_chip_info *chip = rtwdev->chip; u32 addr; @@ -5214,22 +5494,22 @@ static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, val &= B_PHY_STS_BITMAP_MSK_52A; addr = rtw89_phy_get_ie_bitmap_addr(ie_page); - rtw89_phy_write32(rtwdev, addr, val); + rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx); } static void rtw89_physts_enable_ie_bitmap(struct rtw89_dev *rtwdev, enum rtw89_phy_status_bitmap bitmap, enum rtw89_phy_status_ie_type ie, - bool enable) + bool enable, enum rtw89_phy_idx phy_idx) { - u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap); + u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap, phy_idx); if (enable) val |= BIT(ie); else val &= ~BIT(ie); - rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val); + rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val, phy_idx); } static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, @@ -5240,44 +5520,52 @@ static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, const struct rtw89_physts_regs *physts = phy->physts; if (enable) { - rtw89_phy_write32_clr(rtwdev, physts->setting_addr, - physts->dis_trigger_fail_mask); - rtw89_phy_write32_clr(rtwdev, physts->setting_addr, - physts->dis_trigger_brk_mask); + rtw89_phy_write32_idx_clr(rtwdev, physts->setting_addr, + physts->dis_trigger_fail_mask, phy_idx); + rtw89_phy_write32_idx_clr(rtwdev, physts->setting_addr, + physts->dis_trigger_brk_mask, phy_idx); } else { - rtw89_phy_write32_set(rtwdev, physts->setting_addr, - physts->dis_trigger_fail_mask); - rtw89_phy_write32_set(rtwdev, physts->setting_addr, - physts->dis_trigger_brk_mask); + rtw89_phy_write32_idx_set(rtwdev, physts->setting_addr, + physts->dis_trigger_fail_mask, phy_idx); + rtw89_phy_write32_idx_set(rtwdev, physts->setting_addr, + physts->dis_trigger_brk_mask, phy_idx); } } -static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) +static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) { u8 i; - rtw89_physts_enable_fail_report(rtwdev, false, RTW89_PHY_0); + rtw89_physts_enable_fail_report(rtwdev, false, phy_idx); for (i = 0; i < RTW89_PHYSTS_BITMAP_NUM; i++) { if (i >= RTW89_CCK_PKT) rtw89_physts_enable_ie_bitmap(rtwdev, i, RTW89_PHYSTS_IE09_FTR_0, - true); + true, phy_idx); if ((i >= RTW89_CCK_BRK && i <= RTW89_VHT_MU) || (i >= RTW89_RSVD_9 && i <= RTW89_CCK_PKT)) continue; rtw89_physts_enable_ie_bitmap(rtwdev, i, RTW89_PHYSTS_IE24_OFDM_TD_PATH_A, - true); + true, phy_idx); } rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_VHT_PKT, - RTW89_PHYSTS_IE13_DL_MU_DEF, true); + RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx); rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_HE_PKT, - RTW89_PHYSTS_IE13_DL_MU_DEF, true); + RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx); /* force IE01 for channel index, only channel field is valid */ rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_CCK_PKT, - RTW89_PHYSTS_IE01_CMN_OFDM, true); + RTW89_PHYSTS_IE01_CMN_OFDM, true, phy_idx); +} + +static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) +{ + __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_0); + if (rtwdev->dbcc_en) + __rtw89_physts_parsing_init(rtwdev, RTW89_PHY_1); } static void rtw89_phy_dig_read_gain_table(struct rtw89_dev *rtwdev, int type) @@ -5753,26 +6041,15 @@ void rtw89_phy_dig(struct rtw89_dev *rtwdev) rtw89_phy_dig_sdagc_follow_pagc_config(rtwdev, false); } -static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta) +static void __rtw89_phy_tx_path_div_sta_iter(struct rtw89_dev *rtwdev, + struct rtw89_sta_link *rtwsta_link) { - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; - struct rtw89_dev *rtwdev = rtwsta->rtwdev; - struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_hal *hal = &rtwdev->hal; - bool *done = data; u8 rssi_a, rssi_b; u32 candidate; - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION || sta->tdls) - return; - - if (*done) - return; - - *done = true; - - rssi_a = ewma_rssi_read(&rtwsta->rssi[RF_PATH_A]); - rssi_b = ewma_rssi_read(&rtwsta->rssi[RF_PATH_B]); + rssi_a = ewma_rssi_read(&rtwsta_link->rssi[RF_PATH_A]); + rssi_b = ewma_rssi_read(&rtwsta_link->rssi[RF_PATH_B]); if (rssi_a > rssi_b + RTW89_TX_DIV_RSSI_RAW_TH) candidate = RF_A; @@ -5785,7 +6062,7 @@ static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta return; hal->antenna_tx = candidate; - rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta); + rtw89_fw_h2c_txpath_cmac_tbl(rtwdev, rtwsta_link); if (hal->antenna_tx == RF_A) { rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, B_P0_RFMODE_MUX, 0x12); @@ -5796,6 +6073,37 @@ static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta } } +static void rtw89_phy_tx_path_div_sta_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; + bool *done = data; + + if (WARN(ieee80211_vif_is_mld(vif), "MLD mix path_div\n")) + return; + + if (sta->tdls) + return; + + if (*done) + return; + + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION) + continue; + + *done = true; + __rtw89_phy_tx_path_div_sta_iter(rtwdev, rtwsta_link); + return; + } +} + void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; @@ -6002,17 +6310,27 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_chip_cfg_txrx_path(rtwdev); } -void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_reg_def *bss_clr_vld = &chip->bss_clr_vld; - enum rtw89_phy_idx phy_idx = RTW89_PHY_0; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; + struct ieee80211_bss_conf *bss_conf; u8 bss_color; - if (!vif->bss_conf.he_support || !vif->cfg.assoc) + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->he_support || !vif->cfg.assoc) { + rcu_read_unlock(); return; + } + + bss_color = bss_conf->he_bss_color.color; - bss_color = vif->bss_conf.he_bss_color.color; + rcu_read_unlock(); rtw89_phy_write32_idx(rtwdev, bss_clr_vld->addr, bss_clr_vld->mask, 0x1, phy_idx); diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 6dd8ec46939acd..c683f4d7d29b0a 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -815,6 +815,10 @@ void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev, void rtw89_phy_dm_init(struct rtw89_dev *rtwdev); void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 data, enum rtw89_phy_idx phy_idx); +void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits, + enum rtw89_phy_idx phy_idx); +void rtw89_phy_write32_idx_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bits, + enum rtw89_phy_idx phy_idx); u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, enum rtw89_phy_idx phy_idx); s8 *rtw89_phy_raw_byr_seek(struct rtw89_dev *rtwdev, @@ -892,7 +896,7 @@ void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev, phy->set_txpwr_limit_ru(rtwdev, chan, phy_idx); } -void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta); +void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); void rtw89_phy_ra_update(struct rtw89_dev *rtwdev); void rtw89_phy_ra_update_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, u32 changed); @@ -929,7 +933,7 @@ int rtw89_phy_rfk_dack_and_wait(struct rtw89_dev *rtwdev, int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, - unsigned int ms); + bool is_chl_k, unsigned int ms); void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, const struct rtw89_chan *chan, @@ -953,11 +957,12 @@ void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu); void rtw89_phy_antdiv_track(struct rtw89_dev *rtwdev); void rtw89_phy_antdiv_work(struct work_struct *work); -void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, enum rtw89_tssi_bandedge_cfg bandedge_cfg); -void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev); u8 rtw89_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band); void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx, diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index 72eda9bbd3ae4d..37d8f254ae3259 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -398,10 +398,9 @@ static void rtw89_phy_bb_wrap_ul_pwr(struct rtw89_dev *rtwdev) } } -static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) +static void __rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx) { - enum rtw89_mac_idx mac_idx = RTW89_MAC_0; - rtw89_phy_bb_wrap_pwr_by_macid_init(rtwdev); rtw89_phy_bb_wrap_tx_path_by_macid_init(rtwdev); rtw89_phy_bb_wrap_listen_path_en_init(rtwdev); @@ -411,6 +410,13 @@ static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) rtw89_phy_bb_wrap_ul_pwr(rtwdev); } +static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) +{ + __rtw89_phy_bb_wrap_init_be(rtwdev, RTW89_MAC_0); + if (rtwdev->dbcc_en) + __rtw89_phy_bb_wrap_init_be(rtwdev, RTW89_MAC_1); +} + static void rtw89_phy_ch_info_init_be(struct rtw89_dev *rtwdev) { rtw89_phy_write32_mask(rtwdev, R_CHINFO_SEG, B_CHINFO_SEG_LEN, 0x0); diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index aebd6404f80250..c1c12abc2ea93a 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -62,9 +62,9 @@ static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter) rtw89_mac_power_mode_change(rtwdev, enter); } -void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { - if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) + if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) return; if (!rtwdev->ps_mode) @@ -85,23 +85,25 @@ void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) rtw89_ps_power_mode_change(rtwdev, false); } -static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_lps_parm lps_param = { - .macid = rtwvif->mac_id, + .macid = rtwvif_link->mac_id, .psmode = RTW89_MAC_AX_PS_MODE_LEGACY, .lastrpwm = RTW89_LAST_RPWM_PS, }; rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL); rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); - rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif); + rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif_link); } -static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_lps_parm lps_param = { - .macid = rtwvif->mac_id, + .macid = rtwvif_link->mac_id, .psmode = RTW89_MAC_AX_PS_MODE_ACTIVE, .lastrpwm = RTW89_LAST_RPWM_ACTIVE, }; @@ -109,7 +111,7 @@ static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); rtw89_fw_leave_lps_check(rtwdev, 0); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); - rtw89_chip_digital_pwr_comp(rtwdev, rtwvif->phy_idx); + rtw89_chip_digital_pwr_comp(rtwdev, rtwvif_link->phy_idx); } void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) @@ -119,7 +121,7 @@ void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev) __rtw89_leave_ps_mode(rtwdev); } -void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool ps_mode) { lockdep_assert_held(&rtwdev->mutex); @@ -127,23 +129,26 @@ void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, if (test_and_set_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) return; - __rtw89_enter_lps(rtwdev, rtwvif); + __rtw89_enter_lps(rtwdev, rtwvif_link); if (ps_mode) - __rtw89_enter_ps_mode(rtwdev, rtwvif); + __rtw89_enter_ps_mode(rtwdev, rtwvif_link); } -static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw89_leave_lps_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION && - rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) return; - __rtw89_leave_lps(rtwdev, rtwvif); + __rtw89_leave_lps(rtwdev, rtwvif_link); } void rtw89_leave_lps(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; lockdep_assert_held(&rtwdev->mutex); @@ -153,12 +158,15 @@ void rtw89_leave_lps(struct rtw89_dev *rtwdev) __rtw89_leave_ps_mode(rtwdev); rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_leave_lps_vif(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_leave_lps_vif(rtwdev, rtwvif_link); } void rtw89_enter_ips(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; set_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); @@ -166,14 +174,17 @@ void rtw89_enter_ips(struct rtw89_dev *rtwdev) return; rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_vif_deinit(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_vif_deinit(rtwdev, rtwvif_link); rtw89_core_stop(rtwdev); } void rtw89_leave_ips(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; int ret; if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) @@ -186,7 +197,8 @@ void rtw89_leave_ips(struct rtw89_dev *rtwdev) rtw89_set_channel(rtwdev); rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_mac_vif_init(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_mac_vif_init(rtwdev, rtwvif_link); clear_bit(RTW89_FLAG_INACTIVE_PS, rtwdev->flags); } @@ -197,48 +209,50 @@ void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl) rtw89_leave_lps(rtwdev); } -static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, enum rtw89_p2pps_action act) { if (act == RTW89_P2P_ACT_UPDATE || act == RTW89_P2P_ACT_REMOVE) return; if (act == RTW89_P2P_ACT_INIT) - rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, true); + rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif_link, true); else if (act == RTW89_P2P_ACT_TERMINATE) - rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif, false); + rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif_link, false); } static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif) + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; enum rtw89_p2pps_action act; u8 noa_id; - if (rtwvif->last_noa_nr == 0) + if (rtwvif_link->last_noa_nr == 0) return; - for (noa_id = 0; noa_id < rtwvif->last_noa_nr; noa_id++) { - if (noa_id == rtwvif->last_noa_nr - 1) + for (noa_id = 0; noa_id < rtwvif_link->last_noa_nr; noa_id++) { + if (noa_id == rtwvif_link->last_noa_nr - 1) act = RTW89_P2P_ACT_TERMINATE; else act = RTW89_P2P_ACT_REMOVE; - rtw89_tsf32_toggle(rtwdev, rtwvif, act); - rtw89_fw_h2c_p2p_act(rtwdev, vif, NULL, act, noa_id); + rtw89_tsf32_toggle(rtwdev, rtwvif_link, act); + rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf, + NULL, act, noa_id); } } static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev, - struct ieee80211_vif *vif) + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { - struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct ieee80211_p2p_noa_desc *desc; enum rtw89_p2pps_action act; u8 noa_id; for (noa_id = 0; noa_id < RTW89_P2P_MAX_NOA_NUM; noa_id++) { - desc = &vif->bss_conf.p2p_noa_attr.desc[noa_id]; + desc = &bss_conf->p2p_noa_attr.desc[noa_id]; if (!desc->count || !desc->duration) break; @@ -246,16 +260,19 @@ static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev, act = RTW89_P2P_ACT_INIT; else act = RTW89_P2P_ACT_UPDATE; - rtw89_tsf32_toggle(rtwdev, rtwvif, act); - rtw89_fw_h2c_p2p_act(rtwdev, vif, desc, act, noa_id); + rtw89_tsf32_toggle(rtwdev, rtwvif_link, act); + rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf, + desc, act, noa_id); } - rtwvif->last_noa_nr = noa_id; + rtwvif_link->last_noa_nr = noa_id; } -void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { - rtw89_p2p_disable_all_noa(rtwdev, vif); - rtw89_p2p_update_noa(rtwdev, vif); + rtw89_p2p_disable_all_noa(rtwdev, rtwvif_link, bss_conf); + rtw89_p2p_update_noa(rtwdev, rtwvif_link, bss_conf); } void rtw89_recalc_lps(struct rtw89_dev *rtwdev) @@ -265,6 +282,12 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev) enum rtw89_entity_mode mode; int count = 0; + /* FIXME: Fix rtw89_enter_lps() and __rtw89_enter_ps_mode() + * to take MLO cases into account before doing the following. + */ + if (rtwdev->support_mlo) + goto disable_lps; + mode = rtw89_get_entity_mode(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) goto disable_lps; @@ -291,9 +314,9 @@ void rtw89_recalc_lps(struct rtw89_dev *rtwdev) rtwdev->lps_enabled = false; } -void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif) +void rtw89_p2p_noa_renew(struct rtw89_vif_link *rtwvif_link) { - struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa; + struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa; struct rtw89_p2p_noa_ie *ie = &setter->ie; struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head; struct rtw89_noa_attr_head *noa_head = &ie->noa_head; @@ -318,10 +341,10 @@ void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif) noa_head->oppps_ctwindow = 0; } -void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif, +void rtw89_p2p_noa_append(struct rtw89_vif_link *rtwvif_link, const struct ieee80211_p2p_noa_desc *desc) { - struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa; + struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa; struct rtw89_p2p_noa_ie *ie = &setter->ie; struct rtw89_p2p_ie_head *p2p_head = &ie->p2p_head; struct rtw89_noa_attr_head *noa_head = &ie->noa_head; @@ -338,9 +361,9 @@ void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif, ie->noa_desc[setter->noa_count++] = *desc; } -u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data) +u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data) { - struct rtw89_p2p_noa_setter *setter = &rtwvif->p2p_noa; + struct rtw89_p2p_noa_setter *setter = &rtwvif_link->p2p_noa; struct rtw89_p2p_noa_ie *ie = &setter->ie; void *tail; diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h index 54486e4550b61e..cdd712966b09d9 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.h +++ b/drivers/net/wireless/realtek/rtw89/ps.h @@ -5,21 +5,23 @@ #ifndef __RTW89_PS_H_ #define __RTW89_PS_H_ -void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool ps_mode); void rtw89_leave_lps(struct rtw89_dev *rtwdev); void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); -void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); void rtw89_enter_ips(struct rtw89_dev *rtwdev); void rtw89_leave_ips(struct rtw89_dev *rtwdev); void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl); -void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); +void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf); void rtw89_recalc_lps(struct rtw89_dev *rtwdev); -void rtw89_p2p_noa_renew(struct rtw89_vif *rtwvif); -void rtw89_p2p_noa_append(struct rtw89_vif *rtwvif, +void rtw89_p2p_noa_renew(struct rtw89_vif_link *rtwvif_link); +void rtw89_p2p_noa_append(struct rtw89_vif_link *rtwvif_link, const struct ieee80211_p2p_noa_desc *desc); -u8 rtw89_p2p_noa_fetch(struct rtw89_vif *rtwvif, void **data); +u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data); static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 69678eab230939..18ec7c0252fb8e 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -196,6 +196,8 @@ #define R_AX_HALT_C2H 0x016C #define R_AX_WCPU_FW_CTRL 0x01E0 +#define B_AX_IDMEM_SHARE_MODE_RECORD_MASK GENMASK(27, 24) +#define B_AX_IDMEM_SHARE_MODE_RECORD_VALID BIT(23) #define B_AX_WCPU_FWDL_STS_MASK GENMASK(7, 5) #define B_AX_FWDL_PATH_RDY BIT(2) #define B_AX_H2C_PATH_RDY BIT(1) diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index a7720a1f17a743..cad5189708e794 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -646,22 +646,44 @@ static void rtw89_regd_apply_policy_unii4(struct rtw89_dev *rtwdev, sband->channels[i].flags |= IEEE80211_CHAN_DISABLED; } -static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev, - struct wiphy *wiphy) +static bool regd_is_6ghz_blocked(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; const struct rtw89_regd *regd = regulatory->regd; - struct ieee80211_supported_band *sband; u8 index; - int i; index = rtw89_regd_get_index(regd); if (index != RTW89_REGD_MAX_COUNTRY_NUM && !test_bit(index, regulatory->block_6ghz)) - return; + return false; rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is blocked by policy\n", regd->alpha2[0], regd->alpha2[1]); + return true; +} + +static bool regd_is_6ghz_not_applicable(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *regd = regulatory->regd; + + if (regd->txpwr_regd[RTW89_BAND_6G] != RTW89_NA) + return false; + + rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is N/A in regd map\n", + regd->alpha2[0], regd->alpha2[1]); + return true; +} + +static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev, + struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + int i; + + if (!regd_is_6ghz_blocked(rtwdev) && + !regd_is_6ghz_not_applicable(rtwdev)) + return; sband = wiphy->bands[NL80211_BAND_6GHZ]; if (!sband) @@ -793,22 +815,26 @@ static bool __rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; struct rtw89_reg_6ghz_tpe new = {}; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; bool changed = false; rtw89_for_each_rtwvif(rtwdev, rtwvif) { const struct rtw89_reg_6ghz_tpe *tmp; const struct rtw89_chan *chan; - chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); - if (chan->band_type != RTW89_BAND_6G) - continue; + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + if (chan->band_type != RTW89_BAND_6G) + continue; - tmp = &rtwvif->reg_6ghz_tpe; - if (!tmp->valid) - continue; + tmp = &rtwvif_link->reg_6ghz_tpe; + if (!tmp->valid) + continue; - tpe_intersect_constraint(&new, tmp->constraint); + tpe_intersect_constraint(&new, tmp->constraint); + } } if (memcmp(®ulatory->reg_6ghz_tpe, &new, @@ -831,19 +857,24 @@ static bool __rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev) } static int rtw89_reg_6ghz_tpe_recalc(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool active, + struct rtw89_vif_link *rtwvif_link, bool active, unsigned int *changed) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct rtw89_reg_6ghz_tpe *tpe = &rtwvif->reg_6ghz_tpe; + struct rtw89_reg_6ghz_tpe *tpe = &rtwvif_link->reg_6ghz_tpe; + struct ieee80211_bss_conf *bss_conf; memset(tpe, 0, sizeof(*tpe)); - if (!active || rtwvif->reg_6ghz_power != RTW89_REG_6GHZ_POWER_STD) + if (!active || rtwvif_link->reg_6ghz_power != RTW89_REG_6GHZ_POWER_STD) goto bottom; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); rtw89_calculate_tpe(rtwdev, tpe, &bss_conf->tpe); + + rcu_read_unlock(); + if (!tpe->valid) goto bottom; @@ -867,20 +898,24 @@ static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) const struct rtw89_regd *regd = regulatory->regd; enum rtw89_reg_6ghz_power sel; const struct rtw89_chan *chan; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; + unsigned int link_id; int count = 0; u8 index; rtw89_for_each_rtwvif(rtwdev, rtwvif) { - chan = rtw89_chan_get(rtwdev, rtwvif->chanctx_idx); - if (chan->band_type != RTW89_BAND_6G) - continue; + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + if (chan->band_type != RTW89_BAND_6G) + continue; - if (count != 0 && rtwvif->reg_6ghz_power == sel) - continue; + if (count != 0 && rtwvif_link->reg_6ghz_power == sel) + continue; - sel = rtwvif->reg_6ghz_power; - count++; + sel = rtwvif_link->reg_6ghz_power; + count++; + } } if (count != 1) @@ -908,35 +943,41 @@ static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) } static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, bool active, + struct rtw89_vif_link *rtwvif_link, bool active, unsigned int *changed) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_bss_conf *bss_conf; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); if (active) { - switch (vif->bss_conf.power_type) { + switch (bss_conf->power_type) { case IEEE80211_REG_VLP_AP: - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_VLP; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_VLP; break; case IEEE80211_REG_LPI_AP: - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_LPI; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_LPI; break; case IEEE80211_REG_SP_AP: - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_STD; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_STD; break; default: - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; break; } } else { - rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; } + rcu_read_unlock(); + *changed += __rtw89_reg_6ghz_power_recalc(rtwdev); return 0; } -int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool active) { unsigned int changed = 0; @@ -948,11 +989,11 @@ int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, * so must do reg_6ghz_tpe_recalc() after reg_6ghz_power_recalc(). */ - ret = rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, active, &changed); + ret = rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif_link, active, &changed); if (ret) return ret; - ret = rtw89_reg_6ghz_tpe_recalc(rtwdev, rtwvif, active, &changed); + ret = rtw89_reg_6ghz_tpe_recalc(rtwdev, rtwvif_link, active, &changed); if (ret) return ret; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 1679bd408ef3f3..68c67a763f4d56 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -282,7 +282,7 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; u8 val8; - u32 ret; + int ret; rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_AFSM_WLSUS_EN | B_AX_AFSM_PCIE_SUS_EN); @@ -401,7 +401,7 @@ static void rtw8851b_patch_swr_pfm2pwm(struct rtw89_dev *rtwdev) static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF, XTAL_SI_RFC2RF); @@ -1590,10 +1590,11 @@ static void rtw8851b_rfk_init(struct rtw89_dev *rtwdev) rtw8851b_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); } -static void rtw8851b_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8851b_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8851b_rx_dck(rtwdev, phy_idx, chanctx_idx); rtw8851b_iqk(rtwdev, phy_idx, chanctx_idx); @@ -1608,10 +1609,12 @@ static void rtw8851b_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8851b_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8851b_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8851b_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8851b_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx); + rtw8851b_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx, + rtwvif_link->chanctx_idx); } static void rtw8851b_rfk_track(struct rtw89_dev *rtwdev) @@ -2451,6 +2454,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = &rtw89_8851b_phy_bb_table, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index d334924faec8cd..651cbce1dd7e20 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, .recognize_intrs = rtw89_pci_recognize_intrs, + + .ssid_quirks = NULL, }; static const struct rtw89_driver_info rtw89_8851be_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index dde96bd63021ff..e647759ebd69c8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -1350,10 +1350,11 @@ static void rtw8852a_rfk_init(struct rtw89_dev *rtwdev) rtw8852a_rx_dck(rtwdev, RTW89_PHY_0, true, RTW89_CHANCTX_0); } -static void rtw8852a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8852a_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8852a_rx_dck(rtwdev, phy_idx, true, chanctx_idx); rtw8852a_iqk(rtwdev, phy_idx, chanctx_idx); @@ -1368,10 +1369,11 @@ static void rtw8852a_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8852a_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8852a_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8852a_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8852a_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx); + rtw8852a_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx); } static void rtw8852a_rfk_track(struct rtw89_dev *rtwdev) @@ -2168,6 +2170,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xc000, 0xd000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = pwr_on_seq_8852a, .pwr_off_seq = pwr_off_seq_8852a, .bb_table = &rtw89_8852a_phy_bb_table, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index 9a675e2193bcd8..701187d69e14c6 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -58,6 +58,8 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, .recognize_intrs = rtw89_pci_recognize_intrs, + + .ssid_quirks = NULL, }; static const struct rtw89_driver_info rtw89_8852ae_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 12be52f76427a1..49a31912831683 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -254,7 +254,7 @@ static void rtw8852b_pwr_sps_ana(struct rtw89_dev *rtwdev) static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; rtw8852b_pwr_sps_ana(rtwdev); @@ -383,7 +383,7 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) static int rtw8852b_pwr_off_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; rtw8852b_pwr_sps_ana(rtwdev); @@ -562,10 +562,11 @@ static void rtw8852b_rfk_init(struct rtw89_dev *rtwdev) rtw8852b_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); } -static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8852b_rx_dck(rtwdev, phy_idx, chanctx_idx); rtw8852b_iqk(rtwdev, phy_idx, chanctx_idx); @@ -580,10 +581,12 @@ static void rtw8852b_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8852b_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8852b_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8852b_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8852b_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx); + rtw8852b_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx, + rtwvif_link->chanctx_idx); } static void rtw8852b_rfk_track(struct rtw89_dev *rtwdev) @@ -805,6 +808,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = &rtw89_8852b_phy_bb_table, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index ede0ca5426aebc..f4aa4437fb7593 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -905,7 +905,6 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; u32 rx_path_0; - u32 val; rx_path_0 = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, phy_idx); @@ -985,12 +984,11 @@ static void rtw8852bx_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, pri_ch, phy_idx); - /*Set RF mode at A */ - val = chip_id == RTL8852BT ? 0x333 : 0xaaa; + /*Set RF mode at 3 */ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, - B_P0_RFMODE_ORI_RX_ALL, val, phy_idx); + B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, - B_P1_RFMODE_ORI_RX_ALL, val, phy_idx); + B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); break; default: rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri ch:%d)\n", bw, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index d8f9d92ca0fb90..a13ea1cce4a70a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, .recognize_intrs = rtw89_pci_recognize_intrs, + + .ssid_quirks = NULL, }; static const struct rtw89_driver_info rtw89_8852be_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 7dfdcb5964e117..87672513322835 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -244,7 +244,7 @@ static const u8 rtw89_btc_8852bt_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30, static int rtw8852bt_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; rtw89_write32_set(rtwdev, R_AX_LDO_AON_CTRL0, B_AX_PD_REGU_L); rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_AFSM_WLSUS_EN | @@ -357,7 +357,7 @@ static int rtw8852bt_pwr_on_func(struct rtw89_dev *rtwdev) static int rtw8852bt_pwr_off_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF, XTAL_SI_RFC2RF); @@ -535,10 +535,11 @@ static void rtw8852bt_rfk_init(struct rtw89_dev *rtwdev) rtw8852bt_rx_dck(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); } -static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8852bt_rx_dck(rtwdev, phy_idx, chanctx_idx); rtw8852bt_iqk(rtwdev, phy_idx, chanctx_idx); @@ -553,10 +554,12 @@ static void rtw8852bt_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8852bt_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8852bt_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8852bt_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8852bt_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx, rtwvif->chanctx_idx); + rtw8852bt_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx, + rtwvif_link->chanctx_idx); } static void rtw8852bt_rfk_track(struct rtw89_dev *rtwdev) @@ -739,6 +742,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c index 70294811964686..e4f40c2e287ded 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c @@ -60,6 +60,8 @@ static const struct rtw89_pci_info rtw8852bt_pci_info = { .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, .recognize_intrs = rtw89_pci_recognize_intrs, + + .ssid_quirks = NULL, }; static const struct rtw89_driver_info rtw89_8852bte_info = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 1c6e89ab0f4bcb..cde34f8e1e67f9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -203,7 +203,7 @@ static void rtw8852c_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev, u8 tx_path, static int rtw8852c_pwr_on_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; val32 = rtw89_read32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_PAD_HCI_SEL_V2_MASK); if (val32 == MAC_AX_HCI_SEL_PCIE_USB) @@ -324,7 +324,7 @@ static int rtw8852c_pwr_on_func(struct rtw89_dev *rtwdev) static int rtw8852c_pwr_off_func(struct rtw89_dev *rtwdev) { u32 val32; - u32 ret; + int ret; ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF, XTAL_SI_RFC2RF); @@ -1846,10 +1846,11 @@ static void rtw8852c_rfk_init(struct rtw89_dev *rtwdev) rtw8852c_rx_dck(rtwdev, RTW89_PHY_0, false); } -static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; rtw8852c_mcc_get_ch_info(rtwdev, phy_idx); rtw8852c_rx_dck(rtwdev, phy_idx, false); @@ -1866,10 +1867,11 @@ static void rtw8852c_rfk_band_changed(struct rtw89_dev *rtwdev, rtw8852c_tssi_scan(rtwdev, phy_idx, chan); } -static void rtw8852c_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8852c_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { - rtw8852c_wifi_scan_notify(rtwdev, start, rtwvif->phy_idx); + rtw8852c_wifi_scan_notify(rtwdev, start, rtwvif_link->phy_idx); } static void rtw8852c_rfk_track(struct rtw89_dev *rtwdev) @@ -2945,6 +2947,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xe000, 0xf000}, + .thermal_th = {0x32, 0x35}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = &rtw89_8852c_phy_bb_table, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c index 211c051c296762..bd17c0a1c6846b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c @@ -1065,7 +1065,7 @@ static bool _iqk_nbtxk(struct rtw89_dev *rtwdev, static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; u8 idx = rfk_mcc->table_idx; bool is_fail1, is_fail2; @@ -1408,7 +1408,7 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; u8 idx = 0; idx = rfk_mcc->table_idx; @@ -2350,7 +2350,7 @@ static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, if (dgain > 0x5fc || dgain < 0x556) { _dpk_one_shot(rtwdev, phy, path, D_SYNC); - dgain = _dpk_dgain_read(rtwdev); + _dpk_dgain_read(rtwdev); } if (agc_cnt == 0) { @@ -4105,7 +4105,7 @@ void rtw8852c_set_channel_rf(struct rtw89_dev *rtwdev, void rtw8852c_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { - struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; const struct rtw89_chan *chan; enum rtw89_entity_mode mode; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 8aaad7d58c0d97..1a46878be96b2c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -67,6 +67,8 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .enable_intr = rtw89_pci_enable_intr_v1, .disable_intr = rtw89_pci_disable_intr_v1, .recognize_intrs = rtw89_pci_recognize_intrs_v1, + + .ssid_quirks = NULL, }; static const struct dmi_system_id rtw8852c_pci_quirks[] = { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 63b1ff2f98ed31..9a4db04a1967bf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -2,6 +2,7 @@ /* Copyright(c) 2023 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "efuse.h" @@ -13,7 +14,7 @@ #include "rtw8922a_rfk.h" #include "util.h" -#define RTW8922A_FW_FORMAT_MAX 1 +#define RTW8922A_FW_FORMAT_MAX 2 #define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" #define RTW8922A_MODULE_FIRMWARE \ RTW8922A_FW_BASENAME "-" __stringify(RTW8922A_FW_FORMAT_MAX) ".bin" @@ -398,9 +399,6 @@ static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN | B_BE_FEN_BBPLAT_RSTB); - if (!test_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags)) - rtw89_efuse_read_fw_secure_be(rtwdev); - return 0; } @@ -965,6 +963,42 @@ static const struct rtw8922a_bb_gain bb_gain_tia[TIA_GAIN_NUM] = { .gain_g_mask = 0x1FF, .gain_a_mask = 0x3FE00 }, }; +static const struct rtw8922a_bb_gain bb_op1db_lna[LNA_GAIN_NUM] = { + { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x4078, 0x4478}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF000000}, + { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x407c, 0x447c}, + .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF}, + { .gain_g = {0x40ac, 0x44ac}, .gain_a = {0x407c, 0x447c}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF00}, + { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x407c, 0x447c}, + .gain_g_mask = 0xFF, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x407c, 0x447c}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF000000}, + { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x4080, 0x4480}, + .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF}, + { .gain_g = {0x40b0, 0x44b0}, .gain_a = {0x4080, 0x4480}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF00}, +}; + +static const struct rtw8922a_bb_gain bb_op1db_tia_lna[TIA_LNA_OP1DB_NUM] = { + { .gain_g = {0x40b4, 0x44b4}, .gain_a = {0x4080, 0x4480}, + .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF000000}, + { .gain_g = {0x40b4, 0x44b4}, .gain_a = {0x4084, 0x4484}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF}, + { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484}, + .gain_g_mask = 0xFF, .gain_a_mask = 0xFF00}, + { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4084, 0x4484}, + .gain_g_mask = 0xFF0000, .gain_a_mask = 0xFF000000}, + { .gain_g = {0x40b8, 0x44b8}, .gain_a = {0x4088, 0x4488}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF}, + { .gain_g = {0x40bc, 0x44bc}, .gain_a = {0x4088, 0x4488}, + .gain_g_mask = 0xFF, .gain_a_mask = 0xFF00}, + { .gain_g = {0x40bc, 0x44bc}, .gain_a = {0x4088, 0x4488}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF0000}, +}; + struct rtw8922a_bb_gain_bypass { u32 gain_g[BB_PATH_NUM_8922A]; u32 gain_a[BB_PATH_NUM_8922A]; @@ -1056,6 +1090,30 @@ static void rtw8922a_set_lna_tia_gain(struct rtw89_dev *rtwdev, val = gain->tia_gain[gain_band][bw_type][path][i]; rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); } + + for (i = 0; i < LNA_GAIN_NUM; i++) { + if (chan->band_type == RTW89_BAND_2G) { + reg = bb_op1db_lna[i].gain_g[path]; + mask = bb_op1db_lna[i].gain_g_mask; + } else { + reg = bb_op1db_lna[i].gain_a[path]; + mask = bb_op1db_lna[i].gain_a_mask; + } + val = gain->lna_op1db[gain_band][bw_type][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < TIA_LNA_OP1DB_NUM; i++) { + if (chan->band_type == RTW89_BAND_2G) { + reg = bb_op1db_tia_lna[i].gain_g[path]; + mask = bb_op1db_tia_lna[i].gain_g_mask; + } else { + reg = bb_op1db_tia_lna[i].gain_a[path]; + mask = bb_op1db_tia_lna[i].gain_a_mask; + } + val = gain->tia_lna_op1db[gain_band][bw_type][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } } static void rtw8922a_set_gain(struct rtw89_dev *rtwdev, @@ -1745,7 +1803,7 @@ static void rtw8922a_digital_pwr_comp(struct rtw89_dev *rtwdev, static int rtw8922a_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode mode) { - const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); + const struct rtw89_chan *chan0, *chan1; if (mode == MLO_1_PLUS_1_1RF || mode == DBCC_LEGACY) { rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x1); @@ -1758,13 +1816,20 @@ static int rtw8922a_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode return -EOPNOTSUPP; } - if (mode == MLO_2_PLUS_0_1RF) { - rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_A); - rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_B); + if (mode == MLO_1_PLUS_1_1RF) { + chan0 = rtw89_mgnt_chan_get(rtwdev, 0); + chan1 = rtw89_mgnt_chan_get(rtwdev, 1); + } else if (mode == MLO_0_PLUS_2_1RF) { + chan1 = rtw89_mgnt_chan_get(rtwdev, 1); + chan0 = chan1; } else { - rtw89_warn(rtwdev, "unsupported MLO mode %d\n", mode); + chan0 = rtw89_mgnt_chan_get(rtwdev, 0); + chan1 = chan0; } + rtw8922a_ctrl_afe_dac(rtwdev, chan0->band_width, RF_PATH_A); + rtw8922a_ctrl_afe_dac(rtwdev, chan1->band_width, RF_PATH_B); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x6180); if (mode == MLO_2_PLUS_0_1RF) { @@ -1991,14 +2056,23 @@ static void rtw8922a_rfk_init(struct rtw89_dev *rtwdev) memset(rfk_mcc, 0, sizeof(*rfk_mcc)); } +static void __rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, + const struct rtw89_chan *chan) +{ + rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5); + + rtw89_phy_rfk_dack_and_wait(rtwdev, phy_idx, chan, 58); + rtw89_phy_rfk_rxdck_and_wait(rtwdev, phy_idx, chan, false, 32); +} + static void rtw8922a_rfk_init_late(struct rtw89_dev *rtwdev) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_CHANCTX_0); - rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, RTW89_PHY_0, 5); - - rtw89_phy_rfk_dack_and_wait(rtwdev, RTW89_PHY_0, chan, 58); - rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, 32); + __rtw8922a_rfk_init_late(rtwdev, RTW89_PHY_0, chan); + if (rtwdev->dbcc_en) + __rtw8922a_rfk_init_late(rtwdev, RTW89_PHY_1, chan); } static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) @@ -2020,11 +2094,12 @@ static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) } } -static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { - enum rtw89_chanctx_idx chanctx_idx = rtwvif->chanctx_idx; + enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); - enum rtw89_phy_idx phy_idx = rtwvif->phy_idx; + enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB, chanctx_idx); u32 tx_en; @@ -2035,9 +2110,9 @@ static void rtw8922a_rfk_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtw rtw89_phy_rfk_pre_ntfy_and_wait(rtwdev, phy_idx, 5); rtw89_phy_rfk_txgapk_and_wait(rtwdev, phy_idx, chan, 54); rtw89_phy_rfk_iqk_and_wait(rtwdev, phy_idx, chan, 84); - rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 6); + rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_NORMAL, 20); rtw89_phy_rfk_dpk_and_wait(rtwdev, phy_idx, chan, 34); - rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, 32); + rtw89_phy_rfk_rxdck_and_wait(rtwdev, RTW89_PHY_0, chan, true, 32); rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_CHLK, BTC_WRFK_STOP); @@ -2050,7 +2125,8 @@ static void rtw8922a_rfk_band_changed(struct rtw89_dev *rtwdev, rtw89_phy_rfk_tssi_and_wait(rtwdev, phy_idx, chan, RTW89_TSSI_SCAN, 6); } -static void rtw8922a_rfk_scan(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, +static void rtw8922a_rfk_scan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, bool start) { } @@ -2207,10 +2283,12 @@ static void rtw8922a_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) static u8 rtw8922a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) { struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + struct rtw89_hal *hal = &rtwdev->hal; int th; - /* read thermal only if debugging */ - if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_CFO | RTW89_DBG_RFK_TRACK)) + /* read thermal only if debugging or thermal protection enabled */ + if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_CFO | RTW89_DBG_RFK_TRACK) && + !hal->thermal_prot_th) return 80; rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); @@ -2641,6 +2719,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, + .thermal_th = {0xad, 0xb4}, .pwr_on_seq = NULL, .pwr_off_seq = NULL, .bb_table = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index 28907df7407d58..c4c93f836a2f5a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -252,49 +252,58 @@ static void rtw8922a_chlk_ktbl_sel(struct rtw89_dev *rtwdev, u8 kpath, u8 idx) } } -static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) +static u8 rtw8922a_chlk_reload_sel_tbl(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, u8 path) { struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V1] = {}; - enum rtw89_chanctx_idx chanctx_idx; - const struct rtw89_chan *chan; - enum rtw89_entity_mode mode; - u8 s0_tbl, s1_tbl; u8 tbl_sel; - mode = rtw89_get_entity_mode(rtwdev); - switch (mode) { - case RTW89_ENTITY_MODE_MCC_PREPARE: - chanctx_idx = RTW89_CHANCTX_1; - break; - default: - chanctx_idx = RTW89_CHANCTX_0; - break; - } - - chan = rtw89_chan_get(rtwdev, chanctx_idx); - for (tbl_sel = 0; tbl_sel < ARRAY_SIZE(desc); tbl_sel++) { struct rtw89_rfk_chan_desc *p = &desc[tbl_sel]; - p->ch = rfk_mcc->ch[tbl_sel]; + p->ch = rfk_mcc->data[path].ch[tbl_sel]; p->has_band = true; - p->band = rfk_mcc->band[tbl_sel]; + p->band = rfk_mcc->data[path].band[tbl_sel]; p->has_bw = true; - p->bw = rfk_mcc->bw[tbl_sel]; + p->bw = rfk_mcc->data[path].bw[tbl_sel]; } tbl_sel = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); - rfk_mcc->ch[tbl_sel] = chan->channel; - rfk_mcc->band[tbl_sel] = chan->band_type; - rfk_mcc->bw[tbl_sel] = chan->band_width; - rfk_mcc->table_idx = tbl_sel; + rfk_mcc->data[path].ch[tbl_sel] = chan->channel; + rfk_mcc->data[path].band[tbl_sel] = chan->band_type; + rfk_mcc->data[path].bw[tbl_sel] = chan->band_width; + rfk_mcc->data[path].table_idx = tbl_sel; + + return tbl_sel; +} + +static void rtw8922a_chlk_reload(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chan *chan0, *chan1; + u8 s0_tbl, s1_tbl; + + switch (rtwdev->mlo_dbcc_mode) { + default: + case MLO_2_PLUS_0_1RF: + chan0 = rtw89_mgnt_chan_get(rtwdev, 0); + chan1 = chan0; + break; + case MLO_0_PLUS_2_1RF: + chan1 = rtw89_mgnt_chan_get(rtwdev, 1); + chan0 = chan1; + break; + case MLO_1_PLUS_1_1RF: + chan0 = rtw89_mgnt_chan_get(rtwdev, 0); + chan1 = rtw89_mgnt_chan_get(rtwdev, 1); + break; + } - s0_tbl = tbl_sel; - s1_tbl = tbl_sel; + s0_tbl = rtw8922a_chlk_reload_sel_tbl(rtwdev, chan0, 0); + s1_tbl = rtw8922a_chlk_reload_sel_tbl(rtwdev, chan1, 1); rtw8922a_chlk_ktbl_sel(rtwdev, RF_A, s0_tbl); rtw8922a_chlk_ktbl_sel(rtwdev, RF_B, s1_tbl); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 47f855a7a2688d..edfb1f220af024 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -9,6 +9,12 @@ #include "reg.h" #include "rtw8922a.h" +static const struct rtw89_pci_ssid_quirk rtw8922a_pci_ssid_quirks[] = { + {RTW89_PCI_SSID(PCI_VENDOR_ID_REALTEK, 0x8922, 0x10EC, 0xA891, DELL), + .bitmap = BIT(RTW89_QUIRK_THERMAL_PROT_120C)}, + {}, +}; + static const struct rtw89_pci_info rtw8922a_pci_info = { .gen_def = &rtw89_pci_gen_be, .txbd_trunc_mode = MAC_AX_BD_TRUNC, @@ -58,6 +64,8 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .enable_intr = rtw89_pci_enable_intr_v2, .disable_intr = rtw89_pci_disable_intr_v2, .recognize_intrs = rtw89_pci_recognize_intrs_v2, + + .ssid_quirks = rtw8922a_pci_ssid_quirks, }; static const struct rtw89_driver_info rtw89_8922ae_info = { diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c index 27826d909785c8..bcc287771b2a35 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -27,8 +27,8 @@ static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev, return RTW89_SAR_5GHZ_SUBBAND_1_2; case 5500 ... 5720: return RTW89_SAR_5GHZ_SUBBAND_2_E; - case 5745 ... 5825: - return RTW89_SAR_5GHZ_SUBBAND_3; + case 5745 ... 5885: + return RTW89_SAR_5GHZ_SUBBAND_3_4; case 5955 ... 6155: return RTW89_SAR_6GHZ_SUBBAND_5_L; case 6175 ... 6415: @@ -295,7 +295,7 @@ static const struct cfg80211_sar_freq_ranges rtw89_common_sar_freq_ranges[] = { { .start_freq = 2412, .end_freq = 2484, }, { .start_freq = 5180, .end_freq = 5320, }, { .start_freq = 5500, .end_freq = 5720, }, - { .start_freq = 5745, .end_freq = 5825, }, + { .start_freq = 5745, .end_freq = 5885, }, { .start_freq = 5955, .end_freq = 6155, }, { .start_freq = 6175, .end_freq = 6415, }, { .start_freq = 6435, .end_freq = 6515, }, diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 5fc2faa9ba5a7e..7b203bb7f151a7 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -300,37 +300,54 @@ static void drv_resume_rx(struct rtw89_ser *ser) static void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); - rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; - rtwvif->trigger = false; + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + rtwvif->tdls_peer = 0; + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif_link->port); + rtwvif_link->net_type = RTW89_NET_TYPE_NO_LINK; + rtwvif_link->trigger = false; + } } static void ser_sta_deinit_cam_iter(void *data, struct ieee80211_sta *sta) { struct rtw89_vif *target_rtwvif = (struct rtw89_vif *)data; - struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); struct rtw89_vif *rtwvif = rtwsta->rtwvif; struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + unsigned int link_id; if (rtwvif != target_rtwvif) return; - if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) - rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam); - if (sta->tdls) - rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam); + rtw89_sta_for_each_link(rtwsta, rtwsta_link, link_id) { + rtwvif_link = rtwsta_link->rtwvif_link; - INIT_LIST_HEAD(&rtwsta->ba_cam_list); + if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE || sta->tdls) + rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta_link->addr_cam); + if (sta->tdls) + rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta_link->bssid_cam); + + INIT_LIST_HEAD(&rtwsta_link->ba_cam_list); + } } static void ser_deinit_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { + struct rtw89_vif_link *rtwvif_link; + unsigned int link_id; + ieee80211_iterate_stations_atomic(rtwdev->hw, ser_sta_deinit_cam_iter, rtwvif); - rtw89_cam_deinit(rtwdev, rtwvif); + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) + rtw89_cam_deinit(rtwdev, rtwvif_link); bitmap_zero(rtwdev->cam_info.ba_cam_map, RTW89_MAX_BA_CAM_NUM); } diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 86e24e07780d9b..3e81fd974ec180 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -421,7 +421,8 @@ static void rtw89_wow_construct_key_info(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_key_info *key_info = &rtw_wow->key_info; - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); bool err = false; rcu_read_lock(); @@ -596,7 +597,8 @@ static int rtw89_wow_get_aoac_rpt(struct rtw89_dev *rtwdev, bool rx_ready) static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev, u32 cipher, u8 keyidx, u8 *gtk) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); const struct rtw89_cipher_info *cipher_info; struct ieee80211_key_conf *rekey_conf; struct ieee80211_key_conf *key; @@ -632,11 +634,13 @@ static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev, static void rtw89_wow_update_key_info(struct rtw89_dev *rtwdev, bool rx_ready) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt; struct rtw89_set_key_info_iter_data data = {.error = false, .rx_ready = rx_ready}; + struct ieee80211_bss_conf *bss_conf; struct ieee80211_key_conf *key; rcu_read_lock(); @@ -669,9 +673,15 @@ static void rtw89_wow_update_key_info(struct rtw89_dev *rtwdev, bool rx_ready) return; rtw89_rx_pn_set_pmf(rtwdev, key, aoac_rpt->igtk_ipn); - ieee80211_gtk_rekey_notify(wow_vif, wow_vif->bss_conf.bssid, + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + ieee80211_gtk_rekey_notify(wow_vif, bss_conf->bssid, aoac_rpt->eapol_key_replay_count, - GFP_KERNEL); + GFP_ATOMIC); + + rcu_read_unlock(); } static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev) @@ -681,27 +691,24 @@ static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev) static void rtw89_wow_enter_deep_ps(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; - __rtw89_enter_ps_mode(rtwdev, rtwvif); + __rtw89_enter_ps_mode(rtwdev, rtwvif_link); } static void rtw89_wow_enter_ps(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; if (rtw89_wow_mgd_linked(rtwdev)) - rtw89_enter_lps(rtwdev, rtwvif, false); + rtw89_enter_lps(rtwdev, rtwvif_link, false); else if (rtw89_wow_no_link(rtwdev)) - rtw89_fw_h2c_fwips(rtwdev, rtwvif, true); + rtw89_fw_h2c_fwips(rtwdev, rtwvif_link, true); } static void rtw89_wow_leave_ps(struct rtw89_dev *rtwdev, bool enable_wow) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; if (rtw89_wow_mgd_linked(rtwdev)) { rtw89_leave_lps(rtwdev); @@ -709,7 +716,7 @@ static void rtw89_wow_leave_ps(struct rtw89_dev *rtwdev, bool enable_wow) if (enable_wow) rtw89_leave_ips(rtwdev); else - rtw89_fw_h2c_fwips(rtwdev, rtwvif, false); + rtw89_fw_h2c_fwips(rtwdev, rtwvif_link, false); } } @@ -734,6 +741,8 @@ static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable) static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) { + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt; struct cfg80211_wowlan_nd_info nd_info; @@ -780,35 +789,34 @@ static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) break; default: rtw89_warn(rtwdev, "Unknown wakeup reason %x\n", reason); - ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL, - GFP_KERNEL); + ieee80211_report_wowlan_wakeup(wow_vif, NULL, GFP_KERNEL); return; } - ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup, - GFP_KERNEL); + ieee80211_report_wowlan_wakeup(wow_vif, &wakeup, GFP_KERNEL); } -static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); /* Current WoWLAN function support setting of only vif in * infra mode or no link mode. When one suitable vif is found, * stop the iteration. */ - if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION) + if (rtw_wow->rtwvif_link || vif->type != NL80211_IFTYPE_STATION) return; - switch (rtwvif->net_type) { + switch (rtwvif_link->net_type) { case RTW89_NET_TYPE_INFRA: if (rtw_wow_has_mgd_features(rtwdev)) - rtw_wow->wow_vif = vif; + rtw_wow->rtwvif_link = rtwvif_link; break; case RTW89_NET_TYPE_NO_LINK: if (rtw_wow->pno_inited) - rtw_wow->wow_vif = vif; + rtw_wow->rtwvif_link = rtwvif_link; break; default: break; @@ -865,7 +873,7 @@ static u16 rtw89_calc_crc(u8 *pdata, int length) return ~crc; } -static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, +static int rtw89_wow_pattern_get_type(struct rtw89_vif_link *rtwvif_link, struct rtw89_wow_cam_info *rtw_pattern, const u8 *pattern, u8 da_mask) { @@ -885,7 +893,7 @@ static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, rtw_pattern->bc = true; else if (is_multicast_ether_addr(da)) rtw_pattern->mc = true; - else if (ether_addr_equal(da, rtwvif->mac_addr) && + else if (ether_addr_equal(da, rtwvif_link->mac_addr) && da_mask == GENMASK(5, 0)) rtw_pattern->uc = true; else if (!da_mask) /*da_mask == 0 mean wildcard*/ @@ -897,7 +905,7 @@ static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, } static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, const struct cfg80211_pkt_pattern *pkt_pattern, struct rtw89_wow_cam_info *rtw_pattern) { @@ -916,7 +924,7 @@ static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, mask_len = DIV_ROUND_UP(len, 8); memset(rtw_pattern, 0, sizeof(*rtw_pattern)); - ret = rtw89_wow_pattern_get_type(rtwvif, rtw_pattern, pattern, + ret = rtw89_wow_pattern_get_type(rtwvif_link, rtw_pattern, pattern, mask[0] & GENMASK(5, 0)); if (ret) return ret; @@ -970,7 +978,7 @@ static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, } static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif, + struct rtw89_vif_link *rtwvif_link, struct cfg80211_wowlan *wowlan) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; @@ -983,7 +991,7 @@ static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev, for (i = 0; i < wowlan->n_patterns; i++) { rtw_pattern = &rtw_wow->patterns[i]; - ret = rtw89_wow_pattern_generate(rtwdev, rtwvif, + ret = rtw89_wow_pattern_generate(rtwdev, rtwvif_link, &wowlan->patterns[i], rtw_pattern); if (ret) { @@ -1040,7 +1048,7 @@ static void rtw89_wow_clear_wakeups(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - rtw_wow->wow_vif = NULL; + rtw_wow->rtwvif_link = NULL; rtw89_core_release_all_bits_map(rtw_wow->flags, RTW89_WOW_FLAG_NUM); rtw_wow->pattern_cnt = 0; rtw_wow->pno_inited = false; @@ -1066,6 +1074,7 @@ static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; + struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; if (wowlan->disconnect) @@ -1078,36 +1087,40 @@ static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev, if (wowlan->nd_config) rtw89_wow_init_pno(rtwdev, wowlan->nd_config); - rtw89_for_each_rtwvif(rtwdev, rtwvif) - rtw89_wow_vif_iter(rtwdev, rtwvif); + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + /* use the link on HW-0 to do wow flow */ + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (!rtwvif_link) + continue; + + rtw89_wow_vif_iter(rtwdev, rtwvif_link); + } - if (!rtw_wow->wow_vif) + rtwvif_link = rtw_wow->rtwvif_link; + if (!rtwvif_link) return -EPERM; - rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; - return rtw89_wow_parse_patterns(rtwdev, rtwvif, wowlan); + return rtw89_wow_parse_patterns(rtwdev, rtwvif_link, wowlan); } static int rtw89_wow_cfg_wake_pno(struct rtw89_dev *rtwdev, bool wow) { - struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; int ret; - ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif_link, true); if (ret) { rtw89_err(rtwdev, "failed to config pno\n"); return ret; } - ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow); + ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif_link, wow); if (ret) { rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n"); return ret; } - ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow); + ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif_link, wow); if (ret) { rtw89_err(rtwdev, "failed to fw wow global\n"); return ret; @@ -1119,34 +1132,39 @@ static int rtw89_wow_cfg_wake_pno(struct rtw89_dev *rtwdev, bool wow) static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); struct ieee80211_sta *wow_sta; - struct rtw89_sta *rtwsta = NULL; + struct rtw89_sta_link *rtwsta_link = NULL; + struct rtw89_sta *rtwsta; int ret; - wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); - if (wow_sta) - rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; + wow_sta = ieee80211_find_sta(wow_vif, wow_vif->cfg.ap_addr); + if (wow_sta) { + rtwsta = sta_to_rtwsta(wow_sta); + rtwsta_link = rtwsta->links[rtwvif_link->link_id]; + if (!rtwsta_link) + return -ENOLINK; + } if (wow) { if (rtw_wow->pattern_cnt) - rtwvif->wowlan_pattern = true; + rtwvif_link->wowlan_pattern = true; if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) - rtwvif->wowlan_magic = true; + rtwvif_link->wowlan_magic = true; } else { - rtwvif->wowlan_pattern = false; - rtwvif->wowlan_magic = false; + rtwvif_link->wowlan_pattern = false; + rtwvif_link->wowlan_magic = false; } - ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow); + ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif_link, wow); if (ret) { rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n"); return ret; } if (wow) { - ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); + ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n", ret); @@ -1154,13 +1172,13 @@ static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) } } - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; } - ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow); + ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif_link, wow); if (ret) { rtw89_err(rtwdev, "failed to fw wow global\n"); return ret; @@ -1190,25 +1208,30 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) enum rtw89_fw_type fw_type = wow ? RTW89_FW_WOWLAN : RTW89_FW_NORMAL; enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link; + struct ieee80211_vif *wow_vif = rtwvif_link_to_vif(rtwvif_link); enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; const struct rtw89_chip_info *chip = rtwdev->chip; bool include_bb = !!chip->bbmcu_nr; bool disable_intr_for_dlfw = false; struct ieee80211_sta *wow_sta; - struct rtw89_sta *rtwsta = NULL; + struct rtw89_sta_link *rtwsta_link = NULL; + struct rtw89_sta *rtwsta; bool is_conn = true; int ret; if (chip_id == RTL8852C || chip_id == RTL8922A) disable_intr_for_dlfw = true; - wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); - if (wow_sta) - rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; - else + wow_sta = ieee80211_find_sta(wow_vif, wow_vif->cfg.ap_addr); + if (wow_sta) { + rtwsta = sta_to_rtwsta(wow_sta); + rtwsta_link = rtwsta->links[rtwvif_link->link_id]; + if (!rtwsta_link) + return -ENOLINK; + } else { is_conn = false; + } if (disable_intr_for_dlfw) rtw89_hci_disable_intr(rtwdev); @@ -1224,14 +1247,14 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) rtw89_phy_init_rf_reg(rtwdev, true); - ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, + ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link, RTW89_ROLE_FW_RESTORE); if (ret) { rtw89_warn(rtwdev, "failed to send h2c role maintain\n"); return ret; } - ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, rtwvif_link, rtwsta_link); if (ret) { rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n"); return ret; @@ -1240,27 +1263,27 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) if (!is_conn) rtw89_cam_reset_keys(rtwdev); - ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn); + ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif_link, rtwsta_link, !is_conn); if (ret) { rtw89_warn(rtwdev, "failed to send h2c join info\n"); return ret; } - ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); + ret = rtw89_fw_h2c_cam(rtwdev, rtwvif_link, rtwsta_link, NULL); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cam\n"); return ret; } if (is_conn) { - ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id); + ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id); if (ret) { rtw89_warn(rtwdev, "failed to send h2c general packet\n"); return ret; } - rtw89_phy_ra_assoc(rtwdev, wow_sta); - rtw89_phy_set_bss_color(rtwdev, wow_vif); - rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif); + rtw89_phy_ra_assoc(rtwdev, rtwsta_link); + rtw89_phy_set_bss_color(rtwdev, rtwvif_link); + rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, rtwvif_link); } if (chip_gen == RTW89_CHIP_BE) @@ -1363,21 +1386,20 @@ static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev) static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev) { - struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *vif = rtw_wow->wow_vif; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; int ret; ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); if (ret) rtw89_err(rtwdev, "cfg ppdu status\n"); - rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); return ret; } static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct list_head *pkt_list = &rtw_wow->pno_pkt_list; @@ -1391,7 +1413,7 @@ static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev, } static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif_link *rtwvif_link) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; @@ -1401,7 +1423,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, int ret; for (i = 0; i < num; i++) { - skb = ieee80211_probereq_get(rtwdev->hw, rtwvif->mac_addr, + skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, nd_config->match_sets[i].ssid.ssid, nd_config->match_sets[i].ssid.ssid_len, nd_config->ie_len); @@ -1413,7 +1435,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { kfree_skb(skb); - rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif); + rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link); return -ENOMEM; } @@ -1421,7 +1443,7 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, if (ret) { kfree_skb(skb); kfree(info); - rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif); + rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link); return ret; } @@ -1436,20 +1458,19 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; int interval = rtw_wow->nd_config->scan_plans[0].interval; struct rtw89_scan_option opt = {}; int ret; if (enable) { - ret = rtw89_pno_scan_update_probe_req(rtwdev, rtwvif); + ret = rtw89_pno_scan_update_probe_req(rtwdev, rtwvif_link); if (ret) { rtw89_err(rtwdev, "Update probe request failed\n"); return ret; } - ret = mac->add_chan_list_pno(rtwdev, rtwvif); + ret = mac->add_chan_list_pno(rtwdev, rtwvif_link); if (ret) { rtw89_err(rtwdev, "Update channel list failed\n"); return ret; @@ -1471,7 +1492,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) opt.opch_end = RTW89_CHAN_INVALID; } - mac->scan_offload(rtwdev, &opt, rtwvif, true); + mac->scan_offload(rtwdev, &opt, rtwvif_link, true); return 0; } @@ -1479,8 +1500,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link; int ret; if (rtw89_wow_no_link(rtwdev)) { @@ -1499,25 +1519,25 @@ static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) rtw89_wow_pattern_write(rtwdev); rtw89_wow_construct_key_info(rtwdev); - ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif_link, true); if (ret) { rtw89_err(rtwdev, "wow: failed to enable keep alive\n"); return ret; } - ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif_link, true); if (ret) { rtw89_err(rtwdev, "wow: failed to enable disconnect detect\n"); return ret; } - ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif_link, true); if (ret) { rtw89_err(rtwdev, "wow: failed to enable GTK offload\n"); return ret; } - ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif, true); + ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif_link, true); if (ret) rtw89_warn(rtwdev, "wow: failed to enable arp offload\n"); } @@ -1548,8 +1568,7 @@ static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) { struct rtw89_wow_param *rtw_wow = &rtwdev->wow; - struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtw_wow->rtwvif_link; int ret; if (rtw89_wow_no_link(rtwdev)) { @@ -1559,35 +1578,35 @@ static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) return ret; } - ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_cfg_pno(rtwdev, rtwvif_link, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable pno\n"); return ret; } - rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif); + rtw89_fw_release_pno_pkt_list(rtwdev, rtwvif_link); } else { rtw89_wow_pattern_clear(rtwdev); - ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif_link, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable keep alive\n"); return ret; } - ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif_link, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n"); return ret; } - ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_wow_gtk_ofld(rtwdev, rtwvif_link, false); if (ret) { rtw89_err(rtwdev, "wow: failed to disable GTK offload\n"); return ret; } - ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif, false); + ret = rtw89_fw_h2c_arp_offload(rtwdev, rtwvif_link, false); if (ret) rtw89_warn(rtwdev, "wow: failed to disable arp offload\n"); diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index 3fbc2b87c058ac..f91991e8f2e30e 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -97,18 +97,16 @@ static inline int rtw89_wow_get_sec_hdr_len(struct rtw89_dev *rtwdev) #ifdef CONFIG_PM static inline bool rtw89_wow_mgd_linked(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; - return rtwvif->net_type == RTW89_NET_TYPE_INFRA; + return rtwvif_link->net_type == RTW89_NET_TYPE_INFRA; } static inline bool rtw89_wow_no_link(struct rtw89_dev *rtwdev) { - struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; - struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; + struct rtw89_vif_link *rtwvif_link = rtwdev->wow.rtwvif_link; - return rtwvif->net_type == RTW89_NET_TYPE_NO_LINK; + return rtwvif_link->net_type == RTW89_NET_TYPE_NO_LINK; } static inline bool rtw_wow_has_mgd_features(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c index e7198520bdffc7..64441c8bc4606c 100644 --- a/drivers/net/wireless/silabs/wfx/main.c +++ b/drivers/net/wireless/silabs/wfx/main.c @@ -480,10 +480,23 @@ static int __init wfx_core_init(void) { int ret = 0; - if (IS_ENABLED(CONFIG_SPI)) + if (IS_ENABLED(CONFIG_SPI)) { ret = spi_register_driver(&wfx_spi_driver); - if (IS_ENABLED(CONFIG_MMC) && !ret) + if (ret) + goto out; + } + if (IS_ENABLED(CONFIG_MMC)) { ret = sdio_register_driver(&wfx_sdio_driver); + if (ret) + goto unregister_spi; + } + + return 0; + +unregister_spi: + if (IS_ENABLED(CONFIG_SPI)) + spi_unregister_driver(&wfx_spi_driver); +out: return ret; } module_init(wfx_core_init); diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c index 4f346fb977a989..862964a8cc8761 100644 --- a/drivers/net/wireless/st/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c @@ -450,7 +450,7 @@ static int __maybe_unused cw1200_spi_suspend(struct device *dev) { struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev)); - if (!cw1200_can_suspend(self->core)) + if (self && !cw1200_can_suspend(self->core)) return -EAGAIN; /* XXX notify host that we have to keep CW1200 powered on? */ diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c index 805a3c1bf8fe24..259739e53fc19f 100644 --- a/drivers/net/wireless/st/cw1200/queue.c +++ b/drivers/net/wireless/st/cw1200/queue.c @@ -411,33 +411,6 @@ int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id) return ret; } -int cw1200_queue_requeue_all(struct cw1200_queue *queue) -{ - struct cw1200_queue_item *item, *tmp; - struct cw1200_queue_stats *stats = queue->stats; - spin_lock_bh(&queue->lock); - - list_for_each_entry_safe_reverse(item, tmp, &queue->pending, head) { - --queue->num_pending; - ++queue->link_map_cache[item->txpriv.link_id]; - - spin_lock_bh(&stats->lock); - ++stats->num_queued; - ++stats->link_map_cache[item->txpriv.link_id]; - spin_unlock_bh(&stats->lock); - - ++item->generation; - item->packet_id = cw1200_queue_mk_packet_id(queue->generation, - queue->queue_id, - item->generation, - item - queue->pool); - list_move(&item->head, &queue->queue); - } - spin_unlock_bh(&queue->lock); - - return 0; -} - int cw1200_queue_remove(struct cw1200_queue *queue, u32 packet_id) { int ret = 0; diff --git a/drivers/net/wireless/st/cw1200/queue.h b/drivers/net/wireless/st/cw1200/queue.h index 96ac69ae97dea3..d46304b58747ed 100644 --- a/drivers/net/wireless/st/cw1200/queue.h +++ b/drivers/net/wireless/st/cw1200/queue.h @@ -85,7 +85,6 @@ int cw1200_queue_get(struct cw1200_queue *queue, struct ieee80211_tx_info **tx_info, const struct cw1200_txpriv **txpriv); int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packet_id); -int cw1200_queue_requeue_all(struct cw1200_queue *queue); int cw1200_queue_remove(struct cw1200_queue *queue, u32 packet_id); int cw1200_queue_get_skb(struct cw1200_queue *queue, u32 packet_id, diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index c705081249d697..b4505024312916 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c @@ -233,8 +233,8 @@ static int wl1251_sdio_probe(struct sdio_func *func, } if (wl->irq) { - irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); - ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); + ret = request_irq(wl->irq, wl1251_line_irq, IRQF_NO_AUTOEN, + "wl1251", wl); if (ret < 0) { wl1251_error("request_irq() failed: %d", ret); goto disable; diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index b26d42b4e3cc0f..ffbf5477633022 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1939,7 +1939,7 @@ MODULE_DEVICE_TABLE(platform, wl12xx_id_table); static struct platform_driver wl12xx_driver = { .probe = wl12xx_probe, - .remove_new = wl12xx_remove, + .remove = wl12xx_remove, .id_table = wl12xx_id_table, .driver = { .name = "wl12xx_driver", diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 39d8eebb9b6e9e..4be1110bac8888 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -2097,9 +2097,9 @@ MODULE_DEVICE_TABLE(platform, wl18xx_id_table); static struct platform_driver wl18xx_driver = { .probe = wl18xx_probe, - .remove_new = wlcore_remove, + .remove = wlcore_remove, .id_table = wl18xx_id_table, - .driver = { + .driver = { .name = "wl18xx_driver", } }; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 0c77b8524160db..986b07bfa0ee81 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5789,9 +5789,10 @@ static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw, static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { + struct ieee80211_sta *sta = link_sta->sta; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update"); @@ -6052,7 +6053,7 @@ static const struct ieee80211_ops wl1271_ops = { .assign_vif_chanctx = wlcore_op_assign_vif_chanctx, .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx, .switch_vif_chanctx = wlcore_op_switch_vif_chanctx, - .sta_rc_update = wlcore_op_sta_rc_update, + .link_sta_rc_update = wlcore_op_sta_rc_update, .sta_statistics = wlcore_op_sta_statistics, .get_expected_throughput = wlcore_op_get_expected_throughput, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 92fb5b8dcdae64..a73207bbe5d7a3 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -323,17 +323,12 @@ static int wl1271_probe(struct sdio_func *func, memset(res, 0x00, sizeof(res)); - res[0].start = irq; - res[0].flags = IORESOURCE_IRQ | - irqd_get_trigger_type(irq_get_irq_data(irq)); - res[0].name = "irq"; - + res[0] = DEFINE_RES_IRQ_NAMED(irq, "irq"); + res[0].flags |= irq_get_trigger_type(irq); if (wakeirq > 0) { - res[1].start = wakeirq; - res[1].flags = IORESOURCE_IRQ | - irqd_get_trigger_type(irq_get_irq_data(wakeirq)); - res[1].name = "wakeirq"; + res[1] = DEFINE_RES_IRQ_NAMED(wakeirq, "wakeirq"); + res[1].flags |= irq_get_trigger_type(wakeirq); num_irqs = 2; } else { num_irqs = 1; diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 3f424f14de4ec2..347a15544afedb 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2442,7 +2442,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) if (!data->started || !link_data->beacon_int) { hrtimer_cancel(&link_data->beacon_timer); - } else if (!hrtimer_is_queued(&link_data->beacon_timer)) { + } else if (!hrtimer_active(&link_data->beacon_timer)) { u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); u32 bcn_int = link_data->beacon_int; u64 until_tbtt = bcn_int - do_div(tsf, bcn_int); @@ -2537,7 +2537,7 @@ static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, info->enable_beacon, info->beacon_int); vp->bcn_en = info->enable_beacon; if (data->started && - !hrtimer_is_queued(&link_data->beacon_timer) && + !hrtimer_active(&link_data->beacon_timer) && info->enable_beacon) { u64 tsf, until_tbtt; u32 bcn_int; @@ -2594,10 +2594,11 @@ static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw, static void mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, + struct ieee80211_link_sta *link_sta, u32 changed) { struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_sta *sta = link_sta->sta; u32 bw = U32_MAX; int link_id; @@ -2607,7 +2608,6 @@ mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw, link_id++) { enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; struct ieee80211_bss_conf *vif_conf; - struct ieee80211_link_sta *link_sta; link_sta = rcu_dereference(sta->link[link_id]); @@ -2659,7 +2659,7 @@ static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, hwsim_check_magic(vif); hwsim_set_sta_magic(sta); - mac80211_hwsim_sta_rc_update(hw, vif, sta, 0); + mac80211_hwsim_sta_rc_update(hw, vif, &sta->deflink, 0); if (sta->valid_links) { WARN(hweight16(sta->valid_links) > 1, @@ -3961,7 +3961,7 @@ static int hwsim_pmsr_report_nl(struct sk_buff *msg, struct genl_info *info) .link_info_changed = mac80211_hwsim_link_info_changed, \ .tx_last_beacon = mac80211_hwsim_tx_last_beacon, \ .sta_notify = mac80211_hwsim_sta_notify, \ - .sta_rc_update = mac80211_hwsim_sta_rc_update, \ + .link_sta_rc_update = mac80211_hwsim_sta_rc_update, \ .conf_tx = mac80211_hwsim_conf_tx, \ .get_survey = mac80211_hwsim_get_survey, \ CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) \ diff --git a/drivers/net/wwan/qcom_bam_dmux.c b/drivers/net/wwan/qcom_bam_dmux.c index 5dcb9a84a12e35..64dab8b57611c9 100644 --- a/drivers/net/wwan/qcom_bam_dmux.c +++ b/drivers/net/wwan/qcom_bam_dmux.c @@ -896,7 +896,7 @@ MODULE_DEVICE_TABLE(of, bam_dmux_of_match); static struct platform_driver bam_dmux_driver = { .probe = bam_dmux_probe, - .remove_new = bam_dmux_remove, + .remove = bam_dmux_remove, .driver = { .name = "bam-dmux", .pm = &bam_dmux_pm_ops, diff --git a/drivers/net/wwan/t7xx/t7xx_modem_ops.c b/drivers/net/wwan/t7xx/t7xx_modem_ops.c index 79f17100f70b1c..7968e208dd37c1 100644 --- a/drivers/net/wwan/t7xx/t7xx_modem_ops.c +++ b/drivers/net/wwan/t7xx/t7xx_modem_ops.c @@ -198,6 +198,7 @@ int t7xx_reset_device(struct t7xx_pci_dev *t7xx_dev, enum reset_type type) pci_save_state(t7xx_dev->pdev); t7xx_pci_reprobe_early(t7xx_dev); t7xx_mode_update(t7xx_dev, T7XX_RESET); + WRITE_ONCE(t7xx_dev->debug_ports_show, false); if (type == FLDR) { ret = t7xx_acpi_reset(t7xx_dev, "_RST"); diff --git a/drivers/net/wwan/t7xx/t7xx_pci.c b/drivers/net/wwan/t7xx/t7xx_pci.c index e556e5bd49abcf..8381b0dc7acb22 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.c +++ b/drivers/net/wwan/t7xx/t7xx_pci.c @@ -41,6 +41,7 @@ #include "t7xx_pcie_mac.h" #include "t7xx_reg.h" #include "t7xx_state_monitor.h" +#include "t7xx_port_proxy.h" #define T7XX_PCI_IREG_BASE 0 #define T7XX_PCI_EREG_BASE 2 @@ -48,7 +49,7 @@ #define T7XX_INIT_TIMEOUT 20 #define PM_SLEEP_DIS_TIMEOUT_MS 20 #define PM_ACK_TIMEOUT_MS 1500 -#define PM_AUTOSUSPEND_MS 20000 +#define PM_AUTOSUSPEND_MS 5000 #define PM_RESOURCE_POLL_TIMEOUT_US 10000 #define PM_RESOURCE_POLL_STEP_US 100 @@ -120,13 +121,58 @@ static ssize_t t7xx_mode_show(struct device *dev, static DEVICE_ATTR_RW(t7xx_mode); -static struct attribute *t7xx_mode_attr[] = { +static ssize_t t7xx_debug_ports_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct t7xx_pci_dev *t7xx_dev; + struct pci_dev *pdev; + bool show; + int ret; + + pdev = to_pci_dev(dev); + t7xx_dev = pci_get_drvdata(pdev); + if (!t7xx_dev) + return -ENODEV; + + ret = kstrtobool(buf, &show); + if (ret < 0) + return ret; + + t7xx_proxy_debug_ports_show(t7xx_dev, show); + WRITE_ONCE(t7xx_dev->debug_ports_show, show); + + return count; +}; + +static ssize_t t7xx_debug_ports_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct t7xx_pci_dev *t7xx_dev; + struct pci_dev *pdev; + bool show; + + pdev = to_pci_dev(dev); + t7xx_dev = pci_get_drvdata(pdev); + if (!t7xx_dev) + return -ENODEV; + + show = READ_ONCE(t7xx_dev->debug_ports_show); + + return sysfs_emit(buf, "%d\n", show); +} + +static DEVICE_ATTR_RW(t7xx_debug_ports); + +static struct attribute *t7xx_attr[] = { &dev_attr_t7xx_mode.attr, + &dev_attr_t7xx_debug_ports.attr, NULL }; -static const struct attribute_group t7xx_mode_attribute_group = { - .attrs = t7xx_mode_attr, +static const struct attribute_group t7xx_attribute_group = { + .attrs = t7xx_attr, }; void t7xx_mode_update(struct t7xx_pci_dev *t7xx_dev, enum t7xx_mode mode) @@ -839,7 +885,7 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) t7xx_pcie_mac_interrupts_dis(t7xx_dev); ret = sysfs_create_group(&t7xx_dev->pdev->dev.kobj, - &t7xx_mode_attribute_group); + &t7xx_attribute_group); if (ret) goto err_md_exit; @@ -855,7 +901,7 @@ static int t7xx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_remove_group: sysfs_remove_group(&t7xx_dev->pdev->dev.kobj, - &t7xx_mode_attribute_group); + &t7xx_attribute_group); err_md_exit: t7xx_md_exit(t7xx_dev); @@ -870,7 +916,7 @@ static void t7xx_pci_remove(struct pci_dev *pdev) t7xx_dev = pci_get_drvdata(pdev); sysfs_remove_group(&t7xx_dev->pdev->dev.kobj, - &t7xx_mode_attribute_group); + &t7xx_attribute_group); t7xx_md_exit(t7xx_dev); for (i = 0; i < EXT_INT_NUM; i++) { diff --git a/drivers/net/wwan/t7xx/t7xx_pci.h b/drivers/net/wwan/t7xx/t7xx_pci.h index cd8ea17c26441c..b25d867e72d29c 100644 --- a/drivers/net/wwan/t7xx/t7xx_pci.h +++ b/drivers/net/wwan/t7xx/t7xx_pci.h @@ -94,6 +94,7 @@ struct t7xx_pci_dev { struct dentry *debugfs_dir; #endif u32 mode; + bool debug_ports_show; }; enum t7xx_pm_id { diff --git a/drivers/net/wwan/t7xx/t7xx_port.h b/drivers/net/wwan/t7xx/t7xx_port.h index f74d3bab810d84..9f5d6d288c97e9 100644 --- a/drivers/net/wwan/t7xx/t7xx_port.h +++ b/drivers/net/wwan/t7xx/t7xx_port.h @@ -42,6 +42,8 @@ enum port_ch { /* to AP */ PORT_CH_AP_CONTROL_RX = 0x1000, PORT_CH_AP_CONTROL_TX = 0x1001, + PORT_CH_AP_ADB_RX = 0x100a, + PORT_CH_AP_ADB_TX = 0x100b, /* to MD */ PORT_CH_CONTROL_RX = 0x2000, @@ -100,6 +102,7 @@ struct t7xx_port_conf { struct port_ops *ops; char *name; enum wwan_port_type port_type; + bool debug; }; struct t7xx_port { diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c index 35743e7de0c306..4fc131f9632f87 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c @@ -38,7 +38,8 @@ #include "t7xx_state_monitor.h" #define Q_IDX_CTRL 0 -#define Q_IDX_MBIM 2 +#define Q_IDX_MBIM_MIPC 2 +#define Q_IDX_ADB 3 #define Q_IDX_AT_CMD 5 #define INVALID_SEQ_NUM GENMASK(15, 0) @@ -66,8 +67,8 @@ static const struct t7xx_port_conf t7xx_port_conf[] = { }, { .tx_ch = PORT_CH_MBIM_TX, .rx_ch = PORT_CH_MBIM_RX, - .txq_index = Q_IDX_MBIM, - .rxq_index = Q_IDX_MBIM, + .txq_index = Q_IDX_MBIM_MIPC, + .rxq_index = Q_IDX_MBIM_MIPC, .path_id = CLDMA_ID_MD, .ops = &wwan_sub_port_ops, .name = "MBIM", @@ -100,7 +101,27 @@ static const struct t7xx_port_conf t7xx_port_conf[] = { .path_id = CLDMA_ID_AP, .ops = &ctl_port_ops, .name = "t7xx_ap_ctrl", - }, + }, { + .tx_ch = PORT_CH_AP_ADB_TX, + .rx_ch = PORT_CH_AP_ADB_RX, + .txq_index = Q_IDX_ADB, + .rxq_index = Q_IDX_ADB, + .path_id = CLDMA_ID_AP, + .ops = &wwan_sub_port_ops, + .name = "adb", + .port_type = WWAN_PORT_ADB, + .debug = true, + }, { + .tx_ch = PORT_CH_MIPC_TX, + .rx_ch = PORT_CH_MIPC_RX, + .txq_index = Q_IDX_MBIM_MIPC, + .rxq_index = Q_IDX_MBIM_MIPC, + .path_id = CLDMA_ID_MD, + .ops = &wwan_sub_port_ops, + .name = "mipc", + .port_type = WWAN_PORT_MIPC, + .debug = true, + } }; static const struct t7xx_port_conf t7xx_early_port_conf[] = { @@ -505,13 +526,33 @@ static void t7xx_proxy_init_all_ports(struct t7xx_modem *md) spin_lock_init(&port->port_update_lock); port->chan_enable = false; - if (port_conf->ops && port_conf->ops->init) + if (!port_conf->debug && + port_conf->ops && + port_conf->ops->init) port_conf->ops->init(port); } t7xx_proxy_setup_ch_mapping(port_prox); } +void t7xx_proxy_debug_ports_show(struct t7xx_pci_dev *t7xx_dev, bool show) +{ + struct port_proxy *port_prox = t7xx_dev->md->port_prox; + struct t7xx_port *port; + int i; + + for_each_proxy_port(i, port, port_prox) { + const struct t7xx_port_conf *port_conf = port->port_conf; + + if (port_conf->debug && port_conf->ops) { + if (show && port_conf->ops->init) + port_conf->ops->init(port); + else if (!show && port_conf->ops->uninit) + port_conf->ops->uninit(port); + } + } +} + void t7xx_port_proxy_set_cfg(struct t7xx_modem *md, enum port_cfg_id cfg_id) { struct port_proxy *port_prox = md->port_prox; diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h index 7f5706811445ba..f0918b36e899bd 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h +++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h @@ -98,6 +98,7 @@ extern struct port_ops ctl_port_ops; extern struct port_ops t7xx_trace_port_ops; #endif +void t7xx_proxy_debug_ports_show(struct t7xx_pci_dev *t7xx_dev, bool show); void t7xx_port_proxy_reset(struct port_proxy *port_prox); void t7xx_port_proxy_uninit(struct port_proxy *port_prox); int t7xx_port_proxy_init(struct t7xx_modem *md); diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c index 4b23ba693f3f1d..7fc569565ff99a 100644 --- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c +++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c @@ -169,7 +169,9 @@ static int t7xx_port_wwan_init(struct t7xx_port *port) { const struct t7xx_port_conf *port_conf = port->port_conf; - if (port_conf->port_type == WWAN_PORT_FASTBOOT) + if (port_conf->port_type == WWAN_PORT_FASTBOOT || + port_conf->port_type == WWAN_PORT_ADB || + port_conf->port_type == WWAN_PORT_MIPC) t7xx_port_wwan_create(port); port->rx_length_th = RX_QUEUE_MAXLEN; @@ -224,7 +226,9 @@ static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int { const struct t7xx_port_conf *port_conf = port->port_conf; - if (port_conf->port_type == WWAN_PORT_FASTBOOT) + if (port_conf->port_type == WWAN_PORT_FASTBOOT || + port_conf->port_type == WWAN_PORT_ADB || + port_conf->port_type == WWAN_PORT_MIPC) return; if (state != MD_STATE_READY) diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index 65a7ed4d67660d..a51e2755991af9 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -334,6 +334,14 @@ static const struct { .name = "FASTBOOT", .devsuf = "fastboot", }, + [WWAN_PORT_ADB] = { + .name = "ADB", + .devsuf = "adb", + }, + [WWAN_PORT_MIPC] = { + .name = "MIPC", + .devsuf = "mipc", + }, }; static ssize_t type_show(struct device *dev, struct device_attribute *attr, @@ -431,7 +439,7 @@ static int __wwan_port_dev_assign_name(struct wwan_port *port, const char *fmt) return -ENFILE; } - return dev_set_name(&port->dev, buf); + return dev_set_name(&port->dev, "%s", buf); } struct wwan_port *wwan_create_port(struct device *parent, diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 4265c1cd0ff716..63fe51d0e64db3 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -867,7 +867,7 @@ static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev static int xennet_close(struct net_device *dev) { struct netfront_info *np = netdev_priv(dev); - unsigned int num_queues = dev->real_num_tx_queues; + unsigned int num_queues = np->queues ? dev->real_num_tx_queues : 0; unsigned int i; struct netfront_queue *queue; netif_tx_stop_all_queues(np->netdev); @@ -882,6 +882,9 @@ static void xennet_destroy_queues(struct netfront_info *info) { unsigned int i; + if (!info->queues) + return; + for (i = 0; i < info->netdev->real_num_tx_queues; i++) { struct netfront_queue *queue = &info->queues[i]; diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index 6fc9dfe8247477..544d8a4d2af59d 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -2671,15 +2671,20 @@ static int idt_init_pci(struct idt_ntb_dev *ndev) */ pci_set_master(pdev); - /* Request all BARs resources and map BAR0 only */ - ret = pcim_iomap_regions_request_all(pdev, 1, NTB_NAME); + /* Request all BARs resources */ + ret = pcim_request_all_regions(pdev, NTB_NAME); if (ret != 0) { dev_err(&pdev->dev, "Failed to request resources\n"); goto err_clear_master; } - /* Retrieve virtual address of BAR0 - PCI configuration space */ - ndev->cfgspc = pcim_iomap_table(pdev)[0]; + /* ioremap BAR0 - PCI configuration space */ + ndev->cfgspc = pcim_iomap(pdev, 0, 0); + if (!ndev->cfgspc) { + dev_err(&pdev->dev, "Failed to ioremap BAR 0\n"); + ret = -ENOMEM; + goto err_clear_master; + } /* Put the IDT driver data pointer to the PCI-device private pointer */ pci_set_drvdata(pdev, ndev); diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c index 6b4922de30477e..37b743acbb7bad 100644 --- a/drivers/nvdimm/dax_devs.c +++ b/drivers/nvdimm/dax_devs.c @@ -106,12 +106,12 @@ int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns) nvdimm_bus_lock(&ndns->dev); nd_dax = nd_dax_alloc(nd_region); - nd_pfn = &nd_dax->nd_pfn; - dax_dev = nd_pfn_devinit(nd_pfn, ndns); + dax_dev = nd_dax_devinit(nd_dax, ndns); nvdimm_bus_unlock(&ndns->dev); if (!dax_dev) return -ENOMEM; pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL); + nd_pfn = &nd_dax->nd_pfn; nd_pfn->pfn_sb = pfn_sb; rc = nd_pfn_validate(nd_pfn, DAX_SIG); dev_dbg(dev, "dax: %s\n", rc == 0 ? dev_name(dax_dev) : ""); diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c index 0982215371ba0d..41c67dfa80158e 100644 --- a/drivers/nvdimm/e820.c +++ b/drivers/nvdimm/e820.c @@ -59,7 +59,7 @@ static int e820_pmem_probe(struct platform_device *pdev) static struct platform_driver e820_pmem_driver = { .probe = e820_pmem_probe, - .remove_new = e820_pmem_remove, + .remove = e820_pmem_remove, .driver = { .name = "e820_pmem", }, diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 2dbb1dca17b534..5ca06e9a2d2925 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -600,6 +600,13 @@ struct nd_dax *to_nd_dax(struct device *dev); int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns); bool is_nd_dax(const struct device *dev); struct device *nd_dax_create(struct nd_region *nd_region); +static inline struct device *nd_dax_devinit(struct nd_dax *nd_dax, + struct nd_namespace_common *ndns) +{ + if (!nd_dax) + return NULL; + return nd_pfn_devinit(&nd_dax->nd_pfn, ndns); +} #else static inline int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns) diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c index f55d60922b87d3..c3f07be4aa22ad 100644 --- a/drivers/nvdimm/nd_virtio.c +++ b/drivers/nvdimm/nd_virtio.c @@ -97,7 +97,7 @@ static int virtio_pmem_flush(struct nd_region *nd_region) dev_info(&vdev->dev, "failed to send command to virtio pmem device\n"); err = -EIO; } else { - /* A host repsonse results in "host_ack" getting called */ + /* A host response results in "host_ack" getting called */ wait_event(req_data->host_acked, req_data->done); err = le32_to_cpu(req_data->resp.ret); } diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c index b4a1cf70e8b703..68bddab3fb46e6 100644 --- a/drivers/nvdimm/of_pmem.c +++ b/drivers/nvdimm/of_pmem.c @@ -100,7 +100,7 @@ static const struct of_device_id of_pmem_region_match[] = { static struct platform_driver of_pmem_region_driver = { .probe = of_pmem_region_probe, - .remove_new = of_pmem_region_remove, + .remove = of_pmem_region_remove, .driver = { .name = "of_pmem", .of_match_table = of_pmem_region_match, diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 586348125b61ab..cfdfe0eaa51210 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -539,7 +539,7 @@ int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig) if (!nd_pfn->uuid) { /* - * When probing a namepace via nd_pfn_probe() the uuid + * When probing a namespace via nd_pfn_probe() the uuid * is NULL (see: nd_pfn_devinit()) we init settings from * pfn_sb */ diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 210fb77f51ba02..d81faa9d89c935 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -316,7 +316,7 @@ static long pmem_dax_direct_access(struct dax_device *dax_dev, * range, filesystem turns the normal pwrite to a dax_recovery_write. * * The recovery write consists of clearing media poison, clearing page - * HWPoison bit, reenable page-wide read-write permission, flush the + * HWPoison bit, re-enable page-wide read-write permission, flush the * caches and finally write. A competing pread thread will be held * off during the recovery process since data read back might not be * valid, and this is achieved by clearing the badblock records after diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 9e4f7ff024a000..37417ce5ec7bec 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -1270,4 +1270,4 @@ int nd_region_conflict(struct nd_region *nd_region, resource_size_t start, return device_for_each_child(&nvdimm_bus->dev, &ctx, region_conflict); } -MODULE_IMPORT_NS(DEVMEM); +MODULE_IMPORT_NS("DEVMEM"); diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c index c9b97aeabf854a..2396d19ce54969 100644 --- a/drivers/nvdimm/virtio_pmem.c +++ b/drivers/nvdimm/virtio_pmem.c @@ -143,6 +143,28 @@ static void virtio_pmem_remove(struct virtio_device *vdev) virtio_reset_device(vdev); } +static int virtio_pmem_freeze(struct virtio_device *vdev) +{ + vdev->config->del_vqs(vdev); + virtio_reset_device(vdev); + + return 0; +} + +static int virtio_pmem_restore(struct virtio_device *vdev) +{ + int ret; + + ret = init_vq(vdev->priv); + if (ret) { + dev_err(&vdev->dev, "failed to initialize virtio pmem's vq\n"); + return ret; + } + virtio_device_ready(vdev); + + return 0; +} + static unsigned int features[] = { VIRTIO_PMEM_F_SHMEM_REGION, }; @@ -155,6 +177,8 @@ static struct virtio_driver virtio_pmem_driver = { .validate = virtio_pmem_validate, .probe = virtio_pmem_probe, .remove = virtio_pmem_remove, + .freeze = virtio_pmem_freeze, + .restore = virtio_pmem_restore, }; module_virtio_driver(virtio_pmem_driver); diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index b1387dc459a323..4319ab50c10d11 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -649,7 +649,7 @@ static bool apple_nvme_handle_cq(struct apple_nvme_queue *q, bool force) found = apple_nvme_poll_cq(q, &iob); - if (!rq_list_empty(iob.req_list)) + if (!rq_list_empty(&iob.req_list)) apple_nvme_complete_batch(&iob); return found; @@ -1618,7 +1618,7 @@ static struct platform_driver apple_nvme_driver = { .pm = pm_sleep_ptr(&apple_nvme_pm_ops), }, .probe = apple_nvme_probe, - .remove_new = apple_nvme_remove, + .remove = apple_nvme_remove, .shutdown = apple_nvme_shutdown, }; module_platform_driver(apple_nvme_driver); diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 855b42c92284df..a970168a3014e6 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -42,6 +42,8 @@ struct nvme_ns_info { bool is_readonly; bool is_ready; bool is_removed; + bool is_rotational; + bool no_vwc; }; unsigned int admin_timeout = 60; @@ -700,7 +702,7 @@ void nvme_put_ns(struct nvme_ns *ns) { kref_put(&ns->kref, nvme_free_ns); } -EXPORT_SYMBOL_NS_GPL(nvme_put_ns, NVME_TARGET_PASSTHRU); +EXPORT_SYMBOL_NS_GPL(nvme_put_ns, "NVME_TARGET_PASSTHRU"); static inline void nvme_clear_nvme_request(struct request *req) { @@ -1121,7 +1123,7 @@ int nvme_execute_rq(struct request *rq, bool at_head) return nvme_req(rq)->status; return blk_status_to_errno(status); } -EXPORT_SYMBOL_NS_GPL(nvme_execute_rq, NVME_TARGET_PASSTHRU); +EXPORT_SYMBOL_NS_GPL(nvme_execute_rq, "NVME_TARGET_PASSTHRU"); /* * Returns 0 on success. If the result is negative, it's a Linux error code; @@ -1201,7 +1203,7 @@ u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode) return effects; } -EXPORT_SYMBOL_NS_GPL(nvme_command_effects, NVME_TARGET_PASSTHRU); +EXPORT_SYMBOL_NS_GPL(nvme_command_effects, "NVME_TARGET_PASSTHRU"); u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode) { @@ -1221,7 +1223,7 @@ u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode) } return effects; } -EXPORT_SYMBOL_NS_GPL(nvme_passthru_start, NVME_TARGET_PASSTHRU); +EXPORT_SYMBOL_NS_GPL(nvme_passthru_start, "NVME_TARGET_PASSTHRU"); void nvme_passthru_end(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u32 effects, struct nvme_command *cmd, int status) @@ -1266,7 +1268,7 @@ void nvme_passthru_end(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u32 effects, break; } } -EXPORT_SYMBOL_NS_GPL(nvme_passthru_end, NVME_TARGET_PASSTHRU); +EXPORT_SYMBOL_NS_GPL(nvme_passthru_end, "NVME_TARGET_PASSTHRU"); /* * Recommended frequency for KATO commands per NVMe 1.4 section 7.12.1: @@ -1303,9 +1305,10 @@ static void nvme_queue_keep_alive_work(struct nvme_ctrl *ctrl) queue_delayed_work(nvme_wq, &ctrl->ka_work, delay); } -static void nvme_keep_alive_finish(struct request *rq, - blk_status_t status, struct nvme_ctrl *ctrl) +static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq, + blk_status_t status) { + struct nvme_ctrl *ctrl = rq->end_io_data; unsigned long rtt = jiffies - (rq->deadline - rq->timeout); unsigned long delay = nvme_keep_alive_work_period(ctrl); enum nvme_ctrl_state state = nvme_ctrl_state(ctrl); @@ -1322,17 +1325,20 @@ static void nvme_keep_alive_finish(struct request *rq, delay = 0; } + blk_mq_free_request(rq); + if (status) { dev_err(ctrl->device, "failed nvme_keep_alive_end_io error=%d\n", status); - return; + return RQ_END_IO_NONE; } ctrl->ka_last_check_time = jiffies; ctrl->comp_seen = false; if (state == NVME_CTRL_LIVE || state == NVME_CTRL_CONNECTING) queue_delayed_work(nvme_wq, &ctrl->ka_work, delay); + return RQ_END_IO_NONE; } static void nvme_keep_alive_work(struct work_struct *work) @@ -1341,7 +1347,6 @@ static void nvme_keep_alive_work(struct work_struct *work) struct nvme_ctrl, ka_work); bool comp_seen = ctrl->comp_seen; struct request *rq; - blk_status_t status; ctrl->ka_last_check_time = jiffies; @@ -1364,9 +1369,9 @@ static void nvme_keep_alive_work(struct work_struct *work) nvme_init_request(rq, &ctrl->ka_cmd); rq->timeout = ctrl->kato * HZ; - status = blk_execute_rq(rq, false); - nvme_keep_alive_finish(rq, status, ctrl); - blk_mq_free_request(rq); + rq->end_io = nvme_keep_alive_end_io; + rq->end_io_data = ctrl; + blk_execute_rq_nowait(rq, false); } static void nvme_start_keep_alive(struct nvme_ctrl *ctrl) @@ -1639,6 +1644,8 @@ static int nvme_ns_info_from_id_cs_indep(struct nvme_ctrl *ctrl, info->is_shared = id->nmic & NVME_NS_NMIC_SHARED; info->is_readonly = id->nsattr & NVME_NS_ATTR_RO; info->is_ready = id->nstat & NVME_NSTAT_NRDY; + info->is_rotational = id->nsfeat & NVME_NS_ROTATIONAL; + info->no_vwc = id->nsfeat & NVME_NS_VWC_NOT_PRESENT; } kfree(id); return ret; @@ -2027,7 +2034,7 @@ static bool nvme_update_disk_info(struct nvme_ns *ns, struct nvme_id_ns *id, * or smaller than a sector size yet, so catch this early and don't * allow block I/O. */ - if (head->lba_shift > PAGE_SHIFT || head->lba_shift < SECTOR_SHIFT) { + if (blk_validate_block_size(bs)) { bs = (1 << 9); valid = false; } @@ -2064,7 +2071,8 @@ static bool nvme_update_disk_info(struct nvme_ns *ns, struct nvme_id_ns *id, lim->physical_block_size = min(phys_bs, atomic_bs); lim->io_min = phys_bs; lim->io_opt = io_opt; - if (ns->ctrl->quirks & NVME_QUIRK_DEALLOCATE_ZEROES) + if ((ns->ctrl->quirks & NVME_QUIRK_DEALLOCATE_ZEROES) && + (ns->ctrl->oncs & NVME_CTRL_ONCS_DSM)) lim->max_write_zeroes_sectors = UINT_MAX; else lim->max_write_zeroes_sectors = ns->ctrl->max_zeroes_sectors; @@ -2185,11 +2193,14 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns, ns->head->ids.csi == NVME_CSI_ZNS) nvme_update_zone_info(ns, &lim, &zi); - if (ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT) + if ((ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT) && !info->no_vwc) lim.features |= BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA; else lim.features &= ~(BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA); + if (info->is_rotational) + lim.features |= BLK_FEAT_ROTATIONAL; + /* * Register a metadata profile for PI, or the plain non-integrity NVMe * metadata masquerading as Type 0 if supported, otherwise reject block @@ -3250,8 +3261,9 @@ static int nvme_check_ctrl_fabric_info(struct nvme_ctrl *ctrl, struct nvme_id_ct } if (!ctrl->maxcmd) { - dev_err(ctrl->device, "Maximum outstanding commands is 0\n"); - return -EINVAL; + dev_warn(ctrl->device, + "Firmware bug: maximum outstanding commands is 0\n"); + ctrl->maxcmd = ctrl->sqsize + 1; } return 0; @@ -3636,6 +3648,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl, head->ns_id = info->nsid; head->ids = info->ids; head->shared = info->is_shared; + head->rotational = info->is_rotational; ratelimit_state_init(&head->rs_nuse, 5 * HZ, 1); ratelimit_set_flags(&head->rs_nuse, RATELIMIT_MSG_ON_RELEASE); kref_init(&head->ref); @@ -3809,7 +3822,7 @@ struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid) srcu_read_unlock(&ctrl->srcu, srcu_idx); return ret; } -EXPORT_SYMBOL_NS_GPL(nvme_find_get_ns, NVME_TARGET_PASSTHRU); +EXPORT_SYMBOL_NS_GPL(nvme_find_get_ns, "NVME_TARGET_PASSTHRU"); /* * Add the namespace to the controller list while keeping the list ordered. @@ -4017,7 +4030,7 @@ static void nvme_scan_ns(struct nvme_ctrl *ctrl, unsigned nsid) { struct nvme_ns_info info = { .nsid = nsid }; struct nvme_ns *ns; - int ret; + int ret = 1; if (nvme_identify_ns_descs(ctrl, &info)) return; @@ -4034,9 +4047,10 @@ static void nvme_scan_ns(struct nvme_ctrl *ctrl, unsigned nsid) * set up a namespace. If not fall back to the legacy version. */ if ((ctrl->cap & NVME_CAP_CRMS_CRIMS) || - (info.ids.csi != NVME_CSI_NVM && info.ids.csi != NVME_CSI_ZNS)) + (info.ids.csi != NVME_CSI_NVM && info.ids.csi != NVME_CSI_ZNS) || + ctrl->vs >= NVME_VS(2, 0, 0)) ret = nvme_ns_info_from_id_cs_indep(ctrl, &info); - else + if (ret > 0) ret = nvme_ns_info_from_identify(ctrl, &info); if (info.is_removed) @@ -4591,6 +4605,11 @@ EXPORT_SYMBOL_GPL(nvme_alloc_admin_tag_set); void nvme_remove_admin_tag_set(struct nvme_ctrl *ctrl) { + /* + * As we're about to destroy the queue and free tagset + * we can not have keep-alive work running. + */ + nvme_stop_keep_alive(ctrl); blk_mq_destroy_queue(ctrl->admin_q); blk_put_queue(ctrl->admin_q); if (ctrl->ops->flags & NVME_F_FABRICS) { @@ -4895,7 +4914,7 @@ void nvme_unfreeze(struct nvme_ctrl *ctrl) srcu_idx = srcu_read_lock(&ctrl->srcu); list_for_each_entry_srcu(ns, &ctrl->namespaces, list, srcu_read_lock_held(&ctrl->srcu)) - blk_mq_unfreeze_queue(ns->queue); + blk_mq_unfreeze_queue_non_owner(ns->queue); srcu_read_unlock(&ctrl->srcu, srcu_idx); clear_bit(NVME_CTRL_FROZEN, &ctrl->flags); } @@ -4940,7 +4959,12 @@ void nvme_start_freeze(struct nvme_ctrl *ctrl) srcu_idx = srcu_read_lock(&ctrl->srcu); list_for_each_entry_srcu(ns, &ctrl->namespaces, list, srcu_read_lock_held(&ctrl->srcu)) - blk_freeze_queue_start(ns->queue); + /* + * Typical non_owner use case is from pci driver, in which + * start_freeze is called from timeout work function, but + * unfreeze is done in reset work context + */ + blk_freeze_queue_start_non_owner(ns->queue); srcu_read_unlock(&ctrl->srcu, srcu_idx); } EXPORT_SYMBOL_GPL(nvme_start_freeze); @@ -5008,7 +5032,7 @@ struct nvme_ctrl *nvme_ctrl_from_file(struct file *file) return NULL; return file->private_data; } -EXPORT_SYMBOL_NS_GPL(nvme_ctrl_from_file, NVME_TARGET_PASSTHRU); +EXPORT_SYMBOL_NS_GPL(nvme_ctrl_from_file, "NVME_TARGET_PASSTHRU"); /* * Check we didn't inadvertently grow the command structure sizes: @@ -5036,6 +5060,8 @@ static inline void _nvme_check_size(void) BUILD_BUG_ON(sizeof(struct nvme_id_ctrl_nvm) != NVME_IDENTIFY_DATA_SIZE); BUILD_BUG_ON(sizeof(struct nvme_lba_range_type) != 64); BUILD_BUG_ON(sizeof(struct nvme_smart_log) != 512); + BUILD_BUG_ON(sizeof(struct nvme_endurance_group_log) != 512); + BUILD_BUG_ON(sizeof(struct nvme_rotational_media_log) != 512); BUILD_BUG_ON(sizeof(struct nvme_dbbuf) != 64); BUILD_BUG_ON(sizeof(struct nvme_directive_cmd) != 64); BUILD_BUG_ON(sizeof(struct nvme_feat_host_behavior) != 512); @@ -5044,22 +5070,20 @@ static inline void _nvme_check_size(void) static int __init nvme_core_init(void) { + unsigned int wq_flags = WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS; int result = -ENOMEM; _nvme_check_size(); - nvme_wq = alloc_workqueue("nvme-wq", - WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0); + nvme_wq = alloc_workqueue("nvme-wq", wq_flags, 0); if (!nvme_wq) goto out; - nvme_reset_wq = alloc_workqueue("nvme-reset-wq", - WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0); + nvme_reset_wq = alloc_workqueue("nvme-reset-wq", wq_flags, 0); if (!nvme_reset_wq) goto destroy_wq; - nvme_delete_wq = alloc_workqueue("nvme-delete-wq", - WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0); + nvme_delete_wq = alloc_workqueue("nvme-delete-wq", wq_flags, 0); if (!nvme_delete_wq) goto destroy_reset_wq; diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c index a96976b22fa796..e8930146847af4 100644 --- a/drivers/nvme/host/ioctl.c +++ b/drivers/nvme/host/ioctl.c @@ -114,18 +114,26 @@ static struct request *nvme_alloc_user_request(struct request_queue *q, static int nvme_map_user_request(struct request *req, u64 ubuffer, unsigned bufflen, void __user *meta_buffer, unsigned meta_len, - u32 meta_seed, struct io_uring_cmd *ioucmd, unsigned int flags) + struct io_uring_cmd *ioucmd, unsigned int flags) { struct request_queue *q = req->q; struct nvme_ns *ns = q->queuedata; struct block_device *bdev = ns ? ns->disk->part0 : NULL; bool supports_metadata = bdev && blk_get_integrity(bdev->bd_disk); + struct nvme_ctrl *ctrl = nvme_req(req)->ctrl; bool has_metadata = meta_buffer && meta_len; struct bio *bio = NULL; int ret; - if (has_metadata && !supports_metadata) - return -EINVAL; + if (!nvme_ctrl_sgl_supported(ctrl)) + dev_warn_once(ctrl->device, "using unchecked data buffer\n"); + if (has_metadata) { + if (!supports_metadata) + return -EINVAL; + if (!nvme_ctrl_meta_sgl_supported(ctrl)) + dev_warn_once(ctrl->device, + "using unchecked metadata buffer\n"); + } if (ioucmd && (ioucmd->flags & IORING_URING_CMD_FIXED)) { struct iov_iter iter; @@ -152,8 +160,7 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, bio_set_dev(bio, bdev); if (has_metadata) { - ret = blk_rq_integrity_map_user(req, meta_buffer, meta_len, - meta_seed); + ret = blk_rq_integrity_map_user(req, meta_buffer, meta_len); if (ret) goto out_unmap; } @@ -170,7 +177,7 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer, static int nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd, u64 ubuffer, unsigned bufflen, - void __user *meta_buffer, unsigned meta_len, u32 meta_seed, + void __user *meta_buffer, unsigned meta_len, u64 *result, unsigned timeout, unsigned int flags) { struct nvme_ns *ns = q->queuedata; @@ -187,7 +194,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, req->timeout = timeout; if (ubuffer && bufflen) { ret = nvme_map_user_request(req, ubuffer, bufflen, meta_buffer, - meta_len, meta_seed, NULL, flags); + meta_len, NULL, flags); if (ret) return ret; } @@ -268,7 +275,7 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) c.rw.lbatm = cpu_to_le16(io.appmask); return nvme_submit_user_cmd(ns->queue, &c, io.addr, length, metadata, - meta_len, lower_32_bits(io.slba), NULL, 0, 0); + meta_len, NULL, 0, 0); } static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl, @@ -323,7 +330,7 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, cmd.addr, cmd.data_len, nvme_to_user_ptr(cmd.metadata), - cmd.metadata_len, 0, &result, timeout, 0); + cmd.metadata_len, &result, timeout, 0); if (status >= 0) { if (put_user(result, &ucmd->result)) @@ -370,7 +377,7 @@ static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, cmd.addr, cmd.data_len, nvme_to_user_ptr(cmd.metadata), - cmd.metadata_len, 0, &cmd.result, timeout, flags); + cmd.metadata_len, &cmd.result, timeout, flags); if (status >= 0) { if (put_user(cmd.result, &ucmd->result)) @@ -402,7 +409,7 @@ struct nvme_uring_cmd_pdu { static inline struct nvme_uring_cmd_pdu *nvme_uring_cmd_pdu( struct io_uring_cmd *ioucmd) { - return (struct nvme_uring_cmd_pdu *)&ioucmd->pdu; + return io_uring_cmd_to_pdu(ioucmd, struct nvme_uring_cmd_pdu); } static void nvme_uring_task_cb(struct io_uring_cmd *ioucmd, @@ -507,7 +514,7 @@ static int nvme_uring_cmd_io(struct nvme_ctrl *ctrl, struct nvme_ns *ns, if (d.addr && d.data_len) { ret = nvme_map_user_request(req, d.addr, d.data_len, nvme_to_user_ptr(d.metadata), - d.metadata_len, 0, ioucmd, vec); + d.metadata_len, ioucmd, vec); if (ret) return ret; } @@ -635,8 +642,6 @@ static int nvme_ns_uring_cmd(struct nvme_ns *ns, struct io_uring_cmd *ioucmd, struct nvme_ctrl *ctrl = ns->ctrl; int ret; - BUILD_BUG_ON(sizeof(struct nvme_uring_cmd_pdu) > sizeof(ioucmd->pdu)); - ret = nvme_uring_cmd_checks(issue_flags); if (ret) return ret; diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 6a15873055b951..a85d190942bdf9 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -165,7 +165,8 @@ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl) int srcu_idx; srcu_idx = srcu_read_lock(&ctrl->srcu); - list_for_each_entry_rcu(ns, &ctrl->namespaces, list) { + list_for_each_entry_srcu(ns, &ctrl->namespaces, list, + srcu_read_lock_held(&ctrl->srcu)) { if (!ns->head->disk) continue; kblockd_schedule_work(&ns->head->requeue_work); @@ -209,7 +210,8 @@ void nvme_mpath_clear_ctrl_paths(struct nvme_ctrl *ctrl) int srcu_idx; srcu_idx = srcu_read_lock(&ctrl->srcu); - list_for_each_entry_rcu(ns, &ctrl->namespaces, list) { + list_for_each_entry_srcu(ns, &ctrl->namespaces, list, + srcu_read_lock_held(&ctrl->srcu)) { nvme_mpath_clear_current_path(ns); kblockd_schedule_work(&ns->head->requeue_work); } @@ -224,7 +226,8 @@ void nvme_mpath_revalidate_paths(struct nvme_ns *ns) int srcu_idx; srcu_idx = srcu_read_lock(&head->srcu); - list_for_each_entry_rcu(ns, &head->list, siblings) { + list_for_each_entry_srcu(ns, &head->list, siblings, + srcu_read_lock_held(&head->srcu)) { if (capacity != get_capacity(ns->disk)) clear_bit(NVME_NS_READY, &ns->flags); } @@ -257,7 +260,8 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node) int found_distance = INT_MAX, fallback_distance = INT_MAX, distance; struct nvme_ns *found = NULL, *fallback = NULL, *ns; - list_for_each_entry_rcu(ns, &head->list, siblings) { + list_for_each_entry_srcu(ns, &head->list, siblings, + srcu_read_lock_held(&head->srcu)) { if (nvme_path_is_disabled(ns)) continue; @@ -356,7 +360,8 @@ static struct nvme_ns *nvme_queue_depth_path(struct nvme_ns_head *head) unsigned int min_depth_opt = UINT_MAX, min_depth_nonopt = UINT_MAX; unsigned int depth; - list_for_each_entry_rcu(ns, &head->list, siblings) { + list_for_each_entry_srcu(ns, &head->list, siblings, + srcu_read_lock_held(&head->srcu)) { if (nvme_path_is_disabled(ns)) continue; @@ -424,7 +429,8 @@ static bool nvme_available_path(struct nvme_ns_head *head) if (!test_bit(NVME_NSHEAD_DISK_LIVE, &head->flags)) return NULL; - list_for_each_entry_rcu(ns, &head->list, siblings) { + list_for_each_entry_srcu(ns, &head->list, siblings, + srcu_read_lock_held(&head->srcu)) { if (test_bit(NVME_CTRL_FAILFAST_EXPIRED, &ns->ctrl->flags)) continue; switch (nvme_ctrl_state(ns->ctrl)) { @@ -635,8 +641,6 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head) lim.features |= BLK_FEAT_IO_STAT | BLK_FEAT_NOWAIT | BLK_FEAT_POLL; if (head->ids.csi == NVME_CSI_ZNS) lim.features |= BLK_FEAT_ZONED; - else - lim.max_zone_append_sectors = 0; head->disk = blk_alloc_disk(&lim, ctrl->numa_node); if (IS_ERR(head->disk)) @@ -785,7 +789,8 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl, return 0; srcu_idx = srcu_read_lock(&ctrl->srcu); - list_for_each_entry_rcu(ns, &ctrl->namespaces, list) { + list_for_each_entry_srcu(ns, &ctrl->namespaces, list, + srcu_read_lock_held(&ctrl->srcu)) { unsigned nsid; again: nsid = le32_to_cpu(desc->nsids[n]); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index 093cb423f536be..611b02c8a8b37b 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -474,6 +474,7 @@ struct nvme_ns_head { struct list_head entry; struct kref ref; bool shared; + bool rotational; bool passthru_err_log_enabled; struct nvme_effects_log *effects; u64 nuse; @@ -1122,7 +1123,15 @@ static inline void nvme_start_request(struct request *rq) static inline bool nvme_ctrl_sgl_supported(struct nvme_ctrl *ctrl) { - return ctrl->sgls & ((1 << 0) | (1 << 1)); + return ctrl->sgls & (NVME_CTRL_SGLS_BYTE_ALIGNED | + NVME_CTRL_SGLS_DWORD_ALIGNED); +} + +static inline bool nvme_ctrl_meta_sgl_supported(struct nvme_ctrl *ctrl) +{ + if (ctrl->ops->flags & NVME_F_FABRICS) + return true; + return ctrl->sgls & NVME_CTRL_SGLS_MSDS; } #ifdef CONFIG_NVME_HOST_AUTH diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 4b9fda0b1d9a33..1a5ba80f1811a3 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -43,6 +43,7 @@ */ #define NVME_MAX_KB_SZ 8192 #define NVME_MAX_SEGS 128 +#define NVME_MAX_META_SEGS 15 #define NVME_MAX_NR_ALLOCATIONS 5 static int use_threaded_interrupts; @@ -141,8 +142,10 @@ struct nvme_dev { struct nvme_ctrl ctrl; u32 last_ps; bool hmb; + struct sg_table *hmb_sgt; mempool_t *iod_mempool; + mempool_t *iod_meta_mempool; /* shadow doorbell buffer support: */ __le32 *dbbuf_dbs; @@ -153,6 +156,7 @@ struct nvme_dev { /* host memory buffer support: */ u64 host_mem_size; u32 nr_host_mem_descs; + u32 host_mem_descs_size; dma_addr_t host_mem_descs_dma; struct nvme_host_mem_buf_desc *host_mem_descs; void **host_mem_desc_bufs; @@ -237,6 +241,8 @@ struct nvme_iod { dma_addr_t first_dma; dma_addr_t meta_dma; struct sg_table sgt; + struct sg_table meta_sgt; + union nvme_descriptor meta_list; union nvme_descriptor list[NVME_MAX_NR_ALLOCATIONS]; }; @@ -504,6 +510,15 @@ static void nvme_commit_rqs(struct blk_mq_hw_ctx *hctx) spin_unlock(&nvmeq->sq_lock); } +static inline bool nvme_pci_metadata_use_sgls(struct nvme_dev *dev, + struct request *req) +{ + if (!nvme_ctrl_meta_sgl_supported(&dev->ctrl)) + return false; + return req->nr_integrity_segments > 1 || + nvme_req(req)->flags & NVME_REQ_USERCMD; +} + static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req, int nseg) { @@ -516,8 +531,10 @@ static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req, return false; if (!nvmeq->qid) return false; + if (nvme_pci_metadata_use_sgls(dev, req)) + return true; if (!sgl_threshold || avg_seg_size < sgl_threshold) - return false; + return nvme_req(req)->flags & NVME_REQ_USERCMD; return true; } @@ -778,7 +795,8 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req, struct bio_vec bv = req_bvec(req); if (!is_pci_p2pdma_page(bv.bv_page)) { - if ((bv.bv_offset & (NVME_CTRL_PAGE_SIZE - 1)) + + if (!nvme_pci_metadata_use_sgls(dev, req) && + (bv.bv_offset & (NVME_CTRL_PAGE_SIZE - 1)) + bv.bv_len <= NVME_CTRL_PAGE_SIZE * 2) return nvme_setup_prp_simple(dev, req, &cmnd->rw, &bv); @@ -822,11 +840,69 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req, return ret; } -static blk_status_t nvme_map_metadata(struct nvme_dev *dev, struct request *req, - struct nvme_command *cmnd) +static blk_status_t nvme_pci_setup_meta_sgls(struct nvme_dev *dev, + struct request *req) +{ + struct nvme_iod *iod = blk_mq_rq_to_pdu(req); + struct nvme_rw_command *cmnd = &iod->cmd.rw; + struct nvme_sgl_desc *sg_list; + struct scatterlist *sgl, *sg; + unsigned int entries; + dma_addr_t sgl_dma; + int rc, i; + + iod->meta_sgt.sgl = mempool_alloc(dev->iod_meta_mempool, GFP_ATOMIC); + if (!iod->meta_sgt.sgl) + return BLK_STS_RESOURCE; + + sg_init_table(iod->meta_sgt.sgl, req->nr_integrity_segments); + iod->meta_sgt.orig_nents = blk_rq_map_integrity_sg(req, + iod->meta_sgt.sgl); + if (!iod->meta_sgt.orig_nents) + goto out_free_sg; + + rc = dma_map_sgtable(dev->dev, &iod->meta_sgt, rq_dma_dir(req), + DMA_ATTR_NO_WARN); + if (rc) + goto out_free_sg; + + sg_list = dma_pool_alloc(dev->prp_small_pool, GFP_ATOMIC, &sgl_dma); + if (!sg_list) + goto out_unmap_sg; + + entries = iod->meta_sgt.nents; + iod->meta_list.sg_list = sg_list; + iod->meta_dma = sgl_dma; + + cmnd->flags = NVME_CMD_SGL_METASEG; + cmnd->metadata = cpu_to_le64(sgl_dma); + + sgl = iod->meta_sgt.sgl; + if (entries == 1) { + nvme_pci_sgl_set_data(sg_list, sgl); + return BLK_STS_OK; + } + + sgl_dma += sizeof(*sg_list); + nvme_pci_sgl_set_seg(sg_list, sgl_dma, entries); + for_each_sg(sgl, sg, entries, i) + nvme_pci_sgl_set_data(&sg_list[i + 1], sg); + + return BLK_STS_OK; + +out_unmap_sg: + dma_unmap_sgtable(dev->dev, &iod->meta_sgt, rq_dma_dir(req), 0); +out_free_sg: + mempool_free(iod->meta_sgt.sgl, dev->iod_meta_mempool); + return BLK_STS_RESOURCE; +} + +static blk_status_t nvme_pci_setup_meta_mptr(struct nvme_dev *dev, + struct request *req) { struct nvme_iod *iod = blk_mq_rq_to_pdu(req); struct bio_vec bv = rq_integrity_vec(req); + struct nvme_command *cmnd = &iod->cmd; iod->meta_dma = dma_map_bvec(dev->dev, &bv, rq_dma_dir(req), 0); if (dma_mapping_error(dev->dev, iod->meta_dma)) @@ -835,6 +911,13 @@ static blk_status_t nvme_map_metadata(struct nvme_dev *dev, struct request *req, return BLK_STS_OK; } +static blk_status_t nvme_map_metadata(struct nvme_dev *dev, struct request *req) +{ + if (nvme_pci_metadata_use_sgls(dev, req)) + return nvme_pci_setup_meta_sgls(dev, req); + return nvme_pci_setup_meta_mptr(dev, req); +} + static blk_status_t nvme_prep_rq(struct nvme_dev *dev, struct request *req) { struct nvme_iod *iod = blk_mq_rq_to_pdu(req); @@ -843,6 +926,7 @@ static blk_status_t nvme_prep_rq(struct nvme_dev *dev, struct request *req) iod->aborted = false; iod->nr_allocations = -1; iod->sgt.nents = 0; + iod->meta_sgt.nents = 0; ret = nvme_setup_cmd(req->q->queuedata, req); if (ret) @@ -855,7 +939,7 @@ static blk_status_t nvme_prep_rq(struct nvme_dev *dev, struct request *req) } if (blk_integrity_rq(req)) { - ret = nvme_map_metadata(dev, req, &iod->cmd); + ret = nvme_map_metadata(dev, req); if (ret) goto out_unmap_data; } @@ -902,11 +986,12 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx, return BLK_STS_OK; } -static void nvme_submit_cmds(struct nvme_queue *nvmeq, struct request **rqlist) +static void nvme_submit_cmds(struct nvme_queue *nvmeq, struct rq_list *rqlist) { + struct request *req; + spin_lock(&nvmeq->sq_lock); - while (!rq_list_empty(*rqlist)) { - struct request *req = rq_list_pop(rqlist); + while ((req = rq_list_pop(rqlist))) { struct nvme_iod *iod = blk_mq_rq_to_pdu(req); nvme_sq_copy_cmd(nvmeq, &iod->cmd); @@ -929,34 +1014,45 @@ static bool nvme_prep_rq_batch(struct nvme_queue *nvmeq, struct request *req) return nvme_prep_rq(nvmeq->dev, req) == BLK_STS_OK; } -static void nvme_queue_rqs(struct request **rqlist) +static void nvme_queue_rqs(struct rq_list *rqlist) { - struct request *req, *next, *prev = NULL; - struct request *requeue_list = NULL; + struct rq_list submit_list = { }; + struct rq_list requeue_list = { }; + struct nvme_queue *nvmeq = NULL; + struct request *req; - rq_list_for_each_safe(rqlist, req, next) { - struct nvme_queue *nvmeq = req->mq_hctx->driver_data; + while ((req = rq_list_pop(rqlist))) { + if (nvmeq && nvmeq != req->mq_hctx->driver_data) + nvme_submit_cmds(nvmeq, &submit_list); + nvmeq = req->mq_hctx->driver_data; - if (!nvme_prep_rq_batch(nvmeq, req)) { - /* detach 'req' and add to remainder list */ - rq_list_move(rqlist, &requeue_list, req, prev); + if (nvme_prep_rq_batch(nvmeq, req)) + rq_list_add_tail(&submit_list, req); + else + rq_list_add_tail(&requeue_list, req); + } - req = prev; - if (!req) - continue; - } + if (nvmeq) + nvme_submit_cmds(nvmeq, &submit_list); + *rqlist = requeue_list; +} + +static __always_inline void nvme_unmap_metadata(struct nvme_dev *dev, + struct request *req) +{ + struct nvme_iod *iod = blk_mq_rq_to_pdu(req); - if (!next || req->mq_hctx != next->mq_hctx) { - /* detach rest of list, and submit */ - req->rq_next = NULL; - nvme_submit_cmds(nvmeq, rqlist); - *rqlist = next; - prev = NULL; - } else - prev = req; + if (!iod->meta_sgt.nents) { + dma_unmap_page(dev->dev, iod->meta_dma, + rq_integrity_vec(req).bv_len, + rq_dma_dir(req)); + return; } - *rqlist = requeue_list; + dma_pool_free(dev->prp_small_pool, iod->meta_list.sg_list, + iod->meta_dma); + dma_unmap_sgtable(dev->dev, &iod->meta_sgt, rq_dma_dir(req), 0); + mempool_free(iod->meta_sgt.sgl, dev->iod_meta_mempool); } static __always_inline void nvme_pci_unmap_rq(struct request *req) @@ -964,12 +1060,8 @@ static __always_inline void nvme_pci_unmap_rq(struct request *req) struct nvme_queue *nvmeq = req->mq_hctx->driver_data; struct nvme_dev *dev = nvmeq->dev; - if (blk_integrity_rq(req)) { - struct nvme_iod *iod = blk_mq_rq_to_pdu(req); - - dma_unmap_page(dev->dev, iod->meta_dma, - rq_integrity_vec(req).bv_len, rq_dma_dir(req)); - } + if (blk_integrity_rq(req)) + nvme_unmap_metadata(dev, req); if (blk_rq_nr_phys_segments(req)) nvme_unmap_data(dev, req); @@ -1083,7 +1175,7 @@ static irqreturn_t nvme_irq(int irq, void *data) DEFINE_IO_COMP_BATCH(iob); if (nvme_poll_cq(nvmeq, &iob)) { - if (!rq_list_empty(iob.req_list)) + if (!rq_list_empty(&iob.req_list)) nvme_pci_complete_batch(&iob); return IRQ_HANDLED; } @@ -1951,7 +2043,7 @@ static int nvme_set_host_mem(struct nvme_dev *dev, u32 bits) return ret; } -static void nvme_free_host_mem(struct nvme_dev *dev) +static void nvme_free_host_mem_multi(struct nvme_dev *dev) { int i; @@ -1966,18 +2058,54 @@ static void nvme_free_host_mem(struct nvme_dev *dev) kfree(dev->host_mem_desc_bufs); dev->host_mem_desc_bufs = NULL; - dma_free_coherent(dev->dev, - dev->nr_host_mem_descs * sizeof(*dev->host_mem_descs), +} + +static void nvme_free_host_mem(struct nvme_dev *dev) +{ + if (dev->hmb_sgt) + dma_free_noncontiguous(dev->dev, dev->host_mem_size, + dev->hmb_sgt, DMA_BIDIRECTIONAL); + else + nvme_free_host_mem_multi(dev); + + dma_free_coherent(dev->dev, dev->host_mem_descs_size, dev->host_mem_descs, dev->host_mem_descs_dma); dev->host_mem_descs = NULL; + dev->host_mem_descs_size = 0; dev->nr_host_mem_descs = 0; } -static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred, +static int nvme_alloc_host_mem_single(struct nvme_dev *dev, u64 size) +{ + dev->hmb_sgt = dma_alloc_noncontiguous(dev->dev, size, + DMA_BIDIRECTIONAL, GFP_KERNEL, 0); + if (!dev->hmb_sgt) + return -ENOMEM; + + dev->host_mem_descs = dma_alloc_coherent(dev->dev, + sizeof(*dev->host_mem_descs), &dev->host_mem_descs_dma, + GFP_KERNEL); + if (!dev->host_mem_descs) { + dma_free_noncontiguous(dev->dev, dev->host_mem_size, + dev->hmb_sgt, DMA_BIDIRECTIONAL); + dev->hmb_sgt = NULL; + return -ENOMEM; + } + dev->host_mem_size = size; + dev->host_mem_descs_size = sizeof(*dev->host_mem_descs); + dev->nr_host_mem_descs = 1; + + dev->host_mem_descs[0].addr = + cpu_to_le64(dev->hmb_sgt->sgl->dma_address); + dev->host_mem_descs[0].size = cpu_to_le32(size / NVME_CTRL_PAGE_SIZE); + return 0; +} + +static int nvme_alloc_host_mem_multi(struct nvme_dev *dev, u64 preferred, u32 chunk_size) { struct nvme_host_mem_buf_desc *descs; - u32 max_entries, len; + u32 max_entries, len, descs_size; dma_addr_t descs_dma; int i = 0; void **bufs; @@ -1990,8 +2118,9 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred, if (dev->ctrl.hmmaxd && dev->ctrl.hmmaxd < max_entries) max_entries = dev->ctrl.hmmaxd; - descs = dma_alloc_coherent(dev->dev, max_entries * sizeof(*descs), - &descs_dma, GFP_KERNEL); + descs_size = max_entries * sizeof(*descs); + descs = dma_alloc_coherent(dev->dev, descs_size, &descs_dma, + GFP_KERNEL); if (!descs) goto out; @@ -2020,6 +2149,7 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred, dev->host_mem_size = size; dev->host_mem_descs = descs; dev->host_mem_descs_dma = descs_dma; + dev->host_mem_descs_size = descs_size; dev->host_mem_desc_bufs = bufs; return 0; @@ -2034,8 +2164,7 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred, kfree(bufs); out_free_descs: - dma_free_coherent(dev->dev, max_entries * sizeof(*descs), descs, - descs_dma); + dma_free_coherent(dev->dev, descs_size, descs, descs_dma); out: dev->host_mem_descs = NULL; return -ENOMEM; @@ -2043,13 +2172,23 @@ static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred, static int nvme_alloc_host_mem(struct nvme_dev *dev, u64 min, u64 preferred) { + unsigned long dma_merge_boundary = dma_get_merge_boundary(dev->dev); u64 min_chunk = min_t(u64, preferred, PAGE_SIZE * MAX_ORDER_NR_PAGES); u64 hmminds = max_t(u32, dev->ctrl.hmminds * 4096, PAGE_SIZE * 2); u64 chunk_size; + /* + * If there is an IOMMU that can merge pages, try a virtually + * non-contiguous allocation for a single segment first. + */ + if (dma_merge_boundary && (PAGE_SIZE & dma_merge_boundary) == 0) { + if (!nvme_alloc_host_mem_single(dev, preferred)) + return 0; + } + /* start big and work our way down */ for (chunk_size = min_chunk; chunk_size >= hmminds; chunk_size /= 2) { - if (!__nvme_alloc_host_mem(dev, preferred, chunk_size)) { + if (!nvme_alloc_host_mem_multi(dev, preferred, chunk_size)) { if (!min || dev->host_mem_size >= min) return 0; nvme_free_host_mem(dev); @@ -2097,8 +2236,10 @@ static int nvme_setup_host_mem(struct nvme_dev *dev) } dev_info(dev->ctrl.device, - "allocated %lld MiB host memory buffer.\n", - dev->host_mem_size >> ilog2(SZ_1M)); + "allocated %lld MiB host memory buffer (%u segment%s).\n", + dev->host_mem_size >> ilog2(SZ_1M), + dev->nr_host_mem_descs, + str_plural(dev->nr_host_mem_descs)); } ret = nvme_set_host_mem(dev, enable_bits); @@ -2717,6 +2858,7 @@ static void nvme_release_prp_pools(struct nvme_dev *dev) static int nvme_pci_alloc_iod_mempool(struct nvme_dev *dev) { + size_t meta_size = sizeof(struct scatterlist) * (NVME_MAX_META_SEGS + 1); size_t alloc_size = sizeof(struct scatterlist) * NVME_MAX_SEGS; dev->iod_mempool = mempool_create_node(1, @@ -2725,7 +2867,18 @@ static int nvme_pci_alloc_iod_mempool(struct nvme_dev *dev) dev_to_node(dev->dev)); if (!dev->iod_mempool) return -ENOMEM; + + dev->iod_meta_mempool = mempool_create_node(1, + mempool_kmalloc, mempool_kfree, + (void *)meta_size, GFP_KERNEL, + dev_to_node(dev->dev)); + if (!dev->iod_meta_mempool) + goto free; + return 0; +free: + mempool_destroy(dev->iod_mempool); + return -ENOMEM; } static void nvme_free_tagset(struct nvme_dev *dev) @@ -2790,6 +2943,11 @@ static void nvme_reset_work(struct work_struct *work) if (result) goto out; + if (nvme_ctrl_meta_sgl_supported(&dev->ctrl)) + dev->ctrl.max_integrity_segments = NVME_MAX_META_SEGS; + else + dev->ctrl.max_integrity_segments = 1; + nvme_dbbuf_dma_alloc(dev); result = nvme_setup_host_mem(dev); @@ -3057,11 +3215,6 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev, dev->ctrl.max_hw_sectors = min_t(u32, NVME_MAX_KB_SZ << 1, dma_opt_mapping_size(&pdev->dev) >> 9); dev->ctrl.max_segments = NVME_MAX_SEGS; - - /* - * There is no support for SGLs for metadata (yet), so we are limited to - * a single integrity segment for the separate metadata pointer. - */ dev->ctrl.max_integrity_segments = 1; return dev; @@ -3124,6 +3277,11 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (result) goto out_disable; + if (nvme_ctrl_meta_sgl_supported(&dev->ctrl)) + dev->ctrl.max_integrity_segments = NVME_MAX_META_SEGS; + else + dev->ctrl.max_integrity_segments = 1; + nvme_dbbuf_dma_alloc(dev); result = nvme_setup_host_mem(dev); @@ -3166,6 +3324,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) nvme_free_queues(dev, 0); out_release_iod_mempool: mempool_destroy(dev->iod_mempool); + mempool_destroy(dev->iod_meta_mempool); out_release_prp_pools: nvme_release_prp_pools(dev); out_dev_unmap: @@ -3231,6 +3390,7 @@ static void nvme_remove(struct pci_dev *pdev) nvme_dbbuf_dma_free(dev); nvme_free_queues(dev, 0); mempool_destroy(dev->iod_mempool); + mempool_destroy(dev->iod_meta_mempool); nvme_release_prp_pools(dev); nvme_dev_unmap(dev); nvme_uninit_ctrl(&dev->ctrl); @@ -3429,12 +3589,10 @@ static const struct pci_device_id nvme_id_table[] = { NVME_QUIRK_DEALLOCATE_ZEROES, }, { PCI_VDEVICE(INTEL, 0x0a54), /* Intel P4500/P4600 */ .driver_data = NVME_QUIRK_STRIPE_SIZE | - NVME_QUIRK_DEALLOCATE_ZEROES | NVME_QUIRK_IGNORE_DEV_SUBNQN | NVME_QUIRK_BOGUS_NID, }, { PCI_VDEVICE(INTEL, 0x0a55), /* Dell Express Flash P4600 */ - .driver_data = NVME_QUIRK_STRIPE_SIZE | - NVME_QUIRK_DEALLOCATE_ZEROES, }, + .driver_data = NVME_QUIRK_STRIPE_SIZE, }, { PCI_VDEVICE(INTEL, 0xf1a5), /* Intel 600P/P3100 */ .driver_data = NVME_QUIRK_NO_DEEPEST_PS | NVME_QUIRK_MEDIUM_PRIO_SQ | diff --git a/drivers/nvme/host/pr.c b/drivers/nvme/host/pr.c index dc7922f226004f..cf2d2c5039ddbf 100644 --- a/drivers/nvme/host/pr.c +++ b/drivers/nvme/host/pr.c @@ -94,109 +94,137 @@ static int nvme_status_to_pr_err(int status) } } -static int nvme_send_pr_command(struct block_device *bdev, - struct nvme_command *c, void *data, unsigned int data_len) +static int __nvme_send_pr_command(struct block_device *bdev, u32 cdw10, + u32 cdw11, u8 op, void *data, unsigned int data_len) { - if (nvme_disk_is_ns_head(bdev->bd_disk)) - return nvme_send_ns_head_pr_command(bdev, c, data, data_len); + struct nvme_command c = { 0 }; - return nvme_send_ns_pr_command(bdev->bd_disk->private_data, c, data, - data_len); + c.common.opcode = op; + c.common.cdw10 = cpu_to_le32(cdw10); + c.common.cdw11 = cpu_to_le32(cdw11); + + if (nvme_disk_is_ns_head(bdev->bd_disk)) + return nvme_send_ns_head_pr_command(bdev, &c, data, data_len); + return nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c, + data, data_len); } -static int nvme_pr_command(struct block_device *bdev, u32 cdw10, - u64 key, u64 sa_key, u8 op) +static int nvme_send_pr_command(struct block_device *bdev, u32 cdw10, u32 cdw11, + u8 op, void *data, unsigned int data_len) { - struct nvme_command c = { }; - u8 data[16] = { 0, }; int ret; - put_unaligned_le64(key, &data[0]); - put_unaligned_le64(sa_key, &data[8]); - - c.common.opcode = op; - c.common.cdw10 = cpu_to_le32(cdw10); - - ret = nvme_send_pr_command(bdev, &c, data, sizeof(data)); - if (ret < 0) - return ret; - - return nvme_status_to_pr_err(ret); + ret = __nvme_send_pr_command(bdev, cdw10, cdw11, op, data, data_len); + return ret < 0 ? ret : nvme_status_to_pr_err(ret); } -static int nvme_pr_register(struct block_device *bdev, u64 old, - u64 new, unsigned flags) +static int nvme_pr_register(struct block_device *bdev, u64 old_key, u64 new_key, + unsigned int flags) { + struct nvmet_pr_register_data data = { 0 }; u32 cdw10; if (flags & ~PR_FL_IGNORE_KEY) return -EOPNOTSUPP; - cdw10 = old ? 2 : 0; - cdw10 |= (flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0; - cdw10 |= (1 << 30) | (1 << 31); /* PTPL=1 */ - return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_register); + data.crkey = cpu_to_le64(old_key); + data.nrkey = cpu_to_le64(new_key); + + cdw10 = old_key ? NVME_PR_REGISTER_ACT_REPLACE : + NVME_PR_REGISTER_ACT_REG; + cdw10 |= (flags & PR_FL_IGNORE_KEY) ? NVME_PR_IGNORE_KEY : 0; + cdw10 |= NVME_PR_CPTPL_PERSIST; + + return nvme_send_pr_command(bdev, cdw10, 0, nvme_cmd_resv_register, + &data, sizeof(data)); } static int nvme_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, unsigned flags) { + struct nvmet_pr_acquire_data data = { 0 }; u32 cdw10; if (flags & ~PR_FL_IGNORE_KEY) return -EOPNOTSUPP; - cdw10 = nvme_pr_type_from_blk(type) << 8; - cdw10 |= ((flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0); - return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_acquire); + data.crkey = cpu_to_le64(key); + + cdw10 = NVME_PR_ACQUIRE_ACT_ACQUIRE; + cdw10 |= nvme_pr_type_from_blk(type) << 8; + cdw10 |= (flags & PR_FL_IGNORE_KEY) ? NVME_PR_IGNORE_KEY : 0; + + return nvme_send_pr_command(bdev, cdw10, 0, nvme_cmd_resv_acquire, + &data, sizeof(data)); } static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new, enum pr_type type, bool abort) { - u32 cdw10 = nvme_pr_type_from_blk(type) << 8 | (abort ? 2 : 1); + struct nvmet_pr_acquire_data data = { 0 }; + u32 cdw10; + + data.crkey = cpu_to_le64(old); + data.prkey = cpu_to_le64(new); - return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire); + cdw10 = abort ? NVME_PR_ACQUIRE_ACT_PREEMPT_AND_ABORT : + NVME_PR_ACQUIRE_ACT_PREEMPT; + cdw10 |= nvme_pr_type_from_blk(type) << 8; + + return nvme_send_pr_command(bdev, cdw10, 0, nvme_cmd_resv_acquire, + &data, sizeof(data)); } static int nvme_pr_clear(struct block_device *bdev, u64 key) { - u32 cdw10 = 1 | (key ? 0 : 1 << 3); + struct nvmet_pr_release_data data = { 0 }; + u32 cdw10; + + data.crkey = cpu_to_le64(key); - return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release); + cdw10 = NVME_PR_RELEASE_ACT_CLEAR; + cdw10 |= key ? 0 : NVME_PR_IGNORE_KEY; + + return nvme_send_pr_command(bdev, cdw10, 0, nvme_cmd_resv_release, + &data, sizeof(data)); } static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type) { - u32 cdw10 = nvme_pr_type_from_blk(type) << 8 | (key ? 0 : 1 << 3); + struct nvmet_pr_release_data data = { 0 }; + u32 cdw10; + + data.crkey = cpu_to_le64(key); - return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release); + cdw10 = NVME_PR_RELEASE_ACT_RELEASE; + cdw10 |= nvme_pr_type_from_blk(type) << 8; + cdw10 |= key ? 0 : NVME_PR_IGNORE_KEY; + + return nvme_send_pr_command(bdev, cdw10, 0, nvme_cmd_resv_release, + &data, sizeof(data)); } static int nvme_pr_resv_report(struct block_device *bdev, void *data, u32 data_len, bool *eds) { - struct nvme_command c = { }; + u32 cdw10, cdw11; int ret; - c.common.opcode = nvme_cmd_resv_report; - c.common.cdw10 = cpu_to_le32(nvme_bytes_to_numd(data_len)); - c.common.cdw11 = cpu_to_le32(NVME_EXTENDED_DATA_STRUCT); + cdw10 = nvme_bytes_to_numd(data_len); + cdw11 = NVME_EXTENDED_DATA_STRUCT; *eds = true; retry: - ret = nvme_send_pr_command(bdev, &c, data, data_len); + ret = __nvme_send_pr_command(bdev, cdw10, cdw11, nvme_cmd_resv_report, + data, data_len); if (ret == NVME_SC_HOST_ID_INCONSIST && - c.common.cdw11 == cpu_to_le32(NVME_EXTENDED_DATA_STRUCT)) { - c.common.cdw11 = 0; + cdw11 == NVME_EXTENDED_DATA_STRUCT) { + cdw11 = 0; *eds = false; goto retry; } - if (ret < 0) - return ret; - - return nvme_status_to_pr_err(ret); + return ret < 0 ? ret : nvme_status_to_pr_err(ret); } static int nvme_pr_read_keys(struct block_device *bdev, diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 24a2759798d01e..86a2891d9bcc7a 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1019,7 +1019,7 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new) goto destroy_admin; } - if (!(ctrl->ctrl.sgls & (1 << 2))) { + if (!(ctrl->ctrl.sgls & NVME_CTRL_SGLS_KSDBDS)) { ret = -EOPNOTSUPP; dev_err(ctrl->ctrl.device, "Mandatory keyed sgls are not supported!\n"); @@ -1051,7 +1051,7 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new) ctrl->ctrl.sqsize = ctrl->ctrl.maxcmd - 1; } - if (ctrl->ctrl.sgls & (1 << 20)) + if (ctrl->ctrl.sgls & NVME_CTRL_SGLS_SAOS) ctrl->use_inline_data = true; if (ctrl->ctrl.queue_count > 1) { @@ -1091,13 +1091,7 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new) } destroy_admin: nvme_stop_keep_alive(&ctrl->ctrl); - nvme_quiesce_admin_queue(&ctrl->ctrl); - blk_sync_queue(ctrl->ctrl.admin_q); - nvme_rdma_stop_queue(&ctrl->queues[0]); - nvme_cancel_admin_tagset(&ctrl->ctrl); - if (new) - nvme_remove_admin_tag_set(&ctrl->ctrl); - nvme_rdma_destroy_admin_queue(ctrl); + nvme_rdma_teardown_admin_queue(ctrl, new); return ret; } diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 3e416af2659f19..28c76a3e1bd22b 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -2101,14 +2101,6 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new) return ret; } -static void nvme_tcp_destroy_admin_queue(struct nvme_ctrl *ctrl, bool remove) -{ - nvme_tcp_stop_queue(ctrl, 0); - if (remove) - nvme_remove_admin_tag_set(ctrl); - nvme_tcp_free_admin_queue(ctrl); -} - static int nvme_tcp_configure_admin_queue(struct nvme_ctrl *ctrl, bool new) { int error; @@ -2163,9 +2155,11 @@ static void nvme_tcp_teardown_admin_queue(struct nvme_ctrl *ctrl, blk_sync_queue(ctrl->admin_q); nvme_tcp_stop_queue(ctrl, 0); nvme_cancel_admin_tagset(ctrl); - if (remove) + if (remove) { nvme_unquiesce_admin_queue(ctrl); - nvme_tcp_destroy_admin_queue(ctrl, remove); + nvme_remove_admin_tag_set(ctrl); + } + nvme_tcp_free_admin_queue(ctrl); if (ctrl->tls_pskid) { dev_dbg(ctrl->device, "Wipe negotiated TLS_PSK %08x\n", ctrl->tls_pskid); @@ -2178,7 +2172,6 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl, { if (ctrl->queue_count <= 1) return; - nvme_quiesce_admin_queue(ctrl); nvme_quiesce_io_queues(ctrl); nvme_sync_io_queues(ctrl); nvme_tcp_stop_io_queues(ctrl); @@ -2278,7 +2271,7 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new) } destroy_admin: nvme_stop_keep_alive(ctrl); - nvme_tcp_teardown_admin_queue(ctrl, false); + nvme_tcp_teardown_admin_queue(ctrl, new); return ret; } diff --git a/drivers/nvme/host/trace.c b/drivers/nvme/host/trace.c index 87c437fc070d12..ad25ad1e40412c 100644 --- a/drivers/nvme/host/trace.c +++ b/drivers/nvme/host/trace.c @@ -228,27 +228,61 @@ static const char *nvme_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10) static const char *nvme_trace_resv_reg(struct trace_seq *p, u8 *cdw10) { + static const char * const rrega_strs[] = { + [0x00] = "register", + [0x01] = "unregister", + [0x02] = "replace", + }; const char *ret = trace_seq_buffer_ptr(p); u8 rrega = cdw10[0] & 0x7; u8 iekey = (cdw10[0] >> 3) & 0x1; u8 ptpl = (cdw10[3] >> 6) & 0x3; + const char *rrega_str; + + if (rrega < ARRAY_SIZE(rrega_strs) && rrega_strs[rrega]) + rrega_str = rrega_strs[rrega]; + else + rrega_str = "reserved"; - trace_seq_printf(p, "rrega=%u, iekey=%u, ptpl=%u", - rrega, iekey, ptpl); + trace_seq_printf(p, "rrega=%u:%s, iekey=%u, ptpl=%u", + rrega, rrega_str, iekey, ptpl); trace_seq_putc(p, 0); return ret; } +static const char * const rtype_strs[] = { + [0x00] = "reserved", + [0x01] = "write exclusive", + [0x02] = "exclusive access", + [0x03] = "write exclusive registrants only", + [0x04] = "exclusive access registrants only", + [0x05] = "write exclusive all registrants", + [0x06] = "exclusive access all registrants", +}; + static const char *nvme_trace_resv_acq(struct trace_seq *p, u8 *cdw10) { + static const char * const racqa_strs[] = { + [0x00] = "acquire", + [0x01] = "preempt", + [0x02] = "preempt and abort", + }; const char *ret = trace_seq_buffer_ptr(p); u8 racqa = cdw10[0] & 0x7; u8 iekey = (cdw10[0] >> 3) & 0x1; u8 rtype = cdw10[1]; + const char *racqa_str = "reserved"; + const char *rtype_str = "reserved"; - trace_seq_printf(p, "racqa=%u, iekey=%u, rtype=%u", - racqa, iekey, rtype); + if (racqa < ARRAY_SIZE(racqa_strs) && racqa_strs[racqa]) + racqa_str = racqa_strs[racqa]; + + if (rtype < ARRAY_SIZE(rtype_strs) && rtype_strs[rtype]) + rtype_str = rtype_strs[rtype]; + + trace_seq_printf(p, "racqa=%u:%s, iekey=%u, rtype=%u:%s", + racqa, racqa_str, iekey, rtype, rtype_str); trace_seq_putc(p, 0); return ret; @@ -256,13 +290,25 @@ static const char *nvme_trace_resv_acq(struct trace_seq *p, u8 *cdw10) static const char *nvme_trace_resv_rel(struct trace_seq *p, u8 *cdw10) { + static const char * const rrela_strs[] = { + [0x00] = "release", + [0x01] = "clear", + }; const char *ret = trace_seq_buffer_ptr(p); u8 rrela = cdw10[0] & 0x7; u8 iekey = (cdw10[0] >> 3) & 0x1; u8 rtype = cdw10[1]; + const char *rrela_str = "reserved"; + const char *rtype_str = "reserved"; + + if (rrela < ARRAY_SIZE(rrela_strs) && rrela_strs[rrela]) + rrela_str = rrela_strs[rrela]; + + if (rtype < ARRAY_SIZE(rtype_strs) && rtype_strs[rtype]) + rtype_str = rtype_strs[rtype]; - trace_seq_printf(p, "rrela=%u, iekey=%u, rtype=%u", - rrela, iekey, rtype); + trace_seq_printf(p, "rrela=%u:%s, iekey=%u, rtype=%u:%s", + rrela, rrela_str, iekey, rtype, rtype_str); trace_seq_putc(p, 0); return ret; diff --git a/drivers/nvme/host/zns.c b/drivers/nvme/host/zns.c index 9a06f9d98cd68c..382949e18c6ae7 100644 --- a/drivers/nvme/host/zns.c +++ b/drivers/nvme/host/zns.c @@ -111,7 +111,7 @@ void nvme_update_zone_info(struct nvme_ns *ns, struct queue_limits *lim, lim->features |= BLK_FEAT_ZONED; lim->max_open_zones = zi->max_open_zones; lim->max_active_zones = zi->max_active_zones; - lim->max_zone_append_sectors = ns->ctrl->max_zone_append; + lim->max_hw_zone_append_sectors = ns->ctrl->max_zone_append; lim->chunk_sectors = ns->head->zsze = nvme_lba_to_sect(ns->head, zi->zone_size); } diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile index c402c44350b2b5..f2b025bbe10cc0 100644 --- a/drivers/nvme/target/Makefile +++ b/drivers/nvme/target/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_NVME_TARGET_FCLOOP) += nvme-fcloop.o obj-$(CONFIG_NVME_TARGET_TCP) += nvmet-tcp.o nvmet-y += core.o configfs.o admin-cmd.o fabrics-cmd.o \ - discovery.o io-cmd-file.o io-cmd-bdev.o + discovery.o io-cmd-file.o io-cmd-bdev.o pr.o nvmet-$(CONFIG_NVME_TARGET_DEBUGFS) += debugfs.o nvmet-$(CONFIG_NVME_TARGET_PASSTHRU) += passthru.o nvmet-$(CONFIG_BLK_DEV_ZONED) += zns.o diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 081f0473cd9ea1..2962794ce881ee 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -71,6 +71,35 @@ static void nvmet_execute_get_log_page_error(struct nvmet_req *req) nvmet_req_complete(req, 0); } +static void nvmet_execute_get_supported_log_pages(struct nvmet_req *req) +{ + struct nvme_supported_log *logs; + u16 status; + + logs = kzalloc(sizeof(*logs), GFP_KERNEL); + if (!logs) { + status = NVME_SC_INTERNAL; + goto out; + } + + logs->lids[NVME_LOG_SUPPORTED] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_ERROR] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_SMART] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_FW_SLOT] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_CHANGED_NS] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_CMD_EFFECTS] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_ENDURANCE_GROUP] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_ANA] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_FEATURES] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_RMI] = cpu_to_le32(NVME_LIDS_LSUPP); + logs->lids[NVME_LOG_RESERVATION] = cpu_to_le32(NVME_LIDS_LSUPP); + + status = nvmet_copy_to_sgl(req, 0, logs, sizeof(*logs)); + kfree(logs); +out: + nvmet_req_complete(req, status); +} + static u16 nvmet_get_smart_log_nsid(struct nvmet_req *req, struct nvme_smart_log *slog) { @@ -130,6 +159,45 @@ static u16 nvmet_get_smart_log_all(struct nvmet_req *req, return NVME_SC_SUCCESS; } +static void nvmet_execute_get_log_page_rmi(struct nvmet_req *req) +{ + struct nvme_rotational_media_log *log; + struct gendisk *disk; + u16 status; + + req->cmd->common.nsid = cpu_to_le32(le16_to_cpu( + req->cmd->get_log_page.lsi)); + status = nvmet_req_find_ns(req); + if (status) + goto out; + + if (!req->ns->bdev || bdev_nonrot(req->ns->bdev)) { + status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; + goto out; + } + + if (req->transfer_len != sizeof(*log)) { + status = NVME_SC_SGL_INVALID_DATA | NVME_STATUS_DNR; + goto out; + } + + log = kzalloc(sizeof(*log), GFP_KERNEL); + if (!log) + goto out; + + log->endgid = req->cmd->get_log_page.lsi; + disk = req->ns->bdev->bd_disk; + if (disk && disk->ia_ranges) + log->numa = cpu_to_le16(disk->ia_ranges->nr_ia_ranges); + else + log->numa = cpu_to_le16(1); + + status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log)); + kfree(log); +out: + nvmet_req_complete(req, status); +} + static void nvmet_execute_get_log_page_smart(struct nvmet_req *req) { struct nvme_smart_log *log; @@ -176,6 +244,10 @@ static void nvmet_get_cmd_effects_nvm(struct nvme_effects_log *log) log->iocs[nvme_cmd_read] = log->iocs[nvme_cmd_flush] = log->iocs[nvme_cmd_dsm] = + log->iocs[nvme_cmd_resv_acquire] = + log->iocs[nvme_cmd_resv_register] = + log->iocs[nvme_cmd_resv_release] = + log->iocs[nvme_cmd_resv_report] = cpu_to_le32(NVME_CMD_EFFECTS_CSUPP); log->iocs[nvme_cmd_write] = log->iocs[nvme_cmd_write_zeroes] = @@ -272,6 +344,49 @@ static u32 nvmet_format_ana_group(struct nvmet_req *req, u32 grpid, return struct_size(desc, nsids, count); } +static void nvmet_execute_get_log_page_endgrp(struct nvmet_req *req) +{ + u64 host_reads, host_writes, data_units_read, data_units_written; + struct nvme_endurance_group_log *log; + u16 status; + + /* + * The target driver emulates each endurance group as its own + * namespace, reusing the nsid as the endurance group identifier. + */ + req->cmd->common.nsid = cpu_to_le32(le16_to_cpu( + req->cmd->get_log_page.lsi)); + status = nvmet_req_find_ns(req); + if (status) + goto out; + + log = kzalloc(sizeof(*log), GFP_KERNEL); + if (!log) { + status = NVME_SC_INTERNAL; + goto out; + } + + if (!req->ns->bdev) + goto copy; + + host_reads = part_stat_read(req->ns->bdev, ios[READ]); + data_units_read = + DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[READ]), 1000); + host_writes = part_stat_read(req->ns->bdev, ios[WRITE]); + data_units_written = + DIV_ROUND_UP(part_stat_read(req->ns->bdev, sectors[WRITE]), 1000); + + put_unaligned_le64(host_reads, &log->hrc[0]); + put_unaligned_le64(data_units_read, &log->dur[0]); + put_unaligned_le64(host_writes, &log->hwc[0]); + put_unaligned_le64(data_units_written, &log->duw[0]); +copy: + status = nvmet_copy_to_sgl(req, 0, log, sizeof(*log)); + kfree(log); +out: + nvmet_req_complete(req, status); +} + static void nvmet_execute_get_log_page_ana(struct nvmet_req *req) { struct nvme_ana_rsp_hdr hdr = { 0, }; @@ -317,12 +432,44 @@ static void nvmet_execute_get_log_page_ana(struct nvmet_req *req) nvmet_req_complete(req, status); } +static void nvmet_execute_get_log_page_features(struct nvmet_req *req) +{ + struct nvme_supported_features_log *features; + u16 status; + + features = kzalloc(sizeof(*features), GFP_KERNEL); + if (!features) { + status = NVME_SC_INTERNAL; + goto out; + } + + features->fis[NVME_FEAT_NUM_QUEUES] = + cpu_to_le32(NVME_FIS_FSUPP | NVME_FIS_CSCPE); + features->fis[NVME_FEAT_KATO] = + cpu_to_le32(NVME_FIS_FSUPP | NVME_FIS_CSCPE); + features->fis[NVME_FEAT_ASYNC_EVENT] = + cpu_to_le32(NVME_FIS_FSUPP | NVME_FIS_CSCPE); + features->fis[NVME_FEAT_HOST_ID] = + cpu_to_le32(NVME_FIS_FSUPP | NVME_FIS_CSCPE); + features->fis[NVME_FEAT_WRITE_PROTECT] = + cpu_to_le32(NVME_FIS_FSUPP | NVME_FIS_NSCPE); + features->fis[NVME_FEAT_RESV_MASK] = + cpu_to_le32(NVME_FIS_FSUPP | NVME_FIS_NSCPE); + + status = nvmet_copy_to_sgl(req, 0, features, sizeof(*features)); + kfree(features); +out: + nvmet_req_complete(req, status); +} + static void nvmet_execute_get_log_page(struct nvmet_req *req) { if (!nvmet_check_transfer_len(req, nvmet_get_log_page_len(req->cmd))) return; switch (req->cmd->get_log_page.lid) { + case NVME_LOG_SUPPORTED: + return nvmet_execute_get_supported_log_pages(req); case NVME_LOG_ERROR: return nvmet_execute_get_log_page_error(req); case NVME_LOG_SMART: @@ -338,8 +485,16 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req) return nvmet_execute_get_log_changed_ns(req); case NVME_LOG_CMD_EFFECTS: return nvmet_execute_get_log_cmd_effects_ns(req); + case NVME_LOG_ENDURANCE_GROUP: + return nvmet_execute_get_log_page_endgrp(req); case NVME_LOG_ANA: return nvmet_execute_get_log_page_ana(req); + case NVME_LOG_FEATURES: + return nvmet_execute_get_log_page_features(req); + case NVME_LOG_RMI: + return nvmet_execute_get_log_page_rmi(req); + case NVME_LOG_RESERVATION: + return nvmet_execute_get_log_page_resv(req); } pr_debug("unhandled lid %d on qid %d\n", req->cmd->get_log_page.lid, req->sq->qid); @@ -433,7 +588,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) id->nn = cpu_to_le32(NVMET_MAX_NAMESPACES); id->mnan = cpu_to_le32(NVMET_MAX_NAMESPACES); id->oncs = cpu_to_le16(NVME_CTRL_ONCS_DSM | - NVME_CTRL_ONCS_WRITE_ZEROES); + NVME_CTRL_ONCS_WRITE_ZEROES | + NVME_CTRL_ONCS_RESERVATIONS); /* XXX: don't report vwc if the underlying device is write through */ id->vwc = NVME_CTRL_VWC_PRESENT; @@ -445,11 +601,12 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) id->awun = 0; id->awupf = 0; - id->sgls = cpu_to_le32(1 << 0); /* we always support SGLs */ + /* we always support SGLs */ + id->sgls = cpu_to_le32(NVME_CTRL_SGLS_BYTE_ALIGNED); if (ctrl->ops->flags & NVMF_KEYED_SGLS) - id->sgls |= cpu_to_le32(1 << 2); + id->sgls |= cpu_to_le32(NVME_CTRL_SGLS_KSDBDS); if (req->port->inline_data_size) - id->sgls |= cpu_to_le32(1 << 20); + id->sgls |= cpu_to_le32(NVME_CTRL_SGLS_SAOS); strscpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn)); @@ -467,6 +624,13 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) id->msdbd = ctrl->ops->msdbd; + /* + * Endurance group identifier is 16 bits, so we can't let namespaces + * overflow that since we reuse the nsid + */ + BUILD_BUG_ON(NVMET_MAX_NAMESPACES > USHRT_MAX); + id->endgidmax = cpu_to_le16(NVMET_MAX_NAMESPACES); + id->anacap = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4); id->anatt = 10; /* random value */ id->anagrpmax = cpu_to_le32(NVMET_MAX_ANAGRPS); @@ -551,6 +715,21 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req) id->nmic = NVME_NS_NMIC_SHARED; id->anagrpid = cpu_to_le32(req->ns->anagrpid); + if (req->ns->pr.enable) + id->rescap = NVME_PR_SUPPORT_WRITE_EXCLUSIVE | + NVME_PR_SUPPORT_EXCLUSIVE_ACCESS | + NVME_PR_SUPPORT_WRITE_EXCLUSIVE_REG_ONLY | + NVME_PR_SUPPORT_EXCLUSIVE_ACCESS_REG_ONLY | + NVME_PR_SUPPORT_WRITE_EXCLUSIVE_ALL_REGS | + NVME_PR_SUPPORT_EXCLUSIVE_ACCESS_ALL_REGS | + NVME_PR_SUPPORT_IEKEY_VER_1_3_DEF; + + /* + * Since we don't know any better, every namespace is its own endurance + * group. + */ + id->endgid = cpu_to_le16(req->ns->nsid); + memcpy(&id->nguid, &req->ns->nguid, sizeof(id->nguid)); id->lbaf[0].ds = req->ns->blksize_shift; @@ -576,7 +755,40 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req) nvmet_req_complete(req, status); } -static void nvmet_execute_identify_nslist(struct nvmet_req *req) +static void nvmet_execute_identify_endgrp_list(struct nvmet_req *req) +{ + u16 min_endgid = le16_to_cpu(req->cmd->identify.cnssid); + static const int buf_size = NVME_IDENTIFY_DATA_SIZE; + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_ns *ns; + unsigned long idx; + __le16 *list; + u16 status; + int i = 1; + + list = kzalloc(buf_size, GFP_KERNEL); + if (!list) { + status = NVME_SC_INTERNAL; + goto out; + } + + xa_for_each(&ctrl->subsys->namespaces, idx, ns) { + if (ns->nsid <= min_endgid) + continue; + + list[i++] = cpu_to_le16(ns->nsid); + if (i == buf_size / sizeof(__le16)) + break; + } + + list[0] = cpu_to_le16(i - 1); + status = nvmet_copy_to_sgl(req, 0, list, buf_size); + kfree(list); +out: + nvmet_req_complete(req, status); +} + +static void nvmet_execute_identify_nslist(struct nvmet_req *req, bool match_css) { static const int buf_size = NVME_IDENTIFY_DATA_SIZE; struct nvmet_ctrl *ctrl = req->sq->ctrl; @@ -606,6 +818,8 @@ static void nvmet_execute_identify_nslist(struct nvmet_req *req) xa_for_each(&ctrl->subsys->namespaces, idx, ns) { if (ns->nsid <= min_nsid) continue; + if (match_css && req->ns->csi != req->cmd->identify.csi) + continue; list[i++] = cpu_to_le32(ns->nsid); if (i == buf_size / sizeof(__le32)) break; @@ -685,6 +899,61 @@ static void nvmet_execute_identify_ctrl_nvm(struct nvmet_req *req) nvmet_zero_sgl(req, 0, sizeof(struct nvme_id_ctrl_nvm))); } +static void nvme_execute_identify_ns_nvm(struct nvmet_req *req) +{ + u16 status; + struct nvme_id_ns_nvm *id; + + status = nvmet_req_find_ns(req); + if (status) + goto out; + + id = kzalloc(sizeof(*id), GFP_KERNEL); + if (!id) { + status = NVME_SC_INTERNAL; + goto out; + } + status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id)); +out: + nvmet_req_complete(req, status); +} + +static void nvmet_execute_id_cs_indep(struct nvmet_req *req) +{ + struct nvme_id_ns_cs_indep *id; + u16 status; + + status = nvmet_req_find_ns(req); + if (status) + goto out; + + id = kzalloc(sizeof(*id), GFP_KERNEL); + if (!id) { + status = NVME_SC_INTERNAL; + goto out; + } + + id->nstat = NVME_NSTAT_NRDY; + id->anagrpid = cpu_to_le32(req->ns->anagrpid); + id->nmic = NVME_NS_NMIC_SHARED; + if (req->ns->readonly) + id->nsattr |= NVME_NS_ATTR_RO; + if (req->ns->bdev && !bdev_nonrot(req->ns->bdev)) + id->nsfeat |= NVME_NS_ROTATIONAL; + /* + * We need flush command to flush the file's metadata, + * so report supporting vwc if backend is file, even + * though buffered_io is disable. + */ + if (req->ns->bdev && !bdev_write_cache(req->ns->bdev)) + id->nsfeat |= NVME_NS_VWC_NOT_PRESENT; + + status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id)); + kfree(id); +out: + nvmet_req_complete(req, status); +} + static void nvmet_execute_identify(struct nvmet_req *req) { if (!nvmet_check_transfer_len(req, NVME_IDENTIFY_DATA_SIZE)) @@ -698,7 +967,7 @@ static void nvmet_execute_identify(struct nvmet_req *req) nvmet_execute_identify_ctrl(req); return; case NVME_ID_CNS_NS_ACTIVE_LIST: - nvmet_execute_identify_nslist(req); + nvmet_execute_identify_nslist(req, false); return; case NVME_ID_CNS_NS_DESC_LIST: nvmet_execute_identify_desclist(req); @@ -706,8 +975,8 @@ static void nvmet_execute_identify(struct nvmet_req *req) case NVME_ID_CNS_CS_NS: switch (req->cmd->identify.csi) { case NVME_CSI_NVM: - /* Not supported */ - break; + nvme_execute_identify_ns_nvm(req); + return; case NVME_CSI_ZNS: if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) { nvmet_execute_identify_ns_zns(req); @@ -729,6 +998,15 @@ static void nvmet_execute_identify(struct nvmet_req *req) break; } break; + case NVME_ID_CNS_NS_ACTIVE_LIST_CS: + nvmet_execute_identify_nslist(req, true); + return; + case NVME_ID_CNS_NS_CS_INDEP: + nvmet_execute_id_cs_indep(req); + return; + case NVME_ID_CNS_ENDGRP_LIST: + nvmet_execute_identify_endgrp_list(req); + return; } pr_debug("unhandled identify cns %d on qid %d\n", @@ -861,6 +1139,9 @@ void nvmet_execute_set_features(struct nvmet_req *req) case NVME_FEAT_WRITE_PROTECT: status = nvmet_set_feat_write_protect(req); break; + case NVME_FEAT_RESV_MASK: + status = nvmet_set_feat_resv_notif_mask(req, cdw11); + break; default: req->error_loc = offsetof(struct nvme_common_command, cdw10); status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; @@ -959,6 +1240,9 @@ void nvmet_execute_get_features(struct nvmet_req *req) case NVME_FEAT_WRITE_PROTECT: status = nvmet_get_feat_write_protect(req); break; + case NVME_FEAT_RESV_MASK: + status = nvmet_get_feat_resv_notif_mask(req); + break; default: req->error_loc = offsetof(struct nvme_common_command, cdw10); diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 685e89b35d330d..eeee9e9b854c12 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -769,6 +769,32 @@ static ssize_t nvmet_ns_revalidate_size_store(struct config_item *item, CONFIGFS_ATTR_WO(nvmet_ns_, revalidate_size); +static ssize_t nvmet_ns_resv_enable_show(struct config_item *item, char *page) +{ + return sysfs_emit(page, "%d\n", to_nvmet_ns(item)->pr.enable); +} + +static ssize_t nvmet_ns_resv_enable_store(struct config_item *item, + const char *page, size_t count) +{ + struct nvmet_ns *ns = to_nvmet_ns(item); + bool val; + + if (kstrtobool(page, &val)) + return -EINVAL; + + mutex_lock(&ns->subsys->lock); + if (ns->enabled) { + pr_err("the ns:%d is already enabled.\n", ns->nsid); + mutex_unlock(&ns->subsys->lock); + return -EINVAL; + } + ns->pr.enable = val; + mutex_unlock(&ns->subsys->lock); + return count; +} +CONFIGFS_ATTR(nvmet_ns_, resv_enable); + static struct configfs_attribute *nvmet_ns_attrs[] = { &nvmet_ns_attr_device_path, &nvmet_ns_attr_device_nguid, @@ -777,6 +803,7 @@ static struct configfs_attribute *nvmet_ns_attrs[] = { &nvmet_ns_attr_enable, &nvmet_ns_attr_buffered_io, &nvmet_ns_attr_revalidate_size, + &nvmet_ns_attr_resv_enable, #ifdef CONFIG_PCI_P2PDMA &nvmet_ns_attr_p2pmem, #endif diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index ed2424f8a396e0..1f4e9989663be9 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -611,6 +611,12 @@ int nvmet_ns_enable(struct nvmet_ns *ns) if (ret) goto out_restore_subsys_maxnsid; + if (ns->pr.enable) { + ret = nvmet_pr_init_ns(ns); + if (ret) + goto out_remove_from_subsys; + } + subsys->nr_namespaces++; nvmet_ns_changed(subsys, ns->nsid); @@ -620,6 +626,8 @@ int nvmet_ns_enable(struct nvmet_ns *ns) mutex_unlock(&subsys->lock); return ret; +out_remove_from_subsys: + xa_erase(&subsys->namespaces, ns->nsid); out_restore_subsys_maxnsid: subsys->max_nsid = nvmet_max_nsid(subsys); percpu_ref_exit(&ns->ref); @@ -663,6 +671,9 @@ void nvmet_ns_disable(struct nvmet_ns *ns) wait_for_completion(&ns->disable_done); percpu_ref_exit(&ns->ref); + if (ns->pr.enable) + nvmet_pr_exit_ns(ns); + mutex_lock(&subsys->lock); subsys->nr_namespaces--; @@ -754,6 +765,7 @@ static void nvmet_set_error(struct nvmet_req *req, u16 status) static void __nvmet_req_complete(struct nvmet_req *req, u16 status) { struct nvmet_ns *ns = req->ns; + struct nvmet_pr_per_ctrl_ref *pc_ref = req->pc_ref; if (!req->sq->sqhd_disabled) nvmet_update_sq_head(req); @@ -766,6 +778,9 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status) trace_nvmet_req_complete(req); req->ops->queue_response(req); + + if (pc_ref) + nvmet_pr_put_ns_pc_ref(pc_ref); if (ns) nvmet_put_namespace(ns); } @@ -929,18 +944,39 @@ static u16 nvmet_parse_io_cmd(struct nvmet_req *req) return ret; } + if (req->ns->pr.enable) { + ret = nvmet_parse_pr_cmd(req); + if (!ret) + return ret; + } + switch (req->ns->csi) { case NVME_CSI_NVM: if (req->ns->file) - return nvmet_file_parse_io_cmd(req); - return nvmet_bdev_parse_io_cmd(req); + ret = nvmet_file_parse_io_cmd(req); + else + ret = nvmet_bdev_parse_io_cmd(req); + break; case NVME_CSI_ZNS: if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) - return nvmet_bdev_zns_parse_io_cmd(req); - return NVME_SC_INVALID_IO_CMD_SET; + ret = nvmet_bdev_zns_parse_io_cmd(req); + else + ret = NVME_SC_INVALID_IO_CMD_SET; + break; default: - return NVME_SC_INVALID_IO_CMD_SET; + ret = NVME_SC_INVALID_IO_CMD_SET; } + if (ret) + return ret; + + if (req->ns->pr.enable) { + ret = nvmet_pr_check_cmd_access(req); + if (ret) + return ret; + + ret = nvmet_pr_get_ns_pc_ref(req); + } + return ret; } bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, @@ -964,6 +1000,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, req->ns = NULL; req->error_loc = NVMET_NO_ERROR_LOC; req->error_slba = 0; + req->pc_ref = NULL; /* no support for fused commands yet */ if (unlikely(flags & (NVME_CMD_FUSE_FIRST | NVME_CMD_FUSE_SECOND))) { @@ -1015,6 +1052,8 @@ EXPORT_SYMBOL_GPL(nvmet_req_init); void nvmet_req_uninit(struct nvmet_req *req) { percpu_ref_put(&req->sq->ref); + if (req->pc_ref) + nvmet_pr_put_ns_pc_ref(req->pc_ref); if (req->ns) nvmet_put_namespace(req->ns); } @@ -1383,7 +1422,8 @@ static void nvmet_fatal_error_handler(struct work_struct *work) } u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, - struct nvmet_req *req, u32 kato, struct nvmet_ctrl **ctrlp) + struct nvmet_req *req, u32 kato, struct nvmet_ctrl **ctrlp, + uuid_t *hostid) { struct nvmet_subsys *subsys; struct nvmet_ctrl *ctrl; @@ -1462,6 +1502,8 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, } ctrl->cntlid = ret; + uuid_copy(&ctrl->hostid, hostid); + /* * Discovery controllers may use some arbitrary high value * in order to cleanup stale discovery sessions @@ -1478,6 +1520,9 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, nvmet_start_keep_alive_timer(ctrl); mutex_lock(&subsys->lock); + ret = nvmet_ctrl_init_pr(ctrl); + if (ret) + goto init_pr_fail; list_add_tail(&ctrl->subsys_entry, &subsys->ctrls); nvmet_setup_p2p_ns_map(ctrl, req); nvmet_debugfs_ctrl_setup(ctrl); @@ -1486,6 +1531,10 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, *ctrlp = ctrl; return 0; +init_pr_fail: + mutex_unlock(&subsys->lock); + nvmet_stop_keep_alive_timer(ctrl); + ida_free(&cntlid_ida, ctrl->cntlid); out_free_sqs: kfree(ctrl->sqs); out_free_changed_ns_list: @@ -1504,6 +1553,7 @@ static void nvmet_ctrl_free(struct kref *ref) struct nvmet_subsys *subsys = ctrl->subsys; mutex_lock(&subsys->lock); + nvmet_ctrl_destroy_pr(ctrl); nvmet_release_p2p_ns_map(ctrl); list_del(&ctrl->subsys_entry); mutex_unlock(&subsys->lock); @@ -1717,7 +1767,7 @@ static int __init nvmet_init(void) goto out_free_zbd_work_queue; nvmet_wq = alloc_workqueue("nvmet-wq", - WQ_MEM_RECLAIM | WQ_UNBOUND, 0); + WQ_MEM_RECLAIM | WQ_UNBOUND | WQ_SYSFS, 0); if (!nvmet_wq) goto out_free_buffered_work_queue; diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index c4b2eddd5666aa..c49904ebb6c2d7 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -64,6 +64,9 @@ static void nvmet_execute_prop_get(struct nvmet_req *req) case NVME_REG_CSTS: val = ctrl->csts; break; + case NVME_REG_CRTO: + val = NVME_CAP_TIMEOUT(ctrl->csts); + break; default: status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; break; @@ -245,12 +248,10 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) d->subsysnqn[NVMF_NQN_FIELD_LEN - 1] = '\0'; d->hostnqn[NVMF_NQN_FIELD_LEN - 1] = '\0'; status = nvmet_alloc_ctrl(d->subsysnqn, d->hostnqn, req, - le32_to_cpu(c->kato), &ctrl); + le32_to_cpu(c->kato), &ctrl, &d->hostid); if (status) goto out; - uuid_copy(&ctrl->hostid, &d->hostid); - dhchap_status = nvmet_setup_auth(ctrl); if (dhchap_status) { pr_err("Failed to setup authentication, dhchap status %u\n", diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 190f55e6d7532e..58328b35dc9682 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -20,8 +20,9 @@ #include #include #include +#include -#define NVMET_DEFAULT_VS NVME_VS(1, 3, 0) +#define NVMET_DEFAULT_VS NVME_VS(2, 1, 0) #define NVMET_ASYNC_EVENTS 4 #define NVMET_ERROR_LOG_SLOTS 128 @@ -30,6 +31,7 @@ #define NVMET_MN_MAX_SIZE 40 #define NVMET_SN_MAX_SIZE 20 #define NVMET_FR_MAX_SIZE 8 +#define NVMET_PR_LOG_QUEUE_SIZE 64 /* * Supported optional AENs: @@ -56,6 +58,38 @@ #define IPO_IATTR_CONNECT_SQE(x) \ (cpu_to_le32(offsetof(struct nvmf_connect_command, x))) +struct nvmet_pr_registrant { + u64 rkey; + uuid_t hostid; + enum nvme_pr_type rtype; + struct list_head entry; + struct rcu_head rcu; +}; + +struct nvmet_pr { + bool enable; + unsigned long notify_mask; + atomic_t generation; + struct nvmet_pr_registrant __rcu *holder; + /* + * During the execution of the reservation command, mutual + * exclusion is required throughout the process. However, + * while waiting asynchronously for the 'per controller + * percpu_ref' to complete before the 'preempt and abort' + * command finishes, a semaphore is needed to ensure mutual + * exclusion instead of a mutex. + */ + struct semaphore pr_sem; + struct list_head registrant_list; +}; + +struct nvmet_pr_per_ctrl_ref { + struct percpu_ref ref; + struct completion free_done; + struct completion confirm_done; + uuid_t hostid; +}; + struct nvmet_ns { struct percpu_ref ref; struct file *bdev_file; @@ -85,6 +119,8 @@ struct nvmet_ns { int pi_type; int metadata_size; u8 csi; + struct nvmet_pr pr; + struct xarray pr_per_ctrl_refs; }; static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item) @@ -191,6 +227,13 @@ static inline bool nvmet_port_secure_channel_required(struct nvmet_port *port) return nvmet_port_disc_addr_treq_secure_channel(port) == NVMF_TREQ_REQUIRED; } +struct nvmet_pr_log_mgr { + struct mutex lock; + u64 lost_count; + u64 counter; + DECLARE_KFIFO(log_queue, struct nvme_pr_log, NVMET_PR_LOG_QUEUE_SIZE); +}; + struct nvmet_ctrl { struct nvmet_subsys *subsys; struct nvmet_sq **sqs; @@ -246,6 +289,7 @@ struct nvmet_ctrl { u8 *dh_key; size_t dh_keysize; #endif + struct nvmet_pr_log_mgr pr_log_mgr; }; struct nvmet_subsys { @@ -396,6 +440,9 @@ struct nvmet_req { struct work_struct zmgmt_work; } z; #endif /* CONFIG_BLK_DEV_ZONED */ + struct { + struct work_struct abort_work; + } r; }; int sg_cnt; int metadata_sg_cnt; @@ -412,6 +459,7 @@ struct nvmet_req { struct device *p2p_client; u16 error_loc; u64 error_slba; + struct nvmet_pr_per_ctrl_ref *pc_ref; }; #define NVMET_MAX_MPOOL_BVEC 16 @@ -498,7 +546,8 @@ void nvmet_ctrl_fatal_error(struct nvmet_ctrl *ctrl); void nvmet_update_cc(struct nvmet_ctrl *ctrl, u32 new); u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, - struct nvmet_req *req, u32 kato, struct nvmet_ctrl **ctrlp); + struct nvmet_req *req, u32 kato, struct nvmet_ctrl **ctrlp, + uuid_t *hostid); struct nvmet_ctrl *nvmet_ctrl_find_get(const char *subsysnqn, const char *hostnqn, u16 cntlid, struct nvmet_req *req); @@ -761,4 +810,18 @@ static inline bool nvmet_has_auth(struct nvmet_ctrl *ctrl) static inline const char *nvmet_dhchap_dhgroup_name(u8 dhgid) { return NULL; } #endif +int nvmet_pr_init_ns(struct nvmet_ns *ns); +u16 nvmet_parse_pr_cmd(struct nvmet_req *req); +u16 nvmet_pr_check_cmd_access(struct nvmet_req *req); +int nvmet_ctrl_init_pr(struct nvmet_ctrl *ctrl); +void nvmet_ctrl_destroy_pr(struct nvmet_ctrl *ctrl); +void nvmet_pr_exit_ns(struct nvmet_ns *ns); +void nvmet_execute_get_log_page_resv(struct nvmet_req *req); +u16 nvmet_set_feat_resv_notif_mask(struct nvmet_req *req, u32 mask); +u16 nvmet_get_feat_resv_notif_mask(struct nvmet_req *req); +u16 nvmet_pr_get_ns_pc_ref(struct nvmet_req *req); +static inline void nvmet_pr_put_ns_pc_ref(struct nvmet_pr_per_ctrl_ref *pc_ref) +{ + percpu_ref_put(&pc_ref->ref); +} #endif /* _NVMET_H */ diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c index 0f9b280c438d98..30b21936b0c622 100644 --- a/drivers/nvme/target/passthru.c +++ b/drivers/nvme/target/passthru.c @@ -13,7 +13,7 @@ #include "../host/nvme.h" #include "nvmet.h" -MODULE_IMPORT_NS(NVME_TARGET_PASSTHRU); +MODULE_IMPORT_NS("NVME_TARGET_PASSTHRU"); /* * xarray to maintain one passthru subsystem per nvme controller. diff --git a/drivers/nvme/target/pr.c b/drivers/nvme/target/pr.c new file mode 100644 index 00000000000000..90e9f5bbe58152 --- /dev/null +++ b/drivers/nvme/target/pr.c @@ -0,0 +1,1155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVMe over Fabrics Persist Reservation. + * Copyright (c) 2024 Guixin Liu, Alibaba Group. + * All rights reserved. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include "nvmet.h" + +#define NVMET_PR_NOTIFI_MASK_ALL \ + (1 << NVME_PR_NOTIFY_BIT_REG_PREEMPTED | \ + 1 << NVME_PR_NOTIFY_BIT_RESV_RELEASED | \ + 1 << NVME_PR_NOTIFY_BIT_RESV_PREEMPTED) + +static inline bool nvmet_pr_parse_ignore_key(u32 cdw10) +{ + /* Ignore existing key, bit 03. */ + return (cdw10 >> 3) & 1; +} + +static inline struct nvmet_ns *nvmet_pr_to_ns(struct nvmet_pr *pr) +{ + return container_of(pr, struct nvmet_ns, pr); +} + +static struct nvmet_pr_registrant * +nvmet_pr_find_registrant(struct nvmet_pr *pr, uuid_t *hostid) +{ + struct nvmet_pr_registrant *reg; + + list_for_each_entry_rcu(reg, &pr->registrant_list, entry) { + if (uuid_equal(®->hostid, hostid)) + return reg; + } + return NULL; +} + +u16 nvmet_set_feat_resv_notif_mask(struct nvmet_req *req, u32 mask) +{ + u32 nsid = le32_to_cpu(req->cmd->common.nsid); + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_ns *ns; + unsigned long idx; + u16 status; + + if (mask & ~(NVMET_PR_NOTIFI_MASK_ALL)) { + req->error_loc = offsetof(struct nvme_common_command, cdw11); + return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; + } + + if (nsid != U32_MAX) { + status = nvmet_req_find_ns(req); + if (status) + return status; + if (!req->ns->pr.enable) + return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; + + WRITE_ONCE(req->ns->pr.notify_mask, mask); + goto success; + } + + xa_for_each(&ctrl->subsys->namespaces, idx, ns) { + if (ns->pr.enable) + WRITE_ONCE(ns->pr.notify_mask, mask); + } + +success: + nvmet_set_result(req, mask); + return NVME_SC_SUCCESS; +} + +u16 nvmet_get_feat_resv_notif_mask(struct nvmet_req *req) +{ + u16 status; + + status = nvmet_req_find_ns(req); + if (status) + return status; + + if (!req->ns->pr.enable) + return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; + + nvmet_set_result(req, READ_ONCE(req->ns->pr.notify_mask)); + return status; +} + +void nvmet_execute_get_log_page_resv(struct nvmet_req *req) +{ + struct nvmet_pr_log_mgr *log_mgr = &req->sq->ctrl->pr_log_mgr; + struct nvme_pr_log next_log = {0}; + struct nvme_pr_log log = {0}; + u16 status = NVME_SC_SUCCESS; + u64 lost_count; + u64 cur_count; + u64 next_count; + + mutex_lock(&log_mgr->lock); + if (!kfifo_get(&log_mgr->log_queue, &log)) + goto out; + + /* + * We can't get the last in kfifo. + * Utilize the current count and the count from the next log to + * calculate the number of lost logs, while also addressing cases + * of overflow. If there is no subsequent log, the number of lost + * logs is equal to the lost_count within the nvmet_pr_log_mgr. + */ + cur_count = le64_to_cpu(log.count); + if (kfifo_peek(&log_mgr->log_queue, &next_log)) { + next_count = le64_to_cpu(next_log.count); + if (next_count > cur_count) + lost_count = next_count - cur_count - 1; + else + lost_count = U64_MAX - cur_count + next_count - 1; + } else { + lost_count = log_mgr->lost_count; + } + + log.count = cpu_to_le64((cur_count + lost_count) == 0 ? + 1 : (cur_count + lost_count)); + log_mgr->lost_count -= lost_count; + + log.nr_pages = kfifo_len(&log_mgr->log_queue); + +out: + status = nvmet_copy_to_sgl(req, 0, &log, sizeof(log)); + mutex_unlock(&log_mgr->lock); + nvmet_req_complete(req, status); +} + +static void nvmet_pr_add_resv_log(struct nvmet_ctrl *ctrl, u8 log_type, + u32 nsid) +{ + struct nvmet_pr_log_mgr *log_mgr = &ctrl->pr_log_mgr; + struct nvme_pr_log log = {0}; + + mutex_lock(&log_mgr->lock); + log_mgr->counter++; + if (log_mgr->counter == 0) + log_mgr->counter = 1; + + log.count = cpu_to_le64(log_mgr->counter); + log.type = log_type; + log.nsid = cpu_to_le32(nsid); + + if (!kfifo_put(&log_mgr->log_queue, log)) { + pr_info("a reservation log lost, cntlid:%d, log_type:%d, nsid:%d\n", + ctrl->cntlid, log_type, nsid); + log_mgr->lost_count++; + } + + mutex_unlock(&log_mgr->lock); +} + +static void nvmet_pr_resv_released(struct nvmet_pr *pr, uuid_t *hostid) +{ + struct nvmet_ns *ns = nvmet_pr_to_ns(pr); + struct nvmet_subsys *subsys = ns->subsys; + struct nvmet_ctrl *ctrl; + + if (test_bit(NVME_PR_NOTIFY_BIT_RESV_RELEASED, &pr->notify_mask)) + return; + + mutex_lock(&subsys->lock); + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { + if (!uuid_equal(&ctrl->hostid, hostid) && + nvmet_pr_find_registrant(pr, &ctrl->hostid)) { + nvmet_pr_add_resv_log(ctrl, + NVME_PR_LOG_RESERVATION_RELEASED, ns->nsid); + nvmet_add_async_event(ctrl, NVME_AER_CSS, + NVME_AEN_RESV_LOG_PAGE_AVALIABLE, + NVME_LOG_RESERVATION); + } + } + mutex_unlock(&subsys->lock); +} + +static void nvmet_pr_send_event_to_host(struct nvmet_pr *pr, uuid_t *hostid, + u8 log_type) +{ + struct nvmet_ns *ns = nvmet_pr_to_ns(pr); + struct nvmet_subsys *subsys = ns->subsys; + struct nvmet_ctrl *ctrl; + + mutex_lock(&subsys->lock); + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { + if (uuid_equal(hostid, &ctrl->hostid)) { + nvmet_pr_add_resv_log(ctrl, log_type, ns->nsid); + nvmet_add_async_event(ctrl, NVME_AER_CSS, + NVME_AEN_RESV_LOG_PAGE_AVALIABLE, + NVME_LOG_RESERVATION); + } + } + mutex_unlock(&subsys->lock); +} + +static void nvmet_pr_resv_preempted(struct nvmet_pr *pr, uuid_t *hostid) +{ + if (test_bit(NVME_PR_NOTIFY_BIT_RESV_PREEMPTED, &pr->notify_mask)) + return; + + nvmet_pr_send_event_to_host(pr, hostid, + NVME_PR_LOG_RESERVATOIN_PREEMPTED); +} + +static void nvmet_pr_registration_preempted(struct nvmet_pr *pr, + uuid_t *hostid) +{ + if (test_bit(NVME_PR_NOTIFY_BIT_REG_PREEMPTED, &pr->notify_mask)) + return; + + nvmet_pr_send_event_to_host(pr, hostid, + NVME_PR_LOG_REGISTRATION_PREEMPTED); +} + +static inline void nvmet_pr_set_new_holder(struct nvmet_pr *pr, u8 new_rtype, + struct nvmet_pr_registrant *reg) +{ + reg->rtype = new_rtype; + rcu_assign_pointer(pr->holder, reg); +} + +static u16 nvmet_pr_register(struct nvmet_req *req, + struct nvmet_pr_register_data *d) +{ + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_pr_registrant *new, *reg; + struct nvmet_pr *pr = &req->ns->pr; + u16 status = NVME_SC_SUCCESS; + u64 nrkey = le64_to_cpu(d->nrkey); + + new = kmalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return NVME_SC_INTERNAL; + + down(&pr->pr_sem); + reg = nvmet_pr_find_registrant(pr, &ctrl->hostid); + if (reg) { + if (reg->rkey != nrkey) + status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + kfree(new); + goto out; + } + + memset(new, 0, sizeof(*new)); + INIT_LIST_HEAD(&new->entry); + new->rkey = nrkey; + uuid_copy(&new->hostid, &ctrl->hostid); + list_add_tail_rcu(&new->entry, &pr->registrant_list); + +out: + up(&pr->pr_sem); + return status; +} + +static void nvmet_pr_unregister_one(struct nvmet_pr *pr, + struct nvmet_pr_registrant *reg) +{ + struct nvmet_pr_registrant *first_reg; + struct nvmet_pr_registrant *holder; + u8 original_rtype; + + list_del_rcu(®->entry); + + holder = rcu_dereference_protected(pr->holder, 1); + if (reg != holder) + goto out; + + original_rtype = holder->rtype; + if (original_rtype == NVME_PR_WRITE_EXCLUSIVE_ALL_REGS || + original_rtype == NVME_PR_EXCLUSIVE_ACCESS_ALL_REGS) { + first_reg = list_first_or_null_rcu(&pr->registrant_list, + struct nvmet_pr_registrant, entry); + if (first_reg) + first_reg->rtype = original_rtype; + rcu_assign_pointer(pr->holder, first_reg); + } else { + rcu_assign_pointer(pr->holder, NULL); + + if (original_rtype == NVME_PR_WRITE_EXCLUSIVE_REG_ONLY || + original_rtype == NVME_PR_EXCLUSIVE_ACCESS_REG_ONLY) + nvmet_pr_resv_released(pr, ®->hostid); + } +out: + kfree_rcu(reg, rcu); +} + +static u16 nvmet_pr_unregister(struct nvmet_req *req, + struct nvmet_pr_register_data *d, + bool ignore_key) +{ + u16 status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_pr *pr = &req->ns->pr; + struct nvmet_pr_registrant *reg; + + down(&pr->pr_sem); + list_for_each_entry_rcu(reg, &pr->registrant_list, entry) { + if (uuid_equal(®->hostid, &ctrl->hostid)) { + if (ignore_key || reg->rkey == le64_to_cpu(d->crkey)) { + status = NVME_SC_SUCCESS; + nvmet_pr_unregister_one(pr, reg); + } + break; + } + } + up(&pr->pr_sem); + + return status; +} + +static void nvmet_pr_update_reg_rkey(struct nvmet_pr_registrant *reg, + void *attr) +{ + reg->rkey = *(u64 *)attr; +} + +static u16 nvmet_pr_update_reg_attr(struct nvmet_pr *pr, + struct nvmet_pr_registrant *reg, + void (*change_attr)(struct nvmet_pr_registrant *reg, + void *attr), + void *attr) +{ + struct nvmet_pr_registrant *holder; + struct nvmet_pr_registrant *new; + + holder = rcu_dereference_protected(pr->holder, 1); + if (reg != holder) { + change_attr(reg, attr); + return NVME_SC_SUCCESS; + } + + new = kmalloc(sizeof(*new), GFP_ATOMIC); + if (!new) + return NVME_SC_INTERNAL; + + new->rkey = holder->rkey; + new->rtype = holder->rtype; + uuid_copy(&new->hostid, &holder->hostid); + INIT_LIST_HEAD(&new->entry); + + change_attr(new, attr); + list_replace_rcu(&holder->entry, &new->entry); + rcu_assign_pointer(pr->holder, new); + kfree_rcu(holder, rcu); + + return NVME_SC_SUCCESS; +} + +static u16 nvmet_pr_replace(struct nvmet_req *req, + struct nvmet_pr_register_data *d, + bool ignore_key) +{ + u16 status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_pr *pr = &req->ns->pr; + struct nvmet_pr_registrant *reg; + u64 nrkey = le64_to_cpu(d->nrkey); + + down(&pr->pr_sem); + list_for_each_entry_rcu(reg, &pr->registrant_list, entry) { + if (uuid_equal(®->hostid, &ctrl->hostid)) { + if (ignore_key || reg->rkey == le64_to_cpu(d->crkey)) + status = nvmet_pr_update_reg_attr(pr, reg, + nvmet_pr_update_reg_rkey, + &nrkey); + break; + } + } + up(&pr->pr_sem); + return status; +} + +static void nvmet_execute_pr_register(struct nvmet_req *req) +{ + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + bool ignore_key = nvmet_pr_parse_ignore_key(cdw10); + struct nvmet_pr_register_data *d; + u8 reg_act = cdw10 & 0x07; /* Reservation Register Action, bit 02:00 */ + u16 status; + + d = kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + status = NVME_SC_INTERNAL; + goto out; + } + + status = nvmet_copy_from_sgl(req, 0, d, sizeof(*d)); + if (status) + goto free_data; + + switch (reg_act) { + case NVME_PR_REGISTER_ACT_REG: + status = nvmet_pr_register(req, d); + break; + case NVME_PR_REGISTER_ACT_UNREG: + status = nvmet_pr_unregister(req, d, ignore_key); + break; + case NVME_PR_REGISTER_ACT_REPLACE: + status = nvmet_pr_replace(req, d, ignore_key); + break; + default: + req->error_loc = offsetof(struct nvme_common_command, cdw10); + status = NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; + break; + } +free_data: + kfree(d); +out: + if (!status) + atomic_inc(&req->ns->pr.generation); + nvmet_req_complete(req, status); +} + +static u16 nvmet_pr_acquire(struct nvmet_req *req, + struct nvmet_pr_registrant *reg, + u8 rtype) +{ + struct nvmet_pr *pr = &req->ns->pr; + struct nvmet_pr_registrant *holder; + + holder = rcu_dereference_protected(pr->holder, 1); + if (holder && reg != holder) + return NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + if (holder && reg == holder) { + if (holder->rtype == rtype) + return NVME_SC_SUCCESS; + return NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + } + + nvmet_pr_set_new_holder(pr, rtype, reg); + return NVME_SC_SUCCESS; +} + +static void nvmet_pr_confirm_ns_pc_ref(struct percpu_ref *ref) +{ + struct nvmet_pr_per_ctrl_ref *pc_ref = + container_of(ref, struct nvmet_pr_per_ctrl_ref, ref); + + complete(&pc_ref->confirm_done); +} + +static void nvmet_pr_set_ctrl_to_abort(struct nvmet_req *req, uuid_t *hostid) +{ + struct nvmet_pr_per_ctrl_ref *pc_ref; + struct nvmet_ns *ns = req->ns; + unsigned long idx; + + xa_for_each(&ns->pr_per_ctrl_refs, idx, pc_ref) { + if (uuid_equal(&pc_ref->hostid, hostid)) { + percpu_ref_kill_and_confirm(&pc_ref->ref, + nvmet_pr_confirm_ns_pc_ref); + wait_for_completion(&pc_ref->confirm_done); + } + } +} + +static u16 nvmet_pr_unreg_all_host_by_prkey(struct nvmet_req *req, u64 prkey, + uuid_t *send_hostid, + bool abort) +{ + u16 status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + struct nvmet_pr_registrant *reg, *tmp; + struct nvmet_pr *pr = &req->ns->pr; + uuid_t hostid; + + list_for_each_entry_safe(reg, tmp, &pr->registrant_list, entry) { + if (reg->rkey == prkey) { + status = NVME_SC_SUCCESS; + uuid_copy(&hostid, ®->hostid); + if (abort) + nvmet_pr_set_ctrl_to_abort(req, &hostid); + nvmet_pr_unregister_one(pr, reg); + if (!uuid_equal(&hostid, send_hostid)) + nvmet_pr_registration_preempted(pr, &hostid); + } + } + return status; +} + +static void nvmet_pr_unreg_all_others_by_prkey(struct nvmet_req *req, + u64 prkey, + uuid_t *send_hostid, + bool abort) +{ + struct nvmet_pr_registrant *reg, *tmp; + struct nvmet_pr *pr = &req->ns->pr; + uuid_t hostid; + + list_for_each_entry_safe(reg, tmp, &pr->registrant_list, entry) { + if (reg->rkey == prkey && + !uuid_equal(®->hostid, send_hostid)) { + uuid_copy(&hostid, ®->hostid); + if (abort) + nvmet_pr_set_ctrl_to_abort(req, &hostid); + nvmet_pr_unregister_one(pr, reg); + nvmet_pr_registration_preempted(pr, &hostid); + } + } +} + +static void nvmet_pr_unreg_all_others(struct nvmet_req *req, + uuid_t *send_hostid, + bool abort) +{ + struct nvmet_pr_registrant *reg, *tmp; + struct nvmet_pr *pr = &req->ns->pr; + uuid_t hostid; + + list_for_each_entry_safe(reg, tmp, &pr->registrant_list, entry) { + if (!uuid_equal(®->hostid, send_hostid)) { + uuid_copy(&hostid, ®->hostid); + if (abort) + nvmet_pr_set_ctrl_to_abort(req, &hostid); + nvmet_pr_unregister_one(pr, reg); + nvmet_pr_registration_preempted(pr, &hostid); + } + } +} + +static void nvmet_pr_update_holder_rtype(struct nvmet_pr_registrant *reg, + void *attr) +{ + u8 new_rtype = *(u8 *)attr; + + reg->rtype = new_rtype; +} + +static u16 nvmet_pr_preempt(struct nvmet_req *req, + struct nvmet_pr_registrant *reg, + u8 rtype, + struct nvmet_pr_acquire_data *d, + bool abort) +{ + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_pr *pr = &req->ns->pr; + struct nvmet_pr_registrant *holder; + enum nvme_pr_type original_rtype; + u64 prkey = le64_to_cpu(d->prkey); + u16 status; + + holder = rcu_dereference_protected(pr->holder, 1); + if (!holder) + return nvmet_pr_unreg_all_host_by_prkey(req, prkey, + &ctrl->hostid, abort); + + original_rtype = holder->rtype; + if (original_rtype == NVME_PR_WRITE_EXCLUSIVE_ALL_REGS || + original_rtype == NVME_PR_EXCLUSIVE_ACCESS_ALL_REGS) { + if (!prkey) { + /* + * To prevent possible access from other hosts, and + * avoid terminate the holder, set the new holder + * first before unregistering. + */ + nvmet_pr_set_new_holder(pr, rtype, reg); + nvmet_pr_unreg_all_others(req, &ctrl->hostid, abort); + return NVME_SC_SUCCESS; + } + return nvmet_pr_unreg_all_host_by_prkey(req, prkey, + &ctrl->hostid, abort); + } + + if (holder == reg) { + status = nvmet_pr_update_reg_attr(pr, holder, + nvmet_pr_update_holder_rtype, &rtype); + if (!status && original_rtype != rtype) + nvmet_pr_resv_released(pr, ®->hostid); + return status; + } + + if (prkey == holder->rkey) { + /* + * Same as before, set the new holder first. + */ + nvmet_pr_set_new_holder(pr, rtype, reg); + nvmet_pr_unreg_all_others_by_prkey(req, prkey, &ctrl->hostid, + abort); + if (original_rtype != rtype) + nvmet_pr_resv_released(pr, ®->hostid); + return NVME_SC_SUCCESS; + } + + if (prkey) + return nvmet_pr_unreg_all_host_by_prkey(req, prkey, + &ctrl->hostid, abort); + return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; +} + +static void nvmet_pr_do_abort(struct work_struct *w) +{ + struct nvmet_req *req = container_of(w, struct nvmet_req, r.abort_work); + struct nvmet_pr_per_ctrl_ref *pc_ref; + struct nvmet_ns *ns = req->ns; + unsigned long idx; + + /* + * The target does not support abort, just wait per-controller ref to 0. + */ + xa_for_each(&ns->pr_per_ctrl_refs, idx, pc_ref) { + if (percpu_ref_is_dying(&pc_ref->ref)) { + wait_for_completion(&pc_ref->free_done); + reinit_completion(&pc_ref->confirm_done); + reinit_completion(&pc_ref->free_done); + percpu_ref_resurrect(&pc_ref->ref); + } + } + + up(&ns->pr.pr_sem); + nvmet_req_complete(req, NVME_SC_SUCCESS); +} + +static u16 __nvmet_execute_pr_acquire(struct nvmet_req *req, + struct nvmet_pr_registrant *reg, + u8 acquire_act, + u8 rtype, + struct nvmet_pr_acquire_data *d) +{ + u16 status; + + switch (acquire_act) { + case NVME_PR_ACQUIRE_ACT_ACQUIRE: + status = nvmet_pr_acquire(req, reg, rtype); + goto out; + case NVME_PR_ACQUIRE_ACT_PREEMPT: + status = nvmet_pr_preempt(req, reg, rtype, d, false); + goto inc_gen; + case NVME_PR_ACQUIRE_ACT_PREEMPT_AND_ABORT: + status = nvmet_pr_preempt(req, reg, rtype, d, true); + goto inc_gen; + default: + req->error_loc = offsetof(struct nvme_common_command, cdw10); + status = NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; + goto out; + } +inc_gen: + if (!status) + atomic_inc(&req->ns->pr.generation); +out: + return status; +} + +static void nvmet_execute_pr_acquire(struct nvmet_req *req) +{ + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + bool ignore_key = nvmet_pr_parse_ignore_key(cdw10); + /* Reservation type, bit 15:08 */ + u8 rtype = (u8)((cdw10 >> 8) & 0xff); + /* Reservation acquire action, bit 02:00 */ + u8 acquire_act = cdw10 & 0x07; + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_pr_acquire_data *d = NULL; + struct nvmet_pr *pr = &req->ns->pr; + struct nvmet_pr_registrant *reg; + u16 status = NVME_SC_SUCCESS; + + if (ignore_key || + rtype < NVME_PR_WRITE_EXCLUSIVE || + rtype > NVME_PR_EXCLUSIVE_ACCESS_ALL_REGS) { + status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; + goto out; + } + + d = kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + status = NVME_SC_INTERNAL; + goto out; + } + + status = nvmet_copy_from_sgl(req, 0, d, sizeof(*d)); + if (status) + goto free_data; + + status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + down(&pr->pr_sem); + list_for_each_entry_rcu(reg, &pr->registrant_list, entry) { + if (uuid_equal(®->hostid, &ctrl->hostid) && + reg->rkey == le64_to_cpu(d->crkey)) { + status = __nvmet_execute_pr_acquire(req, reg, + acquire_act, rtype, d); + break; + } + } + + if (!status && acquire_act == NVME_PR_ACQUIRE_ACT_PREEMPT_AND_ABORT) { + kfree(d); + INIT_WORK(&req->r.abort_work, nvmet_pr_do_abort); + queue_work(nvmet_wq, &req->r.abort_work); + return; + } + + up(&pr->pr_sem); + +free_data: + kfree(d); +out: + nvmet_req_complete(req, status); +} + +static u16 nvmet_pr_release(struct nvmet_req *req, + struct nvmet_pr_registrant *reg, + u8 rtype) +{ + struct nvmet_pr *pr = &req->ns->pr; + struct nvmet_pr_registrant *holder; + u8 original_rtype; + + holder = rcu_dereference_protected(pr->holder, 1); + if (!holder || reg != holder) + return NVME_SC_SUCCESS; + + original_rtype = holder->rtype; + if (original_rtype != rtype) + return NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + + rcu_assign_pointer(pr->holder, NULL); + + if (original_rtype != NVME_PR_WRITE_EXCLUSIVE && + original_rtype != NVME_PR_EXCLUSIVE_ACCESS) + nvmet_pr_resv_released(pr, ®->hostid); + + return NVME_SC_SUCCESS; +} + +static void nvmet_pr_clear(struct nvmet_req *req) +{ + struct nvmet_pr_registrant *reg, *tmp; + struct nvmet_pr *pr = &req->ns->pr; + + rcu_assign_pointer(pr->holder, NULL); + + list_for_each_entry_safe(reg, tmp, &pr->registrant_list, entry) { + list_del_rcu(®->entry); + if (!uuid_equal(&req->sq->ctrl->hostid, ®->hostid)) + nvmet_pr_resv_preempted(pr, ®->hostid); + kfree_rcu(reg, rcu); + } + + atomic_inc(&pr->generation); +} + +static u16 __nvmet_execute_pr_release(struct nvmet_req *req, + struct nvmet_pr_registrant *reg, + u8 release_act, u8 rtype) +{ + switch (release_act) { + case NVME_PR_RELEASE_ACT_RELEASE: + return nvmet_pr_release(req, reg, rtype); + case NVME_PR_RELEASE_ACT_CLEAR: + nvmet_pr_clear(req); + return NVME_SC_SUCCESS; + default: + req->error_loc = offsetof(struct nvme_common_command, cdw10); + return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; + } +} + +static void nvmet_execute_pr_release(struct nvmet_req *req) +{ + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + bool ignore_key = nvmet_pr_parse_ignore_key(cdw10); + u8 rtype = (u8)((cdw10 >> 8) & 0xff); /* Reservation type, bit 15:08 */ + u8 release_act = cdw10 & 0x07; /* Reservation release action, bit 02:00 */ + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_pr *pr = &req->ns->pr; + struct nvmet_pr_release_data *d; + struct nvmet_pr_registrant *reg; + u16 status; + + if (ignore_key) { + status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; + goto out; + } + + d = kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + status = NVME_SC_INTERNAL; + goto out; + } + + status = nvmet_copy_from_sgl(req, 0, d, sizeof(*d)); + if (status) + goto free_data; + + status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + down(&pr->pr_sem); + list_for_each_entry_rcu(reg, &pr->registrant_list, entry) { + if (uuid_equal(®->hostid, &ctrl->hostid) && + reg->rkey == le64_to_cpu(d->crkey)) { + status = __nvmet_execute_pr_release(req, reg, + release_act, rtype); + break; + } + } + up(&pr->pr_sem); +free_data: + kfree(d); +out: + nvmet_req_complete(req, status); +} + +static void nvmet_execute_pr_report(struct nvmet_req *req) +{ + u32 cdw11 = le32_to_cpu(req->cmd->common.cdw11); + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + u32 num_bytes = 4 * (cdw10 + 1); /* cdw10 is number of dwords */ + u8 eds = cdw11 & 1; /* Extended data structure, bit 00 */ + struct nvme_registered_ctrl_ext *ctrl_eds; + struct nvme_reservation_status_ext *data; + struct nvmet_pr *pr = &req->ns->pr; + struct nvmet_pr_registrant *holder; + struct nvmet_pr_registrant *reg; + u16 num_ctrls = 0; + u16 status; + u8 rtype; + + /* nvmet hostid(uuid_t) is 128 bit. */ + if (!eds) { + req->error_loc = offsetof(struct nvme_common_command, cdw11); + status = NVME_SC_HOST_ID_INCONSIST | NVME_STATUS_DNR; + goto out; + } + + if (num_bytes < sizeof(struct nvme_reservation_status_ext)) { + req->error_loc = offsetof(struct nvme_common_command, cdw10); + status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; + goto out; + } + + data = kzalloc(num_bytes, GFP_KERNEL); + if (!data) { + status = NVME_SC_INTERNAL; + goto out; + } + data->gen = cpu_to_le32(atomic_read(&pr->generation)); + data->ptpls = 0; + ctrl_eds = data->regctl_eds; + + rcu_read_lock(); + holder = rcu_dereference(pr->holder); + rtype = holder ? holder->rtype : 0; + data->rtype = rtype; + + list_for_each_entry_rcu(reg, &pr->registrant_list, entry) { + num_ctrls++; + /* + * continue to get the number of all registrans. + */ + if (((void *)ctrl_eds + sizeof(*ctrl_eds)) > + ((void *)data + num_bytes)) + continue; + /* + * Dynamic controller, set cntlid to 0xffff. + */ + ctrl_eds->cntlid = cpu_to_le16(NVME_CNTLID_DYNAMIC); + if (rtype == NVME_PR_WRITE_EXCLUSIVE_ALL_REGS || + rtype == NVME_PR_EXCLUSIVE_ACCESS_ALL_REGS) + ctrl_eds->rcsts = 1; + if (reg == holder) + ctrl_eds->rcsts = 1; + uuid_copy((uuid_t *)&ctrl_eds->hostid, ®->hostid); + ctrl_eds->rkey = cpu_to_le64(reg->rkey); + ctrl_eds++; + } + rcu_read_unlock(); + + put_unaligned_le16(num_ctrls, data->regctl); + status = nvmet_copy_to_sgl(req, 0, data, num_bytes); + kfree(data); +out: + nvmet_req_complete(req, status); +} + +u16 nvmet_parse_pr_cmd(struct nvmet_req *req) +{ + struct nvme_command *cmd = req->cmd; + + switch (cmd->common.opcode) { + case nvme_cmd_resv_register: + req->execute = nvmet_execute_pr_register; + break; + case nvme_cmd_resv_acquire: + req->execute = nvmet_execute_pr_acquire; + break; + case nvme_cmd_resv_release: + req->execute = nvmet_execute_pr_release; + break; + case nvme_cmd_resv_report: + req->execute = nvmet_execute_pr_report; + break; + default: + return 1; + } + return NVME_SC_SUCCESS; +} + +static bool nvmet_is_req_write_cmd_group(struct nvmet_req *req) +{ + u8 opcode = req->cmd->common.opcode; + + if (req->sq->qid) { + switch (opcode) { + case nvme_cmd_flush: + case nvme_cmd_write: + case nvme_cmd_write_zeroes: + case nvme_cmd_dsm: + case nvme_cmd_zone_append: + case nvme_cmd_zone_mgmt_send: + return true; + default: + return false; + } + } + return false; +} + +static bool nvmet_is_req_read_cmd_group(struct nvmet_req *req) +{ + u8 opcode = req->cmd->common.opcode; + + if (req->sq->qid) { + switch (opcode) { + case nvme_cmd_read: + case nvme_cmd_zone_mgmt_recv: + return true; + default: + return false; + } + } + return false; +} + +u16 nvmet_pr_check_cmd_access(struct nvmet_req *req) +{ + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvmet_pr_registrant *holder; + struct nvmet_ns *ns = req->ns; + struct nvmet_pr *pr = &ns->pr; + u16 status = NVME_SC_SUCCESS; + + rcu_read_lock(); + holder = rcu_dereference(pr->holder); + if (!holder) + goto unlock; + if (uuid_equal(&ctrl->hostid, &holder->hostid)) + goto unlock; + + /* + * The Reservation command group is checked in executing, + * allow it here. + */ + switch (holder->rtype) { + case NVME_PR_WRITE_EXCLUSIVE: + if (nvmet_is_req_write_cmd_group(req)) + status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + break; + case NVME_PR_EXCLUSIVE_ACCESS: + if (nvmet_is_req_read_cmd_group(req) || + nvmet_is_req_write_cmd_group(req)) + status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + break; + case NVME_PR_WRITE_EXCLUSIVE_REG_ONLY: + case NVME_PR_WRITE_EXCLUSIVE_ALL_REGS: + if ((nvmet_is_req_write_cmd_group(req)) && + !nvmet_pr_find_registrant(pr, &ctrl->hostid)) + status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + break; + case NVME_PR_EXCLUSIVE_ACCESS_REG_ONLY: + case NVME_PR_EXCLUSIVE_ACCESS_ALL_REGS: + if ((nvmet_is_req_read_cmd_group(req) || + nvmet_is_req_write_cmd_group(req)) && + !nvmet_pr_find_registrant(pr, &ctrl->hostid)) + status = NVME_SC_RESERVATION_CONFLICT | NVME_STATUS_DNR; + break; + default: + pr_warn("the reservation type is set wrong, type:%d\n", + holder->rtype); + break; + } + +unlock: + rcu_read_unlock(); + if (status) + req->error_loc = offsetof(struct nvme_common_command, opcode); + return status; +} + +u16 nvmet_pr_get_ns_pc_ref(struct nvmet_req *req) +{ + struct nvmet_pr_per_ctrl_ref *pc_ref; + + pc_ref = xa_load(&req->ns->pr_per_ctrl_refs, + req->sq->ctrl->cntlid); + if (unlikely(!percpu_ref_tryget_live(&pc_ref->ref))) + return NVME_SC_INTERNAL; + req->pc_ref = pc_ref; + return NVME_SC_SUCCESS; +} + +static void nvmet_pr_ctrl_ns_all_cmds_done(struct percpu_ref *ref) +{ + struct nvmet_pr_per_ctrl_ref *pc_ref = + container_of(ref, struct nvmet_pr_per_ctrl_ref, ref); + + complete(&pc_ref->free_done); +} + +static int nvmet_pr_alloc_and_insert_pc_ref(struct nvmet_ns *ns, + unsigned long idx, + uuid_t *hostid) +{ + struct nvmet_pr_per_ctrl_ref *pc_ref; + int ret; + + pc_ref = kmalloc(sizeof(*pc_ref), GFP_ATOMIC); + if (!pc_ref) + return -ENOMEM; + + ret = percpu_ref_init(&pc_ref->ref, nvmet_pr_ctrl_ns_all_cmds_done, + PERCPU_REF_ALLOW_REINIT, GFP_KERNEL); + if (ret) + goto free; + + init_completion(&pc_ref->free_done); + init_completion(&pc_ref->confirm_done); + uuid_copy(&pc_ref->hostid, hostid); + + ret = xa_insert(&ns->pr_per_ctrl_refs, idx, pc_ref, GFP_KERNEL); + if (ret) + goto exit; + return ret; +exit: + percpu_ref_exit(&pc_ref->ref); +free: + kfree(pc_ref); + return ret; +} + +int nvmet_ctrl_init_pr(struct nvmet_ctrl *ctrl) +{ + struct nvmet_subsys *subsys = ctrl->subsys; + struct nvmet_pr_per_ctrl_ref *pc_ref; + struct nvmet_ns *ns = NULL; + unsigned long idx; + int ret; + + ctrl->pr_log_mgr.counter = 0; + ctrl->pr_log_mgr.lost_count = 0; + mutex_init(&ctrl->pr_log_mgr.lock); + INIT_KFIFO(ctrl->pr_log_mgr.log_queue); + + /* + * Here we are under subsys lock, if an ns not in subsys->namespaces, + * we can make sure that ns is not enabled, and not call + * nvmet_pr_init_ns(), see more details in nvmet_ns_enable(). + * So just check ns->pr.enable. + */ + xa_for_each(&subsys->namespaces, idx, ns) { + if (ns->pr.enable) { + ret = nvmet_pr_alloc_and_insert_pc_ref(ns, ctrl->cntlid, + &ctrl->hostid); + if (ret) + goto free_per_ctrl_refs; + } + } + return 0; + +free_per_ctrl_refs: + xa_for_each(&subsys->namespaces, idx, ns) { + if (ns->pr.enable) { + pc_ref = xa_erase(&ns->pr_per_ctrl_refs, ctrl->cntlid); + if (pc_ref) + percpu_ref_exit(&pc_ref->ref); + kfree(pc_ref); + } + } + return ret; +} + +void nvmet_ctrl_destroy_pr(struct nvmet_ctrl *ctrl) +{ + struct nvmet_pr_per_ctrl_ref *pc_ref; + struct nvmet_ns *ns; + unsigned long idx; + + kfifo_free(&ctrl->pr_log_mgr.log_queue); + mutex_destroy(&ctrl->pr_log_mgr.lock); + + xa_for_each(&ctrl->subsys->namespaces, idx, ns) { + if (ns->pr.enable) { + pc_ref = xa_erase(&ns->pr_per_ctrl_refs, ctrl->cntlid); + if (pc_ref) + percpu_ref_exit(&pc_ref->ref); + kfree(pc_ref); + } + } +} + +int nvmet_pr_init_ns(struct nvmet_ns *ns) +{ + struct nvmet_subsys *subsys = ns->subsys; + struct nvmet_pr_per_ctrl_ref *pc_ref; + struct nvmet_ctrl *ctrl = NULL; + unsigned long idx; + int ret; + + ns->pr.holder = NULL; + atomic_set(&ns->pr.generation, 0); + sema_init(&ns->pr.pr_sem, 1); + INIT_LIST_HEAD(&ns->pr.registrant_list); + ns->pr.notify_mask = 0; + + xa_init(&ns->pr_per_ctrl_refs); + + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { + ret = nvmet_pr_alloc_and_insert_pc_ref(ns, ctrl->cntlid, + &ctrl->hostid); + if (ret) + goto free_per_ctrl_refs; + } + return 0; + +free_per_ctrl_refs: + xa_for_each(&ns->pr_per_ctrl_refs, idx, pc_ref) { + xa_erase(&ns->pr_per_ctrl_refs, idx); + percpu_ref_exit(&pc_ref->ref); + kfree(pc_ref); + } + return ret; +} + +void nvmet_pr_exit_ns(struct nvmet_ns *ns) +{ + struct nvmet_pr_registrant *reg, *tmp; + struct nvmet_pr_per_ctrl_ref *pc_ref; + struct nvmet_pr *pr = &ns->pr; + unsigned long idx; + + list_for_each_entry_safe(reg, tmp, &pr->registrant_list, entry) { + list_del(®->entry); + kfree(reg); + } + + xa_for_each(&ns->pr_per_ctrl_refs, idx, pc_ref) { + /* + * No command on ns here, we can safely free pc_ref. + */ + pc_ref = xa_erase(&ns->pr_per_ctrl_refs, idx); + percpu_ref_exit(&pc_ref->ref); + kfree(pc_ref); + } + + xa_destroy(&ns->pr_per_ctrl_refs); +} diff --git a/drivers/nvme/target/trace.c b/drivers/nvme/target/trace.c index 9a3548179a8e36..6dbc7036f2e4b1 100644 --- a/drivers/nvme/target/trace.c +++ b/drivers/nvme/target/trace.c @@ -180,6 +180,106 @@ static const char *nvmet_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10) return ret; } +static const char *nvmet_trace_resv_reg(struct trace_seq *p, u8 *cdw10) +{ + static const char * const rrega_strs[] = { + [0x00] = "register", + [0x01] = "unregister", + [0x02] = "replace", + }; + const char *ret = trace_seq_buffer_ptr(p); + u8 rrega = cdw10[0] & 0x7; + u8 iekey = (cdw10[0] >> 3) & 0x1; + u8 ptpl = (cdw10[3] >> 6) & 0x3; + const char *rrega_str; + + if (rrega < ARRAY_SIZE(rrega_strs) && rrega_strs[rrega]) + rrega_str = rrega_strs[rrega]; + else + rrega_str = "reserved"; + + trace_seq_printf(p, "rrega=%u:%s, iekey=%u, ptpl=%u", + rrega, rrega_str, iekey, ptpl); + trace_seq_putc(p, 0); + + return ret; +} + +static const char * const rtype_strs[] = { + [0x00] = "reserved", + [0x01] = "write exclusive", + [0x02] = "exclusive access", + [0x03] = "write exclusive registrants only", + [0x04] = "exclusive access registrants only", + [0x05] = "write exclusive all registrants", + [0x06] = "exclusive access all registrants", +}; + +static const char *nvmet_trace_resv_acq(struct trace_seq *p, u8 *cdw10) +{ + static const char * const racqa_strs[] = { + [0x00] = "acquire", + [0x01] = "preempt", + [0x02] = "preempt and abort", + }; + const char *ret = trace_seq_buffer_ptr(p); + u8 racqa = cdw10[0] & 0x7; + u8 iekey = (cdw10[0] >> 3) & 0x1; + u8 rtype = cdw10[1]; + const char *racqa_str = "reserved"; + const char *rtype_str = "reserved"; + + if (racqa < ARRAY_SIZE(racqa_strs) && racqa_strs[racqa]) + racqa_str = racqa_strs[racqa]; + + if (rtype < ARRAY_SIZE(rtype_strs) && rtype_strs[rtype]) + rtype_str = rtype_strs[rtype]; + + trace_seq_printf(p, "racqa=%u:%s, iekey=%u, rtype=%u:%s", + racqa, racqa_str, iekey, rtype, rtype_str); + trace_seq_putc(p, 0); + + return ret; +} + +static const char *nvmet_trace_resv_rel(struct trace_seq *p, u8 *cdw10) +{ + static const char * const rrela_strs[] = { + [0x00] = "release", + [0x01] = "clear", + }; + const char *ret = trace_seq_buffer_ptr(p); + u8 rrela = cdw10[0] & 0x7; + u8 iekey = (cdw10[0] >> 3) & 0x1; + u8 rtype = cdw10[1]; + const char *rrela_str = "reserved"; + const char *rtype_str = "reserved"; + + if (rrela < ARRAY_SIZE(rrela_strs) && rrela_strs[rrela]) + rrela_str = rrela_strs[rrela]; + + if (rtype < ARRAY_SIZE(rtype_strs) && rtype_strs[rtype]) + rtype_str = rtype_strs[rtype]; + + trace_seq_printf(p, "rrela=%u:%s, iekey=%u, rtype=%u:%s", + rrela, rrela_str, iekey, rtype, rtype_str); + trace_seq_putc(p, 0); + + return ret; +} + +static const char *nvmet_trace_resv_report(struct trace_seq *p, u8 *cdw10) +{ + const char *ret = trace_seq_buffer_ptr(p); + u32 numd = get_unaligned_le32(cdw10); + u8 eds = cdw10[4] & 0x1; + + trace_seq_printf(p, "numd=%u, eds=%u", numd, eds); + trace_seq_putc(p, 0); + + return ret; +} + const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p, u8 opcode, u8 *cdw10) { @@ -195,6 +295,14 @@ const char *nvmet_trace_parse_nvm_cmd(struct trace_seq *p, return nvmet_trace_zone_mgmt_send(p, cdw10); case nvme_cmd_zone_mgmt_recv: return nvmet_trace_zone_mgmt_recv(p, cdw10); + case nvme_cmd_resv_register: + return nvmet_trace_resv_reg(p, cdw10); + case nvme_cmd_resv_acquire: + return nvmet_trace_resv_acq(p, cdw10); + case nvme_cmd_resv_release: + return nvmet_trace_resv_rel(p, cdw10); + case nvme_cmd_resv_report: + return nvmet_trace_resv_report(p, cdw10); default: return nvmet_trace_common(p, cdw10); } diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c index af9e13be767862..3aef35b0511194 100644 --- a/drivers/nvme/target/zns.c +++ b/drivers/nvme/target/zns.c @@ -537,6 +537,7 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req) u16 status = NVME_SC_SUCCESS; unsigned int total_len = 0; struct scatterlist *sg; + u32 data_len = nvmet_rw_data_len(req); struct bio *bio; int sg_cnt; @@ -544,6 +545,13 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req) if (!nvmet_check_transfer_len(req, nvmet_rw_data_len(req))) return; + if (data_len > + bdev_max_zone_append_sectors(req->ns->bdev) << SECTOR_SHIFT) { + req->error_loc = offsetof(struct nvme_rw_command, length); + status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; + goto out; + } + if (!req->sg_cnt) { nvmet_req_complete(req, 0); return; @@ -576,20 +584,17 @@ void nvmet_bdev_execute_zone_append(struct nvmet_req *req) bio->bi_opf |= REQ_FUA; for_each_sg(req->sg, sg, req->sg_cnt, sg_cnt) { - struct page *p = sg_page(sg); - unsigned int l = sg->length; - unsigned int o = sg->offset; - unsigned int ret; + unsigned int len = sg->length; - ret = bio_add_zone_append_page(bio, p, l, o); - if (ret != sg->length) { + if (bio_add_pc_page(bdev_get_queue(bio->bi_bdev), bio, + sg_page(sg), len, sg->offset) != len) { status = NVME_SC_INTERNAL; goto out_put_bio; } - total_len += sg->length; + total_len += len; } - if (total_len != nvmet_rw_data_len(req)) { + if (total_len != data_len) { status = NVME_SC_INTERNAL | NVME_STATUS_DNR; goto out_put_bio; } diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index d2c384f58028dc..8671b7c974b933 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -246,6 +246,17 @@ config NVMEM_RAVE_SP_EEPROM help Say y here to enable Rave SP EEPROM support. +config NVMEM_RCAR_EFUSE + tristate "Renesas R-Car Gen4 E-FUSE support" + depends on (ARCH_RENESAS && ARM64) || COMPILE_TEST + depends on NVMEM + help + Enable support for reading the fuses in the E-FUSE or OTP + non-volatile memory block on Renesas R-Car Gen4 SoCs. + + This driver can also be built as a module. If so, the module + will be called nvmem-rcar-efuse. + config NVMEM_RMEM tristate "Reserved Memory Based Driver Support" depends on HAS_IOMEM diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index cdd01fbf1313b5..5b77bbb6488bf8 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -52,6 +52,8 @@ obj-$(CONFIG_NVMEM_QCOM_SEC_QFPROM) += nvmem_sec_qfprom.o nvmem_sec_qfprom-y := sec-qfprom.o obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o +obj-$(CONFIG_NVMEM_RCAR_EFUSE) += nvmem-rcar-efuse.o +nvmem-rcar-efuse-y := rcar-efuse.o obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o nvmem-rmem-y := rmem.o obj-$(CONFIG_NVMEM_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c index 3d8c87835f4d6c..b810df727b446b 100644 --- a/drivers/nvmem/brcm_nvram.c +++ b/drivers/nvmem/brcm_nvram.c @@ -22,7 +22,7 @@ * * @dev: NVMEM device pointer * @nvmem_size: Size of the whole space available for NVRAM - * @data: NVRAM data copy stored to avoid poking underlaying flash controller + * @data: NVRAM data copy stored to avoid poking underlying flash controller * @data_len: NVRAM data size * @padding_byte: Padding value used to fill remaining space * @cells: Array of discovered NVMEM cells diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 33ffa2aa4c1152..d6494dfc20a732 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -267,7 +267,7 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, count = round_down(count, nvmem->word_size); - if (!nvmem->reg_write) + if (!nvmem->reg_write || nvmem->read_only) return -EPERM; rc = nvmem_reg_write(nvmem, pos, buf, count); @@ -298,16 +298,25 @@ static umode_t nvmem_bin_attr_get_umode(struct nvmem_device *nvmem) } static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, - struct bin_attribute *attr, int i) + const struct bin_attribute *attr, + int i) { struct device *dev = kobj_to_dev(kobj); struct nvmem_device *nvmem = to_nvmem_device(dev); - attr->size = nvmem->size; - return nvmem_bin_attr_get_umode(nvmem); } +static size_t nvmem_bin_attr_size(struct kobject *kobj, + const struct bin_attribute *attr, + int i) +{ + struct device *dev = kobj_to_dev(kobj); + struct nvmem_device *nvmem = to_nvmem_device(dev); + + return nvmem->size; +} + static umode_t nvmem_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { @@ -383,6 +392,7 @@ static const struct attribute_group nvmem_bin_group = { .bin_attrs = nvmem_bin_attributes, .attrs = nvmem_attrs, .is_bin_visible = nvmem_bin_attr_is_visible, + .bin_size = nvmem_bin_attr_size, .is_visible = nvmem_attr_is_visible, }; @@ -1247,7 +1257,7 @@ static void devm_nvmem_device_release(struct device *dev, void *res) } /** - * devm_nvmem_device_put() - put alredy got nvmem device + * devm_nvmem_device_put() - put already got nvmem device * * @dev: Device that uses the nvmem device. * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), @@ -1265,7 +1275,7 @@ void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) EXPORT_SYMBOL_GPL(devm_nvmem_device_put); /** - * nvmem_device_put() - put alredy got nvmem device + * nvmem_device_put() - put already got nvmem device * * @nvmem: pointer to nvmem device that needs to be released. */ diff --git a/drivers/nvmem/imx-iim.c b/drivers/nvmem/imx-iim.c index f13bbd16408682..8cfbe55a56cb30 100644 --- a/drivers/nvmem/imx-iim.c +++ b/drivers/nvmem/imx-iim.c @@ -115,11 +115,11 @@ static int imx_iim_probe(struct platform_device *pdev) if (IS_ERR(iim->clk)) return PTR_ERR(iim->clk); - cfg.name = "imx-iim", - cfg.read_only = true, - cfg.word_size = 1, - cfg.stride = 1, - cfg.reg_read = imx_iim_read, + cfg.name = "imx-iim"; + cfg.read_only = true; + cfg.word_size = 1; + cfg.stride = 1; + cfg.reg_read = imx_iim_read; cfg.dev = dev; cfg.size = drvdata->nregs; cfg.priv = iim; diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c index a73acc7377d251..aa43f5f612f962 100644 --- a/drivers/nvmem/lpc18xx_eeprom.c +++ b/drivers/nvmem/lpc18xx_eeprom.c @@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); static struct platform_driver lpc18xx_eeprom_driver = { .probe = lpc18xx_eeprom_probe, - .remove_new = lpc18xx_eeprom_remove, + .remove = lpc18xx_eeprom_remove, .driver = { .name = "lpc18xx-eeprom", .of_match_table = lpc18xx_eeprom_of_match, diff --git a/drivers/nvmem/lpc18xx_otp.c b/drivers/nvmem/lpc18xx_otp.c index adc9948e7b2ec9..c41a0c58bec765 100644 --- a/drivers/nvmem/lpc18xx_otp.c +++ b/drivers/nvmem/lpc18xx_otp.c @@ -21,7 +21,7 @@ * LPC18xx OTP memory contains 4 banks with 4 32-bit words. Bank 0 starts * at offset 0 from the base. * - * Bank 0 contains the part ID for Flashless devices and is reseverd for + * Bank 0 contains the part ID for Flashless devices and is reserved for * devices with Flash. * Bank 1/2 is generale purpose or AES key storage for secure devices. * Bank 3 contains control data, USB ID and generale purpose words. diff --git a/drivers/nvmem/microchip-otpc.c b/drivers/nvmem/microchip-otpc.c index 7cf81738a3e0a5..df979e8549fdb4 100644 --- a/drivers/nvmem/microchip-otpc.c +++ b/drivers/nvmem/microchip-otpc.c @@ -156,7 +156,7 @@ static int mchp_otpc_read(void *priv, unsigned int off, void *val, /* * We reach this point with off being multiple of stride = 4 to * be able to cross the subsystem. Inside the driver we use continuous - * unsigned integer numbers for packet id, thus devide off by 4 + * unsigned integer numbers for packet id, thus divide off by 4 * before passing it to mchp_otpc_id_to_packet(). */ packet = mchp_otpc_id_to_packet(otpc, off / 4); diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c index 9caf0466734101..af953e1d923023 100644 --- a/drivers/nvmem/mtk-efuse.c +++ b/drivers/nvmem/mtk-efuse.c @@ -127,7 +127,7 @@ static void mtk_efuse_remove(struct platform_device *pdev) static struct platform_driver mtk_efuse_driver = { .probe = mtk_efuse_probe, - .remove_new = mtk_efuse_remove, + .remove = mtk_efuse_remove, .driver = { .name = "mediatek,efuse", .of_match_table = mtk_efuse_of_match, diff --git a/drivers/nvmem/rcar-efuse.c b/drivers/nvmem/rcar-efuse.c new file mode 100644 index 00000000000000..f24bdb9cb5a729 --- /dev/null +++ b/drivers/nvmem/rcar-efuse.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Renesas R-Car E-FUSE/OTP Driver + * + * Copyright (C) 2024 Glider bv + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct rcar_fuse { + struct nvmem_keepout keepouts[2]; + struct nvmem_device *nvmem; + struct device *dev; + void __iomem *base; +}; + +struct rcar_fuse_data { + unsigned int bank; /* 0: PFC + E-FUSE, 1: OPT_MEM + E-FUSE */ + unsigned int start; /* inclusive */ + unsigned int end; /* exclusive */ +}; + +static int rcar_fuse_reg_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct rcar_fuse *fuse = priv; + int ret; + + ret = pm_runtime_resume_and_get(fuse->dev); + if (ret < 0) + return ret; + + __ioread32_copy(val, fuse->base + offset, bytes / 4); + + pm_runtime_put(fuse->dev); + + return 0; +} + +static int rcar_fuse_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct rcar_fuse_data *data = device_get_match_data(dev); + struct nvmem_config config = { + .dev = dev, + .name = "rcar-fuse", + .id = NVMEM_DEVID_NONE, + .owner = THIS_MODULE, + .type = NVMEM_TYPE_OTP, + .read_only = true, + .root_only = true, + .reg_read = rcar_fuse_reg_read, + .word_size = 4, + .stride = 4, + }; + struct rcar_fuse *fuse; + struct resource *res; + int ret; + + ret = devm_pm_runtime_enable(dev); + if (ret < 0) + return ret; + + fuse = devm_kzalloc(dev, sizeof(*fuse), GFP_KERNEL); + if (!fuse) + return -ENOMEM; + + fuse->base = devm_platform_get_and_ioremap_resource(pdev, data->bank, + &res); + if (IS_ERR(fuse->base)) + return PTR_ERR(fuse->base); + + fuse->dev = dev; + fuse->keepouts[0].start = 0; + fuse->keepouts[0].end = data->start; + fuse->keepouts[1].start = data->end; + fuse->keepouts[1].end = resource_size(res); + + config.keepout = fuse->keepouts; + config.nkeepout = ARRAY_SIZE(fuse->keepouts); + config.size = resource_size(res); + config.priv = fuse; + + fuse->nvmem = devm_nvmem_register(dev, &config); + if (IS_ERR(fuse->nvmem)) + return dev_err_probe(dev, PTR_ERR(fuse->nvmem), + "Failed to register NVMEM device\n"); + + return 0; +} + +static const struct rcar_fuse_data rcar_fuse_v3u = { + .bank = 0, + .start = 0x0c0, + .end = 0x0e8, +}; + +static const struct rcar_fuse_data rcar_fuse_s4 = { + .bank = 0, + .start = 0x0c0, + .end = 0x14c, +}; + +static const struct rcar_fuse_data rcar_fuse_v4h = { + .bank = 1, + .start = 0x100, + .end = 0x1a0, +}; + +static const struct rcar_fuse_data rcar_fuse_v4m = { + .bank = 1, + .start = 0x100, + .end = 0x110, +}; + +static const struct of_device_id rcar_fuse_match[] = { + { .compatible = "renesas,r8a779a0-efuse", .data = &rcar_fuse_v3u }, + { .compatible = "renesas,r8a779f0-efuse", .data = &rcar_fuse_s4 }, + { .compatible = "renesas,r8a779g0-otp", .data = &rcar_fuse_v4h }, + { .compatible = "renesas,r8a779h0-otp", .data = &rcar_fuse_v4m }, + { /* sentinel */ } +}; + +static struct platform_driver rcar_fuse_driver = { + .probe = rcar_fuse_probe, + .driver = { + .name = "rcar_fuse", + .of_match_table = rcar_fuse_match, + }, +}; +module_platform_driver(rcar_fuse_driver); + +MODULE_DESCRIPTION("Renesas R-Car E-FUSE/OTP driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Geert Uytterhoeven"); diff --git a/drivers/of/.kunitconfig b/drivers/of/.kunitconfig index 4c53d2c7a2757e..7d570cb922a179 100644 --- a/drivers/of/.kunitconfig +++ b/drivers/of/.kunitconfig @@ -1,4 +1,5 @@ CONFIG_KUNIT=y CONFIG_OF=y CONFIG_OF_KUNIT_TEST=y +CONFIG_OF_OVERLAY=y CONFIG_OF_OVERLAY_KUNIT_TEST=y diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 0e2d608c3e207d..50697cc3b07ebe 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -2,6 +2,12 @@ config DTC bool +config GENERIC_BUILTIN_DTB + bool + +config BUILTIN_DTB_ALL + bool + menuconfig OF bool "Device Tree and Open Firmware support" help @@ -111,7 +117,7 @@ config OF_OVERLAY_KUNIT_TEST tristate "Device Tree overlay KUnit tests" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS - select OF_OVERLAY + select DTC help This option builds KUnit unit tests for the device tree overlay code. diff --git a/drivers/of/address.c b/drivers/of/address.c index 286f0c161e332f..c1f1c810e810d0 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -147,7 +147,7 @@ static unsigned int of_bus_pci_get_flags(const __be32 *addr) * PCI bus specific translator */ -static bool of_node_is_pcie(struct device_node *np) +static bool of_node_is_pcie(const struct device_node *np) { bool is_pcie = of_node_name_eq(np, "pcie"); @@ -230,8 +230,8 @@ static int __of_address_resource_bounds(struct resource *r, u64 start, u64 size) * To guard against that we try to register the IO range first. * If that fails we know that pci_address_to_pio() will do too. */ -int of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, struct resource *res) +int of_pci_range_to_resource(const struct of_pci_range *range, + const struct device_node *np, struct resource *res) { u64 start; int err; @@ -333,14 +333,18 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr) static int of_bus_default_flags_match(struct device_node *np) { - return of_bus_n_addr_cells(np) == 3; + /* + * Check for presence first since of_bus_n_addr_cells() will warn when + * walking parent nodes. + */ + return of_property_present(np, "#address-cells") && (of_bus_n_addr_cells(np) == 3); } /* * Array of bus specific translators */ -static struct of_bus of_busses[] = { +static const struct of_bus of_busses[] = { #ifdef CONFIG_PCI /* PCI */ { @@ -388,7 +392,7 @@ static struct of_bus of_busses[] = { }, }; -static struct of_bus *of_match_bus(struct device_node *np) +static const struct of_bus *of_match_bus(struct device_node *np) { int i; @@ -399,7 +403,7 @@ static struct of_bus *of_match_bus(struct device_node *np) return NULL; } -static int of_empty_ranges_quirk(struct device_node *np) +static int of_empty_ranges_quirk(const struct device_node *np) { if (IS_ENABLED(CONFIG_PPC)) { /* To save cycles, we cache the result for global "Mac" setting */ @@ -419,8 +423,8 @@ static int of_empty_ranges_quirk(struct device_node *np) return false; } -static int of_translate_one(struct device_node *parent, struct of_bus *bus, - struct of_bus *pbus, __be32 *addr, +static int of_translate_one(const struct device_node *parent, const struct of_bus *bus, + const struct of_bus *pbus, __be32 *addr, int na, int ns, int pna, const char *rprop) { const __be32 *ranges; @@ -455,7 +459,8 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus, } if (ranges == NULL || rlen == 0) { offset = of_read_number(addr, na); - memset(addr, 0, pna * 4); + /* set address to zero, pass flags through */ + memset(addr + pbus->flag_cells, 0, (pna - pbus->flag_cells) * 4); pr_debug("empty ranges; 1:1 translation\n"); goto finish; } @@ -505,7 +510,7 @@ static u64 __of_translate_address(struct device_node *node, { struct device_node *dev __free(device_node) = of_node_get(node); struct device_node *parent __free(device_node) = get_parent(dev); - struct of_bus *bus, *pbus; + const struct of_bus *bus, *pbus; __be32 addr[OF_MAX_ADDR_CELLS]; int na, ns, pna, pns; @@ -615,7 +620,7 @@ struct device_node *__of_get_dma_parent(const struct device_node *np) if (ret < 0) return of_get_parent(np); - return of_node_get(args.np); + return args.np; } #endif @@ -690,7 +695,7 @@ const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no, const __be32 *prop; unsigned int psize; struct device_node *parent __free(device_node) = of_get_parent(dev); - struct of_bus *bus; + const struct of_bus *bus; int onesize, i, na, ns; if (parent == NULL) @@ -701,16 +706,16 @@ const __be32 *__of_get_address(struct device_node *dev, int index, int bar_no, if (strcmp(bus->name, "pci") && (bar_no >= 0)) return NULL; - bus->count_cells(dev, &na, &ns); - if (!OF_CHECK_ADDR_COUNT(na)) - return NULL; - /* Get "reg" or "assigned-addresses" property */ prop = of_get_property(dev, bus->addresses, &psize); if (prop == NULL) return NULL; psize /= 4; + bus->count_cells(dev, &na, &ns); + if (!OF_CHECK_ADDR_COUNT(na)) + return NULL; + onesize = na + ns; for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) { u32 val = be32_to_cpu(prop[0]); @@ -1030,7 +1035,7 @@ EXPORT_SYMBOL_GPL(of_dma_is_coherent); * This is currently only enabled on builds that support Apple ARM devices, as * an optimization. */ -static bool of_mmio_is_nonposted(struct device_node *np) +static bool of_mmio_is_nonposted(const struct device_node *np) { if (!IS_ENABLED(CONFIG_ARCH_APPLE)) return false; diff --git a/drivers/of/base.c b/drivers/of/base.c index 20603d3c9931b8..6f5abea2462a32 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -87,15 +87,26 @@ static bool __of_node_is_type(const struct device_node *np, const char *type) return np && match && type && !strcmp(match, type); } +#define EXCLUDED_DEFAULT_CELLS_PLATFORMS ( \ + IS_ENABLED(CONFIG_SPARC) || \ + of_find_compatible_node(NULL, NULL, "coreboot") \ +) + int of_bus_n_addr_cells(struct device_node *np) { u32 cells; - for (; np; np = np->parent) + for (; np; np = np->parent) { if (!of_property_read_u32(np, "#address-cells", &cells)) return cells; - - /* No #address-cells property for the root node */ + /* + * Default root value and walking parent nodes for "#address-cells" + * is deprecated. Any platforms which hit this warning should + * be added to the excluded list. + */ + WARN_ONCE(!EXCLUDED_DEFAULT_CELLS_PLATFORMS, + "Missing '#address-cells' in %pOF\n", np); + } return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; } @@ -112,11 +123,17 @@ int of_bus_n_size_cells(struct device_node *np) { u32 cells; - for (; np; np = np->parent) + for (; np; np = np->parent) { if (!of_property_read_u32(np, "#size-cells", &cells)) return cells; - - /* No #size-cells property for the root node */ + /* + * Default root value and walking parent nodes for "#size-cells" + * is deprecated. Any platforms which hit this warning should + * be added to the excluded list. + */ + WARN_ONCE(!EXCLUDED_DEFAULT_CELLS_PLATFORMS, + "Missing '#size-cells' in %pOF\n", np); + } return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; } @@ -270,7 +287,7 @@ EXPORT_SYMBOL(of_find_all_nodes); const void *__of_get_property(const struct device_node *np, const char *name, int *lenp) { - struct property *pp = __of_find_property(np, name, lenp); + const struct property *pp = __of_find_property(np, name, lenp); return pp ? pp->value : NULL; } @@ -282,7 +299,7 @@ const void *__of_get_property(const struct device_node *np, const void *of_get_property(const struct device_node *np, const char *name, int *lenp) { - struct property *pp = of_find_property(np, name, lenp); + const struct property *pp = of_find_property(np, name, lenp); return pp ? pp->value : NULL; } @@ -321,7 +338,7 @@ EXPORT_SYMBOL(of_get_property); static int __of_device_is_compatible(const struct device_node *device, const char *compat, const char *type, const char *name) { - struct property *prop; + const struct property *prop; const char *cp; int index = 0, score = 0; @@ -628,6 +645,42 @@ struct device_node *of_get_next_child(const struct device_node *node, } EXPORT_SYMBOL(of_get_next_child); +/** + * of_get_next_child_with_prefix - Find the next child node with prefix + * @node: parent node + * @prev: previous child of the parent node, or NULL to get first + * @prefix: prefix that the node name should have + * + * This function is like of_get_next_child(), except that it automatically + * skips any nodes whose name doesn't have the given prefix. + * + * Return: A node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct device_node *of_get_next_child_with_prefix(const struct device_node *node, + struct device_node *prev, + const char *prefix) +{ + struct device_node *next; + unsigned long flags; + + if (!node) + return NULL; + + raw_spin_lock_irqsave(&devtree_lock, flags); + next = prev ? prev->sibling : node->child; + for (; next; next = next->sibling) { + if (!of_node_name_prefix(next, prefix)) + continue; + if (of_node_get(next)) + break; + } + of_node_put(prev); + raw_spin_unlock_irqrestore(&devtree_lock, flags); + return next; +} +EXPORT_SYMBOL(of_get_next_child_with_prefix); + static struct device_node *of_get_next_status_child(const struct device_node *node, struct device_node *prev, bool (*checker)(const struct device_node *)) @@ -771,7 +824,7 @@ struct device_node *of_get_child_by_name(const struct device_node *node, } EXPORT_SYMBOL(of_get_child_by_name); -struct device_node *__of_find_node_by_path(struct device_node *parent, +struct device_node *__of_find_node_by_path(const struct device_node *parent, const char *path) { struct device_node *child; @@ -828,7 +881,7 @@ struct device_node *__of_find_node_by_full_path(struct device_node *node, struct device_node *of_find_node_opts_by_path(const char *path, const char **opts) { struct device_node *np = NULL; - struct property *pp; + const struct property *pp; unsigned long flags; const char *separator = strchr(path, ':'); @@ -974,7 +1027,7 @@ struct device_node *of_find_node_with_property(struct device_node *from, const char *prop_name) { struct device_node *np; - struct property *pp; + const struct property *pp; unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); @@ -1455,8 +1508,10 @@ int of_parse_phandle_with_args_map(const struct device_node *np, map_len--; /* Check if not found */ - if (!new) + if (!new) { + ret = -EINVAL; goto put; + } if (!of_device_is_available(new)) match = 0; @@ -1466,17 +1521,20 @@ int of_parse_phandle_with_args_map(const struct device_node *np, goto put; /* Check for malformed properties */ - if (WARN_ON(new_size > MAX_PHANDLE_ARGS)) - goto put; - if (map_len < new_size) + if (WARN_ON(new_size > MAX_PHANDLE_ARGS) || + map_len < new_size) { + ret = -EINVAL; goto put; + } /* Move forward by new node's #-cells amount */ map += new_size; map_len -= new_size; } - if (!match) + if (!match) { + ret = -ENOENT; goto put; + } /* Get the -map-pass-thru property (optional) */ pass = of_get_property(cur, pass_name, NULL); @@ -1769,7 +1827,7 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np, */ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) { - struct property *pp; + const struct property *pp; of_aliases = of_find_node_by_path("/aliases"); of_chosen = of_find_node_by_path("/chosen"); @@ -1840,7 +1898,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) * * Return: The alias id if found. */ -int of_alias_get_id(struct device_node *np, const char *stem) +int of_alias_get_id(const struct device_node *np, const char *stem) { struct alias_prop *app; int id = -ENODEV; @@ -1898,7 +1956,7 @@ EXPORT_SYMBOL_GPL(of_alias_get_highest_id); * * Return: TRUE if console successfully setup. Otherwise return FALSE. */ -bool of_console_check(struct device_node *dn, char *name, int index) +bool of_console_check(const struct device_node *dn, char *name, int index) { if (!dn || dn != of_stdout || console_set_on_cmdline) return false; @@ -1986,7 +2044,7 @@ int of_find_last_cache_level(unsigned int cpu) * * Return: 0 on success or a standard error code on failure. */ -int of_map_id(struct device_node *np, u32 id, +int of_map_id(const struct device_node *np, u32 id, const char *map_name, const char *map_mask_name, struct device_node **target, u32 *id_out) { diff --git a/drivers/of/cpu.c b/drivers/of/cpu.c index d17b2f851082cb..5214dc3d05ae17 100644 --- a/drivers/of/cpu.c +++ b/drivers/of/cpu.c @@ -188,7 +188,7 @@ EXPORT_SYMBOL(of_cpu_node_to_id); * Return: An idle state node if found at @index. The refcount is incremented * for it, so call of_node_put() on it when done. Returns NULL if not found. */ -struct device_node *of_get_cpu_state_node(struct device_node *cpu_node, +struct device_node *of_get_cpu_state_node(const struct device_node *cpu_node, int index) { struct of_phandle_args args; diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 110104a936d9c1..0aba760f7577ef 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -536,7 +536,7 @@ static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) kfree(ce); } -static void __of_changeset_entry_invert(struct of_changeset_entry *ce, +static void __of_changeset_entry_invert(const struct of_changeset_entry *ce, struct of_changeset_entry *rce) { memcpy(rce, ce, sizeof(*rce)); @@ -636,7 +636,7 @@ static int __of_changeset_entry_apply(struct of_changeset_entry *ce) return 0; } -static inline int __of_changeset_entry_revert(struct of_changeset_entry *ce) +static inline int __of_changeset_entry_revert(const struct of_changeset_entry *ce) { struct of_changeset_entry ce_inverted; @@ -1072,3 +1072,47 @@ int of_changeset_add_prop_bool(struct of_changeset *ocs, struct device_node *np, return of_changeset_add_prop_helper(ocs, np, &prop); } EXPORT_SYMBOL_GPL(of_changeset_add_prop_bool); + +static int of_changeset_update_prop_helper(struct of_changeset *ocs, + struct device_node *np, + const struct property *pp) +{ + struct property *new_pp; + int ret; + + new_pp = __of_prop_dup(pp, GFP_KERNEL); + if (!new_pp) + return -ENOMEM; + + ret = of_changeset_update_property(ocs, np, new_pp); + if (ret) + __of_prop_free(new_pp); + + return ret; +} + +/** + * of_changeset_update_prop_string - Add a string property update to a changeset + * + * @ocs: changeset pointer + * @np: device node pointer + * @prop_name: name of the property to be updated + * @str: pointer to null terminated string + * + * Create a string property to be updated and add it to a changeset. + * + * Return: 0 on success, a negative error value in case of an error. + */ +int of_changeset_update_prop_string(struct of_changeset *ocs, + struct device_node *np, + const char *prop_name, const char *str) +{ + struct property prop = { + .name = (char *)prop_name, + .length = strlen(str) + 1, + .value = (void *)str, + }; + + return of_changeset_update_prop_helper(ocs, np, &prop); +} +EXPORT_SYMBOL_GPL(of_changeset_update_prop_string); diff --git a/drivers/of/empty_root.dts b/drivers/of/empty_root.dts index cf9e97a60f4824..cbe169ba3db52f 100644 --- a/drivers/of/empty_root.dts +++ b/drivers/of/empty_root.dts @@ -2,5 +2,12 @@ /dts-v1/; / { - + /* + * #address-cells/#size-cells are required properties at root node. + * Use 2 cells for both address cells and size cells in order to fully + * support 64-bit addresses and sizes on systems using this empty root + * node. + */ + #address-cells = <0x02>; + #size-cells = <0x02>; }; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 4d528c10df3a9a..0121100372b41d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -457,6 +457,7 @@ int __initdata dt_root_addr_cells; int __initdata dt_root_size_cells; void *initial_boot_params __ro_after_init; +phys_addr_t initial_boot_params_pa __ro_after_init; #ifdef CONFIG_OF_EARLY_FLATTREE @@ -511,8 +512,6 @@ void __init early_init_fdt_scan_reserved_mem(void) break; memblock_reserve(base, size); } - - fdt_init_reserved_mem(); } /** @@ -938,12 +937,12 @@ int __init early_init_dt_scan_root(void) dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT; prop = of_get_flat_dt_prop(node, "#size-cells", NULL); - if (prop) + if (!WARN(!prop, "No '#size-cells' in root node\n")) dt_root_size_cells = be32_to_cpup(prop); pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); prop = of_get_flat_dt_prop(node, "#address-cells", NULL); - if (prop) + if (!WARN(!prop, "No '#address-cells' in root node\n")) dt_root_addr_cells = be32_to_cpup(prop); pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); @@ -1136,17 +1135,18 @@ static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) return ptr; } -bool __init early_init_dt_verify(void *params) +bool __init early_init_dt_verify(void *dt_virt, phys_addr_t dt_phys) { - if (!params) + if (!dt_virt) return false; /* check device tree validity */ - if (fdt_check_header(params)) + if (fdt_check_header(dt_virt)) return false; /* Setup flat device-tree pointer */ - initial_boot_params = params; + initial_boot_params = dt_virt; + initial_boot_params_pa = dt_phys; of_fdt_crc32 = crc32_be(~0, initial_boot_params, fdt_totalsize(initial_boot_params)); @@ -1173,11 +1173,11 @@ void __init early_init_dt_scan_nodes(void) early_init_dt_check_for_usable_mem_range(); } -bool __init early_init_dt_scan(void *params) +bool __init early_init_dt_scan(void *dt_virt, phys_addr_t dt_phys) { bool status; - status = early_init_dt_verify(params); + status = early_init_dt_verify(dt_virt, dt_phys); if (!status) return false; @@ -1212,6 +1212,9 @@ void __init unflatten_device_tree(void) { void *fdt = initial_boot_params; + /* Save the statically-placed regions in the reserved_mem array */ + fdt_scan_reserved_mem_reg_nodes(); + /* Don't use the bootloader provided DTB if ACPI is enabled */ if (!acpi_disabled) fdt = NULL; diff --git a/drivers/of/fdt_address.c b/drivers/of/fdt_address.c index 1dc15ab78b100e..9804d7f067056a 100644 --- a/drivers/of/fdt_address.c +++ b/drivers/of/fdt_address.c @@ -55,7 +55,7 @@ static void __init fdt_bus_default_count_cells(const void *blob, int parentoffse if (prop) *addrc = be32_to_cpup(prop); else - *addrc = dt_root_addr_cells; + *addrc = -1; } if (sizec) { @@ -63,7 +63,7 @@ static void __init fdt_bus_default_count_cells(const void *blob, int parentoffse if (prop) *sizec = be32_to_cpup(prop); else - *sizec = dt_root_size_cells; + *sizec = -1; } } diff --git a/drivers/of/irq.c b/drivers/of/irq.c index a494f56a0d0ee4..98b1cf78ecac7b 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -111,6 +111,7 @@ const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len, struct of_ph else np = of_find_node_by_phandle(be32_to_cpup(imap)); imap++; + len--; /* Check if not found */ if (!np) { @@ -354,6 +355,7 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar return of_irq_parse_oldworld(device, index, out_irq); /* Get the reg property (if any) */ + addr_len = 0; addr = of_get_property(device, "reg", &addr_len); /* Prevent out-of-bounds read in case of longer interrupt parent address size */ @@ -720,7 +722,7 @@ struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 id, * Returns: the MSI domain for this device (or NULL on failure). */ struct irq_domain *of_msi_get_domain(struct device *dev, - struct device_node *np, + const struct device_node *np, enum irq_domain_bus_token token) { struct of_phandle_iterator it; @@ -742,7 +744,7 @@ EXPORT_SYMBOL_GPL(of_msi_get_domain); * @dev: device structure to associate with an MSI irq domain * @np: device node for that device */ -void of_msi_configure(struct device *dev, struct device_node *np) +void of_msi_configure(struct device *dev, const struct device_node *np) { dev_set_msi_domain(dev, of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI)); diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c index 9ccde2fd77cbf5..5b924597a4debe 100644 --- a/drivers/of/kexec.c +++ b/drivers/of/kexec.c @@ -301,7 +301,7 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image, } /* Remove memory reservation for the current device tree. */ - ret = fdt_find_and_del_mem_rsv(fdt, __pa(initial_boot_params), + ret = fdt_find_and_del_mem_rsv(fdt, initial_boot_params_pa, fdt_totalsize(initial_boot_params)); if (ret == -EINVAL) { pr_err("Error removing memory reservation.\n"); diff --git a/drivers/of/kobj.c b/drivers/of/kobj.c index 3dbce1e6f184fc..cab9b169dc67f9 100644 --- a/drivers/of/kobj.c +++ b/drivers/of/kobj.c @@ -37,7 +37,7 @@ static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, } /* always return newly allocated name, caller must free after use */ -static const char *safe_name(struct kobject *kobj, const char *orig_name) +static const char *safe_name(const struct kobject *kobj, const char *orig_name) { const char *name = orig_name; struct kernfs_node *kn; @@ -84,7 +84,7 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp) return rc; } -void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) +void __of_sysfs_remove_bin_file(struct device_node *np, const struct property *prop) { if (!IS_ENABLED(CONFIG_SYSFS)) return; @@ -93,7 +93,7 @@ void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) kfree(prop->attr.attr.name); } -void __of_remove_property_sysfs(struct device_node *np, struct property *prop) +void __of_remove_property_sysfs(struct device_node *np, const struct property *prop) { /* at early boot, bail here and defer setup to of_init() */ if (of_kset && of_node_is_attached(np)) @@ -101,7 +101,7 @@ void __of_remove_property_sysfs(struct device_node *np, struct property *prop) } void __of_update_property_sysfs(struct device_node *np, struct property *newprop, - struct property *oldprop) + const struct property *oldprop) { /* At early boot, bail out and defer setup to of_init() */ if (!of_kset) diff --git a/drivers/of/module.c b/drivers/of/module.c index 780fd82a7ecc58..1e735fc130ad3e 100644 --- a/drivers/of/module.c +++ b/drivers/of/module.c @@ -35,12 +35,10 @@ ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) str += csize; of_property_for_each_string(np, "compatible", p, compat) { - csize = strlen(compat) + 1; + csize = snprintf(str, len, "C%s", compat); tsize += csize; if (csize >= len) continue; - - csize = snprintf(str, len, "C%s", compat); for (c = str; c; ) { c = strchr(c, ' '); if (c) diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index 2ec20886d176c5..230d5f628c1b47 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c @@ -14,9 +14,6 @@ #include -/* define default numa node to 0 */ -#define DEFAULT_NODE 0 - /* * Even though we connect cpus to numa domains later in SMP * init, we need to know the node ids now for all cpus. diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index c235d6c909a16a..ea5a0951ec5e10 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -9,6 +9,7 @@ */ #define FDT_ALIGN_SIZE 8 +#define MAX_RESERVED_REGIONS 64 /** * struct alias_prop - Alias property in 'aliases' node @@ -72,9 +73,9 @@ static inline void of_platform_register_reconfig_notifier(void) { } #if defined(CONFIG_OF_KOBJ) int of_node_is_attached(const struct device_node *node); int __of_add_property_sysfs(struct device_node *np, struct property *pp); -void __of_remove_property_sysfs(struct device_node *np, struct property *prop); +void __of_remove_property_sysfs(struct device_node *np, const struct property *prop); void __of_update_property_sysfs(struct device_node *np, struct property *newprop, - struct property *oldprop); + const struct property *oldprop); int __of_attach_node_sysfs(struct device_node *np); void __of_detach_node_sysfs(struct device_node *np); #else @@ -82,9 +83,9 @@ static inline int __of_add_property_sysfs(struct device_node *np, struct propert { return 0; } -static inline void __of_remove_property_sysfs(struct device_node *np, struct property *prop) {} +static inline void __of_remove_property_sysfs(struct device_node *np, const struct property *prop) {} static inline void __of_update_property_sysfs(struct device_node *np, - struct property *newprop, struct property *oldprop) {} + struct property *newprop, const struct property *oldprop) {} static inline int __of_attach_node_sysfs(struct device_node *np) { return 0; @@ -130,7 +131,7 @@ void __of_prop_free(struct property *prop); struct device_node *__of_node_dup(const struct device_node *np, const char *full_name); -struct device_node *__of_find_node_by_path(struct device_node *parent, +struct device_node *__of_find_node_by_path(const struct device_node *parent, const char *path); struct device_node *__of_find_node_by_full_path(struct device_node *node, const char *path); @@ -145,7 +146,7 @@ extern int __of_update_property(struct device_node *np, extern void __of_detach_node(struct device_node *np); extern void __of_sysfs_remove_bin_file(struct device_node *np, - struct property *prop); + const struct property *prop); /* illegal phandle value (set when unresolved) */ #define OF_PHANDLE_ILLEGAL 0xdeadbeef @@ -183,7 +184,7 @@ static inline struct device_node *__of_get_dma_parent(const struct device_node * #endif int fdt_scan_reserved_mem(void); -void fdt_init_reserved_mem(void); +void __init fdt_scan_reserved_mem_reg_nodes(void); bool of_fdt_device_is_available(const void *blob, unsigned long node); diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 46e1c3fbc7692c..45517b9e57b1ad 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -27,8 +27,9 @@ #include "of_private.h" -#define MAX_RESERVED_REGIONS 64 -static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; +static struct reserved_mem reserved_mem_array[MAX_RESERVED_REGIONS] __initdata; +static struct reserved_mem *reserved_mem __refdata = reserved_mem_array; +static int total_reserved_mem_cnt = MAX_RESERVED_REGIONS; static int reserved_mem_count; static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, @@ -56,6 +57,51 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, return err; } +/* + * alloc_reserved_mem_array() - allocate memory for the reserved_mem + * array using memblock + * + * This function is used to allocate memory for the reserved_mem + * array according to the total number of reserved memory regions + * defined in the DT. + * After the new array is allocated, the information stored in + * the initial static array is copied over to this new array and + * the new array is used from this point on. + */ +static void __init alloc_reserved_mem_array(void) +{ + struct reserved_mem *new_array; + size_t alloc_size, copy_size, memset_size; + + alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array)); + if (alloc_size == SIZE_MAX) { + pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW); + return; + } + + new_array = memblock_alloc(alloc_size, SMP_CACHE_BYTES); + if (!new_array) { + pr_err("Failed to allocate memory for reserved_mem array with err: %d", -ENOMEM); + return; + } + + copy_size = array_size(reserved_mem_count, sizeof(*new_array)); + if (copy_size == SIZE_MAX) { + memblock_free(new_array, alloc_size); + total_reserved_mem_cnt = MAX_RESERVED_REGIONS; + pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW); + return; + } + + memset_size = alloc_size - copy_size; + + memcpy(new_array, reserved_mem, copy_size); + memset(new_array + reserved_mem_count, 0, memset_size); + + reserved_mem = new_array; +} + +static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem); /* * fdt_reserved_mem_save_node() - save fdt node for second pass initialization */ @@ -64,7 +110,7 @@ static void __init fdt_reserved_mem_save_node(unsigned long node, const char *un { struct reserved_mem *rmem = &reserved_mem[reserved_mem_count]; - if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) { + if (reserved_mem_count == total_reserved_mem_cnt) { pr_err("not enough space for all defined regions.\n"); return; } @@ -74,6 +120,9 @@ static void __init fdt_reserved_mem_save_node(unsigned long node, const char *un rmem->base = base; rmem->size = size; + /* Call the region specific initialization function */ + fdt_init_reserved_mem_node(rmem); + reserved_mem_count++; return; } @@ -106,7 +155,6 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, phys_addr_t base, size; int len; const __be32 *prop; - int first = 1; bool nomap; prop = of_get_flat_dt_prop(node, "reg", &len); @@ -134,10 +182,6 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, uname, &base, (unsigned long)(size / SZ_1M)); len -= t_len; - if (first) { - fdt_reserved_mem_save_node(node, uname, base, size); - first = 0; - } } return 0; } @@ -165,12 +209,80 @@ static int __init __reserved_mem_check_root(unsigned long node) return 0; } +static void __init __rmem_check_for_overlap(void); + +/** + * fdt_scan_reserved_mem_reg_nodes() - Store info for the "reg" defined + * reserved memory regions. + * + * This function is used to scan through the DT and store the + * information for the reserved memory regions that are defined using + * the "reg" property. The region node number, name, base address, and + * size are all stored in the reserved_mem array by calling the + * fdt_reserved_mem_save_node() function. + */ +void __init fdt_scan_reserved_mem_reg_nodes(void) +{ + int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); + const void *fdt = initial_boot_params; + phys_addr_t base, size; + const __be32 *prop; + int node, child; + int len; + + if (!fdt) + return; + + node = fdt_path_offset(fdt, "/reserved-memory"); + if (node < 0) { + pr_info("Reserved memory: No reserved-memory node in the DT\n"); + return; + } + + /* Attempt dynamic allocation of a new reserved_mem array */ + alloc_reserved_mem_array(); + + if (__reserved_mem_check_root(node)) { + pr_err("Reserved memory: unsupported node format, ignoring\n"); + return; + } + + fdt_for_each_subnode(child, fdt, node) { + const char *uname; + + prop = of_get_flat_dt_prop(child, "reg", &len); + if (!prop) + continue; + if (!of_fdt_device_is_available(fdt, child)) + continue; + + uname = fdt_get_name(fdt, child, NULL); + if (len && len % t_len != 0) { + pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n", + uname); + continue; + } + base = dt_mem_next_cell(dt_root_addr_cells, &prop); + size = dt_mem_next_cell(dt_root_size_cells, &prop); + + if (size) + fdt_reserved_mem_save_node(child, uname, base, size); + } + + /* check for overlapping reserved regions */ + __rmem_check_for_overlap(); +} + +static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname); + /* * fdt_scan_reserved_mem() - scan a single FDT node for reserved memory */ int __init fdt_scan_reserved_mem(void) { int node, child; + int dynamic_nodes_cnt = 0, count = 0; + int dynamic_nodes[MAX_RESERVED_REGIONS]; const void *fdt = initial_boot_params; node = fdt_path_offset(fdt, "/reserved-memory"); @@ -192,9 +304,31 @@ int __init fdt_scan_reserved_mem(void) uname = fdt_get_name(fdt, child, NULL); err = __reserved_mem_reserve_reg(child, uname); - if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) - fdt_reserved_mem_save_node(child, uname, 0, 0); + if (!err) + count++; + /* + * Save the nodes for the dynamically-placed regions + * into an array which will be used for allocation right + * after all the statically-placed regions are reserved + * or marked as no-map. This is done to avoid dynamically + * allocating from one of the statically-placed regions. + */ + if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) { + dynamic_nodes[dynamic_nodes_cnt] = child; + dynamic_nodes_cnt++; + } } + for (int i = 0; i < dynamic_nodes_cnt; i++) { + const char *uname; + int err; + + child = dynamic_nodes[i]; + uname = fdt_get_name(fdt, child, NULL); + err = __reserved_mem_alloc_size(child, uname); + if (!err) + count++; + } + total_reserved_mem_cnt = count; return 0; } @@ -253,8 +387,7 @@ static int __init __reserved_mem_alloc_in_range(phys_addr_t size, * __reserved_mem_alloc_size() - allocate reserved memory described by * 'size', 'alignment' and 'alloc-ranges' properties. */ -static int __init __reserved_mem_alloc_size(unsigned long node, - const char *uname, phys_addr_t *res_base, phys_addr_t *res_size) +static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname) { int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32); phys_addr_t start = 0, end = 0; @@ -334,9 +467,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node, return -ENOMEM; } - *res_base = base; - *res_size = size; - + /* Save region in the reserved_mem array */ + fdt_reserved_mem_save_node(node, uname, base, size); return 0; } @@ -425,48 +557,37 @@ static void __init __rmem_check_for_overlap(void) } /** - * fdt_init_reserved_mem() - allocate and init all saved reserved memory regions + * fdt_init_reserved_mem_node() - Initialize a reserved memory region + * @rmem: reserved_mem struct of the memory region to be initialized. + * + * This function is used to call the region specific initialization + * function for a reserved memory region. */ -void __init fdt_init_reserved_mem(void) +static void __init fdt_init_reserved_mem_node(struct reserved_mem *rmem) { - int i; - - /* check for overlapping reserved regions */ - __rmem_check_for_overlap(); - - for (i = 0; i < reserved_mem_count; i++) { - struct reserved_mem *rmem = &reserved_mem[i]; - unsigned long node = rmem->fdt_node; - int err = 0; - bool nomap; + unsigned long node = rmem->fdt_node; + int err = 0; + bool nomap; - nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; + nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; - if (rmem->size == 0) - err = __reserved_mem_alloc_size(node, rmem->name, - &rmem->base, &rmem->size); - if (err == 0) { - err = __reserved_mem_init_node(rmem); - if (err != 0 && err != -ENOENT) { - pr_info("node %s compatible matching fail\n", - rmem->name); - if (nomap) - memblock_clear_nomap(rmem->base, rmem->size); - else - memblock_phys_free(rmem->base, - rmem->size); - } else { - phys_addr_t end = rmem->base + rmem->size - 1; - bool reusable = - (of_get_flat_dt_prop(node, "reusable", NULL)) != NULL; - - pr_info("%pa..%pa (%lu KiB) %s %s %s\n", - &rmem->base, &end, (unsigned long)(rmem->size / SZ_1K), - nomap ? "nomap" : "map", - reusable ? "reusable" : "non-reusable", - rmem->name ? rmem->name : "unknown"); - } - } + err = __reserved_mem_init_node(rmem); + if (err != 0 && err != -ENOENT) { + pr_info("node %s compatible matching fail\n", rmem->name); + if (nomap) + memblock_clear_nomap(rmem->base, rmem->size); + else + memblock_phys_free(rmem->base, rmem->size); + } else { + phys_addr_t end = rmem->base + rmem->size - 1; + bool reusable = + (of_get_flat_dt_prop(node, "reusable", NULL)) != NULL; + + pr_info("%pa..%pa (%lu KiB) %s %s %s\n", + &rmem->base, &end, (unsigned long)(rmem->size / SZ_1K), + nomap ? "nomap" : "map", + reusable ? "reusable" : "non-reusable", + rmem->name ? rmem->name : "unknown"); } } diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index cbdecccca09745..434f6dd6a86c1f 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -296,10 +296,11 @@ static struct property *dup_and_fixup_symbol_prop( * invalid @overlay. */ static int add_changeset_property(struct overlay_changeset *ovcs, - struct target *target, struct property *overlay_prop, + struct target *target, const struct property *overlay_prop, bool is_symbols_prop) { - struct property *new_prop = NULL, *prop; + struct property *new_prop = NULL; + const struct property *prop; int ret = 0; if (target->in_livetree) @@ -398,7 +399,7 @@ static int add_changeset_property(struct overlay_changeset *ovcs, * invalid @overlay. */ static int add_changeset_node(struct overlay_changeset *ovcs, - struct target *target, struct device_node *node) + struct target *target, const struct device_node *node) { const char *node_kbasename; const __be32 *phandle; @@ -675,8 +676,8 @@ static int build_changeset(struct overlay_changeset *ovcs) * 1) "target" property containing the phandle of the target * 2) "target-path" property containing the path of the target */ -static struct device_node *find_target(struct device_node *info_node, - struct device_node *target_base) +static struct device_node *find_target(const struct device_node *info_node, + const struct device_node *target_base) { struct device_node *node; char *target_path; @@ -735,7 +736,7 @@ static struct device_node *find_target(struct device_node *info_node, * init_overlay_changeset() must call free_overlay_changeset(). */ static int init_overlay_changeset(struct overlay_changeset *ovcs, - struct device_node *target_base) + const struct device_node *target_base) { struct device_node *node, *overlay_node; struct fragment *fragment; @@ -910,7 +911,7 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs) */ static int of_overlay_apply(struct overlay_changeset *ovcs, - struct device_node *base) + const struct device_node *base) { int ret = 0, ret_revert, ret_tmp; @@ -978,7 +979,7 @@ static int of_overlay_apply(struct overlay_changeset *ovcs, */ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, - int *ret_ovcs_id, struct device_node *base) + int *ret_ovcs_id, const struct device_node *base) { void *new_fdt; void *new_fdt_align; @@ -1074,7 +1075,7 @@ EXPORT_SYMBOL_GPL(of_overlay_fdt_apply); * * Returns 1 if @np is @tree or is contained in @tree, else 0 */ -static int find_node(struct device_node *tree, struct device_node *np) +static int find_node(const struct device_node *tree, struct device_node *np) { if (tree == np) return 1; diff --git a/drivers/of/overlay_test.c b/drivers/of/overlay_test.c index 1f76d50fb16a52..c787524c5a887c 100644 --- a/drivers/of/overlay_test.c +++ b/drivers/of/overlay_test.c @@ -65,6 +65,8 @@ static void of_overlay_apply_kunit_cleanup(struct kunit *test) struct device_node *np; of_root_kunit_skip(test); + if (!IS_ENABLED(CONFIG_OF_OVERLAY)) + kunit_skip(test, "requires CONFIG_OF_OVERLAY to apply overlay"); if (!IS_ENABLED(CONFIG_OF_EARLY_FLATTREE)) kunit_skip(test, "requires CONFIG_OF_EARLY_FLATTREE for root node"); diff --git a/drivers/of/property.c b/drivers/of/property.c index 11b922fde7af16..cfc8aea002e439 100644 --- a/drivers/of/property.c +++ b/drivers/of/property.c @@ -68,7 +68,7 @@ EXPORT_SYMBOL(of_graph_is_present); int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size) { - struct property *prop = of_find_property(np, propname, NULL); + const struct property *prop = of_find_property(np, propname, NULL); if (!prop) return -EINVAL; @@ -104,7 +104,7 @@ EXPORT_SYMBOL_GPL(of_property_count_elems_of_size); static void *of_find_property_value_of_size(const struct device_node *np, const char *propname, u32 min, u32 max, size_t *len) { - struct property *prop = of_find_property(np, propname, NULL); + const struct property *prop = of_find_property(np, propname, NULL); if (!prop) return ERR_PTR(-EINVAL); @@ -530,7 +530,7 @@ int of_property_read_string_helper(const struct device_node *np, } EXPORT_SYMBOL_GPL(of_property_read_string_helper); -const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, +const __be32 *of_prop_next_u32(const struct property *prop, const __be32 *cur, u32 *pu) { const void *curv = cur; @@ -553,7 +553,7 @@ const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, } EXPORT_SYMBOL_GPL(of_prop_next_u32); -const char *of_prop_next_string(struct property *prop, const char *cur) +const char *of_prop_next_string(const struct property *prop, const char *cur) { const void *curv = cur; @@ -630,6 +630,70 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) } EXPORT_SYMBOL(of_graph_get_port_by_id); +/** + * of_graph_get_next_port() - get next port node. + * @parent: pointer to the parent device node, or parent ports node + * @prev: previous port node, or NULL to get first + * + * Parent device node can be used as @parent whether device node has ports node + * or not. It will work same as ports@0 node. + * + * Return: A 'port' node pointer with refcount incremented. Refcount + * of the passed @prev node is decremented. + */ +struct device_node *of_graph_get_next_port(const struct device_node *parent, + struct device_node *prev) +{ + if (!parent) + return NULL; + + if (!prev) { + struct device_node *node __free(device_node) = + of_get_child_by_name(parent, "ports"); + + if (node) + parent = node; + + return of_get_child_by_name(parent, "port"); + } + + do { + prev = of_get_next_child(parent, prev); + if (!prev) + break; + } while (!of_node_name_eq(prev, "port")); + + return prev; +} +EXPORT_SYMBOL(of_graph_get_next_port); + +/** + * of_graph_get_next_port_endpoint() - get next endpoint node in port. + * If it reached to end of the port, it will return NULL. + * @port: pointer to the target port node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is decremented. + */ +struct device_node *of_graph_get_next_port_endpoint(const struct device_node *port, + struct device_node *prev) +{ + while (1) { + prev = of_get_next_child(port, prev); + if (!prev) + break; + if (WARN(!of_node_name_eq(prev, "endpoint"), + "non endpoint node is used (%pOF)", prev)) + continue; + + break; + } + + return prev; +} +EXPORT_SYMBOL(of_graph_get_next_port_endpoint); + /** * of_graph_get_next_endpoint() - get next endpoint node * @parent: pointer to the parent device node @@ -653,13 +717,7 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, * parent port node. */ if (!prev) { - struct device_node *node __free(device_node) = - of_get_child_by_name(parent, "ports"); - - if (node) - parent = node; - - port = of_get_child_by_name(parent, "port"); + port = of_graph_get_next_port(parent, NULL); if (!port) { pr_debug("graph: no port node found in %pOF\n", parent); return NULL; @@ -677,7 +735,7 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, * getting the next child. If the previous endpoint is NULL this * will return the first child. */ - endpoint = of_get_next_child(port, prev); + endpoint = of_graph_get_next_port_endpoint(port, prev); if (endpoint) { of_node_put(port); return endpoint; @@ -686,11 +744,9 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, /* No more endpoints under this port, try the next one. */ prev = NULL; - do { - port = of_get_next_child(parent, port); - if (!port) - return NULL; - } while (!of_node_name_eq(port, "port")); + port = of_graph_get_next_port(parent, port); + if (!port) + return NULL; } } EXPORT_SYMBOL(of_graph_get_next_endpoint); @@ -823,6 +879,23 @@ unsigned int of_graph_get_endpoint_count(const struct device_node *np) } EXPORT_SYMBOL(of_graph_get_endpoint_count); +/** + * of_graph_get_port_count() - get the number of port in a device or ports node + * @np: pointer to the device or ports node + * + * Return: count of port of this device or ports node + */ +unsigned int of_graph_get_port_count(struct device_node *np) +{ + unsigned int num = 0; + + for_each_of_graph_port(np, port) + num++; + + return num; +} +EXPORT_SYMBOL(of_graph_get_port_count); + /** * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint * @node: pointer to parent device_node containing graph port/endpoint @@ -1213,7 +1286,6 @@ DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells") DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells") DEFINE_SIMPLE_PROP(io_channels, "io-channels", "#io-channel-cells") DEFINE_SIMPLE_PROP(io_backends, "io-backends", "#io-backend-cells") -DEFINE_SIMPLE_PROP(interrupt_parent, "interrupt-parent", NULL) DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells") DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells") DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells") @@ -1359,7 +1431,6 @@ static const struct supplier_bindings of_supplier_bindings[] = { { .parse_prop = parse_mboxes, }, { .parse_prop = parse_io_channels, }, { .parse_prop = parse_io_backends, }, - { .parse_prop = parse_interrupt_parent, }, { .parse_prop = parse_dmas, .optional = true, }, { .parse_prop = parse_power_domains, }, { .parse_prop = parse_hwlocks, }, @@ -1466,7 +1537,7 @@ static int of_fwnode_irq_get(const struct fwnode_handle *fwnode, static int of_fwnode_add_links(struct fwnode_handle *fwnode) { - struct property *p; + const struct property *p; struct device_node *con_np = to_of_node(fwnode); if (IS_ENABLED(CONFIG_X86)) diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 5cf96776dd7d31..779db058c42f5b 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -42,7 +42,7 @@ static void adjust_overlay_phandles(struct device_node *overlay, int phandle_delta) { struct device_node *child; - struct property *prop; + const struct property *prop; phandle phandle; /* adjust node's phandle in node */ @@ -71,10 +71,10 @@ static void adjust_overlay_phandles(struct device_node *overlay, } static int update_usages_of_a_phandle_reference(struct device_node *overlay, - struct property *prop_fixup, phandle phandle) + const struct property *prop_fixup, phandle phandle) { struct device_node *refnode; - struct property *prop; + const struct property *prop; char *value __free(kfree) = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL); char *cur, *end, *node_path, *prop_name, *s; int offset, len; @@ -147,11 +147,11 @@ static int node_name_cmp(const struct device_node *dn1, * of offsets of the phandle reference(s) within the respective property * value(s). The values at these offsets will be fixed up. */ -static int adjust_local_phandle_references(struct device_node *local_fixups, - struct device_node *overlay, int phandle_delta) +static int adjust_local_phandle_references(const struct device_node *local_fixups, + const struct device_node *overlay, int phandle_delta) { struct device_node *overlay_child; - struct property *prop_fix, *prop; + const struct property *prop_fix, *prop; int err, i, count; unsigned int off; diff --git a/drivers/of/unittest-data/tests-address.dtsi b/drivers/of/unittest-data/tests-address.dtsi index 3344f15c3755cd..f02a181bb12593 100644 --- a/drivers/of/unittest-data/tests-address.dtsi +++ b/drivers/of/unittest-data/tests-address.dtsi @@ -114,6 +114,7 @@ pcie@d1070000 { device_type = "pci"; ranges = <0x82000000 0 0xe8000000 0 0xe8000000 0 0x7f00000>, <0x81000000 0 0x00000000 0 0xefff0000 0 0x0010000>; + dma-ranges = <0x43000000 0x10 0x00 0x00 0x00 0x00 0x10000000>; reg = <0x00000000 0xd1070000 0x20000>; pci@0,0 { @@ -142,6 +143,7 @@ local-bus@0 { #size-cells = <0x01>; ranges = <0xa0000000 0 0 0 0x2000000>, <0xb0000000 1 0 0 0x1000000>; + dma-ranges = <0xc0000000 0x43000000 0x10 0x00 0x10000000>; dev@e0000000 { reg = <0xa0001000 0x1000>, diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index daf9a2dddd7e0d..438fd70fa99500 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1213,6 +1213,44 @@ static void __init of_unittest_pci_dma_ranges(void) of_node_put(np); } +static void __init of_unittest_pci_empty_dma_ranges(void) +{ + struct device_node *np; + struct of_pci_range range; + struct of_pci_range_parser parser; + + if (!IS_ENABLED(CONFIG_PCI)) + return; + + np = of_find_node_by_path("/testcase-data/address-tests2/pcie@d1070000/pci@0,0/dev@0,0/local-bus@0"); + if (!np) { + pr_err("missing testcase data\n"); + return; + } + + if (of_pci_dma_range_parser_init(&parser, np)) { + pr_err("missing dma-ranges property\n"); + return; + } + + /* + * Get the dma-ranges from the device tree + */ + for_each_of_pci_range(&parser, &range) { + unittest(range.size == 0x10000000, + "for_each_of_pci_range wrong size on node %pOF size=%llx\n", + np, range.size); + unittest(range.cpu_addr == 0x00000000, + "for_each_of_pci_range wrong CPU addr (%llx) on node %pOF", + range.cpu_addr, np); + unittest(range.pci_addr == 0xc0000000, + "for_each_of_pci_range wrong DMA addr (%llx) on node %pOF", + range.pci_addr, np); + } + + of_node_put(np); +} + static void __init of_unittest_bus_ranges(void) { struct device_node *np; @@ -1970,7 +2008,7 @@ static const struct of_device_id unittest_match[] = { static struct platform_driver unittest_driver = { .probe = unittest_probe, - .remove_new = unittest_remove, + .remove = unittest_remove, .driver = { .name = "unittest", .of_match_table = unittest_match, @@ -2071,7 +2109,7 @@ static const struct of_device_id unittest_gpio_id[] = { static struct platform_driver unittest_gpio_driver = { .probe = unittest_gpio_probe, - .remove_new = unittest_gpio_remove, + .remove = unittest_gpio_remove, .driver = { .name = "unittest-gpio", .of_match_table = unittest_gpio_id, @@ -2891,7 +2929,7 @@ static const struct of_device_id unittest_i2c_bus_match[] = { static struct platform_driver unittest_i2c_bus_driver = { .probe = unittest_i2c_bus_probe, - .remove_new = unittest_i2c_bus_remove, + .remove = unittest_i2c_bus_remove, .driver = { .name = "unittest-i2c-bus", .of_match_table = unittest_i2c_bus_match, @@ -4272,6 +4310,7 @@ static int __init of_unittest(void) of_unittest_dma_get_max_cpu_address(); of_unittest_parse_dma_ranges(); of_unittest_pci_dma_ranges(); + of_unittest_pci_empty_dma_ranges(); of_unittest_bus_ranges(); of_unittest_bus_3cell_ranges(); of_unittest_reg(); diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 3aa18737470fa2..0311b18319a458 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -2360,48 +2360,13 @@ static void _opp_put_config_regulators_helper(struct opp_table *opp_table) opp_table->config_regulators = NULL; } -static void _opp_detach_genpd(struct opp_table *opp_table) +static int _opp_set_required_dev(struct opp_table *opp_table, + struct device *dev, + struct device *required_dev, + unsigned int index) { - int index; - - for (index = 0; index < opp_table->required_opp_count; index++) { - if (!opp_table->required_devs[index]) - continue; - - dev_pm_domain_detach(opp_table->required_devs[index], false); - opp_table->required_devs[index] = NULL; - } -} - -/* - * Multiple generic power domains for a device are supported with the help of - * virtual genpd devices, which are created for each consumer device - genpd - * pair. These are the device structures which are attached to the power domain - * and are required by the OPP core to set the performance state of the genpd. - * The same API also works for the case where single genpd is available and so - * we don't need to support that separately. - * - * This helper will normally be called by the consumer driver of the device - * "dev", as only that has details of the genpd names. - * - * This helper needs to be called once with a list of all genpd to attach. - * Otherwise the original device structure will be used instead by the OPP core. - * - * The order of entries in the names array must match the order in which - * "required-opps" are added in DT. - */ -static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev, - const char * const *names, struct device ***virt_devs) -{ - struct device *virt_dev, *gdev; - struct opp_table *genpd_table; - int index = 0, ret = -EINVAL; - const char * const *name = names; - - if (!opp_table->required_devs) { - dev_err(dev, "Required OPPs not available, can't attach genpd\n"); - return -EINVAL; - } + struct opp_table *required_table, *pd_table; + struct device *gdev; /* Genpd core takes care of propagation to parent genpd */ if (opp_table->is_genpd) { @@ -2409,114 +2374,59 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev, return -EOPNOTSUPP; } - /* Checking only the first one is enough ? */ - if (opp_table->required_devs[0]) - return 0; - - while (*name) { - if (index >= opp_table->required_opp_count) { - dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n", - *name, opp_table->required_opp_count, index); - goto err; - } - - virt_dev = dev_pm_domain_attach_by_name(dev, *name); - if (IS_ERR_OR_NULL(virt_dev)) { - ret = virt_dev ? PTR_ERR(virt_dev) : -ENODEV; - dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret); - goto err; - } - - /* - * The required_opp_tables parsing is not perfect, as the OPP - * core does the parsing solely based on the DT node pointers. - * The core sets the required_opp_tables entry to the first OPP - * table in the "opp_tables" list, that matches with the node - * pointer. - * - * If the target DT OPP table is used by multiple devices and - * they all create separate instances of 'struct opp_table' from - * it, then it is possible that the required_opp_tables entry - * may be set to the incorrect sibling device. - * - * Cross check it again and fix if required. - */ - gdev = dev_to_genpd_dev(virt_dev); - if (IS_ERR(gdev)) { - ret = PTR_ERR(gdev); - goto err; - } - - genpd_table = _find_opp_table(gdev); - if (!IS_ERR(genpd_table)) { - if (genpd_table != opp_table->required_opp_tables[index]) { - dev_pm_opp_put_opp_table(opp_table->required_opp_tables[index]); - opp_table->required_opp_tables[index] = genpd_table; - } else { - dev_pm_opp_put_opp_table(genpd_table); - } - } - - opp_table->required_devs[index] = virt_dev; - index++; - name++; - } - - if (virt_devs) - *virt_devs = opp_table->required_devs; - - return 0; - -err: - _opp_detach_genpd(opp_table); - return ret; - -} - -static int _opp_set_required_devs(struct opp_table *opp_table, - struct device *dev, - struct device **required_devs) -{ - int i; - - if (!opp_table->required_devs) { + if (index >= opp_table->required_opp_count) { dev_err(dev, "Required OPPs not available, can't set required devs\n"); return -EINVAL; } - /* Another device that shares the OPP table has set the required devs ? */ - if (opp_table->required_devs[0]) - return 0; + required_table = opp_table->required_opp_tables[index]; + if (IS_ERR(required_table)) { + dev_err(dev, "Missing OPP table, unable to set the required devs\n"); + return -ENODEV; + } - for (i = 0; i < opp_table->required_opp_count; i++) { - /* Genpd core takes care of propagation to parent genpd */ - if (required_devs[i] && opp_table->is_genpd && - opp_table->required_opp_tables[i]->is_genpd) { - dev_err(dev, "%s: Operation not supported for genpds\n", __func__); - return -EOPNOTSUPP; + /* + * The required_opp_tables parsing is not perfect, as the OPP core does + * the parsing solely based on the DT node pointers. The core sets the + * required_opp_tables entry to the first OPP table in the "opp_tables" + * list, that matches with the node pointer. + * + * If the target DT OPP table is used by multiple devices and they all + * create separate instances of 'struct opp_table' from it, then it is + * possible that the required_opp_tables entry may be set to the + * incorrect sibling device. + * + * Cross check it again and fix if required. + */ + gdev = dev_to_genpd_dev(required_dev); + if (IS_ERR(gdev)) + return PTR_ERR(gdev); + + pd_table = _find_opp_table(gdev); + if (!IS_ERR(pd_table)) { + if (pd_table != required_table) { + dev_pm_opp_put_opp_table(required_table); + opp_table->required_opp_tables[index] = pd_table; + } else { + dev_pm_opp_put_opp_table(pd_table); } - - opp_table->required_devs[i] = required_devs[i]; } + opp_table->required_devs[index] = required_dev; return 0; } -static void _opp_put_required_devs(struct opp_table *opp_table) +static void _opp_put_required_dev(struct opp_table *opp_table, + unsigned int index) { - int i; - - for (i = 0; i < opp_table->required_opp_count; i++) - opp_table->required_devs[i] = NULL; + opp_table->required_devs[index] = NULL; } static void _opp_clear_config(struct opp_config_data *data) { - if (data->flags & OPP_CONFIG_REQUIRED_DEVS) - _opp_put_required_devs(data->opp_table); - else if (data->flags & OPP_CONFIG_GENPD) - _opp_detach_genpd(data->opp_table); - + if (data->flags & OPP_CONFIG_REQUIRED_DEV) + _opp_put_required_dev(data->opp_table, + data->required_dev_index); if (data->flags & OPP_CONFIG_REGULATOR) _opp_put_regulators(data->opp_table); if (data->flags & OPP_CONFIG_SUPPORTED_HW) @@ -2628,26 +2538,15 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config) data->flags |= OPP_CONFIG_REGULATOR; } - /* Attach genpds */ - if (config->genpd_names) { - if (config->required_devs) { - ret = -EINVAL; - goto err; - } - - ret = _opp_attach_genpd(opp_table, dev, config->genpd_names, - config->virt_devs); - if (ret) - goto err; - - data->flags |= OPP_CONFIG_GENPD; - } else if (config->required_devs) { - ret = _opp_set_required_devs(opp_table, dev, - config->required_devs); + if (config->required_dev) { + ret = _opp_set_required_dev(opp_table, dev, + config->required_dev, + config->required_dev_index); if (ret) goto err; - data->flags |= OPP_CONFIG_REQUIRED_DEVS; + data->required_dev_index = config->required_dev_index; + data->flags |= OPP_CONFIG_REQUIRED_DEV; } ret = xa_alloc(&opp_configs, &id, data, XA_LIMIT(1, INT_MAX), diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 55c8cfef97d489..fd5ed285825881 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -295,7 +295,7 @@ void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp) of_node_put(opp->np); } -static int _link_required_opps(struct dev_pm_opp *opp, struct opp_table *opp_table, +static int _link_required_opps(struct dev_pm_opp *opp, struct opp_table *required_table, int index) { struct device_node *np; @@ -313,39 +313,6 @@ static int _link_required_opps(struct dev_pm_opp *opp, struct opp_table *opp_tab return -ENODEV; } - /* - * There are two genpd (as required-opp) cases that we need to handle, - * devices with a single genpd and ones with multiple genpds. - * - * The single genpd case requires special handling as we need to use the - * same `dev` structure (instead of a virtual one provided by genpd - * core) for setting the performance state. - * - * It doesn't make sense for a device's DT entry to have both - * "opp-level" and single "required-opps" entry pointing to a genpd's - * OPP, as that would make the OPP core call - * dev_pm_domain_set_performance_state() for two different values for - * the same device structure. Lets treat single genpd configuration as a - * case where the OPP's level is directly available without required-opp - * link in the DT. - * - * Just update the `level` with the right value, which - * dev_pm_opp_set_opp() will take care of in the normal path itself. - * - * There is another case though, where a genpd's OPP table has - * required-opps set to a parent genpd. The OPP core expects the user to - * set the respective required `struct device` pointer via - * dev_pm_opp_set_config(). - */ - if (required_table->is_genpd && opp_table->required_opp_count == 1 && - !opp_table->required_devs[0]) { - /* Genpd core takes care of propagation to parent genpd */ - if (!opp_table->is_genpd) { - if (!WARN_ON(opp->level != OPP_LEVEL_UNSET)) - opp->level = opp->required_opps[0]->level; - } - } - return 0; } @@ -370,7 +337,7 @@ static int _of_opp_alloc_required_opps(struct opp_table *opp_table, if (IS_ERR_OR_NULL(required_table)) continue; - ret = _link_required_opps(opp, opp_table, required_table, i); + ret = _link_required_opps(opp, required_table, i); if (ret) goto free_required_opps; } @@ -391,7 +358,7 @@ static int lazy_link_required_opps(struct opp_table *opp_table, int ret; list_for_each_entry(opp, &opp_table->opp_list, node) { - ret = _link_required_opps(opp, opp_table, new_table, index); + ret = _link_required_opps(opp, new_table, index); if (ret) return ret; } diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index cff1fabd1ae366..430651e7424aac 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -34,13 +34,13 @@ extern struct list_head opp_tables; #define OPP_CONFIG_REGULATOR_HELPER BIT(2) #define OPP_CONFIG_PROP_NAME BIT(3) #define OPP_CONFIG_SUPPORTED_HW BIT(4) -#define OPP_CONFIG_GENPD BIT(5) -#define OPP_CONFIG_REQUIRED_DEVS BIT(6) +#define OPP_CONFIG_REQUIRED_DEV BIT(5) /** * struct opp_config_data - data for set config operations * @opp_table: OPP table * @flags: OPP config flags + * @required_dev_index: The position in the array of required_devs * * This structure stores the OPP config information for each OPP table * configuration by the callers. @@ -48,6 +48,7 @@ extern struct list_head opp_tables; struct opp_config_data { struct opp_table *opp_table; unsigned int flags; + unsigned int required_dev_index; }; /** @@ -262,9 +263,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *o int _opp_add_v1(struct opp_table *opp_table, struct device *dev, struct dev_pm_opp_data *data, bool dynamic); void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu); struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk); -void _put_opp_list_kref(struct opp_table *opp_table); void _required_opps_available(struct dev_pm_opp *opp, int count); -void _update_set_required_opps(struct opp_table *opp_table); static inline bool lazy_linking_pending(struct opp_table *opp_table) { diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index b49cb010a4d80c..e71674753711ee 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -369,7 +369,7 @@ MODULE_ALIAS("platform:platform-leds"); static struct platform_driver hppa_mainboard_led_driver = { .probe = platform_led_probe, - .remove_new = platform_led_remove, + .remove = platform_led_remove, .driver = { .name = "platform-leds", }, diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c index e06c7b2aac5c46..6a819bd0086618 100644 --- a/drivers/parport/parport_amiga.c +++ b/drivers/parport/parport_amiga.c @@ -236,7 +236,7 @@ static void __exit amiga_parallel_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver amiga_parallel_driver __refdata = { - .remove_new = __exit_p(amiga_parallel_remove), + .remove = __exit_p(amiga_parallel_remove), .driver = { .name = "amiga-parallel", }, diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 949236a7a27c97..d6495f2f90a7f6 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -368,7 +368,7 @@ static struct platform_driver bpp_sbus_driver = { .of_match_table = bpp_match, }, .probe = bpp_probe, - .remove_new = bpp_remove, + .remove = bpp_remove, }; module_platform_driver(bpp_sbus_driver); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 0d94e4a967d81d..2fbd379923fd1e 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -173,6 +173,15 @@ config PCI_PASID If unsure, say N. +config PCIE_TPH + bool "TLP Processing Hints" + help + This option adds support for PCIe TLP Processing Hints (TPH). + TPH allows endpoint devices to provide optimization hints, such as + desired caching behavior, for requests that target memory space. + These hints, called Steering Tags, can empower the system hardware + to optimize the utilization of platform resources. + config PCI_P2PDMA bool "PCI peer-to-peer transfer support" depends on ZONE_DEVICE @@ -305,6 +314,6 @@ source "drivers/pci/hotplug/Kconfig" source "drivers/pci/controller/Kconfig" source "drivers/pci/endpoint/Kconfig" source "drivers/pci/switch/Kconfig" -source "drivers/pci/pwrctl/Kconfig" +source "drivers/pci/pwrctrl/Kconfig" endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 374c5c06d92f9d..67647f1880fb8f 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \ obj-$(CONFIG_PCI) += msi/ obj-$(CONFIG_PCI) += pcie/ -obj-$(CONFIG_PCI) += pwrctl/ +obj-$(CONFIG_PCI) += pwrctrl/ ifdef CONFIG_PCI obj-$(CONFIG_PROC_FS) += proc.o @@ -36,6 +36,7 @@ obj-$(CONFIG_VGA_ARB) += vgaarb.o obj-$(CONFIG_PCI_DOE) += doe.o obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o obj-$(CONFIG_PCI_NPEM) += npem.o +obj-$(CONFIG_PCIE_TPH) += tph.o # Endpoint library must be initialized before its users obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 55c85368605187..98910bc0fcc4e5 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -13,11 +13,24 @@ #include #include #include +#include #include #include #include "pci.h" +/* + * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond + * to P2P or CardBus bridge windows) go in a table. Additional ones (for + * buses below host bridges or subtractive decode bridges) go in the list. + * Use pci_bus_for_each_resource() to iterate through all the resources. + */ + +struct pci_bus_resource { + struct list_head list; + struct resource *res; +}; + void pci_add_resource_offset(struct list_head *resources, struct resource *res, resource_size_t offset) { @@ -46,8 +59,7 @@ void pci_free_resource_list(struct list_head *resources) } EXPORT_SYMBOL(pci_free_resource_list); -void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, - unsigned int flags) +void pci_bus_add_resource(struct pci_bus *bus, struct resource *res) { struct pci_bus_resource *bus_res; @@ -58,7 +70,6 @@ void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, } bus_res->res = res; - bus_res->flags = flags; list_add_tail(&bus_res->list, &bus->resources); } @@ -320,6 +331,47 @@ void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } void __weak pcibios_bus_add_device(struct pci_dev *pdev) { } +/* + * Create pwrctrl devices (if required) for the PCI devices to handle the power + * state. + */ +static void pci_pwrctrl_create_devices(struct pci_dev *dev) +{ + struct device_node *np = dev_of_node(&dev->dev); + struct device *parent = &dev->dev; + struct platform_device *pdev; + + /* + * First ensure that we are starting from a PCI bridge and it has a + * corresponding devicetree node. + */ + if (np && pci_is_bridge(dev)) { + /* + * Now look for the child PCI device nodes and create pwrctrl + * devices for them. The pwrctrl device drivers will manage the + * power state of the devices. + */ + for_each_available_child_of_node_scoped(np, child) { + /* + * First check whether the pwrctrl device really + * needs to be created or not. This is decided + * based on at least one of the power supplies + * being defined in the devicetree node of the + * device. + */ + if (!of_pci_supply_present(child)) { + pci_dbg(dev, "skipping OF node: %s\n", child->name); + return; + } + + /* Now create the pwrctrl device */ + pdev = of_platform_device_create(child, NULL, parent); + if (!pdev) + pci_err(dev, "failed to create OF node: %s\n", child->name); + } + } +} + /** * pci_bus_add_device - start driver for a single device * @dev: device to add @@ -329,6 +381,7 @@ void __weak pcibios_bus_add_device(struct pci_dev *pdev) { } void pci_bus_add_device(struct pci_dev *dev) { struct device_node *dn = dev->dev.of_node; + struct platform_device *pdev; int retval; /* @@ -343,20 +396,28 @@ void pci_bus_add_device(struct pci_dev *dev) pci_proc_attach_device(dev); pci_bridge_d3_update(dev); + pci_pwrctrl_create_devices(dev); + + /* + * If the PCI device is associated with a pwrctrl device with a + * power supply, create a device link between the PCI device and + * pwrctrl device. This ensures that pwrctrl drivers are probed + * before PCI client drivers. + */ + pdev = of_find_device_by_node(dn); + if (pdev && of_pci_supply_present(dn)) { + if (!device_link_add(&dev->dev, &pdev->dev, + DL_FLAG_AUTOREMOVE_CONSUMER)) + pci_err(dev, "failed to add device link to power control device %s\n", + pdev->name); + } + dev->match_driver = !dn || of_device_is_available(dn); retval = device_attach(&dev->dev); if (retval < 0 && retval != -EPROBE_DEFER) pci_warn(dev, "device attach failed (%d)\n", retval); - pci_dev_assign_added(dev, true); - - if (dev_of_node(&dev->dev) && pci_is_bridge(dev)) { - retval = of_platform_populate(dev_of_node(&dev->dev), NULL, NULL, - &dev->dev); - if (retval) - pci_err(dev, "failed to populate child OF nodes (%d)\n", - retval); - } + pci_dev_assign_added(dev); } EXPORT_SYMBOL_GPL(pci_bus_add_device); @@ -389,41 +450,23 @@ void pci_bus_add_devices(const struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_add_devices); -static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), - void *userdata, bool locked) +static int __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), + void *userdata) { struct pci_dev *dev; - struct pci_bus *bus; - struct list_head *next; - int retval; + int ret = 0; - bus = top; - if (!locked) - down_read(&pci_bus_sem); - next = top->devices.next; - for (;;) { - if (next == &bus->devices) { - /* end of this bus, go up or finish */ - if (bus == top) + list_for_each_entry(dev, &top->devices, bus_list) { + ret = cb(dev, userdata); + if (ret) + break; + if (dev->subordinate) { + ret = __pci_walk_bus(dev->subordinate, cb, userdata); + if (ret) break; - next = bus->self->bus_list.next; - bus = bus->self->bus; - continue; } - dev = list_entry(next, struct pci_dev, bus_list); - if (dev->subordinate) { - /* this is a pci-pci bridge, do its devices next */ - next = dev->subordinate->devices.next; - bus = dev->subordinate; - } else - next = dev->bus_list.next; - - retval = cb(dev, userdata); - if (retval) - break; } - if (!locked) - up_read(&pci_bus_sem); + return ret; } /** @@ -441,7 +484,9 @@ static void __pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void */ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata) { - __pci_walk_bus(top, cb, userdata, false); + down_read(&pci_bus_sem); + __pci_walk_bus(top, cb, userdata); + up_read(&pci_bus_sem); } EXPORT_SYMBOL_GPL(pci_walk_bus); @@ -449,9 +494,8 @@ void pci_walk_bus_locked(struct pci_bus *top, int (*cb)(struct pci_dev *, void * { lockdep_assert_held(&pci_bus_sem); - __pci_walk_bus(top, cb, userdata, true); + __pci_walk_bus(top, cb, userdata); } -EXPORT_SYMBOL_GPL(pci_walk_bus_locked); struct pci_bus *pci_bus_get(struct pci_bus *bus) { diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c index 284f2e0e4d2615..0341d51d6aed12 100644 --- a/drivers/pci/controller/cadence/pci-j721e.c +++ b/drivers/pci/controller/cadence/pci-j721e.c @@ -386,6 +386,13 @@ static const struct j721e_pcie_data j784s4_pcie_ep_data = { .max_lanes = 4, }; +static const struct j721e_pcie_data j722s_pcie_rc_data = { + .mode = PCI_MODE_RC, + .linkdown_irq_regfield = J7200_LINK_DOWN, + .byte_access_allowed = true, + .max_lanes = 1, +}; + static const struct of_device_id of_j721e_pcie_match[] = { { .compatible = "ti,j721e-pcie-host", @@ -419,6 +426,10 @@ static const struct of_device_id of_j721e_pcie_match[] = { .compatible = "ti,j784s4-pcie-ep", .data = &j784s4_pcie_ep_data, }, + { + .compatible = "ti,j722s-pcie-host", + .data = &j722s_pcie_rc_data, + }, {}, }; @@ -572,15 +583,14 @@ static int j721e_pcie_probe(struct platform_device *pdev) pcie->refclk = clk; /* - * The "Power Sequencing and Reset Signal Timings" table of the - * PCI Express Card Electromechanical Specification, Revision - * 5.1, Section 2.9.2, Symbol "T_PERST-CLK", indicates PERST# - * should be deasserted after minimum of 100us once REFCLK is - * stable. The REFCLK to the connector in RC mode is selected - * while enabling the PHY. So deassert PERST# after 100 us. + * Section 2.2 of the PCI Express Card Electromechanical + * Specification (Revision 5.1) mandates that the deassertion + * of the PERST# signal should be delayed by 100 ms (TPVPERL). + * This shall ensure that the power and the reference clock + * are stable. */ if (gpiod) { - fsleep(PCIE_T_PERST_CLK_US); + msleep(PCIE_T_PVPERL_MS); gpiod_set_value_cansleep(gpiod, 1); } @@ -671,15 +681,14 @@ static int j721e_pcie_resume_noirq(struct device *dev) return ret; /* - * The "Power Sequencing and Reset Signal Timings" table of the - * PCI Express Card Electromechanical Specification, Revision - * 5.1, Section 2.9.2, Symbol "T_PERST-CLK", indicates PERST# - * should be deasserted after minimum of 100us once REFCLK is - * stable. The REFCLK to the connector in RC mode is selected - * while enabling the PHY. So deassert PERST# after 100 us. + * Section 2.2 of the PCI Express Card Electromechanical + * Specification (Revision 5.1) mandates that the deassertion + * of the PERST# signal should be delayed by 100 ms (TPVPERL). + * This shall ensure that the power and the reference clock + * are stable. */ if (pcie->reset_gpio) { - fsleep(PCIE_T_PERST_CLK_US); + msleep(PCIE_T_PVPERL_MS); gpiod_set_value_cansleep(pcie->reset_gpio, 1); } @@ -712,7 +721,7 @@ static DEFINE_NOIRQ_DEV_PM_OPS(j721e_pcie_pm_ops, static struct platform_driver j721e_pcie_driver = { .probe = j721e_pcie_probe, - .remove_new = j721e_pcie_remove, + .remove = j721e_pcie_remove, .driver = { .name = "j721e-pcie", .of_match_table = of_j721e_pcie_match, diff --git a/drivers/pci/controller/cadence/pcie-cadence.c b/drivers/pci/controller/cadence/pcie-cadence.c index 4251fac5e31065..204e045aed8c33 100644 --- a/drivers/pci/controller/cadence/pcie-cadence.c +++ b/drivers/pci/controller/cadence/pcie-cadence.c @@ -197,7 +197,7 @@ int cdns_pcie_init_phy(struct device *dev, struct cdns_pcie *pcie) phy_count = of_property_count_strings(np, "phy-names"); if (phy_count < 1) { - dev_err(dev, "no phy-names. PHY will not be initialized\n"); + dev_info(dev, "no \"phy-names\" property found; PHY will not be initialized\n"); pcie->phy_count = 0; return 0; } @@ -260,7 +260,7 @@ static int cdns_pcie_resume_noirq(struct device *dev) ret = cdns_pcie_enable_phy(pcie); if (ret) { - dev_err(dev, "failed to enable phy\n"); + dev_err(dev, "failed to enable PHY\n"); return ret; } diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index fa45da28a218b5..6a830166d37fff 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -383,7 +383,7 @@ static const struct of_device_id exynos_pcie_of_match[] = { static struct platform_driver exynos_pcie_driver = { .probe = exynos_pcie_probe, - .remove_new = exynos_pcie_remove, + .remove = exynos_pcie_remove, .driver = { .name = "exynos-pcie", .of_match_table = exynos_pcie_of_match, diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c index 808d1f10541733..c8d5c90aa4d45b 100644 --- a/drivers/pci/controller/dwc/pci-imx6.c +++ b/drivers/pci/controller/dwc/pci-imx6.c @@ -82,6 +82,11 @@ enum imx_pcie_variants { #define IMX_PCIE_FLAG_HAS_SERDES BIT(6) #define IMX_PCIE_FLAG_SUPPORT_64BIT BIT(7) #define IMX_PCIE_FLAG_CPU_ADDR_FIXUP BIT(8) +/* + * Because of ERR005723 (PCIe does not support L2 power down) we need to + * workaround suspend resume on some devices which are affected by this errata. + */ +#define IMX_PCIE_FLAG_BROKEN_SUSPEND BIT(9) #define imx_check_flag(pci, val) (pci->drvdata->flags & val) @@ -1237,9 +1242,19 @@ static int imx_pcie_suspend_noirq(struct device *dev) return 0; imx_pcie_msi_save_restore(imx_pcie, true); - imx_pcie_pm_turnoff(imx_pcie); - imx_pcie_stop_link(imx_pcie->pci); - imx_pcie_host_exit(pp); + if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) { + /* + * The minimum for a workaround would be to set PERST# and to + * set the PCIE_TEST_PD flag. However, we can also disable the + * clock which saves some power. + */ + imx_pcie_assert_core_reset(imx_pcie); + imx_pcie->drvdata->enable_ref_clk(imx_pcie, false); + } else { + imx_pcie_pm_turnoff(imx_pcie); + imx_pcie_stop_link(imx_pcie->pci); + imx_pcie_host_exit(pp); + } return 0; } @@ -1253,14 +1268,32 @@ static int imx_pcie_resume_noirq(struct device *dev) if (!(imx_pcie->drvdata->flags & IMX_PCIE_FLAG_SUPPORTS_SUSPEND)) return 0; - ret = imx_pcie_host_init(pp); - if (ret) - return ret; - imx_pcie_msi_save_restore(imx_pcie, false); - dw_pcie_setup_rc(pp); + if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_BROKEN_SUSPEND)) { + ret = imx_pcie->drvdata->enable_ref_clk(imx_pcie, true); + if (ret) + return ret; + ret = imx_pcie_deassert_core_reset(imx_pcie); + if (ret) + return ret; + /* + * Using PCIE_TEST_PD seems to disable MSI and powers down the + * root complex. This is why we have to setup the rc again and + * why we have to restore the MSI register. + */ + ret = dw_pcie_setup_rc(&imx_pcie->pci->pp); + if (ret) + return ret; + imx_pcie_msi_save_restore(imx_pcie, false); + } else { + ret = imx_pcie_host_init(pp); + if (ret) + return ret; + imx_pcie_msi_save_restore(imx_pcie, false); + dw_pcie_setup_rc(pp); - if (imx_pcie->link_is_up) - imx_pcie_start_link(imx_pcie->pci); + if (imx_pcie->link_is_up) + imx_pcie_start_link(imx_pcie->pci); + } return 0; } @@ -1485,7 +1518,9 @@ static const struct imx_pcie_drvdata drvdata[] = { [IMX6Q] = { .variant = IMX6Q, .flags = IMX_PCIE_FLAG_IMX_PHY | - IMX_PCIE_FLAG_IMX_SPEED_CHANGE, + IMX_PCIE_FLAG_IMX_SPEED_CHANGE | + IMX_PCIE_FLAG_BROKEN_SUSPEND | + IMX_PCIE_FLAG_SUPPORTS_SUSPEND, .dbi_length = 0x200, .gpr = "fsl,imx6q-iomuxc-gpr", .clk_names = imx6q_clks, diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index 2219b1a866faf2..63bd5003da458e 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -455,6 +455,17 @@ static void __iomem *ks_pcie_other_map_bus(struct pci_bus *bus, struct keystone_pcie *ks_pcie = to_keystone_pcie(pci); u32 reg; + /* + * Checking whether the link is up here is a last line of defense + * against platforms that forward errors on the system bus as + * SError upon PCI configuration transactions issued when the link + * is down. This check is racy by definition and does not stop + * the system from triggering an SError if the link goes down + * after this check is performed. + */ + if (!dw_pcie_link_up(pci)) + return NULL; + reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) | CFG_FUNC(PCI_FUNC(devfn)); if (!pci_is_root_bus(bus->parent)) @@ -1093,6 +1104,7 @@ static int ks_pcie_am654_set_mode(struct device *dev, static const struct ks_pcie_of_data ks_pcie_rc_of_data = { .host_ops = &ks_pcie_host_ops, + .mode = DW_PCIE_RC_TYPE, .version = DW_PCIE_VER_365A, }; @@ -1363,7 +1375,7 @@ static void ks_pcie_remove(struct platform_device *pdev) static struct platform_driver ks_pcie_driver = { .probe = ks_pcie_probe, - .remove_new = ks_pcie_remove, + .remove = ks_pcie_remove, .driver = { .name = "keystone-pcie", .of_match_table = ks_pcie_of_match, diff --git a/drivers/pci/controller/dwc/pcie-bt1.c b/drivers/pci/controller/dwc/pcie-bt1.c index 76d0ddea800757..1340edc18d1285 100644 --- a/drivers/pci/controller/dwc/pcie-bt1.c +++ b/drivers/pci/controller/dwc/pcie-bt1.c @@ -632,7 +632,7 @@ MODULE_DEVICE_TABLE(of, bt1_pcie_of_match); static struct platform_driver bt1_pcie_driver = { .probe = bt1_pcie_probe, - .remove_new = bt1_pcie_remove, + .remove = bt1_pcie_remove, .driver = { .name = "bt1-pcie", .of_match_table = bt1_pcie_of_match, diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 43ba5c6738df1a..f3ac7d46a855b2 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -268,6 +268,20 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr, return -EINVAL; } +static u64 dw_pcie_ep_align_addr(struct pci_epc *epc, u64 pci_addr, + size_t *pci_size, size_t *offset) +{ + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + u64 mask = pci->region_align - 1; + size_t ofst = pci_addr & mask; + + *pci_size = ALIGN(ofst + *pci_size, epc->mem->window.page_size); + *offset = ofst; + + return pci_addr & ~mask; +} + static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t addr) { @@ -280,6 +294,7 @@ static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, if (ret < 0) return; + ep->outbound_addr[atu_index] = 0; dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, atu_index); clear_bit(atu_index, ep->ob_window_map); } @@ -444,6 +459,7 @@ static const struct pci_epc_ops epc_ops = { .write_header = dw_pcie_ep_write_header, .set_bar = dw_pcie_ep_set_bar, .clear_bar = dw_pcie_ep_clear_bar, + .align_addr = dw_pcie_ep_align_addr, .map_addr = dw_pcie_ep_map_addr, .unmap_addr = dw_pcie_ep_unmap_addr, .set_msi = dw_pcie_ep_set_msi, @@ -488,7 +504,8 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, u32 msg_addr_lower, msg_addr_upper, reg; struct dw_pcie_ep_func *ep_func; struct pci_epc *epc = ep->epc; - unsigned int aligned_offset; + size_t map_size = sizeof(u32); + size_t offset; u16 msg_ctrl, msg_data; bool has_upper; u64 msg_addr; @@ -516,14 +533,13 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, } msg_addr = ((u64)msg_addr_upper) << 32 | msg_addr_lower; - aligned_offset = msg_addr & (epc->mem->window.page_size - 1); - msg_addr = ALIGN_DOWN(msg_addr, epc->mem->window.page_size); + msg_addr = dw_pcie_ep_align_addr(epc, msg_addr, &map_size, &offset); ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr, - epc->mem->window.page_size); + map_size); if (ret) return ret; - writel(msg_data | (interrupt_num - 1), ep->msi_mem + aligned_offset); + writel(msg_data | (interrupt_num - 1), ep->msi_mem + offset); dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); @@ -574,8 +590,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, struct pci_epf_msix_tbl *msix_tbl; struct dw_pcie_ep_func *ep_func; struct pci_epc *epc = ep->epc; + size_t map_size = sizeof(u32); + size_t offset; u32 reg, msg_data, vec_ctrl; - unsigned int aligned_offset; u32 tbl_offset; u64 msg_addr; int ret; @@ -600,14 +617,13 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, return -EPERM; } - aligned_offset = msg_addr & (epc->mem->window.page_size - 1); - msg_addr = ALIGN_DOWN(msg_addr, epc->mem->window.page_size); + msg_addr = dw_pcie_ep_align_addr(epc, msg_addr, &map_size, &offset); ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr, - epc->mem->window.page_size); + map_size); if (ret) return ret; - writel(msg_data, ep->msi_mem + aligned_offset); + writel(msg_data, ep->msi_mem + offset); dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->msi_mem_phys); @@ -689,7 +705,7 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) * for 1 MB BAR size only. */ for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) - dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0); + dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, BIT(4)); } dw_pcie_setup(pci); diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 3e41865c72904e..d2291c3ceb8bed 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -474,8 +474,8 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (pci_msi_enabled()) { pp->has_msi_ctrl = !(pp->ops->msi_init || - of_property_read_bool(np, "msi-parent") || - of_property_read_bool(np, "msi-map")); + of_property_present(np, "msi-parent") || + of_property_present(np, "msi-map")); /* * For the has_msi_ctrl case the default assignment is handled diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c index 7a11c618b9d9c4..615a0e3e6d7eb5 100644 --- a/drivers/pci/controller/dwc/pcie-histb.c +++ b/drivers/pci/controller/dwc/pcie-histb.c @@ -439,7 +439,7 @@ MODULE_DEVICE_TABLE(of, histb_pcie_of_match); static struct platform_driver histb_pcie_platform_driver = { .probe = histb_pcie_probe, - .remove_new = histb_pcie_remove, + .remove = histb_pcie_remove, .driver = { .name = "histb-pcie", .of_match_table = histb_pcie_of_match, diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 676d2aba4fbdec..9b53b8f6f268e2 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -443,7 +443,7 @@ static const struct of_device_id of_intel_pcie_match[] = { static struct platform_driver intel_pcie_driver = { .probe = intel_pcie_probe, - .remove_new = intel_pcie_remove, + .remove = intel_pcie_remove, .driver = { .name = "intel-gw-pcie", .of_match_table = of_intel_pcie_match, diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c index 85a2c77b1835af..1b2088acb538b8 100644 --- a/drivers/pci/controller/dwc/pcie-kirin.c +++ b/drivers/pci/controller/dwc/pcie-kirin.c @@ -769,7 +769,7 @@ static int kirin_pcie_probe(struct platform_device *pdev) static struct platform_driver kirin_pcie_driver = { .probe = kirin_pcie_probe, - .remove_new = kirin_pcie_remove, + .remove = kirin_pcie_remove, .driver = { .name = "kirin-pcie", .of_match_table = kirin_pcie_match, diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c index e588fcc5458936..c08f64d7a825fa 100644 --- a/drivers/pci/controller/dwc/pcie-qcom-ep.c +++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c @@ -396,6 +396,10 @@ static int qcom_pcie_perst_deassert(struct dw_pcie *pci) return ret; } + /* Perform cleanup that requires refclk */ + pci_epc_deinit_notify(pci->ep.epc); + dw_pcie_ep_cleanup(&pci->ep); + /* Assert WAKE# to RC to indicate device is ready */ gpiod_set_value_cansleep(pcie_ep->wake, 1); usleep_range(WAKE_DELAY_US, WAKE_DELAY_US + 500); @@ -540,8 +544,6 @@ static void qcom_pcie_perst_assert(struct dw_pcie *pci) { struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci); - pci_epc_deinit_notify(pci->ep.epc); - dw_pcie_ep_cleanup(&pci->ep); qcom_pcie_disable_resources(pcie_ep); pcie_ep->link_status = QCOM_PCIE_EP_LINK_DISABLED; } @@ -937,7 +939,7 @@ MODULE_DEVICE_TABLE(of, qcom_pcie_ep_match); static struct platform_driver qcom_pcie_ep_driver = { .probe = qcom_pcie_ep_probe, - .remove_new = qcom_pcie_ep_remove, + .remove = qcom_pcie_ep_remove, .driver = { .name = "qcom-pcie-ep", .of_match_table = qcom_pcie_ep_match, diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index ef44a82be058b2..dc102d8bd58c69 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -133,6 +133,7 @@ /* PARF_INT_ALL_{STATUS/CLEAR/MASK} register fields */ #define PARF_INT_ALL_LINK_UP BIT(13) +#define PARF_INT_MSI_DEV_0_7 GENMASK(30, 23) /* PARF_NO_SNOOP_OVERIDE register fields */ #define WR_NO_SNOOP_OVERIDE_EN BIT(1) @@ -1364,6 +1365,16 @@ static const struct qcom_pcie_ops ops_1_9_0 = { .config_sid = qcom_pcie_config_sid_1_9_0, }; +/* Qcom IP rev.: 1.21.0 Synopsys IP rev.: 5.60a */ +static const struct qcom_pcie_ops ops_1_21_0 = { + .get_resources = qcom_pcie_get_resources_2_7_0, + .init = qcom_pcie_init_2_7_0, + .post_init = qcom_pcie_post_init_2_7_0, + .host_post_init = qcom_pcie_host_post_init_2_7_0, + .deinit = qcom_pcie_deinit_2_7_0, + .ltssm_enable = qcom_pcie_2_3_2_ltssm_enable, +}; + /* Qcom IP rev.: 2.9.0 Synopsys IP rev.: 5.00a */ static const struct qcom_pcie_ops ops_2_9_0 = { .get_resources = qcom_pcie_get_resources_2_9_0, @@ -1411,7 +1422,7 @@ static const struct qcom_pcie_cfg cfg_2_9_0 = { }; static const struct qcom_pcie_cfg cfg_sc8280xp = { - .ops = &ops_1_9_0, + .ops = &ops_1_21_0, .no_l0s = true, }; @@ -1716,7 +1727,8 @@ static int qcom_pcie_probe(struct platform_device *pdev) goto err_host_deinit; } - writel_relaxed(PARF_INT_ALL_LINK_UP, pcie->parf + PARF_INT_ALL_MASK); + writel_relaxed(PARF_INT_ALL_LINK_UP | PARF_INT_MSI_DEV_0_7, + pcie->parf + PARF_INT_ALL_MASK); } qcom_pcie_icc_opp_update(pcie); @@ -1828,6 +1840,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 }, { .compatible = "qcom,pcie-ipq8074", .data = &cfg_2_3_3 }, { .compatible = "qcom,pcie-ipq8074-gen3", .data = &cfg_2_9_0 }, + { .compatible = "qcom,pcie-ipq9574", .data = &cfg_2_9_0 }, { .compatible = "qcom,pcie-msm8996", .data = &cfg_2_3_2 }, { .compatible = "qcom,pcie-qcs404", .data = &cfg_2_4_0 }, { .compatible = "qcom,pcie-sa8540p", .data = &cfg_sc8280xp }, @@ -1843,7 +1856,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-sm8450-pcie0", .data = &cfg_1_9_0 }, { .compatible = "qcom,pcie-sm8450-pcie1", .data = &cfg_1_9_0 }, { .compatible = "qcom,pcie-sm8550", .data = &cfg_1_9_0 }, - { .compatible = "qcom,pcie-x1e80100", .data = &cfg_1_9_0 }, + { .compatible = "qcom,pcie-x1e80100", .data = &cfg_sc8280xp }, { } }; diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 3a5511c3f7d970..fc872dd35029c0 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -775,7 +775,7 @@ static struct platform_driver rcar_gen4_pcie_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = rcar_gen4_pcie_probe, - .remove_new = rcar_gen4_pcie_remove, + .remove = rcar_gen4_pcie_remove, }; module_platform_driver(rcar_gen4_pcie_driver); diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c index c1394f2ab63ff1..5103995cd6c752 100644 --- a/drivers/pci/controller/dwc/pcie-tegra194.c +++ b/drivers/pci/controller/dwc/pcie-tegra194.c @@ -1704,9 +1704,6 @@ static void pex_ep_event_pex_rst_assert(struct tegra_pcie_dw *pcie) if (ret) dev_err(pcie->dev, "Failed to go Detect state: %d\n", ret); - pci_epc_deinit_notify(pcie->pci.ep.epc); - dw_pcie_ep_cleanup(&pcie->pci.ep); - reset_control_assert(pcie->core_rst); tegra_pcie_disable_phy(pcie); @@ -1785,6 +1782,10 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie) goto fail_phy; } + /* Perform cleanup that requires refclk */ + pci_epc_deinit_notify(pcie->pci.ep.epc); + dw_pcie_ep_cleanup(&pcie->pci.ep); + /* Clear any stale interrupt statuses */ appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L0); appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_0_0); @@ -2493,7 +2494,7 @@ static const struct dev_pm_ops tegra_pcie_dw_pm_ops = { static struct platform_driver tegra_pcie_dw_driver = { .probe = tegra_pcie_dw_probe, - .remove_new = tegra_pcie_dw_remove, + .remove = tegra_pcie_dw_remove, .shutdown = tegra_pcie_dw_shutdown, .driver = { .name = "tegra194-pcie", diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index a598a98247ce91..a29796cce420a2 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -1996,7 +1996,7 @@ static struct platform_driver advk_pcie_driver = { .of_match_table = advk_pcie_of_match_table, }, .probe = advk_pcie_probe, - .remove_new = advk_pcie_remove, + .remove = advk_pcie_remove, }; module_platform_driver(advk_pcie_driver); diff --git a/drivers/pci/controller/pci-host-generic.c b/drivers/pci/controller/pci-host-generic.c index 5f06f94db7b17e..4051b9b61dace6 100644 --- a/drivers/pci/controller/pci-host-generic.c +++ b/drivers/pci/controller/pci-host-generic.c @@ -82,7 +82,7 @@ static struct platform_driver gen_pci_driver = { .of_match_table = gen_pci_of_match, }, .probe = pci_host_common_probe, - .remove_new = pci_host_common_remove, + .remove = pci_host_common_remove, }; module_platform_driver(gen_pci_driver); diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 29fe09c99e7d9c..46d3afe1d30819 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -1727,7 +1727,7 @@ static struct platform_driver mvebu_pcie_driver = { .pm = &mvebu_pcie_pm_ops, }, .probe = mvebu_pcie_probe, - .remove_new = mvebu_pcie_remove, + .remove = mvebu_pcie_remove, }; module_platform_driver(mvebu_pcie_driver); diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index d7517c3976e7f1..b3cdbc5927de37 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -1460,7 +1460,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) pcie->cs = *res; /* constrain configuration space to 4 KiB */ - pcie->cs.end = pcie->cs.start + SZ_4K - 1; + resource_set_size(&pcie->cs, SZ_4K); pcie->cfg = devm_ioremap_resource(dev, &pcie->cs); if (IS_ERR(pcie->cfg)) { @@ -2800,6 +2800,6 @@ static struct platform_driver tegra_pcie_driver = { .pm = &tegra_pcie_pm_ops, }, .probe = tegra_pcie_probe, - .remove_new = tegra_pcie_remove, + .remove = tegra_pcie_remove, }; module_platform_driver(tegra_pcie_driver); diff --git a/drivers/pci/controller/pci-thunder-pem.c b/drivers/pci/controller/pci-thunder-pem.c index 06a9855cb431cb..f1bd5de67997cd 100644 --- a/drivers/pci/controller/pci-thunder-pem.c +++ b/drivers/pci/controller/pci-thunder-pem.c @@ -400,9 +400,9 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg) * Reserve 64K size PEM specific resources. The full 16M range * size is required for thunder_pem_init() call. */ - res_pem->end = res_pem->start + SZ_64K - 1; + resource_set_size(res_pem, SZ_64K); thunder_pem_reserve_range(dev, root->segment, res_pem); - res_pem->end = res_pem->start + SZ_16M - 1; + resource_set_size(res_pem, SZ_16M); /* Reserve PCI configuration space as well. */ thunder_pem_reserve_range(dev, root->segment, &cfg->res); diff --git a/drivers/pci/controller/pci-xgene-msi.c b/drivers/pci/controller/pci-xgene-msi.c index 3ce38dfd0d29f7..88c0977bc41a49 100644 --- a/drivers/pci/controller/pci-xgene-msi.c +++ b/drivers/pci/controller/pci-xgene-msi.c @@ -518,7 +518,7 @@ static struct platform_driver xgene_msi_driver = { .of_match_table = xgene_msi_match_table, }, .probe = xgene_msi_probe, - .remove_new = xgene_msi_remove, + .remove = xgene_msi_remove, }; static int __init xgene_pcie_msi_init(void) diff --git a/drivers/pci/controller/pcie-altera-msi.c b/drivers/pci/controller/pcie-altera-msi.c index e36a6e158d23c1..e1cee3c0575fbd 100644 --- a/drivers/pci/controller/pcie-altera-msi.c +++ b/drivers/pci/controller/pcie-altera-msi.c @@ -267,7 +267,7 @@ static struct platform_driver altera_msi_driver = { .of_match_table = altera_msi_of_match, }, .probe = altera_msi_probe, - .remove_new = altera_msi_remove, + .remove = altera_msi_remove, }; static int __init altera_msi_init(void) diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c index 650b2dd81c4822..eb55a7f8573a86 100644 --- a/drivers/pci/controller/pcie-altera.c +++ b/drivers/pci/controller/pcie-altera.c @@ -815,10 +815,10 @@ static void altera_pcie_remove(struct platform_device *pdev) } static struct platform_driver altera_pcie_driver = { - .probe = altera_pcie_probe, - .remove_new = altera_pcie_remove, + .probe = altera_pcie_probe, + .remove = altera_pcie_remove, .driver = { - .name = "altera-pcie", + .name = "altera-pcie", .of_match_table = altera_pcie_of_match, }, }; diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c index 9321280f6edbab..e733a27dc8df8e 100644 --- a/drivers/pci/controller/pcie-brcmstb.c +++ b/drivers/pci/controller/pcie-brcmstb.c @@ -1928,7 +1928,7 @@ static const struct dev_pm_ops brcm_pcie_pm_ops = { static struct platform_driver brcm_pcie_driver = { .probe = brcm_pcie_probe, - .remove_new = brcm_pcie_remove, + .remove = brcm_pcie_remove, .driver = { .name = "brcm-pcie", .of_match_table = brcm_pcie_match, diff --git a/drivers/pci/controller/pcie-hisi-error.c b/drivers/pci/controller/pcie-hisi-error.c index ad9d5ffcd9e344..aaf1ed2b6e5971 100644 --- a/drivers/pci/controller/pcie-hisi-error.c +++ b/drivers/pci/controller/pcie-hisi-error.c @@ -317,7 +317,7 @@ static struct platform_driver hisi_pcie_error_handler_driver = { .acpi_match_table = hisi_pcie_acpi_match, }, .probe = hisi_pcie_error_handler_probe, - .remove_new = hisi_pcie_error_handler_remove, + .remove = hisi_pcie_error_handler_remove, }; module_platform_driver(hisi_pcie_error_handler_driver); diff --git a/drivers/pci/controller/pcie-iproc-platform.c b/drivers/pci/controller/pcie-iproc-platform.c index 4e6aa882a567ab..0cb78c583c7ea4 100644 --- a/drivers/pci/controller/pcie-iproc-platform.c +++ b/drivers/pci/controller/pcie-iproc-platform.c @@ -134,7 +134,7 @@ static struct platform_driver iproc_pltfm_pcie_driver = { .of_match_table = of_match_ptr(iproc_pcie_of_match_table), }, .probe = iproc_pltfm_pcie_probe, - .remove_new = iproc_pltfm_pcie_remove, + .remove = iproc_pltfm_pcie_remove, .shutdown = iproc_pltfm_pcie_shutdown, }; module_platform_driver(iproc_pltfm_pcie_driver); diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c index 66ce4b5d309bb6..be52e3a123abd0 100644 --- a/drivers/pci/controller/pcie-mediatek-gen3.c +++ b/drivers/pci/controller/pcie-mediatek-gen3.c @@ -28,7 +28,12 @@ #include "../pci.h" +#define PCIE_BASE_CFG_REG 0x14 +#define PCIE_BASE_CFG_SPEED GENMASK(15, 8) + #define PCIE_SETTING_REG 0x80 +#define PCIE_SETTING_LINK_WIDTH GENMASK(11, 8) +#define PCIE_SETTING_GEN_SUPPORT GENMASK(14, 12) #define PCIE_PCI_IDS_1 0x9c #define PCI_CLASS(class) (class << 8) #define PCIE_RC_MODE BIT(0) @@ -125,6 +130,9 @@ struct mtk_gen3_pcie; +#define PCIE_CONF_LINK2_CTL_STS (PCIE_CFG_OFFSET_ADDR + 0xb0) +#define PCIE_CONF_LINK2_LCR2_LINK_SPEED GENMASK(3, 0) + /** * struct mtk_gen3_pcie_pdata - differentiate between host generations * @power_up: pcie power_up callback @@ -160,6 +168,8 @@ struct mtk_msi_set { * @phy: PHY controller block * @clks: PCIe clocks * @num_clks: PCIe clocks count for this port + * @max_link_speed: Maximum link speed (PCIe Gen) for this port + * @num_lanes: Number of PCIe lanes for this port * @irq: PCIe controller interrupt number * @saved_irq_state: IRQ enable state saved at suspend time * @irq_lock: lock protecting IRQ register access @@ -180,6 +190,8 @@ struct mtk_gen3_pcie { struct phy *phy; struct clk_bulk_data *clks; int num_clks; + u8 max_link_speed; + u8 num_lanes; int irq; u32 saved_irq_state; @@ -381,11 +393,35 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie) int err; u32 val; - /* Set as RC mode */ + /* Set as RC mode and set controller PCIe Gen speed restriction, if any */ val = readl_relaxed(pcie->base + PCIE_SETTING_REG); val |= PCIE_RC_MODE; + if (pcie->max_link_speed) { + val &= ~PCIE_SETTING_GEN_SUPPORT; + + /* Can enable link speed support only from Gen2 onwards */ + if (pcie->max_link_speed >= 2) + val |= FIELD_PREP(PCIE_SETTING_GEN_SUPPORT, + GENMASK(pcie->max_link_speed - 2, 0)); + } + if (pcie->num_lanes) { + val &= ~PCIE_SETTING_LINK_WIDTH; + + /* Zero means one lane, each bit activates x2/x4/x8/x16 */ + if (pcie->num_lanes > 1) + val |= FIELD_PREP(PCIE_SETTING_LINK_WIDTH, + GENMASK(fls(pcie->num_lanes >> 2), 0)); + } writel_relaxed(val, pcie->base + PCIE_SETTING_REG); + /* Set Link Control 2 (LNKCTL2) speed restriction, if any */ + if (pcie->max_link_speed) { + val = readl_relaxed(pcie->base + PCIE_CONF_LINK2_CTL_STS); + val &= ~PCIE_CONF_LINK2_LCR2_LINK_SPEED; + val |= FIELD_PREP(PCIE_CONF_LINK2_LCR2_LINK_SPEED, pcie->max_link_speed); + writel_relaxed(val, pcie->base + PCIE_CONF_LINK2_CTL_STS); + } + /* Set class code */ val = readl_relaxed(pcie->base + PCIE_PCI_IDS_1); val &= ~GENMASK(31, 8); @@ -813,6 +849,7 @@ static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie) struct device *dev = pcie->dev; struct platform_device *pdev = to_platform_device(dev); struct resource *regs; + u32 num_lanes; regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-mac"); if (!regs) @@ -858,6 +895,14 @@ static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie) return pcie->num_clks; } + ret = of_property_read_u32(dev->of_node, "num-lanes", &num_lanes); + if (ret == 0) { + if (num_lanes == 0 || num_lanes > 16 || (num_lanes != 1 && num_lanes % 2)) + dev_warn(dev, "invalid num-lanes, using controller defaults\n"); + else + pcie->num_lanes = num_lanes; + } + return 0; } @@ -1004,9 +1049,21 @@ static void mtk_pcie_power_down(struct mtk_gen3_pcie *pcie) reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets); } +static int mtk_pcie_get_controller_max_link_speed(struct mtk_gen3_pcie *pcie) +{ + u32 val; + int ret; + + val = readl_relaxed(pcie->base + PCIE_BASE_CFG_REG); + val = FIELD_GET(PCIE_BASE_CFG_SPEED, val); + ret = fls(val); + + return ret > 0 ? ret : -EINVAL; +} + static int mtk_pcie_setup(struct mtk_gen3_pcie *pcie) { - int err; + int err, max_speed; err = mtk_pcie_parse_port(pcie); if (err) @@ -1031,6 +1088,20 @@ static int mtk_pcie_setup(struct mtk_gen3_pcie *pcie) if (err) return err; + err = of_pci_get_max_link_speed(pcie->dev->of_node); + if (err) { + /* Get the maximum speed supported by the controller */ + max_speed = mtk_pcie_get_controller_max_link_speed(pcie); + + /* Set max_link_speed only if the controller supports it */ + if (max_speed >= 0 && max_speed <= err) { + pcie->max_link_speed = err; + dev_info(pcie->dev, + "maximum controller link speed Gen%d, overriding to Gen%u", + max_speed, pcie->max_link_speed); + } + } + /* Try link up */ err = mtk_pcie_startup_port(pcie); if (err) @@ -1225,7 +1296,7 @@ MODULE_DEVICE_TABLE(of, mtk_pcie_of_match); static struct platform_driver mtk_pcie_driver = { .probe = mtk_pcie_probe, - .remove_new = mtk_pcie_remove, + .remove = mtk_pcie_remove, .driver = { .name = "mtk-pcie-gen3", .of_match_table = mtk_pcie_of_match, diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c index 7f7d04c2ea573f..3bcfc4e58ba244 100644 --- a/drivers/pci/controller/pcie-mediatek.c +++ b/drivers/pci/controller/pcie-mediatek.c @@ -1235,7 +1235,7 @@ MODULE_DEVICE_TABLE(of, mtk_pcie_ids); static struct platform_driver mtk_pcie_driver = { .probe = mtk_pcie_probe, - .remove_new = mtk_pcie_remove, + .remove = mtk_pcie_remove, .driver = { .name = "mtk-pcie", .of_match_table = mtk_pcie_ids, diff --git a/drivers/pci/controller/pcie-mt7621.c b/drivers/pci/controller/pcie-mt7621.c index 9b4754a45515f5..776caa0b10115b 100644 --- a/drivers/pci/controller/pcie-mt7621.c +++ b/drivers/pci/controller/pcie-mt7621.c @@ -541,7 +541,7 @@ MODULE_DEVICE_TABLE(of, mt7621_pcie_ids); static struct platform_driver mt7621_pcie_driver = { .probe = mt7621_pcie_probe, - .remove_new = mt7621_pcie_remove, + .remove = mt7621_pcie_remove, .driver = { .name = "mt7621-pci", .of_match_table = mt7621_pcie_ids, diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c index 3dd653f3d78414..7c92eada04af40 100644 --- a/drivers/pci/controller/pcie-rcar-host.c +++ b/drivers/pci/controller/pcie-rcar-host.c @@ -796,8 +796,8 @@ static int rcar_pcie_enable_msi(struct rcar_pcie_host *host) rcar_pci_write_reg(pcie, 0, PCIEMSIIER); /* - * Setup MSI data target using RC base address address, which - * is guaranteed to be in the low 32bit range on any R-Car HW. + * Setup MSI data target using RC base address, which is guaranteed + * to be in the low 32bit range on any R-Car HW. */ rcar_pci_write_reg(pcie, lower_32_bits(res.start) | MSIFE, PCIEMSIALR); rcar_pci_write_reg(pcie, upper_32_bits(res.start), PCIEMSIAUR); diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c index 1362745336568e..1064b7b06cef64 100644 --- a/drivers/pci/controller/pcie-rockchip-ep.c +++ b/drivers/pci/controller/pcie-rockchip-ep.c @@ -10,12 +10,16 @@ #include #include +#include +#include #include +#include #include #include #include #include #include +#include #include "pcie-rockchip.h" @@ -48,6 +52,10 @@ struct rockchip_pcie_ep { u64 irq_pci_addr; u8 irq_pci_fn; u8 irq_pending; + int perst_irq; + bool perst_asserted; + bool link_up; + struct delayed_work link_training; }; static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip, @@ -63,15 +71,25 @@ static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip, ROCKCHIP_PCIE_AT_OB_REGION_DESC1(region)); } +static int rockchip_pcie_ep_ob_atu_num_bits(struct rockchip_pcie *rockchip, + u64 pci_addr, size_t size) +{ + int num_pass_bits = fls64(pci_addr ^ (pci_addr + size - 1)); + + return clamp(num_pass_bits, + ROCKCHIP_PCIE_AT_MIN_NUM_BITS, + ROCKCHIP_PCIE_AT_MAX_NUM_BITS); +} + static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn, u32 r, u64 cpu_addr, u64 pci_addr, size_t size) { - int num_pass_bits = fls64(size - 1); + int num_pass_bits; u32 addr0, addr1, desc0; - if (num_pass_bits < 8) - num_pass_bits = 8; + num_pass_bits = rockchip_pcie_ep_ob_atu_num_bits(rockchip, + pci_addr, size); addr0 = ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) | (lower_32_bits(pci_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR); @@ -228,6 +246,28 @@ static inline u32 rockchip_ob_region(phys_addr_t addr) return (addr >> ilog2(SZ_1M)) & 0x1f; } +static u64 rockchip_pcie_ep_align_addr(struct pci_epc *epc, u64 pci_addr, + size_t *pci_size, size_t *addr_offset) +{ + struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); + size_t size = *pci_size; + u64 offset, mask; + int num_bits; + + num_bits = rockchip_pcie_ep_ob_atu_num_bits(&ep->rockchip, + pci_addr, size); + mask = (1ULL << num_bits) - 1; + + offset = pci_addr & mask; + if (size + offset > SZ_1M) + size = SZ_1M - offset; + + *pci_size = ALIGN(offset + size, ROCKCHIP_PCIE_AT_SIZE_ALIGN); + *addr_offset = offset; + + return pci_addr & ~mask; +} + static int rockchip_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, phys_addr_t addr, u64 pci_addr, size_t size) @@ -236,6 +276,9 @@ static int rockchip_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, struct rockchip_pcie *pcie = &ep->rockchip; u32 r = rockchip_ob_region(addr); + if (test_bit(r, &ep->ob_region_map)) + return -EBUSY; + rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, addr, pci_addr, size); set_bit(r, &ep->ob_region_map); @@ -249,13 +292,9 @@ static void rockchip_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, { struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); struct rockchip_pcie *rockchip = &ep->rockchip; - u32 r; - - for (r = 0; r < ep->max_regions; r++) - if (ep->ob_addr[r] == addr) - break; + u32 r = rockchip_ob_region(addr); - if (r == ep->max_regions) + if (addr != ep->ob_addr[r] || !test_bit(r, &ep->ob_region_map)) return; rockchip_pcie_clear_ep_ob_atu(rockchip, r); @@ -351,9 +390,10 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn, { struct rockchip_pcie *rockchip = &ep->rockchip; u32 flags, mme, data, data_mask; + size_t irq_pci_size, offset; + u64 irq_pci_addr; u8 msi_count; u64 pci_addr; - u32 r; /* Check MSI enable bit */ flags = rockchip_pcie_read(&ep->rockchip, @@ -389,18 +429,21 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn, PCI_MSI_ADDRESS_LO); /* Set the outbound region if needed. */ - if (unlikely(ep->irq_pci_addr != (pci_addr & PCIE_ADDR_MASK) || + irq_pci_size = ~PCIE_ADDR_MASK + 1; + irq_pci_addr = rockchip_pcie_ep_align_addr(ep->epc, + pci_addr & PCIE_ADDR_MASK, + &irq_pci_size, &offset); + if (unlikely(ep->irq_pci_addr != irq_pci_addr || ep->irq_pci_fn != fn)) { - r = rockchip_ob_region(ep->irq_phys_addr); - rockchip_pcie_prog_ep_ob_atu(rockchip, fn, r, - ep->irq_phys_addr, - pci_addr & PCIE_ADDR_MASK, - ~PCIE_ADDR_MASK + 1); - ep->irq_pci_addr = (pci_addr & PCIE_ADDR_MASK); + rockchip_pcie_prog_ep_ob_atu(rockchip, fn, + rockchip_ob_region(ep->irq_phys_addr), + ep->irq_phys_addr, + irq_pci_addr, irq_pci_size); + ep->irq_pci_addr = irq_pci_addr; ep->irq_pci_fn = fn; } - writew(data, ep->irq_cpu_addr + (pci_addr & ~PCIE_ADDR_MASK)); + writew(data, ep->irq_cpu_addr + offset + (pci_addr & ~PCIE_ADDR_MASK)); return 0; } @@ -432,14 +475,222 @@ static int rockchip_pcie_ep_start(struct pci_epc *epc) rockchip_pcie_write(rockchip, cfg, PCIE_CORE_PHY_FUNC_CFG); + if (rockchip->perst_gpio) + enable_irq(ep->perst_irq); + + /* Enable configuration and start link training */ + rockchip_pcie_write(rockchip, + PCIE_CLIENT_LINK_TRAIN_ENABLE | + PCIE_CLIENT_CONF_ENABLE, + PCIE_CLIENT_CONFIG); + + if (!rockchip->perst_gpio) + schedule_delayed_work(&ep->link_training, 0); + + return 0; +} + +static void rockchip_pcie_ep_stop(struct pci_epc *epc) +{ + struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); + struct rockchip_pcie *rockchip = &ep->rockchip; + + if (rockchip->perst_gpio) { + ep->perst_asserted = true; + disable_irq(ep->perst_irq); + } + + cancel_delayed_work_sync(&ep->link_training); + + /* Stop link training and disable configuration */ + rockchip_pcie_write(rockchip, + PCIE_CLIENT_CONF_DISABLE | + PCIE_CLIENT_LINK_TRAIN_DISABLE, + PCIE_CLIENT_CONFIG); +} + +static void rockchip_pcie_ep_retrain_link(struct rockchip_pcie *rockchip) +{ + u32 status; + + status = rockchip_pcie_read(rockchip, PCIE_EP_CONFIG_LCS); + status |= PCI_EXP_LNKCTL_RL; + rockchip_pcie_write(rockchip, status, PCIE_EP_CONFIG_LCS); +} + +static bool rockchip_pcie_ep_link_up(struct rockchip_pcie *rockchip) +{ + u32 val = rockchip_pcie_read(rockchip, PCIE_CLIENT_BASIC_STATUS1); + + return PCIE_LINK_UP(val); +} + +static void rockchip_pcie_ep_link_training(struct work_struct *work) +{ + struct rockchip_pcie_ep *ep = + container_of(work, struct rockchip_pcie_ep, link_training.work); + struct rockchip_pcie *rockchip = &ep->rockchip; + struct device *dev = rockchip->dev; + u32 val; + int ret; + + /* Enable Gen1 training and wait for its completion */ + ret = readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL, + val, PCIE_LINK_TRAINING_DONE(val), 50, + LINK_TRAIN_TIMEOUT); + if (ret) + goto again; + + /* Make sure that the link is up */ + ret = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_BASIC_STATUS1, + val, PCIE_LINK_UP(val), 50, + LINK_TRAIN_TIMEOUT); + if (ret) + goto again; + + /* + * Check the current speed: if gen2 speed was requested and we are not + * at gen2 speed yet, retrain again for gen2. + */ + val = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL); + if (!PCIE_LINK_IS_GEN2(val) && rockchip->link_gen == 2) { + /* Enable retrain for gen2 */ + rockchip_pcie_ep_retrain_link(rockchip); + readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL, + val, PCIE_LINK_IS_GEN2(val), 50, + LINK_TRAIN_TIMEOUT); + } + + /* Check again that the link is up */ + if (!rockchip_pcie_ep_link_up(rockchip)) + goto again; + + /* + * If PERST# was asserted while polling the link, do not notify + * the function. + */ + if (ep->perst_asserted) + return; + + val = rockchip_pcie_read(rockchip, PCIE_CLIENT_BASIC_STATUS0); + dev_info(dev, + "link up (negotiated speed: %sGT/s, width: x%lu)\n", + (val & PCIE_CLIENT_NEG_LINK_SPEED) ? "5" : "2.5", + ((val & PCIE_CLIENT_NEG_LINK_WIDTH_MASK) >> + PCIE_CLIENT_NEG_LINK_WIDTH_SHIFT) << 1); + + /* Notify the function */ + pci_epc_linkup(ep->epc); + ep->link_up = true; + + return; + +again: + schedule_delayed_work(&ep->link_training, msecs_to_jiffies(5)); +} + +static void rockchip_pcie_ep_perst_assert(struct rockchip_pcie_ep *ep) +{ + struct rockchip_pcie *rockchip = &ep->rockchip; + + dev_dbg(rockchip->dev, "PERST# asserted, link down\n"); + + if (ep->perst_asserted) + return; + + ep->perst_asserted = true; + + cancel_delayed_work_sync(&ep->link_training); + + if (ep->link_up) { + pci_epc_linkdown(ep->epc); + ep->link_up = false; + } +} + +static void rockchip_pcie_ep_perst_deassert(struct rockchip_pcie_ep *ep) +{ + struct rockchip_pcie *rockchip = &ep->rockchip; + + dev_dbg(rockchip->dev, "PERST# de-asserted, starting link training\n"); + + if (!ep->perst_asserted) + return; + + ep->perst_asserted = false; + + /* Enable link re-training */ + rockchip_pcie_ep_retrain_link(rockchip); + + /* Start link training */ + schedule_delayed_work(&ep->link_training, 0); +} + +static irqreturn_t rockchip_pcie_ep_perst_irq_thread(int irq, void *data) +{ + struct pci_epc *epc = data; + struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); + struct rockchip_pcie *rockchip = &ep->rockchip; + u32 perst = gpiod_get_value(rockchip->perst_gpio); + + if (perst) + rockchip_pcie_ep_perst_assert(ep); + else + rockchip_pcie_ep_perst_deassert(ep); + + irq_set_irq_type(ep->perst_irq, + (perst ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW)); + + return IRQ_HANDLED; +} + +static int rockchip_pcie_ep_setup_irq(struct pci_epc *epc) +{ + struct rockchip_pcie_ep *ep = epc_get_drvdata(epc); + struct rockchip_pcie *rockchip = &ep->rockchip; + struct device *dev = rockchip->dev; + int ret; + + if (!rockchip->perst_gpio) + return 0; + + /* PCIe reset interrupt */ + ep->perst_irq = gpiod_to_irq(rockchip->perst_gpio); + if (ep->perst_irq < 0) { + dev_err(dev, + "failed to get IRQ for PERST# GPIO: %d\n", + ep->perst_irq); + + return ep->perst_irq; + } + + /* + * The perst_gpio is active low, so when it is inactive on start, it + * is high and will trigger the perst_irq handler. So treat this initial + * IRQ as a dummy one by faking the host asserting PERST#. + */ + ep->perst_asserted = true; + irq_set_status_flags(ep->perst_irq, IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(dev, ep->perst_irq, NULL, + rockchip_pcie_ep_perst_irq_thread, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "pcie-ep-perst", epc); + if (ret) { + dev_err(dev, + "failed to request IRQ for PERST# GPIO: %d\n", + ret); + + return ret; + } + return 0; } static const struct pci_epc_features rockchip_pcie_epc_features = { - .linkup_notifier = false, + .linkup_notifier = true, .msi_capable = true, .msix_capable = false, - .align = 256, + .align = ROCKCHIP_PCIE_AT_SIZE_ALIGN, }; static const struct pci_epc_features* @@ -452,17 +703,19 @@ static const struct pci_epc_ops rockchip_pcie_epc_ops = { .write_header = rockchip_pcie_ep_write_header, .set_bar = rockchip_pcie_ep_set_bar, .clear_bar = rockchip_pcie_ep_clear_bar, + .align_addr = rockchip_pcie_ep_align_addr, .map_addr = rockchip_pcie_ep_map_addr, .unmap_addr = rockchip_pcie_ep_unmap_addr, .set_msi = rockchip_pcie_ep_set_msi, .get_msi = rockchip_pcie_ep_get_msi, .raise_irq = rockchip_pcie_ep_raise_irq, .start = rockchip_pcie_ep_start, + .stop = rockchip_pcie_ep_stop, .get_features = rockchip_pcie_ep_get_features, }; -static int rockchip_pcie_parse_ep_dt(struct rockchip_pcie *rockchip, - struct rockchip_pcie_ep *ep) +static int rockchip_pcie_ep_get_resources(struct rockchip_pcie *rockchip, + struct rockchip_pcie_ep *ep) { struct device *dev = rockchip->dev; int err; @@ -496,91 +749,63 @@ static const struct of_device_id rockchip_pcie_ep_of_match[] = { {}, }; -static int rockchip_pcie_ep_probe(struct platform_device *pdev) +static int rockchip_pcie_ep_init_ob_mem(struct rockchip_pcie_ep *ep) { - struct device *dev = &pdev->dev; - struct rockchip_pcie_ep *ep; - struct rockchip_pcie *rockchip; - struct pci_epc *epc; - size_t max_regions; + struct rockchip_pcie *rockchip = &ep->rockchip; + struct device *dev = rockchip->dev; struct pci_epc_mem_window *windows = NULL; int err, i; - u32 cfg_msi, cfg_msix_cp; - - ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); - if (!ep) - return -ENOMEM; - rockchip = &ep->rockchip; - rockchip->is_rc = false; - rockchip->dev = dev; - - epc = devm_pci_epc_create(dev, &rockchip_pcie_epc_ops); - if (IS_ERR(epc)) { - dev_err(dev, "failed to create epc device\n"); - return PTR_ERR(epc); - } - - ep->epc = epc; - epc_set_drvdata(epc, ep); - - err = rockchip_pcie_parse_ep_dt(rockchip, ep); - if (err) - return err; - - err = rockchip_pcie_enable_clocks(rockchip); - if (err) - return err; - - err = rockchip_pcie_init_port(rockchip); - if (err) - goto err_disable_clocks; - - /* Establish the link automatically */ - rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE, - PCIE_CLIENT_CONFIG); - - max_regions = ep->max_regions; - ep->ob_addr = devm_kcalloc(dev, max_regions, sizeof(*ep->ob_addr), + ep->ob_addr = devm_kcalloc(dev, ep->max_regions, sizeof(*ep->ob_addr), GFP_KERNEL); - if (!ep->ob_addr) { - err = -ENOMEM; - goto err_uninit_port; - } - - /* Only enable function 0 by default */ - rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG); + if (!ep->ob_addr) + return -ENOMEM; windows = devm_kcalloc(dev, ep->max_regions, sizeof(struct pci_epc_mem_window), GFP_KERNEL); - if (!windows) { - err = -ENOMEM; - goto err_uninit_port; - } + if (!windows) + return -ENOMEM; + for (i = 0; i < ep->max_regions; i++) { windows[i].phys_base = rockchip->mem_res->start + (SZ_1M * i); windows[i].size = SZ_1M; windows[i].page_size = SZ_1M; } - err = pci_epc_multi_mem_init(epc, windows, ep->max_regions); + err = pci_epc_multi_mem_init(ep->epc, windows, ep->max_regions); devm_kfree(dev, windows); if (err < 0) { dev_err(dev, "failed to initialize the memory space\n"); - goto err_uninit_port; + return err; } - ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr, + ep->irq_cpu_addr = pci_epc_mem_alloc_addr(ep->epc, &ep->irq_phys_addr, SZ_1M); if (!ep->irq_cpu_addr) { dev_err(dev, "failed to reserve memory space for MSI\n"); - err = -ENOMEM; goto err_epc_mem_exit; } ep->irq_pci_addr = ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR; + return 0; + +err_epc_mem_exit: + pci_epc_mem_exit(ep->epc); + + return err; +} + +static void rockchip_pcie_ep_exit_ob_mem(struct rockchip_pcie_ep *ep) +{ + pci_epc_mem_exit(ep->epc); +} + +static void rockchip_pcie_ep_hide_broken_msix_cap(struct rockchip_pcie *rockchip) +{ + u32 cfg_msi, cfg_msix_cp; + /* * MSI-X is not supported but the controller still advertises the MSI-X * capability by default, which can lead to the Root Complex side @@ -603,19 +828,68 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev) rockchip_pcie_write(rockchip, cfg_msi, PCIE_EP_CONFIG_BASE + ROCKCHIP_PCIE_EP_MSI_CTRL_REG); +} - rockchip_pcie_write(rockchip, PCIE_CLIENT_CONF_ENABLE, - PCIE_CLIENT_CONFIG); +static int rockchip_pcie_ep_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rockchip_pcie_ep *ep; + struct rockchip_pcie *rockchip; + struct pci_epc *epc; + int err; + + ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL); + if (!ep) + return -ENOMEM; + + rockchip = &ep->rockchip; + rockchip->is_rc = false; + rockchip->dev = dev; + INIT_DELAYED_WORK(&ep->link_training, rockchip_pcie_ep_link_training); + + epc = devm_pci_epc_create(dev, &rockchip_pcie_epc_ops); + if (IS_ERR(epc)) { + dev_err(dev, "failed to create EPC device\n"); + return PTR_ERR(epc); + } + + ep->epc = epc; + epc_set_drvdata(epc, ep); + + err = rockchip_pcie_ep_get_resources(rockchip, ep); + if (err) + return err; + + err = rockchip_pcie_ep_init_ob_mem(ep); + if (err) + return err; + + err = rockchip_pcie_enable_clocks(rockchip); + if (err) + goto err_exit_ob_mem; + + err = rockchip_pcie_init_port(rockchip); + if (err) + goto err_disable_clocks; + + rockchip_pcie_ep_hide_broken_msix_cap(rockchip); + + /* Only enable function 0 by default */ + rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG); pci_epc_init_notify(epc); + err = rockchip_pcie_ep_setup_irq(epc); + if (err < 0) + goto err_uninit_port; + return 0; -err_epc_mem_exit: - pci_epc_mem_exit(epc); err_uninit_port: rockchip_pcie_deinit_phys(rockchip); err_disable_clocks: rockchip_pcie_disable_clocks(rockchip); +err_exit_ob_mem: + rockchip_pcie_ep_exit_ob_mem(ep); return err; } diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c index cbec711148253a..5adac6adc046f8 100644 --- a/drivers/pci/controller/pcie-rockchip-host.c +++ b/drivers/pci/controller/pcie-rockchip-host.c @@ -294,7 +294,7 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip) int err, i = MAX_LANE_NUM; u32 status; - gpiod_set_value_cansleep(rockchip->ep_gpio, 0); + gpiod_set_value_cansleep(rockchip->perst_gpio, 0); err = rockchip_pcie_init_port(rockchip); if (err) @@ -323,7 +323,7 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip) PCIE_CLIENT_CONFIG); msleep(PCIE_T_PVPERL_MS); - gpiod_set_value_cansleep(rockchip->ep_gpio, 1); + gpiod_set_value_cansleep(rockchip->perst_gpio, 1); msleep(PCIE_T_RRS_READY_MS); @@ -1050,7 +1050,7 @@ static struct platform_driver rockchip_pcie_driver = { .pm = &rockchip_pcie_pm_ops, }, .probe = rockchip_pcie_probe, - .remove_new = rockchip_pcie_remove, + .remove = rockchip_pcie_remove, }; module_platform_driver(rockchip_pcie_driver); diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c index c07d7129f1c7c4..b9ade7632e1134 100644 --- a/drivers/pci/controller/pcie-rockchip.c +++ b/drivers/pci/controller/pcie-rockchip.c @@ -119,13 +119,15 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) return PTR_ERR(rockchip->aclk_rst); } - if (rockchip->is_rc) { - rockchip->ep_gpio = devm_gpiod_get_optional(dev, "ep", - GPIOD_OUT_LOW); - if (IS_ERR(rockchip->ep_gpio)) - return dev_err_probe(dev, PTR_ERR(rockchip->ep_gpio), - "failed to get ep GPIO\n"); - } + if (rockchip->is_rc) + rockchip->perst_gpio = devm_gpiod_get_optional(dev, "ep", + GPIOD_OUT_LOW); + else + rockchip->perst_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_IN); + if (IS_ERR(rockchip->perst_gpio)) + return dev_err_probe(dev, PTR_ERR(rockchip->perst_gpio), + "failed to get PERST# GPIO\n"); rockchip->aclk_pcie = devm_clk_get(dev, "aclk"); if (IS_ERR(rockchip->aclk_pcie)) { @@ -244,11 +246,12 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1, PCIE_CLIENT_CONFIG); - regs = PCIE_CLIENT_LINK_TRAIN_ENABLE | PCIE_CLIENT_ARI_ENABLE | + regs = PCIE_CLIENT_ARI_ENABLE | PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes); if (rockchip->is_rc) - regs |= PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC; + regs |= PCIE_CLIENT_LINK_TRAIN_ENABLE | + PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC; else regs |= PCIE_CLIENT_CONF_DISABLE | PCIE_CLIENT_MODE_EP; diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h index 6111de35f84ca2..a51b087ce87861 100644 --- a/drivers/pci/controller/pcie-rockchip.h +++ b/drivers/pci/controller/pcie-rockchip.h @@ -26,12 +26,14 @@ #define MAX_LANE_NUM 4 #define MAX_REGION_LIMIT 32 #define MIN_EP_APERTURE 28 +#define LINK_TRAIN_TIMEOUT (500 * USEC_PER_MSEC) #define PCIE_CLIENT_BASE 0x0 #define PCIE_CLIENT_CONFIG (PCIE_CLIENT_BASE + 0x00) #define PCIE_CLIENT_CONF_ENABLE HIWORD_UPDATE_BIT(0x0001) #define PCIE_CLIENT_CONF_DISABLE HIWORD_UPDATE(0x0001, 0) #define PCIE_CLIENT_LINK_TRAIN_ENABLE HIWORD_UPDATE_BIT(0x0002) +#define PCIE_CLIENT_LINK_TRAIN_DISABLE HIWORD_UPDATE(0x0002, 0) #define PCIE_CLIENT_ARI_ENABLE HIWORD_UPDATE_BIT(0x0008) #define PCIE_CLIENT_CONF_LANE_NUM(x) HIWORD_UPDATE(0x0030, ENCODE_LANES(x)) #define PCIE_CLIENT_MODE_RC HIWORD_UPDATE_BIT(0x0040) @@ -49,6 +51,10 @@ #define PCIE_CLIENT_DEBUG_LTSSM_MASK GENMASK(5, 0) #define PCIE_CLIENT_DEBUG_LTSSM_L1 0x18 #define PCIE_CLIENT_DEBUG_LTSSM_L2 0x19 +#define PCIE_CLIENT_BASIC_STATUS0 (PCIE_CLIENT_BASE + 0x44) +#define PCIE_CLIENT_NEG_LINK_WIDTH_MASK GENMASK(7, 6) +#define PCIE_CLIENT_NEG_LINK_WIDTH_SHIFT 6 +#define PCIE_CLIENT_NEG_LINK_SPEED BIT(5) #define PCIE_CLIENT_BASIC_STATUS1 (PCIE_CLIENT_BASE + 0x48) #define PCIE_CLIENT_LINK_STATUS_UP 0x00300000 #define PCIE_CLIENT_LINK_STATUS_MASK 0x00300000 @@ -86,6 +92,8 @@ #define PCIE_CORE_CTRL_MGMT_BASE 0x900000 #define PCIE_CORE_CTRL (PCIE_CORE_CTRL_MGMT_BASE + 0x000) +#define PCIE_CORE_PL_CONF_LS_MASK 0x00000001 +#define PCIE_CORE_PL_CONF_LS_READY 0x00000001 #define PCIE_CORE_PL_CONF_SPEED_5G 0x00000008 #define PCIE_CORE_PL_CONF_SPEED_MASK 0x00000018 #define PCIE_CORE_PL_CONF_LANE_MASK 0x00000006 @@ -143,6 +151,7 @@ #define PCIE_RC_CONFIG_BASE 0xa00000 #define PCIE_EP_CONFIG_BASE 0xa00000 #define PCIE_EP_CONFIG_DID_VID (PCIE_EP_CONFIG_BASE + 0x00) +#define PCIE_EP_CONFIG_LCS (PCIE_EP_CONFIG_BASE + 0xd0) #define PCIE_RC_CONFIG_RID_CCR (PCIE_RC_CONFIG_BASE + 0x08) #define PCIE_RC_CONFIG_DCR (PCIE_RC_CONFIG_BASE + 0xc4) #define PCIE_RC_CONFIG_DCR_CSPL_SHIFT 18 @@ -154,6 +163,7 @@ #define PCIE_RC_CONFIG_LINK_CAP (PCIE_RC_CONFIG_BASE + 0xcc) #define PCIE_RC_CONFIG_LINK_CAP_L0S BIT(10) #define PCIE_RC_CONFIG_LCS (PCIE_RC_CONFIG_BASE + 0xd0) +#define PCIE_EP_CONFIG_LCS (PCIE_EP_CONFIG_BASE + 0xd0) #define PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 (PCIE_RC_CONFIG_BASE + 0x90c) #define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274) #define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK GENMASK(31, 20) @@ -191,6 +201,8 @@ #define ROCKCHIP_VENDOR_ID 0x1d87 #define PCIE_LINK_IS_L2(x) \ (((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2) +#define PCIE_LINK_TRAINING_DONE(x) \ + (((x) & PCIE_CORE_PL_CONF_LS_MASK) == PCIE_CORE_PL_CONF_LS_READY) #define PCIE_LINK_UP(x) \ (((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP) #define PCIE_LINK_IS_GEN2(x) \ @@ -241,10 +253,20 @@ #define ROCKCHIP_PCIE_EP_MSIX_CAP_CP_MASK GENMASK(15, 8) #define ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR 0x1 #define ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR 0x3 + +#define ROCKCHIP_PCIE_AT_MIN_NUM_BITS 8 +#define ROCKCHIP_PCIE_AT_MAX_NUM_BITS 20 +#define ROCKCHIP_PCIE_AT_SIZE_ALIGN (1UL << ROCKCHIP_PCIE_AT_MIN_NUM_BITS) + #define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) \ (PCIE_EP_PF_CONFIG_REGS_BASE + (((fn) << 12) & GENMASK(19, 12))) #define ROCKCHIP_PCIE_EP_VIRT_FUNC_BASE(fn) \ (PCIE_EP_PF_CONFIG_REGS_BASE + 0x10000 + (((fn) << 12) & GENMASK(19, 12))) + +#define ROCKCHIP_PCIE_AT_MIN_NUM_BITS 8 +#define ROCKCHIP_PCIE_AT_MAX_NUM_BITS 20 +#define ROCKCHIP_PCIE_AT_SIZE_ALIGN (1UL << ROCKCHIP_PCIE_AT_MIN_NUM_BITS) + #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \ (PCIE_CORE_AXI_CONF_BASE + 0x0828 + (fn) * 0x0040 + (bar) * 0x0008) #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \ @@ -307,7 +329,7 @@ struct rockchip_pcie { struct regulator *vpcie3v3; /* 3.3V power supply */ struct regulator *vpcie1v8; /* 1.8V power supply */ struct regulator *vpcie0v9; /* 0.9V power supply */ - struct gpio_desc *ep_gpio; + struct gpio_desc *perst_gpio; u32 lanes; u8 lanes_map; int link_gen; diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c index a8ae14474dd0a4..8d6e2a89b067b6 100644 --- a/drivers/pci/controller/pcie-xilinx-nwl.c +++ b/drivers/pci/controller/pcie-xilinx-nwl.c @@ -916,6 +916,6 @@ static struct platform_driver nwl_pcie_driver = { .of_match_table = nwl_pcie_of_match, }, .probe = nwl_pcie_probe, - .remove_new = nwl_pcie_remove, + .remove = nwl_pcie_remove, }; builtin_platform_driver(nwl_pcie_driver); diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c index 48f60a04b740ba..6630cacef30105 100644 --- a/drivers/pci/controller/plda/pcie-microchip-host.c +++ b/drivers/pci/controller/plda/pcie-microchip-host.c @@ -25,9 +25,6 @@ #define MC_PCIE1_BRIDGE_ADDR 0x00008000u #define MC_PCIE1_CTRL_ADDR 0x0000a000u -#define MC_PCIE_BRIDGE_ADDR (MC_PCIE1_BRIDGE_ADDR) -#define MC_PCIE_CTRL_ADDR (MC_PCIE1_CTRL_ADDR) - /* PCIe Controller Phy Regs */ #define SEC_ERROR_EVENT_CNT 0x20 #define DED_ERROR_EVENT_CNT 0x24 @@ -128,7 +125,6 @@ [EVENT_LOCAL_ ## x] = { __stringify(x), s } #define PCIE_EVENT(x) \ - .base = MC_PCIE_CTRL_ADDR, \ .offset = PCIE_EVENT_INT, \ .mask_offset = PCIE_EVENT_INT, \ .mask_high = 1, \ @@ -136,7 +132,6 @@ .enb_mask = PCIE_EVENT_INT_ENB_MASK #define SEC_EVENT(x) \ - .base = MC_PCIE_CTRL_ADDR, \ .offset = SEC_ERROR_INT, \ .mask_offset = SEC_ERROR_INT_MASK, \ .mask = SEC_ERROR_INT_ ## x ## _INT, \ @@ -144,7 +139,6 @@ .enb_mask = 0 #define DED_EVENT(x) \ - .base = MC_PCIE_CTRL_ADDR, \ .offset = DED_ERROR_INT, \ .mask_offset = DED_ERROR_INT_MASK, \ .mask_high = 1, \ @@ -152,7 +146,6 @@ .enb_mask = 0 #define LOCAL_EVENT(x) \ - .base = MC_PCIE_BRIDGE_ADDR, \ .offset = ISTATUS_LOCAL, \ .mask_offset = IMASK_LOCAL, \ .mask_high = 0, \ @@ -179,7 +172,8 @@ struct event_map { struct mc_pcie { struct plda_pcie_rp plda; - void __iomem *axi_base_addr; + void __iomem *bridge_base_addr; + void __iomem *ctrl_base_addr; }; struct cause { @@ -253,7 +247,6 @@ static struct event_map local_status_to_event[] = { }; static struct { - u32 base; u32 offset; u32 mask; u32 shift; @@ -325,8 +318,7 @@ static inline u32 reg_to_event(u32 reg, struct event_map field) static u32 pcie_events(struct mc_pcie *port) { - void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; - u32 reg = readl_relaxed(ctrl_base_addr + PCIE_EVENT_INT); + u32 reg = readl_relaxed(port->ctrl_base_addr + PCIE_EVENT_INT); u32 val = 0; int i; @@ -338,8 +330,7 @@ static u32 pcie_events(struct mc_pcie *port) static u32 sec_errors(struct mc_pcie *port) { - void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; - u32 reg = readl_relaxed(ctrl_base_addr + SEC_ERROR_INT); + u32 reg = readl_relaxed(port->ctrl_base_addr + SEC_ERROR_INT); u32 val = 0; int i; @@ -351,8 +342,7 @@ static u32 sec_errors(struct mc_pcie *port) static u32 ded_errors(struct mc_pcie *port) { - void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; - u32 reg = readl_relaxed(ctrl_base_addr + DED_ERROR_INT); + u32 reg = readl_relaxed(port->ctrl_base_addr + DED_ERROR_INT); u32 val = 0; int i; @@ -364,8 +354,7 @@ static u32 ded_errors(struct mc_pcie *port) static u32 local_events(struct mc_pcie *port) { - void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; - u32 reg = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL); + u32 reg = readl_relaxed(port->bridge_base_addr + ISTATUS_LOCAL); u32 val = 0; int i; @@ -412,8 +401,12 @@ static void mc_ack_event_irq(struct irq_data *data) void __iomem *addr; u32 mask; - addr = mc_port->axi_base_addr + event_descs[event].base + - event_descs[event].offset; + if (event_descs[event].offset == ISTATUS_LOCAL) + addr = mc_port->bridge_base_addr; + else + addr = mc_port->ctrl_base_addr; + + addr += event_descs[event].offset; mask = event_descs[event].mask; mask |= event_descs[event].enb_mask; @@ -429,8 +422,12 @@ static void mc_mask_event_irq(struct irq_data *data) u32 mask; u32 val; - addr = mc_port->axi_base_addr + event_descs[event].base + - event_descs[event].mask_offset; + if (event_descs[event].offset == ISTATUS_LOCAL) + addr = mc_port->bridge_base_addr; + else + addr = mc_port->ctrl_base_addr; + + addr += event_descs[event].mask_offset; mask = event_descs[event].mask; if (event_descs[event].enb_mask) { mask <<= PCIE_EVENT_INT_ENB_SHIFT; @@ -460,8 +457,12 @@ static void mc_unmask_event_irq(struct irq_data *data) u32 mask; u32 val; - addr = mc_port->axi_base_addr + event_descs[event].base + - event_descs[event].mask_offset; + if (event_descs[event].offset == ISTATUS_LOCAL) + addr = mc_port->bridge_base_addr; + else + addr = mc_port->ctrl_base_addr; + + addr += event_descs[event].mask_offset; mask = event_descs[event].mask; if (event_descs[event].enb_mask) @@ -554,26 +555,20 @@ static const struct plda_event mc_event = { static inline void mc_clear_secs(struct mc_pcie *port) { - void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; - - writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr + - SEC_ERROR_INT); - writel_relaxed(0, ctrl_base_addr + SEC_ERROR_EVENT_CNT); + writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, + port->ctrl_base_addr + SEC_ERROR_INT); + writel_relaxed(0, port->ctrl_base_addr + SEC_ERROR_EVENT_CNT); } static inline void mc_clear_deds(struct mc_pcie *port) { - void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; - - writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr + - DED_ERROR_INT); - writel_relaxed(0, ctrl_base_addr + DED_ERROR_EVENT_CNT); + writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, + port->ctrl_base_addr + DED_ERROR_INT); + writel_relaxed(0, port->ctrl_base_addr + DED_ERROR_EVENT_CNT); } static void mc_disable_interrupts(struct mc_pcie *port) { - void __iomem *bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; - void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR; u32 val; /* Ensure ECC bypass is enabled */ @@ -581,22 +576,22 @@ static void mc_disable_interrupts(struct mc_pcie *port) ECC_CONTROL_RX_RAM_ECC_BYPASS | ECC_CONTROL_PCIE2AXI_RAM_ECC_BYPASS | ECC_CONTROL_AXI2PCIE_RAM_ECC_BYPASS; - writel_relaxed(val, ctrl_base_addr + ECC_CONTROL); + writel_relaxed(val, port->ctrl_base_addr + ECC_CONTROL); /* Disable SEC errors and clear any outstanding */ - writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, ctrl_base_addr + - SEC_ERROR_INT_MASK); + writel_relaxed(SEC_ERROR_INT_ALL_RAM_SEC_ERR_INT, + port->ctrl_base_addr + SEC_ERROR_INT_MASK); mc_clear_secs(port); /* Disable DED errors and clear any outstanding */ - writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, ctrl_base_addr + - DED_ERROR_INT_MASK); + writel_relaxed(DED_ERROR_INT_ALL_RAM_DED_ERR_INT, + port->ctrl_base_addr + DED_ERROR_INT_MASK); mc_clear_deds(port); /* Disable local interrupts and clear any outstanding */ - writel_relaxed(0, bridge_base_addr + IMASK_LOCAL); - writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_LOCAL); - writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_MSI); + writel_relaxed(0, port->bridge_base_addr + IMASK_LOCAL); + writel_relaxed(GENMASK(31, 0), port->bridge_base_addr + ISTATUS_LOCAL); + writel_relaxed(GENMASK(31, 0), port->bridge_base_addr + ISTATUS_MSI); /* Disable PCIe events and clear any outstanding */ val = PCIE_EVENT_INT_L2_EXIT_INT | @@ -605,11 +600,11 @@ static void mc_disable_interrupts(struct mc_pcie *port) PCIE_EVENT_INT_L2_EXIT_INT_MASK | PCIE_EVENT_INT_HOTRST_EXIT_INT_MASK | PCIE_EVENT_INT_DLUP_EXIT_INT_MASK; - writel_relaxed(val, ctrl_base_addr + PCIE_EVENT_INT); + writel_relaxed(val, port->ctrl_base_addr + PCIE_EVENT_INT); /* Disable host interrupts and clear any outstanding */ - writel_relaxed(0, bridge_base_addr + IMASK_HOST); - writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST); + writel_relaxed(0, port->bridge_base_addr + IMASK_HOST); + writel_relaxed(GENMASK(31, 0), port->bridge_base_addr + ISTATUS_HOST); } static int mc_platform_init(struct pci_config_window *cfg) @@ -617,12 +612,10 @@ static int mc_platform_init(struct pci_config_window *cfg) struct device *dev = cfg->parent; struct platform_device *pdev = to_platform_device(dev); struct pci_host_bridge *bridge = platform_get_drvdata(pdev); - void __iomem *bridge_base_addr = - port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; int ret; /* Configure address translation table 0 for PCIe config space */ - plda_pcie_setup_window(bridge_base_addr, 0, cfg->res.start, + plda_pcie_setup_window(port->bridge_base_addr, 0, cfg->res.start, cfg->res.start, resource_size(&cfg->res)); @@ -649,7 +642,7 @@ static int mc_platform_init(struct pci_config_window *cfg) static int mc_host_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - void __iomem *bridge_base_addr; + void __iomem *apb_base_addr; struct plda_pcie_rp *plda; int ret; u32 val; @@ -661,30 +654,45 @@ static int mc_host_probe(struct platform_device *pdev) plda = &port->plda; plda->dev = dev; - port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(port->axi_base_addr)) - return PTR_ERR(port->axi_base_addr); + port->bridge_base_addr = devm_platform_ioremap_resource_byname(pdev, + "bridge"); + port->ctrl_base_addr = devm_platform_ioremap_resource_byname(pdev, + "ctrl"); + if (!IS_ERR(port->bridge_base_addr) && !IS_ERR(port->ctrl_base_addr)) + goto addrs_set; + + /* + * The original, incorrect, binding that lumped the control and + * bridge addresses together still needs to be handled by the driver. + */ + apb_base_addr = devm_platform_ioremap_resource_byname(pdev, "apb"); + if (IS_ERR(apb_base_addr)) + return dev_err_probe(dev, PTR_ERR(apb_base_addr), + "both legacy apb register and ctrl/bridge regions missing"); + + port->bridge_base_addr = apb_base_addr + MC_PCIE1_BRIDGE_ADDR; + port->ctrl_base_addr = apb_base_addr + MC_PCIE1_CTRL_ADDR; +addrs_set: mc_disable_interrupts(port); - bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR; - plda->bridge_addr = bridge_base_addr; + plda->bridge_addr = port->bridge_base_addr; plda->num_events = NUM_EVENTS; /* Allow enabling MSI by disabling MSI-X */ - val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0); + val = readl(port->bridge_base_addr + PCIE_PCI_IRQ_DW0); val &= ~MSIX_CAP_MASK; - writel(val, bridge_base_addr + PCIE_PCI_IRQ_DW0); + writel(val, port->bridge_base_addr + PCIE_PCI_IRQ_DW0); /* Pick num vectors from bitfile programmed onto FPGA fabric */ - val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0); + val = readl(port->bridge_base_addr + PCIE_PCI_IRQ_DW0); val &= NUM_MSI_MSGS_MASK; val >>= NUM_MSI_MSGS_SHIFT; plda->msi.num_vectors = 1 << val; /* Pick vector address from design */ - plda->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR); + plda->msi.vector_phy = readl_relaxed(port->bridge_base_addr + IMSI_ADDR); ret = mc_pcie_init_clks(dev); if (ret) { diff --git a/drivers/pci/controller/plda/pcie-starfive.c b/drivers/pci/controller/plda/pcie-starfive.c index c9933ecf683382..e73c1b7bc8efc4 100644 --- a/drivers/pci/controller/plda/pcie-starfive.c +++ b/drivers/pci/controller/plda/pcie-starfive.c @@ -404,6 +404,9 @@ static int starfive_pcie_probe(struct platform_device *pdev) if (ret) return ret; + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + plda->host_ops = &sf_host_ops; plda->num_events = PLDA_MAX_EVENT_NUM; /* mask doorbell event */ @@ -413,11 +416,12 @@ static int starfive_pcie_probe(struct platform_device *pdev) plda->events_bitmap <<= PLDA_NUM_DMA_EVENTS; ret = plda_pcie_host_init(&pcie->plda, &starfive_pcie_ops, &stf_pcie_event); - if (ret) + if (ret) { + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); return ret; + } - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); platform_set_drvdata(pdev, pcie); return 0; @@ -480,7 +484,7 @@ static struct platform_driver starfive_pcie_driver = { .pm = pm_sleep_ptr(&starfive_pcie_pm_ops), }, .probe = starfive_pcie_probe, - .remove_new = starfive_pcie_remove, + .remove = starfive_pcie_remove, }; module_platform_driver(starfive_pcie_driver); diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c index 264a180403a0ec..9d9596947350f5 100644 --- a/drivers/pci/controller/vmd.c +++ b/drivers/pci/controller/vmd.c @@ -740,11 +740,9 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata) if (!(features & VMD_FEAT_BIOS_PM_QUIRK)) return 0; - pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL); - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR); if (!pos) - return 0; + goto out_state_change; /* * Skip if the max snoop LTR is non-zero, indicating BIOS has set it @@ -752,7 +750,7 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata) */ pci_read_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, <r_reg); if (!!(ltr_reg & (PCI_LTR_VALUE_MASK | PCI_LTR_SCALE_MASK))) - return 0; + goto out_state_change; /* * Set the default values to the maximum required by the platform to @@ -764,6 +762,13 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata) pci_write_config_dword(pdev, pos + PCI_LTR_MAX_SNOOP_LAT, ltr_reg); pci_info(pdev, "VMD: Default LTR value set by driver\n"); +out_state_change: + /* + * Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per + * PCIe r6.0, sec 5.5.4. + */ + pci_set_power_state_locked(pdev, PCI_D0); + pci_enable_link_state_locked(pdev, PCIE_LINK_STATE_ALL); return 0; } @@ -1100,6 +1105,10 @@ static const struct pci_device_id vmd_ids[] = { .driver_data = VMD_FEATS_CLIENT,}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B), .driver_data = VMD_FEATS_CLIENT,}, + {PCI_VDEVICE(INTEL, 0xb60b), + .driver_data = VMD_FEATS_CLIENT,}, + {PCI_VDEVICE(INTEL, 0xb06f), + .driver_data = VMD_FEATS_CLIENT,}, {0,} }; MODULE_DEVICE_TABLE(pci, vmd_ids); diff --git a/drivers/pci/devres.c b/drivers/pci/devres.c index b133967faef840..3b59a86a764b11 100644 --- a/drivers/pci/devres.c +++ b/drivers/pci/devres.c @@ -773,7 +773,7 @@ EXPORT_SYMBOL(pcim_iomap_region); * Unmap a BAR and release its region manually. Only pass BARs that were * previously mapped by pcim_iomap_region(). */ -static void pcim_iounmap_region(struct pci_dev *pdev, int bar) +void pcim_iounmap_region(struct pci_dev *pdev, int bar) { struct pcim_addr_devres res_searched; @@ -784,6 +784,7 @@ static void pcim_iounmap_region(struct pci_dev *pdev, int bar) devres_release(&pdev->dev, pcim_addr_resource_release, pcim_addr_resources_match, &res_searched); } +EXPORT_SYMBOL(pcim_iounmap_region); /** * pcim_iomap_regions - Request and iomap PCI BARs (DEPRECATED) @@ -939,7 +940,7 @@ static void pcim_release_all_regions(struct pci_dev *pdev) * desired, release individual regions with pcim_release_region() or all of * them at once with pcim_release_all_regions(). */ -static int pcim_request_all_regions(struct pci_dev *pdev, const char *name) +int pcim_request_all_regions(struct pci_dev *pdev, const char *name) { int ret; int bar; @@ -957,69 +958,17 @@ static int pcim_request_all_regions(struct pci_dev *pdev, const char *name) return ret; } +EXPORT_SYMBOL(pcim_request_all_regions); /** - * pcim_iomap_regions_request_all - Request all BARs and iomap specified ones - * (DEPRECATED) - * @pdev: PCI device to map IO resources for - * @mask: Mask of BARs to iomap - * @name: Name associated with the requests - * - * Returns: 0 on success, negative error code on failure. - * - * Request all PCI BARs and iomap regions specified by @mask. - * - * To release these resources manually, call pcim_release_region() for the - * regions and pcim_iounmap() for the mappings. - * - * This function is DEPRECATED. Don't use it in new code. Instead, use one - * of the pcim_* region request functions in combination with a pcim_* - * mapping function. - */ -int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask, - const char *name) -{ - int bar; - int ret; - void __iomem **legacy_iomap_table; - - ret = pcim_request_all_regions(pdev, name); - if (ret != 0) - return ret; - - for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) { - if (!mask_contains_bar(mask, bar)) - continue; - if (!pcim_iomap(pdev, bar, 0)) - goto err; - } - - return 0; - -err: - /* - * If bar is larger than 0, then pcim_iomap() above has most likely - * failed because of -EINVAL. If it is equal 0, most likely the table - * couldn't be created, indicating -ENOMEM. - */ - ret = bar > 0 ? -EINVAL : -ENOMEM; - legacy_iomap_table = (void __iomem **)pcim_iomap_table(pdev); - - while (--bar >= 0) - pcim_iounmap(pdev, legacy_iomap_table[bar]); - - pcim_release_all_regions(pdev); - - return ret; -} -EXPORT_SYMBOL(pcim_iomap_regions_request_all); - -/** - * pcim_iounmap_regions - Unmap and release PCI BARs + * pcim_iounmap_regions - Unmap and release PCI BARs (DEPRECATED) * @pdev: PCI device to map IO resources for * @mask: Mask of BARs to unmap and release * * Unmap and release regions specified by @mask. + * + * This function is DEPRECATED. Do not use it in new code. + * Use pcim_iounmap_region() instead. */ void pcim_iounmap_regions(struct pci_dev *pdev, int mask) { diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c index 652d63df9d22e5..7bd7892c522289 100644 --- a/drivers/pci/doe.c +++ b/drivers/pci/doe.c @@ -146,6 +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; + unsigned long timeout_jiffies; size_t length, remainder; u32 val; int i; @@ -155,8 +156,19 @@ static int pci_doe_send_req(struct pci_doe_mb *doe_mb, * someone other than Linux (e.g. firmware) is using the mailbox. Note * it is expected that firmware and OS will negotiate access rights via * an, as yet to be defined, method. + * + * Wait up to one PCI_DOE_TIMEOUT period to allow the prior command to + * finish. Otherwise, simply error out as unable to field the request. + * + * PCIe r6.2 sec 6.30.3 states no interrupt is raised when the DOE Busy + * bit is cleared, so polling here is our best option for the moment. */ - pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); + timeout_jiffies = jiffies + PCI_DOE_TIMEOUT; + do { + pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); + } while (FIELD_GET(PCI_DOE_STATUS_BUSY, val) && + !time_after(jiffies, timeout_jiffies)); + if (FIELD_GET(PCI_DOE_STATUS_BUSY, val)) return -EBUSY; diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c index 1c40d2506aef34..260b7de2dbd578 100644 --- a/drivers/pci/ecam.c +++ b/drivers/pci/ecam.c @@ -55,7 +55,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev, bus_range_max = resource_size(cfgres) >> bus_shift; if (bus_range > bus_range_max) { bus_range = bus_range_max; - cfg->busr.end = busr->start + bus_range - 1; + resource_set_size(&cfg->busr, bus_range); dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n", cfgres, &cfg->busr, busr); } diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c index 7d070b1def1166..54286a40bdfbf7 100644 --- a/drivers/pci/endpoint/functions/pci-epf-mhi.c +++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c @@ -867,12 +867,18 @@ static int pci_epf_mhi_bind(struct pci_epf *epf) { struct pci_epf_mhi *epf_mhi = epf_get_drvdata(epf); struct pci_epc *epc = epf->epc; + struct device *dev = &epf->dev; struct platform_device *pdev = to_platform_device(epc->dev.parent); struct resource *res; int ret; /* Get MMIO base address from Endpoint controller */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mmio"); + if (!res) { + dev_err(dev, "Failed to get \"mmio\" resource\n"); + return -ENODEV; + } + epf_mhi->mmio_phys = res->start; epf_mhi->mmio_size = resource_size(res); diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index 7c2ed6eae53ad1..ef6677f34116e1 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -291,8 +291,6 @@ static void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test) dma_release_channel(epf_test->dma_chan_rx); epf_test->dma_chan_rx = NULL; - - return; } static void pci_epf_test_print_rate(struct pci_epf_test *epf_test, @@ -317,91 +315,92 @@ static void pci_epf_test_print_rate(struct pci_epf_test *epf_test, static void pci_epf_test_copy(struct pci_epf_test *epf_test, struct pci_epf_test_reg *reg) { - int ret; - void __iomem *src_addr; - void __iomem *dst_addr; - phys_addr_t src_phys_addr; - phys_addr_t dst_phys_addr; + int ret = 0; struct timespec64 start, end; struct pci_epf *epf = epf_test->epf; - struct device *dev = &epf->dev; struct pci_epc *epc = epf->epc; + struct device *dev = &epf->dev; + struct pci_epc_map src_map, dst_map; + u64 src_addr = reg->src_addr; + u64 dst_addr = reg->dst_addr; + size_t copy_size = reg->size; + ssize_t map_size = 0; + void *copy_buf = NULL, *buf; - src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size); - if (!src_addr) { - dev_err(dev, "Failed to allocate source address\n"); - reg->status = STATUS_SRC_ADDR_INVALID; - ret = -ENOMEM; - goto err; - } - - ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, src_phys_addr, - reg->src_addr, reg->size); - if (ret) { - dev_err(dev, "Failed to map source address\n"); - reg->status = STATUS_SRC_ADDR_INVALID; - goto err_src_addr; - } - - dst_addr = pci_epc_mem_alloc_addr(epc, &dst_phys_addr, reg->size); - if (!dst_addr) { - dev_err(dev, "Failed to allocate destination address\n"); - reg->status = STATUS_DST_ADDR_INVALID; - ret = -ENOMEM; - goto err_src_map_addr; - } - - ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, dst_phys_addr, - reg->dst_addr, reg->size); - if (ret) { - dev_err(dev, "Failed to map destination address\n"); - reg->status = STATUS_DST_ADDR_INVALID; - goto err_dst_addr; - } - - ktime_get_ts64(&start); if (reg->flags & FLAG_USE_DMA) { if (epf_test->dma_private) { dev_err(dev, "Cannot transfer data using DMA\n"); ret = -EINVAL; - goto err_map_addr; + goto set_status; } - - ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr, - src_phys_addr, reg->size, 0, - DMA_MEM_TO_MEM); - if (ret) - dev_err(dev, "Data transfer failed\n"); } else { - void *buf; - - buf = kzalloc(reg->size, GFP_KERNEL); - if (!buf) { + copy_buf = kzalloc(copy_size, GFP_KERNEL); + if (!copy_buf) { ret = -ENOMEM; - goto err_map_addr; + goto set_status; } - - memcpy_fromio(buf, src_addr, reg->size); - memcpy_toio(dst_addr, buf, reg->size); - kfree(buf); + buf = copy_buf; } - ktime_get_ts64(&end); - pci_epf_test_print_rate(epf_test, "COPY", reg->size, &start, &end, - reg->flags & FLAG_USE_DMA); -err_map_addr: - pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, dst_phys_addr); + while (copy_size) { + ret = pci_epc_mem_map(epc, epf->func_no, epf->vfunc_no, + src_addr, copy_size, &src_map); + if (ret) { + dev_err(dev, "Failed to map source address\n"); + reg->status = STATUS_SRC_ADDR_INVALID; + goto free_buf; + } + + ret = pci_epc_mem_map(epf->epc, epf->func_no, epf->vfunc_no, + dst_addr, copy_size, &dst_map); + if (ret) { + dev_err(dev, "Failed to map destination address\n"); + reg->status = STATUS_DST_ADDR_INVALID; + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, + &src_map); + goto free_buf; + } -err_dst_addr: - pci_epc_mem_free_addr(epc, dst_phys_addr, dst_addr, reg->size); + map_size = min_t(size_t, dst_map.pci_size, src_map.pci_size); -err_src_map_addr: - pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, src_phys_addr); + ktime_get_ts64(&start); + if (reg->flags & FLAG_USE_DMA) { + ret = pci_epf_test_data_transfer(epf_test, + dst_map.phys_addr, src_map.phys_addr, + map_size, 0, DMA_MEM_TO_MEM); + if (ret) { + dev_err(dev, "Data transfer failed\n"); + goto unmap; + } + } else { + memcpy_fromio(buf, src_map.virt_addr, map_size); + memcpy_toio(dst_map.virt_addr, buf, map_size); + buf += map_size; + } + ktime_get_ts64(&end); -err_src_addr: - pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size); + copy_size -= map_size; + src_addr += map_size; + dst_addr += map_size; -err: + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, &dst_map); + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, &src_map); + map_size = 0; + } + + pci_epf_test_print_rate(epf_test, "COPY", reg->size, &start, + &end, reg->flags & FLAG_USE_DMA); + +unmap: + if (map_size) { + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, &dst_map); + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, &src_map); + } + +free_buf: + kfree(copy_buf); + +set_status: if (!ret) reg->status |= STATUS_COPY_SUCCESS; else @@ -411,82 +410,89 @@ static void pci_epf_test_copy(struct pci_epf_test *epf_test, static void pci_epf_test_read(struct pci_epf_test *epf_test, struct pci_epf_test_reg *reg) { - int ret; - void __iomem *src_addr; - void *buf; + int ret = 0; + void *src_buf, *buf; u32 crc32; - phys_addr_t phys_addr; + struct pci_epc_map map; phys_addr_t dst_phys_addr; struct timespec64 start, end; struct pci_epf *epf = epf_test->epf; - struct device *dev = &epf->dev; struct pci_epc *epc = epf->epc; + struct device *dev = &epf->dev; struct device *dma_dev = epf->epc->dev.parent; + u64 src_addr = reg->src_addr; + size_t src_size = reg->size; + ssize_t map_size = 0; - src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size); - if (!src_addr) { - dev_err(dev, "Failed to allocate address\n"); - reg->status = STATUS_SRC_ADDR_INVALID; + src_buf = kzalloc(src_size, GFP_KERNEL); + if (!src_buf) { ret = -ENOMEM; - goto err; + goto set_status; } + buf = src_buf; - ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr, - reg->src_addr, reg->size); - if (ret) { - dev_err(dev, "Failed to map address\n"); - reg->status = STATUS_SRC_ADDR_INVALID; - goto err_addr; - } - - buf = kzalloc(reg->size, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto err_map_addr; - } + while (src_size) { + ret = pci_epc_mem_map(epc, epf->func_no, epf->vfunc_no, + src_addr, src_size, &map); + if (ret) { + dev_err(dev, "Failed to map address\n"); + reg->status = STATUS_SRC_ADDR_INVALID; + goto free_buf; + } - if (reg->flags & FLAG_USE_DMA) { - dst_phys_addr = dma_map_single(dma_dev, buf, reg->size, - DMA_FROM_DEVICE); - if (dma_mapping_error(dma_dev, dst_phys_addr)) { - dev_err(dev, "Failed to map destination buffer addr\n"); - ret = -ENOMEM; - goto err_dma_map; + map_size = map.pci_size; + if (reg->flags & FLAG_USE_DMA) { + dst_phys_addr = dma_map_single(dma_dev, buf, map_size, + DMA_FROM_DEVICE); + if (dma_mapping_error(dma_dev, dst_phys_addr)) { + dev_err(dev, + "Failed to map destination buffer addr\n"); + ret = -ENOMEM; + goto unmap; + } + + ktime_get_ts64(&start); + ret = pci_epf_test_data_transfer(epf_test, + dst_phys_addr, map.phys_addr, + map_size, src_addr, DMA_DEV_TO_MEM); + if (ret) + dev_err(dev, "Data transfer failed\n"); + ktime_get_ts64(&end); + + dma_unmap_single(dma_dev, dst_phys_addr, map_size, + DMA_FROM_DEVICE); + + if (ret) + goto unmap; + } else { + ktime_get_ts64(&start); + memcpy_fromio(buf, map.virt_addr, map_size); + ktime_get_ts64(&end); } - ktime_get_ts64(&start); - ret = pci_epf_test_data_transfer(epf_test, dst_phys_addr, - phys_addr, reg->size, - reg->src_addr, DMA_DEV_TO_MEM); - if (ret) - dev_err(dev, "Data transfer failed\n"); - ktime_get_ts64(&end); + src_size -= map_size; + src_addr += map_size; + buf += map_size; - dma_unmap_single(dma_dev, dst_phys_addr, reg->size, - DMA_FROM_DEVICE); - } else { - ktime_get_ts64(&start); - memcpy_fromio(buf, src_addr, reg->size); - ktime_get_ts64(&end); + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, &map); + map_size = 0; } - pci_epf_test_print_rate(epf_test, "READ", reg->size, &start, &end, - reg->flags & FLAG_USE_DMA); + pci_epf_test_print_rate(epf_test, "READ", reg->size, &start, + &end, reg->flags & FLAG_USE_DMA); - crc32 = crc32_le(~0, buf, reg->size); + crc32 = crc32_le(~0, src_buf, reg->size); if (crc32 != reg->checksum) ret = -EIO; -err_dma_map: - kfree(buf); - -err_map_addr: - pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, phys_addr); +unmap: + if (map_size) + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, &map); -err_addr: - pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size); +free_buf: + kfree(src_buf); -err: +set_status: if (!ret) reg->status |= STATUS_READ_SUCCESS; else @@ -496,71 +502,79 @@ static void pci_epf_test_read(struct pci_epf_test *epf_test, static void pci_epf_test_write(struct pci_epf_test *epf_test, struct pci_epf_test_reg *reg) { - int ret; - void __iomem *dst_addr; - void *buf; - phys_addr_t phys_addr; + int ret = 0; + void *dst_buf, *buf; + struct pci_epc_map map; phys_addr_t src_phys_addr; struct timespec64 start, end; struct pci_epf *epf = epf_test->epf; - struct device *dev = &epf->dev; struct pci_epc *epc = epf->epc; + struct device *dev = &epf->dev; struct device *dma_dev = epf->epc->dev.parent; + u64 dst_addr = reg->dst_addr; + size_t dst_size = reg->size; + ssize_t map_size = 0; - dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size); - if (!dst_addr) { - dev_err(dev, "Failed to allocate address\n"); - reg->status = STATUS_DST_ADDR_INVALID; + dst_buf = kzalloc(dst_size, GFP_KERNEL); + if (!dst_buf) { ret = -ENOMEM; - goto err; + goto set_status; } + get_random_bytes(dst_buf, dst_size); + reg->checksum = crc32_le(~0, dst_buf, dst_size); + buf = dst_buf; - ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr, - reg->dst_addr, reg->size); - if (ret) { - dev_err(dev, "Failed to map address\n"); - reg->status = STATUS_DST_ADDR_INVALID; - goto err_addr; - } - - buf = kzalloc(reg->size, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto err_map_addr; - } - - get_random_bytes(buf, reg->size); - reg->checksum = crc32_le(~0, buf, reg->size); - - if (reg->flags & FLAG_USE_DMA) { - src_phys_addr = dma_map_single(dma_dev, buf, reg->size, - DMA_TO_DEVICE); - if (dma_mapping_error(dma_dev, src_phys_addr)) { - dev_err(dev, "Failed to map source buffer addr\n"); - ret = -ENOMEM; - goto err_dma_map; + while (dst_size) { + ret = pci_epc_mem_map(epc, epf->func_no, epf->vfunc_no, + dst_addr, dst_size, &map); + if (ret) { + dev_err(dev, "Failed to map address\n"); + reg->status = STATUS_DST_ADDR_INVALID; + goto free_buf; } - ktime_get_ts64(&start); + map_size = map.pci_size; + if (reg->flags & FLAG_USE_DMA) { + src_phys_addr = dma_map_single(dma_dev, buf, map_size, + DMA_TO_DEVICE); + if (dma_mapping_error(dma_dev, src_phys_addr)) { + dev_err(dev, + "Failed to map source buffer addr\n"); + ret = -ENOMEM; + goto unmap; + } + + ktime_get_ts64(&start); + + ret = pci_epf_test_data_transfer(epf_test, + map.phys_addr, src_phys_addr, + map_size, dst_addr, + DMA_MEM_TO_DEV); + if (ret) + dev_err(dev, "Data transfer failed\n"); + ktime_get_ts64(&end); + + dma_unmap_single(dma_dev, src_phys_addr, map_size, + DMA_TO_DEVICE); + + if (ret) + goto unmap; + } else { + ktime_get_ts64(&start); + memcpy_toio(map.virt_addr, buf, map_size); + ktime_get_ts64(&end); + } - ret = pci_epf_test_data_transfer(epf_test, phys_addr, - src_phys_addr, reg->size, - reg->dst_addr, - DMA_MEM_TO_DEV); - if (ret) - dev_err(dev, "Data transfer failed\n"); - ktime_get_ts64(&end); + dst_size -= map_size; + dst_addr += map_size; + buf += map_size; - dma_unmap_single(dma_dev, src_phys_addr, reg->size, - DMA_TO_DEVICE); - } else { - ktime_get_ts64(&start); - memcpy_toio(dst_addr, buf, reg->size); - ktime_get_ts64(&end); + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, &map); + map_size = 0; } - pci_epf_test_print_rate(epf_test, "WRITE", reg->size, &start, &end, - reg->flags & FLAG_USE_DMA); + pci_epf_test_print_rate(epf_test, "WRITE", reg->size, &start, + &end, reg->flags & FLAG_USE_DMA); /* * wait 1ms inorder for the write to complete. Without this delay L3 @@ -568,16 +582,14 @@ static void pci_epf_test_write(struct pci_epf_test *epf_test, */ usleep_range(1000, 2000); -err_dma_map: - kfree(buf); - -err_map_addr: - pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, phys_addr); +unmap: + if (map_size) + pci_epc_mem_unmap(epc, epf->func_no, epf->vfunc_no, &map); -err_addr: - pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size); +free_buf: + kfree(dst_buf); -err: +set_status: if (!ret) reg->status |= STATUS_WRITE_SUCCESS; else @@ -786,7 +798,7 @@ static void pci_epf_test_epc_deinit(struct pci_epf *epf) { struct pci_epf_test *epf_test = epf_get_drvdata(epf); - cancel_delayed_work(&epf_test->cmd_handler); + cancel_delayed_work_sync(&epf_test->cmd_handler); pci_epf_test_clean_dma_chan(epf_test); pci_epf_test_clear_bar(epf); } @@ -917,7 +929,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf) struct pci_epf_test *epf_test = epf_get_drvdata(epf); struct pci_epc *epc = epf->epc; - cancel_delayed_work(&epf_test->cmd_handler); + cancel_delayed_work_sync(&epf_test->cmd_handler); if (epc->init_complete) { pci_epf_test_clean_dma_chan(epf_test); pci_epf_test_clear_bar(epf); diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 17f00710925508..bed7c7d1fe3c37 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -128,6 +128,18 @@ enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features } EXPORT_SYMBOL_GPL(pci_epc_get_next_free_bar); +static bool pci_epc_function_is_valid(struct pci_epc *epc, + u8 func_no, u8 vfunc_no) +{ + if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) + return false; + + if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + return false; + + return true; +} + /** * pci_epc_get_features() - get the features supported by EPC * @epc: the features supported by *this* EPC device will be returned @@ -145,10 +157,7 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc, { const struct pci_epc_features *epc_features; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) - return NULL; - - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return NULL; if (!epc->ops->get_features) @@ -218,10 +227,7 @@ int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no, { int ret; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) - return -EINVAL; - - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; if (!epc->ops->raise_irq) @@ -262,10 +268,7 @@ int pci_epc_map_msi_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no, { int ret; - if (IS_ERR_OR_NULL(epc)) - return -EINVAL; - - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; if (!epc->ops->map_msi_irq) @@ -293,10 +296,7 @@ int pci_epc_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no) { int interrupt; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) - return 0; - - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return 0; if (!epc->ops->get_msi) @@ -329,11 +329,10 @@ int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no, u8 interrupts) int ret; u8 encode_int; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || - interrupts < 1 || interrupts > 32) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (interrupts < 1 || interrupts > 32) return -EINVAL; if (!epc->ops->set_msi) @@ -361,10 +360,7 @@ int pci_epc_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no) { int interrupt; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) - return 0; - - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return 0; if (!epc->ops->get_msix) @@ -397,11 +393,10 @@ int pci_epc_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no, { int ret; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || - interrupts < 1 || interrupts > 2048) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (interrupts < 1 || interrupts > 2048) return -EINVAL; if (!epc->ops->set_msix) @@ -428,10 +423,7 @@ EXPORT_SYMBOL_GPL(pci_epc_set_msix); void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, phys_addr_t phys_addr) { - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) - return; - - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return; if (!epc->ops->unmap_addr) @@ -459,10 +451,7 @@ int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, { int ret; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) - return -EINVAL; - - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; if (!epc->ops->map_addr) @@ -477,6 +466,109 @@ int pci_epc_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, } EXPORT_SYMBOL_GPL(pci_epc_map_addr); +/** + * pci_epc_mem_map() - allocate and map a PCI address to a CPU address + * @epc: the EPC device on which the CPU address is to be allocated and mapped + * @func_no: the physical endpoint function number in the EPC device + * @vfunc_no: the virtual endpoint function number in the physical function + * @pci_addr: PCI address to which the CPU address should be mapped + * @pci_size: the number of bytes to map starting from @pci_addr + * @map: where to return the mapping information + * + * Allocate a controller memory address region and map it to a RC PCI address + * region, taking into account the controller physical address mapping + * constraints using the controller operation align_addr(). If this operation is + * not defined, we assume that there are no alignment constraints for the + * mapping. + * + * The effective size of the PCI address range mapped from @pci_addr is + * indicated by @map->pci_size. This size may be less than the requested + * @pci_size. The local virtual CPU address for the mapping is indicated by + * @map->virt_addr (@map->phys_addr indicates the physical address). + * The size and CPU address of the controller memory allocated and mapped are + * respectively indicated by @map->map_size and @map->virt_base (and + * @map->phys_base for the physical address of @map->virt_base). + * + * Returns 0 on success and a negative error code in case of error. + */ +int pci_epc_mem_map(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + u64 pci_addr, size_t pci_size, struct pci_epc_map *map) +{ + size_t map_size = pci_size; + size_t map_offset = 0; + int ret; + + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) + return -EINVAL; + + if (!pci_size || !map) + return -EINVAL; + + /* + * Align the PCI address to map. If the controller defines the + * .align_addr() operation, use it to determine the PCI address to map + * and the size of the mapping. Otherwise, assume that the controller + * has no alignment constraint. + */ + memset(map, 0, sizeof(*map)); + map->pci_addr = pci_addr; + if (epc->ops->align_addr) + map->map_pci_addr = + epc->ops->align_addr(epc, pci_addr, + &map_size, &map_offset); + else + map->map_pci_addr = pci_addr; + map->map_size = map_size; + if (map->map_pci_addr + map->map_size < pci_addr + pci_size) + map->pci_size = map->map_pci_addr + map->map_size - pci_addr; + else + map->pci_size = pci_size; + + map->virt_base = pci_epc_mem_alloc_addr(epc, &map->phys_base, + map->map_size); + if (!map->virt_base) + return -ENOMEM; + + map->phys_addr = map->phys_base + map_offset; + map->virt_addr = map->virt_base + map_offset; + + ret = pci_epc_map_addr(epc, func_no, vfunc_no, map->phys_base, + map->map_pci_addr, map->map_size); + if (ret) { + pci_epc_mem_free_addr(epc, map->phys_base, map->virt_base, + map->map_size); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(pci_epc_mem_map); + +/** + * pci_epc_mem_unmap() - unmap and free a CPU address region + * @epc: the EPC device on which the CPU address is allocated and mapped + * @func_no: the physical endpoint function number in the EPC device + * @vfunc_no: the virtual endpoint function number in the physical function + * @map: the mapping information + * + * Unmap and free a CPU address region that was allocated and mapped with + * pci_epc_mem_map(). + */ +void pci_epc_mem_unmap(struct pci_epc *epc, u8 func_no, u8 vfunc_no, + struct pci_epc_map *map) +{ + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) + return; + + if (!map || !map->virt_base) + return; + + pci_epc_unmap_addr(epc, func_no, vfunc_no, map->phys_base); + pci_epc_mem_free_addr(epc, map->phys_base, map->virt_base, + map->map_size); +} +EXPORT_SYMBOL_GPL(pci_epc_mem_unmap); + /** * pci_epc_clear_bar() - reset the BAR * @epc: the EPC device for which the BAR has to be cleared @@ -489,12 +581,11 @@ EXPORT_SYMBOL_GPL(pci_epc_map_addr); void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct pci_epf_bar *epf_bar) { - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || - (epf_bar->barno == BAR_5 && - epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return; - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (epf_bar->barno == BAR_5 && + epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) return; if (!epc->ops->clear_bar) @@ -521,18 +612,16 @@ int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, int ret; int flags = epf_bar->flags; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions || - (epf_bar->barno == BAR_5 && - flags & PCI_BASE_ADDRESS_MEM_TYPE_64) || + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) + return -EINVAL; + + if ((epf_bar->barno == BAR_5 && flags & PCI_BASE_ADDRESS_MEM_TYPE_64) || (flags & PCI_BASE_ADDRESS_SPACE_IO && flags & PCI_BASE_ADDRESS_IO_MASK) || (upper_32_bits(epf_bar->size) && !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64))) return -EINVAL; - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) - return -EINVAL; - if (!epc->ops->set_bar) return 0; @@ -561,10 +650,7 @@ int pci_epc_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, { int ret; - if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions) - return -EINVAL; - - if (vfunc_no > 0 && (!epc->max_vfs || vfunc_no > epc->max_vfs[func_no])) + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) return -EINVAL; /* Only Virtual Function #1 has deviceID */ @@ -660,18 +746,18 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf, if (IS_ERR_OR_NULL(epc) || !epf) return; + mutex_lock(&epc->list_lock); if (type == PRIMARY_INTERFACE) { func_no = epf->func_no; list = &epf->list; + epf->epc = NULL; } else { func_no = epf->sec_epc_func_no; list = &epf->sec_epc_list; + epf->sec_epc = NULL; } - - mutex_lock(&epc->list_lock); clear_bit(func_no, &epc->function_num_map); list_del(list); - epf->epc = NULL; mutex_unlock(&epc->list_lock); } EXPORT_SYMBOL_GPL(pci_epc_remove_epf); @@ -837,11 +923,10 @@ EXPORT_SYMBOL_GPL(pci_epc_bus_master_enable_notify); void pci_epc_destroy(struct pci_epc *epc) { pci_ep_cfs_remove_epc_group(epc->group); - device_unregister(&epc->dev); - #ifdef CONFIG_PCI_DOMAINS_GENERIC - pci_bus_release_domain_nr(&epc->dev, epc->domain_nr); + pci_bus_release_domain_nr(epc->dev.parent, epc->domain_nr); #endif + device_unregister(&epc->dev); } EXPORT_SYMBOL_GPL(pci_epc_destroy); diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c index a9c028f58da174..218a60e945db65 100644 --- a/drivers/pci/endpoint/pci-epc-mem.c +++ b/drivers/pci/endpoint/pci-epc-mem.c @@ -178,7 +178,7 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_exit); void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, phys_addr_t *phys_addr, size_t size) { - void __iomem *virt_addr = NULL; + void __iomem *virt_addr; struct pci_epc_mem *mem; unsigned int page_shift; size_t align_size; @@ -188,10 +188,13 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, for (i = 0; i < epc->num_windows; i++) { mem = epc->windows[i]; - mutex_lock(&mem->lock); + if (size > mem->window.size) + continue; + align_size = ALIGN(size, mem->window.page_size); order = pci_epc_mem_get_order(mem, align_size); + mutex_lock(&mem->lock); pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order); if (pageno >= 0) { @@ -211,7 +214,7 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, mutex_unlock(&mem->lock); } - return virt_addr; + return NULL; } EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig index 1472aef0fb812d..123c4c7c2ab596 100644 --- a/drivers/pci/hotplug/Kconfig +++ b/drivers/pci/hotplug/Kconfig @@ -118,6 +118,16 @@ config HOTPLUG_PCI_CPCI_GENERIC When in doubt, say N. +config HOTPLUG_PCI_OCTEONEP + bool "Marvell OCTEON PCI Hotplug driver" + depends on HOTPLUG_PCI + help + Say Y here if you have an OCTEON PCIe device with a hotplug + controller. This driver enables the non-controller functions of the + device to be registered as hotplug slots. + + When in doubt, say N. + config HOTPLUG_PCI_SHPC bool "SHPC PCI Hotplug driver" help diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 240c99517d5e95..40aaf31fe3384b 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o obj-$(CONFIG_HOTPLUG_PCI_S390) += s390_pci_hpc.o +obj-$(CONFIG_HOTPLUG_PCI_OCTEONEP) += octep_hp.o # acpiphp_ibm extends acpiphp, so should be linked afterwards. diff --git a/drivers/pci/hotplug/acpiphp_ampere_altra.c b/drivers/pci/hotplug/acpiphp_ampere_altra.c index f5c9e741c1d419..70dbc0431fc69f 100644 --- a/drivers/pci/hotplug/acpiphp_ampere_altra.c +++ b/drivers/pci/hotplug/acpiphp_ampere_altra.c @@ -119,7 +119,7 @@ static struct platform_driver altra_led_driver = { .acpi_match_table = altra_led_ids, }, .probe = altra_led_probe, - .remove_new = altra_led_remove, + .remove = altra_led_remove, }; module_platform_driver(altra_led_driver); diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index 6d8970d8c3f297..03fa39ab0c8846 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -44,7 +44,6 @@ struct cpci_hp_controller_ops { int (*enable_irq)(void); int (*disable_irq)(void); int (*check_irq)(void *dev_id); - int (*hardware_test)(struct slot *slot, u32 value); u8 (*get_power)(struct slot *slot); int (*set_power)(struct slot *slot, int value); }; diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 718bc6cf12cb3c..ef7534a3ca40ff 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -12,8 +12,11 @@ * */ +#define pr_fmt(fmt) "cpqphp: " fmt + #include #include +#include #include #include #include @@ -132,18 +135,6 @@ int cpqhp_unconfigure_device(struct pci_func *func) return 0; } -static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value) -{ - u32 vendID = 0; - - if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendID) == -1) - return -1; - if (PCI_POSSIBLE_ERROR(vendID)) - return -1; - return pci_bus_read_config_dword(bus, devfn, offset, value); -} - - /* * cpqhp_set_irq * @@ -202,13 +193,16 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 *dev_ { u16 tdevice; u32 work; - u8 tbus; + int ret = -1; ctrl->pci_bus->number = bus_num; for (tdevice = 0; tdevice < 0xFF; tdevice++) { /* Scan for access first */ - if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) + if (!pci_bus_read_dev_vendor_id(ctrl->pci_bus, tdevice, &work, 0)) + continue; + ret = pci_bus_read_config_dword(ctrl->pci_bus, tdevice, PCI_CLASS_REVISION, &work); + if (ret) continue; dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); /* Yep we got one. Not a bridge ? */ @@ -216,23 +210,20 @@ static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 *dev_ *dev_num = tdevice; dbg("found it !\n"); return 0; - } - } - for (tdevice = 0; tdevice < 0xFF; tdevice++) { - /* Scan for access first */ - if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) - continue; - dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); - /* Yep we got one. bridge ? */ - if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { - pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); - /* XXX: no recursion, wtf? */ - dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); - return 0; + } else { + /* + * XXX: Code whose debug printout indicated + * recursion to buses underneath bridges might be + * necessary was removed because it never did + * any recursion. + */ + ret = 0; + pr_warn("missing feature: bridge scan recursion not implemented\n"); } } - return -1; + + return ret; } diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c index fed1360ee9b187..6143ebf71f2117 100644 --- a/drivers/pci/hotplug/cpqphp_sysfs.c +++ b/drivers/pci/hotplug/cpqphp_sysfs.c @@ -123,7 +123,6 @@ static int spew_debug_info(struct controller *ctrl, char *data, int size) struct ctrl_dbg { int size; char *data; - struct controller *ctrl; }; #define MAX_OUTPUT (4*PAGE_SIZE) diff --git a/drivers/pci/hotplug/octep_hp.c b/drivers/pci/hotplug/octep_hp.c new file mode 100644 index 00000000000000..2bce7296c05042 --- /dev/null +++ b/drivers/pci/hotplug/octep_hp.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2024 Marvell. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OCTEP_HP_INTR_OFFSET(x) (0x20400 + ((x) << 4)) +#define OCTEP_HP_INTR_VECTOR(x) (16 + (x)) +#define OCTEP_HP_DRV_NAME "octep_hp" + +/* + * Type of MSI-X interrupts. OCTEP_HP_INTR_VECTOR() and + * OCTEP_HP_INTR_OFFSET() generate the vector and offset for an interrupt + * type. + */ +enum octep_hp_intr_type { + OCTEP_HP_INTR_INVALID = -1, + OCTEP_HP_INTR_ENA = 0, + OCTEP_HP_INTR_DIS = 1, + OCTEP_HP_INTR_MAX = 2, +}; + +struct octep_hp_cmd { + struct list_head list; + enum octep_hp_intr_type intr_type; + u64 intr_val; +}; + +struct octep_hp_slot { + struct list_head list; + struct hotplug_slot slot; + u16 slot_number; + struct pci_dev *hp_pdev; + unsigned int hp_devfn; + struct octep_hp_controller *ctrl; +}; + +struct octep_hp_intr_info { + enum octep_hp_intr_type type; + int number; + char name[16]; +}; + +struct octep_hp_controller { + void __iomem *base; + struct pci_dev *pdev; + struct octep_hp_intr_info intr[OCTEP_HP_INTR_MAX]; + struct work_struct work; + struct list_head slot_list; + struct mutex slot_lock; /* Protects slot_list */ + struct list_head hp_cmd_list; + spinlock_t hp_cmd_lock; /* Protects hp_cmd_list */ +}; + +static void octep_hp_enable_pdev(struct octep_hp_controller *hp_ctrl, + struct octep_hp_slot *hp_slot) +{ + guard(mutex)(&hp_ctrl->slot_lock); + if (hp_slot->hp_pdev) { + pci_dbg(hp_slot->hp_pdev, "Slot %s is already enabled\n", + hotplug_slot_name(&hp_slot->slot)); + return; + } + + /* Scan the device and add it to the bus */ + hp_slot->hp_pdev = pci_scan_single_device(hp_ctrl->pdev->bus, + hp_slot->hp_devfn); + pci_bus_assign_resources(hp_ctrl->pdev->bus); + pci_bus_add_device(hp_slot->hp_pdev); + + dev_dbg(&hp_slot->hp_pdev->dev, "Enabled slot %s\n", + hotplug_slot_name(&hp_slot->slot)); +} + +static void octep_hp_disable_pdev(struct octep_hp_controller *hp_ctrl, + struct octep_hp_slot *hp_slot) +{ + guard(mutex)(&hp_ctrl->slot_lock); + if (!hp_slot->hp_pdev) { + pci_dbg(hp_ctrl->pdev, "Slot %s is already disabled\n", + hotplug_slot_name(&hp_slot->slot)); + return; + } + + pci_dbg(hp_slot->hp_pdev, "Disabling slot %s\n", + hotplug_slot_name(&hp_slot->slot)); + + /* Remove the device from the bus */ + pci_stop_and_remove_bus_device_locked(hp_slot->hp_pdev); + hp_slot->hp_pdev = NULL; +} + +static int octep_hp_enable_slot(struct hotplug_slot *slot) +{ + struct octep_hp_slot *hp_slot = + container_of(slot, struct octep_hp_slot, slot); + + octep_hp_enable_pdev(hp_slot->ctrl, hp_slot); + return 0; +} + +static int octep_hp_disable_slot(struct hotplug_slot *slot) +{ + struct octep_hp_slot *hp_slot = + container_of(slot, struct octep_hp_slot, slot); + + octep_hp_disable_pdev(hp_slot->ctrl, hp_slot); + return 0; +} + +static struct hotplug_slot_ops octep_hp_slot_ops = { + .enable_slot = octep_hp_enable_slot, + .disable_slot = octep_hp_disable_slot, +}; + +#define SLOT_NAME_SIZE 16 +static struct octep_hp_slot * +octep_hp_register_slot(struct octep_hp_controller *hp_ctrl, + struct pci_dev *pdev, u16 slot_number) +{ + char slot_name[SLOT_NAME_SIZE]; + struct octep_hp_slot *hp_slot; + int ret; + + hp_slot = kzalloc(sizeof(*hp_slot), GFP_KERNEL); + if (!hp_slot) + return ERR_PTR(-ENOMEM); + + hp_slot->ctrl = hp_ctrl; + hp_slot->hp_pdev = pdev; + hp_slot->hp_devfn = pdev->devfn; + hp_slot->slot_number = slot_number; + hp_slot->slot.ops = &octep_hp_slot_ops; + + snprintf(slot_name, sizeof(slot_name), "octep_hp_%u", slot_number); + ret = pci_hp_register(&hp_slot->slot, hp_ctrl->pdev->bus, + PCI_SLOT(pdev->devfn), slot_name); + if (ret) { + kfree(hp_slot); + return ERR_PTR(ret); + } + + pci_info(pdev, "Registered slot %s for device %s\n", + slot_name, pci_name(pdev)); + + list_add_tail(&hp_slot->list, &hp_ctrl->slot_list); + octep_hp_disable_pdev(hp_ctrl, hp_slot); + + return hp_slot; +} + +static void octep_hp_deregister_slot(void *data) +{ + struct octep_hp_slot *hp_slot = data; + struct octep_hp_controller *hp_ctrl = hp_slot->ctrl; + + pci_hp_deregister(&hp_slot->slot); + octep_hp_enable_pdev(hp_ctrl, hp_slot); + list_del(&hp_slot->list); + kfree(hp_slot); +} + +static const char *octep_hp_cmd_name(enum octep_hp_intr_type type) +{ + switch (type) { + case OCTEP_HP_INTR_ENA: + return "hotplug enable"; + case OCTEP_HP_INTR_DIS: + return "hotplug disable"; + default: + return "invalid"; + } +} + +static void octep_hp_cmd_handler(struct octep_hp_controller *hp_ctrl, + struct octep_hp_cmd *hp_cmd) +{ + struct octep_hp_slot *hp_slot; + + /* + * Enable or disable the slots based on the slot mask. + * intr_val is a bit mask where each bit represents a slot. + */ + list_for_each_entry(hp_slot, &hp_ctrl->slot_list, list) { + if (!(hp_cmd->intr_val & BIT(hp_slot->slot_number))) + continue; + + pci_info(hp_ctrl->pdev, "Received %s command for slot %s\n", + octep_hp_cmd_name(hp_cmd->intr_type), + hotplug_slot_name(&hp_slot->slot)); + + switch (hp_cmd->intr_type) { + case OCTEP_HP_INTR_ENA: + octep_hp_enable_pdev(hp_ctrl, hp_slot); + break; + case OCTEP_HP_INTR_DIS: + octep_hp_disable_pdev(hp_ctrl, hp_slot); + break; + default: + break; + } + } +} + +static void octep_hp_work_handler(struct work_struct *work) +{ + struct octep_hp_controller *hp_ctrl; + struct octep_hp_cmd *hp_cmd; + unsigned long flags; + + hp_ctrl = container_of(work, struct octep_hp_controller, work); + + /* Process all the hotplug commands */ + spin_lock_irqsave(&hp_ctrl->hp_cmd_lock, flags); + while (!list_empty(&hp_ctrl->hp_cmd_list)) { + hp_cmd = list_first_entry(&hp_ctrl->hp_cmd_list, + struct octep_hp_cmd, list); + list_del(&hp_cmd->list); + spin_unlock_irqrestore(&hp_ctrl->hp_cmd_lock, flags); + + octep_hp_cmd_handler(hp_ctrl, hp_cmd); + kfree(hp_cmd); + + spin_lock_irqsave(&hp_ctrl->hp_cmd_lock, flags); + } + spin_unlock_irqrestore(&hp_ctrl->hp_cmd_lock, flags); +} + +static enum octep_hp_intr_type octep_hp_intr_type(struct octep_hp_intr_info *intr, + int irq) +{ + enum octep_hp_intr_type type; + + for (type = OCTEP_HP_INTR_ENA; type < OCTEP_HP_INTR_MAX; type++) { + if (intr[type].number == irq) + return type; + } + + return OCTEP_HP_INTR_INVALID; +} + +static irqreturn_t octep_hp_intr_handler(int irq, void *data) +{ + struct octep_hp_controller *hp_ctrl = data; + struct pci_dev *pdev = hp_ctrl->pdev; + enum octep_hp_intr_type type; + struct octep_hp_cmd *hp_cmd; + u64 intr_val; + + type = octep_hp_intr_type(hp_ctrl->intr, irq); + if (type == OCTEP_HP_INTR_INVALID) { + pci_err(pdev, "Invalid interrupt %d\n", irq); + return IRQ_HANDLED; + } + + /* Read and clear the interrupt */ + intr_val = readq(hp_ctrl->base + OCTEP_HP_INTR_OFFSET(type)); + writeq(intr_val, hp_ctrl->base + OCTEP_HP_INTR_OFFSET(type)); + + hp_cmd = kzalloc(sizeof(*hp_cmd), GFP_ATOMIC); + if (!hp_cmd) + return IRQ_HANDLED; + + hp_cmd->intr_val = intr_val; + hp_cmd->intr_type = type; + + /* Add the command to the list and schedule the work */ + spin_lock(&hp_ctrl->hp_cmd_lock); + list_add_tail(&hp_cmd->list, &hp_ctrl->hp_cmd_list); + spin_unlock(&hp_ctrl->hp_cmd_lock); + schedule_work(&hp_ctrl->work); + + return IRQ_HANDLED; +} + +static void octep_hp_irq_cleanup(void *data) +{ + struct octep_hp_controller *hp_ctrl = data; + + pci_free_irq_vectors(hp_ctrl->pdev); + flush_work(&hp_ctrl->work); +} + +static int octep_hp_request_irq(struct octep_hp_controller *hp_ctrl, + enum octep_hp_intr_type type) +{ + struct pci_dev *pdev = hp_ctrl->pdev; + struct octep_hp_intr_info *intr; + int irq; + + irq = pci_irq_vector(pdev, OCTEP_HP_INTR_VECTOR(type)); + if (irq < 0) + return irq; + + intr = &hp_ctrl->intr[type]; + intr->number = irq; + intr->type = type; + snprintf(intr->name, sizeof(intr->name), "octep_hp_%d", type); + + return devm_request_irq(&pdev->dev, irq, octep_hp_intr_handler, + IRQF_SHARED, intr->name, hp_ctrl); +} + +static int octep_hp_controller_setup(struct pci_dev *pdev, + struct octep_hp_controller *hp_ctrl) +{ + struct device *dev = &pdev->dev; + enum octep_hp_intr_type type; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable PCI device\n"); + + hp_ctrl->base = pcim_iomap_region(pdev, 0, OCTEP_HP_DRV_NAME); + if (IS_ERR(hp_ctrl->base)) + return dev_err_probe(dev, PTR_ERR(hp_ctrl->base), + "Failed to map PCI device region\n"); + + pci_set_master(pdev); + pci_set_drvdata(pdev, hp_ctrl); + + INIT_LIST_HEAD(&hp_ctrl->slot_list); + INIT_LIST_HEAD(&hp_ctrl->hp_cmd_list); + mutex_init(&hp_ctrl->slot_lock); + spin_lock_init(&hp_ctrl->hp_cmd_lock); + INIT_WORK(&hp_ctrl->work, octep_hp_work_handler); + hp_ctrl->pdev = pdev; + + ret = pci_alloc_irq_vectors(pdev, 1, + OCTEP_HP_INTR_VECTOR(OCTEP_HP_INTR_MAX), + PCI_IRQ_MSIX); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to alloc MSI-X vectors\n"); + + ret = devm_add_action(&pdev->dev, octep_hp_irq_cleanup, hp_ctrl); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to add IRQ cleanup action\n"); + + for (type = OCTEP_HP_INTR_ENA; type < OCTEP_HP_INTR_MAX; type++) { + ret = octep_hp_request_irq(hp_ctrl, type); + if (ret) + return dev_err_probe(dev, ret, + "Failed to request IRQ for vector %d\n", + OCTEP_HP_INTR_VECTOR(type)); + } + + return 0; +} + +static int octep_hp_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct octep_hp_controller *hp_ctrl; + struct pci_dev *tmp_pdev, *next; + struct octep_hp_slot *hp_slot; + u16 slot_number = 0; + int ret; + + hp_ctrl = devm_kzalloc(&pdev->dev, sizeof(*hp_ctrl), GFP_KERNEL); + if (!hp_ctrl) + return -ENOMEM; + + ret = octep_hp_controller_setup(pdev, hp_ctrl); + if (ret) + return ret; + + /* + * Register all hotplug slots. Hotplug controller is the first function + * of the PCI device. The hotplug slots are the remaining functions of + * the PCI device. The hotplug slot functions are logically removed from + * the bus during probing and are re-enabled by the driver when a + * hotplug event is received. + */ + list_for_each_entry_safe(tmp_pdev, next, &pdev->bus->devices, bus_list) { + if (tmp_pdev == pdev) + continue; + + hp_slot = octep_hp_register_slot(hp_ctrl, tmp_pdev, slot_number); + if (IS_ERR(hp_slot)) + return dev_err_probe(&pdev->dev, PTR_ERR(hp_slot), + "Failed to register hotplug slot %u\n", + slot_number); + + ret = devm_add_action(&pdev->dev, octep_hp_deregister_slot, + hp_slot); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to add action for deregistering slot %u\n", + slot_number); + slot_number++; + } + + return 0; +} + +#define PCI_DEVICE_ID_CAVIUM_OCTEP_HP_CTLR 0xa0e3 +static struct pci_device_id octep_hp_pci_map[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_CAVIUM_OCTEP_HP_CTLR) }, + { }, +}; + +static struct pci_driver octep_hp = { + .name = OCTEP_HP_DRV_NAME, + .id_table = octep_hp_pci_map, + .probe = octep_hp_pci_probe, +}; + +module_pci_driver(octep_hp); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marvell"); +MODULE_DESCRIPTION("Marvell OCTEON PCI Hotplug driver"); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 058d5937d8a953..36236ac88fd567 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -388,8 +388,8 @@ static struct hotplug_slot *get_slot_from_name(const char *name) /** * __pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem - * @bus: bus this slot is on * @slot: pointer to the &struct hotplug_slot to register + * @bus: bus this slot is on * @devnr: device number * @name: name registered with kobject core * @owner: caller module owner @@ -498,8 +498,6 @@ EXPORT_SYMBOL_GPL(pci_hp_add); * * The @slot must have been registered with the pci hotplug subsystem * previously with a call to pci_hp_register(). - * - * Returns 0 if successful, anything else for an error. */ void pci_hp_deregister(struct hotplug_slot *slot) { @@ -513,8 +511,6 @@ EXPORT_SYMBOL_GPL(pci_hp_deregister); * @slot: pointer to the &struct hotplug_slot to unpublish * * Remove a hotplug slot's sysfs interface. - * - * Returns 0 on success or a negative int on error. */ void pci_hp_del(struct hotplug_slot *slot) { @@ -545,8 +541,6 @@ EXPORT_SYMBOL_GPL(pci_hp_del); * the driver may no longer invoke hotplug_slot_name() to get the slot's * unique name. The driver no longer needs to handle a ->reset_slot callback * from this point on. - * - * Returns 0 on success or a negative int on error. */ void pci_hp_destroy(struct hotplug_slot *slot) { diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index dcdbfcf404ddf4..d603a7aa74838c 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -19,6 +19,8 @@ #include #include #include + +#include "../pci.h" #include "pciehp.h" /* The following routines constitute the bulk of the @@ -127,6 +129,9 @@ static void remove_board(struct controller *ctrl, bool safe_removal) pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, INDICATOR_NOOP); + + /* Don't carry LBMS indications across */ + pcie_reset_lbms_count(ctrl->pcie->port); } static int pciehp_enable_slot(struct controller *ctrl); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 736ad8baa2a555..bb5a8d9f03ad98 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -319,7 +319,7 @@ int pciehp_check_link_status(struct controller *ctrl) return -1; } - pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); + __pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); if (!found) { ctrl_info(ctrl, "Slot(%s): No device found\n", diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index aaa33e8dc4c977..4be402fe9ab942 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -327,8 +327,8 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id) virtfn->resource[i].name = pci_name(virtfn); virtfn->resource[i].flags = res->flags; size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES); - virtfn->resource[i].start = res->start + size * id; - virtfn->resource[i].end = virtfn->resource[i].start + size - 1; + resource_set_range(&virtfn->resource[i], + res->start + size * id, size); rc = request_resource(res, &virtfn->resource[i]); BUG_ON(rc); } @@ -804,7 +804,7 @@ static int sriov_init(struct pci_dev *dev, int pos) goto failed; } iov->barsz[i] = resource_size(res); - res->end = res->start + resource_size(res) * total - 1; + resource_set_size(res, resource_size(res) * total); pci_info(dev, "%s %pR: contains BAR %d for %d VFs\n", res_name, res, i, total); i += bar64; diff --git a/drivers/pci/of.c b/drivers/pci/of.c index dacea3fc5128fc..52f770bcc48190 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -728,6 +728,33 @@ void of_pci_make_dev_node(struct pci_dev *pdev) } #endif +/** + * of_pci_supply_present() - Check if the power supply is present for the PCI + * device + * @np: Device tree node + * + * Check if the power supply for the PCI device is present in the device tree + * node or not. + * + * Return: true if at least one power supply exists; false otherwise. + */ +bool of_pci_supply_present(struct device_node *np) +{ + struct property *prop; + char *supply; + + if (!np) + return false; + + for_each_property_of_node(np, prop) { + supply = strrchr(prop->name, '-'); + if (supply && !strcmp(supply, "-supply")) + return true; + } + + return false; +} + #endif /* CONFIG_PCI */ /** diff --git a/drivers/pci/of_property.c b/drivers/pci/of_property.c index 5a0b98e697954a..886c236e5de6e6 100644 --- a/drivers/pci/of_property.c +++ b/drivers/pci/of_property.c @@ -126,7 +126,7 @@ static int of_pci_prop_ranges(struct pci_dev *pdev, struct of_changeset *ocs, if (of_pci_get_addr_flags(&res[j], &flags)) continue; - val64 = res[j].start; + val64 = pci_bus_address(pdev, &res[j] - pdev->resource); of_pci_set_address(pdev, rp[i].parent_addr, val64, 0, flags, false); if (pci_is_bridge(pdev)) { diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 4f47a13cb500ff..7abd4f546d3c07 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -90,7 +90,7 @@ static ssize_t published_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(published); static int p2pmem_alloc_mmap(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, struct vm_area_struct *vma) + const struct bin_attribute *attr, struct vm_area_struct *vma) { struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); size_t len = vma->vm_end - vma->vm_start; diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5d0f4db1cab786..7679d75d71e534 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -521,6 +521,31 @@ static ssize_t bus_rescan_store(struct device *dev, static struct device_attribute dev_attr_bus_rescan = __ATTR(rescan, 0200, NULL, bus_rescan_store); +static ssize_t reset_subordinate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct pci_bus *bus = pdev->subordinate; + unsigned long val; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (kstrtoul(buf, 0, &val) < 0) + return -EINVAL; + + if (val) { + int ret = __pci_reset_bus(bus); + + if (ret) + return ret; + } + + return count; +} +static DEVICE_ATTR_WO(reset_subordinate); + #if defined(CONFIG_PM) && defined(CONFIG_ACPI) static ssize_t d3cold_allowed_store(struct device *dev, struct device_attribute *attr, @@ -625,6 +650,7 @@ static struct attribute *pci_dev_attrs[] = { static struct attribute *pci_bridge_attrs[] = { &dev_attr_subordinate_bus_number.attr, &dev_attr_secondary_bus_number.attr, + &dev_attr_reset_subordinate.attr, NULL, }; @@ -818,21 +844,20 @@ static struct bin_attribute *pci_dev_config_attrs[] = { NULL, }; -static umode_t pci_dev_config_attr_is_visible(struct kobject *kobj, - struct bin_attribute *a, int n) +static size_t pci_dev_config_attr_bin_size(struct kobject *kobj, + const struct bin_attribute *a, + int n) { struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); - a->size = PCI_CFG_SPACE_SIZE; if (pdev->cfg_size > PCI_CFG_SPACE_SIZE) - a->size = PCI_CFG_SPACE_EXP_SIZE; - - return a->attr.mode; + return PCI_CFG_SPACE_EXP_SIZE; + return PCI_CFG_SPACE_SIZE; } static const struct attribute_group pci_dev_config_attr_group = { .bin_attrs = pci_dev_config_attrs, - .is_bin_visible = pci_dev_config_attr_is_visible, + .bin_size = pci_dev_config_attr_bin_size, }; /* @@ -842,7 +867,7 @@ static const struct attribute_group pci_dev_config_attr_group = { static __maybe_unused loff_t pci_llseek_resource(struct file *filep, struct kobject *kobj __always_unused, - struct bin_attribute *attr, + const struct bin_attribute *attr, loff_t offset, int whence) { return fixed_size_llseek(filep, offset, whence, attr->size); @@ -911,7 +936,7 @@ static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj, * memory space. */ static int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma) { struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj)); @@ -931,7 +956,7 @@ static int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj, * memory space. Returns -ENOSYS if the operation isn't supported */ static int pci_mmap_legacy_io(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma) { struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj)); @@ -1035,7 +1060,7 @@ void pci_remove_legacy_files(struct pci_bus *b) * * Use the regular PCI mapping routines to map a PCI resource into userspace. */ -static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, +static int pci_mmap_resource(struct kobject *kobj, const struct bin_attribute *attr, struct vm_area_struct *vma, int write_combine) { struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); @@ -1060,14 +1085,14 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, } static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma) { return pci_mmap_resource(kobj, attr, vma, 0); } static int pci_mmap_resource_wc(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma) { return pci_mmap_resource(kobj, attr, vma, 1); @@ -1327,24 +1352,29 @@ static struct bin_attribute *pci_dev_rom_attrs[] = { }; static umode_t pci_dev_rom_attr_is_visible(struct kobject *kobj, - struct bin_attribute *a, int n) + const struct bin_attribute *a, int n) { struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); - size_t rom_size; /* If the device has a ROM, try to expose it in sysfs. */ - rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE); - if (!rom_size) + if (!pci_resource_end(pdev, PCI_ROM_RESOURCE)) return 0; - a->size = rom_size; - return a->attr.mode; } +static size_t pci_dev_rom_attr_bin_size(struct kobject *kobj, + const struct bin_attribute *a, int n) +{ + struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); + + return pci_resource_len(pdev, PCI_ROM_RESOURCE); +} + static const struct attribute_group pci_dev_rom_attr_group = { .bin_attrs = pci_dev_rom_attrs, .is_bin_visible = pci_dev_rom_attr_is_visible, + .bin_size = pci_dev_rom_attr_bin_size, }; static ssize_t reset_store(struct device *dev, struct device_attribute *attr, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 225a6cd2e9ca3b..661f98c6c63a39 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1832,6 +1832,7 @@ int pci_save_state(struct pci_dev *dev) pci_save_dpc_state(dev); pci_save_aer_state(dev); pci_save_ptm_state(dev); + pci_save_tph_state(dev); return pci_save_vc_state(dev); } EXPORT_SYMBOL(pci_save_state); @@ -1937,6 +1938,7 @@ void pci_restore_state(struct pci_dev *dev) pci_restore_rebar_state(dev); pci_restore_dpc_state(dev); pci_restore_ptm_state(dev); + pci_restore_tph_state(dev); pci_aer_clear_status(dev); pci_restore_aer_state(dev); @@ -4167,7 +4169,7 @@ EXPORT_SYMBOL(pci_request_regions_exclusive); * Record the PCI IO range (expressed as CPU physical address + size). * Return a negative value if an error has occurred, zero otherwise */ -int pci_register_io_range(struct fwnode_handle *fwnode, phys_addr_t addr, +int pci_register_io_range(const struct fwnode_handle *fwnode, phys_addr_t addr, resource_size_t size) { int ret = 0; @@ -4744,7 +4746,7 @@ int pcie_retrain_link(struct pci_dev *pdev, bool use_lt) * to track link speed or width changes made by hardware itself * in attempt to correct unreliable link operation. */ - pcie_capability_write_word(pdev, PCI_EXP_LNKSTA, PCI_EXP_LNKSTA_LBMS); + pcie_reset_lbms_count(pdev); return rc; } @@ -5162,6 +5164,8 @@ static void pci_dev_save_and_disable(struct pci_dev *dev) */ if (err_handler && err_handler->reset_prepare) err_handler->reset_prepare(dev); + else if (dev->driver) + pci_warn(dev, "resetting"); /* * Wake-up device prior to save. PM registers default to D0 after @@ -5195,6 +5199,8 @@ static void pci_dev_restore(struct pci_dev *dev) */ if (err_handler && err_handler->reset_done) err_handler->reset_done(dev); + else if (dev->driver) + pci_warn(dev, "reset done"); } /* dev->reset_methods[] is a 0-terminated list of indices into this array */ @@ -5248,7 +5254,7 @@ static ssize_t reset_method_store(struct device *dev, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); - char *options, *name; + char *options, *tmp_options, *name; int m, n; u8 reset_methods[PCI_NUM_RESET_METHODS] = { 0 }; @@ -5268,7 +5274,8 @@ static ssize_t reset_method_store(struct device *dev, return -ENOMEM; n = 0; - while ((name = strsep(&options, " ")) != NULL) { + tmp_options = options; + while ((name = strsep(&tmp_options, " ")) != NULL) { if (sysfs_streq(name, "")) continue; @@ -5884,7 +5891,7 @@ EXPORT_SYMBOL_GPL(pci_probe_reset_bus); * * Same as above except return -EAGAIN if the bus cannot be locked */ -static int __pci_reset_bus(struct pci_bus *bus) +int __pci_reset_bus(struct pci_bus *bus) { int rc; @@ -6193,38 +6200,66 @@ u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev, EXPORT_SYMBOL(pcie_bandwidth_available); /** - * pcie_get_speed_cap - query for the PCI device's link speed capability + * pcie_get_supported_speeds - query Supported Link Speed Vector * @dev: PCI device to query * - * Query the PCI device speed capability. Return the maximum link speed - * supported by the device. + * Query @dev supported link speeds. + * + * Implementation Note in PCIe r6.0 sec 7.5.3.18 recommends determining + * supported link speeds using the Supported Link Speeds Vector in the Link + * Capabilities 2 Register (when available). + * + * Link Capabilities 2 was added in PCIe r3.0, sec 7.8.18. + * + * Without Link Capabilities 2, i.e., prior to PCIe r3.0, Supported Link + * Speeds field in Link Capabilities is used and only 2.5 GT/s and 5.0 GT/s + * speeds were defined. + * + * For @dev without Supported Link Speed Vector, the field is synthesized + * from the Max Link Speed field in the Link Capabilities Register. + * + * Return: Supported Link Speeds Vector (+ reserved 0 at LSB). */ -enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev) +u8 pcie_get_supported_speeds(struct pci_dev *dev) { u32 lnkcap2, lnkcap; + u8 speeds; /* - * Link Capabilities 2 was added in PCIe r3.0, sec 7.8.18. The - * implementation note there recommends using the Supported Link - * Speeds Vector in Link Capabilities 2 when supported. - * - * Without Link Capabilities 2, i.e., prior to PCIe r3.0, software - * should use the Supported Link Speeds field in Link Capabilities, - * where only 2.5 GT/s and 5.0 GT/s speeds were defined. + * Speeds retain the reserved 0 at LSB before PCIe Supported Link + * Speeds Vector to allow using SLS Vector bit defines directly. */ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2); + speeds = lnkcap2 & PCI_EXP_LNKCAP2_SLS; + + /* Ignore speeds higher than Max Link Speed */ + pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap); + speeds &= GENMASK(lnkcap & PCI_EXP_LNKCAP_SLS, 0); /* PCIe r3.0-compliant */ - if (lnkcap2) - return PCIE_LNKCAP2_SLS2SPEED(lnkcap2); + if (speeds) + return speeds; - pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap); + /* Synthesize from the Max Link Speed field */ if ((lnkcap & PCI_EXP_LNKCAP_SLS) == PCI_EXP_LNKCAP_SLS_5_0GB) - return PCIE_SPEED_5_0GT; + speeds = PCI_EXP_LNKCAP2_SLS_5_0GB | PCI_EXP_LNKCAP2_SLS_2_5GB; else if ((lnkcap & PCI_EXP_LNKCAP_SLS) == PCI_EXP_LNKCAP_SLS_2_5GB) - return PCIE_SPEED_2_5GT; + speeds = PCI_EXP_LNKCAP2_SLS_2_5GB; + + return speeds; +} - return PCI_SPEED_UNKNOWN; +/** + * pcie_get_speed_cap - query for the PCI device's link speed capability + * @dev: PCI device to query + * + * Query the PCI device speed capability. + * + * Return: the maximum link speed supported by the device. + */ +enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev) +{ + return PCIE_LNKCAP2_SLS2SPEED(dev->supported_speeds); } EXPORT_SYMBOL(pcie_get_speed_cap); @@ -6653,8 +6688,7 @@ static void pci_request_resource_alignment(struct pci_dev *dev, int bar, } else { r->flags &= ~IORESOURCE_SIZEALIGN; r->flags |= IORESOURCE_STARTALIGN; - r->start = align; - r->end = r->start + size - 1; + resource_set_range(r, align, size); } r->flags |= IORESOURCE_UNSET; } @@ -6900,6 +6934,8 @@ static int __init pci_setup(char *str) pci_no_domains(); } else if (!strncmp(str, "noari", 5)) { pcie_ari_disabled = true; + } else if (!strncmp(str, "notph", 5)) { + pci_no_tph(); } else if (!strncmp(str, "cbiosize=", 9)) { pci_cardbus_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "cbmemsize=", 10)) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 14d00ce45bfa95..2e40fc63ba3159 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -104,6 +104,7 @@ bool pci_reset_supported(struct pci_dev *dev); void pci_init_reset_methods(struct pci_dev *dev); int pci_bridge_secondary_bus_reset(struct pci_dev *dev); int pci_bus_error_reset(struct pci_dev *dev); +int __pci_reset_bus(struct pci_bus *bus); struct pci_cap_saved_data { u16 cap_nr; @@ -323,6 +324,9 @@ void __pci_bus_assign_resources(const struct pci_bus *bus, struct list_head *realloc_head, struct list_head *fail_head); bool pci_bus_clip_resource(struct pci_dev *dev, int idx); +void pci_walk_bus_locked(struct pci_bus *top, + int (*cb)(struct pci_dev *, void *), + void *userdata); const char *pci_resource_name(struct pci_dev *dev, unsigned int i); @@ -331,6 +335,17 @@ void pci_disable_bridge_window(struct pci_dev *dev); struct pci_bus *pci_bus_get(struct pci_bus *bus); void pci_bus_put(struct pci_bus *bus); +#define PCIE_LNKCAP_SLS2SPEED(lnkcap) \ +({ \ + ((lnkcap) == PCI_EXP_LNKCAP_SLS_64_0GB ? PCIE_SPEED_64_0GT : \ + (lnkcap) == PCI_EXP_LNKCAP_SLS_32_0GB ? PCIE_SPEED_32_0GT : \ + (lnkcap) == PCI_EXP_LNKCAP_SLS_16_0GB ? PCIE_SPEED_16_0GT : \ + (lnkcap) == PCI_EXP_LNKCAP_SLS_8_0GB ? PCIE_SPEED_8_0GT : \ + (lnkcap) == PCI_EXP_LNKCAP_SLS_5_0GB ? PCIE_SPEED_5_0GT : \ + (lnkcap) == PCI_EXP_LNKCAP_SLS_2_5GB ? PCIE_SPEED_2_5GT : \ + PCI_SPEED_UNKNOWN); \ +}) + /* PCIe link information from Link Capabilities 2 */ #define PCIE_LNKCAP2_SLS2SPEED(lnkcap2) \ ((lnkcap2) & PCI_EXP_LNKCAP2_SLS_64_0GB ? PCIE_SPEED_64_0GT : \ @@ -341,6 +356,15 @@ void pci_bus_put(struct pci_bus *bus); (lnkcap2) & PCI_EXP_LNKCAP2_SLS_2_5GB ? PCIE_SPEED_2_5GT : \ PCI_SPEED_UNKNOWN) +#define PCIE_LNKCTL2_TLS2SPEED(lnkctl2) \ + ((lnkctl2) == PCI_EXP_LNKCTL2_TLS_64_0GT ? PCIE_SPEED_64_0GT : \ + (lnkctl2) == PCI_EXP_LNKCTL2_TLS_32_0GT ? PCIE_SPEED_32_0GT : \ + (lnkctl2) == PCI_EXP_LNKCTL2_TLS_16_0GT ? PCIE_SPEED_16_0GT : \ + (lnkctl2) == PCI_EXP_LNKCTL2_TLS_8_0GT ? PCIE_SPEED_8_0GT : \ + (lnkctl2) == PCI_EXP_LNKCTL2_TLS_5_0GT ? PCIE_SPEED_5_0GT : \ + (lnkctl2) == PCI_EXP_LNKCTL2_TLS_2_5GT ? PCIE_SPEED_2_5GT : \ + PCI_SPEED_UNKNOWN) + /* PCIe speed to Mb/s reduced by encoding overhead */ #define PCIE_SPEED2MBS_ENC(speed) \ ((speed) == PCIE_SPEED_64_0GT ? 64000*1/1 : \ @@ -373,12 +397,16 @@ static inline int pcie_dev_speed_mbps(enum pci_bus_speed speed) return -EINVAL; } +u8 pcie_get_supported_speeds(struct pci_dev *dev); const char *pci_speed_string(enum pci_bus_speed speed); -enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev); -enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev); void __pcie_print_link_status(struct pci_dev *dev, bool verbose); void pcie_report_downtraining(struct pci_dev *dev); -void pcie_update_link_speed(struct pci_bus *bus, u16 link_status); + +static inline void __pcie_update_link_speed(struct pci_bus *bus, u16 linksta) +{ + bus->cur_bus_speed = pcie_link_speed[linksta & PCI_EXP_LNKSTA_CLS]; +} +void pcie_update_link_speed(struct pci_bus *bus); /* Single Root I/O Virtualization */ struct pci_sriov { @@ -469,10 +497,18 @@ static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused) #define PCI_DEV_ADDED 0 #define PCI_DPC_RECOVERED 1 #define PCI_DPC_RECOVERING 2 +#define PCI_DEV_REMOVED 3 -static inline void pci_dev_assign_added(struct pci_dev *dev, bool added) +static inline void pci_dev_assign_added(struct pci_dev *dev) { - assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added); + smp_mb__before_atomic(); + set_bit(PCI_DEV_ADDED, &dev->priv_flags); + smp_mb__after_atomic(); +} + +static inline bool pci_dev_test_and_clear_added(struct pci_dev *dev) +{ + return test_and_clear_bit(PCI_DEV_ADDED, &dev->priv_flags); } static inline bool pci_dev_is_added(const struct pci_dev *dev) @@ -480,6 +516,11 @@ static inline bool pci_dev_is_added(const struct pci_dev *dev) return test_bit(PCI_DEV_ADDED, &dev->priv_flags); } +static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev) +{ + return test_and_set_bit(PCI_DEV_REMOVED, &dev->priv_flags); +} + #ifdef CONFIG_PCIEAER #include @@ -597,6 +638,18 @@ static inline int pci_iov_bus_range(struct pci_bus *bus) #endif /* CONFIG_PCI_IOV */ +#ifdef CONFIG_PCIE_TPH +void pci_restore_tph_state(struct pci_dev *dev); +void pci_save_tph_state(struct pci_dev *dev); +void pci_no_tph(void); +void pci_tph_init(struct pci_dev *dev); +#else +static inline void pci_restore_tph_state(struct pci_dev *dev) { } +static inline void pci_save_tph_state(struct pci_dev *dev) { } +static inline void pci_no_tph(void) { } +static inline void pci_tph_init(struct pci_dev *dev) { } +#endif + #ifdef CONFIG_PCIE_PTM void pci_ptm_init(struct pci_dev *dev); void pci_save_ptm_state(struct pci_dev *dev); @@ -692,6 +745,17 @@ static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { } static inline void pcie_ecrc_get_policy(char *str) { } #endif +#ifdef CONFIG_PCIEPORTBUS +void pcie_reset_lbms_count(struct pci_dev *port); +int pcie_lbms_count(struct pci_dev *port, unsigned long *val); +#else +static inline void pcie_reset_lbms_count(struct pci_dev *port) {} +static inline int pcie_lbms_count(struct pci_dev *port, unsigned long *val) +{ + return -EOPNOTSUPP; +} +#endif + struct pci_dev_reset_methods { u16 vendor; u16 device; @@ -746,6 +810,7 @@ void pci_set_bus_of_node(struct pci_bus *bus); void pci_release_bus_of_node(struct pci_bus *bus); int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge); +bool of_pci_supply_present(struct device_node *np); #else static inline int @@ -793,6 +858,10 @@ static inline int devm_of_pci_bridge_init(struct device *dev, struct pci_host_br return 0; } +static inline bool of_pci_supply_present(struct device_node *np) +{ + return false; +} #endif /* CONFIG_OF */ struct of_changeset; diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index 6461aa93fe76ec..53ccab62314d97 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile @@ -4,7 +4,7 @@ pcieportdrv-y := portdrv.o rcec.o -obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o +obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o bwctrl.o obj-y += aspm.o obj-$(CONFIG_PCIEAER) += aer.o err.o diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 13b8586924ead1..34ce9f834d0ccc 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -180,7 +180,8 @@ static int disable_ecrc_checking(struct pci_dev *dev) } /** - * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based on global policy + * pcie_set_ecrc_checking - set/unset PCIe ECRC checking for a device based + * on global policy * @dev: the PCI device */ void pcie_set_ecrc_checking(struct pci_dev *dev) @@ -230,7 +231,7 @@ int pcie_aer_is_native(struct pci_dev *dev) return pcie_ports_native || host->native_aer; } -EXPORT_SYMBOL_NS_GPL(pcie_aer_is_native, CXL); +EXPORT_SYMBOL_NS_GPL(pcie_aer_is_native, "CXL"); static int pci_enable_pcie_error_reporting(struct pci_dev *dev) { @@ -801,7 +802,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity, trace_aer_event(dev_name(&dev->dev), (status & ~mask), aer_severity, tlp_header_valid, &aer->header_log); } -EXPORT_SYMBOL_NS_GPL(pci_print_aer, CXL); +EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL"); /** * add_error_device - list device to be handled @@ -1148,14 +1149,16 @@ static void aer_recover_work_func(struct work_struct *work) continue; } pci_print_aer(pdev, entry.severity, entry.regs); + /* - * Memory for aer_capability_regs(entry.regs) is being allocated from the - * ghes_estatus_pool to protect it from overwriting when multiple sections - * are present in the error status. Thus free the same after processing - * the data. + * Memory for aer_capability_regs(entry.regs) is being + * allocated from the ghes_estatus_pool to protect it from + * overwriting when multiple sections are present in the + * error status. Thus free the same after processing the + * data. */ ghes_estatus_pool_region_free((unsigned long)entry.regs, - sizeof(struct aer_capability_regs)); + sizeof(struct aer_capability_regs)); if (entry.severity == AER_NONFATAL) pcie_do_recovery(pdev, pci_channel_io_normal, diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index cee2365e54b8b2..28567d457613bf 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -805,6 +805,15 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl); pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl); + /* Disable L0s/L1 before updating L1SS config */ + if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, child_lnkctl) || + FIELD_GET(PCI_EXP_LNKCTL_ASPMC, parent_lnkctl)) { + pcie_capability_write_word(child, PCI_EXP_LNKCTL, + child_lnkctl & ~PCI_EXP_LNKCTL_ASPMC); + pcie_capability_write_word(parent, PCI_EXP_LNKCTL, + parent_lnkctl & ~PCI_EXP_LNKCTL_ASPMC); + } + /* * Setup L0s state * @@ -829,6 +838,13 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) aspm_l1ss_init(link); + /* Restore L0s/L1 if they were enabled */ + if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, child_lnkctl) || + FIELD_GET(PCI_EXP_LNKCTL_ASPMC, parent_lnkctl)) { + pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_lnkctl); + pcie_capability_write_word(child, PCI_EXP_LNKCTL, child_lnkctl); + } + /* Save default state */ link->aspm_default = link->aspm_enabled; @@ -845,25 +861,28 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) } } -/* Configure the ASPM L1 substates */ +/* Configure the ASPM L1 substates. Caller must disable L1 first. */ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) { - u32 val, enable_req; + u32 val; struct pci_dev *child = link->downstream, *parent = link->pdev; - enable_req = (link->aspm_enabled ^ state) & state; + val = 0; + if (state & PCIE_LINK_STATE_L1_1) + val |= PCI_L1SS_CTL1_ASPM_L1_1; + if (state & PCIE_LINK_STATE_L1_2) + val |= PCI_L1SS_CTL1_ASPM_L1_2; + if (state & PCIE_LINK_STATE_L1_1_PCIPM) + val |= PCI_L1SS_CTL1_PCIPM_L1_1; + if (state & PCIE_LINK_STATE_L1_2_PCIPM) + val |= PCI_L1SS_CTL1_PCIPM_L1_2; /* - * Here are the rules specified in the PCIe spec for enabling L1SS: - * - When enabling L1.x, enable bit at parent first, then at child - * - When disabling L1.x, disable bit at child first, then at parent - * - When enabling ASPM L1.x, need to disable L1 - * (at child followed by parent). - * - The ASPM/PCIPM L1.2 must be disabled while programming timing + * PCIe r6.2, sec 5.5.4, rules for enabling L1 PM Substates: + * - Clear L1.x enable bits at child first, then at parent + * - Set L1.x enable bits at parent first, then at child + * - ASPM/PCIPM L1.2 must be disabled while programming timing * parameters - * - * To keep it simple, disable all L1SS bits first, and later enable - * what is needed. */ /* Disable all L1 substates */ @@ -871,26 +890,6 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) PCI_L1SS_CTL1_L1SS_MASK, 0); pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, PCI_L1SS_CTL1_L1SS_MASK, 0); - /* - * If needed, disable L1, and it gets enabled later - * in pcie_config_aspm_link(). - */ - if (enable_req & (PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2)) { - pcie_capability_clear_word(child, PCI_EXP_LNKCTL, - PCI_EXP_LNKCTL_ASPM_L1); - pcie_capability_clear_word(parent, PCI_EXP_LNKCTL, - PCI_EXP_LNKCTL_ASPM_L1); - } - - val = 0; - if (state & PCIE_LINK_STATE_L1_1) - val |= PCI_L1SS_CTL1_ASPM_L1_1; - if (state & PCIE_LINK_STATE_L1_2) - val |= PCI_L1SS_CTL1_ASPM_L1_2; - if (state & PCIE_LINK_STATE_L1_1_PCIPM) - val |= PCI_L1SS_CTL1_PCIPM_L1_1; - if (state & PCIE_LINK_STATE_L1_2_PCIPM) - val |= PCI_L1SS_CTL1_PCIPM_L1_2; /* Enable what we need to enable */ pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, @@ -937,21 +936,30 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state) dwstream |= PCI_EXP_LNKCTL_ASPM_L1; } + /* + * Per PCIe r6.2, sec 5.5.4, setting either or both of the enable + * bits for ASPM L1 PM Substates must be done while ASPM L1 is + * disabled. Disable L1 here and apply new configuration after L1SS + * configuration has been completed. + * + * Per sec 7.5.3.7, when disabling ASPM L1, software must disable + * it in the Downstream component prior to disabling it in the + * Upstream component, and ASPM L1 must be enabled in the Upstream + * component prior to enabling it in the Downstream component. + * + * Sec 7.5.3.7 also recommends programming the same ASPM Control + * value for all functions of a multi-function device. + */ + list_for_each_entry(child, &linkbus->devices, bus_list) + pcie_config_aspm_dev(child, 0); + pcie_config_aspm_dev(parent, 0); + if (link->aspm_capable & PCIE_LINK_STATE_L1SS) pcie_config_aspm_l1ss(link, state); - /* - * Spec 2.0 suggests all functions should be configured the - * same setting for ASPM. Enabling ASPM L1 should be done in - * upstream component first and then downstream, and vice - * versa for disabling ASPM L1. Spec doesn't mention L0S. - */ - if (state & PCIE_LINK_STATE_L1) - pcie_config_aspm_dev(parent, upstream); + pcie_config_aspm_dev(parent, upstream); list_for_each_entry(child, &linkbus->devices, bus_list) pcie_config_aspm_dev(child, dwstream); - if (!(state & PCIE_LINK_STATE_L1)) - pcie_config_aspm_dev(parent, upstream); link->aspm_enabled = state; @@ -1442,6 +1450,9 @@ static int __pci_enable_link_state(struct pci_dev *pdev, int state, bool locked) * touch the LNKCTL register. Also note that this does not enable states * disabled by pci_disable_link_state(). Return 0 or a negative errno. * + * Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per + * PCIe r6.0, sec 5.5.4. + * * @pdev: PCI device * @state: Mask of ASPM link states to enable */ @@ -1458,6 +1469,9 @@ EXPORT_SYMBOL(pci_enable_link_state); * can't touch the LNKCTL register. Also note that this does not enable states * disabled by pci_disable_link_state(). Return 0 or a negative errno. * + * Note: Ensure devices are in D0 before enabling PCI-PM L1 PM Substates, per + * PCIe r6.0, sec 5.5.4. + * * @pdev: PCI device * @state: Mask of ASPM link states to enable * diff --git a/drivers/pci/pcie/bwctrl.c b/drivers/pci/pcie/bwctrl.c new file mode 100644 index 00000000000000..b59cacc740fa24 --- /dev/null +++ b/drivers/pci/pcie/bwctrl.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PCIe bandwidth controller + * + * Author: Alexandru Gagniuc + * + * Copyright (C) 2019 Dell Inc + * Copyright (C) 2023-2024 Intel Corporation + * + * The PCIe bandwidth controller provides a way to alter PCIe Link Speeds + * and notify the operating system when the Link Width or Speed changes. The + * notification capability is required for all Root Ports and Downstream + * Ports supporting Link Width wider than x1 and/or multiple Link Speeds. + * + * This service port driver hooks into the Bandwidth Notification interrupt + * watching for changes or links becoming degraded in operation. It updates + * the cached Current Link Speed that is exposed to user space through sysfs. + */ + +#define dev_fmt(fmt) "bwctrl: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pci.h" +#include "portdrv.h" + +/** + * struct pcie_bwctrl_data - PCIe bandwidth controller + * @set_speed_mutex: Serializes link speed changes + * @lbms_count: Count for LBMS (since last reset) + * @cdev: Thermal cooling device associated with the port + */ +struct pcie_bwctrl_data { + struct mutex set_speed_mutex; + atomic_t lbms_count; + struct thermal_cooling_device *cdev; +}; + +/* + * Prevent port removal during LBMS count accessors and Link Speed changes. + * + * These have to be differentiated because pcie_bwctrl_change_speed() calls + * pcie_retrain_link() which uses LBMS count reset accessor on success + * (using just one rwsem triggers "possible recursive locking detected" + * warning). + */ +static DECLARE_RWSEM(pcie_bwctrl_lbms_rwsem); +static DECLARE_RWSEM(pcie_bwctrl_setspeed_rwsem); + +static bool pcie_valid_speed(enum pci_bus_speed speed) +{ + return (speed >= PCIE_SPEED_2_5GT) && (speed <= PCIE_SPEED_64_0GT); +} + +static u16 pci_bus_speed2lnkctl2(enum pci_bus_speed speed) +{ + static const u8 speed_conv[] = { + [PCIE_SPEED_2_5GT] = PCI_EXP_LNKCTL2_TLS_2_5GT, + [PCIE_SPEED_5_0GT] = PCI_EXP_LNKCTL2_TLS_5_0GT, + [PCIE_SPEED_8_0GT] = PCI_EXP_LNKCTL2_TLS_8_0GT, + [PCIE_SPEED_16_0GT] = PCI_EXP_LNKCTL2_TLS_16_0GT, + [PCIE_SPEED_32_0GT] = PCI_EXP_LNKCTL2_TLS_32_0GT, + [PCIE_SPEED_64_0GT] = PCI_EXP_LNKCTL2_TLS_64_0GT, + }; + + if (WARN_ON_ONCE(!pcie_valid_speed(speed))) + return 0; + + return speed_conv[speed]; +} + +static inline u16 pcie_supported_speeds2target_speed(u8 supported_speeds) +{ + return __fls(supported_speeds); +} + +/** + * pcie_bwctrl_select_speed - Select Target Link Speed + * @port: PCIe Port + * @speed_req: Requested PCIe Link Speed + * + * Select Target Link Speed by take into account Supported Link Speeds of + * both the Root Port and the Endpoint. + * + * Return: Target Link Speed (1=2.5GT/s, 2=5GT/s, 3=8GT/s, etc.) + */ +static u16 pcie_bwctrl_select_speed(struct pci_dev *port, enum pci_bus_speed speed_req) +{ + struct pci_bus *bus = port->subordinate; + u8 desired_speeds, supported_speeds; + struct pci_dev *dev; + + desired_speeds = GENMASK(pci_bus_speed2lnkctl2(speed_req), + __fls(PCI_EXP_LNKCAP2_SLS_2_5GB)); + + supported_speeds = port->supported_speeds; + if (bus) { + down_read(&pci_bus_sem); + dev = list_first_entry_or_null(&bus->devices, struct pci_dev, bus_list); + if (dev) + supported_speeds &= dev->supported_speeds; + up_read(&pci_bus_sem); + } + if (!supported_speeds) + return PCI_EXP_LNKCAP2_SLS_2_5GB; + + return pcie_supported_speeds2target_speed(supported_speeds & desired_speeds); +} + +static int pcie_bwctrl_change_speed(struct pci_dev *port, u16 target_speed, bool use_lt) +{ + int ret; + + ret = pcie_capability_clear_and_set_word(port, PCI_EXP_LNKCTL2, + PCI_EXP_LNKCTL2_TLS, target_speed); + if (ret != PCIBIOS_SUCCESSFUL) + return pcibios_err_to_errno(ret); + + ret = pcie_retrain_link(port, use_lt); + if (ret < 0) + return ret; + + /* + * Ensure link speed updates also with platforms that have problems + * with notifications. + */ + if (port->subordinate) + pcie_update_link_speed(port->subordinate); + + return 0; +} + +/** + * pcie_set_target_speed - Set downstream Link Speed for PCIe Port + * @port: PCIe Port + * @speed_req: Requested PCIe Link Speed + * @use_lt: Wait for the LT or DLLLA bit to detect the end of link training + * + * Attempt to set PCIe Port Link Speed to @speed_req. @speed_req may be + * adjusted downwards to the best speed supported by both the Port and PCIe + * Device underneath it. + * + * Return: + * * 0 - on success + * * -EINVAL - @speed_req is not a PCIe Link Speed + * * -ENODEV - @port is not controllable + * * -ETIMEDOUT - changing Link Speed took too long + * * -EAGAIN - Link Speed was changed but @speed_req was not achieved + */ +int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req, + bool use_lt) +{ + struct pci_bus *bus = port->subordinate; + u16 target_speed; + int ret; + + if (WARN_ON_ONCE(!pcie_valid_speed(speed_req))) + return -EINVAL; + + if (bus && bus->cur_bus_speed == speed_req) + return 0; + + target_speed = pcie_bwctrl_select_speed(port, speed_req); + + scoped_guard(rwsem_read, &pcie_bwctrl_setspeed_rwsem) { + struct pcie_bwctrl_data *data = port->link_bwctrl; + + /* + * port->link_bwctrl is NULL during initial scan when called + * e.g. from the Target Speed quirk. + */ + if (data) + mutex_lock(&data->set_speed_mutex); + + ret = pcie_bwctrl_change_speed(port, target_speed, use_lt); + + if (data) + mutex_unlock(&data->set_speed_mutex); + } + + /* + * Despite setting higher speed into the Target Link Speed, empty + * bus won't train to 5GT+ speeds. + */ + if (!ret && bus && bus->cur_bus_speed != speed_req && + !list_empty(&bus->devices)) + ret = -EAGAIN; + + return ret; +} + +static void pcie_bwnotif_enable(struct pcie_device *srv) +{ + struct pcie_bwctrl_data *data = srv->port->link_bwctrl; + struct pci_dev *port = srv->port; + u16 link_status; + int ret; + + /* Count LBMS seen so far as one */ + ret = pcie_capability_read_word(port, PCI_EXP_LNKSTA, &link_status); + if (ret == PCIBIOS_SUCCESSFUL && link_status & PCI_EXP_LNKSTA_LBMS) + atomic_inc(&data->lbms_count); + + pcie_capability_set_word(port, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_LBMIE | PCI_EXP_LNKCTL_LABIE); + pcie_capability_write_word(port, PCI_EXP_LNKSTA, + PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_LABS); + + /* + * Update after enabling notifications & clearing status bits ensures + * link speed is up to date. + */ + pcie_update_link_speed(port->subordinate); +} + +static void pcie_bwnotif_disable(struct pci_dev *port) +{ + pcie_capability_clear_word(port, PCI_EXP_LNKCTL, + PCI_EXP_LNKCTL_LBMIE | PCI_EXP_LNKCTL_LABIE); +} + +static irqreturn_t pcie_bwnotif_irq(int irq, void *context) +{ + struct pcie_device *srv = context; + struct pcie_bwctrl_data *data = srv->port->link_bwctrl; + struct pci_dev *port = srv->port; + u16 link_status, events; + int ret; + + ret = pcie_capability_read_word(port, PCI_EXP_LNKSTA, &link_status); + if (ret != PCIBIOS_SUCCESSFUL) + return IRQ_NONE; + + events = link_status & (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_LABS); + if (!events) + return IRQ_NONE; + + if (events & PCI_EXP_LNKSTA_LBMS) + atomic_inc(&data->lbms_count); + + pcie_capability_write_word(port, PCI_EXP_LNKSTA, events); + + /* + * Interrupts will not be triggered from any further Link Speed + * change until LBMS is cleared by the write. Therefore, re-read the + * speed (inside pcie_update_link_speed()) after LBMS has been + * cleared to avoid missing link speed changes. + */ + pcie_update_link_speed(port->subordinate); + + return IRQ_HANDLED; +} + +void pcie_reset_lbms_count(struct pci_dev *port) +{ + struct pcie_bwctrl_data *data; + + guard(rwsem_read)(&pcie_bwctrl_lbms_rwsem); + data = port->link_bwctrl; + if (data) + atomic_set(&data->lbms_count, 0); + else + pcie_capability_write_word(port, PCI_EXP_LNKSTA, + PCI_EXP_LNKSTA_LBMS); +} + +int pcie_lbms_count(struct pci_dev *port, unsigned long *val) +{ + struct pcie_bwctrl_data *data; + + guard(rwsem_read)(&pcie_bwctrl_lbms_rwsem); + data = port->link_bwctrl; + if (!data) + return -ENOTTY; + + *val = atomic_read(&data->lbms_count); + + return 0; +} + +static int pcie_bwnotif_probe(struct pcie_device *srv) +{ + struct pci_dev *port = srv->port; + int ret; + + struct pcie_bwctrl_data *data = devm_kzalloc(&srv->device, + sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = devm_mutex_init(&srv->device, &data->set_speed_mutex); + if (ret) + return ret; + + ret = devm_request_irq(&srv->device, srv->irq, pcie_bwnotif_irq, + IRQF_SHARED, "PCIe bwctrl", srv); + if (ret) + return ret; + + scoped_guard(rwsem_write, &pcie_bwctrl_setspeed_rwsem) { + scoped_guard(rwsem_write, &pcie_bwctrl_lbms_rwsem) { + port->link_bwctrl = no_free_ptr(data); + pcie_bwnotif_enable(srv); + } + } + + pci_dbg(port, "enabled with IRQ %d\n", srv->irq); + + /* Don't fail on errors. Don't leave IS_ERR() "pointer" into ->cdev */ + port->link_bwctrl->cdev = pcie_cooling_device_register(port); + if (IS_ERR(port->link_bwctrl->cdev)) + port->link_bwctrl->cdev = NULL; + + return 0; +} + +static void pcie_bwnotif_remove(struct pcie_device *srv) +{ + struct pcie_bwctrl_data *data = srv->port->link_bwctrl; + + pcie_cooling_device_unregister(data->cdev); + + pcie_bwnotif_disable(srv->port); + + scoped_guard(rwsem_write, &pcie_bwctrl_setspeed_rwsem) + scoped_guard(rwsem_write, &pcie_bwctrl_lbms_rwsem) + srv->port->link_bwctrl = NULL; +} + +static int pcie_bwnotif_suspend(struct pcie_device *srv) +{ + pcie_bwnotif_disable(srv->port); + return 0; +} + +static int pcie_bwnotif_resume(struct pcie_device *srv) +{ + pcie_bwnotif_enable(srv); + return 0; +} + +static struct pcie_port_service_driver pcie_bwctrl_driver = { + .name = "pcie_bwctrl", + .port_type = PCIE_ANY_PORT, + .service = PCIE_PORT_SERVICE_BWCTRL, + .probe = pcie_bwnotif_probe, + .suspend = pcie_bwnotif_suspend, + .resume = pcie_bwnotif_resume, + .remove = pcie_bwnotif_remove, +}; + +int __init pcie_bwctrl_init(void) +{ + return pcie_port_service_register(&pcie_bwctrl_driver); +} diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c index 6af5e042587285..02e73099bad053 100644 --- a/drivers/pci/pcie/portdrv.c +++ b/drivers/pci/pcie/portdrv.c @@ -68,7 +68,7 @@ static int pcie_message_numbers(struct pci_dev *dev, int mask, */ if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP | - PCIE_PORT_SERVICE_BWNOTIF)) { + PCIE_PORT_SERVICE_BWCTRL)) { pcie_capability_read_word(dev, PCI_EXP_FLAGS, ®16); *pme = FIELD_GET(PCI_EXP_FLAGS_IRQ, reg16); nvec = *pme + 1; @@ -150,11 +150,11 @@ static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask) /* PME, hotplug and bandwidth notification share an MSI/MSI-X vector */ if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP | - PCIE_PORT_SERVICE_BWNOTIF)) { + PCIE_PORT_SERVICE_BWCTRL)) { pcie_irq = pci_irq_vector(dev, pme); irqs[PCIE_PORT_SERVICE_PME_SHIFT] = pcie_irq; irqs[PCIE_PORT_SERVICE_HP_SHIFT] = pcie_irq; - irqs[PCIE_PORT_SERVICE_BWNOTIF_SHIFT] = pcie_irq; + irqs[PCIE_PORT_SERVICE_BWCTRL_SHIFT] = pcie_irq; } if (mask & PCIE_PORT_SERVICE_AER) @@ -265,13 +265,15 @@ static int get_port_device_capability(struct pci_dev *dev) (pcie_ports_dpc_native || (services & PCIE_PORT_SERVICE_AER))) services |= PCIE_PORT_SERVICE_DPC; + /* Enable bandwidth control if more than one speed is supported. */ if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM || pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) { u32 linkcap; pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &linkcap); - if (linkcap & PCI_EXP_LNKCAP_LBNC) - services |= PCIE_PORT_SERVICE_BWNOTIF; + if (linkcap & PCI_EXP_LNKCAP_LBNC && + hweight8(dev->supported_speeds) > 1) + services |= PCIE_PORT_SERVICE_BWCTRL; } return services; @@ -828,6 +830,7 @@ static void __init pcie_init_services(void) pcie_aer_init(); pcie_pme_init(); pcie_dpc_init(); + pcie_bwctrl_init(); pcie_hp_init(); } diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 12c89ea0313b9c..bd29d1cc7b8bd7 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -20,8 +20,8 @@ #define PCIE_PORT_SERVICE_HP (1 << PCIE_PORT_SERVICE_HP_SHIFT) #define PCIE_PORT_SERVICE_DPC_SHIFT 3 /* Downstream Port Containment */ #define PCIE_PORT_SERVICE_DPC (1 << PCIE_PORT_SERVICE_DPC_SHIFT) -#define PCIE_PORT_SERVICE_BWNOTIF_SHIFT 4 /* Bandwidth notification */ -#define PCIE_PORT_SERVICE_BWNOTIF (1 << PCIE_PORT_SERVICE_BWNOTIF_SHIFT) +#define PCIE_PORT_SERVICE_BWCTRL_SHIFT 4 /* Bandwidth Controller (notifications) */ +#define PCIE_PORT_SERVICE_BWCTRL (1 << PCIE_PORT_SERVICE_BWCTRL_SHIFT) #define PCIE_PORT_DEVICE_MAXSERVICES 5 @@ -51,6 +51,8 @@ int pcie_dpc_init(void); static inline int pcie_dpc_init(void) { return 0; } #endif +int pcie_bwctrl_init(void); + /* Port Type */ #define PCIE_ANY_PORT (~0) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f1615805f5b078..2e81ab0f5a25cb 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -543,15 +543,15 @@ void pci_read_bridge_bases(struct pci_bus *child) pci_read_bridge_mmio(child->self, child->resource[1], false); pci_read_bridge_mmio_pref(child->self, child->resource[2], false); - if (dev->transparent) { - pci_bus_for_each_resource(child->parent, res) { - if (res && res->flags) { - pci_bus_add_resource(child, res, - PCI_SUBTRACTIVE_DECODE); - pci_info(dev, " bridge window %pR (subtractive decode)\n", - res); - } - } + if (!dev->transparent) + return; + + pci_bus_for_each_resource(child->parent, res) { + if (!res || !res->flags) + continue; + + pci_bus_add_resource(child, res); + pci_info(dev, " bridge window %pR (subtractive decode)\n", res); } } @@ -742,9 +742,13 @@ const char *pci_speed_string(enum pci_bus_speed speed) } EXPORT_SYMBOL_GPL(pci_speed_string); -void pcie_update_link_speed(struct pci_bus *bus, u16 linksta) +void pcie_update_link_speed(struct pci_bus *bus) { - bus->cur_bus_speed = pcie_link_speed[linksta & PCI_EXP_LNKSTA_CLS]; + struct pci_dev *bridge = bus->self; + u16 linksta; + + pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta); + __pcie_update_link_speed(bus, linksta); } EXPORT_SYMBOL_GPL(pcie_update_link_speed); @@ -827,13 +831,11 @@ static void pci_set_bus_speed(struct pci_bus *bus) if (pci_is_pcie(bridge)) { u32 linkcap; - u16 linksta; pcie_capability_read_dword(bridge, PCI_EXP_LNKCAP, &linkcap); bus->max_bus_speed = pcie_link_speed[linkcap & PCI_EXP_LNKCAP_SLS]; - pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta); - pcie_update_link_speed(bus, linksta); + pcie_update_link_speed(bus); } } @@ -1032,7 +1034,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) if (res->flags & IORESOURCE_BUS) pci_bus_insert_busn_res(bus, bus->number, res->end); else - pci_bus_add_resource(bus, res, 0); + pci_bus_add_resource(bus, res); if (offset) { if (resource_type(res) == IORESOURCE_IO) @@ -1633,23 +1635,33 @@ static void set_pcie_thunderbolt(struct pci_dev *dev) static void set_pcie_untrusted(struct pci_dev *dev) { - struct pci_dev *parent; + struct pci_dev *parent = pci_upstream_bridge(dev); + if (!parent) + return; /* - * If the upstream bridge is untrusted we treat this device + * If the upstream bridge is untrusted we treat this device as * untrusted as well. */ - parent = pci_upstream_bridge(dev); - if (parent && (parent->untrusted || parent->external_facing)) + if (parent->untrusted) { + dev->untrusted = true; + return; + } + + if (arch_pci_dev_is_removable(dev)) { + pci_dbg(dev, "marking as untrusted\n"); dev->untrusted = true; + } } static void pci_set_removable(struct pci_dev *dev) { struct pci_dev *parent = pci_upstream_bridge(dev); + if (!parent) + return; /* - * We (only) consider everything downstream from an external_facing + * We (only) consider everything tunneled below an external_facing * device to be removable by the user. We're mainly concerned with * consumer platforms with user accessible thunderbolt ports that are * vulnerable to DMA attacks, and we expect those ports to be marked by @@ -1659,9 +1671,15 @@ static void pci_set_removable(struct pci_dev *dev) * accessible to user / may not be removed by end user, and thus not * exposed as "removable" to userspace. */ - if (parent && - (parent->external_facing || dev_is_removable(&parent->dev))) + if (dev_is_removable(&parent->dev)) { + dev_set_removable(&dev->dev, DEVICE_REMOVABLE); + return; + } + + if (arch_pci_dev_is_removable(dev)) { + pci_dbg(dev, "marking as removable\n"); dev_set_removable(&dev->dev, DEVICE_REMOVABLE); + } } /** @@ -1947,6 +1965,9 @@ int pci_setup_device(struct pci_dev *dev) set_pcie_untrusted(dev); + if (pci_is_pcie(dev)) + dev->supported_speeds = pcie_get_supported_speeds(dev); + /* "Unknown power state" */ dev->current_state = PCI_UNKNOWN; @@ -2495,6 +2516,7 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_dpc_init(dev); /* Downstream Port Containment */ pci_rcec_init(dev); /* Root Complex Event Collector */ pci_doe_init(dev); /* Data Object Exchange */ + pci_tph_init(dev); /* TLP Processing Hints */ pcie_report_downtraining(dev); pci_init_reset_methods(dev); @@ -3108,6 +3130,17 @@ int pci_host_probe(struct pci_host_bridge *bridge) pci_lock_rescan_remove(); pci_bus_add_devices(bus); pci_unlock_rescan_remove(); + + /* + * Ensure pm_runtime_enable() is called for the controller drivers + * before calling pci_host_probe(). The PM framework expects that + * if the parent device supports runtime PM, it will be enabled + * before child runtime PM is enabled. + */ + pm_runtime_set_active(&bridge->dev); + pm_runtime_no_callbacks(&bridge->dev); + devm_pm_runtime_enable(&bridge->dev); + return 0; } EXPORT_SYMBOL_GPL(pci_host_probe); diff --git a/drivers/pci/pwrctl/Kconfig b/drivers/pci/pwrctl/Kconfig deleted file mode 100644 index 54589bb2403b9d..00000000000000 --- a/drivers/pci/pwrctl/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - -config HAVE_PWRCTL - bool - -config PCI_PWRCTL - tristate - -config PCI_PWRCTL_PWRSEQ - tristate - select POWER_SEQUENCING - select PCI_PWRCTL diff --git a/drivers/pci/pwrctl/Makefile b/drivers/pci/pwrctl/Makefile deleted file mode 100644 index d308aae4800cd3..00000000000000 --- a/drivers/pci/pwrctl/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - -obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctl-core.o -pci-pwrctl-core-y := core.o - -obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctl-pwrseq.o diff --git a/drivers/pci/pwrctl/core.c b/drivers/pci/pwrctl/core.c deleted file mode 100644 index 01d913b603160d..00000000000000 --- a/drivers/pci/pwrctl/core.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2024 Linaro Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include - -static int pci_pwrctl_notify(struct notifier_block *nb, unsigned long action, - void *data) -{ - struct pci_pwrctl *pwrctl = container_of(nb, struct pci_pwrctl, nb); - struct device *dev = data; - - if (dev_fwnode(dev) != dev_fwnode(pwrctl->dev)) - return NOTIFY_DONE; - - switch (action) { - case BUS_NOTIFY_ADD_DEVICE: - /* - * We will have two struct device objects bound to two different - * drivers on different buses but consuming the same DT node. We - * must not bind the pins twice in this case but only once for - * the first device to be added. - * - * If we got here then the PCI device is the second after the - * power control platform device. Mark its OF node as reused. - */ - dev->of_node_reused = true; - break; - case BUS_NOTIFY_BOUND_DRIVER: - pwrctl->link = device_link_add(dev, pwrctl->dev, - DL_FLAG_AUTOREMOVE_CONSUMER); - if (!pwrctl->link) - dev_err(pwrctl->dev, "Failed to add device link\n"); - break; - case BUS_NOTIFY_UNBOUND_DRIVER: - if (pwrctl->link) - device_link_remove(dev, pwrctl->dev); - break; - } - - return NOTIFY_DONE; -} - -static void rescan_work_func(struct work_struct *work) -{ - struct pci_pwrctl *pwrctl = container_of(work, struct pci_pwrctl, work); - - pci_lock_rescan_remove(); - pci_rescan_bus(to_pci_dev(pwrctl->dev->parent)->bus); - pci_unlock_rescan_remove(); -} - -/** - * pci_pwrctl_init() - Initialize the PCI power control context struct - * - * @pwrctl: PCI power control data - * @dev: Parent device - */ -void pci_pwrctl_init(struct pci_pwrctl *pwrctl, struct device *dev) -{ - pwrctl->dev = dev; - INIT_WORK(&pwrctl->work, rescan_work_func); -} -EXPORT_SYMBOL_GPL(pci_pwrctl_init); - -/** - * pci_pwrctl_device_set_ready() - Notify the pwrctl subsystem that the PCI - * device is powered-up and ready to be detected. - * - * @pwrctl: PCI power control data. - * - * Returns: - * 0 on success, negative error number on error. - * - * Note: - * This function returning 0 doesn't mean the device was detected. It means, - * that the bus rescan was successfully started. The device will get bound to - * its PCI driver asynchronously. - */ -int pci_pwrctl_device_set_ready(struct pci_pwrctl *pwrctl) -{ - int ret; - - if (!pwrctl->dev) - return -ENODEV; - - pwrctl->nb.notifier_call = pci_pwrctl_notify; - ret = bus_register_notifier(&pci_bus_type, &pwrctl->nb); - if (ret) - return ret; - - schedule_work(&pwrctl->work); - - return 0; -} -EXPORT_SYMBOL_GPL(pci_pwrctl_device_set_ready); - -/** - * pci_pwrctl_device_unset_ready() - Notify the pwrctl subsystem that the PCI - * device is about to be powered-down. - * - * @pwrctl: PCI power control data. - */ -void pci_pwrctl_device_unset_ready(struct pci_pwrctl *pwrctl) -{ - /* - * We don't have to delete the link here. Typically, this function - * is only called when the power control device is being detached. If - * it is being detached then the child PCI device must have already - * been unbound too or the device core wouldn't let us unbind. - */ - bus_unregister_notifier(&pci_bus_type, &pwrctl->nb); -} -EXPORT_SYMBOL_GPL(pci_pwrctl_device_unset_ready); - -static void devm_pci_pwrctl_device_unset_ready(void *data) -{ - struct pci_pwrctl *pwrctl = data; - - pci_pwrctl_device_unset_ready(pwrctl); -} - -/** - * devm_pci_pwrctl_device_set_ready - Managed variant of - * pci_pwrctl_device_set_ready(). - * - * @dev: Device managing this pwrctl provider. - * @pwrctl: PCI power control data. - * - * Returns: - * 0 on success, negative error number on error. - */ -int devm_pci_pwrctl_device_set_ready(struct device *dev, - struct pci_pwrctl *pwrctl) -{ - int ret; - - ret = pci_pwrctl_device_set_ready(pwrctl); - if (ret) - return ret; - - return devm_add_action_or_reset(dev, - devm_pci_pwrctl_device_unset_ready, - pwrctl); -} -EXPORT_SYMBOL_GPL(devm_pci_pwrctl_device_set_ready); - -MODULE_AUTHOR("Bartosz Golaszewski "); -MODULE_DESCRIPTION("PCI Device Power Control core driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c b/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c deleted file mode 100644 index 0e6bd47671c2e6..00000000000000 --- a/drivers/pci/pwrctl/pci-pwrctl-pwrseq.c +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2024 Linaro Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct pci_pwrctl_pwrseq_data { - struct pci_pwrctl ctx; - struct pwrseq_desc *pwrseq; -}; - -struct pci_pwrctl_pwrseq_pdata { - const char *target; - /* - * Called before doing anything else to perform device-specific - * verification between requesting the power sequencing handle. - */ - int (*validate_device)(struct device *dev); -}; - -static int pci_pwrctl_pwrseq_qcm_wcn_validate_device(struct device *dev) -{ - /* - * Old device trees for some platforms already define wifi nodes for - * the WCN family of chips since before power sequencing was added - * upstream. - * - * These nodes don't consume the regulator outputs from the PMU, and - * if we allow this driver to bind to one of such "incomplete" nodes, - * we'll see a kernel log error about the indefinite probe deferral. - * - * Check the existence of the regulator supply that exists on all - * WCN models before moving forward. - */ - if (!device_property_present(dev, "vddaon-supply")) - return -ENODEV; - - return 0; -} - -static const struct pci_pwrctl_pwrseq_pdata pci_pwrctl_pwrseq_qcom_wcn_pdata = { - .target = "wlan", - .validate_device = pci_pwrctl_pwrseq_qcm_wcn_validate_device, -}; - -static void devm_pci_pwrctl_pwrseq_power_off(void *data) -{ - struct pwrseq_desc *pwrseq = data; - - pwrseq_power_off(pwrseq); -} - -static int pci_pwrctl_pwrseq_probe(struct platform_device *pdev) -{ - const struct pci_pwrctl_pwrseq_pdata *pdata; - struct pci_pwrctl_pwrseq_data *data; - struct device *dev = &pdev->dev; - int ret; - - pdata = device_get_match_data(dev); - if (!pdata || !pdata->target) - return -EINVAL; - - if (pdata->validate_device) { - ret = pdata->validate_device(dev); - if (ret) - return ret; - } - - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->pwrseq = devm_pwrseq_get(dev, pdata->target); - if (IS_ERR(data->pwrseq)) - return dev_err_probe(dev, PTR_ERR(data->pwrseq), - "Failed to get the power sequencer\n"); - - ret = pwrseq_power_on(data->pwrseq); - if (ret) - return dev_err_probe(dev, ret, - "Failed to power-on the device\n"); - - ret = devm_add_action_or_reset(dev, devm_pci_pwrctl_pwrseq_power_off, - data->pwrseq); - if (ret) - return ret; - - pci_pwrctl_init(&data->ctx, dev); - - ret = devm_pci_pwrctl_device_set_ready(dev, &data->ctx); - if (ret) - return dev_err_probe(dev, ret, - "Failed to register the pwrctl wrapper\n"); - - return 0; -} - -static const struct of_device_id pci_pwrctl_pwrseq_of_match[] = { - { - /* ATH11K in QCA6390 package. */ - .compatible = "pci17cb,1101", - .data = &pci_pwrctl_pwrseq_qcom_wcn_pdata, - }, - { - /* ATH11K in WCN6855 package. */ - .compatible = "pci17cb,1103", - .data = &pci_pwrctl_pwrseq_qcom_wcn_pdata, - }, - { - /* ATH12K in WCN7850 package. */ - .compatible = "pci17cb,1107", - .data = &pci_pwrctl_pwrseq_qcom_wcn_pdata, - }, - { } -}; -MODULE_DEVICE_TABLE(of, pci_pwrctl_pwrseq_of_match); - -static struct platform_driver pci_pwrctl_pwrseq_driver = { - .driver = { - .name = "pci-pwrctl-pwrseq", - .of_match_table = pci_pwrctl_pwrseq_of_match, - }, - .probe = pci_pwrctl_pwrseq_probe, -}; -module_platform_driver(pci_pwrctl_pwrseq_driver); - -MODULE_AUTHOR("Bartosz Golaszewski "); -MODULE_DESCRIPTION("Generic PCI Power Control module for power sequenced devices"); -MODULE_LICENSE("GPL"); diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig new file mode 100644 index 00000000000000..54589bb2403b9d --- /dev/null +++ b/drivers/pci/pwrctrl/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config HAVE_PWRCTL + bool + +config PCI_PWRCTL + tristate + +config PCI_PWRCTL_PWRSEQ + tristate + select POWER_SEQUENCING + select PCI_PWRCTL diff --git a/drivers/pci/pwrctrl/Makefile b/drivers/pci/pwrctrl/Makefile new file mode 100644 index 00000000000000..75c7ce531c7e27 --- /dev/null +++ b/drivers/pci/pwrctrl/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_PCI_PWRCTL) += pci-pwrctrl-core.o +pci-pwrctrl-core-y := core.o + +obj-$(CONFIG_PCI_PWRCTL_PWRSEQ) += pci-pwrctrl-pwrseq.o diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c new file mode 100644 index 00000000000000..2fb174db91e589 --- /dev/null +++ b/drivers/pci/pwrctrl/core.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct pci_pwrctrl *pwrctrl = container_of(nb, struct pci_pwrctrl, nb); + struct device *dev = data; + + if (dev_fwnode(dev) != dev_fwnode(pwrctrl->dev)) + return NOTIFY_DONE; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + /* + * We will have two struct device objects bound to two different + * drivers on different buses but consuming the same DT node. We + * must not bind the pins twice in this case but only once for + * the first device to be added. + * + * If we got here then the PCI device is the second after the + * power control platform device. Mark its OF node as reused. + */ + dev->of_node_reused = true; + break; + } + + return NOTIFY_DONE; +} + +static void rescan_work_func(struct work_struct *work) +{ + struct pci_pwrctrl *pwrctrl = container_of(work, + struct pci_pwrctrl, work); + + pci_lock_rescan_remove(); + pci_rescan_bus(to_pci_dev(pwrctrl->dev->parent)->bus); + pci_unlock_rescan_remove(); +} + +/** + * pci_pwrctrl_init() - Initialize the PCI power control context struct + * + * @pwrctrl: PCI power control data + * @dev: Parent device + */ +void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct device *dev) +{ + pwrctrl->dev = dev; + INIT_WORK(&pwrctrl->work, rescan_work_func); +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_init); + +/** + * pci_pwrctrl_device_set_ready() - Notify the pwrctrl subsystem that the PCI + * device is powered-up and ready to be detected. + * + * @pwrctrl: PCI power control data. + * + * Returns: + * 0 on success, negative error number on error. + * + * Note: + * This function returning 0 doesn't mean the device was detected. It means, + * that the bus rescan was successfully started. The device will get bound to + * its PCI driver asynchronously. + */ +int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrctrl) +{ + int ret; + + if (!pwrctrl->dev) + return -ENODEV; + + pwrctrl->nb.notifier_call = pci_pwrctrl_notify; + ret = bus_register_notifier(&pci_bus_type, &pwrctrl->nb); + if (ret) + return ret; + + schedule_work(&pwrctrl->work); + + return 0; +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready); + +/** + * pci_pwrctrl_device_unset_ready() - Notify the pwrctrl subsystem that the PCI + * device is about to be powered-down. + * + * @pwrctrl: PCI power control data. + */ +void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl) +{ + /* + * We don't have to delete the link here. Typically, this function + * is only called when the power control device is being detached. If + * it is being detached then the child PCI device must have already + * been unbound too or the device core wouldn't let us unbind. + */ + bus_unregister_notifier(&pci_bus_type, &pwrctrl->nb); +} +EXPORT_SYMBOL_GPL(pci_pwrctrl_device_unset_ready); + +static void devm_pci_pwrctrl_device_unset_ready(void *data) +{ + struct pci_pwrctrl *pwrctrl = data; + + pci_pwrctrl_device_unset_ready(pwrctrl); +} + +/** + * devm_pci_pwrctrl_device_set_ready - Managed variant of + * pci_pwrctrl_device_set_ready(). + * + * @dev: Device managing this pwrctrl provider. + * @pwrctrl: PCI power control data. + * + * Returns: + * 0 on success, negative error number on error. + */ +int devm_pci_pwrctrl_device_set_ready(struct device *dev, + struct pci_pwrctrl *pwrctrl) +{ + int ret; + + ret = pci_pwrctrl_device_set_ready(pwrctrl); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, + devm_pci_pwrctrl_device_unset_ready, + pwrctrl); +} +EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready); + +MODULE_AUTHOR("Bartosz Golaszewski "); +MODULE_DESCRIPTION("PCI Device Power Control core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c new file mode 100644 index 00000000000000..4e664e7b8dd23f --- /dev/null +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct pci_pwrctrl_pwrseq_data { + struct pci_pwrctrl ctx; + struct pwrseq_desc *pwrseq; +}; + +struct pci_pwrctrl_pwrseq_pdata { + const char *target; + /* + * Called before doing anything else to perform device-specific + * verification between requesting the power sequencing handle. + */ + int (*validate_device)(struct device *dev); +}; + +static int pci_pwrctrl_pwrseq_qcm_wcn_validate_device(struct device *dev) +{ + /* + * Old device trees for some platforms already define wifi nodes for + * the WCN family of chips since before power sequencing was added + * upstream. + * + * These nodes don't consume the regulator outputs from the PMU, and + * if we allow this driver to bind to one of such "incomplete" nodes, + * we'll see a kernel log error about the indefinite probe deferral. + * + * Check the existence of the regulator supply that exists on all + * WCN models before moving forward. + */ + if (!device_property_present(dev, "vddaon-supply")) + return -ENODEV; + + return 0; +} + +static const struct pci_pwrctrl_pwrseq_pdata pci_pwrctrl_pwrseq_qcom_wcn_pdata = { + .target = "wlan", + .validate_device = pci_pwrctrl_pwrseq_qcm_wcn_validate_device, +}; + +static void devm_pci_pwrctrl_pwrseq_power_off(void *data) +{ + struct pwrseq_desc *pwrseq = data; + + pwrseq_power_off(pwrseq); +} + +static int pci_pwrctrl_pwrseq_probe(struct platform_device *pdev) +{ + const struct pci_pwrctrl_pwrseq_pdata *pdata; + struct pci_pwrctrl_pwrseq_data *data; + struct device *dev = &pdev->dev; + int ret; + + pdata = device_get_match_data(dev); + if (!pdata || !pdata->target) + return -EINVAL; + + if (pdata->validate_device) { + ret = pdata->validate_device(dev); + if (ret) + return ret; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->pwrseq = devm_pwrseq_get(dev, pdata->target); + if (IS_ERR(data->pwrseq)) + return dev_err_probe(dev, PTR_ERR(data->pwrseq), + "Failed to get the power sequencer\n"); + + ret = pwrseq_power_on(data->pwrseq); + if (ret) + return dev_err_probe(dev, ret, + "Failed to power-on the device\n"); + + ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_pwrseq_power_off, + data->pwrseq); + if (ret) + return ret; + + pci_pwrctrl_init(&data->ctx, dev); + + ret = devm_pci_pwrctrl_device_set_ready(dev, &data->ctx); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register the pwrctrl wrapper\n"); + + return 0; +} + +static const struct of_device_id pci_pwrctrl_pwrseq_of_match[] = { + { + /* ATH11K in QCA6390 package. */ + .compatible = "pci17cb,1101", + .data = &pci_pwrctrl_pwrseq_qcom_wcn_pdata, + }, + { + /* ATH11K in WCN6855 package. */ + .compatible = "pci17cb,1103", + .data = &pci_pwrctrl_pwrseq_qcom_wcn_pdata, + }, + { + /* ATH12K in WCN7850 package. */ + .compatible = "pci17cb,1107", + .data = &pci_pwrctrl_pwrseq_qcom_wcn_pdata, + }, + { } +}; +MODULE_DEVICE_TABLE(of, pci_pwrctrl_pwrseq_of_match); + +static struct platform_driver pci_pwrctrl_pwrseq_driver = { + .driver = { + .name = "pci-pwrctrl-pwrseq", + .of_match_table = pci_pwrctrl_pwrseq_of_match, + }, + .probe = pci_pwrctrl_pwrseq_probe, +}; +module_platform_driver(pci_pwrctrl_pwrseq_driver); + +MODULE_AUTHOR("Bartosz Golaszewski "); +MODULE_DESCRIPTION("Generic PCI Power Control module for power sequenced devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index dccb60c1d9cc3d..76f4df75b08a14 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -12,6 +12,7 @@ * file, where their drivers can use them. */ +#include #include #include #include @@ -29,10 +30,23 @@ #include #include #include +#include #include #include #include "pci.h" +static bool pcie_lbms_seen(struct pci_dev *dev, u16 lnksta) +{ + unsigned long count; + int ret; + + ret = pcie_lbms_count(dev, &count); + if (ret < 0) + return lnksta & PCI_EXP_LNKSTA_LBMS; + + return count > 0; +} + /* * Retrain the link of a downstream PCIe port by hand if necessary. * @@ -96,22 +110,16 @@ int pcie_failed_link_retrain(struct pci_dev *dev) pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2); pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); - if ((lnksta & (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_DLLLA)) == - PCI_EXP_LNKSTA_LBMS) { + if (!(lnksta & PCI_EXP_LNKSTA_DLLLA) && pcie_lbms_seen(dev, lnksta)) { u16 oldlnkctl2 = lnkctl2; pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n"); - lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS; - lnkctl2 |= PCI_EXP_LNKCTL2_TLS_2_5GT; - pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, lnkctl2); - - ret = pcie_retrain_link(dev, false); + ret = pcie_set_target_speed(dev, PCIE_SPEED_2_5GT, false); if (ret) { pci_info(dev, "retraining failed\n"); - pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, - oldlnkctl2); - pcie_retrain_link(dev, true); + pcie_set_target_speed(dev, PCIE_LNKCTL2_TLS2SPEED(oldlnkctl2), + true); return ret; } @@ -125,11 +133,7 @@ int pcie_failed_link_retrain(struct pci_dev *dev) pci_info(dev, "removing 2.5GT/s downstream link speed restriction\n"); pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap); - lnkctl2 &= ~PCI_EXP_LNKCTL2_TLS; - lnkctl2 |= lnkcap & PCI_EXP_LNKCAP_SLS; - pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, lnkctl2); - - ret = pcie_retrain_link(dev, false); + ret = pcie_set_target_speed(dev, PCIE_LNKCAP_SLS2SPEED(lnkcap), false); if (ret) { pci_info(dev, "retraining failed\n"); return ret; @@ -586,8 +590,7 @@ static void quirk_extend_bar_to_page(struct pci_dev *dev) const char *r_name = pci_resource_name(dev, i); if (r->flags & IORESOURCE_MEM && resource_size(r) < PAGE_SIZE) { - r->end = PAGE_SIZE - 1; - r->start = 0; + resource_set_range(r, 0, PAGE_SIZE); r->flags |= IORESOURCE_UNSET; pci_info(dev, "%s %pR: expanded to page size\n", r_name, r); @@ -604,10 +607,9 @@ static void quirk_s3_64M(struct pci_dev *dev) { struct resource *r = &dev->resource[0]; - if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) { + if (!IS_ALIGNED(r->start, SZ_64M) || resource_size(r) != SZ_64M) { r->flags |= IORESOURCE_UNSET; - r->start = 0; - r->end = 0x3ffffff; + resource_set_range(r, 0, SZ_64M); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M); @@ -1342,8 +1344,7 @@ static void quirk_dunord(struct pci_dev *dev) struct resource *r = &dev->resource[1]; r->flags |= IORESOURCE_UNSET; - r->start = 0; - r->end = 0xffffff; + resource_set_range(r, 0, SZ_16M); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk_dunord); @@ -2340,8 +2341,7 @@ static void quirk_tc86c001_ide(struct pci_dev *dev) if (r->start & 0x8) { r->flags |= IORESOURCE_UNSET; - r->start = 0; - r->end = 0xf; + resource_set_range(r, 0, SZ_16); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2, @@ -2369,8 +2369,7 @@ static void quirk_plx_pci9050(struct pci_dev *dev) pci_info(dev, "Re-allocating PLX PCI 9050 BAR %u to length 256 to avoid bit 7 bug\n", bar); r->flags |= IORESOURCE_UNSET; - r->start = 0; - r->end = 0xff; + resource_set_range(r, 0, SZ_256); } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, @@ -3522,13 +3521,13 @@ static void quirk_intel_ntb(struct pci_dev *dev) if (rc) return; - dev->resource[2].end = dev->resource[2].start + ((u64) 1 << val) - 1; + resource_set_size(&dev->resource[2], (resource_size_t)1 << val); rc = pci_read_config_byte(dev, 0x00D1, &val); if (rc) return; - dev->resource[4].end = dev->resource[4].start + ((u64) 1 << val) - 1; + resource_set_size(&dev->resource[4], (resource_size_t)1 << val); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb); @@ -4996,18 +4995,21 @@ static int pci_quirk_brcm_acs(struct pci_dev *dev, u16 acs_flags) } /* - * Wangxun 10G/1G NICs have no ACS capability, and on multi-function - * devices, peer-to-peer transactions are not be used between the functions. - * So add an ACS quirk for below devices to isolate functions. + * Wangxun 40G/25G/10G/1G NICs have no ACS capability, but on + * multi-function devices, the hardware isolates the functions by + * directing all peer-to-peer traffic upstream as though PCI_ACS_RR and + * PCI_ACS_CR were set. * SFxxx 1G NICs(em). * RP1000/RP2000 10G NICs(sp). + * FF5xxx 40G/25G/10G NICs(aml). */ static int pci_quirk_wangxun_nic_acs(struct pci_dev *dev, u16 acs_flags) { switch (dev->device) { - case 0x0100 ... 0x010F: - case 0x1001: - case 0x2001: + case 0x0100 ... 0x010F: /* EM */ + case 0x1001: case 0x2001: /* SP */ + case 0x5010: case 0x5025: case 0x5040: /* AML */ + case 0x5110: case 0x5125: case 0x5140: /* AML */ return pci_acs_ctrl_enabled(acs_flags, PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF); } @@ -6266,6 +6268,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa76e, dpc_log_size); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, of_pci_make_dev_node); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, of_pci_make_dev_node); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REDHAT, 0x0005, of_pci_make_dev_node); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_EFAR, 0x9660, of_pci_make_dev_node); /* * Devices known to require a longer delay before first config space access diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index e4ce1145aa3ee0..efc37fcb73e24d 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -17,37 +17,40 @@ static void pci_free_resources(struct pci_dev *dev) } } -static int pci_pwrctl_unregister(struct device *dev, void *data) +static void pci_pwrctrl_unregister(struct device *dev) { - struct device_node *pci_node = data, *plat_node = dev_of_node(dev); + struct device_node *np; + struct platform_device *pdev; - if (dev_is_platform(dev) && plat_node && plat_node == pci_node) { - of_device_unregister(to_platform_device(dev)); - of_node_clear_flag(plat_node, OF_POPULATED); - } + np = dev_of_node(dev); + if (!np) + return; + + pdev = of_find_device_by_node(np); + if (!pdev) + return; - return 0; + of_device_unregister(pdev); + of_node_clear_flag(np, OF_POPULATED); } static void pci_stop_dev(struct pci_dev *dev) { pci_pme_active(dev, false); - if (pci_dev_is_added(dev)) { - device_for_each_child(dev->dev.parent, dev_of_node(&dev->dev), - pci_pwrctl_unregister); - device_release_driver(&dev->dev); - pci_proc_detach_device(dev); - pci_remove_sysfs_dev_files(dev); - of_pci_remove_node(dev); + if (!pci_dev_test_and_clear_added(dev)) + return; - pci_dev_assign_added(dev, false); - } + pci_pwrctrl_unregister(&dev->dev); + device_release_driver(&dev->dev); + pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); + of_pci_remove_node(dev); } static void pci_destroy_dev(struct pci_dev *dev) { - if (!dev->dev.kobj.parent) + if (pci_dev_test_and_set_removed(dev)) return; pci_npem_remove(dev); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 23082bc0ca37ae..5e00cecf1f1af3 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -134,6 +134,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) int i; pci_dev_for_each_resource(dev, r, i) { + const char *r_name = pci_resource_name(dev, i); struct pci_dev_resource *dev_res, *tmp; resource_size_t r_align; struct list_head *n; @@ -146,8 +147,8 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) r_align = pci_resource_alignment(dev, r); if (!r_align) { - pci_warn(dev, "BAR %d: %pR has bogus alignment\n", - i, r); + pci_warn(dev, "%s %pR: alignment must not be zero\n", + r_name, r); continue; } @@ -246,8 +247,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head, add_size = add_res->add_size; align = add_res->min_align; if (!resource_size(res)) { - res->start = align; - res->end = res->start + add_size - 1; + resource_set_range(res, align, add_size); if (pci_assign_resource(add_res->dev, idx)) reset_resource(res); } else { @@ -938,8 +938,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, return; } - b_res->start = min_align; - b_res->end = b_res->start + size0 - 1; + resource_set_range(b_res, min_align, size0); b_res->flags |= IORESOURCE_STARTALIGN; if (bus->self && size1 > size0 && realloc_head) { add_to_list(realloc_head, bus->self, b_res, size1-size0, @@ -1202,8 +1201,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus, * Reserve some resources for CardBus. We reserve a fixed amount * of bus space for CardBus bridges. */ - b_res->start = pci_cardbus_io_size; - b_res->end = b_res->start + pci_cardbus_io_size - 1; + resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size); b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; if (realloc_head) { b_res->end -= pci_cardbus_io_size; @@ -1215,8 +1213,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus, b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW]; if (b_res->parent) goto handle_b_res_2; - b_res->start = pci_cardbus_io_size; - b_res->end = b_res->start + pci_cardbus_io_size - 1; + resource_set_range(b_res, pci_cardbus_io_size, pci_cardbus_io_size); b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN; if (realloc_head) { b_res->end -= pci_cardbus_io_size; @@ -1249,8 +1246,8 @@ static void pci_bus_size_cardbus(struct pci_bus *bus, * Otherwise, allocate one region of twice the size. */ if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) { - b_res->start = pci_cardbus_mem_size; - b_res->end = b_res->start + pci_cardbus_mem_size - 1; + resource_set_range(b_res, pci_cardbus_mem_size, + pci_cardbus_mem_size); b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_STARTALIGN; if (realloc_head) { @@ -1267,8 +1264,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus, b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW]; if (b_res->parent) goto handle_done; - b_res->start = pci_cardbus_mem_size; - b_res->end = b_res->start + b_res_3_size - 1; + resource_set_range(b_res, pci_cardbus_mem_size, b_res_3_size); b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN; if (realloc_head) { b_res->end -= b_res_3_size; @@ -1847,7 +1843,7 @@ static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res, return; } - res->end = res->start + new_size - 1; + resource_set_size(res, new_size); /* If the resource is part of the add_list, remove it now */ if (add_list) @@ -1899,6 +1895,9 @@ static void remove_dev_resources(struct pci_dev *dev, struct resource *io, } } +#define ALIGN_DOWN_IF_NONZERO(addr, align) \ + ((align) ? ALIGN_DOWN((addr), (align)) : (addr)) + /* * io, mmio and mmio_pref contain the total amount of bridge window space * available. This includes the minimal space needed to cover all the @@ -2010,8 +2009,7 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, * what is available). */ align = pci_resource_alignment(dev, res); - io.end = align ? io.start + ALIGN_DOWN(io_per_b, align) - 1 - : io.start + io_per_b - 1; + resource_set_size(&io, ALIGN_DOWN_IF_NONZERO(io_per_b, align)); /* * The x_per_b holds the extra resource space that can be @@ -2023,15 +2021,14 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus, res = &dev->resource[PCI_BRIDGE_MEM_WINDOW]; align = pci_resource_alignment(dev, res); - mmio.end = align ? mmio.start + ALIGN_DOWN(mmio_per_b, align) - 1 - : mmio.start + mmio_per_b - 1; + resource_set_size(&mmio, + ALIGN_DOWN_IF_NONZERO(mmio_per_b,align)); mmio.start -= resource_size(res); res = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW]; align = pci_resource_alignment(dev, res); - mmio_pref.end = align ? mmio_pref.start + - ALIGN_DOWN(mmio_pref_per_b, align) - 1 - : mmio_pref.start + mmio_pref_per_b - 1; + resource_set_size(&mmio_pref, + ALIGN_DOWN_IF_NONZERO(mmio_pref_per_b, align)); mmio_pref.start -= resource_size(res); pci_bus_distribute_available_resources(b, add_list, io, mmio, diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index c6d933ddfd4649..ca14576bf2bf29 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -211,8 +211,7 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev, start = res->start; end = res->end; - res->start = fw_addr; - res->end = res->start + size - 1; + resource_set_range(res, fw_addr, size); res->flags &= ~IORESOURCE_UNSET; root = pci_find_parent_resource(dev, res); @@ -463,7 +462,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size) if (ret) return ret; - res->end = res->start + pci_rebar_size_to_bytes(size) - 1; + resource_set_size(res, pci_rebar_size_to_bytes(size)); /* Check if the new config works by trying to assign everything. */ if (dev->bus->self) { @@ -475,7 +474,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size) error_resize: pci_rebar_set_size(dev, resno, old); - res->end = res->start + pci_rebar_size_to_bytes(old) - 1; + resource_set_size(res, pci_rebar_size_to_bytes(old)); return ret; } EXPORT_SYMBOL(pci_resize_resource); diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 0f87cade10f74b..36b44be0489d62 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -79,6 +79,7 @@ static void pci_slot_release(struct kobject *kobj) up_read(&pci_bus_sem); list_del(&slot->list); + pci_bus_put(slot->bus); kfree(slot); } @@ -244,12 +245,13 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, slot = get_slot(parent, slot_nr); if (slot) { if (hotplug) { - if ((err = slot->hotplug ? -EBUSY : 0) - || (err = rename_slot(slot, name))) { - kobject_put(&slot->kobj); - slot = NULL; - goto err; + if (slot->hotplug) { + err = -EBUSY; + goto put_slot; } + err = rename_slot(slot, name); + if (err) + goto put_slot; } goto out; } @@ -261,7 +263,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, goto err; } - slot->bus = parent; + slot->bus = pci_bus_get(parent); slot->number = slot_nr; slot->kobj.kset = pci_slots_kset; @@ -269,6 +271,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, slot_name = make_slot_name(name); if (!slot_name) { err = -ENOMEM; + pci_bus_put(slot->bus); kfree(slot); goto err; } @@ -278,10 +281,8 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, "%s", slot_name); - if (err) { - kobject_put(&slot->kobj); - goto err; - } + if (err) + goto put_slot; down_read(&pci_bus_sem); list_for_each_entry(dev, &parent->devices, bus_list) @@ -296,6 +297,9 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, kfree(slot_name); mutex_unlock(&pci_slot_mutex); return slot; + +put_slot: + kobject_put(&slot->kobj); err: slot = ERR_PTR(err); goto out; diff --git a/drivers/pci/tph.c b/drivers/pci/tph.c new file mode 100644 index 00000000000000..1e604fbbda6573 --- /dev/null +++ b/drivers/pci/tph.c @@ -0,0 +1,547 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TPH (TLP Processing Hints) support + * + * Copyright (C) 2024 Advanced Micro Devices, Inc. + * Eric Van Tassell + * Wei Huang + */ +#include +#include +#include +#include +#include + +#include "pci.h" + +/* System-wide TPH disabled */ +static bool pci_tph_disabled; + +#ifdef CONFIG_ACPI +/* + * The st_info struct defines the Steering Tag (ST) info returned by the + * firmware PCI ACPI _DSM method (rev=0x7, func=0xF, "_DSM to Query Cache + * Locality TPH Features"), as specified in the approved ECN for PCI Firmware + * Spec and available at https://members.pcisig.com/wg/PCI-SIG/document/15470. + * + * @vm_st_valid: 8-bit ST for volatile memory is valid + * @vm_xst_valid: 16-bit extended ST for volatile memory is valid + * @vm_ph_ignore: 1 => PH was and will be ignored, 0 => PH should be supplied + * @vm_st: 8-bit ST for volatile mem + * @vm_xst: 16-bit extended ST for volatile mem + * @pm_st_valid: 8-bit ST for persistent memory is valid + * @pm_xst_valid: 16-bit extended ST for persistent memory is valid + * @pm_ph_ignore: 1 => PH was and will be ignored, 0 => PH should be supplied + * @pm_st: 8-bit ST for persistent mem + * @pm_xst: 16-bit extended ST for persistent mem + */ +union st_info { + struct { + u64 vm_st_valid : 1; + u64 vm_xst_valid : 1; + u64 vm_ph_ignore : 1; + u64 rsvd1 : 5; + u64 vm_st : 8; + u64 vm_xst : 16; + u64 pm_st_valid : 1; + u64 pm_xst_valid : 1; + u64 pm_ph_ignore : 1; + u64 rsvd2 : 5; + u64 pm_st : 8; + u64 pm_xst : 16; + }; + u64 value; +}; + +static u16 tph_extract_tag(enum tph_mem_type mem_type, u8 req_type, + union st_info *info) +{ + switch (req_type) { + case PCI_TPH_REQ_TPH_ONLY: /* 8-bit tag */ + switch (mem_type) { + case TPH_MEM_TYPE_VM: + if (info->vm_st_valid) + return info->vm_st; + break; + case TPH_MEM_TYPE_PM: + if (info->pm_st_valid) + return info->pm_st; + break; + } + break; + case PCI_TPH_REQ_EXT_TPH: /* 16-bit tag */ + switch (mem_type) { + case TPH_MEM_TYPE_VM: + if (info->vm_xst_valid) + return info->vm_xst; + break; + case TPH_MEM_TYPE_PM: + if (info->pm_xst_valid) + return info->pm_xst; + break; + } + break; + default: + return 0; + } + + return 0; +} + +#define TPH_ST_DSM_FUNC_INDEX 0xF +static acpi_status tph_invoke_dsm(acpi_handle handle, u32 cpu_uid, + union st_info *st_out) +{ + union acpi_object arg3[3], in_obj, *out_obj; + + if (!acpi_check_dsm(handle, &pci_acpi_dsm_guid, 7, + BIT(TPH_ST_DSM_FUNC_INDEX))) + return AE_ERROR; + + /* DWORD: feature ID (0 for processor cache ST query) */ + arg3[0].integer.type = ACPI_TYPE_INTEGER; + arg3[0].integer.value = 0; + + /* DWORD: target UID */ + arg3[1].integer.type = ACPI_TYPE_INTEGER; + arg3[1].integer.value = cpu_uid; + + /* QWORD: properties, all 0's */ + arg3[2].integer.type = ACPI_TYPE_INTEGER; + arg3[2].integer.value = 0; + + in_obj.type = ACPI_TYPE_PACKAGE; + in_obj.package.count = ARRAY_SIZE(arg3); + in_obj.package.elements = arg3; + + out_obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 7, + TPH_ST_DSM_FUNC_INDEX, &in_obj); + if (!out_obj) + return AE_ERROR; + + if (out_obj->type != ACPI_TYPE_BUFFER) { + ACPI_FREE(out_obj); + return AE_ERROR; + } + + st_out->value = *((u64 *)(out_obj->buffer.pointer)); + + ACPI_FREE(out_obj); + + return AE_OK; +} +#endif + +/* Update the TPH Requester Enable field of TPH Control Register */ +static void set_ctrl_reg_req_en(struct pci_dev *pdev, u8 req_type) +{ + u32 reg; + + pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, ®); + + reg &= ~PCI_TPH_CTRL_REQ_EN_MASK; + reg |= FIELD_PREP(PCI_TPH_CTRL_REQ_EN_MASK, req_type); + + pci_write_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, reg); +} + +static u8 get_st_modes(struct pci_dev *pdev) +{ + u32 reg; + + pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CAP, ®); + reg &= PCI_TPH_CAP_ST_NS | PCI_TPH_CAP_ST_IV | PCI_TPH_CAP_ST_DS; + + return reg; +} + +static u32 get_st_table_loc(struct pci_dev *pdev) +{ + u32 reg; + + pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CAP, ®); + + return FIELD_GET(PCI_TPH_CAP_LOC_MASK, reg); +} + +/* + * Return the size of ST table. If ST table is not in TPH Requester Extended + * Capability space, return 0. Otherwise return the ST Table Size + 1. + */ +static u16 get_st_table_size(struct pci_dev *pdev) +{ + u32 reg; + u32 loc; + + /* Check ST table location first */ + loc = get_st_table_loc(pdev); + + /* Convert loc to match with PCI_TPH_LOC_* defined in pci_regs.h */ + loc = FIELD_PREP(PCI_TPH_CAP_LOC_MASK, loc); + if (loc != PCI_TPH_LOC_CAP) + return 0; + + pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CAP, ®); + + return FIELD_GET(PCI_TPH_CAP_ST_MASK, reg) + 1; +} + +/* Return device's Root Port completer capability */ +static u8 get_rp_completer_type(struct pci_dev *pdev) +{ + struct pci_dev *rp; + u32 reg; + int ret; + + rp = pcie_find_root_port(pdev); + if (!rp) + return 0; + + ret = pcie_capability_read_dword(rp, PCI_EXP_DEVCAP2, ®); + if (ret) + return 0; + + return FIELD_GET(PCI_EXP_DEVCAP2_TPH_COMP_MASK, reg); +} + +/* Write ST to MSI-X vector control reg - Return 0 if OK, otherwise -errno */ +static int write_tag_to_msix(struct pci_dev *pdev, int msix_idx, u16 tag) +{ +#ifdef CONFIG_PCI_MSI + struct msi_desc *msi_desc = NULL; + void __iomem *vec_ctrl; + u32 val; + int err = 0; + + msi_lock_descs(&pdev->dev); + + /* Find the msi_desc entry with matching msix_idx */ + msi_for_each_desc(msi_desc, &pdev->dev, MSI_DESC_ASSOCIATED) { + if (msi_desc->msi_index == msix_idx) + break; + } + + if (!msi_desc) { + err = -ENXIO; + goto err_out; + } + + /* Get the vector control register (offset 0xc) pointed by msix_idx */ + vec_ctrl = pdev->msix_base + msix_idx * PCI_MSIX_ENTRY_SIZE; + vec_ctrl += PCI_MSIX_ENTRY_VECTOR_CTRL; + + val = readl(vec_ctrl); + val &= ~PCI_MSIX_ENTRY_CTRL_ST; + val |= FIELD_PREP(PCI_MSIX_ENTRY_CTRL_ST, tag); + writel(val, vec_ctrl); + + /* Read back to flush the update */ + val = readl(vec_ctrl); + +err_out: + msi_unlock_descs(&pdev->dev); + return err; +#else + return -ENODEV; +#endif +} + +/* Write tag to ST table - Return 0 if OK, otherwise -errno */ +static int write_tag_to_st_table(struct pci_dev *pdev, int index, u16 tag) +{ + int st_table_size; + int offset; + + /* Check if index is out of bound */ + st_table_size = get_st_table_size(pdev); + if (index >= st_table_size) + return -ENXIO; + + offset = pdev->tph_cap + PCI_TPH_BASE_SIZEOF + index * sizeof(u16); + + return pci_write_config_word(pdev, offset, tag); +} + +/** + * pcie_tph_get_cpu_st() - Retrieve Steering Tag for a target memory associated + * with a specific CPU + * @pdev: PCI device + * @mem_type: target memory type (volatile or persistent RAM) + * @cpu_uid: associated CPU id + * @tag: Steering Tag to be returned + * + * Return the Steering Tag for a target memory that is associated with a + * specific CPU as indicated by cpu_uid. + * + * Return: 0 if success, otherwise negative value (-errno) + */ +int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type mem_type, + unsigned int cpu_uid, u16 *tag) +{ +#ifdef CONFIG_ACPI + struct pci_dev *rp; + acpi_handle rp_acpi_handle; + union st_info info; + + rp = pcie_find_root_port(pdev); + if (!rp || !rp->bus || !rp->bus->bridge) + return -ENODEV; + + rp_acpi_handle = ACPI_HANDLE(rp->bus->bridge); + + if (tph_invoke_dsm(rp_acpi_handle, cpu_uid, &info) != AE_OK) { + *tag = 0; + return -EINVAL; + } + + *tag = tph_extract_tag(mem_type, pdev->tph_req_type, &info); + + pci_dbg(pdev, "get steering tag: mem_type=%s, cpu_uid=%d, tag=%#04x\n", + (mem_type == TPH_MEM_TYPE_VM) ? "volatile" : "persistent", + cpu_uid, *tag); + + return 0; +#else + return -ENODEV; +#endif +} +EXPORT_SYMBOL(pcie_tph_get_cpu_st); + +/** + * pcie_tph_set_st_entry() - Set Steering Tag in the ST table entry + * @pdev: PCI device + * @index: ST table entry index + * @tag: Steering Tag to be written + * + * Figure out the proper location of ST table, either in the MSI-X table or + * in the TPH Extended Capability space, and write the Steering Tag into + * the ST entry pointed by index. + * + * Return: 0 if success, otherwise negative value (-errno) + */ +int pcie_tph_set_st_entry(struct pci_dev *pdev, unsigned int index, u16 tag) +{ + u32 loc; + int err = 0; + + if (!pdev->tph_cap) + return -EINVAL; + + if (!pdev->tph_enabled) + return -EINVAL; + + /* No need to write tag if device is in "No ST Mode" */ + if (pdev->tph_mode == PCI_TPH_ST_NS_MODE) + return 0; + + /* + * Disable TPH before updating ST to avoid potential instability as + * cautioned in PCIe r6.2, sec 6.17.3, "ST Modes of Operation" + */ + set_ctrl_reg_req_en(pdev, PCI_TPH_REQ_DISABLE); + + loc = get_st_table_loc(pdev); + /* Convert loc to match with PCI_TPH_LOC_* */ + loc = FIELD_PREP(PCI_TPH_CAP_LOC_MASK, loc); + + switch (loc) { + case PCI_TPH_LOC_MSIX: + err = write_tag_to_msix(pdev, index, tag); + break; + case PCI_TPH_LOC_CAP: + err = write_tag_to_st_table(pdev, index, tag); + break; + default: + err = -EINVAL; + } + + if (err) { + pcie_disable_tph(pdev); + return err; + } + + set_ctrl_reg_req_en(pdev, pdev->tph_mode); + + pci_dbg(pdev, "set steering tag: %s table, index=%d, tag=%#04x\n", + (loc == PCI_TPH_LOC_MSIX) ? "MSI-X" : "ST", index, tag); + + return 0; +} +EXPORT_SYMBOL(pcie_tph_set_st_entry); + +/** + * pcie_disable_tph - Turn off TPH support for device + * @pdev: PCI device + * + * Return: none + */ +void pcie_disable_tph(struct pci_dev *pdev) +{ + if (!pdev->tph_cap) + return; + + if (!pdev->tph_enabled) + return; + + pci_write_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, 0); + + pdev->tph_mode = 0; + pdev->tph_req_type = 0; + pdev->tph_enabled = 0; +} +EXPORT_SYMBOL(pcie_disable_tph); + +/** + * pcie_enable_tph - Enable TPH support for device using a specific ST mode + * @pdev: PCI device + * @mode: ST mode to enable. Current supported modes include: + * + * - PCI_TPH_ST_NS_MODE: NO ST Mode + * - PCI_TPH_ST_IV_MODE: Interrupt Vector Mode + * - PCI_TPH_ST_DS_MODE: Device Specific Mode + * + * Check whether the mode is actually supported by the device before enabling + * and return an error if not. Additionally determine what types of requests, + * TPH or extended TPH, can be issued by the device based on its TPH requester + * capability and the Root Port's completer capability. + * + * Return: 0 on success, otherwise negative value (-errno) + */ +int pcie_enable_tph(struct pci_dev *pdev, int mode) +{ + u32 reg; + u8 dev_modes; + u8 rp_req_type; + + /* Honor "notph" kernel parameter */ + if (pci_tph_disabled) + return -EINVAL; + + if (!pdev->tph_cap) + return -EINVAL; + + if (pdev->tph_enabled) + return -EBUSY; + + /* Sanitize and check ST mode compatibility */ + mode &= PCI_TPH_CTRL_MODE_SEL_MASK; + dev_modes = get_st_modes(pdev); + if (!((1 << mode) & dev_modes)) + return -EINVAL; + + pdev->tph_mode = mode; + + /* Get req_type supported by device and its Root Port */ + pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CAP, ®); + if (FIELD_GET(PCI_TPH_CAP_EXT_TPH, reg)) + pdev->tph_req_type = PCI_TPH_REQ_EXT_TPH; + else + pdev->tph_req_type = PCI_TPH_REQ_TPH_ONLY; + + rp_req_type = get_rp_completer_type(pdev); + + /* Final req_type is the smallest value of two */ + pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type); + + if (pdev->tph_req_type == PCI_TPH_REQ_DISABLE) + return -EINVAL; + + /* Write them into TPH control register */ + pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, ®); + + reg &= ~PCI_TPH_CTRL_MODE_SEL_MASK; + reg |= FIELD_PREP(PCI_TPH_CTRL_MODE_SEL_MASK, pdev->tph_mode); + + reg &= ~PCI_TPH_CTRL_REQ_EN_MASK; + reg |= FIELD_PREP(PCI_TPH_CTRL_REQ_EN_MASK, pdev->tph_req_type); + + pci_write_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, reg); + + pdev->tph_enabled = 1; + + return 0; +} +EXPORT_SYMBOL(pcie_enable_tph); + +void pci_restore_tph_state(struct pci_dev *pdev) +{ + struct pci_cap_saved_state *save_state; + int num_entries, i, offset; + u16 *st_entry; + u32 *cap; + + if (!pdev->tph_cap) + return; + + if (!pdev->tph_enabled) + return; + + save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_TPH); + if (!save_state) + return; + + /* Restore control register and all ST entries */ + cap = &save_state->cap.data[0]; + pci_write_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, *cap++); + st_entry = (u16 *)cap; + offset = PCI_TPH_BASE_SIZEOF; + num_entries = get_st_table_size(pdev); + for (i = 0; i < num_entries; i++) { + pci_write_config_word(pdev, pdev->tph_cap + offset, + *st_entry++); + offset += sizeof(u16); + } +} + +void pci_save_tph_state(struct pci_dev *pdev) +{ + struct pci_cap_saved_state *save_state; + int num_entries, i, offset; + u16 *st_entry; + u32 *cap; + + if (!pdev->tph_cap) + return; + + if (!pdev->tph_enabled) + return; + + save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_TPH); + if (!save_state) + return; + + /* Save control register */ + cap = &save_state->cap.data[0]; + pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, cap++); + + /* Save all ST entries in extended capability structure */ + st_entry = (u16 *)cap; + offset = PCI_TPH_BASE_SIZEOF; + num_entries = get_st_table_size(pdev); + for (i = 0; i < num_entries; i++) { + pci_read_config_word(pdev, pdev->tph_cap + offset, + st_entry++); + offset += sizeof(u16); + } +} + +void pci_no_tph(void) +{ + pci_tph_disabled = true; + + pr_info("PCIe TPH is disabled\n"); +} + +void pci_tph_init(struct pci_dev *pdev) +{ + int num_entries; + u32 save_size; + + pdev->tph_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_TPH); + if (!pdev->tph_cap) + return; + + num_entries = get_st_table_size(pdev); + save_size = sizeof(u32) + num_entries * sizeof(u16); + pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_TPH, save_size); +} diff --git a/drivers/pci/vpd.c b/drivers/pci/vpd.c index e4300f5f304f3c..a469bcbc0da7f7 100644 --- a/drivers/pci/vpd.c +++ b/drivers/pci/vpd.c @@ -325,7 +325,7 @@ static struct bin_attribute *vpd_attrs[] = { }; static umode_t vpd_attr_is_visible(struct kobject *kobj, - struct bin_attribute *a, int n) + const struct bin_attribute *a, int n) { struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); diff --git a/drivers/pcmcia/bcm63xx_pcmcia.c b/drivers/pcmcia/bcm63xx_pcmcia.c index 5bda3e6d43d83e..85874b7a9f3685 100644 --- a/drivers/pcmcia/bcm63xx_pcmcia.c +++ b/drivers/pcmcia/bcm63xx_pcmcia.c @@ -453,7 +453,7 @@ static void bcm63xx_drv_pcmcia_remove(struct platform_device *pdev) struct platform_driver bcm63xx_pcmcia_driver = { .probe = bcm63xx_drv_pcmcia_probe, - .remove_new = bcm63xx_drv_pcmcia_remove, + .remove = bcm63xx_drv_pcmcia_remove, .driver = { .name = "bcm63xx_pcmcia", }, diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 509713b9a502b7..85d2616061dda6 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -592,7 +592,7 @@ static struct platform_driver db1x_pcmcia_socket_driver = { .name = "db1xxx_pcmcia", }, .probe = db1x_pcmcia_socket_probe, - .remove_new = db1x_pcmcia_socket_remove, + .remove = db1x_pcmcia_socket_remove, }; module_platform_driver(db1x_pcmcia_socket_driver); diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c index 5ae826e548116c..3bdd939dd2f4a5 100644 --- a/drivers/pcmcia/electra_cf.c +++ b/drivers/pcmcia/electra_cf.c @@ -342,7 +342,7 @@ static struct platform_driver electra_cf_driver = { .of_match_table = electra_cf_match, }, .probe = electra_cf_probe, - .remove_new = electra_cf_remove, + .remove = electra_cf_remove, }; module_platform_driver(electra_cf_driver); diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 80137c7afe0d9b..f0ccf479f36e52 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -306,7 +306,7 @@ static struct platform_driver omap_cf_driver = { .driver = { .name = driver_name, }, - .remove_new = __exit_p(omap_cf_remove), + .remove = __exit_p(omap_cf_remove), }; static int __init omap_cf_init(void) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 457fb81b497a10..370a8e16dc817f 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -336,7 +336,7 @@ static const struct dev_pm_ops pxa2xx_drv_pcmcia_pm_ops = { static struct platform_driver pxa2xx_pcmcia_driver = { .probe = pxa2xx_drv_pcmcia_probe, - .remove_new = pxa2xx_drv_pcmcia_remove, + .remove = pxa2xx_drv_pcmcia_remove, .driver = { .name = "pxa2xx-pcmcia", .pm = &pxa2xx_drv_pcmcia_pm_ops, diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index ccb219c3876170..7b5ac8fe811df9 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -177,7 +177,7 @@ static struct platform_driver sa11x0_pcmcia_driver = { .name = "sa11x0-pcmcia", }, .probe = sa11x0_drv_pcmcia_probe, - .remove_new = sa11x0_drv_pcmcia_remove, + .remove = sa11x0_drv_pcmcia_remove, }; /* sa11x0_pcmcia_init() diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 61b0c8952bb5e0..1deb9960db3419 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -204,14 +204,8 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) for (i = 0; i < ARRAY_SIZE(skt->stat); i++) { if (gpio_is_valid(skt->stat[i].gpio)) { - unsigned long flags = GPIOF_IN; - - /* CD is active low by default */ - if (i == SOC_STAT_CD) - flags |= GPIOF_ACTIVE_LOW; - ret = devm_gpio_request_one(skt->socket.dev.parent, - skt->stat[i].gpio, flags, + skt->stat[i].gpio, GPIOF_IN, skt->stat[i].name); if (ret) { __soc_pcmcia_hw_shutdown(skt, i); @@ -219,6 +213,10 @@ static int soc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) } skt->stat[i].desc = gpio_to_desc(skt->stat[i].gpio); + + /* CD is active low by default */ + if ((i == SOC_STAT_CD) ^ gpiod_is_active_low(skt->stat[i].desc)) + gpiod_toggle_active_low(skt->stat[i].desc); } if (i < SOC_STAT_VS1 && skt->stat[i].desc) { diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c index 2a93fbbd128da9..f84dd5914a6bda 100644 --- a/drivers/pcmcia/xxs1500_ss.c +++ b/drivers/pcmcia/xxs1500_ss.c @@ -316,7 +316,7 @@ static struct platform_driver xxs1500_pcmcia_socket_driver = { .name = "xxs1500_pcmcia", }, .probe = xxs1500_pcmcia_probe, - .remove_new = xxs1500_pcmcia_remove, + .remove = xxs1500_pcmcia_remove, }; module_platform_driver(xxs1500_pcmcia_socket_driver); diff --git a/drivers/peci/controller/peci-aspeed.c b/drivers/peci/controller/peci-aspeed.c index b93eb6f43b98fa..ad3a7d71ed4c61 100644 --- a/drivers/peci/controller/peci-aspeed.c +++ b/drivers/peci/controller/peci-aspeed.c @@ -597,4 +597,4 @@ MODULE_AUTHOR("Ryan Chen "); MODULE_AUTHOR("Jae Hyun Yoo "); MODULE_DESCRIPTION("ASPEED PECI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PECI); +MODULE_IMPORT_NS("PECI"); diff --git a/drivers/peci/controller/peci-npcm.c b/drivers/peci/controller/peci-npcm.c index ec613d35c7962e..c77591ca583d8d 100644 --- a/drivers/peci/controller/peci-npcm.c +++ b/drivers/peci/controller/peci-npcm.c @@ -224,7 +224,7 @@ static const struct regmap_config npcm_peci_regmap_config = { .fast_io = true, }; -static struct peci_controller_ops npcm_ops = { +static const struct peci_controller_ops npcm_ops = { .xfer = npcm_peci_xfer, }; @@ -295,4 +295,4 @@ module_platform_driver(npcm_peci_driver); MODULE_AUTHOR("Tomer Maimon "); MODULE_DESCRIPTION("NPCM PECI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PECI); +MODULE_IMPORT_NS("PECI"); diff --git a/drivers/peci/core.c b/drivers/peci/core.c index 25e46579dd9c44..936c1fadefe5fd 100644 --- a/drivers/peci/core.c +++ b/drivers/peci/core.c @@ -158,7 +158,7 @@ struct peci_controller *devm_peci_controller_add(struct device *dev, return ERR_PTR(ret); } -EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI); +EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, "PECI"); static const struct peci_device_id * peci_bus_match_device_id(const struct peci_device_id *id, struct peci_device *device) diff --git a/drivers/peci/cpu.c b/drivers/peci/cpu.c index 152bbd8e717a60..2dac8ba8278728 100644 --- a/drivers/peci/cpu.c +++ b/drivers/peci/cpu.c @@ -32,7 +32,7 @@ int peci_temp_read(struct peci_device *device, s16 *temp_raw) return 0; } -EXPORT_SYMBOL_NS_GPL(peci_temp_read, PECI_CPU); +EXPORT_SYMBOL_NS_GPL(peci_temp_read, "PECI_CPU"); /** * peci_pcs_read() - read PCS register @@ -64,7 +64,7 @@ int peci_pcs_read(struct peci_device *device, u8 index, u16 param, u32 *data) return ret; } -EXPORT_SYMBOL_NS_GPL(peci_pcs_read, PECI_CPU); +EXPORT_SYMBOL_NS_GPL(peci_pcs_read, "PECI_CPU"); /** * peci_pci_local_read() - read 32-bit memory location using raw address @@ -99,7 +99,7 @@ int peci_pci_local_read(struct peci_device *device, u8 bus, u8 dev, u8 func, return ret; } -EXPORT_SYMBOL_NS_GPL(peci_pci_local_read, PECI_CPU); +EXPORT_SYMBOL_NS_GPL(peci_pci_local_read, "PECI_CPU"); /** * peci_ep_pci_local_read() - read 32-bit memory location using raw address @@ -135,7 +135,7 @@ int peci_ep_pci_local_read(struct peci_device *device, u8 seg, return ret; } -EXPORT_SYMBOL_NS_GPL(peci_ep_pci_local_read, PECI_CPU); +EXPORT_SYMBOL_NS_GPL(peci_ep_pci_local_read, "PECI_CPU"); /** * peci_mmio_read() - read 32-bit memory location using 64-bit bar offset address @@ -172,7 +172,7 @@ int peci_mmio_read(struct peci_device *device, u8 bar, u8 seg, return ret; } -EXPORT_SYMBOL_NS_GPL(peci_mmio_read, PECI_CPU); +EXPORT_SYMBOL_NS_GPL(peci_mmio_read, "PECI_CPU"); static const char * const peci_adev_types[] = { "cputemp", @@ -337,4 +337,4 @@ module_peci_driver(peci_cpu_driver); MODULE_AUTHOR("Iwona Winiarska "); MODULE_DESCRIPTION("PECI CPU driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(PECI); +MODULE_IMPORT_NS("PECI"); diff --git a/drivers/peci/device.c b/drivers/peci/device.c index 37ca7dd61807c7..416635029f55b3 100644 --- a/drivers/peci/device.c +++ b/drivers/peci/device.c @@ -230,13 +230,13 @@ int __peci_driver_register(struct peci_driver *driver, struct module *owner, return driver_register(&driver->driver); } -EXPORT_SYMBOL_NS_GPL(__peci_driver_register, PECI); +EXPORT_SYMBOL_NS_GPL(__peci_driver_register, "PECI"); void peci_driver_unregister(struct peci_driver *driver) { driver_unregister(&driver->driver); } -EXPORT_SYMBOL_NS_GPL(peci_driver_unregister, PECI); +EXPORT_SYMBOL_NS_GPL(peci_driver_unregister, "PECI"); static void peci_device_release(struct device *dev) { diff --git a/drivers/peci/request.c b/drivers/peci/request.c index 87eefe66743f2d..e6327af45fc7c0 100644 --- a/drivers/peci/request.c +++ b/drivers/peci/request.c @@ -128,7 +128,7 @@ int peci_request_status(struct peci_request *req) return -EIO; } -EXPORT_SYMBOL_NS_GPL(peci_request_status, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_status, "PECI"); static int peci_request_xfer(struct peci_request *req) { @@ -213,7 +213,7 @@ struct peci_request *peci_request_alloc(struct peci_device *device, u8 tx_len, u return req; } -EXPORT_SYMBOL_NS_GPL(peci_request_alloc, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_alloc, "PECI"); /** * peci_request_free() - free peci_request @@ -223,7 +223,7 @@ void peci_request_free(struct peci_request *req) { kfree(req); } -EXPORT_SYMBOL_NS_GPL(peci_request_free, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_free, "PECI"); struct peci_request *peci_xfer_get_dib(struct peci_device *device) { @@ -244,7 +244,7 @@ struct peci_request *peci_xfer_get_dib(struct peci_device *device) return req; } -EXPORT_SYMBOL_NS_GPL(peci_xfer_get_dib, PECI); +EXPORT_SYMBOL_NS_GPL(peci_xfer_get_dib, "PECI"); struct peci_request *peci_xfer_get_temp(struct peci_device *device) { @@ -265,7 +265,7 @@ struct peci_request *peci_xfer_get_temp(struct peci_device *device) return req; } -EXPORT_SYMBOL_NS_GPL(peci_xfer_get_temp, PECI); +EXPORT_SYMBOL_NS_GPL(peci_xfer_get_temp, "PECI"); static struct peci_request * __pkg_cfg_read(struct peci_device *device, u8 index, u16 param, u8 len) @@ -397,44 +397,44 @@ u8 peci_request_data_readb(struct peci_request *req) { return req->rx.buf[1]; } -EXPORT_SYMBOL_NS_GPL(peci_request_data_readb, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_data_readb, "PECI"); u16 peci_request_data_readw(struct peci_request *req) { return get_unaligned_le16(&req->rx.buf[1]); } -EXPORT_SYMBOL_NS_GPL(peci_request_data_readw, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_data_readw, "PECI"); u32 peci_request_data_readl(struct peci_request *req) { return get_unaligned_le32(&req->rx.buf[1]); } -EXPORT_SYMBOL_NS_GPL(peci_request_data_readl, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_data_readl, "PECI"); u64 peci_request_data_readq(struct peci_request *req) { return get_unaligned_le64(&req->rx.buf[1]); } -EXPORT_SYMBOL_NS_GPL(peci_request_data_readq, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_data_readq, "PECI"); u64 peci_request_dib_read(struct peci_request *req) { return get_unaligned_le64(&req->rx.buf[0]); } -EXPORT_SYMBOL_NS_GPL(peci_request_dib_read, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_dib_read, "PECI"); s16 peci_request_temp_read(struct peci_request *req) { return get_unaligned_le16(&req->rx.buf[0]); } -EXPORT_SYMBOL_NS_GPL(peci_request_temp_read, PECI); +EXPORT_SYMBOL_NS_GPL(peci_request_temp_read, "PECI"); #define __read_pkg_config(x, type) \ struct peci_request *peci_xfer_pkg_cfg_##x(struct peci_device *device, u8 index, u16 param) \ { \ return __pkg_cfg_read(device, index, param, sizeof(type)); \ } \ -EXPORT_SYMBOL_NS_GPL(peci_xfer_pkg_cfg_##x, PECI) +EXPORT_SYMBOL_NS_GPL(peci_xfer_pkg_cfg_##x, "PECI") __read_pkg_config(readb, u8); __read_pkg_config(readw, u16); @@ -447,7 +447,7 @@ peci_xfer_pci_cfg_local_##x(struct peci_device *device, u8 bus, u8 dev, u8 func, { \ return __pci_cfg_local_read(device, bus, dev, func, reg, sizeof(type)); \ } \ -EXPORT_SYMBOL_NS_GPL(peci_xfer_pci_cfg_local_##x, PECI) +EXPORT_SYMBOL_NS_GPL(peci_xfer_pci_cfg_local_##x, "PECI") __read_pci_config_local(readb, u8); __read_pci_config_local(readw, u16); @@ -459,7 +459,7 @@ peci_xfer_ep_pci_cfg_##x(struct peci_device *device, u8 seg, u8 bus, u8 dev, u8 { \ return __ep_pci_cfg_read(device, msg_type, seg, bus, dev, func, reg, sizeof(type)); \ } \ -EXPORT_SYMBOL_NS_GPL(peci_xfer_ep_pci_cfg_##x, PECI) +EXPORT_SYMBOL_NS_GPL(peci_xfer_ep_pci_cfg_##x, "PECI") __read_ep_pci_config(local_readb, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u8); __read_ep_pci_config(local_readw, PECI_ENDPTCFG_TYPE_LOCAL_PCI, u16); @@ -476,7 +476,7 @@ struct peci_request *peci_xfer_ep_mmio##y##_##x(struct peci_device *device, u8 b offset, PECI_RDENDPTCFG_MMIO_WR_LEN_BASE + sizeof(type1), \ sizeof(type2)); \ } \ -EXPORT_SYMBOL_NS_GPL(peci_xfer_ep_mmio##y##_##x, PECI) +EXPORT_SYMBOL_NS_GPL(peci_xfer_ep_mmio##y##_##x, "PECI") __read_ep_mmio(readl, 32, PECI_ENDPTCFG_ADDR_TYPE_MMIO_D, u32, u32); __read_ep_mmio(readl, 64, PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q, u64, u32); diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index bab8ba64162ffd..4e268de351c48a 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -284,4 +284,11 @@ config CXL_PMU If unsure say 'm'. +config MARVELL_PEM_PMU + tristate "MARVELL PEM PMU Support" + depends on ARCH_THUNDER || (COMPILE_TEST && 64BIT) + help + Enable support for PCIe Interface performance monitoring + on Marvell platform. + endmenu diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index 8268f38e42c5ae..de71d25748575a 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o obj-$(CONFIG_ARM_DMC620_PMU) += arm_dmc620_pmu.o obj-$(CONFIG_MARVELL_CN10K_TAD_PMU) += marvell_cn10k_tad_pmu.o obj-$(CONFIG_MARVELL_CN10K_DDR_PMU) += marvell_cn10k_ddr_pmu.o +obj-$(CONFIG_MARVELL_PEM_PMU) += marvell_pem_pmu.o obj-$(CONFIG_APPLE_M1_CPU_PMU) += apple_m1_cpu_pmu.o obj-$(CONFIG_ALIBABA_UNCORE_DRW_PMU) += alibaba_uncore_drw_pmu.o obj-$(CONFIG_DWC_PCIE_PMU) += dwc_pcie_pmu.o diff --git a/drivers/perf/alibaba_uncore_drw_pmu.c b/drivers/perf/alibaba_uncore_drw_pmu.c index c6ff1bc7d336b8..99a0ef9817e05f 100644 --- a/drivers/perf/alibaba_uncore_drw_pmu.c +++ b/drivers/perf/alibaba_uncore_drw_pmu.c @@ -782,7 +782,7 @@ static struct platform_driver ali_drw_pmu_driver = { .acpi_match_table = ali_drw_acpi_match, }, .probe = ali_drw_pmu_probe, - .remove_new = ali_drw_pmu_remove, + .remove = ali_drw_pmu_remove, }; static int __init ali_drw_pmu_init(void) diff --git a/drivers/perf/amlogic/meson_g12_ddr_pmu.c b/drivers/perf/amlogic/meson_g12_ddr_pmu.c index 99cc791892bce0..f33e9a456e85e9 100644 --- a/drivers/perf/amlogic/meson_g12_ddr_pmu.c +++ b/drivers/perf/amlogic/meson_g12_ddr_pmu.c @@ -379,7 +379,7 @@ MODULE_DEVICE_TABLE(of, meson_ddr_pmu_dt_match); static struct platform_driver g12_ddr_pmu_driver = { .probe = g12_ddr_pmu_probe, - .remove_new = g12_ddr_pmu_remove, + .remove = g12_ddr_pmu_remove, .driver = { .name = "meson-g12-ddr-pmu", diff --git a/drivers/perf/arm-cci.c b/drivers/perf/arm-cci.c index c76bac668deaf6..1cc3214d6b6da0 100644 --- a/drivers/perf/arm-cci.c +++ b/drivers/perf/arm-cci.c @@ -1705,7 +1705,7 @@ static struct platform_driver cci_pmu_driver = { .suppress_bind_attrs = true, }, .probe = cci_pmu_probe, - .remove_new = cci_pmu_remove, + .remove = cci_pmu_remove, }; module_platform_driver(cci_pmu_driver); diff --git a/drivers/perf/arm-ccn.c b/drivers/perf/arm-ccn.c index 5c66b927886237..d5fcea3d4328be 100644 --- a/drivers/perf/arm-ccn.c +++ b/drivers/perf/arm-ccn.c @@ -1529,7 +1529,7 @@ static struct platform_driver arm_ccn_driver = { .suppress_bind_attrs = true, }, .probe = arm_ccn_probe, - .remove_new = arm_ccn_remove, + .remove = arm_ccn_remove, }; static int __init arm_ccn_init(void) diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c index 397a46410f7cb7..b20fa600e510c5 100644 --- a/drivers/perf/arm-cmn.c +++ b/drivers/perf/arm-cmn.c @@ -2178,8 +2178,6 @@ static int arm_cmn_init_dtcs(struct arm_cmn *cmn) continue; xp = arm_cmn_node_to_xp(cmn, dn); - dn->portid_bits = xp->portid_bits; - dn->deviceid_bits = xp->deviceid_bits; dn->dtc = xp->dtc; dn->dtm = xp->dtm; if (cmn->multi_dtm) @@ -2420,6 +2418,8 @@ static int arm_cmn_discover(struct arm_cmn *cmn, unsigned int rgn_offset) } arm_cmn_init_node_info(cmn, reg & CMN_CHILD_NODE_ADDR, dn); + dn->portid_bits = xp->portid_bits; + dn->deviceid_bits = xp->deviceid_bits; switch (dn->type) { case CMN_TYPE_DTC: @@ -2662,7 +2662,7 @@ static struct platform_driver arm_cmn_driver = { .acpi_match_table = ACPI_PTR(arm_cmn_acpi_match), }, .probe = arm_cmn_probe, - .remove_new = arm_cmn_remove, + .remove = arm_cmn_remove, }; static int __init arm_cmn_init(void) diff --git a/drivers/perf/arm-ni.c b/drivers/perf/arm-ni.c index 90fcfe693439ef..fd7a5e60e96302 100644 --- a/drivers/perf/arm-ni.c +++ b/drivers/perf/arm-ni.c @@ -247,7 +247,6 @@ static struct attribute *arm_ni_other_attrs[] = { static const struct attribute_group arm_ni_other_attr_group = { .attrs = arm_ni_other_attrs, - NULL }; static const struct attribute_group *arm_ni_attr_groups[] = { diff --git a/drivers/perf/arm_cspmu/arm_cspmu.c b/drivers/perf/arm_cspmu/arm_cspmu.c index 2158a5975c9075..81e8b97e935350 100644 --- a/drivers/perf/arm_cspmu/arm_cspmu.c +++ b/drivers/perf/arm_cspmu/arm_cspmu.c @@ -1282,7 +1282,7 @@ static struct platform_driver arm_cspmu_driver = { .suppress_bind_attrs = true, }, .probe = arm_cspmu_device_probe, - .remove_new = arm_cspmu_device_remove, + .remove = arm_cspmu_device_remove, .id_table = arm_cspmu_id, }; diff --git a/drivers/perf/arm_dmc620_pmu.c b/drivers/perf/arm_dmc620_pmu.c index 7e5f1d4fca0f17..619cf937602fb5 100644 --- a/drivers/perf/arm_dmc620_pmu.c +++ b/drivers/perf/arm_dmc620_pmu.c @@ -750,7 +750,7 @@ static struct platform_driver dmc620_pmu_driver = { .suppress_bind_attrs = true, }, .probe = dmc620_pmu_device_probe, - .remove_new = dmc620_pmu_device_remove, + .remove = dmc620_pmu_device_remove, }; static int __init dmc620_pmu_init(void) diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c index f2bd25a3470a5d..cb4fb59fe04bb9 100644 --- a/drivers/perf/arm_dsu_pmu.c +++ b/drivers/perf/arm_dsu_pmu.c @@ -787,7 +787,7 @@ static struct platform_driver dsu_pmu_driver = { .suppress_bind_attrs = true, }, .probe = dsu_pmu_device_probe, - .remove_new = dsu_pmu_device_remove, + .remove = dsu_pmu_device_remove, }; static int dsu_pmu_cpu_online(unsigned int cpu, struct hlist_node *node) diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c index 0afe02f879b45a..b5cc11abc962cc 100644 --- a/drivers/perf/arm_pmuv3.c +++ b/drivers/perf/arm_pmuv3.c @@ -770,18 +770,27 @@ static void armv8pmu_enable_user_access(struct arm_pmu *cpu_pmu) int i; struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); - /* Clear any unused counters to avoid leaking their contents */ - for_each_andnot_bit(i, cpu_pmu->cntr_mask, cpuc->used_mask, - ARMPMU_MAX_HWEVENTS) { - if (i == ARMV8_PMU_CYCLE_IDX) - write_pmccntr(0); - else if (i == ARMV8_PMU_INSTR_IDX) - write_pmicntr(0); - else - armv8pmu_write_evcntr(i, 0); + if (is_pmuv3p9(cpu_pmu->pmuver)) { + u64 mask = 0; + for_each_set_bit(i, cpuc->used_mask, ARMPMU_MAX_HWEVENTS) { + if (armv8pmu_event_has_user_read(cpuc->events[i])) + mask |= BIT(i); + } + write_pmuacr(mask); + } else { + /* Clear any unused counters to avoid leaking their contents */ + for_each_andnot_bit(i, cpu_pmu->cntr_mask, cpuc->used_mask, + ARMPMU_MAX_HWEVENTS) { + if (i == ARMV8_PMU_CYCLE_IDX) + write_pmccntr(0); + else if (i == ARMV8_PMU_INSTR_IDX) + write_pmicntr(0); + else + armv8pmu_write_evcntr(i, 0); + } } - update_pmuserenr(ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_CR); + update_pmuserenr(ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_CR | ARMV8_PMU_USERENR_UEN); } static void armv8pmu_enable_event(struct perf_event *event) @@ -1364,6 +1373,8 @@ PMUV3_INIT_SIMPLE(armv8_neoverse_v3ae) PMUV3_INIT_SIMPLE(armv8_nvidia_carmel) PMUV3_INIT_SIMPLE(armv8_nvidia_denver) +PMUV3_INIT_SIMPLE(armv8_samsung_mongoose) + PMUV3_INIT_MAP_EVENT(armv8_cortex_a35, armv8_a53_map_event) PMUV3_INIT_MAP_EVENT(armv8_cortex_a53, armv8_a53_map_event) PMUV3_INIT_MAP_EVENT(armv8_cortex_a57, armv8_a57_map_event) @@ -1409,6 +1420,7 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = { {.compatible = "brcm,vulcan-pmu", .data = armv8_brcm_vulcan_pmu_init}, {.compatible = "nvidia,carmel-pmu", .data = armv8_nvidia_carmel_pmu_init}, {.compatible = "nvidia,denver-pmu", .data = armv8_nvidia_denver_pmu_init}, + {.compatible = "samsung,mongoose-pmu", .data = armv8_samsung_mongoose_pmu_init}, {}, }; diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c index d5fa92ba837397..621f02a7f43be3 100644 --- a/drivers/perf/arm_smmuv3_pmu.c +++ b/drivers/perf/arm_smmuv3_pmu.c @@ -431,6 +431,17 @@ static int smmu_pmu_event_init(struct perf_event *event) return -EINVAL; } + /* + * Ensure all events are on the same cpu so all events are in the + * same cpu context, to avoid races on pmu_enable etc. + */ + event->cpu = smmu_pmu->on_cpu; + + hwc->idx = -1; + + if (event->group_leader == event) + return 0; + for_each_sibling_event(sibling, event->group_leader) { if (is_software_event(sibling)) continue; @@ -442,14 +453,6 @@ static int smmu_pmu_event_init(struct perf_event *event) return -EINVAL; } - hwc->idx = -1; - - /* - * Ensure all events are on the same cpu so all events are in the - * same cpu context, to avoid races on pmu_enable etc. - */ - event->cpu = smmu_pmu->on_cpu; - return 0; } @@ -996,7 +999,7 @@ static struct platform_driver smmu_pmu_driver = { .suppress_bind_attrs = true, }, .probe = smmu_pmu_probe, - .remove_new = smmu_pmu_remove, + .remove = smmu_pmu_remove, .shutdown = smmu_pmu_shutdown, }; diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c index 3569050f9cf375..fd5b7873260340 100644 --- a/drivers/perf/arm_spe_pmu.c +++ b/drivers/perf/arm_spe_pmu.c @@ -1280,7 +1280,7 @@ static struct platform_driver arm_spe_pmu_driver = { .suppress_bind_attrs = true, }, .probe = arm_spe_pmu_device_probe, - .remove_new = arm_spe_pmu_device_remove, + .remove = arm_spe_pmu_device_remove, }; static int __init arm_spe_pmu_init(void) diff --git a/drivers/perf/cxl_pmu.c b/drivers/perf/cxl_pmu.c index 43d68b69e6300f..d6693519eaee2e 100644 --- a/drivers/perf/cxl_pmu.c +++ b/drivers/perf/cxl_pmu.c @@ -354,7 +354,7 @@ static struct attribute *cxl_pmu_event_attrs[] = { CXL_PMU_EVENT_CXL_ATTR(d2h_req_wowrinvf, CXL_PMU_GID_D2H_REQ, BIT(13)), CXL_PMU_EVENT_CXL_ATTR(d2h_req_wrinv, CXL_PMU_GID_D2H_REQ, BIT(14)), CXL_PMU_EVENT_CXL_ATTR(d2h_req_cacheflushed, CXL_PMU_GID_D2H_REQ, BIT(16)), - /* CXL rev 3.0 Table 3-20 - D2H Repsonse Encodings */ + /* CXL rev 3.0 Table 3-20 - D2H Response Encodings */ CXL_PMU_EVENT_CXL_ATTR(d2h_rsp_rspihiti, CXL_PMU_GID_D2H_RSP, BIT(4)), CXL_PMU_EVENT_CXL_ATTR(d2h_rsp_rspvhitv, CXL_PMU_GID_D2H_RSP, BIT(6)), CXL_PMU_EVENT_CXL_ATTR(d2h_rsp_rspihitse, CXL_PMU_GID_D2H_RSP, BIT(5)), @@ -377,12 +377,14 @@ static struct attribute *cxl_pmu_event_attrs[] = { /* CXL rev 3.0 Table 13-5 directly lists these */ CXL_PMU_EVENT_CXL_ATTR(cachedata_d2h_data, CXL_PMU_GID_CACHE_DATA, BIT(0)), CXL_PMU_EVENT_CXL_ATTR(cachedata_h2d_data, CXL_PMU_GID_CACHE_DATA, BIT(1)), - /* CXL rev 3.0 Table 3-29 M2S Req Memory Opcodes */ + /* CXL rev 3.1 Table 3-35 M2S Req Memory Opcodes */ CXL_PMU_EVENT_CXL_ATTR(m2s_req_meminv, CXL_PMU_GID_M2S_REQ, BIT(0)), CXL_PMU_EVENT_CXL_ATTR(m2s_req_memrd, CXL_PMU_GID_M2S_REQ, BIT(1)), CXL_PMU_EVENT_CXL_ATTR(m2s_req_memrddata, CXL_PMU_GID_M2S_REQ, BIT(2)), CXL_PMU_EVENT_CXL_ATTR(m2s_req_memrdfwd, CXL_PMU_GID_M2S_REQ, BIT(3)), CXL_PMU_EVENT_CXL_ATTR(m2s_req_memwrfwd, CXL_PMU_GID_M2S_REQ, BIT(4)), + CXL_PMU_EVENT_CXL_ATTR(m2s_req_memrdtee, CXL_PMU_GID_M2S_REQ, BIT(5)), + CXL_PMU_EVENT_CXL_ATTR(m2s_req_memrddatatee, CXL_PMU_GID_M2S_REQ, BIT(6)), CXL_PMU_EVENT_CXL_ATTR(m2s_req_memspecrd, CXL_PMU_GID_M2S_REQ, BIT(8)), CXL_PMU_EVENT_CXL_ATTR(m2s_req_meminvnt, CXL_PMU_GID_M2S_REQ, BIT(9)), CXL_PMU_EVENT_CXL_ATTR(m2s_req_memcleanevict, CXL_PMU_GID_M2S_REQ, BIT(10)), @@ -404,10 +406,11 @@ static struct attribute *cxl_pmu_event_attrs[] = { CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_curblk, CXL_PMU_GID_S2M_BISNP, BIT(4)), CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_datblk, CXL_PMU_GID_S2M_BISNP, BIT(5)), CXL_PMU_EVENT_CXL_ATTR(s2m_bisnp_invblk, CXL_PMU_GID_S2M_BISNP, BIT(6)), - /* CXL rev 3.0 Table 3-43 S2M NDR Opcopdes */ + /* CXL rev 3.1 Table 3-50 S2M NDR Opcopdes */ CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmp, CXL_PMU_GID_S2M_NDR, BIT(0)), CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmps, CXL_PMU_GID_S2M_NDR, BIT(1)), CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmpe, CXL_PMU_GID_S2M_NDR, BIT(2)), + CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_cmpm, CXL_PMU_GID_S2M_NDR, BIT(3)), CXL_PMU_EVENT_CXL_ATTR(s2m_ndr_biconflictack, CXL_PMU_GID_S2M_NDR, BIT(4)), /* CXL rev 3.0 Table 3-46 S2M DRS opcodes */ CXL_PMU_EVENT_CXL_ATTR(s2m_drs_memdata, CXL_PMU_GID_S2M_DRS, BIT(0)), @@ -974,7 +977,7 @@ static __exit void cxl_pmu_exit(void) MODULE_DESCRIPTION("CXL Performance Monitor Driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(CXL); +MODULE_IMPORT_NS("CXL"); module_init(cxl_pmu_init); module_exit(cxl_pmu_exit); MODULE_ALIAS_CXL(CXL_DEVICE_PMU); diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c index 4ca50f9b6dfed8..9cbea9675e21a0 100644 --- a/drivers/perf/dwc_pcie_pmu.c +++ b/drivers/perf/dwc_pcie_pmu.c @@ -82,7 +82,6 @@ struct dwc_pcie_pmu { u16 ras_des_offset; u32 nr_lanes; - struct list_head pmu_node; struct hlist_node cpuhp_node; struct perf_event *event[DWC_PCIE_EVENT_TYPE_MAX]; int on_cpu; @@ -107,6 +106,7 @@ struct dwc_pcie_vendor_id { static const struct dwc_pcie_vendor_id dwc_pcie_vendor_ids[] = { {.vendor_id = PCI_VENDOR_ID_ALIBABA }, + {.vendor_id = PCI_VENDOR_ID_AMPERE }, {.vendor_id = PCI_VENDOR_ID_QCOM }, {} /* terminator */ }; @@ -203,10 +203,10 @@ static struct attribute *dwc_pcie_pmu_time_event_attrs[] = { DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1_AUX, 0x09), /* Group #1 */ - DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(Tx_PCIe_TLP_Data_Payload, 0x20), - DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(Rx_PCIe_TLP_Data_Payload, 0x21), - DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(Tx_CCIX_TLP_Data_Payload, 0x22), - DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(Rx_CCIX_TLP_Data_Payload, 0x23), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(tx_pcie_tlp_data_payload, 0x20), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(rx_pcie_tlp_data_payload, 0x21), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(tx_ccix_tlp_data_payload, 0x22), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(rx_ccix_tlp_data_payload, 0x23), /* * Leave it to the user to specify the lane ID to avoid generating @@ -216,9 +216,9 @@ static struct attribute *dwc_pcie_pmu_time_event_attrs[] = { DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_update_fc_dllp, 0x601), DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_ack_dllp, 0x602), DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_update_fc_dllp, 0x603), - DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_nulified_tlp, 0x604), - DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_nulified_tlp, 0x605), - DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_duplicate_tl, 0x606), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_nullified_tlp, 0x604), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_nullified_tlp, 0x605), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_duplicate_tlp, 0x606), DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_memory_write, 0x700), DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_memory_read, 0x701), DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_configuration_write, 0x702), diff --git a/drivers/perf/fsl_imx8_ddr_perf.c b/drivers/perf/fsl_imx8_ddr_perf.c index 746b92330ca7f0..b989ffa95d692f 100644 --- a/drivers/perf/fsl_imx8_ddr_perf.c +++ b/drivers/perf/fsl_imx8_ddr_perf.c @@ -846,7 +846,7 @@ static struct platform_driver imx_ddr_pmu_driver = { .suppress_bind_attrs = true, }, .probe = ddr_perf_probe, - .remove_new = ddr_perf_remove, + .remove = ddr_perf_remove, }; module_platform_driver(imx_ddr_pmu_driver); diff --git a/drivers/perf/fsl_imx9_ddr_perf.c b/drivers/perf/fsl_imx9_ddr_perf.c index 69f920b1caf2c3..3c856d9a4e97ac 100644 --- a/drivers/perf/fsl_imx9_ddr_perf.c +++ b/drivers/perf/fsl_imx9_ddr_perf.c @@ -81,6 +81,10 @@ struct ddr_pmu { int id; }; +static const struct imx_ddr_devtype_data imx91_devtype_data = { + .identifier = "imx91", +}; + static const struct imx_ddr_devtype_data imx93_devtype_data = { .identifier = "imx93", }; @@ -100,6 +104,7 @@ static inline bool is_imx95(struct ddr_pmu *pmu) } static const struct of_device_id imx_ddr_pmu_dt_ids[] = { + { .compatible = "fsl,imx91-ddr-pmu", .data = &imx91_devtype_data }, { .compatible = "fsl,imx93-ddr-pmu", .data = &imx93_devtype_data }, { .compatible = "fsl,imx95-ddr-pmu", .data = &imx95_devtype_data }, { /* sentinel */ } @@ -848,7 +853,7 @@ static struct platform_driver imx_ddr_pmu_driver = { .suppress_bind_attrs = true, }, .probe = ddr_perf_probe, - .remove_new = ddr_perf_remove, + .remove = ddr_perf_remove, }; module_platform_driver(imx_ddr_pmu_driver); diff --git a/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c index 0e923f94fa5b02..3f3fb1de11f5b5 100644 --- a/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_cpa_pmu.c @@ -358,7 +358,7 @@ static struct platform_driver hisi_cpa_pmu_driver = { .suppress_bind_attrs = true, }, .probe = hisi_cpa_pmu_probe, - .remove_new = hisi_cpa_pmu_remove, + .remove = hisi_cpa_pmu_remove, }; static int __init hisi_cpa_pmu_module_init(void) diff --git a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c index b804e37381134c..a6ebf2ec99d371 100644 --- a/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_ddrc_pmu.c @@ -547,7 +547,7 @@ static struct platform_driver hisi_ddrc_pmu_driver = { .suppress_bind_attrs = true, }, .probe = hisi_ddrc_pmu_probe, - .remove_new = hisi_ddrc_pmu_remove, + .remove = hisi_ddrc_pmu_remove, }; static int __init hisi_ddrc_pmu_module_init(void) diff --git a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c index 21e69b1cdd4d20..32624872596f21 100644 --- a/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_hha_pmu.c @@ -550,7 +550,7 @@ static struct platform_driver hisi_hha_pmu_driver = { .suppress_bind_attrs = true, }, .probe = hisi_hha_pmu_probe, - .remove_new = hisi_hha_pmu_remove, + .remove = hisi_hha_pmu_remove, }; static int __init hisi_hha_pmu_module_init(void) diff --git a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c index 51ba76871097a8..c235b46ce87326 100644 --- a/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_l3c_pmu.c @@ -584,7 +584,7 @@ static struct platform_driver hisi_l3c_pmu_driver = { .suppress_bind_attrs = true, }, .probe = hisi_l3c_pmu_probe, - .remove_new = hisi_l3c_pmu_remove, + .remove = hisi_l3c_pmu_remove, }; static int __init hisi_l3c_pmu_module_init(void) diff --git a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c index 3cdb35c741f95a..c0f5d7c73e0647 100644 --- a/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_pa_pmu.c @@ -538,7 +538,7 @@ static struct platform_driver hisi_pa_pmu_driver = { .suppress_bind_attrs = true, }, .probe = hisi_pa_pmu_probe, - .remove_new = hisi_pa_pmu_remove, + .remove = hisi_pa_pmu_remove, }; static int __init hisi_pa_pmu_module_init(void) diff --git a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c index 765bbd61db26ee..c5f4764ee888ab 100644 --- a/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c @@ -476,7 +476,7 @@ static struct platform_driver hisi_sllc_pmu_driver = { .suppress_bind_attrs = true, }, .probe = hisi_sllc_pmu_probe, - .remove_new = hisi_sllc_pmu_remove, + .remove = hisi_sllc_pmu_remove, }; static int __init hisi_sllc_pmu_module_init(void) diff --git a/drivers/perf/marvell_cn10k_ddr_pmu.c b/drivers/perf/marvell_cn10k_ddr_pmu.c index 94f1ebcd2a275d..8860d9f687aec3 100644 --- a/drivers/perf/marvell_cn10k_ddr_pmu.c +++ b/drivers/perf/marvell_cn10k_ddr_pmu.c @@ -732,7 +732,7 @@ static struct platform_driver cn10k_ddr_pmu_driver = { .suppress_bind_attrs = true, }, .probe = cn10k_ddr_perf_probe, - .remove_new = cn10k_ddr_perf_remove, + .remove = cn10k_ddr_perf_remove, }; static int __init cn10k_ddr_pmu_init(void) diff --git a/drivers/perf/marvell_cn10k_tad_pmu.c b/drivers/perf/marvell_cn10k_tad_pmu.c index 9e635f3554709b..cda55ee35eeeec 100644 --- a/drivers/perf/marvell_cn10k_tad_pmu.c +++ b/drivers/perf/marvell_cn10k_tad_pmu.c @@ -383,7 +383,7 @@ static struct platform_driver tad_pmu_driver = { .suppress_bind_attrs = true, }, .probe = tad_pmu_probe, - .remove_new = tad_pmu_remove, + .remove = tad_pmu_remove, }; static int tad_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node) diff --git a/drivers/perf/marvell_pem_pmu.c b/drivers/perf/marvell_pem_pmu.c new file mode 100644 index 00000000000000..29fbcd1848e445 --- /dev/null +++ b/drivers/perf/marvell_pem_pmu.c @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Marvell PEM(PCIe RC) Performance Monitor Driver + * + * Copyright (C) 2024 Marvell. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Each of these events maps to a free running 64 bit counter + * with no event control, but can be reset. + */ +enum pem_events { + IB_TLP_NPR, + IB_TLP_PR, + IB_TLP_CPL, + IB_TLP_DWORDS_NPR, + IB_TLP_DWORDS_PR, + IB_TLP_DWORDS_CPL, + IB_INFLIGHT, + IB_READS, + IB_REQ_NO_RO_NCB, + IB_REQ_NO_RO_EBUS, + OB_TLP_NPR, + OB_TLP_PR, + OB_TLP_CPL, + OB_TLP_DWORDS_NPR, + OB_TLP_DWORDS_PR, + OB_TLP_DWORDS_CPL, + OB_INFLIGHT, + OB_READS, + OB_MERGES_NPR, + OB_MERGES_PR, + OB_MERGES_CPL, + ATS_TRANS, + ATS_TRANS_LATENCY, + ATS_PRI, + ATS_PRI_LATENCY, + ATS_INV, + ATS_INV_LATENCY, + PEM_EVENTIDS_MAX +}; + +static u64 eventid_to_offset_table[] = { + [IB_TLP_NPR] = 0x0, + [IB_TLP_PR] = 0x8, + [IB_TLP_CPL] = 0x10, + [IB_TLP_DWORDS_NPR] = 0x100, + [IB_TLP_DWORDS_PR] = 0x108, + [IB_TLP_DWORDS_CPL] = 0x110, + [IB_INFLIGHT] = 0x200, + [IB_READS] = 0x300, + [IB_REQ_NO_RO_NCB] = 0x400, + [IB_REQ_NO_RO_EBUS] = 0x408, + [OB_TLP_NPR] = 0x500, + [OB_TLP_PR] = 0x508, + [OB_TLP_CPL] = 0x510, + [OB_TLP_DWORDS_NPR] = 0x600, + [OB_TLP_DWORDS_PR] = 0x608, + [OB_TLP_DWORDS_CPL] = 0x610, + [OB_INFLIGHT] = 0x700, + [OB_READS] = 0x800, + [OB_MERGES_NPR] = 0x900, + [OB_MERGES_PR] = 0x908, + [OB_MERGES_CPL] = 0x910, + [ATS_TRANS] = 0x2D18, + [ATS_TRANS_LATENCY] = 0x2D20, + [ATS_PRI] = 0x2D28, + [ATS_PRI_LATENCY] = 0x2D30, + [ATS_INV] = 0x2D38, + [ATS_INV_LATENCY] = 0x2D40, +}; + +struct pem_pmu { + struct pmu pmu; + void __iomem *base; + unsigned int cpu; + struct device *dev; + struct hlist_node node; +}; + +#define to_pem_pmu(p) container_of(p, struct pem_pmu, pmu) + +static int eventid_to_offset(int eventid) +{ + return eventid_to_offset_table[eventid]; +} + +/* Events */ +static ssize_t pem_pmu_event_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + struct perf_pmu_events_attr *pmu_attr; + + pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); + return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id); +} + +#define PEM_EVENT_ATTR(_name, _id) \ + (&((struct perf_pmu_events_attr[]) { \ + { .attr = __ATTR(_name, 0444, pem_pmu_event_show, NULL), \ + .id = _id, } \ + })[0].attr.attr) + +static struct attribute *pem_perf_events_attrs[] = { + PEM_EVENT_ATTR(ib_tlp_npr, IB_TLP_NPR), + PEM_EVENT_ATTR(ib_tlp_pr, IB_TLP_PR), + PEM_EVENT_ATTR(ib_tlp_cpl_partid, IB_TLP_CPL), + PEM_EVENT_ATTR(ib_tlp_dwords_npr, IB_TLP_DWORDS_NPR), + PEM_EVENT_ATTR(ib_tlp_dwords_pr, IB_TLP_DWORDS_PR), + PEM_EVENT_ATTR(ib_tlp_dwords_cpl_partid, IB_TLP_DWORDS_CPL), + PEM_EVENT_ATTR(ib_inflight, IB_INFLIGHT), + PEM_EVENT_ATTR(ib_reads, IB_READS), + PEM_EVENT_ATTR(ib_req_no_ro_ncb, IB_REQ_NO_RO_NCB), + PEM_EVENT_ATTR(ib_req_no_ro_ebus, IB_REQ_NO_RO_EBUS), + PEM_EVENT_ATTR(ob_tlp_npr_partid, OB_TLP_NPR), + PEM_EVENT_ATTR(ob_tlp_pr_partid, OB_TLP_PR), + PEM_EVENT_ATTR(ob_tlp_cpl_partid, OB_TLP_CPL), + PEM_EVENT_ATTR(ob_tlp_dwords_npr_partid, OB_TLP_DWORDS_NPR), + PEM_EVENT_ATTR(ob_tlp_dwords_pr_partid, OB_TLP_DWORDS_PR), + PEM_EVENT_ATTR(ob_tlp_dwords_cpl_partid, OB_TLP_DWORDS_CPL), + PEM_EVENT_ATTR(ob_inflight_partid, OB_INFLIGHT), + PEM_EVENT_ATTR(ob_reads_partid, OB_READS), + PEM_EVENT_ATTR(ob_merges_npr_partid, OB_MERGES_NPR), + PEM_EVENT_ATTR(ob_merges_pr_partid, OB_MERGES_PR), + PEM_EVENT_ATTR(ob_merges_cpl_partid, OB_MERGES_CPL), + PEM_EVENT_ATTR(ats_trans, ATS_TRANS), + PEM_EVENT_ATTR(ats_trans_latency, ATS_TRANS_LATENCY), + PEM_EVENT_ATTR(ats_pri, ATS_PRI), + PEM_EVENT_ATTR(ats_pri_latency, ATS_PRI_LATENCY), + PEM_EVENT_ATTR(ats_inv, ATS_INV), + PEM_EVENT_ATTR(ats_inv_latency, ATS_INV_LATENCY), + NULL +}; + +static struct attribute_group pem_perf_events_attr_group = { + .name = "events", + .attrs = pem_perf_events_attrs, +}; + +PMU_FORMAT_ATTR(event, "config:0-5"); + +static struct attribute *pem_perf_format_attrs[] = { + &format_attr_event.attr, + NULL +}; + +static struct attribute_group pem_perf_format_attr_group = { + .name = "format", + .attrs = pem_perf_format_attrs, +}; + +/* cpumask */ +static ssize_t pem_perf_cpumask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pem_pmu *pmu = dev_get_drvdata(dev); + + return cpumap_print_to_pagebuf(true, buf, cpumask_of(pmu->cpu)); +} + +static struct device_attribute pem_perf_cpumask_attr = + __ATTR(cpumask, 0444, pem_perf_cpumask_show, NULL); + +static struct attribute *pem_perf_cpumask_attrs[] = { + &pem_perf_cpumask_attr.attr, + NULL +}; + +static struct attribute_group pem_perf_cpumask_attr_group = { + .attrs = pem_perf_cpumask_attrs, +}; + +static const struct attribute_group *pem_perf_attr_groups[] = { + &pem_perf_events_attr_group, + &pem_perf_cpumask_attr_group, + &pem_perf_format_attr_group, + NULL +}; + +static int pem_perf_event_init(struct perf_event *event) +{ + struct pem_pmu *pmu = to_pem_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + struct perf_event *sibling; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + if (event->attr.config >= PEM_EVENTIDS_MAX) + return -EINVAL; + + if (is_sampling_event(event) || + event->attach_state & PERF_ATTACH_TASK) { + return -EOPNOTSUPP; + } + + if (event->cpu < 0) + return -EOPNOTSUPP; + + /* We must NOT create groups containing mixed PMUs */ + if (event->group_leader->pmu != event->pmu && + !is_software_event(event->group_leader)) + return -EINVAL; + + for_each_sibling_event(sibling, event->group_leader) { + if (sibling->pmu != event->pmu && + !is_software_event(sibling)) + return -EINVAL; + } + /* + * Set ownership of event to one CPU, same event can not be observed + * on multiple cpus at same time. + */ + event->cpu = pmu->cpu; + hwc->idx = -1; + return 0; +} + +static u64 pem_perf_read_counter(struct pem_pmu *pmu, + struct perf_event *event, int eventid) +{ + return readq_relaxed(pmu->base + eventid_to_offset(eventid)); +} + +static void pem_perf_event_update(struct perf_event *event) +{ + struct pem_pmu *pmu = to_pem_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u64 prev_count, new_count; + + do { + prev_count = local64_read(&hwc->prev_count); + new_count = pem_perf_read_counter(pmu, event, hwc->idx); + } while (local64_xchg(&hwc->prev_count, new_count) != prev_count); + + local64_add((new_count - prev_count), &event->count); +} + +static void pem_perf_event_start(struct perf_event *event, int flags) +{ + struct pem_pmu *pmu = to_pem_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int eventid = hwc->idx; + + /* + * All counters are free-running and associated with + * a fixed event to track in Hardware + */ + local64_set(&hwc->prev_count, + pem_perf_read_counter(pmu, event, eventid)); + + hwc->state = 0; +} + +static int pem_perf_event_add(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + + hwc->idx = event->attr.config; + if (WARN_ON_ONCE(hwc->idx >= PEM_EVENTIDS_MAX)) + return -EINVAL; + hwc->state |= PERF_HES_STOPPED; + + if (flags & PERF_EF_START) + pem_perf_event_start(event, flags); + + return 0; +} + +static void pem_perf_event_stop(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + + if (flags & PERF_EF_UPDATE) + pem_perf_event_update(event); + + hwc->state |= PERF_HES_STOPPED; +} + +static void pem_perf_event_del(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + + pem_perf_event_stop(event, PERF_EF_UPDATE); + hwc->idx = -1; +} + +static int pem_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct pem_pmu *pmu = hlist_entry_safe(node, struct pem_pmu, node); + unsigned int target; + + if (cpu != pmu->cpu) + return 0; + + target = cpumask_any_but(cpu_online_mask, cpu); + if (target >= nr_cpu_ids) + return 0; + + perf_pmu_migrate_context(&pmu->pmu, cpu, target); + pmu->cpu = target; + return 0; +} + +static int pem_perf_probe(struct platform_device *pdev) +{ + struct pem_pmu *pem_pmu; + struct resource *res; + void __iomem *base; + char *name; + int ret; + + pem_pmu = devm_kzalloc(&pdev->dev, sizeof(*pem_pmu), GFP_KERNEL); + if (!pem_pmu) + return -ENOMEM; + + pem_pmu->dev = &pdev->dev; + platform_set_drvdata(pdev, pem_pmu); + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + + pem_pmu->base = base; + + pem_pmu->pmu = (struct pmu) { + .module = THIS_MODULE, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + .task_ctx_nr = perf_invalid_context, + .attr_groups = pem_perf_attr_groups, + .event_init = pem_perf_event_init, + .add = pem_perf_event_add, + .del = pem_perf_event_del, + .start = pem_perf_event_start, + .stop = pem_perf_event_stop, + .read = pem_perf_event_update, + }; + + /* Choose this cpu to collect perf data */ + pem_pmu->cpu = raw_smp_processor_id(); + + name = devm_kasprintf(pem_pmu->dev, GFP_KERNEL, "mrvl_pcie_rc_pmu_%llx", + res->start); + if (!name) + return -ENOMEM; + + cpuhp_state_add_instance_nocalls(CPUHP_AP_PERF_ARM_MRVL_PEM_ONLINE, + &pem_pmu->node); + + ret = perf_pmu_register(&pem_pmu->pmu, name, -1); + if (ret) + goto error; + + return 0; +error: + cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_MRVL_PEM_ONLINE, + &pem_pmu->node); + return ret; +} + +static void pem_perf_remove(struct platform_device *pdev) +{ + struct pem_pmu *pem_pmu = platform_get_drvdata(pdev); + + cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_MRVL_PEM_ONLINE, + &pem_pmu->node); + + perf_pmu_unregister(&pem_pmu->pmu); +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id pem_pmu_acpi_match[] = { + {"MRVL000E", 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, pem_pmu_acpi_match); +#endif + +static struct platform_driver pem_pmu_driver = { + .driver = { + .name = "pem-pmu", + .acpi_match_table = ACPI_PTR(pem_pmu_acpi_match), + .suppress_bind_attrs = true, + }, + .probe = pem_perf_probe, + .remove = pem_perf_remove, +}; + +static int __init pem_pmu_init(void) +{ + int ret; + + ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_MRVL_PEM_ONLINE, + "perf/marvell/pem:online", NULL, + pem_pmu_offline_cpu); + if (ret) + return ret; + + ret = platform_driver_register(&pem_pmu_driver); + if (ret) + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_MRVL_PEM_ONLINE); + return ret; +} + +static void __exit pem_pmu_exit(void) +{ + platform_driver_unregister(&pem_pmu_driver); + cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_MRVL_PEM_ONLINE); +} + +module_init(pem_pmu_init); +module_exit(pem_pmu_exit); + +MODULE_DESCRIPTION("Marvell PEM Perf driver"); +MODULE_AUTHOR("Gowthami Thiagarajan "); +MODULE_LICENSE("GPL"); diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c index 980e3051edd725..ea8c857299373d 100644 --- a/drivers/perf/qcom_l2_pmu.c +++ b/drivers/perf/qcom_l2_pmu.c @@ -981,7 +981,7 @@ static struct platform_driver l2_cache_pmu_driver = { .suppress_bind_attrs = true, }, .probe = l2_cache_pmu_probe, - .remove_new = l2_cache_pmu_remove, + .remove = l2_cache_pmu_remove, }; static int __init register_l2_cache_pmu_driver(void) diff --git a/drivers/perf/thunderx2_pmu.c b/drivers/perf/thunderx2_pmu.c index faf763d2c95cb8..cadd60221b8f76 100644 --- a/drivers/perf/thunderx2_pmu.c +++ b/drivers/perf/thunderx2_pmu.c @@ -1010,7 +1010,7 @@ static struct platform_driver tx2_uncore_driver = { .suppress_bind_attrs = true, }, .probe = tx2_uncore_probe, - .remove_new = tx2_uncore_remove, + .remove = tx2_uncore_remove, }; static int __init tx2_uncore_driver_init(void) diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c index c01466ae1e3d93..33b5497bdc06e4 100644 --- a/drivers/perf/xgene_pmu.c +++ b/drivers/perf/xgene_pmu.c @@ -1943,7 +1943,7 @@ static void xgene_pmu_remove(struct platform_device *pdev) static struct platform_driver xgene_pmu_driver = { .probe = xgene_pmu_probe, - .remove_new = xgene_pmu_remove, + .remove = xgene_pmu_remove, .driver = { .name = "xgene-pmu", .of_match_table = xgene_pmu_of_match, diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index f73abff416bedb..8d58efe998ec5f 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -82,6 +82,17 @@ config PHY_AIROHA_PCIE This driver create the basic PHY instance and provides initialize callback for PCIe GEN3 port. +config PHY_NXP_PTN3222 + tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver" + depends on I2C + depends on OF + select GENERIC_PHY + help + Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver. + This redriver performs translation between eUSB2 and USB2 signalling + schemes. It supports all three USB 2.0 data rates: Low Speed, Full + Speed and High Speed. + source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index ebc399560da4f6..e281442acc7528 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o +obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o obj-y += allwinner/ \ amlogic/ \ broadcom/ \ diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index b0f19e95060107..cd159a71b23c30 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -1049,11 +1049,11 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); static struct platform_driver sun4i_usb_phy_driver = { - .probe = sun4i_usb_phy_probe, - .remove_new = sun4i_usb_phy_remove, + .probe = sun4i_usb_phy_probe, + .remove = sun4i_usb_phy_remove, .driver = { - .of_match_table = sun4i_usb_phy_of_match, - .name = "sun4i-usb-phy", + .of_match_table= sun4i_usb_phy_of_match, + .name = "sun4i-usb-phy", } }; module_platform_driver(sun4i_usb_phy_driver); diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb2.c b/drivers/phy/broadcom/phy-bcm-ns-usb2.c index 5213c75b6da6aa..c5d35031b39833 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb2.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb2.c @@ -24,9 +24,6 @@ struct bcm_ns_usb2 { struct phy *phy; struct regmap *clkset; void __iomem *base; - - /* Deprecated binding */ - void __iomem *dmu; }; static int bcm_ns_usb2_phy_init(struct phy *phy) @@ -49,10 +46,7 @@ static int bcm_ns_usb2_phy_init(struct phy *phy) goto err_clk_off; } - if (usb2->base) - usb2ctl = readl(usb2->base); - else - usb2ctl = readl(usb2->dmu + BCMA_DMU_CRU_USB2_CONTROL); + usb2ctl = readl(usb2->base); if (usb2ctl & BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK) { usb_pll_pdiv = usb2ctl; @@ -66,24 +60,16 @@ static int bcm_ns_usb2_phy_init(struct phy *phy) usb_pll_ndiv = (1920000000 * usb_pll_pdiv) / ref_clk_rate; /* Unlock DMU PLL settings with some magic value */ - if (usb2->clkset) - regmap_write(usb2->clkset, 0, 0x0000ea68); - else - writel(0x0000ea68, usb2->dmu + BCMA_DMU_CRU_CLKSET_KEY); + regmap_write(usb2->clkset, 0, 0x0000ea68); /* Write USB 2.0 PLL control setting */ usb2ctl &= ~BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK; usb2ctl |= usb_pll_ndiv << BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT; - if (usb2->base) - writel(usb2ctl, usb2->base); - else - writel(usb2ctl, usb2->dmu + BCMA_DMU_CRU_USB2_CONTROL); + + writel(usb2ctl, usb2->base); /* Lock DMU PLL settings */ - if (usb2->clkset) - regmap_write(usb2->clkset, 0, 0x00000000); - else - writel(0x00000000, usb2->dmu + BCMA_DMU_CRU_CLKSET_KEY); + regmap_write(usb2->clkset, 0, 0x00000000); err_clk_off: clk_disable_unprepare(usb2->ref_clk); @@ -107,27 +93,17 @@ static int bcm_ns_usb2_probe(struct platform_device *pdev) return -ENOMEM; usb2->dev = dev; - 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"); - return PTR_ERR(usb2->base); - } - - usb2->clkset = syscon_regmap_lookup_by_phandle(dev->of_node, - "brcm,syscon-clkset"); - if (IS_ERR(usb2->clkset)) { - dev_err(dev, "Failed to lookup clkset regmap\n"); - return PTR_ERR(usb2->clkset); - } - } else { - usb2->dmu = devm_platform_ioremap_resource_byname(pdev, "dmu"); - if (IS_ERR(usb2->dmu)) { - dev_err(dev, "Failed to map DMU regs\n"); - return PTR_ERR(usb2->dmu); - } + usb2->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(usb2->base)) { + dev_err(dev, "Failed to map control reg\n"); + return PTR_ERR(usb2->base); + } - dev_warn(dev, "using deprecated DT binding\n"); + usb2->clkset = syscon_regmap_lookup_by_phandle(dev->of_node, + "brcm,syscon-clkset"); + if (IS_ERR(usb2->clkset)) { + dev_err(dev, "Failed to lookup clkset regmap\n"); + return PTR_ERR(usb2->clkset); } usb2->ref_clk = devm_clk_get(dev, "phy-ref-clk"); diff --git a/drivers/phy/broadcom/phy-brcm-usb-init.c b/drivers/phy/broadcom/phy-brcm-usb-init.c index 5ebb3a61611579..da23078878a9b3 100644 --- a/drivers/phy/broadcom/phy-brcm-usb-init.c +++ b/drivers/phy/broadcom/phy-brcm-usb-init.c @@ -193,256 +193,251 @@ static const u32 usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { /* 3390B0 */ [BRCM_FAMILY_3390A0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 4908 */ [BRCM_FAMILY_4908] = { - 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ - 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ - 0, /* USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */ - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - 0, /* USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK */ - 0, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, }, /* 7250b0 */ [BRCM_FAMILY_7250B0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, - 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR] = + USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7271a0 */ [BRCM_FAMILY_7271A0] = { - 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ - 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - USB_CTRL_USB_PM_SOFT_RESET_MASK, - USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK, - USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK, - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_SOFT_RESET_SELECTOR] = + USB_CTRL_USB_PM_SOFT_RESET_MASK, + [USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_SELECTOR] = + USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK, + [USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7364a0 */ [BRCM_FAMILY_7364A0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, - 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR] = + USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7366c0 */ [BRCM_FAMILY_7366C0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 74371A0 */ [BRCM_FAMILY_74371A0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */ - USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ - USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB30_CTL1_USB3_IOC_MASK, - USB_CTRL_USB30_CTL1_USB3_IPP_MASK, - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - 0, /* USB_CTRL_USB_PM_USB20_HC_RESETB_MASK */ - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, + [USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR] = + USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, + [USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB30_CTL1_USB3_IOC_SELECTOR] = + USB_CTRL_USB30_CTL1_USB3_IOC_MASK, + [USB_CTRL_USB30_CTL1_USB3_IPP_SELECTOR] = + USB_CTRL_USB30_CTL1_USB3_IPP_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7439B0 */ [BRCM_FAMILY_7439B0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7445d0 */ [BRCM_FAMILY_7445D0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ - USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK, - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR] = + USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, + [USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7260a0 */ [BRCM_FAMILY_7260A0] = { - 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ - 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - USB_CTRL_USB_PM_SOFT_RESET_MASK, - USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK, - USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK, - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_SOFT_RESET_SELECTOR] = + USB_CTRL_USB_PM_SOFT_RESET_MASK, + [USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_SELECTOR] = + USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK, + [USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7278a0 */ [BRCM_FAMILY_7278A0] = { - 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ - 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ - 0, /*USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */ - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - USB_CTRL_USB_PM_SOFT_RESET_MASK, - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - 0, /* USB_CTRL_USB_PM_USB20_HC_RESETB_MASK */ - 0, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_SOFT_RESET_SELECTOR] = + USB_CTRL_USB_PM_SOFT_RESET_MASK, }, }; diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index ad2eec0956016d..6362ca5b7fb6b5 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -667,7 +667,7 @@ MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids); static struct platform_driver brcm_usb_driver = { .probe = brcm_usb_phy_probe, - .remove_new = brcm_usb_phy_remove, + .remove = brcm_usb_phy_remove, .driver = { .name = "brcmstb-usb-phy", .pm = &brcm_usb_phy_pm_ops, diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index dddb66de6dba15..ed87a3970f8343 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -472,7 +472,7 @@ MODULE_DEVICE_TABLE(of, cdns_dphy_of_match); static struct platform_driver cdns_dphy_platform_driver = { .probe = cdns_dphy_probe, - .remove_new = cdns_dphy_remove, + .remove = 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 dfc4f55d112e19..45a5c00843bf63 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -2731,7 +2731,7 @@ MODULE_DEVICE_TABLE(of, cdns_sierra_id_table); static struct platform_driver cdns_sierra_driver = { .probe = cdns_sierra_phy_probe, - .remove_new = cdns_sierra_phy_remove, + .remove = 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 8bbbbb87bb22e5..a281c0dfae9742 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -5440,8 +5440,8 @@ MODULE_DEVICE_TABLE(of, cdns_torrent_phy_of_match); static struct platform_driver cdns_torrent_phy_driver = { .probe = cdns_torrent_phy_probe, - .remove_new = cdns_torrent_phy_remove, - .driver = { + .remove = cdns_torrent_phy_remove, + .driver = { .name = "cdns-torrent-phy", .of_match_table = cdns_torrent_phy_of_match, .pm = pm_sleep_ptr(&cdns_torrent_phy_pm_ops), diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c index 38388dd04bdc1d..7aef2f59e8eb4a 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c @@ -433,12 +433,12 @@ static const struct of_device_id mixel_lvds_phy_of_match[] = { MODULE_DEVICE_TABLE(of, mixel_lvds_phy_of_match); static struct platform_driver mixel_lvds_phy_driver = { - .probe = mixel_lvds_phy_probe, - .remove_new = mixel_lvds_phy_remove, + .probe = mixel_lvds_phy_probe, + .remove = mixel_lvds_phy_remove, .driver = { .pm = &mixel_lvds_phy_pm_ops, .name = "mixel-lvds-phy", - .of_match_table = mixel_lvds_phy_of_match, + .of_match_table = mixel_lvds_phy_of_match, } }; module_platform_driver(mixel_lvds_phy_driver); diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index b86da8e9daa465..f7994e8983c8ec 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -631,9 +631,9 @@ static const struct of_device_id lynx_28g_of_match_table[] = { MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table); static struct platform_driver lynx_28g_driver = { - .probe = lynx_28g_probe, - .remove_new = lynx_28g_remove, - .driver = { + .probe = lynx_28g_probe, + .remove = lynx_28g_remove, + .driver = { .name = "lynx-28g", .of_match_table = lynx_28g_of_match_table, }, diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c index 9048cdc760c213..2c8038864357b1 100644 --- a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c +++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c @@ -14,352 +14,265 @@ #include #include -#define PHY_REG_00 0x00 -#define PHY_REG_01 0x04 -#define PHY_REG_02 0x08 -#define PHY_REG_08 0x20 -#define PHY_REG_09 0x24 -#define PHY_REG_10 0x28 -#define PHY_REG_11 0x2c - -#define PHY_REG_12 0x30 -#define REG12_CK_DIV_MASK GENMASK(5, 4) - -#define PHY_REG_13 0x34 -#define REG13_TG_CODE_LOW_MASK GENMASK(7, 0) - -#define PHY_REG_14 0x38 -#define REG14_TOL_MASK GENMASK(7, 4) -#define REG14_RP_CODE_MASK GENMASK(3, 1) -#define REG14_TG_CODE_HIGH_MASK GENMASK(0, 0) - -#define PHY_REG_15 0x3c -#define PHY_REG_16 0x40 -#define PHY_REG_17 0x44 -#define PHY_REG_18 0x48 -#define PHY_REG_19 0x4c -#define PHY_REG_20 0x50 - -#define PHY_REG_21 0x54 -#define REG21_SEL_TX_CK_INV BIT(7) -#define REG21_PMS_S_MASK GENMASK(3, 0) - -#define PHY_REG_22 0x58 -#define PHY_REG_23 0x5c -#define PHY_REG_24 0x60 -#define PHY_REG_25 0x64 -#define PHY_REG_26 0x68 -#define PHY_REG_27 0x6c -#define PHY_REG_28 0x70 -#define PHY_REG_29 0x74 -#define PHY_REG_30 0x78 -#define PHY_REG_31 0x7c -#define PHY_REG_32 0x80 +#define PHY_REG(reg) (reg * 4) +#define REG01_PMS_P_MASK GENMASK(3, 0) +#define REG03_PMS_S_MASK GENMASK(7, 4) +#define REG12_CK_DIV_MASK GENMASK(5, 4) + +#define REG13_TG_CODE_LOW_MASK GENMASK(7, 0) + +#define REG14_TOL_MASK GENMASK(7, 4) +#define REG14_RP_CODE_MASK GENMASK(3, 1) +#define REG14_TG_CODE_HIGH_MASK GENMASK(0, 0) + +#define REG21_SEL_TX_CK_INV BIT(7) +#define REG21_PMS_S_MASK GENMASK(3, 0) /* * REG33 does not match the ref manual. According to Sandor Yu from NXP, * "There is a doc issue on the i.MX8MP latest RM" * REG33 is being used per guidance from Sandor */ +#define REG33_MODE_SET_DONE BIT(7) +#define REG33_FIX_DA BIT(1) + +#define REG34_PHY_READY BIT(7) +#define REG34_PLL_LOCK BIT(6) +#define REG34_PHY_CLK_READY BIT(5) -#define PHY_REG_33 0x84 -#define REG33_MODE_SET_DONE BIT(7) -#define REG33_FIX_DA BIT(1) - -#define PHY_REG_34 0x88 -#define REG34_PHY_READY BIT(7) -#define REG34_PLL_LOCK BIT(6) -#define REG34_PHY_CLK_READY BIT(5) - -#define PHY_REG_35 0x8c -#define PHY_REG_36 0x90 -#define PHY_REG_37 0x94 -#define PHY_REG_38 0x98 -#define PHY_REG_39 0x9c -#define PHY_REG_40 0xa0 -#define PHY_REG_41 0xa4 -#define PHY_REG_42 0xa8 -#define PHY_REG_43 0xac -#define PHY_REG_44 0xb0 -#define PHY_REG_45 0xb4 -#define PHY_REG_46 0xb8 -#define PHY_REG_47 0xbc - -#define PHY_PLL_DIV_REGS_NUM 6 +#ifndef MHZ +#define MHZ (1000UL * 1000UL) +#endif + +#define PHY_PLL_DIV_REGS_NUM 7 struct phy_config { u32 pixclk; u8 pll_div_regs[PHY_PLL_DIV_REGS_NUM]; }; +/* + * The calculated_phy_pll_cfg only handles integer divider for PMS, + * meaning the last four entries will be fixed, but the first three will + * be calculated by the PMS calculator. + */ +static struct phy_config calculated_phy_pll_cfg = { + .pixclk = 0, + .pll_div_regs = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }, +}; + +/* The lookup table contains values for which the fractional divder is used */ static const struct phy_config phy_pll_cfg[] = { { .pixclk = 22250000, - .pll_div_regs = { 0x4b, 0xf1, 0x89, 0x88, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x4b, 0xf1, 0x89, 0x88, 0x80, 0x40 }, }, { .pixclk = 23750000, - .pll_div_regs = { 0x50, 0xf1, 0x86, 0x85, 0x80, 0x40 }, - }, { - .pixclk = 24000000, - .pll_div_regs = { 0x50, 0xf0, 0x00, 0x00, 0x80, 0x00 }, + .pll_div_regs = { 0xd1, 0x50, 0xf1, 0x86, 0x85, 0x80, 0x40 }, }, { .pixclk = 24024000, - .pll_div_regs = { 0x50, 0xf1, 0x99, 0x02, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x50, 0xf1, 0x99, 0x02, 0x80, 0x40 }, }, { .pixclk = 25175000, - .pll_div_regs = { 0x54, 0xfc, 0xcc, 0x91, 0x80, 0x40 }, - }, { - .pixclk = 25200000, - .pll_div_regs = { 0x54, 0xf0, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x54, 0xfc, 0xcc, 0x91, 0x80, 0x40 }, + }, { .pixclk = 26750000, - .pll_div_regs = { 0x5a, 0xf2, 0x89, 0x88, 0x80, 0x40 }, - }, { - .pixclk = 27000000, - .pll_div_regs = { 0x5a, 0xf0, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x5a, 0xf2, 0x89, 0x88, 0x80, 0x40 }, + }, { .pixclk = 27027000, - .pll_div_regs = { 0x5a, 0xf2, 0xfd, 0x0c, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x5a, 0xf2, 0xfd, 0x0c, 0x80, 0x40 }, }, { .pixclk = 29500000, - .pll_div_regs = { 0x62, 0xf4, 0x95, 0x08, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x62, 0xf4, 0x95, 0x08, 0x80, 0x40 }, }, { .pixclk = 30750000, - .pll_div_regs = { 0x66, 0xf4, 0x82, 0x01, 0x88, 0x45 }, + .pll_div_regs = { 0xd1, 0x66, 0xf4, 0x82, 0x01, 0x88, 0x45 }, }, { .pixclk = 30888000, - .pll_div_regs = { 0x66, 0xf4, 0x99, 0x18, 0x88, 0x45 }, + .pll_div_regs = { 0xd1, 0x66, 0xf4, 0x99, 0x18, 0x88, 0x45 }, }, { .pixclk = 33750000, - .pll_div_regs = { 0x70, 0xf4, 0x82, 0x01, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x70, 0xf4, 0x82, 0x01, 0x80, 0x40 }, }, { .pixclk = 35000000, - .pll_div_regs = { 0x58, 0xb8, 0x8b, 0x88, 0x80, 0x40 }, - }, { - .pixclk = 36000000, - .pll_div_regs = { 0x5a, 0xb0, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x58, 0xb8, 0x8b, 0x88, 0x80, 0x40 }, + }, { .pixclk = 36036000, - .pll_div_regs = { 0x5a, 0xb2, 0xfd, 0x0c, 0x80, 0x40 }, - }, { - .pixclk = 40000000, - .pll_div_regs = { 0x64, 0xb0, 0x00, 0x00, 0x80, 0x00 }, - }, { - .pixclk = 43200000, - .pll_div_regs = { 0x5a, 0x90, 0x00, 0x00, 0x80, 0x00 }, + .pll_div_regs = { 0xd1, 0x5a, 0xb2, 0xfd, 0x0c, 0x80, 0x40 }, }, { .pixclk = 43243200, - .pll_div_regs = { 0x5a, 0x92, 0xfd, 0x0c, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x5a, 0x92, 0xfd, 0x0c, 0x80, 0x40 }, }, { .pixclk = 44500000, - .pll_div_regs = { 0x5c, 0x92, 0x98, 0x11, 0x84, 0x41 }, + .pll_div_regs = { 0xd1, 0x5c, 0x92, 0x98, 0x11, 0x84, 0x41 }, }, { .pixclk = 47000000, - .pll_div_regs = { 0x62, 0x94, 0x95, 0x82, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x62, 0x94, 0x95, 0x82, 0x80, 0x40 }, }, { .pixclk = 47500000, - .pll_div_regs = { 0x63, 0x96, 0xa1, 0x82, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x63, 0x96, 0xa1, 0x82, 0x80, 0x40 }, }, { .pixclk = 50349650, - .pll_div_regs = { 0x54, 0x7c, 0xc3, 0x8f, 0x80, 0x40 }, - }, { - .pixclk = 50400000, - .pll_div_regs = { 0x54, 0x70, 0x00, 0x00, 0x80, 0x00 }, + .pll_div_regs = { 0xd1, 0x54, 0x7c, 0xc3, 0x8f, 0x80, 0x40 }, }, { .pixclk = 53250000, - .pll_div_regs = { 0x58, 0x72, 0x84, 0x03, 0x82, 0x41 }, + .pll_div_regs = { 0xd1, 0x58, 0x72, 0x84, 0x03, 0x82, 0x41 }, }, { .pixclk = 53500000, - .pll_div_regs = { 0x5a, 0x72, 0x89, 0x88, 0x80, 0x40 }, - }, { - .pixclk = 54000000, - .pll_div_regs = { 0x5a, 0x70, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x5a, 0x72, 0x89, 0x88, 0x80, 0x40 }, + }, { .pixclk = 54054000, - .pll_div_regs = { 0x5a, 0x72, 0xfd, 0x0c, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x5a, 0x72, 0xfd, 0x0c, 0x80, 0x40 }, }, { .pixclk = 59000000, - .pll_div_regs = { 0x62, 0x74, 0x95, 0x08, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x62, 0x74, 0x95, 0x08, 0x80, 0x40 }, }, { .pixclk = 59340659, - .pll_div_regs = { 0x62, 0x74, 0xdb, 0x52, 0x88, 0x47 }, - }, { - .pixclk = 59400000, - .pll_div_regs = { 0x63, 0x70, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x62, 0x74, 0xdb, 0x52, 0x88, 0x47 }, + }, { .pixclk = 61500000, - .pll_div_regs = { 0x66, 0x74, 0x82, 0x01, 0x88, 0x45 }, + .pll_div_regs = { 0xd1, 0x66, 0x74, 0x82, 0x01, 0x88, 0x45 }, }, { .pixclk = 63500000, - .pll_div_regs = { 0x69, 0x74, 0x89, 0x08, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x69, 0x74, 0x89, 0x08, 0x80, 0x40 }, }, { .pixclk = 67500000, - .pll_div_regs = { 0x54, 0x52, 0x87, 0x03, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x54, 0x52, 0x87, 0x03, 0x80, 0x40 }, }, { .pixclk = 70000000, - .pll_div_regs = { 0x58, 0x58, 0x8b, 0x88, 0x80, 0x40 }, - }, { - .pixclk = 72000000, - .pll_div_regs = { 0x5a, 0x50, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x58, 0x58, 0x8b, 0x88, 0x80, 0x40 }, + }, { .pixclk = 72072000, - .pll_div_regs = { 0x5a, 0x52, 0xfd, 0x0c, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x5a, 0x52, 0xfd, 0x0c, 0x80, 0x40 }, }, { .pixclk = 74176000, - .pll_div_regs = { 0x5d, 0x58, 0xdb, 0xA2, 0x88, 0x41 }, + .pll_div_regs = { 0xd1, 0x5d, 0x58, 0xdb, 0xA2, 0x88, 0x41 }, }, { .pixclk = 74250000, - .pll_div_regs = { 0x5c, 0x52, 0x90, 0x0d, 0x84, 0x41 }, + .pll_div_regs = { 0xd1, 0x5c, 0x52, 0x90, 0x0d, 0x84, 0x41 }, }, { .pixclk = 78500000, - .pll_div_regs = { 0x62, 0x54, 0x87, 0x01, 0x80, 0x40 }, - }, { - .pixclk = 80000000, - .pll_div_regs = { 0x64, 0x50, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x62, 0x54, 0x87, 0x01, 0x80, 0x40 }, + }, { .pixclk = 82000000, - .pll_div_regs = { 0x66, 0x54, 0x82, 0x01, 0x88, 0x45 }, + .pll_div_regs = { 0xd1, 0x66, 0x54, 0x82, 0x01, 0x88, 0x45 }, }, { .pixclk = 82500000, - .pll_div_regs = { 0x67, 0x54, 0x88, 0x01, 0x90, 0x49 }, + .pll_div_regs = { 0xd1, 0x67, 0x54, 0x88, 0x01, 0x90, 0x49 }, }, { .pixclk = 89000000, - .pll_div_regs = { 0x70, 0x54, 0x84, 0x83, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x70, 0x54, 0x84, 0x83, 0x80, 0x40 }, }, { .pixclk = 90000000, - .pll_div_regs = { 0x70, 0x54, 0x82, 0x01, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x70, 0x54, 0x82, 0x01, 0x80, 0x40 }, }, { .pixclk = 94000000, - .pll_div_regs = { 0x4e, 0x32, 0xa7, 0x10, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x4e, 0x32, 0xa7, 0x10, 0x80, 0x40 }, }, { .pixclk = 95000000, - .pll_div_regs = { 0x50, 0x31, 0x86, 0x85, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x50, 0x31, 0x86, 0x85, 0x80, 0x40 }, }, { .pixclk = 98901099, - .pll_div_regs = { 0x52, 0x3a, 0xdb, 0x4c, 0x88, 0x47 }, + .pll_div_regs = { 0xd1, 0x52, 0x3a, 0xdb, 0x4c, 0x88, 0x47 }, }, { .pixclk = 99000000, - .pll_div_regs = { 0x52, 0x32, 0x82, 0x01, 0x88, 0x47 }, + .pll_div_regs = { 0xd1, 0x52, 0x32, 0x82, 0x01, 0x88, 0x47 }, }, { .pixclk = 100699300, - .pll_div_regs = { 0x54, 0x3c, 0xc3, 0x8f, 0x80, 0x40 }, - }, { - .pixclk = 100800000, - .pll_div_regs = { 0x54, 0x30, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x54, 0x3c, 0xc3, 0x8f, 0x80, 0x40 }, + }, { .pixclk = 102500000, - .pll_div_regs = { 0x55, 0x32, 0x8c, 0x05, 0x90, 0x4b }, + .pll_div_regs = { 0xd1, 0x55, 0x32, 0x8c, 0x05, 0x90, 0x4b }, }, { .pixclk = 104750000, - .pll_div_regs = { 0x57, 0x32, 0x98, 0x07, 0x90, 0x49 }, + .pll_div_regs = { 0xd1, 0x57, 0x32, 0x98, 0x07, 0x90, 0x49 }, }, { .pixclk = 106500000, - .pll_div_regs = { 0x58, 0x32, 0x84, 0x03, 0x82, 0x41 }, + .pll_div_regs = { 0xd1, 0x58, 0x32, 0x84, 0x03, 0x82, 0x41 }, }, { .pixclk = 107000000, - .pll_div_regs = { 0x5a, 0x32, 0x89, 0x88, 0x80, 0x40 }, - }, { - .pixclk = 108000000, - .pll_div_regs = { 0x5a, 0x30, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x5a, 0x32, 0x89, 0x88, 0x80, 0x40 }, + }, { .pixclk = 108108000, - .pll_div_regs = { 0x5a, 0x32, 0xfd, 0x0c, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x5a, 0x32, 0xfd, 0x0c, 0x80, 0x40 }, }, { .pixclk = 118000000, - .pll_div_regs = { 0x62, 0x34, 0x95, 0x08, 0x80, 0x40 }, - }, { - .pixclk = 118800000, - .pll_div_regs = { 0x63, 0x30, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x62, 0x34, 0x95, 0x08, 0x80, 0x40 }, + }, { .pixclk = 123000000, - .pll_div_regs = { 0x66, 0x34, 0x82, 0x01, 0x88, 0x45 }, + .pll_div_regs = { 0xd1, 0x66, 0x34, 0x82, 0x01, 0x88, 0x45 }, }, { .pixclk = 127000000, - .pll_div_regs = { 0x69, 0x34, 0x89, 0x08, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x69, 0x34, 0x89, 0x08, 0x80, 0x40 }, }, { .pixclk = 135000000, - .pll_div_regs = { 0x70, 0x34, 0x82, 0x01, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x70, 0x34, 0x82, 0x01, 0x80, 0x40 }, }, { .pixclk = 135580000, - .pll_div_regs = { 0x71, 0x39, 0xe9, 0x82, 0x9c, 0x5b }, + .pll_div_regs = { 0xd1, 0x71, 0x39, 0xe9, 0x82, 0x9c, 0x5b }, }, { .pixclk = 137520000, - .pll_div_regs = { 0x72, 0x38, 0x99, 0x10, 0x85, 0x41 }, + .pll_div_regs = { 0xd1, 0x72, 0x38, 0x99, 0x10, 0x85, 0x41 }, }, { .pixclk = 138750000, - .pll_div_regs = { 0x73, 0x35, 0x88, 0x05, 0x90, 0x4d }, + .pll_div_regs = { 0xd1, 0x73, 0x35, 0x88, 0x05, 0x90, 0x4d }, }, { .pixclk = 140000000, - .pll_div_regs = { 0x75, 0x36, 0xa7, 0x90, 0x80, 0x40 }, - }, { - .pixclk = 144000000, - .pll_div_regs = { 0x78, 0x30, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x75, 0x36, 0xa7, 0x90, 0x80, 0x40 }, + }, { .pixclk = 148352000, - .pll_div_regs = { 0x7b, 0x35, 0xdb, 0x39, 0x90, 0x45 }, + .pll_div_regs = { 0xd1, 0x7b, 0x35, 0xdb, 0x39, 0x90, 0x45 }, }, { .pixclk = 148500000, - .pll_div_regs = { 0x7b, 0x35, 0x84, 0x03, 0x90, 0x45 }, + .pll_div_regs = { 0xd1, 0x7b, 0x35, 0x84, 0x03, 0x90, 0x45 }, }, { .pixclk = 154000000, - .pll_div_regs = { 0x40, 0x18, 0x83, 0x01, 0x00, 0x40 }, + .pll_div_regs = { 0xd1, 0x40, 0x18, 0x83, 0x01, 0x00, 0x40 }, }, { .pixclk = 157000000, - .pll_div_regs = { 0x41, 0x11, 0xa7, 0x14, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x41, 0x11, 0xa7, 0x14, 0x80, 0x40 }, }, { .pixclk = 160000000, - .pll_div_regs = { 0x42, 0x12, 0xa1, 0x20, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x42, 0x12, 0xa1, 0x20, 0x80, 0x40 }, }, { .pixclk = 162000000, - .pll_div_regs = { 0x43, 0x18, 0x8b, 0x08, 0x96, 0x55 }, + .pll_div_regs = { 0xd1, 0x43, 0x18, 0x8b, 0x08, 0x96, 0x55 }, }, { .pixclk = 164000000, - .pll_div_regs = { 0x45, 0x11, 0x83, 0x82, 0x90, 0x4b }, + .pll_div_regs = { 0xd1, 0x45, 0x11, 0x83, 0x82, 0x90, 0x4b }, }, { .pixclk = 165000000, - .pll_div_regs = { 0x45, 0x11, 0x84, 0x81, 0x90, 0x4b }, - }, { - .pixclk = 180000000, - .pll_div_regs = { 0x4b, 0x10, 0x00, 0x00, 0x80, 0x00 }, + .pll_div_regs = { 0xd1, 0x45, 0x11, 0x84, 0x81, 0x90, 0x4b }, }, { .pixclk = 185625000, - .pll_div_regs = { 0x4e, 0x12, 0x9a, 0x95, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x4e, 0x12, 0x9a, 0x95, 0x80, 0x40 }, }, { .pixclk = 188000000, - .pll_div_regs = { 0x4e, 0x12, 0xa7, 0x10, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x4e, 0x12, 0xa7, 0x10, 0x80, 0x40 }, }, { .pixclk = 198000000, - .pll_div_regs = { 0x52, 0x12, 0x82, 0x01, 0x88, 0x47 }, + .pll_div_regs = { 0xd1, 0x52, 0x12, 0x82, 0x01, 0x88, 0x47 }, }, { .pixclk = 205000000, - .pll_div_regs = { 0x55, 0x12, 0x8c, 0x05, 0x90, 0x4b }, + .pll_div_regs = { 0xd1, 0x55, 0x12, 0x8c, 0x05, 0x90, 0x4b }, }, { .pixclk = 209500000, - .pll_div_regs = { 0x57, 0x12, 0x98, 0x07, 0x90, 0x49 }, + .pll_div_regs = { 0xd1, 0x57, 0x12, 0x98, 0x07, 0x90, 0x49 }, }, { .pixclk = 213000000, - .pll_div_regs = { 0x58, 0x12, 0x84, 0x03, 0x82, 0x41 }, - }, { - .pixclk = 216000000, - .pll_div_regs = { 0x5a, 0x10, 0x00, 0x00, 0x80, 0x00 }, + .pll_div_regs = { 0xd1, 0x58, 0x12, 0x84, 0x03, 0x82, 0x41 }, }, { .pixclk = 216216000, - .pll_div_regs = { 0x5a, 0x12, 0xfd, 0x0c, 0x80, 0x40 }, - }, { - .pixclk = 237600000, - .pll_div_regs = { 0x63, 0x10, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x5a, 0x12, 0xfd, 0x0c, 0x80, 0x40 }, + }, { .pixclk = 254000000, - .pll_div_regs = { 0x69, 0x14, 0x89, 0x08, 0x80, 0x40 }, + .pll_div_regs = { 0xd1, 0x69, 0x14, 0x89, 0x08, 0x80, 0x40 }, }, { .pixclk = 277500000, - .pll_div_regs = { 0x73, 0x15, 0x88, 0x05, 0x90, 0x4d }, - }, { - .pixclk = 288000000, - .pll_div_regs = { 0x78, 0x10, 0x00, 0x00, 0x80, 0x00 }, - }, { + .pll_div_regs = { 0xd1, 0x73, 0x15, 0x88, 0x05, 0x90, 0x4d }, + }, { .pixclk = 297000000, - .pll_div_regs = { 0x7b, 0x15, 0x84, 0x03, 0x90, 0x45 }, + .pll_div_regs = { 0xd1, 0x7b, 0x15, 0x84, 0x03, 0x90, 0x45 }, }, }; @@ -369,29 +282,30 @@ struct reg_settings { }; static const struct reg_settings common_phy_cfg[] = { - { PHY_REG_00, 0x00 }, { PHY_REG_01, 0xd1 }, - { PHY_REG_08, 0x4f }, { PHY_REG_09, 0x30 }, - { PHY_REG_10, 0x33 }, { PHY_REG_11, 0x65 }, + { PHY_REG(0), 0x00 }, + /* PHY_REG(1-7) pix clk specific */ + { PHY_REG(8), 0x4f }, { PHY_REG(9), 0x30 }, + { PHY_REG(10), 0x33 }, { PHY_REG(11), 0x65 }, /* REG12 pixclk specific */ /* REG13 pixclk specific */ /* REG14 pixclk specific */ - { PHY_REG_15, 0x80 }, { PHY_REG_16, 0x6c }, - { PHY_REG_17, 0xf2 }, { PHY_REG_18, 0x67 }, - { PHY_REG_19, 0x00 }, { PHY_REG_20, 0x10 }, + { PHY_REG(15), 0x80 }, { PHY_REG(16), 0x6c }, + { PHY_REG(17), 0xf2 }, { PHY_REG(18), 0x67 }, + { PHY_REG(19), 0x00 }, { PHY_REG(20), 0x10 }, /* REG21 pixclk specific */ - { PHY_REG_22, 0x30 }, { PHY_REG_23, 0x32 }, - { PHY_REG_24, 0x60 }, { PHY_REG_25, 0x8f }, - { PHY_REG_26, 0x00 }, { PHY_REG_27, 0x00 }, - { PHY_REG_28, 0x08 }, { PHY_REG_29, 0x00 }, - { PHY_REG_30, 0x00 }, { PHY_REG_31, 0x00 }, - { PHY_REG_32, 0x00 }, { PHY_REG_33, 0x80 }, - { PHY_REG_34, 0x00 }, { PHY_REG_35, 0x00 }, - { PHY_REG_36, 0x00 }, { PHY_REG_37, 0x00 }, - { PHY_REG_38, 0x00 }, { PHY_REG_39, 0x00 }, - { PHY_REG_40, 0x00 }, { PHY_REG_41, 0xe0 }, - { PHY_REG_42, 0x83 }, { PHY_REG_43, 0x0f }, - { PHY_REG_44, 0x3E }, { PHY_REG_45, 0xf8 }, - { PHY_REG_46, 0x00 }, { PHY_REG_47, 0x00 } + { PHY_REG(22), 0x30 }, { PHY_REG(23), 0x32 }, + { PHY_REG(24), 0x60 }, { PHY_REG(25), 0x8f }, + { PHY_REG(26), 0x00 }, { PHY_REG(27), 0x00 }, + { PHY_REG(28), 0x08 }, { PHY_REG(29), 0x00 }, + { PHY_REG(30), 0x00 }, { PHY_REG(31), 0x00 }, + { PHY_REG(32), 0x00 }, { PHY_REG(33), 0x80 }, + { PHY_REG(34), 0x00 }, { PHY_REG(35), 0x00 }, + { PHY_REG(36), 0x00 }, { PHY_REG(37), 0x00 }, + { PHY_REG(38), 0x00 }, { PHY_REG(39), 0x00 }, + { PHY_REG(40), 0x00 }, { PHY_REG(41), 0xe0 }, + { PHY_REG(42), 0x83 }, { PHY_REG(43), 0x0f }, + { PHY_REG(44), 0x3E }, { PHY_REG(45), 0xf8 }, + { PHY_REG(46), 0x00 }, { PHY_REG(47), 0x00 } }; struct fsl_samsung_hdmi_phy { @@ -411,40 +325,6 @@ to_fsl_samsung_hdmi_phy(struct clk_hw *hw) return container_of(hw, struct fsl_samsung_hdmi_phy, hw); } -static void -fsl_samsung_hdmi_phy_configure_pixclk(struct fsl_samsung_hdmi_phy *phy, - const struct phy_config *cfg) -{ - u8 div = 0x1; - - switch (cfg->pixclk) { - case 22250000 ... 33750000: - div = 0xf; - break; - case 35000000 ... 40000000: - div = 0xb; - break; - case 43200000 ... 47500000: - div = 0x9; - break; - case 50349650 ... 63500000: - div = 0x7; - break; - case 67500000 ... 90000000: - div = 0x5; - break; - case 94000000 ... 148500000: - div = 0x3; - break; - case 154000000 ... 297000000: - div = 0x1; - break; - } - - writeb(REG21_SEL_TX_CK_INV | FIELD_PREP(REG21_PMS_S_MASK, div), - phy->regs + PHY_REG_21); -} - static void fsl_samsung_hdmi_phy_configure_pll_lock_det(struct fsl_samsung_hdmi_phy *phy, const struct phy_config *cfg) @@ -469,7 +349,7 @@ fsl_samsung_hdmi_phy_configure_pll_lock_det(struct fsl_samsung_hdmi_phy *phy, break; } - writeb(FIELD_PREP(REG12_CK_DIV_MASK, ilog2(div)), phy->regs + PHY_REG_12); + writeb(FIELD_PREP(REG12_CK_DIV_MASK, ilog2(div)), phy->regs + PHY_REG(12)); /* * Calculation for the frequency lock detector target code (fld_tg_code) @@ -489,11 +369,88 @@ fsl_samsung_hdmi_phy_configure_pll_lock_det(struct fsl_samsung_hdmi_phy *phy, /* FLD_TOL and FLD_RP_CODE taken from downstream driver */ writeb(FIELD_PREP(REG13_TG_CODE_LOW_MASK, fld_tg_code), - phy->regs + PHY_REG_13); + phy->regs + PHY_REG(13)); writeb(FIELD_PREP(REG14_TOL_MASK, 2) | FIELD_PREP(REG14_RP_CODE_MASK, 2) | FIELD_PREP(REG14_TG_CODE_HIGH_MASK, fld_tg_code >> 8), - phy->regs + PHY_REG_14); + phy->regs + PHY_REG(14)); +} + +static unsigned long fsl_samsung_hdmi_phy_find_pms(unsigned long fout, u8 *p, u16 *m, u8 *s) +{ + unsigned long best_freq = 0; + u32 min_delta = 0xffffffff; + u8 _p, best_p; + u16 _m, best_m; + u8 _s, best_s; + + /* + * Figure 13-78 of the reference manual states the PLL should be TMDS x 5 + * while the TMDS_CLKO should be the PLL / 5. So to calculate the PLL, + * take the pix clock x 5, then return the value of the PLL / 5. + */ + fout *= 5; + + /* The ref manual states the values of 'P' range from 1 to 11 */ + for (_p = 1; _p <= 11; ++_p) { + for (_s = 1; _s <= 16; ++_s) { + u64 tmp; + u32 delta; + + /* s must be one or even */ + if (_s > 1 && (_s & 0x01) == 1) + _s++; + + /* _s cannot be 14 per the TRM */ + if (_s == 14) + continue; + + /* + * TODO: Ref Manual doesn't state the range of _m + * so this should be further refined if possible. + * This range was set based on the original values + * in the lookup table + */ + tmp = (u64)fout * (_p * _s); + do_div(tmp, 24 * MHZ); + _m = tmp; + if (_m < 0x30 || _m > 0x7b) + continue; + + /* + * Rev 2 of the Ref Manual states the + * VCO can range between 750MHz and + * 3GHz. The VCO is assumed to be + * Fvco = (M * f_ref) / P, + * where f_ref is 24MHz. + */ + tmp = (u64)_m * 24 * MHZ; + do_div(tmp, _p); + if (tmp < 750 * MHZ || + tmp > 3000 * MHZ) + continue; + + /* Final frequency after post-divider */ + do_div(tmp, _s); + + delta = abs(fout - tmp); + if (delta < min_delta) { + best_p = _p; + best_s = _s; + best_m = _m; + min_delta = delta; + best_freq = tmp; + } + } + } + + if (best_freq) { + *p = best_p; + *m = best_m; + *s = best_s; + } + + return best_freq / 5; } static int fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy, @@ -503,22 +460,25 @@ static int fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy, u8 val; /* HDMI PHY init */ - writeb(REG33_FIX_DA, phy->regs + PHY_REG_33); + writeb(REG33_FIX_DA, phy->regs + PHY_REG(33)); /* common PHY registers */ for (i = 0; i < ARRAY_SIZE(common_phy_cfg); i++) writeb(common_phy_cfg[i].val, phy->regs + common_phy_cfg[i].reg); - /* set individual PLL registers PHY_REG2 ... PHY_REG7 */ + /* set individual PLL registers PHY_REG1 ... PHY_REG7 */ for (i = 0; i < PHY_PLL_DIV_REGS_NUM; i++) - writeb(cfg->pll_div_regs[i], phy->regs + PHY_REG_02 + i * 4); + writeb(cfg->pll_div_regs[i], phy->regs + PHY_REG(1) + i * 4); + + /* High nibble of PHY_REG3 and low nibble of PHY_REG21 both contain 'S' */ + writeb(REG21_SEL_TX_CK_INV | FIELD_PREP(REG21_PMS_S_MASK, + cfg->pll_div_regs[2] >> 4), phy->regs + PHY_REG(21)); - fsl_samsung_hdmi_phy_configure_pixclk(phy, cfg); fsl_samsung_hdmi_phy_configure_pll_lock_det(phy, cfg); - writeb(REG33_FIX_DA | REG33_MODE_SET_DONE, phy->regs + PHY_REG_33); + writeb(REG33_FIX_DA | REG33_MODE_SET_DONE, phy->regs + PHY_REG(33)); - ret = readb_poll_timeout(phy->regs + PHY_REG_34, val, + ret = readb_poll_timeout(phy->regs + PHY_REG(34), val, val & REG34_PLL_LOCK, 50, 20000); if (ret) dev_err(phy->dev, "PLL failed to lock\n"); @@ -537,34 +497,120 @@ static unsigned long phy_clk_recalc_rate(struct clk_hw *hw, return phy->cur_cfg->pixclk; } -static long phy_clk_round_rate(struct clk_hw *hw, - unsigned long rate, unsigned long *parent_rate) +/* Helper function to lookup the available fractional-divider rate */ +static const struct phy_config *fsl_samsung_hdmi_phy_lookup_rate(unsigned long rate) { int i; + /* Search the lookup table */ for (i = ARRAY_SIZE(phy_pll_cfg) - 1; i >= 0; i--) if (phy_pll_cfg[i].pixclk <= rate) - return phy_pll_cfg[i].pixclk; + break; - return -EINVAL; + return &phy_pll_cfg[i]; +} + +static void fsl_samsung_hdmi_calculate_phy(struct phy_config *cal_phy, unsigned long rate, + u8 p, u16 m, u8 s) +{ + cal_phy->pixclk = rate; + cal_phy->pll_div_regs[0] = FIELD_PREP(REG01_PMS_P_MASK, p); + cal_phy->pll_div_regs[1] = m; + cal_phy->pll_div_regs[2] = FIELD_PREP(REG03_PMS_S_MASK, s-1); + /* pll_div_regs 3-6 are fixed and pre-defined already */ +} + +static u32 fsl_samsung_hdmi_phy_get_closest_rate(unsigned long rate, + u32 int_div_clk, u32 frac_div_clk) +{ + /* Calculate the absolute value of the differences and return whichever is closest */ + if (abs((long)rate - (long)int_div_clk) < abs((long)(rate - (long)frac_div_clk))) + return int_div_clk; + + return frac_div_clk; +} + +static long phy_clk_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate) +{ + const struct phy_config *fract_div_phy; + u32 int_div_clk; + u16 m; + u8 p, s; + + /* If the clock is out of range return error instead of searching */ + if (rate > 297000000 || rate < 22250000) + return -EINVAL; + + /* Search the fractional divider lookup table */ + fract_div_phy = fsl_samsung_hdmi_phy_lookup_rate(rate); + + /* If the rate is an exact match, return that value */ + if (rate == fract_div_phy->pixclk) + return fract_div_phy->pixclk; + + /* If the exact match isn't found, calculate the integer divider */ + int_div_clk = fsl_samsung_hdmi_phy_find_pms(rate, &p, &m, &s); + + /* If the int_div_clk rate is an exact match, return that value */ + if (int_div_clk == rate) + return int_div_clk; + + /* If neither rate is an exact match, use the value from the LUT */ + return fract_div_phy->pixclk; +} + +static int phy_use_fract_div(struct fsl_samsung_hdmi_phy *phy, const struct phy_config *fract_div_phy) +{ + phy->cur_cfg = fract_div_phy; + dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: using fractional divider rate = %u\n", + phy->cur_cfg->pixclk); + return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); +} + +static int phy_use_integer_div(struct fsl_samsung_hdmi_phy *phy, + const struct phy_config *int_div_clk) +{ + phy->cur_cfg = &calculated_phy_pll_cfg; + dev_dbg(phy->dev, "fsl_samsung_hdmi_phy: integer divider rate = %u\n", + phy->cur_cfg->pixclk); + return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); } static int phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); - int i; + const struct phy_config *fract_div_phy; + u32 int_div_clk; + u16 m; + u8 p, s; - for (i = ARRAY_SIZE(phy_pll_cfg) - 1; i >= 0; i--) - if (phy_pll_cfg[i].pixclk <= rate) - break; + /* Search the fractional divider lookup table */ + fract_div_phy = fsl_samsung_hdmi_phy_lookup_rate(rate); - if (i < 0) - return -EINVAL; + /* If the rate is an exact match, use that value */ + if (fract_div_phy->pixclk == rate) + return phy_use_fract_div(phy, fract_div_phy); - phy->cur_cfg = &phy_pll_cfg[i]; + /* + * If the rate from the fractional divider is not exact, check the integer divider, + * and use it if that value is an exact match. + */ + int_div_clk = fsl_samsung_hdmi_phy_find_pms(rate, &p, &m, &s); + fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s); + if (int_div_clk == rate) + return phy_use_integer_div(phy, &calculated_phy_pll_cfg); - return fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); + /* + * Compare the difference between the integer clock and the fractional clock against + * the desired clock and which whichever is closest. + */ + if (fsl_samsung_hdmi_phy_get_closest_rate(rate, int_div_clk, + fract_div_phy->pixclk) == fract_div_phy->pixclk) + return phy_use_fract_div(phy, fract_div_phy); + else + return phy_use_integer_div(phy, &calculated_phy_pll_cfg); } static const struct clk_ops phy_clk_ops = { @@ -703,8 +749,8 @@ static const struct of_device_id fsl_samsung_hdmi_phy_of_match[] = { MODULE_DEVICE_TABLE(of, fsl_samsung_hdmi_phy_of_match); static struct platform_driver fsl_samsung_hdmi_phy_driver = { - .probe = fsl_samsung_hdmi_phy_probe, - .remove_new = fsl_samsung_hdmi_phy_remove, + .probe = fsl_samsung_hdmi_phy_probe, + .remove = fsl_samsung_hdmi_phy_remove, .driver = { .name = "fsl-samsung-hdmi-phy", .of_match_table = fsl_samsung_hdmi_phy_of_match, diff --git a/drivers/phy/intel/phy-intel-lgm-combo.c b/drivers/phy/intel/phy-intel-lgm-combo.c index f8e3054a9e5977..9ee3cf61cdd004 100644 --- a/drivers/phy/intel/phy-intel-lgm-combo.c +++ b/drivers/phy/intel/phy-intel-lgm-combo.c @@ -605,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_new = intel_cbphy_remove, + .remove = intel_cbphy_remove, .driver = { .name = "intel-combo-phy", .of_match_table = of_intel_cbphy_match, diff --git a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c index 4922a5f3327d51..59903f86b13f56 100644 --- a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c +++ b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c @@ -62,6 +62,8 @@ #define SQ_AMP_CAL_MASK GENMASK(2, 0) #define SQ_AMP_CAL_VAL 1 #define SQ_AMP_CAL_EN BIT(3) +#define UTMI_DIG_CTRL1_REG 0x20 +#define SWAP_DPDM BIT(15) #define UTMI_CTRL_STATUS0_REG 0x24 #define SUSPENDM BIT(22) #define TEST_SEL BIT(25) @@ -99,11 +101,13 @@ struct mvebu_cp110_utmi { * @priv: PHY driver data * @id: PHY port ID * @dr_mode: PHY connection: USB_DR_MODE_HOST or USB_DR_MODE_PERIPHERAL + * @swap_dx: whether to swap d+/d- signals */ struct mvebu_cp110_utmi_port { struct mvebu_cp110_utmi *priv; u32 id; enum usb_dr_mode dr_mode; + bool swap_dx; }; static void mvebu_cp110_utmi_port_setup(struct mvebu_cp110_utmi_port *port) @@ -159,6 +163,13 @@ static void mvebu_cp110_utmi_port_setup(struct mvebu_cp110_utmi_port *port) reg &= ~(VDAT_MASK | VSRC_MASK); reg |= (VDAT_VAL << VDAT_OFFSET) | (VSRC_VAL << VSRC_OFFSET); writel(reg, PORT_REGS(port) + UTMI_CHGDTC_CTRL_REG); + + /* Swap D+/D- */ + reg = readl(PORT_REGS(port) + UTMI_DIG_CTRL1_REG); + reg &= ~(SWAP_DPDM); + if (port->swap_dx) + reg |= SWAP_DPDM; + writel(reg, PORT_REGS(port) + UTMI_DIG_CTRL1_REG); } static int mvebu_cp110_utmi_phy_power_off(struct phy *phy) @@ -286,6 +297,7 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) struct phy_provider *provider; struct device_node *child; u32 usb_devices = 0; + u32 swap_dx = 0; utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL); if (!utmi) @@ -345,6 +357,10 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) } } + of_property_for_each_u32(dev->of_node, "swap-dx-lanes", swap_dx) + if (swap_dx == port_id) + port->swap_dx = 1; + /* Retrieve PHY capabilities */ utmi->ops = &mvebu_cp110_utmi_phy_ops; diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c index 7cb85029fab399..320cf5b50a8cc3 100644 --- a/drivers/phy/microchip/sparx5_serdes.c +++ b/drivers/phy/microchip/sparx5_serdes.c @@ -21,23 +21,33 @@ #include "sparx5_serdes.h" -#define SPX5_CMU_MAX 14 - #define SPX5_SERDES_10G_START 13 #define SPX5_SERDES_25G_START 25 #define SPX5_SERDES_6G10G_CNT SPX5_SERDES_25G_START +#define LAN969X_SERDES_10G_CNT 10 + /* Optimal power settings from GUC */ #define SPX5_SERDES_QUIET_MODE_VAL 0x01ef4e0c -enum sparx5_10g28cmu_mode { - SPX5_SD10G28_CMU_MAIN = 0, - SPX5_SD10G28_CMU_AUX1 = 1, - SPX5_SD10G28_CMU_AUX2 = 3, - SPX5_SD10G28_CMU_NONE = 4, - SPX5_SD10G28_CMU_MAX, +/* Register target sizes */ +const unsigned int sparx5_serdes_tsize[TSIZE_LAST] = { + [TC_SD10G_LANE] = 12, + [TC_SD_CMU] = 14, + [TC_SD_CMU_CFG] = 14, + [TC_SD_LANE] = 25, +}; + +const unsigned int lan969x_serdes_tsize[TSIZE_LAST] = { + [TC_SD10G_LANE] = 10, + [TC_SD_CMU] = 6, + [TC_SD_CMU_CFG] = 6, + [TC_SD_LANE] = 10, }; +/* Pointer to the register target size table */ +const unsigned int *tsize; + enum sparx5_sd25g28_mode_preset_type { SPX5_SD25G28_MODE_PRESET_25000, SPX5_SD25G28_MODE_PRESET_10000, @@ -1095,13 +1105,31 @@ static int sparx5_serdes_cmu_get(enum sparx5_10g28cmu_mode mode, int sd_index) return sparx5_serdes_cmu_map[mode][sd_index]; } +/* Map of 6G/10G serdes mode and index to CMU index. */ +static const int +lan969x_serdes_cmu_map[SPX5_SD10G28_CMU_MAX][LAN969X_SERDES_10G_CNT] = { + [SPX5_SD10G28_CMU_MAIN] = { 2, 2, 2, 2, 2, + 2, 2, 2, 5, 5 }, + [SPX5_SD10G28_CMU_AUX1] = { 0, 0, 3, 3, 3, + 3, 3, 3, 3, 3 }, + [SPX5_SD10G28_CMU_AUX2] = { 1, 1, 1, 1, 4, + 4, 4, 4, 4, 4 }, + [SPX5_SD10G28_CMU_NONE] = { 1, 1, 1, 1, 4, + 4, 4, 4, 4, 4 }, +}; + +static int lan969x_serdes_cmu_get(enum sparx5_10g28cmu_mode mode, int sd_index) +{ + return lan969x_serdes_cmu_map[mode][sd_index]; +} + static void sparx5_serdes_cmu_power_off(struct sparx5_serdes_private *priv) { void __iomem *cmu_inst, *cmu_cfg_inst; int i; /* Power down each CMU */ - for (i = 0; i < SPX5_CMU_MAX; i++) { + for (i = 0; i < priv->data->consts.cmu_max; i++) { cmu_inst = sdx5_inst_get(priv, TARGET_SD_CMU, i); cmu_cfg_inst = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, i); @@ -1650,7 +1678,7 @@ static int sparx5_sd10g28_apply_params(struct sparx5_serdes_macro *macro, if (params->skip_cmu_cfg) return 0; - cmu_idx = sparx5_serdes_cmu_get(params->cmu_sel, lane_index); + cmu_idx = priv->data->ops.serdes_cmu_get(params->cmu_sel, macro->sidx); err = sparx5_cmu_cfg(priv, cmu_idx); if (err) return err; @@ -2183,6 +2211,10 @@ static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro) { struct sparx5_serdes_private *priv = macro->priv; + /* Clock is auto-detected in 100Base-FX mode on lan969x */ + if (priv->data->type == SPX5_TARGET_LAN969X) + return 0; + if (macro->serdesmode == SPX5_SD_MODE_100FX) { u32 freq = priv->coreclock == 250000000 ? 2 : priv->coreclock == 500000000 ? 1 : 0; @@ -2297,10 +2329,12 @@ static int sparx5_serdes_set_speed(struct phy *phy, int speed) { struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); - if (macro->sidx < SPX5_SERDES_10G_START && speed > SPEED_5000) - return -EINVAL; - if (macro->sidx < SPX5_SERDES_25G_START && speed > SPEED_10000) - return -EINVAL; + if (macro->priv->data->type == SPX5_TARGET_SPARX5) { + if (macro->sidx < SPX5_SERDES_10G_START && speed > SPEED_5000) + return -EINVAL; + if (macro->sidx < SPX5_SERDES_25G_START && speed > SPEED_10000) + return -EINVAL; + } if (speed != macro->speed) { macro->speed = speed; if (macro->serdesmode != SPX5_SD_MODE_NONE) @@ -2337,11 +2371,14 @@ static int sparx5_serdes_validate(struct phy *phy, enum phy_mode mode, if (macro->speed == 0) return -EINVAL; - if (macro->sidx < SPX5_SERDES_10G_START && macro->speed > SPEED_5000) - return -EINVAL; - if (macro->sidx < SPX5_SERDES_25G_START && macro->speed > SPEED_10000) - return -EINVAL; - + if (macro->priv->data->type == SPX5_TARGET_SPARX5) { + if (macro->sidx < SPX5_SERDES_10G_START && + macro->speed > SPEED_5000) + return -EINVAL; + if (macro->sidx < SPX5_SERDES_25G_START && + macro->speed > SPEED_10000) + return -EINVAL; + } switch (submode) { case PHY_INTERFACE_MODE_1000BASEX: if (macro->speed != SPEED_100 && /* This is for 100BASE-FX */ @@ -2375,6 +2412,26 @@ static const struct phy_ops sparx5_serdes_ops = { .owner = THIS_MODULE, }; +static void sparx5_serdes_type_set(struct sparx5_serdes_macro *macro, int sidx) +{ + if (sidx < SPX5_SERDES_10G_START) { + macro->serdestype = SPX5_SDT_6G; + macro->stpidx = macro->sidx; + } else if (sidx < SPX5_SERDES_25G_START) { + macro->serdestype = SPX5_SDT_10G; + macro->stpidx = macro->sidx - SPX5_SERDES_10G_START; + } else { + macro->serdestype = SPX5_SDT_25G; + macro->stpidx = macro->sidx - SPX5_SERDES_25G_START; + } +} + +static void lan969x_serdes_type_set(struct sparx5_serdes_macro *macro, int sidx) +{ + macro->serdestype = SPX5_SDT_10G; + macro->stpidx = macro->sidx; +} + static int sparx5_phy_create(struct sparx5_serdes_private *priv, int idx, struct phy **phy) { @@ -2391,16 +2448,8 @@ static int sparx5_phy_create(struct sparx5_serdes_private *priv, macro->sidx = idx; macro->priv = priv; macro->speed = SPEED_UNKNOWN; - if (idx < SPX5_SERDES_10G_START) { - macro->serdestype = SPX5_SDT_6G; - macro->stpidx = macro->sidx; - } else if (idx < SPX5_SERDES_25G_START) { - macro->serdestype = SPX5_SDT_10G; - macro->stpidx = macro->sidx - SPX5_SERDES_10G_START; - } else { - macro->serdestype = SPX5_SDT_25G; - macro->stpidx = macro->sidx - SPX5_SERDES_25G_START; - } + + priv->data->ops.serdes_type_set(macro, idx); phy_set_drvdata(*phy, macro); @@ -2507,6 +2556,71 @@ static struct sparx5_serdes_io_resource sparx5_serdes_iomap[] = { { TARGET_SD_LANE_25G + 7, 0x5c8000 }, /* 0x610dd0000: sd_lane_25g_32 */ }; +static const struct sparx5_serdes_io_resource lan969x_serdes_iomap[] = { + { TARGET_SD_CMU, 0x0 }, /* 0xe3410000 */ + { TARGET_SD_CMU + 1, 0x8000 }, /* 0xe3418000 */ + { TARGET_SD_CMU + 2, 0x10000 }, /* 0xe3420000 */ + { TARGET_SD_CMU + 3, 0x18000 }, /* 0xe3428000 */ + { TARGET_SD_CMU + 4, 0x20000 }, /* 0xe3430000 */ + { TARGET_SD_CMU + 5, 0x28000 }, /* 0xe3438000 */ + { TARGET_SD_CMU_CFG, 0x30000 }, /* 0xe3440000 */ + { TARGET_SD_CMU_CFG + 1, 0x38000 }, /* 0xe3448000 */ + { TARGET_SD_CMU_CFG + 2, 0x40000 }, /* 0xe3450000 */ + { TARGET_SD_CMU_CFG + 3, 0x48000 }, /* 0xe3458000 */ + { TARGET_SD_CMU_CFG + 4, 0x50000 }, /* 0xe3460000 */ + { TARGET_SD_CMU_CFG + 5, 0x58000 }, /* 0xe3468000 */ + { TARGET_SD10G_LANE, 0x60000 }, /* 0xe3470000 */ + { TARGET_SD10G_LANE + 1, 0x68000 }, /* 0xe3478000 */ + { TARGET_SD10G_LANE + 2, 0x70000 }, /* 0xe3480000 */ + { TARGET_SD10G_LANE + 3, 0x78000 }, /* 0xe3488000 */ + { TARGET_SD10G_LANE + 4, 0x80000 }, /* 0xe3490000 */ + { TARGET_SD10G_LANE + 5, 0x88000 }, /* 0xe3498000 */ + { TARGET_SD10G_LANE + 6, 0x90000 }, /* 0xe34a0000 */ + { TARGET_SD10G_LANE + 7, 0x98000 }, /* 0xe34a8000 */ + { TARGET_SD10G_LANE + 8, 0xa0000 }, /* 0xe34b0000 */ + { TARGET_SD10G_LANE + 9, 0xa8000 }, /* 0xe34b8000 */ + { TARGET_SD_LANE, 0x100000 }, /* 0xe3510000 */ + { TARGET_SD_LANE + 1, 0x108000 }, /* 0xe3518000 */ + { TARGET_SD_LANE + 2, 0x110000 }, /* 0xe3520000 */ + { TARGET_SD_LANE + 3, 0x118000 }, /* 0xe3528000 */ + { TARGET_SD_LANE + 4, 0x120000 }, /* 0xe3530000 */ + { TARGET_SD_LANE + 5, 0x128000 }, /* 0xe3538000 */ + { TARGET_SD_LANE + 6, 0x130000 }, /* 0xe3540000 */ + { TARGET_SD_LANE + 7, 0x138000 }, /* 0xe3548000 */ + { TARGET_SD_LANE + 8, 0x140000 }, /* 0xe3550000 */ + { TARGET_SD_LANE + 9, 0x148000 }, /* 0xe3558000 */ +}; + +static const struct sparx5_serdes_match_data sparx5_desc = { + .type = SPX5_TARGET_SPARX5, + .iomap = sparx5_serdes_iomap, + .iomap_size = ARRAY_SIZE(sparx5_serdes_iomap), + .tsize = sparx5_serdes_tsize, + .consts = { + .sd_max = 33, + .cmu_max = 14, + }, + .ops = { + .serdes_type_set = &sparx5_serdes_type_set, + .serdes_cmu_get = &sparx5_serdes_cmu_get, + }, +}; + +static const struct sparx5_serdes_match_data lan969x_desc = { + .type = SPX5_TARGET_LAN969X, + .iomap = lan969x_serdes_iomap, + .iomap_size = ARRAY_SIZE(lan969x_serdes_iomap), + .tsize = lan969x_serdes_tsize, + .consts = { + .sd_max = 10, + .cmu_max = 6, + }, + .ops = { + .serdes_type_set = &lan969x_serdes_type_set, + .serdes_cmu_get = &lan969x_serdes_cmu_get, + } +}; + /* Client lookup function, uses serdes index */ static struct phy *sparx5_serdes_xlate(struct device *dev, const struct of_phandle_args *args) @@ -2521,7 +2635,7 @@ static struct phy *sparx5_serdes_xlate(struct device *dev, sidx = args->args[0]; /* Check validity: ERR_PTR(-ENODEV) if not valid */ - for (idx = 0; idx < SPX5_SERDES_MAX; idx++) { + for (idx = 0; idx < priv->data->consts.sd_max; idx++) { struct sparx5_serdes_macro *macro = phy_get_drvdata(priv->phys[idx]); @@ -2555,6 +2669,12 @@ static int sparx5_serdes_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); priv->dev = &pdev->dev; + priv->data = device_get_match_data(priv->dev); + if (!priv->data) + return -EINVAL; + + tsize = priv->data->tsize; + /* Get coreclock */ clk = devm_clk_get(priv->dev, NULL); if (IS_ERR(clk)) { @@ -2579,19 +2699,21 @@ static int sparx5_serdes_probe(struct platform_device *pdev) iores->name); return -ENOMEM; } - for (idx = 0; idx < ARRAY_SIZE(sparx5_serdes_iomap); idx++) { - struct sparx5_serdes_io_resource *iomap = &sparx5_serdes_iomap[idx]; + for (idx = 0; idx < priv->data->iomap_size; idx++) { + const struct sparx5_serdes_io_resource *iomap = + &priv->data->iomap[idx]; priv->regs[iomap->id] = iomem + iomap->offset; } - for (idx = 0; idx < SPX5_SERDES_MAX; idx++) { + for (idx = 0; idx < priv->data->consts.sd_max; idx++) { err = sparx5_phy_create(priv, idx, &priv->phys[idx]); if (err) return err; } - /* Power down all CMUs by default */ - sparx5_serdes_cmu_power_off(priv); + /* Power down all CMU's by default */ + if (priv->data->type == SPX5_TARGET_SPARX5) + sparx5_serdes_cmu_power_off(priv); provider = devm_of_phy_provider_register(priv->dev, sparx5_serdes_xlate); @@ -2599,7 +2721,8 @@ static int sparx5_serdes_probe(struct platform_device *pdev) } static const struct of_device_id sparx5_serdes_match[] = { - { .compatible = "microchip,sparx5-serdes" }, + { .compatible = "microchip,sparx5-serdes", .data = &sparx5_desc }, + { .compatible = "microchip,lan9691-serdes", .data = &lan969x_desc }, { } }; MODULE_DEVICE_TABLE(of, sparx5_serdes_match); diff --git a/drivers/phy/microchip/sparx5_serdes.h b/drivers/phy/microchip/sparx5_serdes.h index 13f94a29225a40..d7093d0b09c0ca 100644 --- a/drivers/phy/microchip/sparx5_serdes.h +++ b/drivers/phy/microchip/sparx5_serdes.h @@ -26,11 +26,18 @@ enum sparx5_serdes_mode { SPX5_SD_MODE_SFI, }; -struct sparx5_serdes_private { - struct device *dev; - void __iomem *regs[NUM_TARGETS]; - struct phy *phys[SPX5_SERDES_MAX]; - unsigned long coreclock; +enum sparx5_10g28cmu_mode { + SPX5_SD10G28_CMU_MAIN = 0, + SPX5_SD10G28_CMU_AUX1 = 1, + SPX5_SD10G28_CMU_AUX2 = 3, + SPX5_SD10G28_CMU_NONE = 4, + SPX5_SD10G28_CMU_MAX, +}; + +enum sparx5_target { + SPX5_TARGET_SPARX5, + SPX5_TARGET_LAN969X, + }; struct sparx5_serdes_macro { @@ -44,6 +51,33 @@ struct sparx5_serdes_macro { enum phy_media media; }; +struct sparx5_serdes_consts { + int sd_max; + int cmu_max; +}; + +struct sparx5_serdes_ops { + void (*serdes_type_set)(struct sparx5_serdes_macro *macro, int sidx); + int (*serdes_cmu_get)(enum sparx5_10g28cmu_mode mode, int sd_index); +}; + +struct sparx5_serdes_match_data { + enum sparx5_target type; + const struct sparx5_serdes_consts consts; + const struct sparx5_serdes_ops ops; + const struct sparx5_serdes_io_resource *iomap; + int iomap_size; + const unsigned int *tsize; +}; + +struct sparx5_serdes_private { + struct device *dev; + void __iomem *regs[NUM_TARGETS]; + struct phy *phys[SPX5_SERDES_MAX]; + unsigned long coreclock; + const struct sparx5_serdes_match_data *data; +}; + /* Read, Write and modify registers content. * The register definition macros start at the id */ diff --git a/drivers/phy/microchip/sparx5_serdes_regs.h b/drivers/phy/microchip/sparx5_serdes_regs.h index d0543fd3dc94d2..11c4fdc593fade 100644 --- a/drivers/phy/microchip/sparx5_serdes_regs.h +++ b/drivers/phy/microchip/sparx5_serdes_regs.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0+ * Microchip Sparx5 SerDes driver * - * Copyright (c) 2020 Microchip Technology Inc. + * Copyright (c) 2024 Microchip Technology Inc. */ -/* This file is autogenerated by cml-utils 2020-11-16 13:11:27 +0100. - * Commit ID: 13bdf073131d8bf40c54901df6988ae4e9c8f29f +/* This file is autogenerated by cml-utils 2023-04-13 15:02:00 +0200. + * Commit ID: 5ac560288d46048f872ecdb8add53717f1efc0e1 */ #ifndef _SPARX5_SERDES_REGS_H_ @@ -26,10 +26,25 @@ enum sparx5_serdes_target { NUM_TARGETS = 332 }; +enum sparx5_serdes_tsize_enum { + TC_SD10G_LANE, + TC_SD_CMU, + TC_SD_CMU_CFG, + TC_SD_LANE, + TSIZE_LAST, +}; + +/* sparx5_serdes.c */ +extern const unsigned int *tsize; + +#define TSIZE(o) tsize[o] + #define __REG(...) __VA_ARGS__ -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_01 */ -#define SD10G_LANE_LANE_01(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 4, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_01 */ +#define SD10G_LANE_LANE_01(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 4, 0, \ + 1, 4) #define SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_SET(x)\ @@ -49,8 +64,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_01_CFG_RXDET_STR_GET(x)\ FIELD_GET(SD10G_LANE_LANE_01_CFG_RXDET_STR, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_02 */ -#define SD10G_LANE_LANE_02(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 8, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_02 */ +#define SD10G_LANE_LANE_02(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 8, 0, \ + 1, 4) #define SD10G_LANE_LANE_02_CFG_EN_ADV BIT(0) #define SD10G_LANE_LANE_02_CFG_EN_ADV_SET(x)\ @@ -82,8 +99,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_03 */ -#define SD10G_LANE_LANE_03(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 12, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_03 */ +#define SD10G_LANE_LANE_03(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 12, 0, \ + 1, 4) #define SD10G_LANE_LANE_03_CFG_TAP_MAIN BIT(0) #define SD10G_LANE_LANE_03_CFG_TAP_MAIN_SET(x)\ @@ -91,8 +110,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_03_CFG_TAP_MAIN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_03_CFG_TAP_MAIN, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_04 */ -#define SD10G_LANE_LANE_04(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 16, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_04 */ +#define SD10G_LANE_LANE_04(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 16, 0, \ + 1, 4) #define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0 GENMASK(4, 0) #define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_SET(x)\ @@ -100,8 +121,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_06 */ -#define SD10G_LANE_LANE_06(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 24, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_06 */ +#define SD10G_LANE_LANE_06(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 24, 0, \ + 1, 4) #define SD10G_LANE_LANE_06_CFG_PD_DRIVER BIT(0) #define SD10G_LANE_LANE_06_CFG_PD_DRIVER_SET(x)\ @@ -139,8 +162,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_06_CFG_EN_PREEMPH_GET(x)\ FIELD_GET(SD10G_LANE_LANE_06_CFG_EN_PREEMPH, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0B */ -#define SD10G_LANE_LANE_0B(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 44, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0B */ +#define SD10G_LANE_LANE_0B(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 44, 0, \ + 1, 4) #define SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_SET(x)\ @@ -172,8 +197,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0C */ -#define SD10G_LANE_LANE_0C(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 48, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0C */ +#define SD10G_LANE_LANE_0C(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 48, 0, \ + 1, 4) #define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE BIT(0) #define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_SET(x)\ @@ -223,8 +250,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0D */ -#define SD10G_LANE_LANE_0D(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 52, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0D */ +#define SD10G_LANE_LANE_0D(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 52, 0, \ + 1, 4) #define SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0_SET(x)\ @@ -238,8 +267,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0D_CFG_EQR_BYP_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0D_CFG_EQR_BYP, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0E */ -#define SD10G_LANE_LANE_0E(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 56, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0E */ +#define SD10G_LANE_LANE_0E(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 56, 0, \ + 1, 4) #define SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_SET(x)\ @@ -265,8 +296,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0F */ -#define SD10G_LANE_LANE_0F(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 60, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0F */ +#define SD10G_LANE_LANE_0F(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 60, 0, \ + 1, 4) #define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0 GENMASK(7, 0) #define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_SET(x)\ @@ -274,8 +307,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_13 */ -#define SD10G_LANE_LANE_13(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 76, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_13 */ +#define SD10G_LANE_LANE_13(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 76, 0, \ + 1, 4) #define SD10G_LANE_LANE_13_CFG_DCDR_PD BIT(0) #define SD10G_LANE_LANE_13_CFG_DCDR_PD_SET(x)\ @@ -295,8 +330,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_13_CFG_CDRCK_EN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_13_CFG_CDRCK_EN, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_14 */ -#define SD10G_LANE_LANE_14(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 80, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_14 */ +#define SD10G_LANE_LANE_14(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 80, 0, \ + 1, 4) #define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0 GENMASK(7, 0) #define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_SET(x)\ @@ -304,8 +341,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_15 */ -#define SD10G_LANE_LANE_15(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 84, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_15 */ +#define SD10G_LANE_LANE_15(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 84, 0, \ + 1, 4) #define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8 GENMASK(7, 0) #define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_SET(x)\ @@ -313,8 +352,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_GET(x)\ FIELD_GET(SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_16 */ -#define SD10G_LANE_LANE_16(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 88, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_16 */ +#define SD10G_LANE_LANE_16(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 88, 0, \ + 1, 4) #define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16 GENMASK(7, 0) #define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_SET(x)\ @@ -322,8 +363,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_GET(x)\ FIELD_GET(SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_1A */ -#define SD10G_LANE_LANE_1A(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 104, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_1A */ +#define SD10G_LANE_LANE_1A(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 104, 0,\ + 1, 4) #define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN BIT(0) #define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN_SET(x)\ @@ -355,8 +398,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_22 */ -#define SD10G_LANE_LANE_22(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 136, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_22 */ +#define SD10G_LANE_LANE_22(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 136, 0,\ + 1, 4) #define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1 GENMASK(4, 0) #define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_SET(x)\ @@ -364,8 +409,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_GET(x)\ FIELD_GET(SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_23 */ -#define SD10G_LANE_LANE_23(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 140, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_23 */ +#define SD10G_LANE_LANE_23(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 140, 0,\ + 1, 4) #define SD10G_LANE_LANE_23_CFG_DFE_PD BIT(0) #define SD10G_LANE_LANE_23_CFG_DFE_PD_SET(x)\ @@ -397,8 +444,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_24 */ -#define SD10G_LANE_LANE_24(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 144, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_24 */ +#define SD10G_LANE_LANE_24(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 144, 0,\ + 1, 4) #define SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_SET(x)\ @@ -412,8 +461,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_26 */ -#define SD10G_LANE_LANE_26(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 152, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_26 */ +#define SD10G_LANE_LANE_26(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 152, 0,\ + 1, 4) #define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0 GENMASK(7, 0) #define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_SET(x)\ @@ -421,8 +472,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_2F */ -#define SD10G_LANE_LANE_2F(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 188, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_2F */ +#define SD10G_LANE_LANE_2F(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 188, 0,\ + 1, 4) #define SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_SET(x)\ @@ -436,8 +489,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_30 */ -#define SD10G_LANE_LANE_30(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 192, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_30 */ +#define SD10G_LANE_LANE_30(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 192, 0,\ + 1, 4) #define SD10G_LANE_LANE_30_CFG_SUMMER_EN BIT(0) #define SD10G_LANE_LANE_30_CFG_SUMMER_EN_SET(x)\ @@ -451,8 +506,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_31 */ -#define SD10G_LANE_LANE_31(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 196, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_31 */ +#define SD10G_LANE_LANE_31(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 196, 0,\ + 1, 4) #define SD10G_LANE_LANE_31_CFG_PI_RSTN BIT(0) #define SD10G_LANE_LANE_31_CFG_PI_RSTN_SET(x)\ @@ -490,8 +547,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_31_CFG_R50_EN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_31_CFG_R50_EN, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_32 */ -#define SD10G_LANE_LANE_32(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 200, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_32 */ +#define SD10G_LANE_LANE_32(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 200, 0,\ + 1, 4) #define SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0_SET(x)\ @@ -505,8 +564,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_33 */ -#define SD10G_LANE_LANE_33(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 204, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_33 */ +#define SD10G_LANE_LANE_33(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 204, 0,\ + 1, 4) #define SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_SET(x)\ @@ -520,8 +581,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_35 */ -#define SD10G_LANE_LANE_35(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 212, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_35 */ +#define SD10G_LANE_LANE_35(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 212, 0,\ + 1, 4) #define SD10G_LANE_LANE_35_CFG_TXRATE_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_35_CFG_TXRATE_1_0_SET(x)\ @@ -535,8 +598,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_35_CFG_RXRATE_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_35_CFG_RXRATE_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_36 */ -#define SD10G_LANE_LANE_36(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 216, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_36 */ +#define SD10G_LANE_LANE_36(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 216, 0,\ + 1, 4) #define SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_SET(x)\ @@ -568,8 +633,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_36_CFG_PRBS_SETB_GET(x)\ FIELD_GET(SD10G_LANE_LANE_36_CFG_PRBS_SETB, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_37 */ -#define SD10G_LANE_LANE_37(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 220, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_37 */ +#define SD10G_LANE_LANE_37(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 220, 0,\ + 1, 4) #define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD BIT(0) #define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD_SET(x)\ @@ -595,8 +662,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_39 */ -#define SD10G_LANE_LANE_39(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 228, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_39 */ +#define SD10G_LANE_LANE_39(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 228, 0,\ + 1, 4) #define SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0_SET(x)\ @@ -610,8 +679,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_39_CFG_RX_SSC_LH_GET(x)\ FIELD_GET(SD10G_LANE_LANE_39_CFG_RX_SSC_LH, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3A */ -#define SD10G_LANE_LANE_3A(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 232, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3A */ +#define SD10G_LANE_LANE_3A(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 232, 0,\ + 1, 4) #define SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0_SET(x)\ @@ -625,8 +696,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3C */ -#define SD10G_LANE_LANE_3C(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 240, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3C */ +#define SD10G_LANE_LANE_3C(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 240, 0,\ + 1, 4) #define SD10G_LANE_LANE_3C_CFG_DIS_ACC BIT(0) #define SD10G_LANE_LANE_3C_CFG_DIS_ACC_SET(x)\ @@ -640,8 +713,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_GET(x)\ FIELD_GET(SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_40 */ -#define SD10G_LANE_LANE_40(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 256, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_40 */ +#define SD10G_LANE_LANE_40(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 256, 0,\ + 1, 4) #define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0 GENMASK(7, 0) #define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_SET(x)\ @@ -649,8 +724,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_41 */ -#define SD10G_LANE_LANE_41(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 260, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_41 */ +#define SD10G_LANE_LANE_41(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 260, 0,\ + 1, 4) #define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8 GENMASK(7, 0) #define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_SET(x)\ @@ -658,8 +735,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_GET(x)\ FIELD_GET(SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_42 */ -#define SD10G_LANE_LANE_42(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 264, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_42 */ +#define SD10G_LANE_LANE_42(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 264, 0,\ + 1, 4) #define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_SET(x)\ @@ -673,8 +752,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_48 */ -#define SD10G_LANE_LANE_48(t) __REG(TARGET_SD10G_LANE, t, 12, 288, 0, 1, 40, 0, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_48 */ +#define SD10G_LANE_LANE_48(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 288, 0, 1, 40, 0, 0, \ + 1, 4) #define SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_SET(x)\ @@ -694,8 +775,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_48_CFG_CLK_ENQ_GET(x)\ FIELD_GET(SD10G_LANE_LANE_48_CFG_CLK_ENQ, x) -/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_50 */ -#define SD10G_LANE_LANE_50(t) __REG(TARGET_SD10G_LANE, t, 12, 288, 0, 1, 40, 32, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_50 */ +#define SD10G_LANE_LANE_50(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 288, 0, 1, 40, 32, 0,\ + 1, 4) #define SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0_SET(x)\ @@ -727,8 +810,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_50_CFG_JT_EN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_50_CFG_JT_EN, x) -/* SD10G_LANE_TARGET:LANE_GRP_2:LANE_52 */ -#define SD10G_LANE_LANE_52(t) __REG(TARGET_SD10G_LANE, t, 12, 328, 0, 1, 24, 0, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_2:LANE_52 */ +#define SD10G_LANE_LANE_52(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 328, 0, 1, 24, 0, 0, \ + 1, 4) #define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0 GENMASK(5, 0) #define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_SET(x)\ @@ -736,8 +821,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_4:LANE_83 */ -#define SD10G_LANE_LANE_83(t) __REG(TARGET_SD10G_LANE, t, 12, 464, 0, 1, 112, 60, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_4:LANE_83 */ +#define SD10G_LANE_LANE_83(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 464, 0, 1, 112, 60, \ + 0, 1, 4) #define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE BIT(0) #define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE_SET(x)\ @@ -781,8 +868,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_83_R_CTLE_RSTN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_83_R_CTLE_RSTN, x) -/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_93 */ -#define SD10G_LANE_LANE_93(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 12, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_93 */ +#define SD10G_LANE_LANE_93(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 576, 0, 1, 64, 12, 0,\ + 1, 4) #define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN BIT(0) #define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN_SET(x)\ @@ -832,8 +921,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT_GET(x)\ FIELD_GET(SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT, x) -/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_94 */ -#define SD10G_LANE_LANE_94(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 16, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_94 */ +#define SD10G_LANE_LANE_94(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 576, 0, 1, 64, 16, 0,\ + 1, 4) #define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_SET(x)\ @@ -865,8 +956,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_94_R_SWING_REG_GET(x)\ FIELD_GET(SD10G_LANE_LANE_94_R_SWING_REG, x) -/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_9E */ -#define SD10G_LANE_LANE_9E(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 56, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_9E */ +#define SD10G_LANE_LANE_9E(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 576, 0, 1, 64, 56, 0,\ + 1, 4) #define SD10G_LANE_LANE_9E_R_RXEQ_REG BIT(0) #define SD10G_LANE_LANE_9E_R_RXEQ_REG_SET(x)\ @@ -886,8 +979,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, x) -/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A1 */ -#define SD10G_LANE_LANE_A1(t) __REG(TARGET_SD10G_LANE, t, 12, 640, 0, 1, 128, 4, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A1 */ +#define SD10G_LANE_LANE_A1(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 640, 0, 1, 128, 4, 0,\ + 1, 4) #define SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0_SET(x)\ @@ -919,8 +1014,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_A1_R_PCLK_GATING_GET(x)\ FIELD_GET(SD10G_LANE_LANE_A1_R_PCLK_GATING, x) -/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A2 */ -#define SD10G_LANE_LANE_A2(t) __REG(TARGET_SD10G_LANE, t, 12, 640, 0, 1, 128, 8, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A2 */ +#define SD10G_LANE_LANE_A2(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 640, 0, 1, 128, 8, 0,\ + 1, 4) #define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0 GENMASK(4, 0) #define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_SET(x)\ @@ -928,8 +1025,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ -#define SD10G_LANE_LANE_DF(t) __REG(TARGET_SD10G_LANE, t, 12, 832, 0, 1, 84, 60, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ +#define SD10G_LANE_LANE_DF(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 832, 0, 1, 84, 60, 0,\ + 1, 4) #define SD10G_LANE_LANE_DF_LOL_UDL BIT(0) #define SD10G_LANE_LANE_DF_LOL_UDL_SET(x)\ @@ -955,8 +1054,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_DF_SQUELCH_GET(x)\ FIELD_GET(SD10G_LANE_LANE_DF_SQUELCH, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_09 */ -#define SD25G_LANE_CMU_09(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 36, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_09 */ +#define SD25G_LANE_CMU_09(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 36, 0, 1, 4) #define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN BIT(0) #define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN_SET(x)\ @@ -988,8 +1089,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_0B */ -#define SD25G_LANE_CMU_0B(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 44, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_0B */ +#define SD25G_LANE_CMU_0B(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 44, 0, 1, 4) #define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT BIT(0) #define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT_SET(x)\ @@ -1039,8 +1142,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_GET(x)\ FIELD_GET(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_0C */ -#define SD25G_LANE_CMU_0C(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 48, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_0C */ +#define SD25G_LANE_CMU_0C(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 48, 0, 1, 4) #define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET BIT(0) #define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_SET(x)\ @@ -1072,8 +1177,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_0D */ -#define SD25G_LANE_CMU_0D(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 52, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_0D */ +#define SD25G_LANE_CMU_0D(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 52, 0, 1, 4) #define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD BIT(0) #define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD_SET(x)\ @@ -1105,8 +1212,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_0E */ -#define SD25G_LANE_CMU_0E(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 56, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_0E */ +#define SD25G_LANE_CMU_0E(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 56, 0, 1, 4) #define SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0 GENMASK(3, 0) #define SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_SET(x)\ @@ -1120,8 +1229,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD_GET(x)\ FIELD_GET(SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_13 */ -#define SD25G_LANE_CMU_13(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 76, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_13 */ +#define SD25G_LANE_CMU_13(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 76, 0, 1, 4) #define SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0 GENMASK(3, 0) #define SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_SET(x)\ @@ -1135,8 +1246,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_13_CFG_JT_EN_GET(x)\ FIELD_GET(SD25G_LANE_CMU_13_CFG_JT_EN, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_18 */ -#define SD25G_LANE_CMU_18(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 96, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_18 */ +#define SD25G_LANE_CMU_18(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 96, 0, 1, 4) #define SD25G_LANE_CMU_18_R_PLL_RSTN BIT(0) #define SD25G_LANE_CMU_18_R_PLL_RSTN_SET(x)\ @@ -1162,8 +1275,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_19 */ -#define SD25G_LANE_CMU_19(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 100, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_19 */ +#define SD25G_LANE_CMU_19(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 100, 0, 1, 4) #define SD25G_LANE_CMU_19_R_CK_RESETB BIT(0) #define SD25G_LANE_CMU_19_R_CK_RESETB_SET(x)\ @@ -1177,8 +1292,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_19_R_PLL_DLOL_EN_GET(x)\ FIELD_GET(SD25G_LANE_CMU_19_R_PLL_DLOL_EN, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_1A */ -#define SD25G_LANE_CMU_1A(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 104, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_1A */ +#define SD25G_LANE_CMU_1A(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 104, 0, 1, 4) #define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0 GENMASK(2, 0) #define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_SET(x)\ @@ -1204,8 +1321,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_1A_R_REG_MANUAL_GET(x)\ FIELD_GET(SD25G_LANE_CMU_1A_R_REG_MANUAL, x) -/* SD25G_TARGET:CMU_GRP_1:CMU_2A */ -#define SD25G_LANE_CMU_2A(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 36, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_1:CMU_2A */ +#define SD25G_LANE_CMU_2A(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 36, 0, 1, 4) #define SD25G_LANE_CMU_2A_R_DBG_SEL_1_0 GENMASK(1, 0) #define SD25G_LANE_CMU_2A_R_DBG_SEL_1_0_SET(x)\ @@ -1225,8 +1344,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_GET(x)\ FIELD_GET(SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, x) -/* SD25G_TARGET:CMU_GRP_1:CMU_30 */ -#define SD25G_LANE_CMU_30(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 60, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_1:CMU_30 */ +#define SD25G_LANE_CMU_30(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 60, 0, 1, 4) #define SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0 GENMASK(2, 0) #define SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_SET(x)\ @@ -1240,8 +1361,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, x) -/* SD25G_TARGET:CMU_GRP_1:CMU_31 */ -#define SD25G_LANE_CMU_31(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 64, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_1:CMU_31 */ +#define SD25G_LANE_CMU_31(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 64, 0, 1, 4) #define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0 GENMASK(7, 0) #define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_SET(x)\ @@ -1249,8 +1372,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, x) -/* SD25G_TARGET:CMU_GRP_2:CMU_40 */ -#define SD25G_LANE_CMU_40(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_2:CMU_40 */ +#define SD25G_LANE_CMU_40(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 0, 0, 1, 4) #define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL BIT(0) #define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL_SET(x)\ @@ -1288,8 +1413,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST_GET(x)\ FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST, x) -/* SD25G_TARGET:CMU_GRP_2:CMU_45 */ -#define SD25G_LANE_CMU_45(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 20, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_2:CMU_45 */ +#define SD25G_LANE_CMU_45(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 20, 0, 1, 4) #define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0 GENMASK(7, 0) #define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_SET(x)\ @@ -1297,8 +1424,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, x) -/* SD25G_TARGET:CMU_GRP_2:CMU_46 */ -#define SD25G_LANE_CMU_46(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 24, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_2:CMU_46 */ +#define SD25G_LANE_CMU_46(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 24, 0, 1, 4) #define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8 GENMASK(7, 0) #define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_SET(x)\ @@ -1306,8 +1435,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_GET(x)\ FIELD_GET(SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, x) -/* SD25G_TARGET:CMU_GRP_3:CMU_C0 */ -#define SD25G_LANE_CMU_C0(t) __REG(TARGET_SD25G_LANE, t, 8, 768, 0, 1, 252, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_3:CMU_C0 */ +#define SD25G_LANE_CMU_C0(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 768, 0, 1, 252, 0, 0, 1, 4) #define SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0 GENMASK(3, 0) #define SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0_SET(x)\ @@ -1321,8 +1452,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_C0_PLL_LOL_UDL_GET(x)\ FIELD_GET(SD25G_LANE_CMU_C0_PLL_LOL_UDL, x) -/* SD25G_TARGET:CMU_GRP_4:CMU_FF */ -#define SD25G_LANE_CMU_FF(t) __REG(TARGET_SD25G_LANE, t, 8, 1020, 0, 1, 4, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_4:CMU_FF */ +#define SD25G_LANE_CMU_FF(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1020, 0, 1, 4, 0, 0, 1, 4) #define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX GENMASK(7, 0) #define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(x)\ @@ -1330,8 +1463,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_GET(x)\ FIELD_GET(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_00 */ -#define SD25G_LANE_LANE_00(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_00 */ +#define SD25G_LANE_LANE_00(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 0, 0, 1, 4) #define SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0_SET(x)\ @@ -1345,8 +1480,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_01 */ -#define SD25G_LANE_LANE_01(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_01 */ +#define SD25G_LANE_LANE_01(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 4, 0, 1, 4) #define SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_SET(x)\ @@ -1360,8 +1497,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_03 */ -#define SD25G_LANE_LANE_03(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 12, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_03 */ +#define SD25G_LANE_LANE_03(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 12, 0, 1, 4) #define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0 GENMASK(4, 0) #define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_SET(x)\ @@ -1369,8 +1508,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_04 */ -#define SD25G_LANE_LANE_04(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 16, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_04 */ +#define SD25G_LANE_LANE_04(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 16, 0, 1, 4) #define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN BIT(0) #define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_SET(x)\ @@ -1408,8 +1549,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN_GET(x)\ FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_05 */ -#define SD25G_LANE_LANE_05(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 20, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_05 */ +#define SD25G_LANE_LANE_05(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 20, 0, 1, 4) #define SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0_SET(x)\ @@ -1423,8 +1566,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_05_LN_CFG_BW_1_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_05_LN_CFG_BW_1_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_06 */ -#define SD25G_LANE_LANE_06(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 24, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_06 */ +#define SD25G_LANE_LANE_06(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 24, 0, 1, 4) #define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN BIT(0) #define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN_SET(x)\ @@ -1438,8 +1583,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_07 */ -#define SD25G_LANE_LANE_07(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 28, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_07 */ +#define SD25G_LANE_LANE_07(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 28, 0, 1, 4) #define SD25G_LANE_LANE_07_LN_CFG_EN_ADV BIT(0) #define SD25G_LANE_LANE_07_LN_CFG_EN_ADV_SET(x)\ @@ -1459,8 +1606,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_07_LN_CFG_EN_DLY_GET(x)\ FIELD_GET(SD25G_LANE_LANE_07_LN_CFG_EN_DLY, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_09 */ -#define SD25G_LANE_LANE_09(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 36, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_09 */ +#define SD25G_LANE_LANE_09(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 36, 0, 1, 4) #define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_SET(x)\ @@ -1468,8 +1617,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0A */ -#define SD25G_LANE_LANE_0A(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 40, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0A */ +#define SD25G_LANE_LANE_0A(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 40, 0, 1, 4) #define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0 GENMASK(5, 0) #define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_SET(x)\ @@ -1477,8 +1628,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0B */ -#define SD25G_LANE_LANE_0B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 44, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0B */ +#define SD25G_LANE_LANE_0B(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 44, 0, 1, 4) #define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN BIT(0) #define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_SET(x)\ @@ -1498,8 +1651,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0C */ -#define SD25G_LANE_LANE_0C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 48, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0C */ +#define SD25G_LANE_LANE_0C(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 48, 0, 1, 4) #define SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_SET(x)\ @@ -1519,8 +1674,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0D */ -#define SD25G_LANE_LANE_0D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 52, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0D */ +#define SD25G_LANE_LANE_0D(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 52, 0, 1, 4) #define SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_SET(x)\ @@ -1552,8 +1709,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0E */ -#define SD25G_LANE_LANE_0E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 56, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0E */ +#define SD25G_LANE_LANE_0E(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 56, 0, 1, 4) #define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN BIT(0) #define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN_SET(x)\ @@ -1579,8 +1738,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0F */ -#define SD25G_LANE_LANE_0F(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 60, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0F */ +#define SD25G_LANE_LANE_0F(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 60, 0, 1, 4) #define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1 GENMASK(4, 0) #define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_SET(x)\ @@ -1588,8 +1749,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_18 */ -#define SD25G_LANE_LANE_18(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 96, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_18 */ +#define SD25G_LANE_LANE_18(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 96, 0, 1, 4) #define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN BIT(0) #define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_SET(x)\ @@ -1621,8 +1784,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_19 */ -#define SD25G_LANE_LANE_19(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 100, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_19 */ +#define SD25G_LANE_LANE_19(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 100, 0, 1, 4) #define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD BIT(0) #define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD_SET(x)\ @@ -1672,8 +1837,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_19_LN_CFG_PD_CTLE_GET(x)\ FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_PD_CTLE, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1A */ -#define SD25G_LANE_LANE_1A(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 104, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1A */ +#define SD25G_LANE_LANE_1A(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 104, 0, 1, 4) #define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN BIT(0) #define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN_SET(x)\ @@ -1687,8 +1854,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1B */ -#define SD25G_LANE_LANE_1B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 108, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1B */ +#define SD25G_LANE_LANE_1B(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 108, 0, 1, 4) #define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0 GENMASK(7, 0) #define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_SET(x)\ @@ -1696,8 +1865,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1C */ -#define SD25G_LANE_LANE_1C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 112, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1C */ +#define SD25G_LANE_LANE_1C(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 112, 0, 1, 4) #define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN BIT(0) #define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(x)\ @@ -1723,8 +1894,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1D */ -#define SD25G_LANE_LANE_1D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 116, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1D */ +#define SD25G_LANE_LANE_1D(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 116, 0, 1, 4) #define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR BIT(0) #define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR_SET(x)\ @@ -1774,8 +1947,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1E */ -#define SD25G_LANE_LANE_1E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 120, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1E */ +#define SD25G_LANE_LANE_1E(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 120, 0, 1, 4) #define SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0 GENMASK(1, 0) #define SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0_SET(x)\ @@ -1807,8 +1982,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_21 */ -#define SD25G_LANE_LANE_21(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 132, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_21 */ +#define SD25G_LANE_LANE_21(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 132, 0, 1, 4) #define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0 GENMASK(4, 0) #define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_SET(x)\ @@ -1816,8 +1993,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_22 */ -#define SD25G_LANE_LANE_22(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 136, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_22 */ +#define SD25G_LANE_LANE_22(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 136, 0, 1, 4) #define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_SET(x)\ @@ -1825,8 +2004,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_25 */ -#define SD25G_LANE_LANE_25(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 148, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_25 */ +#define SD25G_LANE_LANE_25(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 148, 0, 1, 4) #define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0 GENMASK(6, 0) #define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_SET(x)\ @@ -1834,8 +2015,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_26 */ -#define SD25G_LANE_LANE_26(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 152, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_26 */ +#define SD25G_LANE_LANE_26(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 152, 0, 1, 4) #define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0 GENMASK(6, 0) #define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_SET(x)\ @@ -1843,8 +2026,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_28 */ -#define SD25G_LANE_LANE_28(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 160, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_28 */ +#define SD25G_LANE_LANE_28(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 160, 0, 1, 4) #define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN BIT(0) #define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN_SET(x)\ @@ -1870,8 +2055,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_2B */ -#define SD25G_LANE_LANE_2B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 172, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_2B */ +#define SD25G_LANE_LANE_2B(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 172, 0, 1, 4) #define SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_SET(x)\ @@ -1891,8 +2078,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU_GET(x)\ FIELD_GET(SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_2C */ -#define SD25G_LANE_LANE_2C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 176, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_2C */ +#define SD25G_LANE_LANE_2C(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 176, 0, 1, 4) #define SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_SET(x)\ @@ -1906,8 +2095,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_GET(x)\ FIELD_GET(SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_2D */ -#define SD25G_LANE_LANE_2D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 180, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_2D */ +#define SD25G_LANE_LANE_2D(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 180, 0, 1, 4) #define SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_SET(x)\ @@ -1921,8 +2112,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_2E */ -#define SD25G_LANE_LANE_2E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 184, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_2E */ +#define SD25G_LANE_LANE_2E(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 184, 0, 1, 4) #define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN BIT(0) #define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN_SET(x)\ @@ -1972,8 +2165,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_GET(x)\ FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_40 */ -#define SD25G_LANE_LANE_40(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 256, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_40 */ +#define SD25G_LANE_LANE_40(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 256, 0, 1, 4) #define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE BIT(0) #define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE_SET(x)\ @@ -2017,8 +2212,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_40_LN_R_CTLE_RSTN_GET(x)\ FIELD_GET(SD25G_LANE_LANE_40_LN_R_CTLE_RSTN, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_42 */ -#define SD25G_LANE_LANE_42(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 264, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_42 */ +#define SD25G_LANE_LANE_42(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 264, 0, 1, 4) #define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0 GENMASK(7, 0) #define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_SET(x)\ @@ -2026,8 +2223,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_43 */ -#define SD25G_LANE_LANE_43(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 268, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_43 */ +#define SD25G_LANE_LANE_43(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 268, 0, 1, 4) #define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8 GENMASK(7, 0) #define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_SET(x)\ @@ -2035,8 +2234,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_GET(x)\ FIELD_GET(SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_44 */ -#define SD25G_LANE_LANE_44(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 272, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_44 */ +#define SD25G_LANE_LANE_44(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 272, 0, 1, 4) #define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0 GENMASK(7, 0) #define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_SET(x)\ @@ -2044,8 +2245,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_45 */ -#define SD25G_LANE_LANE_45(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 276, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_45 */ +#define SD25G_LANE_LANE_45(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 276, 0, 1, 4) #define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8 GENMASK(7, 0) #define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_SET(x)\ @@ -2053,8 +2256,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_GET(x)\ FIELD_GET(SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, x) -/* SD25G_TARGET:LANE_GRP_1:LANE_DE */ -#define SD25G_LANE_LANE_DE(t) __REG(TARGET_SD25G_LANE, t, 8, 1792, 0, 1, 128, 120, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_1:LANE_DE */ +#define SD25G_LANE_LANE_DE(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1792, 0, 1, 128, 120, 0, 1, 4) #define SD25G_LANE_LANE_DE_LN_LOL_UDL BIT(0) #define SD25G_LANE_LANE_DE_LN_LOL_UDL_SET(x)\ @@ -2080,8 +2285,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_DE_LN_PMA_RXEI_GET(x)\ FIELD_GET(SD25G_LANE_LANE_DE_LN_PMA_RXEI, x) -/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ -#define SD6G_LANE_LANE_DF(t) __REG(TARGET_SD6G_LANE, t, 13, 832, 0, 1, 84, 60, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ +#define SD6G_LANE_LANE_DF(t) \ + __REG(TARGET_SD6G_LANE, t, 13, 832, 0, 1, 84, 60, 0, 1, 4) #define SD6G_LANE_LANE_DF_LOL_UDL BIT(0) #define SD6G_LANE_LANE_DF_LOL_UDL_SET(x)\ @@ -2107,8 +2314,9 @@ enum sparx5_serdes_target { #define SD6G_LANE_LANE_DF_SQUELCH_GET(x)\ FIELD_GET(SD6G_LANE_LANE_DF_SQUELCH, x) -/* SD10G_CMU_TARGET:CMU_GRP_0:CMU_00 */ -#define SD_CMU_CMU_00(t) __REG(TARGET_SD_CMU, t, 14, 0, 0, 1, 20, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_0:CMU_00 */ +#define SD_CMU_CMU_00(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 0, 0, 1, 20, 0, 0, 1, 4) #define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE BIT(0) #define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE_SET(x)\ @@ -2134,8 +2342,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_GET(x)\ FIELD_GET(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_05 */ -#define SD_CMU_CMU_05(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_05 */ +#define SD_CMU_CMU_05(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 0, 0, 1, 4) #define SD_CMU_CMU_05_CFG_REFCK_TERM_EN BIT(0) #define SD_CMU_CMU_05_CFG_REFCK_TERM_EN_SET(x)\ @@ -2149,9 +2358,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_GET(x)\ FIELD_GET(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_06 */ -#define SD_CMU_CMU_06(t) \ - __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 4, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_06 */ +#define SD_CMU_CMU_06(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 4, 0, 1, 4) #define SD_CMU_CMU_06_CFG_DISLOS BIT(0) #define SD_CMU_CMU_06_CFG_DISLOS_SET(x)\ @@ -2201,9 +2410,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_06_CFG_VCO_CAL_BYP_GET(x)\ FIELD_GET(SD_CMU_CMU_06_CFG_VCO_CAL_BYP, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_08 */ -#define SD_CMU_CMU_08(t) \ - __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 12, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_08 */ +#define SD_CMU_CMU_08(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 12, 0, 1, 4) #define SD_CMU_CMU_08_CFG_VFILT2PAD BIT(0) #define SD_CMU_CMU_08_CFG_VFILT2PAD_SET(x)\ @@ -2235,8 +2444,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN_GET(x)\ FIELD_GET(SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_09 */ -#define SD_CMU_CMU_09(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 16, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_09 */ +#define SD_CMU_CMU_09(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 16, 0, 1, 4) #define SD_CMU_CMU_09_CFG_EN_TX_CK_UP BIT(0) #define SD_CMU_CMU_09_CFG_EN_TX_CK_UP_SET(x)\ @@ -2262,8 +2472,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_09_CFG_SW_10G_GET(x)\ FIELD_GET(SD_CMU_CMU_09_CFG_SW_10G, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_0D */ -#define SD_CMU_CMU_0D(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 32, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_0D */ +#define SD_CMU_CMU_0D(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 32, 0, 1, 4) #define SD_CMU_CMU_0D_CFG_PD_DIV64 BIT(0) #define SD_CMU_CMU_0D_CFG_PD_DIV64_SET(x)\ @@ -2295,8 +2506,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_0D_CFG_REFCK_PD_GET(x)\ FIELD_GET(SD_CMU_CMU_0D_CFG_REFCK_PD, x) -/* SD10G_CMU_TARGET:CMU_GRP_3:CMU_1B */ -#define SD_CMU_CMU_1B(t) __REG(TARGET_SD_CMU, t, 14, 104, 0, 1, 20, 4, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_3:CMU_1B */ +#define SD_CMU_CMU_1B(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 104, 0, 1, 20, 4, 0, 1, 4) #define SD_CMU_CMU_1B_CFG_RESERVE_7_0 GENMASK(7, 0) #define SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(x)\ @@ -2304,8 +2516,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_1B_CFG_RESERVE_7_0_GET(x)\ FIELD_GET(SD_CMU_CMU_1B_CFG_RESERVE_7_0, x) -/* SD10G_CMU_TARGET:CMU_GRP_4:CMU_1F */ -#define SD_CMU_CMU_1F(t) __REG(TARGET_SD_CMU, t, 14, 124, 0, 1, 68, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_4:CMU_1F */ +#define SD_CMU_CMU_1F(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 124, 0, 1, 68, 0, 0, 1, 4) #define SD_CMU_CMU_1F_CFG_BIAS_DN_EN BIT(0) #define SD_CMU_CMU_1F_CFG_BIAS_DN_EN_SET(x)\ @@ -2331,8 +2544,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_1F_CFG_VTUNE_SEL_GET(x)\ FIELD_GET(SD_CMU_CMU_1F_CFG_VTUNE_SEL, x) -/* SD10G_CMU_TARGET:CMU_GRP_5:CMU_30 */ -#define SD_CMU_CMU_30(t) __REG(TARGET_SD_CMU, t, 14, 192, 0, 1, 72, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_5:CMU_30 */ +#define SD_CMU_CMU_30(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 192, 0, 1, 72, 0, 0, 1, 4) #define SD_CMU_CMU_30_R_PLL_DLOL_EN BIT(0) #define SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(x)\ @@ -2340,8 +2554,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_30_R_PLL_DLOL_EN_GET(x)\ FIELD_GET(SD_CMU_CMU_30_R_PLL_DLOL_EN, x) -/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_44 */ -#define SD_CMU_CMU_44(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 8, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_44 */ +#define SD_CMU_CMU_44(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 264, 0, 1, 632, 8, 0, 1, 4) #define SD_CMU_CMU_44_R_PLL_RSTN BIT(0) #define SD_CMU_CMU_44_R_PLL_RSTN_SET(x)\ @@ -2355,8 +2570,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_44_R_CK_RESETB_GET(x)\ FIELD_GET(SD_CMU_CMU_44_R_CK_RESETB, x) -/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_45 */ -#define SD_CMU_CMU_45(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 12, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_45 */ +#define SD_CMU_CMU_45(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 264, 0, 1, 632, 12, 0, 1, 4) #define SD_CMU_CMU_45_R_EN_RATECHG_CTRL BIT(0) #define SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(x)\ @@ -2406,8 +2622,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN_GET(x)\ FIELD_GET(SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN, x) -/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_47 */ -#define SD_CMU_CMU_47(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 20, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_47 */ +#define SD_CMU_CMU_47(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 264, 0, 1, 632, 20, 0, 1, 4) #define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0 GENMASK(4, 0) #define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(x)\ @@ -2415,8 +2632,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_GET(x)\ FIELD_GET(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, x) -/* SD10G_CMU_TARGET:CMU_GRP_7:CMU_E0 */ -#define SD_CMU_CMU_E0(t) __REG(TARGET_SD_CMU, t, 14, 896, 0, 1, 8, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_7:CMU_E0 */ +#define SD_CMU_CMU_E0(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 896, 0, 1, 8, 0, 0, 1, 4) #define SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0 GENMASK(3, 0) #define SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0_SET(x)\ @@ -2430,8 +2648,10 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_E0_PLL_LOL_UDL_GET(x)\ FIELD_GET(SD_CMU_CMU_E0_PLL_LOL_UDL, x) -/* SD_CMU_TARGET:SD_CMU_CFG:SD_CMU_CFG */ -#define SD_CMU_CFG_SD_CMU_CFG(t) __REG(TARGET_SD_CMU_CFG, t, 14, 0, 0, 1, 8, 0, 0, 1, 4) +/* SD_CMU_TARGET:SD_CMU_CFG:SD_CMU_CFG */ +#define SD_CMU_CFG_SD_CMU_CFG(t) \ + __REG(TARGET_SD_CMU_CFG, t, TSIZE(TC_SD_CMU_CFG), 0, 0, 1, 8, 0, 0, 1, \ + 4) #define SD_CMU_CFG_SD_CMU_CFG_CMU_RST BIT(0) #define SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(x)\ @@ -2445,8 +2665,9 @@ enum sparx5_serdes_target { #define SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_GET(x)\ FIELD_GET(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, x) -/* SD_LANE_TARGET:SD_RESET:SD_SER_RST */ -#define SD_LANE_SD_SER_RST(t) __REG(TARGET_SD_LANE, t, 25, 0, 0, 1, 8, 0, 0, 1, 4) +/* SD_LANE_TARGET:SD_RESET:SD_SER_RST */ +#define SD_LANE_SD_SER_RST(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 0, 0, 1, 8, 0, 0, 1, 4) #define SD_LANE_SD_SER_RST_SER_RST BIT(0) #define SD_LANE_SD_SER_RST_SER_RST_SET(x)\ @@ -2454,8 +2675,9 @@ enum sparx5_serdes_target { #define SD_LANE_SD_SER_RST_SER_RST_GET(x)\ FIELD_GET(SD_LANE_SD_SER_RST_SER_RST, x) -/* SD_LANE_TARGET:SD_RESET:SD_DES_RST */ -#define SD_LANE_SD_DES_RST(t) __REG(TARGET_SD_LANE, t, 25, 0, 0, 1, 8, 4, 0, 1, 4) +/* SD_LANE_TARGET:SD_RESET:SD_DES_RST */ +#define SD_LANE_SD_DES_RST(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 0, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_SD_DES_RST_DES_RST BIT(0) #define SD_LANE_SD_DES_RST_DES_RST_SET(x)\ @@ -2463,8 +2685,9 @@ enum sparx5_serdes_target { #define SD_LANE_SD_DES_RST_DES_RST_GET(x)\ FIELD_GET(SD_LANE_SD_DES_RST_DES_RST, x) -/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ -#define SD_LANE_SD_LANE_CFG(t) __REG(TARGET_SD_LANE, t, 25, 8, 0, 1, 8, 0, 0, 1, 4) +/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ +#define SD_LANE_SD_LANE_CFG(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 8, 0, 1, 8, 0, 0, 1, 4) #define SD_LANE_SD_LANE_CFG_MACRO_RST BIT(0) #define SD_LANE_SD_LANE_CFG_MACRO_RST_SET(x)\ @@ -2508,8 +2731,9 @@ enum sparx5_serdes_target { #define SD_LANE_SD_LANE_CFG_LANE_RX_RST_GET(x)\ FIELD_GET(SD_LANE_SD_LANE_CFG_LANE_RX_RST, x) -/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ -#define SD_LANE_SD_LANE_STAT(t) __REG(TARGET_SD_LANE, t, 25, 8, 0, 1, 8, 4, 0, 1, 4) +/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ +#define SD_LANE_SD_LANE_STAT(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 8, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_SD_LANE_STAT_PMA_RST_DONE BIT(0) #define SD_LANE_SD_LANE_STAT_PMA_RST_DONE_SET(x)\ @@ -2529,9 +2753,9 @@ enum sparx5_serdes_target { #define SD_LANE_SD_LANE_STAT_DBG_OBS_GET(x)\ FIELD_GET(SD_LANE_SD_LANE_STAT_DBG_OBS, x) -/* SD_LANE_TARGET:SD_PWR_CFG:QUIET_MODE_6G */ -#define SD_LANE_QUIET_MODE_6G(t) \ - __REG(TARGET_SD_LANE, t, 25, 24, 0, 1, 8, 4, 0, 1, 4) +/* SD_LANE_TARGET:SD_PWR_CFG:QUIET_MODE_6G */ +#define SD_LANE_QUIET_MODE_6G(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 24, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_QUIET_MODE_6G_QUIET_MODE GENMASK(24, 0) #define SD_LANE_QUIET_MODE_6G_QUIET_MODE_SET(x)\ @@ -2539,8 +2763,9 @@ enum sparx5_serdes_target { #define SD_LANE_QUIET_MODE_6G_QUIET_MODE_GET(x)\ FIELD_GET(SD_LANE_QUIET_MODE_6G_QUIET_MODE, x) -/* SD_LANE_TARGET:CFG_STAT_FX100:MISC */ -#define SD_LANE_MISC(t) __REG(TARGET_SD_LANE, t, 25, 56, 0, 1, 56, 0, 0, 1, 4) +/* SD_LANE_TARGET:CFG_STAT_FX100:MISC */ +#define SD_LANE_MISC(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 56, 0, 1, 56, 0, 0, 1, 4) #define SD_LANE_MISC_SD_125_RST_DIS BIT(0) #define SD_LANE_MISC_SD_125_RST_DIS_SET(x)\ @@ -2560,14 +2785,16 @@ enum sparx5_serdes_target { #define SD_LANE_MISC_MUX_ENA_GET(x)\ FIELD_GET(SD_LANE_MISC_MUX_ENA, x) +/* SPARX5 ONLY */ #define SD_LANE_MISC_CORE_CLK_FREQ GENMASK(5, 4) #define SD_LANE_MISC_CORE_CLK_FREQ_SET(x)\ FIELD_PREP(SD_LANE_MISC_CORE_CLK_FREQ, x) #define SD_LANE_MISC_CORE_CLK_FREQ_GET(x)\ FIELD_GET(SD_LANE_MISC_CORE_CLK_FREQ, x) -/* SD_LANE_TARGET:CFG_STAT_FX100:M_STAT_MISC */ -#define SD_LANE_M_STAT_MISC(t) __REG(TARGET_SD_LANE, t, 25, 56, 0, 1, 56, 36, 0, 1, 4) +/* SD_LANE_TARGET:CFG_STAT_FX100:M_STAT_MISC */ +#define SD_LANE_M_STAT_MISC(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 56, 0, 1, 56, 36, 0, 1, 4) #define SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM GENMASK(21, 0) #define SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM_SET(x)\ @@ -2581,8 +2808,10 @@ enum sparx5_serdes_target { #define SD_LANE_M_STAT_MISC_M_LOCK_CNT_GET(x)\ FIELD_GET(SD_LANE_M_STAT_MISC_M_LOCK_CNT, x) -/* SD25G_CFG_TARGET:SD_RESET:SD_SER_RST */ -#define SD_LANE_25G_SD_SER_RST(t) __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_RESET:SD_SER_RST */ +#define SD_LANE_25G_SD_SER_RST(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 0, 0, 1, 4) #define SD_LANE_25G_SD_SER_RST_SER_RST BIT(0) #define SD_LANE_25G_SD_SER_RST_SER_RST_SET(x)\ @@ -2590,8 +2819,10 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_SER_RST_SER_RST_GET(x)\ FIELD_GET(SD_LANE_25G_SD_SER_RST_SER_RST, x) -/* SD25G_CFG_TARGET:SD_RESET:SD_DES_RST */ -#define SD_LANE_25G_SD_DES_RST(t) __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_RESET:SD_DES_RST */ +#define SD_LANE_25G_SD_DES_RST(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_25G_SD_DES_RST_DES_RST BIT(0) #define SD_LANE_25G_SD_DES_RST_DES_RST_SET(x)\ @@ -2599,8 +2830,10 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_DES_RST_DES_RST_GET(x)\ FIELD_GET(SD_LANE_25G_SD_DES_RST_DES_RST, x) -/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ -#define SD_LANE_25G_SD_LANE_CFG(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ +#define SD_LANE_25G_SD_LANE_CFG(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 0, 0, 1, 4) #define SD_LANE_25G_SD_LANE_CFG_MACRO_RST BIT(0) #define SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(x)\ @@ -2698,8 +2931,10 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN_GET(x)\ FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN, x) -/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG2 */ -#define SD_LANE_25G_SD_LANE_CFG2(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG2 */ +#define SD_LANE_25G_SD_LANE_CFG2(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 4, 0, 1, 4) #define SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL GENMASK(2, 0) #define SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL_SET(x)\ @@ -2767,8 +3002,10 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL_GET(x)\ FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL, x) -/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ -#define SD_LANE_25G_SD_LANE_STAT(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 8, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ +#define SD_LANE_25G_SD_LANE_STAT(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 8, 0, 1, 4) #define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE BIT(0) #define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE_SET(x)\ @@ -2788,8 +3025,9 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_GET(x)\ FIELD_GET(SD_LANE_25G_SD_LANE_STAT_DBG_OBS, x) -/* SD25G_CFG_TARGET:SD_PWR_CFG:QUIET_MODE_6G */ -#define SD_LANE_25G_QUIET_MODE_6G(t) \ +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_PWR_CFG:QUIET_MODE_6G */ +#define SD_LANE_25G_QUIET_MODE_6G(t) \ __REG(TARGET_SD_LANE_25G, t, 8, 28, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE GENMASK(24, 0) diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 7bbf729a7c90a9..7cb020dd3423cb 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -704,7 +704,7 @@ static void cpcap_usb_phy_remove(struct platform_device *pdev) static struct platform_driver cpcap_usb_phy_driver = { .probe = cpcap_usb_phy_probe, - .remove_new = cpcap_usb_phy_remove, + .remove = 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 376d023a0aa909..152344e4f7e44d 100644 --- a/drivers/phy/motorola/phy-mapphone-mdm6600.c +++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c @@ -655,7 +655,7 @@ static void phy_mdm6600_remove(struct platform_device *pdev) static struct platform_driver phy_mdm6600_driver = { .probe = phy_mdm6600_probe, - .remove_new = phy_mdm6600_remove, + .remove = phy_mdm6600_remove, .driver = { .name = "phy-mapphone-mdm6600", .pm = &phy_mdm6600_pm_ops, diff --git a/drivers/phy/phy-airoha-pcie-regs.h b/drivers/phy/phy-airoha-pcie-regs.h index bb1f679ca1dfa0..b938a7b468fee3 100644 --- a/drivers/phy/phy-airoha-pcie-regs.h +++ b/drivers/phy/phy-airoha-pcie-regs.h @@ -197,9 +197,9 @@ #define CSR_2L_PXP_TX1_MULTLANE_EN BIT(0) #define REG_CSR_2L_RX0_REV0 0x00fc -#define CSR_2L_PXP_VOS_PNINV GENMASK(3, 2) -#define CSR_2L_PXP_FE_GAIN_NORMAL_MODE GENMASK(6, 4) -#define CSR_2L_PXP_FE_GAIN_TRAIN_MODE GENMASK(10, 8) +#define CSR_2L_PXP_VOS_PNINV GENMASK(19, 18) +#define CSR_2L_PXP_FE_GAIN_NORMAL_MODE GENMASK(22, 20) +#define CSR_2L_PXP_FE_GAIN_TRAIN_MODE GENMASK(26, 24) #define REG_CSR_2L_RX0_PHYCK_DIV 0x0100 #define CSR_2L_PXP_RX0_PHYCK_SEL GENMASK(9, 8) diff --git a/drivers/phy/phy-airoha-pcie.c b/drivers/phy/phy-airoha-pcie.c index 1e410eb410580c..56e9ade8a9fd3d 100644 --- a/drivers/phy/phy-airoha-pcie.c +++ b/drivers/phy/phy-airoha-pcie.c @@ -459,7 +459,7 @@ static void airoha_pcie_phy_init_clk_out(struct airoha_pcie_phy *pcie_phy) airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CLKTX1_OFFSET, CSR_2L_PXP_CLKTX1_SR); airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_PLL_CMN_RESERVE0, - CSR_2L_PXP_PLL_RESERVE_MASK, 0xdd); + CSR_2L_PXP_PLL_RESERVE_MASK, 0xd0d); } static void airoha_pcie_phy_init_csr_2l(struct airoha_pcie_phy *pcie_phy) @@ -471,9 +471,9 @@ static void airoha_pcie_phy_init_csr_2l(struct airoha_pcie_phy *pcie_phy) PCIE_SW_XFI_RXPCS_RST | PCIE_SW_REF_RST | PCIE_SW_RX_RST); airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_TX_RESET, - PCIE_TX_TOP_RST | REG_PCIE_PMA_TX_RESET); + PCIE_TX_TOP_RST | PCIE_TX_CAL_RST); airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_TX_RESET, - PCIE_TX_TOP_RST | REG_PCIE_PMA_TX_RESET); + PCIE_TX_TOP_RST | PCIE_TX_CAL_RST); } static void airoha_pcie_phy_init_rx(struct airoha_pcie_phy *pcie_phy) @@ -802,7 +802,7 @@ static void airoha_pcie_phy_init_ssc_jcpll(struct airoha_pcie_phy *pcie_phy) airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_IFM, CSR_2L_PXP_JCPLL_SDM_IFM); airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN, - REG_CSR_2L_JCPLL_SDM_HREN); + CSR_2L_PXP_JCPLL_SDM_HREN); airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY, CSR_2L_PXP_JCPLL_SDM_DI_EN); airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC, diff --git a/drivers/phy/phy-lgm-usb.c b/drivers/phy/phy-lgm-usb.c index 410729c7f513db..eb7c6fed20d34e 100644 --- a/drivers/phy/phy-lgm-usb.c +++ b/drivers/phy/phy-lgm-usb.c @@ -271,7 +271,7 @@ static struct platform_driver lgm_phy_driver = { .of_match_table = intel_usb_phy_dt_ids, }, .probe = phy_probe, - .remove_new = phy_remove, + .remove = phy_remove, }; module_platform_driver(lgm_phy_driver); diff --git a/drivers/phy/phy-nxp-ptn3222.c b/drivers/phy/phy-nxp-ptn3222.c new file mode 100644 index 00000000000000..c6179d8701e61d --- /dev/null +++ b/drivers/phy/phy-nxp-ptn3222.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include + +#define NUM_SUPPLIES 2 + +struct ptn3222 { + struct i2c_client *client; + struct phy *phy; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; +}; + +static int ptn3222_init(struct phy *phy) +{ + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); + int ret; + + ret = regulator_bulk_enable(NUM_SUPPLIES, ptn3222->supplies); + if (ret) + return ret; + + gpiod_set_value_cansleep(ptn3222->reset_gpio, 0); + + return 0; +} + +static int ptn3222_exit(struct phy *phy) +{ + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); + + gpiod_set_value_cansleep(ptn3222->reset_gpio, 1); + + return regulator_bulk_disable(NUM_SUPPLIES, ptn3222->supplies); +} + +static const struct phy_ops ptn3222_ops = { + .init = ptn3222_init, + .exit = ptn3222_exit, + .owner = THIS_MODULE, +}; + +static const struct regulator_bulk_data ptn3222_supplies[NUM_SUPPLIES] = { + { + .supply = "vdd3v3", + .init_load_uA = 11000, + }, { + .supply = "vdd1v8", + .init_load_uA = 55000, + } +}; + +static int ptn3222_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct phy_provider *phy_provider; + struct ptn3222 *ptn3222; + int ret; + + ptn3222 = devm_kzalloc(dev, sizeof(*ptn3222), GFP_KERNEL); + if (!ptn3222) + return -ENOMEM; + + ptn3222->client = client; + + ptn3222->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ptn3222->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ptn3222->reset_gpio), + "unable to acquire reset gpio\n"); + + ret = devm_regulator_bulk_get_const(dev, NUM_SUPPLIES, ptn3222_supplies, + &ptn3222->supplies); + if (ret) + return ret; + + ptn3222->phy = devm_phy_create(dev, dev->of_node, &ptn3222_ops); + if (IS_ERR(ptn3222->phy)) { + dev_err(dev, "failed to create PHY: %d\n", ret); + return PTR_ERR(ptn3222->phy); + } + + phy_set_drvdata(ptn3222->phy, ptn3222); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct i2c_device_id ptn3222_table[] = { + { "ptn3222" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ptn3222_table); + +static const struct of_device_id ptn3222_of_table[] = { + { .compatible = "nxp,ptn3222" }, + { } +}; +MODULE_DEVICE_TABLE(of, ptn3222_of_table); + +static struct i2c_driver ptn3222_driver = { + .driver = { + .name = "ptn3222", + .of_match_table = ptn3222_of_table, + }, + .probe = ptn3222_probe, + .id_table = ptn3222_table, +}; + +module_i2c_driver(ptn3222_driver); + +MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c index 3642a5d4f2f3b8..cae290a6e19fcb 100644 --- a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c +++ b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c @@ -257,12 +257,12 @@ static const struct of_device_id qcom_apq8064_sata_phy_of_match[] = { 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_new = qcom_apq8064_sata_phy_remove, + .probe = qcom_apq8064_sata_phy_probe, + .remove = qcom_apq8064_sata_phy_remove, .driver = { - .name = "qcom-apq8064-sata-phy", - .of_match_table = qcom_apq8064_sata_phy_of_match, - } + .name = "qcom-apq8064-sata-phy", + .of_match_table = qcom_apq8064_sata_phy_of_match, + }, }; module_platform_driver(qcom_apq8064_sata_phy_driver); diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index da2b32fb5b4511..f1b51018683d51 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -32,16 +32,8 @@ #define DP_PHY_PD_CTL 0x001c #define DP_PHY_MODE 0x0020 -#define DP_PHY_AUX_CFG0 0x0024 -#define DP_PHY_AUX_CFG1 0x0028 -#define DP_PHY_AUX_CFG2 0x002C -#define DP_PHY_AUX_CFG3 0x0030 -#define DP_PHY_AUX_CFG4 0x0034 -#define DP_PHY_AUX_CFG5 0x0038 -#define DP_PHY_AUX_CFG6 0x003C -#define DP_PHY_AUX_CFG7 0x0040 -#define DP_PHY_AUX_CFG8 0x0044 -#define DP_PHY_AUX_CFG9 0x0048 +#define DP_AUX_CFG_SIZE 10 +#define DP_PHY_AUX_CFG(n) (0x24 + (0x04 * (n))) #define DP_PHY_AUX_INTERRUPT_MASK 0x0058 @@ -90,6 +82,7 @@ struct phy_ver_ops { struct qcom_edp_phy_cfg { bool is_edp; + const u8 *aux_cfg; const struct qcom_edp_swing_pre_emph_cfg *swing_pre_emph_cfg; const struct phy_ver_ops *ver_ops; }; @@ -186,11 +179,40 @@ static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg = { .pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3, }; +static const u8 edp_phy_aux_cfg_v4[10] = { + 0x00, 0x13, 0x24, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03 +}; + +static const u8 edp_pre_emp_hbr_rbr_v5[4][4] = { + { 0x05, 0x11, 0x17, 0x1d }, + { 0x05, 0x11, 0x18, 0xff }, + { 0x06, 0x11, 0xff, 0xff }, + { 0x00, 0xff, 0xff, 0xff } +}; + +static const u8 edp_pre_emp_hbr2_hbr3_v5[4][4] = { + { 0x0c, 0x15, 0x19, 0x1e }, + { 0x0b, 0x15, 0x19, 0xff }, + { 0x0e, 0x14, 0xff, 0xff }, + { 0x0d, 0xff, 0xff, 0xff } +}; + +static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg_v5 = { + .swing_hbr_rbr = &edp_swing_hbr_rbr, + .swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3, + .pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr_v5, + .pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3_v5, +}; + +static const u8 edp_phy_aux_cfg_v5[10] = { + 0x00, 0x13, 0xa4, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03 +}; + static int qcom_edp_phy_init(struct phy *phy) { struct qcom_edp *edp = phy_get_drvdata(phy); + u8 aux_cfg[DP_AUX_CFG_SIZE]; int ret; - u8 cfg8; ret = regulator_bulk_enable(ARRAY_SIZE(edp->supplies), edp->supplies); if (ret) @@ -200,6 +222,8 @@ static int qcom_edp_phy_init(struct phy *phy) if (ret) goto out_disable_supplies; + memcpy(aux_cfg, edp->cfg->aux_cfg, sizeof(aux_cfg)); + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, edp->edp + DP_PHY_PD_CTL); @@ -222,22 +246,12 @@ static int qcom_edp_phy_init(struct phy *phy) * even needed. */ if (edp->cfg->swing_pre_emph_cfg && !edp->is_edp) - cfg8 = 0xb7; - else - cfg8 = 0x37; + aux_cfg[8] = 0xb7; writel(0xfc, edp->edp + DP_PHY_MODE); - writel(0x00, edp->edp + DP_PHY_AUX_CFG0); - writel(0x13, edp->edp + DP_PHY_AUX_CFG1); - writel(0x24, edp->edp + DP_PHY_AUX_CFG2); - writel(0x00, edp->edp + DP_PHY_AUX_CFG3); - writel(0x0a, edp->edp + DP_PHY_AUX_CFG4); - writel(0x26, edp->edp + DP_PHY_AUX_CFG5); - writel(0x0a, edp->edp + DP_PHY_AUX_CFG6); - writel(0x03, edp->edp + DP_PHY_AUX_CFG7); - writel(cfg8, edp->edp + DP_PHY_AUX_CFG8); - writel(0x03, edp->edp + DP_PHY_AUX_CFG9); + for (int i = 0; i < DP_AUX_CFG_SIZE; i++) + writel(aux_cfg[i], edp->edp + DP_PHY_AUX_CFG(i)); writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK | @@ -518,17 +532,27 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v4 = { .com_configure_ssc = qcom_edp_com_configure_ssc_v4, }; +static const struct qcom_edp_phy_cfg sa8775p_dp_phy_cfg = { + .is_edp = false, + .aux_cfg = edp_phy_aux_cfg_v5, + .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg_v5, + .ver_ops = &qcom_edp_phy_ops_v4, +}; + static const struct qcom_edp_phy_cfg sc7280_dp_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v4, .ver_ops = &qcom_edp_phy_ops_v4, }; static const struct qcom_edp_phy_cfg sc8280xp_dp_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v4, .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, .ver_ops = &qcom_edp_phy_ops_v4, }; static const struct qcom_edp_phy_cfg sc8280xp_edp_phy_cfg = { .is_edp = true, + .aux_cfg = edp_phy_aux_cfg_v4, .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, .ver_ops = &qcom_edp_phy_ops_v4, }; @@ -707,6 +731,7 @@ static const struct phy_ver_ops qcom_edp_phy_ops_v6 = { }; static struct qcom_edp_phy_cfg x1e80100_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v4, .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, .ver_ops = &qcom_edp_phy_ops_v6, }; @@ -1108,6 +1133,7 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) } static const struct of_device_id qcom_edp_phy_match_table[] = { + { .compatible = "qcom,sa8775p-edp-phy", .data = &sa8775p_dp_phy_cfg, }, { .compatible = "qcom,sc7280-edp-phy", .data = &sc7280_dp_phy_cfg, }, { .compatible = "qcom,sc8180x-edp-phy", .data = &sc7280_dp_phy_cfg, }, { .compatible = "qcom,sc8280xp-dp-phy", .data = &sc8280xp_dp_phy_cfg, }, diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index 68cc8e24f38367..6bd1b3c75c779d 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -294,7 +294,7 @@ MODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table); static struct platform_driver eusb2_repeater_driver = { .probe = eusb2_repeater_probe, - .remove_new = eusb2_repeater_remove, + .remove = 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 f0a72b82c770b5..f5eb0bdac418bb 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c @@ -184,11 +184,11 @@ static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = { 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_new = qcom_ipq806x_sata_phy_remove, + .probe = qcom_ipq806x_sata_phy_probe, + .remove = qcom_ipq806x_sata_phy_remove, .driver = { - .name = "qcom-ipq806x-sata-phy", - .of_match_table = qcom_ipq806x_sata_phy_of_match, + .name = "qcom-ipq806x-sata-phy", + .of_match_table = qcom_ipq806x_sata_phy_of_match, } }; module_platform_driver(qcom_ipq806x_sata_phy_driver); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 643045c9024eaa..3bae39381fd08a 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -3483,7 +3483,7 @@ static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) } #endif -static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_node *np) +static int qmp_combo_parse_dt_legacy_dp(struct qmp_combo *qmp, struct device_node *np) { struct device *dev = qmp->dev; @@ -3510,7 +3510,7 @@ static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_nod return 0; } -static int qmp_combo_parse_dt_lecacy_usb(struct qmp_combo *qmp, struct device_node *np) +static int qmp_combo_parse_dt_legacy_usb(struct qmp_combo *qmp, struct device_node *np) { const struct qmp_phy_cfg *cfg = qmp->cfg; struct device *dev = qmp->dev; @@ -3576,11 +3576,11 @@ static int qmp_combo_parse_dt_legacy(struct qmp_combo *qmp, struct device_node * if (IS_ERR(qmp->dp_serdes)) return PTR_ERR(qmp->dp_serdes); - ret = qmp_combo_parse_dt_lecacy_usb(qmp, usb_np); + ret = qmp_combo_parse_dt_legacy_usb(qmp, usb_np); if (ret) return ret; - ret = qmp_combo_parse_dt_lecacy_dp(qmp, dp_np); + ret = qmp_combo_parse_dt_legacy_dp(qmp, dp_np); if (ret) return ret; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 36aaac34e6c6c3..873f2f9844c66d 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -34,6 +34,8 @@ #include "phy-qcom-qmp-pcs-pcie-v5_20.h" #include "phy-qcom-qmp-pcs-pcie-v6.h" #include "phy-qcom-qmp-pcs-pcie-v6_20.h" +#include "phy-qcom-qmp-pcs-pcie-v6_30.h" +#include "phy-qcom-qmp-pcs-v6_30.h" #include "phy-qcom-qmp-pcie-qhp.h" #define PHY_INIT_COMPLETE_TIMEOUT 10000 @@ -1344,6 +1346,154 @@ static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_FOM_EQ_CONFIG5, 0x8a), }; +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x26), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x68), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE1, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE1, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xf8), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x62), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_POST_DIV_MUX, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_SELECT, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MISC_1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MODE, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_VCO_DC_LEVEL_CTRL, 0x0f), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_ln_shrd_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RXCLK_DIV2_CTRL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_SUMMER_CAL_SPD_MODE, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_DFE_DAC_ENABLE1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B0, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B2, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B3, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B4, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B5, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B6, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_txz_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_TX, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_RX, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_2, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_3, 0x51), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_TRAN_DRVR_EMP_EN, 0x34), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_rxz_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_GAIN_RATE_2, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_3, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_PI_CONTROLS, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_CAL_CTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_POSTCAL_OFFSET, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_BKUP_CTRL1, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_3, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_VGA_CAL_MAN_VAL, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_VGA_CAL_CNTRL1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_GM_CAL, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_PHPRE_CTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x39), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B0, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B1, 0x23), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B2, 0x58), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B3, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B4, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B5, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B6, 0xee), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B0, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B1, 0xe4), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B2, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B3, 0xdf), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B4, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B5, 0x76), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_TX_ADPT_CTRL, 0x10), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG_LANE(QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x3a, BIT(0)), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_LOCK_DETECT_CONFIG2, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_G3S2_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_RX_SIGDET_LVL, 0x99), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_ALIGN_DETECT_CONFIG7, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_EQ_CONFIG4, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_EQ_CONFIG5, 0x22), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_TX_RX_CONFIG, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_TX_RX_CONFIG2, 0x02), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_ENDPOINT_REFCLK_DRIVE, 0xc1), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_OSC_DTCT_ACTIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_EQ_CONFIG1, 0x16), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G4_EQ_CONFIG5, 0x02), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G4_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG1, 0x03), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG3, 0x28), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG5, 0x18), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G3_FOM_EQ_CONFIG5, 0x7a), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G4_FOM_EQ_CONFIG5, 0x8a), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G3_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G4_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_TX_RX_CONFIG, 0xc0), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_POWER_STATE_CONFIG2, 0x1d), +}; + static const struct qmp_phy_init_tbl sm8250_qmp_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08), QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34), @@ -2582,6 +2732,8 @@ struct qmp_pcie_offsets { u16 rx; u16 tx2; u16 rx2; + u16 txz; + u16 rxz; u16 ln_shrd; }; @@ -2592,6 +2744,10 @@ struct qmp_phy_cfg_tbls { int tx_num; const struct qmp_phy_init_tbl *rx; int rx_num; + const struct qmp_phy_init_tbl *txz; + int txz_num; + const struct qmp_phy_init_tbl *rxz; + int rxz_num; const struct qmp_phy_init_tbl *pcs; int pcs_num; const struct qmp_phy_init_tbl *pcs_misc; @@ -2659,6 +2815,8 @@ struct qmp_pcie { void __iomem *rx; void __iomem *tx2; void __iomem *rx2; + void __iomem *txz; + void __iomem *rxz; void __iomem *ln_shrd; void __iomem *port_b; @@ -2826,6 +2984,17 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_20 = { .ln_shrd = 0x0e00, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_30 = { + .serdes = 0x8800, + .pcs = 0x9000, + .pcs_misc = 0x9800, + .tx = 0x0000, + .rx = 0x0200, + .txz = 0xe000, + .rxz = 0xe200, + .ln_shrd = 0x8000, +}; + static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { .lanes = 1, @@ -3704,6 +3873,38 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x4_pciephy_cfg = { .has_nocsr_reset = true, }; +static const struct qmp_phy_cfg x1e80100_qmp_gen4x8_pciephy_cfg = { + .lanes = 8, + + .offsets = &qmp_pcie_offsets_v6_30, + .tbls = { + .serdes = x1e80100_qmp_gen4x8_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_serdes_tbl), + .rx = x1e80100_qmp_gen4x8_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_rx_tbl), + .txz = x1e80100_qmp_gen4x8_pcie_txz_tbl, + .txz_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_txz_tbl), + .rxz = x1e80100_qmp_gen4x8_pcie_rxz_tbl, + .rxz_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_rxz_tbl), + .pcs = x1e80100_qmp_gen4x8_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_pcs_tbl), + .pcs_misc = x1e80100_qmp_gen4x8_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_pcs_misc_tbl), + .ln_shrd = x1e80100_qmp_gen4x8_pcie_ln_shrd_tbl, + .ln_shrd_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_ln_shrd_tbl), + }, + + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = sm8550_qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l), + .regs = pciephy_v6_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, + .has_nocsr_reset = true, +}; + static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -3751,6 +3952,13 @@ static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_c qmp_configure(qmp->dev, serdes, tbls->serdes, tbls->serdes_num); + /* + * Tx/Rx registers that require different settings than + * txz/rxz must be programmed after txz/rxz. + */ + qmp_configure(qmp->dev, qmp->txz, tbls->txz, tbls->txz_num); + qmp_configure(qmp->dev, qmp->rxz, tbls->rxz, tbls->rxz_num); + qmp_configure_lane(qmp->dev, tx, tbls->tx, tbls->tx_num, 1); qmp_configure_lane(qmp->dev, rx, tbls->rx, tbls->rx_num, 1); @@ -4293,6 +4501,9 @@ static int qmp_pcie_parse_dt(struct qmp_pcie *qmp) return PTR_ERR(qmp->port_b); } + qmp->txz = base + offs->txz; + qmp->rxz = base + offs->rxz; + if (cfg->tbls.ln_shrd) qmp->ln_shrd = base + offs->ln_shrd; @@ -4478,6 +4689,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = { }, { .compatible = "qcom,x1e80100-qmp-gen4x4-pcie-phy", .data = &x1e80100_qmp_gen4x4_pciephy_cfg, + }, { + .compatible = "qcom,x1e80100-qmp-gen4x8-pcie-phy", + .data = &x1e80100_qmp_gen4x8_pciephy_cfg, }, { }, }; diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_30.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_30.h new file mode 100644 index 00000000000000..5a58ff197e6e0d --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_30.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_PCIE_V6_30_H_ +#define QCOM_PHY_QMP_PCS_PCIE_V6_30_H_ + +/* Only for QMP V6_30 PHY - PCIE have different offsets than V6 */ +#define QPHY_PCIE_V6_30_PCS_POWER_STATE_CONFIG2 0x014 +#define QPHY_PCIE_V6_30_PCS_TX_RX_CONFIG 0x020 +#define QPHY_PCIE_V6_30_PCS_ENDPOINT_REFCLK_DRIVE 0x024 +#define QPHY_PCIE_V6_30_PCS_OSC_DTCT_ACTIONS 0x098 +#define QPHY_PCIE_V6_30_PCS_EQ_CONFIG1 0x0a8 +#define QPHY_PCIE_V6_30_PCS_G3_RXEQEVAL_TIME 0x0f8 +#define QPHY_PCIE_V6_30_PCS_G4_RXEQEVAL_TIME 0x0fc +#define QPHY_PCIE_V6_30_PCS_G4_EQ_CONFIG5 0x110 +#define QPHY_PCIE_V6_30_PCS_G4_PRE_GAIN 0x164 +#define QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG1 0x184 +#define QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG3 0x18c +#define QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG5 0x194 +#define QPHY_PCIE_V6_30_PCS_G3_FOM_EQ_CONFIG5 0x1b4 +#define QPHY_PCIE_V6_30_PCS_G4_FOM_EQ_CONFIG5 0x1c8 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_30.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_30.h new file mode 100644 index 00000000000000..369120d88bc271 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_30.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_V6_30_H_ +#define QCOM_PHY_QMP_PCS_V6_30_H_ + +/* Only for QMP V6_30 PHY - PCIe PCS registers */ +#define QPHY_V6_30_PCS_LOCK_DETECT_CONFIG2 0x0cc +#define QPHY_V6_30_PCS_G3S2_PRE_GAIN 0x17c +#define QPHY_V6_30_PCS_RX_SIGDET_LVL 0x194 +#define QPHY_V6_30_PCS_ALIGN_DETECT_CONFIG7 0x1dc +#define QPHY_V6_30_PCS_TX_RX_CONFIG 0x1e0 +#define QPHY_V6_30_PCS_TX_RX_CONFIG2 0x1e4 +#define QPHY_V6_30_PCS_EQ_CONFIG4 0x1fc +#define QPHY_V6_30_PCS_EQ_CONFIG5 0x200 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index 1246d3bc8b92f8..acd6075bf6d961 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -871,6 +871,16 @@ static const struct qmp_phy_init_tbl sdx75_usb3_uniphy_pcs_usb_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V6_PCS_USB3_RCVR_DTCT_DLY_U3_H, 0x00), }; +static const struct qmp_phy_init_tbl qcs8300_usb3_uniphy_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xa5), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_2, 0xf2), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_3, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x21), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), +}; + static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xa5), QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_2, 0x82), @@ -989,6 +999,40 @@ static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), }; +static const struct qmp_phy_init_tbl qcs8300_usb3_uniphy_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xec), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0xbd), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa9), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x7b), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xe4), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN2, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FO_GAIN, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL1, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x47), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_CNTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_ENABLES, 0x00), +}; + static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xdc), QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0xbd), @@ -1462,6 +1506,24 @@ static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = { .regs = qmp_v5_usb3phy_regs_layout, }; +static const struct qmp_phy_cfg qcs8300_usb3_uniphy_cfg = { + .offsets = &qmp_usb_offsets_v5, + + .serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_serdes_tbl), + .tx_tbl = qcs8300_usb3_uniphy_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcs8300_usb3_uniphy_tx_tbl), + .rx_tbl = qcs8300_usb3_uniphy_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qcs8300_usb3_uniphy_rx_tbl), + .pcs_tbl = sa8775p_usb3_uniphy_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_tbl), + .pcs_usb_tbl = sa8775p_usb3_uniphy_pcs_usb_tbl, + .pcs_usb_tbl_num = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_usb_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v5_usb3phy_regs_layout, +}; + static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = { .offsets = &qmp_usb_offsets_v5, @@ -2247,6 +2309,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = { }, { .compatible = "qcom,msm8996-qmp-usb3-phy", .data = &msm8996_usb3phy_cfg, + }, { + .compatible = "qcom,qcs8300-qmp-usb3-uni-phy", + .data = &qcs8300_usb3_uniphy_cfg, }, { .compatible = "qcom,qdu1000-qmp-usb3-uni-phy", .data = &qdu1000_usb3_uniphy_cfg, diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c index e3ad7cea510998..248550ef98cab2 100644 --- a/drivers/phy/realtek/phy-rtk-usb2.c +++ b/drivers/phy/realtek/phy-rtk-usb2.c @@ -1023,6 +1023,8 @@ static int rtk_usb2phy_probe(struct platform_device *pdev) rtk_phy->dev = &pdev->dev; rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL); + if (!rtk_phy->phy_cfg) + return -ENOMEM; memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg)); @@ -1298,7 +1300,7 @@ MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); static struct platform_driver rtk_usb2phy_driver = { .probe = rtk_usb2phy_probe, - .remove_new = rtk_usb2phy_remove, + .remove = rtk_usb2phy_remove, .driver = { .name = "rtk-usb2phy", .of_match_table = usbphy_rtk_dt_match, diff --git a/drivers/phy/realtek/phy-rtk-usb3.c b/drivers/phy/realtek/phy-rtk-usb3.c index dfcf4b921bba63..cce453686db214 100644 --- a/drivers/phy/realtek/phy-rtk-usb3.c +++ b/drivers/phy/realtek/phy-rtk-usb3.c @@ -577,6 +577,8 @@ static int rtk_usb3phy_probe(struct platform_device *pdev) rtk_phy->dev = &pdev->dev; rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL); + if (!rtk_phy->phy_cfg) + return -ENOMEM; memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg)); @@ -734,7 +736,7 @@ MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); static struct platform_driver rtk_usb3phy_driver = { .probe = rtk_usb3phy_probe, - .remove_new = rtk_usb3phy_remove, + .remove = rtk_usb3phy_remove, .driver = { .name = "rtk-usb3phy", .of_match_table = usbphy_rtk_dt_match, diff --git a/drivers/phy/renesas/phy-rcar-gen3-pcie.c b/drivers/phy/renesas/phy-rcar-gen3-pcie.c index 0ce7e9c9444474..feca4cb2ff4d1e 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-pcie.c +++ b/drivers/phy/renesas/phy-rcar-gen3-pcie.c @@ -132,11 +132,11 @@ static void rcar_gen3_phy_pcie_remove(struct platform_device *pdev) static struct platform_driver rcar_gen3_phy_driver = { .driver = { - .name = "phy_rcar_gen3_pcie", - .of_match_table = rcar_gen3_phy_pcie_match_table, + .name = "phy_rcar_gen3_pcie", + .of_match_table = rcar_gen3_phy_pcie_match_table, }, - .probe = rcar_gen3_phy_pcie_probe, - .remove_new = rcar_gen3_phy_pcie_remove, + .probe = rcar_gen3_phy_pcie_probe, + .remove = 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 58e1233051526a..775f4f973a6cc2 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -825,7 +825,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_new = rcar_gen3_phy_usb2_remove, + .remove = 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 e2d630edd992db..5c267d148c90be 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c @@ -206,11 +206,11 @@ static void rcar_gen3_phy_usb3_remove(struct platform_device *pdev) static struct platform_driver rcar_gen3_phy_usb3_driver = { .driver = { - .name = "phy_rcar_gen3_usb3", - .of_match_table = rcar_gen3_phy_usb3_match_table, + .name = "phy_rcar_gen3_usb3", + .of_match_table = rcar_gen3_phy_usb3_match_table, }, - .probe = rcar_gen3_phy_usb3_probe, - .remove_new = rcar_gen3_phy_usb3_remove, + .probe = rcar_gen3_phy_usb3_probe, + .remove = 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 f1f1da4a0b1fe5..3b2d8cef75e52c 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -404,7 +404,7 @@ static void r8a779f0_eth_serdes_remove(struct platform_device *pdev) static struct platform_driver r8a779f0_eth_serdes_driver_platform = { .probe = r8a779f0_eth_serdes_probe, - .remove_new = r8a779f0_eth_serdes_remove, + .remove = 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 98c92d6c482fef..2ab99e1d47ebeb 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c @@ -472,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_new = rockchip_inno_csidphy_remove, + .remove = 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 6405943a267678..d5b1a4e2f7d343 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c @@ -784,7 +784,7 @@ static struct platform_driver inno_dsidphy_driver = { .of_match_table = of_match_ptr(inno_dsidphy_of_match), }, .probe = inno_dsidphy_probe, - .remove_new = inno_dsidphy_remove, + .remove = 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 053bd62e31ba77..8dcc2bb777b545 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -1424,8 +1424,8 @@ static const struct of_device_id inno_hdmi_phy_of_match[] = { MODULE_DEVICE_TABLE(of, inno_hdmi_phy_of_match); static struct platform_driver inno_hdmi_phy_driver = { - .probe = inno_hdmi_phy_probe, - .remove_new = inno_hdmi_phy_remove, + .probe = inno_hdmi_phy_probe, + .remove = 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-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 4f71373ae6e1a3..96f3d868a526fc 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -229,9 +229,10 @@ struct rockchip_usb2phy_port { * @dev: pointer to device. * @grf: General Register Files regmap. * @usbgrf: USB General Register Files regmap. - * @clk: clock struct of phy input clk. + * @clks: array of phy input clocks. * @clk480m: clock struct of phy output clk. * @clk480m_hw: clock struct of phy output clk management. + * @num_clks: number of phy input clocks. * @phy_reset: phy reset control. * @chg_state: states involved in USB charger detection. * @chg_type: USB charger types. @@ -246,9 +247,10 @@ struct rockchip_usb2phy { struct device *dev; struct regmap *grf; struct regmap *usbgrf; - struct clk *clk; + struct clk_bulk_data *clks; struct clk *clk480m; struct clk_hw clk480m_hw; + int num_clks; struct reset_control *phy_reset; enum usb_chg_state chg_state; enum power_supply_type chg_type; @@ -310,6 +312,13 @@ static int rockchip_usb2phy_reset(struct rockchip_usb2phy *rphy) return 0; } +static void rockchip_usb2phy_clk_bulk_disable(void *data) +{ + struct rockchip_usb2phy *rphy = data; + + clk_bulk_disable_unprepare(rphy->num_clks, rphy->clks); +} + static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) { struct rockchip_usb2phy *rphy = @@ -376,7 +385,9 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) { struct device_node *node = rphy->dev->of_node; struct clk_init_data init; + struct clk *refclk = NULL; const char *clk_name; + int i; int ret = 0; init.flags = 0; @@ -386,8 +397,15 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) /* optional override of the clockname */ of_property_read_string(node, "clock-output-names", &init.name); - if (rphy->clk) { - clk_name = __clk_get_name(rphy->clk); + for (i = 0; i < rphy->num_clks; i++) { + if (!strncmp(rphy->clks[i].id, "phyclk", 6)) { + refclk = rphy->clks[i].clk; + break; + } + } + + if (!IS_ERR(refclk)) { + clk_name = __clk_get_name(refclk); init.parent_names = &clk_name; init.num_parents = 1; } else { @@ -418,30 +436,28 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy) { - int ret; struct device_node *node = rphy->dev->of_node; struct extcon_dev *edev; + int ret; if (of_property_read_bool(node, "extcon")) { edev = extcon_get_edev_by_phandle(rphy->dev, 0); - if (IS_ERR(edev)) { - if (PTR_ERR(edev) != -EPROBE_DEFER) - dev_err(rphy->dev, "Invalid or missing extcon\n"); - return PTR_ERR(edev); - } + if (IS_ERR(edev)) + return dev_err_probe(rphy->dev, PTR_ERR(edev), + "invalid or missing extcon\n"); } else { /* Initialize extcon device */ edev = devm_extcon_dev_allocate(rphy->dev, rockchip_usb2phy_extcon_cable); if (IS_ERR(edev)) - return -ENOMEM; + return dev_err_probe(rphy->dev, PTR_ERR(edev), + "failed to allocate extcon device\n"); ret = devm_extcon_dev_register(rphy->dev, edev); - if (ret) { - dev_err(rphy->dev, "failed to register extcon device\n"); - return ret; - } + if (ret) + return dev_err_probe(rphy->dev, ret, + "failed to register extcon device\n"); } rphy->edev = edev; @@ -1327,7 +1343,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) struct rockchip_usb2phy *rphy; const struct rockchip_usb2phy_cfg *phy_cfgs; unsigned int reg; - int index, ret; + int index = 0, ret; rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); if (!rphy) @@ -1339,9 +1355,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) dev_err(dev, "failed to locate usbgrf\n"); return PTR_ERR(rphy->grf); } - } - - else { + } else { rphy->grf = syscon_node_to_regmap(dev->parent->of_node); if (IS_ERR(rphy->grf)) return PTR_ERR(rphy->grf); @@ -1358,16 +1372,14 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) } if (of_property_read_u32_index(np, "reg", 0, ®)) { - dev_err(dev, "the reg property is not assigned in %pOFn node\n", - np); + dev_err(dev, "the reg property is not assigned in %pOFn node\n", np); return -EINVAL; } /* support address_cells=2 */ if (of_property_count_u32_elems(np, "reg") > 2 && reg == 0) { if (of_property_read_u32_index(np, "reg", 1, ®)) { - dev_err(dev, "the reg property is not assigned in %pOFn node\n", - np); + dev_err(dev, "the reg property is not assigned in %pOFn node\n", np); return -EINVAL; } } @@ -1386,8 +1398,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) if (ret) return ret; - /* find out a proper config which can be matched with dt. */ - index = 0; + /* find a proper config that can be matched with the DT */ do { if (phy_cfgs[index].reg == reg) { rphy->phy_cfg = &phy_cfgs[index]; @@ -1406,17 +1417,25 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) if (IS_ERR(rphy->phy_reset)) return PTR_ERR(rphy->phy_reset); - rphy->clk = devm_clk_get_optional_enabled(dev, "phyclk"); - if (IS_ERR(rphy->clk)) { - return dev_err_probe(&pdev->dev, PTR_ERR(rphy->clk), - "failed to get phyclk\n"); - } + ret = devm_clk_bulk_get_all(dev, &rphy->clks); + if (ret == -EPROBE_DEFER) + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, + "failed to get phy clock\n"); + + /* Clocks are optional */ + rphy->num_clks = ret < 0 ? 0 : ret; ret = rockchip_usb2phy_clk480m_register(rphy); - if (ret) { - dev_err(dev, "failed to register 480m output clock\n"); + if (ret) + return dev_err_probe(dev, ret, "failed to register 480m output clock\n"); + + ret = clk_bulk_prepare_enable(rphy->num_clks, rphy->clks); + if (ret) + return dev_err_probe(dev, ret, "failed to enable phy clock\n"); + + ret = devm_add_action_or_reset(dev, rockchip_usb2phy_clk_bulk_disable, rphy); + if (ret) return ret; - } if (rphy->phy_cfg->phy_tuning) { ret = rphy->phy_cfg->phy_tuning(rphy); @@ -1436,8 +1455,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops); if (IS_ERR(phy)) { - dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n"); - ret = PTR_ERR(phy); + ret = dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n"); goto put_child; } @@ -1446,13 +1464,11 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) /* initialize otg/host port separately */ if (of_node_name_eq(child_np, "host-port")) { - ret = rockchip_usb2phy_host_port_init(rphy, rport, - child_np); + ret = rockchip_usb2phy_host_port_init(rphy, rport, child_np); if (ret) goto put_child; } else { - ret = rockchip_usb2phy_otg_port_init(rphy, rport, - child_np); + ret = rockchip_usb2phy_otg_port_init(rphy, rport, child_np); if (ret) goto put_child; } @@ -1474,8 +1490,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) "rockchip_usb2phy", rphy); if (ret) { - dev_err(rphy->dev, - "failed to request usb2phy irq handle\n"); + dev_err_probe(rphy->dev, ret, "failed to request usb2phy irq handle\n"); goto put_child; } } @@ -1495,6 +1510,30 @@ static int rk3128_usb2phy_tuning(struct rockchip_usb2phy *rphy) BIT(2) << BIT_WRITEABLE_SHIFT | 0); } +static int rk3576_usb2phy_tuning(struct rockchip_usb2phy *rphy) +{ + int ret; + u32 reg = rphy->phy_cfg->reg; + + /* Deassert SIDDQ to power on analog block */ + ret = regmap_write(rphy->grf, reg + 0x0010, GENMASK(29, 29) | 0x0000); + if (ret) + return ret; + + /* Do reset after exit IDDQ mode */ + ret = rockchip_usb2phy_reset(rphy); + if (ret) + return ret; + + /* HS DC Voltage Level Adjustment 4'b1001 : +5.89% */ + ret |= regmap_write(rphy->grf, reg + 0x000c, GENMASK(27, 24) | 0x0900); + + /* HS Transmitter Pre-Emphasis Current Control 2'b10 : 2x */ + ret |= regmap_write(rphy->grf, reg + 0x0010, GENMASK(20, 19) | 0x0010); + + return ret; +} + static int rk3588_usb2phy_tuning(struct rockchip_usb2phy *rphy) { int ret; @@ -1923,6 +1962,84 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3576_phy_cfgs[] = { + { + .reg = 0x0, + .num_ports = 1, + .phy_tuning = rk3576_usb2phy_tuning, + .clkout_ctl = { 0x0008, 0, 0, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x0000, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x00c0, 1, 1, 0, 1 }, + .bvalid_det_st = { 0x00c4, 1, 1, 0, 1 }, + .bvalid_det_clr = { 0x00c8, 1, 1, 0, 1 }, + .ls_det_en = { 0x00c0, 0, 0, 0, 1 }, + .ls_det_st = { 0x00c4, 0, 0, 0, 1 }, + .ls_det_clr = { 0x00c8, 0, 0, 0, 1 }, + .disfall_en = { 0x00c0, 6, 6, 0, 1 }, + .disfall_st = { 0x00c4, 6, 6, 0, 1 }, + .disfall_clr = { 0x00c8, 6, 6, 0, 1 }, + .disrise_en = { 0x00c0, 5, 5, 0, 1 }, + .disrise_st = { 0x00c4, 5, 5, 0, 1 }, + .disrise_clr = { 0x00c8, 5, 5, 0, 1 }, + .utmi_avalid = { 0x0080, 1, 1, 0, 1 }, + .utmi_bvalid = { 0x0080, 0, 0, 0, 1 }, + .utmi_ls = { 0x0080, 5, 4, 0, 1 }, + } + }, + .chg_det = { + .cp_det = { 0x0080, 8, 8, 0, 1 }, + .dcp_det = { 0x0080, 8, 8, 0, 1 }, + .dp_det = { 0x0080, 9, 9, 1, 0 }, + .idm_sink_en = { 0x0010, 5, 5, 1, 0 }, + .idp_sink_en = { 0x0010, 5, 5, 0, 1 }, + .idp_src_en = { 0x0010, 14, 14, 0, 1 }, + .rdm_pdwn_en = { 0x0010, 14, 14, 0, 1 }, + .vdm_src_en = { 0x0010, 7, 6, 0, 3 }, + .vdp_src_en = { 0x0010, 7, 6, 0, 3 }, + }, + }, + { + .reg = 0x2000, + .num_ports = 1, + .phy_tuning = rk3576_usb2phy_tuning, + .clkout_ctl = { 0x2008, 0, 0, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x2000, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x20c0, 1, 1, 0, 1 }, + .bvalid_det_st = { 0x20c4, 1, 1, 0, 1 }, + .bvalid_det_clr = { 0x20c8, 1, 1, 0, 1 }, + .ls_det_en = { 0x20c0, 0, 0, 0, 1 }, + .ls_det_st = { 0x20c4, 0, 0, 0, 1 }, + .ls_det_clr = { 0x20c8, 0, 0, 0, 1 }, + .disfall_en = { 0x20c0, 6, 6, 0, 1 }, + .disfall_st = { 0x20c4, 6, 6, 0, 1 }, + .disfall_clr = { 0x20c8, 6, 6, 0, 1 }, + .disrise_en = { 0x20c0, 5, 5, 0, 1 }, + .disrise_st = { 0x20c4, 5, 5, 0, 1 }, + .disrise_clr = { 0x20c8, 5, 5, 0, 1 }, + .utmi_avalid = { 0x2080, 1, 1, 0, 1 }, + .utmi_bvalid = { 0x2080, 0, 0, 0, 1 }, + .utmi_ls = { 0x2080, 5, 4, 0, 1 }, + } + }, + .chg_det = { + .cp_det = { 0x2080, 8, 8, 0, 1 }, + .dcp_det = { 0x2080, 8, 8, 0, 1 }, + .dp_det = { 0x2080, 9, 9, 1, 0 }, + .idm_sink_en = { 0x2010, 5, 5, 1, 0 }, + .idp_sink_en = { 0x2010, 5, 5, 0, 1 }, + .idp_src_en = { 0x2010, 14, 14, 0, 1 }, + .rdm_pdwn_en = { 0x2010, 14, 14, 0, 1 }, + .vdm_src_en = { 0x2010, 7, 6, 0, 3 }, + .vdp_src_en = { 0x2010, 7, 6, 0, 3 }, + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { { .reg = 0x0000, @@ -2094,6 +2211,7 @@ static const struct of_device_id rockchip_usb2phy_dt_match[] = { { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, + { .compatible = "rockchip,rk3576-usb2phy", .data = &rk3576_phy_cfgs }, { .compatible = "rockchip,rk3588-usb2phy", .data = &rk3588_phy_cfgs }, { .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs }, {} diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c index 9f084697dd05ce..ceab9c71d3b53a 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -256,13 +256,10 @@ struct ropll_config { }; enum rk_hdptx_reset { - RST_PHY = 0, - RST_APB, + RST_APB = 0, RST_INIT, RST_CMN, RST_LANE, - RST_ROPLL, - RST_LCPLL, RST_MAX }; @@ -665,11 +662,6 @@ static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx) { u32 val; - /* reset phy and apb, or phy locked flag may keep 1 */ - reset_control_assert(hdptx->rsts[RST_PHY].rstc); - usleep_range(20, 30); - reset_control_deassert(hdptx->rsts[RST_PHY].rstc); - reset_control_assert(hdptx->rsts[RST_APB].rstc); usleep_range(20, 30); reset_control_deassert(hdptx->rsts[RST_APB].rstc); @@ -792,10 +784,6 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx, rk_hdptx_pre_power_up(hdptx); - reset_control_assert(hdptx->rsts[RST_ROPLL].rstc); - usleep_range(20, 30); - reset_control_deassert(hdptx->rsts[RST_ROPLL].rstc); - rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq); rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_cmn_init_seq); @@ -1098,13 +1086,10 @@ static int rk_hdptx_phy_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(hdptx->regmap), "Failed to init regmap\n"); - hdptx->rsts[RST_PHY].id = "phy"; hdptx->rsts[RST_APB].id = "apb"; hdptx->rsts[RST_INIT].id = "init"; hdptx->rsts[RST_CMN].id = "cmn"; hdptx->rsts[RST_LANE].id = "lane"; - hdptx->rsts[RST_ROPLL].id = "ropll"; - hdptx->rsts[RST_LCPLL].id = "lcpll"; ret = devm_reset_control_bulk_get_exclusive(dev, RST_MAX, hdptx->rsts); if (ret) diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 4efcb78b0ab18e..122ae0fdc785ee 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -1210,7 +1210,7 @@ MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids); static struct platform_driver rockchip_typec_phy_driver = { .probe = rockchip_typec_phy_probe, - .remove_new = rockchip_typec_phy_remove, + .remove = rockchip_typec_phy_remove, .driver = { .name = "rockchip-typec-phy", .of_match_table = rockchip_typec_phy_dt_ids, diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index 2c51e5c62d3eb5..5b1e8a3806ed4e 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -1538,6 +1538,43 @@ static const char * const rk_udphy_rst_list[] = { "init", "cmn", "lane", "pcs_apb", "pma_apb" }; +static const struct rk_udphy_cfg rk3576_udphy_cfgs = { + .num_phys = 1, + .phy_ids = { 0x2b010000 }, + .num_rsts = ARRAY_SIZE(rk_udphy_rst_list), + .rst_list = rk_udphy_rst_list, + .grfcfg = { + /* u2phy-grf */ + .bvalid_phy_con = RK_UDPHY_GEN_GRF_REG(0x0010, 1, 0, 0x2, 0x3), + .bvalid_grf_con = RK_UDPHY_GEN_GRF_REG(0x0000, 15, 14, 0x1, 0x3), + + /* usb-grf */ + .usb3otg0_cfg = RK_UDPHY_GEN_GRF_REG(0x0030, 15, 0, 0x1100, 0x0188), + + /* usbdpphy-grf */ + .low_pwrn = RK_UDPHY_GEN_GRF_REG(0x0004, 13, 13, 0, 1), + .rx_lfps = RK_UDPHY_GEN_GRF_REG(0x0004, 14, 14, 0, 1), + }, + .vogrfcfg = { + { + .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3), + .dp_lane_reg = 0x0000, + }, + }, + .dp_tx_ctrl_cfg = { + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, + .dp_tx_ctrl_cfg_typec = { + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, +}; + static const struct rk_udphy_cfg rk3588_udphy_cfgs = { .num_phys = 2, .phy_ids = { @@ -1584,6 +1621,10 @@ static const struct rk_udphy_cfg rk3588_udphy_cfgs = { }; static const struct of_device_id rk_udphy_dt_match[] = { + { + .compatible = "rockchip,rk3576-usbdp-phy", + .data = &rk3576_udphy_cfgs + }, { .compatible = "rockchip,rk3588-usbdp-phy", .data = &rk3588_udphy_cfgs diff --git a/drivers/phy/st/Kconfig b/drivers/phy/st/Kconfig index 3fc3d0781fb8ac..304614b6dabfc4 100644 --- a/drivers/phy/st/Kconfig +++ b/drivers/phy/st/Kconfig @@ -33,6 +33,17 @@ config PHY_STIH407_USB Enable this support to enable the picoPHY device used by USB2 and USB3 controllers on STMicroelectronics STiH407 SoC families. +config PHY_STM32_COMBOPHY + tristate "STMicroelectronics COMBOPHY driver for STM32MP25" + depends on ARCH_STM32 || COMPILE_TEST + select GENERIC_PHY + help + Enable this to support the COMBOPHY device used by USB3 or PCIe + controllers on STMicroelectronics STM32MP25 SoC. + This driver controls the COMBOPHY block to generate the PCIe 100Mhz + reference clock from either the external clock generator or HSE + internal SoC clock source. + config PHY_STM32_USBPHYC tristate "STMicroelectronics STM32 USB HS PHY Controller driver" depends on ARCH_STM32 || COMPILE_TEST diff --git a/drivers/phy/st/Makefile b/drivers/phy/st/Makefile index c862dd937b6475..cb80e954ea9f00 100644 --- a/drivers/phy/st/Makefile +++ b/drivers/phy/st/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o +obj-$(CONFIG_PHY_STM32_COMBOPHY) += phy-stm32-combophy.o obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o diff --git a/drivers/phy/st/phy-stm32-combophy.c b/drivers/phy/st/phy-stm32-combophy.c new file mode 100644 index 00000000000000..765bb34fe3589d --- /dev/null +++ b/drivers/phy/st/phy-stm32-combophy.c @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics COMBOPHY STM32MP25 Controller driver. + * + * Copyright (C) 2024 STMicroelectronics + * Author: Christian Bruel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYSCFG_COMBOPHY_CR1 0x4c00 +#define SYSCFG_COMBOPHY_CR2 0x4c04 +#define SYSCFG_COMBOPHY_CR4 0x4c0c +#define SYSCFG_COMBOPHY_CR5 0x4c10 +#define SYSCFG_COMBOPHY_SR 0x4c14 +#define SYSCFG_PCIEPRGCR 0x6080 + +/* SYSCFG PCIEPRGCR */ +#define STM32MP25_PCIEPRGCR_EN BIT(0) +#define STM32MP25_PCIEPRG_IMPCTRL_OHM GENMASK(3, 1) +#define STM32MP25_PCIEPRG_IMPCTRL_VSWING GENMASK(5, 4) + +/* SYSCFG SYSCFG_COMBOPHY_SR */ +#define STM32MP25_PIPE0_PHYSTATUS BIT(1) + +/* SYSCFG CR1 */ +#define SYSCFG_COMBOPHY_CR1_REFUSEPAD BIT(0) +#define SYSCFG_COMBOPHY_CR1_MPLLMULT GENMASK(7, 1) +#define SYSCFG_COMBOPHY_CR1_REFCLKSEL GENMASK(16, 8) +#define SYSCFG_COMBOPHY_CR1_REFCLKDIV2 BIT(17) +#define SYSCFG_COMBOPHY_CR1_REFSSPEN BIT(18) +#define SYSCFG_COMBOPHY_CR1_SSCEN BIT(19) + +/* SYSCFG CR4 */ +#define SYSCFG_COMBOPHY_CR4_RX0_EQ GENMASK(2, 0) + +#define MPLLMULT_19_2 (0x02u << 1) +#define MPLLMULT_20 (0x7du << 1) +#define MPLLMULT_24 (0x68u << 1) +#define MPLLMULT_25 (0x64u << 1) +#define MPLLMULT_26 (0x60u << 1) +#define MPLLMULT_38_4 (0x41u << 1) +#define MPLLMULT_48 (0x6cu << 1) +#define MPLLMULT_50 (0x32u << 1) +#define MPLLMULT_52 (0x30u << 1) +#define MPLLMULT_100 (0x19u << 1) + +#define REFCLKSEL_0 0 +#define REFCLKSEL_1 (0x108u << 8) + +#define REFCLDIV_0 0 + +/* SYSCFG CR2 */ +#define SYSCFG_COMBOPHY_CR2_MODESEL GENMASK(1, 0) +#define SYSCFG_COMBOPHY_CR2_ISO_DIS BIT(15) + +#define COMBOPHY_MODESEL_PCIE 0 +#define COMBOPHY_MODESEL_USB 3 + +/* SYSCFG CR5 */ +#define SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS BIT(12) + +#define COMBOPHY_SUP_ANA_MPLL_LOOP_CTL 0xc0 +#define COMBOPHY_PROP_CNTRL GENMASK(7, 4) + +/* Required apb/ker clocks first, optional pad last. */ +static const char * const combophy_clks[] = {"apb", "ker", "pad"}; +#define APB_CLK 0 +#define KER_CLK 1 +#define PAD_CLK 2 + +struct stm32_combophy { + struct phy *phy; + struct regmap *regmap; + struct device *dev; + void __iomem *base; + struct reset_control *phy_reset; + struct clk_bulk_data clks[ARRAY_SIZE(combophy_clks)]; + int num_clks; + bool have_pad_clk; + unsigned int type; + bool is_init; + int irq_wakeup; +}; + +struct clk_impedance { + u32 microohm; + u32 vswing[4]; +}; + +/* + * lookup table to hold the settings needed for a ref clock frequency + * impedance, the offset is used to set the IMP_CTL and DE_EMP bit of the + * PRG_IMP_CTRL register. Use ordered discrete values in the table + */ +static const struct clk_impedance imp_lookup[] = { + { 6090000, { 442000, 564000, 684000, 802000 } }, + { 5662000, { 528000, 621000, 712000, 803000 } }, + { 5292000, { 491000, 596000, 700000, 802000 } }, + { 4968000, { 558000, 640000, 722000, 803000 } }, + { 4684000, { 468000, 581000, 692000, 802000 } }, + { 4429000, { 554000, 613000, 717000, 803000 } }, + { 4204000, { 511000, 609000, 706000, 802000 } }, + { 3999000, { 571000, 648000, 726000, 803000 } } +}; + +static int stm32_impedance_tune(struct stm32_combophy *combophy) +{ + u8 imp_size = ARRAY_SIZE(imp_lookup); + u8 vswing_size = ARRAY_SIZE(imp_lookup[0].vswing); + u8 imp_of, vswing_of; + u32 max_imp = imp_lookup[0].microohm; + u32 min_imp = imp_lookup[imp_size - 1].microohm; + u32 max_vswing = imp_lookup[imp_size - 1].vswing[vswing_size - 1]; + u32 min_vswing = imp_lookup[0].vswing[0]; + u32 val; + + if (!of_property_read_u32(combophy->dev->of_node, "st,output-micro-ohms", &val)) { + if (val < min_imp || val > max_imp) { + dev_err(combophy->dev, "Invalid value %u for output ohm\n", val); + return -EINVAL; + } + + for (imp_of = 0; imp_of < ARRAY_SIZE(imp_lookup); imp_of++) + if (imp_lookup[imp_of].microohm <= val) + break; + + dev_dbg(combophy->dev, "Set %u micro-ohms output impedance\n", + imp_lookup[imp_of].microohm); + + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRG_IMPCTRL_OHM, + FIELD_PREP(STM32MP25_PCIEPRG_IMPCTRL_OHM, imp_of)); + } else { + regmap_read(combophy->regmap, SYSCFG_PCIEPRGCR, &val); + imp_of = FIELD_GET(STM32MP25_PCIEPRG_IMPCTRL_OHM, val); + } + + if (!of_property_read_u32(combophy->dev->of_node, "st,output-vswing-microvolt", &val)) { + if (val < min_vswing || val > max_vswing) { + dev_err(combophy->dev, "Invalid value %u for output vswing\n", val); + return -EINVAL; + } + + for (vswing_of = 0; vswing_of < ARRAY_SIZE(imp_lookup[imp_of].vswing); vswing_of++) + if (imp_lookup[imp_of].vswing[vswing_of] >= val) + break; + + dev_dbg(combophy->dev, "Set %u microvolt swing\n", + imp_lookup[imp_of].vswing[vswing_of]); + + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRG_IMPCTRL_VSWING, + FIELD_PREP(STM32MP25_PCIEPRG_IMPCTRL_VSWING, vswing_of)); + } + + return 0; +} + +static int stm32_combophy_pll_init(struct stm32_combophy *combophy) +{ + int ret; + u32 refclksel, pllmult, propcntrl, val; + u32 clk_rate; + struct clk *clk; + u32 cr1_val = 0, cr1_mask = 0; + + if (combophy->have_pad_clk) + clk = combophy->clks[PAD_CLK].clk; + else + clk = combophy->clks[KER_CLK].clk; + + clk_rate = clk_get_rate(clk); + + dev_dbg(combophy->dev, "%s pll init rate %d\n", + combophy->have_pad_clk ? "External" : "Ker", clk_rate); + + if (combophy->type != PHY_TYPE_PCIE) { + cr1_mask |= SYSCFG_COMBOPHY_CR1_REFSSPEN; + cr1_val |= SYSCFG_COMBOPHY_CR1_REFSSPEN; + } + + if (of_property_present(combophy->dev->of_node, "st,ssc-on")) { + dev_dbg(combophy->dev, "Enabling clock with SSC\n"); + cr1_mask |= SYSCFG_COMBOPHY_CR1_SSCEN; + cr1_val |= SYSCFG_COMBOPHY_CR1_SSCEN; + } + + switch (clk_rate) { + case 100000000: + pllmult = MPLLMULT_100; + refclksel = REFCLKSEL_0; + propcntrl = 0x8u << 4; + break; + case 19200000: + pllmult = MPLLMULT_19_2; + refclksel = REFCLKSEL_1; + propcntrl = 0x8u << 4; + break; + case 25000000: + pllmult = MPLLMULT_25; + refclksel = REFCLKSEL_0; + propcntrl = 0xeu << 4; + break; + case 24000000: + pllmult = MPLLMULT_24; + refclksel = REFCLKSEL_1; + propcntrl = 0xeu << 4; + break; + case 20000000: + pllmult = MPLLMULT_20; + refclksel = REFCLKSEL_0; + propcntrl = 0xeu << 4; + break; + default: + dev_err(combophy->dev, "Invalid rate 0x%x\n", clk_rate); + return -EINVAL; + } + + cr1_mask |= SYSCFG_COMBOPHY_CR1_REFCLKDIV2; + cr1_val |= REFCLDIV_0; + + cr1_mask |= SYSCFG_COMBOPHY_CR1_REFCLKSEL; + cr1_val |= refclksel; + + cr1_mask |= SYSCFG_COMBOPHY_CR1_MPLLMULT; + cr1_val |= pllmult; + + /* + * vddcombophy is interconnected with vddcore. Isolation bit should be unset + * before using the ComboPHY. + */ + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, + SYSCFG_COMBOPHY_CR2_ISO_DIS, SYSCFG_COMBOPHY_CR2_ISO_DIS); + + reset_control_assert(combophy->phy_reset); + + if (combophy->type == PHY_TYPE_PCIE) { + ret = stm32_impedance_tune(combophy); + if (ret) + goto out_iso; + + cr1_mask |= SYSCFG_COMBOPHY_CR1_REFUSEPAD; + cr1_val |= combophy->have_pad_clk ? SYSCFG_COMBOPHY_CR1_REFUSEPAD : 0; + } + + if (!of_property_read_u32(combophy->dev->of_node, "st,rx-equalizer", &val)) { + dev_dbg(combophy->dev, "Set RX equalizer %u\n", val); + if (val > SYSCFG_COMBOPHY_CR4_RX0_EQ) { + dev_err(combophy->dev, "Invalid value %u for rx0 equalizer\n", val); + ret = -EINVAL; + goto out_iso; + } + + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR4, + SYSCFG_COMBOPHY_CR4_RX0_EQ, val); + } + + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, cr1_mask, cr1_val); + + /* + * Force elasticity buffer to be tuned for the reference clock as + * the separated clock model is not supported + */ + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR5, + SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS, SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS); + + reset_control_deassert(combophy->phy_reset); + + ret = regmap_read_poll_timeout(combophy->regmap, SYSCFG_COMBOPHY_SR, val, + !(val & STM32MP25_PIPE0_PHYSTATUS), + 10, 1000); + if (ret) { + dev_err(combophy->dev, "timeout, cannot lock PLL\n"); + if (combophy->type == PHY_TYPE_PCIE && !combophy->have_pad_clk) + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRGCR_EN, 0); + + if (combophy->type != PHY_TYPE_PCIE) + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, + SYSCFG_COMBOPHY_CR1_REFSSPEN, 0); + + goto out; + } + + + if (combophy->type == PHY_TYPE_PCIE) { + if (!combophy->have_pad_clk) + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRGCR_EN, STM32MP25_PCIEPRGCR_EN); + + val = readl_relaxed(combophy->base + COMBOPHY_SUP_ANA_MPLL_LOOP_CTL); + val &= ~COMBOPHY_PROP_CNTRL; + val |= propcntrl; + writel_relaxed(val, combophy->base + COMBOPHY_SUP_ANA_MPLL_LOOP_CTL); + } + + return 0; + +out_iso: + reset_control_deassert(combophy->phy_reset); + +out: + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, + SYSCFG_COMBOPHY_CR2_ISO_DIS, 0); + + return ret; +} + +static struct phy *stm32_combophy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct stm32_combophy *combophy = dev_get_drvdata(dev); + unsigned int type; + + if (args->args_count != 1) { + dev_err(dev, "invalid number of cells in 'phy' property\n"); + return ERR_PTR(-EINVAL); + } + + type = args->args[0]; + if (type != PHY_TYPE_USB3 && type != PHY_TYPE_PCIE) { + dev_err(dev, "unsupported device type: %d\n", type); + return ERR_PTR(-EINVAL); + } + + if (combophy->have_pad_clk && type != PHY_TYPE_PCIE) { + dev_err(dev, "Invalid use of clk_pad for USB3 mode\n"); + return ERR_PTR(-EINVAL); + } + + combophy->type = type; + + return combophy->phy; +} + +static int stm32_combophy_set_mode(struct stm32_combophy *combophy) +{ + int type = combophy->type; + u32 val; + + switch (type) { + case PHY_TYPE_PCIE: + dev_dbg(combophy->dev, "setting PCIe ComboPHY\n"); + val = COMBOPHY_MODESEL_PCIE; + break; + case PHY_TYPE_USB3: + dev_dbg(combophy->dev, "setting USB3 ComboPHY\n"); + val = COMBOPHY_MODESEL_USB; + break; + default: + dev_err(combophy->dev, "Invalid PHY mode %d\n", type); + return -EINVAL; + } + + return regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, + SYSCFG_COMBOPHY_CR2_MODESEL, val); +} + +static int stm32_combophy_suspend_noirq(struct device *dev) +{ + struct stm32_combophy *combophy = dev_get_drvdata(dev); + + /* + * Clocks should be turned off since it is not needed for + * wakeup capability. In case usb-remote wakeup is not enabled, + * combo-phy is already turned off by HCD driver using exit callback + */ + if (combophy->is_init) { + clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); + + /* since wakeup is enabled for ctrl */ + enable_irq_wake(combophy->irq_wakeup); + } + + return 0; +} + +static int stm32_combophy_resume_noirq(struct device *dev) +{ + struct stm32_combophy *combophy = dev_get_drvdata(dev); + int ret; + + /* + * If clocks was turned off by suspend call for wakeup then needs + * to be turned back ON in resume. In case usb-remote wakeup is not + * enabled, clocks already turned ON by HCD driver using init callback + */ + if (combophy->is_init) { + /* since wakeup was enabled for ctrl */ + disable_irq_wake(combophy->irq_wakeup); + + ret = clk_bulk_prepare_enable(combophy->num_clks, combophy->clks); + if (ret) { + dev_err(dev, "can't enable clocks (%d)\n", ret); + return ret; + } + } + + return 0; +} + +static int stm32_combophy_exit(struct phy *phy) +{ + struct stm32_combophy *combophy = phy_get_drvdata(phy); + struct device *dev = combophy->dev; + + combophy->is_init = false; + + if (combophy->type == PHY_TYPE_PCIE && !combophy->have_pad_clk) + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRGCR_EN, 0); + + if (combophy->type != PHY_TYPE_PCIE) + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, + SYSCFG_COMBOPHY_CR1_REFSSPEN, 0); + + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, + SYSCFG_COMBOPHY_CR2_ISO_DIS, 0); + + clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); + + pm_runtime_put_noidle(dev); + + return 0; +} + +static int stm32_combophy_init(struct phy *phy) +{ + struct stm32_combophy *combophy = phy_get_drvdata(phy); + struct device *dev = combophy->dev; + int ret; + + pm_runtime_get_noresume(dev); + + ret = clk_bulk_prepare_enable(combophy->num_clks, combophy->clks); + if (ret) { + dev_err(dev, "can't enable clocks (%d)\n", ret); + pm_runtime_put_noidle(dev); + return ret; + } + + ret = stm32_combophy_set_mode(combophy); + if (ret) { + dev_err(dev, "combophy mode not set\n"); + clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); + pm_runtime_put_noidle(dev); + return ret; + } + + ret = stm32_combophy_pll_init(combophy); + if (ret) { + clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); + pm_runtime_put_noidle(dev); + return ret; + } + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + combophy->is_init = true; + + return ret; +} + +static const struct phy_ops stm32_combophy_phy_data = { + .init = stm32_combophy_init, + .exit = stm32_combophy_exit, + .owner = THIS_MODULE +}; + +static irqreturn_t stm32_combophy_irq_wakeup_handler(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +static int stm32_combophy_get_clocks(struct stm32_combophy *combophy) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(combophy_clks); i++) + combophy->clks[i].id = combophy_clks[i]; + + combophy->num_clks = ARRAY_SIZE(combophy_clks) - 1; + + ret = devm_clk_bulk_get(combophy->dev, combophy->num_clks, combophy->clks); + if (ret) + return ret; + + ret = devm_clk_bulk_get_optional(combophy->dev, 1, combophy->clks + combophy->num_clks); + if (ret) + return ret; + + if (combophy->clks[combophy->num_clks].clk != NULL) { + combophy->have_pad_clk = true; + combophy->num_clks++; + } + + return 0; +} + +static int stm32_combophy_probe(struct platform_device *pdev) +{ + struct stm32_combophy *combophy; + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + int ret, irq; + + combophy = devm_kzalloc(dev, sizeof(*combophy), GFP_KERNEL); + if (!combophy) + return -ENOMEM; + + combophy->dev = dev; + + dev_set_drvdata(dev, combophy); + + combophy->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(combophy->base)) + return PTR_ERR(combophy->base); + + ret = stm32_combophy_get_clocks(combophy); + if (ret) + return ret; + + combophy->phy_reset = devm_reset_control_get_exclusive(dev, "phy"); + if (IS_ERR(combophy->phy_reset)) + return dev_err_probe(dev, PTR_ERR(combophy->phy_reset), + "Failed to get PHY reset\n"); + + combophy->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg"); + if (IS_ERR(combophy->regmap)) + return dev_err_probe(dev, PTR_ERR(combophy->regmap), + "No syscfg specified\n"); + + combophy->phy = devm_phy_create(dev, NULL, &stm32_combophy_phy_data); + if (IS_ERR(combophy->phy)) + return dev_err_probe(dev, PTR_ERR(combophy->phy), + "failed to create PCIe/USB3 ComboPHY\n"); + + if (device_property_read_bool(dev, "wakeup-source")) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "failed to get IRQ\n"); + combophy->irq_wakeup = irq; + + ret = devm_request_threaded_irq(dev, combophy->irq_wakeup, NULL, + stm32_combophy_irq_wakeup_handler, IRQF_ONESHOT, + NULL, NULL); + if (ret) + return dev_err_probe(dev, ret, "unable to request wake IRQ %d\n", + combophy->irq_wakeup); + } + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pm runtime\n"); + + phy_set_drvdata(combophy->phy, combophy); + + phy_provider = devm_of_phy_provider_register(dev, stm32_combophy_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct dev_pm_ops stm32_combophy_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_combophy_suspend_noirq, + stm32_combophy_resume_noirq) +}; + +static const struct of_device_id stm32_combophy_of_match[] = { + { .compatible = "st,stm32mp25-combophy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, stm32_combophy_of_match); + +static struct platform_driver stm32_combophy_driver = { + .probe = stm32_combophy_probe, + .driver = { + .name = "stm32-combophy", + .of_match_table = stm32_combophy_of_match, + .pm = pm_sleep_ptr(&stm32_combophy_pm_ops) + } +}; + +module_platform_driver(stm32_combophy_driver); + +MODULE_AUTHOR("Christian Bruel "); +MODULE_DESCRIPTION("STM32MP25 Combophy USB3/PCIe controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index 9dbe60dcf3190d..b917cd413de737 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -812,7 +812,7 @@ MODULE_DEVICE_TABLE(of, stm32_usbphyc_of_match); static struct platform_driver stm32_usbphyc_driver = { .probe = stm32_usbphyc_probe, - .remove_new = stm32_usbphyc_remove, + .remove = stm32_usbphyc_remove, .driver = { .of_match_table = stm32_usbphyc_of_match, .name = "stm32-usbphyc", diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 342f5ccf611d87..79d4814d758d5e 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -543,7 +543,7 @@ static int tegra_xusb_port_init(struct tegra_xusb_port *port, device_initialize(&port->dev); port->dev.type = &tegra_xusb_port_type; - port->dev.of_node = of_node_get(np); + device_set_node(&port->dev, of_fwnode_handle(of_node_get(np))); port->dev.parent = padctl->dev; err = dev_set_name(&port->dev, "%s-%u", name, index); @@ -1327,7 +1327,7 @@ static struct platform_driver tegra_xusb_padctl_driver = { .pm = &tegra_xusb_padctl_pm_ops, }, .probe = tegra_xusb_padctl_probe, - .remove_new = tegra_xusb_padctl_remove, + .remove = tegra_xusb_padctl_remove, }; module_platform_driver(tegra_xusb_padctl_driver); diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c index 3bf3aff4b1c746..431b223996e0a1 100644 --- a/drivers/phy/ti/phy-am654-serdes.c +++ b/drivers/phy/ti/phy-am654-serdes.c @@ -837,7 +837,7 @@ static void serdes_am654_remove(struct platform_device *pdev) static struct platform_driver serdes_am654_driver = { .probe = serdes_am654_probe, - .remove_new = serdes_am654_remove, + .remove = 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 68aa595b6ad8d6..1d81a1e6ec6b6b 100644 --- a/drivers/phy/ti/phy-da8xx-usb.c +++ b/drivers/phy/ti/phy-da8xx-usb.c @@ -277,11 +277,11 @@ MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids); static struct platform_driver da8xx_usb_phy_driver = { .probe = da8xx_usb_phy_probe, - .remove_new = da8xx_usb_phy_remove, + .remove = da8xx_usb_phy_remove, .driver = { .name = "da8xx-usb-phy", .pm = &da8xx_usb_phy_pm_ops, - .of_match_table = da8xx_usb_phy_ids, + .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 d5ae972a31fbc0..e8f842d4e841be 100644 --- a/drivers/phy/ti/phy-dm816x-usb.c +++ b/drivers/phy/ti/phy-dm816x-usb.c @@ -259,7 +259,7 @@ static void dm816x_usb_phy_remove(struct platform_device *pdev) static struct platform_driver dm816x_usb_phy_driver = { .probe = dm816x_usb_phy_probe, - .remove_new = dm816x_usb_phy_remove, + .remove = dm816x_usb_phy_remove, .driver = { .name = "dm816x-usb-phy", .pm = &dm816x_usb_phy_pm_ops, diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 103b266fec7717..e0ca59ae315314 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -230,7 +230,8 @@ static const struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = { .use_of_data = true, .regfields = phy_gmii_sel_fields_am654, - .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII), + .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | + BIT(PHY_INTERFACE_MODE_USXGMII), .num_ports = 4, .num_qsgmii_main_ports = 1, }; diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index c6e846d385d284..ab2a4f2c0a5bf3 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1685,7 +1685,7 @@ static DEFINE_NOIRQ_DEV_PM_OPS(wiz_pm_ops, NULL, wiz_resume_noirq); static struct platform_driver wiz_driver = { .probe = wiz_probe, - .remove_new = wiz_remove, + .remove = 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 78e19b128962a9..c1a0ef979142ce 100644 --- a/drivers/phy/ti/phy-omap-usb2.c +++ b/drivers/phy/ti/phy-omap-usb2.c @@ -511,7 +511,7 @@ static void omap_usb2_remove(struct platform_device *pdev) static struct platform_driver omap_usb2_driver = { .probe = omap_usb2_probe, - .remove_new = omap_usb2_remove, + .remove = 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 874c1a25ce36e6..da2cbacb982c6b 100644 --- a/drivers/phy/ti/phy-ti-pipe3.c +++ b/drivers/phy/ti/phy-ti-pipe3.c @@ -920,7 +920,7 @@ MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); static struct platform_driver ti_pipe3_driver = { .probe = ti_pipe3_probe, - .remove_new = ti_pipe3_remove, + .remove = 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 6b265992d988fa..6f12b38cd894f1 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -834,7 +834,7 @@ MODULE_DEVICE_TABLE(of, twl4030_usb_id_table); static struct platform_driver twl4030_usb_driver = { .probe = twl4030_usb_probe, - .remove_new = twl4030_usb_remove, + .remove = 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 e6579002f11463..05a4a59f7c407f 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -1071,7 +1071,7 @@ MODULE_DEVICE_TABLE(of, xpsgtr_of_match); static struct platform_driver xpsgtr_driver = { .probe = xpsgtr_probe, - .remove_new = xpsgtr_remove, + .remove = xpsgtr_remove, .driver = { .name = "xilinx-psgtr", .of_match_table = xpsgtr_of_match, diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 354536de564b67..95a8e2b9a614ab 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -268,6 +268,17 @@ config PINCTRL_K210 Add support for the Canaan Kendryte K210 RISC-V SOC Field Programmable IO Array (FPIOA) controller. +config PINCTRL_K230 + bool "Pinctrl driver for the Canaan Kendryte K230 SoC" + depends on OF + depends on ARCH_CANAAN || COMPILE_TEST + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select REGMAP_MMIO + help + Add support for the Canaan Kendryte K230 RISC-V SOC pin controller. + config PINCTRL_KEEMBAY tristate "Pinctrl driver for Intel Keem Bay SoC" depends on ARCH_KEEMBAY || (ARM64 && COMPILE_TEST) @@ -551,6 +562,20 @@ config PINCTRL_TPS6594 This driver can also be built as a module called tps6594-pinctrl. +config PINCTRL_TH1520 + tristate "Pinctrl driver for the T-Head TH1520 SoC" + depends on ARCH_THEAD || COMPILE_TEST + depends on OF + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + select PINMUX + help + This is the driver for the pin controller blocks on the + T-Head TH1520 SoC. + + This driver is needed for RISC-V development boards like + the BeagleV Ahead and the LicheePi 4A. + config PINCTRL_ZYNQ bool "Pinctrl driver for Xilinx Zynq" depends on ARCH_ZYNQ @@ -606,6 +631,7 @@ source "drivers/pinctrl/realtek/Kconfig" source "drivers/pinctrl/renesas/Kconfig" source "drivers/pinctrl/samsung/Kconfig" source "drivers/pinctrl/sophgo/Kconfig" +source "drivers/pinctrl/spacemit/Kconfig" source "drivers/pinctrl/spear/Kconfig" source "drivers/pinctrl/sprd/Kconfig" source "drivers/pinctrl/starfive/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 97823f52b972a3..fba1c56624c0d8 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_PINCTRL_EYEQ5) += pinctrl-eyeq5.o obj-$(CONFIG_PINCTRL_GEMINI) += pinctrl-gemini.o obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o +obj-$(CONFIG_PINCTRL_K230) += pinctrl-k230.o obj-$(CONFIG_PINCTRL_KEEMBAY) += pinctrl-keembay.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o @@ -54,6 +55,7 @@ obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o obj-$(CONFIG_PINCTRL_TPS6594) += pinctrl-tps6594.o +obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o @@ -76,6 +78,7 @@ obj-$(CONFIG_ARCH_REALTEK) += realtek/ obj-$(CONFIG_PINCTRL_RENESAS) += renesas/ obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/ obj-y += sophgo/ +obj-y += spacemit/ obj-$(CONFIG_PINCTRL_SPEAR) += spear/ obj-y += sprd/ obj-$(CONFIG_SOC_STARFIVE) += starfive/ diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c index 6ecc656abc44fa..5a7cd0a8868764 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c @@ -2607,6 +2607,10 @@ static struct aspeed_pin_config aspeed_g6_configs[] = { { PIN_CONFIG_DRIVE_STRENGTH, { AB8, AB8 }, SCU454, GENMASK(27, 26)}, /* LAD0 */ { PIN_CONFIG_DRIVE_STRENGTH, { AB7, AB7 }, SCU454, GENMASK(25, 24)}, + /* GPIOF */ + { PIN_CONFIG_DRIVE_STRENGTH, { D22, A23 }, SCU458, GENMASK(9, 8)}, + /* GPIOG */ + { PIN_CONFIG_DRIVE_STRENGTH, { E21, B21 }, SCU458, GENMASK(11, 10)}, /* MAC3 */ { PIN_CONFIG_POWER_SOURCE, { H24, E26 }, SCU458, BIT_MASK(4)}, diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c index fd5ce52d05b1d4..c9a3d3aa8c1086 100644 --- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c +++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c @@ -309,7 +309,7 @@ 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)); + seq_puts(p, dev_name(chip->dev)); } static const struct irq_chip iproc_gpio_irq_chip = { diff --git a/drivers/pinctrl/cirrus/pinctrl-madera-core.c b/drivers/pinctrl/cirrus/pinctrl-madera-core.c index 2932d7aba72550..73ec5b9beb49f2 100644 --- a/drivers/pinctrl/cirrus/pinctrl-madera-core.c +++ b/drivers/pinctrl/cirrus/pinctrl-madera-core.c @@ -1091,7 +1091,7 @@ static void madera_pin_remove(struct platform_device *pdev) static struct platform_driver madera_pin_driver = { .probe = madera_pin_probe, - .remove_new = madera_pin_remove, + .remove = madera_pin_remove, .driver = { .name = "madera-pinctrl", }, diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 4061890a174835..b3eec63c00ba04 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -220,6 +220,9 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev, /* Set owner */ pindesc->pctldev = pctldev; +#ifdef CONFIG_PINMUX + mutex_init(&pindesc->mux_lock); +#endif /* Copy basic pin info */ if (pin->name) { diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 4e07707d2435bd..d6c24978e7081a 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -177,6 +177,7 @@ struct pin_desc { const char *mux_owner; const struct pinctrl_setting_mux *mux_setting; const char *gpio_owner; + struct mutex mux_lock; #endif }; diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 3b59d71890045b..4c420b21b804d1 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -9,7 +9,7 @@ config PINCTRL_IMX config PINCTRL_IMX_SCMI tristate "i.MX95 pinctrl driver using SCMI protocol interface" - depends on ARM_SCMI_PROTOCOL && OF || COMPILE_TEST + depends on ARM_SCMI_PROTOCOL && OF select PINMUX select GENERIC_PINCONF select GENERIC_PINCTRL_GROUPS @@ -20,7 +20,7 @@ config PINCTRL_IMX_SCMI config PINCTRL_IMX_SCU tristate - depends on IMX_SCU + depends on IMX_SCU || COMPILE_TEST select PINCTRL_IMX config PINCTRL_IMX1_CORE @@ -30,14 +30,18 @@ config PINCTRL_IMX1_CORE config PINCTRL_IMX1 bool "IMX1 pinctrl driver" - depends on SOC_IMX1 + depends on OF + depends on SOC_IMX1 || COMPILE_TEST + default SOC_IMX1 select PINCTRL_IMX1_CORE help Say Y here to enable the imx1 pinctrl driver config PINCTRL_IMX27 bool "IMX27 pinctrl driver" - depends on SOC_IMX27 + depends on OF + depends on SOC_IMX27 || COMPILE_TEST + default SOC_IMX27 select PINCTRL_IMX1_CORE help Say Y here to enable the imx27 pinctrl driver @@ -46,84 +50,107 @@ config PINCTRL_IMX27 config PINCTRL_IMX25 bool "IMX25 pinctrl driver" depends on OF - depends on SOC_IMX25 + depends on SOC_IMX25 || COMPILE_TEST + default SOC_IMX25 select PINCTRL_IMX help Say Y here to enable the imx25 pinctrl driver config PINCTRL_IMX35 bool "IMX35 pinctrl driver" - depends on SOC_IMX35 + depends on OF + depends on SOC_IMX35 || COMPILE_TEST + default SOC_IMX35 select PINCTRL_IMX help Say Y here to enable the imx35 pinctrl driver config PINCTRL_IMX50 bool "IMX50 pinctrl driver" - depends on SOC_IMX50 + depends on OF + depends on SOC_IMX50 || COMPILE_TEST + default SOC_IMX50 select PINCTRL_IMX help Say Y here to enable the imx50 pinctrl driver config PINCTRL_IMX51 bool "IMX51 pinctrl driver" - depends on SOC_IMX51 + depends on OF + depends on SOC_IMX51 || COMPILE_TEST + default SOC_IMX51 select PINCTRL_IMX help Say Y here to enable the imx51 pinctrl driver config PINCTRL_IMX53 bool "IMX53 pinctrl driver" - depends on SOC_IMX53 + depends on OF + depends on SOC_IMX53 || COMPILE_TEST + default SOC_IMX53 select PINCTRL_IMX help Say Y here to enable the imx53 pinctrl driver config PINCTRL_IMX6Q bool "IMX6Q/DL pinctrl driver" - depends on SOC_IMX6Q + depends on OF + depends on SOC_IMX6Q || COMPILE_TEST + default SOC_IMX6Q select PINCTRL_IMX help Say Y here to enable the imx6q/dl pinctrl driver config PINCTRL_IMX6SL bool "IMX6SL pinctrl driver" - depends on SOC_IMX6SL + depends on OF + depends on SOC_IMX6SL || COMPILE_TEST + default SOC_IMX6SL select PINCTRL_IMX help Say Y here to enable the imx6sl pinctrl driver config PINCTRL_IMX6SLL bool "IMX6SLL pinctrl driver" - depends on SOC_IMX6SLL + depends on OF + depends on SOC_IMX6SLL || COMPILE_TEST + default SOC_IMX6SLL select PINCTRL_IMX help Say Y here to enable the imx6sll pinctrl driver config PINCTRL_IMX6SX bool "IMX6SX pinctrl driver" - depends on SOC_IMX6SX + depends on OF + depends on SOC_IMX6SX || COMPILE_TEST + default SOC_IMX6SX select PINCTRL_IMX help Say Y here to enable the imx6sx pinctrl driver config PINCTRL_IMX6UL bool "IMX6UL pinctrl driver" - depends on SOC_IMX6UL + depends on OF + depends on SOC_IMX6UL || COMPILE_TEST + default SOC_IMX6UL select PINCTRL_IMX help Say Y here to enable the imx6ul pinctrl driver config PINCTRL_IMX7D bool "IMX7D pinctrl driver" - depends on SOC_IMX7D + depends on OF + depends on SOC_IMX7D || COMPILE_TEST + default SOC_IMX7D select PINCTRL_IMX help Say Y here to enable the imx7d pinctrl driver config PINCTRL_IMX7ULP bool "IMX7ULP pinctrl driver" - depends on SOC_IMX7ULP + depends on OF + depends on SOC_IMX7ULP || COMPILE_TEST + default SOC_IMX7ULP select PINCTRL_IMX help Say Y here to enable the imx7ulp pinctrl driver @@ -131,7 +158,7 @@ config PINCTRL_IMX7ULP config PINCTRL_IMX8MM tristate "IMX8MM pinctrl driver" depends on OF - depends on SOC_IMX8M + depends on SOC_IMX8M || COMPILE_TEST select PINCTRL_IMX help Say Y here to enable the imx8mm pinctrl driver @@ -139,7 +166,7 @@ config PINCTRL_IMX8MM config PINCTRL_IMX8MN tristate "IMX8MN pinctrl driver" depends on OF - depends on SOC_IMX8M + depends on SOC_IMX8M || COMPILE_TEST select PINCTRL_IMX help Say Y here to enable the imx8mn pinctrl driver @@ -147,7 +174,7 @@ config PINCTRL_IMX8MN config PINCTRL_IMX8MP tristate "IMX8MP pinctrl driver" depends on OF - depends on SOC_IMX8M + depends on SOC_IMX8M || COMPILE_TEST select PINCTRL_IMX help Say Y here to enable the imx8mp pinctrl driver @@ -155,42 +182,48 @@ config PINCTRL_IMX8MP config PINCTRL_IMX8MQ tristate "IMX8MQ pinctrl driver" depends on OF - depends on SOC_IMX8M + depends on SOC_IMX8M || COMPILE_TEST select PINCTRL_IMX help Say Y here to enable the imx8mq pinctrl driver config PINCTRL_IMX8QM tristate "IMX8QM pinctrl driver" - depends on IMX_SCU && ARCH_MXC && ARM64 + depends on OF + depends on (IMX_SCU && ARCH_MXC && ARM64) || COMPILE_TEST select PINCTRL_IMX_SCU help Say Y here to enable the imx8qm pinctrl driver config PINCTRL_IMX8QXP tristate "IMX8QXP pinctrl driver" - depends on IMX_SCU && ARCH_MXC && ARM64 + depends on OF + depends on (IMX_SCU && ARCH_MXC && ARM64) || COMPILE_TEST select PINCTRL_IMX_SCU help Say Y here to enable the imx8qxp pinctrl driver config PINCTRL_IMX8DXL tristate "IMX8DXL pinctrl driver" - depends on IMX_SCU && ARCH_MXC && ARM64 + depends on OF + depends on (IMX_SCU && ARCH_MXC && ARM64) || COMPILE_TEST select PINCTRL_IMX_SCU help Say Y here to enable the imx8dxl pinctrl driver config PINCTRL_IMX8ULP tristate "IMX8ULP pinctrl driver" - depends on ARCH_MXC + depends on OF + depends on ARCH_MXC || COMPILE_TEST select PINCTRL_IMX help Say Y here to enable the imx8ulp pinctrl driver config PINCTRL_IMXRT1050 bool "IMXRT1050 pinctrl driver" - depends on ARCH_MXC + depends on OF + depends on SOC_IMXRT || COMPILE_TEST + default SOC_IMXRT select PINCTRL_IMX help Say Y here to enable the imxrt1050 pinctrl driver @@ -204,14 +237,17 @@ config PINCTRL_IMX91 config PINCTRL_IMX93 tristate "IMX93 pinctrl driver" - depends on ARCH_MXC + depends on OF + depends on ARCH_MXC || COMPILE_TEST select PINCTRL_IMX help Say Y here to enable the imx93 pinctrl driver config PINCTRL_VF610 bool "Freescale Vybrid VF610 pinctrl driver" - depends on SOC_VF610 + depends on OF + depends on SOC_VF610 || COMPILE_TEST + default SOC_VF610 select PINCTRL_IMX help Say Y here to enable the Freescale Vybrid VF610 pinctrl driver @@ -231,7 +267,8 @@ config PINCTRL_IMX28 config PINCTRL_IMXRT1170 bool "IMXRT1170 pinctrl driver" - depends on ARCH_MXC + depends on OF + depends on SOC_IMXRT || COMPILE_TEST select PINCTRL_IMX help Say Y here to enable the imxrt1170 pinctrl driver diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index d05c2c478e7950..842a1e6cbfc41a 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -633,11 +633,11 @@ static int imx_pinctrl_parse_functions(struct device_node *np, static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np) { for_each_child_of_node_scoped(np, function_np) { - if (of_property_read_bool(function_np, "fsl,pins")) + if (of_property_present(function_np, "fsl,pins")) return true; for_each_child_of_node_scoped(function_np, pinctrl_np) { - if (of_property_read_bool(pinctrl_np, "fsl,pins")) + if (of_property_present(pinctrl_np, "fsl,pins")) return false; } } @@ -746,7 +746,7 @@ int imx_pinctrl_probe(struct platform_device *pdev, if (IS_ERR(ipctl->base)) return PTR_ERR(ipctl->base); - if (of_property_read_bool(dev_np, "fsl,input-sel")) { + if (of_property_present(dev_np, "fsl,input-sel")) { np = of_parse_phandle(dev_np, "fsl,input-sel", 0); if (!np) { dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n"); diff --git a/drivers/pinctrl/freescale/pinctrl-imx1.c b/drivers/pinctrl/freescale/pinctrl-imx1.c index 1e2b0fe9ffd6fd..bd39cadf1f34d3 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1.c @@ -12,122 +12,122 @@ #include "pinctrl-imx1.h" #define PAD_ID(port, pin) ((port) * 32 + (pin)) -#define PA 0 -#define PB 1 -#define PC 2 -#define PD 3 +#define IMX1_PA 0 +#define IMX1_PB 1 +#define IMX1_PC 2 +#define IMX1_PD 3 enum imx1_pads { - MX1_PAD_A24 = PAD_ID(PA, 0), - MX1_PAD_TIN = PAD_ID(PA, 1), - MX1_PAD_PWMO = PAD_ID(PA, 2), - MX1_PAD_CSI_MCLK = PAD_ID(PA, 3), - MX1_PAD_CSI_D0 = PAD_ID(PA, 4), - MX1_PAD_CSI_D1 = PAD_ID(PA, 5), - MX1_PAD_CSI_D2 = PAD_ID(PA, 6), - MX1_PAD_CSI_D3 = PAD_ID(PA, 7), - MX1_PAD_CSI_D4 = PAD_ID(PA, 8), - MX1_PAD_CSI_D5 = PAD_ID(PA, 9), - MX1_PAD_CSI_D6 = PAD_ID(PA, 10), - MX1_PAD_CSI_D7 = PAD_ID(PA, 11), - MX1_PAD_CSI_VSYNC = PAD_ID(PA, 12), - MX1_PAD_CSI_HSYNC = PAD_ID(PA, 13), - MX1_PAD_CSI_PIXCLK = PAD_ID(PA, 14), - MX1_PAD_I2C_SDA = PAD_ID(PA, 15), - MX1_PAD_I2C_SCL = PAD_ID(PA, 16), - MX1_PAD_DTACK = PAD_ID(PA, 17), - MX1_PAD_BCLK = PAD_ID(PA, 18), - MX1_PAD_LBA = PAD_ID(PA, 19), - MX1_PAD_ECB = PAD_ID(PA, 20), - MX1_PAD_A0 = PAD_ID(PA, 21), - MX1_PAD_CS4 = PAD_ID(PA, 22), - MX1_PAD_CS5 = PAD_ID(PA, 23), - MX1_PAD_A16 = PAD_ID(PA, 24), - MX1_PAD_A17 = PAD_ID(PA, 25), - MX1_PAD_A18 = PAD_ID(PA, 26), - MX1_PAD_A19 = PAD_ID(PA, 27), - MX1_PAD_A20 = PAD_ID(PA, 28), - MX1_PAD_A21 = PAD_ID(PA, 29), - MX1_PAD_A22 = PAD_ID(PA, 30), - MX1_PAD_A23 = PAD_ID(PA, 31), - MX1_PAD_SD_DAT0 = PAD_ID(PB, 8), - MX1_PAD_SD_DAT1 = PAD_ID(PB, 9), - MX1_PAD_SD_DAT2 = PAD_ID(PB, 10), - MX1_PAD_SD_DAT3 = PAD_ID(PB, 11), - MX1_PAD_SD_SCLK = PAD_ID(PB, 12), - MX1_PAD_SD_CMD = PAD_ID(PB, 13), - MX1_PAD_SIM_SVEN = PAD_ID(PB, 14), - MX1_PAD_SIM_PD = PAD_ID(PB, 15), - MX1_PAD_SIM_TX = PAD_ID(PB, 16), - MX1_PAD_SIM_RX = PAD_ID(PB, 17), - MX1_PAD_SIM_RST = PAD_ID(PB, 18), - MX1_PAD_SIM_CLK = PAD_ID(PB, 19), - MX1_PAD_USBD_AFE = PAD_ID(PB, 20), - MX1_PAD_USBD_OE = PAD_ID(PB, 21), - MX1_PAD_USBD_RCV = PAD_ID(PB, 22), - MX1_PAD_USBD_SUSPND = PAD_ID(PB, 23), - MX1_PAD_USBD_VP = PAD_ID(PB, 24), - MX1_PAD_USBD_VM = PAD_ID(PB, 25), - MX1_PAD_USBD_VPO = PAD_ID(PB, 26), - MX1_PAD_USBD_VMO = PAD_ID(PB, 27), - MX1_PAD_UART2_CTS = PAD_ID(PB, 28), - MX1_PAD_UART2_RTS = PAD_ID(PB, 29), - MX1_PAD_UART2_TXD = PAD_ID(PB, 30), - MX1_PAD_UART2_RXD = PAD_ID(PB, 31), - MX1_PAD_SSI_RXFS = PAD_ID(PC, 3), - MX1_PAD_SSI_RXCLK = PAD_ID(PC, 4), - MX1_PAD_SSI_RXDAT = PAD_ID(PC, 5), - MX1_PAD_SSI_TXDAT = PAD_ID(PC, 6), - MX1_PAD_SSI_TXFS = PAD_ID(PC, 7), - MX1_PAD_SSI_TXCLK = PAD_ID(PC, 8), - MX1_PAD_UART1_CTS = PAD_ID(PC, 9), - MX1_PAD_UART1_RTS = PAD_ID(PC, 10), - MX1_PAD_UART1_TXD = PAD_ID(PC, 11), - MX1_PAD_UART1_RXD = PAD_ID(PC, 12), - MX1_PAD_SPI1_RDY = PAD_ID(PC, 13), - MX1_PAD_SPI1_SCLK = PAD_ID(PC, 14), - MX1_PAD_SPI1_SS = PAD_ID(PC, 15), - MX1_PAD_SPI1_MISO = PAD_ID(PC, 16), - MX1_PAD_SPI1_MOSI = PAD_ID(PC, 17), - MX1_PAD_BT13 = PAD_ID(PC, 19), - MX1_PAD_BT12 = PAD_ID(PC, 20), - MX1_PAD_BT11 = PAD_ID(PC, 21), - MX1_PAD_BT10 = PAD_ID(PC, 22), - MX1_PAD_BT9 = PAD_ID(PC, 23), - MX1_PAD_BT8 = PAD_ID(PC, 24), - MX1_PAD_BT7 = PAD_ID(PC, 25), - MX1_PAD_BT6 = PAD_ID(PC, 26), - MX1_PAD_BT5 = PAD_ID(PC, 27), - MX1_PAD_BT4 = PAD_ID(PC, 28), - MX1_PAD_BT3 = PAD_ID(PC, 29), - MX1_PAD_BT2 = PAD_ID(PC, 30), - MX1_PAD_BT1 = PAD_ID(PC, 31), - MX1_PAD_LSCLK = PAD_ID(PD, 6), - MX1_PAD_REV = PAD_ID(PD, 7), - MX1_PAD_CLS = PAD_ID(PD, 8), - MX1_PAD_PS = PAD_ID(PD, 9), - MX1_PAD_SPL_SPR = PAD_ID(PD, 10), - MX1_PAD_CONTRAST = PAD_ID(PD, 11), - MX1_PAD_ACD_OE = PAD_ID(PD, 12), - MX1_PAD_LP_HSYNC = PAD_ID(PD, 13), - MX1_PAD_FLM_VSYNC = PAD_ID(PD, 14), - MX1_PAD_LD0 = PAD_ID(PD, 15), - MX1_PAD_LD1 = PAD_ID(PD, 16), - MX1_PAD_LD2 = PAD_ID(PD, 17), - MX1_PAD_LD3 = PAD_ID(PD, 18), - MX1_PAD_LD4 = PAD_ID(PD, 19), - MX1_PAD_LD5 = PAD_ID(PD, 20), - MX1_PAD_LD6 = PAD_ID(PD, 21), - MX1_PAD_LD7 = PAD_ID(PD, 22), - MX1_PAD_LD8 = PAD_ID(PD, 23), - MX1_PAD_LD9 = PAD_ID(PD, 24), - MX1_PAD_LD10 = PAD_ID(PD, 25), - MX1_PAD_LD11 = PAD_ID(PD, 26), - MX1_PAD_LD12 = PAD_ID(PD, 27), - MX1_PAD_LD13 = PAD_ID(PD, 28), - MX1_PAD_LD14 = PAD_ID(PD, 29), - MX1_PAD_LD15 = PAD_ID(PD, 30), - MX1_PAD_TMR2OUT = PAD_ID(PD, 31), + MX1_PAD_A24 = PAD_ID(IMX1_PA, 0), + MX1_PAD_TIN = PAD_ID(IMX1_PA, 1), + MX1_PAD_PWMO = PAD_ID(IMX1_PA, 2), + MX1_PAD_CSI_MCLK = PAD_ID(IMX1_PA, 3), + MX1_PAD_CSI_D0 = PAD_ID(IMX1_PA, 4), + MX1_PAD_CSI_D1 = PAD_ID(IMX1_PA, 5), + MX1_PAD_CSI_D2 = PAD_ID(IMX1_PA, 6), + MX1_PAD_CSI_D3 = PAD_ID(IMX1_PA, 7), + MX1_PAD_CSI_D4 = PAD_ID(IMX1_PA, 8), + MX1_PAD_CSI_D5 = PAD_ID(IMX1_PA, 9), + MX1_PAD_CSI_D6 = PAD_ID(IMX1_PA, 10), + MX1_PAD_CSI_D7 = PAD_ID(IMX1_PA, 11), + MX1_PAD_CSI_VSYNC = PAD_ID(IMX1_PA, 12), + MX1_PAD_CSI_HSYNC = PAD_ID(IMX1_PA, 13), + MX1_PAD_CSI_PIXCLK = PAD_ID(IMX1_PA, 14), + MX1_PAD_I2C_SDA = PAD_ID(IMX1_PA, 15), + MX1_PAD_I2C_SCL = PAD_ID(IMX1_PA, 16), + MX1_PAD_DTACK = PAD_ID(IMX1_PA, 17), + MX1_PAD_BCLK = PAD_ID(IMX1_PA, 18), + MX1_PAD_LBA = PAD_ID(IMX1_PA, 19), + MX1_PAD_ECB = PAD_ID(IMX1_PA, 20), + MX1_PAD_A0 = PAD_ID(IMX1_PA, 21), + MX1_PAD_CS4 = PAD_ID(IMX1_PA, 22), + MX1_PAD_CS5 = PAD_ID(IMX1_PA, 23), + MX1_PAD_A16 = PAD_ID(IMX1_PA, 24), + MX1_PAD_A17 = PAD_ID(IMX1_PA, 25), + MX1_PAD_A18 = PAD_ID(IMX1_PA, 26), + MX1_PAD_A19 = PAD_ID(IMX1_PA, 27), + MX1_PAD_A20 = PAD_ID(IMX1_PA, 28), + MX1_PAD_A21 = PAD_ID(IMX1_PA, 29), + MX1_PAD_A22 = PAD_ID(IMX1_PA, 30), + MX1_PAD_A23 = PAD_ID(IMX1_PA, 31), + MX1_PAD_SD_DAT0 = PAD_ID(IMX1_PB, 8), + MX1_PAD_SD_DAT1 = PAD_ID(IMX1_PB, 9), + MX1_PAD_SD_DAT2 = PAD_ID(IMX1_PB, 10), + MX1_PAD_SD_DAT3 = PAD_ID(IMX1_PB, 11), + MX1_PAD_SD_SCLK = PAD_ID(IMX1_PB, 12), + MX1_PAD_SD_CMD = PAD_ID(IMX1_PB, 13), + MX1_PAD_SIM_SVEN = PAD_ID(IMX1_PB, 14), + MX1_PAD_SIM_PD = PAD_ID(IMX1_PB, 15), + MX1_PAD_SIM_TX = PAD_ID(IMX1_PB, 16), + MX1_PAD_SIM_RX = PAD_ID(IMX1_PB, 17), + MX1_PAD_SIM_RST = PAD_ID(IMX1_PB, 18), + MX1_PAD_SIM_CLK = PAD_ID(IMX1_PB, 19), + MX1_PAD_USBD_AFE = PAD_ID(IMX1_PB, 20), + MX1_PAD_USBD_OE = PAD_ID(IMX1_PB, 21), + MX1_PAD_USBD_RCV = PAD_ID(IMX1_PB, 22), + MX1_PAD_USBD_SUSPND = PAD_ID(IMX1_PB, 23), + MX1_PAD_USBD_VP = PAD_ID(IMX1_PB, 24), + MX1_PAD_USBD_VM = PAD_ID(IMX1_PB, 25), + MX1_PAD_USBD_VPO = PAD_ID(IMX1_PB, 26), + MX1_PAD_USBD_VMO = PAD_ID(IMX1_PB, 27), + MX1_PAD_UART2_CTS = PAD_ID(IMX1_PB, 28), + MX1_PAD_UART2_RTS = PAD_ID(IMX1_PB, 29), + MX1_PAD_UART2_TXD = PAD_ID(IMX1_PB, 30), + MX1_PAD_UART2_RXD = PAD_ID(IMX1_PB, 31), + MX1_PAD_SSI_RXFS = PAD_ID(IMX1_PC, 3), + MX1_PAD_SSI_RXCLK = PAD_ID(IMX1_PC, 4), + MX1_PAD_SSI_RXDAT = PAD_ID(IMX1_PC, 5), + MX1_PAD_SSI_TXDAT = PAD_ID(IMX1_PC, 6), + MX1_PAD_SSI_TXFS = PAD_ID(IMX1_PC, 7), + MX1_PAD_SSI_TXCLK = PAD_ID(IMX1_PC, 8), + MX1_PAD_UART1_CTS = PAD_ID(IMX1_PC, 9), + MX1_PAD_UART1_RTS = PAD_ID(IMX1_PC, 10), + MX1_PAD_UART1_TXD = PAD_ID(IMX1_PC, 11), + MX1_PAD_UART1_RXD = PAD_ID(IMX1_PC, 12), + MX1_PAD_SPI1_RDY = PAD_ID(IMX1_PC, 13), + MX1_PAD_SPI1_SCLK = PAD_ID(IMX1_PC, 14), + MX1_PAD_SPI1_SS = PAD_ID(IMX1_PC, 15), + MX1_PAD_SPI1_MISO = PAD_ID(IMX1_PC, 16), + MX1_PAD_SPI1_MOSI = PAD_ID(IMX1_PC, 17), + MX1_PAD_BT13 = PAD_ID(IMX1_PC, 19), + MX1_PAD_BT12 = PAD_ID(IMX1_PC, 20), + MX1_PAD_BT11 = PAD_ID(IMX1_PC, 21), + MX1_PAD_BT10 = PAD_ID(IMX1_PC, 22), + MX1_PAD_BT9 = PAD_ID(IMX1_PC, 23), + MX1_PAD_BT8 = PAD_ID(IMX1_PC, 24), + MX1_PAD_BT7 = PAD_ID(IMX1_PC, 25), + MX1_PAD_BT6 = PAD_ID(IMX1_PC, 26), + MX1_PAD_BT5 = PAD_ID(IMX1_PC, 27), + MX1_PAD_BT4 = PAD_ID(IMX1_PC, 28), + MX1_PAD_BT3 = PAD_ID(IMX1_PC, 29), + MX1_PAD_BT2 = PAD_ID(IMX1_PC, 30), + MX1_PAD_BT1 = PAD_ID(IMX1_PC, 31), + MX1_PAD_LSCLK = PAD_ID(IMX1_PD, 6), + MX1_PAD_REV = PAD_ID(IMX1_PD, 7), + MX1_PAD_CLS = PAD_ID(IMX1_PD, 8), + MX1_PAD_PS = PAD_ID(IMX1_PD, 9), + MX1_PAD_SPL_SPR = PAD_ID(IMX1_PD, 10), + MX1_PAD_CONTRAST = PAD_ID(IMX1_PD, 11), + MX1_PAD_ACD_OE = PAD_ID(IMX1_PD, 12), + MX1_PAD_LP_HSYNC = PAD_ID(IMX1_PD, 13), + MX1_PAD_FLM_VSYNC = PAD_ID(IMX1_PD, 14), + MX1_PAD_LD0 = PAD_ID(IMX1_PD, 15), + MX1_PAD_LD1 = PAD_ID(IMX1_PD, 16), + MX1_PAD_LD2 = PAD_ID(IMX1_PD, 17), + MX1_PAD_LD3 = PAD_ID(IMX1_PD, 18), + MX1_PAD_LD4 = PAD_ID(IMX1_PD, 19), + MX1_PAD_LD5 = PAD_ID(IMX1_PD, 20), + MX1_PAD_LD6 = PAD_ID(IMX1_PD, 21), + MX1_PAD_LD7 = PAD_ID(IMX1_PD, 22), + MX1_PAD_LD8 = PAD_ID(IMX1_PD, 23), + MX1_PAD_LD9 = PAD_ID(IMX1_PD, 24), + MX1_PAD_LD10 = PAD_ID(IMX1_PD, 25), + MX1_PAD_LD11 = PAD_ID(IMX1_PD, 26), + MX1_PAD_LD12 = PAD_ID(IMX1_PD, 27), + MX1_PAD_LD13 = PAD_ID(IMX1_PD, 28), + MX1_PAD_LD14 = PAD_ID(IMX1_PD, 29), + MX1_PAD_LD15 = PAD_ID(IMX1_PD, 30), + MX1_PAD_TMR2OUT = PAD_ID(IMX1_PD, 31), }; /* Pad names for the pinmux subsystem */ diff --git a/drivers/pinctrl/freescale/pinctrl-imx27.c b/drivers/pinctrl/freescale/pinctrl-imx27.c index 1738df46123511..afeb3995720362 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx27.c +++ b/drivers/pinctrl/freescale/pinctrl-imx27.c @@ -16,188 +16,188 @@ #include "pinctrl-imx1.h" #define PAD_ID(port, pin) (port*32 + pin) -#define PA 0 -#define PB 1 -#define PC 2 -#define PD 3 -#define PE 4 -#define PF 5 +#define MX27_PA 0 +#define MX27_PB 1 +#define MX27_PC 2 +#define MX27_PD 3 +#define MX27_PE 4 +#define MX27_PF 5 enum imx27_pads { - MX27_PAD_USBH2_CLK = PAD_ID(PA, 0), - MX27_PAD_USBH2_DIR = PAD_ID(PA, 1), - MX27_PAD_USBH2_DATA7 = PAD_ID(PA, 2), - MX27_PAD_USBH2_NXT = PAD_ID(PA, 3), - MX27_PAD_USBH2_STP = PAD_ID(PA, 4), - MX27_PAD_LSCLK = PAD_ID(PA, 5), - MX27_PAD_LD0 = PAD_ID(PA, 6), - MX27_PAD_LD1 = PAD_ID(PA, 7), - MX27_PAD_LD2 = PAD_ID(PA, 8), - MX27_PAD_LD3 = PAD_ID(PA, 9), - MX27_PAD_LD4 = PAD_ID(PA, 10), - MX27_PAD_LD5 = PAD_ID(PA, 11), - MX27_PAD_LD6 = PAD_ID(PA, 12), - MX27_PAD_LD7 = PAD_ID(PA, 13), - MX27_PAD_LD8 = PAD_ID(PA, 14), - MX27_PAD_LD9 = PAD_ID(PA, 15), - MX27_PAD_LD10 = PAD_ID(PA, 16), - MX27_PAD_LD11 = PAD_ID(PA, 17), - MX27_PAD_LD12 = PAD_ID(PA, 18), - MX27_PAD_LD13 = PAD_ID(PA, 19), - MX27_PAD_LD14 = PAD_ID(PA, 20), - MX27_PAD_LD15 = PAD_ID(PA, 21), - MX27_PAD_LD16 = PAD_ID(PA, 22), - MX27_PAD_LD17 = PAD_ID(PA, 23), - MX27_PAD_REV = PAD_ID(PA, 24), - MX27_PAD_CLS = PAD_ID(PA, 25), - MX27_PAD_PS = PAD_ID(PA, 26), - MX27_PAD_SPL_SPR = PAD_ID(PA, 27), - MX27_PAD_HSYNC = PAD_ID(PA, 28), - MX27_PAD_VSYNC = PAD_ID(PA, 29), - MX27_PAD_CONTRAST = PAD_ID(PA, 30), - MX27_PAD_OE_ACD = PAD_ID(PA, 31), + MX27_PAD_USBH2_CLK = PAD_ID(MX27_PA, 0), + MX27_PAD_USBH2_DIR = PAD_ID(MX27_PA, 1), + MX27_PAD_USBH2_DATA7 = PAD_ID(MX27_PA, 2), + MX27_PAD_USBH2_NXT = PAD_ID(MX27_PA, 3), + MX27_PAD_USBH2_STP = PAD_ID(MX27_PA, 4), + MX27_PAD_LSCLK = PAD_ID(MX27_PA, 5), + MX27_PAD_LD0 = PAD_ID(MX27_PA, 6), + MX27_PAD_LD1 = PAD_ID(MX27_PA, 7), + MX27_PAD_LD2 = PAD_ID(MX27_PA, 8), + MX27_PAD_LD3 = PAD_ID(MX27_PA, 9), + MX27_PAD_LD4 = PAD_ID(MX27_PA, 10), + MX27_PAD_LD5 = PAD_ID(MX27_PA, 11), + MX27_PAD_LD6 = PAD_ID(MX27_PA, 12), + MX27_PAD_LD7 = PAD_ID(MX27_PA, 13), + MX27_PAD_LD8 = PAD_ID(MX27_PA, 14), + MX27_PAD_LD9 = PAD_ID(MX27_PA, 15), + MX27_PAD_LD10 = PAD_ID(MX27_PA, 16), + MX27_PAD_LD11 = PAD_ID(MX27_PA, 17), + MX27_PAD_LD12 = PAD_ID(MX27_PA, 18), + MX27_PAD_LD13 = PAD_ID(MX27_PA, 19), + MX27_PAD_LD14 = PAD_ID(MX27_PA, 20), + MX27_PAD_LD15 = PAD_ID(MX27_PA, 21), + MX27_PAD_LD16 = PAD_ID(MX27_PA, 22), + MX27_PAD_LD17 = PAD_ID(MX27_PA, 23), + MX27_PAD_REV = PAD_ID(MX27_PA, 24), + MX27_PAD_CLS = PAD_ID(MX27_PA, 25), + MX27_PAD_PS = PAD_ID(MX27_PA, 26), + MX27_PAD_SPL_SPR = PAD_ID(MX27_PA, 27), + MX27_PAD_HSYNC = PAD_ID(MX27_PA, 28), + MX27_PAD_VSYNC = PAD_ID(MX27_PA, 29), + MX27_PAD_CONTRAST = PAD_ID(MX27_PA, 30), + MX27_PAD_OE_ACD = PAD_ID(MX27_PA, 31), - MX27_PAD_SD2_D0 = PAD_ID(PB, 4), - MX27_PAD_SD2_D1 = PAD_ID(PB, 5), - MX27_PAD_SD2_D2 = PAD_ID(PB, 6), - MX27_PAD_SD2_D3 = PAD_ID(PB, 7), - MX27_PAD_SD2_CMD = PAD_ID(PB, 8), - MX27_PAD_SD2_CLK = PAD_ID(PB, 9), - MX27_PAD_CSI_D0 = PAD_ID(PB, 10), - MX27_PAD_CSI_D1 = PAD_ID(PB, 11), - MX27_PAD_CSI_D2 = PAD_ID(PB, 12), - MX27_PAD_CSI_D3 = PAD_ID(PB, 13), - MX27_PAD_CSI_D4 = PAD_ID(PB, 14), - MX27_PAD_CSI_MCLK = PAD_ID(PB, 15), - MX27_PAD_CSI_PIXCLK = PAD_ID(PB, 16), - MX27_PAD_CSI_D5 = PAD_ID(PB, 17), - MX27_PAD_CSI_D6 = PAD_ID(PB, 18), - MX27_PAD_CSI_D7 = PAD_ID(PB, 19), - MX27_PAD_CSI_VSYNC = PAD_ID(PB, 20), - MX27_PAD_CSI_HSYNC = PAD_ID(PB, 21), - MX27_PAD_USBH1_SUSP = PAD_ID(PB, 22), - MX27_PAD_USB_PWR = PAD_ID(PB, 23), - MX27_PAD_USB_OC_B = PAD_ID(PB, 24), - MX27_PAD_USBH1_RCV = PAD_ID(PB, 25), - MX27_PAD_USBH1_FS = PAD_ID(PB, 26), - MX27_PAD_USBH1_OE_B = PAD_ID(PB, 27), - MX27_PAD_USBH1_TXDM = PAD_ID(PB, 28), - MX27_PAD_USBH1_TXDP = PAD_ID(PB, 29), - MX27_PAD_USBH1_RXDM = PAD_ID(PB, 30), - MX27_PAD_USBH1_RXDP = PAD_ID(PB, 31), + MX27_PAD_SD2_D0 = PAD_ID(MX27_PB, 4), + MX27_PAD_SD2_D1 = PAD_ID(MX27_PB, 5), + MX27_PAD_SD2_D2 = PAD_ID(MX27_PB, 6), + MX27_PAD_SD2_D3 = PAD_ID(MX27_PB, 7), + MX27_PAD_SD2_CMD = PAD_ID(MX27_PB, 8), + MX27_PAD_SD2_CLK = PAD_ID(MX27_PB, 9), + MX27_PAD_CSI_D0 = PAD_ID(MX27_PB, 10), + MX27_PAD_CSI_D1 = PAD_ID(MX27_PB, 11), + MX27_PAD_CSI_D2 = PAD_ID(MX27_PB, 12), + MX27_PAD_CSI_D3 = PAD_ID(MX27_PB, 13), + MX27_PAD_CSI_D4 = PAD_ID(MX27_PB, 14), + MX27_PAD_CSI_MCLK = PAD_ID(MX27_PB, 15), + MX27_PAD_CSI_PIXCLK = PAD_ID(MX27_PB, 16), + MX27_PAD_CSI_D5 = PAD_ID(MX27_PB, 17), + MX27_PAD_CSI_D6 = PAD_ID(MX27_PB, 18), + MX27_PAD_CSI_D7 = PAD_ID(MX27_PB, 19), + MX27_PAD_CSI_VSYNC = PAD_ID(MX27_PB, 20), + MX27_PAD_CSI_HSYNC = PAD_ID(MX27_PB, 21), + MX27_PAD_USBH1_SUSP = PAD_ID(MX27_PB, 22), + MX27_PAD_USB_PWR = PAD_ID(MX27_PB, 23), + MX27_PAD_USB_OC_B = PAD_ID(MX27_PB, 24), + MX27_PAD_USBH1_RCV = PAD_ID(MX27_PB, 25), + MX27_PAD_USBH1_FS = PAD_ID(MX27_PB, 26), + MX27_PAD_USBH1_OE_B = PAD_ID(MX27_PB, 27), + MX27_PAD_USBH1_TXDM = PAD_ID(MX27_PB, 28), + MX27_PAD_USBH1_TXDP = PAD_ID(MX27_PB, 29), + MX27_PAD_USBH1_RXDM = PAD_ID(MX27_PB, 30), + MX27_PAD_USBH1_RXDP = PAD_ID(MX27_PB, 31), - MX27_PAD_I2C2_SDA = PAD_ID(PC, 5), - MX27_PAD_I2C2_SCL = PAD_ID(PC, 6), - MX27_PAD_USBOTG_DATA5 = PAD_ID(PC, 7), - MX27_PAD_USBOTG_DATA6 = PAD_ID(PC, 8), - MX27_PAD_USBOTG_DATA0 = PAD_ID(PC, 9), - MX27_PAD_USBOTG_DATA2 = PAD_ID(PC, 10), - MX27_PAD_USBOTG_DATA1 = PAD_ID(PC, 11), - MX27_PAD_USBOTG_DATA4 = PAD_ID(PC, 12), - MX27_PAD_USBOTG_DATA3 = PAD_ID(PC, 13), - MX27_PAD_TOUT = PAD_ID(PC, 14), - MX27_PAD_TIN = PAD_ID(PC, 15), - MX27_PAD_SSI4_FS = PAD_ID(PC, 16), - MX27_PAD_SSI4_RXDAT = PAD_ID(PC, 17), - MX27_PAD_SSI4_TXDAT = PAD_ID(PC, 18), - MX27_PAD_SSI4_CLK = PAD_ID(PC, 19), - MX27_PAD_SSI1_FS = PAD_ID(PC, 20), - MX27_PAD_SSI1_RXDAT = PAD_ID(PC, 21), - MX27_PAD_SSI1_TXDAT = PAD_ID(PC, 22), - MX27_PAD_SSI1_CLK = PAD_ID(PC, 23), - MX27_PAD_SSI2_FS = PAD_ID(PC, 24), - MX27_PAD_SSI2_RXDAT = PAD_ID(PC, 25), - MX27_PAD_SSI2_TXDAT = PAD_ID(PC, 26), - MX27_PAD_SSI2_CLK = PAD_ID(PC, 27), - MX27_PAD_SSI3_FS = PAD_ID(PC, 28), - MX27_PAD_SSI3_RXDAT = PAD_ID(PC, 29), - MX27_PAD_SSI3_TXDAT = PAD_ID(PC, 30), - MX27_PAD_SSI3_CLK = PAD_ID(PC, 31), + MX27_PAD_I2C2_SDA = PAD_ID(MX27_PC, 5), + MX27_PAD_I2C2_SCL = PAD_ID(MX27_PC, 6), + MX27_PAD_USBOTG_DATA5 = PAD_ID(MX27_PC, 7), + MX27_PAD_USBOTG_DATA6 = PAD_ID(MX27_PC, 8), + MX27_PAD_USBOTG_DATA0 = PAD_ID(MX27_PC, 9), + MX27_PAD_USBOTG_DATA2 = PAD_ID(MX27_PC, 10), + MX27_PAD_USBOTG_DATA1 = PAD_ID(MX27_PC, 11), + MX27_PAD_USBOTG_DATA4 = PAD_ID(MX27_PC, 12), + MX27_PAD_USBOTG_DATA3 = PAD_ID(MX27_PC, 13), + MX27_PAD_TOUT = PAD_ID(MX27_PC, 14), + MX27_PAD_TIN = PAD_ID(MX27_PC, 15), + MX27_PAD_SSI4_FS = PAD_ID(MX27_PC, 16), + MX27_PAD_SSI4_RXDAT = PAD_ID(MX27_PC, 17), + MX27_PAD_SSI4_TXDAT = PAD_ID(MX27_PC, 18), + MX27_PAD_SSI4_CLK = PAD_ID(MX27_PC, 19), + MX27_PAD_SSI1_FS = PAD_ID(MX27_PC, 20), + MX27_PAD_SSI1_RXDAT = PAD_ID(MX27_PC, 21), + MX27_PAD_SSI1_TXDAT = PAD_ID(MX27_PC, 22), + MX27_PAD_SSI1_CLK = PAD_ID(MX27_PC, 23), + MX27_PAD_SSI2_FS = PAD_ID(MX27_PC, 24), + MX27_PAD_SSI2_RXDAT = PAD_ID(MX27_PC, 25), + MX27_PAD_SSI2_TXDAT = PAD_ID(MX27_PC, 26), + MX27_PAD_SSI2_CLK = PAD_ID(MX27_PC, 27), + MX27_PAD_SSI3_FS = PAD_ID(MX27_PC, 28), + MX27_PAD_SSI3_RXDAT = PAD_ID(MX27_PC, 29), + MX27_PAD_SSI3_TXDAT = PAD_ID(MX27_PC, 30), + MX27_PAD_SSI3_CLK = PAD_ID(MX27_PC, 31), - MX27_PAD_SD3_CMD = PAD_ID(PD, 0), - MX27_PAD_SD3_CLK = PAD_ID(PD, 1), - MX27_PAD_ATA_DATA0 = PAD_ID(PD, 2), - MX27_PAD_ATA_DATA1 = PAD_ID(PD, 3), - MX27_PAD_ATA_DATA2 = PAD_ID(PD, 4), - MX27_PAD_ATA_DATA3 = PAD_ID(PD, 5), - MX27_PAD_ATA_DATA4 = PAD_ID(PD, 6), - MX27_PAD_ATA_DATA5 = PAD_ID(PD, 7), - MX27_PAD_ATA_DATA6 = PAD_ID(PD, 8), - MX27_PAD_ATA_DATA7 = PAD_ID(PD, 9), - MX27_PAD_ATA_DATA8 = PAD_ID(PD, 10), - MX27_PAD_ATA_DATA9 = PAD_ID(PD, 11), - MX27_PAD_ATA_DATA10 = PAD_ID(PD, 12), - MX27_PAD_ATA_DATA11 = PAD_ID(PD, 13), - MX27_PAD_ATA_DATA12 = PAD_ID(PD, 14), - MX27_PAD_ATA_DATA13 = PAD_ID(PD, 15), - MX27_PAD_ATA_DATA14 = PAD_ID(PD, 16), - MX27_PAD_I2C_DATA = PAD_ID(PD, 17), - MX27_PAD_I2C_CLK = PAD_ID(PD, 18), - MX27_PAD_CSPI2_SS2 = PAD_ID(PD, 19), - MX27_PAD_CSPI2_SS1 = PAD_ID(PD, 20), - MX27_PAD_CSPI2_SS0 = PAD_ID(PD, 21), - MX27_PAD_CSPI2_SCLK = PAD_ID(PD, 22), - MX27_PAD_CSPI2_MISO = PAD_ID(PD, 23), - MX27_PAD_CSPI2_MOSI = PAD_ID(PD, 24), - MX27_PAD_CSPI1_RDY = PAD_ID(PD, 25), - MX27_PAD_CSPI1_SS2 = PAD_ID(PD, 26), - MX27_PAD_CSPI1_SS1 = PAD_ID(PD, 27), - MX27_PAD_CSPI1_SS0 = PAD_ID(PD, 28), - MX27_PAD_CSPI1_SCLK = PAD_ID(PD, 29), - MX27_PAD_CSPI1_MISO = PAD_ID(PD, 30), - MX27_PAD_CSPI1_MOSI = PAD_ID(PD, 31), + MX27_PAD_SD3_CMD = PAD_ID(MX27_PD, 0), + MX27_PAD_SD3_CLK = PAD_ID(MX27_PD, 1), + MX27_PAD_ATA_DATA0 = PAD_ID(MX27_PD, 2), + MX27_PAD_ATA_DATA1 = PAD_ID(MX27_PD, 3), + MX27_PAD_ATA_DATA2 = PAD_ID(MX27_PD, 4), + MX27_PAD_ATA_DATA3 = PAD_ID(MX27_PD, 5), + MX27_PAD_ATA_DATA4 = PAD_ID(MX27_PD, 6), + MX27_PAD_ATA_DATA5 = PAD_ID(MX27_PD, 7), + MX27_PAD_ATA_DATA6 = PAD_ID(MX27_PD, 8), + MX27_PAD_ATA_DATA7 = PAD_ID(MX27_PD, 9), + MX27_PAD_ATA_DATA8 = PAD_ID(MX27_PD, 10), + MX27_PAD_ATA_DATA9 = PAD_ID(MX27_PD, 11), + MX27_PAD_ATA_DATA10 = PAD_ID(MX27_PD, 12), + MX27_PAD_ATA_DATA11 = PAD_ID(MX27_PD, 13), + MX27_PAD_ATA_DATA12 = PAD_ID(MX27_PD, 14), + MX27_PAD_ATA_DATA13 = PAD_ID(MX27_PD, 15), + MX27_PAD_ATA_DATA14 = PAD_ID(MX27_PD, 16), + MX27_PAD_I2C_DATA = PAD_ID(MX27_PD, 17), + MX27_PAD_I2C_CLK = PAD_ID(MX27_PD, 18), + MX27_PAD_CSPI2_SS2 = PAD_ID(MX27_PD, 19), + MX27_PAD_CSPI2_SS1 = PAD_ID(MX27_PD, 20), + MX27_PAD_CSPI2_SS0 = PAD_ID(MX27_PD, 21), + MX27_PAD_CSPI2_SCLK = PAD_ID(MX27_PD, 22), + MX27_PAD_CSPI2_MISO = PAD_ID(MX27_PD, 23), + MX27_PAD_CSPI2_MOSI = PAD_ID(MX27_PD, 24), + MX27_PAD_CSPI1_RDY = PAD_ID(MX27_PD, 25), + MX27_PAD_CSPI1_SS2 = PAD_ID(MX27_PD, 26), + MX27_PAD_CSPI1_SS1 = PAD_ID(MX27_PD, 27), + MX27_PAD_CSPI1_SS0 = PAD_ID(MX27_PD, 28), + MX27_PAD_CSPI1_SCLK = PAD_ID(MX27_PD, 29), + MX27_PAD_CSPI1_MISO = PAD_ID(MX27_PD, 30), + MX27_PAD_CSPI1_MOSI = PAD_ID(MX27_PD, 31), - MX27_PAD_USBOTG_NXT = PAD_ID(PE, 0), - MX27_PAD_USBOTG_STP = PAD_ID(PE, 1), - MX27_PAD_USBOTG_DIR = PAD_ID(PE, 2), - MX27_PAD_UART2_CTS = PAD_ID(PE, 3), - MX27_PAD_UART2_RTS = PAD_ID(PE, 4), - MX27_PAD_PWMO = PAD_ID(PE, 5), - MX27_PAD_UART2_TXD = PAD_ID(PE, 6), - MX27_PAD_UART2_RXD = PAD_ID(PE, 7), - MX27_PAD_UART3_TXD = PAD_ID(PE, 8), - MX27_PAD_UART3_RXD = PAD_ID(PE, 9), - MX27_PAD_UART3_CTS = PAD_ID(PE, 10), - MX27_PAD_UART3_RTS = PAD_ID(PE, 11), - MX27_PAD_UART1_TXD = PAD_ID(PE, 12), - MX27_PAD_UART1_RXD = PAD_ID(PE, 13), - MX27_PAD_UART1_CTS = PAD_ID(PE, 14), - MX27_PAD_UART1_RTS = PAD_ID(PE, 15), - MX27_PAD_RTCK = PAD_ID(PE, 16), - MX27_PAD_RESET_OUT_B = PAD_ID(PE, 17), - MX27_PAD_SD1_D0 = PAD_ID(PE, 18), - MX27_PAD_SD1_D1 = PAD_ID(PE, 19), - MX27_PAD_SD1_D2 = PAD_ID(PE, 20), - MX27_PAD_SD1_D3 = PAD_ID(PE, 21), - MX27_PAD_SD1_CMD = PAD_ID(PE, 22), - MX27_PAD_SD1_CLK = PAD_ID(PE, 23), - MX27_PAD_USBOTG_CLK = PAD_ID(PE, 24), - MX27_PAD_USBOTG_DATA7 = PAD_ID(PE, 25), + MX27_PAD_USBOTG_NXT = PAD_ID(MX27_PE, 0), + MX27_PAD_USBOTG_STP = PAD_ID(MX27_PE, 1), + MX27_PAD_USBOTG_DIR = PAD_ID(MX27_PE, 2), + MX27_PAD_UART2_CTS = PAD_ID(MX27_PE, 3), + MX27_PAD_UART2_RTS = PAD_ID(MX27_PE, 4), + MX27_PAD_PWMO = PAD_ID(MX27_PE, 5), + MX27_PAD_UART2_TXD = PAD_ID(MX27_PE, 6), + MX27_PAD_UART2_RXD = PAD_ID(MX27_PE, 7), + MX27_PAD_UART3_TXD = PAD_ID(MX27_PE, 8), + MX27_PAD_UART3_RXD = PAD_ID(MX27_PE, 9), + MX27_PAD_UART3_CTS = PAD_ID(MX27_PE, 10), + MX27_PAD_UART3_RTS = PAD_ID(MX27_PE, 11), + MX27_PAD_UART1_TXD = PAD_ID(MX27_PE, 12), + MX27_PAD_UART1_RXD = PAD_ID(MX27_PE, 13), + MX27_PAD_UART1_CTS = PAD_ID(MX27_PE, 14), + MX27_PAD_UART1_RTS = PAD_ID(MX27_PE, 15), + MX27_PAD_RTCK = PAD_ID(MX27_PE, 16), + MX27_PAD_RESET_OUT_B = PAD_ID(MX27_PE, 17), + MX27_PAD_SD1_D0 = PAD_ID(MX27_PE, 18), + MX27_PAD_SD1_D1 = PAD_ID(MX27_PE, 19), + MX27_PAD_SD1_D2 = PAD_ID(MX27_PE, 20), + MX27_PAD_SD1_D3 = PAD_ID(MX27_PE, 21), + MX27_PAD_SD1_CMD = PAD_ID(MX27_PE, 22), + MX27_PAD_SD1_CLK = PAD_ID(MX27_PE, 23), + MX27_PAD_USBOTG_CLK = PAD_ID(MX27_PE, 24), + MX27_PAD_USBOTG_DATA7 = PAD_ID(MX27_PE, 25), - MX27_PAD_NFRB = PAD_ID(PF, 0), - MX27_PAD_NFCLE = PAD_ID(PF, 1), - MX27_PAD_NFWP_B = PAD_ID(PF, 2), - MX27_PAD_NFCE_B = PAD_ID(PF, 3), - MX27_PAD_NFALE = PAD_ID(PF, 4), - MX27_PAD_NFRE_B = PAD_ID(PF, 5), - MX27_PAD_NFWE_B = PAD_ID(PF, 6), - MX27_PAD_PC_POE = PAD_ID(PF, 7), - MX27_PAD_PC_RW_B = PAD_ID(PF, 8), - MX27_PAD_IOIS16 = PAD_ID(PF, 9), - MX27_PAD_PC_RST = PAD_ID(PF, 10), - MX27_PAD_PC_BVD2 = PAD_ID(PF, 11), - MX27_PAD_PC_BVD1 = PAD_ID(PF, 12), - MX27_PAD_PC_VS2 = PAD_ID(PF, 13), - MX27_PAD_PC_VS1 = PAD_ID(PF, 14), - MX27_PAD_CLKO = PAD_ID(PF, 15), - MX27_PAD_PC_PWRON = PAD_ID(PF, 16), - MX27_PAD_PC_READY = PAD_ID(PF, 17), - MX27_PAD_PC_WAIT_B = PAD_ID(PF, 18), - MX27_PAD_PC_CD2_B = PAD_ID(PF, 19), - MX27_PAD_PC_CD1_B = PAD_ID(PF, 20), - MX27_PAD_CS4_B = PAD_ID(PF, 21), - MX27_PAD_CS5_B = PAD_ID(PF, 22), - MX27_PAD_ATA_DATA15 = PAD_ID(PF, 23), + MX27_PAD_NFRB = PAD_ID(MX27_PF, 0), + MX27_PAD_NFCLE = PAD_ID(MX27_PF, 1), + MX27_PAD_NFWP_B = PAD_ID(MX27_PF, 2), + MX27_PAD_NFCE_B = PAD_ID(MX27_PF, 3), + MX27_PAD_NFALE = PAD_ID(MX27_PF, 4), + MX27_PAD_NFRE_B = PAD_ID(MX27_PF, 5), + MX27_PAD_NFWE_B = PAD_ID(MX27_PF, 6), + MX27_PAD_PC_POE = PAD_ID(MX27_PF, 7), + MX27_PAD_PC_RW_B = PAD_ID(MX27_PF, 8), + MX27_PAD_IOIS16 = PAD_ID(MX27_PF, 9), + MX27_PAD_PC_RST = PAD_ID(MX27_PF, 10), + MX27_PAD_PC_BVD2 = PAD_ID(MX27_PF, 11), + MX27_PAD_PC_BVD1 = PAD_ID(MX27_PF, 12), + MX27_PAD_PC_VS2 = PAD_ID(MX27_PF, 13), + MX27_PAD_PC_VS1 = PAD_ID(MX27_PF, 14), + MX27_PAD_CLKO = PAD_ID(MX27_PF, 15), + MX27_PAD_PC_PWRON = PAD_ID(MX27_PF, 16), + MX27_PAD_PC_READY = PAD_ID(MX27_PF, 17), + MX27_PAD_PC_WAIT_B = PAD_ID(MX27_PF, 18), + MX27_PAD_PC_CD2_B = PAD_ID(MX27_PF, 19), + MX27_PAD_PC_CD1_B = PAD_ID(MX27_PF, 20), + MX27_PAD_CS4_B = PAD_ID(MX27_PF, 21), + MX27_PAD_CS5_B = PAD_ID(MX27_PF, 22), + MX27_PAD_ATA_DATA15 = PAD_ID(MX27_PF, 23), }; /* Pad names for the pinmux subsystem */ diff --git a/drivers/pinctrl/intel/pinctrl-alderlake.c b/drivers/pinctrl/intel/pinctrl-alderlake.c index 7d9948e5f422f6..108eac205aa9dc 100644 --- a/drivers/pinctrl/intel/pinctrl-alderlake.c +++ b/drivers/pinctrl/intel/pinctrl-alderlake.c @@ -747,4 +747,4 @@ module_platform_driver(adl_pinctrl_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Alder Lake PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 4533c4d0a9e750..7340dc20349c73 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -1723,4 +1723,4 @@ static int __init byt_gpio_init(void) } subsys_initcall(byt_gpio_init); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c index d99541676630de..140b2995634064 100644 --- a/drivers/pinctrl/intel/pinctrl-broxton.c +++ b/drivers/pinctrl/intel/pinctrl-broxton.c @@ -1026,4 +1026,4 @@ module_exit(bxt_pinctrl_exit); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Broxton SoC pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-cannonlake.c b/drivers/pinctrl/intel/pinctrl-cannonlake.c index 1aa09f950be1eb..14a5d339385d34 100644 --- a/drivers/pinctrl/intel/pinctrl-cannonlake.c +++ b/drivers/pinctrl/intel/pinctrl-cannonlake.c @@ -838,4 +838,4 @@ module_platform_driver(cnl_pinctrl_driver); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Cannon Lake PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-cedarfork.c b/drivers/pinctrl/intel/pinctrl-cedarfork.c index 48af8930dd1f95..2ce97abeb0e411 100644 --- a/drivers/pinctrl/intel/pinctrl-cedarfork.c +++ b/drivers/pinctrl/intel/pinctrl-cedarfork.c @@ -350,4 +350,4 @@ module_exit(cdf_pinctrl_exit); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Cedar Fork PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index 067b0d344f0e5f..c673e262e1dbcc 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1792,7 +1792,7 @@ MODULE_DEVICE_TABLE(acpi, chv_pinctrl_acpi_match); static struct platform_driver chv_pinctrl_driver = { .probe = chv_pinctrl_probe, - .remove_new = chv_pinctrl_remove, + .remove = chv_pinctrl_remove, .driver = { .name = "cherryview-pinctrl", .pm = pm_sleep_ptr(&chv_pinctrl_pm_ops), @@ -1815,4 +1815,4 @@ module_exit(chv_pinctrl_exit); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Cherryview/Braswell pinctrl driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-denverton.c b/drivers/pinctrl/intel/pinctrl-denverton.c index 666507f54f2761..fef44c663be602 100644 --- a/drivers/pinctrl/intel/pinctrl-denverton.c +++ b/drivers/pinctrl/intel/pinctrl-denverton.c @@ -287,4 +287,4 @@ module_exit(dnv_pinctrl_exit); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Denverton SoC pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-elkhartlake.c b/drivers/pinctrl/intel/pinctrl-elkhartlake.c index 1678634ebc06c6..ab414e07555a8f 100644 --- a/drivers/pinctrl/intel/pinctrl-elkhartlake.c +++ b/drivers/pinctrl/intel/pinctrl-elkhartlake.c @@ -264,6 +264,43 @@ static const struct intel_pinctrl_soc_data ehl_community1_soc_data = { .ncommunities = ARRAY_SIZE(ehl_community1), }; +static const struct pinctrl_pin_desc ehl_community2_pins[] = { + /* DSW */ + PINCTRL_PIN(0, "BATLOWB"), + PINCTRL_PIN(1, "ACPRESENT"), + PINCTRL_PIN(2, "LAN_WAKEB"), + PINCTRL_PIN(3, "PWRBTNB"), + PINCTRL_PIN(4, "SLP_S3B"), + PINCTRL_PIN(5, "SLP_S4B"), + PINCTRL_PIN(6, "SLP_AB"), + PINCTRL_PIN(7, "GPD_7"), + PINCTRL_PIN(8, "SUSCLK"), + PINCTRL_PIN(9, "SLP_WLANB"), + PINCTRL_PIN(10, "SLP_S5B"), + PINCTRL_PIN(11, "LANPHYPC"), + PINCTRL_PIN(12, "INPUT3VSEL"), + PINCTRL_PIN(13, "SLP_LANB"), + PINCTRL_PIN(14, "SLP_SUSB"), + PINCTRL_PIN(15, "WAKEB"), + PINCTRL_PIN(16, "DRAM_RESETB"), +}; + +static const struct intel_padgroup ehl_community2_gpps[] = { + EHL_GPP(0, 0, 16), /* DSW */ +}; + +static const struct intel_community ehl_community2[] = { + EHL_COMMUNITY(0, 0, 16, ehl_community2_gpps), +}; + +static const struct intel_pinctrl_soc_data ehl_community2_soc_data = { + .uid = "2", + .pins = ehl_community2_pins, + .npins = ARRAY_SIZE(ehl_community2_pins), + .communities = ehl_community2, + .ncommunities = ARRAY_SIZE(ehl_community2), +}; + static const struct pinctrl_pin_desc ehl_community3_pins[] = { /* CPU */ PINCTRL_PIN(0, "HDACPU_SDI"), @@ -474,6 +511,7 @@ static const struct intel_pinctrl_soc_data ehl_community5_soc_data = { static const struct intel_pinctrl_soc_data *ehl_soc_data_array[] = { &ehl_community0_soc_data, &ehl_community1_soc_data, + &ehl_community2_soc_data, &ehl_community3_soc_data, &ehl_community4_soc_data, &ehl_community5_soc_data, @@ -499,4 +537,4 @@ module_platform_driver(ehl_pinctrl_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Elkhart Lake PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-emmitsburg.c b/drivers/pinctrl/intel/pinctrl-emmitsburg.c index e4798d32492c58..9d8a32aca177e3 100644 --- a/drivers/pinctrl/intel/pinctrl-emmitsburg.c +++ b/drivers/pinctrl/intel/pinctrl-emmitsburg.c @@ -372,4 +372,4 @@ module_platform_driver(ebg_pinctrl_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Emmitsburg PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-geminilake.c b/drivers/pinctrl/intel/pinctrl-geminilake.c index 6dcf0ac2059f5d..8dcac4fe8493c3 100644 --- a/drivers/pinctrl/intel/pinctrl-geminilake.c +++ b/drivers/pinctrl/intel/pinctrl-geminilake.c @@ -472,4 +472,4 @@ module_exit(glk_pinctrl_exit); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Gemini Lake SoC pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-icelake.c b/drivers/pinctrl/intel/pinctrl-icelake.c index fe3042de891a61..7e028c61ed0ff1 100644 --- a/drivers/pinctrl/intel/pinctrl-icelake.c +++ b/drivers/pinctrl/intel/pinctrl-icelake.c @@ -690,4 +690,4 @@ MODULE_AUTHOR("Andy Shevchenko "); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Ice Lake PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-intel-platform.c b/drivers/pinctrl/intel/pinctrl-intel-platform.c index 016a9f62eecc10..dd5dbede0f591a 100644 --- a/drivers/pinctrl/intel/pinctrl-intel-platform.c +++ b/drivers/pinctrl/intel/pinctrl-intel-platform.c @@ -221,4 +221,4 @@ module_platform_driver(intel_platform_pinctrl_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 928607a21d36db..527e4b87ae52e8 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -85,6 +85,18 @@ #define PADCFG1_TERM_UP BIT(13) #define PADCFG1_TERM_SHIFT 10 #define PADCFG1_TERM_MASK GENMASK(12, 10) +/* + * Bit 0 Bit 1 Bit 2 Value, Ohms + * + * 0 0 0 - + * 0 0 1 20000 + * 0 1 0 5000 + * 0 1 1 ~4000 + * 1 0 0 1000 (if supported) + * 1 0 1 ~952 (if supported) + * 1 1 0 ~833 (if supported) + * 1 1 1 ~800 (if supported) + */ #define PADCFG1_TERM_20K BIT(2) #define PADCFG1_TERM_5K BIT(1) #define PADCFG1_TERM_4K (BIT(2) | BIT(1)) @@ -146,7 +158,7 @@ const struct intel_community *intel_get_community(const struct intel_pinctrl *pc dev_warn(pctrl->dev, "failed to find community for pin %u\n", pin); return NULL; } -EXPORT_SYMBOL_NS_GPL(intel_get_community, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_get_community, "PINCTRL_INTEL"); static const struct intel_padgroup * intel_community_get_padgroup(const struct intel_community *community, @@ -303,7 +315,7 @@ int intel_get_groups_count(struct pinctrl_dev *pctldev) return pctrl->soc->ngroups; } -EXPORT_SYMBOL_NS_GPL(intel_get_groups_count, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_get_groups_count, "PINCTRL_INTEL"); const char *intel_get_group_name(struct pinctrl_dev *pctldev, unsigned int group) { @@ -311,7 +323,7 @@ const char *intel_get_group_name(struct pinctrl_dev *pctldev, unsigned int group return pctrl->soc->groups[group].grp.name; } -EXPORT_SYMBOL_NS_GPL(intel_get_group_name, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_get_group_name, "PINCTRL_INTEL"); int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, const unsigned int **pins, unsigned int *npins) @@ -322,7 +334,7 @@ int intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group, *npins = pctrl->soc->groups[group].grp.npins; return 0; } -EXPORT_SYMBOL_NS_GPL(intel_get_group_pins, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_get_group_pins, "PINCTRL_INTEL"); static void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned int pin) @@ -388,7 +400,7 @@ int intel_get_functions_count(struct pinctrl_dev *pctldev) return pctrl->soc->nfunctions; } -EXPORT_SYMBOL_NS_GPL(intel_get_functions_count, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_get_functions_count, "PINCTRL_INTEL"); const char *intel_get_function_name(struct pinctrl_dev *pctldev, unsigned int function) { @@ -396,7 +408,7 @@ const char *intel_get_function_name(struct pinctrl_dev *pctldev, unsigned int fu return pctrl->soc->functions[function].func.name; } -EXPORT_SYMBOL_NS_GPL(intel_get_function_name, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_get_function_name, "PINCTRL_INTEL"); int intel_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function, const char * const **groups, unsigned int * const ngroups) @@ -407,7 +419,7 @@ int intel_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function *ngroups = pctrl->soc->functions[function].func.ngroups; return 0; } -EXPORT_SYMBOL_NS_GPL(intel_get_function_groups, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_get_function_groups, "PINCTRL_INTEL"); static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, unsigned int group) @@ -1664,7 +1676,7 @@ int intel_pinctrl_probe(struct platform_device *pdev, return 0; } -EXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe, "PINCTRL_INTEL"); int intel_pinctrl_probe_by_hid(struct platform_device *pdev) { @@ -1676,7 +1688,7 @@ int intel_pinctrl_probe_by_hid(struct platform_device *pdev) return intel_pinctrl_probe(pdev, data); } -EXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe_by_hid, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe_by_hid, "PINCTRL_INTEL"); int intel_pinctrl_probe_by_uid(struct platform_device *pdev) { @@ -1688,7 +1700,7 @@ int intel_pinctrl_probe_by_uid(struct platform_device *pdev) return intel_pinctrl_probe(pdev, data); } -EXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe_by_uid, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe_by_uid, "PINCTRL_INTEL"); const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev) { @@ -1719,7 +1731,7 @@ const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_ return data ?: ERR_PTR(-ENODATA); } -EXPORT_SYMBOL_NS_GPL(intel_pinctrl_get_soc_data, PINCTRL_INTEL); +EXPORT_SYMBOL_NS_GPL(intel_pinctrl_get_soc_data, "PINCTRL_INTEL"); static bool __intel_gpio_is_direct_irq(u32 value) { diff --git a/drivers/pinctrl/intel/pinctrl-jasperlake.c b/drivers/pinctrl/intel/pinctrl-jasperlake.c index 3525480428ea66..aef0e7f921549e 100644 --- a/drivers/pinctrl/intel/pinctrl-jasperlake.c +++ b/drivers/pinctrl/intel/pinctrl-jasperlake.c @@ -340,4 +340,4 @@ module_platform_driver(jsl_pinctrl_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Jasper Lake PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-lakefield.c b/drivers/pinctrl/intel/pinctrl-lakefield.c index adef85db82ca76..60281f4216085f 100644 --- a/drivers/pinctrl/intel/pinctrl-lakefield.c +++ b/drivers/pinctrl/intel/pinctrl-lakefield.c @@ -361,4 +361,4 @@ module_platform_driver(lkf_pinctrl_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Lakefield PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-lewisburg.c b/drivers/pinctrl/intel/pinctrl-lewisburg.c index a304d30ea9ed33..9fe651370f32f4 100644 --- a/drivers/pinctrl/intel/pinctrl-lewisburg.c +++ b/drivers/pinctrl/intel/pinctrl-lewisburg.c @@ -321,4 +321,4 @@ module_platform_driver(lbg_pinctrl_driver); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Lewisburg pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c index bcce97f3b8975e..cc5ede17c38384 100644 --- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c +++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c @@ -859,4 +859,4 @@ MODULE_AUTHOR("Andy Shevchenko (Intel)"); MODULE_DESCRIPTION("Intel Lynxpoint pinctrl driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:lp_gpio"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c index 1a556f5822b6e9..2f4d73dda41d32 100644 --- a/drivers/pinctrl/intel/pinctrl-merrifield.c +++ b/drivers/pinctrl/intel/pinctrl-merrifield.c @@ -380,4 +380,4 @@ MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Merrifield SoC pinctrl driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:pinctrl-merrifield"); -MODULE_IMPORT_NS(PINCTRL_TANGIER); +MODULE_IMPORT_NS("PINCTRL_TANGIER"); diff --git a/drivers/pinctrl/intel/pinctrl-meteorlake.c b/drivers/pinctrl/intel/pinctrl-meteorlake.c index 885fa3b0d6d95f..f564376ce43731 100644 --- a/drivers/pinctrl/intel/pinctrl-meteorlake.c +++ b/drivers/pinctrl/intel/pinctrl-meteorlake.c @@ -604,4 +604,4 @@ module_platform_driver(mtl_pinctrl_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Meteor Lake PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-meteorpoint.c b/drivers/pinctrl/intel/pinctrl-meteorpoint.c index 77e97775a60b1d..ab46ac5f3b159f 100644 --- a/drivers/pinctrl/intel/pinctrl-meteorpoint.c +++ b/drivers/pinctrl/intel/pinctrl-meteorpoint.c @@ -462,4 +462,4 @@ module_platform_driver(mtp_pinctrl_driver); MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Meteor Point PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-moorefield.c b/drivers/pinctrl/intel/pinctrl-moorefield.c index 7b995fbf5c84b6..6a79207e6b2a33 100644 --- a/drivers/pinctrl/intel/pinctrl-moorefield.c +++ b/drivers/pinctrl/intel/pinctrl-moorefield.c @@ -341,4 +341,4 @@ MODULE_AUTHOR("Andy Shevchenko "); MODULE_DESCRIPTION("Intel Moorefield SoC pinctrl driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:pinctrl-moorefield"); -MODULE_IMPORT_NS(PINCTRL_TANGIER); +MODULE_IMPORT_NS("PINCTRL_TANGIER"); diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c index 55df9d2cfb1bee..a7a5fa65fd9d04 100644 --- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c +++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c @@ -605,4 +605,4 @@ MODULE_AUTHOR("Mathias Nyman "); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Sunrisepoint PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/intel/pinctrl-tangier.c b/drivers/pinctrl/intel/pinctrl-tangier.c index 2cb0b4758269ee..d3baf0f4eea098 100644 --- a/drivers/pinctrl/intel/pinctrl-tangier.c +++ b/drivers/pinctrl/intel/pinctrl-tangier.c @@ -579,7 +579,7 @@ int devm_tng_pinctrl_probe(struct platform_device *pdev) return tng_pinctrl_probe(pdev, data); } -EXPORT_SYMBOL_NS_GPL(devm_tng_pinctrl_probe, PINCTRL_TANGIER); +EXPORT_SYMBOL_NS_GPL(devm_tng_pinctrl_probe, "PINCTRL_TANGIER"); MODULE_AUTHOR("Andy Shevchenko "); MODULE_AUTHOR("Raag Jadav "); diff --git a/drivers/pinctrl/intel/pinctrl-tigerlake.c b/drivers/pinctrl/intel/pinctrl-tigerlake.c index 80cd7a06fe5ad6..c43576e10273e0 100644 --- a/drivers/pinctrl/intel/pinctrl-tigerlake.c +++ b/drivers/pinctrl/intel/pinctrl-tigerlake.c @@ -758,4 +758,4 @@ MODULE_AUTHOR("Andy Shevchenko "); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("Intel Tiger Lake PCH pinctrl/GPIO driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PINCTRL_INTEL); +MODULE_IMPORT_NS("PINCTRL_INTEL"); diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index 7af287252834a4..a417a031659c65 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 || RALINK || COMPILE_TEST + depends on ARCH_MEDIATEK || ARCH_AIROHA || RALINK || COMPILE_TEST config EINT_MTK tristate "MediaTek External Interrupt Support" @@ -126,6 +126,21 @@ config PINCTRL_MT8127 select PINCTRL_MTK # For ARMv8 SoCs +config PINCTRL_AIROHA + tristate "Airoha EN7581 pin control" + depends on OF + depends on ARM64 || COMPILE_TEST + select PINMUX + select GENERIC_PINCONF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GPIOLIB + select GPIOLIB_IRQCHIP + select REGMAP_MMIO + help + Say yes here to support pin controller and gpio driver + on Airoha EN7581 SoC. + config PINCTRL_MT2712 bool "MediaTek MT2712 pin control" depends on OF diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile index 680f7e8526e00a..1405d434218ea1 100644 --- a/drivers/pinctrl/mediatek/Makefile +++ b/drivers/pinctrl/mediatek/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_MTK_MOORE) += pinctrl-moore.o obj-$(CONFIG_PINCTRL_MTK_PARIS) += pinctrl-paris.o # SoC Drivers +obj-$(CONFIG_PINCTRL_AIROHA) += pinctrl-airoha.o obj-$(CONFIG_PINCTRL_MT7620) += pinctrl-mt7620.o obj-$(CONFIG_PINCTRL_MT7621) += pinctrl-mt7621.o obj-$(CONFIG_PINCTRL_MT76X8) += pinctrl-mt76x8.o diff --git a/drivers/pinctrl/mediatek/pinctrl-airoha.c b/drivers/pinctrl/mediatek/pinctrl-airoha.c new file mode 100644 index 00000000000000..547a798b71c8ae --- /dev/null +++ b/drivers/pinctrl/mediatek/pinctrl-airoha.c @@ -0,0 +1,2971 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Author: Lorenzo Bianconi + * Author: Benjamin Larsson + * Author: Markus Gothe + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../pinconf.h" +#include "../pinmux.h" + +#define PINCTRL_PIN_GROUP(id) \ + PINCTRL_PINGROUP(#id, id##_pins, ARRAY_SIZE(id##_pins)) + +#define PINCTRL_FUNC_DESC(id) \ + { \ + .desc = { \ + .func = { \ + .name = #id, \ + .groups = id##_groups, \ + .ngroups = ARRAY_SIZE(id##_groups), \ + } \ + }, \ + .groups = id##_func_group, \ + .group_size = ARRAY_SIZE(id##_func_group), \ + } + +#define PINCTRL_CONF_DESC(p, offset, mask) \ + { \ + .pin = p, \ + .reg = { offset, mask }, \ + } + +/* MUX */ +#define REG_GPIO_2ND_I2C_MODE 0x0214 +#define GPIO_MDC_IO_MASTER_MODE_MODE BIT(14) +#define GPIO_I2C_MASTER_MODE_MODE BIT(13) +#define GPIO_I2S_MODE_MASK BIT(12) +#define GPIO_I2C_SLAVE_MODE_MODE BIT(11) +#define GPIO_LAN3_LED1_MODE_MASK BIT(10) +#define GPIO_LAN3_LED0_MODE_MASK BIT(9) +#define GPIO_LAN2_LED1_MODE_MASK BIT(8) +#define GPIO_LAN2_LED0_MODE_MASK BIT(7) +#define GPIO_LAN1_LED1_MODE_MASK BIT(6) +#define GPIO_LAN1_LED0_MODE_MASK BIT(5) +#define GPIO_LAN0_LED1_MODE_MASK BIT(4) +#define GPIO_LAN0_LED0_MODE_MASK BIT(3) +#define PON_TOD_1PPS_MODE_MASK BIT(2) +#define GSW_TOD_1PPS_MODE_MASK BIT(1) +#define GPIO_2ND_I2C_MODE_MASK BIT(0) + +#define REG_GPIO_SPI_CS1_MODE 0x0218 +#define GPIO_PCM_SPI_CS4_MODE_MASK BIT(21) +#define GPIO_PCM_SPI_CS3_MODE_MASK BIT(20) +#define GPIO_PCM_SPI_CS2_MODE_P156_MASK BIT(19) +#define GPIO_PCM_SPI_CS2_MODE_P128_MASK BIT(18) +#define GPIO_PCM_SPI_CS1_MODE_MASK BIT(17) +#define GPIO_PCM_SPI_MODE_MASK BIT(16) +#define GPIO_PCM2_MODE_MASK BIT(13) +#define GPIO_PCM1_MODE_MASK BIT(12) +#define GPIO_PCM_INT_MODE_MASK BIT(9) +#define GPIO_PCM_RESET_MODE_MASK BIT(8) +#define GPIO_SPI_QUAD_MODE_MASK BIT(4) +#define GPIO_SPI_CS4_MODE_MASK BIT(3) +#define GPIO_SPI_CS3_MODE_MASK BIT(2) +#define GPIO_SPI_CS2_MODE_MASK BIT(1) +#define GPIO_SPI_CS1_MODE_MASK BIT(0) + +#define REG_GPIO_PON_MODE 0x021c +#define GPIO_PARALLEL_NAND_MODE_MASK BIT(14) +#define GPIO_SGMII_MDIO_MODE_MASK BIT(13) +#define GPIO_PCIE_RESET2_MASK BIT(12) +#define SIPO_RCLK_MODE_MASK BIT(11) +#define GPIO_PCIE_RESET1_MASK BIT(10) +#define GPIO_PCIE_RESET0_MASK BIT(9) +#define GPIO_UART5_MODE_MASK BIT(8) +#define GPIO_UART4_MODE_MASK BIT(7) +#define GPIO_HSUART_CTS_RTS_MODE_MASK BIT(6) +#define GPIO_HSUART_MODE_MASK BIT(5) +#define GPIO_UART2_CTS_RTS_MODE_MASK BIT(4) +#define GPIO_UART2_MODE_MASK BIT(3) +#define GPIO_SIPO_MODE_MASK BIT(2) +#define GPIO_EMMC_MODE_MASK BIT(1) +#define GPIO_PON_MODE_MASK BIT(0) + +#define REG_NPU_UART_EN 0x0224 +#define JTAG_UDI_EN_MASK BIT(4) +#define JTAG_DFD_EN_MASK BIT(3) + +/* LED MAP */ +#define REG_LAN_LED0_MAPPING 0x027c +#define REG_LAN_LED1_MAPPING 0x0280 + +#define LAN4_LED_MAPPING_MASK GENMASK(18, 16) +#define LAN4_PHY4_LED_MAP BIT(18) +#define LAN4_PHY2_LED_MAP BIT(17) +#define LAN4_PHY1_LED_MAP BIT(16) +#define LAN4_PHY0_LED_MAP 0 +#define LAN4_PHY3_LED_MAP GENMASK(17, 16) + +#define LAN3_LED_MAPPING_MASK GENMASK(14, 12) +#define LAN3_PHY4_LED_MAP BIT(14) +#define LAN3_PHY2_LED_MAP BIT(13) +#define LAN3_PHY1_LED_MAP BIT(12) +#define LAN3_PHY0_LED_MAP 0 +#define LAN3_PHY3_LED_MAP GENMASK(13, 12) + +#define LAN2_LED_MAPPING_MASK GENMASK(10, 8) +#define LAN2_PHY4_LED_MAP BIT(12) +#define LAN2_PHY2_LED_MAP BIT(11) +#define LAN2_PHY1_LED_MAP BIT(10) +#define LAN2_PHY0_LED_MAP 0 +#define LAN2_PHY3_LED_MAP GENMASK(11, 10) + +#define LAN1_LED_MAPPING_MASK GENMASK(6, 4) +#define LAN1_PHY4_LED_MAP BIT(6) +#define LAN1_PHY2_LED_MAP BIT(5) +#define LAN1_PHY1_LED_MAP BIT(4) +#define LAN1_PHY0_LED_MAP 0 +#define LAN1_PHY3_LED_MAP GENMASK(5, 4) + +#define LAN0_LED_MAPPING_MASK GENMASK(2, 0) +#define LAN0_PHY4_LED_MAP BIT(3) +#define LAN0_PHY2_LED_MAP BIT(2) +#define LAN0_PHY1_LED_MAP BIT(1) +#define LAN0_PHY0_LED_MAP 0 +#define LAN0_PHY3_LED_MAP GENMASK(2, 1) + +/* CONF */ +#define REG_I2C_SDA_E2 0x001c +#define SPI_MISO_E2_MASK BIT(14) +#define SPI_MOSI_E2_MASK BIT(13) +#define SPI_CLK_E2_MASK BIT(12) +#define SPI_CS0_E2_MASK BIT(11) +#define PCIE2_RESET_E2_MASK BIT(10) +#define PCIE1_RESET_E2_MASK BIT(9) +#define PCIE0_RESET_E2_MASK BIT(8) +#define UART1_RXD_E2_MASK BIT(3) +#define UART1_TXD_E2_MASK BIT(2) +#define I2C_SCL_E2_MASK BIT(1) +#define I2C_SDA_E2_MASK BIT(0) + +#define REG_I2C_SDA_E4 0x0020 +#define SPI_MISO_E4_MASK BIT(14) +#define SPI_MOSI_E4_MASK BIT(13) +#define SPI_CLK_E4_MASK BIT(12) +#define SPI_CS0_E4_MASK BIT(11) +#define PCIE2_RESET_E4_MASK BIT(10) +#define PCIE1_RESET_E4_MASK BIT(9) +#define PCIE0_RESET_E4_MASK BIT(8) +#define UART1_RXD_E4_MASK BIT(3) +#define UART1_TXD_E4_MASK BIT(2) +#define I2C_SCL_E4_MASK BIT(1) +#define I2C_SDA_E4_MASK BIT(0) + +#define REG_GPIO_L_E2 0x0024 +#define REG_GPIO_L_E4 0x0028 +#define REG_GPIO_H_E2 0x002c +#define REG_GPIO_H_E4 0x0030 + +#define REG_I2C_SDA_PU 0x0044 +#define SPI_MISO_PU_MASK BIT(14) +#define SPI_MOSI_PU_MASK BIT(13) +#define SPI_CLK_PU_MASK BIT(12) +#define SPI_CS0_PU_MASK BIT(11) +#define PCIE2_RESET_PU_MASK BIT(10) +#define PCIE1_RESET_PU_MASK BIT(9) +#define PCIE0_RESET_PU_MASK BIT(8) +#define UART1_RXD_PU_MASK BIT(3) +#define UART1_TXD_PU_MASK BIT(2) +#define I2C_SCL_PU_MASK BIT(1) +#define I2C_SDA_PU_MASK BIT(0) + +#define REG_I2C_SDA_PD 0x0048 +#define SPI_MISO_PD_MASK BIT(14) +#define SPI_MOSI_PD_MASK BIT(13) +#define SPI_CLK_PD_MASK BIT(12) +#define SPI_CS0_PD_MASK BIT(11) +#define PCIE2_RESET_PD_MASK BIT(10) +#define PCIE1_RESET_PD_MASK BIT(9) +#define PCIE0_RESET_PD_MASK BIT(8) +#define UART1_RXD_PD_MASK BIT(3) +#define UART1_TXD_PD_MASK BIT(2) +#define I2C_SCL_PD_MASK BIT(1) +#define I2C_SDA_PD_MASK BIT(0) + +#define REG_GPIO_L_PU 0x004c +#define REG_GPIO_L_PD 0x0050 +#define REG_GPIO_H_PU 0x0054 +#define REG_GPIO_H_PD 0x0058 + +#define REG_PCIE_RESET_OD 0x018c +#define PCIE2_RESET_OD_MASK BIT(2) +#define PCIE1_RESET_OD_MASK BIT(1) +#define PCIE0_RESET_OD_MASK BIT(0) + +/* GPIOs */ +#define REG_GPIO_CTRL 0x0000 +#define REG_GPIO_DATA 0x0004 +#define REG_GPIO_INT 0x0008 +#define REG_GPIO_INT_EDGE 0x000c +#define REG_GPIO_INT_LEVEL 0x0010 +#define REG_GPIO_OE 0x0014 +#define REG_GPIO_CTRL1 0x0020 + +/* PWM MODE CONF */ +#define REG_GPIO_FLASH_MODE_CFG 0x0034 +#define GPIO15_FLASH_MODE_CFG BIT(15) +#define GPIO14_FLASH_MODE_CFG BIT(14) +#define GPIO13_FLASH_MODE_CFG BIT(13) +#define GPIO12_FLASH_MODE_CFG BIT(12) +#define GPIO11_FLASH_MODE_CFG BIT(11) +#define GPIO10_FLASH_MODE_CFG BIT(10) +#define GPIO9_FLASH_MODE_CFG BIT(9) +#define GPIO8_FLASH_MODE_CFG BIT(8) +#define GPIO7_FLASH_MODE_CFG BIT(7) +#define GPIO6_FLASH_MODE_CFG BIT(6) +#define GPIO5_FLASH_MODE_CFG BIT(5) +#define GPIO4_FLASH_MODE_CFG BIT(4) +#define GPIO3_FLASH_MODE_CFG BIT(3) +#define GPIO2_FLASH_MODE_CFG BIT(2) +#define GPIO1_FLASH_MODE_CFG BIT(1) +#define GPIO0_FLASH_MODE_CFG BIT(0) + +#define REG_GPIO_CTRL2 0x0060 +#define REG_GPIO_CTRL3 0x0064 + +/* PWM MODE CONF EXT */ +#define REG_GPIO_FLASH_MODE_CFG_EXT 0x0068 +#define GPIO51_FLASH_MODE_CFG BIT(31) +#define GPIO50_FLASH_MODE_CFG BIT(30) +#define GPIO49_FLASH_MODE_CFG BIT(29) +#define GPIO48_FLASH_MODE_CFG BIT(28) +#define GPIO47_FLASH_MODE_CFG BIT(27) +#define GPIO46_FLASH_MODE_CFG BIT(26) +#define GPIO45_FLASH_MODE_CFG BIT(25) +#define GPIO44_FLASH_MODE_CFG BIT(24) +#define GPIO43_FLASH_MODE_CFG BIT(23) +#define GPIO42_FLASH_MODE_CFG BIT(22) +#define GPIO41_FLASH_MODE_CFG BIT(21) +#define GPIO40_FLASH_MODE_CFG BIT(20) +#define GPIO39_FLASH_MODE_CFG BIT(19) +#define GPIO38_FLASH_MODE_CFG BIT(18) +#define GPIO37_FLASH_MODE_CFG BIT(17) +#define GPIO36_FLASH_MODE_CFG BIT(16) +#define GPIO31_FLASH_MODE_CFG BIT(15) +#define GPIO30_FLASH_MODE_CFG BIT(14) +#define GPIO29_FLASH_MODE_CFG BIT(13) +#define GPIO28_FLASH_MODE_CFG BIT(12) +#define GPIO27_FLASH_MODE_CFG BIT(11) +#define GPIO26_FLASH_MODE_CFG BIT(10) +#define GPIO25_FLASH_MODE_CFG BIT(9) +#define GPIO24_FLASH_MODE_CFG BIT(8) +#define GPIO23_FLASH_MODE_CFG BIT(7) +#define GPIO22_FLASH_MODE_CFG BIT(6) +#define GPIO21_FLASH_MODE_CFG BIT(5) +#define GPIO20_FLASH_MODE_CFG BIT(4) +#define GPIO19_FLASH_MODE_CFG BIT(3) +#define GPIO18_FLASH_MODE_CFG BIT(2) +#define GPIO17_FLASH_MODE_CFG BIT(1) +#define GPIO16_FLASH_MODE_CFG BIT(0) + +#define REG_GPIO_DATA1 0x0070 +#define REG_GPIO_OE1 0x0078 +#define REG_GPIO_INT1 0x007c +#define REG_GPIO_INT_EDGE1 0x0080 +#define REG_GPIO_INT_EDGE2 0x0084 +#define REG_GPIO_INT_EDGE3 0x0088 +#define REG_GPIO_INT_LEVEL1 0x008c +#define REG_GPIO_INT_LEVEL2 0x0090 +#define REG_GPIO_INT_LEVEL3 0x0094 + +#define AIROHA_NUM_PINS 64 +#define AIROHA_PIN_BANK_SIZE (AIROHA_NUM_PINS / 2) +#define AIROHA_REG_GPIOCTRL_NUM_PIN (AIROHA_NUM_PINS / 4) + +static const u32 gpio_data_regs[] = { + REG_GPIO_DATA, + REG_GPIO_DATA1 +}; + +static const u32 gpio_out_regs[] = { + REG_GPIO_OE, + REG_GPIO_OE1 +}; + +static const u32 gpio_dir_regs[] = { + REG_GPIO_CTRL, + REG_GPIO_CTRL1, + REG_GPIO_CTRL2, + REG_GPIO_CTRL3 +}; + +static const u32 irq_status_regs[] = { + REG_GPIO_INT, + REG_GPIO_INT1 +}; + +static const u32 irq_level_regs[] = { + REG_GPIO_INT_LEVEL, + REG_GPIO_INT_LEVEL1, + REG_GPIO_INT_LEVEL2, + REG_GPIO_INT_LEVEL3 +}; + +static const u32 irq_edge_regs[] = { + REG_GPIO_INT_EDGE, + REG_GPIO_INT_EDGE1, + REG_GPIO_INT_EDGE2, + REG_GPIO_INT_EDGE3 +}; + +struct airoha_pinctrl_reg { + u32 offset; + u32 mask; +}; + +enum airoha_pinctrl_mux_func { + AIROHA_FUNC_MUX, + AIROHA_FUNC_PWM_MUX, + AIROHA_FUNC_PWM_EXT_MUX, +}; + +struct airoha_pinctrl_func_group { + const char *name; + struct { + enum airoha_pinctrl_mux_func mux; + u32 offset; + u32 mask; + u32 val; + } regmap[2]; + int regmap_size; +}; + +struct airoha_pinctrl_func { + const struct function_desc desc; + const struct airoha_pinctrl_func_group *groups; + u8 group_size; +}; + +struct airoha_pinctrl_conf { + u32 pin; + struct airoha_pinctrl_reg reg; +}; + +struct airoha_pinctrl_gpiochip { + struct gpio_chip chip; + + /* gpio */ + const u32 *data; + const u32 *dir; + const u32 *out; + /* irq */ + const u32 *status; + const u32 *level; + const u32 *edge; + + u32 irq_type[AIROHA_NUM_PINS]; +}; + +struct airoha_pinctrl { + struct pinctrl_dev *ctrl; + + struct regmap *chip_scu; + struct regmap *regmap; + + struct airoha_pinctrl_gpiochip gpiochip; +}; + +static struct pinctrl_pin_desc airoha_pinctrl_pins[] = { + PINCTRL_PIN(0, "uart1_txd"), + PINCTRL_PIN(1, "uart1_rxd"), + PINCTRL_PIN(2, "i2c_scl"), + PINCTRL_PIN(3, "i2c_sda"), + PINCTRL_PIN(4, "spi_cs0"), + PINCTRL_PIN(5, "spi_clk"), + PINCTRL_PIN(6, "spi_mosi"), + PINCTRL_PIN(7, "spi_miso"), + PINCTRL_PIN(13, "gpio0"), + PINCTRL_PIN(14, "gpio1"), + PINCTRL_PIN(15, "gpio2"), + PINCTRL_PIN(16, "gpio3"), + PINCTRL_PIN(17, "gpio4"), + PINCTRL_PIN(18, "gpio5"), + PINCTRL_PIN(19, "gpio6"), + PINCTRL_PIN(20, "gpio7"), + PINCTRL_PIN(21, "gpio8"), + PINCTRL_PIN(22, "gpio9"), + PINCTRL_PIN(23, "gpio10"), + PINCTRL_PIN(24, "gpio11"), + PINCTRL_PIN(25, "gpio12"), + PINCTRL_PIN(26, "gpio13"), + PINCTRL_PIN(27, "gpio14"), + PINCTRL_PIN(28, "gpio15"), + PINCTRL_PIN(29, "gpio16"), + PINCTRL_PIN(30, "gpio17"), + PINCTRL_PIN(31, "gpio18"), + PINCTRL_PIN(32, "gpio19"), + PINCTRL_PIN(33, "gpio20"), + PINCTRL_PIN(34, "gpio21"), + PINCTRL_PIN(35, "gpio22"), + PINCTRL_PIN(36, "gpio23"), + PINCTRL_PIN(37, "gpio24"), + PINCTRL_PIN(38, "gpio25"), + PINCTRL_PIN(39, "gpio26"), + PINCTRL_PIN(40, "gpio27"), + PINCTRL_PIN(41, "gpio28"), + PINCTRL_PIN(42, "gpio29"), + PINCTRL_PIN(43, "gpio30"), + PINCTRL_PIN(44, "gpio31"), + PINCTRL_PIN(45, "gpio32"), + PINCTRL_PIN(46, "gpio33"), + PINCTRL_PIN(47, "gpio34"), + PINCTRL_PIN(48, "gpio35"), + PINCTRL_PIN(49, "gpio36"), + PINCTRL_PIN(50, "gpio37"), + PINCTRL_PIN(51, "gpio38"), + PINCTRL_PIN(52, "gpio39"), + PINCTRL_PIN(53, "gpio40"), + PINCTRL_PIN(54, "gpio41"), + PINCTRL_PIN(55, "gpio42"), + PINCTRL_PIN(56, "gpio43"), + PINCTRL_PIN(57, "gpio44"), + PINCTRL_PIN(58, "gpio45"), + PINCTRL_PIN(59, "gpio46"), + PINCTRL_PIN(61, "pcie_reset0"), + PINCTRL_PIN(62, "pcie_reset1"), + PINCTRL_PIN(63, "pcie_reset2"), +}; + +static const int pon_pins[] = { 49, 50, 51, 52, 53, 54 }; +static const int pon_tod_1pps_pins[] = { 46 }; +static const int gsw_tod_1pps_pins[] = { 46 }; +static const int sipo_pins[] = { 16, 17 }; +static const int sipo_rclk_pins[] = { 16, 17, 43 }; +static const int mdio_pins[] = { 14, 15 }; +static const int uart2_pins[] = { 48, 55 }; +static const int uart2_cts_rts_pins[] = { 46, 47 }; +static const int hsuart_pins[] = { 28, 29 }; +static const int hsuart_cts_rts_pins[] = { 26, 27 }; +static const int uart4_pins[] = { 38, 39 }; +static const int uart5_pins[] = { 18, 19 }; +static const int i2c0_pins[] = { 2, 3 }; +static const int i2c1_pins[] = { 14, 15 }; +static const int jtag_udi_pins[] = { 16, 17, 18, 19, 20 }; +static const int jtag_dfd_pins[] = { 16, 17, 18, 19, 20 }; +static const int i2s_pins[] = { 26, 27, 28, 29 }; +static const int pcm1_pins[] = { 22, 23, 24, 25 }; +static const int pcm2_pins[] = { 18, 19, 20, 21 }; +static const int spi_quad_pins[] = { 32, 33 }; +static const int spi_pins[] = { 4, 5, 6, 7 }; +static const int spi_cs1_pins[] = { 34 }; +static const int pcm_spi_pins[] = { 18, 19, 20, 21, 22, 23, 24, 25 }; +static const int pcm_spi_int_pins[] = { 14 }; +static const int pcm_spi_rst_pins[] = { 15 }; +static const int pcm_spi_cs1_pins[] = { 43 }; +static const int pcm_spi_cs2_pins[] = { 40 }; +static const int pcm_spi_cs2_p128_pins[] = { 40 }; +static const int pcm_spi_cs2_p156_pins[] = { 40 }; +static const int pcm_spi_cs3_pins[] = { 41 }; +static const int pcm_spi_cs4_pins[] = { 42 }; +static const int emmc_pins[] = { 4, 5, 6, 30, 31, 32, 33, 34, 35, 36, 37 }; +static const int pnand_pins[] = { 4, 5, 6, 7, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42 }; +static const int gpio0_pins[] = { 13 }; +static const int gpio1_pins[] = { 14 }; +static const int gpio2_pins[] = { 15 }; +static const int gpio3_pins[] = { 16 }; +static const int gpio4_pins[] = { 17 }; +static const int gpio5_pins[] = { 18 }; +static const int gpio6_pins[] = { 19 }; +static const int gpio7_pins[] = { 20 }; +static const int gpio8_pins[] = { 21 }; +static const int gpio9_pins[] = { 22 }; +static const int gpio10_pins[] = { 23 }; +static const int gpio11_pins[] = { 24 }; +static const int gpio12_pins[] = { 25 }; +static const int gpio13_pins[] = { 26 }; +static const int gpio14_pins[] = { 27 }; +static const int gpio15_pins[] = { 28 }; +static const int gpio16_pins[] = { 29 }; +static const int gpio17_pins[] = { 30 }; +static const int gpio18_pins[] = { 31 }; +static const int gpio19_pins[] = { 32 }; +static const int gpio20_pins[] = { 33 }; +static const int gpio21_pins[] = { 34 }; +static const int gpio22_pins[] = { 35 }; +static const int gpio23_pins[] = { 36 }; +static const int gpio24_pins[] = { 37 }; +static const int gpio25_pins[] = { 38 }; +static const int gpio26_pins[] = { 39 }; +static const int gpio27_pins[] = { 40 }; +static const int gpio28_pins[] = { 41 }; +static const int gpio29_pins[] = { 42 }; +static const int gpio30_pins[] = { 43 }; +static const int gpio31_pins[] = { 44 }; +static const int gpio33_pins[] = { 46 }; +static const int gpio34_pins[] = { 47 }; +static const int gpio35_pins[] = { 48 }; +static const int gpio36_pins[] = { 49 }; +static const int gpio37_pins[] = { 50 }; +static const int gpio38_pins[] = { 51 }; +static const int gpio39_pins[] = { 52 }; +static const int gpio40_pins[] = { 53 }; +static const int gpio41_pins[] = { 54 }; +static const int gpio42_pins[] = { 55 }; +static const int gpio43_pins[] = { 56 }; +static const int gpio44_pins[] = { 57 }; +static const int gpio45_pins[] = { 58 }; +static const int gpio46_pins[] = { 59 }; +static const int pcie_reset0_pins[] = { 61 }; +static const int pcie_reset1_pins[] = { 62 }; +static const int pcie_reset2_pins[] = { 63 }; + +static const struct pingroup airoha_pinctrl_groups[] = { + PINCTRL_PIN_GROUP(pon), + PINCTRL_PIN_GROUP(pon_tod_1pps), + PINCTRL_PIN_GROUP(gsw_tod_1pps), + PINCTRL_PIN_GROUP(sipo), + PINCTRL_PIN_GROUP(sipo_rclk), + PINCTRL_PIN_GROUP(mdio), + PINCTRL_PIN_GROUP(uart2), + PINCTRL_PIN_GROUP(uart2_cts_rts), + PINCTRL_PIN_GROUP(hsuart), + PINCTRL_PIN_GROUP(hsuart_cts_rts), + PINCTRL_PIN_GROUP(uart4), + PINCTRL_PIN_GROUP(uart5), + PINCTRL_PIN_GROUP(i2c0), + PINCTRL_PIN_GROUP(i2c1), + PINCTRL_PIN_GROUP(jtag_udi), + PINCTRL_PIN_GROUP(jtag_dfd), + PINCTRL_PIN_GROUP(i2s), + PINCTRL_PIN_GROUP(pcm1), + PINCTRL_PIN_GROUP(pcm2), + PINCTRL_PIN_GROUP(spi), + PINCTRL_PIN_GROUP(spi_quad), + PINCTRL_PIN_GROUP(spi_cs1), + PINCTRL_PIN_GROUP(pcm_spi), + PINCTRL_PIN_GROUP(pcm_spi_int), + PINCTRL_PIN_GROUP(pcm_spi_rst), + PINCTRL_PIN_GROUP(pcm_spi_cs1), + PINCTRL_PIN_GROUP(pcm_spi_cs2_p128), + PINCTRL_PIN_GROUP(pcm_spi_cs2_p156), + PINCTRL_PIN_GROUP(pcm_spi_cs2), + PINCTRL_PIN_GROUP(pcm_spi_cs3), + PINCTRL_PIN_GROUP(pcm_spi_cs4), + PINCTRL_PIN_GROUP(emmc), + PINCTRL_PIN_GROUP(pnand), + PINCTRL_PIN_GROUP(gpio0), + PINCTRL_PIN_GROUP(gpio1), + PINCTRL_PIN_GROUP(gpio2), + PINCTRL_PIN_GROUP(gpio3), + PINCTRL_PIN_GROUP(gpio4), + PINCTRL_PIN_GROUP(gpio5), + PINCTRL_PIN_GROUP(gpio6), + PINCTRL_PIN_GROUP(gpio7), + PINCTRL_PIN_GROUP(gpio8), + PINCTRL_PIN_GROUP(gpio9), + PINCTRL_PIN_GROUP(gpio10), + PINCTRL_PIN_GROUP(gpio11), + PINCTRL_PIN_GROUP(gpio12), + PINCTRL_PIN_GROUP(gpio13), + PINCTRL_PIN_GROUP(gpio14), + PINCTRL_PIN_GROUP(gpio15), + PINCTRL_PIN_GROUP(gpio16), + PINCTRL_PIN_GROUP(gpio17), + PINCTRL_PIN_GROUP(gpio18), + PINCTRL_PIN_GROUP(gpio19), + PINCTRL_PIN_GROUP(gpio20), + PINCTRL_PIN_GROUP(gpio21), + PINCTRL_PIN_GROUP(gpio22), + PINCTRL_PIN_GROUP(gpio23), + PINCTRL_PIN_GROUP(gpio24), + PINCTRL_PIN_GROUP(gpio25), + PINCTRL_PIN_GROUP(gpio26), + PINCTRL_PIN_GROUP(gpio27), + PINCTRL_PIN_GROUP(gpio28), + PINCTRL_PIN_GROUP(gpio29), + PINCTRL_PIN_GROUP(gpio30), + PINCTRL_PIN_GROUP(gpio31), + PINCTRL_PIN_GROUP(gpio33), + PINCTRL_PIN_GROUP(gpio34), + PINCTRL_PIN_GROUP(gpio35), + PINCTRL_PIN_GROUP(gpio36), + PINCTRL_PIN_GROUP(gpio37), + PINCTRL_PIN_GROUP(gpio38), + PINCTRL_PIN_GROUP(gpio39), + PINCTRL_PIN_GROUP(gpio40), + PINCTRL_PIN_GROUP(gpio41), + PINCTRL_PIN_GROUP(gpio42), + PINCTRL_PIN_GROUP(gpio43), + PINCTRL_PIN_GROUP(gpio44), + PINCTRL_PIN_GROUP(gpio45), + PINCTRL_PIN_GROUP(gpio46), + PINCTRL_PIN_GROUP(pcie_reset0), + PINCTRL_PIN_GROUP(pcie_reset1), + PINCTRL_PIN_GROUP(pcie_reset2), +}; + +static const char *const pon_groups[] = { "pon" }; +static const char *const tod_1pps_groups[] = { "pon_tod_1pps", "gsw_tod_1pps" }; +static const char *const sipo_groups[] = { "sipo", "sipo_rclk" }; +static const char *const mdio_groups[] = { "mdio" }; +static const char *const uart_groups[] = { "uart2", "uart2_cts_rts", "hsuart", + "hsuart_cts_rts", "uart4", + "uart5" }; +static const char *const i2c_groups[] = { "i2c1" }; +static const char *const jtag_groups[] = { "jtag_udi", "jtag_dfd" }; +static const char *const pcm_groups[] = { "pcm1", "pcm2" }; +static const char *const spi_groups[] = { "spi_quad", "spi_cs1" }; +static const char *const pcm_spi_groups[] = { "pcm_spi", "pcm_spi_int", + "pcm_spi_rst", "pcm_spi_cs1", + "pcm_spi_cs2_p156", + "pcm_spi_cs2_p128", + "pcm_spi_cs3", "pcm_spi_cs4" }; +static const char *const i2s_groups[] = { "i2s" }; +static const char *const emmc_groups[] = { "emmc" }; +static const char *const pnand_groups[] = { "pnand" }; +static const char *const pcie_reset_groups[] = { "pcie_reset0", "pcie_reset1", + "pcie_reset2" }; +static const char *const pwm_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", + "gpio36", "gpio37", + "gpio38", "gpio39", + "gpio40", "gpio41", + "gpio42", "gpio43", + "gpio44", "gpio45", + "gpio46", "gpio47" }; +static const char *const phy1_led0_groups[] = { "gpio33", "gpio34", + "gpio35", "gpio42" }; +static const char *const phy2_led0_groups[] = { "gpio33", "gpio34", + "gpio35", "gpio42" }; +static const char *const phy3_led0_groups[] = { "gpio33", "gpio34", + "gpio35", "gpio42" }; +static const char *const phy4_led0_groups[] = { "gpio33", "gpio34", + "gpio35", "gpio42" }; +static const char *const phy1_led1_groups[] = { "gpio43", "gpio44", + "gpio45", "gpio46" }; +static const char *const phy2_led1_groups[] = { "gpio43", "gpio44", + "gpio45", "gpio46" }; +static const char *const phy3_led1_groups[] = { "gpio43", "gpio44", + "gpio45", "gpio46" }; +static const char *const phy4_led1_groups[] = { "gpio43", "gpio44", + "gpio45", "gpio46" }; + +static const struct airoha_pinctrl_func_group pon_func_group[] = { + { + .name = "pon", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PON_MODE_MASK, + GPIO_PON_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = { + { + .name = "pon_tod_1pps", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + PON_TOD_1PPS_MODE_MASK, + PON_TOD_1PPS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "gsw_tod_1pps", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GSW_TOD_1PPS_MODE_MASK, + GSW_TOD_1PPS_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group sipo_func_group[] = { + { + .name = "sipo", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK, + GPIO_SIPO_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "sipo_rclk", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group mdio_func_group[] = { + { + .name = "mdio", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SGMII_MDIO_MODE_MASK, + GPIO_SGMII_MDIO_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_MDC_IO_MASTER_MODE_MODE, + GPIO_MDC_IO_MASTER_MODE_MODE + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group uart_func_group[] = { + { + .name = "uart2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART2_MODE_MASK, + GPIO_UART2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart2_cts_rts", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK, + GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "hsuart", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK, + GPIO_HSUART_MODE_MASK + }, + .regmap_size = 1, + }, + { + .name = "hsuart_cts_rts", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART4_MODE_MASK, + GPIO_UART4_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart5", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART5_MODE_MASK, + GPIO_UART5_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group i2c_func_group[] = { + { + .name = "i2c1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_2ND_I2C_MODE_MASK, + GPIO_2ND_I2C_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group jtag_func_group[] = { + { + .name = "jtag_udi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + JTAG_UDI_EN_MASK, + JTAG_UDI_EN_MASK + }, + .regmap_size = 1, + }, { + .name = "jtag_dfd", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + JTAG_DFD_EN_MASK, + JTAG_DFD_EN_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcm_func_group[] = { + { + .name = "pcm1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM1_MODE_MASK, + GPIO_PCM1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM2_MODE_MASK, + GPIO_PCM2_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group spi_func_group[] = { + { + .name = "spi_quad", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_QUAD_MODE_MASK, + GPIO_SPI_QUAD_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS1_MODE_MASK, + GPIO_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS2_MODE_MASK, + GPIO_SPI_CS2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs3", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS3_MODE_MASK, + GPIO_SPI_CS3_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS4_MODE_MASK, + GPIO_SPI_CS4_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = { + { + .name = "pcm_spi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_MODE_MASK, + GPIO_PCM_SPI_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_int", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_INT_MODE_MASK, + GPIO_PCM_INT_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_rst", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_RESET_MODE_MASK, + GPIO_PCM_RESET_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS1_MODE_MASK, + GPIO_PCM_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs2_p128", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS2_MODE_P128_MASK, + GPIO_PCM_SPI_CS2_MODE_P128_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs2_p156", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS2_MODE_P156_MASK, + GPIO_PCM_SPI_CS2_MODE_P156_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs3", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS3_MODE_MASK, + GPIO_PCM_SPI_CS3_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS4_MODE_MASK, + GPIO_PCM_SPI_CS4_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group i2s_func_group[] = { + { + .name = "i2s", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_I2S_MODE_MASK, + GPIO_I2S_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group emmc_func_group[] = { + { + .name = "emmc", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_EMMC_MODE_MASK, + GPIO_EMMC_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pnand_func_group[] = { + { + .name = "pnand", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PARALLEL_NAND_MODE_MASK, + GPIO_PARALLEL_NAND_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = { + { + .name = "pcie_reset0", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET0_MASK, + GPIO_PCIE_RESET0_MASK + }, + .regmap_size = 1, + }, { + .name = "pcie_reset1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET1_MASK, + GPIO_PCIE_RESET1_MASK + }, + .regmap_size = 1, + }, { + .name = "pcie_reset2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET2_MASK, + GPIO_PCIE_RESET2_MASK + }, + .regmap_size = 1, + }, +}; + +/* PWM */ +static const struct airoha_pinctrl_func_group pwm_func_group[] = { + { + .name = "gpio0", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO0_FLASH_MODE_CFG, + GPIO0_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio1", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO1_FLASH_MODE_CFG, + GPIO1_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio2", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO2_FLASH_MODE_CFG, + GPIO2_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio3", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO3_FLASH_MODE_CFG, + GPIO3_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio4", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO4_FLASH_MODE_CFG, + GPIO4_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio5", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO5_FLASH_MODE_CFG, + GPIO5_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio6", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO6_FLASH_MODE_CFG, + GPIO6_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio7", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO7_FLASH_MODE_CFG, + GPIO7_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio8", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO8_FLASH_MODE_CFG, + GPIO8_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio9", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO9_FLASH_MODE_CFG, + GPIO9_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio10", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO10_FLASH_MODE_CFG, + GPIO10_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio11", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO11_FLASH_MODE_CFG, + GPIO11_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio12", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO12_FLASH_MODE_CFG, + GPIO12_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio13", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO13_FLASH_MODE_CFG, + GPIO13_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio14", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO14_FLASH_MODE_CFG, + GPIO14_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio15", + .regmap[0] = { + AIROHA_FUNC_PWM_MUX, + REG_GPIO_FLASH_MODE_CFG, + GPIO15_FLASH_MODE_CFG, + GPIO15_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio16", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO16_FLASH_MODE_CFG, + GPIO16_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio17", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO17_FLASH_MODE_CFG, + GPIO17_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio18", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO18_FLASH_MODE_CFG, + GPIO18_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio19", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO19_FLASH_MODE_CFG, + GPIO19_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio20", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO20_FLASH_MODE_CFG, + GPIO20_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio21", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO21_FLASH_MODE_CFG, + GPIO21_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio22", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO22_FLASH_MODE_CFG, + GPIO22_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio23", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO23_FLASH_MODE_CFG, + GPIO23_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio24", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO24_FLASH_MODE_CFG, + GPIO24_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio25", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO25_FLASH_MODE_CFG, + GPIO25_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio26", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO26_FLASH_MODE_CFG, + GPIO26_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio27", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO27_FLASH_MODE_CFG, + GPIO27_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio28", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO28_FLASH_MODE_CFG, + GPIO28_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio29", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO29_FLASH_MODE_CFG, + GPIO29_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio30", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO30_FLASH_MODE_CFG, + GPIO30_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio31", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO31_FLASH_MODE_CFG, + GPIO31_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio36", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO36_FLASH_MODE_CFG, + GPIO36_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio37", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO37_FLASH_MODE_CFG, + GPIO37_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio38", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO38_FLASH_MODE_CFG, + GPIO38_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio39", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO39_FLASH_MODE_CFG, + GPIO39_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio40", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO40_FLASH_MODE_CFG, + GPIO40_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio41", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO41_FLASH_MODE_CFG, + GPIO41_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio42", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO42_FLASH_MODE_CFG, + GPIO42_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio43", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO43_FLASH_MODE_CFG, + GPIO43_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio44", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO44_FLASH_MODE_CFG, + GPIO44_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio45", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO45_FLASH_MODE_CFG, + GPIO45_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio46", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO46_FLASH_MODE_CFG, + GPIO46_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, { + .name = "gpio47", + .regmap[0] = { + AIROHA_FUNC_PWM_EXT_MUX, + REG_GPIO_FLASH_MODE_CFG_EXT, + GPIO47_FLASH_MODE_CFG, + GPIO47_FLASH_MODE_CFG + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = { + { + .name = "gpio33", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN0_LED0_MODE_MASK, + GPIO_LAN0_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN1_LED_MAPPING_MASK, + LAN1_PHY1_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio34", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN1_LED0_MODE_MASK, + GPIO_LAN1_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN2_LED_MAPPING_MASK, + LAN2_PHY1_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio35", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN2_LED0_MODE_MASK, + GPIO_LAN2_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN3_LED_MAPPING_MASK, + LAN3_PHY1_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio42", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN3_LED0_MODE_MASK, + GPIO_LAN3_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN4_LED_MAPPING_MASK, + LAN4_PHY1_LED_MAP + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = { + { + .name = "gpio33", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN0_LED0_MODE_MASK, + GPIO_LAN0_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN1_LED_MAPPING_MASK, + LAN1_PHY2_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio34", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN1_LED0_MODE_MASK, + GPIO_LAN1_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN2_LED_MAPPING_MASK, + LAN2_PHY2_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio35", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN2_LED0_MODE_MASK, + GPIO_LAN2_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN3_LED_MAPPING_MASK, + LAN3_PHY2_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio42", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN3_LED0_MODE_MASK, + GPIO_LAN3_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN4_LED_MAPPING_MASK, + LAN4_PHY2_LED_MAP + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = { + { + .name = "gpio33", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN0_LED0_MODE_MASK, + GPIO_LAN0_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN1_LED_MAPPING_MASK, + LAN1_PHY3_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio34", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN1_LED0_MODE_MASK, + GPIO_LAN1_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN2_LED_MAPPING_MASK, + LAN2_PHY3_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio35", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN2_LED0_MODE_MASK, + GPIO_LAN2_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN3_LED_MAPPING_MASK, + LAN3_PHY3_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio42", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN3_LED0_MODE_MASK, + GPIO_LAN3_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN4_LED_MAPPING_MASK, + LAN4_PHY3_LED_MAP + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = { + { + .name = "gpio33", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN0_LED0_MODE_MASK, + GPIO_LAN0_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN1_LED_MAPPING_MASK, + LAN1_PHY4_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio34", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN1_LED0_MODE_MASK, + GPIO_LAN1_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN2_LED_MAPPING_MASK, + LAN2_PHY4_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio35", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN2_LED0_MODE_MASK, + GPIO_LAN2_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN3_LED_MAPPING_MASK, + LAN3_PHY4_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio42", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN3_LED0_MODE_MASK, + GPIO_LAN3_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED0_MAPPING, + LAN4_LED_MAPPING_MASK, + LAN4_PHY4_LED_MAP + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = { + { + .name = "gpio43", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN0_LED1_MODE_MASK, + GPIO_LAN0_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN1_LED_MAPPING_MASK, + LAN1_PHY1_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio44", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN1_LED1_MODE_MASK, + GPIO_LAN1_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN2_LED_MAPPING_MASK, + LAN2_PHY1_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio45", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN2_LED1_MODE_MASK, + GPIO_LAN2_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN3_LED_MAPPING_MASK, + LAN3_PHY1_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio46", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN3_LED0_MODE_MASK, + GPIO_LAN3_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN4_LED_MAPPING_MASK, + LAN4_PHY1_LED_MAP + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = { + { + .name = "gpio43", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN0_LED1_MODE_MASK, + GPIO_LAN0_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN1_LED_MAPPING_MASK, + LAN1_PHY2_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio44", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN1_LED1_MODE_MASK, + GPIO_LAN1_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN2_LED_MAPPING_MASK, + LAN2_PHY2_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio45", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN2_LED1_MODE_MASK, + GPIO_LAN2_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN3_LED_MAPPING_MASK, + LAN3_PHY2_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio46", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN3_LED0_MODE_MASK, + GPIO_LAN3_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN4_LED_MAPPING_MASK, + LAN4_PHY2_LED_MAP + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = { + { + .name = "gpio43", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN0_LED1_MODE_MASK, + GPIO_LAN0_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN1_LED_MAPPING_MASK, + LAN1_PHY3_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio44", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN1_LED1_MODE_MASK, + GPIO_LAN1_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN2_LED_MAPPING_MASK, + LAN2_PHY3_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio45", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN2_LED1_MODE_MASK, + GPIO_LAN2_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN3_LED_MAPPING_MASK, + LAN3_PHY3_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio46", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN3_LED0_MODE_MASK, + GPIO_LAN3_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN4_LED_MAPPING_MASK, + LAN4_PHY3_LED_MAP + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = { + { + .name = "gpio43", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN0_LED1_MODE_MASK, + GPIO_LAN0_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN1_LED_MAPPING_MASK, + LAN1_PHY4_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio44", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN1_LED1_MODE_MASK, + GPIO_LAN1_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN2_LED_MAPPING_MASK, + LAN2_PHY4_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio45", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN2_LED1_MODE_MASK, + GPIO_LAN2_LED1_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN3_LED_MAPPING_MASK, + LAN3_PHY4_LED_MAP + }, + .regmap_size = 2, + }, { + .name = "gpio46", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_LAN3_LED0_MODE_MASK, + GPIO_LAN3_LED0_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_LAN_LED1_MAPPING, + LAN4_LED_MAPPING_MASK, + LAN4_PHY4_LED_MAP + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func airoha_pinctrl_funcs[] = { + PINCTRL_FUNC_DESC(pon), + PINCTRL_FUNC_DESC(tod_1pps), + PINCTRL_FUNC_DESC(sipo), + PINCTRL_FUNC_DESC(mdio), + PINCTRL_FUNC_DESC(uart), + PINCTRL_FUNC_DESC(i2c), + PINCTRL_FUNC_DESC(jtag), + PINCTRL_FUNC_DESC(pcm), + PINCTRL_FUNC_DESC(spi), + PINCTRL_FUNC_DESC(pcm_spi), + PINCTRL_FUNC_DESC(i2s), + PINCTRL_FUNC_DESC(emmc), + PINCTRL_FUNC_DESC(pnand), + PINCTRL_FUNC_DESC(pcie_reset), + PINCTRL_FUNC_DESC(pwm), + PINCTRL_FUNC_DESC(phy1_led0), + PINCTRL_FUNC_DESC(phy2_led0), + PINCTRL_FUNC_DESC(phy3_led0), + PINCTRL_FUNC_DESC(phy4_led0), + PINCTRL_FUNC_DESC(phy1_led1), + PINCTRL_FUNC_DESC(phy2_led1), + PINCTRL_FUNC_DESC(phy3_led1), + PINCTRL_FUNC_DESC(phy4_led1), +}; + +static const struct airoha_pinctrl_conf airoha_pinctrl_pullup_conf[] = { + PINCTRL_CONF_DESC(0, REG_I2C_SDA_PU, UART1_TXD_PU_MASK), + PINCTRL_CONF_DESC(1, REG_I2C_SDA_PU, UART1_RXD_PU_MASK), + PINCTRL_CONF_DESC(2, REG_I2C_SDA_PU, I2C_SDA_PU_MASK), + PINCTRL_CONF_DESC(3, REG_I2C_SDA_PU, I2C_SCL_PU_MASK), + PINCTRL_CONF_DESC(4, REG_I2C_SDA_PU, SPI_CS0_PU_MASK), + PINCTRL_CONF_DESC(5, REG_I2C_SDA_PU, SPI_CLK_PU_MASK), + PINCTRL_CONF_DESC(6, REG_I2C_SDA_PU, SPI_MOSI_PU_MASK), + PINCTRL_CONF_DESC(7, REG_I2C_SDA_PU, SPI_MISO_PU_MASK), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PU, BIT(0)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PU, BIT(1)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PU, BIT(2)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PU, BIT(3)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PU, BIT(4)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PU, BIT(5)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PU, BIT(6)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PU, BIT(7)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PU, BIT(8)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PU, BIT(9)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PU, BIT(10)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PU, BIT(11)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PU, BIT(12)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PU, BIT(13)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PU, BIT(14)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PU, BIT(15)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PU, BIT(16)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PU, BIT(17)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PU, BIT(18)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PU, BIT(18)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PU, BIT(20)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_PU, BIT(21)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_PU, BIT(22)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_PU, BIT(23)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_PU, BIT(24)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_PU, BIT(25)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_PU, BIT(26)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_PU, BIT(27)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_PU, BIT(28)), + PINCTRL_CONF_DESC(42, REG_GPIO_L_PU, BIT(29)), + PINCTRL_CONF_DESC(43, REG_GPIO_L_PU, BIT(30)), + PINCTRL_CONF_DESC(44, REG_GPIO_L_PU, BIT(31)), + PINCTRL_CONF_DESC(45, REG_GPIO_H_PU, BIT(0)), + PINCTRL_CONF_DESC(46, REG_GPIO_H_PU, BIT(1)), + PINCTRL_CONF_DESC(47, REG_GPIO_H_PU, BIT(2)), + PINCTRL_CONF_DESC(48, REG_GPIO_H_PU, BIT(3)), + PINCTRL_CONF_DESC(49, REG_GPIO_H_PU, BIT(4)), + PINCTRL_CONF_DESC(50, REG_GPIO_H_PU, BIT(5)), + PINCTRL_CONF_DESC(51, REG_GPIO_H_PU, BIT(6)), + PINCTRL_CONF_DESC(52, REG_GPIO_H_PU, BIT(7)), + PINCTRL_CONF_DESC(53, REG_GPIO_H_PU, BIT(8)), + PINCTRL_CONF_DESC(54, REG_GPIO_H_PU, BIT(9)), + PINCTRL_CONF_DESC(55, REG_GPIO_H_PU, BIT(10)), + PINCTRL_CONF_DESC(56, REG_GPIO_H_PU, BIT(11)), + PINCTRL_CONF_DESC(57, REG_GPIO_H_PU, BIT(12)), + PINCTRL_CONF_DESC(58, REG_GPIO_H_PU, BIT(13)), + PINCTRL_CONF_DESC(59, REG_GPIO_H_PU, BIT(14)), + PINCTRL_CONF_DESC(61, REG_I2C_SDA_PU, PCIE0_RESET_PU_MASK), + PINCTRL_CONF_DESC(62, REG_I2C_SDA_PU, PCIE1_RESET_PU_MASK), + PINCTRL_CONF_DESC(63, REG_I2C_SDA_PU, PCIE2_RESET_PU_MASK), +}; + +static const struct airoha_pinctrl_conf airoha_pinctrl_pulldown_conf[] = { + PINCTRL_CONF_DESC(0, REG_I2C_SDA_PD, UART1_TXD_PD_MASK), + PINCTRL_CONF_DESC(1, REG_I2C_SDA_PD, UART1_RXD_PD_MASK), + PINCTRL_CONF_DESC(2, REG_I2C_SDA_PD, I2C_SDA_PD_MASK), + PINCTRL_CONF_DESC(3, REG_I2C_SDA_PD, I2C_SCL_PD_MASK), + PINCTRL_CONF_DESC(4, REG_I2C_SDA_PD, SPI_CS0_PD_MASK), + PINCTRL_CONF_DESC(5, REG_I2C_SDA_PD, SPI_CLK_PD_MASK), + PINCTRL_CONF_DESC(6, REG_I2C_SDA_PD, SPI_MOSI_PD_MASK), + PINCTRL_CONF_DESC(7, REG_I2C_SDA_PD, SPI_MISO_PD_MASK), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PD, BIT(0)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PD, BIT(1)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PD, BIT(2)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PD, BIT(3)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PD, BIT(4)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PD, BIT(5)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PD, BIT(6)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PD, BIT(7)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PD, BIT(8)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PD, BIT(9)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PD, BIT(10)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PD, BIT(11)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PD, BIT(12)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PD, BIT(13)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PD, BIT(14)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PD, BIT(15)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PD, BIT(16)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PD, BIT(17)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PD, BIT(18)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PD, BIT(18)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PD, BIT(20)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_PD, BIT(21)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_PD, BIT(22)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_PD, BIT(23)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_PD, BIT(24)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_PD, BIT(25)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_PD, BIT(26)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_PD, BIT(27)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_PD, BIT(28)), + PINCTRL_CONF_DESC(42, REG_GPIO_L_PD, BIT(29)), + PINCTRL_CONF_DESC(43, REG_GPIO_L_PD, BIT(30)), + PINCTRL_CONF_DESC(44, REG_GPIO_L_PD, BIT(31)), + PINCTRL_CONF_DESC(45, REG_GPIO_H_PD, BIT(0)), + PINCTRL_CONF_DESC(46, REG_GPIO_H_PD, BIT(1)), + PINCTRL_CONF_DESC(47, REG_GPIO_H_PD, BIT(2)), + PINCTRL_CONF_DESC(48, REG_GPIO_H_PD, BIT(3)), + PINCTRL_CONF_DESC(49, REG_GPIO_H_PD, BIT(4)), + PINCTRL_CONF_DESC(50, REG_GPIO_H_PD, BIT(5)), + PINCTRL_CONF_DESC(51, REG_GPIO_H_PD, BIT(6)), + PINCTRL_CONF_DESC(52, REG_GPIO_H_PD, BIT(7)), + PINCTRL_CONF_DESC(53, REG_GPIO_H_PD, BIT(8)), + PINCTRL_CONF_DESC(54, REG_GPIO_H_PD, BIT(9)), + PINCTRL_CONF_DESC(55, REG_GPIO_H_PD, BIT(10)), + PINCTRL_CONF_DESC(56, REG_GPIO_H_PD, BIT(11)), + PINCTRL_CONF_DESC(57, REG_GPIO_H_PD, BIT(12)), + PINCTRL_CONF_DESC(58, REG_GPIO_H_PD, BIT(13)), + PINCTRL_CONF_DESC(59, REG_GPIO_H_PD, BIT(14)), + PINCTRL_CONF_DESC(61, REG_I2C_SDA_PD, PCIE0_RESET_PD_MASK), + PINCTRL_CONF_DESC(62, REG_I2C_SDA_PD, PCIE1_RESET_PD_MASK), + PINCTRL_CONF_DESC(63, REG_I2C_SDA_PD, PCIE2_RESET_PD_MASK), +}; + +static const struct airoha_pinctrl_conf airoha_pinctrl_drive_e2_conf[] = { + PINCTRL_CONF_DESC(0, REG_I2C_SDA_E2, UART1_TXD_E2_MASK), + PINCTRL_CONF_DESC(1, REG_I2C_SDA_E2, UART1_RXD_E2_MASK), + PINCTRL_CONF_DESC(2, REG_I2C_SDA_E2, I2C_SDA_E2_MASK), + PINCTRL_CONF_DESC(3, REG_I2C_SDA_E2, I2C_SCL_E2_MASK), + PINCTRL_CONF_DESC(4, REG_I2C_SDA_E2, SPI_CS0_E2_MASK), + PINCTRL_CONF_DESC(5, REG_I2C_SDA_E2, SPI_CLK_E2_MASK), + PINCTRL_CONF_DESC(6, REG_I2C_SDA_E2, SPI_MOSI_E2_MASK), + PINCTRL_CONF_DESC(7, REG_I2C_SDA_E2, SPI_MISO_E2_MASK), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E2, BIT(0)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E2, BIT(1)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E2, BIT(2)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E2, BIT(3)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E2, BIT(4)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E2, BIT(5)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E2, BIT(6)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E2, BIT(7)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E2, BIT(8)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E2, BIT(9)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E2, BIT(10)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E2, BIT(11)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E2, BIT(12)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E2, BIT(13)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E2, BIT(14)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E2, BIT(15)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E2, BIT(16)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E2, BIT(17)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E2, BIT(18)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E2, BIT(18)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E2, BIT(20)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_E2, BIT(21)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_E2, BIT(22)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_E2, BIT(23)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_E2, BIT(24)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_E2, BIT(25)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_E2, BIT(26)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_E2, BIT(27)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_E2, BIT(28)), + PINCTRL_CONF_DESC(42, REG_GPIO_L_E2, BIT(29)), + PINCTRL_CONF_DESC(43, REG_GPIO_L_E2, BIT(30)), + PINCTRL_CONF_DESC(44, REG_GPIO_L_E2, BIT(31)), + PINCTRL_CONF_DESC(45, REG_GPIO_H_E2, BIT(0)), + PINCTRL_CONF_DESC(46, REG_GPIO_H_E2, BIT(1)), + PINCTRL_CONF_DESC(47, REG_GPIO_H_E2, BIT(2)), + PINCTRL_CONF_DESC(48, REG_GPIO_H_E2, BIT(3)), + PINCTRL_CONF_DESC(49, REG_GPIO_H_E2, BIT(4)), + PINCTRL_CONF_DESC(50, REG_GPIO_H_E2, BIT(5)), + PINCTRL_CONF_DESC(51, REG_GPIO_H_E2, BIT(6)), + PINCTRL_CONF_DESC(52, REG_GPIO_H_E2, BIT(7)), + PINCTRL_CONF_DESC(53, REG_GPIO_H_E2, BIT(8)), + PINCTRL_CONF_DESC(54, REG_GPIO_H_E2, BIT(9)), + PINCTRL_CONF_DESC(55, REG_GPIO_H_E2, BIT(10)), + PINCTRL_CONF_DESC(56, REG_GPIO_H_E2, BIT(11)), + PINCTRL_CONF_DESC(57, REG_GPIO_H_E2, BIT(12)), + PINCTRL_CONF_DESC(58, REG_GPIO_H_E2, BIT(13)), + PINCTRL_CONF_DESC(59, REG_GPIO_H_E2, BIT(14)), + PINCTRL_CONF_DESC(61, REG_I2C_SDA_E2, PCIE0_RESET_E2_MASK), + PINCTRL_CONF_DESC(62, REG_I2C_SDA_E2, PCIE1_RESET_E2_MASK), + PINCTRL_CONF_DESC(63, REG_I2C_SDA_E2, PCIE2_RESET_E2_MASK), +}; + +static const struct airoha_pinctrl_conf airoha_pinctrl_drive_e4_conf[] = { + PINCTRL_CONF_DESC(0, REG_I2C_SDA_E4, UART1_TXD_E4_MASK), + PINCTRL_CONF_DESC(1, REG_I2C_SDA_E4, UART1_RXD_E4_MASK), + PINCTRL_CONF_DESC(2, REG_I2C_SDA_E4, I2C_SDA_E4_MASK), + PINCTRL_CONF_DESC(3, REG_I2C_SDA_E4, I2C_SCL_E4_MASK), + PINCTRL_CONF_DESC(4, REG_I2C_SDA_E4, SPI_CS0_E4_MASK), + PINCTRL_CONF_DESC(5, REG_I2C_SDA_E4, SPI_CLK_E4_MASK), + PINCTRL_CONF_DESC(6, REG_I2C_SDA_E4, SPI_MOSI_E4_MASK), + PINCTRL_CONF_DESC(7, REG_I2C_SDA_E4, SPI_MISO_E4_MASK), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E4, BIT(0)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E4, BIT(1)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E4, BIT(2)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E4, BIT(3)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E4, BIT(4)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E4, BIT(5)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E4, BIT(6)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E4, BIT(7)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E4, BIT(8)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E4, BIT(9)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E4, BIT(10)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E4, BIT(11)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E4, BIT(12)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E4, BIT(13)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E4, BIT(14)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E4, BIT(15)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E4, BIT(16)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E4, BIT(17)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E4, BIT(18)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E4, BIT(18)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E4, BIT(20)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_E4, BIT(21)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_E4, BIT(22)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_E4, BIT(23)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_E4, BIT(24)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_E4, BIT(25)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_E4, BIT(26)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_E4, BIT(27)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_E4, BIT(28)), + PINCTRL_CONF_DESC(42, REG_GPIO_L_E4, BIT(29)), + PINCTRL_CONF_DESC(43, REG_GPIO_L_E4, BIT(30)), + PINCTRL_CONF_DESC(44, REG_GPIO_L_E4, BIT(31)), + PINCTRL_CONF_DESC(45, REG_GPIO_H_E4, BIT(0)), + PINCTRL_CONF_DESC(46, REG_GPIO_H_E4, BIT(1)), + PINCTRL_CONF_DESC(47, REG_GPIO_H_E4, BIT(2)), + PINCTRL_CONF_DESC(48, REG_GPIO_H_E4, BIT(3)), + PINCTRL_CONF_DESC(49, REG_GPIO_H_E4, BIT(4)), + PINCTRL_CONF_DESC(50, REG_GPIO_H_E4, BIT(5)), + PINCTRL_CONF_DESC(51, REG_GPIO_H_E4, BIT(6)), + PINCTRL_CONF_DESC(52, REG_GPIO_H_E4, BIT(7)), + PINCTRL_CONF_DESC(53, REG_GPIO_H_E4, BIT(8)), + PINCTRL_CONF_DESC(54, REG_GPIO_H_E4, BIT(9)), + PINCTRL_CONF_DESC(55, REG_GPIO_H_E4, BIT(10)), + PINCTRL_CONF_DESC(56, REG_GPIO_H_E4, BIT(11)), + PINCTRL_CONF_DESC(57, REG_GPIO_H_E4, BIT(12)), + PINCTRL_CONF_DESC(58, REG_GPIO_H_E4, BIT(13)), + PINCTRL_CONF_DESC(59, REG_GPIO_H_E4, BIT(14)), + PINCTRL_CONF_DESC(61, REG_I2C_SDA_E4, PCIE0_RESET_E4_MASK), + PINCTRL_CONF_DESC(62, REG_I2C_SDA_E4, PCIE1_RESET_E4_MASK), + PINCTRL_CONF_DESC(63, REG_I2C_SDA_E4, PCIE2_RESET_E4_MASK), +}; + +static const struct airoha_pinctrl_conf airoha_pinctrl_pcie_rst_od_conf[] = { + PINCTRL_CONF_DESC(61, REG_PCIE_RESET_OD, PCIE0_RESET_OD_MASK), + PINCTRL_CONF_DESC(62, REG_PCIE_RESET_OD, PCIE1_RESET_OD_MASK), + PINCTRL_CONF_DESC(63, REG_PCIE_RESET_OD, PCIE2_RESET_OD_MASK), +}; + +static int airoha_convert_pin_to_reg_offset(struct pinctrl_dev *pctrl_dev, + struct pinctrl_gpio_range *range, + int pin) +{ + if (!range) + range = pinctrl_find_gpio_range_from_pin_nolock(pctrl_dev, + pin); + if (!range) + return -EINVAL; + + return pin - range->pin_base; +} + +/* gpio callbacks */ +static void airoha_gpio_set(struct gpio_chip *chip, unsigned int gpio, + int value) +{ + struct airoha_pinctrl *pinctrl = gpiochip_get_data(chip); + u32 offset = gpio % AIROHA_PIN_BANK_SIZE; + u8 index = gpio / AIROHA_PIN_BANK_SIZE; + + regmap_update_bits(pinctrl->regmap, pinctrl->gpiochip.data[index], + BIT(offset), value ? BIT(offset) : 0); +} + +static int airoha_gpio_get(struct gpio_chip *chip, unsigned int gpio) +{ + struct airoha_pinctrl *pinctrl = gpiochip_get_data(chip); + u32 val, pin = gpio % AIROHA_PIN_BANK_SIZE; + u8 index = gpio / AIROHA_PIN_BANK_SIZE; + int err; + + err = regmap_read(pinctrl->regmap, + pinctrl->gpiochip.data[index], &val); + + return err ? err : !!(val & BIT(pin)); +} + +static int airoha_gpio_direction_output(struct gpio_chip *chip, + unsigned int gpio, int value) +{ + int err; + + err = pinctrl_gpio_direction_output(chip, gpio); + if (err) + return err; + + airoha_gpio_set(chip, gpio, value); + + return 0; +} + +/* irq callbacks */ +static void airoha_irq_unmask(struct irq_data *data) +{ + u8 offset = data->hwirq % AIROHA_REG_GPIOCTRL_NUM_PIN; + u8 index = data->hwirq / AIROHA_REG_GPIOCTRL_NUM_PIN; + u32 mask = GENMASK(2 * offset + 1, 2 * offset); + struct airoha_pinctrl_gpiochip *gpiochip; + struct airoha_pinctrl *pinctrl; + u32 val = BIT(2 * offset); + + gpiochip = irq_data_get_irq_chip_data(data); + if (WARN_ON_ONCE(data->hwirq >= ARRAY_SIZE(gpiochip->irq_type))) + return; + + pinctrl = container_of(gpiochip, struct airoha_pinctrl, gpiochip); + switch (gpiochip->irq_type[data->hwirq]) { + case IRQ_TYPE_LEVEL_LOW: + val = val << 1; + fallthrough; + case IRQ_TYPE_LEVEL_HIGH: + regmap_update_bits(pinctrl->regmap, gpiochip->level[index], + mask, val); + break; + case IRQ_TYPE_EDGE_FALLING: + val = val << 1; + fallthrough; + case IRQ_TYPE_EDGE_RISING: + regmap_update_bits(pinctrl->regmap, gpiochip->edge[index], + mask, val); + break; + case IRQ_TYPE_EDGE_BOTH: + regmap_set_bits(pinctrl->regmap, gpiochip->edge[index], mask); + break; + default: + break; + } +} + +static void airoha_irq_mask(struct irq_data *data) +{ + u8 offset = data->hwirq % AIROHA_REG_GPIOCTRL_NUM_PIN; + u8 index = data->hwirq / AIROHA_REG_GPIOCTRL_NUM_PIN; + u32 mask = GENMASK(2 * offset + 1, 2 * offset); + struct airoha_pinctrl_gpiochip *gpiochip; + struct airoha_pinctrl *pinctrl; + + gpiochip = irq_data_get_irq_chip_data(data); + pinctrl = container_of(gpiochip, struct airoha_pinctrl, gpiochip); + + regmap_clear_bits(pinctrl->regmap, gpiochip->level[index], mask); + regmap_clear_bits(pinctrl->regmap, gpiochip->edge[index], mask); +} + +static int airoha_irq_type(struct irq_data *data, unsigned int type) +{ + struct airoha_pinctrl_gpiochip *gpiochip; + + gpiochip = irq_data_get_irq_chip_data(data); + if (data->hwirq >= ARRAY_SIZE(gpiochip->irq_type)) + return -EINVAL; + + if (type == IRQ_TYPE_PROBE) { + if (gpiochip->irq_type[data->hwirq]) + return 0; + + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + gpiochip->irq_type[data->hwirq] = type & IRQ_TYPE_SENSE_MASK; + + return 0; +} + +static irqreturn_t airoha_irq_handler(int irq, void *data) +{ + struct airoha_pinctrl *pinctrl = data; + bool handled = false; + int i; + + for (i = 0; i < ARRAY_SIZE(irq_status_regs); i++) { + struct gpio_irq_chip *girq = &pinctrl->gpiochip.chip.irq; + u32 regmap; + unsigned long status; + int irq; + + if (regmap_read(pinctrl->regmap, pinctrl->gpiochip.status[i], + ®map)) + continue; + + status = regmap; + for_each_set_bit(irq, &status, AIROHA_PIN_BANK_SIZE) { + u32 offset = irq + i * AIROHA_PIN_BANK_SIZE; + + generic_handle_irq(irq_find_mapping(girq->domain, + offset)); + regmap_write(pinctrl->regmap, + pinctrl->gpiochip.status[i], BIT(irq)); + } + handled |= !!status; + } + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static const struct irq_chip airoha_gpio_irq_chip = { + .name = "airoha-gpio-irq", + .irq_unmask = airoha_irq_unmask, + .irq_mask = airoha_irq_mask, + .irq_mask_ack = airoha_irq_mask, + .irq_set_type = airoha_irq_type, + .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_IMMUTABLE, +}; + +static int airoha_pinctrl_add_gpiochip(struct airoha_pinctrl *pinctrl, + struct platform_device *pdev) +{ + struct airoha_pinctrl_gpiochip *chip = &pinctrl->gpiochip; + struct gpio_chip *gc = &chip->chip; + struct gpio_irq_chip *girq = &gc->irq; + struct device *dev = &pdev->dev; + int irq, err; + + chip->data = gpio_data_regs; + chip->dir = gpio_dir_regs; + chip->out = gpio_out_regs; + chip->status = irq_status_regs; + chip->level = irq_level_regs; + chip->edge = irq_edge_regs; + + gc->parent = dev; + gc->label = dev_name(dev); + gc->request = gpiochip_generic_request; + gc->free = gpiochip_generic_free; + gc->direction_input = pinctrl_gpio_direction_input; + gc->direction_output = airoha_gpio_direction_output; + gc->set = airoha_gpio_set; + gc->get = airoha_gpio_get; + gc->base = -1; + gc->ngpio = AIROHA_NUM_PINS; + + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + gpio_irq_chip_set_chip(girq, &airoha_gpio_irq_chip); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + err = devm_request_irq(dev, irq, airoha_irq_handler, IRQF_SHARED, + dev_name(dev), pinctrl); + if (err) { + dev_err(dev, "error requesting irq %d: %d\n", irq, err); + return err; + } + + return devm_gpiochip_add_data(dev, gc, pinctrl); +} + +/* pinmux callbacks */ +static int airoha_pinmux_set_mux(struct pinctrl_dev *pctrl_dev, + unsigned int selector, + unsigned int group) +{ + struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + const struct airoha_pinctrl_func *func; + struct function_desc *desc; + struct group_desc *grp; + int i; + + desc = pinmux_generic_get_function(pctrl_dev, selector); + if (!desc) + return -EINVAL; + + grp = pinctrl_generic_get_group(pctrl_dev, group); + if (!grp) + return -EINVAL; + + dev_dbg(pctrl_dev->dev, "enable function %s group %s\n", + desc->func.name, grp->grp.name); + + func = desc->data; + for (i = 0; i < func->group_size; i++) { + const struct airoha_pinctrl_func_group *group; + int j; + + group = &func->groups[i]; + if (strcmp(group->name, grp->grp.name)) + continue; + + for (j = 0; j < group->regmap_size; j++) { + switch (group->regmap[j].mux) { + case AIROHA_FUNC_PWM_EXT_MUX: + case AIROHA_FUNC_PWM_MUX: + regmap_update_bits(pinctrl->regmap, + group->regmap[j].offset, + group->regmap[j].mask, + group->regmap[j].val); + break; + default: + regmap_update_bits(pinctrl->chip_scu, + group->regmap[j].offset, + group->regmap[j].mask, + group->regmap[j].val); + break; + } + } + return 0; + } + + return -EINVAL; +} + +static int airoha_pinmux_set_direction(struct pinctrl_dev *pctrl_dev, + struct pinctrl_gpio_range *range, + unsigned int p, bool input) +{ + struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + u32 mask, index; + int err, pin; + + pin = airoha_convert_pin_to_reg_offset(pctrl_dev, range, p); + if (pin < 0) + return pin; + + /* set output enable */ + mask = BIT(pin % AIROHA_PIN_BANK_SIZE); + index = pin / AIROHA_PIN_BANK_SIZE; + err = regmap_update_bits(pinctrl->regmap, pinctrl->gpiochip.out[index], + mask, !input ? mask : 0); + if (err) + return err; + + /* set direction */ + mask = BIT(2 * (pin % AIROHA_REG_GPIOCTRL_NUM_PIN)); + index = pin / AIROHA_REG_GPIOCTRL_NUM_PIN; + return regmap_update_bits(pinctrl->regmap, + pinctrl->gpiochip.dir[index], mask, + !input ? mask : 0); +} + +static const struct pinmux_ops airoha_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, + .gpio_set_direction = airoha_pinmux_set_direction, + .set_mux = airoha_pinmux_set_mux, + .strict = true, +}; + +/* pinconf callbacks */ +static const struct airoha_pinctrl_reg * +airoha_pinctrl_get_conf_reg(const struct airoha_pinctrl_conf *conf, + int conf_size, int pin) +{ + int i; + + for (i = 0; i < conf_size; i++) { + if (conf[i].pin == pin) + return &conf[i].reg; + } + + return NULL; +} + +static int airoha_pinctrl_get_conf(struct airoha_pinctrl *pinctrl, + const struct airoha_pinctrl_conf *conf, + int conf_size, int pin, u32 *val) +{ + const struct airoha_pinctrl_reg *reg; + + reg = airoha_pinctrl_get_conf_reg(conf, conf_size, pin); + if (!reg) + return -EINVAL; + + if (regmap_read(pinctrl->chip_scu, reg->offset, val)) + return -EINVAL; + + *val = (*val & reg->mask) >> __ffs(reg->mask); + + return 0; +} + +static int airoha_pinctrl_set_conf(struct airoha_pinctrl *pinctrl, + const struct airoha_pinctrl_conf *conf, + int conf_size, int pin, u32 val) +{ + const struct airoha_pinctrl_reg *reg = NULL; + + reg = airoha_pinctrl_get_conf_reg(conf, conf_size, pin); + if (!reg) + return -EINVAL; + + + if (regmap_update_bits(pinctrl->chip_scu, reg->offset, reg->mask, + val << __ffs(reg->mask))) + return -EINVAL; + + return 0; +} + +#define airoha_pinctrl_get_pullup_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pullup_conf, \ + ARRAY_SIZE(airoha_pinctrl_pullup_conf), \ + (pin), (val)) +#define airoha_pinctrl_get_pulldown_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pulldown_conf, \ + ARRAY_SIZE(airoha_pinctrl_pulldown_conf), \ + (pin), (val)) +#define airoha_pinctrl_get_drive_e2_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_drive_e2_conf, \ + ARRAY_SIZE(airoha_pinctrl_drive_e2_conf), \ + (pin), (val)) +#define airoha_pinctrl_get_drive_e4_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_drive_e4_conf, \ + ARRAY_SIZE(airoha_pinctrl_drive_e4_conf), \ + (pin), (val)) +#define airoha_pinctrl_get_pcie_rst_od_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), airoha_pinctrl_pcie_rst_od_conf, \ + ARRAY_SIZE(airoha_pinctrl_pcie_rst_od_conf), \ + (pin), (val)) +#define airoha_pinctrl_set_pullup_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pullup_conf, \ + ARRAY_SIZE(airoha_pinctrl_pullup_conf), \ + (pin), (val)) +#define airoha_pinctrl_set_pulldown_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pulldown_conf, \ + ARRAY_SIZE(airoha_pinctrl_pulldown_conf), \ + (pin), (val)) +#define airoha_pinctrl_set_drive_e2_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_drive_e2_conf, \ + ARRAY_SIZE(airoha_pinctrl_drive_e2_conf), \ + (pin), (val)) +#define airoha_pinctrl_set_drive_e4_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_drive_e4_conf, \ + ARRAY_SIZE(airoha_pinctrl_drive_e4_conf), \ + (pin), (val)) +#define airoha_pinctrl_set_pcie_rst_od_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), airoha_pinctrl_pcie_rst_od_conf, \ + ARRAY_SIZE(airoha_pinctrl_pcie_rst_od_conf), \ + (pin), (val)) + +static int airoha_pinconf_get_direction(struct pinctrl_dev *pctrl_dev, u32 p) +{ + struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + u32 val, mask; + int err, pin; + u8 index; + + pin = airoha_convert_pin_to_reg_offset(pctrl_dev, NULL, p); + if (pin < 0) + return pin; + + index = pin / AIROHA_REG_GPIOCTRL_NUM_PIN; + err = regmap_read(pinctrl->regmap, pinctrl->gpiochip.dir[index], &val); + if (err) + return err; + + mask = BIT(2 * (pin % AIROHA_REG_GPIOCTRL_NUM_PIN)); + return val & mask ? PIN_CONFIG_OUTPUT_ENABLE : PIN_CONFIG_INPUT_ENABLE; +} + +static int airoha_pinconf_get(struct pinctrl_dev *pctrl_dev, + unsigned int pin, unsigned long *config) +{ + struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + enum pin_config_param param = pinconf_to_config_param(*config); + u32 arg; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: { + u32 pull_up, pull_down; + + if (airoha_pinctrl_get_pullup_conf(pinctrl, pin, &pull_up) || + airoha_pinctrl_get_pulldown_conf(pinctrl, pin, &pull_down)) + return -EINVAL; + + if (param == PIN_CONFIG_BIAS_PULL_UP && + !(pull_up && !pull_down)) + return -EINVAL; + else if (param == PIN_CONFIG_BIAS_PULL_DOWN && + !(pull_down && !pull_up)) + return -EINVAL; + else if (pull_up || pull_down) + return -EINVAL; + + arg = 1; + break; + } + case PIN_CONFIG_DRIVE_STRENGTH: { + u32 e2, e4; + + if (airoha_pinctrl_get_drive_e2_conf(pinctrl, pin, &e2) || + airoha_pinctrl_get_drive_e4_conf(pinctrl, pin, &e4)) + return -EINVAL; + + arg = e4 << 1 | e2; + break; + } + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (airoha_pinctrl_get_pcie_rst_od_conf(pinctrl, pin, &arg)) + return -EINVAL; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + case PIN_CONFIG_INPUT_ENABLE: + arg = airoha_pinconf_get_direction(pctrl_dev, pin); + if (arg != param) + return -EINVAL; + + arg = 1; + break; + default: + return -EOPNOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int airoha_pinconf_set_pin_value(struct pinctrl_dev *pctrl_dev, + unsigned int p, bool value) +{ + struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + int pin; + + pin = airoha_convert_pin_to_reg_offset(pctrl_dev, NULL, p); + if (pin < 0) + return pin; + + airoha_gpio_set(&pinctrl->gpiochip.chip, pin, value); + + return 0; +} + +static int airoha_pinconf_set(struct pinctrl_dev *pctrl_dev, + unsigned int pin, unsigned long *configs, + unsigned int num_configs) +{ + struct airoha_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctrl_dev); + int i; + + for (i = 0; i < num_configs; i++) { + u32 param = pinconf_to_config_param(configs[i]); + u32 arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 0); + airoha_pinctrl_set_pullup_conf(pinctrl, pin, 0); + break; + case PIN_CONFIG_BIAS_PULL_UP: + airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 0); + airoha_pinctrl_set_pullup_conf(pinctrl, pin, 1); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 1); + airoha_pinctrl_set_pullup_conf(pinctrl, pin, 0); + break; + case PIN_CONFIG_DRIVE_STRENGTH: { + u32 e2 = 0, e4 = 0; + + switch (arg) { + case MTK_DRIVE_2mA: + break; + case MTK_DRIVE_4mA: + e2 = 1; + break; + case MTK_DRIVE_6mA: + e4 = 1; + break; + case MTK_DRIVE_8mA: + e2 = 1; + e4 = 1; + break; + default: + return -EINVAL; + } + + airoha_pinctrl_set_drive_e2_conf(pinctrl, pin, e2); + airoha_pinctrl_set_drive_e4_conf(pinctrl, pin, e4); + break; + } + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + airoha_pinctrl_set_pcie_rst_od_conf(pinctrl, pin, !!arg); + break; + case PIN_CONFIG_OUTPUT_ENABLE: + case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_OUTPUT: { + bool input = param == PIN_CONFIG_INPUT_ENABLE; + int err; + + err = airoha_pinmux_set_direction(pctrl_dev, NULL, pin, + input); + if (err) + return err; + + if (param == PIN_CONFIG_OUTPUT) { + err = airoha_pinconf_set_pin_value(pctrl_dev, + pin, !!arg); + if (err) + return err; + } + break; + } + default: + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int airoha_pinconf_group_get(struct pinctrl_dev *pctrl_dev, + unsigned int group, unsigned long *config) +{ + u32 cur_config = 0; + int i; + + for (i = 0; i < airoha_pinctrl_groups[group].npins; i++) { + if (airoha_pinconf_get(pctrl_dev, + airoha_pinctrl_groups[group].pins[i], + config)) + return -EOPNOTSUPP; + + if (i && cur_config != *config) + return -EOPNOTSUPP; + + cur_config = *config; + } + + return 0; +} + +static int airoha_pinconf_group_set(struct pinctrl_dev *pctrl_dev, + unsigned int group, unsigned long *configs, + unsigned int num_configs) +{ + int i; + + for (i = 0; i < airoha_pinctrl_groups[group].npins; i++) { + int err; + + err = airoha_pinconf_set(pctrl_dev, + airoha_pinctrl_groups[group].pins[i], + configs, num_configs); + if (err) + return err; + } + + return 0; +} + +static const struct pinconf_ops airoha_confops = { + .is_generic = true, + .pin_config_get = airoha_pinconf_get, + .pin_config_set = airoha_pinconf_set, + .pin_config_group_get = airoha_pinconf_group_get, + .pin_config_group_set = airoha_pinconf_group_set, + .pin_config_config_dbg_show = pinconf_generic_dump_config, +}; + +static const struct pinctrl_ops airoha_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 struct pinctrl_desc airoha_pinctrl_desc = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .pctlops = &airoha_pctlops, + .pmxops = &airoha_pmxops, + .confops = &airoha_confops, + .pins = airoha_pinctrl_pins, + .npins = ARRAY_SIZE(airoha_pinctrl_pins), +}; + +static int airoha_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct airoha_pinctrl *pinctrl; + struct regmap *map; + int err, i; + + pinctrl = devm_kzalloc(dev, sizeof(*pinctrl), GFP_KERNEL); + if (!pinctrl) + return -ENOMEM; + + pinctrl->regmap = device_node_to_regmap(dev->parent->of_node); + if (IS_ERR(pinctrl->regmap)) + return PTR_ERR(pinctrl->regmap); + + map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu"); + if (IS_ERR(map)) + return PTR_ERR(map); + + pinctrl->chip_scu = map; + + err = devm_pinctrl_register_and_init(dev, &airoha_pinctrl_desc, + pinctrl, &pinctrl->ctrl); + if (err) + return err; + + /* build pin groups */ + for (i = 0; i < ARRAY_SIZE(airoha_pinctrl_groups); i++) { + const struct pingroup *grp = &airoha_pinctrl_groups[i]; + + err = pinctrl_generic_add_group(pinctrl->ctrl, grp->name, + grp->pins, grp->npins, + (void *)grp); + if (err < 0) { + dev_err(&pdev->dev, "Failed to register group %s\n", + grp->name); + return err; + } + } + + /* build functions */ + for (i = 0; i < ARRAY_SIZE(airoha_pinctrl_funcs); i++) { + const struct airoha_pinctrl_func *func; + + func = &airoha_pinctrl_funcs[i]; + err = pinmux_generic_add_function(pinctrl->ctrl, + func->desc.func.name, + func->desc.func.groups, + func->desc.func.ngroups, + (void *)func); + if (err < 0) { + dev_err(dev, "Failed to register function %s\n", + func->desc.func.name); + return err; + } + } + + err = pinctrl_enable(pinctrl->ctrl); + if (err) + return err; + + /* build gpio-chip */ + return airoha_pinctrl_add_gpiochip(pinctrl, pdev); +} + +static const struct of_device_id airoha_pinctrl_of_match[] = { + { .compatible = "airoha,en7581-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, airoha_pinctrl_of_match); + +static struct platform_driver airoha_pinctrl_driver = { + .probe = airoha_pinctrl_probe, + .driver = { + .name = "pinctrl-airoha", + .of_match_table = airoha_pinctrl_of_match, + }, +}; +module_platform_driver(airoha_pinctrl_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lorenzo Bianconi "); +MODULE_AUTHOR("Benjamin Larsson "); +MODULE_AUTHOR("Markus Gothe "); +MODULE_DESCRIPTION("Pinctrl driver for Airoha SoC"); diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 4c4ada06423d72..335744ac831057 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -734,7 +734,7 @@ 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); + seq_puts(p, info->data->name); } static const struct irq_chip armada_37xx_irqchip = { diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c index 68750b6f8e57a5..4ce2e35a637335 100644 --- a/drivers/pinctrl/nomadik/pinctrl-abx500.c +++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c @@ -1089,7 +1089,7 @@ static struct platform_driver abx500_gpio_driver = { .of_match_table = abx500_gpio_match, }, .probe = abx500_gpio_probe, - .remove_new = abx500_gpio_remove, + .remove = abx500_gpio_remove, }; static int __init abx500_gpio_init(void) diff --git a/drivers/pinctrl/nxp/pinctrl-s32g2.c b/drivers/pinctrl/nxp/pinctrl-s32g2.c index 440ff18794249f..c49d28793b6960 100644 --- a/drivers/pinctrl/nxp/pinctrl-s32g2.c +++ b/drivers/pinctrl/nxp/pinctrl-s32g2.c @@ -216,6 +216,12 @@ enum s32_pins { S32G_IMCR_CAN1_RXD = 631, S32G_IMCR_CAN2_RXD = 632, S32G_IMCR_CAN3_RXD = 633, + + /* JTAG IMCRs */ + S32G_IMCR_JTAG_TMS = 562, + S32G_IMCR_JTAG_TCK = 572, + S32G_IMCR_JTAG_TDI = 573, + /* GMAC0 */ S32G_IMCR_Ethernet_MDIO = 527, S32G_IMCR_Ethernet_CRS = 526, @@ -229,7 +235,21 @@ enum s32_pins { S32G_IMCR_Ethernet_RX_DV = 530, S32G_IMCR_Ethernet_TX_CLK = 538, S32G_IMCR_Ethernet_REF_CLK = 535, + /* PFE EMAC 0 MII */ + S32G_IMCR_PFE_EMAC_0_MDIO = 837, + S32G_IMCR_PFE_EMAC_0_CRS = 836, + S32G_IMCR_PFE_EMAC_0_COL = 835, + S32G_IMCR_PFE_EMAC_0_RX_D0 = 841, + S32G_IMCR_PFE_EMAC_0_RX_D1 = 842, + S32G_IMCR_PFE_EMAC_0_RX_D2 = 843, + S32G_IMCR_PFE_EMAC_0_RX_D3 = 844, + S32G_IMCR_PFE_EMAC_0_RX_ER = 840, + S32G_IMCR_PFE_EMAC_0_RX_CLK = 839, + S32G_IMCR_PFE_EMAC_0_RX_DV = 845, + S32G_IMCR_PFE_EMAC_0_TX_CLK = 846, + S32G_IMCR_PFE_EMAC_0_REF_CLK = 838, + /* PFE EMAC 1 MII */ S32G_IMCR_PFE_EMAC_1_MDIO = 857, S32G_IMCR_PFE_EMAC_1_CRS = 856, @@ -317,6 +337,13 @@ enum s32_pins { S32G_IMCR_LLCE_CAN13_RXD = 758, S32G_IMCR_LLCE_CAN14_RXD = 759, S32G_IMCR_LLCE_CAN15_RXD = 760, + S32G_IMCR_LLCE_UART0_RXD = 790, + S32G_IMCR_LLCE_UART1_RXD = 791, + S32G_IMCR_LLCE_UART2_RXD = 792, + S32G_IMCR_LLCE_UART3_RXD = 793, + S32G_IMCR_LLCE_LPSPI2_PCS0 = 811, + S32G_IMCR_LLCE_LPSPI2_SCK = 816, + S32G_IMCR_LLCE_LPSPI2_SIN = 817, S32G_IMCR_USB_CLK = 895, S32G_IMCR_USB_DATA0 = 896, S32G_IMCR_USB_DATA1 = 897, @@ -503,6 +530,12 @@ static const struct pinctrl_pin_desc s32_pinctrl_pads_siul2[] = { S32_PINCTRL_PIN(S32G_IMCR_USDHC_DAT7), S32_PINCTRL_PIN(S32G_IMCR_USDHC_DQS), S32_PINCTRL_PIN(S32G_IMCR_CAN0_RXD), + + /* JTAG IMCRs */ + S32_PINCTRL_PIN(S32G_IMCR_JTAG_TMS), + S32_PINCTRL_PIN(S32G_IMCR_JTAG_TCK), + S32_PINCTRL_PIN(S32G_IMCR_JTAG_TDI), + /* GMAC0 */ S32_PINCTRL_PIN(S32G_IMCR_Ethernet_MDIO), S32_PINCTRL_PIN(S32G_IMCR_Ethernet_CRS), @@ -638,6 +671,13 @@ static const struct pinctrl_pin_desc s32_pinctrl_pads_siul2[] = { 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_LLCE_UART0_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_UART1_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_UART2_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_UART3_RXD), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_LPSPI2_PCS0), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_LPSPI2_SCK), + S32_PINCTRL_PIN(S32G_IMCR_LLCE_LPSPI2_SIN), S32_PINCTRL_PIN(S32G_IMCR_CAN1_RXD), S32_PINCTRL_PIN(S32G_IMCR_CAN2_RXD), S32_PINCTRL_PIN(S32G_IMCR_CAN3_RXD), @@ -652,6 +692,18 @@ static const struct pinctrl_pin_desc s32_pinctrl_pads_siul2[] = { 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_0_MDIO), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_CRS), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_COL), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_RX_D0), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_RX_D1), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_RX_D2), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_RX_D3), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_RX_ER), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_RX_CLK), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_RX_DV), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_TX_CLK), + S32_PINCTRL_PIN(S32G_IMCR_PFE_EMAC_0_REF_CLK), 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), diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 7f66ec73199a9c..fff6d4209ad578 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -506,7 +506,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) case IRQ_TYPE_EDGE_BOTH: pin_reg &= ~BIT(LEVEL_TRIG_OFF); pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); - pin_reg |= BOTH_EADGE << ACTIVE_LEVEL_OFF; + pin_reg |= BOTH_EDGES << ACTIVE_LEVEL_OFF; irq_set_handler_locked(d, handle_edge_irq); break; @@ -1204,7 +1204,7 @@ static struct platform_driver amd_gpio_driver = { #endif }, .probe = amd_gpio_probe, - .remove_new = amd_gpio_remove, + .remove = amd_gpio_remove, }; module_platform_driver(amd_gpio_driver); diff --git a/drivers/pinctrl/pinctrl-amd.h b/drivers/pinctrl/pinctrl-amd.h index cf59089f277639..667be49c3f48d2 100644 --- a/drivers/pinctrl/pinctrl-amd.h +++ b/drivers/pinctrl/pinctrl-amd.h @@ -60,12 +60,12 @@ #define DB_TYPE_PRESERVE_HIGH_GLITCH 0x2UL #define DB_TYPE_REMOVE_GLITCH 0x3UL -#define EDGE_TRAGGER 0x0UL +#define EDGE_TRIGGER 0x0UL #define LEVEL_TRIGGER 0x1UL #define ACTIVE_HIGH 0x0UL #define ACTIVE_LOW 0x1UL -#define BOTH_EADGE 0x2UL +#define BOTH_EDGES 0x2UL #define ENABLE_INTERRUPT 0x1UL #define DISABLE_INTERRUPT 0x0UL diff --git a/drivers/pinctrl/pinctrl-artpec6.c b/drivers/pinctrl/pinctrl-artpec6.c index dd93f124e0a096..717f9592b28b51 100644 --- a/drivers/pinctrl/pinctrl-artpec6.c +++ b/drivers/pinctrl/pinctrl-artpec6.c @@ -988,7 +988,7 @@ static struct platform_driver artpec6_pmx_driver = { .of_match_table = artpec6_pinctrl_match, }, .probe = artpec6_pmx_probe, - .remove_new = artpec6_pmx_remove, + .remove = artpec6_pmx_remove, }; static int __init artpec6_pmx_init(void) diff --git a/drivers/pinctrl/pinctrl-aw9523.c b/drivers/pinctrl/pinctrl-aw9523.c index 1374f30166bc3b..9bf53de20be874 100644 --- a/drivers/pinctrl/pinctrl-aw9523.c +++ b/drivers/pinctrl/pinctrl-aw9523.c @@ -80,7 +80,7 @@ struct aw9523 { struct regmap *regmap; struct mutex i2c_lock; struct gpio_desc *reset_gpio; - struct regulator *vio_vreg; + int vio_vreg; struct pinctrl_dev *pctl; struct gpio_chip gpio; struct aw9523_irq *irq; @@ -550,10 +550,10 @@ static int aw9523_gpio_get(struct gpio_chip *chip, unsigned int offset) /** * _aw9523_gpio_get_multiple - Get I/O state for an entire port - * @regmap: Regmap structure - * @pin: gpiolib pin number + * @awi: Controller data * @regbit: hw pin index, used to retrieve port number * @state: returned port I/O state + * @mask: lines to read values for * * Return: Zero for success or negative number for error */ @@ -972,29 +972,23 @@ static int aw9523_probe(struct i2c_client *client) if (IS_ERR(awi->regmap)) return PTR_ERR(awi->regmap); - awi->vio_vreg = devm_regulator_get_optional(dev, "vio"); - if (IS_ERR(awi->vio_vreg)) { - if (PTR_ERR(awi->vio_vreg) == -EPROBE_DEFER) - return -EPROBE_DEFER; - awi->vio_vreg = NULL; - } else { - ret = regulator_enable(awi->vio_vreg); - if (ret) - return ret; - } + awi->vio_vreg = devm_regulator_get_enable_optional(dev, "vio"); + if (awi->vio_vreg && awi->vio_vreg != -ENODEV) + return awi->vio_vreg; + + ret = devm_mutex_init(dev, &awi->i2c_lock); + if (ret) + return ret; - mutex_init(&awi->i2c_lock); lockdep_set_subclass(&awi->i2c_lock, i2c_adapter_depth(client->adapter)); pdesc = devm_kzalloc(dev, sizeof(*pdesc), GFP_KERNEL); - if (!pdesc) { - ret = -ENOMEM; - goto err_disable_vregs; - } + if (!pdesc) + return -ENOMEM; ret = aw9523_hw_init(awi); if (ret) - goto err_disable_vregs; + return ret; pdesc->name = dev_name(dev); pdesc->owner = THIS_MODULE; @@ -1006,31 +1000,20 @@ static int aw9523_probe(struct i2c_client *client) ret = aw9523_init_gpiochip(awi, pdesc->npins); if (ret) - goto err_disable_vregs; + return ret; if (client->irq) { ret = aw9523_init_irq(awi, client->irq); if (ret) - goto err_disable_vregs; + return ret; } awi->pctl = devm_pinctrl_register(dev, pdesc, awi); - if (IS_ERR(awi->pctl)) { - ret = dev_err_probe(dev, PTR_ERR(awi->pctl), "Cannot register pinctrl"); - goto err_disable_vregs; - } - - ret = devm_gpiochip_add_data(dev, &awi->gpio, awi); - if (ret) - goto err_disable_vregs; - - return ret; + if (IS_ERR(awi->pctl)) + return dev_err_probe(dev, PTR_ERR(awi->pctl), + "Cannot register pinctrl"); -err_disable_vregs: - if (awi->vio_vreg) - regulator_disable(awi->vio_vreg); - mutex_destroy(&awi->i2c_lock); - return ret; + return devm_gpiochip_add_data(dev, &awi->gpio, awi); } static void aw9523_remove(struct i2c_client *client) @@ -1043,19 +1026,15 @@ static void aw9523_remove(struct i2c_client *client) * set the pins to hardware defaults before removing the driver * to leave it in a clean, safe and predictable state. */ - if (awi->vio_vreg) { - regulator_disable(awi->vio_vreg); - } else { + if (awi->vio_vreg == -ENODEV) { mutex_lock(&awi->i2c_lock); aw9523_hw_init(awi); mutex_unlock(&awi->i2c_lock); } - - mutex_destroy(&awi->i2c_lock); } static const struct i2c_device_id aw9523_i2c_id_table[] = { - { "aw9523_i2c", 0 }, + { "aw9523_i2c" }, { } }; MODULE_DEVICE_TABLE(i2c, aw9523_i2c_id_table); diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 5096ccdd459ea4..0d6c2027d4c18a 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -141,7 +141,6 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = { * @nport: Number of Gports in this chip * @gpio_chip: gpiolib chip * @driver_data: private driver data - * @regulator: Pointer to the regulator for the IC * @dev: struct device * @pctldev: pin controller device * @pinctrl_desc: pin controller description @@ -160,10 +159,9 @@ struct cy8c95x0_pinctrl { DECLARE_BITMAP(irq_trig_high, MAX_LINE); DECLARE_BITMAP(push_pull, MAX_LINE); DECLARE_BITMAP(shiftmask, MAX_LINE); - int nport; + unsigned int nport; struct gpio_chip gpio_chip; unsigned long driver_data; - struct regulator *regulator; struct device *dev; struct pinctrl_dev *pctldev; struct pinctrl_desc pinctrl_desc; @@ -612,9 +610,8 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, DECLARE_BITMAP(tmask, MAX_LINE); DECLARE_BITMAP(tval, MAX_LINE); int write_val; - int ret = 0; - int i; u8 bits; + int ret; /* Add the 4 bit gap of Gport2 */ bitmap_andnot(tmask, mask, chip->shiftmask, MAX_LINE); @@ -625,7 +622,7 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, bitmap_shift_left(tval, tval, 4, MAX_LINE); bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3); - for (i = 0; i < chip->nport; i++) { + for (unsigned int i = 0; i < chip->nport; i++) { /* Skip over unused banks */ bits = bitmap_get_value8(tmask, i * BANK_SZ); if (!bits) @@ -634,15 +631,13 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, write_val = bitmap_get_value8(tval, i * BANK_SZ); ret = cy8c95x0_regmap_update_bits(chip, reg, i, bits, write_val); - if (ret < 0) - goto out; + if (ret < 0) { + dev_err(chip->dev, "failed writing register %d, port %u: err %d\n", reg, i, ret); + return ret; + } } -out: - if (ret < 0) - dev_err(chip->dev, "failed writing register %d, port %d: err %d\n", reg, i, ret); - - return ret; + return 0; } static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, @@ -652,9 +647,8 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, DECLARE_BITMAP(tval, MAX_LINE); DECLARE_BITMAP(tmp, MAX_LINE); int read_val; - int ret = 0; - int i; u8 bits; + int ret; /* Add the 4 bit gap of Gport2 */ bitmap_andnot(tmask, mask, chip->shiftmask, MAX_LINE); @@ -665,15 +659,17 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, bitmap_shift_left(tval, tval, 4, MAX_LINE); bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3); - for (i = 0; i < chip->nport; i++) { + for (unsigned int i = 0; i < chip->nport; i++) { /* Skip over unused banks */ bits = bitmap_get_value8(tmask, i * BANK_SZ); if (!bits) continue; ret = cy8c95x0_regmap_read(chip, reg, i, &read_val); - if (ret < 0) - goto out; + if (ret < 0) { + dev_err(chip->dev, "failed reading register %d, port %u: err %d\n", reg, i, ret); + return ret; + } read_val &= bits; read_val |= bitmap_get_value8(tval, i * BANK_SZ) & ~bits; @@ -684,11 +680,7 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg, bitmap_shift_right(tmp, tval, 4, MAX_LINE); bitmap_replace(val, tmp, tval, chip->shiftmask, MAX_LINE); -out: - if (ret < 0) - dev_err(chip->dev, "failed reading register %d, port %d: err %d\n", reg, i, ret); - - return ret; + return 0; } static int cy8c95x0_gpio_direction_input(struct gpio_chip *gc, unsigned int off) @@ -754,14 +746,12 @@ static int cy8c95x0_gpio_get_direction(struct gpio_chip *gc, unsigned int off) ret = cy8c95x0_regmap_read(chip, CY8C95X0_DIRECTION, port, ®_val); if (ret < 0) - goto out; + return ret; if (reg_val & bit) return GPIO_LINE_DIRECTION_IN; return GPIO_LINE_DIRECTION_OUT; -out: - return ret; } static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, @@ -823,8 +813,7 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, case PIN_CONFIG_SLEEP_HARDWARE_STATE: case PIN_CONFIG_SLEW_RATE: default: - ret = -ENOTSUPP; - goto out; + return -ENOTSUPP; } /* * Writing 1 to one of the drive mode registers will automatically @@ -832,7 +821,7 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, */ ret = cy8c95x0_regmap_read(chip, reg, port, ®_val); if (ret < 0) - goto out; + return ret; if (reg_val & bit) arg = 1; @@ -840,8 +829,7 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip, arg = !arg; *config = pinconf_to_config_packed(param, (u16)arg); -out: - return ret; + return 0; } static int cy8c95x0_gpio_set_pincfg(struct cy8c95x0_pinctrl *chip, @@ -853,7 +841,6 @@ static int cy8c95x0_gpio_set_pincfg(struct cy8c95x0_pinctrl *chip, unsigned long param = pinconf_to_config_param(config); unsigned long arg = pinconf_to_config_argument(config); unsigned int reg; - int ret; switch (param) { case PIN_CONFIG_BIAS_PULL_UP: @@ -884,22 +871,17 @@ static int cy8c95x0_gpio_set_pincfg(struct cy8c95x0_pinctrl *chip, reg = CY8C95X0_PWMSEL; break; case PIN_CONFIG_OUTPUT_ENABLE: - ret = cy8c95x0_pinmux_direction(chip, off, !arg); - goto out; + return cy8c95x0_pinmux_direction(chip, off, !arg); case PIN_CONFIG_INPUT_ENABLE: - ret = cy8c95x0_pinmux_direction(chip, off, arg); - goto out; + return cy8c95x0_pinmux_direction(chip, off, arg); default: - ret = -ENOTSUPP; - goto out; + return -ENOTSUPP; } /* * Writing 1 to one of the drive mode registers will automatically * clear conflicting set bits in the other drive mode registers. */ - ret = cy8c95x0_regmap_write_bits(chip, reg, port, bit, bit); -out: - return ret; + return cy8c95x0_regmap_write_bits(chip, reg, port, bit, bit); } static int cy8c95x0_gpio_get_multiple(struct gpio_chip *gc, @@ -1424,32 +1406,30 @@ static int cy8c95x0_detect(struct i2c_client *client, } dev_info(&client->dev, "Found a %s chip at 0x%02x.\n", name, client->addr); - strscpy(info->type, name, I2C_NAME_SIZE); + strscpy(info->type, name); return 0; } static int cy8c95x0_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct cy8c95x0_pinctrl *chip; struct regmap_config regmap_conf; struct regmap_range_cfg regmap_range_conf; - struct regulator *reg; int ret; - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - chip->dev = &client->dev; + chip->dev = dev; /* Set the device type */ chip->driver_data = (uintptr_t)i2c_get_match_data(client); if (!chip->driver_data) return -ENODEV; - i2c_set_clientdata(client, chip); - chip->tpin = chip->driver_data & CY8C95X0_GPIO_MASK; chip->nport = DIV_ROUND_UP(CY8C95X0_PIN_TO_OFFSET(chip->tpin), BANK_SZ); @@ -1457,46 +1437,34 @@ static int cy8c95x0_probe(struct i2c_client *client) switch (chip->tpin) { case 20: - strscpy(chip->name, cy8c95x0_id[0].name, I2C_NAME_SIZE); + strscpy(chip->name, cy8c95x0_id[0].name); regmap_range_conf.range_max = CY8C95X0_VIRTUAL + 3 * MUXED_STRIDE; break; case 40: - strscpy(chip->name, cy8c95x0_id[1].name, I2C_NAME_SIZE); + strscpy(chip->name, cy8c95x0_id[1].name); regmap_range_conf.range_max = CY8C95X0_VIRTUAL + 6 * MUXED_STRIDE; break; case 60: - strscpy(chip->name, cy8c95x0_id[2].name, I2C_NAME_SIZE); + strscpy(chip->name, cy8c95x0_id[2].name); regmap_range_conf.range_max = CY8C95X0_VIRTUAL + 8 * MUXED_STRIDE; break; default: return -ENODEV; } - reg = devm_regulator_get(&client->dev, "vdd"); - if (IS_ERR(reg)) { - if (PTR_ERR(reg) == -EPROBE_DEFER) - return -EPROBE_DEFER; - } else { - ret = regulator_enable(reg); - if (ret) { - dev_err(&client->dev, "failed to enable regulator vdd: %d\n", ret); - return ret; - } - chip->regulator = reg; - } + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable regulator vdd\n"); /* bring the chip out of reset if reset pin is provided */ - chip->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(chip->gpio_reset)) { - ret = dev_err_probe(chip->dev, PTR_ERR(chip->gpio_reset), - "Failed to get GPIO 'reset'\n"); - goto err_exit; - } else if (chip->gpio_reset) { - usleep_range(1000, 2000); + chip->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(chip->gpio_reset)) + return dev_err_probe(dev, PTR_ERR(chip->gpio_reset), "Failed to get GPIO 'reset'\n"); + gpiod_set_consumer_name(chip->gpio_reset, "CY8C95X0 RESET"); + if (chip->gpio_reset) { + fsleep(1000); gpiod_set_value_cansleep(chip->gpio_reset, 0); - usleep_range(250000, 300000); - - gpiod_set_consumer_name(chip->gpio_reset, "CY8C95X0 RESET"); + fsleep(250000); } /* Regmap for direct and paged registers */ @@ -1506,10 +1474,8 @@ static int cy8c95x0_probe(struct i2c_client *client) regmap_conf.num_reg_defaults_raw = regmap_range_conf.range_max; chip->regmap = devm_regmap_init_i2c(client, ®map_conf); - if (IS_ERR(chip->regmap)) { - ret = PTR_ERR(chip->regmap); - goto err_exit; - } + if (IS_ERR(chip->regmap)) + return PTR_ERR(chip->regmap); bitmap_zero(chip->push_pull, MAX_LINE); bitmap_zero(chip->shiftmask, MAX_LINE); @@ -1525,31 +1491,14 @@ static int cy8c95x0_probe(struct i2c_client *client) if (client->irq) { ret = cy8c95x0_irq_setup(chip, client->irq); if (ret) - goto err_exit; + return ret; } ret = cy8c95x0_setup_pinctrl(chip); if (ret) - goto err_exit; - - ret = cy8c95x0_setup_gpiochip(chip); - if (ret) - goto err_exit; - - return 0; - -err_exit: - if (!IS_ERR_OR_NULL(chip->regulator)) - regulator_disable(chip->regulator); - return ret; -} - -static void cy8c95x0_remove(struct i2c_client *client) -{ - struct cy8c95x0_pinctrl *chip = i2c_get_clientdata(client); + return ret; - if (!IS_ERR_OR_NULL(chip->regulator)) - regulator_disable(chip->regulator); + return cy8c95x0_setup_gpiochip(chip); } static const struct acpi_device_id cy8c95x0_acpi_ids[] = { @@ -1565,7 +1514,6 @@ static struct i2c_driver cy8c95x0_driver = { .acpi_match_table = cy8c95x0_acpi_ids, }, .probe = cy8c95x0_probe, - .remove = cy8c95x0_remove, .id_table = cy8c95x0_id, .detect = cy8c95x0_detect, }; diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c index 0f6b55fec31de7..eddb01796a83eb 100644 --- a/drivers/pinctrl/pinctrl-k210.c +++ b/drivers/pinctrl/pinctrl-k210.c @@ -96,8 +96,6 @@ struct k210_fpioa_data { struct k210_fpioa __iomem *fpioa; struct regmap *sysctl_map; u32 power_offset; - struct clk *clk; - struct clk *pclk; }; #define K210_PIN_NAME(i) ("IO_" #i) @@ -183,7 +181,7 @@ static const u32 k210_pinconf_mode_id_to_mode[] = { [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, }; -#undef DEFAULT +#undef K210_PC_DEFAULT /* * Pin functions configuration information. @@ -925,6 +923,7 @@ static int k210_fpioa_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct k210_fpioa_data *pdata; + struct clk *clk, *pclk; dev_info(dev, "K210 FPIOA pin controller\n"); @@ -939,13 +938,13 @@ static int k210_fpioa_probe(struct platform_device *pdev) if (IS_ERR(pdata->fpioa)) return PTR_ERR(pdata->fpioa); - pdata->clk = devm_clk_get_enabled(dev, "ref"); - if (IS_ERR(pdata->clk)) - return PTR_ERR(pdata->clk); + clk = devm_clk_get_enabled(dev, "ref"); + if (IS_ERR(clk)) + return PTR_ERR(clk); - pdata->pclk = devm_clk_get_optional_enabled(dev, "pclk"); - if (IS_ERR(pdata->pclk)) - return PTR_ERR(pdata->pclk); + pclk = devm_clk_get_optional_enabled(dev, "pclk"); + if (IS_ERR(pclk)) + return PTR_ERR(pclk); pdata->sysctl_map = syscon_regmap_lookup_by_phandle_args(np, diff --git a/drivers/pinctrl/pinctrl-k230.c b/drivers/pinctrl/pinctrl-k230.c new file mode 100644 index 00000000000000..a9b4627b46b012 --- /dev/null +++ b/drivers/pinctrl/pinctrl-k230.c @@ -0,0 +1,641 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +/* + * Copyright (C) 2024 Canaan Bright Sight Co. Ltd + * Copyright (C) 2024 Ze Huang <18771902331@163.com> + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "pinconf.h" + +#define K230_NPINS 64 + +#define K230_SHIFT_ST (0) +#define K230_SHIFT_DS (1) +#define K230_SHIFT_BIAS (5) +#define K230_SHIFT_PD (5) +#define K230_SHIFT_PU (6) +#define K230_SHIFT_OE (7) +#define K230_SHIFT_IE (8) +#define K230_SHIFT_MSC (9) +#define K230_SHIFT_SL (10) +#define K230_SHIFT_SEL (11) + +#define K230_PC_ST BIT(0) +#define K230_PC_DS GENMASK(4, 1) +#define K230_PC_PD BIT(5) +#define K230_PC_PU BIT(6) +#define K230_PC_BIAS GENMASK(6, 5) +#define K230_PC_OE BIT(7) +#define K230_PC_IE BIT(8) +#define K230_PC_MSC BIT(9) +#define K230_PC_SL BIT(10) +#define K230_PC_SEL GENMASK(13, 11) + +struct k230_pin_conf { + unsigned int func; + unsigned long *configs; + unsigned int nconfigs; +}; + +struct k230_pin_group { + const char *name; + unsigned int *pins; + unsigned int num_pins; + + struct k230_pin_conf *data; +}; + +struct k230_pmx_func { + const char *name; + const char **groups; + unsigned int *group_idx; + unsigned int ngroups; +}; + +struct k230_pinctrl { + struct pinctrl_desc pctl; + struct pinctrl_dev *pctl_dev; + struct regmap *regmap_base; + void __iomem *base; + struct k230_pin_group *groups; + unsigned int ngroups; + struct k230_pmx_func *functions; + unsigned int nfunctions; +}; + +static const struct regmap_config k230_regmap_config = { + .name = "canaan,pinctrl", + .reg_bits = 32, + .val_bits = 32, + .max_register = 0x100, + .reg_stride = 4, +}; + +static int k230_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *k230_get_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[selector].name; +} + +static int k230_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int selector, + const unsigned int **pins, + unsigned int *num_pins) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pins; + *num_pins = info->groups[selector].num_pins; + + return 0; +} + +static inline const struct k230_pmx_func *k230_name_to_funtion( + const struct k230_pinctrl *info, const char *name) +{ + unsigned int i; + + for (i = 0; i < info->nfunctions; i++) { + if (!strcmp(info->functions[i].name, name)) + return &info->functions[i]; + } + + return NULL; +} + +static struct pinctrl_pin_desc k230_pins[] = { + PINCTRL_PIN(0, "IO0"), PINCTRL_PIN(1, "IO1"), PINCTRL_PIN(2, "IO2"), + PINCTRL_PIN(3, "IO3"), PINCTRL_PIN(4, "IO4"), PINCTRL_PIN(5, "IO5"), + PINCTRL_PIN(6, "IO6"), PINCTRL_PIN(7, "IO7"), PINCTRL_PIN(8, "IO8"), + PINCTRL_PIN(9, "IO9"), PINCTRL_PIN(10, "IO10"), PINCTRL_PIN(11, "IO11"), + PINCTRL_PIN(12, "IO12"), PINCTRL_PIN(13, "IO13"), PINCTRL_PIN(14, "IO14"), + PINCTRL_PIN(15, "IO15"), PINCTRL_PIN(16, "IO16"), PINCTRL_PIN(17, "IO17"), + PINCTRL_PIN(18, "IO18"), PINCTRL_PIN(19, "IO19"), PINCTRL_PIN(20, "IO20"), + PINCTRL_PIN(21, "IO21"), PINCTRL_PIN(22, "IO22"), PINCTRL_PIN(23, "IO23"), + PINCTRL_PIN(24, "IO24"), PINCTRL_PIN(25, "IO25"), PINCTRL_PIN(26, "IO26"), + PINCTRL_PIN(27, "IO27"), PINCTRL_PIN(28, "IO28"), PINCTRL_PIN(29, "IO29"), + PINCTRL_PIN(30, "IO30"), PINCTRL_PIN(31, "IO31"), PINCTRL_PIN(32, "IO32"), + PINCTRL_PIN(33, "IO33"), PINCTRL_PIN(34, "IO34"), PINCTRL_PIN(35, "IO35"), + PINCTRL_PIN(36, "IO36"), PINCTRL_PIN(37, "IO37"), PINCTRL_PIN(38, "IO38"), + PINCTRL_PIN(39, "IO39"), PINCTRL_PIN(40, "IO40"), PINCTRL_PIN(41, "IO41"), + PINCTRL_PIN(42, "IO42"), PINCTRL_PIN(43, "IO43"), PINCTRL_PIN(44, "IO44"), + PINCTRL_PIN(45, "IO45"), PINCTRL_PIN(46, "IO46"), PINCTRL_PIN(47, "IO47"), + PINCTRL_PIN(48, "IO48"), PINCTRL_PIN(49, "IO49"), PINCTRL_PIN(50, "IO50"), + PINCTRL_PIN(51, "IO51"), PINCTRL_PIN(52, "IO52"), PINCTRL_PIN(53, "IO53"), + PINCTRL_PIN(54, "IO54"), PINCTRL_PIN(55, "IO55"), PINCTRL_PIN(56, "IO56"), + PINCTRL_PIN(57, "IO57"), PINCTRL_PIN(58, "IO58"), PINCTRL_PIN(59, "IO59"), + PINCTRL_PIN(60, "IO60"), PINCTRL_PIN(61, "IO61"), PINCTRL_PIN(62, "IO62"), + PINCTRL_PIN(63, "IO63") +}; + +static void k230_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int offset) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + u32 val, bias, drive, input, slew, schmitt, power; + struct k230_pin_group *grp = k230_pins[offset].drv_data; + static const char * const biasing[] = { + "pull none", "pull down", "pull up", "" }; + static const char * const enable[] = { + "disable", "enable" }; + static const char * const power_source[] = { + "3V3", "1V8" }; + + regmap_read(info->regmap_base, offset * 4, &val); + + drive = (val & K230_PC_DS) >> K230_SHIFT_DS; + bias = (val & K230_PC_BIAS) >> K230_SHIFT_BIAS; + input = (val & K230_PC_IE) >> K230_SHIFT_IE; + slew = (val & K230_PC_SL) >> K230_SHIFT_SL; + schmitt = (val & K230_PC_ST) >> K230_SHIFT_ST; + power = (val & K230_PC_MSC) >> K230_SHIFT_MSC; + + seq_printf(s, "%s - strength %d - %s - %s - slewrate %s - schmitt %s - %s", + grp ? grp->name : "unknown", + drive, + biasing[bias], + input ? "input" : "output", + enable[slew], + enable[schmitt], + power_source[power]); +} + +static int k230_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = info->pctl_dev->dev; + const struct k230_pmx_func *func; + const struct k230_pin_group *grp; + struct pinctrl_map *new_map; + int map_num, i, j, idx; + unsigned int grp_id; + + func = k230_name_to_funtion(info, np_config->name); + if (!func) { + dev_err(dev, "function %s not found\n", np_config->name); + return -EINVAL; + } + + map_num = 0; + for (i = 0; i < func->ngroups; ++i) { + grp_id = func->group_idx[i]; + /* npins of config map plus a mux map */ + map_num += info->groups[grp_id].num_pins + 1; + } + + new_map = kcalloc(map_num, sizeof(*new_map), GFP_KERNEL); + if (!new_map) + return -ENOMEM; + *map = new_map; + *num_maps = map_num; + + idx = 0; + for (i = 0; i < func->ngroups; ++i) { + grp_id = func->group_idx[i]; + grp = &info->groups[grp_id]; + new_map[idx].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[idx].data.mux.group = grp->name; + new_map[idx].data.mux.function = np_config->name; + idx++; + + for (j = 0; j < grp->num_pins; ++j) { + new_map[idx].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[idx].data.configs.group_or_pin = + pin_get_name(pctldev, grp->pins[j]); + new_map[idx].data.configs.configs = + grp->data[j].configs; + new_map[idx].data.configs.num_configs = + grp->data[j].nconfigs; + idx++; + } + } + + return 0; +} + +static void k230_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned int num_maps) +{ + kfree(map); +} + +static const struct pinctrl_ops k230_pctrl_ops = { + .get_groups_count = k230_get_groups_count, + .get_group_name = k230_get_group_name, + .get_group_pins = k230_get_group_pins, + .pin_dbg_show = k230_pinctrl_pin_dbg_show, + .dt_node_to_map = k230_dt_node_to_map, + .dt_free_map = k230_dt_free_map, +}; + +static int k230_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *config) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + enum pin_config_param param = pinconf_to_config_param(*config); + unsigned int val, arg; + + regmap_read(info->regmap_base, pin * 4, &val); + + switch (param) { + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + arg = (val & K230_PC_ST) ? 1 : 0; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg = (val & K230_PC_DS) >> K230_SHIFT_DS; + break; + case PIN_CONFIG_BIAS_DISABLE: + arg = (val & K230_PC_BIAS) ? 0 : 1; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + arg = (val & K230_PC_PD) ? 1 : 0; + break; + case PIN_CONFIG_BIAS_PULL_UP: + arg = (val & K230_PC_PU) ? 1 : 0; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + arg = (val & K230_PC_OE) ? 1 : 0; + break; + case PIN_CONFIG_INPUT_ENABLE: + arg = (val & K230_PC_IE) ? 1 : 0; + break; + case PIN_CONFIG_POWER_SOURCE: + arg = (val & K230_PC_MSC) ? 1 : 0; + break; + case PIN_CONFIG_SLEW_RATE: + arg = (val & K230_PC_SL) ? 1 : 0; + break; + default: + return -EINVAL; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int k230_pinconf_set_param(struct pinctrl_dev *pctldev, unsigned int pin, + enum pin_config_param param, unsigned int arg) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + unsigned int val; + + regmap_read(info->regmap_base, pin * 4, &val); + + switch (param) { + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (arg) + val |= K230_PC_ST; + else + val &= ~K230_PC_ST; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + val &= ~K230_PC_DS; + val |= (arg << K230_SHIFT_DS) & K230_PC_DS; + break; + case PIN_CONFIG_BIAS_DISABLE: + val &= ~K230_PC_BIAS; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (!arg) + return -EINVAL; + val |= K230_PC_PD; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (!arg) + return -EINVAL; + val |= K230_PC_PU; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + if (!arg) + return -EINVAL; + val |= K230_PC_OE; + break; + case PIN_CONFIG_INPUT_ENABLE: + if (!arg) + return -EINVAL; + val |= K230_PC_IE; + break; + case PIN_CONFIG_POWER_SOURCE: + if (arg) + val |= K230_PC_MSC; + else + val &= ~K230_PC_MSC; + break; + case PIN_CONFIG_SLEW_RATE: + if (arg) + val |= K230_PC_SL; + else + val &= ~K230_PC_SL; + break; + default: + return -EINVAL; + } + + regmap_write(info->regmap_base, pin * 4, val); + + return 0; +} + +static int k230_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = info->pctl_dev->dev; + enum pin_config_param param; + unsigned int arg, i; + int ret; + + if (pin >= K230_NPINS) { + dev_err(dev, "pin number out of range\n"); + return -EINVAL; + } + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + ret = k230_pinconf_set_param(pctldev, pin, param, arg); + if (ret) + return ret; + } + + return 0; +} + +static void k230_pconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + unsigned int val; + + regmap_read(info->regmap_base, pin * 4, &val); + + seq_printf(s, " 0x%08x", val); +} + +static const struct pinconf_ops k230_pinconf_ops = { + .is_generic = true, + .pin_config_get = k230_pinconf_get, + .pin_config_set = k230_pinconf_set, + .pin_config_dbg_show = k230_pconf_dbg_show, +}; + +static int k230_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfunctions; +} + +static const char *k230_get_fname(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->functions[selector].name; +} + +static int k230_get_groups(struct pinctrl_dev *pctldev, unsigned int selector, + const char * const **groups, unsigned int *num_groups) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].ngroups; + + return 0; +} + +static int k230_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, + unsigned int group) +{ + struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct k230_pin_conf *data = info->groups[group].data; + struct k230_pin_group *grp = &info->groups[group]; + const unsigned int *pins = grp->pins; + struct regmap *regmap; + unsigned int value, mask; + int cnt, reg; + + regmap = info->regmap_base; + + for (cnt = 0; cnt < grp->num_pins; cnt++) { + reg = pins[cnt] * 4; + value = data[cnt].func << K230_SHIFT_SEL; + mask = K230_PC_SEL; + regmap_update_bits(regmap, reg, mask, value); + k230_pins[pins[cnt]].drv_data = grp; + } + + return 0; +} + +static const struct pinmux_ops k230_pmxops = { + .get_functions_count = k230_get_functions_count, + .get_function_name = k230_get_fname, + .get_function_groups = k230_get_groups, + .set_mux = k230_set_mux, + .strict = true, +}; + +static int k230_pinctrl_parse_groups(struct device_node *np, + struct k230_pin_group *grp, + struct k230_pinctrl *info, + unsigned int index) +{ + struct device *dev = info->pctl_dev->dev; + const __be32 *list; + int size, i, ret; + + grp->name = np->name; + + list = of_get_property(np, "pinmux", &size); + size /= sizeof(*list); + + grp->num_pins = size; + grp->pins = devm_kcalloc(dev, grp->num_pins, sizeof(*grp->pins), + GFP_KERNEL); + grp->data = devm_kcalloc(dev, grp->num_pins, sizeof(*grp->data), + GFP_KERNEL); + if (!grp->pins || !grp->data) + return -ENOMEM; + + for (i = 0; i < size; i++) { + unsigned int mux_data = be32_to_cpu(*list++); + + grp->pins[i] = (mux_data >> 8); + grp->data[i].func = (mux_data & 0xff); + + ret = pinconf_generic_parse_dt_config(np, NULL, + &grp->data[i].configs, + &grp->data[i].nconfigs); + if (ret) + return ret; + } + + return 0; +} + +static int k230_pinctrl_parse_functions(struct device_node *np, + struct k230_pinctrl *info, + unsigned int index) +{ + struct device *dev = info->pctl_dev->dev; + struct k230_pmx_func *func; + struct k230_pin_group *grp; + static unsigned int idx, i; + int ret; + + func = &info->functions[index]; + + func->name = np->name; + func->ngroups = of_get_child_count(np); + if (func->ngroups <= 0) + return 0; + + func->groups = devm_kcalloc(dev, func->ngroups, + sizeof(*func->groups), GFP_KERNEL); + func->group_idx = devm_kcalloc(dev, func->ngroups, + sizeof(*func->group_idx), GFP_KERNEL); + if (!func->groups || !func->group_idx) + return -ENOMEM; + + i = 0; + + for_each_child_of_node_scoped(np, child) { + func->groups[i] = child->name; + func->group_idx[i] = idx; + grp = &info->groups[idx]; + idx++; + ret = k230_pinctrl_parse_groups(child, grp, info, i++); + if (ret) + return ret; + } + + return 0; +} + +static void k230_pinctrl_child_count(struct k230_pinctrl *info, + struct device_node *np) +{ + for_each_child_of_node_scoped(np, child) { + info->nfunctions++; + info->ngroups += of_get_child_count(child); + } +} + +static int k230_pinctrl_parse_dt(struct platform_device *pdev, + struct k230_pinctrl *info) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + unsigned int i; + int ret; + + k230_pinctrl_child_count(info, np); + + info->functions = devm_kcalloc(dev, info->nfunctions, + sizeof(*info->functions), GFP_KERNEL); + info->groups = devm_kcalloc(dev, info->ngroups, + sizeof(*info->groups), GFP_KERNEL); + if (!info->functions || !info->groups) + return -ENOMEM; + + i = 0; + + for_each_child_of_node_scoped(np, child) { + ret = k230_pinctrl_parse_functions(child, info, i++); + if (ret) { + dev_err(dev, "failed to parse function\n"); + return ret; + } + } + + return 0; +} + +static int k230_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct k230_pinctrl *info; + struct pinctrl_desc *pctl; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + pctl = &info->pctl; + + pctl->name = "k230-pinctrl"; + pctl->owner = THIS_MODULE; + pctl->pins = k230_pins; + pctl->npins = ARRAY_SIZE(k230_pins); + pctl->pctlops = &k230_pctrl_ops; + pctl->pmxops = &k230_pmxops; + pctl->confops = &k230_pinconf_ops; + + info->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(info->base)) + return PTR_ERR(info->base); + + info->regmap_base = devm_regmap_init_mmio(dev, info->base, + &k230_regmap_config); + if (IS_ERR(info->regmap_base)) + return dev_err_probe(dev, PTR_ERR(info->regmap_base), + "failed to init regmap\n"); + + info->pctl_dev = devm_pinctrl_register(dev, pctl, info); + if (IS_ERR(info->pctl_dev)) + return dev_err_probe(dev, PTR_ERR(info->pctl_dev), + "devm_pinctrl_register failed\n"); + + k230_pinctrl_parse_dt(pdev, info); + + return 0; +} + +static const struct of_device_id k230_dt_ids[] = { + { .compatible = "canaan,k230-pinctrl", }, + { /* sintenel */ } +}; +MODULE_DEVICE_TABLE(of, k230_dt_ids); + +static struct platform_driver k230_pinctrl_driver = { + .probe = k230_pinctrl_probe, + .driver = { + .name = "k230-pinctrl", + .of_match_table = k230_dt_ids, + }, +}; +module_platform_driver(k230_pinctrl_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ze Huang <18771902331@163.com>"); +MODULE_DESCRIPTION("Canaan K230 pinctrl driver"); diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index 737d0ae3d0b662..d66c3a3e842924 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -569,7 +569,7 @@ 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)); + seq_puts(p, dev_name(mcp->dev)); } static const struct irq_chip mcp23s08_irq_chip = { diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c index d1ab8450ea93eb..61532a7a612adf 100644 --- a/drivers/pinctrl/pinctrl-ocelot.c +++ b/drivers/pinctrl/pinctrl-ocelot.c @@ -57,6 +57,8 @@ enum { FUNC_CAN1, FUNC_CLKMON, FUNC_NONE, + FUNC_FAN, + FUNC_FC, FUNC_FC0_a, FUNC_FC0_b, FUNC_FC0_c, @@ -71,6 +73,7 @@ enum { FUNC_FC4_a, FUNC_FC4_b, FUNC_FC4_c, + FUNC_FC_SHRD, FUNC_FC_SHRD0, FUNC_FC_SHRD1, FUNC_FC_SHRD2, @@ -92,6 +95,7 @@ enum { FUNC_FC_SHRD18, FUNC_FC_SHRD19, FUNC_FC_SHRD20, + FUNC_FUSA, FUNC_GPIO, FUNC_IB_TRG_a, FUNC_IB_TRG_b, @@ -108,6 +112,8 @@ enum { FUNC_IRQ1, FUNC_IRQ1_IN, FUNC_IRQ1_OUT, + FUNC_IRQ3, + FUNC_IRQ4, FUNC_EXT_IRQ, FUNC_MIIM, FUNC_MIIM_a, @@ -115,12 +121,14 @@ enum { FUNC_MIIM_c, FUNC_MIIM_Sa, FUNC_MIIM_Sb, + FUNC_MIIM_IRQ, FUNC_OB_TRG, FUNC_OB_TRG_a, FUNC_OB_TRG_b, FUNC_PHY_LED, FUNC_PCI_WAKE, FUNC_MD, + FUNC_PCIE_PERST, FUNC_PTP0, FUNC_PTP1, FUNC_PTP2, @@ -152,6 +160,7 @@ enum { FUNC_SGPIO_b, FUNC_SI, FUNC_SI2, + FUNC_SYNCE, FUNC_TACHO, FUNC_TACHO_a, FUNC_TACHO_b, @@ -170,6 +179,10 @@ enum { FUNC_USB_S_a, FUNC_USB_S_b, FUNC_USB_S_c, + FUNC_USB_POWER, + FUNC_USB2PHY_RST, + FUNC_USB_OVER_DETECT, + FUNC_USB_ULPI, FUNC_PLL_STAT, FUNC_EMMC, FUNC_EMMC_SD, @@ -184,6 +197,8 @@ static const char *const ocelot_function_names[] = { [FUNC_CAN1] = "can1", [FUNC_CLKMON] = "clkmon", [FUNC_NONE] = "none", + [FUNC_FAN] = "fan", + [FUNC_FC] = "fc", [FUNC_FC0_a] = "fc0_a", [FUNC_FC0_b] = "fc0_b", [FUNC_FC0_c] = "fc0_c", @@ -198,6 +213,7 @@ static const char *const ocelot_function_names[] = { [FUNC_FC4_a] = "fc4_a", [FUNC_FC4_b] = "fc4_b", [FUNC_FC4_c] = "fc4_c", + [FUNC_FC_SHRD] = "fc_shrd", [FUNC_FC_SHRD0] = "fc_shrd0", [FUNC_FC_SHRD1] = "fc_shrd1", [FUNC_FC_SHRD2] = "fc_shrd2", @@ -219,6 +235,7 @@ static const char *const ocelot_function_names[] = { [FUNC_FC_SHRD18] = "fc_shrd18", [FUNC_FC_SHRD19] = "fc_shrd19", [FUNC_FC_SHRD20] = "fc_shrd20", + [FUNC_FUSA] = "fusa", [FUNC_GPIO] = "gpio", [FUNC_IB_TRG_a] = "ib_trig_a", [FUNC_IB_TRG_b] = "ib_trig_b", @@ -235,6 +252,8 @@ static const char *const ocelot_function_names[] = { [FUNC_IRQ1] = "irq1", [FUNC_IRQ1_IN] = "irq1_in", [FUNC_IRQ1_OUT] = "irq1_out", + [FUNC_IRQ3] = "irq3", + [FUNC_IRQ4] = "irq4", [FUNC_EXT_IRQ] = "ext_irq", [FUNC_MIIM] = "miim", [FUNC_MIIM_a] = "miim_a", @@ -242,8 +261,10 @@ static const char *const ocelot_function_names[] = { [FUNC_MIIM_c] = "miim_c", [FUNC_MIIM_Sa] = "miim_slave_a", [FUNC_MIIM_Sb] = "miim_slave_b", + [FUNC_MIIM_IRQ] = "miim_irq", [FUNC_PHY_LED] = "phy_led", [FUNC_PCI_WAKE] = "pci_wake", + [FUNC_PCIE_PERST] = "pcie_perst", [FUNC_MD] = "md", [FUNC_OB_TRG] = "ob_trig", [FUNC_OB_TRG_a] = "ob_trig_a", @@ -279,6 +300,7 @@ static const char *const ocelot_function_names[] = { [FUNC_SGPIO_b] = "sgpio_b", [FUNC_SI] = "si", [FUNC_SI2] = "si2", + [FUNC_SYNCE] = "synce", [FUNC_TACHO] = "tacho", [FUNC_TACHO_a] = "tacho_a", [FUNC_TACHO_b] = "tacho_b", @@ -294,6 +316,10 @@ static const char *const ocelot_function_names[] = { [FUNC_USB_S_a] = "usb_slave_a", [FUNC_USB_S_b] = "usb_slave_b", [FUNC_USB_S_c] = "usb_slave_c", + [FUNC_USB_POWER] = "usb_power", + [FUNC_USB2PHY_RST] = "usb2phy_rst", + [FUNC_USB_OVER_DETECT] = "usb_over_detect", + [FUNC_USB_ULPI] = "usb_ulpi", [FUNC_UART] = "uart", [FUNC_UART2] = "uart2", [FUNC_UART3] = "uart3", @@ -1136,6 +1162,165 @@ static const struct pinctrl_pin_desc lan966x_pins[] = { LAN966X_PIN(77), }; +#define LAN969X_P(p, f0, f1, f2, f3, f4, f5, f6, f7) \ +static struct ocelot_pin_caps lan969x_pin_##p = { \ + .pin = p, \ + .functions = { \ + FUNC_##f0, FUNC_##f1, FUNC_##f2, \ + FUNC_##f3 \ + }, \ + .a_functions = { \ + FUNC_##f4, FUNC_##f5, FUNC_##f6, \ + FUNC_##f7 \ + }, \ +} + +/* Pinmuxing table taken from data sheet */ +/* Pin FUNC0 FUNC1 FUNC2 FUNC3 FUNC4 FUNC5 FUNC6 FUNC7 */ +LAN969X_P(0, GPIO, IRQ0, FC_SHRD, PCIE_PERST, NONE, NONE, NONE, R); +LAN969X_P(1, GPIO, IRQ1, FC_SHRD, USB_POWER, NONE, NONE, NONE, R); +LAN969X_P(2, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R); +LAN969X_P(3, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R); +LAN969X_P(4, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R); +LAN969X_P(5, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R); +LAN969X_P(6, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R); +LAN969X_P(7, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R); +LAN969X_P(8, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R); +LAN969X_P(9, GPIO, MIIM, MIIM_Sa, CLKMON, NONE, NONE, NONE, R); +LAN969X_P(10, GPIO, MIIM, MIIM_Sa, CLKMON, NONE, NONE, NONE, R); +LAN969X_P(11, GPIO, MIIM_IRQ, MIIM_Sa, CLKMON, NONE, NONE, NONE, R); +LAN969X_P(12, GPIO, IRQ3, FC_SHRD, USB2PHY_RST, NONE, NONE, NONE, R); +LAN969X_P(13, GPIO, IRQ4, FC_SHRD, USB_OVER_DETECT, NONE, NONE, NONE, R); +LAN969X_P(14, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R); +LAN969X_P(15, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R); +LAN969X_P(16, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R); +LAN969X_P(17, GPIO, EMMC_SD, QSPI1, PTPSYNC_0, USB_POWER, NONE, NONE, R); +LAN969X_P(18, GPIO, EMMC_SD, QSPI1, PTPSYNC_1, USB2PHY_RST, NONE, NONE, R); +LAN969X_P(19, GPIO, EMMC_SD, QSPI1, PTPSYNC_2, USB_OVER_DETECT, NONE, NONE, R); +LAN969X_P(20, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R); +LAN969X_P(21, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R); +LAN969X_P(22, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R); +LAN969X_P(23, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R); +LAN969X_P(24, GPIO, EMMC_SD, NONE, NONE, NONE, NONE, NONE, R); +LAN969X_P(25, GPIO, FAN, FUSA, CAN0_a, QSPI1, NONE, NONE, R); +LAN969X_P(26, GPIO, FAN, FUSA, CAN0_a, QSPI1, NONE, NONE, R); +LAN969X_P(27, GPIO, SYNCE, FC, MIIM, QSPI1, NONE, NONE, R); +LAN969X_P(28, GPIO, SYNCE, FC, MIIM, QSPI1, NONE, NONE, R); +LAN969X_P(29, GPIO, SYNCE, FC, MIIM_IRQ, QSPI1, NONE, NONE, R); +LAN969X_P(30, GPIO, PTPSYNC_0, USB_ULPI, FC_SHRD, QSPI1, NONE, NONE, R); +LAN969X_P(31, GPIO, PTPSYNC_1, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R); +LAN969X_P(32, GPIO, PTPSYNC_2, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R); +LAN969X_P(33, GPIO, SD, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R); +LAN969X_P(34, GPIO, SD, USB_ULPI, CAN1, FC_SHRD, NONE, NONE, R); +LAN969X_P(35, GPIO, SD, USB_ULPI, CAN1, FC_SHRD, NONE, NONE, R); +LAN969X_P(36, GPIO, SD, USB_ULPI, PCIE_PERST, FC_SHRD, NONE, NONE, R); +LAN969X_P(37, GPIO, SD, USB_ULPI, CAN0_b, NONE, NONE, NONE, R); +LAN969X_P(38, GPIO, SD, USB_ULPI, CAN0_b, NONE, NONE, NONE, R); +LAN969X_P(39, GPIO, SD, USB_ULPI, MIIM, NONE, NONE, NONE, R); +LAN969X_P(40, GPIO, SD, USB_ULPI, MIIM, NONE, NONE, NONE, R); +LAN969X_P(41, GPIO, SD, USB_ULPI, MIIM_IRQ, NONE, NONE, NONE, R); +LAN969X_P(42, GPIO, PTPSYNC_3, CAN1, NONE, NONE, NONE, NONE, R); +LAN969X_P(43, GPIO, PTPSYNC_4, CAN1, NONE, NONE, NONE, NONE, R); +LAN969X_P(44, GPIO, PTPSYNC_5, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(45, GPIO, PTPSYNC_6, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(46, GPIO, PTPSYNC_7, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(47, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(48, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(49, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(50, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(51, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(52, GPIO, FAN, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(53, GPIO, FAN, SFP_SD, NONE, NONE, NONE, NONE, R); +LAN969X_P(54, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R); +LAN969X_P(55, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R); +LAN969X_P(56, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R); +LAN969X_P(57, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_3, NONE, NONE, R); +LAN969X_P(58, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_4, NONE, NONE, R); +LAN969X_P(59, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_5, NONE, NONE, R); +LAN969X_P(60, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_6, NONE, NONE, R); +LAN969X_P(61, GPIO, MIIM, FC_SHRD, TWI, NONE, NONE, NONE, R); +LAN969X_P(62, GPIO, MIIM, FC_SHRD, TWI, NONE, NONE, NONE, R); +LAN969X_P(63, GPIO, MIIM_IRQ, FC_SHRD, TWI, NONE, NONE, NONE, R); +LAN969X_P(64, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R); +LAN969X_P(65, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R); +LAN969X_P(66, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R); + +#define LAN969X_PIN(n) { \ + .number = n, \ + .name = "GPIO_"#n, \ + .drv_data = &lan969x_pin_##n \ +} + +static const struct pinctrl_pin_desc lan969x_pins[] = { + LAN969X_PIN(0), + LAN969X_PIN(1), + LAN969X_PIN(2), + LAN969X_PIN(3), + LAN969X_PIN(4), + LAN969X_PIN(5), + LAN969X_PIN(6), + LAN969X_PIN(7), + LAN969X_PIN(8), + LAN969X_PIN(9), + LAN969X_PIN(10), + LAN969X_PIN(11), + LAN969X_PIN(12), + LAN969X_PIN(13), + LAN969X_PIN(14), + LAN969X_PIN(15), + LAN969X_PIN(16), + LAN969X_PIN(17), + LAN969X_PIN(18), + LAN969X_PIN(19), + LAN969X_PIN(20), + LAN969X_PIN(21), + LAN969X_PIN(22), + LAN969X_PIN(23), + LAN969X_PIN(24), + LAN969X_PIN(25), + LAN969X_PIN(26), + LAN969X_PIN(27), + LAN969X_PIN(28), + LAN969X_PIN(29), + LAN969X_PIN(30), + LAN969X_PIN(31), + LAN969X_PIN(32), + LAN969X_PIN(33), + LAN969X_PIN(34), + LAN969X_PIN(35), + LAN969X_PIN(36), + LAN969X_PIN(37), + LAN969X_PIN(38), + LAN969X_PIN(39), + LAN969X_PIN(40), + LAN969X_PIN(41), + LAN969X_PIN(42), + LAN969X_PIN(43), + LAN969X_PIN(44), + LAN969X_PIN(45), + LAN969X_PIN(46), + LAN969X_PIN(47), + LAN969X_PIN(48), + LAN969X_PIN(49), + LAN969X_PIN(50), + LAN969X_PIN(51), + LAN969X_PIN(52), + LAN969X_PIN(53), + LAN969X_PIN(54), + LAN969X_PIN(55), + LAN969X_PIN(56), + LAN969X_PIN(57), + LAN969X_PIN(58), + LAN969X_PIN(59), + LAN969X_PIN(60), + LAN969X_PIN(61), + LAN969X_PIN(62), + LAN969X_PIN(63), + LAN969X_PIN(64), + LAN969X_PIN(65), + LAN969X_PIN(66), +}; + static int ocelot_get_functions_count(struct pinctrl_dev *pctldev) { return ARRAY_SIZE(ocelot_function_names); @@ -1682,6 +1867,23 @@ static struct ocelot_match_data lan966x_desc = { }, }; +static struct ocelot_match_data lan969x_desc = { + .desc = { + .name = "lan969x-pinctrl", + .pins = lan969x_pins, + .npins = ARRAY_SIZE(lan969x_pins), + .pctlops = &ocelot_pctl_ops, + .pmxops = &lan966x_pmx_ops, + .confops = &ocelot_confops, + .owner = THIS_MODULE, + }, + .pincfg_data = { + .pd_bit = BIT(3), + .pu_bit = BIT(2), + .drive_bits = GENMASK(1, 0), + }, +}; + static int ocelot_create_group_func_map(struct device *dev, struct ocelot_pinctrl *info) { @@ -2014,6 +2216,7 @@ static const struct of_device_id ocelot_pinctrl_of_match[] = { { .compatible = "mscc,servalt-pinctrl", .data = &servalt_desc }, { .compatible = "microchip,sparx5-pinctrl", .data = &sparx5_desc }, { .compatible = "microchip,lan966x-pinctrl", .data = &lan966x_desc }, + { .compatible = "microchip,lan9691-pinctrl", .data = &lan969x_desc }, {}, }; MODULE_DEVICE_TABLE(of, ocelot_pinctrl_of_match); diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 5c1bc4d5b662ed..36d4eaf0ebd154 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -3227,7 +3227,9 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np, /* we do not check return since it's safe node passed down */ size /= sizeof(*list); if (!size || size % 4) - return dev_err_probe(dev, -EINVAL, "wrong pins number or pins and configs should be by 4\n"); + return dev_err_probe(dev, -EINVAL, + "%pOF: rockchip,pins: expected one or more of , got %d args instead\n", + np, size); grp->npins = size / 4; @@ -4219,7 +4221,7 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = { static struct platform_driver rockchip_pinctrl_driver = { .probe = rockchip_pinctrl_probe, - .remove_new = rockchip_pinctrl_remove, + .remove = rockchip_pinctrl_remove, .driver = { .name = "rockchip-pinctrl", .pm = &rockchip_pinctrl_dev_pm_ops, diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 2ec599e383e4b2..5be14dc979e26d 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1966,6 +1966,7 @@ static const struct pcs_soc_data pinconf_single = { }; static const struct of_device_id pcs_of_match[] = { + { .compatible = "marvell,pxa1908-padconf", .data = &pinconf_single }, { .compatible = "ti,am437-padconf", .data = &pinctrl_single_am437x }, { .compatible = "ti,am654-padconf", .data = &pinctrl_single_am654 }, { .compatible = "ti,dra7-padconf", .data = &pinctrl_single_dra7 }, @@ -1981,7 +1982,7 @@ MODULE_DEVICE_TABLE(of, pcs_of_match); static struct platform_driver pcs_driver = { .probe = pcs_probe, - .remove_new = pcs_remove, + .remove = pcs_remove, .driver = { .name = DRIVER_NAME, .of_match_table = pcs_of_match, diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c index d2c5321dd025f8..521f6fef0b9f68 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -599,7 +599,7 @@ 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)); + seq_puts(p, dev_name(pctl->dev)); } static const struct irq_chip stmfx_pinctrl_irq_chip = { @@ -855,7 +855,7 @@ static struct platform_driver stmfx_pinctrl_driver = { .pm = &stmfx_pinctrl_dev_pm_ops, }, .probe = stmfx_pinctrl_probe, - .remove_new = stmfx_pinctrl_remove, + .remove = stmfx_pinctrl_remove, }; module_platform_driver(stmfx_pinctrl_driver); diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c index fd0331a87cda21..98262b8ce43ac4 100644 --- a/drivers/pinctrl/pinctrl-sx150x.c +++ b/drivers/pinctrl/pinctrl-sx150x.c @@ -584,7 +584,7 @@ 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); + seq_puts(p, pctl->client->name); } static const struct irq_chip sx150x_irq_chip = { @@ -1105,7 +1105,7 @@ static const struct regmap_config sx150x_regmap_config = { .reg_bits = 8, .val_bits = 32, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_read = sx150x_regmap_reg_read, .reg_write = sx150x_regmap_reg_write, diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c index 4f98f72565f48b..d6bb8f58978df1 100644 --- a/drivers/pinctrl/pinctrl-tb10x.c +++ b/drivers/pinctrl/pinctrl-tb10x.c @@ -820,7 +820,7 @@ MODULE_DEVICE_TABLE(of, tb10x_pinctrl_dt_ids); static struct platform_driver tb10x_pinctrl_pdrv = { .probe = tb10x_pinctrl_probe, - .remove_new = tb10x_pinctrl_remove, + .remove = tb10x_pinctrl_remove, .driver = { .name = "tb10x_pinctrl", .of_match_table = of_match_ptr(tb10x_pinctrl_dt_ids), diff --git a/drivers/pinctrl/pinctrl-th1520.c b/drivers/pinctrl/pinctrl-th1520.c new file mode 100644 index 00000000000000..e641bad6728cc5 --- /dev/null +++ b/drivers/pinctrl/pinctrl-th1520.c @@ -0,0 +1,918 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Pinctrl driver for the T-Head TH1520 SoC + * + * Copyright (C) 2023 Emil Renner Berthing + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "core.h" +#include "pinmux.h" +#include "pinconf.h" + +#define TH1520_PADCFG_IE BIT(9) +#define TH1520_PADCFG_SL BIT(8) +#define TH1520_PADCFG_ST BIT(7) +#define TH1520_PADCFG_SPU BIT(6) +#define TH1520_PADCFG_PS BIT(5) +#define TH1520_PADCFG_PE BIT(4) +#define TH1520_PADCFG_BIAS (TH1520_PADCFG_SPU | TH1520_PADCFG_PS | TH1520_PADCFG_PE) +#define TH1520_PADCFG_DS GENMASK(3, 0) + +#define TH1520_PULL_DOWN_OHM 44000 /* typ. 44kOhm */ +#define TH1520_PULL_UP_OHM 48000 /* typ. 48kOhm */ +#define TH1520_PULL_STRONG_OHM 2100 /* typ. 2.1kOhm */ + +#define TH1520_PAD_NO_PADCFG BIT(30) +#define TH1520_PAD_MUXDATA GENMASK(29, 0) + +struct th1520_pad_group { + const char *name; + const struct pinctrl_pin_desc *pins; + unsigned int npins; +}; + +struct th1520_pinctrl { + struct pinctrl_desc desc; + struct mutex mutex; /* serialize adding functions */ + raw_spinlock_t lock; /* serialize register access */ + void __iomem *base; + struct pinctrl_dev *pctl; +}; + +static void __iomem *th1520_padcfg(struct th1520_pinctrl *thp, + unsigned int pin) +{ + return thp->base + 4 * (pin / 2); +} + +static unsigned int th1520_padcfg_shift(unsigned int pin) +{ + return 16 * (pin & BIT(0)); +} + +static void __iomem *th1520_muxcfg(struct th1520_pinctrl *thp, + unsigned int pin) +{ + return thp->base + 0x400 + 4 * (pin / 8); +} + +static unsigned int th1520_muxcfg_shift(unsigned int pin) +{ + return 4 * (pin & GENMASK(2, 0)); +} + +enum th1520_muxtype { + TH1520_MUX_____, + TH1520_MUX_GPIO, + TH1520_MUX_PWM, + TH1520_MUX_UART, + TH1520_MUX_IR, + TH1520_MUX_I2C, + TH1520_MUX_SPI, + TH1520_MUX_QSPI, + TH1520_MUX_SDIO, + TH1520_MUX_AUD, + TH1520_MUX_I2S, + TH1520_MUX_MAC0, + TH1520_MUX_MAC1, + TH1520_MUX_DPU0, + TH1520_MUX_DPU1, + TH1520_MUX_ISP, + TH1520_MUX_HDMI, + TH1520_MUX_BSEL, + TH1520_MUX_DBG, + TH1520_MUX_CLK, + TH1520_MUX_JTAG, + TH1520_MUX_ISO, + TH1520_MUX_FUSE, + TH1520_MUX_RST, +}; + +static const char *const th1520_muxtype_string[] = { + [TH1520_MUX_GPIO] = "gpio", + [TH1520_MUX_PWM] = "pwm", + [TH1520_MUX_UART] = "uart", + [TH1520_MUX_IR] = "ir", + [TH1520_MUX_I2C] = "i2c", + [TH1520_MUX_SPI] = "spi", + [TH1520_MUX_QSPI] = "qspi", + [TH1520_MUX_SDIO] = "sdio", + [TH1520_MUX_AUD] = "audio", + [TH1520_MUX_I2S] = "i2s", + [TH1520_MUX_MAC0] = "gmac0", + [TH1520_MUX_MAC1] = "gmac1", + [TH1520_MUX_DPU0] = "dpu0", + [TH1520_MUX_DPU1] = "dpu1", + [TH1520_MUX_ISP] = "isp", + [TH1520_MUX_HDMI] = "hdmi", + [TH1520_MUX_BSEL] = "bootsel", + [TH1520_MUX_DBG] = "debug", + [TH1520_MUX_CLK] = "clock", + [TH1520_MUX_JTAG] = "jtag", + [TH1520_MUX_ISO] = "iso7816", + [TH1520_MUX_FUSE] = "efuse", + [TH1520_MUX_RST] = "reset", +}; + +static enum th1520_muxtype th1520_muxtype_get(const char *str) +{ + enum th1520_muxtype mt; + + for (mt = TH1520_MUX_GPIO; mt < ARRAY_SIZE(th1520_muxtype_string); mt++) { + if (!strcmp(str, th1520_muxtype_string[mt])) + return mt; + } + return TH1520_MUX_____; +} + +#define TH1520_PAD(_nr, _name, m0, m1, m2, m3, m4, m5, _flags) \ + { .number = _nr, .name = #_name, .drv_data = (void *)((_flags) | \ + (TH1520_MUX_##m0 << 0) | (TH1520_MUX_##m1 << 5) | (TH1520_MUX_##m2 << 10) | \ + (TH1520_MUX_##m3 << 15) | (TH1520_MUX_##m4 << 20) | (TH1520_MUX_##m5 << 25)) } + +static unsigned long th1520_pad_muxdata(void *drv_data) +{ + return (uintptr_t)drv_data & TH1520_PAD_MUXDATA; +} + +static bool th1520_pad_no_padcfg(void *drv_data) +{ + return (uintptr_t)drv_data & TH1520_PAD_NO_PADCFG; +} + +static const struct pinctrl_pin_desc th1520_group1_pins[] = { + TH1520_PAD(0, OSC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(1, OSC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(2, SYS_RST_N, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(3, RTC_CLK_IN, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(4, RTC_CLK_OUT, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + /* skip number 5 so we can calculate register offsets and shifts from the pin number */ + TH1520_PAD(6, TEST_MODE, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(7, DEBUG_MODE, DBG, ____, ____, GPIO, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(8, POR_SEL, ____, ____, ____, ____, ____, ____, TH1520_PAD_NO_PADCFG), + TH1520_PAD(9, I2C_AON_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, I2C_AON_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, CPU_JTG_TCLK, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, CPU_JTG_TMS, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, CPU_JTG_TDI, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(14, CPU_JTG_TDO, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(15, CPU_JTG_TRST, JTAG, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(16, AOGPIO_7, CLK, AUD, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, AOGPIO_8, UART, AUD, IR, GPIO, ____, ____, 0), + TH1520_PAD(18, AOGPIO_9, UART, AUD, IR, GPIO, ____, ____, 0), + TH1520_PAD(19, AOGPIO_10, CLK, AUD, ____, GPIO, ____, ____, 0), + TH1520_PAD(20, AOGPIO_11, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(21, AOGPIO_12, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(22, AOGPIO_13, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(23, AOGPIO_14, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(24, AOGPIO_15, GPIO, AUD, ____, ____, ____, ____, 0), + TH1520_PAD(25, AUDIO_PA0, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(26, AUDIO_PA1, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(27, AUDIO_PA2, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(28, AUDIO_PA3, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(29, AUDIO_PA4, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(30, AUDIO_PA5, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(31, AUDIO_PA6, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(32, AUDIO_PA7, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(33, AUDIO_PA8, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(34, AUDIO_PA9, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(35, AUDIO_PA10, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(36, AUDIO_PA11, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(37, AUDIO_PA12, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(38, AUDIO_PA13, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(39, AUDIO_PA14, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(40, AUDIO_PA15, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(41, AUDIO_PA16, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(42, AUDIO_PA17, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(43, AUDIO_PA27, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(44, AUDIO_PA28, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(45, AUDIO_PA29, AUD, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(46, AUDIO_PA30, AUD, RST, ____, GPIO, ____, ____, 0), +}; + +static const struct pinctrl_pin_desc th1520_group2_pins[] = { + TH1520_PAD(0, QSPI1_SCLK, QSPI, ISO, ____, GPIO, FUSE, ____, 0), + TH1520_PAD(1, QSPI1_CSN0, QSPI, ____, I2C, GPIO, FUSE, ____, 0), + TH1520_PAD(2, QSPI1_D0_MOSI, QSPI, ISO, I2C, GPIO, FUSE, ____, 0), + TH1520_PAD(3, QSPI1_D1_MISO, QSPI, ISO, ____, GPIO, FUSE, ____, 0), + TH1520_PAD(4, QSPI1_D2_WP, QSPI, ISO, UART, GPIO, FUSE, ____, 0), + TH1520_PAD(5, QSPI1_D3_HOLD, QSPI, ISO, UART, GPIO, ____, ____, 0), + TH1520_PAD(6, I2C0_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(7, I2C0_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(8, I2C1_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(9, I2C1_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, UART1_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, UART1_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, UART4_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, UART4_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(14, UART4_CTSN, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(15, UART4_RTSN, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(16, UART3_TXD, DBG, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, UART3_RXD, DBG, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(18, GPIO0_18, GPIO, I2C, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(19, GPIO0_19, GPIO, I2C, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(20, GPIO0_20, GPIO, UART, IR, ____, DPU0, DPU1, 0), + TH1520_PAD(21, GPIO0_21, GPIO, UART, IR, ____, DPU0, DPU1, 0), + TH1520_PAD(22, GPIO0_22, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(23, GPIO0_23, GPIO, JTAG, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(24, GPIO0_24, GPIO, JTAG, QSPI, ____, DPU0, DPU1, 0), + TH1520_PAD(25, GPIO0_25, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(26, GPIO0_26, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(27, GPIO0_27, GPIO, ____, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(28, GPIO0_28, GPIO, ____, I2C, ____, DPU0, DPU1, 0), + TH1520_PAD(29, GPIO0_29, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(30, GPIO0_30, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(31, GPIO0_31, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(32, GPIO1_0, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(33, GPIO1_1, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(34, GPIO1_2, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(35, GPIO1_3, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(36, GPIO1_4, GPIO, JTAG, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(37, GPIO1_5, GPIO, ____, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(38, GPIO1_6, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(39, GPIO1_7, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(40, GPIO1_8, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(41, GPIO1_9, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(42, GPIO1_10, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(43, GPIO1_11, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(44, GPIO1_12, GPIO, QSPI, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(45, GPIO1_13, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(46, GPIO1_14, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(47, GPIO1_15, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(48, GPIO1_16, GPIO, UART, ____, ____, DPU0, DPU1, 0), + TH1520_PAD(49, CLK_OUT_0, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(50, CLK_OUT_1, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(51, CLK_OUT_2, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(52, CLK_OUT_3, BSEL, CLK, ____, GPIO, ____, ____, 0), + TH1520_PAD(53, GPIO1_21, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(54, GPIO1_22, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(55, GPIO1_23, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(56, GPIO1_24, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(57, GPIO1_25, JTAG, ____, ISP, GPIO, ____, ____, 0), + TH1520_PAD(58, GPIO1_26, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(59, GPIO1_27, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(60, GPIO1_28, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(61, GPIO1_29, GPIO, ____, ISP, ____, ____, ____, 0), + TH1520_PAD(62, GPIO1_30, GPIO, ____, ISP, ____, ____, ____, 0), +}; + +static const struct pinctrl_pin_desc th1520_group3_pins[] = { + TH1520_PAD(0, UART0_TXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(1, UART0_RXD, UART, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(2, QSPI0_SCLK, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(3, QSPI0_CSN0, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(4, QSPI0_CSN1, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(5, QSPI0_D0_MOSI, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(6, QSPI0_D1_MISO, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(7, QSPI0_D2_WP, QSPI, PWM, I2S, GPIO, ____, ____, 0), + TH1520_PAD(8, QSPI1_D3_HOLD, QSPI, ____, I2S, GPIO, ____, ____, 0), + TH1520_PAD(9, I2C2_SCL, I2C, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(10, I2C2_SDA, I2C, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(11, I2C3_SCL, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(12, I2C3_SDA, I2C, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(13, GPIO2_13, GPIO, SPI, ____, ____, ____, ____, 0), + TH1520_PAD(14, SPI_SCLK, SPI, UART, IR, GPIO, ____, ____, 0), + TH1520_PAD(15, SPI_CSN, SPI, UART, IR, GPIO, ____, ____, 0), + TH1520_PAD(16, SPI_MOSI, SPI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(17, SPI_MISO, SPI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(18, GPIO2_18, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(19, GPIO2_19, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(20, GPIO2_20, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(21, GPIO2_21, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(22, GPIO2_22, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(23, GPIO2_23, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(24, GPIO2_24, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(25, GPIO2_25, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(26, SDIO0_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(27, SDIO0_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(28, SDIO1_WPRTN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(29, SDIO1_DETN, SDIO, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(30, GPIO2_30, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(31, GPIO2_31, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(32, GPIO3_0, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(33, GPIO3_1, GPIO, MAC1, ____, ____, ____, ____, 0), + TH1520_PAD(34, GPIO3_2, GPIO, PWM, ____, ____, ____, ____, 0), + TH1520_PAD(35, GPIO3_3, GPIO, PWM, ____, ____, ____, ____, 0), + TH1520_PAD(36, HDMI_SCL, HDMI, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(37, HDMI_SDA, HDMI, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(38, HDMI_CEC, HDMI, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(39, GMAC0_TX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(40, GMAC0_RX_CLK, MAC0, ____, ____, GPIO, ____, ____, 0), + TH1520_PAD(41, GMAC0_TXEN, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(42, GMAC0_TXD0, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(43, GMAC0_TXD1, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(44, GMAC0_TXD2, MAC0, UART, ____, GPIO, ____, ____, 0), + TH1520_PAD(45, GMAC0_TXD3, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(46, GMAC0_RXDV, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(47, GMAC0_RXD0, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(48, GMAC0_RXD1, MAC0, I2C, ____, GPIO, ____, ____, 0), + TH1520_PAD(49, GMAC0_RXD2, MAC0, SPI, ____, GPIO, ____, ____, 0), + TH1520_PAD(50, GMAC0_RXD3, MAC0, SPI, ____, GPIO, ____, ____, 0), + TH1520_PAD(51, GMAC0_MDC, MAC0, SPI, MAC1, GPIO, ____, ____, 0), + TH1520_PAD(52, GMAC0_MDIO, MAC0, SPI, MAC1, GPIO, ____, ____, 0), + TH1520_PAD(53, GMAC0_COL, MAC0, PWM, ____, GPIO, ____, ____, 0), + TH1520_PAD(54, GMAC0_CRS, MAC0, PWM, ____, GPIO, ____, ____, 0), +}; + +static const struct th1520_pad_group th1520_group1 = { + .name = "th1520-group1", + .pins = th1520_group1_pins, + .npins = ARRAY_SIZE(th1520_group1_pins), +}; + +static const struct th1520_pad_group th1520_group2 = { + .name = "th1520-group2", + .pins = th1520_group2_pins, + .npins = ARRAY_SIZE(th1520_group2_pins), +}; + +static const struct th1520_pad_group th1520_group3 = { + .name = "th1520-group3", + .pins = th1520_group3_pins, + .npins = ARRAY_SIZE(th1520_group3_pins), +}; + +static int th1520_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + + return thp->desc.npins; +} + +static const char *th1520_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned int gsel) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + + return thp->desc.pins[gsel].name; +} + +static int th1520_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned int gsel, + const unsigned int **pins, + unsigned int *npins) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + + *pins = &thp->desc.pins[gsel].number; + *npins = 1; + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void th1520_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + void __iomem *padcfg = th1520_padcfg(thp, pin); + void __iomem *muxcfg = th1520_muxcfg(thp, pin); + u32 pad; + u32 mux; + + scoped_guard(raw_spinlock_irqsave, &thp->lock) { + pad = readl_relaxed(padcfg); + mux = readl_relaxed(muxcfg); + } + + seq_printf(s, "[PADCFG_%03u:0x%x=0x%07x MUXCFG_%03u:0x%x=0x%08x]", + 1 + pin / 2, 0x000 + 4 * (pin / 2), pad, + 1 + pin / 8, 0x400 + 4 * (pin / 8), mux); +} +#else +#define th1520_pin_dbg_show NULL +#endif + +static void th1520_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned int nmaps) +{ + unsigned long *seen = NULL; + unsigned int i; + + for (i = 0; i < nmaps; i++) { + if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN && + map[i].data.configs.configs != seen) { + seen = map[i].data.configs.configs; + kfree(seen); + } + } + + kfree(map); +} + +static int th1520_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **maps, + unsigned int *num_maps) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + struct pinctrl_map *map; + unsigned long *configs; + unsigned int nconfigs; + unsigned int nmaps; + int ret; + + nmaps = 0; + for_each_available_child_of_node_scoped(np, child) { + int npins = of_property_count_strings(child, "pins"); + + if (npins <= 0) { + dev_err(thp->pctl->dev, "no pins selected for %pOFn.%pOFn\n", + np, child); + return -EINVAL; + } + nmaps += npins; + if (of_property_present(child, "function")) + nmaps += npins; + } + + map = kcalloc(nmaps, sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + nmaps = 0; + guard(mutex)(&thp->mutex); + for_each_available_child_of_node_scoped(np, child) { + unsigned int rollback = nmaps; + enum th1520_muxtype muxtype; + struct property *prop; + const char *funcname; + const char **pgnames; + const char *pinname; + int npins; + + ret = pinconf_generic_parse_dt_config(child, pctldev, &configs, &nconfigs); + if (ret) { + dev_err(thp->pctl->dev, "%pOFn.%pOFn: error parsing pin config\n", + np, child); + goto free_map; + } + + if (!of_property_read_string(child, "function", &funcname)) { + muxtype = th1520_muxtype_get(funcname); + if (!muxtype) { + dev_err(thp->pctl->dev, "%pOFn.%pOFn: unknown function '%s'\n", + np, child, funcname); + ret = -EINVAL; + goto free_configs; + } + + funcname = devm_kasprintf(thp->pctl->dev, GFP_KERNEL, "%pOFn.%pOFn", + np, child); + if (!funcname) { + ret = -ENOMEM; + goto free_configs; + } + + npins = of_property_count_strings(child, "pins"); + pgnames = devm_kcalloc(thp->pctl->dev, npins, sizeof(*pgnames), GFP_KERNEL); + if (!pgnames) { + ret = -ENOMEM; + goto free_configs; + } + } else { + funcname = NULL; + } + + npins = 0; + of_property_for_each_string(child, "pins", prop, pinname) { + unsigned int i; + + for (i = 0; i < thp->desc.npins; i++) { + if (!strcmp(pinname, thp->desc.pins[i].name)) + break; + } + if (i == thp->desc.npins) { + nmaps = rollback; + dev_err(thp->pctl->dev, "%pOFn.%pOFn: unknown pin '%s'\n", + np, child, pinname); + ret = -EINVAL; + goto free_configs; + } + + if (nconfigs) { + map[nmaps].type = PIN_MAP_TYPE_CONFIGS_PIN; + map[nmaps].data.configs.group_or_pin = thp->desc.pins[i].name; + map[nmaps].data.configs.configs = configs; + map[nmaps].data.configs.num_configs = nconfigs; + nmaps += 1; + } + if (funcname) { + pgnames[npins++] = thp->desc.pins[i].name; + map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + map[nmaps].data.mux.function = funcname; + map[nmaps].data.mux.group = thp->desc.pins[i].name; + nmaps += 1; + } + } + + if (funcname) { + ret = pinmux_generic_add_function(pctldev, funcname, pgnames, + npins, (void *)muxtype); + if (ret < 0) { + dev_err(thp->pctl->dev, "error adding function %s\n", funcname); + goto free_map; + } + } + } + + *maps = map; + *num_maps = nmaps; + return 0; + +free_configs: + kfree(configs); +free_map: + th1520_pinctrl_dt_free_map(pctldev, map, nmaps); + return ret; +} + +static const struct pinctrl_ops th1520_pinctrl_ops = { + .get_groups_count = th1520_pinctrl_get_groups_count, + .get_group_name = th1520_pinctrl_get_group_name, + .get_group_pins = th1520_pinctrl_get_group_pins, + .pin_dbg_show = th1520_pin_dbg_show, + .dt_node_to_map = th1520_pinctrl_dt_node_to_map, + .dt_free_map = th1520_pinctrl_dt_free_map, +}; + +static const u8 th1520_drive_strength_in_ma[16] = { + 1, 2, 3, 5, 7, 8, 10, 12, 13, 15, 16, 18, 20, 21, 23, 25, +}; + +static u16 th1520_drive_strength_from_ma(u32 arg) +{ + u16 ds; + + for (ds = 0; ds < TH1520_PADCFG_DS; ds++) { + if (arg <= th1520_drive_strength_in_ma[ds]) + return ds; + } + return TH1520_PADCFG_DS; +} + +static int th1520_padcfg_rmw(struct th1520_pinctrl *thp, unsigned int pin, + u32 mask, u32 value) +{ + void __iomem *padcfg = th1520_padcfg(thp, pin); + unsigned int shift = th1520_padcfg_shift(pin); + u32 tmp; + + mask <<= shift; + value <<= shift; + + scoped_guard(raw_spinlock_irqsave, &thp->lock) { + tmp = readl_relaxed(padcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, padcfg); + } + return 0; +} + +static int th1520_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + const struct pin_desc *desc = pin_desc_get(pctldev, pin); + bool enabled; + int param; + u32 value; + u32 arg; + + if (th1520_pad_no_padcfg(desc->drv_data)) + return -ENOTSUPP; + + value = readl_relaxed(th1520_padcfg(thp, pin)); + value = (value >> th1520_padcfg_shift(pin)) & GENMASK(9, 0); + + param = pinconf_to_config_param(*config); + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + enabled = !(value & (TH1520_PADCFG_SPU | TH1520_PADCFG_PE)); + arg = 0; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + enabled = (value & TH1520_PADCFG_BIAS) == TH1520_PADCFG_PE; + arg = enabled ? TH1520_PULL_DOWN_OHM : 0; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (value & TH1520_PADCFG_SPU) { + enabled = true; + arg = TH1520_PULL_STRONG_OHM; + } else if ((value & (TH1520_PADCFG_PE | TH1520_PADCFG_PS)) == + (TH1520_PADCFG_PE | TH1520_PADCFG_PS)) { + enabled = true; + arg = TH1520_PULL_UP_OHM; + } else { + enabled = false; + arg = 0; + } + break; + case PIN_CONFIG_DRIVE_STRENGTH: + enabled = true; + arg = th1520_drive_strength_in_ma[value & TH1520_PADCFG_DS]; + break; + case PIN_CONFIG_INPUT_ENABLE: + enabled = value & TH1520_PADCFG_IE; + arg = enabled ? 1 : 0; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + enabled = value & TH1520_PADCFG_ST; + arg = enabled ? 1 : 0; + break; + case PIN_CONFIG_SLEW_RATE: + enabled = value & TH1520_PADCFG_SL; + arg = enabled ? 1 : 0; + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return enabled ? 0 : -EINVAL; +} + +static int th1520_pinconf_group_get(struct pinctrl_dev *pctldev, + unsigned int gsel, unsigned long *config) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + unsigned int pin = thp->desc.pins[gsel].number; + + return th1520_pinconf_get(pctldev, pin, config); +} + +static int th1520_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned int num_configs) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + const struct pin_desc *desc = pin_desc_get(pctldev, pin); + unsigned int i; + u16 mask, value; + + if (th1520_pad_no_padcfg(desc->drv_data)) + return -ENOTSUPP; + + mask = 0; + value = 0; + for (i = 0; i < num_configs; i++) { + int param = pinconf_to_config_param(configs[i]); + u32 arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (arg == 0) + return -ENOTSUPP; + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + value |= TH1520_PADCFG_PE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (arg == 0) + return -ENOTSUPP; + mask |= TH1520_PADCFG_BIAS; + value &= ~TH1520_PADCFG_BIAS; + if (arg == TH1520_PULL_STRONG_OHM) + value |= TH1520_PADCFG_SPU; + else + value |= TH1520_PADCFG_PE | TH1520_PADCFG_PS; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + mask |= TH1520_PADCFG_DS; + value &= ~TH1520_PADCFG_DS; + value |= th1520_drive_strength_from_ma(arg); + break; + case PIN_CONFIG_INPUT_ENABLE: + mask |= TH1520_PADCFG_IE; + if (arg) + value |= TH1520_PADCFG_IE; + else + value &= ~TH1520_PADCFG_IE; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + mask |= TH1520_PADCFG_ST; + if (arg) + value |= TH1520_PADCFG_ST; + else + value &= ~TH1520_PADCFG_ST; + break; + case PIN_CONFIG_SLEW_RATE: + mask |= TH1520_PADCFG_SL; + if (arg) + value |= TH1520_PADCFG_SL; + else + value &= ~TH1520_PADCFG_SL; + break; + default: + return -ENOTSUPP; + } + } + + return th1520_padcfg_rmw(thp, pin, mask, value); +} + +static int th1520_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int gsel, + unsigned long *configs, + unsigned int num_configs) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + unsigned int pin = thp->desc.pins[gsel].number; + + return th1520_pinconf_set(pctldev, pin, configs, num_configs); +} + +#ifdef CONFIG_DEBUG_FS +static void th1520_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned int pin) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + u32 value = readl_relaxed(th1520_padcfg(thp, pin)); + + value = (value >> th1520_padcfg_shift(pin)) & GENMASK(9, 0); + + seq_printf(s, " [0x%03x]", value); +} +#else +#define th1520_pinconf_dbg_show NULL +#endif + +static const struct pinconf_ops th1520_pinconf_ops = { + .pin_config_get = th1520_pinconf_get, + .pin_config_group_get = th1520_pinconf_group_get, + .pin_config_set = th1520_pinconf_set, + .pin_config_group_set = th1520_pinconf_group_set, + .pin_config_dbg_show = th1520_pinconf_dbg_show, + .is_generic = true, +}; + +static int th1520_pinmux_set(struct th1520_pinctrl *thp, unsigned int pin, + unsigned long muxdata, enum th1520_muxtype muxtype) +{ + void __iomem *muxcfg = th1520_muxcfg(thp, pin); + unsigned int shift = th1520_muxcfg_shift(pin); + u32 mask, value, tmp; + + for (value = 0; muxdata; muxdata >>= 5, value++) { + if ((muxdata & GENMASK(4, 0)) == muxtype) + break; + } + if (!muxdata) { + dev_err(thp->pctl->dev, "invalid mux %s for pin %s\n", + th1520_muxtype_string[muxtype], pin_get_name(thp->pctl, pin)); + return -EINVAL; + } + + mask = GENMASK(3, 0) << shift; + value = value << shift; + + scoped_guard(raw_spinlock_irqsave, &thp->lock) { + tmp = readl_relaxed(muxcfg); + tmp = (tmp & ~mask) | value; + writel_relaxed(tmp, muxcfg); + } + return 0; +} + +static int th1520_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned int fsel, unsigned int gsel) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + const struct function_desc *func = pinmux_generic_get_function(pctldev, fsel); + enum th1520_muxtype muxtype; + + if (!func) + return -EINVAL; + + muxtype = (uintptr_t)func->data; + return th1520_pinmux_set(thp, thp->desc.pins[gsel].number, + th1520_pad_muxdata(thp->desc.pins[gsel].drv_data), + muxtype); +} + +static int th1520_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + const struct pin_desc *desc = pin_desc_get(pctldev, offset); + + return th1520_pinmux_set(thp, offset, + th1520_pad_muxdata(desc->drv_data), + TH1520_MUX_GPIO); +} + +static int th1520_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct th1520_pinctrl *thp = pinctrl_dev_get_drvdata(pctldev); + + return th1520_padcfg_rmw(thp, offset, TH1520_PADCFG_IE, + input ? TH1520_PADCFG_IE : 0); +} + +static const struct pinmux_ops th1520_pinmux_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = th1520_pinmux_set_mux, + .gpio_request_enable = th1520_gpio_request_enable, + .gpio_set_direction = th1520_gpio_set_direction, + .strict = true, +}; + +static int th1520_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct th1520_pad_group *group; + struct device_node *np = dev->of_node; + struct th1520_pinctrl *thp; + struct clk *clk; + u32 pin_group; + int ret; + + thp = devm_kzalloc(dev, sizeof(*thp), GFP_KERNEL); + if (!thp) + return -ENOMEM; + + thp->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(thp->base)) + return PTR_ERR(thp->base); + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "error getting clock\n"); + + ret = of_property_read_u32(np, "thead,pad-group", &pin_group); + if (ret) + return dev_err_probe(dev, ret, "failed to read the thead,pad-group property\n"); + + if (pin_group == 1) + group = &th1520_group1; + else if (pin_group == 2) + group = &th1520_group2; + else if (pin_group == 3) + group = &th1520_group3; + else + return dev_err_probe(dev, -EINVAL, "unit address did not match any pad group\n"); + + thp->desc.name = group->name; + thp->desc.pins = group->pins; + thp->desc.npins = group->npins; + thp->desc.pctlops = &th1520_pinctrl_ops; + thp->desc.pmxops = &th1520_pinmux_ops; + thp->desc.confops = &th1520_pinconf_ops; + thp->desc.owner = THIS_MODULE; + mutex_init(&thp->mutex); + raw_spin_lock_init(&thp->lock); + + ret = devm_pinctrl_register_and_init(dev, &thp->desc, thp, &thp->pctl); + if (ret) + return dev_err_probe(dev, ret, "could not register pinctrl driver\n"); + + return pinctrl_enable(thp->pctl); +} + +static const struct of_device_id th1520_pinctrl_of_match[] = { + { .compatible = "thead,th1520-pinctrl"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, th1520_pinctrl_of_match); + +static struct platform_driver th1520_pinctrl_driver = { + .probe = th1520_pinctrl_probe, + .driver = { + .name = "pinctrl-th1520", + .of_match_table = th1520_pinctrl_of_match, + }, +}; +module_platform_driver(th1520_pinctrl_driver); + +MODULE_DESCRIPTION("Pinctrl driver for the T-Head TH1520 SoC"); +MODULE_AUTHOR("Emil Renner Berthing "); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index f4256a918165f4..48f8aabf3bfa3a 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -1524,7 +1524,7 @@ static int pinmux_xway_probe(struct platform_device *pdev) * files which don't set the "gpio-ranges" property or systems that * utilize ACPI the driver has to call gpiochip_add_pin_range(). */ - if (!of_property_read_bool(pdev->dev.of_node, "gpio-ranges")) { + if (!of_property_present(pdev->dev.of_node, "gpio-ranges")) { /* finish with registering the gpio range in pinctrl */ xway_gpio_range.npins = xway_chip.ngpio; xway_gpio_range.base = xway_chip.base; diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c index 3c6d56fdb8c964..fddf0fef4b13b8 100644 --- a/drivers/pinctrl/pinctrl-zynqmp.c +++ b/drivers/pinctrl/pinctrl-zynqmp.c @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -44,12 +45,17 @@ #define DRIVE_STRENGTH_8MA 8 #define DRIVE_STRENGTH_12MA 12 +#define VERSAL_LPD_PIN_PREFIX "LPD_MIO" +#define VERSAL_PMC_PIN_PREFIX "PMC_MIO" + +#define VERSAL_PINCTRL_ATTR_NODETYPE_MASK GENMASK(19, 14) +#define VERSAL_PINCTRL_NODETYPE_LPD_MIO BIT(0) + /** * struct zynqmp_pmux_function - a pinmux function * @name: Name of the pin mux function * @groups: List of pin groups for this function * @ngroups: Number of entries in @groups - * @node: Firmware node matching with the function * * This structure holds information about pin control function * and function group names supporting that function. @@ -93,6 +99,8 @@ struct zynqmp_pctrl_group { }; static struct pinctrl_desc zynqmp_desc; +static u32 family_code; +static u32 sub_family_code; static int zynqmp_pctrl_get_groups_count(struct pinctrl_dev *pctldev) { @@ -596,8 +604,12 @@ static int zynqmp_pinctrl_prepare_func_groups(struct device *dev, u32 fid, if (!groups[resp[i]].name) return -ENOMEM; - for (pin = 0; pin < groups[resp[i]].npins; pin++) - __set_bit(groups[resp[i]].pins[pin], used_pins); + for (pin = 0; pin < groups[resp[i]].npins; pin++) { + if (family_code == ZYNQMP_FAMILY_CODE) + __set_bit(groups[resp[i]].pins[pin], used_pins); + else + __set_bit((u8)groups[resp[i]].pins[pin] - 1, used_pins); + } } } done: @@ -873,6 +885,70 @@ static int zynqmp_pinctrl_prepare_pin_desc(struct device *dev, return 0; } +static int versal_pinctrl_get_attributes(u32 pin_idx, u32 *response) +{ + struct zynqmp_pm_query_data qdata = {0}; + u32 payload[PAYLOAD_ARG_CNT]; + int ret; + + qdata.qid = PM_QID_PINCTRL_GET_ATTRIBUTES; + qdata.arg1 = pin_idx; + + ret = zynqmp_pm_query_data(qdata, payload); + if (ret) + return ret; + + memcpy(response, &payload[1], sizeof(*response)); + + return 0; +} + +static int versal_pinctrl_prepare_pin_desc(struct device *dev, + const struct pinctrl_pin_desc **zynqmp_pins, + unsigned int *npins) +{ + u32 lpd_mio_pins = 0, attr, nodetype; + struct pinctrl_pin_desc *pins, *pin; + int ret, i; + + ret = zynqmp_pm_is_function_supported(PM_QUERY_DATA, PM_QID_PINCTRL_GET_ATTRIBUTES); + if (ret) + return ret; + + ret = zynqmp_pinctrl_get_num_pins(npins); + if (ret) + return ret; + + pins = devm_kzalloc(dev, sizeof(*pins) * *npins, GFP_KERNEL); + if (!pins) + return -ENOMEM; + + for (i = 0; i < *npins; i++) { + ret = versal_pinctrl_get_attributes(i, &attr); + if (ret) + return ret; + + pin = &pins[i]; + pin->number = attr; + nodetype = FIELD_GET(VERSAL_PINCTRL_ATTR_NODETYPE_MASK, attr); + if (nodetype == VERSAL_PINCTRL_NODETYPE_LPD_MIO) { + pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", + VERSAL_LPD_PIN_PREFIX, i); + lpd_mio_pins++; + } else { + pin->name = devm_kasprintf(dev, GFP_KERNEL, "%s%d", + VERSAL_PMC_PIN_PREFIX, i - lpd_mio_pins); + } + + if (!pin->name) + return -ENOMEM; + } + + *zynqmp_pins = pins; + + return 0; +} + static int zynqmp_pinctrl_probe(struct platform_device *pdev) { struct zynqmp_pinctrl *pctrl; @@ -882,9 +958,18 @@ static int zynqmp_pinctrl_probe(struct platform_device *pdev) if (!pctrl) return -ENOMEM; - ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev, - &zynqmp_desc.pins, - &zynqmp_desc.npins); + ret = zynqmp_pm_get_family_info(&family_code, &sub_family_code); + if (ret < 0) + return ret; + + if (family_code == ZYNQMP_FAMILY_CODE) { + ret = zynqmp_pinctrl_prepare_pin_desc(&pdev->dev, &zynqmp_desc.pins, + &zynqmp_desc.npins); + } else { + ret = versal_pinctrl_prepare_pin_desc(&pdev->dev, &zynqmp_desc.pins, + &zynqmp_desc.npins); + } + if (ret) { dev_err(&pdev->dev, "pin desc prepare fail with %d\n", ret); return ret; @@ -907,6 +992,7 @@ static int zynqmp_pinctrl_probe(struct platform_device *pdev) static const struct of_device_id zynqmp_pinctrl_of_match[] = { { .compatible = "xlnx,zynqmp-pinctrl" }, + { .compatible = "xlnx,versal-pinctrl" }, { } }; MODULE_DEVICE_TABLE(of, zynqmp_pinctrl_of_match); diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 02033ea1c64384..0743190da59e81 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -93,6 +94,7 @@ bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned int pin) if (!desc || !ops) return true; + guard(mutex)(&desc->mux_lock); if (ops->strict && desc->mux_usecount) return false; @@ -127,29 +129,31 @@ static int pin_request(struct pinctrl_dev *pctldev, dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", pin, desc->name, owner); - if ((!gpio_range || ops->strict) && - desc->mux_usecount && strcmp(desc->mux_owner, owner)) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->mux_owner, owner); - goto out; - } + scoped_guard(mutex, &desc->mux_lock) { + if ((!gpio_range || ops->strict) && + desc->mux_usecount && strcmp(desc->mux_owner, owner)) { + dev_err(pctldev->dev, + "pin %s already requested by %s; cannot claim for %s\n", + desc->name, desc->mux_owner, owner); + goto out; + } - if ((gpio_range || ops->strict) && desc->gpio_owner) { - dev_err(pctldev->dev, - "pin %s already requested by %s; cannot claim for %s\n", - desc->name, desc->gpio_owner, owner); - goto out; - } + if ((gpio_range || ops->strict) && desc->gpio_owner) { + dev_err(pctldev->dev, + "pin %s already requested by %s; cannot claim for %s\n", + desc->name, desc->gpio_owner, owner); + goto out; + } - if (gpio_range) { - desc->gpio_owner = owner; - } else { - desc->mux_usecount++; - if (desc->mux_usecount > 1) - return 0; + if (gpio_range) { + desc->gpio_owner = owner; + } else { + desc->mux_usecount++; + if (desc->mux_usecount > 1) + return 0; - desc->mux_owner = owner; + desc->mux_owner = owner; + } } /* Let each pin increase references to this module */ @@ -178,12 +182,14 @@ static int pin_request(struct pinctrl_dev *pctldev, out_free_pin: if (status) { - if (gpio_range) { - desc->gpio_owner = NULL; - } else { - desc->mux_usecount--; - if (!desc->mux_usecount) - desc->mux_owner = NULL; + scoped_guard(mutex, &desc->mux_lock) { + if (gpio_range) { + desc->gpio_owner = NULL; + } else { + desc->mux_usecount--; + if (!desc->mux_usecount) + desc->mux_owner = NULL; + } } } out: @@ -219,15 +225,17 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin, return NULL; } - if (!gpio_range) { - /* - * A pin should not be freed more times than allocated. - */ - if (WARN_ON(!desc->mux_usecount)) - return NULL; - desc->mux_usecount--; - if (desc->mux_usecount) - return NULL; + scoped_guard(mutex, &desc->mux_lock) { + if (!gpio_range) { + /* + * A pin should not be freed more times than allocated. + */ + if (WARN_ON(!desc->mux_usecount)) + return NULL; + desc->mux_usecount--; + if (desc->mux_usecount) + return NULL; + } } /* @@ -239,13 +247,15 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin, else if (ops->free) ops->free(pctldev, pin); - if (gpio_range) { - owner = desc->gpio_owner; - desc->gpio_owner = NULL; - } else { - owner = desc->mux_owner; - desc->mux_owner = NULL; - desc->mux_setting = NULL; + scoped_guard(mutex, &desc->mux_lock) { + if (gpio_range) { + owner = desc->gpio_owner; + desc->gpio_owner = NULL; + } else { + owner = desc->mux_owner; + desc->mux_owner = NULL; + desc->mux_setting = NULL; + } } module_put(pctldev->owner); @@ -458,7 +468,8 @@ int pinmux_enable_setting(const struct pinctrl_setting *setting) pins[i]); continue; } - desc->mux_setting = &(setting->data.mux); + scoped_guard(mutex, &desc->mux_lock) + desc->mux_setting = &(setting->data.mux); } ret = ops->set_mux(pctldev, setting->data.mux.func, @@ -472,8 +483,10 @@ int pinmux_enable_setting(const struct pinctrl_setting *setting) err_set_mux: for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); - if (desc) - desc->mux_setting = NULL; + if (desc) { + scoped_guard(mutex, &desc->mux_lock) + desc->mux_setting = NULL; + } } err_pin_request: /* On error release all taken pins */ @@ -492,6 +505,7 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting) unsigned int num_pins = 0; int i; struct pin_desc *desc; + bool is_equal; if (pctlops->get_group_pins) ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, @@ -517,7 +531,10 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting) pins[i]); continue; } - if (desc->mux_setting == &(setting->data.mux)) { + scoped_guard(mutex, &desc->mux_lock) + is_equal = (desc->mux_setting == &(setting->data.mux)); + + if (is_equal) { pin_free(pctldev, pins[i], NULL); } else { const char *gname; @@ -608,40 +625,42 @@ static int pinmux_pins_show(struct seq_file *s, void *what) if (desc == NULL) continue; - if (desc->mux_owner && - !strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev))) - is_hog = true; - - if (pmxops->strict) { - if (desc->mux_owner) - seq_printf(s, "pin %d (%s): device %s%s", - pin, desc->name, desc->mux_owner, + scoped_guard(mutex, &desc->mux_lock) { + if (desc->mux_owner && + !strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev))) + is_hog = true; + + if (pmxops->strict) { + if (desc->mux_owner) + seq_printf(s, "pin %d (%s): device %s%s", + pin, desc->name, desc->mux_owner, + is_hog ? " (HOG)" : ""); + else if (desc->gpio_owner) + seq_printf(s, "pin %d (%s): GPIO %s", + pin, desc->name, desc->gpio_owner); + else + seq_printf(s, "pin %d (%s): UNCLAIMED", + pin, desc->name); + } else { + /* For non-strict controllers */ + seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name, + desc->mux_owner ? desc->mux_owner + : "(MUX UNCLAIMED)", + desc->gpio_owner ? desc->gpio_owner + : "(GPIO UNCLAIMED)", is_hog ? " (HOG)" : ""); - else if (desc->gpio_owner) - seq_printf(s, "pin %d (%s): GPIO %s", - pin, desc->name, desc->gpio_owner); + } + + /* If mux: print function+group claiming the pin */ + if (desc->mux_setting) + seq_printf(s, " function %s group %s\n", + pmxops->get_function_name(pctldev, + desc->mux_setting->func), + pctlops->get_group_name(pctldev, + desc->mux_setting->group)); else - seq_printf(s, "pin %d (%s): UNCLAIMED", - pin, desc->name); - } else { - /* For non-strict controllers */ - seq_printf(s, "pin %d (%s): %s %s%s", pin, desc->name, - desc->mux_owner ? desc->mux_owner - : "(MUX UNCLAIMED)", - desc->gpio_owner ? desc->gpio_owner - : "(GPIO UNCLAIMED)", - is_hog ? " (HOG)" : ""); + seq_putc(s, '\n'); } - - /* If mux: print function+group claiming the pin */ - if (desc->mux_setting) - seq_printf(s, " function %s group %s\n", - pmxops->get_function_name(pctldev, - desc->mux_setting->func), - pctlops->get_group_name(pctldev, - desc->mux_setting->group)); - else - seq_putc(s, '\n'); } mutex_unlock(&pctldev->mutex); diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm index 8fe459d082ede6..206226318e4520 100644 --- a/drivers/pinctrl/qcom/Kconfig.msm +++ b/drivers/pinctrl/qcom/Kconfig.msm @@ -46,6 +46,15 @@ config PINCTRL_IPQ5332 Qualcomm Technologies Inc TLMM block found on the Qualcomm Technologies Inc IPQ5332 platform. +config PINCTRL_IPQ5424 + tristate "Qualcomm Technologies, Inc. IPQ5424 pin controller driver" + depends on ARM64 || COMPILE_TEST + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for + the Qualcomm Technologies Inc. TLMM block found on the + Qualcomm Technologies Inc. IPQ5424 platform. Select this for + IPQ5424. + config PINCTRL_IPQ8074 tristate "Qualcomm Technologies, Inc. IPQ8074 pin controller driver" depends on ARM64 || COMPILE_TEST @@ -182,6 +191,20 @@ config PINCTRL_QCS404 This is the pinctrl, pinmux, pinconf and gpiolib driver for the TLMM block found in the Qualcomm QCS404 platform. +config PINCTRL_QCS615 + tristate "Qualcomm Technologies QCS615 pin controller driver" + depends on ARM64 || COMPILE_TEST + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + TLMM block found on the Qualcomm QCS615 platform. + +config PINCTRL_QCS8300 + tristate "Qualcomm Technologies QCS8300 pin controller driver" + depends on ARM64 || COMPILE_TEST + help + This is the pinctrl, pinmux and pinconf driver for the Qualcomm + TLMM block found on the Qualcomm QCS8300 platform. + config PINCTRL_QDF2XXX tristate "Qualcomm Technologies QDF2xxx pin controller driver" depends on ACPI @@ -204,6 +227,14 @@ config PINCTRL_SA8775P This is the pinctrl, pinmux and pinconf driver for the Qualcomm TLMM block found on the Qualcomm SA8775P platforms. +config PINCTRL_SAR2130P + tristate "Qualcomm Technologies Inc SAR2130P pin controller driver" + depends on ARM64 || COMPILE_TEST + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm Technologies Inc TLMM block found on the Qualcomm + Technologies Inc SAR2130P platform. + config PINCTRL_SC7180 tristate "Qualcomm Technologies Inc SC7180 pin controller driver" depends on ARM64 || COMPILE_TEST @@ -382,6 +413,14 @@ config PINCTRL_SM8650 Qualcomm Technologies Inc TLMM block found on the Qualcomm Technologies Inc SM8650 platform. +config PINCTRL_SM8750 + tristate "Qualcomm Technologies Inc SM8750 pin controller driver" + depends on ARM64 || COMPILE_TEST + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm Technologies Inc TLMM block found on the Qualcomm + Technologies Inc SM8750 platform. + config PINCTRL_X1E80100 tristate "Qualcomm Technologies Inc X1E80100 pin controller driver" depends on ARM64 || COMPILE_TEST diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index eb04297b638894..9a23d41d801c42 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_PINCTRL_IPQ4019) += pinctrl-ipq4019.o obj-$(CONFIG_PINCTRL_IPQ5018) += pinctrl-ipq5018.o obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o obj-$(CONFIG_PINCTRL_IPQ5332) += pinctrl-ipq5332.o +obj-$(CONFIG_PINCTRL_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_PINCTRL_IPQ8074) += pinctrl-ipq8074.o obj-$(CONFIG_PINCTRL_IPQ6018) += pinctrl-ipq6018.o obj-$(CONFIG_PINCTRL_IPQ9574) += pinctrl-ipq9574.o @@ -23,6 +24,8 @@ obj-$(CONFIG_PINCTRL_MSM8996) += pinctrl-msm8996.o obj-$(CONFIG_PINCTRL_MSM8998) += pinctrl-msm8998.o obj-$(CONFIG_PINCTRL_QCM2290) += pinctrl-qcm2290.o obj-$(CONFIG_PINCTRL_QCS404) += pinctrl-qcs404.o +obj-$(CONFIG_PINCTRL_QCS615) += pinctrl-qcs615.o +obj-$(CONFIG_PINCTRL_QCS8300) += pinctrl-qcs8300.o obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o obj-$(CONFIG_PINCTRL_MDM9607) += pinctrl-mdm9607.o obj-$(CONFIG_PINCTRL_MDM9615) += pinctrl-mdm9615.o @@ -32,6 +35,7 @@ obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o obj-$(CONFIG_PINCTRL_QDU1000) += pinctrl-qdu1000.o obj-$(CONFIG_PINCTRL_SA8775P) += pinctrl-sa8775p.o +obj-$(CONFIG_PINCTRL_SAR2130P) += pinctrl-sar2130p.o obj-$(CONFIG_PINCTRL_SC7180) += pinctrl-sc7180.o obj-$(CONFIG_PINCTRL_SC7280) += pinctrl-sc7280.o obj-$(CONFIG_PINCTRL_SC7280_LPASS_LPI) += pinctrl-sc7280-lpass-lpi.o @@ -62,6 +66,7 @@ obj-$(CONFIG_PINCTRL_SM8550) += pinctrl-sm8550.o obj-$(CONFIG_PINCTRL_SM8550_LPASS_LPI) += pinctrl-sm8550-lpass-lpi.o obj-$(CONFIG_PINCTRL_SM8650) += pinctrl-sm8650.o obj-$(CONFIG_PINCTRL_SM8650_LPASS_LPI) += pinctrl-sm8650-lpass-lpi.o +obj-$(CONFIG_PINCTRL_SM8750) += pinctrl-sm8750.o obj-$(CONFIG_PINCTRL_SC8280XP_LPASS_LPI) += pinctrl-sc8280xp-lpass-lpi.o obj-$(CONFIG_PINCTRL_LPASS_LPI) += pinctrl-lpass-lpi.o obj-$(CONFIG_PINCTRL_X1E80100) += pinctrl-x1e80100.o diff --git a/drivers/pinctrl/qcom/pinctrl-apq8064.c b/drivers/pinctrl/qcom/pinctrl-apq8064.c index a18df416229993..20c3b902504451 100644 --- a/drivers/pinctrl/qcom/pinctrl-apq8064.c +++ b/drivers/pinctrl/qcom/pinctrl-apq8064.c @@ -629,7 +629,7 @@ static struct platform_driver apq8064_pinctrl_driver = { .of_match_table = apq8064_pinctrl_of_match, }, .probe = apq8064_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init apq8064_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-apq8084.c b/drivers/pinctrl/qcom/pinctrl-apq8084.c index afada80e52a235..3fc0a40762b631 100644 --- a/drivers/pinctrl/qcom/pinctrl-apq8084.c +++ b/drivers/pinctrl/qcom/pinctrl-apq8084.c @@ -1207,7 +1207,7 @@ static struct platform_driver apq8084_pinctrl_driver = { .of_match_table = apq8084_pinctrl_of_match, }, .probe = apq8084_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init apq8084_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq4019.c b/drivers/pinctrl/qcom/pinctrl-ipq4019.c index cb13576ad6cfb4..1f7944dd829d1b 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq4019.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq4019.c @@ -710,7 +710,7 @@ static struct platform_driver ipq4019_pinctrl_driver = { .of_match_table = ipq4019_pinctrl_of_match, }, .probe = ipq4019_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init ipq4019_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5018.c b/drivers/pinctrl/qcom/pinctrl-ipq5018.c index 68f65b57003e91..e2951f81c3eeb3 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c @@ -754,7 +754,7 @@ static struct platform_driver ipq5018_pinctrl_driver = { .of_match_table = ipq5018_pinctrl_of_match, }, .probe = ipq5018_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init ipq5018_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5332.c b/drivers/pinctrl/qcom/pinctrl-ipq5332.c index 88217511897088..625f8014051f6a 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5332.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5332.c @@ -834,7 +834,7 @@ static struct platform_driver ipq5332_pinctrl_driver = { .of_match_table = ipq5332_pinctrl_of_match, }, .probe = ipq5332_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init ipq5332_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5424.c b/drivers/pinctrl/qcom/pinctrl-ipq5424.c new file mode 100644 index 00000000000000..796299cd2e4ed3 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ipq5424.c @@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016-2018,2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include + +#include "pinctrl-msm.h" + +#define REG_SIZE 0x1000 +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + { \ + .grp = PINCTRL_PINGROUP("gpio" #id, \ + gpio##id##_pins, \ + 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 ipq5424_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"), +}; + +#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); + +enum ipq5424_functions { + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_atest_tic, + msm_mux_audio_pri, + msm_mux_audio_pri0, + msm_mux_audio_pri1, + msm_mux_audio_sec, + msm_mux_audio_sec0, + msm_mux_audio_sec1, + msm_mux_core_voltage, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_cri_trng2, + msm_mux_cri_trng3, + msm_mux_cxc_clk, + msm_mux_cxc_data, + msm_mux_dbg_out, + msm_mux_gcc_plltest, + msm_mux_gcc_tlmm, + msm_mux_gpio, + msm_mux_i2c0_scl, + msm_mux_i2c0_sda, + msm_mux_i2c1_scl, + msm_mux_i2c1_sda, + msm_mux_i2c11, + msm_mux_mac0, + msm_mux_mac1, + msm_mux_mdc_mst, + msm_mux_mdc_slv, + msm_mux_mdio_mst, + msm_mux_mdio_slv, + 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_pll_test, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_PTA0_0, + msm_mux_PTA0_1, + msm_mux_PTA0_2, + msm_mux_PTA10, + msm_mux_PTA11, + msm_mux_pwm0, + msm_mux_pwm1, + msm_mux_pwm2, + msm_mux_qdss_cti_trig_in_a0, + msm_mux_qdss_cti_trig_out_a0, + msm_mux_qdss_cti_trig_in_a1, + msm_mux_qdss_cti_trig_out_a1, + msm_mux_qdss_cti_trig_in_b0, + msm_mux_qdss_cti_trig_out_b0, + msm_mux_qdss_cti_trig_in_b1, + msm_mux_qdss_cti_trig_out_b1, + msm_mux_qdss_traceclk_a, + msm_mux_qdss_tracectl_a, + msm_mux_qdss_tracedata_a, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qspi_data, + msm_mux_resout, + msm_mux_rx0, + msm_mux_rx1, + msm_mux_rx2, + msm_mux_sdc_clk, + msm_mux_sdc_cmd, + msm_mux_sdc_data, + msm_mux_spi0, + msm_mux_spi1, + msm_mux_spi10, + msm_mux_spi11, + msm_mux_tsens_max, + msm_mux_uart0, + msm_mux_uart1, + msm_mux_wci_txd, + msm_mux_wci_rxd, + msm_mux_wsi_clk, + msm_mux_wsi_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", +}; + +static const char * const sdc_data_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; + +static const char * const qspi_data_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; + +static const char * const pwm2_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; + +static const char * const wci_txd_groups[] = { + "gpio0", "gpio1", "gpio8", "gpio10", "gpio11", "gpio40", "gpio41", +}; + +static const char * const wci_rxd_groups[] = { + "gpio0", "gpio1", "gpio8", "gpio10", "gpio11", "gpio40", "gpio41", +}; + +static const char * const sdc_cmd_groups[] = { + "gpio4", +}; + +static const char * const qspi_cs_groups[] = { + "gpio4", +}; + +static const char * const qdss_cti_trig_out_a1_groups[] = { + "gpio27", +}; + +static const char * const sdc_clk_groups[] = { + "gpio5", +}; + +static const char * const qspi_clk_groups[] = { + "gpio5", +}; + +static const char * const spi0_groups[] = { + "gpio6", "gpio7", "gpio8", "gpio9", +}; + +static const char * const pwm1_groups[] = { + "gpio6", "gpio7", "gpio8", "gpio9", +}; + +static const char * const cri_trng0_groups[] = { + "gpio6", +}; + +static const char * const qdss_tracedata_a_groups[] = { + "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", + "gpio13", "gpio14", "gpio15", "gpio20", "gpio21", "gpio36", "gpio37", + "gpio38", "gpio39", +}; + +static const char * const cri_trng1_groups[] = { + "gpio7", +}; + +static const char * const cri_trng2_groups[] = { + "gpio8", +}; + +static const char * const cri_trng3_groups[] = { + "gpio9", +}; + +static const char * const uart0_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio13", +}; + +static const char * const pwm0_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio13", +}; + +static const char * const prng_rosc0_groups[] = { + "gpio12", +}; + +static const char * const prng_rosc1_groups[] = { + "gpio13", +}; + +static const char * const i2c0_scl_groups[] = { + "gpio14", +}; + +static const char * const tsens_max_groups[] = { + "gpio14", +}; + +static const char * const prng_rosc2_groups[] = { + "gpio14", +}; + +static const char * const i2c0_sda_groups[] = { + "gpio15", +}; + +static const char * const prng_rosc3_groups[] = { + "gpio15", +}; + +static const char * const core_voltage_groups[] = { + "gpio16", "gpio17", +}; + +static const char * const i2c1_scl_groups[] = { + "gpio16", +}; + +static const char * const i2c1_sda_groups[] = { + "gpio17", +}; + +static const char * const mdc_slv_groups[] = { + "gpio20", +}; + +static const char * const atest_char0_groups[] = { + "gpio20", +}; + +static const char * const mdio_slv_groups[] = { + "gpio21", +}; + +static const char * const atest_char1_groups[] = { + "gpio21", +}; + +static const char * const mdc_mst_groups[] = { + "gpio22", +}; + +static const char * const atest_char2_groups[] = { + "gpio22", +}; + +static const char * const mdio_mst_groups[] = { + "gpio23", +}; + +static const char * const atest_char3_groups[] = { + "gpio23", +}; + +static const char * const pcie0_clk_groups[] = { + "gpio24", +}; + +static const char * const PTA10_groups[] = { + "gpio24", "gpio26", "gpio27", +}; + +static const char * const mac0_groups[] = { + "gpio24", "gpio26", +}; + +static const char * const atest_char_groups[] = { + "gpio24", +}; + +static const char * const pcie0_wake_groups[] = { + "gpio26", +}; + +static const char * const pcie1_clk_groups[] = { + "gpio27", +}; + +static const char * const i2c11_groups[] = { + "gpio27", "gpio29", +}; + +static const char * const pcie1_wake_groups[] = { + "gpio29", +}; + +static const char * const pcie2_clk_groups[] = { + "gpio30", +}; + +static const char * const mac1_groups[] = { + "gpio30", "gpio32", +}; + +static const char * const pcie2_wake_groups[] = { + "gpio32", +}; + +static const char * const PTA11_groups[] = { + "gpio30", "gpio32", "gpio33", +}; + +static const char * const audio_pri0_groups[] = { + "gpio32", "gpio32", +}; + +static const char * const pcie3_clk_groups[] = { + "gpio33", +}; + +static const char * const audio_pri1_groups[] = { + "gpio33", "gpio33", +}; + +static const char * const pcie3_wake_groups[] = { + "gpio35", +}; + +static const char * const audio_sec1_groups[] = { + "gpio35", "gpio35", +}; + +static const char * const audio_pri_groups[] = { + "gpio36", "gpio37", "gpio38", "gpio39", +}; + +static const char * const spi1_groups[] = { + "gpio11", "gpio36", "gpio37", "gpio38", "gpio46", +}; + +static const char * const audio_sec0_groups[] = { + "gpio36", "gpio36", +}; + +static const char * const rx1_groups[] = { + "gpio38", "gpio46", +}; + +static const char * const pll_test_groups[] = { + "gpio38", +}; + +static const char * const dbg_out_groups[] = { + "gpio46", +}; + +static const char * const PTA0_0_groups[] = { + "gpio40", +}; + +static const char * const atest_tic_groups[] = { + "gpio40", +}; + +static const char * const PTA0_1_groups[] = { + "gpio41", +}; + +static const char * const cxc_data_groups[] = { + "gpio41", +}; + +static const char * const PTA0_2_groups[] = { + "gpio42", +}; + +static const char * const cxc_clk_groups[] = { + "gpio42", +}; + +static const char * const uart1_groups[] = { + "gpio43", "gpio44", +}; + +static const char * const audio_sec_groups[] = { + "gpio45", "gpio46", "gpio47", "gpio48", +}; + +static const char * const gcc_plltest_groups[] = { + "gpio43", "gpio45", +}; + +static const char * const gcc_tlmm_groups[] = { + "gpio44", +}; + +static const char * const qdss_cti_trig_out_b1_groups[] = { + "gpio33", +}; + +static const char * const rx0_groups[] = { + "gpio39", "gpio47", +}; + +static const char * const qdss_traceclk_a_groups[] = { + "gpio45", +}; + +static const char * const qdss_tracectl_a_groups[] = { + "gpio46", +}; + +static const char * const qdss_cti_trig_out_a0_groups[] = { + "gpio24", +}; + +static const char * const qdss_cti_trig_in_a0_groups[] = { + "gpio26", +}; + +static const char * const resout_groups[] = { + "gpio49", +}; + +static const char * const qdss_cti_trig_in_a1_groups[] = { + "gpio29", +}; + +static const char * const qdss_cti_trig_out_b0_groups[] = { + "gpio30", +}; + +static const char * const qdss_cti_trig_in_b0_groups[] = { + "gpio32", +}; + +static const char * const qdss_cti_trig_in_b1_groups[] = { + "gpio35", +}; + +static const char * const spi10_groups[] = { + "gpio45", "gpio47", "gpio48", +}; + +static const char * const spi11_groups[] = { + "gpio10", "gpio12", "gpio13", +}; + +static const char * const wsi_clk_groups[] = { + "gpio24", "gpio27", +}; + +static const char * const wsi_data_groups[] = { + "gpio26", "gpio29", +}; + +static const char * const rx2_groups[] = { + "gpio37", "gpio45", +}; + +static const struct pinfunction ipq5424_functions[] = { + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_char0), + MSM_PIN_FUNCTION(atest_char1), + MSM_PIN_FUNCTION(atest_char2), + MSM_PIN_FUNCTION(atest_char3), + MSM_PIN_FUNCTION(atest_tic), + MSM_PIN_FUNCTION(audio_pri), + MSM_PIN_FUNCTION(audio_pri0), + MSM_PIN_FUNCTION(audio_pri1), + MSM_PIN_FUNCTION(audio_sec), + MSM_PIN_FUNCTION(audio_sec0), + MSM_PIN_FUNCTION(audio_sec1), + MSM_PIN_FUNCTION(core_voltage), + MSM_PIN_FUNCTION(cri_trng0), + MSM_PIN_FUNCTION(cri_trng1), + MSM_PIN_FUNCTION(cri_trng2), + MSM_PIN_FUNCTION(cri_trng3), + MSM_PIN_FUNCTION(cxc_clk), + MSM_PIN_FUNCTION(cxc_data), + MSM_PIN_FUNCTION(dbg_out), + MSM_PIN_FUNCTION(gcc_plltest), + MSM_PIN_FUNCTION(gcc_tlmm), + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(i2c0_scl), + MSM_PIN_FUNCTION(i2c0_sda), + MSM_PIN_FUNCTION(i2c1_scl), + MSM_PIN_FUNCTION(i2c1_sda), + MSM_PIN_FUNCTION(i2c11), + MSM_PIN_FUNCTION(mac0), + MSM_PIN_FUNCTION(mac1), + MSM_PIN_FUNCTION(mdc_mst), + MSM_PIN_FUNCTION(mdc_slv), + MSM_PIN_FUNCTION(mdio_mst), + MSM_PIN_FUNCTION(mdio_slv), + MSM_PIN_FUNCTION(pcie0_clk), + MSM_PIN_FUNCTION(pcie0_wake), + MSM_PIN_FUNCTION(pcie1_clk), + MSM_PIN_FUNCTION(pcie1_wake), + MSM_PIN_FUNCTION(pcie2_clk), + MSM_PIN_FUNCTION(pcie2_wake), + MSM_PIN_FUNCTION(pcie3_clk), + MSM_PIN_FUNCTION(pcie3_wake), + MSM_PIN_FUNCTION(pll_test), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(PTA0_0), + MSM_PIN_FUNCTION(PTA0_1), + MSM_PIN_FUNCTION(PTA0_2), + MSM_PIN_FUNCTION(PTA10), + MSM_PIN_FUNCTION(PTA11), + MSM_PIN_FUNCTION(pwm0), + MSM_PIN_FUNCTION(pwm1), + MSM_PIN_FUNCTION(pwm2), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_a1), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b0), + MSM_PIN_FUNCTION(qdss_cti_trig_in_b1), + MSM_PIN_FUNCTION(qdss_cti_trig_out_b1), + MSM_PIN_FUNCTION(qdss_traceclk_a), + MSM_PIN_FUNCTION(qdss_tracectl_a), + MSM_PIN_FUNCTION(qdss_tracedata_a), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs), + MSM_PIN_FUNCTION(qspi_data), + MSM_PIN_FUNCTION(resout), + MSM_PIN_FUNCTION(rx0), + MSM_PIN_FUNCTION(rx1), + MSM_PIN_FUNCTION(rx2), + MSM_PIN_FUNCTION(sdc_clk), + MSM_PIN_FUNCTION(sdc_cmd), + MSM_PIN_FUNCTION(sdc_data), + MSM_PIN_FUNCTION(spi0), + MSM_PIN_FUNCTION(spi1), + MSM_PIN_FUNCTION(spi10), + MSM_PIN_FUNCTION(spi11), + MSM_PIN_FUNCTION(tsens_max), + MSM_PIN_FUNCTION(uart0), + MSM_PIN_FUNCTION(uart1), + MSM_PIN_FUNCTION(wci_txd), + MSM_PIN_FUNCTION(wci_rxd), + MSM_PIN_FUNCTION(wsi_clk), + MSM_PIN_FUNCTION(wsi_data), +}; + +static const struct msm_pingroup ipq5424_groups[] = { + PINGROUP(0, sdc_data, qspi_data, pwm2, wci_txd, wci_rxd, _, _, _, _), + PINGROUP(1, sdc_data, qspi_data, pwm2, wci_txd, wci_rxd, _, _, _, _), + PINGROUP(2, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(3, sdc_data, qspi_data, pwm2, _, _, _, _, _, _), + PINGROUP(4, sdc_cmd, qspi_cs, _, _, _, _, _, _, _), + PINGROUP(5, sdc_clk, qspi_clk, _, _, _, _, _, _, _), + PINGROUP(6, spi0, pwm1, _, cri_trng0, qdss_tracedata_a, _, _, _, _), + PINGROUP(7, spi0, pwm1, _, cri_trng1, qdss_tracedata_a, _, _, _, _), + PINGROUP(8, spi0, pwm1, wci_txd, wci_rxd, _, cri_trng2, qdss_tracedata_a, _, _), + PINGROUP(9, spi0, pwm1, _, cri_trng3, qdss_tracedata_a, _, _, _, _), + PINGROUP(10, uart0, pwm0, spi11, _, wci_txd, wci_rxd, _, qdss_tracedata_a, _), + PINGROUP(11, uart0, pwm0, spi1, _, wci_txd, wci_rxd, _, qdss_tracedata_a, _), + PINGROUP(12, uart0, pwm0, spi11, _, prng_rosc0, qdss_tracedata_a, _, _, _), + PINGROUP(13, uart0, pwm0, spi11, _, prng_rosc1, qdss_tracedata_a, _, _, _), + PINGROUP(14, i2c0_scl, tsens_max, _, prng_rosc2, qdss_tracedata_a, _, _, _, _), + PINGROUP(15, i2c0_sda, _, prng_rosc3, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(16, core_voltage, i2c1_scl, _, _, _, _, _, _, _), + PINGROUP(17, core_voltage, i2c1_sda, _, _, _, _, _, _, _), + PINGROUP(18, _, _, _, _, _, _, _, _, _), + PINGROUP(19, _, _, _, _, _, _, _, _, _), + PINGROUP(20, mdc_slv, atest_char0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(21, mdio_slv, atest_char1, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(22, mdc_mst, atest_char2, _, _, _, _, _, _, _), + PINGROUP(23, mdio_mst, atest_char3, _, _, _, _, _, _, _), + PINGROUP(24, pcie0_clk, PTA10, mac0, _, wsi_clk, _, atest_char, qdss_cti_trig_out_a0, _), + PINGROUP(25, _, _, _, _, _, _, _, _, _), + PINGROUP(26, pcie0_wake, PTA10, mac0, _, wsi_data, _, qdss_cti_trig_in_a0, _, _), + PINGROUP(27, pcie1_clk, i2c11, PTA10, wsi_clk, qdss_cti_trig_out_a1, _, _, _, _), + PINGROUP(28, _, _, _, _, _, _, _, _, _), + PINGROUP(29, pcie1_wake, i2c11, wsi_data, qdss_cti_trig_in_a1, _, _, _, _, _), + PINGROUP(30, pcie2_clk, PTA11, mac1, qdss_cti_trig_out_b0, _, _, _, _, _), + PINGROUP(31, _, _, _, _, _, _, _, _, _), + PINGROUP(32, pcie2_wake, PTA11, mac1, audio_pri0, audio_pri0, qdss_cti_trig_in_b0, _, _, _), + PINGROUP(33, pcie3_clk, PTA11, audio_pri1, audio_pri1, qdss_cti_trig_out_b1, _, _, _, _), + PINGROUP(34, _, _, _, _, _, _, _, _, _), + PINGROUP(35, pcie3_wake, audio_sec1, audio_sec1, qdss_cti_trig_in_b1, _, _, _, _, _), + PINGROUP(36, audio_pri, spi1, audio_sec0, audio_sec0, qdss_tracedata_a, _, _, _, _), + PINGROUP(37, audio_pri, spi1, rx2, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(38, audio_pri, spi1, pll_test, rx1, qdss_tracedata_a, _, _, _, _), + PINGROUP(39, audio_pri, rx0, _, qdss_tracedata_a, _, _, _, _, _), + PINGROUP(40, PTA0_0, wci_txd, wci_rxd, _, atest_tic, _, _, _, _), + PINGROUP(41, PTA0_1, wci_txd, wci_rxd, cxc_data, _, _, _, _, _), + PINGROUP(42, PTA0_2, cxc_clk, _, _, _, _, _, _, _), + PINGROUP(43, uart1, gcc_plltest, _, _, _, _, _, _, _), + PINGROUP(44, uart1, gcc_tlmm, _, _, _, _, _, _, _), + PINGROUP(45, spi10, rx2, audio_sec, gcc_plltest, _, qdss_traceclk_a, _, _, _), + PINGROUP(46, spi1, rx1, audio_sec, dbg_out, qdss_tracectl_a, _, _, _, _), + PINGROUP(47, spi10, rx0, audio_sec, _, _, _, _, _, _), + PINGROUP(48, spi10, audio_sec, _, _, _, _, _, _, _), + PINGROUP(49, resout, _, _, _, _, _, _, _, _), +}; + +static const struct msm_pinctrl_soc_data ipq5424_pinctrl = { + .pins = ipq5424_pins, + .npins = ARRAY_SIZE(ipq5424_pins), + .functions = ipq5424_functions, + .nfunctions = ARRAY_SIZE(ipq5424_functions), + .groups = ipq5424_groups, + .ngroups = ARRAY_SIZE(ipq5424_groups), + .ngpios = 50, +}; + +static int ipq5424_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &ipq5424_pinctrl); +} + +static const struct of_device_id ipq5424_pinctrl_of_match[] = { + { .compatible = "qcom,ipq5424-tlmm", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ipq5424_pinctrl_of_match); + +static struct platform_driver ipq5424_pinctrl_driver = { + .driver = { + .name = "ipq5424-tlmm", + .of_match_table = ipq5424_pinctrl_of_match, + }, + .probe = ipq5424_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init ipq5424_pinctrl_init(void) +{ + return platform_driver_register(&ipq5424_pinctrl_driver); +} +arch_initcall(ipq5424_pinctrl_init); + +static void __exit ipq5424_pinctrl_exit(void) +{ + platform_driver_unregister(&ipq5424_pinctrl_driver); +} +module_exit(ipq5424_pinctrl_exit); + +MODULE_DESCRIPTION("QTI IPQ5424 TLMM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/qcom/pinctrl-ipq6018.c b/drivers/pinctrl/qcom/pinctrl-ipq6018.c index ac330d8712b5cb..0ad08647dbcdf0 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq6018.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq6018.c @@ -1080,7 +1080,7 @@ static struct platform_driver ipq6018_pinctrl_driver = { .of_match_table = ipq6018_pinctrl_of_match, }, .probe = ipq6018_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init ipq6018_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8064.c b/drivers/pinctrl/qcom/pinctrl-ipq8064.c index e10e1bc4c91131..e2bb94e86aef6e 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq8064.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq8064.c @@ -631,7 +631,7 @@ static struct platform_driver ipq8064_pinctrl_driver = { .of_match_table = ipq8064_pinctrl_of_match, }, .probe = ipq8064_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init ipq8064_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq8074.c b/drivers/pinctrl/qcom/pinctrl-ipq8074.c index fee32c1d1d3e9a..337f3a1c92c192 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq8074.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq8074.c @@ -1041,7 +1041,7 @@ static struct platform_driver ipq8074_pinctrl_driver = { .of_match_table = ipq8074_pinctrl_of_match, }, .probe = ipq8074_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init ipq8074_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-ipq9574.c b/drivers/pinctrl/qcom/pinctrl-ipq9574.c index 20ab59cb621bc3..e2491617b2364a 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq9574.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq9574.c @@ -799,7 +799,7 @@ static struct platform_driver ipq9574_pinctrl_driver = { .of_match_table = ipq9574_pinctrl_of_match, }, .probe = ipq9574_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init ipq9574_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9607.c b/drivers/pinctrl/qcom/pinctrl-mdm9607.c index 415d24e16267d0..e7cd3ef1cf3e81 100644 --- a/drivers/pinctrl/qcom/pinctrl-mdm9607.c +++ b/drivers/pinctrl/qcom/pinctrl-mdm9607.c @@ -1059,7 +1059,7 @@ static struct platform_driver mdm9607_pinctrl_driver = { .of_match_table = mdm9607_pinctrl_of_match, }, .probe = mdm9607_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init mdm9607_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-mdm9615.c b/drivers/pinctrl/qcom/pinctrl-mdm9615.c index 3f2eafea0b2467..0a2ae383d3d57b 100644 --- a/drivers/pinctrl/qcom/pinctrl-mdm9615.c +++ b/drivers/pinctrl/qcom/pinctrl-mdm9615.c @@ -446,7 +446,7 @@ static struct platform_driver mdm9615_pinctrl_driver = { .of_match_table = mdm9615_pinctrl_of_match, }, .probe = mdm9615_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init mdm9615_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index aeaf0d1958f56a..ec913c2e200f5f 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -1457,7 +1457,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) * files which don't set the "gpio-ranges" property or systems that * utilize ACPI the driver has to call gpiochip_add_pin_range(). */ - if (!of_property_read_bool(pctrl->dev->of_node, "gpio-ranges")) { + if (!of_property_present(pctrl->dev->of_node, "gpio-ranges")) { ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio); if (ret) { diff --git a/drivers/pinctrl/qcom/pinctrl-msm8226.c b/drivers/pinctrl/qcom/pinctrl-msm8226.c index 40806c0650ef25..64fee70f1772c4 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8226.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8226.c @@ -654,7 +654,7 @@ static struct platform_driver msm8226_pinctrl_driver = { .of_match_table = msm8226_pinctrl_of_match, }, .probe = msm8226_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8226_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8660.c b/drivers/pinctrl/qcom/pinctrl-msm8660.c index dba6d531b4a146..999a5f867eb508 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8660.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8660.c @@ -981,7 +981,7 @@ static struct platform_driver msm8660_pinctrl_driver = { .of_match_table = msm8660_pinctrl_of_match, }, .probe = msm8660_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8660_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8909.c b/drivers/pinctrl/qcom/pinctrl-msm8909.c index 14b17ba9f9061a..756856d20d6b5f 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8909.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8909.c @@ -929,7 +929,7 @@ static struct platform_driver msm8909_pinctrl_driver = { .of_match_table = msm8909_pinctrl_of_match, }, .probe = msm8909_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8909_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8916.c b/drivers/pinctrl/qcom/pinctrl-msm8916.c index 184dcf8422735b..cea5c54f92fec1 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8916.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8916.c @@ -969,7 +969,7 @@ static struct platform_driver msm8916_pinctrl_driver = { .of_match_table = msm8916_pinctrl_of_match, }, .probe = msm8916_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8916_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8953.c b/drivers/pinctrl/qcom/pinctrl-msm8953.c index c2253821ae8d36..998351bdfee136 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8953.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8953.c @@ -1816,7 +1816,7 @@ static struct platform_driver msm8953_pinctrl_driver = { .of_match_table = msm8953_pinctrl_of_match, }, .probe = msm8953_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8953_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8960.c b/drivers/pinctrl/qcom/pinctrl-msm8960.c index 6b9148d226e9b8..ebe230b3b437cc 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8960.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8960.c @@ -1246,7 +1246,7 @@ static struct platform_driver msm8960_pinctrl_driver = { .of_match_table = msm8960_pinctrl_of_match, }, .probe = msm8960_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8960_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8976.c b/drivers/pinctrl/qcom/pinctrl-msm8976.c index 9a951888e8a1b1..c30d80e4e98ca6 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8976.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8976.c @@ -1096,7 +1096,7 @@ static struct platform_driver msm8976_pinctrl_driver = { .of_match_table = msm8976_pinctrl_of_match, }, .probe = msm8976_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8976_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8994.c b/drivers/pinctrl/qcom/pinctrl-msm8994.c index 1ed1dd32d6c795..b1a6759ab4a5e7 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8994.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8994.c @@ -1343,7 +1343,7 @@ static struct platform_driver msm8994_pinctrl_driver = { .of_match_table = msm8994_pinctrl_of_match, }, .probe = msm8994_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8994_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8996.c b/drivers/pinctrl/qcom/pinctrl-msm8996.c index 777c2a74036ed5..1b5d80eaab83c7 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8996.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8996.c @@ -1920,7 +1920,7 @@ static struct platform_driver msm8996_pinctrl_driver = { .of_match_table = msm8996_pinctrl_of_match, }, .probe = msm8996_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8996_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8998.c b/drivers/pinctrl/qcom/pinctrl-msm8998.c index 4aaf45e54f3a79..b7cbf32b3125a9 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8998.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8998.c @@ -1535,7 +1535,7 @@ static struct platform_driver msm8998_pinctrl_driver = { .of_match_table = msm8998_pinctrl_of_match, }, .probe = msm8998_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8998_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-msm8x74.c b/drivers/pinctrl/qcom/pinctrl-msm8x74.c index 750a8272ded7f4..238c83f6ec4f41 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm8x74.c +++ b/drivers/pinctrl/qcom/pinctrl-msm8x74.c @@ -1083,7 +1083,7 @@ static struct platform_driver msm8x74_pinctrl_driver = { .of_match_table = msm8x74_pinctrl_of_match, }, .probe = msm8x74_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init msm8x74_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qcm2290.c b/drivers/pinctrl/qcom/pinctrl-qcm2290.c index f5c1c427b44e91..ba699eac9ee8b2 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcm2290.c +++ b/drivers/pinctrl/qcom/pinctrl-qcm2290.c @@ -1113,7 +1113,7 @@ static struct platform_driver qcm2290_pinctrl_driver = { .of_match_table = qcm2290_pinctrl_of_match, }, .probe = qcm2290_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init qcm2290_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qcs404.c b/drivers/pinctrl/qcom/pinctrl-qcs404.c index 9a875b7dc9989c..ae7224012f8aa0 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcs404.c +++ b/drivers/pinctrl/qcom/pinctrl-qcs404.c @@ -1644,7 +1644,7 @@ static struct platform_driver qcs404_pinctrl_driver = { .of_match_table = qcs404_pinctrl_of_match, }, .probe = qcs404_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init qcs404_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qcs615.c b/drivers/pinctrl/qcom/pinctrl-qcs615.c new file mode 100644 index 00000000000000..23015b055f6a92 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-qcs615.c @@ -0,0 +1,1107 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include + +#include "pinctrl-msm.h" + +enum { + SOUTH, + EAST, + WEST +}; + +static const char * const qcs615_tiles[] = { + [SOUTH] = "south", + [EAST] = "east", + [WEST] = "west" +}; + +#define PINGROUP(id, _tile, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + { \ + .grp = PINCTRL_PINGROUP("gpio" #id, \ + gpio##id##_pins, \ + 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 = 0x1000 * id, \ + .io_reg = 0x1000 * id + 0x4, \ + .intr_cfg_reg = 0x1000 * id + 0x8, \ + .intr_status_reg = 0x1000 * id + 0xc, \ + .intr_target_reg = 0x1000 * id + 0x8, \ + .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, _tile, ctl, pull, drv) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .tile = _tile, \ + .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) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + 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 = WEST, \ + .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 qcs615_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "UFS_RESET"), + PINCTRL_PIN(124, "SDC1_RCLK"), + PINCTRL_PIN(125, "SDC1_CLK"), + PINCTRL_PIN(126, "SDC1_CMD"), + PINCTRL_PIN(127, "SDC1_DATA"), + PINCTRL_PIN(128, "SDC2_CLK"), + PINCTRL_PIN(129, "SDC2_CMD"), + PINCTRL_PIN(130, "SDC2_DATA"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); + +static const unsigned int ufs_reset_pins[] = { 123 }; +static const unsigned int sdc1_rclk_pins[] = { 124 }; +static const unsigned int sdc1_clk_pins[] = { 125 }; +static const unsigned int sdc1_cmd_pins[] = { 126 }; +static const unsigned int sdc1_data_pins[] = { 127 }; +static const unsigned int sdc2_clk_pins[] = { 128 }; +static const unsigned int sdc2_cmd_pins[] = { 129 }; +static const unsigned int sdc2_data_pins[] = { 130 }; + +enum qcs615_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_usb, + msm_mux_cam_mclk, + msm_mux_cci_async, + msm_mux_cci_i2c, + msm_mux_cci_timer, + msm_mux_copy_gp, + msm_mux_copy_phase, + msm_mux_cri_trng, + msm_mux_dbg_out_clk, + msm_mux_ddr_bist, + msm_mux_ddr_pxi, + msm_mux_dp_hot, + msm_mux_edp_hot, + msm_mux_edp_lcd, + msm_mux_emac_gcc, + msm_mux_emac_phy_intr, + msm_mux_forced_usb, + msm_mux_gcc_gp, + msm_mux_gp_pdm, + msm_mux_gps_tx, + msm_mux_hs0_mi2s, + msm_mux_hs1_mi2s, + msm_mux_jitter_bist, + msm_mux_ldo_en, + msm_mux_ldo_update, + msm_mux_m_voc, + msm_mux_mclk1, + msm_mux_mclk2, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0_out, + msm_mux_mdp_vsync1_out, + msm_mux_mdp_vsync2_out, + msm_mux_mdp_vsync3_out, + msm_mux_mdp_vsync4_out, + msm_mux_mdp_vsync5_out, + msm_mux_mi2s_1, + msm_mux_mss_lte, + msm_mux_nav_pps_in, + msm_mux_nav_pps_out, + msm_mux_pa_indicator_or, + msm_mux_pcie_clk_req, + msm_mux_pcie_ep_rst, + msm_mux_phase_flag, + msm_mux_pll_bist, + msm_mux_pll_bypassnl, + msm_mux_pll_reset_n, + msm_mux_prng_rosc, + msm_mux_qdss_cti, + msm_mux_qdss_gpio, + msm_mux_qlink_enable, + msm_mux_qlink_request, + msm_mux_qspi, + msm_mux_qup0, + msm_mux_qup1, + msm_mux_rgmii, + msm_mux_sd_write_protect, + msm_mux_sp_cmu, + msm_mux_ter_mi2s, + msm_mux_tgu_ch, + msm_mux_uim1, + msm_mux_uim2, + msm_mux_usb0_hs, + msm_mux_usb1_hs, + msm_mux_usb_phy_ps, + msm_mux_vfr_1, + msm_mux_vsense_trigger_mirnat, + msm_mux_wlan, + 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", "gpio119", + "gpio120", "gpio121", "gpio122", +}; + +static const char *const adsp_ext_groups[] = { + "gpio118", +}; + +static const char *const agera_pll_groups[] = { + "gpio28", +}; + +static const char *const aoss_cti_groups[] = { + "gpio76", +}; + +static const char *const atest_char_groups[] = { + "gpio84", "gpio85", "gpio86", "gpio87", + "gpio115", "gpio117", "gpio118", "gpio119", + "gpio120", "gpio121", +}; + +static const char *const atest_tsens_groups[] = { + "gpio7", "gpio29", +}; + +static const char *const atest_usb_groups[] = { + "gpio7", "gpio10", "gpio11", "gpio54", + "gpio55", "gpio67", "gpio68", "gpio76", + "gpio75", "gpio77", +}; + +static const char *const cam_mclk_groups[] = { + "gpio28", "gpio29", "gpio30", "gpio31", +}; + +static const char *const cci_async_groups[] = { + "gpio26", "gpio41", "gpio42", +}; + +static const char *const cci_i2c_groups[] = { + "gpio32", "gpio33", "gpio34", "gpio35", +}; + +static const char *const cci_timer_groups[] = { + "gpio37", "gpio38", "gpio39", "gpio41", + "gpio42", +}; + +static const char *const copy_gp_groups[] = { + "gpio86", +}; + +static const char *const copy_phase_groups[] = { + "gpio103", +}; + +static const char *const cri_trng_groups[] = { + "gpio60", "gpio61", "gpio62", +}; + +static const char *const dbg_out_clk_groups[] = { + "gpio11", +}; + +static const char *const ddr_bist_groups[] = { + "gpio7", "gpio8", "gpio9", "gpio10", +}; + +static const char *const ddr_pxi_groups[] = { + "gpio6", "gpio7", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio54", "gpio55", +}; + +static const char *const dp_hot_groups[] = { + "gpio102", "gpio103", "gpio104", +}; + +static const char *const edp_hot_groups[] = { + "gpio113", +}; + +static const char *const edp_lcd_groups[] = { + "gpio119", +}; + +static const char *const emac_gcc_groups[] = { + "gpio101", "gpio102", +}; + +static const char *const emac_phy_intr_groups[] = { + "gpio89", +}; + +static const char *const forced_usb_groups[] = { + "gpio43", +}; + +static const char *const gcc_gp_groups[] = { + "gpio21", "gpio22", "gpio57", "gpio58", + "gpio59", "gpio78", +}; + +static const char *const gp_pdm_groups[] = { + "gpio8", "gpio54", "gpio63", "gpio66", + "gpio79", "gpio95", +}; + +static const char *const gps_tx_groups[] = { + "gpio53", "gpio54", "gpio56", "gpio57", + "gpio59", "gpio60", +}; + +static const char *const hs0_mi2s_groups[] = { + "gpio36", "gpio37", "gpio38", "gpio39", +}; + +static const char *const hs1_mi2s_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", +}; + +static const char *const jitter_bist_groups[] = { + "gpio12", "gpio26", +}; + +static const char *const ldo_en_groups[] = { + "gpio97", +}; + +static const char *const ldo_update_groups[] = { + "gpio98", +}; + +static const char *const m_voc_groups[] = { + "gpio120", +}; + +static const char *const mclk1_groups[] = { + "gpio121", +}; + +static const char *const mclk2_groups[] = { + "gpio122", +}; + +static const char *const mdp_vsync_groups[] = { + "gpio81", "gpio82", "gpio83", "gpio90", + "gpio97", "gpio98", +}; + +static const char *const mdp_vsync0_out_groups[] = { + "gpio90", +}; + +static const char *const mdp_vsync1_out_groups[] = { + "gpio90", +}; + +static const char *const mdp_vsync2_out_groups[] = { + "gpio90", +}; + +static const char *const mdp_vsync3_out_groups[] = { + "gpio90", +}; + +static const char *const mdp_vsync4_out_groups[] = { + "gpio90", +}; + +static const char *const mdp_vsync5_out_groups[] = { + "gpio90", +}; + +static const char *const mi2s_1_groups[] = { + "gpio108", "gpio109", "gpio110", "gpio111", +}; + +static const char *const mss_lte_groups[] = { + "gpio106", "gpio107", +}; + +static const char *const nav_pps_in_groups[] = { + "gpio53", "gpio56", "gpio57", "gpio59", + "gpio60", +}; + +static const char *const nav_pps_out_groups[] = { + "gpio53", "gpio56", "gpio57", "gpio59", + "gpio60", +}; + +static const char *const pa_indicator_or_groups[] = { + "gpio53", +}; + +static const char *const pcie_clk_req_groups[] = { + "gpio90", +}; + +static const char *const pcie_ep_rst_groups[] = { + "gpio89", +}; + +static const char *const phase_flag_groups[] = { + "gpio10", "gpio18", "gpio19", "gpio20", + "gpio23", "gpio24", "gpio25", "gpio38", + "gpio40", "gpio41", "gpio42", "gpio43", + "gpio44", "gpio45", "gpio53", "gpio54", + "gpio55", "gpio67", "gpio68", "gpio75", + "gpio76", "gpio77", "gpio78", "gpio79", + "gpio80", "gpio82", "gpio84", "gpio92", + "gpio116", "gpio117", "gpio118", "gpio119", +}; + +static const char *const pll_bist_groups[] = { + "gpio27", +}; + +static const char *const pll_bypassnl_groups[] = { + "gpio13", +}; + +static const char *const pll_reset_n_groups[] = { + "gpio14", +}; + +static const char *const prng_rosc_groups[] = { + "gpio99", "gpio102", +}; + +static const char *const qdss_cti_groups[] = { + "gpio83", "gpio96", "gpio97", "gpio98", + "gpio103", "gpio104", "gpio112", "gpio113", +}; + +static const char *const qdss_gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", + "gpio6", "gpio7", "gpio8", "gpio9", + "gpio14", "gpio15", "gpio20", "gpio21", + "gpio28", "gpio29", "gpio30", "gpio31", + "gpio32", "gpio33", "gpio34", "gpio35", + "gpio44", "gpio45", "gpio46", "gpio47", + "gpio81", "gpio82", "gpio92", "gpio93", + "gpio94", "gpio95", "gpio108", "gpio109", + "gpio117", "gpio118", "gpio119", "gpio120", +}; + +static const char *const qlink_enable_groups[] = { + "gpio52", +}; + +static const char *const qlink_request_groups[] = { + "gpio51", +}; + +static const char *const qspi_groups[] = { + "gpio44", "gpio45", "gpio46", "gpio47", + "gpio48", "gpio49", "gpio50", +}; + +static const char *const qup0_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", + "gpio4", "gpio5", "gpio16", "gpio17", + "gpio18", "gpio19", +}; + +static const char *const qup1_groups[] = { + "gpio6", "gpio7", "gpio8", "gpio9", + "gpio10", "gpio11", "gpio12", "gpio13", + "gpio14", "gpio15", "gpio20", "gpio21", + "gpio22", "gpio23", +}; + +static const char *const rgmii_groups[] = { + "gpio81", "gpio82", "gpio83", "gpio91", + "gpio92", "gpio93", "gpio94", "gpio95", + "gpio96", "gpio97", "gpio102", "gpio103", + "gpio112", "gpio113", "gpio114", +}; + +static const char *const sd_write_protect_groups[] = { + "gpio24", +}; + +static const char *const sp_cmu_groups[] = { + "gpio64", +}; + +static const char *const ter_mi2s_groups[] = { + "gpio115", "gpio116", "gpio117", "gpio118", +}; + +static const char *const tgu_ch_groups[] = { + "gpio89", "gpio90", "gpio91", "gpio92", +}; + +static const char *const uim1_groups[] = { + "gpio77", "gpio78", "gpio79", "gpio80", +}; + +static const char *const uim2_groups[] = { + "gpio73", "gpio74", "gpio75", "gpio76", +}; + +static const char *const usb0_hs_groups[] = { + "gpio88", +}; + +static const char *const usb1_hs_groups[] = { + "gpio89", +}; + +static const char *const usb_phy_ps_groups[] = { + "gpio104", +}; + +static const char *const vfr_1_groups[] = { + "gpio92", +}; + +static const char *const vsense_trigger_mirnat_groups[] = { + "gpio7", +}; + +static const char *const wlan_groups[] = { + "gpio16", "gpio17", "gpio47", "gpio48", +}; + +static const char *const wsa_clk_groups[] = { + "gpio111", +}; + +static const char *const wsa_data_groups[] = { + "gpio110", +}; + +static const struct pinfunction qcs615_functions[] = { + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(adsp_ext), + MSM_PIN_FUNCTION(agera_pll), + MSM_PIN_FUNCTION(aoss_cti), + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_tsens), + MSM_PIN_FUNCTION(atest_usb), + MSM_PIN_FUNCTION(cam_mclk), + MSM_PIN_FUNCTION(cci_async), + MSM_PIN_FUNCTION(cci_i2c), + MSM_PIN_FUNCTION(cci_timer), + MSM_PIN_FUNCTION(copy_gp), + MSM_PIN_FUNCTION(copy_phase), + MSM_PIN_FUNCTION(cri_trng), + MSM_PIN_FUNCTION(dbg_out_clk), + MSM_PIN_FUNCTION(ddr_bist), + MSM_PIN_FUNCTION(ddr_pxi), + MSM_PIN_FUNCTION(dp_hot), + MSM_PIN_FUNCTION(edp_hot), + MSM_PIN_FUNCTION(edp_lcd), + MSM_PIN_FUNCTION(emac_gcc), + MSM_PIN_FUNCTION(emac_phy_intr), + MSM_PIN_FUNCTION(forced_usb), + MSM_PIN_FUNCTION(gcc_gp), + MSM_PIN_FUNCTION(gp_pdm), + MSM_PIN_FUNCTION(gps_tx), + MSM_PIN_FUNCTION(hs0_mi2s), + MSM_PIN_FUNCTION(hs1_mi2s), + MSM_PIN_FUNCTION(jitter_bist), + MSM_PIN_FUNCTION(ldo_en), + MSM_PIN_FUNCTION(ldo_update), + MSM_PIN_FUNCTION(m_voc), + MSM_PIN_FUNCTION(mclk1), + MSM_PIN_FUNCTION(mclk2), + MSM_PIN_FUNCTION(mdp_vsync), + MSM_PIN_FUNCTION(mdp_vsync0_out), + MSM_PIN_FUNCTION(mdp_vsync1_out), + MSM_PIN_FUNCTION(mdp_vsync2_out), + MSM_PIN_FUNCTION(mdp_vsync3_out), + MSM_PIN_FUNCTION(mdp_vsync4_out), + MSM_PIN_FUNCTION(mdp_vsync5_out), + MSM_PIN_FUNCTION(mi2s_1), + MSM_PIN_FUNCTION(mss_lte), + MSM_PIN_FUNCTION(nav_pps_in), + MSM_PIN_FUNCTION(nav_pps_out), + MSM_PIN_FUNCTION(pa_indicator_or), + MSM_PIN_FUNCTION(pcie_clk_req), + MSM_PIN_FUNCTION(pcie_ep_rst), + MSM_PIN_FUNCTION(phase_flag), + MSM_PIN_FUNCTION(pll_bist), + MSM_PIN_FUNCTION(pll_bypassnl), + MSM_PIN_FUNCTION(pll_reset_n), + MSM_PIN_FUNCTION(prng_rosc), + MSM_PIN_FUNCTION(qdss_cti), + MSM_PIN_FUNCTION(qdss_gpio), + MSM_PIN_FUNCTION(qlink_enable), + MSM_PIN_FUNCTION(qlink_request), + MSM_PIN_FUNCTION(qspi), + MSM_PIN_FUNCTION(qup0), + MSM_PIN_FUNCTION(qup1), + MSM_PIN_FUNCTION(rgmii), + MSM_PIN_FUNCTION(sd_write_protect), + MSM_PIN_FUNCTION(sp_cmu), + MSM_PIN_FUNCTION(ter_mi2s), + MSM_PIN_FUNCTION(tgu_ch), + MSM_PIN_FUNCTION(uim1), + MSM_PIN_FUNCTION(uim2), + MSM_PIN_FUNCTION(usb0_hs), + MSM_PIN_FUNCTION(usb1_hs), + MSM_PIN_FUNCTION(usb_phy_ps), + MSM_PIN_FUNCTION(vfr_1), + MSM_PIN_FUNCTION(vsense_trigger_mirnat), + MSM_PIN_FUNCTION(wlan), + MSM_PIN_FUNCTION(wsa_clk), + MSM_PIN_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 qcs615_groups[] = { + [0] = PINGROUP(0, WEST, qup0, _, qdss_gpio, _, _, _, _, _, _), + [1] = PINGROUP(1, WEST, qup0, _, qdss_gpio, _, _, _, _, _, _), + [2] = PINGROUP(2, WEST, qup0, _, qdss_gpio, _, _, _, _, _, _), + [3] = PINGROUP(3, WEST, qup0, _, qdss_gpio, _, _, _, _, _, _), + [4] = PINGROUP(4, WEST, qup0, _, _, _, _, _, _, _, _), + [5] = PINGROUP(5, WEST, qup0, _, _, _, _, _, _, _, _), + [6] = PINGROUP(6, EAST, qup1, qdss_gpio, ddr_pxi, _, _, _, _, _, _), + [7] = PINGROUP(7, EAST, qup1, ddr_bist, qdss_gpio, atest_tsens, + vsense_trigger_mirnat, atest_usb, ddr_pxi, _, _), + [8] = PINGROUP(8, EAST, qup1, gp_pdm, ddr_bist, qdss_gpio, _, _, _, _, _), + [9] = PINGROUP(9, EAST, qup1, ddr_bist, qdss_gpio, _, _, _, _, _, _), + [10] = PINGROUP(10, EAST, qup1, ddr_bist, _, phase_flag, atest_usb, ddr_pxi, _, _, _), + [11] = PINGROUP(11, EAST, qup1, dbg_out_clk, atest_usb, ddr_pxi, _, _, _, _, _), + [12] = PINGROUP(12, EAST, qup1, jitter_bist, ddr_pxi, _, _, _, _, _, _), + [13] = PINGROUP(13, EAST, qup1, pll_bypassnl, _, ddr_pxi, _, _, _, _, _), + [14] = PINGROUP(14, EAST, qup1, pll_reset_n, _, qdss_gpio, _, _, _, _, _), + [15] = PINGROUP(15, EAST, qup1, qdss_gpio, _, _, _, _, _, _, _), + [16] = PINGROUP(16, WEST, qup0, _, wlan, _, _, _, _, _, _), + [17] = PINGROUP(17, WEST, qup0, _, wlan, _, _, _, _, _, _), + [18] = PINGROUP(18, WEST, qup0, _, phase_flag, _, _, _, _, _, _), + [19] = PINGROUP(19, WEST, qup0, _, phase_flag, _, _, _, _, _, _), + [20] = PINGROUP(20, SOUTH, qup1, _, phase_flag, qdss_gpio, _, _, _, _, _), + [21] = PINGROUP(21, SOUTH, qup1, gcc_gp, _, qdss_gpio, _, _, _, _, _), + [22] = PINGROUP(22, SOUTH, qup1, gcc_gp, _, _, _, _, _, _, _), + [23] = PINGROUP(23, SOUTH, qup1, _, phase_flag, _, _, _, _, _, _), + [24] = PINGROUP(24, EAST, hs1_mi2s, sd_write_protect, _, phase_flag, _, _, _, _, _), + [25] = PINGROUP(25, EAST, hs1_mi2s, _, phase_flag, _, _, _, _, _, _), + [26] = PINGROUP(26, EAST, cci_async, hs1_mi2s, jitter_bist, _, _, _, _, _, _), + [27] = PINGROUP(27, EAST, hs1_mi2s, pll_bist, _, _, _, _, _, _, _), + [28] = PINGROUP(28, EAST, cam_mclk, agera_pll, qdss_gpio, _, _, _, _, _, _), + [29] = PINGROUP(29, EAST, cam_mclk, _, qdss_gpio, atest_tsens, _, _, _, _, _), + [30] = PINGROUP(30, EAST, cam_mclk, qdss_gpio, _, _, _, _, _, _, _), + [31] = PINGROUP(31, EAST, cam_mclk, _, qdss_gpio, _, _, _, _, _, _), + [32] = PINGROUP(32, EAST, cci_i2c, _, qdss_gpio, _, _, _, _, _, _), + [33] = PINGROUP(33, EAST, cci_i2c, _, qdss_gpio, _, _, _, _, _, _), + [34] = PINGROUP(34, EAST, cci_i2c, _, qdss_gpio, _, _, _, _, _, _), + [35] = PINGROUP(35, EAST, cci_i2c, _, qdss_gpio, _, _, _, _, _, _), + [36] = PINGROUP(36, EAST, hs0_mi2s, _, _, _, _, _, _, _, _), + [37] = PINGROUP(37, EAST, cci_timer, hs0_mi2s, _, _, _, _, _, _, _), + [38] = PINGROUP(38, EAST, cci_timer, hs0_mi2s, _, phase_flag, _, _, _, _, _), + [39] = PINGROUP(39, EAST, cci_timer, hs0_mi2s, _, _, _, _, _, _, _), + [40] = PINGROUP(40, EAST, _, phase_flag, _, _, _, _, _, _, _), + [41] = PINGROUP(41, EAST, cci_async, cci_timer, _, phase_flag, _, _, _, _, _), + [42] = PINGROUP(42, EAST, cci_async, cci_timer, _, phase_flag, _, _, _, _, _), + [43] = PINGROUP(43, SOUTH, _, phase_flag, forced_usb, _, _, _, _, _, _), + [44] = PINGROUP(44, EAST, qspi, _, phase_flag, qdss_gpio, _, _, _, _, _), + [45] = PINGROUP(45, EAST, qspi, _, phase_flag, qdss_gpio, _, _, _, _, _), + [46] = PINGROUP(46, EAST, qspi, _, qdss_gpio, _, _, _, _, _, _), + [47] = PINGROUP(47, EAST, qspi, _, qdss_gpio, wlan, _, _, _, _, _), + [48] = PINGROUP(48, EAST, qspi, _, wlan, _, _, _, _, _, _), + [49] = PINGROUP(49, EAST, qspi, _, _, _, _, _, _, _, _), + [50] = PINGROUP(50, EAST, qspi, _, _, _, _, _, _, _, _), + [51] = PINGROUP(51, SOUTH, qlink_request, _, _, _, _, _, _, _, _), + [52] = PINGROUP(52, SOUTH, qlink_enable, _, _, _, _, _, _, _, _), + [53] = PINGROUP(53, SOUTH, pa_indicator_or, nav_pps_in, nav_pps_out, gps_tx, _, + phase_flag, _, _, _), + [54] = PINGROUP(54, SOUTH, _, gps_tx, gp_pdm, _, phase_flag, atest_usb, ddr_pxi, _, _), + [55] = PINGROUP(55, SOUTH, _, _, phase_flag, atest_usb, ddr_pxi, _, _, _, _), + [56] = PINGROUP(56, SOUTH, _, nav_pps_in, nav_pps_out, gps_tx, _, _, _, _, _), + [57] = PINGROUP(57, SOUTH, _, nav_pps_in, gps_tx, nav_pps_out, gcc_gp, _, _, _, _), + [58] = PINGROUP(58, SOUTH, _, gcc_gp, _, _, _, _, _, _, _), + [59] = PINGROUP(59, SOUTH, _, nav_pps_in, nav_pps_out, gps_tx, gcc_gp, _, _, _, _), + [60] = PINGROUP(60, SOUTH, _, nav_pps_in, nav_pps_out, gps_tx, cri_trng, _, _, _, _), + [61] = PINGROUP(61, SOUTH, _, cri_trng, _, _, _, _, _, _, _), + [62] = PINGROUP(62, SOUTH, _, cri_trng, _, _, _, _, _, _, _), + [63] = PINGROUP(63, SOUTH, _, _, gp_pdm, _, _, _, _, _, _), + [64] = PINGROUP(64, SOUTH, _, sp_cmu, _, _, _, _, _, _, _), + [65] = PINGROUP(65, SOUTH, _, _, _, _, _, _, _, _, _), + [66] = PINGROUP(66, SOUTH, _, gp_pdm, _, _, _, _, _, _, _), + [67] = PINGROUP(67, SOUTH, _, _, _, phase_flag, atest_usb, _, _, _, _), + [68] = PINGROUP(68, SOUTH, _, _, _, phase_flag, atest_usb, _, _, _, _), + [69] = PINGROUP(69, SOUTH, _, _, _, _, _, _, _, _, _), + [70] = PINGROUP(70, SOUTH, _, _, _, _, _, _, _, _, _), + [71] = PINGROUP(71, SOUTH, _, _, _, _, _, _, _, _, _), + [72] = PINGROUP(72, SOUTH, _, _, _, _, _, _, _, _, _), + [73] = PINGROUP(73, SOUTH, uim2, _, _, _, _, _, _, _, _), + [74] = PINGROUP(74, SOUTH, uim2, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, SOUTH, uim2, _, phase_flag, atest_usb, _, _, _, _, _), + [76] = PINGROUP(76, SOUTH, uim2, _, phase_flag, atest_usb, aoss_cti, _, _, _, _), + [77] = PINGROUP(77, SOUTH, uim1, _, phase_flag, atest_usb, _, _, _, _, _), + [78] = PINGROUP(78, SOUTH, uim1, gcc_gp, _, phase_flag, _, _, _, _, _), + [79] = PINGROUP(79, SOUTH, uim1, gp_pdm, _, phase_flag, _, _, _, _, _), + [80] = PINGROUP(80, SOUTH, uim1, _, phase_flag, _, _, _, _, _, _), + [81] = PINGROUP(81, WEST, rgmii, mdp_vsync, _, qdss_gpio, _, _, _, _, _), + [82] = PINGROUP(82, WEST, rgmii, mdp_vsync, _, phase_flag, qdss_gpio, _, _, _, _), + [83] = PINGROUP(83, WEST, rgmii, mdp_vsync, _, qdss_cti, _, _, _, _, _), + [84] = PINGROUP(84, SOUTH, _, phase_flag, atest_char, _, _, _, _, _, _), + [85] = PINGROUP(85, SOUTH, _, atest_char, _, _, _, _, _, _, _), + [86] = PINGROUP(86, SOUTH, copy_gp, _, atest_char, _, _, _, _, _, _), + [87] = PINGROUP(87, SOUTH, _, atest_char, _, _, _, _, _, _, _), + [88] = PINGROUP(88, WEST, _, usb0_hs, _, _, _, _, _, _, _), + [89] = PINGROUP(89, WEST, emac_phy_intr, pcie_ep_rst, tgu_ch, usb1_hs, _, _, _, _, _), + [90] = PINGROUP(90, WEST, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, + mdp_vsync2_out, mdp_vsync3_out, mdp_vsync4_out, mdp_vsync5_out, + pcie_clk_req, tgu_ch), + [91] = PINGROUP(91, WEST, rgmii, tgu_ch, _, _, _, _, _, _, _), + [92] = PINGROUP(92, WEST, rgmii, vfr_1, tgu_ch, _, phase_flag, qdss_gpio, _, _, _), + [93] = PINGROUP(93, WEST, rgmii, qdss_gpio, _, _, _, _, _, _, _), + [94] = PINGROUP(94, WEST, rgmii, qdss_gpio, _, _, _, _, _, _, _), + [95] = PINGROUP(95, WEST, rgmii, gp_pdm, qdss_gpio, _, _, _, _, _, _), + [96] = PINGROUP(96, WEST, rgmii, qdss_cti, _, _, _, _, _, _, _), + [97] = PINGROUP(97, WEST, rgmii, mdp_vsync, ldo_en, qdss_cti, _, _, _, _, _), + [98] = PINGROUP(98, WEST, mdp_vsync, ldo_update, qdss_cti, _, _, _, _, _, _), + [99] = PINGROUP(99, EAST, prng_rosc, _, _, _, _, _, _, _, _), + [100] = PINGROUP(100, WEST, _, _, _, _, _, _, _, _, _), + [101] = PINGROUP(101, WEST, emac_gcc, _, _, _, _, _, _, _, _), + [102] = PINGROUP(102, WEST, rgmii, dp_hot, emac_gcc, prng_rosc, _, _, _, _, _), + [103] = PINGROUP(103, WEST, rgmii, dp_hot, copy_phase, qdss_cti, _, _, _, _, _), + [104] = PINGROUP(104, WEST, usb_phy_ps, _, qdss_cti, dp_hot, _, _, _, _, _), + [105] = PINGROUP(105, SOUTH, _, _, _, _, _, _, _, _, _), + [106] = PINGROUP(106, EAST, mss_lte, _, _, _, _, _, _, _, _), + [107] = PINGROUP(107, EAST, mss_lte, _, _, _, _, _, _, _, _), + [108] = PINGROUP(108, SOUTH, mi2s_1, _, qdss_gpio, _, _, _, _, _, _), + [109] = PINGROUP(109, SOUTH, mi2s_1, _, qdss_gpio, _, _, _, _, _, _), + [110] = PINGROUP(110, SOUTH, wsa_data, mi2s_1, _, _, _, _, _, _, _), + [111] = PINGROUP(111, SOUTH, wsa_clk, mi2s_1, _, _, _, _, _, _, _), + [112] = PINGROUP(112, WEST, rgmii, _, qdss_cti, _, _, _, _, _, _), + [113] = PINGROUP(113, WEST, rgmii, edp_hot, _, qdss_cti, _, _, _, _, _), + [114] = PINGROUP(114, WEST, rgmii, _, _, _, _, _, _, _, _), + [115] = PINGROUP(115, SOUTH, ter_mi2s, atest_char, _, _, _, _, _, _, _), + [116] = PINGROUP(116, SOUTH, ter_mi2s, _, phase_flag, _, _, _, _, _, _), + [117] = PINGROUP(117, SOUTH, ter_mi2s, _, phase_flag, qdss_gpio, atest_char, _, _, _, _), + [118] = PINGROUP(118, SOUTH, ter_mi2s, adsp_ext, _, phase_flag, qdss_gpio, atest_char, + _, _, _), + [119] = PINGROUP(119, SOUTH, edp_lcd, _, phase_flag, qdss_gpio, atest_char, _, _, _, _), + [120] = PINGROUP(120, SOUTH, m_voc, qdss_gpio, atest_char, _, _, _, _, _, _), + [121] = PINGROUP(121, SOUTH, mclk1, atest_char, _, _, _, _, _, _, _), + [122] = PINGROUP(122, SOUTH, mclk2, _, _, _, _, _, _, _, _), + [123] = UFS_RESET(ufs_reset, 0x9f000), + [124] = SDC_QDSD_PINGROUP(sdc1_rclk, WEST, 0x9a000, 15, 0), + [125] = SDC_QDSD_PINGROUP(sdc1_clk, WEST, 0x9a000, 13, 6), + [126] = SDC_QDSD_PINGROUP(sdc1_cmd, WEST, 0x9a000, 11, 3), + [127] = SDC_QDSD_PINGROUP(sdc1_data, WEST, 0x9a000, 9, 0), + [128] = SDC_QDSD_PINGROUP(sdc2_clk, SOUTH, 0x98000, 14, 6), + [129] = SDC_QDSD_PINGROUP(sdc2_cmd, SOUTH, 0x98000, 11, 3), + [130] = SDC_QDSD_PINGROUP(sdc2_data, SOUTH, 0x98000, 9, 0), +}; + +static const struct msm_gpio_wakeirq_map qcs615_pdc_map[] = { + { 1, 45 }, { 3, 31 }, { 7, 55 }, { 9, 110 }, { 11, 34 }, + { 13, 33 }, { 14, 35 }, { 17, 46 }, { 19, 48 }, { 21, 83 }, + { 22, 36 }, { 26, 38 }, { 35, 37 }, { 39, 125 }, { 41, 47 }, + { 47, 49 }, { 48, 51 }, { 50, 52 }, { 51, 123 }, { 55, 56 }, + { 56, 57 }, { 57, 58 }, { 60, 60 }, { 71, 54 }, { 80, 73 }, + { 81, 64 }, { 82, 50 }, { 83, 65 }, { 84, 92 }, { 85, 99 }, + { 86, 67 }, { 87, 84 }, { 88, 124 }, { 89, 122 }, { 90, 69 }, + { 92, 88 }, { 93, 75 }, { 94, 91 }, { 95, 72 }, { 96, 82 }, + { 97, 74 }, { 98, 95 }, { 99, 94 }, { 100, 100 }, { 101, 40 }, + { 102, 93 }, { 103, 77 }, { 104, 78 }, { 105, 96 }, { 107, 97 }, + { 108, 111 }, { 112, 112 }, { 113, 113 }, { 117, 85 }, { 118, 102 }, + { 119, 87 }, { 120, 114 }, { 121, 89 }, { 122, 90 }, +}; + +static const struct msm_pinctrl_soc_data qcs615_tlmm = { + .pins = qcs615_pins, + .npins = ARRAY_SIZE(qcs615_pins), + .functions = qcs615_functions, + .nfunctions = ARRAY_SIZE(qcs615_functions), + .groups = qcs615_groups, + .ngroups = ARRAY_SIZE(qcs615_groups), + .ngpios = 123, + .tiles = qcs615_tiles, + .ntiles = ARRAY_SIZE(qcs615_tiles), + .wakeirq_map = qcs615_pdc_map, + .nwakeirq_map = ARRAY_SIZE(qcs615_pdc_map), +}; + +static const struct of_device_id qcs615_tlmm_of_match[] = { + { + .compatible = "qcom,qcs615-tlmm", + }, + {}, +}; + +static int qcs615_tlmm_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &qcs615_tlmm); +} + +static struct platform_driver qcs615_tlmm_driver = { + .driver = { + .name = "qcs615-tlmm", + .of_match_table = qcs615_tlmm_of_match, + }, + .probe = qcs615_tlmm_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init qcs615_tlmm_init(void) +{ + return platform_driver_register(&qcs615_tlmm_driver); +} +arch_initcall(qcs615_tlmm_init); + +static void __exit qcs615_tlmm_exit(void) +{ + platform_driver_unregister(&qcs615_tlmm_driver); +} +module_exit(qcs615_tlmm_exit); + +MODULE_DESCRIPTION("QTI QCS615 TLMM driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, qcs615_tlmm_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-qcs8300.c b/drivers/pinctrl/qcom/pinctrl-qcs8300.c new file mode 100644 index 00000000000000..ba6de944a859a0 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-qcs8300.c @@ -0,0 +1,1246 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include + +#include "pinctrl-msm.h" + +#define REG_SIZE 0x1000 +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11)\ + { \ + .grp = PINCTRL_PINGROUP("gpio" #id, \ + gpio##id##_pins, \ + 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, \ + msm_mux_##f10, \ + msm_mux_##f11 /* egpio mode */ \ + }, \ + .nfuncs = 12, \ + .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, \ + .egpio_enable = 12, \ + .egpio_present = 11, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +#define QUP_I3C(qup_mode, qup_offset) \ + { \ + .mode = qup_mode, \ + .offset = qup_offset, \ + } + +#define QUP_I3C_6_MODE_OFFSET 0xaf000 +#define QUP_I3C_7_MODE_OFFSET 0xb0000 +#define QUP_I3C_13_MODE_OFFSET 0xb1000 +#define QUP_I3C_14_MODE_OFFSET 0xb2000 + +static const struct pinctrl_pin_desc qcs8300_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "UFS_RESET"), + PINCTRL_PIN(134, "SDC1_RCLK"), + PINCTRL_PIN(135, "SDC1_CLK"), + PINCTRL_PIN(136, "SDC1_CMD"), + PINCTRL_PIN(137, "SDC1_DATA"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); +DECLARE_MSM_GPIO_PINS(123); +DECLARE_MSM_GPIO_PINS(124); +DECLARE_MSM_GPIO_PINS(125); +DECLARE_MSM_GPIO_PINS(126); +DECLARE_MSM_GPIO_PINS(127); +DECLARE_MSM_GPIO_PINS(128); +DECLARE_MSM_GPIO_PINS(129); +DECLARE_MSM_GPIO_PINS(130); +DECLARE_MSM_GPIO_PINS(131); +DECLARE_MSM_GPIO_PINS(132); + +static const unsigned int ufs_reset_pins[] = { 133 }; +static const unsigned int sdc1_rclk_pins[] = { 134 }; +static const unsigned int sdc1_clk_pins[] = { 135 }; +static const unsigned int sdc1_cmd_pins[] = { 136 }; +static const unsigned int sdc1_data_pins[] = { 137 }; + +enum qcs8300_functions { + msm_mux_gpio, + msm_mux_aoss_cti, + msm_mux_atest_char, + msm_mux_atest_usb2, + msm_mux_audio_ref, + msm_mux_cam_mclk, + msm_mux_cci_async, + msm_mux_cci_i2c_scl, + msm_mux_cci_i2c_sda, + msm_mux_cci_timer, + msm_mux_cri_trng, + msm_mux_dbg_out, + msm_mux_ddr_bist, + msm_mux_ddr_pxi0, + msm_mux_ddr_pxi1, + msm_mux_ddr_pxi2, + msm_mux_ddr_pxi3, + msm_mux_edp0_hot, + msm_mux_edp0_lcd, + msm_mux_edp1_lcd, + msm_mux_egpio, + msm_mux_emac0_mcg0, + msm_mux_emac0_mcg1, + msm_mux_emac0_mcg2, + msm_mux_emac0_mcg3, + msm_mux_emac0_mdc, + msm_mux_emac0_mdio, + msm_mux_emac0_ptp_aux, + msm_mux_emac0_ptp_pps, + msm_mux_gcc_gp1, + msm_mux_gcc_gp2, + msm_mux_gcc_gp3, + msm_mux_gcc_gp4, + msm_mux_gcc_gp5, + msm_mux_hs0_mi2s, + msm_mux_hs1_mi2s, + msm_mux_hs2_mi2s, + msm_mux_ibi_i3c, + msm_mux_jitter_bist, + msm_mux_mdp0_vsync0, + msm_mux_mdp0_vsync1, + msm_mux_mdp0_vsync3, + msm_mux_mdp0_vsync6, + msm_mux_mdp0_vsync7, + msm_mux_mdp_vsync, + msm_mux_mi2s1_data0, + msm_mux_mi2s1_data1, + msm_mux_mi2s1_sck, + msm_mux_mi2s1_ws, + msm_mux_mi2s2_data0, + msm_mux_mi2s2_data1, + msm_mux_mi2s2_sck, + msm_mux_mi2s2_ws, + msm_mux_mi2s_mclk0, + msm_mux_mi2s_mclk1, + msm_mux_pcie0_clkreq, + msm_mux_pcie1_clkreq, + msm_mux_phase_flag, + msm_mux_pll_bist, + msm_mux_pll_clk, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_qdss_cti, + msm_mux_qdss_gpio, + msm_mux_qup0_se0, + msm_mux_qup0_se1, + msm_mux_qup0_se2, + msm_mux_qup0_se3, + msm_mux_qup0_se4, + msm_mux_qup0_se5, + msm_mux_qup0_se6, + msm_mux_qup0_se7, + msm_mux_qup1_se0, + msm_mux_qup1_se1, + msm_mux_qup1_se2, + msm_mux_qup1_se3, + msm_mux_qup1_se4, + msm_mux_qup1_se5, + msm_mux_qup1_se6, + msm_mux_qup1_se7, + msm_mux_qup2_se0, + msm_mux_sailss_emac0, + msm_mux_sailss_ospi, + msm_mux_sgmii_phy, + msm_mux_tb_trig, + msm_mux_tgu_ch0, + msm_mux_tgu_ch1, + msm_mux_tgu_ch2, + msm_mux_tgu_ch3, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_tsense_pwm3, + msm_mux_tsense_pwm4, + msm_mux_usb2phy_ac, + msm_mux_vsense_trigger, + 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", "gpio119", "gpio120", "gpio121", "gpio122", + "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128", + "gpio129", "gpio130", "gpio131", "gpio132", +}; + +static const char *const aoss_cti_groups[] = { + "gpio37", "gpio38", "gpio39", "gpio40", +}; + +static const char * const atest_char_groups[] = { + "gpio66", "gpio70", "gpio71", "gpio72", "gpio93", +}; + +static const char * const atest_usb2_groups[] = { + "gpio63", "gpio83", "gpio92", "gpio74", "gpio84", "gpio87", "gpio67", + "gpio75", "gpio85", "gpio65", "gpio68", "gpio80", "gpio64", "gpio69", + "gpio81", +}; + +static const char * const audio_ref_groups[] = { + "gpio105", +}; + +static const char * const cam_mclk_groups[] = { + "gpio67", "gpio68", "gpio69", +}; + +static const char * const cci_async_groups[] = { + "gpio63", "gpio64", "gpio65", "gpio29", "gpio30", "gpio31", +}; + +static const char * const cci_i2c_scl_groups[] = { + "gpio58", "gpio30", "gpio60", "gpio32", "gpio62", "gpio55", +}; + +static const char * const cci_i2c_sda_groups[] = { + "gpio57", "gpio29", "gpio59", "gpio31", "gpio61", "gpio54", +}; + +static const char *const cci_timer_groups[] = { + "gpio63", "gpio64", "gpio65", "gpio49", "gpio50", "gpio19", + "gpio20", "gpio21", "gpio22", "gpio23", +}; + +static const char *const cri_trng_groups[] = { + "gpio92", "gpio90", "gpio91", +}; + +static const char *const dbg_out_groups[] = { + "gpio75", +}; + +static const char * const ddr_bist_groups[] = { + "gpio53", "gpio54", "gpio55", "gpio56", +}; + +static const char *const ddr_pxi0_groups[] = { + "gpio68", "gpio69", +}; + +static const char *const ddr_pxi1_groups[] = { + "gpio49", "gpio50", +}; + +static const char *const ddr_pxi2_groups[] = { + "gpio52", "gpio83", +}; + +static const char *const ddr_pxi3_groups[] = { + "gpio80", "gpio81", +}; + +static const char *const edp0_hot_groups[] = { + "gpio94", +}; + +static const char *const edp0_lcd_groups[] = { + "gpio48", +}; + +static const char *const edp1_lcd_groups[] = { + "gpio49", +}; + +static const char *const egpio_groups[] = { + "gpio110", "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", + "gpio116", "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", + "gpio122", "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", + "gpio128", "gpio129", "gpio130", "gpio131", "gpio132", +}; + +static const char *const emac0_mcg0_groups[] = { + "gpio10", +}; + +static const char *const emac0_mcg1_groups[] = { + "gpio11", +}; + +static const char *const emac0_mcg2_groups[] = { + "gpio24", +}; + +static const char *const emac0_mcg3_groups[] = { + "gpio79", +}; + +static const char *const emac0_mdc_groups[] = { + "gpio5", +}; + +static const char *const emac0_mdio_groups[] = { + "gpio6", +}; + +static const char * const emac0_ptp_aux_groups[] = { + "gpio24", "gpio31", "gpio32", "gpio79", +}; + +static const char * const emac0_ptp_pps_groups[] = { + "gpio24", "gpio29", "gpio30", "gpio79", +}; + +static const char *const gcc_gp1_groups[] = { + "gpio35", "gpio84", +}; + +static const char *const gcc_gp2_groups[] = { + "gpio36", "gpio81", +}; + +static const char *const gcc_gp3_groups[] = { + "gpio69", "gpio82", +}; + +static const char *const gcc_gp4_groups[] = { + "gpio68", "gpio83", +}; + +static const char *const gcc_gp5_groups[] = { + "gpio76", "gpio77", +}; + +static const char * const hs0_mi2s_groups[] = { + "gpio106", "gpio107", "gpio108", "gpio109", +}; + +static const char * const hs1_mi2s_groups[] = { + "gpio45", "gpio46", "gpio47", "gpio48", +}; + +static const char * const hs2_mi2s_groups[] = { + "gpio49", "gpio50", "gpio51", "gpio52", +}; + +static const char * const ibi_i3c_groups[] = { + "gpio17", "gpio18", "gpio19", "gpio20", "gpio37", "gpio38", + "gpio39", "gpio40", +}; + +static const char *const jitter_bist_groups[] = { + "gpio97", +}; + +static const char *const mdp0_vsync0_groups[] = { + "gpio89", +}; + +static const char *const mdp0_vsync1_groups[] = { + "gpio90", +}; + +static const char *const mdp0_vsync3_groups[] = { + "gpio91", +}; + +static const char *const mdp0_vsync6_groups[] = { + "gpio80", +}; + +static const char *const mdp0_vsync7_groups[] = { + "gpio81", +}; + +static const char *const mdp_vsync_groups[] = { + "gpio42", "gpio52", "gpio32", +}; + +static const char *const mi2s1_data0_groups[] = { + "gpio100", +}; + +static const char *const mi2s1_data1_groups[] = { + "gpio101", +}; + +static const char *const mi2s1_sck_groups[] = { + "gpio98", +}; + +static const char *const mi2s1_ws_groups[] = { + "gpio99", +}; + +static const char *const mi2s2_data0_groups[] = { + "gpio104", +}; + +static const char *const mi2s2_data1_groups[] = { + "gpio105", +}; + +static const char *const mi2s2_sck_groups[] = { + "gpio102", +}; + +static const char *const mi2s2_ws_groups[] = { + "gpio103", +}; + +static const char *const mi2s_mclk0_groups[] = { + "gpio97", +}; + +static const char *const mi2s_mclk1_groups[] = { + "gpio109", +}; + +static const char *const pcie0_clkreq_groups[] = { + "gpio1", +}; + +static const char *const pcie1_clkreq_groups[] = { + "gpio22", +}; + +static const char *const phase_flag_groups[] = { + "gpio66", "gpio56", "gpio118", "gpio117", "gpio116", + "gpio3", "gpio114", "gpio113", "gpio112", "gpio111", + "gpio110", "gpio28", "gpio55", "gpio108", "gpio107", + "gpio106", "gpio105", "gpio104", "gpio103", "gpio102", + "gpio101", "gpio100", "gpio99", "gpio125", "gpio98", + "gpio54", "gpio25", "gpio26", "gpio122", "gpio121", + "gpio120", "gpio9", +}; + +static const char *const pll_bist_groups[] = { + "gpio107", +}; + +static const char *const pll_clk_groups[] = { + "gpio74", +}; + +static const char *const prng_rosc0_groups[] = { + "gpio57", +}; + +static const char *const prng_rosc1_groups[] = { + "gpio58", +}; + +static const char *const prng_rosc2_groups[] = { + "gpio59", +}; + +static const char *const prng_rosc3_groups[] = { + "gpio60", +}; + +static const char *const qdss_cti_groups[] = { + "gpio4", "gpio5", "gpio23", "gpio24", "gpio49", "gpio50", + "gpio51", "gpio52", +}; + +static const char *const qdss_gpio_groups[] = { + "gpio57", "gpio58", "gpio97", "gpio106", + "gpio59", "gpio107", "gpio60", "gpio108", + "gpio36", "gpio100", "gpio61", "gpio101", + "gpio62", "gpio102", "gpio33", "gpio103", + "gpio34", "gpio104", "gpio75", "gpio105", + "gpio72", "gpio109", "gpio71", "gpio110", + "gpio70", "gpio111", "gpio63", "gpio112", + "gpio64", "gpio113", "gpio65", "gpio114", + "gpio73", "gpio98", "gpio74", "gpio99", +}; + +static const char *const qup0_se0_groups[] = { + "gpio17", "gpio18", "gpio19", "gpio20", +}; + +static const char *const qup0_se1_groups[] = { + "gpio19", "gpio20", "gpio17", "gpio18", +}; + +static const char *const qup0_se2_groups[] = { + "gpio33", "gpio34", "gpio35", "gpio36", +}; + +static const char *const qup0_se3_groups[] = { + "gpio25", "gpio26", "gpio27", "gpio28", +}; + +static const char *const qup0_se4_groups[] = { + "gpio29", "gpio30", "gpio31", "gpio32", +}; + +static const char *const qup0_se5_groups[] = { + "gpio21", "gpio22", "gpio23", "gpio24", +}; + +static const char *const qup0_se6_groups[] = { + "gpio80", "gpio81", "gpio82", "gpio83", +}; + +static const char *const qup0_se7_groups[] = { + "gpio43", "gpio44", "gpio43", "gpio44", +}; + +static const char *const qup1_se0_groups[] = { + "gpio37", "gpio38", "gpio39", "gpio40", +}; + +static const char *const qup1_se1_groups[] = { + "gpio39", "gpio40", "gpio37", "gpio38", +}; + +static const char *const qup1_se2_groups[] = { + "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", +}; + +static const char *const qup1_se3_groups[] = { + "gpio41", "gpio42", "gpio41", "gpio42", +}; + +static const char *const qup1_se4_groups[] = { + "gpio45", "gpio46", "gpio47", "gpio48", +}; + +static const char *const qup1_se5_groups[] = { + "gpio49", "gpio50", "gpio51", "gpio52", +}; + +static const char *const qup1_se6_groups[] = { + "gpio89", "gpio90", "gpio91", "gpio92", +}; + +static const char *const qup1_se7_groups[] = { + "gpio91", "gpio92", "gpio89", "gpio90", +}; + +static const char *const qup2_se0_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio13", + "gpio14", "gpio15", "gpio16", +}; + +static const char *const sailss_emac0_groups[] = { + "gpio15", "gpio16", +}; + +static const char *const sailss_ospi_groups[] = { + "gpio15", "gpio16", +}; + +static const char *const sgmii_phy_groups[] = { + "gpio4", +}; + +static const char *const tb_trig_groups[] = { + "gpio14", +}; + +static const char *const tgu_ch0_groups[] = { + "gpio43", +}; + +static const char *const tgu_ch1_groups[] = { + "gpio44", +}; + +static const char *const tgu_ch2_groups[] = { + "gpio29", +}; + +static const char *const tgu_ch3_groups[] = { + "gpio30", +}; + +static const char *const tsense_pwm1_groups[] = { + "gpio79", +}; + +static const char *const tsense_pwm2_groups[] = { + "gpio78", +}; + +static const char *const tsense_pwm3_groups[] = { + "gpio77", +}; + +static const char *const tsense_pwm4_groups[] = { + "gpio76", +}; + +static const char *const usb2phy_ac_groups[] = { + "gpio7", "gpio8", +}; + +static const char *const vsense_trigger_groups[] = { + "gpio67", +}; + +static const struct pinfunction qcs8300_functions[] = { + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(aoss_cti), + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_usb2), + MSM_PIN_FUNCTION(audio_ref), + MSM_PIN_FUNCTION(cam_mclk), + MSM_PIN_FUNCTION(cci_async), + MSM_PIN_FUNCTION(cci_i2c_scl), + MSM_PIN_FUNCTION(cci_i2c_sda), + MSM_PIN_FUNCTION(cci_timer), + MSM_PIN_FUNCTION(cri_trng), + MSM_PIN_FUNCTION(dbg_out), + MSM_PIN_FUNCTION(ddr_bist), + MSM_PIN_FUNCTION(ddr_pxi0), + MSM_PIN_FUNCTION(ddr_pxi1), + MSM_PIN_FUNCTION(ddr_pxi2), + MSM_PIN_FUNCTION(ddr_pxi3), + MSM_PIN_FUNCTION(edp0_hot), + MSM_PIN_FUNCTION(edp0_lcd), + MSM_PIN_FUNCTION(edp1_lcd), + MSM_PIN_FUNCTION(egpio), + MSM_PIN_FUNCTION(emac0_mcg0), + MSM_PIN_FUNCTION(emac0_mcg1), + MSM_PIN_FUNCTION(emac0_mcg2), + MSM_PIN_FUNCTION(emac0_mcg3), + MSM_PIN_FUNCTION(emac0_mdc), + MSM_PIN_FUNCTION(emac0_mdio), + MSM_PIN_FUNCTION(emac0_ptp_aux), + MSM_PIN_FUNCTION(emac0_ptp_pps), + MSM_PIN_FUNCTION(gcc_gp1), + MSM_PIN_FUNCTION(gcc_gp2), + MSM_PIN_FUNCTION(gcc_gp3), + MSM_PIN_FUNCTION(gcc_gp4), + MSM_PIN_FUNCTION(gcc_gp5), + MSM_PIN_FUNCTION(hs0_mi2s), + MSM_PIN_FUNCTION(hs1_mi2s), + MSM_PIN_FUNCTION(hs2_mi2s), + MSM_PIN_FUNCTION(ibi_i3c), + MSM_PIN_FUNCTION(jitter_bist), + MSM_PIN_FUNCTION(mdp0_vsync0), + MSM_PIN_FUNCTION(mdp0_vsync1), + MSM_PIN_FUNCTION(mdp0_vsync3), + MSM_PIN_FUNCTION(mdp0_vsync6), + MSM_PIN_FUNCTION(mdp0_vsync7), + MSM_PIN_FUNCTION(mdp_vsync), + MSM_PIN_FUNCTION(mi2s1_data0), + MSM_PIN_FUNCTION(mi2s1_data1), + MSM_PIN_FUNCTION(mi2s1_sck), + MSM_PIN_FUNCTION(mi2s1_ws), + MSM_PIN_FUNCTION(mi2s2_data0), + MSM_PIN_FUNCTION(mi2s2_data1), + MSM_PIN_FUNCTION(mi2s2_sck), + MSM_PIN_FUNCTION(mi2s2_ws), + MSM_PIN_FUNCTION(mi2s_mclk0), + MSM_PIN_FUNCTION(mi2s_mclk1), + MSM_PIN_FUNCTION(pcie0_clkreq), + MSM_PIN_FUNCTION(pcie1_clkreq), + MSM_PIN_FUNCTION(phase_flag), + MSM_PIN_FUNCTION(pll_bist), + MSM_PIN_FUNCTION(pll_clk), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(qdss_cti), + MSM_PIN_FUNCTION(qdss_gpio), + MSM_PIN_FUNCTION(qup0_se0), + MSM_PIN_FUNCTION(qup0_se1), + MSM_PIN_FUNCTION(qup0_se2), + MSM_PIN_FUNCTION(qup0_se3), + MSM_PIN_FUNCTION(qup0_se4), + MSM_PIN_FUNCTION(qup0_se5), + MSM_PIN_FUNCTION(qup0_se6), + MSM_PIN_FUNCTION(qup0_se7), + MSM_PIN_FUNCTION(qup1_se0), + MSM_PIN_FUNCTION(qup1_se1), + MSM_PIN_FUNCTION(qup1_se2), + MSM_PIN_FUNCTION(qup1_se3), + MSM_PIN_FUNCTION(qup1_se4), + MSM_PIN_FUNCTION(qup1_se5), + MSM_PIN_FUNCTION(qup1_se6), + MSM_PIN_FUNCTION(qup1_se7), + MSM_PIN_FUNCTION(qup2_se0), + MSM_PIN_FUNCTION(sailss_emac0), + MSM_PIN_FUNCTION(sailss_ospi), + MSM_PIN_FUNCTION(sgmii_phy), + MSM_PIN_FUNCTION(tb_trig), + MSM_PIN_FUNCTION(tgu_ch0), + MSM_PIN_FUNCTION(tgu_ch1), + MSM_PIN_FUNCTION(tgu_ch2), + MSM_PIN_FUNCTION(tgu_ch3), + MSM_PIN_FUNCTION(tsense_pwm1), + MSM_PIN_FUNCTION(tsense_pwm2), + MSM_PIN_FUNCTION(tsense_pwm3), + MSM_PIN_FUNCTION(tsense_pwm4), + MSM_PIN_FUNCTION(usb2phy_ac), + MSM_PIN_FUNCTION(vsense_trigger), +}; + +/* + * 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 qcs8300_groups[] = { + [0] = PINGROUP(0, _, _, _, _, _, _, _, _, _, _, _), + [1] = PINGROUP(1, pcie0_clkreq, _, _, _, _, _, _, _, _, _, _), + [2] = PINGROUP(2, _, _, _, _, _, _, _, _, _, _, _), + [3] = PINGROUP(3, phase_flag, _, _, _, _, _, _, _, _, _, _), + [4] = PINGROUP(4, sgmii_phy, qdss_cti, _, _, _, _, _, _, _, _, _), + [5] = PINGROUP(5, emac0_mdc, qdss_cti, _, _, _, _, _, _, _, _, _), + [6] = PINGROUP(6, emac0_mdio, _, _, _, _, _, _, _, _, _, _), + [7] = PINGROUP(7, usb2phy_ac, _, _, _, _, _, _, _, _, _, _), + [8] = PINGROUP(8, usb2phy_ac, _, _, _, _, _, _, _, _, _, _), + [9] = PINGROUP(9, phase_flag, _, _, _, _, _, _, _, _, _, _), + [10] = PINGROUP(10, qup2_se0, emac0_mcg0, _, _, _, _, _, _, _, _, _), + [11] = PINGROUP(11, qup2_se0, emac0_mcg1, _, _, _, _, _, _, _, _, _), + [12] = PINGROUP(12, qup2_se0, _, _, _, _, _, _, _, _, _, _), + [13] = PINGROUP(13, qup2_se0, _, _, _, _, _, _, _, _, _, _), + [14] = PINGROUP(14, qup2_se0, tb_trig, _, _, _, _, _, _, _, _, _), + [15] = PINGROUP(15, qup2_se0, _, sailss_ospi, sailss_emac0, _, _, _, _, _, _, _), + [16] = PINGROUP(16, qup2_se0, _, _, sailss_ospi, sailss_emac0, _, _, _, _, _, _), + [17] = PINGROUP(17, qup0_se0, qup0_se1, ibi_i3c, _, _, _, _, _, _, _, _), + [18] = PINGROUP(18, qup0_se0, qup0_se1, ibi_i3c, _, _, _, _, _, _, _, _), + [19] = PINGROUP(19, qup0_se1, qup0_se0, cci_timer, ibi_i3c, _, _, _, _, _, _, _), + [20] = PINGROUP(20, qup0_se1, qup0_se0, cci_timer, ibi_i3c, _, _, _, _, _, _, _), + [21] = PINGROUP(21, qup0_se5, cci_timer, _, _, _, _, _, _, _, _, _), + [22] = PINGROUP(22, pcie1_clkreq, qup0_se5, cci_timer, _, _, _, _, _, _, _, _), + [23] = PINGROUP(23, qup0_se5, cci_timer, qdss_cti, _, _, _, _, _, _, _, _), + [24] = PINGROUP(24, qup0_se5, emac0_ptp_aux, emac0_ptp_pps, qdss_cti, + emac0_mcg2, _, _, _, _, _, _), + [25] = PINGROUP(25, qup0_se3, phase_flag, _, _, _, _, _, _, _, _, _), + [26] = PINGROUP(26, qup0_se3, phase_flag, _, _, _, _, _, _, _, _, _), + [27] = PINGROUP(27, qup0_se3, _, _, _, _, _, _, _, _, _, _), + [28] = PINGROUP(28, qup0_se3, phase_flag, _, _, _, _, _, _, _, _, _), + [29] = PINGROUP(29, qup0_se4, cci_i2c_sda, cci_async, emac0_ptp_pps, + tgu_ch2, _, _, _, _, _, _), + [30] = PINGROUP(30, qup0_se4, cci_i2c_scl, cci_async, emac0_ptp_pps, + tgu_ch3, _, _, _, _, _, _), + [31] = PINGROUP(31, qup0_se4, cci_i2c_sda, cci_async, emac0_ptp_aux, _, _, _, _, _, _, _), + [32] = PINGROUP(32, qup0_se4, cci_i2c_scl, emac0_ptp_aux, mdp_vsync, _, _, _, _, _, _, _), + [33] = PINGROUP(33, qup0_se2, qdss_gpio, _, _, _, _, _, _, _, _, _), + [34] = PINGROUP(34, qup0_se2, qdss_gpio, _, _, _, _, _, _, _, _, _), + [35] = PINGROUP(35, qup0_se2, gcc_gp1, _, _, _, _, _, _, _, _, _), + [36] = PINGROUP(36, qup0_se2, gcc_gp2, qdss_gpio, _, _, _, _, _, _, _, _), + [37] = PINGROUP(37, qup1_se0, ibi_i3c, qup1_se1, aoss_cti, _, _, _, _, _, _, _), + [38] = PINGROUP(38, qup1_se0, ibi_i3c, qup1_se1, aoss_cti, _, _, _, _, _, _, _), + [39] = PINGROUP(39, qup1_se1, ibi_i3c, qup1_se0, aoss_cti, _, _, _, _, _, _, _), + [40] = PINGROUP(40, qup1_se1, ibi_i3c, qup1_se0, aoss_cti, _, _, _, _, _, _, _), + [41] = PINGROUP(41, qup1_se3, _, _, _, _, _, _, _, _, _, _), + [42] = PINGROUP(42, qup1_se3, _, mdp_vsync, _, _, _, _, _, _, _, _), + [43] = PINGROUP(43, qup0_se7, _, tgu_ch0, _, _, _, _, _, _, _, _), + [44] = PINGROUP(44, qup0_se7, _, tgu_ch1, _, _, _, _, _, _, _, _), + [45] = PINGROUP(45, qup1_se4, hs1_mi2s, _, _, _, _, _, _, _, _, _), + [46] = PINGROUP(46, qup1_se4, hs1_mi2s, _, _, _, _, _, _, _, _, _), + [47] = PINGROUP(47, qup1_se4, hs1_mi2s, _, _, _, _, _, _, _, _, _), + [48] = PINGROUP(48, qup1_se4, hs1_mi2s, edp0_lcd, _, _, _, _, _, _, _, _), + [49] = PINGROUP(49, qup1_se5, hs2_mi2s, cci_timer, qdss_cti, edp1_lcd, + ddr_pxi1, _, _, _, _, _), + [50] = PINGROUP(50, qup1_se5, hs2_mi2s, cci_timer, qdss_cti, _, ddr_pxi1, _, _, _, _, _), + [51] = PINGROUP(51, qup1_se5, hs2_mi2s, qdss_cti, _, _, _, _, _, _, _, _), + [52] = PINGROUP(52, qup1_se5, hs2_mi2s, qdss_cti, mdp_vsync, ddr_pxi2, _, _, _, _, _, _), + [53] = PINGROUP(53, ddr_bist, _, _, _, _, _, _, _, _, _, _), + [54] = PINGROUP(54, cci_i2c_sda, phase_flag, ddr_bist, _, _, _, _, _, _, _, _), + [55] = PINGROUP(55, cci_i2c_scl, phase_flag, ddr_bist, _, _, _, _, _, _, _, _), + [56] = PINGROUP(56, phase_flag, ddr_bist, _, _, _, _, _, _, _, _, _), + [57] = PINGROUP(57, cci_i2c_sda, prng_rosc0, qdss_gpio, _, _, _, _, _, _, _, _), + [58] = PINGROUP(58, cci_i2c_scl, prng_rosc1, qdss_gpio, _, _, _, _, _, _, _, _), + [59] = PINGROUP(59, cci_i2c_sda, prng_rosc2, qdss_gpio, _, _, _, _, _, _, _, _), + [60] = PINGROUP(60, cci_i2c_scl, prng_rosc3, qdss_gpio, _, _, _, _, _, _, _, _), + [61] = PINGROUP(61, cci_i2c_sda, qdss_gpio, _, _, _, _, _, _, _, _, _), + [62] = PINGROUP(62, cci_i2c_scl, qdss_gpio, _, _, _, _, _, _, _, _, _), + [63] = PINGROUP(63, cci_timer, cci_async, qdss_gpio, atest_usb2, _, _, _, _, _, _, _), + [64] = PINGROUP(64, cci_timer, cci_async, qdss_gpio, atest_usb2, _, _, _, _, _, _, _), + [65] = PINGROUP(65, cci_timer, cci_async, qdss_gpio, atest_usb2, _, _, _, _, _, _, _), + [66] = PINGROUP(66, phase_flag, _, atest_char, _, _, _, _, _, _, _, _), + [67] = PINGROUP(67, cam_mclk, vsense_trigger, atest_usb2, _, _, _, _, _, _, _, _), + [68] = PINGROUP(68, cam_mclk, gcc_gp4, atest_usb2, ddr_pxi0, _, _, _, _, _, _, _), + [69] = PINGROUP(69, cam_mclk, gcc_gp3, atest_usb2, ddr_pxi0, _, _, _, _, _, _, _), + [70] = PINGROUP(70, qdss_gpio, atest_char, _, _, _, _, _, _, _, _, _), + [71] = PINGROUP(71, qdss_gpio, atest_char, _, _, _, _, _, _, _, _, _), + [72] = PINGROUP(72, qdss_gpio, atest_char, _, _, _, _, _, _, _, _, _), + [73] = PINGROUP(73, _, qdss_gpio, _, _, _, _, _, _, _, _, _), + [74] = PINGROUP(74, pll_clk, qdss_gpio, atest_usb2, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, _, dbg_out, qdss_gpio, atest_usb2, _, _, _, _, _, _, _), + [76] = PINGROUP(76, gcc_gp5, tsense_pwm4, _, _, _, _, _, _, _, _, _), + [77] = PINGROUP(77, gcc_gp5, tsense_pwm3, _, _, _, _, _, _, _, _, _), + [78] = PINGROUP(78, tsense_pwm2, _, _, _, _, _, _, _, _, _, _), + [79] = PINGROUP(79, emac0_ptp_aux, emac0_ptp_pps, emac0_mcg3, _, + tsense_pwm1, _, _, _, _, _, _), + [80] = PINGROUP(80, qup0_se6, mdp0_vsync6, _, atest_usb2, ddr_pxi3, _, _, _, _, _, _), + [81] = PINGROUP(81, qup0_se6, mdp0_vsync7, gcc_gp2, _, atest_usb2, ddr_pxi3, _, _, _, _, _), + [82] = PINGROUP(82, qup0_se6, gcc_gp3, _, _, _, _, _, _, _, _, _), + [83] = PINGROUP(83, qup0_se6, gcc_gp4, _, atest_usb2, ddr_pxi2, _, _, _, _, _, _), + [84] = PINGROUP(84, qup1_se2, gcc_gp1, _, atest_usb2, _, _, _, _, _, _, _), + [85] = PINGROUP(85, qup1_se2, _, atest_usb2, _, _, _, _, _, _, _, _), + [86] = PINGROUP(86, qup1_se2, _, _, _, _, _, _, _, _, _, _), + [87] = PINGROUP(87, qup1_se2, _, atest_usb2, _, _, _, _, _, _, _, _), + [88] = PINGROUP(88, qup1_se2, _, _, _, _, _, _, _, _, _, _), + [89] = PINGROUP(89, qup1_se6, qup1_se7, mdp0_vsync0, _, _, _, _, _, _, _, _), + [90] = PINGROUP(90, qup1_se6, qup1_se7, mdp0_vsync1, cri_trng, _, _, _, _, _, _, _), + [91] = PINGROUP(91, qup1_se7, qup1_se6, mdp0_vsync3, cri_trng, _, _, _, _, _, _, _), + [92] = PINGROUP(92, qup1_se7, qup1_se6, cri_trng, _, atest_usb2, _, _, _, _, _, _), + [93] = PINGROUP(93, atest_char, _, _, _, _, _, _, _, _, _, _), + [94] = PINGROUP(94, edp0_hot, _, _, _, _, _, _, _, _, _, _), + [95] = PINGROUP(95, _, _, _, _, _, _, _, _, _, _, _), + [96] = PINGROUP(96, _, _, _, _, _, _, _, _, _, _, _), + [97] = PINGROUP(97, mi2s_mclk0, jitter_bist, qdss_gpio, _, _, _, _, _, _, _, _), + [98] = PINGROUP(98, mi2s1_sck, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [99] = PINGROUP(99, mi2s1_ws, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [100] = PINGROUP(100, mi2s1_data0, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [101] = PINGROUP(101, mi2s1_data1, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [102] = PINGROUP(102, mi2s2_sck, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [103] = PINGROUP(103, mi2s2_ws, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [104] = PINGROUP(104, mi2s2_data0, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [105] = PINGROUP(105, mi2s2_data1, audio_ref, phase_flag, _, qdss_gpio, _, _, _, _, _, _), + [106] = PINGROUP(106, hs0_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [107] = PINGROUP(107, hs0_mi2s, pll_bist, phase_flag, _, qdss_gpio, _, _, _, _, _, _), + [108] = PINGROUP(108, hs0_mi2s, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _), + [109] = PINGROUP(109, hs0_mi2s, mi2s_mclk1, qdss_gpio, _, _, _, _, _, _, _, _), + [110] = PINGROUP(110, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _, egpio), + [111] = PINGROUP(111, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _, egpio), + [112] = PINGROUP(112, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _, egpio), + [113] = PINGROUP(113, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _, egpio), + [114] = PINGROUP(114, phase_flag, _, qdss_gpio, _, _, _, _, _, _, _, egpio), + [115] = PINGROUP(115, _, _, _, _, _, _, _, _, _, _, egpio), + [116] = PINGROUP(116, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [117] = PINGROUP(117, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [118] = PINGROUP(118, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [119] = PINGROUP(119, _, _, _, _, _, _, _, _, _, _, egpio), + [120] = PINGROUP(120, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [121] = PINGROUP(121, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [122] = PINGROUP(122, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [123] = PINGROUP(123, _, _, _, _, _, _, _, _, _, _, egpio), + [124] = PINGROUP(124, _, _, _, _, _, _, _, _, _, _, egpio), + [125] = PINGROUP(125, phase_flag, _, _, _, _, _, _, _, _, _, egpio), + [126] = PINGROUP(126, _, _, _, _, _, _, _, _, _, _, egpio), + [127] = PINGROUP(127, _, _, _, _, _, _, _, _, _, _, egpio), + [128] = PINGROUP(128, _, _, _, _, _, _, _, _, _, _, egpio), + [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _, _, egpio), + [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _, _, egpio), + [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _, _, egpio), + [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _, _, egpio), + [133] = UFS_RESET(ufs_reset, 0x92000), + [134] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x89000, 15, 0), + [135] = SDC_QDSD_PINGROUP(sdc1_clk, 0x89000, 13, 6), + [136] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x89000, 11, 3), + [137] = SDC_QDSD_PINGROUP(sdc1_data, 0x89000, 9, 0), +}; + +static const struct msm_gpio_wakeirq_map qcs8300_pdc_map[] = { + { 0, 169 }, { 1, 174 }, { 2, 221 }, { 3, 176 }, { 4, 171 }, + { 9, 198 }, { 10, 187 }, { 11, 188 }, { 13, 211 }, { 16, 203 }, + { 17, 213 }, { 18, 209 }, { 19, 201 }, { 20, 230 }, { 21, 231 }, + { 22, 175 }, { 23, 170 }, { 24, 232 }, { 28, 235 }, { 29, 216 }, + { 31, 208 }, { 32, 200 }, { 36, 212 }, { 37, 177 }, { 38, 178 }, + { 39, 184 }, { 40, 185 }, { 42, 186 }, { 44, 194 }, { 45, 173 }, + { 48, 195 }, { 51, 215 }, { 52, 197 }, { 53, 192 }, { 56, 193 }, + { 66, 238 }, { 67, 172 }, { 68, 182 }, { 69, 179 }, { 70, 181 }, + { 71, 202 }, { 72, 183 }, { 73, 189 }, { 74, 196 }, { 75, 190 }, + { 76, 191 }, { 77, 204 }, { 78, 206 }, { 79, 207 }, { 83, 214 }, + { 84, 205 }, { 87, 237 }, { 89, 225 }, { 90, 217 }, { 91, 218 }, + { 92, 226 }, { 93, 227 }, { 94, 228 }, { 95, 236 }, { 97, 199 }, + { 98, 229 }, { 99, 180 }, { 100, 220 }, { 101, 239 }, { 102, 219 }, + { 103, 233 }, { 104, 234 }, { 105, 223 }, { 129, 210 }, { 130, 222 }, +}; + +static const struct msm_pinctrl_soc_data qcs8300_pinctrl = { + .pins = qcs8300_pins, + .npins = ARRAY_SIZE(qcs8300_pins), + .functions = qcs8300_functions, + .nfunctions = ARRAY_SIZE(qcs8300_functions), + .groups = qcs8300_groups, + .ngroups = ARRAY_SIZE(qcs8300_groups), + .ngpios = 133, + .wakeirq_map = qcs8300_pdc_map, + .nwakeirq_map = ARRAY_SIZE(qcs8300_pdc_map), + .egpio_func = 11, +}; + +static int qcs8300_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &qcs8300_pinctrl); +} + +static const struct of_device_id qcs8300_pinctrl_of_match[] = { + { .compatible = "qcom,qcs8300-tlmm", }, + { }, +}; +MODULE_DEVICE_TABLE(of, qcs8300_pinctrl_of_match); + +static struct platform_driver qcs8300_pinctrl_driver = { + .driver = { + .name = "qcs8300-tlmm", + .of_match_table = qcs8300_pinctrl_of_match, + }, + .probe = qcs8300_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init qcs8300_pinctrl_init(void) +{ + return platform_driver_register(&qcs8300_pinctrl_driver); +} +arch_initcall(qcs8300_pinctrl_init); + +static void __exit qcs8300_pinctrl_exit(void) +{ + platform_driver_unregister(&qcs8300_pinctrl_driver); +} +module_exit(qcs8300_pinctrl_exit); + +MODULE_DESCRIPTION("QTI QCS8300 pinctrl driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c index 4d2f6f495163bc..b5808fcfb13cde 100644 --- a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c +++ b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c @@ -145,7 +145,7 @@ static struct platform_driver qdf2xxx_pinctrl_driver = { .acpi_match_table = qdf2xxx_acpi_ids, }, .probe = qdf2xxx_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init qdf2xxx_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-qdu1000.c b/drivers/pinctrl/qcom/pinctrl-qdu1000.c index da4f940bc8d4e8..47bc529ef550d2 100644 --- a/drivers/pinctrl/qcom/pinctrl-qdu1000.c +++ b/drivers/pinctrl/qcom/pinctrl-qdu1000.c @@ -1248,7 +1248,7 @@ static struct platform_driver qdu1000_tlmm_driver = { .of_match_table = qdu1000_tlmm_of_match, }, .probe = qdu1000_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init qdu1000_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c index 5459c0c681a23f..8fdea25d8d67e1 100644 --- a/drivers/pinctrl/qcom/pinctrl-sa8775p.c +++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c @@ -1530,7 +1530,7 @@ static struct platform_driver sa8775p_pinctrl_driver = { .of_match_table = sa8775p_pinctrl_of_match, }, .probe = sa8775p_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sa8775p_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sar2130p.c b/drivers/pinctrl/qcom/pinctrl-sar2130p.c new file mode 100644 index 00000000000000..19a2e37826c7b2 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sar2130p.c @@ -0,0 +1,1505 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Linaro Limited + */ + +#include +#include +#include + +#include "pinctrl-msm.h" + +#define REG_SIZE 0x1000 + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + { \ + .grp = PINCTRL_PINGROUP("gpio" #id, \ + gpio##id##_pins, \ + 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, \ + .egpio_enable = 12, \ + .egpio_present = 11, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 4, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +static const struct pinctrl_pin_desc sar2130p_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "GPIO_133"), + PINCTRL_PIN(134, "GPIO_134"), + PINCTRL_PIN(135, "GPIO_135"), + PINCTRL_PIN(136, "GPIO_136"), + PINCTRL_PIN(137, "GPIO_137"), + PINCTRL_PIN(138, "GPIO_138"), + PINCTRL_PIN(139, "GPIO_139"), + PINCTRL_PIN(140, "GPIO_140"), + PINCTRL_PIN(141, "GPIO_141"), + PINCTRL_PIN(142, "GPIO_142"), + PINCTRL_PIN(143, "GPIO_143"), + PINCTRL_PIN(144, "GPIO_144"), + PINCTRL_PIN(145, "GPIO_145"), + PINCTRL_PIN(146, "GPIO_146"), + PINCTRL_PIN(147, "GPIO_147"), + PINCTRL_PIN(148, "GPIO_148"), + PINCTRL_PIN(149, "GPIO_149"), + PINCTRL_PIN(150, "GPIO_150"), + PINCTRL_PIN(151, "GPIO_151"), + PINCTRL_PIN(152, "GPIO_152"), + PINCTRL_PIN(153, "GPIO_153"), + PINCTRL_PIN(154, "GPIO_154"), + PINCTRL_PIN(155, "GPIO_155"), + PINCTRL_PIN(156, "SDC1_RCLK"), + PINCTRL_PIN(157, "SDC1_CLK"), + PINCTRL_PIN(158, "SDC1_CMD"), + PINCTRL_PIN(159, "SDC1_DATA"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); +DECLARE_MSM_GPIO_PINS(123); +DECLARE_MSM_GPIO_PINS(124); +DECLARE_MSM_GPIO_PINS(125); +DECLARE_MSM_GPIO_PINS(126); +DECLARE_MSM_GPIO_PINS(127); +DECLARE_MSM_GPIO_PINS(128); +DECLARE_MSM_GPIO_PINS(129); +DECLARE_MSM_GPIO_PINS(130); +DECLARE_MSM_GPIO_PINS(131); +DECLARE_MSM_GPIO_PINS(132); +DECLARE_MSM_GPIO_PINS(133); +DECLARE_MSM_GPIO_PINS(134); +DECLARE_MSM_GPIO_PINS(135); +DECLARE_MSM_GPIO_PINS(136); +DECLARE_MSM_GPIO_PINS(137); +DECLARE_MSM_GPIO_PINS(138); +DECLARE_MSM_GPIO_PINS(139); +DECLARE_MSM_GPIO_PINS(140); +DECLARE_MSM_GPIO_PINS(141); +DECLARE_MSM_GPIO_PINS(142); +DECLARE_MSM_GPIO_PINS(143); +DECLARE_MSM_GPIO_PINS(144); +DECLARE_MSM_GPIO_PINS(145); +DECLARE_MSM_GPIO_PINS(146); +DECLARE_MSM_GPIO_PINS(147); +DECLARE_MSM_GPIO_PINS(148); +DECLARE_MSM_GPIO_PINS(149); +DECLARE_MSM_GPIO_PINS(150); +DECLARE_MSM_GPIO_PINS(151); +DECLARE_MSM_GPIO_PINS(152); +DECLARE_MSM_GPIO_PINS(153); +DECLARE_MSM_GPIO_PINS(154); +DECLARE_MSM_GPIO_PINS(155); + +static const unsigned int sdc1_rclk_pins[] = { 156 }; +static const unsigned int sdc1_clk_pins[] = { 157 }; +static const unsigned int sdc1_cmd_pins[] = { 158 }; +static const unsigned int sdc1_data_pins[] = { 159 }; + +enum sar2130p_functions { + msm_mux_gpio, + msm_mux_aoss_cti, + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_atest_usb0, + msm_mux_atest_usb00, + msm_mux_atest_usb01, + msm_mux_atest_usb02, + msm_mux_atest_usb03, + msm_mux_audio_ref, + msm_mux_cam_mclk, + msm_mux_cci_async, + msm_mux_cci_i2c, + msm_mux_cci_timer0, + msm_mux_cci_timer1, + msm_mux_cci_timer2, + msm_mux_cci_timer3, + msm_mux_cci_timer4, + msm_mux_cri_trng, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + 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_dp0_hot, + msm_mux_ext_mclk0, + msm_mux_ext_mclk1, + msm_mux_gcc_gp1, + msm_mux_gcc_gp2, + msm_mux_gcc_gp3, + msm_mux_host2wlan_sol, + msm_mux_i2s0_data0, + msm_mux_i2s0_data1, + msm_mux_i2s0_sck, + msm_mux_i2s0_ws, + msm_mux_ibi_i3c, + msm_mux_jitter_bist, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0, + msm_mux_mdp_vsync1, + msm_mux_mdp_vsync2, + msm_mux_mdp_vsync3, + msm_mux_pcie0_clkreqn, + msm_mux_pcie1_clkreqn, + msm_mux_phase_flag0, + msm_mux_phase_flag1, + msm_mux_phase_flag10, + msm_mux_phase_flag11, + msm_mux_phase_flag12, + msm_mux_phase_flag13, + msm_mux_phase_flag14, + msm_mux_phase_flag15, + msm_mux_phase_flag16, + msm_mux_phase_flag17, + msm_mux_phase_flag18, + msm_mux_phase_flag19, + msm_mux_phase_flag2, + msm_mux_phase_flag20, + msm_mux_phase_flag21, + msm_mux_phase_flag22, + msm_mux_phase_flag23, + msm_mux_phase_flag24, + msm_mux_phase_flag25, + msm_mux_phase_flag26, + msm_mux_phase_flag27, + msm_mux_phase_flag28, + msm_mux_phase_flag29, + msm_mux_phase_flag3, + msm_mux_phase_flag30, + msm_mux_phase_flag31, + msm_mux_phase_flag4, + msm_mux_phase_flag5, + msm_mux_phase_flag6, + msm_mux_phase_flag7, + msm_mux_phase_flag8, + msm_mux_phase_flag9, + msm_mux_pll_bist, + msm_mux_pll_clk, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_qdss_cti, + msm_mux_qdss_gpio, + msm_mux_qdss_gpio0, + msm_mux_qdss_gpio1, + msm_mux_qdss_gpio10, + msm_mux_qdss_gpio11, + msm_mux_qdss_gpio12, + msm_mux_qdss_gpio13, + msm_mux_qdss_gpio14, + msm_mux_qdss_gpio15, + msm_mux_qdss_gpio2, + msm_mux_qdss_gpio3, + msm_mux_qdss_gpio4, + msm_mux_qdss_gpio5, + msm_mux_qdss_gpio6, + msm_mux_qdss_gpio7, + msm_mux_qdss_gpio8, + msm_mux_qdss_gpio9, + msm_mux_qspi0, + msm_mux_qspi1, + msm_mux_qspi2, + msm_mux_qspi3, + msm_mux_qspi_clk, + msm_mux_qspi_cs0, + msm_mux_qspi_cs1, + msm_mux_qup0, + msm_mux_qup1, + msm_mux_qup2, + msm_mux_qup3, + msm_mux_qup4, + msm_mux_qup5, + msm_mux_qup6, + msm_mux_qup7, + msm_mux_qup8, + msm_mux_qup9, + msm_mux_qup10, + msm_mux_qup11, + msm_mux_tb_trig, + msm_mux_tgu_ch0, + msm_mux_tgu_ch1, + msm_mux_tgu_ch2, + msm_mux_tgu_ch3, + msm_mux_tmess_prng0, + msm_mux_tmess_prng1, + msm_mux_tmess_prng2, + msm_mux_tmess_prng3, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_usb0_phy, + msm_mux_vsense_trigger, + 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", "gpio119", "gpio120", "gpio121", "gpio122", + "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128", + "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134", + "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140", + "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146", + "gpio147", "gpio148", "gpio149", "gpio150", "gpio151", "gpio152", + "gpio153", "gpio154", "gpio155", +}; + +static const char * const aoss_cti_groups[] = { + "gpio20", "gpio21", "gpio22", "gpio23", +}; + +static const char * const atest_char_groups[] = { + "gpio45", +}; + +static const char * const atest_char0_groups[] = { + "gpio90", +}; + +static const char * const atest_char1_groups[] = { + "gpio89", +}; + +static const char * const atest_char2_groups[] = { + "gpio88", +}; + +static const char * const atest_char3_groups[] = { + "gpio87", +}; + +static const char * const atest_usb0_groups[] = { + "gpio26", +}; + +static const char * const atest_usb00_groups[] = { + "gpio110", +}; + +static const char * const atest_usb01_groups[] = { + "gpio109", +}; + +static const char * const atest_usb02_groups[] = { + "gpio27", +}; + +static const char * const atest_usb03_groups[] = { + "gpio60", +}; + +static const char * const audio_ref_groups[] = { + "gpio103", +}; + +static const char * const cam_mclk_groups[] = { + "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", + "gpio76", +}; + +static const char * const cci_async_groups[] = { + "gpio80", "gpio81", "gpio82", +}; + +static const char * const cci_i2c_groups[] = { + "gpio67", "gpio68", "gpio78", "gpio79", "gpio80", "gpio81", "gpio83", + "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", + "gpio91", "gpio92", +}; + +static const char * const cci_timer0_groups[] = { + "gpio77", +}; + +static const char * const cci_timer1_groups[] = { + "gpio78", +}; + +static const char * const cci_timer2_groups[] = { + "gpio79", +}; + +static const char * const cci_timer3_groups[] = { + "gpio80", +}; + +static const char * const cci_timer4_groups[] = { + "gpio81", +}; + +static const char * const cri_trng_groups[] = { + "gpio60", +}; + +static const char * const cri_trng0_groups[] = { + "gpio70", +}; + +static const char * const cri_trng1_groups[] = { + "gpio71", +}; + +static const char * const dbg_out_groups[] = { + "gpio59", +}; + +static const char * const ddr_bist_groups[] = { + "gpio4", "gpio5", "gpio100", "gpio103", +}; + +static const char * const ddr_pxi0_groups[] = { + "gpio56", "gpio57", +}; + +static const char * const ddr_pxi1_groups[] = { + "gpio41", "gpio45", +}; + +static const char * const ddr_pxi2_groups[] = { + "gpio48", "gpio55", +}; + +static const char * const ddr_pxi3_groups[] = { + "gpio46", "gpio47", +}; + +static const char * const dp0_hot_groups[] = { + "gpio35", "gpio103", +}; + +static const char * const ext_mclk0_groups[] = { + "gpio104", +}; + +static const char * const ext_mclk1_groups[] = { + "gpio103", +}; + +static const char * const gcc_gp1_groups[] = { + "gpio129", "gpio132", +}; + +static const char * const gcc_gp2_groups[] = { + "gpio130", "gpio135", +}; + +static const char * const gcc_gp3_groups[] = { + "gpio131", "gpio136", +}; + +static const char * const host2wlan_sol_groups[] = { + "gpio111", +}; + +static const char * const i2s0_data0_groups[] = { + "gpio106", +}; + +static const char * const i2s0_data1_groups[] = { + "gpio107", +}; + +static const char * const i2s0_sck_groups[] = { + "gpio105", +}; + +static const char * const i2s0_ws_groups[] = { + "gpio108", +}; + +static const char * const ibi_i3c_groups[] = { + "gpio0", "gpio1", "gpio91", "gpio92", +}; + +static const char * const jitter_bist_groups[] = { + "gpio0", +}; + +static const char * const mdp_vsync_groups[] = { + "gpio12", "gpio13", "gpio41", "gpio49", "gpio50", +}; + +static const char * const mdp_vsync0_groups[] = { + "gpio49", +}; + +static const char * const mdp_vsync1_groups[] = { + "gpio49", +}; + +static const char * const mdp_vsync2_groups[] = { + "gpio50", +}; + +static const char * const mdp_vsync3_groups[] = { + "gpio50", +}; + +static const char * const pcie0_clkreqn_groups[] = { + "gpio56", +}; + +static const char * const pcie1_clkreqn_groups[] = { + "gpio59", +}; + +static const char * const phase_flag0_groups[] = { + "gpio133", +}; + +static const char * const phase_flag1_groups[] = { + "gpio128", +}; + +static const char * const phase_flag10_groups[] = { + "gpio94", +}; + +static const char * const phase_flag11_groups[] = { + "gpio93", +}; + +static const char * const phase_flag12_groups[] = { + "gpio134", +}; + +static const char * const phase_flag13_groups[] = { + "gpio139", +}; + +static const char * const phase_flag14_groups[] = { + "gpio138", +}; + +static const char * const phase_flag15_groups[] = { + "gpio137", +}; + +static const char * const phase_flag16_groups[] = { + "gpio62", +}; + +static const char * const phase_flag17_groups[] = { + "gpio61", +}; + +static const char * const phase_flag18_groups[] = { + "gpio41", +}; + +static const char * const phase_flag19_groups[] = { + "gpio23", +}; + +static const char * const phase_flag2_groups[] = { + "gpio127", +}; + +static const char * const phase_flag20_groups[] = { + "gpio22", +}; + +static const char * const phase_flag21_groups[] = { + "gpio21", +}; + +static const char * const phase_flag22_groups[] = { + "gpio19", +}; + +static const char * const phase_flag23_groups[] = { + "gpio18", +}; + +static const char * const phase_flag24_groups[] = { + "gpio17", +}; + +static const char * const phase_flag25_groups[] = { + "gpio16", +}; + +static const char * const phase_flag26_groups[] = { + "gpio13", +}; + +static const char * const phase_flag27_groups[] = { + "gpio12", +}; + +static const char * const phase_flag28_groups[] = { + "gpio3", +}; + +static const char * const phase_flag29_groups[] = { + "gpio2", +}; + +static const char * const phase_flag3_groups[] = { + "gpio126", +}; + +static const char * const phase_flag30_groups[] = { + "gpio149", +}; + +static const char * const phase_flag31_groups[] = { + "gpio148", +}; + +static const char * const phase_flag4_groups[] = { + "gpio151", +}; + +static const char * const phase_flag5_groups[] = { + "gpio150", +}; + +static const char * const phase_flag6_groups[] = { + "gpio98", +}; + +static const char * const phase_flag7_groups[] = { + "gpio97", +}; + +static const char * const phase_flag8_groups[] = { + "gpio96", +}; + +static const char * const phase_flag9_groups[] = { + "gpio95", +}; + +static const char * const pll_bist_groups[] = { + "gpio8", +}; + +static const char * const pll_clk_groups[] = { + "gpio54", +}; + +static const char * const prng_rosc0_groups[] = { + "gpio72", +}; + +static const char * const prng_rosc1_groups[] = { + "gpio73", +}; + +static const char * const prng_rosc2_groups[] = { + "gpio74", +}; + +static const char * const prng_rosc3_groups[] = { + "gpio75", +}; + +static const char * const qdss_cti_groups[] = { + "gpio28", "gpio29", "gpio36", "gpio37", "gpio38", "gpio38", "gpio47", + "gpio48", "gpio53", "gpio53", "gpio105", "gpio106", "gpio154", + "gpio155", +}; + +static const char * const qdss_gpio_groups[] = { + "gpio89", "gpio90", "gpio109", "gpio110", +}; + +static const char * const qdss_gpio0_groups[] = { + "gpio24", "gpio65", +}; + +static const char * const qdss_gpio1_groups[] = { + "gpio25", "gpio66", +}; + +static const char * const qdss_gpio10_groups[] = { + "gpio63", "gpio83", +}; + +static const char * const qdss_gpio11_groups[] = { + "gpio64", "gpio84", +}; + +static const char * const qdss_gpio12_groups[] = { + "gpio39", "gpio85", +}; + +static const char * const qdss_gpio13_groups[] = { + "gpio10", "gpio86", +}; + +static const char * const qdss_gpio14_groups[] = { + "gpio45", "gpio87", +}; + +static const char * const qdss_gpio15_groups[] = { + "gpio11", "gpio88", +}; + +static const char * const qdss_gpio2_groups[] = { + "gpio26", "gpio67", +}; + +static const char * const qdss_gpio3_groups[] = { + "gpio27", "gpio68", +}; + +static const char * const qdss_gpio4_groups[] = { + "gpio30", "gpio77", +}; + +static const char * const qdss_gpio5_groups[] = { + "gpio31", "gpio78", +}; + +static const char * const qdss_gpio6_groups[] = { + "gpio4", "gpio79", +}; + +static const char * const qdss_gpio7_groups[] = { + "gpio5", "gpio80", +}; + +static const char * const qdss_gpio8_groups[] = { + "gpio6", "gpio81", +}; + +static const char * const qdss_gpio9_groups[] = { + "gpio7", "gpio82", +}; + +static const char * const qspi0_groups[] = { + "gpio32", +}; + +static const char * const qspi1_groups[] = { + "gpio33", +}; + +static const char * const qspi2_groups[] = { + "gpio36", +}; + +static const char * const qspi3_groups[] = { + "gpio37", +}; + +static const char * const qspi_clk_groups[] = { + "gpio34", +}; + +static const char * const qspi_cs0_groups[] = { + "gpio35", +}; + +static const char * const qspi_cs1_groups[] = { + "gpio38", +}; + +static const char * const qup0_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio93", +}; + +static const char * const qup1_groups[] = { + "gpio2", "gpio3", "gpio61", "gpio62", +}; + +static const char * const qup2_groups[] = { + "gpio12", "gpio13", "gpio22", "gpio23", +}; + +static const char * const qup3_groups[] = { + "gpio16", "gpio17", "gpio18", "gpio19", "gpio41", +}; + +static const char * const qup4_groups[] = { + "gpio20", "gpio21", "gpio22", "gpio23", "gpio94", +}; + +static const char * const qup5_groups[] = { + "gpio95", "gpio96", "gpio97", "gpio98", +}; + +static const char * const qup6_groups[] = { + "gpio63", "gpio64", "gpio91", "gpio92", +}; + +static const char * const qup7_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", +}; + +static const char * const qup8_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11", +}; + +static const char * const qup9_groups[] = { + "gpio34", "gpio35", "gpio109", "gpio110", +}; + +static const char * const qup10_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; + +static const char * const qup11_groups[] = { + "gpio14", "gpio15", "gpio28", "gpio30", +}; + +static const char * const tb_trig_groups[] = { + "gpio69", +}; + +static const char * const tgu_ch0_groups[] = { + "gpio20", +}; + +static const char * const tgu_ch1_groups[] = { + "gpio21", +}; + +static const char * const tgu_ch2_groups[] = { + "gpio22", +}; + +static const char * const tgu_ch3_groups[] = { + "gpio23", +}; + +static const char * const tmess_prng0_groups[] = { + "gpio80", +}; + +static const char * const tmess_prng1_groups[] = { + "gpio79", +}; + +static const char * const tmess_prng2_groups[] = { + "gpio83", +}; + +static const char * const tmess_prng3_groups[] = { + "gpio81", +}; + +static const char * const tsense_pwm1_groups[] = { + "gpio86", +}; + +static const char * const tsense_pwm2_groups[] = { + "gpio86", +}; + +static const char * const usb0_phy_groups[] = { + "gpio100", +}; + +static const char * const vsense_trigger_groups[] = { + "gpio36", +}; + +static const struct pinfunction sar2130p_functions[] = { + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(qup0), + MSM_PIN_FUNCTION(ibi_i3c), + MSM_PIN_FUNCTION(jitter_bist), + MSM_PIN_FUNCTION(qup1), + MSM_PIN_FUNCTION(phase_flag29), + MSM_PIN_FUNCTION(phase_flag28), + MSM_PIN_FUNCTION(qup10), + MSM_PIN_FUNCTION(ddr_bist), + MSM_PIN_FUNCTION(qdss_gpio6), + MSM_PIN_FUNCTION(qdss_gpio7), + MSM_PIN_FUNCTION(qdss_gpio8), + MSM_PIN_FUNCTION(qdss_gpio9), + MSM_PIN_FUNCTION(qup8), + MSM_PIN_FUNCTION(pll_bist), + MSM_PIN_FUNCTION(qdss_gpio13), + MSM_PIN_FUNCTION(qdss_gpio15), + MSM_PIN_FUNCTION(qup2), + MSM_PIN_FUNCTION(mdp_vsync), + MSM_PIN_FUNCTION(phase_flag27), + MSM_PIN_FUNCTION(phase_flag26), + MSM_PIN_FUNCTION(qup11), + MSM_PIN_FUNCTION(qup3), + MSM_PIN_FUNCTION(phase_flag25), + MSM_PIN_FUNCTION(phase_flag24), + MSM_PIN_FUNCTION(phase_flag23), + MSM_PIN_FUNCTION(phase_flag22), + MSM_PIN_FUNCTION(qup4), + MSM_PIN_FUNCTION(aoss_cti), + MSM_PIN_FUNCTION(tgu_ch0), + MSM_PIN_FUNCTION(phase_flag21), + MSM_PIN_FUNCTION(tgu_ch1), + MSM_PIN_FUNCTION(phase_flag20), + MSM_PIN_FUNCTION(tgu_ch2), + MSM_PIN_FUNCTION(phase_flag19), + MSM_PIN_FUNCTION(tgu_ch3), + MSM_PIN_FUNCTION(qup7), + MSM_PIN_FUNCTION(qdss_gpio0), + MSM_PIN_FUNCTION(qdss_gpio1), + MSM_PIN_FUNCTION(qdss_gpio2), + MSM_PIN_FUNCTION(atest_usb0), + MSM_PIN_FUNCTION(qdss_gpio3), + MSM_PIN_FUNCTION(atest_usb02), + MSM_PIN_FUNCTION(qdss_cti), + MSM_PIN_FUNCTION(qdss_gpio4), + MSM_PIN_FUNCTION(qdss_gpio5), + MSM_PIN_FUNCTION(qspi0), + MSM_PIN_FUNCTION(qspi1), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qup9), + MSM_PIN_FUNCTION(qspi_cs0), + MSM_PIN_FUNCTION(dp0_hot), + MSM_PIN_FUNCTION(qspi2), + MSM_PIN_FUNCTION(vsense_trigger), + MSM_PIN_FUNCTION(qspi3), + MSM_PIN_FUNCTION(qspi_cs1), + MSM_PIN_FUNCTION(qdss_gpio12), + MSM_PIN_FUNCTION(phase_flag18), + MSM_PIN_FUNCTION(ddr_pxi1), + MSM_PIN_FUNCTION(qdss_gpio14), + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(ddr_pxi3), + MSM_PIN_FUNCTION(ddr_pxi2), + MSM_PIN_FUNCTION(mdp_vsync0), + MSM_PIN_FUNCTION(mdp_vsync1), + MSM_PIN_FUNCTION(mdp_vsync2), + MSM_PIN_FUNCTION(mdp_vsync3), + MSM_PIN_FUNCTION(pll_clk), + MSM_PIN_FUNCTION(pcie0_clkreqn), + MSM_PIN_FUNCTION(ddr_pxi0), + MSM_PIN_FUNCTION(pcie1_clkreqn), + MSM_PIN_FUNCTION(dbg_out), + MSM_PIN_FUNCTION(cri_trng), + MSM_PIN_FUNCTION(atest_usb03), + MSM_PIN_FUNCTION(phase_flag17), + MSM_PIN_FUNCTION(phase_flag16), + MSM_PIN_FUNCTION(qup6), + MSM_PIN_FUNCTION(qdss_gpio10), + MSM_PIN_FUNCTION(qdss_gpio11), + MSM_PIN_FUNCTION(cci_i2c), + MSM_PIN_FUNCTION(cam_mclk), + MSM_PIN_FUNCTION(tb_trig), + MSM_PIN_FUNCTION(cri_trng0), + MSM_PIN_FUNCTION(cri_trng1), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(cci_timer0), + MSM_PIN_FUNCTION(cci_timer1), + MSM_PIN_FUNCTION(cci_timer2), + MSM_PIN_FUNCTION(tmess_prng1), + MSM_PIN_FUNCTION(cci_timer3), + MSM_PIN_FUNCTION(cci_async), + MSM_PIN_FUNCTION(tmess_prng0), + MSM_PIN_FUNCTION(cci_timer4), + MSM_PIN_FUNCTION(tmess_prng3), + MSM_PIN_FUNCTION(tmess_prng2), + MSM_PIN_FUNCTION(tsense_pwm1), + MSM_PIN_FUNCTION(tsense_pwm2), + MSM_PIN_FUNCTION(atest_char3), + MSM_PIN_FUNCTION(atest_char2), + MSM_PIN_FUNCTION(qdss_gpio), + MSM_PIN_FUNCTION(atest_char1), + MSM_PIN_FUNCTION(atest_char0), + MSM_PIN_FUNCTION(phase_flag11), + MSM_PIN_FUNCTION(phase_flag10), + MSM_PIN_FUNCTION(qup5), + MSM_PIN_FUNCTION(phase_flag9), + MSM_PIN_FUNCTION(phase_flag8), + MSM_PIN_FUNCTION(phase_flag7), + MSM_PIN_FUNCTION(phase_flag6), + MSM_PIN_FUNCTION(usb0_phy), + MSM_PIN_FUNCTION(ext_mclk1), + MSM_PIN_FUNCTION(audio_ref), + MSM_PIN_FUNCTION(ext_mclk0), + MSM_PIN_FUNCTION(i2s0_sck), + MSM_PIN_FUNCTION(i2s0_data0), + MSM_PIN_FUNCTION(i2s0_data1), + MSM_PIN_FUNCTION(i2s0_ws), + MSM_PIN_FUNCTION(atest_usb01), + MSM_PIN_FUNCTION(atest_usb00), + MSM_PIN_FUNCTION(host2wlan_sol), + MSM_PIN_FUNCTION(phase_flag3), + MSM_PIN_FUNCTION(phase_flag2), + MSM_PIN_FUNCTION(phase_flag1), + MSM_PIN_FUNCTION(gcc_gp1), + MSM_PIN_FUNCTION(gcc_gp2), + MSM_PIN_FUNCTION(gcc_gp3), + MSM_PIN_FUNCTION(phase_flag0), + MSM_PIN_FUNCTION(phase_flag12), + MSM_PIN_FUNCTION(phase_flag15), + MSM_PIN_FUNCTION(phase_flag14), + MSM_PIN_FUNCTION(phase_flag13), + MSM_PIN_FUNCTION(phase_flag31), + MSM_PIN_FUNCTION(phase_flag30), + MSM_PIN_FUNCTION(phase_flag5), + MSM_PIN_FUNCTION(phase_flag4), +}; + +/* 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 sar2130p_groups[] = { + [0] = PINGROUP(0, qup0, ibi_i3c, jitter_bist, _, _, _, _, _, _), + [1] = PINGROUP(1, qup0, ibi_i3c, _, _, _, _, _, _, _), + [2] = PINGROUP(2, qup0, qup1, phase_flag29, _, _, _, _, _, _), + [3] = PINGROUP(3, qup0, qup1, phase_flag28, _, _, _, _, _, _), + [4] = PINGROUP(4, qup10, ddr_bist, qdss_gpio6, _, _, _, _, _, _), + [5] = PINGROUP(5, qup10, ddr_bist, qdss_gpio7, _, _, _, _, _, _), + [6] = PINGROUP(6, qup10, qdss_gpio8, _, _, _, _, _, _, _), + [7] = PINGROUP(7, qup10, qdss_gpio9, _, _, _, _, _, _, _), + [8] = PINGROUP(8, qup8, pll_bist, _, _, _, _, _, _, _), + [9] = PINGROUP(9, qup8, _, _, _, _, _, _, _, _), + [10] = PINGROUP(10, qup8, qdss_gpio13, _, _, _, _, _, _, _), + [11] = PINGROUP(11, qup8, qdss_gpio15, _, _, _, _, _, _, _), + [12] = PINGROUP(12, qup2, mdp_vsync, phase_flag27, _, _, _, _, _, _), + [13] = PINGROUP(13, qup2, mdp_vsync, phase_flag26, _, _, _, _, _, _), + [14] = PINGROUP(14, qup11, _, _, _, _, _, _, _, _), + [15] = PINGROUP(15, qup11, _, _, _, _, _, _, _, _), + [16] = PINGROUP(16, qup3, phase_flag25, _, _, _, _, _, _, _), + [17] = PINGROUP(17, qup3, phase_flag24, _, _, _, _, _, _, _), + [18] = PINGROUP(18, qup3, phase_flag23, _, _, _, _, _, _, _), + [19] = PINGROUP(19, qup3, phase_flag22, _, _, _, _, _, _, _), + [20] = PINGROUP(20, qup4, aoss_cti, tgu_ch0, _, _, _, _, _, _), + [21] = PINGROUP(21, qup4, aoss_cti, phase_flag21, tgu_ch1, _, _, _, _, _), + [22] = PINGROUP(22, qup4, qup2, aoss_cti, phase_flag20, tgu_ch2, _, _, _, _), + [23] = PINGROUP(23, qup4, qup2, aoss_cti, phase_flag19, tgu_ch3, _, _, _, _), + [24] = PINGROUP(24, qup7, qdss_gpio0, _, _, _, _, _, _, _), + [25] = PINGROUP(25, qup7, qdss_gpio1, _, _, _, _, _, _, _), + [26] = PINGROUP(26, qup7, qdss_gpio2, atest_usb0, _, _, _, _, _, _), + [27] = PINGROUP(27, qup7, qdss_gpio3, atest_usb02, _, _, _, _, _, _), + [28] = PINGROUP(28, qup11, qdss_cti, _, _, _, _, _, _, _), + [29] = PINGROUP(29, qdss_cti, _, _, _, _, _, _, _, _), + [30] = PINGROUP(30, qup11, qdss_gpio4, _, _, _, _, _, _, _), + [31] = PINGROUP(31, qdss_gpio5, _, _, _, _, _, _, _, _), + [32] = PINGROUP(32, qspi0, _, _, _, _, _, _, _, _), + [33] = PINGROUP(33, qspi1, _, _, _, _, _, _, _, _), + [34] = PINGROUP(34, qspi_clk, qup9, _, _, _, _, _, _, _), + [35] = PINGROUP(35, qspi_cs0, qup9, dp0_hot, _, _, _, _, _, _), + [36] = PINGROUP(36, qspi2, qdss_cti, vsense_trigger, _, _, _, _, _, _), + [37] = PINGROUP(37, qspi3, qdss_cti, _, _, _, _, _, _, _), + [38] = PINGROUP(38, qspi_cs1, qdss_cti, qdss_cti, _, _, _, _, _, _), + [39] = PINGROUP(39, qdss_gpio12, _, _, _, _, _, _, _, _), + [40] = PINGROUP(40, _, _, _, _, _, _, _, _, _), + [41] = PINGROUP(41, qup3, mdp_vsync, phase_flag18, _, ddr_pxi1, _, _, _, _), + [42] = PINGROUP(42, _, _, _, _, _, _, _, _, _), + [43] = PINGROUP(43, _, _, _, _, _, _, _, _, _), + [44] = PINGROUP(44, _, _, _, _, _, _, _, _, _), + [45] = PINGROUP(45, qdss_gpio14, ddr_pxi1, atest_char, _, _, _, _, _, _), + [46] = PINGROUP(46, ddr_pxi3, _, _, _, _, _, _, _, _), + [47] = PINGROUP(47, qdss_cti, ddr_pxi3, _, _, _, _, _, _, _), + [48] = PINGROUP(48, qdss_cti, ddr_pxi2, _, _, _, _, _, _, _), + [49] = PINGROUP(49, mdp_vsync, mdp_vsync0, mdp_vsync1, _, _, _, _, _, _), + [50] = PINGROUP(50, mdp_vsync, mdp_vsync2, mdp_vsync3, _, _, _, _, _, _), + [51] = PINGROUP(51, _, _, _, _, _, _, _, _, _), + [52] = PINGROUP(52, _, _, _, _, _, _, _, _, _), + [53] = PINGROUP(53, qdss_cti, qdss_cti, _, _, _, _, _, _, _), + [54] = PINGROUP(54, pll_clk, _, _, _, _, _, _, _, _), + [55] = PINGROUP(55, _, ddr_pxi2, _, _, _, _, _, _, _), + [56] = PINGROUP(56, pcie0_clkreqn, _, ddr_pxi0, _, _, _, _, _, _), + [57] = PINGROUP(57, ddr_pxi0, _, _, _, _, _, _, _, _), + [58] = PINGROUP(58, _, _, _, _, _, _, _, _, _), + [59] = PINGROUP(59, pcie1_clkreqn, dbg_out, _, _, _, _, _, _, _), + [60] = PINGROUP(60, cri_trng, atest_usb03, _, _, _, _, _, _, _), + [61] = PINGROUP(61, qup1, phase_flag17, _, _, _, _, _, _, _), + [62] = PINGROUP(62, qup1, phase_flag16, _, _, _, _, _, _, _), + [63] = PINGROUP(63, qup6, qdss_gpio10, _, _, _, _, _, _, _), + [64] = PINGROUP(64, qup6, qdss_gpio11, _, _, _, _, _, _, _), + [65] = PINGROUP(65, qdss_gpio0, _, _, _, _, _, _, _, _), + [66] = PINGROUP(66, qdss_gpio1, _, _, _, _, _, _, _, _), + [67] = PINGROUP(67, cci_i2c, qdss_gpio2, _, _, _, _, _, _, _), + [68] = PINGROUP(68, cci_i2c, qdss_gpio3, _, _, _, _, _, _, _), + [69] = PINGROUP(69, cam_mclk, tb_trig, _, _, _, _, _, _, _), + [70] = PINGROUP(70, cam_mclk, cri_trng0, _, _, _, _, _, _, _), + [71] = PINGROUP(71, cam_mclk, cri_trng1, _, _, _, _, _, _, _), + [72] = PINGROUP(72, cam_mclk, prng_rosc0, _, _, _, _, _, _, _), + [73] = PINGROUP(73, cam_mclk, prng_rosc1, _, _, _, _, _, _, _), + [74] = PINGROUP(74, cam_mclk, prng_rosc2, _, _, _, _, _, _, _), + [75] = PINGROUP(75, cam_mclk, prng_rosc3, _, _, _, _, _, _, _), + [76] = PINGROUP(76, cam_mclk, _, _, _, _, _, _, _, _), + [77] = PINGROUP(77, cci_timer0, qdss_gpio4, _, _, _, _, _, _, _), + [78] = PINGROUP(78, cci_timer1, cci_i2c, qdss_gpio5, _, _, _, _, _, _), + [79] = PINGROUP(79, cci_timer2, cci_i2c, tmess_prng1, qdss_gpio6, _, _, _, _, _), + [80] = PINGROUP(80, cci_timer3, cci_i2c, cci_async, tmess_prng0, qdss_gpio7, _, _, _, _), + [81] = PINGROUP(81, cci_timer4, cci_i2c, cci_async, tmess_prng3, qdss_gpio8, _, _, _, _), + [82] = PINGROUP(82, cci_async, qdss_gpio9, _, _, _, _, _, _, _), + [83] = PINGROUP(83, cci_i2c, tmess_prng2, qdss_gpio10, _, _, _, _, _, _), + [84] = PINGROUP(84, cci_i2c, qdss_gpio11, _, _, _, _, _, _, _), + [85] = PINGROUP(85, cci_i2c, qdss_gpio12, _, _, _, _, _, _, _), + [86] = PINGROUP(86, cci_i2c, qdss_gpio13, tsense_pwm1, tsense_pwm2, _, _, _, _, _), + [87] = PINGROUP(87, cci_i2c, qdss_gpio14, atest_char3, _, _, _, _, _, _), + [88] = PINGROUP(88, cci_i2c, qdss_gpio15, atest_char2, _, _, _, _, _, _), + [89] = PINGROUP(89, cci_i2c, qdss_gpio, atest_char1, _, _, _, _, _, _), + [90] = PINGROUP(90, cci_i2c, qdss_gpio, atest_char0, _, _, _, _, _, _), + [91] = PINGROUP(91, cci_i2c, qup6, ibi_i3c, _, _, _, _, _, _), + [92] = PINGROUP(92, cci_i2c, qup6, ibi_i3c, _, _, _, _, _, _), + [93] = PINGROUP(93, qup0, phase_flag11, _, _, _, _, _, _, _), + [94] = PINGROUP(94, qup4, phase_flag10, _, _, _, _, _, _, _), + [95] = PINGROUP(95, qup5, phase_flag9, _, _, _, _, _, _, _), + [96] = PINGROUP(96, qup5, phase_flag8, _, _, _, _, _, _, _), + [97] = PINGROUP(97, qup5, phase_flag7, _, _, _, _, _, _, _), + [98] = PINGROUP(98, qup5, phase_flag6, _, _, _, _, _, _, _), + [99] = PINGROUP(99, _, _, _, _, _, _, _, _, _), + [100] = PINGROUP(100, usb0_phy, ddr_bist, _, _, _, _, _, _, _), + [101] = PINGROUP(101, _, _, _, _, _, _, _, _, _), + [102] = PINGROUP(102, _, _, _, _, _, _, _, _, _), + [103] = PINGROUP(103, ext_mclk1, audio_ref, dp0_hot, ddr_bist, _, _, _, _, _), + [104] = PINGROUP(104, ext_mclk0, _, _, _, _, _, _, _, _), + [105] = PINGROUP(105, i2s0_sck, _, qdss_cti, _, _, _, _, _, _), + [106] = PINGROUP(106, i2s0_data0, _, qdss_cti, _, _, _, _, _, _), + [107] = PINGROUP(107, i2s0_data1, _, _, _, _, _, _, _, _), + [108] = PINGROUP(108, i2s0_ws, _, _, _, _, _, _, _, _), + [109] = PINGROUP(109, qup9, qdss_gpio, atest_usb01, _, _, _, _, _, _), + [110] = PINGROUP(110, qup9, qdss_gpio, atest_usb00, _, _, _, _, _, _), + [111] = PINGROUP(111, host2wlan_sol, _, _, _, _, _, _, _, _), + [112] = PINGROUP(112, _, _, _, _, _, _, _, _, _), + [113] = PINGROUP(113, _, _, _, _, _, _, _, _, _), + [114] = PINGROUP(114, _, _, _, _, _, _, _, _, _), + [115] = PINGROUP(115, _, _, _, _, _, _, _, _, _), + [116] = PINGROUP(116, _, _, _, _, _, _, _, _, _), + [117] = PINGROUP(117, _, _, _, _, _, _, _, _, _), + [118] = PINGROUP(118, _, _, _, _, _, _, _, _, _), + [119] = PINGROUP(119, _, _, _, _, _, _, _, _, _), + [120] = PINGROUP(120, _, _, _, _, _, _, _, _, _), + [121] = PINGROUP(121, _, _, _, _, _, _, _, _, _), + [122] = PINGROUP(122, _, _, _, _, _, _, _, _, _), + [123] = PINGROUP(123, _, _, _, _, _, _, _, _, _), + [124] = PINGROUP(124, _, _, _, _, _, _, _, _, _), + [125] = PINGROUP(125, _, _, _, _, _, _, _, _, _), + [126] = PINGROUP(126, phase_flag3, _, _, _, _, _, _, _, _), + [127] = PINGROUP(127, phase_flag2, _, _, _, _, _, _, _, _), + [128] = PINGROUP(128, phase_flag1, _, _, _, _, _, _, _, _), + [129] = PINGROUP(129, gcc_gp1, _, _, _, _, _, _, _, _), + [130] = PINGROUP(130, gcc_gp2, _, _, _, _, _, _, _, _), + [131] = PINGROUP(131, gcc_gp3, _, _, _, _, _, _, _, _), + [132] = PINGROUP(132, gcc_gp1, _, _, _, _, _, _, _, _), + [133] = PINGROUP(133, phase_flag0, _, _, _, _, _, _, _, _), + [134] = PINGROUP(134, phase_flag12, _, _, _, _, _, _, _, _), + [135] = PINGROUP(135, gcc_gp2, _, _, _, _, _, _, _, _), + [136] = PINGROUP(136, gcc_gp3, _, _, _, _, _, _, _, _), + [137] = PINGROUP(137, phase_flag15, _, _, _, _, _, _, _, _), + [138] = PINGROUP(138, phase_flag14, _, _, _, _, _, _, _, _), + [139] = PINGROUP(139, phase_flag13, _, _, _, _, _, _, _, _), + [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _), + [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _), + [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _), + [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _), + [144] = PINGROUP(144, _, _, _, _, _, _, _, _, _), + [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _), + [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _), + [147] = PINGROUP(147, _, _, _, _, _, _, _, _, _), + [148] = PINGROUP(148, phase_flag31, _, _, _, _, _, _, _, _), + [149] = PINGROUP(149, phase_flag30, _, _, _, _, _, _, _, _), + [150] = PINGROUP(150, phase_flag5, _, _, _, _, _, _, _, _), + [151] = PINGROUP(151, phase_flag4, _, _, _, _, _, _, _, _), + [152] = PINGROUP(152, _, _, _, _, _, _, _, _, _), + [153] = PINGROUP(153, _, _, _, _, _, _, _, _, _), + [154] = PINGROUP(154, qdss_cti, _, _, _, _, _, _, _, _), + [155] = PINGROUP(155, qdss_cti, _, _, _, _, _, _, _, _), + [156] = SDC_QDSD_PINGROUP(sdc1_rclk, 0xa1000, 0, 0), + [157] = SDC_QDSD_PINGROUP(sdc1_clk, 0xa0000, 13, 6), + [158] = SDC_QDSD_PINGROUP(sdc1_cmd, 0xa0000, 11, 3), + [159] = SDC_QDSD_PINGROUP(sdc1_data, 0xa0000, 9, 0), +}; + +static const struct msm_gpio_wakeirq_map sar2130p_pdc_map[] = { + { 0, 50 }, { 3, 68 }, { 6, 88 }, { 7, 55 }, { 10, 66 }, { 11, 96 }, + { 12, 48 }, { 13, 49 }, { 15, 62 }, { 18, 57 }, { 19, 59 }, { 23, 51 }, + { 27, 74 }, { 28, 67 }, { 29, 84 }, { 30, 58 }, { 31, 94 }, { 32, 60 }, + { 33, 61 }, { 35, 69 }, { 37, 70 }, { 38, 64 }, { 39, 65 }, { 40, 63 }, + { 41, 92 }, { 42, 82 }, { 44, 83 }, { 45, 43 }, { 46, 72 }, { 47, 45 }, + { 48, 44 }, { 49, 71 }, { 50, 87 }, { 53, 77 }, { 54, 78 }, + { 55, 106 }, { 56, 79 }, { 57, 80 }, { 58, 107 }, { 59, 81 }, + { 60, 89 }, { 61, 54 }, { 62, 73 }, { 63, 93 }, { 64, 86 }, { 65, 75 }, + { 67, 42 }, { 68, 76 }, { 76, 116 }, { 77, 12 }, { 83, 13 }, + { 91, 90 }, { 94, 95 }, { 95, 91 }, { 98, 47 }, { 100, 85 }, + { 101, 52 }, { 102, 53 }, { 103, 97 }, { 104, 98 }, { 105, 99 }, + { 106, 100 }, { 107, 101 }, { 108, 102 }, { 109, 103 }, { 111, 104 }, + { 113, 46 }, { 114, 56 }, { 115, 108 }, { 116, 109 }, { 117, 110 }, + { 118, 111 }, { 121, 112 }, { 122, 113 }, { 124, 114 }, { 127, 115 }, + { 132, 118 }, { 134, 119 }, { 135, 120 }, { 136, 121 }, { 139, 122 }, + { 140, 123 }, { 141, 124 }, { 143, 128 }, { 144, 129 }, { 145, 130 }, + { 146, 131 }, { 148, 132 }, { 150, 133 }, { 151, 134 }, { 153, 135 }, + { 155, 137 }, +}; + +static const struct msm_pinctrl_soc_data sar2130p_tlmm = { + .pins = sar2130p_pins, + .npins = ARRAY_SIZE(sar2130p_pins), + .functions = sar2130p_functions, + .nfunctions = ARRAY_SIZE(sar2130p_functions), + .groups = sar2130p_groups, + .ngroups = ARRAY_SIZE(sar2130p_groups), + .ngpios = 156, + .wakeirq_map = sar2130p_pdc_map, + .nwakeirq_map = ARRAY_SIZE(sar2130p_pdc_map), +}; + +static int sar2130p_tlmm_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &sar2130p_tlmm); +} + +static const struct of_device_id sar2130p_tlmm_of_match[] = { + { .compatible = "qcom,sar2130p-tlmm", .data = &sar2130p_tlmm}, + { }, +}; +MODULE_DEVICE_TABLE(of, sar2130p_tlmm_of_match); + +static struct platform_driver sar2130p_tlmm_driver = { + .driver = { + .name = "sar2130p-tlmm", + .of_match_table = sar2130p_tlmm_of_match, + }, + .probe = sar2130p_tlmm_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init sar2130p_tlmm_init(void) +{ + return platform_driver_register(&sar2130p_tlmm_driver); +} +arch_initcall(sar2130p_tlmm_init); + +static void __exit sar2130p_tlmm_exit(void) +{ + platform_driver_unregister(&sar2130p_tlmm_driver); +} +module_exit(sar2130p_tlmm_exit); + +MODULE_DESCRIPTION("QTI SAR2130P TLMM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/qcom/pinctrl-sc7180.c b/drivers/pinctrl/qcom/pinctrl-sc7180.c index c27aaa599b917a..6eb0c73791c0bc 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7180.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7180.c @@ -1159,7 +1159,7 @@ static struct platform_driver sc7180_pinctrl_driver = { .of_match_table = sc7180_pinctrl_of_match, }, .probe = sc7180_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sc7180_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c index 6bb39812e1d8b3..1161f0a91a002a 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c @@ -142,7 +142,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c index c2db663e396eb4..0c10eeb60b55e7 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7280.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c @@ -1505,7 +1505,7 @@ static struct platform_driver sc7280_pinctrl_driver = { .of_match_table = sc7280_pinctrl_of_match, }, .probe = sc7280_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sc7280_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sc8180x.c b/drivers/pinctrl/qcom/pinctrl-sc8180x.c index cfa7c8be9770c9..d6a79ad41a40a8 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc8180x.c +++ b/drivers/pinctrl/qcom/pinctrl-sc8180x.c @@ -1720,7 +1720,7 @@ static struct platform_driver sc8180x_pinctrl_driver = { .acpi_match_table = sc8180x_pinctrl_acpi_match, }, .probe = sc8180x_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sc8180x_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c index c0369baf339896..0e839b6aaaf4bd 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c @@ -179,7 +179,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c index 4b1c49697698de..96f4fb5a5d297f 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc8280xp.c +++ b/drivers/pinctrl/qcom/pinctrl-sc8280xp.c @@ -1926,7 +1926,7 @@ static struct platform_driver sc8280xp_pinctrl_driver = { .of_match_table = sc8280xp_pinctrl_of_match, }, .probe = sc8280xp_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sc8280xp_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660.c b/drivers/pinctrl/qcom/pinctrl-sdm660.c index b93837c00954ae..907e4ffca5e7df 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm660.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm660.c @@ -1442,7 +1442,7 @@ static struct platform_driver sdm660_pinctrl_driver = { .of_match_table = sdm660_pinctrl_of_match, }, .probe = sdm660_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sdm660_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c index 894c042cb52499..c76183ba95e174 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm670.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c @@ -1337,7 +1337,7 @@ static struct platform_driver sdm670_pinctrl_driver = { .of_match_table = sdm670_pinctrl_of_match, }, .probe = sdm670_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sdm670_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c index 3f3265e0018d66..cc05c415ed1551 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm845.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c @@ -1351,7 +1351,7 @@ static struct platform_driver sdm845_pinctrl_driver = { .acpi_match_table = ACPI_PTR(sdm845_pinctrl_acpi_match), }, .probe = sdm845_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sdm845_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdx55.c b/drivers/pinctrl/qcom/pinctrl-sdx55.c index c88b8bfcacb6a7..8826db9d21d04c 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdx55.c +++ b/drivers/pinctrl/qcom/pinctrl-sdx55.c @@ -990,7 +990,7 @@ static struct platform_driver sdx55_pinctrl_driver = { .of_match_table = sdx55_pinctrl_of_match, }, .probe = sdx55_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sdx55_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdx65.c b/drivers/pinctrl/qcom/pinctrl-sdx65.c index bd44ec0fcab43c..f6f319c997fc7a 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdx65.c +++ b/drivers/pinctrl/qcom/pinctrl-sdx65.c @@ -939,7 +939,7 @@ static struct platform_driver sdx65_pinctrl_driver = { .of_match_table = sdx65_pinctrl_of_match, }, .probe = sdx65_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sdx65_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sdx75.c b/drivers/pinctrl/qcom/pinctrl-sdx75.c index 396f6fc779a2e5..3cfe8c7f04df81 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdx75.c +++ b/drivers/pinctrl/qcom/pinctrl-sdx75.c @@ -1124,7 +1124,7 @@ static struct platform_driver sdx75_pinctrl_driver = { .of_match_table = sdx75_pinctrl_of_match, }, .probe = sdx75_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sdx75_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c index 2d2c636a3e2073..c0e178be9cfc3e 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm4250-lpass-lpi.c @@ -227,7 +227,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sm4450.c b/drivers/pinctrl/qcom/pinctrl-sm4450.c index 27317b86d83592..622f20e6f6f859 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm4450.c +++ b/drivers/pinctrl/qcom/pinctrl-sm4450.c @@ -994,7 +994,7 @@ static struct platform_driver sm4450_tlmm_driver = { .of_match_table = sm4450_tlmm_of_match, }, .probe = sm4450_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; MODULE_DEVICE_TABLE(of, sm4450_tlmm_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c index 316d6fc69131b5..b7d9186861a2ff 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c @@ -147,7 +147,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sm6115.c b/drivers/pinctrl/qcom/pinctrl-sm6115.c index 7ce04144b6ed3e..4e91c75ad95248 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6115.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6115.c @@ -907,7 +907,7 @@ static struct platform_driver sm6115_tlmm_driver = { .of_match_table = sm6115_tlmm_of_match, }, .probe = sm6115_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm6115_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6125.c b/drivers/pinctrl/qcom/pinctrl-sm6125.c index 65de34c3075946..c188842047aae0 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6125.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6125.c @@ -1266,7 +1266,7 @@ static struct platform_driver sm6125_tlmm_driver = { .of_match_table = sm6125_tlmm_of_match, }, .probe = sm6125_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm6125_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6350.c b/drivers/pinctrl/qcom/pinctrl-sm6350.c index 4aeb1ba43ee3d4..f3828c07b13450 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6350.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6350.c @@ -1373,7 +1373,7 @@ static struct platform_driver sm6350_tlmm_driver = { .of_match_table = sm6350_tlmm_of_match, }, .probe = sm6350_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm6350_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6375.c b/drivers/pinctrl/qcom/pinctrl-sm6375.c index d86630d7125c2a..c82c8516932ea2 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6375.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6375.c @@ -1516,7 +1516,7 @@ static struct platform_driver sm6375_tlmm_driver = { .of_match_table = sm6375_tlmm_of_match, }, .probe = sm6375_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm6375_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c index 095a1ca7584902..3c7fd8af6635b9 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm7150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c @@ -1255,7 +1255,7 @@ static struct platform_driver sm7150_tlmm_driver = { .of_match_table = sm7150_tlmm_of_match, }, .probe = sm7150_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm7150_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8150.c b/drivers/pinctrl/qcom/pinctrl-sm8150.c index f8f5bee74f1dc0..01aea9c70b7a78 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8150.c @@ -1542,7 +1542,7 @@ static struct platform_driver sm8150_pinctrl_driver = { .of_match_table = sm8150_pinctrl_of_match, }, .probe = sm8150_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm8150_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c index 9791d9ba5087c2..64494a86490e2f 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c @@ -140,7 +140,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250.c b/drivers/pinctrl/qcom/pinctrl-sm8250.c index 54fda77bf2968c..e9961a49ff9811 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8250.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8250.c @@ -1351,7 +1351,7 @@ static struct platform_driver sm8250_pinctrl_driver = { .of_match_table = sm8250_pinctrl_of_match, }, .probe = sm8250_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm8250_pinctrl_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c index 5b9a2cb216bd80..7b146b4acfdf42 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c @@ -142,7 +142,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sm8350.c b/drivers/pinctrl/qcom/pinctrl-sm8350.c index ac7f2820f2cbfb..9c69458bd91091 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8350.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8350.c @@ -1642,7 +1642,7 @@ static struct platform_driver sm8350_tlmm_driver = { .of_match_table = sm8350_tlmm_of_match, }, .probe = sm8350_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm8350_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c index a028cbb4994725..439f6541622e92 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c @@ -208,7 +208,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sm8450.c b/drivers/pinctrl/qcom/pinctrl-sm8450.c index 61728671169527..d11bb1ee9e3d8d 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8450.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8450.c @@ -1677,7 +1677,7 @@ static struct platform_driver sm8450_tlmm_driver = { .of_match_table = sm8450_tlmm_of_match, }, .probe = sm8450_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm8450_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c index 852192b044e170..73065919c8c265 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c @@ -216,7 +216,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550.c b/drivers/pinctrl/qcom/pinctrl-sm8550.c index 9184e0183755da..3c847d9cb5d93b 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8550.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8550.c @@ -1762,7 +1762,7 @@ static struct platform_driver sm8550_tlmm_driver = { .of_match_table = sm8550_tlmm_of_match, }, .probe = sm8550_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm8550_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c index 04400c832327a5..f9fcedf5a65d71 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c @@ -223,7 +223,7 @@ static struct platform_driver lpi_pinctrl_driver = { .of_match_table = lpi_pinctrl_of_match, }, .probe = lpi_pinctrl_probe, - .remove_new = lpi_pinctrl_remove, + .remove = lpi_pinctrl_remove, }; module_platform_driver(lpi_pinctrl_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650.c b/drivers/pinctrl/qcom/pinctrl-sm8650.c index adaddd728662f9..104708252d12a8 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm8650.c +++ b/drivers/pinctrl/qcom/pinctrl-sm8650.c @@ -1742,7 +1742,7 @@ static struct platform_driver sm8650_tlmm_driver = { .of_match_table = sm8650_tlmm_of_match, }, .probe = sm8650_tlmm_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init sm8650_tlmm_init(void) diff --git a/drivers/pinctrl/qcom/pinctrl-sm8750.c b/drivers/pinctrl/qcom/pinctrl-sm8750.c new file mode 100644 index 00000000000000..1af11cd95fb0e6 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm8750.c @@ -0,0 +1,1729 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include + +#include "pinctrl-msm.h" + +#define REG_SIZE 0x1000 + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \ + { \ + .grp = PINCTRL_PINGROUP("gpio" #id, \ + gpio##id##_pins, \ + 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, \ + msm_mux_##f10, \ + msm_mux_##f11 /* egpio mode */ \ + }, \ + .nfuncs = 12, \ + .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, \ + .egpio_enable = 12, \ + .egpio_present = 11, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +#define UFS_RESET(pg_name, ctl, io) \ + { \ + .grp = PINCTRL_PINGROUP(#pg_name, \ + pg_name##_pins, \ + ARRAY_SIZE(pg_name##_pins)), \ + .ctl_reg = ctl, \ + .io_reg = io, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +static const struct pinctrl_pin_desc sm8750_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "GPIO_133"), + PINCTRL_PIN(134, "GPIO_134"), + PINCTRL_PIN(135, "GPIO_135"), + PINCTRL_PIN(136, "GPIO_136"), + PINCTRL_PIN(137, "GPIO_137"), + PINCTRL_PIN(138, "GPIO_138"), + PINCTRL_PIN(139, "GPIO_139"), + PINCTRL_PIN(140, "GPIO_140"), + PINCTRL_PIN(141, "GPIO_141"), + PINCTRL_PIN(142, "GPIO_142"), + PINCTRL_PIN(143, "GPIO_143"), + PINCTRL_PIN(144, "GPIO_144"), + PINCTRL_PIN(145, "GPIO_145"), + PINCTRL_PIN(146, "GPIO_146"), + PINCTRL_PIN(147, "GPIO_147"), + PINCTRL_PIN(148, "GPIO_148"), + PINCTRL_PIN(149, "GPIO_149"), + PINCTRL_PIN(150, "GPIO_150"), + PINCTRL_PIN(151, "GPIO_151"), + PINCTRL_PIN(152, "GPIO_152"), + PINCTRL_PIN(153, "GPIO_153"), + PINCTRL_PIN(154, "GPIO_154"), + PINCTRL_PIN(155, "GPIO_155"), + PINCTRL_PIN(156, "GPIO_156"), + PINCTRL_PIN(157, "GPIO_157"), + PINCTRL_PIN(158, "GPIO_158"), + PINCTRL_PIN(159, "GPIO_159"), + PINCTRL_PIN(160, "GPIO_160"), + PINCTRL_PIN(161, "GPIO_161"), + PINCTRL_PIN(162, "GPIO_162"), + PINCTRL_PIN(163, "GPIO_163"), + PINCTRL_PIN(164, "GPIO_164"), + PINCTRL_PIN(165, "GPIO_165"), + PINCTRL_PIN(166, "GPIO_166"), + PINCTRL_PIN(167, "GPIO_167"), + PINCTRL_PIN(168, "GPIO_168"), + PINCTRL_PIN(169, "GPIO_169"), + PINCTRL_PIN(170, "GPIO_170"), + PINCTRL_PIN(171, "GPIO_171"), + PINCTRL_PIN(172, "GPIO_172"), + PINCTRL_PIN(173, "GPIO_173"), + PINCTRL_PIN(174, "GPIO_174"), + PINCTRL_PIN(175, "GPIO_175"), + PINCTRL_PIN(176, "GPIO_176"), + PINCTRL_PIN(177, "GPIO_177"), + PINCTRL_PIN(178, "GPIO_178"), + PINCTRL_PIN(179, "GPIO_179"), + PINCTRL_PIN(180, "GPIO_180"), + PINCTRL_PIN(181, "GPIO_181"), + PINCTRL_PIN(182, "GPIO_182"), + PINCTRL_PIN(183, "GPIO_183"), + PINCTRL_PIN(184, "GPIO_184"), + PINCTRL_PIN(185, "GPIO_185"), + PINCTRL_PIN(186, "GPIO_186"), + PINCTRL_PIN(187, "GPIO_187"), + PINCTRL_PIN(188, "GPIO_188"), + PINCTRL_PIN(189, "GPIO_189"), + PINCTRL_PIN(190, "GPIO_190"), + PINCTRL_PIN(191, "GPIO_191"), + PINCTRL_PIN(192, "GPIO_192"), + PINCTRL_PIN(193, "GPIO_193"), + PINCTRL_PIN(194, "GPIO_194"), + PINCTRL_PIN(195, "GPIO_195"), + PINCTRL_PIN(196, "GPIO_196"), + PINCTRL_PIN(197, "GPIO_197"), + PINCTRL_PIN(198, "GPIO_198"), + PINCTRL_PIN(199, "GPIO_199"), + PINCTRL_PIN(200, "GPIO_200"), + PINCTRL_PIN(201, "GPIO_201"), + PINCTRL_PIN(202, "GPIO_202"), + PINCTRL_PIN(203, "GPIO_203"), + PINCTRL_PIN(204, "GPIO_204"), + PINCTRL_PIN(205, "GPIO_205"), + PINCTRL_PIN(206, "GPIO_206"), + PINCTRL_PIN(207, "GPIO_207"), + PINCTRL_PIN(208, "GPIO_208"), + PINCTRL_PIN(209, "GPIO_209"), + PINCTRL_PIN(210, "GPIO_210"), + PINCTRL_PIN(211, "GPIO_211"), + PINCTRL_PIN(212, "GPIO_212"), + PINCTRL_PIN(213, "GPIO_213"), + PINCTRL_PIN(214, "GPIO_214"), + PINCTRL_PIN(215, "UFS_RESET"), + PINCTRL_PIN(216, "SDC2_CLK"), + PINCTRL_PIN(217, "SDC2_CMD"), + PINCTRL_PIN(218, "SDC2_DATA"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); +DECLARE_MSM_GPIO_PINS(123); +DECLARE_MSM_GPIO_PINS(124); +DECLARE_MSM_GPIO_PINS(125); +DECLARE_MSM_GPIO_PINS(126); +DECLARE_MSM_GPIO_PINS(127); +DECLARE_MSM_GPIO_PINS(128); +DECLARE_MSM_GPIO_PINS(129); +DECLARE_MSM_GPIO_PINS(130); +DECLARE_MSM_GPIO_PINS(131); +DECLARE_MSM_GPIO_PINS(132); +DECLARE_MSM_GPIO_PINS(133); +DECLARE_MSM_GPIO_PINS(134); +DECLARE_MSM_GPIO_PINS(135); +DECLARE_MSM_GPIO_PINS(136); +DECLARE_MSM_GPIO_PINS(137); +DECLARE_MSM_GPIO_PINS(138); +DECLARE_MSM_GPIO_PINS(139); +DECLARE_MSM_GPIO_PINS(140); +DECLARE_MSM_GPIO_PINS(141); +DECLARE_MSM_GPIO_PINS(142); +DECLARE_MSM_GPIO_PINS(143); +DECLARE_MSM_GPIO_PINS(144); +DECLARE_MSM_GPIO_PINS(145); +DECLARE_MSM_GPIO_PINS(146); +DECLARE_MSM_GPIO_PINS(147); +DECLARE_MSM_GPIO_PINS(148); +DECLARE_MSM_GPIO_PINS(149); +DECLARE_MSM_GPIO_PINS(150); +DECLARE_MSM_GPIO_PINS(151); +DECLARE_MSM_GPIO_PINS(152); +DECLARE_MSM_GPIO_PINS(153); +DECLARE_MSM_GPIO_PINS(154); +DECLARE_MSM_GPIO_PINS(155); +DECLARE_MSM_GPIO_PINS(156); +DECLARE_MSM_GPIO_PINS(157); +DECLARE_MSM_GPIO_PINS(158); +DECLARE_MSM_GPIO_PINS(159); +DECLARE_MSM_GPIO_PINS(160); +DECLARE_MSM_GPIO_PINS(161); +DECLARE_MSM_GPIO_PINS(162); +DECLARE_MSM_GPIO_PINS(163); +DECLARE_MSM_GPIO_PINS(164); +DECLARE_MSM_GPIO_PINS(165); +DECLARE_MSM_GPIO_PINS(166); +DECLARE_MSM_GPIO_PINS(167); +DECLARE_MSM_GPIO_PINS(168); +DECLARE_MSM_GPIO_PINS(169); +DECLARE_MSM_GPIO_PINS(170); +DECLARE_MSM_GPIO_PINS(171); +DECLARE_MSM_GPIO_PINS(172); +DECLARE_MSM_GPIO_PINS(173); +DECLARE_MSM_GPIO_PINS(174); +DECLARE_MSM_GPIO_PINS(175); +DECLARE_MSM_GPIO_PINS(176); +DECLARE_MSM_GPIO_PINS(177); +DECLARE_MSM_GPIO_PINS(178); +DECLARE_MSM_GPIO_PINS(179); +DECLARE_MSM_GPIO_PINS(180); +DECLARE_MSM_GPIO_PINS(181); +DECLARE_MSM_GPIO_PINS(182); +DECLARE_MSM_GPIO_PINS(183); +DECLARE_MSM_GPIO_PINS(184); +DECLARE_MSM_GPIO_PINS(185); +DECLARE_MSM_GPIO_PINS(186); +DECLARE_MSM_GPIO_PINS(187); +DECLARE_MSM_GPIO_PINS(188); +DECLARE_MSM_GPIO_PINS(189); +DECLARE_MSM_GPIO_PINS(190); +DECLARE_MSM_GPIO_PINS(191); +DECLARE_MSM_GPIO_PINS(192); +DECLARE_MSM_GPIO_PINS(193); +DECLARE_MSM_GPIO_PINS(194); +DECLARE_MSM_GPIO_PINS(195); +DECLARE_MSM_GPIO_PINS(196); +DECLARE_MSM_GPIO_PINS(197); +DECLARE_MSM_GPIO_PINS(198); +DECLARE_MSM_GPIO_PINS(199); +DECLARE_MSM_GPIO_PINS(200); +DECLARE_MSM_GPIO_PINS(201); +DECLARE_MSM_GPIO_PINS(202); +DECLARE_MSM_GPIO_PINS(203); +DECLARE_MSM_GPIO_PINS(204); +DECLARE_MSM_GPIO_PINS(205); +DECLARE_MSM_GPIO_PINS(206); +DECLARE_MSM_GPIO_PINS(207); +DECLARE_MSM_GPIO_PINS(208); +DECLARE_MSM_GPIO_PINS(209); +DECLARE_MSM_GPIO_PINS(210); +DECLARE_MSM_GPIO_PINS(211); +DECLARE_MSM_GPIO_PINS(212); +DECLARE_MSM_GPIO_PINS(213); +DECLARE_MSM_GPIO_PINS(214); + +static const unsigned int ufs_reset_pins[] = { 215 }; +static const unsigned int sdc2_clk_pins[] = { 216 }; +static const unsigned int sdc2_cmd_pins[] = { 217 }; +static const unsigned int sdc2_data_pins[] = { 218 }; + +enum sm8750_functions { + msm_mux_gpio, + msm_mux_aoss_cti, + msm_mux_atest_char, + msm_mux_atest_usb, + msm_mux_audio_ext_mclk0, + msm_mux_audio_ext_mclk1, + msm_mux_audio_ref_clk, + msm_mux_cam_aon_mclk2, + msm_mux_cam_aon_mclk4, + msm_mux_cam_mclk, + msm_mux_cci_async_in, + msm_mux_cci_i2c_scl, + msm_mux_cci_i2c_sda, + msm_mux_cci_timer, + msm_mux_cmu_rng, + msm_mux_coex_uart1_rx, + msm_mux_coex_uart1_tx, + msm_mux_coex_uart2_rx, + msm_mux_coex_uart2_tx, + msm_mux_dbg_out_clk, + msm_mux_ddr_bist_complete, + msm_mux_ddr_bist_fail, + msm_mux_ddr_bist_start, + msm_mux_ddr_bist_stop, + msm_mux_ddr_pxi0, + msm_mux_ddr_pxi1, + msm_mux_ddr_pxi2, + msm_mux_ddr_pxi3, + msm_mux_dp_hot, + msm_mux_egpio, + msm_mux_gcc_gp1, + msm_mux_gcc_gp2, + msm_mux_gcc_gp3, + msm_mux_gnss_adc0, + msm_mux_gnss_adc1, + msm_mux_i2chub0_se0, + msm_mux_i2chub0_se1, + msm_mux_i2chub0_se2, + msm_mux_i2chub0_se3, + msm_mux_i2chub0_se4, + msm_mux_i2chub0_se5, + msm_mux_i2chub0_se6, + msm_mux_i2chub0_se7, + msm_mux_i2chub0_se8, + msm_mux_i2chub0_se9, + msm_mux_i2s0_data0, + msm_mux_i2s0_data1, + msm_mux_i2s0_sck, + msm_mux_i2s0_ws, + msm_mux_i2s1_data0, + msm_mux_i2s1_data1, + msm_mux_i2s1_sck, + msm_mux_i2s1_ws, + msm_mux_ibi_i3c, + msm_mux_jitter_bist, + msm_mux_mdp_esync0_out, + msm_mux_mdp_esync1_out, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0_out, + msm_mux_mdp_vsync1_out, + msm_mux_mdp_vsync2_out, + msm_mux_mdp_vsync3_out, + msm_mux_mdp_vsync5_out, + msm_mux_mdp_vsync_e, + msm_mux_nav_gpio0, + msm_mux_nav_gpio1, + msm_mux_nav_gpio2, + msm_mux_nav_gpio3, + msm_mux_pcie0_clk_req_n, + msm_mux_phase_flag, + msm_mux_pll_bist_sync, + msm_mux_pll_clk_aux, + msm_mux_prng_rosc0, + msm_mux_prng_rosc1, + msm_mux_prng_rosc2, + msm_mux_prng_rosc3, + msm_mux_qdss_cti, + msm_mux_qlink_big_enable, + msm_mux_qlink_big_request, + msm_mux_qlink_little_enable, + msm_mux_qlink_little_request, + msm_mux_qlink_wmss, + msm_mux_qspi0, + msm_mux_qspi1, + msm_mux_qspi2, + msm_mux_qspi3, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qup1_se0, + msm_mux_qup1_se1, + msm_mux_qup1_se2, + msm_mux_qup1_se3, + msm_mux_qup1_se4, + msm_mux_qup1_se5, + msm_mux_qup1_se6, + msm_mux_qup1_se7, + msm_mux_qup2_se0, + msm_mux_qup2_se1, + msm_mux_qup2_se2, + msm_mux_qup2_se3, + msm_mux_qup2_se4, + msm_mux_qup2_se5, + msm_mux_qup2_se6, + msm_mux_qup2_se7, + msm_mux_sd_write_protect, + msm_mux_sdc40, + msm_mux_sdc41, + msm_mux_sdc42, + msm_mux_sdc43, + msm_mux_sdc4_clk, + msm_mux_sdc4_cmd, + msm_mux_tb_trig_sdc2, + msm_mux_tb_trig_sdc4, + msm_mux_tmess_prng0, + msm_mux_tmess_prng1, + msm_mux_tmess_prng2, + msm_mux_tmess_prng3, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_tsense_pwm3, + msm_mux_tsense_pwm4, + msm_mux_uim0_clk, + msm_mux_uim0_data, + msm_mux_uim0_present, + msm_mux_uim0_reset, + msm_mux_uim1_clk, + msm_mux_uim1_data, + msm_mux_uim1_present, + msm_mux_uim1_reset, + msm_mux_usb1_hs, + msm_mux_usb_phy, + msm_mux_vfr_0, + msm_mux_vfr_1, + msm_mux_vsense_trigger_mirnat, + msm_mux_wcn_sw, + msm_mux_wcn_sw_ctrl, + 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", "gpio119", + "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125", + "gpio126", "gpio127", "gpio128", "gpio129", "gpio130", "gpio131", + "gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137", + "gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143", + "gpio144", "gpio145", "gpio146", "gpio147", "gpio148", "gpio149", + "gpio150", "gpio151", "gpio152", "gpio153", "gpio154", "gpio155", + "gpio156", "gpio157", "gpio158", "gpio159", "gpio160", "gpio161", + "gpio162", "gpio163", "gpio164", "gpio165", "gpio166", "gpio167", + "gpio168", "gpio169", "gpio170", "gpio171", "gpio172", "gpio173", + "gpio174", "gpio175", "gpio176", "gpio177", "gpio178", "gpio179", + "gpio180", "gpio181", "gpio182", "gpio183", "gpio184", "gpio185", + "gpio186", "gpio187", "gpio188", "gpio189", "gpio190", "gpio191", + "gpio192", "gpio193", "gpio194", "gpio195", "gpio196", "gpio197", + "gpio198", "gpio199", "gpio200", "gpio201", "gpio202", "gpio203", + "gpio204", "gpio205", "gpio206", "gpio207", "gpio208", "gpio209", + "gpio210", "gpio211", "gpio212", "gpio213", "gpio214", +}; + +static const char *const egpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", + "gpio6", "gpio7", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio105", "gpio106", "gpio107", "gpio108", + "gpio165", "gpio166", "gpio167", "gpio168", "gpio169", "gpio170", + "gpio171", "gpio172", "gpio173", "gpio174", "gpio175", "gpio176", + "gpio177", "gpio178", "gpio179", "gpio180", "gpio181", "gpio182", + "gpio183", "gpio184", "gpio185", "gpio186", "gpio187", "gpio188", + "gpio189", "gpio190", "gpio191", "gpio192", "gpio193", "gpio194", + "gpio195", "gpio196", "gpio197", "gpio198", "gpio199", "gpio200", + "gpio201", "gpio202", "gpio203", "gpio204", "gpio205", "gpio206", + "gpio207", "gpio208", "gpio209", "gpio210", "gpio211", "gpio212", + "gpio213", "gpio214", +}; + +static const char *const aoss_cti_groups[] = { + "gpio50", "gpio51", "gpio60", "gpio61", +}; + +static const char *const atest_char_groups[] = { + "gpio130", "gpio131", "gpio132", "gpio133", "gpio137", +}; + +static const char *const atest_usb_groups[] = { + "gpio70", "gpio71", "gpio72", "gpio73", "gpio76", +}; + +static const char *const audio_ext_mclk0_groups[] = { + "gpio125", +}; + +static const char *const audio_ext_mclk1_groups[] = { + "gpio124", +}; + +static const char *const audio_ref_clk_groups[] = { + "gpio124", +}; + +static const char *const cam_aon_mclk2_groups[] = { + "gpio91", +}; + +static const char *const cam_aon_mclk4_groups[] = { + "gpio93", +}; + +static const char *const cam_mclk_groups[] = { + "gpio89", "gpio90", "gpio92", "gpio94", "gpio95", "gpio96", +}; + +static const char *const cci_async_in_groups[] = { + "gpio10", "gpio11", "gpio15", +}; + +static const char *const cci_i2c_scl_groups[] = { + "gpio114", "gpio116", "gpio118", "gpio120", "gpio153", "gpio164", +}; + +static const char *const cci_i2c_sda_groups[] = { + "gpio111", "gpio112", "gpio113", "gpio115", "gpio117", "gpio119", +}; + +static const char *const cci_timer_groups[] = { + "gpio109", "gpio110", "gpio111", "gpio163", "gpio164", +}; + +static const char *const cmu_rng_groups[] = { + "gpio40", "gpio41", "gpio41", "gpio43", "gpio148", "gpio149", + "gpio150", "gpio151", +}; + +static const char *const coex_uart1_rx_groups[] = { + "gpio148", +}; + +static const char *const coex_uart1_tx_groups[] = { + "gpio149", +}; + +static const char *const coex_uart2_rx_groups[] = { + "gpio150", +}; + +static const char *const coex_uart2_tx_groups[] = { + "gpio151", +}; + +static const char *const dbg_out_clk_groups[] = { + "gpio78", +}; + +static const char *const ddr_bist_complete_groups[] = { + "gpio44", +}; + +static const char *const ddr_bist_fail_groups[] = { + "gpio40", +}; + +static const char *const ddr_bist_start_groups[] = { + "gpio41", +}; + +static const char *const ddr_bist_stop_groups[] = { + "gpio45", +}; + +static const char *const ddr_pxi0_groups[] = { + "gpio54", "gpio55", +}; + +static const char *const ddr_pxi1_groups[] = { + "gpio44", "gpio45", +}; + +static const char *const ddr_pxi2_groups[] = { + "gpio43", "gpio52", +}; + +static const char *const ddr_pxi3_groups[] = { + "gpio46", "gpio53", +}; + +static const char *const dp_hot_groups[] = { + "gpio47", +}; + +static const char *const gcc_gp1_groups[] = { + "gpio86", "gpio134", +}; + +static const char *const gcc_gp2_groups[] = { + "gpio87", "gpio135", +}; + +static const char *const gcc_gp3_groups[] = { + "gpio88", "gpio136", +}; + +static const char *const gnss_adc0_groups[] = { + "gpio78", "gpio79", +}; + +static const char *const gnss_adc1_groups[] = { + "gpio77", "gpio99", +}; + +static const char *const i2chub0_se0_groups[] = { + "gpio64", "gpio65", +}; + +static const char *const i2chub0_se1_groups[] = { + "gpio66", "gpio67", +}; + +static const char *const i2chub0_se2_groups[] = { + "gpio68", "gpio69", +}; + +static const char *const i2chub0_se3_groups[] = { + "gpio70", "gpio71", +}; + +static const char *const i2chub0_se4_groups[] = { + "gpio72", "gpio73", +}; + +static const char *const i2chub0_se5_groups[] = { + "gpio74", "gpio75", +}; + +static const char *const i2chub0_se6_groups[] = { + "gpio76", "gpio77", +}; + +static const char *const i2chub0_se7_groups[] = { + "gpio82", "gpio83", +}; + +static const char *const i2chub0_se8_groups[] = { + "gpio206", "gpio207", +}; + +static const char *const i2chub0_se9_groups[] = { + "gpio80", "gpio81", +}; + +static const char *const i2s0_data0_groups[] = { + "gpio127", +}; + +static const char *const i2s0_data1_groups[] = { + "gpio128", +}; + +static const char *const i2s0_sck_groups[] = { + "gpio126", +}; + +static const char *const i2s0_ws_groups[] = { + "gpio129", +}; + +static const char *const i2s1_data0_groups[] = { + "gpio122", +}; + +static const char *const i2s1_data1_groups[] = { + "gpio124", +}; + +static const char *const i2s1_sck_groups[] = { + "gpio121", +}; + +static const char *const i2s1_ws_groups[] = { + "gpio123", +}; + +static const char *const ibi_i3c_groups[] = { + "gpio0", "gpio1", "gpio4", "gpio5", "gpio8", "gpio9", + "gpio12", "gpio13", "gpio28", "gpio29", "gpio32", "gpio33", + "gpio36", "gpio37", "gpio48", "gpio49", +}; + +static const char *const jitter_bist_groups[] = { + "gpio73", +}; + +static const char *const mdp_esync0_out_groups[] = { + "gpio88", +}; + +static const char *const mdp_esync1_out_groups[] = { + "gpio100", +}; + +static const char *const mdp_vsync_groups[] = { + "gpio86", "gpio87", "gpio97", "gpio98", +}; + +static const char *const mdp_vsync0_out_groups[] = { + "gpio86", +}; + +static const char *const mdp_vsync1_out_groups[] = { + "gpio86", +}; + +static const char *const mdp_vsync2_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync3_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync5_out_groups[] = { + "gpio87", +}; + +static const char *const mdp_vsync_e_groups[] = { + "gpio88", +}; + +static const char *const nav_gpio0_groups[] = { + "gpio154", +}; + +static const char *const nav_gpio1_groups[] = { + "gpio155", +}; + +static const char *const nav_gpio2_groups[] = { + "gpio152", +}; + +static const char *const nav_gpio3_groups[] = { + "gpio154", +}; + +static const char *const pcie0_clk_req_n_groups[] = { + "gpio103", +}; + +static const char *const phase_flag_groups[] = { + "gpio10", "gpio11", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", + "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", "gpio24", "gpio25", + "gpio26", "gpio27", "gpio28", "gpio29", "gpio31", "gpio64", "gpio65", + "gpio66", "gpio67", "gpio68", "gpio69", "gpio82", "gpio83", "gpio85", + "gpio101", "gpio102", "gpio103", "gpio104", +}; + +static const char *const pll_bist_sync_groups[] = { + "gpio104", +}; + +static const char *const pll_clk_aux_groups[] = { + "gpio95", +}; + +static const char *const prng_rosc0_groups[] = { + "gpio85", +}; + +static const char *const prng_rosc1_groups[] = { + "gpio64", +}; + +static const char *const prng_rosc2_groups[] = { + "gpio65", +}; + +static const char *const prng_rosc3_groups[] = { + "gpio66", +}; + +static const char *const qdss_cti_groups[] = { + "gpio27", "gpio31", "gpio72", "gpio73", "gpio82", "gpio83", "gpio159", + "gpio162", +}; + +static const char *const qlink_big_enable_groups[] = { + "gpio160", +}; + +static const char *const qlink_big_request_groups[] = { + "gpio159", +}; + +static const char *const qlink_little_enable_groups[] = { + "gpio157", +}; + +static const char *const qlink_little_request_groups[] = { + "gpio156", +}; + +static const char *const qlink_wmss_groups[] = { + "gpio158", +}; + +static const char *const qspi0_groups[] = { + "gpio52", +}; + +static const char *const qspi1_groups[] = { + "gpio53", +}; + +static const char *const qspi2_groups[] = { + "gpio55", +}; + +static const char *const qspi3_groups[] = { + "gpio56", +}; + +static const char *const qspi_clk_groups[] = { + "gpio54", +}; + +static const char *const qspi_cs_groups[] = { + "gpio57", "gpio58", +}; + +static const char *const qup1_se0_groups[] = { + "gpio32", "gpio33", "gpio34", "gpio35", +}; + +static const char *const qup1_se1_groups[] = { + "gpio36", "gpio37", "gpio38", "gpio39", +}; + +static const char *const qup1_se2_groups[] = { + "gpio40", "gpio41", "gpio42", "gpio43", "gpio134", "gpio135", "gpio136", +}; + +static const char *const qup1_se3_groups[] = { + "gpio44", "gpio45", "gpio46", "gpio47", +}; + +static const char *const qup1_se4_groups[] = { + "gpio48", "gpio49", "gpio50", "gpio51", +}; + +static const char *const qup1_se5_groups[] = { + "gpio52", "gpio53", "gpio54", "gpio55", +}; + +static const char *const qup1_se6_groups[] = { + "gpio56", "gpio57", "gpio58", "gpio59", +}; + +static const char *const qup1_se7_groups[] = { + "gpio60", "gpio61", "gpio62", "gpio63", +}; + +static const char *const qup2_se0_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; + +static const char *const qup2_se1_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; + +static const char *const qup2_se2_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio15", +}; + +static const char *const qup2_se3_groups[] = { + "gpio12", "gpio13", "gpio14", "gpio15", +}; + +static const char *const qup2_se4_groups[] = { + "gpio16", "gpio17", "gpio18", "gpio19", +}; + +static const char *const qup2_se5_groups[] = { + "gpio20", "gpio21", "gpio22", "gpio23", +}; + +static const char *const qup2_se6_groups[] = { + "gpio24", "gpio25", "gpio26", "gpio27", +}; + +static const char *const qup2_se7_groups[] = { + "gpio28", "gpio29", "gpio30", "gpio31", +}; + +static const char *const sd_write_protect_groups[] = { + "gpio85", +}; + +static const char *const sdc40_groups[] = { + "gpio36", "gpio49", +}; + +static const char *const sdc41_groups[] = { + "gpio37", "gpio51", +}; + +static const char *const sdc42_groups[] = { + "gpio38", "gpio60", +}; + +static const char *const sdc43_groups[] = { + "gpio39", "gpio61", +}; + +static const char *const sdc4_clk_groups[] = { + "gpio50", "gpio150", +}; + +static const char *const sdc4_cmd_groups[] = { + "gpio48", "gpio151", +}; + +static const char *const tb_trig_sdc2_groups[] = { + "gpio89", +}; + +static const char *const tb_trig_sdc4_groups[] = { + "gpio147", +}; + +static const char *const tmess_prng0_groups[] = { + "gpio85", +}; + +static const char *const tmess_prng1_groups[] = { + "gpio64", +}; + +static const char *const tmess_prng2_groups[] = { + "gpio65", +}; + +static const char *const tmess_prng3_groups[] = { + "gpio66", +}; + +static const char *const tsense_pwm1_groups[] = { + "gpio57", +}; + +static const char *const tsense_pwm2_groups[] = { + "gpio57", +}; + +static const char *const tsense_pwm3_groups[] = { + "gpio57", +}; + +static const char *const tsense_pwm4_groups[] = { + "gpio57", +}; + +static const char *const uim0_clk_groups[] = { + "gpio131", +}; + +static const char *const uim0_data_groups[] = { + "gpio130", +}; + +static const char *const uim0_present_groups[] = { + "gpio133", +}; + +static const char *const uim0_reset_groups[] = { + "gpio132", +}; + +static const char *const uim1_clk_groups[] = { + "gpio37", "gpio55", "gpio71", "gpio135", +}; + +static const char *const uim1_data_groups[] = { + "gpio134", "gpio36", "gpio54", "gpio70", +}; + +static const char *const uim1_present_groups[] = { + "gpio137", +}; + +static const char *const uim1_reset_groups[] = { + "gpio39", "gpio56", "gpio72", "gpio136", +}; + +static const char *const usb1_hs_groups[] = { + "gpio79", +}; + +static const char *const usb_phy_groups[] = { + "gpio59", "gpio61", +}; + +static const char *const vfr_0_groups[] = { + "gpio150", +}; + +static const char *const vfr_1_groups[] = { + "gpio155", +}; + +static const char *const vsense_trigger_mirnat_groups[] = { + "gpio59", +}; + +static const char *const wcn_sw_groups[] = { + "gpio19", +}; + +static const char *const wcn_sw_ctrl_groups[] = { + "gpio18", +}; + +static const struct pinfunction sm8750_functions[] = { + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(aoss_cti), + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_usb), + MSM_PIN_FUNCTION(audio_ext_mclk0), + MSM_PIN_FUNCTION(audio_ext_mclk1), + MSM_PIN_FUNCTION(audio_ref_clk), + MSM_PIN_FUNCTION(cam_aon_mclk2), + MSM_PIN_FUNCTION(cam_aon_mclk4), + MSM_PIN_FUNCTION(cam_mclk), + MSM_PIN_FUNCTION(cci_async_in), + MSM_PIN_FUNCTION(cci_i2c_scl), + MSM_PIN_FUNCTION(cci_i2c_sda), + MSM_PIN_FUNCTION(cci_timer), + MSM_PIN_FUNCTION(cmu_rng), + MSM_PIN_FUNCTION(coex_uart1_rx), + MSM_PIN_FUNCTION(coex_uart1_tx), + MSM_PIN_FUNCTION(coex_uart2_rx), + MSM_PIN_FUNCTION(coex_uart2_tx), + MSM_PIN_FUNCTION(dbg_out_clk), + MSM_PIN_FUNCTION(ddr_bist_complete), + MSM_PIN_FUNCTION(ddr_bist_fail), + MSM_PIN_FUNCTION(ddr_bist_start), + MSM_PIN_FUNCTION(ddr_bist_stop), + MSM_PIN_FUNCTION(ddr_pxi0), + MSM_PIN_FUNCTION(ddr_pxi1), + MSM_PIN_FUNCTION(ddr_pxi2), + MSM_PIN_FUNCTION(ddr_pxi3), + MSM_PIN_FUNCTION(dp_hot), + MSM_PIN_FUNCTION(egpio), + MSM_PIN_FUNCTION(gcc_gp1), + MSM_PIN_FUNCTION(gcc_gp2), + MSM_PIN_FUNCTION(gcc_gp3), + MSM_PIN_FUNCTION(gnss_adc0), + MSM_PIN_FUNCTION(gnss_adc1), + MSM_PIN_FUNCTION(i2chub0_se0), + MSM_PIN_FUNCTION(i2chub0_se1), + MSM_PIN_FUNCTION(i2chub0_se2), + MSM_PIN_FUNCTION(i2chub0_se3), + MSM_PIN_FUNCTION(i2chub0_se4), + MSM_PIN_FUNCTION(i2chub0_se5), + MSM_PIN_FUNCTION(i2chub0_se6), + MSM_PIN_FUNCTION(i2chub0_se7), + MSM_PIN_FUNCTION(i2chub0_se8), + MSM_PIN_FUNCTION(i2chub0_se9), + MSM_PIN_FUNCTION(i2s0_data0), + MSM_PIN_FUNCTION(i2s0_data1), + MSM_PIN_FUNCTION(i2s0_sck), + MSM_PIN_FUNCTION(i2s0_ws), + MSM_PIN_FUNCTION(i2s1_data0), + MSM_PIN_FUNCTION(i2s1_data1), + MSM_PIN_FUNCTION(i2s1_sck), + MSM_PIN_FUNCTION(i2s1_ws), + MSM_PIN_FUNCTION(ibi_i3c), + MSM_PIN_FUNCTION(jitter_bist), + MSM_PIN_FUNCTION(mdp_esync0_out), + MSM_PIN_FUNCTION(mdp_esync1_out), + MSM_PIN_FUNCTION(mdp_vsync), + MSM_PIN_FUNCTION(mdp_vsync0_out), + MSM_PIN_FUNCTION(mdp_vsync1_out), + MSM_PIN_FUNCTION(mdp_vsync2_out), + MSM_PIN_FUNCTION(mdp_vsync3_out), + MSM_PIN_FUNCTION(mdp_vsync5_out), + MSM_PIN_FUNCTION(mdp_vsync_e), + MSM_PIN_FUNCTION(nav_gpio0), + MSM_PIN_FUNCTION(nav_gpio1), + MSM_PIN_FUNCTION(nav_gpio2), + MSM_PIN_FUNCTION(nav_gpio3), + MSM_PIN_FUNCTION(pcie0_clk_req_n), + MSM_PIN_FUNCTION(phase_flag), + MSM_PIN_FUNCTION(pll_bist_sync), + MSM_PIN_FUNCTION(pll_clk_aux), + MSM_PIN_FUNCTION(prng_rosc0), + MSM_PIN_FUNCTION(prng_rosc1), + MSM_PIN_FUNCTION(prng_rosc2), + MSM_PIN_FUNCTION(prng_rosc3), + MSM_PIN_FUNCTION(qdss_cti), + MSM_PIN_FUNCTION(qlink_big_enable), + MSM_PIN_FUNCTION(qlink_big_request), + MSM_PIN_FUNCTION(qlink_little_enable), + MSM_PIN_FUNCTION(qlink_little_request), + MSM_PIN_FUNCTION(qlink_wmss), + MSM_PIN_FUNCTION(qspi0), + MSM_PIN_FUNCTION(qspi1), + MSM_PIN_FUNCTION(qspi2), + MSM_PIN_FUNCTION(qspi3), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs), + MSM_PIN_FUNCTION(qup1_se0), + MSM_PIN_FUNCTION(qup1_se1), + MSM_PIN_FUNCTION(qup1_se2), + MSM_PIN_FUNCTION(qup1_se3), + MSM_PIN_FUNCTION(qup1_se4), + MSM_PIN_FUNCTION(qup1_se5), + MSM_PIN_FUNCTION(qup1_se6), + MSM_PIN_FUNCTION(qup1_se7), + MSM_PIN_FUNCTION(qup2_se0), + MSM_PIN_FUNCTION(qup2_se1), + MSM_PIN_FUNCTION(qup2_se2), + MSM_PIN_FUNCTION(qup2_se3), + MSM_PIN_FUNCTION(qup2_se4), + MSM_PIN_FUNCTION(qup2_se5), + MSM_PIN_FUNCTION(qup2_se6), + MSM_PIN_FUNCTION(qup2_se7), + MSM_PIN_FUNCTION(sd_write_protect), + MSM_PIN_FUNCTION(sdc40), + MSM_PIN_FUNCTION(sdc41), + MSM_PIN_FUNCTION(sdc42), + MSM_PIN_FUNCTION(sdc43), + MSM_PIN_FUNCTION(sdc4_clk), + MSM_PIN_FUNCTION(sdc4_cmd), + MSM_PIN_FUNCTION(tb_trig_sdc2), + MSM_PIN_FUNCTION(tb_trig_sdc4), + MSM_PIN_FUNCTION(tmess_prng0), + MSM_PIN_FUNCTION(tmess_prng1), + MSM_PIN_FUNCTION(tmess_prng2), + MSM_PIN_FUNCTION(tmess_prng3), + MSM_PIN_FUNCTION(tsense_pwm1), + MSM_PIN_FUNCTION(tsense_pwm2), + MSM_PIN_FUNCTION(tsense_pwm3), + MSM_PIN_FUNCTION(tsense_pwm4), + MSM_PIN_FUNCTION(uim0_clk), + MSM_PIN_FUNCTION(uim0_data), + MSM_PIN_FUNCTION(uim0_present), + MSM_PIN_FUNCTION(uim0_reset), + MSM_PIN_FUNCTION(uim1_clk), + MSM_PIN_FUNCTION(uim1_data), + MSM_PIN_FUNCTION(uim1_present), + MSM_PIN_FUNCTION(uim1_reset), + MSM_PIN_FUNCTION(usb1_hs), + MSM_PIN_FUNCTION(usb_phy), + MSM_PIN_FUNCTION(vfr_0), + MSM_PIN_FUNCTION(vfr_1), + MSM_PIN_FUNCTION(vsense_trigger_mirnat), + MSM_PIN_FUNCTION(wcn_sw), + MSM_PIN_FUNCTION(wcn_sw_ctrl), +}; + +/* + * 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 sm8750_groups[] = { + [0] = PINGROUP(0, qup2_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [1] = PINGROUP(1, qup2_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [2] = PINGROUP(2, qup2_se0, _, _, _, _, _, _, _, _, _, egpio), + [3] = PINGROUP(3, qup2_se0, _, _, _, _, _, _, _, _, _, egpio), + [4] = PINGROUP(4, qup2_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [5] = PINGROUP(5, qup2_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [6] = PINGROUP(6, qup2_se1, _, _, _, _, _, _, _, _, _, egpio), + [7] = PINGROUP(7, qup2_se1, _, _, _, _, _, _, _, _, _, egpio), + [8] = PINGROUP(8, qup2_se2, ibi_i3c, _, _, _, _, _, _, _, _, _), + [9] = PINGROUP(9, qup2_se2, ibi_i3c, _, _, _, _, _, _, _, _, _), + [10] = PINGROUP(10, qup2_se2, cci_async_in, phase_flag, _, _, _, _, _, _, _, _), + [11] = PINGROUP(11, qup2_se2, cci_async_in, phase_flag, _, _, _, _, _, _, _, _), + [12] = PINGROUP(12, qup2_se3, ibi_i3c, qup2_se2, _, _, _, _, _, _, _, _), + [13] = PINGROUP(13, qup2_se3, ibi_i3c, qup2_se2, _, _, _, _, _, _, _, _), + [14] = PINGROUP(14, qup2_se3, phase_flag, _, _, _, _, _, _, _, _, _), + [15] = PINGROUP(15, qup2_se3, cci_async_in, qup2_se2, phase_flag, _, _, _, _, _, _, _), + [16] = PINGROUP(16, qup2_se4, phase_flag, _, _, _, _, _, _, _, _, _), + [17] = PINGROUP(17, qup2_se4, phase_flag, _, _, _, _, _, _, _, _, _), + [18] = PINGROUP(18, wcn_sw_ctrl, qup2_se4, phase_flag, _, _, _, _, _, _, _, _), + [19] = PINGROUP(19, wcn_sw, qup2_se4, phase_flag, _, _, _, _, _, _, _, _), + [20] = PINGROUP(20, qup2_se5, phase_flag, _, _, _, _, _, _, _, _, _), + [21] = PINGROUP(21, qup2_se5, phase_flag, _, _, _, _, _, _, _, _, _), + [22] = PINGROUP(22, qup2_se5, phase_flag, _, _, _, _, _, _, _, _, _), + [23] = PINGROUP(23, qup2_se5, qup2_se5, phase_flag, _, _, _, _, _, _, _, _), + [24] = PINGROUP(24, qup2_se6, phase_flag, _, _, _, _, _, _, _, _, _), + [25] = PINGROUP(25, qup2_se6, phase_flag, _, _, _, _, _, _, _, _, _), + [26] = PINGROUP(26, qup2_se6, phase_flag, _, _, _, _, _, _, _, _, _), + [27] = PINGROUP(27, qup2_se6, qdss_cti, phase_flag, _, _, _, _, _, _, _, _), + [28] = PINGROUP(28, qup2_se7, ibi_i3c, phase_flag, _, _, _, _, _, _, _, _), + [29] = PINGROUP(29, qup2_se7, ibi_i3c, phase_flag, _, _, _, _, _, _, _, _), + [30] = PINGROUP(30, qup2_se7, _, _, _, _, _, _, _, _, _, _), + [31] = PINGROUP(31, qup2_se7, qdss_cti, phase_flag, _, _, _, _, _, _, _, _), + [32] = PINGROUP(32, qup1_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [33] = PINGROUP(33, qup1_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio), + [34] = PINGROUP(34, qup1_se0, _, _, _, _, _, _, _, _, _, egpio), + [35] = PINGROUP(35, qup1_se0, _, _, _, _, _, _, _, _, _, egpio), + [36] = PINGROUP(36, qup1_se1, uim1_data, ibi_i3c, sdc40, _, _, _, _, _, _, egpio), + [37] = PINGROUP(37, qup1_se1, uim1_clk, ibi_i3c, sdc41, _, _, _, _, _, _, egpio), + [38] = PINGROUP(38, qup1_se1, sdc42, _, _, _, _, _, _, _, _, _), + [39] = PINGROUP(39, qup1_se1, uim1_reset, sdc43, _, _, _, _, _, _, _, _), + [40] = PINGROUP(40, qup1_se2, cmu_rng, ddr_bist_fail, _, _, _, _, _, _, _, _), + [41] = PINGROUP(41, qup1_se2, cmu_rng, ddr_bist_start, _, _, _, _, _, _, _, _), + [42] = PINGROUP(42, qup1_se2, cmu_rng, _, _, _, _, _, _, _, _, _), + [43] = PINGROUP(43, qup1_se2, cmu_rng, _, ddr_pxi2, _, _, _, _, _, _, _), + [44] = PINGROUP(44, qup1_se3, ddr_bist_complete, ddr_pxi1, _, _, _, _, _, _, _, _), + [45] = PINGROUP(45, qup1_se3, ddr_bist_stop, ddr_pxi1, _, _, _, _, _, _, _, _), + [46] = PINGROUP(46, qup1_se3, ddr_pxi3, _, _, _, _, _, _, _, _, _), + [47] = PINGROUP(47, qup1_se3, dp_hot, _, _, _, _, _, _, _, _, _), + [48] = PINGROUP(48, qup1_se4, ibi_i3c, sdc4_cmd, _, _, _, _, _, _, _, _), + [49] = PINGROUP(49, qup1_se4, ibi_i3c, sdc40, _, _, _, _, _, _, _, _), + [50] = PINGROUP(50, qup1_se4, aoss_cti, sdc4_clk, _, _, _, _, _, _, _, _), + [51] = PINGROUP(51, qup1_se4, aoss_cti, sdc41, _, _, _, _, _, _, _, _), + [52] = PINGROUP(52, qup1_se5, qspi0, ddr_pxi2, _, _, _, _, _, _, _, _), + [53] = PINGROUP(53, qup1_se5, qspi1, _, ddr_pxi3, _, _, _, _, _, _, _), + [54] = PINGROUP(54, qup1_se5, qspi_clk, uim1_data, ddr_pxi0, _, _, _, _, _, _, _), + [55] = PINGROUP(55, qup1_se5, qspi2, uim1_clk, ddr_pxi0, _, _, _, _, _, _, _), + [56] = PINGROUP(56, qup1_se6, qspi3, uim1_reset, _, _, _, _, _, _, _, _), + [57] = PINGROUP(57, qup1_se6, qspi_cs, tsense_pwm1, tsense_pwm2, tsense_pwm3, tsense_pwm4, + _, _, _, _, _), + [58] = PINGROUP(58, qup1_se6, qspi_cs, _, _, _, _, _, _, _, _, _), + [59] = PINGROUP(59, qup1_se6, usb_phy, vsense_trigger_mirnat, _, _, _, _, _, _, _, _), + [60] = PINGROUP(60, qup1_se7, aoss_cti, sdc42, _, _, _, _, _, _, _, _), + [61] = PINGROUP(61, qup1_se7, usb_phy, aoss_cti, sdc43, _, _, _, _, _, _, _), + [62] = PINGROUP(62, qup1_se7, _, _, _, _, _, _, _, _, _, _), + [63] = PINGROUP(63, qup1_se7, _, _, _, _, _, _, _, _, _, _), + [64] = PINGROUP(64, i2chub0_se0, prng_rosc1, tmess_prng1, phase_flag, _, _, _, _, _, _, _), + [65] = PINGROUP(65, i2chub0_se0, prng_rosc2, tmess_prng2, phase_flag, _, _, _, _, _, _, _), + [66] = PINGROUP(66, i2chub0_se1, prng_rosc3, tmess_prng3, phase_flag, _, _, _, _, _, _, _), + [67] = PINGROUP(67, i2chub0_se1, phase_flag, _, _, _, _, _, _, _, _, _), + [68] = PINGROUP(68, i2chub0_se2, phase_flag, _, _, _, _, _, _, _, _, _), + [69] = PINGROUP(69, i2chub0_se2, phase_flag, _, _, _, _, _, _, _, _, _), + [70] = PINGROUP(70, i2chub0_se3, uim1_data, _, atest_usb, _, _, _, _, _, _, _), + [71] = PINGROUP(71, i2chub0_se3, uim1_clk, _, atest_usb, _, _, _, _, _, _, _), + [72] = PINGROUP(72, i2chub0_se4, uim1_reset, qdss_cti, _, atest_usb, _, _, _, _, _, _), + [73] = PINGROUP(73, i2chub0_se4, qdss_cti, jitter_bist, atest_usb, _, _, _, _, _, _, _), + [74] = PINGROUP(74, i2chub0_se5, _, _, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, i2chub0_se5, _, _, _, _, _, _, _, _, _, _), + [76] = PINGROUP(76, i2chub0_se6, atest_usb, _, _, _, _, _, _, _, _, _), + [77] = PINGROUP(77, i2chub0_se6, gnss_adc1, _, _, _, _, _, _, _, _, _), + [78] = PINGROUP(78, dbg_out_clk, gnss_adc0, _, _, _, _, _, _, _, _, _), + [79] = PINGROUP(79, usb1_hs, gnss_adc0, _, _, _, _, _, _, _, _, _), + [80] = PINGROUP(80, i2chub0_se9, _, _, _, _, _, _, _, _, _, _), + [81] = PINGROUP(81, i2chub0_se9, _, _, _, _, _, _, _, _, _, _), + [82] = PINGROUP(82, i2chub0_se7, qdss_cti, phase_flag, _, _, _, _, _, _, _, _), + [83] = PINGROUP(83, i2chub0_se7, qdss_cti, phase_flag, _, _, _, _, _, _, _, _), + [84] = PINGROUP(84, _, _, _, _, _, _, _, _, _, _, _), + [85] = PINGROUP(85, sd_write_protect, prng_rosc0, tmess_prng0, phase_flag, _, _, _, _, _, + _, _), + [86] = PINGROUP(86, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, gcc_gp1, _, _, _, _, _, _, + _), + [87] = PINGROUP(87, mdp_vsync, mdp_vsync2_out, mdp_vsync3_out, mdp_vsync5_out, gcc_gp2, _, + _, _, _, _, _), + [88] = PINGROUP(88, mdp_vsync_e, mdp_esync0_out, gcc_gp3, _, _, _, _, _, _, _, _), + [89] = PINGROUP(89, cam_mclk, tb_trig_sdc2, _, _, _, _, _, _, _, _, _), + [90] = PINGROUP(90, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [91] = PINGROUP(91, cam_aon_mclk2, _, _, _, _, _, _, _, _, _, _), + [92] = PINGROUP(92, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [93] = PINGROUP(93, cam_aon_mclk4, _, _, _, _, _, _, _, _, _, _), + [94] = PINGROUP(94, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [95] = PINGROUP(95, cam_mclk, pll_clk_aux, _, _, _, _, _, _, _, _, _), + [96] = PINGROUP(96, cam_mclk, _, _, _, _, _, _, _, _, _, _), + [97] = PINGROUP(97, mdp_vsync, _, _, _, _, _, _, _, _, _, _), + [98] = PINGROUP(98, mdp_vsync, _, _, _, _, _, _, _, _, _, _), + [99] = PINGROUP(99, gnss_adc1, _, _, _, _, _, _, _, _, _, _), + [100] = PINGROUP(100, mdp_esync1_out, _, _, _, _, _, _, _, _, _, _), + [101] = PINGROUP(101, phase_flag, _, _, _, _, _, _, _, _, _, _), + [102] = PINGROUP(102, phase_flag, _, _, _, _, _, _, _, _, _, _), + [103] = PINGROUP(103, pcie0_clk_req_n, phase_flag, _, _, _, _, _, _, _, _, _), + [104] = PINGROUP(104, pll_bist_sync, phase_flag, _, _, _, _, _, _, _, _, _), + [105] = PINGROUP(105, _, _, _, _, _, _, _, _, _, _, egpio), + [106] = PINGROUP(106, _, _, _, _, _, _, _, _, _, _, egpio), + [107] = PINGROUP(107, _, _, _, _, _, _, _, _, _, _, egpio), + [108] = PINGROUP(108, _, _, _, _, _, _, _, _, _, _, egpio), + [109] = PINGROUP(109, cci_timer, _, _, _, _, _, _, _, _, _, _), + [110] = PINGROUP(110, cci_timer, _, _, _, _, _, _, _, _, _, _), + [111] = PINGROUP(111, cci_timer, cci_i2c_sda, _, _, _, _, _, _, _, _, _), + [112] = PINGROUP(112, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [113] = PINGROUP(113, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [114] = PINGROUP(114, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [115] = PINGROUP(115, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [116] = PINGROUP(116, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [117] = PINGROUP(117, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [118] = PINGROUP(118, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [119] = PINGROUP(119, cci_i2c_sda, _, _, _, _, _, _, _, _, _, _), + [120] = PINGROUP(120, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [121] = PINGROUP(121, i2s1_sck, _, _, _, _, _, _, _, _, _, _), + [122] = PINGROUP(122, i2s1_data0, _, _, _, _, _, _, _, _, _, _), + [123] = PINGROUP(123, i2s1_ws, _, _, _, _, _, _, _, _, _, _), + [124] = PINGROUP(124, i2s1_data1, audio_ext_mclk1, audio_ref_clk, _, _, _, _, _, _, _, _), + [125] = PINGROUP(125, audio_ext_mclk0, _, _, _, _, _, _, _, _, _, _), + [126] = PINGROUP(126, i2s0_sck, _, _, _, _, _, _, _, _, _, _), + [127] = PINGROUP(127, i2s0_data0, _, _, _, _, _, _, _, _, _, _), + [128] = PINGROUP(128, i2s0_data1, _, _, _, _, _, _, _, _, _, _), + [129] = PINGROUP(129, i2s0_ws, _, _, _, _, _, _, _, _, _, _), + [130] = PINGROUP(130, uim0_data, atest_char, _, _, _, _, _, _, _, _, _), + [131] = PINGROUP(131, uim0_clk, atest_char, _, _, _, _, _, _, _, _, _), + [132] = PINGROUP(132, uim0_reset, atest_char, _, _, _, _, _, _, _, _, _), + [133] = PINGROUP(133, uim0_present, atest_char, _, _, _, _, _, _, _, _, _), + [134] = PINGROUP(134, uim1_data, qup1_se2, gcc_gp1, _, _, _, _, _, _, _, _), + [135] = PINGROUP(135, uim1_clk, qup1_se2, gcc_gp2, _, _, _, _, _, _, _, _), + [136] = PINGROUP(136, uim1_reset, qup1_se2, gcc_gp3, _, _, _, _, _, _, _, _), + [137] = PINGROUP(137, uim1_present, atest_char, _, _, _, _, _, _, _, _, _), + [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _, _, _), + [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _, _, _), + [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _, _, _), + [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _, _, _), + [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _, _, _), + [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _, _, _), + [144] = PINGROUP(144, _, _, _, _, _, _, _, _, _, _, _), + [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _, _, _), + [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _, _, _), + [147] = PINGROUP(147, _, tb_trig_sdc4, _, _, _, _, _, _, _, _, _), + [148] = PINGROUP(148, coex_uart1_rx, cmu_rng, _, _, _, _, _, _, _, _, _), + [149] = PINGROUP(149, coex_uart1_tx, cmu_rng, _, _, _, _, _, _, _, _, _), + [150] = PINGROUP(150, _, vfr_0, coex_uart2_rx, cmu_rng, sdc4_clk, _, _, _, _, _, _), + [151] = PINGROUP(151, _, coex_uart2_tx, cmu_rng, sdc4_cmd, _, _, _, _, _, _, _), + [152] = PINGROUP(152, nav_gpio2, _, _, _, _, _, _, _, _, _, _), + [153] = PINGROUP(153, cci_i2c_scl, _, _, _, _, _, _, _, _, _, _), + [154] = PINGROUP(154, nav_gpio0, nav_gpio3, _, _, _, _, _, _, _, _, _), + [155] = PINGROUP(155, nav_gpio1, vfr_1, _, _, _, _, _, _, _, _, _), + [156] = PINGROUP(156, qlink_little_request, _, _, _, _, _, _, _, _, _, _), + [157] = PINGROUP(157, qlink_little_enable, _, _, _, _, _, _, _, _, _, _), + [158] = PINGROUP(158, qlink_wmss, _, _, _, _, _, _, _, _, _, _), + [159] = PINGROUP(159, qlink_big_request, qdss_cti, _, _, _, _, _, _, _, _, _), + [160] = PINGROUP(160, qlink_big_enable, _, _, _, _, _, _, _, _, _, _), + [161] = PINGROUP(161, _, _, _, _, _, _, _, _, _, _, _), + [162] = PINGROUP(162, qdss_cti, _, _, _, _, _, _, _, _, _, _), + [163] = PINGROUP(163, cci_timer, _, _, _, _, _, _, _, _, _, _), + [164] = PINGROUP(164, cci_timer, cci_i2c_scl, _, _, _, _, _, _, _, _, _), + [165] = PINGROUP(165, _, _, _, _, _, _, _, _, _, _, egpio), + [166] = PINGROUP(166, _, _, _, _, _, _, _, _, _, _, egpio), + [167] = PINGROUP(167, _, _, _, _, _, _, _, _, _, _, egpio), + [168] = PINGROUP(168, _, _, _, _, _, _, _, _, _, _, egpio), + [169] = PINGROUP(169, _, _, _, _, _, _, _, _, _, _, egpio), + [170] = PINGROUP(170, _, _, _, _, _, _, _, _, _, _, egpio), + [171] = PINGROUP(171, _, _, _, _, _, _, _, _, _, _, egpio), + [172] = PINGROUP(172, _, _, _, _, _, _, _, _, _, _, egpio), + [173] = PINGROUP(173, _, _, _, _, _, _, _, _, _, _, egpio), + [174] = PINGROUP(174, _, _, _, _, _, _, _, _, _, _, egpio), + [175] = PINGROUP(175, _, _, _, _, _, _, _, _, _, _, egpio), + [176] = PINGROUP(176, _, _, _, _, _, _, _, _, _, _, egpio), + [177] = PINGROUP(177, _, _, _, _, _, _, _, _, _, _, egpio), + [178] = PINGROUP(178, _, _, _, _, _, _, _, _, _, _, egpio), + [179] = PINGROUP(179, _, _, _, _, _, _, _, _, _, _, egpio), + [180] = PINGROUP(180, _, _, _, _, _, _, _, _, _, _, egpio), + [181] = PINGROUP(181, _, _, _, _, _, _, _, _, _, _, egpio), + [182] = PINGROUP(182, _, _, _, _, _, _, _, _, _, _, egpio), + [183] = PINGROUP(183, _, _, _, _, _, _, _, _, _, _, egpio), + [184] = PINGROUP(184, _, _, _, _, _, _, _, _, _, _, egpio), + [185] = PINGROUP(185, _, _, _, _, _, _, _, _, _, _, egpio), + [186] = PINGROUP(186, _, _, _, _, _, _, _, _, _, _, egpio), + [187] = PINGROUP(187, _, _, _, _, _, _, _, _, _, _, egpio), + [188] = PINGROUP(188, _, _, _, _, _, _, _, _, _, _, egpio), + [189] = PINGROUP(189, _, _, _, _, _, _, _, _, _, _, egpio), + [190] = PINGROUP(190, _, _, _, _, _, _, _, _, _, _, egpio), + [191] = PINGROUP(191, _, _, _, _, _, _, _, _, _, _, egpio), + [192] = PINGROUP(192, _, _, _, _, _, _, _, _, _, _, egpio), + [193] = PINGROUP(193, _, _, _, _, _, _, _, _, _, _, egpio), + [194] = PINGROUP(194, _, _, _, _, _, _, _, _, _, _, egpio), + [195] = PINGROUP(195, _, _, _, _, _, _, _, _, _, _, egpio), + [196] = PINGROUP(196, _, _, _, _, _, _, _, _, _, _, egpio), + [197] = PINGROUP(197, _, _, _, _, _, _, _, _, _, _, egpio), + [198] = PINGROUP(198, _, _, _, _, _, _, _, _, _, _, egpio), + [199] = PINGROUP(199, _, _, _, _, _, _, _, _, _, _, egpio), + [200] = PINGROUP(200, _, _, _, _, _, _, _, _, _, _, egpio), + [201] = PINGROUP(201, _, _, _, _, _, _, _, _, _, _, egpio), + [202] = PINGROUP(202, _, _, _, _, _, _, _, _, _, _, egpio), + [203] = PINGROUP(203, _, _, _, _, _, _, _, _, _, _, egpio), + [204] = PINGROUP(204, _, _, _, _, _, _, _, _, _, _, egpio), + [205] = PINGROUP(205, _, _, _, _, _, _, _, _, _, _, egpio), + [206] = PINGROUP(206, i2chub0_se8, _, _, _, _, _, _, _, _, _, egpio), + [207] = PINGROUP(207, i2chub0_se8, _, _, _, _, _, _, _, _, _, egpio), + [208] = PINGROUP(208, _, _, _, _, _, _, _, _, _, _, egpio), + [209] = PINGROUP(209, _, _, _, _, _, _, _, _, _, _, egpio), + [210] = PINGROUP(210, _, _, _, _, _, _, _, _, _, _, egpio), + [211] = PINGROUP(211, _, _, _, _, _, _, _, _, _, _, egpio), + [212] = PINGROUP(212, _, _, _, _, _, _, _, _, _, _, egpio), + [213] = PINGROUP(213, _, _, _, _, _, _, _, _, _, _, egpio), + [214] = PINGROUP(214, _, _, _, _, _, _, _, _, _, _, egpio), + [215] = UFS_RESET(ufs_reset, 0xe2004, 0xe3000), + [216] = SDC_QDSD_PINGROUP(sdc2_clk, 0xdb000, 14, 6), + [217] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xdb000, 11, 3), + [218] = SDC_QDSD_PINGROUP(sdc2_data, 0xdb000, 9, 0), +}; + +static const struct msm_gpio_wakeirq_map sm8750_pdc_map[] = { + { 0, 72 }, { 3, 80 }, { 4, 73 }, { 7, 74 }, { 8, 75 }, + { 11, 76 }, { 12, 87 }, { 15, 98 }, { 18, 110 }, { 19, 79 }, + { 23, 82 }, { 24, 83 }, { 27, 84 }, { 28, 85 }, { 31, 86 }, + { 32, 92 }, { 35, 68 }, { 36, 93 }, { 39, 94 }, { 43, 95 }, + { 46, 96 }, { 47, 121 }, { 48, 97 }, { 51, 118 }, { 54, 102 }, + { 55, 71 }, { 56, 103 }, { 57, 104 }, { 59, 105 }, { 61, 81 }, + { 63, 91 }, { 64, 77 }, { 65, 90 }, { 66, 106 }, { 67, 99 }, + { 68, 112 }, { 69, 113 }, { 75, 114 }, { 78, 115 }, { 79, 116 }, + { 80, 122 }, { 81, 123 }, { 84, 101 }, { 85, 124 }, { 86, 125 }, + { 87, 126 }, { 88, 127 }, { 95, 128 }, { 96, 129 }, { 97, 100 }, + { 98, 117 }, { 99, 78 }, { 102, 130 }, { 103, 131 }, { 104, 132 }, + { 108, 133 }, { 133, 134 }, { 137, 67 }, { 148, 135 }, { 150, 136 }, + { 152, 137 }, { 154, 138 }, { 155, 89 }, { 156, 139 }, { 159, 140 }, + { 162, 109 }, { 163, 108 }, { 166, 141 }, { 169, 142 }, { 171, 143 }, + { 172, 144 }, { 174, 145 }, { 176, 146 }, { 177, 120 }, { 181, 147 }, + { 182, 148 }, { 185, 149 }, { 188, 111 }, { 190, 88 }, { 191, 150 }, + { 192, 151 }, { 193, 152 }, { 196, 153 }, { 197, 154 }, { 198, 70 }, + { 199, 119 }, { 200, 69 }, { 201, 155 }, { 202, 156 }, { 203, 157 }, + { 204, 158 }, { 205, 107 }, { 209, 159 }, +}; + +static const struct msm_pinctrl_soc_data sm8750_tlmm = { + .pins = sm8750_pins, + .npins = ARRAY_SIZE(sm8750_pins), + .functions = sm8750_functions, + .nfunctions = ARRAY_SIZE(sm8750_functions), + .groups = sm8750_groups, + .ngroups = ARRAY_SIZE(sm8750_groups), + .ngpios = 216, + .wakeirq_map = sm8750_pdc_map, + .nwakeirq_map = ARRAY_SIZE(sm8750_pdc_map), + .egpio_func = 11, +}; + +static int sm8750_tlmm_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &sm8750_tlmm); +} + +static const struct of_device_id sm8750_tlmm_of_match[] = { + { .compatible = "qcom,sm8750-tlmm", }, + {}, +}; + +static struct platform_driver sm8750_tlmm_driver = { + .driver = { + .name = "sm8750-tlmm", + .of_match_table = sm8750_tlmm_of_match, + }, + .probe = sm8750_tlmm_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init sm8750_tlmm_init(void) +{ + return platform_driver_register(&sm8750_tlmm_driver); +} +arch_initcall(sm8750_tlmm_init); + +static void __exit sm8750_tlmm_exit(void) +{ + platform_driver_unregister(&sm8750_tlmm_driver); +} +module_exit(sm8750_tlmm_exit); + +MODULE_DESCRIPTION("QTI SM8750 TLMM driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, sm8750_tlmm_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index d2dd66769aa891..0c806b8128b637 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -667,7 +667,7 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev, "push-pull", "open-drain", "open-source" }; static const char *const strengths[] = { - "no", "high", "medium", "low" + "no", "low", "medium", "high" }; pad = pctldev->desc->pins[pin].drv_data; @@ -1169,7 +1169,7 @@ static int pmic_gpio_probe(struct platform_device *pdev) * files which don't set the "gpio-ranges" property or systems that * utilize ACPI the driver has to call gpiochip_add_pin_range(). */ - if (!of_property_read_bool(dev->of_node, "gpio-ranges")) { + if (!of_property_present(dev->of_node, "gpio-ranges")) { ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins); if (ret) { @@ -1226,6 +1226,8 @@ static const struct of_device_id pmic_gpio_of_match[] = { { .compatible = "qcom,pm8550ve-gpio", .data = (void *) 8 }, { .compatible = "qcom,pm8550vs-gpio", .data = (void *) 6 }, { .compatible = "qcom,pm8916-gpio", .data = (void *) 4 }, + /* pm8937 has 8 GPIOs with holes on 3, 4 and 6 */ + { .compatible = "qcom,pm8937-gpio", .data = (void *) 8 }, { .compatible = "qcom,pm8941-gpio", .data = (void *) 36 }, /* pm8950 has 8 GPIOs with holes on 3 */ { .compatible = "qcom,pm8950-gpio", .data = (void *) 8 }, @@ -1268,7 +1270,7 @@ static struct platform_driver pmic_gpio_driver = { .of_match_table = pmic_gpio_of_match, }, .probe = pmic_gpio_probe, - .remove_new = pmic_gpio_remove, + .remove = pmic_gpio_remove, }; module_platform_driver(pmic_gpio_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index d16ece90d926cf..84de584cf7ebbd 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -983,6 +983,7 @@ static const struct of_device_id pmic_mpp_of_match[] = { { .compatible = "qcom,pm8226-mpp", .data = (void *) 8 }, { .compatible = "qcom,pm8841-mpp", .data = (void *) 4 }, { .compatible = "qcom,pm8916-mpp", .data = (void *) 4 }, + { .compatible = "qcom,pm8937-mpp", .data = (void *) 4 }, { .compatible = "qcom,pm8941-mpp", .data = (void *) 8 }, { .compatible = "qcom,pm8950-mpp", .data = (void *) 4 }, { .compatible = "qcom,pmi8950-mpp", .data = (void *) 4 }, @@ -1000,7 +1001,7 @@ static struct platform_driver pmic_mpp_driver = { .of_match_table = pmic_mpp_of_match, }, .probe = pmic_mpp_probe, - .remove_new = pmic_mpp_remove, + .remove = pmic_mpp_remove, }; module_platform_driver(pmic_mpp_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c index 9cd5247ea57420..2225dc49d477c1 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -832,7 +832,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) * files which don't set the "gpio-ranges" property or systems that * utilize ACPI the driver has to call gpiochip_add_pin_range(). */ - if (!of_property_read_bool(pctrl->dev->of_node, "gpio-ranges")) { + if (!of_property_present(pctrl->dev->of_node, "gpio-ranges")) { ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, pctrl->chip.ngpio); if (ret) { @@ -866,7 +866,7 @@ static struct platform_driver pm8xxx_gpio_driver = { .of_match_table = pm8xxx_gpio_of_match, }, .probe = pm8xxx_gpio_probe, - .remove_new = pm8xxx_gpio_remove, + .remove = pm8xxx_gpio_remove, }; module_platform_driver(pm8xxx_gpio_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c index 3aee6835a2de0a..9b1039c08aa6d7 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c @@ -949,7 +949,7 @@ static struct platform_driver pm8xxx_mpp_driver = { .of_match_table = pm8xxx_mpp_of_match, }, .probe = pm8xxx_mpp_probe, - .remove_new = pm8xxx_mpp_remove, + .remove = pm8xxx_mpp_remove, }; module_platform_driver(pm8xxx_mpp_driver); diff --git a/drivers/pinctrl/qcom/pinctrl-x1e80100.c b/drivers/pinctrl/qcom/pinctrl-x1e80100.c index abfcdd3da9e823..419cb8facb2f3d 100644 --- a/drivers/pinctrl/qcom/pinctrl-x1e80100.c +++ b/drivers/pinctrl/qcom/pinctrl-x1e80100.c @@ -1861,7 +1861,7 @@ static struct platform_driver x1e80100_pinctrl_driver = { .of_match_table = x1e80100_pinctrl_of_match, }, .probe = x1e80100_pinctrl_probe, - .remove_new = msm_pinctrl_remove, + .remove = msm_pinctrl_remove, }; static int __init x1e80100_pinctrl_init(void) diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig index 14bd55d647319b..7f3f41c7fe54c8 100644 --- a/drivers/pinctrl/renesas/Kconfig +++ b/drivers/pinctrl/renesas/Kconfig @@ -41,6 +41,7 @@ config PINCTRL_RENESAS select PINCTRL_PFC_R8A779H0 if ARCH_R8A779H0 select PINCTRL_RZG2L if ARCH_RZG2L select PINCTRL_RZV2M if ARCH_R9A09G011 + select PINCTRL_RZG2L if ARCH_R9A09G057 select PINCTRL_PFC_SH7203 if CPU_SUBTYPE_SH7203 select PINCTRL_PFC_SH7264 if CPU_SUBTYPE_SH7264 select PINCTRL_PFC_SH7269 if CPU_SUBTYPE_SH7269 diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c index 6527872813dc58..b1058504e0bb3e 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza1.c +++ b/drivers/pinctrl/renesas/pinctrl-rza1.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -750,6 +751,11 @@ static int rza1_pin_mux_single(struct rza1_pinctrl *rza1_pctl, static int rza1_gpio_request(struct gpio_chip *chip, unsigned int gpio) { struct rza1_port *port = gpiochip_get_data(chip); + int ret; + + ret = pinctrl_gpio_request(chip, gpio); + if (ret) + return ret; rza1_pin_reset(port, gpio); @@ -771,6 +777,7 @@ static void rza1_gpio_free(struct gpio_chip *chip, unsigned int gpio) struct rza1_port *port = gpiochip_get_data(chip); rza1_pin_reset(port, gpio); + pinctrl_gpio_free(chip, gpio); } static int rza1_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c index af689d7c117f35..dd1f8c29d3e755 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza2.c +++ b/drivers/pinctrl/renesas/pinctrl-rza2.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -229,6 +230,8 @@ static const char * const rza2_gpio_names[] = { static struct gpio_chip chip = { .names = rza2_gpio_names, .base = -1, + .request = pinctrl_gpio_request, + .free = pinctrl_gpio_free, .get_direction = rza2_chip_get_direction, .direction_input = rza2_chip_direction_input, .direction_output = rza2_chip_direction_output, diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 5a403915fed2c6..1df9cec2873fff 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -139,6 +139,8 @@ #define IEN(off) (0x1800 + (off) * 8) #define PUPD(off) (0x1C00 + (off) * 8) #define ISEL(off) (0x2C00 + (off) * 8) +#define NOD(off) (0x3000 + (off) * 8) +#define SMT(off) (0x3400 + (off) * 8) #define SD_CH(off, ch) ((off) + (ch) * 4) #define ETH_POC(off, ch) ((off) + (ch) * 4) #define QSPI (0x3008) @@ -160,6 +162,8 @@ #define IOLH_MASK 0x03 #define SR_MASK 0x01 #define PUPD_MASK 0x03 +#define NOD_MASK 0x01 +#define SMT_MASK 0x01 #define PM_INPUT 0x1 #define PM_OUTPUT 0x2 @@ -168,7 +172,6 @@ #define RZG2L_PIN_ID_TO_PIN(id) ((id) % RZG2L_PINS_PER_PORT) #define RZG2L_TINT_MAX_INTERRUPT 32 -#define RZG2L_TINT_IRQ_START_INDEX 9 #define RZG2L_PACK_HWIRQ(t, i) (((t) << 16) | (i)) /* Custom pinconf parameters */ @@ -247,6 +250,7 @@ enum rzg2l_iolh_index { * @iolh_groupb_ua: IOLH group B uA specific values * @iolh_groupc_ua: IOLH group C uA specific values * @iolh_groupb_oi: IOLH group B output impedance specific values + * @tint_start_index: the start index for the TINT interrupts * @drive_strength_ua: drive strength in uA is supported (otherwise mA is supported) * @func_base: base number for port function (see register PFC) * @oen_max_pin: the maximum pin number supporting output enable @@ -258,6 +262,7 @@ struct rzg2l_hwcfg { u16 iolh_groupb_ua[RZG2L_IOLH_IDX_MAX]; u16 iolh_groupc_ua[RZG2L_IOLH_IDX_MAX]; u16 iolh_groupb_oi[4]; + u16 tint_start_index; bool drive_strength_ua; u8 func_base; u8 oen_max_pin; @@ -1337,6 +1342,27 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev, break; } + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + case PIN_CONFIG_DRIVE_PUSH_PULL: + if (!(cfg & PIN_CFG_NOD)) + return -EINVAL; + + arg = rzg2l_read_pin_config(pctrl, NOD(off), bit, NOD_MASK); + if (!arg && param != PIN_CONFIG_DRIVE_PUSH_PULL) + return -EINVAL; + if (arg && param != PIN_CONFIG_DRIVE_OPEN_DRAIN) + return -EINVAL; + break; + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (!(cfg & PIN_CFG_SMT)) + return -EINVAL; + + arg = rzg2l_read_pin_config(pctrl, SMT(off), bit, SMT_MASK); + if (!arg) + return -EINVAL; + break; + case RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE: if (!(cfg & PIN_CFG_IOLH_RZV2H)) return -EINVAL; @@ -1466,6 +1492,22 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev, rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, index); break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + case PIN_CONFIG_DRIVE_PUSH_PULL: + if (!(cfg & PIN_CFG_NOD)) + return -EINVAL; + + rzg2l_rmw_pin_config(pctrl, NOD(off), bit, NOD_MASK, + param == PIN_CONFIG_DRIVE_OPEN_DRAIN ? 1 : 0); + break; + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (!(cfg & PIN_CFG_SMT)) + return -EINVAL; + + rzg2l_rmw_pin_config(pctrl, SMT(off), bit, SMT_MASK, arg); + break; + case RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE: if (!(cfg & PIN_CFG_IOLH_RZV2H)) return -EINVAL; @@ -2290,7 +2332,7 @@ static void rzg2l_gpio_irq_print_chip(struct irq_data *data, struct seq_file *p) { struct gpio_chip *gc = irq_data_get_irq_chip_data(data); - seq_printf(p, dev_name(gc->parent)); + seq_puts(p, dev_name(gc->parent)); } static int rzg2l_gpio_irq_set_wake(struct irq_data *data, unsigned int on) @@ -2379,7 +2421,7 @@ static int rzg2l_gpio_child_to_parent_hwirq(struct gpio_chip *gc, rzg2l_gpio_irq_endisable(pctrl, child, true); pctrl->hwirq[irq] = child; - irq += RZG2L_TINT_IRQ_START_INDEX; + irq += pctrl->data->hwcfg->tint_start_index; /* All these interrupts are level high in the CPU */ *parent_type = IRQ_TYPE_LEVEL_HIGH; @@ -2391,21 +2433,6 @@ static int rzg2l_gpio_child_to_parent_hwirq(struct gpio_chip *gc, return ret; } -static int rzg2l_gpio_populate_parent_fwspec(struct gpio_chip *chip, - union gpio_irq_fwspec *gfwspec, - unsigned int parent_hwirq, - unsigned int parent_type) -{ - struct irq_fwspec *fwspec = &gfwspec->fwspec; - - fwspec->fwnode = chip->irq.parent_domain->fwnode; - fwspec->param_count = 2; - fwspec->param[0] = parent_hwirq; - fwspec->param[1] = parent_type; - - return 0; -} - static void rzg2l_gpio_irq_restore(struct rzg2l_pinctrl *pctrl) { struct irq_domain *domain = pctrl->gpio_chip.irq.domain; @@ -2607,7 +2634,7 @@ static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl) girq->fwnode = dev_fwnode(pctrl->dev); girq->parent_domain = parent_domain; girq->child_to_parent_hwirq = rzg2l_gpio_child_to_parent_hwirq; - girq->populate_parent_alloc_arg = rzg2l_gpio_populate_parent_fwspec; + girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell; girq->child_irq_domain_ops.free = rzg2l_gpio_irq_domain_free; girq->init_valid_mask = rzg2l_init_irq_valid_mask; @@ -2710,7 +2737,7 @@ static int rzg2l_pinctrl_register(struct rzg2l_pinctrl *pctrl) ret = pinctrl_enable(pctrl->pctl); if (ret) - dev_err_probe(pctrl->dev, ret, "pinctrl enable failed\n"); + return dev_err_probe(pctrl->dev, ret, "pinctrl enable failed\n"); ret = rzg2l_gpio_register(pctrl); if (ret) @@ -3034,6 +3061,7 @@ static const struct rzg2l_hwcfg rzg2l_hwcfg = { [RZG2L_IOLH_IDX_3V3] = 2000, 4000, 8000, 12000, }, .iolh_groupb_oi = { 100, 66, 50, 33, }, + .tint_start_index = 9, .oen_max_pin = 0, }; @@ -3063,6 +3091,7 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = { /* 3v3 power source */ [RZG2L_IOLH_IDX_3V3] = 4500, 5200, 5700, 6050, }, + .tint_start_index = 9, .drive_strength_ua = true, .func_base = 1, .oen_max_pin = 1, /* Pin 1 of P0 and P7 is the maximum OEN pin. */ @@ -3073,6 +3102,7 @@ static const struct rzg2l_hwcfg rzv2h_hwcfg = { .regs = { .pwpr = 0x3c04, }, + .tint_start_index = 17, }; static struct rzg2l_pinctrl_data r9a07g043_data = { diff --git a/drivers/pinctrl/renesas/pinctrl-rzn1.c b/drivers/pinctrl/renesas/pinctrl-rzn1.c index 39af1fe79c8462..d442d4f9981c90 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzn1.c +++ b/drivers/pinctrl/renesas/pinctrl-rzn1.c @@ -925,7 +925,7 @@ MODULE_DEVICE_TABLE(of, rzn1_pinctrl_match); static struct platform_driver rzn1_pinctrl_driver = { .probe = rzn1_pinctrl_probe, - .remove_new = rzn1_pinctrl_remove, + .remove = rzn1_pinctrl_remove, .driver = { .name = "rzn1-pinctrl", .of_match_table = rzn1_pinctrl_match, diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c index 5480e0884abecf..3ea7106ce5eae3 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c @@ -58,6 +58,15 @@ static const struct samsung_pin_bank_type exynos850_bank_type_alive = { .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, }; +/* + * Bank type for non-alive type. Bit fields: + * CON: 4, DAT: 1, PUD: 2, DRV: 3, CONPDN: 2, PUDPDN: 2 + */ +static const struct samsung_pin_bank_type exynos8895_bank_type_off = { + .fld_width = { 4, 1, 2, 3, 2, 2, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, }, +}; + /* Pad retention control code for accessing PMU regmap */ static atomic_t exynos_shared_retention_refcnt; @@ -618,6 +627,300 @@ const struct samsung_pinctrl_of_match_data exynos850_of_data __initconst = { .num_ctrl = ARRAY_SIZE(exynos850_pin_ctrl), }; +/* pin banks of exynos990 pin-controller 0 (ALIVE) */ +static struct samsung_pin_bank_data exynos990_pin_banks0[] = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS850_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00), + EXYNOS850_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04), + EXYNOS850_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08), + EXYNOS850_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c), + EXYNOS850_PIN_BANK_EINTW(2, 0x080, "gpa4", 0x10), + EXYNOS850_PIN_BANK_EINTN(7, 0x0A0, "gpq0"), +}; + +/* pin banks of exynos990 pin-controller 1 (CMGP) */ +static struct samsung_pin_bank_data exynos990_pin_banks1[] = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS850_PIN_BANK_EINTN(1, 0x000, "gpm0"), + EXYNOS850_PIN_BANK_EINTN(1, 0x020, "gpm1"), + EXYNOS850_PIN_BANK_EINTN(1, 0x040, "gpm2"), + EXYNOS850_PIN_BANK_EINTN(1, 0x060, "gpm3"), + EXYNOS850_PIN_BANK_EINTW(1, 0x080, "gpm4", 0x00), + EXYNOS850_PIN_BANK_EINTW(1, 0x0A0, "gpm5", 0x04), + EXYNOS850_PIN_BANK_EINTW(1, 0x0C0, "gpm6", 0x08), + EXYNOS850_PIN_BANK_EINTW(1, 0x0E0, "gpm7", 0x0c), + EXYNOS850_PIN_BANK_EINTW(1, 0x100, "gpm8", 0x10), + EXYNOS850_PIN_BANK_EINTW(1, 0x120, "gpm9", 0x14), + EXYNOS850_PIN_BANK_EINTW(1, 0x140, "gpm10", 0x18), + EXYNOS850_PIN_BANK_EINTW(1, 0x160, "gpm11", 0x1c), + EXYNOS850_PIN_BANK_EINTW(1, 0x180, "gpm12", 0x20), + EXYNOS850_PIN_BANK_EINTW(1, 0x1A0, "gpm13", 0x24), + EXYNOS850_PIN_BANK_EINTW(1, 0x1C0, "gpm14", 0x28), + EXYNOS850_PIN_BANK_EINTW(1, 0x1E0, "gpm15", 0x2c), + EXYNOS850_PIN_BANK_EINTW(1, 0x200, "gpm16", 0x30), + EXYNOS850_PIN_BANK_EINTW(1, 0x220, "gpm17", 0x34), + EXYNOS850_PIN_BANK_EINTW(1, 0x240, "gpm18", 0x38), + EXYNOS850_PIN_BANK_EINTW(1, 0x260, "gpm19", 0x3c), + EXYNOS850_PIN_BANK_EINTW(1, 0x280, "gpm20", 0x40), + EXYNOS850_PIN_BANK_EINTW(1, 0x2A0, "gpm21", 0x44), + EXYNOS850_PIN_BANK_EINTW(1, 0x2C0, "gpm22", 0x48), + EXYNOS850_PIN_BANK_EINTW(1, 0x2E0, "gpm23", 0x4c), + EXYNOS850_PIN_BANK_EINTW(1, 0x300, "gpm24", 0x50), + EXYNOS850_PIN_BANK_EINTW(1, 0x320, "gpm25", 0x54), + EXYNOS850_PIN_BANK_EINTW(1, 0x340, "gpm26", 0x58), + EXYNOS850_PIN_BANK_EINTW(1, 0x360, "gpm27", 0x5c), + EXYNOS850_PIN_BANK_EINTW(1, 0x380, "gpm28", 0x60), + EXYNOS850_PIN_BANK_EINTW(1, 0x3A0, "gpm29", 0x64), + EXYNOS850_PIN_BANK_EINTW(1, 0x3C0, "gpm30", 0x68), + EXYNOS850_PIN_BANK_EINTW(1, 0x3E0, "gpm31", 0x6c), + EXYNOS850_PIN_BANK_EINTW(1, 0x400, "gpm32", 0x70), + EXYNOS850_PIN_BANK_EINTW(1, 0x420, "gpm33", 0x74), + +}; + +/* pin banks of exynos990 pin-controller 2 (HSI1) */ +static struct samsung_pin_bank_data exynos990_pin_banks2[] = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gpf0", 0x00), + EXYNOS850_PIN_BANK_EINTG(6, 0x020, "gpf1", 0x04), + EXYNOS850_PIN_BANK_EINTG(3, 0x040, "gpf2", 0x08), +}; + +/* pin banks of exynos990 pin-controller 3 (HSI2) */ +static struct samsung_pin_bank_data exynos990_pin_banks3[] = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS850_PIN_BANK_EINTG(2, 0x000, "gpf3", 0x00), +}; + +/* pin banks of exynos990 pin-controller 4 (PERIC0) */ +static struct samsung_pin_bank_data exynos990_pin_banks4[] = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp0", 0x00), + EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp1", 0x04), + EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpp2", 0x08), + EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpp3", 0x0C), + EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpp4", 0x10), + EXYNOS850_PIN_BANK_EINTG(2, 0x0A0, "gpg0", 0x14), +}; + +/* pin banks of exynos990 pin-controller 5 (PERIC1) */ +static struct samsung_pin_bank_data exynos990_pin_banks5[] = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp5", 0x00), + EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp6", 0x04), + EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpp7", 0x08), + EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpp8", 0x0C), + EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpp9", 0x10), + EXYNOS850_PIN_BANK_EINTG(6, 0x0A0, "gpc0", 0x14), + EXYNOS850_PIN_BANK_EINTG(4, 0x0C0, "gpg1", 0x18), + EXYNOS850_PIN_BANK_EINTG(8, 0x0E0, "gpb0", 0x1C), + EXYNOS850_PIN_BANK_EINTG(8, 0x100, "gpb1", 0x20), + EXYNOS850_PIN_BANK_EINTG(8, 0x120, "gpb2", 0x24), +}; + +/* pin banks of exynos990 pin-controller 6 (VTS) */ +static struct samsung_pin_bank_data exynos990_pin_banks6[] = { + /* Must start with EINTG banks, ordered by EINT group number. */ + EXYNOS850_PIN_BANK_EINTG(7, 0x000, "gpv0", 0x00), +}; + +static const struct samsung_pin_ctrl exynos990_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 ALIVE data */ + .pin_banks = exynos990_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos990_pin_banks0), + .eint_wkup_init = exynos_eint_wkup_init, + }, { + /* pin-controller instance 1 CMGP data */ + .pin_banks = exynos990_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos990_pin_banks1), + .eint_wkup_init = exynos_eint_wkup_init, + }, { + /* pin-controller instance 2 HSI1 data */ + .pin_banks = exynos990_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos990_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 3 HSI2 data */ + .pin_banks = exynos990_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos990_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 4 PERIC0 data */ + .pin_banks = exynos990_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos990_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 5 PERIC1 data */ + .pin_banks = exynos990_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos990_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 6 VTS data */ + .pin_banks = exynos990_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos990_pin_banks6), + }, +}; + +const struct samsung_pinctrl_of_match_data exynos990_of_data __initconst = { + .ctrl = exynos990_pin_ctrl, + .num_ctrl = ARRAY_SIZE(exynos990_pin_ctrl), +}; + +/* pin banks of exynos9810 pin-controller 0 (ALIVE) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks0[] __initconst = { + EXYNOS850_PIN_BANK_EINTN(6, 0x000, "etc1"), + EXYNOS850_PIN_BANK_EINTW(8, 0x020, "gpa0", 0x00), + EXYNOS850_PIN_BANK_EINTW(8, 0x040, "gpa1", 0x04), + EXYNOS850_PIN_BANK_EINTW(8, 0x060, "gpa2", 0x08), + EXYNOS850_PIN_BANK_EINTW(8, 0x080, "gpa3", 0x0c), + EXYNOS850_PIN_BANK_EINTN(6, 0x0A0, "gpq0"), + EXYNOS850_PIN_BANK_EINTW(2, 0x0C0, "gpa4", 0x10), +}; + +/* pin banks of exynos9810 pin-controller 1 (AUD) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks1[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00), + EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpb1", 0x04), + EXYNOS850_PIN_BANK_EINTG(4, 0x040, "gpb2", 0x08), +}; + +/* pin banks of exynos9810 pin-controller 2 (CHUB) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks2[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gph0", 0x00), + EXYNOS850_PIN_BANK_EINTG(5, 0x020, "gph1", 0x04), +}; + +/* pin banks of exynos9810 pin-controller 3 (CMGP) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks3[] __initconst = { + EXYNOS850_PIN_BANK_EINTW(1, 0x000, "gpm0", 0x00), + EXYNOS850_PIN_BANK_EINTW(1, 0x020, "gpm1", 0x04), + EXYNOS850_PIN_BANK_EINTW(1, 0x040, "gpm2", 0x08), + EXYNOS850_PIN_BANK_EINTW(1, 0x060, "gpm3", 0x0C), + EXYNOS850_PIN_BANK_EINTW(1, 0x080, "gpm4", 0x10), + EXYNOS850_PIN_BANK_EINTW(1, 0x0A0, "gpm5", 0x14), + EXYNOS850_PIN_BANK_EINTW(1, 0x0C0, "gpm6", 0x18), + EXYNOS850_PIN_BANK_EINTW(1, 0x0E0, "gpm7", 0x1C), + EXYNOS850_PIN_BANK_EINTW(1, 0x100, "gpm10", 0x20), + EXYNOS850_PIN_BANK_EINTW(1, 0x120, "gpm11", 0x24), + EXYNOS850_PIN_BANK_EINTW(1, 0x140, "gpm12", 0x28), + EXYNOS850_PIN_BANK_EINTW(1, 0x160, "gpm13", 0x2C), + EXYNOS850_PIN_BANK_EINTW(1, 0x180, "gpm14", 0x30), + EXYNOS850_PIN_BANK_EINTW(1, 0x1A0, "gpm15", 0x34), + EXYNOS850_PIN_BANK_EINTW(1, 0x1C0, "gpm16", 0x38), + EXYNOS850_PIN_BANK_EINTW(1, 0x1E0, "gpm17", 0x3C), + EXYNOS850_PIN_BANK_EINTW(1, 0x200, "gpm40", 0x40), + EXYNOS850_PIN_BANK_EINTW(1, 0x220, "gpm41", 0x44), + EXYNOS850_PIN_BANK_EINTW(1, 0x240, "gpm42", 0x48), + EXYNOS850_PIN_BANK_EINTW(1, 0x260, "gpm43", 0x4C), +}; + +/* pin banks of exynos9810 pin-controller 4 (FSYS0) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks4[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(2, 0x000, "gpf0", 0x00), +}; + +/* pin banks of exynos9810 pin-controller 5 (FSYS1) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks5[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(7, 0x000, "gpf1", 0x00), + EXYNOS850_PIN_BANK_EINTG(6, 0x020, "gpf2", 0x04), +}; + +/* pin banks of exynos9810 pin-controller 6 (PERIC0) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks6[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp0", 0x00), + EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp1", 0x04), + EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpp2", 0x08), + EXYNOS850_PIN_BANK_EINTG(4, 0x060, "gpp3", 0x0C), + EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpg0", 0x10), + EXYNOS850_PIN_BANK_EINTG(8, 0x0A0, "gpg1", 0x14), + EXYNOS850_PIN_BANK_EINTG(8, 0x0C0, "gpg2", 0x18), +}; + +/* pin banks of exynos9810 pin-controller 7 (PERIC1) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks7[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(8, 0x000, "gpp4", 0x00), + EXYNOS850_PIN_BANK_EINTG(8, 0x020, "gpp5", 0x04), + EXYNOS850_PIN_BANK_EINTG(4, 0x040, "gpp6", 0x08), + EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpc0", 0x0C), + EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpc1", 0x10), + EXYNOS850_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14), + EXYNOS850_PIN_BANK_EINTG(7, 0x0C0, "gpg3", 0x18), +}; + +/* pin banks of exynos9810 pin-controller 8 (VTS) */ +static const struct samsung_pin_bank_data exynos9810_pin_banks8[] __initconst = { + EXYNOS850_PIN_BANK_EINTG(3, 0x000, "gpt0", 0x00), +}; + +static const struct samsung_pin_ctrl exynos9810_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 ALIVE data */ + .pin_banks = exynos9810_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks0), + .eint_wkup_init = exynos_eint_wkup_init, + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 1 AUD data */ + .pin_banks = exynos9810_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks1), + }, { + /* pin-controller instance 2 CHUB data */ + .pin_banks = exynos9810_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 3 CMGP data */ + .pin_banks = exynos9810_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks3), + .eint_wkup_init = exynos_eint_wkup_init, + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 4 FSYS0 data */ + .pin_banks = exynos9810_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 5 FSYS1 data */ + .pin_banks = exynos9810_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 6 PERIC0 data */ + .pin_banks = exynos9810_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 7 PERIC1 data */ + .pin_banks = exynos9810_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 8 VTS data */ + .pin_banks = exynos9810_pin_banks8, + .nr_banks = ARRAY_SIZE(exynos9810_pin_banks8), + }, +}; + +const struct samsung_pinctrl_of_match_data exynos9810_of_data __initconst = { + .ctrl = exynos9810_pin_ctrl, + .num_ctrl = ARRAY_SIZE(exynos9810_pin_ctrl), +}; + /* pin banks of exynosautov9 pin-controller 0 (ALIVE) */ static const struct samsung_pin_bank_data exynosautov9_pin_banks0[] __initconst = { EXYNOS850_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00), @@ -866,6 +1169,134 @@ const struct samsung_pinctrl_of_match_data exynosautov920_of_data __initconst = .num_ctrl = ARRAY_SIZE(exynosautov920_pin_ctrl), }; +/* pin banks of exynos8895 pin-controller 0 (ALIVE) */ +static const struct samsung_pin_bank_data exynos8895_pin_banks0[] __initconst = { + EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa0", 0x00), + EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa1", 0x04), + EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa2", 0x08), + EXYNOS_PIN_BANK_EINTW(8, 0x080, "gpa3", 0x0c), + EXYNOS_PIN_BANK_EINTW(7, 0x0a0, "gpa4", 0x24), +}; + +/* pin banks of exynos8895 pin-controller 1 (ABOX) */ +static const struct samsung_pin_bank_data exynos8895_pin_banks1[] __initconst = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gph0", 0x00), + EXYNOS_PIN_BANK_EINTG(7, 0x020, "gph1", 0x04), + EXYNOS_PIN_BANK_EINTG(4, 0x040, "gph3", 0x08), +}; + +/* pin banks of exynos8895 pin-controller 2 (VTS) */ +static const struct samsung_pin_bank_data exynos8895_pin_banks2[] __initconst = { + EXYNOS_PIN_BANK_EINTG(3, 0x000, "gph2", 0x00), +}; + +/* pin banks of exynos8895 pin-controller 3 (FSYS0) */ +static const struct samsung_pin_bank_data exynos8895_pin_banks3[] __initconst = { + EXYNOS8895_PIN_BANK_EINTG(3, 0x000, "gpi0", 0x00), + EXYNOS8895_PIN_BANK_EINTG(8, 0x020, "gpi1", 0x04), +}; + +/* pin banks of exynos8895 pin-controller 4 (FSYS1) */ +static const struct samsung_pin_bank_data exynos8895_pin_banks4[] __initconst = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj1", 0x00), + EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpj0", 0x04), +}; + +/* pin banks of exynos8895 pin-controller 5 (BUSC) */ +static const struct samsung_pin_bank_data exynos8895_pin_banks5[] __initconst = { + EXYNOS_PIN_BANK_EINTG(2, 0x000, "gpb2", 0x00), +}; + +/* pin banks of exynos8895 pin-controller 6 (PERIC0) */ +static const struct samsung_pin_bank_data exynos8895_pin_banks6[] __initconst = { + EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpd0", 0x00), + EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpd1", 0x04), + EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpd2", 0x08), + EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpd3", 0x0C), + EXYNOS_PIN_BANK_EINTG(4, 0x080, "gpb1", 0x10), + EXYNOS_PIN_BANK_EINTG(8, 0x0a0, "gpe7", 0x14), + EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpf1", 0x18), +}; + +/* pin banks of exynos8895 pin-controller 7 (PERIC1) */ +static const struct samsung_pin_bank_data exynos8895_pin_banks7[] __initconst = { + EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpb0", 0x00), + EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpc0", 0x04), + EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpc1", 0x08), + EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpc2", 0x0C), + EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpc3", 0x10), + EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpk0", 0x14), + EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpe5", 0x18), + EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpe6", 0x1C), + EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe2", 0x20), + EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpe3", 0x24), + EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe4", 0x28), + EXYNOS_PIN_BANK_EINTG(4, 0x160, "gpf0", 0x2C), + EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpe1", 0x30), + EXYNOS_PIN_BANK_EINTG(2, 0x1a0, "gpg0", 0x34), +}; + +static const struct samsung_pin_ctrl exynos8895_pin_ctrl[] __initconst = { + { + /* pin-controller instance 0 ALIVE data */ + .pin_banks = exynos8895_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos8895_pin_banks0), + .eint_gpio_init = exynos_eint_gpio_init, + .eint_wkup_init = exynos_eint_wkup_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 1 ABOX data */ + .pin_banks = exynos8895_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos8895_pin_banks1), + }, { + /* pin-controller instance 2 VTS data */ + .pin_banks = exynos8895_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos8895_pin_banks2), + .eint_gpio_init = exynos_eint_gpio_init, + }, { + /* pin-controller instance 3 FSYS0 data */ + .pin_banks = exynos8895_pin_banks3, + .nr_banks = ARRAY_SIZE(exynos8895_pin_banks3), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 4 FSYS1 data */ + .pin_banks = exynos8895_pin_banks4, + .nr_banks = ARRAY_SIZE(exynos8895_pin_banks4), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 5 BUSC data */ + .pin_banks = exynos8895_pin_banks5, + .nr_banks = ARRAY_SIZE(exynos8895_pin_banks5), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 6 PERIC0 data */ + .pin_banks = exynos8895_pin_banks6, + .nr_banks = ARRAY_SIZE(exynos8895_pin_banks6), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, { + /* pin-controller instance 7 PERIC1 data */ + .pin_banks = exynos8895_pin_banks7, + .nr_banks = ARRAY_SIZE(exynos8895_pin_banks7), + .eint_gpio_init = exynos_eint_gpio_init, + .suspend = exynos_pinctrl_suspend, + .resume = exynos_pinctrl_resume, + }, +}; + +const struct samsung_pinctrl_of_match_data exynos8895_of_data __initconst = { + .ctrl = exynos8895_pin_ctrl, + .num_ctrl = ARRAY_SIZE(exynos8895_pin_ctrl), +}; + /* * Pinctrl driver data for Tesla FSD SoC. FSD SoC includes three * gpio/pin-mux/pinconfig controllers. diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 305cb1d31de491..7b7ff7ffeb56bd 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -141,6 +141,16 @@ .name = id \ } +#define EXYNOS8895_PIN_BANK_EINTG(pins, reg, id, offs) \ + { \ + .type = &exynos8895_bank_type_off, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_GPIO, \ + .eint_offset = offs, \ + .name = id \ + } + #define EXYNOSV920_PIN_BANK_EINTG(pins, reg, id, con_offs, mask_offs, pend_offs) \ { \ .type = &exynos850_bank_type_off, \ diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index 675efa5d86a9af..bbedd980ec6723 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c @@ -1477,6 +1477,12 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = { .data = &exynos7885_of_data }, { .compatible = "samsung,exynos850-pinctrl", .data = &exynos850_of_data }, + { .compatible = "samsung,exynos8895-pinctrl", + .data = &exynos8895_of_data }, + { .compatible = "samsung,exynos9810-pinctrl", + .data = &exynos9810_of_data }, + { .compatible = "samsung,exynos990-pinctrl", + .data = &exynos990_of_data }, { .compatible = "samsung,exynosautov9-pinctrl", .data = &exynosautov9_of_data }, { .compatible = "samsung,exynosautov920-pinctrl", diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h index a1e7377bd890b7..bb0689d52ea0b4 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.h +++ b/drivers/pinctrl/samsung/pinctrl-samsung.h @@ -384,6 +384,9 @@ extern const struct samsung_pinctrl_of_match_data exynos5433_of_data; extern const struct samsung_pinctrl_of_match_data exynos7_of_data; extern const struct samsung_pinctrl_of_match_data exynos7885_of_data; extern const struct samsung_pinctrl_of_match_data exynos850_of_data; +extern const struct samsung_pinctrl_of_match_data exynos8895_of_data; +extern const struct samsung_pinctrl_of_match_data exynos9810_of_data; +extern const struct samsung_pinctrl_of_match_data exynos990_of_data; extern const struct samsung_pinctrl_of_match_data exynosautov9_of_data; extern const struct samsung_pinctrl_of_match_data exynosautov920_of_data; extern const struct samsung_pinctrl_of_match_data fsd_of_data; diff --git a/drivers/pinctrl/sophgo/Kconfig b/drivers/pinctrl/sophgo/Kconfig index b14792ee46fc3e..c05f909a88389c 100644 --- a/drivers/pinctrl/sophgo/Kconfig +++ b/drivers/pinctrl/sophgo/Kconfig @@ -43,7 +43,7 @@ config PINCTRL_SOPHGO_SG2000 pinctrl-sg2000. config PINCTRL_SOPHGO_SG2002 - tristate "Sophgo SG2000 SoC Pinctrl driver" + tristate "Sophgo SG2002 SoC Pinctrl driver" depends on ARCH_SOPHGO || COMPILE_TEST depends on OF select PINCTRL_SOPHGO_CV18XX diff --git a/drivers/pinctrl/spacemit/Kconfig b/drivers/pinctrl/spacemit/Kconfig new file mode 100644 index 00000000000000..168f8a5ffbb952 --- /dev/null +++ b/drivers/pinctrl/spacemit/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Sophgo SoC PINCTRL drivers +# + +config PINCTRL_SPACEMIT_K1 + tristate "SpacemiT K1 SoC Pinctrl driver" + depends on ARCH_SPACEMIT || COMPILE_TEST + depends on OF + select GENERIC_PINCTRL_GROUPS + select GENERIC_PINMUX_FUNCTIONS + select GENERIC_PINCONF + help + Say Y to select the pinctrl driver for K1 SoC. + This pin controller allows selecting the mux function for + each pin. This driver can also be built as a module called + pinctrl-k1. diff --git a/drivers/pinctrl/spacemit/Makefile b/drivers/pinctrl/spacemit/Makefile new file mode 100644 index 00000000000000..fede1e80fe0ff0 --- /dev/null +++ b/drivers/pinctrl/spacemit/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_PINCTRL_SPACEMIT_K1) += pinctrl-k1.o diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c new file mode 100644 index 00000000000000..a32579d736130c --- /dev/null +++ b/drivers/pinctrl/spacemit/pinctrl-k1.c @@ -0,0 +1,1051 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Yixun Lan */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../core.h" +#include "../pinctrl-utils.h" +#include "../pinconf.h" +#include "../pinmux.h" +#include "pinctrl-k1.h" + +/* + * +---------+----------+-----------+--------+--------+----------+--------+ + * | pull | drive | schmitter | slew | edge | strong | mux | + * | up/down | strength | trigger | rate | detect | pull | mode | + * +---------+----------+-----------+--------+--------+----------+--------+ + * 3 bits 3 bits 2 bits 1 bit 3 bits 1 bit 3 bits + */ + +#define PAD_MUX GENMASK(2, 0) +#define PAD_STRONG_PULL BIT(3) +#define PAD_EDGE_RISE BIT(4) +#define PAD_EDGE_FALL BIT(5) +#define PAD_EDGE_CLEAR BIT(6) +#define PAD_SLEW_RATE GENMASK(12, 11) +#define PAD_SLEW_RATE_EN BIT(7) +#define PAD_SCHMITT GENMASK(9, 8) +#define PAD_DRIVE GENMASK(12, 10) +#define PAD_PULLDOWN BIT(13) +#define PAD_PULLUP BIT(14) +#define PAD_PULL_EN BIT(15) + +struct spacemit_pin { + u16 pin; + u16 flags; + u8 gpiofunc; +}; + +struct spacemit_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl_dev; + const struct spacemit_pinctrl_data *data; + struct pinctrl_desc pdesc; + + struct mutex mutex; + raw_spinlock_t lock; + + void __iomem *regs; +}; + +struct spacemit_pinctrl_data { + const struct pinctrl_pin_desc *pins; + const struct spacemit_pin *data; + u16 npins; +}; + +struct spacemit_pin_mux_config { + const struct spacemit_pin *pin; + u32 config; +}; + +struct spacemit_pin_drv_strength { + u8 val; + u32 mA; +}; + +/* map pin id to pinctrl register offset, refer MFPR definition */ +static unsigned int spacemit_pin_to_offset(unsigned int pin) +{ + unsigned int offset = 0; + + switch (pin) { + case 0 ... 85: + offset = pin + 1; + break; + case 86 ... 92: + offset = pin + 37; + break; + case 93 ... 97: + offset = pin + 24; + break; + case 98: + offset = 93; + break; + case 99: + offset = 92; + break; + case 100: + offset = 91; + break; + case 101: + offset = 90; + break; + case 102: + offset = 95; + break; + case 103: + offset = 94; + break; + case 104 ... 110: + offset = pin + 6; + break; + case 111 ... 127: + offset = pin + 20; + break; + default: + break; + } + + return offset << 2; +} + +static inline void __iomem *spacemit_pin_to_reg(struct spacemit_pinctrl *pctrl, + unsigned int pin) +{ + return pctrl->regs + spacemit_pin_to_offset(pin); +} + +static u16 spacemit_dt_get_pin(u32 value) +{ + return value >> 16; +} + +static u16 spacemit_dt_get_pin_mux(u32 value) +{ + return value & GENMASK(15, 0); +} + +static const struct spacemit_pin *spacemit_get_pin(struct spacemit_pinctrl *pctrl, + unsigned long pin) +{ + const struct spacemit_pin *pdata = pctrl->data->data; + int i; + + for (i = 0; i < pctrl->data->npins; i++) { + if (pin == pdata[i].pin) + return &pdata[i]; + } + + return NULL; +} + +static inline enum spacemit_pin_io_type spacemit_to_pin_io_type( + const struct spacemit_pin *pin) +{ + return K1_PIN_GET_IO_TYPE(pin->flags); +} + +/* External: IO voltage via external source, can be 1.8V or 3.3V */ +static const char * const io_type_desc[] = { + "None", + "Fixed/1V8", + "Fixed/3V3", + "External", +}; + +static void spacemit_pctrl_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *seq, unsigned int pin) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin); + enum spacemit_pin_io_type type = spacemit_to_pin_io_type(spin); + void __iomem *reg; + u32 value; + + seq_printf(seq, "offset: 0x%04x ", spacemit_pin_to_offset(pin)); + seq_printf(seq, "type: %s ", io_type_desc[type]); + + reg = spacemit_pin_to_reg(pctrl, pin); + value = readl(reg); + seq_printf(seq, "mux: %ld reg: 0x%04x", (value & PAD_MUX), value); +} + +/* use IO high level output current as the table */ +static struct spacemit_pin_drv_strength spacemit_ds_1v8_tbl[4] = { + { 0, 11 }, + { 2, 21 }, + { 4, 32 }, + { 6, 42 }, +}; + +static struct spacemit_pin_drv_strength spacemit_ds_3v3_tbl[8] = { + { 0, 7 }, + { 2, 10 }, + { 4, 13 }, + { 6, 16 }, + { 1, 19 }, + { 3, 23 }, + { 5, 26 }, + { 7, 29 }, +}; + +static inline u8 spacemit_get_ds_value(struct spacemit_pin_drv_strength *tbl, + u32 num, u32 mA) +{ + int i; + + for (i = 0; i < num; i++) + if (mA <= tbl[i].mA) + return tbl[i].val; + + return tbl[num - 1].val; +} + +static inline u32 spacemit_get_ds_mA(struct spacemit_pin_drv_strength *tbl, + u32 num, u32 val) +{ + int i; + + for (i = 0; i < num; i++) + if (val == tbl[i].val) + return tbl[i].mA; + + return 0; +} + +static inline u8 spacemit_get_driver_strength(enum spacemit_pin_io_type type, + u32 mA) +{ + switch (type) { + case IO_TYPE_1V8: + return spacemit_get_ds_value(spacemit_ds_1v8_tbl, + ARRAY_SIZE(spacemit_ds_1v8_tbl), + mA); + case IO_TYPE_3V3: + return spacemit_get_ds_value(spacemit_ds_3v3_tbl, + ARRAY_SIZE(spacemit_ds_3v3_tbl), + mA); + default: + return 0; + } +} + +static inline u32 spacemit_get_drive_strength_mA(enum spacemit_pin_io_type type, + u32 value) +{ + switch (type) { + case IO_TYPE_1V8: + return spacemit_get_ds_mA(spacemit_ds_1v8_tbl, + ARRAY_SIZE(spacemit_ds_1v8_tbl), + value & 0x6); + case IO_TYPE_3V3: + return spacemit_get_ds_mA(spacemit_ds_3v3_tbl, + ARRAY_SIZE(spacemit_ds_3v3_tbl), + value); + default: + return 0; + } +} + +static int spacemit_pctrl_check_power(struct pinctrl_dev *pctldev, + struct device_node *dn, + struct spacemit_pin_mux_config *pinmuxs, + int num_pins, const char *grpname) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = pctrl->dev; + enum spacemit_pin_io_type type; + u32 power = 0, i; + + of_property_read_u32(dn, "power-source", &power); + + for (i = 0; i < num_pins; i++) { + type = spacemit_to_pin_io_type(pinmuxs[i].pin); + + if (type != IO_TYPE_EXTERNAL) + continue; + + switch (power) { + case PIN_POWER_STATE_1V8: + case PIN_POWER_STATE_3V3: + break; + default: + dev_err(dev, "group %s has unsupported power\n", + grpname); + return -ENOTSUPP; + } + } + + return 0; +} + +static int spacemit_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **maps, + unsigned int *num_maps) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = pctrl->dev; + struct device_node *child; + struct pinctrl_map *map; + const char **grpnames; + const char *grpname; + int ngroups = 0; + int nmaps = 0; + int ret; + + for_each_available_child_of_node(np, child) + ngroups += 1; + + grpnames = devm_kcalloc(dev, ngroups, sizeof(*grpnames), GFP_KERNEL); + if (!grpnames) + return -ENOMEM; + + map = kcalloc(ngroups * 2, sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + ngroups = 0; + guard(mutex)(&pctrl->mutex); + for_each_available_child_of_node_scoped(np, child) { + struct spacemit_pin_mux_config *pinmuxs; + unsigned int config, *pins; + int i, npins; + + npins = of_property_count_u32_elems(child, "pinmux"); + + if (npins < 1) { + dev_err(dev, "invalid pinctrl group %pOFn.%pOFn\n", + np, child); + return -EINVAL; + } + + grpname = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", + np, child); + if (!grpname) + return -ENOMEM; + + grpnames[ngroups++] = grpname; + + pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); + if (!pins) + return -ENOMEM; + + pinmuxs = devm_kcalloc(dev, npins, sizeof(*pinmuxs), GFP_KERNEL); + if (!pinmuxs) + return -ENOMEM; + + for (i = 0; i < npins; i++) { + ret = of_property_read_u32_index(child, "pinmux", + i, &config); + + if (ret) + return -EINVAL; + + pins[i] = spacemit_dt_get_pin(config); + pinmuxs[i].config = config; + pinmuxs[i].pin = spacemit_get_pin(pctrl, pins[i]); + + if (!pinmuxs[i].pin) + return dev_err_probe(dev, -ENODEV, "failed to get pin %d\n", pins[i]); + } + + ret = spacemit_pctrl_check_power(pctldev, child, pinmuxs, + npins, grpname); + if (ret < 0) + return ret; + + map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP; + map[nmaps].data.mux.function = np->name; + map[nmaps].data.mux.group = grpname; + nmaps += 1; + + ret = pinctrl_generic_add_group(pctldev, grpname, + pins, npins, pinmuxs); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to add group %s: %d\n", grpname, ret); + + ret = pinconf_generic_parse_dt_config(child, pctldev, + &map[nmaps].data.configs.configs, + &map[nmaps].data.configs.num_configs); + if (ret) + return dev_err_probe(dev, ret, "failed to parse pin config of group %s\n", + grpname); + + if (map[nmaps].data.configs.num_configs == 0) + continue; + + map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; + map[nmaps].data.configs.group_or_pin = grpname; + nmaps += 1; + } + + ret = pinmux_generic_add_function(pctldev, np->name, + grpnames, ngroups, NULL); + if (ret < 0) { + pinctrl_utils_free_map(pctldev, map, nmaps); + return dev_err_probe(dev, ret, "error adding function %s\n", np->name); + } + + *maps = map; + *num_maps = nmaps; + + return 0; +} + +static const struct pinctrl_ops spacemit_pctrl_ops = { + .get_groups_count = pinctrl_generic_get_group_count, + .get_group_name = pinctrl_generic_get_group_name, + .get_group_pins = pinctrl_generic_get_group_pins, + .pin_dbg_show = spacemit_pctrl_dbg_show, + .dt_node_to_map = spacemit_pctrl_dt_node_to_map, + .dt_free_map = pinctrl_utils_free_map, +}; + +static int spacemit_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int fsel, unsigned int gsel) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct group_desc *group; + const struct spacemit_pin_mux_config *configs; + unsigned int i, mux; + void __iomem *reg; + + group = pinctrl_generic_get_group(pctldev, gsel); + if (!group) + return -EINVAL; + + configs = group->data; + + for (i = 0; i < group->grp.npins; i++) { + const struct spacemit_pin *spin = configs[i].pin; + u32 value = configs[i].config; + + reg = spacemit_pin_to_reg(pctrl, spin->pin); + mux = spacemit_dt_get_pin_mux(value); + + guard(raw_spinlock_irqsave)(&pctrl->lock); + value = readl_relaxed(reg) & ~PAD_MUX; + writel_relaxed(mux | value, reg); + } + + return 0; +} + +static int spacemit_request_gpio(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin); + void __iomem *reg; + + reg = spacemit_pin_to_reg(pctrl, pin); + guard(raw_spinlock_irqsave)(&pctrl->lock); + writel_relaxed(spin->gpiofunc, reg); + + return 0; +} + +static const struct pinmux_ops spacemit_pmx_ops = { + .get_functions_count = pinmux_generic_get_function_count, + .get_function_name = pinmux_generic_get_function_name, + .get_function_groups = pinmux_generic_get_function_groups, + .set_mux = spacemit_pmx_set_mux, + .gpio_request_enable = spacemit_request_gpio, + .strict = true, +}; + +static int spacemit_pinconf_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + int param = pinconf_to_config_param(*config); + u32 value, arg = 0; + + if (!pin) + return -EINVAL; + + value = readl(spacemit_pin_to_reg(pctrl, pin)); + + switch (param) { + case PIN_CONFIG_SLEW_RATE: + if (FIELD_GET(PAD_SLEW_RATE_EN, value)) + arg = FIELD_GET(PAD_SLEW_RATE, value) + 2; + else + arg = 0; + break; + default: + return -EINVAL; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +#define ENABLE_DRV_STRENGTH BIT(1) +#define ENABLE_SLEW_RATE BIT(2) +static int spacemit_pinconf_generate_config(const struct spacemit_pin *spin, + unsigned long *configs, + unsigned int num_configs, + u32 *value) +{ + enum spacemit_pin_io_type type; + int i, param; + u32 v = 0, voltage = 0, arg, val; + u32 flag = 0, drv_strength, slew_rate; + + if (!spin) + return -EINVAL; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + v &= ~(PAD_PULL_EN | PAD_PULLDOWN | PAD_PULLUP); + v &= ~PAD_STRONG_PULL; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + v &= ~(PAD_PULLUP | PAD_STRONG_PULL); + v |= (PAD_PULL_EN | PAD_PULLDOWN); + break; + case PIN_CONFIG_BIAS_PULL_UP: + v &= ~PAD_PULLDOWN; + v |= (PAD_PULL_EN | PAD_PULLUP); + + if (arg == 1) + v |= PAD_STRONG_PULL; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + flag |= ENABLE_DRV_STRENGTH; + drv_strength = arg; + break; + case PIN_CONFIG_INPUT_SCHMITT: + v &= ~PAD_SCHMITT; + v |= FIELD_PREP(PAD_SCHMITT, arg); + break; + case PIN_CONFIG_POWER_SOURCE: + voltage = arg; + break; + case PIN_CONFIG_SLEW_RATE: + if (arg) { + flag |= ENABLE_SLEW_RATE; + v |= PAD_SLEW_RATE_EN; + slew_rate = arg; + } else { + v &= ~PAD_SLEW_RATE_EN; + } + break; + default: + return -EINVAL; + } + } + + if (flag & ENABLE_DRV_STRENGTH) { + type = spacemit_to_pin_io_type(spin); + + /* fix external io type */ + if (type == IO_TYPE_EXTERNAL) { + switch (voltage) { + case 1800: + type = IO_TYPE_1V8; + break; + case 3300: + type = IO_TYPE_3V3; + break; + default: + return -EINVAL; + } + } + + val = spacemit_get_driver_strength(type, drv_strength); + + v &= ~PAD_DRIVE; + v |= FIELD_PREP(PAD_DRIVE, val); + } + + if (flag & ENABLE_SLEW_RATE) { + /* check, driver strength & slew rate */ + if (flag & ENABLE_DRV_STRENGTH) { + val = FIELD_GET(PAD_SLEW_RATE, v) + 2; + if (slew_rate > 1 && slew_rate != val) { + pr_err("slew rate conflict with drive strength\n"); + return -EINVAL; + } + } else { + v &= ~PAD_SLEW_RATE; + slew_rate = slew_rate > 1 ? (slew_rate - 2) : 0; + v |= FIELD_PREP(PAD_SLEW_RATE, slew_rate); + } + } + + *value = v; + + return 0; +} + +static int spacemit_pin_set_config(struct spacemit_pinctrl *pctrl, + unsigned int pin, u32 value) +{ + const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin); + void __iomem *reg; + unsigned int mux; + + if (!pin) + return -EINVAL; + + reg = spacemit_pin_to_reg(pctrl, spin->pin); + + guard(raw_spinlock_irqsave)(&pctrl->lock); + mux = readl_relaxed(reg) & PAD_MUX; + writel_relaxed(mux | value, reg); + + return 0; +} + +static int spacemit_pinconf_set(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *configs, + unsigned int num_configs) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin); + u32 value; + + if (spacemit_pinconf_generate_config(spin, configs, num_configs, &value)) + return -EINVAL; + + return spacemit_pin_set_config(pctrl, pin, value); +} + +static int spacemit_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned int gsel, + unsigned long *configs, + unsigned int num_configs) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct spacemit_pin *spin; + const struct group_desc *group; + u32 value; + int i; + + group = pinctrl_generic_get_group(pctldev, gsel); + if (!group) + return -EINVAL; + + spin = spacemit_get_pin(pctrl, group->grp.pins[0]); + if (spacemit_pinconf_generate_config(spin, configs, num_configs, &value)) + return -EINVAL; + + for (i = 0; i < group->grp.npins; i++) + spacemit_pin_set_config(pctrl, group->grp.pins[i], value); + + return 0; +} + +static void spacemit_pinconf_dbg_pull(struct seq_file *seq, unsigned int value) +{ + u32 normal, strong; + + if (!FIELD_GET(PAD_PULL_EN, value)) { + seq_puts(seq, ", bias pull disabled"); + return; + } + + if (FIELD_GET(PAD_PULLDOWN, value)) + seq_puts(seq, ", bias pull down"); + + normal = FIELD_GET(PAD_PULLUP, value); + strong = FIELD_GET(PAD_STRONG_PULL, value); + + if (normal && strong) + seq_puts(seq, ", bias strong pull up"); + else if (normal) + seq_puts(seq, ", bias normal pull up"); +} + +static void spacemit_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *seq, unsigned int pin) +{ + struct spacemit_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + const struct spacemit_pin *spin = spacemit_get_pin(pctrl, pin); + enum spacemit_pin_io_type type = spacemit_to_pin_io_type(spin); + void __iomem *reg = spacemit_pin_to_reg(pctrl, pin); + u32 value, tmp, mA; + + value = readl(reg); + spacemit_pinconf_dbg_pull(seq, value); + + seq_printf(seq, ", io type (%s)", io_type_desc[type]); + + tmp = FIELD_GET(PAD_DRIVE, value); + if (type == IO_TYPE_1V8 || type == IO_TYPE_3V3) { + mA = spacemit_get_drive_strength_mA(type, tmp); + seq_printf(seq, ", drive strength (%d mA)", mA); + } + + /* drive strength depend on power source, so show all values */ + if (type == IO_TYPE_EXTERNAL) + seq_printf(seq, ", drive strength (%d or %d mA)", + spacemit_get_drive_strength_mA(IO_TYPE_1V8, tmp), + spacemit_get_drive_strength_mA(IO_TYPE_3V3, tmp)); + + seq_printf(seq, ", register (0x%04x)\n", value); +} + +static const struct pinconf_ops spacemit_pinconf_ops = { + .pin_config_get = spacemit_pinconf_get, + .pin_config_set = spacemit_pinconf_set, + .pin_config_group_set = spacemit_pinconf_group_set, + .pin_config_dbg_show = spacemit_pinconf_dbg_show, + .is_generic = true, +}; + +static int spacemit_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spacemit_pinctrl *pctrl; + const struct spacemit_pinctrl_data *pctrl_data; + int ret; + + pctrl_data = device_get_match_data(dev); + if (!pctrl_data) + return -ENODEV; + + if (pctrl_data->npins == 0) + return dev_err_probe(dev, -EINVAL, "invalid pin data\n"); + + pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pctrl->regs)) + return PTR_ERR(pctrl->regs); + + pctrl->pdesc.name = dev_name(dev); + pctrl->pdesc.pins = pctrl_data->pins; + pctrl->pdesc.npins = pctrl_data->npins; + pctrl->pdesc.pctlops = &spacemit_pctrl_ops; + pctrl->pdesc.pmxops = &spacemit_pmx_ops; + pctrl->pdesc.confops = &spacemit_pinconf_ops; + pctrl->pdesc.owner = THIS_MODULE; + + pctrl->data = pctrl_data; + pctrl->dev = dev; + raw_spin_lock_init(&pctrl->lock); + mutex_init(&pctrl->mutex); + + platform_set_drvdata(pdev, pctrl); + + ret = devm_pinctrl_register_and_init(dev, &pctrl->pdesc, + pctrl, &pctrl->pctl_dev); + if (ret) + return dev_err_probe(dev, ret, + "fail to register pinctrl driver\n"); + + return pinctrl_enable(pctrl->pctl_dev); +} + +static const struct pinctrl_pin_desc k1_pin_desc[] = { + PINCTRL_PIN(0, "GPIO_00"), + PINCTRL_PIN(1, "GPIO_01"), + PINCTRL_PIN(2, "GPIO_02"), + PINCTRL_PIN(3, "GPIO_03"), + PINCTRL_PIN(4, "GPIO_04"), + PINCTRL_PIN(5, "GPIO_05"), + PINCTRL_PIN(6, "GPIO_06"), + PINCTRL_PIN(7, "GPIO_07"), + PINCTRL_PIN(8, "GPIO_08"), + PINCTRL_PIN(9, "GPIO_09"), + 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/PRI_DTI"), + PINCTRL_PIN(71, "GPIO_71/PRI_TMS"), + PINCTRL_PIN(72, "GPIO_72/PRI_TCK"), + PINCTRL_PIN(73, "GPIO_73/PRI_TDO"), + 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/PWR_SCL"), + PINCTRL_PIN(94, "GPIO_94/PWR_SDA"), + PINCTRL_PIN(95, "GPIO_95/VCX0_EN"), + PINCTRL_PIN(96, "GPIO_96/DVL0"), + PINCTRL_PIN(97, "GPIO_97/DVL1"), + PINCTRL_PIN(98, "GPIO_98/QSPI_DAT3"), + PINCTRL_PIN(99, "GPIO_99/QSPI_DAT2"), + PINCTRL_PIN(100, "GPIO_100/QSPI_DAT1"), + PINCTRL_PIN(101, "GPIO_101/QSPI_DAT0"), + PINCTRL_PIN(102, "GPIO_102/QSPI_CLK"), + PINCTRL_PIN(103, "GPIO_103/QSPI_CS1"), + PINCTRL_PIN(104, "GPIO_104/MMC1_DAT3"), + PINCTRL_PIN(105, "GPIO_105/MMC1_DAT2"), + PINCTRL_PIN(106, "GPIO_106/MMC1_DAT1"), + PINCTRL_PIN(107, "GPIO_107/MMC1_DAT0"), + PINCTRL_PIN(108, "GPIO_108/MMC1_CMD"), + PINCTRL_PIN(109, "GPIO_109/MMC1_CLK"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), +}; + +static const struct spacemit_pin k1_pin_data[ARRAY_SIZE(k1_pin_desc)] = { + K1_FUNC_PIN(0, 0, IO_TYPE_1V8), + K1_FUNC_PIN(1, 0, IO_TYPE_1V8), + K1_FUNC_PIN(2, 0, IO_TYPE_1V8), + K1_FUNC_PIN(3, 0, IO_TYPE_1V8), + K1_FUNC_PIN(4, 0, IO_TYPE_1V8), + K1_FUNC_PIN(5, 0, IO_TYPE_1V8), + K1_FUNC_PIN(6, 0, IO_TYPE_1V8), + K1_FUNC_PIN(7, 0, IO_TYPE_1V8), + K1_FUNC_PIN(8, 0, IO_TYPE_1V8), + K1_FUNC_PIN(9, 0, IO_TYPE_1V8), + K1_FUNC_PIN(10, 0, IO_TYPE_1V8), + K1_FUNC_PIN(11, 0, IO_TYPE_1V8), + K1_FUNC_PIN(12, 0, IO_TYPE_1V8), + K1_FUNC_PIN(13, 0, IO_TYPE_1V8), + K1_FUNC_PIN(14, 0, IO_TYPE_1V8), + K1_FUNC_PIN(15, 0, IO_TYPE_1V8), + K1_FUNC_PIN(16, 0, IO_TYPE_1V8), + K1_FUNC_PIN(17, 0, IO_TYPE_1V8), + K1_FUNC_PIN(18, 0, IO_TYPE_1V8), + K1_FUNC_PIN(19, 0, IO_TYPE_1V8), + K1_FUNC_PIN(20, 0, IO_TYPE_1V8), + K1_FUNC_PIN(21, 0, IO_TYPE_1V8), + K1_FUNC_PIN(22, 0, IO_TYPE_1V8), + K1_FUNC_PIN(23, 0, IO_TYPE_1V8), + K1_FUNC_PIN(24, 0, IO_TYPE_1V8), + K1_FUNC_PIN(25, 0, IO_TYPE_1V8), + K1_FUNC_PIN(26, 0, IO_TYPE_1V8), + K1_FUNC_PIN(27, 0, IO_TYPE_1V8), + K1_FUNC_PIN(28, 0, IO_TYPE_1V8), + K1_FUNC_PIN(29, 0, IO_TYPE_1V8), + K1_FUNC_PIN(30, 0, IO_TYPE_1V8), + K1_FUNC_PIN(31, 0, IO_TYPE_1V8), + K1_FUNC_PIN(32, 0, IO_TYPE_1V8), + K1_FUNC_PIN(33, 0, IO_TYPE_1V8), + K1_FUNC_PIN(34, 0, IO_TYPE_1V8), + K1_FUNC_PIN(35, 0, IO_TYPE_1V8), + K1_FUNC_PIN(36, 0, IO_TYPE_1V8), + K1_FUNC_PIN(37, 0, IO_TYPE_1V8), + K1_FUNC_PIN(38, 0, IO_TYPE_1V8), + K1_FUNC_PIN(39, 0, IO_TYPE_1V8), + K1_FUNC_PIN(40, 0, IO_TYPE_1V8), + K1_FUNC_PIN(41, 0, IO_TYPE_1V8), + K1_FUNC_PIN(42, 0, IO_TYPE_1V8), + K1_FUNC_PIN(43, 0, IO_TYPE_1V8), + K1_FUNC_PIN(44, 0, IO_TYPE_1V8), + K1_FUNC_PIN(45, 0, IO_TYPE_1V8), + K1_FUNC_PIN(46, 0, IO_TYPE_1V8), + K1_FUNC_PIN(47, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(48, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(49, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(50, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(51, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(52, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(53, 0, IO_TYPE_1V8), + K1_FUNC_PIN(54, 0, IO_TYPE_1V8), + K1_FUNC_PIN(55, 0, IO_TYPE_1V8), + K1_FUNC_PIN(56, 0, IO_TYPE_1V8), + K1_FUNC_PIN(57, 0, IO_TYPE_1V8), + K1_FUNC_PIN(58, 0, IO_TYPE_1V8), + K1_FUNC_PIN(59, 0, IO_TYPE_1V8), + K1_FUNC_PIN(60, 0, IO_TYPE_1V8), + K1_FUNC_PIN(61, 0, IO_TYPE_1V8), + K1_FUNC_PIN(62, 0, IO_TYPE_1V8), + K1_FUNC_PIN(63, 0, IO_TYPE_1V8), + K1_FUNC_PIN(64, 0, IO_TYPE_1V8), + K1_FUNC_PIN(65, 0, IO_TYPE_1V8), + K1_FUNC_PIN(66, 0, IO_TYPE_1V8), + K1_FUNC_PIN(67, 0, IO_TYPE_1V8), + K1_FUNC_PIN(68, 0, IO_TYPE_1V8), + K1_FUNC_PIN(69, 0, IO_TYPE_1V8), + K1_FUNC_PIN(70, 1, IO_TYPE_1V8), + K1_FUNC_PIN(71, 1, IO_TYPE_1V8), + K1_FUNC_PIN(72, 1, IO_TYPE_1V8), + K1_FUNC_PIN(73, 1, IO_TYPE_1V8), + K1_FUNC_PIN(74, 0, IO_TYPE_1V8), + K1_FUNC_PIN(75, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(76, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(77, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(78, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(79, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(80, 0, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(81, 0, IO_TYPE_1V8), + K1_FUNC_PIN(82, 0, IO_TYPE_1V8), + K1_FUNC_PIN(83, 0, IO_TYPE_1V8), + K1_FUNC_PIN(84, 0, IO_TYPE_1V8), + K1_FUNC_PIN(85, 0, IO_TYPE_1V8), + K1_FUNC_PIN(86, 0, IO_TYPE_1V8), + K1_FUNC_PIN(87, 0, IO_TYPE_1V8), + K1_FUNC_PIN(88, 0, IO_TYPE_1V8), + K1_FUNC_PIN(89, 0, IO_TYPE_1V8), + K1_FUNC_PIN(90, 0, IO_TYPE_1V8), + K1_FUNC_PIN(91, 0, IO_TYPE_1V8), + K1_FUNC_PIN(92, 0, IO_TYPE_1V8), + K1_FUNC_PIN(93, 1, IO_TYPE_1V8), + K1_FUNC_PIN(94, 1, IO_TYPE_1V8), + K1_FUNC_PIN(95, 1, IO_TYPE_1V8), + K1_FUNC_PIN(96, 1, IO_TYPE_1V8), + K1_FUNC_PIN(97, 1, IO_TYPE_1V8), + K1_FUNC_PIN(98, 1, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(99, 1, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(100, 1, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(101, 1, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(102, 1, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(103, 1, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(104, 4, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(105, 4, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(106, 4, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(107, 4, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(108, 4, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(109, 4, IO_TYPE_EXTERNAL), + K1_FUNC_PIN(110, 0, IO_TYPE_1V8), + K1_FUNC_PIN(111, 0, IO_TYPE_1V8), + K1_FUNC_PIN(112, 0, IO_TYPE_1V8), + K1_FUNC_PIN(113, 0, IO_TYPE_1V8), + K1_FUNC_PIN(114, 0, IO_TYPE_1V8), + K1_FUNC_PIN(115, 0, IO_TYPE_1V8), + K1_FUNC_PIN(116, 0, IO_TYPE_1V8), + K1_FUNC_PIN(117, 0, IO_TYPE_1V8), + K1_FUNC_PIN(118, 0, IO_TYPE_1V8), + K1_FUNC_PIN(119, 0, IO_TYPE_1V8), + K1_FUNC_PIN(120, 0, IO_TYPE_1V8), + K1_FUNC_PIN(121, 0, IO_TYPE_1V8), + K1_FUNC_PIN(122, 0, IO_TYPE_1V8), + K1_FUNC_PIN(123, 0, IO_TYPE_1V8), + K1_FUNC_PIN(124, 0, IO_TYPE_1V8), + K1_FUNC_PIN(125, 0, IO_TYPE_1V8), + K1_FUNC_PIN(126, 0, IO_TYPE_1V8), + K1_FUNC_PIN(127, 0, IO_TYPE_1V8), +}; + +static const struct spacemit_pinctrl_data k1_pinctrl_data = { + .pins = k1_pin_desc, + .data = k1_pin_data, + .npins = ARRAY_SIZE(k1_pin_desc), +}; + +static const struct of_device_id k1_pinctrl_ids[] = { + { .compatible = "spacemit,k1-pinctrl", .data = &k1_pinctrl_data }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, k1_pinctrl_ids); + +static struct platform_driver k1_pinctrl_driver = { + .probe = spacemit_pinctrl_probe, + .driver = { + .name = "k1-pinctrl", + .suppress_bind_attrs = true, + .of_match_table = k1_pinctrl_ids, + }, +}; +module_platform_driver(k1_pinctrl_driver); + +MODULE_AUTHOR("Yixun Lan "); +MODULE_DESCRIPTION("Pinctrl driver for the SpacemiT K1 SoC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.h b/drivers/pinctrl/spacemit/pinctrl-k1.h new file mode 100644 index 00000000000000..16143fea469ebc --- /dev/null +++ b/drivers/pinctrl/spacemit/pinctrl-k1.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2024 Yixun Lan */ + +#ifndef _PINCTRL_SPACEMIT_K1_H +#define _PINCTRL_SPACEMIT_K1_H + +#include +#include +#include +#include +#include +#include +#include +#include + +enum spacemit_pin_io_type { + IO_TYPE_NONE = 0, + IO_TYPE_1V8, + IO_TYPE_3V3, + IO_TYPE_EXTERNAL, +}; + +#define PIN_POWER_STATE_1V8 1800 +#define PIN_POWER_STATE_3V3 3300 + +#define K1_PIN_IO_TYPE GENMASK(2, 1) + +#define K1_PIN_CAP_IO_TYPE(type) \ + FIELD_PREP_CONST(K1_PIN_IO_TYPE, type) +#define K1_PIN_GET_IO_TYPE(val) \ + FIELD_GET(K1_PIN_IO_TYPE, val) + +#define K1_FUNC_PIN(_id, _gpiofunc, _io) \ + { \ + .pin = (_id), \ + .gpiofunc = (_gpiofunc), \ + .flags = (K1_PIN_CAP_IO_TYPE(_io)), \ + } + +#endif /* _PINCTRL_SPACEMIT_K1_H */ diff --git a/drivers/pinctrl/sprd/pinctrl-sprd-sc9860.c b/drivers/pinctrl/sprd/pinctrl-sprd-sc9860.c index 9c3c39dc6550c8..d14f382f2392c6 100644 --- a/drivers/pinctrl/sprd/pinctrl-sprd-sc9860.c +++ b/drivers/pinctrl/sprd/pinctrl-sprd-sc9860.c @@ -943,7 +943,7 @@ static struct platform_driver sprd_pinctrl_driver = { .of_match_table = sprd_pinctrl_of_match, }, .probe = sprd_pinctrl_probe, - .remove_new = sprd_pinctrl_remove, + .remove = sprd_pinctrl_remove, .shutdown = sprd_pinctrl_shutdown, }; module_platform_driver(sprd_pinctrl_driver); diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 7dbeb786352af7..b7dbaf77b6db46 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -61,6 +61,17 @@ config CHROMEOS_TBMC To compile this driver as a module, choose M here: the module will be called chromeos_tbmc. +config CHROMEOS_OF_HW_PROBER + tristate "ChromeOS Device Tree Hardware Prober" + depends on OF + depends on I2C + select OF_DYNAMIC + default OF + help + This option enables the device tree hardware prober for ChromeOS + devices. The driver will probe the correct component variant in + devices that have multiple drop-in options for one component. + config CROS_EC tristate "ChromeOS Embedded Controller" select CROS_EC_PROTO diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 2dcc6ccc23022b..fb8335458a2216 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -6,6 +6,7 @@ CFLAGS_cros_ec_sensorhub_ring.o:= -I$(src) obj-$(CONFIG_CHROMEOS_ACPI) += chromeos_acpi.o obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o +obj-$(CONFIG_CHROMEOS_OF_HW_PROBER) += chromeos_of_hw_prober.o obj-$(CONFIG_CHROMEOS_PRIVACY_SCREEN) += chromeos_privacy_screen.o obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o diff --git a/drivers/platform/chrome/chromeos_of_hw_prober.c b/drivers/platform/chrome/chromeos_of_hw_prober.c new file mode 100644 index 00000000000000..c6992f5cdc7660 --- /dev/null +++ b/drivers/platform/chrome/chromeos_of_hw_prober.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ChromeOS Device Tree Hardware Prober + * + * Copyright (c) 2024 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "chromeos_of_hw_prober" + +/** + * struct hw_prober_entry - Holds an entry for the hardware prober + * + * @compatible: compatible string to match against the machine + * @prober: prober function to call when machine matches + * @data: extra data for the prober function + */ +struct hw_prober_entry { + const char *compatible; + int (*prober)(struct device *dev, const void *data); + const void *data; +}; + +struct chromeos_i2c_probe_data { + const struct i2c_of_probe_cfg *cfg; + const struct i2c_of_probe_simple_opts *opts; +}; + +static int chromeos_i2c_component_prober(struct device *dev, const void *_data) +{ + const struct chromeos_i2c_probe_data *data = _data; + struct i2c_of_probe_simple_ctx ctx = { + .opts = data->opts, + }; + + return i2c_of_probe_component(dev, data->cfg, &ctx); +} + +#define DEFINE_CHROMEOS_I2C_PROBE_CFG_SIMPLE_BY_TYPE(_type) \ + static const struct i2c_of_probe_cfg chromeos_i2c_probe_simple_ ## _type ## _cfg = { \ + .type = #_type, \ + .ops = &i2c_of_probe_simple_ops, \ + } + +#define DEFINE_CHROMEOS_I2C_PROBE_DATA_DUMB_BY_TYPE(_type) \ + static const struct chromeos_i2c_probe_data chromeos_i2c_probe_dumb_ ## _type = { \ + .cfg = &(const struct i2c_of_probe_cfg) { \ + .type = #_type, \ + }, \ + } + +DEFINE_CHROMEOS_I2C_PROBE_DATA_DUMB_BY_TYPE(touchscreen); + +DEFINE_CHROMEOS_I2C_PROBE_CFG_SIMPLE_BY_TYPE(trackpad); + +static const struct chromeos_i2c_probe_data chromeos_i2c_probe_hana_trackpad = { + .cfg = &chromeos_i2c_probe_simple_trackpad_cfg, + .opts = &(const struct i2c_of_probe_simple_opts) { + .res_node_compatible = "elan,ekth3000", + .supply_name = "vcc", + /* + * ELAN trackpad needs 2 ms for H/W init and 100 ms for F/W init. + * Synaptics trackpad needs 100 ms. + * However, the regulator is set to "always-on", presumably to + * avoid this delay. The ELAN driver is also missing delays. + */ + .post_power_on_delay_ms = 0, + }, +}; + +static const struct hw_prober_entry hw_prober_platforms[] = { + { + .compatible = "google,hana", + .prober = chromeos_i2c_component_prober, + .data = &chromeos_i2c_probe_dumb_touchscreen, + }, { + .compatible = "google,hana", + .prober = chromeos_i2c_component_prober, + .data = &chromeos_i2c_probe_hana_trackpad, + }, +}; + +static int chromeos_of_hw_prober_probe(struct platform_device *pdev) +{ + for (size_t i = 0; i < ARRAY_SIZE(hw_prober_platforms); i++) { + int ret; + + if (!of_machine_is_compatible(hw_prober_platforms[i].compatible)) + continue; + + ret = hw_prober_platforms[i].prober(&pdev->dev, hw_prober_platforms[i].data); + /* Ignore unrecoverable errors and keep going through other probers */ + if (ret == -EPROBE_DEFER) + return ret; + } + + return 0; +} + +static struct platform_driver chromeos_of_hw_prober_driver = { + .probe = chromeos_of_hw_prober_probe, + .driver = { + .name = DRV_NAME, + }, +}; + +static struct platform_device *chromeos_of_hw_prober_pdev; + +static int chromeos_of_hw_prober_driver_init(void) +{ + size_t i; + int ret; + + for (i = 0; i < ARRAY_SIZE(hw_prober_platforms); i++) + if (of_machine_is_compatible(hw_prober_platforms[i].compatible)) + break; + if (i == ARRAY_SIZE(hw_prober_platforms)) + return -ENODEV; + + ret = platform_driver_register(&chromeos_of_hw_prober_driver); + if (ret) + return ret; + + chromeos_of_hw_prober_pdev = + platform_device_register_simple(DRV_NAME, PLATFORM_DEVID_NONE, NULL, 0); + if (IS_ERR(chromeos_of_hw_prober_pdev)) + goto err; + + return 0; + +err: + platform_driver_unregister(&chromeos_of_hw_prober_driver); + + return PTR_ERR(chromeos_of_hw_prober_pdev); +} +module_init(chromeos_of_hw_prober_driver_init); + +static void chromeos_of_hw_prober_driver_exit(void) +{ + platform_device_unregister(chromeos_of_hw_prober_pdev); + platform_driver_unregister(&chromeos_of_hw_prober_driver); +} +module_exit(chromeos_of_hw_prober_driver_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ChromeOS device tree hardware prober"); +MODULE_IMPORT_NS("I2C_OF_PROBER"); diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c index 7f034ead7ae47c..21a484385fc5db 100644 --- a/drivers/platform/chrome/cros_ec_chardev.c +++ b/drivers/platform/chrome/cros_ec_chardev.c @@ -415,7 +415,7 @@ static struct platform_driver cros_ec_chardev_driver = { .name = DRV_NAME, }, .probe = cros_ec_chardev_probe, - .remove_new = cros_ec_chardev_remove, + .remove = cros_ec_chardev_remove, .id_table = cros_ec_chardev_id, }; diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index 839154c46e46cd..92ac9a2f9c88f6 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -582,7 +582,7 @@ static struct platform_driver cros_ec_debugfs_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = cros_ec_debugfs_probe, - .remove_new = cros_ec_debugfs_remove, + .remove = cros_ec_debugfs_remove, .id_table = cros_ec_debugfs_id, }; diff --git a/drivers/platform/chrome/cros_ec_i2c.c b/drivers/platform/chrome/cros_ec_i2c.c index e29c51cbfd71b4..62662ba5bf6e76 100644 --- a/drivers/platform/chrome/cros_ec_i2c.c +++ b/drivers/platform/chrome/cros_ec_i2c.c @@ -352,7 +352,7 @@ MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match); #endif static const struct i2c_device_id cros_ec_i2c_id[] = { - { "cros-ec-i2c", 0 }, + { "cros-ec-i2c" }, { } }; MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id); diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 1e69f61115a4d0..87634f6921b78a 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -608,7 +608,7 @@ static struct platform_driver cros_ec_lightbar_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = cros_ec_lightbar_probe, - .remove_new = cros_ec_lightbar_remove, + .remove = cros_ec_lightbar_remove, .id_table = cros_ec_lightbar_id, }; diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index c784119ab5dc0c..924bf4d3cc77b9 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -783,7 +783,7 @@ static struct platform_driver cros_ec_lpc_driver = { .probe_type = PROBE_FORCE_SYNCHRONOUS, }, .probe = cros_ec_lpc_probe, - .remove_new = cros_ec_lpc_remove, + .remove = cros_ec_lpc_remove, }; static struct platform_device cros_ec_lpc_device = { diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index 9c944146ee507d..bc1a5ba0952815 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -359,7 +359,7 @@ static struct platform_driver cros_ec_sysfs_driver = { .name = DRV_NAME, }, .probe = cros_ec_sysfs_probe, - .remove_new = cros_ec_sysfs_remove, + .remove = cros_ec_sysfs_remove, .id_table = cros_ec_sysfs_id, }; diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index c7781aea0b88b2..ae2f862969547c 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -409,6 +409,7 @@ static int cros_typec_init_ports(struct cros_typec_data *typec) return 0; unregister_ports: + fwnode_handle_put(fwnode); cros_unregister_ports(typec); return ret; } @@ -1325,7 +1326,7 @@ static struct platform_driver cros_typec_driver = { .pm = &cros_typec_pm_ops, }, .probe = cros_typec_probe, - .remove_new = cros_typec_remove, + .remove = cros_typec_remove, }; module_platform_driver(cros_typec_driver); diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c index 787a19db4911af..7bdb489354c5d2 100644 --- a/drivers/platform/chrome/cros_ec_vbc.c +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -145,7 +145,7 @@ static struct platform_driver cros_ec_vbc_driver = { .name = DRV_NAME, }, .probe = cros_ec_vbc_probe, - .remove_new = cros_ec_vbc_remove, + .remove = cros_ec_vbc_remove, .id_table = cros_ec_vbc_id, }; diff --git a/drivers/platform/chrome/cros_hps_i2c.c b/drivers/platform/chrome/cros_hps_i2c.c index dd14957ec39fc4..6b479cfe3f73a5 100644 --- a/drivers/platform/chrome/cros_hps_i2c.c +++ b/drivers/platform/chrome/cros_hps_i2c.c @@ -129,7 +129,7 @@ static int hps_resume(struct device *dev) static DEFINE_RUNTIME_DEV_PM_OPS(hps_pm_ops, hps_suspend, hps_resume, NULL); static const struct i2c_device_id hps_i2c_id[] = { - { "cros-hps", 0 }, + { "cros-hps" }, { } }; MODULE_DEVICE_TABLE(i2c, hps_i2c_id); diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index 07a19386dc4eee..8d7c34abb0a128 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -318,7 +318,7 @@ static struct platform_driver cros_typec_switch_driver = { .acpi_match_table = ACPI_PTR(cros_typec_switch_acpi_id), }, .probe = cros_typec_switch_probe, - .remove_new = cros_typec_switch_remove, + .remove = cros_typec_switch_remove, }; module_platform_driver(cros_typec_switch_driver); diff --git a/drivers/platform/chrome/cros_usbpd_logger.c b/drivers/platform/chrome/cros_usbpd_logger.c index 930c2f47269f6f..cd71f1caea81e8 100644 --- a/drivers/platform/chrome/cros_usbpd_logger.c +++ b/drivers/platform/chrome/cros_usbpd_logger.c @@ -262,7 +262,7 @@ static struct platform_driver cros_usbpd_logger_driver = { .pm = &cros_usbpd_logger_pm_ops, }, .probe = cros_usbpd_logger_probe, - .remove_new = cros_usbpd_logger_remove, + .remove = cros_usbpd_logger_remove, .id_table = cros_usbpd_logger_id, }; diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index c83f81d86483c1..313d2bcd577bda 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -156,7 +156,7 @@ static struct platform_driver cros_usbpd_notify_acpi_driver = { .acpi_match_table = cros_usbpd_notify_acpi_device_ids, }, .probe = cros_usbpd_notify_probe_acpi, - .remove_new = cros_usbpd_notify_remove_acpi, + .remove = cros_usbpd_notify_remove_acpi, }; #endif /* CONFIG_ACPI */ @@ -230,7 +230,7 @@ static struct platform_driver cros_usbpd_notify_plat_driver = { .name = DRV_NAME, }, .probe = cros_usbpd_notify_probe_plat, - .remove_new = cros_usbpd_notify_remove_plat, + .remove = cros_usbpd_notify_remove_plat, .id_table = cros_usbpd_notify_id, }; diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c index 3e6b6cd81a9bb0..9f978e531e1f5e 100644 --- a/drivers/platform/chrome/wilco_ec/core.c +++ b/drivers/platform/chrome/wilco_ec/core.c @@ -163,7 +163,7 @@ static struct platform_driver wilco_ec_driver = { .acpi_match_table = wilco_ec_acpi_device_ids, }, .probe = wilco_ec_probe, - .remove_new = wilco_ec_remove, + .remove = wilco_ec_remove, .id_table = wilco_ec_id, }; diff --git a/drivers/platform/chrome/wilco_ec/debugfs.c b/drivers/platform/chrome/wilco_ec/debugfs.c index 99486086af6a16..0617292b5cd76e 100644 --- a/drivers/platform/chrome/wilco_ec/debugfs.c +++ b/drivers/platform/chrome/wilco_ec/debugfs.c @@ -276,7 +276,7 @@ static struct platform_driver wilco_ec_debugfs_driver = { .name = DRV_NAME, }, .probe = wilco_ec_debugfs_probe, - .remove_new = wilco_ec_debugfs_remove, + .remove = wilco_ec_debugfs_remove, .id_table = wilco_ec_debugfs_id, }; diff --git a/drivers/platform/chrome/wilco_ec/telemetry.c b/drivers/platform/chrome/wilco_ec/telemetry.c index a87877e4300a5b..7d8ae2cbf72f9e 100644 --- a/drivers/platform/chrome/wilco_ec/telemetry.c +++ b/drivers/platform/chrome/wilco_ec/telemetry.c @@ -417,7 +417,7 @@ MODULE_DEVICE_TABLE(platform, telem_id); static struct platform_driver telem_driver = { .probe = telem_device_probe, - .remove_new = telem_device_remove, + .remove = telem_device_remove, .driver = { .name = DRV_NAME, }, diff --git a/drivers/platform/cznic/turris-omnia-mcu-gpio.c b/drivers/platform/cznic/turris-omnia-mcu-gpio.c index 88e208d458820a..5f35f7c5d5d7ed 100644 --- a/drivers/platform/cznic/turris-omnia-mcu-gpio.c +++ b/drivers/platform/cznic/turris-omnia-mcu-gpio.c @@ -28,7 +28,7 @@ #define OMNIA_CMD_INT_ARG_LEN 8 #define FRONT_BUTTON_RELEASE_DELAY_MS 50 -static const char * const omnia_mcu_gpio_templates[64] = { +static const char * const omnia_mcu_gpio_names[64] = { /* GPIOs with value read from the 16-bit wide status */ [4] = "MiniPCIe0 Card Detect", [5] = "MiniPCIe0 mSATA Indicator", @@ -1018,7 +1018,7 @@ int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu) mcu->gc.set_multiple = omnia_gpio_set_multiple; mcu->gc.init_valid_mask = omnia_gpio_init_valid_mask; mcu->gc.can_sleep = true; - mcu->gc.names = omnia_mcu_gpio_templates; + mcu->gc.names = omnia_mcu_gpio_names; mcu->gc.base = -1; mcu->gc.ngpio = ARRAY_SIZE(omnia_gpios); mcu->gc.label = "Turris Omnia MCU GPIOs"; diff --git a/drivers/platform/cznic/turris-omnia-mcu.h b/drivers/platform/cznic/turris-omnia-mcu.h index 57ef5d3500436a..2b13e28ee323b3 100644 --- a/drivers/platform/cznic/turris-omnia-mcu.h +++ b/drivers/platform/cznic/turris-omnia-mcu.h @@ -23,41 +23,71 @@ struct i2c_client; struct rtc_device; +/** + * struct omnia_mcu - driver private data structure + * @client: I2C client + * @type: MCU type (STM32, GD32, MKL, or unknown) + * @features: bitmap of features supported by the MCU firmware + * @board_serial_number: board serial number, if stored in MCU + * @board_first_mac: board first MAC address, if stored in MCU + * @board_revision: board revision, if stored in MCU + * @gc: GPIO chip + * @lock: mutex to protect internal GPIO chip state + * @mask: bitmap of masked IRQs + * @rising: bitmap of rising edge IRQs + * @falling: bitmap of falling edge IRQs + * @both: bitmap of both edges IRQs + * @cached: bitmap of cached IRQ line values (when an IRQ line is configured for + * both edges, we cache the corresponding GPIO values in the IRQ + * handler) + * @is_cached: bitmap of which IRQ line values are cached + * @button_release_emul_work: front button release emulation work, used with old MCU firmware + * versions which did not send button release events, only button press + * events + * @last_status: cached value of the status word, to be compared with new value to + * determine which interrupt events occurred, used with old MCU + * firmware versions which only informed that the status word changed, + * but not which bits of the status word changed + * @button_pressed_emul: the front button is still emulated to be pressed + * @rtcdev: RTC device, does not actually count real-time, the device is only + * used for the RTC alarm mechanism, so that the board can be + * configured to wake up from poweroff state at a specific time + * @rtc_alarm: RTC alarm that was set for the board to wake up on, in MCU time + * (seconds since last MCU reset) + * @front_button_poweron: the front button should power on the device after it is powered off + * @wdt: watchdog driver structure + * @trng: RNG driver structure + * @trng_entropy_ready: RNG entropy ready completion + */ struct omnia_mcu { struct i2c_client *client; const char *type; u32 features; - /* board information */ u64 board_serial_number; u8 board_first_mac[ETH_ALEN]; u8 board_revision; #ifdef CONFIG_TURRIS_OMNIA_MCU_GPIO - /* GPIO chip */ struct gpio_chip gc; struct mutex lock; unsigned long mask, rising, falling, both, cached, is_cached; - /* Old MCU firmware handling needs the following */ struct delayed_work button_release_emul_work; unsigned long last_status; bool button_pressed_emul; #endif #ifdef CONFIG_TURRIS_OMNIA_MCU_SYSOFF_WAKEUP - /* RTC device for configuring wake-up */ struct rtc_device *rtcdev; u32 rtc_alarm; bool front_button_poweron; #endif #ifdef CONFIG_TURRIS_OMNIA_MCU_WATCHDOG - /* MCU watchdog */ struct watchdog_device wdt; #endif #ifdef CONFIG_TURRIS_OMNIA_MCU_TRNG - /* true random number generator */ struct hwrng trng; struct completion trng_entropy_ready; #endif diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index c2aab0cfab3383..abc31971fe6a3a 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -61,7 +61,6 @@ #include #include #include -#include #include #include "goldfish_pipe_qemu.h" @@ -936,11 +935,11 @@ MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match); static struct platform_driver goldfish_pipe_driver = { .probe = goldfish_pipe_probe, - .remove_new = goldfish_pipe_remove, + .remove = goldfish_pipe_remove, .driver = { .name = "goldfish_pipe", .of_match_table = goldfish_pipe_of_match, - .acpi_match_table = ACPI_PTR(goldfish_pipe_acpi_match), + .acpi_match_table = goldfish_pipe_acpi_match, } }; diff --git a/drivers/platform/loongarch/Kconfig b/drivers/platform/loongarch/Kconfig index 5633e4d73991a6..447528797d07aa 100644 --- a/drivers/platform/loongarch/Kconfig +++ b/drivers/platform/loongarch/Kconfig @@ -18,7 +18,7 @@ if LOONGARCH_PLATFORM_DEVICES config LOONGSON_LAPTOP tristate "Generic Loongson-3 Laptop Driver" - depends on ACPI + depends on ACPI_EC depends on BACKLIGHT_CLASS_DEVICE depends on INPUT depends on MACH_LOONGSON64 diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c index dd5f370c316823..c5b36837e6943a 100644 --- a/drivers/platform/mellanox/mlxbf-bootctl.c +++ b/drivers/platform/mellanox/mlxbf-bootctl.c @@ -1049,7 +1049,7 @@ static void mlxbf_bootctl_remove(struct platform_device *pdev) static struct platform_driver mlxbf_bootctl_driver = { .probe = mlxbf_bootctl_probe, - .remove_new = mlxbf_bootctl_remove, + .remove = mlxbf_bootctl_remove, .driver = { .name = "mlxbf-bootctl", .dev_groups = mlxbf_bootctl_groups, diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index 6c834e39352d61..300cdaa75a1770 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -1446,7 +1446,7 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match); static struct platform_driver mlxbf_tmfifo_driver = { .probe = mlxbf_tmfifo_probe, - .remove_new = mlxbf_tmfifo_remove, + .remove = mlxbf_tmfifo_remove, .driver = { .name = "bf-tmfifo", .acpi_match_table = mlxbf_tmfifo_acpi_match, diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index 0ce9fff1f7d4d4..6aa2a465036707 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -786,7 +786,7 @@ static struct platform_driver mlxreg_hotplug_driver = { .name = "mlxreg-hotplug", }, .probe = mlxreg_hotplug_probe, - .remove_new = mlxreg_hotplug_remove, + .remove = mlxreg_hotplug_remove, }; module_platform_driver(mlxreg_hotplug_driver); diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c index ee7bd623ba44f4..595276206baf12 100644 --- a/drivers/platform/mellanox/mlxreg-io.c +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -275,7 +275,7 @@ static struct platform_driver mlxreg_io_driver = { .name = "mlxreg-io", }, .probe = mlxreg_io_probe, - .remove_new = mlxreg_io_remove, + .remove = mlxreg_io_remove, }; module_platform_driver(mlxreg_io_driver); diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index 43d119e3a47342..aee395bb48ae44 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -944,7 +944,7 @@ static void mlxreg_lc_remove(struct platform_device *pdev) static struct platform_driver mlxreg_lc_driver = { .probe = mlxreg_lc_probe, - .remove_new = mlxreg_lc_remove, + .remove = mlxreg_lc_remove, .driver = { .name = "mlxreg-lc", }, diff --git a/drivers/platform/mellanox/nvsw-sn2201.c b/drivers/platform/mellanox/nvsw-sn2201.c index abe7be602f846e..0c047aa2345b36 100644 --- a/drivers/platform/mellanox/nvsw-sn2201.c +++ b/drivers/platform/mellanox/nvsw-sn2201.c @@ -1253,7 +1253,7 @@ MODULE_DEVICE_TABLE(acpi, nvsw_sn2201_acpi_ids); static struct platform_driver nvsw_sn2201_driver = { .probe = nvsw_sn2201_probe, - .remove_new = nvsw_sn2201_remove, + .remove = nvsw_sn2201_remove, .driver = { .name = "nvsw-sn2201", .acpi_match_table = nvsw_sn2201_acpi_ids, diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c index c15ed7a12784ae..6c8fb7a4dde444 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -247,7 +247,7 @@ static struct platform_driver s3_wmi_driver = { .name = "surface3-wmi", .pm = &s3_wmi_pm, }, - .remove_new = s3_wmi_remove, + .remove = s3_wmi_remove, }; static int __init s3_wmi_init(void) diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index 14a9d8a267cbbe..3b30cfe3466b8f 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -850,7 +850,7 @@ MODULE_DEVICE_TABLE(acpi, san_match); static struct platform_driver surface_acpi_notify = { .probe = san_probe, - .remove_new = san_remove, + .remove = san_remove, .driver = { .name = "surface_acpi_notify", .acpi_match_table = san_match, diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c index 165b1416230d71..bfaa09d1648bcf 100644 --- a/drivers/platform/surface/surface_aggregator_cdev.c +++ b/drivers/platform/surface/surface_aggregator_cdev.c @@ -762,7 +762,7 @@ static struct platform_device *ssam_cdev_device; static struct platform_driver ssam_cdev_driver = { .probe = ssam_dbg_device_probe, - .remove_new = ssam_dbg_device_remove, + .remove = ssam_dbg_device_remove, .driver = { .name = SSAM_CDEV_DEVICE_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 25c8aa2131d638..d4f32ad6653054 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -371,7 +371,7 @@ static const struct software_node *ssam_node_group_sp8[] = { NULL, }; -/* Devices for Surface Pro 9 and 10 */ +/* Devices for Surface Pro 9 (Intel/x86) and 10 */ static const struct software_node *ssam_node_group_sp9[] = { &ssam_node_root, &ssam_node_hub_kip, @@ -390,6 +390,21 @@ static const struct software_node *ssam_node_group_sp9[] = { NULL, }; +/* Devices for Surface Pro 9 5G (ARM/QCOM) */ +static const struct software_node *ssam_node_group_sp9_5g[] = { + &ssam_node_root, + &ssam_node_hub_kip, + &ssam_node_bat_ac, + &ssam_node_bat_main, + &ssam_node_tmp_sensors, + &ssam_node_hid_kip_keyboard, + &ssam_node_hid_kip_penstash, + &ssam_node_hid_kip_touchpad, + &ssam_node_hid_kip_fwupd, + &ssam_node_hid_sam_sensors, + &ssam_node_kip_tablet_switch, + NULL, +}; /* -- SSAM platform/meta-hub driver. ---------------------------------------- */ @@ -462,6 +477,8 @@ static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_acpi_match); static const struct of_device_id ssam_platform_hub_of_match[] __maybe_unused = { + /* Surface Pro 9 5G (ARM/QCOM) */ + { .compatible = "microsoft,arcata", (void *)ssam_node_group_sp9_5g }, /* Surface Laptop 7 */ { .compatible = "microsoft,romulus13", (void *)ssam_node_group_sl7 }, { .compatible = "microsoft,romulus15", (void *)ssam_node_group_sl7 }, @@ -537,7 +554,7 @@ static void ssam_platform_hub_remove(struct platform_device *pdev) static struct platform_driver ssam_platform_hub_driver = { .probe = ssam_platform_hub_probe, - .remove_new = ssam_platform_hub_remove, + .remove = ssam_platform_hub_remove, .driver = { .name = "surface_aggregator_platform_hub", .acpi_match_table = ssam_platform_hub_acpi_match, diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c index 89ca6b50e8129b..97ae010069e40a 100644 --- a/drivers/platform/surface/surface_dtx.c +++ b/drivers/platform/surface/surface_dtx.c @@ -1180,7 +1180,7 @@ MODULE_DEVICE_TABLE(acpi, surface_dtx_acpi_match); static struct platform_driver surface_dtx_platform_driver = { .probe = surface_dtx_platform_probe, - .remove_new = surface_dtx_platform_remove, + .remove = surface_dtx_platform_remove, .driver = { .name = "surface_dtx_pltf", .acpi_match_table = surface_dtx_acpi_match, diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c index 62fd4004db31a0..b359413903b13c 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -278,7 +278,7 @@ static void surface_gpe_remove(struct platform_device *pdev) static struct platform_driver surface_gpe_driver = { .probe = surface_gpe_probe, - .remove_new = surface_gpe_remove, + .remove = surface_gpe_remove, .driver = { .name = "surface_gpe", .pm = &surface_gpe_pm, diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c index a404f26cfae8d7..c0d83ed5a208c4 100644 --- a/drivers/platform/surface/surface_hotplug.c +++ b/drivers/platform/surface/surface_hotplug.c @@ -259,7 +259,7 @@ MODULE_DEVICE_TABLE(acpi, surface_hotplug_acpi_match); static struct platform_driver surface_hotplug_driver = { .probe = surface_hotplug_probe, - .remove_new = surface_hotplug_remove, + .remove = surface_hotplug_remove, .driver = { .name = "surface_hotplug", .acpi_match_table = surface_hotplug_acpi_match, diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 3875abba5a7903..0258dd879d64be 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -52,6 +52,7 @@ config WMI_BMOF config HUAWEI_WMI tristate "Huawei WMI laptop extras driver" depends on ACPI_BATTERY + depends on ACPI_EC depends on ACPI_WMI depends on INPUT select INPUT_SPARSEKMAP @@ -147,7 +148,7 @@ config YT2_1380 config ACERHDF tristate "Acer Aspire One temperature and fan driver" - depends on ACPI && THERMAL + depends on ACPI_EC && THERMAL select THERMAL_GOV_BANG_BANG help This is a driver for Acer Aspire One netbooks. It allows to access @@ -186,6 +187,7 @@ config ACER_WMI depends on SERIO_I8042 depends on INPUT depends on RFKILL || RFKILL = n + depends on ACPI_EC depends on ACPI_WMI depends on ACPI_VIDEO || ACPI_VIDEO = n depends on HWMON @@ -334,7 +336,7 @@ config MERAKI_MX100 config EEEPC_LAPTOP tristate "Eee PC Hotkey Driver" - depends on ACPI + depends on ACPI_EC depends on INPUT depends on RFKILL || RFKILL = n depends on ACPI_VIDEO || ACPI_VIDEO = n @@ -503,7 +505,7 @@ config SENSORS_HDAPS config THINKPAD_ACPI tristate "ThinkPad ACPI Laptop Extras" - depends on ACPI + depends on ACPI_EC depends on ACPI_BATTERY depends on INPUT depends on RFKILL || RFKILL = n @@ -682,7 +684,7 @@ config MEEGOPAD_ANX7428 config MSI_EC tristate "MSI EC Extras" - depends on ACPI + depends on ACPI_EC depends on ACPI_BATTERY help This driver allows various MSI laptops' functionalities to be @@ -690,7 +692,7 @@ config MSI_EC config MSI_LAPTOP tristate "MSI Laptop Extras" - depends on ACPI + depends on ACPI_EC depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL @@ -796,7 +798,7 @@ config SAMSUNG_LAPTOP config SAMSUNG_Q10 tristate "Samsung Q10 Extras" - depends on ACPI + depends on ACPI_EC select BACKLIGHT_CLASS_DEVICE help This driver provides support for backlight control on Samsung Q10 @@ -804,7 +806,7 @@ config SAMSUNG_Q10 config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" - depends on ACPI + depends on ACPI_EC depends on ACPI_BATTERY depends on ACPI_WMI select LEDS_CLASS @@ -904,7 +906,7 @@ config ACPI_CMPC config COMPAL_LAPTOP tristate "Compal (and others) Laptop Extras" - depends on ACPI + depends on ACPI_EC depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL @@ -949,7 +951,7 @@ config PANASONIC_LAPTOP config SONY_LAPTOP tristate "Sony Laptop Extras" - depends on ACPI + depends on ACPI_EC depends on ACPI_VIDEO || ACPI_VIDEO = n depends on BACKLIGHT_CLASS_DEVICE depends on INPUT @@ -972,7 +974,7 @@ config SONYPI_COMPAT config SYSTEM76_ACPI tristate "System76 ACPI Driver" - depends on ACPI + depends on ACPI_EC depends on ACPI_BATTERY depends on HWMON depends on INPUT diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 7169b84ccdb6e2..d09baa3d3d902e 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -258,11 +258,6 @@ enum interface_flags { ACER_WMID_v2, }; -#define ACER_DEFAULT_WIRELESS 0 -#define ACER_DEFAULT_BLUETOOTH 0 -#define ACER_DEFAULT_MAILLED 0 -#define ACER_DEFAULT_THREEG 0 - static int max_brightness = 0xF; static int mailled = -1; @@ -2641,7 +2636,7 @@ static struct platform_driver acer_platform_driver = { .pm = &acer_pm, }, .probe = acer_platform_probe, - .remove_new = acer_platform_remove, + .remove = acer_platform_remove, .shutdown = acer_platform_shutdown, }; diff --git a/drivers/platform/x86/adv_swbutton.c b/drivers/platform/x86/adv_swbutton.c index 6b23ba78e028f8..6fa60f3fc53c0b 100644 --- a/drivers/platform/x86/adv_swbutton.c +++ b/drivers/platform/x86/adv_swbutton.c @@ -110,7 +110,7 @@ static struct platform_driver adv_swbutton_driver = { .acpi_match_table = button_device_ids, }, .probe = adv_swbutton_probe, - .remove_new = adv_swbutton_remove, + .remove = adv_swbutton_remove, }; module_platform_driver(adv_swbutton_driver); diff --git a/drivers/platform/x86/amd/Kconfig b/drivers/platform/x86/amd/Kconfig index f88682d36447c2..c3e086ea64fc6f 100644 --- a/drivers/platform/x86/amd/Kconfig +++ b/drivers/platform/x86/amd/Kconfig @@ -3,21 +3,21 @@ # AMD x86 Platform Specific Drivers # +source "drivers/platform/x86/amd/hsmp/Kconfig" source "drivers/platform/x86/amd/pmf/Kconfig" source "drivers/platform/x86/amd/pmc/Kconfig" -config AMD_HSMP - tristate "AMD HSMP Driver" - depends on AMD_NB && X86_64 && ACPI +config AMD_3D_VCACHE + tristate "AMD 3D V-Cache Performance Optimizer Driver" + depends on X86_64 && ACPI help - The driver provides a way for user space tools to monitor and manage - system management functionality on EPYC server CPUs from AMD. - - Host System Management Port (HSMP) interface is a mailbox interface - between the x86 core and the System Management Unit (SMU) firmware. + The driver provides a sysfs interface, enabling the setting of a bias + that alters CPU core reordering. This bias prefers cores with higher + frequencies or larger L3 caches on processors supporting AMD 3D V-Cache + technology. If you choose to compile this driver as a module the module will be - called amd_hsmp. + called amd_3d_vcache. config AMD_WBRF bool "AMD Wifi RF Band mitigations (WBRF)" diff --git a/drivers/platform/x86/amd/Makefile b/drivers/platform/x86/amd/Makefile index dcec0a46f8af16..56f62fc9c97b40 100644 --- a/drivers/platform/x86/amd/Makefile +++ b/drivers/platform/x86/amd/Makefile @@ -4,8 +4,9 @@ # AMD x86 Platform-Specific Drivers # +obj-$(CONFIG_AMD_3D_VCACHE) += amd_3d_vcache.o +amd_3d_vcache-objs := x3d_vcache.o obj-$(CONFIG_AMD_PMC) += pmc/ -amd_hsmp-y := hsmp.o -obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o +obj-$(CONFIG_AMD_HSMP) += hsmp/ obj-$(CONFIG_AMD_PMF) += pmf/ obj-$(CONFIG_AMD_WBRF) += wbrf.o diff --git a/drivers/platform/x86/amd/hsmp.c b/drivers/platform/x86/amd/hsmp.c deleted file mode 100644 index 8fcf38eed7f00e..00000000000000 --- a/drivers/platform/x86/amd/hsmp.c +++ /dev/null @@ -1,988 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * AMD HSMP Platform Driver - * Copyright (c) 2022, AMD. - * All Rights Reserved. - * - * This file provides a device implementation for HSMP interface - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "amd_hsmp" -#define DRIVER_VERSION "2.2" -#define ACPI_HSMP_DEVICE_HID "AMDI0097" - -/* HSMP Status / Error codes */ -#define HSMP_STATUS_NOT_READY 0x00 -#define HSMP_STATUS_OK 0x01 -#define HSMP_ERR_INVALID_MSG 0xFE -#define HSMP_ERR_INVALID_INPUT 0xFF - -/* Timeout in millsec */ -#define HSMP_MSG_TIMEOUT 100 -#define HSMP_SHORT_SLEEP 1 - -#define HSMP_WR true -#define HSMP_RD false - -/* - * To access specific HSMP mailbox register, s/w writes the SMN address of HSMP mailbox - * register into the SMN_INDEX register, and reads/writes the SMN_DATA reg. - * Below are required SMN address for HSMP Mailbox register offsets in SMU address space - */ -#define SMN_HSMP_BASE 0x3B00000 -#define SMN_HSMP_MSG_ID 0x0010534 -#define SMN_HSMP_MSG_ID_F1A_M0H 0x0010934 -#define SMN_HSMP_MSG_RESP 0x0010980 -#define SMN_HSMP_MSG_DATA 0x00109E0 - -#define HSMP_INDEX_REG 0xc4 -#define HSMP_DATA_REG 0xc8 - -#define HSMP_CDEV_NAME "hsmp_cdev" -#define HSMP_DEVNODE_NAME "hsmp" -#define HSMP_METRICS_TABLE_NAME "metrics_bin" - -#define HSMP_ATTR_GRP_NAME_SIZE 10 - -/* These are the strings specified in ACPI table */ -#define MSG_IDOFF_STR "MsgIdOffset" -#define MSG_ARGOFF_STR "MsgArgOffset" -#define MSG_RESPOFF_STR "MsgRspOffset" - -#define MAX_AMD_SOCKETS 8 - -struct hsmp_mbaddr_info { - u32 base_addr; - u32 msg_id_off; - u32 msg_resp_off; - u32 msg_arg_off; - u32 size; -}; - -struct hsmp_socket { - struct bin_attribute hsmp_attr; - struct hsmp_mbaddr_info mbinfo; - void __iomem *metric_tbl_addr; - void __iomem *virt_base_addr; - struct semaphore hsmp_sem; - char name[HSMP_ATTR_GRP_NAME_SIZE]; - struct pci_dev *root; - struct device *dev; - u16 sock_ind; -}; - -struct hsmp_plat_device { - struct miscdevice hsmp_device; - struct hsmp_socket *sock; - u32 proto_ver; - u16 num_sockets; - bool is_acpi_device; - bool is_probed; -}; - -static struct hsmp_plat_device plat_dev; - -static int amd_hsmp_pci_rdwr(struct hsmp_socket *sock, u32 offset, - u32 *value, bool write) -{ - int ret; - - if (!sock->root) - return -ENODEV; - - ret = pci_write_config_dword(sock->root, HSMP_INDEX_REG, - sock->mbinfo.base_addr + offset); - if (ret) - return ret; - - ret = (write ? pci_write_config_dword(sock->root, HSMP_DATA_REG, *value) - : pci_read_config_dword(sock->root, HSMP_DATA_REG, value)); - - return ret; -} - -static void amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset, - u32 *value, bool write) -{ - if (write) - iowrite32(*value, sock->virt_base_addr + offset); - else - *value = ioread32(sock->virt_base_addr + offset); -} - -static int amd_hsmp_rdwr(struct hsmp_socket *sock, u32 offset, - u32 *value, bool write) -{ - if (plat_dev.is_acpi_device) - amd_hsmp_acpi_rdwr(sock, offset, value, write); - else - return amd_hsmp_pci_rdwr(sock, offset, value, write); - - return 0; -} - -/* - * Send a message to the HSMP port via PCI-e config space registers - * or by writing to MMIO space. - * - * The caller is expected to zero out any unused arguments. - * If a response is expected, the number of response words should be greater than 0. - * - * Returns 0 for success and populates the requested number of arguments. - * Returns a negative error code for failure. - */ -static int __hsmp_send_message(struct hsmp_socket *sock, struct hsmp_message *msg) -{ - struct hsmp_mbaddr_info *mbinfo; - unsigned long timeout, short_sleep; - u32 mbox_status; - u32 index; - int ret; - - mbinfo = &sock->mbinfo; - - /* Clear the status register */ - mbox_status = HSMP_STATUS_NOT_READY; - ret = amd_hsmp_rdwr(sock, mbinfo->msg_resp_off, &mbox_status, HSMP_WR); - if (ret) { - pr_err("Error %d clearing mailbox status register\n", ret); - return ret; - } - - index = 0; - /* Write any message arguments */ - while (index < msg->num_args) { - ret = amd_hsmp_rdwr(sock, mbinfo->msg_arg_off + (index << 2), - &msg->args[index], HSMP_WR); - if (ret) { - pr_err("Error %d writing message argument %d\n", ret, index); - return ret; - } - index++; - } - - /* Write the message ID which starts the operation */ - ret = amd_hsmp_rdwr(sock, mbinfo->msg_id_off, &msg->msg_id, HSMP_WR); - if (ret) { - pr_err("Error %d writing message ID %u\n", ret, msg->msg_id); - return ret; - } - - /* - * Depending on when the trigger write completes relative to the SMU - * firmware 1 ms cycle, the operation may take from tens of us to 1 ms - * to complete. Some operations may take more. Therefore we will try - * a few short duration sleeps and switch to long sleeps if we don't - * succeed quickly. - */ - short_sleep = jiffies + msecs_to_jiffies(HSMP_SHORT_SLEEP); - timeout = jiffies + msecs_to_jiffies(HSMP_MSG_TIMEOUT); - - while (time_before(jiffies, timeout)) { - ret = amd_hsmp_rdwr(sock, mbinfo->msg_resp_off, &mbox_status, HSMP_RD); - if (ret) { - pr_err("Error %d reading mailbox status\n", ret); - return ret; - } - - if (mbox_status != HSMP_STATUS_NOT_READY) - break; - if (time_before(jiffies, short_sleep)) - usleep_range(50, 100); - else - usleep_range(1000, 2000); - } - - if (unlikely(mbox_status == HSMP_STATUS_NOT_READY)) { - return -ETIMEDOUT; - } else if (unlikely(mbox_status == HSMP_ERR_INVALID_MSG)) { - return -ENOMSG; - } else if (unlikely(mbox_status == HSMP_ERR_INVALID_INPUT)) { - return -EINVAL; - } else if (unlikely(mbox_status != HSMP_STATUS_OK)) { - pr_err("Message ID %u unknown failure (status = 0x%X)\n", - msg->msg_id, mbox_status); - return -EIO; - } - - /* - * SMU has responded OK. Read response data. - * SMU reads the input arguments from eight 32 bit registers starting - * from SMN_HSMP_MSG_DATA and writes the response data to the same - * SMN_HSMP_MSG_DATA address. - * We copy the response data if any, back to the args[]. - */ - index = 0; - while (index < msg->response_sz) { - ret = amd_hsmp_rdwr(sock, mbinfo->msg_arg_off + (index << 2), - &msg->args[index], HSMP_RD); - if (ret) { - pr_err("Error %d reading response %u for message ID:%u\n", - ret, index, msg->msg_id); - break; - } - index++; - } - - return ret; -} - -static int validate_message(struct hsmp_message *msg) -{ - /* msg_id against valid range of message IDs */ - if (msg->msg_id < HSMP_TEST || msg->msg_id >= HSMP_MSG_ID_MAX) - return -ENOMSG; - - /* msg_id is a reserved message ID */ - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_RSVD) - return -ENOMSG; - - /* num_args and response_sz against the HSMP spec */ - if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args || - msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz) - return -EINVAL; - - return 0; -} - -int hsmp_send_message(struct hsmp_message *msg) -{ - struct hsmp_socket *sock; - int ret; - - if (!msg) - return -EINVAL; - ret = validate_message(msg); - if (ret) - return ret; - - if (!plat_dev.sock || msg->sock_ind >= plat_dev.num_sockets) - return -ENODEV; - sock = &plat_dev.sock[msg->sock_ind]; - - /* - * The time taken by smu operation to complete is between - * 10us to 1ms. Sometime it may take more time. - * In SMP system timeout of 100 millisecs should - * be enough for the previous thread to finish the operation - */ - ret = down_timeout(&sock->hsmp_sem, msecs_to_jiffies(HSMP_MSG_TIMEOUT)); - if (ret < 0) - return ret; - - ret = __hsmp_send_message(sock, msg); - - up(&sock->hsmp_sem); - - return ret; -} -EXPORT_SYMBOL_GPL(hsmp_send_message); - -static int hsmp_test(u16 sock_ind, u32 value) -{ - struct hsmp_message msg = { 0 }; - int ret; - - /* - * Test the hsmp port by performing TEST command. The test message - * takes one argument and returns the value of that argument + 1. - */ - msg.msg_id = HSMP_TEST; - msg.num_args = 1; - msg.response_sz = 1; - msg.args[0] = value; - msg.sock_ind = sock_ind; - - ret = hsmp_send_message(&msg); - if (ret) - return ret; - - /* Check the response value */ - if (msg.args[0] != (value + 1)) { - dev_err(plat_dev.sock[sock_ind].dev, - "Socket %d test message failed, Expected 0x%08X, received 0x%08X\n", - sock_ind, (value + 1), msg.args[0]); - return -EBADE; - } - - return ret; -} - -static long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) -{ - int __user *arguser = (int __user *)arg; - struct hsmp_message msg = { 0 }; - int ret; - - if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message))) - return -EFAULT; - - /* - * Check msg_id is within the range of supported msg ids - * i.e within the array bounds of hsmp_msg_desc_table - */ - if (msg.msg_id < HSMP_TEST || msg.msg_id >= HSMP_MSG_ID_MAX) - return -ENOMSG; - - switch (fp->f_mode & (FMODE_WRITE | FMODE_READ)) { - case FMODE_WRITE: - /* - * Device is opened in O_WRONLY mode - * Execute only set/configure commands - */ - if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_SET) - return -EINVAL; - break; - case FMODE_READ: - /* - * Device is opened in O_RDONLY mode - * Execute only get/monitor commands - */ - if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_GET) - return -EINVAL; - break; - case FMODE_READ | FMODE_WRITE: - /* - * Device is opened in O_RDWR mode - * Execute both get/monitor and set/configure commands - */ - break; - default: - return -EINVAL; - } - - ret = hsmp_send_message(&msg); - if (ret) - return ret; - - if (hsmp_msg_desc_table[msg.msg_id].response_sz > 0) { - /* Copy results back to user for get/monitor commands */ - if (copy_to_user(arguser, &msg, sizeof(struct hsmp_message))) - return -EFAULT; - } - - return 0; -} - -static const struct file_operations hsmp_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = hsmp_ioctl, - .compat_ioctl = hsmp_ioctl, -}; - -/* This is the UUID used for HSMP */ -static const guid_t acpi_hsmp_uuid = GUID_INIT(0xb74d619d, 0x5707, 0x48bd, - 0xa6, 0x9f, 0x4e, 0xa2, - 0x87, 0x1f, 0xc2, 0xf6); - -static inline bool is_acpi_hsmp_uuid(union acpi_object *obj) -{ - if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == UUID_SIZE) - return guid_equal((guid_t *)obj->buffer.pointer, &acpi_hsmp_uuid); - - return false; -} - -static inline int hsmp_get_uid(struct device *dev, u16 *sock_ind) -{ - char *uid; - - /* - * UID (ID00, ID01..IDXX) is used for differentiating sockets, - * read it and strip the "ID" part of it and convert the remaining - * bytes to integer. - */ - uid = acpi_device_uid(ACPI_COMPANION(dev)); - - return kstrtou16(uid + 2, 10, sock_ind); -} - -static acpi_status hsmp_resource(struct acpi_resource *res, void *data) -{ - struct hsmp_socket *sock = data; - struct resource r; - - switch (res->type) { - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - if (!acpi_dev_resource_memory(res, &r)) - return AE_ERROR; - if (!r.start || r.end < r.start || !(r.flags & IORESOURCE_MEM_WRITEABLE)) - return AE_ERROR; - sock->mbinfo.base_addr = r.start; - sock->mbinfo.size = resource_size(&r); - break; - case ACPI_RESOURCE_TYPE_END_TAG: - break; - default: - return AE_ERROR; - } - - return AE_OK; -} - -static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) -{ - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *guid, *mailbox_package; - union acpi_object *dsd; - acpi_status status; - int ret = 0; - int j; - - status = acpi_evaluate_object_typed(ACPI_HANDLE(sock->dev), "_DSD", NULL, - &buf, ACPI_TYPE_PACKAGE); - if (ACPI_FAILURE(status)) { - dev_err(sock->dev, "Failed to read mailbox reg offsets from DSD table, err: %s\n", - acpi_format_exception(status)); - return -ENODEV; - } - - dsd = buf.pointer; - - /* HSMP _DSD property should contain 2 objects. - * 1. guid which is an acpi object of type ACPI_TYPE_BUFFER - * 2. mailbox which is an acpi object of type ACPI_TYPE_PACKAGE - * This mailbox object contains 3 more acpi objects of type - * ACPI_TYPE_PACKAGE for holding msgid, msgresp, msgarg offsets - * these packages inturn contain 2 acpi objects of type - * ACPI_TYPE_STRING and ACPI_TYPE_INTEGER - */ - if (!dsd || dsd->type != ACPI_TYPE_PACKAGE || dsd->package.count != 2) { - ret = -EINVAL; - goto free_buf; - } - - guid = &dsd->package.elements[0]; - mailbox_package = &dsd->package.elements[1]; - if (!is_acpi_hsmp_uuid(guid) || mailbox_package->type != ACPI_TYPE_PACKAGE) { - dev_err(sock->dev, "Invalid hsmp _DSD table data\n"); - ret = -EINVAL; - goto free_buf; - } - - for (j = 0; j < mailbox_package->package.count; j++) { - union acpi_object *msgobj, *msgstr, *msgint; - - msgobj = &mailbox_package->package.elements[j]; - msgstr = &msgobj->package.elements[0]; - msgint = &msgobj->package.elements[1]; - - /* package should have 1 string and 1 integer object */ - if (msgobj->type != ACPI_TYPE_PACKAGE || - msgstr->type != ACPI_TYPE_STRING || - msgint->type != ACPI_TYPE_INTEGER) { - ret = -EINVAL; - goto free_buf; - } - - if (!strncmp(msgstr->string.pointer, MSG_IDOFF_STR, - msgstr->string.length)) { - sock->mbinfo.msg_id_off = msgint->integer.value; - } else if (!strncmp(msgstr->string.pointer, MSG_RESPOFF_STR, - msgstr->string.length)) { - sock->mbinfo.msg_resp_off = msgint->integer.value; - } else if (!strncmp(msgstr->string.pointer, MSG_ARGOFF_STR, - msgstr->string.length)) { - sock->mbinfo.msg_arg_off = msgint->integer.value; - } else { - ret = -ENOENT; - goto free_buf; - } - } - - if (!sock->mbinfo.msg_id_off || !sock->mbinfo.msg_resp_off || - !sock->mbinfo.msg_arg_off) - ret = -EINVAL; - -free_buf: - ACPI_FREE(buf.pointer); - return ret; -} - -static int hsmp_read_acpi_crs(struct hsmp_socket *sock) -{ - acpi_status status; - - status = acpi_walk_resources(ACPI_HANDLE(sock->dev), METHOD_NAME__CRS, - hsmp_resource, sock); - if (ACPI_FAILURE(status)) { - dev_err(sock->dev, "Failed to look up MP1 base address from CRS method, err: %s\n", - acpi_format_exception(status)); - return -EINVAL; - } - if (!sock->mbinfo.base_addr || !sock->mbinfo.size) - return -EINVAL; - - /* The mapped region should be un cached */ - sock->virt_base_addr = devm_ioremap_uc(sock->dev, sock->mbinfo.base_addr, - sock->mbinfo.size); - if (!sock->virt_base_addr) { - dev_err(sock->dev, "Failed to ioremap MP1 base address\n"); - return -ENOMEM; - } - - return 0; -} - -/* Parse the ACPI table to read the data */ -static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind) -{ - struct hsmp_socket *sock = &plat_dev.sock[sock_ind]; - int ret; - - sock->sock_ind = sock_ind; - sock->dev = dev; - plat_dev.is_acpi_device = true; - - sema_init(&sock->hsmp_sem, 1); - - /* Read MP1 base address from CRS method */ - ret = hsmp_read_acpi_crs(sock); - if (ret) - return ret; - - /* Read mailbox offsets from DSD table */ - return hsmp_read_acpi_dsd(sock); -} - -static ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, char *buf, - loff_t off, size_t count) -{ - struct hsmp_socket *sock = bin_attr->private; - struct hsmp_message msg = { 0 }; - int ret; - - if (!sock) - return -EINVAL; - - /* Do not support lseek(), reads entire metric table */ - if (count < bin_attr->size) { - dev_err(sock->dev, "Wrong buffer size\n"); - return -EINVAL; - } - - msg.msg_id = HSMP_GET_METRIC_TABLE; - msg.sock_ind = sock->sock_ind; - - ret = hsmp_send_message(&msg); - if (ret) - return ret; - memcpy_fromio(buf, sock->metric_tbl_addr, bin_attr->size); - - return bin_attr->size; -} - -static int hsmp_get_tbl_dram_base(u16 sock_ind) -{ - struct hsmp_socket *sock = &plat_dev.sock[sock_ind]; - struct hsmp_message msg = { 0 }; - phys_addr_t dram_addr; - int ret; - - msg.sock_ind = sock_ind; - msg.response_sz = hsmp_msg_desc_table[HSMP_GET_METRIC_TABLE_DRAM_ADDR].response_sz; - msg.msg_id = HSMP_GET_METRIC_TABLE_DRAM_ADDR; - - ret = hsmp_send_message(&msg); - if (ret) - return ret; - - /* - * calculate the metric table DRAM address from lower and upper 32 bits - * sent from SMU and ioremap it to virtual address. - */ - dram_addr = msg.args[0] | ((u64)(msg.args[1]) << 32); - if (!dram_addr) { - dev_err(sock->dev, "Invalid DRAM address for metric table\n"); - return -ENOMEM; - } - sock->metric_tbl_addr = devm_ioremap(sock->dev, dram_addr, - sizeof(struct hsmp_metric_table)); - if (!sock->metric_tbl_addr) { - dev_err(sock->dev, "Failed to ioremap metric table addr\n"); - return -ENOMEM; - } - return 0; -} - -static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, - struct bin_attribute *battr, int id) -{ - if (plat_dev.proto_ver == HSMP_PROTO_VER6) - return battr->attr.mode; - else - return 0; -} - -static int hsmp_init_metric_tbl_bin_attr(struct bin_attribute **hattrs, u16 sock_ind) -{ - struct bin_attribute *hattr = &plat_dev.sock[sock_ind].hsmp_attr; - - sysfs_bin_attr_init(hattr); - hattr->attr.name = HSMP_METRICS_TABLE_NAME; - hattr->attr.mode = 0444; - hattr->read = hsmp_metric_tbl_read; - hattr->size = sizeof(struct hsmp_metric_table); - hattr->private = &plat_dev.sock[sock_ind]; - hattrs[0] = hattr; - - if (plat_dev.proto_ver == HSMP_PROTO_VER6) - return hsmp_get_tbl_dram_base(sock_ind); - else - return 0; -} - -/* One bin sysfs for metrics table */ -#define NUM_HSMP_ATTRS 1 - -static int hsmp_create_attr_list(struct attribute_group *attr_grp, - struct device *dev, u16 sock_ind) -{ - struct bin_attribute **hsmp_bin_attrs; - - /* Null terminated list of attributes */ - hsmp_bin_attrs = devm_kcalloc(dev, NUM_HSMP_ATTRS + 1, - sizeof(*hsmp_bin_attrs), - GFP_KERNEL); - if (!hsmp_bin_attrs) - return -ENOMEM; - - attr_grp->bin_attrs = hsmp_bin_attrs; - - return hsmp_init_metric_tbl_bin_attr(hsmp_bin_attrs, sock_ind); -} - -static int hsmp_create_non_acpi_sysfs_if(struct device *dev) -{ - const struct attribute_group **hsmp_attr_grps; - struct attribute_group *attr_grp; - u16 i; - - hsmp_attr_grps = devm_kcalloc(dev, plat_dev.num_sockets + 1, - sizeof(*hsmp_attr_grps), - GFP_KERNEL); - if (!hsmp_attr_grps) - return -ENOMEM; - - /* Create a sysfs directory for each socket */ - for (i = 0; i < plat_dev.num_sockets; i++) { - attr_grp = devm_kzalloc(dev, sizeof(struct attribute_group), - GFP_KERNEL); - if (!attr_grp) - return -ENOMEM; - - snprintf(plat_dev.sock[i].name, HSMP_ATTR_GRP_NAME_SIZE, "socket%u", (u8)i); - attr_grp->name = plat_dev.sock[i].name; - attr_grp->is_bin_visible = hsmp_is_sock_attr_visible; - hsmp_attr_grps[i] = attr_grp; - - hsmp_create_attr_list(attr_grp, dev, i); - } - - return device_add_groups(dev, hsmp_attr_grps); -} - -static int hsmp_create_acpi_sysfs_if(struct device *dev) -{ - struct attribute_group *attr_grp; - u16 sock_ind; - int ret; - - attr_grp = devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL); - if (!attr_grp) - return -ENOMEM; - - attr_grp->is_bin_visible = hsmp_is_sock_attr_visible; - - ret = hsmp_get_uid(dev, &sock_ind); - if (ret) - return ret; - - ret = hsmp_create_attr_list(attr_grp, dev, sock_ind); - if (ret) - return ret; - - return devm_device_add_group(dev, attr_grp); -} - -static int hsmp_cache_proto_ver(u16 sock_ind) -{ - struct hsmp_message msg = { 0 }; - int ret; - - msg.msg_id = HSMP_GET_PROTO_VER; - msg.sock_ind = sock_ind; - msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; - - ret = hsmp_send_message(&msg); - if (!ret) - plat_dev.proto_ver = msg.args[0]; - - return ret; -} - -static inline bool is_f1a_m0h(void) -{ - if (boot_cpu_data.x86 == 0x1A && boot_cpu_data.x86_model <= 0x0F) - return true; - - return false; -} - -static int init_platform_device(struct device *dev) -{ - struct hsmp_socket *sock; - int ret, i; - - for (i = 0; i < plat_dev.num_sockets; i++) { - if (!node_to_amd_nb(i)) - return -ENODEV; - sock = &plat_dev.sock[i]; - sock->root = node_to_amd_nb(i)->root; - sock->sock_ind = i; - sock->dev = dev; - sock->mbinfo.base_addr = SMN_HSMP_BASE; - - /* - * This is a transitional change from non-ACPI to ACPI, only - * family 0x1A, model 0x00 platform is supported for both ACPI and non-ACPI. - */ - if (is_f1a_m0h()) - sock->mbinfo.msg_id_off = SMN_HSMP_MSG_ID_F1A_M0H; - else - sock->mbinfo.msg_id_off = SMN_HSMP_MSG_ID; - - sock->mbinfo.msg_resp_off = SMN_HSMP_MSG_RESP; - sock->mbinfo.msg_arg_off = SMN_HSMP_MSG_DATA; - sema_init(&sock->hsmp_sem, 1); - - /* Test the hsmp interface on each socket */ - ret = hsmp_test(i, 0xDEADBEEF); - if (ret) { - dev_err(dev, "HSMP test message failed on Fam:%x model:%x\n", - boot_cpu_data.x86, boot_cpu_data.x86_model); - dev_err(dev, "Is HSMP disabled in BIOS ?\n"); - return ret; - } - } - - return 0; -} - -static const struct acpi_device_id amd_hsmp_acpi_ids[] = { - {ACPI_HSMP_DEVICE_HID, 0}, - {} -}; -MODULE_DEVICE_TABLE(acpi, amd_hsmp_acpi_ids); - -static int hsmp_pltdrv_probe(struct platform_device *pdev) -{ - struct acpi_device *adev; - u16 sock_ind = 0; - int ret; - - /* - * On ACPI supported BIOS, there is an ACPI HSMP device added for - * each socket, so the per socket probing, but the memory allocated for - * sockets should be contiguous to access it as an array, - * Hence allocate memory for all the sockets at once instead of allocating - * on each probe. - */ - if (!plat_dev.is_probed) { - plat_dev.sock = devm_kcalloc(&pdev->dev, plat_dev.num_sockets, - sizeof(*plat_dev.sock), - GFP_KERNEL); - if (!plat_dev.sock) - return -ENOMEM; - } - adev = ACPI_COMPANION(&pdev->dev); - if (adev && !acpi_match_device_ids(adev, amd_hsmp_acpi_ids)) { - ret = hsmp_get_uid(&pdev->dev, &sock_ind); - if (ret) - return ret; - if (sock_ind >= plat_dev.num_sockets) - return -EINVAL; - ret = hsmp_parse_acpi_table(&pdev->dev, sock_ind); - if (ret) { - dev_err(&pdev->dev, "Failed to parse ACPI table\n"); - return ret; - } - /* Test the hsmp interface */ - ret = hsmp_test(sock_ind, 0xDEADBEEF); - if (ret) { - dev_err(&pdev->dev, "HSMP test message failed on Fam:%x model:%x\n", - boot_cpu_data.x86, boot_cpu_data.x86_model); - dev_err(&pdev->dev, "Is HSMP disabled in BIOS ?\n"); - return ret; - } - } else { - ret = init_platform_device(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Failed to init HSMP mailbox\n"); - return ret; - } - } - - ret = hsmp_cache_proto_ver(sock_ind); - if (ret) { - dev_err(&pdev->dev, "Failed to read HSMP protocol version\n"); - return ret; - } - - if (plat_dev.is_acpi_device) - ret = hsmp_create_acpi_sysfs_if(&pdev->dev); - else - ret = hsmp_create_non_acpi_sysfs_if(&pdev->dev); - if (ret) - dev_err(&pdev->dev, "Failed to create HSMP sysfs interface\n"); - - if (!plat_dev.is_probed) { - plat_dev.hsmp_device.name = HSMP_CDEV_NAME; - plat_dev.hsmp_device.minor = MISC_DYNAMIC_MINOR; - plat_dev.hsmp_device.fops = &hsmp_fops; - plat_dev.hsmp_device.parent = &pdev->dev; - plat_dev.hsmp_device.nodename = HSMP_DEVNODE_NAME; - plat_dev.hsmp_device.mode = 0644; - - ret = misc_register(&plat_dev.hsmp_device); - if (ret) - return ret; - - plat_dev.is_probed = true; - } - - return 0; - -} - -static void hsmp_pltdrv_remove(struct platform_device *pdev) -{ - /* - * We register only one misc_device even on multi socket system. - * So, deregister should happen only once. - */ - if (plat_dev.is_probed) { - misc_deregister(&plat_dev.hsmp_device); - plat_dev.is_probed = false; - } -} - -static struct platform_driver amd_hsmp_driver = { - .probe = hsmp_pltdrv_probe, - .remove_new = hsmp_pltdrv_remove, - .driver = { - .name = DRIVER_NAME, - .acpi_match_table = amd_hsmp_acpi_ids, - }, -}; - -static struct platform_device *amd_hsmp_platdev; - -static int hsmp_plat_dev_register(void) -{ - int ret; - - amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE); - if (!amd_hsmp_platdev) - return -ENOMEM; - - ret = platform_device_add(amd_hsmp_platdev); - if (ret) - platform_device_put(amd_hsmp_platdev); - - return ret; -} - -/* - * This check is only needed for backward compatibility of previous platforms. - * All new platforms are expected to support ACPI based probing. - */ -static bool legacy_hsmp_support(void) -{ - if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) - return false; - - switch (boot_cpu_data.x86) { - case 0x19: - switch (boot_cpu_data.x86_model) { - case 0x00 ... 0x1F: - case 0x30 ... 0x3F: - case 0x90 ... 0x9F: - case 0xA0 ... 0xAF: - return true; - default: - return false; - } - case 0x1A: - switch (boot_cpu_data.x86_model) { - case 0x00 ... 0x1F: - return true; - default: - return false; - } - default: - return false; - } - - return false; -} - -static int __init hsmp_plt_init(void) -{ - int ret = -ENODEV; - - /* - * amd_nb_num() returns number of SMN/DF interfaces present in the system - * if we have N SMN/DF interfaces that ideally means N sockets - */ - plat_dev.num_sockets = amd_nb_num(); - if (plat_dev.num_sockets == 0 || plat_dev.num_sockets > MAX_AMD_SOCKETS) - return ret; - - ret = platform_driver_register(&amd_hsmp_driver); - if (ret) - return ret; - - if (!plat_dev.is_acpi_device) { - if (legacy_hsmp_support()) { - /* Not ACPI device, but supports HSMP, register a plat_dev */ - ret = hsmp_plat_dev_register(); - } else { - /* Not ACPI, Does not support HSMP */ - pr_info("HSMP is not supported on Family:%x model:%x\n", - boot_cpu_data.x86, boot_cpu_data.x86_model); - ret = -ENODEV; - } - if (ret) - platform_driver_unregister(&amd_hsmp_driver); - } - - return ret; -} - -static void __exit hsmp_plt_exit(void) -{ - platform_device_unregister(amd_hsmp_platdev); - platform_driver_unregister(&amd_hsmp_driver); -} - -device_initcall(hsmp_plt_init); -module_exit(hsmp_plt_exit); - -MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/amd/hsmp/Kconfig b/drivers/platform/x86/amd/hsmp/Kconfig new file mode 100644 index 00000000000000..7d10d4462a453d --- /dev/null +++ b/drivers/platform/x86/amd/hsmp/Kconfig @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# AMD HSMP Driver +# + +config AMD_HSMP + tristate + +menu "AMD HSMP Driver" + depends on AMD_NB || COMPILE_TEST + +config AMD_HSMP_ACPI + tristate "AMD HSMP ACPI device driver" + depends on ACPI + select AMD_HSMP + help + Host System Management Port (HSMP) interface is a mailbox interface + between the x86 core and the System Management Unit (SMU) firmware. + The driver provides a way for user space tools to monitor and manage + system management functionality on EPYC and MI300A server CPUs + from AMD. + + This option supports ACPI based probing. + You may enable this, if your platform BIOS provides an ACPI object + as described in amd_hsmp.rst document. + + If you choose to compile this driver as a module the module will be + called hsmp_acpi. + +config AMD_HSMP_PLAT + tristate "AMD HSMP platform device driver" + select AMD_HSMP + help + Host System Management Port (HSMP) interface is a mailbox interface + between the x86 core and the System Management Unit (SMU) firmware. + The driver provides a way for user space tools to monitor and manage + system management functionality on EPYC and MI300A server CPUs + from AMD. + + This option supports platform device based probing. + You may enable this, if your platform BIOS does not provide + HSMP ACPI object. + + If you choose to compile this driver as a module the module will be + called amd_hsmp. + +endmenu diff --git a/drivers/platform/x86/amd/hsmp/Makefile b/drivers/platform/x86/amd/hsmp/Makefile new file mode 100644 index 00000000000000..3175d8885e87b2 --- /dev/null +++ b/drivers/platform/x86/amd/hsmp/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for drivers/platform/x86/amd/hsmp +# AMD HSMP Driver +# + +obj-$(CONFIG_AMD_HSMP) += hsmp_common.o +hsmp_common-objs := hsmp.o +obj-$(CONFIG_AMD_HSMP_PLAT) += amd_hsmp.o +amd_hsmp-objs := plat.o +obj-$(CONFIG_AMD_HSMP_ACPI) += hsmp_acpi.o +hsmp_acpi-objs := acpi.o diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c new file mode 100644 index 00000000000000..e981d45e1c1279 --- /dev/null +++ b/drivers/platform/x86/amd/hsmp/acpi.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD HSMP Platform Driver + * Copyright (c) 2024, AMD. + * All Rights Reserved. + * + * This file provides an ACPI based driver implementation for HSMP interface. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hsmp.h" + +#define DRIVER_NAME "amd_hsmp" +#define DRIVER_VERSION "2.3" +#define ACPI_HSMP_DEVICE_HID "AMDI0097" + +/* These are the strings specified in ACPI table */ +#define MSG_IDOFF_STR "MsgIdOffset" +#define MSG_ARGOFF_STR "MsgArgOffset" +#define MSG_RESPOFF_STR "MsgRspOffset" + +static struct hsmp_plat_device *hsmp_pdev; + +static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset, + u32 *value, bool write) +{ + if (write) + iowrite32(*value, sock->virt_base_addr + offset); + else + *value = ioread32(sock->virt_base_addr + offset); + + return 0; +} + +/* This is the UUID used for HSMP */ +static const guid_t acpi_hsmp_uuid = GUID_INIT(0xb74d619d, 0x5707, 0x48bd, + 0xa6, 0x9f, 0x4e, 0xa2, + 0x87, 0x1f, 0xc2, 0xf6); + +static inline bool is_acpi_hsmp_uuid(union acpi_object *obj) +{ + if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == UUID_SIZE) + return guid_equal((guid_t *)obj->buffer.pointer, &acpi_hsmp_uuid); + + return false; +} + +static inline int hsmp_get_uid(struct device *dev, u16 *sock_ind) +{ + char *uid; + + /* + * UID (ID00, ID01..IDXX) is used for differentiating sockets, + * read it and strip the "ID" part of it and convert the remaining + * bytes to integer. + */ + uid = acpi_device_uid(ACPI_COMPANION(dev)); + + return kstrtou16(uid + 2, 10, sock_ind); +} + +static acpi_status hsmp_resource(struct acpi_resource *res, void *data) +{ + struct hsmp_socket *sock = data; + struct resource r; + + switch (res->type) { + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + if (!acpi_dev_resource_memory(res, &r)) + return AE_ERROR; + if (!r.start || r.end < r.start || !(r.flags & IORESOURCE_MEM_WRITEABLE)) + return AE_ERROR; + sock->mbinfo.base_addr = r.start; + sock->mbinfo.size = resource_size(&r); + break; + case ACPI_RESOURCE_TYPE_END_TAG: + break; + default: + return AE_ERROR; + } + + return AE_OK; +} + +static int hsmp_read_acpi_dsd(struct hsmp_socket *sock) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *guid, *mailbox_package; + union acpi_object *dsd; + acpi_status status; + int ret = 0; + int j; + + status = acpi_evaluate_object_typed(ACPI_HANDLE(sock->dev), "_DSD", NULL, + &buf, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + dev_err(sock->dev, "Failed to read mailbox reg offsets from DSD table, err: %s\n", + acpi_format_exception(status)); + return -ENODEV; + } + + dsd = buf.pointer; + + /* HSMP _DSD property should contain 2 objects. + * 1. guid which is an acpi object of type ACPI_TYPE_BUFFER + * 2. mailbox which is an acpi object of type ACPI_TYPE_PACKAGE + * This mailbox object contains 3 more acpi objects of type + * ACPI_TYPE_PACKAGE for holding msgid, msgresp, msgarg offsets + * these packages inturn contain 2 acpi objects of type + * ACPI_TYPE_STRING and ACPI_TYPE_INTEGER + */ + if (!dsd || dsd->type != ACPI_TYPE_PACKAGE || dsd->package.count != 2) { + ret = -EINVAL; + goto free_buf; + } + + guid = &dsd->package.elements[0]; + mailbox_package = &dsd->package.elements[1]; + if (!is_acpi_hsmp_uuid(guid) || mailbox_package->type != ACPI_TYPE_PACKAGE) { + dev_err(sock->dev, "Invalid hsmp _DSD table data\n"); + ret = -EINVAL; + goto free_buf; + } + + for (j = 0; j < mailbox_package->package.count; j++) { + union acpi_object *msgobj, *msgstr, *msgint; + + msgobj = &mailbox_package->package.elements[j]; + msgstr = &msgobj->package.elements[0]; + msgint = &msgobj->package.elements[1]; + + /* package should have 1 string and 1 integer object */ + if (msgobj->type != ACPI_TYPE_PACKAGE || + msgstr->type != ACPI_TYPE_STRING || + msgint->type != ACPI_TYPE_INTEGER) { + ret = -EINVAL; + goto free_buf; + } + + if (!strncmp(msgstr->string.pointer, MSG_IDOFF_STR, + msgstr->string.length)) { + sock->mbinfo.msg_id_off = msgint->integer.value; + } else if (!strncmp(msgstr->string.pointer, MSG_RESPOFF_STR, + msgstr->string.length)) { + sock->mbinfo.msg_resp_off = msgint->integer.value; + } else if (!strncmp(msgstr->string.pointer, MSG_ARGOFF_STR, + msgstr->string.length)) { + sock->mbinfo.msg_arg_off = msgint->integer.value; + } else { + ret = -ENOENT; + goto free_buf; + } + } + + if (!sock->mbinfo.msg_id_off || !sock->mbinfo.msg_resp_off || + !sock->mbinfo.msg_arg_off) + ret = -EINVAL; + +free_buf: + ACPI_FREE(buf.pointer); + return ret; +} + +static int hsmp_read_acpi_crs(struct hsmp_socket *sock) +{ + acpi_status status; + + status = acpi_walk_resources(ACPI_HANDLE(sock->dev), METHOD_NAME__CRS, + hsmp_resource, sock); + if (ACPI_FAILURE(status)) { + dev_err(sock->dev, "Failed to look up MP1 base address from CRS method, err: %s\n", + acpi_format_exception(status)); + return -EINVAL; + } + if (!sock->mbinfo.base_addr || !sock->mbinfo.size) + return -EINVAL; + + /* The mapped region should be un-cached */ + sock->virt_base_addr = devm_ioremap_uc(sock->dev, sock->mbinfo.base_addr, + sock->mbinfo.size); + if (!sock->virt_base_addr) { + dev_err(sock->dev, "Failed to ioremap MP1 base address\n"); + return -ENOMEM; + } + + return 0; +} + +/* Parse the ACPI table to read the data */ +static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind) +{ + struct hsmp_socket *sock = &hsmp_pdev->sock[sock_ind]; + int ret; + + sock->sock_ind = sock_ind; + sock->dev = dev; + sock->amd_hsmp_rdwr = amd_hsmp_acpi_rdwr; + + sema_init(&sock->hsmp_sem, 1); + + dev_set_drvdata(dev, sock); + + /* Read MP1 base address from CRS method */ + ret = hsmp_read_acpi_crs(sock); + if (ret) + return ret; + + /* Read mailbox offsets from DSD table */ + return hsmp_read_acpi_dsd(sock); +} + +static ssize_t hsmp_metric_tbl_acpi_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct hsmp_socket *sock = dev_get_drvdata(dev); + + return hsmp_metric_tbl_read(sock, buf, count); +} + +static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, + const struct bin_attribute *battr, int id) +{ + if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) + return battr->attr.mode; + + return 0; +} + +static int init_acpi(struct device *dev) +{ + u16 sock_ind; + int ret; + + ret = hsmp_get_uid(dev, &sock_ind); + if (ret) + return ret; + if (sock_ind >= hsmp_pdev->num_sockets) + return -EINVAL; + + ret = hsmp_parse_acpi_table(dev, sock_ind); + if (ret) { + dev_err(dev, "Failed to parse ACPI table\n"); + return ret; + } + + /* Test the hsmp interface */ + ret = hsmp_test(sock_ind, 0xDEADBEEF); + if (ret) { + dev_err(dev, "HSMP test message failed on Fam:%x model:%x\n", + boot_cpu_data.x86, boot_cpu_data.x86_model); + dev_err(dev, "Is HSMP disabled in BIOS ?\n"); + return ret; + } + + ret = hsmp_cache_proto_ver(sock_ind); + if (ret) { + dev_err(dev, "Failed to read HSMP protocol version\n"); + return ret; + } + + if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) { + ret = hsmp_get_tbl_dram_base(sock_ind); + if (ret) + dev_err(dev, "Failed to init metric table\n"); + } + + return ret; +} + +static struct bin_attribute hsmp_metric_tbl_attr = { + .attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444}, + .read = hsmp_metric_tbl_acpi_read, + .size = sizeof(struct hsmp_metric_table), +}; + +static struct bin_attribute *hsmp_attr_list[] = { + &hsmp_metric_tbl_attr, + NULL +}; + +static struct attribute_group hsmp_attr_grp = { + .bin_attrs = hsmp_attr_list, + .is_bin_visible = hsmp_is_sock_attr_visible, +}; + +static const struct attribute_group *hsmp_groups[] = { + &hsmp_attr_grp, + NULL +}; + +static const struct acpi_device_id amd_hsmp_acpi_ids[] = { + {ACPI_HSMP_DEVICE_HID, 0}, + {} +}; +MODULE_DEVICE_TABLE(acpi, amd_hsmp_acpi_ids); + +static int hsmp_acpi_probe(struct platform_device *pdev) +{ + int ret; + + hsmp_pdev = get_hsmp_pdev(); + if (!hsmp_pdev) + return -ENOMEM; + + if (!hsmp_pdev->is_probed) { + hsmp_pdev->num_sockets = amd_nb_num(); + if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_SOCKETS) + return -ENODEV; + + hsmp_pdev->sock = devm_kcalloc(&pdev->dev, hsmp_pdev->num_sockets, + sizeof(*hsmp_pdev->sock), + GFP_KERNEL); + if (!hsmp_pdev->sock) + return -ENOMEM; + } + + ret = init_acpi(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize HSMP interface.\n"); + return ret; + } + + if (!hsmp_pdev->is_probed) { + ret = hsmp_misc_register(&pdev->dev); + if (ret) + return ret; + hsmp_pdev->is_probed = true; + } + + return 0; +} + +static void hsmp_acpi_remove(struct platform_device *pdev) +{ + /* + * We register only one misc_device even on multi-socket system. + * So, deregister should happen only once. + */ + if (hsmp_pdev->is_probed) { + hsmp_misc_deregister(); + hsmp_pdev->is_probed = false; + } +} + +static struct platform_driver amd_hsmp_driver = { + .probe = hsmp_acpi_probe, + .remove = hsmp_acpi_remove, + .driver = { + .name = DRIVER_NAME, + .acpi_match_table = amd_hsmp_acpi_ids, + .dev_groups = hsmp_groups, + }, +}; + +module_platform_driver(amd_hsmp_driver); + +MODULE_IMPORT_NS("AMD_HSMP"); +MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c new file mode 100644 index 00000000000000..227b4ad4a51afb --- /dev/null +++ b/drivers/platform/x86/amd/hsmp/hsmp.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD HSMP Platform Driver + * Copyright (c) 2022, AMD. + * All Rights Reserved. + * + * This file provides a device implementation for HSMP interface + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "hsmp.h" + +/* HSMP Status / Error codes */ +#define HSMP_STATUS_NOT_READY 0x00 +#define HSMP_STATUS_OK 0x01 +#define HSMP_ERR_INVALID_MSG 0xFE +#define HSMP_ERR_INVALID_INPUT 0xFF +#define HSMP_ERR_PREREQ_NOT_SATISFIED 0xFD +#define HSMP_ERR_SMU_BUSY 0xFC + +/* Timeout in millsec */ +#define HSMP_MSG_TIMEOUT 100 +#define HSMP_SHORT_SLEEP 1 + +#define HSMP_WR true +#define HSMP_RD false + +#define DRIVER_VERSION "2.3" + +static struct hsmp_plat_device hsmp_pdev; + +/* + * Send a message to the HSMP port via PCI-e config space registers + * or by writing to MMIO space. + * + * The caller is expected to zero out any unused arguments. + * If a response is expected, the number of response words should be greater than 0. + * + * Returns 0 for success and populates the requested number of arguments. + * Returns a negative error code for failure. + */ +static int __hsmp_send_message(struct hsmp_socket *sock, struct hsmp_message *msg) +{ + struct hsmp_mbaddr_info *mbinfo; + unsigned long timeout, short_sleep; + u32 mbox_status; + u32 index; + int ret; + + mbinfo = &sock->mbinfo; + + /* Clear the status register */ + mbox_status = HSMP_STATUS_NOT_READY; + ret = sock->amd_hsmp_rdwr(sock, mbinfo->msg_resp_off, &mbox_status, HSMP_WR); + if (ret) { + dev_err(sock->dev, "Error %d clearing mailbox status register\n", ret); + return ret; + } + + index = 0; + /* Write any message arguments */ + while (index < msg->num_args) { + ret = sock->amd_hsmp_rdwr(sock, mbinfo->msg_arg_off + (index << 2), + &msg->args[index], HSMP_WR); + if (ret) { + dev_err(sock->dev, "Error %d writing message argument %d\n", ret, index); + return ret; + } + index++; + } + + /* Write the message ID which starts the operation */ + ret = sock->amd_hsmp_rdwr(sock, mbinfo->msg_id_off, &msg->msg_id, HSMP_WR); + if (ret) { + dev_err(sock->dev, "Error %d writing message ID %u\n", ret, msg->msg_id); + return ret; + } + + /* + * Depending on when the trigger write completes relative to the SMU + * firmware 1 ms cycle, the operation may take from tens of us to 1 ms + * to complete. Some operations may take more. Therefore we will try + * a few short duration sleeps and switch to long sleeps if we don't + * succeed quickly. + */ + short_sleep = jiffies + msecs_to_jiffies(HSMP_SHORT_SLEEP); + timeout = jiffies + msecs_to_jiffies(HSMP_MSG_TIMEOUT); + + while (time_before(jiffies, timeout)) { + ret = sock->amd_hsmp_rdwr(sock, mbinfo->msg_resp_off, &mbox_status, HSMP_RD); + if (ret) { + dev_err(sock->dev, "Error %d reading mailbox status\n", ret); + return ret; + } + + if (mbox_status != HSMP_STATUS_NOT_READY) + break; + if (time_before(jiffies, short_sleep)) + usleep_range(50, 100); + else + usleep_range(1000, 2000); + } + + if (unlikely(mbox_status == HSMP_STATUS_NOT_READY)) { + dev_err(sock->dev, "Message ID 0x%X failure : SMU tmeout (status = 0x%X)\n", + msg->msg_id, mbox_status); + return -ETIMEDOUT; + } else if (unlikely(mbox_status == HSMP_ERR_INVALID_MSG)) { + dev_err(sock->dev, "Message ID 0x%X failure : Invalid message (status = 0x%X)\n", + msg->msg_id, mbox_status); + return -ENOMSG; + } else if (unlikely(mbox_status == HSMP_ERR_INVALID_INPUT)) { + dev_err(sock->dev, "Message ID 0x%X failure : Invalid arguments (status = 0x%X)\n", + msg->msg_id, mbox_status); + return -EINVAL; + } else if (unlikely(mbox_status == HSMP_ERR_PREREQ_NOT_SATISFIED)) { + dev_err(sock->dev, "Message ID 0x%X failure : Prerequisite not satisfied (status = 0x%X)\n", + msg->msg_id, mbox_status); + return -EREMOTEIO; + } else if (unlikely(mbox_status == HSMP_ERR_SMU_BUSY)) { + dev_err(sock->dev, "Message ID 0x%X failure : SMU BUSY (status = 0x%X)\n", + msg->msg_id, mbox_status); + return -EBUSY; + } else if (unlikely(mbox_status != HSMP_STATUS_OK)) { + dev_err(sock->dev, "Message ID 0x%X unknown failure (status = 0x%X)\n", + msg->msg_id, mbox_status); + return -EIO; + } + + /* + * SMU has responded OK. Read response data. + * SMU reads the input arguments from eight 32 bit registers starting + * from SMN_HSMP_MSG_DATA and writes the response data to the same + * SMN_HSMP_MSG_DATA address. + * We copy the response data if any, back to the args[]. + */ + index = 0; + while (index < msg->response_sz) { + ret = sock->amd_hsmp_rdwr(sock, mbinfo->msg_arg_off + (index << 2), + &msg->args[index], HSMP_RD); + if (ret) { + dev_err(sock->dev, "Error %d reading response %u for message ID:%u\n", + ret, index, msg->msg_id); + break; + } + index++; + } + + return ret; +} + +static int validate_message(struct hsmp_message *msg) +{ + /* msg_id against valid range of message IDs */ + if (msg->msg_id < HSMP_TEST || msg->msg_id >= HSMP_MSG_ID_MAX) + return -ENOMSG; + + /* msg_id is a reserved message ID */ + if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_RSVD) + return -ENOMSG; + + /* num_args and response_sz against the HSMP spec */ + if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args || + msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz) + return -EINVAL; + + return 0; +} + +int hsmp_send_message(struct hsmp_message *msg) +{ + struct hsmp_socket *sock; + int ret; + + if (!msg) + return -EINVAL; + ret = validate_message(msg); + if (ret) + return ret; + + if (!hsmp_pdev.sock || msg->sock_ind >= hsmp_pdev.num_sockets) + return -ENODEV; + sock = &hsmp_pdev.sock[msg->sock_ind]; + + /* + * The time taken by smu operation to complete is between + * 10us to 1ms. Sometime it may take more time. + * In SMP system timeout of 100 millisecs should + * be enough for the previous thread to finish the operation + */ + ret = down_timeout(&sock->hsmp_sem, msecs_to_jiffies(HSMP_MSG_TIMEOUT)); + if (ret < 0) + return ret; + + ret = __hsmp_send_message(sock, msg); + + up(&sock->hsmp_sem); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(hsmp_send_message, "AMD_HSMP"); + +int hsmp_test(u16 sock_ind, u32 value) +{ + struct hsmp_message msg = { 0 }; + int ret; + + /* + * Test the hsmp port by performing TEST command. The test message + * takes one argument and returns the value of that argument + 1. + */ + msg.msg_id = HSMP_TEST; + msg.num_args = 1; + msg.response_sz = 1; + msg.args[0] = value; + msg.sock_ind = sock_ind; + + ret = hsmp_send_message(&msg); + if (ret) + return ret; + + /* Check the response value */ + if (msg.args[0] != (value + 1)) { + dev_err(hsmp_pdev.sock[sock_ind].dev, + "Socket %d test message failed, Expected 0x%08X, received 0x%08X\n", + sock_ind, (value + 1), msg.args[0]); + return -EBADE; + } + + return ret; +} +EXPORT_SYMBOL_NS_GPL(hsmp_test, "AMD_HSMP"); + +long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ + int __user *arguser = (int __user *)arg; + struct hsmp_message msg = { 0 }; + int ret; + + if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message))) + return -EFAULT; + + /* + * Check msg_id is within the range of supported msg ids + * i.e within the array bounds of hsmp_msg_desc_table + */ + if (msg.msg_id < HSMP_TEST || msg.msg_id >= HSMP_MSG_ID_MAX) + return -ENOMSG; + + switch (fp->f_mode & (FMODE_WRITE | FMODE_READ)) { + case FMODE_WRITE: + /* + * Device is opened in O_WRONLY mode + * Execute only set/configure commands + */ + if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_SET) + return -EPERM; + break; + case FMODE_READ: + /* + * Device is opened in O_RDONLY mode + * Execute only get/monitor commands + */ + if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_GET) + return -EPERM; + break; + case FMODE_READ | FMODE_WRITE: + /* + * Device is opened in O_RDWR mode + * Execute both get/monitor and set/configure commands + */ + break; + default: + return -EPERM; + } + + ret = hsmp_send_message(&msg); + if (ret) + return ret; + + if (hsmp_msg_desc_table[msg.msg_id].response_sz > 0) { + /* Copy results back to user for get/monitor commands */ + if (copy_to_user(arguser, &msg, sizeof(struct hsmp_message))) + return -EFAULT; + } + + return 0; +} + +ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size) +{ + struct hsmp_message msg = { 0 }; + int ret; + + if (!sock || !buf) + return -EINVAL; + + /* Do not support lseek(), also don't allow more than the size of metric table */ + if (size != sizeof(struct hsmp_metric_table)) { + dev_err(sock->dev, "Wrong buffer size\n"); + return -EINVAL; + } + + msg.msg_id = HSMP_GET_METRIC_TABLE; + msg.sock_ind = sock->sock_ind; + + ret = hsmp_send_message(&msg); + if (ret) + return ret; + memcpy_fromio(buf, sock->metric_tbl_addr, size); + + return size; +} +EXPORT_SYMBOL_NS_GPL(hsmp_metric_tbl_read, "AMD_HSMP"); + +int hsmp_get_tbl_dram_base(u16 sock_ind) +{ + struct hsmp_socket *sock = &hsmp_pdev.sock[sock_ind]; + struct hsmp_message msg = { 0 }; + phys_addr_t dram_addr; + int ret; + + msg.sock_ind = sock_ind; + msg.response_sz = hsmp_msg_desc_table[HSMP_GET_METRIC_TABLE_DRAM_ADDR].response_sz; + msg.msg_id = HSMP_GET_METRIC_TABLE_DRAM_ADDR; + + ret = hsmp_send_message(&msg); + if (ret) + return ret; + + /* + * calculate the metric table DRAM address from lower and upper 32 bits + * sent from SMU and ioremap it to virtual address. + */ + dram_addr = msg.args[0] | ((u64)(msg.args[1]) << 32); + if (!dram_addr) { + dev_err(sock->dev, "Invalid DRAM address for metric table\n"); + return -ENOMEM; + } + sock->metric_tbl_addr = devm_ioremap(sock->dev, dram_addr, + sizeof(struct hsmp_metric_table)); + if (!sock->metric_tbl_addr) { + dev_err(sock->dev, "Failed to ioremap metric table addr\n"); + return -ENOMEM; + } + return 0; +} +EXPORT_SYMBOL_NS_GPL(hsmp_get_tbl_dram_base, "AMD_HSMP"); + +int hsmp_cache_proto_ver(u16 sock_ind) +{ + struct hsmp_message msg = { 0 }; + int ret; + + msg.msg_id = HSMP_GET_PROTO_VER; + msg.sock_ind = sock_ind; + msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; + + ret = hsmp_send_message(&msg); + if (!ret) + hsmp_pdev.proto_ver = msg.args[0]; + + return ret; +} +EXPORT_SYMBOL_NS_GPL(hsmp_cache_proto_ver, "AMD_HSMP"); + +static const struct file_operations hsmp_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = hsmp_ioctl, + .compat_ioctl = hsmp_ioctl, +}; + +int hsmp_misc_register(struct device *dev) +{ + hsmp_pdev.mdev.name = HSMP_CDEV_NAME; + hsmp_pdev.mdev.minor = MISC_DYNAMIC_MINOR; + hsmp_pdev.mdev.fops = &hsmp_fops; + hsmp_pdev.mdev.parent = dev; + hsmp_pdev.mdev.nodename = HSMP_DEVNODE_NAME; + hsmp_pdev.mdev.mode = 0644; + + return misc_register(&hsmp_pdev.mdev); +} +EXPORT_SYMBOL_NS_GPL(hsmp_misc_register, "AMD_HSMP"); + +void hsmp_misc_deregister(void) +{ + misc_deregister(&hsmp_pdev.mdev); +} +EXPORT_SYMBOL_NS_GPL(hsmp_misc_deregister, "AMD_HSMP"); + +struct hsmp_plat_device *get_hsmp_pdev(void) +{ + return &hsmp_pdev; +} +EXPORT_SYMBOL_NS_GPL(get_hsmp_pdev, "AMD_HSMP"); + +MODULE_DESCRIPTION("AMD HSMP Common driver"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h new file mode 100644 index 00000000000000..e852f0a947e4f8 --- /dev/null +++ b/drivers/platform/x86/amd/hsmp/hsmp.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AMD HSMP Platform Driver + * Copyright (c) 2024, AMD. + * All Rights Reserved. + * + * Header file for HSMP driver + */ + +#ifndef HSMP_H +#define HSMP_H + +#include +#include +#include +#include +#include +#include + +#define HSMP_METRICS_TABLE_NAME "metrics_bin" + +#define HSMP_ATTR_GRP_NAME_SIZE 10 + +#define MAX_AMD_SOCKETS 8 + +#define HSMP_CDEV_NAME "hsmp_cdev" +#define HSMP_DEVNODE_NAME "hsmp" + +struct hsmp_mbaddr_info { + u32 base_addr; + u32 msg_id_off; + u32 msg_resp_off; + u32 msg_arg_off; + u32 size; +}; + +struct hsmp_socket { + struct bin_attribute hsmp_attr; + struct hsmp_mbaddr_info mbinfo; + void __iomem *metric_tbl_addr; + void __iomem *virt_base_addr; + struct semaphore hsmp_sem; + char name[HSMP_ATTR_GRP_NAME_SIZE]; + struct pci_dev *root; + struct device *dev; + u16 sock_ind; + int (*amd_hsmp_rdwr)(struct hsmp_socket *sock, u32 off, u32 *val, bool rw); +}; + +struct hsmp_plat_device { + struct miscdevice mdev; + struct hsmp_socket *sock; + u32 proto_ver; + u16 num_sockets; + bool is_probed; +}; + +int hsmp_cache_proto_ver(u16 sock_ind); +int hsmp_test(u16 sock_ind, u32 value); +long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); +void hsmp_misc_deregister(void); +int hsmp_misc_register(struct device *dev); +int hsmp_get_tbl_dram_base(u16 sock_ind); +ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size); +struct hsmp_plat_device *get_hsmp_pdev(void); +#endif /* HSMP_H */ diff --git a/drivers/platform/x86/amd/hsmp/plat.c b/drivers/platform/x86/amd/hsmp/plat.c new file mode 100644 index 00000000000000..a61f815c9f8065 --- /dev/null +++ b/drivers/platform/x86/amd/hsmp/plat.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD HSMP Platform Driver + * Copyright (c) 2024, AMD. + * All Rights Reserved. + * + * This file provides platform device implementations. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +#include +#include +#include +#include +#include + +#include "hsmp.h" + +#define DRIVER_NAME "amd_hsmp" +#define DRIVER_VERSION "2.3" + +/* + * To access specific HSMP mailbox register, s/w writes the SMN address of HSMP mailbox + * register into the SMN_INDEX register, and reads/writes the SMN_DATA reg. + * Below are required SMN address for HSMP Mailbox register offsets in SMU address space + */ +#define SMN_HSMP_BASE 0x3B00000 +#define SMN_HSMP_MSG_ID 0x0010534 +#define SMN_HSMP_MSG_ID_F1A_M0H 0x0010934 +#define SMN_HSMP_MSG_RESP 0x0010980 +#define SMN_HSMP_MSG_DATA 0x00109E0 + +#define HSMP_INDEX_REG 0xc4 +#define HSMP_DATA_REG 0xc8 + +static struct hsmp_plat_device *hsmp_pdev; + +static int amd_hsmp_pci_rdwr(struct hsmp_socket *sock, u32 offset, + u32 *value, bool write) +{ + int ret; + + if (!sock->root) + return -ENODEV; + + ret = pci_write_config_dword(sock->root, HSMP_INDEX_REG, + sock->mbinfo.base_addr + offset); + if (ret) + return ret; + + ret = (write ? pci_write_config_dword(sock->root, HSMP_DATA_REG, *value) + : pci_read_config_dword(sock->root, HSMP_DATA_REG, value)); + + return ret; +} + +static ssize_t hsmp_metric_tbl_plat_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct hsmp_socket *sock; + u16 sock_ind; + + sock_ind = (uintptr_t)bin_attr->private; + if (sock_ind >= hsmp_pdev->num_sockets) + return -EINVAL; + + sock = &hsmp_pdev->sock[sock_ind]; + + return hsmp_metric_tbl_read(sock, buf, count); +} + +static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, + const struct bin_attribute *battr, int id) +{ + u16 sock_ind; + + sock_ind = (uintptr_t)battr->private; + + if (id == 0 && sock_ind >= hsmp_pdev->num_sockets) + return SYSFS_GROUP_INVISIBLE; + + if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) + return battr->attr.mode; + + return 0; +} + +/* + * AMD supports maximum of 8 sockets in a system. + * Static array of 8 + 1(for NULL) elements is created below + * to create sysfs groups for sockets. + * is_bin_visible function is used to show / hide the necessary groups. + */ +#define HSMP_BIN_ATTR(index, _list) \ +static struct bin_attribute attr##index = { \ + .attr = { .name = HSMP_METRICS_TABLE_NAME, .mode = 0444}, \ + .private = (void *)index, \ + .read = hsmp_metric_tbl_plat_read, \ + .size = sizeof(struct hsmp_metric_table), \ +}; \ +static struct bin_attribute _list[] = { \ + &attr##index, \ + NULL \ +} + +HSMP_BIN_ATTR(0, *sock0_attr_list); +HSMP_BIN_ATTR(1, *sock1_attr_list); +HSMP_BIN_ATTR(2, *sock2_attr_list); +HSMP_BIN_ATTR(3, *sock3_attr_list); +HSMP_BIN_ATTR(4, *sock4_attr_list); +HSMP_BIN_ATTR(5, *sock5_attr_list); +HSMP_BIN_ATTR(6, *sock6_attr_list); +HSMP_BIN_ATTR(7, *sock7_attr_list); + +#define HSMP_BIN_ATTR_GRP(index, _list, _name) \ +static struct attribute_group sock##index##_attr_grp = { \ + .bin_attrs = _list, \ + .is_bin_visible = hsmp_is_sock_attr_visible, \ + .name = #_name, \ +} + +HSMP_BIN_ATTR_GRP(0, sock0_attr_list, socket0); +HSMP_BIN_ATTR_GRP(1, sock1_attr_list, socket1); +HSMP_BIN_ATTR_GRP(2, sock2_attr_list, socket2); +HSMP_BIN_ATTR_GRP(3, sock3_attr_list, socket3); +HSMP_BIN_ATTR_GRP(4, sock4_attr_list, socket4); +HSMP_BIN_ATTR_GRP(5, sock5_attr_list, socket5); +HSMP_BIN_ATTR_GRP(6, sock6_attr_list, socket6); +HSMP_BIN_ATTR_GRP(7, sock7_attr_list, socket7); + +static const struct attribute_group *hsmp_groups[] = { + &sock0_attr_grp, + &sock1_attr_grp, + &sock2_attr_grp, + &sock3_attr_grp, + &sock4_attr_grp, + &sock5_attr_grp, + &sock6_attr_grp, + &sock7_attr_grp, + NULL +}; + +static inline bool is_f1a_m0h(void) +{ + if (boot_cpu_data.x86 == 0x1A && boot_cpu_data.x86_model <= 0x0F) + return true; + + return false; +} + +static int init_platform_device(struct device *dev) +{ + struct hsmp_socket *sock; + int ret, i; + + for (i = 0; i < hsmp_pdev->num_sockets; i++) { + if (!node_to_amd_nb(i)) + return -ENODEV; + sock = &hsmp_pdev->sock[i]; + sock->root = node_to_amd_nb(i)->root; + sock->sock_ind = i; + sock->dev = dev; + sock->mbinfo.base_addr = SMN_HSMP_BASE; + sock->amd_hsmp_rdwr = amd_hsmp_pci_rdwr; + + /* + * This is a transitional change from non-ACPI to ACPI, only + * family 0x1A, model 0x00 platform is supported for both ACPI and non-ACPI. + */ + if (is_f1a_m0h()) + sock->mbinfo.msg_id_off = SMN_HSMP_MSG_ID_F1A_M0H; + else + sock->mbinfo.msg_id_off = SMN_HSMP_MSG_ID; + + sock->mbinfo.msg_resp_off = SMN_HSMP_MSG_RESP; + sock->mbinfo.msg_arg_off = SMN_HSMP_MSG_DATA; + sema_init(&sock->hsmp_sem, 1); + + /* Test the hsmp interface on each socket */ + ret = hsmp_test(i, 0xDEADBEEF); + if (ret) { + dev_err(dev, "HSMP test message failed on Fam:%x model:%x\n", + boot_cpu_data.x86, boot_cpu_data.x86_model); + dev_err(dev, "Is HSMP disabled in BIOS ?\n"); + return ret; + } + + ret = hsmp_cache_proto_ver(i); + if (ret) { + dev_err(dev, "Failed to read HSMP protocol version\n"); + return ret; + } + + if (hsmp_pdev->proto_ver == HSMP_PROTO_VER6) { + ret = hsmp_get_tbl_dram_base(i); + if (ret) + dev_err(dev, "Failed to init metric table\n"); + } + } + + return 0; +} + +static int hsmp_pltdrv_probe(struct platform_device *pdev) +{ + int ret; + + hsmp_pdev->sock = devm_kcalloc(&pdev->dev, hsmp_pdev->num_sockets, + sizeof(*hsmp_pdev->sock), + GFP_KERNEL); + if (!hsmp_pdev->sock) + return -ENOMEM; + + ret = init_platform_device(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Failed to init HSMP mailbox\n"); + return ret; + } + + return hsmp_misc_register(&pdev->dev); +} + +static void hsmp_pltdrv_remove(struct platform_device *pdev) +{ + hsmp_misc_deregister(); +} + +static struct platform_driver amd_hsmp_driver = { + .probe = hsmp_pltdrv_probe, + .remove = hsmp_pltdrv_remove, + .driver = { + .name = DRIVER_NAME, + .dev_groups = hsmp_groups, + }, +}; + +static struct platform_device *amd_hsmp_platdev; + +static int hsmp_plat_dev_register(void) +{ + int ret; + + amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE); + if (!amd_hsmp_platdev) + return -ENOMEM; + + ret = platform_device_add(amd_hsmp_platdev); + if (ret) + platform_device_put(amd_hsmp_platdev); + + return ret; +} + +/* + * This check is only needed for backward compatibility of previous platforms. + * All new platforms are expected to support ACPI based probing. + */ +static bool legacy_hsmp_support(void) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return false; + + switch (boot_cpu_data.x86) { + case 0x19: + switch (boot_cpu_data.x86_model) { + case 0x00 ... 0x1F: + case 0x30 ... 0x3F: + case 0x90 ... 0x9F: + case 0xA0 ... 0xAF: + return true; + default: + return false; + } + case 0x1A: + switch (boot_cpu_data.x86_model) { + case 0x00 ... 0x1F: + return true; + default: + return false; + } + default: + return false; + } + + return false; +} + +static int __init hsmp_plt_init(void) +{ + int ret = -ENODEV; + + if (!legacy_hsmp_support()) { + pr_info("HSMP is not supported on Family:%x model:%x\n", + boot_cpu_data.x86, boot_cpu_data.x86_model); + return ret; + } + + hsmp_pdev = get_hsmp_pdev(); + if (!hsmp_pdev) + return -ENOMEM; + + /* + * amd_nb_num() returns number of SMN/DF interfaces present in the system + * if we have N SMN/DF interfaces that ideally means N sockets + */ + hsmp_pdev->num_sockets = amd_nb_num(); + if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_SOCKETS) + return ret; + + ret = platform_driver_register(&amd_hsmp_driver); + if (ret) + return ret; + + ret = hsmp_plat_dev_register(); + if (ret) + platform_driver_unregister(&amd_hsmp_driver); + + return ret; +} + +static void __exit hsmp_plt_exit(void) +{ + platform_device_unregister(amd_hsmp_platdev); + platform_driver_unregister(&amd_hsmp_driver); +} + +device_initcall(hsmp_plt_init); +module_exit(hsmp_plt_exit); + +MODULE_IMPORT_NS("AMD_HSMP"); +MODULE_DESCRIPTION("AMD HSMP Platform Interface Driver"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index 5669f94c3d06bf..26b878ee519181 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -1161,7 +1161,7 @@ static struct platform_driver amd_pmc_driver = { .pm = pm_sleep_ptr(&amd_pmc_pm), }, .probe = amd_pmc_probe, - .remove_new = amd_pmc_remove, + .remove = amd_pmc_remove, }; module_platform_driver(amd_pmc_driver); diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig index f4fa8bd8bda832..99d67cdbd91e5e 100644 --- a/drivers/platform/x86/amd/pmf/Kconfig +++ b/drivers/platform/x86/amd/pmf/Kconfig @@ -11,6 +11,7 @@ config AMD_PMF select ACPI_PLATFORM_PROFILE depends on TEE && AMDTEE depends on AMD_SFH_HID + depends on HAS_IOMEM help This driver provides support for the AMD Platform Management Framework. The goal is to enhance end user experience by making AMD PCs smarter, diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c index d5b496433d6975..1b9c7acf0ddf55 100644 --- a/drivers/platform/x86/amd/pmf/acpi.c +++ b/drivers/platform/x86/amd/pmf/acpi.c @@ -433,37 +433,29 @@ int apmf_install_handler(struct amd_pmf_dev *pmf_dev) return 0; } -static acpi_status apmf_walk_resources(struct acpi_resource *res, void *data) +int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev) { - struct amd_pmf_dev *dev = data; + struct platform_device *pdev = to_platform_device(pmf_dev->dev); - switch (res->type) { - case ACPI_RESOURCE_TYPE_ADDRESS64: - dev->policy_addr = res->data.address64.address.minimum; - dev->policy_sz = res->data.address64.address.address_length; - break; - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - dev->policy_addr = res->data.fixed_memory32.address; - dev->policy_sz = res->data.fixed_memory32.address_length; - break; - } - - if (!dev->policy_addr || dev->policy_sz > POLICY_BUF_MAX_SZ || dev->policy_sz == 0) { - pr_err("Incorrect Policy params, possibly a SBIOS bug\n"); - return AE_ERROR; + pmf_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!pmf_dev->res) { + dev_dbg(pmf_dev->dev, "Failed to get I/O memory resource\n"); + return -EINVAL; } - return AE_OK; -} - -int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev) -{ - acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev); - acpi_status status; - - status = acpi_walk_resources(ahandle, METHOD_NAME__CRS, apmf_walk_resources, pmf_dev); - if (ACPI_FAILURE(status)) { - dev_dbg(pmf_dev->dev, "acpi_walk_resources failed :%d\n", status); + pmf_dev->policy_addr = pmf_dev->res->start; + /* + * We cannot use resource_size() here because it adds an extra byte to round off the size. + * In the case of PMF ResourceTemplate(), this rounding is already handled within the _CRS. + * Using resource_size() would increase the resource size by 1, causing a mismatch with the + * length field and leading to issues. Therefore, simply use end-start of the ACPI resource + * to obtain the actual length. + */ + pmf_dev->policy_sz = pmf_dev->res->end - pmf_dev->res->start; + + if (!pmf_dev->policy_addr || pmf_dev->policy_sz > POLICY_BUF_MAX_SZ || + pmf_dev->policy_sz == 0) { + dev_err(pmf_dev->dev, "Incorrect policy params, possibly a SBIOS bug\n"); return -EINVAL; } diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c index 347bb43a5f2b75..06a97c533cb852 100644 --- a/drivers/platform/x86/amd/pmf/core.c +++ b/drivers/platform/x86/amd/pmf/core.c @@ -430,18 +430,18 @@ static int amd_pmf_probe(struct platform_device *pdev) err = amd_smn_read(0, AMD_PMF_BASE_ADDR_LO, &val); if (err) { - dev_err(dev->dev, "error in reading from 0x%x\n", AMD_PMF_BASE_ADDR_LO); pci_dev_put(rdev); - return pcibios_err_to_errno(err); + return dev_err_probe(dev->dev, pcibios_err_to_errno(err), + "error in reading from 0x%x\n", AMD_PMF_BASE_ADDR_LO); } base_addr_lo = val & AMD_PMF_BASE_ADDR_HI_MASK; err = amd_smn_read(0, AMD_PMF_BASE_ADDR_HI, &val); if (err) { - dev_err(dev->dev, "error in reading from 0x%x\n", AMD_PMF_BASE_ADDR_HI); pci_dev_put(rdev); - return pcibios_err_to_errno(err); + return dev_err_probe(dev->dev, pcibios_err_to_errno(err), + "error in reading from 0x%x\n", AMD_PMF_BASE_ADDR_HI); } base_addr_hi = val & AMD_PMF_BASE_ADDR_LO_MASK; @@ -497,7 +497,7 @@ static struct platform_driver amd_pmf_driver = { .pm = pm_sleep_ptr(&amd_pmf_pm), }, .probe = amd_pmf_probe, - .remove_new = amd_pmf_remove, + .remove = amd_pmf_remove, }; module_platform_driver(amd_pmf_driver); diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h index 8ce8816da9c168..a79808fda1d891 100644 --- a/drivers/platform/x86/amd/pmf/pmf.h +++ b/drivers/platform/x86/amd/pmf/pmf.h @@ -13,6 +13,7 @@ #include #include +#include #include #define POLICY_BUF_MAX_SZ 0x4b000 @@ -355,19 +356,20 @@ struct amd_pmf_dev { /* Smart PC solution builder */ struct dentry *esbin; unsigned char *policy_buf; - u32 policy_sz; + resource_size_t policy_sz; struct tee_context *tee_ctx; struct tee_shm *fw_shm_pool; u32 session_id; void *shbuf; struct delayed_work pb_work; struct pmf_action_table *prev_data; - u64 policy_addr; + resource_size_t policy_addr; void __iomem *policy_base; bool smart_pc_enabled; u16 pmf_if_version; struct input_dev *pmf_idev; size_t mtable_size; + struct resource *res; }; struct apmf_sps_prop_granular_v2 { diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c index 19c27b6e46663c..8c88769ea1d87d 100644 --- a/drivers/platform/x86/amd/pmf/tee-if.c +++ b/drivers/platform/x86/amd/pmf/tee-if.c @@ -257,7 +257,7 @@ static int amd_pmf_invoke_cmd_init(struct amd_pmf_dev *dev) return -ENODEV; } - dev_dbg(dev->dev, "Policy Binary size: %u bytes\n", dev->policy_sz); + dev_dbg(dev->dev, "Policy Binary size: %llu bytes\n", (unsigned long long)dev->policy_sz); memset(dev->shbuf, 0, dev->policy_sz); ta_sm = dev->shbuf; in = &ta_sm->pmf_input.init_table; @@ -512,9 +512,9 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev) if (ret) goto error; - dev->policy_base = devm_ioremap(dev->dev, dev->policy_addr, dev->policy_sz); - if (!dev->policy_base) { - ret = -ENOMEM; + dev->policy_base = devm_ioremap_resource(dev->dev, dev->res); + if (IS_ERR(dev->policy_base)) { + ret = PTR_ERR(dev->policy_base); goto error; } diff --git a/drivers/platform/x86/amd/x3d_vcache.c b/drivers/platform/x86/amd/x3d_vcache.c new file mode 100644 index 00000000000000..0f6d3c54d87955 --- /dev/null +++ b/drivers/platform/x86/amd/x3d_vcache.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD 3D V-Cache Performance Optimizer Driver + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Authors: Basavaraj Natikar + * Perry Yuan + * Mario Limonciello + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *x3d_mode = "frequency"; +module_param(x3d_mode, charp, 0); +MODULE_PARM_DESC(x3d_mode, "Initial 3D-VCache mode; 'frequency' (default) or 'cache'"); + +#define DSM_REVISION_ID 0 +#define DSM_SET_X3D_MODE 1 + +static guid_t x3d_guid = GUID_INIT(0xdff8e55f, 0xbcfd, 0x46fb, 0xba, 0x0a, + 0xef, 0xd0, 0x45, 0x0f, 0x34, 0xee); + +enum amd_x3d_mode_type { + MODE_INDEX_FREQ, + MODE_INDEX_CACHE, +}; + +static const char * const amd_x3d_mode_strings[] = { + [MODE_INDEX_FREQ] = "frequency", + [MODE_INDEX_CACHE] = "cache", +}; + +struct amd_x3d_dev { + struct device *dev; + acpi_handle ahandle; + /* To protect x3d mode setting */ + struct mutex lock; + enum amd_x3d_mode_type curr_mode; +}; + +static int amd_x3d_get_mode(struct amd_x3d_dev *data) +{ + guard(mutex)(&data->lock); + + return data->curr_mode; +} + +static int amd_x3d_mode_switch(struct amd_x3d_dev *data, int new_state) +{ + union acpi_object *out, argv; + + guard(mutex)(&data->lock); + argv.type = ACPI_TYPE_INTEGER; + argv.integer.value = new_state; + + out = acpi_evaluate_dsm(data->ahandle, &x3d_guid, DSM_REVISION_ID, + DSM_SET_X3D_MODE, &argv); + if (!out) { + dev_err(data->dev, "failed to evaluate _DSM\n"); + return -EINVAL; + } + + data->curr_mode = new_state; + + kfree(out); + + return 0; +} + +static ssize_t amd_x3d_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct amd_x3d_dev *data = dev_get_drvdata(dev); + int ret; + + ret = sysfs_match_string(amd_x3d_mode_strings, buf); + if (ret < 0) + return ret; + + ret = amd_x3d_mode_switch(data, ret); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t amd_x3d_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct amd_x3d_dev *data = dev_get_drvdata(dev); + int mode = amd_x3d_get_mode(data); + + return sysfs_emit(buf, "%s\n", amd_x3d_mode_strings[mode]); +} +static DEVICE_ATTR_RW(amd_x3d_mode); + +static struct attribute *amd_x3d_attrs[] = { + &dev_attr_amd_x3d_mode.attr, + NULL +}; +ATTRIBUTE_GROUPS(amd_x3d); + +static int amd_x3d_resume_handler(struct device *dev) +{ + struct amd_x3d_dev *data = dev_get_drvdata(dev); + int ret = amd_x3d_get_mode(data); + + return amd_x3d_mode_switch(data, ret); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(amd_x3d_pm, NULL, amd_x3d_resume_handler); + +static const struct acpi_device_id amd_x3d_acpi_ids[] = { + {"AMDI0101"}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, amd_x3d_acpi_ids); + +static int amd_x3d_probe(struct platform_device *pdev) +{ + struct amd_x3d_dev *data; + acpi_handle handle; + int ret; + + handle = ACPI_HANDLE(&pdev->dev); + if (!handle) + return -ENODEV; + + if (!acpi_check_dsm(handle, &x3d_guid, DSM_REVISION_ID, BIT(DSM_SET_X3D_MODE))) + return -ENODEV; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &pdev->dev; + + ret = devm_mutex_init(data->dev, &data->lock); + if (ret) + return ret; + + data->ahandle = handle; + platform_set_drvdata(pdev, data); + + ret = match_string(amd_x3d_mode_strings, ARRAY_SIZE(amd_x3d_mode_strings), x3d_mode); + if (ret < 0) + return dev_err_probe(&pdev->dev, -EINVAL, "invalid mode %s\n", x3d_mode); + + return amd_x3d_mode_switch(data, ret); +} + +static struct platform_driver amd_3d_vcache_driver = { + .driver = { + .name = "amd_x3d_vcache", + .dev_groups = amd_x3d_groups, + .acpi_match_table = amd_x3d_acpi_ids, + .pm = pm_sleep_ptr(&amd_x3d_pm), + }, + .probe = amd_x3d_probe, +}; +module_platform_driver(amd_3d_vcache_driver); + +MODULE_DESCRIPTION("AMD 3D V-Cache Performance Optimizer Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c index 2423dc91debb93..18397c527eab35 100644 --- a/drivers/platform/x86/amilo-rfkill.c +++ b/drivers/platform/x86/amilo-rfkill.c @@ -132,10 +132,10 @@ static void amilo_rfkill_remove(struct platform_device *device) static struct platform_driver amilo_rfkill_driver = { .driver = { - .name = KBUILD_MODNAME, + .name = KBUILD_MODNAME, }, - .probe = amilo_rfkill_probe, - .remove_new = amilo_rfkill_remove, + .probe = amilo_rfkill_probe, + .remove = amilo_rfkill_remove, }; static int __init amilo_rfkill_init(void) diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 9d7e6b712abf11..d460dd194f1965 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1832,8 +1832,8 @@ static int asus_acpi_add(struct acpi_device *device) if (!asus) return -ENOMEM; asus->handle = device->handle; - strcpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME); - strcpy(acpi_device_class(device), ASUS_LAPTOP_CLASS); + strscpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME); + strscpy(acpi_device_class(device), ASUS_LAPTOP_CLASS); device->driver_data = asus; asus->device = device; diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index ef04d396f61c77..a5933980ade3d6 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -623,6 +623,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ + { KE_IGNORE, 0xCF, }, /* AC mode */ { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ { KE_KEY, 0xBD, { KEY_PROG2 } }, /* Lid flip action on ROG xflow laptops */ { KE_END, 0}, diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index abdca3f05c5c15..8bd187e8b47f80 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -3696,12 +3696,29 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) /* Throttle thermal policy ****************************************************/ static int throttle_thermal_policy_write(struct asus_wmi *asus) { - u8 value = asus->throttle_thermal_policy_mode; - u32 retval; + u8 value; int err; - err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, - value, &retval); + if (asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO) { + switch (asus->throttle_thermal_policy_mode) { + case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: + value = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; + break; + case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: + value = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; + break; + case ASUS_THROTTLE_THERMAL_POLICY_SILENT: + value = ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; + break; + default: + return -EINVAL; + } + } else { + value = asus->throttle_thermal_policy_mode; + } + + /* Some machines do not return an error code as a result, so we ignore it */ + err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev, value, NULL); sysfs_notify(&asus->platform_device->dev.kobj, NULL, "throttle_thermal_policy"); @@ -3711,12 +3728,6 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) return err; } - if (retval != 1) { - pr_warn("Failed to set throttle thermal policy (retval): 0x%x\n", - retval); - return -EIO; - } - /* Must set to disabled if mode is toggled */ if (asus->cpu_fan_curve_available) asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; @@ -3737,28 +3748,6 @@ static int throttle_thermal_policy_set_default(struct asus_wmi *asus) return throttle_thermal_policy_write(asus); } -static int throttle_thermal_policy_switch_next(struct asus_wmi *asus) -{ - u8 new_mode = asus->throttle_thermal_policy_mode + 1; - int err; - - if (new_mode > PLATFORM_PROFILE_MAX) - new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; - - asus->throttle_thermal_policy_mode = new_mode; - err = throttle_thermal_policy_write(asus); - if (err) - return err; - - /* - * Ensure that platform_profile updates userspace with the change to ensure - * that platform_profile and throttle_thermal_policy_mode are in sync. - */ - platform_profile_notify(); - - return 0; -} - static ssize_t throttle_thermal_policy_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -3804,46 +3793,6 @@ static ssize_t throttle_thermal_policy_store(struct device *dev, static DEVICE_ATTR_RW(throttle_thermal_policy); /* Platform profile ***********************************************************/ -static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode) -{ - bool vivo; - - vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; - - if (vivo) { - switch (mode) { - case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: - return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO; - case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST: - return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO; - case ASUS_THROTTLE_THERMAL_POLICY_SILENT: - return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO; - } - } - - return mode; -} - -static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode) -{ - bool vivo; - - vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO; - - if (vivo) { - switch (mode) { - case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO: - return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT; - case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO: - return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST; - case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO: - return ASUS_THROTTLE_THERMAL_POLICY_SILENT; - } - } - - return mode; -} - static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, enum platform_profile_option *profile) { @@ -3853,7 +3802,7 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof, asus = container_of(pprof, struct asus_wmi, platform_profile_handler); tp = asus->throttle_thermal_policy_mode; - switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) { + switch (tp) { case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT: *profile = PLATFORM_PROFILE_BALANCED; break; @@ -3892,7 +3841,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof, return -EOPNOTSUPP; } - asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp); + asus->throttle_thermal_policy_mode = tp; return throttle_thermal_policy_write(asus); } @@ -4323,7 +4272,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus) if (asus->fan_boost_mode_available) fan_boost_mode_switch_next(asus); if (asus->throttle_thermal_policy_dev) - throttle_thermal_policy_switch_next(asus); + platform_profile_cycle(); return; } @@ -5076,7 +5025,7 @@ int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver) return -EBUSY; platform_driver = &driver->platform_driver; - platform_driver->remove_new = asus_wmi_remove; + platform_driver->remove = asus_wmi_remove; platform_driver->driver.owner = driver->owner; platform_driver->driver.name = driver->name; platform_driver->driver.pm = &asus_pm_ops; diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c index af566f71205779..143d14548565fc 100644 --- a/drivers/platform/x86/barco-p50-gpio.c +++ b/drivers/platform/x86/barco-p50-gpio.c @@ -385,7 +385,7 @@ static struct platform_driver p50_gpio_driver = { .name = DRIVER_NAME, }, .probe = p50_gpio_probe, - .remove_new = p50_gpio_remove, + .remove = p50_gpio_remove, }; /* Board setup */ diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index cb6fce655e35b3..6b1b8e444e241c 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -12,6 +12,7 @@ #include #include #include +#include struct cmpc_accel { int sensitivity; @@ -208,7 +209,7 @@ static ssize_t cmpc_accel_sensitivity_show_v4(struct device *dev, inputdev = dev_get_drvdata(&acpi->dev); accel = dev_get_drvdata(&inputdev->dev); - return sprintf(buf, "%d\n", accel->sensitivity); + return sysfs_emit(buf, "%d\n", accel->sensitivity); } static ssize_t cmpc_accel_sensitivity_store_v4(struct device *dev, @@ -257,7 +258,7 @@ static ssize_t cmpc_accel_g_select_show_v4(struct device *dev, inputdev = dev_get_drvdata(&acpi->dev); accel = dev_get_drvdata(&inputdev->dev); - return sprintf(buf, "%d\n", accel->g_select); + return sysfs_emit(buf, "%d\n", accel->g_select); } static ssize_t cmpc_accel_g_select_store_v4(struct device *dev, @@ -550,7 +551,7 @@ static ssize_t cmpc_accel_sensitivity_show(struct device *dev, inputdev = dev_get_drvdata(&acpi->dev); accel = dev_get_drvdata(&inputdev->dev); - return sprintf(buf, "%d\n", accel->sensitivity); + return sysfs_emit(buf, "%d\n", accel->sensitivity); } static ssize_t cmpc_accel_sensitivity_store(struct device *dev, diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 5546fb18949130..58754bc5b5b175 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include @@ -364,21 +365,21 @@ static const struct rfkill_ops compal_rfkill_ops = { /* Wake_up interface */ -#define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK) \ -static ssize_t NAME##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return sprintf(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0)); \ -} \ -static ssize_t NAME##_store(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - int state; \ - u8 old_val = ec_read_u8(ADDR); \ - if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1)) \ - return -EINVAL; \ - ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK)); \ - return count; \ +#define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK) \ +static ssize_t NAME##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + return sysfs_emit(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0)); \ +} \ +static ssize_t NAME##_store(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + int state; \ + u8 old_val = ec_read_u8(ADDR); \ + if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1)) \ + return -EINVAL; \ + ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK)); \ + return count; \ } SIMPLE_MASKED_STORE_SHOW(wake_up_pme, WAKE_UP_ADDR, WAKE_UP_PME) @@ -393,7 +394,7 @@ static ssize_t pwm_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct compal_data *data = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", data->pwm_enable); + return sysfs_emit(buf, "%d\n", data->pwm_enable); } static ssize_t pwm_enable_store(struct device *dev, @@ -432,7 +433,7 @@ static ssize_t pwm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct compal_data *data = dev_get_drvdata(dev); - return sprintf(buf, "%hhu\n", data->curr_pwm); + return sysfs_emit(buf, "%hhu\n", data->curr_pwm); } static ssize_t pwm_store(struct device *dev, struct device_attribute *attr, @@ -460,21 +461,21 @@ static ssize_t pwm_store(struct device *dev, struct device_attribute *attr, static ssize_t fan_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", get_fan_rpm()); + return sysfs_emit(buf, "%d\n", get_fan_rpm()); } /* Temperature interface */ -#define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL) \ -static ssize_t temp_##POSTFIX(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return sprintf(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS)); \ -} \ -static ssize_t label_##POSTFIX(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return sprintf(buf, "%s\n", LABEL); \ +#define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL) \ +static ssize_t temp_##POSTFIX(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + return sysfs_emit(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS)); \ +} \ +static ssize_t label_##POSTFIX(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + return sysfs_emit(buf, "%s\n", LABEL); \ } /* Labels as in service guide */ @@ -1023,8 +1024,8 @@ static struct platform_driver compal_driver = { .driver = { .name = DRIVER_NAME, }, - .probe = compal_probe, - .remove_new = compal_remove, + .probe = compal_probe, + .remove = compal_remove, }; static int __init compal_init(void) diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig index 68a49788a39633..2dddafb3f7fa2f 100644 --- a/drivers/platform/x86/dell/Kconfig +++ b/drivers/platform/x86/dell/Kconfig @@ -21,6 +21,7 @@ config ALIENWARE_WMI depends on LEDS_CLASS depends on NEW_LEDS depends on ACPI_WMI + select ACPI_PLATFORM_PROFILE help This is a driver for controlling Alienware BIOS driven features. It exposes an interface for controlling the AlienFX @@ -194,6 +195,7 @@ config DELL_WMI config DELL_WMI_PRIVACY bool "Dell WMI Hardware Privacy Support" depends on DELL_WMI + depends on ACPI_EC help This option adds integration with the "Dell Hardware Privacy" feature of Dell laptops to the dell-wmi driver. diff --git a/drivers/platform/x86/dell/alienware-wmi.c b/drivers/platform/x86/dell/alienware-wmi.c index f5ee62ce175399..341d01d3e3e4c7 100644 --- a/drivers/platform/x86/dell/alienware-wmi.c +++ b/drivers/platform/x86/dell/alienware-wmi.c @@ -8,8 +8,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include +#include #include #include +#include #include #include @@ -25,6 +28,13 @@ #define WMAX_METHOD_AMPLIFIER_CABLE 0x6 #define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B #define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C +#define WMAX_METHOD_THERMAL_INFORMATION 0x14 +#define WMAX_METHOD_THERMAL_CONTROL 0x15 +#define WMAX_METHOD_GAME_SHIFT_STATUS 0x25 + +#define WMAX_THERMAL_MODE_GMODE 0xAB + +#define WMAX_FAILURE_CODE 0xFFFFFFFF MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Alienware special feature control"); @@ -32,6 +42,14 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("wmi:" LEGACY_CONTROL_GUID); MODULE_ALIAS("wmi:" WMAX_CONTROL_GUID); +static bool force_platform_profile; +module_param_unsafe(force_platform_profile, bool, 0); +MODULE_PARM_DESC(force_platform_profile, "Forces auto-detecting thermal profiles without checking if WMI thermal backend is available"); + +static bool force_gmode; +module_param_unsafe(force_gmode, bool, 0); +MODULE_PARM_DESC(force_gmode, "Forces G-Mode when performance profile is selected"); + enum INTERFACE_FLAGS { LEGACY, WMAX, @@ -49,11 +67,60 @@ enum WMAX_CONTROL_STATES { WMAX_SUSPEND = 3, }; +enum WMAX_THERMAL_INFORMATION_OPERATIONS { + WMAX_OPERATION_SYS_DESCRIPTION = 0x02, + WMAX_OPERATION_LIST_IDS = 0x03, + WMAX_OPERATION_CURRENT_PROFILE = 0x0B, +}; + +enum WMAX_THERMAL_CONTROL_OPERATIONS { + WMAX_OPERATION_ACTIVATE_PROFILE = 0x01, +}; + +enum WMAX_GAME_SHIFT_STATUS_OPERATIONS { + WMAX_OPERATION_TOGGLE_GAME_SHIFT = 0x01, + WMAX_OPERATION_GET_GAME_SHIFT_STATUS = 0x02, +}; + +enum WMAX_THERMAL_TABLES { + WMAX_THERMAL_TABLE_BASIC = 0x90, + WMAX_THERMAL_TABLE_USTT = 0xA0, +}; + +enum wmax_thermal_mode { + THERMAL_MODE_USTT_BALANCED, + THERMAL_MODE_USTT_BALANCED_PERFORMANCE, + THERMAL_MODE_USTT_COOL, + THERMAL_MODE_USTT_QUIET, + THERMAL_MODE_USTT_PERFORMANCE, + THERMAL_MODE_USTT_LOW_POWER, + THERMAL_MODE_BASIC_QUIET, + THERMAL_MODE_BASIC_BALANCED, + THERMAL_MODE_BASIC_BALANCED_PERFORMANCE, + THERMAL_MODE_BASIC_PERFORMANCE, + THERMAL_MODE_LAST, +}; + +static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_MODE_LAST] = { + [THERMAL_MODE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED, + [THERMAL_MODE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, + [THERMAL_MODE_USTT_COOL] = PLATFORM_PROFILE_COOL, + [THERMAL_MODE_USTT_QUIET] = PLATFORM_PROFILE_QUIET, + [THERMAL_MODE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, + [THERMAL_MODE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER, + [THERMAL_MODE_BASIC_QUIET] = PLATFORM_PROFILE_QUIET, + [THERMAL_MODE_BASIC_BALANCED] = PLATFORM_PROFILE_BALANCED, + [THERMAL_MODE_BASIC_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, + [THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, +}; + struct quirk_entry { u8 num_zones; u8 hdmi_mux; u8 amplifier; u8 deepslp; + bool thermal; + bool gmode; }; static struct quirk_entry *quirks; @@ -64,6 +131,8 @@ static struct quirk_entry quirk_inspiron5675 = { .hdmi_mux = 0, .amplifier = 0, .deepslp = 0, + .thermal = false, + .gmode = false, }; static struct quirk_entry quirk_unknown = { @@ -71,6 +140,8 @@ static struct quirk_entry quirk_unknown = { .hdmi_mux = 0, .amplifier = 0, .deepslp = 0, + .thermal = false, + .gmode = false, }; static struct quirk_entry quirk_x51_r1_r2 = { @@ -78,6 +149,8 @@ static struct quirk_entry quirk_x51_r1_r2 = { .hdmi_mux = 0, .amplifier = 0, .deepslp = 0, + .thermal = false, + .gmode = false, }; static struct quirk_entry quirk_x51_r3 = { @@ -85,6 +158,8 @@ static struct quirk_entry quirk_x51_r3 = { .hdmi_mux = 0, .amplifier = 1, .deepslp = 0, + .thermal = false, + .gmode = false, }; static struct quirk_entry quirk_asm100 = { @@ -92,6 +167,8 @@ static struct quirk_entry quirk_asm100 = { .hdmi_mux = 1, .amplifier = 0, .deepslp = 0, + .thermal = false, + .gmode = false, }; static struct quirk_entry quirk_asm200 = { @@ -99,6 +176,8 @@ static struct quirk_entry quirk_asm200 = { .hdmi_mux = 1, .amplifier = 0, .deepslp = 1, + .thermal = false, + .gmode = false, }; static struct quirk_entry quirk_asm201 = { @@ -106,6 +185,26 @@ static struct quirk_entry quirk_asm201 = { .hdmi_mux = 1, .amplifier = 1, .deepslp = 1, + .thermal = false, + .gmode = false, +}; + +static struct quirk_entry quirk_g_series = { + .num_zones = 0, + .hdmi_mux = 0, + .amplifier = 0, + .deepslp = 0, + .thermal = true, + .gmode = true, +}; + +static struct quirk_entry quirk_x_series = { + .num_zones = 0, + .hdmi_mux = 0, + .amplifier = 0, + .deepslp = 0, + .thermal = true, + .gmode = false, }; static int __init dmi_matched(const struct dmi_system_id *dmi) @@ -116,68 +215,167 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) static const struct dmi_system_id alienware_quirks[] __initconst = { { - .callback = dmi_matched, - .ident = "Alienware X51 R3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"), - }, - .driver_data = &quirk_x51_r3, - }, + .callback = dmi_matched, + .ident = "Alienware ASM100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"), + }, + .driver_data = &quirk_asm100, + }, + { + .callback = dmi_matched, + .ident = "Alienware ASM200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "ASM200"), + }, + .driver_data = &quirk_asm200, + }, + { + .callback = dmi_matched, + .ident = "Alienware ASM201", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"), + }, + .driver_data = &quirk_asm201, + }, + { + .callback = dmi_matched, + .ident = "Alienware m16 R1 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"), + }, + .driver_data = &quirk_x_series, + }, + { + .callback = dmi_matched, + .ident = "Alienware m17 R5", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"), + }, + .driver_data = &quirk_x_series, + }, + { + .callback = dmi_matched, + .ident = "Alienware m18 R2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"), + }, + .driver_data = &quirk_x_series, + }, + { + .callback = dmi_matched, + .ident = "Alienware x15 R1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"), + }, + .driver_data = &quirk_x_series, + }, + { + .callback = dmi_matched, + .ident = "Alienware x17 R2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"), + }, + .driver_data = &quirk_x_series, + }, + { + .callback = dmi_matched, + .ident = "Alienware X51 R1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"), + }, + .driver_data = &quirk_x51_r1_r2, + }, + { + .callback = dmi_matched, + .ident = "Alienware X51 R2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"), + }, + .driver_data = &quirk_x51_r1_r2, + }, + { + .callback = dmi_matched, + .ident = "Alienware X51 R3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"), + }, + .driver_data = &quirk_x51_r3, + }, { - .callback = dmi_matched, - .ident = "Alienware X51 R2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"), - }, - .driver_data = &quirk_x51_r1_r2, - }, + .callback = dmi_matched, + .ident = "Dell Inc. G15 5510", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"), + }, + .driver_data = &quirk_g_series, + }, { - .callback = dmi_matched, - .ident = "Alienware X51 R1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"), - }, - .driver_data = &quirk_x51_r1_r2, - }, + .callback = dmi_matched, + .ident = "Dell Inc. G15 5511", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"), + }, + .driver_data = &quirk_g_series, + }, { - .callback = dmi_matched, - .ident = "Alienware ASM100", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"), - }, - .driver_data = &quirk_asm100, - }, + .callback = dmi_matched, + .ident = "Dell Inc. G15 5515", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"), + }, + .driver_data = &quirk_g_series, + }, { - .callback = dmi_matched, - .ident = "Alienware ASM200", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "ASM200"), - }, - .driver_data = &quirk_asm200, - }, + .callback = dmi_matched, + .ident = "Dell Inc. G3 3500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"), + }, + .driver_data = &quirk_g_series, + }, { - .callback = dmi_matched, - .ident = "Alienware ASM201", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"), - }, - .driver_data = &quirk_asm201, - }, - { - .callback = dmi_matched, - .ident = "Dell Inc. Inspiron 5675", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"), - }, - .driver_data = &quirk_inspiron5675, - }, + .callback = dmi_matched, + .ident = "Dell Inc. G3 3590", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"), + }, + .driver_data = &quirk_g_series, + }, + { + .callback = dmi_matched, + .ident = "Dell Inc. G5 5500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"), + }, + .driver_data = &quirk_g_series, + }, + { + .callback = dmi_matched, + .ident = "Dell Inc. Inspiron 5675", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"), + }, + .driver_data = &quirk_inspiron5675, + }, {} }; @@ -214,15 +412,24 @@ struct wmax_led_args { u8 state; } __packed; +struct wmax_u32_args { + u8 operation; + u8 arg1; + u8 arg2; + u8 arg3; +}; + static struct platform_device *platform_device; static struct device_attribute *zone_dev_attrs; static struct attribute **zone_attrs; static struct platform_zone *zone_data; +static struct platform_profile_handler pp_handler; +static enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST]; static struct platform_driver platform_driver = { .driver = { - .name = "alienware-wmi", - } + .name = "alienware-wmi", + } }; static struct attribute_group zone_attribute_group = { @@ -292,7 +499,7 @@ static int alienware_update_led(struct platform_zone *zone) guid = WMAX_CONTROL_GUID; method_id = WMAX_METHOD_ZONE_CONTROL; - input.length = (acpi_size) sizeof(wmax_basic_args); + input.length = sizeof(wmax_basic_args); input.pointer = &wmax_basic_args; } else { legacy_args.colors = zone->colors; @@ -306,7 +513,7 @@ static int alienware_update_led(struct platform_zone *zone) guid = LEGACY_CONTROL_GUID; method_id = zone->location + 1; - input.length = (acpi_size) sizeof(legacy_args); + input.length = sizeof(legacy_args); input.pointer = &legacy_args; } pr_debug("alienware-wmi: guid %s method %d\n", guid, method_id); @@ -358,7 +565,7 @@ static int wmax_brightness(int brightness) .led_mask = 0xFF, .percentage = brightness, }; - input.length = (acpi_size) sizeof(args); + input.length = sizeof(args); input.pointer = &args; status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, WMAX_METHOD_BRIGHTNESS, &input, NULL); @@ -489,6 +696,9 @@ static void alienware_zone_exit(struct platform_device *dev) { u8 zone; + if (!quirks->num_zones) + return; + sysfs_remove_group(&dev->dev.kobj, &zone_attribute_group); led_classdev_unregister(&global_led); if (zone_dev_attrs) { @@ -500,15 +710,15 @@ static void alienware_zone_exit(struct platform_device *dev) kfree(zone_attrs); } -static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, - u32 command, int *out_data) +static acpi_status alienware_wmax_command(void *in_args, size_t in_size, + u32 command, u32 *out_data) { acpi_status status; union acpi_object *obj; struct acpi_buffer input; struct acpi_buffer output; - input.length = (acpi_size) sizeof(*in_args); + input.length = in_size; input.pointer = in_args; if (out_data) { output.length = ACPI_ALLOCATE_BUFFER; @@ -541,8 +751,8 @@ static ssize_t show_hdmi_cable(struct device *dev, .arg = 0, }; status = - alienware_wmax_command(&in_args, WMAX_METHOD_HDMI_CABLE, - (u32 *) &out_data); + alienware_wmax_command(&in_args, sizeof(in_args), + WMAX_METHOD_HDMI_CABLE, &out_data); if (ACPI_SUCCESS(status)) { if (out_data == 0) return sysfs_emit(buf, "[unconnected] connected unknown\n"); @@ -562,8 +772,8 @@ static ssize_t show_hdmi_source(struct device *dev, .arg = 0, }; status = - alienware_wmax_command(&in_args, WMAX_METHOD_HDMI_STATUS, - (u32 *) &out_data); + alienware_wmax_command(&in_args, sizeof(in_args), + WMAX_METHOD_HDMI_STATUS, &out_data); if (ACPI_SUCCESS(status)) { if (out_data == 1) @@ -589,7 +799,8 @@ static ssize_t toggle_hdmi_source(struct device *dev, args.arg = 3; pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); - status = alienware_wmax_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); + status = alienware_wmax_command(&args, sizeof(args), + WMAX_METHOD_HDMI_SOURCE, NULL); if (ACPI_FAILURE(status)) pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", @@ -642,8 +853,8 @@ static ssize_t show_amplifier_status(struct device *dev, .arg = 0, }; status = - alienware_wmax_command(&in_args, WMAX_METHOD_AMPLIFIER_CABLE, - (u32 *) &out_data); + alienware_wmax_command(&in_args, sizeof(in_args), + WMAX_METHOD_AMPLIFIER_CABLE, &out_data); if (ACPI_SUCCESS(status)) { if (out_data == 0) return sysfs_emit(buf, "[unconnected] connected unknown\n"); @@ -694,8 +905,8 @@ static ssize_t show_deepsleep_status(struct device *dev, struct wmax_basic_args in_args = { .arg = 0, }; - status = alienware_wmax_command(&in_args, WMAX_METHOD_DEEP_SLEEP_STATUS, - (u32 *) &out_data); + status = alienware_wmax_command(&in_args, sizeof(in_args), + WMAX_METHOD_DEEP_SLEEP_STATUS, &out_data); if (ACPI_SUCCESS(status)) { if (out_data == 0) return sysfs_emit(buf, "[disabled] s5 s5_s4\n"); @@ -723,8 +934,8 @@ static ssize_t toggle_deepsleep(struct device *dev, args.arg = 2; pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf); - status = alienware_wmax_command(&args, WMAX_METHOD_DEEP_SLEEP_CONTROL, - NULL); + status = alienware_wmax_command(&args, sizeof(args), + WMAX_METHOD_DEEP_SLEEP_CONTROL, NULL); if (ACPI_FAILURE(status)) pr_err("alienware-wmi: deep sleep control failed: results: %u\n", @@ -760,6 +971,213 @@ static int create_deepsleep(struct platform_device *dev) return ret; } +/* + * Thermal Profile control + * - Provides thermal profile control through the Platform Profile API + */ +#define WMAX_THERMAL_TABLE_MASK GENMASK(7, 4) +#define WMAX_THERMAL_MODE_MASK GENMASK(3, 0) +#define WMAX_SENSOR_ID_MASK BIT(8) + +static bool is_wmax_thermal_code(u32 code) +{ + if (code & WMAX_SENSOR_ID_MASK) + return false; + + if ((code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_LAST) + return false; + + if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_BASIC && + (code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_BASIC_QUIET) + return true; + + if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_USTT && + (code & WMAX_THERMAL_MODE_MASK) <= THERMAL_MODE_USTT_LOW_POWER) + return true; + + return false; +} + +static int wmax_thermal_information(u8 operation, u8 arg, u32 *out_data) +{ + acpi_status status; + struct wmax_u32_args in_args = { + .operation = operation, + .arg1 = arg, + .arg2 = 0, + .arg3 = 0, + }; + + status = alienware_wmax_command(&in_args, sizeof(in_args), + WMAX_METHOD_THERMAL_INFORMATION, + out_data); + + if (ACPI_FAILURE(status)) + return -EIO; + + if (*out_data == WMAX_FAILURE_CODE) + return -EBADRQC; + + return 0; +} + +static int wmax_thermal_control(u8 profile) +{ + acpi_status status; + struct wmax_u32_args in_args = { + .operation = WMAX_OPERATION_ACTIVATE_PROFILE, + .arg1 = profile, + .arg2 = 0, + .arg3 = 0, + }; + u32 out_data; + + status = alienware_wmax_command(&in_args, sizeof(in_args), + WMAX_METHOD_THERMAL_CONTROL, + &out_data); + + if (ACPI_FAILURE(status)) + return -EIO; + + if (out_data == WMAX_FAILURE_CODE) + return -EBADRQC; + + return 0; +} + +static int wmax_game_shift_status(u8 operation, u32 *out_data) +{ + acpi_status status; + struct wmax_u32_args in_args = { + .operation = operation, + .arg1 = 0, + .arg2 = 0, + .arg3 = 0, + }; + + status = alienware_wmax_command(&in_args, sizeof(in_args), + WMAX_METHOD_GAME_SHIFT_STATUS, + out_data); + + if (ACPI_FAILURE(status)) + return -EIO; + + if (*out_data == WMAX_FAILURE_CODE) + return -EOPNOTSUPP; + + return 0; +} + +static int thermal_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) +{ + u32 out_data; + int ret; + + ret = wmax_thermal_information(WMAX_OPERATION_CURRENT_PROFILE, + 0, &out_data); + + if (ret < 0) + return ret; + + if (out_data == WMAX_THERMAL_MODE_GMODE) { + *profile = PLATFORM_PROFILE_PERFORMANCE; + return 0; + } + + if (!is_wmax_thermal_code(out_data)) + return -ENODATA; + + out_data &= WMAX_THERMAL_MODE_MASK; + *profile = wmax_mode_to_platform_profile[out_data]; + + return 0; +} + +static int thermal_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) +{ + if (quirks->gmode) { + u32 gmode_status; + int ret; + + ret = wmax_game_shift_status(WMAX_OPERATION_GET_GAME_SHIFT_STATUS, + &gmode_status); + + if (ret < 0) + return ret; + + if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) || + (profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) { + ret = wmax_game_shift_status(WMAX_OPERATION_TOGGLE_GAME_SHIFT, + &gmode_status); + + if (ret < 0) + return ret; + } + } + + return wmax_thermal_control(supported_thermal_profiles[profile]); +} + +static int create_thermal_profile(void) +{ + u32 out_data; + u8 sys_desc[4]; + u32 first_mode; + enum wmax_thermal_mode mode; + enum platform_profile_option profile; + int ret; + + ret = wmax_thermal_information(WMAX_OPERATION_SYS_DESCRIPTION, + 0, (u32 *) &sys_desc); + if (ret < 0) + return ret; + + first_mode = sys_desc[0] + sys_desc[1]; + + for (u32 i = 0; i < sys_desc[3]; i++) { + ret = wmax_thermal_information(WMAX_OPERATION_LIST_IDS, + i + first_mode, &out_data); + + if (ret == -EIO) + return ret; + + if (ret == -EBADRQC) + break; + + if (!is_wmax_thermal_code(out_data)) + continue; + + mode = out_data & WMAX_THERMAL_MODE_MASK; + profile = wmax_mode_to_platform_profile[mode]; + supported_thermal_profiles[profile] = out_data; + + set_bit(profile, pp_handler.choices); + } + + if (bitmap_empty(pp_handler.choices, PLATFORM_PROFILE_LAST)) + return -ENODEV; + + if (quirks->gmode) { + supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] = + WMAX_THERMAL_MODE_GMODE; + + set_bit(PLATFORM_PROFILE_PERFORMANCE, pp_handler.choices); + } + + pp_handler.profile_get = thermal_profile_get; + pp_handler.profile_set = thermal_profile_set; + + return platform_profile_register(&pp_handler); +} + +static void remove_thermal_profile(void) +{ + if (quirks->thermal) + platform_profile_remove(); +} + static int __init alienware_wmi_init(void) { int ret; @@ -777,6 +1195,16 @@ static int __init alienware_wmi_init(void) if (quirks == NULL) quirks = &quirk_unknown; + if (force_platform_profile) + quirks->thermal = true; + + if (force_gmode) { + if (quirks->thermal) + quirks->gmode = true; + else + pr_warn("force_gmode requires platform profile support\n"); + } + ret = platform_driver_register(&platform_driver); if (ret) goto fail_platform_driver; @@ -807,14 +1235,24 @@ static int __init alienware_wmi_init(void) goto fail_prep_deepsleep; } - ret = alienware_zone_init(platform_device); - if (ret) - goto fail_prep_zones; + if (quirks->thermal) { + ret = create_thermal_profile(); + if (ret) + goto fail_prep_thermal_profile; + } + + if (quirks->num_zones > 0) { + ret = alienware_zone_init(platform_device); + if (ret) + goto fail_prep_zones; + } return 0; fail_prep_zones: alienware_zone_exit(platform_device); + remove_thermal_profile(); +fail_prep_thermal_profile: fail_prep_deepsleep: fail_prep_amplifier: fail_prep_hdmi: @@ -834,6 +1272,7 @@ static void __exit alienware_wmi_exit(void) if (platform_device) { alienware_zone_exit(platform_device); remove_hdmi(platform_device); + remove_thermal_profile(); platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); } diff --git a/drivers/platform/x86/dell/dcdbas.c b/drivers/platform/x86/dell/dcdbas.c index a60e350563875f..0aeb8149c16bfc 100644 --- a/drivers/platform/x86/dell/dcdbas.c +++ b/drivers/platform/x86/dell/dcdbas.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -132,14 +133,14 @@ static ssize_t smi_data_buf_phys_addr_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%x\n", (u32)smi_buf.dma); + return sysfs_emit(buf, "%x\n", (u32)smi_buf.dma); } static ssize_t smi_data_buf_size_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%lu\n", smi_buf.size); + return sysfs_emit(buf, "%lu\n", smi_buf.size); } static ssize_t smi_data_buf_size_store(struct device *dev, @@ -200,7 +201,7 @@ static ssize_t host_control_action_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", host_control_action); + return sysfs_emit(buf, "%u\n", host_control_action); } static ssize_t host_control_action_store(struct device *dev, @@ -224,7 +225,7 @@ static ssize_t host_control_smi_type_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", host_control_smi_type); + return sysfs_emit(buf, "%u\n", host_control_smi_type); } static ssize_t host_control_smi_type_store(struct device *dev, @@ -239,7 +240,7 @@ static ssize_t host_control_on_shutdown_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%u\n", host_control_on_shutdown); + return sysfs_emit(buf, "%u\n", host_control_on_shutdown); } static ssize_t host_control_on_shutdown_store(struct device *dev, @@ -709,7 +710,7 @@ static struct platform_driver dcdbas_driver = { .name = DRIVER_NAME, }, .probe = dcdbas_probe, - .remove_new = dcdbas_remove, + .remove = dcdbas_remove, }; static const struct platform_device_info dcdbas_dev_info __initconst = { diff --git a/drivers/platform/x86/dell/dell-smo8800.c b/drivers/platform/x86/dell/dell-smo8800.c index f7ec17c5683321..87fe03f23f2409 100644 --- a/drivers/platform/x86/dell/dell-smo8800.c +++ b/drivers/platform/x86/dell/dell-smo8800.c @@ -179,7 +179,7 @@ MODULE_DEVICE_TABLE(acpi, smo8800_ids); static struct platform_driver smo8800_driver = { .probe = smo8800_probe, - .remove_new = smo8800_remove, + .remove = smo8800_remove, .driver = { .name = DRIVER_NAME, .acpi_match_table = smo8800_ids, diff --git a/drivers/platform/x86/dell/dell-uart-backlight.c b/drivers/platform/x86/dell/dell-uart-backlight.c index 3995f90add4568..6e5dc7e3674f5a 100644 --- a/drivers/platform/x86/dell/dell-uart-backlight.c +++ b/drivers/platform/x86/dell/dell-uart-backlight.c @@ -393,7 +393,7 @@ static void dell_uart_bl_pdev_remove(struct platform_device *pdev) static struct platform_driver dell_uart_bl_pdev_driver = { .probe = dell_uart_bl_pdev_probe, - .remove_new = dell_uart_bl_pdev_remove, + .remove = dell_uart_bl_pdev_remove, .driver = { .name = "dell-uart-backlight", }, diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 03319a80e11408..f52fbc4924d4ee 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -285,7 +286,7 @@ static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf) if (value < 0) return -EIO; - return sprintf(buf, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } #define EEEPC_ACPI_SHOW_FUNC(_name, _cm) \ @@ -361,7 +362,7 @@ static ssize_t cpufv_show(struct device *dev, if (get_cpufv(eeepc, &c)) return -ENODEV; - return sprintf(buf, "%#x\n", (c.num << 8) | c.cur); + return sysfs_emit(buf, "%#x\n", (c.num << 8) | c.cur); } static ssize_t cpufv_store(struct device *dev, @@ -393,7 +394,7 @@ static ssize_t cpufv_disabled_show(struct device *dev, { struct eeepc_laptop *eeepc = dev_get_drvdata(dev); - return sprintf(buf, "%d\n", eeepc->cpufv_disabled); + return sysfs_emit(buf, "%d\n", eeepc->cpufv_disabled); } static ssize_t cpufv_disabled_store(struct device *dev, @@ -1025,7 +1026,7 @@ static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) static ssize_t show_sys_hwmon(int (*get)(void), char *buf) { - return sprintf(buf, "%d\n", get()); + return sysfs_emit(buf, "%d\n", get()); } #define EEEPC_SENSOR_SHOW_FUNC(_name, _get) \ diff --git a/drivers/platform/x86/hp/Kconfig b/drivers/platform/x86/hp/Kconfig index d776761cd5fda6..dd51491b9bcd8a 100644 --- a/drivers/platform/x86/hp/Kconfig +++ b/drivers/platform/x86/hp/Kconfig @@ -37,6 +37,7 @@ config HP_ACCEL config HP_WMI tristate "HP WMI extras" default m + depends on ACPI_EC depends on ACPI_WMI depends on INPUT depends on RFKILL || RFKILL = n diff --git a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c index 35936c05e45b9c..187b372123ed39 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c @@ -531,14 +531,9 @@ void hp_exit_password_attributes(void) struct kobject *attr_name_kobj = bioscfg_drv.password_data[instance_id].attr_name_kobj; - if (attr_name_kobj) { - if (!strcmp(attr_name_kobj->name, SETUP_PASSWD)) - sysfs_remove_group(attr_name_kobj, - &password_attr_group); - else - sysfs_remove_group(attr_name_kobj, - &password_attr_group); - } + if (attr_name_kobj) + sysfs_remove_group(attr_name_kobj, + &password_attr_group); } bioscfg_drv.password_instances_count = 0; kfree(bioscfg_drv.password_data); diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 8c05e0dd2a218e..81ccc96ffe40a3 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -1748,7 +1748,7 @@ static struct platform_driver hp_wmi_driver __refdata = { .pm = &hp_wmi_pm_ops, .dev_groups = hp_wmi_groups, }, - .remove_new = __exit_p(hp_wmi_bios_remove), + .remove = __exit_p(hp_wmi_bios_remove), }; static umode_t hp_wmi_hwmon_is_visible(const void *data, diff --git a/drivers/platform/x86/hp/hp_accel.c b/drivers/platform/x86/hp/hp_accel.c index 52535576772ad8..39a6530f5072ba 100644 --- a/drivers/platform/x86/hp/hp_accel.c +++ b/drivers/platform/x86/hp/hp_accel.c @@ -372,7 +372,7 @@ static SIMPLE_DEV_PM_OPS(hp_accel_pm, lis3lv02d_suspend, lis3lv02d_resume); /* For the HP MDPS aka 3D Driveguard */ static struct platform_driver lis3lv02d_driver = { .probe = lis3lv02d_probe, - .remove_new = lis3lv02d_remove, + .remove = lis3lv02d_remove, .driver = { .name = "hp_accel", .pm = &hp_accel_pm, diff --git a/drivers/platform/x86/hp/tc1100-wmi.c b/drivers/platform/x86/hp/tc1100-wmi.c index 5298b0f6804f01..146716d8144234 100644 --- a/drivers/platform/x86/hp/tc1100-wmi.c +++ b/drivers/platform/x86/hp/tc1100-wmi.c @@ -221,7 +221,7 @@ static struct platform_driver tc1100_driver = { .pm = &tc1100_pm_ops, #endif }, - .remove_new = tc1100_remove, + .remove = tc1100_remove, }; static int __init tc1100_init(void) diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index d81fd5df4a000b..c3772df34679f5 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -842,7 +842,7 @@ static struct platform_driver huawei_wmi_driver = { .name = "huawei-wmi", }, .probe = huawei_wmi_probe, - .remove_new = huawei_wmi_remove, + .remove = huawei_wmi_remove, }; static __init int huawei_wmi_init(void) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index c908f52ed717b1..e980dd18e5f6ca 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1826,19 +1826,19 @@ int ideapad_laptop_register_notifier(struct notifier_block *nb) { return blocking_notifier_chain_register(&ideapad_laptop_chain_head, nb); } -EXPORT_SYMBOL_NS_GPL(ideapad_laptop_register_notifier, IDEAPAD_LAPTOP); +EXPORT_SYMBOL_NS_GPL(ideapad_laptop_register_notifier, "IDEAPAD_LAPTOP"); int ideapad_laptop_unregister_notifier(struct notifier_block *nb) { return blocking_notifier_chain_unregister(&ideapad_laptop_chain_head, nb); } -EXPORT_SYMBOL_NS_GPL(ideapad_laptop_unregister_notifier, IDEAPAD_LAPTOP); +EXPORT_SYMBOL_NS_GPL(ideapad_laptop_unregister_notifier, "IDEAPAD_LAPTOP"); void ideapad_laptop_call_notifier(unsigned long action, void *data) { blocking_notifier_call_chain(&ideapad_laptop_chain_head, action, data); } -EXPORT_SYMBOL_NS_GPL(ideapad_laptop_call_notifier, IDEAPAD_LAPTOP); +EXPORT_SYMBOL_NS_GPL(ideapad_laptop_call_notifier, "IDEAPAD_LAPTOP"); static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) { @@ -2309,7 +2309,7 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); static struct platform_driver ideapad_acpi_driver = { .probe = ideapad_acpi_add, - .remove_new = ideapad_acpi_remove, + .remove = ideapad_acpi_remove, .driver = { .name = "ideapad_acpi", .pm = &ideapad_pm, diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index ad50bbabec615c..eb698dcb9af91e 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -62,7 +62,7 @@ config INTEL_INT0002_VGPIO config INTEL_OAKTRAIL tristate "Intel Oaktrail Platform Extras" - depends on ACPI + depends on ACPI_EC depends on ACPI_VIDEO || ACPI_VIDEO=n depends on RFKILL && BACKLIGHT_CLASS_DEVICE && ACPI help diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 74db065c82d61c..78acb414e1540d 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -17,50 +17,40 @@ obj-$(CONFIG_INTEL_UNCORE_FREQ_CONTROL) += uncore-frequency/ # Intel input drivers -intel-hid-y := hid.o -obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o -intel-vbtn-y := vbtn.o -obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o +intel-target-$(CONFIG_INTEL_HID_EVENT) += hid.o +intel-target-$(CONFIG_INTEL_VBTN) += vbtn.o # Intel miscellaneous drivers -obj-$(CONFIG_INTEL_ISHTP_ECLITE) += ishtp_eclite.o -intel_int0002_vgpio-y := int0002_vgpio.o -obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o -intel_oaktrail-y := oaktrail.o -obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o -intel_sdsi-y := sdsi.o -obj-$(CONFIG_INTEL_SDSI) += intel_sdsi.o -intel_vsec-y := vsec.o -obj-$(CONFIG_INTEL_VSEC) += intel_vsec.o +intel-target-$(CONFIG_INTEL_INT0002_VGPIO) += int0002_vgpio.o +intel-target-$(CONFIG_INTEL_ISHTP_ECLITE) += ishtp_eclite.o +intel-target-$(CONFIG_INTEL_OAKTRAIL) += oaktrail.o +intel-target-$(CONFIG_INTEL_SDSI) += sdsi.o +intel-target-$(CONFIG_INTEL_VSEC) += vsec.o # Intel PMIC / PMC / P-Unit drivers -intel_bxtwc_tmu-y := bxtwc_tmu.o -obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o -intel_crystal_cove_charger-y := crystal_cove_charger.o -obj-$(CONFIG_X86_ANDROID_TABLETS) += intel_crystal_cove_charger.o -intel_bytcrc_pwrsrc-y := bytcrc_pwrsrc.o -obj-$(CONFIG_INTEL_BYTCRC_PWRSRC) += intel_bytcrc_pwrsrc.o -intel_chtdc_ti_pwrbtn-y := chtdc_ti_pwrbtn.o -obj-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += intel_chtdc_ti_pwrbtn.o -intel_chtwc_int33fe-y := chtwc_int33fe.o -obj-$(CONFIG_INTEL_CHTWC_INT33FE) += intel_chtwc_int33fe.o -intel_mrfld_pwrbtn-y := mrfld_pwrbtn.o -obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o -intel_punit_ipc-y := punit_ipc.o -obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o +intel-target-$(CONFIG_INTEL_BYTCRC_PWRSRC) += bytcrc_pwrsrc.o +intel-target-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += bxtwc_tmu.o +intel-target-$(CONFIG_INTEL_CHTDC_TI_PWRBTN) += chtdc_ti_pwrbtn.o +intel-target-$(CONFIG_INTEL_CHTWC_INT33FE) += chtwc_int33fe.o +intel-target-$(CONFIG_X86_ANDROID_TABLETS) += crystal_cove_charger.o +intel-target-$(CONFIG_INTEL_MRFLD_PWRBTN) += mrfld_pwrbtn.o +intel-target-$(CONFIG_INTEL_PUNIT_IPC) += punit_ipc.o # TPMI drivers -intel_vsec_tpmi-y := tpmi.o -obj-$(CONFIG_INTEL_TPMI) += intel_vsec_tpmi.o -obj-$(CONFIG_INTEL_PLR_TPMI) += intel_plr_tpmi.o - -intel_tpmi_power_domains-y := tpmi_power_domains.o -obj-$(CONFIG_INTEL_TPMI_POWER_DOMAINS) += intel_tpmi_power_domains.o +intel-target-$(CONFIG_INTEL_PLR_TPMI) += plr_tpmi.o +intel-target-$(CONFIG_INTEL_TPMI_POWER_DOMAINS) += tpmi_power_domains.o +intel-target-$(CONFIG_INTEL_TPMI) += vsec_tpmi.o # Intel Uncore drivers -intel-rst-y := rst.o -obj-$(CONFIG_INTEL_RST) += intel-rst.o -intel-smartconnect-y := smartconnect.o -obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o -intel_turbo_max_3-y := turbo_max_3.o -obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o +intel-target-$(CONFIG_INTEL_RST) += rst.o +intel-target-$(CONFIG_INTEL_SMARTCONNECT) += smartconnect.o +intel-target-$(CONFIG_INTEL_TURBO_MAX_3) += turbo_max_3.o + +# Add 'intel' prefix to each module listed in intel-target-* +define INTEL_OBJ_TARGET +intel-$(1)-y := $(1).o +obj-$(2) += intel-$(1).o +endef + +$(foreach target, $(basename $(intel-target-y)), $(eval $(call INTEL_OBJ_TARGET,$(target),y))) +$(foreach target, $(basename $(intel-target-m)), $(eval $(call INTEL_OBJ_TARGET,$(target),m))) diff --git a/drivers/platform/x86/intel/bxtwc_tmu.c b/drivers/platform/x86/intel/bxtwc_tmu.c index d0e2a3c293b0b0..99437b2ccc25aa 100644 --- a/drivers/platform/x86/intel/bxtwc_tmu.c +++ b/drivers/platform/x86/intel/bxtwc_tmu.c @@ -48,9 +48,8 @@ static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data) static int bxt_wcove_tmu_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); - struct regmap_irq_chip_data *regmap_irq_chip; struct wcove_tmu *wctmu; - int ret, virq, irq; + int ret; wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL); if (!wctmu) @@ -59,27 +58,18 @@ static int bxt_wcove_tmu_probe(struct platform_device *pdev) wctmu->dev = &pdev->dev; wctmu->regmap = pmic->regmap; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + wctmu->irq = platform_get_irq(pdev, 0); + if (wctmu->irq < 0) + return wctmu->irq; - regmap_irq_chip = pmic->irq_chip_data_tmu; - virq = regmap_irq_get_virq(regmap_irq_chip, irq); - if (virq < 0) { - dev_err(&pdev->dev, - "failed to get virtual interrupt=%d\n", irq); - return virq; - } - - ret = devm_request_threaded_irq(&pdev->dev, virq, + ret = devm_request_threaded_irq(&pdev->dev, wctmu->irq, NULL, bxt_wcove_tmu_irq_handler, IRQF_ONESHOT, "bxt_wcove_tmu", wctmu); if (ret) { dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n", - ret, virq); + ret, wctmu->irq); return ret; } - wctmu->irq = virq; /* Unmask TMU second level Wake & System alarm */ regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG, @@ -131,7 +121,7 @@ MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table); static struct platform_driver bxt_wcove_tmu_driver = { .probe = bxt_wcove_tmu_probe, - .remove_new = bxt_wcove_tmu_remove, + .remove = bxt_wcove_tmu_remove, .driver = { .name = "bxt_wcove_tmu", .pm = &bxtwc_tmu_pm_ops, diff --git a/drivers/platform/x86/intel/bytcrc_pwrsrc.c b/drivers/platform/x86/intel/bytcrc_pwrsrc.c index 418b71af27ff52..3edc2a9dab388d 100644 --- a/drivers/platform/x86/intel/bytcrc_pwrsrc.c +++ b/drivers/platform/x86/intel/bytcrc_pwrsrc.c @@ -167,7 +167,7 @@ static void crc_pwrsrc_remove(struct platform_device *pdev) static struct platform_driver crc_pwrsrc_driver = { .probe = crc_pwrsrc_probe, - .remove_new = crc_pwrsrc_remove, + .remove = crc_pwrsrc_remove, .driver = { .name = "crystal_cove_pwrsrc", }, diff --git a/drivers/platform/x86/intel/chtdc_ti_pwrbtn.c b/drivers/platform/x86/intel/chtdc_ti_pwrbtn.c index 615f8d1a0c687b..53f01e19804728 100644 --- a/drivers/platform/x86/intel/chtdc_ti_pwrbtn.c +++ b/drivers/platform/x86/intel/chtdc_ti_pwrbtn.c @@ -84,7 +84,7 @@ static struct platform_driver chtdc_ti_pwrbtn_driver = { .name = KBUILD_MODNAME, }, .probe = chtdc_ti_pwrbtn_probe, - .remove_new = chtdc_ti_pwrbtn_remove, + .remove = chtdc_ti_pwrbtn_remove, .id_table = chtdc_ti_pwrbtn_id_table, }; module_platform_driver(chtdc_ti_pwrbtn_driver); diff --git a/drivers/platform/x86/intel/chtwc_int33fe.c b/drivers/platform/x86/intel/chtwc_int33fe.c index 11503b1c85f3fb..29e8b5432f4c9e 100644 --- a/drivers/platform/x86/intel/chtwc_int33fe.c +++ b/drivers/platform/x86/intel/chtwc_int33fe.c @@ -427,7 +427,7 @@ static struct platform_driver cht_int33fe_typec_driver = { .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids), }, .probe = cht_int33fe_typec_probe, - .remove_new = cht_int33fe_typec_remove, + .remove = cht_int33fe_typec_remove, }; module_platform_driver(cht_int33fe_typec_driver); diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c index 445e7a59beb414..927a2993f61606 100644 --- a/drivers/platform/x86/intel/hid.c +++ b/drivers/platform/x86/intel/hid.c @@ -118,6 +118,13 @@ static const struct dmi_system_id button_array_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x2 Detachable"), }, }, + { + .ident = "Lenovo ThinkPad X1 Tablet Gen 1", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X12 Detachable Gen 1"), + }, + }, { .ident = "Lenovo ThinkPad X1 Tablet Gen 2", .matches = { @@ -747,7 +754,7 @@ static struct platform_driver intel_hid_pl_driver = { .pm = &intel_hid_pl_pm_ops, }, .probe = intel_hid_probe, - .remove_new = intel_hid_remove, + .remove = intel_hid_remove, }; /* diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c index bc252b883210a5..1ae50702bdb760 100644 --- a/drivers/platform/x86/intel/ifs/core.c +++ b/drivers/platform/x86/intel/ifs/core.c @@ -20,6 +20,7 @@ static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { X86_MATCH(INTEL_GRANITERAPIDS_X, ARRAY_GEN0), X86_MATCH(INTEL_GRANITERAPIDS_D, ARRAY_GEN0), X86_MATCH(INTEL_ATOM_CRESTMONT_X, ARRAY_GEN1), + X86_MATCH(INTEL_ATOM_DARKMONT_X, ARRAY_GEN1), {} }; MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); diff --git a/drivers/platform/x86/intel/int0002_vgpio.c b/drivers/platform/x86/intel/int0002_vgpio.c index 527d8fbc7cc110..0cc80603a8a9dc 100644 --- a/drivers/platform/x86/intel/int0002_vgpio.c +++ b/drivers/platform/x86/intel/int0002_vgpio.c @@ -266,13 +266,13 @@ static const struct acpi_device_id int0002_acpi_ids[] = { MODULE_DEVICE_TABLE(acpi, int0002_acpi_ids); static struct platform_driver int0002_driver = { - .driver = { + .driver = { .name = DRV_NAME, .acpi_match_table = int0002_acpi_ids, .pm = &int0002_pm_ops, }, .probe = int0002_probe, - .remove_new = int0002_remove, + .remove = int0002_remove, }; module_platform_driver(int0002_driver); diff --git a/drivers/platform/x86/intel/int1092/intel_sar.c b/drivers/platform/x86/intel/int1092/intel_sar.c index 6246c066ade2bc..e526841aff603b 100644 --- a/drivers/platform/x86/intel/int1092/intel_sar.c +++ b/drivers/platform/x86/intel/int1092/intel_sar.c @@ -308,7 +308,7 @@ static void sar_remove(struct platform_device *device) static struct platform_driver sar_driver = { .probe = sar_probe, - .remove_new = sar_remove, + .remove = sar_remove, .driver = { .name = DRVNAME, .acpi_match_table = ACPI_PTR(sar_device_ids) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 3de463c3d13b8e..d881b2cfcdfcfb 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -392,7 +392,7 @@ static struct platform_driver int3472_discrete = { .acpi_match_table = int3472_device_id, }, .probe = skl_int3472_discrete_probe, - .remove_new = skl_int3472_discrete_remove, + .remove = skl_int3472_discrete_remove, }; module_platform_driver(int3472_discrete); diff --git a/drivers/platform/x86/intel/intel_plr_tpmi.c b/drivers/platform/x86/intel/intel_plr_tpmi.c deleted file mode 100644 index 69ace6a629bc79..00000000000000 --- a/drivers/platform/x86/intel/intel_plr_tpmi.c +++ /dev/null @@ -1,354 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Performance Limit Reasons via TPMI - * - * Copyright (c) 2024, Intel Corporation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tpmi_power_domains.h" - -#define PLR_HEADER 0x00 -#define PLR_MAILBOX_INTERFACE 0x08 -#define PLR_MAILBOX_DATA 0x10 -#define PLR_DIE_LEVEL 0x18 - -#define PLR_MODULE_ID_MASK GENMASK_ULL(19, 12) -#define PLR_RUN_BUSY BIT_ULL(63) - -#define PLR_COMMAND_WRITE 1 - -#define PLR_INVALID GENMASK_ULL(63, 0) - -#define PLR_TIMEOUT_US 5 -#define PLR_TIMEOUT_MAX_US 1000 - -#define PLR_COARSE_REASON_BITS 32 - -struct tpmi_plr; - -struct tpmi_plr_die { - void __iomem *base; - struct mutex lock; /* Protect access to PLR mailbox */ - int package_id; - int die_id; - struct tpmi_plr *plr; -}; - -struct tpmi_plr { - struct dentry *dbgfs_dir; - struct tpmi_plr_die *die_info; - int num_dies; - struct auxiliary_device *auxdev; -}; - -static const char * const plr_coarse_reasons[] = { - "FREQUENCY", - "CURRENT", - "POWER", - "THERMAL", - "PLATFORM", - "MCP", - "RAS", - "MISC", - "QOS", - "DFC", -}; - -static const char * const plr_fine_reasons[] = { - "FREQUENCY_CDYN0", - "FREQUENCY_CDYN1", - "FREQUENCY_CDYN2", - "FREQUENCY_CDYN3", - "FREQUENCY_CDYN4", - "FREQUENCY_CDYN5", - "FREQUENCY_FCT", - "FREQUENCY_PCS_TRL", - "CURRENT_MTPMAX", - "POWER_FAST_RAPL", - "POWER_PKG_PL1_MSR_TPMI", - "POWER_PKG_PL1_MMIO", - "POWER_PKG_PL1_PCS", - "POWER_PKG_PL2_MSR_TPMI", - "POWER_PKG_PL2_MMIO", - "POWER_PKG_PL2_PCS", - "POWER_PLATFORM_PL1_MSR_TPMI", - "POWER_PLATFORM_PL1_MMIO", - "POWER_PLATFORM_PL1_PCS", - "POWER_PLATFORM_PL2_MSR_TPMI", - "POWER_PLATFORM_PL2_MMIO", - "POWER_PLATFORM_PL2_PCS", - "UNKNOWN(22)", - "THERMAL_PER_CORE", - "DFC_UFS", - "PLATFORM_PROCHOT", - "PLATFORM_HOT_VR", - "UNKNOWN(27)", - "UNKNOWN(28)", - "MISC_PCS_PSTATE", -}; - -static u64 plr_read(struct tpmi_plr_die *plr_die, int offset) -{ - return readq(plr_die->base + offset); -} - -static void plr_write(u64 val, struct tpmi_plr_die *plr_die, int offset) -{ - writeq(val, plr_die->base + offset); -} - -static int plr_read_cpu_status(struct tpmi_plr_die *plr_die, int cpu, - u64 *status) -{ - u64 regval; - int ret; - - lockdep_assert_held(&plr_die->lock); - - regval = FIELD_PREP(PLR_MODULE_ID_MASK, tpmi_get_punit_core_number(cpu)); - regval |= PLR_RUN_BUSY; - - plr_write(regval, plr_die, PLR_MAILBOX_INTERFACE); - - ret = readq_poll_timeout(plr_die->base + PLR_MAILBOX_INTERFACE, regval, - !(regval & PLR_RUN_BUSY), PLR_TIMEOUT_US, - PLR_TIMEOUT_MAX_US); - if (ret) - return ret; - - *status = plr_read(plr_die, PLR_MAILBOX_DATA); - - return 0; -} - -static int plr_clear_cpu_status(struct tpmi_plr_die *plr_die, int cpu) -{ - u64 regval; - - lockdep_assert_held(&plr_die->lock); - - regval = FIELD_PREP(PLR_MODULE_ID_MASK, tpmi_get_punit_core_number(cpu)); - regval |= PLR_RUN_BUSY | PLR_COMMAND_WRITE; - - plr_write(0, plr_die, PLR_MAILBOX_DATA); - - plr_write(regval, plr_die, PLR_MAILBOX_INTERFACE); - - return readq_poll_timeout(plr_die->base + PLR_MAILBOX_INTERFACE, regval, - !(regval & PLR_RUN_BUSY), PLR_TIMEOUT_US, - PLR_TIMEOUT_MAX_US); -} - -static void plr_print_bits(struct seq_file *s, u64 val, int bits) -{ - const unsigned long mask[] = { BITMAP_FROM_U64(val) }; - int bit, index; - - for_each_set_bit(bit, mask, bits) { - const char *str = NULL; - - if (bit < PLR_COARSE_REASON_BITS) { - if (bit < ARRAY_SIZE(plr_coarse_reasons)) - str = plr_coarse_reasons[bit]; - } else { - index = bit - PLR_COARSE_REASON_BITS; - if (index < ARRAY_SIZE(plr_fine_reasons)) - str = plr_fine_reasons[index]; - } - - if (str) - seq_printf(s, " %s", str); - else - seq_printf(s, " UNKNOWN(%d)", bit); - } - - if (!val) - seq_puts(s, " none"); - - seq_putc(s, '\n'); -} - -static int plr_status_show(struct seq_file *s, void *unused) -{ - struct tpmi_plr_die *plr_die = s->private; - int ret; - u64 val; - - val = plr_read(plr_die, PLR_DIE_LEVEL); - seq_puts(s, "cpus"); - plr_print_bits(s, val, 32); - - guard(mutex)(&plr_die->lock); - - for (int cpu = 0; cpu < nr_cpu_ids; cpu++) { - if (plr_die->die_id != tpmi_get_power_domain_id(cpu)) - continue; - - if (plr_die->package_id != topology_physical_package_id(cpu)) - continue; - - seq_printf(s, "cpu%d", cpu); - ret = plr_read_cpu_status(plr_die, cpu, &val); - if (ret) { - dev_err(&plr_die->plr->auxdev->dev, "Failed to read PLR for cpu %d, ret=%d\n", - cpu, ret); - return ret; - } - - plr_print_bits(s, val, 64); - } - - return 0; -} - -static ssize_t plr_status_write(struct file *filp, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct seq_file *s = filp->private_data; - struct tpmi_plr_die *plr_die = s->private; - bool val; - int ret; - - ret = kstrtobool_from_user(ubuf, count, &val); - if (ret) - return ret; - - if (val != 0) - return -EINVAL; - - plr_write(0, plr_die, PLR_DIE_LEVEL); - - guard(mutex)(&plr_die->lock); - - for (int cpu = 0; cpu < nr_cpu_ids; cpu++) { - if (plr_die->die_id != tpmi_get_power_domain_id(cpu)) - continue; - - if (plr_die->package_id != topology_physical_package_id(cpu)) - continue; - - plr_clear_cpu_status(plr_die, cpu); - } - - return count; -} -DEFINE_SHOW_STORE_ATTRIBUTE(plr_status); - -static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id) -{ - struct intel_tpmi_plat_info *plat_info; - struct dentry *dentry; - int i, num_resources; - struct resource *res; - struct tpmi_plr *plr; - void __iomem *base; - char name[16]; - int err; - - plat_info = tpmi_get_platform_data(auxdev); - if (!plat_info) - return dev_err_probe(&auxdev->dev, -EINVAL, "No platform info\n"); - - dentry = tpmi_get_debugfs_dir(auxdev); - if (!dentry) - return dev_err_probe(&auxdev->dev, -ENODEV, "No TPMI debugfs directory.\n"); - - num_resources = tpmi_get_resource_count(auxdev); - if (!num_resources) - return -EINVAL; - - plr = devm_kzalloc(&auxdev->dev, sizeof(*plr), GFP_KERNEL); - if (!plr) - return -ENOMEM; - - plr->die_info = devm_kcalloc(&auxdev->dev, num_resources, sizeof(*plr->die_info), - GFP_KERNEL); - if (!plr->die_info) - return -ENOMEM; - - plr->num_dies = num_resources; - plr->dbgfs_dir = debugfs_create_dir("plr", dentry); - plr->auxdev = auxdev; - - for (i = 0; i < num_resources; i++) { - res = tpmi_get_resource_at_index(auxdev, i); - if (!res) { - err = dev_err_probe(&auxdev->dev, -EINVAL, "No resource\n"); - goto err; - } - - base = devm_ioremap_resource(&auxdev->dev, res); - if (IS_ERR(base)) { - err = PTR_ERR(base); - goto err; - } - - plr->die_info[i].base = base; - plr->die_info[i].package_id = plat_info->package_id; - plr->die_info[i].die_id = i; - plr->die_info[i].plr = plr; - mutex_init(&plr->die_info[i].lock); - - if (plr_read(&plr->die_info[i], PLR_HEADER) == PLR_INVALID) - continue; - - snprintf(name, sizeof(name), "domain%d", i); - - dentry = debugfs_create_dir(name, plr->dbgfs_dir); - debugfs_create_file("status", 0444, dentry, &plr->die_info[i], - &plr_status_fops); - } - - auxiliary_set_drvdata(auxdev, plr); - - return 0; - -err: - debugfs_remove_recursive(plr->dbgfs_dir); - return err; -} - -static void intel_plr_remove(struct auxiliary_device *auxdev) -{ - struct tpmi_plr *plr = auxiliary_get_drvdata(auxdev); - - debugfs_remove_recursive(plr->dbgfs_dir); -} - -static const struct auxiliary_device_id intel_plr_id_table[] = { - { .name = "intel_vsec.tpmi-plr" }, - {} -}; -MODULE_DEVICE_TABLE(auxiliary, intel_plr_id_table); - -static struct auxiliary_driver intel_plr_aux_driver = { - .id_table = intel_plr_id_table, - .remove = intel_plr_remove, - .probe = intel_plr_probe, -}; -module_auxiliary_driver(intel_plr_aux_driver); - -MODULE_IMPORT_NS(INTEL_TPMI); -MODULE_IMPORT_NS(INTEL_TPMI_POWER_DOMAIN); -MODULE_DESCRIPTION("Intel TPMI PLR Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel/mrfld_pwrbtn.c b/drivers/platform/x86/intel/mrfld_pwrbtn.c index 549a3f586f3bcf..6c43f801c4673f 100644 --- a/drivers/platform/x86/intel/mrfld_pwrbtn.c +++ b/drivers/platform/x86/intel/mrfld_pwrbtn.c @@ -97,7 +97,7 @@ static struct platform_driver mrfld_pwrbtn_driver = { .name = "mrfld_bcove_pwrbtn", }, .probe = mrfld_pwrbtn_probe, - .remove_new = mrfld_pwrbtn_remove, + .remove = mrfld_pwrbtn_remove, .id_table = mrfld_pwrbtn_id_table, }; module_platform_driver(mrfld_pwrbtn_driver); diff --git a/drivers/platform/x86/intel/plr_tpmi.c b/drivers/platform/x86/intel/plr_tpmi.c new file mode 100644 index 00000000000000..691d43c3592c27 --- /dev/null +++ b/drivers/platform/x86/intel/plr_tpmi.c @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Performance Limit Reasons via TPMI + * + * Copyright (c) 2024, Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tpmi_power_domains.h" + +#define PLR_HEADER 0x00 +#define PLR_MAILBOX_INTERFACE 0x08 +#define PLR_MAILBOX_DATA 0x10 +#define PLR_DIE_LEVEL 0x18 + +#define PLR_MODULE_ID_MASK GENMASK_ULL(19, 12) +#define PLR_RUN_BUSY BIT_ULL(63) + +#define PLR_COMMAND_WRITE 1 + +#define PLR_INVALID GENMASK_ULL(63, 0) + +#define PLR_TIMEOUT_US 5 +#define PLR_TIMEOUT_MAX_US 1000 + +#define PLR_COARSE_REASON_BITS 32 + +struct tpmi_plr; + +struct tpmi_plr_die { + void __iomem *base; + struct mutex lock; /* Protect access to PLR mailbox */ + int package_id; + int die_id; + struct tpmi_plr *plr; +}; + +struct tpmi_plr { + struct dentry *dbgfs_dir; + struct tpmi_plr_die *die_info; + int num_dies; + struct auxiliary_device *auxdev; +}; + +static const char * const plr_coarse_reasons[] = { + "FREQUENCY", + "CURRENT", + "POWER", + "THERMAL", + "PLATFORM", + "MCP", + "RAS", + "MISC", + "QOS", + "DFC", +}; + +static const char * const plr_fine_reasons[] = { + "FREQUENCY_CDYN0", + "FREQUENCY_CDYN1", + "FREQUENCY_CDYN2", + "FREQUENCY_CDYN3", + "FREQUENCY_CDYN4", + "FREQUENCY_CDYN5", + "FREQUENCY_FCT", + "FREQUENCY_PCS_TRL", + "CURRENT_MTPMAX", + "POWER_FAST_RAPL", + "POWER_PKG_PL1_MSR_TPMI", + "POWER_PKG_PL1_MMIO", + "POWER_PKG_PL1_PCS", + "POWER_PKG_PL2_MSR_TPMI", + "POWER_PKG_PL2_MMIO", + "POWER_PKG_PL2_PCS", + "POWER_PLATFORM_PL1_MSR_TPMI", + "POWER_PLATFORM_PL1_MMIO", + "POWER_PLATFORM_PL1_PCS", + "POWER_PLATFORM_PL2_MSR_TPMI", + "POWER_PLATFORM_PL2_MMIO", + "POWER_PLATFORM_PL2_PCS", + "UNKNOWN(22)", + "THERMAL_PER_CORE", + "DFC_UFS", + "PLATFORM_PROCHOT", + "PLATFORM_HOT_VR", + "UNKNOWN(27)", + "UNKNOWN(28)", + "MISC_PCS_PSTATE", +}; + +static u64 plr_read(struct tpmi_plr_die *plr_die, int offset) +{ + return readq(plr_die->base + offset); +} + +static void plr_write(u64 val, struct tpmi_plr_die *plr_die, int offset) +{ + writeq(val, plr_die->base + offset); +} + +static int plr_read_cpu_status(struct tpmi_plr_die *plr_die, int cpu, + u64 *status) +{ + u64 regval; + int ret; + + lockdep_assert_held(&plr_die->lock); + + regval = FIELD_PREP(PLR_MODULE_ID_MASK, tpmi_get_punit_core_number(cpu)); + regval |= PLR_RUN_BUSY; + + plr_write(regval, plr_die, PLR_MAILBOX_INTERFACE); + + ret = readq_poll_timeout(plr_die->base + PLR_MAILBOX_INTERFACE, regval, + !(regval & PLR_RUN_BUSY), PLR_TIMEOUT_US, + PLR_TIMEOUT_MAX_US); + if (ret) + return ret; + + *status = plr_read(plr_die, PLR_MAILBOX_DATA); + + return 0; +} + +static int plr_clear_cpu_status(struct tpmi_plr_die *plr_die, int cpu) +{ + u64 regval; + + lockdep_assert_held(&plr_die->lock); + + regval = FIELD_PREP(PLR_MODULE_ID_MASK, tpmi_get_punit_core_number(cpu)); + regval |= PLR_RUN_BUSY | PLR_COMMAND_WRITE; + + plr_write(0, plr_die, PLR_MAILBOX_DATA); + + plr_write(regval, plr_die, PLR_MAILBOX_INTERFACE); + + return readq_poll_timeout(plr_die->base + PLR_MAILBOX_INTERFACE, regval, + !(regval & PLR_RUN_BUSY), PLR_TIMEOUT_US, + PLR_TIMEOUT_MAX_US); +} + +static void plr_print_bits(struct seq_file *s, u64 val, int bits) +{ + const unsigned long mask[] = { BITMAP_FROM_U64(val) }; + int bit, index; + + for_each_set_bit(bit, mask, bits) { + const char *str = NULL; + + if (bit < PLR_COARSE_REASON_BITS) { + if (bit < ARRAY_SIZE(plr_coarse_reasons)) + str = plr_coarse_reasons[bit]; + } else { + index = bit - PLR_COARSE_REASON_BITS; + if (index < ARRAY_SIZE(plr_fine_reasons)) + str = plr_fine_reasons[index]; + } + + if (str) + seq_printf(s, " %s", str); + else + seq_printf(s, " UNKNOWN(%d)", bit); + } + + if (!val) + seq_puts(s, " none"); + + seq_putc(s, '\n'); +} + +static int plr_status_show(struct seq_file *s, void *unused) +{ + struct tpmi_plr_die *plr_die = s->private; + int ret; + u64 val; + + val = plr_read(plr_die, PLR_DIE_LEVEL); + seq_puts(s, "cpus"); + plr_print_bits(s, val, 32); + + guard(mutex)(&plr_die->lock); + + for (int cpu = 0; cpu < nr_cpu_ids; cpu++) { + if (plr_die->die_id != tpmi_get_power_domain_id(cpu)) + continue; + + if (plr_die->package_id != topology_physical_package_id(cpu)) + continue; + + seq_printf(s, "cpu%d", cpu); + ret = plr_read_cpu_status(plr_die, cpu, &val); + if (ret) { + dev_err(&plr_die->plr->auxdev->dev, "Failed to read PLR for cpu %d, ret=%d\n", + cpu, ret); + return ret; + } + + plr_print_bits(s, val, 64); + } + + return 0; +} + +static ssize_t plr_status_write(struct file *filp, const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = filp->private_data; + struct tpmi_plr_die *plr_die = s->private; + bool val; + int ret; + + ret = kstrtobool_from_user(ubuf, count, &val); + if (ret) + return ret; + + if (val != 0) + return -EINVAL; + + plr_write(0, plr_die, PLR_DIE_LEVEL); + + guard(mutex)(&plr_die->lock); + + for (int cpu = 0; cpu < nr_cpu_ids; cpu++) { + if (plr_die->die_id != tpmi_get_power_domain_id(cpu)) + continue; + + if (plr_die->package_id != topology_physical_package_id(cpu)) + continue; + + plr_clear_cpu_status(plr_die, cpu); + } + + return count; +} +DEFINE_SHOW_STORE_ATTRIBUTE(plr_status); + +static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id) +{ + struct intel_tpmi_plat_info *plat_info; + struct dentry *dentry; + int i, num_resources; + struct resource *res; + struct tpmi_plr *plr; + void __iomem *base; + char name[16]; + int err; + + plat_info = tpmi_get_platform_data(auxdev); + if (!plat_info) + return dev_err_probe(&auxdev->dev, -EINVAL, "No platform info\n"); + + dentry = tpmi_get_debugfs_dir(auxdev); + if (!dentry) + return dev_err_probe(&auxdev->dev, -ENODEV, "No TPMI debugfs directory.\n"); + + num_resources = tpmi_get_resource_count(auxdev); + if (!num_resources) + return -EINVAL; + + plr = devm_kzalloc(&auxdev->dev, sizeof(*plr), GFP_KERNEL); + if (!plr) + return -ENOMEM; + + plr->die_info = devm_kcalloc(&auxdev->dev, num_resources, sizeof(*plr->die_info), + GFP_KERNEL); + if (!plr->die_info) + return -ENOMEM; + + plr->num_dies = num_resources; + plr->dbgfs_dir = debugfs_create_dir("plr", dentry); + plr->auxdev = auxdev; + + for (i = 0; i < num_resources; i++) { + res = tpmi_get_resource_at_index(auxdev, i); + if (!res) { + err = dev_err_probe(&auxdev->dev, -EINVAL, "No resource\n"); + goto err; + } + + base = devm_ioremap_resource(&auxdev->dev, res); + if (IS_ERR(base)) { + err = PTR_ERR(base); + goto err; + } + + plr->die_info[i].base = base; + plr->die_info[i].package_id = plat_info->package_id; + plr->die_info[i].die_id = i; + plr->die_info[i].plr = plr; + mutex_init(&plr->die_info[i].lock); + + if (plr_read(&plr->die_info[i], PLR_HEADER) == PLR_INVALID) + continue; + + snprintf(name, sizeof(name), "domain%d", i); + + dentry = debugfs_create_dir(name, plr->dbgfs_dir); + debugfs_create_file("status", 0444, dentry, &plr->die_info[i], + &plr_status_fops); + } + + auxiliary_set_drvdata(auxdev, plr); + + return 0; + +err: + debugfs_remove_recursive(plr->dbgfs_dir); + return err; +} + +static void intel_plr_remove(struct auxiliary_device *auxdev) +{ + struct tpmi_plr *plr = auxiliary_get_drvdata(auxdev); + + debugfs_remove_recursive(plr->dbgfs_dir); +} + +static const struct auxiliary_device_id intel_plr_id_table[] = { + { .name = "intel_vsec.tpmi-plr" }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, intel_plr_id_table); + +static struct auxiliary_driver intel_plr_aux_driver = { + .id_table = intel_plr_id_table, + .remove = intel_plr_remove, + .probe = intel_plr_probe, +}; +module_auxiliary_driver(intel_plr_aux_driver); + +MODULE_IMPORT_NS("INTEL_TPMI"); +MODULE_IMPORT_NS("INTEL_TPMI_POWER_DOMAIN"); +MODULE_DESCRIPTION("Intel TPMI PLR Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c index e10527c4e3e0d5..05dec4f5019f3b 100644 --- a/drivers/platform/x86/intel/pmc/arl.c +++ b/drivers/platform/x86/intel/pmc/arl.c @@ -687,9 +687,8 @@ static void arl_d3_fixup(void) static int arl_resume(struct pmc_dev *pmcdev) { arl_d3_fixup(); - pmc_core_send_ltr_ignore(pmcdev, 3, 0); - return pmc_core_resume_common(pmcdev); + return cnl_resume(pmcdev); } int arl_core_init(struct pmc_dev *pmcdev) diff --git a/drivers/platform/x86/intel/pmc/cnp.c b/drivers/platform/x86/intel/pmc/cnp.c index dd72974bf71e2a..fc5193fdf8a88a 100644 --- a/drivers/platform/x86/intel/pmc/cnp.c +++ b/drivers/platform/x86/intel/pmc/cnp.c @@ -8,6 +8,8 @@ * */ +#include +#include #include "core.h" /* Cannon Lake: PGD PFET Enable Ack Status Register(s) bitmap */ @@ -204,8 +206,57 @@ const struct pmc_reg_map cnp_reg_map = { .etr3_offset = ETR3_OFFSET, }; + +/* + * Disable C1 auto-demotion + * + * Aggressive C1 auto-demotion may lead to failure to enter the deepest C-state + * during suspend-to-idle, causing high power consumption. To prevent this, we + * disable C1 auto-demotion during suspend and re-enable on resume. + * + * Note that, although MSR_PKG_CST_CONFIG_CONTROL has 'package' in its name, it + * is actually a per-core MSR on client platforms, affecting only a single CPU. + * Therefore, it must be configured on all online CPUs. The online cpu mask is + * unchanged during the phase of suspend/resume as user space is frozen. + */ + +static DEFINE_PER_CPU(u64, pkg_cst_config); + +static void disable_c1_auto_demote(void *unused) +{ + int cpunum = smp_processor_id(); + u64 val; + + rdmsrl(MSR_PKG_CST_CONFIG_CONTROL, val); + per_cpu(pkg_cst_config, cpunum) = val; + val &= ~NHM_C1_AUTO_DEMOTE; + wrmsrl(MSR_PKG_CST_CONFIG_CONTROL, val); + + pr_debug("%s: cpu:%d cst %llx\n", __func__, cpunum, val); +} + +static void restore_c1_auto_demote(void *unused) +{ + int cpunum = smp_processor_id(); + + wrmsrl(MSR_PKG_CST_CONFIG_CONTROL, per_cpu(pkg_cst_config, cpunum)); + + pr_debug("%s: cpu:%d cst %llx\n", __func__, cpunum, + per_cpu(pkg_cst_config, cpunum)); +} + +static void s2idle_cpu_quirk(smp_call_func_t func) +{ + if (pm_suspend_via_firmware()) + return; + + on_each_cpu(func, NULL, true); +} + void cnl_suspend(struct pmc_dev *pmcdev) { + s2idle_cpu_quirk(disable_c1_auto_demote); + /* * Due to a hardware limitation, the GBE LTR blocks PC10 * when a cable is attached. To unblock PC10 during suspend, @@ -216,6 +267,8 @@ void cnl_suspend(struct pmc_dev *pmcdev) int cnl_resume(struct pmc_dev *pmcdev) { + s2idle_cpu_quirk(restore_c1_auto_demote); + pmc_core_send_ltr_ignore(pmcdev, 3, 0); return pmc_core_resume_common(pmcdev); diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 4e9c8c96c8ccee..3e7f99ac8c941e 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -1676,7 +1676,7 @@ static struct platform_driver pmc_core_driver = { .dev_groups = pmc_dev_groups, }, .probe = pmc_core_probe, - .remove_new = pmc_core_remove, + .remove = pmc_core_remove, }; module_platform_driver(pmc_core_driver); diff --git a/drivers/platform/x86/intel/pmc/core_ssram.c b/drivers/platform/x86/intel/pmc/core_ssram.c index 8504154b649f47..50ebfd586d3f78 100644 --- a/drivers/platform/x86/intel/pmc/core_ssram.c +++ b/drivers/platform/x86/intel/pmc/core_ssram.c @@ -324,5 +324,5 @@ int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func) return ret; } -MODULE_IMPORT_NS(INTEL_VSEC); -MODULE_IMPORT_NS(INTEL_PMT_TELEMETRY); +MODULE_IMPORT_NS("INTEL_VSEC"); +MODULE_IMPORT_NS("INTEL_PMT_TELEMETRY"); diff --git a/drivers/platform/x86/intel/pmc/lnl.c b/drivers/platform/x86/intel/pmc/lnl.c index e7a8077d1a3e12..be029f12cdf403 100644 --- a/drivers/platform/x86/intel/pmc/lnl.c +++ b/drivers/platform/x86/intel/pmc/lnl.c @@ -546,9 +546,8 @@ static void lnl_d3_fixup(void) static int lnl_resume(struct pmc_dev *pmcdev) { lnl_d3_fixup(); - pmc_core_send_ltr_ignore(pmcdev, 3, 0); - return pmc_core_resume_common(pmcdev); + return cnl_resume(pmcdev); } int lnl_core_init(struct pmc_dev *pmcdev) diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c index c7d15d864039d0..02949fed76e916 100644 --- a/drivers/platform/x86/intel/pmc/mtl.c +++ b/drivers/platform/x86/intel/pmc/mtl.c @@ -986,9 +986,8 @@ static void mtl_d3_fixup(void) static int mtl_resume(struct pmc_dev *pmcdev) { mtl_d3_fixup(); - pmc_core_send_ltr_ignore(pmcdev, 3, 0); - return pmc_core_resume_common(pmcdev); + return cnl_resume(pmcdev); } int mtl_core_init(struct pmc_dev *pmcdev) diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c index c04bb7f97a4db1..8ed54b7a333313 100644 --- a/drivers/platform/x86/intel/pmt/class.c +++ b/drivers/platform/x86/intel/pmt/class.c @@ -33,7 +33,7 @@ bool intel_pmt_is_early_client_hw(struct device *dev) */ return !!(ivdev->quirks & VSEC_QUIRK_EARLY_HW); } -EXPORT_SYMBOL_NS_GPL(intel_pmt_is_early_client_hw, INTEL_PMT); +EXPORT_SYMBOL_NS_GPL(intel_pmt_is_early_client_hw, "INTEL_PMT"); static inline int pmt_memcpy64_fromio(void *to, const u64 __iomem *from, size_t count) @@ -59,10 +59,12 @@ pmt_memcpy64_fromio(void *to, const u64 __iomem *from, size_t count) } int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid, void *buf, - void __iomem *addr, u32 count) + void __iomem *addr, loff_t off, u32 count) { if (cb && cb->read_telem) - return cb->read_telem(pdev, guid, buf, count); + return cb->read_telem(pdev, guid, buf, off, count); + + addr += off; if (guid == GUID_SPR_PUNIT) /* PUNIT on SPR only supports aligned 64-bit read */ @@ -72,7 +74,7 @@ int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid return count; } -EXPORT_SYMBOL_NS_GPL(pmt_telem_read_mmio, INTEL_PMT); +EXPORT_SYMBOL_NS_GPL(pmt_telem_read_mmio, "INTEL_PMT"); /* * sysfs @@ -96,14 +98,14 @@ intel_pmt_read(struct file *filp, struct kobject *kobj, count = entry->size - off; count = pmt_telem_read_mmio(entry->ep->pcidev, entry->cb, entry->header.guid, buf, - entry->base + off, count); + entry->base, off, count); return count; } static int intel_pmt_mmap(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, struct vm_area_struct *vma) + const struct bin_attribute *attr, struct vm_area_struct *vma) { struct intel_pmt_entry *entry = container_of(attr, struct intel_pmt_entry, @@ -207,7 +209,7 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry, /* * Some hardware use a different calculation for the base address * when access_type == ACCESS_LOCAL. On the these systems - * ACCCESS_LOCAL refers to an address in the same BAR as the + * ACCESS_LOCAL refers to an address in the same BAR as the * header but at a fixed offset. But as the header address was * supplied to the driver, we don't know which BAR it was in. * So search for the bar whose range includes the header address. @@ -357,7 +359,7 @@ int intel_pmt_dev_create(struct intel_pmt_entry *entry, struct intel_pmt_namespa return intel_pmt_dev_register(entry, ns, dev); } -EXPORT_SYMBOL_NS_GPL(intel_pmt_dev_create, INTEL_PMT); +EXPORT_SYMBOL_NS_GPL(intel_pmt_dev_create, "INTEL_PMT"); void intel_pmt_dev_destroy(struct intel_pmt_entry *entry, struct intel_pmt_namespace *ns) @@ -373,7 +375,7 @@ void intel_pmt_dev_destroy(struct intel_pmt_entry *entry, device_unregister(dev); xa_erase(ns->xa, entry->devid); } -EXPORT_SYMBOL_NS_GPL(intel_pmt_dev_destroy, INTEL_PMT); +EXPORT_SYMBOL_NS_GPL(intel_pmt_dev_destroy, "INTEL_PMT"); static int __init pmt_class_init(void) { diff --git a/drivers/platform/x86/intel/pmt/class.h b/drivers/platform/x86/intel/pmt/class.h index a267ac96442301..b2006d57779d66 100644 --- a/drivers/platform/x86/intel/pmt/class.h +++ b/drivers/platform/x86/intel/pmt/class.h @@ -62,7 +62,7 @@ struct intel_pmt_namespace { }; int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid, void *buf, - void __iomem *addr, u32 count); + void __iomem *addr, loff_t off, u32 count); bool intel_pmt_is_early_client_hw(struct device *dev); int intel_pmt_dev_create(struct intel_pmt_entry *entry, struct intel_pmt_namespace *ns, diff --git a/drivers/platform/x86/intel/pmt/crashlog.c b/drivers/platform/x86/intel/pmt/crashlog.c index 9079d5dffc031a..6a9eb3c4b31378 100644 --- a/drivers/platform/x86/intel/pmt/crashlog.c +++ b/drivers/platform/x86/intel/pmt/crashlog.c @@ -328,4 +328,4 @@ module_exit(pmt_crashlog_exit); MODULE_AUTHOR("Alexander Duyck "); MODULE_DESCRIPTION("Intel PMT Crashlog driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(INTEL_PMT); +MODULE_IMPORT_NS("INTEL_PMT"); diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c index c9feac859e574c..ac3a9bdf560157 100644 --- a/drivers/platform/x86/intel/pmt/telemetry.c +++ b/drivers/platform/x86/intel/pmt/telemetry.c @@ -153,7 +153,7 @@ unsigned long pmt_telem_get_next_endpoint(unsigned long start) return found_idx == start ? 0 : found_idx; } -EXPORT_SYMBOL_NS_GPL(pmt_telem_get_next_endpoint, INTEL_PMT_TELEMETRY); +EXPORT_SYMBOL_NS_GPL(pmt_telem_get_next_endpoint, "INTEL_PMT_TELEMETRY"); struct telem_endpoint *pmt_telem_register_endpoint(int devid) { @@ -172,13 +172,13 @@ struct telem_endpoint *pmt_telem_register_endpoint(int devid) return entry->ep; } -EXPORT_SYMBOL_NS_GPL(pmt_telem_register_endpoint, INTEL_PMT_TELEMETRY); +EXPORT_SYMBOL_NS_GPL(pmt_telem_register_endpoint, "INTEL_PMT_TELEMETRY"); void pmt_telem_unregister_endpoint(struct telem_endpoint *ep) { kref_put(&ep->kref, pmt_telem_ep_release); } -EXPORT_SYMBOL_NS_GPL(pmt_telem_unregister_endpoint, INTEL_PMT_TELEMETRY); +EXPORT_SYMBOL_NS_GPL(pmt_telem_unregister_endpoint, "INTEL_PMT_TELEMETRY"); int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info) { @@ -204,7 +204,7 @@ int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info) return err; } -EXPORT_SYMBOL_NS_GPL(pmt_telem_get_endpoint_info, INTEL_PMT_TELEMETRY); +EXPORT_SYMBOL_NS_GPL(pmt_telem_get_endpoint_info, "INTEL_PMT_TELEMETRY"); int pmt_telem_read(struct telem_endpoint *ep, u32 id, u64 *data, u32 count) { @@ -219,12 +219,12 @@ int pmt_telem_read(struct telem_endpoint *ep, u32 id, u64 *data, u32 count) if (offset + NUM_BYTES_QWORD(count) > size) return -EINVAL; - pmt_telem_read_mmio(ep->pcidev, ep->cb, ep->header.guid, data, ep->base + offset, + pmt_telem_read_mmio(ep->pcidev, ep->cb, ep->header.guid, data, ep->base, offset, NUM_BYTES_QWORD(count)); return ep->present ? 0 : -EPIPE; } -EXPORT_SYMBOL_NS_GPL(pmt_telem_read, INTEL_PMT_TELEMETRY); +EXPORT_SYMBOL_NS_GPL(pmt_telem_read, "INTEL_PMT_TELEMETRY"); int pmt_telem_read32(struct telem_endpoint *ep, u32 id, u32 *data, u32 count) { @@ -243,7 +243,7 @@ int pmt_telem_read32(struct telem_endpoint *ep, u32 id, u32 *data, u32 count) return ep->present ? 0 : -EPIPE; } -EXPORT_SYMBOL_NS_GPL(pmt_telem_read32, INTEL_PMT_TELEMETRY); +EXPORT_SYMBOL_NS_GPL(pmt_telem_read32, "INTEL_PMT_TELEMETRY"); struct telem_endpoint * pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, u32 guid, u16 pos) @@ -268,7 +268,7 @@ pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, u32 guid, u16 pos) return ERR_PTR(-ENXIO); } -EXPORT_SYMBOL_NS_GPL(pmt_telem_find_and_register_endpoint, INTEL_PMT_TELEMETRY); +EXPORT_SYMBOL_NS_GPL(pmt_telem_find_and_register_endpoint, "INTEL_PMT_TELEMETRY"); static void pmt_telem_remove(struct auxiliary_device *auxdev) { @@ -347,4 +347,4 @@ module_exit(pmt_telem_exit); MODULE_AUTHOR("David E. Box "); MODULE_DESCRIPTION("Intel PMT Telemetry driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(INTEL_PMT); +MODULE_IMPORT_NS("INTEL_PMT"); diff --git a/drivers/platform/x86/intel/sdsi.c b/drivers/platform/x86/intel/sdsi.c index 9d137621f0e6e7..33f33b1070fdc9 100644 --- a/drivers/platform/x86/intel/sdsi.c +++ b/drivers/platform/x86/intel/sdsi.c @@ -541,7 +541,7 @@ static struct bin_attribute *sdsi_bin_attrs[] = { }; static umode_t -sdsi_battr_is_visible(struct kobject *kobj, struct bin_attribute *attr, int n) +sdsi_battr_is_visible(struct kobject *kobj, const struct bin_attribute *attr, int n) { struct device *dev = kobj_to_dev(kobj); struct sdsi_priv *priv = dev_get_drvdata(dev); diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi.c index 17972191538a39..bcf0a5cbc68d59 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi.c @@ -67,6 +67,6 @@ static struct auxiliary_driver intel_sst_aux_driver = { module_auxiliary_driver(intel_sst_aux_driver); -MODULE_IMPORT_NS(INTEL_TPMI_SST); +MODULE_IMPORT_NS("INTEL_TPMI_SST"); MODULE_DESCRIPTION("Intel TPMI SST Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c index 4045823071091a..9978cdd1985185 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c @@ -1593,7 +1593,7 @@ int tpmi_sst_dev_add(struct auxiliary_device *auxdev) return ret; } -EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_add, INTEL_TPMI_SST); +EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_add, "INTEL_TPMI_SST"); void tpmi_sst_dev_remove(struct auxiliary_device *auxdev) { @@ -1614,7 +1614,7 @@ void tpmi_sst_dev_remove(struct auxiliary_device *auxdev) } mutex_unlock(&isst_tpmi_dev_lock); } -EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_remove, INTEL_TPMI_SST); +EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_remove, "INTEL_TPMI_SST"); void tpmi_sst_dev_suspend(struct auxiliary_device *auxdev) { @@ -1642,7 +1642,7 @@ void tpmi_sst_dev_suspend(struct auxiliary_device *auxdev) power_domain_info->sst_header.pp_offset + SST_PP_CONTROL_OFFSET); } -EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_suspend, INTEL_TPMI_SST); +EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_suspend, "INTEL_TPMI_SST"); void tpmi_sst_dev_resume(struct auxiliary_device *auxdev) { @@ -1669,7 +1669,7 @@ void tpmi_sst_dev_resume(struct auxiliary_device *auxdev) writeq(power_domain_info->saved_pp_control, power_domain_info->sst_base + power_domain_info->sst_header.pp_offset + SST_PP_CONTROL_OFFSET); } -EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_resume, INTEL_TPMI_SST); +EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_resume, "INTEL_TPMI_SST"); #define ISST_TPMI_API_VERSION 0x03 @@ -1709,7 +1709,7 @@ int tpmi_sst_init(void) mutex_unlock(&isst_tpmi_dev_lock); return ret; } -EXPORT_SYMBOL_NS_GPL(tpmi_sst_init, INTEL_TPMI_SST); +EXPORT_SYMBOL_NS_GPL(tpmi_sst_init, "INTEL_TPMI_SST"); void tpmi_sst_exit(void) { @@ -1723,10 +1723,10 @@ void tpmi_sst_exit(void) } mutex_unlock(&isst_tpmi_dev_lock); } -EXPORT_SYMBOL_NS_GPL(tpmi_sst_exit, INTEL_TPMI_SST); +EXPORT_SYMBOL_NS_GPL(tpmi_sst_exit, "INTEL_TPMI_SST"); -MODULE_IMPORT_NS(INTEL_TPMI); -MODULE_IMPORT_NS(INTEL_TPMI_POWER_DOMAIN); +MODULE_IMPORT_NS("INTEL_TPMI"); +MODULE_IMPORT_NS("INTEL_TPMI_POWER_DOMAIN"); MODULE_DESCRIPTION("ISST TPMI interface module"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel/telemetry/pltdrv.c b/drivers/platform/x86/intel/telemetry/pltdrv.c index 767a0bc6c7ad57..9a499efa1e4d5b 100644 --- a/drivers/platform/x86/intel/telemetry/pltdrv.c +++ b/drivers/platform/x86/intel/telemetry/pltdrv.c @@ -1163,7 +1163,7 @@ static void telemetry_pltdrv_remove(struct platform_device *pdev) static struct platform_driver telemetry_soc_driver = { .probe = telemetry_pltdrv_probe, - .remove_new = telemetry_pltdrv_remove, + .remove = telemetry_pltdrv_remove, .driver = { .name = DRIVER_NAME, }, diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c deleted file mode 100644 index 486ddc9b359248..00000000000000 --- a/drivers/platform/x86/intel/tpmi.c +++ /dev/null @@ -1,857 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * intel-tpmi : Driver to enumerate TPMI features and create devices - * - * Copyright (c) 2023, Intel Corporation. - * All Rights Reserved. - * - * The TPMI (Topology Aware Register and PM Capsule Interface) provides a - * flexible, extendable and PCIe enumerable MMIO interface for PM features. - * - * For example Intel RAPL (Running Average Power Limit) provides a MMIO - * interface using TPMI. This has advantage over traditional MSR - * (Model Specific Register) interface, where a thread needs to be scheduled - * on the target CPU to read or write. Also the RAPL features vary between - * CPU models, and hence lot of model specific code. Here TPMI provides an - * architectural interface by providing hierarchical tables and fields, - * which will not need any model specific implementation. - * - * The TPMI interface uses a PCI VSEC structure to expose the location of - * MMIO region. - * - * This VSEC structure is present in the PCI configuration space of the - * Intel Out-of-Band (OOB) device, which is handled by the Intel VSEC - * driver. The Intel VSEC driver parses VSEC structures present in the PCI - * configuration space of the given device and creates an auxiliary device - * object for each of them. In particular, it creates an auxiliary device - * object representing TPMI that can be bound by an auxiliary driver. - * - * This TPMI driver will bind to the TPMI auxiliary device object created - * by the Intel VSEC driver. - * - * The TPMI specification defines a PFS (PM Feature Structure) table. - * This table is present in the TPMI MMIO region. The starting address - * of PFS is derived from the tBIR (Bar Indicator Register) and "Address" - * field from the VSEC header. - * - * Each TPMI PM feature has one entry in the PFS with a unique TPMI - * ID and its access details. The TPMI driver creates device nodes - * for the supported PM features. - * - * The names of the devices created by the TPMI driver start with the - * "intel_vsec.tpmi-" prefix which is followed by a specific name of the - * given PM feature (for example, "intel_vsec.tpmi-rapl.0"). - * - * The device nodes are create by using interface "intel_vsec_add_aux()" - * provided by the Intel VSEC driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * struct intel_tpmi_pfs_entry - TPMI PM Feature Structure (PFS) entry - * @tpmi_id: TPMI feature identifier (what the feature is and its data format). - * @num_entries: Number of feature interface instances present in the PFS. - * This represents the maximum number of Power domains in the SoC. - * @entry_size: Interface instance entry size in 32-bit words. - * @cap_offset: Offset from the PM_Features base address to the base of the PM VSEC - * register bank in KB. - * @attribute: Feature attribute: 0=BIOS. 1=OS. 2-3=Reserved. - * @reserved: Bits for use in the future. - * - * Represents one TPMI feature entry data in the PFS retrieved as is - * from the hardware. - */ -struct intel_tpmi_pfs_entry { - u64 tpmi_id:8; - u64 num_entries:8; - u64 entry_size:16; - u64 cap_offset:16; - u64 attribute:2; - u64 reserved:14; -} __packed; - -/** - * struct intel_tpmi_pm_feature - TPMI PM Feature information for a TPMI ID - * @pfs_header: PFS header retireved from the hardware. - * @vsec_offset: Starting MMIO address for this feature in bytes. Essentially - * this offset = "Address" from VSEC header + PFS Capability - * offset for this feature entry. - * @vsec_dev: Pointer to intel_vsec_device structure for this TPMI device - * - * Represents TPMI instance information for one TPMI ID. - */ -struct intel_tpmi_pm_feature { - struct intel_tpmi_pfs_entry pfs_header; - u64 vsec_offset; - struct intel_vsec_device *vsec_dev; -}; - -/** - * struct intel_tpmi_info - TPMI information for all IDs in an instance - * @tpmi_features: Pointer to a list of TPMI feature instances - * @vsec_dev: Pointer to intel_vsec_device structure for this TPMI device - * @feature_count: Number of TPMI of TPMI instances pointed by tpmi_features - * @pfs_start: Start of PFS offset for the TPMI instances in this device - * @plat_info: Stores platform info which can be used by the client drivers - * @tpmi_control_mem: Memory mapped IO for getting control information - * @dbgfs_dir: debugfs entry pointer - * - * Stores the information for all TPMI devices enumerated from a single PCI device. - */ -struct intel_tpmi_info { - struct intel_tpmi_pm_feature *tpmi_features; - struct intel_vsec_device *vsec_dev; - int feature_count; - u64 pfs_start; - struct intel_tpmi_plat_info plat_info; - void __iomem *tpmi_control_mem; - struct dentry *dbgfs_dir; -}; - -/** - * struct tpmi_info_header - CPU package ID to PCI device mapping information - * @fn: PCI function number - * @dev: PCI device number - * @bus: PCI bus number - * @pkg: CPU Package id - * @segment: PCI segment id - * @partition: Package Partition id - * @cdie_mask: Bitmap of compute dies in the current partition - * @reserved: Reserved for future use - * @lock: When set to 1 the register is locked and becomes read-only - * until next reset. Not for use by the OS driver. - * - * The structure to read hardware provided mapping information. - */ -struct tpmi_info_header { - u64 fn:3; - u64 dev:5; - u64 bus:8; - u64 pkg:8; - u64 segment:8; - u64 partition:2; - u64 cdie_mask:16; - u64 reserved:13; - u64 lock:1; -} __packed; - -/** - * struct tpmi_feature_state - Structure to read hardware state of a feature - * @enabled: Enable state of a feature, 1: enabled, 0: disabled - * @reserved_1: Reserved for future use - * @write_blocked: Writes are blocked means all write operations are ignored - * @read_blocked: Reads are blocked means will read 0xFFs - * @pcs_select: Interface used by out of band software, not used in OS - * @reserved_2: Reserved for future use - * @id: TPMI ID of the feature - * @reserved_3: Reserved for future use - * @locked: When set to 1, OS can't change this register. - * - * The structure is used to read hardware state of a TPMI feature. This - * information is used for debug and restricting operations for this feature. - */ -struct tpmi_feature_state { - u32 enabled:1; - u32 reserved_1:3; - u32 write_blocked:1; - u32 read_blocked:1; - u32 pcs_select:1; - u32 reserved_2:1; - u32 id:8; - u32 reserved_3:15; - u32 locked:1; -} __packed; - -/* - * The size from hardware is in u32 units. This size is from a trusted hardware, - * but better to verify for pre silicon platforms. Set size to 0, when invalid. - */ -#define TPMI_GET_SINGLE_ENTRY_SIZE(pfs) \ -({ \ - pfs->pfs_header.entry_size > SZ_1K ? 0 : pfs->pfs_header.entry_size << 2; \ -}) - -/* Used during auxbus device creation */ -static DEFINE_IDA(intel_vsec_tpmi_ida); - -struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev) -{ - struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); - - return vsec_dev->priv_data; -} -EXPORT_SYMBOL_NS_GPL(tpmi_get_platform_data, INTEL_TPMI); - -int tpmi_get_resource_count(struct auxiliary_device *auxdev) -{ - struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); - - if (vsec_dev) - return vsec_dev->num_resources; - - return 0; -} -EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_count, INTEL_TPMI); - -struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int index) -{ - struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); - - if (vsec_dev && index < vsec_dev->num_resources) - return &vsec_dev->resource[index]; - - return NULL; -} -EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); - -/* TPMI Control Interface */ - -#define TPMI_CONTROL_STATUS_OFFSET 0x00 -#define TPMI_COMMAND_OFFSET 0x08 -#define TMPI_CONTROL_DATA_VAL_OFFSET 0x0c - -/* - * Spec is calling for max 1 seconds to get ownership at the worst - * case. Read at 10 ms timeouts and repeat up to 1 second. - */ -#define TPMI_CONTROL_TIMEOUT_US (10 * USEC_PER_MSEC) -#define TPMI_CONTROL_TIMEOUT_MAX_US (1 * USEC_PER_SEC) - -#define TPMI_RB_TIMEOUT_US (10 * USEC_PER_MSEC) -#define TPMI_RB_TIMEOUT_MAX_US USEC_PER_SEC - -/* TPMI Control status register defines */ - -#define TPMI_CONTROL_STATUS_RB BIT_ULL(0) - -#define TPMI_CONTROL_STATUS_OWNER GENMASK_ULL(5, 4) -#define TPMI_OWNER_NONE 0 -#define TPMI_OWNER_IN_BAND 1 - -#define TPMI_CONTROL_STATUS_CPL BIT_ULL(6) -#define TPMI_CONTROL_STATUS_RESULT GENMASK_ULL(15, 8) -#define TPMI_CONTROL_STATUS_LEN GENMASK_ULL(31, 16) - -#define TPMI_CMD_PKT_LEN 2 -#define TPMI_CMD_STATUS_SUCCESS 0x40 - -/* TPMI command data registers */ -#define TMPI_CONTROL_DATA_CMD GENMASK_ULL(7, 0) -#define TPMI_CONTROL_DATA_VAL_FEATURE GENMASK_ULL(48, 40) - -/* Command to send via control interface */ -#define TPMI_CONTROL_GET_STATE_CMD 0x10 - -#define TPMI_CONTROL_CMD_MASK GENMASK_ULL(48, 40) - -#define TPMI_CMD_LEN_MASK GENMASK_ULL(18, 16) - -/* Mutex to complete get feature status without interruption */ -static DEFINE_MUTEX(tpmi_dev_lock); - -static int tpmi_wait_for_owner(struct intel_tpmi_info *tpmi_info, u8 owner) -{ - u64 control; - - return readq_poll_timeout(tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET, - control, owner == FIELD_GET(TPMI_CONTROL_STATUS_OWNER, control), - TPMI_CONTROL_TIMEOUT_US, TPMI_CONTROL_TIMEOUT_MAX_US); -} - -static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int feature_id, - struct tpmi_feature_state *feature_state) -{ - u64 control, data; - int ret; - - if (!tpmi_info->tpmi_control_mem) - return -EFAULT; - - mutex_lock(&tpmi_dev_lock); - - /* Wait for owner bit set to 0 (none) */ - ret = tpmi_wait_for_owner(tpmi_info, TPMI_OWNER_NONE); - if (ret) - goto err_unlock; - - /* set command id to 0x10 for TPMI_GET_STATE */ - data = FIELD_PREP(TMPI_CONTROL_DATA_CMD, TPMI_CONTROL_GET_STATE_CMD); - - /* 32 bits for DATA offset and +8 for feature_id field */ - data |= FIELD_PREP(TPMI_CONTROL_DATA_VAL_FEATURE, feature_id); - - /* Write at command offset for qword access */ - writeq(data, tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET); - - /* Wait for owner bit set to in-band */ - ret = tpmi_wait_for_owner(tpmi_info, TPMI_OWNER_IN_BAND); - if (ret) - goto err_unlock; - - /* Set Run Busy and packet length of 2 dwords */ - control = TPMI_CONTROL_STATUS_RB; - control |= FIELD_PREP(TPMI_CONTROL_STATUS_LEN, TPMI_CMD_PKT_LEN); - - /* Write at status offset for qword access */ - writeq(control, tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET); - - /* Wait for Run Busy clear */ - ret = readq_poll_timeout(tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET, - control, !(control & TPMI_CONTROL_STATUS_RB), - TPMI_RB_TIMEOUT_US, TPMI_RB_TIMEOUT_MAX_US); - if (ret) - goto done_proc; - - control = FIELD_GET(TPMI_CONTROL_STATUS_RESULT, control); - if (control != TPMI_CMD_STATUS_SUCCESS) { - ret = -EBUSY; - goto done_proc; - } - - /* Response is ready */ - memcpy_fromio(feature_state, tpmi_info->tpmi_control_mem + TMPI_CONTROL_DATA_VAL_OFFSET, - sizeof(*feature_state)); - - ret = 0; - -done_proc: - /* Set CPL "completion" bit */ - writeq(TPMI_CONTROL_STATUS_CPL, tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET); - -err_unlock: - mutex_unlock(&tpmi_dev_lock); - - return ret; -} - -int tpmi_get_feature_status(struct auxiliary_device *auxdev, - int feature_id, bool *read_blocked, bool *write_blocked) -{ - struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); - struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); - struct tpmi_feature_state feature_state; - int ret; - - ret = tpmi_read_feature_status(tpmi_info, feature_id, &feature_state); - if (ret) - return ret; - - *read_blocked = feature_state.read_blocked; - *write_blocked = feature_state.write_blocked; - - return 0; -} -EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI); - -struct dentry *tpmi_get_debugfs_dir(struct auxiliary_device *auxdev) -{ - struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); - struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); - - return tpmi_info->dbgfs_dir; -} -EXPORT_SYMBOL_NS_GPL(tpmi_get_debugfs_dir, INTEL_TPMI); - -static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused) -{ - struct intel_tpmi_info *tpmi_info = s->private; - int locked, disabled, read_blocked, write_blocked; - struct tpmi_feature_state feature_state; - struct intel_tpmi_pm_feature *pfs; - int ret, i; - - - seq_printf(s, "tpmi PFS start offset 0x:%llx\n", tpmi_info->pfs_start); - seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\tread_blocked\twrite_blocked\n"); - for (i = 0; i < tpmi_info->feature_count; ++i) { - pfs = &tpmi_info->tpmi_features[i]; - ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state); - if (ret) { - locked = 'U'; - disabled = 'U'; - read_blocked = 'U'; - write_blocked = 'U'; - } else { - disabled = feature_state.enabled ? 'N' : 'Y'; - locked = feature_state.locked ? 'Y' : 'N'; - read_blocked = feature_state.read_blocked ? 'Y' : 'N'; - write_blocked = feature_state.write_blocked ? 'Y' : 'N'; - } - seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%016llx\t%c\t%c\t\t%c\t\t%c\n", - pfs->pfs_header.tpmi_id, pfs->pfs_header.num_entries, - pfs->pfs_header.entry_size, pfs->pfs_header.cap_offset, - pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled, - read_blocked, write_blocked); - } - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(tpmi_pfs_dbg); - -#define MEM_DUMP_COLUMN_COUNT 8 - -static int tpmi_mem_dump_show(struct seq_file *s, void *unused) -{ - size_t row_size = MEM_DUMP_COLUMN_COUNT * sizeof(u32); - struct intel_tpmi_pm_feature *pfs = s->private; - int count, ret = 0; - void __iomem *mem; - u32 size; - u64 off; - u8 *buffer; - - size = TPMI_GET_SINGLE_ENTRY_SIZE(pfs); - if (!size) - return -EIO; - - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - off = pfs->vsec_offset; - - mutex_lock(&tpmi_dev_lock); - - for (count = 0; count < pfs->pfs_header.num_entries; ++count) { - seq_printf(s, "TPMI Instance:%d offset:0x%llx\n", count, off); - - mem = ioremap(off, size); - if (!mem) { - ret = -ENOMEM; - break; - } - - memcpy_fromio(buffer, mem, size); - - seq_hex_dump(s, " ", DUMP_PREFIX_OFFSET, row_size, sizeof(u32), buffer, size, - false); - - iounmap(mem); - - off += size; - } - - mutex_unlock(&tpmi_dev_lock); - - kfree(buffer); - - return ret; -} -DEFINE_SHOW_ATTRIBUTE(tpmi_mem_dump); - -static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t len, loff_t *ppos) -{ - struct seq_file *m = file->private_data; - struct intel_tpmi_pm_feature *pfs = m->private; - u32 addr, value, punit, size; - u32 num_elems, *array; - void __iomem *mem; - int ret; - - size = TPMI_GET_SINGLE_ENTRY_SIZE(pfs); - if (!size) - return -EIO; - - ret = parse_int_array_user(userbuf, len, (int **)&array); - if (ret < 0) - return ret; - - num_elems = *array; - if (num_elems != 3) { - ret = -EINVAL; - goto exit_write; - } - - punit = array[1]; - addr = array[2]; - value = array[3]; - - if (punit >= pfs->pfs_header.num_entries) { - ret = -EINVAL; - goto exit_write; - } - - if (addr >= size) { - ret = -EINVAL; - goto exit_write; - } - - mutex_lock(&tpmi_dev_lock); - - mem = ioremap(pfs->vsec_offset + punit * size, size); - if (!mem) { - ret = -ENOMEM; - goto unlock_mem_write; - } - - writel(value, mem + addr); - - iounmap(mem); - - ret = len; - -unlock_mem_write: - mutex_unlock(&tpmi_dev_lock); - -exit_write: - kfree(array); - - return ret; -} - -static int mem_write_show(struct seq_file *s, void *unused) -{ - return 0; -} - -static int mem_write_open(struct inode *inode, struct file *file) -{ - return single_open(file, mem_write_show, inode->i_private); -} - -static const struct file_operations mem_write_ops = { - .open = mem_write_open, - .read = seq_read, - .write = mem_write, - .llseek = seq_lseek, - .release = single_release, -}; - -#define tpmi_to_dev(info) (&info->vsec_dev->pcidev->dev) - -static void tpmi_dbgfs_register(struct intel_tpmi_info *tpmi_info) -{ - char name[64]; - int i; - - snprintf(name, sizeof(name), "tpmi-%s", dev_name(tpmi_to_dev(tpmi_info))); - tpmi_info->dbgfs_dir = debugfs_create_dir(name, NULL); - - debugfs_create_file("pfs_dump", 0444, tpmi_info->dbgfs_dir, tpmi_info, &tpmi_pfs_dbg_fops); - - for (i = 0; i < tpmi_info->feature_count; ++i) { - struct intel_tpmi_pm_feature *pfs; - struct dentry *dir; - - pfs = &tpmi_info->tpmi_features[i]; - snprintf(name, sizeof(name), "tpmi-id-%02x", pfs->pfs_header.tpmi_id); - dir = debugfs_create_dir(name, tpmi_info->dbgfs_dir); - - debugfs_create_file("mem_dump", 0444, dir, pfs, &tpmi_mem_dump_fops); - debugfs_create_file("mem_write", 0644, dir, pfs, &mem_write_ops); - } -} - -static void tpmi_set_control_base(struct auxiliary_device *auxdev, - struct intel_tpmi_info *tpmi_info, - struct intel_tpmi_pm_feature *pfs) -{ - void __iomem *mem; - u32 size; - - size = TPMI_GET_SINGLE_ENTRY_SIZE(pfs); - if (!size) - return; - - mem = devm_ioremap(&auxdev->dev, pfs->vsec_offset, size); - if (!mem) - return; - - /* mem is pointing to TPMI CONTROL base */ - tpmi_info->tpmi_control_mem = mem; -} - -static const char *intel_tpmi_name(enum intel_tpmi_id id) -{ - switch (id) { - case TPMI_ID_RAPL: - return "rapl"; - case TPMI_ID_PEM: - return "pem"; - case TPMI_ID_UNCORE: - return "uncore"; - case TPMI_ID_SST: - return "sst"; - case TPMI_ID_PLR: - return "plr"; - default: - return NULL; - } -} - -/* String Length for tpmi-"feature_name(upto 8 bytes)" */ -#define TPMI_FEATURE_NAME_LEN 14 - -static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, - struct intel_tpmi_pm_feature *pfs, - u64 pfs_start) -{ - struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev; - char feature_id_name[TPMI_FEATURE_NAME_LEN]; - struct intel_vsec_device *feature_vsec_dev; - struct tpmi_feature_state feature_state; - struct resource *res, *tmp; - const char *name; - int i, ret; - - ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state); - if (ret) - return ret; - - /* - * If not enabled, continue to look at other features in the PFS, so return -EOPNOTSUPP. - * This will not cause failure of loading of this driver. - */ - if (!feature_state.enabled) - return -EOPNOTSUPP; - - name = intel_tpmi_name(pfs->pfs_header.tpmi_id); - if (!name) - return -EOPNOTSUPP; - - res = kcalloc(pfs->pfs_header.num_entries, sizeof(*res), GFP_KERNEL); - if (!res) - return -ENOMEM; - - feature_vsec_dev = kzalloc(sizeof(*feature_vsec_dev), GFP_KERNEL); - if (!feature_vsec_dev) { - kfree(res); - return -ENOMEM; - } - - snprintf(feature_id_name, sizeof(feature_id_name), "tpmi-%s", name); - - for (i = 0, tmp = res; i < pfs->pfs_header.num_entries; i++, tmp++) { - u64 entry_size_bytes = pfs->pfs_header.entry_size * sizeof(u32); - - tmp->start = pfs->vsec_offset + entry_size_bytes * i; - tmp->end = tmp->start + entry_size_bytes - 1; - tmp->flags = IORESOURCE_MEM; - } - - feature_vsec_dev->pcidev = vsec_dev->pcidev; - feature_vsec_dev->resource = res; - feature_vsec_dev->num_resources = pfs->pfs_header.num_entries; - feature_vsec_dev->priv_data = &tpmi_info->plat_info; - feature_vsec_dev->priv_data_size = sizeof(tpmi_info->plat_info); - feature_vsec_dev->ida = &intel_vsec_tpmi_ida; - - /* - * intel_vsec_add_aux() is resource managed, no explicit - * delete is required on error or on module unload. - * feature_vsec_dev and res memory are also freed as part of - * device deletion. - */ - return intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev, - feature_vsec_dev, feature_id_name); -} - -static int tpmi_create_devices(struct intel_tpmi_info *tpmi_info) -{ - struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev; - int ret, i; - - for (i = 0; i < vsec_dev->num_resources; i++) { - ret = tpmi_create_device(tpmi_info, &tpmi_info->tpmi_features[i], - tpmi_info->pfs_start); - /* - * Fail, if the supported features fails to create device, - * otherwise, continue. Even if one device failed to create, - * fail the loading of driver. Since intel_vsec_add_aux() - * is resource managed, no clean up is required for the - * successfully created devices. - */ - if (ret && ret != -EOPNOTSUPP) - return ret; - } - - return 0; -} - -#define TPMI_INFO_BUS_INFO_OFFSET 0x08 -#define TPMI_INFO_MAJOR_VERSION 0x00 -#define TPMI_INFO_MINOR_VERSION 0x02 - -static int tpmi_process_info(struct intel_tpmi_info *tpmi_info, - struct intel_tpmi_pm_feature *pfs) -{ - struct tpmi_info_header header; - void __iomem *info_mem; - u64 feature_header; - int ret = 0; - - info_mem = ioremap(pfs->vsec_offset, pfs->pfs_header.entry_size * sizeof(u32)); - if (!info_mem) - return -ENOMEM; - - feature_header = readq(info_mem); - if (TPMI_MAJOR_VERSION(feature_header) != TPMI_INFO_MAJOR_VERSION) { - ret = -ENODEV; - goto error_info_header; - } - - memcpy_fromio(&header, info_mem + TPMI_INFO_BUS_INFO_OFFSET, sizeof(header)); - - tpmi_info->plat_info.package_id = header.pkg; - tpmi_info->plat_info.bus_number = header.bus; - tpmi_info->plat_info.device_number = header.dev; - tpmi_info->plat_info.function_number = header.fn; - - if (TPMI_MINOR_VERSION(feature_header) >= TPMI_INFO_MINOR_VERSION) { - tpmi_info->plat_info.cdie_mask = header.cdie_mask; - tpmi_info->plat_info.partition = header.partition; - tpmi_info->plat_info.segment = header.segment; - } - -error_info_header: - iounmap(info_mem); - - return ret; -} - -static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, int size) -{ - void __iomem *pfs_mem; - - pfs_mem = ioremap(start, size); - if (!pfs_mem) - return -ENOMEM; - - memcpy_fromio(&pfs->pfs_header, pfs_mem, sizeof(pfs->pfs_header)); - - iounmap(pfs_mem); - - return 0; -} - -#define TPMI_CAP_OFFSET_UNIT 1024 - -static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) -{ - struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); - struct pci_dev *pci_dev = vsec_dev->pcidev; - struct intel_tpmi_info *tpmi_info; - u64 pfs_start = 0; - int ret, i; - - tpmi_info = devm_kzalloc(&auxdev->dev, sizeof(*tpmi_info), GFP_KERNEL); - if (!tpmi_info) - return -ENOMEM; - - tpmi_info->vsec_dev = vsec_dev; - tpmi_info->feature_count = vsec_dev->num_resources; - tpmi_info->plat_info.bus_number = pci_dev->bus->number; - - tpmi_info->tpmi_features = devm_kcalloc(&auxdev->dev, vsec_dev->num_resources, - sizeof(*tpmi_info->tpmi_features), - GFP_KERNEL); - if (!tpmi_info->tpmi_features) - return -ENOMEM; - - for (i = 0; i < vsec_dev->num_resources; i++) { - struct intel_tpmi_pm_feature *pfs; - struct resource *res; - u64 res_start; - int size, ret; - - pfs = &tpmi_info->tpmi_features[i]; - pfs->vsec_dev = vsec_dev; - - res = &vsec_dev->resource[i]; - if (!res) - continue; - - res_start = res->start; - size = resource_size(res); - if (size < 0) - continue; - - ret = tpmi_fetch_pfs_header(pfs, res_start, size); - if (ret) - continue; - - if (!pfs_start) - pfs_start = res_start; - - pfs->vsec_offset = pfs_start + pfs->pfs_header.cap_offset * TPMI_CAP_OFFSET_UNIT; - - /* - * Process TPMI_INFO to get PCI device to CPU package ID. - * Device nodes for TPMI features are not created in this - * for loop. So, the mapping information will be available - * when actual device nodes created outside this - * loop via tpmi_create_devices(). - */ - if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) { - ret = tpmi_process_info(tpmi_info, pfs); - if (ret) - return ret; - } - - if (pfs->pfs_header.tpmi_id == TPMI_CONTROL_ID) - tpmi_set_control_base(auxdev, tpmi_info, pfs); - } - - tpmi_info->pfs_start = pfs_start; - - auxiliary_set_drvdata(auxdev, tpmi_info); - - ret = tpmi_create_devices(tpmi_info); - if (ret) - return ret; - - /* - * Allow debugfs when security policy allows. Everything this debugfs - * interface provides, can also be done via /dev/mem access. If - * /dev/mem interface is locked, don't allow debugfs to present any - * information. Also check for CAP_SYS_RAWIO as /dev/mem interface. - */ - if (!security_locked_down(LOCKDOWN_DEV_MEM) && capable(CAP_SYS_RAWIO)) - tpmi_dbgfs_register(tpmi_info); - - return 0; -} - -static int tpmi_probe(struct auxiliary_device *auxdev, - const struct auxiliary_device_id *id) -{ - return intel_vsec_tpmi_init(auxdev); -} - -static void tpmi_remove(struct auxiliary_device *auxdev) -{ - struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(auxdev); - - debugfs_remove_recursive(tpmi_info->dbgfs_dir); -} - -static const struct auxiliary_device_id tpmi_id_table[] = { - { .name = "intel_vsec.tpmi" }, - {} -}; -MODULE_DEVICE_TABLE(auxiliary, tpmi_id_table); - -static struct auxiliary_driver tpmi_aux_driver = { - .id_table = tpmi_id_table, - .probe = tpmi_probe, - .remove = tpmi_remove, -}; - -module_auxiliary_driver(tpmi_aux_driver); - -MODULE_IMPORT_NS(INTEL_VSEC); -MODULE_DESCRIPTION("Intel TPMI enumeration module"); -MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel/tpmi_power_domains.c b/drivers/platform/x86/intel/tpmi_power_domains.c index 0609a8320f7ec1..603e7ded06a91b 100644 --- a/drivers/platform/x86/intel/tpmi_power_domains.c +++ b/drivers/platform/x86/intel/tpmi_power_domains.c @@ -110,7 +110,7 @@ int tpmi_get_linux_cpu_number(int package_id, int domain_id, int punit_core_id) return ret; } -EXPORT_SYMBOL_NS_GPL(tpmi_get_linux_cpu_number, INTEL_TPMI_POWER_DOMAIN); +EXPORT_SYMBOL_NS_GPL(tpmi_get_linux_cpu_number, "INTEL_TPMI_POWER_DOMAIN"); int tpmi_get_punit_core_number(int cpu_no) { @@ -119,7 +119,7 @@ int tpmi_get_punit_core_number(int cpu_no) return per_cpu(tpmi_cpu_info, cpu_no).punit_core_id; } -EXPORT_SYMBOL_NS_GPL(tpmi_get_punit_core_number, INTEL_TPMI_POWER_DOMAIN); +EXPORT_SYMBOL_NS_GPL(tpmi_get_punit_core_number, "INTEL_TPMI_POWER_DOMAIN"); int tpmi_get_power_domain_id(int cpu_no) { @@ -128,7 +128,7 @@ int tpmi_get_power_domain_id(int cpu_no) return per_cpu(tpmi_cpu_info, cpu_no).punit_domain_id; } -EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_id, INTEL_TPMI_POWER_DOMAIN); +EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_id, "INTEL_TPMI_POWER_DOMAIN"); cpumask_t *tpmi_get_power_domain_mask(int cpu_no) { @@ -149,7 +149,7 @@ cpumask_t *tpmi_get_power_domain_mask(int cpu_no) return mask; } -EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_mask, INTEL_TPMI_POWER_DOMAIN); +EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_mask, "INTEL_TPMI_POWER_DOMAIN"); static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info) { 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 e22b683a7a434c..4e2c6a2d7e6e1f 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c @@ -257,7 +257,7 @@ int uncore_freq_add_entry(struct uncore_data *data, int cpu) return ret; } -EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, INTEL_UNCORE_FREQUENCY); +EXPORT_SYMBOL_NS_GPL(uncore_freq_add_entry, "INTEL_UNCORE_FREQUENCY"); void uncore_freq_remove_die_entry(struct uncore_data *data) { @@ -270,7 +270,7 @@ void uncore_freq_remove_die_entry(struct uncore_data *data) mutex_unlock(&uncore_lock); } -EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, INTEL_UNCORE_FREQUENCY); +EXPORT_SYMBOL_NS_GPL(uncore_freq_remove_die_entry, "INTEL_UNCORE_FREQUENCY"); int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value, enum uncore_index index), @@ -297,7 +297,7 @@ int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int * return uncore_root_kobj ? 0 : -ENOMEM; } -EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, INTEL_UNCORE_FREQUENCY); +EXPORT_SYMBOL_NS_GPL(uncore_freq_common_init, "INTEL_UNCORE_FREQUENCY"); void uncore_freq_common_exit(void) { @@ -309,7 +309,7 @@ void uncore_freq_common_exit(void) } mutex_unlock(&uncore_lock); } -EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, INTEL_UNCORE_FREQUENCY); +EXPORT_SYMBOL_NS_GPL(uncore_freq_common_exit, "INTEL_UNCORE_FREQUENCY"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 0591053813a283..4aa6c227ec8202 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -629,7 +629,7 @@ static struct auxiliary_driver intel_uncore_aux_driver = { module_auxiliary_driver(intel_uncore_aux_driver); -MODULE_IMPORT_NS(INTEL_TPMI); -MODULE_IMPORT_NS(INTEL_UNCORE_FREQUENCY); +MODULE_IMPORT_NS("INTEL_TPMI"); +MODULE_IMPORT_NS("INTEL_UNCORE_FREQUENCY"); MODULE_DESCRIPTION("Intel TPMI UFS Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c index a450b8a6bcec10..40bbf8e45fa4bb 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency.c @@ -316,6 +316,6 @@ static void __exit intel_uncore_exit(void) } module_exit(intel_uncore_exit) -MODULE_IMPORT_NS(INTEL_UNCORE_FREQUENCY); +MODULE_IMPORT_NS("INTEL_UNCORE_FREQUENCY"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Uncore Frequency Limits Driver"); diff --git a/drivers/platform/x86/intel/vbtn.c b/drivers/platform/x86/intel/vbtn.c index a353e830b65fd1..232cd12e3c9fab 100644 --- a/drivers/platform/x86/intel/vbtn.c +++ b/drivers/platform/x86/intel/vbtn.c @@ -387,7 +387,7 @@ static struct platform_driver intel_vbtn_pl_driver = { .pm = &intel_vbtn_pm_ops, }, .probe = intel_vbtn_probe, - .remove_new = intel_vbtn_remove, + .remove = intel_vbtn_remove, }; static acpi_status __init diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index 7b5cc9993974ef..8272f1dd0fbc09 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -79,17 +79,13 @@ static void intel_vsec_remove_aux(void *data) auxiliary_device_uninit(data); } -static DEFINE_MUTEX(vsec_ida_lock); - static void intel_vsec_dev_release(struct device *dev) { struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev); xa_erase(&auxdev_array, intel_vsec_dev->id); - mutex_lock(&vsec_ida_lock); ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id); - mutex_unlock(&vsec_ida_lock); kfree(intel_vsec_dev->resource); kfree(intel_vsec_dev); @@ -113,9 +109,7 @@ int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, return ret; } - mutex_lock(&vsec_ida_lock); id = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL); - mutex_unlock(&vsec_ida_lock); if (id < 0) { xa_erase(&auxdev_array, intel_vsec_dev->id); kfree(intel_vsec_dev->resource); @@ -143,7 +137,7 @@ int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, return devm_add_action_or_reset(parent, intel_vsec_remove_aux, auxdev); } -EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, INTEL_VSEC); +EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, "INTEL_VSEC"); static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, struct intel_vsec_platform_info *info) @@ -346,7 +340,7 @@ void intel_vsec_register(struct pci_dev *pdev, intel_vsec_walk_header(pdev, info); } -EXPORT_SYMBOL_NS_GPL(intel_vsec_register, INTEL_VSEC); +EXPORT_SYMBOL_NS_GPL(intel_vsec_register, "INTEL_VSEC"); static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -429,6 +423,7 @@ static const struct intel_vsec_platform_info lnl_info = { #define PCI_DEVICE_ID_INTEL_VSEC_RPL 0xa77d #define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d #define PCI_DEVICE_ID_INTEL_VSEC_LNL_M 0x647d +#define PCI_DEVICE_ID_INTEL_VSEC_PTL 0xb07d static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, @@ -438,6 +433,7 @@ static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_LNL_M, &lnl_info) }, + { PCI_DEVICE_DATA(INTEL, VSEC_PTL, &mtl_info) }, { } }; MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids); diff --git a/drivers/platform/x86/intel/vsec_tpmi.c b/drivers/platform/x86/intel/vsec_tpmi.c new file mode 100644 index 00000000000000..5c383a27bbe8d1 --- /dev/null +++ b/drivers/platform/x86/intel/vsec_tpmi.c @@ -0,0 +1,857 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver to enumerate TPMI features and create devices + * + * Copyright (c) 2023, Intel Corporation. + * All Rights Reserved. + * + * The TPMI (Topology Aware Register and PM Capsule Interface) provides a + * flexible, extendable and PCIe enumerable MMIO interface for PM features. + * + * For example Intel RAPL (Running Average Power Limit) provides a MMIO + * interface using TPMI. This has advantage over traditional MSR + * (Model Specific Register) interface, where a thread needs to be scheduled + * on the target CPU to read or write. Also the RAPL features vary between + * CPU models, and hence lot of model specific code. Here TPMI provides an + * architectural interface by providing hierarchical tables and fields, + * which will not need any model specific implementation. + * + * The TPMI interface uses a PCI VSEC structure to expose the location of + * MMIO region. + * + * This VSEC structure is present in the PCI configuration space of the + * Intel Out-of-Band (OOB) device, which is handled by the Intel VSEC + * driver. The Intel VSEC driver parses VSEC structures present in the PCI + * configuration space of the given device and creates an auxiliary device + * object for each of them. In particular, it creates an auxiliary device + * object representing TPMI that can be bound by an auxiliary driver. + * + * This TPMI driver will bind to the TPMI auxiliary device object created + * by the Intel VSEC driver. + * + * The TPMI specification defines a PFS (PM Feature Structure) table. + * This table is present in the TPMI MMIO region. The starting address + * of PFS is derived from the tBIR (Bar Indicator Register) and "Address" + * field from the VSEC header. + * + * Each TPMI PM feature has one entry in the PFS with a unique TPMI + * ID and its access details. The TPMI driver creates device nodes + * for the supported PM features. + * + * The names of the devices created by the TPMI driver start with the + * "intel_vsec.tpmi-" prefix which is followed by a specific name of the + * given PM feature (for example, "intel_vsec.tpmi-rapl.0"). + * + * The device nodes are create by using interface "intel_vsec_add_aux()" + * provided by the Intel VSEC driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct intel_tpmi_pfs_entry - TPMI PM Feature Structure (PFS) entry + * @tpmi_id: TPMI feature identifier (what the feature is and its data format). + * @num_entries: Number of feature interface instances present in the PFS. + * This represents the maximum number of Power domains in the SoC. + * @entry_size: Interface instance entry size in 32-bit words. + * @cap_offset: Offset from the PM_Features base address to the base of the PM VSEC + * register bank in KB. + * @attribute: Feature attribute: 0=BIOS. 1=OS. 2-3=Reserved. + * @reserved: Bits for use in the future. + * + * Represents one TPMI feature entry data in the PFS retrieved as is + * from the hardware. + */ +struct intel_tpmi_pfs_entry { + u64 tpmi_id:8; + u64 num_entries:8; + u64 entry_size:16; + u64 cap_offset:16; + u64 attribute:2; + u64 reserved:14; +} __packed; + +/** + * struct intel_tpmi_pm_feature - TPMI PM Feature information for a TPMI ID + * @pfs_header: PFS header retireved from the hardware. + * @vsec_offset: Starting MMIO address for this feature in bytes. Essentially + * this offset = "Address" from VSEC header + PFS Capability + * offset for this feature entry. + * @vsec_dev: Pointer to intel_vsec_device structure for this TPMI device + * + * Represents TPMI instance information for one TPMI ID. + */ +struct intel_tpmi_pm_feature { + struct intel_tpmi_pfs_entry pfs_header; + u64 vsec_offset; + struct intel_vsec_device *vsec_dev; +}; + +/** + * struct intel_tpmi_info - TPMI information for all IDs in an instance + * @tpmi_features: Pointer to a list of TPMI feature instances + * @vsec_dev: Pointer to intel_vsec_device structure for this TPMI device + * @feature_count: Number of TPMI of TPMI instances pointed by tpmi_features + * @pfs_start: Start of PFS offset for the TPMI instances in this device + * @plat_info: Stores platform info which can be used by the client drivers + * @tpmi_control_mem: Memory mapped IO for getting control information + * @dbgfs_dir: debugfs entry pointer + * + * Stores the information for all TPMI devices enumerated from a single PCI device. + */ +struct intel_tpmi_info { + struct intel_tpmi_pm_feature *tpmi_features; + struct intel_vsec_device *vsec_dev; + int feature_count; + u64 pfs_start; + struct intel_tpmi_plat_info plat_info; + void __iomem *tpmi_control_mem; + struct dentry *dbgfs_dir; +}; + +/** + * struct tpmi_info_header - CPU package ID to PCI device mapping information + * @fn: PCI function number + * @dev: PCI device number + * @bus: PCI bus number + * @pkg: CPU Package id + * @segment: PCI segment id + * @partition: Package Partition id + * @cdie_mask: Bitmap of compute dies in the current partition + * @reserved: Reserved for future use + * @lock: When set to 1 the register is locked and becomes read-only + * until next reset. Not for use by the OS driver. + * + * The structure to read hardware provided mapping information. + */ +struct tpmi_info_header { + u64 fn:3; + u64 dev:5; + u64 bus:8; + u64 pkg:8; + u64 segment:8; + u64 partition:2; + u64 cdie_mask:16; + u64 reserved:13; + u64 lock:1; +} __packed; + +/** + * struct tpmi_feature_state - Structure to read hardware state of a feature + * @enabled: Enable state of a feature, 1: enabled, 0: disabled + * @reserved_1: Reserved for future use + * @write_blocked: Writes are blocked means all write operations are ignored + * @read_blocked: Reads are blocked means will read 0xFFs + * @pcs_select: Interface used by out of band software, not used in OS + * @reserved_2: Reserved for future use + * @id: TPMI ID of the feature + * @reserved_3: Reserved for future use + * @locked: When set to 1, OS can't change this register. + * + * The structure is used to read hardware state of a TPMI feature. This + * information is used for debug and restricting operations for this feature. + */ +struct tpmi_feature_state { + u32 enabled:1; + u32 reserved_1:3; + u32 write_blocked:1; + u32 read_blocked:1; + u32 pcs_select:1; + u32 reserved_2:1; + u32 id:8; + u32 reserved_3:15; + u32 locked:1; +} __packed; + +/* + * The size from hardware is in u32 units. This size is from a trusted hardware, + * but better to verify for pre silicon platforms. Set size to 0, when invalid. + */ +#define TPMI_GET_SINGLE_ENTRY_SIZE(pfs) \ +({ \ + pfs->pfs_header.entry_size > SZ_1K ? 0 : pfs->pfs_header.entry_size << 2; \ +}) + +/* Used during auxbus device creation */ +static DEFINE_IDA(intel_vsec_tpmi_ida); + +struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev) +{ + struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + + return vsec_dev->priv_data; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_platform_data, "INTEL_TPMI"); + +int tpmi_get_resource_count(struct auxiliary_device *auxdev) +{ + struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + + if (vsec_dev) + return vsec_dev->num_resources; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_count, "INTEL_TPMI"); + +struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int index) +{ + struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + + if (vsec_dev && index < vsec_dev->num_resources) + return &vsec_dev->resource[index]; + + return NULL; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, "INTEL_TPMI"); + +/* TPMI Control Interface */ + +#define TPMI_CONTROL_STATUS_OFFSET 0x00 +#define TPMI_COMMAND_OFFSET 0x08 +#define TMPI_CONTROL_DATA_VAL_OFFSET 0x0c + +/* + * Spec is calling for max 1 seconds to get ownership at the worst + * case. Read at 10 ms timeouts and repeat up to 1 second. + */ +#define TPMI_CONTROL_TIMEOUT_US (10 * USEC_PER_MSEC) +#define TPMI_CONTROL_TIMEOUT_MAX_US (1 * USEC_PER_SEC) + +#define TPMI_RB_TIMEOUT_US (10 * USEC_PER_MSEC) +#define TPMI_RB_TIMEOUT_MAX_US USEC_PER_SEC + +/* TPMI Control status register defines */ + +#define TPMI_CONTROL_STATUS_RB BIT_ULL(0) + +#define TPMI_CONTROL_STATUS_OWNER GENMASK_ULL(5, 4) +#define TPMI_OWNER_NONE 0 +#define TPMI_OWNER_IN_BAND 1 + +#define TPMI_CONTROL_STATUS_CPL BIT_ULL(6) +#define TPMI_CONTROL_STATUS_RESULT GENMASK_ULL(15, 8) +#define TPMI_CONTROL_STATUS_LEN GENMASK_ULL(31, 16) + +#define TPMI_CMD_PKT_LEN 2 +#define TPMI_CMD_STATUS_SUCCESS 0x40 + +/* TPMI command data registers */ +#define TMPI_CONTROL_DATA_CMD GENMASK_ULL(7, 0) +#define TPMI_CONTROL_DATA_VAL_FEATURE GENMASK_ULL(48, 40) + +/* Command to send via control interface */ +#define TPMI_CONTROL_GET_STATE_CMD 0x10 + +#define TPMI_CONTROL_CMD_MASK GENMASK_ULL(48, 40) + +#define TPMI_CMD_LEN_MASK GENMASK_ULL(18, 16) + +/* Mutex to complete get feature status without interruption */ +static DEFINE_MUTEX(tpmi_dev_lock); + +static int tpmi_wait_for_owner(struct intel_tpmi_info *tpmi_info, u8 owner) +{ + u64 control; + + return readq_poll_timeout(tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET, + control, owner == FIELD_GET(TPMI_CONTROL_STATUS_OWNER, control), + TPMI_CONTROL_TIMEOUT_US, TPMI_CONTROL_TIMEOUT_MAX_US); +} + +static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int feature_id, + struct tpmi_feature_state *feature_state) +{ + u64 control, data; + int ret; + + if (!tpmi_info->tpmi_control_mem) + return -EFAULT; + + mutex_lock(&tpmi_dev_lock); + + /* Wait for owner bit set to 0 (none) */ + ret = tpmi_wait_for_owner(tpmi_info, TPMI_OWNER_NONE); + if (ret) + goto err_unlock; + + /* set command id to 0x10 for TPMI_GET_STATE */ + data = FIELD_PREP(TMPI_CONTROL_DATA_CMD, TPMI_CONTROL_GET_STATE_CMD); + + /* 32 bits for DATA offset and +8 for feature_id field */ + data |= FIELD_PREP(TPMI_CONTROL_DATA_VAL_FEATURE, feature_id); + + /* Write at command offset for qword access */ + writeq(data, tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET); + + /* Wait for owner bit set to in-band */ + ret = tpmi_wait_for_owner(tpmi_info, TPMI_OWNER_IN_BAND); + if (ret) + goto err_unlock; + + /* Set Run Busy and packet length of 2 dwords */ + control = TPMI_CONTROL_STATUS_RB; + control |= FIELD_PREP(TPMI_CONTROL_STATUS_LEN, TPMI_CMD_PKT_LEN); + + /* Write at status offset for qword access */ + writeq(control, tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET); + + /* Wait for Run Busy clear */ + ret = readq_poll_timeout(tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET, + control, !(control & TPMI_CONTROL_STATUS_RB), + TPMI_RB_TIMEOUT_US, TPMI_RB_TIMEOUT_MAX_US); + if (ret) + goto done_proc; + + control = FIELD_GET(TPMI_CONTROL_STATUS_RESULT, control); + if (control != TPMI_CMD_STATUS_SUCCESS) { + ret = -EBUSY; + goto done_proc; + } + + /* Response is ready */ + memcpy_fromio(feature_state, tpmi_info->tpmi_control_mem + TMPI_CONTROL_DATA_VAL_OFFSET, + sizeof(*feature_state)); + + ret = 0; + +done_proc: + /* Set CPL "completion" bit */ + writeq(TPMI_CONTROL_STATUS_CPL, tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET); + +err_unlock: + mutex_unlock(&tpmi_dev_lock); + + return ret; +} + +int tpmi_get_feature_status(struct auxiliary_device *auxdev, + int feature_id, bool *read_blocked, bool *write_blocked) +{ + struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); + struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); + struct tpmi_feature_state feature_state; + int ret; + + ret = tpmi_read_feature_status(tpmi_info, feature_id, &feature_state); + if (ret) + return ret; + + *read_blocked = feature_state.read_blocked; + *write_blocked = feature_state.write_blocked; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, "INTEL_TPMI"); + +struct dentry *tpmi_get_debugfs_dir(struct auxiliary_device *auxdev) +{ + struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); + struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); + + return tpmi_info->dbgfs_dir; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_debugfs_dir, "INTEL_TPMI"); + +static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused) +{ + struct intel_tpmi_info *tpmi_info = s->private; + int locked, disabled, read_blocked, write_blocked; + struct tpmi_feature_state feature_state; + struct intel_tpmi_pm_feature *pfs; + int ret, i; + + + seq_printf(s, "tpmi PFS start offset 0x:%llx\n", tpmi_info->pfs_start); + seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\tread_blocked\twrite_blocked\n"); + for (i = 0; i < tpmi_info->feature_count; ++i) { + pfs = &tpmi_info->tpmi_features[i]; + ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state); + if (ret) { + locked = 'U'; + disabled = 'U'; + read_blocked = 'U'; + write_blocked = 'U'; + } else { + disabled = feature_state.enabled ? 'N' : 'Y'; + locked = feature_state.locked ? 'Y' : 'N'; + read_blocked = feature_state.read_blocked ? 'Y' : 'N'; + write_blocked = feature_state.write_blocked ? 'Y' : 'N'; + } + seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%016llx\t%c\t%c\t\t%c\t\t%c\n", + pfs->pfs_header.tpmi_id, pfs->pfs_header.num_entries, + pfs->pfs_header.entry_size, pfs->pfs_header.cap_offset, + pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled, + read_blocked, write_blocked); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(tpmi_pfs_dbg); + +#define MEM_DUMP_COLUMN_COUNT 8 + +static int tpmi_mem_dump_show(struct seq_file *s, void *unused) +{ + size_t row_size = MEM_DUMP_COLUMN_COUNT * sizeof(u32); + struct intel_tpmi_pm_feature *pfs = s->private; + int count, ret = 0; + void __iomem *mem; + u32 size; + u64 off; + u8 *buffer; + + size = TPMI_GET_SINGLE_ENTRY_SIZE(pfs); + if (!size) + return -EIO; + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + off = pfs->vsec_offset; + + mutex_lock(&tpmi_dev_lock); + + for (count = 0; count < pfs->pfs_header.num_entries; ++count) { + seq_printf(s, "TPMI Instance:%d offset:0x%llx\n", count, off); + + mem = ioremap(off, size); + if (!mem) { + ret = -ENOMEM; + break; + } + + memcpy_fromio(buffer, mem, size); + + seq_hex_dump(s, " ", DUMP_PREFIX_OFFSET, row_size, sizeof(u32), buffer, size, + false); + + iounmap(mem); + + off += size; + } + + mutex_unlock(&tpmi_dev_lock); + + kfree(buffer); + + return ret; +} +DEFINE_SHOW_ATTRIBUTE(tpmi_mem_dump); + +static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t len, loff_t *ppos) +{ + struct seq_file *m = file->private_data; + struct intel_tpmi_pm_feature *pfs = m->private; + u32 addr, value, punit, size; + u32 num_elems, *array; + void __iomem *mem; + int ret; + + size = TPMI_GET_SINGLE_ENTRY_SIZE(pfs); + if (!size) + return -EIO; + + ret = parse_int_array_user(userbuf, len, (int **)&array); + if (ret < 0) + return ret; + + num_elems = *array; + if (num_elems != 3) { + ret = -EINVAL; + goto exit_write; + } + + punit = array[1]; + addr = array[2]; + value = array[3]; + + if (punit >= pfs->pfs_header.num_entries) { + ret = -EINVAL; + goto exit_write; + } + + if (addr >= size) { + ret = -EINVAL; + goto exit_write; + } + + mutex_lock(&tpmi_dev_lock); + + mem = ioremap(pfs->vsec_offset + punit * size, size); + if (!mem) { + ret = -ENOMEM; + goto unlock_mem_write; + } + + writel(value, mem + addr); + + iounmap(mem); + + ret = len; + +unlock_mem_write: + mutex_unlock(&tpmi_dev_lock); + +exit_write: + kfree(array); + + return ret; +} + +static int mem_write_show(struct seq_file *s, void *unused) +{ + return 0; +} + +static int mem_write_open(struct inode *inode, struct file *file) +{ + return single_open(file, mem_write_show, inode->i_private); +} + +static const struct file_operations mem_write_ops = { + .open = mem_write_open, + .read = seq_read, + .write = mem_write, + .llseek = seq_lseek, + .release = single_release, +}; + +#define tpmi_to_dev(info) (&info->vsec_dev->pcidev->dev) + +static void tpmi_dbgfs_register(struct intel_tpmi_info *tpmi_info) +{ + char name[64]; + int i; + + snprintf(name, sizeof(name), "tpmi-%s", dev_name(tpmi_to_dev(tpmi_info))); + tpmi_info->dbgfs_dir = debugfs_create_dir(name, NULL); + + debugfs_create_file("pfs_dump", 0444, tpmi_info->dbgfs_dir, tpmi_info, &tpmi_pfs_dbg_fops); + + for (i = 0; i < tpmi_info->feature_count; ++i) { + struct intel_tpmi_pm_feature *pfs; + struct dentry *dir; + + pfs = &tpmi_info->tpmi_features[i]; + snprintf(name, sizeof(name), "tpmi-id-%02x", pfs->pfs_header.tpmi_id); + dir = debugfs_create_dir(name, tpmi_info->dbgfs_dir); + + debugfs_create_file("mem_dump", 0444, dir, pfs, &tpmi_mem_dump_fops); + debugfs_create_file("mem_write", 0644, dir, pfs, &mem_write_ops); + } +} + +static void tpmi_set_control_base(struct auxiliary_device *auxdev, + struct intel_tpmi_info *tpmi_info, + struct intel_tpmi_pm_feature *pfs) +{ + void __iomem *mem; + u32 size; + + size = TPMI_GET_SINGLE_ENTRY_SIZE(pfs); + if (!size) + return; + + mem = devm_ioremap(&auxdev->dev, pfs->vsec_offset, size); + if (!mem) + return; + + /* mem is pointing to TPMI CONTROL base */ + tpmi_info->tpmi_control_mem = mem; +} + +static const char *intel_tpmi_name(enum intel_tpmi_id id) +{ + switch (id) { + case TPMI_ID_RAPL: + return "rapl"; + case TPMI_ID_PEM: + return "pem"; + case TPMI_ID_UNCORE: + return "uncore"; + case TPMI_ID_SST: + return "sst"; + case TPMI_ID_PLR: + return "plr"; + default: + return NULL; + } +} + +/* String Length for tpmi-"feature_name(upto 8 bytes)" */ +#define TPMI_FEATURE_NAME_LEN 14 + +static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, + struct intel_tpmi_pm_feature *pfs, + u64 pfs_start) +{ + struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev; + char feature_id_name[TPMI_FEATURE_NAME_LEN]; + struct intel_vsec_device *feature_vsec_dev; + struct tpmi_feature_state feature_state; + struct resource *res, *tmp; + const char *name; + int i, ret; + + ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state); + if (ret) + return ret; + + /* + * If not enabled, continue to look at other features in the PFS, so return -EOPNOTSUPP. + * This will not cause failure of loading of this driver. + */ + if (!feature_state.enabled) + return -EOPNOTSUPP; + + name = intel_tpmi_name(pfs->pfs_header.tpmi_id); + if (!name) + return -EOPNOTSUPP; + + res = kcalloc(pfs->pfs_header.num_entries, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + feature_vsec_dev = kzalloc(sizeof(*feature_vsec_dev), GFP_KERNEL); + if (!feature_vsec_dev) { + kfree(res); + return -ENOMEM; + } + + snprintf(feature_id_name, sizeof(feature_id_name), "tpmi-%s", name); + + for (i = 0, tmp = res; i < pfs->pfs_header.num_entries; i++, tmp++) { + u64 entry_size_bytes = pfs->pfs_header.entry_size * sizeof(u32); + + tmp->start = pfs->vsec_offset + entry_size_bytes * i; + tmp->end = tmp->start + entry_size_bytes - 1; + tmp->flags = IORESOURCE_MEM; + } + + feature_vsec_dev->pcidev = vsec_dev->pcidev; + feature_vsec_dev->resource = res; + feature_vsec_dev->num_resources = pfs->pfs_header.num_entries; + feature_vsec_dev->priv_data = &tpmi_info->plat_info; + feature_vsec_dev->priv_data_size = sizeof(tpmi_info->plat_info); + feature_vsec_dev->ida = &intel_vsec_tpmi_ida; + + /* + * intel_vsec_add_aux() is resource managed, no explicit + * delete is required on error or on module unload. + * feature_vsec_dev and res memory are also freed as part of + * device deletion. + */ + return intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev, + feature_vsec_dev, feature_id_name); +} + +static int tpmi_create_devices(struct intel_tpmi_info *tpmi_info) +{ + struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev; + int ret, i; + + for (i = 0; i < vsec_dev->num_resources; i++) { + ret = tpmi_create_device(tpmi_info, &tpmi_info->tpmi_features[i], + tpmi_info->pfs_start); + /* + * Fail, if the supported features fails to create device, + * otherwise, continue. Even if one device failed to create, + * fail the loading of driver. Since intel_vsec_add_aux() + * is resource managed, no clean up is required for the + * successfully created devices. + */ + if (ret && ret != -EOPNOTSUPP) + return ret; + } + + return 0; +} + +#define TPMI_INFO_BUS_INFO_OFFSET 0x08 +#define TPMI_INFO_MAJOR_VERSION 0x00 +#define TPMI_INFO_MINOR_VERSION 0x02 + +static int tpmi_process_info(struct intel_tpmi_info *tpmi_info, + struct intel_tpmi_pm_feature *pfs) +{ + struct tpmi_info_header header; + void __iomem *info_mem; + u64 feature_header; + int ret = 0; + + info_mem = ioremap(pfs->vsec_offset, pfs->pfs_header.entry_size * sizeof(u32)); + if (!info_mem) + return -ENOMEM; + + feature_header = readq(info_mem); + if (TPMI_MAJOR_VERSION(feature_header) != TPMI_INFO_MAJOR_VERSION) { + ret = -ENODEV; + goto error_info_header; + } + + memcpy_fromio(&header, info_mem + TPMI_INFO_BUS_INFO_OFFSET, sizeof(header)); + + tpmi_info->plat_info.package_id = header.pkg; + tpmi_info->plat_info.bus_number = header.bus; + tpmi_info->plat_info.device_number = header.dev; + tpmi_info->plat_info.function_number = header.fn; + + if (TPMI_MINOR_VERSION(feature_header) >= TPMI_INFO_MINOR_VERSION) { + tpmi_info->plat_info.cdie_mask = header.cdie_mask; + tpmi_info->plat_info.partition = header.partition; + tpmi_info->plat_info.segment = header.segment; + } + +error_info_header: + iounmap(info_mem); + + return ret; +} + +static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, int size) +{ + void __iomem *pfs_mem; + + pfs_mem = ioremap(start, size); + if (!pfs_mem) + return -ENOMEM; + + memcpy_fromio(&pfs->pfs_header, pfs_mem, sizeof(pfs->pfs_header)); + + iounmap(pfs_mem); + + return 0; +} + +#define TPMI_CAP_OFFSET_UNIT 1024 + +static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) +{ + struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + struct pci_dev *pci_dev = vsec_dev->pcidev; + struct intel_tpmi_info *tpmi_info; + u64 pfs_start = 0; + int ret, i; + + tpmi_info = devm_kzalloc(&auxdev->dev, sizeof(*tpmi_info), GFP_KERNEL); + if (!tpmi_info) + return -ENOMEM; + + tpmi_info->vsec_dev = vsec_dev; + tpmi_info->feature_count = vsec_dev->num_resources; + tpmi_info->plat_info.bus_number = pci_dev->bus->number; + + tpmi_info->tpmi_features = devm_kcalloc(&auxdev->dev, vsec_dev->num_resources, + sizeof(*tpmi_info->tpmi_features), + GFP_KERNEL); + if (!tpmi_info->tpmi_features) + return -ENOMEM; + + for (i = 0; i < vsec_dev->num_resources; i++) { + struct intel_tpmi_pm_feature *pfs; + struct resource *res; + u64 res_start; + int size, ret; + + pfs = &tpmi_info->tpmi_features[i]; + pfs->vsec_dev = vsec_dev; + + res = &vsec_dev->resource[i]; + if (!res) + continue; + + res_start = res->start; + size = resource_size(res); + if (size < 0) + continue; + + ret = tpmi_fetch_pfs_header(pfs, res_start, size); + if (ret) + continue; + + if (!pfs_start) + pfs_start = res_start; + + pfs->vsec_offset = pfs_start + pfs->pfs_header.cap_offset * TPMI_CAP_OFFSET_UNIT; + + /* + * Process TPMI_INFO to get PCI device to CPU package ID. + * Device nodes for TPMI features are not created in this + * for loop. So, the mapping information will be available + * when actual device nodes created outside this + * loop via tpmi_create_devices(). + */ + if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) { + ret = tpmi_process_info(tpmi_info, pfs); + if (ret) + return ret; + } + + if (pfs->pfs_header.tpmi_id == TPMI_CONTROL_ID) + tpmi_set_control_base(auxdev, tpmi_info, pfs); + } + + tpmi_info->pfs_start = pfs_start; + + auxiliary_set_drvdata(auxdev, tpmi_info); + + ret = tpmi_create_devices(tpmi_info); + if (ret) + return ret; + + /* + * Allow debugfs when security policy allows. Everything this debugfs + * interface provides, can also be done via /dev/mem access. If + * /dev/mem interface is locked, don't allow debugfs to present any + * information. Also check for CAP_SYS_RAWIO as /dev/mem interface. + */ + if (!security_locked_down(LOCKDOWN_DEV_MEM) && capable(CAP_SYS_RAWIO)) + tpmi_dbgfs_register(tpmi_info); + + return 0; +} + +static int tpmi_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + return intel_vsec_tpmi_init(auxdev); +} + +static void tpmi_remove(struct auxiliary_device *auxdev) +{ + struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(auxdev); + + debugfs_remove_recursive(tpmi_info->dbgfs_dir); +} + +static const struct auxiliary_device_id tpmi_id_table[] = { + { .name = "intel_vsec.tpmi" }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, tpmi_id_table); + +static struct auxiliary_driver tpmi_aux_driver = { + .id_table = tpmi_id_table, + .probe = tpmi_probe, + .remove = tpmi_remove, +}; + +module_auxiliary_driver(tpmi_aux_driver); + +MODULE_IMPORT_NS("INTEL_VSEC"); +MODULE_DESCRIPTION("Intel TPMI enumeration module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 5b16d29c93d7d0..3acf6149a9ecf4 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -13,6 +13,7 @@ * along with other APIs. */ +#include #include #include #include @@ -56,11 +57,11 @@ struct intel_scu_ipc_dev { struct device dev; - struct resource mem; struct module *owner; - int irq; void __iomem *ipc_base; struct completion cmd_complete; + + struct intel_scu_ipc_data data; }; #define IPC_STATUS 0x04 @@ -99,23 +100,21 @@ static struct class intel_scu_ipc_class = { */ struct intel_scu_ipc_dev *intel_scu_ipc_dev_get(void) { - struct intel_scu_ipc_dev *scu = NULL; + guard(mutex)(&ipclock); - mutex_lock(&ipclock); if (ipcdev) { get_device(&ipcdev->dev); /* * Prevent the IPC provider from being unloaded while it * is being used. */ - if (!try_module_get(ipcdev->owner)) - put_device(&ipcdev->dev); - else - scu = ipcdev; + if (try_module_get(ipcdev->owner)) + return ipcdev; + + put_device(&ipcdev->dev); } - mutex_unlock(&ipclock); - return scu; + return NULL; } EXPORT_SYMBOL_GPL(intel_scu_ipc_dev_get); @@ -217,12 +216,6 @@ static inline u8 ipc_read_status(struct intel_scu_ipc_dev *scu) return __raw_readl(scu->ipc_base + IPC_STATUS); } -/* Read ipc byte data */ -static inline u8 ipc_data_readb(struct intel_scu_ipc_dev *scu, u32 offset) -{ - return readb(scu->ipc_base + IPC_READ_BUFFER + offset); -} - /* Read ipc u32 data */ static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset) { @@ -262,7 +255,7 @@ static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu) static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu) { - return scu->irq > 0 ? ipc_wait_for_interrupt(scu) : busy_loop(scu); + return scu->data.irq > 0 ? ipc_wait_for_interrupt(scu) : busy_loop(scu); } static struct intel_scu_ipc_dev *intel_scu_ipc_get(struct intel_scu_ipc_dev *scu) @@ -295,12 +288,11 @@ static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data, memset(cbuf, 0, sizeof(cbuf)); - mutex_lock(&ipclock); + guard(mutex)(&ipclock); + scu = intel_scu_ipc_get(scu); - if (IS_ERR(scu)) { - mutex_unlock(&ipclock); + if (IS_ERR(scu)) return PTR_ERR(scu); - } for (nc = 0; nc < count; nc++, offset += 2) { cbuf[offset] = addr[nc]; @@ -325,14 +317,15 @@ static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data, } err = intel_scu_ipc_check_status(scu); - if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ - /* Workaround: values are read as 0 without memcpy_fromio */ - memcpy_fromio(cbuf, scu->ipc_base + 0x90, 16); - for (nc = 0; nc < count; nc++) - data[nc] = ipc_data_readb(scu, nc); - } - mutex_unlock(&ipclock); - return err; + if (err) + return err; + + /* Read rbuf */ + for (nc = 0, offset = 0; nc < 4; nc++, offset += 4) + wbuf[nc] = ipc_data_readl(scu, offset); + memcpy(data, wbuf, count); + + return 0; } /** @@ -453,17 +446,15 @@ int intel_scu_ipc_dev_simple_command(struct intel_scu_ipc_dev *scu, int cmd, u32 cmdval; int err; - mutex_lock(&ipclock); + guard(mutex)(&ipclock); + scu = intel_scu_ipc_get(scu); - if (IS_ERR(scu)) { - mutex_unlock(&ipclock); + if (IS_ERR(scu)) return PTR_ERR(scu); - } cmdval = sub << 12 | cmd; ipc_command(scu, cmdval); err = intel_scu_ipc_check_status(scu); - mutex_unlock(&ipclock); if (err) dev_err(&scu->dev, "IPC command %#x failed with %d\n", cmdval, err); return err; @@ -492,18 +483,17 @@ int intel_scu_ipc_dev_command_with_size(struct intel_scu_ipc_dev *scu, int cmd, { size_t outbuflen = DIV_ROUND_UP(outlen, sizeof(u32)); size_t inbuflen = DIV_ROUND_UP(inlen, sizeof(u32)); - u32 cmdval, inbuf[4] = {}; + u32 cmdval, inbuf[4] = {}, outbuf[4] = {}; int i, err; if (inbuflen > 4 || outbuflen > 4) return -EINVAL; - mutex_lock(&ipclock); + guard(mutex)(&ipclock); + scu = intel_scu_ipc_get(scu); - if (IS_ERR(scu)) { - mutex_unlock(&ipclock); + if (IS_ERR(scu)) return PTR_ERR(scu); - } memcpy(inbuf, in, inlen); for (i = 0; i < inbuflen; i++) @@ -512,20 +502,17 @@ int intel_scu_ipc_dev_command_with_size(struct intel_scu_ipc_dev *scu, int cmd, cmdval = (size << 16) | (sub << 12) | cmd; ipc_command(scu, cmdval); err = intel_scu_ipc_check_status(scu); + if (err) { + dev_err(&scu->dev, "IPC command %#x failed with %d\n", cmdval, err); + return err; + } - if (!err) { - u32 outbuf[4] = {}; - - for (i = 0; i < outbuflen; i++) - outbuf[i] = ipc_data_readl(scu, 4 * i); + for (i = 0; i < outbuflen; i++) + outbuf[i] = ipc_data_readl(scu, 4 * i); - memcpy(out, outbuf, outlen); - } + memcpy(out, outbuf, outlen); - mutex_unlock(&ipclock); - if (err) - dev_err(&scu->dev, "IPC command %#x failed with %d\n", cmdval, err); - return err; + return 0; } EXPORT_SYMBOL(intel_scu_ipc_dev_command_with_size); @@ -549,13 +536,13 @@ static irqreturn_t ioc(int irq, void *dev_id) static void intel_scu_ipc_release(struct device *dev) { - struct intel_scu_ipc_dev *scu; + struct intel_scu_ipc_dev *scu = container_of(dev, struct intel_scu_ipc_dev, dev); + struct intel_scu_ipc_data *data = &scu->data; - scu = container_of(dev, struct intel_scu_ipc_dev, dev); - if (scu->irq > 0) - free_irq(scu->irq, scu); + if (data->irq > 0) + free_irq(data->irq, scu); iounmap(scu->ipc_base); - release_mem_region(scu->mem.start, resource_size(&scu->mem)); + release_mem_region(data->mem.start, resource_size(&data->mem)); kfree(scu); } @@ -576,46 +563,44 @@ __intel_scu_ipc_register(struct device *parent, struct module *owner) { int err; + struct intel_scu_ipc_data *data; struct intel_scu_ipc_dev *scu; void __iomem *ipc_base; - mutex_lock(&ipclock); + guard(mutex)(&ipclock); + /* We support only one IPC */ - if (ipcdev) { - err = -EBUSY; - goto err_unlock; - } + if (ipcdev) + return ERR_PTR(-EBUSY); scu = kzalloc(sizeof(*scu), GFP_KERNEL); - if (!scu) { - err = -ENOMEM; - goto err_unlock; - } + if (!scu) + return ERR_PTR(-ENOMEM); scu->owner = owner; scu->dev.parent = parent; scu->dev.class = &intel_scu_ipc_class; scu->dev.release = intel_scu_ipc_release; - if (!request_mem_region(scu_data->mem.start, resource_size(&scu_data->mem), - "intel_scu_ipc")) { + memcpy(&scu->data, scu_data, sizeof(scu->data)); + data = &scu->data; + + if (!request_mem_region(data->mem.start, resource_size(&data->mem), "intel_scu_ipc")) { err = -EBUSY; goto err_free; } - ipc_base = ioremap(scu_data->mem.start, resource_size(&scu_data->mem)); + ipc_base = ioremap(data->mem.start, resource_size(&data->mem)); if (!ipc_base) { err = -ENOMEM; goto err_release; } scu->ipc_base = ipc_base; - scu->mem = scu_data->mem; - scu->irq = scu_data->irq; init_completion(&scu->cmd_complete); - if (scu->irq > 0) { - err = request_irq(scu->irq, ioc, 0, "intel_scu_ipc", scu); + if (data->irq > 0) { + err = request_irq(data->irq, ioc, 0, "intel_scu_ipc", scu); if (err) goto err_unmap; } @@ -628,24 +613,19 @@ __intel_scu_ipc_register(struct device *parent, err = device_register(&scu->dev); if (err) { put_device(&scu->dev); - goto err_unlock; + return ERR_PTR(err); } /* Assign device at last */ ipcdev = scu; - mutex_unlock(&ipclock); - return scu; err_unmap: iounmap(ipc_base); err_release: - release_mem_region(scu_data->mem.start, resource_size(&scu_data->mem)); + release_mem_region(data->mem.start, resource_size(&data->mem)); err_free: kfree(scu); -err_unlock: - mutex_unlock(&ipclock); - return ERR_PTR(err); } EXPORT_SYMBOL_GPL(__intel_scu_ipc_register); @@ -659,12 +639,12 @@ EXPORT_SYMBOL_GPL(__intel_scu_ipc_register); */ void intel_scu_ipc_unregister(struct intel_scu_ipc_dev *scu) { - mutex_lock(&ipclock); + guard(mutex)(&ipclock); + if (!WARN_ON(!ipcdev)) { ipcdev = NULL; device_unregister(&scu->dev); } - mutex_unlock(&ipclock); } EXPORT_SYMBOL_GPL(intel_scu_ipc_unregister); diff --git a/drivers/platform/x86/lenovo-ymc.c b/drivers/platform/x86/lenovo-ymc.c index bd9f95404c7cb0..470d53e3c9d299 100644 --- a/drivers/platform/x86/lenovo-ymc.c +++ b/drivers/platform/x86/lenovo-ymc.c @@ -162,4 +162,4 @@ module_wmi_driver(lenovo_ymc_driver); MODULE_AUTHOR("Gergo Koteles "); MODULE_DESCRIPTION("Lenovo Yoga Mode Control driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IDEAPAD_LAPTOP); +MODULE_IMPORT_NS("IDEAPAD_LAPTOP"); diff --git a/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c b/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c index d525bdc8ca9b3f..d2699ca24f340d 100644 --- a/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c +++ b/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c @@ -298,7 +298,7 @@ static void yt2_1380_fc_pdev_remove(struct platform_device *pdev) static struct platform_driver yt2_1380_fc_pdev_driver = { .probe = yt2_1380_fc_pdev_probe, - .remove_new = yt2_1380_fc_pdev_remove, + .remove = yt2_1380_fc_pdev_remove, .driver = { .name = YT2_1380_FC_PDEV_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/platform/x86/lenovo-yogabook.c b/drivers/platform/x86/lenovo-yogabook.c index fd62bf746ebde4..31b298dc5046f8 100644 --- a/drivers/platform/x86/lenovo-yogabook.c +++ b/drivers/platform/x86/lenovo-yogabook.c @@ -536,7 +536,7 @@ static void yogabook_pdev_remove(struct platform_device *pdev) static struct platform_driver yogabook_pdev_driver = { .probe = yogabook_pdev_probe, - .remove_new = yogabook_pdev_remove, + .remove = yogabook_pdev_remove, .driver = { .name = YB_PDEV_NAME, .pm = pm_sleep_ptr(&yogabook_pm_ops), diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 9d70146fd7420a..671021cd1f5985 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -6633,7 +6633,7 @@ static struct platform_driver mlxplat_driver = { .probe_type = PROBE_FORCE_SYNCHRONOUS, }, .probe = mlxplat_probe, - .remove_new = mlxplat_remove, + .remove = mlxplat_remove, }; static int __init mlxplat_init(void) diff --git a/drivers/platform/x86/p2sb.c b/drivers/platform/x86/p2sb.c index 31f38309b389ab..cbbb0f809704ea 100644 --- a/drivers/platform/x86/p2sb.c +++ b/drivers/platform/x86/p2sb.c @@ -25,6 +25,7 @@ static const struct x86_cpu_id p2sb_cpu_ids[] = { X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, P2SB_DEVFN_GOLDMONT), + X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS, P2SB_DEVFN_GOLDMONT), {} }; @@ -42,6 +43,7 @@ struct p2sb_res_cache { }; static struct p2sb_res_cache p2sb_resources[NR_P2SB_RES_CACHE]; +static bool p2sb_hidden_by_bios; static void p2sb_get_devfn(unsigned int *devfn) { @@ -96,6 +98,12 @@ static void p2sb_scan_and_cache_devfn(struct pci_bus *bus, unsigned int devfn) static int p2sb_scan_and_cache(struct pci_bus *bus, unsigned int devfn) { + /* + * The BIOS prevents the P2SB device from being enumerated by the PCI + * subsystem, so we need to unhide and hide it back to lookup the BAR. + */ + pci_bus_write_config_dword(bus, devfn, P2SBC, 0); + /* Scan the P2SB device and cache its BAR0 */ p2sb_scan_and_cache_devfn(bus, devfn); @@ -103,6 +111,8 @@ static int p2sb_scan_and_cache(struct pci_bus *bus, unsigned int devfn) if (devfn == P2SB_DEVFN_GOLDMONT) p2sb_scan_and_cache_devfn(bus, SPI_DEVFN_GOLDMONT); + pci_bus_write_config_dword(bus, devfn, P2SBC, P2SBC_HIDE); + if (!p2sb_valid_resource(&p2sb_resources[PCI_FUNC(devfn)].res)) return -ENOENT; @@ -128,7 +138,7 @@ static int p2sb_cache_resources(void) u32 value = P2SBC_HIDE; struct pci_bus *bus; u16 class; - int ret; + int ret = 0; /* Get devfn for P2SB device itself */ p2sb_get_devfn(&devfn_p2sb); @@ -151,22 +161,53 @@ static int p2sb_cache_resources(void) */ pci_lock_rescan_remove(); + pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value); + p2sb_hidden_by_bios = value & P2SBC_HIDE; + /* - * The BIOS prevents the P2SB device from being enumerated by the PCI - * subsystem, so we need to unhide and hide it back to lookup the BAR. - * Unhide the P2SB device here, if needed. + * If the BIOS does not hide the P2SB device then its resources + * are accesilble. Cache them only if the P2SB device is hidden. */ - pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value); - if (value & P2SBC_HIDE) - pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0); + if (p2sb_hidden_by_bios) + ret = p2sb_scan_and_cache(bus, devfn_p2sb); - ret = p2sb_scan_and_cache(bus, devfn_p2sb); + pci_unlock_rescan_remove(); - /* Hide the P2SB device, if it was hidden */ - if (value & P2SBC_HIDE) - pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, P2SBC_HIDE); + return ret; +} - pci_unlock_rescan_remove(); +static int p2sb_read_from_cache(struct pci_bus *bus, unsigned int devfn, + struct resource *mem) +{ + struct p2sb_res_cache *cache = &p2sb_resources[PCI_FUNC(devfn)]; + + if (cache->bus_dev_id != bus->dev.id) + return -ENODEV; + + if (!p2sb_valid_resource(&cache->res)) + return -ENOENT; + + memcpy(mem, &cache->res, sizeof(*mem)); + + return 0; +} + +static int p2sb_read_from_dev(struct pci_bus *bus, unsigned int devfn, + struct resource *mem) +{ + struct pci_dev *pdev; + int ret = 0; + + pdev = pci_get_slot(bus, devfn); + if (!pdev) + return -ENODEV; + + if (p2sb_valid_resource(pci_resource_n(pdev, 0))) + p2sb_read_bar0(pdev, mem); + else + ret = -ENOENT; + + pci_dev_put(pdev); return ret; } @@ -187,8 +228,6 @@ static int p2sb_cache_resources(void) */ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) { - struct p2sb_res_cache *cache; - bus = p2sb_get_bus(bus); if (!bus) return -ENODEV; @@ -196,15 +235,10 @@ int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) if (!devfn) p2sb_get_devfn(&devfn); - cache = &p2sb_resources[PCI_FUNC(devfn)]; - if (cache->bus_dev_id != bus->dev.id) - return -ENODEV; + if (p2sb_hidden_by_bios) + return p2sb_read_from_cache(bus, devfn, mem); - if (!p2sb_valid_resource(&cache->res)) - return -ENOENT; - - memcpy(mem, &cache->res, sizeof(*mem)); - return 0; + return p2sb_read_from_dev(bus, devfn, mem); } EXPORT_SYMBOL_GPL(p2sb_bar); diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 2bf94d0ab32432..22ca70eb822718 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -614,8 +614,7 @@ static ssize_t eco_mode_show(struct device *dev, struct device_attribute *attr, result = 1; break; default: - result = -EIO; - break; + return -EIO; } return sysfs_emit(buf, "%u\n", result); } @@ -761,7 +760,12 @@ static ssize_t current_brightness_store(struct device *dev, struct device_attrib static ssize_t cdpower_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sysfs_emit(buf, "%d\n", get_optd_power_state()); + int state = get_optd_power_state(); + + if (state < 0) + return state; + + return sysfs_emit(buf, "%d\n", state); } static ssize_t cdpower_store(struct device *dev, struct device_attribute *attr, diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 0d3e3ca20b1bfe..decde4c9a3d976 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -1653,5 +1653,5 @@ module_init(samsung_init); module_exit(samsung_exit); MODULE_AUTHOR("Greg Kroah-Hartman "); -MODULE_DESCRIPTION("Samsung Backlight driver"); +MODULE_DESCRIPTION("Samsung Laptop driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c index 134e2c3d91ca9b..8160d45f8a2391 100644 --- a/drivers/platform/x86/samsung-q10.c +++ b/drivers/platform/x86/samsung-q10.c @@ -78,7 +78,7 @@ static struct platform_driver samsungq10_driver = { .name = KBUILD_MODNAME, }, .probe = samsungq10_probe, - .remove_new = samsungq10_remove, + .remove = samsungq10_remove, }; static struct platform_device *samsungq10_device; diff --git a/drivers/platform/x86/sel3350-platform.c b/drivers/platform/x86/sel3350-platform.c index d09e976e714832..02e2081e2333b1 100644 --- a/drivers/platform/x86/sel3350-platform.c +++ b/drivers/platform/x86/sel3350-platform.c @@ -235,7 +235,7 @@ MODULE_DEVICE_TABLE(acpi, sel3350_device_ids); static struct platform_driver sel3350_platform_driver = { .probe = sel3350_probe, - .remove_new = sel3350_remove, + .remove = sel3350_remove, .driver = { .name = "sel3350-platform", .acpi_match_table = sel3350_device_ids, diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index 7c04cc9e5891be..ed6b28505cd66f 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -409,7 +409,7 @@ static struct platform_driver smi_driver = { .acpi_match_table = smi_acpi_ids, }, .probe = smi_probe, - .remove_new = smi_remove, + .remove = smi_remove, }; module_platform_driver(smi_driver); diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c index 5edc294de6e4ad..6ff6f3de492b99 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c @@ -37,7 +37,7 @@ static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_apollolake_probe, - .remove_new = simatic_ipc_batt_apollolake_remove, + .remove = simatic_ipc_batt_apollolake_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c index e6a56d14b505cc..83f532498c8c77 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c @@ -37,7 +37,7 @@ static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_elkhartlake_probe, - .remove_new = simatic_ipc_batt_elkhartlake_remove, + .remove = simatic_ipc_batt_elkhartlake_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c index f8849d0e48a846..c6a79338f1d0d9 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c @@ -73,7 +73,7 @@ static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_f7188x_probe, - .remove_new = simatic_ipc_batt_f7188x_remove, + .remove = simatic_ipc_batt_f7188x_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.c b/drivers/platform/x86/siemens/simatic-ipc-batt.c index d9aff10608cf28..7cfe991cba0040 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt.c @@ -239,7 +239,7 @@ static int simatic_ipc_batt_io_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_io_probe, - .remove_new = simatic_ipc_batt_io_remove, + .remove = simatic_ipc_batt_io_remove, .driver = { .name = KBUILD_MODNAME, }, diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index 4cfb53206cb848..38de0cb20d7785 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -12,6 +12,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -169,11 +170,12 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support"); */ #define LENOVO_CERT_THUMBPRINT_GUID "C59119ED-1C0D-4806-A8E9-59AA318176C4" -#define TLMI_POP_PWD BIT(0) /* Supervisor */ -#define TLMI_PAP_PWD BIT(1) /* Power-on */ -#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */ -#define TLMI_SMP_PWD BIT(6) /* System Management */ -#define TLMI_CERT BIT(7) /* Certificate Based */ +#define TLMI_POP_PWD BIT(0) /* Supervisor */ +#define TLMI_PAP_PWD BIT(1) /* Power-on */ +#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */ +#define TLMI_SMP_PWD BIT(6) /* System Management */ +#define TLMI_CERT_SVC BIT(7) /* Admin Certificate Based */ +#define TLMI_CERT_SMC BIT(8) /* System Certificate Based */ static const struct tlmi_err_codes tlmi_errs[] = { {"Success", 0}, @@ -391,7 +393,7 @@ static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr { struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); - return sysfs_emit(buf, "%d\n", setting->valid); + return sysfs_emit(buf, "%d\n", setting->pwd_enabled || setting->cert_installed); } static struct kobj_attribute auth_is_pass_set = __ATTR_RO(is_enabled); @@ -469,7 +471,12 @@ static ssize_t new_password_store(struct kobject *kobj, if (ret) goto out; - if (tlmi_priv.pwd_admin->valid) { + /* + * Note admin password is not always required if SMPControl enabled in BIOS, + * So only set if it's configured. + * Let BIOS figure it out - we'll get an error if operation is not permitted + */ + if (tlmi_priv.pwd_admin->pwd_enabled && strlen(tlmi_priv.pwd_admin->password)) { ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", tlmi_priv.pwd_admin->password); if (ret) @@ -524,6 +531,10 @@ static struct kobj_attribute auth_max_pass_length = __ATTR_RO(max_password_lengt static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { + struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); + + if (setting->cert_installed) + return sysfs_emit(buf, "certificate\n"); return sysfs_emit(buf, "password\n"); } static struct kobj_attribute auth_mechanism = __ATTR_RO(mechanism); @@ -644,6 +655,17 @@ static ssize_t level_store(struct kobject *kobj, static struct kobj_attribute auth_level = __ATTR_RW(level); +static char *cert_command(struct tlmi_pwd_setting *setting, const char *arg1, const char *arg2) +{ + /* Prepend with SVC or SMC if multicert supported */ + if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) + return kasprintf(GFP_KERNEL, "%s,%s,%s", + setting == tlmi_priv.pwd_admin ? "SVC" : "SMC", + arg1, arg2); + else + return kasprintf(GFP_KERNEL, "%s,%s", arg1, arg2); +} + static ssize_t cert_thumbprint(char *buf, const char *arg, int count) { const struct acpi_buffer input = { strlen(arg), (char *)arg }; @@ -669,18 +691,35 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count) return count; } +static char *thumbtypes[] = {"Md5", "Sha1", "Sha256"}; + static ssize_t certificate_thumbprint_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); + unsigned int i; int count = 0; + char *wmistr; if (!tlmi_priv.certificate_support || !setting->cert_installed) return -EOPNOTSUPP; - count += cert_thumbprint(buf, "Md5", count); - count += cert_thumbprint(buf, "Sha1", count); - count += cert_thumbprint(buf, "Sha256", count); + for (i = 0; i < ARRAY_SIZE(thumbtypes); i++) { + if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) { + /* Format: 'SVC | SMC, Thumbtype' */ + wmistr = kasprintf(GFP_KERNEL, "%s,%s", + setting == tlmi_priv.pwd_admin ? "SVC" : "SMC", + thumbtypes[i]); + } else { + /* Format: 'Thumbtype' */ + wmistr = kasprintf(GFP_KERNEL, "%s", thumbtypes[i]); + } + if (!wmistr) + return -ENOMEM; + count += cert_thumbprint(buf, wmistr, count); + kfree(wmistr); + } + return count; } @@ -712,7 +751,7 @@ static ssize_t cert_to_password_store(struct kobject *kobj, return -ENOMEM; /* Format: 'Password,Signature' */ - auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature); + auth_str = cert_command(setting, passwd, setting->signature); if (!auth_str) { kfree_sensitive(passwd); return -ENOMEM; @@ -726,12 +765,19 @@ static ssize_t cert_to_password_store(struct kobject *kobj, static struct kobj_attribute auth_cert_to_password = __ATTR_WO(cert_to_password); +enum cert_install_mode { + TLMI_CERT_INSTALL, + TLMI_CERT_UPDATE, +}; + static ssize_t certificate_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj); + enum cert_install_mode install_mode = TLMI_CERT_INSTALL; char *auth_str, *new_cert; + char *signature; char *guid; int ret; @@ -748,9 +794,9 @@ static ssize_t certificate_store(struct kobject *kobj, return -EACCES; /* Format: 'serial#, signature' */ - auth_str = kasprintf(GFP_KERNEL, "%s,%s", - dmi_get_system_info(DMI_PRODUCT_SERIAL), - setting->signature); + auth_str = cert_command(setting, + dmi_get_system_info(DMI_PRODUCT_SERIAL), + setting->signature); if (!auth_str) return -ENOMEM; @@ -767,24 +813,44 @@ static ssize_t certificate_store(struct kobject *kobj, if (setting->cert_installed) { /* Certificate is installed so this is an update */ - if (!setting->signature || !setting->signature[0]) { + install_mode = TLMI_CERT_UPDATE; + /* If admin account enabled - need to use its signature */ + if (tlmi_priv.pwd_admin->pwd_enabled) + signature = tlmi_priv.pwd_admin->signature; + else + signature = setting->signature; + } else { /* Cert install */ + /* Check if SMC and SVC already installed */ + if ((setting == tlmi_priv.pwd_system) && tlmi_priv.pwd_admin->cert_installed) { + /* This gets treated as a cert update */ + install_mode = TLMI_CERT_UPDATE; + signature = tlmi_priv.pwd_admin->signature; + } else { /* Regular cert install */ + install_mode = TLMI_CERT_INSTALL; + signature = setting->signature; + } + } + + if (install_mode == TLMI_CERT_UPDATE) { + /* This is a certificate update */ + if (!signature || !signature[0]) { kfree(new_cert); return -EACCES; } guid = LENOVO_UPDATE_BIOS_CERT_GUID; /* Format: 'Certificate,Signature' */ - auth_str = kasprintf(GFP_KERNEL, "%s,%s", - new_cert, setting->signature); + auth_str = cert_command(setting, new_cert, signature); } else { /* This is a fresh install */ - if (!setting->valid || !setting->password[0]) { + /* To set admin cert, a password must be enabled */ + if ((setting == tlmi_priv.pwd_admin) && + (!setting->pwd_enabled || !setting->password[0])) { kfree(new_cert); return -EACCES; } guid = LENOVO_SET_BIOS_CERT_GUID; - /* Format: 'Certificate,Admin-password' */ - auth_str = kasprintf(GFP_KERNEL, "%s,%s", - new_cert, setting->password); + /* Format: 'Certificate, password' */ + auth_str = cert_command(setting, new_cert, setting->password); } kfree(new_cert); if (!auth_str) @@ -864,14 +930,19 @@ static umode_t auth_attr_is_visible(struct kobject *kobj, return 0; } - /* We only display certificates on Admin account, if supported */ + /* We only display certificates, if supported */ if (attr == &auth_certificate.attr || attr == &auth_signature.attr || attr == &auth_save_signature.attr || attr == &auth_cert_thumb.attr || attr == &auth_cert_to_password.attr) { - if ((setting == tlmi_priv.pwd_admin) && tlmi_priv.certificate_support) - return attr->mode; + if (tlmi_priv.certificate_support) { + if (setting == tlmi_priv.pwd_admin) + return attr->mode; + if ((tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) && + (setting == tlmi_priv.pwd_system)) + return attr->mode; + } return 0; } @@ -1019,7 +1090,7 @@ static ssize_t current_value_store(struct kobject *kobj, * Workstation's require the opcode to be set before changing the * attribute. */ - if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { + if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) { ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", tlmi_priv.pwd_admin->password); if (ret) @@ -1042,7 +1113,7 @@ static ssize_t current_value_store(struct kobject *kobj, else ret = tlmi_save_bios_settings(""); } else { /* old non-opcode based authentication method (deprecated) */ - if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { + if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) { auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", tlmi_priv.pwd_admin->password, encoding_options[tlmi_priv.pwd_admin->encoding], @@ -1215,7 +1286,7 @@ static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute * if (ret) goto out; } else if (tlmi_priv.opcode_support) { - if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { + if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) { ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", tlmi_priv.pwd_admin->password); if (ret) @@ -1223,7 +1294,7 @@ static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute * } ret = tlmi_save_bios_settings(""); } else { /* old non-opcode based authentication method (deprecated) */ - if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { + if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) { auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", tlmi_priv.pwd_admin->password, encoding_options[tlmi_priv.pwd_admin->encoding], @@ -1273,7 +1344,7 @@ static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr if (!new_setting) return -ENOMEM; - if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { + if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) { auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", tlmi_priv.pwd_admin->password, encoding_options[tlmi_priv.pwd_admin->encoding], @@ -1637,14 +1708,14 @@ static int tlmi_analyze(void) goto fail_clear_attr; if (tlmi_priv.pwdcfg.core.password_state & TLMI_PAP_PWD) - tlmi_priv.pwd_admin->valid = true; + tlmi_priv.pwd_admin->pwd_enabled = true; tlmi_priv.pwd_power = tlmi_create_auth("pop", "power-on"); if (!tlmi_priv.pwd_power) goto fail_clear_attr; if (tlmi_priv.pwdcfg.core.password_state & TLMI_POP_PWD) - tlmi_priv.pwd_power->valid = true; + tlmi_priv.pwd_power->pwd_enabled = true; if (tlmi_priv.opcode_support) { tlmi_priv.pwd_system = tlmi_create_auth("smp", "system"); @@ -1652,7 +1723,7 @@ static int tlmi_analyze(void) goto fail_clear_attr; if (tlmi_priv.pwdcfg.core.password_state & TLMI_SMP_PWD) - tlmi_priv.pwd_system->valid = true; + tlmi_priv.pwd_system->pwd_enabled = true; tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd"); if (!tlmi_priv.pwd_hdd) @@ -1670,7 +1741,7 @@ static int tlmi_analyze(void) /* Check if PWD is configured and set index to first drive found */ if (tlmi_priv.pwdcfg.ext.hdd_user_password || tlmi_priv.pwdcfg.ext.hdd_master_password) { - tlmi_priv.pwd_hdd->valid = true; + tlmi_priv.pwd_hdd->pwd_enabled = true; if (tlmi_priv.pwdcfg.ext.hdd_master_password) tlmi_priv.pwd_hdd->index = ffs(tlmi_priv.pwdcfg.ext.hdd_master_password) - 1; @@ -1680,7 +1751,7 @@ static int tlmi_analyze(void) } if (tlmi_priv.pwdcfg.ext.nvme_user_password || tlmi_priv.pwdcfg.ext.nvme_master_password) { - tlmi_priv.pwd_nvme->valid = true; + tlmi_priv.pwd_nvme->pwd_enabled = true; if (tlmi_priv.pwdcfg.ext.nvme_master_password) tlmi_priv.pwd_nvme->index = ffs(tlmi_priv.pwdcfg.ext.nvme_master_password) - 1; @@ -1691,10 +1762,12 @@ static int tlmi_analyze(void) } } - if (tlmi_priv.certificate_support && - (tlmi_priv.pwdcfg.core.password_state & TLMI_CERT)) - tlmi_priv.pwd_admin->cert_installed = true; - + if (tlmi_priv.certificate_support) { + tlmi_priv.pwd_admin->cert_installed = + tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SVC; + tlmi_priv.pwd_system->cert_installed = + tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SMC; + } return 0; fail_clear_attr: diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h index e1975ffebeb42d..f267d8b46957e6 100644 --- a/drivers/platform/x86/think-lmi.h +++ b/drivers/platform/x86/think-lmi.h @@ -41,6 +41,10 @@ enum save_mode { }; /* password configuration details */ +#define TLMI_PWDCFG_MODE_LEGACY 0 +#define TLMI_PWDCFG_MODE_PASSWORD 1 +#define TLMI_PWDCFG_MODE_MULTICERT 3 + struct tlmi_pwdcfg_core { uint32_t password_mode; uint32_t password_state; @@ -65,7 +69,7 @@ struct tlmi_pwdcfg { /* password setting details */ struct tlmi_pwd_setting { struct kobject kobj; - bool valid; + bool pwd_enabled; char password[TLMI_PWD_BUFSIZE]; const char *pwd_type; const char *role; diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 0a39f68c641d15..bdc19cd8d3edf7 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -855,6 +855,23 @@ static const struct ts_dmi_data rwc_nanote_next_data = { .properties = rwc_nanote_next_props, }; +static const struct property_entry sary_tab_3_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1730), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1151), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-sary-tab-3.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data sary_tab_3_data = { + .acpi_name = "MSSL1680:00", + .properties = sary_tab_3_props, +}; + static const struct property_entry schneider_sct101ctm_props[] = { PROPERTY_ENTRY_U32("touchscreen-size-x", 1715), PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), @@ -1615,6 +1632,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_BIOS_VERSION, "S8A70R100-V005"), }, }, + { + /* SARY Tab 3 */ + .driver_data = (void *)&sary_tab_3_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SARY"), + DMI_MATCH(DMI_PRODUCT_NAME, "C210C"), + DMI_MATCH(DMI_PRODUCT_SKU, "TAB3"), + }, + }, { /* Schneider SCT101CTM */ .driver_data = (void *)&schneider_sct101ctm_data, diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 3cbe180c3fc0a4..646370bd6b0388 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -37,8 +36,6 @@ MODULE_AUTHOR("Carlos Corbacho"); MODULE_DESCRIPTION("ACPI-WMI Mapping Driver"); MODULE_LICENSE("GPL"); -static LIST_HEAD(wmi_block_list); - struct guid_block { guid_t guid; union { @@ -63,7 +60,6 @@ enum { /* wmi_block flags */ struct wmi_block { struct wmi_device dev; - struct list_head list; struct guid_block gblock; struct acpi_device *acpi_device; struct rw_semaphore notify_lock; /* Protects notify callback add/remove */ @@ -73,6 +69,10 @@ struct wmi_block { unsigned long flags; }; +struct wmi_guid_count_context { + const guid_t *guid; + int count; +}; /* * If the GUID data block is marked as expensive, we must enable and @@ -91,7 +91,6 @@ static const struct acpi_device_id wmi_device_ids[] = { MODULE_DEVICE_TABLE(acpi, wmi_device_ids); #define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev) -#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev) /* * GUID parsing functions @@ -199,7 +198,7 @@ static struct wmi_device *wmi_find_device_by_guid(const char *guid_string) if (!dev) return ERR_PTR(-ENODEV); - return dev_to_wdev(dev); + return to_wmi_device(dev); } static void wmi_device_put(struct wmi_device *wdev) @@ -654,8 +653,6 @@ char *wmi_get_acpi_device_uid(const char *guid_string) } EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid); -#define drv_to_wdrv(__drv) container_of_const(__drv, struct wmi_driver, driver) - /* * sysfs interface */ @@ -761,7 +758,7 @@ static DEVICE_ATTR_RO(object_id); static ssize_t setable_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct wmi_device *wdev = dev_to_wdev(dev); + struct wmi_device *wdev = to_wmi_device(dev); return sysfs_emit(buf, "%d\n", (int)wdev->setable); } @@ -803,7 +800,7 @@ static void wmi_dev_release(struct device *dev) static int wmi_dev_match(struct device *dev, const struct device_driver *driver) { - const struct wmi_driver *wmi_driver = drv_to_wdrv(driver); + const struct wmi_driver *wmi_driver = to_wmi_driver(driver); struct wmi_block *wblock = dev_to_wblock(dev); const struct wmi_device_id *id = wmi_driver->id_table; @@ -827,7 +824,7 @@ static int wmi_dev_match(struct device *dev, const struct device_driver *driver) static int wmi_dev_probe(struct device *dev) { struct wmi_block *wblock = dev_to_wblock(dev); - struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); + struct wmi_driver *wdriver = to_wmi_driver(dev->driver); int ret = 0; /* Some older WMI drivers will break if instantiated multiple times, @@ -851,7 +848,7 @@ static int wmi_dev_probe(struct device *dev) dev_warn(dev, "failed to enable device -- probing anyway\n"); if (wdriver->probe) { - ret = wdriver->probe(dev_to_wdev(dev), + ret = wdriver->probe(to_wmi_device(dev), find_guid_context(wblock, wdriver)); if (ret) { if (ACPI_FAILURE(wmi_method_enable(wblock, false))) @@ -871,19 +868,45 @@ static int wmi_dev_probe(struct device *dev) static void wmi_dev_remove(struct device *dev) { struct wmi_block *wblock = dev_to_wblock(dev); - struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); + struct wmi_driver *wdriver = to_wmi_driver(dev->driver); down_write(&wblock->notify_lock); wblock->driver_ready = false; up_write(&wblock->notify_lock); if (wdriver->remove) - wdriver->remove(dev_to_wdev(dev)); + wdriver->remove(to_wmi_device(dev)); if (ACPI_FAILURE(wmi_method_enable(wblock, false))) dev_warn(dev, "failed to disable device\n"); } +static void wmi_dev_shutdown(struct device *dev) +{ + struct wmi_driver *wdriver; + struct wmi_block *wblock; + + if (dev->driver) { + wdriver = to_wmi_driver(dev->driver); + wblock = dev_to_wblock(dev); + + /* + * Some machines return bogus WMI event data when disabling + * the WMI event. Because of this we must prevent the associated + * WMI driver from receiving new WMI events before disabling it. + */ + down_write(&wblock->notify_lock); + wblock->driver_ready = false; + up_write(&wblock->notify_lock); + + if (wdriver->shutdown) + wdriver->shutdown(to_wmi_device(dev)); + + if (ACPI_FAILURE(wmi_method_enable(wblock, false))) + dev_warn(dev, "Failed to disable device\n"); + } +} + static struct class wmi_bus_class = { .name = "wmi_bus", }; @@ -895,6 +918,7 @@ static const struct bus_type wmi_bus_type = { .uevent = wmi_dev_uevent, .probe = wmi_dev_probe, .remove = wmi_dev_remove, + .shutdown = wmi_dev_shutdown, }; static const struct device_type wmi_type_event = { @@ -915,21 +939,30 @@ static const struct device_type wmi_type_data = { .release = wmi_dev_release, }; -/* - * _WDG is a static list that is only parsed at startup, - * so it's safe to count entries without extra protection. - */ +static int wmi_count_guids(struct device *dev, void *data) +{ + struct wmi_guid_count_context *context = data; + struct wmi_block *wblock = dev_to_wblock(dev); + + if (guid_equal(&wblock->gblock.guid, context->guid)) + context->count++; + + return 0; +} + static int guid_count(const guid_t *guid) { - struct wmi_block *wblock; - int count = 0; + struct wmi_guid_count_context context = { + .guid = guid, + .count = 0, + }; + int ret; - list_for_each_entry(wblock, &wmi_block_list, list) { - if (guid_equal(&wblock->gblock.guid, guid)) - count++; - } + ret = bus_for_each_dev(&wmi_bus_type, NULL, &context, wmi_count_guids); + if (ret < 0) + return ret; - return count; + return context.count; } static int wmi_create_device(struct device *wmi_bus_dev, @@ -940,7 +973,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, struct acpi_device_info *info; acpi_handle method_handle; acpi_status status; - uint count; + int count; if (wblock->gblock.flags & ACPI_WMI_EVENT) { wblock->dev.dev.type = &wmi_type_event; @@ -1008,6 +1041,9 @@ static int wmi_create_device(struct device *wmi_bus_dev, wblock->dev.dev.parent = wmi_bus_dev; count = guid_count(&wblock->gblock.guid); + if (count < 0) + return count; + if (count) { dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, count); set_bit(WMI_GUID_DUPLICATED, &wblock->flags); @@ -1093,14 +1129,11 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev) continue; } - list_add_tail(&wblock->list, &wmi_block_list); - retval = wmi_add_device(pdev, &wblock->dev); if (retval) { dev_err(wmi_bus_dev, "failed to register %pUL\n", &wblock->gblock.guid); - list_del(&wblock->list); put_device(&wblock->dev.dev); } } @@ -1138,7 +1171,7 @@ static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj) { - struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver); + struct wmi_driver *driver = to_wmi_driver(wblock->dev.dev.driver); if (!obj && !driver->no_notify_data) { dev_warn(&wblock->dev.dev, "Event contains no event data\n"); @@ -1200,9 +1233,6 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, void *context static int wmi_remove_device(struct device *dev, void *data) { - struct wmi_block *wblock = dev_to_wblock(dev); - - list_del(&wblock->list); device_unregister(dev); return 0; @@ -1301,7 +1331,7 @@ static struct platform_driver acpi_wmi_driver = { .acpi_match_table = wmi_device_ids, }, .probe = acpi_wmi_probe, - .remove_new = acpi_wmi_remove, + .remove = acpi_wmi_remove, }; static int __init acpi_wmi_init(void) diff --git a/drivers/platform/x86/x86-android-tablets/Kconfig b/drivers/platform/x86/x86-android-tablets/Kconfig index 88d9e8f2ff24ec..a67bddc4300757 100644 --- a/drivers/platform/x86/x86-android-tablets/Kconfig +++ b/drivers/platform/x86/x86-android-tablets/Kconfig @@ -5,7 +5,9 @@ config X86_ANDROID_TABLETS tristate "X86 Android tablet support" - depends on I2C && SPI && SERIAL_DEV_BUS && ACPI && EFI && GPIOLIB && PMIC_OPREGION + depends on I2C && SPI && SERIAL_DEV_BUS + depends on GPIOLIB && PMIC_OPREGION + depends on ACPI && EFI && PCI select NEW_LEDS select LEDS_CLASS help diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index ef572b90e06ba4..4218afcec0e9b7 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -11,11 +11,13 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include #include #include +#include #include #include #include @@ -155,26 +157,66 @@ static struct gpiod_lookup_table * const *gpiod_lookup_tables; static const struct software_node *bat_swnode; static void (*exit_handler)(void); +static struct i2c_adapter * +get_i2c_adap_by_handle(const struct x86_i2c_client_info *client_info) +{ + acpi_handle handle; + acpi_status status; + + status = acpi_get_handle(NULL, client_info->adapter_path, &handle); + if (ACPI_FAILURE(status)) { + pr_err("Error could not get %s handle\n", client_info->adapter_path); + return NULL; + } + + return i2c_acpi_find_adapter_by_handle(handle); +} + +static __init int match_parent(struct device *dev, const void *data) +{ + return dev->parent == data; +} + +static struct i2c_adapter * +get_i2c_adap_by_pci_parent(const struct x86_i2c_client_info *client_info) +{ + struct i2c_adapter *adap = NULL; + struct device *pdev, *adap_dev; + + pdev = bus_find_device_by_name(&pci_bus_type, NULL, client_info->adapter_path); + if (!pdev) { + pr_err("Error could not find %s PCI device\n", client_info->adapter_path); + return NULL; + } + + adap_dev = bus_find_device(&i2c_bus_type, NULL, pdev, match_parent); + if (adap_dev) { + adap = i2c_verify_adapter(adap_dev); + if (!adap) + put_device(adap_dev); + } + + put_device(pdev); + + return adap; +} + static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info, int idx) { const struct x86_i2c_client_info *client_info = &dev_info->i2c_client_info[idx]; struct i2c_board_info board_info = client_info->board_info; struct i2c_adapter *adap; - acpi_handle handle; - acpi_status status; board_info.irq = x86_acpi_irq_helper_get(&client_info->irq_data); if (board_info.irq < 0) return board_info.irq; - status = acpi_get_handle(NULL, client_info->adapter_path, &handle); - if (ACPI_FAILURE(status)) { - pr_err("Error could not get %s handle\n", client_info->adapter_path); - return -ENODEV; - } + if (dev_info->use_pci_devname) + adap = get_i2c_adap_by_pci_parent(client_info); + else + adap = get_i2c_adap_by_handle(client_info); - adap = i2c_acpi_find_adapter_by_handle(handle); if (!adap) { pr_err("error could not get %s adapter\n", client_info->adapter_path); return -ENODEV; @@ -458,7 +500,7 @@ static struct platform_driver x86_android_tablet_driver = { .driver = { .name = KBUILD_MODNAME, }, - .remove_new = x86_android_tablet_remove, + .remove = x86_android_tablet_remove, }; static int __init x86_android_tablet_init(void) diff --git a/drivers/platform/x86/x86-android-tablets/dmi.c b/drivers/platform/x86/x86-android-tablets/dmi.c index 17f6da96aa016e..3e5fa3b6e2fdfe 100644 --- a/drivers/platform/x86/x86-android-tablets/dmi.c +++ b/drivers/platform/x86/x86-android-tablets/dmi.c @@ -179,6 +179,16 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = { }, .driver_data = (void *)&peaq_c1010_info, }, + { + /* Vexia Edu Atla 10 tablet 9V version */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), + }, + .driver_data = (void *)&vexia_edu_atla10_info, + }, { /* Whitelabel (sold as various brands) TM800A550L */ .matches = { diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index 7db8aa58b90790..735df818f76bfe 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,7 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = { /* Novatek NVT-ts touchscreen */ .board_info = { - .type = "NVT-ts", + .type = "nt11205-ts", .addr = 0x34, .dev_name = "NVT-ts", }, @@ -597,6 +598,168 @@ const struct x86_dev_info whitelabel_tm800a550l_info __initconst = { .gpiod_lookup_tables = whitelabel_tm800a550l_gpios, }; +/* + * Vexia EDU ATLA 10 tablet, Android 4.2 / 4.4 + Guadalinex Ubuntu tablet + * distributed to schools in the Spanish Andalucía region. + */ +const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" }; + +static const struct property_entry vexia_edu_atla10_ulpmc_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy), + { } +}; + +const struct software_node vexia_edu_atla10_ulpmc_node = { + .properties = vexia_edu_atla10_ulpmc_props, +}; + +static const char * const vexia_edu_atla10_accel_mount_matrix[] = { + "0", "-1", "0", + "1", "0", "0", + "0", "0", "1" +}; + +static const struct property_entry vexia_edu_atla10_accel_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_accel_mount_matrix), + { } +}; + +static const struct software_node vexia_edu_atla10_accel_node = { + .properties = vexia_edu_atla10_accel_props, +}; + +static const struct property_entry vexia_edu_atla10_touchscreen_props[] = { + PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000), + PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120), + { } +}; + +static const struct software_node vexia_edu_atla10_touchscreen_node = { + .properties = vexia_edu_atla10_touchscreen_props, +}; + +static const struct property_entry vexia_edu_atla10_pmic_props[] = { + PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"), + { } +}; + +static const struct software_node vexia_edu_atla10_pmic_node = { + .properties = vexia_edu_atla10_pmic_props, +}; + +static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initconst = { + { + /* I2C attached embedded controller, used to access fuel-gauge */ + .board_info = { + .type = "vexia_atla10_ec", + .addr = 0x76, + .dev_name = "ulpmc", + .swnode = &vexia_edu_atla10_ulpmc_node, + }, + .adapter_path = "0000:00:18.1", + }, { + /* RT5642 audio codec */ + .board_info = { + .type = "rt5640", + .addr = 0x1c, + .dev_name = "rt5640", + }, + .adapter_path = "0000:00:18.2", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 4, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + .con_id = "rt5640_irq", + }, + }, { + /* kxtj21009 accelerometer */ + .board_info = { + .type = "kxtj21009", + .addr = 0x0f, + .dev_name = "kxtj21009", + .swnode = &vexia_edu_atla10_accel_node, + }, + .adapter_path = "0000:00:18.5", + }, { + /* FT5416DQ9 touchscreen controller */ + .board_info = { + .type = "hid-over-i2c", + .addr = 0x38, + .dev_name = "FTSC1000", + .swnode = &vexia_edu_atla10_touchscreen_node, + }, + .adapter_path = "0000:00:18.6", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_APIC, + .index = 0x45, + .trigger = ACPI_LEVEL_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + }, + }, { + /* Crystal Cove PMIC */ + .board_info = { + .type = "intel_soc_pmic_crc", + .addr = 0x6e, + .dev_name = "intel_soc_pmic_crc", + .swnode = &vexia_edu_atla10_pmic_node, + }, + .adapter_path = "0000:00:18.7", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_APIC, + .index = 0x43, + .trigger = ACPI_LEVEL_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + }, + } +}; + +static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = { + .dev_id = "i2c-FTSC1000", + .table = { + GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW), + { } + }, +}; + +static struct gpiod_lookup_table * const vexia_edu_atla10_gpios[] = { + &vexia_edu_atla10_ft5416_gpios, + NULL +}; + +static int __init vexia_edu_atla10_init(struct device *dev) +{ + struct pci_dev *pdev; + int ret; + + /* Enable the Wifi module by setting the wifi_enable pin to 1 */ + ret = x86_android_tablet_get_gpiod("INT33FC:02", 20, "wifi_enable", + false, GPIOD_OUT_HIGH, NULL); + if (ret) + return ret; + + /* Reprobe the SDIO controller to enumerate the now enabled Wifi module */ + pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x11, 0)); + if (!pdev) + return -EPROBE_DEFER; + + ret = device_reprobe(&pdev->dev); + if (ret) + pci_warn(pdev, "Reprobing error: %d\n", ret); + + pci_dev_put(pdev); + return 0; +} + +const struct x86_dev_info vexia_edu_atla10_info __initconst = { + .i2c_client_info = vexia_edu_atla10_i2c_clients, + .i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_i2c_clients), + .gpiod_lookup_tables = vexia_edu_atla10_gpios, + .init = vexia_edu_atla10_init, + .use_pci_devname = true, +}; + /* * The firmware node for ktd2026 on Xaomi pad2. It composed of a RGB LED node * with three subnodes for each color (B/G/R). The RGB LED node is named diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index 5517e438c7b69a..0fc7e8cff6728c 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -91,6 +91,7 @@ struct x86_dev_info { int gpio_button_count; int (*init)(struct device *dev); void (*exit)(void); + bool use_pci_devname; }; int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id, @@ -119,6 +120,7 @@ extern const struct x86_dev_info nextbook_ares8_info; extern const struct x86_dev_info nextbook_ares8a_info; extern const struct x86_dev_info peaq_c1010_info; extern const struct x86_dev_info whitelabel_tm800a550l_info; +extern const struct x86_dev_info vexia_edu_atla10_info; extern const struct x86_dev_info xiaomi_mipad2_info; extern const struct dmi_system_id x86_android_tablet_ids[]; diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c index 5fe68296501c44..5fedb99b9d944c 100644 --- a/drivers/platform/x86/xo1-rfkill.c +++ b/drivers/platform/x86/xo1-rfkill.c @@ -68,7 +68,7 @@ static struct platform_driver xo1_rfkill_driver = { .name = "xo1-rfkill", }, .probe = xo1_rfkill_probe, - .remove_new = xo1_rfkill_remove, + .remove = xo1_rfkill_remove, }; module_platform_driver(xo1_rfkill_driver); diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 29ad510e881c39..bb11f467dc78c7 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -1727,6 +1727,7 @@ static void genpd_free_dev_data(struct device *dev, spin_unlock_irq(&dev->power.lock); + dev_pm_opp_clear_config(gpd_data->opp_token); kfree(gpd_data->td); kfree(gpd_data); dev_pm_put_subsys_data(dev); @@ -2171,8 +2172,24 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd) } genpd->gd = gd; - return 0; + device_initialize(&genpd->dev); + + if (!genpd_is_dev_name_fw(genpd)) { + dev_set_name(&genpd->dev, "%s", genpd->name); + } else { + ret = ida_alloc(&genpd_ida, GFP_KERNEL); + if (ret < 0) + goto put; + genpd->device_id = ret; + dev_set_name(&genpd->dev, "%s_%u", genpd->name, genpd->device_id); + } + + return 0; +put: + put_device(&genpd->dev); + if (genpd->free_states == genpd_free_default_power_state) + kfree(genpd->states); free: if (genpd_is_cpu_domain(genpd)) free_cpumask_var(genpd->cpus); @@ -2182,6 +2199,9 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd) static void genpd_free_data(struct generic_pm_domain *genpd) { + put_device(&genpd->dev); + if (genpd->device_id != -ENXIO) + ida_free(&genpd_ida, genpd->device_id); if (genpd_is_cpu_domain(genpd)) free_cpumask_var(genpd->cpus); if (genpd->free_states) @@ -2270,20 +2290,6 @@ int pm_genpd_init(struct generic_pm_domain *genpd, if (ret) return ret; - device_initialize(&genpd->dev); - - if (!genpd_is_dev_name_fw(genpd)) { - dev_set_name(&genpd->dev, "%s", genpd->name); - } else { - ret = ida_alloc(&genpd_ida, GFP_KERNEL); - if (ret < 0) { - put_device(&genpd->dev); - return ret; - } - genpd->device_id = ret; - dev_set_name(&genpd->dev, "%s_%u", genpd->name, genpd->device_id); - } - mutex_lock(&gpd_list_lock); list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); @@ -2324,8 +2330,6 @@ static int genpd_remove(struct generic_pm_domain *genpd) genpd_unlock(genpd); genpd_debug_remove(genpd); cancel_work_sync(&genpd->power_off_work); - if (genpd->device_id != -ENXIO) - ida_free(&genpd_ida, genpd->device_id); genpd_free_data(genpd); pr_debug("%s: removed %s\n", __func__, dev_name(&genpd->dev)); @@ -2903,12 +2907,58 @@ static void genpd_dev_pm_sync(struct device *dev) genpd_queue_power_off_work(pd); } +static int genpd_set_required_opp_dev(struct device *dev, + struct device *base_dev) +{ + struct dev_pm_opp_config config = { + .required_dev = dev, + }; + int ret; + + /* Limit support to non-providers for now. */ + if (of_property_present(base_dev->of_node, "#power-domain-cells")) + return 0; + + if (!dev_pm_opp_of_has_required_opp(base_dev)) + return 0; + + ret = dev_pm_opp_set_config(base_dev, &config); + if (ret < 0) + return ret; + + dev_gpd_data(dev)->opp_token = ret; + return 0; +} + +static int genpd_set_required_opp(struct device *dev, unsigned int index) +{ + int ret, pstate; + + /* Set the default performance state */ + pstate = of_get_required_opp_performance_state(dev->of_node, index); + if (pstate < 0 && pstate != -ENODEV && pstate != -EOPNOTSUPP) { + ret = pstate; + goto err; + } else if (pstate > 0) { + ret = dev_pm_genpd_set_performance_state(dev, pstate); + if (ret) + goto err; + dev_gpd_data(dev)->default_pstate = pstate; + } + + return 0; +err: + dev_err(dev, "failed to set required performance state for power-domain %s: %d\n", + dev_to_genpd(dev)->name, ret); + return ret; +} + static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev, - unsigned int index, bool power_on) + unsigned int index, unsigned int num_domains, + bool power_on) { struct of_phandle_args pd_args; struct generic_pm_domain *pd; - int pstate; int ret; ret = of_parse_phandle_with_args(dev->of_node, "power-domains", @@ -2937,18 +2987,21 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev, dev->pm_domain->detach = genpd_dev_pm_detach; dev->pm_domain->sync = genpd_dev_pm_sync; - /* Set the default performance state */ - pstate = of_get_required_opp_performance_state(dev->of_node, index); - if (pstate < 0 && pstate != -ENODEV && pstate != -EOPNOTSUPP) { - ret = pstate; - goto err; - } else if (pstate > 0) { - ret = dev_pm_genpd_set_performance_state(dev, pstate); + /* + * For a single PM domain the index of the required OPP must be zero, so + * let's try to assign a required dev in that case. In the multiple PM + * domains case, we need platform code to specify the index. + */ + if (num_domains == 1) { + ret = genpd_set_required_opp_dev(dev, base_dev); if (ret) goto err; - dev_gpd_data(dev)->default_pstate = pstate; } + ret = genpd_set_required_opp(dev, index); + if (ret) + goto err; + if (power_on) { genpd_lock(pd); ret = genpd_power_on(pd, 0); @@ -2969,8 +3022,6 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev, return 1; err: - dev_err(dev, "failed to set required performance state for power-domain %s: %d\n", - pd->name, ret); genpd_remove_device(pd, dev); return ret; } @@ -3001,7 +3052,7 @@ int genpd_dev_pm_attach(struct device *dev) "#power-domain-cells") != 1) return 0; - return __genpd_dev_pm_attach(dev, dev, 0, true); + return __genpd_dev_pm_attach(dev, dev, 0, 1, true); } EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); @@ -3054,7 +3105,7 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev, } /* Try to attach the device to the PM domain at the specified index. */ - ret = __genpd_dev_pm_attach(virt_dev, dev, index, false); + ret = __genpd_dev_pm_attach(virt_dev, dev, index, num_domains, false); if (ret < 1) { device_unregister(virt_dev); return ret ? ERR_PTR(ret) : NULL; diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index 80a4dcc77199cf..f18c7e6e75ddc5 100644 --- a/drivers/pmdomain/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c @@ -233,7 +233,7 @@ static struct platform_driver imx_pgc_power_domain_driver = { .name = "imx-pgc-pd", }, .probe = imx_pgc_power_domain_probe, - .remove_new = imx_pgc_power_domain_remove, + .remove = imx_pgc_power_domain_remove, .id_table = imx_pgc_power_domain_id, }; builtin_platform_driver(imx_pgc_power_domain_driver) @@ -411,7 +411,7 @@ static int imx_gpc_probe(struct platform_device *pdev) pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); /* bail out if DT too old and doesn't provide the necessary info */ - if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && + if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") && !pgc_node) return 0; @@ -511,7 +511,7 @@ static void imx_gpc_remove(struct platform_device *pdev) pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); /* bail out if DT too old and doesn't provide the necessary info */ - if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") && + if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") && !pgc_node) return; @@ -545,6 +545,6 @@ static struct platform_driver imx_gpc_driver = { .of_match_table = imx_gpc_dt_ids, }, .probe = imx_gpc_probe, - .remove_new = imx_gpc_remove, + .remove = imx_gpc_remove, }; builtin_platform_driver(imx_gpc_driver) diff --git a/drivers/pmdomain/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c index 963d61c5af6d5e..e67ecf99ef84f3 100644 --- a/drivers/pmdomain/imx/gpcv2.c +++ b/drivers/pmdomain/imx/gpcv2.c @@ -403,7 +403,7 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd) * already reaches target before udelay() */ regmap_read_bypassed(domain->regmap, domain->regs->hsk, ®_val); - udelay(5); + udelay(10); } /* Disable reset clocks for all devices in the domain */ @@ -1356,7 +1356,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) ret = pm_genpd_init(&domain->genpd, NULL, true); if (ret) { - dev_err(domain->dev, "Failed to init power domain\n"); + dev_err_probe(domain->dev, ret, "Failed to init power domain\n"); goto out_domain_unmap; } @@ -1367,7 +1367,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) ret = of_genpd_add_provider_simple(domain->dev->of_node, &domain->genpd); if (ret) { - dev_err(domain->dev, "Failed to add genpd provider\n"); + dev_err_probe(domain->dev, ret, "Failed to add genpd provider\n"); goto out_genpd_remove; } @@ -1439,7 +1439,7 @@ static struct platform_driver imx_pgc_domain_driver = { .pm = &imx_pgc_domain_pm_ops, }, .probe = imx_pgc_domain_probe, - .remove_new = imx_pgc_domain_remove, + .remove = imx_pgc_domain_remove, .id_table = imx_pgc_domain_id, }; builtin_platform_driver(imx_pgc_domain_driver) diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c index ca942d7929c2ba..23db85b7aa9e68 100644 --- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c @@ -889,7 +889,7 @@ MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match); static struct platform_driver imx8m_blk_ctrl_driver = { .probe = imx8m_blk_ctrl_probe, - .remove_new = imx8m_blk_ctrl_remove, + .remove = imx8m_blk_ctrl_remove, .driver = { .name = "imx8m-blk-ctrl", .pm = &imx8m_blk_ctrl_pm_ops, diff --git a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c index 77e889165eed3c..e3a0f64c144ca9 100644 --- a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c @@ -857,7 +857,7 @@ MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match); static struct platform_driver imx8mp_blk_ctrl_driver = { .probe = imx8mp_blk_ctrl_probe, - .remove_new = imx8mp_blk_ctrl_remove, + .remove = imx8mp_blk_ctrl_remove, .driver = { .name = "imx8mp-blk-ctrl", .pm = &imx8mp_blk_ctrl_pm_ops, diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c index b10348ac10f06d..0e2ba8ec55d757 100644 --- a/drivers/pmdomain/imx/imx93-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c @@ -438,7 +438,7 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match); static struct platform_driver imx93_blk_ctrl_driver = { .probe = imx93_blk_ctrl_probe, - .remove_new = imx93_blk_ctrl_remove, + .remove = imx93_blk_ctrl_remove, .driver = { .name = "imx93-blk-ctrl", .of_match_table = imx93_blk_ctrl_of_match, diff --git a/drivers/pmdomain/imx/imx93-pd.c b/drivers/pmdomain/imx/imx93-pd.c index 25ab592945bd7b..d68273330687a8 100644 --- a/drivers/pmdomain/imx/imx93-pd.c +++ b/drivers/pmdomain/imx/imx93-pd.c @@ -162,7 +162,7 @@ static struct platform_driver imx93_power_domain_driver = { .of_match_table = imx93_pd_ids, }, .probe = imx93_pd_probe, - .remove_new = imx93_pd_remove, + .remove = imx93_pd_remove, }; module_platform_driver(imx93_power_domain_driver); diff --git a/drivers/pmdomain/mediatek/mt6735-pm-domains.h b/drivers/pmdomain/mediatek/mt6735-pm-domains.h new file mode 100644 index 00000000000000..71896be68e227f --- /dev/null +++ b/drivers/pmdomain/mediatek/mt6735-pm-domains.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT6735_PM_DOMAINS_H +#define __SOC_MEDIATEK_MT6735_PM_DOMAINS_H + +#include "mtk-pm-domains.h" +#include + +/* + * MT6735 power domain support + */ + +static const struct scpsys_domain_data scpsys_domain_data_mt6735[] = { + [MT6735_POWER_DOMAIN_MD1] = { + .name = "md1", + .sta_mask = PWR_STATUS_MD1, + .ctl_offs = SPM_MD1_PWR_CON, + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = 0, + .bp_cfg = { + BUS_PROT_INFRA_UPDATE_TOPAXI(MT6735_TOP_AXI_PROT_EN_MD1), + }, + }, + [MT6735_POWER_DOMAIN_CONN] = { + .name = "conn", + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = SPM_CONN_PWR_CON, + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = 0, + .bp_cfg = { + BUS_PROT_INFRA_UPDATE_TOPAXI(MT6735_TOP_AXI_PROT_EN_CONN), + }, + }, + [MT6735_POWER_DOMAIN_DIS] = { + .name = "dis", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_cfg = { + BUS_PROT_INFRA_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0), + }, + }, + [MT6735_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_cfg = { + BUS_PROT_INFRA_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S), + }, + }, + [MT6735_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + }, + [MT6735_POWER_DOMAIN_VDE] = { + .name = "vde", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT6735_POWER_DOMAIN_VEN] = { + .name = "ven", + .sta_mask = BIT(8), + .ctl_offs = SPM_VEN_PWR_CON, + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, +}; + +static const struct scpsys_soc_data mt6735_scpsys_data = { + .domains_data = scpsys_domain_data_mt6735, + .num_domains = ARRAY_SIZE(scpsys_domain_data_mt6735), +}; + +#endif /* __SOC_MEDIATEK_MT6735_PM_DOMAINS_H */ diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index 88406e9ac63c22..b866b006af6997 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -16,6 +16,7 @@ #include #include +#include "mt6735-pm-domains.h" #include "mt6795-pm-domains.h" #include "mt8167-pm-domains.h" #include "mt8173-pm-domains.h" @@ -353,7 +354,6 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no { const struct scpsys_domain_data *domain_data; struct scpsys_domain *pd; - struct device_node *root_node = scpsys->dev->of_node; struct device_node *smi_node; struct property *prop; const char *clk_name; @@ -388,16 +388,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no pd->scpsys = scpsys; if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) { - /* - * Find regulator in current power domain node. - * devm_regulator_get() finds regulator in a node and its child - * node, so set of_node to current power domain node then change - * back to original node after regulator is found for current - * power domain node. - */ - scpsys->dev->of_node = node; - pd->supply = devm_regulator_get(scpsys->dev, "domain"); - scpsys->dev->of_node = root_node; + pd->supply = devm_of_regulator_get_optional(scpsys->dev, node, "domain"); if (IS_ERR(pd->supply)) return dev_err_cast_probe(scpsys->dev, pd->supply, "%pOF: failed to get power supply.\n", @@ -618,6 +609,10 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys) } static const struct of_device_id scpsys_of_match[] = { + { + .compatible = "mediatek,mt6735-power-controller", + .data = &mt6735_scpsys_data, + }, { .compatible = "mediatek,mt6795-power-controller", .data = &mt6795_scpsys_data, diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h index aaba5e6b0536ff..2ac96804b98537 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.h +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h @@ -21,6 +21,7 @@ #define SPM_ISP_PWR_CON 0x0238 #define SPM_DIS_PWR_CON 0x023c #define SPM_CONN_PWR_CON 0x0280 +#define SPM_MD1_PWR_CON 0x0284 #define SPM_VEN2_PWR_CON 0x0298 #define SPM_AUDIO_PWR_CON 0x029c #define SPM_MFG_2D_PWR_CON 0x02c0 @@ -30,6 +31,7 @@ #define SPM_PWR_STATUS 0x060c #define SPM_PWR_STATUS_2ND 0x0610 +#define PWR_STATUS_MD1 BIT(0) #define PWR_STATUS_CONN BIT(1) #define PWR_STATUS_DISP BIT(3) #define PWR_STATUS_MFG BIT(4) diff --git a/drivers/pmdomain/qcom/cpr.c b/drivers/pmdomain/qcom/cpr.c index 26a60a101e42a0..3ee8184e4be36d 100644 --- a/drivers/pmdomain/qcom/cpr.c +++ b/drivers/pmdomain/qcom/cpr.c @@ -1717,7 +1717,7 @@ MODULE_DEVICE_TABLE(of, cpr_match_table); static struct platform_driver cpr_driver = { .probe = cpr_probe, - .remove_new = cpr_remove, + .remove = cpr_remove, .driver = { .name = "qcom-cpr", .of_match_table = cpr_match_table, diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c index 65505e1e221986..dfd0f80154e49d 100644 --- a/drivers/pmdomain/qcom/rpmhpd.c +++ b/drivers/pmdomain/qcom/rpmhpd.c @@ -259,6 +259,30 @@ static const struct rpmhpd_desc sa8775p_desc = { .num_pds = ARRAY_SIZE(sa8775p_rpmhpds), }; +/* SAR2130P RPMH powerdomains */ +static struct rpmhpd *sar2130p_rpmhpds[] = { + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_LCX] = &lcx, + [RPMHPD_LMX] = &lmx, + [RPMHPD_MMCX] = &mmcx_w_cx_parent, + [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, + [RPMHPD_MSS] = &mss, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_MXC] = &mxc, + [RPMHPD_MXC_AO] = &mxc_ao, + [RPMHPD_NSP] = &nsp, + [RPMHPD_QPHY] = &qphy, +}; + +static const struct rpmhpd_desc sar2130p_desc = { + .rpmhpds = sar2130p_rpmhpds, + .num_pds = ARRAY_SIZE(sar2130p_rpmhpds), +}; + /* SDM670 RPMH powerdomains */ static struct rpmhpd *sdm670_rpmhpds[] = { [SDM670_CX] = &cx_w_mx_parent, @@ -513,6 +537,31 @@ static const struct rpmhpd_desc sm8650_desc = { .num_pds = ARRAY_SIZE(sm8650_rpmhpds), }; +/* SM8750 RPMH powerdomains */ +static struct rpmhpd *sm8750_rpmhpds[] = { + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_GMXC] = &gmxc, + [RPMHPD_LCX] = &lcx, + [RPMHPD_LMX] = &lmx, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_MMCX] = &mmcx_w_cx_parent, + [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, + [RPMHPD_MSS] = &mss, + [RPMHPD_MXC] = &mxc, + [RPMHPD_MXC_AO] = &mxc_ao, + [RPMHPD_NSP] = &nsp, + [RPMHPD_NSP2] = &nsp2, +}; + +static const struct rpmhpd_desc sm8750_desc = { + .rpmhpds = sm8750_rpmhpds, + .num_pds = ARRAY_SIZE(sm8750_rpmhpds), +}; + /* QDU1000/QRU1000 RPMH powerdomains */ static struct rpmhpd *qdu1000_rpmhpds[] = { [QDU1000_CX] = &cx, @@ -624,11 +673,48 @@ static const struct rpmhpd_desc x1e80100_desc = { .num_pds = ARRAY_SIZE(x1e80100_rpmhpds), }; +/* QCS8300 RPMH power domains */ +static struct rpmhpd *qcs8300_rpmhpds[] = { + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_LCX] = &lcx, + [RPMHPD_LMX] = &lmx, + [RPMHPD_MMCX] = &mmcx_w_cx_parent, + [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, + [RPMHPD_MXC] = &mxc, + [RPMHPD_MXC_AO] = &mxc_ao, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_NSP0] = &nsp0, + [RPMHPD_NSP1] = &nsp1, +}; + +static const struct rpmhpd_desc qcs8300_desc = { + .rpmhpds = qcs8300_rpmhpds, + .num_pds = ARRAY_SIZE(qcs8300_rpmhpds), +}; + +/* QCS615 RPMH powerdomains */ +static struct rpmhpd *qcs615_rpmhpds[] = { + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, +}; + +static const struct rpmhpd_desc qcs615_desc = { + .rpmhpds = qcs615_rpmhpds, + .num_pds = ARRAY_SIZE(qcs615_rpmhpds), +}; + static const struct of_device_id rpmhpd_match_table[] = { + { .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc }, + { .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc }, { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc }, { .compatible = "qcom,sa8155p-rpmhpd", .data = &sa8155p_desc }, { .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc }, { .compatible = "qcom,sa8775p-rpmhpd", .data = &sa8775p_desc }, + { .compatible = "qcom,sar2130p-rpmhpd", .data = &sar2130p_desc}, { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc }, { .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc }, { .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc }, @@ -646,6 +732,7 @@ static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc }, { .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc }, { .compatible = "qcom,sm8650-rpmhpd", .data = &sm8650_desc }, + { .compatible = "qcom,sm8750-rpmhpd", .data = &sm8750_desc }, { .compatible = "qcom,x1e80100-rpmhpd", .data = &x1e80100_desc }, { } }; diff --git a/drivers/pmdomain/ti/ti_sci_pm_domains.c b/drivers/pmdomain/ti/ti_sci_pm_domains.c index 1510d5ddae3dec..0e4bd749d06730 100644 --- a/drivers/pmdomain/ti/ti_sci_pm_domains.c +++ b/drivers/pmdomain/ti/ti_sci_pm_domains.c @@ -131,9 +131,8 @@ static int ti_sci_pm_domain_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct ti_sci_genpd_provider *pd_provider; struct ti_sci_pm_domain *pd; - struct device_node *np; + struct device_node *np __free(device_node) = NULL; struct of_phandle_args args; - int ret; u32 max_id = 0; int index; @@ -153,14 +152,12 @@ static int ti_sci_pm_domain_probe(struct platform_device *pdev) for_each_node_with_property(np, "power-domains") { index = 0; - while (1) { - ret = of_parse_phandle_with_args(np, "power-domains", - "#power-domain-cells", - index, &args); - if (ret) - break; + while (!of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", + index, &args)) { if (args.args_count >= 1 && args.np == dev->of_node) { + of_node_put(args.np); if (args.args[0] > max_id) { max_id = args.args[0]; } else { @@ -171,28 +168,28 @@ static int ti_sci_pm_domain_probe(struct platform_device *pdev) } pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); - if (!pd) { - of_node_put(np); + if (!pd) return -ENOMEM; - } pd->pd.name = devm_kasprintf(dev, GFP_KERNEL, "pd:%d", args.args[0]); - if (!pd->pd.name) { - of_node_put(np); + if (!pd->pd.name) return -ENOMEM; - } pd->pd.power_off = ti_sci_pd_power_off; pd->pd.power_on = ti_sci_pd_power_on; + pd->pd.flags |= GENPD_FLAG_ACTIVE_WAKEUP; pd->idx = args.args[0]; pd->parent = pd_provider; pm_genpd_init(&pd->pd, NULL, true); list_add(&pd->node, &pd_provider->pd_list); + } else { + of_node_put(args.np); } + index++; } } diff --git a/drivers/pmdomain/xilinx/zynqmp-pm-domains.c b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c index 0b5831e5ba1bfd..d579220a4500a7 100644 --- a/drivers/pmdomain/xilinx/zynqmp-pm-domains.c +++ b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c @@ -313,7 +313,7 @@ static struct platform_driver zynqmp_power_domain_driver = { .sync_state = zynqmp_gpd_sync_state, }, .probe = zynqmp_gpd_probe, - .remove_new = zynqmp_gpd_remove, + .remove = zynqmp_gpd_remove, }; module_platform_driver(zynqmp_power_domain_driver); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 389d5a193e5dce..f5fc33a8bf4431 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -79,6 +79,7 @@ config POWER_RESET_EP93XX bool "Cirrus EP93XX reset driver" if COMPILE_TEST depends on MFD_SYSCON default ARCH_EP93XX + select AUXILIARY_BUS help This driver provides restart support for Cirrus EP93XX SoC. diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c index 93eece02786522..7bc779055cf3f7 100644 --- a/drivers/power/reset/at91-poweroff.c +++ b/drivers/power/reset/at91-poweroff.c @@ -223,7 +223,7 @@ MODULE_DEVICE_TABLE(of, at91_poweroff_of_match); static struct platform_driver at91_poweroff_driver = { .probe = at91_poweroff_probe, - .remove_new = at91_poweroff_remove, + .remove = at91_poweroff_remove, .driver = { .name = "at91-poweroff", .of_match_table = at91_poweroff_of_match, diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 16512654295f5c..036b18a1f90f80 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -427,7 +427,7 @@ static void at91_reset_remove(struct platform_device *pdev) static struct platform_driver at91_reset_driver = { .probe = at91_reset_probe, - .remove_new = at91_reset_remove, + .remove = at91_reset_remove, .driver = { .name = "at91-reset", .of_match_table = at91_reset_of_match, diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index 959ce0dbe91d11..edb0df86aff45e 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -441,7 +441,7 @@ static void at91_shdwc_remove(struct platform_device *pdev) static struct platform_driver at91_shdwc_driver = { .probe = at91_shdwc_probe, - .remove_new = at91_shdwc_remove, + .remove = at91_shdwc_remove, .driver = { .name = "at91-shdwc", .of_match_table = at91_shdwc_of_match, diff --git a/drivers/power/reset/keystone-reset.c b/drivers/power/reset/keystone-reset.c index dbc4ff61cd7486..cfaa54ced0d0a9 100644 --- a/drivers/power/reset/keystone-reset.c +++ b/drivers/power/reset/keystone-reset.c @@ -16,7 +16,6 @@ #include #include -#define RSTYPE_RG 0x0 #define RSCTRL_RG 0x4 #define RSCFG_RG 0x8 #define RSISO_RG 0xc @@ -28,7 +27,6 @@ #define RSMUX_OMODE_MASK 0xe #define RSMUX_OMODE_RESET_ON 0xa #define RSMUX_OMODE_RESET_OFF 0x0 -#define RSMUX_LOCK_MASK 0x1 #define RSMUX_LOCK_SET 0x1 #define RSCFG_RSTYPE_SOFT 0x300f diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c index fa25fbd5393433..1a6fc8d38e2067 100644 --- a/drivers/power/reset/ltc2952-poweroff.c +++ b/drivers/power/reset/ltc2952-poweroff.c @@ -305,7 +305,7 @@ MODULE_DEVICE_TABLE(of, of_ltc2952_poweroff_match); static struct platform_driver ltc2952_poweroff_driver = { .probe = ltc2952_poweroff_probe, - .remove_new = ltc2952_poweroff_remove, + .remove = ltc2952_poweroff_remove, .driver = { .name = "ltc2952-poweroff", .of_match_table = of_ltc2952_poweroff_match, diff --git a/drivers/power/reset/qnap-poweroff.c b/drivers/power/reset/qnap-poweroff.c index e0f2ff6b147c19..f7d8fc935d5199 100644 --- a/drivers/power/reset/qnap-poweroff.c +++ b/drivers/power/reset/qnap-poweroff.c @@ -118,7 +118,7 @@ static void qnap_power_off_remove(struct platform_device *pdev) static struct platform_driver qnap_power_off_driver = { .probe = qnap_power_off_probe, - .remove_new = qnap_power_off_remove, + .remove = qnap_power_off_remove, .driver = { .name = "qnap_power_off", .of_match_table = of_match_ptr(qnap_power_off_of_match_table), diff --git a/drivers/power/reset/syscon-reboot.c b/drivers/power/reset/syscon-reboot.c index 4d622c19bc486f..d623d77e657e4c 100644 --- a/drivers/power/reset/syscon-reboot.c +++ b/drivers/power/reset/syscon-reboot.c @@ -61,7 +61,8 @@ static int syscon_reboot_probe(struct platform_device *pdev) priority = 192; if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset)) - return -EINVAL; + if (of_property_read_u32(pdev->dev.of_node, "reg", &ctx->offset)) + return -EINVAL; value_err = of_property_read_u32(pdev->dev.of_node, "value", &ctx->value); mask_err = of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask); diff --git a/drivers/power/sequencing/Kconfig b/drivers/power/sequencing/Kconfig index c9f1cdb6652488..ddcc42a984921c 100644 --- a/drivers/power/sequencing/Kconfig +++ b/drivers/power/sequencing/Kconfig @@ -16,6 +16,7 @@ if POWER_SEQUENCING config POWER_SEQUENCING_QCOM_WCN tristate "Qualcomm WCN family PMU driver" default m if ARCH_QCOM + depends on OF help Say Y here to enable the power sequencing driver for Qualcomm WCN Bluetooth/WLAN chipsets. diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c index 4fa129877d7e4c..682a9beac69eb6 100644 --- a/drivers/power/sequencing/pwrseq-qcom-wcn.c +++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c @@ -22,6 +22,7 @@ struct pwrseq_qcom_wcn_pdata { size_t num_vregs; unsigned int pwup_delay_ms; unsigned int gpio_enable_delay_ms; + const struct pwrseq_target_data **targets; }; struct pwrseq_qcom_wcn_ctx { @@ -31,6 +32,7 @@ struct pwrseq_qcom_wcn_ctx { struct regulator_bulk_data *regs; struct gpio_desc *bt_gpio; struct gpio_desc *wlan_gpio; + struct gpio_desc *xo_clk_gpio; struct clk *clk; unsigned long last_gpio_enable_jf; }; @@ -98,6 +100,33 @@ static const struct pwrseq_unit_data *pwrseq_qcom_wcn_unit_deps[] = { NULL }; +static int pwrseq_qcom_wcn6855_clk_assert(struct pwrseq_device *pwrseq) +{ + struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); + + if (!ctx->xo_clk_gpio) + return 0; + + msleep(1); + + gpiod_set_value_cansleep(ctx->xo_clk_gpio, 1); + usleep_range(100, 200); + + return 0; +} + +static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_xo_clk_assert = { + .name = "xo-clk-assert", + .enable = pwrseq_qcom_wcn6855_clk_assert, +}; + +static const struct pwrseq_unit_data *pwrseq_qcom_wcn6855_unit_deps[] = { + &pwrseq_qcom_wcn_vregs_unit_data, + &pwrseq_qcom_wcn_clk_unit_data, + &pwrseq_qcom_wcn6855_xo_clk_assert, + NULL +}; + static int pwrseq_qcom_wcn_bt_enable(struct pwrseq_device *pwrseq) { struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); @@ -125,6 +154,13 @@ static const struct pwrseq_unit_data pwrseq_qcom_wcn_bt_unit_data = { .disable = pwrseq_qcom_wcn_bt_disable, }; +static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_bt_unit_data = { + .name = "wlan-enable", + .deps = pwrseq_qcom_wcn6855_unit_deps, + .enable = pwrseq_qcom_wcn_bt_enable, + .disable = pwrseq_qcom_wcn_bt_disable, +}; + static int pwrseq_qcom_wcn_wlan_enable(struct pwrseq_device *pwrseq) { struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); @@ -152,6 +188,13 @@ static const struct pwrseq_unit_data pwrseq_qcom_wcn_wlan_unit_data = { .disable = pwrseq_qcom_wcn_wlan_disable, }; +static const struct pwrseq_unit_data pwrseq_qcom_wcn6855_wlan_unit_data = { + .name = "wlan-enable", + .deps = pwrseq_qcom_wcn6855_unit_deps, + .enable = pwrseq_qcom_wcn_wlan_enable, + .disable = pwrseq_qcom_wcn_wlan_disable, +}; + static int pwrseq_qcom_wcn_pwup_delay(struct pwrseq_device *pwrseq) { struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); @@ -162,6 +205,18 @@ static int pwrseq_qcom_wcn_pwup_delay(struct pwrseq_device *pwrseq) return 0; } +static int pwrseq_qcom_wcn6855_xo_clk_deassert(struct pwrseq_device *pwrseq) +{ + struct pwrseq_qcom_wcn_ctx *ctx = pwrseq_device_get_drvdata(pwrseq); + + if (ctx->xo_clk_gpio) { + usleep_range(2000, 5000); + gpiod_set_value_cansleep(ctx->xo_clk_gpio, 0); + } + + return pwrseq_qcom_wcn_pwup_delay(pwrseq); +} + static const struct pwrseq_target_data pwrseq_qcom_wcn_bt_target_data = { .name = "bluetooth", .unit = &pwrseq_qcom_wcn_bt_unit_data, @@ -174,12 +229,30 @@ static const struct pwrseq_target_data pwrseq_qcom_wcn_wlan_target_data = { .post_enable = pwrseq_qcom_wcn_pwup_delay, }; +static const struct pwrseq_target_data pwrseq_qcom_wcn6855_bt_target_data = { + .name = "bluetooth", + .unit = &pwrseq_qcom_wcn6855_bt_unit_data, + .post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert, +}; + +static const struct pwrseq_target_data pwrseq_qcom_wcn6855_wlan_target_data = { + .name = "wlan", + .unit = &pwrseq_qcom_wcn6855_wlan_unit_data, + .post_enable = pwrseq_qcom_wcn6855_xo_clk_deassert, +}; + static const struct pwrseq_target_data *pwrseq_qcom_wcn_targets[] = { &pwrseq_qcom_wcn_bt_target_data, &pwrseq_qcom_wcn_wlan_target_data, NULL }; +static const struct pwrseq_target_data *pwrseq_qcom_wcn6855_targets[] = { + &pwrseq_qcom_wcn6855_bt_target_data, + &pwrseq_qcom_wcn6855_wlan_target_data, + NULL +}; + static const char *const pwrseq_qca6390_vregs[] = { "vddio", "vddaon", @@ -196,13 +269,28 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_qca6390_of_data = { .num_vregs = ARRAY_SIZE(pwrseq_qca6390_vregs), .pwup_delay_ms = 60, .gpio_enable_delay_ms = 100, + .targets = pwrseq_qcom_wcn_targets, +}; + +static const char *const pwrseq_wcn6855_vregs[] = { + "vddio", + "vddaon", + "vddpmu", + "vddpmumx", + "vddpmucx", + "vddrfa0p95", + "vddrfa1p3", + "vddrfa1p9", + "vddpcie1p3", + "vddpcie1p9", }; static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn6855_of_data = { - .vregs = pwrseq_qca6390_vregs, - .num_vregs = ARRAY_SIZE(pwrseq_qca6390_vregs), + .vregs = pwrseq_wcn6855_vregs, + .num_vregs = ARRAY_SIZE(pwrseq_wcn6855_vregs), .pwup_delay_ms = 50, .gpio_enable_delay_ms = 5, + .targets = pwrseq_qcom_wcn6855_targets, }; static const char *const pwrseq_wcn7850_vregs[] = { @@ -219,6 +307,7 @@ static const struct pwrseq_qcom_wcn_pdata pwrseq_wcn7850_of_data = { .vregs = pwrseq_wcn7850_vregs, .num_vregs = ARRAY_SIZE(pwrseq_wcn7850_vregs), .pwup_delay_ms = 50, + .targets = pwrseq_qcom_wcn_targets, }; static int pwrseq_qcom_wcn_match(struct pwrseq_device *pwrseq, @@ -295,6 +384,12 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(ctx->wlan_gpio), "Failed to get the WLAN enable GPIO\n"); + ctx->xo_clk_gpio = devm_gpiod_get_optional(dev, "xo-clk", + GPIOD_OUT_LOW); + if (IS_ERR(ctx->xo_clk_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->xo_clk_gpio), + "Failed to get the XO_CLK GPIO\n"); + /* * Set direction to output but keep the current value in order to not * disable the WLAN module accidentally if it's already powered on. @@ -313,7 +408,7 @@ static int pwrseq_qcom_wcn_probe(struct platform_device *pdev) config.owner = THIS_MODULE; config.drvdata = ctx; config.match = pwrseq_qcom_wcn_match; - config.targets = pwrseq_qcom_wcn_targets; + config.targets = ctx->pdata->targets; ctx->pwrseq = devm_pwrseq_device_register(dev, &config); if (IS_ERR(ctx->pwrseq)) diff --git a/drivers/power/supply/88pm860x_battery.c b/drivers/power/supply/88pm860x_battery.c index 34619c4d4eced9..b7938fbb24a51f 100644 --- a/drivers/power/supply/88pm860x_battery.c +++ b/drivers/power/supply/88pm860x_battery.c @@ -422,7 +422,7 @@ static irqreturn_t pm860x_batt_handler(int irq, void *data) info->temp_type = PM860X_TEMP_TINT; } mutex_unlock(&info->lock); - /* clear ccnt since battery is attached or dettached */ + /* clear ccnt since battery is attached or detached */ clear_ccnt(info, &ccnt_data); return IRQ_HANDLED; } @@ -566,7 +566,7 @@ static int measure_temp(struct pm860x_battery_info *info, int *data) ret = measure_12bit_voltage(info, PM8607_GPADC1_MEAS1, data); if (ret) return ret; - /* meausered Vtbat(mV) / Ibias_current(11uA)*/ + /* measured Vtbat(mV) / Ibias_current(11uA)*/ *data = (*data * 1000) / GPBIAS2_GPADC1_UA; if (*data > TBAT_NEG_25D) { diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index bcfa63fb9f1e20..9f2eef6787f7ae 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -493,6 +493,16 @@ config CHARGER_TWL4030 help Say Y here to enable support for TWL4030 Battery Charge Interface. +config CHARGER_TWL6030 + tristate "OMAP TWL6030 BCI charger driver" + depends on IIO && TWL4030_CORE + help + Say Y here to enable support for TWL6030/6032 Battery Charge + Interface. + + This driver can be build as a module. If so, the module will be + called twl6030_charger. + config CHARGER_LP8727 tristate "TI/National Semiconductor LP8727 charger driver" depends on I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 8dcb4154531718..59c4a9f40d28ac 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o +obj-$(CONFIG_CHARGER_TWL6030) += twl6030_charger.o obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index 3e6ea22372b2dc..19ed5285280485 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -16,7 +16,7 @@ /* Default: temperature hysteresis */ #define AB8500_TEMP_HYSTERESIS 3 -static struct power_supply_battery_ocv_table ocv_cap_tbl[] = { +static const struct power_supply_battery_ocv_table ocv_cap_tbl[] = { { .ocv = 4186000, .capacity = 100}, { .ocv = 4163000, .capacity = 99}, { .ocv = 4114000, .capacity = 95}, @@ -48,7 +48,7 @@ static struct power_supply_battery_ocv_table ocv_cap_tbl[] = { * temperature values to work. Factory resistance is 300 mOhm and the * resistance values to the right are percentages of 300 mOhm. */ -static struct power_supply_resistance_temp_table temp_to_batres_tbl_thermistor[] = { +static const struct power_supply_resistance_temp_table temp_to_batres_tbl_thermistor[] = { { .temp = 40, .resistance = 40 /* 120 mOhm */ }, { .temp = 30, .resistance = 45 /* 135 mOhm */ }, { .temp = 20, .resistance = 55 /* 165 mOhm */ }, diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 56f136b2d071d3..37039e28fc4bd2 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -283,7 +283,7 @@ static void ab8500_btemp_periodic_work(struct work_struct *work) dev_warn(di->dev, "failed to identify the battery\n"); } - /* Failover if a reading is erroneous, use last meausurement */ + /* Failover if a reading is erroneous, use last measurement */ ret = thermal_zone_get_temp(di->tz, &bat_temp); if (ret) { dev_err(di->dev, "error reading temperature\n"); @@ -818,7 +818,7 @@ MODULE_DEVICE_TABLE(of, ab8500_btemp_match); struct platform_driver ab8500_btemp_driver = { .probe = ab8500_btemp_probe, - .remove_new = ab8500_btemp_remove, + .remove = ab8500_btemp_remove, .driver = { .name = "ab8500-btemp", .of_match_table = ab8500_btemp_match, diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index 854491ad3ecd5f..14e1b448bd39b2 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -1837,7 +1837,7 @@ static const struct of_device_id ab8500_chargalg_match[] = { struct platform_driver ab8500_chargalg_driver = { .probe = ab8500_chargalg_probe, - .remove_new = ab8500_chargalg_remove, + .remove = ab8500_chargalg_remove, .driver = { .name = "ab8500_chargalg", .of_match_table = ab8500_chargalg_match, diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 93181ebfb32473..cece8d6753ac14 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3711,7 +3711,7 @@ MODULE_DEVICE_TABLE(of, ab8500_charger_match); static struct platform_driver ab8500_charger_driver = { .probe = ab8500_charger_probe, - .remove_new = ab8500_charger_remove, + .remove = ab8500_charger_remove, .driver = { .name = "ab8500-charger", .of_match_table = ab8500_charger_match, diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index a71903b1bf781e..78871a2143de34 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -3242,7 +3242,7 @@ MODULE_DEVICE_TABLE(of, ab8500_fg_match); struct platform_driver ab8500_fg_driver = { .probe = ab8500_fg_probe, - .remove_new = ab8500_fg_remove, + .remove = ab8500_fg_remove, .driver = { .name = "ab8500-fg", .of_match_table = ab8500_fg_match, diff --git a/drivers/power/supply/acer_a500_battery.c b/drivers/power/supply/acer_a500_battery.c index ef5c419b1b7f20..39d85b11a13c23 100644 --- a/drivers/power/supply/acer_a500_battery.c +++ b/drivers/power/supply/acer_a500_battery.c @@ -233,14 +233,15 @@ static int a500_battery_probe(struct platform_device *pdev) psy_cfg.of_node = pdev->dev.parent->of_node; psy_cfg.drv_data = bat; + psy_cfg.no_wakeup_source = true; bat->regmap = dev_get_regmap(pdev->dev.parent, "KB930"); if (!bat->regmap) return -EINVAL; - bat->psy = devm_power_supply_register_no_ws(&pdev->dev, - &a500_battery_desc, - &psy_cfg); + bat->psy = devm_power_supply_register(&pdev->dev, + &a500_battery_desc, + &psy_cfg); if (IS_ERR(bat->psy)) return dev_err_probe(&pdev->dev, PTR_ERR(bat->psy), "failed to register battery\n"); @@ -285,7 +286,7 @@ static struct platform_driver a500_battery_driver = { .pm = &a500_battery_pm_ops, }, .probe = a500_battery_probe, - .remove_new = a500_battery_remove, + .remove = a500_battery_remove, }; module_platform_driver(a500_battery_driver); diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index 51122bfbf196c9..b2b82f97a47120 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -651,7 +651,7 @@ static struct platform_driver act8945a_charger_driver = { .name = "act8945a-charger", }, .probe = act8945a_charger_probe, - .remove_new = act8945a_charger_remove, + .remove = act8945a_charger_remove, }; module_platform_driver(act8945a_charger_driver); diff --git a/drivers/power/supply/adp5061.c b/drivers/power/supply/adp5061.c index dac9875d993c9c..458fd3024373ff 100644 --- a/drivers/power/supply/adp5061.c +++ b/drivers/power/supply/adp5061.c @@ -590,7 +590,7 @@ static int adp5061_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_AVG: /* * This property is used to set the VWEAK threshold - * bellow this value, weak charge mode is entered + * below this value, weak charge mode is entered * above this value, fast chargerge mode is entered */ return adp5061_get_vweak_th(st, val); diff --git a/drivers/power/supply/axp20x_battery.c b/drivers/power/supply/axp20x_battery.c index f71cc90fea1273..fa27195f074e7d 100644 --- a/drivers/power/supply/axp20x_battery.c +++ b/drivers/power/supply/axp20x_battery.c @@ -354,17 +354,18 @@ static int axp20x_battery_get_prop(struct power_supply *psy, if (ret) return ret; + /* IIO framework gives mA but Power Supply framework gives uA */ if (reg & AXP20X_PWR_STATUS_BAT_CHARGING) { - ret = iio_read_channel_processed(axp20x_batt->batt_chrg_i, &val->intval); + ret = iio_read_channel_processed_scale(axp20x_batt->batt_chrg_i, + &val->intval, 1000); } else { - ret = iio_read_channel_processed(axp20x_batt->batt_dischrg_i, &val1); + ret = iio_read_channel_processed_scale(axp20x_batt->batt_dischrg_i, + &val1, 1000); val->intval = -val1; } if (ret) return ret; - /* IIO framework gives mA but Power Supply framework gives uA */ - val->intval *= 1000; break; case POWER_SUPPLY_PROP_CAPACITY: @@ -406,13 +407,12 @@ static int axp20x_battery_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - ret = iio_read_channel_processed(axp20x_batt->batt_v, - &val->intval); + /* IIO framework gives mV but Power Supply framework gives uV */ + ret = iio_read_channel_processed_scale(axp20x_batt->batt_v, + &val->intval, 1000); if (ret) return ret; - /* IIO framework gives mV but Power Supply framework gives uV */ - val->intval *= 1000; break; default: @@ -519,13 +519,15 @@ static int axp717_battery_get_prop(struct power_supply *psy, * The offset of this value is currently unknown and is * not documented in the datasheet. Based on * observation it's assumed to be somewhere around - * 450ma. I will leave the value raw for now. + * 450ma. I will leave the value raw for now. Note that + * IIO framework gives mA but Power Supply framework + * gives uA. */ - ret = iio_read_channel_processed(axp20x_batt->batt_chrg_i, &val->intval); + ret = iio_read_channel_processed_scale(axp20x_batt->batt_chrg_i, + &val->intval, 1000); if (ret) return ret; - /* IIO framework gives mA but Power Supply framework gives uA */ - val->intval *= 1000; + return 0; case POWER_SUPPLY_PROP_CAPACITY: @@ -564,13 +566,12 @@ static int axp717_battery_get_prop(struct power_supply *psy, return 0; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - ret = iio_read_channel_processed(axp20x_batt->batt_v, - &val->intval); + /* IIO framework gives mV but Power Supply framework gives uV */ + ret = iio_read_channel_processed_scale(axp20x_batt->batt_v, + &val->intval, 1000); if (ret) return ret; - /* IIO framework gives mV but Power Supply framework gives uV */ - val->intval *= 1000; return 0; case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 2766352ab737da..9722912268fe8e 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -220,16 +220,15 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, return 0; case POWER_SUPPLY_PROP_VOLTAGE_NOW: if (IS_ENABLED(CONFIG_AXP20X_ADC)) { - ret = iio_read_channel_processed(power->vbus_v, - &val->intval); - if (ret) - return ret; - /* * IIO framework gives mV but Power Supply framework * gives uV. */ - val->intval *= 1000; + ret = iio_read_channel_processed_scale(power->vbus_v, + &val->intval, 1000); + if (ret) + return ret; + return 0; } @@ -253,16 +252,15 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, return 0; case POWER_SUPPLY_PROP_CURRENT_NOW: if (IS_ENABLED(CONFIG_AXP20X_ADC)) { - ret = iio_read_channel_processed(power->vbus_i, - &val->intval); - if (ret) - return ret; - /* * IIO framework gives mA but Power Supply framework * gives uA. */ - val->intval *= 1000; + ret = iio_read_channel_processed_scale(power->vbus_i, + &val->intval, 1000); + if (ret) + return ret; + return 0; } @@ -374,16 +372,15 @@ static int axp717_usb_power_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: if (IS_ENABLED(CONFIG_AXP20X_ADC)) { - ret = iio_read_channel_processed(power->vbus_v, - &val->intval); - if (ret) - return ret; - /* * IIO framework gives mV but Power Supply framework * gives uV. */ - val->intval *= 1000; + ret = iio_read_channel_processed_scale(power->vbus_v, + &val->intval, 1000); + if (ret) + return ret; + return 0; } diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 750fda543308c8..40c5ac7a111886 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -449,9 +449,29 @@ static u8 [BQ27XXX_REG_AP] = 0x18, BQ27XXX_DM_REG_ROWS, }, + bq27426_regs[BQ27XXX_REG_MAX] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x02, + [BQ27XXX_REG_INT_TEMP] = 0x1e, + [BQ27XXX_REG_VOLT] = 0x04, + [BQ27XXX_REG_AI] = 0x10, + [BQ27XXX_REG_FLAGS] = 0x06, + [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x08, + [BQ27XXX_REG_RC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x0e, + [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x1c, + [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, + [BQ27XXX_REG_AP] = 0x18, + BQ27XXX_DM_REG_ROWS, + }, #define bq27411_regs bq27421_regs #define bq27425_regs bq27421_regs -#define bq27426_regs bq27421_regs #define bq27441_regs bq27421_regs #define bq27621_regs bq27421_regs bq27z561_regs[BQ27XXX_REG_MAX] = { @@ -769,10 +789,23 @@ static enum power_supply_property bq27421_props[] = { }; #define bq27411_props bq27421_props #define bq27425_props bq27421_props -#define bq27426_props bq27421_props #define bq27441_props bq27421_props #define bq27621_props bq27421_props +static enum power_supply_property bq27426_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + static enum power_supply_property bq27z561_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, @@ -2131,6 +2164,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) struct power_supply_config psy_cfg = { .of_node = di->dev->of_node, .drv_data = di, + .no_wakeup_source = true, }; int ret; @@ -2157,7 +2191,7 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di) psy_desc->get_property = bq27xxx_battery_get_property; psy_desc->external_power_changed = bq27xxx_external_power_changed; - di->bat = devm_power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); + di->bat = devm_power_supply_register(di->dev, psy_desc, &psy_cfg); if (IS_ERR(di->bat)) return dev_err_probe(di->dev, PTR_ERR(di->bat), "failed to register battery\n"); diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 96f0a7fbf10518..a69faef444c042 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -221,7 +221,7 @@ static bool is_charging(struct charger_manager *cm) /* If at least one of the charger is charging, return yes */ for (i = 0; cm->desc->psy_charger_stat[i]; i++) { - /* 1. The charger sholuld not be DISABLED */ + /* 1. The charger should not be DISABLED */ if (cm->emergency_stop) continue; if (!cm->charger_enabled) @@ -1412,10 +1412,9 @@ static inline struct charger_desc *cm_get_drv_data(struct platform_device *pdev) return dev_get_platdata(&pdev->dev); } -static enum alarmtimer_restart cm_timer_func(struct alarm *alarm, ktime_t now) +static void cm_timer_func(struct alarm *alarm, ktime_t now) { cm_timer_set = false; - return ALARMTIMER_NORESTART; } static int charger_manager_probe(struct platform_device *pdev) @@ -1740,7 +1739,7 @@ static struct platform_driver charger_manager_driver = { .of_match_table = charger_manager_match, }, .probe = charger_manager_probe, - .remove_new = charger_manager_remove, + .remove = charger_manager_remove, .id_table = charger_manager_id, }; diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index 30ec76cdf34b0b..813037c00ded56 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -1169,7 +1169,7 @@ static struct platform_driver cpcap_battery_driver = { .of_match_table = of_match_ptr(cpcap_battery_id_table), }, .probe = cpcap_battery_probe, - .remove_new = cpcap_battery_remove, + .remove = cpcap_battery_remove, }; module_platform_driver(cpcap_battery_driver); diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index 91e7292d86bb77..7781b45a67a7d2 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -969,7 +969,7 @@ static struct platform_driver cpcap_charger_driver = { .of_match_table = cpcap_charger_id_table, }, .shutdown = cpcap_charger_shutdown, - .remove_new = cpcap_charger_remove, + .remove = cpcap_charger_remove, }; module_platform_driver(cpcap_charger_driver); diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c index bed3e2e9bfea97..47d3f58aa15ceb 100644 --- a/drivers/power/supply/cros_usbpd-charger.c +++ b/drivers/power/supply/cros_usbpd-charger.c @@ -618,6 +618,7 @@ static int cros_usbpd_charger_probe(struct platform_device *pd) psy_desc->external_power_changed = cros_usbpd_charger_power_changed; psy_cfg.drv_data = port; + psy_cfg.no_wakeup_source = true; if (cros_usbpd_charger_port_is_dedicated(port)) { sprintf(port->name, CHARGER_DEDICATED_DIR_NAME); @@ -644,8 +645,7 @@ static int cros_usbpd_charger_probe(struct platform_device *pd) psy_desc->name = port->name; - psy = devm_power_supply_register_no_ws(dev, psy_desc, - &psy_cfg); + psy = devm_power_supply_register(dev, psy_desc, &psy_cfg); if (IS_ERR(psy)) { dev_err(dev, "Failed to register power supply\n"); continue; diff --git a/drivers/power/supply/da9030_battery.c b/drivers/power/supply/da9030_battery.c index 04e0f4162d42b8..34328f5d556e21 100644 --- a/drivers/power/supply/da9030_battery.c +++ b/drivers/power/supply/da9030_battery.c @@ -269,7 +269,7 @@ static void da9030_charger_check_state(struct da9030_charger *charger) } if (charger->adc.vchmax_res > charger->thresholds.vcharge_max || charger->adc.vchmin_res < charger->thresholds.vcharge_min || - /* Tempreture readings are negative */ + /* Temperature readings are negative */ charger->adc.tbat_res < charger->thresholds.tbat_high || charger->adc.tbat_res > charger->thresholds.tbat_low) { /* disable charger */ @@ -470,7 +470,7 @@ static int da9030_battery_charger_init(struct da9030_charger *charger) if (ret) return ret; - /* enable auto ADC measuremnts */ + /* enable auto ADC measurements */ return da903x_write(charger->master, DA9030_ADC_AUTO_CONTROL, DA9030_ADC_TBAT_ENABLE | DA9030_ADC_VBAT_IN_TXON | DA9030_ADC_VCH_ENABLE | DA9030_ADC_ICH_ENABLE | @@ -571,7 +571,7 @@ static struct platform_driver da903x_battery_driver = { .name = "da903x-battery", }, .probe = da9030_battery_probe, - .remove_new = da9030_battery_remove, + .remove = da9030_battery_remove, }; module_platform_driver(da903x_battery_driver); diff --git a/drivers/power/supply/da9052-battery.c b/drivers/power/supply/da9052-battery.c index 0d84c42c624e08..6f17e2fa1a28ef 100644 --- a/drivers/power/supply/da9052-battery.c +++ b/drivers/power/supply/da9052-battery.c @@ -648,7 +648,7 @@ static void da9052_bat_remove(struct platform_device *pdev) static struct platform_driver da9052_bat_driver = { .probe = da9052_bat_probe, - .remove_new = da9052_bat_remove, + .remove = da9052_bat_remove, .driver = { .name = "da9052-bat", }, diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c index b13cecd84f5891..27f36ef5b88dc4 100644 --- a/drivers/power/supply/da9150-charger.c +++ b/drivers/power/supply/da9150-charger.c @@ -636,7 +636,7 @@ static struct platform_driver da9150_charger_driver = { .name = "da9150-charger", }, .probe = da9150_charger_probe, - .remove_new = da9150_charger_remove, + .remove = da9150_charger_remove, }; module_platform_driver(da9150_charger_driver); diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c index 7bdc6b26360904..d5d215f5ad8b16 100644 --- a/drivers/power/supply/generic-adc-battery.c +++ b/drivers/power/supply/generic-adc-battery.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Generic battery driver using IIO - * Copyright (C) 2012, Anish Kumar + * Copyright (C) 2012, Anish Kumar * Copyright (c) 2023, Sebastian Reichel */ #include @@ -295,6 +295,6 @@ static struct platform_driver gab_driver = { }; module_platform_driver(gab_driver); -MODULE_AUTHOR("anish kumar "); +MODULE_AUTHOR("anish kumar "); MODULE_DESCRIPTION("generic battery driver using IIO"); MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/ipaq_micro_battery.c b/drivers/power/supply/ipaq_micro_battery.c index 66cc649f702afa..7e0568a5353f16 100644 --- a/drivers/power/supply/ipaq_micro_battery.c +++ b/drivers/power/supply/ipaq_micro_battery.c @@ -302,7 +302,7 @@ static struct platform_driver micro_batt_device_driver = { .pm = µ_batt_dev_pm_ops, }, .probe = micro_batt_probe, - .remove_new = micro_batt_remove, + .remove = micro_batt_remove, }; module_platform_driver(micro_batt_device_driver); diff --git a/drivers/power/supply/isp1704_charger.c b/drivers/power/supply/isp1704_charger.c index 860d8614c98fd3..237912a9227245 100644 --- a/drivers/power/supply/isp1704_charger.c +++ b/drivers/power/supply/isp1704_charger.c @@ -501,7 +501,7 @@ static struct platform_driver isp1704_charger_driver = { .of_match_table = of_match_ptr(omap_isp1704_of_match), }, .probe = isp1704_charger_probe, - .remove_new = isp1704_charger_remove, + .remove = isp1704_charger_remove, }; module_platform_driver(isp1704_charger_driver); diff --git a/drivers/power/supply/lenovo_yoga_c630_battery.c b/drivers/power/supply/lenovo_yoga_c630_battery.c index f98f65e00831a5..7a6c8af9e8c248 100644 --- a/drivers/power/supply/lenovo_yoga_c630_battery.c +++ b/drivers/power/supply/lenovo_yoga_c630_battery.c @@ -368,11 +368,12 @@ static int yoga_c630_psy_register_bat_psy(struct yoga_c630_psy *ecbat) bat_cfg.drv_data = ecbat; bat_cfg.fwnode = ecbat->fwnode; - ecbat->bat_psy = power_supply_register_no_ws(ecbat->dev, - ecbat->unit_mA ? - &yoga_c630_psy_bat_psy_desc_mA : - &yoga_c630_psy_bat_psy_desc_mWh, - &bat_cfg); + bat_cfg.no_wakeup_source = true; + ecbat->bat_psy = power_supply_register(ecbat->dev, + ecbat->unit_mA ? + &yoga_c630_psy_bat_psy_desc_mA : + &yoga_c630_psy_bat_psy_desc_mWh, + &bat_cfg); if (IS_ERR(ecbat->bat_psy)) { dev_err(ecbat->dev, "failed to register battery supply\n"); return PTR_ERR(ecbat->bat_psy); @@ -442,7 +443,8 @@ static int yoga_c630_psy_probe(struct auxiliary_device *adev, adp_cfg.fwnode = ecbat->fwnode; adp_cfg.supplied_to = (char **)&yoga_c630_psy_bat_psy_desc_mA.name; adp_cfg.num_supplicants = 1; - ecbat->adp_psy = devm_power_supply_register_no_ws(dev, &yoga_c630_psy_adpt_psy_desc, &adp_cfg); + adp_cfg.no_wakeup_source = true; + ecbat->adp_psy = devm_power_supply_register(dev, &yoga_c630_psy_adpt_psy_desc, &adp_cfg); if (IS_ERR(ecbat->adp_psy)) { dev_err(dev, "failed to register AC adapter supply\n"); return PTR_ERR(ecbat->adp_psy); diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c index 72b170b4ac46a7..f0a680c155c485 100644 --- a/drivers/power/supply/lp8788-charger.c +++ b/drivers/power/supply/lp8788-charger.c @@ -716,7 +716,7 @@ static void lp8788_charger_remove(struct platform_device *pdev) static struct platform_driver lp8788_charger_driver = { .probe = lp8788_charger_probe, - .remove_new = lp8788_charger_remove, + .remove = lp8788_charger_remove, .driver = { .name = LP8788_DEV_CHARGER, }, diff --git a/drivers/power/supply/max14577_charger.c b/drivers/power/supply/max14577_charger.c index b28c04157709a7..1cef2f860b5fcc 100644 --- a/drivers/power/supply/max14577_charger.c +++ b/drivers/power/supply/max14577_charger.c @@ -634,7 +634,7 @@ static struct platform_driver max14577_charger_driver = { .of_match_table = of_max14577_charger_dt_match, }, .probe = max14577_charger_probe, - .remove_new = max14577_charger_remove, + .remove = max14577_charger_remove, .id_table = max14577_charger_id, }; module_platform_driver(max14577_charger_driver); diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c index 818e13c613e355..5f58c0c24b4d63 100644 --- a/drivers/power/supply/max77650-charger.c +++ b/drivers/power/supply/max77650-charger.c @@ -364,7 +364,7 @@ static struct platform_driver max77650_charger_driver = { .of_match_table = max77650_charger_of_match, }, .probe = max77650_charger_probe, - .remove_new = max77650_charger_remove, + .remove = max77650_charger_remove, }; module_platform_driver(max77650_charger_driver); diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c index 4caac142c4285a..cdea35c0d1de11 100644 --- a/drivers/power/supply/max77693_charger.c +++ b/drivers/power/supply/max77693_charger.c @@ -798,7 +798,7 @@ static struct platform_driver max77693_charger_driver = { .name = "max77693-charger", }, .probe = max77693_charger_probe, - .remove_new = max77693_charger_remove, + .remove = max77693_charger_remove, .id_table = max77693_charger_id, }; module_platform_driver(max77693_charger_driver); diff --git a/drivers/power/supply/max77976_charger.c b/drivers/power/supply/max77976_charger.c index d7e520da768864..e6fe68cebc32b6 100644 --- a/drivers/power/supply/max77976_charger.c +++ b/drivers/power/supply/max77976_charger.c @@ -452,6 +452,7 @@ static int max77976_probe(struct i2c_client *client) i2c_set_clientdata(client, chg); psy_cfg.drv_data = chg; + psy_cfg.no_wakeup_source = true; chg->client = client; chg->regmap = devm_regmap_init_i2c(client, &max77976_regmap_config); @@ -475,7 +476,7 @@ static int max77976_probe(struct i2c_client *client) if (err) return err; - psy = devm_power_supply_register_no_ws(dev, &max77976_psy_desc, &psy_cfg); + psy = devm_power_supply_register(dev, &max77976_psy_desc, &psy_cfg); if (IS_ERR(psy)) return dev_err_probe(dev, PTR_ERR(psy), "cannot register\n"); diff --git a/drivers/power/supply/max8925_power.c b/drivers/power/supply/max8925_power.c index 621a006d52a960..d753145de3bb38 100644 --- a/drivers/power/supply/max8925_power.c +++ b/drivers/power/supply/max8925_power.c @@ -73,7 +73,7 @@ struct max8925_power_info { unsigned usb_online:1; unsigned bat_online:1; unsigned chg_mode:2; - unsigned batt_detect:1; /* detecing MB by ID pin */ + unsigned batt_detect:1; /* detecting MB by ID pin */ unsigned topoff_threshold:2; unsigned fast_charge:3; unsigned no_temp_support:1; @@ -563,7 +563,7 @@ static void max8925_power_remove(struct platform_device *pdev) static struct platform_driver max8925_power_driver = { .probe = max8925_power_probe, - .remove_new = max8925_power_remove, + .remove = max8925_power_remove, .driver = { .name = "max8925-power", }, diff --git a/drivers/power/supply/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c index 0e980522fee513..0136bc87b105e1 100644 --- a/drivers/power/supply/pcf50633-charger.c +++ b/drivers/power/supply/pcf50633-charger.c @@ -455,7 +455,7 @@ static struct platform_driver pcf50633_mbc_driver = { .name = "pcf50633-mbc", }, .probe = pcf50633_mbc_probe, - .remove_new = pcf50633_mbc_remove, + .remove = pcf50633_mbc_remove, }; module_platform_driver(pcf50633_mbc_driver); diff --git a/drivers/power/supply/pmu_battery.c b/drivers/power/supply/pmu_battery.c index eaab7500d99b5d..ed83c5e05ca320 100644 --- a/drivers/power/supply/pmu_battery.c +++ b/drivers/power/supply/pmu_battery.c @@ -170,6 +170,7 @@ static int __init pmu_bat_init(void) pbat->bat_desc.properties = pmu_bat_props; pbat->bat_desc.num_properties = ARRAY_SIZE(pmu_bat_props); pbat->bat_desc.get_property = pmu_bat_get_property; + pbat->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; pbat->pbi = &pmu_batteries[i]; psy_cfg.drv_data = pbat; diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h index 3cbafc58bdad0b..7434a6f2477504 100644 --- a/drivers/power/supply/power_supply.h +++ b/drivers/power/supply/power_supply.h @@ -13,9 +13,12 @@ struct device; struct device_type; struct power_supply; +extern int power_supply_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp); + #ifdef CONFIG_SYSFS -extern void power_supply_init_attrs(void); +extern void __init power_supply_init_attrs(void); extern int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env); extern const struct attribute_group *power_supply_attr_groups[]; @@ -41,3 +44,20 @@ static inline int power_supply_create_triggers(struct power_supply *psy) static inline void power_supply_remove_triggers(struct power_supply *psy) {} #endif /* CONFIG_LEDS_TRIGGERS */ + +#ifdef CONFIG_POWER_SUPPLY_HWMON + +int power_supply_add_hwmon_sysfs(struct power_supply *psy); +void power_supply_remove_hwmon_sysfs(struct power_supply *psy); + +#else + +static inline int power_supply_add_hwmon_sysfs(struct power_supply *psy) +{ + return 0; +} + +static inline +void power_supply_remove_hwmon_sysfs(struct power_supply *psy) {} + +#endif /* CONFIG_POWER_SUPPLY_HWMON */ diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 49534458a9f7d3..16085eff008442 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -152,7 +152,7 @@ static void power_supply_deferred_register_work(struct work_struct *work) deferred_register_work.work); if (psy->dev.parent) { - while (!mutex_trylock(&psy->dev.parent->mutex)) { + while (!device_trylock(psy->dev.parent)) { if (psy->removing) return; msleep(10); @@ -162,7 +162,7 @@ static void power_supply_deferred_register_work(struct work_struct *work) power_supply_changed(psy); if (psy->dev.parent) - mutex_unlock(&psy->dev.parent->mutex); + device_unlock(psy->dev.parent); } #ifdef CONFIG_OF @@ -484,8 +484,6 @@ EXPORT_SYMBOL_GPL(power_supply_get_by_name); */ void power_supply_put(struct power_supply *psy) { - might_sleep(); - atomic_dec(&psy->use_cnt); put_device(&psy->dev); } @@ -777,7 +775,7 @@ int power_supply_get_battery_info(struct power_supply *psy, tab_len = size / (2 * sizeof(__be32)); info->ocv_table_size[index] = tab_len; - table = info->ocv_table[index] = + info->ocv_table[index] = table = devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL); if (!info->ocv_table[index]) { power_supply_put_battery_info(psy, info); @@ -798,7 +796,7 @@ int power_supply_get_battery_info(struct power_supply *psy, goto out_ret_pointer; info->resist_table_size = len / (2 * sizeof(__be32)); - resist_table = info->resist_table = devm_kcalloc(&psy->dev, + info->resist_table = resist_table = devm_kcalloc(&psy->dev, info->resist_table_size, sizeof(*resist_table), GFP_KERNEL); @@ -982,7 +980,7 @@ EXPORT_SYMBOL_GPL(power_supply_battery_info_get_prop); * * Return: the battery internal resistance percent */ -int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *table, +int power_supply_temp2resist_simple(const struct power_supply_resistance_temp_table *table, int table_len, int temp) { int i, high, low; @@ -1093,7 +1091,7 @@ EXPORT_SYMBOL_GPL(power_supply_get_maintenance_charging_setting); * * Return: the battery capacity. */ -int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table, +int power_supply_ocv2cap_simple(const struct power_supply_battery_ocv_table *table, int table_len, int ocv) { int i, high, low; @@ -1118,7 +1116,7 @@ int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table, } EXPORT_SYMBOL_GPL(power_supply_ocv2cap_simple); -struct power_supply_battery_ocv_table * +const struct power_supply_battery_ocv_table * power_supply_find_ocv2cap_table(struct power_supply_battery_info *info, int temp, int *table_len) { @@ -1149,7 +1147,7 @@ EXPORT_SYMBOL_GPL(power_supply_find_ocv2cap_table); int power_supply_batinfo_ocv2cap(struct power_supply_battery_info *info, int ocv, int temp) { - struct power_supply_battery_ocv_table *table; + const struct power_supply_battery_ocv_table *table; int table_len; table = power_supply_find_ocv2cap_table(info, temp, &table_len); @@ -1233,7 +1231,6 @@ int power_supply_property_is_writeable(struct power_supply *psy, { return psy->desc->property_is_writeable && psy->desc->property_is_writeable(psy, psp); } -EXPORT_SYMBOL_GPL(power_supply_property_is_writeable); void power_supply_external_power_changed(struct power_supply *psy) { @@ -1342,8 +1339,7 @@ static void psy_unregister_thermal(struct power_supply *psy) static struct power_supply *__must_check __power_supply_register(struct device *parent, const struct power_supply_desc *desc, - const struct power_supply_config *cfg, - bool ws) + const struct power_supply_config *cfg) { struct device *dev; struct power_supply *psy; @@ -1410,7 +1406,7 @@ __power_supply_register(struct device *parent, if (rc) goto device_add_failed; - rc = device_init_wakeup(dev, ws); + rc = device_init_wakeup(dev, cfg ? !cfg->no_wakeup_source : true); if (rc) goto wakeup_init_failed; @@ -1476,33 +1472,10 @@ struct power_supply *__must_check power_supply_register(struct device *parent, const struct power_supply_desc *desc, const struct power_supply_config *cfg) { - return __power_supply_register(parent, desc, cfg, true); + return __power_supply_register(parent, desc, cfg); } EXPORT_SYMBOL_GPL(power_supply_register); -/** - * power_supply_register_no_ws() - Register new non-waking-source power supply - * @parent: Device to be a parent of power supply's device, usually - * the device which probe function calls this - * @desc: Description of power supply, must be valid through whole - * lifetime of this power supply - * @cfg: Run-time specific configuration accessed during registering, - * may be NULL - * - * Return: A pointer to newly allocated power_supply on success - * or ERR_PTR otherwise. - * Use power_supply_unregister() on returned power_supply pointer to release - * resources. - */ -struct power_supply *__must_check -power_supply_register_no_ws(struct device *parent, - const struct power_supply_desc *desc, - const struct power_supply_config *cfg) -{ - return __power_supply_register(parent, desc, cfg, false); -} -EXPORT_SYMBOL_GPL(power_supply_register_no_ws); - static void devm_power_supply_release(struct device *dev, void *res) { struct power_supply **psy = res; @@ -1535,7 +1508,7 @@ devm_power_supply_register(struct device *parent, if (!ptr) return ERR_PTR(-ENOMEM); - psy = __power_supply_register(parent, desc, cfg, true); + psy = __power_supply_register(parent, desc, cfg); if (IS_ERR(psy)) { devres_free(ptr); } else { @@ -1546,42 +1519,6 @@ devm_power_supply_register(struct device *parent, } EXPORT_SYMBOL_GPL(devm_power_supply_register); -/** - * devm_power_supply_register_no_ws() - Register managed non-waking-source power supply - * @parent: Device to be a parent of power supply's device, usually - * the device which probe function calls this - * @desc: Description of power supply, must be valid through whole - * lifetime of this power supply - * @cfg: Run-time specific configuration accessed during registering, - * may be NULL - * - * Return: A pointer to newly allocated power_supply on success - * or ERR_PTR otherwise. - * The returned power_supply pointer will be automatically unregistered - * on driver detach. - */ -struct power_supply *__must_check -devm_power_supply_register_no_ws(struct device *parent, - const struct power_supply_desc *desc, - const struct power_supply_config *cfg) -{ - struct power_supply **ptr, *psy; - - ptr = devres_alloc(devm_power_supply_release, sizeof(*ptr), GFP_KERNEL); - - if (!ptr) - return ERR_PTR(-ENOMEM); - psy = __power_supply_register(parent, desc, cfg, false); - if (IS_ERR(psy)) { - devres_free(ptr); - } else { - *ptr = psy; - devres_add(parent, ptr); - } - return psy; -} -EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws); - /** * power_supply_unregister() - Remove this power supply from system * @psy: Pointer to power supply to unregister diff --git a/drivers/power/supply/power_supply_hwmon.c b/drivers/power/supply/power_supply_hwmon.c index 6fbbfb1c685e6c..01be04903d7d24 100644 --- a/drivers/power/supply/power_supply_hwmon.c +++ b/drivers/power/supply/power_supply_hwmon.c @@ -7,6 +7,7 @@ #include #include #include +#include "power_supply.h" struct power_supply_hwmon { struct power_supply *psy; diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 16b3c5880cd8ce..571de43fcca982 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -142,7 +142,7 @@ static const char * const POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[] = { [POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE] = "force-discharge", }; -static struct power_supply_attr power_supply_attrs[] = { +static struct power_supply_attr power_supply_attrs[] __ro_after_init = { /* Properties of type `int' */ POWER_SUPPLY_ENUM_ATTR(STATUS), POWER_SUPPLY_ENUM_ATTR(CHARGE_TYPE), @@ -225,9 +225,9 @@ static struct power_supply_attr power_supply_attrs[] = { #define POWER_SUPPLY_ATTR_CNT ARRAY_SIZE(power_supply_attrs) static struct attribute * -__power_supply_attrs[POWER_SUPPLY_ATTR_CNT + 1]; +__power_supply_attrs[POWER_SUPPLY_ATTR_CNT + 1] __ro_after_init; -static struct power_supply_attr *to_ps_attr(struct device_attribute *attr) +static const struct power_supply_attr *to_ps_attr(struct device_attribute *attr) { return container_of(attr, struct power_supply_attr, dev_attr); } @@ -273,7 +273,7 @@ static ssize_t power_supply_show_property(struct device *dev, char *buf) { ssize_t ret; struct power_supply *psy = dev_get_drvdata(dev); - struct power_supply_attr *ps_attr = to_ps_attr(attr); + const struct power_supply_attr *ps_attr = to_ps_attr(attr); enum power_supply_property psp = dev_attr_psp(attr); union power_supply_propval value; @@ -326,7 +326,7 @@ static ssize_t power_supply_store_property(struct device *dev, const char *buf, size_t count) { ssize_t ret; struct power_supply *psy = dev_get_drvdata(dev); - struct power_supply_attr *ps_attr = to_ps_attr(attr); + const struct power_supply_attr *ps_attr = to_ps_attr(attr); enum power_supply_property psp = dev_attr_psp(attr); union power_supply_propval value; @@ -401,7 +401,7 @@ const struct attribute_group *power_supply_attr_groups[] = { NULL }; -void power_supply_init_attrs(void) +void __init power_supply_init_attrs(void) { int i; diff --git a/drivers/power/supply/qcom_battmgr.c b/drivers/power/supply/qcom_battmgr.c index f0a64c00ddaae0..47d29271ddf400 100644 --- a/drivers/power/supply/qcom_battmgr.c +++ b/drivers/power/supply/qcom_battmgr.c @@ -151,7 +151,7 @@ struct qcom_battmgr_message { __le32 capacity_low; __le32 capacity_warning; __le32 cycle_count; - /* thousandth of persent */ + /* thousandth of percent */ __le32 accuracy; __le32 max_sample_time_ms; __le32 min_sample_time_ms; diff --git a/drivers/power/supply/qcom_pmi8998_charger.c b/drivers/power/supply/qcom_pmi8998_charger.c index 81acbd8b2169ce..3b4132376649e0 100644 --- a/drivers/power/supply/qcom_pmi8998_charger.c +++ b/drivers/power/supply/qcom_pmi8998_charger.c @@ -832,7 +832,7 @@ static const struct smb2_register smb2_init_seq[] = { AUTO_RECHG_BIT | EN_ANALOG_DROP_IN_VBATT_BIT | CHARGER_INHIBIT_BIT, .val = CHARGER_INHIBIT_BIT }, - /* STAT pin software override, match downstream. Parallell charging? */ + /* STAT pin software override, match downstream. Parallel charging? */ { .addr = STAT_CFG, .mask = STAT_SW_OVERRIDE_CFG_BIT, .val = STAT_SW_OVERRIDE_CFG_BIT }, diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c index 4e57762e27badc..a79563f6ff7a0c 100644 --- a/drivers/power/supply/qcom_smbb.c +++ b/drivers/power/supply/qcom_smbb.c @@ -1017,10 +1017,10 @@ static const struct of_device_id smbb_charger_id_table[] = { MODULE_DEVICE_TABLE(of, smbb_charger_id_table); static struct platform_driver smbb_charger_driver = { - .probe = smbb_charger_probe, - .remove_new = smbb_charger_remove, - .driver = { - .name = "qcom-smbb", + .probe = smbb_charger_probe, + .remove = smbb_charger_remove, + .driver = { + .name = "qcom-smbb", .of_match_table = smbb_charger_id_table, }, }; diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c index 57b6ddefad28db..e5f35d083c23d5 100644 --- a/drivers/power/supply/rk817_charger.c +++ b/drivers/power/supply/rk817_charger.c @@ -240,9 +240,32 @@ static int rk817_record_battery_nvram_values(struct rk817_charger *charger) static int rk817_bat_calib_cap(struct rk817_charger *charger) { struct rk808 *rk808 = charger->rk808; - int tmp, charge_now, charge_now_adc, volt_avg; + int charge_now, charge_now_adc; u8 bulk_reg[4]; + /* Don't do anything if there's no battery. */ + if (!charger->battery_present) + return 0; + + /* + * When resuming from suspend, sometimes the voltage value would be + * incorrect. BSP would simply wait two seconds and try reading the + * values again. Do not do any sort of calibration activity when the + * reported value is incorrect. The next scheduled update of battery + * vaules should then return valid data and the driver can continue. + * Use 2.7v as the sanity value because per the datasheet the PMIC + * can in no way support a battery voltage lower than this. BSP only + * checked for values too low, but I'm adding in a check for values + * too high just in case; again the PMIC can in no way support + * voltages above 4.45v, so this seems like a good value. + */ + if ((charger->volt_avg_uv < 2700000) || (charger->volt_avg_uv > 4450000)) { + dev_dbg(charger->dev, + "Battery voltage of %d is invalid, ignoring.\n", + charger->volt_avg_uv); + return -EINVAL; + } + /* Calibrate the soc and fcc on a fully charged battery */ if (charger->charge_status == CHARGE_FINISH && (!charger->soc_cal)) { @@ -304,51 +327,6 @@ static int rk817_bat_calib_cap(struct rk817_charger *charger) } } - /* - * Calibrate the fully charged capacity when we previously had a full - * battery (soc_cal = 1) and are now empty (at or below minimum design - * voltage). If our columb counter is still positive, subtract that - * from our fcc value to get a calibrated fcc, and if our columb - * counter is negative add that to our fcc (but not to exceed our - * design capacity). - */ - regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_BAT_VOL_H, - bulk_reg, 2); - tmp = get_unaligned_be16(bulk_reg); - volt_avg = (charger->voltage_k * tmp) + 1000 * charger->voltage_b; - if (volt_avg <= charger->bat_voltage_min_design_uv && - charger->soc_cal) { - regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3, - bulk_reg, 4); - charge_now_adc = get_unaligned_be32(bulk_reg); - charge_now = ADC_TO_CHARGE_UAH(charge_now_adc, - charger->res_div); - /* - * Note, if charge_now is negative this will add it (what we - * want) and if it's positive this will subtract (also what - * we want). - */ - charger->fcc_mah = charger->fcc_mah - (charge_now / 1000); - - dev_dbg(charger->dev, - "Recalibrating full charge capacity to %d uah\n", - 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; @@ -648,6 +626,24 @@ static irqreturn_t rk817_plug_out_isr(int irq, void *cg) return IRQ_HANDLED; } +static int rk817_bat_set_prop(struct power_supply *ps, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + struct rk817_charger *charger = power_supply_get_drvdata(ps); + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGE_FULL: + if ((val->intval < 500000) || + (val->intval > charger->bat_charge_full_design_uah)) + return -EINVAL; + charger->fcc_mah = val->intval / 1000; + return rk817_bat_calib_cap(charger); + default: + return -EINVAL; + } +} + static enum power_supply_property rk817_bat_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_STATUS, @@ -673,12 +669,25 @@ static enum power_supply_property rk817_chg_props[] = { POWER_SUPPLY_PROP_VOLTAGE_AVG, }; +static int rk817_bat_prop_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_FULL: + return 1; + default: + return 0; + } +} + static const struct power_supply_desc rk817_bat_desc = { .name = "rk817-battery", .type = POWER_SUPPLY_TYPE_BATTERY, .properties = rk817_bat_props, + .property_is_writeable = rk817_bat_prop_writeable, .num_properties = ARRAY_SIZE(rk817_bat_props), .get_property = rk817_bat_get_prop, + .set_property = rk817_bat_set_prop, }; static const struct power_supply_desc rk817_chg_desc = { @@ -1202,6 +1211,15 @@ static int rk817_charger_probe(struct platform_device *pdev) return 0; } +static int __maybe_unused rk817_suspend(struct device *dev) +{ + struct rk817_charger *charger = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&charger->work); + + return 0; +} + static int __maybe_unused rk817_resume(struct device *dev) { @@ -1213,7 +1231,7 @@ static int __maybe_unused rk817_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(rk817_charger_pm, NULL, rk817_resume); +static SIMPLE_DEV_PM_OPS(rk817_charger_pm, rk817_suspend, rk817_resume); static struct platform_driver rk817_charger_driver = { .probe = rk817_charger_probe, diff --git a/drivers/power/supply/rt9471.c b/drivers/power/supply/rt9471.c index c04af1ee89c675..67b86ac91a21dd 100644 --- a/drivers/power/supply/rt9471.c +++ b/drivers/power/supply/rt9471.c @@ -139,6 +139,19 @@ enum { RT9471_PORTSTAT_DCP, }; +enum { + RT9471_ICSTAT_SLEEP = 0, + RT9471_ICSTAT_VBUSRDY, + RT9471_ICSTAT_TRICKLECHG, + RT9471_ICSTAT_PRECHG, + RT9471_ICSTAT_FASTCHG, + RT9471_ICSTAT_IEOC, + RT9471_ICSTAT_BGCHG, + RT9471_ICSTAT_CHGDONE, + RT9471_ICSTAT_CHGFAULT, + RT9471_ICSTAT_OTG = 15, +}; + struct rt9471_chip { struct device *dev; struct regmap *regmap; @@ -153,8 +166,8 @@ struct rt9471_chip { }; static const struct reg_field rt9471_reg_fields[F_MAX_FIELDS] = { - [F_WDT] = REG_FIELD(RT9471_REG_TOP, 0, 0), - [F_WDT_RST] = REG_FIELD(RT9471_REG_TOP, 1, 1), + [F_WDT] = REG_FIELD(RT9471_REG_TOP, 0, 1), + [F_WDT_RST] = REG_FIELD(RT9471_REG_TOP, 2, 2), [F_CHG_EN] = REG_FIELD(RT9471_REG_FUNC, 0, 0), [F_HZ] = REG_FIELD(RT9471_REG_FUNC, 5, 5), [F_BATFET_DIS] = REG_FIELD(RT9471_REG_FUNC, 7, 7), @@ -255,31 +268,32 @@ static int rt9471_get_ieoc(struct rt9471_chip *chip, int *microamp) static int rt9471_get_status(struct rt9471_chip *chip, int *status) { - unsigned int chg_ready, chg_done, fault_stat; + unsigned int ic_stat; int ret; - ret = regmap_field_read(chip->rm_fields[F_ST_CHG_RDY], &chg_ready); - if (ret) - return ret; - - ret = regmap_field_read(chip->rm_fields[F_ST_CHG_DONE], &chg_done); + ret = regmap_field_read(chip->rm_fields[F_IC_STAT], &ic_stat); if (ret) return ret; - ret = regmap_read(chip->regmap, RT9471_REG_STAT1, &fault_stat); - if (ret) - return ret; - - fault_stat &= RT9471_CHGFAULT_MASK; - - if (chg_ready && chg_done) - *status = POWER_SUPPLY_STATUS_FULL; - else if (chg_ready && fault_stat) + switch (ic_stat) { + case RT9471_ICSTAT_VBUSRDY: + case RT9471_ICSTAT_CHGFAULT: *status = POWER_SUPPLY_STATUS_NOT_CHARGING; - else if (chg_ready && !fault_stat) + break; + case RT9471_ICSTAT_TRICKLECHG ... RT9471_ICSTAT_BGCHG: *status = POWER_SUPPLY_STATUS_CHARGING; - else + break; + case RT9471_ICSTAT_CHGDONE: + *status = POWER_SUPPLY_STATUS_FULL; + break; + case RT9471_ICSTAT_SLEEP: + case RT9471_ICSTAT_OTG: *status = POWER_SUPPLY_STATUS_DISCHARGING; + break; + default: + *status = POWER_SUPPLY_STATUS_UNKNOWN; + break; + } return 0; } diff --git a/drivers/power/supply/samsung-sdi-battery.c b/drivers/power/supply/samsung-sdi-battery.c index b63fd2758c2f13..33565002ee2705 100644 --- a/drivers/power/supply/samsung-sdi-battery.c +++ b/drivers/power/supply/samsung-sdi-battery.c @@ -431,7 +431,7 @@ static const struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb58515 * temperature compensation tables so we just state 100% for every temperature. * If you have the datasheets, please provide these tables. */ -static struct power_supply_resistance_temp_table samsung_temp2res[] = { +static const struct power_supply_resistance_temp_table samsung_temp2res[] = { { .temp = 50, .resistance = 100 }, { .temp = 40, .resistance = 100 }, { .temp = 30, .resistance = 100 }, @@ -447,7 +447,7 @@ static struct power_supply_resistance_temp_table samsung_temp2res[] = { * These must be sorted by falling OCV value. */ -static struct power_supply_battery_ocv_table samsung_ocv_cap_eb485159lu[] = { +static const struct power_supply_battery_ocv_table samsung_ocv_cap_eb485159lu[] = { { .ocv = 4330000, .capacity = 100}, { .ocv = 4320000, .capacity = 99}, { .ocv = 4283000, .capacity = 95}, @@ -499,7 +499,7 @@ static struct power_supply_battery_ocv_table samsung_ocv_cap_eb485159lu[] = { }; /* Same capacity table is used by eb-l1m7flu, eb425161la, eb425161lu */ -static struct power_supply_battery_ocv_table samsung_ocv_cap_1500mah[] = { +static const struct power_supply_battery_ocv_table samsung_ocv_cap_1500mah[] = { { .ocv = 4328000, .capacity = 100}, { .ocv = 4299000, .capacity = 99}, { .ocv = 4281000, .capacity = 98}, @@ -540,7 +540,7 @@ static struct power_supply_battery_ocv_table samsung_ocv_cap_1500mah[] = { { .ocv = 3300000, .capacity = 0}, }; -static struct power_supply_battery_ocv_table samsung_ocv_cap_eb535151vu[] = { +static const struct power_supply_battery_ocv_table samsung_ocv_cap_eb535151vu[] = { { .ocv = 4178000, .capacity = 100}, { .ocv = 4148000, .capacity = 99}, { .ocv = 4105000, .capacity = 95}, @@ -572,7 +572,7 @@ static struct power_supply_battery_ocv_table samsung_ocv_cap_eb535151vu[] = { { .ocv = 3300000, .capacity = 0}, }; -static struct power_supply_battery_ocv_table samsung_ocv_cap_eb585157lu[] = { +static const struct power_supply_battery_ocv_table samsung_ocv_cap_eb585157lu[] = { { .ocv = 4320000, .capacity = 100}, { .ocv = 4296000, .capacity = 99}, { .ocv = 4283000, .capacity = 98}, diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c index b3d8b1ca97da70..50d5157af9277d 100644 --- a/drivers/power/supply/sc2731_charger.c +++ b/drivers/power/supply/sc2731_charger.c @@ -530,7 +530,7 @@ static struct platform_driver sc2731_charger_driver = { .of_match_table = sc2731_charger_of_match, }, .probe = sc2731_charger_probe, - .remove_new = sc2731_charger_remove, + .remove = sc2731_charger_remove, }; module_platform_driver(sc2731_charger_driver); diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index bd23c4d9fed434..f36edc2ba70874 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -992,7 +992,7 @@ static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data) static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data) { struct power_supply_battery_info *info; - struct power_supply_battery_ocv_table *table; + const struct power_supply_battery_ocv_table *table; int ret, delta_clbcnt, alarm_adc; ret = power_supply_get_battery_info(data->battery, &info); @@ -1183,10 +1183,14 @@ static int sc27xx_fgu_probe(struct platform_device *pdev) return PTR_ERR(data->charge_chan); } - data->gpiod = devm_gpiod_get(dev, "bat-detect", GPIOD_IN); + data->gpiod = devm_gpiod_get(dev, "battery-detect", GPIOD_IN); if (IS_ERR(data->gpiod)) { - dev_err(dev, "failed to get battery detection GPIO\n"); - return PTR_ERR(data->gpiod); + data->gpiod = devm_gpiod_get(dev, "bat-detect", GPIOD_IN); + if (IS_ERR(data->gpiod)) { + dev_err(dev, "failed to get battery detection GPIO\n"); + return PTR_ERR(data->gpiod); + } + dev_warn(dev, "bat-detect is deprecated, please use battery-detect\n"); } ret = gpiod_get_value_cansleep(data->gpiod); diff --git a/drivers/power/supply/tps65090-charger.c b/drivers/power/supply/tps65090-charger.c index d41595764caa52..d65193e410a625 100644 --- a/drivers/power/supply/tps65090-charger.c +++ b/drivers/power/supply/tps65090-charger.c @@ -343,7 +343,7 @@ static struct platform_driver tps65090_charger_driver = { .of_match_table = of_tps65090_charger_match, }, .probe = tps65090_charger_probe, - .remove_new = tps65090_charger_remove, + .remove = tps65090_charger_remove, }; module_platform_driver(tps65090_charger_driver); diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c index 2382749a2f5311..6fff44e1ecac80 100644 --- a/drivers/power/supply/tps65217_charger.c +++ b/drivers/power/supply/tps65217_charger.c @@ -269,7 +269,7 @@ MODULE_DEVICE_TABLE(of, tps65217_charger_match_table); static struct platform_driver tps65217_charger_driver = { .probe = tps65217_charger_probe, - .remove_new = tps65217_charger_remove, + .remove = tps65217_charger_remove, .driver = { .name = "tps65217-charger", .of_match_table = of_match_ptr(tps65217_charger_match_table), diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index f3f1a0862e935c..9dcb5457bef41c 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -1133,7 +1133,7 @@ MODULE_DEVICE_TABLE(of, twl_bci_of_match); static struct platform_driver twl4030_bci_driver = { .probe = twl4030_bci_probe, - .remove_new = twl4030_bci_remove, + .remove = twl4030_bci_remove, .driver = { .name = "twl4030_bci", .of_match_table = of_match_ptr(twl_bci_of_match), diff --git a/drivers/power/supply/twl6030_charger.c b/drivers/power/supply/twl6030_charger.c new file mode 100644 index 00000000000000..b4ec26ff257ccc --- /dev/null +++ b/drivers/power/supply/twl6030_charger.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TWL6030 charger + * + * Copyright (C) 2024 Andreas Kemnade + * + * based on older 6030 driver found in a v3.0 vendor kernel + * + * based on twl4030_bci_battery.c by TI + * Copyright (C) 2008 Texas Instruments, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONTROLLER_INT_MASK 0x00 +#define CONTROLLER_CTRL1 0x01 +#define CONTROLLER_WDG 0x02 +#define CONTROLLER_STAT1 0x03 +#define CHARGERUSB_INT_STATUS 0x04 +#define CHARGERUSB_INT_MASK 0x05 +#define CHARGERUSB_STATUS_INT1 0x06 +#define CHARGERUSB_STATUS_INT2 0x07 +#define CHARGERUSB_CTRL1 0x08 +#define CHARGERUSB_CTRL2 0x09 +#define CHARGERUSB_CTRL3 0x0A +#define CHARGERUSB_STAT1 0x0B +#define CHARGERUSB_VOREG 0x0C +#define CHARGERUSB_VICHRG 0x0D +#define CHARGERUSB_CINLIMIT 0x0E +#define CHARGERUSB_CTRLLIMIT1 0x0F +#define CHARGERUSB_CTRLLIMIT2 0x10 +#define ANTICOLLAPSE_CTRL1 0x11 +#define ANTICOLLAPSE_CTRL2 0x12 + +/* TWL6032 registers 0xDA to 0xDE - TWL6032_MODULE_CHARGER */ +#define CONTROLLER_CTRL2 0x00 +#define CONTROLLER_VSEL_COMP 0x01 +#define CHARGERUSB_VSYSREG 0x02 +#define CHARGERUSB_VICHRG_PC 0x03 +#define LINEAR_CHRG_STS 0x04 + +#define LINEAR_CHRG_STS_CRYSTL_OSC_OK 0x40 +#define LINEAR_CHRG_STS_END_OF_CHARGE 0x20 +#define LINEAR_CHRG_STS_VBATOV 0x10 +#define LINEAR_CHRG_STS_VSYSOV 0x08 +#define LINEAR_CHRG_STS_DPPM_STS 0x04 +#define LINEAR_CHRG_STS_CV_STS 0x02 +#define LINEAR_CHRG_STS_CC_STS 0x01 + +#define FG_REG_00 0x00 +#define FG_REG_01 0x01 +#define FG_REG_02 0x02 +#define FG_REG_03 0x03 +#define FG_REG_04 0x04 +#define FG_REG_05 0x05 +#define FG_REG_06 0x06 +#define FG_REG_07 0x07 +#define FG_REG_08 0x08 +#define FG_REG_09 0x09 +#define FG_REG_10 0x0A +#define FG_REG_11 0x0B + +/* CONTROLLER_INT_MASK */ +#define MVAC_FAULT BIT(7) +#define MAC_EOC BIT(6) +#define LINCH_GATED BIT(5) +#define MBAT_REMOVED BIT(4) +#define MFAULT_WDG BIT(3) +#define MBAT_TEMP BIT(2) +#define MVBUS_DET BIT(1) +#define MVAC_DET BIT(0) + +/* CONTROLLER_CTRL1 */ +#define CONTROLLER_CTRL1_EN_LINCH BIT(5) +#define CONTROLLER_CTRL1_EN_CHARGER BIT(4) +#define CONTROLLER_CTRL1_SEL_CHARGER BIT(3) + +/* CONTROLLER_STAT1 */ +#define CONTROLLER_STAT1_EXTCHRG_STATZ BIT(7) +#define CONTROLLER_STAT1_LINCH_GATED BIT(6) +#define CONTROLLER_STAT1_CHRG_DET_N BIT(5) +#define CONTROLLER_STAT1_FAULT_WDG BIT(4) +#define CONTROLLER_STAT1_VAC_DET BIT(3) +#define VAC_DET BIT(3) +#define CONTROLLER_STAT1_VBUS_DET BIT(2) +#define VBUS_DET BIT(2) +#define CONTROLLER_STAT1_BAT_REMOVED BIT(1) +#define CONTROLLER_STAT1_BAT_TEMP_OVRANGE BIT(0) + +/* CHARGERUSB_INT_STATUS */ +#define EN_LINCH BIT(4) +#define CURRENT_TERM_INT BIT(3) +#define CHARGERUSB_STAT BIT(2) +#define CHARGERUSB_THMREG BIT(1) +#define CHARGERUSB_FAULT BIT(0) + +/* CHARGERUSB_INT_MASK */ +#define MASK_MCURRENT_TERM BIT(3) +#define MASK_MCHARGERUSB_STAT BIT(2) +#define MASK_MCHARGERUSB_THMREG BIT(1) +#define MASK_MCHARGERUSB_FAULT BIT(0) + +/* CHARGERUSB_STATUS_INT1 */ +#define CHARGERUSB_STATUS_INT1_TMREG BIT(7) +#define CHARGERUSB_STATUS_INT1_NO_BAT BIT(6) +#define CHARGERUSB_STATUS_INT1_BST_OCP BIT(5) +#define CHARGERUSB_STATUS_INT1_TH_SHUTD BIT(4) +#define CHARGERUSB_STATUS_INT1_BAT_OVP BIT(3) +#define CHARGERUSB_STATUS_INT1_POOR_SRC BIT(2) +#define CHARGERUSB_STATUS_INT1_SLP_MODE BIT(1) +#define CHARGERUSB_STATUS_INT1_VBUS_OVP BIT(0) + +/* CHARGERUSB_STATUS_INT2 */ +#define ICCLOOP BIT(3) +#define CURRENT_TERM BIT(2) +#define CHARGE_DONE BIT(1) +#define ANTICOLLAPSE BIT(0) + +/* CHARGERUSB_CTRL1 */ +#define SUSPEND_BOOT BIT(7) +#define OPA_MODE BIT(6) +#define HZ_MODE BIT(5) +#define TERM BIT(4) + +/* CHARGERUSB_CTRL2 */ +#define UA_TO_VITERM(x) (((x) / 50000 - 1) << 5) + +/* CHARGERUSB_CTRL3 */ +#define VBUSCHRG_LDO_OVRD BIT(7) +#define CHARGE_ONCE BIT(6) +#define BST_HW_PR_DIS BIT(5) +#define AUTOSUPPLY BIT(3) +#define BUCK_HSILIM BIT(0) + +/* CHARGERUSB_VOREG */ +#define UV_TO_VOREG(x) (((x) - 3500000) / 20000) +#define VOREG_TO_UV(x) (((x) & 0x3F) * 20000 + 3500000) +#define CHARGERUSB_VOREG_3P52 0x01 +#define CHARGERUSB_VOREG_4P0 0x19 +#define CHARGERUSB_VOREG_4P2 0x23 +#define CHARGERUSB_VOREG_4P76 0x3F + +/* CHARGERUSB_VICHRG */ +/* + * might be inaccurate for < 500 mA, diffent scale might apply, + * either starting from 100 mA or 300 mA + */ +#define UA_TO_VICHRG(x) (((x) / 100000) - 1) +#define VICHRG_TO_UA(x) (((x) & 0xf) * 100000 + 100000) + +/* CHARGERUSB_CINLIMIT */ +#define CHARGERUSB_CIN_LIMIT_100 0x1 +#define CHARGERUSB_CIN_LIMIT_300 0x5 +#define CHARGERUSB_CIN_LIMIT_500 0x9 +#define CHARGERUSB_CIN_LIMIT_NONE 0xF + +/* CHARGERUSB_CTRLLIMIT2 */ +#define CHARGERUSB_CTRLLIMIT2_1500 0x0E +#define LOCK_LIMIT BIT(4) + +/* ANTICOLLAPSE_CTRL2 */ +#define BUCK_VTH_SHIFT 5 + +/* FG_REG_00 */ +#define CC_ACTIVE_MODE_SHIFT 6 +#define CC_AUTOCLEAR BIT(2) +#define CC_CAL_EN BIT(1) +#define CC_PAUSE BIT(0) + +#define REG_TOGGLE1 0x90 +#define REG_PWDNSTATUS1 0x93 +#define FGDITHS BIT(7) +#define FGDITHR BIT(6) +#define FGS BIT(5) +#define FGR BIT(4) +#define BBSPOR_CFG 0xE6 +#define BB_CHG_EN BIT(3) + +struct twl6030_charger_info { + struct device *dev; + struct power_supply *usb; + struct power_supply_battery_info *binfo; + struct work_struct work; + int irq_chg; + int input_current_limit; + struct iio_channel *channel_vusb; + struct delayed_work charger_monitor; + bool extended_current_range; +}; + +struct twl6030_charger_chip_data { + bool extended_current_range; +}; + +static int twl6030_charger_read(u8 reg, u8 *val) +{ + return twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, val, reg); +} + +static int twl6030_charger_write(u8 reg, u8 val) +{ + return twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, val, reg); +} + +static int twl6030_config_cinlimit_reg(struct twl6030_charger_info *charger, + unsigned int ua) +{ + if (ua >= 50000 && ua <= 750000) { + ua = (ua - 50000) / 50000; + } else if ((ua > 750000) && (ua <= 1500000) && charger->extended_current_range) { + ua = ((ua % 100000) ? 0x30 : 0x20) + ((ua - 100000) / 100000); + } else { + if (ua < 50000) { + dev_err(charger->dev, "invalid input current limit\n"); + return -EINVAL; + } + /* This is no current limit */ + ua = 0x0F; + } + + return twl6030_charger_write(CHARGERUSB_CINLIMIT, ua); +} + +/* + * rewriting all stuff here, resets to extremely conservative defaults were + * seen under some circumstances, like charge voltage to 3.5V + */ +static int twl6030_enable_usb(struct twl6030_charger_info *charger) +{ + int ret; + + ret = twl6030_charger_write(CHARGERUSB_VICHRG, + UA_TO_VICHRG(charger->binfo->constant_charge_current_max_ua)); + if (ret < 0) + return ret; + + ret = twl6030_charger_write(CONTROLLER_WDG, 0xff); + if (ret < 0) + return ret; + + charger->input_current_limit = 500000; + ret = twl6030_config_cinlimit_reg(charger, charger->input_current_limit); + if (ret < 0) + return ret; + + ret = twl6030_charger_write(CHARGERUSB_CINLIMIT, CHARGERUSB_CIN_LIMIT_500); + if (ret < 0) + return ret; + + ret = twl6030_charger_write(CHARGERUSB_VOREG, + UV_TO_VOREG(charger->binfo->constant_charge_voltage_max_uv)); + if (ret < 0) + return ret; + + ret = twl6030_charger_write(CHARGERUSB_CTRL1, TERM); + if (ret < 0) + return ret; + + if (charger->binfo->charge_term_current_ua != -EINVAL) { + ret = twl6030_charger_write(CHARGERUSB_CTRL2, + UA_TO_VITERM(charger->binfo->charge_term_current_ua)); + if (ret < 0) + return ret; + } + + return twl6030_charger_write(CONTROLLER_CTRL1, CONTROLLER_CTRL1_EN_CHARGER); +} + +static void twl6030_charger_wdg(struct work_struct *data) +{ + struct twl6030_charger_info *charger = + container_of(data, struct twl6030_charger_info, + charger_monitor.work); + + u8 val; + u8 int_stat; + u8 stat_int1; + u8 stat_int2; + + twl6030_charger_read(CONTROLLER_STAT1, &val); + twl6030_charger_read(CHARGERUSB_INT_STATUS, &int_stat); + twl6030_charger_read(CHARGERUSB_STATUS_INT1, &stat_int1); + twl6030_charger_read(CHARGERUSB_STATUS_INT2, &stat_int2); + dev_dbg(charger->dev, + "wdg: stat1: %02x %s INT_STATUS %02x STATUS_INT1 %02x STATUS_INT2 %02x\n", + val, (val & VBUS_DET) ? "usb online" : "usb offline", + int_stat, stat_int1, stat_int2); + + twl6030_charger_write(CONTROLLER_WDG, 0xff); + schedule_delayed_work(&charger->charger_monitor, + msecs_to_jiffies(10000)); +} + +static irqreturn_t twl6030_charger_interrupt(int irq, void *arg) +{ + struct twl6030_charger_info *charger = arg; + u8 val; + u8 int_stat; + u8 stat_int1; + u8 stat_int2; + + if (twl6030_charger_read(CONTROLLER_STAT1, &val) < 0) + return IRQ_HANDLED; + + if (twl6030_charger_read(CHARGERUSB_INT_STATUS, &int_stat) < 0) + return IRQ_HANDLED; + + if (twl6030_charger_read(CHARGERUSB_STATUS_INT1, &stat_int1) < 0) + return IRQ_HANDLED; + + if (twl6030_charger_read(CHARGERUSB_STATUS_INT2, &stat_int2) < 0) + return IRQ_HANDLED; + + dev_dbg(charger->dev, + "charger irq: stat1: %02x %s INT_STATUS %02x STATUS_INT1 %02x STATUS_INT2 %02x\n", + val, (val & VBUS_DET) ? "usb online" : "usb offline", + int_stat, stat_int1, stat_int2); + power_supply_changed(charger->usb); + + if (val & VBUS_DET) { + if (twl6030_charger_read(CONTROLLER_CTRL1, &val) < 0) + return IRQ_HANDLED; + + if (!(val & CONTROLLER_CTRL1_EN_CHARGER)) { + if (twl6030_enable_usb(charger) < 0) + return IRQ_HANDLED; + + schedule_delayed_work(&charger->charger_monitor, + msecs_to_jiffies(10000)); + } + } else { + cancel_delayed_work(&charger->charger_monitor); + } + return IRQ_HANDLED; +} + +static int twl6030_charger_usb_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct twl6030_charger_info *charger = power_supply_get_drvdata(psy); + int ret; + u8 stat1; + u8 intstat; + + ret = twl6030_charger_read(CONTROLLER_STAT1, &stat1); + if (ret) + return ret; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + if (!(stat1 & VBUS_DET)) { + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + } + ret = twl6030_charger_read(CHARGERUSB_STATUS_INT2, &intstat); + if (ret) + return ret; + + if (intstat & CHARGE_DONE) + val->intval = POWER_SUPPLY_STATUS_FULL; + else if (intstat & CURRENT_TERM) + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_CHARGING; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (!charger->channel_vusb) + return -ENODATA; + + ret = iio_read_channel_processed_scale(charger->channel_vusb, &val->intval, 1000); + if (ret < 0) + return ret; + + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = !!(stat1 & VBUS_DET); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + val->intval = charger->input_current_limit; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int twl6030_charger_usb_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct twl6030_charger_info *charger = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + charger->input_current_limit = val->intval; + return twl6030_config_cinlimit_reg(charger, charger->input_current_limit); + default: + return -EINVAL; + } + + return 0; +} + +static int twl6030_charger_usb_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + dev_info(&psy->dev, "is %d writeable?\n", (int)psp); + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + return true; + default: + return false; + } +} + +static enum power_supply_property twl6030_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, +}; + +static const struct power_supply_desc twl6030_charger_usb_desc = { + .name = "twl6030_usb", + .type = POWER_SUPPLY_TYPE_USB, + .properties = twl6030_charger_props, + .num_properties = ARRAY_SIZE(twl6030_charger_props), + .get_property = twl6030_charger_usb_get_property, + .set_property = twl6030_charger_usb_set_property, + .property_is_writeable = twl6030_charger_usb_property_is_writeable, +}; + +static int twl6030_charger_probe(struct platform_device *pdev) +{ + struct twl6030_charger_info *charger; + const struct twl6030_charger_chip_data *chip_data; + struct power_supply_config psy_cfg = {}; + int ret; + u8 val; + + charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); + if (!charger) + return -ENOMEM; + + charger->dev = &pdev->dev; + charger->irq_chg = platform_get_irq(pdev, 0); + + chip_data = device_get_match_data(&pdev->dev); + if (!chip_data) + return dev_err_probe(&pdev->dev, -EINVAL, "missing chip data\n"); + + charger->extended_current_range = chip_data->extended_current_range; + platform_set_drvdata(pdev, charger); + psy_cfg.drv_data = charger; + psy_cfg.fwnode = dev_fwnode(&pdev->dev); + + charger->channel_vusb = devm_iio_channel_get(&pdev->dev, "vusb"); + if (IS_ERR(charger->channel_vusb)) { + ret = PTR_ERR(charger->channel_vusb); + if (ret == -EPROBE_DEFER) + return ret; /* iio not ready */ + dev_warn(&pdev->dev, "could not request vusb iio channel (%d)", + ret); + charger->channel_vusb = NULL; + } + + charger->usb = devm_power_supply_register(&pdev->dev, + &twl6030_charger_usb_desc, + &psy_cfg); + if (IS_ERR(charger->usb)) + return dev_err_probe(&pdev->dev, PTR_ERR(charger->usb), + "Failed to register usb\n"); + + ret = power_supply_get_battery_info(charger->usb, &charger->binfo); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to get battery info\n"); + + dev_info(&pdev->dev, "battery with vmax %d imax: %d\n", + charger->binfo->constant_charge_voltage_max_uv, + charger->binfo->constant_charge_current_max_ua); + + if (charger->binfo->constant_charge_voltage_max_uv == -EINVAL) { + ret = twl6030_charger_read(CHARGERUSB_CTRLLIMIT1, &val); + if (ret < 0) + return ret; + + charger->binfo->constant_charge_voltage_max_uv = + VOREG_TO_UV(val); + } + + if (charger->binfo->constant_charge_voltage_max_uv > 4760000 || + charger->binfo->constant_charge_voltage_max_uv < 350000) + return dev_err_probe(&pdev->dev, -EINVAL, + "Invalid charge voltage\n"); + + if (charger->binfo->constant_charge_current_max_ua == -EINVAL) { + ret = twl6030_charger_read(CHARGERUSB_CTRLLIMIT2, &val); + if (ret < 0) + return ret; + + charger->binfo->constant_charge_current_max_ua = VICHRG_TO_UA(val); + } + + if (charger->binfo->constant_charge_current_max_ua < 100000 || + charger->binfo->constant_charge_current_max_ua > 1500000) { + return dev_err_probe(&pdev->dev, -EINVAL, + "Invalid charge current\n"); + } + + if ((charger->binfo->charge_term_current_ua != -EINVAL) && + (charger->binfo->charge_term_current_ua > 400000 || + charger->binfo->charge_term_current_ua < 50000)) { + return dev_err_probe(&pdev->dev, -EINVAL, + "Invalid charge termination current\n"); + } + + ret = devm_delayed_work_autocancel(&pdev->dev, + &charger->charger_monitor, + twl6030_charger_wdg); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to register delayed work\n"); + + ret = devm_request_threaded_irq(&pdev->dev, charger->irq_chg, NULL, + twl6030_charger_interrupt, + IRQF_ONESHOT, pdev->name, + charger); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "could not request irq %d\n", + charger->irq_chg); + + /* turing to charging to configure things */ + twl6030_charger_write(CONTROLLER_CTRL1, 0); + twl6030_charger_interrupt(0, charger); + + return 0; +} + +static const struct twl6030_charger_chip_data twl6030_data = { + .extended_current_range = false, +}; + +static const struct twl6030_charger_chip_data twl6032_data = { + .extended_current_range = true, +}; + +static const struct of_device_id twl_charger_of_match[] = { + {.compatible = "ti,twl6030-charger", .data = &twl6030_data}, + {.compatible = "ti,twl6032-charger", .data = &twl6032_data}, + { } +}; +MODULE_DEVICE_TABLE(of, twl_charger_of_match); + +static struct platform_driver twl6030_charger_driver = { + .probe = twl6030_charger_probe, + .driver = { + .name = "twl6030_charger", + .of_match_table = twl_charger_of_match, + }, +}; +module_platform_driver(twl6030_charger_driver); + +MODULE_DESCRIPTION("TWL6030 Battery Charger Interface driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c index d56e499ac59fb1..538055b29decb3 100644 --- a/drivers/power/supply/wm831x_power.c +++ b/drivers/power/supply/wm831x_power.c @@ -720,7 +720,7 @@ static void wm831x_power_remove(struct platform_device *pdev) static struct platform_driver wm831x_power_driver = { .probe = wm831x_power_probe, - .remove_new = wm831x_power_remove, + .remove = wm831x_power_remove, .driver = { .name = "wm831x-power", }, diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index 3f79ab6f6abf1c..b0eb6e0ce8bcfa 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -577,7 +577,7 @@ static void wm8350_power_remove(struct platform_device *pdev) static struct platform_driver wm8350_power_driver = { .probe = wm8350_power_probe, - .remove_new = wm8350_power_remove, + .remove = wm8350_power_remove, .driver = { .name = "wm8350-power", }, diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c index 1cc38d1437d91f..b3b0c37a9dd2d5 100644 --- a/drivers/power/supply/wm97xx_battery.c +++ b/drivers/power/supply/wm97xx_battery.c @@ -265,7 +265,7 @@ static struct platform_driver wm97xx_bat_driver = { #endif }, .probe = wm97xx_bat_probe, - .remove_new = wm97xx_bat_remove, + .remove = wm97xx_bat_remove, }; module_platform_driver(wm97xx_bat_driver); diff --git a/drivers/powercap/idle_inject.c b/drivers/powercap/idle_inject.c index bafc59904ed354..04c212953ded6a 100644 --- a/drivers/powercap/idle_inject.c +++ b/drivers/powercap/idle_inject.c @@ -179,7 +179,7 @@ void idle_inject_set_duration(struct idle_inject_device *ii_dev, if (!run_duration_us) pr_debug("CPU is forced to 100 percent idle\n"); } -EXPORT_SYMBOL_NS_GPL(idle_inject_set_duration, IDLE_INJECT); +EXPORT_SYMBOL_NS_GPL(idle_inject_set_duration, "IDLE_INJECT"); /** * idle_inject_get_duration - idle and run duration retrieval helper @@ -194,7 +194,7 @@ void idle_inject_get_duration(struct idle_inject_device *ii_dev, *run_duration_us = READ_ONCE(ii_dev->run_duration_us); *idle_duration_us = READ_ONCE(ii_dev->idle_duration_us); } -EXPORT_SYMBOL_NS_GPL(idle_inject_get_duration, IDLE_INJECT); +EXPORT_SYMBOL_NS_GPL(idle_inject_get_duration, "IDLE_INJECT"); /** * idle_inject_set_latency - set the maximum latency allowed @@ -206,7 +206,7 @@ void idle_inject_set_latency(struct idle_inject_device *ii_dev, { WRITE_ONCE(ii_dev->latency_us, latency_us); } -EXPORT_SYMBOL_NS_GPL(idle_inject_set_latency, IDLE_INJECT); +EXPORT_SYMBOL_NS_GPL(idle_inject_set_latency, "IDLE_INJECT"); /** * idle_inject_start - start idle injections @@ -238,7 +238,7 @@ int idle_inject_start(struct idle_inject_device *ii_dev) return 0; } -EXPORT_SYMBOL_NS_GPL(idle_inject_start, IDLE_INJECT); +EXPORT_SYMBOL_NS_GPL(idle_inject_start, "IDLE_INJECT"); /** * idle_inject_stop - stops idle injections @@ -285,7 +285,7 @@ void idle_inject_stop(struct idle_inject_device *ii_dev) cpu_hotplug_enable(); } -EXPORT_SYMBOL_NS_GPL(idle_inject_stop, IDLE_INJECT); +EXPORT_SYMBOL_NS_GPL(idle_inject_stop, "IDLE_INJECT"); /** * idle_inject_setup - prepare the current task for idle injection @@ -367,7 +367,7 @@ struct idle_inject_device *idle_inject_register_full(struct cpumask *cpumask, return NULL; } -EXPORT_SYMBOL_NS_GPL(idle_inject_register_full, IDLE_INJECT); +EXPORT_SYMBOL_NS_GPL(idle_inject_register_full, "IDLE_INJECT"); /** * idle_inject_register - initialize idle injection on a set of CPUs @@ -384,7 +384,7 @@ struct idle_inject_device *idle_inject_register(struct cpumask *cpumask) { return idle_inject_register_full(cpumask, NULL); } -EXPORT_SYMBOL_NS_GPL(idle_inject_register, IDLE_INJECT); +EXPORT_SYMBOL_NS_GPL(idle_inject_register, "IDLE_INJECT"); /** * idle_inject_unregister - unregister idle injection control device @@ -405,7 +405,7 @@ void idle_inject_unregister(struct idle_inject_device *ii_dev) kfree(ii_dev); } -EXPORT_SYMBOL_NS_GPL(idle_inject_unregister, IDLE_INJECT); +EXPORT_SYMBOL_NS_GPL(idle_inject_unregister, "IDLE_INJECT"); static struct smp_hotplug_thread idle_inject_threads = { .store = &idle_inject_thread.tsk, diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c index cbe07450de933b..2b81aabdb0db7c 100644 --- a/drivers/powercap/intel_rapl_msr.c +++ b/drivers/powercap/intel_rapl_msr.c @@ -213,7 +213,7 @@ MODULE_DEVICE_TABLE(platform, rapl_msr_ids); static struct platform_driver intel_rapl_msr_driver = { .probe = rapl_msr_probe, - .remove_new = rapl_msr_remove, + .remove = rapl_msr_remove, .id_table = rapl_msr_ids, .driver = { .name = "intel_rapl_msr", diff --git a/drivers/powercap/intel_rapl_tpmi.c b/drivers/powercap/intel_rapl_tpmi.c index 645fd1dc51a982..af2368f4db10a5 100644 --- a/drivers/powercap/intel_rapl_tpmi.c +++ b/drivers/powercap/intel_rapl_tpmi.c @@ -347,7 +347,7 @@ static struct auxiliary_driver intel_rapl_tpmi_driver = { module_auxiliary_driver(intel_rapl_tpmi_driver) -MODULE_IMPORT_NS(INTEL_TPMI); +MODULE_IMPORT_NS("INTEL_TPMI"); MODULE_DESCRIPTION("Intel RAPL TPMI Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 791fdc9326dd60..634c3b2f8c2654 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -239,7 +239,7 @@ MODULE_DEVICE_TABLE(of, pps_gpio_dt_ids); static struct platform_driver pps_gpio_driver = { .probe = pps_gpio_probe, - .remove_new = pps_gpio_remove, + .remove = pps_gpio_remove, .driver = { .name = PPS_GPIO_NAME, .of_match_table = pps_gpio_dt_ids, diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c index 200ad8751860a6..188ae257267409 100644 --- a/drivers/ps3/ps3-lpm.c +++ b/drivers/ps3/ps3-lpm.c @@ -91,7 +91,7 @@ struct ps3_lpm_shadow_regs { * struct ps3_lpm_priv - Private lpm device data. * * @open: An atomic variable indicating the lpm driver has been opened. - * @rights: The lpm rigths granted by the system policy module. A logical + * @rights: The lpm rights granted by the system policy module. A logical * OR of enum ps3_lpm_rights. * @node_id: The node id of a BE processor whose performance monitor this * lpar has the right to use. diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c index ad8ef59dea3404..ab798b52910ebb 100644 --- a/drivers/ps3/ps3-sys-manager.c +++ b/drivers/ps3/ps3-sys-manager.c @@ -362,7 +362,7 @@ static int ps3_sys_manager_send_request_shutdown( * ps3_sys_manager_send_response - Send a 'response' to the system manager. * @status: zero = success, others fail. * - * The guest sends this message to the system manager to acnowledge success or + * The guest sends this message to the system manager to acknowledge success or * failure of a command sent by the system manager. */ diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c index 6328abd51ffad4..5cb92535a4a145 100644 --- a/drivers/ps3/ps3-vuart.c +++ b/drivers/ps3/ps3-vuart.c @@ -467,8 +467,8 @@ struct list_buffer { * * If the port is idle on entry as much of the incoming data is written to * the port as the port will accept. Otherwise a list buffer is created - * and any remaning incoming data is copied to that buffer. The buffer is - * then enqueued for transmision via the transmit interrupt. + * and any remaining incoming data is copied to that buffer. The buffer is + * then enqueued for transmission via the transmit interrupt. */ int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf, diff --git a/drivers/ps3/sys-manager-core.c b/drivers/ps3/sys-manager-core.c index e061b7d0632bdc..f50032ad970242 100644 --- a/drivers/ps3/sys-manager-core.c +++ b/drivers/ps3/sys-manager-core.c @@ -12,7 +12,7 @@ #include /** - * Staticly linked routines that allow late binding of a loaded sys-manager + * Statically linked routines that allow late binding of a loaded sys-manager * module. */ diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 604541dcb32065..07bf7f9aae019c 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -131,6 +131,23 @@ config PTP_1588_CLOCK_KVM To compile this driver as a module, choose M here: the module will be called ptp_kvm. +config PTP_1588_CLOCK_VMCLOCK + tristate "Virtual machine PTP clock" + depends on X86_TSC || ARM_ARCH_TIMER + depends on PTP_1588_CLOCK && ACPI && ARCH_SUPPORTS_INT128 + default PTP_1588_CLOCK_KVM + help + This driver adds support for using a virtual precision clock + advertised by the hypervisor. This clock is only useful in virtual + machines where such a device is present. + + Unlike the KVM virtual PTP clock, the VMCLOCK device offers support + for reliable timekeeping even across live migration. So this driver + is enabled by default whenever the KVM PTP clock is. + + To compile this driver as a module, choose M here: the module + will be called ptp_vmclock. + config PTP_1588_CLOCK_IDT82P33 tristate "IDT 82P33xxx PTP clock" depends on PTP_1588_CLOCK && I2C @@ -224,4 +241,15 @@ config PTP_DFL_TOD To compile this driver as a module, choose M here: the module will be called ptp_dfl_tod. +config PTP_S390 + tristate "S390 PTP driver" + depends on PTP_1588_CLOCK + depends on S390 + help + This driver adds support for S390 time steering via the PtP + interface. This works by adding a in-kernel clock delta value, + which is always added to time values used in the kernel. The PtP + driver provides the raw clock value without the delta to + userspace. That way userspace programs like chrony could steer + the kernel clock. endmenu diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile index 68bf02078053b8..25f846fe48c9f0 100644 --- a/drivers/ptp/Makefile +++ b/drivers/ptp/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o obj-$(CONFIG_PTP_1588_CLOCK_INES) += ptp_ines.o obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o obj-$(CONFIG_PTP_1588_CLOCK_KVM) += ptp_kvm.o +obj-$(CONFIG_PTP_1588_CLOCK_VMCLOCK) += ptp_vmclock.o obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp-qoriq.o ptp-qoriq-y += ptp_qoriq.o ptp-qoriq-$(CONFIG_DEBUG_FS) += ptp_qoriq_debugfs.o @@ -21,3 +22,4 @@ obj-$(CONFIG_PTP_1588_CLOCK_MOCK) += ptp_mock.o obj-$(CONFIG_PTP_1588_CLOCK_VMW) += ptp_vmw.o obj-$(CONFIG_PTP_1588_CLOCK_OCP) += ptp_ocp.o obj-$(CONFIG_PTP_DFL_TOD) += ptp_dfl_tod.o +obj-$(CONFIG_PTP_S390) += ptp_s390.o diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index c56cd0f63909a2..77a36e7bddd54e 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -150,7 +150,8 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) if (ppb > ops->max_adj || ppb < -ops->max_adj) return -ERANGE; err = ops->adjfine(ops, tx->freq); - ptp->dialed_frequency = tx->freq; + if (!err) + ptp->dialed_frequency = tx->freq; } else if (tx->modes & ADJ_OFFSET) { if (ops->adjphase) { s32 max_phase_adj = ops->getmaxphase(ops); diff --git a/drivers/ptp/ptp_clockmatrix.c b/drivers/ptp/ptp_clockmatrix.c index b6f1941308b17a..fbb3fa8fc60b2f 100644 --- a/drivers/ptp/ptp_clockmatrix.c +++ b/drivers/ptp/ptp_clockmatrix.c @@ -2471,7 +2471,7 @@ static struct platform_driver idtcm_driver = { .name = "8a3400x-phc", }, .probe = idtcm_probe, - .remove_new = idtcm_remove, + .remove = idtcm_remove, }; module_platform_driver(idtcm_driver); diff --git a/drivers/ptp/ptp_dte.c b/drivers/ptp/ptp_dte.c index 449ff90927beb0..847276c6900836 100644 --- a/drivers/ptp/ptp_dte.c +++ b/drivers/ptp/ptp_dte.c @@ -327,7 +327,7 @@ static struct platform_driver ptp_dte_driver = { .of_match_table = ptp_dte_of_match, }, .probe = ptp_dte_probe, - .remove_new = ptp_dte_remove, + .remove = ptp_dte_remove, }; module_platform_driver(ptp_dte_driver); diff --git a/drivers/ptp/ptp_fc3.c b/drivers/ptp/ptp_fc3.c index e14e149b746eb2..cfced36c70bcb2 100644 --- a/drivers/ptp/ptp_fc3.c +++ b/drivers/ptp/ptp_fc3.c @@ -986,11 +986,6 @@ static int idtfc3_probe(struct platform_device *pdev) mutex_unlock(idtfc3->lock); - if (err) { - ptp_clock_unregister(idtfc3->ptp_clock); - return err; - } - platform_set_drvdata(pdev, idtfc3); return 0; @@ -1008,7 +1003,7 @@ static struct platform_driver idtfc3_driver = { .name = "rc38xxx-phc", }, .probe = idtfc3_probe, - .remove_new = idtfc3_remove, + .remove = idtfc3_remove, }; module_platform_driver(idtfc3_driver); diff --git a/drivers/ptp/ptp_idt82p33.c b/drivers/ptp/ptp_idt82p33.c index d5732490ed9d16..b2fd94d4f86312 100644 --- a/drivers/ptp/ptp_idt82p33.c +++ b/drivers/ptp/ptp_idt82p33.c @@ -1461,7 +1461,7 @@ static struct platform_driver idt82p33_driver = { .name = "82p33x1x-phc", }, .probe = idt82p33_probe, - .remove_new = idt82p33_remove, + .remove = idt82p33_remove, }; module_platform_driver(idt82p33_driver); diff --git a/drivers/ptp/ptp_ines.c b/drivers/ptp/ptp_ines.c index 14a23d3a27f2c9..68f1f7fdaa9deb 100644 --- a/drivers/ptp/ptp_ines.c +++ b/drivers/ptp/ptp_ines.c @@ -782,7 +782,7 @@ MODULE_DEVICE_TABLE(of, ines_ptp_ctrl_of_match); static struct platform_driver ines_ptp_ctrl_driver = { .probe = ines_ptp_ctrl_probe, - .remove_new = ines_ptp_ctrl_remove, + .remove = ines_ptp_ctrl_remove, .driver = { .name = "ines_ptp_ctrl", .of_match_table = ines_ptp_ctrl_of_match, diff --git a/drivers/ptp/ptp_kvm_x86.c b/drivers/ptp/ptp_kvm_x86.c index 617c8d6706d3d0..6cea4fe39bcfe4 100644 --- a/drivers/ptp/ptp_kvm_x86.c +++ b/drivers/ptp/ptp_kvm_x86.c @@ -26,7 +26,7 @@ int kvm_arch_ptp_init(void) long ret; if (!kvm_para_available()) - return -ENODEV; + return -EOPNOTSUPP; if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) { p = alloc_page(GFP_KERNEL | __GFP_ZERO); @@ -46,14 +46,14 @@ int kvm_arch_ptp_init(void) clock_pair_gpa = slow_virt_to_phys(clock_pair); if (!pvclock_get_pvti_cpu0_va()) { - ret = -ENODEV; + ret = -EOPNOTSUPP; goto err; } ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa, KVM_CLOCK_PAIRING_WALLCLOCK); if (ret == -KVM_ENOSYS) { - ret = -ENODEV; + ret = -EOPNOTSUPP; goto err; } diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c index 33355d5eb0336d..b8a9a54a176c6c 100644 --- a/drivers/ptp/ptp_pch.c +++ b/drivers/ptp/ptp_pch.c @@ -462,14 +462,14 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } - ret = pcim_iomap_regions(pdev, BIT(IO_MEM_BAR), "1588_regs"); + /* get the virtual address to the 1588 registers */ + chip->regs = pcim_iomap_region(pdev, IO_MEM_BAR, KBUILD_MODNAME); + ret = PTR_ERR_OR_ZERO(chip->regs); if (ret) { dev_err(&pdev->dev, "could not locate IO memory address\n"); return ret; } - /* get the virtual address to the 1588 registers */ - chip->regs = pcim_iomap_table(pdev)[IO_MEM_BAR]; chip->caps = ptp_pch_caps; chip->ptp_clock = ptp_clock_register(&chip->caps, &pdev->dev); if (IS_ERR(chip->ptp_clock)) diff --git a/drivers/ptp/ptp_qoriq.c b/drivers/ptp/ptp_qoriq.c index 879cfc1537ac85..4d488c1f1941bf 100644 --- a/drivers/ptp/ptp_qoriq.c +++ b/drivers/ptp/ptp_qoriq.c @@ -670,7 +670,7 @@ static struct platform_driver ptp_qoriq_driver = { .of_match_table = match_table, }, .probe = ptp_qoriq_probe, - .remove_new = ptp_qoriq_remove, + .remove = ptp_qoriq_remove, }; module_platform_driver(ptp_qoriq_driver); diff --git a/drivers/ptp/ptp_s390.c b/drivers/ptp/ptp_s390.c new file mode 100644 index 00000000000000..29618eb9bf442c --- /dev/null +++ b/drivers/ptp/ptp_s390.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * s390 PTP clock driver + * + */ + +#include "ptp_private.h" +#include +#include + +static struct ptp_clock *ptp_stcke_clock, *ptp_qpt_clock; + +static int ptp_s390_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + return -EOPNOTSUPP; +} + +static int ptp_s390_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + return -EOPNOTSUPP; +} + +static struct timespec64 eitod_to_timespec64(union tod_clock *clk) +{ + return ns_to_timespec64(eitod_to_ns(clk->eitod - TOD_UNIX_EPOCH)); +} + +static struct timespec64 tod_to_timespec64(unsigned long tod) +{ + return ns_to_timespec64(tod_to_ns(tod - TOD_UNIX_EPOCH)); +} + +static int ptp_s390_stcke_gettime(struct ptp_clock_info *ptp, + struct timespec64 *ts) +{ + union tod_clock tod; + + if (!stp_enabled()) + return -EOPNOTSUPP; + + store_tod_clock_ext(&tod); + *ts = eitod_to_timespec64(&tod); + return 0; +} + +static int ptp_s390_qpt_gettime(struct ptp_clock_info *ptp, + struct timespec64 *ts) +{ + unsigned long tod; + + ptff(&tod, sizeof(tod), PTFF_QPT); + *ts = tod_to_timespec64(tod); + return 0; +} + +static int ptp_s390_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + +static int s390_arch_ptp_get_crosststamp(ktime_t *device_time, + struct system_counterval_t *system_counter, + void *ctx) +{ + union tod_clock clk; + + store_tod_clock_ext(&clk); + *device_time = ns_to_ktime(tod_to_ns(clk.tod - TOD_UNIX_EPOCH)); + system_counter->cycles = clk.tod; + system_counter->cs_id = CSID_S390_TOD; + return 0; +} + +static int ptp_s390_getcrosststamp(struct ptp_clock_info *ptp, + struct system_device_crosststamp *xtstamp) +{ + if (!stp_enabled()) + return -EOPNOTSUPP; + return get_device_system_crosststamp(s390_arch_ptp_get_crosststamp, NULL, NULL, xtstamp); +} + +static struct ptp_clock_info ptp_s390_stcke_info = { + .owner = THIS_MODULE, + .name = "s390 STCKE Clock", + .max_adj = 0, + .adjfine = ptp_s390_adjfine, + .adjtime = ptp_s390_adjtime, + .gettime64 = ptp_s390_stcke_gettime, + .settime64 = ptp_s390_settime, + .getcrosststamp = ptp_s390_getcrosststamp, +}; + +static struct ptp_clock_info ptp_s390_qpt_info = { + .owner = THIS_MODULE, + .name = "s390 Physical Clock", + .max_adj = 0, + .adjfine = ptp_s390_adjfine, + .adjtime = ptp_s390_adjtime, + .gettime64 = ptp_s390_qpt_gettime, + .settime64 = ptp_s390_settime, +}; + +static __init int ptp_s390_init(void) +{ + ptp_stcke_clock = ptp_clock_register(&ptp_s390_stcke_info, NULL); + if (IS_ERR(ptp_stcke_clock)) + return PTR_ERR(ptp_stcke_clock); + + ptp_qpt_clock = ptp_clock_register(&ptp_s390_qpt_info, NULL); + if (IS_ERR(ptp_qpt_clock)) { + ptp_clock_unregister(ptp_stcke_clock); + return PTR_ERR(ptp_qpt_clock); + } + return 0; +} + +static __exit void ptp_s390_exit(void) +{ + ptp_clock_unregister(ptp_qpt_clock); + ptp_clock_unregister(ptp_stcke_clock); +} + +module_init(ptp_s390_init); +module_exit(ptp_s390_exit); + +MODULE_AUTHOR("Sven Schnelle "); +MODULE_DESCRIPTION("s390 Physical/STCKE Clock PtP Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ptp/ptp_vmclock.c b/drivers/ptp/ptp_vmclock.c new file mode 100644 index 00000000000000..0a2cfc8ad3c540 --- /dev/null +++ b/drivers/ptp/ptp_vmclock.c @@ -0,0 +1,615 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Virtual PTP 1588 clock for use with LM-safe VMclock device. + * + * Copyright © 2024 Amazon.com, Inc. or its affiliates. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef CONFIG_X86 +#include +#include +#endif + +#ifdef CONFIG_KVM_GUEST +#define SUPPORT_KVMCLOCK +#endif + +static DEFINE_IDA(vmclock_ida); + +ACPI_MODULE_NAME("vmclock"); + +struct vmclock_state { + struct resource res; + struct vmclock_abi *clk; + struct miscdevice miscdev; + struct ptp_clock_info ptp_clock_info; + struct ptp_clock *ptp_clock; + enum clocksource_ids cs_id, sys_cs_id; + int index; + char *name; +}; + +#define VMCLOCK_MAX_WAIT ms_to_ktime(100) + +/* Require at least the flags field to be present. All else can be optional. */ +#define VMCLOCK_MIN_SIZE offsetof(struct vmclock_abi, pad) + +#define VMCLOCK_FIELD_PRESENT(_c, _f) \ + (le32_to_cpu((_c)->size) >= (offsetof(struct vmclock_abi, _f) + \ + sizeof((_c)->_f))) + +/* + * Multiply a 64-bit count by a 64-bit tick 'period' in units of seconds >> 64 + * and add the fractional second part of the reference time. + * + * The result is a 128-bit value, the top 64 bits of which are seconds, and + * the low 64 bits are (seconds >> 64). + */ +static uint64_t mul_u64_u64_shr_add_u64(uint64_t *res_hi, uint64_t delta, + uint64_t period, uint8_t shift, + uint64_t frac_sec) +{ + unsigned __int128 res = (unsigned __int128)delta * period; + + res >>= shift; + res += frac_sec; + *res_hi = res >> 64; + return (uint64_t)res; +} + +static bool tai_adjust(struct vmclock_abi *clk, uint64_t *sec) +{ + if (likely(clk->time_type == VMCLOCK_TIME_UTC)) + return true; + + if (clk->time_type == VMCLOCK_TIME_TAI && + (le64_to_cpu(clk->flags) & VMCLOCK_FLAG_TAI_OFFSET_VALID)) { + if (sec) + *sec += (int16_t)le16_to_cpu(clk->tai_offset_sec); + return true; + } + return false; +} + +static int vmclock_get_crosststamp(struct vmclock_state *st, + struct ptp_system_timestamp *sts, + struct system_counterval_t *system_counter, + struct timespec64 *tspec) +{ + ktime_t deadline = ktime_add(ktime_get(), VMCLOCK_MAX_WAIT); + struct system_time_snapshot systime_snapshot; + uint64_t cycle, delta, seq, frac_sec; + +#ifdef CONFIG_X86 + /* + * We'd expect the hypervisor to know this and to report the clock + * status as VMCLOCK_STATUS_UNRELIABLE. But be paranoid. + */ + if (check_tsc_unstable()) + return -EINVAL; +#endif + + while (1) { + seq = le32_to_cpu(st->clk->seq_count) & ~1ULL; + + /* + * This pairs with a write barrier in the hypervisor + * which populates this structure. + */ + virt_rmb(); + + if (st->clk->clock_status == VMCLOCK_STATUS_UNRELIABLE) + return -EINVAL; + + /* + * When invoked for gettimex64(), fill in the pre/post system + * times. The simple case is when system time is based on the + * same counter as st->cs_id, in which case all three times + * will be derived from the *same* counter value. + * + * If the system isn't using the same counter, then the value + * from ktime_get_snapshot() will still be used as pre_ts, and + * ptp_read_system_postts() is called to populate postts after + * calling get_cycles(). + * + * The conversion to timespec64 happens further down, outside + * the seq_count loop. + */ + if (sts) { + ktime_get_snapshot(&systime_snapshot); + if (systime_snapshot.cs_id == st->cs_id) { + cycle = systime_snapshot.cycles; + } else { + cycle = get_cycles(); + ptp_read_system_postts(sts); + } + } else { + cycle = get_cycles(); + } + + delta = cycle - le64_to_cpu(st->clk->counter_value); + + frac_sec = mul_u64_u64_shr_add_u64(&tspec->tv_sec, delta, + le64_to_cpu(st->clk->counter_period_frac_sec), + st->clk->counter_period_shift, + le64_to_cpu(st->clk->time_frac_sec)); + tspec->tv_nsec = mul_u64_u64_shr(frac_sec, NSEC_PER_SEC, 64); + tspec->tv_sec += le64_to_cpu(st->clk->time_sec); + + if (!tai_adjust(st->clk, &tspec->tv_sec)) + return -EINVAL; + + /* + * This pairs with a write barrier in the hypervisor + * which populates this structure. + */ + virt_rmb(); + if (seq == le32_to_cpu(st->clk->seq_count)) + break; + + if (ktime_after(ktime_get(), deadline)) + return -ETIMEDOUT; + } + + if (system_counter) { + system_counter->cycles = cycle; + system_counter->cs_id = st->cs_id; + } + + if (sts) { + sts->pre_ts = ktime_to_timespec64(systime_snapshot.real); + if (systime_snapshot.cs_id == st->cs_id) + sts->post_ts = sts->pre_ts; + } + + return 0; +} + +#ifdef SUPPORT_KVMCLOCK +/* + * In the case where the system is using the KVM clock for timekeeping, convert + * the TSC value into a KVM clock time in order to return a paired reading that + * get_device_system_crosststamp() can cope with. + */ +static int vmclock_get_crosststamp_kvmclock(struct vmclock_state *st, + struct ptp_system_timestamp *sts, + struct system_counterval_t *system_counter, + struct timespec64 *tspec) +{ + struct pvclock_vcpu_time_info *pvti = this_cpu_pvti(); + unsigned int pvti_ver; + int ret; + + preempt_disable_notrace(); + + do { + pvti_ver = pvclock_read_begin(pvti); + + ret = vmclock_get_crosststamp(st, sts, system_counter, tspec); + if (ret) + break; + + system_counter->cycles = __pvclock_read_cycles(pvti, + system_counter->cycles); + system_counter->cs_id = CSID_X86_KVM_CLK; + + /* + * This retry should never really happen; if the TSC is + * stable and reliable enough across vCPUS that it is sane + * for the hypervisor to expose a VMCLOCK device which uses + * it as the reference counter, then the KVM clock sohuld be + * in 'master clock mode' and basically never changed. But + * the KVM clock is a fickle and often broken thing, so do + * it "properly" just in case. + */ + } while (pvclock_read_retry(pvti, pvti_ver)); + + preempt_enable_notrace(); + + return ret; +} +#endif + +static int ptp_vmclock_get_time_fn(ktime_t *device_time, + struct system_counterval_t *system_counter, + void *ctx) +{ + struct vmclock_state *st = ctx; + struct timespec64 tspec; + int ret; + +#ifdef SUPPORT_KVMCLOCK + if (READ_ONCE(st->sys_cs_id) == CSID_X86_KVM_CLK) + ret = vmclock_get_crosststamp_kvmclock(st, NULL, system_counter, + &tspec); + else +#endif + ret = vmclock_get_crosststamp(st, NULL, system_counter, &tspec); + + if (!ret) + *device_time = timespec64_to_ktime(tspec); + + return ret; +} + +static int ptp_vmclock_getcrosststamp(struct ptp_clock_info *ptp, + struct system_device_crosststamp *xtstamp) +{ + struct vmclock_state *st = container_of(ptp, struct vmclock_state, + ptp_clock_info); + int ret = get_device_system_crosststamp(ptp_vmclock_get_time_fn, st, + NULL, xtstamp); +#ifdef SUPPORT_KVMCLOCK + /* + * On x86, the KVM clock may be used for the system time. We can + * actually convert a TSC reading to that, and return a paired + * timestamp that get_device_system_crosststamp() *can* handle. + */ + if (ret == -ENODEV) { + struct system_time_snapshot systime_snapshot; + + ktime_get_snapshot(&systime_snapshot); + + if (systime_snapshot.cs_id == CSID_X86_TSC || + systime_snapshot.cs_id == CSID_X86_KVM_CLK) { + WRITE_ONCE(st->sys_cs_id, systime_snapshot.cs_id); + ret = get_device_system_crosststamp(ptp_vmclock_get_time_fn, + st, NULL, xtstamp); + } + } +#endif + return ret; +} + +/* + * PTP clock operations + */ + +static int ptp_vmclock_adjfine(struct ptp_clock_info *ptp, long delta) +{ + return -EOPNOTSUPP; +} + +static int ptp_vmclock_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + return -EOPNOTSUPP; +} + +static int ptp_vmclock_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + +static int ptp_vmclock_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, + struct ptp_system_timestamp *sts) +{ + struct vmclock_state *st = container_of(ptp, struct vmclock_state, + ptp_clock_info); + + return vmclock_get_crosststamp(st, sts, NULL, ts); +} + +static int ptp_vmclock_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + return -EOPNOTSUPP; +} + +static const struct ptp_clock_info ptp_vmclock_info = { + .owner = THIS_MODULE, + .max_adj = 0, + .n_ext_ts = 0, + .n_pins = 0, + .pps = 0, + .adjfine = ptp_vmclock_adjfine, + .adjtime = ptp_vmclock_adjtime, + .gettimex64 = ptp_vmclock_gettimex, + .settime64 = ptp_vmclock_settime, + .enable = ptp_vmclock_enable, + .getcrosststamp = ptp_vmclock_getcrosststamp, +}; + +static struct ptp_clock *vmclock_ptp_register(struct device *dev, + struct vmclock_state *st) +{ + enum clocksource_ids cs_id; + + if (IS_ENABLED(CONFIG_ARM64) && + st->clk->counter_id == VMCLOCK_COUNTER_ARM_VCNT) { + /* Can we check it's the virtual counter? */ + cs_id = CSID_ARM_ARCH_COUNTER; + } else if (IS_ENABLED(CONFIG_X86) && + st->clk->counter_id == VMCLOCK_COUNTER_X86_TSC) { + cs_id = CSID_X86_TSC; + } else { + return NULL; + } + + /* Only UTC, or TAI with offset */ + if (!tai_adjust(st->clk, NULL)) { + dev_info(dev, "vmclock does not provide unambiguous UTC\n"); + return NULL; + } + + st->sys_cs_id = cs_id; + st->cs_id = cs_id; + st->ptp_clock_info = ptp_vmclock_info; + strscpy(st->ptp_clock_info.name, st->name); + + return ptp_clock_register(&st->ptp_clock_info, dev); +} + +static int vmclock_miscdev_mmap(struct file *fp, struct vm_area_struct *vma) +{ + struct vmclock_state *st = container_of(fp->private_data, + struct vmclock_state, miscdev); + + if ((vma->vm_flags & (VM_READ|VM_WRITE)) != VM_READ) + return -EROFS; + + if (vma->vm_end - vma->vm_start != PAGE_SIZE || vma->vm_pgoff) + return -EINVAL; + + if (io_remap_pfn_range(vma, vma->vm_start, + st->res.start >> PAGE_SHIFT, PAGE_SIZE, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static ssize_t vmclock_miscdev_read(struct file *fp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct vmclock_state *st = container_of(fp->private_data, + struct vmclock_state, miscdev); + ktime_t deadline = ktime_add(ktime_get(), VMCLOCK_MAX_WAIT); + size_t max_count; + uint32_t seq; + + if (*ppos >= PAGE_SIZE) + return 0; + + max_count = PAGE_SIZE - *ppos; + if (count > max_count) + count = max_count; + + while (1) { + seq = le32_to_cpu(st->clk->seq_count) & ~1U; + /* Pairs with hypervisor wmb */ + virt_rmb(); + + if (copy_to_user(buf, ((char *)st->clk) + *ppos, count)) + return -EFAULT; + + /* Pairs with hypervisor wmb */ + virt_rmb(); + if (seq == le32_to_cpu(st->clk->seq_count)) + break; + + if (ktime_after(ktime_get(), deadline)) + return -ETIMEDOUT; + } + + *ppos += count; + return count; +} + +static const struct file_operations vmclock_miscdev_fops = { + .mmap = vmclock_miscdev_mmap, + .read = vmclock_miscdev_read, +}; + +/* module operations */ + +static void vmclock_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct vmclock_state *st = dev_get_drvdata(dev); + + if (st->ptp_clock) + ptp_clock_unregister(st->ptp_clock); + + if (st->miscdev.minor != MISC_DYNAMIC_MINOR) + misc_deregister(&st->miscdev); +} + +static acpi_status vmclock_acpi_resources(struct acpi_resource *ares, void *data) +{ + struct vmclock_state *st = data; + struct resource_win win; + struct resource *res = &win.res; + + if (ares->type == ACPI_RESOURCE_TYPE_END_TAG) + return AE_OK; + + /* There can be only one */ + if (resource_type(&st->res) == IORESOURCE_MEM) + return AE_ERROR; + + if (acpi_dev_resource_memory(ares, res) || + acpi_dev_resource_address_space(ares, &win)) { + + if (resource_type(res) != IORESOURCE_MEM || + resource_size(res) < sizeof(st->clk)) + return AE_ERROR; + + st->res = *res; + return AE_OK; + } + + return AE_ERROR; +} + +static int vmclock_probe_acpi(struct device *dev, struct vmclock_state *st) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + acpi_status status; + + /* + * This should never happen as this function is only called when + * has_acpi_companion(dev) is true, but the logic is sufficiently + * complex that Coverity can't see the tautology. + */ + if (!adev) + return -ENODEV; + + status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, + vmclock_acpi_resources, st); + if (ACPI_FAILURE(status) || resource_type(&st->res) != IORESOURCE_MEM) { + dev_err(dev, "failed to get resources\n"); + return -ENODEV; + } + + return 0; +} + +static void vmclock_put_idx(void *data) +{ + struct vmclock_state *st = data; + + ida_free(&vmclock_ida, st->index); +} + +static int vmclock_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct vmclock_state *st; + int ret; + + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + if (has_acpi_companion(dev)) + ret = vmclock_probe_acpi(dev, st); + else + ret = -EINVAL; /* Only ACPI for now */ + + if (ret) { + dev_info(dev, "Failed to obtain physical address: %d\n", ret); + goto out; + } + + if (resource_size(&st->res) < VMCLOCK_MIN_SIZE) { + dev_info(dev, "Region too small (0x%llx)\n", + resource_size(&st->res)); + ret = -EINVAL; + goto out; + } + st->clk = devm_memremap(dev, st->res.start, resource_size(&st->res), + MEMREMAP_WB | MEMREMAP_DEC); + if (IS_ERR(st->clk)) { + ret = PTR_ERR(st->clk); + dev_info(dev, "failed to map shared memory\n"); + st->clk = NULL; + goto out; + } + + if (le32_to_cpu(st->clk->magic) != VMCLOCK_MAGIC || + le32_to_cpu(st->clk->size) > resource_size(&st->res) || + le16_to_cpu(st->clk->version) != 1) { + dev_info(dev, "vmclock magic fields invalid\n"); + ret = -EINVAL; + goto out; + } + + ret = ida_alloc(&vmclock_ida, GFP_KERNEL); + if (ret < 0) + goto out; + + st->index = ret; + ret = devm_add_action_or_reset(&pdev->dev, vmclock_put_idx, st); + if (ret) + goto out; + + st->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "vmclock%d", st->index); + if (!st->name) { + ret = -ENOMEM; + goto out; + } + + /* + * If the structure is big enough, it can be mapped to userspace. + * Theoretically a guest OS even using larger pages could still + * use 4KiB PTEs to map smaller MMIO regions like this, but let's + * cross that bridge if/when we come to it. + */ + if (le32_to_cpu(st->clk->size) >= PAGE_SIZE) { + st->miscdev.minor = MISC_DYNAMIC_MINOR; + st->miscdev.fops = &vmclock_miscdev_fops; + st->miscdev.name = st->name; + + ret = misc_register(&st->miscdev); + if (ret) + goto out; + } + + /* If there is valid clock information, register a PTP clock */ + if (VMCLOCK_FIELD_PRESENT(st->clk, time_frac_sec)) { + /* Can return a silent NULL, or an error. */ + st->ptp_clock = vmclock_ptp_register(dev, st); + if (IS_ERR(st->ptp_clock)) { + ret = PTR_ERR(st->ptp_clock); + st->ptp_clock = NULL; + vmclock_remove(pdev); + goto out; + } + } + + if (!st->miscdev.minor && !st->ptp_clock) { + /* Neither miscdev nor PTP registered */ + dev_info(dev, "vmclock: Neither miscdev nor PTP available; not registering\n"); + ret = -ENODEV; + goto out; + } + + dev_info(dev, "%s: registered %s%s%s\n", st->name, + st->miscdev.minor ? "miscdev" : "", + (st->miscdev.minor && st->ptp_clock) ? ", " : "", + st->ptp_clock ? "PTP" : ""); + + dev_set_drvdata(dev, st); + + out: + return ret; +} + +static const struct acpi_device_id vmclock_acpi_ids[] = { + { "AMZNC10C", 0 }, + {} +}; +MODULE_DEVICE_TABLE(acpi, vmclock_acpi_ids); + +static struct platform_driver vmclock_platform_driver = { + .probe = vmclock_probe, + .remove = vmclock_remove, + .driver = { + .name = "vmclock", + .acpi_match_table = vmclock_acpi_ids, + }, +}; + +module_platform_driver(vmclock_platform_driver) + +MODULE_AUTHOR("David Woodhouse "); +MODULE_DESCRIPTION("PTP clock using VMCLOCK"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 6e752e148b98cc..675b252d9c8ce7 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -6,7 +6,7 @@ * Copyright (C) 2011-2012 Avionic Design GmbH */ -#define DEFAULT_SYMBOL_NAMESPACE PWM +#define DEFAULT_SYMBOL_NAMESPACE "PWM" #include #include @@ -31,6 +31,397 @@ static DEFINE_MUTEX(pwm_lock); static DEFINE_IDR(pwm_chips); +static void pwmchip_lock(struct pwm_chip *chip) +{ + if (chip->atomic) + spin_lock(&chip->atomic_lock); + else + mutex_lock(&chip->nonatomic_lock); +} + +static void pwmchip_unlock(struct pwm_chip *chip) +{ + if (chip->atomic) + spin_unlock(&chip->atomic_lock); + else + mutex_unlock(&chip->nonatomic_lock); +} + +DEFINE_GUARD(pwmchip, struct pwm_chip *, pwmchip_lock(_T), pwmchip_unlock(_T)) + +static bool pwm_wf_valid(const struct pwm_waveform *wf) +{ + /* + * For now restrict waveforms to period_length_ns <= S64_MAX to provide + * some space for future extensions. One possibility is to simplify + * representing waveforms with inverted polarity using negative values + * somehow. + */ + if (wf->period_length_ns > S64_MAX) + return false; + + if (wf->duty_length_ns > wf->period_length_ns) + return false; + + /* + * .duty_offset_ns is supposed to be smaller than .period_length_ns, apart + * from the corner case .duty_offset_ns == 0 && .period_length_ns == 0. + */ + if (wf->duty_offset_ns && wf->duty_offset_ns >= wf->period_length_ns) + return false; + + return true; +} + +static void pwm_wf2state(const struct pwm_waveform *wf, struct pwm_state *state) +{ + if (wf->period_length_ns) { + if (wf->duty_length_ns + wf->duty_offset_ns < wf->period_length_ns) + *state = (struct pwm_state){ + .enabled = true, + .polarity = PWM_POLARITY_NORMAL, + .period = wf->period_length_ns, + .duty_cycle = wf->duty_length_ns, + }; + else + *state = (struct pwm_state){ + .enabled = true, + .polarity = PWM_POLARITY_INVERSED, + .period = wf->period_length_ns, + .duty_cycle = wf->period_length_ns - wf->duty_length_ns, + }; + } else { + *state = (struct pwm_state){ + .enabled = false, + }; + } +} + +static void pwm_state2wf(const struct pwm_state *state, struct pwm_waveform *wf) +{ + if (state->enabled) { + if (state->polarity == PWM_POLARITY_NORMAL) + *wf = (struct pwm_waveform){ + .period_length_ns = state->period, + .duty_length_ns = state->duty_cycle, + .duty_offset_ns = 0, + }; + else + *wf = (struct pwm_waveform){ + .period_length_ns = state->period, + .duty_length_ns = state->period - state->duty_cycle, + .duty_offset_ns = state->duty_cycle, + }; + } else { + *wf = (struct pwm_waveform){ + .period_length_ns = 0, + }; + } +} + +static int pwmwfcmp(const struct pwm_waveform *a, const struct pwm_waveform *b) +{ + if (a->period_length_ns > b->period_length_ns) + return 1; + + if (a->period_length_ns < b->period_length_ns) + return -1; + + if (a->duty_length_ns > b->duty_length_ns) + return 1; + + if (a->duty_length_ns < b->duty_length_ns) + return -1; + + if (a->duty_offset_ns > b->duty_offset_ns) + return 1; + + if (a->duty_offset_ns < b->duty_offset_ns) + return -1; + + return 0; +} + +static bool pwm_check_rounding(const struct pwm_waveform *wf, + const struct pwm_waveform *wf_rounded) +{ + if (!wf->period_length_ns) + return true; + + if (wf->period_length_ns < wf_rounded->period_length_ns) + return false; + + if (wf->duty_length_ns < wf_rounded->duty_length_ns) + return false; + + if (wf->duty_offset_ns < wf_rounded->duty_offset_ns) + return false; + + return true; +} + +static int __pwm_round_waveform_tohw(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_waveform *wf, void *wfhw) +{ + const struct pwm_ops *ops = chip->ops; + int ret; + + ret = ops->round_waveform_tohw(chip, pwm, wf, wfhw); + trace_pwm_round_waveform_tohw(pwm, wf, wfhw, ret); + + return ret; +} + +static int __pwm_round_waveform_fromhw(struct pwm_chip *chip, struct pwm_device *pwm, + const void *wfhw, struct pwm_waveform *wf) +{ + const struct pwm_ops *ops = chip->ops; + int ret; + + ret = ops->round_waveform_fromhw(chip, pwm, wfhw, wf); + trace_pwm_round_waveform_fromhw(pwm, wfhw, wf, ret); + + return ret; +} + +static int __pwm_read_waveform(struct pwm_chip *chip, struct pwm_device *pwm, void *wfhw) +{ + const struct pwm_ops *ops = chip->ops; + int ret; + + ret = ops->read_waveform(chip, pwm, wfhw); + trace_pwm_read_waveform(pwm, wfhw, ret); + + return ret; +} + +static int __pwm_write_waveform(struct pwm_chip *chip, struct pwm_device *pwm, const void *wfhw) +{ + const struct pwm_ops *ops = chip->ops; + int ret; + + ret = ops->write_waveform(chip, pwm, wfhw); + trace_pwm_write_waveform(pwm, wfhw, ret); + + return ret; +} + +#define WFHWSIZE 20 + +/** + * pwm_round_waveform_might_sleep - Query hardware capabilities + * Cannot be used in atomic context. + * @pwm: PWM device + * @wf: waveform to round and output parameter + * + * Typically a given waveform cannot be implemented exactly by hardware, e.g. + * because hardware only supports coarse period resolution or no duty_offset. + * This function returns the actually implemented waveform if you pass wf to + * pwm_set_waveform_might_sleep now. + * + * Note however that the world doesn't stop turning when you call it, so when + * doing + * + * pwm_round_waveform_might_sleep(mypwm, &wf); + * pwm_set_waveform_might_sleep(mypwm, &wf, true); + * + * the latter might fail, e.g. because an input clock changed its rate between + * these two calls and the waveform determined by + * pwm_round_waveform_might_sleep() cannot be implemented any more. + * + * Returns 0 on success, 1 if there is no valid hardware configuration matching + * the input waveform under the PWM rounding rules or a negative errno. + */ +int pwm_round_waveform_might_sleep(struct pwm_device *pwm, struct pwm_waveform *wf) +{ + struct pwm_chip *chip = pwm->chip; + const struct pwm_ops *ops = chip->ops; + struct pwm_waveform wf_req = *wf; + char wfhw[WFHWSIZE]; + int ret_tohw, ret_fromhw; + + BUG_ON(WFHWSIZE < ops->sizeof_wfhw); + + if (!pwm_wf_valid(wf)) + return -EINVAL; + + guard(pwmchip)(chip); + + if (!chip->operational) + return -ENODEV; + + ret_tohw = __pwm_round_waveform_tohw(chip, pwm, wf, wfhw); + if (ret_tohw < 0) + return ret_tohw; + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && ret_tohw > 1) + dev_err(&chip->dev, "Unexpected return value from __pwm_round_waveform_tohw: requested %llu/%llu [+%llu], return value %d\n", + wf_req.duty_length_ns, wf_req.period_length_ns, wf_req.duty_offset_ns, ret_tohw); + + ret_fromhw = __pwm_round_waveform_fromhw(chip, pwm, wfhw, wf); + if (ret_fromhw < 0) + return ret_fromhw; + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && ret_fromhw > 0) + dev_err(&chip->dev, "Unexpected return value from __pwm_round_waveform_fromhw: requested %llu/%llu [+%llu], return value %d\n", + wf_req.duty_length_ns, wf_req.period_length_ns, wf_req.duty_offset_ns, ret_tohw); + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && + ret_tohw == 0 && !pwm_check_rounding(&wf_req, wf)) + dev_err(&chip->dev, "Wrong rounding: requested %llu/%llu [+%llu], result %llu/%llu [+%llu]\n", + wf_req.duty_length_ns, wf_req.period_length_ns, wf_req.duty_offset_ns, + wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns); + + return ret_tohw; +} +EXPORT_SYMBOL_GPL(pwm_round_waveform_might_sleep); + +/** + * pwm_get_waveform_might_sleep - Query hardware about current configuration + * Cannot be used in atomic context. + * @pwm: PWM device + * @wf: output parameter + * + * Stores the current configuration of the PWM in @wf. Note this is the + * equivalent of pwm_get_state_hw() (and not pwm_get_state()) for pwm_waveform. + */ +int pwm_get_waveform_might_sleep(struct pwm_device *pwm, struct pwm_waveform *wf) +{ + struct pwm_chip *chip = pwm->chip; + const struct pwm_ops *ops = chip->ops; + char wfhw[WFHWSIZE]; + int err; + + BUG_ON(WFHWSIZE < ops->sizeof_wfhw); + + guard(pwmchip)(chip); + + if (!chip->operational) + return -ENODEV; + + err = __pwm_read_waveform(chip, pwm, &wfhw); + if (err) + return err; + + return __pwm_round_waveform_fromhw(chip, pwm, &wfhw, wf); +} +EXPORT_SYMBOL_GPL(pwm_get_waveform_might_sleep); + +/* Called with the pwmchip lock held */ +static int __pwm_set_waveform(struct pwm_device *pwm, + const struct pwm_waveform *wf, + bool exact) +{ + struct pwm_chip *chip = pwm->chip; + const struct pwm_ops *ops = chip->ops; + char wfhw[WFHWSIZE]; + struct pwm_waveform wf_rounded; + int err; + + BUG_ON(WFHWSIZE < ops->sizeof_wfhw); + + if (!pwm_wf_valid(wf)) + return -EINVAL; + + err = __pwm_round_waveform_tohw(chip, pwm, wf, &wfhw); + if (err) + return err; + + if ((IS_ENABLED(CONFIG_PWM_DEBUG) || exact) && wf->period_length_ns) { + err = __pwm_round_waveform_fromhw(chip, pwm, &wfhw, &wf_rounded); + if (err) + return err; + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && !pwm_check_rounding(wf, &wf_rounded)) + dev_err(&chip->dev, "Wrong rounding: requested %llu/%llu [+%llu], result %llu/%llu [+%llu]\n", + wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, + wf_rounded.duty_length_ns, wf_rounded.period_length_ns, wf_rounded.duty_offset_ns); + + if (exact && pwmwfcmp(wf, &wf_rounded)) { + dev_dbg(&chip->dev, "Requested no rounding, but %llu/%llu [+%llu] -> %llu/%llu [+%llu]\n", + wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, + wf_rounded.duty_length_ns, wf_rounded.period_length_ns, wf_rounded.duty_offset_ns); + + return 1; + } + } + + err = __pwm_write_waveform(chip, pwm, &wfhw); + if (err) + return err; + + /* update .state */ + pwm_wf2state(wf, &pwm->state); + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && ops->read_waveform && wf->period_length_ns) { + struct pwm_waveform wf_set; + + err = __pwm_read_waveform(chip, pwm, &wfhw); + if (err) + /* maybe ignore? */ + return err; + + err = __pwm_round_waveform_fromhw(chip, pwm, &wfhw, &wf_set); + if (err) + /* maybe ignore? */ + return err; + + if (pwmwfcmp(&wf_set, &wf_rounded) != 0) + dev_err(&chip->dev, + "Unexpected setting: requested %llu/%llu [+%llu], expected %llu/%llu [+%llu], set %llu/%llu [+%llu]\n", + wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, + wf_rounded.duty_length_ns, wf_rounded.period_length_ns, wf_rounded.duty_offset_ns, + wf_set.duty_length_ns, wf_set.period_length_ns, wf_set.duty_offset_ns); + } + return 0; +} + +/** + * pwm_set_waveform_might_sleep - Apply a new waveform + * Cannot be used in atomic context. + * @pwm: PWM device + * @wf: The waveform to apply + * @exact: If true no rounding is allowed + * + * Typically a requested waveform cannot be implemented exactly, e.g. because + * you requested .period_length_ns = 100 ns, but the hardware can only set + * periods that are a multiple of 8.5 ns. With that hardware passing exact = + * true results in pwm_set_waveform_might_sleep() failing and returning 1. If + * exact = false you get a period of 93.5 ns (i.e. the biggest period not bigger + * than the requested value). + * Note that even with exact = true, some rounding by less than 1 is + * possible/needed. In the above example requesting .period_length_ns = 94 and + * exact = true, you get the hardware configured with period = 93.5 ns. + */ +int pwm_set_waveform_might_sleep(struct pwm_device *pwm, + const struct pwm_waveform *wf, bool exact) +{ + struct pwm_chip *chip = pwm->chip; + int err; + + might_sleep(); + + guard(pwmchip)(chip); + + if (!chip->operational) + return -ENODEV; + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && chip->atomic) { + /* + * Catch any drivers that have been marked as atomic but + * that will sleep anyway. + */ + non_block_start(); + err = __pwm_set_waveform(pwm, wf, exact); + non_block_end(); + } else { + err = __pwm_set_waveform(pwm, wf, exact); + } + + return err; +} +EXPORT_SYMBOL_GPL(pwm_set_waveform_might_sleep); + static void pwm_apply_debug(struct pwm_device *pwm, const struct pwm_state *state) { @@ -75,7 +466,7 @@ static void pwm_apply_debug(struct pwm_device *pwm, state->duty_cycle < state->period) dev_warn(pwmchip_parent(chip), ".apply ignored .polarity\n"); - if (state->enabled && + if (state->enabled && s2.enabled && last->polarity == state->polarity && last->period > s2.period && last->period <= state->period) @@ -83,7 +474,11 @@ static void pwm_apply_debug(struct pwm_device *pwm, ".apply didn't pick the best available period (requested: %llu, applied: %llu, possible: %llu)\n", state->period, s2.period, last->period); - if (state->enabled && state->period < s2.period) + /* + * Rounding period up is fine only if duty_cycle is 0 then, because a + * flat line doesn't have a characteristic period. + */ + if (state->enabled && s2.enabled && state->period < s2.period && s2.duty_cycle) dev_warn(pwmchip_parent(chip), ".apply is supposed to round down period (requested: %llu, applied: %llu)\n", state->period, s2.period); @@ -99,7 +494,7 @@ static void pwm_apply_debug(struct pwm_device *pwm, s2.duty_cycle, s2.period, last->duty_cycle, last->period); - if (state->enabled && state->duty_cycle < s2.duty_cycle) + if (state->enabled && s2.enabled && state->duty_cycle < s2.duty_cycle) dev_warn(pwmchip_parent(chip), ".apply is supposed to round down duty_cycle (requested: %llu/%llu, applied: %llu/%llu)\n", state->duty_cycle, state->period, @@ -164,6 +559,7 @@ static bool pwm_state_valid(const struct pwm_state *state) static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) { struct pwm_chip *chip; + const struct pwm_ops *ops; int err; if (!pwm || !state) @@ -187,6 +583,7 @@ static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) } chip = pwm->chip; + ops = chip->ops; if (state->period == pwm->state.period && state->duty_cycle == pwm->state.duty_cycle && @@ -195,18 +592,69 @@ static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) state->usage_power == pwm->state.usage_power) return 0; - err = chip->ops->apply(chip, pwm, state); - trace_pwm_apply(pwm, state, err); - if (err) - return err; + if (ops->write_waveform) { + struct pwm_waveform wf; + char wfhw[WFHWSIZE]; - pwm->state = *state; + BUG_ON(WFHWSIZE < ops->sizeof_wfhw); - /* - * only do this after pwm->state was applied as some - * implementations of .get_state depend on this - */ - pwm_apply_debug(pwm, state); + pwm_state2wf(state, &wf); + + /* + * The rounding is wrong here for states with inverted polarity. + * While .apply() rounds down duty_cycle (which represents the + * time from the start of the period to the inner edge), + * .round_waveform_tohw() rounds down the time the PWM is high. + * Can be fixed if the need arises, until reported otherwise + * let's assume that consumers don't care. + */ + + err = __pwm_round_waveform_tohw(chip, pwm, &wf, &wfhw); + if (err) { + if (err > 0) + /* + * This signals an invalid request, typically + * the requested period (or duty_offset) is + * smaller than possible with the hardware. + */ + return -EINVAL; + + return err; + } + + if (IS_ENABLED(CONFIG_PWM_DEBUG)) { + struct pwm_waveform wf_rounded; + + err = __pwm_round_waveform_fromhw(chip, pwm, &wfhw, &wf_rounded); + if (err) + return err; + + if (!pwm_check_rounding(&wf, &wf_rounded)) + dev_err(&chip->dev, "Wrong rounding: requested %llu/%llu [+%llu], result %llu/%llu [+%llu]\n", + wf.duty_length_ns, wf.period_length_ns, wf.duty_offset_ns, + wf_rounded.duty_length_ns, wf_rounded.period_length_ns, wf_rounded.duty_offset_ns); + } + + err = __pwm_write_waveform(chip, pwm, &wfhw); + if (err) + return err; + + pwm->state = *state; + + } else { + err = ops->apply(chip, pwm, state); + trace_pwm_apply(pwm, state, err); + if (err) + return err; + + pwm->state = *state; + + /* + * only do this after pwm->state was applied as some + * implementations of .get_state() depend on this + */ + pwm_apply_debug(pwm, state); + } return 0; } @@ -220,6 +668,7 @@ static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state) int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state) { int err; + struct pwm_chip *chip = pwm->chip; /* * Some lowlevel driver's implementations of .apply() make use of @@ -230,7 +679,12 @@ int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state) */ might_sleep(); - if (IS_ENABLED(CONFIG_PWM_DEBUG) && pwm->chip->atomic) { + guard(pwmchip)(chip); + + if (!chip->operational) + return -ENODEV; + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && chip->atomic) { /* * Catch any drivers that have been marked as atomic but * that will sleep anyway. @@ -254,13 +708,69 @@ EXPORT_SYMBOL_GPL(pwm_apply_might_sleep); */ int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state) { - WARN_ONCE(!pwm->chip->atomic, + struct pwm_chip *chip = pwm->chip; + + WARN_ONCE(!chip->atomic, "sleeping PWM driver used in atomic context\n"); + guard(pwmchip)(chip); + + if (!chip->operational) + return -ENODEV; + return __pwm_apply(pwm, state); } EXPORT_SYMBOL_GPL(pwm_apply_atomic); +/** + * pwm_get_state_hw() - get the current PWM state from hardware + * @pwm: PWM device + * @state: state to fill with the current PWM state + * + * Similar to pwm_get_state() but reads the current PWM state from hardware + * instead of the requested state. + * + * Returns: 0 on success or a negative error code on failure. + * Context: May sleep. + */ +int pwm_get_state_hw(struct pwm_device *pwm, struct pwm_state *state) +{ + struct pwm_chip *chip = pwm->chip; + const struct pwm_ops *ops = chip->ops; + int ret = -EOPNOTSUPP; + + might_sleep(); + + guard(pwmchip)(chip); + + if (!chip->operational) + return -ENODEV; + + if (ops->read_waveform) { + char wfhw[WFHWSIZE]; + struct pwm_waveform wf; + + BUG_ON(WFHWSIZE < ops->sizeof_wfhw); + + ret = __pwm_read_waveform(chip, pwm, &wfhw); + if (ret) + return ret; + + ret = __pwm_round_waveform_fromhw(chip, pwm, &wfhw, &wf); + if (ret) + return ret; + + pwm_wf2state(&wf, state); + + } else if (ops->get_state) { + ret = ops->get_state(chip, pwm, state); + trace_pwm_get(pwm, state, ret); + } + + return ret; +} +EXPORT_SYMBOL_GPL(pwm_get_state_hw); + /** * pwm_adjust_config() - adjust the current PWM config to the PWM arguments * @pwm: PWM device @@ -334,8 +844,18 @@ static int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, if (!ops->capture) return -ENOSYS; + /* + * Holding the pwm_lock is probably not needed. If you use pwm_capture() + * and you're interested to speed it up, please convince yourself it's + * really not needed, test and then suggest a patch on the mailing list. + */ guard(mutex)(&pwm_lock); + guard(pwmchip)(chip); + + if (!chip->operational) + return -ENODEV; + return ops->capture(chip, pwm, result, timeout); } @@ -350,9 +870,7 @@ static struct pwm_chip *pwmchip_find_by_name(const char *name) guard(mutex)(&pwm_lock); idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) { - const char *chip_name = dev_name(pwmchip_parent(chip)); - - if (chip_name && strcmp(chip_name, name) == 0) + if (device_match_name(pwmchip_parent(chip), name)) return chip; } @@ -368,6 +886,14 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) if (test_bit(PWMF_REQUESTED, &pwm->flags)) return -EBUSY; + /* + * This function is called while holding pwm_lock. As .operational only + * changes while holding this lock, checking it here without holding the + * chip lock is fine. + */ + if (!chip->operational) + return -ENODEV; + if (!try_module_get(chip->owner)) return -ENODEV; @@ -386,7 +912,7 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) } } - if (ops->get_state) { + if (ops->read_waveform || ops->get_state) { /* * Zero-initialize state because most drivers are unaware of * .usage_power. The other members of state are supposed to be @@ -396,9 +922,7 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) */ struct pwm_state state = { 0, }; - err = ops->get_state(chip, pwm, &state); - trace_pwm_get(pwm, &state, err); - + err = pwm_get_state_hw(pwm, &state); if (!err) pwm->state = state; @@ -1020,178 +1544,92 @@ struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t chip->npwm = npwm; chip->uses_pwmchip_alloc = true; + chip->operational = false; pwmchip_dev = &chip->dev; device_initialize(pwmchip_dev); pwmchip_dev->class = &pwm_class; - pwmchip_dev->parent = parent; - pwmchip_dev->release = pwmchip_release; - - pwmchip_set_drvdata(chip, pwmchip_priv(chip)); - - for (i = 0; i < chip->npwm; i++) { - struct pwm_device *pwm = &chip->pwms[i]; - pwm->chip = chip; - pwm->hwpwm = i; - } - - return chip; -} -EXPORT_SYMBOL_GPL(pwmchip_alloc); - -static void devm_pwmchip_put(void *data) -{ - struct pwm_chip *chip = data; - - pwmchip_put(chip); -} - -struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv) -{ - struct pwm_chip *chip; - int ret; - - chip = pwmchip_alloc(parent, npwm, sizeof_priv); - if (IS_ERR(chip)) - return chip; - - ret = devm_add_action_or_reset(parent, devm_pwmchip_put, chip); - if (ret) - return ERR_PTR(ret); - - return chip; -} -EXPORT_SYMBOL_GPL(devm_pwmchip_alloc); - -static void of_pwmchip_add(struct pwm_chip *chip) -{ - if (!pwmchip_parent(chip) || !pwmchip_parent(chip)->of_node) - return; - - if (!chip->of_xlate) - chip->of_xlate = of_pwm_xlate_with_flags; - - of_node_get(pwmchip_parent(chip)->of_node); -} - -static void of_pwmchip_remove(struct pwm_chip *chip) -{ - if (pwmchip_parent(chip)) - of_node_put(pwmchip_parent(chip)->of_node); -} - -static bool pwm_ops_check(const struct pwm_chip *chip) -{ - const struct pwm_ops *ops = chip->ops; - - if (!ops->apply) - return false; - - if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state) - dev_warn(pwmchip_parent(chip), - "Please implement the .get_state() callback\n"); - - return true; -} - -/** - * __pwmchip_add() - register a new PWM chip - * @chip: the PWM chip to add - * @owner: reference to the module providing the chip. - * - * Register a new PWM chip. @owner is supposed to be THIS_MODULE, use the - * pwmchip_add wrapper to do this right. - * - * Returns: 0 on success or a negative error code on failure. - */ -int __pwmchip_add(struct pwm_chip *chip, struct module *owner) -{ - int ret; - - if (!chip || !pwmchip_parent(chip) || !chip->ops || !chip->npwm) - return -EINVAL; - - /* - * a struct pwm_chip must be allocated using (devm_)pwmchip_alloc, - * otherwise the embedded struct device might disappear too early - * resulting in memory corruption. - * Catch drivers that were not converted appropriately. - */ - if (!chip->uses_pwmchip_alloc) - return -EINVAL; - - if (!pwm_ops_check(chip)) - return -EINVAL; - - chip->owner = owner; - - guard(mutex)(&pwm_lock); + pwmchip_dev->parent = parent; + pwmchip_dev->release = pwmchip_release; - ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL); - if (ret < 0) - return ret; + pwmchip_set_drvdata(chip, pwmchip_priv(chip)); - chip->id = ret; + for (i = 0; i < chip->npwm; i++) { + struct pwm_device *pwm = &chip->pwms[i]; + pwm->chip = chip; + pwm->hwpwm = i; + } - dev_set_name(&chip->dev, "pwmchip%u", chip->id); + return chip; +} +EXPORT_SYMBOL_GPL(pwmchip_alloc); - if (IS_ENABLED(CONFIG_OF)) - of_pwmchip_add(chip); +static void devm_pwmchip_put(void *data) +{ + struct pwm_chip *chip = data; - ret = device_add(&chip->dev); - if (ret) - goto err_device_add; + pwmchip_put(chip); +} - return 0; +struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv) +{ + struct pwm_chip *chip; + int ret; -err_device_add: - if (IS_ENABLED(CONFIG_OF)) - of_pwmchip_remove(chip); + chip = pwmchip_alloc(parent, npwm, sizeof_priv); + if (IS_ERR(chip)) + return chip; - idr_remove(&pwm_chips, chip->id); + ret = devm_add_action_or_reset(parent, devm_pwmchip_put, chip); + if (ret) + return ERR_PTR(ret); - return ret; + return chip; } -EXPORT_SYMBOL_GPL(__pwmchip_add); +EXPORT_SYMBOL_GPL(devm_pwmchip_alloc); -/** - * pwmchip_remove() - remove a PWM chip - * @chip: the PWM chip to remove - * - * Removes a PWM chip. - */ -void pwmchip_remove(struct pwm_chip *chip) +static void of_pwmchip_add(struct pwm_chip *chip) { - pwmchip_sysfs_unexport(chip); - - if (IS_ENABLED(CONFIG_OF)) - of_pwmchip_remove(chip); + if (!pwmchip_parent(chip) || !pwmchip_parent(chip)->of_node) + return; - scoped_guard(mutex, &pwm_lock) - idr_remove(&pwm_chips, chip->id); + if (!chip->of_xlate) + chip->of_xlate = of_pwm_xlate_with_flags; - device_del(&chip->dev); + of_node_get(pwmchip_parent(chip)->of_node); } -EXPORT_SYMBOL_GPL(pwmchip_remove); -static void devm_pwmchip_remove(void *data) +static void of_pwmchip_remove(struct pwm_chip *chip) { - struct pwm_chip *chip = data; - - pwmchip_remove(chip); + if (pwmchip_parent(chip)) + of_node_put(pwmchip_parent(chip)->of_node); } -int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner) +static bool pwm_ops_check(const struct pwm_chip *chip) { - int ret; + const struct pwm_ops *ops = chip->ops; - ret = __pwmchip_add(chip, owner); - if (ret) - return ret; + if (ops->write_waveform) { + if (!ops->round_waveform_tohw || + !ops->round_waveform_fromhw || + !ops->write_waveform) + return false; - return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip); + if (WFHWSIZE < ops->sizeof_wfhw) { + dev_warn(pwmchip_parent(chip), "WFHWSIZE < %zu\n", ops->sizeof_wfhw); + return false; + } + } else { + if (!ops->apply) + return false; + + if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state) + dev_warn(pwmchip_parent(chip), + "Please implement the .get_state() callback\n"); + } + + return true; } -EXPORT_SYMBOL_GPL(__devm_pwmchip_add); static struct device_link *pwm_device_link_add(struct device *dev, struct pwm_device *pwm) @@ -1370,36 +1808,6 @@ static struct pwm_device *acpi_pwm_get(const struct fwnode_handle *fwnode) static DEFINE_MUTEX(pwm_lookup_lock); static LIST_HEAD(pwm_lookup_list); -/** - * pwm_add_table() - register PWM device consumers - * @table: array of consumers to register - * @num: number of consumers in table - */ -void pwm_add_table(struct pwm_lookup *table, size_t num) -{ - guard(mutex)(&pwm_lookup_lock); - - while (num--) { - list_add_tail(&table->list, &pwm_lookup_list); - table++; - } -} - -/** - * pwm_remove_table() - unregister PWM device consumers - * @table: array of consumers to unregister - * @num: number of consumers in table - */ -void pwm_remove_table(struct pwm_lookup *table, size_t num) -{ - guard(mutex)(&pwm_lookup_lock); - - while (num--) { - list_del(&table->list); - table++; - } -} - /** * pwm_get() - look up and request a PWM device * @dev: device for PWM consumer @@ -1538,12 +1946,17 @@ void pwm_put(struct pwm_device *pwm) guard(mutex)(&pwm_lock); - if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) { + /* + * Trigger a warning if a consumer called pwm_put() twice. + * If the chip isn't operational, PWMF_REQUESTED was already cleared in + * pwmchip_remove(). So don't warn in this case. + */ + if (chip->operational && !test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) { pr_warn("PWM device already freed\n"); return; } - if (chip->ops->free) + if (chip->operational && chip->ops->free) pwm->chip->ops->free(pwm->chip, pwm); pwm->label = NULL; @@ -1621,6 +2034,162 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev, } EXPORT_SYMBOL_GPL(devm_fwnode_pwm_get); +/** + * __pwmchip_add() - register a new PWM chip + * @chip: the PWM chip to add + * @owner: reference to the module providing the chip. + * + * Register a new PWM chip. @owner is supposed to be THIS_MODULE, use the + * pwmchip_add wrapper to do this right. + * + * Returns: 0 on success or a negative error code on failure. + */ +int __pwmchip_add(struct pwm_chip *chip, struct module *owner) +{ + int ret; + + if (!chip || !pwmchip_parent(chip) || !chip->ops || !chip->npwm) + return -EINVAL; + + /* + * a struct pwm_chip must be allocated using (devm_)pwmchip_alloc, + * otherwise the embedded struct device might disappear too early + * resulting in memory corruption. + * Catch drivers that were not converted appropriately. + */ + if (!chip->uses_pwmchip_alloc) + return -EINVAL; + + if (!pwm_ops_check(chip)) + return -EINVAL; + + chip->owner = owner; + + if (chip->atomic) + spin_lock_init(&chip->atomic_lock); + else + mutex_init(&chip->nonatomic_lock); + + guard(mutex)(&pwm_lock); + + ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL); + if (ret < 0) + return ret; + + chip->id = ret; + + dev_set_name(&chip->dev, "pwmchip%u", chip->id); + + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_add(chip); + + scoped_guard(pwmchip, chip) + chip->operational = true; + + ret = device_add(&chip->dev); + if (ret) + goto err_device_add; + + return 0; + +err_device_add: + scoped_guard(pwmchip, chip) + chip->operational = false; + + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_remove(chip); + + idr_remove(&pwm_chips, chip->id); + + return ret; +} +EXPORT_SYMBOL_GPL(__pwmchip_add); + +/** + * pwmchip_remove() - remove a PWM chip + * @chip: the PWM chip to remove + * + * Removes a PWM chip. + */ +void pwmchip_remove(struct pwm_chip *chip) +{ + pwmchip_sysfs_unexport(chip); + + scoped_guard(mutex, &pwm_lock) { + unsigned int i; + + scoped_guard(pwmchip, chip) + chip->operational = false; + + for (i = 0; i < chip->npwm; ++i) { + struct pwm_device *pwm = &chip->pwms[i]; + + if (test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) { + dev_warn(&chip->dev, "Freeing requested PWM #%u\n", i); + if (pwm->chip->ops->free) + pwm->chip->ops->free(pwm->chip, pwm); + } + } + + if (IS_ENABLED(CONFIG_OF)) + of_pwmchip_remove(chip); + + idr_remove(&pwm_chips, chip->id); + } + + device_del(&chip->dev); +} +EXPORT_SYMBOL_GPL(pwmchip_remove); + +static void devm_pwmchip_remove(void *data) +{ + struct pwm_chip *chip = data; + + pwmchip_remove(chip); +} + +int __devm_pwmchip_add(struct device *dev, struct pwm_chip *chip, struct module *owner) +{ + int ret; + + ret = __pwmchip_add(chip, owner); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_pwmchip_remove, chip); +} +EXPORT_SYMBOL_GPL(__devm_pwmchip_add); + +/** + * pwm_add_table() - register PWM device consumers + * @table: array of consumers to register + * @num: number of consumers in table + */ +void pwm_add_table(struct pwm_lookup *table, size_t num) +{ + guard(mutex)(&pwm_lookup_lock); + + while (num--) { + list_add_tail(&table->list, &pwm_lookup_list); + table++; + } +} + +/** + * pwm_remove_table() - unregister PWM device consumers + * @table: array of consumers to unregister + * @num: number of consumers in table + */ +void pwm_remove_table(struct pwm_lookup *table, size_t num) +{ + guard(mutex)(&pwm_lookup_lock); + + while (num--) { + list_del(&table->list); + table++; + } +} + static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) { unsigned int i; diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 5ee4254d1e4878..f9ff78ba122d49 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -342,8 +342,8 @@ static int atmel_tcb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, return 0; } - period = state->period < INT_MAX ? state->period : INT_MAX; - duty_cycle = state->duty_cycle < INT_MAX ? state->duty_cycle : INT_MAX; + period = min(state->period, INT_MAX); + duty_cycle = min(state->duty_cycle, INT_MAX); ret = atmel_tcb_pwm_config(chip, pwm, duty_cycle, period); if (ret) diff --git a/drivers/pwm/pwm-axi-pwmgen.c b/drivers/pwm/pwm-axi-pwmgen.c index b5477659ba186c..4259a0db9ff458 100644 --- a/drivers/pwm/pwm-axi-pwmgen.c +++ b/drivers/pwm/pwm-axi-pwmgen.c @@ -9,7 +9,7 @@ * * Limitations: * - The writes to registers for period and duty are shadowed until - * LOAD_CONFIG is written to AXI_PWMGEN_REG_CONFIG, at which point + * LOAD_CONFIG is written to AXI_PWMGEN_REG_RSTN, at which point * they take effect. * - Writing LOAD_CONFIG also has the effect of re-synchronizing all * enabled channels, which could cause glitching on other channels. It @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -32,14 +33,16 @@ #define AXI_PWMGEN_REG_ID 0x04 #define AXI_PWMGEN_REG_SCRATCHPAD 0x08 #define AXI_PWMGEN_REG_CORE_MAGIC 0x0C -#define AXI_PWMGEN_REG_CONFIG 0x10 +#define AXI_PWMGEN_REG_RSTN 0x10 +#define AXI_PWMGEN_REG_RSTN_LOAD_CONFIG BIT(1) +#define AXI_PWMGEN_REG_RSTN_RESET BIT(0) #define AXI_PWMGEN_REG_NPWM 0x14 +#define AXI_PWMGEN_REG_CONFIG 0x18 +#define AXI_PWMGEN_REG_CONFIG_FORCE_ALIGN BIT(1) #define AXI_PWMGEN_CHX_PERIOD(ch) (0x40 + (4 * (ch))) #define AXI_PWMGEN_CHX_DUTY(ch) (0x80 + (4 * (ch))) #define AXI_PWMGEN_CHX_OFFSET(ch) (0xC0 + (4 * (ch))) #define AXI_PWMGEN_REG_CORE_MAGIC_VAL 0x601A3471 /* Identification number to test during setup */ -#define AXI_PWMGEN_LOAD_CONFIG BIT(1) -#define AXI_PWMGEN_REG_CONFIG_RESET BIT(0) struct axi_pwmgen_ddata { struct regmap *regmap; @@ -53,81 +56,147 @@ static const struct regmap_config axi_pwmgen_regmap_config = { .max_register = 0xFC, }; -static int axi_pwmgen_apply(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) +/* This represents a hardware configuration for one channel */ +struct axi_pwmgen_waveform { + u32 period_cnt; + u32 duty_cycle_cnt; + u32 duty_offset_cnt; +}; + +static struct axi_pwmgen_ddata *axi_pwmgen_ddata_from_chip(struct pwm_chip *chip) { - struct axi_pwmgen_ddata *ddata = pwmchip_get_drvdata(chip); - unsigned int ch = pwm->hwpwm; - struct regmap *regmap = ddata->regmap; - u64 period_cnt, duty_cnt; - int ret; + return pwmchip_get_drvdata(chip); +} - if (state->polarity != PWM_POLARITY_NORMAL) - return -EINVAL; +static int axi_pwmgen_round_waveform_tohw(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_waveform *wf, + void *_wfhw) +{ + struct axi_pwmgen_waveform *wfhw = _wfhw; + struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip); + + if (wf->period_length_ns == 0) { + *wfhw = (struct axi_pwmgen_waveform){ + .period_cnt = 0, + .duty_cycle_cnt = 0, + .duty_offset_cnt = 0, + }; + } else { + /* With ddata->clk_rate_hz < NSEC_PER_SEC this won't overflow. */ + wfhw->period_cnt = min_t(u64, + mul_u64_u32_div(wf->period_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC), + U32_MAX); + + if (wfhw->period_cnt == 0) { + /* + * The specified period is too short for the hardware. + * Let's round .duty_cycle down to 0 to get a (somewhat) + * valid result. + */ + wfhw->period_cnt = 1; + wfhw->duty_cycle_cnt = 0; + wfhw->duty_offset_cnt = 0; + } else { + wfhw->duty_cycle_cnt = min_t(u64, + mul_u64_u32_div(wf->duty_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC), + U32_MAX); + wfhw->duty_offset_cnt = min_t(u64, + mul_u64_u32_div(wf->duty_offset_ns, ddata->clk_rate_hz, NSEC_PER_SEC), + U32_MAX); + } + } - if (state->enabled) { - period_cnt = mul_u64_u64_div_u64(state->period, ddata->clk_rate_hz, NSEC_PER_SEC); - if (period_cnt > UINT_MAX) - period_cnt = UINT_MAX; + dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> PERIOD: %08x, DUTY: %08x, OFFSET: %08x\n", + pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, + ddata->clk_rate_hz, wfhw->period_cnt, wfhw->duty_cycle_cnt, wfhw->duty_offset_cnt); - if (period_cnt == 0) - return -EINVAL; + return 0; +} - ret = regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(ch), period_cnt); - if (ret) - return ret; +static int axi_pwmgen_round_waveform_fromhw(struct pwm_chip *chip, struct pwm_device *pwm, + const void *_wfhw, struct pwm_waveform *wf) +{ + const struct axi_pwmgen_waveform *wfhw = _wfhw; + struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip); - duty_cnt = mul_u64_u64_div_u64(state->duty_cycle, ddata->clk_rate_hz, NSEC_PER_SEC); - if (duty_cnt > UINT_MAX) - duty_cnt = UINT_MAX; + wf->period_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->period_cnt * NSEC_PER_SEC, + ddata->clk_rate_hz); - ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(ch), duty_cnt); - if (ret) - return ret; - } else { - ret = regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(ch), 0); - if (ret) - return ret; + wf->duty_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_cycle_cnt * NSEC_PER_SEC, + ddata->clk_rate_hz); - ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(ch), 0); - if (ret) - return ret; - } + wf->duty_offset_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_offset_cnt * NSEC_PER_SEC, + ddata->clk_rate_hz); - return regmap_write(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_LOAD_CONFIG); + return 0; } -static int axi_pwmgen_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) +static int axi_pwmgen_write_waveform(struct pwm_chip *chip, + struct pwm_device *pwm, + const void *_wfhw) { - struct axi_pwmgen_ddata *ddata = pwmchip_get_drvdata(chip); + const struct axi_pwmgen_waveform *wfhw = _wfhw; + struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip); struct regmap *regmap = ddata->regmap; unsigned int ch = pwm->hwpwm; - u32 cnt; int ret; - ret = regmap_read(regmap, AXI_PWMGEN_CHX_PERIOD(ch), &cnt); + ret = regmap_write(regmap, AXI_PWMGEN_CHX_PERIOD(ch), wfhw->period_cnt); + if (ret) + return ret; + + ret = regmap_write(regmap, AXI_PWMGEN_CHX_DUTY(ch), wfhw->duty_cycle_cnt); if (ret) return ret; - state->enabled = cnt != 0; + ret = regmap_write(regmap, AXI_PWMGEN_CHX_OFFSET(ch), wfhw->duty_offset_cnt); + if (ret) + return ret; + + return regmap_write(regmap, AXI_PWMGEN_REG_RSTN, AXI_PWMGEN_REG_RSTN_LOAD_CONFIG); +} + +static int axi_pwmgen_read_waveform(struct pwm_chip *chip, + struct pwm_device *pwm, + void *_wfhw) +{ + struct axi_pwmgen_waveform *wfhw = _wfhw; + struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip); + struct regmap *regmap = ddata->regmap; + unsigned int ch = pwm->hwpwm; + int ret; - state->period = DIV_ROUND_UP_ULL((u64)cnt * NSEC_PER_SEC, ddata->clk_rate_hz); + ret = regmap_read(regmap, AXI_PWMGEN_CHX_PERIOD(ch), &wfhw->period_cnt); + if (ret) + return ret; - ret = regmap_read(regmap, AXI_PWMGEN_CHX_DUTY(ch), &cnt); + ret = regmap_read(regmap, AXI_PWMGEN_CHX_DUTY(ch), &wfhw->duty_cycle_cnt); if (ret) return ret; - state->duty_cycle = DIV_ROUND_UP_ULL((u64)cnt * NSEC_PER_SEC, ddata->clk_rate_hz); + ret = regmap_read(regmap, AXI_PWMGEN_CHX_OFFSET(ch), &wfhw->duty_offset_cnt); + if (ret) + return ret; - state->polarity = PWM_POLARITY_NORMAL; + if (wfhw->duty_cycle_cnt > wfhw->period_cnt) + wfhw->duty_cycle_cnt = wfhw->period_cnt; + + /* XXX: is this the actual behaviour of the hardware? */ + if (wfhw->duty_offset_cnt >= wfhw->period_cnt) { + wfhw->duty_cycle_cnt = 0; + wfhw->duty_offset_cnt = 0; + } return 0; } static const struct pwm_ops axi_pwmgen_pwm_ops = { - .apply = axi_pwmgen_apply, - .get_state = axi_pwmgen_get_state, + .sizeof_wfhw = sizeof(struct axi_pwmgen_waveform), + .round_waveform_tohw = axi_pwmgen_round_waveform_tohw, + .round_waveform_fromhw = axi_pwmgen_round_waveform_fromhw, + .read_waveform = axi_pwmgen_read_waveform, + .write_waveform = axi_pwmgen_write_waveform, }; static int axi_pwmgen_setup(struct regmap *regmap, struct device *dev) @@ -156,7 +225,17 @@ static int axi_pwmgen_setup(struct regmap *regmap, struct device *dev) } /* Enable the core */ - ret = regmap_clear_bits(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_REG_CONFIG_RESET); + ret = regmap_clear_bits(regmap, AXI_PWMGEN_REG_RSTN, AXI_PWMGEN_REG_RSTN_RESET); + if (ret) + return ret; + + /* + * Enable force align so that changes to PWM period and duty cycle take + * effect immediately. Otherwise, the effect of the change is delayed + * until the period of all channels run out, which can be long after the + * apply function returns. + */ + ret = regmap_set_bits(regmap, AXI_PWMGEN_REG_CONFIG, AXI_PWMGEN_REG_CONFIG_FORCE_ALIGN); if (ret) return ret; diff --git a/drivers/pwm/pwm-dwc-core.c b/drivers/pwm/pwm-dwc-core.c index c8425493b95d85..6dabec93a3c641 100644 --- a/drivers/pwm/pwm-dwc-core.c +++ b/drivers/pwm/pwm-dwc-core.c @@ -9,7 +9,7 @@ * Author: Raymond Tan */ -#define DEFAULT_SYMBOL_NAMESPACE dwc_pwm +#define DEFAULT_SYMBOL_NAMESPACE "dwc_pwm" #include #include diff --git a/drivers/pwm/pwm-dwc.h b/drivers/pwm/pwm-dwc.h index c6e2df5a612271..1562594e7f85a8 100644 --- a/drivers/pwm/pwm-dwc.h +++ b/drivers/pwm/pwm-dwc.h @@ -9,7 +9,7 @@ * Author: Raymond Tan */ -MODULE_IMPORT_NS(dwc_pwm); +MODULE_IMPORT_NS("dwc_pwm"); #define DWC_TIM_LD_CNT(n) ((n) * 0x14) #define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0) diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index 9e2bbf5b4a8ce7..3d34cdc4a3a51b 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -26,6 +26,7 @@ #define MX3_PWMSR 0x04 /* PWM Status Register */ #define MX3_PWMSAR 0x0C /* PWM Sample Register */ #define MX3_PWMPR 0x10 /* PWM Period Register */ +#define MX3_PWMCNR 0x14 /* PWM Counter Register */ #define MX3_PWMCR_FWM GENMASK(27, 26) #define MX3_PWMCR_STOPEN BIT(25) @@ -79,9 +80,12 @@ /* PWMPR register value of 0xffff has the same effect as 0xfffe */ #define MX3_PWMPR_MAX 0xfffe +static const char * const pwm_imx27_clks[] = {"ipg", "per"}; +#define PWM_IMX27_PER 1 + struct pwm_imx27_chip { - struct clk *clk_ipg; - struct clk *clk_per; + struct clk_bulk_data clks[ARRAY_SIZE(pwm_imx27_clks)]; + int clks_cnt; void __iomem *mmio_base; /* @@ -97,29 +101,6 @@ static inline struct pwm_imx27_chip *to_pwm_imx27_chip(struct pwm_chip *chip) return pwmchip_get_drvdata(chip); } -static int pwm_imx27_clk_prepare_enable(struct pwm_imx27_chip *imx) -{ - int ret; - - ret = clk_prepare_enable(imx->clk_ipg); - if (ret) - return ret; - - ret = clk_prepare_enable(imx->clk_per); - if (ret) { - clk_disable_unprepare(imx->clk_ipg); - return ret; - } - - return 0; -} - -static void pwm_imx27_clk_disable_unprepare(struct pwm_imx27_chip *imx) -{ - clk_disable_unprepare(imx->clk_per); - clk_disable_unprepare(imx->clk_ipg); -} - static int pwm_imx27_get_state(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { @@ -128,7 +109,7 @@ static int pwm_imx27_get_state(struct pwm_chip *chip, u64 tmp; int ret; - ret = pwm_imx27_clk_prepare_enable(imx); + ret = clk_bulk_prepare_enable(imx->clks_cnt, imx->clks); if (ret < 0) return ret; @@ -151,7 +132,7 @@ static int pwm_imx27_get_state(struct pwm_chip *chip, } prescaler = MX3_PWMCR_PRESCALER_GET(val); - pwm_clk = clk_get_rate(imx->clk_per); + pwm_clk = clk_get_rate(imx->clks[PWM_IMX27_PER].clk); val = readl(imx->mmio_base + MX3_PWMPR); period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val; @@ -171,7 +152,7 @@ static int pwm_imx27_get_state(struct pwm_chip *chip, tmp = NSEC_PER_SEC * (u64)(val) * prescaler; state->duty_cycle = DIV_ROUND_UP_ULL(tmp, pwm_clk); - pwm_imx27_clk_disable_unprepare(imx); + clk_bulk_disable_unprepare(imx->clks_cnt, imx->clks); return 0; } @@ -219,14 +200,16 @@ static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip, static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, const struct pwm_state *state) { - unsigned long period_cycles, duty_cycles, prescale; + unsigned long period_cycles, duty_cycles, prescale, period_us, tmp; struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); unsigned long long c; unsigned long long clkrate; + unsigned long flags; + int val; int ret; u32 cr; - clkrate = clk_get_rate(imx->clk_per); + clkrate = clk_get_rate(imx->clks[PWM_IMX27_PER].clk); c = clkrate * state->period; do_div(c, NSEC_PER_SEC); @@ -256,14 +239,105 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (pwm->state.enabled) { pwm_imx27_wait_fifo_slot(chip, pwm); } else { - ret = pwm_imx27_clk_prepare_enable(imx); + ret = clk_bulk_prepare_enable(imx->clks_cnt, imx->clks); if (ret) return ret; pwm_imx27_sw_reset(chip); } - writel(duty_cycles, imx->mmio_base + MX3_PWMSAR); + val = readl(imx->mmio_base + MX3_PWMPR); + val = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val; + cr = readl(imx->mmio_base + MX3_PWMCR); + tmp = NSEC_PER_SEC * (u64)(val + 2) * MX3_PWMCR_PRESCALER_GET(cr); + tmp = DIV_ROUND_UP_ULL(tmp, clkrate); + period_us = DIV_ROUND_UP_ULL(tmp, 1000); + + /* + * ERR051198: + * PWM: PWM output may not function correctly if the FIFO is empty when + * a new SAR value is programmed + * + * Description: + * When the PWM FIFO is empty, a new value programmed to the PWM Sample + * register (PWM_PWMSAR) will be directly applied even if the current + * timer period has not expired. + * + * If the new SAMPLE value programmed in the PWM_PWMSAR register is + * less than the previous value, and the PWM counter register + * (PWM_PWMCNR) that contains the current COUNT value is greater than + * the new programmed SAMPLE value, the current period will not flip + * the level. This may result in an output pulse with a duty cycle of + * 100%. + * + * Consider a change from + * ________ + * / \______/ + * ^ * ^ + * to + * ____ + * / \__________/ + * ^ ^ + * At the time marked by *, the new write value will be directly applied + * to SAR even the current period is not over if FIFO is empty. + * + * ________ ____________________ + * / \______/ \__________/ + * ^ ^ * ^ ^ + * |<-- old SAR -->| |<-- new SAR -->| + * + * That is the output is active for a whole period. + * + * Workaround: + * Check new SAR less than old SAR and current counter is in errata + * windows, write extra old SAR into FIFO and new SAR will effect at + * next period. + * + * Sometime period is quite long, such as over 1 second. If add old SAR + * into FIFO unconditional, new SAR have to wait for next period. It + * may be too long. + * + * Turn off the interrupt to ensure that not IRQ and schedule happen + * during above operations. If any irq and schedule happen, counter + * in PWM will be out of data and take wrong action. + * + * Add a safety margin 1.5us because it needs some time to complete + * IO write. + * + * Use writel_relaxed() to minimize the interval between two writes to + * the SAR register to increase the fastest PWM frequency supported. + * + * When the PWM period is longer than 2us(or <500kHz), this workaround + * can solve this problem. No software workaround is available if PWM + * period is shorter than IO write. Just try best to fill old data + * into FIFO. + */ + c = clkrate * 1500; + do_div(c, NSEC_PER_SEC); + + local_irq_save(flags); + val = FIELD_GET(MX3_PWMSR_FIFOAV, readl_relaxed(imx->mmio_base + MX3_PWMSR)); + + if (duty_cycles < imx->duty_cycle && (cr & MX3_PWMCR_EN)) { + if (period_us < 2) { /* 2us = 500 kHz */ + /* Best effort attempt to fix up >500 kHz case */ + udelay(3 * period_us); + writel_relaxed(imx->duty_cycle, imx->mmio_base + MX3_PWMSAR); + writel_relaxed(imx->duty_cycle, imx->mmio_base + MX3_PWMSAR); + } else if (val < MX3_PWMSR_FIFOAV_2WORDS) { + val = readl_relaxed(imx->mmio_base + MX3_PWMCNR); + /* + * If counter is close to period, controller may roll over when + * next IO write. + */ + if ((val + c >= duty_cycles && val < imx->duty_cycle) || + val + c >= period_cycles) + writel_relaxed(imx->duty_cycle, imx->mmio_base + MX3_PWMSAR); + } + } + writel_relaxed(duty_cycles, imx->mmio_base + MX3_PWMSAR); + local_irq_restore(flags); + writel(period_cycles, imx->mmio_base + MX3_PWMPR); /* @@ -287,7 +361,7 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, writel(cr, imx->mmio_base + MX3_PWMCR); if (!state->enabled) - pwm_imx27_clk_disable_unprepare(imx); + clk_bulk_disable_unprepare(imx->clks_cnt, imx->clks); return 0; } @@ -309,21 +383,22 @@ static int pwm_imx27_probe(struct platform_device *pdev) struct pwm_imx27_chip *imx; int ret; u32 pwmcr; + int i; chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*imx)); if (IS_ERR(chip)) return PTR_ERR(chip); imx = to_pwm_imx27_chip(chip); - imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(imx->clk_ipg)) - return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg), - "getting ipg clock failed\n"); + imx->clks_cnt = ARRAY_SIZE(pwm_imx27_clks); + for (i = 0; i < imx->clks_cnt; ++i) + imx->clks[i].id = pwm_imx27_clks[i]; + + ret = devm_clk_bulk_get(&pdev->dev, imx->clks_cnt, imx->clks); - imx->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(imx->clk_per)) - return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_per), - "failed to get peripheral clock\n"); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "getting clocks failed\n"); chip->ops = &pwm_imx27_ops; @@ -331,14 +406,14 @@ static int pwm_imx27_probe(struct platform_device *pdev) if (IS_ERR(imx->mmio_base)) return PTR_ERR(imx->mmio_base); - ret = pwm_imx27_clk_prepare_enable(imx); + ret = clk_bulk_prepare_enable(imx->clks_cnt, imx->clks); if (ret) return ret; /* keep clks on if pwm is running */ pwmcr = readl(imx->mmio_base + MX3_PWMCR); if (!(pwmcr & MX3_PWMCR_EN)) - pwm_imx27_clk_disable_unprepare(imx); + clk_bulk_disable_unprepare(imx->clks_cnt, imx->clks); return devm_pwmchip_add(&pdev->dev, chip); } diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c index f7ece2809e6bba..ddc2a4ca90fd6d 100644 --- a/drivers/pwm/pwm-lpss-pci.c +++ b/drivers/pwm/pwm-lpss-pci.c @@ -70,4 +70,4 @@ module_pci_driver(pwm_lpss_driver_pci); MODULE_DESCRIPTION("PWM PCI driver for Intel LPSS"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PWM_LPSS); +MODULE_IMPORT_NS("PWM_LPSS"); diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 5130238a45670c..653ec9d0c8bf6a 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -78,5 +78,5 @@ module_platform_driver(pwm_lpss_driver_platform); MODULE_DESCRIPTION("PWM platform driver for Intel LPSS"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(PWM_LPSS); +MODULE_IMPORT_NS("PWM_LPSS"); MODULE_ALIAS("platform:pwm-lpss"); diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 867e2bc8c601c8..3b99feb3bb4918 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -19,7 +19,7 @@ #include #include -#define DEFAULT_SYMBOL_NAMESPACE PWM_LPSS +#define DEFAULT_SYMBOL_NAMESPACE "PWM_LPSS" #include "pwm-lpss.h" diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index eb24054f972973..17e591f61efb60 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -51,6 +51,391 @@ static u32 active_channels(struct stm32_pwm *dev) return ccer & TIM_CCER_CCXE; } +struct stm32_pwm_waveform { + u32 ccer; + u32 psc; + u32 arr; + u32 ccr; +}; + +static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip, + struct pwm_device *pwm, + const struct pwm_waveform *wf, + void *_wfhw) +{ + struct stm32_pwm_waveform *wfhw = _wfhw; + struct stm32_pwm *priv = to_stm32_pwm_dev(chip); + unsigned int ch = pwm->hwpwm; + unsigned long rate; + u64 ccr, duty; + int ret; + + if (wf->period_length_ns == 0) { + *wfhw = (struct stm32_pwm_waveform){ + .ccer = 0, + }; + + return 0; + } + + ret = clk_enable(priv->clk); + if (ret) + return ret; + + wfhw->ccer = TIM_CCER_CCxE(ch + 1); + if (priv->have_complementary_output) + wfhw->ccer |= TIM_CCER_CCxNE(ch + 1); + + rate = clk_get_rate(priv->clk); + + if (active_channels(priv) & ~(1 << ch * 4)) { + u64 arr; + + /* + * Other channels are already enabled, so the configured PSC and + * ARR must be used for this channel, too. + */ + ret = regmap_read(priv->regmap, TIM_PSC, &wfhw->psc); + if (ret) + goto out; + + ret = regmap_read(priv->regmap, TIM_ARR, &wfhw->arr); + if (ret) + goto out; + + /* + * calculate the best value for ARR for the given PSC, refuse if + * the resulting period gets bigger than the requested one. + */ + arr = mul_u64_u64_div_u64(wf->period_length_ns, rate, + (u64)NSEC_PER_SEC * (wfhw->psc + 1)); + if (arr <= wfhw->arr) { + /* + * requested period is small than the currently + * configured and unchangable period, report back the smallest + * possible period, i.e. the current state; Initialize + * ccr to anything valid. + */ + wfhw->ccr = 0; + ret = 1; + goto out; + } + + } else { + /* + * .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so + * the calculations here won't overflow. + * First we need to find the minimal value for prescaler such that + * + * period_ns * clkrate + * ------------------------------ < max_arr + 1 + * NSEC_PER_SEC * (prescaler + 1) + * + * This equation is equivalent to + * + * period_ns * clkrate + * ---------------------------- < prescaler + 1 + * NSEC_PER_SEC * (max_arr + 1) + * + * Using integer division and knowing that the right hand side is + * integer, this is further equivalent to + * + * (period_ns * clkrate) // (NSEC_PER_SEC * (max_arr + 1)) ≤ prescaler + */ + u64 psc = mul_u64_u64_div_u64(wf->period_length_ns, rate, + (u64)NSEC_PER_SEC * ((u64)priv->max_arr + 1)); + u64 arr; + + wfhw->psc = min_t(u64, psc, MAX_TIM_PSC); + + arr = mul_u64_u64_div_u64(wf->period_length_ns, rate, + (u64)NSEC_PER_SEC * (wfhw->psc + 1)); + if (!arr) { + /* + * requested period is too small, report back the smallest + * possible period, i.e. ARR = 0. The only valid CCR + * value is then zero, too. + */ + wfhw->arr = 0; + wfhw->ccr = 0; + ret = 1; + goto out; + } + + /* + * ARR is limited intentionally to values less than + * priv->max_arr to allow 100% duty cycle. + */ + wfhw->arr = min_t(u64, arr, priv->max_arr) - 1; + } + + duty = mul_u64_u64_div_u64(wf->duty_length_ns, rate, + (u64)NSEC_PER_SEC * (wfhw->psc + 1)); + duty = min_t(u64, duty, wfhw->arr + 1); + + if (wf->duty_length_ns && wf->duty_offset_ns && + wf->duty_length_ns + wf->duty_offset_ns >= wf->period_length_ns) { + wfhw->ccer |= TIM_CCER_CCxP(ch + 1); + if (priv->have_complementary_output) + wfhw->ccer |= TIM_CCER_CCxNP(ch + 1); + + ccr = wfhw->arr + 1 - duty; + } else { + ccr = duty; + } + + wfhw->ccr = min_t(u64, ccr, wfhw->arr + 1); + + dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> CCER: %08x, PSC: %08x, ARR: %08x, CCR: %08x\n", + pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns, + rate, wfhw->ccer, wfhw->psc, wfhw->arr, wfhw->ccr); + +out: + clk_disable(priv->clk); + + return ret; +} + +/* + * This should be moved to lib/math/div64.c. Currently there are some changes + * pending to mul_u64_u64_div_u64. Uwe will care for that when the dust settles. + */ +static u64 stm32_pwm_mul_u64_u64_div_u64_roundup(u64 a, u64 b, u64 c) +{ + u64 res = mul_u64_u64_div_u64(a, b, c); + /* Those multiplications might overflow but it doesn't matter */ + u64 rem = a * b - c * res; + + if (rem) + res += 1; + + return res; +} + +static int stm32_pwm_round_waveform_fromhw(struct pwm_chip *chip, + struct pwm_device *pwm, + const void *_wfhw, + struct pwm_waveform *wf) +{ + const struct stm32_pwm_waveform *wfhw = _wfhw; + struct stm32_pwm *priv = to_stm32_pwm_dev(chip); + unsigned int ch = pwm->hwpwm; + + if (wfhw->ccer & TIM_CCER_CCxE(ch + 1)) { + unsigned long rate = clk_get_rate(priv->clk); + u64 ccr_ns; + + /* The result doesn't overflow for rate >= 15259 */ + wf->period_length_ns = stm32_pwm_mul_u64_u64_div_u64_roundup(((u64)wfhw->psc + 1) * (wfhw->arr + 1), + NSEC_PER_SEC, rate); + + ccr_ns = stm32_pwm_mul_u64_u64_div_u64_roundup(((u64)wfhw->psc + 1) * wfhw->ccr, + NSEC_PER_SEC, rate); + + if (wfhw->ccer & TIM_CCER_CCxP(ch + 1)) { + wf->duty_length_ns = + stm32_pwm_mul_u64_u64_div_u64_roundup(((u64)wfhw->psc + 1) * (wfhw->arr + 1 - wfhw->ccr), + NSEC_PER_SEC, rate); + + wf->duty_offset_ns = ccr_ns; + } else { + wf->duty_length_ns = ccr_ns; + wf->duty_offset_ns = 0; + } + + dev_dbg(&chip->dev, "pwm#%u: CCER: %08x, PSC: %08x, ARR: %08x, CCR: %08x @%lu -> %lld/%lld [+%lld]\n", + pwm->hwpwm, wfhw->ccer, wfhw->psc, wfhw->arr, wfhw->ccr, rate, + wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns); + + } else { + *wf = (struct pwm_waveform){ + .period_length_ns = 0, + }; + } + + return 0; +} + +static int stm32_pwm_read_waveform(struct pwm_chip *chip, + struct pwm_device *pwm, + void *_wfhw) +{ + struct stm32_pwm_waveform *wfhw = _wfhw; + struct stm32_pwm *priv = to_stm32_pwm_dev(chip); + unsigned int ch = pwm->hwpwm; + int ret; + + ret = clk_enable(priv->clk); + if (ret) + return ret; + + ret = regmap_read(priv->regmap, TIM_CCER, &wfhw->ccer); + if (ret) + goto out; + + if (wfhw->ccer & TIM_CCER_CCxE(ch + 1)) { + ret = regmap_read(priv->regmap, TIM_PSC, &wfhw->psc); + if (ret) + goto out; + + ret = regmap_read(priv->regmap, TIM_ARR, &wfhw->arr); + if (ret) + goto out; + + if (wfhw->arr == U32_MAX) + wfhw->arr -= 1; + + ret = regmap_read(priv->regmap, TIM_CCRx(ch + 1), &wfhw->ccr); + if (ret) + goto out; + + if (wfhw->ccr > wfhw->arr + 1) + wfhw->ccr = wfhw->arr + 1; + } + +out: + clk_disable(priv->clk); + + return ret; +} + +static int stm32_pwm_write_waveform(struct pwm_chip *chip, + struct pwm_device *pwm, + const void *_wfhw) +{ + const struct stm32_pwm_waveform *wfhw = _wfhw; + struct stm32_pwm *priv = to_stm32_pwm_dev(chip); + unsigned int ch = pwm->hwpwm; + int ret; + + ret = clk_enable(priv->clk); + if (ret) + return ret; + + if (wfhw->ccer & TIM_CCER_CCxE(ch + 1)) { + u32 ccer, mask; + unsigned int shift; + u32 ccmr; + + ret = regmap_read(priv->regmap, TIM_CCER, &ccer); + if (ret) + goto out; + + /* If there are other channels enabled, don't update PSC and ARR */ + if (ccer & ~TIM_CCER_CCxE(ch + 1) & TIM_CCER_CCXE) { + u32 psc, arr; + + ret = regmap_read(priv->regmap, TIM_PSC, &psc); + if (ret) + goto out; + + if (psc != wfhw->psc) { + ret = -EBUSY; + goto out; + } + + ret = regmap_read(priv->regmap, TIM_ARR, &arr); + if (ret) + goto out; + + if (arr != wfhw->arr) { + ret = -EBUSY; + goto out; + } + } else { + ret = regmap_write(priv->regmap, TIM_PSC, wfhw->psc); + if (ret) + goto out; + + ret = regmap_write(priv->regmap, TIM_ARR, wfhw->arr); + if (ret) + goto out; + + ret = regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); + if (ret) + goto out; + + } + + /* set polarity */ + mask = TIM_CCER_CCxP(ch + 1) | TIM_CCER_CCxNP(ch + 1); + ret = regmap_update_bits(priv->regmap, TIM_CCER, mask, wfhw->ccer); + if (ret) + goto out; + + ret = regmap_write(priv->regmap, TIM_CCRx(ch + 1), wfhw->ccr); + if (ret) + goto out; + + /* Configure output mode */ + shift = (ch & 0x1) * CCMR_CHANNEL_SHIFT; + ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift; + mask = CCMR_CHANNEL_MASK << shift; + + if (ch < 2) + ret = regmap_update_bits(priv->regmap, TIM_CCMR1, mask, ccmr); + else + ret = regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr); + if (ret) + goto out; + + ret = regmap_set_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE); + if (ret) + goto out; + + if (!(ccer & TIM_CCER_CCxE(ch + 1))) { + mask = TIM_CCER_CCxE(ch + 1) | TIM_CCER_CCxNE(ch + 1); + + ret = clk_enable(priv->clk); + if (ret) + goto out; + + ccer = (ccer & ~mask) | (wfhw->ccer & mask); + regmap_write(priv->regmap, TIM_CCER, ccer); + + /* Make sure that registers are updated */ + regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); + + /* Enable controller */ + regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); + } + + } else { + /* disable channel */ + u32 mask, ccer; + + mask = TIM_CCER_CCxE(ch + 1); + if (priv->have_complementary_output) + mask |= TIM_CCER_CCxNE(ch + 1); + + ret = regmap_read(priv->regmap, TIM_CCER, &ccer); + if (ret) + goto out; + + if (ccer & mask) { + ccer = ccer & ~mask; + + ret = regmap_write(priv->regmap, TIM_CCER, ccer); + if (ret) + goto out; + + if (!(ccer & TIM_CCER_CCXE)) { + /* When all channels are disabled, we can disable the controller */ + ret = regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); + if (ret) + goto out; + } + + clk_disable(priv->clk); + } + } + +out: + clk_disable(priv->clk); + + return ret; +} + #define TIM_CCER_CC12P (TIM_CCER_CC1P | TIM_CCER_CC2P) #define TIM_CCER_CC12E (TIM_CCER_CC1E | TIM_CCER_CC2E) #define TIM_CCER_CC34P (TIM_CCER_CC3P | TIM_CCER_CC4P) @@ -308,228 +693,13 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } -static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch, - u64 duty_ns, u64 period_ns) -{ - unsigned long long prd, dty; - unsigned long long prescaler; - u32 ccmr, mask, shift; - - /* - * .probe() asserted that clk_get_rate() is not bigger than 1 GHz, so - * the calculations here won't overflow. - * First we need to find the minimal value for prescaler such that - * - * period_ns * clkrate - * ------------------------------ < max_arr + 1 - * NSEC_PER_SEC * (prescaler + 1) - * - * This equation is equivalent to - * - * period_ns * clkrate - * ---------------------------- < prescaler + 1 - * NSEC_PER_SEC * (max_arr + 1) - * - * Using integer division and knowing that the right hand side is - * integer, this is further equivalent to - * - * (period_ns * clkrate) // (NSEC_PER_SEC * (max_arr + 1)) ≤ prescaler - */ - - prescaler = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk), - (u64)NSEC_PER_SEC * ((u64)priv->max_arr + 1)); - if (prescaler > MAX_TIM_PSC) - return -EINVAL; - - prd = mul_u64_u64_div_u64(period_ns, clk_get_rate(priv->clk), - (u64)NSEC_PER_SEC * (prescaler + 1)); - if (!prd) - return -EINVAL; - - /* - * All channels share the same prescaler and counter so when two - * channels are active at the same time we can't change them - */ - if (active_channels(priv) & ~(1 << ch * 4)) { - u32 psc, arr; - - regmap_read(priv->regmap, TIM_PSC, &psc); - regmap_read(priv->regmap, TIM_ARR, &arr); - - if ((psc != prescaler) || (arr != prd - 1)) - return -EBUSY; - } - - regmap_write(priv->regmap, TIM_PSC, prescaler); - regmap_write(priv->regmap, TIM_ARR, prd - 1); - regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE); - - /* Calculate the duty cycles */ - dty = mul_u64_u64_div_u64(duty_ns, clk_get_rate(priv->clk), - (u64)NSEC_PER_SEC * (prescaler + 1)); - - regmap_write(priv->regmap, TIM_CCRx(ch + 1), dty); - - /* Configure output mode */ - shift = (ch & 0x1) * CCMR_CHANNEL_SHIFT; - ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift; - mask = CCMR_CHANNEL_MASK << shift; - - if (ch < 2) - regmap_update_bits(priv->regmap, TIM_CCMR1, mask, ccmr); - else - regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr); - - regmap_set_bits(priv->regmap, TIM_BDTR, TIM_BDTR_MOE); - - return 0; -} - -static int stm32_pwm_set_polarity(struct stm32_pwm *priv, unsigned int ch, - enum pwm_polarity polarity) -{ - u32 mask; - - mask = TIM_CCER_CCxP(ch + 1); - if (priv->have_complementary_output) - mask |= TIM_CCER_CCxNP(ch + 1); - - regmap_update_bits(priv->regmap, TIM_CCER, mask, - polarity == PWM_POLARITY_NORMAL ? 0 : mask); - - return 0; -} - -static int stm32_pwm_enable(struct stm32_pwm *priv, unsigned int ch) -{ - u32 mask; - int ret; - - ret = clk_enable(priv->clk); - if (ret) - return ret; - - /* Enable channel */ - mask = TIM_CCER_CCxE(ch + 1); - if (priv->have_complementary_output) - mask |= TIM_CCER_CCxNE(ch + 1); - - regmap_set_bits(priv->regmap, TIM_CCER, mask); - - /* Make sure that registers are updated */ - regmap_set_bits(priv->regmap, TIM_EGR, TIM_EGR_UG); - - /* Enable controller */ - regmap_set_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); - - return 0; -} - -static void stm32_pwm_disable(struct stm32_pwm *priv, unsigned int ch) -{ - u32 mask; - - /* Disable channel */ - mask = TIM_CCER_CCxE(ch + 1); - if (priv->have_complementary_output) - mask |= TIM_CCER_CCxNE(ch + 1); - - regmap_clear_bits(priv->regmap, TIM_CCER, mask); - - /* When all channels are disabled, we can disable the controller */ - if (!active_channels(priv)) - regmap_clear_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN); - - clk_disable(priv->clk); -} - -static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) -{ - bool enabled; - struct stm32_pwm *priv = to_stm32_pwm_dev(chip); - int ret; - - enabled = pwm->state.enabled; - - if (!state->enabled) { - if (enabled) - stm32_pwm_disable(priv, pwm->hwpwm); - return 0; - } - - if (state->polarity != pwm->state.polarity) - stm32_pwm_set_polarity(priv, pwm->hwpwm, state->polarity); - - ret = stm32_pwm_config(priv, pwm->hwpwm, - state->duty_cycle, state->period); - if (ret) - return ret; - - if (!enabled && state->enabled) - ret = stm32_pwm_enable(priv, pwm->hwpwm); - - return ret; -} - -static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) -{ - struct stm32_pwm *priv = to_stm32_pwm_dev(chip); - int ret; - - /* protect common prescaler for all active channels */ - mutex_lock(&priv->lock); - ret = stm32_pwm_apply(chip, pwm, state); - mutex_unlock(&priv->lock); - - return ret; -} - -static int stm32_pwm_get_state(struct pwm_chip *chip, - struct pwm_device *pwm, struct pwm_state *state) -{ - struct stm32_pwm *priv = to_stm32_pwm_dev(chip); - int ch = pwm->hwpwm; - unsigned long rate; - u32 ccer, psc, arr, ccr; - u64 dty, prd; - int ret; - - mutex_lock(&priv->lock); - - ret = regmap_read(priv->regmap, TIM_CCER, &ccer); - if (ret) - goto out; - - state->enabled = ccer & TIM_CCER_CCxE(ch + 1); - state->polarity = (ccer & TIM_CCER_CCxP(ch + 1)) ? - PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL; - ret = regmap_read(priv->regmap, TIM_PSC, &psc); - if (ret) - goto out; - ret = regmap_read(priv->regmap, TIM_ARR, &arr); - if (ret) - goto out; - ret = regmap_read(priv->regmap, TIM_CCRx(ch + 1), &ccr); - if (ret) - goto out; - - rate = clk_get_rate(priv->clk); - - prd = (u64)NSEC_PER_SEC * (psc + 1) * (arr + 1); - state->period = DIV_ROUND_UP_ULL(prd, rate); - dty = (u64)NSEC_PER_SEC * (psc + 1) * ccr; - state->duty_cycle = DIV_ROUND_UP_ULL(dty, rate); - -out: - mutex_unlock(&priv->lock); - return ret; -} - static const struct pwm_ops stm32pwm_ops = { - .apply = stm32_pwm_apply_locked, - .get_state = stm32_pwm_get_state, + .sizeof_wfhw = sizeof(struct stm32_pwm_waveform), + .round_waveform_tohw = stm32_pwm_round_waveform_tohw, + .round_waveform_fromhw = stm32_pwm_round_waveform_fromhw, + .read_waveform = stm32_pwm_read_waveform, + .write_waveform = stm32_pwm_write_waveform, + .capture = IS_ENABLED(CONFIG_DMA_ENGINE) ? stm32_pwm_capture : NULL, }; diff --git a/drivers/ras/amd/atl/access.c b/drivers/ras/amd/atl/access.c index ee4661ed28ba78..c2334f8f9add0b 100644 --- a/drivers/ras/amd/atl/access.c +++ b/drivers/ras/amd/atl/access.c @@ -70,12 +70,16 @@ static int __df_indirect_read(u16 node, u8 func, u16 reg, u8 instance_id, u32 *l u32 ficaa = 0; node = get_accessible_node(node); - if (node >= amd_nb_num()) + if (node >= amd_nb_num()) { + pr_debug("Node %u is out of bounds\n", node); goto out; + } F4 = node_to_amd_nb(node)->link; - if (!F4) + if (!F4) { + pr_debug("DF function 4 not found\n"); goto out; + } /* Enable instance-specific access. */ if (instance_id != DF_BROADCAST) { diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 4b54068d4f5990..501843996faae1 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -375,18 +375,18 @@ static int madera_ldo1_probe(struct platform_device *pdev) static struct platform_driver arizona_ldo1_driver = { .probe = arizona_ldo1_probe, - .remove_new = arizona_ldo1_remove, - .driver = { - .name = "arizona-ldo1", + .remove = arizona_ldo1_remove, + .driver = { + .name = "arizona-ldo1", .probe_type = PROBE_FORCE_SYNCHRONOUS, }, }; static struct platform_driver madera_ldo1_driver = { .probe = madera_ldo1_probe, - .remove_new = arizona_ldo1_remove, - .driver = { - .name = "madera-ldo1", + .remove = arizona_ldo1_remove, + .driver = { + .name = "madera-ldo1", .probe_type = PROBE_FORCE_SYNCHRONOUS, }, }; diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index a8e91d9d028b89..dca99cfb7cbb8a 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -371,8 +371,8 @@ .ops = &axp20x_ops, \ } -#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ - _vmask, _ereg, _emask) \ +#define AXP_DESC_DELAY(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _ramp_delay) \ [_family##_##_id] = { \ .name = (_match), \ .supply_name = (_supply), \ @@ -388,9 +388,15 @@ .vsel_mask = (_vmask), \ .enable_reg = (_ereg), \ .enable_mask = (_emask), \ + .ramp_delay = (_ramp_delay), \ .ops = &axp20x_ops, \ } +#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask) \ + AXP_DESC_DELAY(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, 0) + #define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \ [_family##_##_id] = { \ .name = (_match), \ @@ -419,8 +425,8 @@ .ops = &axp20x_ops_fixed \ } -#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \ - _vreg, _vmask, _ereg, _emask) \ +#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \ + _vreg, _vmask, _ereg, _emask, _ramp_delay) \ [_family##_##_id] = { \ .name = (_match), \ .supply_name = (_supply), \ @@ -436,9 +442,15 @@ .enable_mask = (_emask), \ .linear_ranges = (_ranges), \ .n_linear_ranges = ARRAY_SIZE(_ranges), \ + .ramp_delay = (_ramp_delay), \ .ops = &axp20x_ops_range, \ } +#define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \ + _vreg, _vmask, _ereg, _emask) \ + AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \ + _n_voltages, _vreg, _vmask, _ereg, _emask, 0) + static const int axp209_dcdc2_ldo3_slew_rates[] = { 1600, 800, @@ -781,21 +793,21 @@ static const struct linear_range axp717_dcdc3_ranges[] = { }; static const struct regulator_desc axp717_regulators[] = { - AXP_DESC_RANGES(AXP717, DCDC1, "dcdc1", "vin1", + AXP_DESC_RANGES_DELAY(AXP717, DCDC1, "dcdc1", "vin1", axp717_dcdc1_ranges, AXP717_DCDC1_NUM_VOLTAGES, AXP717_DCDC1_CONTROL, AXP717_DCDC_V_OUT_MASK, - AXP717_DCDC_OUTPUT_CONTROL, BIT(0)), - AXP_DESC_RANGES(AXP717, DCDC2, "dcdc2", "vin2", + AXP717_DCDC_OUTPUT_CONTROL, BIT(0), 640), + AXP_DESC_RANGES_DELAY(AXP717, DCDC2, "dcdc2", "vin2", axp717_dcdc2_ranges, AXP717_DCDC2_NUM_VOLTAGES, AXP717_DCDC2_CONTROL, AXP717_DCDC_V_OUT_MASK, - AXP717_DCDC_OUTPUT_CONTROL, BIT(1)), - AXP_DESC_RANGES(AXP717, DCDC3, "dcdc3", "vin3", + AXP717_DCDC_OUTPUT_CONTROL, BIT(1), 640), + AXP_DESC_RANGES_DELAY(AXP717, DCDC3, "dcdc3", "vin3", axp717_dcdc3_ranges, AXP717_DCDC3_NUM_VOLTAGES, AXP717_DCDC3_CONTROL, AXP717_DCDC_V_OUT_MASK, - AXP717_DCDC_OUTPUT_CONTROL, BIT(2)), - AXP_DESC(AXP717, DCDC4, "dcdc4", "vin4", 1000, 3700, 100, + AXP717_DCDC_OUTPUT_CONTROL, BIT(2), 640), + AXP_DESC_DELAY(AXP717, DCDC4, "dcdc4", "vin4", 1000, 3700, 100, AXP717_DCDC4_CONTROL, AXP717_DCDC_V_OUT_MASK, - AXP717_DCDC_OUTPUT_CONTROL, BIT(3)), + AXP717_DCDC_OUTPUT_CONTROL, BIT(3), 6400), AXP_DESC(AXP717, ALDO1, "aldo1", "aldoin", 500, 3500, 100, AXP717_ALDO1_CONTROL, AXP717_LDO_V_OUT_MASK, AXP717_LDO0_OUTPUT_CONTROL, BIT(0)), @@ -1341,6 +1353,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) step = 150; break; case AXP313A_ID: + case AXP323_ID: case AXP717_ID: case AXP15060_ID: /* The DCDC PWM frequency seems to be fixed to 3 MHz. */ @@ -1527,6 +1540,15 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) } break; + case AXP323_ID: + regmap_read(axp20x->regmap, AXP323_DCDC_MODE_CTRL2, ®); + + switch (id) { + case AXP313A_DCDC2: + return !!(reg & BIT(1)); + } + break; + default: return false; } @@ -1565,6 +1587,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) "x-powers,drive-vbus-en"); break; case AXP313A_ID: + case AXP323_ID: regulators = axp313a_regulators; nregulators = AXP313A_REG_ID_MAX; break; @@ -1597,7 +1620,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) nregulators = AXP15060_REG_ID_MAX; break; default: - dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n", + dev_err(&pdev->dev, "Unsupported AXP variant: %d\n", axp20x->variant); return -EINVAL; } diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index c7ceba56e7dc90..209beabb5c37c6 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -356,7 +356,7 @@ static struct platform_driver bd9571mwv_regulator_driver = { .pm = DEV_PM_OPS, }, .probe = bd9571mwv_regulator_probe, - .remove_new = bd9571mwv_regulator_remove, + .remove = bd9571mwv_regulator_remove, .id_table = bd9571mwv_regulator_id_table, }; module_platform_driver(bd9571mwv_regulator_driver); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 1179766811f583..8cb948a91e60d9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -497,7 +497,8 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, return -EPERM; } - if (*max_uA > rdev->constraints->max_uA) + if (*max_uA > rdev->constraints->max_uA && + rdev->constraints->max_uA) *max_uA = rdev->constraints->max_uA; if (*min_uA < rdev->constraints->min_uA) *min_uA = rdev->constraints->min_uA; @@ -1959,8 +1960,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, regulator_supply_alias(&dev, &supply); /* first do a dt based lookup */ - if (dev && dev->of_node) { - r = of_regulator_dev_lookup(dev, supply); + if (dev_of_node(dev)) { + r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply); if (!IS_ERR(r)) return r; if (PTR_ERR(r) == -EPROBE_DEFER) @@ -2642,45 +2643,6 @@ static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) return 0; } -/** - * _regulator_delay_helper - a delay helper function - * @delay: time to delay in microseconds - * - * Delay for the requested amount of time as per the guidelines in: - * - * Documentation/timers/timers-howto.rst - * - * The assumption here is that these regulator operations will never used in - * atomic context and therefore sleeping functions can be used. - */ -static void _regulator_delay_helper(unsigned int delay) -{ - unsigned int ms = delay / 1000; - unsigned int us = delay % 1000; - - if (ms > 0) { - /* - * For small enough values, handle super-millisecond - * delays in the usleep_range() call below. - */ - if (ms < 20) - us += ms * 1000; - else - msleep(ms); - } - - /* - * Give the scheduler some room to coalesce with any other - * wakeup sources. For delays shorter than 10 us, don't even - * bother setting up high-resolution timers and just busy- - * loop. - */ - if (us >= 10) - usleep_range(us, us + 100); - else - udelay(us); -} - /** * _regulator_check_status_enabled - check if regulator status can be * interpreted as "regulator is enabled" @@ -2733,7 +2695,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) s64 remaining = ktime_us_delta(end, ktime_get_boottime()); if (remaining > 0) - _regulator_delay_helper(remaining); + fsleep(remaining); } if (rdev->ena_pin) { @@ -2767,7 +2729,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) int time_remaining = delay; while (time_remaining > 0) { - _regulator_delay_helper(rdev->desc->poll_enabled_time); + fsleep(rdev->desc->poll_enabled_time); if (rdev->desc->ops->get_status) { ret = _regulator_check_status_enabled(rdev); @@ -2786,7 +2748,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev) return -ETIMEDOUT; } } else { - _regulator_delay_helper(delay); + fsleep(delay); } trace_regulator_enable_complete(rdev_get_name(rdev)); @@ -3730,7 +3692,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } /* Insert any necessary delays */ - _regulator_delay_helper(delay); + fsleep(delay); if (best_val >= 0) { unsigned long data = best_val; @@ -5681,32 +5643,43 @@ regulator_register(struct device *dev, goto clean; } - init_data = regulator_of_get_init_data(dev, regulator_desc, config, - &rdev->dev.of_node); - - /* - * Sometimes not all resources are probed already so we need to take - * that into account. This happens most the time if the ena_gpiod comes - * from a gpio extender or something else. - */ - if (PTR_ERR(init_data) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto clean; - } + if (config->init_data) { + /* + * Providing of_match means the framework is expected to parse + * DT to get the init_data. This would conflict with provided + * init_data, if set. Warn if it happens. + */ + if (regulator_desc->of_match) + dev_warn(dev, "Using provided init data - OF match ignored\n"); - /* - * We need to keep track of any GPIO descriptor coming from the - * device tree until we have handled it over to the core. If the - * config that was passed in to this function DOES NOT contain - * a descriptor, and the config after this call DOES contain - * a descriptor, we definitely got one from parsing the device - * tree. - */ - if (!cfg->ena_gpiod && config->ena_gpiod) - dangling_of_gpiod = true; - if (!init_data) { init_data = config->init_data; rdev->dev.of_node = of_node_get(config->of_node); + + } else { + init_data = regulator_of_get_init_data(dev, regulator_desc, + config, + &rdev->dev.of_node); + + /* + * Sometimes not all resources are probed already so we need to + * take that into account. This happens most the time if the + * ena_gpiod comes from a gpio extender or something else. + */ + if (PTR_ERR(init_data) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto clean; + } + + /* + * We need to keep track of any GPIO descriptor coming from the + * device tree until we have handled it over to the core. If the + * config that was passed in to this function DOES NOT contain a + * descriptor, and the config after this call DOES contain a + * descriptor, we definitely got one from parsing the device + * tree. + */ + if (!cfg->ena_gpiod && config->ena_gpiod) + dangling_of_gpiod = true; } ww_mutex_init(&rdev->mutex, ®ulator_ww_class); @@ -5747,6 +5720,12 @@ regulator_register(struct device *dev, goto wash; } + if (regulator_desc->init_cb) { + ret = regulator_desc->init_cb(rdev, config); + if (ret < 0) + goto wash; + } + if ((rdev->supply_name && !rdev->supply) && (rdev->constraints->always_on || rdev->constraints->boot_on)) { @@ -5758,13 +5737,6 @@ regulator_register(struct device *dev, resolved_early = true; } - /* perform any regulator specific init */ - if (init_data && init_data->regulator_init) { - ret = init_data->regulator_init(rdev->reg_data); - if (ret < 0) - goto wash; - } - if (config->ena_gpiod) { ret = regulator_ena_gpio_request(rdev, config); if (ret != 0) { diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 1e2d54da1b9a74..1ec2e1348891df 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -480,7 +480,7 @@ static struct platform_driver db8500_regulator_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = db8500_regulator_probe, - .remove_new = db8500_regulator_remove, + .remove = db8500_regulator_remove, }; static int __init db8500_regulator_init(void) diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 1b893cdd1aad61..36164aec30e83d 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -749,3 +749,42 @@ void *devm_regulator_irq_helper(struct device *dev, return ptr; } EXPORT_SYMBOL_GPL(devm_regulator_irq_helper); + +#if IS_ENABLED(CONFIG_OF) +static struct regulator *_devm_of_regulator_get(struct device *dev, struct device_node *node, + const char *id, int get_type) +{ + struct regulator **ptr, *regulator; + + ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + regulator = _of_regulator_get(dev, node, id, get_type); + if (!IS_ERR(regulator)) { + *ptr = regulator; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return regulator; +} + +/** + * devm_of_regulator_get_optional - Resource managed of_regulator_get_optional() + * @dev: device used for dev_printk() messages and resource lifetime management + * @node: device node for regulator "consumer" + * @id: supply name or regulator ID. + * + * Managed regulator_get_optional(). Regulators returned from this + * function are automatically regulator_put() on driver detach. See + * of_regulator_get_optional() for more information. + */ +struct regulator *devm_of_regulator_get_optional(struct device *dev, struct device_node *node, + const char *id) +{ + return _devm_of_regulator_get(dev, node, id, OPTIONAL_GET); +} +EXPORT_SYMBOL_GPL(devm_of_regulator_get_optional); +#endif diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index 5b43f802468ddb..b3d48dc38bc4a5 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -65,14 +65,25 @@ static inline struct regulator_dev *dev_to_rdev(struct device *dev) return container_of(dev, struct regulator_dev, dev); } +enum regulator_get_type { + NORMAL_GET, + EXCLUSIVE_GET, + OPTIONAL_GET, + MAX_GET_TYPE +}; + #ifdef CONFIG_OF struct regulator_dev *of_regulator_dev_lookup(struct device *dev, + struct device_node *np, const char *supply); struct regulator_init_data *regulator_of_get_init_data(struct device *dev, const struct regulator_desc *desc, struct regulator_config *config, struct device_node **node); +struct regulator *_of_regulator_get(struct device *dev, struct device_node *node, + const char *id, enum regulator_get_type get_type); + struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev, int index); @@ -82,6 +93,7 @@ bool of_check_coupling_data(struct regulator_dev *rdev); #else static inline struct regulator_dev *of_regulator_dev_lookup(struct device *dev, + struct device_node *np, const char *supply) { return ERR_PTR(-ENODEV); @@ -114,12 +126,6 @@ static inline bool of_check_coupling_data(struct regulator_dev *rdev) } #endif -enum regulator_get_type { - NORMAL_GET, - EXCLUSIVE_GET, - OPTIONAL_GET, - MAX_GET_TYPE -}; int _regulator_get_common_check(struct device *dev, const char *id, enum regulator_get_type get_type); diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 69b4afe95e66bf..7883cd160727d9 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -138,8 +138,8 @@ static int isl6271a_probe(struct i2c_client *i2c) } static const struct i2c_device_id isl6271a_id[] = { - {.name = "isl6271a", 0 }, - { }, + { .name = "isl6271a", }, + { } }; MODULE_DEVICE_TABLE(i2c, isl6271a_id); diff --git a/drivers/regulator/max5970-regulator.c b/drivers/regulator/max5970-regulator.c index 4a568b1b010711..fc14177ddf5d2b 100644 --- a/drivers/regulator/max5970-regulator.c +++ b/drivers/regulator/max5970-regulator.c @@ -485,7 +485,7 @@ static int max597x_irq_handler(int irq, struct regulator_irq_data *rid, } static int max597x_adc_range(struct regmap *regmap, const int ch, - u32 *irng, u32 *mon_rng) + int *irng, int *mon_rng) { unsigned int reg; int ret; @@ -552,7 +552,6 @@ static int max597x_setup_irq(struct device *dev, static int max597x_regulator_probe(struct platform_device *pdev) { - struct max5970_data *max597x; struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL); struct max5970_regulator *data; struct i2c_client *i2c = to_i2c_client(pdev->dev.parent); @@ -566,26 +565,18 @@ static int max597x_regulator_probe(struct platform_device *pdev) if (!regmap) return -EPROBE_DEFER; - max597x = devm_kzalloc(&i2c->dev, sizeof(struct max5970_data), GFP_KERNEL); - if (!max597x) - return -ENOMEM; - rdevs = devm_kcalloc(&i2c->dev, MAX5970_NUM_SWITCHES, sizeof(struct regulator_dev *), GFP_KERNEL); if (!rdevs) return -ENOMEM; - i2c_set_clientdata(i2c, max597x); - if (of_device_is_compatible(i2c->dev.of_node, "maxim,max5978")) - max597x->num_switches = MAX5978_NUM_SWITCHES; + num_switches = MAX5978_NUM_SWITCHES; else if (of_device_is_compatible(i2c->dev.of_node, "maxim,max5970")) - max597x->num_switches = MAX5970_NUM_SWITCHES; + num_switches = MAX5970_NUM_SWITCHES; else return -ENODEV; - num_switches = max597x->num_switches; - for (i = 0; i < num_switches; i++) { data = devm_kzalloc(&i2c->dev, sizeof(struct max5970_regulator), @@ -596,13 +587,10 @@ static int max597x_regulator_probe(struct platform_device *pdev) data->num_switches = num_switches; data->regmap = regmap; - ret = max597x_adc_range(regmap, i, &max597x->irng[i], &max597x->mon_rng[i]); + ret = max597x_adc_range(regmap, i, &data->irng, &data->mon_rng); if (ret < 0) return ret; - data->irng = max597x->irng[i]; - data->mon_rng = max597x->mon_rng[i]; - config.dev = &i2c->dev; config.driver_data = (void *)data; config.regmap = data->regmap; @@ -614,7 +602,6 @@ static int max597x_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } rdevs[i] = rdev; - max597x->shunt_micro_ohms[i] = data->shunt_micro_ohms; } if (IS_REACHABLE(CONFIG_HWMON)) { diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 3f490d81abc28f..e5b4b93c07e3f5 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -175,7 +175,7 @@ static int of_get_regulation_constraints(struct device *dev, if (!ret) constraints->enable_time = pval; - ret = of_property_read_u32(np, "regulator-uv-survival-time-ms", &pval); + ret = of_property_read_u32(np, "regulator-uv-less-critical-window-ms", &pval); if (!ret) constraints->uv_less_critical_window_ms = pval; else @@ -588,7 +588,8 @@ static struct device_node *of_get_child_regulator(struct device_node *parent, /** * of_get_regulator - get a regulator device node based on supply name - * @dev: Device pointer for the consumer (of regulator) device + * @dev: Device pointer for dev_printk() messages + * @node: Device node pointer for supply property lookup * @supply: regulator supply name * * Extract the regulator device node corresponding to the supply name. @@ -596,15 +597,16 @@ static struct device_node *of_get_child_regulator(struct device_node *parent, * Return: Pointer to the &struct device_node corresponding to the regulator * if found, or %NULL if not found. */ -static struct device_node *of_get_regulator(struct device *dev, const char *supply) +static struct device_node *of_get_regulator(struct device *dev, struct device_node *node, + const char *supply) { struct device_node *regnode = NULL; char prop_name[64]; /* 64 is max size of property name */ - dev_dbg(dev, "Looking up %s-supply from device tree\n", supply); + dev_dbg(dev, "Looking up %s-supply from device node %pOF\n", supply, node); snprintf(prop_name, 64, "%s-supply", supply); - regnode = of_parse_phandle(dev->of_node, prop_name, 0); + regnode = of_parse_phandle(node, prop_name, 0); if (regnode) return regnode; @@ -628,6 +630,7 @@ static struct regulator_dev *of_find_regulator_by_node(struct device_node *np) /** * of_regulator_dev_lookup - lookup a regulator device with device tree only * @dev: Device pointer for regulator supply lookup. + * @np: Device node pointer for regulator supply lookup. * @supply: Supply name or regulator ID. * * Return: Pointer to the &struct regulator_dev on success, or ERR_PTR() @@ -642,13 +645,13 @@ static struct regulator_dev *of_find_regulator_by_node(struct device_node *np) * * -%ENODEV if lookup fails permanently. * * -%EPROBE_DEFER if lookup could succeed in the future. */ -struct regulator_dev *of_regulator_dev_lookup(struct device *dev, +struct regulator_dev *of_regulator_dev_lookup(struct device *dev, struct device_node *np, const char *supply) { struct regulator_dev *r; struct device_node *node; - node = of_get_regulator(dev, supply); + node = of_get_regulator(dev, np, supply); if (node) { r = of_find_regulator_by_node(node); of_node_put(node); @@ -665,6 +668,42 @@ struct regulator_dev *of_regulator_dev_lookup(struct device *dev, return ERR_PTR(-ENODEV); } +struct regulator *_of_regulator_get(struct device *dev, struct device_node *node, + const char *id, enum regulator_get_type get_type) +{ + struct regulator_dev *r; + int ret; + + ret = _regulator_get_common_check(dev, id, get_type); + if (ret) + return ERR_PTR(ret); + + r = of_regulator_dev_lookup(dev, node, id); + return _regulator_get_common(r, dev, id, get_type); +} + +/** + * of_regulator_get_optional - get optional regulator via device tree lookup + * @dev: device used for dev_printk() messages + * @node: device node for regulator "consumer" + * @id: Supply name + * + * Return: pointer to struct regulator corresponding to the regulator producer, + * or PTR_ERR() encoded error number. + * + * This is intended for use by consumers that want to get a regulator + * supply directly from a device node, and can and want to deal with + * absence of such supplies. This will _not_ consider supply aliases. + * See regulator_dev_lookup(). + */ +struct regulator *of_regulator_get_optional(struct device *dev, + struct device_node *node, + const char *id) +{ + return _of_regulator_get(dev, node, id, OPTIONAL_GET); +} +EXPORT_SYMBOL_GPL(of_regulator_get_optional); + /* * Returns number of regulators coupled with rdev. */ diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index 6c343b4b9d15a8..7870722b6ee21c 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -843,26 +843,15 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = { .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, }; -static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = { +static const struct rpmh_vreg_hw_data pmic5_ftsmps525 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, .voltage_ranges = (struct linear_range[]) { REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000), + REGULATOR_LINEAR_RANGE(1376000, 268, 438, 8000), }, - .n_linear_ranges = 1, - .n_voltages = 268, - .pmic_mode_map = pmic_mode_map_pmic5_smps, - .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, -}; - -static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = { - .regulator_type = VRM, - .ops = &rpmh_regulator_vrm_ops, - .voltage_ranges = (struct linear_range[]) { - REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000), - }, - .n_linear_ranges = 1, - .n_voltages = 268, + .n_linear_ranges = 2, + .n_voltages = 439, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, }; @@ -1190,12 +1179,12 @@ static const struct rpmh_vreg_init_data pm8550_vreg_data[] = { }; static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_lv, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_mv, "vdd-s6"), + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), @@ -1203,14 +1192,14 @@ static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = { }; static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"), + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), @@ -1218,14 +1207,14 @@ static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = { }; static const struct rpmh_vreg_init_data pmc8380_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"), + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), @@ -1409,16 +1398,16 @@ static const struct rpmh_vreg_init_data pmx65_vreg_data[] = { }; static const struct rpmh_vreg_init_data pmx75_vreg_data[] = { - RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), - RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), - RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), - RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"), - RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), - RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"), - RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"), - RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"), - RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525_lv, "vdd-s9"), - RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525_lv, "vdd-s10"), + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525, "vdd-s8"), + RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525, "vdd-s9"), + RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525, "vdd-s10"), RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-18"), RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 28e7ce60cb617c..25ed9f713974ba 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -11,7 +11,7 @@ #include #include -struct qcom_smd_rpm *smd_vreg_rpm; +static struct qcom_smd_rpm *smd_vreg_rpm; struct qcom_rpm_reg { struct device *dev; diff --git a/drivers/regulator/renesas-usb-vbus-regulator.c b/drivers/regulator/renesas-usb-vbus-regulator.c index 4eceb6b54497a6..dec7cac5e8d594 100644 --- a/drivers/regulator/renesas-usb-vbus-regulator.c +++ b/drivers/regulator/renesas-usb-vbus-regulator.c @@ -49,13 +49,10 @@ static int rzg2l_usb_vbus_regulator_probe(struct platform_device *pdev) return dev_err_probe(dev, -ENODEV, "regulator node not found\n"); rdev = devm_regulator_register(dev, &rzg2l_usb_vbus_rdesc, &config); - if (IS_ERR(rdev)) { - of_node_put(config.of_node); + of_node_put(config.of_node); + if (IS_ERR(rdev)) return dev_err_probe(dev, PTR_ERR(rdev), "not able to register vbus regulator\n"); - } - - of_node_put(config.of_node); return 0; } diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 01a8d04879184c..7d82bd1b36dfcf 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Regulator driver for Rockchip RK805/RK808/RK818 + * Regulator driver for Rockchip RK80x and RK81x PMIC series * * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd * Copyright (c) 2021 Rockchip Electronics Co., Ltd. @@ -23,7 +23,7 @@ #include #include -/* Field Definitions */ +/* Field definitions */ #define RK808_BUCK_VSEL_MASK 0x3f #define RK808_BUCK4_VSEL_MASK 0xf #define RK808_LDO_VSEL_MASK 0x1f @@ -1831,9 +1831,8 @@ static const struct regulator_desc rk818_reg[] = { RK818_DCDC_EN_REG, BIT(7)), }; -static int rk808_regulator_dt_parse_pdata(struct device *dev, - struct regmap *map, - struct rk808_regulator_data *pdata) +static int rk808_regulator_dt_parse_pdata(struct device *dev, struct regmap *map, + struct rk808_regulator_data *pdata) { struct device_node *np; int tmp, ret = 0, i; @@ -1844,23 +1843,21 @@ static int rk808_regulator_dt_parse_pdata(struct device *dev, for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) { pdata->dvs_gpio[i] = - devm_gpiod_get_index_optional(dev, "dvs", i, - GPIOD_OUT_LOW); + devm_gpiod_get_index_optional(dev, "dvs", i, GPIOD_OUT_LOW); if (IS_ERR(pdata->dvs_gpio[i])) { - ret = PTR_ERR(pdata->dvs_gpio[i]); - dev_err(dev, "failed to get dvs%d gpio (%d)\n", i, ret); + ret = dev_err_probe(dev, PTR_ERR(pdata->dvs_gpio[i]), + "failed to get dvs%d gpio\n", i); goto dt_parse_end; } if (!pdata->dvs_gpio[i]) { - dev_info(dev, "there is no dvs%d gpio\n", i); + dev_dbg(dev, "there is no dvs%d gpio\n", i); continue; } tmp = i ? RK808_DVS2_POL : RK808_DVS1_POL; ret = regmap_update_bits(map, RK808_IO_POL_REG, tmp, - gpiod_is_active_low(pdata->dvs_gpio[i]) ? - 0 : tmp); + gpiod_is_active_low(pdata->dvs_gpio[i]) ? 0 : tmp); } dt_parse_end: @@ -1889,12 +1886,6 @@ static int rk808_regulator_probe(struct platform_device *pdev) if (!pdata) return -ENOMEM; - ret = rk808_regulator_dt_parse_pdata(&pdev->dev, regmap, pdata); - if (ret < 0) - return ret; - - platform_set_drvdata(pdev, pdata); - switch (rk808->variant) { case RK805_ID: regulators = rk805_reg; @@ -1905,6 +1896,11 @@ static int rk808_regulator_probe(struct platform_device *pdev) nregulators = ARRAY_SIZE(rk806_reg); break; case RK808_ID: + /* DVS0/1 GPIOs are supported on the RK808 only */ + ret = rk808_regulator_dt_parse_pdata(&pdev->dev, regmap, pdata); + if (ret < 0) + return ret; + regulators = rk808_reg; nregulators = RK808_NUM_REGULATORS; break; @@ -1925,11 +1921,12 @@ static int rk808_regulator_probe(struct platform_device *pdev) nregulators = RK818_NUM_REGULATORS; break; default: - dev_err(&pdev->dev, "unsupported RK8XX ID %lu\n", - rk808->variant); - return -EINVAL; + return dev_err_probe(&pdev->dev, -EINVAL, + "unsupported RK8xx ID %lu\n", rk808->variant); } + platform_set_drvdata(pdev, pdata); + config.dev = &pdev->dev; config.driver_data = pdata; config.regmap = regmap; @@ -1956,7 +1953,7 @@ static struct platform_driver rk808_regulator_driver = { module_platform_driver(rk808_regulator_driver); -MODULE_DESCRIPTION("regulator driver for the RK805/RK808/RK818 series PMICs"); +MODULE_DESCRIPTION("Rockchip RK80x/RK81x PMIC series regulator driver"); MODULE_AUTHOR("Tony xie "); MODULE_AUTHOR("Chris Zhong "); MODULE_AUTHOR("Zhang Qing "); diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c index 40855105dd3357..a85ea94f067307 100644 --- a/drivers/regulator/stm32-vrefbuf.c +++ b/drivers/regulator/stm32-vrefbuf.c @@ -280,7 +280,7 @@ MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match); static struct platform_driver stm32_vrefbuf_driver = { .probe = stm32_vrefbuf_probe, - .remove_new = stm32_vrefbuf_remove, + .remove = stm32_vrefbuf_remove, .driver = { .name = "stm32-vrefbuf", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c index 5f868042392fd8..74939b7fcd8185 100644 --- a/drivers/regulator/uniphier-regulator.c +++ b/drivers/regulator/uniphier-regulator.c @@ -207,7 +207,7 @@ MODULE_DEVICE_TABLE(of, uniphier_regulator_match); static struct platform_driver uniphier_regulator_driver = { .probe = uniphier_regulator_probe, - .remove_new = uniphier_regulator_remove, + .remove = uniphier_regulator_remove, .driver = { .name = "uniphier-regulator", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index 6153d0295b6de7..72bb5ffb49a8ce 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -210,7 +210,7 @@ MODULE_DEVICE_TABLE(of, regulator_userspace_consumer_of_match); static struct platform_driver regulator_userspace_consumer_driver = { .probe = regulator_userspace_consumer_probe, - .remove_new = regulator_userspace_consumer_remove, + .remove = regulator_userspace_consumer_remove, .driver = { .name = "reg-userspace-consumer", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 0a0ee186c6aff3..218a0d66a15282 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -357,7 +357,7 @@ static void regulator_virtual_remove(struct platform_device *pdev) static struct platform_driver regulator_virtual_consumer_driver = { .probe = regulator_virtual_probe, - .remove_new = regulator_virtual_remove, + .remove = regulator_virtual_remove, .driver = { .name = "reg-virt-consumer", .probe_type = PROBE_PREFER_ASYNCHRONOUS, diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 9939a5d2cbec0a..d09864bae5ef4f 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1304,9 +1304,9 @@ EXPORT_SYMBOL_GPL(wm8350_register_led); static struct platform_driver wm8350_regulator_driver = { .probe = wm8350_regulator_probe, - .remove_new = wm8350_regulator_remove, - .driver = { - .name = "wm8350-regulator", + .remove = wm8350_regulator_remove, + .driver = { + .name = "wm8350-regulator", .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 955e4e38477e6f..83962a114dc9fd 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -329,7 +329,8 @@ config STM32_RPROC config TI_K3_DSP_REMOTEPROC tristate "TI K3 DSP remoteproc support" - depends on ARCH_K3 + depends on ARCH_K3 || COMPILE_TEST + depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) depends on OMAP2PLUS_MBOX help Say m here to support TI's C66x and C71x DSP remote processor @@ -341,9 +342,9 @@ config TI_K3_DSP_REMOTEPROC config TI_K3_M4_REMOTEPROC tristate "TI K3 M4 remoteproc support" - depends on ARCH_OMAP2PLUS || ARCH_K3 - select MAILBOX - select OMAP2PLUS_MBOX + depends on ARCH_K3 || COMPILE_TEST + depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) + depends on OMAP2PLUS_MBOX help Say m here to support TI's M4 remote processor subsystems on various TI K3 family of SoCs through the remote processor @@ -354,7 +355,8 @@ config TI_K3_M4_REMOTEPROC config TI_K3_R5_REMOTEPROC tristate "TI K3 R5 remoteproc support" - depends on ARCH_K3 + depends on ARCH_K3 || COMPILE_TEST + depends on TI_SCI_PROTOCOL || (COMPILE_TEST && TI_SCI_PROTOCOL=n) depends on OMAP2PLUS_MBOX help Say m here to support TI's R5F remote processor subsystems diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c index 8770d0cf1255f8..93031f0867d106 100644 --- a/drivers/remoteproc/da8xx_remoteproc.c +++ b/drivers/remoteproc/da8xx_remoteproc.c @@ -251,10 +251,8 @@ static int da8xx_rproc_probe(struct platform_device *pdev) return irq; irq_data = irq_get_irq_data(irq); - if (!irq_data) { - dev_err(dev, "irq_get_irq_data(%d): NULL\n", irq); - return -EINVAL; - } + if (!irq_data) + return dev_err_probe(dev, -EINVAL, "irq_get_irq_data(%d): NULL\n", irq); bootreg = devm_platform_ioremap_resource_byname(pdev, "host1cfg"); if (IS_ERR(bootreg)) @@ -265,28 +263,17 @@ static int da8xx_rproc_probe(struct platform_device *pdev) return PTR_ERR(chipsig); dsp_clk = devm_clk_get(dev, NULL); - if (IS_ERR(dsp_clk)) { - dev_err(dev, "clk_get error: %ld\n", PTR_ERR(dsp_clk)); - - return PTR_ERR(dsp_clk); - } + if (IS_ERR(dsp_clk)) + return dev_err_probe(dev, PTR_ERR(dsp_clk), "clk_get error\n"); dsp_reset = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR(dsp_reset)) { - if (PTR_ERR(dsp_reset) != -EPROBE_DEFER) - dev_err(dev, "unable to get reset control: %ld\n", - PTR_ERR(dsp_reset)); - - return PTR_ERR(dsp_reset); - } + if (IS_ERR(dsp_reset)) + return dev_err_probe(dev, PTR_ERR(dsp_reset), "unable to get reset control\n"); if (dev->of_node) { ret = of_reserved_mem_device_init(dev); - if (ret) { - dev_err(dev, "device does not have specific CMA pool: %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "device does not have specific CMA pool\n"); } rproc = rproc_alloc(dev, "dsp", &da8xx_rproc_ops, da8xx_fw_name, @@ -378,7 +365,7 @@ MODULE_DEVICE_TABLE(of, davinci_rproc_of_match); static struct platform_driver da8xx_rproc_driver = { .probe = da8xx_rproc_probe, - .remove_new = da8xx_rproc_remove, + .remove = da8xx_rproc_remove, .driver = { .name = "davinci-rproc", .of_match_table = of_match_ptr(davinci_rproc_of_match), diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c index 376187ad5754cd..ea5024919c2ffc 100644 --- a/drivers/remoteproc/imx_dsp_rproc.c +++ b/drivers/remoteproc/imx_dsp_rproc.c @@ -1258,7 +1258,7 @@ MODULE_DEVICE_TABLE(of, imx_dsp_rproc_of_match); static struct platform_driver imx_dsp_rproc_driver = { .probe = imx_dsp_rproc_probe, - .remove_new = imx_dsp_rproc_remove, + .remove = imx_dsp_rproc_remove, .driver = { .name = "imx-dsp-rproc", .of_match_table = imx_dsp_rproc_of_match, diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c index 800015ff7ff923..74299af1d7f10a 100644 --- a/drivers/remoteproc/imx_rproc.c +++ b/drivers/remoteproc/imx_rproc.c @@ -1198,7 +1198,7 @@ MODULE_DEVICE_TABLE(of, imx_rproc_of_match); static struct platform_driver imx_rproc_driver = { .probe = imx_rproc_probe, - .remove_new = imx_rproc_remove, + .remove = imx_rproc_remove, .driver = { .name = "imx-rproc", .of_match_table = imx_rproc_of_match, diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c index 8f0f7a4cfef262..6e54093d173231 100644 --- a/drivers/remoteproc/keystone_remoteproc.c +++ b/drivers/remoteproc/keystone_remoteproc.c @@ -490,7 +490,7 @@ MODULE_DEVICE_TABLE(of, keystone_rproc_of_match); static struct platform_driver keystone_rproc_driver = { .probe = keystone_rproc_probe, - .remove_new = keystone_rproc_remove, + .remove = keystone_rproc_remove, .driver = { .name = "keystone-rproc", .of_match_table = keystone_rproc_of_match, diff --git a/drivers/remoteproc/meson_mx_ao_arc.c b/drivers/remoteproc/meson_mx_ao_arc.c index f6744b53832308..7dfdf11b00368e 100644 --- a/drivers/remoteproc/meson_mx_ao_arc.c +++ b/drivers/remoteproc/meson_mx_ao_arc.c @@ -246,7 +246,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_ao_arc_rproc_match); static struct platform_driver meson_mx_ao_arc_rproc_driver = { .probe = meson_mx_ao_arc_rproc_probe, - .remove_new = meson_mx_ao_arc_rproc_remove, + .remove = meson_mx_ao_arc_rproc_remove, .driver = { .name = "meson-mx-ao-arc-rproc", .of_match_table = meson_mx_ao_arc_rproc_match, diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c index e744c07507eede..0f4a7065d0bd9e 100644 --- a/drivers/remoteproc/mtk_scp.c +++ b/drivers/remoteproc/mtk_scp.c @@ -1521,7 +1521,7 @@ MODULE_DEVICE_TABLE(of, mtk_scp_of_match); static struct platform_driver mtk_scp_driver = { .probe = scp_probe, - .remove_new = scp_remove, + .remove = scp_remove, .driver = { .name = "mtk-scp", .of_match_table = mtk_scp_of_match, diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 327f0c7ee3d6ba..1656574b73175a 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -1132,7 +1132,7 @@ static struct platform_driver pru_rproc_driver = { .suppress_bind_attrs = true, }, .probe = pru_rproc_probe, - .remove_new = pru_rproc_remove, + .remove = pru_rproc_remove, }; module_platform_driver(pru_rproc_driver); diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c index 572dcb0f055b76..94af77baa7a1c5 100644 --- a/drivers/remoteproc/qcom_q6v5_adsp.c +++ b/drivers/remoteproc/qcom_q6v5_adsp.c @@ -534,15 +534,11 @@ static const struct rproc_ops adsp_ops = { static int adsp_init_clock(struct qcom_adsp *adsp, const char **clk_ids) { int num_clks = 0; - int i, ret; + int i; adsp->xo = devm_clk_get(adsp->dev, "xo"); - if (IS_ERR(adsp->xo)) { - ret = PTR_ERR(adsp->xo); - if (ret != -EPROBE_DEFER) - dev_err(adsp->dev, "failed to get xo clock"); - return ret; - } + if (IS_ERR(adsp->xo)) + return dev_err_probe(adsp->dev, PTR_ERR(adsp->xo), "failed to get xo clock"); for (i = 0; clk_ids[i]; i++) num_clks++; @@ -708,10 +704,9 @@ static int adsp_probe(struct platform_device *pdev) return ret; ret = qcom_rproc_pds_attach(adsp, desc->pd_names, desc->num_pds); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to attach proxy power domains\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to attach proxy power domains\n"); ret = adsp_init_reset(adsp); if (ret) @@ -734,15 +729,22 @@ static int adsp_probe(struct platform_device *pdev) desc->ssctl_id); if (IS_ERR(adsp->sysmon)) { ret = PTR_ERR(adsp->sysmon); - goto disable_pm; + goto deinit_remove_glink_pdm_ssr; } ret = rproc_add(rproc); if (ret) - goto disable_pm; + goto remove_sysmon; return 0; +remove_sysmon: + qcom_remove_sysmon_subdev(adsp->sysmon); +deinit_remove_glink_pdm_ssr: + qcom_q6v5_deinit(&adsp->q6v5); + qcom_remove_glink_subdev(rproc, &adsp->glink_subdev); + qcom_remove_pdm_subdev(rproc, &adsp->pdm_subdev); + qcom_remove_ssr_subdev(rproc, &adsp->ssr_subdev); disable_pm: qcom_rproc_pds_detach(adsp); @@ -840,7 +842,7 @@ MODULE_DEVICE_TABLE(of, adsp_of_match); static struct platform_driver adsp_pil_driver = { .probe = adsp_probe, - .remove_new = adsp_remove, + .remove = adsp_remove, .driver = { .name = "qcom_q6v5_adsp", .of_match_table = adsp_of_match, diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 2a42215ce8e07b..e78bd986dc3f25 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -261,7 +261,6 @@ enum { static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, const struct qcom_mss_reg_res *reg_res) { - int rc; int i; if (!reg_res) @@ -269,13 +268,10 @@ static int q6v5_regulator_init(struct device *dev, struct reg_info *regs, for (i = 0; reg_res[i].supply; i++) { regs[i].reg = devm_regulator_get(dev, reg_res[i].supply); - if (IS_ERR(regs[i].reg)) { - rc = PTR_ERR(regs[i].reg); - if (rc != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s\n regulator", - reg_res[i].supply); - return rc; - } + if (IS_ERR(regs[i].reg)) + return dev_err_probe(dev, PTR_ERR(regs[i].reg), + "Failed to get %s\n regulator", + reg_res[i].supply); regs[i].uV = reg_res[i].uV; regs[i].uA = reg_res[i].uA; @@ -1162,6 +1158,9 @@ static int q6v5_mba_load(struct q6v5 *qproc) goto disable_active_clks; } + if (qproc->has_mba_logs) + qcom_pil_info_store("mba", qproc->mba_phys, MBA_LOG_SIZE); + writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG); if (qproc->dp_size) { writel(qproc->mba_phys + SZ_1M, qproc->rmb_base + RMB_PMI_CODE_START_REG); @@ -1172,9 +1171,6 @@ static int q6v5_mba_load(struct q6v5 *qproc) if (ret) goto reclaim_mba; - if (qproc->has_mba_logs) - qcom_pil_info_store("mba", qproc->mba_phys, MBA_LOG_SIZE); - ret = q6v5_rmb_mba_wait(qproc, 0, 5000); if (ret == -ETIMEDOUT) { dev_err(qproc->dev, "MBA boot timed out\n"); @@ -1813,14 +1809,10 @@ static int q6v5_init_clocks(struct device *dev, struct clk **clks, for (i = 0; clk_names[i]; i++) { clks[i] = devm_clk_get(dev, clk_names[i]); - if (IS_ERR(clks[i])) { - int rc = PTR_ERR(clks[i]); - - if (rc != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s clock\n", - clk_names[i]); - return rc; - } + if (IS_ERR(clks[i])) + return dev_err_probe(dev, PTR_ERR(clks[i]), + "Failed to get %s clock\n", + clk_names[i]); } return i; @@ -2028,42 +2020,32 @@ static int q6v5_probe(struct platform_device *pdev) ret = q6v5_init_clocks(&pdev->dev, qproc->proxy_clks, desc->proxy_clk_names); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get proxy clocks.\n"); + if (ret < 0) return ret; - } qproc->proxy_clk_count = ret; ret = q6v5_init_clocks(&pdev->dev, qproc->reset_clks, desc->reset_clk_names); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get reset clocks.\n"); + if (ret < 0) return ret; - } qproc->reset_clk_count = ret; ret = q6v5_init_clocks(&pdev->dev, qproc->active_clks, desc->active_clk_names); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get active clocks.\n"); + if (ret < 0) return ret; - } qproc->active_clk_count = ret; ret = q6v5_regulator_init(&pdev->dev, qproc->proxy_regs, desc->proxy_supply); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get proxy regulators.\n"); + if (ret < 0) return ret; - } qproc->proxy_reg_count = ret; ret = q6v5_regulator_init(&pdev->dev, qproc->active_regs, desc->active_supply); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get active regulators.\n"); + if (ret < 0) return ret; - } qproc->active_reg_count = ret; ret = q6v5_pds_attach(&pdev->dev, qproc->proxy_pds, @@ -2073,10 +2055,8 @@ static int q6v5_probe(struct platform_device *pdev) ret = q6v5_regulator_init(&pdev->dev, qproc->fallback_proxy_regs, desc->fallback_proxy_supply); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to get fallback proxy regulators.\n"); + if (ret < 0) return ret; - } qproc->fallback_proxy_reg_count = ret; } else if (ret < 0) { dev_err(&pdev->dev, "Failed to init power domains\n"); @@ -2533,7 +2513,7 @@ MODULE_DEVICE_TABLE(of, q6v5_of_match); static struct platform_driver q6v5_driver = { .probe = q6v5_probe, - .remove_new = q6v5_remove, + .remove = q6v5_remove, .driver = { .name = "qcom-q6v5-mss", .of_match_table = q6v5_of_match, diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index ef82835e98a4ef..97c4bdd9222a8d 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -453,24 +453,16 @@ static const struct rproc_ops adsp_minidump_ops = { static int adsp_init_clock(struct qcom_adsp *adsp) { - int ret; - adsp->xo = devm_clk_get(adsp->dev, "xo"); - if (IS_ERR(adsp->xo)) { - ret = PTR_ERR(adsp->xo); - if (ret != -EPROBE_DEFER) - dev_err(adsp->dev, "failed to get xo clock"); - return ret; - } + if (IS_ERR(adsp->xo)) + return dev_err_probe(adsp->dev, PTR_ERR(adsp->xo), + "failed to get xo clock"); + adsp->aggre2_clk = devm_clk_get_optional(adsp->dev, "aggre2"); - if (IS_ERR(adsp->aggre2_clk)) { - ret = PTR_ERR(adsp->aggre2_clk); - if (ret != -EPROBE_DEFER) - dev_err(adsp->dev, - "failed to get aggre2 clock"); - return ret; - } + if (IS_ERR(adsp->aggre2_clk)) + return dev_err_probe(adsp->dev, PTR_ERR(adsp->aggre2_clk), + "failed to get aggre2 clock"); return 0; } @@ -716,7 +708,7 @@ static int adsp_probe(struct platform_device *pdev) if (desc->minidump_id) ops = &adsp_minidump_ops; - rproc = devm_rproc_alloc(&pdev->dev, pdev->name, ops, fw_name, sizeof(*adsp)); + rproc = devm_rproc_alloc(&pdev->dev, desc->sysmon_name, ops, fw_name, sizeof(*adsp)); if (!rproc) { dev_err(&pdev->dev, "unable to allocate remoteproc\n"); @@ -759,16 +751,16 @@ static int adsp_probe(struct platform_device *pdev) ret = adsp_init_clock(adsp); if (ret) - goto free_rproc; + goto unassign_mem; ret = adsp_init_regulator(adsp); if (ret) - goto free_rproc; + goto unassign_mem; ret = adsp_pds_attach(&pdev->dev, adsp->proxy_pds, desc->proxy_pd_names); if (ret < 0) - goto free_rproc; + goto unassign_mem; adsp->proxy_pd_count = ret; ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem, desc->load_state, @@ -784,18 +776,28 @@ static int adsp_probe(struct platform_device *pdev) desc->ssctl_id); if (IS_ERR(adsp->sysmon)) { ret = PTR_ERR(adsp->sysmon); - goto detach_proxy_pds; + goto deinit_remove_pdm_smd_glink; } qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name); ret = rproc_add(rproc); if (ret) - goto detach_proxy_pds; + goto remove_ssr_sysmon; return 0; +remove_ssr_sysmon: + qcom_remove_ssr_subdev(rproc, &adsp->ssr_subdev); + qcom_remove_sysmon_subdev(adsp->sysmon); +deinit_remove_pdm_smd_glink: + qcom_remove_pdm_subdev(rproc, &adsp->pdm_subdev); + qcom_remove_smd_subdev(rproc, &adsp->smd_subdev); + qcom_remove_glink_subdev(rproc, &adsp->glink_subdev); + qcom_q6v5_deinit(&adsp->q6v5); detach_proxy_pds: adsp_pds_detach(adsp, adsp->proxy_pds, adsp->proxy_pd_count); +unassign_mem: + adsp_unassign_memory_region(adsp); free_rproc: device_init_wakeup(adsp->dev, false); @@ -907,6 +909,7 @@ static const struct adsp_data sm8250_adsp_resource = { .crash_reason_smem = 423, .firmware_name = "adsp.mdt", .pas_id = 1, + .minidump_id = 5, .auto_boot = true, .proxy_pd_names = (char*[]){ "lcx", @@ -1124,6 +1127,7 @@ static const struct adsp_data sm8350_cdsp_resource = { .crash_reason_smem = 601, .firmware_name = "cdsp.mdt", .pas_id = 18, + .minidump_id = 7, .auto_boot = true, .proxy_pd_names = (char*[]){ "cx", @@ -1344,7 +1348,7 @@ static const struct adsp_data sc7280_wpss_resource = { .crash_reason_smem = 626, .firmware_name = "wpss.mdt", .pas_id = 6, - .auto_boot = true, + .auto_boot = false, .proxy_pd_names = (char*[]){ "cx", "mx", @@ -1421,6 +1425,7 @@ static const struct of_device_id adsp_of_match[] = { { .compatible = "qcom,sa8775p-cdsp1-pas", .data = &sa8775p_cdsp1_resource}, { .compatible = "qcom,sa8775p-gpdsp0-pas", .data = &sa8775p_gpdsp0_resource}, { .compatible = "qcom,sa8775p-gpdsp1-pas", .data = &sa8775p_gpdsp1_resource}, + { .compatible = "qcom,sar2130p-adsp-pas", .data = &sm8350_adsp_resource}, { .compatible = "qcom,sc7180-adsp-pas", .data = &sm8250_adsp_resource}, { .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init}, { .compatible = "qcom,sc7280-adsp-pas", .data = &sm8350_adsp_resource}, @@ -1477,7 +1482,7 @@ MODULE_DEVICE_TABLE(of, adsp_of_match); static struct platform_driver adsp_driver = { .probe = adsp_probe, - .remove_new = adsp_remove, + .remove = adsp_remove, .driver = { .name = "qcom_q6v5_pas", .of_match_table = adsp_of_match, diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c index e913dabae99245..93648734a2f254 100644 --- a/drivers/remoteproc/qcom_q6v5_wcss.c +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -902,90 +902,58 @@ static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss) static int q6v5_wcss_init_clock(struct q6v5_wcss *wcss) { - int ret; - wcss->xo = devm_clk_get(wcss->dev, "xo"); - if (IS_ERR(wcss->xo)) { - ret = PTR_ERR(wcss->xo); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get xo clock"); - return ret; - } + if (IS_ERR(wcss->xo)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->xo), + "failed to get xo clock"); wcss->gcc_abhs_cbcr = devm_clk_get(wcss->dev, "gcc_abhs_cbcr"); - if (IS_ERR(wcss->gcc_abhs_cbcr)) { - ret = PTR_ERR(wcss->gcc_abhs_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get gcc abhs clock"); - return ret; - } + if (IS_ERR(wcss->gcc_abhs_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->gcc_abhs_cbcr), + "failed to get gcc abhs clock"); wcss->gcc_axim_cbcr = devm_clk_get(wcss->dev, "gcc_axim_cbcr"); - if (IS_ERR(wcss->gcc_axim_cbcr)) { - ret = PTR_ERR(wcss->gcc_axim_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get gcc axim clock\n"); - return ret; - } + if (IS_ERR(wcss->gcc_axim_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->gcc_axim_cbcr), + "failed to get gcc axim clock\n"); wcss->ahbfabric_cbcr_clk = devm_clk_get(wcss->dev, "lcc_ahbfabric_cbc"); - if (IS_ERR(wcss->ahbfabric_cbcr_clk)) { - ret = PTR_ERR(wcss->ahbfabric_cbcr_clk); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get ahbfabric clock\n"); - return ret; - } + if (IS_ERR(wcss->ahbfabric_cbcr_clk)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->ahbfabric_cbcr_clk), + "failed to get ahbfabric clock\n"); wcss->lcc_csr_cbcr = devm_clk_get(wcss->dev, "tcsr_lcc_cbc"); - if (IS_ERR(wcss->lcc_csr_cbcr)) { - ret = PTR_ERR(wcss->lcc_csr_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get csr cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->lcc_csr_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->lcc_csr_cbcr), + "failed to get csr cbcr clk\n"); wcss->ahbs_cbcr = devm_clk_get(wcss->dev, "lcc_abhs_cbc"); - if (IS_ERR(wcss->ahbs_cbcr)) { - ret = PTR_ERR(wcss->ahbs_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get ahbs_cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->ahbs_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->ahbs_cbcr), + "failed to get ahbs_cbcr clk\n"); wcss->tcm_slave_cbcr = devm_clk_get(wcss->dev, "lcc_tcm_slave_cbc"); - if (IS_ERR(wcss->tcm_slave_cbcr)) { - ret = PTR_ERR(wcss->tcm_slave_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get tcm cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->tcm_slave_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->tcm_slave_cbcr), + "failed to get tcm cbcr clk\n"); wcss->qdsp6ss_abhm_cbcr = devm_clk_get(wcss->dev, "lcc_abhm_cbc"); - if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) { - ret = PTR_ERR(wcss->qdsp6ss_abhm_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get abhm cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->qdsp6ss_abhm_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->qdsp6ss_abhm_cbcr), + "failed to get abhm cbcr clk\n"); wcss->qdsp6ss_axim_cbcr = devm_clk_get(wcss->dev, "lcc_axim_cbc"); - if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) { - ret = PTR_ERR(wcss->qdsp6ss_axim_cbcr); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get axim cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->qdsp6ss_axim_cbcr)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->qdsp6ss_axim_cbcr), + "failed to get axim cbcr clk\n"); wcss->lcc_bcr_sleep = devm_clk_get(wcss->dev, "lcc_bcr_sleep"); - if (IS_ERR(wcss->lcc_bcr_sleep)) { - ret = PTR_ERR(wcss->lcc_bcr_sleep); - if (ret != -EPROBE_DEFER) - dev_err(wcss->dev, "failed to get bcr cbcr clk\n"); - return ret; - } + if (IS_ERR(wcss->lcc_bcr_sleep)) + return dev_err_probe(wcss->dev, PTR_ERR(wcss->lcc_bcr_sleep), + "failed to get bcr cbcr clk\n"); return 0; } @@ -1021,7 +989,6 @@ static int q6v5_wcss_probe(struct platform_device *pdev) wcss = rproc->priv; wcss->dev = &pdev->dev; - wcss->version = desc->version; wcss->version = desc->version; wcss->requires_force_stop = desc->requires_force_stop; @@ -1056,18 +1023,33 @@ static int q6v5_wcss_probe(struct platform_device *pdev) qcom_add_pdm_subdev(rproc, &wcss->pdm_subdev); qcom_add_ssr_subdev(rproc, &wcss->ssr_subdev, "q6wcss"); - if (desc->ssctl_id) + if (desc->ssctl_id) { wcss->sysmon = qcom_add_sysmon_subdev(rproc, desc->sysmon_name, desc->ssctl_id); + if (IS_ERR(wcss->sysmon)) { + ret = PTR_ERR(wcss->sysmon); + goto deinit_remove_subdevs; + } + } ret = rproc_add(rproc); if (ret) - return ret; + goto remove_sysmon_subdev; platform_set_drvdata(pdev, rproc); return 0; + +remove_sysmon_subdev: + if (desc->ssctl_id) + qcom_remove_sysmon_subdev(wcss->sysmon); +deinit_remove_subdevs: + qcom_q6v5_deinit(&wcss->q6v5); + qcom_remove_glink_subdev(rproc, &wcss->glink_subdev); + qcom_remove_pdm_subdev(rproc, &wcss->pdm_subdev); + qcom_remove_ssr_subdev(rproc, &wcss->ssr_subdev); + return ret; } static void q6v5_wcss_remove(struct platform_device *pdev) @@ -1111,7 +1093,7 @@ MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match); static struct platform_driver q6v5_wcss_driver = { .probe = q6v5_wcss_probe, - .remove_new = q6v5_wcss_remove, + .remove = q6v5_wcss_remove, .driver = { .name = "qcom-q6v5-wcss-pil", .of_match_table = q6v5_wcss_of_match, diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c index a7bb9da27029db..5b5664603eed29 100644 --- a/drivers/remoteproc/qcom_wcnss.c +++ b/drivers/remoteproc/qcom_wcnss.c @@ -682,7 +682,7 @@ MODULE_DEVICE_TABLE(of, wcnss_of_match); static struct platform_driver wcnss_driver = { .probe = wcnss_probe, - .remove_new = wcnss_remove, + .remove = wcnss_remove, .driver = { .name = "qcom-wcnss-pil", .of_match_table = wcnss_of_match, diff --git a/drivers/remoteproc/qcom_wcnss_iris.c b/drivers/remoteproc/qcom_wcnss_iris.c index dd36fd077911af..b989718776bdb5 100644 --- a/drivers/remoteproc/qcom_wcnss_iris.c +++ b/drivers/remoteproc/qcom_wcnss_iris.c @@ -155,9 +155,8 @@ struct qcom_iris *qcom_iris_probe(struct device *parent, bool *use_48mhz_xo) iris->xo_clk = devm_clk_get(&iris->dev, "xo"); if (IS_ERR(iris->xo_clk)) { - ret = PTR_ERR(iris->xo_clk); - if (ret != -EPROBE_DEFER) - dev_err(&iris->dev, "failed to acquire xo clk\n"); + ret = dev_err_probe(&iris->dev, PTR_ERR(iris->xo_clk), + "failed to acquire xo clk\n"); goto err_device_del; } diff --git a/drivers/remoteproc/rcar_rproc.c b/drivers/remoteproc/rcar_rproc.c index cc17e8421f65bf..921d853594f42f 100644 --- a/drivers/remoteproc/rcar_rproc.c +++ b/drivers/remoteproc/rcar_rproc.c @@ -214,7 +214,7 @@ MODULE_DEVICE_TABLE(of, rcar_rproc_of_match); static struct platform_driver rcar_rproc_driver = { .probe = rcar_rproc_probe, - .remove_new = rcar_rproc_remove, + .remove = rcar_rproc_remove, .driver = { .name = "rcar-rproc", .of_match_table = rcar_rproc_of_match, diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index f276956f2c5cec..eb66f78ec8b774 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -109,10 +109,10 @@ static int rproc_enable_iommu(struct rproc *rproc) return 0; } - domain = iommu_domain_alloc(dev->bus); - if (!domain) { + domain = iommu_paging_domain_alloc(dev); + if (IS_ERR(domain)) { dev_err(dev, "can't alloc iommu domain\n"); - return -ENOMEM; + return PTR_ERR(domain); } iommu_set_fault_handler(domain, rproc_iommu_fault, rproc); diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index d3f39009b28ed2..25a655f33ec0ed 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -593,7 +593,7 @@ static void rproc_virtio_remove(struct platform_device *pdev) /* Platform driver */ static struct platform_driver rproc_virtio_driver = { .probe = rproc_virtio_probe, - .remove_new = rproc_virtio_remove, + .remove = rproc_virtio_remove, .driver = { .name = "rproc-virtio", }, diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c index 1340be9d011017..5df99bae7131a8 100644 --- a/drivers/remoteproc/st_remoteproc.c +++ b/drivers/remoteproc/st_remoteproc.c @@ -457,7 +457,7 @@ static void st_rproc_remove(struct platform_device *pdev) static struct platform_driver st_rproc_driver = { .probe = st_rproc_probe, - .remove_new = st_rproc_remove, + .remove = st_rproc_remove, .driver = { .name = "st-rproc", .of_match_table = of_match_ptr(st_rproc_match), diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c index 8c7f7950b80eee..b02b36a3f51564 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -946,7 +946,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, static struct platform_driver stm32_rproc_driver = { .probe = stm32_rproc_probe, - .remove_new = stm32_rproc_remove, + .remove = stm32_rproc_remove, .driver = { .name = "stm32-rproc", .pm = pm_ptr(&stm32_rproc_pm_ops), diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c index 8be3f631c19206..a695890254ff76 100644 --- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c +++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c @@ -403,7 +403,7 @@ static struct resource_table *k3_dsp_get_loaded_rsc_table(struct rproc *rproc, * the hard-coded value suffices to support the IPC-only mode. */ *rsc_table_sz = 256; - return (struct resource_table *)kproc->rmem[0].cpu_addr; + return (__force struct resource_table *)kproc->rmem[0].cpu_addr; } /* @@ -576,11 +576,9 @@ static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc) return -EINVAL; rmem = of_reserved_mem_lookup(rmem_np); - if (!rmem) { - of_node_put(rmem_np); - return -EINVAL; - } of_node_put(rmem_np); + if (!rmem) + return -EINVAL; kproc->rmem[i].bus_addr = rmem->base; /* 64-bit address regions currently not supported */ @@ -793,7 +791,7 @@ MODULE_DEVICE_TABLE(of, k3_dsp_of_match); static struct platform_driver k3_dsp_rproc_driver = { .probe = k3_dsp_rproc_probe, - .remove_new = k3_dsp_rproc_remove, + .remove = k3_dsp_rproc_remove, .driver = { .name = "k3-dsp-rproc", .of_match_table = k3_dsp_of_match, diff --git a/drivers/remoteproc/ti_k3_m4_remoteproc.c b/drivers/remoteproc/ti_k3_m4_remoteproc.c index 09f0484a90e103..a16fb165fcedd4 100644 --- a/drivers/remoteproc/ti_k3_m4_remoteproc.c +++ b/drivers/remoteproc/ti_k3_m4_remoteproc.c @@ -433,11 +433,9 @@ static int k3_m4_reserved_mem_init(struct k3_m4_rproc *kproc) return -EINVAL; rmem = of_reserved_mem_lookup(rmem_np); - if (!rmem) { - of_node_put(rmem_np); - return -EINVAL; - } of_node_put(rmem_np); + if (!rmem) + return -EINVAL; kproc->rmem[i].bus_addr = rmem->base; /* 64-bit address regions currently not supported */ diff --git a/drivers/remoteproc/ti_k3_r5_remoteproc.c b/drivers/remoteproc/ti_k3_r5_remoteproc.c index 747ee467da88c9..6560b7954027f2 100644 --- a/drivers/remoteproc/ti_k3_r5_remoteproc.c +++ b/drivers/remoteproc/ti_k3_r5_remoteproc.c @@ -487,10 +487,10 @@ static int k3_r5_rproc_prepare(struct rproc *rproc) * can be effective on all TCM addresses. */ dev_dbg(dev, "zeroing out ATCM memory\n"); - memset(core->mem[0].cpu_addr, 0x00, core->mem[0].size); + memset_io(core->mem[0].cpu_addr, 0x00, core->mem[0].size); dev_dbg(dev, "zeroing out BTCM memory\n"); - memset(core->mem[1].cpu_addr, 0x00, core->mem[1].size); + memset_io(core->mem[1].cpu_addr, 0x00, core->mem[1].size); return 0; } @@ -717,7 +717,7 @@ static struct resource_table *k3_r5_get_loaded_rsc_table(struct rproc *rproc, * the hard-coded value suffices to support the IPC-only mode. */ *rsc_table_sz = 256; - return (struct resource_table *)kproc->rmem[0].cpu_addr; + return (__force struct resource_table *)kproc->rmem[0].cpu_addr; } /* @@ -1001,12 +1001,11 @@ static int k3_r5_reserved_mem_init(struct k3_r5_rproc *kproc) } rmem = of_reserved_mem_lookup(rmem_np); + of_node_put(rmem_np); if (!rmem) { - of_node_put(rmem_np); ret = -EINVAL; goto unmap_rmem; } - of_node_put(rmem_np); kproc->rmem[i].bus_addr = rmem->base; /* @@ -1558,11 +1557,7 @@ static int k3_r5_core_of_init(struct platform_device *pdev) core->ti_sci = devm_ti_sci_get_by_phandle(dev, "ti,sci"); if (IS_ERR(core->ti_sci)) { - ret = PTR_ERR(core->ti_sci); - if (ret != -EPROBE_DEFER) { - dev_err(dev, "failed to get ti-sci handle, ret = %d\n", - ret); - } + ret = dev_err_probe(dev, PTR_ERR(core->ti_sci), "failed to get ti-sci handle\n"); core->ti_sci = NULL; goto err; } @@ -1578,18 +1573,14 @@ static int k3_r5_core_of_init(struct platform_device *pdev) ret = PTR_ERR_OR_ZERO(core->reset); if (!ret) ret = -ENODEV; - if (ret != -EPROBE_DEFER) { - dev_err(dev, "failed to get reset handle, ret = %d\n", - ret); - } + dev_err_probe(dev, ret, "failed to get reset handle\n"); goto err; } core->tsp = ti_sci_proc_of_get_tsp(dev, core->ti_sci); if (IS_ERR(core->tsp)) { - ret = PTR_ERR(core->tsp); - dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n", - ret); + ret = dev_err_probe(dev, PTR_ERR(core->tsp), + "failed to construct ti-sci proc control\n"); goto err; } @@ -1659,16 +1650,14 @@ static int k3_r5_cluster_of_init(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev_of_node(dev); struct platform_device *cpdev; - struct device_node *child; struct k3_r5_core *core; int ret; - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { cpdev = of_find_device_by_node(child); if (!cpdev) { ret = -ENODEV; dev_err(dev, "could not get R5 core platform device\n"); - of_node_put(child); goto fail; } @@ -1677,7 +1666,6 @@ static int k3_r5_cluster_of_init(struct platform_device *pdev) dev_err(dev, "k3_r5_core_of_init failed, ret = %d\n", ret); put_device(&cpdev->dev); - of_node_put(child); goto fail; } @@ -1718,11 +1706,8 @@ static int k3_r5_probe(struct platform_device *pdev) init_waitqueue_head(&cluster->core_transition); ret = of_property_read_u32(np, "ti,cluster-mode", &cluster->mode); - if (ret < 0 && ret != -EINVAL) { - dev_err(dev, "invalid format for ti,cluster-mode, ret = %d\n", - ret); - return ret; - } + if (ret < 0 && ret != -EINVAL) + return dev_err_probe(dev, ret, "invalid format for ti,cluster-mode\n"); if (ret == -EINVAL) { /* @@ -1741,49 +1726,39 @@ static int k3_r5_probe(struct platform_device *pdev) } if ((cluster->mode == CLUSTER_MODE_SINGLECPU && !data->single_cpu_mode) || - (cluster->mode == CLUSTER_MODE_SINGLECORE && !data->is_single_core)) { - dev_err(dev, "Cluster mode = %d is not supported on this SoC\n", cluster->mode); - return -EINVAL; - } + (cluster->mode == CLUSTER_MODE_SINGLECORE && !data->is_single_core)) + return dev_err_probe(dev, -EINVAL, + "Cluster mode = %d is not supported on this SoC\n", + cluster->mode); num_cores = of_get_available_child_count(np); - if (num_cores != 2 && !data->is_single_core) { - dev_err(dev, "MCU cluster requires both R5F cores to be enabled but num_cores is set to = %d\n", - num_cores); - return -ENODEV; - } + if (num_cores != 2 && !data->is_single_core) + return dev_err_probe(dev, -ENODEV, + "MCU cluster requires both R5F cores to be enabled but num_cores is set to = %d\n", + num_cores); - if (num_cores != 1 && data->is_single_core) { - dev_err(dev, "SoC supports only single core R5 but num_cores is set to %d\n", - num_cores); - return -ENODEV; - } + if (num_cores != 1 && data->is_single_core) + return dev_err_probe(dev, -ENODEV, + "SoC supports only single core R5 but num_cores is set to %d\n", + num_cores); platform_set_drvdata(pdev, cluster); ret = devm_of_platform_populate(dev); - if (ret) { - dev_err(dev, "devm_of_platform_populate failed, ret = %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "devm_of_platform_populate failed\n"); ret = k3_r5_cluster_of_init(pdev); - if (ret) { - dev_err(dev, "k3_r5_cluster_of_init failed, ret = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "k3_r5_cluster_of_init failed\n"); ret = devm_add_action_or_reset(dev, k3_r5_cluster_of_exit, pdev); if (ret) return ret; ret = k3_r5_cluster_rproc_init(pdev); - if (ret) { - dev_err(dev, "k3_r5_cluster_rproc_init failed, ret = %d\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "k3_r5_cluster_rproc_init failed\n"); ret = devm_add_action_or_reset(dev, k3_r5_cluster_rproc_exit, pdev); if (ret) diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c index 36a55f7ffa64d5..d8be21e717212a 100644 --- a/drivers/remoteproc/wkup_m3_rproc.c +++ b/drivers/remoteproc/wkup_m3_rproc.c @@ -251,7 +251,7 @@ static const struct dev_pm_ops wkup_m3_rproc_pm_ops = { static struct platform_driver wkup_m3_rproc_driver = { .probe = wkup_m3_rproc_probe, - .remove_new = wkup_m3_rproc_remove, + .remove = wkup_m3_rproc_remove, .driver = { .name = "wkup_m3_rproc", .of_match_table = wkup_m3_rproc_of_match, diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 5484a65f66b953..5b3abb6db24898 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -146,30 +146,17 @@ config RESET_LPC18XX This enables the reset controller driver for NXP LPC18xx/43xx SoCs. config RESET_MCHP_SPARX5 - bool "Microchip Sparx5 reset driver" - depends on ARCH_SPARX5 || SOC_LAN966 || COMPILE_TEST + tristate "Microchip Sparx5 reset driver" + depends on ARCH_SPARX5 || SOC_LAN966 || MCHP_LAN966X_PCI || COMPILE_TEST default y if SPARX5_SWITCH select MFD_SYSCON help This driver supports switch core reset for the Microchip Sparx5 SoC. -config RESET_MESON - tristate "Meson Reset Driver" - depends on ARCH_MESON || COMPILE_TEST - default ARCH_MESON - help - This enables the reset driver for Amlogic Meson SoCs. - -config RESET_MESON_AUDIO_ARB - tristate "Meson Audio Memory Arbiter Reset Driver" - depends on ARCH_MESON || COMPILE_TEST - help - This enables the reset driver for Audio Memory Arbiter of - Amlogic's A113 based SoCs - config RESET_NPCM bool "NPCM BMC Reset Driver" if COMPILE_TEST default ARCH_NPCM + select AUXILIARY_BUS help This enables the reset controller driver for Nuvoton NPCM BMC SoCs. @@ -356,6 +343,7 @@ config RESET_ZYNQMP help This enables the reset controller driver for Xilinx ZynqMP SoCs. +source "drivers/reset/amlogic/Kconfig" source "drivers/reset/starfive/Kconfig" source "drivers/reset/sti/Kconfig" source "drivers/reset/hisilicon/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 4411a2a124d7de..677c4d1e263201 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += core.o +obj-y += amlogic/ obj-y += hisilicon/ obj-y += starfive/ obj-y += sti/ @@ -21,8 +22,6 @@ obj-$(CONFIG_RESET_K210) += reset-k210.o obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o -obj-$(CONFIG_RESET_MESON) += reset-meson.o -obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o obj-$(CONFIG_RESET_NPCM) += reset-npcm.o obj-$(CONFIG_RESET_NUVOTON_MA35D1) += reset-ma35d1.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o diff --git a/drivers/reset/amlogic/Kconfig b/drivers/reset/amlogic/Kconfig new file mode 100644 index 00000000000000..3bee9fd6026942 --- /dev/null +++ b/drivers/reset/amlogic/Kconfig @@ -0,0 +1,27 @@ +config RESET_MESON_COMMON + tristate + select REGMAP + +config RESET_MESON + tristate "Meson Reset Driver" + depends on ARCH_MESON || COMPILE_TEST + default ARCH_MESON + select REGMAP_MMIO + select RESET_MESON_COMMON + help + This enables the reset driver for Amlogic SoCs. + +config RESET_MESON_AUX + tristate "Meson Reset Auxiliary Driver" + depends on ARCH_MESON || COMPILE_TEST + select AUXILIARY_BUS + select RESET_MESON_COMMON + help + This enables the reset auxiliary driver for Amlogic SoCs. + +config RESET_MESON_AUDIO_ARB + tristate "Meson Audio Memory Arbiter Reset Driver" + depends on ARCH_MESON || COMPILE_TEST + help + This enables the reset driver for Audio Memory Arbiter of + Amlogic's A113 based SoCs diff --git a/drivers/reset/amlogic/Makefile b/drivers/reset/amlogic/Makefile new file mode 100644 index 00000000000000..ca99a691282c2f --- /dev/null +++ b/drivers/reset/amlogic/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_RESET_MESON) += reset-meson.o +obj-$(CONFIG_RESET_MESON_AUX) += reset-meson-aux.o +obj-$(CONFIG_RESET_MESON_COMMON) += reset-meson-common.o +obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o diff --git a/drivers/reset/amlogic/reset-meson-audio-arb.c b/drivers/reset/amlogic/reset-meson-audio-arb.c new file mode 100644 index 00000000000000..6ec253976bed07 --- /dev/null +++ b/drivers/reset/amlogic/reset-meson-audio-arb.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// Copyright (c) 2018 BayLibre, SAS. +// Author: Jerome Brunet + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct meson_audio_arb_data { + struct reset_controller_dev rstc; + void __iomem *regs; + struct clk *clk; + const unsigned int *reset_bits; + spinlock_t lock; +}; + +struct meson_audio_arb_match_data { + const unsigned int *reset_bits; + unsigned int reset_num; +}; + +#define ARB_GENERAL_BIT 31 + +static const unsigned int axg_audio_arb_reset_bits[] = { + [AXG_ARB_TODDR_A] = 0, + [AXG_ARB_TODDR_B] = 1, + [AXG_ARB_TODDR_C] = 2, + [AXG_ARB_FRDDR_A] = 4, + [AXG_ARB_FRDDR_B] = 5, + [AXG_ARB_FRDDR_C] = 6, +}; + +static const struct meson_audio_arb_match_data axg_audio_arb_match = { + .reset_bits = axg_audio_arb_reset_bits, + .reset_num = ARRAY_SIZE(axg_audio_arb_reset_bits), +}; + +static const unsigned int sm1_audio_arb_reset_bits[] = { + [AXG_ARB_TODDR_A] = 0, + [AXG_ARB_TODDR_B] = 1, + [AXG_ARB_TODDR_C] = 2, + [AXG_ARB_FRDDR_A] = 4, + [AXG_ARB_FRDDR_B] = 5, + [AXG_ARB_FRDDR_C] = 6, + [AXG_ARB_TODDR_D] = 3, + [AXG_ARB_FRDDR_D] = 7, +}; + +static const struct meson_audio_arb_match_data sm1_audio_arb_match = { + .reset_bits = sm1_audio_arb_reset_bits, + .reset_num = ARRAY_SIZE(sm1_audio_arb_reset_bits), +}; + +static int meson_audio_arb_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + u32 val; + struct meson_audio_arb_data *arb = + container_of(rcdev, struct meson_audio_arb_data, rstc); + + spin_lock(&arb->lock); + val = readl(arb->regs); + + if (assert) + val &= ~BIT(arb->reset_bits[id]); + else + val |= BIT(arb->reset_bits[id]); + + writel(val, arb->regs); + spin_unlock(&arb->lock); + + return 0; +} + +static int meson_audio_arb_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + u32 val; + struct meson_audio_arb_data *arb = + container_of(rcdev, struct meson_audio_arb_data, rstc); + + val = readl(arb->regs); + + return !(val & BIT(arb->reset_bits[id])); +} + +static int meson_audio_arb_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_audio_arb_update(rcdev, id, true); +} + +static int meson_audio_arb_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_audio_arb_update(rcdev, id, false); +} + +static const struct reset_control_ops meson_audio_arb_rstc_ops = { + .assert = meson_audio_arb_assert, + .deassert = meson_audio_arb_deassert, + .status = meson_audio_arb_status, +}; + +static const struct of_device_id meson_audio_arb_of_match[] = { + { + .compatible = "amlogic,meson-axg-audio-arb", + .data = &axg_audio_arb_match, + }, { + .compatible = "amlogic,meson-sm1-audio-arb", + .data = &sm1_audio_arb_match, + }, + {} +}; +MODULE_DEVICE_TABLE(of, meson_audio_arb_of_match); + +static void meson_audio_arb_remove(struct platform_device *pdev) +{ + struct meson_audio_arb_data *arb = platform_get_drvdata(pdev); + + /* Disable all access */ + spin_lock(&arb->lock); + writel(0, arb->regs); + spin_unlock(&arb->lock); +} + +static int meson_audio_arb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct meson_audio_arb_match_data *data; + struct meson_audio_arb_data *arb; + int ret; + + data = of_device_get_match_data(dev); + if (!data) + return -EINVAL; + + arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL); + if (!arb) + return -ENOMEM; + platform_set_drvdata(pdev, arb); + + arb->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(arb->clk)) + return dev_err_probe(dev, PTR_ERR(arb->clk), "failed to get clock\n"); + + arb->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(arb->regs)) + return PTR_ERR(arb->regs); + + spin_lock_init(&arb->lock); + arb->reset_bits = data->reset_bits; + arb->rstc.nr_resets = data->reset_num; + arb->rstc.ops = &meson_audio_arb_rstc_ops; + arb->rstc.of_node = dev->of_node; + arb->rstc.owner = THIS_MODULE; + + /* + * Enable general : + * In the initial state, all memory interfaces are disabled + * and the general bit is on + */ + writel(BIT(ARB_GENERAL_BIT), arb->regs); + + /* Register reset controller */ + ret = devm_reset_controller_register(dev, &arb->rstc); + if (ret) { + dev_err(dev, "failed to register arb reset controller\n"); + meson_audio_arb_remove(pdev); + } + + return ret; +} + +static struct platform_driver meson_audio_arb_pdrv = { + .probe = meson_audio_arb_probe, + .remove = meson_audio_arb_remove, + .driver = { + .name = "meson-audio-arb-reset", + .of_match_table = meson_audio_arb_of_match, + }, +}; +module_platform_driver(meson_audio_arb_pdrv); + +MODULE_DESCRIPTION("Amlogic A113 Audio Memory Arbiter"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/amlogic/reset-meson-aux.c b/drivers/reset/amlogic/reset-meson-aux.c new file mode 100644 index 00000000000000..61ce515d92a2d1 --- /dev/null +++ b/drivers/reset/amlogic/reset-meson-aux.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Amlogic Meson Reset Auxiliary driver + * + * Copyright (c) 2024 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include +#include +#include +#include +#include + +#include "reset-meson.h" +#include + +static DEFINE_IDA(meson_rst_aux_ida); + +struct meson_reset_adev { + struct auxiliary_device adev; + struct regmap *map; +}; + +#define to_meson_reset_adev(_adev) \ + container_of((_adev), struct meson_reset_adev, adev) + +static const struct meson_reset_param meson_g12a_audio_param = { + .reset_ops = &meson_reset_toggle_ops, + .reset_num = 26, + .level_offset = 0x24, +}; + +static const struct meson_reset_param meson_sm1_audio_param = { + .reset_ops = &meson_reset_toggle_ops, + .reset_num = 39, + .level_offset = 0x28, +}; + +static const struct auxiliary_device_id meson_reset_aux_ids[] = { + { + .name = "axg-audio-clkc.rst-g12a", + .driver_data = (kernel_ulong_t)&meson_g12a_audio_param, + }, { + .name = "axg-audio-clkc.rst-sm1", + .driver_data = (kernel_ulong_t)&meson_sm1_audio_param, + }, {} +}; +MODULE_DEVICE_TABLE(auxiliary, meson_reset_aux_ids); + +static int meson_reset_aux_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + const struct meson_reset_param *param = + (const struct meson_reset_param *)(id->driver_data); + struct meson_reset_adev *raux = + to_meson_reset_adev(adev); + + return meson_reset_controller_register(&adev->dev, raux->map, param); +} + +static struct auxiliary_driver meson_reset_aux_driver = { + .probe = meson_reset_aux_probe, + .id_table = meson_reset_aux_ids, +}; +module_auxiliary_driver(meson_reset_aux_driver); + +static void meson_rst_aux_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct meson_reset_adev *raux = + to_meson_reset_adev(adev); + + ida_free(&meson_rst_aux_ida, adev->id); + kfree(raux); +} + +static void meson_rst_aux_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +int devm_meson_rst_aux_register(struct device *dev, + struct regmap *map, + const char *adev_name) +{ + struct meson_reset_adev *raux; + struct auxiliary_device *adev; + int ret; + + raux = kzalloc(sizeof(*raux), GFP_KERNEL); + if (!raux) + return -ENOMEM; + + ret = ida_alloc(&meson_rst_aux_ida, GFP_KERNEL); + if (ret < 0) + goto raux_free; + + raux->map = map; + + adev = &raux->adev; + adev->id = ret; + adev->name = adev_name; + adev->dev.parent = dev; + adev->dev.release = meson_rst_aux_release; + device_set_of_node_from_dev(&adev->dev, dev); + + ret = auxiliary_device_init(adev); + if (ret) + goto ida_free; + + ret = __auxiliary_device_add(adev, dev->driver->name); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(dev, meson_rst_aux_unregister_adev, + adev); + +ida_free: + ida_free(&meson_rst_aux_ida, adev->id); +raux_free: + kfree(raux); + return ret; +} +EXPORT_SYMBOL_GPL(devm_meson_rst_aux_register); + +MODULE_DESCRIPTION("Amlogic Meson Reset Auxiliary driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS("MESON_RESET"); diff --git a/drivers/reset/amlogic/reset-meson-common.c b/drivers/reset/amlogic/reset-meson-common.c new file mode 100644 index 00000000000000..a90e0ecaaadf07 --- /dev/null +++ b/drivers/reset/amlogic/reset-meson-common.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Amlogic Meson Reset core functions + * + * Copyright (c) 2016-2024 BayLibre, SAS. + * Authors: Neil Armstrong + * Jerome Brunet + */ + +#include +#include +#include +#include + +#include "reset-meson.h" + +struct meson_reset { + const struct meson_reset_param *param; + struct reset_controller_dev rcdev; + struct regmap *map; +}; + +static void meson_reset_offset_and_bit(struct meson_reset *data, + unsigned long id, + unsigned int *offset, + unsigned int *bit) +{ + unsigned int stride = regmap_get_reg_stride(data->map); + + *offset = (id / (stride * BITS_PER_BYTE)) * stride; + *bit = id % (stride * BITS_PER_BYTE); +} + +static int meson_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct meson_reset *data = + container_of(rcdev, struct meson_reset, rcdev); + unsigned int offset, bit; + + meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->reset_offset; + + return regmap_write(data->map, offset, BIT(bit)); +} + +static int meson_reset_level(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct meson_reset *data = + container_of(rcdev, struct meson_reset, rcdev); + unsigned int offset, bit; + + meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->level_offset; + assert ^= data->param->level_low_reset; + + return regmap_update_bits(data->map, offset, + BIT(bit), assert ? BIT(bit) : 0); +} + +static int meson_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct meson_reset *data = + container_of(rcdev, struct meson_reset, rcdev); + unsigned int val, offset, bit; + + meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->level_offset; + + regmap_read(data->map, offset, &val); + val = !!(BIT(bit) & val); + + return val ^ data->param->level_low_reset; +} + +static int meson_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_reset_level(rcdev, id, true); +} + +static int meson_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_reset_level(rcdev, id, false); +} + +static int meson_reset_level_toggle(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + ret = meson_reset_assert(rcdev, id); + if (ret) + return ret; + + return meson_reset_deassert(rcdev, id); +} + +const struct reset_control_ops meson_reset_ops = { + .reset = meson_reset_reset, + .assert = meson_reset_assert, + .deassert = meson_reset_deassert, + .status = meson_reset_status, +}; +EXPORT_SYMBOL_NS_GPL(meson_reset_ops, "MESON_RESET"); + +const struct reset_control_ops meson_reset_toggle_ops = { + .reset = meson_reset_level_toggle, + .assert = meson_reset_assert, + .deassert = meson_reset_deassert, + .status = meson_reset_status, +}; +EXPORT_SYMBOL_NS_GPL(meson_reset_toggle_ops, "MESON_RESET"); + +int meson_reset_controller_register(struct device *dev, struct regmap *map, + const struct meson_reset_param *param) +{ + struct meson_reset *data; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->param = param; + data->map = map; + data->rcdev.owner = dev->driver->owner; + data->rcdev.nr_resets = param->reset_num; + data->rcdev.ops = data->param->reset_ops; + data->rcdev.of_node = dev->of_node; + + return devm_reset_controller_register(dev, &data->rcdev); +} +EXPORT_SYMBOL_NS_GPL(meson_reset_controller_register, "MESON_RESET"); + +MODULE_DESCRIPTION("Amlogic Meson Reset Core function"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS("MESON_RESET"); diff --git a/drivers/reset/amlogic/reset-meson.c b/drivers/reset/amlogic/reset-meson.c new file mode 100644 index 00000000000000..84610365a823ca --- /dev/null +++ b/drivers/reset/amlogic/reset-meson.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Amlogic Meson Reset Controller driver + * + * Copyright (c) 2016-2024 BayLibre, SAS. + * Authors: Neil Armstrong + * Jerome Brunet + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "reset-meson.h" + +static const struct meson_reset_param meson8b_param = { + .reset_ops = &meson_reset_ops, + .reset_num = 256, + .reset_offset = 0x0, + .level_offset = 0x7c, + .level_low_reset = true, +}; + +static const struct meson_reset_param meson_a1_param = { + .reset_ops = &meson_reset_ops, + .reset_num = 96, + .reset_offset = 0x0, + .level_offset = 0x40, + .level_low_reset = true, +}; + +static const struct meson_reset_param meson_s4_param = { + .reset_ops = &meson_reset_ops, + .reset_num = 192, + .reset_offset = 0x0, + .level_offset = 0x40, + .level_low_reset = true, +}; + +static const struct meson_reset_param t7_param = { + .reset_num = 224, + .reset_offset = 0x0, + .level_offset = 0x40, + .level_low_reset = true, +}; + +static const struct of_device_id meson_reset_dt_ids[] = { + { .compatible = "amlogic,meson8b-reset", .data = &meson8b_param}, + { .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param}, + { .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param}, + { .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param}, + { .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param}, + { .compatible = "amlogic,c3-reset", .data = &meson_s4_param}, + { .compatible = "amlogic,t7-reset", .data = &t7_param}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, meson_reset_dt_ids); + +static const struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int meson_reset_probe(struct platform_device *pdev) +{ + const struct meson_reset_param *param; + struct device *dev = &pdev->dev; + struct regmap *map; + void __iomem *base; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + param = device_get_match_data(dev); + if (!param) + return -ENODEV; + + map = devm_regmap_init_mmio(dev, base, ®map_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "can't init regmap mmio region\n"); + + return meson_reset_controller_register(dev, map, param); +} + +static struct platform_driver meson_reset_driver = { + .probe = meson_reset_probe, + .driver = { + .name = "meson_reset", + .of_match_table = meson_reset_dt_ids, + }, +}; +module_platform_driver(meson_reset_driver); + +MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS("MESON_RESET"); diff --git a/drivers/reset/amlogic/reset-meson.h b/drivers/reset/amlogic/reset-meson.h new file mode 100644 index 00000000000000..2051e126dc3a2e --- /dev/null +++ b/drivers/reset/amlogic/reset-meson.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (c) 2024 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_RESET_H +#define __MESON_RESET_H + +#include +#include +#include + +struct meson_reset_param { + const struct reset_control_ops *reset_ops; + unsigned int reset_num; + unsigned int reset_offset; + unsigned int level_offset; + bool level_low_reset; +}; + +int meson_reset_controller_register(struct device *dev, struct regmap *map, + const struct meson_reset_param *param); + +extern const struct reset_control_ops meson_reset_ops; +extern const struct reset_control_ops meson_reset_toggle_ops; + +#endif /* __MESON_RESET_H */ diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 4d509d41456ad8..22f67fc77ae531 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -773,12 +773,19 @@ EXPORT_SYMBOL_GPL(reset_control_bulk_release); static struct reset_control * __reset_control_get_internal(struct reset_controller_dev *rcdev, - unsigned int index, bool shared, bool acquired) + unsigned int index, enum reset_control_flags flags) { + bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED; + bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED; struct reset_control *rstc; lockdep_assert_held(&reset_list_mutex); + /* Expect callers to filter out OPTIONAL and DEASSERTED bits */ + if (WARN_ON(flags & ~(RESET_CONTROL_FLAGS_BIT_SHARED | + RESET_CONTROL_FLAGS_BIT_ACQUIRED))) + return ERR_PTR(-EINVAL); + list_for_each_entry(rstc, &rcdev->reset_control_head, list) { if (rstc->id == index) { /* @@ -994,8 +1001,9 @@ static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_a struct reset_control * __of_reset_control_get(struct device_node *node, const char *id, int index, - bool shared, bool optional, bool acquired) + enum reset_control_flags flags) { + bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; bool gpio_fallback = false; struct reset_control *rstc; struct reset_controller_dev *rcdev; @@ -1059,8 +1067,10 @@ __of_reset_control_get(struct device_node *node, const char *id, int index, goto out_unlock; } + flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL; + /* reset_list_mutex also protects the rcdev's reset_control list */ - rstc = __reset_control_get_internal(rcdev, rstc_id, shared, acquired); + rstc = __reset_control_get_internal(rcdev, rstc_id, flags); out_unlock: mutex_unlock(&reset_list_mutex); @@ -1091,8 +1101,9 @@ __reset_controller_by_name(const char *name) static struct reset_control * __reset_control_get_from_lookup(struct device *dev, const char *con_id, - bool shared, bool optional, bool acquired) + enum reset_control_flags flags) { + bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; const struct reset_control_lookup *lookup; struct reset_controller_dev *rcdev; const char *dev_id = dev_name(dev); @@ -1116,9 +1127,11 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id, return ERR_PTR(-EPROBE_DEFER); } + flags &= ~RESET_CONTROL_FLAGS_BIT_OPTIONAL; + rstc = __reset_control_get_internal(rcdev, lookup->index, - shared, acquired); + flags); mutex_unlock(&reset_list_mutex); break; } @@ -1133,30 +1146,29 @@ __reset_control_get_from_lookup(struct device *dev, const char *con_id, } struct reset_control *__reset_control_get(struct device *dev, const char *id, - int index, bool shared, bool optional, - bool acquired) + int index, enum reset_control_flags flags) { + bool shared = flags & RESET_CONTROL_FLAGS_BIT_SHARED; + bool acquired = flags & RESET_CONTROL_FLAGS_BIT_ACQUIRED; + if (WARN_ON(shared && acquired)) return ERR_PTR(-EINVAL); if (dev->of_node) - return __of_reset_control_get(dev->of_node, id, index, shared, - optional, acquired); + return __of_reset_control_get(dev->of_node, id, index, flags); - return __reset_control_get_from_lookup(dev, id, shared, optional, - acquired); + return __reset_control_get_from_lookup(dev, id, flags); } EXPORT_SYMBOL_GPL(__reset_control_get); int __reset_control_bulk_get(struct device *dev, int num_rstcs, struct reset_control_bulk_data *rstcs, - bool shared, bool optional, bool acquired) + enum reset_control_flags flags) { int ret, i; for (i = 0; i < num_rstcs; i++) { - rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0, - shared, optional, acquired); + rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0, flags); if (IS_ERR(rstcs[i].rstc)) { ret = PTR_ERR(rstcs[i].rstc); goto err; @@ -1224,23 +1236,46 @@ static void devm_reset_control_release(struct device *dev, void *res) reset_control_put(*(struct reset_control **)res); } +static void devm_reset_control_release_deasserted(struct device *dev, void *res) +{ + struct reset_control *rstc = *(struct reset_control **)res; + + reset_control_assert(rstc); + reset_control_put(rstc); +} + struct reset_control * __devm_reset_control_get(struct device *dev, const char *id, int index, - bool shared, bool optional, bool acquired) + enum reset_control_flags flags) { struct reset_control **ptr, *rstc; + bool deasserted = flags & RESET_CONTROL_FLAGS_BIT_DEASSERTED; - ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr), + ptr = devres_alloc(deasserted ? devm_reset_control_release_deasserted : + devm_reset_control_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); - rstc = __reset_control_get(dev, id, index, shared, optional, acquired); + flags &= ~RESET_CONTROL_FLAGS_BIT_DEASSERTED; + + rstc = __reset_control_get(dev, id, index, flags); if (IS_ERR_OR_NULL(rstc)) { devres_free(ptr); return rstc; } + if (deasserted) { + int ret; + + ret = reset_control_deassert(rstc); + if (ret) { + reset_control_put(rstc); + devres_free(ptr); + return ERR_PTR(ret); + } + } + *ptr = rstc; devres_add(dev, ptr); @@ -1260,24 +1295,45 @@ static void devm_reset_control_bulk_release(struct device *dev, void *res) reset_control_bulk_put(devres->num_rstcs, devres->rstcs); } +static void devm_reset_control_bulk_release_deasserted(struct device *dev, void *res) +{ + struct reset_control_bulk_devres *devres = res; + + reset_control_bulk_assert(devres->num_rstcs, devres->rstcs); + reset_control_bulk_put(devres->num_rstcs, devres->rstcs); +} + int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, struct reset_control_bulk_data *rstcs, - bool shared, bool optional, bool acquired) + enum reset_control_flags flags) { struct reset_control_bulk_devres *ptr; + bool deasserted = flags & RESET_CONTROL_FLAGS_BIT_DEASSERTED; int ret; - ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr), + ptr = devres_alloc(deasserted ? devm_reset_control_bulk_release_deasserted : + devm_reset_control_bulk_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return -ENOMEM; - ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired); + flags &= ~RESET_CONTROL_FLAGS_BIT_DEASSERTED; + + ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, flags); if (ret < 0) { devres_free(ptr); return ret; } + if (deasserted) { + ret = reset_control_bulk_deassert(num_rstcs, rstcs); + if (ret) { + reset_control_bulk_put(num_rstcs, rstcs); + devres_free(ptr); + return ret; + } + } + ptr->num_rstcs = num_rstcs; ptr->rstcs = rstcs; devres_add(dev, ptr); @@ -1298,6 +1354,7 @@ EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get); */ int __device_reset(struct device *dev, bool optional) { + enum reset_control_flags flags; struct reset_control *rstc; int ret; @@ -1313,7 +1370,8 @@ int __device_reset(struct device *dev, bool optional) } #endif - rstc = __reset_control_get(dev, NULL, 0, 0, optional, true); + flags = optional ? RESET_CONTROL_OPTIONAL_EXCLUSIVE : RESET_CONTROL_EXCLUSIVE; + rstc = __reset_control_get(dev, NULL, 0, flags); if (IS_ERR(rstc)) return PTR_ERR(rstc); @@ -1356,17 +1414,14 @@ static int of_reset_control_get_count(struct device_node *node) * device node. * * @np: device node for the device that requests the reset controls array - * @shared: whether reset controls are shared or not - * @optional: whether it is optional to get the reset controls - * @acquired: only one reset control may be acquired for a given controller - * and ID + * @flags: whether reset controls are shared, optional, acquired * * Returns pointer to allocated reset_control on success or error on failure */ struct reset_control * -of_reset_control_array_get(struct device_node *np, bool shared, bool optional, - bool acquired) +of_reset_control_array_get(struct device_node *np, enum reset_control_flags flags) { + bool optional = flags & RESET_CONTROL_FLAGS_BIT_OPTIONAL; struct reset_control_array *resets; struct reset_control *rstc; int num, i; @@ -1381,8 +1436,7 @@ of_reset_control_array_get(struct device_node *np, bool shared, bool optional, resets->num_rstcs = num; for (i = 0; i < num; i++) { - rstc = __of_reset_control_get(np, NULL, i, shared, optional, - acquired); + rstc = __of_reset_control_get(np, NULL, i, flags); if (IS_ERR(rstc)) goto err_rst; resets->rstc[i] = rstc; @@ -1407,8 +1461,7 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get); * devm_reset_control_array_get - Resource managed reset control array get * * @dev: device that requests the list of reset controls - * @shared: whether reset controls are shared or not - * @optional: whether it is optional to get the reset controls + * @flags: whether reset controls are shared, optional, acquired * * The reset control array APIs are intended for a list of resets * that just have to be asserted or deasserted, without any @@ -1417,7 +1470,7 @@ EXPORT_SYMBOL_GPL(of_reset_control_array_get); * Returns pointer to allocated reset_control on success or error on failure */ struct reset_control * -devm_reset_control_array_get(struct device *dev, bool shared, bool optional) +devm_reset_control_array_get(struct device *dev, enum reset_control_flags flags) { struct reset_control **ptr, *rstc; @@ -1426,7 +1479,7 @@ devm_reset_control_array_get(struct device *dev, bool shared, bool optional) if (!ptr) return ERR_PTR(-ENOMEM); - rstc = of_reset_control_array_get(dev->of_node, shared, optional, true); + rstc = of_reset_control_array_get(dev->of_node, flags); if (IS_ERR_OR_NULL(rstc)) { devres_free(ptr); return rstc; diff --git a/drivers/reset/reset-meson-audio-arb.c b/drivers/reset/reset-meson-audio-arb.c deleted file mode 100644 index 421ccb40da8c73..00000000000000 --- a/drivers/reset/reset-meson-audio-arb.c +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR MIT) -// Copyright (c) 2018 BayLibre, SAS. -// Author: Jerome Brunet - -#include -#include -#include -#include -#include -#include -#include - -#include - -struct meson_audio_arb_data { - struct reset_controller_dev rstc; - void __iomem *regs; - struct clk *clk; - const unsigned int *reset_bits; - spinlock_t lock; -}; - -struct meson_audio_arb_match_data { - const unsigned int *reset_bits; - unsigned int reset_num; -}; - -#define ARB_GENERAL_BIT 31 - -static const unsigned int axg_audio_arb_reset_bits[] = { - [AXG_ARB_TODDR_A] = 0, - [AXG_ARB_TODDR_B] = 1, - [AXG_ARB_TODDR_C] = 2, - [AXG_ARB_FRDDR_A] = 4, - [AXG_ARB_FRDDR_B] = 5, - [AXG_ARB_FRDDR_C] = 6, -}; - -static const struct meson_audio_arb_match_data axg_audio_arb_match = { - .reset_bits = axg_audio_arb_reset_bits, - .reset_num = ARRAY_SIZE(axg_audio_arb_reset_bits), -}; - -static const unsigned int sm1_audio_arb_reset_bits[] = { - [AXG_ARB_TODDR_A] = 0, - [AXG_ARB_TODDR_B] = 1, - [AXG_ARB_TODDR_C] = 2, - [AXG_ARB_FRDDR_A] = 4, - [AXG_ARB_FRDDR_B] = 5, - [AXG_ARB_FRDDR_C] = 6, - [AXG_ARB_TODDR_D] = 3, - [AXG_ARB_FRDDR_D] = 7, -}; - -static const struct meson_audio_arb_match_data sm1_audio_arb_match = { - .reset_bits = sm1_audio_arb_reset_bits, - .reset_num = ARRAY_SIZE(sm1_audio_arb_reset_bits), -}; - -static int meson_audio_arb_update(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) -{ - u32 val; - struct meson_audio_arb_data *arb = - container_of(rcdev, struct meson_audio_arb_data, rstc); - - spin_lock(&arb->lock); - val = readl(arb->regs); - - if (assert) - val &= ~BIT(arb->reset_bits[id]); - else - val |= BIT(arb->reset_bits[id]); - - writel(val, arb->regs); - spin_unlock(&arb->lock); - - return 0; -} - -static int meson_audio_arb_status(struct reset_controller_dev *rcdev, - unsigned long id) -{ - u32 val; - struct meson_audio_arb_data *arb = - container_of(rcdev, struct meson_audio_arb_data, rstc); - - val = readl(arb->regs); - - return !(val & BIT(arb->reset_bits[id])); -} - -static int meson_audio_arb_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return meson_audio_arb_update(rcdev, id, true); -} - -static int meson_audio_arb_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return meson_audio_arb_update(rcdev, id, false); -} - -static const struct reset_control_ops meson_audio_arb_rstc_ops = { - .assert = meson_audio_arb_assert, - .deassert = meson_audio_arb_deassert, - .status = meson_audio_arb_status, -}; - -static const struct of_device_id meson_audio_arb_of_match[] = { - { - .compatible = "amlogic,meson-axg-audio-arb", - .data = &axg_audio_arb_match, - }, { - .compatible = "amlogic,meson-sm1-audio-arb", - .data = &sm1_audio_arb_match, - }, - {} -}; -MODULE_DEVICE_TABLE(of, meson_audio_arb_of_match); - -static void meson_audio_arb_remove(struct platform_device *pdev) -{ - struct meson_audio_arb_data *arb = platform_get_drvdata(pdev); - - /* Disable all access */ - spin_lock(&arb->lock); - writel(0, arb->regs); - spin_unlock(&arb->lock); -} - -static int meson_audio_arb_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - const struct meson_audio_arb_match_data *data; - struct meson_audio_arb_data *arb; - int ret; - - data = of_device_get_match_data(dev); - if (!data) - return -EINVAL; - - arb = devm_kzalloc(dev, sizeof(*arb), GFP_KERNEL); - if (!arb) - return -ENOMEM; - platform_set_drvdata(pdev, arb); - - arb->clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(arb->clk)) - return dev_err_probe(dev, PTR_ERR(arb->clk), "failed to get clock\n"); - - arb->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(arb->regs)) - return PTR_ERR(arb->regs); - - spin_lock_init(&arb->lock); - arb->reset_bits = data->reset_bits; - arb->rstc.nr_resets = data->reset_num; - arb->rstc.ops = &meson_audio_arb_rstc_ops; - arb->rstc.of_node = dev->of_node; - arb->rstc.owner = THIS_MODULE; - - /* - * Enable general : - * In the initial state, all memory interfaces are disabled - * and the general bit is on - */ - writel(BIT(ARB_GENERAL_BIT), arb->regs); - - /* Register reset controller */ - ret = devm_reset_controller_register(dev, &arb->rstc); - if (ret) { - dev_err(dev, "failed to register arb reset controller\n"); - meson_audio_arb_remove(pdev); - } - - return ret; -} - -static struct platform_driver meson_audio_arb_pdrv = { - .probe = meson_audio_arb_probe, - .remove_new = meson_audio_arb_remove, - .driver = { - .name = "meson-audio-arb-reset", - .of_match_table = meson_audio_arb_of_match, - }, -}; -module_platform_driver(meson_audio_arb_pdrv); - -MODULE_DESCRIPTION("Amlogic A113 Audio Memory Arbiter"); -MODULE_AUTHOR("Jerome Brunet "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c deleted file mode 100644 index 1e9fca3e30e8e3..00000000000000 --- a/drivers/reset/reset-meson.c +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* - * Amlogic Meson Reset Controller driver - * - * Copyright (c) 2016 BayLibre, SAS. - * Author: Neil Armstrong - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BITS_PER_REG 32 - -struct meson_reset_param { - int reg_count; - int level_offset; -}; - -struct meson_reset { - void __iomem *reg_base; - const struct meson_reset_param *param; - struct reset_controller_dev rcdev; - spinlock_t lock; -}; - -static int meson_reset_reset(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct meson_reset *data = - container_of(rcdev, struct meson_reset, rcdev); - unsigned int bank = id / BITS_PER_REG; - unsigned int offset = id % BITS_PER_REG; - void __iomem *reg_addr = data->reg_base + (bank << 2); - - writel(BIT(offset), reg_addr); - - return 0; -} - -static int meson_reset_level(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) -{ - struct meson_reset *data = - container_of(rcdev, struct meson_reset, rcdev); - unsigned int bank = id / BITS_PER_REG; - unsigned int offset = id % BITS_PER_REG; - void __iomem *reg_addr; - unsigned long flags; - u32 reg; - - reg_addr = data->reg_base + data->param->level_offset + (bank << 2); - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(reg_addr); - if (assert) - writel(reg & ~BIT(offset), reg_addr); - else - writel(reg | BIT(offset), reg_addr); - - spin_unlock_irqrestore(&data->lock, flags); - - return 0; -} - -static int meson_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return meson_reset_level(rcdev, id, true); -} - -static int meson_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return meson_reset_level(rcdev, id, false); -} - -static const struct reset_control_ops meson_reset_ops = { - .reset = meson_reset_reset, - .assert = meson_reset_assert, - .deassert = meson_reset_deassert, -}; - -static const struct meson_reset_param meson8b_param = { - .reg_count = 8, - .level_offset = 0x7c, -}; - -static const struct meson_reset_param meson_a1_param = { - .reg_count = 3, - .level_offset = 0x40, -}; - -static const struct meson_reset_param meson_s4_param = { - .reg_count = 6, - .level_offset = 0x40, -}; - -static const struct meson_reset_param t7_param = { - .reg_count = 7, - .level_offset = 0x40, -}; - -static const struct of_device_id meson_reset_dt_ids[] = { - { .compatible = "amlogic,meson8b-reset", .data = &meson8b_param}, - { .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param}, - { .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param}, - { .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param}, - { .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param}, - { .compatible = "amlogic,c3-reset", .data = &meson_s4_param}, - { .compatible = "amlogic,t7-reset", .data = &t7_param}, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, meson_reset_dt_ids); - -static int meson_reset_probe(struct platform_device *pdev) -{ - struct meson_reset *data; - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(data->reg_base)) - return PTR_ERR(data->reg_base); - - data->param = of_device_get_match_data(&pdev->dev); - if (!data->param) - return -ENODEV; - - spin_lock_init(&data->lock); - - data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = data->param->reg_count * BITS_PER_REG; - data->rcdev.ops = &meson_reset_ops; - data->rcdev.of_node = pdev->dev.of_node; - - return devm_reset_controller_register(&pdev->dev, &data->rcdev); -} - -static struct platform_driver meson_reset_driver = { - .probe = meson_reset_probe, - .driver = { - .name = "meson_reset", - .of_match_table = meson_reset_dt_ids, - }, -}; -module_platform_driver(meson_reset_driver); - -MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver"); -MODULE_AUTHOR("Neil Armstrong "); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/reset/reset-microchip-sparx5.c b/drivers/reset/reset-microchip-sparx5.c index 636e85c388b039..aa5464be7053be 100644 --- a/drivers/reset/reset-microchip-sparx5.c +++ b/drivers/reset/reset-microchip-sparx5.c @@ -62,6 +62,28 @@ static const struct reset_control_ops sparx5_reset_ops = { .reset = sparx5_reset_noop, }; +static const struct regmap_config mchp_lan966x_syscon_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static struct regmap *mchp_lan966x_syscon_to_regmap(struct device *dev, + struct device_node *syscon_np) +{ + struct regmap_config regmap_config = mchp_lan966x_syscon_regmap_config; + resource_size_t size; + void __iomem *base; + + base = devm_of_iomap(dev, syscon_np, 0, &size); + if (IS_ERR(base)) + return ERR_CAST(base); + + regmap_config.max_register = size - 4; + + return devm_regmap_init_mmio(dev, base, ®map_config); +} + static int mchp_sparx5_map_syscon(struct platform_device *pdev, char *name, struct regmap **target) { @@ -72,7 +94,18 @@ static int mchp_sparx5_map_syscon(struct platform_device *pdev, char *name, syscon_np = of_parse_phandle(pdev->dev.of_node, name, 0); if (!syscon_np) return -ENODEV; - regmap = syscon_node_to_regmap(syscon_np); + + /* + * The syscon API doesn't support syscon device removal. + * When used in LAN966x PCI device, the cpu-syscon device needs to be + * removed when the PCI device is removed. + * In case of LAN966x, map the syscon device locally to support the + * device removal. + */ + if (of_device_is_compatible(pdev->dev.of_node, "microchip,lan966x-switch-reset")) + regmap = mchp_lan966x_syscon_to_regmap(&pdev->dev, syscon_np); + else + regmap = syscon_node_to_regmap(syscon_np); of_node_put(syscon_np); if (IS_ERR(regmap)) { err = PTR_ERR(regmap); @@ -121,6 +154,7 @@ static int mchp_sparx5_reset_probe(struct platform_device *pdev) return err; ctx->rcdev.owner = THIS_MODULE; + ctx->rcdev.dev = &pdev->dev; ctx->rcdev.nr_resets = 1; ctx->rcdev.ops = &sparx5_reset_ops; ctx->rcdev.of_node = dn; @@ -158,6 +192,7 @@ static const struct of_device_id mchp_sparx5_reset_of_match[] = { }, { } }; +MODULE_DEVICE_TABLE(of, mchp_sparx5_reset_of_match); static struct platform_driver mchp_sparx5_reset_driver = { .probe = mchp_sparx5_reset_probe, @@ -180,3 +215,4 @@ postcore_initcall(mchp_sparx5_reset_init); MODULE_DESCRIPTION("Microchip Sparx5 switch reset driver"); MODULE_AUTHOR("Steen Hegelund "); +MODULE_LICENSE("GPL"); diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c index 710f9c1676f938..574e59db83a4fc 100644 --- a/drivers/reset/reset-mpfs.c +++ b/drivers/reset/reset-mpfs.c @@ -212,7 +212,7 @@ int mpfs_reset_controller_register(struct device *clk_dev, void __iomem *base) return devm_add_action_or_reset(clk_dev, mpfs_reset_unregister_adev, adev); } -EXPORT_SYMBOL_NS_GPL(mpfs_reset_controller_register, MCHP_CLK_MPFS); +EXPORT_SYMBOL_NS_GPL(mpfs_reset_controller_register, "MCHP_CLK_MPFS"); static const struct auxiliary_device_id mpfs_reset_ids[] = { { @@ -231,4 +231,4 @@ module_auxiliary_driver(mpfs_reset_driver); MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver"); MODULE_AUTHOR("Conor Dooley "); -MODULE_IMPORT_NS(MCHP_CLK_MPFS); +MODULE_IMPORT_NS("MCHP_CLK_MPFS"); diff --git a/drivers/reset/reset-npcm.c b/drivers/reset/reset-npcm.c index a200cc8c795502..e5b6127783a760 100644 --- a/drivers/reset/reset-npcm.c +++ b/drivers/reset/reset-npcm.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Nuvoton Technology corporation. +#include #include #include #include @@ -10,11 +11,14 @@ #include #include #include +#include #include #include #include #include +#include + /* NPCM7xx GCR registers */ #define NPCM_MDLR_OFFSET 0x7C #define NPCM7XX_MDLR_USBD0 BIT(9) @@ -89,6 +93,7 @@ struct npcm_rc_data { const struct npcm_reset_info *info; struct regmap *gcr_regmap; u32 sw_reset_number; + struct device *dev; void __iomem *base; spinlock_t lock; }; @@ -372,6 +377,67 @@ static const struct reset_control_ops npcm_rc_ops = { .status = npcm_rc_status, }; +static void npcm_clock_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +static void npcm_clock_adev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct npcm_clock_adev *rdev = to_npcm_clock_adev(adev); + + kfree(rdev); +} + +static struct auxiliary_device *npcm_clock_adev_alloc(struct npcm_rc_data *rst_data, char *clk_name) +{ + struct npcm_clock_adev *rdev; + struct auxiliary_device *adev; + int ret; + + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); + if (!rdev) + return ERR_PTR(-ENOMEM); + + rdev->base = rst_data->base; + + adev = &rdev->adev; + adev->name = clk_name; + adev->dev.parent = rst_data->dev; + adev->dev.release = npcm_clock_adev_release; + adev->id = 555u; + + ret = auxiliary_device_init(adev); + if (ret) { + kfree(rdev); + return ERR_PTR(ret); + } + + return adev; +} + +static int npcm8xx_clock_controller_register(struct npcm_rc_data *rst_data, char *clk_name) +{ + struct auxiliary_device *adev; + int ret; + + adev = npcm_clock_adev_alloc(rst_data, clk_name); + if (IS_ERR(adev)) + return PTR_ERR(adev); + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(rst_data->dev, npcm_clock_unregister_adev, adev); +} + static int npcm_rc_probe(struct platform_device *pdev) { struct npcm_rc_data *rc; @@ -392,6 +458,7 @@ static int npcm_rc_probe(struct platform_device *pdev) rc->rcdev.of_node = pdev->dev.of_node; rc->rcdev.of_reset_n_cells = 2; rc->rcdev.of_xlate = npcm_reset_xlate; + rc->dev = &pdev->dev; ret = devm_reset_controller_register(&pdev->dev, &rc->rcdev); if (ret) { @@ -408,12 +475,19 @@ static int npcm_rc_probe(struct platform_device *pdev) rc->restart_nb.priority = 192; rc->restart_nb.notifier_call = npcm_rc_restart; ret = register_restart_handler(&rc->restart_nb); - if (ret) + if (ret) { dev_warn(&pdev->dev, "failed to register restart handler\n"); + return ret; + } } } - return ret; + switch (rc->info->bmc_id) { + case BMC_NPCM8XX: + return npcm8xx_clock_controller_register(rc, "clk-npcm8xx"); + default: + return 0; + } } static struct platform_driver npcm_rc_driver = { diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c index 1cd157f4f03b47..12d0535a874bb4 100644 --- a/drivers/reset/reset-rzg2l-usbphy-ctrl.c +++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c @@ -208,7 +208,7 @@ static struct platform_driver rzg2l_usbphy_ctrl_driver = { .of_match_table = rzg2l_usbphy_ctrl_match_table, }, .probe = rzg2l_usbphy_ctrl_probe, - .remove_new = rzg2l_usbphy_ctrl_remove, + .remove = rzg2l_usbphy_ctrl_remove, }; module_platform_driver(rzg2l_usbphy_ctrl_driver); diff --git a/drivers/reset/reset-ti-sci.c b/drivers/reset/reset-ti-sci.c index d384da0982fa1e..1dc5b766aac1fe 100644 --- a/drivers/reset/reset-ti-sci.c +++ b/drivers/reset/reset-ti-sci.c @@ -246,7 +246,7 @@ static void ti_sci_reset_remove(struct platform_device *pdev) static struct platform_driver ti_sci_reset_driver = { .probe = ti_sci_reset_probe, - .remove_new = ti_sci_reset_remove, + .remove = ti_sci_reset_remove, .driver = { .name = "ti-sci-reset", .of_match_table = ti_sci_reset_of_match, diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c index 5f9f2f7994c07a..a2a262bf6bfc71 100644 --- a/drivers/reset/reset-uniphier-glue.c +++ b/drivers/reset/reset-uniphier-glue.c @@ -35,13 +35,6 @@ static void uniphier_clk_disable(void *_priv) clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); } -static void uniphier_rst_assert(void *_priv) -{ - struct uniphier_glue_reset_priv *priv = _priv; - - reset_control_bulk_assert(priv->data->nrsts, priv->rst); -} - static int uniphier_glue_reset_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -68,13 +61,6 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev) if (ret) return ret; - for (i = 0; i < priv->data->nrsts; i++) - priv->rst[i].id = priv->data->reset_names[i]; - ret = devm_reset_control_bulk_get_shared(dev, priv->data->nrsts, - priv->rst); - if (ret) - return ret; - ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk); if (ret) return ret; @@ -83,11 +69,11 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev) if (ret) return ret; - ret = reset_control_bulk_deassert(priv->data->nrsts, priv->rst); - if (ret) - return ret; - - ret = devm_add_action_or_reset(dev, uniphier_rst_assert, priv); + for (i = 0; i < priv->data->nrsts; i++) + priv->rst[i].id = priv->data->reset_names[i]; + ret = devm_reset_control_bulk_get_shared_deasserted(dev, + priv->data->nrsts, + priv->rst); if (ret) return ret; diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index d3af1dfa3c7d71..a2f9d85c7156dc 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1204,7 +1204,8 @@ void qcom_glink_native_rx(struct qcom_glink *glink) ret = qcom_glink_rx_open_ack(glink, param1); break; case GLINK_CMD_OPEN: - ret = qcom_glink_rx_defer(glink, param2); + /* upper 16 bits of param2 are the "prio" field */ + ret = qcom_glink_rx_defer(glink, param2 & 0xffff); break; case GLINK_CMD_TX_DATA: case GLINK_CMD_TX_DATA_CONT: diff --git a/drivers/rpmsg/qcom_glink_rpm.c b/drivers/rpmsg/qcom_glink_rpm.c index 357272d7062e36..e3ba2c63a5fce5 100644 --- a/drivers/rpmsg/qcom_glink_rpm.c +++ b/drivers/rpmsg/qcom_glink_rpm.c @@ -381,7 +381,7 @@ MODULE_DEVICE_TABLE(of, glink_rpm_of_match); static struct platform_driver glink_rpm_driver = { .probe = glink_rpm_probe, - .remove_new = glink_rpm_remove, + .remove = glink_rpm_remove, .driver = { .name = "qcom_glink_rpm", .of_match_table = glink_rpm_of_match, diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index 43f601c84b4fcb..40d386809d6b78 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1596,7 +1596,7 @@ MODULE_DEVICE_TABLE(of, qcom_smd_of_match); static struct platform_driver qcom_smd_driver = { .probe = qcom_smd_probe, - .remove_new = qcom_smd_remove, + .remove = qcom_smd_remove, .driver = { .name = "qcom-smd", .of_match_table = qcom_smd_of_match, diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 66eb1122248b65..a60bcc791a4803 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -182,6 +182,16 @@ config RTC_DRV_88PM80X This driver can also be built as a module. If so, the module will be called rtc-88pm80x. +config RTC_DRV_88PM886 + tristate "Marvell 88PM886 RTC driver" + depends on MFD_88PM886_PMIC + help + If you say yes here you will get support for the RTC function in the + Marvell 88PM886 chip. + + This driver can also be built as a module. If so, the module + will be called rtc-88pm886. + config RTC_DRV_ABB5ZES3 select REGMAP_I2C tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3" @@ -496,6 +506,7 @@ config RTC_DRV_PCF85363 config RTC_DRV_PCF8563 tristate "Philips PCF8563/Epson RTC8564" + select REGMAP_I2C help If you say yes here you get support for the Philips PCF8563 RTC chip. The Epson RTC8564 @@ -2005,6 +2016,16 @@ config RTC_DRV_MA35D1 This driver can also be built as a module, if so, the module will be called "rtc-ma35d1". +config RTC_DRV_RENESAS_RTCA3 + tristate "Renesas RTCA-3 RTC" + depends on ARCH_RENESAS + help + If you say yes here you get support for the Renesas RTCA-3 RTC + available on the Renesas RZ/G3S SoC. + + This driver can also be built as a module, if so, the module + will be called "rtc-rtca3". + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME @@ -2070,4 +2091,16 @@ config RTC_DRV_SSD202D This driver can also be built as a module, if so, the module will be called "rtc-ssd20xd". +config RTC_DRV_AMLOGIC_A4 + tristate "Amlogic RTC" + depends on ARCH_MESON || COMPILE_TEST + select REGMAP_MMIO + default y + help + If you say yes here you get support for the RTC block on the + Amlogic A113L2(A4) and A113X2(A5) SoCs. + + This driver can also be built as a module. If so, the module + will be called "rtc-amlogic-a4". + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index f62340ecc5348d..489b4ab07068c7 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -21,11 +21,13 @@ obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o +obj-$(CONFIG_RTC_DRV_88PM886) += rtc-88pm886.o obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o obj-$(CONFIG_RTC_DRV_ABEOZ9) += rtc-ab-eoz9.o obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o +obj-$(CONFIG_RTC_DRV_AMLOGIC_A4) += rtc-amlogic-a4.o obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o @@ -158,13 +160,14 @@ obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8111) += rtc-rx8111.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o obj-$(CONFIG_RTC_DRV_RZN1) += rtc-rzn1.o +obj-$(CONFIG_RTC_DRV_RENESAS_RTCA3) += rtc-renesas-rtca3.o obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o -obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o +obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index cca650b2e0b94d..aaf76406cd7d7d 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -904,13 +904,18 @@ void rtc_timer_do_work(struct work_struct *work) struct timerqueue_node *next; ktime_t now; struct rtc_time tm; + int err; struct rtc_device *rtc = container_of(work, struct rtc_device, irqwork); mutex_lock(&rtc->ops_lock); again: - __rtc_read_time(rtc, &tm); + err = __rtc_read_time(rtc, &tm); + if (err) { + mutex_unlock(&rtc->ops_lock); + return; + } now = rtc_tm_to_ktime(tm); while ((next = timerqueue_getnext(&rtc->timerqueue))) { if (next->expires > now) diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index f40cc06b097973..5c39cf252392de 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -329,7 +329,7 @@ static struct platform_driver pm80x_rtc_driver = { .pm = &pm80x_rtc_pm_ops, }, .probe = pm80x_rtc_probe, - .remove_new = pm80x_rtc_remove, + .remove = pm80x_rtc_remove, }; module_platform_driver(pm80x_rtc_driver); diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 0f124ed5b3e56b..814230d6184271 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -371,7 +371,7 @@ static struct platform_driver pm860x_rtc_driver = { .pm = &pm860x_rtc_pm_ops, }, .probe = pm860x_rtc_probe, - .remove_new = pm860x_rtc_remove, + .remove = pm860x_rtc_remove, }; module_platform_driver(pm860x_rtc_driver); diff --git a/drivers/rtc/rtc-88pm886.c b/drivers/rtc/rtc-88pm886.c new file mode 100644 index 00000000000000..57e9b0a66eed4e --- /dev/null +++ b/drivers/rtc/rtc-88pm886.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include + +#include + +/* + * Time is calculated as the sum of a 32-bit read-only advancing counter and a + * writeable constant offset stored in the chip's spare registers. + */ + +static int pm886_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct regmap *regmap = dev_get_drvdata(dev); + u32 time; + u32 buf; + int ret; + + ret = regmap_bulk_read(regmap, PM886_REG_RTC_SPARE1, &buf, 4); + if (ret) + return ret; + time = buf; + + ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4); + if (ret) + return ret; + time += buf; + + rtc_time64_to_tm(time, tm); + + return 0; +} + +static int pm886_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct regmap *regmap = dev_get_drvdata(dev); + u32 buf; + int ret; + + ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4); + if (ret) + return ret; + + buf = rtc_tm_to_time64(tm) - buf; + + return regmap_bulk_write(regmap, PM886_REG_RTC_SPARE1, &buf, 4); +} + +static const struct rtc_class_ops pm886_rtc_ops = { + .read_time = pm886_rtc_read_time, + .set_time = pm886_rtc_set_time, +}; + +static int pm886_rtc_probe(struct platform_device *pdev) +{ + struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct rtc_device *rtc; + int ret; + + platform_set_drvdata(pdev, chip->regmap); + + rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc)) + return dev_err_probe(dev, PTR_ERR(rtc), + "Failed to allocate RTC device\n"); + + rtc->ops = &pm886_rtc_ops; + rtc->range_max = U32_MAX; + + ret = devm_rtc_register_device(rtc); + if (ret) + return dev_err_probe(dev, ret, "Failed to register RTC device\n"); + + return 0; +} + +static const struct platform_device_id pm886_rtc_id_table[] = { + { "88pm886-rtc", }, + { } +}; +MODULE_DEVICE_TABLE(platform, pm886_rtc_id_table); + +static struct platform_driver pm886_rtc_driver = { + .driver = { + .name = "88pm886-rtc", + }, + .probe = pm886_rtc_probe, + .id_table = pm886_rtc_id_table, +}; +module_platform_driver(pm886_rtc_driver); + +MODULE_DESCRIPTION("Marvell 88PM886 RTC driver"); +MODULE_AUTHOR("Karel Balej "); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c index 02f7d071128772..d2b60487d4623e 100644 --- a/drivers/rtc/rtc-ab-eoz9.c +++ b/drivers/rtc/rtc-ab-eoz9.c @@ -64,7 +64,7 @@ #define ABEOZ9_BIT_ALARM_MIN GENMASK(6, 0) #define ABEOZ9_REG_ALARM_HOURS 0x12 #define ABEOZ9_BIT_ALARM_HOURS_PM BIT(5) -#define ABEOZ9_BIT_ALARM_HOURS GENMASK(4, 0) +#define ABEOZ9_BIT_ALARM_HOURS GENMASK(5, 0) #define ABEOZ9_REG_ALARM_DAYS 0x13 #define ABEOZ9_BIT_ALARM_DAYS GENMASK(5, 0) #define ABEOZ9_REG_ALARM_WEEKDAYS 0x14 @@ -231,8 +231,6 @@ static int abeoz9_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) alarm->time.tm_sec = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_SEC, regs[0])); alarm->time.tm_min = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_MIN, regs[1])); alarm->time.tm_hour = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_HOURS, regs[2])); - if (FIELD_GET(ABEOZ9_BIT_ALARM_HOURS_PM, regs[2])) - alarm->time.tm_hour += 12; alarm->time.tm_mday = bcd2bin(FIELD_GET(ABEOZ9_BIT_ALARM_DAYS, regs[3])); @@ -396,13 +394,6 @@ static int abeoz9z3_temp_read(struct device *dev, if (ret < 0) return ret; - if ((val & ABEOZ9_REG_CTRL_STATUS_V1F) || - (val & ABEOZ9_REG_CTRL_STATUS_V2F)) { - dev_err(dev, - "thermometer might be disabled due to low voltage\n"); - return -EINVAL; - } - switch (attr) { case hwmon_temp_input: ret = regmap_read(regmap, ABEOZ9_REG_REG_TEMP, &val); diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 75bb2ac9005c26..2dcda96f4a8ef7 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -403,7 +403,7 @@ static struct platform_driver ab8500_rtc_driver = { .name = "ab8500-rtc", }, .probe = ab8500_rtc_probe, - .remove_new = ab8500_rtc_remove, + .remove = ab8500_rtc_remove, .id_table = ab85xx_rtc_ids, }; diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 1298962402ff47..3fee27914ba805 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -39,7 +39,7 @@ #define ABX8XX_REG_STATUS 0x0f #define ABX8XX_STATUS_AF BIT(2) #define ABX8XX_STATUS_BLF BIT(4) -#define ABX8XX_STATUS_WDT BIT(6) +#define ABX8XX_STATUS_WDT BIT(5) #define ABX8XX_REG_CTRL1 0x10 #define ABX8XX_CTRL_WRITE BIT(0) diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index fa642bba3cee00..33626311fa781b 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -628,7 +628,7 @@ MODULE_DEVICE_TABLE(of, ac100_rtc_match); static struct platform_driver ac100_rtc_driver = { .probe = ac100_rtc_probe, - .remove_new = ac100_rtc_remove, + .remove = ac100_rtc_remove, .driver = { .name = "ac100-rtc", .of_match_table = of_match_ptr(ac100_rtc_match), diff --git a/drivers/rtc/rtc-amlogic-a4.c b/drivers/rtc/rtc-amlogic-a4.c new file mode 100644 index 00000000000000..2278b4c98a711f --- /dev/null +++ b/drivers/rtc/rtc-amlogic-a4.c @@ -0,0 +1,465 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Copyright (C) 2024 Amlogic, Inc. All rights reserved + * Author: Yiting Deng + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* rtc oscillator rate */ +#define OSC_32K 32768 +#define OSC_24M 24000000 + +#define RTC_CTRL (0x0 << 2) /* Control RTC */ +#define RTC_ALRM0_EN BIT(0) +#define RTC_OSC_SEL BIT(8) +#define RTC_ENABLE BIT(12) + +#define RTC_COUNTER_REG (0x1 << 2) /* Program RTC counter initial value */ + +#define RTC_ALARM0_REG (0x2 << 2) /* Program RTC alarm0 value */ + +#define RTC_SEC_ADJUST_REG (0x6 << 2) /* Control second-based timing adjustment */ +#define RTC_MATCH_COUNTER GENMASK(18, 0) +#define RTC_SEC_ADJUST_CTRL GENMASK(20, 19) +#define RTC_ADJ_VALID BIT(23) + +#define RTC_INT_MASK (0x8 << 2) /* RTC interrupt mask */ +#define RTC_ALRM0_IRQ_MSK BIT(0) + +#define RTC_INT_CLR (0x9 << 2) /* Clear RTC interrupt */ +#define RTC_ALRM0_IRQ_CLR BIT(0) + +#define RTC_OSCIN_CTRL0 (0xa << 2) /* Control RTC clk from 24M */ +#define RTC_OSCIN_CTRL1 (0xb << 2) /* Control RTC clk from 24M */ +#define RTC_OSCIN_IN_EN BIT(31) +#define RTC_OSCIN_OUT_CFG GENMASK(29, 28) +#define RTC_OSCIN_OUT_N0M0 GENMASK(11, 0) +#define RTC_OSCIN_OUT_N1M1 GENMASK(23, 12) + +#define RTC_INT_STATUS (0xc << 2) /* RTC interrupt status */ +#define RTC_ALRM0_IRQ_STATUS BIT(0) + +#define RTC_REAL_TIME (0xd << 2) /* RTC time value */ + +#define RTC_OSCIN_OUT_32K_N0 0x2dc +#define RTC_OSCIN_OUT_32K_N1 0x2db +#define RTC_OSCIN_OUT_32K_M0 0x1 +#define RTC_OSCIN_OUT_32K_M1 0x2 + +#define RTC_SWALLOW_SECOND 0x2 +#define RTC_INSERT_SECOND 0x3 + +struct aml_rtc_config { + bool gray_stored; +}; + +struct aml_rtc_data { + struct regmap *map; + struct rtc_device *rtc_dev; + int irq; + struct clk *rtc_clk; + struct clk *sys_clk; + int rtc_enabled; + const struct aml_rtc_config *config; +}; + +static const struct regmap_config aml_rtc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = RTC_REAL_TIME, +}; + +static inline u32 gray_to_binary(u32 gray) +{ + u32 bcd = gray; + int size = sizeof(bcd) * 8; + int i; + + for (i = 0; (1 << i) < size; i++) + bcd ^= bcd >> (1 << i); + + return bcd; +} + +static inline u32 binary_to_gray(u32 bcd) +{ + return bcd ^ (bcd >> 1); +} + +static int aml_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + u32 time_sec; + + /* if RTC disabled, read time failed */ + if (!rtc->rtc_enabled) + return -EINVAL; + + regmap_read(rtc->map, RTC_REAL_TIME, &time_sec); + if (rtc->config->gray_stored) + time_sec = gray_to_binary(time_sec); + rtc_time64_to_tm(time_sec, tm); + dev_dbg(dev, "%s: read time = %us\n", __func__, time_sec); + + return 0; +} + +static int aml_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + u32 time_sec; + + /* if RTC disabled, first enable it */ + if (!rtc->rtc_enabled) { + regmap_write_bits(rtc->map, RTC_CTRL, RTC_ENABLE, RTC_ENABLE); + usleep_range(100, 200); + rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE); + if (!rtc->rtc_enabled) + return -EINVAL; + } + + time_sec = rtc_tm_to_time64(tm); + if (rtc->config->gray_stored) + time_sec = binary_to_gray(time_sec); + regmap_write(rtc->map, RTC_COUNTER_REG, time_sec); + dev_dbg(dev, "%s: set time = %us\n", __func__, time_sec); + + return 0; +} + +static int aml_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + time64_t alarm_sec; + + /* if RTC disabled, set alarm failed */ + if (!rtc->rtc_enabled) + return -EINVAL; + + regmap_update_bits(rtc->map, RTC_CTRL, + RTC_ALRM0_EN, RTC_ALRM0_EN); + regmap_update_bits(rtc->map, RTC_INT_MASK, + RTC_ALRM0_IRQ_MSK, 0); + + alarm_sec = rtc_tm_to_time64(&alarm->time); + if (rtc->config->gray_stored) + alarm_sec = binary_to_gray(alarm_sec); + regmap_write(rtc->map, RTC_ALARM0_REG, alarm_sec); + + dev_dbg(dev, "%s: alarm->enabled=%d alarm_set=%llds\n", __func__, + alarm->enabled, alarm_sec); + + return 0; +} + +static int aml_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + u32 alarm_sec; + int alarm_enable; + int alarm_mask; + + /* if RTC disabled, read alarm failed */ + if (!rtc->rtc_enabled) + return -EINVAL; + + regmap_read(rtc->map, RTC_ALARM0_REG, &alarm_sec); + if (rtc->config->gray_stored) + alarm_sec = gray_to_binary(alarm_sec); + rtc_time64_to_tm(alarm_sec, &alarm->time); + + alarm_enable = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN); + alarm_mask = regmap_test_bits(rtc->map, RTC_INT_MASK, RTC_ALRM0_IRQ_MSK); + alarm->enabled = (alarm_enable && !alarm_mask) ? 1 : 0; + dev_dbg(dev, "%s: alarm->enabled=%d alarm=%us\n", __func__, + alarm->enabled, alarm_sec); + + return 0; +} + +static int aml_rtc_read_offset(struct device *dev, long *offset) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + u32 reg_val; + long val; + int sign, match_counter, enable; + + /* if RTC disabled, read offset failed */ + if (!rtc->rtc_enabled) + return -EINVAL; + + regmap_read(rtc->map, RTC_SEC_ADJUST_REG, ®_val); + enable = FIELD_GET(RTC_ADJ_VALID, reg_val); + if (!enable) { + val = 0; + } else { + sign = FIELD_GET(RTC_SEC_ADJUST_CTRL, reg_val); + match_counter = FIELD_GET(RTC_MATCH_COUNTER, reg_val); + val = 1000000000 / (match_counter + 1); + if (sign == RTC_SWALLOW_SECOND) + val = -val; + } + *offset = val; + + return 0; +} + +static int aml_rtc_set_offset(struct device *dev, long offset) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + int sign = 0; + int match_counter = 0; + int enable = 0; + u32 reg_val; + + /* if RTC disabled, set offset failed */ + if (!rtc->rtc_enabled) + return -EINVAL; + + if (offset) { + enable = 1; + sign = offset < 0 ? RTC_SWALLOW_SECOND : RTC_INSERT_SECOND; + match_counter = 1000000000 / abs(offset) - 1; + if (match_counter < 0 || match_counter > RTC_MATCH_COUNTER) + return -EINVAL; + } + + reg_val = FIELD_PREP(RTC_ADJ_VALID, enable) | + FIELD_PREP(RTC_SEC_ADJUST_CTRL, sign) | + FIELD_PREP(RTC_MATCH_COUNTER, match_counter); + regmap_write(rtc->map, RTC_SEC_ADJUST_REG, reg_val); + + return 0; +} + +static int aml_rtc_alarm_enable(struct device *dev, unsigned int enabled) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + + if (enabled) { + regmap_update_bits(rtc->map, RTC_CTRL, + RTC_ALRM0_EN, RTC_ALRM0_EN); + regmap_update_bits(rtc->map, RTC_INT_MASK, + RTC_ALRM0_IRQ_MSK, 0); + } else { + regmap_update_bits(rtc->map, RTC_INT_MASK, + RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK); + regmap_update_bits(rtc->map, RTC_CTRL, + RTC_ALRM0_EN, 0); + } + + return 0; +} + +static const struct rtc_class_ops aml_rtc_ops = { + .read_time = aml_rtc_read_time, + .set_time = aml_rtc_set_time, + .read_alarm = aml_rtc_read_alarm, + .set_alarm = aml_rtc_set_alarm, + .alarm_irq_enable = aml_rtc_alarm_enable, + .read_offset = aml_rtc_read_offset, + .set_offset = aml_rtc_set_offset, +}; + +static irqreturn_t aml_rtc_handler(int irq, void *data) +{ + struct aml_rtc_data *rtc = (struct aml_rtc_data *)data; + + regmap_write(rtc->map, RTC_ALARM0_REG, 0); + regmap_write(rtc->map, RTC_INT_CLR, RTC_ALRM0_IRQ_STATUS); + + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); + + return IRQ_HANDLED; +} + +static void aml_rtc_init(struct aml_rtc_data *rtc) +{ + u32 reg_val = 0; + + rtc->rtc_enabled = regmap_test_bits(rtc->map, RTC_CTRL, RTC_ENABLE); + if (!rtc->rtc_enabled) { + if (clk_get_rate(rtc->rtc_clk) == OSC_24M) { + /* select 24M oscillator */ + regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, RTC_OSC_SEL); + + /* + * Set RTC oscillator to freq_out to freq_in/((N0*M0+N1*M1)/(M0+M1)) + * Enable clock_in gate of oscillator 24MHz + * Set N0 to 733, N1 to 732 + */ + reg_val = FIELD_PREP(RTC_OSCIN_IN_EN, 1) + | FIELD_PREP(RTC_OSCIN_OUT_CFG, 1) + | FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_N0) + | FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_N1); + regmap_write_bits(rtc->map, RTC_OSCIN_CTRL0, RTC_OSCIN_IN_EN + | RTC_OSCIN_OUT_CFG | RTC_OSCIN_OUT_N0M0 + | RTC_OSCIN_OUT_N1M1, reg_val); + + /* Set M0 to 2, M1 to 3, so freq_out = 32768 Hz*/ + reg_val = FIELD_PREP(RTC_OSCIN_OUT_N0M0, RTC_OSCIN_OUT_32K_M0) + | FIELD_PREP(RTC_OSCIN_OUT_N1M1, RTC_OSCIN_OUT_32K_M1); + regmap_write_bits(rtc->map, RTC_OSCIN_CTRL1, RTC_OSCIN_OUT_N0M0 + | RTC_OSCIN_OUT_N1M1, reg_val); + } else { + /* select 32K oscillator */ + regmap_write_bits(rtc->map, RTC_CTRL, RTC_OSC_SEL, 0); + } + } + regmap_write_bits(rtc->map, RTC_INT_MASK, + RTC_ALRM0_IRQ_MSK, RTC_ALRM0_IRQ_MSK); + regmap_write_bits(rtc->map, RTC_CTRL, RTC_ALRM0_EN, 0); +} + +static int aml_rtc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct aml_rtc_data *rtc; + void __iomem *base; + int ret = 0; + + rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + rtc->config = of_device_get_match_data(dev); + if (!rtc->config) + return -ENODEV; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), "resource ioremap failed\n"); + + rtc->map = devm_regmap_init_mmio(dev, base, &aml_rtc_regmap_config); + if (IS_ERR(rtc->map)) + return dev_err_probe(dev, PTR_ERR(rtc->map), "regmap init failed\n"); + + rtc->irq = platform_get_irq(pdev, 0); + if (rtc->irq < 0) + return rtc->irq; + + rtc->rtc_clk = devm_clk_get(dev, "osc"); + if (IS_ERR(rtc->rtc_clk)) + return dev_err_probe(dev, PTR_ERR(rtc->rtc_clk), + "failed to find rtc clock\n"); + if (clk_get_rate(rtc->rtc_clk) != OSC_32K && clk_get_rate(rtc->rtc_clk) != OSC_24M) + return dev_err_probe(dev, -EINVAL, "Invalid clock configuration\n"); + + rtc->sys_clk = devm_clk_get_enabled(dev, "sys"); + if (IS_ERR(rtc->sys_clk)) + return dev_err_probe(dev, PTR_ERR(rtc->sys_clk), + "failed to get_enable rtc sys clk\n"); + aml_rtc_init(rtc); + + device_init_wakeup(dev, 1); + platform_set_drvdata(pdev, rtc); + + rtc->rtc_dev = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc->rtc_dev)) { + ret = PTR_ERR(rtc->rtc_dev); + goto err_clk; + } + + ret = devm_request_irq(dev, rtc->irq, aml_rtc_handler, + IRQF_ONESHOT, "aml-rtc alarm", rtc); + if (ret) { + dev_err_probe(dev, ret, "IRQ%d request failed, ret = %d\n", + rtc->irq, ret); + goto err_clk; + } + + rtc->rtc_dev->ops = &aml_rtc_ops; + rtc->rtc_dev->range_min = 0; + rtc->rtc_dev->range_max = U32_MAX; + + ret = devm_rtc_register_device(rtc->rtc_dev); + if (ret) { + dev_err_probe(&pdev->dev, ret, "Failed to register RTC device: %d\n", ret); + goto err_clk; + } + + return 0; +err_clk: + clk_disable_unprepare(rtc->sys_clk); + device_init_wakeup(dev, 0); + + return ret; +} + +#ifdef CONFIG_PM_SLEEP +static int aml_rtc_suspend(struct device *dev) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->irq); + + return 0; +} + +static int aml_rtc_resume(struct device *dev) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(aml_rtc_pm_ops, + aml_rtc_suspend, aml_rtc_resume); + +static void aml_rtc_remove(struct platform_device *pdev) +{ + struct aml_rtc_data *rtc = dev_get_drvdata(&pdev->dev); + + clk_disable_unprepare(rtc->sys_clk); + device_init_wakeup(&pdev->dev, 0); +} + +static const struct aml_rtc_config a5_rtc_config = { +}; + +static const struct aml_rtc_config a4_rtc_config = { + .gray_stored = true, +}; + +static const struct of_device_id aml_rtc_device_id[] = { + { + .compatible = "amlogic,a4-rtc", + .data = &a4_rtc_config, + }, + { + .compatible = "amlogic,a5-rtc", + .data = &a5_rtc_config, + }, + { } +}; +MODULE_DEVICE_TABLE(of, aml_rtc_device_id); + +static struct platform_driver aml_rtc_driver = { + .probe = aml_rtc_probe, + .remove = aml_rtc_remove, + .driver = { + .name = "aml-rtc", + .pm = &aml_rtc_pm_ops, + .of_match_table = aml_rtc_device_id, + }, +}; + +module_platform_driver(aml_rtc_driver); +MODULE_DESCRIPTION("Amlogic RTC driver"); +MODULE_AUTHOR("Yiting Deng "); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-asm9260.c b/drivers/rtc/rtc-asm9260.c index a83b47e0d8f532..705470ae84280f 100644 --- a/drivers/rtc/rtc-asm9260.c +++ b/drivers/rtc/rtc-asm9260.c @@ -325,7 +325,7 @@ MODULE_DEVICE_TABLE(of, asm9260_dt_ids); static struct platform_driver asm9260_rtc_driver = { .probe = asm9260_rtc_probe, - .remove_new = asm9260_rtc_remove, + .remove = asm9260_rtc_remove, .driver = { .name = "asm9260-rtc", .of_match_table = asm9260_dt_ids, diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index c16fe711a0d94f..9b3898b8de7cf7 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -640,7 +640,7 @@ static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); * triggering a section mismatch warning. */ static struct platform_driver at91_rtc_driver __refdata = { - .remove_new = __exit_p(at91_rtc_remove), + .remove = __exit_p(at91_rtc_remove), .shutdown = at91_rtc_shutdown, .driver = { .name = "at91_rtc", diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 993c0878fb6606..15b21da2788f63 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -530,7 +530,7 @@ MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); static struct platform_driver at91_rtc_driver = { .probe = at91_rtc_probe, - .remove_new = at91_rtc_remove, + .remove = at91_rtc_remove, .shutdown = at91_rtc_shutdown, .driver = { .name = "rtc-at91sam9", diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c index 59b627fc1ecfa0..954ac4ef53e835 100644 --- a/drivers/rtc/rtc-bd70528.c +++ b/drivers/rtc/rtc-bd70528.c @@ -236,7 +236,6 @@ static int bd70528_probe(struct platform_device *pdev) { struct bd70528_rtc *bd_rtc; const struct rtc_class_ops *rtc_ops; - const char *irq_name; int ret; struct rtc_device *rtc; int irq; @@ -259,7 +258,6 @@ static int bd70528_probe(struct platform_device *pdev) switch (chip) { case ROHM_CHIP_TYPE_BD71815: - irq_name = "bd71815-rtc-alm-0"; bd_rtc->reg_time_start = BD71815_REG_RTC_START; /* @@ -276,7 +274,6 @@ static int bd70528_probe(struct platform_device *pdev) hour_reg = BD71815_REG_HOUR; break; case ROHM_CHIP_TYPE_BD71828: - irq_name = "bd71828-rtc-alm-0"; bd_rtc->reg_time_start = BD71828_REG_RTC_START; bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START; hour_reg = BD71828_REG_RTC_HOUR; @@ -286,7 +283,7 @@ static int bd70528_probe(struct platform_device *pdev) return -ENOENT; } - irq = platform_get_irq_byname(pdev, irq_name); + irq = platform_get_irq_byname(pdev, "bd70528-rtc-alm-0"); if (irq < 0) return irq; diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index 1a65a4e0dc0035..fb47c32ab5ff4f 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -417,7 +416,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_new = brcmstb_waketmr_remove, + .remove = 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 4ca60b51983650..bf2a9a1fdea744 100644 --- a/drivers/rtc/rtc-cadence.c +++ b/drivers/rtc/rtc-cadence.c @@ -402,7 +402,7 @@ static struct platform_driver cdns_rtc_driver = { .pm = &cdns_rtc_pm_ops, }, .probe = cdns_rtc_probe, - .remove_new = cdns_rtc_remove, + .remove = cdns_rtc_remove, }; module_platform_driver(cdns_rtc_driver); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 35dca2accbb8df..78f2ce12c75a77 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -645,18 +645,17 @@ static int cmos_nvram_read(void *priv, unsigned int off, void *val, unsigned char *buf = val; off += NVRAM_OFFSET; - spin_lock_irq(&rtc_lock); - for (; count; count--, off++) { + for (; count; count--, off++, buf++) { + guard(spinlock_irq)(&rtc_lock); if (off < 128) - *buf++ = CMOS_READ(off); + *buf = CMOS_READ(off); else if (can_bank2) - *buf++ = cmos_read_bank2(off); + *buf = cmos_read_bank2(off); else - break; + return -EIO; } - spin_unlock_irq(&rtc_lock); - return count ? -EIO : 0; + return 0; } static int cmos_nvram_write(void *priv, unsigned int off, void *val, @@ -671,23 +670,23 @@ static int cmos_nvram_write(void *priv, unsigned int off, void *val, * NVRAM to update, updating checksums is also part of its job. */ off += NVRAM_OFFSET; - spin_lock_irq(&rtc_lock); - for (; count; count--, off++) { + for (; count; count--, off++, buf++) { /* don't trash RTC registers */ if (off == cmos->day_alrm || off == cmos->mon_alrm || off == cmos->century) - buf++; - else if (off < 128) - CMOS_WRITE(*buf++, off); + continue; + + guard(spinlock_irq)(&rtc_lock); + if (off < 128) + CMOS_WRITE(*buf, off); else if (can_bank2) - cmos_write_bank2(*buf++, off); + cmos_write_bank2(*buf, off); else - break; + return -EIO; } - spin_unlock_irq(&rtc_lock); - return count ? -EIO : 0; + return 0; } /*----------------------------------------------------------------*/ @@ -1528,7 +1527,7 @@ static void cmos_platform_shutdown(struct platform_device *pdev) MODULE_ALIAS("platform:rtc_cmos"); static struct platform_driver cmos_platform_driver = { - .remove_new = cmos_platform_remove, + .remove = 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 f57462c7b2c64f..60a48c3ba3ca50 100644 --- a/drivers/rtc/rtc-cros-ec.c +++ b/drivers/rtc/rtc-cros-ec.c @@ -401,7 +401,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_rtc_id); static struct platform_driver cros_ec_rtc_driver = { .probe = cros_ec_rtc_probe, - .remove_new = cros_ec_rtc_remove, + .remove = cros_ec_rtc_remove, .driver = { .name = DRV_NAME, .pm = &cros_ec_rtc_pm_ops, diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 04dbf35cf3b706..38e25f63597ab7 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -1354,7 +1354,7 @@ static struct platform_driver ds1685_rtc_driver = { .name = "rtc-ds1685", }, .probe = ds1685_rtc_probe, - .remove_new = ds1685_rtc_remove, + .remove = ds1685_rtc_remove, }; module_platform_driver(ds1685_rtc_driver); /* ----------------------------------------------------------------------- */ diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c index 8bfe7378f6533f..cb4a5d101f537e 100644 --- a/drivers/rtc/rtc-ftrtc010.c +++ b/drivers/rtc/rtc-ftrtc010.c @@ -214,7 +214,7 @@ static struct platform_driver ftrtc010_rtc_driver = { .of_match_table = ftrtc010_rtc_dt_match, }, .probe = ftrtc010_rtc_probe, - .remove_new = ftrtc010_rtc_remove, + .remove = 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 b81cea505ee93f..6228d0b2486e9f 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -319,11 +319,11 @@ static struct platform_driver hid_time_platform_driver = { .name = KBUILD_MODNAME, }, .probe = hid_time_probe, - .remove_new = hid_time_remove, + .remove = hid_time_remove, }; module_platform_driver(hid_time_platform_driver); MODULE_DESCRIPTION("HID Sensor Time"); MODULE_AUTHOR("Alexander Holler "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(IIO_HID); +MODULE_IMPORT_NS("IIO_HID"); diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 284011c419db97..ca4a0af95e8c5a 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -860,7 +860,7 @@ static struct platform_driver dryice_rtc_driver __refdata = { .name = "imxdi_rtc", .of_match_table = dryice_dt_ids, }, - .remove_new = __exit_p(dryice_rtc_remove), + .remove = __exit_p(dryice_rtc_remove), }; module_platform_driver_probe(dryice_rtc_driver, dryice_rtc_probe); diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 6fa9a68af9d980..9b44839a7402c9 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -21,7 +21,7 @@ #include -/* ISL register offsets */ +/* RTC - Real time clock registers */ #define ISL12022_REG_SC 0x00 #define ISL12022_REG_MN 0x01 #define ISL12022_REG_HR 0x02 @@ -30,21 +30,36 @@ #define ISL12022_REG_YR 0x05 #define ISL12022_REG_DW 0x06 +/* CSR - Control and status registers */ #define ISL12022_REG_SR 0x07 #define ISL12022_REG_INT 0x08 - #define ISL12022_REG_PWR_VBAT 0x0a - #define ISL12022_REG_BETA 0x0d + +/* ALARM - Alarm registers */ +#define ISL12022_REG_SCA0 0x10 +#define ISL12022_REG_MNA0 0x11 +#define ISL12022_REG_HRA0 0x12 +#define ISL12022_REG_DTA0 0x13 +#define ISL12022_REG_MOA0 0x14 +#define ISL12022_REG_DWA0 0x15 +#define ISL12022_ALARM ISL12022_REG_SCA0 +#define ISL12022_ALARM_LEN (ISL12022_REG_DWA0 - ISL12022_REG_SCA0 + 1) + +/* TEMP - Temperature sensor registers */ #define ISL12022_REG_TEMP_L 0x28 /* ISL register bits */ #define ISL12022_HR_MIL (1 << 7) /* military or 24 hour time */ +#define ISL12022_SR_ALM (1 << 4) #define ISL12022_SR_LBAT85 (1 << 2) #define ISL12022_SR_LBAT75 (1 << 1) +#define ISL12022_INT_ARST (1 << 7) #define ISL12022_INT_WRTC (1 << 6) +#define ISL12022_INT_IM (1 << 5) +#define ISL12022_INT_FOBATB (1 << 4) #define ISL12022_INT_FO_MASK GENMASK(3, 0) #define ISL12022_INT_FO_OFF 0x0 #define ISL12022_INT_FO_32K 0x1 @@ -52,8 +67,19 @@ #define ISL12022_REG_VB85_MASK GENMASK(5, 3) #define ISL12022_REG_VB75_MASK GENMASK(2, 0) +#define ISL12022_ALARM_ENABLE (1 << 7) /* for all ALARM registers */ + #define ISL12022_BETA_TSE (1 << 7) +static struct i2c_driver isl12022_driver; + +struct isl12022 { + struct rtc_device *rtc; + struct regmap *regmap; + int irq; + bool irq_enabled; +}; + static umode_t isl12022_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -116,7 +142,8 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = { static void isl12022_hwmon_register(struct device *dev) { - struct regmap *regmap = dev_get_drvdata(dev); + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; struct device *hwmon; int ret; @@ -143,8 +170,9 @@ static void isl12022_hwmon_register(struct device *dev) */ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct regmap *regmap = dev_get_drvdata(dev); - uint8_t buf[ISL12022_REG_INT + 1]; + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; + u8 buf[ISL12022_REG_INT + 1]; int ret; ret = regmap_bulk_read(regmap, ISL12022_REG_SC, buf, sizeof(buf)); @@ -178,9 +206,10 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct regmap *regmap = dev_get_drvdata(dev); + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; int ret; - uint8_t buf[ISL12022_REG_DW + 1]; + u8 buf[ISL12022_REG_DW + 1]; dev_dbg(dev, "%s: %ptR\n", __func__, tm); @@ -208,9 +237,198 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf)); } +static int isl12022_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct rtc_time *tm = &alarm->time; + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; + u8 buf[ISL12022_ALARM_LEN]; + unsigned int i, yr; + int ret; + + ret = regmap_bulk_read(regmap, ISL12022_ALARM, buf, sizeof(buf)); + if (ret) { + dev_dbg(dev, "%s: reading ALARM registers failed\n", + __func__); + return ret; + } + + /* The alarm doesn't store the year so get it from the rtc section */ + ret = regmap_read(regmap, ISL12022_REG_YR, &yr); + if (ret) { + dev_dbg(dev, "%s: reading YR register failed\n", __func__); + return ret; + } + + dev_dbg(dev, + "%s: sc=%02x, mn=%02x, hr=%02x, dt=%02x, mo=%02x, dw=%02x yr=%u\n", + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], yr); + + tm->tm_sec = bcd2bin(buf[ISL12022_REG_SCA0 - ISL12022_ALARM] & 0x7F); + tm->tm_min = bcd2bin(buf[ISL12022_REG_MNA0 - ISL12022_ALARM] & 0x7F); + tm->tm_hour = bcd2bin(buf[ISL12022_REG_HRA0 - ISL12022_ALARM] & 0x3F); + tm->tm_mday = bcd2bin(buf[ISL12022_REG_DTA0 - ISL12022_ALARM] & 0x3F); + tm->tm_mon = bcd2bin(buf[ISL12022_REG_MOA0 - ISL12022_ALARM] & 0x1F) - 1; + tm->tm_wday = buf[ISL12022_REG_DWA0 - ISL12022_ALARM] & 0x07; + tm->tm_year = bcd2bin(yr) + 100; + + for (i = 0; i < ISL12022_ALARM_LEN; i++) { + if (buf[i] & ISL12022_ALARM_ENABLE) { + alarm->enabled = 1; + break; + } + } + + dev_dbg(dev, "%s: %ptR\n", __func__, tm); + + return 0; +} + +static int isl12022_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct rtc_time *alarm_tm = &alarm->time; + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; + u8 regs[ISL12022_ALARM_LEN] = { 0, }; + struct rtc_time rtc_tm; + int ret, enable, dw; + + ret = isl12022_rtc_read_time(dev, &rtc_tm); + if (ret) + return ret; + + /* If the alarm time is before the current time disable the alarm */ + if (!alarm->enabled || rtc_tm_sub(alarm_tm, &rtc_tm) <= 0) + enable = 0; + else + enable = ISL12022_ALARM_ENABLE; + + /* + * Set non-matching day of the week to safeguard against early false + * matching while setting all the alarm registers (this rtc lacks a + * general alarm/irq enable/disable bit). + */ + ret = regmap_read(regmap, ISL12022_REG_DW, &dw); + if (ret) { + dev_dbg(dev, "%s: reading DW failed\n", __func__); + return ret; + } + /* ~4 days into the future should be enough to avoid match */ + dw = ((dw + 4) % 7) | ISL12022_ALARM_ENABLE; + ret = regmap_write(regmap, ISL12022_REG_DWA0, dw); + if (ret) { + dev_dbg(dev, "%s: writing DWA0 failed\n", __func__); + return ret; + } + + /* Program the alarm and enable it for each setting */ + regs[ISL12022_REG_SCA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_sec) | enable; + regs[ISL12022_REG_MNA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_min) | enable; + regs[ISL12022_REG_HRA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_hour) | enable; + regs[ISL12022_REG_DTA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_mday) | enable; + regs[ISL12022_REG_MOA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_mon + 1) | enable; + regs[ISL12022_REG_DWA0 - ISL12022_ALARM] = bin2bcd(alarm_tm->tm_wday & 7) | enable; + + /* write ALARM registers */ + ret = regmap_bulk_write(regmap, ISL12022_ALARM, ®s, sizeof(regs)); + if (ret) { + dev_dbg(dev, "%s: writing ALARM registers failed\n", __func__); + return ret; + } + + return 0; +} + +static irqreturn_t isl12022_rtc_interrupt(int irq, void *data) +{ + struct isl12022 *isl12022 = data; + struct rtc_device *rtc = isl12022->rtc; + struct device *dev = &rtc->dev; + struct regmap *regmap = isl12022->regmap; + u32 val = 0; + unsigned long events = 0; + int ret; + + ret = regmap_read(regmap, ISL12022_REG_SR, &val); + if (ret) { + dev_dbg(dev, "%s: reading SR failed\n", __func__); + return IRQ_HANDLED; + } + + if (val & ISL12022_SR_ALM) + events |= RTC_IRQF | RTC_AF; + + if (events & RTC_AF) + dev_dbg(dev, "alarm!\n"); + + if (!events) + return IRQ_NONE; + + rtc_update_irq(rtc, 1, events); + return IRQ_HANDLED; +} + +static int isl12022_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct isl12022 *isl12022 = dev_get_drvdata(dev); + + /* Make sure enabled is 0 or 1 */ + enabled = !!enabled; + + if (isl12022->irq_enabled == enabled) + return 0; + + if (enabled) + enable_irq(isl12022->irq); + else + disable_irq(isl12022->irq); + + isl12022->irq_enabled = enabled; + + return 0; +} + +static int isl12022_setup_irq(struct device *dev, int irq) +{ + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; + unsigned int reg_mask, reg_val; + u8 buf[ISL12022_ALARM_LEN] = { 0, }; + int ret; + + /* Clear and disable all alarm registers */ + ret = regmap_bulk_write(regmap, ISL12022_ALARM, buf, sizeof(buf)); + if (ret) + return ret; + + /* + * Enable automatic reset of ALM bit and enable single event interrupt + * mode. + */ + reg_mask = ISL12022_INT_ARST | ISL12022_INT_IM | ISL12022_INT_FO_MASK; + reg_val = ISL12022_INT_ARST | ISL12022_INT_FO_OFF; + ret = regmap_write_bits(regmap, ISL12022_REG_INT, + reg_mask, reg_val); + if (ret) + return ret; + + ret = devm_request_threaded_irq(dev, irq, NULL, + isl12022_rtc_interrupt, + IRQF_SHARED | IRQF_ONESHOT, + isl12022_driver.driver.name, + isl12022); + if (ret) + return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); + + isl12022->irq = irq; + return 0; +} + static int isl12022_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - struct regmap *regmap = dev_get_drvdata(dev); + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; u32 user, val; int ret; @@ -238,6 +456,9 @@ static const struct rtc_class_ops isl12022_rtc_ops = { .ioctl = isl12022_rtc_ioctl, .read_time = isl12022_rtc_read_time, .set_time = isl12022_rtc_set_time, + .read_alarm = isl12022_rtc_read_alarm, + .set_alarm = isl12022_rtc_set_alarm, + .alarm_irq_enable = isl12022_rtc_alarm_irq_enable, }; static const struct regmap_config regmap_config = { @@ -248,7 +469,8 @@ static const struct regmap_config regmap_config = { static int isl12022_register_clock(struct device *dev) { - struct regmap *regmap = dev_get_drvdata(dev); + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; struct clk_hw *hw; int ret; @@ -288,7 +510,8 @@ static const u32 trip_levels[2][7] = { static void isl12022_set_trip_levels(struct device *dev) { - struct regmap *regmap = dev_get_drvdata(dev); + struct isl12022 *isl12022 = dev_get_drvdata(dev); + struct regmap *regmap = isl12022->regmap; u32 levels[2] = {0, 0}; int ret, i, j, x[2]; u8 val, mask; @@ -325,6 +548,7 @@ static void isl12022_set_trip_levels(struct device *dev) static int isl12022_probe(struct i2c_client *client) { + struct isl12022 *isl12022; struct rtc_device *rtc; struct regmap *regmap; int ret; @@ -332,13 +556,17 @@ static int isl12022_probe(struct i2c_client *client) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; + /* Allocate driver state */ + isl12022 = devm_kzalloc(&client->dev, sizeof(*isl12022), GFP_KERNEL); + if (!isl12022) + return -ENOMEM; + regmap = devm_regmap_init_i2c(client, ®map_config); - if (IS_ERR(regmap)) { - dev_err(&client->dev, "regmap allocation failed\n"); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(&client->dev, PTR_ERR(regmap), "regmap allocation failed\n"); + isl12022->regmap = regmap; - dev_set_drvdata(&client->dev, regmap); + dev_set_drvdata(&client->dev, isl12022); ret = isl12022_register_clock(&client->dev); if (ret) @@ -350,11 +578,20 @@ static int isl12022_probe(struct i2c_client *client) rtc = devm_rtc_allocate_device(&client->dev); if (IS_ERR(rtc)) return PTR_ERR(rtc); + isl12022->rtc = rtc; rtc->ops = &isl12022_rtc_ops; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_max = RTC_TIMESTAMP_END_2099; + if (client->irq > 0) { + ret = isl12022_setup_irq(&client->dev, client->irq); + if (ret) + return ret; + } else { + clear_bit(RTC_FEATURE_ALARM, rtc->features); + } + return devm_rtc_register_device(rtc); } diff --git a/drivers/rtc/rtc-loongson.c b/drivers/rtc/rtc-loongson.c index e8ffc1ab90b02f..8d713e563d7c0a 100644 --- a/drivers/rtc/rtc-loongson.c +++ b/drivers/rtc/rtc-loongson.c @@ -381,7 +381,7 @@ MODULE_DEVICE_TABLE(acpi, loongson_rtc_acpi_match); static struct platform_driver loongson_rtc_driver = { .probe = loongson_rtc_probe, - .remove_new = loongson_rtc_remove, + .remove = loongson_rtc_remove, .driver = { .name = "loongson-rtc", .of_match_table = loongson_rtc_of_match, diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c index df17c48ff086ee..2dcdc77ff646c9 100644 --- a/drivers/rtc/rtc-lpc24xx.c +++ b/drivers/rtc/rtc-lpc24xx.c @@ -285,7 +285,7 @@ MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match); static struct platform_driver lpc24xx_rtc_driver = { .probe = lpc24xx_rtc_probe, - .remove_new = lpc24xx_rtc_remove, + .remove = lpc24xx_rtc_remove, .driver = { .name = "lpc24xx-rtc", .of_match_table = lpc24xx_rtc_match, diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 5d30ce8e13ca03..4e608bc8bbd369 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -71,7 +71,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) /* Issue the READ command */ M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); - tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)); + tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset; /* tm_mon is 0-11 */ tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; tm->tm_mday = bcd2bin(M48T59_READ(M48T59_MDAY)); @@ -82,10 +82,6 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) dev_dbg(dev, "Century bit is enabled\n"); tm->tm_year += 100; /* one century */ } -#ifdef CONFIG_SPARC - /* Sun SPARC machines count years since 1968 */ - tm->tm_year += 68; -#endif tm->tm_wday = bcd2bin(val & 0x07); tm->tm_hour = bcd2bin(M48T59_READ(M48T59_HOUR) & 0x3F); @@ -106,12 +102,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm) struct m48t59_private *m48t59 = dev_get_drvdata(dev); unsigned long flags; u8 val = 0; - int year = tm->tm_year; - -#ifdef CONFIG_SPARC - /* Sun SPARC machines count years since 1968 */ - year -= 68; -#endif + int year = tm->tm_year - pdata->yy_offset; dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n", year + 1900, tm->tm_mon, tm->tm_mday, @@ -162,11 +153,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) /* Issue the READ command */ M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL); - tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)); -#ifdef CONFIG_SPARC - /* Sun SPARC machines count years since 1968 */ - tm->tm_year += 68; -#endif + tm->tm_year = bcd2bin(M48T59_READ(M48T59_YEAR)) + pdata->yy_offset; /* tm_mon is 0-11 */ tm->tm_mon = bcd2bin(M48T59_READ(M48T59_MONTH)) - 1; @@ -197,12 +184,7 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; u8 mday, hour, min, sec; unsigned long flags; - int year = tm->tm_year; - -#ifdef CONFIG_SPARC - /* Sun SPARC machines count years since 1968 */ - year -= 68; -#endif + int year = tm->tm_year - pdata->yy_offset; /* If no irq, we don't support ALARM */ if (m48t59->irq == NO_IRQ) diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index 35a6021d9ba4c2..a8f4b645c09d24 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -875,7 +875,7 @@ static struct platform_driver max77686_rtc_driver = { .pm = &max77686_rtc_pm_ops, }, .probe = max77686_rtc_probe, - .remove_new = max77686_rtc_remove, + .remove = max77686_rtc_remove, .id_table = rtc_id, }; diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index 763a42f422eb27..e7b87130e6248d 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable); static struct platform_driver mc13xxx_rtc_driver = { .id_table = mc13xxx_rtc_idtable, - .remove_new = mc13xxx_rtc_remove, + .remove = mc13xxx_rtc_remove, .driver = { .name = DRIVER_NAME, }, diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c index 651bf3c279c746..dbd2d5835f002c 100644 --- a/drivers/rtc/rtc-mc146818-lib.c +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -216,7 +216,7 @@ int mc146818_set_time(struct rtc_time *time) unsigned char save_control, save_freq_select; unsigned int yrs; #ifdef CONFIG_MACH_DECSTATION - unsigned int real_yrs, leap_yr; + unsigned int real_yrs; #endif unsigned char century = 0; @@ -232,8 +232,6 @@ int mc146818_set_time(struct rtc_time *time) #ifdef CONFIG_MACH_DECSTATION real_yrs = yrs; - leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || - !((yrs + 1900) % 400)); yrs = 72; /* @@ -241,7 +239,7 @@ int mc146818_set_time(struct rtc_time *time) * for non-leap years, so that Feb, 29th is handled * correctly. */ - if (!leap_yr && mon < 3) { + if (!is_leap_year(real_yrs + 1900) && mon < 3) { real_yrs--; yrs = 73; } diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 71eafe4fbc72bd..6003281316031c 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -398,7 +398,7 @@ static struct platform_driver mpc5121_rtc_driver = { .of_match_table = of_match_ptr(mpc5121_rtc_match), }, .probe = mpc5121_rtc_probe, - .remove_new = mpc5121_rtc_remove, + .remove = mpc5121_rtc_remove, }; module_platform_driver(mpc5121_rtc_driver); diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c index 5b96a6d39210cf..3892b0f9917fa7 100644 --- a/drivers/rtc/rtc-mpfs.c +++ b/drivers/rtc/rtc-mpfs.c @@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE(of, mpfs_rtc_of_match); static struct platform_driver mpfs_rtc_driver = { .probe = mpfs_rtc_probe, - .remove_new = mpfs_rtc_remove, + .remove = mpfs_rtc_remove, .driver = { .name = "mpfs_rtc", .of_match_table = mpfs_rtc_of_match, diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 1617063669cc58..152699219a2b9e 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -75,6 +75,7 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc, tm->tm_min = data[RTC_OFFSET_MIN]; tm->tm_hour = data[RTC_OFFSET_HOUR]; tm->tm_mday = data[RTC_OFFSET_DOM]; + tm->tm_wday = data[RTC_OFFSET_DOW]; tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK; tm->tm_year = data[RTC_OFFSET_YEAR]; @@ -86,9 +87,8 @@ static int __mtk_rtc_read_time(struct mt6397_rtc *rtc, static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm) { - time64_t time; struct mt6397_rtc *rtc = dev_get_drvdata(dev); - int days, sec, ret; + int sec, ret; do { ret = __mtk_rtc_read_time(rtc, tm, &sec); @@ -96,21 +96,9 @@ static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm) goto exit; } while (sec < tm->tm_sec); - /* HW register use 7 bits to store year data, minus - * RTC_MIN_YEAR_OFFSET before write year data to register, and plus - * RTC_MIN_YEAR_OFFSET back after read year from register - */ - tm->tm_year += RTC_MIN_YEAR_OFFSET; - - /* HW register start mon from one, but tm_mon start from zero. */ + /* HW register start mon/wday from one, but tm_mon/tm_wday start from zero. */ tm->tm_mon--; - time = rtc_tm_to_time64(tm); - - /* rtc_tm_to_time64 covert Gregorian date to seconds since - * 01-01-1970 00:00:00, and this date is Thursday. - */ - days = div_s64(time, 86400); - tm->tm_wday = (days + 4) % 7; + tm->tm_wday--; exit: return ret; @@ -122,13 +110,14 @@ static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm) int ret; u16 data[RTC_OFFSET_COUNT]; - tm->tm_year -= RTC_MIN_YEAR_OFFSET; tm->tm_mon++; + tm->tm_wday++; data[RTC_OFFSET_SEC] = tm->tm_sec; data[RTC_OFFSET_MIN] = tm->tm_min; data[RTC_OFFSET_HOUR] = tm->tm_hour; data[RTC_OFFSET_DOM] = tm->tm_mday; + data[RTC_OFFSET_DOW] = tm->tm_wday; data[RTC_OFFSET_MTH] = tm->tm_mon; data[RTC_OFFSET_YEAR] = tm->tm_year; @@ -178,7 +167,6 @@ static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK; tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK; - tm->tm_year += RTC_MIN_YEAR_OFFSET; tm->tm_mon--; return 0; @@ -194,7 +182,6 @@ static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) int ret; u16 data[RTC_OFFSET_COUNT]; - tm->tm_year -= RTC_MIN_YEAR_OFFSET; tm->tm_mon++; mutex_lock(&rtc->lock); @@ -302,6 +289,10 @@ static int mtk_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); rtc->rtc_dev->ops = &mtk_rtc_ops; + rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900; + rtc->rtc_dev->range_max = mktime64(2027, 12, 31, 23, 59, 59); + rtc->rtc_dev->start_secs = mktime64(1968, 1, 2, 0, 0, 0); + rtc->rtc_dev->set_start_time = true; return devm_rtc_register_device(rtc->rtc_dev); } diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c index 094c649fc137f2..4cf0cbb31a313d 100644 --- a/drivers/rtc/rtc-mt7622.c +++ b/drivers/rtc/rtc-mt7622.c @@ -394,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_new = mtk_rtc_remove, + .remove = mtk_rtc_remove, .driver = { .name = MTK_RTC_DEV, .of_match_table = mtk_rtc_match, diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index db31da56bfa74d..51029c53624418 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -308,7 +308,7 @@ MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table); * triggering a section mismatch warning. */ static struct platform_driver mv_rtc_driver __refdata = { - .remove_new = __exit_p(mv_rtc_remove), + .remove = __exit_p(mv_rtc_remove), .driver = { .name = "rtc-mv", .of_match_table = of_match_ptr(rtc_mv_of_match_table), diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c index 6934bce4b29fd5..13c041bb79f160 100644 --- a/drivers/rtc/rtc-mxc_v2.c +++ b/drivers/rtc/rtc-mxc_v2.c @@ -381,7 +381,7 @@ static struct platform_driver mxc_rtc_driver = { .of_match_table = mxc_ids, }, .probe = mxc_rtc_probe, - .remove_new = mxc_rtc_remove, + .remove = mxc_rtc_remove, }; module_platform_driver(mxc_rtc_driver); diff --git a/drivers/rtc/rtc-nxp-bbnsm.c b/drivers/rtc/rtc-nxp-bbnsm.c index acbfbeb8b07007..fa3b0328c7a255 100644 --- a/drivers/rtc/rtc-nxp-bbnsm.c +++ b/drivers/rtc/rtc-nxp-bbnsm.c @@ -197,13 +197,28 @@ static int bbnsm_rtc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request irq %d: %d\n", bbnsm->irq, ret); - return ret; + goto err; } bbnsm->rtc->ops = &bbnsm_rtc_ops; bbnsm->rtc->range_max = U32_MAX; - return devm_rtc_register_device(bbnsm->rtc); + ret = devm_rtc_register_device(bbnsm->rtc); + if (ret) + goto err; + + return 0; + +err: + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + return ret; +} + +static void bbnsm_rtc_remove(struct platform_device *pdev) +{ + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); } static const struct of_device_id bbnsm_dt_ids[] = { @@ -218,6 +233,7 @@ static struct platform_driver bbnsm_rtc_driver = { .of_match_table = bbnsm_dt_ids, }, .probe = bbnsm_rtc_probe, + .remove = bbnsm_rtc_remove, }; module_platform_driver(bbnsm_rtc_driver); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index e6b2a9c15b542e..c123778e2d9bcc 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -1014,7 +1014,7 @@ static void omap_rtc_shutdown(struct platform_device *pdev) static struct platform_driver omap_rtc_driver = { .probe = omap_rtc_probe, - .remove_new = omap_rtc_remove, + .remove = 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 6971e47c6021ee..7256a88b490c98 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -346,7 +346,7 @@ MODULE_DEVICE_TABLE(of, of_palmas_rtc_match); static struct platform_driver palmas_rtc_driver = { .probe = palmas_rtc_probe, - .remove_new = palmas_rtc_remove, + .remove = 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 23edd11aa40c55..c019c4d91c7d77 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -273,7 +273,7 @@ static struct platform_driver pcf50633_rtc_driver = { .name = "pcf50633-rtc", }, .probe = pcf50633_rtc_probe, - .remove_new = pcf50633_rtc_remove, + .remove = pcf50633_rtc_remove, }; module_platform_driver(pcf50633_rtc_driver); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 647d52f1f5c5e8..5a084d426e58d0 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -11,14 +11,15 @@ * https://www.nxp.com/docs/en/data-sheet/PCF8563.pdf */ +#include #include +#include #include -#include -#include -#include #include #include -#include +#include +#include +#include #define PCF8563_REG_ST1 0x00 /* status */ #define PCF8563_REG_ST2 0x01 @@ -77,64 +78,18 @@ struct pcf8563 { */ int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */ - struct i2c_client *client; + struct regmap *regmap; #ifdef CONFIG_COMMON_CLK struct clk_hw clkout_hw; #endif }; -static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg, - unsigned char length, unsigned char *buf) -{ - struct i2c_msg msgs[] = { - {/* setup read ptr */ - .addr = client->addr, - .len = 1, - .buf = ®, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = length, - .buf = buf - }, - }; - - if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { - dev_err(&client->dev, "%s: read error\n", __func__); - return -EIO; - } - - return 0; -} - -static int pcf8563_write_block_data(struct i2c_client *client, - unsigned char reg, unsigned char length, - unsigned char *buf) -{ - int i, err; - - for (i = 0; i < length; i++) { - unsigned char data[2] = { reg + i, buf[i] }; - - err = i2c_master_send(client, data, sizeof(data)); - if (err != sizeof(data)) { - dev_err(&client->dev, - "%s: err=%d addr=%02x, data=%02x\n", - __func__, err, data[0], data[1]); - return -EIO; - } - } - - return 0; -} - -static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on) +static int pcf8563_set_alarm_mode(struct pcf8563 *pcf8563, bool on) { - unsigned char buf; + u32 buf; int err; - err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); + err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf); if (err < 0) return err; @@ -145,23 +100,17 @@ static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on) buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N); - err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf); - if (err < 0) { - dev_err(&client->dev, "%s: write error\n", __func__); - return -EIO; - } - - return 0; + return regmap_write(pcf8563->regmap, PCF8563_REG_ST2, buf); } -static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en, +static int pcf8563_get_alarm_mode(struct pcf8563 *pcf8563, unsigned char *en, unsigned char *pen) { - unsigned char buf; + u32 buf; int err; - err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); - if (err) + err = regmap_read(pcf8563->regmap, PCF8563_REG_ST2, &buf); + if (err < 0) return err; if (en) @@ -174,17 +123,17 @@ static int pcf8563_get_alarm_mode(struct i2c_client *client, unsigned char *en, static irqreturn_t pcf8563_irq(int irq, void *dev_id) { - struct pcf8563 *pcf8563 = i2c_get_clientdata(dev_id); - int err; + struct pcf8563 *pcf8563 = dev_id; char pending; + int err; - err = pcf8563_get_alarm_mode(pcf8563->client, NULL, &pending); + err = pcf8563_get_alarm_mode(pcf8563, NULL, &pending); if (err) return IRQ_NONE; if (pending) { rtc_update_irq(pcf8563->rtc, 1, RTC_IRQF | RTC_AF); - pcf8563_set_alarm_mode(pcf8563->client, 1); + pcf8563_set_alarm_mode(pcf8563, 1); return IRQ_HANDLED; } @@ -197,22 +146,22 @@ static irqreturn_t pcf8563_irq(int irq, void *dev_id) */ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct i2c_client *client = to_i2c_client(dev); - struct pcf8563 *pcf8563 = i2c_get_clientdata(client); + struct pcf8563 *pcf8563 = dev_get_drvdata(dev); unsigned char buf[9]; int err; - err = pcf8563_read_block_data(client, PCF8563_REG_ST1, 9, buf); - if (err) + err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_ST1, buf, + sizeof(buf)); + if (err < 0) return err; if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) { - dev_err(&client->dev, + dev_err(dev, "low voltage detected, date/time is not reliable.\n"); return -EINVAL; } - dev_dbg(&client->dev, + dev_dbg(dev, "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", __func__, @@ -220,7 +169,6 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) buf[4], buf[5], buf[6], buf[7], buf[8]); - tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F); tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F); tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */ @@ -232,7 +180,7 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ? (tm->tm_year >= 100) : (tm->tm_year < 100); - dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, @@ -243,11 +191,10 @@ static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct i2c_client *client = to_i2c_client(dev); - struct pcf8563 *pcf8563 = i2c_get_clientdata(client); + struct pcf8563 *pcf8563 = dev_get_drvdata(dev); unsigned char buf[9]; - dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " + dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, @@ -270,22 +217,24 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) buf[PCF8563_REG_DW] = tm->tm_wday & 0x07; - return pcf8563_write_block_data(client, PCF8563_REG_SC, - 9 - PCF8563_REG_SC, buf + PCF8563_REG_SC); + return regmap_bulk_write(pcf8563->regmap, PCF8563_REG_SC, + buf + PCF8563_REG_SC, + sizeof(buf) - PCF8563_REG_SC); } static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - struct i2c_client *client = to_i2c_client(dev); + struct pcf8563 *pcf8563 = dev_get_drvdata(dev); int ret; switch (cmd) { case RTC_VL_READ: - ret = i2c_smbus_read_byte_data(client, PCF8563_REG_SC); + ret = regmap_test_bits(pcf8563->regmap, PCF8563_REG_SC, + PCF8563_SC_LV); if (ret < 0) return ret; - return put_user(ret & PCF8563_SC_LV ? RTC_VL_DATA_INVALID : 0, + return put_user(ret ? RTC_VL_DATA_INVALID : 0, (unsigned int __user *)arg); default: return -ENOIOCTLCMD; @@ -294,15 +243,16 @@ static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) { - struct i2c_client *client = to_i2c_client(dev); + struct pcf8563 *pcf8563 = dev_get_drvdata(dev); unsigned char buf[4]; int err; - err = pcf8563_read_block_data(client, PCF8563_REG_AMN, 4, buf); - if (err) + err = regmap_bulk_read(pcf8563->regmap, PCF8563_REG_AMN, buf, + sizeof(buf)); + if (err < 0) return err; - dev_dbg(&client->dev, + dev_dbg(dev, "%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n", __func__, buf[0], buf[1], buf[2], buf[3]); @@ -312,11 +262,11 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) tm->time.tm_mday = bcd2bin(buf[2] & 0x3F); tm->time.tm_wday = bcd2bin(buf[3] & 0x7); - err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending); + err = pcf8563_get_alarm_mode(pcf8563, &tm->enabled, &tm->pending); if (err < 0) return err; - dev_dbg(&client->dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d," + dev_dbg(dev, "%s: tm is mins=%d, hours=%d, mday=%d, wday=%d," " enabled=%d, pending=%d\n", __func__, tm->time.tm_min, tm->time.tm_hour, tm->time.tm_mday, tm->time.tm_wday, tm->enabled, tm->pending); @@ -326,7 +276,7 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) { - struct i2c_client *client = to_i2c_client(dev); + struct pcf8563 *pcf8563 = dev_get_drvdata(dev); unsigned char buf[4]; int err; @@ -335,17 +285,20 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) buf[2] = bin2bcd(tm->time.tm_mday); buf[3] = tm->time.tm_wday & 0x07; - err = pcf8563_write_block_data(client, PCF8563_REG_AMN, 4, buf); + err = regmap_bulk_write(pcf8563->regmap, PCF8563_REG_SC, buf, + sizeof(buf)); if (err) return err; - return pcf8563_set_alarm_mode(client, !!tm->enabled); + return pcf8563_set_alarm_mode(pcf8563, !!tm->enabled); } static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) { + struct pcf8563 *pcf8563 = dev_get_drvdata(dev); + dev_dbg(dev, "%s: en=%d\n", __func__, enabled); - return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); + return pcf8563_set_alarm_mode(pcf8563, !!enabled); } #ifdef CONFIG_COMMON_CLK @@ -366,10 +319,10 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); - struct i2c_client *client = pcf8563->client; - unsigned char buf; - int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + u32 buf; + int ret; + ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf); if (ret < 0) return 0; @@ -393,11 +346,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); - struct i2c_client *client = pcf8563->client; - unsigned char buf; - int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); - int i; + int i, ret; + u32 buf; + ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf); if (ret < 0) return ret; @@ -405,10 +357,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate, if (clkout_rates[i] == rate) { buf &= ~PCF8563_REG_CLKO_F_MASK; buf |= i; - ret = pcf8563_write_block_data(client, - PCF8563_REG_CLKO, 1, - &buf); - return ret; + return regmap_update_bits(pcf8563->regmap, + PCF8563_REG_CLKO, + PCF8563_REG_CLKO_F_MASK, + buf); } return -EINVAL; @@ -417,10 +369,10 @@ static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate, static int pcf8563_clkout_control(struct clk_hw *hw, bool enable) { struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); - struct i2c_client *client = pcf8563->client; - unsigned char buf; - int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + u32 buf; + int ret; + ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf); if (ret < 0) return ret; @@ -429,8 +381,8 @@ static int pcf8563_clkout_control(struct clk_hw *hw, bool enable) else buf &= ~PCF8563_REG_CLKO_FE; - ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); - return ret; + return regmap_update_bits(pcf8563->regmap, PCF8563_REG_CLKO, + PCF8563_REG_CLKO_FE, buf); } static int pcf8563_clkout_prepare(struct clk_hw *hw) @@ -446,10 +398,10 @@ static void pcf8563_clkout_unprepare(struct clk_hw *hw) static int pcf8563_clkout_is_prepared(struct clk_hw *hw) { struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); - struct i2c_client *client = pcf8563->client; - unsigned char buf; - int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + u32 buf; + int ret; + ret = regmap_read(pcf8563->regmap, PCF8563_REG_CLKO, &buf); if (ret < 0) return ret; @@ -467,16 +419,14 @@ static const struct clk_ops pcf8563_clkout_ops = { static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) { - struct i2c_client *client = pcf8563->client; - struct device_node *node = client->dev.of_node; - struct clk *clk; + struct device_node *node = pcf8563->rtc->dev.of_node; struct clk_init_data init; + struct clk *clk; int ret; - unsigned char buf; /* disable the clkout output */ - buf = 0; - ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); + ret = regmap_clear_bits(pcf8563->regmap, PCF8563_REG_CLKO, + PCF8563_REG_CLKO_FE); if (ret < 0) return ERR_PTR(ret); @@ -491,7 +441,7 @@ static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) of_property_read_string(node, "clock-output-names", &init.name); /* register the clock */ - clk = devm_clk_register(&client->dev, &pcf8563->clkout_hw); + clk = devm_clk_register(&pcf8563->rtc->dev, &pcf8563->clkout_hw); if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); @@ -509,11 +459,16 @@ static const struct rtc_class_ops pcf8563_rtc_ops = { .alarm_irq_enable = pcf8563_irq_enable, }; +static const struct regmap_config regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xF, +}; + static int pcf8563_probe(struct i2c_client *client) { struct pcf8563 *pcf8563; int err; - unsigned char buf; dev_dbg(&client->dev, "%s\n", __func__); @@ -525,20 +480,23 @@ static int pcf8563_probe(struct i2c_client *client) if (!pcf8563) return -ENOMEM; + pcf8563->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(pcf8563->regmap)) + return PTR_ERR(pcf8563->regmap); + i2c_set_clientdata(client, pcf8563); - pcf8563->client = client; + device_set_wakeup_capable(&client->dev, 1); /* Set timer to lowest frequency to save power (ref Haoyu datasheet) */ - buf = PCF8563_TMRC_1_60; - err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf); + err = regmap_set_bits(pcf8563->regmap, PCF8563_REG_TMRC, + PCF8563_TMRC_1_60); if (err < 0) { dev_err(&client->dev, "%s: write error\n", __func__); return err; } /* Clear flags and disable interrupts */ - buf = 0; - err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf); + err = regmap_write(pcf8563->regmap, PCF8563_REG_ST2, 0); if (err < 0) { dev_err(&client->dev, "%s: write error\n", __func__); return err; diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c index 4f85e0c3d75729..bed3c27e665f32 100644 --- a/drivers/rtc/rtc-pic32.c +++ b/drivers/rtc/rtc-pic32.c @@ -371,7 +371,7 @@ MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids); static struct platform_driver pic32_rtc_driver = { .probe = pic32_rtc_probe, - .remove_new = pic32_rtc_remove, + .remove = 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 c32fba550c8e0a..2f32187ecc8d32 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -537,7 +537,7 @@ static void pm8xxx_remove(struct platform_device *pdev) static struct platform_driver pm8xxx_rtc_driver = { .probe = pm8xxx_rtc_probe, - .remove_new = pm8xxx_remove, + .remove = pm8xxx_remove, .driver = { .name = "rtc-pm8xxx", .of_match_table = pm8xxx_id_table, diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index cdb39fc4cab52c..34d8545c8e155a 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -409,7 +409,7 @@ static SIMPLE_DEV_PM_OPS(pxa_rtc_pm_ops, pxa_rtc_suspend, pxa_rtc_resume); * triggering a section mismatch warning. */ static struct platform_driver pxa_rtc_driver __refdata = { - .remove_new = __exit_p(pxa_rtc_remove), + .remove = __exit_p(pxa_rtc_remove), .driver = { .name = "pxa-rtc", .of_match_table = of_match_ptr(pxa_rtc_dt_ids), diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c index 115c46f862f95b..eecb49bab56ad5 100644 --- a/drivers/rtc/rtc-rc5t583.c +++ b/drivers/rtc/rtc-rc5t583.c @@ -298,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_new = rc5t583_rtc_remove, + .remove = rc5t583_rtc_remove, .driver = { .name = "rtc-rc5t583", .pm = &rc5t583_rtc_pm_ops, diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c new file mode 100644 index 00000000000000..d127933bfc8adc --- /dev/null +++ b/drivers/rtc/rtc-renesas-rtca3.c @@ -0,0 +1,900 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * On-Chip RTC Support available on RZ/G3S SoC + * + * Copyright (C) 2024 Renesas Electronics Corp. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Counter registers. */ +#define RTCA3_RSECCNT 0x2 +#define RTCA3_RSECCNT_SEC GENMASK(6, 0) +#define RTCA3_RMINCNT 0x4 +#define RTCA3_RMINCNT_MIN GENMASK(6, 0) +#define RTCA3_RHRCNT 0x6 +#define RTCA3_RHRCNT_HR GENMASK(5, 0) +#define RTCA3_RHRCNT_PM BIT(6) +#define RTCA3_RWKCNT 0x8 +#define RTCA3_RWKCNT_WK GENMASK(2, 0) +#define RTCA3_RDAYCNT 0xa +#define RTCA3_RDAYCNT_DAY GENMASK(5, 0) +#define RTCA3_RMONCNT 0xc +#define RTCA3_RMONCNT_MONTH GENMASK(4, 0) +#define RTCA3_RYRCNT 0xe +#define RTCA3_RYRCNT_YEAR GENMASK(7, 0) + +/* Alarm registers. */ +#define RTCA3_RSECAR 0x10 +#define RTCA3_RSECAR_SEC GENMASK(6, 0) +#define RTCA3_RMINAR 0x12 +#define RTCA3_RMINAR_MIN GENMASK(6, 0) +#define RTCA3_RHRAR 0x14 +#define RTCA3_RHRAR_HR GENMASK(5, 0) +#define RTCA3_RHRAR_PM BIT(6) +#define RTCA3_RWKAR 0x16 +#define RTCA3_RWKAR_DAYW GENMASK(2, 0) +#define RTCA3_RDAYAR 0x18 +#define RTCA3_RDAYAR_DATE GENMASK(5, 0) +#define RTCA3_RMONAR 0x1a +#define RTCA3_RMONAR_MON GENMASK(4, 0) +#define RTCA3_RYRAR 0x1c +#define RTCA3_RYRAR_YR GENMASK(7, 0) +#define RTCA3_RYRAREN 0x1e + +/* Alarm enable bit (for all alarm registers). */ +#define RTCA3_AR_ENB BIT(7) + +/* Control registers. */ +#define RTCA3_RCR1 0x22 +#define RTCA3_RCR1_AIE BIT(0) +#define RTCA3_RCR1_CIE BIT(1) +#define RTCA3_RCR1_PIE BIT(2) +#define RTCA3_RCR1_PES GENMASK(7, 4) +#define RTCA3_RCR1_PES_1_64_SEC 0x8 +#define RTCA3_RCR2 0x24 +#define RTCA3_RCR2_START BIT(0) +#define RTCA3_RCR2_RESET BIT(1) +#define RTCA3_RCR2_AADJE BIT(4) +#define RTCA3_RCR2_ADJP BIT(5) +#define RTCA3_RCR2_HR24 BIT(6) +#define RTCA3_RCR2_CNTMD BIT(7) +#define RTCA3_RSR 0x20 +#define RTCA3_RSR_AF BIT(0) +#define RTCA3_RSR_CF BIT(1) +#define RTCA3_RSR_PF BIT(2) +#define RTCA3_RADJ 0x2e +#define RTCA3_RADJ_ADJ GENMASK(5, 0) +#define RTCA3_RADJ_ADJ_MAX 0x3f +#define RTCA3_RADJ_PMADJ GENMASK(7, 6) +#define RTCA3_RADJ_PMADJ_NONE 0 +#define RTCA3_RADJ_PMADJ_ADD 1 +#define RTCA3_RADJ_PMADJ_SUB 2 + +/* Polling operation timeouts. */ +#define RTCA3_DEFAULT_TIMEOUT_US 150 +#define RTCA3_IRQSET_TIMEOUT_US 5000 +#define RTCA3_START_TIMEOUT_US 150000 +#define RTCA3_RESET_TIMEOUT_US 200000 + +/** + * enum rtca3_alrm_set_step - RTCA3 alarm set steps + * @RTCA3_ALRM_SSTEP_DONE: alarm setup done step + * @RTCA3_ALRM_SSTEP_IRQ: two 1/64 periodic IRQs were generated step + * @RTCA3_ALRM_SSTEP_INIT: alarm setup initialization step + */ +enum rtca3_alrm_set_step { + RTCA3_ALRM_SSTEP_DONE = 0, + RTCA3_ALRM_SSTEP_IRQ = 1, + RTCA3_ALRM_SSTEP_INIT = 3, +}; + +/** + * struct rtca3_ppb_per_cycle - PPB per cycle + * @ten_sec: PPB per cycle in 10 seconds adjutment mode + * @sixty_sec: PPB per cycle in 60 seconds adjustment mode + */ +struct rtca3_ppb_per_cycle { + int ten_sec; + int sixty_sec; +}; + +/** + * struct rtca3_priv - RTCA3 private data structure + * @base: base address + * @rtc_dev: RTC device + * @rstc: reset control + * @set_alarm_completion: alarm setup completion + * @alrm_sstep: alarm setup step (see enum rtca3_alrm_set_step) + * @lock: device lock + * @ppb: ppb per cycle for each the available adjustment modes + * @wakeup_irq: wakeup IRQ + */ +struct rtca3_priv { + void __iomem *base; + struct rtc_device *rtc_dev; + struct reset_control *rstc; + struct completion set_alarm_completion; + atomic_t alrm_sstep; + spinlock_t lock; + struct rtca3_ppb_per_cycle ppb; + int wakeup_irq; +}; + +static void rtca3_byte_update_bits(struct rtca3_priv *priv, u8 off, u8 mask, u8 val) +{ + u8 tmp; + + tmp = readb(priv->base + off); + tmp &= ~mask; + tmp |= (val & mask); + writeb(tmp, priv->base + off); +} + +static u8 rtca3_alarm_handler_helper(struct rtca3_priv *priv) +{ + u8 val, pending; + + val = readb(priv->base + RTCA3_RSR); + pending = val & RTCA3_RSR_AF; + writeb(val & ~pending, priv->base + RTCA3_RSR); + + if (pending) + rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF); + + return pending; +} + +static irqreturn_t rtca3_alarm_handler(int irq, void *dev_id) +{ + struct rtca3_priv *priv = dev_id; + u8 pending; + + guard(spinlock)(&priv->lock); + + pending = rtca3_alarm_handler_helper(priv); + + return IRQ_RETVAL(pending); +} + +static irqreturn_t rtca3_periodic_handler(int irq, void *dev_id) +{ + struct rtca3_priv *priv = dev_id; + u8 val, pending; + + guard(spinlock)(&priv->lock); + + val = readb(priv->base + RTCA3_RSR); + pending = val & RTCA3_RSR_PF; + + if (pending) { + writeb(val & ~pending, priv->base + RTCA3_RSR); + + if (atomic_read(&priv->alrm_sstep) > RTCA3_ALRM_SSTEP_IRQ) { + /* Alarm setup in progress. */ + atomic_dec(&priv->alrm_sstep); + + if (atomic_read(&priv->alrm_sstep) == RTCA3_ALRM_SSTEP_IRQ) { + /* + * We got 2 * 1/64 periodic interrupts. Disable + * interrupt and let alarm setup continue. + */ + rtca3_byte_update_bits(priv, RTCA3_RCR1, + RTCA3_RCR1_PIE, 0); + readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, val, + !(val & RTCA3_RCR1_PIE), + 10, RTCA3_DEFAULT_TIMEOUT_US); + complete(&priv->set_alarm_completion); + } + } + } + + return IRQ_RETVAL(pending); +} + +static void rtca3_prepare_cntalrm_regs_for_read(struct rtca3_priv *priv, bool cnt) +{ + /* Offset b/w time and alarm registers. */ + u8 offset = cnt ? 0 : 0xe; + + /* + * According to HW manual (section 22.6.4. Notes on writing to and + * reading from registers) after writing to count registers, alarm + * registers, year alarm enable register, bits RCR2.AADJE, AADJP, + * and HR24 register, we need to do 3 empty reads before being + * able to fetch the registers content. + */ + for (u8 i = 0; i < 3; i++) { + readb(priv->base + RTCA3_RSECCNT + offset); + readb(priv->base + RTCA3_RMINCNT + offset); + readb(priv->base + RTCA3_RHRCNT + offset); + readb(priv->base + RTCA3_RWKCNT + offset); + readb(priv->base + RTCA3_RDAYCNT + offset); + readw(priv->base + RTCA3_RYRCNT + offset); + if (!cnt) + readb(priv->base + RTCA3_RYRAREN); + } +} + +static int rtca3_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + u8 sec, min, hour, wday, mday, month, tmp; + u8 trials = 0; + u32 year100; + u16 year; + + guard(spinlock_irqsave)(&priv->lock); + + tmp = readb(priv->base + RTCA3_RCR2); + if (!(tmp & RTCA3_RCR2_START)) + return -EINVAL; + + do { + /* Clear carry interrupt. */ + rtca3_byte_update_bits(priv, RTCA3_RSR, RTCA3_RSR_CF, 0); + + /* Read counters. */ + sec = readb(priv->base + RTCA3_RSECCNT); + min = readb(priv->base + RTCA3_RMINCNT); + hour = readb(priv->base + RTCA3_RHRCNT); + wday = readb(priv->base + RTCA3_RWKCNT); + mday = readb(priv->base + RTCA3_RDAYCNT); + month = readb(priv->base + RTCA3_RMONCNT); + year = readw(priv->base + RTCA3_RYRCNT); + + tmp = readb(priv->base + RTCA3_RSR); + + /* + * We cannot generate carries due to reading 64Hz counter as + * the driver doesn't implement carry, thus, carries will be + * generated once per seconds. Add a timeout of 5 trials here + * to avoid infinite loop, if any. + */ + } while ((tmp & RTCA3_RSR_CF) && ++trials < 5); + + if (trials >= 5) + return -ETIMEDOUT; + + tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECCNT_SEC, sec)); + tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINCNT_MIN, min)); + tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRCNT_HR, hour)); + tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKCNT_WK, wday)); + tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYCNT_DAY, mday)); + tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONCNT_MONTH, month)) - 1; + year = FIELD_GET(RTCA3_RYRCNT_YEAR, year); + year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20); + tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900; + + return 0; +} + +static int rtca3_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + u8 rcr2, tmp; + int ret; + + guard(spinlock_irqsave)(&priv->lock); + + /* Stop the RTC. */ + rcr2 = readb(priv->base + RTCA3_RCR2); + writeb(rcr2 & ~RTCA3_RCR2_START, priv->base + RTCA3_RCR2); + ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp, + !(tmp & RTCA3_RCR2_START), + 10, RTCA3_DEFAULT_TIMEOUT_US); + if (ret) + return ret; + + /* Update time. */ + writeb(bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECCNT); + writeb(bin2bcd(tm->tm_min), priv->base + RTCA3_RMINCNT); + writeb(bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRCNT); + writeb(bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKCNT); + writeb(bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYCNT); + writeb(bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONCNT); + writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRCNT); + + /* Make sure we can read back the counters. */ + rtca3_prepare_cntalrm_regs_for_read(priv, true); + + /* Start RTC. */ + writeb(rcr2 | RTCA3_RCR2_START, priv->base + RTCA3_RCR2); + return readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp, + (tmp & RTCA3_RCR2_START), + 10, RTCA3_DEFAULT_TIMEOUT_US); +} + +static int rtca3_alarm_irq_set_helper(struct rtca3_priv *priv, + u8 interrupts, + unsigned int enabled) +{ + u8 tmp, val; + + if (enabled) { + /* + * AIE, CIE, PIE bit indexes in RSR corresponds with + * those on RCR1. Same interrupts mask can be used. + */ + rtca3_byte_update_bits(priv, RTCA3_RSR, interrupts, 0); + val = interrupts; + } else { + val = 0; + } + + rtca3_byte_update_bits(priv, RTCA3_RCR1, interrupts, val); + return readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, + ((tmp & interrupts) == val), + 10, RTCA3_IRQSET_TIMEOUT_US); +} + +static int rtca3_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + + guard(spinlock_irqsave)(&priv->lock); + + return rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, enabled); +} + +static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + u8 sec, min, hour, wday, mday, month; + struct rtc_time *tm = &wkalrm->time; + u32 year100; + u16 year; + + guard(spinlock_irqsave)(&priv->lock); + + sec = readb(priv->base + RTCA3_RSECAR); + min = readb(priv->base + RTCA3_RMINAR); + hour = readb(priv->base + RTCA3_RHRAR); + wday = readb(priv->base + RTCA3_RWKAR); + mday = readb(priv->base + RTCA3_RDAYAR); + month = readb(priv->base + RTCA3_RMONAR); + year = readw(priv->base + RTCA3_RYRAR); + + tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECAR_SEC, sec)); + tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINAR_MIN, min)); + tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRAR_HR, hour)); + tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKAR_DAYW, wday)); + tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYAR_DATE, mday)); + tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONAR_MON, month)) - 1; + year = FIELD_GET(RTCA3_RYRAR_YR, year); + year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20); + tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900; + + wkalrm->enabled = !!(readb(priv->base + RTCA3_RCR1) & RTCA3_RCR1_AIE); + + return 0; +} + +static int rtca3_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + u8 rcr1, tmp; + int ret; + + scoped_guard(spinlock_irqsave, &priv->lock) { + tmp = readb(priv->base + RTCA3_RCR2); + if (!(tmp & RTCA3_RCR2_START)) + return -EPERM; + + /* Disable AIE to prevent false interrupts. */ + rcr1 = readb(priv->base + RTCA3_RCR1); + rcr1 &= ~RTCA3_RCR1_AIE; + writeb(rcr1, priv->base + RTCA3_RCR1); + ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, + !(tmp & RTCA3_RCR1_AIE), + 10, RTCA3_DEFAULT_TIMEOUT_US); + if (ret) + return ret; + + /* Set the time and enable the alarm. */ + writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECAR); + writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_min), priv->base + RTCA3_RMINAR); + writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRAR); + writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKAR); + writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYAR); + writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONAR); + + writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRAR); + writeb(RTCA3_AR_ENB, priv->base + RTCA3_RYRAREN); + + /* Make sure we can read back the counters. */ + rtca3_prepare_cntalrm_regs_for_read(priv, false); + + /* Need to wait for 2 * 1/64 periodic interrupts to be generated. */ + atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_INIT); + reinit_completion(&priv->set_alarm_completion); + + /* Enable periodic interrupt. */ + rcr1 |= RTCA3_RCR1_PIE; + writeb(rcr1, priv->base + RTCA3_RCR1); + ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, + (tmp & RTCA3_RCR1_PIE), + 10, RTCA3_IRQSET_TIMEOUT_US); + } + + if (ret) + goto setup_failed; + + /* Wait for the 2 * 1/64 periodic interrupts. */ + ret = wait_for_completion_interruptible_timeout(&priv->set_alarm_completion, + msecs_to_jiffies(500)); + if (ret <= 0) { + ret = -ETIMEDOUT; + goto setup_failed; + } + + scoped_guard(spinlock_irqsave, &priv->lock) { + ret = rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, wkalrm->enabled); + atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE); + } + + return ret; + +setup_failed: + scoped_guard(spinlock_irqsave, &priv->lock) { + /* + * Disable PIE to avoid interrupt storm in case HW needed more than + * specified timeout for setup. + */ + writeb(rcr1 & ~RTCA3_RCR1_PIE, priv->base + RTCA3_RCR1); + readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & ~RTCA3_RCR1_PIE), + 10, RTCA3_DEFAULT_TIMEOUT_US); + atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE); + } + + return ret; +} + +static int rtca3_read_offset(struct device *dev, long *offset) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + u8 val, radj, cycles; + u32 ppb_per_cycle; + + scoped_guard(spinlock_irqsave, &priv->lock) { + radj = readb(priv->base + RTCA3_RADJ); + val = readb(priv->base + RTCA3_RCR2); + } + + cycles = FIELD_GET(RTCA3_RADJ_ADJ, radj); + + if (!cycles) { + *offset = 0; + return 0; + } + + if (val & RTCA3_RCR2_ADJP) + ppb_per_cycle = priv->ppb.ten_sec; + else + ppb_per_cycle = priv->ppb.sixty_sec; + + *offset = cycles * ppb_per_cycle; + val = FIELD_GET(RTCA3_RADJ_PMADJ, radj); + if (val == RTCA3_RADJ_PMADJ_SUB) + *offset = -(*offset); + + return 0; +} + +static int rtca3_set_offset(struct device *dev, long offset) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + int cycles, cycles10, cycles60; + u8 radj, adjp, tmp; + int ret; + + /* + * Automatic time error adjustment could be set at intervals of 10 + * or 60 seconds. + */ + cycles10 = DIV_ROUND_CLOSEST(offset, priv->ppb.ten_sec); + cycles60 = DIV_ROUND_CLOSEST(offset, priv->ppb.sixty_sec); + + /* We can set b/w 1 and 63 clock cycles. */ + if (cycles60 >= -RTCA3_RADJ_ADJ_MAX && + cycles60 <= RTCA3_RADJ_ADJ_MAX) { + cycles = cycles60; + adjp = 0; + } else if (cycles10 >= -RTCA3_RADJ_ADJ_MAX && + cycles10 <= RTCA3_RADJ_ADJ_MAX) { + cycles = cycles10; + adjp = RTCA3_RCR2_ADJP; + } else { + return -ERANGE; + } + + radj = FIELD_PREP(RTCA3_RADJ_ADJ, abs(cycles)); + if (!cycles) + radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_NONE); + else if (cycles > 0) + radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_ADD); + else + radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_SUB); + + guard(spinlock_irqsave)(&priv->lock); + + tmp = readb(priv->base + RTCA3_RCR2); + + if ((tmp & RTCA3_RCR2_ADJP) != adjp) { + /* RADJ.PMADJ need to be set to zero before setting RCR2.ADJP. */ + writeb(0, priv->base + RTCA3_RADJ); + ret = readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, !tmp, + 10, RTCA3_DEFAULT_TIMEOUT_US); + if (ret) + return ret; + + rtca3_byte_update_bits(priv, RTCA3_RCR2, RTCA3_RCR2_ADJP, adjp); + ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp, + ((tmp & RTCA3_RCR2_ADJP) == adjp), + 10, RTCA3_DEFAULT_TIMEOUT_US); + if (ret) + return ret; + } + + writeb(radj, priv->base + RTCA3_RADJ); + return readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, (tmp == radj), + 10, RTCA3_DEFAULT_TIMEOUT_US); +} + +static const struct rtc_class_ops rtca3_ops = { + .read_time = rtca3_read_time, + .set_time = rtca3_set_time, + .read_alarm = rtca3_read_alarm, + .set_alarm = rtca3_set_alarm, + .alarm_irq_enable = rtca3_alarm_irq_enable, + .set_offset = rtca3_set_offset, + .read_offset = rtca3_read_offset, +}; + +static int rtca3_initial_setup(struct clk *clk, struct rtca3_priv *priv) +{ + unsigned long osc32k_rate; + u8 val, tmp, mask; + u32 sleep_us; + int ret; + + osc32k_rate = clk_get_rate(clk); + if (!osc32k_rate) + return -EINVAL; + + sleep_us = DIV_ROUND_UP_ULL(1000000ULL, osc32k_rate) * 6; + + priv->ppb.ten_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 10)); + priv->ppb.sixty_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 60)); + + /* + * According to HW manual (section 22.4.2. Clock and count mode setting procedure) + * we need to wait at least 6 cycles of the 32KHz clock after clock was enabled. + */ + usleep_range(sleep_us, sleep_us + 10); + + /* Disable all interrupts. */ + mask = RTCA3_RCR1_AIE | RTCA3_RCR1_CIE | RTCA3_RCR1_PIE; + ret = rtca3_alarm_irq_set_helper(priv, mask, 0); + if (ret) + return ret; + + mask = RTCA3_RCR2_START | RTCA3_RCR2_HR24; + val = readb(priv->base + RTCA3_RCR2); + /* Nothing to do if already started in 24 hours and calendar count mode. */ + if ((val & mask) == mask) + return 0; + + /* Reconfigure the RTC in 24 hours and calendar count mode. */ + mask = RTCA3_RCR2_START | RTCA3_RCR2_CNTMD; + writeb(0, priv->base + RTCA3_RCR2); + ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask), + 10, RTCA3_DEFAULT_TIMEOUT_US); + if (ret) + return ret; + + /* + * Set 24 hours mode. According to HW manual (section 22.3.19. RTC Control + * Register 2) this needs to be done separate from stop operation. + */ + mask = RTCA3_RCR2_HR24; + val = RTCA3_RCR2_HR24; + writeb(val, priv->base + RTCA3_RCR2); + ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, (tmp & mask), + 10, RTCA3_DEFAULT_TIMEOUT_US); + if (ret) + return ret; + + /* Execute reset. */ + mask = RTCA3_RCR2_RESET; + writeb(val | RTCA3_RCR2_RESET, priv->base + RTCA3_RCR2); + ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask), + 10, RTCA3_RESET_TIMEOUT_US); + if (ret) + return ret; + + /* + * According to HW manual (section 22.6.3. Notes on writing to and reading + * from registers) after reset we need to wait 6 clock cycles before + * writing to RTC registers. + */ + usleep_range(sleep_us, sleep_us + 10); + + /* Set no adjustment. */ + writeb(0, priv->base + RTCA3_RADJ); + ret = readb_poll_timeout(priv->base + RTCA3_RADJ, tmp, !tmp, 10, + RTCA3_DEFAULT_TIMEOUT_US); + + /* Start the RTC and enable automatic time error adjustment. */ + mask = RTCA3_RCR2_START | RTCA3_RCR2_AADJE; + val |= RTCA3_RCR2_START | RTCA3_RCR2_AADJE; + writeb(val, priv->base + RTCA3_RCR2); + ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, ((tmp & mask) == mask), + 10, RTCA3_START_TIMEOUT_US); + if (ret) + return ret; + + /* + * According to HW manual (section 22.6.4. Notes on writing to and reading + * from registers) we need to wait 1/128 seconds while the clock is operating + * (RCR2.START bit = 1) to be able to read the counters after a return from + * reset. + */ + usleep_range(8000, 9000); + + /* Set period interrupt to 1/64 seconds. It is necessary for alarm setup. */ + val = FIELD_PREP(RTCA3_RCR1_PES, RTCA3_RCR1_PES_1_64_SEC); + rtca3_byte_update_bits(priv, RTCA3_RCR1, RTCA3_RCR1_PES, val); + return readb_poll_timeout(priv->base + RTCA3_RCR1, tmp, ((tmp & RTCA3_RCR1_PES) == val), + 10, RTCA3_DEFAULT_TIMEOUT_US); +} + +static int rtca3_request_irqs(struct platform_device *pdev, struct rtca3_priv *priv) +{ + struct device *dev = &pdev->dev; + int ret, irq; + + irq = platform_get_irq_byname(pdev, "alarm"); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get alarm IRQ!\n"); + + ret = devm_request_irq(dev, irq, rtca3_alarm_handler, 0, "rtca3-alarm", priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to request alarm IRQ!\n"); + priv->wakeup_irq = irq; + + irq = platform_get_irq_byname(pdev, "period"); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get period IRQ!\n"); + + ret = devm_request_irq(dev, irq, rtca3_periodic_handler, 0, "rtca3-period", priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to request period IRQ!\n"); + + /* + * Driver doesn't implement carry handler. Just get the IRQ here + * for backward compatibility, in case carry support will be added later. + */ + irq = platform_get_irq_byname(pdev, "carry"); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get carry IRQ!\n"); + + return 0; +} + +static void rtca3_action(void *data) +{ + struct device *dev = data; + struct rtca3_priv *priv = dev_get_drvdata(dev); + int ret; + + ret = reset_control_assert(priv->rstc); + if (ret) + dev_err(dev, "Failed to de-assert reset!"); + + ret = pm_runtime_put_sync(dev); + if (ret < 0) + dev_err(dev, "Failed to runtime suspend!"); +} + +static int rtca3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtca3_priv *priv; + struct clk *clk; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + priv->rstc = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(priv->rstc)) + return PTR_ERR(priv->rstc); + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = reset_control_deassert(priv->rstc); + if (ret) { + pm_runtime_put_sync(dev); + return ret; + } + + dev_set_drvdata(dev, priv); + ret = devm_add_action_or_reset(dev, rtca3_action, dev); + if (ret) + return ret; + + /* + * This must be an always-on clock to keep the RTC running even after + * driver is unbinded. + */ + clk = devm_clk_get_enabled(dev, "counter"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + spin_lock_init(&priv->lock); + atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE); + init_completion(&priv->set_alarm_completion); + + ret = rtca3_initial_setup(clk, priv); + if (ret) + return dev_err_probe(dev, ret, "Failed to setup the RTC!\n"); + + ret = rtca3_request_irqs(pdev, priv); + if (ret) + return ret; + + device_init_wakeup(&pdev->dev, 1); + + priv->rtc_dev = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(priv->rtc_dev)) + return PTR_ERR(priv->rtc_dev); + + priv->rtc_dev->ops = &rtca3_ops; + priv->rtc_dev->max_user_freq = 256; + priv->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; + priv->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; + + return devm_rtc_register_device(priv->rtc_dev); +} + +static void rtca3_remove(struct platform_device *pdev) +{ + struct rtca3_priv *priv = platform_get_drvdata(pdev); + + guard(spinlock_irqsave)(&priv->lock); + + /* + * Disable alarm, periodic interrupts. The RTC device cannot + * power up the system. + */ + rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE | RTCA3_RCR1_PIE, 0); +} + +static int rtca3_suspend(struct device *dev) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + + if (!device_may_wakeup(dev)) + return 0; + + /* Alarm setup in progress. */ + if (atomic_read(&priv->alrm_sstep) != RTCA3_ALRM_SSTEP_DONE) + return -EBUSY; + + enable_irq_wake(priv->wakeup_irq); + + return 0; +} + +static int rtca3_clean_alarm(struct rtca3_priv *priv) +{ + struct rtc_device *rtc_dev = priv->rtc_dev; + time64_t alarm_time, now; + struct rtc_wkalrm alarm; + struct rtc_time tm; + u8 pending; + int ret; + + ret = rtc_read_alarm(rtc_dev, &alarm); + if (ret) + return ret; + + if (!alarm.enabled) + return 0; + + ret = rtc_read_time(rtc_dev, &tm); + if (ret) + return ret; + + alarm_time = rtc_tm_to_time64(&alarm.time); + now = rtc_tm_to_time64(&tm); + if (alarm_time >= now) + return 0; + + /* + * Heuristically, it has been determined that when returning from deep + * sleep state the RTCA3_RSR.AF is zero even though the alarm expired. + * Call again the rtc_update_irq() if alarm helper detects this. + */ + + guard(spinlock_irqsave)(&priv->lock); + + pending = rtca3_alarm_handler_helper(priv); + if (!pending) + rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF); + + return 0; +} + +static int rtca3_resume(struct device *dev) +{ + struct rtca3_priv *priv = dev_get_drvdata(dev); + + if (!device_may_wakeup(dev)) + return 0; + + disable_irq_wake(priv->wakeup_irq); + + /* + * According to the HW manual (section 22.6.4 Notes on writing to + * and reading from registers) we need to wait 1/128 seconds while + * RCR2.START = 1 to be able to read the counters after a return from low + * power consumption state. + */ + mdelay(8); + + /* + * The alarm cannot wake the system from deep sleep states. In case + * we return from deep sleep states and the alarm expired we need + * to disable it to avoid failures when setting another alarm. + */ + return rtca3_clean_alarm(priv); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(rtca3_pm_ops, rtca3_suspend, rtca3_resume); + +static const struct of_device_id rtca3_of_match[] = { + { .compatible = "renesas,rz-rtca3", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtca3_of_match); + +static struct platform_driver rtca3_platform_driver = { + .driver = { + .name = "rtc-rtca3", + .pm = pm_ptr(&rtca3_pm_ops), + .of_match_table = rtca3_of_match, + }, + .probe = rtca3_probe, + .remove = rtca3_remove, +}; +module_platform_driver(rtca3_platform_driver); + +MODULE_DESCRIPTION("Renesas RTCA-3 RTC driver"); +MODULE_AUTHOR("Claudiu Beznea "); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-rtd119x.c b/drivers/rtc/rtc-rtd119x.c index 29662dfd56fef9..85a138db81d78a 100644 --- a/drivers/rtc/rtc-rtd119x.c +++ b/drivers/rtc/rtc-rtd119x.c @@ -228,7 +228,7 @@ static void rtd119x_rtc_remove(struct platform_device *pdev) static struct platform_driver rtd119x_rtc_driver = { .probe = rtd119x_rtc_probe, - .remove_new = rtd119x_rtc_remove, + .remove = rtd119x_rtc_remove, .driver = { .name = "rtd1295-rtc", .of_match_table = rtd119x_rtc_dt_ids, diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index 2f001c59c61d54..868d1b1eb0f42e 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -120,8 +120,9 @@ static ssize_t timestamp0_show(struct device *dev, { struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent); struct rtc_time tm; - int ret, count; + unsigned int count; u8 date[6]; + int ret; ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count); if (ret) @@ -156,7 +157,8 @@ static ssize_t timestamp0_count_show(struct device *dev, struct device_attribute *attr, char *buf) { struct rv3028_data *rv3028 = dev_get_drvdata(dev->parent); - int ret, count; + unsigned int count; + int ret; ret = regmap_read(rv3028->regmap, RV3028_TS_COUNT, &count); if (ret) diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index 56ebbd4d048147..cb220807d925b1 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -7,7 +7,7 @@ * - 2022 Schneider Electric * * Authors: - * - Michel Pollet , + * - Michel Pollet * - Miquel Raynal */ @@ -35,13 +35,13 @@ #define RZN1_RTC_CTL2_WUST BIT(5) #define RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST) -#define RZN1_RTC_SEC 0x14 -#define RZN1_RTC_MIN 0x18 -#define RZN1_RTC_HOUR 0x1c -#define RZN1_RTC_WEEK 0x20 -#define RZN1_RTC_DAY 0x24 -#define RZN1_RTC_MONTH 0x28 -#define RZN1_RTC_YEAR 0x2c +#define RZN1_RTC_TIME 0x30 +#define RZN1_RTC_TIME_MIN_SHIFT 8 +#define RZN1_RTC_TIME_HOUR_SHIFT 16 +#define RZN1_RTC_CAL 0x34 +#define RZN1_RTC_CAL_DAY_SHIFT 8 +#define RZN1_RTC_CAL_MON_SHIFT 16 +#define RZN1_RTC_CAL_YEAR_SHIFT 24 #define RZN1_RTC_SUBU 0x38 #define RZN1_RTC_SUBU_DEV BIT(7) @@ -52,12 +52,8 @@ #define RZN1_RTC_ALW 0x48 #define RZN1_RTC_SECC 0x4c -#define RZN1_RTC_MINC 0x50 -#define RZN1_RTC_HOURC 0x54 -#define RZN1_RTC_WEEKC 0x58 -#define RZN1_RTC_DAYC 0x5c -#define RZN1_RTC_MONTHC 0x60 -#define RZN1_RTC_YEARC 0x64 +#define RZN1_RTC_TIMEC 0x68 +#define RZN1_RTC_CALC 0x6c struct rzn1_rtc { struct rtc_device *rtcdev; @@ -66,26 +62,18 @@ struct rzn1_rtc { static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm) { - tm->tm_sec = readl(rtc->base + RZN1_RTC_SECC); - tm->tm_min = readl(rtc->base + RZN1_RTC_MINC); - tm->tm_hour = readl(rtc->base + RZN1_RTC_HOURC); - tm->tm_wday = readl(rtc->base + RZN1_RTC_WEEKC); - tm->tm_mday = readl(rtc->base + RZN1_RTC_DAYC); - tm->tm_mon = readl(rtc->base + RZN1_RTC_MONTHC); - tm->tm_year = readl(rtc->base + RZN1_RTC_YEARC); -} - -static unsigned int rzn1_rtc_tm_to_wday(struct rtc_time *tm) -{ - time64_t time; - unsigned int days; - u32 secs; + u32 val; - time = rtc_tm_to_time64(tm); - days = div_s64_rem(time, 86400, &secs); + val = readl(rtc->base + RZN1_RTC_TIMEC); + tm->tm_sec = bcd2bin(val); + tm->tm_min = bcd2bin(val >> RZN1_RTC_TIME_MIN_SHIFT); + tm->tm_hour = bcd2bin(val >> RZN1_RTC_TIME_HOUR_SHIFT); - /* day of the week, 1970-01-01 was a Thursday */ - return (days + 4) % 7; + val = readl(rtc->base + RZN1_RTC_CALC); + tm->tm_wday = val & 0x0f; + tm->tm_mday = bcd2bin(val >> RZN1_RTC_CAL_DAY_SHIFT); + tm->tm_mon = bcd2bin(val >> RZN1_RTC_CAL_MON_SHIFT) - 1; + tm->tm_year = bcd2bin(val >> RZN1_RTC_CAL_YEAR_SHIFT) + 100; } static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -103,17 +91,9 @@ static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm) rzn1_rtc_get_time_snapshot(rtc, tm); secs = readl(rtc->base + RZN1_RTC_SECC); - if (tm->tm_sec != secs) + if (tm->tm_sec != bcd2bin(secs)) rzn1_rtc_get_time_snapshot(rtc, tm); - tm->tm_sec = bcd2bin(tm->tm_sec); - tm->tm_min = bcd2bin(tm->tm_min); - tm->tm_hour = bcd2bin(tm->tm_hour); - tm->tm_wday = bcd2bin(tm->tm_wday); - tm->tm_mday = bcd2bin(tm->tm_mday); - tm->tm_mon = bcd2bin(tm->tm_mon); - tm->tm_year = bcd2bin(tm->tm_year); - return 0; } @@ -123,14 +103,6 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm) u32 val; int ret; - tm->tm_sec = bin2bcd(tm->tm_sec); - tm->tm_min = bin2bcd(tm->tm_min); - tm->tm_hour = bin2bcd(tm->tm_hour); - tm->tm_wday = bin2bcd(rzn1_rtc_tm_to_wday(tm)); - tm->tm_mday = bin2bcd(tm->tm_mday); - tm->tm_mon = bin2bcd(tm->tm_mon); - tm->tm_year = bin2bcd(tm->tm_year); - val = readl(rtc->base + RZN1_RTC_CTL2); if (!(val & RZN1_RTC_CTL2_STOPPED)) { /* Hold the counter if it was counting up */ @@ -144,13 +116,17 @@ static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm) return ret; } - writel(tm->tm_sec, rtc->base + RZN1_RTC_SEC); - writel(tm->tm_min, rtc->base + RZN1_RTC_MIN); - writel(tm->tm_hour, rtc->base + RZN1_RTC_HOUR); - writel(tm->tm_wday, rtc->base + RZN1_RTC_WEEK); - writel(tm->tm_mday, rtc->base + RZN1_RTC_DAY); - writel(tm->tm_mon, rtc->base + RZN1_RTC_MONTH); - writel(tm->tm_year, rtc->base + RZN1_RTC_YEAR); + val = bin2bcd(tm->tm_sec); + val |= bin2bcd(tm->tm_min) << RZN1_RTC_TIME_MIN_SHIFT; + val |= bin2bcd(tm->tm_hour) << RZN1_RTC_TIME_HOUR_SHIFT; + writel(val, rtc->base + RZN1_RTC_TIME); + + val = tm->tm_wday; + val |= bin2bcd(tm->tm_mday) << RZN1_RTC_CAL_DAY_SHIFT; + val |= bin2bcd(tm->tm_mon + 1) << RZN1_RTC_CAL_MON_SHIFT; + val |= bin2bcd(tm->tm_year - 100) << RZN1_RTC_CAL_YEAR_SHIFT; + writel(val, rtc->base + RZN1_RTC_CAL); + writel(0, rtc->base + RZN1_RTC_CTL2); return 0; @@ -405,7 +381,7 @@ MODULE_DEVICE_TABLE(of, rzn1_rtc_of_match); static struct platform_driver rzn1_rtc_driver = { .probe = rzn1_rtc_probe, - .remove_new = rzn1_rtc_remove, + .remove = rzn1_rtc_remove, .driver = { .name = "rzn1-rtc", .of_match_table = rzn1_rtc_of_match, @@ -413,7 +389,7 @@ static struct platform_driver rzn1_rtc_driver = { }; module_platform_driver(rzn1_rtc_driver); -MODULE_AUTHOR("Michel Pollet "); MODULE_AUTHOR("Miquel Raynal dev, rtc->irq, st_rtc_handler, 0, - pdev->name, rtc); + ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler, + IRQF_NO_AUTOEN, pdev->name, rtc); if (ret) { dev_err(&pdev->dev, "Failed to request irq %i\n", rtc->irq); return ret; } enable_irq_wake(rtc->irq); - disable_irq(rtc->irq); rtc->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(rtc->clk)) diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 3e4f2ee22b0bc8..9f1a019ec8afa5 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -1287,7 +1287,7 @@ static const struct dev_pm_ops stm32_rtc_pm_ops = { static struct platform_driver stm32_rtc_driver = { .probe = stm32_rtc_probe, - .remove_new = stm32_rtc_remove, + .remove = 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 7566d0a44af82a..7afcd14aeee562 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(of, rtc_dt_ids); static struct platform_driver stmp3xxx_rtcdrv = { .probe = stmp3xxx_rtc_probe, - .remove_new = stmp3xxx_rtc_remove, + .remove = stmp3xxx_rtc_remove, .driver = { .name = "stmp3xxx-rtc", .pm = &stmp3xxx_rtc_pm_ops, diff --git a/drivers/rtc/rtc-sunplus.c b/drivers/rtc/rtc-sunplus.c index 20c7e97c2fc815..9b1ce0e8ba27e6 100644 --- a/drivers/rtc/rtc-sunplus.c +++ b/drivers/rtc/rtc-sunplus.c @@ -344,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_new = sp_rtc_remove, + .remove = 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 441e0a66b215b7..79a3102c83549a 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -399,7 +399,7 @@ static void tegra_rtc_shutdown(struct platform_device *pdev) static struct platform_driver tegra_rtc_driver = { .probe = tegra_rtc_probe, - .remove_new = tegra_rtc_remove, + .remove = tegra_rtc_remove, .shutdown = tegra_rtc_shutdown, .driver = { .name = "tegra_rtc", diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 20faf08c254cc0..e796729fc817c1 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -317,7 +317,7 @@ static struct platform_driver tps6586x_rtc_driver = { .pm = &tps6586x_pm_ops, }, .probe = tps6586x_rtc_probe, - .remove_new = tps6586x_rtc_remove, + .remove = tps6586x_rtc_remove, }; module_platform_driver(tps6586x_rtc_driver); diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 4e24c12004f165..794429182b3480 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -673,7 +673,7 @@ MODULE_DEVICE_TABLE(of, twl_rtc_of_match); static struct platform_driver twl4030rtc_driver = { .probe = twl_rtc_probe, - .remove_new = twl_rtc_remove, + .remove = 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 ccfa76513a2ca8..c8b568498016f2 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -251,7 +251,7 @@ MODULE_DEVICE_TABLE(of, wmt_dt_ids); static struct platform_driver vt8500_rtc_driver = { .probe = vt8500_rtc_probe, - .remove_new = vt8500_rtc_remove, + .remove = 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 3c773cff2b3930..6797eb4d2e493e 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -459,7 +459,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_new = wm8350_rtc_remove, + .remove = 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 f78efc9760c0e9..0813ea1a03c273 100644 --- a/drivers/rtc/rtc-xgene.c +++ b/drivers/rtc/rtc-xgene.c @@ -263,7 +263,7 @@ MODULE_DEVICE_TABLE(of, xgene_rtc_of_match); static struct platform_driver xgene_rtc_driver = { .probe = xgene_rtc_probe, - .remove_new = xgene_rtc_remove, + .remove = 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 08ed171bdab43a..af1abb69d1e324 100644 --- a/drivers/rtc/rtc-zynqmp.c +++ b/drivers/rtc/rtc-zynqmp.c @@ -382,7 +382,7 @@ MODULE_DEVICE_TABLE(of, xlnx_rtc_of_match); static struct platform_driver xlnx_rtc_driver = { .probe = xlnx_rtc_probe, - .remove_new = xlnx_rtc_remove, + .remove = xlnx_rtc_remove, .driver = { .name = KBUILD_MODNAME, .pm = &xlnx_rtc_pm_ops, diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 42a4a996defbe1..3ed642f4f00dac 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2117,7 +2117,7 @@ int dasd_flush_device_queue(struct dasd_device *device) case DASD_CQR_IN_IO: rc = device->discipline->term_IO(cqr); if (rc) { - /* unable to terminate requeust */ + /* unable to terminate request */ dev_err(&device->cdev->dev, "Flushing the DASD request queue failed\n"); /* stop flush processing */ diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 6adaeb985dde12..71d8fb86139db6 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -855,7 +855,7 @@ dasd_delete_device(struct dasd_device *device) dev_set_drvdata(&device->cdev->dev, NULL); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); - /* Removve copy relation */ + /* Remove copy relation */ dasd_devmap_delete_copy_relation_device(device); /* * Drop ref_count by 3, one for the devmap reference, one for diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 8245b742e4a23c..26812abddef188 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "dasd_int.h" #include "dasd_diag.h" @@ -67,22 +68,24 @@ static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */ static inline int __dia250(void *iob, int cmd) { union register_pair rx = { .even = (unsigned long)iob, }; + int cc, exception; typedef union { struct dasd_diag_init_io init_io; struct dasd_diag_rw_io rw_io; } addr_type; - int cc; - cc = 3; + exception = 1; asm volatile( " diag %[rx],%[cmd],0x250\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b,1b) - : [cc] "+&d" (cc), [rx] "+&d" (rx.pair), "+m" (*(addr_type *)iob) + : CC_OUT(cc, cc), [rx] "+d" (rx.pair), + "+m" (*(addr_type *)iob), [exc] "+d" (exception) : [cmd] "d" (cmd) - : "cc"); + : CC_CLOBBER); + cc = exception ? 3 : CC_TRANSFORM(cc); return cc | rx.odd; } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 90b106408992d0..1ebe589b5185ad 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2405,7 +2405,7 @@ static int dasd_eckd_end_analysis(struct dasd_block *block) } if (count_area != NULL && count_area->kl == 0) { - /* we found notthing violating our disk layout */ + /* we found nothing violating our disk layout */ if (dasd_check_blocksize(count_area->dl) == 0) block->bp_block = count_area->dl; } diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 0faaa437d9be85..48e12e81df00c2 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -350,6 +350,7 @@ dasd_proc_init(void) remove_proc_entry("devices", dasd_proc_root_entry); out_nodevices: remove_proc_entry("dasd", NULL); + dasd_proc_root_entry = NULL; out_nodasd: return -ENOENT; } @@ -357,7 +358,11 @@ dasd_proc_init(void) void dasd_proc_exit(void) { + if (!dasd_proc_root_entry) + return; + remove_proc_entry("devices", dasd_proc_root_entry); remove_proc_entry("statistics", dasd_proc_root_entry); remove_proc_entry("dasd", NULL); + dasd_proc_root_entry = NULL; } diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 02a4a51da1b782..0f14d279d30b52 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -339,7 +339,7 @@ dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf struct dcssblk_dev_info *dev_info; dev_info = container_of(dev, struct dcssblk_dev_info, dev); - return sprintf(buf, dev_info->is_shared ? "1\n" : "0\n"); + return sysfs_emit(buf, dev_info->is_shared ? "1\n" : "0\n"); } static ssize_t @@ -444,7 +444,7 @@ dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf) struct dcssblk_dev_info *dev_info; dev_info = container_of(dev, struct dcssblk_dev_info, dev); - return sprintf(buf, dev_info->save_pending ? "1\n" : "0\n"); + return sysfs_emit(buf, dev_info->save_pending ? "1\n" : "0\n"); } static ssize_t @@ -506,21 +506,15 @@ static ssize_t dcssblk_seglist_show(struct device *dev, struct device_attribute *attr, char *buf) { - int i; - struct dcssblk_dev_info *dev_info; struct segment_info *entry; + int i; + i = 0; down_read(&dcssblk_devices_sem); dev_info = container_of(dev, struct dcssblk_dev_info, dev); - i = 0; - buf[0] = '\0'; - list_for_each_entry(entry, &dev_info->seg_list, lh) { - strcpy(&buf[i], entry->segment_name); - i += strlen(entry->segment_name); - buf[i] = '\n'; - i++; - } + list_for_each_entry(entry, &dev_info->seg_list, lh) + i += sysfs_emit_at(buf, i, "%s\n", entry->segment_name); up_read(&dcssblk_devices_sem); return i; } diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index dcb3c32f027af6..c763c50d145467 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -803,7 +803,6 @@ static struct attribute *con3215_drv_attrs[] = { static struct attribute_group con3215_drv_attr_group = { .attrs = con3215_drv_attrs, - NULL, }; static const struct attribute_group *con3215_drv_attr_groups[] = { diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 053102d0fcd2ec..ae1b9aa3a2b512 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -528,7 +528,7 @@ static void tty3270_update(struct timer_list *t) u8 cmd = TC_WRITE; int rc, len; - wrq = xchg(&tp->write, 0); + wrq = xchg(&tp->write, NULL); if (!wrq) { tty3270_set_timer(tp, 1); return; @@ -746,7 +746,7 @@ static void tty3270_issue_read(struct tty3270 *tp, int lock) struct raw3270_request *rrq; int rc; - rrq = xchg(&tp->read, 0); + rrq = xchg(&tp->read, NULL); if (!rrq) /* Read already scheduled. */ return; diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 6a23ec286c7021..6c91e422927ff5 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -14,6 +14,7 @@ #include #include #include +#include /* maximum number of pages concerning our own memory management */ #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) @@ -325,19 +326,22 @@ struct read_info_sccb * __init sclp_early_get_info(void); /* Perform service call. Return 0 on success, non-zero otherwise. */ static inline int sclp_service_call(sclp_cmdw_t command, void *sccb) { - int cc = 4; /* Initialize for program check handling */ + int cc, exception; + exception = 1; asm volatile( - "0: .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ - "1: ipm %0\n" - " srl %0,28\n" + "0: .insn rre,0xb2200000,%[cmd],%[sccb]\n" /* servc */ + "1: lhi %[exc],0\n" "2:\n" + CC_IPM(cc) EX_TABLE(0b, 2b) EX_TABLE(1b, 2b) - : "+&d" (cc) : "d" (command), "a" (__pa(sccb)) - : "cc", "memory"); - if (cc == 4) + : CC_OUT(cc, cc), [exc] "+d" (exception) + : [cmd] "d" (command), [sccb] "a" (__pa(sccb)) + : CC_CLOBBER_LIST("memory")); + if (exception) return -EINVAL; + cc = CC_TRANSFORM(cc); if (cc == 3) return -EIO; if (cc == 2) diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c index f60d7ea8268d10..d8f91aab11e830 100644 --- a/drivers/s390/char/sclp_cpi_sys.c +++ b/drivers/s390/char/sclp_cpi_sys.c @@ -223,7 +223,7 @@ static ssize_t system_name_show(struct kobject *kobj, int rc; mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", system_name); + rc = sysfs_emit(page, "%s\n", system_name); mutex_unlock(&sclp_cpi_mutex); return rc; } @@ -255,7 +255,7 @@ static ssize_t sysplex_name_show(struct kobject *kobj, int rc; mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", sysplex_name); + rc = sysfs_emit(page, "%s\n", sysplex_name); mutex_unlock(&sclp_cpi_mutex); return rc; } @@ -287,7 +287,7 @@ static ssize_t system_type_show(struct kobject *kobj, int rc; mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", system_type); + rc = sysfs_emit(page, "%s\n", system_type); mutex_unlock(&sclp_cpi_mutex); return rc; } @@ -321,7 +321,7 @@ static ssize_t system_level_show(struct kobject *kobj, mutex_lock(&sclp_cpi_mutex); level = system_level; mutex_unlock(&sclp_cpi_mutex); - return snprintf(page, PAGE_SIZE, "%#018llx\n", level); + return sysfs_emit(page, "%#018llx\n", level); } static ssize_t system_level_store(struct kobject *kobj, diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c index d35f10ea5b5218..ca6c5260dc53c8 100644 --- a/drivers/s390/char/sclp_ocf.c +++ b/drivers/s390/char/sclp_ocf.c @@ -101,7 +101,7 @@ static ssize_t cpc_name_show(struct kobject *kobj, sclp_ocf_cpc_name_copy(name); name[OCF_LENGTH_CPC_NAME] = 0; EBCASC(name, OCF_LENGTH_CPC_NAME); - return snprintf(page, PAGE_SIZE, "%s\n", name); + return sysfs_emit(page, "%s\n", name); } static struct kobj_attribute cpc_name_attr = @@ -113,7 +113,7 @@ static ssize_t hmc_network_show(struct kobject *kobj, int rc; spin_lock_irq(&sclp_ocf_lock); - rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network); + rc = sysfs_emit(page, "%s\n", hmc_network); spin_unlock_irq(&sclp_ocf_lock); return rc; } diff --git a/drivers/s390/char/sclp_pci.c b/drivers/s390/char/sclp_pci.c index a3e5a5fb0c1e73..c3466a8c56bb5d 100644 --- a/drivers/s390/char/sclp_pci.c +++ b/drivers/s390/char/sclp_pci.c @@ -27,6 +27,7 @@ #define SCLP_ERRNOTIFY_AQ_RESET 0 #define SCLP_ERRNOTIFY_AQ_REPAIR 1 #define SCLP_ERRNOTIFY_AQ_INFO_LOG 2 +#define SCLP_ERRNOTIFY_AQ_OPTICS_DATA 3 static DEFINE_MUTEX(sclp_pci_mutex); static struct sclp_register sclp_pci_event = { @@ -116,6 +117,7 @@ static int sclp_pci_check_report(struct zpci_report_error_header *report) case SCLP_ERRNOTIFY_AQ_RESET: case SCLP_ERRNOTIFY_AQ_REPAIR: case SCLP_ERRNOTIFY_AQ_INFO_LOG: + case SCLP_ERRNOTIFY_AQ_OPTICS_DATA: break; default: return -EINVAL; diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index a6d2a479218509..ce8a440598a814 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -96,7 +96,7 @@ tape_medium_state_show(struct device *dev, struct device_attribute *attr, char * struct tape_device *tdev; tdev = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state); + return sysfs_emit(buf, "%i\n", tdev->medium_state); } static @@ -108,7 +108,7 @@ tape_first_minor_show(struct device *dev, struct device_attribute *attr, char *b struct tape_device *tdev; tdev = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor); + return sysfs_emit(buf, "%i\n", tdev->first_minor); } static @@ -120,8 +120,8 @@ tape_state_show(struct device *dev, struct device_attribute *attr, char *buf) struct tape_device *tdev; tdev = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ? - "OFFLINE" : tape_state_verbose[tdev->tape_state]); + return sysfs_emit(buf, "%s\n", (tdev->first_minor < 0) ? + "OFFLINE" : tape_state_verbose[tdev->tape_state]); } static @@ -135,17 +135,17 @@ tape_operation_show(struct device *dev, struct device_attribute *attr, char *buf tdev = dev_get_drvdata(dev); if (tdev->first_minor < 0) - return scnprintf(buf, PAGE_SIZE, "N/A\n"); + return sysfs_emit(buf, "N/A\n"); spin_lock_irq(get_ccwdev_lock(tdev->cdev)); if (list_empty(&tdev->req_queue)) - rc = scnprintf(buf, PAGE_SIZE, "---\n"); + rc = sysfs_emit(buf, "---\n"); else { struct tape_request *req; req = list_entry(tdev->req_queue.next, struct tape_request, list); - rc = scnprintf(buf,PAGE_SIZE, "%s\n", tape_op_verbose[req->op]); + rc = sysfs_emit(buf, "%s\n", tape_op_verbose[req->op]); } spin_unlock_irq(get_ccwdev_lock(tdev->cdev)); return rc; @@ -161,7 +161,7 @@ tape_blocksize_show(struct device *dev, struct device_attribute *attr, char *buf tdev = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size); + return sysfs_emit(buf, "%i\n", tdev->char_data.block_size); } static diff --git a/drivers/s390/char/uvdevice.c b/drivers/s390/char/uvdevice.c index f598edc5f25192..2b83fb6dc1d76b 100644 --- a/drivers/s390/char/uvdevice.c +++ b/drivers/s390/char/uvdevice.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright IBM Corp. 2022 + * Copyright IBM Corp. 2022, 2024 * Author(s): Steffen Eiden * * This file provides a Linux misc device to give userspace access to some @@ -40,6 +40,7 @@ static const u32 ioctl_nr_to_uvc_bit[] __initconst = { [UVIO_IOCTL_ADD_SECRET_NR] = BIT_UVC_CMD_ADD_SECRET, [UVIO_IOCTL_LIST_SECRETS_NR] = BIT_UVC_CMD_LIST_SECRETS, [UVIO_IOCTL_LOCK_SECRETS_NR] = BIT_UVC_CMD_LOCK_SECRETS, + [UVIO_IOCTL_RETR_SECRET_NR] = BIT_UVC_CMD_RETR_ATTEST, }; static_assert(ARRAY_SIZE(ioctl_nr_to_uvc_bit) == UVIO_IOCTL_NUM_IOCTLS); @@ -62,11 +63,13 @@ static void __init set_supp_uv_cmds(unsigned long *supp_uv_cmds) } /** - * uvio_uvdev_info() - get information about the uvdevice + * uvio_uvdev_info() - Get information about the uvdevice * * @uv_ioctl: ioctl control block * * Lists all IOCTLs that are supported by this uvdevice + * + * Return: 0 on success or a negative error code on error */ static int uvio_uvdev_info(struct uvio_ioctl_cb *uv_ioctl) { @@ -177,7 +180,7 @@ static int get_uvio_attest(struct uvio_ioctl_cb *uv_ioctl, struct uvio_attest *u * * Context: might sleep * - * Return: 0 on success or a negative error code on error. + * Return: 0 on success or a negative error code on error */ static int uvio_attestation(struct uvio_ioctl_cb *uv_ioctl) { @@ -237,7 +240,8 @@ static int uvio_attestation(struct uvio_ioctl_cb *uv_ioctl) return ret; } -/** uvio_add_secret() - perform an Add Secret UVC +/** + * uvio_add_secret() - Perform an Add Secret UVC * * @uv_ioctl: ioctl control block * @@ -260,7 +264,7 @@ static int uvio_attestation(struct uvio_ioctl_cb *uv_ioctl) * * Context: might sleep * - * Return: 0 on success or a negative error code on error. + * Return: 0 on success or a negative error code on error */ static int uvio_add_secret(struct uvio_ioctl_cb *uv_ioctl) { @@ -296,7 +300,44 @@ static int uvio_add_secret(struct uvio_ioctl_cb *uv_ioctl) return ret; } -/** uvio_list_secrets() - perform a List Secret UVC +/* + * Do the actual secret list creation. Calls the list secrets UVC until there + * is no more space in the user buffer, or the list ends. + */ +static int uvio_get_list(void *zpage, struct uvio_ioctl_cb *uv_ioctl) +{ + const size_t data_off = offsetof(struct uv_secret_list, secrets); + u8 __user *user_buf = (u8 __user *)uv_ioctl->argument_addr; + struct uv_secret_list *list = zpage; + u16 num_secrets_stored = 0; + size_t user_off = data_off; + size_t copy_len; + + do { + uv_list_secrets(list, list->next_secret_idx, &uv_ioctl->uv_rc, + &uv_ioctl->uv_rrc); + if (uv_ioctl->uv_rc != UVC_RC_EXECUTED && + uv_ioctl->uv_rc != UVC_RC_MORE_DATA) + break; + + copy_len = sizeof(list->secrets[0]) * list->num_secr_stored; + if (copy_to_user(user_buf + user_off, list->secrets, copy_len)) + return -EFAULT; + + user_off += copy_len; + num_secrets_stored += list->num_secr_stored; + } while (uv_ioctl->uv_rc == UVC_RC_MORE_DATA && + user_off + sizeof(*list) <= uv_ioctl->argument_len); + + list->num_secr_stored = num_secrets_stored; + if (copy_to_user(user_buf, list, data_off)) + return -EFAULT; + return 0; +} + +/** + * uvio_list_secrets() - Perform a List Secret UVC + * * @uv_ioctl: ioctl control block * * uvio_list_secrets() performs the List Secret Ultravisor Call. It verifies @@ -307,45 +348,43 @@ static int uvio_add_secret(struct uvio_ioctl_cb *uv_ioctl) * * The argument specifies the location for the result of the UV-Call. * + * Argument length must be a multiple of a page. + * The list secrets IOCTL will call the list UVC multiple times and fill + * the provided user-buffer with list elements until either the list ends or + * the buffer is full. The list header is merged over all list header from the + * individual UVCs. + * * If the List Secrets UV facility is not present, UV will return invalid * command rc. This won't be fenced in the driver and does not result in a * negative return value. * * Context: might sleep * - * Return: 0 on success or a negative error code on error. + * Return: 0 on success or a negative error code on error */ static int uvio_list_secrets(struct uvio_ioctl_cb *uv_ioctl) { - void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr; - struct uv_cb_guest_addr uvcb = { - .header.len = sizeof(uvcb), - .header.cmd = UVC_CMD_LIST_SECRETS, - }; - void *secrets = NULL; - int ret = 0; + void *zpage; + int rc; - if (uv_ioctl->argument_len != UVIO_LIST_SECRETS_LEN) + if (uv_ioctl->argument_len == 0 || + uv_ioctl->argument_len % UVIO_LIST_SECRETS_LEN != 0) return -EINVAL; - secrets = kvzalloc(UVIO_LIST_SECRETS_LEN, GFP_KERNEL); - if (!secrets) + zpage = (void *)get_zeroed_page(GFP_KERNEL); + if (!zpage) return -ENOMEM; - uvcb.addr = (u64)secrets; - uv_call_sched(0, (u64)&uvcb); - uv_ioctl->uv_rc = uvcb.header.rc; - uv_ioctl->uv_rrc = uvcb.header.rrc; - - if (copy_to_user(user_buf_arg, secrets, UVIO_LIST_SECRETS_LEN)) - ret = -EFAULT; + rc = uvio_get_list(zpage, uv_ioctl); - kvfree(secrets); - return ret; + free_page((unsigned long)zpage); + return rc; } -/** uvio_lock_secrets() - perform a Lock Secret Store UVC - * @uv_ioctl: ioctl control block +/** + * uvio_lock_secrets() - Perform a Lock Secret Store UVC + * + * @ioctl: ioctl control block * * uvio_lock_secrets() performs the Lock Secret Store Ultravisor Call. It * performs the UV-call and copies the return codes to the ioctl control block. @@ -360,7 +399,7 @@ static int uvio_list_secrets(struct uvio_ioctl_cb *uv_ioctl) * * Context: might sleep * - * Return: 0 on success or a negative error code on error. + * Return: 0 on success or a negative error code on error */ static int uvio_lock_secrets(struct uvio_ioctl_cb *ioctl) { @@ -379,6 +418,59 @@ static int uvio_lock_secrets(struct uvio_ioctl_cb *ioctl) return 0; } +/** + * uvio_retr_secret() - Perform a retrieve secret UVC + * + * @uv_ioctl: ioctl control block. + * + * uvio_retr_secret() performs the Retrieve Secret Ultravisor Call. + * The first two bytes of the argument specify the index of the secret to be + * retrieved. The retrieved secret is copied into the argument buffer if there + * is enough space. + * The argument length must be at least two bytes and at max 8192 bytes. + * + * Context: might sleep + * + * Return: 0 on success or a negative error code on error + */ +static int uvio_retr_secret(struct uvio_ioctl_cb *uv_ioctl) +{ + u16 __user *user_index = (u16 __user *)uv_ioctl->argument_addr; + struct uv_cb_retr_secr uvcb = { + .header.len = sizeof(uvcb), + .header.cmd = UVC_CMD_RETR_SECRET, + }; + u32 buf_len = uv_ioctl->argument_len; + void *buf = NULL; + int ret; + + if (buf_len > UVIO_RETR_SECRET_MAX_LEN || buf_len < sizeof(*user_index)) + return -EINVAL; + + buf = kvzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = -EFAULT; + if (get_user(uvcb.secret_idx, user_index)) + goto err; + + uvcb.buf_addr = (u64)buf; + uvcb.buf_size = buf_len; + uv_call_sched(0, (u64)&uvcb); + + if (copy_to_user((__user void *)uv_ioctl->argument_addr, buf, buf_len)) + goto err; + + ret = 0; + uv_ioctl->uv_rc = uvcb.header.rc; + uv_ioctl->uv_rrc = uvcb.header.rrc; + +err: + kvfree_sensitive(buf, buf_len); + return ret; +} + static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp, unsigned long cmd) { @@ -432,6 +524,9 @@ static long uvio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case UVIO_IOCTL_LOCK_SECRETS_NR: ret = uvio_lock_secrets(&uv_ioctl); break; + case UVIO_IOCTL_RETR_SECRET_NR: + ret = uvio_retr_secret(&uv_ioctl); + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index bd5cecc44123ff..3dd50ac9c5b0d0 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -531,7 +531,7 @@ static ssize_t vmlogrdr_autopurge_show(struct device *dev, char *buf) { struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", priv->autopurge); + return sysfs_emit(buf, "%u\n", priv->autopurge); } @@ -605,7 +605,7 @@ static ssize_t vmlogrdr_autorecording_show(struct device *dev, char *buf) { struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", priv->autorecording); + return sysfs_emit(buf, "%u\n", priv->autorecording); } diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index fe94dec427b697..90ba7a2b9cb41c 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -345,7 +345,7 @@ static ssize_t ur_attr_reclen_show(struct device *dev, urd = urdev_get_from_cdev(to_ccwdev(dev)); if (!urd) return -ENODEV; - rc = sprintf(buf, "%zu\n", urd->reclen); + rc = sysfs_emit(buf, "%zu\n", urd->reclen); urdev_put(urd); return rc; } diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 66b1bdc6328443..7bcf8b98b8dd9b 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -147,7 +147,7 @@ static ssize_t ccwgroup_online_show(struct device *dev, online = (gdev->state == CCWGROUP_ONLINE) ? 1 : 0; - return scnprintf(buf, PAGE_SIZE, "%d\n", online); + return sysfs_emit(buf, "%d\n", online); } /* diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index a07bbecba61cd4..cba2d048a96b3c 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -144,6 +144,18 @@ static ssize_t measurement_chars_read(struct file *filp, struct kobject *kobj, } static BIN_ATTR_ADMIN_RO(measurement_chars, sizeof(struct cmg_chars)); +static ssize_t measurement_chars_full_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct channel_path *chp = to_channelpath(kobj_to_dev(kobj)); + + return memory_read_from_buffer(buf, count, &off, &chp->cmcb, + sizeof(chp->cmcb)); +} +static BIN_ATTR_ADMIN_RO(measurement_chars_full, sizeof(struct cmg_cmcb)); + static ssize_t chp_measurement_copy_block(void *buf, loff_t off, size_t count, struct kobject *kobj, bool extended) { @@ -201,6 +213,7 @@ static BIN_ATTR_ADMIN_RO(ext_measurement, sizeof(struct cmg_ext_entry)); static struct bin_attribute *measurement_attrs[] = { &bin_attr_measurement_chars, + &bin_attr_measurement_chars_full, &bin_attr_measurement, &bin_attr_ext_measurement, NULL, @@ -230,7 +243,7 @@ static ssize_t chp_status_show(struct device *dev, status = chp->state; mutex_unlock(&chp->lock); - return status ? sprintf(buf, "online\n") : sprintf(buf, "offline\n"); + return status ? sysfs_emit(buf, "online\n") : sysfs_emit(buf, "offline\n"); } static ssize_t chp_status_write(struct device *dev, @@ -311,7 +324,7 @@ static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr, mutex_lock(&chp->lock); type = chp->desc.desc; mutex_unlock(&chp->lock); - return sprintf(buf, "%x\n", type); + return sysfs_emit(buf, "%x\n", type); } static DEVICE_ATTR(type, 0444, chp_type_show, NULL); @@ -324,8 +337,8 @@ static ssize_t chp_cmg_show(struct device *dev, struct device_attribute *attr, if (!chp) return 0; if (chp->cmg == -1) /* channel measurements not available */ - return sprintf(buf, "unknown\n"); - return sprintf(buf, "%d\n", chp->cmg); + return sysfs_emit(buf, "unknown\n"); + return sysfs_emit(buf, "%d\n", chp->cmg); } static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL); @@ -338,8 +351,8 @@ static ssize_t chp_shared_show(struct device *dev, if (!chp) return 0; if (chp->shared == -1) /* channel measurements not available */ - return sprintf(buf, "unknown\n"); - return sprintf(buf, "%x\n", chp->shared); + return sysfs_emit(buf, "unknown\n"); + return sysfs_emit(buf, "%x\n", chp->shared); } static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL); @@ -352,7 +365,7 @@ static ssize_t chp_chid_show(struct device *dev, struct device_attribute *attr, mutex_lock(&chp->lock); if (chp->desc_fmt1.flags & 0x10) - rc = sprintf(buf, "%04x\n", chp->desc_fmt1.chid); + rc = sysfs_emit(buf, "%04x\n", chp->desc_fmt1.chid); else rc = 0; mutex_unlock(&chp->lock); @@ -369,7 +382,7 @@ static ssize_t chp_chid_external_show(struct device *dev, mutex_lock(&chp->lock); if (chp->desc_fmt1.flags & 0x10) - rc = sprintf(buf, "%x\n", chp->desc_fmt1.flags & 0x8 ? 1 : 0); + rc = sysfs_emit(buf, "%x\n", chp->desc_fmt1.flags & 0x8 ? 1 : 0); else rc = 0; mutex_unlock(&chp->lock); @@ -385,7 +398,7 @@ static ssize_t chp_esc_show(struct device *dev, ssize_t rc; mutex_lock(&chp->lock); - rc = sprintf(buf, "%x\n", chp->desc_fmt1.esc); + rc = sysfs_emit(buf, "%x\n", chp->desc_fmt1.esc); mutex_unlock(&chp->lock); return rc; diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index a15324a43aa3ad..391b52a7474cf7 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h @@ -54,6 +54,7 @@ struct channel_path { int extended; unsigned long speed; struct cmg_chars cmg_chars; + struct cmg_cmcb cmcb; }; /* Return channel_path struct for given chpid. */ diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index dcc1e1c34ca2e1..e6462317abd064 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -376,7 +376,7 @@ struct lir { #define PARAMS_LEN 10 /* PARAMS=xx,xxxxxx */ #define NODEID_LEN 35 /* NODEID=tttttt/mdl,mmm.ppssssssssssss,xxxx */ -/* Copy EBCIDC text, convert to ASCII and optionally add delimiter. */ +/* Copy EBCDIC text, convert to ASCII and optionally add delimiter. */ static char *store_ebcdic(char *dest, const char *src, unsigned long len, char delim) { @@ -1092,19 +1092,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) u32 zeroes1; struct chsc_header response; u32 zeroes2; - u32 not_valid : 1; - u32 shared : 1; - u32 extended : 1; - u32 : 21; - u32 chpid : 8; - u32 cmcv : 5; - u32 : 7; - u32 cmgp : 4; - u32 cmgq : 8; - u32 cmg : 8; - u32 : 16; - u32 cmgs : 16; - u32 data[NR_MEASUREMENT_CHARS]; + struct cmg_cmcb cmcb; } *scmc_area; chp->shared = -1; @@ -1135,15 +1123,16 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) scmc_area->response.code); goto out; } - if (scmc_area->not_valid) + chp->cmcb = scmc_area->cmcb; + if (scmc_area->cmcb.not_valid) goto out; - chp->cmg = scmc_area->cmg; - chp->shared = scmc_area->shared; - chp->extended = scmc_area->extended; - chp->speed = scmc_get_speed(scmc_area->cmgs, scmc_area->cmgp); - chsc_initialize_cmg_chars(chp, scmc_area->cmcv, - (struct cmg_chars *) &scmc_area->data); + chp->cmg = scmc_area->cmcb.cmg; + chp->shared = scmc_area->cmcb.shared; + chp->extended = scmc_area->cmcb.extended; + chp->speed = scmc_get_speed(scmc_area->cmcb.cmgs, scmc_area->cmcb.cmgp); + chsc_initialize_cmg_chars(chp, scmc_area->cmcb.cmcv, + (struct cmg_chars *)&scmc_area->cmcb.data); out: spin_unlock_irqrestore(&chsc_page_lock, flags); return ret; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 24cd65dbc5a763..6fe983ebf4b38a 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -17,6 +17,22 @@ struct cmg_chars { u32 values[NR_MEASUREMENT_CHARS]; }; +struct cmg_cmcb { + u32 not_valid : 1; + u32 shared : 1; + u32 extended : 1; + u32 : 21; + u32 chpid : 8; + u32 cmcv : 5; + u32 : 7; + u32 cmgp : 4; + u32 cmgq : 8; + u32 cmg : 8; + u32 : 16; + u32 cmgs : 16; + u32 data[NR_MEASUREMENT_CHARS]; +}; + #define NR_MEASUREMENT_ENTRIES 8 struct cmg_entry { u32 values[NR_MEASUREMENT_ENTRIES]; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index c32e818f06dbad..ad17ab0a931494 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -459,10 +459,14 @@ int cio_update_schib(struct subchannel *sch) { struct schib schib; - if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib)) + if (stsch(sch->schid, &schib)) return -ENODEV; memcpy(&sch->schib, &schib, sizeof(schib)); + + if (!css_sch_is_valid(&schib)) + return -EACCES; + return 0; } EXPORT_SYMBOL_GPL(cio_update_schib); diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index a9057a5b670a66..08a5e9380e75a9 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -19,7 +19,7 @@ struct pmcw { u32 intparm; /* interruption parameter */ u32 qf : 1; /* qdio facility */ u32 w : 1; - u32 isc : 3; /* interruption sublass */ + u32 isc : 3; /* interruption subclass */ u32 res5 : 3; /* reserved zeros */ u32 ena : 1; /* enabled */ u32 lm : 2; /* limit mode */ diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index f80dc18e2a7616..fdab760f1f28f6 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -46,7 +46,7 @@ /* indices for READCMB */ enum cmb_index { avg_utilization = -1, - /* basic and exended format: */ + /* basic and extended format: */ cmb_ssch_rsch_count = 0, cmb_sample_count, cmb_device_connect_time, @@ -135,7 +135,7 @@ static inline u64 time_to_nsec(u32 value) * Users are usually interested in average times, * not accumulated time. * This also helps us with atomicity problems - * when reading sinlge values. + * when reading single values. */ static inline u64 time_to_avg_nsec(u32 value, u32 count) { @@ -977,8 +977,7 @@ static struct cmb_operations cmbops_extended = { static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx) { - return sprintf(buf, "%lld\n", - (unsigned long long) cmf_read(to_ccwdev(dev), idx)); + return sysfs_emit(buf, "%lld\n", cmf_read(to_ccwdev(dev), idx)); } static ssize_t cmb_show_avg_sample_interval(struct device *dev, @@ -998,7 +997,7 @@ static ssize_t cmb_show_avg_sample_interval(struct device *dev, } else interval = -1; spin_unlock_irq(cdev->ccwlock); - return sprintf(buf, "%ld\n", interval); + return sysfs_emit(buf, "%ld\n", interval); } static ssize_t cmb_show_avg_utilization(struct device *dev, @@ -1007,7 +1006,7 @@ static ssize_t cmb_show_avg_utilization(struct device *dev, { unsigned long u = cmf_read(to_ccwdev(dev), avg_utilization); - return sprintf(buf, "%02lu.%01lu%%\n", u / 10, u % 10); + return sysfs_emit(buf, "%02lu.%01lu%%\n", u / 10, u % 10); } #define cmf_attr(name) \ @@ -1080,7 +1079,7 @@ static ssize_t cmb_enable_show(struct device *dev, { struct ccw_device *cdev = to_ccwdev(dev); - return sprintf(buf, "%d\n", cmf_enabled(cdev)); + return sysfs_emit(buf, "%d\n", cmf_enabled(cdev)); } static ssize_t cmb_enable_store(struct device *dev, @@ -1227,7 +1226,7 @@ int cmf_readall(struct ccw_device *cdev, struct cmbdata *data) return cmbops->readall(cdev, data); } -/* Reenable cmf when a disconnected device becomes available again. */ +/* Re-enable cmf when a disconnected device becomes available again. */ int cmf_reenable(struct ccw_device *cdev) { cmbops->reset(cdev); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 7b59d20bf7850e..be78a57f9bfdef 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -380,11 +380,11 @@ static ssize_t chpids_show(struct device *dev, for (chp = 0; chp < 8; chp++) { mask = 0x80 >> chp; if (ssd->path_mask & mask) - ret += sprintf(buf + ret, "%02x ", ssd->chpid[chp].id); + ret += sysfs_emit_at(buf, ret, "%02x ", ssd->chpid[chp].id); else - ret += sprintf(buf + ret, "00 "); + ret += sysfs_emit_at(buf, ret, "00 "); } - ret += sprintf(buf + ret, "\n"); + ret += sysfs_emit_at(buf, ret, "\n"); return ret; } static DEVICE_ATTR_RO(chpids); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index b0f23242e17145..fb2c07cb4d3dd3 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -201,10 +201,9 @@ devtype_show (struct device *dev, struct device_attribute *attr, char *buf) struct ccw_device_id *id = &(cdev->id); if (id->dev_type != 0) - return sprintf(buf, "%04x/%02x\n", - id->dev_type, id->dev_model); + return sysfs_emit(buf, "%04x/%02x\n", id->dev_type, id->dev_model); else - return sprintf(buf, "n/a\n"); + return sysfs_emit(buf, "n/a\n"); } static ssize_t @@ -213,8 +212,7 @@ cutype_show (struct device *dev, struct device_attribute *attr, char *buf) struct ccw_device *cdev = to_ccwdev(dev); struct ccw_device_id *id = &(cdev->id); - return sprintf(buf, "%04x/%02x\n", - id->cu_type, id->cu_model); + return sysfs_emit(buf, "%04x/%02x\n", id->cu_type, id->cu_model); } static ssize_t @@ -234,7 +232,7 @@ online_show (struct device *dev, struct device_attribute *attr, char *buf) { struct ccw_device *cdev = to_ccwdev(dev); - return sprintf(buf, cdev->online ? "1\n" : "0\n"); + return sysfs_emit(buf, cdev->online ? "1\n" : "0\n"); } int ccw_device_is_orphan(struct ccw_device *cdev) @@ -546,21 +544,21 @@ available_show (struct device *dev, struct device_attribute *attr, char *buf) struct subchannel *sch; if (ccw_device_is_orphan(cdev)) - return sprintf(buf, "no device\n"); + return sysfs_emit(buf, "no device\n"); switch (cdev->private->state) { case DEV_STATE_BOXED: - return sprintf(buf, "boxed\n"); + return sysfs_emit(buf, "boxed\n"); case DEV_STATE_DISCONNECTED: case DEV_STATE_DISCONNECTED_SENSE_ID: case DEV_STATE_NOT_OPER: sch = to_subchannel(dev->parent); if (!sch->lpm) - return sprintf(buf, "no path\n"); + return sysfs_emit(buf, "no path\n"); else - return sprintf(buf, "no device\n"); + return sysfs_emit(buf, "no device\n"); default: /* All other states considered fine. */ - return sprintf(buf, "good\n"); + return sysfs_emit(buf, "good\n"); } } @@ -587,7 +585,7 @@ static ssize_t vpm_show(struct device *dev, struct device_attribute *attr, { struct subchannel *sch = to_subchannel(dev); - return sprintf(buf, "%02x\n", sch->vpm); + return sysfs_emit(buf, "%02x\n", sch->vpm); } static DEVICE_ATTR_RO(devtype); @@ -1387,14 +1385,18 @@ enum io_sch_action { IO_SCH_VERIFY, IO_SCH_DISC, IO_SCH_NOP, + IO_SCH_ORPH_CDEV, }; static enum io_sch_action sch_get_action(struct subchannel *sch) { struct ccw_device *cdev; + int rc; cdev = sch_get_cdev(sch); - if (cio_update_schib(sch)) { + rc = cio_update_schib(sch); + + if (rc == -ENODEV) { /* Not operational. */ if (!cdev) return IO_SCH_UNREG; @@ -1402,6 +1404,16 @@ static enum io_sch_action sch_get_action(struct subchannel *sch) return IO_SCH_UNREG; return IO_SCH_ORPH_UNREG; } + + /* Avoid unregistering subchannels without working device. */ + if (rc == -EACCES) { + if (!cdev) + return IO_SCH_NOP; + if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK) + return IO_SCH_UNREG_CDEV; + return IO_SCH_ORPH_CDEV; + } + /* Operational. */ if (!cdev) return IO_SCH_ATTACH; @@ -1471,6 +1483,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) rc = 0; goto out_unlock; case IO_SCH_ORPH_UNREG: + case IO_SCH_ORPH_CDEV: case IO_SCH_ORPH_ATTACH: ccw_device_set_disconnected(cdev); break; @@ -1502,6 +1515,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) /* Handle attached ccw device. */ switch (action) { case IO_SCH_ORPH_UNREG: + case IO_SCH_ORPH_CDEV: case IO_SCH_ORPH_ATTACH: /* Move ccw device to orphanage. */ rc = ccw_device_move_to_orph(cdev); diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c index acf1edd3654965..5ff1e51cddf399 100644 --- a/drivers/s390/cio/ioasm.c +++ b/drivers/s390/cio/ioasm.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "ioasm.h" @@ -18,19 +19,20 @@ static inline int __stsch(struct subchannel_id schid, struct schib *addr) { unsigned long r1 = *(unsigned int *)&schid; - int ccode = -EIO; + int ccode, exception; + exception = 1; asm volatile( " lgr 1,%[r1]\n" " stsch %[addr]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+&d" (ccode), [addr] "=Q" (*addr) + : CC_OUT(cc, ccode), [addr] "=Q" (*addr), [exc] "+d" (exception) : [r1] "d" (r1) - : "cc", "1"); - return ccode; + : CC_CLOBBER_LIST("1")); + return exception ? -EIO : CC_TRANSFORM(ccode); } int stsch(struct subchannel_id schid, struct schib *addr) @@ -47,19 +49,20 @@ EXPORT_SYMBOL(stsch); static inline int __msch(struct subchannel_id schid, struct schib *addr) { unsigned long r1 = *(unsigned int *)&schid; - int ccode = -EIO; + int ccode, exception; + exception = 1; asm volatile( " lgr 1,%[r1]\n" " msch %[addr]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+&d" (ccode) + : CC_OUT(cc, ccode), [exc] "+d" (exception) : [r1] "d" (r1), [addr] "Q" (*addr) - : "cc", "1"); - return ccode; + : CC_CLOBBER_LIST("1")); + return exception ? -EIO : CC_TRANSFORM(ccode); } int msch(struct subchannel_id schid, struct schib *addr) @@ -80,12 +83,11 @@ static inline int __tsch(struct subchannel_id schid, struct irb *addr) asm volatile( " lgr 1,%[r1]\n" " tsch %[addr]\n" - " ipm %[cc]\n" - " srl %[cc],28" - : [cc] "=&d" (ccode), [addr] "=Q" (*addr) + CC_IPM(cc) + : CC_OUT(cc, ccode), [addr] "=Q" (*addr) : [r1] "d" (r1) - : "cc", "1"); - return ccode; + : CC_CLOBBER_LIST("1")); + return CC_TRANSFORM(ccode); } int tsch(struct subchannel_id schid, struct irb *addr) @@ -101,19 +103,20 @@ int tsch(struct subchannel_id schid, struct irb *addr) static inline int __ssch(struct subchannel_id schid, union orb *addr) { unsigned long r1 = *(unsigned int *)&schid; - int ccode = -EIO; + int ccode, exception; + exception = 1; asm volatile( " lgr 1,%[r1]\n" " ssch %[addr]\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+&d" (ccode) + : CC_OUT(cc, ccode), [exc] "+d" (exception) : [r1] "d" (r1), [addr] "Q" (*addr) - : "cc", "memory", "1"); - return ccode; + : CC_CLOBBER_LIST("memory", "1")); + return CC_TRANSFORM(ccode); } int ssch(struct subchannel_id schid, union orb *addr) @@ -135,12 +138,11 @@ static inline int __csch(struct subchannel_id schid) asm volatile( " lgr 1,%[r1]\n" " csch\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (ccode) + CC_IPM(cc) + : CC_OUT(cc, ccode) : [r1] "d" (r1) - : "cc", "1"); - return ccode; + : CC_CLOBBER_LIST("1")); + return CC_TRANSFORM(ccode); } int csch(struct subchannel_id schid) @@ -160,11 +162,11 @@ int tpi(struct tpi_info *addr) asm volatile( " tpi %[addr]\n" - " ipm %[cc]\n" - " srl %[cc],28" - : [cc] "=&d" (ccode), [addr] "=Q" (*addr) + CC_IPM(cc) + : CC_OUT(cc, ccode), [addr] "=Q" (*addr) : - : "cc"); + : CC_CLOBBER); + ccode = CC_TRANSFORM(ccode); trace_s390_cio_tpi(addr, ccode); return ccode; @@ -173,17 +175,19 @@ int tpi(struct tpi_info *addr) int chsc(void *chsc_area) { typedef struct { char _[4096]; } addr_type; - int cc = -EIO; + int cc, exception; + exception = 1; asm volatile( " .insn rre,0xb25f0000,%[chsc_area],0\n" - "0: ipm %[cc]\n" - " srl %[cc],28\n" + "0: lhi %[exc],0\n" "1:\n" + CC_IPM(cc) EX_TABLE(0b, 1b) - : [cc] "+&d" (cc), "+m" (*(addr_type *)chsc_area) + : CC_OUT(cc, cc), "+m" (*(addr_type *)chsc_area), [exc] "+d" (exception) : [chsc_area] "d" (chsc_area) - : "cc"); + : CC_CLOBBER); + cc = exception ? -EIO : CC_TRANSFORM(cc); trace_s390_cio_chsc(chsc_area, cc); return cc; @@ -198,12 +202,11 @@ static inline int __rsch(struct subchannel_id schid) asm volatile( " lgr 1,%[r1]\n" " rsch\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (ccode) + CC_IPM(cc) + : CC_OUT(cc, ccode) : [r1] "d" (r1) - : "cc", "memory", "1"); - return ccode; + : CC_CLOBBER_LIST("memory", "1")); + return CC_TRANSFORM(ccode); } int rsch(struct subchannel_id schid) @@ -224,12 +227,11 @@ static inline int __hsch(struct subchannel_id schid) asm volatile( " lgr 1,%[r1]\n" " hsch\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (ccode) + CC_IPM(cc) + : CC_OUT(cc, ccode) : [r1] "d" (r1) - : "cc", "1"); - return ccode; + : CC_CLOBBER_LIST("1")); + return CC_TRANSFORM(ccode); } int hsch(struct subchannel_id schid) @@ -256,7 +258,7 @@ static inline int __xsch(struct subchannel_id schid) : [cc] "=&d" (ccode) : [r1] "d" (r1) : "cc", "1"); - return ccode; + return CC_TRANSFORM(ccode); } int xsch(struct subchannel_id schid) @@ -275,12 +277,11 @@ static inline int __stcrw(struct crw *crw) asm volatile( " stcrw %[crw]\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (ccode), [crw] "=Q" (*crw) + CC_IPM(cc) + : CC_OUT(cc, ccode), [crw] "=Q" (*crw) : - : "cc"); - return ccode; + : CC_CLOBBER); + return CC_TRANSFORM(ccode); } static inline int _stcrw(struct crw *crw) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index b711bb17f9da92..07e82816b77adf 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "cio.h" @@ -42,13 +43,12 @@ static inline int do_siga_sync(unsigned long schid, " lgr 2,%[out]\n" " lgr 3,%[in]\n" " siga 0\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (cc) + CC_IPM(cc) + : CC_OUT(cc, cc) : [fc] "d" (fc), [schid] "d" (schid), [out] "d" (out_mask), [in] "d" (in_mask) - : "cc", "0", "1", "2", "3"); - return cc; + : CC_CLOBBER_LIST("0", "1", "2", "3")); + return CC_TRANSFORM(cc); } static inline int do_siga_input(unsigned long schid, unsigned long mask, @@ -61,12 +61,11 @@ static inline int do_siga_input(unsigned long schid, unsigned long mask, " lgr 1,%[schid]\n" " lgr 2,%[mask]\n" " siga 0\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (cc) + CC_IPM(cc) + : CC_OUT(cc, cc) : [fc] "d" (fc), [schid] "d" (schid), [mask] "d" (mask) - : "cc", "0", "1", "2"); - return cc; + : CC_CLOBBER_LIST("0", "1", "2")); + return CC_TRANSFORM(cc); } /** @@ -93,13 +92,12 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask, " lgr 3,%[aob]\n" " siga 0\n" " lgr %[fc],0\n" - " ipm %[cc]\n" - " srl %[cc],28\n" - : [cc] "=&d" (cc), [fc] "+&d" (fc) + CC_IPM(cc) + : CC_OUT(cc, cc), [fc] "+&d" (fc) : [schid] "d" (schid), [mask] "d" (mask), [aob] "d" (aob) - : "cc", "0", "1", "2", "3"); + : CC_CLOBBER_LIST("0", "1", "2", "3")); *bb = fc >> 31; - return cc; + return CC_TRANSFORM(cc); } /** diff --git a/drivers/s390/cio/scm.c b/drivers/s390/cio/scm.c index c7894d61306d74..a0825e372d420a 100644 --- a/drivers/s390/cio/scm.c +++ b/drivers/s390/cio/scm.c @@ -91,7 +91,7 @@ static ssize_t show_##name(struct device *dev, \ int ret; \ \ device_lock(dev); \ - ret = sprintf(buf, "%u\n", scmdev->attrs.name); \ + ret = sysfs_emit(buf, "%u\n", scmdev->attrs.name); \ device_unlock(dev); \ \ return ret; \ diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index c88b6e07184708..e83c6603c8587d 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -29,6 +29,10 @@ obj-$(CONFIG_PKEY_EP11) += pkey-ep11.o pkey-pckmo-objs := pkey_pckmo.o obj-$(CONFIG_PKEY_PCKMO) += pkey-pckmo.o +# pkey uv handler module +pkey-uv-objs := pkey_uv.o +obj-$(CONFIG_PKEY_UV) += pkey-uv.o + # adjunct processor matrix vfio_ap-objs := vfio_ap_drv.o vfio_ap_ops.o obj-$(CONFIG_VFIO_AP) += vfio_ap.o diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index e14638936de6b8..26e1ea1940ecb5 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -453,7 +453,7 @@ static void ap_tasklet_fn(unsigned long dummy) * important that no requests on any AP get lost. */ if (ap_irq_flag) - xchg(ap_airq.lsi_ptr, 0); + WRITE_ONCE(*ap_airq.lsi_ptr, 0); spin_lock_bh(&ap_queues_lock); hash_for_each(ap_queues, bkt, aq, hnode) { diff --git a/drivers/s390/crypto/pkey_base.c b/drivers/s390/crypto/pkey_base.c index fea24332283835..64a376501d2659 100644 --- a/drivers/s390/crypto/pkey_base.c +++ b/drivers/s390/crypto/pkey_base.c @@ -304,7 +304,19 @@ void pkey_handler_request_modules(void) { #ifdef CONFIG_MODULES static const char * const pkey_handler_modules[] = { - "pkey_cca", "pkey_ep11", "pkey_pckmo" }; +#if IS_MODULE(CONFIG_PKEY_CCA) + "pkey_cca", +#endif +#if IS_MODULE(CONFIG_PKEY_EP11) + "pkey_ep11", +#endif +#if IS_MODULE(CONFIG_PKEY_PCKMO) + "pkey_pckmo", +#endif +#if IS_MODULE(CONFIG_PKEY_UV) + "pkey_uv", +#endif + }; int i; for (i = 0; i < ARRAY_SIZE(pkey_handler_modules); i++) { diff --git a/drivers/s390/crypto/pkey_base.h b/drivers/s390/crypto/pkey_base.h index 7a1a5ce192d827..7347647dfaa768 100644 --- a/drivers/s390/crypto/pkey_base.h +++ b/drivers/s390/crypto/pkey_base.h @@ -96,6 +96,42 @@ static inline u32 pkey_aes_bitsize_to_keytype(u32 keybitsize) } } +/* + * helper function which translates the PKEY_KEYTYPE_* + * to the protected key size minus the WK VP length + */ +static inline u32 pkey_keytype_to_size(u32 keytype) +{ + switch (keytype) { + case PKEY_KEYTYPE_AES_128: + return 16; + case PKEY_KEYTYPE_AES_192: + return 24; + case PKEY_KEYTYPE_AES_256: + return 32; + case PKEY_KEYTYPE_ECC_P256: + return 32; + case PKEY_KEYTYPE_ECC_P384: + return 48; + case PKEY_KEYTYPE_ECC_P521: + return 80; + case PKEY_KEYTYPE_ECC_ED25519: + return 32; + case PKEY_KEYTYPE_ECC_ED448: + return 54; + case PKEY_KEYTYPE_AES_XTS_128: + return 32; + case PKEY_KEYTYPE_AES_XTS_256: + return 64; + case PKEY_KEYTYPE_HMAC_512: + return 64; + case PKEY_KEYTYPE_HMAC_1024: + return 128; + default: + return 0; + } +} + /* * pkey_api.c: */ diff --git a/drivers/s390/crypto/pkey_cca.c b/drivers/s390/crypto/pkey_cca.c index 9370513817209e..cda22db31f6c11 100644 --- a/drivers/s390/crypto/pkey_cca.c +++ b/drivers/s390/crypto/pkey_cca.c @@ -12,7 +12,6 @@ #include #include -#include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "pkey_base.h" @@ -225,14 +224,14 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns, if (hdr->type == TOKTYPE_CCA_INTERNAL && hdr->version == TOKVER_CCA_AES) { /* CCA AES data key */ - if (keylen != sizeof(struct secaeskeytoken)) + if (keylen < sizeof(struct secaeskeytoken)) return -EINVAL; if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0)) return -EINVAL; } else if (hdr->type == TOKTYPE_CCA_INTERNAL && hdr->version == TOKVER_CCA_VLSC) { /* CCA AES cipher key */ - if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE) + if (keylen < hdr->len) return -EINVAL; if (cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1)) diff --git a/drivers/s390/crypto/pkey_ep11.c b/drivers/s390/crypto/pkey_ep11.c index f42d397a9cb664..5b033ca3e8285a 100644 --- a/drivers/s390/crypto/pkey_ep11.c +++ b/drivers/s390/crypto/pkey_ep11.c @@ -12,7 +12,6 @@ #include #include -#include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "zcrypt_ep11misc.h" #include "pkey_base.h" diff --git a/drivers/s390/crypto/pkey_pckmo.c b/drivers/s390/crypto/pkey_pckmo.c index beeca8827c4649..835d59f4fbc563 100644 --- a/drivers/s390/crypto/pkey_pckmo.c +++ b/drivers/s390/crypto/pkey_pckmo.c @@ -15,7 +15,6 @@ #include #include -#include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "pkey_base.h" @@ -38,23 +37,9 @@ static bool is_pckmo_key(const u8 *key, u32 keylen) case TOKTYPE_NON_CCA: switch (hdr->version) { case TOKVER_CLEAR_KEY: - switch (t->keytype) { - case PKEY_KEYTYPE_AES_128: - case PKEY_KEYTYPE_AES_192: - case PKEY_KEYTYPE_AES_256: - case PKEY_KEYTYPE_ECC_P256: - case PKEY_KEYTYPE_ECC_P384: - case PKEY_KEYTYPE_ECC_P521: - case PKEY_KEYTYPE_ECC_ED25519: - case PKEY_KEYTYPE_ECC_ED448: - case PKEY_KEYTYPE_AES_XTS_128: - case PKEY_KEYTYPE_AES_XTS_256: - case PKEY_KEYTYPE_HMAC_512: - case PKEY_KEYTYPE_HMAC_1024: + if (pkey_keytype_to_size(t->keytype)) return true; - default: - return false; - } + return false; case TOKVER_PROTECTED_KEY: return true; default: @@ -86,80 +71,49 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen, int keysize, rc = -EINVAL; u8 paramblock[160]; - u32 pkeytype; - long fc; + u32 pkeytype = 0; + unsigned int fc; switch (keytype) { case PKEY_KEYTYPE_AES_128: - /* 16 byte key, 32 byte aes wkvp, total 48 bytes */ - keysize = 16; - pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_128_KEY; break; case PKEY_KEYTYPE_AES_192: - /* 24 byte key, 32 byte aes wkvp, total 56 bytes */ - keysize = 24; - pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_192_KEY; break; case PKEY_KEYTYPE_AES_256: - /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ - keysize = 32; - pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_256_KEY; break; case PKEY_KEYTYPE_ECC_P256: - /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ - keysize = 32; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_P256_KEY; break; case PKEY_KEYTYPE_ECC_P384: - /* 48 byte key, 32 byte aes wkvp, total 80 bytes */ - keysize = 48; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_P384_KEY; break; case PKEY_KEYTYPE_ECC_P521: - /* 80 byte key, 32 byte aes wkvp, total 112 bytes */ - keysize = 80; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_P521_KEY; break; case PKEY_KEYTYPE_ECC_ED25519: - /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ - keysize = 32; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_ED25519_KEY; break; case PKEY_KEYTYPE_ECC_ED448: - /* 64 byte key, 32 byte aes wkvp, total 96 bytes */ - keysize = 64; pkeytype = PKEY_KEYTYPE_ECC; fc = CPACF_PCKMO_ENC_ECC_ED448_KEY; break; case PKEY_KEYTYPE_AES_XTS_128: - /* 2x16 byte keys, 32 byte aes wkvp, total 64 bytes */ - keysize = 32; - pkeytype = PKEY_KEYTYPE_AES_XTS_128; fc = CPACF_PCKMO_ENC_AES_XTS_128_DOUBLE_KEY; break; case PKEY_KEYTYPE_AES_XTS_256: - /* 2x32 byte keys, 32 byte aes wkvp, total 96 bytes */ - keysize = 64; - pkeytype = PKEY_KEYTYPE_AES_XTS_256; fc = CPACF_PCKMO_ENC_AES_XTS_256_DOUBLE_KEY; break; case PKEY_KEYTYPE_HMAC_512: - /* 64 byte key, 32 byte aes wkvp, total 96 bytes */ - keysize = 64; - pkeytype = PKEY_KEYTYPE_HMAC_512; fc = CPACF_PCKMO_ENC_HMAC_512_KEY; break; case PKEY_KEYTYPE_HMAC_1024: - /* 128 byte key, 32 byte aes wkvp, total 160 bytes */ - keysize = 128; - pkeytype = PKEY_KEYTYPE_HMAC_1024; fc = CPACF_PCKMO_ENC_HMAC_1024_KEY; break; default: @@ -168,6 +122,9 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen, goto out; } + keysize = pkey_keytype_to_size(keytype); + pkeytype = pkeytype ?: keytype; + if (clrkeylen && clrkeylen < keysize) { PKEY_DBF_ERR("%s clear key size too small: %u < %d\n", __func__, clrkeylen, keysize); @@ -190,7 +147,8 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen, } /* check for the pckmo subfunction we need now */ if (!cpacf_test_func(&pckmo_functions, fc)) { - PKEY_DBF_ERR("%s pckmo functions not available\n", __func__); + PKEY_DBF_ERR("%s pckmo fc 0x%02x not available\n", + __func__, fc); rc = -ENODEV; goto out; } @@ -216,60 +174,42 @@ static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen, /* * Verify a raw protected key blob. - * Currently only AES protected keys are supported. */ static int pckmo_verify_protkey(const u8 *protkey, u32 protkeylen, u32 protkeytype) { - struct { - u8 iv[AES_BLOCK_SIZE]; - u8 key[MAXPROTKEYSIZE]; - } param; - u8 null_msg[AES_BLOCK_SIZE]; - u8 dest_buf[AES_BLOCK_SIZE]; - unsigned int k, pkeylen; - unsigned long fc; - int rc = -EINVAL; + u8 clrkey[16] = { 0 }, tmpkeybuf[16 + AES_WK_VP_SIZE]; + u32 tmpkeybuflen, tmpkeytype; + int keysize, rc = -EINVAL; + u8 *wkvp; - switch (protkeytype) { - case PKEY_KEYTYPE_AES_128: - pkeylen = 16 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_128; - break; - case PKEY_KEYTYPE_AES_192: - pkeylen = 24 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_192; - break; - case PKEY_KEYTYPE_AES_256: - pkeylen = 32 + AES_WK_VP_SIZE; - fc = CPACF_KMC_PAES_256; - break; - default: + /* check protkey type and size */ + keysize = pkey_keytype_to_size(protkeytype); + if (!keysize) { PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n", __func__, protkeytype); goto out; } - if (protkeylen != pkeylen) { - PKEY_DBF_ERR("%s invalid protected key size %u for keytype %u\n", - __func__, protkeylen, protkeytype); + if (protkeylen < keysize + AES_WK_VP_SIZE) goto out; - } - - memset(null_msg, 0, sizeof(null_msg)); - memset(param.iv, 0, sizeof(param.iv)); - memcpy(param.key, protkey, protkeylen); + /* generate a dummy AES 128 protected key */ + tmpkeybuflen = sizeof(tmpkeybuf); + rc = pckmo_clr2protkey(PKEY_KEYTYPE_AES_128, + clrkey, sizeof(clrkey), + tmpkeybuf, &tmpkeybuflen, &tmpkeytype); + if (rc) + goto out; + memzero_explicit(tmpkeybuf, 16); + wkvp = tmpkeybuf + 16; - k = cpacf_kmc(fc | CPACF_ENCRYPT, ¶m, null_msg, dest_buf, - sizeof(null_msg)); - if (k != sizeof(null_msg)) { - PKEY_DBF_ERR("%s protected key is not valid\n", __func__); + /* compare WK VP from the temp key with that of the given prot key */ + if (memcmp(wkvp, protkey + keysize, AES_WK_VP_SIZE)) { + PKEY_DBF_ERR("%s protected key WK VP mismatch\n", __func__); rc = -EKEYREJECTED; goto out; } - rc = 0; - out: pr_debug("rc=%d\n", rc); return rc; @@ -289,37 +229,33 @@ static int pckmo_key2protkey(const u8 *key, u32 keylen, switch (hdr->version) { case TOKVER_PROTECTED_KEY: { struct protkeytoken *t = (struct protkeytoken *)key; + u32 keysize; if (keylen < sizeof(*t)) goto out; + keysize = pkey_keytype_to_size(t->keytype); + if (!keysize) { + PKEY_DBF_ERR("%s protected key token: unknown keytype %u\n", + __func__, t->keytype); + goto out; + } switch (t->keytype) { case PKEY_KEYTYPE_AES_128: case PKEY_KEYTYPE_AES_192: case PKEY_KEYTYPE_AES_256: - if (keylen != sizeof(struct protaeskeytoken)) + if (t->len != keysize + AES_WK_VP_SIZE || + keylen < sizeof(struct protaeskeytoken)) goto out; rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype); if (rc) goto out; break; - case PKEY_KEYTYPE_AES_XTS_128: - if (t->len != 64 || keylen != sizeof(*t) + t->len) - goto out; - break; - case PKEY_KEYTYPE_AES_XTS_256: - case PKEY_KEYTYPE_HMAC_512: - if (t->len != 96 || keylen != sizeof(*t) + t->len) - goto out; - break; - case PKEY_KEYTYPE_HMAC_1024: - if (t->len != 160 || keylen != sizeof(*t) + t->len) + default: + if (t->len != keysize + AES_WK_VP_SIZE || + keylen < sizeof(*t) + keysize + AES_WK_VP_SIZE) goto out; break; - default: - PKEY_DBF_ERR("%s protected key token: unknown keytype %u\n", - __func__, t->keytype); - goto out; } memcpy(protkey, t->protkey, t->len); *protkeylen = t->len; @@ -329,47 +265,12 @@ static int pckmo_key2protkey(const u8 *key, u32 keylen, } case TOKVER_CLEAR_KEY: { struct clearkeytoken *t = (struct clearkeytoken *)key; - u32 keysize = 0; + u32 keysize; - if (keylen < sizeof(struct clearkeytoken) || - keylen != sizeof(*t) + t->len) + if (keylen < sizeof(*t) || + keylen < sizeof(*t) + t->len) goto out; - switch (t->keytype) { - case PKEY_KEYTYPE_AES_128: - case PKEY_KEYTYPE_AES_192: - case PKEY_KEYTYPE_AES_256: - keysize = pkey_keytype_aes_to_size(t->keytype); - break; - case PKEY_KEYTYPE_ECC_P256: - keysize = 32; - break; - case PKEY_KEYTYPE_ECC_P384: - keysize = 48; - break; - case PKEY_KEYTYPE_ECC_P521: - keysize = 80; - break; - case PKEY_KEYTYPE_ECC_ED25519: - keysize = 32; - break; - case PKEY_KEYTYPE_ECC_ED448: - keysize = 64; - break; - case PKEY_KEYTYPE_AES_XTS_128: - keysize = 32; - break; - case PKEY_KEYTYPE_AES_XTS_256: - keysize = 64; - break; - case PKEY_KEYTYPE_HMAC_512: - keysize = 64; - break; - case PKEY_KEYTYPE_HMAC_1024: - keysize = 128; - break; - default: - break; - } + keysize = pkey_keytype_to_size(t->keytype); if (!keysize) { PKEY_DBF_ERR("%s clear key token: unknown keytype %u\n", __func__, t->keytype); @@ -397,8 +298,6 @@ static int pckmo_key2protkey(const u8 *key, u32 keylen, /* * Generate a random protected key. - * Currently only the generation of AES protected keys - * is supported. */ static int pckmo_gen_protkey(u32 keytype, u32 subtype, u8 *protkey, u32 *protkeylen, u32 *protkeytype) @@ -407,32 +306,32 @@ static int pckmo_gen_protkey(u32 keytype, u32 subtype, int keysize; int rc; + keysize = pkey_keytype_to_size(keytype); + if (!keysize) { + PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", + __func__, keytype); + return -EINVAL; + } + if (subtype != PKEY_TYPE_PROTKEY) { + PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n", + __func__, subtype); + return -EINVAL; + } + switch (keytype) { case PKEY_KEYTYPE_AES_128: case PKEY_KEYTYPE_AES_192: case PKEY_KEYTYPE_AES_256: - keysize = pkey_keytype_aes_to_size(keytype); - break; case PKEY_KEYTYPE_AES_XTS_128: - keysize = 32; - break; case PKEY_KEYTYPE_AES_XTS_256: case PKEY_KEYTYPE_HMAC_512: - keysize = 64; - break; case PKEY_KEYTYPE_HMAC_1024: - keysize = 128; break; default: - PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n", + PKEY_DBF_ERR("%s unsupported keytype %d\n", __func__, keytype); return -EINVAL; } - if (subtype != PKEY_TYPE_PROTKEY) { - PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n", - __func__, subtype); - return -EINVAL; - } /* generate a dummy random clear key */ get_random_bytes(clrkey, keysize); @@ -453,7 +352,6 @@ static int pckmo_gen_protkey(u32 keytype, u32 subtype, /* * Verify a protected key token blob. - * Currently only AES protected keys are supported. */ static int pckmo_verify_key(const u8 *key, u32 keylen) { @@ -467,11 +365,26 @@ static int pckmo_verify_key(const u8 *key, u32 keylen) switch (hdr->version) { case TOKVER_PROTECTED_KEY: { - struct protaeskeytoken *t; + struct protkeytoken *t = (struct protkeytoken *)key; + u32 keysize; - if (keylen != sizeof(struct protaeskeytoken)) + if (keylen < sizeof(*t)) + goto out; + keysize = pkey_keytype_to_size(t->keytype); + if (!keysize || t->len != keysize + AES_WK_VP_SIZE) goto out; - t = (struct protaeskeytoken *)key; + switch (t->keytype) { + case PKEY_KEYTYPE_AES_128: + case PKEY_KEYTYPE_AES_192: + case PKEY_KEYTYPE_AES_256: + if (keylen < sizeof(struct protaeskeytoken)) + goto out; + break; + default: + if (keylen < sizeof(*t) + keysize + AES_WK_VP_SIZE) + goto out; + break; + } rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype); break; } diff --git a/drivers/s390/crypto/pkey_sysfs.c b/drivers/s390/crypto/pkey_sysfs.c index cc0fc1e264bd0d..a4eb45803f5e6d 100644 --- a/drivers/s390/crypto/pkey_sysfs.c +++ b/drivers/s390/crypto/pkey_sysfs.c @@ -10,7 +10,6 @@ #include -#include "zcrypt_api.h" #include "zcrypt_ccamisc.h" #include "zcrypt_ep11misc.h" diff --git a/drivers/s390/crypto/pkey_uv.c b/drivers/s390/crypto/pkey_uv.c new file mode 100644 index 00000000000000..805817b1435401 --- /dev/null +++ b/drivers/s390/crypto/pkey_uv.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * pkey uv specific code + * + * Copyright IBM Corp. 2024 + */ + +#define KMSG_COMPONENT "pkey" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include +#include + +#include "zcrypt_ccamisc.h" +#include "pkey_base.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); +MODULE_DESCRIPTION("s390 protected key UV handler"); + +/* + * UV secret token struct and defines. + */ + +#define TOKVER_UV_SECRET 0x09 + +struct uvsecrettoken { + u8 type; /* 0x00 = TOKTYPE_NON_CCA */ + u8 res0[3]; + u8 version; /* 0x09 = TOKVER_UV_SECRET */ + u8 res1[3]; + u16 secret_type; /* one of enum uv_secret_types from uv.h */ + u16 secret_len; /* length in bytes of the secret */ + u8 secret_id[UV_SECRET_ID_LEN]; /* the secret id for this secret */ +} __packed; + +/* + * Check key blob for known and supported UV key. + */ +static bool is_uv_key(const u8 *key, u32 keylen) +{ + struct uvsecrettoken *t = (struct uvsecrettoken *)key; + + if (keylen < sizeof(*t)) + return false; + + switch (t->type) { + case TOKTYPE_NON_CCA: + switch (t->version) { + case TOKVER_UV_SECRET: + switch (t->secret_type) { + case UV_SECRET_AES_128: + case UV_SECRET_AES_192: + case UV_SECRET_AES_256: + case UV_SECRET_AES_XTS_128: + case UV_SECRET_AES_XTS_256: + case UV_SECRET_HMAC_SHA_256: + case UV_SECRET_HMAC_SHA_512: + case UV_SECRET_ECDSA_P256: + case UV_SECRET_ECDSA_P384: + case UV_SECRET_ECDSA_P521: + case UV_SECRET_ECDSA_ED25519: + case UV_SECRET_ECDSA_ED448: + return true; + default: + return false; + } + default: + return false; + } + default: + return false; + } +} + +static bool is_uv_keytype(enum pkey_key_type keytype) +{ + switch (keytype) { + case PKEY_TYPE_UVSECRET: + return true; + default: + return false; + } +} + +static int retrieve_secret(const u8 secret_id[UV_SECRET_ID_LEN], + u16 *secret_type, u8 *buf, u32 *buflen) +{ + struct uv_secret_list_item_hdr secret_meta_data; + int rc; + + rc = uv_get_secret_metadata(secret_id, &secret_meta_data); + if (rc) + return rc; + + if (*buflen < secret_meta_data.length) + return -EINVAL; + + rc = uv_retrieve_secret(secret_meta_data.index, + buf, secret_meta_data.length); + if (rc) + return rc; + + *secret_type = secret_meta_data.type; + *buflen = secret_meta_data.length; + + return 0; +} + +static int uv_get_size_and_type(u16 secret_type, u32 *pkeysize, u32 *pkeytype) +{ + int rc = 0; + + switch (secret_type) { + case UV_SECRET_AES_128: + *pkeysize = 16 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_128; + break; + case UV_SECRET_AES_192: + *pkeysize = 24 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_192; + break; + case UV_SECRET_AES_256: + *pkeysize = 32 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_256; + break; + case UV_SECRET_AES_XTS_128: + *pkeysize = 16 + 16 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_XTS_128; + break; + case UV_SECRET_AES_XTS_256: + *pkeysize = 32 + 32 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_AES_XTS_256; + break; + case UV_SECRET_HMAC_SHA_256: + *pkeysize = 64 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_HMAC_512; + break; + case UV_SECRET_HMAC_SHA_512: + *pkeysize = 128 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_HMAC_1024; + break; + case UV_SECRET_ECDSA_P256: + *pkeysize = 32 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_P256; + break; + case UV_SECRET_ECDSA_P384: + *pkeysize = 48 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_P384; + break; + case UV_SECRET_ECDSA_P521: + *pkeysize = 80 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_P521; + break; + case UV_SECRET_ECDSA_ED25519: + *pkeysize = 32 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_ED25519; + break; + case UV_SECRET_ECDSA_ED448: + *pkeysize = 64 + AES_WK_VP_SIZE; + *pkeytype = PKEY_KEYTYPE_ECC_ED448; + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static int uv_key2protkey(const struct pkey_apqn *_apqns __always_unused, + size_t _nr_apqns __always_unused, + const u8 *key, u32 keylen, + u8 *protkey, u32 *protkeylen, u32 *keyinfo) +{ + struct uvsecrettoken *t = (struct uvsecrettoken *)key; + u32 pkeysize, pkeytype; + u16 secret_type; + int rc; + + rc = uv_get_size_and_type(t->secret_type, &pkeysize, &pkeytype); + if (rc) + goto out; + + if (*protkeylen < pkeysize) { + PKEY_DBF_ERR("%s prot key buffer size too small: %u < %u\n", + __func__, *protkeylen, pkeysize); + rc = -EINVAL; + goto out; + } + + rc = retrieve_secret(t->secret_id, &secret_type, protkey, protkeylen); + if (rc) { + PKEY_DBF_ERR("%s retrieve_secret() failed with %d\n", + __func__, rc); + goto out; + } + if (secret_type != t->secret_type) { + PKEY_DBF_ERR("%s retrieved secret type %u != expected type %u\n", + __func__, secret_type, t->secret_type); + rc = -EINVAL; + goto out; + } + + if (keyinfo) + *keyinfo = pkeytype; + +out: + pr_debug("rc=%d\n", rc); + return rc; +} + +static int uv_verifykey(const u8 *key, u32 keylen, + u16 *_card __always_unused, + u16 *_dom __always_unused, + u32 *keytype, u32 *keybitsize, u32 *flags) +{ + struct uvsecrettoken *t = (struct uvsecrettoken *)key; + struct uv_secret_list_item_hdr secret_meta_data; + u32 pkeysize, pkeytype, bitsize; + int rc; + + rc = uv_get_size_and_type(t->secret_type, &pkeysize, &pkeytype); + if (rc) + goto out; + + rc = uv_get_secret_metadata(t->secret_id, &secret_meta_data); + if (rc) + goto out; + + if (secret_meta_data.type != t->secret_type) { + rc = -EINVAL; + goto out; + } + + /* set keytype; keybitsize and flags are not supported */ + if (keytype) + *keytype = PKEY_TYPE_UVSECRET; + if (keybitsize) { + bitsize = 8 * pkey_keytype_to_size(pkeytype); + *keybitsize = bitsize ?: PKEY_SIZE_UNKNOWN; + } + if (flags) + *flags = pkeytype; + +out: + pr_debug("rc=%d\n", rc); + return rc; +} + +static struct pkey_handler uv_handler = { + .module = THIS_MODULE, + .name = "PKEY UV handler", + .is_supported_key = is_uv_key, + .is_supported_keytype = is_uv_keytype, + .key_to_protkey = uv_key2protkey, + .verify_key = uv_verifykey, +}; + +/* + * Module init + */ +static int __init pkey_uv_init(void) +{ + if (!is_prot_virt_guest()) + return -ENODEV; + + if (!test_bit_inv(BIT_UVC_CMD_RETR_SECRET, uv_info.inst_calls_list)) + return -ENODEV; + + return pkey_handler_register(&uv_handler); +} + +/* + * Module exit + */ +static void __exit pkey_uv_exit(void) +{ + pkey_handler_unregister(&uv_handler); +} + +module_cpu_feature_match(S390_CPU_FEATURE_UV, pkey_uv_init); +module_exit(pkey_uv_exit); diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 9f76f2d7b66e58..a52c2690933fd5 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -360,10 +360,26 @@ static int vfio_ap_validate_nib(struct kvm_vcpu *vcpu, dma_addr_t *nib) return 0; } -static int ensure_nib_shared(unsigned long addr, struct gmap *gmap) +/** + * ensure_nib_shared() - Ensure the address of the NIB is secure and shared + * @addr: the physical (absolute) address of the NIB + * + * This function checks whether the NIB page, which has been pinned with + * vfio_pin_pages(), is a shared page belonging to a secure guest. + * + * It will call uv_pin_shared() on it; if the page was already pinned shared + * (i.e. if the NIB belongs to a secure guest and is shared), then 0 + * (success) is returned. If the NIB was not shared, vfio_pin_pages() had + * exported it and now it does not belong to the secure guest anymore. In + * that case, an error is returned. + * + * Context: the NIB (at physical address @addr) has to be pinned with + * vfio_pin_pages() before calling this function. + * + * Return: 0 in case of success, otherwise an error < 0. + */ +static int ensure_nib_shared(unsigned long addr) { - int ret; - /* * The nib has to be located in shared storage since guest and * host access it. vfio_pin_pages() will do a pin shared and @@ -374,12 +390,7 @@ static int ensure_nib_shared(unsigned long addr, struct gmap *gmap) * * If the page is already pinned shared the UV will return a success. */ - ret = uv_pin_shared(addr); - if (ret) { - /* vfio_pin_pages() likely exported the page so let's re-import */ - gmap_convert_to_secure(gmap, addr); - } - return ret; + return uv_pin_shared(addr); } /** @@ -425,6 +436,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, return status; } + /* The pin will probably be successful even if the NIB was not shared */ ret = vfio_pin_pages(&q->matrix_mdev->vdev, nib, 1, IOMMU_READ | IOMMU_WRITE, &h_page); switch (ret) { @@ -447,7 +459,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, /* NIB in non-shared storage is a rc 6 for PV guests */ if (kvm_s390_pv_cpu_is_protected(vcpu) && - ensure_nib_shared(h_nib & PAGE_MASK, kvm->arch.gmap)) { + ensure_nib_shared(h_nib & PAGE_MASK)) { vfio_unpin_pages(&q->matrix_mdev->vdev, nib, 1); status.response_code = AP_RESPONSE_INVALID_ADDRESS; return status; @@ -1521,18 +1533,13 @@ static ssize_t control_domains_show(struct device *dev, char *buf) { unsigned long id; - int nchars = 0; - int n; - char *bufpos = buf; struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev); unsigned long max_domid = matrix_mdev->matrix.adm_max; + int nchars = 0; mutex_lock(&matrix_dev->mdevs_lock); - for_each_set_bit_inv(id, matrix_mdev->matrix.adm, max_domid + 1) { - n = sprintf(bufpos, "%04lx\n", id); - bufpos += n; - nchars += n; - } + for_each_set_bit_inv(id, matrix_mdev->matrix.adm, max_domid + 1) + nchars += sysfs_emit_at(buf, nchars, "%04lx\n", id); mutex_unlock(&matrix_dev->mdevs_lock); return nchars; @@ -1541,7 +1548,6 @@ static DEVICE_ATTR_RO(control_domains); static ssize_t vfio_ap_mdev_matrix_show(struct ap_matrix *matrix, char *buf) { - char *bufpos = buf; unsigned long apid; unsigned long apqi; unsigned long apid1; @@ -1549,33 +1555,21 @@ static ssize_t vfio_ap_mdev_matrix_show(struct ap_matrix *matrix, char *buf) unsigned long napm_bits = matrix->apm_max + 1; unsigned long naqm_bits = matrix->aqm_max + 1; int nchars = 0; - int n; apid1 = find_first_bit_inv(matrix->apm, napm_bits); apqi1 = find_first_bit_inv(matrix->aqm, naqm_bits); if ((apid1 < napm_bits) && (apqi1 < naqm_bits)) { for_each_set_bit_inv(apid, matrix->apm, napm_bits) { - for_each_set_bit_inv(apqi, matrix->aqm, - naqm_bits) { - n = sprintf(bufpos, "%02lx.%04lx\n", apid, - apqi); - bufpos += n; - nchars += n; - } + for_each_set_bit_inv(apqi, matrix->aqm, naqm_bits) + nchars += sysfs_emit_at(buf, nchars, "%02lx.%04lx\n", apid, apqi); } } else if (apid1 < napm_bits) { - for_each_set_bit_inv(apid, matrix->apm, napm_bits) { - n = sprintf(bufpos, "%02lx.\n", apid); - bufpos += n; - nchars += n; - } + for_each_set_bit_inv(apid, matrix->apm, napm_bits) + nchars += sysfs_emit_at(buf, nchars, "%02lx.\n", apid); } else if (apqi1 < naqm_bits) { - for_each_set_bit_inv(apqi, matrix->aqm, naqm_bits) { - n = sprintf(bufpos, ".%04lx\n", apqi); - bufpos += n; - nchars += n; - } + for_each_set_bit_inv(apqi, matrix->aqm, naqm_bits) + nchars += sysfs_emit_at(buf, nchars, ".%04lx\n", apqi); } return nchars; @@ -2263,14 +2257,11 @@ static ssize_t status_show(struct device *dev, if (matrix_mdev->kvm && test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) && test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) - nchars = scnprintf(buf, PAGE_SIZE, "%s\n", - AP_QUEUE_IN_USE); + nchars = sysfs_emit(buf, "%s\n", AP_QUEUE_IN_USE); else - nchars = scnprintf(buf, PAGE_SIZE, "%s\n", - AP_QUEUE_ASSIGNED); + nchars = sysfs_emit(buf, "%s\n", AP_QUEUE_ASSIGNED); } else { - nchars = scnprintf(buf, PAGE_SIZE, "%s\n", - AP_QUEUE_UNASSIGNED); + nchars = sysfs_emit(buf, "%s\n", AP_QUEUE_UNASSIGNED); } mutex_unlock(&matrix_dev->mdevs_lock); diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h index aed7e838454267..26bdca702523dc 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.h +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -12,6 +12,7 @@ #include #include +#include "zcrypt_api.h" /* Key token types */ #define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */ diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 039e18d46f769b..31c9f95d809d47 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1319,7 +1319,7 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%s\n", netiucv_printuser(priv->conn)); + return sysfs_emit(buf, "%s\n", netiucv_printuser(priv->conn)); } static int netiucv_check_user(const char *buf, size_t count, char *username, @@ -1415,7 +1415,7 @@ static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%d\n", priv->conn->max_buffsize); + return sysfs_emit(buf, "%d\n", priv->conn->max_buffsize); } static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, @@ -1473,7 +1473,7 @@ static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm)); + return sysfs_emit(buf, "%s\n", fsm_getstate_str(priv->fsm)); } static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); @@ -1484,7 +1484,7 @@ static ssize_t conn_fsm_show (struct device *dev, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm)); + return sysfs_emit(buf, "%s\n", fsm_getstate_str(priv->conn->fsm)); } static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); @@ -1495,7 +1495,7 @@ static ssize_t maxmulti_show (struct device *dev, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); + return sysfs_emit(buf, "%ld\n", priv->conn->prof.maxmulti); } static ssize_t maxmulti_write (struct device *dev, @@ -1517,7 +1517,7 @@ static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); + return sysfs_emit(buf, "%ld\n", priv->conn->prof.maxcqueue); } static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, @@ -1538,7 +1538,7 @@ static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); + return sysfs_emit(buf, "%ld\n", priv->conn->prof.doios_single); } static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, @@ -1559,7 +1559,7 @@ static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); + return sysfs_emit(buf, "%ld\n", priv->conn->prof.doios_multi); } static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, @@ -1580,7 +1580,7 @@ static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%ld\n", priv->conn->prof.txlen); + return sysfs_emit(buf, "%ld\n", priv->conn->prof.txlen); } static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, @@ -1601,7 +1601,7 @@ static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); + return sysfs_emit(buf, "%ld\n", priv->conn->prof.tx_time); } static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, @@ -1622,7 +1622,7 @@ static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); + return sysfs_emit(buf, "%ld\n", priv->conn->prof.tx_pending); } static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, @@ -1643,7 +1643,7 @@ static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, struct netiucv_priv *priv = dev_get_drvdata(dev); IUCV_DBF_TEXT(trace, 5, __func__); - return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); + return sysfs_emit(buf, "%ld\n", priv->conn->prof.tx_max_pending); } static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index cb67fa80fb12c8..304b81bb5f90c4 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -24,7 +24,7 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ { \ struct _feat_def *_feat = container_of(dev, struct _feat_def, dev); \ \ - return sprintf(buf, _format, _value); \ + return sysfs_emit(buf, _format, _value); \ } \ static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ zfcp_sysfs_##_feat##_##_name##_show, NULL); @@ -34,7 +34,7 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ struct device_attribute *at,\ char *buf) \ { \ - return sprintf(buf, _format, _value); \ + return sysfs_emit(buf, _format, _value); \ } \ static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ zfcp_sysfs_##_feat##_##_name##_show, NULL); @@ -51,7 +51,7 @@ static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ if (!adapter) \ return -ENODEV; \ \ - i = sprintf(buf, _format, _value); \ + i = sysfs_emit(buf, _format, _value); \ zfcp_ccw_adapter_put(adapter); \ return i; \ } \ @@ -95,9 +95,9 @@ static ssize_t zfcp_sysfs_port_failed_show(struct device *dev, struct zfcp_port *port = container_of(dev, struct zfcp_port, dev); if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - return sprintf(buf, "1\n"); + return sysfs_emit(buf, "1\n"); - return sprintf(buf, "0\n"); + return sysfs_emit(buf, "0\n"); } static ssize_t zfcp_sysfs_port_failed_store(struct device *dev, @@ -135,7 +135,7 @@ static ssize_t zfcp_sysfs_unit_failed_show(struct device *dev, scsi_device_put(sdev); } - return sprintf(buf, "%d\n", failed); + return sysfs_emit(buf, "%d\n", failed); } static ssize_t zfcp_sysfs_unit_failed_store(struct device *dev, @@ -176,9 +176,9 @@ static ssize_t zfcp_sysfs_adapter_failed_show(struct device *dev, return -ENODEV; if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - i = sprintf(buf, "1\n"); + i = sysfs_emit(buf, "1\n"); else - i = sprintf(buf, "0\n"); + i = sysfs_emit(buf, "0\n"); zfcp_ccw_adapter_put(adapter); return i; @@ -348,8 +348,7 @@ zfcp_sysfs_adapter_diag_max_age_show(struct device *dev, if (!adapter) return -ENODEV; - /* ceil(log(2^64 - 1) / log(10)) = 20 */ - rc = scnprintf(buf, 20 + 2, "%lu\n", adapter->diagnostics->max_age); + rc = sysfs_emit(buf, "%lu\n", adapter->diagnostics->max_age); zfcp_ccw_adapter_put(adapter); return rc; @@ -401,14 +400,14 @@ static ssize_t zfcp_sysfs_adapter_fc_security_show( */ status = atomic_read(&adapter->status); if (0 == (status & ZFCP_STATUS_COMMON_OPEN)) - i = sprintf(buf, "unknown\n"); + i = sysfs_emit(buf, "unknown\n"); else if (!(adapter->adapter_features & FSF_FEATURE_FC_SECURITY)) - i = sprintf(buf, "unsupported\n"); + i = sysfs_emit(buf, "unsupported\n"); else { i = zfcp_fsf_scnprint_fc_security( buf, PAGE_SIZE - 1, adapter->fc_security_algorithms, ZFCP_FSF_PRINT_FMT_LIST); - i += scnprintf(buf + i, PAGE_SIZE - i, "\n"); + i += sysfs_emit_at(buf, i, "\n"); } zfcp_ccw_adapter_put(adapter); @@ -490,14 +489,14 @@ static ssize_t zfcp_sysfs_port_fc_security_show(struct device *dev, 0 != (status & ZFCP_STATUS_PORT_LINK_TEST) || 0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED) || 0 != (status & ZFCP_STATUS_COMMON_ACCESS_BOXED)) - i = sprintf(buf, "unknown\n"); + i = sysfs_emit(buf, "unknown\n"); else if (!(adapter->adapter_features & FSF_FEATURE_FC_SECURITY)) - i = sprintf(buf, "unsupported\n"); + i = sysfs_emit(buf, "unsupported\n"); else { i = zfcp_fsf_scnprint_fc_security( buf, PAGE_SIZE - 1, port->connection_info, ZFCP_FSF_PRINT_FMT_SINGLEITEM); - i += scnprintf(buf + i, PAGE_SIZE - i, "\n"); + i += sysfs_emit_at(buf, i, "\n"); } return i; @@ -569,8 +568,8 @@ zfcp_sysfs_unit_##_name##_latency_show(struct device *dev, \ do_div(cmin, 1000); \ do_div(cmax, 1000); \ \ - return sprintf(buf, "%llu %llu %llu %llu %llu %llu %llu\n", \ - fmin, fmax, fsum, cmin, cmax, csum, cc); \ + return sysfs_emit(buf, "%llu %llu %llu %llu %llu %llu %llu\n", \ + fmin, fmax, fsum, cmin, cmax, csum, cc); \ } \ static ssize_t \ zfcp_sysfs_unit_##_name##_latency_store(struct device *dev, \ @@ -610,8 +609,8 @@ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \ struct scsi_device *sdev = to_scsi_device(dev); \ struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \ \ - return sprintf(buf, _format, _value); \ -} \ + return sysfs_emit(buf, _format, _value); \ +} \ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL); ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n", @@ -625,7 +624,7 @@ static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev, { struct scsi_device *sdev = to_scsi_device(dev); - return sprintf(buf, "0x%016llx\n", zfcp_scsi_dev_lun(sdev)); + return sysfs_emit(buf, "0x%016llx\n", zfcp_scsi_dev_lun(sdev)); } static DEVICE_ATTR(fcp_lun, S_IRUGO, zfcp_sysfs_scsi_fcp_lun_show, NULL); @@ -641,7 +640,7 @@ static ssize_t zfcp_sysfs_scsi_zfcp_failed_show(struct device *dev, unsigned int status = atomic_read(&sdev_to_zfcp(sdev)->status); unsigned int failed = status & ZFCP_STATUS_COMMON_ERP_FAILED ? 1 : 0; - return sprintf(buf, "%d\n", failed); + return sysfs_emit(buf, "%d\n", failed); } static ssize_t zfcp_sysfs_scsi_zfcp_failed_store(struct device *dev, @@ -714,8 +713,8 @@ static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, retval = zfcp_fsf_exchange_port_data_sync(adapter->qdio, qtcb_port); if (retval == 0 || retval == -EAGAIN) - retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, - qtcb_port->cb_util, qtcb_port->a_util); + retval = sysfs_emit(buf, "%u %u %u\n", qtcb_port->cp_util, + qtcb_port->cb_util, qtcb_port->a_util); kfree(qtcb_port); return retval; } @@ -758,7 +757,7 @@ static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ if (retval) \ return retval; \ \ - return sprintf(buf, _format, ## _arg); \ + return sysfs_emit(buf, _format, ## _arg); \ } \ static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); @@ -787,8 +786,8 @@ static ssize_t zfcp_sysfs_adapter_q_full_show(struct device *dev, util = qdio->req_q_util; spin_unlock_bh(&qdio->stat_lock); - return sprintf(buf, "%d %llu\n", atomic_read(&qdio->req_q_full), - (unsigned long long)util); + return sysfs_emit(buf, "%d %llu\n", atomic_read(&qdio->req_q_full), + (unsigned long long)util); } static DEVICE_ATTR(queue_full, S_IRUGO, zfcp_sysfs_adapter_q_full_show, NULL); @@ -843,8 +842,7 @@ static ssize_t zfcp_sysfs_adapter_diag_b2b_credit_show( .data.nport_serv_param - sizeof(u32)); - rc = scnprintf(buf, 5 + 2, "%hu\n", - be16_to_cpu(nsp->fl_csp.sp_bb_cred)); + rc = sysfs_emit(buf, "%hu\n", be16_to_cpu(nsp->fl_csp.sp_bb_cred)); spin_unlock_irqrestore(&diag_hdr->access_lock, flags); out: @@ -854,7 +852,7 @@ static ssize_t zfcp_sysfs_adapter_diag_b2b_credit_show( static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400, zfcp_sysfs_adapter_diag_b2b_credit_show, NULL); -#define ZFCP_DEFINE_DIAG_SFP_ATTR(_name, _qtcb_member, _prtsize, _prtfmt) \ +#define ZFCP_DEFINE_DIAG_SFP_ATTR(_name, _qtcb_member, _prtfmt) \ static ssize_t zfcp_sysfs_adapter_diag_sfp_##_name##_show( \ struct device *dev, struct device_attribute *attr, char *buf) \ { \ @@ -887,8 +885,8 @@ static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400, goto out; \ \ spin_lock_irqsave(&diag_hdr->access_lock, flags); \ - rc = scnprintf( \ - buf, (_prtsize) + 2, _prtfmt "\n", \ + rc = sysfs_emit( \ + buf, _prtfmt "\n", \ adapter->diagnostics->port_data.data._qtcb_member); \ spin_unlock_irqrestore(&diag_hdr->access_lock, flags); \ \ @@ -899,16 +897,16 @@ static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400, static ZFCP_DEV_ATTR(adapter_diag_sfp, _name, 0400, \ zfcp_sysfs_adapter_diag_sfp_##_name##_show, NULL) -ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 6, "%hd"); -ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, 5, "%hu"); -ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, 5, "%hu"); -ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, 5, "%hu"); -ZFCP_DEFINE_DIAG_SFP_ATTR(rx_power, rx_power, 5, "%hu"); -ZFCP_DEFINE_DIAG_SFP_ATTR(port_tx_type, sfp_flags.port_tx_type, 2, "%hu"); -ZFCP_DEFINE_DIAG_SFP_ATTR(optical_port, sfp_flags.optical_port, 1, "%hu"); -ZFCP_DEFINE_DIAG_SFP_ATTR(sfp_invalid, sfp_flags.sfp_invalid, 1, "%hu"); -ZFCP_DEFINE_DIAG_SFP_ATTR(connector_type, sfp_flags.connector_type, 1, "%hu"); -ZFCP_DEFINE_DIAG_SFP_ATTR(fec_active, sfp_flags.fec_active, 1, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, "%hd"); +ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(rx_power, rx_power, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(port_tx_type, sfp_flags.port_tx_type, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(optical_port, sfp_flags.optical_port, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(sfp_invalid, sfp_flags.sfp_invalid, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(connector_type, sfp_flags.connector_type, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(fec_active, sfp_flags.fec_active, "%hu"); static struct attribute *zfcp_sysfs_diag_attrs[] = { &dev_attr_adapter_diag_sfp_temperature.attr, diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 62eca9419ad76e..21fa7ac849e5c3 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -58,6 +58,8 @@ struct virtio_ccw_device { struct virtio_device vdev; __u8 config[VIRTIO_CCW_CONFIG_SIZE]; struct ccw_device *cdev; + /* we make cdev->dev.dma_parms point to this */ + struct device_dma_parameters dma_parms; __u32 curr_io; int err; unsigned int revision; /* Transport revision */ @@ -1303,6 +1305,7 @@ static int virtio_ccw_offline(struct ccw_device *cdev) unregister_virtio_device(&vcdev->vdev); spin_lock_irqsave(get_ccwdev_lock(cdev), flags); dev_set_drvdata(&cdev->dev, NULL); + cdev->dev.dma_parms = NULL; spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); return 0; } @@ -1366,6 +1369,7 @@ static int virtio_ccw_online(struct ccw_device *cdev) } vcdev->vdev.dev.parent = &cdev->dev; vcdev->cdev = cdev; + cdev->dev.dma_parms = &vcdev->dma_parms; vcdev->dma_area = ccw_device_dma_zalloc(vcdev->cdev, sizeof(*vcdev->dma_area), &vcdev->dma_area_addr); diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index d7fcde692f46ae..90e71ce4bab868 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -413,7 +413,7 @@ static struct platform_driver bbc_i2c_driver = { .of_match_table = bbc_i2c_match, }, .probe = bbc_i2c_probe, - .remove_new = bbc_i2c_remove, + .remove = bbc_i2c_remove, }; module_platform_driver(bbc_i2c_driver); diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 521cf8affe65a1..e94222b3523cdc 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -261,7 +261,7 @@ static struct platform_driver d7s_driver = { .of_match_table = d7s_match, }, .probe = d7s_probe, - .remove_new = d7s_remove, + .remove = d7s_remove, }; module_platform_driver(d7s_driver); diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index b543e9bcc78590..81918aa6710992 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1125,7 +1125,7 @@ static struct platform_driver envctrl_driver = { .of_match_table = envctrl_match, }, .probe = envctrl_probe, - .remove_new = envctrl_remove, + .remove = envctrl_remove, }; module_platform_driver(envctrl_driver); diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index ddd449dfda31a6..6524a4a1910956 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -206,7 +206,7 @@ static struct platform_driver flash_driver = { .of_match_table = flash_match, }, .probe = flash_probe, - .remove_new = flash_remove, + .remove = flash_remove, }; module_platform_driver(flash_driver); diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 8bbed7a7afb77f..e3dec78f51e9d7 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -424,7 +424,7 @@ static struct platform_driver uctrl_driver = { .of_match_table = uctrl_match, }, .probe = uctrl_probe, - .remove_new = uctrl_remove, + .remove = uctrl_remove, }; diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index ad39797890e59a..bf054dd7682bf1 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -302,9 +302,9 @@ static void __exit amiga_a3000_scsi_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver amiga_a3000_scsi_driver __refdata = { - .remove_new = __exit_p(amiga_a3000_scsi_remove), - .driver = { - .name = "amiga-a3000-scsi", + .remove = __exit_p(amiga_a3000_scsi_remove), + .driver = { + .name = "amiga-a3000-scsi", }, }; diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c index d9103adc87fef4..75b43047a15581 100644 --- a/drivers/scsi/a4000t.c +++ b/drivers/scsi/a4000t.c @@ -115,9 +115,9 @@ static void __exit amiga_a4000t_scsi_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver amiga_a4000t_scsi_driver __refdata = { - .remove_new = __exit_p(amiga_a4000t_scsi_remove), - .driver = { - .name = "amiga-a4000t-scsi", + .remove = __exit_p(amiga_a4000t_scsi_remove), + .driver = { + .name = "amiga-a4000t-scsi", }, }; diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 1d09d3ac6aa450..8c384c25dca179 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -2736,7 +2736,6 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index, int isAif, int isFastResponse, struct hw_fib *aif_fib); int aac_reset_adapter(struct aac_dev *dev, int forced, u8 reset_type); -int aac_check_health(struct aac_dev * dev); int aac_command_thread(void *data); int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); int aac_fib_adapter_complete(struct fib * fibptr, unsigned short size); diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 47287559c768f3..ffef61c4aa0159 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1698,127 +1698,6 @@ int aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) return retval; } -int aac_check_health(struct aac_dev * aac) -{ - int BlinkLED; - unsigned long time_now, flagv = 0; - struct list_head * entry; - - /* Extending the scope of fib_lock slightly to protect aac->in_reset */ - if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0) - return 0; - - if (aac->in_reset || !(BlinkLED = aac_adapter_check_health(aac))) { - spin_unlock_irqrestore(&aac->fib_lock, flagv); - return 0; /* OK */ - } - - aac->in_reset = 1; - - /* Fake up an AIF: - * aac_aifcmd.command = AifCmdEventNotify = 1 - * aac_aifcmd.seqnum = 0xFFFFFFFF - * aac_aifcmd.data[0] = AifEnExpEvent = 23 - * aac_aifcmd.data[1] = AifExeFirmwarePanic = 3 - * aac.aifcmd.data[2] = AifHighPriority = 3 - * aac.aifcmd.data[3] = BlinkLED - */ - - time_now = jiffies/HZ; - entry = aac->fib_list.next; - - /* - * For each Context that is on the - * fibctxList, make a copy of the - * fib, and then set the event to wake up the - * thread that is waiting for it. - */ - while (entry != &aac->fib_list) { - /* - * Extract the fibctx - */ - struct aac_fib_context *fibctx = list_entry(entry, struct aac_fib_context, next); - struct hw_fib * hw_fib; - struct fib * fib; - /* - * Check if the queue is getting - * backlogged - */ - if (fibctx->count > 20) { - /* - * It's *not* jiffies folks, - * but jiffies / HZ, so do not - * panic ... - */ - u32 time_last = fibctx->jiffies; - /* - * Has it been > 2 minutes - * since the last read off - * the queue? - */ - if ((time_now - time_last) > aif_timeout) { - entry = entry->next; - aac_close_fib_context(aac, fibctx); - continue; - } - } - /* - * Warning: no sleep allowed while - * holding spinlock - */ - hw_fib = kzalloc(sizeof(struct hw_fib), GFP_ATOMIC); - fib = kzalloc(sizeof(struct fib), GFP_ATOMIC); - if (fib && hw_fib) { - struct aac_aifcmd * aif; - - fib->hw_fib_va = hw_fib; - fib->dev = aac; - aac_fib_init(fib); - fib->type = FSAFS_NTC_FIB_CONTEXT; - fib->size = sizeof (struct fib); - fib->data = hw_fib->data; - aif = (struct aac_aifcmd *)hw_fib->data; - aif->command = cpu_to_le32(AifCmdEventNotify); - aif->seqnum = cpu_to_le32(0xFFFFFFFF); - ((__le32 *)aif->data)[0] = cpu_to_le32(AifEnExpEvent); - ((__le32 *)aif->data)[1] = cpu_to_le32(AifExeFirmwarePanic); - ((__le32 *)aif->data)[2] = cpu_to_le32(AifHighPriority); - ((__le32 *)aif->data)[3] = cpu_to_le32(BlinkLED); - - /* - * Put the FIB onto the - * fibctx's fibs - */ - list_add_tail(&fib->fiblink, &fibctx->fib_list); - fibctx->count++; - /* - * Set the event to wake up the - * thread that will waiting. - */ - complete(&fibctx->completion); - } else { - printk(KERN_WARNING "aifd: didn't allocate NewFib.\n"); - kfree(fib); - kfree(hw_fib); - } - entry = entry->next; - } - - spin_unlock_irqrestore(&aac->fib_lock, flagv); - - if (BlinkLED < 0) { - printk(KERN_ERR "%s: Host adapter is dead (or got a PCI error) %d\n", - aac->name, BlinkLED); - goto out; - } - - printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED); - -out: - aac->in_reset = 0; - return BlinkLED; -} - static inline int is_safw_raid_volume(struct aac_dev *aac, int bus, int target) { return bus == CONTAINER_CHANNEL && target < aac->maximum_num_containers; diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index a0fb330b8df54a..4276f868cd9159 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -295,7 +295,7 @@ CMD_INC_RESID(struct scsi_cmnd *cmd, int inc) #else #define IRQ_MIN 9 #if defined(__PPC) -#define IRQ_MAX (nr_irqs-1) +#define IRQ_MAX (irq_get_nr_irqs()-1) #else #define IRQ_MAX 12 #endif diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c index 176704b24e6abe..f1ce02cd569e32 100644 --- a/drivers/scsi/aic7xxx/aic7770.c +++ b/drivers/scsi/aic7xxx/aic7770.c @@ -99,21 +99,6 @@ struct aic7770_identity aic7770_ident_table[] = ahc_aic7770_EISA_setup } }; -const int ahc_num_aic7770_devs = ARRAY_SIZE(aic7770_ident_table); - -struct aic7770_identity * -aic7770_find_device(uint32_t id) -{ - struct aic7770_identity *entry; - int i; - - for (i = 0; i < ahc_num_aic7770_devs; i++) { - entry = &aic7770_ident_table[i]; - if (entry->full_id == (id & entry->id_mask)) - return (entry); - } - return (NULL); -} int aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 9bc755a0a2d38b..20857c213c726f 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -1119,7 +1119,6 @@ struct aic7770_identity { ahc_device_setup_t *setup; }; extern struct aic7770_identity aic7770_ident_table[]; -extern const int ahc_num_aic7770_devs; #define AHC_EISA_SLOT_OFFSET 0xc00 #define AHC_EISA_IOSIZE 0x100 @@ -1135,7 +1134,6 @@ int ahc_pci_test_register_access(struct ahc_softc *); void __maybe_unused ahc_pci_resume(struct ahc_softc *ahc); /*************************** EISA/VL Front End ********************************/ -struct aic7770_identity *aic7770_find_device(uint32_t); int aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *, u_int port); diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index 98a1b966a0b078..85055677666c51 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -885,7 +885,7 @@ static void __exit atari_scsi_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver atari_scsi_driver __refdata = { - .remove_new = __exit_p(atari_scsi_remove), + .remove = __exit_p(atari_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/scsi/bfa/bfa.h b/drivers/scsi/bfa/bfa.h index 4cb9249e583ccc..a6b8c4ddea19df 100644 --- a/drivers/scsi/bfa/bfa.h +++ b/drivers/scsi/bfa/bfa.h @@ -138,14 +138,6 @@ bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg), } while (0) -/* - * PCI devices supported by the current BFA - */ -struct bfa_pciid_s { - u16 device_id; - u16 vendor_id; -}; - extern char bfa_version[]; struct bfa_iocfc_regs_s { @@ -408,9 +400,7 @@ int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, (((&(_bfa)->modules.dconf_mod)->min_cfg) \ ? BFA_LUNMASK_MINCFG : ((bfa_get_lun_mask(_bfa))->status)) -void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids); void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg); -void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg); void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_s *bfa); diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index 3438d0b8ba0624..a99a101b95efee 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -1933,24 +1933,6 @@ bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q) } } -/* - * Return the list of PCI vendor/device id lists supported by this - * BFA instance. - */ -void -bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids) -{ - static struct bfa_pciid_s __pciids[] = { - {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P}, - {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P}, - {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT}, - {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT_FC}, - }; - - *npciids = ARRAY_SIZE(__pciids); - *pciids = __pciids; -} - /* * Use this function query the default struct bfa_iocfc_cfg_s value (compiled * into BFA layer). The OS driver can then turn back and overwrite entries that @@ -1987,20 +1969,3 @@ bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg) cfg->drvcfg.delay_comp = BFA_FALSE; } - -void -bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg) -{ - bfa_cfg_get_default(cfg); - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN; - cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN; - cfg->fwcfg.num_fcxp_reqs = BFA_FCXP_MIN; - cfg->fwcfg.num_uf_bufs = BFA_UF_MIN; - cfg->fwcfg.num_rports = BFA_RPORT_MIN; - cfg->fwcfg.num_fwtio_reqs = 0; - - cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; - cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN; - cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN; - cfg->drvcfg.min_cfg = BFA_TRUE; -} diff --git a/drivers/scsi/bfa/bfa_defs_fcs.h b/drivers/scsi/bfa/bfa_defs_fcs.h index 5e36620425ac73..760606062c6605 100644 --- a/drivers/scsi/bfa/bfa_defs_fcs.h +++ b/drivers/scsi/bfa/bfa_defs_fcs.h @@ -124,28 +124,6 @@ enum bfa_lport_offline_reason { BFA_LPORT_OFFLINE_FAB_LOGOUT, }; -/* - * FCS lport info. - */ -struct bfa_lport_info_s { - u8 port_type; /* bfa_lport_type_t : physical or - * virtual */ - u8 port_state; /* one of bfa_lport_state values */ - u8 offline_reason; /* one of bfa_lport_offline_reason_t - * values */ - wwn_t port_wwn; - wwn_t node_wwn; - - /* - * following 4 feilds are valid for Physical Ports only - */ - u32 max_vports_supp; /* Max supported vports */ - u32 num_vports_inuse; /* Num of in use vports */ - u32 max_rports_supp; /* Max supported rports */ - u32 num_rports_inuse; /* Num of doscovered rports */ - -}; - /* * FCS port statistics */ diff --git a/drivers/scsi/bfa/bfa_fcbuild.c b/drivers/scsi/bfa/bfa_fcbuild.c index 52303e8c716dd4..c44fd096ee688d 100644 --- a/drivers/scsi/bfa/bfa_fcbuild.c +++ b/drivers/scsi/bfa/bfa_fcbuild.c @@ -219,44 +219,6 @@ fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, return sizeof(struct fc_logi_s); } -u16 -fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size, - u8 set_npiv, u8 set_auth, u16 local_bb_credits) -{ - u32 d_id = bfa_hton3b(FC_FABRIC_PORT); - __be32 *vvl_info; - - memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); - - flogi->els_cmd.els_code = FC_ELS_FLOGI; - fc_els_req_build(fchs, d_id, s_id, ox_id); - - flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size); - flogi->port_name = port_name; - flogi->node_name = node_name; - - /* - * Set the NPIV Capability Bit ( word 1, bit 31) of Common - * Service Parameters. - */ - flogi->csp.ciro = set_npiv; - - /* set AUTH capability */ - flogi->csp.security = set_auth; - - flogi->csp.bbcred = cpu_to_be16(local_bb_credits); - - /* Set brcd token in VVL */ - vvl_info = (u32 *)&flogi->vvl[0]; - - /* set the flag to indicate the presence of VVL */ - flogi->csp.npiv_supp = 1; /* @todo. field name is not correct */ - vvl_info[0] = cpu_to_be32(FLOGI_VVL_BRCD); - - return sizeof(struct fc_logi_s); -} - u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name, @@ -279,24 +241,6 @@ fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, return sizeof(struct fc_logi_s); } -u16 -fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size) -{ - u32 d_id = bfa_hton3b(FC_FABRIC_PORT); - - memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); - - flogi->els_cmd.els_code = FC_ELS_FDISC; - fc_els_req_build(fchs, d_id, s_id, ox_id); - - flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size); - flogi->port_name = port_name; - flogi->node_name = node_name; - - return sizeof(struct fc_logi_s); -} - u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, @@ -315,40 +259,6 @@ fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, node_name, pdu_size, bb_cr, FC_ELS_ACC); } -enum fc_parse_status -fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - struct fc_logi_s *plogi; - struct fc_ls_rjt_s *ls_rjt; - - switch (els_cmd->els_code) { - case FC_ELS_LS_RJT: - ls_rjt = (struct fc_ls_rjt_s *) (fchs + 1); - if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY) - return FC_PARSE_BUSY; - else - return FC_PARSE_FAILURE; - case FC_ELS_ACC: - plogi = (struct fc_logi_s *) (fchs + 1); - if (len < sizeof(struct fc_logi_s)) - return FC_PARSE_FAILURE; - - if (!wwn_is_equal(plogi->port_name, port_name)) - return FC_PARSE_FAILURE; - - if (!plogi->class3.class_valid) - return FC_PARSE_FAILURE; - - if (be16_to_cpu(plogi->class3.rxsz) < (FC_MIN_PDUSZ)) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; - default: - return FC_PARSE_FAILURE; - } -} - enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs) { @@ -421,21 +331,6 @@ fc_prli_rsp_parse(struct fc_prli_s *prli, int len) return FC_PARSE_OK; } -enum fc_parse_status -fc_prli_parse(struct fc_prli_s *prli) -{ - if (prli->parampage.type != FC_TYPE_FCP) - return FC_PARSE_FAILURE; - - if (!prli->parampage.imagepair) - return FC_PARSE_FAILURE; - - if (!prli->parampage.servparams.initiator) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name) @@ -506,84 +401,6 @@ fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name, return FC_PARSE_OK; } -enum fc_parse_status -fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap, wwn_t node_name, - wwn_t port_name) -{ - struct fc_adisc_s *adisc = (struct fc_adisc_s *) pld; - - if (adisc->els_cmd.els_code != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - if ((adisc->nport_id == (host_dap)) - && wwn_is_equal(adisc->orig_port_name, port_name) - && wwn_is_equal(adisc->orig_node_name, node_name)) - return FC_PARSE_OK; - - return FC_PARSE_FAILURE; -} - -enum fc_parse_status -fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name) -{ - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); - - if (pdisc->class3.class_valid != 1) - return FC_PARSE_FAILURE; - - if ((be16_to_cpu(pdisc->class3.rxsz) < - (FC_MIN_PDUSZ - sizeof(struct fchs_s))) - || (pdisc->class3.rxsz == 0)) - return FC_PARSE_FAILURE; - - if (!wwn_is_equal(pdisc->port_name, port_name)) - return FC_PARSE_FAILURE; - - if (!wwn_is_equal(pdisc->node_name, node_name)) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - -u16 -fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) -{ - memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s)); - fchs->cat_info = FC_CAT_ABTS; - fchs->d_id = (d_id); - fchs->s_id = (s_id); - fchs->ox_id = cpu_to_be16(ox_id); - - return sizeof(struct fchs_s); -} - -enum fc_parse_status -fc_abts_rsp_parse(struct fchs_s *fchs, int len) -{ - if ((fchs->cat_info == FC_CAT_BA_ACC) - || (fchs->cat_info == FC_CAT_BA_RJT)) - return FC_PARSE_OK; - - return FC_PARSE_FAILURE; -} - -u16 -fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id, u32 s_id, - u16 ox_id, u16 rrq_oxid) -{ - fc_els_req_build(fchs, d_id, s_id, ox_id); - - /* - * build rrq payload - */ - memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s)); - rrq->s_id = (s_id); - rrq->ox_id = cpu_to_be16(rrq_oxid); - rrq->rx_id = FC_RXID_ANY; - - return sizeof(struct fc_rrq_s); -} - u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, __be16 ox_id) @@ -658,30 +475,6 @@ fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code) return num_pages; } -u16 -fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, - u32 d_id, u32 s_id, __be16 ox_id, int num_pages) -{ - int page; - - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - memset(tprlo_acc, 0, (num_pages * 16) + 4); - tprlo_acc->command = FC_ELS_ACC; - - tprlo_acc->page_len = 0x10; - tprlo_acc->payload_len = cpu_to_be16((num_pages * 16) + 4); - - for (page = 0; page < num_pages; page++) { - tprlo_acc->tprlo_acc_params[page].opa_valid = 0; - tprlo_acc->tprlo_acc_params[page].rpa_valid = 0; - tprlo_acc->tprlo_acc_params[page].fc4type_csp = FC_TYPE_FCP; - tprlo_acc->tprlo_acc_params[page].orig_process_assc = 0; - tprlo_acc->tprlo_acc_params[page].resp_process_assc = 0; - } - return be16_to_cpu(tprlo_acc->payload_len); -} - u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id, u32 s_id, __be16 ox_id, int num_pages) @@ -706,20 +499,6 @@ fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id, return be16_to_cpu(prlo_acc->payload_len); } -u16 -fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id, - u32 s_id, u16 ox_id, u32 data_format) -{ - fc_els_req_build(fchs, d_id, s_id, ox_id); - - memset(rnid, 0, sizeof(struct fc_rnid_cmd_s)); - - rnid->els_cmd.els_code = FC_ELS_RNID; - rnid->node_id_data_format = data_format; - - return sizeof(struct fc_rnid_cmd_s); -} - u16 fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id, u32 s_id, __be16 ox_id, u32 data_format, @@ -748,18 +527,6 @@ fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id, } -u16 -fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id, - u32 s_id, u16 ox_id) -{ - fc_els_req_build(fchs, d_id, s_id, ox_id); - - memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s)); - - rpsc->els_cmd.els_code = FC_ELS_RPSC; - return sizeof(struct fc_rpsc_cmd_s); -} - u16 fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, u32 d_id, u32 s_id, u32 *pid_list, u16 npids) @@ -801,115 +568,6 @@ fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, return sizeof(struct fc_rpsc_acc_s); } -u16 -fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, - wwn_t port_name, wwn_t node_name, u16 pdu_size) -{ - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); - - memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s)); - - pdisc->els_cmd.els_code = FC_ELS_PDISC; - fc_els_req_build(fchs, d_id, s_id, ox_id); - - pdisc->csp.rxsz = pdisc->class3.rxsz = cpu_to_be16(pdu_size); - pdisc->port_name = port_name; - pdisc->node_name = node_name; - - return sizeof(struct fc_logi_s); -} - -u16 -fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) -{ - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); - - if (len < sizeof(struct fc_logi_s)) - return FC_PARSE_LEN_INVAL; - - if (pdisc->els_cmd.els_code != FC_ELS_ACC) - return FC_PARSE_ACC_INVAL; - - if (!wwn_is_equal(pdisc->port_name, port_name)) - return FC_PARSE_PWWN_NOT_EQUAL; - - if (!pdisc->class3.class_valid) - return FC_PARSE_NWWN_NOT_EQUAL; - - if (be16_to_cpu(pdisc->class3.rxsz) < (FC_MIN_PDUSZ)) - return FC_PARSE_RXSZ_INVAL; - - return FC_PARSE_OK; -} - -u16 -fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, - int num_pages) -{ - struct fc_prlo_s *prlo = (struct fc_prlo_s *) (fchs + 1); - int page; - - fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(prlo, 0, (num_pages * 16) + 4); - prlo->command = FC_ELS_PRLO; - prlo->page_len = 0x10; - prlo->payload_len = cpu_to_be16((num_pages * 16) + 4); - - for (page = 0; page < num_pages; page++) { - prlo->prlo_params[page].type = FC_TYPE_FCP; - prlo->prlo_params[page].opa_valid = 0; - prlo->prlo_params[page].rpa_valid = 0; - prlo->prlo_params[page].orig_process_assc = 0; - prlo->prlo_params[page].resp_process_assc = 0; - } - - return be16_to_cpu(prlo->payload_len); -} - -u16 -fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, - int num_pages, enum fc_tprlo_type tprlo_type, u32 tpr_id) -{ - struct fc_tprlo_s *tprlo = (struct fc_tprlo_s *) (fchs + 1); - int page; - - fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(tprlo, 0, (num_pages * 16) + 4); - tprlo->command = FC_ELS_TPRLO; - tprlo->page_len = 0x10; - tprlo->payload_len = cpu_to_be16((num_pages * 16) + 4); - - for (page = 0; page < num_pages; page++) { - tprlo->tprlo_params[page].type = FC_TYPE_FCP; - tprlo->tprlo_params[page].opa_valid = 0; - tprlo->tprlo_params[page].rpa_valid = 0; - tprlo->tprlo_params[page].orig_process_assc = 0; - tprlo->tprlo_params[page].resp_process_assc = 0; - if (tprlo_type == FC_GLOBAL_LOGO) { - tprlo->tprlo_params[page].global_process_logout = 1; - } else if (tprlo_type == FC_TPR_LOGO) { - tprlo->tprlo_params[page].tpo_nport_valid = 1; - tprlo->tprlo_params[page].tpo_nport_id = (tpr_id); - } - } - - return be16_to_cpu(tprlo->payload_len); -} - -u16 -fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id, - u32 reason_code, u32 reason_expl) -{ - struct fc_ba_rjt_s *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1); - - fc_bls_rsp_build(fchs, d_id, s_id, ox_id); - - fchs->cat_info = FC_CAT_BA_RJT; - ba_rjt->reason_code = reason_code; - ba_rjt->reason_expl = reason_expl; - return sizeof(struct fc_ba_rjt_s); -} - static void fc_gs_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code) { @@ -973,35 +631,6 @@ fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, return sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s); } -u16 -fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u32 port_id) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - fcgs_gnnid_req_t *gnnid = (fcgs_gnnid_req_t *) (cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_GNN_ID); - - memset(gnnid, 0, sizeof(fcgs_gnnid_req_t)); - gnnid->dap = port_id; - return sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s); -} - -u16 -fc_ct_rsp_parse(struct ct_hdr_s *cthdr) -{ - if (be16_to_cpu(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) { - if (cthdr->reason_code == CT_RSN_LOGICAL_BUSY) - return FC_PARSE_BUSY; - else - return FC_PARSE_FAILURE; - } - - return FC_PARSE_OK; -} - u16 fc_gs_rjt_build(struct fchs_s *fchs, struct ct_hdr_s *cthdr, u32 d_id, u32 s_id, u16 ox_id, u8 reason_code, @@ -1034,26 +663,6 @@ fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, return sizeof(struct fc_scr_s); } -u16 -fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, - u32 s_id, u16 ox_id) -{ - u32 d_id = bfa_hton3b(FC_FABRIC_CONTROLLER); - u16 payldlen; - - fc_els_req_build(fchs, d_id, s_id, ox_id); - rscn->command = FC_ELS_RSCN; - rscn->pagelen = sizeof(rscn->event[0]); - - payldlen = sizeof(u32) + rscn->pagelen; - rscn->payldlen = cpu_to_be16(payldlen); - - rscn->event[0].format = FC_RSCN_FORMAT_PORTID; - rscn->event[0].portid = s_id; - - return struct_size(rscn, event, 1); -} - u16 fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, enum bfa_lport_role roles) @@ -1078,26 +687,6 @@ fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s); } -u16 -fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u8 *fc4_bitmap, u32 bitmap_size) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID); - - memset(rftid, 0, sizeof(struct fcgs_rftid_req_s)); - - rftid->dap = s_id; - memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap, - (bitmap_size < 32 ? bitmap_size : 32)); - - return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s); -} - u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, u8 fc4_type, u8 fc4_ftrs) @@ -1181,24 +770,6 @@ fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id, u8 fc4_type) return sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s); } -u16 -fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, - wwn_t port_name) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rpnid_req_s *rpnid = (struct fcgs_rpnid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_RPN_ID); - - memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s)); - rpnid->port_id = port_id; - rpnid->port_name = port_name; - - return sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s); -} - u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, wwn_t node_name) @@ -1217,59 +788,6 @@ fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, return sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s); } -u16 -fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, - u32 cos) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rcsid_req_s *rcsid = - (struct fcgs_rcsid_req_s *) (cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_RCS_ID); - - memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s)); - rcsid->port_id = port_id; - rcsid->cos = cos; - - return sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, - u8 port_type) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rptid_req_s *rptid = (struct fcgs_rptid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_RPT_ID); - - memset(rptid, 0, sizeof(struct fcgs_rptid_req_s)); - rptid->port_id = port_id; - rptid->port_type = port_type; - - return sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_ganxt_req_s *ganxt = (struct fcgs_ganxt_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_GA_NXT); - - memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s)); - ganxt->port_id = port_id; - - return sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s); -} - /* * Builds fc hdr and ct hdr for FDMI requests. */ diff --git a/drivers/scsi/bfa/bfa_fcbuild.h b/drivers/scsi/bfa/bfa_fcbuild.h index 49e0ee4a733479..51da37b2ae6b52 100644 --- a/drivers/scsi/bfa/bfa_fcbuild.h +++ b/drivers/scsi/bfa/bfa_fcbuild.h @@ -127,15 +127,6 @@ struct fc_templates_s { void fcbuild_init(void); -u16 fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, - u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u8 set_npiv, u8 set_auth, - u16 local_bb_credits); - -u16 fc_fdisc_build(struct fchs_s *buf, struct fc_logi_s *flogi, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size); - u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name, @@ -148,14 +139,6 @@ u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs); -u16 fc_abts_build(struct fchs_s *buf, u32 d_id, u32 s_id, - u16 ox_id); - -enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len); - -u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id, - u32 s_id, u16 ox_id, u16 rrq_oxid); - u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id, u16 ox_id, u8 *name); u16 fc_rsnn_nn_build(struct fchs_s *fchs, void *pld, u32 s_id, @@ -164,10 +147,6 @@ u16 fc_rsnn_nn_build(struct fchs_s *fchs, void *pld, u32 s_id, u16 fc_rftid_build(struct fchs_s *fchs, void *pld, u32 s_id, u16 ox_id, enum bfa_lport_role role); -u16 fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, u8 *fc4_bitmap, - u32 bitmap_size); - u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, u8 fc4_type, u8 fc4_ftrs); @@ -193,9 +172,6 @@ u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name); -enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld, - u32 host_dap, wwn_t node_name, wwn_t port_name); - enum fc_parse_status fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name, wwn_t node_name); @@ -216,10 +192,6 @@ u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, __be16 ox_id, enum bfa_lport_role role); -u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, - u32 d_id, u32 s_id, u16 ox_id, - u32 data_format); - u16 fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id, u32 s_id, __be16 ox_id, u32 data_format, @@ -228,29 +200,15 @@ u16 fc_rnid_acc_build(struct fchs_s *fchs, u16 fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rps2c, u32 d_id, u32 s_id, u32 *pid_list, u16 npids); -u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, - u32 d_id, u32 s_id, u16 ox_id); u16 fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, u32 d_id, u32 s_id, __be16 ox_id, struct fc_rpsc_speed_info_s *oper_speed); u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id, u8 fc4_type); -u16 fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, wwn_t port_name); - u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, wwn_t node_name); -u16 fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, u32 cos); - -u16 fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, u8 port_type); - -u16 fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id); - u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, u32 s_id, u16 ox_id, wwn_t port_name); @@ -267,46 +225,16 @@ void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask); void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id); -enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len, - wwn_t port_name); - -enum fc_parse_status fc_prli_parse(struct fc_prli_s *prli); - -enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, - wwn_t port_name); - u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id, u32 s_id, __be16 ox_id, u16 rx_id); int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code); -u16 fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, - u32 d_id, u32 s_id, __be16 ox_id, int num_pages); - u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id, u32 s_id, __be16 ox_id, int num_pages); -u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size); - -u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name); - -u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, int num_pages); - u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, int num_pages, enum fc_tprlo_type tprlo_type, u32 tpr_id); -u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - __be16 ox_id, u32 reason_code, u32 reason_expl); - -u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u32 port_id); - -u16 fc_ct_rsp_parse(struct ct_hdr_s *cthdr); - -u16 fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id, - u16 ox_id); #endif diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 28ae4dc14dc9ce..2518e36d70d35e 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -3412,15 +3412,6 @@ bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim) } } -/* - * Notification on completions from related ioim. - */ -void -bfa_tskim_iodone(struct bfa_tskim_s *tskim) -{ - bfa_wc_down(&tskim->wc); -} - /* * Handle IOC h/w failure notification from itnim. */ diff --git a/drivers/scsi/bfa/bfa_fcpim.h b/drivers/scsi/bfa/bfa_fcpim.h index 4499f84c2d8121..64e4485b226e92 100644 --- a/drivers/scsi/bfa/bfa_fcpim.h +++ b/drivers/scsi/bfa/bfa_fcpim.h @@ -339,7 +339,6 @@ void bfa_ioim_tov(struct bfa_ioim_s *ioim); void bfa_tskim_attach(struct bfa_fcpim_s *fcpim); void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_tskim_iodone(struct bfa_tskim_s *tskim); void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim); void bfa_tskim_cleanup(struct bfa_tskim_s *tskim); void bfa_tskim_res_recfg(struct bfa_s *bfa, u16 num_tskim_fw); diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index 9788354b90da75..19903539a08dcf 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -373,15 +373,11 @@ bfa_boolean_t bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port); struct bfa_fcs_lport_s *bfa_fcs_get_base_port(struct bfa_fcs_s *fcs); void bfa_fcs_lport_get_rport_quals(struct bfa_fcs_lport_s *port, struct bfa_rport_qualifier_s rport[], int *nrports); -wwn_t bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn, - int index, int nrports, bfa_boolean_t bwwn); struct bfa_fcs_lport_s *bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn); void bfa_fcs_lport_set_symname(struct bfa_fcs_lport_s *port, char *symname); -void bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port, - struct bfa_lport_info_s *port_info); void bfa_fcs_lport_get_attr(struct bfa_fcs_lport_s *port, struct bfa_lport_attr_s *port_attr); void bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port, @@ -416,8 +412,6 @@ struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_old_pid( struct bfa_fcs_lport_s *port, u32 pid); struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_pwwn( struct bfa_fcs_lport_s *port, wwn_t pwwn); -struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_nwwn( - struct bfa_fcs_lport_s *port, wwn_t nwwn); struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_qualifier( struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 pid); void bfa_fcs_lport_add_rport(struct bfa_fcs_lport_s *port, @@ -486,7 +480,6 @@ bfa_status_t bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, u16 vf_id, struct bfa_lport_cfg_s *port_cfg, struct bfad_vport_s *vport_drv); -bfa_boolean_t bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport); bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport); bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport); bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport); @@ -494,7 +487,6 @@ void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, struct bfa_vport_attr_s *vport_attr); struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn); -void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); @@ -623,8 +615,6 @@ void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, struct bfa_rport_attr_s *attr); struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn); -struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn( - struct bfa_fcs_lport_s *port, wwn_t rnwwn); void bfa_fcs_rport_set_del_timeout(u8 rport_tmo); void bfa_fcs_rport_set_max_logins(u32 max_logins); void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, @@ -633,8 +623,6 @@ void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport); struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_lport_s *port, u32 pid); -void bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, - struct fc_logi_s *plogi_rsp); void bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, struct fc_logi_s *plogi); diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 966bf6cc6dd90b..9a85f417018f99 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -937,25 +937,6 @@ bfa_fcs_lport_get_rport_by_pwwn(struct bfa_fcs_lport_s *port, wwn_t pwwn) return NULL; } -/* - * NWWN based Lookup for a R-Port in the Port R-Port Queue - */ -struct bfa_fcs_rport_s * -bfa_fcs_lport_get_rport_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t nwwn) -{ - struct bfa_fcs_rport_s *rport; - struct list_head *qe; - - list_for_each(qe, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - if (wwn_is_equal(rport->nwwn, nwwn)) - return rport; - } - - bfa_trc(port->fcs, nwwn); - return NULL; -} - /* * PWWN & PID based Lookup for a R-Port in the Port R-Port Queue */ @@ -5645,54 +5626,6 @@ bfa_fcs_get_base_port(struct bfa_fcs_s *fcs) return &fcs->fabric.bport; } -wwn_t -bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn, int index, - int nrports, bfa_boolean_t bwwn) -{ - struct list_head *qh, *qe; - struct bfa_fcs_rport_s *rport = NULL; - int i; - struct bfa_fcs_s *fcs; - - if (port == NULL || nrports == 0) - return (wwn_t) 0; - - fcs = port->fcs; - bfa_trc(fcs, (u32) nrports); - - i = 0; - qh = &port->rport_q; - qe = bfa_q_first(qh); - - while ((qe != qh) && (i < nrports)) { - rport = (struct bfa_fcs_rport_s *) qe; - if (bfa_ntoh3b(rport->pid) > 0xFFF000) { - qe = bfa_q_next(qe); - bfa_trc(fcs, (u32) rport->pwwn); - bfa_trc(fcs, rport->pid); - bfa_trc(fcs, i); - continue; - } - - if (bwwn) { - if (!memcmp(&wwn, &rport->pwwn, 8)) - break; - } else { - if (i == index) - break; - } - - i++; - qe = bfa_q_next(qe); - } - - bfa_trc(fcs, i); - if (rport) - return rport->pwwn; - else - return (wwn_t) 0; -} - void bfa_fcs_lport_get_rport_quals(struct bfa_fcs_lport_s *port, struct bfa_rport_qualifier_s rports[], int *nrports) @@ -5823,54 +5756,6 @@ bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn) return NULL; } -/* - * API corresponding to NPIV_VPORT_GETINFO. - */ -void -bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port, - struct bfa_lport_info_s *port_info) -{ - - bfa_trc(port->fcs, port->fabric->fabric_name); - - if (port->vport == NULL) { - /* - * This is a Physical port - */ - port_info->port_type = BFA_LPORT_TYPE_PHYSICAL; - - /* - * @todo : need to fix the state & reason - */ - port_info->port_state = 0; - port_info->offline_reason = 0; - - port_info->port_wwn = bfa_fcs_lport_get_pwwn(port); - port_info->node_wwn = bfa_fcs_lport_get_nwwn(port); - - port_info->max_vports_supp = - bfa_lps_get_max_vport(port->fcs->bfa); - port_info->num_vports_inuse = - port->fabric->num_vports; - port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP; - port_info->num_rports_inuse = port->num_rports; - } else { - /* - * This is a virtual port - */ - port_info->port_type = BFA_LPORT_TYPE_VIRTUAL; - - /* - * @todo : need to fix the state & reason - */ - port_info->port_state = 0; - port_info->offline_reason = 0; - - port_info->port_wwn = bfa_fcs_lport_get_pwwn(port); - port_info->node_wwn = bfa_fcs_lport_get_nwwn(port); - } -} - void bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port, struct bfa_lport_stats_s *port_stats) @@ -6567,15 +6452,6 @@ bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport) bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE); } -/* - * Cleanup notification from fabric SM on link timer expiry. - */ -void -bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport) -{ - vport->vport_stats.fab_cleanup++; -} - /* * Stop notification from fabric SM. To be invoked from within FCS. */ @@ -6698,24 +6574,6 @@ bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, return rc; } -/* - * Use this function to findout if this is a pbc vport or not. - * - * @param[in] vport - pointer to bfa_fcs_vport_t. - * - * @returns None - */ -bfa_boolean_t -bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport) -{ - - if (vport && (vport->lport.port_cfg.preboot_vp == BFA_TRUE)) - return BFA_TRUE; - else - return BFA_FALSE; - -} - /* * Use this function initialize the vport. * diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c index ce52a9c88ae63b..d4bde9bbe75ba1 100644 --- a/drivers/scsi/bfa/bfa_fcs_rport.c +++ b/drivers/scsi/bfa/bfa_fcs_rport.c @@ -2646,27 +2646,6 @@ bfa_fcs_rport_create_by_wwn(struct bfa_fcs_lport_s *port, wwn_t rpwwn) bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_DISC); return rport; } -/* - * Called by bport in private loop topology to indicate that a - * rport has been discovered and plogi has been completed. - * - * @param[in] port - base port or vport - * @param[in] rpid - remote port ID - */ -void -bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *fchs, - struct fc_logi_s *plogi) -{ - struct bfa_fcs_rport_s *rport; - - rport = bfa_fcs_rport_alloc(port, WWN_NULL, fchs->s_id); - if (!rport) - return; - - bfa_fcs_rport_update(rport, plogi); - - bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_COMP); -} /* * Called by bport/vport to handle PLOGI received from a new remote port. @@ -3089,21 +3068,6 @@ bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn) return rport; } -struct bfa_fcs_rport_s * -bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t rnwwn) -{ - struct bfa_fcs_rport_s *rport; - - rport = bfa_fcs_lport_get_rport_by_nwwn(port, rnwwn); - if (rport == NULL) { - /* - * TBD Error handling - */ - } - - return rport; -} - /* * Remote port features (RPF) implementation. */ diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index ea2f107f564cd0..aa68d61a2d0d39 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -2254,33 +2254,12 @@ bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env) return status; } -/* - * Enable/disable IOC failure auto recovery. - */ -void -bfa_ioc_auto_recover(bfa_boolean_t auto_recover) -{ - bfa_auto_recover = auto_recover; -} - - - bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc) { return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op); } -bfa_boolean_t -bfa_ioc_is_initialized(struct bfa_ioc_s *ioc) -{ - u32 r32 = bfa_ioc_get_cur_ioc_fwstate(ioc); - - return ((r32 != BFI_IOC_UNINIT) && - (r32 != BFI_IOC_INITING) && - (r32 != BFI_IOC_MEMTEST)); -} - bfa_boolean_t bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) { diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 3ec10503caff92..d70332e9ad6d72 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -919,7 +919,6 @@ void bfa_ioc_ct2_poweron(struct bfa_ioc_s *ioc); void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod); -void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); void bfa_ioc_detach(struct bfa_ioc_s *ioc); void bfa_ioc_suspend(struct bfa_ioc_s *ioc); void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, @@ -934,7 +933,6 @@ bfa_status_t bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg); void bfa_ioc_error_isr(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_is_initialized(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_is_acq_addr(struct bfa_ioc_s *ioc); bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc); diff --git a/drivers/scsi/bfa/bfa_modules.h b/drivers/scsi/bfa/bfa_modules.h index 578e7678b056ee..ed29ebda30da27 100644 --- a/drivers/scsi/bfa/bfa_modules.h +++ b/drivers/scsi/bfa/bfa_modules.h @@ -113,7 +113,6 @@ void bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, struct bfa_s *); void bfa_sgpg_attach(struct bfa_s *, void *bfad, struct bfa_iocfc_cfg_s *, struct bfa_pcidev_s *); -void bfa_uf_iocdisable(struct bfa_s *); void bfa_uf_meminfo(struct bfa_iocfc_cfg_s *, struct bfa_meminfo_s *, struct bfa_s *); void bfa_uf_attach(struct bfa_s *, void *, struct bfa_iocfc_cfg_s *, diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c index 9f33aa303b1896..df33afaaa67350 100644 --- a/drivers/scsi/bfa/bfa_svc.c +++ b/drivers/scsi/bfa/bfa_svc.c @@ -913,14 +913,6 @@ bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) return reqbuf; } -u32 -bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - - return mod->req_pld_sz; -} - /* * Get the internal response buffer pointer * @@ -1023,21 +1015,6 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, bfa_fcxp_queue(fcxp, send_req); } -/* - * Abort a BFA FCXP - * - * @param[in] fcxp BFA fcxp pointer - * - * @return void - */ -bfa_status_t -bfa_fcxp_abort(struct bfa_fcxp_s *fcxp) -{ - bfa_trc(fcxp->fcxp_mod->bfa, fcxp->fcxp_tag); - WARN_ON(1); - return BFA_STATUS_OK; -} - void bfa_fcxp_req_rsp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg, @@ -3857,15 +3834,6 @@ bfa_fcport_clr_hardalpa(struct bfa_s *bfa) return BFA_STATUS_OK; } -bfa_boolean_t -bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - *alpa = fcport->cfg.hardalpa; - return fcport->cfg.cfg_hardalpa; -} - u8 bfa_fcport_get_myalpa(struct bfa_s *bfa) { @@ -3923,17 +3891,6 @@ bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit) /* * Get port attributes. */ - -wwn_t -bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - if (node) - return fcport->nwwn; - else - return fcport->pwwn; -} - void bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr) { @@ -4105,18 +4062,6 @@ bfa_fcport_is_ratelim(struct bfa_s *bfa) } -/* - * Enable/Disable FAA feature in port config - */ -void -bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, state); - fcport->cfg.faa_state = state; -} - /* * Get default minimum ratelim speed */ @@ -5528,23 +5473,6 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf); } -void -bfa_uf_iocdisable(struct bfa_s *bfa) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - struct bfa_uf_s *uf; - struct list_head *qe, *qen; - - /* Enqueue unused uf resources to free_q */ - list_splice_tail_init(&ufm->uf_unused_q, &ufm->uf_free_q); - - list_for_each_safe(qe, qen, &ufm->uf_posted_q) { - uf = (struct bfa_uf_s *) qe; - list_del(&uf->qe); - bfa_uf_put(ufm, uf); - } -} - void bfa_uf_start(struct bfa_s *bfa) { diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h index 26eeee82bedc68..99a960a8a2dbbb 100644 --- a/drivers/scsi/bfa/bfa_svc.h +++ b/drivers/scsi/bfa/bfa_svc.h @@ -587,14 +587,12 @@ bfa_status_t bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_port_topology bfa_fcport_get_topology(struct bfa_s *bfa); enum bfa_port_topology bfa_fcport_get_cfg_topology(struct bfa_s *bfa); bfa_status_t bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa); -bfa_boolean_t bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa); u8 bfa_fcport_get_myalpa(struct bfa_s *bfa); bfa_status_t bfa_fcport_clr_hardalpa(struct bfa_s *bfa); bfa_status_t bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize); u16 bfa_fcport_get_maxfrsize(struct bfa_s *bfa); u8 bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa); void bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr); -wwn_t bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node); void bfa_fcport_event_register(struct bfa_s *bfa, void (*event_cbfn) (void *cbarg, enum bfa_port_linkstate event), void *event_cbarg); @@ -619,7 +617,6 @@ bfa_boolean_t bfa_fcport_is_trunk_enabled(struct bfa_s *bfa); void bfa_fcport_dportenable(struct bfa_s *bfa); void bfa_fcport_dportdisable(struct bfa_s *bfa); bfa_status_t bfa_fcport_is_pbcdisabled(struct bfa_s *bfa); -void bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state); bfa_status_t bfa_fcport_cfg_bbcr(struct bfa_s *bfa, bfa_boolean_t on_off, u8 bb_scn); bfa_status_t bfa_fcport_get_bbcr_attr(struct bfa_s *bfa, @@ -687,8 +684,6 @@ void bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, bfa_cb_fcxp_send_t cbfn, void *cbarg, u32 rsp_maxlen, u8 rsp_timeout); -bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp); -u32 bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp); u32 bfa_fcxp_get_maxrsp(struct bfa_s *bfa); void bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw); diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 62cb7a864fd53d..6aa1d3a7e24bc8 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -842,26 +842,6 @@ bfad_drv_init(struct bfad_s *bfad) return BFA_STATUS_OK; } -void -bfad_drv_uninit(struct bfad_s *bfad) -{ - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfa_iocfc_stop(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); - - del_timer_sync(&bfad->hal_tmo); - bfa_isr_disable(&bfad->bfa); - bfa_detach(&bfad->bfa); - bfad_remove_intr(bfad); - bfad_hal_mem_release(bfad); - - bfad->bfad_flags &= ~BFAD_DRV_INIT_DONE; -} - void bfad_drv_start(struct bfad_s *bfad) { @@ -1693,9 +1673,8 @@ bfad_init(void) error = bfad_im_module_init(); if (error) { - error = -ENOMEM; printk(KERN_WARNING "bfad_im_module_init failure\n"); - goto ext; + return -ENOMEM; } if (strcmp(FCPI_NAME, " fcpim") == 0) diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index da42e3261237ec..ce2ec51089472f 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -312,7 +312,6 @@ void bfad_bfa_tmo(struct timer_list *t); void bfad_init_timer(struct bfad_s *bfad); int bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad); void bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad); -void bfad_drv_uninit(struct bfad_s *bfad); int bfad_worker(void *ptr); void bfad_debugfs_init(struct bfad_port_s *port); void bfad_debugfs_exit(struct bfad_port_s *port); diff --git a/drivers/scsi/bfa/bfi.h b/drivers/scsi/bfa/bfi.h index 41e6b4dac056a5..e1e0e967bcc3f8 100644 --- a/drivers/scsi/bfa/bfi.h +++ b/drivers/scsi/bfa/bfi.h @@ -1148,7 +1148,7 @@ struct bfi_diag_dport_scn_testcomp_s { u16 numbuffer; /* from switch */ u8 subtest_status[DPORT_TEST_MAX]; /* 4 bytes */ u32 latency; /* from switch */ - u32 distance; /* from swtich unit in meters */ + u32 distance; /* from switch unit in meters */ /* Buffers required to saturate the link */ u16 frm_sz; /* from switch for buf_reqd */ u8 rsvd[2]; diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c index f893e9779e9de7..baf5f4e479378d 100644 --- a/drivers/scsi/bvme6000_scsi.c +++ b/drivers/scsi/bvme6000_scsi.c @@ -106,7 +106,7 @@ static struct platform_driver bvme6000_scsi_driver = { .name = "bvme6000-scsi", }, .probe = bvme6000_probe, - .remove_new = bvme6000_device_remove, + .remove = bvme6000_device_remove, }; static int __init bvme6000_scsi_init(void) diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index 8a133254c4f657..1e2d7c63a8e36a 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -1045,10 +1045,6 @@ void esas2r_build_mgt_req(struct esas2r_adapter *a, u32 length, void *data); void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq); -void esas2r_build_cli_req(struct esas2r_adapter *a, - struct esas2r_request *rq, - u32 length, - u32 cmd_rsp_len); void esas2r_build_ioctl_req(struct esas2r_adapter *a, struct esas2r_request *rq, u32 length, diff --git a/drivers/scsi/esas2r/esas2r_vda.c b/drivers/scsi/esas2r/esas2r_vda.c index 30028e56df6379..5aa728704dfcb0 100644 --- a/drivers/scsi/esas2r/esas2r_vda.c +++ b/drivers/scsi/esas2r/esas2r_vda.c @@ -444,23 +444,6 @@ void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq) } } -/* Build a VDA CLI request. */ -void esas2r_build_cli_req(struct esas2r_adapter *a, - struct esas2r_request *rq, - u32 length, - u32 cmd_rsp_len) -{ - struct atto_vda_cli_req *vrq = &rq->vrq->cli; - - clear_vda_request(rq); - - rq->vrq->scsi.function = VDA_FUNC_CLI; - - vrq->length = cpu_to_le32(length); - vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len); - vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge); -} - /* Build a VDA IOCTL request. */ void esas2r_build_ioctl_req(struct esas2r_adapter *a, struct esas2r_request *rq, diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index d223f482488fc6..a44768bceb9ab2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -307,6 +307,7 @@ enum { struct hisi_sas_hw { int (*hw_init)(struct hisi_hba *hisi_hba); + int (*fw_info_check)(struct hisi_hba *hisi_hba); int (*interrupt_preinit)(struct hisi_hba *hisi_hba); void (*setup_itct)(struct hisi_hba *hisi_hba, struct hisi_sas_device *device); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 6219807ce3b9e1..53cb15f6714bd4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1321,6 +1321,7 @@ static int hisi_sas_softreset_ata_disk(struct domain_device *device) } if (rc == TMF_RESP_FUNC_COMPLETE) { + usleep_range(900, 1000); ata_for_each_link(link, ap, EDGE) { int pmp = sata_srst_pmp(link); @@ -1384,6 +1385,7 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state) { + u32 new_state = hisi_hba->hw->get_phys_state(hisi_hba); struct asd_sas_port *_sas_port = NULL; int phy_no; @@ -1397,7 +1399,7 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state) continue; /* Report PHY state change to libsas */ - if (state & BIT(phy_no)) { + if (new_state & BIT(phy_no)) { if (do_port_check && sas_port && sas_port->port_dev) { struct domain_device *dev = sas_port->port_dev; @@ -1410,6 +1412,16 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state) } } else { hisi_sas_phy_down(hisi_hba, phy_no, 0, GFP_KERNEL); + + /* + * The new_state is not ready but old_state is ready, + * the two possible causes: + * 1. The connected device is removed + * 2. Device exists but phyup timed out + */ + if (state & BIT(phy_no)) + hisi_sas_notify_phy_event(phy, + HISI_PHYE_LINK_RESET); } } } @@ -1545,9 +1557,15 @@ void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba) /* Init and wait for PHYs to come up and all libsas event finished. */ for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; - if (!(hisi_hba->phy_state & BIT(phy_no))) + if (!sas_phy->phy->enabled) + continue; + + if (!(hisi_hba->phy_state & BIT(phy_no))) { + hisi_sas_phy_enable(hisi_hba, phy_no, 1); continue; + } async_schedule_domain(hisi_sas_async_init_wait_phyup, phy, &async); @@ -2450,6 +2468,11 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, if (hisi_sas_get_fw_info(hisi_hba) < 0) goto err_out; + if (hisi_hba->hw->fw_info_check) { + if (hisi_hba->hw->fw_info_check(hisi_hba)) + goto err_out; + } + error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (error) { dev_err(dev, "No usable DMA addressing method\n"); @@ -2630,10 +2653,10 @@ static __init int hisi_sas_init(void) static __exit void hisi_sas_exit(void) { - sas_release_transport(hisi_sas_stt); - if (hisi_sas_debugfs_enable) debugfs_remove(hisi_sas_debugfs_dir); + + sas_release_transport(hisi_sas_stt); } module_init(hisi_sas_init); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 71b5008c3552cb..c3e571be22220a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1734,6 +1734,23 @@ static struct attribute *host_v1_hw_attrs[] = { ATTRIBUTE_GROUPS(host_v1_hw); +static int check_fw_info_v1_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + + if (hisi_hba->n_phy < 0 || hisi_hba->n_phy > 9) { + dev_err(dev, "invalid phy number from FW\n"); + return -EINVAL; + } + + if (hisi_hba->queue_count < 0 || hisi_hba->queue_count > 32) { + dev_err(dev, "invalid queue count from FW\n"); + return -EINVAL; + } + + return 0; +} + static const struct scsi_host_template sht_v1_hw = { LIBSAS_SHT_BASE_NO_SLAVE_INIT .device_configure = hisi_sas_device_configure, @@ -1747,6 +1764,7 @@ static const struct scsi_host_template sht_v1_hw = { static const struct hisi_sas_hw hisi_sas_v1_hw = { .hw_init = hisi_sas_v1_init, + .fw_info_check = check_fw_info_v1_hw, .setup_itct = setup_itct_v1_hw, .sl_notify_ssp = sl_notify_ssp_v1_hw, .clear_itct = clear_itct_v1_hw, @@ -1784,7 +1802,7 @@ MODULE_DEVICE_TABLE(acpi, sas_v1_acpi_match); static struct platform_driver hisi_sas_v1_driver = { .probe = hisi_sas_v1_probe, - .remove_new = hisi_sas_remove, + .remove = hisi_sas_remove, .driver = { .name = DRV_NAME, .of_match_table = sas_v1_of_match, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 342d75f12051d2..1a62b5d15eca72 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -3566,6 +3566,23 @@ static void map_queues_v2_hw(struct Scsi_Host *shost) } } +static int check_fw_info_v2_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + + if (hisi_hba->n_phy < 0 || hisi_hba->n_phy > 9) { + dev_err(dev, "invalid phy number from FW\n"); + return -EINVAL; + } + + if (hisi_hba->queue_count < 0 || hisi_hba->queue_count > 16) { + dev_err(dev, "invalid queue count from FW\n"); + return -EINVAL; + } + + return 0; +} + static const struct scsi_host_template sht_v2_hw = { LIBSAS_SHT_BASE_NO_SLAVE_INIT .device_configure = hisi_sas_device_configure, @@ -3582,6 +3599,7 @@ static const struct scsi_host_template sht_v2_hw = { static const struct hisi_sas_hw hisi_sas_v2_hw = { .hw_init = hisi_sas_v2_init, + .fw_info_check = check_fw_info_v2_hw, .interrupt_preinit = hisi_sas_v2_interrupt_preinit, .setup_itct = setup_itct_v2_hw, .slot_index_alloc = slot_index_alloc_quirk_v2_hw, @@ -3631,7 +3649,7 @@ MODULE_DEVICE_TABLE(acpi, sas_v2_acpi_match); static struct platform_driver hisi_sas_v2_driver = { .probe = hisi_sas_v2_probe, - .remove_new = hisi_sas_remove, + .remove = hisi_sas_remove, .driver = { .name = DRV_NAME, .of_match_table = sas_v2_of_match, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 4cd3a3eab6f1c4..5db931663ae4e3 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -43,6 +43,7 @@ #define CQ_INT_CONVERGE_EN 0xb0 #define CFG_AGING_TIME 0xbc #define HGC_DFX_CFG2 0xc0 +#define CFG_ICT_TIMER_STEP_TRSH 0xc8 #define CFG_ABT_SET_QUERY_IPTT 0xd4 #define CFG_SET_ABORTED_IPTT_OFF 0 #define CFG_SET_ABORTED_IPTT_MSK (0xfff << CFG_SET_ABORTED_IPTT_OFF) @@ -638,9 +639,12 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_write32(hisi_hba, TRANS_LOCK_ICT_TIME, 0x4A817C80); hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108); hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1); - hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1); + hisi_sas_write32(hisi_hba, CFG_ICT_TIMER_STEP_TRSH, 0xf4240); + hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x3); + /* configure the interrupt coalescing timeout period 10us */ + hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0xa); + /* configure the count of CQ entries 10 */ + hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0xa); hisi_sas_write32(hisi_hba, CQ_INT_CONVERGE_EN, hisi_sas_intr_conv); hisi_sas_write32(hisi_hba, OQ_INT_SRC, 0xffff); @@ -682,7 +686,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) hisi_sas_phy_write32(hisi_hba, i, PHY_CTRL_RDY_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_DWS_RESET_MSK, 0x0); hisi_sas_phy_write32(hisi_hba, i, PHYCTRL_OOB_RESTART_MSK, 0x1); - hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7f7a120); + hisi_sas_phy_write32(hisi_hba, i, STP_LINK_TIMER, 0x7ffffff); hisi_sas_phy_write32(hisi_hba, i, CON_CFG_DRIVER, 0x2a0a01); hisi_sas_phy_write32(hisi_hba, i, SAS_EC_INT_COAL_TIME, 0x30f4240); @@ -2493,6 +2497,7 @@ static int complete_v3_hw(struct hisi_sas_cq *cq) /* update rd_point */ cq->rd_point = rd_point; hisi_sas_write32(hisi_hba, COMPL_Q_0_RD_PTR + (0x14 * queue), rd_point); + cond_resched(); return completed; } @@ -2796,14 +2801,15 @@ static void config_intr_coal_v3_hw(struct hisi_hba *hisi_hba) { /* config those registers between enable and disable PHYs */ hisi_sas_stop_phys(hisi_hba); + hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x3); if (hisi_hba->intr_coal_ticks == 0 || hisi_hba->intr_coal_count == 0) { - hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0x1); - hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0x1); + /* configure the interrupt coalescing timeout period 10us */ + hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, 0xa); + /* configure the count of CQ entries 10 */ + hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, 0xa); } else { - hisi_sas_write32(hisi_hba, INT_COAL_EN, 0x3); hisi_sas_write32(hisi_hba, OQ_INT_COAL_TIME, hisi_hba->intr_coal_ticks); hisi_sas_write32(hisi_hba, OQ_INT_COAL_CNT, @@ -3371,6 +3377,23 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { .debugfs_snapshot_regs = debugfs_snapshot_regs_v3_hw, }; +static int check_fw_info_v3_hw(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + + if (hisi_hba->n_phy < 0 || hisi_hba->n_phy > 8) { + dev_err(dev, "invalid phy number from FW\n"); + return -EINVAL; + } + + if (hisi_hba->queue_count < 0 || hisi_hba->queue_count > 16) { + dev_err(dev, "invalid queue count from FW\n"); + return -EINVAL; + } + + return 0; +} + static struct Scsi_Host * hisi_sas_shost_alloc_pci(struct pci_dev *pdev) { @@ -3401,6 +3424,9 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev) if (hisi_sas_get_fw_info(hisi_hba) < 0) goto err_out; + if (check_fw_info_v3_hw(hisi_hba) < 0) + goto err_out; + if (experimental_iopoll_q_cnt < 0 || experimental_iopoll_q_cnt >= hisi_hba->queue_count) dev_err(dev, "iopoll queue count %d cannot exceed or equal 16, using default 0\n", @@ -3550,6 +3576,11 @@ debugfs_to_reg_name_v3_hw(int off, int base_off, return NULL; } +static bool debugfs_dump_is_generated_v3_hw(void *p) +{ + return p ? true : false; +} + static void debugfs_print_reg_v3_hw(u32 *regs_val, struct seq_file *s, const struct hisi_sas_debugfs_reg *reg) { @@ -3575,6 +3606,9 @@ static int debugfs_global_v3_hw_show(struct seq_file *s, void *p) { struct hisi_sas_debugfs_regs *global = s->private; + if (!debugfs_dump_is_generated_v3_hw(global->data)) + return -EPERM; + debugfs_print_reg_v3_hw(global->data, s, &debugfs_global_reg); @@ -3586,6 +3620,9 @@ static int debugfs_axi_v3_hw_show(struct seq_file *s, void *p) { struct hisi_sas_debugfs_regs *axi = s->private; + if (!debugfs_dump_is_generated_v3_hw(axi->data)) + return -EPERM; + debugfs_print_reg_v3_hw(axi->data, s, &debugfs_axi_reg); @@ -3597,6 +3634,9 @@ static int debugfs_ras_v3_hw_show(struct seq_file *s, void *p) { struct hisi_sas_debugfs_regs *ras = s->private; + if (!debugfs_dump_is_generated_v3_hw(ras->data)) + return -EPERM; + debugfs_print_reg_v3_hw(ras->data, s, &debugfs_ras_reg); @@ -3609,6 +3649,9 @@ static int debugfs_port_v3_hw_show(struct seq_file *s, void *p) struct hisi_sas_debugfs_port *port = s->private; const struct hisi_sas_debugfs_reg *reg_port = &debugfs_port_reg; + if (!debugfs_dump_is_generated_v3_hw(port->data)) + return -EPERM; + debugfs_print_reg_v3_hw(port->data, s, reg_port); return 0; @@ -3664,6 +3707,9 @@ static int debugfs_cq_v3_hw_show(struct seq_file *s, void *p) struct hisi_sas_debugfs_cq *debugfs_cq = s->private; int slot; + if (!debugfs_dump_is_generated_v3_hw(debugfs_cq->complete_hdr)) + return -EPERM; + for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) debugfs_cq_show_slot_v3_hw(s, slot, debugfs_cq); @@ -3685,8 +3731,12 @@ static void debugfs_dq_show_slot_v3_hw(struct seq_file *s, int slot, static int debugfs_dq_v3_hw_show(struct seq_file *s, void *p) { + struct hisi_sas_debugfs_dq *debugfs_dq = s->private; int slot; + if (!debugfs_dump_is_generated_v3_hw(debugfs_dq->hdr)) + return -EPERM; + for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) debugfs_dq_show_slot_v3_hw(s, slot, s->private); @@ -3700,6 +3750,9 @@ static int debugfs_iost_v3_hw_show(struct seq_file *s, void *p) struct hisi_sas_iost *iost = debugfs_iost->iost; int i, max_command_entries = HISI_SAS_MAX_COMMANDS; + if (!debugfs_dump_is_generated_v3_hw(iost)) + return -EPERM; + for (i = 0; i < max_command_entries; i++, iost++) { __le64 *data = &iost->qw0; @@ -3719,6 +3772,9 @@ static int debugfs_iost_cache_v3_hw_show(struct seq_file *s, void *p) int i, tab_idx; __le64 *iost; + if (!debugfs_dump_is_generated_v3_hw(iost_cache)) + return -EPERM; + for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) { /* * Data struct of IOST cache: @@ -3742,6 +3798,9 @@ static int debugfs_itct_v3_hw_show(struct seq_file *s, void *p) struct hisi_sas_debugfs_itct *debugfs_itct = s->private; struct hisi_sas_itct *itct = debugfs_itct->itct; + if (!debugfs_dump_is_generated_v3_hw(itct)) + return -EPERM; + for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { __le64 *data = &itct->qw0; @@ -3761,6 +3820,9 @@ static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p) int i, tab_idx; __le64 *itct; + if (!debugfs_dump_is_generated_v3_hw(itct_cache)) + return -EPERM; + for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) { /* * Data struct of ITCT cache: @@ -3778,10 +3840,9 @@ static int debugfs_itct_cache_v3_hw_show(struct seq_file *s, void *p) } DEFINE_SHOW_ATTRIBUTE(debugfs_itct_cache_v3_hw); -static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba) +static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba, int index) { u64 *debugfs_timestamp; - int dump_index = hisi_hba->debugfs_dump_index; struct dentry *dump_dentry; struct dentry *dentry; char name[256]; @@ -3789,17 +3850,17 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba) int c; int d; - snprintf(name, 256, "%d", dump_index); + snprintf(name, 256, "%d", index); dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry); - debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index]; + debugfs_timestamp = &hisi_hba->debugfs_timestamp[index]; debugfs_create_u64("timestamp", 0400, dump_dentry, debugfs_timestamp); debugfs_create_file("global", 0400, dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL], + &hisi_hba->debugfs_regs[index][DEBUGFS_GLOBAL], &debugfs_global_v3_hw_fops); /* Create port dir and files */ @@ -3808,7 +3869,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", p); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_port_reg[dump_index][p], + &hisi_hba->debugfs_port_reg[index][p], &debugfs_port_v3_hw_fops); } @@ -3818,7 +3879,7 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", c); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_cq[dump_index][c], + &hisi_hba->debugfs_cq[index][c], &debugfs_cq_v3_hw_fops); } @@ -3828,32 +3889,32 @@ static void debugfs_create_files_v3_hw(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", d); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_dq[dump_index][d], + &hisi_hba->debugfs_dq[index][d], &debugfs_dq_v3_hw_fops); } debugfs_create_file("iost", 0400, dump_dentry, - &hisi_hba->debugfs_iost[dump_index], + &hisi_hba->debugfs_iost[index], &debugfs_iost_v3_hw_fops); debugfs_create_file("iost_cache", 0400, dump_dentry, - &hisi_hba->debugfs_iost_cache[dump_index], + &hisi_hba->debugfs_iost_cache[index], &debugfs_iost_cache_v3_hw_fops); debugfs_create_file("itct", 0400, dump_dentry, - &hisi_hba->debugfs_itct[dump_index], + &hisi_hba->debugfs_itct[index], &debugfs_itct_v3_hw_fops); debugfs_create_file("itct_cache", 0400, dump_dentry, - &hisi_hba->debugfs_itct_cache[dump_index], + &hisi_hba->debugfs_itct_cache[index], &debugfs_itct_cache_v3_hw_fops); debugfs_create_file("axi", 0400, dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI], + &hisi_hba->debugfs_regs[index][DEBUGFS_AXI], &debugfs_axi_v3_hw_fops); debugfs_create_file("ras", 0400, dump_dentry, - &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS], + &hisi_hba->debugfs_regs[index][DEBUGFS_RAS], &debugfs_ras_v3_hw_fops); } @@ -4516,22 +4577,34 @@ static void debugfs_release_v3_hw(struct hisi_hba *hisi_hba, int dump_index) int i; devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache); + hisi_hba->debugfs_iost_cache[dump_index].cache = NULL; devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache); + hisi_hba->debugfs_itct_cache[dump_index].cache = NULL; devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost); + hisi_hba->debugfs_iost[dump_index].iost = NULL; devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct); + hisi_hba->debugfs_itct[dump_index].itct = NULL; - for (i = 0; i < hisi_hba->queue_count; i++) + for (i = 0; i < hisi_hba->queue_count; i++) { devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr); + hisi_hba->debugfs_dq[dump_index][i].hdr = NULL; + } - for (i = 0; i < hisi_hba->queue_count; i++) + for (i = 0; i < hisi_hba->queue_count; i++) { devm_kfree(dev, hisi_hba->debugfs_cq[dump_index][i].complete_hdr); + hisi_hba->debugfs_cq[dump_index][i].complete_hdr = NULL; + } - for (i = 0; i < DEBUGFS_REGS_NUM; i++) + for (i = 0; i < DEBUGFS_REGS_NUM; i++) { devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data); + hisi_hba->debugfs_regs[dump_index][i].data = NULL; + } - for (i = 0; i < hisi_hba->n_phy; i++) + for (i = 0; i < hisi_hba->n_phy; i++) { devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data); + hisi_hba->debugfs_port_reg[dump_index][i].data = NULL; + } } static const struct hisi_sas_debugfs_reg *debugfs_reg_array_v3_hw[DEBUGFS_REGS_NUM] = { @@ -4658,8 +4731,6 @@ static int debugfs_snapshot_regs_v3_hw(struct hisi_hba *hisi_hba) debugfs_snapshot_itct_reg_v3_hw(hisi_hba); debugfs_snapshot_iost_reg_v3_hw(hisi_hba); - debugfs_create_files_v3_hw(hisi_hba); - debugfs_snapshot_restore_v3_hw(hisi_hba); hisi_hba->debugfs_dump_index++; @@ -4743,6 +4814,34 @@ static void debugfs_bist_init_v3_hw(struct hisi_hba *hisi_hba) hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS; } +static int debugfs_dump_index_v3_hw_show(struct seq_file *s, void *p) +{ + int *debugfs_dump_index = s->private; + + if (*debugfs_dump_index > 0) + seq_printf(s, "%d\n", *debugfs_dump_index - 1); + else + seq_puts(s, "dump not triggered\n"); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(debugfs_dump_index_v3_hw); + +static void debugfs_dump_init_v3_hw(struct hisi_hba *hisi_hba) +{ + int i; + + hisi_hba->debugfs_dump_dentry = + debugfs_create_dir("dump", hisi_hba->debugfs_dir); + + debugfs_create_file("latest_dump", 0400, hisi_hba->debugfs_dump_dentry, + &hisi_hba->debugfs_dump_index, + &debugfs_dump_index_v3_hw_fops); + + for (i = 0; i < hisi_sas_debugfs_dump_count; i++) + debugfs_create_files_v3_hw(hisi_hba, i); +} + static void debugfs_exit_v3_hw(struct hisi_hba *hisi_hba) { debugfs_remove_recursive(hisi_hba->debugfs_dir); @@ -4755,19 +4854,17 @@ static void debugfs_init_v3_hw(struct hisi_hba *hisi_hba) hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), hisi_sas_debugfs_dir); - debugfs_create_file("trigger_dump", 0200, - hisi_hba->debugfs_dir, - hisi_hba, - &debugfs_trigger_dump_v3_hw_fops); - /* create bist structures */ debugfs_bist_init_v3_hw(hisi_hba); - hisi_hba->debugfs_dump_dentry = - debugfs_create_dir("dump", hisi_hba->debugfs_dir); + debugfs_dump_init_v3_hw(hisi_hba); debugfs_phy_down_cnt_init_v3_hw(hisi_hba); debugfs_fifo_init_v3_hw(hisi_hba); + debugfs_create_file("trigger_dump", 0200, + hisi_hba->debugfs_dir, + hisi_hba, + &debugfs_trigger_dump_v3_hw_fops); } static int @@ -4860,16 +4957,13 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) SHOST_DIX_GUARD_CRC); } - if (hisi_sas_debugfs_enable) - debugfs_init_v3_hw(hisi_hba); - rc = interrupt_preinit_v3_hw(hisi_hba); if (rc) - goto err_out_undo_debugfs; + goto err_out_free_host; rc = scsi_add_host(shost, dev); if (rc) - goto err_out_undo_debugfs; + goto err_out_free_host; rc = sas_register_ha(sha); if (rc) @@ -4880,6 +4974,8 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_out_unregister_ha; scsi_scan_host(shost); + if (hisi_sas_debugfs_enable) + debugfs_init_v3_hw(hisi_hba); pm_runtime_set_autosuspend_delay(dev, 5000); pm_runtime_use_autosuspend(dev); @@ -4900,9 +4996,6 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) sas_unregister_ha(sha); err_out_remove_host: scsi_remove_host(shost); -err_out_undo_debugfs: - if (hisi_sas_debugfs_enable) - debugfs_exit_v3_hw(hisi_hba); err_out_free_host: hisi_sas_free(hisi_hba); scsi_host_put(shost); @@ -4934,6 +5027,8 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) struct Scsi_Host *shost = sha->shost; pm_runtime_get_noresume(dev); + if (hisi_sas_debugfs_enable) + debugfs_exit_v3_hw(hisi_hba); sas_unregister_ha(sha); flush_workqueue(hisi_hba->wq); @@ -4941,9 +5036,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) hisi_sas_v3_destroy_irqs(pdev, hisi_hba); hisi_sas_free(hisi_hba); - if (hisi_sas_debugfs_enable) - debugfs_exit_v3_hw(hisi_hba); - scsi_host_put(shost); } @@ -5034,7 +5126,8 @@ static int _suspend_v3_hw(struct device *device) interrupt_disable_v3_hw(hisi_hba); #ifdef CONFIG_PM - if (atomic_read(&device->power.usage_count)) { + if ((device->power.runtime_status == RPM_SUSPENDING) && + atomic_read(&device->power.usage_count)) { dev_err(dev, "PM suspend: host status cannot be suspended\n"); rc = -EBUSY; goto err_out; diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index fb04b0b515ab1f..35137f5cfb3a81 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -196,7 +196,7 @@ MODULE_ALIAS("platform:jazz_esp"); static struct platform_driver esp_jazz_driver = { .probe = esp_jazz_probe, - .remove_new = esp_jazz_remove, + .remove = esp_jazz_remove, .driver = { .name = "jazz_esp", }, diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 85059b83ea6b4f..1c6b024160da76 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -398,7 +398,11 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job) /* in case no data is transferred */ bsg_reply->reply_payload_rcv_len = 0; - if (ndlp->nlp_flag & NLP_ELS_SND_MASK) + if (test_bit(NLP_PLOGI_SND, &ndlp->nlp_flag) || + test_bit(NLP_PRLI_SND, &ndlp->nlp_flag) || + test_bit(NLP_ADISC_SND, &ndlp->nlp_flag) || + test_bit(NLP_LOGO_SND, &ndlp->nlp_flag) || + test_bit(NLP_RNID_SND, &ndlp->nlp_flag)) return -ENODEV; /* allocate our bsg tracking structure */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index d4e46a08f94daa..efeb61b15a5b5b 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -571,7 +571,7 @@ int lpfc_issue_reg_vfi(struct lpfc_vport *); int lpfc_issue_unreg_vfi(struct lpfc_vport *); int lpfc_selective_reset(struct lpfc_hba *); int lpfc_sli4_read_config(struct lpfc_hba *); -void lpfc_sli4_node_prep(struct lpfc_hba *); +void lpfc_sli4_node_rpi_restore(struct lpfc_hba *phba); int lpfc_sli4_els_sgl_update(struct lpfc_hba *phba); int lpfc_sli4_nvmet_sgl_update(struct lpfc_hba *phba); int lpfc_io_buf_flush(struct lpfc_hba *phba, struct list_head *sglist); @@ -660,6 +660,7 @@ void lpfc_wqe_cmd_template(void); void lpfc_nvmet_cmd_template(void); void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, uint32_t stat, uint32_t param); +void lpfc_nvmels_flush_cmd(struct lpfc_hba *phba); extern int lpfc_enable_nvmet_cnt; extern unsigned long long lpfc_enable_nvmet[]; extern int lpfc_no_hba_reset_cnt; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 134bc96dd13400..30891ad17e2a41 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -735,7 +735,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0238 Process x%06x NameServer Rsp " - "Data: x%x x%x x%x x%lx x%x\n", Did, + "Data: x%lx x%x x%x x%lx x%x\n", Did, ndlp->nlp_flag, ndlp->nlp_fc4_type, ndlp->nlp_state, vport->fc_flag, vport->fc_rscn_id_cnt); @@ -744,7 +744,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) * state of ndlp hit devloss, change state to * allow rediscovery. */ - if (ndlp->nlp_flag & NLP_NPR_2B_DISC && + if (test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag) && ndlp->nlp_state == NLP_STE_UNUSED_NODE) { lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -832,12 +832,10 @@ lpfc_ns_rsp_audit_did(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) if (ndlp->nlp_type != NLP_NVME_INITIATOR || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) continue; - spin_lock_irq(&ndlp->lock); if (ndlp->nlp_DID == Did) - ndlp->nlp_flag &= ~NLP_NVMET_RECOV; + clear_bit(NLP_NVMET_RECOV, &ndlp->nlp_flag); else - ndlp->nlp_flag |= NLP_NVMET_RECOV; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NVMET_RECOV, &ndlp->nlp_flag); } } } @@ -894,13 +892,11 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint8_t fc4_type, */ if (vport->phba->nvmet_support) { list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!(ndlp->nlp_flag & NLP_NVMET_RECOV)) + if (!test_bit(NLP_NVMET_RECOV, &ndlp->nlp_flag)) continue; lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NVMET_RECOV; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NVMET_RECOV, &ndlp->nlp_flag); } } @@ -1440,7 +1436,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (ndlp) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0242 Process x%x GFF " - "NameServer Rsp Data: x%x x%lx x%x\n", + "NameServer Rsp Data: x%lx x%lx x%x\n", did, ndlp->nlp_flag, vport->fc_flag, vport->fc_rscn_id_cnt); } else { @@ -2226,6 +2222,11 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ulp_status, ulp_word4, latt); if (latt || ulp_status) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY, + "0229 FDMI cmd %04x failed, latt = %d " + "ulp_status: (x%x/x%x), sli_flag x%x\n", + be16_to_cpu(fdmi_cmd), latt, ulp_status, + ulp_word4, phba->sli.sli_flag); /* Look for a retryable error */ if (ulp_status == IOSTAT_LOCAL_REJECT) { @@ -2234,8 +2235,16 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, case IOERR_SLI_DOWN: /* Driver aborted this IO. No retry as error * is likely Offline->Online or some adapter - * error. Recovery will try again. + * error. Recovery will try again, but if port + * is not active there's no point to continue + * issuing follow up FDMI commands. */ + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { + free_ndlp = cmdiocb->ndlp; + lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); + return; + } break; case IOERR_ABORT_IN_PROGRESS: case IOERR_SEQUENCE_TIMEOUT: @@ -2256,12 +2265,6 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; } } - - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0229 FDMI cmd %04x latt = %d " - "ulp_status: x%x, rid x%x\n", - be16_to_cpu(fdmi_cmd), latt, ulp_status, - ulp_word4); } free_ndlp = cmdiocb->ndlp; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index a2d2b02b34187f..3fd1aa5cc78cc8 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -870,8 +870,8 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) wwn_to_u64(ndlp->nlp_nodename.u.wwn)); len += scnprintf(buf+len, size-len, "RPI:x%04x ", ndlp->nlp_rpi); - len += scnprintf(buf+len, size-len, "flag:x%08x ", - ndlp->nlp_flag); + len += scnprintf(buf+len, size-len, "flag:x%08lx ", + ndlp->nlp_flag); if (!ndlp->nlp_type) len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE "); if (ndlp->nlp_type & NLP_FC_NODE) diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index f5ae8cc158205c..3e173b5d00e008 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2013 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -102,7 +102,7 @@ struct lpfc_nodelist { spinlock_t lock; /* Node management lock */ - uint32_t nlp_flag; /* entry flags */ + unsigned long nlp_flag; /* entry flags */ uint32_t nlp_DID; /* FC D_ID of entry */ uint32_t nlp_last_elscmd; /* Last ELS cmd sent */ uint16_t nlp_type; @@ -182,37 +182,37 @@ struct lpfc_node_rrq { #define lpfc_ndlp_check_qdepth(phba, ndlp) \ (ndlp->cmd_qdepth < phba->sli4_hba.max_cfg_param.max_xri) -/* Defines for nlp_flag (uint32) */ -#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */ -#define NLP_REG_LOGIN_SEND 0x00000002 /* sent reglogin to adapter */ -#define NLP_RELEASE_RPI 0x00000004 /* Release RPI to free pool */ -#define NLP_SUPPRESS_RSP 0x00000010 /* Remote NPort supports suppress rsp */ -#define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */ -#define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */ -#define NLP_ADISC_SND 0x00000080 /* sent ADISC request for this entry */ -#define NLP_LOGO_SND 0x00000100 /* sent LOGO request for this entry */ -#define NLP_RNID_SND 0x00000400 /* sent RNID request for this entry */ -#define NLP_ELS_SND_MASK 0x000007e0 /* sent ELS request for this entry */ -#define NLP_NVMET_RECOV 0x00001000 /* NVMET auditing node for recovery. */ -#define NLP_UNREG_INP 0x00008000 /* UNREG_RPI cmd is in progress */ -#define NLP_DROPPED 0x00010000 /* Init ref count has been dropped */ -#define NLP_DELAY_TMO 0x00020000 /* delay timeout is running for node */ -#define NLP_NPR_2B_DISC 0x00040000 /* node is included in num_disc_nodes */ -#define NLP_RCV_PLOGI 0x00080000 /* Rcv'ed PLOGI from remote system */ -#define NLP_LOGO_ACC 0x00100000 /* Process LOGO after ACC completes */ -#define NLP_TGT_NO_SCSIID 0x00200000 /* good PRLI but no binding for scsid */ -#define NLP_ISSUE_LOGO 0x00400000 /* waiting to issue a LOGO */ -#define NLP_IN_DEV_LOSS 0x00800000 /* devloss in progress */ -#define NLP_ACC_REGLOGIN 0x01000000 /* Issue Reg Login after successful +/* nlp_flag mask bits */ +enum lpfc_nlp_flag { + NLP_IGNR_REG_CMPL = 0, /* Rcvd rscn before we cmpl reg login */ + NLP_REG_LOGIN_SEND = 1, /* sent reglogin to adapter */ + NLP_SUPPRESS_RSP = 4, /* Remote NPort supports suppress rsp */ + NLP_PLOGI_SND = 5, /* sent PLOGI request for this entry */ + NLP_PRLI_SND = 6, /* sent PRLI request for this entry */ + NLP_ADISC_SND = 7, /* sent ADISC request for this entry */ + NLP_LOGO_SND = 8, /* sent LOGO request for this entry */ + NLP_RNID_SND = 10, /* sent RNID request for this entry */ + NLP_NVMET_RECOV = 12, /* NVMET auditing node for recovery. */ + NLP_UNREG_INP = 15, /* UNREG_RPI cmd is in progress */ + NLP_DROPPED = 16, /* Init ref count has been dropped */ + NLP_DELAY_TMO = 17, /* delay timeout is running for node */ + NLP_NPR_2B_DISC = 18, /* node is included in num_disc_nodes */ + NLP_RCV_PLOGI = 19, /* Rcv'ed PLOGI from remote system */ + NLP_LOGO_ACC = 20, /* Process LOGO after ACC completes */ + NLP_TGT_NO_SCSIID = 21, /* good PRLI but no binding for scsid */ + NLP_ISSUE_LOGO = 22, /* waiting to issue a LOGO */ + NLP_IN_DEV_LOSS = 23, /* devloss in progress */ + NLP_ACC_REGLOGIN = 24, /* Issue Reg Login after successful ACC */ -#define NLP_NPR_ADISC 0x02000000 /* Issue ADISC when dq'ed from + NLP_NPR_ADISC = 25, /* Issue ADISC when dq'ed from NPR list */ -#define NLP_RM_DFLT_RPI 0x04000000 /* need to remove leftover dflt RPI */ -#define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */ -#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ -#define NLP_SC_REQ 0x20000000 /* Target requires authentication */ -#define NLP_FIRSTBURST 0x40000000 /* Target supports FirstBurst */ -#define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */ + NLP_RM_DFLT_RPI = 26, /* need to remove leftover dflt RPI */ + NLP_NODEV_REMOVE = 27, /* Defer removal till discovery ends */ + NLP_TARGET_REMOVE = 28, /* Target remove in process */ + NLP_SC_REQ = 29, /* Target requires authentication */ + NLP_FIRSTBURST = 30, /* Target supports FirstBurst */ + NLP_RPI_REGISTERED = 31 /* nlp_rpi is valid */ +}; /* There are 4 different double linked lists nodelist entries can reside on. * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index d737b897ddd821..37f0a930d46914 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -725,11 +725,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, list_for_each_entry_safe(np, next_np, &vport->fc_nodes, nlp_listp) { if ((np->nlp_state != NLP_STE_NPR_NODE) || - !(np->nlp_flag & NLP_NPR_ADISC)) + !test_bit(NLP_NPR_ADISC, &np->nlp_flag)) continue; - spin_lock_irq(&np->lock); - np->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&np->lock); + clear_bit(NLP_NPR_ADISC, &np->nlp_flag); lpfc_unreg_rpi(vport, np); } lpfc_cleanup_pending_mbox(vport); @@ -864,9 +862,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, sizeof(struct lpfc_name)); /* Set state will put ndlp onto node list if not already done */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) @@ -1018,7 +1014,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * registered with the SCSI transport, remove the initial * reference to trigger node release. */ - if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS) && + if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag) && !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) lpfc_nlp_put(ndlp); @@ -1236,9 +1232,9 @@ lpfc_cmpl_els_link_down(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "6445 ELS completes after LINK_DOWN: " - " Status %x/%x cmd x%x flg x%x\n", + " Status %x/%x cmd x%x flg x%x iotag x%x\n", ulp_status, ulp_word4, cmd, - cmdiocb->cmd_flag); + cmdiocb->cmd_flag, cmdiocb->iotag); if (cmdiocb->cmd_flag & LPFC_IO_FABRIC) { cmdiocb->cmd_flag &= ~LPFC_IO_FABRIC; @@ -1548,7 +1544,7 @@ lpfc_initial_flogi(struct lpfc_vport *vport) * Otherwise, decrement node reference to trigger release. */ if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) && - !(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + !test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) lpfc_nlp_put(ndlp); return 0; } @@ -1597,7 +1593,7 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) * Otherwise, decrement node reference to trigger release. */ if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) && - !(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + !test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) lpfc_nlp_put(ndlp); return 0; } @@ -1675,9 +1671,9 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, struct lpfc_nodelist *new_ndlp; struct serv_parm *sp; uint8_t name[sizeof(struct lpfc_name)]; - uint32_t keepDID = 0, keep_nlp_flag = 0; + uint32_t keepDID = 0; int rc; - uint32_t keep_new_nlp_flag = 0; + unsigned long keep_nlp_flag = 0, keep_new_nlp_flag = 0; uint16_t keep_nlp_state; u32 keep_nlp_fc4_type = 0; struct lpfc_nvme_rport *keep_nrport = NULL; @@ -1704,8 +1700,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, } lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_NODE, - "3178 PLOGI confirm: ndlp x%x x%x x%x: " - "new_ndlp x%x x%x x%x\n", + "3178 PLOGI confirm: ndlp x%x x%lx x%x: " + "new_ndlp x%x x%lx x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_fc4_type, (new_ndlp ? new_ndlp->nlp_DID : 0), (new_ndlp ? new_ndlp->nlp_flag : 0), @@ -1769,48 +1765,48 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, new_ndlp->nlp_flag = ndlp->nlp_flag; /* if new_ndlp had NLP_UNREG_INP set, keep it */ - if (keep_new_nlp_flag & NLP_UNREG_INP) - new_ndlp->nlp_flag |= NLP_UNREG_INP; + if (test_bit(NLP_UNREG_INP, &keep_new_nlp_flag)) + set_bit(NLP_UNREG_INP, &new_ndlp->nlp_flag); else - new_ndlp->nlp_flag &= ~NLP_UNREG_INP; + clear_bit(NLP_UNREG_INP, &new_ndlp->nlp_flag); /* if new_ndlp had NLP_RPI_REGISTERED set, keep it */ - if (keep_new_nlp_flag & NLP_RPI_REGISTERED) - new_ndlp->nlp_flag |= NLP_RPI_REGISTERED; + if (test_bit(NLP_RPI_REGISTERED, &keep_new_nlp_flag)) + set_bit(NLP_RPI_REGISTERED, &new_ndlp->nlp_flag); else - new_ndlp->nlp_flag &= ~NLP_RPI_REGISTERED; + clear_bit(NLP_RPI_REGISTERED, &new_ndlp->nlp_flag); /* * Retain the DROPPED flag. This will take care of the init * refcount when affecting the state change */ - if (keep_new_nlp_flag & NLP_DROPPED) - new_ndlp->nlp_flag |= NLP_DROPPED; + if (test_bit(NLP_DROPPED, &keep_new_nlp_flag)) + set_bit(NLP_DROPPED, &new_ndlp->nlp_flag); else - new_ndlp->nlp_flag &= ~NLP_DROPPED; + clear_bit(NLP_DROPPED, &new_ndlp->nlp_flag); ndlp->nlp_flag = keep_new_nlp_flag; /* if ndlp had NLP_UNREG_INP set, keep it */ - if (keep_nlp_flag & NLP_UNREG_INP) - ndlp->nlp_flag |= NLP_UNREG_INP; + if (test_bit(NLP_UNREG_INP, &keep_nlp_flag)) + set_bit(NLP_UNREG_INP, &ndlp->nlp_flag); else - ndlp->nlp_flag &= ~NLP_UNREG_INP; + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); /* if ndlp had NLP_RPI_REGISTERED set, keep it */ - if (keep_nlp_flag & NLP_RPI_REGISTERED) - ndlp->nlp_flag |= NLP_RPI_REGISTERED; + if (test_bit(NLP_RPI_REGISTERED, &keep_nlp_flag)) + set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); else - ndlp->nlp_flag &= ~NLP_RPI_REGISTERED; + clear_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); /* * Retain the DROPPED flag. This will take care of the init * refcount when affecting the state change */ - if (keep_nlp_flag & NLP_DROPPED) - ndlp->nlp_flag |= NLP_DROPPED; + if (test_bit(NLP_DROPPED, &keep_nlp_flag)) + set_bit(NLP_DROPPED, &ndlp->nlp_flag); else - ndlp->nlp_flag &= ~NLP_DROPPED; + clear_bit(NLP_DROPPED, &ndlp->nlp_flag); spin_unlock_irq(&new_ndlp->lock); spin_unlock_irq(&ndlp->lock); @@ -1888,7 +1884,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, phba->active_rrq_pool); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_NODE, - "3173 PLOGI confirm exit: new_ndlp x%x x%x x%x\n", + "3173 PLOGI confirm exit: new_ndlp x%x x%lx x%x\n", new_ndlp->nlp_DID, new_ndlp->nlp_flag, new_ndlp->nlp_fc4_type); @@ -2009,7 +2005,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; struct lpfc_nodelist *ndlp, *free_ndlp; struct lpfc_dmabuf *prsp; - int disc; + bool disc; struct serv_parm *sp = NULL; u32 ulp_status, ulp_word4, did, iotag; bool release_node = false; @@ -2044,10 +2040,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Since ndlp can be freed in the disc state machine, note if this node * is being used during discovery. */ - spin_lock_irq(&ndlp->lock); - disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + disc = test_and_clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); /* PLOGI completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, @@ -2060,9 +2053,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); goto out; } @@ -2070,11 +2061,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ - if (disc) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); - } + if (disc) + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); goto out; } /* Warn PLOGI status Don't print the vport to vport rjts */ @@ -2097,7 +2085,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * with the reglogin process. */ spin_lock_irq(&ndlp->lock); - if ((ndlp->nlp_flag & (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI)) && + if ((test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag) || + test_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag)) && ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE) { spin_unlock_irq(&ndlp->lock); goto out; @@ -2108,8 +2097,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * start the device remove process. */ if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); + if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) release_node = true; } spin_unlock_irq(&ndlp->lock); @@ -2212,12 +2201,13 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) * outstanding UNREG_RPI mbox command completes, unless we * are going offline. This logic does not apply for Fabric DIDs */ - if ((ndlp->nlp_flag & (NLP_IGNR_REG_CMPL | NLP_UNREG_INP)) && + if ((test_bit(NLP_IGNR_REG_CMPL, &ndlp->nlp_flag) || + test_bit(NLP_UNREG_INP, &ndlp->nlp_flag)) && ((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && !test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "4110 Issue PLOGI x%x deferred " - "on NPort x%x rpi x%x flg x%x Data:" + "on NPort x%x rpi x%x flg x%lx Data:" " x%px\n", ndlp->nlp_defer_did, ndlp->nlp_DID, ndlp->nlp_rpi, ndlp->nlp_flag, ndlp); @@ -2335,10 +2325,10 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ulp_status = get_job_ulpstatus(phba, rspiocb); ulp_word4 = get_job_word4(phba, rspiocb); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_PRLI_SND; + clear_bit(NLP_PRLI_SND, &ndlp->nlp_flag); /* Driver supports multiple FC4 types. Counters matter. */ + spin_lock_irq(&ndlp->lock); vport->fc_prli_sent--; ndlp->fc4_prli_sent--; spin_unlock_irq(&ndlp->lock); @@ -2379,7 +2369,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Warn PRLI status */ lpfc_printf_vlog(vport, mode, LOG_ELS, "2754 PRLI DID:%06X Status:x%x/x%x, " - "data: x%x x%x x%x\n", + "data: x%x x%x x%lx\n", ndlp->nlp_DID, ulp_status, ulp_word4, ndlp->nlp_state, ndlp->fc4_prli_sent, ndlp->nlp_flag); @@ -2396,10 +2386,10 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((ndlp->nlp_state >= NLP_STE_PLOGI_ISSUE && ndlp->nlp_state <= NLP_STE_REG_LOGIN_ISSUE) || (ndlp->nlp_state == NLP_STE_NPR_NODE && - ndlp->nlp_flag & NLP_DELAY_TMO)) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, + test_bit(NLP_DELAY_TMO, &ndlp->nlp_flag))) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, "2784 PRLI cmpl: Allow Node recovery " - "DID x%06x nstate x%x nflag x%x\n", + "DID x%06x nstate x%x nflag x%lx\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag); goto out; @@ -2420,8 +2410,8 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, spin_lock_irq(&ndlp->lock); if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) && !ndlp->fc4_prli_sent) { - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); + if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) release_node = true; } spin_unlock_irq(&ndlp->lock); @@ -2496,7 +2486,8 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - ndlp->nlp_flag &= ~(NLP_FIRSTBURST | NLP_NPR_2B_DISC); + clear_bit(NLP_FIRSTBURST, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); ndlp->nvme_fb_size = 0; send_next_prli: @@ -2627,8 +2618,8 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * the ndlp is used to track outstanding PRLIs for different * FC4 types. */ + set_bit(NLP_PRLI_SND, &ndlp->nlp_flag); spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_PRLI_SND; vport->fc_prli_sent++; ndlp->fc4_prli_sent++; spin_unlock_irq(&ndlp->lock); @@ -2789,7 +2780,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; IOCB_t *irsp; struct lpfc_nodelist *ndlp; - int disc; + bool disc; u32 ulp_status, ulp_word4, tmo, iotag; bool release_node = false; @@ -2818,10 +2809,8 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Since ndlp can be freed in the disc state machine, note if this node * is being used during discovery. */ - spin_lock_irq(&ndlp->lock); - disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); - ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC); - spin_unlock_irq(&ndlp->lock); + disc = test_and_clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); + clear_bit(NLP_ADISC_SND, &ndlp->nlp_flag); /* ADISC completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0104 ADISC completes to NPort x%x " @@ -2832,9 +2821,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); goto out; } @@ -2843,9 +2830,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { /* ELS command is being retried */ if (disc) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_set_disctmo(vport); } goto out; @@ -2864,8 +2849,8 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ spin_lock_irq(&ndlp->lock); if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS)) + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); + if (!test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) release_node = true; } spin_unlock_irq(&ndlp->lock); @@ -2938,9 +2923,7 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->fc_stat.elsXmitADISC++; elsiocb->cmd_cmpl = lpfc_cmpl_els_adisc; - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_ADISC_SND; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_ADISC_SND, &ndlp->nlp_flag); elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); @@ -2961,9 +2944,7 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 0; err: - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_ADISC_SND; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_ADISC_SND, &ndlp->nlp_flag); return 1; } @@ -2985,7 +2966,6 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_nodelist *ndlp = cmdiocb->ndlp; struct lpfc_vport *vport = ndlp->vport; IOCB_t *irsp; - unsigned long flags; uint32_t skip_recovery = 0; int wake_up_waiter = 0; u32 ulp_status; @@ -3007,8 +2987,8 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, iotag = irsp->ulpIoTag; } + clear_bit(NLP_LOGO_SND, &ndlp->nlp_flag); spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; if (ndlp->save_flags & NLP_WAIT_FOR_LOGO) { wake_up_waiter = 1; ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO; @@ -3023,7 +3003,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* LOGO completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0105 LOGO completes to NPort x%x " - "IoTag x%x refcnt %d nflags x%x xflags x%x " + "IoTag x%x refcnt %d nflags x%lx xflags x%x " "Data: x%x x%x x%x x%x\n", ndlp->nlp_DID, iotag, kref_read(&ndlp->kref), ndlp->nlp_flag, @@ -3061,12 +3041,8 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* The driver sets this flag for an NPIV instance that doesn't want to * log into the remote port. */ - if (ndlp->nlp_flag & NLP_TARGET_REMOVE) { - spin_lock_irq(&ndlp->lock); - if (phba->sli_rev == LPFC_SLI_REV4) - ndlp->nlp_flag |= NLP_RELEASE_RPI; - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_TARGET_REMOVE, &ndlp->nlp_flag)) { + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_DEVICE_RM); goto out_rsrc_free; @@ -3089,9 +3065,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET) && skip_recovery == 0) { lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irqsave(&ndlp->lock, flags); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irqrestore(&ndlp->lock, flags); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3187 LOGO completes to NPort x%x: Start " @@ -3113,9 +3087,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * register with the transport. */ if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_DEVICE_RM); } @@ -3156,12 +3128,8 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint16_t cmdsize; int rc; - spin_lock_irq(&ndlp->lock); - if (ndlp->nlp_flag & NLP_LOGO_SND) { - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_LOGO_SND, &ndlp->nlp_flag)) return 0; - } - spin_unlock_irq(&ndlp->lock); cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, @@ -3180,10 +3148,8 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->fc_stat.elsXmitLOGO++; elsiocb->cmd_cmpl = lpfc_cmpl_els_logo; - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_LOGO_SND; - ndlp->nlp_flag &= ~NLP_ISSUE_LOGO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_LOGO_SND, &ndlp->nlp_flag); + clear_bit(NLP_ISSUE_LOGO, &ndlp->nlp_flag); elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); @@ -3208,9 +3174,7 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 0; err: - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_LOGO_SND, &ndlp->nlp_flag); return 1; } @@ -3286,13 +3250,13 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, static int lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) { - int rc = 0; + int rc; struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ns_ndlp; LPFC_MBOXQ_t *mbox; - if (fc_ndlp->nlp_flag & NLP_RPI_REGISTERED) - return rc; + if (test_bit(NLP_RPI_REGISTERED, &fc_ndlp->nlp_flag)) + return 0; ns_ndlp = lpfc_findnode_did(vport, NameServer_DID); if (!ns_ndlp) @@ -3309,7 +3273,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) if (!mbox) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, "0936 %s: no memory for reg_login " - "Data: x%x x%x x%x x%x\n", __func__, + "Data: x%x x%x x%lx x%x\n", __func__, fc_ndlp->nlp_DID, fc_ndlp->nlp_state, fc_ndlp->nlp_flag, fc_ndlp->nlp_rpi); return -ENOMEM; @@ -3321,7 +3285,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) goto out; } - fc_ndlp->nlp_flag |= NLP_REG_LOGIN_SEND; + set_bit(NLP_REG_LOGIN_SEND, &fc_ndlp->nlp_flag); mbox->mbox_cmpl = lpfc_mbx_cmpl_fc_reg_login; mbox->ctx_ndlp = lpfc_nlp_get(fc_ndlp); if (!mbox->ctx_ndlp) { @@ -3345,7 +3309,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, "0938 %s: failed to format reg_login " - "Data: x%x x%x x%x x%x\n", __func__, + "Data: x%x x%x x%lx x%x\n", __func__, fc_ndlp->nlp_DID, fc_ndlp->nlp_state, fc_ndlp->nlp_flag, fc_ndlp->nlp_rpi); return rc; @@ -4384,11 +4348,8 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) { struct lpfc_work_evt *evtp; - if (!(nlp->nlp_flag & NLP_DELAY_TMO)) + if (!test_and_clear_bit(NLP_DELAY_TMO, &nlp->nlp_flag)) return; - spin_lock_irq(&nlp->lock); - nlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(&nlp->lock); del_timer_sync(&nlp->nlp_delayfunc); nlp->nlp_last_elscmd = 0; if (!list_empty(&nlp->els_retry_evt.evt_listp)) { @@ -4397,10 +4358,7 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) evtp = &nlp->els_retry_evt; lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); } - if (nlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(&nlp->lock); - nlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(&nlp->lock); + if (test_and_clear_bit(NLP_NPR_2B_DISC, &nlp->nlp_flag)) { if (vport->num_disc_nodes) { if (vport->port_state < LPFC_VPORT_READY) { /* Check if there are more ADISCs to be sent */ @@ -4480,14 +4438,11 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) spin_lock_irq(&ndlp->lock); cmd = ndlp->nlp_last_elscmd; ndlp->nlp_last_elscmd = 0; + spin_unlock_irq(&ndlp->lock); - if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { - spin_unlock_irq(&ndlp->lock); + if (!test_and_clear_bit(NLP_DELAY_TMO, &ndlp->nlp_flag)) return; - } - ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); /* * If a discovery event readded nlp_delayfunc after timer * firing and before processing the timer, cancel the @@ -5010,9 +4965,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* delay is specified in milliseconds */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(delay)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_prev_state = ndlp->nlp_state; if ((cmd == ELS_CMD_PRLI) || @@ -5072,7 +5025,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0108 No retry ELS command x%x to remote " "NPORT x%x Retried:%d Error:x%x/%x " - "IoTag x%x nflags x%x\n", + "IoTag x%x nflags x%lx\n", cmd, did, cmdiocb->retry, ulp_status, ulp_word4, cmdiocb->iotag, (ndlp ? ndlp->nlp_flag : 0)); @@ -5239,7 +5192,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* ACC to LOGO completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0109 ACC to LOGO completes to NPort x%x refcnt %d " - "last els x%x Data: x%x x%x x%x\n", + "last els x%x Data: x%lx x%x x%x\n", ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_last_elscmd, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -5254,16 +5207,14 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; if (ndlp->nlp_state == NLP_STE_NPR_NODE) { - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) + if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) lpfc_unreg_rpi(vport, ndlp); /* If came from PRLO, then PRLO_ACC is done. * Start rediscovery now. */ if (ndlp->nlp_last_elscmd == ELS_CMD_PRLO) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); @@ -5300,7 +5251,7 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (ndlp) { lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0006 rpi x%x DID:%x flg:%x %d x%px " + "0006 rpi x%x DID:%x flg:%lx %d x%px " "mbx_cmd x%x mbx_flag x%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp, mbx_cmd, @@ -5311,11 +5262,9 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * first on an UNREG_LOGIN and then release the final * references. */ - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + clear_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); if (mbx_cmd == MBX_UNREG_LOGIN) - ndlp->nlp_flag &= ~NLP_UNREG_INP; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); lpfc_drop_node(ndlp->vport, ndlp); } @@ -5381,23 +5330,23 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* ELS response tag completes */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0110 ELS response tag x%x completes " - "Data: x%x x%x x%x x%x x%x x%x x%x x%x %p %p\n", + "Data: x%x x%x x%x x%x x%lx x%x x%x x%x %p %p\n", iotag, ulp_status, ulp_word4, tmo, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi, kref_read(&ndlp->kref), mbox, ndlp); if (mbox) { - if (ulp_status == 0 - && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { + if (ulp_status == 0 && + test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag)) { if (!lpfc_unreg_rpi(vport, ndlp) && !test_bit(FC_PT2PT, &vport->fc_flag)) { - if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || + if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0314 PLOGI recov " "DID x%x " - "Data: x%x x%x x%x\n", + "Data: x%x x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_rpi, @@ -5414,18 +5363,17 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out_free_mbox; mbox->vport = vport; - if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) { + if (test_bit(NLP_RM_DFLT_RPI, &ndlp->nlp_flag)) { mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; - } - else { + } else { mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); } - ndlp->nlp_flag |= NLP_REG_LOGIN_SEND; + set_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) != MBX_NOT_FINISHED) goto out; @@ -5434,12 +5382,12 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * set for this failed mailbox command. */ lpfc_nlp_put(ndlp); - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + clear_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); /* ELS rsp: Cannot issue reg_login for */ lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0138 ELS rsp: Cannot issue reg_login for x%x " - "Data: x%x x%x x%x\n", + "Data: x%lx x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); } @@ -5448,32 +5396,20 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } out: if (ndlp && shost) { - spin_lock_irq(&ndlp->lock); if (mbox) - ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN; - ndlp->nlp_flag &= ~NLP_RM_DFLT_RPI; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); + clear_bit(NLP_RM_DFLT_RPI, &ndlp->nlp_flag); } /* An SLI4 NPIV instance wants to drop the node at this point under - * these conditions and release the RPI. + * these conditions because it doesn't need the login. */ if (phba->sli_rev == LPFC_SLI_REV4 && vport && vport->port_type == LPFC_NPIV_PORT && !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { - if (ndlp->nlp_flag & NLP_RELEASE_RPI) { - if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE && - ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) { - lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - ndlp->nlp_flag &= ~NLP_RELEASE_RPI; - spin_unlock_irq(&ndlp->lock); - } - lpfc_drop_node(vport, ndlp); - } else if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE && - ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE && - ndlp->nlp_state != NLP_STE_PRLI_ISSUE) { + if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE && + ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE && + ndlp->nlp_state != NLP_STE_PRLI_ISSUE) { /* Drop ndlp if there is no planned or outstanding * issued PRLI. * @@ -5540,9 +5476,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, ELS_CMD_ACC); if (!elsiocb) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_LOGO_ACC; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); return 1; } @@ -5570,7 +5504,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, pcmd += sizeof(uint32_t); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC: did:x%x flg:x%x", + "Issue ACC: did:x%x flg:x%lx", ndlp->nlp_DID, ndlp->nlp_flag, 0); break; case ELS_CMD_FLOGI: @@ -5649,7 +5583,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC FLOGI/PLOGI: did:x%x flg:x%x", + "Issue ACC FLOGI/PLOGI: did:x%x flg:x%lx", ndlp->nlp_DID, ndlp->nlp_flag, 0); break; case ELS_CMD_PRLO: @@ -5687,7 +5621,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC PRLO: did:x%x flg:x%x", + "Issue ACC PRLO: did:x%x flg:x%lx", ndlp->nlp_DID, ndlp->nlp_flag, 0); break; case ELS_CMD_RDF: @@ -5732,12 +5666,10 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, default: return 1; } - if (ndlp->nlp_flag & NLP_LOGO_ACC) { - spin_lock_irq(&ndlp->lock); - if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED || - ndlp->nlp_flag & NLP_REG_LOGIN_SEND)) - ndlp->nlp_flag &= ~NLP_LOGO_ACC; - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_LOGO_ACC, &ndlp->nlp_flag)) { + if (!test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag) && + !test_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag)) + clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); elsiocb->cmd_cmpl = lpfc_cmpl_els_logo_acc; } else { elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; @@ -5760,7 +5692,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, /* Xmit ELS ACC response tag */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0128 Xmit ELS ACC response Status: x%x, IoTag: x%x, " - "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " + "XRI: x%x, DID: x%x, nlp_flag: x%lx nlp_state: x%x " "RPI: x%x, fc_flag x%lx refcnt %d\n", rc, elsiocb->iotag, elsiocb->sli4_xritag, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, @@ -5835,13 +5767,13 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, /* Xmit ELS RJT response tag */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0129 Xmit ELS RJT x%x response tag x%x " - "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, " + "xri x%x, did x%x, nlp_flag x%lx, nlp_state x%x, " "rpi x%x\n", rejectError, elsiocb->iotag, get_job_ulpcontext(phba, elsiocb), ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue LS_RJT: did:x%x flg:x%x err:x%x", + "Issue LS_RJT: did:x%x flg:x%lx err:x%x", ndlp->nlp_DID, ndlp->nlp_flag, rejectError); phba->fc_stat.elsXmitLSRJT++; @@ -5852,18 +5784,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, return 1; } - /* The NPIV instance is rejecting this unsolicited ELS. Make sure the - * node's assigned RPI gets released provided this node is not already - * registered with the transport. - */ - if (phba->sli_rev == LPFC_SLI_REV4 && - vport->port_type == LPFC_NPIV_PORT && - !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_RELEASE_RPI; - spin_unlock_irq(&ndlp->lock); - } - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); @@ -5944,7 +5864,7 @@ lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_format_edc_lft_desc(phba, tlv); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue EDC ACC: did:x%x flg:x%x refcnt %d", + "Issue EDC ACC: did:x%x flg:x%lx refcnt %d", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp; @@ -5966,7 +5886,7 @@ lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Xmit ELS ACC response tag */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0152 Xmit EDC ACC response Status: x%x, IoTag: x%x, " - "XRI: x%x, DID: x%x, nlp_flag: x%x nlp_state: x%x " + "XRI: x%x, DID: x%x, nlp_flag: x%lx nlp_state: x%x " "RPI: x%x, fc_flag x%lx\n", rc, elsiocb->iotag, elsiocb->sli4_xritag, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, @@ -6035,7 +5955,7 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, /* Xmit ADISC ACC response tag */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0130 Xmit ADISC ACC response iotag x%x xri: " - "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n", + "x%x, did x%x, nlp_flag x%lx, nlp_state x%x rpi x%x\n", elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -6051,7 +5971,7 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, ap->DID = be32_to_cpu(vport->fc_myDID); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC ADISC: did:x%x flg:x%x refcnt %d", + "Issue ACC ADISC: did:x%x flg:x%lx refcnt %d", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; @@ -6157,7 +6077,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, /* Xmit PRLI ACC response tag */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0131 Xmit PRLI ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", + "did x%x, nlp_flag x%lx, nlp_state x%x, rpi x%x\n", elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -6228,7 +6148,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6015 NVME issue PRLI ACC word1 x%08x " - "word4 x%08x word5 x%08x flag x%x, " + "word4 x%08x word5 x%08x flag x%lx, " "fcp_info x%x nlp_type x%x\n", npr_nvme->word1, npr_nvme->word4, npr_nvme->word5, ndlp->nlp_flag, @@ -6243,7 +6163,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, ndlp->nlp_DID); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC PRLI: did:x%x flg:x%x", + "Issue ACC PRLI: did:x%x flg:x%lx", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; @@ -6357,7 +6277,7 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC RNID: did:x%x flg:x%x refcnt %d", + "Issue ACC RNID: did:x%x flg:x%lx refcnt %d", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; @@ -6414,7 +6334,7 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport, get_job_ulpcontext(phba, iocb)); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Clear RRQ: did:x%x flg:x%x exchg:x%.08x", + "Clear RRQ: did:x%x flg:x%lx exchg:x%.08x", ndlp->nlp_DID, ndlp->nlp_flag, rrq->rrq_exchg); if (vport->fc_myDID == be32_to_cpu(bf_get(rrq_did, rrq))) xri = bf_get(rrq_oxid, rrq); @@ -6491,7 +6411,7 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, memcpy(pcmd, data, cmdsize - sizeof(uint32_t)); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC ECHO: did:x%x flg:x%x refcnt %d", + "Issue ACC ECHO: did:x%x flg:x%lx refcnt %d", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); phba->fc_stat.elsXmitACC++; @@ -6541,14 +6461,12 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport) list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state != NLP_STE_NPR_NODE || - !(ndlp->nlp_flag & NLP_NPR_ADISC)) + !test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) continue; - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); - if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { + if (!test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { /* This node was marked for ADISC but was not picked * for discovery. This is possible if the node was * missing in gidft response. @@ -6606,9 +6524,9 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) /* go thru NPR nodes and issue any remaining ELS PLOGIs */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state == NLP_STE_NPR_NODE && - (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && - (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 && - (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) { + test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag) && + !test_bit(NLP_DELAY_TMO, &ndlp->nlp_flag) && + !test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) { ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); @@ -7104,7 +7022,7 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context, lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2171 Xmit RDP response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x", + "did x%x, nlp_flag x%lx, nlp_state x%x, rpi x%x", elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -8078,7 +7996,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, */ if (vport->port_state <= LPFC_NS_QRY) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RSCN ignore: did:x%x/ste:x%x flg:x%x", + "RCV RSCN ignore: did:x%x/ste:x%x flg:x%lx", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); @@ -8108,7 +8026,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, vport->fc_flag, payload_len, *lp, vport->fc_rscn_id_cnt); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RSCN vport: did:x%x/ste:x%x flg:x%x", + "RCV RSCN vport: did:x%x/ste:x%x flg:x%lx", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); @@ -8145,7 +8063,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (test_bit(FC_RSCN_MODE, &vport->fc_flag) || test_bit(FC_NDISC_ACTIVE, &vport->fc_flag)) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RSCN defer: did:x%x/ste:x%x flg:x%x", + "RCV RSCN defer: did:x%x/ste:x%x flg:x%lx", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); set_bit(FC_RSCN_DEFERRED, &vport->fc_flag); @@ -8201,7 +8119,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 0; } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RSCN: did:x%x/ste:x%x flg:x%x", + "RCV RSCN: did:x%x/ste:x%x flg:x%lx", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); set_bit(FC_RSCN_MODE, &vport->fc_flag); @@ -8707,7 +8625,7 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Xmit ELS RLS ACC response tag */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, "2874 Xmit ELS RLS ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", + "did x%x, nlp_flag x%lx, nlp_state x%x, rpi x%x\n", elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -8869,7 +8787,7 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Xmit ELS RLS ACC response tag */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, "2875 Xmit ELS RTV ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x, " + "did x%x, nlp_flag x%lx, nlp_state x%x, rpi x%x, " "Data: x%x x%x x%x\n", elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, @@ -9066,7 +8984,7 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, /* Xmit ELS RPL ACC response tag */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0120 Xmit ELS RPL ACC response tag x%x " - "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, " + "xri x%x, did x%x, nlp_flag x%lx, nlp_state x%x, " "rpi x%x\n", elsiocb->iotag, ulp_context, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, @@ -9642,14 +9560,24 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) mbx_tmo_err = test_bit(MBX_TMO_ERR, &phba->bit_flags); /* First we need to issue aborts to outstanding cmds on txcmpl */ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { - if (piocb->cmd_flag & LPFC_IO_LIBDFC && !mbx_tmo_err) - continue; + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "2243 iotag = 0x%x cmd_flag = 0x%x " + "ulp_command = 0x%x this_vport %x " + "sli_flag = 0x%x\n", + piocb->iotag, piocb->cmd_flag, + get_job_cmnd(phba, piocb), + (piocb->vport == vport), + phba->sli.sli_flag); if (piocb->vport != vport) continue; - if (piocb->cmd_flag & LPFC_DRIVER_ABORTED && !mbx_tmo_err) - continue; + if ((phba->sli.sli_flag & LPFC_SLI_ACTIVE) && !mbx_tmo_err) { + if (piocb->cmd_flag & LPFC_IO_LIBDFC) + continue; + if (piocb->cmd_flag & LPFC_DRIVER_ABORTED) + continue; + } /* On the ELS ring we can have ELS_REQUESTs, ELS_RSPs, * or GEN_REQUESTs waiting for a CQE response. @@ -10411,14 +10339,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * Do not process any unsolicited ELS commands * if the ndlp is in DEV_LOSS */ - spin_lock_irq(&ndlp->lock); - if (ndlp->nlp_flag & NLP_IN_DEV_LOSS) { - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) { if (newnode) lpfc_nlp_put(ndlp); goto dropit; } - spin_unlock_irq(&ndlp->lock); elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) @@ -10447,7 +10372,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, switch (cmd) { case ELS_CMD_PLOGI: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV PLOGI: did:x%x/ste:x%x flg:x%x", + "RCV PLOGI: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvPLOGI++; @@ -10486,9 +10411,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_TARGET_REMOVE; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_TARGET_REMOVE, &ndlp->nlp_flag); lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PLOGI); @@ -10496,7 +10419,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_FLOGI: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FLOGI: did:x%x/ste:x%x flg:x%x", + "RCV FLOGI: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvFLOGI++; @@ -10523,7 +10446,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_LOGO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV LOGO: did:x%x/ste:x%x flg:x%x", + "RCV LOGO: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvLOGO++; @@ -10540,7 +10463,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_PRLO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV PRLO: did:x%x/ste:x%x flg:x%x", + "RCV PRLO: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvPRLO++; @@ -10569,7 +10492,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_ADISC: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV ADISC: did:x%x/ste:x%x flg:x%x", + "RCV ADISC: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); lpfc_send_els_event(vport, ndlp, payload); @@ -10584,7 +10507,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_PDISC: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV PDISC: did:x%x/ste:x%x flg:x%x", + "RCV PDISC: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvPDISC++; @@ -10598,7 +10521,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_FARPR: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FARPR: did:x%x/ste:x%x flg:x%x", + "RCV FARPR: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvFARPR++; @@ -10606,7 +10529,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_FARP: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FARP: did:x%x/ste:x%x flg:x%x", + "RCV FARP: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvFARP++; @@ -10614,7 +10537,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_FAN: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FAN: did:x%x/ste:x%x flg:x%x", + "RCV FAN: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvFAN++; @@ -10623,7 +10546,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, case ELS_CMD_PRLI: case ELS_CMD_NVMEPRLI: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV PRLI: did:x%x/ste:x%x flg:x%x", + "RCV PRLI: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvPRLI++; @@ -10637,7 +10560,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_LIRR: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV LIRR: did:x%x/ste:x%x flg:x%x", + "RCV LIRR: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvLIRR++; @@ -10648,7 +10571,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_RLS: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RLS: did:x%x/ste:x%x flg:x%x", + "RCV RLS: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvRLS++; @@ -10659,7 +10582,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_RPL: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RPL: did:x%x/ste:x%x flg:x%x", + "RCV RPL: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvRPL++; @@ -10670,7 +10593,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_RNID: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RNID: did:x%x/ste:x%x flg:x%x", + "RCV RNID: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvRNID++; @@ -10681,7 +10604,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_RTV: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RTV: did:x%x/ste:x%x flg:x%x", + "RCV RTV: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvRTV++; lpfc_els_rcv_rtv(vport, elsiocb, ndlp); @@ -10691,7 +10614,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_RRQ: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RRQ: did:x%x/ste:x%x flg:x%x", + "RCV RRQ: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvRRQ++; @@ -10702,7 +10625,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_ECHO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV ECHO: did:x%x/ste:x%x flg:x%x", + "RCV ECHO: did:x%x/ste:x%x flg:x%lx", did, vport->port_state, ndlp->nlp_flag); phba->fc_stat.elsRcvECHO++; @@ -10718,7 +10641,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; case ELS_CMD_FPIN: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FPIN: did:x%x/ste:x%x flg:x%x", + "RCV FPIN: did:x%x/ste:x%x " + "flg:x%lx", did, vport->port_state, ndlp->nlp_flag); lpfc_els_rcv_fpin(vport, (struct fc_els_fpin *)payload, @@ -11226,9 +11150,7 @@ lpfc_retry_pport_discovery(struct lpfc_hba *phba) return; mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; phba->pport->port_state = LPFC_FLOGI; return; @@ -11359,11 +11281,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, list_for_each_entry_safe(np, next_np, &vport->fc_nodes, nlp_listp) { if ((np->nlp_state != NLP_STE_NPR_NODE) || - !(np->nlp_flag & NLP_NPR_ADISC)) + !test_bit(NLP_NPR_ADISC, &np->nlp_flag)) continue; - spin_lock_irq(&ndlp->lock); - np->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NPR_ADISC, &np->nlp_flag); lpfc_unreg_rpi(vport, np); } lpfc_cleanup_pending_mbox(vport); @@ -11566,7 +11486,7 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* NPIV LOGO completes to NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "2928 NPIV LOGO completes to NPort x%x " - "Data: x%x x%x x%x x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%x x%x x%lx x%x\n", ndlp->nlp_DID, ulp_status, ulp_word4, tmo, vport->num_disc_nodes, kref_read(&ndlp->kref), ndlp->nlp_flag, @@ -11582,8 +11502,9 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Wake up lpfc_vport_delete if waiting...*/ if (ndlp->logo_waitq) wake_up(ndlp->logo_waitq); + clear_bit(NLP_ISSUE_LOGO, &ndlp->nlp_flag); + clear_bit(NLP_LOGO_SND, &ndlp->nlp_flag); spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_ISSUE_LOGO | NLP_LOGO_SND); ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO; spin_unlock_irq(&ndlp->lock); } @@ -11633,13 +11554,11 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name)); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue LOGO npiv did:x%x flg:x%x", + "Issue LOGO npiv did:x%x flg:x%lx", ndlp->nlp_DID, ndlp->nlp_flag, 0); elsiocb->cmd_cmpl = lpfc_cmpl_els_npiv_logo; - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_LOGO_SND; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_LOGO_SND, &ndlp->nlp_flag); elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) { lpfc_els_free_iocb(phba, elsiocb); @@ -11655,9 +11574,7 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) return 0; err: - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_LOGO_SND, &ndlp->nlp_flag); return 1; } @@ -12138,7 +12055,7 @@ lpfc_sli_abts_recover_port(struct lpfc_vport *vport, lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3094 Start rport recovery on shost id 0x%x " "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " - "flags 0x%x\n", + "flag 0x%lx\n", shost->host_no, ndlp->nlp_DID, vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state, ndlp->nlp_flag); @@ -12148,8 +12065,8 @@ lpfc_sli_abts_recover_port(struct lpfc_vport *vport, */ spin_lock_irqsave(&ndlp->lock, flags); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - ndlp->nlp_flag |= NLP_ISSUE_LOGO; spin_unlock_irqrestore(&ndlp->lock, flags); + set_bit(NLP_ISSUE_LOGO, &ndlp->nlp_flag); lpfc_unreg_rpi(vport, ndlp); } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 9241075f72fa4b..4036a9838bb594 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -100,6 +100,12 @@ lpfc_rport_invalid(struct fc_rport *rport) return -EINVAL; } + if (rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) { + pr_info("**** %s: devloss_callbk_done rport x%px SID x%x\n", + __func__, rport, rport->scsi_target_id); + return -EINVAL; + } + rdata = rport->dd_data; if (!rdata) { pr_err("**** %s: NULL dd_data on rport x%px SID x%x\n", @@ -137,7 +143,7 @@ lpfc_terminate_rport_io(struct fc_rport *rport) ndlp = rdata->pnode; vport = ndlp->vport; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport terminate: sid:x%x did:x%x flg:x%x", + "rport terminate: sid:x%x did:x%x flg:x%lx", ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); if (ndlp->nlp_sid != NLP_NO_SID) @@ -155,6 +161,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) struct lpfc_hba *phba; struct lpfc_work_evt *evtp; unsigned long iflags; + bool nvme_reg = false; ndlp = ((struct lpfc_rport_data *)rport->dd_data)->pnode; if (!ndlp) @@ -164,11 +171,11 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) phba = vport->phba; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport devlosscb: sid:x%x did:x%x flg:x%x", + "rport devlosscb: sid:x%x did:x%x flg:x%lx", ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3181 dev_loss_callbk x%06x, rport x%px flg x%x " + "3181 dev_loss_callbk x%06x, rport x%px flg x%lx " "load_flag x%lx refcnt %u state %d xpt x%x\n", ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag, vport->load_flag, kref_read(&ndlp->kref), @@ -177,38 +184,44 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) /* Don't schedule a worker thread event if the vport is going down. */ if (test_bit(FC_UNLOADING, &vport->load_flag) || !test_bit(HBA_SETUP, &phba->hba_flag)) { + spin_lock_irqsave(&ndlp->lock, iflags); ndlp->rport = NULL; + if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) + nvme_reg = true; + /* The scsi_transport is done with the rport so lpfc cannot - * call to unregister. Remove the scsi transport reference - * and clean up the SCSI transport node details. + * call to unregister. */ - if (ndlp->fc4_xpt_flags & (NLP_XPT_REGD | SCSI_XPT_REGD)) { + if (ndlp->fc4_xpt_flags & SCSI_XPT_REGD) { ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD; - /* NVME transport-registered rports need the - * NLP_XPT_REGD flag to complete an unregister. + /* If NLP_XPT_REGD was cleared in lpfc_nlp_unreg_node, + * unregister calls were made to the scsi and nvme + * transports and refcnt was already decremented. Clear + * the NLP_XPT_REGD flag only if the NVME Rport is + * confirmed unregistered. */ - if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) + if (!nvme_reg && ndlp->fc4_xpt_flags & NLP_XPT_REGD) { ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD; + spin_unlock_irqrestore(&ndlp->lock, iflags); + lpfc_nlp_put(ndlp); /* may free ndlp */ + } else { + spin_unlock_irqrestore(&ndlp->lock, iflags); + } + } else { spin_unlock_irqrestore(&ndlp->lock, iflags); - lpfc_nlp_put(ndlp); - spin_lock_irqsave(&ndlp->lock, iflags); } /* Only 1 thread can drop the initial node reference. If * another thread has set NLP_DROPPED, this thread is done. */ - if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD) && - !(ndlp->nlp_flag & NLP_DROPPED)) { - ndlp->nlp_flag |= NLP_DROPPED; - spin_unlock_irqrestore(&ndlp->lock, iflags); - lpfc_nlp_put(ndlp); + if (nvme_reg || test_bit(NLP_DROPPED, &ndlp->nlp_flag)) return; - } - spin_unlock_irqrestore(&ndlp->lock, iflags); + set_bit(NLP_DROPPED, &ndlp->nlp_flag); + lpfc_nlp_put(ndlp); return; } @@ -235,14 +248,14 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) return; } - spin_lock_irqsave(&ndlp->lock, iflags); - ndlp->nlp_flag |= NLP_IN_DEV_LOSS; + set_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag); + spin_lock_irqsave(&ndlp->lock, iflags); /* If there is a PLOGI in progress, and we are in a * NLP_NPR_2B_DISC state, don't turn off the flag. */ if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE) - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); /* * The backend does not expect any more calls associated with this @@ -271,15 +284,13 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) } else { lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "3188 worker thread is stopped %s x%06x, " - " rport x%px flg x%x load_flag x%lx refcnt " + " rport x%px flg x%lx load_flag x%lx refcnt " "%d\n", __func__, ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag, vport->load_flag, kref_read(&ndlp->kref)); if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) { - spin_lock_irqsave(&ndlp->lock, iflags); /* Node is in dev loss. No further transaction. */ - ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(&ndlp->lock, iflags); + clear_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag); lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); } @@ -412,7 +423,7 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, lpfc_nlp_get(ndlp); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, "8438 Devloss timeout reversed on DID x%x " - "refcnt %d ndlp %p flag x%x " + "refcnt %d ndlp %p flag x%lx " "port_state = x%x\n", ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp, ndlp->nlp_flag, vport->port_state); @@ -455,7 +466,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_sid); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3182 %s x%06x, nflag x%x xflags x%x refcnt %d\n", + "3182 %s x%06x, nflag x%lx xflags x%x refcnt %d\n", __func__, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->fc4_xpt_flags, kref_read(&ndlp->kref)); @@ -469,9 +480,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID); - spin_lock_irqsave(&ndlp->lock, iflags); - ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(&ndlp->lock, iflags); + clear_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag); return fcf_inuse; } @@ -499,7 +508,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) } break; case Fabric_Cntl_DID: - if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) + if (test_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag)) recovering = true; break; case FDMI_DID: @@ -527,15 +536,13 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) * the following lpfc_nlp_put is necessary after fabric node is * recovered. */ - spin_lock_irqsave(&ndlp->lock, iflags); - ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(&ndlp->lock, iflags); + clear_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag); if (recovering) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_NODE, "8436 Devloss timeout marked on " "DID x%x refcnt %d ndlp %p " - "flag x%x port_state = x%x\n", + "flag x%lx port_state = x%x\n", ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp, ndlp->nlp_flag, vport->port_state); @@ -552,7 +559,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) LOG_DISCOVERY | LOG_NODE, "8437 Devloss timeout ignored on " "DID x%x refcnt %d ndlp %p " - "flag x%x port_state = x%x\n", + "flag x%lx port_state = x%x\n", ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp, ndlp->nlp_flag, vport->port_state); @@ -572,7 +579,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0203 Devloss timeout on " "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " - "NPort x%06x Data: x%x x%x x%x refcnt %d\n", + "NPort x%06x Data: x%lx x%x x%x refcnt %d\n", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID, ndlp->nlp_flag, @@ -582,15 +589,13 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_INFO, LOG_TRACE_EVENT, "0204 Devloss timeout on " "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " - "NPort x%06x Data: x%x x%x x%x\n", + "NPort x%06x Data: x%lx x%x x%x\n", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); } - spin_lock_irqsave(&ndlp->lock, iflags); - ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; - spin_unlock_irqrestore(&ndlp->lock, iflags); + clear_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag); /* If we are devloss, but we are in the process of rediscovering the * ndlp, don't issue a NLP_EVT_DEVICE_RM event. @@ -1355,7 +1360,7 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) if (ndlp->nlp_DID != Fabric_DID) lpfc_unreg_rpi(vport, ndlp); lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { + } else if (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) { /* Fail outstanding IO now since device is * marked for PLOGI. */ @@ -3864,14 +3869,13 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) pmb->ctx_ndlp = NULL; lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI | LOG_NODE | LOG_DISCOVERY, - "0002 rpi:%x DID:%x flg:%x %d x%px\n", + "0002 rpi:%x DID:%x flg:%lx %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp); - if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + clear_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); - if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL || + if (test_bit(NLP_IGNR_REG_CMPL, &ndlp->nlp_flag) || ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) { /* We rcvd a rscn after issuing this * mbox reg login, we may have cycled @@ -3881,16 +3885,14 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * there is another reg login in * process. */ - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_IGNR_REG_CMPL, &ndlp->nlp_flag); /* * We cannot leave the RPI registered because * if we go thru discovery again for this ndlp * a subsequent REG_RPI will fail. */ - ndlp->nlp_flag |= NLP_RPI_REGISTERED; + set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); lpfc_unreg_rpi(vport, ndlp); } @@ -4203,7 +4205,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->sli_rev < LPFC_SLI_REV4) ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; + set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); @@ -4334,9 +4336,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * reference. */ if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); } @@ -4357,11 +4357,11 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->sli_rev < LPFC_SLI_REV4) ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; + set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, - "0003 rpi:%x DID:%x flg:%x %d x%px\n", + "0003 rpi:%x DID:%x flg:%lx %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp); @@ -4453,8 +4453,8 @@ lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) __func__, ndlp->nlp_DID, ndlp->nlp_rpi, ndlp->nlp_state); - ndlp->nlp_flag |= NLP_RPI_REGISTERED; - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); + clear_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); @@ -4488,7 +4488,7 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport add: did:x%x flg:x%x type x%x", + "rport add: did:x%x flg:x%lx type x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); /* Don't add the remote port if unloading. */ @@ -4556,7 +4556,7 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) return; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport delete: did:x%x flg:x%x type x%x", + "rport delete: did:x%x flg:x%lx type x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, @@ -4672,7 +4672,7 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_NODE | LOG_DISCOVERY, "0999 %s Not regd: ndlp x%px rport x%px DID " - "x%x FLG x%x XPT x%x\n", + "x%x FLG x%lx XPT x%x\n", __func__, ndlp, ndlp->rport, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->fc4_xpt_flags); return; @@ -4688,7 +4688,7 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) } else if (!ndlp->rport) { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_NODE | LOG_DISCOVERY, - "1999 %s NDLP in devloss x%px DID x%x FLG x%x" + "1999 %s NDLP in devloss x%px DID x%x FLG x%lx" " XPT x%x refcnt %u\n", __func__, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->fc4_xpt_flags, @@ -4733,7 +4733,7 @@ lpfc_handle_adisc_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_type |= NLP_FC_NODE; fallthrough; case NLP_STE_MAPPED_NODE: - ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); lpfc_nlp_reg_node(vport, ndlp); break; @@ -4744,7 +4744,7 @@ lpfc_handle_adisc_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * backend, attempt it now */ case NLP_STE_NPR_NODE: - ndlp->nlp_flag &= ~NLP_RCV_PLOGI; + clear_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag); fallthrough; default: lpfc_nlp_unreg_node(vport, ndlp); @@ -4765,13 +4765,13 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } if (new_state == NLP_STE_UNMAPPED_NODE) { - ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); ndlp->nlp_type |= NLP_FC_NODE; } if (new_state == NLP_STE_MAPPED_NODE) - ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); if (new_state == NLP_STE_NPR_NODE) - ndlp->nlp_flag &= ~NLP_RCV_PLOGI; + clear_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag); /* Reg/Unreg for FCP and NVME Transport interface */ if ((old_state == NLP_STE_MAPPED_NODE || @@ -4779,7 +4779,7 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* For nodes marked for ADISC, Handle unreg in ADISC cmpl * if linkup. In linkdown do unreg_node */ - if (!(ndlp->nlp_flag & NLP_NPR_ADISC) || + if (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag) || !lpfc_is_link_up(vport->phba)) lpfc_nlp_unreg_node(vport, ndlp); } @@ -4799,9 +4799,7 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, (!ndlp->rport || ndlp->rport->scsi_target_id == -1 || ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_TGT_NO_SCSIID; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_TGT_NO_SCSIID, &ndlp->nlp_flag); lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } } @@ -4833,7 +4831,7 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int state) { int old_state = ndlp->nlp_state; - int node_dropped = ndlp->nlp_flag & NLP_DROPPED; + bool node_dropped = test_bit(NLP_DROPPED, &ndlp->nlp_flag); char name1[16], name2[16]; unsigned long iflags; @@ -4849,7 +4847,7 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (node_dropped && old_state == NLP_STE_UNUSED_NODE && state != NLP_STE_UNUSED_NODE) { - ndlp->nlp_flag &= ~NLP_DROPPED; + clear_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_get(ndlp); } @@ -4857,7 +4855,7 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, state != NLP_STE_NPR_NODE) lpfc_cancel_retry_delay_tmo(vport, ndlp); if (old_state == NLP_STE_UNMAPPED_NODE) { - ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID; + clear_bit(NLP_TGT_NO_SCSIID, &ndlp->nlp_flag); ndlp->nlp_type &= ~NLP_FC_NODE; } @@ -4954,14 +4952,8 @@ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * reference from lpfc_nlp_init. If set, don't drop it again and * introduce an imbalance. */ - spin_lock_irq(&ndlp->lock); - if (!(ndlp->nlp_flag & NLP_DROPPED)) { - ndlp->nlp_flag |= NLP_DROPPED; - spin_unlock_irq(&ndlp->lock); + if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) lpfc_nlp_put(ndlp); - return; - } - spin_unlock_irq(&ndlp->lock); } /* @@ -5076,9 +5068,9 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, } else if (pring->ringno == LPFC_FCP_RING) { /* Skip match check if waiting to relogin to FCP target */ if ((ndlp->nlp_type & NLP_FCP_TARGET) && - (ndlp->nlp_flag & NLP_DELAY_TMO)) { + test_bit(NLP_DELAY_TMO, &ndlp->nlp_flag)) return 0; - } + if (ulp_context == ndlp->nlp_rpi) return 1; } @@ -5148,7 +5140,7 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) * Everything that matches on txcmplq will be returned * by firmware with a no rpi error. */ - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { + if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) { if (phba->sli_rev != LPFC_SLI_REV4) lpfc_sli3_dequeue_nport_iocbs(phba, ndlp, &completions); else @@ -5182,29 +5174,19 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_issue_els_logo(vport, ndlp, 0); /* Check to see if there are any deferred events to process */ - if ((ndlp->nlp_flag & NLP_UNREG_INP) && - (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { + if (test_bit(NLP_UNREG_INP, &ndlp->nlp_flag) && + ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "1434 UNREG cmpl deferred logo x%x " "on NPort x%x Data: x%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp); - ndlp->nlp_flag &= ~NLP_UNREG_INP; + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); } else { - /* NLP_RELEASE_RPI is only set for SLI4 ports. */ - if (ndlp->nlp_flag & NLP_RELEASE_RPI) { - lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_RELEASE_RPI; - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - spin_unlock_irq(&ndlp->lock); - } - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_UNREG_INP; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); } /* The node has an outstanding reference for the unreg. Now @@ -5224,8 +5206,6 @@ static void lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox) { - unsigned long iflags; - /* Driver always gets a reference on the mailbox job * in support of async jobs. */ @@ -5233,9 +5213,8 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, if (!mbox->ctx_ndlp) return; - if (ndlp->nlp_flag & NLP_ISSUE_LOGO) { + if (test_bit(NLP_ISSUE_LOGO, &ndlp->nlp_flag)) { mbox->mbox_cmpl = lpfc_nlp_logo_unreg; - } else if (phba->sli_rev == LPFC_SLI_REV4 && !test_bit(FC_UNLOADING, &vport->load_flag) && (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= @@ -5243,13 +5222,6 @@ lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, (kref_read(&ndlp->kref) > 0)) { mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr; } else { - if (test_bit(FC_UNLOADING, &vport->load_flag)) { - if (phba->sli_rev == LPFC_SLI_REV4) { - spin_lock_irqsave(&ndlp->lock, iflags); - ndlp->nlp_flag |= NLP_RELEASE_RPI; - spin_unlock_irqrestore(&ndlp->lock, iflags); - } - } mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } } @@ -5271,13 +5243,13 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) int rc, acc_plogi = 1; uint16_t rpi; - if (ndlp->nlp_flag & NLP_RPI_REGISTERED || - ndlp->nlp_flag & NLP_REG_LOGIN_SEND) { - if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) + if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag) || + test_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag)) { + if (test_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag)) lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "3366 RPI x%x needs to be " - "unregistered nlp_flag x%x " + "unregistered nlp_flag x%lx " "did x%x\n", ndlp->nlp_rpi, ndlp->nlp_flag, ndlp->nlp_DID); @@ -5285,11 +5257,11 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* If there is already an UNREG in progress for this ndlp, * no need to queue up another one. */ - if (ndlp->nlp_flag & NLP_UNREG_INP) { + if (test_bit(NLP_UNREG_INP, &ndlp->nlp_flag)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "1436 unreg_rpi SKIP UNREG x%x on " - "NPort x%x deferred x%x flg x%x " + "NPort x%x deferred x%x flg x%lx " "Data: x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, @@ -5312,27 +5284,24 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) return 1; } + /* Accept PLOGIs after unreg_rpi_cmpl. */ if (mbox->mbox_cmpl == lpfc_sli4_unreg_rpi_cmpl_clr) - /* - * accept PLOGIs after unreg_rpi_cmpl - */ acc_plogi = 0; - if (((ndlp->nlp_DID & Fabric_DID_MASK) != - Fabric_DID_MASK) && - (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag))) - ndlp->nlp_flag |= NLP_UNREG_INP; + + if (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag)) + set_bit(NLP_UNREG_INP, &ndlp->nlp_flag); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "1433 unreg_rpi UNREG x%x on " - "NPort x%x deferred flg x%x " + "NPort x%x deferred flg x%lx " "Data:x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, ndlp); rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - ndlp->nlp_flag &= ~NLP_UNREG_INP; + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); mempool_free(mbox, phba->mbox_mem_pool); acc_plogi = 1; lpfc_nlp_put(ndlp); @@ -5342,7 +5311,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) LOG_NODE | LOG_DISCOVERY, "1444 Failed to allocate mempool " "unreg_rpi UNREG x%x, " - "DID x%x, flag x%x, " + "DID x%x, flag x%lx, " "ndlp x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, ndlp); @@ -5352,7 +5321,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * not unloading. */ if (!test_bit(FC_UNLOADING, &vport->load_flag)) { - ndlp->nlp_flag &= ~NLP_UNREG_INP; + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); lpfc_issue_els_logo(vport, ndlp, 0); ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, @@ -5365,13 +5334,13 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) out: if (phba->sli_rev != LPFC_SLI_REV4) ndlp->nlp_rpi = 0; - ndlp->nlp_flag &= ~NLP_RPI_REGISTERED; - ndlp->nlp_flag &= ~NLP_NPR_ADISC; + clear_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); if (acc_plogi) - ndlp->nlp_flag &= ~NLP_LOGO_ACC; + clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); return 1; } - ndlp->nlp_flag &= ~NLP_LOGO_ACC; + clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); return 0; } @@ -5399,7 +5368,7 @@ lpfc_unreg_hba_rpis(struct lpfc_hba *phba) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { spin_lock_irqsave(&vports[i]->fc_nodes_list_lock, iflags); list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { + if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) { /* The mempool_alloc might sleep */ spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags); @@ -5487,7 +5456,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* Cleanup node for NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "0900 Cleanup node for NPort x%x " - "Data: x%x x%x x%x\n", + "Data: x%lx x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); lpfc_dequeue_node(vport, ndlp); @@ -5532,9 +5501,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_els_abort(phba, ndlp); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = 0; del_timer_sync(&ndlp->nlp_delayfunc); @@ -5543,10 +5510,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) list_del_init(&ndlp->dev_loss_evt.evt_listp); list_del_init(&ndlp->recovery_evt.evt_listp); lpfc_cleanup_vports_rrqs(vport, ndlp); - - if (phba->sli_rev == LPFC_SLI_REV4) - ndlp->nlp_flag |= NLP_RELEASE_RPI; - return 0; } @@ -5620,7 +5583,7 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) ); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE_VERBOSE, "0929 FIND node DID " - "Data: x%px x%x x%x x%x x%x x%px\n", + "Data: x%px x%x x%lx x%x x%x x%px\n", ndlp, ndlp->nlp_DID, ndlp->nlp_flag, data1, ndlp->nlp_rpi, ndlp->active_rrqs_xri_bitmap); @@ -5667,7 +5630,7 @@ lpfc_findnode_mapped(struct lpfc_vport *vport) iflags); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE_VERBOSE, "2025 FIND node DID MAPPED " - "Data: x%px x%x x%x x%x x%px\n", + "Data: x%px x%x x%lx x%x x%px\n", ndlp, ndlp->nlp_DID, ndlp->nlp_flag, data1, ndlp->active_rrqs_xri_bitmap); @@ -5701,13 +5664,11 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6453 Setup New Node 2B_DISC x%x " - "Data:x%x x%x x%lx\n", + "Data:x%lx x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); return ndlp; } @@ -5726,7 +5687,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6455 Setup RSCN Node 2B_DISC x%x " - "Data:x%x x%x x%lx\n", + "Data:x%lx x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); @@ -5744,13 +5705,11 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) NLP_EVT_DEVICE_RECOVERY); } - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6456 Skip Setup RSCN Node x%x " - "Data:x%x x%x x%lx\n", + "Data:x%lx x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); ndlp = NULL; @@ -5758,7 +5717,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "6457 Setup Active Node 2B_DISC x%x " - "Data:x%x x%x x%lx\n", + "Data:x%lx x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, vport->fc_flag); @@ -5769,7 +5728,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || (!vport->phba->nvmet_support && - ndlp->nlp_flag & NLP_RCV_PLOGI)) + test_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag))) return NULL; if (vport->phba->nvmet_support) @@ -5779,10 +5738,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) * allows for rediscovery */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); } return ndlp; } @@ -6153,7 +6109,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) /* Clean up the ndlp on Fabric connections */ lpfc_drop_node(vport, ndlp); - } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { + } else if (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) { /* Fail outstanding IO now since device * is marked for PLOGI. */ @@ -6366,11 +6322,11 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->sli_rev < LPFC_SLI_REV4) ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; + set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, - "0004 rpi:%x DID:%x flg:%x %d x%px\n", + "0004 rpi:%x DID:%x flg:%lx %d x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp); @@ -6420,7 +6376,7 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) if (filter(ndlp, param)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE_VERBOSE, "3185 FIND node filter %ps DID " - "ndlp x%px did x%x flg x%x st x%x " + "ndlp x%px did x%x flg x%lx st x%x " "xri x%x type x%x rpi x%x\n", filter, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, @@ -6555,9 +6511,10 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) INIT_LIST_HEAD(&ndlp->nlp_listp); if (vport->phba->sli_rev == LPFC_SLI_REV4) { ndlp->nlp_rpi = rpi; - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, - "0007 Init New ndlp x%px, rpi:x%x DID:%x " - "flg:x%x refcnt:%d\n", + lpfc_printf_vlog(vport, KERN_INFO, + LOG_ELS | LOG_NODE | LOG_DISCOVERY, + "0007 Init New ndlp x%px, rpi:x%x DID:x%x " + "flg:x%lx refcnt:%d\n", ndlp, ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); @@ -6589,7 +6546,7 @@ lpfc_nlp_release(struct kref *kref) struct lpfc_vport *vport = ndlp->vport; lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node release: did:x%x flg:x%x type:x%x", + "node release: did:x%x flg:x%lx type:x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, @@ -6601,19 +6558,12 @@ lpfc_nlp_release(struct kref *kref) lpfc_cancel_retry_delay_tmo(vport, ndlp); lpfc_cleanup_node(vport, ndlp); - /* Not all ELS transactions have registered the RPI with the port. - * In these cases the rpi usage is temporary and the node is - * released when the WQE is completed. Catch this case to free the - * RPI to the pool. Because this node is in the release path, a lock - * is unnecessary. All references are gone and the node has been - * dequeued. + /* All nodes are initialized with an RPI that needs to be released + * now. All references are gone and the node has been dequeued. */ - if (ndlp->nlp_flag & NLP_RELEASE_RPI) { - if (ndlp->nlp_rpi != LPFC_RPI_ALLOC_ERROR && - !(ndlp->nlp_flag & (NLP_RPI_REGISTERED | NLP_UNREG_INP))) { - lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - } + if (vport->phba->sli_rev == LPFC_SLI_REV4) { + lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; } /* The node is not freed back to memory, it is released to a pool so @@ -6642,7 +6592,7 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) if (ndlp) { lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node get: did:x%x flg:x%x refcnt:x%x", + "node get: did:x%x flg:x%lx refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); @@ -6674,7 +6624,7 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) { if (ndlp) { lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node put: did:x%x flg:x%x refcnt:x%x", + "node put: did:x%x flg:x%lx refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref)); } else { @@ -6727,11 +6677,12 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) spin_unlock_irqrestore(&vports[i]->fc_nodes_list_lock, iflags); goto out; - } else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { + } else if (test_bit(NLP_RPI_REGISTERED, + &ndlp->nlp_flag)) { ret = 1; lpfc_printf_log(phba, KERN_INFO, LOG_NODE | LOG_DISCOVERY, - "2624 RPI %x DID %x flag %x " + "2624 RPI %x DID %x flag %lx " "still logged in\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 0dd451009b0791..7f57397d91a90d 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1943,6 +1943,7 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, lpfc_offline_prep(phba, mbx_action); lpfc_sli_flush_io_rings(phba); + lpfc_nvmels_flush_cmd(phba); lpfc_offline(phba); /* release interrupt for possible resource change */ lpfc_sli4_disable_intr(phba); @@ -3092,7 +3093,8 @@ lpfc_cleanup(struct lpfc_vport *vport) lpfc_printf_vlog(ndlp->vport, KERN_ERR, LOG_DISCOVERY, "0282 did:x%x ndlp:x%px " - "refcnt:%d xflags x%x nflag x%x\n", + "refcnt:%d xflags x%x " + "nflag x%lx\n", ndlp->nlp_DID, (void *)ndlp, kref_read(&ndlp->kref), ndlp->fc4_xpt_flags, @@ -3379,7 +3381,7 @@ lpfc_block_mgmt_io(struct lpfc_hba *phba, int mbx_action) } /** - * lpfc_sli4_node_prep - Assign RPIs for active nodes. + * lpfc_sli4_node_rpi_restore - Recover assigned RPIs for active nodes. * @phba: pointer to lpfc hba data structure. * * Allocate RPIs for all active remote nodes. This is needed whenever @@ -3387,7 +3389,7 @@ lpfc_block_mgmt_io(struct lpfc_hba *phba, int mbx_action) * is to fixup the temporary rpi assignments. **/ void -lpfc_sli4_node_prep(struct lpfc_hba *phba) +lpfc_sli4_node_rpi_restore(struct lpfc_hba *phba) { struct lpfc_nodelist *ndlp, *next_ndlp; struct lpfc_vport **vports; @@ -3397,10 +3399,10 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) return; vports = lpfc_create_vport_work_array(phba); - if (vports == NULL) + if (!vports) return; - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + for (i = 0; i <= phba->max_vports && vports[i]; i++) { if (test_bit(FC_UNLOADING, &vports[i]->load_flag)) continue; @@ -3409,14 +3411,20 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) nlp_listp) { rpi = lpfc_sli4_alloc_rpi(phba); if (rpi == LPFC_RPI_ALLOC_ERROR) { - /* TODO print log? */ + lpfc_printf_vlog(ndlp->vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0099 RPI alloc error for " + "ndlp x%px DID:x%06x " + "flg:x%lx\n", + ndlp, ndlp->nlp_DID, + ndlp->nlp_flag); continue; } ndlp->nlp_rpi = rpi; lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0009 Assign RPI x%x to ndlp x%px " - "DID:x%06x flg:x%x\n", + "DID:x%06x flg:x%lx\n", ndlp->nlp_rpi, ndlp, ndlp->nlp_DID, ndlp->nlp_flag); } @@ -3820,35 +3828,12 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) &vports[i]->fc_nodes, nlp_listp) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); - + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); if (offline || hba_pci_err) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_UNREG_INP | - NLP_RPI_REGISTERED); - spin_unlock_irq(&ndlp->lock); - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli_rpi_release(vports[i], - ndlp); - } else { - lpfc_unreg_rpi(vports[i], ndlp); - } - /* - * Whenever an SLI4 port goes offline, free the - * RPI. Get a new RPI when the adapter port - * comes back online. - */ - if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_printf_vlog(vports[i], KERN_INFO, - LOG_NODE | LOG_DISCOVERY, - "0011 Free RPI x%x on " - "ndlp: x%px did x%x\n", - ndlp->nlp_rpi, ndlp, - ndlp->nlp_DID); - lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; + clear_bit(NLP_UNREG_INP, + &ndlp->nlp_flag); + clear_bit(NLP_RPI_REGISTERED, + &ndlp->nlp_flag); } if (ndlp->nlp_type & NLP_FABRIC) { @@ -6925,9 +6910,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_FDISC; vport->port_state = LPFC_FDISC; } else { @@ -13518,6 +13501,8 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) /* Disable FW logging to host memory */ lpfc_ras_stop_fwlog(phba); + lpfc_sli4_queue_unset(phba); + /* Reset SLI4 HBA FCoE function */ lpfc_pci_function_reset(phba); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 4574716c8764fb..4d88cfe71caed3 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -65,7 +65,7 @@ lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_name *nn, struct lpfc_name *pn) { /* First, we MUST have a RPI registered */ - if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) + if (!test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) return 0; /* Compare the ADISC rsp WWNN / WWPN matches our internal node @@ -239,7 +239,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) /* Abort outstanding I/O on NPort */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY, "2819 Abort outstanding I/O on NPort x%x " - "Data: x%x x%x x%x\n", + "Data: x%lx x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); /* Clean up all fabric IOs first.*/ @@ -340,7 +340,7 @@ lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox) /* Now process the REG_RPI cmpl */ lpfc_mbx_cmpl_reg_login(phba, login_mbox); - ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN; + clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); kfree(save_iocb); } @@ -404,7 +404,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* PLOGI chkparm OK */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0114 PLOGI chkparm OK Data: x%x x%x x%x " + "0114 PLOGI chkparm OK Data: x%x x%x x%lx " "x%x x%x x%lx\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi, vport->port_state, @@ -429,7 +429,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* if already logged in, do implicit logout */ switch (ndlp->nlp_state) { case NLP_STE_NPR_NODE: - if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) + if (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) break; fallthrough; case NLP_STE_REG_LOGIN_ISSUE: @@ -449,7 +449,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; - ndlp->nlp_flag &= ~NLP_FIRSTBURST; + clear_bit(NLP_FIRSTBURST, &ndlp->nlp_flag); lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); @@ -480,7 +480,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; - ndlp->nlp_flag &= ~NLP_FIRSTBURST; + clear_bit(NLP_FIRSTBURST, &ndlp->nlp_flag); login_mbox = NULL; link_mbox = NULL; @@ -552,13 +552,13 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_can_disctmo(vport); } - ndlp->nlp_flag &= ~NLP_SUPPRESS_RSP; + clear_bit(NLP_SUPPRESS_RSP, &ndlp->nlp_flag); if ((phba->sli.sli_flag & LPFC_SLI_SUPPRESS_RSP) && sp->cmn.valid_vendor_ver_level) { vid = be32_to_cpu(sp->un.vv.vid); flag = be32_to_cpu(sp->un.vv.flags); if ((vid == LPFC_VV_EMLX_ID) && (flag & LPFC_VV_SUPPRESS_RSP)) - ndlp->nlp_flag |= NLP_SUPPRESS_RSP; + set_bit(NLP_SUPPRESS_RSP, &ndlp->nlp_flag); } login_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -627,10 +627,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * this ELS request. The only way to do this is * to register, then unregister the RPI. */ - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= (NLP_RM_DFLT_RPI | NLP_ACC_REGLOGIN | - NLP_RCV_PLOGI); - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_RM_DFLT_RPI, &ndlp->nlp_flag); + set_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); + set_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag); } stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD; @@ -665,9 +664,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, login_mbox->ctx_u.save_iocb = save_iocb; /* For PLOGI ACC */ - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); + set_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag); /* Start the ball rolling by issuing REG_LOGIN here */ rc = lpfc_sli_issue_mbox(phba, login_mbox, MBX_NOWAIT); @@ -797,7 +795,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) { if ((ndlp->nlp_state != NLP_STE_MAPPED_NODE) && - !(ndlp->nlp_flag & NLP_NPR_ADISC)) + !test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); } @@ -814,9 +812,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* 1 sec timeout */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -835,9 +831,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary * PLOGIs during LOGO storms from a device. */ - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); if (els_cmd == ELS_CMD_PRLO) lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); else @@ -890,9 +884,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_FDISC; vport->port_state = LPFC_FDISC; } else { @@ -915,14 +907,12 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_state <= NLP_STE_PRLI_ISSUE)) { mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_ELS | LOG_DISCOVERY, "3204 Start nlpdelay on DID x%06x " - "nflag x%x lastels x%x ref cnt %u", + "nflag x%lx lastels x%x ref cnt %u", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_last_elscmd, kref_read(&ndlp->kref)); @@ -935,9 +925,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); /* The driver has to wait until the ACC completes before it continues * processing the LOGO. The action will resume in * lpfc_cmpl_els_logo_acc routine. Since part of processing includes an @@ -978,7 +966,7 @@ lpfc_rcv_prli_support_check(struct lpfc_vport *vport, out: lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY, "6115 Rcv PRLI (%x) check failed: ndlp rpi %d " - "state x%x flags x%x port_type: x%x " + "state x%x flags x%lx port_type: x%x " "npr->initfcn: x%x npr->tgtfcn: x%x\n", cmd, ndlp->nlp_rpi, ndlp->nlp_state, ndlp->nlp_flag, vport->port_type, @@ -1020,7 +1008,7 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (npr->prliType == PRLI_NVME_TYPE) ndlp->nlp_type |= NLP_NVME_TARGET; if (npr->writeXferRdyDis) - ndlp->nlp_flag |= NLP_FIRSTBURST; + set_bit(NLP_FIRSTBURST, &ndlp->nlp_flag); } if (npr->Retry && ndlp->nlp_type & (NLP_FCP_INITIATOR | NLP_FCP_TARGET)) @@ -1057,7 +1045,7 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, roles |= FC_RPORT_ROLE_FCP_TARGET; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport rolechg: role:x%x did:x%x flg:x%x", + "rport rolechg: role:x%x did:x%x flg:x%lx", roles, ndlp->nlp_DID, ndlp->nlp_flag); if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME) @@ -1068,10 +1056,8 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, static uint32_t lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); + if (!test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) { + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); return 0; } @@ -1081,16 +1067,12 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) (test_bit(FC_RSCN_MODE, &vport->fc_flag) || ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && (ndlp->nlp_type & NLP_FCP_TARGET)))) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); return 1; } } - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); lpfc_unreg_rpi(vport, ndlp); return 0; } @@ -1115,10 +1097,10 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, /* If there is already an UNREG in progress for this ndlp, * no need to queue up another one. */ - if (ndlp->nlp_flag & NLP_UNREG_INP) { + if (test_bit(NLP_UNREG_INP, &ndlp->nlp_flag)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "1435 release_rpi SKIP UNREG x%x on " - "NPort x%x deferred x%x flg x%x " + "NPort x%x deferred x%x flg x%lx " "Data: x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, @@ -1143,11 +1125,11 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && (!test_bit(FC_OFFLINE_MODE, &vport->fc_flag))) - ndlp->nlp_flag |= NLP_UNREG_INP; + set_bit(NLP_UNREG_INP, &ndlp->nlp_flag); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "1437 release_rpi UNREG x%x " - "on NPort x%x flg x%x\n", + "on NPort x%x flg x%lx\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); @@ -1175,7 +1157,7 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0271 Illegal State Transition: node x%x " - "event x%x, state x%x Data: x%x x%x\n", + "event x%x, state x%x Data: x%x x%lx\n", ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, ndlp->nlp_flag); return ndlp->nlp_state; @@ -1190,13 +1172,12 @@ lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * working on the same NPortID, do nothing for this thread * to stop it. */ - if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { + if (!test_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag)) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0272 Illegal State Transition: node x%x " - "event x%x, state x%x Data: x%x x%x\n", + "event x%x, state x%x Data: x%x x%lx\n", ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, ndlp->nlp_flag); - } return ndlp->nlp_state; } @@ -1230,9 +1211,7 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return ndlp->nlp_state; @@ -1290,11 +1269,9 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, NULL); } else { if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) && - (ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (vport->num_disc_nodes)) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag) && + vport->num_disc_nodes) { + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); /* Check if there are more PLOGIs to be sent */ lpfc_more_plogi(vport); if (vport->num_disc_nodes == 0) { @@ -1356,9 +1333,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Put ndlp in npr state set plogi timer for 1 sec */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); @@ -1389,7 +1364,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ulp_status = get_job_ulpstatus(phba, rspiocb); - if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { + if (test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag)) { /* Recovery from PLOGI collision logic */ return ndlp->nlp_state; } @@ -1418,7 +1393,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, goto out; /* PLOGI chkparm OK */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0121 PLOGI chkparm OK Data: x%x x%x x%x x%x\n", + "0121 PLOGI chkparm OK Data: x%x x%x x%lx x%x\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi); if (vport->cfg_fcp_class == 2 && (sp->cls2.classValid)) @@ -1446,14 +1421,14 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ed_tov = (phba->fc_edtov + 999999) / 1000000; } - ndlp->nlp_flag &= ~NLP_SUPPRESS_RSP; + clear_bit(NLP_SUPPRESS_RSP, &ndlp->nlp_flag); if ((phba->sli.sli_flag & LPFC_SLI_SUPPRESS_RSP) && sp->cmn.valid_vendor_ver_level) { vid = be32_to_cpu(sp->un.vv.vid); flag = be32_to_cpu(sp->un.vv.flags); if ((vid == LPFC_VV_EMLX_ID) && (flag & LPFC_VV_SUPPRESS_RSP)) - ndlp->nlp_flag |= NLP_SUPPRESS_RSP; + set_bit(NLP_SUPPRESS_RSP, &ndlp->nlp_flag); } /* @@ -1476,7 +1451,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, LOG_TRACE_EVENT, "0133 PLOGI: no memory " "for config_link " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%lx x%x\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi); goto out; @@ -1500,7 +1475,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, if (!mbox) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0018 PLOGI: no memory for reg_login " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%lx x%x\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi); goto out; @@ -1520,7 +1495,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login; break; default: - ndlp->nlp_flag |= NLP_REG_LOGIN_SEND; + set_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; } @@ -1535,8 +1510,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, NLP_STE_REG_LOGIN_ISSUE); return ndlp->nlp_state; } - if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + clear_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); /* decrement node reference count to the failed mbox * command */ @@ -1544,7 +1518,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0134 PLOGI: cannot issue reg_login " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%lx x%x\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi); } else { @@ -1552,7 +1526,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0135 PLOGI: cannot format reg_login " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%lx x%x\n", ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi); } @@ -1605,18 +1579,15 @@ static uint32_t lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { + set_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); return ndlp->nlp_state; - } else { - /* software abort outstanding PLOGI */ - lpfc_els_abort(vport->phba, ndlp); - - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; } + /* software abort outstanding PLOGI */ + lpfc_els_abort(vport->phba, ndlp); + + lpfc_drop_node(vport, ndlp); + return NLP_STE_FREED_NODE; } static uint32_t @@ -1636,9 +1607,8 @@ lpfc_device_recov_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); return ndlp->nlp_state; } @@ -1656,10 +1626,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, cmdiocb = (struct lpfc_iocbq *) arg; if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(&ndlp->lock); + if (test_and_clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { if (vport->num_disc_nodes) lpfc_more_adisc(vport); } @@ -1748,9 +1715,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, /* 1 sec timeout */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; @@ -1789,18 +1754,15 @@ static uint32_t lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { + set_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); return ndlp->nlp_state; - } else { - /* software abort outstanding ADISC */ - lpfc_els_abort(vport->phba, ndlp); - - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; } + /* software abort outstanding ADISC */ + lpfc_els_abort(vport->phba, ndlp); + + lpfc_drop_node(vport, ndlp); + return NLP_STE_FREED_NODE; } static uint32_t @@ -1820,9 +1782,8 @@ lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -1856,7 +1817,7 @@ lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport, * transition to UNMAPPED provided the RPI has completed * registration. */ - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { + if (test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag)) { lpfc_rcv_prli(vport, ndlp, cmdiocb); lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); } else { @@ -1895,7 +1856,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, if ((mb = phba->sli.mbox_active)) { if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == mb->ctx_ndlp)) { - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + clear_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); mb->ctx_ndlp = NULL; mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; @@ -1906,7 +1867,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == mb->ctx_ndlp)) { - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + clear_bit(NLP_REG_LOGIN_SEND, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); list_del(&mb->list); phba->sli.mboxq_cnt--; @@ -1976,9 +1937,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, /* Put ndlp in npr state set plogi timer for 1 sec */ mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; lpfc_issue_els_logo(vport, ndlp, 0); @@ -1989,7 +1948,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, if (phba->sli_rev < LPFC_SLI_REV4) ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; + set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); /* Only if we are not a fabric nport do we issue PRLI */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -2061,15 +2020,12 @@ lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport, void *arg, uint32_t evt) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { + set_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); return ndlp->nlp_state; - } else { - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; } + lpfc_drop_node(vport, ndlp); + return NLP_STE_FREED_NODE; } static uint32_t @@ -2084,17 +2040,16 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(&ndlp->lock); /* If we are a target we won't immediately transition into PRLI, * so if REG_LOGIN already completed we don't need to ignore it. */ - if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED) || + if (!test_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag) || !vport->phba->nvmet_support) - ndlp->nlp_flag |= NLP_IGNR_REG_CMPL; + set_bit(NLP_IGNR_REG_CMPL, &ndlp->nlp_flag); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2228,7 +2183,8 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (npr->targetFunc) { ndlp->nlp_type |= NLP_FCP_TARGET; if (npr->writeXferRdyDis) - ndlp->nlp_flag |= NLP_FIRSTBURST; + set_bit(NLP_FIRSTBURST, + &ndlp->nlp_flag); } if (npr->Retry) ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; @@ -2272,7 +2228,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Both sides support FB. The target's first * burst size is a 512 byte encoded value. */ - ndlp->nlp_flag |= NLP_FIRSTBURST; + set_bit(NLP_FIRSTBURST, &ndlp->nlp_flag); ndlp->nvme_fb_size = bf_get_be32(prli_fb_sz, nvpr); @@ -2287,7 +2243,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6029 NVME PRLI Cmpl w1 x%08x " - "w4 x%08x w5 x%08x flag x%x, " + "w4 x%08x w5 x%08x flag x%lx, " "fcp_info x%x nlp_type x%x\n", be32_to_cpu(nvpr->word1), be32_to_cpu(nvpr->word4), @@ -2299,9 +2255,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, (vport->port_type == LPFC_NPIV_PORT) && vport->cfg_restrict_login) { out: - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_TARGET_REMOVE; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_TARGET_REMOVE, &ndlp->nlp_flag); lpfc_issue_els_logo(vport, ndlp, 0); ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; @@ -2353,18 +2307,15 @@ static uint32_t lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { + set_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); return ndlp->nlp_state; - } else { - /* software abort outstanding PLOGI */ - lpfc_els_abort(vport->phba, ndlp); - - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; } + /* software abort outstanding PLOGI */ + lpfc_els_abort(vport->phba, ndlp); + + lpfc_drop_node(vport, ndlp); + return NLP_STE_FREED_NODE; } @@ -2401,9 +2352,8 @@ lpfc_device_recov_prli_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2442,9 +2392,7 @@ lpfc_rcv_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg; - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return ndlp->nlp_state; } @@ -2483,9 +2431,8 @@ lpfc_cmpl_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { ndlp->nlp_prev_state = NLP_STE_LOGO_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); lpfc_disc_set_adisc(vport, ndlp); return ndlp->nlp_state; } @@ -2591,8 +2538,9 @@ lpfc_device_recov_unmap_node(struct lpfc_vport *vport, { ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); spin_unlock_irq(&ndlp->lock); lpfc_disc_set_adisc(vport, ndlp); @@ -2653,9 +2601,7 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_sli_abort_iocb(vport, ndlp->nlp_sid, 0, LPFC_CTX_TGT); /* Send PRLO_ACC */ - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); /* Save ELS_CMD_PRLO as the last elscmd and then set to NPR. @@ -2665,7 +2611,7 @@ lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_ELS | LOG_DISCOVERY, - "3422 DID x%06x nflag x%x lastels x%x ref cnt %u\n", + "3422 DID x%06x nflag x%lx lastels x%x ref cnt %u\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_last_elscmd, kref_read(&ndlp->kref)); @@ -2685,8 +2631,9 @@ lpfc_device_recov_mapped_node(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; @@ -2699,16 +2646,16 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; /* Ignore PLOGI if we have an outstanding LOGO */ - if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) + if (test_bit(NLP_LOGO_SND, &ndlp->nlp_flag) || + test_bit(NLP_LOGO_ACC, &ndlp->nlp_flag)) return ndlp->nlp_state; if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC); - spin_unlock_irq(&ndlp->lock); - } else if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); + } else if (!test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { /* send PLOGI immediately, move to PLOGI issue state */ - if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { + if (!test_bit(NLP_DELAY_TMO, &ndlp->nlp_flag)) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); @@ -2729,14 +2676,14 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { + if (!test_bit(NLP_DELAY_TMO, &ndlp->nlp_flag)) { /* * ADISC nodes will be handled in regular discovery path after * receiving response from NS. * * For other nodes, Send PLOGI to trigger an implicit LOGO. */ - if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { + if (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); @@ -2767,15 +2714,15 @@ lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * or discovery in progress for this node. Starting discovery * here will affect the counting of discovery threads. */ - if (!(ndlp->nlp_flag & NLP_DELAY_TMO) && - !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { + if (!test_bit(NLP_DELAY_TMO, &ndlp->nlp_flag) && + !test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { /* * ADISC nodes will be handled in regular discovery path after * receiving response from NS. * * For other nodes, Send PLOGI to trigger an implicit LOGO. */ - if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { + if (!test_bit(NLP_NPR_ADISC, &ndlp->nlp_flag)) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); @@ -2790,24 +2737,18 @@ lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) { + if (!test_bit(NLP_DELAY_TMO, &ndlp->nlp_flag)) { mod_timer(&ndlp->nlp_delayfunc, jiffies + msecs_to_jiffies(1000 * 1)); - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); + set_bit(NLP_DELAY_TMO, &ndlp->nlp_flag); + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; } else { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(&ndlp->lock); + clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); } return ndlp->nlp_state; } @@ -2844,7 +2785,7 @@ lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ulp_status = get_job_ulpstatus(phba, rspiocb); - if (ulp_status && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { + if (ulp_status && test_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag)) { lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -2877,7 +2818,7 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ulp_status = get_job_ulpstatus(phba, rspiocb); - if (ulp_status && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { + if (ulp_status && test_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag)) { lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -2896,12 +2837,11 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport, /* SLI4 ports have preallocated logical rpis. */ if (vport->phba->sli_rev < LPFC_SLI_REV4) ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; - if (ndlp->nlp_flag & NLP_LOGO_ACC) { + set_bit(NLP_RPI_REGISTERED, &ndlp->nlp_flag); + if (test_bit(NLP_LOGO_ACC, &ndlp->nlp_flag)) lpfc_unreg_rpi(vport, ndlp); - } } else { - if (ndlp->nlp_flag & NLP_NODEV_REMOVE) { + if (test_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag)) { lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -2913,10 +2853,8 @@ static uint32_t lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(&ndlp->lock); + if (test_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag)) { + set_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); return ndlp->nlp_state; } lpfc_drop_node(vport, ndlp); @@ -2932,8 +2870,9 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp->nlp_state; lpfc_cancel_retry_delay_tmo(vport, ndlp); + clear_bit(NLP_NODEV_REMOVE, &ndlp->nlp_flag); + clear_bit(NLP_NPR_2B_DISC, &ndlp->nlp_flag); spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME); spin_unlock_irq(&ndlp->lock); return ndlp->nlp_state; @@ -3146,7 +3085,7 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* DSM in event on NPort in state */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0211 DSM in event x%x on NPort x%x in " - "state %d rpi x%x Data: x%x x%x\n", + "state %d rpi x%x Data: x%lx x%x\n", evt, ndlp->nlp_DID, cur_state, ndlp->nlp_rpi, ndlp->nlp_flag, data1); @@ -3163,12 +3102,12 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ((uint32_t)ndlp->nlp_type)); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0212 DSM out state %d on NPort x%x " - "rpi x%x Data: x%x x%x\n", + "rpi x%x Data: x%lx x%x\n", rc, ndlp->nlp_DID, ndlp->nlp_rpi, ndlp->nlp_flag, data1); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, - "DSM out: ste:%d did:x%x flg:x%x", + "DSM out: ste:%d did:x%x flg:x%lx", rc, ndlp->nlp_DID, ndlp->nlp_flag); /* Decrement the ndlp reference count held for this function */ lpfc_nlp_put(ndlp); diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index fec23c7237304b..43dc1da4a1567c 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -242,7 +242,7 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) * @phba: pointer to lpfc hba data structure. * @axchg: pointer to exchange context for the NVME LS request * - * This routine is used for processing an asychronously received NVME LS + * This routine is used for processing an asynchronously received NVME LS * request. Any remaining validation is done and the LS is then forwarded * to the nvme-fc transport via nvme_fc_rcv_ls_req(). * @@ -1232,7 +1232,7 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, /* Word 5 */ if ((phba->cfg_nvme_enable_fb) && - (pnode->nlp_flag & NLP_FIRSTBURST)) { + test_bit(NLP_FIRSTBURST, &pnode->nlp_flag)) { req_len = lpfc_ncmd->nvmeCmd->payload_length; if (req_len < pnode->nvme_fb_size) wqe->fcp_iwrite.initial_xfer_len = @@ -2231,6 +2231,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, struct lpfc_hba *phba = vport->phba; struct lpfc_sli4_hdw_queue *qp; int abts_scsi, abts_nvme; + u16 nvmels_cnt; /* Host transport has to clean up and confirm requiring an indefinite * wait. Print a message if a 10 second wait expires and renew the @@ -2243,6 +2244,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, pending = 0; abts_scsi = 0; abts_nvme = 0; + nvmels_cnt = 0; for (i = 0; i < phba->cfg_hdw_queue; i++) { qp = &phba->sli4_hba.hdwq[i]; if (!vport->localport || !qp || !qp->io_wq) @@ -2255,6 +2257,11 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, abts_scsi += qp->abts_scsi_io_bufs; abts_nvme += qp->abts_nvme_io_bufs; } + if (phba->sli4_hba.nvmels_wq) { + pring = phba->sli4_hba.nvmels_wq->pring; + if (pring) + nvmels_cnt = pring->txcmplq_cnt; + } if (!vport->localport || test_bit(HBA_PCI_ERR, &vport->phba->bit_flags) || phba->link_state == LPFC_HBA_ERROR || @@ -2263,10 +2270,10 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "6176 Lport x%px Localport x%px wait " - "timed out. Pending %d [%d:%d]. " + "timed out. Pending %d [%d:%d:%d]. " "Renewing.\n", lport, vport->localport, pending, - abts_scsi, abts_nvme); + abts_scsi, abts_nvme, nvmels_cnt); continue; } break; @@ -2644,14 +2651,11 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * reference. Check if another thread has set * NLP_DROPPED. */ - spin_lock_irq(&ndlp->lock); - if (!(ndlp->nlp_flag & NLP_DROPPED)) { - ndlp->nlp_flag |= NLP_DROPPED; - spin_unlock_irq(&ndlp->lock); + if (!test_and_set_bit(NLP_DROPPED, + &ndlp->nlp_flag)) { lpfc_nlp_put(ndlp); return; } - spin_unlock_irq(&ndlp->lock); } } } @@ -2841,3 +2845,43 @@ lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, (pwqeIn->cmd_cmpl)(phba, pwqeIn, pwqeIn); #endif } + +/** + * lpfc_nvmels_flush_cmd - Clean up outstanding nvmels commands for a port + * @phba: Pointer to HBA context object. + * + **/ +void +lpfc_nvmels_flush_cmd(struct lpfc_hba *phba) +{ +#if (IS_ENABLED(CONFIG_NVME_FC)) + LIST_HEAD(cancel_list); + struct lpfc_sli_ring *pring = NULL; + struct lpfc_iocbq *piocb, *tmp_iocb; + unsigned long iflags; + + if (phba->sli4_hba.nvmels_wq) + pring = phba->sli4_hba.nvmels_wq->pring; + + if (unlikely(!pring)) + return; + + spin_lock_irqsave(&phba->hbalock, iflags); + spin_lock(&pring->ring_lock); + list_splice_init(&pring->txq, &cancel_list); + pring->txq_cnt = 0; + list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { + if (piocb->cmd_flag & LPFC_IO_NVME_LS) { + list_move_tail(&piocb->list, &cancel_list); + pring->txcmplq_cnt--; + piocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ; + } + } + spin_unlock(&pring->ring_lock); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + if (!list_empty(&cancel_list)) + lpfc_sli_cancel_iocbs(phba, &cancel_list, IOSTAT_LOCAL_REJECT, + IOERR_SLI_DOWN); +#endif +} diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 55c3e2c2bf8f7e..fba2e62027b719 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -2142,7 +2142,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) * @phba: pointer to lpfc hba data structure. * @axchg: pointer to exchange context for the NVME LS request * - * This routine is used for processing an asychronously received NVME LS + * This routine is used for processing an asynchronously received NVME LS * request. Any remaining validation is done and the LS is then forwarded * to the nvmet-fc transport via nvmet_fc_rcv_ls_req(). * @@ -2854,7 +2854,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, /* In template ar=1 wqes=0 sup=0 irsp=0 irsplen=0 */ if (rsp->rsplen == LPFC_NVMET_SUCCESS_LEN) { - if (ndlp->nlp_flag & NLP_SUPPRESS_RSP) + if (test_bit(NLP_SUPPRESS_RSP, &ndlp->nlp_flag)) bf_set(wqe_sup, &wqe->fcp_tsend.wqe_com, 1); } else { diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 11c974bffa7209..905026a4782cf9 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -4629,7 +4629,7 @@ static int lpfc_scsi_prep_cmnd_buf_s3(struct lpfc_vport *vport, iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR; iocb_cmd->ulpPU = PARM_READ_CHECK; if (vport->cfg_first_burst_size && - (pnode->nlp_flag & NLP_FIRSTBURST)) { + test_bit(NLP_FIRSTBURST, &pnode->nlp_flag)) { u32 xrdy_len; fcpdl = scsi_bufflen(scsi_cmnd); @@ -5829,7 +5829,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct fc_rport *rport, lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, "0702 Issue %s to TGT %d LUN %llu " - "rpi x%x nlp_flag x%x Data: x%x x%x\n", + "rpi x%x nlp_flag x%lx Data: x%x x%x\n", lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id, pnode->nlp_rpi, pnode->nlp_flag, iocbq->sli4_xritag, iocbq->cmd_flag); @@ -6094,8 +6094,8 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0722 Target Reset rport failure: rdata x%px\n", rdata); if (pnode) { + clear_bit(NLP_NPR_ADISC, &pnode->nlp_flag); spin_lock_irqsave(&pnode->lock, flags); - pnode->nlp_flag &= ~NLP_NPR_ADISC; pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; spin_unlock_irqrestore(&pnode->lock, flags); } @@ -6124,7 +6124,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) !pnode->logo_waitq) { pnode->logo_waitq = &waitq; pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - pnode->nlp_flag |= NLP_ISSUE_LOGO; + set_bit(NLP_ISSUE_LOGO, &pnode->nlp_flag); pnode->save_flags |= NLP_WAIT_FOR_LOGO; spin_unlock_irqrestore(&pnode->lock, flags); lpfc_unreg_rpi(vport, pnode); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 2ec6e55771b45a..874644b31a3ebd 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1932,7 +1932,7 @@ lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total) union lpfc_wqe128 *wqe; struct lpfc_iocbq *sync_buf; unsigned long iflags; - u32 ret_val; + u32 ret_val, cgn_sig_freq; u32 atot, wtot, max; u8 warn_sync_period = 0; @@ -1987,8 +1987,10 @@ lpfc_issue_cmf_sync_wqe(struct lpfc_hba *phba, u32 ms, u64 total) } else if (wtot) { if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY || phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) { + cgn_sig_freq = phba->cgn_sig_freq ? phba->cgn_sig_freq : + lpfc_fabric_cgn_frequency; /* We hit an Signal warning condition */ - max = LPFC_SEC_TO_MSEC / lpfc_fabric_cgn_frequency * + max = LPFC_SEC_TO_MSEC / cgn_sig_freq * lpfc_acqe_cgn_frequency; bf_set(cmf_sync_wsigmax, &wqe->cmf_sync, max); bf_set(cmf_sync_wsigcnt, &wqe->cmf_sync, wtot); @@ -2842,27 +2844,6 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) return; } -static void -__lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - unsigned long iflags; - - if (ndlp->nlp_flag & NLP_RELEASE_RPI) { - lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); - spin_lock_irqsave(&ndlp->lock, iflags); - ndlp->nlp_flag &= ~NLP_RELEASE_RPI; - ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; - spin_unlock_irqrestore(&ndlp->lock, iflags); - } - ndlp->nlp_flag &= ~NLP_UNREG_INP; -} - -void -lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - __lpfc_sli_rpi_release(vport, ndlp); -} - /** * lpfc_sli_def_mbox_cmpl - Default mailbox completion handler * @phba: Pointer to HBA context object. @@ -2932,18 +2913,16 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_MBOX | LOG_DISCOVERY, "1438 UNREG cmpl deferred mbox x%x " - "on NPort x%x Data: x%x x%x x%px x%lx x%x\n", + "on NPort x%x Data: x%lx x%x x%px x%lx x%x\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_defer_did, ndlp, vport->load_flag, kref_read(&ndlp->kref)); - if ((ndlp->nlp_flag & NLP_UNREG_INP) && - (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { - ndlp->nlp_flag &= ~NLP_UNREG_INP; + if (test_bit(NLP_UNREG_INP, &ndlp->nlp_flag) && + ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING) { + clear_bit(NLP_UNREG_INP, &ndlp->nlp_flag); ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - } else { - __lpfc_sli_rpi_release(vport, ndlp); } /* The unreg_login mailbox is complete and had a @@ -2991,6 +2970,7 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; struct lpfc_nodelist *ndlp; + bool unreg_inp; ndlp = pmb->ctx_ndlp; if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) { @@ -3003,20 +2983,26 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_MBOX | LOG_SLI | LOG_NODE, "0010 UNREG_LOGIN vpi:x%x " - "rpi:%x DID:%x defer x%x flg x%x " + "rpi:%x DID:%x defer x%x flg x%lx " "x%px\n", vport->vpi, ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp->nlp_flag, ndlp); - ndlp->nlp_flag &= ~NLP_LOGO_ACC; + + /* Cleanup the nlp_flag now that the UNREG RPI + * has completed. + */ + unreg_inp = test_and_clear_bit(NLP_UNREG_INP, + &ndlp->nlp_flag); + clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); /* Check to see if there are any deferred * events to process */ - if ((ndlp->nlp_flag & NLP_UNREG_INP) && - (ndlp->nlp_defer_did != - NLP_EVT_NOTHING_PENDING)) { + if (unreg_inp && + ndlp->nlp_defer_did != + NLP_EVT_NOTHING_PENDING) { lpfc_printf_vlog( vport, KERN_INFO, LOG_MBOX | LOG_SLI | LOG_NODE, @@ -3025,14 +3011,12 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) "NPort x%x Data: x%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp); - ndlp->nlp_flag &= ~NLP_UNREG_INP; ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; lpfc_issue_els_plogi( vport, ndlp->nlp_DID, 0); - } else { - __lpfc_sli_rpi_release(vport, ndlp); } + lpfc_nlp_put(ndlp); } } @@ -5291,6 +5275,8 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) "0296 Restart HBA Data: x%x x%x\n", phba->pport->port_state, psli->sli_flag); + lpfc_sli4_queue_unset(phba); + rc = lpfc_sli4_brdreset(phba); if (rc) { phba->link_state = LPFC_HBA_ERROR; @@ -8748,6 +8734,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) lpfc_sli_config_mbox_opcode_get( phba, mboxq), rc, dd); + /* * Allocate all resources (xri,rpi,vpi,vfi) now. Subsequent * calls depends on these resources to complete port setup. @@ -8760,6 +8747,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) goto out_free_mbox; } + lpfc_sli4_node_rpi_restore(phba); + lpfc_set_host_data(phba, mboxq); rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); @@ -8947,7 +8936,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = -ENODEV; goto out_free_iocblist; } - lpfc_sli4_node_prep(phba); if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag)) { if ((phba->nvmet_support == 0) || (phba->cfg_nvmet_mrq == 1)) { @@ -14352,9 +14340,7 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) * an unsolicited PLOGI from the same NPortId from * starting another mailbox transaction. */ - spin_lock_irqsave(&ndlp->lock, iflags); - ndlp->nlp_flag |= NLP_UNREG_INP; - spin_unlock_irqrestore(&ndlp->lock, iflags); + set_bit(NLP_UNREG_INP, &ndlp->nlp_flag); lpfc_unreg_login(phba, vport->vpi, pmbox->un.varWords[0], pmb); pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; @@ -17625,6 +17611,9 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) if (!eq) return -ENODEV; + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) + goto list_remove; + mbox = mempool_alloc(eq->phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; @@ -17651,10 +17640,12 @@ lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) shdr_status, shdr_add_status, rc); status = -ENXIO; } + mempool_free(mbox, eq->phba->mbox_mem_pool); +list_remove: /* Remove eq from any list */ list_del_init(&eq->list); - mempool_free(mbox, eq->phba->mbox_mem_pool); + return status; } @@ -17682,6 +17673,10 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) /* sanity check on queue memory */ if (!cq) return -ENODEV; + + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) + goto list_remove; + mbox = mempool_alloc(cq->phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; @@ -17707,9 +17702,11 @@ lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) shdr_status, shdr_add_status, rc); status = -ENXIO; } + mempool_free(mbox, cq->phba->mbox_mem_pool); + +list_remove: /* Remove cq from any list */ list_del_init(&cq->list); - mempool_free(mbox, cq->phba->mbox_mem_pool); return status; } @@ -17737,6 +17734,10 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) /* sanity check on queue memory */ if (!mq) return -ENODEV; + + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) + goto list_remove; + mbox = mempool_alloc(mq->phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; @@ -17762,9 +17763,11 @@ lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) shdr_status, shdr_add_status, rc); status = -ENXIO; } + mempool_free(mbox, mq->phba->mbox_mem_pool); + +list_remove: /* Remove mq from any list */ list_del_init(&mq->list); - mempool_free(mbox, mq->phba->mbox_mem_pool); return status; } @@ -17792,6 +17795,10 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) /* sanity check on queue memory */ if (!wq) return -ENODEV; + + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) + goto list_remove; + mbox = mempool_alloc(wq->phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; @@ -17816,11 +17823,13 @@ lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) shdr_status, shdr_add_status, rc); status = -ENXIO; } + mempool_free(mbox, wq->phba->mbox_mem_pool); + +list_remove: /* Remove wq from any list */ list_del_init(&wq->list); kfree(wq->pring); wq->pring = NULL; - mempool_free(mbox, wq->phba->mbox_mem_pool); return status; } @@ -17850,6 +17859,10 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, /* sanity check on queue memory */ if (!hrq || !drq) return -ENODEV; + + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) + goto list_remove; + mbox = mempool_alloc(hrq->phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; @@ -17890,9 +17903,11 @@ lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, shdr_status, shdr_add_status, rc); status = -ENXIO; } + mempool_free(mbox, hrq->phba->mbox_mem_pool); + +list_remove: list_del_init(&hrq->list); list_del_init(&drq->list); - mempool_free(mbox, hrq->phba->mbox_mem_pool); return status; } @@ -19074,9 +19089,9 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, * to free ndlp when transmit completes */ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE && - !(ndlp->nlp_flag & NLP_DROPPED) && + !test_bit(NLP_DROPPED, &ndlp->nlp_flag) && !(ndlp->fc4_xpt_flags & (NVME_XPT_REGD | SCSI_XPT_REGD))) { - ndlp->nlp_flag |= NLP_DROPPED; + set_bit(NLP_DROPPED, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); } } @@ -21094,11 +21109,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) /* Unregister the RPI when mailbox complete */ mb->mbox_flag |= LPFC_MBX_IMED_UNREG; restart_loop = 1; - spin_unlock_irq(&phba->hbalock); - spin_lock(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(&ndlp->lock); - spin_lock_irq(&phba->hbalock); + clear_bit(NLP_IGNR_REG_CMPL, &ndlp->nlp_flag); break; } } @@ -21113,9 +21124,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) ndlp = mb->ctx_ndlp; mb->ctx_ndlp = NULL; if (ndlp) { - spin_lock(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(&ndlp->lock); + clear_bit(NLP_IGNR_REG_CMPL, &ndlp->nlp_flag); lpfc_nlp_put(ndlp); } } @@ -21124,9 +21133,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) /* Release the ndlp with the cleaned-up active mailbox command */ if (act_mbx_ndlp) { - spin_lock(&act_mbx_ndlp->lock); - act_mbx_ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(&act_mbx_ndlp->lock); + clear_bit(NLP_IGNR_REG_CMPL, &act_mbx_ndlp->nlp_flag); lpfc_nlp_put(act_mbx_ndlp); } } diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index e70f163fab9003..61fe1220f8ad38 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.4.0.5" +#define LPFC_DRIVER_VERSION "14.4.0.6" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 7a4d4d8e2ad55f..9e0e357633779f 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -496,7 +496,7 @@ lpfc_send_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) !ndlp->logo_waitq) { ndlp->logo_waitq = &waitq; ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - ndlp->nlp_flag |= NLP_ISSUE_LOGO; + set_bit(NLP_ISSUE_LOGO, &ndlp->nlp_flag); ndlp->save_flags |= NLP_WAIT_FOR_LOGO; } spin_unlock_irq(&ndlp->lock); @@ -515,8 +515,8 @@ lpfc_send_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) } /* Error - clean up node flags. */ + clear_bit(NLP_ISSUE_LOGO, &ndlp->nlp_flag); spin_lock_irq(&ndlp->lock); - ndlp->nlp_flag &= ~NLP_ISSUE_LOGO; ndlp->save_flags &= ~NLP_WAIT_FOR_LOGO; spin_unlock_irq(&ndlp->lock); @@ -708,7 +708,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT | LOG_ELS, "1829 DA_ID issue status %d. " - "SFlag x%x NState x%x, NFlag x%x " + "SFlag x%x NState x%x, NFlag x%lx " "Rpi x%x\n", rc, ndlp->save_flags, ndlp->nlp_state, ndlp->nlp_flag, ndlp->nlp_rpi); diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 187ae0a65d404e..ff0253d47a0e88 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -432,7 +432,7 @@ static void esp_mac_remove(struct platform_device *dev) static struct platform_driver esp_mac_driver = { .probe = esp_mac_probe, - .remove_new = esp_mac_remove, + .remove = esp_mac_remove, .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index f225bb20aa2201..a86bd839d08e9e 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -547,7 +547,7 @@ static void __exit mac_scsi_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver mac_scsi_driver __refdata = { - .remove_new = __exit_p(mac_scsi_remove), + .remove = __exit_p(mac_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 8e75e2e279a40a..50f1dcb6d58460 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -8907,8 +8907,11 @@ megasas_aen_polling(struct work_struct *work) (ld_target_id / MEGASAS_MAX_DEV_PER_CHANNEL), (ld_target_id % MEGASAS_MAX_DEV_PER_CHANNEL), 0); - if (sdev1) + if (sdev1) { + mutex_unlock(&instance->reset_mutex); megasas_remove_scsi_device(sdev1); + mutex_lock(&instance->reset_mutex); + } event_type = SCAN_VD_CHANNEL; break; diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 81bb408ce56d8f..0c3e1ac076b5ff 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -57,8 +57,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.12.0.0.50" -#define MPI3MR_DRIVER_RELDATE "05-Sept-2024" +#define MPI3MR_DRIVER_VERSION "8.12.0.3.50" +#define MPI3MR_DRIVER_RELDATE "11-November-2024" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" @@ -134,8 +134,6 @@ extern atomic64_t event_counter; #define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */ -#define MPI3MR_DEFAULT_CFG_PAGE_SZ 1024 /* in bytes */ - #define MPI3MR_RESET_TOPOLOGY_SETTLE_TIME 10 #define MPI3MR_SCMD_TIMEOUT (60 * HZ) @@ -1133,9 +1131,6 @@ struct scmd_priv { * @io_throttle_low: I/O size to stop throttle in 512b blocks * @num_io_throttle_group: Maximum number of throttle groups * @throttle_groups: Pointer to throttle group info structures - * @cfg_page: Default memory for configuration pages - * @cfg_page_dma: Configuration page DMA address - * @cfg_page_sz: Default configuration page memory size * @sas_transport_enabled: SAS transport enabled or not * @scsi_device_channel: Channel ID for SCSI devices * @transport_cmds: Command tracker for SAS transport commands @@ -1332,10 +1327,6 @@ struct mpi3mr_ioc { u16 num_io_throttle_group; struct mpi3mr_throttle_group_info *throttle_groups; - void *cfg_page; - dma_addr_t cfg_page_dma; - u16 cfg_page_sz; - u8 sas_transport_enabled; u8 scsi_device_channel; struct mpi3mr_drv_cmd transport_cmds; diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 01f035f9330e4b..10b8e4dc64f8b0 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -2329,6 +2329,15 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) if (!mrioc) return -ENODEV; + if (mutex_lock_interruptible(&mrioc->bsg_cmds.mutex)) + return -ERESTARTSYS; + + if (mrioc->bsg_cmds.state & MPI3MR_CMD_PENDING) { + dprint_bsg_err(mrioc, "%s: command is in use\n", __func__); + mutex_unlock(&mrioc->bsg_cmds.mutex); + return -EAGAIN; + } + if (!mrioc->ioctl_sges_allocated) { dprint_bsg_err(mrioc, "%s: DMA memory was not allocated\n", __func__); @@ -2339,13 +2348,16 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) karg->timeout = MPI3MR_APP_DEFAULT_TIMEOUT; mpi_req = kzalloc(MPI3MR_ADMIN_REQ_FRAME_SZ, GFP_KERNEL); - if (!mpi_req) + if (!mpi_req) { + mutex_unlock(&mrioc->bsg_cmds.mutex); return -ENOMEM; + } mpi_header = (struct mpi3_request_header *)mpi_req; bufcnt = karg->buf_entry_list.num_of_entries; drv_bufs = kzalloc((sizeof(*drv_bufs) * bufcnt), GFP_KERNEL); if (!drv_bufs) { + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -ENOMEM; goto out; } @@ -2353,6 +2365,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) dout_buf = kzalloc(job->request_payload.payload_len, GFP_KERNEL); if (!dout_buf) { + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -ENOMEM; goto out; } @@ -2360,6 +2373,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) din_buf = kzalloc(job->reply_payload.payload_len, GFP_KERNEL); if (!din_buf) { + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -ENOMEM; goto out; } @@ -2435,6 +2449,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) (mpi_msg_size > MPI3MR_ADMIN_REQ_FRAME_SZ)) { dprint_bsg_err(mrioc, "%s: invalid MPI message size\n", __func__); + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -EINVAL; goto out; } @@ -2447,6 +2462,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) if (invalid_be) { dprint_bsg_err(mrioc, "%s: invalid buffer entries passed\n", __func__); + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -EINVAL; goto out; } @@ -2454,12 +2470,14 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) { dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n", __func__); + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -EINVAL; goto out; } if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) { dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n", __func__); + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -EINVAL; goto out; } @@ -2472,6 +2490,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x din_size = %d, dout_size = %d\n", __func__, __LINE__, mpi_header->function, din_size, dout_size); + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -EINVAL; goto out; } @@ -2480,6 +2499,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x din_size=%d\n", __func__, __LINE__, mpi_header->function, din_size); + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -EINVAL; goto out; } @@ -2487,6 +2507,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x dout_size = %d\n", __func__, __LINE__, mpi_header->function, dout_size); + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -EINVAL; goto out; } @@ -2497,6 +2518,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) dprint_bsg_err(mrioc, "%s:%d: invalid message size passed:%d:%d:%d:%d\n", __func__, __LINE__, din_cnt, dout_cnt, din_size, dout_size); + mutex_unlock(&mrioc->bsg_cmds.mutex); rval = -EINVAL; goto out; } @@ -2544,6 +2566,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) continue; if (mpi3mr_map_data_buffer_dma(mrioc, drv_buf_iter, desc_count)) { rval = -ENOMEM; + mutex_unlock(&mrioc->bsg_cmds.mutex); dprint_bsg_err(mrioc, "%s:%d: mapping data buffers failed\n", __func__, __LINE__); goto out; @@ -2556,20 +2579,11 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) sense_buff_k = kzalloc(erbsz, GFP_KERNEL); if (!sense_buff_k) { rval = -ENOMEM; + mutex_unlock(&mrioc->bsg_cmds.mutex); goto out; } } - if (mutex_lock_interruptible(&mrioc->bsg_cmds.mutex)) { - rval = -ERESTARTSYS; - goto out; - } - if (mrioc->bsg_cmds.state & MPI3MR_CMD_PENDING) { - rval = -EAGAIN; - dprint_bsg_err(mrioc, "%s: command is in use\n", __func__); - mutex_unlock(&mrioc->bsg_cmds.mutex); - goto out; - } if (mrioc->unrecoverable) { dprint_bsg_err(mrioc, "%s: unrecoverable controller\n", __func__); diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index f1ab76351bd81e..5ed31fe57474a3 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1035,6 +1035,36 @@ static const char *mpi3mr_reset_type_name(u16 reset_type) return name; } +/** + * mpi3mr_is_fault_recoverable - Read fault code and decide + * whether the controller can be recoverable + * @mrioc: Adapter instance reference + * Return: true if fault is recoverable, false otherwise. + */ +static inline bool mpi3mr_is_fault_recoverable(struct mpi3mr_ioc *mrioc) +{ + u32 fault; + + fault = (readl(&mrioc->sysif_regs->fault) & + MPI3_SYSIF_FAULT_CODE_MASK); + + switch (fault) { + case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED: + case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: + ioc_warn(mrioc, + "controller requires system power cycle, marking controller as unrecoverable\n"); + return false; + case MPI3_SYSIF_FAULT_CODE_INSUFFICIENT_PCI_SLOT_POWER: + ioc_warn(mrioc, + "controller faulted due to insufficient power,\n" + " try by connecting it to a different slot\n"); + return false; + default: + break; + } + return true; +} + /** * mpi3mr_print_fault_info - Display fault information * @mrioc: Adapter instance reference @@ -1373,6 +1403,11 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n", ioc_status, ioc_config, base_info); + if (!mpi3mr_is_fault_recoverable(mrioc)) { + mrioc->unrecoverable = 1; + goto out_device_not_present; + } + /*The timeout value is in 2sec unit, changing it to seconds*/ mrioc->ready_timeout = ((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >> @@ -2734,6 +2769,11 @@ static void mpi3mr_watchdog_work(struct work_struct *work) mpi3mr_print_fault_info(mrioc); mrioc->diagsave_timeout = 0; + if (!mpi3mr_is_fault_recoverable(mrioc)) { + mrioc->unrecoverable = 1; + goto schedule_work; + } + switch (trigger_data.fault) { case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED: case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: @@ -4186,17 +4226,6 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc) mpi3mr_read_tsu_interval(mrioc); mpi3mr_print_ioc_info(mrioc); - if (!mrioc->cfg_page) { - dprint_init(mrioc, "allocating config page buffers\n"); - mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ; - mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev, - mrioc->cfg_page_sz, &mrioc->cfg_page_dma, GFP_KERNEL); - if (!mrioc->cfg_page) { - retval = -1; - goto out_failed_noretry; - } - } - dprint_init(mrioc, "allocating host diag buffers\n"); mpi3mr_alloc_diag_bufs(mrioc); @@ -4768,11 +4797,7 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) mrioc->admin_req_base, mrioc->admin_req_dma); mrioc->admin_req_base = NULL; } - if (mrioc->cfg_page) { - dma_free_coherent(&mrioc->pdev->dev, mrioc->cfg_page_sz, - mrioc->cfg_page, mrioc->cfg_page_dma); - mrioc->cfg_page = NULL; - } + if (mrioc->pel_seqnum_virt) { dma_free_coherent(&mrioc->pdev->dev, mrioc->pel_seqnum_sz, mrioc->pel_seqnum_virt, mrioc->pel_seqnum_dma); @@ -5392,55 +5417,6 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, return retval; } - -/** - * mpi3mr_free_config_dma_memory - free memory for config page - * @mrioc: Adapter instance reference - * @mem_desc: memory descriptor structure - * - * Check whether the size of the buffer specified by the memory - * descriptor is greater than the default page size if so then - * free the memory pointed by the descriptor. - * - * Return: Nothing. - */ -static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc, - struct dma_memory_desc *mem_desc) -{ - if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) { - dma_free_coherent(&mrioc->pdev->dev, mem_desc->size, - mem_desc->addr, mem_desc->dma_addr); - mem_desc->addr = NULL; - } -} - -/** - * mpi3mr_alloc_config_dma_memory - Alloc memory for config page - * @mrioc: Adapter instance reference - * @mem_desc: Memory descriptor to hold dma memory info - * - * This function allocates new dmaable memory or provides the - * default config page dmaable memory based on the memory size - * described by the descriptor. - * - * Return: 0 on success, non-zero on failure. - */ -static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc, - struct dma_memory_desc *mem_desc) -{ - if (mem_desc->size > mrioc->cfg_page_sz) { - mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev, - mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL); - if (!mem_desc->addr) - return -ENOMEM; - } else { - mem_desc->addr = mrioc->cfg_page; - mem_desc->dma_addr = mrioc->cfg_page_dma; - memset(mem_desc->addr, 0, mrioc->cfg_page_sz); - } - return 0; -} - /** * mpi3mr_post_cfg_req - Issue config requests and wait * @mrioc: Adapter instance reference @@ -5596,8 +5572,12 @@ static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc, cfg_req->page_length = cfg_hdr->page_length; cfg_req->page_version = cfg_hdr->page_version; } - if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc)) - goto out; + + mem_desc.addr = dma_alloc_coherent(&mrioc->pdev->dev, + mem_desc.size, &mem_desc.dma_addr, GFP_KERNEL); + + if (!mem_desc.addr) + return retval; mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size, mem_desc.dma_addr); @@ -5626,7 +5606,12 @@ static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc, } out: - mpi3mr_free_config_dma_memory(mrioc, &mem_desc); + if (mem_desc.addr) { + dma_free_coherent(&mrioc->pdev->dev, mem_desc.size, + mem_desc.addr, mem_desc.dma_addr); + mem_desc.addr = NULL; + } + return retval; } diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 5f2f67acf8bf31..1bef88130d0c06 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -5215,7 +5215,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) } mrioc = shost_priv(shost); - retval = ida_alloc_range(&mrioc_ida, 1, U8_MAX, GFP_KERNEL); + retval = ida_alloc_range(&mrioc_ida, 0, U8_MAX, GFP_KERNEL); if (retval < 0) goto id_alloc_failed; mrioc->id = (u8)retval; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index ed5046593fdab6..16ac2267c71e19 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -7041,11 +7041,12 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, int i; u8 failed; __le32 *mfp; + int ret_val; /* make sure doorbell is not in use */ if ((ioc->base_readl_ext_retry(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { ioc_err(ioc, "doorbell is in use (line=%d)\n", __LINE__); - return -EFAULT; + goto doorbell_diag_reset; } /* clear pending doorbell interrupts from previous state changes */ @@ -7135,6 +7136,10 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes, le32_to_cpu(mfp[i])); } return 0; + +doorbell_diag_reset: + ret_val = _base_diag_reset(ioc); + return ret_val; } /** diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index eceb5eeb465132..d8d1a64b4764d1 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -77,11 +77,11 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "48.100.00.00" -#define MPT3SAS_MAJOR_VERSION 48 +#define MPT3SAS_DRIVER_VERSION "51.100.00.00" +#define MPT3SAS_MAJOR_VERSION 51 #define MPT3SAS_MINOR_VERSION 100 -#define MPT3SAS_BUILD_VERSION 0 -#define MPT3SAS_RELEASE_VERSION 00 +#define MPT3SAS_BUILD_VERSION 00 +#define MPT3SAS_RELEASE_VERSION 00 #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c index e08a38e2a442b6..9b19d5205e508c 100644 --- a/drivers/scsi/mvme16x_scsi.c +++ b/drivers/scsi/mvme16x_scsi.c @@ -127,7 +127,7 @@ static struct platform_driver mvme16x_scsi_driver = { .name = "mvme16x-scsi", }, .probe = mvme16x_probe, - .remove_new = mvme16x_device_remove, + .remove = mvme16x_device_remove, }; static int __init mvme16x_scsi_init(void) diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index 501b574239e8b1..7871e29a820a09 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -92,8 +92,11 @@ enum port_type { #define PM8001_MAX_MSIX_VEC 64 /* max msi-x int for spcv/ve */ #define PM8001_RESERVE_SLOT 8 -#define CONFIG_SCSI_PM8001_MAX_DMA_SG 528 -#define PM8001_MAX_DMA_SG CONFIG_SCSI_PM8001_MAX_DMA_SG +#define PM8001_SECTOR_SIZE 512 +#define PM8001_PAGE_SIZE_4K 4096 +#define PM8001_MAX_IO_SIZE (4 * 1024 * 1024) +#define PM8001_MAX_DMA_SG (PM8001_MAX_IO_SIZE / PM8001_PAGE_SIZE_4K) +#define PM8001_MAX_SECTORS (PM8001_MAX_IO_SIZE / PM8001_SECTOR_SIZE) enum memory_region_num { AAP1 = 0x0, /* application acceleration processor */ diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 33e1eba62ca12c..f8c81e53e93f78 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -68,6 +68,10 @@ static bool pm8001_read_wwn = true; module_param_named(read_wwn, pm8001_read_wwn, bool, 0444); MODULE_PARM_DESC(zoned, "Get WWN from the controller. Default: true"); +uint pcs_event_log_severity = 0x03; +module_param(pcs_event_log_severity, int, 0644); +MODULE_PARM_DESC(pcs_event_log_severity, "PCS event log severity level"); + static struct scsi_transport_template *pm8001_stt; static int pm8001_init_ccb_tag(struct pm8001_hba_info *); @@ -117,6 +121,7 @@ static const struct scsi_host_template pm8001_sht = { .scan_start = pm8001_scan_start, .can_queue = 1, .sg_tablesize = PM8001_MAX_DMA_SG, + .max_sectors = PM8001_MAX_SECTORS, .shost_groups = pm8001_host_groups, .sdev_groups = pm8001_sdev_groups, .track_queue_depth = 1, @@ -447,9 +452,6 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, } for (i = 0; i < PM8001_MAX_DEVICES; i++) { pm8001_ha->devices[i].dev_type = SAS_PHY_UNUSED; - pm8001_ha->devices[i].id = i; - pm8001_ha->devices[i].device_id = PM8001_MAX_DEVICES; - atomic_set(&pm8001_ha->devices[i].running_req, 0); } pm8001_ha->flags = PM8001F_INIT_TIME; return 0; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index ee2da8e49d4cfb..d80cffd25a6ed0 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -572,6 +572,13 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha, pm8001_ccb_free(pm8001_ha, ccb); } +static void pm8001_init_dev(struct pm8001_device *pm8001_dev, int id) +{ + pm8001_dev->id = id; + pm8001_dev->device_id = PM8001_MAX_DEVICES; + atomic_set(&pm8001_dev->running_req, 0); +} + /** * pm8001_alloc_dev - find a empty pm8001_device * @pm8001_ha: our hba card information @@ -580,9 +587,11 @@ static struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha) { u32 dev; for (dev = 0; dev < PM8001_MAX_DEVICES; dev++) { - if (pm8001_ha->devices[dev].dev_type == SAS_PHY_UNUSED) { - pm8001_ha->devices[dev].id = dev; - return &pm8001_ha->devices[dev]; + struct pm8001_device *pm8001_dev = &pm8001_ha->devices[dev]; + + if (pm8001_dev->dev_type == SAS_PHY_UNUSED) { + pm8001_init_dev(pm8001_dev, dev); + return pm8001_dev; } } if (dev == PM8001_MAX_DEVICES) { @@ -613,9 +622,7 @@ struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha, void pm8001_free_dev(struct pm8001_device *pm8001_dev) { - u32 id = pm8001_dev->id; memset(pm8001_dev, 0, sizeof(*pm8001_dev)); - pm8001_dev->id = id; pm8001_dev->dev_type = SAS_PHY_UNUSED; pm8001_dev->device_id = PM8001_MAX_DEVICES; pm8001_dev->sas_device = NULL; diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index ced6721380a853..42c7b3f7afbf1b 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -96,6 +96,8 @@ extern struct list_head hba_list; extern const struct pm8001_dispatch pm8001_8001_dispatch; extern const struct pm8001_dispatch pm8001_80xx_dispatch; +extern uint pcs_event_log_severity; + struct pm8001_hba_info; struct pm8001_ccb_info; struct pm8001_device; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index a9869cd8c4c075..e65951dd2024ef 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -763,7 +763,8 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha) pm8001_ha->memoryMap.region[IOP].phys_addr_lo; pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size = PM8001_EVENT_LOG_SIZE; - pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity = 0x01; + pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity = + pcs_event_log_severity; pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt = 0x01; /* Enable higher IQs and OQs, 32 to 63, bit 16 */ diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index cf13148ba281c1..d2f47dc31dbf9b 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2738,6 +2738,7 @@ static int qedf_alloc_and_init_sb(struct qedf_ctx *qedf, sb_id, QED_SB_TYPE_STORAGE); if (ret) { + dma_free_coherent(&qedf->pdev->dev, sizeof(*sb_virt), sb_virt, sb_phys); QEDF_ERR(&qedf->dbg_ctx, "Status block initialization failed (0x%x) for id = %d.\n", ret, sb_id); @@ -4018,11 +4019,6 @@ void qedf_stag_change_work(struct work_struct *work) struct qedf_ctx *qedf = container_of(work, struct qedf_ctx, stag_work.work); - if (!qedf) { - QEDF_ERR(&qedf->dbg_ctx, "qedf is NULL"); - return; - } - if (test_bit(QEDF_IN_RECOVERY, &qedf->flags)) { QEDF_ERR(&qedf->dbg_ctx, "Already is in recovery, hence not calling software context reset.\n"); diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index c5aec26019d6ab..628d59dda20cc4 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -369,6 +369,7 @@ static int qedi_alloc_and_init_sb(struct qedi_ctx *qedi, ret = qedi_ops->common->sb_init(qedi->cdev, sb_info, sb_virt, sb_phys, sb_id, QED_SB_TYPE_STORAGE); if (ret) { + dma_free_coherent(&qedi->pdev->dev, sizeof(*sb_virt), sb_virt, sb_phys); QEDI_ERR(&qedi->dbg_ctx, "Status block initialization failed for id = %d.\n", sb_id); diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index d309e2ca14deb3..dea2290b37d4d7 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -116,12 +116,12 @@ struct device_reg { uint16_t id_h; /* ID high */ uint16_t cfg_0; /* Configuration 0 */ #define ISP_CFG0_HWMSK 0x000f /* Hardware revision mask */ -#define ISP_CFG0_1020 BIT_0 /* ISP1020 */ -#define ISP_CFG0_1020A BIT_1 /* ISP1020A */ -#define ISP_CFG0_1040 BIT_2 /* ISP1040 */ -#define ISP_CFG0_1040A BIT_3 /* ISP1040A */ -#define ISP_CFG0_1040B BIT_4 /* ISP1040B */ -#define ISP_CFG0_1040C BIT_5 /* ISP1040C */ +#define ISP_CFG0_1020 1 /* ISP1020 */ +#define ISP_CFG0_1020A 2 /* ISP1020A */ +#define ISP_CFG0_1040 3 /* ISP1040 */ +#define ISP_CFG0_1040A 4 /* ISP1040A */ +#define ISP_CFG0_1040B 5 /* ISP1040B */ +#define ISP_CFG0_1040C 6 /* ISP1040C */ uint16_t cfg_1; /* Configuration 1 */ #define ISP_CFG1_F128 BIT_6 /* 128-byte FIFO threshold */ #define ISP_CFG1_F64 BIT_4|BIT_5 /* 128-byte FIFO threshold */ diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 2810608acd963a..e6ece30c43486c 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -3304,6 +3304,7 @@ struct fc_function_template qla2xxx_transport_vport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, .show_host_supported_classes = 1, + .show_host_supported_speeds = 1, .get_host_port_id = qla2x00_get_host_port_id, .show_host_port_id = 1, diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 52dc9604f56746..10431a67d202bb 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -24,6 +24,7 @@ void qla2x00_bsg_job_done(srb_t *sp, int res) { struct bsg_job *bsg_job = sp->u.bsg_job; struct fc_bsg_reply *bsg_reply = bsg_job->reply; + struct completion *comp = sp->comp; ql_dbg(ql_dbg_user, sp->vha, 0x7009, "%s: sp hdl %x, result=%x bsg ptr %p\n", @@ -35,6 +36,9 @@ void qla2x00_bsg_job_done(srb_t *sp, int res) bsg_reply->result = res; bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + if (comp) + complete(comp); } void qla2x00_bsg_sp_free(srb_t *sp) @@ -490,16 +494,6 @@ qla2x00_process_ct(struct bsg_job *bsg_job) goto done; } - if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || - (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { - ql_log(ql_log_warn, vha, 0x7011, - "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x " - "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt, - req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt); - rval = -EAGAIN; - goto done_unmap_sg; - } - if (!vha->flags.online) { ql_log(ql_log_warn, vha, 0x7012, "Host is not online.\n"); @@ -3061,7 +3055,7 @@ qla24xx_bsg_request(struct bsg_job *bsg_job) static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job) { - bool found = false; + bool found, do_bsg_done; struct fc_bsg_reply *bsg_reply = bsg_job->reply; scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); struct qla_hw_data *ha = vha->hw; @@ -3069,6 +3063,11 @@ static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job) int cnt; unsigned long flags; struct req_que *req; + int rval; + DECLARE_COMPLETION_ONSTACK(comp); + uint32_t ratov_j; + + found = do_bsg_done = false; spin_lock_irqsave(qpair->qp_lock_ptr, flags); req = qpair->req; @@ -3080,42 +3079,104 @@ static bool qla_bsg_found(struct qla_qpair *qpair, struct bsg_job *bsg_job) sp->type == SRB_ELS_CMD_HST || sp->type == SRB_ELS_CMD_HST_NOLOGIN) && sp->u.bsg_job == bsg_job) { - req->outstanding_cmds[cnt] = NULL; - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - - if (!ha->flags.eeh_busy && ha->isp_ops->abort_command(sp)) { - ql_log(ql_log_warn, vha, 0x7089, - "mbx abort_command failed.\n"); - bsg_reply->result = -EIO; - } else { - ql_dbg(ql_dbg_user, vha, 0x708a, - "mbx abort_command success.\n"); - bsg_reply->result = 0; - } - /* ref: INIT */ - kref_put(&sp->cmd_kref, qla2x00_sp_release); found = true; - goto done; + sp->comp = ∁ + break; } } spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); -done: - return found; + if (!found) + return false; + + if (ha->flags.eeh_busy) { + /* skip over abort. EEH handling will return the bsg. Wait for it */ + rval = QLA_SUCCESS; + ql_dbg(ql_dbg_user, vha, 0x802c, + "eeh encounter. bsg %p sp=%p handle=%x \n", + bsg_job, sp, sp->handle); + } else { + rval = ha->isp_ops->abort_command(sp); + ql_dbg(ql_dbg_user, vha, 0x802c, + "Aborting bsg %p sp=%p handle=%x rval=%x\n", + bsg_job, sp, sp->handle, rval); + } + + switch (rval) { + case QLA_SUCCESS: + /* Wait for the command completion. */ + ratov_j = ha->r_a_tov / 10 * 4 * 1000; + ratov_j = msecs_to_jiffies(ratov_j); + + if (!wait_for_completion_timeout(&comp, ratov_j)) { + ql_log(ql_log_info, vha, 0x7089, + "bsg abort timeout. bsg=%p sp=%p handle %#x .\n", + bsg_job, sp, sp->handle); + + do_bsg_done = true; + } else { + /* fw had returned the bsg */ + ql_dbg(ql_dbg_user, vha, 0x708a, + "bsg abort success. bsg %p sp=%p handle=%#x\n", + bsg_job, sp, sp->handle); + do_bsg_done = false; + } + break; + default: + ql_log(ql_log_info, vha, 0x704f, + "bsg abort fail. bsg=%p sp=%p rval=%x.\n", + bsg_job, sp, rval); + + do_bsg_done = true; + break; + } + + if (!do_bsg_done) + return true; + + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + /* + * recheck to make sure it's still the same bsg_job due to + * qp_lock_ptr was released earlier. + */ + if (req->outstanding_cmds[cnt] && + req->outstanding_cmds[cnt]->u.bsg_job != bsg_job) { + /* fw had returned the bsg */ + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + return true; + } + req->outstanding_cmds[cnt] = NULL; + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + + /* ref: INIT */ + sp->comp = NULL; + kref_put(&sp->cmd_kref, qla2x00_sp_release); + bsg_reply->result = -ENXIO; + bsg_reply->reply_payload_rcv_len = 0; + + ql_dbg(ql_dbg_user, vha, 0x7051, + "%s bsg_job_done : bsg %p result %#x sp %p.\n", + __func__, bsg_job, bsg_reply->result, sp); + + bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + return true; } int qla24xx_bsg_timeout(struct bsg_job *bsg_job) { - struct fc_bsg_reply *bsg_reply = bsg_job->reply; + struct fc_bsg_request *bsg_request = bsg_job->request; scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); struct qla_hw_data *ha = vha->hw; int i; struct qla_qpair *qpair; - ql_log(ql_log_info, vha, 0x708b, "%s CMD timeout. bsg ptr %p.\n", - __func__, bsg_job); + ql_log(ql_log_info, vha, 0x708b, + "%s CMD timeout. bsg ptr %p msgcode %x vendor cmd %x\n", + __func__, bsg_job, bsg_request->msgcode, + bsg_request->rqst_data.h_vendor.vendor_cmd[0]); if (qla2x00_isp_reg_stat(ha)) { ql_log(ql_log_info, vha, 0x9007, @@ -3136,7 +3197,6 @@ qla24xx_bsg_timeout(struct bsg_job *bsg_job) } ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n"); - bsg_reply->result = -ENXIO; done: return 0; diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 76703f2706b8e3..79879c4743e6dc 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -506,6 +506,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) return(NULL); } + vha->irq_offset = QLA_BASE_VECTORS; host = vha->host; fc_vport->dd_data = vha; /* New host info */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7f980e6141c282..7ab717ed72327e 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6902,12 +6902,15 @@ qla2x00_do_dpc(void *data) set_user_nice(current, MIN_NICE); set_current_state(TASK_INTERRUPTIBLE); - while (!kthread_should_stop()) { + while (1) { ql_dbg(ql_dbg_dpc, base_vha, 0x4000, "DPC handler sleeping.\n"); schedule(); + if (kthread_should_stop()) + break; + if (test_and_clear_bit(DO_EEH_RECOVERY, &base_vha->dpc_flags)) qla_pci_set_eeh_busy(base_vha); @@ -6920,15 +6923,16 @@ qla2x00_do_dpc(void *data) goto end_loop; } + if (test_bit(UNLOADING, &base_vha->dpc_flags)) + /* don't do any work. Wait to be terminated by kthread_stop */ + goto end_loop; + ha->dpc_active = 1; ql_dbg(ql_dbg_dpc + ql_dbg_verbose, base_vha, 0x4001, "DPC handler waking up, dpc_flags=0x%lx.\n", base_vha->dpc_flags); - if (test_bit(UNLOADING, &base_vha->dpc_flags)) - break; - if (IS_P3P_TYPE(ha)) { if (IS_QLA8044(ha)) { if (test_and_clear_bit(ISP_UNRECOVERABLE, @@ -7241,9 +7245,6 @@ qla2x00_do_dpc(void *data) */ ha->dpc_active = 0; - /* Cleanup any residual CTX SRBs. */ - qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); - return 0; } diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index cf0f9d9db64582..a491d6ee5c94c3 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -6,9 +6,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.02.09.300-k" +#define QLA2XXX_VERSION "10.02.09.400-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 2 #define QLA_DRIVER_PATCH_VER 9 -#define QLA_DRIVER_BETA_VER 300 +#define QLA_DRIVER_BETA_VER 400 diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 6177f4798f3ac9..74866b9f2b1452 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1463,7 +1463,7 @@ static struct platform_driver qpti_sbus_driver = { .of_match_table = qpti_match, }, .probe = qpti_sbus_probe, - .remove_new = qpti_sbus_remove, + .remove = qpti_sbus_remove, }; module_platform_driver(qpti_sbus_driver); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index b52513eeeafa75..680ba180a67252 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -6447,7 +6447,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, } sd_dp = &sqcp->sd_dp; - if (polled) + if (polled || (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)) ns_from_boot = ktime_get_boottime_ns(); /* one of the resp_*() response functions is called here */ diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 32f94db6d6bf5d..f3a1ecb42128a2 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1274,7 +1274,7 @@ static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj, } static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj, - struct bin_attribute *attr, int i) + const struct bin_attribute *attr, int i) { struct device *dev = kobj_to_dev(kobj); struct scsi_device *sdev = to_scsi_device(dev); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ca4bc0ac76adcf..8947dab132d789 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1190,8 +1190,8 @@ static u8 sd_group_number(struct scsi_cmnd *cmd) if (!sdkp->rscs) return 0; - return min3((u32)rq->write_hint, (u32)sdkp->permanent_stream_count, - 0x3fu); + return min3((u32)rq->bio->bi_write_hint, + (u32)sdkp->permanent_stream_count, 0x3fu); } static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write, @@ -1389,7 +1389,7 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks, protect | fua, dld); } else if ((nr_blocks > 0xff) || (lba > 0x1fffff) || - sdp->use_10_for_rw || protect || rq->write_hint) { + sdp->use_10_for_rw || protect || rq->bio->bi_write_hint) { ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks, protect | fua); } else { diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 6ab27f4f487844..7a447ff600d276 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -633,8 +633,6 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, struct queue_limits *lim, lim->max_open_zones = sdkp->zones_max_open; lim->max_active_zones = 0; lim->chunk_sectors = logical_to_sectors(sdkp->device, zone_blocks); - /* Enable block layer zone append emulation */ - lim->max_zone_append_sectors = 0; return 0; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index f86be197fedd04..94127868bedf8a 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -307,10 +307,6 @@ sg_open(struct inode *inode, struct file *filp) if (retval) goto sg_put; - retval = scsi_autopm_get_device(device); - if (retval) - goto sdp_put; - /* scsi_block_when_processing_errors() may block so bypass * check if O_NONBLOCK. Permits SCSI commands to be issued * during error recovery. Tread carefully. */ @@ -318,7 +314,7 @@ sg_open(struct inode *inode, struct file *filp) scsi_block_when_processing_errors(device))) { retval = -ENXIO; /* we are in error recovery for this device */ - goto error_out; + goto sdp_put; } mutex_lock(&sdp->open_rel_lock); @@ -371,8 +367,6 @@ sg_open(struct inode *inode, struct file *filp) } error_mutex_locked: mutex_unlock(&sdp->open_rel_lock); -error_out: - scsi_autopm_put_device(device); sdp_put: kref_put(&sdp->d_ref, sg_device_destroy); scsi_device_put(device); @@ -392,8 +386,6 @@ sg_release(struct inode *inode, struct file *filp) SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, "sg_release\n")); mutex_lock(&sdp->open_rel_lock); - scsi_autopm_put_device(sdp->device); - kref_put(&sfp->f_ref, sg_remove_sfp); sdp->open_cnt--; /* possibly many open()s waiting on exlude clearing, start many; @@ -405,6 +397,7 @@ sg_release(struct inode *inode, struct file *filp) wake_up_interruptible(&sdp->open_wait); } mutex_unlock(&sdp->open_rel_lock); + kref_put(&sfp->f_ref, sg_remove_sfp); return 0; } diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index b0bef83db7b60e..6594661db5f407 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -306,7 +306,7 @@ static void sgiwd93_remove(struct platform_device *pdev) static struct platform_driver sgiwd93_driver = { .probe = sgiwd93_probe, - .remove_new = sgiwd93_remove, + .remove = sgiwd93_remove, .driver = { .name = "sgiwd93", } diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 9df1c90a24c11b..d1d2556c8fc4b2 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -119,7 +119,7 @@ static void snirm710_driver_remove(struct platform_device *dev) static struct platform_driver snirm710_driver = { .probe = snirm710_probe, - .remove_new = snirm710_driver_remove, + .remove = snirm710_driver_remove, .driver = { .name = "snirm_53c710", }, diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index beb88f25dbb993..e8ef27d7ef6181 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -991,7 +991,10 @@ static int test_ready(struct scsi_tape *STp, int do_wait) scode = cmdstatp->sense_hdr.sense_key; if (scode == UNIT_ATTENTION) { /* New media? */ - new_session = 1; + if (cmdstatp->sense_hdr.asc == 0x28) { /* New media */ + new_session = 1; + DEBC_printk(STp, "New tape session."); + } if (attentions < MAX_ATTENTIONS) { attentions++; continue; @@ -3506,6 +3509,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) int i, cmd_nr, cmd_type, bt; int retval = 0; unsigned int blk; + bool cmd_mtiocget; struct scsi_tape *STp = file->private_data; struct st_modedef *STm; struct st_partstat *STps; @@ -3619,6 +3623,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) */ if (mtc.mt_op != MTREW && mtc.mt_op != MTOFFL && + mtc.mt_op != MTLOAD && mtc.mt_op != MTRETEN && mtc.mt_op != MTERASE && mtc.mt_op != MTSEEK && @@ -3732,17 +3737,28 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) goto out; } + cmd_mtiocget = cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET); + if ((i = flush_buffer(STp, 0)) < 0) { - retval = i; - goto out; - } - if (STp->can_partitions && - (i = switch_partition(STp)) < 0) { - retval = i; - goto out; + if (cmd_mtiocget && STp->pos_unknown) { + /* flush fails -> modify status accordingly */ + reset_state(STp); + STp->pos_unknown = 1; + } else { /* return error */ + retval = i; + goto out; + } + } else { /* flush_buffer succeeds */ + if (STp->can_partitions) { + i = switch_partition(STp); + if (i < 0) { + retval = i; + goto out; + } + } } - if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { + if (cmd_mtiocget) { struct mtget mt_status; if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { @@ -3756,7 +3772,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); mt_status.mt_blkno = STps->drv_block; mt_status.mt_fileno = STps->drv_file; - if (STp->block_size != 0) { + if (STp->block_size != 0 && mt_status.mt_blkno >= 0) { if (STps->rw == ST_WRITING) mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size; diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 7ceb982040a5df..d0b55c1fa908a5 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -149,6 +149,8 @@ struct hv_fc_wwn_packet { */ static int vmstor_proto_version; +static bool hv_dev_is_fc(struct hv_device *hv_dev); + #define STORVSC_LOGGING_NONE 0 #define STORVSC_LOGGING_ERROR 1 #define STORVSC_LOGGING_WARN 2 @@ -1138,6 +1140,7 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, * not correctly handle: * INQUIRY command with page code parameter set to 0x80 * MODE_SENSE command with cmd[2] == 0x1c + * MAINTENANCE_IN is not supported by HyperV FC passthrough * * Setup srb and scsi status so this won't be fatal. * We do this so we can distinguish truly fatal failues @@ -1145,7 +1148,9 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, */ if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || - (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) { + (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || + (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && + hv_dev_is_fc(device))) { vstor_packet->vm_srb.scsi_status = 0; vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; } diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index fffc0fa525940c..ca9cd691cc324d 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -656,8 +656,14 @@ static void __exit sun3_scsi_remove(struct platform_device *pdev) iounmap(ioaddr); } -static struct platform_driver sun3_scsi_driver = { - .remove_new = __exit_p(sun3_scsi_remove), +/* + * sun3_scsi_remove() lives in .exit.text. For drivers registered via + * module_platform_driver_probe() this is ok because they cannot get unbound at + * runtime. So mark the driver struct with __refdata to prevent modpost + * triggering a section mismatch warning. + */ +static struct platform_driver sun3_scsi_driver __refdata = { + .remove = __exit_p(sun3_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index e20f314cf3e7d7..365406885b8ef5 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -265,7 +265,7 @@ static void esp_sun3x_remove(struct platform_device *dev) static struct platform_driver esp_sun3x_driver = { .probe = esp_sun3x_probe, - .remove_new = esp_sun3x_remove, + .remove = esp_sun3x_remove, .driver = { .name = "sun3x_esp", }, diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index 5ce6c9d19d1e61..aa430501f0c719 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -603,7 +603,7 @@ static struct platform_driver esp_sbus_driver = { .of_match_table = esp_match, }, .probe = esp_sbus_probe, - .remove_new = esp_sbus_remove, + .remove = esp_sbus_remove, }; module_platform_driver(esp_sbus_driver); diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 74350b5871dc8e..ea571eeb307878 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -209,7 +209,6 @@ int __init register_intc_controller(struct intc_desc *desc) goto err0; INIT_LIST_HEAD(&d->list); - list_add_tail(&d->list, &intc_list); raw_spin_lock_init(&d->lock); INIT_RADIX_TREE(&d->tree, GFP_ATOMIC); @@ -369,6 +368,7 @@ int __init register_intc_controller(struct intc_desc *desc) d->skip_suspend = desc->skip_syscore_suspend; + list_add_tail(&d->list, &intc_list); nr_intc_controllers++; return 0; diff --git a/drivers/sh/intc/virq-debugfs.c b/drivers/sh/intc/virq-debugfs.c index 939915a07d9997..5dd8febe6da524 100644 --- a/drivers/sh/intc/virq-debugfs.c +++ b/drivers/sh/intc/virq-debugfs.c @@ -18,6 +18,7 @@ static int intc_irq_xlate_show(struct seq_file *m, void *priv) { + const unsigned int nr_irqs = irq_get_nr_irqs(); int i; seq_printf(m, "%-5s %-7s %-15s\n", "irq", "enum", "chip name"); diff --git a/drivers/slimbus/qcom-ctrl.c b/drivers/slimbus/qcom-ctrl.c index e25f9bdd9b2337..ab344f7472f254 100644 --- a/drivers/slimbus/qcom-ctrl.c +++ b/drivers/slimbus/qcom-ctrl.c @@ -722,7 +722,7 @@ MODULE_DEVICE_TABLE(of, qcom_slim_dt_match); static struct platform_driver qcom_slim_driver = { .probe = qcom_slim_probe, - .remove_new = qcom_slim_remove, + .remove = qcom_slim_remove, .driver = { .name = "qcom_slim_ctrl", .of_match_table = qcom_slim_dt_match, diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index 1ac8e2912fd1ce..4fb66986cc22e0 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -1743,7 +1743,7 @@ static const struct dev_pm_ops qcom_slim_ngd_dev_pm_ops = { static struct platform_driver qcom_slim_ngd_ctrl_driver = { .probe = qcom_slim_ngd_ctrl_probe, - .remove_new = qcom_slim_ngd_ctrl_remove, + .remove = qcom_slim_ngd_ctrl_remove, .driver = { .name = "qcom,slim-ngd-ctrl", .of_match_table = qcom_slim_ngd_dt_match, @@ -1752,7 +1752,7 @@ static struct platform_driver qcom_slim_ngd_ctrl_driver = { static struct platform_driver qcom_slim_ngd_driver = { .probe = qcom_slim_ngd_probe, - .remove_new = qcom_slim_ngd_remove, + .remove = qcom_slim_ngd_remove, .driver = { .name = QCOM_SLIM_NGD_DRV_NAME, .pm = &qcom_slim_ngd_dev_pm_ops, diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c index e87038009d1b2c..ee58151bd69ec9 100644 --- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c +++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c @@ -353,7 +353,7 @@ static struct platform_driver aspeed_lpc_ctrl_driver = { .of_match_table = aspeed_lpc_ctrl_match, }, .probe = aspeed_lpc_ctrl_probe, - .remove_new = aspeed_lpc_ctrl_remove, + .remove = aspeed_lpc_ctrl_remove, }; module_platform_driver(aspeed_lpc_ctrl_driver); diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c index 888b5840c01500..9ab5ba9cf1d61c 100644 --- a/drivers/soc/aspeed/aspeed-lpc-snoop.c +++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c @@ -366,7 +366,7 @@ static struct platform_driver aspeed_lpc_snoop_driver = { .of_match_table = aspeed_lpc_snoop_match, }, .probe = aspeed_lpc_snoop_probe, - .remove_new = aspeed_lpc_snoop_remove, + .remove = aspeed_lpc_snoop_remove, }; module_platform_driver(aspeed_lpc_snoop_driver); diff --git a/drivers/soc/aspeed/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c index 8610ddacc7bc9c..6cc943744e1295 100644 --- a/drivers/soc/aspeed/aspeed-p2a-ctrl.c +++ b/drivers/soc/aspeed/aspeed-p2a-ctrl.c @@ -431,7 +431,7 @@ static struct platform_driver aspeed_p2a_ctrl_driver = { .of_match_table = aspeed_p2a_ctrl_match, }, .probe = aspeed_p2a_ctrl_probe, - .remove_new = aspeed_p2a_ctrl_remove, + .remove = aspeed_p2a_ctrl_remove, }; module_platform_driver(aspeed_p2a_ctrl_driver); diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c index a2195f062e01b5..0191e36e66e10d 100644 --- a/drivers/soc/aspeed/aspeed-uart-routing.c +++ b/drivers/soc/aspeed/aspeed-uart-routing.c @@ -589,7 +589,7 @@ static struct platform_driver aspeed_uart_routing_driver = { .of_match_table = aspeed_uart_routing_table, }, .probe = aspeed_uart_routing_probe, - .remove_new = aspeed_uart_routing_remove, + .remove = aspeed_uart_routing_remove, }; module_platform_driver(aspeed_uart_routing_driver); diff --git a/drivers/soc/fsl/dpaa2-console.c b/drivers/soc/fsl/dpaa2-console.c index 6dbc77db771849..6310f54e68a213 100644 --- a/drivers/soc/fsl/dpaa2-console.c +++ b/drivers/soc/fsl/dpaa2-console.c @@ -320,7 +320,7 @@ static struct platform_driver dpaa2_console_driver = { .of_match_table = dpaa2_console_match_table, }, .probe = dpaa2_console_probe, - .remove_new = dpaa2_console_remove, + .remove = dpaa2_console_remove, }; module_platform_driver(dpaa2_console_driver); diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index b811446e0fa55f..0b60ed16297c64 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -891,7 +891,7 @@ void dpaa2_io_update_net_dim(struct dpaa2_io *d, __u64 frames, __u64 bytes) d->frames += frames; dim_update_sample(d->event_ctr, d->frames, d->bytes, &dim_sample); - net_dim(&d->rx_dim, dim_sample); + net_dim(&d->rx_dim, &dim_sample); spin_unlock(&d->dim_lock); } diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index 19cc581b06d0c8..36c0ccc06151f3 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -2004,8 +2004,10 @@ static int qmc_probe(struct platform_device *pdev) /* Set the irq handler */ irq = platform_get_irq(pdev, 0); - if (irq < 0) + if (irq < 0) { + ret = irq; goto err_exit_xcc; + } ret = devm_request_irq(qmc->dev, irq, qmc_irq_handler, 0, "qmc", qmc); if (ret < 0) goto err_exit_xcc; @@ -2092,7 +2094,7 @@ static struct platform_driver qmc_driver = { .of_match_table = of_match_ptr(qmc_id_table), }, .probe = qmc_probe, - .remove_new = qmc_remove, + .remove = qmc_remove, }; module_platform_driver(qmc_driver); diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index f0889b3fcaf2c2..4a88e54d25b949 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -680,7 +680,6 @@ static inline int tsa_of_parse_tdm_tx_route(struct tsa *tsa, static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) { - struct device_node *tdm_np; struct tsa_tdm *tdm; struct clk *clk; u32 tdm_id, val; @@ -691,11 +690,10 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) tsa->tdm[i].is_enable = false; - for_each_available_child_of_node(np, tdm_np) { + for_each_available_child_of_node_scoped(np, tdm_np) { ret = of_property_read_u32(tdm_np, "reg", &tdm_id); if (ret) { dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np); - of_node_put(tdm_np); return ret; } switch (tdm_id) { @@ -719,16 +717,14 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) invalid_tdm: dev_err(tsa->dev, "%pOF: Invalid tdm_id (%u)\n", tdm_np, tdm_id); - of_node_put(tdm_np); return -EINVAL; } } - for_each_available_child_of_node(np, tdm_np) { + for_each_available_child_of_node_scoped(np, tdm_np) { ret = of_property_read_u32(tdm_np, "reg", &tdm_id); if (ret) { dev_err(tsa->dev, "%pOF: failed to read reg\n", tdm_np); - of_node_put(tdm_np); return ret; } @@ -742,14 +738,12 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) dev_err(tsa->dev, "%pOF: failed to read fsl,rx-frame-sync-delay-bits\n", tdm_np); - of_node_put(tdm_np); return ret; } if (val > 3) { dev_err(tsa->dev, "%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n", tdm_np, val); - of_node_put(tdm_np); return -EINVAL; } tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val); @@ -761,14 +755,12 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) dev_err(tsa->dev, "%pOF: failed to read fsl,tx-frame-sync-delay-bits\n", tdm_np); - of_node_put(tdm_np); return ret; } if (val > 3) { dev_err(tsa->dev, "%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n", tdm_np, val); - of_node_put(tdm_np); return -EINVAL; } tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val); @@ -792,13 +784,11 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rsync" : "l1rsync"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(tdm_np); goto err; } ret = clk_prepare_enable(clk); if (ret) { clk_put(clk); - of_node_put(tdm_np); goto err; } tdm->l1rsync_clk = clk; @@ -806,13 +796,11 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rclk" : "l1rclk"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(tdm_np); goto err; } ret = clk_prepare_enable(clk); if (ret) { clk_put(clk); - of_node_put(tdm_np); goto err; } tdm->l1rclk_clk = clk; @@ -821,13 +809,11 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tsync" : "l1tsync"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(tdm_np); goto err; } ret = clk_prepare_enable(clk); if (ret) { clk_put(clk); - of_node_put(tdm_np); goto err; } tdm->l1tsync_clk = clk; @@ -835,13 +821,11 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tclk" : "l1tclk"); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - of_node_put(tdm_np); goto err; } ret = clk_prepare_enable(clk); if (ret) { clk_put(clk); - of_node_put(tdm_np); goto err; } tdm->l1tclk_clk = clk; @@ -859,16 +843,12 @@ static int tsa_of_parse_tdms(struct tsa *tsa, struct device_node *np) } ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id); - if (ret) { - of_node_put(tdm_np); + if (ret) goto err; - } ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id); - if (ret) { - of_node_put(tdm_np); + if (ret) goto err; - } tdm->is_enable = true; } @@ -1086,7 +1066,7 @@ static struct platform_driver tsa_driver = { .of_match_table = of_match_ptr(tsa_id_table), }, .probe = tsa_probe, - .remove_new = tsa_remove, + .remove = tsa_remove, }; module_platform_driver(tsa_driver); diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c index 3d0cae30c769ea..06bd94b29fb321 100644 --- a/drivers/soc/fsl/rcpm.c +++ b/drivers/soc/fsl/rcpm.c @@ -36,6 +36,7 @@ static void copy_ippdexpcr1_setting(u32 val) return; regs = of_iomap(np, 0); + of_node_put(np); if (!regs) return; diff --git a/drivers/soc/fujitsu/a64fx-diag.c b/drivers/soc/fujitsu/a64fx-diag.c index 330901893577ee..76cb0b6a221c27 100644 --- a/drivers/soc/fujitsu/a64fx-diag.c +++ b/drivers/soc/fujitsu/a64fx-diag.c @@ -142,7 +142,7 @@ static struct platform_driver a64fx_diag_driver = { .acpi_match_table = ACPI_PTR(a64fx_diag_acpi_match), }, .probe = a64fx_diag_probe, - .remove_new = a64fx_diag_remove, + .remove = a64fx_diag_remove, }; module_platform_driver(a64fx_diag_driver); diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index 4b0a099b28cc2e..6d7c244d2e784e 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -13,9 +13,12 @@ config KUNPENG_HCCS interconnection bus protocol. The performance of application may be affected if some HCCS ports are not in full lane status, have a large number of CRC - errors and so on. + errors and so on. This may support for reducing system power + consumption if there are HCCS ports supported low power feature + on platform. Say M here if you want to include support for querying the - health status and port information of HCCS on Kunpeng SoC. + health status and port information of HCCS, or reducing system + power consumption on Kunpeng SoC. endmenu diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c index e882a61636ec86..8aa8dec14911cd 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.c +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -21,11 +21,22 @@ * - if all enabled ports are in linked * - if all linked ports are in full lane * - CRC error count sum + * + * - Retrieve all HCCS types used on the platform. + * + * - Support low power feature for all specified HCCS type ports, and + * provide the following interface: + * - query HCCS types supported increasing and decreasing lane number. + * - decrease lane number of all specified HCCS type ports on idle state. + * - increase lane number of all specified HCCS type ports. */ #include +#include #include #include +#include #include +#include #include @@ -53,6 +64,42 @@ static struct hccs_chip_info *kobj_to_chip_info(struct kobject *k) return container_of(k, struct hccs_chip_info, kobj); } +static struct hccs_dev *device_kobj_to_hccs_dev(struct kobject *k) +{ + struct device *dev = container_of(k, struct device, kobj); + struct platform_device *pdev = + container_of(dev, struct platform_device, dev); + + return platform_get_drvdata(pdev); +} + +static char *hccs_port_type_to_name(struct hccs_dev *hdev, u8 type) +{ + u16 i; + + for (i = 0; i < hdev->used_type_num; i++) { + if (hdev->type_name_maps[i].type == type) + return hdev->type_name_maps[i].name; + } + + return NULL; +} + +static int hccs_name_to_port_type(struct hccs_dev *hdev, + const char *name, u8 *type) +{ + u16 i; + + for (i = 0; i < hdev->used_type_num; i++) { + if (strcmp(hdev->type_name_maps[i].name, name) == 0) { + *type = hdev->type_name_maps[i].type; + return 0; + } + } + + return -EINVAL; +} + struct hccs_register_ctx { struct device *dev; u8 chan_id; @@ -144,7 +191,7 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev) pcc_chan = pcc_mbox_request_channel(cl, hdev->chan_id); if (IS_ERR(pcc_chan)) { - dev_err(dev, "PPC channel request failed.\n"); + dev_err(dev, "PCC channel request failed.\n"); rc = -ENODEV; goto out; } @@ -170,15 +217,21 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev) goto err_mbx_channel_free; } - if (pcc_chan->shmem_base_addr) { - cl_info->pcc_comm_addr = ioremap(pcc_chan->shmem_base_addr, - pcc_chan->shmem_size); - if (!cl_info->pcc_comm_addr) { - dev_err(dev, "Failed to ioremap PCC communication region for channel-%u.\n", - hdev->chan_id); - rc = -ENOMEM; - goto err_mbx_channel_free; - } + if (!pcc_chan->shmem_base_addr || + pcc_chan->shmem_size != HCCS_PCC_SHARE_MEM_BYTES) { + dev_err(dev, "The base address or size (%llu) of PCC communication region is invalid.\n", + pcc_chan->shmem_size); + rc = -EINVAL; + goto err_mbx_channel_free; + } + + cl_info->pcc_comm_addr = ioremap(pcc_chan->shmem_base_addr, + pcc_chan->shmem_size); + if (!cl_info->pcc_comm_addr) { + dev_err(dev, "Failed to ioremap PCC communication region for channel-%u.\n", + hdev->chan_id); + rc = -ENOMEM; + goto err_mbx_channel_free; } return 0; @@ -451,6 +504,7 @@ static int hccs_query_all_die_info_on_platform(struct hccs_dev *hdev) struct device *dev = hdev->dev; struct hccs_chip_info *chip; struct hccs_die_info *die; + bool has_die_info = false; u8 i, j; int ret; @@ -459,6 +513,7 @@ static int hccs_query_all_die_info_on_platform(struct hccs_dev *hdev) if (!chip->die_num) continue; + has_die_info = true; chip->dies = devm_kzalloc(hdev->dev, chip->die_num * sizeof(struct hccs_die_info), GFP_KERNEL); @@ -480,7 +535,7 @@ static int hccs_query_all_die_info_on_platform(struct hccs_dev *hdev) } } - return 0; + return has_die_info ? 0 : -EINVAL; } static int hccs_get_bd_info(struct hccs_dev *hdev, u8 opcode, @@ -586,7 +641,7 @@ static int hccs_get_all_port_info_on_die(struct hccs_dev *hdev, port = &die->ports[i]; port->port_id = attrs[i].port_id; port->port_type = attrs[i].port_type; - port->lane_mode = attrs[i].lane_mode; + port->max_lane_num = attrs[i].max_lane_num; port->enable = attrs[i].enable; port->die = die; } @@ -601,6 +656,7 @@ static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev) struct device *dev = hdev->dev; struct hccs_chip_info *chip; struct hccs_die_info *die; + bool has_port_info = false; u8 i, j; int ret; @@ -611,6 +667,7 @@ static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev) if (!die->port_num) continue; + has_port_info = true; die->ports = devm_kzalloc(dev, die->port_num * sizeof(struct hccs_port_info), GFP_KERNEL); @@ -629,7 +686,7 @@ static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev) } } - return 0; + return has_port_info ? 0 : -EINVAL; } static int hccs_get_hw_info(struct hccs_dev *hdev) @@ -660,6 +717,55 @@ static int hccs_get_hw_info(struct hccs_dev *hdev) return 0; } +static u16 hccs_calc_used_type_num(struct hccs_dev *hdev, + unsigned long *hccs_ver) +{ + struct hccs_chip_info *chip; + struct hccs_port_info *port; + struct hccs_die_info *die; + u16 used_type_num = 0; + u16 i, j, k; + + for (i = 0; i < hdev->chip_num; i++) { + chip = &hdev->chips[i]; + for (j = 0; j < chip->die_num; j++) { + die = &chip->dies[j]; + for (k = 0; k < die->port_num; k++) { + port = &die->ports[k]; + set_bit(port->port_type, hccs_ver); + } + } + } + + for_each_set_bit(i, hccs_ver, HCCS_IP_MAX + 1) + used_type_num++; + + return used_type_num; +} + +static int hccs_init_type_name_maps(struct hccs_dev *hdev) +{ + DECLARE_BITMAP(hccs_ver, HCCS_IP_MAX + 1) = {}; + unsigned int i; + u16 idx = 0; + + hdev->used_type_num = hccs_calc_used_type_num(hdev, hccs_ver); + hdev->type_name_maps = devm_kcalloc(hdev->dev, hdev->used_type_num, + sizeof(struct hccs_type_name_map), + GFP_KERNEL); + if (!hdev->type_name_maps) + return -ENOMEM; + + for_each_set_bit(i, hccs_ver, HCCS_IP_MAX + 1) { + hdev->type_name_maps[idx].type = i; + sprintf(hdev->type_name_maps[idx].name, + "%s%u", HCCS_IP_PREFIX, i); + idx++; + } + + return 0; +} + static int hccs_query_port_link_status(struct hccs_dev *hdev, const struct hccs_port_info *port, struct hccs_link_status *link_status) @@ -820,7 +926,7 @@ static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, { const struct hccs_port_info *port = kobj_to_port_info(kobj); - return sysfs_emit(buf, "HCCS-v%u\n", port->port_type); + return sysfs_emit(buf, "%s%u\n", HCCS_IP_PREFIX, port->port_type); } static struct kobj_attribute hccs_type_attr = __ATTR_RO(type); @@ -829,7 +935,7 @@ static ssize_t lane_mode_show(struct kobject *kobj, struct kobj_attribute *attr, { const struct hccs_port_info *port = kobj_to_port_info(kobj); - return sysfs_emit(buf, "x%u\n", port->lane_mode); + return sysfs_emit(buf, "x%u\n", port->max_lane_num); } static struct kobj_attribute lane_mode_attr = __ATTR_RO(lane_mode); @@ -1124,6 +1230,372 @@ static const struct kobj_type hccs_chip_type = { .default_groups = hccs_chip_default_groups, }; +static int hccs_parse_pm_port_type(struct hccs_dev *hdev, const char *buf, + u8 *port_type) +{ + char hccs_name[HCCS_NAME_MAX_LEN + 1] = ""; + u8 type; + int ret; + + ret = sscanf(buf, "%" __stringify(HCCS_NAME_MAX_LEN) "s", hccs_name); + if (ret != 1) + return -EINVAL; + + ret = hccs_name_to_port_type(hdev, hccs_name, &type); + if (ret) { + dev_dbg(hdev->dev, "input invalid, please get the available types from 'used_types'.\n"); + return ret; + } + + if (type == HCCS_V2 && hdev->caps & HCCS_CAPS_HCCS_V2_PM) { + *port_type = type; + return 0; + } + + dev_dbg(hdev->dev, "%s doesn't support for increasing and decreasing lane.\n", + hccs_name); + + return -EOPNOTSUPP; +} + +static int hccs_query_port_idle_status(struct hccs_dev *hdev, + struct hccs_port_info *port, u8 *idle) +{ + const struct hccs_die_info *die = port->die; + const struct hccs_chip_info *chip = die->chip; + struct hccs_port_comm_req_param *req_param; + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + req_param = (struct hccs_port_comm_req_param *)desc.req.data; + req_param->chip_id = chip->chip_id; + req_param->die_id = die->die_id; + req_param->port_id = port->port_id; + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_PORT_IDLE_STATUS, &desc); + if (ret) { + dev_err(hdev->dev, + "get port idle status failed, ret = %d.\n", ret); + return ret; + } + + *idle = *((u8 *)desc.rsp.data); + return 0; +} + +static int hccs_get_all_spec_port_idle_sta(struct hccs_dev *hdev, u8 port_type, + bool *all_idle) +{ + struct hccs_chip_info *chip; + struct hccs_port_info *port; + struct hccs_die_info *die; + int ret = 0; + u8 i, j, k; + u8 idle; + + *all_idle = false; + for (i = 0; i < hdev->chip_num; i++) { + chip = &hdev->chips[i]; + for (j = 0; j < chip->die_num; j++) { + die = &chip->dies[j]; + for (k = 0; k < die->port_num; k++) { + port = &die->ports[k]; + if (port->port_type != port_type) + continue; + ret = hccs_query_port_idle_status(hdev, port, + &idle); + if (ret) { + dev_err(hdev->dev, + "hccs%u on chip%u/die%u get idle status failed, ret = %d.\n", + k, i, j, ret); + return ret; + } else if (idle == 0) { + dev_info(hdev->dev, "hccs%u on chip%u/die%u is busy.\n", + k, i, j); + return 0; + } + } + } + } + *all_idle = true; + + return 0; +} + +static int hccs_get_all_spec_port_full_lane_sta(struct hccs_dev *hdev, + u8 port_type, bool *full_lane) +{ + struct hccs_link_status status = {0}; + struct hccs_chip_info *chip; + struct hccs_port_info *port; + struct hccs_die_info *die; + u8 i, j, k; + int ret; + + *full_lane = false; + for (i = 0; i < hdev->chip_num; i++) { + chip = &hdev->chips[i]; + for (j = 0; j < chip->die_num; j++) { + die = &chip->dies[j]; + for (k = 0; k < die->port_num; k++) { + port = &die->ports[k]; + if (port->port_type != port_type) + continue; + ret = hccs_query_port_link_status(hdev, port, + &status); + if (ret) + return ret; + if (status.lane_num != port->max_lane_num) + return 0; + } + } + } + *full_lane = true; + + return 0; +} + +static int hccs_prepare_inc_lane(struct hccs_dev *hdev, u8 type) +{ + struct hccs_inc_lane_req_param *req_param; + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + req_param = (struct hccs_inc_lane_req_param *)desc.req.data; + req_param->port_type = type; + req_param->opt_type = HCCS_PREPARE_INC_LANE; + ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc); + if (ret) + dev_err(hdev->dev, "prepare for increasing lane failed, ret = %d.\n", + ret); + + return ret; +} + +static int hccs_wait_serdes_adapt_completed(struct hccs_dev *hdev, u8 type) +{ +#define HCCS_MAX_WAIT_CNT_FOR_ADAPT 10 +#define HCCS_QUERY_ADAPT_RES_DELAY_MS 100 +#define HCCS_SERDES_ADAPT_OK 0 + + struct hccs_inc_lane_req_param *req_param; + u8 wait_cnt = HCCS_MAX_WAIT_CNT_FOR_ADAPT; + struct hccs_desc desc; + u8 adapt_res; + int ret; + + do { + hccs_init_req_desc(&desc); + req_param = (struct hccs_inc_lane_req_param *)desc.req.data; + req_param->port_type = type; + req_param->opt_type = HCCS_GET_ADAPT_RES; + ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc); + if (ret) { + dev_err(hdev->dev, "query adapting result failed, ret = %d.\n", + ret); + return ret; + } + adapt_res = *((u8 *)&desc.rsp.data); + if (adapt_res == HCCS_SERDES_ADAPT_OK) + return 0; + + msleep(HCCS_QUERY_ADAPT_RES_DELAY_MS); + } while (--wait_cnt); + + dev_err(hdev->dev, "wait for adapting completed timeout.\n"); + + return -ETIMEDOUT; +} + +static int hccs_start_hpcs_retraining(struct hccs_dev *hdev, u8 type) +{ + struct hccs_inc_lane_req_param *req_param; + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + req_param = (struct hccs_inc_lane_req_param *)desc.req.data; + req_param->port_type = type; + req_param->opt_type = HCCS_START_RETRAINING; + ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc); + if (ret) + dev_err(hdev->dev, "start hpcs retraining failed, ret = %d.\n", + ret); + + return ret; +} + +static int hccs_start_inc_lane(struct hccs_dev *hdev, u8 type) +{ + int ret; + + ret = hccs_prepare_inc_lane(hdev, type); + if (ret) + return ret; + + ret = hccs_wait_serdes_adapt_completed(hdev, type); + if (ret) + return ret; + + return hccs_start_hpcs_retraining(hdev, type); +} + +static int hccs_start_dec_lane(struct hccs_dev *hdev, u8 type) +{ + struct hccs_desc desc; + u8 *port_type; + int ret; + + hccs_init_req_desc(&desc); + port_type = (u8 *)desc.req.data; + *port_type = type; + ret = hccs_pcc_cmd_send(hdev, HCCS_PM_DEC_LANE, &desc); + if (ret) + dev_err(hdev->dev, "start to decrease lane failed, ret = %d.\n", + ret); + + return ret; +} + +static ssize_t dec_lane_of_type_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); + bool all_in_idle; + u8 port_type; + int ret; + + ret = hccs_parse_pm_port_type(hdev, buf, &port_type); + if (ret) + return ret; + + mutex_lock(&hdev->lock); + ret = hccs_get_all_spec_port_idle_sta(hdev, port_type, &all_in_idle); + if (ret) + goto out; + if (!all_in_idle) { + ret = -EBUSY; + dev_err(hdev->dev, "please don't decrese lanes on high load with %s, ret = %d.\n", + hccs_port_type_to_name(hdev, port_type), ret); + goto out; + } + + ret = hccs_start_dec_lane(hdev, port_type); +out: + mutex_unlock(&hdev->lock); + + return ret == 0 ? count : ret; +} +static struct kobj_attribute dec_lane_of_type_attr = + __ATTR(dec_lane_of_type, 0200, NULL, dec_lane_of_type_store); + +static ssize_t inc_lane_of_type_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); + bool full_lane; + u8 port_type; + int ret; + + ret = hccs_parse_pm_port_type(hdev, buf, &port_type); + if (ret) + return ret; + + mutex_lock(&hdev->lock); + ret = hccs_get_all_spec_port_full_lane_sta(hdev, port_type, &full_lane); + if (ret || full_lane) + goto out; + + ret = hccs_start_inc_lane(hdev, port_type); +out: + mutex_unlock(&hdev->lock); + return ret == 0 ? count : ret; +} +static struct kobj_attribute inc_lane_of_type_attr = + __ATTR(inc_lane_of_type, 0200, NULL, inc_lane_of_type_store); + +static ssize_t available_inc_dec_lane_types_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); + + if (hdev->caps & HCCS_CAPS_HCCS_V2_PM) + return sysfs_emit(buf, "%s\n", + hccs_port_type_to_name(hdev, HCCS_V2)); + + return -EINVAL; +} +static struct kobj_attribute available_inc_dec_lane_types_attr = + __ATTR(available_inc_dec_lane_types, 0444, + available_inc_dec_lane_types_show, NULL); + +static ssize_t used_types_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); + int len = 0; + u16 i; + + for (i = 0; i < hdev->used_type_num - 1; i++) + len += sysfs_emit(&buf[len], "%s ", hdev->type_name_maps[i].name); + len += sysfs_emit(&buf[len], "%s\n", hdev->type_name_maps[i].name); + + return len; +} +static struct kobj_attribute used_types_attr = + __ATTR(used_types, 0444, used_types_show, NULL); + +static void hccs_remove_misc_sysfs(struct hccs_dev *hdev) +{ + sysfs_remove_file(&hdev->dev->kobj, &used_types_attr.attr); + + if (!(hdev->caps & HCCS_CAPS_HCCS_V2_PM)) + return; + + sysfs_remove_file(&hdev->dev->kobj, + &available_inc_dec_lane_types_attr.attr); + sysfs_remove_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr); + sysfs_remove_file(&hdev->dev->kobj, &inc_lane_of_type_attr.attr); +} + +static int hccs_add_misc_sysfs(struct hccs_dev *hdev) +{ + int ret; + + ret = sysfs_create_file(&hdev->dev->kobj, &used_types_attr.attr); + if (ret) + return ret; + + if (!(hdev->caps & HCCS_CAPS_HCCS_V2_PM)) + return 0; + + ret = sysfs_create_file(&hdev->dev->kobj, + &available_inc_dec_lane_types_attr.attr); + if (ret) + goto used_types_remove; + + ret = sysfs_create_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr); + if (ret) + goto inc_dec_lane_types_remove; + + ret = sysfs_create_file(&hdev->dev->kobj, &inc_lane_of_type_attr.attr); + if (ret) + goto dec_lane_of_type_remove; + + return 0; + +dec_lane_of_type_remove: + sysfs_remove_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr); +inc_dec_lane_types_remove: + sysfs_remove_file(&hdev->dev->kobj, + &available_inc_dec_lane_types_attr.attr); +used_types_remove: + sysfs_remove_file(&hdev->dev->kobj, &used_types_attr.attr); + return ret; +} + static void hccs_remove_die_dir(struct hccs_die_info *die) { struct hccs_port_info *port; @@ -1158,6 +1630,8 @@ static void hccs_remove_topo_dirs(struct hccs_dev *hdev) for (i = 0; i < hdev->chip_num; i++) hccs_remove_chip_dir(&hdev->chips[i]); + + hccs_remove_misc_sysfs(hdev); } static int hccs_create_hccs_dir(struct hccs_dev *hdev, @@ -1253,6 +1727,12 @@ static int hccs_create_topo_dirs(struct hccs_dev *hdev) } } + ret = hccs_add_misc_sysfs(hdev); + if (ret) { + dev_err(hdev->dev, "create misc sysfs interface failed, ret = %d\n", ret); + goto err; + } + return 0; err: for (k = 0; k < id; k++) @@ -1303,6 +1783,10 @@ static int hccs_probe(struct platform_device *pdev) if (rc) goto unregister_pcc_chan; + rc = hccs_init_type_name_maps(hdev); + if (rc) + goto unregister_pcc_chan; + rc = hccs_create_topo_dirs(hdev); if (rc) goto unregister_pcc_chan; @@ -1348,7 +1832,7 @@ MODULE_DEVICE_TABLE(acpi, hccs_acpi_match); static struct platform_driver hccs_driver = { .probe = hccs_probe, - .remove_new = hccs_remove, + .remove = hccs_remove, .driver = { .name = "kunpeng_hccs", .acpi_match_table = hccs_acpi_match, diff --git a/drivers/soc/hisilicon/kunpeng_hccs.h b/drivers/soc/hisilicon/kunpeng_hccs.h index c3adbc01b4719b..dc267136919b7b 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.h +++ b/drivers/soc/hisilicon/kunpeng_hccs.h @@ -10,6 +10,19 @@ * | P0 | P1 | P2 | P3 | P0 | P1 | P2 | P3 | P0 | P1 | P2 | P3 |P0 | P1 | P2 | P3 | */ +enum hccs_port_type { + HCCS_V1 = 1, + HCCS_V2, +}; + +#define HCCS_IP_PREFIX "HCCS-v" +#define HCCS_IP_MAX 255 +#define HCCS_NAME_MAX_LEN 9 +struct hccs_type_name_map { + u8 type; + char name[HCCS_NAME_MAX_LEN + 1]; +}; + /* * This value cannot be 255, otherwise the loop of the multi-BD communication * case cannot end. @@ -19,7 +32,7 @@ struct hccs_port_info { u8 port_id; u8 port_type; - u8 lane_mode; + u8 max_lane_num; bool enable; /* if the port is enabled */ struct kobject kobj; bool dir_created; @@ -67,13 +80,18 @@ struct hccs_verspecific_data { bool has_txdone_irq; }; +#define HCCS_CAPS_HCCS_V2_PM BIT_ULL(0) + struct hccs_dev { struct device *dev; struct acpi_device *acpi_dev; const struct hccs_verspecific_data *verspec_data; + /* device capabilities from firmware, like HCCS_CAPS_xxx. */ u64 caps; u8 chip_num; struct hccs_chip_info *chips; + u16 used_type_num; + struct hccs_type_name_map *type_name_maps; u8 chan_id; struct mutex lock; struct hccs_mbox_client_info cl_info; @@ -91,6 +109,9 @@ enum hccs_subcmd_type { HCCS_GET_DIE_PORTS_LANE_STA, HCCS_GET_DIE_PORTS_LINK_STA, HCCS_GET_DIE_PORTS_CRC_ERR_CNT, + HCCS_GET_PORT_IDLE_STATUS, + HCCS_PM_DEC_LANE, + HCCS_PM_INC_LANE, HCCS_SUB_CMD_MAX = 255, }; @@ -113,7 +134,7 @@ struct hccs_die_info_rsp_data { struct hccs_port_attr { u8 port_id; u8 port_type; - u8 lane_mode; + u8 max_lane_num; u8 enable : 1; /* if the port is enabled */ u16 rsv[2]; }; @@ -134,6 +155,14 @@ struct hccs_port_comm_req_param { u8 port_id; }; +#define HCCS_PREPARE_INC_LANE 1 +#define HCCS_GET_ADAPT_RES 2 +#define HCCS_START_RETRAINING 3 +struct hccs_inc_lane_req_param { + u8 port_type; + u8 opt_type; +}; + #define HCCS_PORT_RESET 1 #define HCCS_PORT_SETUP 2 #define HCCS_PORT_CONFIG 3 diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c index fe111bae38c8e1..8ac7658e3d5255 100644 --- a/drivers/soc/imx/soc-imx8m.c +++ b/drivers/soc/imx/soc-imx8m.c @@ -30,11 +30,9 @@ struct imx8_soc_data { char *name; - u32 (*soc_revision)(void); + int (*soc_revision)(u32 *socrev, u64 *socuid); }; -static u64 soc_uid; - #ifdef CONFIG_HAVE_ARM_SMCCC static u32 imx8mq_soc_revision_from_atf(void) { @@ -51,24 +49,27 @@ static u32 imx8mq_soc_revision_from_atf(void) static inline u32 imx8mq_soc_revision_from_atf(void) { return 0; }; #endif -static u32 __init imx8mq_soc_revision(void) +static int imx8mq_soc_revision(u32 *socrev, u64 *socuid) { - struct device_node *np; + struct device_node *np __free(device_node) = + of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp"); void __iomem *ocotp_base; u32 magic; u32 rev; struct clk *clk; + int ret; - np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp"); if (!np) - return 0; + return -EINVAL; ocotp_base = of_iomap(np, 0); - WARN_ON(!ocotp_base); + if (!ocotp_base) + return -EINVAL; + clk = of_clk_get_by_name(np, NULL); if (IS_ERR(clk)) { - WARN_ON(IS_ERR(clk)); - return 0; + ret = PTR_ERR(clk); + goto err_clk; } clk_prepare_enable(clk); @@ -84,71 +85,78 @@ static u32 __init imx8mq_soc_revision(void) rev = REV_B1; } - soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); - soc_uid <<= 32; - soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); + *socuid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH); + *socuid <<= 32; + *socuid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW); + + *socrev = rev; clk_disable_unprepare(clk); clk_put(clk); iounmap(ocotp_base); - of_node_put(np); - return rev; + return 0; + +err_clk: + iounmap(ocotp_base); + return ret; } -static void __init imx8mm_soc_uid(void) +static int imx8mm_soc_uid(u64 *socuid) { + struct device_node *np __free(device_node) = + of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp"); void __iomem *ocotp_base; - struct device_node *np; struct clk *clk; + int ret = 0; u32 offset = of_machine_is_compatible("fsl,imx8mp") ? IMX8MP_OCOTP_UID_OFFSET : 0; - np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp"); if (!np) - return; + return -EINVAL; ocotp_base = of_iomap(np, 0); - WARN_ON(!ocotp_base); + if (!ocotp_base) + return -EINVAL; + clk = of_clk_get_by_name(np, NULL); if (IS_ERR(clk)) { - WARN_ON(IS_ERR(clk)); - return; + ret = PTR_ERR(clk); + goto err_clk; } clk_prepare_enable(clk); - soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + offset); - soc_uid <<= 32; - soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + offset); + *socuid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + offset); + *socuid <<= 32; + *socuid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + offset); clk_disable_unprepare(clk); clk_put(clk); + +err_clk: iounmap(ocotp_base); - of_node_put(np); + return ret; } -static u32 __init imx8mm_soc_revision(void) +static int imx8mm_soc_revision(u32 *socrev, u64 *socuid) { - struct device_node *np; + struct device_node *np __free(device_node) = + of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop"); void __iomem *anatop_base; - u32 rev; - np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop"); if (!np) - return 0; + return -EINVAL; anatop_base = of_iomap(np, 0); - WARN_ON(!anatop_base); + if (!anatop_base) + return -EINVAL; - rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM); + *socrev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM); iounmap(anatop_base); - of_node_put(np); - - imx8mm_soc_uid(); - return rev; + return imx8mm_soc_uid(socuid); } static const struct imx8_soc_data imx8mq_soc_data = { @@ -179,21 +187,23 @@ static __maybe_unused const struct of_device_id imx8_soc_match[] = { { } }; -#define imx8_revision(soc_rev) \ - soc_rev ? \ - kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ +#define imx8_revision(dev, soc_rev) \ + (soc_rev) ? \ + devm_kasprintf((dev), GFP_KERNEL, "%d.%d", ((soc_rev) >> 4) & 0xf, (soc_rev) & 0xf) : \ "unknown" -static int __init imx8_soc_init(void) +static int imx8m_soc_probe(struct platform_device *pdev) { struct soc_device_attribute *soc_dev_attr; - struct soc_device *soc_dev; + const struct imx8_soc_data *data; + struct device *dev = &pdev->dev; const struct of_device_id *id; + struct soc_device *soc_dev; u32 soc_rev = 0; - const struct imx8_soc_data *data; + u64 soc_uid = 0; int ret; - soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + soc_dev_attr = devm_kzalloc(dev, sizeof(*soc_dev_attr), GFP_KERNEL); if (!soc_dev_attr) return -ENOMEM; @@ -201,38 +211,33 @@ static int __init imx8_soc_init(void) ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine); if (ret) - goto free_soc; + return ret; id = of_match_node(imx8_soc_match, of_root); - if (!id) { - ret = -ENODEV; - goto free_soc; - } + if (!id) + return -ENODEV; data = id->data; if (data) { soc_dev_attr->soc_id = data->name; - if (data->soc_revision) - soc_rev = data->soc_revision(); + if (data->soc_revision) { + ret = data->soc_revision(&soc_rev, &soc_uid); + if (ret) + return ret; + } } - soc_dev_attr->revision = imx8_revision(soc_rev); - if (!soc_dev_attr->revision) { - ret = -ENOMEM; - goto free_soc; - } + soc_dev_attr->revision = imx8_revision(dev, soc_rev); + if (!soc_dev_attr->revision) + return -ENOMEM; - soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); - if (!soc_dev_attr->serial_number) { - ret = -ENOMEM; - goto free_rev; - } + soc_dev_attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, "%016llX", soc_uid); + if (!soc_dev_attr->serial_number) + return -ENOMEM; soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) { - ret = PTR_ERR(soc_dev); - goto free_serial_number; - } + if (IS_ERR(soc_dev)) + return PTR_ERR(soc_dev); pr_info("SoC: %s revision %s\n", soc_dev_attr->soc_id, soc_dev_attr->revision); @@ -241,15 +246,38 @@ static int __init imx8_soc_init(void) platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0); return 0; +} -free_serial_number: - kfree(soc_dev_attr->serial_number); -free_rev: - if (strcmp(soc_dev_attr->revision, "unknown")) - kfree(soc_dev_attr->revision); -free_soc: - kfree(soc_dev_attr); - return ret; +static struct platform_driver imx8m_soc_driver = { + .probe = imx8m_soc_probe, + .driver = { + .name = "imx8m-soc", + }, +}; + +static int __init imx8_soc_init(void) +{ + struct platform_device *pdev; + int ret; + + /* No match means this is non-i.MX8M hardware, do nothing. */ + if (!of_match_node(imx8_soc_match, of_root)) + return 0; + + ret = platform_driver_register(&imx8m_soc_driver); + if (ret) { + pr_err("Failed to register imx8m-soc platform driver: %d\n", ret); + return ret; + } + + pdev = platform_device_register_simple("imx8m-soc", -1, NULL, 0); + if (IS_ERR(pdev)) { + pr_err("Failed to register imx8m-soc platform device: %ld\n", PTR_ERR(pdev)); + platform_driver_unregister(&imx8m_soc_driver); + return PTR_ERR(pdev); + } + + return 0; } device_initcall(imx8_soc_init); MODULE_DESCRIPTION("NXP i.MX8M SoC driver"); diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c index 34a6f187c220d4..33e2e0366f19c3 100644 --- a/drivers/soc/ixp4xx/ixp4xx-npe.c +++ b/drivers/soc/ixp4xx/ixp4xx-npe.c @@ -759,7 +759,7 @@ static struct platform_driver ixp4xx_npe_driver = { .of_match_table = ixp4xx_npe_of_match, }, .probe = ixp4xx_npe_probe, - .remove_new = ixp4xx_npe_remove, + .remove = ixp4xx_npe_remove, }; module_platform_driver(ixp4xx_npe_driver); diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c index cb112f3643e975..475e229039e30c 100644 --- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c +++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c @@ -461,7 +461,7 @@ static struct platform_driver ixp4xx_qmgr_driver = { .of_match_table = ixp4xx_qmgr_of_match, }, .probe = ixp4xx_qmgr_probe, - .remove_new = ixp4xx_qmgr_remove, + .remove = ixp4xx_qmgr_remove, }; module_platform_driver(ixp4xx_qmgr_driver); diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c index 72c44119dd5418..d08bfc8ef7be7a 100644 --- a/drivers/soc/litex/litex_soc_ctrl.c +++ b/drivers/soc/litex/litex_soc_ctrl.c @@ -131,7 +131,7 @@ static struct platform_driver litex_soc_ctrl_driver = { .of_match_table = litex_soc_ctrl_of_match, }, .probe = litex_soc_ctrl_probe, - .remove_new = litex_soc_ctrl_remove, + .remove = litex_soc_ctrl_remove, }; module_platform_driver(litex_soc_ctrl_driver); diff --git a/drivers/soc/loongson/loongson2_guts.c b/drivers/soc/loongson/loongson2_guts.c index ef352a0f502208..ae42e3a9127fc1 100644 --- a/drivers/soc/loongson/loongson2_guts.c +++ b/drivers/soc/loongson/loongson2_guts.c @@ -169,7 +169,7 @@ static struct platform_driver loongson2_guts_driver = { .of_match_table = loongson2_guts_of_match, }, .probe = loongson2_guts_probe, - .remove_new = loongson2_guts_remove, + .remove = loongson2_guts_remove, }; static int __init loongson2_guts_init(void) diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index 1b7afb19ccd637..d7293977f06e80 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -26,6 +26,17 @@ config MTK_DEVAPC The violation information is logged for further analysis or countermeasures. +config MTK_DVFSRC + tristate "MediaTek DVFSRC Support" + depends on ARCH_MEDIATEK + help + Say yes here to add support for the MediaTek Dynamic Voltage + and Frequency Scaling Resource Collector (DVFSRC): a HW + IP found on many MediaTek SoCs, which is responsible for + collecting DVFS requests from various SoC IPs, other than + software, and performing bandwidth scaling to provide the + best achievable performance-per-watt. + config MTK_INFRACFG bool "MediaTek INFRACFG Support" select REGMAP diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index 6830512848fd0f..0665573e3c4b3b 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o obj-$(CONFIG_MTK_DEVAPC) += mtk-devapc.o +obj-$(CONFIG_MTK_DVFSRC) += mtk-dvfsrc.o obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o obj-$(CONFIG_MTK_REGULATOR_COUPLER) += mtk-regulator-coupler.o diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c index a8fccedba83f28..0a05ee87a0fce8 100644 --- a/drivers/soc/mediatek/mtk-cmdq-helper.c +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -180,15 +180,23 @@ static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, return 0; } -int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) +static int cmdq_pkt_mask(struct cmdq_pkt *pkt, u32 mask) { - struct cmdq_instruction inst; - - inst.op = CMDQ_CODE_WRITE; - inst.value = value; - inst.offset = offset; - inst.subsys = subsys; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_MASK, + .mask = ~mask + }; + return cmdq_pkt_append_command(pkt, inst); +} +int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) +{ + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WRITE, + .value = value, + .offset = offset, + .subsys = subsys + }; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_write); @@ -196,36 +204,30 @@ EXPORT_SYMBOL(cmdq_pkt_write); int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask) { - struct cmdq_instruction inst = { {0} }; u16 offset_mask = offset; int err; - if (mask != 0xffffffff) { - inst.op = CMDQ_CODE_MASK; - inst.mask = ~mask; - err = cmdq_pkt_append_command(pkt, inst); + if (mask != GENMASK(31, 0)) { + err = cmdq_pkt_mask(pkt, mask); if (err < 0) return err; offset_mask |= CMDQ_WRITE_ENABLE_MASK; } - err = cmdq_pkt_write(pkt, subsys, offset_mask, value); - - return err; + return cmdq_pkt_write(pkt, subsys, offset_mask, value); } EXPORT_SYMBOL(cmdq_pkt_write_mask); int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low, u16 reg_idx) { - struct cmdq_instruction inst = {}; - - inst.op = CMDQ_CODE_READ_S; - inst.dst_t = CMDQ_REG_TYPE; - inst.sop = high_addr_reg_idx; - inst.reg_dst = reg_idx; - inst.src_reg = addr_low; - + struct cmdq_instruction inst = { + .op = CMDQ_CODE_READ_S, + .dst_t = CMDQ_REG_TYPE, + .sop = high_addr_reg_idx, + .reg_dst = reg_idx, + .src_reg = addr_low + }; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_read_s); @@ -233,14 +235,13 @@ EXPORT_SYMBOL(cmdq_pkt_read_s); int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low, u16 src_reg_idx) { - struct cmdq_instruction inst = {}; - - inst.op = CMDQ_CODE_WRITE_S; - inst.src_t = CMDQ_REG_TYPE; - inst.sop = high_addr_reg_idx; - inst.offset = addr_low; - inst.src_reg = src_reg_idx; - + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WRITE_S, + .src_t = CMDQ_REG_TYPE, + .sop = high_addr_reg_idx, + .offset = addr_low, + .src_reg = src_reg_idx + }; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_write_s); @@ -248,22 +249,19 @@ EXPORT_SYMBOL(cmdq_pkt_write_s); int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low, u16 src_reg_idx, u32 mask) { - struct cmdq_instruction inst = {}; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WRITE_S_MASK, + .src_t = CMDQ_REG_TYPE, + .sop = high_addr_reg_idx, + .offset = addr_low, + .src_reg = src_reg_idx, + }; int err; - inst.op = CMDQ_CODE_MASK; - inst.mask = ~mask; - err = cmdq_pkt_append_command(pkt, inst); + err = cmdq_pkt_mask(pkt, mask); if (err < 0) return err; - inst.mask = 0; - inst.op = CMDQ_CODE_WRITE_S_MASK; - inst.src_t = CMDQ_REG_TYPE; - inst.sop = high_addr_reg_idx; - inst.offset = addr_low; - inst.src_reg = src_reg_idx; - return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_write_s_mask); @@ -271,13 +269,12 @@ EXPORT_SYMBOL(cmdq_pkt_write_s_mask); int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, u16 addr_low, u32 value) { - struct cmdq_instruction inst = {}; - - inst.op = CMDQ_CODE_WRITE_S; - inst.sop = high_addr_reg_idx; - inst.offset = addr_low; - inst.value = value; - + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WRITE_S, + .sop = high_addr_reg_idx, + .offset = addr_low, + .value = value + }; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_write_s_value); @@ -285,20 +282,18 @@ EXPORT_SYMBOL(cmdq_pkt_write_s_value); int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, u16 addr_low, u32 value, u32 mask) { - struct cmdq_instruction inst = {}; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WRITE_S_MASK, + .sop = high_addr_reg_idx, + .offset = addr_low, + .value = value + }; int err; - inst.op = CMDQ_CODE_MASK; - inst.mask = ~mask; - err = cmdq_pkt_append_command(pkt, inst); + err = cmdq_pkt_mask(pkt, mask); if (err < 0) return err; - inst.op = CMDQ_CODE_WRITE_S_MASK; - inst.sop = high_addr_reg_idx; - inst.offset = addr_low; - inst.value = value; - return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value); @@ -331,61 +326,61 @@ EXPORT_SYMBOL(cmdq_pkt_mem_move); int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear) { - struct cmdq_instruction inst = { {0} }; u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WFE, + .value = CMDQ_WFE_OPTION | clear_option, + .event = event + }; if (event >= CMDQ_MAX_EVENT) return -EINVAL; - inst.op = CMDQ_CODE_WFE; - inst.value = CMDQ_WFE_OPTION | clear_option; - inst.event = event; - return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_wfe); int cmdq_pkt_acquire_event(struct cmdq_pkt *pkt, u16 event) { - struct cmdq_instruction inst = {}; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WFE, + .value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE | CMDQ_WFE_WAIT, + .event = event + }; if (event >= CMDQ_MAX_EVENT) return -EINVAL; - inst.op = CMDQ_CODE_WFE; - inst.value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE | CMDQ_WFE_WAIT; - inst.event = event; - return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_acquire_event); int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event) { - struct cmdq_instruction inst = { {0} }; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WFE, + .value = CMDQ_WFE_UPDATE, + .event = event + }; if (event >= CMDQ_MAX_EVENT) return -EINVAL; - inst.op = CMDQ_CODE_WFE; - inst.value = CMDQ_WFE_UPDATE; - inst.event = event; - return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_clear_event); int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event) { - struct cmdq_instruction inst = {}; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_WFE, + .value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE, + .event = event + }; if (event >= CMDQ_MAX_EVENT) return -EINVAL; - inst.op = CMDQ_CODE_WFE; - inst.value = CMDQ_WFE_UPDATE | CMDQ_WFE_UPDATE_VALUE; - inst.event = event; - return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_set_event); @@ -393,35 +388,27 @@ EXPORT_SYMBOL(cmdq_pkt_set_event); int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) { - struct cmdq_instruction inst = { {0} }; - int err; - - inst.op = CMDQ_CODE_POLL; - inst.value = value; - inst.offset = offset; - inst.subsys = subsys; - err = cmdq_pkt_append_command(pkt, inst); - - return err; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_POLL, + .value = value, + .offset = offset, + .subsys = subsys + }; + return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_poll); int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask) { - struct cmdq_instruction inst = { {0} }; int err; - inst.op = CMDQ_CODE_MASK; - inst.mask = ~mask; - err = cmdq_pkt_append_command(pkt, inst); + err = cmdq_pkt_mask(pkt, mask); if (err < 0) return err; offset = offset | CMDQ_POLL_ENABLE_MASK; - err = cmdq_pkt_poll(pkt, subsys, offset, value); - - return err; + return cmdq_pkt_poll(pkt, subsys, offset, value); } EXPORT_SYMBOL(cmdq_pkt_poll_mask); @@ -436,9 +423,7 @@ int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mas * which enables use_mask bit. */ if (mask != GENMASK(31, 0)) { - inst.op = CMDQ_CODE_MASK; - inst.mask = ~mask; - ret = cmdq_pkt_append_command(pkt, inst); + ret = cmdq_pkt_mask(pkt, mask); if (ret < 0) return ret; use_mask = CMDQ_POLL_ENABLE_MASK; @@ -477,11 +462,12 @@ int cmdq_pkt_logic_command(struct cmdq_pkt *pkt, u16 result_reg_idx, enum cmdq_logic_op s_op, struct cmdq_operand *right_operand) { - struct cmdq_instruction inst = { {0} }; + struct cmdq_instruction inst; if (!left_operand || !right_operand || s_op >= CMDQ_LOGIC_MAX) return -EINVAL; + inst.value = 0; inst.op = CMDQ_CODE_LOGIC; inst.dst_t = CMDQ_REG_TYPE; inst.src_t = cmdq_operand_get_type(left_operand); @@ -497,43 +483,43 @@ EXPORT_SYMBOL(cmdq_pkt_logic_command); int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value) { - struct cmdq_instruction inst = {}; - - inst.op = CMDQ_CODE_LOGIC; - inst.dst_t = CMDQ_REG_TYPE; - inst.reg_dst = reg_idx; - inst.value = value; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_LOGIC, + .dst_t = CMDQ_REG_TYPE, + .reg_dst = reg_idx, + .value = value + }; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_assign); int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa) { - struct cmdq_instruction inst = {}; - - inst.op = CMDQ_CODE_JUMP; - inst.offset = CMDQ_JUMP_ABSOLUTE; - inst.value = addr >> shift_pa; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_JUMP, + .offset = CMDQ_JUMP_ABSOLUTE, + .value = addr >> shift_pa + }; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_jump_abs); int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa) { - struct cmdq_instruction inst = { {0} }; - - inst.op = CMDQ_CODE_JUMP; - inst.value = (u32)offset >> shift_pa; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_JUMP, + .value = (u32)offset >> shift_pa + }; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_jump_rel); int cmdq_pkt_eoc(struct cmdq_pkt *pkt) { - struct cmdq_instruction inst = { {0} }; - - inst.op = CMDQ_CODE_EOC; - inst.value = CMDQ_EOC_IRQ_EN; + struct cmdq_instruction inst = { + .op = CMDQ_CODE_EOC, + .value = CMDQ_EOC_IRQ_EN + }; return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_eoc); @@ -544,9 +530,7 @@ int cmdq_pkt_finalize(struct cmdq_pkt *pkt) int err; /* insert EOC and generate IRQ for each command iteration */ - inst.op = CMDQ_CODE_EOC; - inst.value = CMDQ_EOC_IRQ_EN; - err = cmdq_pkt_append_command(pkt, inst); + err = cmdq_pkt_eoc(pkt); if (err < 0) return err; @@ -554,9 +538,7 @@ int cmdq_pkt_finalize(struct cmdq_pkt *pkt) inst.op = CMDQ_CODE_JUMP; inst.value = CMDQ_JUMP_PASS >> cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan); - err = cmdq_pkt_append_command(pkt, inst); - - return err; + return cmdq_pkt_append_command(pkt, inst); } EXPORT_SYMBOL(cmdq_pkt_finalize); diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c index 56cc345552a430..2a1adcb87d4e4b 100644 --- a/drivers/soc/mediatek/mtk-devapc.c +++ b/drivers/soc/mediatek/mtk-devapc.c @@ -301,7 +301,7 @@ static void mtk_devapc_remove(struct platform_device *pdev) static struct platform_driver mtk_devapc_driver = { .probe = mtk_devapc_probe, - .remove_new = mtk_devapc_remove, + .remove = mtk_devapc_remove, .driver = { .name = "mtk-devapc", .of_match_table = mtk_devapc_dt_match, diff --git a/drivers/soc/mediatek/mtk-dvfsrc.c b/drivers/soc/mediatek/mtk-dvfsrc.c new file mode 100644 index 00000000000000..83bf46fdcf2de3 --- /dev/null +++ b/drivers/soc/mediatek/mtk-dvfsrc.c @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 MediaTek Inc. + * Copyright (c) 2024 Collabora Ltd. + * AngeloGioacchino Del Regno + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* DVFSRC_LEVEL */ +#define DVFSRC_V1_LEVEL_TARGET_LEVEL GENMASK(15, 0) +#define DVFSRC_TGT_LEVEL_IDLE 0x00 +#define DVFSRC_V1_LEVEL_CURRENT_LEVEL GENMASK(31, 16) + +/* DVFSRC_SW_REQ, DVFSRC_SW_REQ2 */ +#define DVFSRC_V1_SW_REQ2_DRAM_LEVEL GENMASK(1, 0) +#define DVFSRC_V1_SW_REQ2_VCORE_LEVEL GENMASK(3, 2) + +#define DVFSRC_V2_SW_REQ_DRAM_LEVEL GENMASK(3, 0) +#define DVFSRC_V2_SW_REQ_VCORE_LEVEL GENMASK(6, 4) + +/* DVFSRC_VCORE */ +#define DVFSRC_V2_VCORE_REQ_VSCP_LEVEL GENMASK(14, 12) + +#define DVFSRC_POLL_TIMEOUT_US 1000 +#define STARTUP_TIME_US 1 + +#define MTK_SIP_DVFSRC_INIT 0x0 +#define MTK_SIP_DVFSRC_START 0x1 + +struct dvfsrc_bw_constraints { + u16 max_dram_nom_bw; + u16 max_dram_peak_bw; + u16 max_dram_hrt_bw; +}; + +struct dvfsrc_opp { + u32 vcore_opp; + u32 dram_opp; +}; + +struct dvfsrc_opp_desc { + const struct dvfsrc_opp *opps; + u32 num_opp; +}; + +struct dvfsrc_soc_data; +struct mtk_dvfsrc { + struct device *dev; + struct platform_device *icc; + struct platform_device *regulator; + const struct dvfsrc_soc_data *dvd; + const struct dvfsrc_opp_desc *curr_opps; + void __iomem *regs; + int dram_type; +}; + +struct dvfsrc_soc_data { + const int *regs; + const struct dvfsrc_opp_desc *opps_desc; + u32 (*get_target_level)(struct mtk_dvfsrc *dvfsrc); + u32 (*get_current_level)(struct mtk_dvfsrc *dvfsrc); + u32 (*get_vcore_level)(struct mtk_dvfsrc *dvfsrc); + u32 (*get_vscp_level)(struct mtk_dvfsrc *dvfsrc); + void (*set_dram_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw); + void (*set_dram_peak_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw); + void (*set_dram_hrt_bw)(struct mtk_dvfsrc *dvfsrc, u64 bw); + void (*set_opp_level)(struct mtk_dvfsrc *dvfsrc, u32 level); + void (*set_vcore_level)(struct mtk_dvfsrc *dvfsrc, u32 level); + void (*set_vscp_level)(struct mtk_dvfsrc *dvfsrc, u32 level); + int (*wait_for_opp_level)(struct mtk_dvfsrc *dvfsrc, u32 level); + int (*wait_for_vcore_level)(struct mtk_dvfsrc *dvfsrc, u32 level); + const struct dvfsrc_bw_constraints *bw_constraints; +}; + +static u32 dvfsrc_readl(struct mtk_dvfsrc *dvfs, u32 offset) +{ + return readl(dvfs->regs + dvfs->dvd->regs[offset]); +} + +static void dvfsrc_writel(struct mtk_dvfsrc *dvfs, u32 offset, u32 val) +{ + writel(val, dvfs->regs + dvfs->dvd->regs[offset]); +} + +enum dvfsrc_regs { + DVFSRC_SW_REQ, + DVFSRC_SW_REQ2, + DVFSRC_LEVEL, + DVFSRC_TARGET_LEVEL, + DVFSRC_SW_BW, + DVFSRC_SW_PEAK_BW, + DVFSRC_SW_HRT_BW, + DVFSRC_VCORE, + DVFSRC_REGS_MAX, +}; + +static const int dvfsrc_mt8183_regs[] = { + [DVFSRC_SW_REQ] = 0x4, + [DVFSRC_SW_REQ2] = 0x8, + [DVFSRC_LEVEL] = 0xDC, + [DVFSRC_SW_BW] = 0x160, +}; + +static const int dvfsrc_mt8195_regs[] = { + [DVFSRC_SW_REQ] = 0xc, + [DVFSRC_VCORE] = 0x6c, + [DVFSRC_SW_PEAK_BW] = 0x278, + [DVFSRC_SW_BW] = 0x26c, + [DVFSRC_SW_HRT_BW] = 0x290, + [DVFSRC_LEVEL] = 0xd44, + [DVFSRC_TARGET_LEVEL] = 0xd48, +}; + +static const struct dvfsrc_opp *dvfsrc_get_current_opp(struct mtk_dvfsrc *dvfsrc) +{ + u32 level = dvfsrc->dvd->get_current_level(dvfsrc); + + return &dvfsrc->curr_opps->opps[level]; +} + +static bool dvfsrc_is_idle(struct mtk_dvfsrc *dvfsrc) +{ + if (!dvfsrc->dvd->get_target_level) + return true; + + return dvfsrc->dvd->get_target_level(dvfsrc) == DVFSRC_TGT_LEVEL_IDLE; +} + +static int dvfsrc_wait_for_vcore_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level) +{ + const struct dvfsrc_opp *curr; + + return readx_poll_timeout_atomic(dvfsrc_get_current_opp, dvfsrc, curr, + curr->vcore_opp >= level, STARTUP_TIME_US, + DVFSRC_POLL_TIMEOUT_US); +} + +static int dvfsrc_wait_for_opp_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level) +{ + const struct dvfsrc_opp *target, *curr; + int ret; + + target = &dvfsrc->curr_opps->opps[level]; + ret = readx_poll_timeout_atomic(dvfsrc_get_current_opp, dvfsrc, curr, + curr->dram_opp >= target->dram_opp && + curr->vcore_opp >= target->vcore_opp, + STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US); + if (ret < 0) { + dev_warn(dvfsrc->dev, + "timeout! target OPP: %u, dram: %d, vcore: %d\n", level, + curr->dram_opp, curr->vcore_opp); + return ret; + } + + return 0; +} + +static int dvfsrc_wait_for_opp_level_v2(struct mtk_dvfsrc *dvfsrc, u32 level) +{ + const struct dvfsrc_opp *target, *curr; + int ret; + + target = &dvfsrc->curr_opps->opps[level]; + ret = readx_poll_timeout_atomic(dvfsrc_get_current_opp, dvfsrc, curr, + curr->dram_opp >= target->dram_opp && + curr->vcore_opp >= target->vcore_opp, + STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US); + if (ret < 0) { + dev_warn(dvfsrc->dev, + "timeout! target OPP: %u, dram: %d\n", level, curr->dram_opp); + return ret; + } + + return 0; +} + +static u32 dvfsrc_get_target_level_v1(struct mtk_dvfsrc *dvfsrc) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL); + + return FIELD_GET(DVFSRC_V1_LEVEL_TARGET_LEVEL, val); +} + +static u32 dvfsrc_get_current_level_v1(struct mtk_dvfsrc *dvfsrc) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL); + u32 current_level = FIELD_GET(DVFSRC_V1_LEVEL_CURRENT_LEVEL, val); + + return ffs(current_level) - 1; +} + +static u32 dvfsrc_get_target_level_v2(struct mtk_dvfsrc *dvfsrc) +{ + return dvfsrc_readl(dvfsrc, DVFSRC_TARGET_LEVEL); +} + +static u32 dvfsrc_get_current_level_v2(struct mtk_dvfsrc *dvfsrc) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_LEVEL); + u32 level = ffs(val); + + /* Valid levels */ + if (level < dvfsrc->curr_opps->num_opp) + return dvfsrc->curr_opps->num_opp - level; + + /* Zero for level 0 or invalid level */ + return 0; +} + +static u32 dvfsrc_get_vcore_level_v1(struct mtk_dvfsrc *dvfsrc) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ2); + + return FIELD_GET(DVFSRC_V1_SW_REQ2_VCORE_LEVEL, val); +} + +static void dvfsrc_set_vcore_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ2); + + val &= ~DVFSRC_V1_SW_REQ2_VCORE_LEVEL; + val |= FIELD_PREP(DVFSRC_V1_SW_REQ2_VCORE_LEVEL, level); + + dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ2, val); +} + +static u32 dvfsrc_get_vcore_level_v2(struct mtk_dvfsrc *dvfsrc) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ); + + return FIELD_GET(DVFSRC_V2_SW_REQ_VCORE_LEVEL, val); +} + +static void dvfsrc_set_vcore_level_v2(struct mtk_dvfsrc *dvfsrc, u32 level) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_SW_REQ); + + val &= ~DVFSRC_V2_SW_REQ_VCORE_LEVEL; + val |= FIELD_PREP(DVFSRC_V2_SW_REQ_VCORE_LEVEL, level); + + dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ, val); +} + +static u32 dvfsrc_get_vscp_level_v2(struct mtk_dvfsrc *dvfsrc) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_VCORE); + + return FIELD_GET(DVFSRC_V2_VCORE_REQ_VSCP_LEVEL, val); +} + +static void dvfsrc_set_vscp_level_v2(struct mtk_dvfsrc *dvfsrc, u32 level) +{ + u32 val = dvfsrc_readl(dvfsrc, DVFSRC_VCORE); + + val &= ~DVFSRC_V2_VCORE_REQ_VSCP_LEVEL; + val |= FIELD_PREP(DVFSRC_V2_VCORE_REQ_VSCP_LEVEL, level); + + dvfsrc_writel(dvfsrc, DVFSRC_VCORE, val); +} + +static void __dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u32 reg, + u16 max_bw, u16 min_bw, u64 bw) +{ + u32 new_bw = (u32)div_u64(bw, 100 * 1000); + + /* If bw constraints (in mbps) are defined make sure to respect them */ + if (max_bw) + new_bw = min(new_bw, max_bw); + if (min_bw && new_bw > 0) + new_bw = max(new_bw, min_bw); + + dvfsrc_writel(dvfsrc, reg, new_bw); +} + +static void dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw) +{ + u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_nom_bw; + + __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, max_bw, 0, bw); +}; + +static void dvfsrc_set_dram_peak_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw) +{ + u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_peak_bw; + + __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, max_bw, 0, bw); +} + +static void dvfsrc_set_dram_hrt_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw) +{ + u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_hrt_bw; + + __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, max_bw, 0, bw); +} + +static void dvfsrc_set_opp_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level) +{ + const struct dvfsrc_opp *opp = &dvfsrc->curr_opps->opps[level]; + u32 val; + + /* Translate Pstate to DVFSRC level and set it to DVFSRC HW */ + val = FIELD_PREP(DVFSRC_V1_SW_REQ2_DRAM_LEVEL, opp->dram_opp); + val |= FIELD_PREP(DVFSRC_V1_SW_REQ2_VCORE_LEVEL, opp->vcore_opp); + + dev_dbg(dvfsrc->dev, "vcore_opp: %d, dram_opp: %d\n", opp->vcore_opp, opp->dram_opp); + dvfsrc_writel(dvfsrc, DVFSRC_SW_REQ, val); +} + +int mtk_dvfsrc_send_request(const struct device *dev, u32 cmd, u64 data) +{ + struct mtk_dvfsrc *dvfsrc = dev_get_drvdata(dev); + bool state; + int ret; + + dev_dbg(dvfsrc->dev, "cmd: %d, data: %llu\n", cmd, data); + + switch (cmd) { + case MTK_DVFSRC_CMD_BW: + dvfsrc->dvd->set_dram_bw(dvfsrc, data); + return 0; + case MTK_DVFSRC_CMD_HRT_BW: + if (dvfsrc->dvd->set_dram_hrt_bw) + dvfsrc->dvd->set_dram_hrt_bw(dvfsrc, data); + return 0; + case MTK_DVFSRC_CMD_PEAK_BW: + if (dvfsrc->dvd->set_dram_peak_bw) + dvfsrc->dvd->set_dram_peak_bw(dvfsrc, data); + return 0; + case MTK_DVFSRC_CMD_OPP: + if (!dvfsrc->dvd->set_opp_level) + return 0; + + dvfsrc->dvd->set_opp_level(dvfsrc, data); + break; + case MTK_DVFSRC_CMD_VCORE_LEVEL: + dvfsrc->dvd->set_vcore_level(dvfsrc, data); + break; + case MTK_DVFSRC_CMD_VSCP_LEVEL: + if (!dvfsrc->dvd->set_vscp_level) + return 0; + + dvfsrc->dvd->set_vscp_level(dvfsrc, data); + break; + default: + dev_err(dvfsrc->dev, "unknown command: %d\n", cmd); + return -EOPNOTSUPP; + } + + /* DVFSRC needs at least 2T(~196ns) to handle a request */ + udelay(STARTUP_TIME_US); + + ret = readx_poll_timeout_atomic(dvfsrc_is_idle, dvfsrc, state, state, + STARTUP_TIME_US, DVFSRC_POLL_TIMEOUT_US); + if (ret < 0) { + dev_warn(dvfsrc->dev, + "%d: idle timeout, data: %llu, last: %d -> %d\n", cmd, data, + dvfsrc->dvd->get_current_level(dvfsrc), + dvfsrc->dvd->get_target_level(dvfsrc)); + return ret; + } + + if (cmd == MTK_DVFSRC_CMD_OPP) + ret = dvfsrc->dvd->wait_for_opp_level(dvfsrc, data); + else + ret = dvfsrc->dvd->wait_for_vcore_level(dvfsrc, data); + + if (ret < 0) { + dev_warn(dvfsrc->dev, + "%d: wait timeout, data: %llu, last: %d -> %d\n", + cmd, data, + dvfsrc->dvd->get_current_level(dvfsrc), + dvfsrc->dvd->get_target_level(dvfsrc)); + return ret; + } + + return 0; +} +EXPORT_SYMBOL(mtk_dvfsrc_send_request); + +int mtk_dvfsrc_query_info(const struct device *dev, u32 cmd, int *data) +{ + struct mtk_dvfsrc *dvfsrc = dev_get_drvdata(dev); + + switch (cmd) { + case MTK_DVFSRC_CMD_VCORE_LEVEL: + *data = dvfsrc->dvd->get_vcore_level(dvfsrc); + break; + case MTK_DVFSRC_CMD_VSCP_LEVEL: + *data = dvfsrc->dvd->get_vscp_level(dvfsrc); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} +EXPORT_SYMBOL(mtk_dvfsrc_query_info); + +static int mtk_dvfsrc_probe(struct platform_device *pdev) +{ + struct arm_smccc_res ares; + struct mtk_dvfsrc *dvfsrc; + int ret; + + dvfsrc = devm_kzalloc(&pdev->dev, sizeof(*dvfsrc), GFP_KERNEL); + if (!dvfsrc) + return -ENOMEM; + + dvfsrc->dvd = of_device_get_match_data(&pdev->dev); + dvfsrc->dev = &pdev->dev; + + dvfsrc->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(dvfsrc->regs)) + return PTR_ERR(dvfsrc->regs); + + arm_smccc_smc(MTK_SIP_DVFSRC_VCOREFS_CONTROL, MTK_SIP_DVFSRC_INIT, + 0, 0, 0, 0, 0, 0, &ares); + if (ares.a0) + return dev_err_probe(&pdev->dev, -EINVAL, "DVFSRC init failed: %lu\n", ares.a0); + + dvfsrc->dram_type = ares.a1; + dev_dbg(&pdev->dev, "DRAM Type: %d\n", dvfsrc->dram_type); + + dvfsrc->curr_opps = &dvfsrc->dvd->opps_desc[dvfsrc->dram_type]; + platform_set_drvdata(pdev, dvfsrc); + + ret = devm_of_platform_populate(&pdev->dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to populate child devices\n"); + + /* Everything is set up - make it run! */ + arm_smccc_smc(MTK_SIP_DVFSRC_VCOREFS_CONTROL, MTK_SIP_DVFSRC_START, + 0, 0, 0, 0, 0, 0, &ares); + if (ares.a0) + return dev_err_probe(&pdev->dev, -EINVAL, "Cannot start DVFSRC: %lu\n", ares.a0); + + return 0; +} + +static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp4[] = { + { 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 2 }, +}; + +static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp3[] = { + { 0, 0 }, { 0, 1 }, { 1, 1 }, { 1, 2 }, +}; + +static const struct dvfsrc_opp_desc dvfsrc_opp_mt8183_desc[] = { + [0] = { + .opps = dvfsrc_opp_mt8183_lp4, + .num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp4), + }, + [1] = { + .opps = dvfsrc_opp_mt8183_lp3, + .num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp3), + }, + [2] = { + .opps = dvfsrc_opp_mt8183_lp3, + .num_opp = ARRAY_SIZE(dvfsrc_opp_mt8183_lp3), + } +}; + +static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_mt8183 = { 0, 0, 0 }; + +static const struct dvfsrc_soc_data mt8183_data = { + .opps_desc = dvfsrc_opp_mt8183_desc, + .regs = dvfsrc_mt8183_regs, + .get_target_level = dvfsrc_get_target_level_v1, + .get_current_level = dvfsrc_get_current_level_v1, + .get_vcore_level = dvfsrc_get_vcore_level_v1, + .set_dram_bw = dvfsrc_set_dram_bw_v1, + .set_opp_level = dvfsrc_set_opp_level_v1, + .set_vcore_level = dvfsrc_set_vcore_level_v1, + .wait_for_opp_level = dvfsrc_wait_for_opp_level_v1, + .wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1, + .bw_constraints = &dvfsrc_bw_constr_mt8183, +}; + +static const struct dvfsrc_opp dvfsrc_opp_mt8195_lp4[] = { + { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 }, + { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, + { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 }, + { 1, 3 }, { 2, 3 }, { 3, 3 }, { 1, 4 }, + { 2, 4 }, { 3, 4 }, { 2, 5 }, { 3, 5 }, + { 3, 6 }, +}; + +static const struct dvfsrc_opp_desc dvfsrc_opp_mt8195_desc[] = { + [0] = { + .opps = dvfsrc_opp_mt8195_lp4, + .num_opp = ARRAY_SIZE(dvfsrc_opp_mt8195_lp4), + } +}; + +static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_mt8195 = { + .max_dram_nom_bw = 255, + .max_dram_peak_bw = 255, + .max_dram_hrt_bw = 1023, +}; + +static const struct dvfsrc_soc_data mt8195_data = { + .opps_desc = dvfsrc_opp_mt8195_desc, + .regs = dvfsrc_mt8195_regs, + .get_target_level = dvfsrc_get_target_level_v2, + .get_current_level = dvfsrc_get_current_level_v2, + .get_vcore_level = dvfsrc_get_vcore_level_v2, + .get_vscp_level = dvfsrc_get_vscp_level_v2, + .set_dram_bw = dvfsrc_set_dram_bw_v1, + .set_dram_peak_bw = dvfsrc_set_dram_peak_bw_v1, + .set_dram_hrt_bw = dvfsrc_set_dram_hrt_bw_v1, + .set_vcore_level = dvfsrc_set_vcore_level_v2, + .set_vscp_level = dvfsrc_set_vscp_level_v2, + .wait_for_opp_level = dvfsrc_wait_for_opp_level_v2, + .wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1, + .bw_constraints = &dvfsrc_bw_constr_mt8195, +}; + +static const struct of_device_id mtk_dvfsrc_of_match[] = { + { .compatible = "mediatek,mt8183-dvfsrc", .data = &mt8183_data }, + { .compatible = "mediatek,mt8195-dvfsrc", .data = &mt8195_data }, + { /* sentinel */ } +}; + +static struct platform_driver mtk_dvfsrc_driver = { + .probe = mtk_dvfsrc_probe, + .driver = { + .name = "mtk-dvfsrc", + .of_match_table = mtk_dvfsrc_of_match, + }, +}; +module_platform_driver(mtk_dvfsrc_driver); + +MODULE_AUTHOR("AngeloGioacchino Del Regno "); +MODULE_AUTHOR("Dawei Chien "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek DVFSRC driver"); diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index 938240714e54c2..bb4639ca0b8cdc 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -487,7 +487,7 @@ static struct platform_driver mtk_mmsys_drv = { .of_match_table = of_match_mtk_mmsys, }, .probe = mtk_mmsys_probe, - .remove_new = mtk_mmsys_remove, + .remove = mtk_mmsys_remove, }; module_platform_driver(mtk_mmsys_drv); diff --git a/drivers/soc/mediatek/mtk-regulator-coupler.c b/drivers/soc/mediatek/mtk-regulator-coupler.c index ad2ed42aa69797..0b6a2884145e37 100644 --- a/drivers/soc/mediatek/mtk-regulator-coupler.c +++ b/drivers/soc/mediatek/mtk-regulator-coupler.c @@ -147,6 +147,7 @@ static int mediatek_regulator_coupler_init(void) { if (!of_machine_is_compatible("mediatek,mt8183") && !of_machine_is_compatible("mediatek,mt8186") && + !of_machine_is_compatible("mediatek,mt8188") && !of_machine_is_compatible("mediatek,mt8192")) return 0; diff --git a/drivers/soc/mediatek/mtk-socinfo.c b/drivers/soc/mediatek/mtk-socinfo.c index 74672a9d6d13dd..123b12cd25432b 100644 --- a/drivers/soc/mediatek/mtk-socinfo.c +++ b/drivers/soc/mediatek/mtk-socinfo.c @@ -187,7 +187,7 @@ static void mtk_socinfo_remove(struct platform_device *pdev) static struct platform_driver mtk_socinfo = { .probe = mtk_socinfo_probe, - .remove_new = mtk_socinfo_remove, + .remove = mtk_socinfo_remove, .driver = { .name = "mtk-socinfo", }, diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index 9a91298c125397..7c349a94b45c03 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -2133,14 +2133,12 @@ static struct device *svs_get_subsys_device(struct svs_platform *svsp, } pdev = of_find_device_by_node(np); + of_node_put(np); if (!pdev) { - of_node_put(np); dev_err(svsp->dev, "cannot find pdev by %s\n", node_name); return ERR_PTR(-ENXIO); } - of_node_put(np); - return &pdev->dev; } diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c index 7a4936019329c4..30bc45d17d3434 100644 --- a/drivers/soc/microchip/mpfs-sys-controller.c +++ b/drivers/soc/microchip/mpfs-sys-controller.c @@ -232,7 +232,7 @@ static struct platform_driver mpfs_sys_controller_driver = { .of_match_table = mpfs_sys_controller_of_match, }, .probe = mpfs_sys_controller_probe, - .remove_new = mpfs_sys_controller_remove, + .remove = mpfs_sys_controller_remove, }; module_platform_driver(mpfs_sys_controller_driver); diff --git a/drivers/soc/pxa/ssp.c b/drivers/soc/pxa/ssp.c index 854d32e0455834..bb0062c165fe90 100644 --- a/drivers/soc/pxa/ssp.c +++ b/drivers/soc/pxa/ssp.c @@ -197,7 +197,7 @@ static const struct platform_device_id ssp_id_table[] = { static struct platform_driver pxa_ssp_driver = { .probe = pxa_ssp_probe, - .remove_new = pxa_ssp_remove, + .remove = pxa_ssp_remove, .driver = { .name = "pxa2xx-ssp", .of_match_table = of_match_ptr(pxa_ssp_of_ids), diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index f9235bc3aa3bbb..3dfa448bf8cf98 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -872,7 +872,7 @@ MODULE_DEVICE_TABLE(of, bwmon_of_match); static struct platform_driver bwmon_driver = { .probe = bwmon_probe, - .remove_new = bwmon_remove, + .remove = bwmon_remove, .driver = { .name = "qcom-bwmon", .of_match_table = bwmon_of_match, diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c index 50be7a9274a14e..393d2d1d275f18 100644 --- a/drivers/soc/qcom/ice.c +++ b/drivers/soc/qcom/ice.c @@ -44,7 +44,6 @@ struct qcom_ice { struct device *dev; void __iomem *base; - struct device_link *link; struct clk *core_clk; }; @@ -268,6 +267,7 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) struct qcom_ice *ice; struct resource *res; void __iomem *base; + struct device_link *link; if (!dev || !dev->of_node) return ERR_PTR(-ENODEV); @@ -311,8 +311,8 @@ struct qcom_ice *of_qcom_ice_get(struct device *dev) return ERR_PTR(-EPROBE_DEFER); } - ice->link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER); - if (!ice->link) { + link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER); + if (!link) { dev_err(&pdev->dev, "Failed to create device link to consumer %s\n", dev_name(dev)); diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 28bcc65e91beb3..32c3bc887cefb8 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -27,14 +27,14 @@ #define ACT_CTRL_OPCODE_ACTIVATE BIT(0) #define ACT_CTRL_OPCODE_DEACTIVATE BIT(1) #define ACT_CTRL_ACT_TRIG BIT(0) -#define ACT_CTRL_OPCODE_SHIFT 0x01 -#define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02 -#define ATTR1_FIXED_SIZE_SHIFT 0x03 -#define ATTR1_PRIORITY_SHIFT 0x04 -#define ATTR1_MAX_CAP_SHIFT 0x10 +#define ACT_CTRL_OPCODE_SHIFT 1 +#define ATTR1_PROBE_TARGET_WAYS_SHIFT 2 +#define ATTR1_FIXED_SIZE_SHIFT 3 +#define ATTR1_PRIORITY_SHIFT 4 +#define ATTR1_MAX_CAP_SHIFT 16 #define ATTR0_RES_WAYS_MASK GENMASK(15, 0) #define ATTR0_BONUS_WAYS_MASK GENMASK(31, 16) -#define ATTR0_BONUS_WAYS_SHIFT 0x10 +#define ATTR0_BONUS_WAYS_SHIFT 16 #define LLCC_STATUS_READ_DELAY 100 #define CACHE_LINE_SIZE_SHIFT 6 @@ -136,8 +136,10 @@ struct qcom_llcc_config { const struct llcc_slice_config *sct_data; const u32 *reg_offset; const struct llcc_edac_reg_offset *edac_reg_offset; + u32 max_cap_shift; /* instead of ATTR1_MAX_CAP_SHIFT */ + u32 num_banks; int size; - bool need_llcc_cfg; + bool skip_llcc_cfg; bool no_edac; bool irq_configured; }; @@ -153,325 +155,2922 @@ enum llcc_reg_offset { }; static const struct llcc_slice_config sa8775p_data[] = { - {LLCC_CPUSS, 1, 2048, 1, 0, 0x00FF, 0x0, 0, 0, 0, 1, 1, 0, 0}, - {LLCC_VIDSC0, 2, 512, 3, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_CPUSS1, 3, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_CPUHWT, 5, 512, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_AUDIO, 6, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CMPT, 10, 4096, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_GPUHTW, 11, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_GPU, 12, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 1, 0}, - {LLCC_MMUHWT, 13, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 0, 1, 0, 0}, - {LLCC_CMPTDMA, 15, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_DISP, 16, 4096, 2, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_VIDFW, 17, 3072, 1, 0, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_AUDHW, 22, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CVP, 28, 256, 3, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xF0, 1, 0, 0, 1, 0, 0, 0}, - {LLCC_WRCACHE, 31, 512, 1, 1, 0x00FF, 0x0, 0, 0, 0, 0, 1, 0, 0}, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 2048, + .priority = 1, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CPUSS1, + .slice_id = 3, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CPUHWT, + .slice_id = 5, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 4096, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CMPTDMA, + .slice_id = 15, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 4096, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIDFW, + .slice_id = 17, + .max_cap = 3072, + .priority = 1, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 28, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .res_ways = 0xf0, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xff, + .cache_mode = 0, + .activate_on_init = true, + }, +}; + +static const struct llcc_slice_config sar1130p_data[] = { + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 4096, + .priority = 1, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 3072, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 12800, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 28, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 26, + .max_cap = 2048, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x3, + .cache_mode = true, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_AENPU, + .slice_id = 30, + .max_cap = 3072, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x1fff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP_LEFT, + .slice_id = 17, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP_RIGHT, + .slice_id = 18, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_EVCS_LEFT, + .slice_id = 22, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_EVCS_RIGHT, + .slice_id = 23, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, +}; + +static const struct llcc_slice_config sar2130p_data[] = { + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 6144, + .priority = 1, + .fixed_size = 0, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 128, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 1536, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 26, + .max_cap = 2048, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x3, + .cache_mode = true, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIEYE, + .slice_id = 7, + .max_cap = 7168, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIDPTH, + .slice_id = 8, + .max_cap = 7168, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUMV, + .slice_id = 9, + .max_cap = 2048, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_EVA_LEFT, + .slice_id = 20, + .max_cap = 7168, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0x3ffffffc, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_EVA_RIGHT, + .slice_id = 21, + .max_cap = 7168, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0x3ffffffc, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_EVAGAIN, + .slice_id = 25, + .max_cap = 1024, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AENPU, + .slice_id = 30, + .max_cap = 3072, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIPTH, + .slice_id = 29, + .max_cap = 1024, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0x3fffffff, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP_LEFT, + .slice_id = 17, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP_RIGHT, + .slice_id = 18, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_EVCS_LEFT, + .slice_id = 22, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_EVCS_RIGHT, + .slice_id = 23, + .max_cap = 0, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_SPAD, + .slice_id = 24, + .max_cap = 7168, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .cache_mode = 0, + .retain_on_pc = true, + }, }; static const struct llcc_slice_config sc7180_data[] = { - { LLCC_CPUSS, 1, 256, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 1 }, - { LLCC_MDM, 8, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_GPUHTW, 11, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_GPU, 12, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 256, + .priority = 1, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MDM, + .slice_id = 8, + .max_cap = 128, + .priority = 1, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 128, + .priority = 1, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 128, + .priority = 1, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, }; static const struct llcc_slice_config sc7280_data[] = { - { LLCC_CPUSS, 1, 768, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 1, 0}, - { LLCC_MDMHPGRW, 7, 512, 2, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, - { LLCC_CMPT, 10, 768, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, - { LLCC_GPUHTW, 11, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, - { LLCC_GPU, 12, 512, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, - { LLCC_MMUHWT, 13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 0, 1, 0}, - { LLCC_MDMPNG, 21, 768, 0, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, - { LLCC_WLHW, 24, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, - { LLCC_MODPE, 29, 64, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0}, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 768, + .priority = 1, + .bonus_ways = 0x3f, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 512, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0x3f, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 768, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3f, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3f, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 512, + .priority = 1, + .bonus_ways = 0x3f, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3f, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 768, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0x3f, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WLHW, + .slice_id = 24, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3f, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 64, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3f, + .cache_mode = 0, + .retain_on_pc = true, + }, }; static const struct llcc_slice_config sc8180x_data[] = { - { LLCC_CPUSS, 1, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1 }, - { LLCC_VIDSC0, 2, 512, 2, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_VIDSC1, 3, 512, 2, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_AUDIO, 6, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MDMHPGRW, 7, 3072, 1, 1, 0x3ff, 0xc00, 0, 0, 0, 1, 0 }, - { LLCC_MDM, 8, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_CMPT, 10, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_GPU, 12, 5120, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1 }, - { LLCC_CMPTDMA, 15, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_DISP, 16, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_VIDFW, 17, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MDMHPFX, 20, 1024, 2, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MDMPNG, 21, 1024, 0, 1, 0xc, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_AUDHW, 22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_NPU, 23, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_WLHW, 24, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MODPE, 29, 512, 1, 1, 0xc, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_APTCM, 30, 512, 3, 1, 0x0, 0x1, 1, 0, 0, 1, 0 }, - { LLCC_WRCACHE, 31, 128, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIDSC1, + .slice_id = 3, + .max_cap = 512, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3ff, + .res_ways = 0xc00, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDM, + .slice_id = 8, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 9, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 5120, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CMPTDMA, + .slice_id = 15, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIDFW, + .slice_id = 17, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMHPFX, + .slice_id = 20, + .max_cap = 1024, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 1024, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0xc, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_NPU, + .slice_id = 23, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WLHW, + .slice_id = 24, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xc, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .res_ways = 0x1, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 128, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, }; static const struct llcc_slice_config sc8280xp_data[] = { - { LLCC_CPUSS, 1, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 }, - { LLCC_VIDSC0, 2, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_AUDIO, 6, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 }, - { LLCC_CMPT, 10, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 }, - { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_GPU, 12, 4096, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 1 }, - { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_DISP, 16, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_AUDHW, 22, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_ECC, 26, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_CVP, 28, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0x1, 1, 0, 0, 1, 0, 0 }, - { LLCC_WRCACHE, 31, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_CVPFW, 17, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_CPUSS1, 3, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_CPUHWT, 5, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, -}; - -static const struct llcc_slice_config sdm845_data[] = { - { LLCC_CPUSS, 1, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 1 }, - { LLCC_VIDSC0, 2, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0 }, - { LLCC_VIDSC1, 3, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0 }, - { LLCC_ROTATOR, 4, 563, 2, 1, 0x0, 0x00e, 2, 0, 1, 1, 0 }, - { LLCC_VOICE, 5, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 }, - { LLCC_AUDIO, 6, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 }, - { LLCC_MDMHPGRW, 7, 1024, 2, 0, 0xfc, 0xf00, 0, 0, 1, 1, 0 }, - { LLCC_MDM, 8, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 }, - { LLCC_CMPT, 10, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 }, - { LLCC_GPUHTW, 11, 512, 1, 1, 0xc, 0x0, 0, 0, 1, 1, 0 }, - { LLCC_GPU, 12, 2304, 1, 0, 0xff0, 0x2, 0, 0, 1, 1, 0 }, - { LLCC_MMUHWT, 13, 256, 2, 0, 0x0, 0x1, 0, 0, 1, 0, 1 }, - { LLCC_CMPTDMA, 15, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 }, - { LLCC_DISP, 16, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 }, - { LLCC_VIDFW, 17, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0 }, - { LLCC_MDMHPFX, 20, 1024, 2, 1, 0x0, 0xf00, 0, 0, 1, 1, 0 }, - { LLCC_MDMPNG, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0 }, - { LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 4096, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 2048, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_ECC, + .slice_id = 26, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 28, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .res_ways = 0x1, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CVPFW, + .slice_id = 17, + .max_cap = 512, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CPUSS1, + .slice_id = 3, + .max_cap = 2048, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CPUHWT, + .slice_id = 5, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, +}; + +static const struct llcc_slice_config sdm845_data[] = {{ + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 2816, + .priority = 1, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 2, + .fixed_size = true, + .res_ways = 0xf0, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIDSC1, + .slice_id = 3, + .max_cap = 512, + .priority = 2, + .fixed_size = true, + .res_ways = 0xf0, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_ROTATOR, + .slice_id = 4, + .max_cap = 563, + .priority = 2, + .fixed_size = true, + .res_ways = 0xe, + .cache_mode = 2, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VOICE, + .slice_id = 5, + .max_cap = 2816, + .priority = 1, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 2816, + .priority = 1, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 1024, + .priority = 2, + .bonus_ways = 0xfc, + .res_ways = 0xf00, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDM, + .slice_id = 8, + .max_cap = 2816, + .priority = 1, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 2816, + .priority = 1, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xc, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 2304, + .priority = 1, + .bonus_ways = 0xff0, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 256, + .priority = 2, + .res_ways = 0x1, + .cache_mode = 0, + .dis_cap_alloc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CMPTDMA, + .slice_id = 15, + .max_cap = 2816, + .priority = 1, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 2816, + .priority = 1, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIDFW, + .slice_id = 17, + .max_cap = 2816, + .priority = 1, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMHPFX, + .slice_id = 20, + .max_cap = 1024, + .priority = 2, + .fixed_size = true, + .res_ways = 0xf00, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 1024, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0x1e, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffc, + .res_ways = 0x2, + .cache_mode = 0, + .dis_cap_alloc = true, + .retain_on_pc = true, + }, }; static const struct llcc_slice_config sm6350_data[] = { - { LLCC_CPUSS, 1, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1 }, - { LLCC_MDM, 8, 512, 2, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_GPUHTW, 11, 256, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_GPU, 12, 512, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_MDMPNG, 21, 768, 0, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_NPU, 23, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_MODPE, 29, 64, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 768, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MDM, + .slice_id = 8, + .max_cap = 512, + .priority = 2, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 256, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 512, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 768, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_NPU, + .slice_id = 23, + .max_cap = 768, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 64, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, }; static const struct llcc_slice_config sm7150_data[] = { - { LLCC_CPUSS, 1, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 1 }, - { LLCC_MDM, 8, 128, 2, 0, 0xF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_GPUHTW, 11, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_GPU, 12, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_NPU, 23, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 512, + .priority = 1, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MDM, + .slice_id = 8, + .max_cap = 128, + .priority = 2, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_NPU, + .slice_id = 23, + .max_cap = 512, + .priority = 1, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, }; static const struct llcc_slice_config sm8150_data[] = { - { LLCC_CPUSS, 1, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 1 }, - { LLCC_VIDSC0, 2, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_VIDSC1, 3, 512, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_AUDIO, 6, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MDMHPGRW, 7, 3072, 1, 0, 0xFF, 0xF00, 0, 0, 0, 1, 0 }, - { LLCC_MDM, 8, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MODHW, 9, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_CMPT, 10, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_GPUHTW , 11, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_GPU, 12, 2560, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MMUHWT, 13, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1 }, - { LLCC_CMPTDMA, 15, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_DISP, 16, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MDMHPFX, 20, 1024, 2, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MDMHPFX, 21, 1024, 0, 1, 0xF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_AUDHW, 22, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_NPU, 23, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_WLHW, 24, 3072, 1, 1, 0xFFF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_MODPE, 29, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 }, - { LLCC_APTCM, 30, 256, 3, 1, 0x0, 0x1, 1, 0, 0, 1, 0 }, - { LLCC_WRCACHE, 31, 128, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIDSC1, + .slice_id = 3, + .max_cap = 512, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 3072, + .priority = 1, + .bonus_ways = 0xff, + .res_ways = 0xf00, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDM, + .slice_id = 8, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 9, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 2560, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CMPTDMA, + .slice_id = 15, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMHPFX, + .slice_id = 20, + .max_cap = 1024, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMHPFX, + .slice_id = 21, + .max_cap = 1024, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_NPU, + .slice_id = 23, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WLHW, + .slice_id = 24, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .res_ways = 0x1, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 128, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, }; static const struct llcc_slice_config sm8250_data[] = { - { LLCC_CPUSS, 1, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 }, - { LLCC_VIDSC0, 2, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_AUDIO, 6, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 }, - { LLCC_CMPT, 10, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 }, - { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_GPU, 12, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 1 }, - { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_CMPTDMA, 15, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_DISP, 16, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_VIDFW, 17, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_AUDHW, 22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_NPU, 23, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_WLHW, 24, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_CVP, 28, 256, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_APTCM, 30, 128, 3, 0, 0x0, 0x3, 1, 0, 0, 1, 0, 0 }, - { LLCC_WRCACHE, 31, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 1024, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 1024, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CMPTDMA, + .slice_id = 15, + .max_cap = 1024, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_VIDFW, + .slice_id = 17, + .max_cap = 512, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_NPU, + .slice_id = 23, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WLHW, + .slice_id = 24, + .max_cap = 1024, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 28, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 128, + .priority = 3, + .res_ways = 0x3, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, }; static const struct llcc_slice_config sm8350_data[] = { - { LLCC_CPUSS, 1, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 1 }, - { LLCC_VIDSC0, 2, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_AUDIO, 6, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 }, - { LLCC_MDMHPGRW, 7, 1024, 3, 0, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_CMPT, 10, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_GPU, 12, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 }, - { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 }, - { LLCC_DISP, 16, 3072, 2, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_MDMPNG, 21, 1024, 0, 1, 0xf, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_AUDHW, 22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_CVP, 28, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_MODPE, 29, 256, 1, 1, 0xf, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0x1, 1, 0, 0, 0, 1, 0 }, - { LLCC_WRCACHE, 31, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 }, - { LLCC_CVPFW, 17, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_CPUSS1, 3, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, - { LLCC_CPUHWT, 5, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 1024, + .priority = 3, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 9, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 1024, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .write_scid_en = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 3072, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 1024, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 28, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .res_ways = 0x1, + .cache_mode = 1, + .activate_on_init = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .write_scid_en = true, + }, { + .usecase_id = LLCC_CVPFW, + .slice_id = 17, + .max_cap = 512, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CPUSS1, + .slice_id = 3, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CPUHWT, + .slice_id = 5, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .write_scid_en = true, + }, }; static const struct llcc_slice_config sm8450_data[] = { - {LLCC_CPUSS, 1, 3072, 1, 0, 0xFFFF, 0x0, 0, 0, 0, 1, 1, 0, 0 }, - {LLCC_VIDSC0, 2, 512, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_AUDIO, 6, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 }, - {LLCC_MDMHPGRW, 7, 1024, 3, 0, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_MODHW, 9, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_CMPT, 10, 4096, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_GPU, 12, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 1, 0 }, - {LLCC_MMUHWT, 13, 768, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0 }, - {LLCC_DISP, 16, 4096, 2, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_MDMPNG, 21, 1024, 1, 1, 0xF000, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 }, - {LLCC_CVP, 28, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_MODPE, 29, 64, 1, 1, 0xF000, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xF0, 1, 0, 0, 1, 0, 0, 0 }, - {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0 }, - {LLCC_CVPFW, 17, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_CPUSS1, 3, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_CAMEXP0, 4, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_CPUMTE, 23, 256, 1, 1, 0x0FFF, 0x0, 0, 0, 0, 0, 1, 0, 0 }, - {LLCC_CPUHWT, 5, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 1, 0, 0 }, - {LLCC_CAMEXP1, 27, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - {LLCC_AENPU, 8, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 3072, + .priority = 1, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 1024, + .priority = 3, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 9, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 4096, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 2048, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 768, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 4096, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf000, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 28, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 64, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf000, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .res_ways = 0xf0, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CVPFW, + .slice_id = 17, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CPUSS1, + .slice_id = 3, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CAMEXP0, + .slice_id = 4, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_CPUMTE, + .slice_id = 23, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CPUHWT, + .slice_id = 5, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CAMEXP1, + .slice_id = 27, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_AENPU, + .slice_id = 8, + .max_cap = 2048, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffff, + .cache_mode = 0, + }, }; static const struct llcc_slice_config sm8550_data[] = { - {LLCC_CPUSS, 1, 5120, 1, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_VIDSC0, 2, 512, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_AUDIO, 6, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_MDMHPGRW, 25, 1024, 4, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_MODHW, 26, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CMPT, 10, 4096, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_GPU, 9, 3096, 1, 0, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_MMUHWT, 18, 768, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_DISP, 16, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_MDMPNG, 27, 1024, 0, 1, 0xF00000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CVP, 8, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_MODPE, 29, 64, 1, 1, 0xF00000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, }, - {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CAMEXP0, 4, 256, 4, 1, 0xF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CPUHWT, 5, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CAMEXP1, 7, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CMPTHCP, 17, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_LCPDARE, 30, 128, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, }, - {LLCC_AENPU, 3, 3072, 1, 1, 0xFE01FF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_ISLAND1, 12, 1792, 7, 1, 0xFE00, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_ISLAND4, 15, 256, 7, 1, 0x10000, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CAMEXP2, 19, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CAMEXP3, 20, 3200, 2, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_CAMEXP4, 21, 3200, 2, 1, 0xFFFFF0, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_DISP_WB, 23, 1024, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_DISP_1, 24, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - {LLCC_VIDVSP, 28, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 5120, + .priority = 1, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 25, + .max_cap = 1024, + .priority = 4, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 26, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 4096, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 9, + .max_cap = 3096, + .priority = 1, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .write_scid_en = true, + .write_scid_cacheable_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 18, + .max_cap = 768, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 2, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 27, + .max_cap = 1024, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0xf00000, + .cache_mode = 0, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 8, + .max_cap = 256, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 64, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf00000, + .cache_mode = 0, + .alloc_oneway_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CAMEXP0, + .slice_id = 4, + .max_cap = 256, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CPUHWT, + .slice_id = 5, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CAMEXP1, + .slice_id = 7, + .max_cap = 3200, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfffff0, + .cache_mode = 2, + }, { + .usecase_id = LLCC_CMPTHCP, + .slice_id = 17, + .max_cap = 256, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_LCPDARE, + .slice_id = 30, + .max_cap = 128, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + .alloc_oneway_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_AENPU, + .slice_id = 3, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfe01ff, + .cache_mode = 2, + }, { + .usecase_id = LLCC_ISLAND1, + .slice_id = 12, + .max_cap = 1792, + .priority = 7, + .fixed_size = true, + .bonus_ways = 0xfe00, + .cache_mode = 0, + }, { + .usecase_id = LLCC_ISLAND4, + .slice_id = 15, + .max_cap = 256, + .priority = 7, + .fixed_size = true, + .bonus_ways = 0x10000, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CAMEXP2, + .slice_id = 19, + .max_cap = 3200, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfffff0, + .cache_mode = 2, + }, { + .usecase_id = LLCC_CAMEXP3, + .slice_id = 20, + .max_cap = 3200, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfffff0, + .cache_mode = 2, + }, { + .usecase_id = LLCC_CAMEXP4, + .slice_id = 21, + .max_cap = 3200, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xfffff0, + .cache_mode = 2, + }, { + .usecase_id = LLCC_DISP_WB, + .slice_id = 23, + .max_cap = 1024, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_DISP_1, + .slice_id = 24, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 2, + }, { + .usecase_id = LLCC_VIDVSP, + .slice_id = 28, + .max_cap = 256, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, }; static const struct llcc_slice_config sm8650_data[] = { - {LLCC_CPUSS, 1, 5120, 1, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_VIDSC0, 2, 512, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_AUDIO, 6, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_MDMHPGRW, 25, 1024, 3, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_MODHW, 26, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CMPT, 10, 4096, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_GPU, 9, 3096, 1, 0, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_MMUHWT, 18, 768, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_DISP, 16, 6144, 1, 1, 0xFFFFFF, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_MDMHPFX, 24, 1024, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_MDMPNG, 27, 1024, 0, 1, 0x000000, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CVP, 8, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_MODPE, 29, 128, 1, 1, 0xF00000, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP0, 4, 256, 3, 1, 0xF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP1, 7, 3200, 3, 1, 0xFFFFF0, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CMPTHCP, 17, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_LCPDARE, 30, 128, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_AENPU, 3, 3072, 1, 1, 0xFFFFFF, 0x0, 2, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_ISLAND1, 12, 5888, 7, 1, 0x0, 0x7FFFFF, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_DISP_WB, 23, 1024, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_VIDVSP, 28, 256, 3, 1, 0xFFFFFF, 0x0, 0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 5120, + .priority = 1, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + .stale_en = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 25, + .max_cap = 1024, + .priority = 3, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 26, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 4096, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 9, + .max_cap = 3096, + .priority = 1, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .write_scid_en = true, + .write_scid_cacheable_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 18, + .max_cap = 768, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_DISP, + .slice_id = 16, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 2, + }, { + .usecase_id = LLCC_MDMHPFX, + .slice_id = 24, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 27, + .max_cap = 1024, + .priority = 0, + .fixed_size = true, + .cache_mode = 0, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 8, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 128, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf00000, + .cache_mode = 0, + .alloc_oneway_en = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CAMEXP0, + .slice_id = 4, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CAMEXP1, + .slice_id = 7, + .max_cap = 3200, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfffff0, + .cache_mode = 2, + }, { + .usecase_id = LLCC_CMPTHCP, + .slice_id = 17, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_LCPDARE, + .slice_id = 30, + .max_cap = 128, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + .activate_on_init = true, + .alloc_oneway_en = true, + }, { + .usecase_id = LLCC_AENPU, + .slice_id = 3, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 2, + }, { + .usecase_id = LLCC_ISLAND1, + .slice_id = 12, + .max_cap = 5888, + .priority = 7, + .fixed_size = true, + .res_ways = 0x7fffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_DISP_WB, + .slice_id = 23, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_VIDVSP, + .slice_id = 28, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffffff, + .cache_mode = 0, + }, +}; + +static const struct llcc_slice_config qcs615_data[] = { + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 128, + .priority = 1, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MDM, + .slice_id = 8, + .max_cap = 256, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 128, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 128, + .priority = 1, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + }, +}; + +static const struct llcc_slice_config qcs8300_data[] = { + { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 128, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 12, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .retain_on_pc = true, + .write_scid_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 13, + .max_cap = 128, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_ECC, + .slice_id = 26, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 128, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf, + .cache_mode = 0, + .activate_on_init = true, + }, }; static const struct llcc_slice_config qdu1000_data_2ch[] = { - { LLCC_MDMHPGRW, 7, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_MODHW, 9, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_MDMPNG, 21, 256, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_ECC, 26, 512, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 }, - { LLCC_MODPE, 29, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_APTCM, 30, 256, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 }, - { LLCC_WRCACHE, 31, 128, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 }, + { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 9, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 256, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0x3, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_ECC, + .slice_id = 26, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffc, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .res_ways = 0xc, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 128, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3, + .cache_mode = 0, + .activate_on_init = true, + }, }; static const struct llcc_slice_config qdu1000_data_4ch[] = { - { LLCC_MDMHPGRW, 7, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_MODHW, 9, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_MDMPNG, 21, 512, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_ECC, 26, 1024, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 }, - { LLCC_MODPE, 29, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_APTCM, 30, 512, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 }, - { LLCC_WRCACHE, 31, 256, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 }, + { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 9, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 512, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0x3, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_ECC, + .slice_id = 26, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffc, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .res_ways = 0xc, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3, + .cache_mode = 0, + .activate_on_init = true, + }, }; static const struct llcc_slice_config qdu1000_data_8ch[] = { - { LLCC_MDMHPGRW, 7, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_MDMPNG, 21, 1024, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_ECC, 26, 2048, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 }, - { LLCC_MODPE, 29, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, - { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 }, - { LLCC_WRCACHE, 31, 512, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 }, + { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 7, + .max_cap = 2048, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MODHW, + .slice_id = 9, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_MDMPNG, + .slice_id = 21, + .max_cap = 1024, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0x3, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_ECC, + .slice_id = 26, + .max_cap = 2048, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffc, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_APTCM, + .slice_id = 30, + .max_cap = 1024, + .priority = 3, + .fixed_size = true, + .res_ways = 0xc, + .cache_mode = 1, + .retain_on_pc = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0x3, + .cache_mode = 0, + .activate_on_init = true, + }, }; static const struct llcc_slice_config x1e80100_data[] = { - {LLCC_CPUSS, 1, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_VIDSC0, 2, 512, 4, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_AUDIO, 6, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CMPT, 10, 6144, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_GPUHTW, 11, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_GPU, 9, 4608, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_MMUHWT, 18, 512, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_AUDHW, 22, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CVP, 8, 512, 4, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_WRCACHE, 31, 1024, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP0, 4, 256, 4, 1, 0x3, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP1, 7, 3072, 3, 1, 0xFFC, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_LCPDARE, 30, 512, 3, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}, - {LLCC_AENPU, 3, 3072, 1, 1, 0xFFF, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_ISLAND1, 12, 2048, 7, 1, 0x0, 0xF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP2, 19, 3072, 3, 1, 0xFFC, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP3, 20, 3072, 2, 1, 0xFFC, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {LLCC_CAMEXP4, 21, 3072, 2, 1, 0xFFC, 0x0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 6144, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 9, + .max_cap = 4608, + .priority = 1, + .bonus_ways = 0xfff, + .cache_mode = 0, + .write_scid_en = true, + .write_scid_cacheable_en = true, + .stale_en = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 18, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 8, + .max_cap = 512, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CAMEXP0, + .slice_id = 4, + .max_cap = 256, + .priority = 4, + .fixed_size = true, + .bonus_ways = 0x3, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CAMEXP1, + .slice_id = 7, + .max_cap = 3072, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffc, + .cache_mode = 2, + }, { + .usecase_id = LLCC_LCPDARE, + .slice_id = 30, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 0, + .activate_on_init = true, + .alloc_oneway_en = true, + }, { + .usecase_id = LLCC_AENPU, + .slice_id = 3, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .cache_mode = 2, + }, { + .usecase_id = LLCC_ISLAND1, + .slice_id = 12, + .max_cap = 2048, + .priority = 7, + .fixed_size = true, + .res_ways = 0xf, + .cache_mode = 0, + }, { + .usecase_id = LLCC_CAMEXP2, + .slice_id = 19, + .max_cap = 3072, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xffc, + .cache_mode = 2, + }, { + .usecase_id = LLCC_CAMEXP3, + .slice_id = 20, + .max_cap = 3072, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xffc, + .cache_mode = 2, + }, { + .usecase_id = LLCC_CAMEXP4, + .slice_id = 21, + .max_cap = 3072, + .priority = 2, + .fixed_size = true, + .bonus_ways = 0xffc, + .cache_mode = 2, + }, }; static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { @@ -540,32 +3139,47 @@ static const u32 llcc_v2_1_reg_offset[] = { [LLCC_COMMON_STATUS0] = 0x0003400c, }; +static const struct qcom_llcc_config qcs615_cfg[] = { + { + .sct_data = qcs615_data, + .size = ARRAY_SIZE(qcs615_data), + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config qcs8300_cfg[] = { + { + .sct_data = qcs8300_data, + .size = ARRAY_SIZE(qcs8300_data), + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + .num_banks = 4, + }, +}; + static const struct qcom_llcc_config qdu1000_cfg[] = { { .sct_data = qdu1000_data_8ch, .size = ARRAY_SIZE(qdu1000_data_8ch), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, }, { .sct_data = qdu1000_data_4ch, .size = ARRAY_SIZE(qdu1000_data_4ch), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, }, { .sct_data = qdu1000_data_4ch, .size = ARRAY_SIZE(qdu1000_data_4ch), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, }, { .sct_data = qdu1000_data_2ch, .size = ARRAY_SIZE(qdu1000_data_2ch), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, }, @@ -575,17 +3189,37 @@ static const struct qcom_llcc_config sa8775p_cfg[] = { { .sct_data = sa8775p_data, .size = ARRAY_SIZE(sa8775p_data), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, }, }; +static const struct qcom_llcc_config sar1130p_cfg[] = { + { + .sct_data = sar1130p_data, + .size = ARRAY_SIZE(sar1130p_data), + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + .max_cap_shift = 14, + .num_banks = 2, + }, +}; + +static const struct qcom_llcc_config sar2130p_cfg[] = { + { + .sct_data = sar2130p_data, + .size = ARRAY_SIZE(sar2130p_data), + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + .max_cap_shift = 14, + .num_banks = 2, + }, +}; + static const struct qcom_llcc_config sc7180_cfg[] = { { .sct_data = sc7180_data, .size = ARRAY_SIZE(sc7180_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -595,7 +3229,6 @@ static const struct qcom_llcc_config sc7280_cfg[] = { { .sct_data = sc7280_data, .size = ARRAY_SIZE(sc7280_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -605,7 +3238,6 @@ static const struct qcom_llcc_config sc8180x_cfg[] = { { .sct_data = sc8180x_data, .size = ARRAY_SIZE(sc8180x_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -615,7 +3247,6 @@ static const struct qcom_llcc_config sc8280xp_cfg[] = { { .sct_data = sc8280xp_data, .size = ARRAY_SIZE(sc8280xp_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -625,7 +3256,7 @@ static const struct qcom_llcc_config sdm845_cfg[] = { { .sct_data = sdm845_data, .size = ARRAY_SIZE(sdm845_data), - .need_llcc_cfg = false, + .skip_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, .no_edac = true, @@ -636,7 +3267,6 @@ static const struct qcom_llcc_config sm6350_cfg[] = { { .sct_data = sm6350_data, .size = ARRAY_SIZE(sm6350_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -646,7 +3276,6 @@ static const struct qcom_llcc_config sm7150_cfg[] = { { .sct_data = sm7150_data, .size = ARRAY_SIZE(sm7150_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -656,7 +3285,6 @@ static const struct qcom_llcc_config sm8150_cfg[] = { { .sct_data = sm8150_data, .size = ARRAY_SIZE(sm8150_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -666,7 +3294,6 @@ static const struct qcom_llcc_config sm8250_cfg[] = { { .sct_data = sm8250_data, .size = ARRAY_SIZE(sm8250_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -676,7 +3303,6 @@ static const struct qcom_llcc_config sm8350_cfg[] = { { .sct_data = sm8350_data, .size = ARRAY_SIZE(sm8350_data), - .need_llcc_cfg = true, .reg_offset = llcc_v1_reg_offset, .edac_reg_offset = &llcc_v1_edac_reg_offset, }, @@ -686,7 +3312,6 @@ static const struct qcom_llcc_config sm8450_cfg[] = { { .sct_data = sm8450_data, .size = ARRAY_SIZE(sm8450_data), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, }, @@ -696,7 +3321,6 @@ static const struct qcom_llcc_config sm8550_cfg[] = { { .sct_data = sm8550_data, .size = ARRAY_SIZE(sm8550_data), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, }, @@ -706,7 +3330,6 @@ static const struct qcom_llcc_config sm8650_cfg[] = { { .sct_data = sm8650_data, .size = ARRAY_SIZE(sm8650_data), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, }, @@ -716,13 +3339,22 @@ static const struct qcom_llcc_config x1e80100_cfg[] = { { .sct_data = x1e80100_data, .size = ARRAY_SIZE(x1e80100_data), - .need_llcc_cfg = true, .reg_offset = llcc_v2_1_reg_offset, .edac_reg_offset = &llcc_v2_1_edac_reg_offset, .irq_configured = true, }, }; +static const struct qcom_sct_config qcs615_cfgs = { + .llcc_config = qcs615_cfg, + .num_config = ARRAY_SIZE(qcs615_cfg), +}; + +static const struct qcom_sct_config qcs8300_cfgs = { + .llcc_config = qcs8300_cfg, + .num_config = ARRAY_SIZE(qcs8300_cfg), +}; + static const struct qcom_sct_config qdu1000_cfgs = { .llcc_config = qdu1000_cfg, .num_config = ARRAY_SIZE(qdu1000_cfg), @@ -733,6 +3365,16 @@ static const struct qcom_sct_config sa8775p_cfgs = { .num_config = ARRAY_SIZE(sa8775p_cfg), }; +static const struct qcom_sct_config sar1130p_cfgs = { + .llcc_config = sar1130p_cfg, + .num_config = ARRAY_SIZE(sar1130p_cfg), +}; + +static const struct qcom_sct_config sar2130p_cfgs = { + .llcc_config = sar2130p_cfg, + .num_config = ARRAY_SIZE(sar2130p_cfg), +}; + static const struct qcom_sct_config sc7180_cfgs = { .llcc_config = sc7180_cfg, .num_config = ARRAY_SIZE(sc7180_cfg), @@ -1040,7 +3682,10 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config, */ max_cap_cacheline = max_cap_cacheline / drv_data->num_banks; max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT; - attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT; + if (cfg->max_cap_shift) + attr1_val |= max_cap_cacheline << cfg->max_cap_shift; + else + attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT; attr1_cfg = LLCC_TRP_ATTR1_CFGn(config->slice_id); @@ -1069,7 +3714,8 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config, return ret; } - if (cfg->need_llcc_cfg) { + /* At least SDM845 disallows non-secure writes to these registers */ + if (!cfg->skip_llcc_cfg) { u32 disable_cap_alloc, retain_pc; disable_cap_alloc = config->dis_cap_alloc << config->slice_id; @@ -1277,12 +3923,17 @@ static int qcom_llcc_probe(struct platform_device *pdev) goto err; cfg = &cfgs->llcc_config[cfg_index]; - ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks); - if (ret) - goto err; + if (cfg->num_banks) { + num_banks = cfg->num_banks; + } else { + ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks); + if (ret) + goto err; + + num_banks &= LLCC_LB_CNT_MASK; + num_banks >>= LLCC_LB_CNT_SHIFT; + } - num_banks &= LLCC_LB_CNT_MASK; - num_banks >>= LLCC_LB_CNT_SHIFT; drv_data->num_banks = num_banks; drv_data->regmaps = devm_kcalloc(dev, num_banks, sizeof(*drv_data->regmaps), GFP_KERNEL); @@ -1378,8 +4029,12 @@ static int qcom_llcc_probe(struct platform_device *pdev) } static const struct of_device_id qcom_llcc_of_match[] = { + { .compatible = "qcom,qcs615-llcc", .data = &qcs615_cfgs}, + { .compatible = "qcom,qcs8300-llcc", .data = &qcs8300_cfgs}, { .compatible = "qcom,qdu1000-llcc", .data = &qdu1000_cfgs}, { .compatible = "qcom,sa8775p-llcc", .data = &sa8775p_cfgs }, + { .compatible = "qcom,sar1130p-llcc", .data = &sar1130p_cfgs }, + { .compatible = "qcom,sar2130p-llcc", .data = &sar2130p_cfgs }, { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfgs }, { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfgs }, { .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfgs }, @@ -1404,7 +4059,7 @@ static struct platform_driver qcom_llcc_driver = { .of_match_table = qcom_llcc_of_match, }, .probe = qcom_llcc_probe, - .remove_new = qcom_llcc_remove, + .remove = qcom_llcc_remove, }; module_platform_driver(qcom_llcc_driver); diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index ff8df7d75d6b26..9c3bd37b6579d3 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -439,7 +439,7 @@ MODULE_DEVICE_TABLE(of, ocmem_of_match); static struct platform_driver ocmem_driver = { .probe = ocmem_dev_probe, - .remove_new = ocmem_dev_remove, + .remove = ocmem_dev_remove, .driver = { .name = "ocmem", .of_match_table = ocmem_of_match, diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index baa4ac6704a901..caf3f63d940e35 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -399,7 +399,7 @@ MODULE_DEVICE_TABLE(of, pmic_glink_of_match); static struct platform_driver pmic_glink_driver = { .probe = pmic_glink_probe, - .remove_new = pmic_glink_remove, + .remove = pmic_glink_remove, .driver = { .name = "qcom_pmic_glink", .of_match_table = pmic_glink_of_match, diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 2e8f24d5da80b6..4cb959106efa9e 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -585,7 +585,8 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { freq = clk_round_rate(se->clk, freq + 1); - if (freq <= 0 || freq == se->clk_perf_tbl[i - 1]) + if (freq <= 0 || + (i > 0 && freq == se->clk_perf_tbl[i - 1])) break; se->clk_perf_tbl[i] = freq; } diff --git a/drivers/soc/qcom/qcom-pbs.c b/drivers/soc/qcom/qcom-pbs.c index 77a70d3d0d0b51..1cc5d045f9ddfe 100644 --- a/drivers/soc/qcom/qcom-pbs.c +++ b/drivers/soc/qcom/qcom-pbs.c @@ -84,16 +84,16 @@ int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap) if (IS_ERR_OR_NULL(pbs)) return -EINVAL; - mutex_lock(&pbs->lock); + guard(mutex)(&pbs->lock); ret = regmap_read(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, &val); if (ret < 0) - goto out; + return ret; if (val == PBS_CLIENT_SCRATCH2_ERROR) { /* PBS error - clear SCRATCH2 register */ ret = regmap_write(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, 0); if (ret < 0) - goto out; + return ret; } for (bit_pos = 0; bit_pos < 8; bit_pos++) { @@ -104,37 +104,31 @@ int qcom_pbs_trigger_event(struct pbs_dev *pbs, u8 bitmap) ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0); if (ret < 0) - goto out_clear_scratch1; + break; /* Set the PBS sequence bit position */ ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, BIT(bit_pos), BIT(bit_pos)); if (ret < 0) - goto out_clear_scratch1; + break; /* Initiate the SW trigger */ ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_TRIG_CTL, PBS_CLIENT_SW_TRIG_BIT, PBS_CLIENT_SW_TRIG_BIT); if (ret < 0) - goto out_clear_scratch1; + break; ret = qcom_pbs_wait_for_ack(pbs, bit_pos); if (ret < 0) - goto out_clear_scratch1; + break; /* Clear the PBS sequence bit position */ regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, BIT(bit_pos), 0); regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0); } -out_clear_scratch1: /* Clear all the requested bitmap */ - ret = regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, bitmap, 0); - -out: - mutex_unlock(&pbs->lock); - - return ret; + return regmap_update_bits(pbs->regmap, pbs->base + PBS_CLIENT_SCRATCH1, bitmap, 0); } EXPORT_SYMBOL_GPL(qcom_pbs_trigger_event); diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 60af26667bce45..0320ad3b91483d 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -664,7 +664,7 @@ static struct platform_driver qmp_driver = { .suppress_bind_attrs = true, }, .probe = qmp_probe, - .remove_new = qmp_remove, + .remove = qmp_remove, }; module_platform_driver(qmp_driver); diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c index f04b9a324ea9ce..8f1158e0c6313a 100644 --- a/drivers/soc/qcom/qcom_gsbi.c +++ b/drivers/soc/qcom/qcom_gsbi.c @@ -232,7 +232,7 @@ static struct platform_driver gsbi_driver = { .of_match_table = gsbi_dt_match, }, .probe = gsbi_probe, - .remove_new = gsbi_remove, + .remove = gsbi_remove, }; module_platform_driver(gsbi_driver); diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c index c940f4da28ed5c..6e30f08761aa43 100644 --- a/drivers/soc/qcom/qcom_pd_mapper.c +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -540,6 +540,7 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = { { .compatible = "qcom,msm8996", .data = msm8996_domains, }, { .compatible = "qcom,msm8998", .data = msm8998_domains, }, { .compatible = "qcom,qcm2290", .data = qcm2290_domains, }, + { .compatible = "qcom,qcm6490", .data = sc7280_domains, }, { .compatible = "qcom,qcs404", .data = qcs404_domains, }, { .compatible = "qcom,sc7180", .data = sc7180_domains, }, { .compatible = "qcom,sc7280", .data = sc7280_domains, }, diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index c429d5154aaec2..5de99cf59b9fbe 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -274,7 +274,7 @@ MODULE_DEVICE_TABLE(of, qcom_stats_table); static struct platform_driver qcom_stats = { .probe = qcom_stats_probe, - .remove_new = qcom_stats_remove, + .remove = qcom_stats_remove, .driver = { .name = "qcom_stats", .of_match_table = qcom_stats_table, diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index bb98b06e87f88e..bc6d6379d8b1bb 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -195,8 +195,8 @@ static void qmi_send_new_lookup(struct qmi_handle *qmi, struct qmi_service *svc) * qmi_add_lookup() - register a new lookup with the name service * @qmi: qmi handle * @service: service id of the request - * @instance: instance id of the request * @version: version number of the request + * @instance: instance id of the request * * Registering a lookup query with the name server will cause the name server * to send NEW_SERVER and DEL_SERVER control messages to this socket as diff --git a/drivers/soc/qcom/ramp_controller.c b/drivers/soc/qcom/ramp_controller.c index e9a0cca0718924..349bdfbc61eff9 100644 --- a/drivers/soc/qcom/ramp_controller.c +++ b/drivers/soc/qcom/ramp_controller.c @@ -331,8 +331,8 @@ static struct platform_driver qcom_ramp_controller_driver = { .of_match_table = qcom_ramp_controller_match_table, .suppress_bind_attrs = true, }, - .probe = qcom_ramp_controller_probe, - .remove_new = qcom_ramp_controller_remove, + .probe = qcom_ramp_controller_probe, + .remove = qcom_ramp_controller_remove, }; static int __init qcom_ramp_controller_init(void) diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index df850d0731022d..33603b8fd8f38e 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c @@ -315,7 +315,7 @@ MODULE_DEVICE_TABLE(of, qcom_rmtfs_mem_of_match); static struct platform_driver qcom_rmtfs_mem_driver = { .probe = qcom_rmtfs_mem_probe, - .remove_new = qcom_rmtfs_mem_remove, + .remove = qcom_rmtfs_mem_remove, .driver = { .name = "qcom_rmtfs_mem", .of_match_table = qcom_rmtfs_mem_of_match, diff --git a/drivers/soc/qcom/rpm-proc.c b/drivers/soc/qcom/rpm-proc.c index 2995d9b901903e..2466d0400c2e9a 100644 --- a/drivers/soc/qcom/rpm-proc.c +++ b/drivers/soc/qcom/rpm-proc.c @@ -53,7 +53,7 @@ MODULE_DEVICE_TABLE(of, rpm_proc_of_match); static struct platform_driver rpm_proc_driver = { .probe = rpm_proc_probe, - .remove_new = rpm_proc_remove, + .remove = rpm_proc_remove, .driver = { .name = "qcom-rpm-proc", .of_match_table = rpm_proc_of_match, diff --git a/drivers/soc/qcom/rpm_master_stats.c b/drivers/soc/qcom/rpm_master_stats.c index 086fe4ba6707fe..49e4f945727927 100644 --- a/drivers/soc/qcom/rpm_master_stats.c +++ b/drivers/soc/qcom/rpm_master_stats.c @@ -155,7 +155,7 @@ static const struct of_device_id rpm_master_table[] = { static struct platform_driver master_stats_driver = { .probe = master_stats_probe, - .remove_new = master_stats_remove, + .remove = master_stats_remove, .driver = { .name = "qcom_rpm_master_stats", .of_match_table = rpm_master_table, diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index de86009ecd913d..cb82e887b51d44 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -1045,12 +1045,9 @@ static int rpmh_rsc_probe(struct platform_device *pdev) * do. To avoid adding this check to our children we'll do it now. */ ret = cmd_db_ready(); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Command DB not available (%d)\n", - ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Command DB not available\n"); drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index e4411771f482f8..59281970180921 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -499,6 +499,8 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem, * * Allocate space for a given smem item of size @size, given that the item is * not yet allocated. + * + * Return: 0 on success, negative errno on failure. */ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) { @@ -677,6 +679,8 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, * * Looks up smem item and returns pointer to it. Size of smem * item is returned in @size. + * + * Return: a pointer to an SMEM item on success, ERR_PTR() on failure. */ void *qcom_smem_get(unsigned host, unsigned item, size_t *size) { @@ -709,6 +713,8 @@ EXPORT_SYMBOL_GPL(qcom_smem_get); * * To be used by smem clients as a quick way to determine if any new * allocations has been made. + * + * Return: number of available bytes on success, negative errno on failure. */ int qcom_smem_get_free_space(unsigned host) { @@ -758,7 +764,7 @@ static bool addr_in_range(void __iomem *base, size_t size, void *addr) * with an smem item pointer (previously returned by qcom_smem_get() * @p: the virtual address to convert * - * Returns 0 if the pointer provided is not within any smem region. + * Return: physical address of the SMEM item (if found), 0 otherwise */ phys_addr_t qcom_smem_virt_to_phys(void *p) { @@ -1180,11 +1186,9 @@ static int qcom_smem_probe(struct platform_device *pdev) } hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); - if (hwlock_id < 0) { - if (hwlock_id != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to retrieve hwlock\n"); - return hwlock_id; - } + if (hwlock_id < 0) + return dev_err_probe(&pdev->dev, hwlock_id, + "failed to retrieve hwlock\n"); smem->hwlock = hwspin_lock_request_specific(hwlock_id); if (!smem->hwlock) @@ -1251,7 +1255,7 @@ MODULE_DEVICE_TABLE(of, qcom_smem_of_match); static struct platform_driver qcom_smem_driver = { .probe = qcom_smem_probe, - .remove_new = qcom_smem_remove, + .remove = qcom_smem_remove, .driver = { .name = "qcom-smem", .of_match_table = qcom_smem_of_match, diff --git a/drivers/soc/qcom/smem_state.c b/drivers/soc/qcom/smem_state.c index e848cc9a3cf801..d9bfac6c54fb8a 100644 --- a/drivers/soc/qcom/smem_state.c +++ b/drivers/soc/qcom/smem_state.c @@ -3,6 +3,7 @@ * Copyright (c) 2015, Sony Mobile Communications Inc. * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -60,20 +61,15 @@ static struct qcom_smem_state *of_node_to_state(struct device_node *np) { struct qcom_smem_state *state; - mutex_lock(&list_lock); + guard(mutex)(&list_lock); list_for_each_entry(state, &smem_states, list) { if (state->of_node == np) { kref_get(&state->refcount); - goto unlock; + return state; } } - state = ERR_PTR(-EPROBE_DEFER); - -unlock: - mutex_unlock(&list_lock); - - return state; + return ERR_PTR(-EPROBE_DEFER); } /** diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index cefcbd61c62815..4783ab1adb8d95 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -467,12 +467,9 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) int ret; ret = qcom_smem_alloc(pid, smem_id, sizeof(*out)); - if (ret < 0 && ret != -EEXIST) { - if (ret != -EPROBE_DEFER) - dev_err(smp2p->dev, - "unable to allocate local smp2p item\n"); - return ret; - } + if (ret < 0 && ret != -EEXIST) + return dev_err_probe(smp2p->dev, ret, + "unable to allocate local smp2p item\n"); out = qcom_smem_get(pid, smem_id, NULL); if (IS_ERR(out)) { @@ -698,7 +695,7 @@ MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match); static struct platform_driver qcom_smp2p_driver = { .probe = qcom_smp2p_probe, - .remove_new = qcom_smp2p_remove, + .remove = qcom_smp2p_remove, .driver = { .name = "qcom_smp2p", .of_match_table = qcom_smp2p_of_match, diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c index ffe78ae3438648..e803ea342c971e 100644 --- a/drivers/soc/qcom/smsm.c +++ b/drivers/soc/qcom/smsm.c @@ -682,9 +682,9 @@ MODULE_DEVICE_TABLE(of, qcom_smsm_of_match); static struct platform_driver qcom_smsm_driver = { .probe = qcom_smsm_probe, - .remove_new = qcom_smsm_remove, - .driver = { - .name = "qcom-smsm", + .remove = qcom_smsm_remove, + .driver = { + .name = "qcom-smsm", .of_match_table = qcom_smsm_of_match, }, }; diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index ecfd3da9d5e877..62fadfe44a09f8 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -422,8 +422,10 @@ static const struct soc_id soc_id[] = { { qcom_board_id(IPQ9510) }, { qcom_board_id(QRB4210) }, { qcom_board_id(QRB2210) }, + { qcom_board_id(SAR2130P) }, { qcom_board_id(SM8475) }, { qcom_board_id(SM8475P) }, + { qcom_board_id(SA8255P) }, { qcom_board_id(SA8775P) }, { qcom_board_id(QRU1000) }, { qcom_board_id(SM8475_2) }, @@ -431,6 +433,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(X1E80100) }, { qcom_board_id(SM8650) }, { qcom_board_id(SM4450) }, + { qcom_board_id(SAR1130P) }, { qcom_board_id(QDU1010) }, { qcom_board_id(QRU1032) }, { qcom_board_id(QRU1052) }, @@ -443,8 +446,12 @@ static const struct soc_id soc_id[] = { { qcom_board_id(QCM8550) }, { qcom_board_id(IPQ5300) }, { qcom_board_id(IPQ5321) }, + { qcom_board_id(IPQ5424) }, + { qcom_board_id(IPQ5404) }, + { qcom_board_id(QCS9100) }, { qcom_board_id(QCS8300) }, { qcom_board_id(QCS8275) }, + { qcom_board_id(QCS615) }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) @@ -822,7 +829,7 @@ static void qcom_socinfo_remove(struct platform_device *pdev) static struct platform_driver qcom_socinfo_driver = { .probe = qcom_socinfo_probe, - .remove_new = qcom_socinfo_remove, + .remove = qcom_socinfo_remove, .driver = { .name = "qcom-socinfo", }, diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 5d94c3f3149448..9f7fe02310b9ad 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -347,6 +347,7 @@ config ARCH_R9A09G011 config ARCH_R9A09G057 bool "ARM64 Platform support for RZ/V2H(P)" + select RENESAS_RZV2H_ICU help This enables support for the Renesas RZ/V2H(P) SoC variants. diff --git a/drivers/soc/rockchip/io-domain.c b/drivers/soc/rockchip/io-domain.c index fd9fd31f71c253..f94985a905c296 100644 --- a/drivers/soc/rockchip/io-domain.c +++ b/drivers/soc/rockchip/io-domain.c @@ -742,10 +742,10 @@ static void rockchip_iodomain_remove(struct platform_device *pdev) } static struct platform_driver rockchip_iodomain_driver = { - .probe = rockchip_iodomain_probe, - .remove_new = rockchip_iodomain_remove, - .driver = { - .name = "rockchip-iodomain", + .probe = rockchip_iodomain_probe, + .remove = rockchip_iodomain_remove, + .driver = { + .name = "rockchip-iodomain", .of_match_table = rockchip_iodomain_match, }, }; diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index b1118d37779e46..e37dde1fb588ec 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -58,6 +58,9 @@ static const struct exynos_soc_id { /* Compatible with: samsung,exynos850-chipid */ { "EXYNOS7885", 0xE7885000 }, { "EXYNOS850", 0xE3830000 }, + { "EXYNOS8895", 0xE8895000 }, + { "EXYNOS9810", 0xE9810000 }, + { "EXYNOS990", 0xE9830000 }, { "EXYNOSAUTOV9", 0xAAA80000 }, { "EXYNOSAUTOV920", 0x0A920000 }, }; @@ -195,8 +198,8 @@ static struct platform_driver exynos_chipid_driver = { .name = "exynos-chipid", .of_match_table = exynos_chipid_of_device_ids, }, - .probe = exynos_chipid_probe, - .remove_new = exynos_chipid_remove, + .probe = exynos_chipid_probe, + .remove = exynos_chipid_remove, }; module_platform_driver(exynos_chipid_driver); diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c index 9cbc562ae7d37a..846b17ffc2f972 100644 --- a/drivers/soc/tegra/cbb/tegra194-cbb.c +++ b/drivers/soc/tegra/cbb/tegra194-cbb.c @@ -2330,7 +2330,7 @@ static const struct dev_pm_ops tegra194_cbb_pm = { static struct platform_driver tegra194_cbb_driver = { .probe = tegra194_cbb_probe, - .remove_new = tegra194_cbb_remove, + .remove = tegra194_cbb_remove, .driver = { .name = "tegra194-cbb", .of_match_table = of_match_ptr(tegra194_cbb_match), diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c index 8c01029683515c..82a15cad1c6c43 100644 --- a/drivers/soc/ti/k3-ringacc.c +++ b/drivers/soc/ti/k3-ringacc.c @@ -1562,7 +1562,7 @@ static void k3_ringacc_remove(struct platform_device *pdev) static struct platform_driver k3_ringacc_driver = { .probe = k3_ringacc_probe, - .remove_new = k3_ringacc_remove, + .remove = k3_ringacc_remove, .driver = { .name = "k3-ringacc", .of_match_table = k3_ringacc_of_match, diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index fb0746d8caad4a..a25ebe6cd5030d 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -783,8 +783,8 @@ MODULE_DEVICE_TABLE(of, of_match); static struct platform_driver knav_dma_driver = { .probe = knav_dma_probe, - .remove_new = knav_dma_remove, - .driver = { + .remove = knav_dma_remove, + .driver = { .name = "keystone-navigator-dma", .of_match_table = of_match, }, diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 6c98738e548a80..ea52425864a9c5 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -119,11 +119,10 @@ static int knav_queue_setup_irq(struct knav_range_info *range, if (range->flags & RANGE_HAS_IRQ) { irq = range->irqs[queue].irq; - ret = request_irq(irq, knav_queue_int_handler, 0, - inst->irq_name, inst); + ret = request_irq(irq, knav_queue_int_handler, IRQF_NO_AUTOEN, + inst->irq_name, inst); if (ret) return ret; - disable_irq(irq); if (range->irqs[queue].cpu_mask) { ret = irq_set_affinity_hint(irq, range->irqs[queue].cpu_mask); if (ret) { @@ -723,7 +722,6 @@ static void kdesc_empty_pool(struct knav_pool *pool) if (!desc) { dev_dbg(pool->kdev->dev, "couldn't unmap desc, continuing\n"); - continue; } } WARN_ON(i != pool->num_desc); @@ -1894,7 +1892,7 @@ static void knav_queue_remove(struct platform_device *pdev) static struct platform_driver keystone_qmss_driver = { .probe = knav_queue_probe, - .remove_new = knav_queue_remove, + .remove = knav_queue_remove, .driver = { .name = "keystone-navigator-qmss", .of_match_table = keystone_qmss_of_match, diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 8169885ab1e056..dfdff186c805c4 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -591,7 +591,7 @@ static struct platform_driver am33xx_pm_driver = { .name = "pm33xx", }, .probe = am33xx_pm_probe, - .remove_new = am33xx_pm_remove, + .remove = am33xx_pm_remove, }; module_platform_driver(am33xx_pm_driver); diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index 3ec758f50e2481..d7634bf5413a34 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -593,8 +593,8 @@ static struct platform_driver pruss_driver = { .name = "pruss", .of_match_table = pruss_of_match, }, - .probe = pruss_probe, - .remove_new = pruss_remove, + .probe = pruss_probe, + .remove = pruss_remove, }; module_platform_driver(pruss_driver); diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c index d6219060b616d6..ced3a73929e3b8 100644 --- a/drivers/soc/ti/smartreflex.c +++ b/drivers/soc/ti/smartreflex.c @@ -202,10 +202,10 @@ static int sr_late_init(struct omap_sr *sr_info) if (sr_class->notify && sr_class->notify_flags && sr_info->irq) { ret = devm_request_irq(&sr_info->pdev->dev, sr_info->irq, - sr_interrupt, 0, sr_info->name, sr_info); + sr_interrupt, IRQF_NO_AUTOEN, + sr_info->name, sr_info); if (ret) goto error; - disable_irq(sr_info->irq); } return ret; @@ -969,7 +969,7 @@ MODULE_DEVICE_TABLE(of, omap_sr_match); static struct platform_driver smartreflex_driver = { .probe = omap_sr_probe, - .remove_new = omap_sr_remove, + .remove = omap_sr_remove, .shutdown = omap_sr_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 88f774db920848..79dde9a7ec6394 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -755,7 +755,7 @@ MODULE_DEVICE_TABLE(of, wkup_m3_ipc_of_match); static struct platform_driver wkup_m3_ipc_driver = { .probe = wkup_m3_ipc_probe, - .remove_new = wkup_m3_ipc_remove, + .remove = wkup_m3_ipc_remove, .driver = { .name = "wkup_m3_ipc", .of_match_table = wkup_m3_ipc_of_match, diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c index f529e1346247cc..a572d15f616161 100644 --- a/drivers/soc/xilinx/xlnx_event_manager.c +++ b/drivers/soc/xilinx/xlnx_event_manager.c @@ -188,8 +188,10 @@ static int xlnx_add_cb_for_suspend(event_cb_func_t cb_fun, void *data) INIT_LIST_HEAD(&eve_data->cb_list_head); cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL); - if (!cb_data) + if (!cb_data) { + kfree(eve_data); return -ENOMEM; + } cb_data->eve_cb = cb_fun; cb_data->agent_data = data; @@ -709,7 +711,7 @@ static void xlnx_event_manager_remove(struct platform_device *pdev) static struct platform_driver xlnx_event_manager_driver = { .probe = xlnx_event_manager_probe, - .remove_new = xlnx_event_manager_remove, + .remove = xlnx_event_manager_remove, .driver = { .name = "xlnx_event_manager", }, diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 411d33f2fb053b..ae59bf16659a68 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -408,7 +408,7 @@ MODULE_DEVICE_TABLE(of, pm_of_match); static struct platform_driver zynqmp_pm_platform_driver = { .probe = zynqmp_pm_probe, - .remove_new = zynqmp_pm_remove, + .remove = zynqmp_pm_remove, .driver = { .name = "zynqmp_power", .of_match_table = pm_of_match, diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig index 4d8f3b7024ae59..f66f869dff2e51 100644 --- a/drivers/soundwire/Kconfig +++ b/drivers/soundwire/Kconfig @@ -6,6 +6,7 @@ menuconfig SOUNDWIRE tristate "SoundWire support" depends on ACPI || OF + depends on SND_SOC_SDCA_OPTIONAL help SoundWire is a 2-Pin interface with data and clock line ratified by the MIPI Alliance. SoundWire is used for transporting data diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c index db040f43505994..643e94524fe6da 100644 --- a/drivers/soundwire/amd_init.c +++ b/drivers/soundwire/amd_init.c @@ -121,6 +121,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) sdw_pdata[index].instance = index; sdw_pdata[index].acp_sdw_lock = res->acp_lock; + sdw_pdata[index].acp_rev = res->acp_rev; pdevinfo[index].name = "amd_sdw_manager"; pdevinfo[index].id = index; pdevinfo[index].parent = res->parent; @@ -172,15 +173,15 @@ int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx) return sdw_amd_startup(*sdw_ctx); } -EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT); +EXPORT_SYMBOL_NS(sdw_amd_probe, "SOUNDWIRE_AMD_INIT"); void sdw_amd_exit(struct sdw_amd_ctx *ctx) { sdw_amd_cleanup(ctx); - kfree(ctx->ids); + kfree(ctx->peripherals); kfree(ctx); } -EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT); +EXPORT_SYMBOL_NS(sdw_amd_exit, "SOUNDWIRE_AMD_INIT"); int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx) { @@ -204,10 +205,11 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx) num_slaves++; } - ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL); - if (!ctx->ids) + ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves), + GFP_KERNEL); + if (!ctx->peripherals) return -ENOMEM; - ctx->num_slaves = num_slaves; + ctx->peripherals->num_peripherals = num_slaves; for (index = 0; index < ctx->count; index++) { if (!(ctx->link_mask & BIT(index))) continue; @@ -215,15 +217,14 @@ int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx) if (amd_manager) { bus = &amd_manager->bus; list_for_each_entry(slave, &bus->slaves, node) { - ctx->ids[i].id = slave->id; - ctx->ids[i].link_id = bus->link_id; + ctx->peripherals->array[i] = slave; i++; } } } return 0; } -EXPORT_SYMBOL_NS(sdw_amd_get_slave_info, SOUNDWIRE_AMD_INIT); +EXPORT_SYMBOL_NS(sdw_amd_get_slave_info, "SOUNDWIRE_AMD_INIT"); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); MODULE_DESCRIPTION("AMD SoundWire Init Library"); diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c index 0d01849c358619..96a7f9709720bb 100644 --- a/drivers/soundwire/amd_manager.c +++ b/drivers/soundwire/amd_manager.c @@ -433,12 +433,18 @@ static int amd_sdw_port_params(struct sdw_bus *bus, struct sdw_port_params *p_pa 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; + switch (amd_manager->acp_rev) { + case ACP63_PCI_REV_ID: + switch (amd_manager->instance) { + case ACP_SDW0: + frame_fmt_reg = acp63_sdw0_dp_reg[p_params->num].frame_fmt_reg; + break; + case ACP_SDW1: + frame_fmt_reg = acp63_sdw1_dp_reg[p_params->num].frame_fmt_reg; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -465,20 +471,28 @@ static int amd_sdw_transport_params(struct sdw_bus *bus, 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; + switch (amd_manager->acp_rev) { + case ACP63_PCI_REV_ID: + switch (amd_manager->instance) { + case ACP_SDW0: + frame_fmt_reg = acp63_sdw0_dp_reg[params->port_num].frame_fmt_reg; + sample_int_reg = acp63_sdw0_dp_reg[params->port_num].sample_int_reg; + hctrl_dp0_reg = acp63_sdw0_dp_reg[params->port_num].hctrl_dp0_reg; + offset_reg = acp63_sdw0_dp_reg[params->port_num].offset_reg; + lane_ctrl_ch_en_reg = + acp63_sdw0_dp_reg[params->port_num].lane_ctrl_ch_en_reg; + break; + case ACP_SDW1: + frame_fmt_reg = acp63_sdw1_dp_reg[params->port_num].frame_fmt_reg; + sample_int_reg = acp63_sdw1_dp_reg[params->port_num].sample_int_reg; + hctrl_dp0_reg = acp63_sdw1_dp_reg[params->port_num].hctrl_dp0_reg; + offset_reg = acp63_sdw1_dp_reg[params->port_num].offset_reg; + lane_ctrl_ch_en_reg = + acp63_sdw1_dp_reg[params->port_num].lane_ctrl_ch_en_reg; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -520,12 +534,20 @@ static int amd_sdw_port_enable(struct sdw_bus *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; + switch (amd_manager->acp_rev) { + case ACP63_PCI_REV_ID: + switch (amd_manager->instance) { + case ACP_SDW0: + lane_ctrl_ch_en_reg = + acp63_sdw0_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg; + break; + case ACP_SDW1: + lane_ctrl_ch_en_reg = + acp63_sdw1_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -910,6 +932,7 @@ static int amd_sdw_manager_probe(struct platform_device *pdev) 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->acp_rev = pdata->acp_rev; 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; @@ -926,15 +949,21 @@ static int amd_sdw_manager_probe(struct platform_device *pdev) * information. */ amd_manager->bus.controller_id = 0; - - 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; + dev_dbg(dev, "acp_rev:0x%x\n", amd_manager->acp_rev); + switch (amd_manager->acp_rev) { + case ACP63_PCI_REV_ID: + switch (amd_manager->instance) { + case ACP_SDW0: + amd_manager->num_dout_ports = AMD_ACP63_SDW0_MAX_TX_PORTS; + amd_manager->num_din_ports = AMD_ACP63_SDW0_MAX_RX_PORTS; + break; + case ACP_SDW1: + amd_manager->num_dout_ports = AMD_ACP63_SDW1_MAX_TX_PORTS; + amd_manager->num_din_ports = AMD_ACP63_SDW1_MAX_RX_PORTS; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -1192,7 +1221,7 @@ static const struct dev_pm_ops amd_pm = { static struct platform_driver amd_sdw_driver = { .probe = &amd_sdw_manager_probe, - .remove_new = &amd_sdw_manager_remove, + .remove = &amd_sdw_manager_remove, .driver = { .name = "amd_sdw_manager", .pm = &amd_pm, diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h index 707065468e05a0..cc2170e4521edd 100644 --- a/drivers/soundwire/amd_manager.h +++ b/drivers/soundwire/amd_manager.h @@ -155,12 +155,12 @@ #define AMD_SDW_IRQ_MASK_8TO11 0x000c7777 #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_ACP63_SDW0_MAX_TX_PORTS 3 +#define AMD_ACP63_SDW0_MAX_RX_PORTS 3 +#define AMD_ACP63_SDW1_MAX_TX_PORTS 1 +#define AMD_ACP63_SDW1_MAX_RX_PORTS 1 +#define AMD_ACP63_SDW0_MAX_DAI 6 +#define AMD_ACP63_SDW1_MAX_DAI 2 #define AMD_SDW_SLAVE_0_ATTACHED 5 #define AMD_SDW_SSP_COUNTER_VAL 3 @@ -222,7 +222,7 @@ struct sdw_manager_dp_reg { * in SoundWire DMA driver. */ -static struct sdw_manager_dp_reg sdw0_manager_dp_reg[AMD_SDW0_MAX_DAI] = { +static struct sdw_manager_dp_reg acp63_sdw0_dp_reg[AMD_ACP63_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, @@ -237,7 +237,7 @@ static struct sdw_manager_dp_reg sdw0_manager_dp_reg[AMD_SDW0_MAX_DAI] = { 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] = { +static struct sdw_manager_dp_reg acp63_sdw1_dp_reg[AMD_ACP63_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, diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 263ca32f0c5c39..d1dc62c34f1cf3 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -112,7 +112,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, /* Set higher order bits */ *bus->assigned = ~GENMASK(SDW_BROADCAST_DEV_NUM, SDW_ENUM_DEV_NUM); - /* Set enumuration device number and broadcast device number */ + /* Set enumeration device number and broadcast device number */ set_bit(SDW_ENUM_DEV_NUM, bus->assigned); set_bit(SDW_BROADCAST_DEV_NUM, bus->assigned); diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 05652e983539b4..f367670ea991b9 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1377,6 +1377,31 @@ static void cdns_init_clock_ctrl(struct sdw_cdns *cdns) cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, ssp_interval); } +/** + * sdw_cdns_soft_reset() - Cadence soft-reset + * @cdns: Cadence instance + */ +int sdw_cdns_soft_reset(struct sdw_cdns *cdns) +{ + int ret; + + cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_SOFT_RST, + CDNS_MCP_CONTROL_SOFT_RST); + + ret = cdns_config_update(cdns); + if (ret < 0) { + dev_err(cdns->dev, "%s: config update failed\n", __func__); + return ret; + } + + ret = cdns_set_wait(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_SOFT_RST, 0); + if (ret < 0) + dev_err(cdns->dev, "%s: Soft Reset timed out\n", __func__); + + return ret; +} +EXPORT_SYMBOL(sdw_cdns_soft_reset); + /** * sdw_cdns_init() - Cadence initialization * @cdns: Cadence instance @@ -1400,6 +1425,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns) cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT, CDNS_IP_MCP_CONTROL_CMD_ACCEPT); + /* disable wakeup */ + cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, + CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP, + 0); + /* Configure mcp config */ val = cdns_readl(cdns, CDNS_MCP_CONFIG); diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index e1d7969ba48ae8..c34fb050fe4f0e 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -168,6 +168,7 @@ int sdw_cdns_probe(struct sdw_cdns *cdns); irqreturn_t sdw_cdns_irq(int irq, void *dev_id); irqreturn_t sdw_cdns_thread(int irq, void *dev_id); +int sdw_cdns_soft_reset(struct sdw_cdns *cdns); int sdw_cdns_init(struct sdw_cdns *cdns); int sdw_cdns_pdi_init(struct sdw_cdns *cdns, struct sdw_cdns_stream_config config); diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 421da0f86fad68..9db78f3d761522 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1111,4 +1111,4 @@ const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = { .sync_go = intel_shim_sync_go, .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked, }; -EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL); +EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, "SOUNDWIRE_INTEL"); diff --git a/drivers/soundwire/intel_ace2x.c b/drivers/soundwire/intel_ace2x.c index 4f3dd70d6a1a78..e305c6258ca967 100644 --- a/drivers/soundwire/intel_ace2x.c +++ b/drivers/soundwire/intel_ace2x.c @@ -175,6 +175,9 @@ static int intel_link_power_up(struct sdw_intel *sdw) __func__, ret); goto out; } + + hdac_bus_eml_enable_interrupt_unlocked(sdw->link_res->hbus, true, + AZX_REG_ML_LEPTR_ID_SDW, true); } *shim_mask |= BIT(link_id); @@ -201,6 +204,10 @@ static int intel_link_power_down(struct sdw_intel *sdw) *shim_mask &= ~BIT(link_id); + if (!*shim_mask) + hdac_bus_eml_enable_interrupt_unlocked(sdw->link_res->hbus, true, + AZX_REG_ML_LEPTR_ID_SDW, false); + ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id); if (ret < 0) { dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n", @@ -747,6 +754,6 @@ const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = { .program_sdi = intel_program_sdi, }; -EXPORT_SYMBOL_NS(sdw_intel_lnl_hw_ops, SOUNDWIRE_INTEL); +EXPORT_SYMBOL_NS(sdw_intel_lnl_hw_ops, "SOUNDWIRE_INTEL"); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c index ae689d5d1ab9eb..599954d9275299 100644 --- a/drivers/soundwire/intel_auxdevice.c +++ b/drivers/soundwire/intel_auxdevice.c @@ -41,6 +41,10 @@ static int md_flags; module_param_named(sdw_md_flags, md_flags, int, 0444); MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)"); +static int mclk_divider; +module_param_named(sdw_mclk_divider, mclk_divider, int, 0444); +MODULE_PARM_DESC(sdw_mclk_divider, "SoundWire Intel mclk divider"); + struct wake_capable_part { const u16 mfg_id; const u16 part_id; @@ -142,8 +146,12 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) "intel-sdw-ip-clock", &prop->mclk_freq); - /* the values reported by BIOS are the 2x clock, not the bus clock */ - prop->mclk_freq /= 2; + if (mclk_divider) + /* use kernel parameter for BIOS or board work-arounds */ + prop->mclk_freq /= mclk_divider; + else + /* the values reported by BIOS are the 2x clock, not the bus clock */ + prop->mclk_freq /= 2; fwnode_property_read_u32(link, "intel-quirk-mask", diff --git a/drivers/soundwire/intel_bus_common.c b/drivers/soundwire/intel_bus_common.c index d3ff6c65b64c33..ad1f8ebdbfc9b1 100644 --- a/drivers/soundwire/intel_bus_common.c +++ b/drivers/soundwire/intel_bus_common.c @@ -16,6 +16,12 @@ int intel_start_bus(struct sdw_intel *sdw) struct sdw_bus *bus = &cdns->bus; int ret; + ret = sdw_cdns_soft_reset(cdns); + if (ret < 0) { + dev_err(dev, "%s: unable to soft-reset Cadence IP: %d\n", __func__, ret); + return ret; + } + /* * follow recommended programming flows to avoid timeouts when * gsync is enabled diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index a09134b97cd666..5f53666514a45a 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -149,7 +149,7 @@ irqreturn_t sdw_intel_thread(int irq, void *dev_id) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT); +EXPORT_SYMBOL_NS(sdw_intel_thread, "SOUNDWIRE_INTEL_INIT"); static struct sdw_intel_ctx *sdw_intel_probe_controller(struct sdw_intel_res *res) @@ -252,17 +252,16 @@ static struct sdw_intel_ctx num_slaves++; } - ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL); - if (!ctx->ids) + ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves), + GFP_KERNEL); + if (!ctx->peripherals) goto err; - - ctx->num_slaves = num_slaves; + ctx->peripherals->num_peripherals = num_slaves; i = 0; list_for_each_entry(link, &ctx->link_list, list) { bus = &link->cdns->bus; list_for_each_entry(slave, &bus->slaves, node) { - ctx->ids[i].id = slave->id; - ctx->ids[i].link_id = bus->link_id; + ctx->peripherals->array[i] = slave; i++; } } @@ -335,7 +334,7 @@ struct sdw_intel_ctx { return sdw_intel_probe_controller(res); } -EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT); +EXPORT_SYMBOL_NS(sdw_intel_probe, "SOUNDWIRE_INTEL_INIT"); /** * sdw_intel_startup() - SoundWire Intel startup @@ -348,7 +347,7 @@ int sdw_intel_startup(struct sdw_intel_ctx *ctx) { return sdw_intel_startup_controller(ctx); } -EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT); +EXPORT_SYMBOL_NS(sdw_intel_startup, "SOUNDWIRE_INTEL_INIT"); /** * sdw_intel_exit() - SoundWire Intel exit * @ctx: SoundWire context allocated in the probe @@ -371,11 +370,11 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx) } sdw_intel_cleanup(ctx); - kfree(ctx->ids); + kfree(ctx->peripherals); kfree(ctx->ldev); kfree(ctx); } -EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); +EXPORT_SYMBOL_NS(sdw_intel_exit, "SOUNDWIRE_INTEL_INIT"); void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx) { @@ -398,7 +397,7 @@ void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx) intel_link_process_wakeen_event(&ldev->auxdev); } } -EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT); +EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, "SOUNDWIRE_INTEL_INIT"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Intel Soundwire Init Library"); diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index e5d9df26d4dc95..9d59f486edbe0a 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -23,6 +23,26 @@ #include #include "bus.h" +static bool mipi_fwnode_property_read_bool(const struct fwnode_handle *fwnode, + const char *propname) +{ + int ret; + u8 val; + + if (!fwnode_property_present(fwnode, propname)) + return false; + ret = fwnode_property_read_u8_array(fwnode, propname, &val, 1); + if (ret < 0) + return false; + return !!val; +} + +static bool mipi_device_property_read_bool(const struct device *dev, + const char *propname) +{ + return mipi_fwnode_property_read_bool(dev_fwnode(dev), propname); +} + /** * sdw_master_read_prop() - Read Master properties * @bus: SDW bus instance @@ -31,8 +51,11 @@ int sdw_master_read_prop(struct sdw_bus *bus) { struct sdw_master_prop *prop = &bus->prop; struct fwnode_handle *link; + const char *scales_prop; char name[32]; - int nval, i; + int nval; + int ret; + int i; device_property_read_u32(bus->dev, "mipi-sdw-sw-interface-revision", @@ -48,11 +71,11 @@ int sdw_master_read_prop(struct sdw_bus *bus) return -EIO; } - if (fwnode_property_read_bool(link, + if (mipi_fwnode_property_read_bool(link, "mipi-sdw-clock-stop-mode0-supported")) prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0); - if (fwnode_property_read_bool(link, + if (mipi_fwnode_property_read_bool(link, "mipi-sdw-clock-stop-mode1-supported")) prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1); @@ -71,9 +94,11 @@ int sdw_master_read_prop(struct sdw_bus *bus) return -ENOMEM; } - fwnode_property_read_u32_array(link, + ret = fwnode_property_read_u32_array(link, "mipi-sdw-clock-frequencies-supported", prop->clk_freq, prop->num_clk_freq); + if (ret < 0) + return ret; } /* @@ -88,7 +113,12 @@ int sdw_master_read_prop(struct sdw_bus *bus) } } - nval = fwnode_property_count_u32(link, "mipi-sdw-supported-clock-gears"); + scales_prop = "mipi-sdw-supported-clock-scales"; + nval = fwnode_property_count_u32(link, scales_prop); + if (nval == 0) { + scales_prop = "mipi-sdw-supported-clock-gears"; + nval = fwnode_property_count_u32(link, scales_prop); + } if (nval > 0) { prop->num_clk_gears = nval; prop->clk_gears = devm_kcalloc(bus->dev, prop->num_clk_gears, @@ -99,10 +129,12 @@ int sdw_master_read_prop(struct sdw_bus *bus) return -ENOMEM; } - fwnode_property_read_u32_array(link, - "mipi-sdw-supported-clock-gears", + ret = fwnode_property_read_u32_array(link, + scales_prop, prop->clk_gears, prop->num_clk_gears); + if (ret < 0) + return ret; } fwnode_property_read_u32(link, "mipi-sdw-default-frame-rate", @@ -114,7 +146,7 @@ int sdw_master_read_prop(struct sdw_bus *bus) fwnode_property_read_u32(link, "mipi-sdw-default-frame-col-size", &prop->default_col); - prop->dynamic_frame = fwnode_property_read_bool(link, + prop->dynamic_frame = mipi_fwnode_property_read_bool(link, "mipi-sdw-dynamic-frame-shape"); fwnode_property_read_u32(link, "mipi-sdw-command-error-threshold", @@ -131,6 +163,7 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave, struct sdw_dp0_prop *dp0) { int nval; + int ret; fwnode_property_read_u32(port, "mipi-sdw-port-max-wordlength", &dp0->max_word); @@ -148,20 +181,38 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave, if (!dp0->words) return -ENOMEM; - fwnode_property_read_u32_array(port, + ret = fwnode_property_read_u32_array(port, "mipi-sdw-port-wordlength-configs", dp0->words, dp0->num_words); + if (ret < 0) + return ret; } - dp0->BRA_flow_controlled = fwnode_property_read_bool(port, + dp0->BRA_flow_controlled = mipi_fwnode_property_read_bool(port, "mipi-sdw-bra-flow-controlled"); - dp0->simple_ch_prep_sm = fwnode_property_read_bool(port, + dp0->simple_ch_prep_sm = mipi_fwnode_property_read_bool(port, "mipi-sdw-simplified-channel-prepare-sm"); - dp0->imp_def_interrupts = fwnode_property_read_bool(port, + dp0->imp_def_interrupts = mipi_fwnode_property_read_bool(port, "mipi-sdw-imp-def-dp0-interrupts-supported"); + nval = fwnode_property_count_u32(port, "mipi-sdw-lane-list"); + if (nval > 0) { + dp0->num_lanes = nval; + dp0->lane_list = devm_kcalloc(&slave->dev, + dp0->num_lanes, sizeof(*dp0->lane_list), + GFP_KERNEL); + if (!dp0->lane_list) + return -ENOMEM; + + ret = fwnode_property_read_u32_array(port, + "mipi-sdw-lane-list", + dp0->lane_list, dp0->num_lanes); + if (ret < 0) + return ret; + } + return 0; } @@ -171,9 +222,10 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, { struct fwnode_handle *node; u32 bit, i = 0; - int nval; unsigned long addr; char name[40]; + int nval; + int ret; addr = ports; /* valid ports are 1 to 14 so apply mask */ @@ -208,9 +260,11 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, return -ENOMEM; } - fwnode_property_read_u32_array(node, + ret = fwnode_property_read_u32_array(node, "mipi-sdw-port-wordlength-configs", dpn[i].words, dpn[i].num_words); + if (ret < 0) + return ret; } fwnode_property_read_u32(node, "mipi-sdw-data-port-type", @@ -220,7 +274,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, "mipi-sdw-max-grouping-supported", &dpn[i].max_grouping); - dpn[i].simple_ch_prep_sm = fwnode_property_read_bool(node, + dpn[i].simple_ch_prep_sm = mipi_fwnode_property_read_bool(node, "mipi-sdw-simplified-channelprepare-sm"); fwnode_property_read_u32(node, @@ -249,9 +303,11 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, return -ENOMEM; } - fwnode_property_read_u32_array(node, + ret = fwnode_property_read_u32_array(node, "mipi-sdw-channel-number-list", dpn[i].channels, dpn[i].num_channels); + if (ret < 0) + return ret; } nval = fwnode_property_count_u32(node, "mipi-sdw-channel-combination-list"); @@ -266,10 +322,12 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, return -ENOMEM; } - fwnode_property_read_u32_array(node, + ret = fwnode_property_read_u32_array(node, "mipi-sdw-channel-combination-list", dpn[i].ch_combinations, dpn[i].num_ch_combinations); + if (ret < 0) + return ret; } fwnode_property_read_u32(node, @@ -278,13 +336,27 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, fwnode_property_read_u32(node, "mipi-sdw-max-async-buffer", &dpn[i].max_async_buffer); - dpn[i].block_pack_mode = fwnode_property_read_bool(node, + dpn[i].block_pack_mode = mipi_fwnode_property_read_bool(node, "mipi-sdw-block-packing-mode"); fwnode_property_read_u32(node, "mipi-sdw-port-encoding-type", &dpn[i].port_encoding); - /* TODO: Read audio mode */ + nval = fwnode_property_count_u32(node, "mipi-sdw-lane-list"); + if (nval > 0) { + dpn[i].num_lanes = nval; + dpn[i].lane_list = devm_kcalloc(&slave->dev, + dpn[i].num_lanes, sizeof(*dpn[i].lane_list), + GFP_KERNEL); + if (!dpn[i].lane_list) + return -ENOMEM; + + ret = fwnode_property_read_u32_array(node, + "mipi-sdw-lane-list", + dpn[i].lane_list, dpn[i].num_lanes); + if (ret < 0) + return ret; + } fwnode_handle_put(node); @@ -304,42 +376,46 @@ int sdw_slave_read_prop(struct sdw_slave *slave) struct device *dev = &slave->dev; struct fwnode_handle *port; int nval; + int ret; device_property_read_u32(dev, "mipi-sdw-sw-interface-revision", &prop->mipi_revision); - prop->wake_capable = device_property_read_bool(dev, + prop->wake_capable = mipi_device_property_read_bool(dev, "mipi-sdw-wake-up-unavailable"); prop->wake_capable = !prop->wake_capable; - prop->test_mode_capable = device_property_read_bool(dev, + prop->test_mode_capable = mipi_device_property_read_bool(dev, "mipi-sdw-test-mode-supported"); prop->clk_stop_mode1 = false; - if (device_property_read_bool(dev, + if (mipi_device_property_read_bool(dev, "mipi-sdw-clock-stop-mode1-supported")) prop->clk_stop_mode1 = true; - prop->simple_clk_stop_capable = device_property_read_bool(dev, + prop->simple_clk_stop_capable = mipi_device_property_read_bool(dev, "mipi-sdw-simplified-clockstopprepare-sm-supported"); device_property_read_u32(dev, "mipi-sdw-clockstopprepare-timeout", &prop->clk_stop_timeout); - device_property_read_u32(dev, "mipi-sdw-slave-channelprepare-timeout", - &prop->ch_prep_timeout); + ret = device_property_read_u32(dev, "mipi-sdw-peripheral-channelprepare-timeout", + &prop->ch_prep_timeout); + if (ret < 0) + device_property_read_u32(dev, "mipi-sdw-slave-channelprepare-timeout", + &prop->ch_prep_timeout); device_property_read_u32(dev, "mipi-sdw-clockstopprepare-hard-reset-behavior", &prop->reset_behave); - prop->high_PHY_capable = device_property_read_bool(dev, + prop->high_PHY_capable = mipi_device_property_read_bool(dev, "mipi-sdw-highPHY-capable"); - prop->paging_support = device_property_read_bool(dev, + prop->paging_support = mipi_device_property_read_bool(dev, "mipi-sdw-paging-support"); - prop->bank_delay_support = device_property_read_bool(dev, + prop->bank_delay_support = mipi_device_property_read_bool(dev, "mipi-sdw-bank-delay-support"); device_property_read_u32(dev, @@ -354,7 +430,17 @@ int sdw_slave_read_prop(struct sdw_slave *slave) device_property_read_u32(dev, "mipi-sdw-sink-port-list", &prop->sink_ports); - /* Read dp0 properties */ + device_property_read_u32(dev, "mipi-sdw-sdca-interrupt-register-list", + &prop->sdca_interrupt_register_list); + + prop->commit_register_supported = mipi_device_property_read_bool(dev, + "mipi-sdw-commit-register-supported"); + + /* + * Read dp0 properties - we don't rely on the 'mipi-sdw-dp-0-supported' + * property since the 'mipi-sdw-dp0-subproperties' property is logically + * equivalent. + */ port = device_get_named_child_node(dev, "mipi-sdw-dp-0-subproperties"); if (!port) { dev_dbg(dev, "DP0 node not found!!\n"); diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index aed57002fd0e63..e00c5ac496a685 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -1173,7 +1173,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, else sconfig.direction = SDW_DATA_DIR_RX; - /* hw parameters wil be ignored as we only support PDM */ + /* hw parameters will be ignored as we only support PDM */ sconfig.ch_count = 1; sconfig.frame_rate = params_rate(params); sconfig.type = stream->type; @@ -1779,7 +1779,7 @@ MODULE_DEVICE_TABLE(of, qcom_swrm_of_match); static struct platform_driver qcom_swrm_driver = { .probe = &qcom_swrm_probe, - .remove_new = qcom_swrm_remove, + .remove = qcom_swrm_remove, .driver = { .name = "qcom-soundwire", .of_match_table = qcom_swrm_of_match, diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index f1a4df6cfebd9c..4869b073b11c2f 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "bus.h" #include "sysfs_local.h" @@ -70,6 +71,17 @@ int sdw_slave_add(struct sdw_bus *bus, list_add_tail(&slave->node, &bus->slaves); mutex_unlock(&bus->bus_lock); + /* + * The Soundwire driver probe may optionally register SDCA + * sub-devices, one per Function. This means the information + * on the SDCA revision and the number/type of Functions need + * to be extracted from platform firmware before the SoundWire + * driver probe, and as a consequence before the SoundWire + * device_register() below. + */ + sdca_lookup_interface_revision(slave); + sdca_lookup_functions(slave); + ret = device_register(&slave->dev); if (ret) { dev_err(bus->dev, "Failed to add slave: ret %d\n", ret); @@ -259,3 +271,5 @@ int sdw_of_find_slaves(struct sdw_bus *bus) return 0; } + +MODULE_IMPORT_NS("SND_SOC_SDCA"); diff --git a/drivers/soundwire/sysfs_slave.c b/drivers/soundwire/sysfs_slave.c index f4259710dd0f72..c5c22d1708ec52 100644 --- a/drivers/soundwire/sysfs_slave.c +++ b/drivers/soundwire/sysfs_slave.c @@ -215,7 +215,7 @@ const struct attribute_group *sdw_attr_groups[] = { /* * the status is shown in capital letters for UNATTACHED and RESERVED - * on purpose, to highligh users to the fact that these status values + * on purpose, to highlight users to the fact that these status values * are not expected. */ static const char *const slave_status[] = { diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 82379721740480..f51f9466e518ae 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -96,6 +96,17 @@ config SPI_AMLOGIC_SPIFC_A1 This enables master mode support for the SPIFC (SPI flash controller) available in Amlogic A1 (A113L SoC). +config SPI_APPLE + tristate "Apple SoC SPI Controller platform driver" + depends on ARCH_APPLE || COMPILE_TEST + help + This enables support for the SPI controller present on + many Apple SoCs, including the t8103 (M1), t8112 (M2) + and t600x (M1 Pro/Max/Ultra). Multiple SPI controller + instances are present on the SoC and each connects usually + to a single device like spi-nor (nvram), input device controller + or fingerprint sensor. + config SPI_AR934X tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver" depends on ATH79 || COMPILE_TEST @@ -843,6 +854,17 @@ config SPI_PXA2XX config SPI_PXA2XX_PCI def_tristate SPI_PXA2XX && PCI && COMMON_CLK +config SPI_REALTEK_SNAND + tristate "Realtek SPI-NAND Flash Controller" + depends on MACH_REALTEK_RTL || COMPILE_TEST + select REGMAP + help + This enables support for the SPI-NAND Flash controller on + Realtek SoCs. + + This driver does not support generic SPI. The implementation + only supports the spi-mem interface. + config SPI_ROCKCHIP tristate "Rockchip SPI controller driver" depends on ARCH_ROCKCHIP || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index a9b1bc259b68d1..aea5e54de195b6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o obj-$(CONFIG_SPI_AMLOGIC_SPIFC_A1) += spi-amlogic-spifc-a1.o +obj-$(CONFIG_SPI_APPLE) += spi-apple.o obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o obj-$(CONFIG_SPI_ASPEED_SMC) += spi-aspeed-smc.o @@ -119,6 +120,7 @@ obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o +obj-$(CONFIG_SPI_REALTEK_SNAND) += spi-realtek-rtl-snand.o obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 95cdfc28361ef7..316bce577081f1 100644 --- a/drivers/spi/atmel-quadspi.c +++ b/drivers/spi/atmel-quadspi.c @@ -183,7 +183,7 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz) case QSPI_MR: return "MR"; case QSPI_RD: - return "MR"; + return "RD"; case QSPI_TD: return "TD"; case QSPI_SR: @@ -516,21 +516,45 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi) struct spi_controller *ctrl = spi->controller; struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); unsigned long clk_rate; + u32 cs_inactive; u32 cs_setup; + u32 cs_hold; int delay; int ret; - delay = spi_delay_to_ns(&spi->cs_setup, NULL); - if (delay <= 0) - return delay; - clk_rate = clk_get_rate(aq->pclk); if (!clk_rate) return -EINVAL; + /* hold */ + delay = spi_delay_to_ns(&spi->cs_hold, NULL); + if (aq->mr & QSPI_MR_SMM) { + if (delay > 0) + dev_warn(&aq->pdev->dev, + "Ignoring cs_hold, must be 0 in Serial Memory Mode.\n"); + cs_hold = 0; + } else { + delay = spi_delay_to_ns(&spi->cs_hold, NULL); + if (delay < 0) + return delay; + + cs_hold = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 32000); + } + + /* setup */ + delay = spi_delay_to_ns(&spi->cs_setup, NULL); + if (delay < 0) + return delay; + cs_setup = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 1000); + /* inactive */ + delay = spi_delay_to_ns(&spi->cs_inactive, NULL); + if (delay < 0) + return delay; + cs_inactive = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 1000); + ret = pm_runtime_resume_and_get(ctrl->dev.parent); if (ret < 0) return ret; @@ -539,6 +563,10 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi) aq->scr |= QSPI_SCR_DLYBS(cs_setup); atmel_qspi_write(aq->scr, aq, QSPI_SCR); + aq->mr &= ~(QSPI_MR_DLYBCT_MASK | QSPI_MR_DLYCS_MASK); + aq->mr |= QSPI_MR_DLYBCT(cs_hold) | QSPI_MR_DLYCS(cs_inactive); + atmel_qspi_write(aq->mr, aq, QSPI_MR); + pm_runtime_mark_last_busy(ctrl->dev.parent); pm_runtime_put_autosuspend(ctrl->dev.parent); @@ -840,7 +868,7 @@ static struct platform_driver atmel_qspi_driver = { .pm = pm_ptr(&atmel_qspi_pm_ops), }, .probe = atmel_qspi_probe, - .remove_new = atmel_qspi_remove, + .remove = atmel_qspi_remove, }; module_platform_driver(atmel_qspi_driver); diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c index 1369691a997bfc..dbe640986825eb 100644 --- a/drivers/spi/spi-airoha-snfi.c +++ b/drivers/spi/spi-airoha-snfi.c @@ -206,13 +206,6 @@ enum airoha_snand_cs { SPI_CHIP_SEL_LOW, }; -struct airoha_snand_dev { - size_t buf_len; - - u8 *txrx_buf; - dma_addr_t dma_addr; -}; - struct airoha_snand_ctrl { struct device *dev; struct regmap *regmap_ctrl; @@ -617,9 +610,9 @@ static bool airoha_snand_supports_op(struct spi_mem *mem, static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) { - struct airoha_snand_dev *as_dev = spi_get_ctldata(desc->mem->spi); + u8 *txrx_buf = spi_get_ctldata(desc->mem->spi); - if (!as_dev->txrx_buf) + if (!txrx_buf) return -EINVAL; if (desc->info.offset + desc->info.length > U32_MAX) @@ -634,10 +627,11 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { - struct spi_device *spi = desc->mem->spi; - struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_device *spi = desc->mem->spi; struct airoha_snand_ctrl *as_ctrl; + u8 *txrx_buf = spi_get_ctldata(spi); + dma_addr_t dma_addr; u32 val, rd_mode; int err; @@ -662,14 +656,17 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, if (err) return err; - dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); + dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_FROM_DEVICE); + err = dma_mapping_error(as_ctrl->dev, dma_addr); + if (err) + return err; /* set dma addr */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, - as_dev->dma_addr); + dma_addr); if (err) - return err; + goto error_dma_unmap; /* set cust sec size */ val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; @@ -678,58 +675,58 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, REG_SPI_NFI_SNF_MISC_CTL2, SPI_NFI_READ_DATA_BYTE_NUM, val); if (err) - return err; + goto error_dma_unmap; /* set read command */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2, op->cmd.opcode); if (err) - return err; + goto error_dma_unmap; /* set read mode */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode)); if (err) - return err; + goto error_dma_unmap; /* set read addr */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0); if (err) - return err; + goto error_dma_unmap; /* set nfi read */ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_OPMODE, FIELD_PREP(SPI_NFI_OPMODE, 6)); if (err) - return err; + goto error_dma_unmap; err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x0); if (err) - return err; + goto error_dma_unmap; /* trigger dma start read */ err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_RD_TRIG); if (err) - return err; + goto error_dma_unmap; err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_RD_TRIG); if (err) - return err; + goto error_dma_unmap; err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, val, (val & SPI_NFI_READ_FROM_CACHE_DONE), 0, 1 * USEC_PER_SEC); if (err) - return err; + goto error_dma_unmap; /* * SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end @@ -739,35 +736,41 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, SPI_NFI_READ_FROM_CACHE_DONE, SPI_NFI_READ_FROM_CACHE_DONE); if (err) - return err; + goto error_dma_unmap; err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR, val, (val & SPI_NFI_AHB_DONE), 0, 1 * USEC_PER_SEC); if (err) - return err; + goto error_dma_unmap; /* DMA read need delay for data ready from controller to DRAM */ udelay(1); - dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_FROM_DEVICE); err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); if (err < 0) return err; - memcpy(buf, as_dev->txrx_buf + offs, len); + memcpy(buf, txrx_buf + offs, len); return len; + +error_dma_unmap: + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_FROM_DEVICE); + return err; } static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, const void *buf) { - struct spi_device *spi = desc->mem->spi; - struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); struct spi_mem_op *op = &desc->info.op_tmpl; + struct spi_device *spi = desc->mem->spi; + u8 *txrx_buf = spi_get_ctldata(spi); struct airoha_snand_ctrl *as_ctrl; + dma_addr_t dma_addr; u32 wr_mode, val; int err; @@ -776,19 +779,20 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, if (err < 0) return err; - dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); - memcpy(as_dev->txrx_buf + offs, buf, len); - dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); + memcpy(txrx_buf + offs, buf, len); + dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); + err = dma_mapping_error(as_ctrl->dev, dma_addr); + if (err) + return err; err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); if (err < 0) - return err; + goto error_dma_unmap; err = airoha_snand_nfi_config(as_ctrl); if (err) - return err; + goto error_dma_unmap; if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD || op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD) @@ -797,9 +801,9 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, wr_mode = 0; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, - as_dev->dma_addr); + dma_addr); if (err) - return err; + goto error_dma_unmap; val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); @@ -807,65 +811,65 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, REG_SPI_NFI_SNF_MISC_CTL2, SPI_NFI_PROG_LOAD_BYTE_NUM, val); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1, FIELD_PREP(SPI_NFI_PG_LOAD_CMD, op->cmd.opcode)); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode)); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0); if (err) - return err; + goto error_dma_unmap; err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_READ_MODE); if (err) - return err; + goto error_dma_unmap; err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_OPMODE, FIELD_PREP(SPI_NFI_OPMODE, 3)); if (err) - return err; + goto error_dma_unmap; err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, SPI_NFI_DMA_MODE); if (err) - return err; + goto error_dma_unmap; err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80); if (err) - return err; + goto error_dma_unmap; err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_WR_TRIG); if (err) - return err; + goto error_dma_unmap; err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_WR_TRIG); if (err) - return err; + goto error_dma_unmap; err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR, val, (val & SPI_NFI_AHB_DONE), 0, 1 * USEC_PER_SEC); if (err) - return err; + goto error_dma_unmap; err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, val, (val & SPI_NFI_LOAD_TO_CACHE_DONE), 0, 1 * USEC_PER_SEC); if (err) - return err; + goto error_dma_unmap; /* * SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end @@ -875,13 +879,20 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, SPI_NFI_LOAD_TO_CACHE_DONE, SPI_NFI_LOAD_TO_CACHE_DONE); if (err) - return err; + goto error_dma_unmap; + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); if (err < 0) return err; return len; + +error_dma_unmap: + dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); + return err; } static int airoha_snand_exec_op(struct spi_mem *mem, @@ -956,42 +967,20 @@ static const struct spi_controller_mem_ops airoha_snand_mem_ops = { static int airoha_snand_setup(struct spi_device *spi) { struct airoha_snand_ctrl *as_ctrl; - struct airoha_snand_dev *as_dev; - - as_ctrl = spi_controller_get_devdata(spi->controller); - - as_dev = devm_kzalloc(as_ctrl->dev, sizeof(*as_dev), GFP_KERNEL); - if (!as_dev) - return -ENOMEM; + u8 *txrx_buf; /* prepare device buffer */ - as_dev->buf_len = SPI_NAND_CACHE_SIZE; - as_dev->txrx_buf = devm_kzalloc(as_ctrl->dev, as_dev->buf_len, - GFP_KERNEL); - if (!as_dev->txrx_buf) - return -ENOMEM; - - as_dev->dma_addr = dma_map_single(as_ctrl->dev, as_dev->txrx_buf, - as_dev->buf_len, DMA_BIDIRECTIONAL); - if (dma_mapping_error(as_ctrl->dev, as_dev->dma_addr)) + as_ctrl = spi_controller_get_devdata(spi->controller); + txrx_buf = devm_kzalloc(as_ctrl->dev, SPI_NAND_CACHE_SIZE, + GFP_KERNEL); + if (!txrx_buf) return -ENOMEM; - spi_set_ctldata(spi, as_dev); + spi_set_ctldata(spi, txrx_buf); return 0; } -static void airoha_snand_cleanup(struct spi_device *spi) -{ - struct airoha_snand_dev *as_dev = spi_get_ctldata(spi); - struct airoha_snand_ctrl *as_ctrl; - - as_ctrl = spi_controller_get_devdata(spi->controller); - dma_unmap_single(as_ctrl->dev, as_dev->dma_addr, - as_dev->buf_len, DMA_BIDIRECTIONAL); - spi_set_ctldata(spi, NULL); -} - static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl) { u32 val, sec_size, sec_num; @@ -1093,7 +1082,6 @@ static int airoha_snand_probe(struct platform_device *pdev) ctrl->bits_per_word_mask = SPI_BPW_MASK(8); ctrl->mode_bits = SPI_RX_DUAL; ctrl->setup = airoha_snand_setup; - ctrl->cleanup = airoha_snand_cleanup; device_set_node(&ctrl->dev, dev_fwnode(dev)); err = airoha_snand_nfi_setup(as_ctrl); diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c index 2245ad54b03aa3..d30a21b0b05f96 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -7,12 +7,14 @@ // Author: Sanjay R Mehta #include +#include +#include #include +#include +#include #include #include -#include #include -#include #include #define AMD_SPI_CTRL0_REG 0x00 @@ -33,10 +35,12 @@ #define AMD_SPI_TX_COUNT_REG 0x48 #define AMD_SPI_RX_COUNT_REG 0x4B #define AMD_SPI_STATUS_REG 0x4C +#define AMD_SPI_ADDR32CTRL_REG 0x50 #define AMD_SPI_FIFO_SIZE 70 #define AMD_SPI_MEM_SIZE 200 #define AMD_SPI_MAX_DATA 64 +#define AMD_SPI_HID2_DMA_SIZE 4096 #define AMD_SPI_ENA_REG 0x20 #define AMD_SPI_ALT_SPD_SHIFT 20 @@ -47,17 +51,46 @@ #define AMD_SPI_SPD7_SHIFT 8 #define AMD_SPI_SPD7_MASK GENMASK(13, AMD_SPI_SPD7_SHIFT) +#define AMD_SPI_HID2_INPUT_RING_BUF0 0X100 +#define AMD_SPI_HID2_CNTRL 0x150 +#define AMD_SPI_HID2_INT_STATUS 0x154 +#define AMD_SPI_HID2_CMD_START 0x156 +#define AMD_SPI_HID2_INT_MASK 0x158 +#define AMD_SPI_HID2_READ_CNTRL0 0x170 +#define AMD_SPI_HID2_READ_CNTRL1 0x174 +#define AMD_SPI_HID2_READ_CNTRL2 0x180 + #define AMD_SPI_MAX_HZ 100000000 #define AMD_SPI_MIN_HZ 800000 +#define AMD_SPI_IO_SLEEP_US 20 +#define AMD_SPI_IO_TIMEOUT_US 2000000 + +/* SPI read command opcodes */ +#define AMD_SPI_OP_READ 0x03 /* Read data bytes (low frequency) */ +#define AMD_SPI_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */ +#define AMD_SPI_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */ +#define AMD_SPI_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */ +#define AMD_SPI_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */ +#define AMD_SPI_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */ + +/* SPI read command opcodes - 4B address */ +#define AMD_SPI_OP_READ_FAST_4B 0x0c /* Read data bytes (high frequency) */ +#define AMD_SPI_OP_READ_1_1_2_4B 0x3c /* Read data bytes (Dual Output SPI) */ +#define AMD_SPI_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */ +#define AMD_SPI_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */ +#define AMD_SPI_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */ + /** * enum amd_spi_versions - SPI controller versions * @AMD_SPI_V1: AMDI0061 hardware version * @AMD_SPI_V2: AMDI0062 hardware version + * @AMD_HID2_SPI: AMDI0063 hardware version */ enum amd_spi_versions { AMD_SPI_V1 = 1, AMD_SPI_V2, + AMD_HID2_SPI, }; enum amd_spi_speed { @@ -88,23 +121,27 @@ struct amd_spi_freq { /** * struct amd_spi - SPI driver instance * @io_remap_addr: Start address of the SPI controller registers + * @phy_dma_buf: Physical address of DMA buffer + * @dma_virt_addr: Virtual address of DMA buffer * @version: SPI controller hardware version * @speed_hz: Device frequency */ struct amd_spi { void __iomem *io_remap_addr; + dma_addr_t phy_dma_buf; + void *dma_virt_addr; enum amd_spi_versions version; unsigned int speed_hz; }; static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx) { - return ioread8((u8 __iomem *)amd_spi->io_remap_addr + idx); + return readb((u8 __iomem *)amd_spi->io_remap_addr + idx); } static inline void amd_spi_writereg8(struct amd_spi *amd_spi, int idx, u8 val) { - iowrite8(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); + writeb(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); } static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 clear) @@ -115,14 +152,34 @@ static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 c amd_spi_writereg8(amd_spi, idx, tmp); } +static inline u16 amd_spi_readreg16(struct amd_spi *amd_spi, int idx) +{ + return readw((u8 __iomem *)amd_spi->io_remap_addr + idx); +} + +static inline void amd_spi_writereg16(struct amd_spi *amd_spi, int idx, u16 val) +{ + writew(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); +} + static inline u32 amd_spi_readreg32(struct amd_spi *amd_spi, int idx) { - return ioread32((u8 __iomem *)amd_spi->io_remap_addr + idx); + return readl((u8 __iomem *)amd_spi->io_remap_addr + idx); } static inline void amd_spi_writereg32(struct amd_spi *amd_spi, int idx, u32 val) { - iowrite32(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); + writel(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); +} + +static inline u64 amd_spi_readreg64(struct amd_spi *amd_spi, int idx) +{ + return readq((u8 __iomem *)amd_spi->io_remap_addr + idx); +} + +static inline void amd_spi_writereg64(struct amd_spi *amd_spi, int idx, u64 val) +{ + writeq(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx)); } static inline void amd_spi_setclear_reg32(struct amd_spi *amd_spi, int idx, u32 set, u32 clear) @@ -156,6 +213,7 @@ static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode) AMD_SPI_OPCODE_MASK); return 0; case AMD_SPI_V2: + case AMD_HID2_SPI: amd_spi_writereg8(amd_spi, AMD_SPI_OPCODE_REG, cmd_opcode); return 0; default: @@ -165,12 +223,12 @@ static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode) static inline void amd_spi_set_rx_count(struct amd_spi *amd_spi, u8 rx_count) { - amd_spi_setclear_reg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count, 0xff); + amd_spi_writereg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count); } static inline void amd_spi_set_tx_count(struct amd_spi *amd_spi, u8 tx_count) { - amd_spi_setclear_reg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count, 0xff); + amd_spi_writereg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count); } static int amd_spi_busy_wait(struct amd_spi *amd_spi) @@ -183,6 +241,7 @@ static int amd_spi_busy_wait(struct amd_spi *amd_spi) reg = AMD_SPI_CTRL0_REG; break; case AMD_SPI_V2: + case AMD_HID2_SPI: reg = AMD_SPI_STATUS_REG; break; default: @@ -208,6 +267,7 @@ static int amd_spi_execute_opcode(struct amd_spi *amd_spi) AMD_SPI_EXEC_CMD); return 0; case AMD_SPI_V2: + case AMD_HID2_SPI: /* Trigger the command execution */ amd_spi_setclear_reg8(amd_spi, AMD_SPI_CMD_TRIGGER_REG, AMD_SPI_TRIGGER_CMD, AMD_SPI_TRIGGER_CMD); @@ -349,6 +409,7 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, case AMD_SPI_V1: break; case AMD_SPI_V2: + case AMD_HID2_SPI: amd_spi_clear_chip(amd_spi, spi_get_chipselect(message->spi, 0)); break; default: @@ -360,20 +421,82 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi, return message->status; } +static inline bool amd_is_spi_read_cmd_4b(const u16 op) +{ + switch (op) { + case AMD_SPI_OP_READ_FAST_4B: + case AMD_SPI_OP_READ_1_1_2_4B: + case AMD_SPI_OP_READ_1_2_2_4B: + case AMD_SPI_OP_READ_1_1_4_4B: + case AMD_SPI_OP_READ_1_4_4_4B: + return true; + default: + return false; + } +} + +static inline bool amd_is_spi_read_cmd(const u16 op) +{ + switch (op) { + case AMD_SPI_OP_READ: + case AMD_SPI_OP_READ_FAST: + case AMD_SPI_OP_READ_1_1_2: + case AMD_SPI_OP_READ_1_2_2: + case AMD_SPI_OP_READ_1_1_4: + case AMD_SPI_OP_READ_1_4_4: + return true; + default: + return amd_is_spi_read_cmd_4b(op); + } +} + static bool amd_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { + struct amd_spi *amd_spi = spi_controller_get_devdata(mem->spi->controller); + /* bus width is number of IO lines used to transmit */ - if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 || - op->data.buswidth > 1 || op->data.nbytes > AMD_SPI_MAX_DATA) + if (op->cmd.buswidth > 1 || op->addr.buswidth > 4) return false; + /* AMD SPI controllers support quad mode only for read operations */ + if (amd_is_spi_read_cmd(op->cmd.opcode)) { + if (op->data.buswidth > 4) + return false; + + /* + * HID2 SPI controller supports DMA read up to 4K bytes and + * doesn't support 4-byte address commands. + */ + if (amd_spi->version == AMD_HID2_SPI) { + if (amd_is_spi_read_cmd_4b(op->cmd.opcode) || + op->data.nbytes > AMD_SPI_HID2_DMA_SIZE) + return false; + } else if (op->data.nbytes > AMD_SPI_MAX_DATA) { + return false; + } + } else if (op->data.buswidth > 1 || op->data.nbytes > AMD_SPI_MAX_DATA) { + return false; + } + return spi_mem_default_supports_op(mem, op); } static int amd_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) { - op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA); + struct amd_spi *amd_spi = spi_controller_get_devdata(mem->spi->controller); + + /* + * HID2 SPI controller DMA read mode supports reading up to 4k + * bytes in single transaction, where as SPI0 and HID2 SPI + * controller index mode supports maximum of 64 bytes in a single + * transaction. + */ + if (amd_spi->version == AMD_HID2_SPI && amd_is_spi_read_cmd(op->cmd.opcode)) + op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_HID2_DMA_SIZE); + else + op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA); + return 0; } @@ -397,15 +520,23 @@ static void amd_spi_mem_data_out(struct amd_spi *amd_spi, const struct spi_mem_op *op) { int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes; - u8 *buf = (u8 *)op->data.buf.out; + u64 *buf_64 = (u64 *)op->data.buf.out; u32 nbytes = op->data.nbytes; + u32 left_data = nbytes; + u8 *buf; int i; amd_spi_set_opcode(amd_spi, op->cmd.opcode); amd_spi_set_addr(amd_spi, op); - for (i = 0; i < nbytes; i++) - amd_spi_writereg8(amd_spi, (base_addr + i), buf[i]); + for (i = 0; left_data >= 8; i++, left_data -= 8) + amd_spi_writereg64(amd_spi, base_addr + op->dummy.nbytes + (i * 8), *buf_64++); + + buf = (u8 *)buf_64; + for (i = 0; i < left_data; i++) { + amd_spi_writereg8(amd_spi, base_addr + op->dummy.nbytes + nbytes + i - left_data, + buf[i]); + } amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->data.nbytes); amd_spi_set_rx_count(amd_spi, 0); @@ -413,26 +544,128 @@ static void amd_spi_mem_data_out(struct amd_spi *amd_spi, amd_spi_execute_opcode(amd_spi); } +static void amd_spi_hiddma_read(struct amd_spi *amd_spi, const struct spi_mem_op *op) +{ + u16 hid_cmd_start, val; + u32 hid_regval; + + /* Set the opcode in hid2_read_control0 register */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL0); + hid_regval = (hid_regval & ~GENMASK(7, 0)) | op->cmd.opcode; + + /* + * Program the address in the hid2_read_control0 register [8:31]. The address should + * be written starting from the 8th bit of the register, requiring an 8-bit shift. + * Additionally, to convert a 2-byte spinand address to a 3-byte address, another + * 8-bit shift is needed. Therefore, a total shift of 16 bits is required. + */ + hid_regval = (hid_regval & ~GENMASK(31, 8)) | (op->addr.val << 16); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL0, hid_regval); + + /* Configure dummy clock cycles for fast read, dual, quad I/O commands */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL2); + /* Fast read dummy cycle */ + hid_regval &= ~GENMASK(4, 0); + + /* Fast read Dual I/O dummy cycle */ + hid_regval &= ~GENMASK(12, 8); + + /* Fast read Quad I/O dummy cycle */ + hid_regval = (hid_regval & ~GENMASK(20, 16)) | BIT(17); + + /* Set no of preamble bytecount */ + hid_regval &= ~GENMASK(27, 24); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL2, hid_regval); + + /* + * Program the HID2 Input Ring Buffer0. 4k aligned buf_memory_addr[31:12], + * buf_size[4:0], end_input_ring[5]. + */ + hid_regval = amd_spi->phy_dma_buf | BIT(5) | BIT(0); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INPUT_RING_BUF0, hid_regval); + + /* Program max read length(no of DWs) in hid2_read_control1 register */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL1); + hid_regval = (hid_regval & ~GENMASK(15, 0)) | ((op->data.nbytes / 4) - 1); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL1, hid_regval); + + /* Set cmd start bit in hid2_cmd_start register to trigger HID basic read operation */ + hid_cmd_start = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_CMD_START); + amd_spi_writereg16(amd_spi, AMD_SPI_HID2_CMD_START, (hid_cmd_start | BIT(3))); + + /* Check interrupt status of HIDDMA basic read operation in hid2_int_status register */ + readw_poll_timeout(amd_spi->io_remap_addr + AMD_SPI_HID2_INT_STATUS, val, + (val & BIT(3)), AMD_SPI_IO_SLEEP_US, AMD_SPI_IO_TIMEOUT_US); + + /* Clear the interrupts by writing to hid2_int_status register */ + val = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_INT_STATUS); + amd_spi_writereg16(amd_spi, AMD_SPI_HID2_INT_STATUS, val); +} + static void amd_spi_mem_data_in(struct amd_spi *amd_spi, const struct spi_mem_op *op) { - int offset = (op->addr.nbytes == 0) ? 0 : 1; - u8 *buf = (u8 *)op->data.buf.in; + int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes; + u64 *buf_64 = (u64 *)op->data.buf.in; u32 nbytes = op->data.nbytes; - int base_addr, i; + u32 left_data = nbytes; + u32 data; + u8 *buf; + int i; - base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes + offset; + /* + * Condition for using HID read mode. Only for reading complete page data, use HID read. + * Use index mode otherwise. + */ + if (amd_spi->version == AMD_HID2_SPI && amd_is_spi_read_cmd(op->cmd.opcode)) { + amd_spi_hiddma_read(amd_spi, op); + + for (i = 0; left_data >= 8; i++, left_data -= 8) + *buf_64++ = readq((u8 __iomem *)amd_spi->dma_virt_addr + (i * 8)); + + buf = (u8 *)buf_64; + for (i = 0; i < left_data; i++) + buf[i] = readb((u8 __iomem *)amd_spi->dma_virt_addr + + (nbytes - left_data + i)); + + /* Reset HID RX memory logic */ + data = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_CNTRL); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_CNTRL, data | BIT(5)); + } else { + /* Index mode */ + amd_spi_set_opcode(amd_spi, op->cmd.opcode); + amd_spi_set_addr(amd_spi, op); + amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->dummy.nbytes); + + for (i = 0; i < op->dummy.nbytes; i++) + amd_spi_writereg8(amd_spi, (base_addr + i), 0xff); + + amd_spi_set_rx_count(amd_spi, op->data.nbytes); + amd_spi_clear_fifo_ptr(amd_spi); + amd_spi_execute_opcode(amd_spi); + amd_spi_busy_wait(amd_spi); + + for (i = 0; left_data >= 8; i++, left_data -= 8) + *buf_64++ = amd_spi_readreg64(amd_spi, base_addr + op->dummy.nbytes + + (i * 8)); + + buf = (u8 *)buf_64; + for (i = 0; i < left_data; i++) + buf[i] = amd_spi_readreg8(amd_spi, base_addr + op->dummy.nbytes + + nbytes + i - left_data); + } - amd_spi_set_opcode(amd_spi, op->cmd.opcode); - amd_spi_set_addr(amd_spi, op); - amd_spi_set_tx_count(amd_spi, op->addr.nbytes); - amd_spi_set_rx_count(amd_spi, op->data.nbytes + 1); - amd_spi_clear_fifo_ptr(amd_spi); - amd_spi_execute_opcode(amd_spi); - amd_spi_busy_wait(amd_spi); +} - for (i = 0; i < nbytes; i++) - buf[i] = amd_spi_readreg8(amd_spi, base_addr + i); +static void amd_set_spi_addr_mode(struct amd_spi *amd_spi, + const struct spi_mem_op *op) +{ + u32 val = amd_spi_readreg32(amd_spi, AMD_SPI_ADDR32CTRL_REG); + + if (amd_is_spi_read_cmd_4b(op->cmd.opcode)) + amd_spi_writereg32(amd_spi, AMD_SPI_ADDR32CTRL_REG, val | BIT(0)); + else + amd_spi_writereg32(amd_spi, AMD_SPI_ADDR32CTRL_REG, val & ~BIT(0)); } static int amd_spi_exec_mem_op(struct spi_mem *mem, @@ -447,6 +680,9 @@ static int amd_spi_exec_mem_op(struct spi_mem *mem, if (ret) return ret; + if (amd_spi->version == AMD_SPI_V2) + amd_set_spi_addr_mode(amd_spi, op); + switch (op->data.dir) { case SPI_MEM_DATA_IN: amd_spi_mem_data_in(amd_spi, op); @@ -489,6 +725,31 @@ static size_t amd_spi_max_transfer_size(struct spi_device *spi) return AMD_SPI_FIFO_SIZE; } +static int amd_spi_setup_hiddma(struct amd_spi *amd_spi, struct device *dev) +{ + u32 hid_regval; + + /* Allocate DMA buffer to use for HID basic read operation */ + amd_spi->dma_virt_addr = dma_alloc_coherent(dev, AMD_SPI_HID2_DMA_SIZE, + &amd_spi->phy_dma_buf, GFP_KERNEL); + if (!amd_spi->dma_virt_addr) + return -ENOMEM; + + /* + * Enable interrupts and set mask bits in hid2_int_mask register to generate interrupt + * properly for HIDDMA basic read operations. + */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_INT_MASK); + hid_regval = (hid_regval & GENMASK(31, 8)) | BIT(19); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INT_MASK, hid_regval); + + /* Configure buffer unit(4k) in hid2_control register */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_CNTRL); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_CNTRL, hid_regval & ~BIT(3)); + + return 0; +} + static int amd_spi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -512,9 +773,9 @@ static int amd_spi_probe(struct platform_device *pdev) amd_spi->version = (uintptr_t) device_get_match_data(dev); /* Initialize the spi_controller fields */ - host->bus_num = 0; + host->bus_num = (amd_spi->version == AMD_HID2_SPI) ? 2 : 0; host->num_chipselect = 4; - host->mode_bits = 0; + host->mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD; host->flags = SPI_CONTROLLER_HALF_DUPLEX; host->max_speed_hz = AMD_SPI_MAX_HZ; host->min_speed_hz = AMD_SPI_MIN_HZ; @@ -529,13 +790,17 @@ static int amd_spi_probe(struct platform_device *pdev) if (err) return dev_err_probe(dev, err, "error registering SPI controller\n"); - return 0; + if (amd_spi->version == AMD_HID2_SPI) + err = amd_spi_setup_hiddma(amd_spi, dev); + + return err; } #ifdef CONFIG_ACPI static const struct acpi_device_id spi_acpi_match[] = { { "AMDI0061", AMD_SPI_V1 }, { "AMDI0062", AMD_SPI_V2 }, + { "AMDI0063", AMD_HID2_SPI }, {}, }; MODULE_DEVICE_TABLE(acpi, spi_acpi_match); diff --git a/drivers/spi/spi-apple.c b/drivers/spi/spi-apple.c new file mode 100644 index 00000000000000..6273352a2b2861 --- /dev/null +++ b/drivers/spi/spi-apple.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Apple SoC SPI device driver +// +// Copyright The Asahi Linux Contributors +// +// Based on spi-sifive.c, Copyright 2018 SiFive, Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APPLE_SPI_CTRL 0x000 +#define APPLE_SPI_CTRL_RUN BIT(0) +#define APPLE_SPI_CTRL_TX_RESET BIT(2) +#define APPLE_SPI_CTRL_RX_RESET BIT(3) + +#define APPLE_SPI_CFG 0x004 +#define APPLE_SPI_CFG_CPHA BIT(1) +#define APPLE_SPI_CFG_CPOL BIT(2) +#define APPLE_SPI_CFG_MODE GENMASK(6, 5) +#define APPLE_SPI_CFG_MODE_POLLED 0 +#define APPLE_SPI_CFG_MODE_IRQ 1 +#define APPLE_SPI_CFG_MODE_DMA 2 +#define APPLE_SPI_CFG_IE_RXCOMPLETE BIT(7) +#define APPLE_SPI_CFG_IE_TXRXTHRESH BIT(8) +#define APPLE_SPI_CFG_LSB_FIRST BIT(13) +#define APPLE_SPI_CFG_WORD_SIZE GENMASK(16, 15) +#define APPLE_SPI_CFG_WORD_SIZE_8B 0 +#define APPLE_SPI_CFG_WORD_SIZE_16B 1 +#define APPLE_SPI_CFG_WORD_SIZE_32B 2 +#define APPLE_SPI_CFG_FIFO_THRESH GENMASK(18, 17) +#define APPLE_SPI_CFG_FIFO_THRESH_8B 0 +#define APPLE_SPI_CFG_FIFO_THRESH_4B 1 +#define APPLE_SPI_CFG_FIFO_THRESH_1B 2 +#define APPLE_SPI_CFG_IE_TXCOMPLETE BIT(21) + +#define APPLE_SPI_STATUS 0x008 +#define APPLE_SPI_STATUS_RXCOMPLETE BIT(0) +#define APPLE_SPI_STATUS_TXRXTHRESH BIT(1) +#define APPLE_SPI_STATUS_TXCOMPLETE BIT(2) + +#define APPLE_SPI_PIN 0x00c +#define APPLE_SPI_PIN_KEEP_MOSI BIT(0) +#define APPLE_SPI_PIN_CS BIT(1) + +#define APPLE_SPI_TXDATA 0x010 +#define APPLE_SPI_RXDATA 0x020 +#define APPLE_SPI_CLKDIV 0x030 +#define APPLE_SPI_CLKDIV_MAX 0x7ff +#define APPLE_SPI_RXCNT 0x034 +#define APPLE_SPI_WORD_DELAY 0x038 +#define APPLE_SPI_TXCNT 0x04c + +#define APPLE_SPI_FIFOSTAT 0x10c +#define APPLE_SPI_FIFOSTAT_TXFULL BIT(4) +#define APPLE_SPI_FIFOSTAT_LEVEL_TX GENMASK(15, 8) +#define APPLE_SPI_FIFOSTAT_RXEMPTY BIT(20) +#define APPLE_SPI_FIFOSTAT_LEVEL_RX GENMASK(31, 24) + +#define APPLE_SPI_IE_XFER 0x130 +#define APPLE_SPI_IF_XFER 0x134 +#define APPLE_SPI_XFER_RXCOMPLETE BIT(0) +#define APPLE_SPI_XFER_TXCOMPLETE BIT(1) + +#define APPLE_SPI_IE_FIFO 0x138 +#define APPLE_SPI_IF_FIFO 0x13c +#define APPLE_SPI_FIFO_RXTHRESH BIT(4) +#define APPLE_SPI_FIFO_TXTHRESH BIT(5) +#define APPLE_SPI_FIFO_RXFULL BIT(8) +#define APPLE_SPI_FIFO_TXEMPTY BIT(9) +#define APPLE_SPI_FIFO_RXUNDERRUN BIT(16) +#define APPLE_SPI_FIFO_TXOVERFLOW BIT(17) + +#define APPLE_SPI_SHIFTCFG 0x150 +#define APPLE_SPI_SHIFTCFG_CLK_ENABLE BIT(0) +#define APPLE_SPI_SHIFTCFG_CS_ENABLE BIT(1) +#define APPLE_SPI_SHIFTCFG_AND_CLK_DATA BIT(8) +#define APPLE_SPI_SHIFTCFG_CS_AS_DATA BIT(9) +#define APPLE_SPI_SHIFTCFG_TX_ENABLE BIT(10) +#define APPLE_SPI_SHIFTCFG_RX_ENABLE BIT(11) +#define APPLE_SPI_SHIFTCFG_BITS GENMASK(21, 16) +#define APPLE_SPI_SHIFTCFG_OVERRIDE_CS BIT(24) + +#define APPLE_SPI_PINCFG 0x154 +#define APPLE_SPI_PINCFG_KEEP_CLK BIT(0) +#define APPLE_SPI_PINCFG_KEEP_CS BIT(1) +#define APPLE_SPI_PINCFG_KEEP_MOSI BIT(2) +#define APPLE_SPI_PINCFG_CLK_IDLE_VAL BIT(8) +#define APPLE_SPI_PINCFG_CS_IDLE_VAL BIT(9) +#define APPLE_SPI_PINCFG_MOSI_IDLE_VAL BIT(10) + +#define APPLE_SPI_DELAY_PRE 0x160 +#define APPLE_SPI_DELAY_POST 0x168 +#define APPLE_SPI_DELAY_ENABLE BIT(0) +#define APPLE_SPI_DELAY_NO_INTERBYTE BIT(1) +#define APPLE_SPI_DELAY_SET_SCK BIT(4) +#define APPLE_SPI_DELAY_SET_MOSI BIT(6) +#define APPLE_SPI_DELAY_SCK_VAL BIT(8) +#define APPLE_SPI_DELAY_MOSI_VAL BIT(12) + +#define APPLE_SPI_FIFO_DEPTH 16 + +/* + * The slowest refclock available is 24MHz, the highest divider is 0x7ff, + * the largest word size is 32 bits, the FIFO depth is 16, the maximum + * intra-word delay is 0xffff refclocks. So the maximum time a transfer + * cycle can take is: + * + * (0x7ff * 32 + 0xffff) * 16 / 24e6 Hz ~= 87ms + * + * Double it and round it up to 200ms for good measure. + */ +#define APPLE_SPI_TIMEOUT_MS 200 + +struct apple_spi { + void __iomem *regs; /* MMIO register address */ + struct clk *clk; /* bus clock */ + struct completion done; /* wake-up from interrupt */ +}; + +static inline void reg_write(struct apple_spi *spi, int offset, u32 value) +{ + writel_relaxed(value, spi->regs + offset); +} + +static inline u32 reg_read(struct apple_spi *spi, int offset) +{ + return readl_relaxed(spi->regs + offset); +} + +static inline void reg_mask(struct apple_spi *spi, int offset, u32 clear, u32 set) +{ + u32 val = reg_read(spi, offset); + + val &= ~clear; + val |= set; + reg_write(spi, offset, val); +} + +static void apple_spi_init(struct apple_spi *spi) +{ + /* Set CS high (inactive) and disable override and auto-CS */ + reg_write(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS); + reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_OVERRIDE_CS, 0); + reg_mask(spi, APPLE_SPI_PINCFG, APPLE_SPI_PINCFG_CS_IDLE_VAL, APPLE_SPI_PINCFG_KEEP_CS); + + /* Reset FIFOs */ + reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET); + + /* Configure defaults */ + reg_write(spi, APPLE_SPI_CFG, + FIELD_PREP(APPLE_SPI_CFG_FIFO_THRESH, APPLE_SPI_CFG_FIFO_THRESH_8B) | + FIELD_PREP(APPLE_SPI_CFG_MODE, APPLE_SPI_CFG_MODE_IRQ) | + FIELD_PREP(APPLE_SPI_CFG_WORD_SIZE, APPLE_SPI_CFG_WORD_SIZE_8B)); + + /* Disable IRQs */ + reg_write(spi, APPLE_SPI_IE_FIFO, 0); + reg_write(spi, APPLE_SPI_IE_XFER, 0); + + /* Disable delays */ + reg_write(spi, APPLE_SPI_DELAY_PRE, 0); + reg_write(spi, APPLE_SPI_DELAY_POST, 0); +} + +static int apple_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *msg) +{ + struct apple_spi *spi = spi_controller_get_devdata(ctlr); + struct spi_device *device = msg->spi; + + u32 cfg = ((device->mode & SPI_CPHA ? APPLE_SPI_CFG_CPHA : 0) | + (device->mode & SPI_CPOL ? APPLE_SPI_CFG_CPOL : 0) | + (device->mode & SPI_LSB_FIRST ? APPLE_SPI_CFG_LSB_FIRST : 0)); + + /* Update core config */ + reg_mask(spi, APPLE_SPI_CFG, + APPLE_SPI_CFG_CPHA | APPLE_SPI_CFG_CPOL | APPLE_SPI_CFG_LSB_FIRST, cfg); + + return 0; +} + +static void apple_spi_set_cs(struct spi_device *device, bool is_high) +{ + struct apple_spi *spi = spi_controller_get_devdata(device->controller); + + reg_mask(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS, is_high ? APPLE_SPI_PIN_CS : 0); +} + +static bool apple_spi_prep_transfer(struct apple_spi *spi, struct spi_transfer *t) +{ + u32 cr, fifo_threshold; + + /* Calculate and program the clock rate */ + cr = DIV_ROUND_UP(clk_get_rate(spi->clk), t->speed_hz); + reg_write(spi, APPLE_SPI_CLKDIV, min_t(u32, cr, APPLE_SPI_CLKDIV_MAX)); + + /* Update bits per word */ + reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_BITS, + FIELD_PREP(APPLE_SPI_SHIFTCFG_BITS, t->bits_per_word)); + + /* We will want to poll if the time we need to wait is + * less than the context switching time. + * Let's call that threshold 5us. The operation will take: + * bits_per_word * fifo_threshold / hz <= 5 * 10^-6 + * 200000 * bits_per_word * fifo_threshold <= hz + */ + fifo_threshold = APPLE_SPI_FIFO_DEPTH / 2; + return (200000 * t->bits_per_word * fifo_threshold) <= t->speed_hz; +} + +static irqreturn_t apple_spi_irq(int irq, void *dev_id) +{ + struct apple_spi *spi = dev_id; + u32 fifo = reg_read(spi, APPLE_SPI_IF_FIFO) & reg_read(spi, APPLE_SPI_IE_FIFO); + u32 xfer = reg_read(spi, APPLE_SPI_IF_XFER) & reg_read(spi, APPLE_SPI_IE_XFER); + + if (fifo || xfer) { + /* Disable interrupts until next transfer */ + reg_write(spi, APPLE_SPI_IE_XFER, 0); + reg_write(spi, APPLE_SPI_IE_FIFO, 0); + complete(&spi->done); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int apple_spi_wait(struct apple_spi *spi, u32 fifo_bit, u32 xfer_bit, int poll) +{ + int ret = 0; + + if (poll) { + u32 fifo, xfer; + unsigned long timeout = jiffies + APPLE_SPI_TIMEOUT_MS * HZ / 1000; + + do { + fifo = reg_read(spi, APPLE_SPI_IF_FIFO); + xfer = reg_read(spi, APPLE_SPI_IF_XFER); + if (time_after(jiffies, timeout)) { + ret = -ETIMEDOUT; + break; + } + } while (!((fifo & fifo_bit) || (xfer & xfer_bit))); + } else { + reinit_completion(&spi->done); + reg_write(spi, APPLE_SPI_IE_XFER, xfer_bit); + reg_write(spi, APPLE_SPI_IE_FIFO, fifo_bit); + + if (!wait_for_completion_timeout(&spi->done, + msecs_to_jiffies(APPLE_SPI_TIMEOUT_MS))) + ret = -ETIMEDOUT; + + reg_write(spi, APPLE_SPI_IE_XFER, 0); + reg_write(spi, APPLE_SPI_IE_FIFO, 0); + } + + return ret; +} + +static void apple_spi_tx(struct apple_spi *spi, const void **tx_ptr, u32 *left, + unsigned int bytes_per_word) +{ + u32 inuse, words, wrote; + + if (!*tx_ptr) + return; + + inuse = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_TX, reg_read(spi, APPLE_SPI_FIFOSTAT)); + words = wrote = min_t(u32, *left, APPLE_SPI_FIFO_DEPTH - inuse); + + if (!words) + return; + + *left -= words; + + switch (bytes_per_word) { + case 1: { + const u8 *p = *tx_ptr; + + while (words--) + reg_write(spi, APPLE_SPI_TXDATA, *p++); + break; + } + case 2: { + const u16 *p = *tx_ptr; + + while (words--) + reg_write(spi, APPLE_SPI_TXDATA, *p++); + break; + } + case 4: { + const u32 *p = *tx_ptr; + + while (words--) + reg_write(spi, APPLE_SPI_TXDATA, *p++); + break; + } + default: + WARN_ON(1); + } + + *tx_ptr = ((u8 *)*tx_ptr) + bytes_per_word * wrote; +} + +static void apple_spi_rx(struct apple_spi *spi, void **rx_ptr, u32 *left, + unsigned int bytes_per_word) +{ + u32 words, read; + + if (!*rx_ptr) + return; + + words = read = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_RX, reg_read(spi, APPLE_SPI_FIFOSTAT)); + WARN_ON(words > *left); + + if (!words) + return; + + *left -= min_t(u32, *left, words); + + switch (bytes_per_word) { + case 1: { + u8 *p = *rx_ptr; + + while (words--) + *p++ = reg_read(spi, APPLE_SPI_RXDATA); + break; + } + case 2: { + u16 *p = *rx_ptr; + + while (words--) + *p++ = reg_read(spi, APPLE_SPI_RXDATA); + break; + } + case 4: { + u32 *p = *rx_ptr; + + while (words--) + *p++ = reg_read(spi, APPLE_SPI_RXDATA); + break; + } + default: + WARN_ON(1); + } + + *rx_ptr = ((u8 *)*rx_ptr) + bytes_per_word * read; +} + +static int apple_spi_transfer_one(struct spi_controller *ctlr, struct spi_device *device, + struct spi_transfer *t) +{ + struct apple_spi *spi = spi_controller_get_devdata(ctlr); + bool poll = apple_spi_prep_transfer(spi, t); + const void *tx_ptr = t->tx_buf; + void *rx_ptr = t->rx_buf; + unsigned int bytes_per_word; + u32 words, remaining_tx, remaining_rx; + u32 xfer_flags = 0; + u32 fifo_flags; + int retries = 100; + int ret = 0; + + if (t->bits_per_word > 16) + bytes_per_word = 4; + else if (t->bits_per_word > 8) + bytes_per_word = 2; + else + bytes_per_word = 1; + + words = t->len / bytes_per_word; + remaining_tx = tx_ptr ? words : 0; + remaining_rx = rx_ptr ? words : 0; + + /* Reset FIFOs */ + reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET); + + /* Clear IRQ flags */ + reg_write(spi, APPLE_SPI_IF_XFER, ~0); + reg_write(spi, APPLE_SPI_IF_FIFO, ~0); + + /* Determine transfer completion flags we wait for */ + if (tx_ptr) + xfer_flags |= APPLE_SPI_XFER_TXCOMPLETE; + if (rx_ptr) + xfer_flags |= APPLE_SPI_XFER_RXCOMPLETE; + + /* Set transfer length */ + reg_write(spi, APPLE_SPI_TXCNT, remaining_tx); + reg_write(spi, APPLE_SPI_RXCNT, remaining_rx); + + /* Prime transmit FIFO */ + apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); + + /* Start transfer */ + reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RUN); + + /* TX again since a few words get popped off immediately */ + apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); + + while (xfer_flags) { + fifo_flags = 0; + + if (remaining_tx) + fifo_flags |= APPLE_SPI_FIFO_TXTHRESH; + if (remaining_rx) + fifo_flags |= APPLE_SPI_FIFO_RXTHRESH; + + /* Wait for anything to happen */ + ret = apple_spi_wait(spi, fifo_flags, xfer_flags, poll); + if (ret) { + dev_err(&ctlr->dev, "transfer timed out (remaining %d tx, %d rx)\n", + remaining_tx, remaining_rx); + goto err; + } + + /* Stop waiting on transfer halves once they complete */ + xfer_flags &= ~reg_read(spi, APPLE_SPI_IF_XFER); + + /* Transmit and receive everything we can */ + apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word); + apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word); + } + + /* + * Sometimes the transfer completes before the last word is in the RX FIFO. + * Normally one retry is all it takes to get the last word out. + */ + while (remaining_rx && retries--) + apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word); + + if (remaining_tx) + dev_err(&ctlr->dev, "transfer completed with %d words left to transmit\n", + remaining_tx); + if (remaining_rx) + dev_err(&ctlr->dev, "transfer completed with %d words left to receive\n", + remaining_rx); + +err: + fifo_flags = reg_read(spi, APPLE_SPI_IF_FIFO); + WARN_ON(fifo_flags & APPLE_SPI_FIFO_TXOVERFLOW); + WARN_ON(fifo_flags & APPLE_SPI_FIFO_RXUNDERRUN); + + /* Stop transfer */ + reg_write(spi, APPLE_SPI_CTRL, 0); + + return ret; +} + +static int apple_spi_probe(struct platform_device *pdev) +{ + struct apple_spi *spi; + int ret, irq; + struct spi_controller *ctlr; + + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(struct apple_spi)); + if (!ctlr) + return -ENOMEM; + + spi = spi_controller_get_devdata(ctlr); + init_completion(&spi->done); + + spi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(spi->regs)) + return PTR_ERR(spi->regs); + + spi->clk = devm_clk_get_enabled(&pdev->dev, NULL); + if (IS_ERR(spi->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk), + "Unable to find or enable bus clock\n"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, apple_spi_irq, 0, + dev_name(&pdev->dev), spi); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Unable to bind to interrupt\n"); + + ctlr->dev.of_node = pdev->dev.of_node; + ctlr->bus_num = pdev->id; + ctlr->num_chipselect = 1; + ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; + ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); + ctlr->prepare_message = apple_spi_prepare_message; + ctlr->set_cs = apple_spi_set_cs; + ctlr->transfer_one = apple_spi_transfer_one; + ctlr->use_gpio_descriptors = true; + ctlr->auto_runtime_pm = true; + + pm_runtime_set_active(&pdev->dev); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret < 0) + return ret; + + apple_spi_init(spi); + + ret = devm_spi_register_controller(&pdev->dev, ctlr); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "devm_spi_register_controller failed\n"); + + return 0; +} + +static const struct of_device_id apple_spi_of_match[] = { + { .compatible = "apple,spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, apple_spi_of_match); + +static struct platform_driver apple_spi_driver = { + .probe = apple_spi_probe, + .driver = { + .name = "apple-spi", + .of_match_table = apple_spi_of_match, + }, +}; +module_platform_driver(apple_spi_driver); + +MODULE_AUTHOR("Hector Martin "); +MODULE_DESCRIPTION("Apple SoC SPI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-ar934x.c b/drivers/spi/spi-ar934x.c index 5ba98872085184..86c54fff9d6e1c 100644 --- a/drivers/spi/spi-ar934x.c +++ b/drivers/spi/spi-ar934x.c @@ -223,7 +223,7 @@ static struct platform_driver ar934x_spi_driver = { .of_match_table = ar934x_spi_match, }, .probe = ar934x_spi_probe, - .remove_new = ar934x_spi_remove, + .remove = ar934x_spi_remove, }; module_platform_driver(ar934x_spi_driver); diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index bbd417c55e7f56..e9beae95ddedaf 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -239,7 +239,7 @@ static ssize_t aspeed_spi_read_user(struct aspeed_spi_chip *chip, ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, offset, op->cmd.opcode); if (ret < 0) - return ret; + goto stop_user; if (op->dummy.buswidth && op->dummy.nbytes) { for (i = 0; i < op->dummy.nbytes / op->dummy.buswidth; i++) @@ -249,8 +249,9 @@ static ssize_t aspeed_spi_read_user(struct aspeed_spi_chip *chip, aspeed_spi_set_io_mode(chip, io_mode); aspeed_spi_read_from_ahb(buf, chip->ahb_base, len); +stop_user: aspeed_spi_stop_user(chip); - return 0; + return ret; } static ssize_t aspeed_spi_write_user(struct aspeed_spi_chip *chip, @@ -261,10 +262,11 @@ static ssize_t aspeed_spi_write_user(struct aspeed_spi_chip *chip, aspeed_spi_start_user(chip); ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, op->addr.val, op->cmd.opcode); if (ret < 0) - return ret; + goto stop_user; aspeed_spi_write_to_ahb(chip->ahb_base, op->data.buf.out, op->data.nbytes); +stop_user: aspeed_spi_stop_user(chip); - return 0; + return ret; } /* support for 1-1-1, 1-1-2 or 1-1-4 */ @@ -1189,7 +1191,7 @@ MODULE_DEVICE_TABLE(of, aspeed_spi_matches); static struct platform_driver aspeed_spi_driver = { .probe = aspeed_spi_probe, - .remove_new = aspeed_spi_remove, + .remove = aspeed_spi_remove, .driver = { .name = DEVICE_NAME, .of_match_table = aspeed_spi_matches, diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c index 1cea8e159344ec..bbe97ce89a2fd3 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -650,7 +650,7 @@ static struct platform_driver at91_usart_spi_driver = { .pm = &at91_usart_spi_pm_ops, }, .probe = at91_usart_spi_probe, - .remove_new = at91_usart_spi_remove, + .remove = at91_usart_spi_remove, }; module_platform_driver(at91_usart_spi_driver); diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index d78762d4db98f1..9a705a9fddd2ab 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -253,7 +253,7 @@ MODULE_DEVICE_TABLE(of, ath79_spi_of_match); static struct platform_driver ath79_spi_driver = { .probe = ath79_spi_probe, - .remove_new = ath79_spi_remove, + .remove = ath79_spi_remove, .shutdown = ath79_spi_shutdown, .driver = { .name = DRV_NAME, diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index b62f57390d8f0b..89a6b46cd3191a 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1781,7 +1781,7 @@ static struct platform_driver atmel_spi_driver = { .of_match_table = atmel_spi_dt_ids, }, .probe = atmel_spi_probe, - .remove_new = atmel_spi_remove, + .remove = atmel_spi_remove, }; module_platform_driver(atmel_spi_driver); diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index 16f200bb3d1743..b65798ccc6798a 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -940,7 +940,7 @@ MODULE_ALIAS("platform:au1550-spi"); static struct platform_driver au1550_spi_drv = { .probe = au1550_spi_probe, - .remove_new = au1550_spi_remove, + .remove = au1550_spi_remove, .driver = { .name = "au1550-spi", }, diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 2dff95d2b3f5d6..7c252126b33ea8 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -15,6 +15,7 @@ #include #include #include +#include #define SPI_ENGINE_REG_RESET 0x40 @@ -590,6 +591,13 @@ static int spi_engine_transfer_one_message(struct spi_controller *host, reinit_completion(&spi_engine->msg_complete); + if (trace_spi_transfer_start_enabled()) { + struct spi_transfer *xfer; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) + trace_spi_transfer_start(msg, xfer); + } + spin_lock_irqsave(&spi_engine->lock, flags); if (spi_engine_write_cmd_fifo(spi_engine, msg)) @@ -617,6 +625,13 @@ static int spi_engine_transfer_one_message(struct spi_controller *host, msg->status = -ETIMEDOUT; } + if (trace_spi_transfer_stop_enabled()) { + struct spi_transfer *xfer; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) + trace_spi_transfer_stop(msg, xfer); + } + spi_finalize_current_message(host); return msg->status; diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index e1b9b12357877f..0d1aa659248460 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1435,7 +1435,7 @@ static struct platform_driver bcm2835_spi_driver = { .of_match_table = bcm2835_spi_match, }, .probe = bcm2835_spi_probe, - .remove_new = bcm2835_spi_remove, + .remove = bcm2835_spi_remove, .shutdown = bcm2835_spi_remove, }; module_platform_driver(bcm2835_spi_driver); diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 06fe155a70c98e..90698d7d809dd1 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -577,7 +577,7 @@ static struct platform_driver bcm2835aux_spi_driver = { .of_match_table = bcm2835aux_spi_match, }, .probe = bcm2835aux_spi_probe, - .remove_new = bcm2835aux_spi_remove, + .remove = bcm2835aux_spi_remove, }; module_platform_driver(bcm2835aux_spi_driver); diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 1ca857c2a4aa31..644b44d2aef24e 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -944,7 +944,7 @@ static struct platform_driver bcm63xx_hsspi_driver = { .of_match_table = bcm63xx_hsspi_of_match, }, .probe = bcm63xx_hsspi_probe, - .remove_new = bcm63xx_hsspi_remove, + .remove = bcm63xx_hsspi_remove, }; module_platform_driver(bcm63xx_hsspi_driver); diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index ef3a7226db125c..c8f64ec69344af 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -656,7 +656,7 @@ static struct platform_driver bcm63xx_spi_driver = { }, .id_table = bcm63xx_spi_dev_match, .probe = bcm63xx_spi_probe, - .remove_new = bcm63xx_spi_remove, + .remove = bcm63xx_spi_remove, }; module_platform_driver(bcm63xx_spi_driver); diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c index d936104a41ece7..f16298b7523609 100644 --- a/drivers/spi/spi-bcmbca-hsspi.c +++ b/drivers/spi/spi-bcmbca-hsspi.c @@ -633,7 +633,7 @@ static struct platform_driver bcmbca_hsspi_driver = { .of_match_table = bcmbca_hsspi_of_match, }, .probe = bcmbca_hsspi_probe, - .remove_new = bcmbca_hsspi_remove, + .remove = bcmbca_hsspi_remove, }; module_platform_driver(bcmbca_hsspi_driver); diff --git a/drivers/spi/spi-brcmstb-qspi.c b/drivers/spi/spi-brcmstb-qspi.c index e1b137419f5cdb..7a33b479c1f706 100644 --- a/drivers/spi/spi-brcmstb-qspi.c +++ b/drivers/spi/spi-brcmstb-qspi.c @@ -28,7 +28,7 @@ static void brcmstb_qspi_remove(struct platform_device *pdev) static struct platform_driver brcmstb_qspi_driver = { .probe = brcmstb_qspi_probe, - .remove_new = brcmstb_qspi_remove, + .remove = brcmstb_qspi_remove, .driver = { .name = "brcmstb_qspi", .pm = &bcm_qspi_pm_ops, diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 1755ca026f08ff..a031ecb358e082 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -43,6 +43,7 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SPI_CS_CNT_MAX); #define CQSPI_SLOW_SRAM BIT(4) #define CQSPI_NEEDS_APB_AHB_HAZARD_WAR BIT(5) #define CQSPI_RD_NO_IRQ BIT(6) +#define CQSPI_DISABLE_STIG_MODE BIT(7) /* Capabilities */ #define CQSPI_SUPPORTS_OCTAL BIT(0) @@ -103,6 +104,7 @@ struct cqspi_st { bool apb_ahb_hazard; bool is_jh7110; /* Flag for StarFive JH7110 SoC */ + bool disable_stig_mode; const struct cqspi_driver_platdata *ddata; }; @@ -1416,7 +1418,8 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op) * reads, prefer STIG mode for such small reads. */ if (!op->addr.nbytes || - op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX) + (op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX && + !cqspi->disable_stig_mode)) return cqspi_command_read(f_pdata, op); return cqspi_read(f_pdata, op); @@ -1880,6 +1883,8 @@ static int cqspi_probe(struct platform_device *pdev) if (ret) goto probe_reset_failed; } + if (ddata->quirks & CQSPI_DISABLE_STIG_MODE) + cqspi->disable_stig_mode = true; if (of_device_is_compatible(pdev->dev.of_node, "xlnx,versal-ospi-1.0")) { @@ -2043,7 +2048,8 @@ static const struct cqspi_driver_platdata intel_lgm_qspi = { static const struct cqspi_driver_platdata socfpga_qspi = { .quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_NO_SUPPORT_WR_COMPLETION - | CQSPI_SLOW_SRAM, + | CQSPI_SLOW_SRAM + | CQSPI_DISABLE_STIG_MODE, }; static const struct cqspi_driver_platdata versal_ospi = { @@ -2112,7 +2118,7 @@ MODULE_DEVICE_TABLE(of, cqspi_dt_ids); static struct platform_driver cqspi_platform_driver = { .probe = cqspi_probe, - .remove_new = cqspi_remove, + .remove = cqspi_remove, .driver = { .name = CQSPI_NAME, .pm = pm_ptr(&cqspi_dev_pm_ops), diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 3c87d2bf786a9e..9e56bde8776804 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -806,7 +806,7 @@ MODULE_DEVICE_TABLE(of, cdns_spi_of_match); /* cdns_spi_driver - This structure defines the SPI subsystem platform driver */ static struct platform_driver cdns_spi_driver = { .probe = cdns_spi_probe, - .remove_new = cdns_spi_remove, + .remove = cdns_spi_remove, .driver = { .name = CDNS_SPI_NAME, .of_match_table = cdns_spi_of_match, diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c index 4511c3b31223d3..a5ad90d66ec045 100644 --- a/drivers/spi/spi-cavium-octeon.c +++ b/drivers/spi/spi-cavium-octeon.c @@ -90,7 +90,7 @@ static struct platform_driver octeon_spi_driver = { .of_match_table = octeon_spi_match, }, .probe = octeon_spi_probe, - .remove_new = octeon_spi_remove, + .remove = octeon_spi_remove, }; module_platform_driver(octeon_spi_driver); diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c index d2351812d310d7..46bc208f2d0509 100644 --- a/drivers/spi/spi-ch341.c +++ b/drivers/spi/spi-ch341.c @@ -152,7 +152,7 @@ static int ch341_probe(struct usb_interface *intf, if (ret) return ret; - ctrl = devm_spi_alloc_master(&udev->dev, sizeof(struct ch341_spi_dev)); + ctrl = devm_spi_alloc_host(&udev->dev, sizeof(struct ch341_spi_dev)); if (!ctrl) return -ENOMEM; diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index e83cd0510f2029..fdf37636cb9f08 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -502,7 +502,7 @@ static struct platform_driver mcfqspi_driver = { .driver.name = DRIVER_NAME, .driver.pm = &mcfqspi_pm, .probe = mcfqspi_probe, - .remove_new = mcfqspi_remove, + .remove = mcfqspi_remove, }; module_platform_driver(mcfqspi_driver); diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index 5b8ed65f8094d2..ceefc253c54904 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -229,6 +230,33 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi) return CS42L43_SPI_MAX_LENGTH; } +static int cs42l43_get_speaker_id_gpios(struct cs42l43_spi *priv, int *result) +{ + struct gpio_descs *descs; + u32 spkid; + int i, ret; + + descs = gpiod_get_array_optional(priv->dev, "spk-id", GPIOD_IN); + if (IS_ERR_OR_NULL(descs)) + return PTR_ERR(descs); + + spkid = 0; + for (i = 0; i < descs->ndescs; i++) { + ret = gpiod_get_value_cansleep(descs->desc[i]); + if (ret < 0) + goto err; + + spkid |= (ret << i); + } + + dev_dbg(priv->dev, "spk-id-gpios = %d\n", spkid); + *result = spkid; +err: + gpiod_put_array(descs); + + return ret; +} + static struct fwnode_handle *cs42l43_find_xu_node(struct fwnode_handle *fwnode) { static const u32 func_smart_amp = 0x1; @@ -306,6 +334,7 @@ static int cs42l43_spi_probe(struct platform_device *pdev) struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev); struct fwnode_handle *xu_fwnode __free(fwnode_handle) = cs42l43_find_xu_node(fwnode); int nsidecars = 0; + int spkid = -EINVAL; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -360,6 +389,18 @@ static int cs42l43_spi_probe(struct platform_device *pdev) fwnode_property_read_u32(xu_fwnode, "01fa-sidecar-instances", &nsidecars); if (nsidecars) { + ret = fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid); + if (!ret) { + dev_dbg(priv->dev, "01fa-spk-id-val = %d\n", spkid); + } else if (ret != -EINVAL) { + return dev_err_probe(priv->dev, ret, "Failed to get spk-id-val\n"); + } else { + ret = cs42l43_get_speaker_id_gpios(priv, &spkid); + if (ret < 0) + return dev_err_probe(priv->dev, ret, + "Failed to get spk-id-gpios\n"); + } + ret = software_node_register(&cs42l43_gpiochip_swnode); if (ret) return dev_err_probe(priv->dev, ret, @@ -385,11 +426,6 @@ static int cs42l43_spi_probe(struct platform_device *pdev) if (nsidecars) { struct spi_board_info *ampl_info; struct spi_board_info *ampr_info; - int spkid = -EINVAL; - - fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid); - - dev_dbg(priv->dev, "Found speaker ID %d\n", spkid); ampl_info = cs42l43_create_bridge_amp(priv, "cs35l56-left", 0, spkid); if (!ampl_info) @@ -426,7 +462,7 @@ static struct platform_driver cs42l43_spi_driver = { }; module_platform_driver(cs42l43_spi_driver); -MODULE_IMPORT_NS(GPIO_SWNODE); +MODULE_IMPORT_NS("GPIO_SWNODE"); MODULE_DESCRIPTION("CS42L43 SPI Driver"); MODULE_AUTHOR("Lucas Tanure "); MODULE_AUTHOR("Maciej Strozek "); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index ad26c8409733ca..a29934422356b6 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -1039,7 +1039,7 @@ static struct platform_driver davinci_spi_driver = { .of_match_table = of_match_ptr(davinci_spi_of_match), }, .probe = davinci_spi_probe, - .remove_new = davinci_spi_remove, + .remove = davinci_spi_remove, }; module_platform_driver(davinci_spi_driver); diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c index 4ba1d9245c9fd1..2013bc56ded8fd 100644 --- a/drivers/spi/spi-dln2.c +++ b/drivers/spi/spi-dln2.c @@ -871,7 +871,7 @@ static struct platform_driver spi_dln2_driver = { .pm = &dln2_spi_pm, }, .probe = dln2_spi_probe, - .remove_new = dln2_spi_remove, + .remove = dln2_spi_remove, }; module_platform_driver(spi_dln2_driver); diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index 4577e8096cd952..4a5be813efa75e 100644 --- a/drivers/spi/spi-dw-bt1.c +++ b/drivers/spi/spi-dw-bt1.c @@ -317,7 +317,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_bt1_of_match); static struct platform_driver dw_spi_bt1_driver = { .probe = dw_spi_bt1_probe, - .remove_new = dw_spi_bt1_remove, + .remove = dw_spi_bt1_remove, .driver = { .name = "bt1-sys-ssi", .of_match_table = dw_spi_bt1_of_match, @@ -328,4 +328,4 @@ module_platform_driver(dw_spi_bt1_driver); MODULE_AUTHOR("Serge Semin "); MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SPI_DW_CORE); +MODULE_IMPORT_NS("SPI_DW_CORE"); diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index 431788dd848cea..ea517af9435fa1 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -104,7 +104,7 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable) else dw_writel(dws, DW_SPI_SER, 0); } -EXPORT_SYMBOL_NS_GPL(dw_spi_set_cs, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_set_cs, "SPI_DW_CORE"); /* Return the max entries we can fill into tx fifo */ static inline u32 dw_spi_tx_max(struct dw_spi *dws) @@ -208,7 +208,7 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw) return ret; } -EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, "SPI_DW_CORE"); static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws) { @@ -351,7 +351,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi, dws->cur_rx_sample_dly = chip->rx_sample_dly; } } -EXPORT_SYMBOL_NS_GPL(dw_spi_update_config, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_update_config, "SPI_DW_CORE"); static void dw_spi_irq_setup(struct dw_spi *dws) { @@ -982,7 +982,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) spi_controller_put(host); return ret; } -EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, "SPI_DW_CORE"); void dw_spi_remove_host(struct dw_spi *dws) { @@ -997,7 +997,7 @@ void dw_spi_remove_host(struct dw_spi *dws) free_irq(dws->irq, dws->host); } -EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, "SPI_DW_CORE"); int dw_spi_suspend_host(struct dw_spi *dws) { @@ -1010,14 +1010,14 @@ int dw_spi_suspend_host(struct dw_spi *dws) dw_spi_shutdown_chip(dws); return 0; } -EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_host, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_host, "SPI_DW_CORE"); int dw_spi_resume_host(struct dw_spi *dws) { dw_spi_hw_init(&dws->host->dev, dws); return spi_controller_resume(dws->host); } -EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, "SPI_DW_CORE"); MODULE_AUTHOR("Feng Tang "); MODULE_DESCRIPTION("Driver for DesignWare SPI controller core"); diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c index f4c209e5f52baa..b5bed02b7e5006 100644 --- a/drivers/spi/spi-dw-dma.c +++ b/drivers/spi/spi-dw-dma.c @@ -693,7 +693,7 @@ void dw_spi_dma_setup_mfld(struct dw_spi *dws) { dws->dma_ops = &dw_spi_dma_mfld_ops; } -EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_mfld, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_mfld, "SPI_DW_CORE"); static const struct dw_spi_dma_ops dw_spi_dma_generic_ops = { .dma_init = dw_spi_dma_init_generic, @@ -708,4 +708,4 @@ void dw_spi_dma_setup_generic(struct dw_spi *dws) { dws->dma_ops = &dw_spi_dma_generic_ops; } -EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_generic, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_generic, "SPI_DW_CORE"); diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 819907e332c4b0..f0f576fac77afe 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -433,7 +433,7 @@ MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match); static struct platform_driver dw_spi_mmio_driver = { .probe = dw_spi_mmio_probe, - .remove_new = dw_spi_mmio_remove, + .remove = dw_spi_mmio_remove, .driver = { .name = DRIVER_NAME, .of_match_table = dw_spi_mmio_of_match, @@ -445,4 +445,4 @@ module_platform_driver(dw_spi_mmio_driver); MODULE_AUTHOR("Jean-Hugues Deschenes "); MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SPI_DW_CORE); +MODULE_IMPORT_NS("SPI_DW_CORE"); diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c index 7c8279d13f3194..b32d6648a32ea2 100644 --- a/drivers/spi/spi-dw-pci.c +++ b/drivers/spi/spi-dw-pci.c @@ -98,15 +98,14 @@ static int dw_spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *en dws->paddr = pci_resource_start(pdev, pci_bar); pci_set_master(pdev); - ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev)); - if (ret) - return ret; - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (ret < 0) return ret; - dws->regs = pcim_iomap_table(pdev)[pci_bar]; + dws->regs = pcim_iomap_region(pdev, pci_bar, pci_name(pdev)); + if (IS_ERR(dws->regs)) + return PTR_ERR(dws->regs); + dws->irq = pci_irq_vector(pdev, 0); /* @@ -212,4 +211,4 @@ module_pci_driver(dw_spi_pci_driver); MODULE_AUTHOR("Feng Tang "); MODULE_DESCRIPTION("PCI interface driver for DW SPI Core"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SPI_DW_CORE); +MODULE_IMPORT_NS("SPI_DW_CORE"); diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index dc6bdc74643d3a..e1d097091925c2 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -729,7 +729,7 @@ static struct platform_driver ep93xx_spi_driver = { .of_match_table = ep93xx_spi_of_ids, }, .probe = ep93xx_spi_probe, - .remove_new = ep93xx_spi_remove, + .remove = ep93xx_spi_remove, }; module_platform_driver(ep93xx_spi_driver); diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 3fa990fb59c78b..067c954cb6ea03 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -280,25 +280,25 @@ static void dspi_native_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) static void dspi_8on32_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) { - *txdata = cpu_to_be32(*(u32 *)dspi->tx); + *txdata = (__force u32)cpu_to_be32(*(u32 *)dspi->tx); dspi->tx += sizeof(u32); } static void dspi_8on32_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) { - *(u32 *)dspi->rx = be32_to_cpu(rxdata); + *(u32 *)dspi->rx = be32_to_cpu((__force __be32)rxdata); dspi->rx += sizeof(u32); } static void dspi_8on16_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) { - *txdata = cpu_to_be16(*(u16 *)dspi->tx); + *txdata = (__force u32)cpu_to_be16(*(u16 *)dspi->tx); dspi->tx += sizeof(u16); } static void dspi_8on16_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) { - *(u16 *)dspi->rx = be16_to_cpu(rxdata); + *(u16 *)dspi->rx = be16_to_cpu((__force __be16)rxdata); dspi->rx += sizeof(u16); } @@ -1473,7 +1473,7 @@ static struct platform_driver fsl_dspi_driver = { .driver.of_match_table = fsl_dspi_dt_ids, .driver.pm = &dspi_pm, .probe = dspi_probe, - .remove_new = dspi_remove, + .remove = dspi_remove, .shutdown = dspi_shutdown, }; module_platform_driver(fsl_dspi_driver); diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index ea647ee94da8ab..6a73eaa34cf7cd 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -835,7 +835,7 @@ static struct platform_driver fsl_espi_driver = { .pm = &espi_pm, }, .probe = of_fsl_espi_probe, - .remove_new = of_fsl_espi_remove, + .remove = of_fsl_espi_remove, }; module_platform_driver(fsl_espi_driver); diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 977e8b55c82b7d..40f5c8fdba765a 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -92,6 +92,7 @@ struct lpspi_config { u8 prescale; u16 mode; u32 speed_hz; + u32 effective_speed_hz; }; struct fsl_lpspi_data { @@ -315,9 +316,10 @@ static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi) static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) { struct lpspi_config config = fsl_lpspi->config; - unsigned int perclk_rate, scldiv, div; + unsigned int perclk_rate, div; u8 prescale_max; u8 prescale; + int scldiv; perclk_rate = clk_get_rate(fsl_lpspi->clk_per); prescale_max = fsl_lpspi->devtype_data->prescale_max; @@ -338,19 +340,22 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) for (prescale = 0; prescale <= prescale_max; prescale++) { scldiv = div / (1 << prescale) - 2; - if (scldiv < 256) { + if (scldiv >= 0 && scldiv < 256) { fsl_lpspi->config.prescale = prescale; break; } } - if (scldiv >= 256) + if (scldiv < 0 || scldiv >= 256) return -EINVAL; writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16), fsl_lpspi->base + IMX7ULP_CCR); - dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale=%d, scldiv=%d\n", + fsl_lpspi->config.effective_speed_hz = perclk_rate / (scldiv + 2) * + (1 << prescale); + + dev_dbg(fsl_lpspi->dev, "perclk=%u, speed=%u, prescale=%u, scldiv=%d\n", perclk_rate, config.speed_hz, prescale, scldiv); return 0; @@ -749,6 +754,8 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller, if (ret < 0) return ret; + t->effective_speed_hz = fsl_lpspi->config.effective_speed_hz; + fsl_lpspi_set_cmd(fsl_lpspi); fsl_lpspi->is_first_byte = false; @@ -891,7 +898,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) return ret; } - ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, IRQF_NO_AUTOEN, dev_name(&pdev->dev), fsl_lpspi); if (ret) { dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret); @@ -948,14 +955,10 @@ static int fsl_lpspi_probe(struct platform_device *pdev) ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller); if (ret == -EPROBE_DEFER) goto out_pm_get; - if (ret < 0) + if (ret < 0) { dev_warn(&pdev->dev, "dma setup error %d, use pio\n", ret); - else - /* - * disable LPSPI module IRQ when enable DMA mode successfully, - * to prevent the unexpected LPSPI module IRQ events. - */ - disable_irq(irq); + enable_irq(irq); + } ret = devm_spi_register_controller(&pdev->dev, controller); if (ret < 0) { @@ -1024,7 +1027,7 @@ static struct platform_driver fsl_lpspi_driver = { .pm = pm_ptr(&fsl_lpspi_pm_ops), }, .probe = fsl_lpspi_probe, - .remove_new = fsl_lpspi_remove, + .remove = fsl_lpspi_remove, }; module_platform_driver(fsl_lpspi_driver); diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index 79bac30e79af64..9ec53bf0dda8ea 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -997,7 +997,7 @@ static struct platform_driver fsl_qspi_driver = { .pm = &fsl_qspi_pm_ops, }, .probe = fsl_qspi_probe, - .remove_new = fsl_qspi_remove, + .remove = fsl_qspi_remove, }; module_platform_driver(fsl_qspi_driver); diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 997e07c0a24aa9..856a4a9def66f2 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -714,7 +714,7 @@ static struct platform_driver of_fsl_spi_driver = { .of_match_table = of_fsl_spi_match, }, .probe = of_fsl_spi_probe, - .remove_new = of_fsl_spi_remove, + .remove = of_fsl_spi_remove, }; #ifdef CONFIG_MPC832x_RDB @@ -757,7 +757,7 @@ static void plat_mpc8xxx_spi_remove(struct platform_device *pdev) MODULE_ALIAS("platform:mpc8xxx_spi"); static struct platform_driver mpc8xxx_spi_driver = { .probe = plat_mpc8xxx_spi_probe, - .remove_new = plat_mpc8xxx_spi_remove, + .remove = plat_mpc8xxx_spi_remove, .driver = { .name = "mpc8xxx_spi", }, diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index 16054695bdb04a..dadf558dd9c0c6 100644 --- a/drivers/spi/spi-hisi-kunpeng.c +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -542,7 +542,7 @@ MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match); static struct platform_driver hisi_spi_driver = { .probe = hisi_spi_probe, - .remove_new = hisi_spi_remove, + .remove = hisi_spi_remove, .driver = { .name = "hisi-kunpeng-spi", .acpi_match_table = hisi_spi_acpi_match, diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c index 1301d14483d482..b2af2eed197f28 100644 --- a/drivers/spi/spi-hisi-sfc-v3xx.c +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -40,7 +40,7 @@ /* Common definition of interrupt bit masks */ #define HISI_SFC_V3XX_INT_MASK_ALL (0x1ff) /* all the masks */ #define HISI_SFC_V3XX_INT_MASK_CPLT BIT(0) /* command execution complete */ -#define HISI_SFC_V3XX_INT_MASK_PP_ERR BIT(2) /* page progrom error */ +#define HISI_SFC_V3XX_INT_MASK_PP_ERR BIT(2) /* page program error */ #define HISI_SFC_V3XX_INT_MASK_IACCES BIT(5) /* error visiting inaccessible/ * protected address */ diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index d8360f94d3b7df..168ccf51f6d4a8 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -756,7 +756,7 @@ static struct platform_driver img_spfi_driver = { .of_match_table = of_match_ptr(img_spfi_of_match), }, .probe = img_spfi_probe, - .remove_new = img_spfi_remove, + .remove = img_spfi_remove, }; module_platform_driver(img_spfi_driver); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 4c31d36f3130a9..eeb7d082c2472f 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -3,6 +3,7 @@ // Copyright (C) 2008 Juergen Beisert #include +#include #include #include #include @@ -13,7 +14,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -71,7 +75,8 @@ struct spi_imx_data; struct spi_imx_devtype_data { void (*intctrl)(struct spi_imx_data *spi_imx, int enable); int (*prepare_message)(struct spi_imx_data *spi_imx, struct spi_message *msg); - int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi); + int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi, + struct spi_transfer *t); void (*trigger)(struct spi_imx_data *spi_imx); int (*rx_available)(struct spi_imx_data *spi_imx); void (*reset)(struct spi_imx_data *spi_imx); @@ -301,6 +306,18 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device #define MX51_ECSPI_STAT 0x18 #define MX51_ECSPI_STAT_RR (1 << 3) +#define MX51_ECSPI_PERIOD 0x1c +#define MX51_ECSPI_PERIOD_MASK 0x7fff +/* + * As measured on the i.MX6, the SPI host controller inserts a 4 SPI-Clock + * (SCLK) delay after each burst if the PERIOD reg is 0x0. This value will be + * called MX51_ECSPI_PERIOD_MIN_DELAY_SCK. + * + * If the PERIOD register is != 0, the controller inserts a delay of + * MX51_ECSPI_PERIOD_MIN_DELAY_SCK + register value + 1 SCLK after each burst. + */ +#define MX51_ECSPI_PERIOD_MIN_DELAY_SCK 4 + #define MX51_ECSPI_TESTREG 0x20 #define MX51_ECSPI_TESTREG_LBC BIT(31) @@ -407,7 +424,7 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx) static void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx) { - u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA)); + u32 val = ioread32be(spi_imx->base + MXC_CSPIRXDATA); if (spi_imx->rx_buf) { int n_bytes = spi_imx->target_burst % sizeof(val); @@ -436,13 +453,12 @@ static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx) if (spi_imx->tx_buf) { memcpy(((u8 *)&val) + sizeof(val) - n_bytes, spi_imx->tx_buf, n_bytes); - val = cpu_to_be32(val); spi_imx->tx_buf += n_bytes; } spi_imx->count -= n_bytes; - writel(val, spi_imx->base + MXC_CSPITXDATA); + iowrite32be(val, spi_imx->base + MXC_CSPITXDATA); } /* MX51 eCSPI */ @@ -649,9 +665,10 @@ static void mx51_configure_cpha(struct spi_imx_data *spi_imx, } static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL); + u64 word_delay_sck; u32 clk; /* Clear BL field and set the right value */ @@ -683,6 +700,49 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); + /* calculate word delay in SPI Clock (SCLK) cycles */ + if (t->word_delay.value == 0) { + word_delay_sck = 0; + } else if (t->word_delay.unit == SPI_DELAY_UNIT_SCK) { + word_delay_sck = t->word_delay.value; + + if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK) + word_delay_sck = 0; + else if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1) + word_delay_sck = 1; + else + word_delay_sck -= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1; + } else { + int word_delay_ns; + + word_delay_ns = spi_delay_to_ns(&t->word_delay, t); + if (word_delay_ns < 0) + return word_delay_ns; + + if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK, + spi_imx->spi_bus_clk)) { + word_delay_sck = 0; + } else if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1, + spi_imx->spi_bus_clk)) { + word_delay_sck = 1; + } else { + word_delay_ns -= mul_u64_u32_div(NSEC_PER_SEC, + MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1, + spi_imx->spi_bus_clk); + + word_delay_sck = DIV_U64_ROUND_UP((u64)word_delay_ns * spi_imx->spi_bus_clk, + NSEC_PER_SEC); + } + } + + if (!FIELD_FIT(MX51_ECSPI_PERIOD_MASK, word_delay_sck)) + return -EINVAL; + + writel(FIELD_PREP(MX51_ECSPI_PERIOD_MASK, word_delay_sck), + spi_imx->base + MX51_ECSPI_PERIOD); + return 0; } @@ -774,7 +834,7 @@ static int mx31_prepare_message(struct spi_imx_data *spi_imx, } static int mx31_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_HOST; unsigned int clk; @@ -878,7 +938,7 @@ static int mx21_prepare_message(struct spi_imx_data *spi_imx, } static int mx21_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_HOST; unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; @@ -953,7 +1013,7 @@ static int mx1_prepare_message(struct spi_imx_data *spi_imx, } static int mx1_prepare_transfer(struct spi_imx_data *spi_imx, - struct spi_device *spi) + struct spi_device *spi, struct spi_transfer *t) { unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_HOST; unsigned int clk; @@ -1263,11 +1323,13 @@ static int spi_imx_setupxfer(struct spi_device *spi, /* * Initialize the functions for transfer. To transfer non byte-aligned - * words, we have to use multiple word-size bursts, we can't use - * dynamic_burst in that case. + * words, we have to use multiple word-size bursts. To insert word + * delay, the burst size has to equal the word size. We can't use + * dynamic_burst in these cases. */ if (spi_imx->devtype_data->dynamic_burst && !spi_imx->target_mode && !(spi->mode & SPI_CS_WORD) && + !(t->word_delay.value) && (spi_imx->bits_per_word == 8 || spi_imx->bits_per_word == 16 || spi_imx->bits_per_word == 32)) { @@ -1304,7 +1366,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, spi_imx->target_burst = t->len; } - spi_imx->devtype_data->prepare_transfer(spi_imx, spi); + spi_imx->devtype_data->prepare_transfer(spi_imx, spi, t); return 0; } @@ -1610,12 +1672,30 @@ static int spi_imx_pio_transfer_target(struct spi_device *spi, return ret; } +static unsigned int spi_imx_transfer_estimate_time_us(struct spi_transfer *transfer) +{ + u64 result; + + result = DIV_U64_ROUND_CLOSEST((u64)USEC_PER_SEC * transfer->len * BITS_PER_BYTE, + transfer->effective_speed_hz); + if (transfer->word_delay.value) { + unsigned int word_delay_us; + unsigned int words; + + words = DIV_ROUND_UP(transfer->len * BITS_PER_BYTE, transfer->bits_per_word); + word_delay_us = DIV_ROUND_CLOSEST(spi_delay_to_ns(&transfer->word_delay, transfer), + NSEC_PER_USEC); + result += (u64)words * word_delay_us; + } + + return min(result, U32_MAX); +} + static int spi_imx_transfer_one(struct spi_controller *controller, struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); - unsigned long hz_per_byte, byte_limit; spi_imx_setupxfer(spi, transfer); transfer->effective_speed_hz = spi_imx->spi_bus_clk; @@ -1634,15 +1714,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller, */ if (spi_imx->usedma) return spi_imx_dma_transfer(spi_imx, transfer); - /* - * Calculate the estimated time in us the transfer runs. Find - * the number of Hz per byte per polling limit. - */ - hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0; - byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1; /* run in polling mode for short transfers */ - if (transfer->len < byte_limit) + if (transfer->len == 1 || (polling_limit_us && + spi_imx_transfer_estimate_time_us(transfer) < polling_limit_us)) return spi_imx_poll_transfer(spi, transfer); return spi_imx_pio_transfer(spi, transfer); @@ -1956,7 +2031,7 @@ static struct platform_driver spi_imx_driver = { .pm = pm_ptr(&imx_spi_pm), }, .probe = spi_imx_probe, - .remove_new = spi_imx_remove, + .remove = spi_imx_remove, }; module_platform_driver(spi_imx_driver); diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c index 4337ca51d7aa21..4d9ffec900bbf1 100644 --- a/drivers/spi/spi-intel-pci.c +++ b/drivers/spi/spi-intel-pci.c @@ -86,6 +86,8 @@ static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0xa823), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xe323), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xe423), (unsigned long)&cnl_info }, { }, }; MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); @@ -94,6 +96,7 @@ static struct pci_driver intel_spi_pci_driver = { .name = "intel-spi", .id_table = intel_spi_pci_ids, .probe = intel_spi_pci_probe, + .dev_groups = intel_spi_groups, }; module_pci_driver(intel_spi_pci_driver); diff --git a/drivers/spi/spi-intel-platform.c b/drivers/spi/spi-intel-platform.c index 2ef09fa356612b..0974cca83a5d23 100644 --- a/drivers/spi/spi-intel-platform.c +++ b/drivers/spi/spi-intel-platform.c @@ -28,6 +28,7 @@ static struct platform_driver intel_spi_platform_driver = { .probe = intel_spi_platform_probe, .driver = { .name = "intel-spi", + .dev_groups = intel_spi_groups, }, }; diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c index 795b7e72baead0..b0dcdb6fb8fa9f 100644 --- a/drivers/spi/spi-intel.c +++ b/drivers/spi/spi-intel.c @@ -148,6 +148,8 @@ * @pr_num: Maximum number of protected range registers * @chip0_size: Size of the first flash chip in bytes * @locked: Is SPI setting locked + * @protected: Whether the regions are write protected + * @bios_locked: Is BIOS region locked * @swseq_reg: Use SW sequencer in register reads/writes * @swseq_erase: Use SW sequencer in erase operation * @atomic_preopcode: Holds preopcode when atomic sequence is requested @@ -166,6 +168,8 @@ struct intel_spi { size_t pr_num; size_t chip0_size; bool locked; + bool protected; + bool bios_locked; bool swseq_reg; bool swseq_erase; u8 atomic_preopcode; @@ -1109,10 +1113,13 @@ static int intel_spi_init(struct intel_spi *ispi) return -EINVAL; } - /* Try to disable write protection if user asked to do so */ - if (writeable && !intel_spi_set_writeable(ispi)) { - dev_warn(ispi->dev, "can't disable chip write protection\n"); - writeable = false; + ispi->bios_locked = true; + /* Try to disable BIOS write protection if user asked to do so */ + if (writeable) { + if (intel_spi_set_writeable(ispi)) + ispi->bios_locked = false; + else + dev_warn(ispi->dev, "can't disable chip write protection\n"); } /* Disable #SMI generation from HW sequencer */ @@ -1247,8 +1254,10 @@ static void intel_spi_fill_partition(struct intel_spi *ispi, * Also if the user did not ask the chip to be writeable * mask the bit too. */ - if (!writeable || intel_spi_is_protected(ispi, base, limit)) + if (!writeable || intel_spi_is_protected(ispi, base, limit)) { part->mask_flags |= MTD_WRITEABLE; + ispi->protected = true; + } end = (limit << 12) + 4096; if (end > part->size) @@ -1411,6 +1420,50 @@ static int intel_spi_populate_chip(struct intel_spi *ispi) return 0; } +static ssize_t intel_spi_protected_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_spi *ispi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", ispi->protected); +} +static DEVICE_ATTR_ADMIN_RO(intel_spi_protected); + +static ssize_t intel_spi_locked_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_spi *ispi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", ispi->locked); +} +static DEVICE_ATTR_ADMIN_RO(intel_spi_locked); + +static ssize_t intel_spi_bios_locked_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_spi *ispi = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", ispi->bios_locked); +} +static DEVICE_ATTR_ADMIN_RO(intel_spi_bios_locked); + +static struct attribute *intel_spi_attrs[] = { + &dev_attr_intel_spi_protected.attr, + &dev_attr_intel_spi_locked.attr, + &dev_attr_intel_spi_bios_locked.attr, + NULL +}; + +static const struct attribute_group intel_spi_attr_group = { + .attrs = intel_spi_attrs, +}; + +const struct attribute_group *intel_spi_groups[] = { + &intel_spi_attr_group, + NULL +}; +EXPORT_SYMBOL_GPL(intel_spi_groups); + /** * intel_spi_probe() - Probe the Intel SPI flash controller * @dev: Pointer to the parent device @@ -1451,6 +1504,7 @@ int intel_spi_probe(struct device *dev, struct resource *mem, if (ret) return ret; + dev_set_drvdata(dev, ispi); return intel_spi_populate_chip(ispi); } EXPORT_SYMBOL_GPL(intel_spi_probe); diff --git a/drivers/spi/spi-intel.h b/drivers/spi/spi-intel.h index a4f0327a46ff29..c5f35060dd6372 100644 --- a/drivers/spi/spi-intel.h +++ b/drivers/spi/spi-intel.h @@ -13,6 +13,8 @@ struct resource; +extern const struct attribute_group *intel_spi_groups[]; + int intel_spi_probe(struct device *dev, struct resource *mem, const struct intel_spi_boardinfo *info); diff --git a/drivers/spi/spi-iproc-qspi.c b/drivers/spi/spi-iproc-qspi.c index 39ee2b43a51627..392acc4026ab27 100644 --- a/drivers/spi/spi-iproc-qspi.c +++ b/drivers/spi/spi-iproc-qspi.c @@ -138,7 +138,7 @@ MODULE_DEVICE_TABLE(of, bcm_iproc_of_match); static struct platform_driver bcm_iproc_driver = { .probe = bcm_iproc_probe, - .remove_new = bcm_iproc_remove, + .remove = bcm_iproc_remove, .driver = { .name = "bcm_iproc", .pm = &bcm_qspi_pm_ops, diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c index 18a46569ba46e9..60849e07f674a4 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -139,7 +139,7 @@ #define LTQ_SPI_FGPO_CLROUTN_S 0 #define LTQ_SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */ -#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */ +#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Receive to-do value */ #define LTQ_SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */ #define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ @@ -1029,7 +1029,7 @@ static void lantiq_ssc_remove(struct platform_device *pdev) static struct platform_driver lantiq_ssc_driver = { .probe = lantiq_ssc_probe, - .remove_new = lantiq_ssc_remove, + .remove = lantiq_ssc_remove, .driver = { .name = "spi-lantiq-ssc", .of_match_table = lantiq_ssc_match, diff --git a/drivers/spi/spi-ljca.c b/drivers/spi/spi-ljca.c index 1cc1422ddba0b6..2cab79ad2b98f2 100644 --- a/drivers/spi/spi-ljca.c +++ b/drivers/spi/spi-ljca.c @@ -294,4 +294,4 @@ MODULE_AUTHOR("Zhifeng Wang "); MODULE_AUTHOR("Lixu Zhang "); MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-SPI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(LJCA); +MODULE_IMPORT_NS("LJCA"); diff --git a/drivers/spi/spi-loongson-core.c b/drivers/spi/spi-loongson-core.c index f97800b6fd6536..4fec226456d1bb 100644 --- a/drivers/spi/spi-loongson-core.c +++ b/drivers/spi/spi-loongson-core.c @@ -227,7 +227,7 @@ int loongson_spi_init_controller(struct device *dev, void __iomem *regs) return devm_spi_register_controller(dev, controller); } -EXPORT_SYMBOL_NS_GPL(loongson_spi_init_controller, SPI_LOONGSON_CORE); +EXPORT_SYMBOL_NS_GPL(loongson_spi_init_controller, "SPI_LOONGSON_CORE"); static int __maybe_unused loongson_spi_suspend(struct device *dev) { @@ -273,7 +273,7 @@ const struct dev_pm_ops loongson_spi_dev_pm_ops = { .suspend = loongson_spi_suspend, .resume = loongson_spi_resume, }; -EXPORT_SYMBOL_NS_GPL(loongson_spi_dev_pm_ops, SPI_LOONGSON_CORE); +EXPORT_SYMBOL_NS_GPL(loongson_spi_dev_pm_ops, "SPI_LOONGSON_CORE"); MODULE_DESCRIPTION("Loongson SPI core driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-loongson-pci.c b/drivers/spi/spi-loongson-pci.c index 134cda0c13a5cd..cbcde153260e77 100644 --- a/drivers/spi/spi-loongson-pci.c +++ b/drivers/spi/spi-loongson-pci.c @@ -19,12 +19,11 @@ static int loongson_spi_pci_register(struct pci_dev *pdev, if (ret < 0) return dev_err_probe(dev, ret, "cannot enable pci device\n"); - ret = pcim_iomap_regions(pdev, BIT(pci_bar), pci_name(pdev)); + reg_base = pcim_iomap_region(pdev, pci_bar, pci_name(pdev)); + ret = PTR_ERR_OR_ZERO(reg_base); if (ret) return dev_err_probe(dev, ret, "failed to request and remap memory\n"); - reg_base = pcim_iomap_table(pdev)[pci_bar]; - ret = loongson_spi_init_controller(dev, reg_base); if (ret) return dev_err_probe(dev, ret, "failed to initialize controller\n"); @@ -52,4 +51,4 @@ module_pci_driver(loongson_spi_pci_driver); MODULE_DESCRIPTION("Loongson spi pci driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SPI_LOONGSON_CORE); +MODULE_IMPORT_NS("SPI_LOONGSON_CORE"); diff --git a/drivers/spi/spi-loongson-plat.c b/drivers/spi/spi-loongson-plat.c index c066e5f5891e9a..64a7270f9a642a 100644 --- a/drivers/spi/spi-loongson-plat.c +++ b/drivers/spi/spi-loongson-plat.c @@ -44,4 +44,4 @@ module_platform_driver(loongson_spi_plat_driver); MODULE_DESCRIPTION("Loongson spi platform driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SPI_LOONGSON_CORE); +MODULE_IMPORT_NS("SPI_LOONGSON_CORE"); diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 17b8baf749e6aa..abc6792e738c73 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -172,6 +172,9 @@ bool spi_mem_default_supports_op(struct spi_mem *mem, if (!spi_mem_controller_is_capable(ctlr, dtr)) return false; + if (op->data.swap16 && !spi_mem_controller_is_capable(ctlr, swap16)) + return false; + if (op->cmd.nbytes != 2) return false; } else { diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index 1d05590a743469..df74ad5060f85a 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -949,7 +949,7 @@ MODULE_DEVICE_TABLE(of, meson_spicc_of_match); static struct platform_driver meson_spicc_driver = { .probe = meson_spicc_probe, - .remove_new = meson_spicc_remove, + .remove = meson_spicc_remove, .driver = { .name = "meson-spicc", .of_match_table = of_match_ptr(meson_spicc_of_match), diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index fd8b26dd4a792a..ef7efeaeee97ee 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -429,7 +429,7 @@ MODULE_DEVICE_TABLE(of, meson_spifc_dt_match); static struct platform_driver meson_spifc_driver = { .probe = meson_spifc_probe, - .remove_new = meson_spifc_remove, + .remove = meson_spifc_remove, .driver = { .name = "meson-spifc", .of_match_table = of_match_ptr(meson_spifc_dt_match), diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c index 09f16471c53757..ad2b5ffa615343 100644 --- a/drivers/spi/spi-microchip-core-qspi.c +++ b/drivers/spi/spi-microchip-core-qspi.c @@ -575,7 +575,7 @@ static struct platform_driver mchp_coreqspi_driver = { .name = "microchip,coreqspi", .of_match_table = mchp_coreqspi_of_match, }, - .remove_new = mchp_coreqspi_remove, + .remove = mchp_coreqspi_remove, }; module_platform_driver(mchp_coreqspi_driver); diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c index 7c1a9a9853733e..5b6af55855efc4 100644 --- a/drivers/spi/spi-microchip-core.c +++ b/drivers/spi/spi-microchip-core.c @@ -622,7 +622,7 @@ static struct platform_driver mchp_corespi_driver = { .pm = MICROCHIP_SPI_PM_OPS, .of_match_table = of_match_ptr(mchp_corespi_dt_ids), }, - .remove_new = mchp_corespi_remove, + .remove = mchp_corespi_remove, }; module_platform_driver(mchp_corespi_driver); MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver"); diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index 28f06122edac56..3bbeb8d5bfb8e4 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -107,7 +107,7 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, struct mpc52xx_psc_spi *mps = spi_controller_get_devdata(spi->controller); struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo; - unsigned rb = 0; /* number of bytes receieved */ + unsigned rb = 0; /* number of bytes received */ unsigned sb = 0; /* number of bytes sent */ unsigned char *rx_buf = (unsigned char *)t->rx_buf; unsigned char *tx_buf = (unsigned char *)t->tx_buf; @@ -325,7 +325,7 @@ static int mpc52xx_psc_spi_of_probe(struct platform_device *pdev) if (IS_ERR(mps->psc)) return dev_err_probe(dev, PTR_ERR(mps->psc), "could not ioremap I/O port range\n"); - /* On the 5200, fifo regs are immediately ajacent to the psc regs */ + /* On the 5200, fifo regs are immediately adjacent to the psc regs */ mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc); mps->irq = platform_get_irq(pdev, 0); diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index d5ac60c135c20a..6d4dde15ac5451 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -520,6 +520,7 @@ static void mpc52xx_spi_remove(struct platform_device *op) struct mpc52xx_spi *ms = spi_controller_get_devdata(host); int i; + cancel_work_sync(&ms->work); free_irq(ms->irq0, ms); free_irq(ms->irq1, ms); @@ -544,6 +545,6 @@ static struct platform_driver mpc52xx_spi_of_driver = { .of_match_table = mpc52xx_spi_match, }, .probe = mpc52xx_spi_probe, - .remove_new = mpc52xx_spi_remove, + .remove = mpc52xx_spi_remove, }; module_platform_driver(mpc52xx_spi_of_driver); diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index dfee244fc3173c..85f3bafc975dbc 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -1432,7 +1432,7 @@ static struct platform_driver mtk_spi_driver = { .of_match_table = mtk_spi_of_match, }, .probe = mtk_spi_probe, - .remove_new = mtk_spi_remove, + .remove = mtk_spi_remove, }; module_platform_driver(mtk_spi_driver); diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 62b1c8995fa46b..85ab5ce96c4df8 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -998,7 +998,7 @@ static struct platform_driver mtk_nor_driver = { .pm = &mtk_nor_pm_ops, }, .probe = mtk_nor_probe, - .remove_new = mtk_nor_remove, + .remove = mtk_nor_remove, }; module_platform_driver(mtk_nor_driver); diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c index c5677fd94e5e14..fdbea9dffb62ca 100644 --- a/drivers/spi/spi-mtk-snfi.c +++ b/drivers/spi/spi-mtk-snfi.c @@ -776,7 +776,7 @@ static int mtk_snand_ecc_finish_io_req(struct nand_device *nand, return snf->ecc_stats.failed ? -EBADMSG : snf->ecc_stats.bitflips; } -static struct nand_ecc_engine_ops mtk_snfi_ecc_engine_ops = { +static const struct nand_ecc_engine_ops mtk_snfi_ecc_engine_ops = { .init_ctx = mtk_snand_ecc_init_ctx, .cleanup_ctx = mtk_snand_ecc_cleanup_ctx, .prepare_io_req = mtk_snand_ecc_prepare_io_req, @@ -1477,7 +1477,7 @@ static void mtk_snand_remove(struct platform_device *pdev) static struct platform_driver mtk_snand_driver = { .probe = mtk_snand_probe, - .remove_new = mtk_snand_remove, + .remove = mtk_snand_remove, .driver = { .name = "mtk-snand", .of_match_table = mtk_snand_ids, diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 6156d691630a56..809767d3145c17 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -294,7 +294,8 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic) mxic->regs + HC_CFG); } -static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags) +static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags, + bool swap16) { int nio = 1; @@ -305,6 +306,11 @@ static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags) else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL)) nio = 2; + if (swap16) + flags &= ~HC_CFG_DATA_PASS; + else + flags |= HC_CFG_DATA_PASS; + return flags | HC_CFG_NIO(nio) | HC_CFG_TYPE(spi_get_chipselect(spi, 0), HC_CFG_TYPE_SPI_NOR) | HC_CFG_SLV_ACT(spi_get_chipselect(spi, 0)) | HC_CFG_IDLE_SIO_LVL(1); @@ -397,7 +403,8 @@ static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) return -EINVAL; - writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG); + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16), + mxic->regs + HC_CFG); writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), mxic->regs + LRD_CFG); @@ -441,7 +448,8 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) return -EINVAL; - writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG); + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16), + mxic->regs + HC_CFG); writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), mxic->regs + LWR_CFG); @@ -518,7 +526,7 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, if (ret) return ret; - writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN), + writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN, op->data.swap16), mxic->regs + HC_CFG); writel(HC_EN_BIT, mxic->regs + HC_EN); @@ -573,6 +581,7 @@ static const struct spi_controller_mem_ops mxic_spi_mem_ops = { static const struct spi_controller_mem_caps mxic_spi_mem_caps = { .dtr = true, .ecc = true, + .swap16 = true, }; static void mxic_spi_set_cs(struct spi_device *spi, bool lvl) @@ -640,7 +649,7 @@ static int mxic_spi_transfer_one(struct spi_controller *host, /* ECC wrapper */ static int mxic_spi_mem_ecc_init_ctx(struct nand_device *nand) { - struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops(); + const struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops(); struct mxic_spi *mxic = nand->ecc.engine->priv; mxic->ecc.use_pipelined_conf = true; @@ -650,7 +659,7 @@ static int mxic_spi_mem_ecc_init_ctx(struct nand_device *nand) static void mxic_spi_mem_ecc_cleanup_ctx(struct nand_device *nand) { - struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops(); + const struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops(); struct mxic_spi *mxic = nand->ecc.engine->priv; mxic->ecc.use_pipelined_conf = false; @@ -661,7 +670,7 @@ static void mxic_spi_mem_ecc_cleanup_ctx(struct nand_device *nand) static int mxic_spi_mem_ecc_prepare_io_req(struct nand_device *nand, struct nand_page_io_req *req) { - struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops(); + const struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops(); return ops->prepare_io_req(nand, req); } @@ -669,12 +678,12 @@ static int mxic_spi_mem_ecc_prepare_io_req(struct nand_device *nand, static int mxic_spi_mem_ecc_finish_io_req(struct nand_device *nand, struct nand_page_io_req *req) { - struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops(); + const struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops(); return ops->finish_io_req(nand, req); } -static struct nand_ecc_engine_ops mxic_spi_mem_ecc_engine_pipelined_ops = { +static const struct nand_ecc_engine_ops mxic_spi_mem_ecc_engine_pipelined_ops = { .init_ctx = mxic_spi_mem_ecc_init_ctx, .cleanup_ctx = mxic_spi_mem_ecc_cleanup_ctx, .prepare_io_req = mxic_spi_mem_ecc_prepare_io_req, @@ -836,7 +845,7 @@ MODULE_DEVICE_TABLE(of, mxic_spi_of_ids); static struct platform_driver mxic_spi_driver = { .probe = mxic_spi_probe, - .remove_new = mxic_spi_remove, + .remove = mxic_spi_remove, .driver = { .name = "mxic-spi", .of_match_table = mxic_spi_of_ids, diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 3e341d1ff3b63b..e6d955d964f4b5 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -657,7 +657,7 @@ static void mxs_spi_remove(struct platform_device *pdev) static struct platform_driver mxs_spi_driver = { .probe = mxs_spi_probe, - .remove_new = mxs_spi_remove, + .remove = mxs_spi_remove, .driver = { .name = DRIVER_NAME, .of_match_table = mxs_spi_dt_ids, diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index f3bb8bbc192f29..958bab27a08130 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -766,12 +766,12 @@ MODULE_DEVICE_TABLE(of, npcm_fiu_dt_ids); static struct platform_driver npcm_fiu_driver = { .driver = { - .name = "NPCM-FIU", - .bus = &platform_bus_type, + .name = "NPCM-FIU", + .bus = &platform_bus_type, .of_match_table = npcm_fiu_dt_ids, }, - .probe = npcm_fiu_probe, - .remove_new = npcm_fiu_remove, + .probe = npcm_fiu_probe, + .remove = npcm_fiu_remove, }; module_platform_driver(npcm_fiu_driver); diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c index 30aa37b0c3b82f..98b6479b961cae 100644 --- a/drivers/spi/spi-npcm-pspi.c +++ b/drivers/spi/spi-npcm-pspi.c @@ -452,7 +452,7 @@ static struct platform_driver npcm_pspi_driver = { .of_match_table = npcm_pspi_match, }, .probe = npcm_pspi_probe, - .remove_new = npcm_pspi_remove, + .remove = npcm_pspi_remove, }; module_platform_driver(npcm_pspi_driver); diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 5a1e55a01c5210..1161b9e5a4dce6 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -1331,7 +1331,7 @@ static struct platform_driver nxp_fspi_driver = { .pm = &nxp_fspi_pm_ops, }, .probe = nxp_fspi_probe, - .remove_new = nxp_fspi_remove, + .remove = nxp_fspi_remove, }; module_platform_driver(nxp_fspi_driver); diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 7d8c5cd680d1d9..cba22992035731 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE(of, tiny_spi_match); static struct platform_driver tiny_spi_driver = { .probe = tiny_spi_probe, - .remove_new = tiny_spi_remove, + .remove = tiny_spi_remove, .driver = { .name = DRV_NAME, .pm = NULL, diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 03b820e856511a..b9a91dbfeaef82 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -523,7 +523,7 @@ static struct platform_driver uwire_driver = { .name = "omap_uwire", }, .probe = uwire_probe, - .remove_new = uwire_remove, + .remove = uwire_remove, // suspend ... unuse ck // resume ... use ck }; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 2c043817c66a88..add6247d348190 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1561,10 +1561,10 @@ static int omap2_mcspi_probe(struct platform_device *pdev) } mcspi->ref_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); - if (mcspi->ref_clk) - mcspi->ref_clk_hz = clk_get_rate(mcspi->ref_clk); - else + if (IS_ERR(mcspi->ref_clk)) mcspi->ref_clk_hz = OMAP2_MCSPI_MAX_FREQ; + else + mcspi->ref_clk_hz = clk_get_rate(mcspi->ref_clk); ctlr->max_speed_hz = mcspi->ref_clk_hz; ctlr->min_speed_hz = mcspi->ref_clk_hz >> 15; @@ -1654,7 +1654,7 @@ static struct platform_driver omap2_mcspi_driver = { .of_match_table = omap_mcspi_of_match, }, .probe = omap2_mcspi_probe, - .remove_new = omap2_mcspi_remove, + .remove = omap2_mcspi_remove, }; module_platform_driver(omap2_mcspi_driver); diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 4730e4ba890101..43bd9f21137f95 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -846,7 +846,7 @@ static struct platform_driver orion_spi_driver = { .of_match_table = of_match_ptr(orion_spi_of_match_table), }, .probe = orion_spi_probe, - .remove_new = orion_spi_remove, + .remove = orion_spi_remove, }; module_platform_driver(orion_spi_driver); diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index 0031063a7e254c..fa0c1ee84532cd 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -226,7 +226,7 @@ static irqreturn_t pic32_sqi_isr(int irq, void *dev_id) if (status & PESQI_PKTCOMP) { /* mask all interrupts */ enable = 0; - /* complete trasaction */ + /* complete transaction */ complete(&sqi->xfer_done); } @@ -682,7 +682,7 @@ static struct platform_driver pic32_sqi_driver = { .of_match_table = of_match_ptr(pic32_sqi_of_ids), }, .probe = pic32_sqi_probe, - .remove_new = pic32_sqi_remove, + .remove = pic32_sqi_remove, }; module_platform_driver(pic32_sqi_driver); diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index b8bcc220e96d61..369850d1431367 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -859,7 +859,7 @@ static struct platform_driver pic32_spi_driver = { .of_match_table = of_match_ptr(pic32_spi_of_match), }, .probe = pic32_spi_probe, - .remove_new = pic32_spi_remove, + .remove = pic32_spi_remove, }; module_platform_driver(pic32_spi_driver); diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index de63cf0557cec7..dd87cf4f70dd56 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -899,7 +899,7 @@ static int configure_dma(struct pl022 *pl022) break; } - /* SPI pecularity: we need to read and write the same width */ + /* SPI peculiarity: we need to read and write the same width */ if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) rx_conf.src_addr_width = tx_conf.dst_addr_width; if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 4a64ea0f596f9a..688cabcfbc5266 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -484,7 +484,7 @@ MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match); static struct platform_driver spi_ppc4xx_of_driver = { .probe = spi_ppc4xx_of_probe, - .remove_new = spi_ppc4xx_of_remove, + .remove = spi_ppc4xx_of_remove, .driver = { .name = DRIVER_NAME, .of_match_table = spi_ppc4xx_of_match, diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index cc8dcf782399e9..cae77ac1852061 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -273,10 +273,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, if (ret) return ret; - ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI"); - if (ret) - return ret; - pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; @@ -284,7 +280,9 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ssp = &pdata->ssp; ssp->dev = &dev->dev; ssp->phys_base = pci_resource_start(dev, 0); - ssp->mmio_base = pcim_iomap_table(dev)[0]; + ssp->mmio_base = pcim_iomap_region(dev, 0, "PXA2xx SPI"); + if (IS_ERR(ssp->mmio_base)) + return PTR_ERR(ssp->mmio_base); info = (struct pxa_spi_info *)ent->driver_data; ret = info->setup(dev, pdata); @@ -348,5 +346,5 @@ module_pci_driver(pxa2xx_spi_pci_driver); MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SPI_PXA2xx); +MODULE_IMPORT_NS("SPI_PXA2xx"); MODULE_AUTHOR("Sebastian Andrzej Siewior "); diff --git a/drivers/spi/spi-pxa2xx-platform.c b/drivers/spi/spi-pxa2xx-platform.c index 595af9fa4e0f89..45e159e75a521f 100644 --- a/drivers/spi/spi-pxa2xx-platform.c +++ b/drivers/spi/spi-pxa2xx-platform.c @@ -207,7 +207,7 @@ static struct platform_driver driver = { .of_match_table = pxa2xx_spi_of_match, }, .probe = pxa2xx_spi_platform_probe, - .remove_new = pxa2xx_spi_platform_remove, + .remove = pxa2xx_spi_platform_remove, }; static int __init pxa2xx_spi_init(void) @@ -225,6 +225,6 @@ module_exit(pxa2xx_spi_exit); MODULE_AUTHOR("Stephen Street"); MODULE_DESCRIPTION("PXA2xx SSP SPI Controller platform driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SPI_PXA2xx); +MODULE_IMPORT_NS("SPI_PXA2xx"); MODULE_ALIAS("platform:pxa2xx-spi"); MODULE_SOFTDEP("pre: dw_dmac"); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index bf1f34b0ffc8eb..903d761452725c 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1468,7 +1468,7 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp, return status; } -EXPORT_SYMBOL_NS_GPL(pxa2xx_spi_probe, SPI_PXA2xx); +EXPORT_SYMBOL_NS_GPL(pxa2xx_spi_probe, "SPI_PXA2xx"); void pxa2xx_spi_remove(struct device *dev) { @@ -1488,7 +1488,7 @@ void pxa2xx_spi_remove(struct device *dev) /* Release IRQ */ free_irq(ssp->irq, drv_data); } -EXPORT_SYMBOL_NS_GPL(pxa2xx_spi_remove, SPI_PXA2xx); +EXPORT_SYMBOL_NS_GPL(pxa2xx_spi_remove, "SPI_PXA2xx"); static int pxa2xx_spi_suspend(struct device *dev) { diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c index 49b77513448519..3aeddada58e1c3 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -771,7 +771,7 @@ static int qcom_qspi_probe(struct platform_device *pdev) host->prepare_message = qcom_qspi_prepare_message; host->transfer_one = qcom_qspi_transfer_one; host->handle_err = qcom_qspi_handle_err; - if (of_property_read_bool(pdev->dev.of_node, "iommus")) + if (of_property_present(pdev->dev.of_node, "iommus")) host->can_dma = qcom_qspi_can_dma; host->auto_runtime_pm = true; host->mem_ops = &qcom_qspi_mem_ops; @@ -908,7 +908,7 @@ static struct platform_driver qcom_qspi_driver = { .of_match_table = qcom_qspi_dt_match, }, .probe = qcom_qspi_probe, - .remove_new = qcom_qspi_remove, + .remove = qcom_qspi_remove, }; module_platform_driver(qcom_qspi_driver); diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 1a2f9cd92b3c2d..7d647edf6bc31c 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -1364,7 +1364,7 @@ static struct platform_driver spi_qup_driver = { .of_match_table = spi_qup_dt_match, }, .probe = spi_qup_probe, - .remove_new = spi_qup_remove, + .remove = spi_qup_remove, }; module_platform_driver(spi_qup_driver); diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c index 225f7555078028..e71d3805b150de 100644 --- a/drivers/spi/spi-rb4xx.c +++ b/drivers/spi/spi-rb4xx.c @@ -196,7 +196,7 @@ MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match); static struct platform_driver rb4xx_spi_drv = { .probe = rb4xx_spi_probe, - .remove_new = rb4xx_spi_remove, + .remove = rb4xx_spi_remove, .driver = { .name = "rb4xx-spi", .of_match_table = of_match_ptr(rb4xx_spi_dt_match), diff --git a/drivers/spi/spi-realtek-rtl-snand.c b/drivers/spi/spi-realtek-rtl-snand.c new file mode 100644 index 00000000000000..cd0484041147f6 --- /dev/null +++ b/drivers/spi/spi-realtek-rtl-snand.c @@ -0,0 +1,419 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SNAFCFR 0x00 +#define SNAFCFR_DMA_IE BIT(20) +#define SNAFCCR 0x04 +#define SNAFWCMR 0x08 +#define SNAFRCMR 0x0c +#define SNAFRDR 0x10 +#define SNAFWDR 0x14 +#define SNAFDTR 0x18 +#define SNAFDRSAR 0x1c +#define SNAFDIR 0x20 +#define SNAFDIR_DMA_IP BIT(0) +#define SNAFDLR 0x24 +#define SNAFSR 0x40 +#define SNAFSR_NFCOS BIT(3) +#define SNAFSR_NFDRS BIT(2) +#define SNAFSR_NFDWS BIT(1) + +#define CMR_LEN(len) ((len) - 1) +#define CMR_WID(width) (((width) >> 1) << 28) + +struct rtl_snand { + struct device *dev; + struct regmap *regmap; + struct completion comp; +}; + +static irqreturn_t rtl_snand_irq(int irq, void *data) +{ + struct rtl_snand *snand = data; + u32 val = 0; + + regmap_read(snand->regmap, SNAFSR, &val); + if (val & (SNAFSR_NFCOS | SNAFSR_NFDRS | SNAFSR_NFDWS)) + return IRQ_NONE; + + regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP); + complete(&snand->comp); + + return IRQ_HANDLED; +} + +static bool rtl_snand_supports_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(mem, op)) + return false; + if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1) + return false; + return true; +} + +static void rtl_snand_set_cs(struct rtl_snand *snand, int cs, bool active) +{ + u32 val; + + if (active) + val = ~(1 << (4 * cs)); + else + val = ~0; + + regmap_write(snand->regmap, SNAFCCR, val); +} + +static int rtl_snand_wait_ready(struct rtl_snand *snand) +{ + u32 val; + + return regmap_read_poll_timeout(snand->regmap, SNAFSR, val, !(val & SNAFSR_NFCOS), + 0, 2 * USEC_PER_MSEC); +} + +static int rtl_snand_xfer_head(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) +{ + int ret; + u32 val, len = 0; + + rtl_snand_set_cs(snand, cs, true); + + val = op->cmd.opcode << 24; + len = 1; + if (op->addr.nbytes && op->addr.buswidth == 1) { + val |= op->addr.val << ((3 - op->addr.nbytes) * 8); + len += op->addr.nbytes; + } + + ret = rtl_snand_wait_ready(snand); + if (ret) + return ret; + + ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(len)); + if (ret) + return ret; + + ret = regmap_write(snand->regmap, SNAFWDR, val); + if (ret) + return ret; + + ret = rtl_snand_wait_ready(snand); + if (ret) + return ret; + + if (op->addr.buswidth > 1) { + val = op->addr.val << ((3 - op->addr.nbytes) * 8); + len = op->addr.nbytes; + + ret = regmap_write(snand->regmap, SNAFWCMR, + CMR_WID(op->addr.buswidth) | CMR_LEN(len)); + if (ret) + return ret; + + ret = regmap_write(snand->regmap, SNAFWDR, val); + if (ret) + return ret; + + ret = rtl_snand_wait_ready(snand); + if (ret) + return ret; + } + + if (op->dummy.nbytes) { + val = 0; + + ret = regmap_write(snand->regmap, SNAFWCMR, + CMR_WID(op->dummy.buswidth) | CMR_LEN(op->dummy.nbytes)); + if (ret) + return ret; + + ret = regmap_write(snand->regmap, SNAFWDR, val); + if (ret) + return ret; + + ret = rtl_snand_wait_ready(snand); + if (ret) + return ret; + } + + return 0; +} + +static void rtl_snand_xfer_tail(struct rtl_snand *snand, int cs) +{ + rtl_snand_set_cs(snand, cs, false); +} + +static int rtl_snand_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) +{ + unsigned int pos, nbytes; + int ret; + u32 val, len = 0; + + ret = rtl_snand_xfer_head(snand, cs, op); + if (ret) + goto out_deselect; + + if (op->data.dir == SPI_MEM_DATA_IN) { + pos = 0; + len = op->data.nbytes; + + while (pos < len) { + nbytes = len - pos; + if (nbytes > 4) + nbytes = 4; + + ret = rtl_snand_wait_ready(snand); + if (ret) + goto out_deselect; + + ret = regmap_write(snand->regmap, SNAFRCMR, + CMR_WID(op->data.buswidth) | CMR_LEN(nbytes)); + if (ret) + goto out_deselect; + + ret = rtl_snand_wait_ready(snand); + if (ret) + goto out_deselect; + + ret = regmap_read(snand->regmap, SNAFRDR, &val); + if (ret) + goto out_deselect; + + memcpy(op->data.buf.in + pos, &val, nbytes); + + pos += nbytes; + } + } else if (op->data.dir == SPI_MEM_DATA_OUT) { + pos = 0; + len = op->data.nbytes; + + while (pos < len) { + nbytes = len - pos; + if (nbytes > 4) + nbytes = 4; + + memcpy(&val, op->data.buf.out + pos, nbytes); + + pos += nbytes; + + ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(nbytes)); + if (ret) + goto out_deselect; + + ret = regmap_write(snand->regmap, SNAFWDR, val); + if (ret) + goto out_deselect; + + ret = rtl_snand_wait_ready(snand); + if (ret) + goto out_deselect; + } + } + +out_deselect: + rtl_snand_xfer_tail(snand, cs); + + if (ret) + dev_err(snand->dev, "transfer failed %d\n", ret); + + return ret; +} + +static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) +{ + unsigned int pos, nbytes; + int ret; + dma_addr_t buf_dma; + enum dma_data_direction dir; + u32 trig, len, maxlen; + + ret = rtl_snand_xfer_head(snand, cs, op); + if (ret) + goto out_deselect; + + if (op->data.dir == SPI_MEM_DATA_IN) { + maxlen = 2080; + dir = DMA_FROM_DEVICE; + trig = 0; + } else if (op->data.dir == SPI_MEM_DATA_OUT) { + maxlen = 520; + dir = DMA_TO_DEVICE; + trig = 1; + } else { + ret = -EOPNOTSUPP; + goto out_deselect; + } + + buf_dma = dma_map_single(snand->dev, op->data.buf.in, op->data.nbytes, dir); + ret = dma_mapping_error(snand->dev, buf_dma); + if (ret) + goto out_deselect; + + ret = regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP); + if (ret) + goto out_unmap; + + ret = regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, SNAFCFR_DMA_IE); + if (ret) + goto out_unmap; + + pos = 0; + len = op->data.nbytes; + + while (pos < len) { + nbytes = len - pos; + if (nbytes > maxlen) + nbytes = maxlen; + + reinit_completion(&snand->comp); + + ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma + pos); + if (ret) + goto out_disable_int; + + pos += nbytes; + + ret = regmap_write(snand->regmap, SNAFDLR, + CMR_WID(op->data.buswidth) | nbytes); + if (ret) + goto out_disable_int; + + ret = regmap_write(snand->regmap, SNAFDTR, trig); + if (ret) + goto out_disable_int; + + if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000))) + ret = -ETIMEDOUT; + + if (ret) + goto out_disable_int; + } + +out_disable_int: + regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0); +out_unmap: + dma_unmap_single(snand->dev, buf_dma, op->data.nbytes, dir); +out_deselect: + rtl_snand_xfer_tail(snand, cs); + + if (ret) + dev_err(snand->dev, "transfer failed %d\n", ret); + + return ret; +} + +static bool rtl_snand_dma_op(const struct spi_mem_op *op) +{ + switch (op->data.dir) { + case SPI_MEM_DATA_IN: + case SPI_MEM_DATA_OUT: + return op->data.nbytes > 32; + default: + return false; + } +} + +static int rtl_snand_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct rtl_snand *snand = spi_controller_get_devdata(mem->spi->controller); + int cs = spi_get_chipselect(mem->spi, 0); + + dev_dbg(snand->dev, "cs %d op cmd %02x %d:%d, dummy %d:%d, addr %08llx@%d:%d, data %d:%d\n", + cs, op->cmd.opcode, + op->cmd.buswidth, op->cmd.nbytes, op->dummy.buswidth, + op->dummy.nbytes, op->addr.val, op->addr.buswidth, + op->addr.nbytes, op->data.buswidth, op->data.nbytes); + + if (rtl_snand_dma_op(op)) + return rtl_snand_dma_xfer(snand, cs, op); + else + return rtl_snand_xfer(snand, cs, op); +} + +static const struct spi_controller_mem_ops rtl_snand_mem_ops = { + .supports_op = rtl_snand_supports_op, + .exec_op = rtl_snand_exec_op, +}; + +static const struct of_device_id rtl_snand_match[] = { + { .compatible = "realtek,rtl9301-snand" }, + { .compatible = "realtek,rtl9302b-snand" }, + { .compatible = "realtek,rtl9302c-snand" }, + { .compatible = "realtek,rtl9303-snand" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rtl_snand_match); + +static int rtl_snand_probe(struct platform_device *pdev) +{ + struct rtl_snand *snand; + struct device *dev = &pdev->dev; + struct spi_controller *ctrl; + void __iomem *base; + const struct regmap_config rc = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .cache_type = REGCACHE_NONE, + }; + int irq, ret; + + ctrl = devm_spi_alloc_host(dev, sizeof(*snand)); + if (!ctrl) + return -ENOMEM; + + snand = spi_controller_get_devdata(ctrl); + snand->dev = dev; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + snand->regmap = devm_regmap_init_mmio(dev, base, &rc); + if (IS_ERR(snand->regmap)) + return PTR_ERR(snand->regmap); + + init_completion(&snand->comp); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = dma_set_mask(snand->dev, DMA_BIT_MASK(32)); + if (ret) + return dev_err_probe(dev, ret, "failed to set DMA mask\n"); + + ret = devm_request_irq(dev, irq, rtl_snand_irq, 0, "rtl-snand", snand); + if (ret) + return dev_err_probe(dev, ret, "failed to request irq\n"); + + ctrl->num_chipselect = 2; + ctrl->mem_ops = &rtl_snand_mem_ops; + ctrl->bits_per_word_mask = SPI_BPW_MASK(8); + ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; + device_set_node(&ctrl->dev, dev_fwnode(dev)); + + return devm_spi_register_controller(dev, ctrl); +} + +static struct platform_driver rtl_snand_driver = { + .driver = { + .name = "realtek-rtl-snand", + .of_match_table = rtl_snand_match, + }, + .probe = rtl_snand_probe, +}; +module_platform_driver(rtl_snand_driver); + +MODULE_DESCRIPTION("Realtek SPI-NAND Flash Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 0d7fadcd4ed32a..70bbb459caa4f5 100644 --- a/drivers/spi/spi-rockchip-sfc.c +++ b/drivers/spi/spi-rockchip-sfc.c @@ -111,7 +111,7 @@ #define SFC_VER_4 0x4 #define SFC_VER_5 0x5 -/* Delay line controller resiter */ +/* Delay line controller register */ #define SFC_DLL_CTRL0 0x3C #define SFC_DLL_CTRL0_SCLK_SMP_DLL BIT(15) #define SFC_DLL_CTRL0_DLL_MAX_VER4 0xFFU @@ -182,6 +182,7 @@ struct rockchip_sfc { bool use_dma; u32 max_iosize; u16 version; + struct spi_controller *host; }; static int rockchip_sfc_reset(struct rockchip_sfc *sfc) @@ -503,7 +504,7 @@ static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op rockchip_sfc_adjust_op_work((struct spi_mem_op *)op); rockchip_sfc_xfer_setup(sfc, mem, op, len); if (len) { - if (likely(sfc->use_dma) && len >= SFC_DMA_TRANS_THRETHOLD) { + if (likely(sfc->use_dma) && len >= SFC_DMA_TRANS_THRETHOLD && !(len & 0x3)) { init_completion(&sfc->cp); rockchip_sfc_irq_unmask(sfc, SFC_IMR_DMA); ret = rockchip_sfc_xfer_data_dma(sfc, op, len); @@ -574,25 +575,23 @@ static int rockchip_sfc_probe(struct platform_device *pdev) sfc = spi_controller_get_devdata(host); sfc->dev = dev; + sfc->host = host; sfc->regbase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sfc->regbase)) return PTR_ERR(sfc->regbase); sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc"); - if (IS_ERR(sfc->clk)) { - dev_err(&pdev->dev, "Failed to get sfc interface clk\n"); - return PTR_ERR(sfc->clk); - } + if (IS_ERR(sfc->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sfc->clk), + "Failed to get sfc interface clk\n"); sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc"); - if (IS_ERR(sfc->hclk)) { - dev_err(&pdev->dev, "Failed to get sfc ahb clk\n"); - return PTR_ERR(sfc->hclk); - } + if (IS_ERR(sfc->hclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(sfc->hclk), + "Failed to get sfc ahb clk\n"); - sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, - "rockchip,sfc-no-dma"); + sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, "rockchip,sfc-no-dma"); if (sfc->use_dma) { ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); @@ -602,8 +601,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev) } sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_IOSIZE_VER3, - &sfc->dma_buffer, - GFP_KERNEL); + &sfc->dma_buffer, GFP_KERNEL); if (!sfc->buffer) return -ENOMEM; } @@ -629,7 +627,6 @@ static int rockchip_sfc_probe(struct platform_device *pdev) 0, pdev->name, sfc); if (ret) { dev_err(dev, "Failed to request irq\n"); - goto err_irq; } @@ -656,8 +653,8 @@ static int rockchip_sfc_probe(struct platform_device *pdev) static void rockchip_sfc_remove(struct platform_device *pdev) { - struct spi_controller *host = platform_get_drvdata(pdev); struct rockchip_sfc *sfc = platform_get_drvdata(pdev); + struct spi_controller *host = sfc->host; spi_unregister_controller(host); @@ -677,7 +674,7 @@ static struct platform_driver rockchip_sfc_driver = { .of_match_table = rockchip_sfc_dt_ids, }, .probe = rockchip_sfc_probe, - .remove_new = rockchip_sfc_remove, + .remove = rockchip_sfc_remove, }; module_platform_driver(rockchip_sfc_driver); diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0bb33c43b1b46e..1bc012fce7cb8d 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -192,7 +192,7 @@ struct rockchip_spi { u8 rsd; bool target_abort; - bool cs_inactive; /* spi target tansmition stop when cs inactive */ + bool cs_inactive; /* spi target transmission stop when cs inactive */ bool cs_high_supported; /* native CS supports active-high polarity */ struct spi_transfer *xfer; /* Store xfer temporarily */ @@ -241,6 +241,20 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) struct spi_controller *ctlr = spi->controller; struct rockchip_spi *rs = spi_controller_get_devdata(ctlr); bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable; + bool cs_actual; + + /* + * SPI subsystem tries to avoid no-op calls that would break the PM + * refcount below. It can't however for the first time it is used. + * To detect this case we read it here and bail out early for no-ops. + */ + if (spi_get_csgpiod(spi, 0)) + cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & 1); + else + cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & + BIT(spi_get_chipselect(spi, 0))); + if (unlikely(cs_actual == cs_asserted)) + return; if (cs_asserted) { /* Keep things powered as long as CS is asserted */ @@ -742,22 +756,20 @@ static int rockchip_spi_setup(struct spi_device *spi) static int rockchip_spi_probe(struct platform_device *pdev) { - int ret; - struct rockchip_spi *rs; + struct device_node *np = pdev->dev.of_node; struct spi_controller *ctlr; + struct rockchip_spi *rs; struct resource *mem; - struct device_node *np = pdev->dev.of_node; u32 rsd_nsecs, num_cs; bool target_mode; + int ret; target_mode = of_property_read_bool(np, "spi-slave"); if (target_mode) - ctlr = spi_alloc_target(&pdev->dev, - sizeof(struct rockchip_spi)); + ctlr = spi_alloc_target(&pdev->dev, sizeof(struct rockchip_spi)); else - ctlr = spi_alloc_host(&pdev->dev, - sizeof(struct rockchip_spi)); + ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rockchip_spi)); if (!ctlr) return -ENOMEM; @@ -769,21 +781,21 @@ static int rockchip_spi_probe(struct platform_device *pdev) /* Get basic io resource and map it */ rs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); if (IS_ERR(rs->regs)) { - ret = PTR_ERR(rs->regs); + ret = PTR_ERR(rs->regs); goto err_put_ctlr; } rs->apb_pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk"); if (IS_ERR(rs->apb_pclk)) { - dev_err(&pdev->dev, "Failed to get apb_pclk\n"); - ret = PTR_ERR(rs->apb_pclk); + ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->apb_pclk), + "Failed to get apb_pclk\n"); goto err_put_ctlr; } rs->spiclk = devm_clk_get_enabled(&pdev->dev, "spiclk"); if (IS_ERR(rs->spiclk)) { - dev_err(&pdev->dev, "Failed to get spi_pclk\n"); - ret = PTR_ERR(rs->spiclk); + ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->spiclk), + "Failed to get spi_pclk\n"); goto err_put_ctlr; } @@ -794,7 +806,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) goto err_put_ctlr; ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL, - IRQF_ONESHOT, dev_name(&pdev->dev), ctlr); + IRQF_ONESHOT, dev_name(&pdev->dev), ctlr); if (ret) goto err_put_ctlr; @@ -804,24 +816,22 @@ static int rockchip_spi_probe(struct platform_device *pdev) if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns", &rsd_nsecs)) { /* rx sample delay is expressed in parent clock cycles (max 3) */ - u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), - 1000000000 >> 8); + u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), 1000000000 >> 8); if (!rsd) { dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n", - rs->freq, rsd_nsecs); + rs->freq, rsd_nsecs); } else if (rsd > CR0_RSD_MAX) { rsd = CR0_RSD_MAX; - dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n", - rs->freq, rsd_nsecs, - CR0_RSD_MAX * 1000000000U / rs->freq); + dev_warn(rs->dev, + "%u Hz are too fast to express %u ns delay, clamping at %u ns\n", + rs->freq, rsd_nsecs, CR0_RSD_MAX * 1000000000U / rs->freq); } rs->rsd = rsd; } rs->fifo_len = get_fifo_len(rs); if (!rs->fifo_len) { - dev_err(&pdev->dev, "Failed to get fifo length\n"); - ret = -EINVAL; + ret = dev_err_probe(&pdev->dev, -EINVAL, "Failed to get fifo length\n"); goto err_put_ctlr; } @@ -861,22 +871,21 @@ static int rockchip_spi_probe(struct platform_device *pdev) ctlr->dma_tx = dma_request_chan(rs->dev, "tx"); if (IS_ERR(ctlr->dma_tx)) { - /* Check tx to see if we need defer probing driver */ - if (PTR_ERR(ctlr->dma_tx) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + /* Check tx to see if we need to defer driver probing */ + ret = dev_warn_probe(rs->dev, PTR_ERR(ctlr->dma_tx), + "Failed to request optional TX DMA channel\n"); + if (ret == -EPROBE_DEFER) goto err_disable_pm_runtime; - } - dev_warn(rs->dev, "Failed to request TX DMA channel\n"); ctlr->dma_tx = NULL; } ctlr->dma_rx = dma_request_chan(rs->dev, "rx"); if (IS_ERR(ctlr->dma_rx)) { - if (PTR_ERR(ctlr->dma_rx) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + /* Check rx to see if we need to defer driver probing */ + ret = dev_warn_probe(rs->dev, PTR_ERR(ctlr->dma_rx), + "Failed to request optional RX DMA channel\n"); + if (ret == -EPROBE_DEFER) goto err_free_dma_tx; - } - dev_warn(rs->dev, "Failed to request RX DMA channel\n"); ctlr->dma_rx = NULL; } @@ -1036,7 +1045,7 @@ static struct platform_driver rockchip_spi_driver = { .of_match_table = of_match_ptr(rockchip_spi_dt_match), }, .probe = rockchip_spi_probe, - .remove_new = rockchip_spi_remove, + .remove = rockchip_spi_remove, }; module_platform_driver(rockchip_spi_driver); diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index c24dad51a0e966..e0c66a24a3cb46 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -206,7 +206,7 @@ MODULE_DEVICE_TABLE(platform, rpc_if_spi_id_table); static struct platform_driver rpcif_spi_driver = { .probe = rpcif_spi_probe, - .remove_new = rpcif_spi_remove, + .remove = rpcif_spi_remove, .id_table = rpc_if_spi_id_table, .driver = { .name = "rpc-if-spi", diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 7f95d22fb1ac65..92faaf614f8ea1 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1427,7 +1427,7 @@ static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume); static struct platform_driver rspi_driver = { .probe = rspi_probe, - .remove_new = rspi_remove, + .remove = rspi_remove, .id_table = spi_driver_ids, .driver = { .name = "renesas_spi", diff --git a/drivers/spi/spi-rzv2m-csi.c b/drivers/spi/spi-rzv2m-csi.c index 741e0f44c49cc3..7c0442883ac08e 100644 --- a/drivers/spi/spi-rzv2m-csi.c +++ b/drivers/spi/spi-rzv2m-csi.c @@ -683,7 +683,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_csi_match); static struct platform_driver rzv2m_csi_drv = { .probe = rzv2m_csi_probe, - .remove_new = rzv2m_csi_remove, + .remove = rzv2m_csi_remove, .driver = { .name = "rzv2m_csi", .of_match_table = rzv2m_csi_match, diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 8c9e5e97041f9c..389275dbc00347 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1353,7 +1353,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - /* Setup Deufult Mode */ + /* Setup Default Mode */ s3c64xx_spi_hwinit(sdd); spin_lock_init(&sdd->lock); @@ -1681,7 +1681,7 @@ static struct platform_driver s3c64xx_spi_driver = { .of_match_table = of_match_ptr(s3c64xx_spi_dt_match), }, .probe = s3c64xx_spi_probe, - .remove_new = s3c64xx_spi_remove, + .remove = s3c64xx_spi_remove, .id_table = s3c64xx_spi_driver_ids, }; MODULE_ALIAS("platform:s3c64xx-spi"); diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 5d63aa1d28e2bc..93017faeb7b554 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -293,7 +293,7 @@ MODULE_DEVICE_TABLE(of, hspi_of_match); static struct platform_driver hspi_driver = { .probe = hspi_probe, - .remove_new = hspi_remove, + .remove = hspi_remove, .driver = { .name = "sh-hspi", .of_match_table = hspi_of_match, diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 3519656515ea12..8a98c313548e37 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1429,7 +1429,7 @@ static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend, static struct platform_driver sh_msiof_spi_drv = { .probe = sh_msiof_spi_probe, - .remove_new = sh_msiof_spi_remove, + .remove = sh_msiof_spi_remove, .id_table = spi_driver_ids, .driver = { .name = "spi_sh_msiof", diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 3d560b154ad36b..f66efaabcacadb 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -183,7 +183,7 @@ static void sh_sci_spi_remove(struct platform_device *dev) static struct platform_driver sh_sci_spi_drv = { .probe = sh_sci_spi_probe, - .remove_new = sh_sci_spi_remove, + .remove = sh_sci_spi_remove, .driver = { .name = "spi_sh_sci", }, diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c index 4b873d9a7602a8..130d7fc452fa83 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -459,7 +459,7 @@ static int spi_sh_probe(struct platform_device *pdev) static struct platform_driver spi_sh_driver = { .probe = spi_sh_probe, - .remove_new = spi_sh_remove, + .remove = spi_sh_remove, .driver = { .name = "sh_spi", }, diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index cfd17bbb220230..87bde2a207a3e8 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -471,7 +471,7 @@ MODULE_DEVICE_TABLE(of, sifive_spi_of_match); static struct platform_driver sifive_spi_driver = { .probe = sifive_spi_probe, - .remove_new = sifive_spi_remove, + .remove = sifive_spi_remove, .driver = { .name = SIFIVE_SPI_DRIVER_NAME, .pm = &sifive_spi_pm_ops, diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c index 4a91b7bae3c68a..e331df9673855f 100644 --- a/drivers/spi/spi-slave-mt27xx.c +++ b/drivers/spi/spi-slave-mt27xx.c @@ -388,9 +388,9 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) int irq, ret; const struct of_device_id *of_id; - ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata)); + ctlr = spi_alloc_target(&pdev->dev, sizeof(*mdata)); if (!ctlr) { - dev_err(&pdev->dev, "failed to alloc spi slave\n"); + dev_err(&pdev->dev, "failed to alloc spi target\n"); return -ENOMEM; } @@ -455,15 +455,13 @@ static int mtk_spi_slave_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); ret = devm_spi_register_controller(&pdev->dev, ctlr); + clk_disable_unprepare(mdata->spi_clk); if (ret) { dev_err(&pdev->dev, "failed to register slave controller(%d)\n", ret); - clk_disable_unprepare(mdata->spi_clk); goto err_disable_runtime_pm; } - clk_disable_unprepare(mdata->spi_clk); - return 0; err_disable_runtime_pm: @@ -558,7 +556,7 @@ static struct platform_driver mtk_spi_slave_driver = { .of_match_table = mtk_spi_slave_of_match, }, .probe = mtk_spi_slave_probe, - .remove_new = mtk_spi_slave_remove, + .remove = mtk_spi_slave_remove, }; module_platform_driver(mtk_spi_slave_driver); diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c index a7c3b3923b4af7..adac645732fedf 100644 --- a/drivers/spi/spi-sn-f-ospi.c +++ b/drivers/spi/spi-sn-f-ospi.c @@ -680,7 +680,7 @@ static struct platform_driver f_ospi_driver = { .of_match_table = f_ospi_dt_ids, }, .probe = f_ospi_probe, - .remove_new = f_ospi_remove, + .remove = f_ospi_remove, }; module_platform_driver(f_ospi_driver); diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c index 831ebae10fe01b..ae794058b38158 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -728,7 +728,7 @@ static int sprd_spi_setup_transfer(struct spi_device *sdev, if (ret) return ret; - /* Set tansfer speed and valid bits */ + /* Set transfer speed and valid bits */ sprd_spi_set_speed(ss, t->speed_hz); sprd_spi_set_transfer_bits(ss, bits_per_word); @@ -1072,7 +1072,7 @@ static struct platform_driver sprd_spi_driver = { .pm = &sprd_spi_pm_ops, }, .probe = sprd_spi_probe, - .remove_new = sprd_spi_remove, + .remove = sprd_spi_remove, }; module_platform_driver(sprd_spi_driver); diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c index e064025e2fd6d0..4cff976ab16fbd 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -449,7 +449,7 @@ static struct platform_driver spi_st_driver = { .of_match_table = of_match_ptr(stm_spi_match), }, .probe = spi_st_probe, - .remove_new = spi_st_remove, + .remove = spi_st_remove, }; module_platform_driver(spi_st_driver); diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 955c920c4b6390..540b6948b24db0 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -963,7 +963,7 @@ MODULE_DEVICE_TABLE(of, stm32_qspi_match); static struct platform_driver stm32_qspi_driver = { .probe = stm32_qspi_probe, - .remove_new = stm32_qspi_remove, + .remove = stm32_qspi_remove, .driver = { .name = "stm32-qspi", .of_match_table = stm32_qspi_match, diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index fc72a89fb3a7b7..da3517d7102dce 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -2356,7 +2356,7 @@ static const struct dev_pm_ops stm32_spi_pm_ops = { static struct platform_driver stm32_spi_driver = { .probe = stm32_spi_probe, - .remove_new = stm32_spi_remove, + .remove = stm32_spi_remove, .driver = { .name = DRIVER_NAME, .pm = &stm32_spi_pm_ops, diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 2ee6755b43f549..fcbe864c9b7d69 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -535,7 +535,7 @@ static const struct dev_pm_ops sun4i_spi_pm_ops = { static struct platform_driver sun4i_spi_driver = { .probe = sun4i_spi_probe, - .remove_new = sun4i_spi_remove, + .remove = sun4i_spi_remove, .driver = { .name = "sun4i-spi", .of_match_table = sun4i_spi_match, diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 5c26bf056293f6..871dfd3e77be28 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -810,7 +810,7 @@ static const struct dev_pm_ops sun6i_spi_pm_ops = { static struct platform_driver sun6i_spi_driver = { .probe = sun6i_spi_probe, - .remove_new = sun6i_spi_remove, + .remove = sun6i_spi_remove, .driver = { .name = "sun6i-spi", .of_match_table = sun6i_spi_match, diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c index 4e481380c259dd..7fd4cc6f74c25e 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -563,7 +563,7 @@ MODULE_DEVICE_TABLE(of, sp7021_spi_controller_ids); static struct platform_driver sp7021_spi_controller_driver = { .probe = sp7021_spi_controller_probe, - .remove_new = sp7021_spi_controller_remove, + .remove = sp7021_spi_controller_remove, .driver = { .name = "sunplus,sp7021-spi-controller", .of_match_table = sp7021_spi_controller_ids, diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c index 7cb4301a6fb285..eaf560487591d9 100644 --- a/drivers/spi/spi-synquacer.c +++ b/drivers/spi/spi-synquacer.c @@ -818,7 +818,7 @@ static struct platform_driver synquacer_spi_driver = { .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids), }, .probe = synquacer_spi_probe, - .remove_new = synquacer_spi_remove, + .remove = synquacer_spi_remove, }; module_platform_driver(synquacer_spi_driver); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index bc7cc4088eea0d..3822d7c8d8edb9 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1518,7 +1518,7 @@ static struct platform_driver tegra_spi_driver = { .of_match_table = tegra_spi_of_match, }, .probe = tegra_spi_probe, - .remove_new = tegra_spi_remove, + .remove = tegra_spi_remove, }; module_platform_driver(tegra_spi_driver); diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 9f6b9f89be5b84..d5c8ee20b8e5b2 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -600,7 +600,7 @@ static struct platform_driver tegra_sflash_driver = { .of_match_table = tegra_sflash_of_match, }, .probe = tegra_sflash_probe, - .remove_new = tegra_sflash_remove, + .remove = tegra_sflash_remove, }; module_platform_driver(tegra_sflash_driver); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index ed1393d159aeec..fe452d03c1ee43 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -542,7 +542,7 @@ static int tegra_slink_start_dma_based_transfer( if (tspi->is_packed) { val |= SLINK_PACKED; tegra_slink_writel(tspi, val, SLINK_DMA_CTL); - /* HW need small delay after settign Packed mode */ + /* HW need small delay after setting Packed mode */ udelay(1); } tspi->dma_control_reg = val; @@ -1214,7 +1214,7 @@ static struct platform_driver tegra_slink_driver = { .of_match_table = tegra_slink_of_match, }, .probe = tegra_slink_probe, - .remove_new = tegra_slink_remove, + .remove = tegra_slink_remove, }; module_platform_driver(tegra_slink_driver); diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c index afbd64a217eb06..08e49a8768943c 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -341,7 +341,7 @@ tegra_qspi_fill_tx_fifo_from_client_txbuf(struct tegra_qspi *tqspi, struct spi_t for (count = 0; count < max_n_32bit; count++) { u32 x = 0; - for (i = 0; len && (i < bytes_per_word); i++, len--) + for (i = 0; len && (i < min(4, bytes_per_word)); i++, len--) x |= (u32)(*tx_buf++) << (i * 8); tegra_qspi_writel(tqspi, x, QSPI_TX_FIFO); } @@ -1724,7 +1724,7 @@ static struct platform_driver tegra_qspi_driver = { .acpi_match_table = ACPI_PTR(tegra_qspi_acpi_match), }, .probe = tegra_qspi_probe, - .remove_new = tegra_qspi_remove, + .remove = tegra_qspi_remove, }; module_platform_driver(tegra_qspi_driver); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 0fe6899e78dda5..9122350402b506 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -824,7 +824,7 @@ static int ti_qspi_probe(struct platform_device *pdev) } - if (of_property_read_bool(np, "syscon-chipselects")) { + if (of_property_present(np, "syscon-chipselects")) { qspi->ctrl_base = syscon_regmap_lookup_by_phandle(np, "syscon-chipselects"); @@ -863,7 +863,6 @@ static int ti_qspi_probe(struct platform_device *pdev) dev_err(qspi->dev, "No Rx DMA available, trying mmap mode\n"); qspi->rx_chan = NULL; - ret = 0; goto no_dma; } qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev, @@ -931,7 +930,7 @@ static const struct dev_pm_ops ti_qspi_pm_ops = { static struct platform_driver ti_qspi_driver = { .probe = ti_qspi_probe, - .remove_new = ti_qspi_remove, + .remove = ti_qspi_remove, .driver = { .name = "ti-qspi", .pm = &ti_qspi_pm_ops, diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 271f3e7f834be4..60fce5c73031f7 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1514,7 +1514,7 @@ static struct platform_driver pch_spi_pd_driver = { .name = "pch-spi", }, .probe = pch_spi_pd_probe, - .remove_new = pch_spi_pd_remove, + .remove = pch_spi_pd_remove, .suspend = pch_spi_pd_suspend, .resume = pch_spi_pd_resume }; diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index 07b155980e712c..ff2142f87277f7 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -796,7 +796,7 @@ MODULE_DEVICE_TABLE(of, uniphier_spi_match); static struct platform_driver uniphier_spi_driver = { .probe = uniphier_spi_probe, - .remove_new = uniphier_spi_remove, + .remove = uniphier_spi_remove, .driver = { .name = "uniphier-spi", .of_match_table = uniphier_spi_match, diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 7795328427a68b..ded709b2b45918 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -524,7 +524,7 @@ MODULE_ALIAS("platform:" XILINX_SPI_NAME); static struct platform_driver xilinx_spi_driver = { .probe = xilinx_spi_probe, - .remove_new = xilinx_spi_remove, + .remove = xilinx_spi_remove, .driver = { .name = XILINX_SPI_NAME, .of_match_table = xilinx_spi_of_match, diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c index 3c2cda3153973f..1b54d8f9f5ec51 100644 --- a/drivers/spi/spi-xtensa-xtfpga.c +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -138,7 +138,7 @@ MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match); static struct platform_driver xtfpga_spi_driver = { .probe = xtfpga_spi_probe, - .remove_new = xtfpga_spi_remove, + .remove = xtfpga_spi_remove, .driver = { .name = XTFPGA_SPI_NAME, .of_match_table = of_match_ptr(xtfpga_spi_of_match), diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index b67455bda972b2..dee9c339a35e74 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -763,7 +763,7 @@ MODULE_DEVICE_TABLE(of, zynq_qspi_of_match); */ static struct platform_driver zynq_qspi_driver = { .probe = zynq_qspi_probe, - .remove_new = zynq_qspi_remove, + .remove = zynq_qspi_remove, .driver = { .name = "zynq-qspi", .of_match_table = zynq_qspi_of_match, diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index fcd0ca99668419..549a6e0c965462 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1351,6 +1351,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) clk_dis_all: pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(xqspi->refclk); @@ -1379,6 +1380,7 @@ static void zynqmp_qspi_remove(struct platform_device *pdev) zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(xqspi->refclk); @@ -1389,7 +1391,7 @@ MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match); static struct platform_driver zynqmp_qspi_driver = { .probe = zynqmp_qspi_probe, - .remove_new = zynqmp_qspi_remove, + .remove = zynqmp_qspi_remove, .driver = { .name = "zynqmp-qspi", .of_match_table = zynqmp_qspi_of_match, diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index c1dad30a4528b7..ff1add2ecb91f1 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -418,6 +418,16 @@ static int spi_probe(struct device *dev) if (dev->of_node) { spi->irq = of_irq_get(dev->of_node, 0); + if (spi->irq == -EPROBE_DEFER) + return dev_err_probe(dev, -EPROBE_DEFER, "Failed to get irq\n"); + if (spi->irq < 0) + spi->irq = 0; + } + + if (has_acpi_companion(dev) && spi->irq < 0) { + struct acpi_device *adev = to_acpi_device_node(dev->fwnode); + + spi->irq = acpi_dev_gpio_irq_get(adev, 0); if (spi->irq == -EPROBE_DEFER) return -EPROBE_DEFER; if (spi->irq < 0) @@ -984,9 +994,6 @@ static void spi_res_free(void *res) { struct spi_res *sres = container_of(res, struct spi_res, data); - if (!res) - return; - WARN_ON(!list_empty(&sres->entry)); kfree(sres); } @@ -2454,7 +2461,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, nc, rc); return rc; } - if ((of_property_read_bool(nc, "parallel-memories")) && + if ((of_property_present(nc, "parallel-memories")) && (!(ctlr->flags & SPI_CONTROLLER_MULTI_CS))) { dev_err(&ctlr->dev, "SPI controller doesn't support multi CS\n"); return -EINVAL; @@ -2869,9 +2876,6 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias, sizeof(spi->modalias)); - if (spi->irq < 0) - spi->irq = acpi_dev_gpio_irq_get(adev, 0); - acpi_device_set_enumerated(adev); adev->power.flags.ignore_parent = true; @@ -2926,7 +2930,7 @@ static void spi_controller_release(struct device *dev) kfree(ctlr); } -static struct class spi_master_class = { +static const struct class spi_master_class = { .name = "spi_master", .dev_release = spi_controller_release, .dev_groups = spi_master_groups, @@ -3016,7 +3020,7 @@ static const struct attribute_group *spi_slave_groups[] = { NULL, }; -static struct class spi_slave_class = { +static const struct class spi_slave_class = { .name = "spi_slave", .dev_release = spi_controller_release, .dev_groups = spi_slave_groups, @@ -3238,9 +3242,9 @@ static int spi_controller_id_alloc(struct spi_controller *ctlr, int start, int e } /** - * spi_register_controller - register SPI master or slave controller - * @ctlr: initialized master, originally from spi_alloc_master() or - * spi_alloc_slave() + * spi_register_controller - register SPI host or target controller + * @ctlr: initialized controller, originally from spi_alloc_host() or + * spi_alloc_target() * Context: can sleep * * SPI controllers connect to their drivers using some non-SPI bus, @@ -3390,11 +3394,11 @@ static void devm_spi_unregister(struct device *dev, void *res) } /** - * devm_spi_register_controller - register managed SPI master or slave + * devm_spi_register_controller - register managed SPI host or target * controller * @dev: device managing SPI controller - * @ctlr: initialized controller, originally from spi_alloc_master() or - * spi_alloc_slave() + * @ctlr: initialized controller, originally from spi_alloc_host() or + * spi_alloc_target() * Context: can sleep * * Register a SPI device as with spi_register_controller() which will @@ -3478,7 +3482,7 @@ void spi_unregister_controller(struct spi_controller *ctlr) /* * Release the last reference on the controller if its driver - * has not yet been converted to devm_spi_alloc_master/slave(). + * has not yet been converted to devm_spi_alloc_host/target(). */ if (!ctlr->devm_allocated) put_device(&ctlr->dev); diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c index 5079442f8ea166..160d36f7d238e7 100644 --- a/drivers/spmi/spmi-mtk-pmif.c +++ b/drivers/spmi/spmi-mtk-pmif.c @@ -545,7 +545,7 @@ static struct platform_driver mtk_spmi_driver = { .of_match_table = mtk_spmi_match_table, }, .probe = mtk_spmi_probe, - .remove_new = mtk_spmi_remove, + .remove = 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 9ba9495fcc4bae..5c058db2182186 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -1763,14 +1763,13 @@ static int spmi_pmic_arb_register_buses(struct spmi_pmic_arb *pmic_arb, { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - struct device_node *child; int ret; /* legacy mode doesn't provide child node for the bus */ if (of_device_is_compatible(node, "qcom,spmi-pmic-arb")) return spmi_pmic_arb_bus_init(pdev, node, pmic_arb); - for_each_available_child_of_node(node, child) { + for_each_available_child_of_node_scoped(node, child) { if (of_node_name_eq(child, "spmi")) { ret = spmi_pmic_arb_bus_init(pdev, child, pmic_arb); if (ret) @@ -1882,7 +1881,7 @@ MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table); static struct platform_driver spmi_pmic_arb_driver = { .probe = spmi_pmic_arb_probe, - .remove_new = spmi_pmic_arb_remove, + .remove = spmi_pmic_arb_remove, .driver = { .name = "spmi_pmic_arb", .of_match_table = spmi_pmic_arb_match_table, diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 3fb68d60dfc1b5..075e775d3868b3 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -24,22 +24,10 @@ menuconfig STAGING if STAGING -source "drivers/staging/olpc_dcon/Kconfig" - -source "drivers/staging/rtl8192e/Kconfig" - source "drivers/staging/rtl8723bs/Kconfig" -source "drivers/staging/rtl8712/Kconfig" - -source "drivers/staging/rts5208/Kconfig" - source "drivers/staging/octeon/Kconfig" -source "drivers/staging/vt6655/Kconfig" - -source "drivers/staging/vt6656/Kconfig" - source "drivers/staging/iio/Kconfig" source "drivers/staging/sm750fb/Kconfig" @@ -48,8 +36,6 @@ source "drivers/staging/nvec/Kconfig" source "drivers/staging/media/Kconfig" -source "drivers/staging/gdm724x/Kconfig" - source "drivers/staging/fbtft/Kconfig" source "drivers/staging/most/Kconfig" @@ -60,8 +46,8 @@ source "drivers/staging/vc04_services/Kconfig" source "drivers/staging/axis-fifo/Kconfig" -source "drivers/staging/fieldbus/Kconfig" - source "drivers/staging/vme_user/Kconfig" +source "drivers/staging/gpib/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index c977aa13fad40c..e681e403509ce2 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -2,22 +2,15 @@ # Makefile for staging directory obj-y += media/ -obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ -obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_RTL8723BS) += rtl8723bs/ -obj-$(CONFIG_R8712U) += rtl8712/ -obj-$(CONFIG_RTS5208) += rts5208/ obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ -obj-$(CONFIG_VT6655) += vt6655/ -obj-$(CONFIG_VT6656) += vt6656/ obj-$(CONFIG_VME_BUS) += vme_user/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_FB_SM750) += sm750fb/ obj-$(CONFIG_MFD_NVEC) += nvec/ -obj-$(CONFIG_LTE_GDM724X) += gdm724x/ obj-$(CONFIG_FB_TFT) += fbtft/ obj-$(CONFIG_MOST) += most/ obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/ -obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/ +obj-$(CONFIG_GPIB) += gpib/ diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index 1bbb9a6db5979a..7540c20090c78b 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -919,7 +919,7 @@ static struct platform_driver axis_fifo_driver = { .of_match_table = axis_fifo_of_match, }, .probe = axis_fifo_probe, - .remove_new = axis_fifo_remove, + .remove = axis_fifo_remove, }; static int __init axis_fifo_init(void) diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index 77ab44362f167e..dcf6a70455cc24 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -3,6 +3,7 @@ menuconfig FB_TFT tristate "Support for small TFT LCD display modules" depends on FB && SPI depends on FB_DEVICE + depends on BACKLIGHT_CLASS_DEVICE depends on GPIOLIB || COMPILE_TEST select FB_BACKLIGHT select FB_SYSMEM_HELPERS_DEFERRED diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 3e00a26a29d5c3..317be17b95c167 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -330,7 +330,7 @@ static struct platform_driver fbtft_driver_platform_driver = { \ .of_match_table = dt_ids, \ }, \ .probe = fbtft_driver_probe_pdev, \ - .remove_new = fbtft_driver_remove_pdev, \ + .remove = fbtft_driver_remove_pdev, \ }; \ \ static int __init fbtft_driver_module_init(void) \ diff --git a/drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev b/drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev deleted file mode 100644 index 45f631ea32a60c..00000000000000 --- a/drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev +++ /dev/null @@ -1,31 +0,0 @@ -What: /dev/fieldbus_devX -Date: December 2018 -KernelVersion: 5.1 (staging) -Contact: Sven Van Asbroeck -Description: - The cdev interface to drivers for Fieldbus Device Memory - (aka. Process Memory). - - The following file operations are supported: - - open(2) - Create an I/O context associated with the file descriptor. - - read(2) - Read from Process Memory's "read area". - Clears POLLERR | POLLPRI from the file descriptor. - - write(2) - Write to Process Memory's "write area". - - poll(2), select(2), epoll_wait(2) etc. - When a "Process Memory Read Area Changed" event occurs, - POLLERR | POLLPRI will be set on the file descriptor. - Note that POLLIN | POLLOUT events are always set, because the - process memory area is always readable and writable. - - close(2) - Free up the I/O context that was associated - with the file descriptor. - -Users: TBD diff --git a/drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev b/drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev deleted file mode 100644 index 439f14d33c3bfb..00000000000000 --- a/drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev +++ /dev/null @@ -1,62 +0,0 @@ -What: /sys/class/fieldbus_dev/fieldbus_devX/card_name -KernelVersion: 5.1 (staging) -Contact: Sven Van Asbroeck -Description: - Human-readable name of the Fieldbus Device. - -What: /sys/class/fieldbus_dev/fieldbus_devX/fieldbus_type -KernelVersion: 5.1 (staging) -Contact: Sven Van Asbroeck -Description: - The type of fieldbus implemented by this device. - Possible values: - 'unknown' - 'profinet' - -What: /sys/class/fieldbus_dev/fieldbus_devX/fieldbus_id -KernelVersion: 5.1 (staging) -Contact: Sven Van Asbroeck -Description: - The unique fieldbus id associated with this device. - The exact format of this id is fieldbus type dependent, e.g. - a mac address for profinet. - -What: /sys/class/fieldbus_dev/fieldbus_devX/read_area_size -KernelVersion: 5.1 (staging) -Contact: Sven Van Asbroeck -Description: - The size, in bytes, of the Process Memory read area. - Note: this area is accessible by reading from the associated - character device (/dev/fieldbus_devX). - -What: /sys/class/fieldbus_dev/fieldbus_devX/write_area_size -KernelVersion: 5.1 (staging) -Contact: Sven Van Asbroeck -Description: - The size, in bytes, of the Process Memory write area. - Note: this area is accessible by writing to the associated - character device (/dev/fieldbus_devX) - -What: /sys/class/fieldbus_dev/fieldbus_devX/online -KernelVersion: 5.1 (staging) -Contact: Sven Van Asbroeck -Description: - Whether the fieldbus is online or offline. - Possible values: - '1' meaning 'online' - '0' meaning 'offline' - Note: an uevent is generated when this property changes. - -What: /sys/class/fieldbus_dev/fieldbus_devX/enabled -KernelVersion: 5.1 (staging) -Contact: Sven Van Asbroeck -Description: - Whether the device is enabled (power on) or - disabled (power off). - Possible values: - '1' meaning enabled - '0' meaning disabled - Normally a r/o property, but optionally r/w: - Writing '1' enables the device (power on) with default - settings. - Writing '0' disables the card (power off). diff --git a/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt b/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt deleted file mode 100644 index f34a95611645bd..00000000000000 --- a/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt +++ /dev/null @@ -1,71 +0,0 @@ -* Arcx Anybus-S controller - -This chip communicates with the SoC over a parallel bus. It is -expected that its Device Tree node is specified as the child of a node -corresponding to the parallel bus used for communication. - -Required properties: --------------------- - - - compatible : The following chip-specific string: - "arcx,anybus-controller" - - - reg : three areas: - index 0: bus memory area where the cpld registers are located. - index 1: bus memory area of the first host's dual-port ram. - index 2: bus memory area of the second host's dual-port ram. - - - reset-gpios : the GPIO pin connected to the reset line of the controller. - - - interrupts : two interrupts: - index 0: interrupt connected to the first host - index 1: interrupt connected to the second host - Generic interrupt client node bindings are described in - interrupt-controller/interrupts.txt - -Optional: use of subnodes -------------------------- - -The card connected to a host may need additional properties. These can be -specified in subnodes to the controller node. - -The subnodes are identified by the standard 'reg' property. Which information -exactly can be specified depends on the bindings for the function driver -for the subnode. - -Required controller node properties when using subnodes: -- #address-cells: should be one. -- #size-cells: should be zero. - -Required subnode properties: -- reg: Must contain the host index of the card this subnode describes: - <0> for the first host on the controller - <1> for the second host on the controller - Note that only a single card can be plugged into a host, so the host - index uniquely describes the card location. - -Example of usage: ------------------ - -This example places the bridge on top of the i.MX WEIM parallel bus, see: -Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml - -&weim { - controller@0,0 { - compatible = "arcx,anybus-controller"; - reg = <0 0 0x100>, <0 0x400000 0x800>, <1 0x400000 0x800>; - reset-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>; - interrupt-parent = <&gpio1>; - interrupts = <1 IRQ_TYPE_LEVEL_LOW>, <5 IRQ_TYPE_LEVEL_LOW>; - /* fsl,weim-cs-timing is a i.MX WEIM bus specific property */ - fsl,weim-cs-timing = <0x024400b1 0x00001010 0x20081100 - 0x00000000 0xa0000240 0x00000000>; - /* optional subnode for a card plugged into the first host */ - #address-cells = <1>; - #size-cells = <0>; - card@0 { - reg = <0>; - /* card specific properties go here */ - }; - }; -}; diff --git a/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt b/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt deleted file mode 100644 index 89fb8e14676f99..00000000000000 --- a/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt +++ /dev/null @@ -1,66 +0,0 @@ - Fieldbus-Device Subsystem - ============================================ - -Part 0 - What is a Fieldbus Device ? ------------------------------------- - -Fieldbus is the name of a family of industrial computer network protocols used -for real-time distributed control, standardized as IEC 61158. - -A complex automated industrial system -- such as manufacturing assembly line -- -usually needs a distributed control system -- an organized hierarchy of -controller systems -- to function. In this hierarchy, there is usually a -Human Machine Interface (HMI) at the top, where an operator can monitor or -operate the system. This is typically linked to a middle layer of programmable -logic controllers (PLC) via a non-time-critical communications system -(e.g. Ethernet). At the bottom of the control chain is the fieldbus that links -the PLCs to the components that actually do the work, such as sensors, -actuators, electric motors, console lights, switches, valves and contactors. - -(Source: Wikipedia) - -A "Fieldbus Device" is such an actuator, motor, console light, switch, ... -controlled via the Fieldbus by a PLC aka "Fieldbus Controller". - -Communication between PLC and device typically happens via process data memory, -separated into input and output areas. The Fieldbus then cyclically transfers -the PLC's output area to the device's input area, and vice versa. - -Part I - Why do we need this subsystem? ---------------------------------------- - -Fieldbus device (client) adapters are commercially available. They allow data -exchange with a PLC aka "Fieldbus Controller" via process data memory. - -They are typically used when a Linux device wants to expose itself as an -actuator, motor, console light, switch, etc. over the fieldbus. - -The purpose of this subsystem is: -a) present a general, standardized, extensible API/ABI to userspace; and -b) present a convenient interface to drivers. - -Part II - How can drivers use the subsystem? --------------------------------------------- - -Any driver that wants to register as a Fieldbus Device should allocate and -populate a 'struct fieldbus_dev' (from include/linux/fieldbus_dev.h). -Registration then happens by calling fieldbus_dev_register(). - -Part III - How can userspace use the subsystem? ------------------------------------------------ - -Fieldbus protocols and adapters are diverse and varied. However, they share -a limited few common behaviours and properties. This allows us to define -a simple interface consisting of a character device and a set of sysfs files: - -See: -drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev -drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev - -Note that this simple interface does not provide a way to modify adapter -configuration settings. It is therefore useful only for adapters that get their -configuration settings some other way, e.g. non-volatile memory on the adapter, -through the network, ... - -At a later phase, this simple interface can easily co-exist with a future -(netlink-based ?) configuration settings interface. diff --git a/drivers/staging/fieldbus/Kconfig b/drivers/staging/fieldbus/Kconfig deleted file mode 100644 index b0b865acccfbc0..00000000000000 --- a/drivers/staging/fieldbus/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -menuconfig FIELDBUS_DEV - tristate "Fieldbus Device Support" - help - Support for Fieldbus Device Adapters. - - Fieldbus device (client) adapters allow data exchange with a PLC aka. - "Fieldbus Controller" over a fieldbus (Profinet, FLNet, etc.) - - They are typically used when a Linux device wants to expose itself - as an actuator, motor, console light, switch, etc. over the fieldbus. - - This framework is designed to provide a generic interface to Fieldbus - Devices from both the Linux Kernel and the userspace. - - If unsure, say no. - -source "drivers/staging/fieldbus/anybuss/Kconfig" - diff --git a/drivers/staging/fieldbus/Makefile b/drivers/staging/fieldbus/Makefile deleted file mode 100644 index bdf645d41344d6..00000000000000 --- a/drivers/staging/fieldbus/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for fieldbus_dev drivers. -# - -obj-$(CONFIG_FIELDBUS_DEV) += fieldbus_dev.o anybuss/ -fieldbus_dev-y := dev_core.o diff --git a/drivers/staging/fieldbus/TODO b/drivers/staging/fieldbus/TODO deleted file mode 100644 index 6d6626af4ec7de..00000000000000 --- a/drivers/staging/fieldbus/TODO +++ /dev/null @@ -1,5 +0,0 @@ -TODO: --Get more people/drivers to use the Fieldbus userspace ABI. It requires - verification/sign-off by multiple users. - -Contact: Sven Van Asbroeck diff --git a/drivers/staging/fieldbus/anybuss/Kconfig b/drivers/staging/fieldbus/anybuss/Kconfig deleted file mode 100644 index 635a0a7b7dd29b..00000000000000 --- a/drivers/staging/fieldbus/anybuss/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config HMS_ANYBUSS_BUS - tristate "HMS Anybus-S Bus Support" - select REGMAP - depends on OF && FIELDBUS_DEV - help - Driver for the HMS Industrial Networks Anybus-S bus. - You can attach a single Anybus-S compatible card to it, which - typically provides fieldbus and industrial ethernet - functionality. - -if HMS_ANYBUSS_BUS - -config ARCX_ANYBUS_CONTROLLER - tristate "Arcx Anybus-S Controller" - depends on OF && GPIOLIB && HAS_IOMEM && REGULATOR - select REGMAP_MMIO - help - Select this to get support for the Arcx Anybus controller. - It connects to the SoC via a parallel memory bus, and - embeds up to two Anybus-S buses (slots). - There is also a CAN power readout, unrelated to the Anybus, - modelled as a regulator. - -config HMS_PROFINET - tristate "HMS Profinet IRT Controller (Anybus-S)" - depends on FIELDBUS_DEV && HMS_ANYBUSS_BUS - help - If you say yes here you get support for the HMS Industrial - Networks Profinet IRT Controller. - - It will be registered with the kernel as a fieldbus_dev, - so userspace can interact with it via the fieldbus_dev userspace - interface(s). - - This driver can also be built as a module. If so, the module - will be called hms-profinet. - - If unsure, say N. - -endif diff --git a/drivers/staging/fieldbus/anybuss/Makefile b/drivers/staging/fieldbus/anybuss/Makefile deleted file mode 100644 index 3ad3dcc6be56bd..00000000000000 --- a/drivers/staging/fieldbus/anybuss/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for anybuss drivers. -# - -obj-$(CONFIG_HMS_ANYBUSS_BUS) += anybuss_core.o -anybuss_core-y += host.o - -obj-$(CONFIG_ARCX_ANYBUS_CONTROLLER) += arcx-anybus.o -obj-$(CONFIG_HMS_PROFINET) += hms-profinet.o diff --git a/drivers/staging/fieldbus/anybuss/anybuss-client.h b/drivers/staging/fieldbus/anybuss/anybuss-client.h deleted file mode 100644 index c21c4bebfb8457..00000000000000 --- a/drivers/staging/fieldbus/anybuss/anybuss-client.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Anybus-S client adapter definitions - * - * Copyright 2018 Arcx Inc - */ - -#ifndef __LINUX_ANYBUSS_CLIENT_H__ -#define __LINUX_ANYBUSS_CLIENT_H__ - -#include -#include -#include - -/* move to when taking this out of staging */ -#include "../fieldbus_dev.h" - -struct anybuss_host; - -struct anybuss_client { - struct device dev; - struct anybuss_host *host; - __be16 anybus_id; - /* - * these can be optionally set by the client to receive event - * notifications from the host. - */ - void (*on_area_updated)(struct anybuss_client *client); - void (*on_online_changed)(struct anybuss_client *client, bool online); -}; - -struct anybuss_client_driver { - struct device_driver driver; - int (*probe)(struct anybuss_client *adev); - void (*remove)(struct anybuss_client *adev); - u16 anybus_id; -}; - -int anybuss_client_driver_register(struct anybuss_client_driver *drv); -void anybuss_client_driver_unregister(struct anybuss_client_driver *drv); - -static inline struct anybuss_client *to_anybuss_client(struct device *dev) -{ - return container_of(dev, struct anybuss_client, dev); -} - -#define to_anybuss_client_driver(__drv) container_of_const(__drv, struct anybuss_client_driver, driver) - -static inline void * -anybuss_get_drvdata(const struct anybuss_client *client) -{ - return dev_get_drvdata(&client->dev); -} - -static inline void -anybuss_set_drvdata(struct anybuss_client *client, void *data) -{ - dev_set_drvdata(&client->dev, data); -} - -int anybuss_set_power(struct anybuss_client *client, bool power_on); - -struct anybuss_memcfg { - u16 input_io; - u16 input_dpram; - u16 input_total; - - u16 output_io; - u16 output_dpram; - u16 output_total; - - enum fieldbus_dev_offl_mode offl_mode; -}; - -int anybuss_start_init(struct anybuss_client *client, - const struct anybuss_memcfg *cfg); -int anybuss_finish_init(struct anybuss_client *client); -int anybuss_read_fbctrl(struct anybuss_client *client, u16 addr, - void *buf, size_t count); -int anybuss_send_msg(struct anybuss_client *client, u16 cmd_num, - const void *buf, size_t count); -int anybuss_send_ext(struct anybuss_client *client, u16 cmd_num, - const void *buf, size_t count); -int anybuss_recv_msg(struct anybuss_client *client, u16 cmd_num, - void *buf, size_t count); - -/* these help clients make a struct file_operations */ -int anybuss_write_input(struct anybuss_client *client, - const char __user *buf, size_t size, - loff_t *offset); -int anybuss_read_output(struct anybuss_client *client, - char __user *buf, size_t size, - loff_t *offset); - -#endif /* __LINUX_ANYBUSS_CLIENT_H__ */ diff --git a/drivers/staging/fieldbus/anybuss/anybuss-controller.h b/drivers/staging/fieldbus/anybuss/anybuss-controller.h deleted file mode 100644 index 02fa0749043bd9..00000000000000 --- a/drivers/staging/fieldbus/anybuss/anybuss-controller.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Anybus-S controller definitions - * - * Copyright 2018 Arcx Inc - */ - -#ifndef __LINUX_ANYBUSS_CONTROLLER_H__ -#define __LINUX_ANYBUSS_CONTROLLER_H__ - -#include -#include - -/* - * To instantiate an Anybus-S host, a controller should provide the following: - * - a reset function which resets the attached card; - * - a regmap which provides access to the attached card's dpram; - * - the irq of the attached card - */ -/** - * struct anybuss_ops - Controller resources to instantiate an Anybus-S host - * - * @reset: asserts/deasserts the anybus card's reset line. - * @regmap: provides access to the card's dual-port RAM area. - * @irq: number of the interrupt connected to the card's interrupt line. - * @host_idx: for multi-host controllers, the host index: - * 0 for the first host on the controller, 1 for the second, etc. - */ -struct anybuss_ops { - void (*reset)(struct device *dev, bool assert); - struct regmap *regmap; - int irq; - int host_idx; -}; - -struct anybuss_host; - -struct anybuss_host * __must_check -anybuss_host_common_probe(struct device *dev, - const struct anybuss_ops *ops); -void anybuss_host_common_remove(struct anybuss_host *host); - -struct anybuss_host * __must_check -devm_anybuss_host_common_probe(struct device *dev, - const struct anybuss_ops *ops); - -#endif /* __LINUX_ANYBUSS_CONTROLLER_H__ */ diff --git a/drivers/staging/fieldbus/anybuss/arcx-anybus.c b/drivers/staging/fieldbus/anybuss/arcx-anybus.c deleted file mode 100644 index fcd3e3722ae017..00000000000000 --- a/drivers/staging/fieldbus/anybuss/arcx-anybus.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Arcx Anybus-S Controller driver - * - * Copyright (C) 2018 Arcx Inc - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* move to when taking this out of staging */ -#include "anybuss-controller.h" - -#define CPLD_STATUS1 0x80 -#define CPLD_CONTROL 0x80 -#define CPLD_CONTROL_CRST 0x40 -#define CPLD_CONTROL_RST1 0x04 -#define CPLD_CONTROL_RST2 0x80 -#define CPLD_STATUS1_AB 0x02 -#define CPLD_STATUS1_CAN_POWER 0x01 -#define CPLD_DESIGN_LO 0x81 -#define CPLD_DESIGN_HI 0x82 -#define CPLD_CAP 0x83 -#define CPLD_CAP_COMPAT 0x01 -#define CPLD_CAP_SEP_RESETS 0x02 - -struct controller_priv { - struct device *class_dev; - bool common_reset; - struct gpio_desc *reset_gpiod; - void __iomem *cpld_base; - struct mutex ctrl_lock; /* protects CONTROL register */ - u8 control_reg; - char version[3]; - u16 design_no; -}; - -static void do_reset(struct controller_priv *cd, u8 rst_bit, bool reset) -{ - mutex_lock(&cd->ctrl_lock); - /* - * CPLD_CONTROL is write-only, so cache its value in - * cd->control_reg - */ - if (reset) - cd->control_reg &= ~rst_bit; - else - cd->control_reg |= rst_bit; - writeb(cd->control_reg, cd->cpld_base + CPLD_CONTROL); - /* - * h/w work-around: - * the hardware is 'too fast', so a reset followed by an immediate - * not-reset will _not_ change the anybus reset line in any way, - * losing the reset. to prevent this from happening, introduce - * a minimum reset duration. - * Verified minimum safe duration required using a scope - * on 14-June-2018: 100 us. - */ - if (reset) - usleep_range(100, 200); - mutex_unlock(&cd->ctrl_lock); -} - -static int anybuss_reset(struct controller_priv *cd, - unsigned long id, bool reset) -{ - if (id >= 2) - return -EINVAL; - if (cd->common_reset) - do_reset(cd, CPLD_CONTROL_CRST, reset); - else - do_reset(cd, id ? CPLD_CONTROL_RST2 : CPLD_CONTROL_RST1, reset); - return 0; -} - -static void export_reset_0(struct device *dev, bool assert) -{ - struct controller_priv *cd = dev_get_drvdata(dev); - - anybuss_reset(cd, 0, assert); -} - -static void export_reset_1(struct device *dev, bool assert) -{ - struct controller_priv *cd = dev_get_drvdata(dev); - - anybuss_reset(cd, 1, assert); -} - -/* - * parallel bus limitation: - * - * the anybus is 8-bit wide. we can't assume that the hardware will translate - * word accesses on the parallel bus to multiple byte-accesses on the anybus. - * - * the imx WEIM bus does not provide this type of translation. - * - * to be safe, we will limit parallel bus accesses to a single byte - * at a time for now. - */ - -static const struct regmap_config arcx_regmap_cfg = { - .reg_bits = 16, - .val_bits = 8, - .max_register = 0x7ff, - .use_single_read = true, - .use_single_write = true, - /* - * single-byte parallel bus accesses are atomic, so don't - * require any synchronization. - */ - .disable_locking = true, -}; - -static struct regmap *create_parallel_regmap(struct platform_device *pdev, - int idx) -{ - void __iomem *base; - struct device *dev = &pdev->dev; - - base = devm_platform_ioremap_resource(pdev, idx + 1); - if (IS_ERR(base)) - return ERR_CAST(base); - return devm_regmap_init_mmio(dev, base, &arcx_regmap_cfg); -} - -static struct anybuss_host * -create_anybus_host(struct platform_device *pdev, int idx) -{ - struct anybuss_ops ops = {}; - - switch (idx) { - case 0: - ops.reset = export_reset_0; - break; - case 1: - ops.reset = export_reset_1; - break; - default: - return ERR_PTR(-EINVAL); - } - ops.host_idx = idx; - ops.regmap = create_parallel_regmap(pdev, idx); - if (IS_ERR(ops.regmap)) - return ERR_CAST(ops.regmap); - ops.irq = platform_get_irq(pdev, idx); - if (ops.irq < 0) - return ERR_PTR(ops.irq); - return devm_anybuss_host_common_probe(&pdev->dev, &ops); -} - -static ssize_t version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct controller_priv *cd = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", cd->version); -} -static DEVICE_ATTR_RO(version); - -static ssize_t design_number_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct controller_priv *cd = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", cd->design_no); -} -static DEVICE_ATTR_RO(design_number); - -static struct attribute *controller_attributes[] = { - &dev_attr_version.attr, - &dev_attr_design_number.attr, - NULL, -}; - -static const struct attribute_group controller_attribute_group = { - .attrs = controller_attributes, -}; - -static const struct attribute_group *controller_attribute_groups[] = { - &controller_attribute_group, - NULL, -}; - -static void controller_device_release(struct device *dev) -{ - kfree(dev); -} - -static int can_power_is_enabled(struct regulator_dev *rdev) -{ - struct controller_priv *cd = rdev_get_drvdata(rdev); - - return !(readb(cd->cpld_base + CPLD_STATUS1) & CPLD_STATUS1_CAN_POWER); -} - -static const struct regulator_ops can_power_ops = { - .is_enabled = can_power_is_enabled, -}; - -static const struct regulator_desc can_power_desc = { - .name = "regulator-can-power", - .id = -1, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, - .ops = &can_power_ops, -}; - -static const struct class controller_class = { - .name = "arcx_anybus_controller", -}; - -static DEFINE_IDA(controller_index_ida); - -static int controller_probe(struct platform_device *pdev) -{ - struct controller_priv *cd; - struct device *dev = &pdev->dev; - struct regulator_config config = { }; - struct regulator_dev *regulator; - int err, id; - struct anybuss_host *host; - u8 status1, cap; - - cd = devm_kzalloc(dev, sizeof(*cd), GFP_KERNEL); - if (!cd) - return -ENOMEM; - dev_set_drvdata(dev, cd); - mutex_init(&cd->ctrl_lock); - cd->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(cd->reset_gpiod)) - return PTR_ERR(cd->reset_gpiod); - - /* CPLD control memory, sits at index 0 */ - cd->cpld_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(cd->cpld_base)) { - dev_err(dev, - "failed to map cpld base address\n"); - err = PTR_ERR(cd->cpld_base); - goto out_reset; - } - - /* identify cpld */ - status1 = readb(cd->cpld_base + CPLD_STATUS1); - cd->design_no = (readb(cd->cpld_base + CPLD_DESIGN_HI) << 8) | - readb(cd->cpld_base + CPLD_DESIGN_LO); - snprintf(cd->version, sizeof(cd->version), "%c%d", - 'A' + ((status1 >> 5) & 0x7), - (status1 >> 2) & 0x7); - dev_info(dev, "design number %d, revision %s\n", - cd->design_no, - cd->version); - cap = readb(cd->cpld_base + CPLD_CAP); - if (!(cap & CPLD_CAP_COMPAT)) { - dev_err(dev, "unsupported controller [cap=0x%02X]", cap); - err = -ENODEV; - goto out_reset; - } - - if (status1 & CPLD_STATUS1_AB) { - dev_info(dev, "has anybus-S slot(s)"); - cd->common_reset = !(cap & CPLD_CAP_SEP_RESETS); - dev_info(dev, "supports %s", cd->common_reset ? - "a common reset" : "separate resets"); - for (id = 0; id < 2; id++) { - host = create_anybus_host(pdev, id); - if (!IS_ERR(host)) - continue; - err = PTR_ERR(host); - /* -ENODEV is fine, it just means no card detected */ - if (err != -ENODEV) - goto out_reset; - } - } - - id = ida_alloc(&controller_index_ida, GFP_KERNEL); - if (id < 0) { - err = id; - goto out_reset; - } - /* export can power readout as a regulator */ - config.dev = dev; - config.driver_data = cd; - regulator = devm_regulator_register(dev, &can_power_desc, &config); - if (IS_ERR(regulator)) { - err = PTR_ERR(regulator); - goto out_ida; - } - /* make controller info visible to userspace */ - cd->class_dev = kzalloc(sizeof(*cd->class_dev), GFP_KERNEL); - if (!cd->class_dev) { - err = -ENOMEM; - goto out_ida; - } - cd->class_dev->class = &controller_class; - cd->class_dev->groups = controller_attribute_groups; - cd->class_dev->parent = dev; - cd->class_dev->id = id; - cd->class_dev->release = controller_device_release; - dev_set_name(cd->class_dev, "%d", cd->class_dev->id); - dev_set_drvdata(cd->class_dev, cd); - err = device_register(cd->class_dev); - if (err) - goto out_dev; - return 0; -out_dev: - put_device(cd->class_dev); -out_ida: - ida_free(&controller_index_ida, id); -out_reset: - gpiod_set_value_cansleep(cd->reset_gpiod, 1); - return err; -} - -static void controller_remove(struct platform_device *pdev) -{ - struct controller_priv *cd = platform_get_drvdata(pdev); - int id = cd->class_dev->id; - - device_unregister(cd->class_dev); - ida_free(&controller_index_ida, id); - gpiod_set_value_cansleep(cd->reset_gpiod, 1); -} - -static const struct of_device_id controller_of_match[] = { - { .compatible = "arcx,anybus-controller" }, - { } -}; - -MODULE_DEVICE_TABLE(of, controller_of_match); - -static struct platform_driver controller_driver = { - .probe = controller_probe, - .remove_new = controller_remove, - .driver = { - .name = "arcx-anybus-controller", - .of_match_table = controller_of_match, - }, -}; - -static int __init controller_init(void) -{ - int err; - - err = class_register(&controller_class); - if (err) - return err; - err = platform_driver_register(&controller_driver); - if (err) - class_unregister(&controller_class); - - return err; -} - -static void __exit controller_exit(void) -{ - platform_driver_unregister(&controller_driver); - class_unregister(&controller_class); - ida_destroy(&controller_index_ida); -} - -module_init(controller_init); -module_exit(controller_exit); - -MODULE_DESCRIPTION("Arcx Anybus-S Controller driver"); -MODULE_AUTHOR("Sven Van Asbroeck "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/fieldbus/anybuss/hms-profinet.c b/drivers/staging/fieldbus/anybuss/hms-profinet.c deleted file mode 100644 index e691736a53f178..00000000000000 --- a/drivers/staging/fieldbus/anybuss/hms-profinet.c +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * HMS Profinet Client Driver - * - * Copyright (C) 2018 Arcx Inc - */ - -#include -#include -#include -#include - -/* move to when taking this out of staging */ -#include "../fieldbus_dev.h" - -/* move to when taking this out of staging */ -#include "anybuss-client.h" - -#define PROFI_DPRAM_SIZE 512 - -/* - * --------------------------------------------------------------- - * Anybus Profinet mailbox messages - definitions - * --------------------------------------------------------------- - * note that we're depending on the layout of these structures being - * exactly as advertised. - */ - -struct msg_mac_addr { - u8 addr[6]; -}; - -struct profi_priv { - struct fieldbus_dev fbdev; - struct anybuss_client *client; - struct mutex enable_lock; /* serializes card enable */ - bool power_on; -}; - -static ssize_t -profi_read_area(struct fieldbus_dev *fbdev, char __user *buf, size_t size, - loff_t *offset) -{ - struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); - - return anybuss_read_output(priv->client, buf, size, offset); -} - -static ssize_t -profi_write_area(struct fieldbus_dev *fbdev, const char __user *buf, - size_t size, loff_t *offset) -{ - struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); - - return anybuss_write_input(priv->client, buf, size, offset); -} - -static int profi_id_get(struct fieldbus_dev *fbdev, char *buf, - size_t max_size) -{ - struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); - struct msg_mac_addr response; - int ret; - - ret = anybuss_recv_msg(priv->client, 0x0010, &response, - sizeof(response)); - if (ret < 0) - return ret; - return snprintf(buf, max_size, "%pM\n", response.addr); -} - -static bool profi_enable_get(struct fieldbus_dev *fbdev) -{ - struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); - bool power_on; - - mutex_lock(&priv->enable_lock); - power_on = priv->power_on; - mutex_unlock(&priv->enable_lock); - - return power_on; -} - -static int __profi_enable(struct profi_priv *priv) -{ - int ret; - struct anybuss_client *client = priv->client; - /* Initialization Sequence, Generic Anybus Mode */ - const struct anybuss_memcfg mem_cfg = { - .input_io = 220, - .input_dpram = PROFI_DPRAM_SIZE, - .input_total = PROFI_DPRAM_SIZE, - .output_io = 220, - .output_dpram = PROFI_DPRAM_SIZE, - .output_total = PROFI_DPRAM_SIZE, - .offl_mode = FIELDBUS_DEV_OFFL_MODE_CLEAR, - }; - - /* - * switch anybus off then on, this ensures we can do a complete - * configuration cycle in case anybus was already on. - */ - anybuss_set_power(client, false); - ret = anybuss_set_power(client, true); - if (ret) - goto err; - ret = anybuss_start_init(client, &mem_cfg); - if (ret) - goto err; - ret = anybuss_finish_init(client); - if (ret) - goto err; - priv->power_on = true; - return 0; - -err: - anybuss_set_power(client, false); - priv->power_on = false; - return ret; -} - -static int __profi_disable(struct profi_priv *priv) -{ - struct anybuss_client *client = priv->client; - - anybuss_set_power(client, false); - priv->power_on = false; - return 0; -} - -static int profi_simple_enable(struct fieldbus_dev *fbdev, bool enable) -{ - int ret; - struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev); - - mutex_lock(&priv->enable_lock); - if (enable) - ret = __profi_enable(priv); - else - ret = __profi_disable(priv); - mutex_unlock(&priv->enable_lock); - - return ret; -} - -static void profi_on_area_updated(struct anybuss_client *client) -{ - struct profi_priv *priv = anybuss_get_drvdata(client); - - fieldbus_dev_area_updated(&priv->fbdev); -} - -static void profi_on_online_changed(struct anybuss_client *client, bool online) -{ - struct profi_priv *priv = anybuss_get_drvdata(client); - - fieldbus_dev_online_changed(&priv->fbdev, online); -} - -static int profinet_probe(struct anybuss_client *client) -{ - struct profi_priv *priv; - struct device *dev = &client->dev; - int err; - - client->on_area_updated = profi_on_area_updated; - client->on_online_changed = profi_on_online_changed; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - mutex_init(&priv->enable_lock); - priv->client = client; - priv->fbdev.read_area_sz = PROFI_DPRAM_SIZE; - priv->fbdev.write_area_sz = PROFI_DPRAM_SIZE; - priv->fbdev.card_name = "HMS Profinet IRT (Anybus-S)"; - priv->fbdev.fieldbus_type = FIELDBUS_DEV_TYPE_PROFINET; - priv->fbdev.read_area = profi_read_area; - priv->fbdev.write_area = profi_write_area; - priv->fbdev.fieldbus_id_get = profi_id_get; - priv->fbdev.enable_get = profi_enable_get; - priv->fbdev.simple_enable_set = profi_simple_enable; - priv->fbdev.parent = dev; - err = fieldbus_dev_register(&priv->fbdev); - if (err < 0) - return err; - dev_info(dev, "card detected, registered as %s", - dev_name(priv->fbdev.dev)); - anybuss_set_drvdata(client, priv); - - return 0; -} - -static void profinet_remove(struct anybuss_client *client) -{ - struct profi_priv *priv = anybuss_get_drvdata(client); - - fieldbus_dev_unregister(&priv->fbdev); -} - -static struct anybuss_client_driver profinet_driver = { - .probe = profinet_probe, - .remove = profinet_remove, - .driver = { - .name = "hms-profinet", - .owner = THIS_MODULE, - }, - .anybus_id = 0x0089, -}; - -static int __init profinet_init(void) -{ - return anybuss_client_driver_register(&profinet_driver); -} -module_init(profinet_init); - -static void __exit profinet_exit(void) -{ - return anybuss_client_driver_unregister(&profinet_driver); -} -module_exit(profinet_exit); - -MODULE_AUTHOR("Sven Van Asbroeck "); -MODULE_DESCRIPTION("HMS Profinet IRT Driver (Anybus-S)"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/fieldbus/anybuss/host.c b/drivers/staging/fieldbus/anybuss/host.c deleted file mode 100644 index 4f2b2fce92eec4..00000000000000 --- a/drivers/staging/fieldbus/anybuss/host.c +++ /dev/null @@ -1,1452 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * HMS Anybus-S Host Driver - * - * Copyright (C) 2018 Arcx Inc - */ - -/* - * Architecture Overview - * ===================== - * This driver (running on the CPU/SoC) and the Anybus-S card communicate - * by reading and writing data to/from the Anybus-S Dual-Port RAM (dpram). - * This is memory connected to both the SoC and Anybus-S card, which both sides - * can access freely and concurrently. - * - * Synchronization happens by means of two registers located in the dpram: - * IND_AB: written exclusively by the Anybus card; and - * IND_AP: written exclusively by this driver. - * - * Communication happens using one of the following mechanisms: - * 1. reserve, read/write, release dpram memory areas: - * using an IND_AB/IND_AP protocol, the driver is able to reserve certain - * memory areas. no dpram memory can be read or written except if reserved. - * (with a few limited exceptions) - * 2. send and receive data structures via a shared mailbox: - * using an IND_AB/IND_AP protocol, the driver and Anybus card are able to - * exchange commands and responses using a shared mailbox. - * 3. receive software interrupts: - * using an IND_AB/IND_AP protocol, the Anybus card is able to notify the - * driver of certain events such as: bus online/offline, data available. - * note that software interrupt event bits are located in a memory area - * which must be reserved before it can be accessed. - * - * The manual[1] is silent on whether these mechanisms can happen concurrently, - * or how they should be synchronized. However, section 13 (Driver Example) - * provides the following suggestion for developing a driver: - * a) an interrupt handler which updates global variables; - * b) a continuously-running task handling area requests (1 above) - * c) a continuously-running task handling mailbox requests (2 above) - * The example conspicuously leaves out software interrupts (3 above), which - * is the thorniest issue to get right (see below). - * - * The naive, straightforward way to implement this would be: - * - create an isr which updates shared variables; - * - create a work_struct which handles software interrupts on a queue; - * - create a function which does reserve/update/unlock in a loop; - * - create a function which does mailbox send/receive in a loop; - * - call the above functions from the driver's read/write/ioctl; - * - synchronize using mutexes/spinlocks: - * + only one area request at a time - * + only one mailbox request at a time - * + protect AB_IND, AB_IND against data hazards (e.g. read-after-write) - * - * Unfortunately, the presence of the software interrupt causes subtle yet - * considerable synchronization issues; especially problematic is the - * requirement to reserve/release the area which contains the status bits. - * - * The driver architecture presented here sidesteps these synchronization issues - * by accessing the dpram from a single kernel thread only. User-space throws - * "tasks" (i.e. 1, 2 above) into a task queue, waits for their completion, - * and the kernel thread runs them to completion. - * - * Each task has a task_function, which is called/run by the queue thread. - * That function communicates with the Anybus card, and returns either - * 0 (OK), a negative error code (error), or -EINPROGRESS (waiting). - * On OK or error, the queue thread completes and dequeues the task, - * which also releases the user space thread which may still be waiting for it. - * On -EINPROGRESS (waiting), the queue thread will leave the task on the queue, - * and revisit (call again) whenever an interrupt event comes in. - * - * Each task has a state machine, which is run by calling its task_function. - * It ensures that the task will go through its various stages over time, - * returning -EINPROGRESS if it wants to wait for an event to happen. - * - * Note that according to the manual's driver example, the following operations - * may run independent of each other: - * - area reserve/read/write/release (point 1 above) - * - mailbox operations (point 2 above) - * - switching power on/off - * - * To allow them to run independently, each operation class gets its own queue. - * - * Userspace processes A, B, C, D post tasks to the appropriate queue, - * and wait for task completion: - * - * process A B C D - * | | | | - * v v v v - * |<----- ======================================== - * | | | | - * | v v v-------<-------+ - * | +--------------------------------------+ | - * | | power q | mbox q | area q | | - * | |------------|------------|------------| | - * | | task | task | task | | - * | | task | task | task | | - * | | task wait | task wait | task wait | | - * | +--------------------------------------+ | - * | ^ ^ ^ | - * | | | | ^ - * | +--------------------------------------+ | - * | | queue thread | | - * | |--------------------------------------| | - * | | single-threaded: | | - * | | loop: | | - * v | for each queue: | | - * | | run task state machine | | - * | | if task waiting: | | - * | | leave on queue | | - * | | if task done: | | - * | | complete task, remove from q | | - * | | if software irq event bits set: | | - * | | notify userspace | | - * | | post clear event bits task------>|>-------+ - * | | wait for IND_AB changed event OR | - * | | task added event OR | - * | | timeout | - * | | end loop | - * | +--------------------------------------+ - * | + wake up + - * | +--------------------------------------+ - * | ^ ^ - * | | | - * +-------->------- | - * | - * +--------------------------------------+ - * | interrupt service routine | - * |--------------------------------------| - * | wake up queue thread on IND_AB change| - * +--------------------------------------+ - * - * Note that the Anybus interrupt is dual-purpose: - * - after a reset, triggered when the card becomes ready; - * - during normal operation, triggered when AB_IND changes. - * This is why the interrupt service routine doesn't just wake up the - * queue thread, but also completes the card_boot completion. - * - * [1] https://www.anybus.com/docs/librariesprovider7/default-document-library/ - * manuals-design-guides/hms-hmsi-27-275.pdf - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* move to when taking this out of staging */ -#include "anybuss-client.h" -#include "anybuss-controller.h" - -#define DPRAM_SIZE 0x800 -#define MAX_MBOX_MSG_SZ 0x0FF -#define TIMEOUT (HZ * 2) -#define MAX_DATA_AREA_SZ 0x200 -#define MAX_FBCTRL_AREA_SZ 0x1BE - -#define REG_BOOTLOADER_V 0x7C0 -#define REG_API_V 0x7C2 -#define REG_FIELDBUS_V 0x7C4 -#define REG_SERIAL_NO 0x7C6 -#define REG_FIELDBUS_TYPE 0x7CC -#define REG_MODULE_SW_V 0x7CE -#define REG_IND_AB 0x7FF -#define REG_IND_AP 0x7FE -#define REG_EVENT_CAUSE 0x7ED -#define MBOX_IN_AREA 0x400 -#define MBOX_OUT_AREA 0x520 -#define DATA_IN_AREA 0x000 -#define DATA_OUT_AREA 0x200 -#define FBCTRL_AREA 0x640 - -#define EVENT_CAUSE_DC 0x01 -#define EVENT_CAUSE_FBOF 0x02 -#define EVENT_CAUSE_FBON 0x04 - -#define IND_AB_UPDATED 0x08 -#define IND_AX_MIN 0x80 -#define IND_AX_MOUT 0x40 -#define IND_AX_IN 0x04 -#define IND_AX_OUT 0x02 -#define IND_AX_FBCTRL 0x01 -#define IND_AP_LOCK 0x08 -#define IND_AP_ACTION 0x10 -#define IND_AX_EVNT 0x20 -#define IND_AP_ABITS (IND_AX_IN | IND_AX_OUT | \ - IND_AX_FBCTRL | \ - IND_AP_ACTION | IND_AP_LOCK) - -#define INFO_TYPE_FB 0x0002 -#define INFO_TYPE_APP 0x0001 -#define INFO_COMMAND 0x4000 - -#define OP_MODE_FBFC 0x0002 -#define OP_MODE_FBS 0x0004 -#define OP_MODE_CD 0x0200 - -#define CMD_START_INIT 0x0001 -#define CMD_ANYBUS_INIT 0x0002 -#define CMD_END_INIT 0x0003 - -/* - * --------------------------------------------------------------- - * Anybus mailbox messages - definitions - * --------------------------------------------------------------- - * note that we're depending on the layout of these structures being - * exactly as advertised. - */ - -struct anybus_mbox_hdr { - __be16 id; - __be16 info; - __be16 cmd_num; - __be16 data_size; - __be16 frame_count; - __be16 frame_num; - __be16 offset_high; - __be16 offset_low; - __be16 extended[8]; -}; - -struct msg_anybus_init { - __be16 input_io_len; - __be16 input_dpram_len; - __be16 input_total_len; - __be16 output_io_len; - __be16 output_dpram_len; - __be16 output_total_len; - __be16 op_mode; - __be16 notif_config; - __be16 wd_val; -}; - -/* ------------- ref counted tasks ------------- */ - -struct ab_task; -typedef int (*ab_task_fn_t)(struct anybuss_host *cd, - struct ab_task *t); -typedef void (*ab_done_fn_t)(struct anybuss_host *cd); - -struct area_priv { - bool is_write; - u16 flags; - u16 addr; - size_t count; - u8 buf[MAX_DATA_AREA_SZ]; -}; - -struct mbox_priv { - struct anybus_mbox_hdr hdr; - size_t msg_out_sz; - size_t msg_in_sz; - u8 msg[MAX_MBOX_MSG_SZ]; -}; - -struct ab_task { - struct kmem_cache *cache; - struct kref refcount; - ab_task_fn_t task_fn; - ab_done_fn_t done_fn; - int result; - struct completion done; - unsigned long start_jiffies; - union { - struct area_priv area_pd; - struct mbox_priv mbox_pd; - }; -}; - -static struct ab_task *ab_task_create_get(struct kmem_cache *cache, - ab_task_fn_t task_fn) -{ - struct ab_task *t; - - t = kmem_cache_alloc(cache, GFP_KERNEL); - if (!t) - return NULL; - t->cache = cache; - kref_init(&t->refcount); - t->task_fn = task_fn; - t->done_fn = NULL; - t->result = 0; - init_completion(&t->done); - return t; -} - -static void __ab_task_destroy(struct kref *refcount) -{ - struct ab_task *t = container_of(refcount, struct ab_task, refcount); - struct kmem_cache *cache = t->cache; - - kmem_cache_free(cache, t); -} - -static void ab_task_put(struct ab_task *t) -{ - kref_put(&t->refcount, __ab_task_destroy); -} - -static struct ab_task *__ab_task_get(struct ab_task *t) -{ - kref_get(&t->refcount); - return t; -} - -static void __ab_task_finish(struct ab_task *t, struct anybuss_host *cd) -{ - if (t->done_fn) - t->done_fn(cd); - complete(&t->done); -} - -static void -ab_task_dequeue_finish_put(struct kfifo *q, struct anybuss_host *cd) -{ - int ret; - struct ab_task *t; - - ret = kfifo_out(q, &t, sizeof(t)); - WARN_ON(!ret); - __ab_task_finish(t, cd); - ab_task_put(t); -} - -static int -ab_task_enqueue(struct ab_task *t, struct kfifo *q, spinlock_t *slock, - wait_queue_head_t *wq) -{ - int ret; - - t->start_jiffies = jiffies; - __ab_task_get(t); - ret = kfifo_in_spinlocked(q, &t, sizeof(t), slock); - if (!ret) { - ab_task_put(t); - return -ENOMEM; - } - wake_up(wq); - return 0; -} - -static int -ab_task_enqueue_wait(struct ab_task *t, struct kfifo *q, spinlock_t *slock, - wait_queue_head_t *wq) -{ - int ret; - - ret = ab_task_enqueue(t, q, slock, wq); - if (ret) - return ret; - ret = wait_for_completion_interruptible(&t->done); - if (ret) - return ret; - return t->result; -} - -/* ------------------------ anybus hardware ------------------------ */ - -struct anybuss_host { - struct device *dev; - struct anybuss_client *client; - void (*reset)(struct device *dev, bool assert); - struct regmap *regmap; - int irq; - int host_idx; - struct task_struct *qthread; - wait_queue_head_t wq; - struct completion card_boot; - atomic_t ind_ab; - spinlock_t qlock; /* protects IN side of powerq, mboxq, areaq */ - struct kmem_cache *qcache; - struct kfifo qs[3]; - struct kfifo *powerq; - struct kfifo *mboxq; - struct kfifo *areaq; - bool power_on; - bool softint_pending; -}; - -static void reset_assert(struct anybuss_host *cd) -{ - cd->reset(cd->dev, true); -} - -static void reset_deassert(struct anybuss_host *cd) -{ - cd->reset(cd->dev, false); -} - -static int test_dpram(struct regmap *regmap) -{ - int i; - unsigned int val; - - for (i = 0; i < DPRAM_SIZE; i++) - regmap_write(regmap, i, (u8)i); - for (i = 0; i < DPRAM_SIZE; i++) { - regmap_read(regmap, i, &val); - if ((u8)val != (u8)i) - return -EIO; - } - return 0; -} - -static int read_ind_ab(struct regmap *regmap) -{ - unsigned long timeout = jiffies + HZ / 2; - unsigned int a, b, i = 0; - - while (time_before_eq(jiffies, timeout)) { - regmap_read(regmap, REG_IND_AB, &a); - regmap_read(regmap, REG_IND_AB, &b); - if (likely(a == b)) - return (int)a; - if (i < 10) { - cpu_relax(); - i++; - } else { - usleep_range(500, 1000); - } - } - WARN(1, "IND_AB register not stable"); - return -ETIMEDOUT; -} - -static int write_ind_ap(struct regmap *regmap, unsigned int ind_ap) -{ - unsigned long timeout = jiffies + HZ / 2; - unsigned int v, i = 0; - - while (time_before_eq(jiffies, timeout)) { - regmap_write(regmap, REG_IND_AP, ind_ap); - regmap_read(regmap, REG_IND_AP, &v); - if (likely(ind_ap == v)) - return 0; - if (i < 10) { - cpu_relax(); - i++; - } else { - usleep_range(500, 1000); - } - } - WARN(1, "IND_AP register not stable"); - return -ETIMEDOUT; -} - -static irqreturn_t irq_handler(int irq, void *data) -{ - struct anybuss_host *cd = data; - int ind_ab; - - /* - * irq handler needs exclusive access to the IND_AB register, - * because the act of reading the register acks the interrupt. - * - * store the register value in cd->ind_ab (an atomic_t), so that the - * queue thread is able to read it without causing an interrupt ack - * side-effect (and without spuriously acking an interrupt). - */ - ind_ab = read_ind_ab(cd->regmap); - if (ind_ab < 0) - return IRQ_NONE; - atomic_set(&cd->ind_ab, ind_ab); - complete(&cd->card_boot); - wake_up(&cd->wq); - return IRQ_HANDLED; -} - -/* ------------------------ power on/off tasks --------------------- */ - -static int task_fn_power_off(struct anybuss_host *cd, - struct ab_task *t) -{ - struct anybuss_client *client = cd->client; - - if (!cd->power_on) - return 0; - disable_irq(cd->irq); - reset_assert(cd); - atomic_set(&cd->ind_ab, IND_AB_UPDATED); - if (client->on_online_changed) - client->on_online_changed(client, false); - cd->power_on = false; - return 0; -} - -static int task_fn_power_on_2(struct anybuss_host *cd, - struct ab_task *t) -{ - if (completion_done(&cd->card_boot)) { - cd->power_on = true; - return 0; - } - if (time_after(jiffies, t->start_jiffies + TIMEOUT)) { - disable_irq(cd->irq); - reset_assert(cd); - dev_err(cd->dev, "power on timed out"); - return -ETIMEDOUT; - } - return -EINPROGRESS; -} - -static int task_fn_power_on(struct anybuss_host *cd, - struct ab_task *t) -{ - unsigned int dummy; - - if (cd->power_on) - return 0; - /* - * anybus docs: prevent false 'init done' interrupt by - * doing a dummy read of IND_AB register while in reset. - */ - regmap_read(cd->regmap, REG_IND_AB, &dummy); - reinit_completion(&cd->card_boot); - enable_irq(cd->irq); - reset_deassert(cd); - t->task_fn = task_fn_power_on_2; - return -EINPROGRESS; -} - -int anybuss_set_power(struct anybuss_client *client, bool power_on) -{ - struct anybuss_host *cd = client->host; - struct ab_task *t; - int err; - - t = ab_task_create_get(cd->qcache, power_on ? - task_fn_power_on : task_fn_power_off); - if (!t) - return -ENOMEM; - err = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq); - ab_task_put(t); - return err; -} -EXPORT_SYMBOL_GPL(anybuss_set_power); - -/* ---------------------------- area tasks ------------------------ */ - -static int task_fn_area_3(struct anybuss_host *cd, struct ab_task *t) -{ - struct area_priv *pd = &t->area_pd; - - if (!cd->power_on) - return -EIO; - if (atomic_read(&cd->ind_ab) & pd->flags) { - /* area not released yet */ - if (time_after(jiffies, t->start_jiffies + TIMEOUT)) - return -ETIMEDOUT; - return -EINPROGRESS; - } - return 0; -} - -static int task_fn_area_2(struct anybuss_host *cd, struct ab_task *t) -{ - struct area_priv *pd = &t->area_pd; - unsigned int ind_ap; - int ret; - - if (!cd->power_on) - return -EIO; - regmap_read(cd->regmap, REG_IND_AP, &ind_ap); - if (!(atomic_read(&cd->ind_ab) & pd->flags)) { - /* we don't own the area yet */ - if (time_after(jiffies, t->start_jiffies + TIMEOUT)) { - dev_warn(cd->dev, "timeout waiting for area"); - dump_stack(); - return -ETIMEDOUT; - } - return -EINPROGRESS; - } - /* we own the area, do what we're here to do */ - if (pd->is_write) - regmap_bulk_write(cd->regmap, pd->addr, pd->buf, - pd->count); - else - regmap_bulk_read(cd->regmap, pd->addr, pd->buf, - pd->count); - /* ask to release the area, must use unlocked release */ - ind_ap &= ~IND_AP_ABITS; - ind_ap |= pd->flags; - ret = write_ind_ap(cd->regmap, ind_ap); - if (ret) - return ret; - t->task_fn = task_fn_area_3; - return -EINPROGRESS; -} - -static int task_fn_area(struct anybuss_host *cd, struct ab_task *t) -{ - struct area_priv *pd = &t->area_pd; - unsigned int ind_ap; - int ret; - - if (!cd->power_on) - return -EIO; - regmap_read(cd->regmap, REG_IND_AP, &ind_ap); - /* ask to take the area */ - ind_ap &= ~IND_AP_ABITS; - ind_ap |= pd->flags | IND_AP_ACTION | IND_AP_LOCK; - ret = write_ind_ap(cd->regmap, ind_ap); - if (ret) - return ret; - t->task_fn = task_fn_area_2; - return -EINPROGRESS; -} - -static struct ab_task * -create_area_reader(struct kmem_cache *qcache, u16 flags, u16 addr, - size_t count) -{ - struct ab_task *t; - struct area_priv *ap; - - t = ab_task_create_get(qcache, task_fn_area); - if (!t) - return NULL; - ap = &t->area_pd; - ap->flags = flags; - ap->addr = addr; - ap->is_write = false; - ap->count = count; - return t; -} - -static struct ab_task * -create_area_writer(struct kmem_cache *qcache, u16 flags, u16 addr, - const void *buf, size_t count) -{ - struct ab_task *t; - struct area_priv *ap; - - t = ab_task_create_get(qcache, task_fn_area); - if (!t) - return NULL; - ap = &t->area_pd; - ap->flags = flags; - ap->addr = addr; - ap->is_write = true; - ap->count = count; - memcpy(ap->buf, buf, count); - return t; -} - -static struct ab_task * -create_area_user_writer(struct kmem_cache *qcache, u16 flags, u16 addr, - const void __user *buf, size_t count) -{ - struct ab_task *t; - struct area_priv *ap; - - t = ab_task_create_get(qcache, task_fn_area); - if (!t) - return ERR_PTR(-ENOMEM); - ap = &t->area_pd; - ap->flags = flags; - ap->addr = addr; - ap->is_write = true; - ap->count = count; - if (copy_from_user(ap->buf, buf, count)) { - ab_task_put(t); - return ERR_PTR(-EFAULT); - } - return t; -} - -static bool area_range_ok(u16 addr, size_t count, u16 area_start, - size_t area_sz) -{ - u16 area_end_ex = area_start + area_sz; - u16 addr_end_ex; - - if (addr < area_start) - return false; - if (addr >= area_end_ex) - return false; - addr_end_ex = addr + count; - if (addr_end_ex > area_end_ex) - return false; - return true; -} - -/* -------------------------- mailbox tasks ----------------------- */ - -static int task_fn_mbox_2(struct anybuss_host *cd, struct ab_task *t) -{ - struct mbox_priv *pd = &t->mbox_pd; - unsigned int ind_ap; - - if (!cd->power_on) - return -EIO; - regmap_read(cd->regmap, REG_IND_AP, &ind_ap); - if (((atomic_read(&cd->ind_ab) ^ ind_ap) & IND_AX_MOUT) == 0) { - /* output message not here */ - if (time_after(jiffies, t->start_jiffies + TIMEOUT)) - return -ETIMEDOUT; - return -EINPROGRESS; - } - /* grab the returned header and msg */ - regmap_bulk_read(cd->regmap, MBOX_OUT_AREA, &pd->hdr, - sizeof(pd->hdr)); - regmap_bulk_read(cd->regmap, MBOX_OUT_AREA + sizeof(pd->hdr), - pd->msg, pd->msg_in_sz); - /* tell anybus we've consumed the message */ - ind_ap ^= IND_AX_MOUT; - return write_ind_ap(cd->regmap, ind_ap); -} - -static int task_fn_mbox(struct anybuss_host *cd, struct ab_task *t) -{ - struct mbox_priv *pd = &t->mbox_pd; - unsigned int ind_ap; - int ret; - - if (!cd->power_on) - return -EIO; - regmap_read(cd->regmap, REG_IND_AP, &ind_ap); - if ((atomic_read(&cd->ind_ab) ^ ind_ap) & IND_AX_MIN) { - /* mbox input area busy */ - if (time_after(jiffies, t->start_jiffies + TIMEOUT)) - return -ETIMEDOUT; - return -EINPROGRESS; - } - /* write the header and msg to input area */ - regmap_bulk_write(cd->regmap, MBOX_IN_AREA, &pd->hdr, - sizeof(pd->hdr)); - regmap_bulk_write(cd->regmap, MBOX_IN_AREA + sizeof(pd->hdr), - pd->msg, pd->msg_out_sz); - /* tell anybus we gave it a message */ - ind_ap ^= IND_AX_MIN; - ret = write_ind_ap(cd->regmap, ind_ap); - if (ret) - return ret; - t->start_jiffies = jiffies; - t->task_fn = task_fn_mbox_2; - return -EINPROGRESS; -} - -static void log_invalid_other(struct device *dev, - struct anybus_mbox_hdr *hdr) -{ - size_t ext_offs = ARRAY_SIZE(hdr->extended) - 1; - u16 code = be16_to_cpu(hdr->extended[ext_offs]); - - dev_err(dev, " Invalid other: [0x%02X]", code); -} - -static const char * const EMSGS[] = { - "Invalid Message ID", - "Invalid Message Type", - "Invalid Command", - "Invalid Data Size", - "Message Header Malformed (offset 008h)", - "Message Header Malformed (offset 00Ah)", - "Message Header Malformed (offset 00Ch - 00Dh)", - "Invalid Address", - "Invalid Response", - "Flash Config Error", -}; - -static int mbox_cmd_err(struct device *dev, struct mbox_priv *mpriv) -{ - int i; - u8 ecode; - struct anybus_mbox_hdr *hdr = &mpriv->hdr; - u16 info = be16_to_cpu(hdr->info); - u8 *phdr = (u8 *)hdr; - u8 *pmsg = mpriv->msg; - - if (!(info & 0x8000)) - return 0; - ecode = (info >> 8) & 0x0F; - dev_err(dev, "mailbox command failed:"); - if (ecode == 0x0F) - log_invalid_other(dev, hdr); - else if (ecode < ARRAY_SIZE(EMSGS)) - dev_err(dev, " Error code: %s (0x%02X)", - EMSGS[ecode], ecode); - else - dev_err(dev, " Error code: 0x%02X\n", ecode); - dev_err(dev, "Failed command:"); - dev_err(dev, "Message Header:"); - for (i = 0; i < sizeof(mpriv->hdr); i += 2) - dev_err(dev, "%02X%02X", phdr[i], phdr[i + 1]); - dev_err(dev, "Message Data:"); - for (i = 0; i < mpriv->msg_in_sz; i += 2) - dev_err(dev, "%02X%02X", pmsg[i], pmsg[i + 1]); - dev_err(dev, "Stack dump:"); - dump_stack(); - return -EIO; -} - -static int _anybus_mbox_cmd(struct anybuss_host *cd, - u16 cmd_num, bool is_fb_cmd, - const void *msg_out, size_t msg_out_sz, - void *msg_in, size_t msg_in_sz, - const void *ext, size_t ext_sz) -{ - struct ab_task *t; - struct mbox_priv *pd; - struct anybus_mbox_hdr *h; - size_t msg_sz = max(msg_in_sz, msg_out_sz); - u16 info; - int err; - - if (msg_sz > MAX_MBOX_MSG_SZ) - return -EINVAL; - if (ext && ext_sz > sizeof(h->extended)) - return -EINVAL; - t = ab_task_create_get(cd->qcache, task_fn_mbox); - if (!t) - return -ENOMEM; - pd = &t->mbox_pd; - h = &pd->hdr; - info = is_fb_cmd ? INFO_TYPE_FB : INFO_TYPE_APP; - /* - * prevent uninitialized memory in the header from being sent - * across the anybus - */ - memset(h, 0, sizeof(*h)); - h->info = cpu_to_be16(info | INFO_COMMAND); - h->cmd_num = cpu_to_be16(cmd_num); - h->data_size = cpu_to_be16(msg_out_sz); - h->frame_count = cpu_to_be16(1); - h->frame_num = cpu_to_be16(1); - h->offset_high = cpu_to_be16(0); - h->offset_low = cpu_to_be16(0); - if (ext) - memcpy(h->extended, ext, ext_sz); - memcpy(pd->msg, msg_out, msg_out_sz); - pd->msg_out_sz = msg_out_sz; - pd->msg_in_sz = msg_in_sz; - err = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq); - if (err) - goto out; - /* - * mailbox mechanism worked ok, but maybe the mbox response - * contains an error ? - */ - err = mbox_cmd_err(cd->dev, pd); - if (err) - goto out; - memcpy(msg_in, pd->msg, msg_in_sz); -out: - ab_task_put(t); - return err; -} - -/* ------------------------ anybus queues ------------------------ */ - -static void process_q(struct anybuss_host *cd, struct kfifo *q) -{ - struct ab_task *t; - int ret; - - ret = kfifo_out_peek(q, &t, sizeof(t)); - if (!ret) - return; - t->result = t->task_fn(cd, t); - if (t->result != -EINPROGRESS) - ab_task_dequeue_finish_put(q, cd); -} - -static bool qs_have_work(struct kfifo *qs, size_t num) -{ - size_t i; - struct ab_task *t; - int ret; - - for (i = 0; i < num; i++, qs++) { - ret = kfifo_out_peek(qs, &t, sizeof(t)); - if (ret && (t->result != -EINPROGRESS)) - return true; - } - return false; -} - -static void process_qs(struct anybuss_host *cd) -{ - size_t i; - struct kfifo *qs = cd->qs; - size_t nqs = ARRAY_SIZE(cd->qs); - - for (i = 0; i < nqs; i++, qs++) - process_q(cd, qs); -} - -static void softint_ack(struct anybuss_host *cd) -{ - unsigned int ind_ap; - - cd->softint_pending = false; - if (!cd->power_on) - return; - regmap_read(cd->regmap, REG_IND_AP, &ind_ap); - ind_ap &= ~IND_AX_EVNT; - ind_ap |= atomic_read(&cd->ind_ab) & IND_AX_EVNT; - write_ind_ap(cd->regmap, ind_ap); -} - -static void process_softint(struct anybuss_host *cd) -{ - struct anybuss_client *client = cd->client; - static const u8 zero; - int ret; - unsigned int ind_ap, ev; - struct ab_task *t; - - if (!cd->power_on) - return; - if (cd->softint_pending) - return; - regmap_read(cd->regmap, REG_IND_AP, &ind_ap); - if (!((atomic_read(&cd->ind_ab) ^ ind_ap) & IND_AX_EVNT)) - return; - /* process software interrupt */ - regmap_read(cd->regmap, REG_EVENT_CAUSE, &ev); - if (ev & EVENT_CAUSE_FBON) { - if (client->on_online_changed) - client->on_online_changed(client, true); - dev_dbg(cd->dev, "Fieldbus ON"); - } - if (ev & EVENT_CAUSE_FBOF) { - if (client->on_online_changed) - client->on_online_changed(client, false); - dev_dbg(cd->dev, "Fieldbus OFF"); - } - if (ev & EVENT_CAUSE_DC) { - if (client->on_area_updated) - client->on_area_updated(client); - dev_dbg(cd->dev, "Fieldbus data changed"); - } - /* - * reset the event cause bits. - * this must be done while owning the fbctrl area, so we'll - * enqueue a task to do that. - */ - t = create_area_writer(cd->qcache, IND_AX_FBCTRL, - REG_EVENT_CAUSE, &zero, sizeof(zero)); - if (!t) { - ret = -ENOMEM; - goto out; - } - t->done_fn = softint_ack; - ret = ab_task_enqueue(t, cd->powerq, &cd->qlock, &cd->wq); - ab_task_put(t); - cd->softint_pending = true; -out: - WARN_ON(ret); - if (ret) - softint_ack(cd); -} - -static int qthread_fn(void *data) -{ - struct anybuss_host *cd = data; - struct kfifo *qs = cd->qs; - size_t nqs = ARRAY_SIZE(cd->qs); - unsigned int ind_ab; - - /* - * this kernel thread has exclusive access to the anybus's memory. - * only exception: the IND_AB register, which is accessed exclusively - * by the interrupt service routine (ISR). This thread must not touch - * the IND_AB register, but it does require access to its value. - * - * the interrupt service routine stores the register's value in - * cd->ind_ab (an atomic_t), where we may safely access it, with the - * understanding that it can be modified by the ISR at any time. - */ - - while (!kthread_should_stop()) { - /* - * make a local copy of IND_AB, so we can go around the loop - * again in case it changed while processing queues and softint. - */ - ind_ab = atomic_read(&cd->ind_ab); - process_qs(cd); - process_softint(cd); - wait_event_timeout(cd->wq, - (atomic_read(&cd->ind_ab) != ind_ab) || - qs_have_work(qs, nqs) || - kthread_should_stop(), - HZ); - /* - * time out so even 'stuck' tasks will run eventually, - * and can time out. - */ - } - - return 0; -} - -/* ------------------------ anybus exports ------------------------ */ - -int anybuss_start_init(struct anybuss_client *client, - const struct anybuss_memcfg *cfg) -{ - int ret; - u16 op_mode; - struct anybuss_host *cd = client->host; - struct msg_anybus_init msg = { - .input_io_len = cpu_to_be16(cfg->input_io), - .input_dpram_len = cpu_to_be16(cfg->input_dpram), - .input_total_len = cpu_to_be16(cfg->input_total), - .output_io_len = cpu_to_be16(cfg->output_io), - .output_dpram_len = cpu_to_be16(cfg->output_dpram), - .output_total_len = cpu_to_be16(cfg->output_total), - .notif_config = cpu_to_be16(0x000F), - .wd_val = cpu_to_be16(0), - }; - - switch (cfg->offl_mode) { - case FIELDBUS_DEV_OFFL_MODE_CLEAR: - op_mode = 0; - break; - case FIELDBUS_DEV_OFFL_MODE_FREEZE: - op_mode = OP_MODE_FBFC; - break; - case FIELDBUS_DEV_OFFL_MODE_SET: - op_mode = OP_MODE_FBS; - break; - default: - return -EINVAL; - } - msg.op_mode = cpu_to_be16(op_mode | OP_MODE_CD); - ret = _anybus_mbox_cmd(cd, CMD_START_INIT, false, NULL, 0, - NULL, 0, NULL, 0); - if (ret) - return ret; - return _anybus_mbox_cmd(cd, CMD_ANYBUS_INIT, false, - &msg, sizeof(msg), NULL, 0, NULL, 0); -} -EXPORT_SYMBOL_GPL(anybuss_start_init); - -int anybuss_finish_init(struct anybuss_client *client) -{ - struct anybuss_host *cd = client->host; - - return _anybus_mbox_cmd(cd, CMD_END_INIT, false, NULL, 0, - NULL, 0, NULL, 0); -} -EXPORT_SYMBOL_GPL(anybuss_finish_init); - -int anybuss_read_fbctrl(struct anybuss_client *client, u16 addr, - void *buf, size_t count) -{ - struct anybuss_host *cd = client->host; - struct ab_task *t; - int ret; - - if (count == 0) - return 0; - if (!area_range_ok(addr, count, FBCTRL_AREA, - MAX_FBCTRL_AREA_SZ)) - return -EFAULT; - t = create_area_reader(cd->qcache, IND_AX_FBCTRL, addr, count); - if (!t) - return -ENOMEM; - ret = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq); - if (ret) - goto out; - memcpy(buf, t->area_pd.buf, count); -out: - ab_task_put(t); - return ret; -} -EXPORT_SYMBOL_GPL(anybuss_read_fbctrl); - -int anybuss_write_input(struct anybuss_client *client, - const char __user *buf, size_t size, - loff_t *offset) -{ - ssize_t len = min_t(loff_t, MAX_DATA_AREA_SZ - *offset, size); - struct anybuss_host *cd = client->host; - struct ab_task *t; - int ret; - - if (len <= 0) - return 0; - t = create_area_user_writer(cd->qcache, IND_AX_IN, - DATA_IN_AREA + *offset, buf, len); - if (IS_ERR(t)) - return PTR_ERR(t); - ret = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq); - ab_task_put(t); - if (ret) - return ret; - /* success */ - *offset += len; - return len; -} -EXPORT_SYMBOL_GPL(anybuss_write_input); - -int anybuss_read_output(struct anybuss_client *client, - char __user *buf, size_t size, - loff_t *offset) -{ - ssize_t len = min_t(loff_t, MAX_DATA_AREA_SZ - *offset, size); - struct anybuss_host *cd = client->host; - struct ab_task *t; - int ret; - - if (len <= 0) - return 0; - t = create_area_reader(cd->qcache, IND_AX_OUT, - DATA_OUT_AREA + *offset, len); - if (!t) - return -ENOMEM; - ret = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq); - if (ret) - goto out; - if (copy_to_user(buf, t->area_pd.buf, len)) - ret = -EFAULT; -out: - ab_task_put(t); - if (ret) - return ret; - /* success */ - *offset += len; - return len; -} -EXPORT_SYMBOL_GPL(anybuss_read_output); - -int anybuss_send_msg(struct anybuss_client *client, u16 cmd_num, - const void *buf, size_t count) -{ - struct anybuss_host *cd = client->host; - - return _anybus_mbox_cmd(cd, cmd_num, true, buf, count, NULL, 0, - NULL, 0); -} -EXPORT_SYMBOL_GPL(anybuss_send_msg); - -int anybuss_send_ext(struct anybuss_client *client, u16 cmd_num, - const void *buf, size_t count) -{ - struct anybuss_host *cd = client->host; - - return _anybus_mbox_cmd(cd, cmd_num, true, NULL, 0, NULL, 0, - buf, count); -} -EXPORT_SYMBOL_GPL(anybuss_send_ext); - -int anybuss_recv_msg(struct anybuss_client *client, u16 cmd_num, - void *buf, size_t count) -{ - struct anybuss_host *cd = client->host; - - return _anybus_mbox_cmd(cd, cmd_num, true, NULL, 0, buf, count, - NULL, 0); -} -EXPORT_SYMBOL_GPL(anybuss_recv_msg); - -/* ------------------------ bus functions ------------------------ */ - -static int anybus_bus_match(struct device *dev, - const struct device_driver *drv) -{ - const struct anybuss_client_driver *adrv = - to_anybuss_client_driver(drv); - struct anybuss_client *adev = - to_anybuss_client(dev); - - return adrv->anybus_id == be16_to_cpu(adev->anybus_id); -} - -static int anybus_bus_probe(struct device *dev) -{ - struct anybuss_client_driver *adrv = - to_anybuss_client_driver(dev->driver); - struct anybuss_client *adev = - to_anybuss_client(dev); - - return adrv->probe(adev); -} - -static void anybus_bus_remove(struct device *dev) -{ - struct anybuss_client_driver *adrv = - to_anybuss_client_driver(dev->driver); - - if (adrv->remove) - adrv->remove(to_anybuss_client(dev)); -} - -static const struct bus_type anybus_bus = { - .name = "anybuss", - .match = anybus_bus_match, - .probe = anybus_bus_probe, - .remove = anybus_bus_remove, -}; - -int anybuss_client_driver_register(struct anybuss_client_driver *drv) -{ - if (!drv->probe) - return -ENODEV; - - drv->driver.bus = &anybus_bus; - return driver_register(&drv->driver); -} -EXPORT_SYMBOL_GPL(anybuss_client_driver_register); - -void anybuss_client_driver_unregister(struct anybuss_client_driver *drv) -{ - return driver_unregister(&drv->driver); -} -EXPORT_SYMBOL_GPL(anybuss_client_driver_unregister); - -static void client_device_release(struct device *dev) -{ - kfree(to_anybuss_client(dev)); -} - -static int taskq_alloc(struct device *dev, struct kfifo *q) -{ - void *buf; - size_t size = 64 * sizeof(struct ab_task *); - - buf = devm_kzalloc(dev, size, GFP_KERNEL); - if (!buf) - return -EIO; - return kfifo_init(q, buf, size); -} - -static int anybus_of_get_host_idx(struct device_node *np) -{ - const __be32 *host_idx; - - host_idx = of_get_address(np, 0, NULL, NULL); - if (!host_idx) - return -ENOENT; - return __be32_to_cpu(*host_idx); -} - -static struct device_node * -anybus_of_find_child_device(struct device *dev, int host_idx) -{ - struct device_node *node; - - if (!dev || !dev->of_node) - return NULL; - for_each_child_of_node(dev->of_node, node) { - if (anybus_of_get_host_idx(node) == host_idx) - return node; - } - return NULL; -} - -struct anybuss_host * __must_check -anybuss_host_common_probe(struct device *dev, - const struct anybuss_ops *ops) -{ - int ret, i; - u8 val[4]; - __be16 fieldbus_type; - struct anybuss_host *cd; - - cd = devm_kzalloc(dev, sizeof(*cd), GFP_KERNEL); - if (!cd) - return ERR_PTR(-ENOMEM); - cd->dev = dev; - cd->host_idx = ops->host_idx; - init_completion(&cd->card_boot); - init_waitqueue_head(&cd->wq); - for (i = 0; i < ARRAY_SIZE(cd->qs); i++) { - ret = taskq_alloc(dev, &cd->qs[i]); - if (ret) - return ERR_PTR(ret); - } - if (WARN_ON(ARRAY_SIZE(cd->qs) < 3)) - return ERR_PTR(-EINVAL); - cd->powerq = &cd->qs[0]; - cd->mboxq = &cd->qs[1]; - cd->areaq = &cd->qs[2]; - cd->reset = ops->reset; - if (!cd->reset) - return ERR_PTR(-EINVAL); - cd->regmap = ops->regmap; - if (!cd->regmap) - return ERR_PTR(-EINVAL); - spin_lock_init(&cd->qlock); - cd->qcache = kmem_cache_create(dev_name(dev), - sizeof(struct ab_task), 0, 0, NULL); - if (!cd->qcache) - return ERR_PTR(-ENOMEM); - cd->irq = ops->irq; - if (cd->irq <= 0) { - ret = -EINVAL; - goto err_qcache; - } - /* - * use a dpram test to check if a card is present, this is only - * possible while in reset. - */ - reset_assert(cd); - if (test_dpram(cd->regmap)) { - dev_err(dev, "no Anybus-S card in slot"); - ret = -ENODEV; - goto err_qcache; - } - ret = devm_request_threaded_irq(dev, cd->irq, NULL, irq_handler, - IRQF_ONESHOT, dev_name(dev), cd); - if (ret) { - dev_err(dev, "could not request irq"); - goto err_qcache; - } - /* - * startup sequence: - * a) perform dummy IND_AB read to prevent false 'init done' irq - * (already done by test_dpram() above) - * b) release reset - * c) wait for first interrupt - * d) interrupt came in: ready to go ! - */ - reset_deassert(cd); - if (!wait_for_completion_timeout(&cd->card_boot, TIMEOUT)) { - ret = -ETIMEDOUT; - goto err_reset; - } - /* - * according to the anybus docs, we're allowed to read these - * without handshaking / reserving the area - */ - dev_info(dev, "Anybus-S card detected"); - regmap_bulk_read(cd->regmap, REG_BOOTLOADER_V, val, 2); - dev_info(dev, "Bootloader version: %02X%02X", - val[0], val[1]); - regmap_bulk_read(cd->regmap, REG_API_V, val, 2); - dev_info(dev, "API version: %02X%02X", val[0], val[1]); - regmap_bulk_read(cd->regmap, REG_FIELDBUS_V, val, 2); - dev_info(dev, "Fieldbus version: %02X%02X", val[0], val[1]); - regmap_bulk_read(cd->regmap, REG_SERIAL_NO, val, 4); - dev_info(dev, "Serial number: %02X%02X%02X%02X", - val[0], val[1], val[2], val[3]); - add_device_randomness(&val, 4); - regmap_bulk_read(cd->regmap, REG_FIELDBUS_TYPE, &fieldbus_type, - sizeof(fieldbus_type)); - dev_info(dev, "Fieldbus type: %04X", be16_to_cpu(fieldbus_type)); - regmap_bulk_read(cd->regmap, REG_MODULE_SW_V, val, 2); - dev_info(dev, "Module SW version: %02X%02X", - val[0], val[1]); - /* put card back reset until a client driver releases it */ - disable_irq(cd->irq); - reset_assert(cd); - atomic_set(&cd->ind_ab, IND_AB_UPDATED); - /* fire up the queue thread */ - cd->qthread = kthread_run(qthread_fn, cd, dev_name(dev)); - if (IS_ERR(cd->qthread)) { - dev_err(dev, "could not create kthread"); - ret = PTR_ERR(cd->qthread); - goto err_reset; - } - /* - * now advertise that we've detected a client device (card). - * the bus infrastructure will match it to a client driver. - */ - cd->client = kzalloc(sizeof(*cd->client), GFP_KERNEL); - if (!cd->client) { - ret = -ENOMEM; - goto err_kthread; - } - cd->client->anybus_id = fieldbus_type; - cd->client->host = cd; - cd->client->dev.bus = &anybus_bus; - cd->client->dev.parent = dev; - cd->client->dev.release = client_device_release; - cd->client->dev.of_node = - anybus_of_find_child_device(dev, cd->host_idx); - dev_set_name(&cd->client->dev, "anybuss.card%d", cd->host_idx); - ret = device_register(&cd->client->dev); - if (ret) - goto err_device; - return cd; -err_device: - put_device(&cd->client->dev); -err_kthread: - kthread_stop(cd->qthread); -err_reset: - reset_assert(cd); -err_qcache: - kmem_cache_destroy(cd->qcache); - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(anybuss_host_common_probe); - -void anybuss_host_common_remove(struct anybuss_host *host) -{ - struct anybuss_host *cd = host; - - device_unregister(&cd->client->dev); - kthread_stop(cd->qthread); - reset_assert(cd); - kmem_cache_destroy(cd->qcache); -} -EXPORT_SYMBOL_GPL(anybuss_host_common_remove); - -static void host_release(void *res) -{ - anybuss_host_common_remove(res); -} - -struct anybuss_host * __must_check -devm_anybuss_host_common_probe(struct device *dev, - const struct anybuss_ops *ops) -{ - struct anybuss_host *host; - int ret; - - host = anybuss_host_common_probe(dev, ops); - if (IS_ERR(host)) - return host; - - ret = devm_add_action_or_reset(dev, host_release, host); - if (ret) - return ERR_PTR(ret); - - return host; -} -EXPORT_SYMBOL_GPL(devm_anybuss_host_common_probe); - -static int __init anybus_init(void) -{ - int ret; - - ret = bus_register(&anybus_bus); - if (ret) - pr_err("could not register Anybus-S bus: %d\n", ret); - return ret; -} -module_init(anybus_init); - -static void __exit anybus_exit(void) -{ - bus_unregister(&anybus_bus); -} -module_exit(anybus_exit); - -MODULE_DESCRIPTION("HMS Anybus-S Host Driver"); -MODULE_AUTHOR("Sven Van Asbroeck "); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/fieldbus/dev_core.c b/drivers/staging/fieldbus/dev_core.c deleted file mode 100644 index 0053ebd91442de..00000000000000 --- a/drivers/staging/fieldbus/dev_core.c +++ /dev/null @@ -1,344 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Fieldbus Device Driver Core - * - */ - -#include -#include -#include -#include -#include -#include -#include - -/* move to when taking this out of staging */ -#include "fieldbus_dev.h" - -/* Maximum number of fieldbus devices */ -#define MAX_FIELDBUSES 32 - -/* the dev_t structure to store the dynamically allocated fieldbus devices */ -static dev_t fieldbus_devt; -static DEFINE_IDA(fieldbus_ida); -static DEFINE_MUTEX(fieldbus_mtx); - -static ssize_t online_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fieldbus_dev *fb = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%d\n", !!fb->online); -} -static DEVICE_ATTR_RO(online); - -static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fieldbus_dev *fb = dev_get_drvdata(dev); - - if (!fb->enable_get) - return -EINVAL; - return sysfs_emit(buf, "%d\n", !!fb->enable_get(fb)); -} - -static ssize_t enabled_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct fieldbus_dev *fb = dev_get_drvdata(dev); - bool value; - int ret; - - if (!fb->simple_enable_set) - return -ENOTSUPP; - ret = kstrtobool(buf, &value); - if (ret) - return ret; - ret = fb->simple_enable_set(fb, value); - if (ret < 0) - return ret; - return n; -} -static DEVICE_ATTR_RW(enabled); - -static ssize_t card_name_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fieldbus_dev *fb = dev_get_drvdata(dev); - - /* card_name was provided by child driver. */ - return sysfs_emit(buf, "%s\n", fb->card_name); -} -static DEVICE_ATTR_RO(card_name); - -static ssize_t read_area_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fieldbus_dev *fb = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%zu\n", fb->read_area_sz); -} -static DEVICE_ATTR_RO(read_area_size); - -static ssize_t write_area_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fieldbus_dev *fb = dev_get_drvdata(dev); - - return sysfs_emit(buf, "%zu\n", fb->write_area_sz); -} -static DEVICE_ATTR_RO(write_area_size); - -static ssize_t fieldbus_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fieldbus_dev *fb = dev_get_drvdata(dev); - - return fb->fieldbus_id_get(fb, buf, PAGE_SIZE); -} -static DEVICE_ATTR_RO(fieldbus_id); - -static ssize_t fieldbus_type_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fieldbus_dev *fb = dev_get_drvdata(dev); - const char *t; - - switch (fb->fieldbus_type) { - case FIELDBUS_DEV_TYPE_PROFINET: - t = "profinet"; - break; - default: - t = "unknown"; - break; - } - - return sysfs_emit(buf, "%s\n", t); -} -static DEVICE_ATTR_RO(fieldbus_type); - -static struct attribute *fieldbus_attrs[] = { - &dev_attr_enabled.attr, - &dev_attr_card_name.attr, - &dev_attr_fieldbus_id.attr, - &dev_attr_read_area_size.attr, - &dev_attr_write_area_size.attr, - &dev_attr_online.attr, - &dev_attr_fieldbus_type.attr, - NULL, -}; - -static umode_t fieldbus_is_visible(struct kobject *kobj, struct attribute *attr, - int n) -{ - struct device *dev = kobj_to_dev(kobj); - struct fieldbus_dev *fb = dev_get_drvdata(dev); - umode_t mode = attr->mode; - - if (attr == &dev_attr_enabled.attr) { - mode = 0; - if (fb->enable_get) - mode |= 0444; - if (fb->simple_enable_set) - mode |= 0200; - } - - return mode; -} - -static const struct attribute_group fieldbus_group = { - .attrs = fieldbus_attrs, - .is_visible = fieldbus_is_visible, -}; -__ATTRIBUTE_GROUPS(fieldbus); - -static const struct class fieldbus_class = { - .name = "fieldbus_dev", - .dev_groups = fieldbus_groups, -}; - -struct fb_open_file { - struct fieldbus_dev *fbdev; - int dc_event; -}; - -static int fieldbus_open(struct inode *inode, struct file *filp) -{ - struct fb_open_file *of; - struct fieldbus_dev *fbdev = container_of(inode->i_cdev, - struct fieldbus_dev, - cdev); - - of = kzalloc(sizeof(*of), GFP_KERNEL); - if (!of) - return -ENOMEM; - of->fbdev = fbdev; - filp->private_data = of; - return 0; -} - -static int fieldbus_release(struct inode *node, struct file *filp) -{ - struct fb_open_file *of = filp->private_data; - - kfree(of); - return 0; -} - -static ssize_t fieldbus_read(struct file *filp, char __user *buf, size_t size, - loff_t *offset) -{ - struct fb_open_file *of = filp->private_data; - struct fieldbus_dev *fbdev = of->fbdev; - - of->dc_event = fbdev->dc_event; - return fbdev->read_area(fbdev, buf, size, offset); -} - -static ssize_t fieldbus_write(struct file *filp, const char __user *buf, - size_t size, loff_t *offset) -{ - struct fb_open_file *of = filp->private_data; - struct fieldbus_dev *fbdev = of->fbdev; - - return fbdev->write_area(fbdev, buf, size, offset); -} - -static __poll_t fieldbus_poll(struct file *filp, poll_table *wait) -{ - struct fb_open_file *of = filp->private_data; - struct fieldbus_dev *fbdev = of->fbdev; - __poll_t mask = EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM; - - poll_wait(filp, &fbdev->dc_wq, wait); - /* data changed ? */ - if (fbdev->dc_event != of->dc_event) - mask |= EPOLLPRI | EPOLLERR; - return mask; -} - -static const struct file_operations fieldbus_fops = { - .open = fieldbus_open, - .release = fieldbus_release, - .read = fieldbus_read, - .write = fieldbus_write, - .poll = fieldbus_poll, - .llseek = generic_file_llseek, - .owner = THIS_MODULE, -}; - -void fieldbus_dev_area_updated(struct fieldbus_dev *fb) -{ - fb->dc_event++; - wake_up_all(&fb->dc_wq); -} -EXPORT_SYMBOL_GPL(fieldbus_dev_area_updated); - -void fieldbus_dev_online_changed(struct fieldbus_dev *fb, bool online) -{ - fb->online = online; - kobject_uevent(&fb->dev->kobj, KOBJ_CHANGE); -} -EXPORT_SYMBOL_GPL(fieldbus_dev_online_changed); - -static void __fieldbus_dev_unregister(struct fieldbus_dev *fb) -{ - if (!fb) - return; - device_destroy(&fieldbus_class, fb->cdev.dev); - cdev_del(&fb->cdev); - ida_free(&fieldbus_ida, fb->id); -} - -void fieldbus_dev_unregister(struct fieldbus_dev *fb) -{ - mutex_lock(&fieldbus_mtx); - __fieldbus_dev_unregister(fb); - mutex_unlock(&fieldbus_mtx); -} -EXPORT_SYMBOL_GPL(fieldbus_dev_unregister); - -static int __fieldbus_dev_register(struct fieldbus_dev *fb) -{ - dev_t devno; - int err; - - if (!fb) - return -EINVAL; - if (!fb->read_area || !fb->write_area || !fb->fieldbus_id_get) - return -EINVAL; - fb->id = ida_alloc_max(&fieldbus_ida, MAX_FIELDBUSES - 1, GFP_KERNEL); - if (fb->id < 0) - return fb->id; - devno = MKDEV(MAJOR(fieldbus_devt), fb->id); - init_waitqueue_head(&fb->dc_wq); - cdev_init(&fb->cdev, &fieldbus_fops); - err = cdev_add(&fb->cdev, devno, 1); - if (err) { - pr_err("fieldbus_dev%d unable to add device %d:%d\n", - fb->id, MAJOR(fieldbus_devt), fb->id); - goto err_cdev; - } - fb->dev = device_create(&fieldbus_class, fb->parent, devno, fb, - "fieldbus_dev%d", fb->id); - if (IS_ERR(fb->dev)) { - err = PTR_ERR(fb->dev); - goto err_dev_create; - } - return 0; - -err_dev_create: - cdev_del(&fb->cdev); -err_cdev: - ida_free(&fieldbus_ida, fb->id); - return err; -} - -int fieldbus_dev_register(struct fieldbus_dev *fb) -{ - int err; - - mutex_lock(&fieldbus_mtx); - err = __fieldbus_dev_register(fb); - mutex_unlock(&fieldbus_mtx); - - return err; -} -EXPORT_SYMBOL_GPL(fieldbus_dev_register); - -static int __init fieldbus_init(void) -{ - int err; - - err = class_register(&fieldbus_class); - if (err < 0) { - pr_err("fieldbus_dev: could not register class\n"); - return err; - } - err = alloc_chrdev_region(&fieldbus_devt, 0, - MAX_FIELDBUSES, "fieldbus_dev"); - if (err < 0) { - pr_err("fieldbus_dev: unable to allocate char dev region\n"); - goto err_alloc; - } - return 0; - -err_alloc: - class_unregister(&fieldbus_class); - return err; -} - -static void __exit fieldbus_exit(void) -{ - unregister_chrdev_region(fieldbus_devt, MAX_FIELDBUSES); - class_unregister(&fieldbus_class); - ida_destroy(&fieldbus_ida); -} - -subsys_initcall(fieldbus_init); -module_exit(fieldbus_exit); - -MODULE_AUTHOR("Sven Van Asbroeck "); -MODULE_AUTHOR("Jonathan Stiles "); -MODULE_DESCRIPTION("Fieldbus Device Driver Core"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/fieldbus/fieldbus_dev.h b/drivers/staging/fieldbus/fieldbus_dev.h deleted file mode 100644 index 301dca3b8d71a7..00000000000000 --- a/drivers/staging/fieldbus/fieldbus_dev.h +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Fieldbus Device Driver Core - * - */ - -#ifndef __FIELDBUS_DEV_H -#define __FIELDBUS_DEV_H - -#include -#include - -enum fieldbus_dev_type { - FIELDBUS_DEV_TYPE_UNKNOWN = 0, - FIELDBUS_DEV_TYPE_PROFINET, -}; - -enum fieldbus_dev_offl_mode { - FIELDBUS_DEV_OFFL_MODE_CLEAR = 0, - FIELDBUS_DEV_OFFL_MODE_FREEZE, - FIELDBUS_DEV_OFFL_MODE_SET -}; - -/** - * struct fieldbus_dev - Fieldbus device - * @read_area: [DRIVER] function to read the process data area of the - * device. same parameters/return values as - * the read function in struct file_operations - * @write_area: [DRIVER] function to write to the process data area of - * the device. same parameters/return values as - * the write function in struct file_operations - * @write_area_sz [DRIVER] size of the writable process data area - * @read_area_sz [DRIVER] size of the readable process data area - * @card_name [DRIVER] name of the card, e.g. "ACME Inc. profinet" - * @fieldbus_type [DRIVER] fieldbus type of this device, e.g. - * FIELDBUS_DEV_TYPE_PROFINET - * @enable_get [DRIVER] function which returns true if the card - * is enabled, false otherwise - * @fieldbus_id_get [DRIVER] function to retrieve the unique fieldbus id - * by which this device can be identified; - * return value follows the snprintf convention - * @simple_enable_set [DRIVER] (optional) function to enable the device - * according to its default settings - * @parent [DRIVER] (optional) the device's parent device - */ -struct fieldbus_dev { - ssize_t (*read_area)(struct fieldbus_dev *fbdev, char __user *buf, - size_t size, loff_t *offset); - ssize_t (*write_area)(struct fieldbus_dev *fbdev, - const char __user *buf, size_t size, - loff_t *offset); - size_t write_area_sz, read_area_sz; - const char *card_name; - enum fieldbus_dev_type fieldbus_type; - bool (*enable_get)(struct fieldbus_dev *fbdev); - int (*fieldbus_id_get)(struct fieldbus_dev *fbdev, char *buf, - size_t max_size); - int (*simple_enable_set)(struct fieldbus_dev *fbdev, bool enable); - struct device *parent; - - /* private data */ - int id; - struct cdev cdev; - struct device *dev; - int dc_event; - wait_queue_head_t dc_wq; - bool online; -}; - -#if IS_ENABLED(CONFIG_FIELDBUS_DEV) - -/** - * fieldbus_dev_unregister() - * - unregister a previously registered fieldbus device - * @fb: Device structure previously registered - **/ -void fieldbus_dev_unregister(struct fieldbus_dev *fb); - -/** - * fieldbus_dev_register() - * - register a device with the fieldbus device subsystem - * @fb: Device structure filled by the device driver - **/ -int __must_check fieldbus_dev_register(struct fieldbus_dev *fb); - -/** - * fieldbus_dev_area_updated() - * - notify the subsystem that an external fieldbus controller updated - * the process data area - * @fb: Device structure - **/ -void fieldbus_dev_area_updated(struct fieldbus_dev *fb); - -/** - * fieldbus_dev_online_changed() - * - notify the subsystem that the fieldbus online status changed - * @fb: Device structure - **/ -void fieldbus_dev_online_changed(struct fieldbus_dev *fb, bool online); - -#else /* IS_ENABLED(CONFIG_FIELDBUS_DEV) */ - -static inline void fieldbus_dev_unregister(struct fieldbus_dev *fb) {} -static inline int __must_check fieldbus_dev_register(struct fieldbus_dev *fb) -{ - return -ENOTSUPP; -} - -static inline void fieldbus_dev_area_updated(struct fieldbus_dev *fb) {} -static inline void fieldbus_dev_online_changed(struct fieldbus_dev *fb, - bool online) {} - -#endif /* IS_ENABLED(CONFIG_FIELDBUS_DEV) */ -#endif /* __FIELDBUS_DEV_H */ diff --git a/drivers/staging/gdm724x/Kconfig b/drivers/staging/gdm724x/Kconfig deleted file mode 100644 index 1f403ecd9608b4..00000000000000 --- a/drivers/staging/gdm724x/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# GCT GDM724x LTE driver configuration -# - -config LTE_GDM724X - tristate "GCT GDM724x LTE support" - depends on NET && USB && TTY && m - help - This driver supports GCT GDM724x LTE chip based USB modem devices. - It exposes 4 network devices to be used per PDN and 2 tty devices to be - used for AT commands and DM monitoring applications. - The modules will be called gdmulte.ko and gdmtty.ko - - GCT-ATCx can be used for AT Commands - GCT-DMx can be used for LTE protocol monitoring diff --git a/drivers/staging/gdm724x/Makefile b/drivers/staging/gdm724x/Makefile deleted file mode 100644 index e61b95788c9fca..00000000000000 --- a/drivers/staging/gdm724x/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_LTE_GDM724X) := gdmulte.o -gdmulte-y += gdm_lte.o netlink_k.o -gdmulte-y += gdm_usb.o gdm_endian.o - -obj-$(CONFIG_LTE_GDM724X) += gdmtty.o -gdmtty-y := gdm_tty.o gdm_mux.o - diff --git a/drivers/staging/gdm724x/TODO b/drivers/staging/gdm724x/TODO deleted file mode 100644 index b2b571ecb063f7..00000000000000 --- a/drivers/staging/gdm724x/TODO +++ /dev/null @@ -1,16 +0,0 @@ -TODO: -- Clean up coding style to meet kernel standard. (80 line limit, netdev_err) -- Remove test for host endian -- Remove confusing macros (endian, hci_send, sdu_send, rcv_with_cb) -- Fixes for every instances of function returning -1 -- Check for skb->len in gdm_lte_emulate_arp() -- Use ALIGN() macro for dummy_cnt in up_to_host() -- Error handling in init_usb() -- Explain reason for multiples of 512 bytes in alloc_tx_struct() -- Review use of atomic allocation for tx structs -- No error checking for alloc_tx_struct in do_tx() -- fix up static tty port allocation to be dynamic - -Patches to: - Jonathan Kim - Dean ahn diff --git a/drivers/staging/gdm724x/gdm_endian.c b/drivers/staging/gdm724x/gdm_endian.c deleted file mode 100644 index ae39e59daf7074..00000000000000 --- a/drivers/staging/gdm724x/gdm_endian.c +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#include -#include "gdm_endian.h" - -__dev16 gdm_cpu_to_dev16(u8 dev_ed, u16 x) -{ - if (dev_ed == ENDIANNESS_LITTLE) - return (__force __dev16)cpu_to_le16(x); - else - return (__force __dev16)cpu_to_be16(x); -} - -u16 gdm_dev16_to_cpu(u8 dev_ed, __dev16 x) -{ - if (dev_ed == ENDIANNESS_LITTLE) - return le16_to_cpu((__force __le16)x); - else - return be16_to_cpu((__force __be16)x); -} - -__dev32 gdm_cpu_to_dev32(u8 dev_ed, u32 x) -{ - if (dev_ed == ENDIANNESS_LITTLE) - return (__force __dev32)cpu_to_le32(x); - else - return (__force __dev32)cpu_to_be32(x); -} - -u32 gdm_dev32_to_cpu(u8 dev_ed, __dev32 x) -{ - if (dev_ed == ENDIANNESS_LITTLE) - return le32_to_cpu((__force __le32)x); - else - return be32_to_cpu((__force __be32)x); -} diff --git a/drivers/staging/gdm724x/gdm_endian.h b/drivers/staging/gdm724x/gdm_endian.h deleted file mode 100644 index f373dc3a19bf3e..00000000000000 --- a/drivers/staging/gdm724x/gdm_endian.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#ifndef __GDM_ENDIAN_H__ -#define __GDM_ENDIAN_H__ - -#include - -/* - * For data in "device-endian" byte order (device endianness is model - * dependent). Analogous to __leXX or __beXX. - */ -typedef __u32 __bitwise __dev32; -typedef __u16 __bitwise __dev16; - -enum { - ENDIANNESS_MIN = 0, - ENDIANNESS_UNKNOWN, - ENDIANNESS_LITTLE, - ENDIANNESS_BIG, - ENDIANNESS_MIDDLE, - ENDIANNESS_MAX -}; - -__dev16 gdm_cpu_to_dev16(u8 dev_ed, u16 x); -u16 gdm_dev16_to_cpu(u8 dev_ed, __dev16 x); -__dev32 gdm_cpu_to_dev32(u8 dev_ed, u32 x); -u32 gdm_dev32_to_cpu(u8 dev_ed, __dev32 x); - -#endif /*__GDM_ENDIAN_H__*/ diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c deleted file mode 100644 index eb754b231429be..00000000000000 --- a/drivers/staging/gdm724x/gdm_lte.c +++ /dev/null @@ -1,937 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gdm_lte.h" -#include "netlink_k.h" -#include "hci.h" -#include "hci_packet.h" -#include "gdm_endian.h" - -/* - * Netlink protocol number - */ -#define NETLINK_LTE 30 - -/* - * Default MTU Size - */ -#define DEFAULT_MTU_SIZE 1500 - -#define IP_VERSION_4 4 -#define IP_VERSION_6 6 - -static struct { - int ref_cnt; - struct sock *sock; -} lte_event; - -static const struct device_type wwan_type = { - .name = "wwan", -}; - -static int gdm_lte_open(struct net_device *dev) -{ - netif_start_queue(dev); - return 0; -} - -static int gdm_lte_close(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -static int gdm_lte_set_config(struct net_device *dev, struct ifmap *map) -{ - if (dev->flags & IFF_UP) - return -EBUSY; - return 0; -} - -static void tx_complete(void *arg) -{ - struct nic *nic = arg; - - if (netif_queue_stopped(nic->netdev)) - netif_wake_queue(nic->netdev); -} - -static int gdm_lte_rx(struct sk_buff *skb, struct nic *nic, int nic_type) -{ - int ret, len; - - len = skb->len + ETH_HLEN; - ret = netif_rx(skb); - if (ret == NET_RX_DROP) { - nic->stats.rx_dropped++; - } else { - nic->stats.rx_packets++; - nic->stats.rx_bytes += len; - } - - return 0; -} - -static int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type) -{ - struct nic *nic = netdev_priv(skb_in->dev); - struct sk_buff *skb_out; - struct ethhdr eth; - struct vlan_ethhdr vlan_eth; - struct arphdr *arp_in; - struct arphdr *arp_out; - struct arpdata { - u8 ar_sha[ETH_ALEN]; - u8 ar_sip[4]; - u8 ar_tha[ETH_ALEN]; - u8 ar_tip[4]; - }; - struct arpdata *arp_data_in; - struct arpdata *arp_data_out; - u8 arp_temp[60]; - void *mac_header_data; - u32 mac_header_len; - - /* Check for skb->len, discard if empty */ - if (skb_in->len == 0) - return -ENODATA; - - /* Format the mac header so that it can be put to skb */ - if (ntohs(((struct ethhdr *)skb_in->data)->h_proto) == ETH_P_8021Q) { - memcpy(&vlan_eth, skb_in->data, sizeof(struct vlan_ethhdr)); - mac_header_data = &vlan_eth; - mac_header_len = VLAN_ETH_HLEN; - } else { - memcpy(ð, skb_in->data, sizeof(struct ethhdr)); - mac_header_data = ð - mac_header_len = ETH_HLEN; - } - - /* Get the pointer of the original request */ - arp_in = (struct arphdr *)(skb_in->data + mac_header_len); - arp_data_in = (struct arpdata *)(skb_in->data + mac_header_len + - sizeof(struct arphdr)); - - /* Get the pointer of the outgoing response */ - arp_out = (struct arphdr *)arp_temp; - arp_data_out = (struct arpdata *)(arp_temp + sizeof(struct arphdr)); - - /* Copy the arp header */ - memcpy(arp_out, arp_in, sizeof(struct arphdr)); - arp_out->ar_op = htons(ARPOP_REPLY); - - /* Copy the arp payload: based on 2 bytes of mac and fill the IP */ - arp_data_out->ar_sha[0] = arp_data_in->ar_sha[0]; - arp_data_out->ar_sha[1] = arp_data_in->ar_sha[1]; - memcpy(&arp_data_out->ar_sha[2], &arp_data_in->ar_tip[0], 4); - memcpy(&arp_data_out->ar_sip[0], &arp_data_in->ar_tip[0], 4); - memcpy(&arp_data_out->ar_tha[0], &arp_data_in->ar_sha[0], 6); - memcpy(&arp_data_out->ar_tip[0], &arp_data_in->ar_sip[0], 4); - - /* Fill the destination mac with source mac of the received packet */ - memcpy(mac_header_data, mac_header_data + ETH_ALEN, ETH_ALEN); - /* Fill the source mac with nic's source mac */ - memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN); - - /* Alloc skb and reserve align */ - skb_out = dev_alloc_skb(skb_in->len); - if (!skb_out) - return -ENOMEM; - skb_reserve(skb_out, NET_IP_ALIGN); - - skb_put_data(skb_out, mac_header_data, mac_header_len); - skb_put_data(skb_out, arp_out, sizeof(struct arphdr)); - skb_put_data(skb_out, arp_data_out, sizeof(struct arpdata)); - - skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto; - skb_out->dev = skb_in->dev; - skb_reset_mac_header(skb_out); - skb_pull(skb_out, ETH_HLEN); - - gdm_lte_rx(skb_out, nic, nic_type); - - return 0; -} - -static __sum16 icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len) -{ - unsigned short *w; - __wsum sum = 0; - int i; - u16 pa; - - union { - struct { - u8 ph_src[16]; - u8 ph_dst[16]; - u32 ph_len; - u8 ph_zero[3]; - u8 ph_nxt; - } ph __packed; - u16 pa[20]; - } pseudo_header; - - memset(&pseudo_header, 0, sizeof(pseudo_header)); - memcpy(&pseudo_header.ph.ph_src, &ipv6->saddr.in6_u.u6_addr8, 16); - memcpy(&pseudo_header.ph.ph_dst, &ipv6->daddr.in6_u.u6_addr8, 16); - pseudo_header.ph.ph_len = be16_to_cpu(ipv6->payload_len); - pseudo_header.ph.ph_nxt = ipv6->nexthdr; - - for (i = 0; i < ARRAY_SIZE(pseudo_header.pa); i++) { - pa = pseudo_header.pa[i]; - sum = csum_add(sum, csum_unfold((__force __sum16)pa)); - } - - w = ptr; - while (len > 1) { - sum = csum_add(sum, csum_unfold((__force __sum16)*w++)); - len -= 2; - } - - return csum_fold(sum); -} - -static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) -{ - struct nic *nic = netdev_priv(skb_in->dev); - struct sk_buff *skb_out; - struct ethhdr eth; - struct vlan_ethhdr vlan_eth; - struct neighbour_advertisement { - u8 target_address[16]; - u8 type; - u8 length; - u8 link_layer_address[6]; - }; - struct neighbour_advertisement na; - struct neighbour_solicitation { - u8 target_address[16]; - }; - struct neighbour_solicitation *ns; - struct ipv6hdr *ipv6_in; - struct ipv6hdr ipv6_out; - struct icmp6hdr *icmp6_in; - struct icmp6hdr icmp6_out; - - void *mac_header_data; - u32 mac_header_len; - - /* Format the mac header so that it can be put to skb */ - if (ntohs(((struct ethhdr *)skb_in->data)->h_proto) == ETH_P_8021Q) { - memcpy(&vlan_eth, skb_in->data, sizeof(struct vlan_ethhdr)); - if (ntohs(vlan_eth.h_vlan_encapsulated_proto) != ETH_P_IPV6) - return -EPROTONOSUPPORT; - mac_header_data = &vlan_eth; - mac_header_len = VLAN_ETH_HLEN; - } else { - memcpy(ð, skb_in->data, sizeof(struct ethhdr)); - if (ntohs(eth.h_proto) != ETH_P_IPV6) - return -EPROTONOSUPPORT; - mac_header_data = ð - mac_header_len = ETH_HLEN; - } - - /* Check if this is IPv6 ICMP packet */ - ipv6_in = (struct ipv6hdr *)(skb_in->data + mac_header_len); - if (ipv6_in->version != 6 || ipv6_in->nexthdr != IPPROTO_ICMPV6) - return -EPROTONOSUPPORT; - - /* Check if this is NDP packet */ - icmp6_in = (struct icmp6hdr *)(skb_in->data + mac_header_len + - sizeof(struct ipv6hdr)); - if (icmp6_in->icmp6_type == NDISC_ROUTER_SOLICITATION) { /* Check RS */ - return -EPROTONOSUPPORT; - } else if (icmp6_in->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { - /* Check NS */ - u8 icmp_na[sizeof(struct icmp6hdr) + - sizeof(struct neighbour_advertisement)]; - u8 zero_addr8[16] = {0,}; - - if (memcmp(ipv6_in->saddr.in6_u.u6_addr8, zero_addr8, 16) == 0) - /* Duplicate Address Detection: Source IP is all zero */ - return 0; - - icmp6_out.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT; - icmp6_out.icmp6_code = 0; - icmp6_out.icmp6_cksum = 0; - /* R=0, S=1, O=1 */ - icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000); - - ns = (struct neighbour_solicitation *) - (skb_in->data + mac_header_len + - sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr)); - memcpy(&na.target_address, ns->target_address, 16); - na.type = 0x02; - na.length = 1; - na.link_layer_address[0] = 0x00; - na.link_layer_address[1] = 0x0a; - na.link_layer_address[2] = 0x3b; - na.link_layer_address[3] = 0xaf; - na.link_layer_address[4] = 0x63; - na.link_layer_address[5] = 0xc7; - - memcpy(&ipv6_out, ipv6_in, sizeof(struct ipv6hdr)); - memcpy(ipv6_out.saddr.in6_u.u6_addr8, &na.target_address, 16); - memcpy(ipv6_out.daddr.in6_u.u6_addr8, - ipv6_in->saddr.in6_u.u6_addr8, 16); - ipv6_out.payload_len = htons(sizeof(struct icmp6hdr) + - sizeof(struct neighbour_advertisement)); - - memcpy(icmp_na, &icmp6_out, sizeof(struct icmp6hdr)); - memcpy(icmp_na + sizeof(struct icmp6hdr), &na, - sizeof(struct neighbour_advertisement)); - - icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out, - (u16 *)icmp_na, - sizeof(icmp_na)); - } else { - return -EINVAL; - } - - /* Fill the destination mac with source mac of the received packet */ - memcpy(mac_header_data, mac_header_data + ETH_ALEN, ETH_ALEN); - /* Fill the source mac with nic's source mac */ - memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN); - - /* Alloc skb and reserve align */ - skb_out = dev_alloc_skb(skb_in->len); - if (!skb_out) - return -ENOMEM; - skb_reserve(skb_out, NET_IP_ALIGN); - - skb_put_data(skb_out, mac_header_data, mac_header_len); - skb_put_data(skb_out, &ipv6_out, sizeof(struct ipv6hdr)); - skb_put_data(skb_out, &icmp6_out, sizeof(struct icmp6hdr)); - skb_put_data(skb_out, &na, sizeof(struct neighbour_advertisement)); - - skb_out->protocol = ((struct ethhdr *)mac_header_data)->h_proto; - skb_out->dev = skb_in->dev; - skb_reset_mac_header(skb_out); - skb_pull(skb_out, ETH_HLEN); - - gdm_lte_rx(skb_out, nic, nic_type); - - return 0; -} - -static s32 gdm_lte_tx_nic_type(struct net_device *dev, struct sk_buff *skb) -{ - struct nic *nic = netdev_priv(dev); - struct ethhdr *eth; - struct vlan_ethhdr *vlan_eth; - struct iphdr *ip; - struct ipv6hdr *ipv6; - int mac_proto; - void *network_data; - u32 nic_type; - - /* NIC TYPE is based on the nic_id of this net_device */ - nic_type = 0x00000010 | nic->nic_id; - - /* Get ethernet protocol */ - eth = (struct ethhdr *)skb->data; - if (ntohs(eth->h_proto) == ETH_P_8021Q) { - vlan_eth = skb_vlan_eth_hdr(skb); - mac_proto = ntohs(vlan_eth->h_vlan_encapsulated_proto); - network_data = skb->data + VLAN_ETH_HLEN; - nic_type |= NIC_TYPE_F_VLAN; - } else { - mac_proto = ntohs(eth->h_proto); - network_data = skb->data + ETH_HLEN; - } - - /* Process packet for nic type */ - switch (mac_proto) { - case ETH_P_ARP: - nic_type |= NIC_TYPE_ARP; - break; - case ETH_P_IP: - nic_type |= NIC_TYPE_F_IPV4; - ip = network_data; - - /* Check DHCPv4 */ - if (ip->protocol == IPPROTO_UDP) { - struct udphdr *udp = - network_data + sizeof(struct iphdr); - if (ntohs(udp->dest) == 67 || ntohs(udp->dest) == 68) - nic_type |= NIC_TYPE_F_DHCP; - } - break; - case ETH_P_IPV6: - nic_type |= NIC_TYPE_F_IPV6; - ipv6 = network_data; - - if (ipv6->nexthdr == IPPROTO_ICMPV6) /* Check NDP request */ { - struct icmp6hdr *icmp6 = - network_data + sizeof(struct ipv6hdr); - if (icmp6->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) - nic_type |= NIC_TYPE_ICMPV6; - } else if (ipv6->nexthdr == IPPROTO_UDP) /* Check DHCPv6 */ { - struct udphdr *udp = - network_data + sizeof(struct ipv6hdr); - if (ntohs(udp->dest) == 546 || ntohs(udp->dest) == 547) - nic_type |= NIC_TYPE_F_DHCP; - } - break; - default: - break; - } - - return nic_type; -} - -static netdev_tx_t gdm_lte_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct nic *nic = netdev_priv(dev); - u32 nic_type; - void *data_buf; - int data_len; - int idx; - int ret = 0; - - nic_type = gdm_lte_tx_nic_type(dev, skb); - if (nic_type == 0) { - netdev_err(dev, "tx - invalid nic_type\n"); - return -EMEDIUMTYPE; - } - - if (nic_type & NIC_TYPE_ARP) { - if (gdm_lte_emulate_arp(skb, nic_type) == 0) { - dev_kfree_skb(skb); - return 0; - } - } - - if (nic_type & NIC_TYPE_ICMPV6) { - if (gdm_lte_emulate_ndp(skb, nic_type) == 0) { - dev_kfree_skb(skb); - return 0; - } - } - - /* - * Need byte shift (that is, remove VLAN tag) if there is one - * For the case of ARP, this breaks the offset as vlan_ethhdr+4 - * is treated as ethhdr However, it shouldn't be a problem as - * the response starts from arp_hdr and ethhdr is created by this - * driver based on the NIC mac - */ - if (nic_type & NIC_TYPE_F_VLAN) { - struct vlan_ethhdr *vlan_eth = skb_vlan_eth_hdr(skb); - - nic->vlan_id = ntohs(vlan_eth->h_vlan_TCI) & VLAN_VID_MASK; - data_buf = skb->data + (VLAN_ETH_HLEN - ETH_HLEN); - data_len = skb->len - (VLAN_ETH_HLEN - ETH_HLEN); - } else { - nic->vlan_id = 0; - data_buf = skb->data; - data_len = skb->len; - } - - /* If it is a ICMPV6 packet, clear all the other bits : - * for backward compatibility with the firmware - */ - if (nic_type & NIC_TYPE_ICMPV6) - nic_type = NIC_TYPE_ICMPV6; - - /* If it is not a dhcp packet, clear all the flag bits : - * original NIC, otherwise the special flag (IPVX | DHCP) - */ - if (!(nic_type & NIC_TYPE_F_DHCP)) - nic_type &= NIC_TYPE_MASK; - - ret = sscanf(dev->name, "lte%d", &idx); - if (ret != 1) { - dev_kfree_skb(skb); - return -EINVAL; - } - - ret = nic->phy_dev->send_sdu_func(nic->phy_dev->priv_dev, - data_buf, data_len, - nic->pdn_table.dft_eps_id, 0, - tx_complete, nic, idx, - nic_type); - - if (ret == TX_NO_BUFFER || ret == TX_NO_SPC) { - netif_stop_queue(dev); - if (ret == TX_NO_BUFFER) - ret = 0; - else - ret = -ENOSPC; - } else if (ret == TX_NO_DEV) { - ret = -ENODEV; - } - - /* Updates tx stats */ - if (ret) { - nic->stats.tx_dropped++; - } else { - nic->stats.tx_packets++; - nic->stats.tx_bytes += data_len; - } - dev_kfree_skb(skb); - - return 0; -} - -static struct net_device_stats *gdm_lte_stats(struct net_device *dev) -{ - struct nic *nic = netdev_priv(dev); - - return &nic->stats; -} - -static int gdm_lte_event_send(struct net_device *dev, char *buf, int len) -{ - struct phy_dev *phy_dev = ((struct nic *)netdev_priv(dev))->phy_dev; - struct hci_packet *hci = (struct hci_packet *)buf; - int length; - int idx; - int ret; - - ret = sscanf(dev->name, "lte%d", &idx); - if (ret != 1) - return -EINVAL; - - length = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), - hci->len) + HCI_HEADER_SIZE; - return netlink_send(lte_event.sock, idx, 0, buf, length, dev); -} - -static void gdm_lte_event_rcv(struct net_device *dev, u16 type, - void *msg, int len) -{ - struct nic *nic = netdev_priv(dev); - - nic->phy_dev->send_hci_func(nic->phy_dev->priv_dev, msg, len, NULL, - NULL); -} - -int gdm_lte_event_init(void) -{ - if (lte_event.ref_cnt == 0) - lte_event.sock = netlink_init(NETLINK_LTE, gdm_lte_event_rcv); - - if (lte_event.sock) { - lte_event.ref_cnt++; - return 0; - } - - pr_err("event init failed\n"); - return -ENODATA; -} - -void gdm_lte_event_exit(void) -{ - if (lte_event.sock && --lte_event.ref_cnt == 0) { - sock_release(lte_event.sock->sk_socket); - lte_event.sock = NULL; - } -} - -static int find_dev_index(u32 nic_type) -{ - u8 index; - - index = (u8)(nic_type & 0x0000000f); - if (index >= MAX_NIC_TYPE) - return -EINVAL; - - return index; -} - -static void gdm_lte_netif_rx(struct net_device *dev, char *buf, - int len, int flagged_nic_type) -{ - u32 nic_type; - struct nic *nic; - struct sk_buff *skb; - struct ethhdr eth; - struct vlan_ethhdr vlan_eth; - void *mac_header_data; - u32 mac_header_len; - char ip_version = 0; - - nic_type = flagged_nic_type & NIC_TYPE_MASK; - nic = netdev_priv(dev); - - if (flagged_nic_type & NIC_TYPE_F_DHCP) { - /* Change the destination mac address - * with the one requested the IP - */ - if (flagged_nic_type & NIC_TYPE_F_IPV4) { - struct dhcp_packet { - u8 op; /* BOOTREQUEST or BOOTREPLY */ - u8 htype; /* hardware address type. - * 1 = 10mb ethernet - */ - u8 hlen; /* hardware address length */ - u8 hops; /* used by relay agents only */ - u32 xid; /* unique id */ - u16 secs; /* elapsed since client began - * acquisition/renewal - */ - u16 flags; /* only one flag so far: */ - #define BROADCAST_FLAG 0x8000 - /* "I need broadcast replies" */ - u32 ciaddr; /* client IP (if client is in - * BOUND, RENEW or REBINDING state) - */ - u32 yiaddr; /* 'your' (client) IP address */ - /* IP address of next server to use in - * bootstrap, returned in DHCPOFFER, - * DHCPACK by server - */ - u32 siaddr_nip; - u32 gateway_nip; /* relay agent IP address */ - u8 chaddr[16]; /* link-layer client hardware - * address (MAC) - */ - u8 sname[64]; /* server host name (ASCIZ) */ - u8 file[128]; /* boot file name (ASCIZ) */ - u32 cookie; /* fixed first four option - * bytes (99,130,83,99 dec) - */ - } __packed; - int offset = sizeof(struct iphdr) + - sizeof(struct udphdr) + - offsetof(struct dhcp_packet, chaddr); - if (offset + ETH_ALEN > len) - return; - ether_addr_copy(nic->dest_mac_addr, buf + offset); - } - } - - if (nic->vlan_id > 0) { - mac_header_data = (void *)&vlan_eth; - mac_header_len = VLAN_ETH_HLEN; - } else { - mac_header_data = (void *)ð - mac_header_len = ETH_HLEN; - } - - /* Format the data so that it can be put to skb */ - ether_addr_copy(mac_header_data, nic->dest_mac_addr); - memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN); - - vlan_eth.h_vlan_TCI = htons(nic->vlan_id); - vlan_eth.h_vlan_proto = htons(ETH_P_8021Q); - - if (nic_type == NIC_TYPE_ARP) { - /* Should be response: Only happens because - * there was a request from the host - */ - eth.h_proto = htons(ETH_P_ARP); - vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_ARP); - } else { - ip_version = buf[0] >> 4; - if (ip_version == IP_VERSION_4) { - eth.h_proto = htons(ETH_P_IP); - vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_IP); - } else if (ip_version == IP_VERSION_6) { - eth.h_proto = htons(ETH_P_IPV6); - vlan_eth.h_vlan_encapsulated_proto = htons(ETH_P_IPV6); - } else { - netdev_err(dev, "Unknown IP version %d\n", ip_version); - return; - } - } - - /* Alloc skb and reserve align */ - skb = dev_alloc_skb(len + mac_header_len + NET_IP_ALIGN); - if (!skb) - return; - skb_reserve(skb, NET_IP_ALIGN); - - skb_put_data(skb, mac_header_data, mac_header_len); - skb_put_data(skb, buf, len); - - skb->protocol = ((struct ethhdr *)mac_header_data)->h_proto; - skb->dev = dev; - skb_reset_mac_header(skb); - skb_pull(skb, ETH_HLEN); - - gdm_lte_rx(skb, nic, nic_type); -} - -static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len) -{ - struct net_device *dev; - struct multi_sdu *multi_sdu = (struct multi_sdu *)buf; - struct sdu *sdu = NULL; - u8 endian = phy_dev->get_endian(phy_dev->priv_dev); - u8 *data = (u8 *)multi_sdu->data; - int copied; - u16 i = 0; - u16 num_packet; - u16 hci_len; - u16 cmd_evt; - u32 nic_type; - int index; - - num_packet = gdm_dev16_to_cpu(endian, multi_sdu->num_packet); - - for (i = 0; i < num_packet; i++) { - copied = data - multi_sdu->data; - if (len < copied + sizeof(*sdu)) { - pr_err("rx prevent buffer overflow"); - return; - } - - sdu = (struct sdu *)data; - - cmd_evt = gdm_dev16_to_cpu(endian, sdu->cmd_evt); - hci_len = gdm_dev16_to_cpu(endian, sdu->len); - nic_type = gdm_dev32_to_cpu(endian, sdu->nic_type); - - if (cmd_evt != LTE_RX_SDU) { - pr_err("rx sdu wrong hci %04x\n", cmd_evt); - return; - } - if (hci_len < 12 || - len < copied + sizeof(*sdu) + (hci_len - 12)) { - pr_err("rx sdu invalid len %d\n", hci_len); - return; - } - - index = find_dev_index(nic_type); - if (index < 0) { - pr_err("rx sdu invalid nic_type :%x\n", nic_type); - return; - } - dev = phy_dev->dev[index]; - gdm_lte_netif_rx(dev, (char *)sdu->data, - (int)(hci_len - 12), nic_type); - - data += ((hci_len + 3) & 0xfffc) + HCI_HEADER_SIZE; - } -} - -static void gdm_lte_pdn_table(struct net_device *dev, char *buf, int len) -{ - struct nic *nic = netdev_priv(dev); - struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf; - u8 ed = nic->phy_dev->get_endian(nic->phy_dev->priv_dev); - - if (!pdn_table->activate) { - memset(&nic->pdn_table, 0x00, sizeof(struct pdn_table)); - netdev_info(dev, "pdn deactivated\n"); - - return; - } - - nic->pdn_table.activate = pdn_table->activate; - nic->pdn_table.dft_eps_id = gdm_dev32_to_cpu(ed, pdn_table->dft_eps_id); - nic->pdn_table.nic_type = gdm_dev32_to_cpu(ed, pdn_table->nic_type); - - netdev_info(dev, "pdn activated, nic_type=0x%x\n", - nic->pdn_table.nic_type); -} - -static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len) -{ - struct hci_packet *hci = (struct hci_packet *)buf; - struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf; - struct sdu *sdu; - struct net_device *dev; - u8 endian = phy_dev->get_endian(phy_dev->priv_dev); - int ret = 0; - u16 cmd_evt; - u32 nic_type; - int index; - - if (!len) - return ret; - - cmd_evt = gdm_dev16_to_cpu(endian, hci->cmd_evt); - - dev = phy_dev->dev[0]; - if (!dev) - return 0; - - switch (cmd_evt) { - case LTE_RX_SDU: - sdu = (struct sdu *)hci->data; - nic_type = gdm_dev32_to_cpu(endian, sdu->nic_type); - index = find_dev_index(nic_type); - if (index < 0) - return index; - dev = phy_dev->dev[index]; - gdm_lte_netif_rx(dev, hci->data, len, nic_type); - break; - case LTE_RX_MULTI_SDU: - gdm_lte_multi_sdu_pkt(phy_dev, buf, len); - break; - case LTE_LINK_ON_OFF_INDICATION: - netdev_info(dev, "link %s\n", - ((struct hci_connect_ind *)buf)->connect - ? "on" : "off"); - break; - case LTE_PDN_TABLE_IND: - pdn_table = (struct hci_pdn_table_ind *)buf; - nic_type = gdm_dev32_to_cpu(endian, pdn_table->nic_type); - index = find_dev_index(nic_type); - if (index < 0) - return index; - dev = phy_dev->dev[index]; - gdm_lte_pdn_table(dev, buf, len); - fallthrough; - default: - ret = gdm_lte_event_send(dev, buf, len); - break; - } - - return ret; -} - -static int rx_complete(void *arg, void *data, int len, int context) -{ - struct phy_dev *phy_dev = arg; - - return gdm_lte_receive_pkt(phy_dev, data, len); -} - -void start_rx_proc(struct phy_dev *phy_dev) -{ - int i; - - for (i = 0; i < MAX_RX_SUBMIT_COUNT; i++) - phy_dev->rcv_func(phy_dev->priv_dev, - rx_complete, phy_dev, USB_COMPLETE); -} - -static const struct net_device_ops gdm_netdev_ops = { - .ndo_open = gdm_lte_open, - .ndo_stop = gdm_lte_close, - .ndo_set_config = gdm_lte_set_config, - .ndo_start_xmit = gdm_lte_tx, - .ndo_get_stats = gdm_lte_stats, -}; - -static u8 gdm_lte_macaddr[ETH_ALEN] = {0x00, 0x0a, 0x3b, 0x00, 0x00, 0x00}; - -static void form_mac_address(u8 *dev_addr, u8 *nic_src, u8 *nic_dest, - u8 *mac_address, u8 index) -{ - /* Form the dev_addr */ - if (!mac_address) - ether_addr_copy(dev_addr, gdm_lte_macaddr); - else - ether_addr_copy(dev_addr, mac_address); - - /* The last byte of the mac address - * should be less than or equal to 0xFC - */ - dev_addr[ETH_ALEN - 1] += index; - - /* Create random nic src and copy the first - * 3 bytes to be the same as dev_addr - */ - eth_random_addr(nic_src); - memcpy(nic_src, dev_addr, 3); - - /* Copy the nic_dest from dev_addr*/ - ether_addr_copy(nic_dest, dev_addr); -} - -static void validate_mac_address(u8 *mac_address) -{ - /* if zero address or multicast bit set, restore the default value */ - if (is_zero_ether_addr(mac_address) || (mac_address[0] & 0x01)) { - pr_err("MAC invalid, restoring default\n"); - memcpy(mac_address, gdm_lte_macaddr, 6); - } -} - -int register_lte_device(struct phy_dev *phy_dev, - struct device *dev, u8 *mac_address) -{ - struct nic *nic; - struct net_device *net; - char pdn_dev_name[16]; - u8 addr[ETH_ALEN]; - int ret = 0; - u8 index; - - validate_mac_address(mac_address); - - for (index = 0; index < MAX_NIC_TYPE; index++) { - /* Create device name lteXpdnX */ - sprintf(pdn_dev_name, "lte%%dpdn%d", index); - - /* Allocate netdev */ - net = alloc_netdev(sizeof(struct nic), pdn_dev_name, - NET_NAME_UNKNOWN, ether_setup); - if (!net) { - ret = -ENOMEM; - goto err; - } - net->netdev_ops = &gdm_netdev_ops; - net->flags &= ~IFF_MULTICAST; - net->mtu = DEFAULT_MTU_SIZE; - - nic = netdev_priv(net); - memset(nic, 0, sizeof(struct nic)); - nic->netdev = net; - nic->phy_dev = phy_dev; - nic->nic_id = index; - - form_mac_address(addr, - nic->src_mac_addr, - nic->dest_mac_addr, - mac_address, - index); - eth_hw_addr_set(net, addr); - - SET_NETDEV_DEV(net, dev); - SET_NETDEV_DEVTYPE(net, &wwan_type); - - ret = register_netdev(net); - if (ret) - goto err; - - netif_carrier_on(net); - - phy_dev->dev[index] = net; - } - - return 0; - -err: - unregister_lte_device(phy_dev); - - return ret; -} - -void unregister_lte_device(struct phy_dev *phy_dev) -{ - struct net_device *net; - int index; - - for (index = 0; index < MAX_NIC_TYPE; index++) { - net = phy_dev->dev[index]; - if (!net) - continue; - - unregister_netdev(net); - free_netdev(net); - } -} diff --git a/drivers/staging/gdm724x/gdm_lte.h b/drivers/staging/gdm724x/gdm_lte.h deleted file mode 100644 index f2143a6e0e990f..00000000000000 --- a/drivers/staging/gdm724x/gdm_lte.h +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#ifndef _GDM_LTE_H_ -#define _GDM_LTE_H_ - -#include -#include - -#include "gdm_endian.h" - -#define MAX_NIC_TYPE 4 -#define MAX_RX_SUBMIT_COUNT 3 -#define DRIVER_VERSION "3.7.17.0" - -enum TX_ERROR_CODE { - TX_NO_ERROR = 0, - TX_NO_DEV, - TX_NO_SPC, - TX_NO_BUFFER, -}; - -enum CALLBACK_CONTEXT { - KERNEL_THREAD = 0, - USB_COMPLETE, -}; - -struct pdn_table { - u8 activate; - u32 dft_eps_id; - u32 nic_type; -} __packed; - -struct nic; - -struct phy_dev { - void *priv_dev; - struct net_device *dev[MAX_NIC_TYPE]; - int (*send_hci_func)(void *priv_dev, void *data, int len, - void (*cb)(void *cb_data), void *cb_data); - int (*send_sdu_func)(void *priv_dev, void *data, int len, - unsigned int dft_eps_id, unsigned int eps_id, - void (*cb)(void *cb_data), void *cb_data, - int dev_idx, int nic_type); - int (*rcv_func)(void *priv_dev, - int (*cb)(void *cb_data, void *data, int len, - int context), - void *cb_data, int context); - u8 (*get_endian)(void *priv_dev); -}; - -struct nic { - struct net_device *netdev; - struct phy_dev *phy_dev; - struct net_device_stats stats; - struct pdn_table pdn_table; - u8 dest_mac_addr[ETH_ALEN]; - u8 src_mac_addr[ETH_ALEN]; - u32 nic_id; - u16 vlan_id; -}; - -int gdm_lte_event_init(void); -void gdm_lte_event_exit(void); - -void start_rx_proc(struct phy_dev *phy_dev); -int register_lte_device(struct phy_dev *phy_dev, struct device *dev, - u8 *mac_address); -void unregister_lte_device(struct phy_dev *phy_dev); - -#endif /* _GDM_LTE_H_ */ diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c deleted file mode 100644 index 9b12619671a13e..00000000000000 --- a/drivers/staging/gdm724x/gdm_mux.c +++ /dev/null @@ -1,668 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gdm_mux.h" - -static u16 packet_type_for_tty_index[TTY_MAX_COUNT] = {0xF011, 0xF010}; - -#define USB_DEVICE_CDC_DATA(vid, pid) \ - .match_flags = \ - USB_DEVICE_ID_MATCH_DEVICE |\ - USB_DEVICE_ID_MATCH_INT_CLASS |\ - USB_DEVICE_ID_MATCH_INT_SUBCLASS,\ - .idVendor = vid,\ - .idProduct = pid,\ - .bInterfaceClass = USB_CLASS_COMM,\ - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM - -static const struct usb_device_id id_table[] = { - { USB_DEVICE_CDC_DATA(0x1076, 0x8000) }, /* GCT GDM7240 */ - { USB_DEVICE_CDC_DATA(0x1076, 0x8f00) }, /* GCT GDM7243 */ - { USB_DEVICE_CDC_DATA(0x1076, 0x9000) }, /* GCT GDM7243 */ - { USB_DEVICE_CDC_DATA(0x1d74, 0x2300) }, /* LGIT Phoenix */ - {} -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static int packet_type_to_tty_index(u16 packet_type) -{ - int i; - - for (i = 0; i < TTY_MAX_COUNT; i++) { - if (packet_type_for_tty_index[i] == packet_type) - return i; - } - - return -1; -} - -static struct mux_tx *alloc_mux_tx(int len) -{ - struct mux_tx *t; - - t = kzalloc(sizeof(*t), GFP_ATOMIC); - if (!t) - return NULL; - - t->urb = usb_alloc_urb(0, GFP_ATOMIC); - t->buf = kmalloc(MUX_TX_MAX_SIZE, GFP_ATOMIC); - if (!t->urb || !t->buf) { - usb_free_urb(t->urb); - kfree(t->buf); - kfree(t); - return NULL; - } - - return t; -} - -static void free_mux_tx(struct mux_tx *t) -{ - if (t) { - usb_free_urb(t->urb); - kfree(t->buf); - kfree(t); - } -} - -static struct mux_rx *alloc_mux_rx(void) -{ - struct mux_rx *r; - - r = kzalloc(sizeof(*r), GFP_KERNEL); - if (!r) - return NULL; - - r->urb = usb_alloc_urb(0, GFP_KERNEL); - r->buf = kmalloc(MUX_RX_MAX_SIZE, GFP_KERNEL); - if (!r->urb || !r->buf) { - usb_free_urb(r->urb); - kfree(r->buf); - kfree(r); - return NULL; - } - - return r; -} - -static void free_mux_rx(struct mux_rx *r) -{ - if (r) { - usb_free_urb(r->urb); - kfree(r->buf); - kfree(r); - } -} - -static struct mux_rx *get_rx_struct(struct rx_cxt *rx) -{ - struct mux_rx *r; - unsigned long flags; - - spin_lock_irqsave(&rx->free_list_lock, flags); - - if (list_empty(&rx->rx_free_list)) { - spin_unlock_irqrestore(&rx->free_list_lock, flags); - return NULL; - } - - r = list_entry(rx->rx_free_list.prev, struct mux_rx, free_list); - list_del(&r->free_list); - - spin_unlock_irqrestore(&rx->free_list_lock, flags); - - return r; -} - -static void put_rx_struct(struct rx_cxt *rx, struct mux_rx *r) -{ - unsigned long flags; - - spin_lock_irqsave(&rx->free_list_lock, flags); - list_add_tail(&r->free_list, &rx->rx_free_list); - spin_unlock_irqrestore(&rx->free_list_lock, flags); -} - -static int up_to_host(struct mux_rx *r) -{ - struct mux_dev *mux_dev = r->mux_dev; - struct mux_pkt_header *mux_header; - unsigned int start_flag; - unsigned int payload_size; - unsigned short packet_type; - int total_len; - u32 packet_size_sum = r->offset; - int index; - int ret = TO_HOST_INVALID_PACKET; - int len = r->len; - - while (1) { - mux_header = (struct mux_pkt_header *)(r->buf + - packet_size_sum); - start_flag = __le32_to_cpu(mux_header->start_flag); - payload_size = __le32_to_cpu(mux_header->payload_size); - packet_type = __le16_to_cpu(mux_header->packet_type); - - if (start_flag != START_FLAG) { - pr_err("invalid START_FLAG %x\n", start_flag); - break; - } - - total_len = ALIGN(MUX_HEADER_SIZE + payload_size, 4); - - if (len - packet_size_sum < total_len) { - pr_err("invalid payload : %d %d %04x\n", - payload_size, len, packet_type); - break; - } - - index = packet_type_to_tty_index(packet_type); - if (index < 0) { - pr_err("invalid index %d\n", index); - break; - } - - ret = r->callback(mux_header->data, - payload_size, - index, - mux_dev->tty_dev, - RECV_PACKET_PROCESS_CONTINUE - ); - if (ret == TO_HOST_BUFFER_REQUEST_FAIL) { - r->offset += packet_size_sum; - break; - } - - packet_size_sum += total_len; - if (len - packet_size_sum <= MUX_HEADER_SIZE + 2) { - ret = r->callback(NULL, - 0, - index, - mux_dev->tty_dev, - RECV_PACKET_PROCESS_COMPLETE - ); - break; - } - } - - return ret; -} - -static void do_rx(struct work_struct *work) -{ - struct mux_dev *mux_dev = - container_of(work, struct mux_dev, work_rx.work); - struct mux_rx *r; - struct rx_cxt *rx = &mux_dev->rx; - unsigned long flags; - int ret = 0; - - while (1) { - spin_lock_irqsave(&rx->to_host_lock, flags); - if (list_empty(&rx->to_host_list)) { - spin_unlock_irqrestore(&rx->to_host_lock, flags); - break; - } - r = list_entry(rx->to_host_list.next, struct mux_rx, - to_host_list); - list_del(&r->to_host_list); - spin_unlock_irqrestore(&rx->to_host_lock, flags); - - ret = up_to_host(r); - if (ret == TO_HOST_BUFFER_REQUEST_FAIL) - pr_err("failed to send mux data to host\n"); - else - put_rx_struct(rx, r); - } -} - -static void remove_rx_submit_list(struct mux_rx *r, struct rx_cxt *rx) -{ - unsigned long flags; - struct mux_rx *r_remove, *r_remove_next; - - spin_lock_irqsave(&rx->submit_list_lock, flags); - list_for_each_entry_safe(r_remove, r_remove_next, &rx->rx_submit_list, - rx_submit_list) { - if (r == r_remove) - list_del(&r->rx_submit_list); - } - spin_unlock_irqrestore(&rx->submit_list_lock, flags); -} - -static void gdm_mux_rcv_complete(struct urb *urb) -{ - struct mux_rx *r = urb->context; - struct mux_dev *mux_dev = r->mux_dev; - struct rx_cxt *rx = &mux_dev->rx; - unsigned long flags; - - remove_rx_submit_list(r, rx); - - if (urb->status) { - if (mux_dev->usb_state == PM_NORMAL) - dev_err(&urb->dev->dev, "%s: urb status error %d\n", - __func__, urb->status); - put_rx_struct(rx, r); - } else { - r->len = r->urb->actual_length; - spin_lock_irqsave(&rx->to_host_lock, flags); - list_add_tail(&r->to_host_list, &rx->to_host_list); - schedule_work(&mux_dev->work_rx.work); - spin_unlock_irqrestore(&rx->to_host_lock, flags); - } -} - -static int gdm_mux_recv(void *priv_dev, - int (*cb)(void *data, int len, int tty_index, - struct tty_dev *tty_dev, int complete)) -{ - struct mux_dev *mux_dev = priv_dev; - struct usb_device *usbdev = mux_dev->usbdev; - struct mux_rx *r; - struct rx_cxt *rx = &mux_dev->rx; - unsigned long flags; - int ret; - - if (!usbdev) { - pr_err("device is disconnected\n"); - return -ENODEV; - } - - r = get_rx_struct(rx); - if (!r) { - pr_err("get_rx_struct fail\n"); - return -ENOMEM; - } - - r->offset = 0; - r->mux_dev = (void *)mux_dev; - r->callback = cb; - mux_dev->rx_cb = cb; - - usb_fill_bulk_urb(r->urb, - usbdev, - usb_rcvbulkpipe(usbdev, 0x86), - r->buf, - MUX_RX_MAX_SIZE, - gdm_mux_rcv_complete, - r); - - spin_lock_irqsave(&rx->submit_list_lock, flags); - list_add_tail(&r->rx_submit_list, &rx->rx_submit_list); - spin_unlock_irqrestore(&rx->submit_list_lock, flags); - - ret = usb_submit_urb(r->urb, GFP_KERNEL); - - if (ret) { - spin_lock_irqsave(&rx->submit_list_lock, flags); - list_del(&r->rx_submit_list); - spin_unlock_irqrestore(&rx->submit_list_lock, flags); - - put_rx_struct(rx, r); - - pr_err("usb_submit_urb ret=%d\n", ret); - } - - usb_mark_last_busy(usbdev); - - return ret; -} - -static void gdm_mux_send_complete(struct urb *urb) -{ - struct mux_tx *t = urb->context; - - if (urb->status == -ECONNRESET) { - dev_info(&urb->dev->dev, "CONNRESET\n"); - free_mux_tx(t); - return; - } - - if (t->callback) - t->callback(t->cb_data); - - free_mux_tx(t); -} - -static int gdm_mux_send(void *priv_dev, void *data, int len, int tty_index, - void (*cb)(void *data), void *cb_data) -{ - struct mux_dev *mux_dev = priv_dev; - struct usb_device *usbdev = mux_dev->usbdev; - struct mux_pkt_header *mux_header; - struct mux_tx *t = NULL; - static u32 seq_num = 1; - int total_len; - int ret; - unsigned long flags; - - if (mux_dev->usb_state == PM_SUSPEND) { - ret = usb_autopm_get_interface(mux_dev->intf); - if (!ret) - usb_autopm_put_interface(mux_dev->intf); - } - - spin_lock_irqsave(&mux_dev->write_lock, flags); - - total_len = ALIGN(MUX_HEADER_SIZE + len, 4); - - t = alloc_mux_tx(total_len); - if (!t) { - pr_err("alloc_mux_tx fail\n"); - spin_unlock_irqrestore(&mux_dev->write_lock, flags); - return -ENOMEM; - } - - mux_header = (struct mux_pkt_header *)t->buf; - mux_header->start_flag = __cpu_to_le32(START_FLAG); - mux_header->seq_num = __cpu_to_le32(seq_num++); - mux_header->payload_size = __cpu_to_le32((u32)len); - mux_header->packet_type = __cpu_to_le16(packet_type_for_tty_index[tty_index]); - - memcpy(t->buf + MUX_HEADER_SIZE, data, len); - memset(t->buf + MUX_HEADER_SIZE + len, 0, - total_len - MUX_HEADER_SIZE - len); - - t->len = total_len; - t->callback = cb; - t->cb_data = cb_data; - - usb_fill_bulk_urb(t->urb, - usbdev, - usb_sndbulkpipe(usbdev, 5), - t->buf, - total_len, - gdm_mux_send_complete, - t); - - ret = usb_submit_urb(t->urb, GFP_ATOMIC); - - spin_unlock_irqrestore(&mux_dev->write_lock, flags); - - if (ret) - pr_err("usb_submit_urb Error: %d\n", ret); - - usb_mark_last_busy(usbdev); - - return ret; -} - -static int gdm_mux_send_control(void *priv_dev, int request, int value, - void *buf, int len) -{ - struct mux_dev *mux_dev = priv_dev; - struct usb_device *usbdev = mux_dev->usbdev; - int ret; - - ret = usb_control_msg(usbdev, - usb_sndctrlpipe(usbdev, 0), - request, - USB_RT_ACM, - value, - 2, - buf, - len, - 5000 - ); - - if (ret < 0) - pr_err("usb_control_msg error: %d\n", ret); - - return min(ret, 0); -} - -static void release_usb(struct mux_dev *mux_dev) -{ - struct rx_cxt *rx = &mux_dev->rx; - struct mux_rx *r, *r_next; - unsigned long flags; - - cancel_delayed_work(&mux_dev->work_rx); - - spin_lock_irqsave(&rx->submit_list_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, - rx_submit_list) { - spin_unlock_irqrestore(&rx->submit_list_lock, flags); - usb_kill_urb(r->urb); - spin_lock_irqsave(&rx->submit_list_lock, flags); - } - spin_unlock_irqrestore(&rx->submit_list_lock, flags); - - spin_lock_irqsave(&rx->free_list_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->rx_free_list, free_list) { - list_del(&r->free_list); - free_mux_rx(r); - } - spin_unlock_irqrestore(&rx->free_list_lock, flags); - - spin_lock_irqsave(&rx->to_host_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->to_host_list, to_host_list) { - if (r->mux_dev == (void *)mux_dev) { - list_del(&r->to_host_list); - free_mux_rx(r); - } - } - spin_unlock_irqrestore(&rx->to_host_lock, flags); -} - -static int init_usb(struct mux_dev *mux_dev) -{ - struct mux_rx *r; - struct rx_cxt *rx = &mux_dev->rx; - int ret = 0; - int i; - - spin_lock_init(&mux_dev->write_lock); - INIT_LIST_HEAD(&rx->to_host_list); - INIT_LIST_HEAD(&rx->rx_submit_list); - INIT_LIST_HEAD(&rx->rx_free_list); - spin_lock_init(&rx->to_host_lock); - spin_lock_init(&rx->submit_list_lock); - spin_lock_init(&rx->free_list_lock); - - for (i = 0; i < MAX_ISSUE_NUM * 2; i++) { - r = alloc_mux_rx(); - if (!r) { - ret = -ENOMEM; - break; - } - - list_add(&r->free_list, &rx->rx_free_list); - } - - INIT_DELAYED_WORK(&mux_dev->work_rx, do_rx); - - return ret; -} - -static int gdm_mux_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct mux_dev *mux_dev; - struct tty_dev *tty_dev; - u16 idVendor, idProduct; - int bInterfaceNumber; - int ret; - int i; - struct usb_device *usbdev = interface_to_usbdev(intf); - - bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; - - idVendor = __le16_to_cpu(usbdev->descriptor.idVendor); - idProduct = __le16_to_cpu(usbdev->descriptor.idProduct); - - pr_info("mux vid = 0x%04x pid = 0x%04x\n", idVendor, idProduct); - - if (bInterfaceNumber != 2) - return -ENODEV; - - mux_dev = kzalloc(sizeof(*mux_dev), GFP_KERNEL); - if (!mux_dev) - return -ENOMEM; - - tty_dev = kzalloc(sizeof(*tty_dev), GFP_KERNEL); - if (!tty_dev) { - ret = -ENOMEM; - goto err_free_mux; - } - - mux_dev->usbdev = usbdev; - mux_dev->control_intf = intf; - - ret = init_usb(mux_dev); - if (ret) - goto err_free_usb; - - tty_dev->priv_dev = (void *)mux_dev; - tty_dev->send_func = gdm_mux_send; - tty_dev->recv_func = gdm_mux_recv; - tty_dev->send_control = gdm_mux_send_control; - - ret = register_lte_tty_device(tty_dev, &intf->dev); - if (ret) - goto err_unregister_tty; - - for (i = 0; i < TTY_MAX_COUNT; i++) - mux_dev->tty_dev = tty_dev; - - mux_dev->intf = intf; - mux_dev->usb_state = PM_NORMAL; - - usb_get_dev(usbdev); - usb_set_intfdata(intf, tty_dev); - - return 0; - -err_unregister_tty: - unregister_lte_tty_device(tty_dev); -err_free_usb: - release_usb(mux_dev); - kfree(tty_dev); -err_free_mux: - kfree(mux_dev); - - return ret; -} - -static void gdm_mux_disconnect(struct usb_interface *intf) -{ - struct tty_dev *tty_dev; - struct mux_dev *mux_dev; - struct usb_device *usbdev = interface_to_usbdev(intf); - - tty_dev = usb_get_intfdata(intf); - - mux_dev = tty_dev->priv_dev; - - release_usb(mux_dev); - unregister_lte_tty_device(tty_dev); - - kfree(mux_dev); - kfree(tty_dev); - - usb_put_dev(usbdev); -} - -static int gdm_mux_suspend(struct usb_interface *intf, pm_message_t pm_msg) -{ - struct tty_dev *tty_dev; - struct mux_dev *mux_dev; - struct rx_cxt *rx; - struct mux_rx *r, *r_next; - unsigned long flags; - - tty_dev = usb_get_intfdata(intf); - mux_dev = tty_dev->priv_dev; - rx = &mux_dev->rx; - - cancel_work_sync(&mux_dev->work_rx.work); - - if (mux_dev->usb_state != PM_NORMAL) { - dev_err(intf->usb_dev, "usb suspend - invalid state\n"); - return -1; - } - - mux_dev->usb_state = PM_SUSPEND; - - spin_lock_irqsave(&rx->submit_list_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, - rx_submit_list) { - spin_unlock_irqrestore(&rx->submit_list_lock, flags); - usb_kill_urb(r->urb); - spin_lock_irqsave(&rx->submit_list_lock, flags); - } - spin_unlock_irqrestore(&rx->submit_list_lock, flags); - - return 0; -} - -static int gdm_mux_resume(struct usb_interface *intf) -{ - struct tty_dev *tty_dev; - struct mux_dev *mux_dev; - u8 i; - - tty_dev = usb_get_intfdata(intf); - mux_dev = tty_dev->priv_dev; - - if (mux_dev->usb_state != PM_SUSPEND) { - dev_err(intf->usb_dev, "usb resume - invalid state\n"); - return -1; - } - - mux_dev->usb_state = PM_NORMAL; - - for (i = 0; i < MAX_ISSUE_NUM; i++) - gdm_mux_recv(mux_dev, mux_dev->rx_cb); - - return 0; -} - -static struct usb_driver gdm_mux_driver = { - .name = "gdm_mux", - .probe = gdm_mux_probe, - .disconnect = gdm_mux_disconnect, - .id_table = id_table, - .supports_autosuspend = 1, - .suspend = gdm_mux_suspend, - .resume = gdm_mux_resume, - .reset_resume = gdm_mux_resume, -}; - -static int __init gdm_usb_mux_init(void) -{ - int ret; - - ret = register_lte_tty_driver(); - if (ret) - return ret; - - return usb_register(&gdm_mux_driver); -} - -static void __exit gdm_usb_mux_exit(void) -{ - usb_deregister(&gdm_mux_driver); - unregister_lte_tty_driver(); -} - -module_init(gdm_usb_mux_init); -module_exit(gdm_usb_mux_exit); - -MODULE_DESCRIPTION("GCT LTE TTY Device Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/gdm724x/gdm_mux.h b/drivers/staging/gdm724x/gdm_mux.h deleted file mode 100644 index 87b8d921fdc822..00000000000000 --- a/drivers/staging/gdm724x/gdm_mux.h +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#ifndef _GDM_MUX_H_ -#define _GDM_MUX_H_ - -#include -#include -#include - -#include "gdm_tty.h" - -#define PM_NORMAL 0 -#define PM_SUSPEND 1 - -#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) - -#define START_FLAG 0xA512485A -#define MUX_HEADER_SIZE 14 -#define MUX_TX_MAX_SIZE (1024 * 10) -#define MUX_RX_MAX_SIZE (1024 * 30) -#define AT_PKT_TYPE 0xF011 -#define DM_PKT_TYPE 0xF010 - -#define RETRY_TIMER 30 /* msec */ - -struct mux_pkt_header { - __le32 start_flag; - __le32 seq_num; - __le32 payload_size; - __le16 packet_type; - unsigned char data[]; -}; - -struct mux_tx { - struct urb *urb; - u8 *buf; - int len; - void (*callback)(void *cb_data); - void *cb_data; -}; - -struct mux_rx { - struct list_head free_list; - struct list_head rx_submit_list; - struct list_head to_host_list; - struct urb *urb; - u8 *buf; - void *mux_dev; - u32 offset; - u32 len; - int (*callback)(void *data, - int len, - int tty_index, - struct tty_dev *tty_dev, - int complete); -}; - -struct rx_cxt { - struct list_head to_host_list; - struct list_head rx_submit_list; - struct list_head rx_free_list; - spinlock_t to_host_lock; - spinlock_t submit_list_lock; - spinlock_t free_list_lock; -}; - -struct mux_dev { - struct usb_device *usbdev; - struct usb_interface *control_intf; - struct usb_interface *data_intf; - struct rx_cxt rx; - struct delayed_work work_rx; - struct usb_interface *intf; - int usb_state; - int (*rx_cb)(void *data, - int len, - int tty_index, - struct tty_dev *tty_dev, - int complete); - spinlock_t write_lock; - struct tty_dev *tty_dev; -}; - -#endif /* _GDM_MUX_H_ */ diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c deleted file mode 100644 index 15c246d3b1a3eb..00000000000000 --- a/drivers/staging/gdm724x/gdm_tty.c +++ /dev/null @@ -1,316 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "gdm_tty.h" - -#define GDM_TTY_MAJOR 0 -#define GDM_TTY_MINOR 32 - -#define WRITE_SIZE 2048 - -#define MUX_TX_MAX_SIZE 2048 - -static inline bool gdm_tty_ready(struct gdm *gdm) -{ - return gdm && gdm->tty_dev && gdm->port.count; -} - -static struct tty_driver *gdm_driver[TTY_MAX_COUNT]; -static struct gdm *gdm_table[TTY_MAX_COUNT][GDM_TTY_MINOR]; -static DEFINE_MUTEX(gdm_table_lock); - -static const char *DRIVER_STRING[TTY_MAX_COUNT] = {"GCTATC", "GCTDM"}; -static char *DEVICE_STRING[TTY_MAX_COUNT] = {"GCT-ATC", "GCT-DM"}; - -static void gdm_port_destruct(struct tty_port *port) -{ - struct gdm *gdm = container_of(port, struct gdm, port); - - mutex_lock(&gdm_table_lock); - gdm_table[gdm->index][gdm->minor] = NULL; - mutex_unlock(&gdm_table_lock); - - kfree(gdm); -} - -static const struct tty_port_operations gdm_port_ops = { - .destruct = gdm_port_destruct, -}; - -static int gdm_tty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - struct gdm *gdm = NULL; - int ret; - - ret = match_string(DRIVER_STRING, TTY_MAX_COUNT, - tty->driver->driver_name); - if (ret < 0) - return -ENODEV; - - mutex_lock(&gdm_table_lock); - gdm = gdm_table[ret][tty->index]; - if (!gdm) { - mutex_unlock(&gdm_table_lock); - return -ENODEV; - } - - tty_port_get(&gdm->port); - - ret = tty_standard_install(driver, tty); - if (ret) { - tty_port_put(&gdm->port); - mutex_unlock(&gdm_table_lock); - return ret; - } - - tty->driver_data = gdm; - mutex_unlock(&gdm_table_lock); - - return 0; -} - -static int gdm_tty_open(struct tty_struct *tty, struct file *filp) -{ - struct gdm *gdm = tty->driver_data; - - return tty_port_open(&gdm->port, tty, filp); -} - -static void gdm_tty_cleanup(struct tty_struct *tty) -{ - struct gdm *gdm = tty->driver_data; - - tty_port_put(&gdm->port); -} - -static void gdm_tty_hangup(struct tty_struct *tty) -{ - struct gdm *gdm = tty->driver_data; - - tty_port_hangup(&gdm->port); -} - -static void gdm_tty_close(struct tty_struct *tty, struct file *filp) -{ - struct gdm *gdm = tty->driver_data; - - tty_port_close(&gdm->port, tty, filp); -} - -static int gdm_tty_recv_complete(void *data, - int len, - int index, - struct tty_dev *tty_dev, - int complete) -{ - struct gdm *gdm = tty_dev->gdm[index]; - - if (!gdm_tty_ready(gdm)) { - if (complete == RECV_PACKET_PROCESS_COMPLETE) - gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev, - gdm_tty_recv_complete); - return TO_HOST_PORT_CLOSE; - } - - if (data && len) { - if (tty_buffer_request_room(&gdm->port, len) == len) { - tty_insert_flip_string(&gdm->port, data, len); - tty_flip_buffer_push(&gdm->port); - } else { - return TO_HOST_BUFFER_REQUEST_FAIL; - } - } - - if (complete == RECV_PACKET_PROCESS_COMPLETE) - gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev, - gdm_tty_recv_complete); - - return 0; -} - -static void gdm_tty_send_complete(void *arg) -{ - struct gdm *gdm = arg; - - if (!gdm_tty_ready(gdm)) - return; - - tty_port_tty_wakeup(&gdm->port); -} - -static ssize_t gdm_tty_write(struct tty_struct *tty, const u8 *buf, size_t len) -{ - struct gdm *gdm = tty->driver_data; - size_t remain = len; - size_t sent_len = 0; - - if (!gdm_tty_ready(gdm)) - return -ENODEV; - - while (remain) { - size_t sending_len = min_t(size_t, MUX_TX_MAX_SIZE, remain); - - gdm->tty_dev->send_func(gdm->tty_dev->priv_dev, - (void *)(buf + sent_len), - sending_len, - gdm->index, - gdm_tty_send_complete, - gdm); - sent_len += sending_len; - remain -= sending_len; - } - - return len; -} - -static unsigned int gdm_tty_write_room(struct tty_struct *tty) -{ - struct gdm *gdm = tty->driver_data; - - if (!gdm_tty_ready(gdm)) - return 0; - - return WRITE_SIZE; -} - -int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device) -{ - struct gdm *gdm; - int i; - int j; - - for (i = 0; i < TTY_MAX_COUNT; i++) { - gdm = kmalloc(sizeof(*gdm), GFP_KERNEL); - if (!gdm) - return -ENOMEM; - - mutex_lock(&gdm_table_lock); - for (j = 0; j < GDM_TTY_MINOR; j++) { - if (!gdm_table[i][j]) - break; - } - - if (j == GDM_TTY_MINOR) { - kfree(gdm); - mutex_unlock(&gdm_table_lock); - return -EINVAL; - } - - gdm_table[i][j] = gdm; - mutex_unlock(&gdm_table_lock); - - tty_dev->gdm[i] = gdm; - tty_port_init(&gdm->port); - - gdm->port.ops = &gdm_port_ops; - gdm->index = i; - gdm->minor = j; - gdm->tty_dev = tty_dev; - - tty_port_register_device(&gdm->port, gdm_driver[i], - gdm->minor, device); - } - - for (i = 0; i < MAX_ISSUE_NUM; i++) - gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev, - gdm_tty_recv_complete); - - return 0; -} - -void unregister_lte_tty_device(struct tty_dev *tty_dev) -{ - struct gdm *gdm; - struct tty_struct *tty; - int i; - - for (i = 0; i < TTY_MAX_COUNT; i++) { - gdm = tty_dev->gdm[i]; - if (!gdm) - continue; - - mutex_lock(&gdm_table_lock); - gdm_table[gdm->index][gdm->minor] = NULL; - mutex_unlock(&gdm_table_lock); - - tty = tty_port_tty_get(&gdm->port); - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } - - tty_unregister_device(gdm_driver[i], gdm->minor); - tty_port_put(&gdm->port); - } -} - -static const struct tty_operations gdm_tty_ops = { - .install = gdm_tty_install, - .open = gdm_tty_open, - .close = gdm_tty_close, - .cleanup = gdm_tty_cleanup, - .hangup = gdm_tty_hangup, - .write = gdm_tty_write, - .write_room = gdm_tty_write_room, -}; - -int register_lte_tty_driver(void) -{ - struct tty_driver *tty_driver; - int i; - int ret; - - for (i = 0; i < TTY_MAX_COUNT; i++) { - tty_driver = tty_alloc_driver(GDM_TTY_MINOR, - TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); - if (IS_ERR(tty_driver)) - return PTR_ERR(tty_driver); - - tty_driver->owner = THIS_MODULE; - tty_driver->driver_name = DRIVER_STRING[i]; - tty_driver->name = DEVICE_STRING[i]; - tty_driver->major = GDM_TTY_MAJOR; - tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - tty_driver->subtype = SERIAL_TYPE_NORMAL; - tty_driver->init_termios = tty_std_termios; - tty_driver->init_termios.c_cflag = B9600 | CS8 | HUPCL | CLOCAL; - tty_driver->init_termios.c_lflag = ISIG | ICANON | IEXTEN; - tty_set_operations(tty_driver, &gdm_tty_ops); - - ret = tty_register_driver(tty_driver); - if (ret) { - tty_driver_kref_put(tty_driver); - return ret; - } - - gdm_driver[i] = tty_driver; - } - - return ret; -} - -void unregister_lte_tty_driver(void) -{ - struct tty_driver *tty_driver; - int i; - - for (i = 0; i < TTY_MAX_COUNT; i++) { - tty_driver = gdm_driver[i]; - if (tty_driver) { - tty_unregister_driver(tty_driver); - tty_driver_kref_put(tty_driver); - } - } -} - diff --git a/drivers/staging/gdm724x/gdm_tty.h b/drivers/staging/gdm724x/gdm_tty.h deleted file mode 100644 index afec97ced4769b..00000000000000 --- a/drivers/staging/gdm724x/gdm_tty.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#ifndef _GDM_TTY_H_ -#define _GDM_TTY_H_ - -#include -#include - -#define TTY_MAX_COUNT 2 - -#define MAX_ISSUE_NUM 3 - -enum TO_HOST_RESULT { - TO_HOST_BUFFER_REQUEST_FAIL = 1, - TO_HOST_PORT_CLOSE = 2, - TO_HOST_INVALID_PACKET = 3, -}; - -enum RECV_PACKET_PROCESS { - RECV_PACKET_PROCESS_COMPLETE = 0, - RECV_PACKET_PROCESS_CONTINUE = 1, -}; - -struct gdm { - struct tty_dev *tty_dev; - struct tty_port port; - unsigned int index; - unsigned int minor; -}; - -struct tty_dev { - void *priv_dev; - int (*send_func)(void *priv_dev, - void *data, - int len, - int tty_index, - void (*cb)(void *cb_data), - void *cb_data); - int (*recv_func)(void *priv_dev, - int (*cb)(void *data, - int len, - int tty_index, - struct tty_dev *tty_dev, - int complete)); - int (*send_control)(void *priv_dev, - int request, - int value, - void *data, - int len); - struct gdm *gdm[2]; -}; - -int register_lte_tty_driver(void); -void unregister_lte_tty_driver(void); -int register_lte_tty_device(struct tty_dev *tty_dev, struct device *dev); -void unregister_lte_tty_device(struct tty_dev *tty_dev); - -#endif /* _GDM_USB_H_ */ - diff --git a/drivers/staging/gdm724x/gdm_usb.c b/drivers/staging/gdm724x/gdm_usb.c deleted file mode 100644 index 54bdb64f52e889..00000000000000 --- a/drivers/staging/gdm724x/gdm_usb.c +++ /dev/null @@ -1,1012 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gdm_usb.h" -#include "gdm_lte.h" -#include "hci.h" -#include "hci_packet.h" -#include "gdm_endian.h" - -#define USB_DEVICE_CDC_DATA(vid, pid) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_INT_CLASS | \ - USB_DEVICE_ID_MATCH_INT_SUBCLASS,\ - .idVendor = vid,\ - .idProduct = pid,\ - .bInterfaceClass = USB_CLASS_COMM,\ - .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET - -#define USB_DEVICE_MASS_DATA(vid, pid) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_INT_INFO,\ - .idVendor = vid,\ - .idProduct = pid,\ - .bInterfaceSubClass = USB_SC_SCSI, \ - .bInterfaceClass = USB_CLASS_MASS_STORAGE,\ - .bInterfaceProtocol = USB_PR_BULK - -static const struct usb_device_id id_table[] = { - { USB_DEVICE_CDC_DATA(VID_GCT, PID_GDM7240) }, /* GCT GDM7240 */ - { USB_DEVICE_CDC_DATA(VID_GCT, PID_GDM7243) }, /* GCT GDM7243 */ - { } -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static void do_tx(struct work_struct *work); -static void do_rx(struct work_struct *work); - -static int gdm_usb_recv(void *priv_dev, - int (*cb)(void *cb_data, - void *data, int len, int context), - void *cb_data, - int context); - -static int request_mac_address(struct lte_udev *udev) -{ - struct hci_packet *hci; - struct usb_device *usbdev = udev->usbdev; - int actual; - int ret = -1; - - hci = kmalloc(struct_size(hci, data, 1), GFP_KERNEL); - if (!hci) - return -ENOMEM; - - hci->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_GET_INFORMATION); - hci->len = gdm_cpu_to_dev16(udev->gdm_ed, 1); - hci->data[0] = MAC_ADDRESS; - - ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 2), hci, 5, - &actual, 1000); - - udev->request_mac_addr = 1; - kfree(hci); - - return ret; -} - -static struct usb_tx *alloc_tx_struct(int len) -{ - struct usb_tx *t = NULL; - int ret = 0; - - t = kzalloc(sizeof(*t), GFP_ATOMIC); - if (!t) { - ret = -ENOMEM; - goto out; - } - - t->urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!(len % 512)) - len++; - - t->buf = kmalloc(len, GFP_ATOMIC); - if (!t->urb || !t->buf) { - ret = -ENOMEM; - goto out; - } - -out: - if (ret < 0) { - if (t) { - usb_free_urb(t->urb); - kfree(t->buf); - kfree(t); - } - return NULL; - } - - return t; -} - -static struct usb_tx_sdu *alloc_tx_sdu_struct(void) -{ - struct usb_tx_sdu *t_sdu; - - t_sdu = kzalloc(sizeof(*t_sdu), GFP_KERNEL); - if (!t_sdu) - return NULL; - - t_sdu->buf = kmalloc(SDU_BUF_SIZE, GFP_KERNEL); - if (!t_sdu->buf) { - kfree(t_sdu); - return NULL; - } - - return t_sdu; -} - -static void free_tx_struct(struct usb_tx *t) -{ - if (t) { - usb_free_urb(t->urb); - kfree(t->buf); - kfree(t); - } -} - -static void free_tx_sdu_struct(struct usb_tx_sdu *t_sdu) -{ - if (t_sdu) { - kfree(t_sdu->buf); - kfree(t_sdu); - } -} - -static struct usb_tx_sdu *get_tx_sdu_struct(struct tx_cxt *tx, int *no_spc) -{ - struct usb_tx_sdu *t_sdu; - - if (list_empty(&tx->free_list)) - return NULL; - - t_sdu = list_entry(tx->free_list.next, struct usb_tx_sdu, list); - list_del(&t_sdu->list); - - tx->avail_count--; - - *no_spc = list_empty(&tx->free_list) ? 1 : 0; - - return t_sdu; -} - -static void put_tx_struct(struct tx_cxt *tx, struct usb_tx_sdu *t_sdu) -{ - list_add_tail(&t_sdu->list, &tx->free_list); - tx->avail_count++; -} - -static struct usb_rx *alloc_rx_struct(void) -{ - struct usb_rx *r = NULL; - int ret = 0; - - r = kmalloc(sizeof(*r), GFP_KERNEL); - if (!r) { - ret = -ENOMEM; - goto out; - } - - r->urb = usb_alloc_urb(0, GFP_KERNEL); - r->buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); - if (!r->urb || !r->buf) { - ret = -ENOMEM; - goto out; - } -out: - - if (ret < 0) { - if (r) { - usb_free_urb(r->urb); - kfree(r->buf); - kfree(r); - } - return NULL; - } - - return r; -} - -static void free_rx_struct(struct usb_rx *r) -{ - if (r) { - usb_free_urb(r->urb); - kfree(r->buf); - kfree(r); - } -} - -static struct usb_rx *get_rx_struct(struct rx_cxt *rx, int *no_spc) -{ - struct usb_rx *r; - unsigned long flags; - - spin_lock_irqsave(&rx->rx_lock, flags); - - if (list_empty(&rx->free_list)) { - spin_unlock_irqrestore(&rx->rx_lock, flags); - return NULL; - } - - r = list_entry(rx->free_list.next, struct usb_rx, free_list); - list_del(&r->free_list); - - rx->avail_count--; - - *no_spc = list_empty(&rx->free_list) ? 1 : 0; - - spin_unlock_irqrestore(&rx->rx_lock, flags); - - return r; -} - -static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r) -{ - unsigned long flags; - - spin_lock_irqsave(&rx->rx_lock, flags); - - list_add_tail(&r->free_list, &rx->free_list); - rx->avail_count++; - - spin_unlock_irqrestore(&rx->rx_lock, flags); -} - -static void release_usb(struct lte_udev *udev) -{ - struct rx_cxt *rx = &udev->rx; - struct tx_cxt *tx = &udev->tx; - struct usb_tx *t, *t_next; - struct usb_rx *r, *r_next; - struct usb_tx_sdu *t_sdu, *t_sdu_next; - unsigned long flags; - - spin_lock_irqsave(&tx->lock, flags); - list_for_each_entry_safe(t_sdu, t_sdu_next, &tx->sdu_list, list) { - list_del(&t_sdu->list); - free_tx_sdu_struct(t_sdu); - } - - list_for_each_entry_safe(t, t_next, &tx->hci_list, list) { - list_del(&t->list); - free_tx_struct(t); - } - - list_for_each_entry_safe(t_sdu, t_sdu_next, &tx->free_list, list) { - list_del(&t_sdu->list); - free_tx_sdu_struct(t_sdu); - } - spin_unlock_irqrestore(&tx->lock, flags); - - spin_lock_irqsave(&rx->submit_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, - rx_submit_list) { - spin_unlock_irqrestore(&rx->submit_lock, flags); - usb_kill_urb(r->urb); - spin_lock_irqsave(&rx->submit_lock, flags); - } - spin_unlock_irqrestore(&rx->submit_lock, flags); - - spin_lock_irqsave(&rx->rx_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->free_list, free_list) { - list_del(&r->free_list); - free_rx_struct(r); - } - spin_unlock_irqrestore(&rx->rx_lock, flags); - - spin_lock_irqsave(&rx->to_host_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->to_host_list, to_host_list) { - if (r->index == (void *)udev) { - list_del(&r->to_host_list); - free_rx_struct(r); - } - } - spin_unlock_irqrestore(&rx->to_host_lock, flags); -} - -static int init_usb(struct lte_udev *udev) -{ - int ret = 0; - int i; - struct tx_cxt *tx = &udev->tx; - struct rx_cxt *rx = &udev->rx; - struct usb_tx_sdu *t_sdu = NULL; - struct usb_rx *r = NULL; - - udev->send_complete = 1; - udev->tx_stop = 0; - udev->request_mac_addr = 0; - udev->usb_state = PM_NORMAL; - - INIT_LIST_HEAD(&tx->sdu_list); - INIT_LIST_HEAD(&tx->hci_list); - INIT_LIST_HEAD(&tx->free_list); - INIT_LIST_HEAD(&rx->rx_submit_list); - INIT_LIST_HEAD(&rx->free_list); - INIT_LIST_HEAD(&rx->to_host_list); - spin_lock_init(&tx->lock); - spin_lock_init(&rx->rx_lock); - spin_lock_init(&rx->submit_lock); - spin_lock_init(&rx->to_host_lock); - - tx->avail_count = 0; - rx->avail_count = 0; - - udev->rx_cb = NULL; - - for (i = 0; i < MAX_NUM_SDU_BUF; i++) { - t_sdu = alloc_tx_sdu_struct(); - if (!t_sdu) { - ret = -ENOMEM; - goto fail; - } - - list_add(&t_sdu->list, &tx->free_list); - tx->avail_count++; - } - - for (i = 0; i < MAX_RX_SUBMIT_COUNT * 2; i++) { - r = alloc_rx_struct(); - if (!r) { - ret = -ENOMEM; - goto fail; - } - - list_add(&r->free_list, &rx->free_list); - rx->avail_count++; - } - INIT_DELAYED_WORK(&udev->work_tx, do_tx); - INIT_DELAYED_WORK(&udev->work_rx, do_rx); - return 0; -fail: - release_usb(udev); - return ret; -} - -static int set_mac_address(u8 *data, void *arg) -{ - struct phy_dev *phy_dev = arg; - struct lte_udev *udev = phy_dev->priv_dev; - struct tlv *tlv = (struct tlv *)data; - u8 mac_address[ETH_ALEN] = {0, }; - - if (tlv->type == MAC_ADDRESS && udev->request_mac_addr) { - memcpy(mac_address, tlv->data, tlv->len); - - if (register_lte_device(phy_dev, - &udev->intf->dev, mac_address) < 0) - pr_err("register lte device failed\n"); - - udev->request_mac_addr = 0; - - return 1; - } - - return 0; -} - -static void do_rx(struct work_struct *work) -{ - struct lte_udev *udev = - container_of(work, struct lte_udev, work_rx.work); - struct rx_cxt *rx = &udev->rx; - struct usb_rx *r; - struct hci_packet *hci; - struct phy_dev *phy_dev; - u16 cmd_evt; - int ret; - unsigned long flags; - - while (1) { - spin_lock_irqsave(&rx->to_host_lock, flags); - if (list_empty(&rx->to_host_list)) { - spin_unlock_irqrestore(&rx->to_host_lock, flags); - break; - } - r = list_entry(rx->to_host_list.next, - struct usb_rx, to_host_list); - list_del(&r->to_host_list); - spin_unlock_irqrestore(&rx->to_host_lock, flags); - - phy_dev = r->cb_data; - udev = phy_dev->priv_dev; - hci = (struct hci_packet *)r->buf; - cmd_evt = gdm_dev16_to_cpu(udev->gdm_ed, hci->cmd_evt); - - switch (cmd_evt) { - case LTE_GET_INFORMATION_RESULT: - if (set_mac_address(hci->data, r->cb_data) == 0) { - r->callback(r->cb_data, - r->buf, - r->urb->actual_length, - KERNEL_THREAD); - } - break; - - default: - if (r->callback) { - ret = r->callback(r->cb_data, - r->buf, - r->urb->actual_length, - KERNEL_THREAD); - - if (ret == -EAGAIN) - pr_err("failed to send received data\n"); - } - break; - } - - put_rx_struct(rx, r); - - gdm_usb_recv(udev, - r->callback, - r->cb_data, - USB_COMPLETE); - } -} - -static void remove_rx_submit_list(struct usb_rx *r, struct rx_cxt *rx) -{ - unsigned long flags; - struct usb_rx *r_remove, *r_remove_next; - - spin_lock_irqsave(&rx->submit_lock, flags); - list_for_each_entry_safe(r_remove, r_remove_next, - &rx->rx_submit_list, rx_submit_list) { - if (r == r_remove) { - list_del(&r->rx_submit_list); - break; - } - } - spin_unlock_irqrestore(&rx->submit_lock, flags); -} - -static void gdm_usb_rcv_complete(struct urb *urb) -{ - struct usb_rx *r = urb->context; - struct rx_cxt *rx = r->rx; - unsigned long flags; - struct lte_udev *udev = container_of(r->rx, struct lte_udev, rx); - struct usb_device *usbdev = udev->usbdev; - - remove_rx_submit_list(r, rx); - - if (!urb->status && r->callback) { - spin_lock_irqsave(&rx->to_host_lock, flags); - list_add_tail(&r->to_host_list, &rx->to_host_list); - schedule_work(&udev->work_rx.work); - spin_unlock_irqrestore(&rx->to_host_lock, flags); - } else { - if (urb->status && udev->usb_state == PM_NORMAL) - dev_err(&urb->dev->dev, "%s: urb status error %d\n", - __func__, urb->status); - - put_rx_struct(rx, r); - } - - usb_mark_last_busy(usbdev); -} - -static int gdm_usb_recv(void *priv_dev, - int (*cb)(void *cb_data, - void *data, int len, int context), - void *cb_data, - int context) -{ - struct lte_udev *udev = priv_dev; - struct usb_device *usbdev = udev->usbdev; - struct rx_cxt *rx = &udev->rx; - struct usb_rx *r; - int no_spc; - int ret; - unsigned long flags; - - if (!udev->usbdev) { - pr_err("invalid device\n"); - return -ENODEV; - } - - r = get_rx_struct(rx, &no_spc); - if (!r) { - pr_err("Out of Memory\n"); - return -ENOMEM; - } - - udev->rx_cb = cb; - r->callback = cb; - r->cb_data = cb_data; - r->index = (void *)udev; - r->rx = rx; - - usb_fill_bulk_urb(r->urb, - usbdev, - usb_rcvbulkpipe(usbdev, 0x83), - r->buf, - RX_BUF_SIZE, - gdm_usb_rcv_complete, - r); - - spin_lock_irqsave(&rx->submit_lock, flags); - list_add_tail(&r->rx_submit_list, &rx->rx_submit_list); - spin_unlock_irqrestore(&rx->submit_lock, flags); - - if (context == KERNEL_THREAD) - ret = usb_submit_urb(r->urb, GFP_KERNEL); - else - ret = usb_submit_urb(r->urb, GFP_ATOMIC); - - if (ret) { - spin_lock_irqsave(&rx->submit_lock, flags); - list_del(&r->rx_submit_list); - spin_unlock_irqrestore(&rx->submit_lock, flags); - - pr_err("usb_submit_urb failed (%p)\n", r); - put_rx_struct(rx, r); - } - - return ret; -} - -static void gdm_usb_send_complete(struct urb *urb) -{ - struct usb_tx *t = urb->context; - struct tx_cxt *tx = t->tx; - struct lte_udev *udev = container_of(tx, struct lte_udev, tx); - unsigned long flags; - - if (urb->status == -ECONNRESET) { - dev_info(&urb->dev->dev, "CONNRESET\n"); - return; - } - - if (t->callback) - t->callback(t->cb_data); - - free_tx_struct(t); - - spin_lock_irqsave(&tx->lock, flags); - udev->send_complete = 1; - schedule_work(&udev->work_tx.work); - spin_unlock_irqrestore(&tx->lock, flags); -} - -static int send_tx_packet(struct usb_device *usbdev, struct usb_tx *t, u32 len) -{ - int ret = 0; - - if (!(len % 512)) - len++; - - usb_fill_bulk_urb(t->urb, - usbdev, - usb_sndbulkpipe(usbdev, 2), - t->buf, - len, - gdm_usb_send_complete, - t); - - ret = usb_submit_urb(t->urb, GFP_ATOMIC); - - if (ret) - dev_err(&usbdev->dev, "usb_submit_urb failed: %d\n", - ret); - - usb_mark_last_busy(usbdev); - - return ret; -} - -static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf) -{ - struct tx_cxt *tx = &udev->tx; - struct usb_tx_sdu *t_sdu = NULL; - struct multi_sdu *multi_sdu = (struct multi_sdu *)send_buf; - u16 send_len = 0; - u16 num_packet = 0; - unsigned long flags; - - multi_sdu->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_TX_MULTI_SDU); - - while (num_packet < MAX_PACKET_IN_MULTI_SDU) { - spin_lock_irqsave(&tx->lock, flags); - if (list_empty(&tx->sdu_list)) { - spin_unlock_irqrestore(&tx->lock, flags); - break; - } - - t_sdu = list_entry(tx->sdu_list.next, struct usb_tx_sdu, list); - if (send_len + t_sdu->len > MAX_SDU_SIZE) { - spin_unlock_irqrestore(&tx->lock, flags); - break; - } - - list_del(&t_sdu->list); - spin_unlock_irqrestore(&tx->lock, flags); - - memcpy(multi_sdu->data + send_len, t_sdu->buf, t_sdu->len); - - send_len += (t_sdu->len + 3) & 0xfffc; - num_packet++; - - if (tx->avail_count > 10) - t_sdu->callback(t_sdu->cb_data); - - spin_lock_irqsave(&tx->lock, flags); - put_tx_struct(tx, t_sdu); - spin_unlock_irqrestore(&tx->lock, flags); - } - - multi_sdu->len = gdm_cpu_to_dev16(udev->gdm_ed, send_len); - multi_sdu->num_packet = gdm_cpu_to_dev16(udev->gdm_ed, num_packet); - - return send_len + offsetof(struct multi_sdu, data); -} - -static void do_tx(struct work_struct *work) -{ - struct lte_udev *udev = - container_of(work, struct lte_udev, work_tx.work); - struct usb_device *usbdev = udev->usbdev; - struct tx_cxt *tx = &udev->tx; - struct usb_tx *t = NULL; - int is_send = 0; - u32 len = 0; - unsigned long flags; - - if (!usb_autopm_get_interface(udev->intf)) - usb_autopm_put_interface(udev->intf); - - if (udev->usb_state == PM_SUSPEND) - return; - - spin_lock_irqsave(&tx->lock, flags); - if (!udev->send_complete) { - spin_unlock_irqrestore(&tx->lock, flags); - return; - } - udev->send_complete = 0; - - if (!list_empty(&tx->hci_list)) { - t = list_entry(tx->hci_list.next, struct usb_tx, list); - list_del(&t->list); - len = t->len; - t->is_sdu = 0; - is_send = 1; - } else if (!list_empty(&tx->sdu_list)) { - if (udev->tx_stop) { - udev->send_complete = 1; - spin_unlock_irqrestore(&tx->lock, flags); - return; - } - - t = alloc_tx_struct(TX_BUF_SIZE); - if (!t) { - spin_unlock_irqrestore(&tx->lock, flags); - return; - } - t->callback = NULL; - t->tx = tx; - t->is_sdu = 1; - is_send = 1; - } - - if (!is_send) { - udev->send_complete = 1; - spin_unlock_irqrestore(&tx->lock, flags); - return; - } - spin_unlock_irqrestore(&tx->lock, flags); - - if (t->is_sdu) - len = packet_aggregation(udev, t->buf); - - if (send_tx_packet(usbdev, t, len)) { - pr_err("send_tx_packet failed\n"); - t->callback = NULL; - gdm_usb_send_complete(t->urb); - } -} - -#define SDU_PARAM_LEN 12 -static int gdm_usb_sdu_send(void *priv_dev, void *data, int len, - unsigned int dft_eps_ID, unsigned int eps_ID, - void (*cb)(void *data), void *cb_data, - int dev_idx, int nic_type) -{ - struct lte_udev *udev = priv_dev; - struct tx_cxt *tx = &udev->tx; - struct usb_tx_sdu *t_sdu; - struct sdu *sdu = NULL; - unsigned long flags; - int no_spc = 0; - u16 send_len; - - if (!udev->usbdev) { - pr_err("sdu send - invalid device\n"); - return TX_NO_DEV; - } - - spin_lock_irqsave(&tx->lock, flags); - t_sdu = get_tx_sdu_struct(tx, &no_spc); - spin_unlock_irqrestore(&tx->lock, flags); - - if (!t_sdu) { - pr_err("sdu send - free list empty\n"); - return TX_NO_SPC; - } - - sdu = (struct sdu *)t_sdu->buf; - sdu->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_TX_SDU); - if (nic_type == NIC_TYPE_ARP) { - send_len = len + SDU_PARAM_LEN; - memcpy(sdu->data, data, len); - } else { - send_len = len - ETH_HLEN; - send_len += SDU_PARAM_LEN; - memcpy(sdu->data, data + ETH_HLEN, len - ETH_HLEN); - } - - sdu->len = gdm_cpu_to_dev16(udev->gdm_ed, send_len); - sdu->dft_eps_ID = gdm_cpu_to_dev32(udev->gdm_ed, dft_eps_ID); - sdu->bearer_ID = gdm_cpu_to_dev32(udev->gdm_ed, eps_ID); - sdu->nic_type = gdm_cpu_to_dev32(udev->gdm_ed, nic_type); - - t_sdu->len = send_len + HCI_HEADER_SIZE; - t_sdu->callback = cb; - t_sdu->cb_data = cb_data; - - spin_lock_irqsave(&tx->lock, flags); - list_add_tail(&t_sdu->list, &tx->sdu_list); - schedule_work(&udev->work_tx.work); - spin_unlock_irqrestore(&tx->lock, flags); - - if (no_spc) - return TX_NO_BUFFER; - - return 0; -} - -static int gdm_usb_hci_send(void *priv_dev, void *data, int len, - void (*cb)(void *data), void *cb_data) -{ - struct lte_udev *udev = priv_dev; - struct tx_cxt *tx = &udev->tx; - struct usb_tx *t; - unsigned long flags; - - if (!udev->usbdev) { - pr_err("hci send - invalid device\n"); - return -ENODEV; - } - - t = alloc_tx_struct(len); - if (!t) { - pr_err("hci_send - out of memory\n"); - return -ENOMEM; - } - - memcpy(t->buf, data, len); - t->callback = cb; - t->cb_data = cb_data; - t->len = len; - t->tx = tx; - t->is_sdu = 0; - - spin_lock_irqsave(&tx->lock, flags); - list_add_tail(&t->list, &tx->hci_list); - schedule_work(&udev->work_tx.work); - spin_unlock_irqrestore(&tx->lock, flags); - - return 0; -} - -static u8 gdm_usb_get_endian(void *priv_dev) -{ - struct lte_udev *udev = priv_dev; - - return udev->gdm_ed; -} - -static int gdm_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int ret = 0; - struct phy_dev *phy_dev = NULL; - struct lte_udev *udev = NULL; - u16 idVendor, idProduct; - int bInterfaceNumber; - struct usb_device *usbdev = interface_to_usbdev(intf); - - bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber; - idVendor = __le16_to_cpu(usbdev->descriptor.idVendor); - idProduct = __le16_to_cpu(usbdev->descriptor.idProduct); - - pr_info("net vid = 0x%04x pid = 0x%04x\n", idVendor, idProduct); - - if (bInterfaceNumber > NETWORK_INTERFACE) { - pr_info("not a network device\n"); - return -ENODEV; - } - - phy_dev = kzalloc(sizeof(*phy_dev), GFP_KERNEL); - if (!phy_dev) - return -ENOMEM; - - udev = kzalloc(sizeof(*udev), GFP_KERNEL); - if (!udev) { - ret = -ENOMEM; - goto err_udev; - } - - phy_dev->priv_dev = (void *)udev; - phy_dev->send_hci_func = gdm_usb_hci_send; - phy_dev->send_sdu_func = gdm_usb_sdu_send; - phy_dev->rcv_func = gdm_usb_recv; - phy_dev->get_endian = gdm_usb_get_endian; - - udev->usbdev = usbdev; - ret = init_usb(udev); - if (ret < 0) { - dev_err(intf->usb_dev, "init_usb func failed\n"); - goto err_init_usb; - } - udev->intf = intf; - - intf->needs_remote_wakeup = 1; - usb_enable_autosuspend(usbdev); - pm_runtime_set_autosuspend_delay(&usbdev->dev, AUTO_SUSPEND_TIMER); - - /* List up hosts with big endians, otherwise, - * defaults to little endian - */ - if (idProduct == PID_GDM7243) - udev->gdm_ed = ENDIANNESS_BIG; - else - udev->gdm_ed = ENDIANNESS_LITTLE; - - ret = request_mac_address(udev); - if (ret < 0) { - dev_err(intf->usb_dev, "request Mac address failed\n"); - goto err_mac_address; - } - - start_rx_proc(phy_dev); - usb_get_dev(usbdev); - usb_set_intfdata(intf, phy_dev); - - return 0; - -err_mac_address: - release_usb(udev); -err_init_usb: - kfree(udev); -err_udev: - kfree(phy_dev); - - return ret; -} - -static void gdm_usb_disconnect(struct usb_interface *intf) -{ - struct phy_dev *phy_dev; - struct lte_udev *udev; - struct usb_device *usbdev; - - usbdev = interface_to_usbdev(intf); - phy_dev = usb_get_intfdata(intf); - - udev = phy_dev->priv_dev; - unregister_lte_device(phy_dev); - - release_usb(udev); - - kfree(udev); - udev = NULL; - - kfree(phy_dev); - phy_dev = NULL; - - usb_put_dev(usbdev); -} - -static int gdm_usb_suspend(struct usb_interface *intf, pm_message_t pm_msg) -{ - struct phy_dev *phy_dev; - struct lte_udev *udev; - struct rx_cxt *rx; - struct usb_rx *r; - struct usb_rx *r_next; - unsigned long flags; - - phy_dev = usb_get_intfdata(intf); - udev = phy_dev->priv_dev; - rx = &udev->rx; - if (udev->usb_state != PM_NORMAL) { - dev_err(intf->usb_dev, "usb suspend - invalid state\n"); - return -1; - } - - udev->usb_state = PM_SUSPEND; - - spin_lock_irqsave(&rx->submit_lock, flags); - list_for_each_entry_safe(r, r_next, &rx->rx_submit_list, - rx_submit_list) { - spin_unlock_irqrestore(&rx->submit_lock, flags); - usb_kill_urb(r->urb); - spin_lock_irqsave(&rx->submit_lock, flags); - } - spin_unlock_irqrestore(&rx->submit_lock, flags); - - cancel_work_sync(&udev->work_tx.work); - cancel_work_sync(&udev->work_rx.work); - - return 0; -} - -static int gdm_usb_resume(struct usb_interface *intf) -{ - struct phy_dev *phy_dev; - struct lte_udev *udev; - struct tx_cxt *tx; - struct rx_cxt *rx; - unsigned long flags; - int issue_count; - int i; - - phy_dev = usb_get_intfdata(intf); - udev = phy_dev->priv_dev; - rx = &udev->rx; - - if (udev->usb_state != PM_SUSPEND) { - dev_err(intf->usb_dev, "usb resume - invalid state\n"); - return -1; - } - udev->usb_state = PM_NORMAL; - - spin_lock_irqsave(&rx->rx_lock, flags); - issue_count = rx->avail_count - MAX_RX_SUBMIT_COUNT; - spin_unlock_irqrestore(&rx->rx_lock, flags); - - if (issue_count >= 0) { - for (i = 0; i < issue_count; i++) - gdm_usb_recv(phy_dev->priv_dev, - udev->rx_cb, - phy_dev, - USB_COMPLETE); - } - - tx = &udev->tx; - spin_lock_irqsave(&tx->lock, flags); - schedule_work(&udev->work_tx.work); - spin_unlock_irqrestore(&tx->lock, flags); - - return 0; -} - -static struct usb_driver gdm_usb_lte_driver = { - .name = "gdm_lte", - .probe = gdm_usb_probe, - .disconnect = gdm_usb_disconnect, - .id_table = id_table, - .supports_autosuspend = 1, - .suspend = gdm_usb_suspend, - .resume = gdm_usb_resume, - .reset_resume = gdm_usb_resume, -}; - -static int __init gdm_usb_lte_init(void) -{ - if (gdm_lte_event_init() < 0) { - pr_err("error creating event\n"); - return -1; - } - - return usb_register(&gdm_usb_lte_driver); -} - -static void __exit gdm_usb_lte_exit(void) -{ - gdm_lte_event_exit(); - - usb_deregister(&gdm_usb_lte_driver); -} - -module_init(gdm_usb_lte_init); -module_exit(gdm_usb_lte_exit); - -MODULE_VERSION(DRIVER_VERSION); -MODULE_DESCRIPTION("GCT LTE USB Device Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/gdm724x/gdm_usb.h b/drivers/staging/gdm724x/gdm_usb.h deleted file mode 100644 index db689b091c4fd4..00000000000000 --- a/drivers/staging/gdm724x/gdm_usb.h +++ /dev/null @@ -1,99 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#ifndef _GDM_USB_H_ -#define _GDM_USB_H_ - -#include -#include -#include -#include - -#include "gdm_endian.h" -#include "hci_packet.h" - -#define PM_NORMAL 0 -#define PM_SUSPEND 1 -#define AUTO_SUSPEND_TIMER 5000 /* ms */ - -#define RX_BUF_SIZE (1024 * 32) -#define TX_BUF_SIZE (1024 * 32) -#define SDU_BUF_SIZE 2048 -#define MAX_SDU_SIZE (1024 * 30) -#define MAX_PACKET_IN_MULTI_SDU 256 - -#define VID_GCT 0x1076 -#define PID_GDM7240 0x8000 -#define PID_GDM7243 0x9000 - -#define NETWORK_INTERFACE 1 -#define USB_SC_SCSI 0x06 -#define USB_PR_BULK 0x50 - -#define MAX_NUM_SDU_BUF 64 - -struct usb_tx { - struct list_head list; - struct urb *urb; - u8 *buf; - u32 len; - void (*callback)(void *cb_data); - void *cb_data; - struct tx_cxt *tx; - u8 is_sdu; -}; - -struct usb_tx_sdu { - struct list_head list; - u8 *buf; - u32 len; - void (*callback)(void *cb_data); - void *cb_data; -}; - -struct usb_rx { - struct list_head to_host_list; - struct list_head free_list; - struct list_head rx_submit_list; - struct rx_cxt *rx; - struct urb *urb; - u8 *buf; - int (*callback)(void *cb_data, void *data, int len, int context); - void *cb_data; - void *index; -}; - -struct tx_cxt { - struct list_head sdu_list; - struct list_head hci_list; - struct list_head free_list; - u32 avail_count; - spinlock_t lock; -}; - -struct rx_cxt { - struct list_head to_host_list; - struct list_head rx_submit_list; - struct list_head free_list; - u32 avail_count; - spinlock_t to_host_lock; - spinlock_t rx_lock; - spinlock_t submit_lock; -}; - -struct lte_udev { - struct usb_device *usbdev; - struct tx_cxt tx; - struct rx_cxt rx; - struct delayed_work work_tx; - struct delayed_work work_rx; - u8 gdm_ed; - u8 send_complete; - u8 tx_stop; - struct usb_interface *intf; - int (*rx_cb)(void *cb_data, void *data, int len, int context); - int usb_state; - u8 request_mac_addr; -}; - -#endif /* _GDM_USB_H_ */ diff --git a/drivers/staging/gdm724x/hci.h b/drivers/staging/gdm724x/hci.h deleted file mode 100644 index b30945daf3a539..00000000000000 --- a/drivers/staging/gdm724x/hci.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#ifndef _HCI_H_ -#define _HCI_H_ - -#define LTE_GET_INFORMATION 0x3002 -#define LTE_GET_INFORMATION_RESULT 0xB003 - #define MAC_ADDRESS 0xA2 - -#define LTE_LINK_ON_OFF_INDICATION 0xB133 -#define LTE_PDN_TABLE_IND 0xB143 - -#define LTE_TX_SDU 0x3200 -#define LTE_RX_SDU 0xB201 -#define LTE_TX_MULTI_SDU 0x3202 -#define LTE_RX_MULTI_SDU 0xB203 - -#define LTE_DL_SDU_FLOW_CONTROL 0x3305 -#define LTE_UL_SDU_FLOW_CONTROL 0xB306 - -#define LTE_AT_CMD_TO_DEVICE 0x3307 -#define LTE_AT_CMD_FROM_DEVICE 0xB308 - -#define LTE_SDIO_DM_SEND_PKT 0x3312 -#define LTE_SDIO_DM_RECV_PKT 0xB313 - -#define LTE_NV_RESTORE_REQUEST 0xB30C -#define LTE_NV_RESTORE_RESPONSE 0x330D -#define LTE_NV_SAVE_REQUEST 0xB30E - #define NV_TYPE_LTE_INFO 0x00 - #define NV_TYPE_BOARD_CONFIG 0x01 - #define NV_TYPE_RF_CAL 0x02 - #define NV_TYPE_TEMP 0x03 - #define NV_TYPE_NET_INFO 0x04 - #define NV_TYPE_SAFETY_INFO 0x05 - #define NV_TYPE_CDMA_CAL 0x06 - #define NV_TYPE_VENDOR 0x07 - #define NV_TYPE_ALL 0xff -#define LTE_NV_SAVE_RESPONSE 0x330F - -#define LTE_AT_CMD_TO_DEVICE_EXT 0x3323 -#define LTE_AT_CMD_FROM_DEVICE_EXT 0xB324 - -#endif /* _HCI_H_ */ diff --git a/drivers/staging/gdm724x/hci_packet.h b/drivers/staging/gdm724x/hci_packet.h deleted file mode 100644 index 3bb01e94f3b576..00000000000000 --- a/drivers/staging/gdm724x/hci_packet.h +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#ifndef _HCI_PACKET_H_ -#define _HCI_PACKET_H_ - -#define HCI_HEADER_SIZE 4 - -/* - * The NIC type definition: - * For backward compatibility, lower 16 bits used as they were. - * Lower 16 bit: NIC_TYPE values - * Uppoer 16 bit: NIC_TYPE Flags - */ -#define NIC_TYPE_NIC0 0x00000010 -#define NIC_TYPE_NIC1 0x00000011 -#define NIC_TYPE_NIC2 0x00000012 -#define NIC_TYPE_NIC3 0x00000013 -#define NIC_TYPE_ARP 0x00000100 -#define NIC_TYPE_ICMPV6 0x00000200 -#define NIC_TYPE_MASK 0x0000FFFF -#define NIC_TYPE_F_IPV4 0x00010000 -#define NIC_TYPE_F_IPV6 0x00020000 -#define NIC_TYPE_F_DHCP 0x00040000 -#define NIC_TYPE_F_NDP 0x00080000 -#define NIC_TYPE_F_VLAN 0x00100000 - -struct hci_packet { - __dev16 cmd_evt; - __dev16 len; - u8 data[]; -} __packed; - -struct tlv { - u8 type; - u8 len; - u8 *data[]; -} __packed; - -struct sdu_header { - __dev16 cmd_evt; - __dev16 len; - __dev32 dft_eps_id; - __dev32 bearer_ID; - __dev32 nic_type; -} __packed; - -struct sdu { - __dev16 cmd_evt; - __dev16 len; - __dev32 dft_eps_ID; - __dev32 bearer_ID; - __dev32 nic_type; - u8 data[]; -} __packed; - -struct multi_sdu { - __dev16 cmd_evt; - __dev16 len; - __dev16 num_packet; - __dev16 reserved; - u8 data[]; -} __packed; - -struct hci_pdn_table_ind { - __dev16 cmd_evt; - __dev16 len; - u8 activate; - __dev32 dft_eps_id; - __dev32 nic_type; - u8 pdn_type; - u8 ipv4_addr[4]; - u8 ipv6_intf_id[8]; -} __packed; - -struct hci_connect_ind { - __dev16 cmd_evt; - __dev16 len; - __dev32 connect; -} __packed; - -#endif /* _HCI_PACKET_H_ */ diff --git a/drivers/staging/gdm724x/netlink_k.c b/drivers/staging/gdm724x/netlink_k.c deleted file mode 100644 index 8f39cc5617aada..00000000000000 --- a/drivers/staging/gdm724x/netlink_k.c +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include "netlink_k.h" - -static DEFINE_MUTEX(netlink_mutex); - -#define ND_MAX_GROUP 30 -#define ND_IFINDEX_LEN sizeof(int) -#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN) -#define ND_NLMSG_DATA(nlh) ((void *)((char *)NLMSG_DATA(nlh) + \ - ND_IFINDEX_LEN)) -#define ND_NLMSG_S_LEN(len) ((len) + ND_IFINDEX_LEN) -#define ND_NLMSG_R_LEN(nlh) ((nlh)->nlmsg_len - ND_IFINDEX_LEN) -#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh) -#define ND_MAX_MSG_LEN (1024 * 32) - -static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len); - -static void netlink_rcv_cb(struct sk_buff *skb) -{ - struct nlmsghdr *nlh; - struct net_device *dev; - u32 mlen; - void *msg; - int ifindex; - - if (!rcv_cb) { - pr_err("nl cb - unregistered\n"); - return; - } - - if (skb->len < NLMSG_HDRLEN) { - pr_err("nl cb - invalid skb length\n"); - return; - } - - nlh = (struct nlmsghdr *)skb->data; - - if (skb->len < nlh->nlmsg_len || nlh->nlmsg_len > ND_MAX_MSG_LEN) { - pr_err("nl cb - invalid length (%d,%d)\n", - skb->len, nlh->nlmsg_len); - return; - } - - memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN); - msg = ND_NLMSG_DATA(nlh); - mlen = ND_NLMSG_R_LEN(nlh); - - dev = dev_get_by_index(&init_net, ifindex); - if (dev) { - rcv_cb(dev, nlh->nlmsg_type, msg, mlen); - dev_put(dev); - } else { - pr_err("nl cb - dev (%d) not found\n", ifindex); - } -} - -static void netlink_rcv(struct sk_buff *skb) -{ - mutex_lock(&netlink_mutex); - netlink_rcv_cb(skb); - mutex_unlock(&netlink_mutex); -} - -struct sock *netlink_init(int unit, - void (*cb)(struct net_device *dev, u16 type, - void *msg, int len)) -{ - struct sock *sock; - struct netlink_kernel_cfg cfg = { - .input = netlink_rcv, - }; - - sock = netlink_kernel_create(&init_net, unit, &cfg); - - if (sock) - rcv_cb = cb; - - return sock; -} - -int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len, - struct net_device *dev) -{ - static u32 seq; - struct sk_buff *skb = NULL; - struct nlmsghdr *nlh; - int ret = 0; - - if (group > ND_MAX_GROUP) - return -EINVAL; - - if (!netlink_has_listeners(sock, group + 1)) - return -ESRCH; - - skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - seq++; - - nlh = nlmsg_put(skb, 0, seq, type, len, 0); - memcpy(NLMSG_DATA(nlh), msg, len); - NETLINK_CB(skb).portid = 0; - NETLINK_CB(skb).dst_group = 0; - - ret = netlink_broadcast(sock, skb, 0, group + 1, GFP_ATOMIC); - if (!ret) - return len; - - if (ret != -ESRCH) - netdev_err(dev, "nl broadcast g=%d, t=%d, l=%d, r=%d\n", - group, type, len, ret); - else if (netlink_has_listeners(sock, group + 1)) - return -EAGAIN; - - return ret; -} diff --git a/drivers/staging/gdm724x/netlink_k.h b/drivers/staging/gdm724x/netlink_k.h deleted file mode 100644 index d42eea9bea3ec5..00000000000000 --- a/drivers/staging/gdm724x/netlink_k.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved. */ - -#ifndef _NETLINK_K_H -#define _NETLINK_K_H - -#include -#include - -struct sock *netlink_init(int unit, - void (*cb)(struct net_device *dev, - u16 type, void *msg, int len)); -int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len, - struct net_device *dev); - -#endif /* _NETLINK_K_H_ */ diff --git a/drivers/staging/gpib/Kconfig b/drivers/staging/gpib/Kconfig new file mode 100644 index 00000000000000..259f3ff3364676 --- /dev/null +++ b/drivers/staging/gpib/Kconfig @@ -0,0 +1,256 @@ +# SPDX-License-Identifier: GPL-2.0 +menuconfig GPIB + tristate "Linux GPIB drivers" + help + Enable support for GPIB cards and dongles for Linux. GPIB + is the General Purpose Interface Bus which conforms to the + IEEE488 standard. + + This set of drivers can be used with the corresponding user + space library that can be found on Sourceforge under linux-gpib. + Select the drivers for your hardware from the list. + +if GPIB + +config GPIB_COMMON + tristate "GPIB core" + help + + Core common driver for all GPIB drivers. It provides the + interface for the userland library + + To compile this driver as a module, choose M here: the module will be + called gpib_common + +config GPIB_AGILENT_82350B + tristate "Agilent 8235xx PCI(e) adapters" + depends on PCI + select GPIB_COMMON + select GPIB_TMS9914 + help + Enable support for HP/Agilent/Keysight boards + 82350A + 82350B + 82351A + + To compile this driver as a module, choose M here: the module will be + called agilent_82350b. + +config GPIB_AGILENT_82357A + tristate "Agilent 82357a/b USB dongles" + select GPIB_COMMON + depends on USB + help + Enable support for Agilent/Keysight 82357x USB dongles. + + To compile this driver as a module, choose M here: the module will be + called agilent_82357a. + +config GPIB_CEC_PCI + tristate "CEC PCI board" + depends on PCI + depends on HAS_IOPORT + depends on !X86_PAE + select GPIB_COMMON + select GPIB_NEC7210 + help + Enable support for Capital Equipment Corporation PCI-488 + and Keithly KPCI-488 boards. + + To compile this driver as a module, choose M here: the module will be + called cec_gpib. + +config GPIB_NI_PCI_ISA + tristate "NI PCI/ISA compatible boards" + depends on ISA_BUS || PCI || PCMCIA + depends on HAS_IOPORT + depends on !X86_PAE + select GPIB_COMMON + select GPIB_NEC7210 + help + Enable support for National Instruments boards based + on TNT4882 chips: + AT-GPIB (with NAT4882 chip) + AT-GPIB (with NEC7210 chip) + AT-GPIB/TNT + PCI-GPIB + PCIe-GPIB + PCI-GPIB+ + PCM-GPIB + PXI-GPIB + PCMCIA-GPIB + and Capital Equipment Corporation CEC-488 board. + + To compile this driver as a module, choose M here: the module will be + called tnt4882. + +config GPIB_CB7210 + tristate "Measurement Computing compatible boards" + depends on HAS_IOPORT + depends on ISA_BUS || PCI || PCMCIA + depends on !X86_PAE + select GPIB_COMMON + select GPIB_NEC7210 + help + Enable support for Measurement Computing (Computer Boards): + CPCI_GPIB, ISA-GPIB, ISA-GPIB/LC, PCI-GPIB/1M, PCI-GPIB/300K and + PCMCIA-GPIB + Quancom PCIGPIB-1 with MC cb7210 chip + + To compile this driver as a module, choose M here: the module will be + +config GPIB_NI_USB + tristate "NI USB dongles" + select GPIB_COMMON + depends on USB + help + Enable support for National Instruments + GPIB-USB-B + GPIB-USB-HS + GPIB-USB-HS+ + Keithly + KUSB-488 + KUSB-488A + Measurement Computing (Computer Boards) + USB-488 + + To compile this driver as a module, choose M here: the module will be + called ni_usb. + +config GPIB_FLUKE + tristate "Fluke" + depends on OF + select GPIB_COMMON + select GPIB_NEC7210 + help + GPIB driver for Fluke based cda devices. + + To compile this driver as a module, choose M here: the module will be + called fluke_gpib + +config GPIB_FMH + tristate "FMH FPGA based devices" + select GPIB_COMMON + select GPIB_NEC7210 + depends on !PPC + depends on OF && PCI + help + GPIB driver for fmhess FPGA based devices + + To compile this driver as a module, choose M here: the module will be + called fmh_gpib + +config GPIB_GPIO + tristate "RPi GPIO bitbang" + depends on ARCH_BCM2835 || COMPILE_TEST + select GPIB_COMMON + help + GPIB bitbang driver Raspberry Pi GPIO adapters + + To compile this driver as a module, choose M here: the module will be + called gpib_bitbang + +config GPIB_HP82335 + tristate "HP82335/HP27209" + depends on ISA_BUS + select GPIB_COMMON + select GPIB_TMS9914 + help + GPIB driver for HP82335 and HP27209 boards + + To compile this driver as a module, choose M here: the module will be + called hp82335 + + +config GPIB_HP82341 + tristate "HP82341x" + select GPIB_COMMON + select GPIB_TMS9914 + depends on BROKEN + depends on ISA_BUS || EISA + help + GPIB driver for HP82341 A/B/C/D boards + + To compile this driver as a module, choose M here: the module will be + called hp82341 + +config GPIB_INES + tristate "INES" + depends on PCI || ISA_BUS || PCMCIA + depends on HAS_IOPORT + depends on !X86_PAE + select GPIB_COMMON + select GPIB_NEC7210 + help + GPIB driver for Ines compatible boards + Ines + GPIB-HS-NT + GPIB for Compact PCI + GPIB for PCI + GPIB for PCMCIA + GPIB PC/104 + Hameg + HO80-2 + Quancom + PCIGPIB-1 based on Ines iGPIB 72010 chip + + To compile this driver as a module, choose M here: the module will be + called ines_gpib + called cb7210. + +config GPIB_PCMCIA + bool "PCMCIA/Cardbus support for NI MC and Ines boards" + depends on PCCARD && (GPIB_NI_PCI_ISA || GPIB_CB7210 || GPIB_INES) + help + Enable PCMCIA/CArdbus support for National Instruments, + measurement computing boards and Ines boards. + +config GPIB_LPVO + tristate "LPVO DIY USB GPIB" + select GPIB_COMMON + depends on USB + help + Enable support for LPVO Self-made usb-gpib adapter + + To compile this driver as a module, choose M here: the module will be + called lpvo_usb_gpib + +config GPIB_PC2 + tristate "PC2 PC2a" + depends on ISA_BUS + depends on HAS_IOPORT + select GPIB_COMMON + select GPIB_NEC7210 + help + Enable support for pc2 and pc2a compatible adapters + Capital Equipment Corporation PC-488 + CONTEC GP-IB(PC) + Hameg HO80 + Iotech GP488B + Keithly MBC-488 + Measurement Computing ISA-GPIB-PCA2 + National Instruments PCII, PCIIa and PCII/IIa + + To compile this driver as a module, choose M here: the module will be + called pc2_gpib + + +config GPIB_TMS9914 + tristate + select GPIB_COMMON + help + Enable support for TMS 9914 chip. + + To compile this driver as a module, choose M here: the module will be + called tms9914 + +config GPIB_NEC7210 + tristate + select GPIB_COMMON + help + Enable support for NEC 7210 compatible chips. + + To compile this driver as a module, choose M here: the module will be + called nec7210 + +endif # GPIB diff --git a/drivers/staging/gpib/Makefile b/drivers/staging/gpib/Makefile new file mode 100644 index 00000000000000..d0e88f5c08444d --- /dev/null +++ b/drivers/staging/gpib/Makefile @@ -0,0 +1,20 @@ + +subdir-ccflags-y += -I$(src)/include -I$(src)/uapi + +obj-$(CONFIG_GPIB_AGILENT_82350B) += agilent_82350b/ +obj-$(CONFIG_GPIB_AGILENT_82357A) += agilent_82357a/ +obj-$(CONFIG_GPIB_CB7210) += cb7210/ +obj-$(CONFIG_GPIB_CEC_PCI) += cec/ +obj-$(CONFIG_GPIB_COMMON) += common/ +obj-$(CONFIG_GPIB_FLUKE) += eastwood/ +obj-$(CONFIG_GPIB_FMH) += fmh_gpib/ +obj-$(CONFIG_GPIB_GPIO) += gpio/ +obj-$(CONFIG_GPIB_HP82335) += hp_82335/ +obj-$(CONFIG_GPIB_HP82341) += hp_82341/ +obj-$(CONFIG_GPIB_INES) += ines/ +obj-$(CONFIG_GPIB_LPVO) += lpvo_usb_gpib/ +obj-$(CONFIG_GPIB_NEC7210) += nec7210/ +obj-$(CONFIG_GPIB_NI_USB) += ni_usb/ +obj-$(CONFIG_GPIB_PC2) += pc2/ +obj-$(CONFIG_GPIB_TMS9914) += tms9914/ +obj-$(CONFIG_GPIB_NI_PCI_ISA) += tnt4882/ diff --git a/drivers/staging/gpib/TODO b/drivers/staging/gpib/TODO new file mode 100644 index 00000000000000..bf2c3974254872 --- /dev/null +++ b/drivers/staging/gpib/TODO @@ -0,0 +1,21 @@ +TODO: +- checkpatch.pl fixes +- fix device drivers that are broken ("depends on BROKEN" in Kconfig) +- tidy-up comments: + - there are some "//comments" and "// comments" scattered around + - sometimes they are misaligned + - sometimes "// comments" are interleaved with "/* comments */" + - multiline comments should start with initial almost-blank line: + /* + * Good + * multiline + * comment + */ + /* Bad + * multiline + * comment + */ +- resolve XXX notes where possible +- fix FIXME notes +- clean-up commented-out code +- fix typos diff --git a/drivers/staging/gpib/agilent_82350b/Makefile b/drivers/staging/gpib/agilent_82350b/Makefile new file mode 100644 index 00000000000000..d9236c92e04be4 --- /dev/null +++ b/drivers/staging/gpib/agilent_82350b/Makefile @@ -0,0 +1,2 @@ + +obj-m += agilent_82350b.o diff --git a/drivers/staging/gpib/agilent_82350b/agilent_82350b.c b/drivers/staging/gpib/agilent_82350b/agilent_82350b.c new file mode 100644 index 00000000000000..53006d0cc79c5d --- /dev/null +++ b/drivers/staging/gpib/agilent_82350b/agilent_82350b.c @@ -0,0 +1,932 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 2002, 2004 by Frank Mori Hess * + ***************************************************************************/ + +#include "agilent_82350b.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for Agilent 82350b"); + +int agilent_82350b_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + struct tms9914_priv *tms_priv = &a_priv->tms9914_priv; + int retval = 0; + unsigned short event_status; + int i, num_fifo_bytes; + //hardware doesn't support checking for end-of-string character when using fifo + if (tms_priv->eos_flags & REOS) { + //pr_info("ag-rd: using tms9914 read for REOS %x EOS %x\n",tms_priv->eos_flags, + // tms_priv->eos); + return tms9914_read(board, tms_priv, buffer, length, end, bytes_read); + } + + clear_bit(DEV_CLEAR_BN, &tms_priv->state); + + read_and_clear_event_status(board); + *end = 0; + *bytes_read = 0; + if (length == 0) + return 0; + //disable fifo for the moment + writeb(DIRECTION_GPIB_TO_HOST, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); + // handle corner case of board not in holdoff and one byte might slip in early + if (tms_priv->holdoff_active == 0 && length > 1) { + size_t num_bytes; + + retval = tms9914_read(board, tms_priv, buffer, 1, end, &num_bytes); + *bytes_read += num_bytes; + if (retval < 0) + dev_err(board->gpib_dev, "%s: tms9914_read failed retval=%i\n", + driver_name, retval); + if (retval < 0 || *end) + return retval; + ++buffer; + --length; + } + tms9914_set_holdoff_mode(tms_priv, TMS9914_HOLDOFF_EOI); + tms9914_release_holdoff(tms_priv); + i = 0; + num_fifo_bytes = length - 1; + write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BIIE, IMR0); // disable BI interrupts + while (i < num_fifo_bytes && *end == 0) { + int block_size; + int j; + int count; + + if (num_fifo_bytes - i < agilent_82350b_fifo_size) + block_size = num_fifo_bytes - i; + else + block_size = agilent_82350b_fifo_size; + set_transfer_counter(a_priv, block_size); + writeb(ENABLE_TI_TO_SRAM | DIRECTION_GPIB_TO_HOST, + a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); + if (agilent_82350b_fifo_is_halted(a_priv)) + writeb(RESTART_STREAM_BIT, a_priv->gpib_base + STREAM_STATUS_REG); + + clear_bit(READ_READY_BN, &tms_priv->state); + + retval = wait_event_interruptible(board->wait, + ((event_status = + read_and_clear_event_status(board)) & + (TERM_COUNT_STATUS_BIT | + BUFFER_END_STATUS_BIT)) || + test_bit(DEV_CLEAR_BN, &tms_priv->state) || + test_bit(TIMO_NUM, &board->status)); + if (retval) { + dev_dbg(board->gpib_dev, "%s: read wait interrupted\n", driver_name); + retval = -ERESTARTSYS; + break; + } + count = block_size - read_transfer_counter(a_priv); + for (j = 0; j < count && i < num_fifo_bytes; ++j) + buffer[i++] = readb(a_priv->sram_base + j); + if (event_status & BUFFER_END_STATUS_BIT) { + clear_bit(RECEIVED_END_BN, &tms_priv->state); + + tms_priv->holdoff_active = 1; + *end = 1; + } + if (test_bit(TIMO_NUM, &board->status)) { + dev_err(board->gpib_dev, "%s: read timed out\n", driver_name); + retval = -ETIMEDOUT; + break; + } + if (test_bit(DEV_CLEAR_BN, &tms_priv->state)) { + dev_err(board->gpib_dev, "%s: device clear interrupted read\n", + driver_name); + retval = -EINTR; + break; + } + } + write_byte(tms_priv, tms_priv->imr0_bits, IMR0); // re-enable BI interrupts + *bytes_read += i; + buffer += i; + length -= i; + writeb(DIRECTION_GPIB_TO_HOST, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); + if (retval < 0) + return retval; + // read last bytes if we havn't received an END yet + if (*end == 0) { + size_t num_bytes; + // try to make sure we holdoff after last byte read + retval = tms9914_read(board, tms_priv, buffer, length, end, &num_bytes); + *bytes_read += num_bytes; + if (retval < 0) + return retval; + } + return 0; +} + +static int translate_wait_return_value(gpib_board_t *board, int retval) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + struct tms9914_priv *tms_priv = &a_priv->tms9914_priv; + + if (retval) { + dev_err(board->gpib_dev, "%s: write wait interrupted\n", driver_name); + return -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) { + dev_err(board->gpib_dev, "%s: write timed out\n", driver_name); + return -ETIMEDOUT; + } + if (test_bit(DEV_CLEAR_BN, &tms_priv->state)) { + dev_err(board->gpib_dev, "%s: device clear interrupted write\n", driver_name); + return -EINTR; + } + return 0; +} + +int agilent_82350b_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + struct tms9914_priv *tms_priv = &a_priv->tms9914_priv; + int i, j; + unsigned short event_status; + int retval = 0; + int fifotransferlength = length; + int block_size = 0; + size_t num_bytes; + + *bytes_written = 0; + if (send_eoi) + --fifotransferlength; + + clear_bit(DEV_CLEAR_BN, &tms_priv->state); + + writeb(0, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); + + event_status = read_and_clear_event_status(board); + + //pr_info("ag_ac_wr: event status 0x%x tms state 0x%lx\n", event_status, tms_priv->state); + +#ifdef EXPERIMENTAL + pr_info("ag_ac_wr: wait for previous BO to complete if any\n"); + retval = wait_event_interruptible(board->wait, + test_bit(DEV_CLEAR_BN, &tms_priv->state) || + test_bit(WRITE_READY_BN, &tms_priv->state) || + test_bit(TIMO_NUM, &board->status)); + retval = translate_wait_return_value(board, retval); + + if (retval) + return retval; +#endif + + //pr_info("ag_ac_wr: sending first byte\n"); + retval = agilent_82350b_write(board, buffer, 1, 0, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + return retval; + + //pr_info("ag_ac_wr: %ld bytes eoi %d tms state 0x%lx\n",length, send_eoi, tms_priv->state); + + write_byte(tms_priv, tms_priv->imr0_bits & ~HR_BOIE, IMR0); + for (i = 1; i < fifotransferlength;) { + clear_bit(WRITE_READY_BN, &tms_priv->state); + + if (fifotransferlength - i < agilent_82350b_fifo_size) + block_size = fifotransferlength - i; + else + block_size = agilent_82350b_fifo_size; + set_transfer_counter(a_priv, block_size); + for (j = 0; j < block_size; ++j, ++i) { + // load data into board's sram + writeb(buffer[i], a_priv->sram_base + j); + } + writeb(ENABLE_TI_TO_SRAM, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); + + //pr_info("ag_ac_wr: send block: %d bytes tms 0x%lx\n", block_size, + // tms_priv->state); + + if (agilent_82350b_fifo_is_halted(a_priv)) { + writeb(RESTART_STREAM_BIT, a_priv->gpib_base + STREAM_STATUS_REG); + // pr_info("ag_ac_wr: needed restart\n"); + } + + retval = wait_event_interruptible(board->wait, + ((event_status = + read_and_clear_event_status(board)) & + TERM_COUNT_STATUS_BIT) || + test_bit(DEV_CLEAR_BN, &tms_priv->state) || + test_bit(TIMO_NUM, &board->status)); + writeb(0, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); + num_bytes = block_size - read_transfer_counter(a_priv); + //pr_info("ag_ac_wr: sent %ld bytes tms 0x%lx\n", num_bytes, tms_priv->state); + + *bytes_written += num_bytes; + retval = translate_wait_return_value(board, retval); + if (retval) + break; + } + write_byte(tms_priv, tms_priv->imr0_bits, IMR0); + if (retval) + return retval; + + if (send_eoi) { + //pr_info("ag_ac_wr: sending last byte with eoi byte no: %d\n", + // fifotransferlength+1); + + retval = agilent_82350b_write(board, buffer + fifotransferlength, 1, send_eoi, + &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + return retval; + } + return 0; +} + +unsigned short read_and_clear_event_status(gpib_board_t *board) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + unsigned long flags; + unsigned short status; + + spin_lock_irqsave(&board->spinlock, flags); + status = a_priv->event_status_bits; + a_priv->event_status_bits = 0; + spin_unlock_irqrestore(&board->spinlock, flags); + return status; +} + +irqreturn_t agilent_82350b_interrupt(int irq, void *arg) + +{ + int tms9914_status1 = 0, tms9914_status2 = 0; + int event_status; + gpib_board_t *board = arg; + struct agilent_82350b_priv *a_priv = board->private_data; + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + + spin_lock_irqsave(&board->spinlock, flags); + event_status = readb(a_priv->gpib_base + EVENT_STATUS_REG); + if (event_status & IRQ_STATUS_BIT) + retval = IRQ_HANDLED; + + if (event_status & TMS9914_IRQ_STATUS_BIT) { + tms9914_status1 = read_byte(&a_priv->tms9914_priv, ISR0); + tms9914_status2 = read_byte(&a_priv->tms9914_priv, ISR1); + tms9914_interrupt_have_status(board, &a_priv->tms9914_priv, tms9914_status1, + tms9914_status2); + } +//pr_info("event_status=0x%x s1 %x s2 %x\n", event_status,tms9914_status1,tms9914_status2); +//write-clear status bits + if (event_status & (BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT)) { + writeb(event_status & (BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT), + a_priv->gpib_base + EVENT_STATUS_REG); + a_priv->event_status_bits |= event_status; + wake_up_interruptible(&board->wait); + } + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +void agilent_82350b_detach(gpib_board_t *board); + +const char *driver_name = "agilent_82350b"; + +int read_transfer_counter(struct agilent_82350b_priv *a_priv) + +{ + int lo, mid, value; + + lo = readb(a_priv->gpib_base + XFER_COUNT_LO_REG); + mid = readb(a_priv->gpib_base + XFER_COUNT_MID_REG); + value = (lo & 0xff) | ((mid << 8) & 0x7f00); + value = ~(value - 1) & 0x7fff; + return value; +} + +void set_transfer_counter(struct agilent_82350b_priv *a_priv, int count) + +{ + int complement = -count; + + writeb(complement & 0xff, a_priv->gpib_base + XFER_COUNT_LO_REG); + writeb((complement >> 8) & 0xff, a_priv->gpib_base + XFER_COUNT_MID_REG); + //I don't think the hi count reg is even used, but oh well + writeb((complement >> 16) & 0xf, a_priv->gpib_base + XFER_COUNT_HI_REG); +} + +// wrappers for interface functions +int agilent_82350b_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read); +} + +int agilent_82350b_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written); +} + +int agilent_82350b_command(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_command(board, &priv->tms9914_priv, buffer, length, bytes_written); +} + +int agilent_82350b_take_control(gpib_board_t *board, int synchronous) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_take_control_workaround(board, &priv->tms9914_priv, synchronous); +} + +int agilent_82350b_go_to_standby(gpib_board_t *board) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_go_to_standby(board, &priv->tms9914_priv); +} + +void agilent_82350b_request_system_control(gpib_board_t *board, int request_control) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + + if (request_control) { + a_priv->card_mode_bits |= CM_SYSTEM_CONTROLLER_BIT; + if (a_priv->model != MODEL_82350A) + writeb(IC_SYSTEM_CONTROLLER_BIT, a_priv->gpib_base + INTERNAL_CONFIG_REG); + } else { + a_priv->card_mode_bits &= ~CM_SYSTEM_CONTROLLER_BIT; + if (a_priv->model != MODEL_82350A) + writeb(0, a_priv->gpib_base + INTERNAL_CONFIG_REG); + } + writeb(a_priv->card_mode_bits, a_priv->gpib_base + CARD_MODE_REG); + tms9914_request_system_control(board, &a_priv->tms9914_priv, request_control); +} + +void agilent_82350b_interface_clear(gpib_board_t *board, int assert) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + tms9914_interface_clear(board, &priv->tms9914_priv, assert); +} + +void agilent_82350b_remote_enable(gpib_board_t *board, int enable) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + tms9914_remote_enable(board, &priv->tms9914_priv, enable); +} + +int agilent_82350b_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_enable_eos(board, &priv->tms9914_priv, eos_byte, compare_8_bits); +} + +void agilent_82350b_disable_eos(gpib_board_t *board) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + tms9914_disable_eos(board, &priv->tms9914_priv); +} + +unsigned int agilent_82350b_update_status(gpib_board_t *board, unsigned int clear_mask) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_update_status(board, &priv->tms9914_priv, clear_mask); +} + +int agilent_82350b_primary_address(gpib_board_t *board, unsigned int address) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_primary_address(board, &priv->tms9914_priv, address); +} + +int agilent_82350b_secondary_address(gpib_board_t *board, unsigned int address, int enable) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable); +} + +int agilent_82350b_parallel_poll(gpib_board_t *board, uint8_t *result) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_parallel_poll(board, &priv->tms9914_priv, result); +} + +void agilent_82350b_parallel_poll_configure(gpib_board_t *board, uint8_t config) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + tms9914_parallel_poll_configure(board, &priv->tms9914_priv, config); +} + +void agilent_82350b_parallel_poll_response(gpib_board_t *board, int ist) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist); +} + +void agilent_82350b_serial_poll_response(gpib_board_t *board, uint8_t status) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + tms9914_serial_poll_response(board, &priv->tms9914_priv, status); +} + +uint8_t agilent_82350b_serial_poll_status(gpib_board_t *board) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_serial_poll_status(board, &priv->tms9914_priv); +} + +int agilent_82350b_line_status(const gpib_board_t *board) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + return tms9914_line_status(board, &priv->tms9914_priv); +} + +unsigned int agilent_82350b_t1_delay(gpib_board_t *board, unsigned int nanosec) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + static const int nanosec_per_clock = 30; + unsigned int value; + + tms9914_t1_delay(board, &a_priv->tms9914_priv, nanosec); + + value = (nanosec + nanosec_per_clock - 1) / nanosec_per_clock; + if (value > 0xff) + value = 0xff; + writeb(value, a_priv->gpib_base + T1_DELAY_REG); + return value * nanosec_per_clock; +} + +void agilent_82350b_return_to_local(gpib_board_t *board) + +{ + struct agilent_82350b_priv *priv = board->private_data; + + tms9914_return_to_local(board, &priv->tms9914_priv); +} + +int agilent_82350b_allocate_private(gpib_board_t *board) + +{ + board->private_data = kzalloc(sizeof(struct agilent_82350b_priv), GFP_KERNEL); + if (!board->private_data) + return -ENOMEM; + return 0; +} + +void agilent_82350b_free_private(gpib_board_t *board) + +{ + kfree(board->private_data); + board->private_data = NULL; +} + +static int init_82350a_hardware(gpib_board_t *board, const gpib_board_config_t *config) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + static const unsigned int firmware_length = 5302; + unsigned int borg_status; + static const unsigned int timeout = 1000; + int i, j; + const char *firmware_data = config->init_data; + const unsigned int plx_cntrl_static_bits = PLX9050_WAITO_NOT_USER0_SELECT_BIT | + PLX9050_USER0_OUTPUT_BIT | + PLX9050_LLOCK_NOT_USER1_SELECT_BIT | + PLX9050_USER1_OUTPUT_BIT | + PLX9050_USER2_OUTPUT_BIT | + PLX9050_USER3_OUTPUT_BIT | + PLX9050_PCI_READ_MODE_BIT | + PLX9050_PCI_WRITE_MODE_BIT | + PLX9050_PCI_RETRY_DELAY_BITS(64) | + PLX9050_DIRECT_SLAVE_LOCK_ENABLE_BIT; + +// load borg data + borg_status = readb(a_priv->borg_base); + if ((borg_status & BORG_DONE_BIT)) + return 0; + // need to programme borg + if (!config->init_data || config->init_data_length != firmware_length) { + dev_err(board->gpib_dev, "%s: the 82350A board requires firmware after powering on.\n", + driver_name); + return -EIO; + } + dev_info(board->gpib_dev, "%s: Loading firmware...\n", driver_name); + + // tickle the borg + writel(plx_cntrl_static_bits | PLX9050_USER3_DATA_BIT, + a_priv->plx_base + PLX9050_CNTRL_REG); + usleep_range(1000, 2000); + writel(plx_cntrl_static_bits, a_priv->plx_base + PLX9050_CNTRL_REG); + usleep_range(1000, 2000); + writel(plx_cntrl_static_bits | PLX9050_USER3_DATA_BIT, + a_priv->plx_base + PLX9050_CNTRL_REG); + usleep_range(1000, 2000); + + for (i = 0; i < config->init_data_length; ++i) { + for (j = 0; j < timeout && (readb(a_priv->borg_base) & BORG_READY_BIT) == 0; ++j) { + if (need_resched()) + schedule(); + usleep_range(10, 20); + } + if (j == timeout) { + dev_err(board->gpib_dev, "%s: timed out loading firmware.\n", driver_name); + return -ETIMEDOUT; + } + writeb(firmware_data[i], a_priv->gpib_base + CONFIG_DATA_REG); + } + for (j = 0; j < timeout && (readb(a_priv->borg_base) & BORG_DONE_BIT) == 0; ++j) { + if (need_resched()) + schedule(); + usleep_range(10, 20); + } + if (j == timeout) { + dev_err(board->gpib_dev, "%s: timed out waiting for firmware load to complete.\n", + driver_name); + return -ETIMEDOUT; + } + dev_info(board->gpib_dev, "%s: ...done.\n", driver_name); + return 0; +} + +static int test_sram(gpib_board_t *board) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + unsigned int i; + const unsigned int sram_length = pci_resource_len(a_priv->pci_device, SRAM_82350A_REGION); + // test SRAM + const unsigned int byte_mask = 0xff; + + for (i = 0; i < sram_length; ++i) { + writeb(i & byte_mask, a_priv->sram_base + i); + if (need_resched()) + schedule(); + } + for (i = 0; i < sram_length; ++i) { + unsigned int read_value = readb(a_priv->sram_base + i); + + if ((i & byte_mask) != read_value) { + dev_err(board->gpib_dev, "%s: SRAM test failed at %d wanted %d got %d\n", + driver_name, i, (i & byte_mask), read_value); + return -EIO; + } + if (need_resched()) + schedule(); + } + dev_info(board->gpib_dev, "%s: SRAM test passed 0x%x bytes checked\n", + driver_name, sram_length); + return 0; +} + +static int agilent_82350b_generic_attach(gpib_board_t *board, const gpib_board_config_t *config, + int use_fifos) + +{ + struct agilent_82350b_priv *a_priv; + struct tms9914_priv *tms_priv; + int retval; + + board->status = 0; + + if (agilent_82350b_allocate_private(board)) + return -ENOMEM; + a_priv = board->private_data; + a_priv->using_fifos = use_fifos; + tms_priv = &a_priv->tms9914_priv; + tms_priv->read_byte = tms9914_iomem_read_byte; + tms_priv->write_byte = tms9914_iomem_write_byte; + tms_priv->offset = 1; + + // find board + a_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_AGILENT, + PCI_DEVICE_ID_82350B, NULL); + if (a_priv->pci_device) { + a_priv->model = MODEL_82350B; + dev_info(board->gpib_dev, "%s: Agilent 82350B board found\n", driver_name); + + } else { + a_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_AGILENT, + PCI_DEVICE_ID_82351A, NULL); + if (a_priv->pci_device) { + a_priv->model = MODEL_82351A; + dev_info(board->gpib_dev, "%s: Agilent 82351B board found\n", driver_name); + + } else { + a_priv->pci_device = gpib_pci_get_subsys(config, PCI_VENDOR_ID_PLX, + PCI_DEVICE_ID_PLX_9050, + PCI_VENDOR_ID_HP, + PCI_SUBDEVICE_ID_82350A, + a_priv->pci_device); + if (a_priv->pci_device) { + a_priv->model = MODEL_82350A; + dev_info(board->gpib_dev, "%s: HP/Agilent 82350A board found\n", + driver_name); + } else { + dev_err(board->gpib_dev, "%s: no 82350/82351 board found\n", + driver_name); + return -ENODEV; + } + } + } + if (pci_enable_device(a_priv->pci_device)) { + dev_err(board->gpib_dev, "%s: error enabling pci device\n", driver_name); + return -EIO; + } + if (pci_request_regions(a_priv->pci_device, driver_name)) + return -EIO; + switch (a_priv->model) { + case MODEL_82350A: + a_priv->plx_base = ioremap(pci_resource_start(a_priv->pci_device, PLX_MEM_REGION), + pci_resource_len(a_priv->pci_device, PLX_MEM_REGION)); + dev_dbg(board->gpib_dev, "%s: plx base address remapped to 0x%p\n", + driver_name, a_priv->plx_base); + a_priv->gpib_base = ioremap(pci_resource_start(a_priv->pci_device, + GPIB_82350A_REGION), + pci_resource_len(a_priv->pci_device, + GPIB_82350A_REGION)); + dev_dbg(board->gpib_dev, "%s: gpib base address remapped to 0x%p\n", + driver_name, a_priv->gpib_base); + tms_priv->iobase = a_priv->gpib_base + TMS9914_BASE_REG; + a_priv->sram_base = ioremap(pci_resource_start(a_priv->pci_device, + SRAM_82350A_REGION), + pci_resource_len(a_priv->pci_device, + SRAM_82350A_REGION)); + dev_dbg(board->gpib_dev, "%s: sram base address remapped to 0x%p\n", + driver_name, a_priv->sram_base); + a_priv->borg_base = ioremap(pci_resource_start(a_priv->pci_device, + BORG_82350A_REGION), + pci_resource_len(a_priv->pci_device, + BORG_82350A_REGION)); + dev_dbg(board->gpib_dev, "%s: borg base address remapped to 0x%p\n", + driver_name, a_priv->borg_base); + + retval = init_82350a_hardware(board, config); + if (retval < 0) + return retval; + break; + case MODEL_82350B: + case MODEL_82351A: + a_priv->gpib_base = ioremap(pci_resource_start(a_priv->pci_device, GPIB_REGION), + pci_resource_len(a_priv->pci_device, GPIB_REGION)); + dev_dbg(board->gpib_dev, "%s: gpib base address remapped to 0x%p\n", + driver_name, a_priv->gpib_base); + tms_priv->iobase = a_priv->gpib_base + TMS9914_BASE_REG; + a_priv->sram_base = ioremap(pci_resource_start(a_priv->pci_device, SRAM_REGION), + pci_resource_len(a_priv->pci_device, SRAM_REGION)); + dev_dbg(board->gpib_dev, "%s: sram base address remapped to 0x%p\n", + driver_name, a_priv->sram_base); + a_priv->misc_base = ioremap(pci_resource_start(a_priv->pci_device, MISC_REGION), + pci_resource_len(a_priv->pci_device, MISC_REGION)); + dev_dbg(board->gpib_dev, "%s: misc base address remapped to 0x%p\n", + driver_name, a_priv->misc_base); + break; + default: + pr_err("%s: invalid board\n", driver_name); + return -1; + } + + retval = test_sram(board); + if (retval < 0) + return retval; + + if (request_irq(a_priv->pci_device->irq, agilent_82350b_interrupt, + IRQF_SHARED, driver_name, board)) { + pr_err("%s: can't request IRQ %d\n", driver_name, a_priv->pci_device->irq); + return -EIO; + } + a_priv->irq = a_priv->pci_device->irq; + dev_dbg(board->gpib_dev, "%s: IRQ %d\n", driver_name, a_priv->irq); + + writeb(0, a_priv->gpib_base + SRAM_ACCESS_CONTROL_REG); + a_priv->card_mode_bits = ENABLE_PCI_IRQ_BIT; + writeb(a_priv->card_mode_bits, a_priv->gpib_base + CARD_MODE_REG); + + if (a_priv->model == MODEL_82350A) { + // enable PCI interrupts for 82350a + writel(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR2_POLARITY_BIT | + PLX9050_PCI_INTR_EN_BIT, + a_priv->plx_base + PLX9050_INTCSR_REG); + } + + if (use_fifos) { + writeb(ENABLE_BUFFER_END_EVENTS_BIT | ENABLE_TERM_COUNT_EVENTS_BIT, + a_priv->gpib_base + EVENT_ENABLE_REG); + writeb(ENABLE_TERM_COUNT_INTERRUPT_BIT | ENABLE_BUFFER_END_INTERRUPT_BIT | + ENABLE_TMS9914_INTERRUPTS_BIT, a_priv->gpib_base + INTERRUPT_ENABLE_REG); + //write-clear event status bits + writeb(BUFFER_END_STATUS_BIT | TERM_COUNT_STATUS_BIT, + a_priv->gpib_base + EVENT_STATUS_REG); + } else { + writeb(0, a_priv->gpib_base + EVENT_ENABLE_REG); + writeb(ENABLE_TMS9914_INTERRUPTS_BIT, + a_priv->gpib_base + INTERRUPT_ENABLE_REG); + } + board->t1_nano_sec = agilent_82350b_t1_delay(board, 2000); + tms9914_board_reset(tms_priv); + + tms9914_online(board, tms_priv); + + return 0; +} + +int agilent_82350b_unaccel_attach(gpib_board_t *board, const gpib_board_config_t *config) + +{ + return agilent_82350b_generic_attach(board, config, 0); +} + +int agilent_82350b_accel_attach(gpib_board_t *board, const gpib_board_config_t *config) + +{ + return agilent_82350b_generic_attach(board, config, 1); +} + +void agilent_82350b_detach(gpib_board_t *board) + +{ + struct agilent_82350b_priv *a_priv = board->private_data; + struct tms9914_priv *tms_priv; + + if (a_priv) { + if (a_priv->plx_base) // disable interrupts + writel(0, a_priv->plx_base + PLX9050_INTCSR_REG); + + tms_priv = &a_priv->tms9914_priv; + if (a_priv->irq) + free_irq(a_priv->irq, board); + if (a_priv->gpib_base) { + tms9914_board_reset(tms_priv); + if (a_priv->misc_base) + iounmap((void *)a_priv->misc_base); + if (a_priv->borg_base) + iounmap((void *)a_priv->borg_base); + if (a_priv->sram_base) + iounmap((void *)a_priv->sram_base); + if (a_priv->gpib_base) + iounmap((void *)a_priv->gpib_base); + if (a_priv->plx_base) + iounmap((void *)a_priv->plx_base); + pci_release_regions(a_priv->pci_device); + } + if (a_priv->pci_device) + pci_dev_put(a_priv->pci_device); + } + agilent_82350b_free_private(board); +} + +gpib_interface_t agilent_82350b_unaccel_interface = { +name: "agilent_82350b_unaccel", +attach : agilent_82350b_unaccel_attach, +detach : agilent_82350b_detach, +read : agilent_82350b_read, +write : agilent_82350b_write, +command : agilent_82350b_command, +request_system_control : agilent_82350b_request_system_control, +take_control : agilent_82350b_take_control, +go_to_standby : agilent_82350b_go_to_standby, +interface_clear : agilent_82350b_interface_clear, +remote_enable : agilent_82350b_remote_enable, +enable_eos : agilent_82350b_enable_eos, +disable_eos : agilent_82350b_disable_eos, +parallel_poll : agilent_82350b_parallel_poll, +parallel_poll_configure : agilent_82350b_parallel_poll_configure, +parallel_poll_response : agilent_82350b_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : agilent_82350b_line_status, +update_status : agilent_82350b_update_status, +primary_address : agilent_82350b_primary_address, +secondary_address : agilent_82350b_secondary_address, +serial_poll_response : agilent_82350b_serial_poll_response, +t1_delay : agilent_82350b_t1_delay, +return_to_local : agilent_82350b_return_to_local, +}; + +gpib_interface_t agilent_82350b_interface = { +name: "agilent_82350b", +attach : agilent_82350b_accel_attach, +detach : agilent_82350b_detach, +read : agilent_82350b_accel_read, +write : agilent_82350b_accel_write, +command : agilent_82350b_command, +request_system_control : agilent_82350b_request_system_control, +take_control : agilent_82350b_take_control, +go_to_standby : agilent_82350b_go_to_standby, +interface_clear : agilent_82350b_interface_clear, +remote_enable : agilent_82350b_remote_enable, +enable_eos : agilent_82350b_enable_eos, +disable_eos : agilent_82350b_disable_eos, +parallel_poll : agilent_82350b_parallel_poll, +parallel_poll_configure : agilent_82350b_parallel_poll_configure, +parallel_poll_response : agilent_82350b_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : agilent_82350b_line_status, +update_status : agilent_82350b_update_status, +primary_address : agilent_82350b_primary_address, +secondary_address : agilent_82350b_secondary_address, +serial_poll_response : agilent_82350b_serial_poll_response, +t1_delay : agilent_82350b_t1_delay, +return_to_local : agilent_82350b_return_to_local, +}; + +static int agilent_82350b_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) + +{ + return 0; +} + +static const struct pci_device_id agilent_82350b_pci_table[] = { + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_HP, + PCI_SUBDEVICE_ID_82350A, 0, 0, 0 }, + { PCI_VENDOR_ID_AGILENT, PCI_DEVICE_ID_82350B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_AGILENT, PCI_DEVICE_ID_82351A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, agilent_82350b_pci_table); + +static struct pci_driver agilent_82350b_pci_driver = { + .name = "agilent_82350b", + .id_table = agilent_82350b_pci_table, + .probe = &agilent_82350b_pci_probe +}; + +static int __init agilent_82350b_init_module(void) + +{ + int result; + + result = pci_register_driver(&agilent_82350b_pci_driver); + if (result) { + pr_err("agilent_82350b: pci_driver_register failed!\n"); + return result; + } + + gpib_register_driver(&agilent_82350b_unaccel_interface, THIS_MODULE); + gpib_register_driver(&agilent_82350b_interface, THIS_MODULE); + return 0; +} + +static void __exit agilent_82350b_exit_module(void) + +{ + gpib_unregister_driver(&agilent_82350b_interface); + gpib_unregister_driver(&agilent_82350b_unaccel_interface); + + pci_unregister_driver(&agilent_82350b_pci_driver); +} + +module_init(agilent_82350b_init_module); +module_exit(agilent_82350b_exit_module); diff --git a/drivers/staging/gpib/agilent_82350b/agilent_82350b.h b/drivers/staging/gpib/agilent_82350b/agilent_82350b.h new file mode 100644 index 00000000000000..30683d67d17050 --- /dev/null +++ b/drivers/staging/gpib/agilent_82350b/agilent_82350b.h @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002, 2004 by Frank Mori Hess * + ***************************************************************************/ + +#include "gpibP.h" +#include "plx9050.h" +#include "tms9914.h" + +enum pci_vendor_ids { + PCI_VENDOR_ID_AGILENT = 0x15bc, +}; + +enum pci_device_ids { + PCI_DEVICE_ID_82350B = 0x0b01, + PCI_DEVICE_ID_82351A = 0x1218 +}; + +enum pci_subdevice_ids { + PCI_SUBDEVICE_ID_82350A = 0x10b0, +}; + +enum pci_regions_82350a { + PLX_MEM_REGION = 0, + PLX_IO_REGION = 1, + GPIB_82350A_REGION = 2, + SRAM_82350A_REGION = 3, + BORG_82350A_REGION = 4 +}; + +enum pci_regions_82350b { + GPIB_REGION = 0, + SRAM_REGION = 1, + MISC_REGION = 2, +}; + +enum board_model { + MODEL_82350A, + MODEL_82350B, + MODEL_82351A +}; + +// struct which defines private_data for board +struct agilent_82350b_priv { + struct tms9914_priv tms9914_priv; + struct pci_dev *pci_device; + void *plx_base; //82350a only + void *gpib_base; + void *sram_base; + void *misc_base; + void *borg_base; + int irq; + unsigned short card_mode_bits; + unsigned short event_status_bits; + enum board_model model; + bool using_fifos; +}; + +// driver name +extern const char *driver_name; + +// interfaces +extern gpib_interface_t agilent_82350b_interface; +// init functions + +int agilent_82350b_unaccel_attach(gpib_board_t *board, const gpib_board_config_t *config); +int agilent_82350b_accel_attach(gpib_board_t *board, const gpib_board_config_t *config); + +// interface functions +int agilent_82350b_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read); +int agilent_82350b_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written); +int agilent_82350b_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read); +int agilent_82350b_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written); +int agilent_82350b_command(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written); +int agilent_82350b_take_control(gpib_board_t *board, int synchronous); +int agilent_82350b_go_to_standby(gpib_board_t *board); +void agilent_82350b_request_system_control(gpib_board_t *board, int request_control); +void agilent_82350b_interface_clear(gpib_board_t *board, int assert); +void agilent_82350b_remote_enable(gpib_board_t *board, int enable); +int agilent_82350b_enable_eos(gpib_board_t *board, uint8_t eos_byte, int + compare_8_bits); +void agilent_82350b_disable_eos(gpib_board_t *board); +unsigned int agilent_82350b_update_status(gpib_board_t *board, unsigned int clear_mask); +int agilent_82350b_primary_address(gpib_board_t *board, unsigned int address); +int agilent_82350b_secondary_address(gpib_board_t *board, unsigned int address, int + enable); +int agilent_82350b_parallel_poll(gpib_board_t *board, uint8_t *result); +void agilent_82350b_parallel_poll_configure(gpib_board_t *board, uint8_t config); +void agilent_82350b_parallel_poll_response(gpib_board_t *board, int ist); +void agilent_82350b_serial_poll_response(gpib_board_t *board, uint8_t status); +void agilent_82350b_return_to_local(gpib_board_t *board); +uint8_t agilent_82350b_serial_poll_status(gpib_board_t *board); +int agilent_82350b_line_status(const gpib_board_t *board); +unsigned int agilent_82350b_t1_delay(gpib_board_t *board, unsigned int nanosec); + +// interrupt service routines +irqreturn_t agilent_82350b_interrupt(int irq, void *arg); + +// utility functions +int agilent_82350b_allocate_private(gpib_board_t *board); +void agilent_82350b_free_private(gpib_board_t *board); +unsigned short read_and_clear_event_status(gpib_board_t *board); +int read_transfer_counter(struct agilent_82350b_priv *a_priv); +void set_transfer_counter(struct agilent_82350b_priv *a_priv, int count); + +//registers +enum agilent_82350b_gpib_registers + +{ + CARD_MODE_REG = 0x1, + CONFIG_DATA_REG = 0x2, // 82350A specific + INTERRUPT_ENABLE_REG = 0x3, + EVENT_STATUS_REG = 0x4, + EVENT_ENABLE_REG = 0x5, + STREAM_STATUS_REG = 0x7, + DEBUG_RAM0_REG = 0x8, + DEBUG_RAM1_REG = 0x9, + DEBUG_RAM2_REG = 0xa, + DEBUG_RAM3_REG = 0xb, + XFER_COUNT_LO_REG = 0xc, + XFER_COUNT_MID_REG = 0xd, + XFER_COUNT_HI_REG = 0xe, + TMS9914_BASE_REG = 0x10, + INTERNAL_CONFIG_REG = 0x18, + IMR0_READ_REG = 0x19, //read + T1_DELAY_REG = 0x19, // write + IMR1_READ_REG = 0x1a, + ADR_READ_REG = 0x1b, + SPMR_READ_REG = 0x1c, + PPR_READ_REG = 0x1d, + CDOR_READ_REG = 0x1e, + SRAM_ACCESS_CONTROL_REG = 0x1f, +}; + +enum card_mode_bits + +{ + ACTIVE_CONTROLLER_BIT = 0x2, // read-only + CM_SYSTEM_CONTROLLER_BIT = 0x8, + ENABLE_BUS_MONITOR_BIT = 0x10, + ENABLE_PCI_IRQ_BIT = 0x20, +}; + +enum interrupt_enable_bits + +{ + ENABLE_TMS9914_INTERRUPTS_BIT = 0x1, + ENABLE_BUFFER_END_INTERRUPT_BIT = 0x10, + ENABLE_TERM_COUNT_INTERRUPT_BIT = 0x20, +}; + +enum event_enable_bits + +{ + ENABLE_BUFFER_END_EVENTS_BIT = 0x10, + ENABLE_TERM_COUNT_EVENTS_BIT = 0x20, +}; + +enum event_status_bits + +{ + TMS9914_IRQ_STATUS_BIT = 0x1, + IRQ_STATUS_BIT = 0x2, + BUFFER_END_STATUS_BIT = 0x10, // write-clear + TERM_COUNT_STATUS_BIT = 0x20, // write-clear +}; + +enum stream_status_bits + +{ + HALTED_STATUS_BIT = 0x1, //read + RESTART_STREAM_BIT = 0x1, //write +}; + +enum internal_config_bits + +{ + IC_SYSTEM_CONTROLLER_BIT = 0x80, +}; + +enum sram_access_control_bits + +{ + DIRECTION_GPIB_TO_HOST = 0x20, // transfer direction + ENABLE_TI_TO_SRAM = 0x40, // enable fifo + ENABLE_FAST_TALKER = 0x80 // added for 82350A (not used) +}; + +enum borg_bits + +{ + BORG_READY_BIT = 0x40, + BORG_DONE_BIT = 0x80 +}; + +static const int agilent_82350b_fifo_size = 0x8000; + +static inline int agilent_82350b_fifo_is_halted(struct agilent_82350b_priv *a_priv) + +{ + return readb(a_priv->gpib_base + STREAM_STATUS_REG) & HALTED_STATUS_BIT; +} + diff --git a/drivers/staging/gpib/agilent_82357a/Makefile b/drivers/staging/gpib/agilent_82357a/Makefile new file mode 100644 index 00000000000000..4a1d940fce2b83 --- /dev/null +++ b/drivers/staging/gpib/agilent_82357a/Makefile @@ -0,0 +1,4 @@ + +obj-m += agilent_82357a.o + + diff --git a/drivers/staging/gpib/agilent_82357a/agilent_82357a.c b/drivers/staging/gpib/agilent_82357a/agilent_82357a.c new file mode 100644 index 00000000000000..bf05fb4a736b3f --- /dev/null +++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.c @@ -0,0 +1,1712 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * driver for Agilent 82357A/B usb to gpib adapters * + * copyright : (C) 2004 by Frank Mori Hess * + ***************************************************************************/ + +#define _GNU_SOURCE + +#include +#include +#include +#include "agilent_82357a.h" +#include "gpibP.h" +#include "tms9914.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for Agilent 82357A/B usb adapters"); + +#define MAX_NUM_82357A_INTERFACES 128 +static struct usb_interface *agilent_82357a_driver_interfaces[MAX_NUM_82357A_INTERFACES]; +DEFINE_MUTEX(agilent_82357a_hotplug_lock); // protect board insertion and removal + +static unsigned int agilent_82357a_update_status(gpib_board_t *board, unsigned int clear_mask); + +static int agilent_82357a_take_control_internal(gpib_board_t *board, int synchronous); + +static void agilent_82357a_bulk_complete(struct urb *urb) +{ + struct agilent_82357a_urb_ctx *context = urb->context; + + up(&context->complete); +} + +static void agilent_82357a_timeout_handler(struct timer_list *t) +{ + struct agilent_82357a_priv *a_priv = from_timer(a_priv, t, bulk_timer); + struct agilent_82357a_urb_ctx *context = &a_priv->context; + + context->timed_out = 1; + up(&context->complete); +} + +static int agilent_82357a_send_bulk_msg(struct agilent_82357a_priv *a_priv, void *data, + int data_length, int *actual_data_length, + int timeout_msecs) +{ + struct usb_device *usb_dev; + int retval; + unsigned int out_pipe; + struct agilent_82357a_urb_ctx *context = &a_priv->context; + + *actual_data_length = 0; + retval = mutex_lock_interruptible(&a_priv->bulk_alloc_lock); + if (retval) + return retval; + if (!a_priv->bus_interface) { + mutex_unlock(&a_priv->bulk_alloc_lock); + return -ENODEV; + } + if (a_priv->bulk_urb) { + mutex_unlock(&a_priv->bulk_alloc_lock); + return -EAGAIN; + } + a_priv->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!a_priv->bulk_urb) { + mutex_unlock(&a_priv->bulk_alloc_lock); + return -ENOMEM; + } + usb_dev = interface_to_usbdev(a_priv->bus_interface); + out_pipe = usb_sndbulkpipe(usb_dev, a_priv->bulk_out_endpoint); + sema_init(&context->complete, 0); + context->timed_out = 0; + usb_fill_bulk_urb(a_priv->bulk_urb, usb_dev, out_pipe, data, data_length, + &agilent_82357a_bulk_complete, context); + + if (timeout_msecs) + mod_timer(&a_priv->bulk_timer, jiffies + msecs_to_jiffies(timeout_msecs)); + + retval = usb_submit_urb(a_priv->bulk_urb, GFP_KERNEL); + if (retval) { + dev_err(&usb_dev->dev, "%s: failed to submit bulk out urb, retval=%i\n", + __func__, retval); + mutex_unlock(&a_priv->bulk_alloc_lock); + goto cleanup; + } + mutex_unlock(&a_priv->bulk_alloc_lock); + if (down_interruptible(&context->complete)) { + dev_err(&usb_dev->dev, "%s: interrupted\n", __func__); + retval = -ERESTARTSYS; + goto cleanup; + } + if (context->timed_out) { + retval = -ETIMEDOUT; + } else { + retval = a_priv->bulk_urb->status; + *actual_data_length = a_priv->bulk_urb->actual_length; + } +cleanup: + if (timeout_msecs) { + if (timer_pending(&a_priv->bulk_timer)) + del_timer_sync(&a_priv->bulk_timer); + } + mutex_lock(&a_priv->bulk_alloc_lock); + if (a_priv->bulk_urb) { + usb_kill_urb(a_priv->bulk_urb); + usb_free_urb(a_priv->bulk_urb); + a_priv->bulk_urb = NULL; + } + mutex_unlock(&a_priv->bulk_alloc_lock); + return retval; +} + +static int agilent_82357a_receive_bulk_msg(struct agilent_82357a_priv *a_priv, void *data, + int data_length, int *actual_data_length, + int timeout_msecs) +{ + struct usb_device *usb_dev; + int retval; + unsigned int in_pipe; + struct agilent_82357a_urb_ctx *context = &a_priv->context; + + *actual_data_length = 0; + retval = mutex_lock_interruptible(&a_priv->bulk_alloc_lock); + if (retval) + return retval; + if (!a_priv->bus_interface) { + mutex_unlock(&a_priv->bulk_alloc_lock); + return -ENODEV; + } + if (a_priv->bulk_urb) { + mutex_unlock(&a_priv->bulk_alloc_lock); + return -EAGAIN; + } + a_priv->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!a_priv->bulk_urb) { + mutex_unlock(&a_priv->bulk_alloc_lock); + return -ENOMEM; + } + usb_dev = interface_to_usbdev(a_priv->bus_interface); + in_pipe = usb_rcvbulkpipe(usb_dev, AGILENT_82357_BULK_IN_ENDPOINT); + sema_init(&context->complete, 0); + context->timed_out = 0; + usb_fill_bulk_urb(a_priv->bulk_urb, usb_dev, in_pipe, data, data_length, + &agilent_82357a_bulk_complete, context); + + if (timeout_msecs) + mod_timer(&a_priv->bulk_timer, jiffies + msecs_to_jiffies(timeout_msecs)); + + retval = usb_submit_urb(a_priv->bulk_urb, GFP_KERNEL); + if (retval) { + dev_err(&usb_dev->dev, "%s: failed to submit bulk out urb, retval=%i\n", + __func__, retval); + mutex_unlock(&a_priv->bulk_alloc_lock); + goto cleanup; + } + mutex_unlock(&a_priv->bulk_alloc_lock); + if (down_interruptible(&context->complete)) { + dev_err(&usb_dev->dev, "%s: interrupted\n", __func__); + retval = -ERESTARTSYS; + goto cleanup; + } + if (context->timed_out) { + retval = -ETIMEDOUT; + goto cleanup; + } + retval = a_priv->bulk_urb->status; + *actual_data_length = a_priv->bulk_urb->actual_length; +cleanup: + if (timeout_msecs) + del_timer_sync(&a_priv->bulk_timer); + + mutex_lock(&a_priv->bulk_alloc_lock); + if (a_priv->bulk_urb) { + usb_kill_urb(a_priv->bulk_urb); + usb_free_urb(a_priv->bulk_urb); + a_priv->bulk_urb = NULL; + } + mutex_unlock(&a_priv->bulk_alloc_lock); + return retval; +} + +static int agilent_82357a_receive_control_msg(struct agilent_82357a_priv *a_priv, __u8 request, + __u8 requesttype, __u16 value, __u16 index, + void *data, __u16 size, int timeout_msecs) +{ + struct usb_device *usb_dev; + int retval; + unsigned int in_pipe; + + retval = mutex_lock_interruptible(&a_priv->control_alloc_lock); + if (retval) + return retval; + if (!a_priv->bus_interface) { + mutex_unlock(&a_priv->control_alloc_lock); + return -ENODEV; + } + usb_dev = interface_to_usbdev(a_priv->bus_interface); + in_pipe = usb_rcvctrlpipe(usb_dev, AGILENT_82357_CONTROL_ENDPOINT); + retval = usb_control_msg(usb_dev, in_pipe, request, requesttype, value, index, data, + size, timeout_msecs); + mutex_unlock(&a_priv->control_alloc_lock); + return retval; +} + +static void agilent_82357a_dump_raw_block(const u8 *raw_data, int length) +{ + pr_info("hex block dump\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 8, 1, raw_data, length, true); +} + +static int agilent_82357a_write_registers(struct agilent_82357a_priv *a_priv, + const struct agilent_82357a_register_pairlet *writes, + int num_writes) +{ + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + int retval; + u8 *out_data, *in_data; + int out_data_length, in_data_length; + int bytes_written, bytes_read; + int i = 0; + int j; + static const int bytes_per_write = 2; + static const int header_length = 2; + static const int max_writes = 31; + + if (num_writes > max_writes) { + dev_err(&usb_dev->dev, "%s: bug! num_writes=%i too large\n", __func__, num_writes); + return -EIO; + } + out_data_length = num_writes * bytes_per_write + header_length; + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + + out_data[i++] = DATA_PIPE_CMD_WR_REGS; + out_data[i++] = num_writes; + for (j = 0; j < num_writes; j++) { + out_data[i++] = writes[j].address; + out_data[i++] = writes[j].value; + } + if (i > out_data_length) + dev_err(&usb_dev->dev, "%s: bug! buffer overrun\n", __func__); + retval = mutex_lock_interruptible(&a_priv->bulk_transfer_lock); + if (retval) { + kfree(out_data); + return retval; + } + retval = agilent_82357a_send_bulk_msg(a_priv, out_data, i, &bytes_written, 1000); + kfree(out_data); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + mutex_unlock(&a_priv->bulk_transfer_lock); + return retval; + } + in_data_length = 0x20; + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&a_priv->bulk_transfer_lock); + return -ENOMEM; + } + retval = agilent_82357a_receive_bulk_msg(a_priv, in_data, in_data_length, + &bytes_read, 1000); + mutex_unlock(&a_priv->bulk_transfer_lock); + + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + agilent_82357a_dump_raw_block(in_data, bytes_read); + kfree(in_data); + return -EIO; + } + if (in_data[0] != (0xff & ~DATA_PIPE_CMD_WR_REGS)) { + dev_err(&usb_dev->dev, "%s: error, bulk command=0x%x != ~DATA_PIPE_CMD_WR_REGS\n", + __func__, in_data[0]); + return -EIO; + } + if (in_data[1]) { + dev_err(&usb_dev->dev, "%s: nonzero error code 0x%x in DATA_PIPE_CMD_WR_REGS response\n", + __func__, in_data[1]); + return -EIO; + } + kfree(in_data); + return 0; +} + +static int agilent_82357a_read_registers(struct agilent_82357a_priv *a_priv, + struct agilent_82357a_register_pairlet *reads, + int num_reads, int blocking) +{ + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + int retval; + u8 *out_data, *in_data; + int out_data_length, in_data_length; + int bytes_written, bytes_read; + int i = 0; + int j; + static const int header_length = 2; + static const int max_reads = 62; + + if (num_reads > max_reads) + dev_err(&usb_dev->dev, "%s: bug! num_reads=%i too large\n", __func__, num_reads); + + out_data_length = num_reads + header_length; + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + + out_data[i++] = DATA_PIPE_CMD_RD_REGS; + out_data[i++] = num_reads; + for (j = 0; j < num_reads; j++) + out_data[i++] = reads[j].address; + if (i > out_data_length) + dev_err(&usb_dev->dev, "%s: bug! buffer overrun\n", __func__); + if (blocking) { + retval = mutex_lock_interruptible(&a_priv->bulk_transfer_lock); + if (retval) { + kfree(out_data); + return retval; + } + } else { + retval = mutex_trylock(&a_priv->bulk_transfer_lock); + if (retval == 0) { + kfree(out_data); + return -EAGAIN; + } + } + retval = agilent_82357a_send_bulk_msg(a_priv, out_data, i, &bytes_written, 1000); + kfree(out_data); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + mutex_unlock(&a_priv->bulk_transfer_lock); + return retval; + } + in_data_length = 0x20; + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&a_priv->bulk_transfer_lock); + return -ENOMEM; + } + retval = agilent_82357a_receive_bulk_msg(a_priv, in_data, in_data_length, + &bytes_read, 10000); + mutex_unlock(&a_priv->bulk_transfer_lock); + + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + agilent_82357a_dump_raw_block(in_data, bytes_read); + kfree(in_data); + return -EIO; + } + i = 0; + if (in_data[i++] != (0xff & ~DATA_PIPE_CMD_RD_REGS)) { + dev_err(&usb_dev->dev, "%s: error, bulk command=0x%x != ~DATA_PIPE_CMD_RD_REGS\n", + __func__, in_data[0]); + return -EIO; + } + if (in_data[i++]) { + dev_err(&usb_dev->dev, "%s: nonzero error code 0x%x in DATA_PIPE_CMD_RD_REGS response\n", + __func__, in_data[1]); + return -EIO; + } + for (j = 0; j < num_reads; j++) + reads[j].value = in_data[i++]; + kfree(in_data); + return 0; +} + +static int agilent_82357a_abort(struct agilent_82357a_priv *a_priv, int flush) +{ + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + int retval = 0; + int receive_control_retval; + u16 wIndex = 0; + u8 *status_data; + static const unsigned int status_data_len = 2; + + status_data = kmalloc(status_data_len, GFP_KERNEL); + if (!status_data) + return -ENOMEM; + + if (flush) + wIndex |= XA_FLUSH; + receive_control_retval = agilent_82357a_receive_control_msg(a_priv, + agilent_82357a_control_request, + USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, XFER_ABORT, + wIndex, status_data, + status_data_len, 100); + if (receive_control_retval < 0) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_receive_control_msg() returned %i\n", + __func__, receive_control_retval); + retval = -EIO; + goto cleanup; + } + if (status_data[0] != (~XFER_ABORT & 0xff)) { + dev_err(&usb_dev->dev, "%s: error, major code=0x%x != ~XFER_ABORT\n", + __func__, status_data[0]); + retval = -EIO; + goto cleanup; + } + switch (status_data[1]) { + case UGP_SUCCESS: + retval = 0; + break; + case UGP_ERR_FLUSHING: + if (flush) { + retval = 0; + break; + } + fallthrough; + case UGP_ERR_FLUSHING_ALREADY: + default: + dev_err(&usb_dev->dev, "%s: abort returned error code=0x%x\n", + __func__, status_data[1]); + retval = -EIO; + break; + } + +cleanup: + kfree(status_data); + return retval; +} + +// interface functions +int agilent_82357a_command(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written); + +static int agilent_82357a_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *nbytes) +{ + int retval; + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + u8 *out_data, *in_data; + int out_data_length, in_data_length; + int bytes_written, bytes_read; + int i = 0; + u8 trailing_flags; + unsigned long start_jiffies = jiffies; + int msec_timeout; + + *nbytes = 0; + *end = 0; + out_data_length = 0x9; + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + out_data[i++] = DATA_PIPE_CMD_READ; + out_data[i++] = 0; //primary address when ARF_NO_ADDR is not set + out_data[i++] = 0; //secondary address when ARF_NO_ADDR is not set + out_data[i] = ARF_NO_ADDRESS | ARF_END_ON_EOI; + if (a_priv->eos_mode & REOS) + out_data[i] |= ARF_END_ON_EOS_CHAR; + ++i; + out_data[i++] = length & 0xff; + out_data[i++] = (length >> 8) & 0xff; + out_data[i++] = (length >> 16) & 0xff; + out_data[i++] = (length >> 24) & 0xff; + out_data[i++] = a_priv->eos_char; + msec_timeout = (board->usec_timeout + 999) / 1000; + retval = mutex_lock_interruptible(&a_priv->bulk_transfer_lock); + if (retval) { + kfree(out_data); + return retval; + } + retval = agilent_82357a_send_bulk_msg(a_priv, out_data, i, &bytes_written, msec_timeout); + kfree(out_data); + if (retval || bytes_written != i) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + mutex_unlock(&a_priv->bulk_transfer_lock); + if (retval < 0) + return retval; + return -EIO; + } + in_data_length = length + 1; + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&a_priv->bulk_transfer_lock); + return -ENOMEM; + } + if (board->usec_timeout != 0) + msec_timeout -= jiffies_to_msecs(jiffies - start_jiffies) - 1; + if (msec_timeout >= 0) { + retval = agilent_82357a_receive_bulk_msg(a_priv, in_data, in_data_length, + &bytes_read, msec_timeout); + } else { + retval = -ETIMEDOUT; + bytes_read = 0; + } + if (retval == -ETIMEDOUT) { + int extra_bytes_read; + int extra_bytes_retval; + + agilent_82357a_abort(a_priv, 1); + extra_bytes_retval = agilent_82357a_receive_bulk_msg(a_priv, in_data + bytes_read, + in_data_length - bytes_read, + &extra_bytes_read, 100); + bytes_read += extra_bytes_read; + if (extra_bytes_retval) { + dev_err(&usb_dev->dev, "%s: extra_bytes_retval=%i, bytes_read=%i\n", + __func__, extra_bytes_retval, bytes_read); + agilent_82357a_abort(a_priv, 0); + } + } else if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + agilent_82357a_abort(a_priv, 0); + } + mutex_unlock(&a_priv->bulk_transfer_lock); + if (bytes_read > length + 1) { + bytes_read = length + 1; + pr_warn("%s: bytes_read > length? truncating", __func__); + } + + if (bytes_read >= 1) { + memcpy(buffer, in_data, bytes_read - 1); + trailing_flags = in_data[bytes_read - 1]; + *nbytes = bytes_read - 1; + if (trailing_flags & (ATRF_EOI | ATRF_EOS)) + *end = 1; + } + kfree(in_data); + + /* Fix for a bug in 9914A that does not return the contents of ADSR + * when the board is in listener active state and ATN is not asserted. + * Set ATN here to obtain a valid board level ibsta + */ + agilent_82357a_take_control_internal(board, 0); + + //FIXME check trailing flags for error + return retval; +} + +static ssize_t agilent_82357a_generic_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_commands, int send_eoi, size_t *bytes_written) +{ + int retval; + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + u8 *out_data = NULL; + u8 *status_data = NULL; + int out_data_length; + int raw_bytes_written; + int i = 0, j; + int msec_timeout; + unsigned short bsr, adsr; + struct agilent_82357a_register_pairlet read_reg; + + *bytes_written = 0; + out_data_length = length + 0x8; + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + out_data[i++] = DATA_PIPE_CMD_WRITE; + out_data[i++] = 0; // primary address when AWF_NO_ADDRESS is not set + out_data[i++] = 0; // secondary address when AWF_NO_ADDRESS is not set + out_data[i] = AWF_NO_ADDRESS | AWF_NO_FAST_TALKER_FIRST_BYTE; + if (send_commands) + out_data[i] |= AWF_ATN | AWF_NO_FAST_TALKER; + if (send_eoi) + out_data[i] |= AWF_SEND_EOI; + ++i; + out_data[i++] = length & 0xff; + out_data[i++] = (length >> 8) & 0xff; + out_data[i++] = (length >> 16) & 0xff; + out_data[i++] = (length >> 24) & 0xff; + for (j = 0; j < length; j++) + out_data[i++] = buffer[j]; + + clear_bit(AIF_WRITE_COMPLETE_BN, &a_priv->interrupt_flags); + + msec_timeout = (board->usec_timeout + 999) / 1000; + retval = mutex_lock_interruptible(&a_priv->bulk_transfer_lock); + if (retval) { + kfree(out_data); + return retval; + } + retval = agilent_82357a_send_bulk_msg(a_priv, out_data, i, &raw_bytes_written, + msec_timeout); + kfree(out_data); + if (retval || raw_bytes_written != i) { + agilent_82357a_abort(a_priv, 0); + dev_err(&usb_dev->dev, "%s: agilent_82357a_send_bulk_msg returned %i, raw_bytes_written=%i, i=%i\n", + __func__, retval, raw_bytes_written, i); + mutex_unlock(&a_priv->bulk_transfer_lock); + if (retval < 0) + return retval; + return -EIO; + } + + retval = wait_event_interruptible(board->wait, + test_bit(AIF_WRITE_COMPLETE_BN, + &a_priv->interrupt_flags) || + test_bit(TIMO_NUM, &board->status)); + if (retval) { + dev_err(&usb_dev->dev, "%s: wait write complete interrupted\n", __func__); + agilent_82357a_abort(a_priv, 0); + mutex_unlock(&a_priv->bulk_transfer_lock); + return -ERESTARTSYS; + } + + if (test_bit(AIF_WRITE_COMPLETE_BN, &a_priv->interrupt_flags) == 0) { + dev_dbg(&usb_dev->dev, "write timed out ibs %i, tmo %i\n", + test_bit(TIMO_NUM, &board->status), msec_timeout); + + agilent_82357a_abort(a_priv, 0); + + mutex_unlock(&a_priv->bulk_transfer_lock); + + read_reg.address = BSR; + retval = agilent_82357a_read_registers(a_priv, &read_reg, 1, 1); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_read_registers() returned error\n", + __func__); + return -ETIMEDOUT; + } + + bsr = read_reg.value; + dev_dbg(&usb_dev->dev, "write aborted bsr 0x%x\n", bsr); + + if (send_commands) {/* check for no listeners */ + if ((bsr & BSR_ATN_BIT) && !(bsr & (BSR_NDAC_BIT | BSR_NRFD_BIT))) { + dev_dbg(&usb_dev->dev, "No listener on command\n"); + clear_bit(TIMO_NUM, &board->status); + return -ENOTCONN; // no listener on bus + } + } else { + read_reg.address = ADSR; + retval = agilent_82357a_read_registers(a_priv, &read_reg, 1, 1); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_read_registers() returned error\n", + __func__); + return -ETIMEDOUT; + } + adsr = read_reg.value; + if ((adsr & HR_TA) && !(bsr & (BSR_NDAC_BIT | BSR_NRFD_BIT))) { + dev_dbg(&usb_dev->dev, "No listener on write\n"); + clear_bit(TIMO_NUM, &board->status); + return -ECOMM; + } + } + + return -ETIMEDOUT; + } + + status_data = kmalloc(STATUS_DATA_LEN, GFP_KERNEL); + if (!status_data) { + mutex_unlock(&a_priv->bulk_transfer_lock); + return -ENOMEM; + } + + retval = agilent_82357a_receive_control_msg(a_priv, agilent_82357a_control_request, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + XFER_STATUS, 0, status_data, STATUS_DATA_LEN, + 100); + mutex_unlock(&a_priv->bulk_transfer_lock); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_receive_control_msg() returned %i\n", + __func__, retval); + kfree(status_data); + return -EIO; + } + *bytes_written = (u32)status_data[2]; + *bytes_written |= (u32)status_data[3] << 8; + *bytes_written |= (u32)status_data[4] << 16; + *bytes_written |= (u32)status_data[5] << 24; + + kfree(status_data); + return 0; +} + +static int agilent_82357a_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + return agilent_82357a_generic_write(board, buffer, length, 0, send_eoi, bytes_written); +} + +int agilent_82357a_command(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written) +{ + return agilent_82357a_generic_write(board, buffer, length, 1, 0, bytes_written); +} + +int agilent_82357a_take_control_internal(gpib_board_t *board, int synchronous) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet write; + int retval; + + write.address = AUXCR; + if (synchronous) + write.value = AUX_TCS; + else + write.value = AUX_TCA; + retval = agilent_82357a_write_registers(a_priv, &write, 1); + if (retval) + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + + return retval; +} + +static int agilent_82357a_take_control(gpib_board_t *board, int synchronous) +{ + const int timeout = 10; + int i; + +/* It looks like the 9914 does not handle tcs properly. + * See comment above tms9914_take_control_workaround() in + * drivers/gpib/tms9914/tms9914_aux.c + */ + if (synchronous) + return -ETIMEDOUT; + + agilent_82357a_take_control_internal(board, synchronous); + // busy wait until ATN is asserted + for (i = 0; i < timeout; ++i) { + agilent_82357a_update_status(board, 0); + if (test_bit(ATN_NUM, &board->status)) + break; + udelay(1); + } + if (i == timeout) + return -ETIMEDOUT; + return 0; +} + +static int agilent_82357a_go_to_standby(gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet write; + int retval; + + write.address = AUXCR; + write.value = AUX_GTS; + retval = agilent_82357a_write_registers(a_priv, &write, 1); + if (retval) + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return 0; +} + +//FIXME should change prototype to return int +static void agilent_82357a_request_system_control(gpib_board_t *board, int request_control) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet writes[2]; + int retval; + int i = 0; + + /* 82357B needs bit to be set in 9914 AUXCR register */ + writes[i].address = AUXCR; + if (request_control) { + writes[i].value = AUX_RQC; + a_priv->hw_control_bits |= SYSTEM_CONTROLLER; + } else { + writes[i].value = AUX_RLC; + a_priv->is_cic = 0; + a_priv->hw_control_bits &= ~SYSTEM_CONTROLLER; + } + ++i; + writes[i].address = HW_CONTROL; + writes[i].value = a_priv->hw_control_bits; + ++i; + retval = agilent_82357a_write_registers(a_priv, writes, i); + if (retval) + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return;// retval; +} + +static void agilent_82357a_interface_clear(gpib_board_t *board, int assert) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet write; + int retval; + + write.address = AUXCR; + write.value = AUX_SIC; + if (assert) { + write.value |= AUX_CS; + a_priv->is_cic = 1; + } + retval = agilent_82357a_write_registers(a_priv, &write, 1); + if (retval) + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); +} + +static void agilent_82357a_remote_enable(gpib_board_t *board, int enable) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet write; + int retval; + + write.address = AUXCR; + write.value = AUX_SRE; + if (enable) + write.value |= AUX_CS; + retval = agilent_82357a_write_registers(a_priv, &write, 1); + if (retval) + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + a_priv->ren_state = enable; + return;// 0; +} + +static int agilent_82357a_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + + if (compare_8_bits == 0) { + pr_warn("%s: hardware only supports 8-bit EOS compare", __func__); + return -EOPNOTSUPP; + } + a_priv->eos_char = eos_byte; + a_priv->eos_mode = REOS | BIN; + return 0; +} + +static void agilent_82357a_disable_eos(gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + + a_priv->eos_mode &= ~REOS; +} + +static unsigned int agilent_82357a_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet address_status, bus_status; + int retval; + + board->status &= ~clear_mask; + if (a_priv->is_cic) + set_bit(CIC_NUM, &board->status); + else + clear_bit(CIC_NUM, &board->status); + address_status.address = ADSR; + retval = agilent_82357a_read_registers(a_priv, &address_status, 1, 0); + if (retval) { + if (retval != -EAGAIN) + dev_err(&usb_dev->dev, "%s: agilent_82357a_read_registers() returned error\n", + __func__); + return board->status; + } + // check for remote/local + if (address_status.value & HR_REM) + set_bit(REM_NUM, &board->status); + else + clear_bit(REM_NUM, &board->status); + // check for lockout + if (address_status.value & HR_LLO) + set_bit(LOK_NUM, &board->status); + else + clear_bit(LOK_NUM, &board->status); + // check for ATN + if (address_status.value & HR_ATN) + set_bit(ATN_NUM, &board->status); + else + clear_bit(ATN_NUM, &board->status); + // check for talker/listener addressed + if (address_status.value & HR_TA) + set_bit(TACS_NUM, &board->status); + else + clear_bit(TACS_NUM, &board->status); + if (address_status.value & HR_LA) + set_bit(LACS_NUM, &board->status); + else + clear_bit(LACS_NUM, &board->status); + + bus_status.address = BSR; + retval = agilent_82357a_read_registers(a_priv, &bus_status, 1, 0); + if (retval) { + if (retval != -EAGAIN) + dev_err(&usb_dev->dev, "%s: agilent_82357a_read_registers() returned error\n", + __func__); + return board->status; + } + if (bus_status.value & BSR_SRQ_BIT) + set_bit(SRQI_NUM, &board->status); + else + clear_bit(SRQI_NUM, &board->status); + + return board->status; +} + +static int agilent_82357a_primary_address(gpib_board_t *board, unsigned int address) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet write; + int retval; + + // put primary address in address0 + write.address = ADR; + write.value = address & ADDRESS_MASK; + retval = agilent_82357a_write_registers(a_priv, &write, 1); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return retval; + } + return retval; +} + +static int agilent_82357a_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + if (enable) + pr_warn("%s: warning: assigning a secondary address not supported\n", __func__); + return -EOPNOTSUPP; +} + +static int agilent_82357a_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet writes[2]; + struct agilent_82357a_register_pairlet read; + int retval; + + // execute parallel poll + writes[0].address = AUXCR; + writes[0].value = AUX_CS | AUX_RPP; + writes[1].address = HW_CONTROL; + writes[1].value = a_priv->hw_control_bits & ~NOT_PARALLEL_POLL; + retval = agilent_82357a_write_registers(a_priv, writes, 2); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return retval; + } + udelay(2); //silly, since usb write will take way longer + read.address = CPTR; + retval = agilent_82357a_read_registers(a_priv, &read, 1, 1); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_read_registers() returned error\n", + __func__); + return retval; + } + *result = read.value; + // clear parallel poll state + writes[0].address = HW_CONTROL; + writes[0].value = a_priv->hw_control_bits | NOT_PARALLEL_POLL; + writes[1].address = AUXCR; + writes[1].value = AUX_RPP; + retval = agilent_82357a_write_registers(a_priv, writes, 2); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return retval; + } + return 0; +} + +static void agilent_82357a_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + //board can only be system controller + return;// 0; +} + +static void agilent_82357a_parallel_poll_response(gpib_board_t *board, int ist) +{ + //board can only be system controller + return;// 0; +} + +static void agilent_82357a_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + //board can only be system controller + return;// 0; +} + +static uint8_t agilent_82357a_serial_poll_status(gpib_board_t *board) +{ + //board can only be system controller + return 0; +} + +static void agilent_82357a_return_to_local(gpib_board_t *board) +{ + //board can only be system controller + return;// 0; +} + +static int agilent_82357a_line_status(const gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet bus_status; + int retval; + int status = ValidALL; + + bus_status.address = BSR; + retval = agilent_82357a_read_registers(a_priv, &bus_status, 1, 0); + if (retval) { + if (retval != -EAGAIN) + dev_err(&usb_dev->dev, "%s: agilent_82357a_read_registers() returned error\n", + __func__); + return retval; + } + if (bus_status.value & BSR_REN_BIT) + status |= BusREN; + if (bus_status.value & BSR_IFC_BIT) + status |= BusIFC; + if (bus_status.value & BSR_SRQ_BIT) + status |= BusSRQ; + if (bus_status.value & BSR_EOI_BIT) + status |= BusEOI; + if (bus_status.value & BSR_NRFD_BIT) + status |= BusNRFD; + if (bus_status.value & BSR_NDAC_BIT) + status |= BusNDAC; + if (bus_status.value & BSR_DAV_BIT) + status |= BusDAV; + if (bus_status.value & BSR_ATN_BIT) + status |= BusATN; + return status; +} + +static unsigned short nanosec_to_fast_talker_bits(unsigned int *nanosec) +{ + static const int nanosec_per_bit = 21; + static const int max_value = 0x72; + static const int min_value = 0x11; + unsigned short bits; + + bits = (*nanosec + nanosec_per_bit / 2) / nanosec_per_bit; + if (bits < min_value) + bits = min_value; + if (bits > max_value) + bits = max_value; + *nanosec = bits * nanosec_per_bit; + return bits; +} + +static unsigned int agilent_82357a_t1_delay(gpib_board_t *board, unsigned int nanosec) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet write; + int retval; + + write.address = FAST_TALKER_T1; + write.value = nanosec_to_fast_talker_bits(&nanosec); + retval = agilent_82357a_write_registers(a_priv, &write, 1); + if (retval) + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return nanosec; +} + +static void agilent_82357a_interrupt_complete(struct urb *urb) +{ + gpib_board_t *board = urb->context; + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + int retval; + u8 *transfer_buffer = urb->transfer_buffer; + unsigned long interrupt_flags; + + switch (urb->status) { + /* success */ + case 0: + break; + /* unlinked, don't resubmit */ + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* other error, resubmit */ + retval = usb_submit_urb(a_priv->interrupt_urb, GFP_ATOMIC); + if (retval) + dev_err(&usb_dev->dev, "%s: failed to resubmit interrupt urb\n", __func__); + return; + } + + interrupt_flags = transfer_buffer[0]; + if (test_bit(AIF_READ_COMPLETE_BN, &interrupt_flags)) + set_bit(AIF_READ_COMPLETE_BN, &a_priv->interrupt_flags); + if (test_bit(AIF_WRITE_COMPLETE_BN, &interrupt_flags)) + set_bit(AIF_WRITE_COMPLETE_BN, &a_priv->interrupt_flags); + if (test_bit(AIF_SRQ_BN, &interrupt_flags)) + set_bit(SRQI_NUM, &board->status); + + wake_up_interruptible(&board->wait); + + retval = usb_submit_urb(a_priv->interrupt_urb, GFP_ATOMIC); + if (retval) + dev_err(&usb_dev->dev, "%s: failed to resubmit interrupt urb\n", __func__); +} + +static int agilent_82357a_setup_urbs(gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev; + int int_pipe; + int retval; + + retval = mutex_lock_interruptible(&a_priv->interrupt_alloc_lock); + if (retval) + return retval; + if (!a_priv->bus_interface) { + retval = -ENODEV; + goto setup_exit; + } + + a_priv->interrupt_buffer = kmalloc(INTERRUPT_BUF_LEN, GFP_KERNEL); + if (!a_priv->interrupt_buffer) { + retval = -ENOMEM; + goto setup_exit; + } + a_priv->interrupt_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!a_priv->interrupt_urb) { + retval = -ENOMEM; + goto setup_exit; + } + usb_dev = interface_to_usbdev(a_priv->bus_interface); + int_pipe = usb_rcvintpipe(usb_dev, a_priv->interrupt_in_endpoint); + usb_fill_int_urb(a_priv->interrupt_urb, usb_dev, int_pipe, a_priv->interrupt_buffer, + INTERRUPT_BUF_LEN, &agilent_82357a_interrupt_complete, board, 1); + retval = usb_submit_urb(a_priv->interrupt_urb, GFP_KERNEL); + if (retval) { + usb_free_urb(a_priv->interrupt_urb); + a_priv->interrupt_urb = NULL; + dev_err(&usb_dev->dev, "%s: failed to submit first interrupt urb, retval=%i\n", + __func__, retval); + goto setup_exit; + } + mutex_unlock(&a_priv->interrupt_alloc_lock); + return 0; + +setup_exit: + kfree(a_priv->interrupt_buffer); + mutex_unlock(&a_priv->interrupt_alloc_lock); + return retval; +} + +#ifdef RESET_USB_CONFIG +static int agilent_82357a_reset_usb_configuration(gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct usb_device *usb_dev; + int retval; + + if (!a_priv->bus_interface) + return -ENODEV; + usb_dev = interface_to_usbdev(a_priv->bus_interface); + retval = usb_reset_configuration(usb_dev); + if (retval) + dev_err(&usb_dev->dev, "%s: usb_reset_configuration() returned %i\n", + __func__, retval); + return retval; +} +#endif + +static void agilent_82357a_cleanup_urbs(struct agilent_82357a_priv *a_priv) +{ + if (a_priv && a_priv->bus_interface) { + if (a_priv->interrupt_urb) + usb_kill_urb(a_priv->interrupt_urb); + if (a_priv->bulk_urb) + usb_kill_urb(a_priv->bulk_urb); + } +}; + +static int agilent_82357a_allocate_private(gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv; + + board->private_data = kmalloc(sizeof(struct agilent_82357a_priv), GFP_KERNEL); + if (!board->private_data) + return -ENOMEM; + a_priv = board->private_data; + memset(a_priv, 0, sizeof(struct agilent_82357a_priv)); + mutex_init(&a_priv->bulk_transfer_lock); + mutex_init(&a_priv->bulk_alloc_lock); + mutex_init(&a_priv->control_alloc_lock); + mutex_init(&a_priv->interrupt_alloc_lock); + return 0; +} + +static void agilent_82357a_free_private(struct agilent_82357a_priv *a_priv) +{ + usb_free_urb(a_priv->interrupt_urb); + kfree(a_priv->interrupt_buffer); + kfree(a_priv); +} + +static int agilent_82357a_init(gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet hw_control; + struct agilent_82357a_register_pairlet writes[0x20]; + int retval; + int i; + unsigned int nanosec; + + i = 0; + writes[i].address = LED_CONTROL; + writes[i].value = FAIL_LED_ON; + ++i; + writes[i].address = RESET_TO_POWERUP; + writes[i].value = RESET_SPACEBALL; + ++i; + retval = agilent_82357a_write_registers(a_priv, writes, i); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return -EIO; + } + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout(usec_to_jiffies(2000))) + return -ERESTARTSYS; + i = 0; + writes[i].address = AUXCR; + writes[i].value = AUX_NBAF; + ++i; + writes[i].address = AUXCR; + writes[i].value = AUX_HLDE; + ++i; + writes[i].address = AUXCR; + writes[i].value = AUX_TON; + ++i; + writes[i].address = AUXCR; + writes[i].value = AUX_LON; + ++i; + writes[i].address = AUXCR; + writes[i].value = AUX_RSV2; + ++i; + writes[i].address = AUXCR; + writes[i].value = AUX_INVAL; + ++i; + writes[i].address = AUXCR; + writes[i].value = AUX_RPP; + ++i; + writes[i].address = AUXCR; + writes[i].value = AUX_STDL; + ++i; + writes[i].address = AUXCR; + writes[i].value = AUX_VSTDL; + ++i; + writes[i].address = FAST_TALKER_T1; + nanosec = board->t1_nano_sec; + writes[i].value = nanosec_to_fast_talker_bits(&nanosec); + board->t1_nano_sec = nanosec; + ++i; + writes[i].address = ADR; + writes[i].value = board->pad & ADDRESS_MASK; + ++i; + writes[i].address = PPR; + writes[i].value = 0; + ++i; + writes[i].address = SPMR; + writes[i].value = 0; + ++i; + writes[i].address = PROTOCOL_CONTROL; + writes[i].value = WRITE_COMPLETE_INTERRUPT_EN; + ++i; + writes[i].address = IMR0; + writes[i].value = HR_BOIE | HR_BIIE; + ++i; + writes[i].address = IMR1; + writes[i].value = HR_SRQIE; + ++i; + // turn off reset state + writes[i].address = AUXCR; + writes[i].value = AUX_CHIP_RESET; + ++i; + writes[i].address = LED_CONTROL; + writes[i].value = FIRMWARE_LED_CONTROL; + ++i; + if (i > ARRAY_SIZE(writes)) { + dev_err(&usb_dev->dev, "%s: bug! writes[] overflow\n", __func__); + return -EFAULT; + } + retval = agilent_82357a_write_registers(a_priv, writes, i); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return -EIO; + } + hw_control.address = HW_CONTROL; + retval = agilent_82357a_read_registers(a_priv, &hw_control, 1, 1); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_read_registers() returned error\n", + __func__); + return -EIO; + } + a_priv->hw_control_bits = (hw_control.value & ~0x7) | NOT_TI_RESET | NOT_PARALLEL_POLL; + + return 0; +} + +static inline int agilent_82357a_device_match(struct usb_interface *interface, + const gpib_board_config_t *config) +{ + struct usb_device * const usbdev = interface_to_usbdev(interface); + + if (gpib_match_device_path(&interface->dev, config->device_path) == 0) + return 0; + if (config->serial_number && + strcmp(usbdev->serial, config->serial_number) != 0) + return 0; + + return 1; +} + +static int agilent_82357a_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + int retval; + int i; + unsigned int product_id; + struct agilent_82357a_priv *a_priv; + struct usb_device *usb_dev; + + if (mutex_lock_interruptible(&agilent_82357a_hotplug_lock)) + return -ERESTARTSYS; + + retval = agilent_82357a_allocate_private(board); + if (retval < 0) { + mutex_unlock(&agilent_82357a_hotplug_lock); + return retval; + } + a_priv = board->private_data; + for (i = 0; i < MAX_NUM_82357A_INTERFACES; ++i) { + if (agilent_82357a_driver_interfaces[i] && + !usb_get_intfdata(agilent_82357a_driver_interfaces[i]) && + agilent_82357a_device_match(agilent_82357a_driver_interfaces[i], config)) { + a_priv->bus_interface = agilent_82357a_driver_interfaces[i]; + usb_set_intfdata(agilent_82357a_driver_interfaces[i], board); + usb_dev = interface_to_usbdev(a_priv->bus_interface); + dev_info(&usb_dev->dev, + "bus %d dev num %d attached to gpib minor %d, agilent usb interface %i\n", + usb_dev->bus->busnum, usb_dev->devnum, board->minor, i); + break; + } + } + if (i == MAX_NUM_82357A_INTERFACES) { + mutex_unlock(&agilent_82357a_hotplug_lock); + pr_err("No Agilent 82357 gpib adapters found, have you loaded its firmware?\n"); + return -ENODEV; + } + product_id = le16_to_cpu(interface_to_usbdev(a_priv->bus_interface)->descriptor.idProduct); + switch (product_id) { + case USB_DEVICE_ID_AGILENT_82357A: + a_priv->bulk_out_endpoint = AGILENT_82357A_BULK_OUT_ENDPOINT; + a_priv->interrupt_in_endpoint = AGILENT_82357A_INTERRUPT_IN_ENDPOINT; + break; + case USB_DEVICE_ID_AGILENT_82357B: + a_priv->bulk_out_endpoint = AGILENT_82357B_BULK_OUT_ENDPOINT; + a_priv->interrupt_in_endpoint = AGILENT_82357B_INTERRUPT_IN_ENDPOINT; + break; + default: + dev_err(&usb_dev->dev, "bug, unhandled product_id in switch?\n"); + return -EIO; + } +#ifdef RESET_USB_CONFIG + retval = agilent_82357a_reset_usb_configuration(board); + if (retval < 0) { + mutex_unlock(&agilent_82357a_hotplug_lock); + return retval; + } +#endif + retval = agilent_82357a_setup_urbs(board); + if (retval < 0) { + mutex_unlock(&agilent_82357a_hotplug_lock); + return retval; + } + + timer_setup(&a_priv->bulk_timer, agilent_82357a_timeout_handler, 0); + + board->t1_nano_sec = 800; + + retval = agilent_82357a_init(board); + + if (retval < 0) { + mutex_unlock(&agilent_82357a_hotplug_lock); + return retval; + } + + dev_info(&usb_dev->dev, "%s: attached\n", __func__); + mutex_unlock(&agilent_82357a_hotplug_lock); + return retval; +} + +static int agilent_82357a_go_idle(gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(a_priv->bus_interface); + struct agilent_82357a_register_pairlet writes[0x20]; + int retval; + int i; + + i = 0; + // turn on tms9914 reset state + writes[i].address = AUXCR; + writes[i].value = AUX_CS | AUX_CHIP_RESET; + ++i; + a_priv->hw_control_bits &= ~NOT_TI_RESET; + writes[i].address = HW_CONTROL; + writes[i].value = a_priv->hw_control_bits; + ++i; + writes[i].address = PROTOCOL_CONTROL; + writes[i].value = 0; + ++i; + writes[i].address = IMR0; + writes[i].value = 0; + ++i; + writes[i].address = IMR1; + writes[i].value = 0; + ++i; + writes[i].address = LED_CONTROL; + writes[i].value = 0; + ++i; + if (i > ARRAY_SIZE(writes)) { + dev_err(&usb_dev->dev, "%s: bug! writes[] overflow\n", __func__); + return -EFAULT; + } + retval = agilent_82357a_write_registers(a_priv, writes, i); + if (retval) { + dev_err(&usb_dev->dev, "%s: agilent_82357a_write_registers() returned error\n", + __func__); + return -EIO; + } + return 0; +} + +static void agilent_82357a_detach(gpib_board_t *board) +{ + struct agilent_82357a_priv *a_priv; + struct usb_device *usb_dev; + + mutex_lock(&agilent_82357a_hotplug_lock); + + a_priv = board->private_data; + usb_dev = interface_to_usbdev(a_priv->bus_interface); + if (a_priv) { + if (a_priv->bus_interface) { + agilent_82357a_go_idle(board); + usb_set_intfdata(a_priv->bus_interface, NULL); + } + mutex_lock(&a_priv->control_alloc_lock); + mutex_lock(&a_priv->bulk_alloc_lock); + mutex_lock(&a_priv->interrupt_alloc_lock); + agilent_82357a_cleanup_urbs(a_priv); + agilent_82357a_free_private(a_priv); + } + dev_info(&usb_dev->dev, "%s: detached\n", __func__); + mutex_unlock(&agilent_82357a_hotplug_lock); +} + +gpib_interface_t agilent_82357a_gpib_interface = { +name: "agilent_82357a", +attach : agilent_82357a_attach, +detach : agilent_82357a_detach, +read : agilent_82357a_read, +write : agilent_82357a_write, +command : agilent_82357a_command, +take_control : agilent_82357a_take_control, +go_to_standby : agilent_82357a_go_to_standby, +request_system_control : agilent_82357a_request_system_control, +interface_clear : agilent_82357a_interface_clear, +remote_enable : agilent_82357a_remote_enable, +enable_eos : agilent_82357a_enable_eos, +disable_eos : agilent_82357a_disable_eos, +parallel_poll : agilent_82357a_parallel_poll, +parallel_poll_configure : agilent_82357a_parallel_poll_configure, +parallel_poll_response : agilent_82357a_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : agilent_82357a_line_status, +update_status : agilent_82357a_update_status, +primary_address : agilent_82357a_primary_address, +secondary_address : agilent_82357a_secondary_address, +serial_poll_response : agilent_82357a_serial_poll_response, +serial_poll_status : agilent_82357a_serial_poll_status, +t1_delay : agilent_82357a_t1_delay, +return_to_local : agilent_82357a_return_to_local, +no_7_bit_eos : 1, +skip_check_for_command_acceptors : 1 +}; + +// Table with the USB-devices: just now only testing IDs +static struct usb_device_id agilent_82357a_driver_device_table[] = { + {USB_DEVICE(USB_VENDOR_ID_AGILENT, USB_DEVICE_ID_AGILENT_82357A)}, + {USB_DEVICE(USB_VENDOR_ID_AGILENT, USB_DEVICE_ID_AGILENT_82357B)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, agilent_82357a_driver_device_table); + +static int agilent_82357a_driver_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + int i; + char *path; + static const int path_length = 1024; + struct usb_device *usb_dev; + + if (mutex_lock_interruptible(&agilent_82357a_hotplug_lock)) + return -ERESTARTSYS; + usb_dev = usb_get_dev(interface_to_usbdev(interface)); + for (i = 0; i < MAX_NUM_82357A_INTERFACES; ++i) { + if (!agilent_82357a_driver_interfaces[i]) { + agilent_82357a_driver_interfaces[i] = interface; + usb_set_intfdata(interface, NULL); + dev_dbg(&usb_dev->dev, "set bus interface %i to address 0x%p\n", + i, interface); + break; + } + } + if (i == MAX_NUM_82357A_INTERFACES) { + usb_put_dev(usb_dev); + mutex_unlock(&agilent_82357a_hotplug_lock); + dev_err(&usb_dev->dev, "%s: out of space in agilent_82357a_driver_interfaces[]\n", + __func__); + return -1; + } + path = kmalloc(path_length, GFP_KERNEL); + if (!path) { + usb_put_dev(usb_dev); + mutex_unlock(&agilent_82357a_hotplug_lock); + return -ENOMEM; + } + usb_make_path(usb_dev, path, path_length); + dev_info(&usb_dev->dev, "probe succeeded for path: %s\n", path); + kfree(path); + mutex_unlock(&agilent_82357a_hotplug_lock); + return 0; +} + +static void agilent_82357a_driver_disconnect(struct usb_interface *interface) +{ + int i; + struct usb_device *usb_dev = interface_to_usbdev(interface); + + mutex_lock(&agilent_82357a_hotplug_lock); + + for (i = 0; i < MAX_NUM_82357A_INTERFACES; ++i) { + if (agilent_82357a_driver_interfaces[i] == interface) { + gpib_board_t *board = usb_get_intfdata(interface); + + if (board) { + struct agilent_82357a_priv *a_priv = board->private_data; + + if (a_priv) { + mutex_lock(&a_priv->control_alloc_lock); + mutex_lock(&a_priv->bulk_alloc_lock); + mutex_lock(&a_priv->interrupt_alloc_lock); + agilent_82357a_cleanup_urbs(a_priv); + a_priv->bus_interface = NULL; + mutex_unlock(&a_priv->interrupt_alloc_lock); + mutex_unlock(&a_priv->bulk_alloc_lock); + mutex_unlock(&a_priv->control_alloc_lock); + } + } + dev_dbg(&usb_dev->dev, "nulled agilent_82357a_driver_interfaces[%i]\n", i); + agilent_82357a_driver_interfaces[i] = NULL; + break; + } + } + if (i == MAX_NUM_82357A_INTERFACES) + dev_err(&usb_dev->dev, "unable to find interface in agilent_82357a_driver_interfaces[]? bug?\n"); + usb_put_dev(usb_dev); + + mutex_unlock(&agilent_82357a_hotplug_lock); +} + +static int agilent_82357a_driver_suspend(struct usb_interface *interface, pm_message_t message) +{ + int i, retval; + struct usb_device *usb_dev = interface_to_usbdev(interface); + + mutex_lock(&agilent_82357a_hotplug_lock); + + for (i = 0; i < MAX_NUM_82357A_INTERFACES; ++i) { + if (agilent_82357a_driver_interfaces[i] == interface) { + gpib_board_t *board = usb_get_intfdata(interface); + + if (board) { + struct agilent_82357a_priv *a_priv = board->private_data; + + if (a_priv) { + agilent_82357a_abort(a_priv, 0); + agilent_82357a_abort(a_priv, 0); + retval = agilent_82357a_go_idle(board); + if (retval) { + dev_err(&usb_dev->dev, "%s: failed to go idle, retval=%i\n", + __func__, retval); + mutex_unlock(&agilent_82357a_hotplug_lock); + return retval; + } + mutex_lock(&a_priv->interrupt_alloc_lock); + agilent_82357a_cleanup_urbs(a_priv); + mutex_unlock(&a_priv->interrupt_alloc_lock); + dev_info(&usb_dev->dev, + "bus %d dev num %d gpib minor %d, agilent usb interface %i suspended\n", + usb_dev->bus->busnum, usb_dev->devnum, + board->minor, i); + } + } + break; + } + } + + mutex_unlock(&agilent_82357a_hotplug_lock); + + return 0; +} + +static int agilent_82357a_driver_resume(struct usb_interface *interface) +{ + struct usb_device *usb_dev = interface_to_usbdev(interface); + gpib_board_t *board; + int i, retval; + + mutex_lock(&agilent_82357a_hotplug_lock); + + for (i = 0; i < MAX_NUM_82357A_INTERFACES; ++i) { + if (agilent_82357a_driver_interfaces[i] == interface) { + board = usb_get_intfdata(interface); + if (board) + break; + } + } + if (i == MAX_NUM_82357A_INTERFACES) + goto resume_exit; + + struct agilent_82357a_priv *a_priv = board->private_data; + + if (a_priv) { + if (a_priv->interrupt_urb) { + mutex_lock(&a_priv->interrupt_alloc_lock); + retval = usb_submit_urb(a_priv->interrupt_urb, GFP_KERNEL); + if (retval) { + dev_err(&usb_dev->dev, "%s: failed to resubmit interrupt urb, retval=%i\n", + __func__, retval); + mutex_unlock(&a_priv->interrupt_alloc_lock); + mutex_unlock(&agilent_82357a_hotplug_lock); + return retval; + } + mutex_unlock(&a_priv->interrupt_alloc_lock); + } + retval = agilent_82357a_init(board); + if (retval < 0) { + mutex_unlock(&agilent_82357a_hotplug_lock); + return retval; + } + // set/unset system controller + agilent_82357a_request_system_control(board, board->master); + // toggle ifc if master + if (board->master) { + agilent_82357a_interface_clear(board, 1); + usleep_range(200, 250); + agilent_82357a_interface_clear(board, 0); + } + // assert/unassert REN + agilent_82357a_remote_enable(board, a_priv->ren_state); + + dev_info(&usb_dev->dev, + "bus %d dev num %d gpib minor %d, agilent usb interface %i resumed\n", + usb_dev->bus->busnum, usb_dev->devnum, board->minor, i); + } + +resume_exit: + mutex_unlock(&agilent_82357a_hotplug_lock); + + return 0; +} + +static struct usb_driver agilent_82357a_bus_driver = { + .name = "agilent_82357a_gpib", + .probe = agilent_82357a_driver_probe, + .disconnect = agilent_82357a_driver_disconnect, + .suspend = agilent_82357a_driver_suspend, + .resume = agilent_82357a_driver_resume, + .id_table = agilent_82357a_driver_device_table, +}; + +static int __init agilent_82357a_init_module(void) +{ + int i; + + pr_info("agilent_82357a_gpib driver loading"); + for (i = 0; i < MAX_NUM_82357A_INTERFACES; ++i) + agilent_82357a_driver_interfaces[i] = NULL; + usb_register(&agilent_82357a_bus_driver); + gpib_register_driver(&agilent_82357a_gpib_interface, THIS_MODULE); + + return 0; +} + +static void __exit agilent_82357a_exit_module(void) +{ + pr_info("agilent_82357a_gpib driver unloading"); + gpib_unregister_driver(&agilent_82357a_gpib_interface); + usb_deregister(&agilent_82357a_bus_driver); +} + +module_init(agilent_82357a_init_module); +module_exit(agilent_82357a_exit_module); diff --git a/drivers/staging/gpib/agilent_82357a/agilent_82357a.h b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h new file mode 100644 index 00000000000000..cdbc3ec5d8bd07 --- /dev/null +++ b/drivers/staging/gpib/agilent_82357a/agilent_82357a.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2004 by Frank Mori Hess * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "gpibP.h" +#include "tms9914.h" + +enum usb_vendor_ids { + USB_VENDOR_ID_AGILENT = 0x0957 +}; + +enum usb_device_ids { + USB_DEVICE_ID_AGILENT_82357A = 0x0107, + USB_DEVICE_ID_AGILENT_82357A_PREINIT = 0x0007, // device id before firmware is loaded + USB_DEVICE_ID_AGILENT_82357B = 0x0718, // device id before firmware is loaded + USB_DEVICE_ID_AGILENT_82357B_PREINIT = 0x0518, // device id before firmware is loaded +}; + +enum endpoint_addresses { + AGILENT_82357_CONTROL_ENDPOINT = 0x0, + AGILENT_82357_BULK_IN_ENDPOINT = 0x2, + AGILENT_82357A_BULK_OUT_ENDPOINT = 0x4, + AGILENT_82357A_INTERRUPT_IN_ENDPOINT = 0x6, + AGILENT_82357B_BULK_OUT_ENDPOINT = 0x6, + AGILENT_82357B_INTERRUPT_IN_ENDPOINT = 0x8, +}; + +enum bulk_commands { + DATA_PIPE_CMD_WRITE = 0x1, + DATA_PIPE_CMD_READ = 0x3, + DATA_PIPE_CMD_WR_REGS = 0x4, + DATA_PIPE_CMD_RD_REGS = 0x5 +}; + +enum agilent_82357a_read_flags { + ARF_END_ON_EOI = 0x1, + ARF_NO_ADDRESS = 0x2, + ARF_END_ON_EOS_CHAR = 0x4, + ARF_SPOLL = 0x8 +}; + +enum agilent_82357a_trailing_read_flags { + ATRF_EOI = 0x1, + ATRF_ATN = 0x2, + ATRF_IFC = 0x4, + ATRF_EOS = 0x8, + ATRF_ABORT = 0x10, + ATRF_COUNT = 0x20, + ATRF_DEAD_BUS = 0x40, + ATRF_UNADDRESSED = 0x80 +}; + +enum agilent_82357a_write_flags { + AWF_SEND_EOI = 0x1, + AWF_NO_FAST_TALKER_FIRST_BYTE = 0x2, + AWF_NO_FAST_TALKER = 0x4, + AWF_NO_ADDRESS = 0x8, + AWF_ATN = 0x10, + AWF_SEPARATE_HEADER = 0x80 +}; + +enum agilent_82357a_interrupt_flag_bit_numbers { + AIF_SRQ_BN = 0, + AIF_WRITE_COMPLETE_BN = 1, + AIF_READ_COMPLETE_BN = 2, +}; + +enum agilent_82357_error_codes { + UGP_SUCCESS = 0, + UGP_ERR_INVALID_CMD = 1, + UGP_ERR_INVALID_PARAM = 2, + UGP_ERR_INVALID_REG = 3, + UGP_ERR_GPIB_READ = 4, + UGP_ERR_GPIB_WRITE = 5, + UGP_ERR_FLUSHING = 6, + UGP_ERR_FLUSHING_ALREADY = 7, + UGP_ERR_UNSUPPORTED = 8, + UGP_ERR_OTHER = 9 +}; + +enum agilent_82357_control_values { + XFER_ABORT = 0xa0, + XFER_STATUS = 0xb0, +}; + +enum xfer_status_bits { + XS_COMPLETED = 0x1, + XS_READ = 0x2, +}; + +enum xfer_status_completion_bits { + XSC_EOI = 0x1, + XSC_ATN = 0x2, + XSC_IFC = 0x4, + XSC_EOS = 0x8, + XSC_ABORT = 0x10, + XSC_COUNT = 0x20, + XSC_DEAD_BUS = 0x40, + XSC_BUS_NOT_ADDRESSED = 0x80 +}; + +enum xfer_abort_type { + XA_FLUSH = 0x1 +}; + +#define STATUS_DATA_LEN 8 +#define INTERRUPT_BUF_LEN 8 + +struct agilent_82357a_urb_ctx { + struct semaphore complete; + unsigned timed_out : 1; +}; + +// struct which defines local data for each 82357 device +struct agilent_82357a_priv { + struct usb_interface *bus_interface; + unsigned short eos_char; + unsigned short eos_mode; + unsigned short hw_control_bits; + unsigned long interrupt_flags; + struct urb *bulk_urb; + struct urb *interrupt_urb; + u8 *interrupt_buffer; + struct mutex bulk_transfer_lock; // bulk transfer lock + struct mutex bulk_alloc_lock; // bulk transfer allocation lock + struct mutex interrupt_alloc_lock; // interrupt allocation lock + struct mutex control_alloc_lock; // control message allocation lock + struct timer_list bulk_timer; + struct agilent_82357a_urb_ctx context; + unsigned int bulk_out_endpoint; + unsigned int interrupt_in_endpoint; + unsigned is_cic : 1; + unsigned ren_state : 1; +}; + +struct agilent_82357a_register_pairlet { + short address; + unsigned short value; +}; + +enum firmware_registers { + HW_CONTROL = 0xa, + LED_CONTROL = 0xb, + RESET_TO_POWERUP = 0xc, + PROTOCOL_CONTROL = 0xd, + FAST_TALKER_T1 = 0xe +}; + +enum hardware_control_bits { + NOT_TI_RESET = 0x1, + SYSTEM_CONTROLLER = 0x2, + NOT_PARALLEL_POLL = 0x4, + OSCILLATOR_5V_ON = 0x8, + OUTPUT_5V_ON = 0x20, + CPLD_3V_ON = 0x80, +}; + +enum led_control_bits { + FIRMWARE_LED_CONTROL = 0x1, + FAIL_LED_ON = 0x20, + READY_LED_ON = 0x40, + ACCESS_LED_ON = 0x80 +}; + +enum reset_to_powerup_bits { + RESET_SPACEBALL = 0x1, // wait 2 millisec after sending +}; + +enum protocol_control_bits { + WRITE_COMPLETE_INTERRUPT_EN = 0x1, +}; + +static const int agilent_82357a_control_request = 0x4; + diff --git a/drivers/staging/gpib/cb7210/Makefile b/drivers/staging/gpib/cb7210/Makefile new file mode 100644 index 00000000000000..22e0214fc17dca --- /dev/null +++ b/drivers/staging/gpib/cb7210/Makefile @@ -0,0 +1,4 @@ +ccflags-$(CONFIG_GPIB_PCMCIA) := -DGPIB_PCMCIA +obj-m += cb7210.o + + diff --git a/drivers/staging/gpib/cb7210/cb7210.c b/drivers/staging/gpib/cb7210/cb7210.c new file mode 100644 index 00000000000000..63df7f3eb3f3e7 --- /dev/null +++ b/drivers/staging/gpib/cb7210/cb7210.c @@ -0,0 +1,1556 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * Measurement Computing boards using cb7210.2 and cbi488.2 chips + * copyright : (C) 2001, 2002 by Frank Mori Hess + ***************************************************************************/ + +#include "cb7210.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gpib_pci_ids.h" +#include "quancom_pci.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver Measurement Computing boards using cb7210.2 and cbi488.2"); + +static inline int have_fifo_word(const struct cb7210_priv *cb_priv) +{ + if (((cb7210_read_byte(cb_priv, HS_STATUS)) & + (HS_RX_MSB_NOT_EMPTY | HS_RX_LSB_NOT_EMPTY)) == + (HS_RX_MSB_NOT_EMPTY | HS_RX_LSB_NOT_EMPTY)) + return 1; + else + return 0; +} + +static inline void input_fifo_enable(gpib_board_t *board, int enable) +{ + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + + if (enable) { + cb_priv->in_fifo_half_full = 0; + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + + cb7210_write_byte(cb_priv, HS_RX_ENABLE | HS_TX_ENABLE | HS_CLR_SRQ_INT | + HS_CLR_EOI_EMPTY_INT | HS_CLR_HF_INT | cb_priv->hs_mode_bits, + HS_MODE); + + cb_priv->hs_mode_bits &= ~HS_ENABLE_MASK; + cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, HS_MODE); + + cb7210_write_byte(cb_priv, irq_bits(cb_priv->irq), HS_INT_LEVEL); + + cb_priv->hs_mode_bits |= HS_RX_ENABLE; + cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, HS_MODE); + } else { + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + + cb_priv->hs_mode_bits &= ~HS_ENABLE_MASK; + cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, nec7210_iobase(cb_priv) + + HS_MODE); + + clear_bit(READ_READY_BN, &nec_priv->state); + } + + spin_unlock_irqrestore(&board->spinlock, flags); +} + +static int fifo_read(gpib_board_t *board, struct cb7210_priv *cb_priv, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + ssize_t retval = 0; + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + int hs_status; + u16 word; + unsigned long flags; + + *bytes_read = 0; + if (cb_priv->fifo_iobase == 0) { + pr_err("cb7210: fifo iobase is zero!\n"); + return -EIO; + } + *end = 0; + if (length <= cb7210_fifo_size) { + pr_err("cb7210: bug! %s with length < fifo size\n", __func__); + return -EINVAL; + } + + input_fifo_enable(board, 1); + + while (*bytes_read + cb7210_fifo_size < length) { + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, HR_DMAI); + + if (wait_event_interruptible(board->wait, + (cb_priv->in_fifo_half_full && + have_fifo_word(cb_priv)) || + test_bit(RECEIVED_END_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_warn("cb7210: fifo half full wait interrupted\n"); + retval = -ERESTARTSYS; + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + break; + } + + spin_lock_irqsave(&board->spinlock, flags); + + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + + while (have_fifo_word(cb_priv)) { + word = inw(cb_priv->fifo_iobase + DIR); + buffer[(*bytes_read)++] = word & 0xff; + buffer[(*bytes_read)++] = (word >> 8) & 0xff; + } + + cb_priv->in_fifo_half_full = 0; + + hs_status = cb7210_read_byte(cb_priv, HS_STATUS); + + spin_unlock_irqrestore(&board->spinlock, flags); + + if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state)) { + *end = 1; + break; + } + if (hs_status & HS_FIFO_FULL) + break; + if (test_bit(TIMO_NUM, &board->status)) { + retval = -ETIMEDOUT; + break; + } + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) { + retval = -EINTR; + break; + } + } + hs_status = cb7210_read_byte(cb_priv, HS_STATUS); + if (hs_status & HS_RX_LSB_NOT_EMPTY) { + word = inw(cb_priv->fifo_iobase + DIR); + buffer[(*bytes_read)++] = word & 0xff; + } + + input_fifo_enable(board, 0); + + if (wait_event_interruptible(board->wait, + test_bit(READ_READY_BN, &nec_priv->state) || + test_bit(RECEIVED_END_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_warn("cb7210: fifo half full wait interrupted\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + if (test_bit(READ_READY_BN, &nec_priv->state)) { + nec7210_set_handshake_mode(board, nec_priv, HR_HLDA); + buffer[(*bytes_read)++] = nec7210_read_data_in(board, nec_priv, end); + } + + return retval; +} + +int cb7210_accel_read(gpib_board_t *board, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + ssize_t retval; + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + size_t num_bytes; + + *bytes_read = 0; + // deal with limitations of fifo + if (length < cb7210_fifo_size + 3 || (nec_priv->auxa_bits & HR_REOS)) + return cb7210_read(board, buffer, length, end, bytes_read); + *end = 0; + + nec7210_release_rfd_holdoff(board, nec_priv); + + if (wait_event_interruptible(board->wait, + test_bit(READ_READY_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_warn("cb7210: read ready wait interrupted\n"); + return -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + return -ETIMEDOUT; + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) + return -EINTR; + + nec7210_set_handshake_mode(board, nec_priv, HR_HLDE); + buffer[(*bytes_read)++] = nec7210_read_data_in(board, nec_priv, end); + if (*end) + return 0; + + nec7210_release_rfd_holdoff(board, nec_priv); + + retval = fifo_read(board, cb_priv, &buffer[*bytes_read], length - *bytes_read - 1, + end, &num_bytes); + *bytes_read += num_bytes; + if (retval < 0) + return retval; + if (*end) + return 0; + + retval = cb7210_read(board, &buffer[*bytes_read], 1, end, &num_bytes); + *bytes_read += num_bytes; + if (retval < 0) + return retval; + + return 0; +} + +static int output_fifo_empty(const struct cb7210_priv *cb_priv) +{ + if ((cb7210_read_byte(cb_priv, HS_STATUS) & (HS_TX_MSB_NOT_EMPTY | HS_TX_LSB_NOT_EMPTY)) + == 0) + return 1; + else + return 0; +} + +static inline void output_fifo_enable(gpib_board_t *board, int enable) +{ + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + + if (enable) { + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, HR_DMAO); + + cb7210_write_byte(cb_priv, HS_RX_ENABLE | HS_TX_ENABLE | HS_CLR_SRQ_INT | + HS_CLR_EOI_EMPTY_INT | HS_CLR_HF_INT | cb_priv->hs_mode_bits, + HS_MODE); + + cb_priv->hs_mode_bits &= ~HS_ENABLE_MASK; + cb_priv->hs_mode_bits |= HS_TX_ENABLE; + cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, HS_MODE); + + cb7210_write_byte(cb_priv, irq_bits(cb_priv->irq), HS_INT_LEVEL); + + clear_bit(WRITE_READY_BN, &nec_priv->state); + + } else { + cb_priv->hs_mode_bits &= ~HS_ENABLE_MASK; + cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, HS_MODE); + + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0); + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE, HR_DOIE); + } + + spin_unlock_irqrestore(&board->spinlock, flags); +} + +static int fifo_write(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + size_t count = 0; + ssize_t retval = 0; + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + unsigned int num_bytes, i; + unsigned long flags; + + *bytes_written = 0; + if (cb_priv->fifo_iobase == 0) { + pr_err("cb7210: fifo iobase is zero!\n"); + return -EINVAL; + } + if (length == 0) + return 0; + + clear_bit(DEV_CLEAR_BN, &nec_priv->state); + clear_bit(BUS_ERROR_BN, &nec_priv->state); + + output_fifo_enable(board, 1); + + while (count < length) { + // wait until byte is ready to be sent + if (wait_event_interruptible(board->wait, + cb_priv->out_fifo_half_empty || + output_fifo_empty(cb_priv) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(BUS_ERROR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_warn("cb7210: fifo wait interrupted\n"); + retval = -ERESTARTSYS; + break; + } + if (test_bit(TIMO_NUM, &board->status) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(BUS_ERROR_BN, &nec_priv->state)) + break; + + if (output_fifo_empty(cb_priv)) + num_bytes = cb7210_fifo_size - cb7210_fifo_width; + else + num_bytes = cb7210_fifo_size / 2; + if (num_bytes + count > length) + num_bytes = length - count; + if (num_bytes % cb7210_fifo_width) { + pr_err("cb7210: bug! %s with odd number of bytes\n", __func__); + retval = -EINVAL; + break; + } + + spin_lock_irqsave(&board->spinlock, flags); + for (i = 0; i < num_bytes / cb7210_fifo_width; i++) { + u16 word; + + word = buffer[count++] & 0xff; + word |= (buffer[count++] << 8) & 0xff00; + outw(word, cb_priv->fifo_iobase + CDOR); + } + cb_priv->out_fifo_half_empty = 0; + cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits | + HS_CLR_EOI_EMPTY_INT | HS_CLR_HF_INT, HS_MODE); + cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, HS_MODE); + spin_unlock_irqrestore(&board->spinlock, flags); + } + // wait last byte has been sent + if (wait_event_interruptible(board->wait, + output_fifo_empty(cb_priv) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(BUS_ERROR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_err("cb7210: wait for last byte interrupted\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_bit(BUS_ERROR_BN, &nec_priv->state)) + retval = -EIO; + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + + output_fifo_enable(board, 0); + + *bytes_written = count; + return retval; +} + +int cb7210_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) +{ + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + unsigned long fast_chunk_size, leftover; + int retval; + size_t num_bytes; + + *bytes_written = 0; + if (length > cb7210_fifo_width) + fast_chunk_size = length - 1; + else + fast_chunk_size = 0; + fast_chunk_size -= fast_chunk_size % cb7210_fifo_width; + leftover = length - fast_chunk_size; + + retval = fifo_write(board, buffer, fast_chunk_size, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + return retval; + + retval = nec7210_write(board, nec_priv, buffer + fast_chunk_size, leftover, + send_eoi, &num_bytes); + *bytes_written += num_bytes; + return retval; +} + +int cb7210_line_status(const gpib_board_t *board) +{ + int status = ValidALL; + int bsr_bits; + struct cb7210_priv *cb_priv; + struct nec7210_priv *nec_priv; + + cb_priv = board->private_data; + nec_priv = &cb_priv->nec7210_priv; + + bsr_bits = cb7210_paged_read_byte(cb_priv, BUS_STATUS, BUS_STATUS_PAGE); + + if ((bsr_bits & BSR_REN_BIT) == 0) + status |= BusREN; + if ((bsr_bits & BSR_IFC_BIT) == 0) + status |= BusIFC; + if ((bsr_bits & BSR_SRQ_BIT) == 0) + status |= BusSRQ; + if ((bsr_bits & BSR_EOI_BIT) == 0) + status |= BusEOI; + if ((bsr_bits & BSR_NRFD_BIT) == 0) + status |= BusNRFD; + if ((bsr_bits & BSR_NDAC_BIT) == 0) + status |= BusNDAC; + if ((bsr_bits & BSR_DAV_BIT) == 0) + status |= BusDAV; + if ((bsr_bits & BSR_ATN_BIT) == 0) + status |= BusATN; + + return status; +} + +unsigned int cb7210_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + unsigned int retval; + + retval = nec7210_t1_delay(board, nec_priv, nano_sec); + + if (nano_sec <= 350) { + write_byte(nec_priv, AUX_HI_SPEED, AUXMR); + retval = 350; + } else { + write_byte(nec_priv, AUX_LO_SPEED, AUXMR); + } + return retval; +} + +irqreturn_t cb7210_locked_internal_interrupt(gpib_board_t *board); + +/* + * GPIB interrupt service routines + */ + +irqreturn_t cb_pci_interrupt(int irq, void *arg) +{ + int bits; + gpib_board_t *board = arg; + struct cb7210_priv *priv = board->private_data; + + // first task check if this is really our interrupt in a shared irq environment + switch (priv->pci_chip) { + case PCI_CHIP_AMCC_S5933: + if ((inl(priv->amcc_iobase + INTCSR_REG) & + (INBOX_INTR_CS_BIT | INTR_ASSERTED_BIT)) == 0) + return IRQ_NONE; + + // read incoming mailbox to clear mailbox full flag + inl(priv->amcc_iobase + INCOMING_MAILBOX_REG(3)); + // clear amccs5933 interrupt + bits = INBOX_FULL_INTR_BIT | INBOX_BYTE_BITS(3) | + INBOX_SELECT_BITS(3) | INBOX_INTR_CS_BIT; + outl(bits, priv->amcc_iobase + INTCSR_REG); + break; + case PCI_CHIP_QUANCOM: + if ((inb(nec7210_iobase(priv) + QUANCOM_IRQ_CONTROL_STATUS_REG) & + QUANCOM_IRQ_ASSERTED_BIT)) + outb(QUANCOM_IRQ_ENABLE_BIT, nec7210_iobase(priv) + + QUANCOM_IRQ_CONTROL_STATUS_REG); + break; + default: + break; + } + return cb7210_locked_internal_interrupt(arg); +} + +irqreturn_t cb7210_internal_interrupt(gpib_board_t *board) +{ + int hs_status, status1, status2; + struct cb7210_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + int clear_bits; + + if ((priv->hs_mode_bits & HS_ENABLE_MASK)) { + status1 = 0; + hs_status = cb7210_read_byte(priv, HS_STATUS); + } else { + hs_status = 0; + status1 = read_byte(nec_priv, ISR1); + } + status2 = read_byte(nec_priv, ISR2); + nec7210_interrupt_have_status(board, nec_priv, status1, status2); + + dev_dbg(board->gpib_dev, "cb7210: status 0x%x, mode 0x%x\n", hs_status, priv->hs_mode_bits); + + clear_bits = 0; + + if (hs_status & HS_HALF_FULL) { + if (priv->hs_mode_bits & HS_TX_ENABLE) + priv->out_fifo_half_empty = 1; + else if (priv->hs_mode_bits & HS_RX_ENABLE) + priv->in_fifo_half_full = 1; + clear_bits |= HS_CLR_HF_INT; + } + + if (hs_status & HS_SRQ_INT) { + set_bit(SRQI_NUM, &board->status); + clear_bits |= HS_CLR_SRQ_INT; + } + + if ((hs_status & HS_EOI_INT)) { + clear_bits |= HS_CLR_EOI_EMPTY_INT; + set_bit(RECEIVED_END_BN, &nec_priv->state); + if ((nec_priv->auxa_bits & HR_HANDSHAKE_MASK) == HR_HLDE) + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + } + + if ((priv->hs_mode_bits & HS_TX_ENABLE) && + (hs_status & (HS_TX_MSB_NOT_EMPTY | HS_TX_LSB_NOT_EMPTY)) == 0) + clear_bits |= HS_CLR_EOI_EMPTY_INT; + + if (clear_bits) { + cb7210_write_byte(priv, priv->hs_mode_bits | clear_bits, HS_MODE); + cb7210_write_byte(priv, priv->hs_mode_bits, HS_MODE); + wake_up_interruptible(&board->wait); + } + + return IRQ_HANDLED; +} + +irqreturn_t cb7210_locked_internal_interrupt(gpib_board_t *board) +{ + unsigned long flags; + irqreturn_t retval; + + spin_lock_irqsave(&board->spinlock, flags); + retval = cb7210_internal_interrupt(board); + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +irqreturn_t cb7210_interrupt(int irq, void *arg) +{ + return cb7210_internal_interrupt(arg); +} + +static int cb_pci_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int cb_isa_attach(gpib_board_t *board, const gpib_board_config_t *config); + +static void cb_pci_detach(gpib_board_t *board); +static void cb_isa_detach(gpib_board_t *board); + +// wrappers for interface functions +int cb7210_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); +} + +int cb7210_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); +} + +int cb7210_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); +} + +int cb7210_take_control(gpib_board_t *board, int synchronous) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_take_control(board, &priv->nec7210_priv, synchronous); +} + +int cb7210_go_to_standby(gpib_board_t *board) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_go_to_standby(board, &priv->nec7210_priv); +} + +void cb7210_request_system_control(gpib_board_t *board, int request_control) +{ + struct cb7210_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + + if (request_control) + priv->hs_mode_bits |= HS_SYS_CONTROL; + else + priv->hs_mode_bits &= ~HS_SYS_CONTROL; + + cb7210_write_byte(priv, priv->hs_mode_bits, HS_MODE); + nec7210_request_system_control(board, nec_priv, request_control); +} + +void cb7210_interface_clear(gpib_board_t *board, int assert) +{ + struct cb7210_priv *priv = board->private_data; + + nec7210_interface_clear(board, &priv->nec7210_priv, assert); +} + +void cb7210_remote_enable(gpib_board_t *board, int enable) +{ + struct cb7210_priv *priv = board->private_data; + + nec7210_remote_enable(board, &priv->nec7210_priv, enable); +} + +int cb7210_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); +} + +void cb7210_disable_eos(gpib_board_t *board) +{ + struct cb7210_priv *priv = board->private_data; + + nec7210_disable_eos(board, &priv->nec7210_priv); +} + +unsigned int cb7210_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_update_status(board, &priv->nec7210_priv, clear_mask); +} + +int cb7210_primary_address(gpib_board_t *board, unsigned int address) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_primary_address(board, &priv->nec7210_priv, address); +} + +int cb7210_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); +} + +int cb7210_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_parallel_poll(board, &priv->nec7210_priv, result); +} + +void cb7210_parallel_poll_configure(gpib_board_t *board, uint8_t configuration) +{ + struct cb7210_priv *priv = board->private_data; + + nec7210_parallel_poll_configure(board, &priv->nec7210_priv, configuration); +} + +void cb7210_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct cb7210_priv *priv = board->private_data; + + nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); +} + +void cb7210_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + struct cb7210_priv *priv = board->private_data; + + nec7210_serial_poll_response(board, &priv->nec7210_priv, status); +} + +uint8_t cb7210_serial_poll_status(gpib_board_t *board) +{ + struct cb7210_priv *priv = board->private_data; + + return nec7210_serial_poll_status(board, &priv->nec7210_priv); +} + +void cb7210_return_to_local(gpib_board_t *board) +{ + struct cb7210_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + + write_byte(nec_priv, AUX_RTL2, AUXMR); + udelay(1); + write_byte(nec_priv, AUX_RTL, AUXMR); +} + +gpib_interface_t cb_pci_unaccel_interface = { +name: "cbi_pci_unaccel", +attach : cb_pci_attach, +detach : cb_pci_detach, +read : cb7210_read, +write : cb7210_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +gpib_interface_t cb_pci_accel_interface = { +name: "cbi_pci_accel", +attach : cb_pci_attach, +detach : cb_pci_detach, +read : cb7210_accel_read, +write : cb7210_accel_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +gpib_interface_t cb_pci_interface = { +name: "cbi_pci", +attach : cb_pci_attach, +detach : cb_pci_detach, +read : cb7210_accel_read, +write : cb7210_accel_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +gpib_interface_t cb_isa_unaccel_interface = { +name: "cbi_isa_unaccel", +attach : cb_isa_attach, +detach : cb_isa_detach, +read : cb7210_read, +write : cb7210_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +gpib_interface_t cb_isa_interface = { +name: "cbi_isa", +attach : cb_isa_attach, +detach : cb_isa_detach, +read : cb7210_accel_read, +write : cb7210_accel_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +gpib_interface_t cb_isa_accel_interface = { +name: "cbi_isa_accel", +attach : cb_isa_attach, +detach : cb_isa_detach, +read : cb7210_accel_read, +write : cb7210_accel_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +static int cb7210_allocate_private(gpib_board_t *board) +{ + struct cb7210_priv *priv; + + board->private_data = kmalloc(sizeof(struct cb7210_priv), GFP_KERNEL); + if (!board->private_data) + return -1; + priv = board->private_data; + memset(priv, 0, sizeof(struct cb7210_priv)); + init_nec7210_private(&priv->nec7210_priv); + return 0; +} + +void cb7210_generic_detach(gpib_board_t *board) +{ + kfree(board->private_data); + board->private_data = NULL; +} + +// generic part of attach functions shared by all cb7210 boards +int cb7210_generic_attach(gpib_board_t *board) +{ + struct cb7210_priv *cb_priv; + struct nec7210_priv *nec_priv; + + board->status = 0; + + if (cb7210_allocate_private(board)) + return -ENOMEM; + cb_priv = board->private_data; + nec_priv = &cb_priv->nec7210_priv; + nec_priv->read_byte = nec7210_locking_ioport_read_byte; + nec_priv->write_byte = nec7210_locking_ioport_write_byte; + nec_priv->offset = cb7210_reg_offset; + nec_priv->type = CB7210; + return 0; +} + +int cb7210_init(struct cb7210_priv *cb_priv, gpib_board_t *board) +{ + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + + cb7210_write_byte(cb_priv, HS_RESET7210, HS_INT_LEVEL); + cb7210_write_byte(cb_priv, irq_bits(cb_priv->irq), HS_INT_LEVEL); + + nec7210_board_reset(nec_priv, board); + cb7210_write_byte(cb_priv, HS_TX_ENABLE | HS_RX_ENABLE | HS_CLR_SRQ_INT | + HS_CLR_EOI_EMPTY_INT | HS_CLR_HF_INT, HS_MODE); + + cb_priv->hs_mode_bits = HS_HF_INT_EN; + cb7210_write_byte(cb_priv, cb_priv->hs_mode_bits, HS_MODE); + + write_byte(nec_priv, AUX_LO_SPEED, AUXMR); + /* set clock register for maximum (20 MHz) driving frequency + * ICR should be set to clock in megahertz (1-15) and to zero + * for clocks faster than 15 MHz (max 20MHz) + */ + write_byte(nec_priv, ICR | 0, AUXMR); + + if (cb_priv->pci_chip == PCI_CHIP_QUANCOM) { + /* change interrupt polarity */ + nec_priv->auxb_bits |= HR_INV; + write_byte(nec_priv, nec_priv->auxb_bits, AUXMR); + } + nec7210_board_online(nec_priv, board); + + /* poll so we can detect assertion of ATN */ + if (gpib_request_pseudo_irq(board, cb_pci_interrupt)) { + pr_err("pc2_gpib: failed to allocate pseudo_irq\n"); + return -1; + } + return 0; +} + +int cb_pci_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct cb7210_priv *cb_priv; + struct nec7210_priv *nec_priv; + int isr_flags = 0; + int bits; + int retval; + + retval = cb7210_generic_attach(board); + if (retval) + return retval; + + cb_priv = board->private_data; + nec_priv = &cb_priv->nec7210_priv; + + cb_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_CBOARDS, + PCI_DEVICE_ID_CBOARDS_PCI_GPIB, NULL); + if (cb_priv->pci_device) + cb_priv->pci_chip = PCI_CHIP_AMCC_S5933; + if (!cb_priv->pci_device) { + cb_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_CBOARDS, + PCI_DEVICE_ID_CBOARDS_CPCI_GPIB, NULL); + if (cb_priv->pci_device) + cb_priv->pci_chip = PCI_CHIP_AMCC_S5933; + } + if (!cb_priv->pci_device) { + cb_priv->pci_device = gpib_pci_get_device(config, PCI_VENDOR_ID_QUANCOM, + PCI_DEVICE_ID_QUANCOM_GPIB, NULL); + if (cb_priv->pci_device) { + cb_priv->pci_chip = PCI_CHIP_QUANCOM; + nec_priv->offset = 4; + } + } + if (!cb_priv->pci_device) { + pr_warn("cb7210: no supported boards found.\n"); + return -1; + } + + if (pci_enable_device(cb_priv->pci_device)) { + pr_err("cb7210: error enabling pci device\n"); + return -1; + } + + if (pci_request_regions(cb_priv->pci_device, "cb7210")) + return -1; + switch (cb_priv->pci_chip) { + case PCI_CHIP_AMCC_S5933: + cb_priv->amcc_iobase = pci_resource_start(cb_priv->pci_device, 0); + nec_priv->iobase = (void *)(pci_resource_start(cb_priv->pci_device, 1)); + cb_priv->fifo_iobase = pci_resource_start(cb_priv->pci_device, 2); + break; + case PCI_CHIP_QUANCOM: + nec_priv->iobase = (void *)(pci_resource_start(cb_priv->pci_device, 0)); + cb_priv->fifo_iobase = (unsigned long)nec_priv->iobase; + break; + default: + pr_err("cb7210: bug! unhandled pci_chip=%i\n", cb_priv->pci_chip); + return -EIO; + } + isr_flags |= IRQF_SHARED; + if (request_irq(cb_priv->pci_device->irq, cb_pci_interrupt, isr_flags, "cb7210", board)) { + pr_err("cb7210: can't request IRQ %d\n", cb_priv->pci_device->irq); + return -1; + } + cb_priv->irq = cb_priv->pci_device->irq; + + switch (cb_priv->pci_chip) { + case PCI_CHIP_AMCC_S5933: + // make sure mailbox flags are clear + inl(cb_priv->amcc_iobase + INCOMING_MAILBOX_REG(3)); + // enable interrupts on amccs5933 chip + bits = INBOX_FULL_INTR_BIT | INBOX_BYTE_BITS(3) | INBOX_SELECT_BITS(3) | + INBOX_INTR_CS_BIT; + outl(bits, cb_priv->amcc_iobase + INTCSR_REG); + break; + default: + break; + } + return cb7210_init(cb_priv, board); +} + +void cb_pci_detach(gpib_board_t *board) +{ + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (cb_priv) { + gpib_free_pseudo_irq(board); + nec_priv = &cb_priv->nec7210_priv; + if (cb_priv->irq) { + // disable amcc interrupts + outl(0, cb_priv->amcc_iobase + INTCSR_REG); + free_irq(cb_priv->irq, board); + } + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + pci_release_regions(cb_priv->pci_device); + } + if (cb_priv->pci_device) + pci_dev_put(cb_priv->pci_device); + } + cb7210_generic_detach(board); +} + +int cb_isa_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + int isr_flags = 0; + struct cb7210_priv *cb_priv; + struct nec7210_priv *nec_priv; + unsigned int bits; + int retval; + + retval = cb7210_generic_attach(board); + if (retval) + return retval; + cb_priv = board->private_data; + nec_priv = &cb_priv->nec7210_priv; + if (request_region((unsigned long)config->ibbase, cb7210_iosize, "cb7210") == 0) { + pr_err("gpib: ioports starting at 0x%p are already in use\n", config->ibbase); + return -EIO; + } + nec_priv->iobase = config->ibbase; + cb_priv->fifo_iobase = nec7210_iobase(cb_priv); + + bits = irq_bits(config->ibirq); + if (bits == 0) + pr_err("board incapable of using irq %i, try 2-5, 7, 10, or 11\n", config->ibirq); + + // install interrupt handler + if (request_irq(config->ibirq, cb7210_interrupt, isr_flags, "cb7210", board)) { + pr_err("gpib: can't request IRQ %d\n", config->ibirq); + return -EBUSY; + } + cb_priv->irq = config->ibirq; + + return cb7210_init(cb_priv, board); +} + +void cb_isa_detach(gpib_board_t *board) +{ + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (cb_priv) { + gpib_free_pseudo_irq(board); + nec_priv = &cb_priv->nec7210_priv; + if (cb_priv->irq) + free_irq(cb_priv->irq, board); + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + release_region(nec7210_iobase(cb_priv), cb7210_iosize); + } + } + cb7210_generic_detach(board); +} + +static int cb7210_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return 0; +} + +static const struct pci_device_id cb7210_pci_table[] = { + {PCI_VENDOR_ID_CBOARDS, PCI_DEVICE_ID_CBOARDS_PCI_GPIB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + {PCI_VENDOR_ID_CBOARDS, PCI_DEVICE_ID_CBOARDS_CPCI_GPIB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + {PCI_VENDOR_ID_QUANCOM, PCI_DEVICE_ID_QUANCOM_GPIB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cb7210_pci_table); + +static struct pci_driver cb7210_pci_driver = { + .name = "cb7210", + .id_table = cb7210_pci_table, + .probe = &cb7210_pci_probe +}; + +/*************************************************************************** + * Support for computer boards pcmcia-gpib card + * + * Based on gpib PCMCIA client driver written by Claus Schroeter + * (clausi@chemie.fu-berlin.de), which was adapted from the + * pcmcia skeleton example (presumably David Hinds) + ***************************************************************************/ + +#ifdef GPIB_PCMCIA + +#include +#include +#include +#include + +#include +#include + +/* + * All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + * you do not define PCMCIA_DEBUG at all, all the debug code will be + * left out. If you compile with PCMCIA_DEBUG=0, the debug code will + * be present but disabled -- but it can then be enabled for specific + * modules at load time with a 'pc_debug=#' option to insmod. + */ + +#define PCMCIA_DEBUG 1 + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +#define DEBUG(n, args...) do {if (pc_debug > (n)) pr_debug(args); } while (0) +#else +#define DEBUG(args...) +#endif + +/* + * The event() function is this driver's Card Services event handler. + * It will be called by Card Services when an appropriate card status + * event is received. The config() and release() entry points are + * used to configure or release a socket, in response to card insertion + * and ejection events. They are invoked from the gpib event + * handler. + */ + +static int cb_gpib_config(struct pcmcia_device *link); +static void cb_gpib_release(struct pcmcia_device *link); +static int cb_pcmcia_attach(gpib_board_t *board, const gpib_board_config_t *config); +static void cb_pcmcia_detach(gpib_board_t *board); + +/* + * A linked list of "instances" of the gpib device. Each actual + * PCMCIA card corresponds to one device instance, and is described + * by one dev_link_t structure (defined in ds.h). + * + * You may not want to use a linked list for this -- for example, the + * memory card driver uses an array of dev_link_t pointers, where minor + * device numbers are used to derive the corresponding array index. + */ + +static struct pcmcia_device *curr_dev; + +/* + * A dev_link_t structure has fields for most things that are needed + * to keep track of a socket, but there will usually be some device + * specific information that also needs to be kept track of. The + * 'priv' pointer in a dev_link_t structure can be used to point to + * a device-specific private data structure, like this. + * + * A driver needs to provide a dev_node_t structure for each device + * on a card. In some cases, there is only one device per card (for + * example, ethernet cards, modems). In other cases, there may be + * many actual or logical devices (SCSI adapters, memory cards with + * multiple partitions). The dev_node_t structures need to be kept + * in a linked list starting at the 'dev' field of a dev_link_t + * structure. We allocate them in the card's private data structure, + * because they generally can't be allocated dynamically. + */ + +struct local_info { + struct pcmcia_device *p_dev; + gpib_board_t *dev; +}; + +/* + * gpib_attach() creates an "instance" of the driver, allocating + * local data structures for one device. The device is registered + * with Card Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a + * card insertion event. + */ + +static int cb_gpib_probe(struct pcmcia_device *link) +{ + struct local_info *info; + +// int ret, i; + + DEBUG(0, "%s(0x%p)\n", __func__, link); + + /* Allocate space for private device-specific data */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->p_dev = link; + link->priv = info; + + /* The io structure describes IO port mapping */ + link->resource[0]->end = 16; + link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; + link->resource[1]->end = 16; + link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16; + link->io_lines = 10; + + /* General socket configuration */ + link->config_flags = CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + link->config_index = 1; + link->config_regs = PRESENT_OPTION; + + /* Register with Card Services */ + curr_dev = link; + return cb_gpib_config(link); +} /* gpib_attach */ + +/* + * This deletes a driver "instance". The device is de-registered + * with Card Services. If it has been released, all local data + * structures are freed. Otherwise, the structures will be freed + * when the device is released. + */ + +static void cb_gpib_remove(struct pcmcia_device *link) +{ + struct local_info *info = link->priv; + //struct gpib_board_t *dev = info->dev; + + DEBUG(0, "%s(0x%p)\n", __func__, link); + + if (info->dev) + cb_pcmcia_detach(info->dev); + cb_gpib_release(link); + + //free_netdev(dev); + kfree(info); +} + +static int cb_gpib_config_iteration(struct pcmcia_device *link, void *priv_data) +{ + return pcmcia_request_io(link); +} + +/* + * gpib_config() is scheduled to run after a CARD_INSERTION event + * is received, to configure the PCMCIA socket, and to make the + * ethernet device available to the system. + */ + +static int cb_gpib_config(struct pcmcia_device *link) +{ + struct pcmcia_device *handle; + struct local_info *dev; + int retval; + + handle = link; + dev = link->priv; + DEBUG(0, "%s(0x%p)\n", __func__, link); + + retval = pcmcia_loop_config(link, &cb_gpib_config_iteration, NULL); + if (retval) { + dev_warn(&link->dev, "no configuration found\n"); + cb_gpib_release(link); + return -ENODEV; + } + + DEBUG(0, "gpib_cs: manufacturer: 0x%x card: 0x%x\n", link->manf_id, link->card_id); + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + retval = pcmcia_enable_device(link); + if (retval) { + dev_warn(&link->dev, "pcmcia_enable_device failed\n"); + cb_gpib_release(link); + return -ENODEV; + } + + pr_info("gpib device loaded\n"); + return 0; +} /* gpib_config */ + +/* + * After a card is removed, gpib_release() will unregister the net + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ + +static void cb_gpib_release(struct pcmcia_device *link) +{ + DEBUG(0, "%s(0x%p)\n", __func__, link); + pcmcia_disable_device(link); +} + +static int cb_gpib_suspend(struct pcmcia_device *link) +{ + //struct local_info *info = link->priv; + //struct gpib_board_t *dev = info->dev; + DEBUG(0, "%s(0x%p)\n", __func__, link); + + if (link->open) + pr_warn("Device still open ???\n"); + //netif_device_detach(dev); + + return 0; +} + +static int cb_gpib_resume(struct pcmcia_device *link) +{ + //struct local_info *info = link->priv; + //struct gpib_board_t *dev = info->dev; + DEBUG(0, "%s(0x%p)\n", __func__, link); + + /*if (link->open) { + * ni_gpib_probe(dev); / really? + * printk("Gpib resumed ???\n"); + * //netif_device_attach(dev); + * + */ + return cb_gpib_config(link); +} + +/*====================================================================*/ + +static struct pcmcia_device_id cb_pcmcia_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0005), + PCMCIA_DEVICE_NULL +}; +MODULE_DEVICE_TABLE(pcmcia, cb_pcmcia_ids); + +static struct pcmcia_driver cb_gpib_cs_driver = { + .owner = THIS_MODULE, + .drv = { .name = "cb_gpib_cs", }, + .id_table = cb_pcmcia_ids, + .probe = cb_gpib_probe, + .remove = cb_gpib_remove, + .suspend = cb_gpib_suspend, + .resume = cb_gpib_resume, +}; + +int cb_pcmcia_init_module(void) +{ + pcmcia_register_driver(&cb_gpib_cs_driver); + return 0; +} + +void cb_pcmcia_cleanup_module(void) +{ + DEBUG(0, "cb_gpib_cs: unloading\n"); + pcmcia_unregister_driver(&cb_gpib_cs_driver); +} + +gpib_interface_t cb_pcmcia_unaccel_interface = { +name: "cbi_pcmcia_unaccel", +attach : cb_pcmcia_attach, +detach : cb_pcmcia_detach, +read : cb7210_read, +write : cb7210_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +gpib_interface_t cb_pcmcia_interface = { +name: "cbi_pcmcia", +attach : cb_pcmcia_attach, +detach : cb_pcmcia_detach, +read : cb7210_accel_read, +write : cb7210_accel_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +gpib_interface_t cb_pcmcia_accel_interface = { +name: "cbi_pcmcia_accel", +attach : cb_pcmcia_attach, +detach : cb_pcmcia_detach, +read : cb7210_accel_read, +write : cb7210_accel_write, +command : cb7210_command, +take_control : cb7210_take_control, +go_to_standby : cb7210_go_to_standby, +request_system_control : cb7210_request_system_control, +interface_clear : cb7210_interface_clear, +remote_enable : cb7210_remote_enable, +enable_eos : cb7210_enable_eos, +disable_eos : cb7210_disable_eos, +parallel_poll : cb7210_parallel_poll, +parallel_poll_configure : cb7210_parallel_poll_configure, +parallel_poll_response : cb7210_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : cb7210_line_status, +update_status : cb7210_update_status, +primary_address : cb7210_primary_address, +secondary_address : cb7210_secondary_address, +serial_poll_response : cb7210_serial_poll_response, +serial_poll_status : cb7210_serial_poll_status, +t1_delay : cb7210_t1_delay, +return_to_local : cb7210_return_to_local, +}; + +int cb_pcmcia_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct cb7210_priv *cb_priv; + struct nec7210_priv *nec_priv; + int retval; + + if (!curr_dev) { + pr_err("no cb pcmcia cards found\n"); + return -1; + } + + retval = cb7210_generic_attach(board); + if (retval) + return retval; + + cb_priv = board->private_data; + nec_priv = &cb_priv->nec7210_priv; + + if (request_region(curr_dev->resource[0]->start, resource_size(curr_dev->resource[0]), + "cb7210") == 0) { + pr_err("gpib: ioports starting at 0x%lx are already in use\n", + (unsigned long)curr_dev->resource[0]->start); + return -EIO; + } + nec_priv->iobase = (void *)(unsigned long)curr_dev->resource[0]->start; + cb_priv->fifo_iobase = curr_dev->resource[0]->start; + + if (request_irq(curr_dev->irq, cb7210_interrupt, IRQF_SHARED, + "cb7210", board)) { + pr_err("cb7210: failed to request IRQ %d\n", curr_dev->irq); + return -1; + } + cb_priv->irq = curr_dev->irq; + + return cb7210_init(cb_priv, board); +} + +void cb_pcmcia_detach(gpib_board_t *board) +{ + struct cb7210_priv *cb_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (cb_priv) { + nec_priv = &cb_priv->nec7210_priv; + gpib_free_pseudo_irq(board); + if (cb_priv->irq) + free_irq(cb_priv->irq, board); + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + release_region(nec7210_iobase(cb_priv), cb7210_iosize); + } + } + cb7210_generic_detach(board); +} + +#endif /* GPIB_PCMCIA */ + +static int __init cb7210_init_module(void) +{ + int err = 0; + int result; + + result = pci_register_driver(&cb7210_pci_driver); + if (result) { + pr_err("cb7210: pci_driver_register failed!\n"); + return result; + } + + gpib_register_driver(&cb_pci_interface, THIS_MODULE); + gpib_register_driver(&cb_isa_interface, THIS_MODULE); + gpib_register_driver(&cb_pci_accel_interface, THIS_MODULE); + gpib_register_driver(&cb_pci_unaccel_interface, THIS_MODULE); + gpib_register_driver(&cb_isa_accel_interface, THIS_MODULE); + gpib_register_driver(&cb_isa_unaccel_interface, THIS_MODULE); + +#ifdef GPIB__PCMCIA + gpib_register_driver(&cb_pcmcia_interface, THIS_MODULE); + gpib_register_driver(&cb_pcmcia_accel_interface, THIS_MODULE); + gpib_register_driver(&cb_pcmcia_unaccel_interface, THIS_MODULE); + err += cb_pcmcia_init_module(); +#endif + if (err) + return -1; + + return 0; +} + +static void __exit cb7210_exit_module(void) +{ + gpib_unregister_driver(&cb_pci_interface); + gpib_unregister_driver(&cb_isa_interface); + gpib_unregister_driver(&cb_pci_accel_interface); + gpib_unregister_driver(&cb_pci_unaccel_interface); + gpib_unregister_driver(&cb_isa_accel_interface); + gpib_unregister_driver(&cb_isa_unaccel_interface); +#ifdef GPIB_PCMCIA + gpib_unregister_driver(&cb_pcmcia_interface); + gpib_unregister_driver(&cb_pcmcia_accel_interface); + gpib_unregister_driver(&cb_pcmcia_unaccel_interface); + cb_pcmcia_cleanup_module(); +#endif + + pci_unregister_driver(&cb7210_pci_driver); +} + +module_init(cb7210_init_module); +module_exit(cb7210_exit_module); diff --git a/drivers/staging/gpib/cb7210/cb7210.h b/drivers/staging/gpib/cb7210/cb7210.h new file mode 100644 index 00000000000000..4ad976de2b6840 --- /dev/null +++ b/drivers/staging/gpib/cb7210/cb7210.h @@ -0,0 +1,251 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#include "nec7210.h" +#include "gpibP.h" +#include "amccs5933.h" + +#include +#include + +enum { + PCI_DEVICE_ID_CBOARDS_PCI_GPIB = 0x6, + PCI_DEVICE_ID_CBOARDS_CPCI_GPIB = 0xe, +}; + +enum pci_chip { + PCI_CHIP_NONE = 0, + PCI_CHIP_AMCC_S5933, + PCI_CHIP_QUANCOM +}; + +// struct which defines private_data for cb7210 boards +struct cb7210_priv { + struct nec7210_priv nec7210_priv; + struct pci_dev *pci_device; + // base address of amccs5933 pci chip + unsigned long amcc_iobase; + unsigned long fifo_iobase; + unsigned int irq; + enum pci_chip pci_chip; + u8 hs_mode_bits; + unsigned out_fifo_half_empty : 1; + unsigned in_fifo_half_full : 1; +}; + +// interfaces +extern gpib_interface_t cb_pcmcia_interface; +extern gpib_interface_t cb_pcmcia_accel_interface; +extern gpib_interface_t cb_pcmcia_unaccel_interface; + +// interrupt service routines +irqreturn_t cb_pci_interrupt(int irq, void *arg); +irqreturn_t cb7210_interrupt(int irq, void *arg); +irqreturn_t cb7210_internal_interrupt(gpib_board_t *board); + +// interface functions +int cb7210_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read); +int cb7210_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read); +int cb7210_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written); +int cb7210_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written); +int cb7210_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written); +int cb7210_take_control(gpib_board_t *board, int synchronous); +int cb7210_go_to_standby(gpib_board_t *board); +void cb7210_request_system_control(gpib_board_t *board, int request_control); +void cb7210_interface_clear(gpib_board_t *board, int assert); +void cb7210_remote_enable(gpib_board_t *board, int enable); +int cb7210_enable_eos(gpib_board_t *board, uint8_t eos_byte, + int compare_8_bits); +void cb7210_disable_eos(gpib_board_t *board); +unsigned int cb7210_update_status(gpib_board_t *board, unsigned int clear_mask); +int cb7210_primary_address(gpib_board_t *board, unsigned int address); +int cb7210_secondary_address(gpib_board_t *board, unsigned int address, + int enable); +int cb7210_parallel_poll(gpib_board_t *board, uint8_t *result); +void cb7210_serial_poll_response(gpib_board_t *board, uint8_t status); +uint8_t cb7210_serial_poll_status(gpib_board_t *board); +void cb7210_parallel_poll_configure(gpib_board_t *board, uint8_t configuration); +void cb7210_parallel_poll_response(gpib_board_t *board, int ist); +int cb7210_line_status(const gpib_board_t *board); +unsigned int cb7210_t1_delay(gpib_board_t *board, unsigned int nano_sec); +void cb7210_return_to_local(gpib_board_t *board); + +// utility functions +void cb7210_generic_detach(gpib_board_t *board); +int cb7210_generic_attach(gpib_board_t *board); +int cb7210_init(struct cb7210_priv *priv, gpib_board_t *board); + +// pcmcia init/cleanup +int cb_pcmcia_init_module(void); +void cb_pcmcia_cleanup_module(void); + +// pci-gpib register offset +static const int cb7210_reg_offset = 1; + +// uses 10 ioports +static const int cb7210_iosize = 10; + +// fifo size in bytes +static const int cb7210_fifo_size = 2048; +static const int cb7210_fifo_width = 2; + +// cb7210 specific registers and bits +enum cb7210_regs { + BUS_STATUS = 0x7, +}; + +enum cb7210_page_in { + BUS_STATUS_PAGE = 1, +}; + +enum hs_regs { + //write registers + HS_MODE = 0x8, /* HS_MODE register */ + HS_INT_LEVEL = 0x9, /* HS_INT_LEVEL register */ + //read registers + HS_STATUS = 0x8, /* HS_STATUS register */ +}; + +static inline unsigned long nec7210_iobase(const struct cb7210_priv *cb_priv) +{ + return (unsigned long)(cb_priv->nec7210_priv.iobase); +} + +static inline int cb7210_page_in_bits(unsigned int page) +{ + return 0x50 | (page & 0xf); +} + +static inline uint8_t cb7210_paged_read_byte(struct cb7210_priv *cb_priv, + unsigned int register_num, unsigned int page) +{ + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + u8 retval; + unsigned long flags; + + spin_lock_irqsave(&nec_priv->register_page_lock, flags); + outb(cb7210_page_in_bits(page), nec7210_iobase(cb_priv) + AUXMR * nec_priv->offset); + udelay(1); + retval = inb(nec7210_iobase(cb_priv) + register_num * nec_priv->offset); + spin_unlock_irqrestore(&nec_priv->register_page_lock, flags); + return retval; +} + +// don't use for register_num < 8, since it doesn't lock +static inline uint8_t cb7210_read_byte(const struct cb7210_priv *cb_priv, + enum hs_regs register_num) +{ + const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + u8 retval; + + retval = inb(nec7210_iobase(cb_priv) + register_num * nec_priv->offset); + return retval; +} + +static inline void cb7210_paged_write_byte(struct cb7210_priv *cb_priv, uint8_t data, + unsigned int register_num, unsigned int page) +{ + struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + unsigned long flags; + + spin_lock_irqsave(&nec_priv->register_page_lock, flags); + outb(cb7210_page_in_bits(page), nec7210_iobase(cb_priv) + AUXMR * nec_priv->offset); + udelay(1); + outb(data, nec7210_iobase(cb_priv) + register_num * nec_priv->offset); + spin_unlock_irqrestore(&nec_priv->register_page_lock, flags); +} + +// don't use for register_num < 8, since it doesn't lock +static inline void cb7210_write_byte(const struct cb7210_priv *cb_priv, uint8_t data, + enum hs_regs register_num) +{ + const struct nec7210_priv *nec_priv = &cb_priv->nec7210_priv; + + outb(data, nec7210_iobase(cb_priv) + register_num * nec_priv->offset); +} + +enum bus_status_bits { + BSR_ATN_BIT = 0x1, + BSR_EOI_BIT = 0x2, + BSR_SRQ_BIT = 0x4, + BSR_IFC_BIT = 0x8, + BSR_REN_BIT = 0x10, + BSR_DAV_BIT = 0x20, + BSR_NRFD_BIT = 0x40, + BSR_NDAC_BIT = 0x80, +}; + +/* CBI 488.2 HS control */ + +/* when both bit 0 and 1 are set, it + * 1 clears the transmit state machine to an initial condition + * 2 clears any residual interrupts left latched on cbi488.2 + * 3 resets all control bits in HS_MODE to zero + * 4 enables TX empty interrupts + * when both bit 0 and 1 are zero, then the high speed mode is disabled + */ +enum hs_mode_bits { + HS_ENABLE_MASK = 0x3, + HS_TX_ENABLE = (1 << 0), + HS_RX_ENABLE = (1 << 1), + HS_HF_INT_EN = (1 << 3), + HS_CLR_SRQ_INT = (1 << 4), + HS_CLR_EOI_EMPTY_INT = (1 << 5), + HS_CLR_HF_INT = (1 << 6), + HS_SYS_CONTROL = (1 << 7), +}; + +/* CBI 488.2 status */ +enum hs_status_bits { + HS_FIFO_FULL = (1 << 0), + HS_HALF_FULL = (1 << 1), + HS_SRQ_INT = (1 << 2), + HS_EOI_INT = (1 << 3), + HS_TX_MSB_NOT_EMPTY = (1 << 4), + HS_RX_MSB_NOT_EMPTY = (1 << 5), + HS_TX_LSB_NOT_EMPTY = (1 << 6), + HS_RX_LSB_NOT_EMPTY = (1 << 7), +}; + +/* CBI488.2 hs_int_level register */ +enum hs_int_level_bits { + HS_RESET7210 = (1 << 7), +}; + +static inline unsigned int irq_bits(unsigned int irq) +{ + switch (irq) { + case 2: + case 3: + case 4: + case 5: + return irq - 1; + case 7: + return 0x5; + case 10: + return 0x6; + case 11: + return 0x7; + default: + return 0; + } +} + +enum cb7210_aux_cmds { +/* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert + * (and keep asserted) local rtl message. This is used in conjunction + * with the (stupid) cb7210 implementation + * of the normal nec7210 AUX_RTL aux command, which + * causes the rtl message to toggle between on and off. + */ + AUX_RTL2 = 0xd, + AUX_LO_SPEED = 0x40, + AUX_HI_SPEED = 0x41, +}; diff --git a/drivers/staging/gpib/cec/Makefile b/drivers/staging/gpib/cec/Makefile new file mode 100644 index 00000000000000..f4638628ff2945 --- /dev/null +++ b/drivers/staging/gpib/cec/Makefile @@ -0,0 +1,3 @@ + +obj-m += cec_gpib.o + diff --git a/drivers/staging/gpib/cec/cec.h b/drivers/staging/gpib/cec/cec.h new file mode 100644 index 00000000000000..352cf83d8328f7 --- /dev/null +++ b/drivers/staging/gpib/cec/cec.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#include "nec7210.h" +#include "gpibP.h" +#include "plx9050.h" + +struct cec_priv { + struct nec7210_priv nec7210_priv; + struct pci_dev *pci_device; + // base address for plx9052 pci chip + unsigned long plx_iobase; + unsigned int irq; +}; + +// interfaces +extern gpib_interface_t cec_pci_interface; +extern gpib_interface_t cec_pcmcia_interface; + +// interface functions +int cec_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read); +int cec_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written); +int cec_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written); +int cec_take_control(gpib_board_t *board, int synchronous); +int cec_go_to_standby(gpib_board_t *board); +void cec_request_system_control(gpib_board_t *board, int request_control); +void cec_interface_clear(gpib_board_t *board, int assert); +void cec_remote_enable(gpib_board_t *board, int enable); +int cec_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits); +void cec_disable_eos(gpib_board_t *board); +unsigned int cec_update_status(gpib_board_t *board, unsigned int clear_mask); +int cec_primary_address(gpib_board_t *board, unsigned int address); +int cec_secondary_address(gpib_board_t *board, unsigned int address, int enable); +int cec_parallel_poll(gpib_board_t *board, uint8_t *result); +void cec_parallel_poll_configure(gpib_board_t *board, uint8_t configuration); +void cec_parallel_poll_response(gpib_board_t *board, int ist); +void cec_serial_poll_response(gpib_board_t *board, uint8_t status); +void cec_return_to_local(gpib_board_t *board); + +// interrupt service routines +irqreturn_t cec_interrupt(int irq, void *arg); + +// utility functions +void cec_free_private(gpib_board_t *board); +int cec_generic_attach(gpib_board_t *board); +void cec_init(struct cec_priv *priv, const gpib_board_t *board); + +// offset between consecutive nec7210 registers +static const int cec_reg_offset = 1; diff --git a/drivers/staging/gpib/cec/cec_gpib.c b/drivers/staging/gpib/cec/cec_gpib.c new file mode 100644 index 00000000000000..3dc933deb40180 --- /dev/null +++ b/drivers/staging/gpib/cec/cec_gpib.c @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#include "cec.h" +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for CEC PCI and PCMCIA boards"); + +/* + * GPIB interrupt service routines + */ + +irqreturn_t cec_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + struct cec_priv *priv = board->private_data; + unsigned long flags; + irqreturn_t retval; + + spin_lock_irqsave(&board->spinlock, flags); + retval = nec7210_interrupt(board, &priv->nec7210_priv); + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +#define CEC_VENDOR_ID 0x12fc +#define CEC_DEV_ID 0x5cec +#define CEC_SUBID 0x9050 + +static int cec_pci_attach(gpib_board_t *board, const gpib_board_config_t *config); + +static void cec_pci_detach(gpib_board_t *board); + +// wrappers for interface functions +int cec_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); +} + +int cec_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); +} + +int cec_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); +} + +int cec_take_control(gpib_board_t *board, int synchronous) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_take_control(board, &priv->nec7210_priv, synchronous); +} + +int cec_go_to_standby(gpib_board_t *board) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_go_to_standby(board, &priv->nec7210_priv); +} + +void cec_request_system_control(gpib_board_t *board, int request_control) +{ + struct cec_priv *priv = board->private_data; + + nec7210_request_system_control(board, &priv->nec7210_priv, request_control); +} + +void cec_interface_clear(gpib_board_t *board, int assert) +{ + struct cec_priv *priv = board->private_data; + + nec7210_interface_clear(board, &priv->nec7210_priv, assert); +} + +void cec_remote_enable(gpib_board_t *board, int enable) +{ + struct cec_priv *priv = board->private_data; + + nec7210_remote_enable(board, &priv->nec7210_priv, enable); +} + +int cec_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); +} + +void cec_disable_eos(gpib_board_t *board) +{ + struct cec_priv *priv = board->private_data; + + nec7210_disable_eos(board, &priv->nec7210_priv); +} + +unsigned int cec_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_update_status(board, &priv->nec7210_priv, clear_mask); +} + +int cec_primary_address(gpib_board_t *board, unsigned int address) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_primary_address(board, &priv->nec7210_priv, address); +} + +int cec_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); +} + +int cec_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_parallel_poll(board, &priv->nec7210_priv, result); +} + +void cec_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + struct cec_priv *priv = board->private_data; + + nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config); +} + +void cec_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct cec_priv *priv = board->private_data; + + nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); +} + +void cec_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + struct cec_priv *priv = board->private_data; + + nec7210_serial_poll_response(board, &priv->nec7210_priv, status); +} + +static uint8_t cec_serial_poll_status(gpib_board_t *board) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_serial_poll_status(board, &priv->nec7210_priv); +} + +static unsigned int cec_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct cec_priv *priv = board->private_data; + + return nec7210_t1_delay(board, &priv->nec7210_priv, nano_sec); +} + +void cec_return_to_local(gpib_board_t *board) +{ + struct cec_priv *priv = board->private_data; + + nec7210_return_to_local(board, &priv->nec7210_priv); +} + +gpib_interface_t cec_pci_interface = { +name: "cec_pci", +attach : cec_pci_attach, +detach : cec_pci_detach, +read : cec_read, +write : cec_write, +command : cec_command, +take_control : cec_take_control, +go_to_standby : cec_go_to_standby, +request_system_control : cec_request_system_control, +interface_clear : cec_interface_clear, +remote_enable : cec_remote_enable, +enable_eos : cec_enable_eos, +disable_eos : cec_disable_eos, +parallel_poll : cec_parallel_poll, +parallel_poll_configure : cec_parallel_poll_configure, +parallel_poll_response : cec_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : NULL, //XXX +update_status : cec_update_status, +primary_address : cec_primary_address, +secondary_address : cec_secondary_address, +serial_poll_response : cec_serial_poll_response, +serial_poll_status : cec_serial_poll_status, +t1_delay : cec_t1_delay, +return_to_local : cec_return_to_local, +}; + +static int cec_allocate_private(gpib_board_t *board) +{ + struct cec_priv *priv; + + board->private_data = kmalloc(sizeof(struct cec_priv), GFP_KERNEL); + if (!board->private_data) + return -1; + priv = board->private_data; + memset(priv, 0, sizeof(struct cec_priv)); + init_nec7210_private(&priv->nec7210_priv); + return 0; +} + +void cec_free_private(gpib_board_t *board) +{ + kfree(board->private_data); + board->private_data = NULL; +} + +int cec_generic_attach(gpib_board_t *board) +{ + struct cec_priv *cec_priv; + struct nec7210_priv *nec_priv; + + board->status = 0; + + if (cec_allocate_private(board)) + return -ENOMEM; + cec_priv = board->private_data; + nec_priv = &cec_priv->nec7210_priv; + nec_priv->read_byte = nec7210_ioport_read_byte; + nec_priv->write_byte = nec7210_ioport_write_byte; + nec_priv->offset = cec_reg_offset; + nec_priv->type = NEC7210; // guess + return 0; +} + +void cec_init(struct cec_priv *cec_priv, const gpib_board_t *board) +{ + struct nec7210_priv *nec_priv = &cec_priv->nec7210_priv; + + nec7210_board_reset(nec_priv, board); + + /* set internal counter register for 8 MHz input clock */ + write_byte(nec_priv, ICR | 8, AUXMR); + + nec7210_board_online(nec_priv, board); +} + +int cec_pci_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct cec_priv *cec_priv; + struct nec7210_priv *nec_priv; + int isr_flags = 0; + int retval; + + retval = cec_generic_attach(board); + if (retval) + return retval; + + cec_priv = board->private_data; + nec_priv = &cec_priv->nec7210_priv; + + // find board + cec_priv->pci_device = NULL; + while ((cec_priv->pci_device = + gpib_pci_get_device(config, CEC_VENDOR_ID, + CEC_DEV_ID, cec_priv->pci_device))) { + // check for board with plx9050 controller + if (cec_priv->pci_device->subsystem_device == CEC_SUBID) + break; + } + if (!cec_priv->pci_device) { + pr_err("gpib: no cec PCI board found\n"); + return -1; + } + + if (pci_enable_device(cec_priv->pci_device)) { + pr_err("error enabling pci device\n"); + return -1; + } + + if (pci_request_regions(cec_priv->pci_device, "cec-gpib")) + return -1; + + cec_priv->plx_iobase = pci_resource_start(cec_priv->pci_device, 1); + pr_info(" plx9050 base address 0x%lx\n", cec_priv->plx_iobase); + nec_priv->iobase = (void *)(pci_resource_start(cec_priv->pci_device, 3)); + pr_info(" nec7210 base address 0x%p\n", nec_priv->iobase); + + isr_flags |= IRQF_SHARED; + if (request_irq(cec_priv->pci_device->irq, cec_interrupt, isr_flags, "pci-gpib", board)) { + pr_err("gpib: can't request IRQ %d\n", cec_priv->pci_device->irq); + return -1; + } + cec_priv->irq = cec_priv->pci_device->irq; + if (gpib_request_pseudo_irq(board, cec_interrupt)) { + pr_err("cec: failed to allocate pseudo irq\n"); + return -1; + } + cec_init(cec_priv, board); + + // enable interrupts on plx chip + outl(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR1_POLARITY_BIT | PLX9050_PCI_INTR_EN_BIT, + cec_priv->plx_iobase + PLX9050_INTCSR_REG); + + return 0; +} + +void cec_pci_detach(gpib_board_t *board) +{ + struct cec_priv *cec_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (cec_priv) { + nec_priv = &cec_priv->nec7210_priv; + gpib_free_pseudo_irq(board); + if (cec_priv->irq) { + // disable plx9050 interrupts + outl(0, cec_priv->plx_iobase + PLX9050_INTCSR_REG); + free_irq(cec_priv->irq, board); + } + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + pci_release_regions(cec_priv->pci_device); + } + if (cec_priv->pci_device) + pci_dev_put(cec_priv->pci_device); + } + cec_free_private(board); +} + +static int cec_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return 0; +} + +static const struct pci_device_id cec_pci_table[] = { + {CEC_VENDOR_ID, CEC_DEV_ID, PCI_ANY_ID, CEC_SUBID, 0, 0, 0 }, + {0} +}; +MODULE_DEVICE_TABLE(pci, cec_pci_table); + +static struct pci_driver cec_pci_driver = { + .name = "cec_gpib", + .id_table = cec_pci_table, + .probe = &cec_pci_probe +}; + +static int __init cec_init_module(void) +{ + int result; + + result = pci_register_driver(&cec_pci_driver); + if (result) { + pr_err("cec_gpib: pci_driver_register failed!\n"); + return result; + } + + gpib_register_driver(&cec_pci_interface, THIS_MODULE); + + return 0; +} + +static void cec_exit_module(void) +{ + gpib_unregister_driver(&cec_pci_interface); + + pci_unregister_driver(&cec_pci_driver); +} + +module_init(cec_init_module); +module_exit(cec_exit_module); diff --git a/drivers/staging/gpib/common/Makefile b/drivers/staging/gpib/common/Makefile new file mode 100644 index 00000000000000..460586edb5741b --- /dev/null +++ b/drivers/staging/gpib/common/Makefile @@ -0,0 +1,6 @@ + +obj-$(CONFIG_GPIB_COMMON) += gpib_common.o + +gpib_common-objs := gpib_os.o iblib.o + + diff --git a/drivers/staging/gpib/common/gpib_os.c b/drivers/staging/gpib/common/gpib_os.c new file mode 100644 index 00000000000000..405237d8cb479f --- /dev/null +++ b/drivers/staging/gpib/common/gpib_os.c @@ -0,0 +1,2328 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 2001, 2004 by Frank Mori Hess + *************************************************************************** + */ + +#include "ibsys.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB base support"); +MODULE_ALIAS_CHARDEV_MAJOR(GPIB_CODE); + +static int board_type_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, unsigned long arg); +static int read_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, + unsigned long arg); +static int write_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, + unsigned long arg); +static int command_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, + unsigned long arg); +static int open_dev_ioctl(struct file *filep, gpib_board_t *board, unsigned long arg); +static int close_dev_ioctl(struct file *filep, gpib_board_t *board, unsigned long arg); +static int serial_poll_ioctl(gpib_board_t *board, unsigned long arg); +static int wait_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, unsigned long arg); +static int parallel_poll_ioctl(gpib_board_t *board, unsigned long arg); +static int online_ioctl(gpib_board_t *board, unsigned long arg); +static int remote_enable_ioctl(gpib_board_t *board, unsigned long arg); +static int take_control_ioctl(gpib_board_t *board, unsigned long arg); +static int line_status_ioctl(gpib_board_t *board, unsigned long arg); +static int pad_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv, + unsigned long arg); +static int sad_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv, + unsigned long arg); +static int eos_ioctl(gpib_board_t *board, unsigned long arg); +static int request_service_ioctl(gpib_board_t *board, unsigned long arg); +static int request_service2_ioctl(gpib_board_t *board, unsigned long arg); +static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg); +static int irq_ioctl(gpib_board_config_t *config, unsigned long arg); +static int dma_ioctl(gpib_board_config_t *config, unsigned long arg); +static int autospoll_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv, + unsigned long arg); +static int mutex_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv, + unsigned long arg); +static int timeout_ioctl(gpib_board_t *board, unsigned long arg); +static int status_bytes_ioctl(gpib_board_t *board, unsigned long arg); +static int board_info_ioctl(const gpib_board_t *board, unsigned long arg); +static int ppc_ioctl(gpib_board_t *board, unsigned long arg); +static int set_local_ppoll_mode_ioctl(gpib_board_t *board, unsigned long arg); +static int get_local_ppoll_mode_ioctl(gpib_board_t *board, unsigned long arg); +static int query_board_rsv_ioctl(gpib_board_t *board, unsigned long arg); +static int interface_clear_ioctl(gpib_board_t *board, unsigned long arg); +static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg); +static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long arg); +static int event_ioctl(gpib_board_t *board, unsigned long arg); +static int request_system_control_ioctl(gpib_board_t *board, unsigned long arg); +static int t1_delay_ioctl(gpib_board_t *board, unsigned long arg); + +static int cleanup_open_devices(gpib_file_private_t *file_priv, gpib_board_t *board); + +static int pop_gpib_event_nolock(gpib_board_t *board, gpib_event_queue_t *queue, short *event_type); + +/* + * Timer functions + */ + +/* Watchdog timeout routine */ + +static void watchdog_timeout(struct timer_list *t) +{ + gpib_board_t *board = from_timer(board, t, timer); + + set_bit(TIMO_NUM, &board->status); + wake_up_interruptible(&board->wait); +} + +/* install timer interrupt handler */ +void os_start_timer(gpib_board_t *board, unsigned int usec_timeout) +/* Starts the timeout task */ +{ + if (timer_pending(&board->timer)) { + pr_err("gpib: bug! timer already running?\n"); + return; + } + clear_bit(TIMO_NUM, &board->status); + + if (usec_timeout > 0) { + board->timer.function = watchdog_timeout; + /* set number of ticks */ + mod_timer(&board->timer, jiffies + usec_to_jiffies(usec_timeout)); + } +} + +void os_remove_timer(gpib_board_t *board) +/* Removes the timeout task */ +{ + if (timer_pending(&board->timer)) + del_timer_sync(&board->timer); +} + +int io_timed_out(gpib_board_t *board) +{ + if (test_bit(TIMO_NUM, &board->status)) + return 1; + return 0; +} + +void writeb_wrapper(unsigned int value, void *address) +{ + writeb(value, address); +}; +EXPORT_SYMBOL(writeb_wrapper); + +void writew_wrapper(unsigned int value, void *address) +{ + writew(value, address); +}; +EXPORT_SYMBOL(writew_wrapper); + +unsigned int readb_wrapper(void *address) +{ + return readb(address); +}; +EXPORT_SYMBOL(readb_wrapper); + +unsigned int readw_wrapper(void *address) +{ + return readw(address); +}; +EXPORT_SYMBOL(readw_wrapper); + +#ifdef CONFIG_HAS_IOPORT +void outb_wrapper(unsigned int value, void *address) +{ + outb(value, (unsigned long)(address)); +}; +EXPORT_SYMBOL(outb_wrapper); + +void outw_wrapper(unsigned int value, void *address) +{ + outw(value, (unsigned long)(address)); +}; +EXPORT_SYMBOL(outw_wrapper); + +unsigned int inb_wrapper(void *address) +{ + return inb((unsigned long)(address)); +}; +EXPORT_SYMBOL(inb_wrapper); + +unsigned int inw_wrapper(void *address) +{ + return inw((unsigned long)(address)); +}; +EXPORT_SYMBOL(inw_wrapper); +#endif + +/* this is a function instead of a constant because of Suse + * defining HZ to be a function call to get_hz() + */ +static inline int pseudo_irq_period(void) +{ + return (HZ + 99) / 100; +} + +static void pseudo_irq_handler(struct timer_list *t) +{ + struct gpib_pseudo_irq *pseudo_irq = from_timer(pseudo_irq, t, timer); + + if (pseudo_irq->handler) + pseudo_irq->handler(0, pseudo_irq->board); + else + pr_err("gpib: bug! pseudo_irq.handler is NULL\n"); + + if (atomic_read(&pseudo_irq->active)) + mod_timer(&pseudo_irq->timer, jiffies + pseudo_irq_period()); +} + +int gpib_request_pseudo_irq(gpib_board_t *board, irqreturn_t (*handler)(int, void *)) +{ + if (timer_pending(&board->pseudo_irq.timer) || board->pseudo_irq.handler) { + pr_err("gpib: only one pseudo interrupt per board allowed\n"); + return -1; + } + + board->pseudo_irq.handler = handler; + board->pseudo_irq.timer.function = pseudo_irq_handler; + board->pseudo_irq.board = board; + + atomic_set(&board->pseudo_irq.active, 1); + + mod_timer(&board->pseudo_irq.timer, jiffies + pseudo_irq_period()); + + return 0; +} +EXPORT_SYMBOL(gpib_request_pseudo_irq); + +void gpib_free_pseudo_irq(gpib_board_t *board) +{ + atomic_set(&board->pseudo_irq.active, 0); + + del_timer_sync(&board->pseudo_irq.timer); + board->pseudo_irq.handler = NULL; +} +EXPORT_SYMBOL(gpib_free_pseudo_irq); + +static const unsigned int serial_timeout = 1000000; + +unsigned int num_status_bytes(const gpib_status_queue_t *dev) +{ + if (!dev) + return 0; + return dev->num_status_bytes; +} + +// push status byte onto back of status byte fifo +int push_status_byte(gpib_board_t *board, gpib_status_queue_t *device, u8 poll_byte) +{ + struct list_head *head = &device->status_bytes; + status_byte_t *status; + static const unsigned int max_num_status_bytes = 1024; + int retval; + + if (num_status_bytes(device) >= max_num_status_bytes) { + u8 lost_byte; + + device->dropped_byte = 1; + retval = pop_status_byte(board, device, &lost_byte); + if (retval < 0) + return retval; + } + + status = kmalloc(sizeof(status_byte_t), GFP_KERNEL); + if (!status) + return -ENOMEM; + + INIT_LIST_HEAD(&status->list); + status->poll_byte = poll_byte; + + list_add_tail(&status->list, head); + + device->num_status_bytes++; + + dev_dbg(board->gpib_dev, "pushed status byte 0x%x, %i in queue\n", + (int)poll_byte, num_status_bytes(device)); + + return 0; +} + +// pop status byte from front of status byte fifo +int pop_status_byte(gpib_board_t *board, gpib_status_queue_t *device, u8 *poll_byte) +{ + struct list_head *head = &device->status_bytes; + struct list_head *front = head->next; + status_byte_t *status; + + if (num_status_bytes(device) == 0) + return -EIO; + + if (front == head) + return -EIO; + + if (device->dropped_byte) { + device->dropped_byte = 0; + return -EPIPE; + } + + status = list_entry(front, status_byte_t, list); + *poll_byte = status->poll_byte; + + list_del(front); + kfree(status); + + device->num_status_bytes--; + + dev_dbg(board->gpib_dev, "popped status byte 0x%x, %i in queue\n", + (int)*poll_byte, num_status_bytes(device)); + + return 0; +} + +gpib_status_queue_t *get_gpib_status_queue(gpib_board_t *board, unsigned int pad, int sad) +{ + gpib_status_queue_t *device; + struct list_head *list_ptr; + const struct list_head *head = &board->device_list; + + for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) { + device = list_entry(list_ptr, gpib_status_queue_t, list); + if (gpib_address_equal(device->pad, device->sad, pad, sad)) + return device; + } + + return NULL; +} + +int get_serial_poll_byte(gpib_board_t *board, unsigned int pad, int sad, unsigned int usec_timeout, + uint8_t *poll_byte) +{ + gpib_status_queue_t *device; + + dev_dbg(board->gpib_dev, "%s:()\n", __func__); + + device = get_gpib_status_queue(board, pad, sad); + if (num_status_bytes(device)) + return pop_status_byte(board, device, poll_byte); + else + return dvrsp(board, pad, sad, usec_timeout, poll_byte); +} + +int autopoll_all_devices(gpib_board_t *board) +{ + int retval; + + dev_dbg(board->gpib_dev, "entering %s()\n", __func__); + if (mutex_lock_interruptible(&board->user_mutex)) + return -ERESTARTSYS; + if (mutex_lock_interruptible(&board->big_gpib_mutex)) { + mutex_unlock(&board->user_mutex); + return -ERESTARTSYS; + } + + dev_dbg(board->gpib_dev, "autopoll has board lock\n"); + + retval = serial_poll_all(board, serial_timeout); + if (retval < 0) { + mutex_unlock(&board->big_gpib_mutex); + mutex_unlock(&board->user_mutex); + return retval; + } + + dev_dbg(board->gpib_dev, "%s complete\n", __func__); + /* need to wake wait queue in case someone is + * waiting on RQS + */ + wake_up_interruptible(&board->wait); + mutex_unlock(&board->big_gpib_mutex); + mutex_unlock(&board->user_mutex); + + return retval; +} + +static int setup_serial_poll(gpib_board_t *board, unsigned int usec_timeout) +{ + u8 cmd_string[8]; + int i; + size_t bytes_written; + int ret; + + dev_dbg(board->gpib_dev, "entering %s()\n", __func__); + + os_start_timer(board, usec_timeout); + ret = ibcac(board, 1, 1); + if (ret < 0) { + os_remove_timer(board); + return ret; + } + + i = 0; + cmd_string[i++] = UNL; + cmd_string[i++] = MLA(board->pad); /* controller's listen address */ + if (board->sad >= 0) + cmd_string[i++] = MSA(board->sad); + cmd_string[i++] = SPE; //serial poll enable + + ret = board->interface->command(board, cmd_string, i, &bytes_written); + if (ret < 0 || bytes_written < i) { + pr_err("gpib: failed to setup serial poll\n"); + os_remove_timer(board); + return -EIO; + } + os_remove_timer(board); + + return 0; +} + +static int read_serial_poll_byte(gpib_board_t *board, unsigned int pad, + int sad, unsigned int usec_timeout, uint8_t *result) +{ + u8 cmd_string[8]; + int end_flag; + int ret; + int i; + size_t nbytes; + + dev_dbg(board->gpib_dev, "entering %s(), pad=%i sad=%i\n", __func__, pad, sad); + + os_start_timer(board, usec_timeout); + ret = ibcac(board, 1, 1); + if (ret < 0) { + os_remove_timer(board); + return ret; + } + + i = 0; + // send talk address + cmd_string[i++] = MTA(pad); + if (sad >= 0) + cmd_string[i++] = MSA(sad); + + ret = board->interface->command(board, cmd_string, i, &nbytes); + if (ret < 0 || nbytes < i) { + pr_err("gpib: failed to setup serial poll\n"); + os_remove_timer(board); + return -EIO; + } + + ibgts(board); + + // read poll result + ret = board->interface->read(board, result, 1, &end_flag, &nbytes); + if (ret < 0 || nbytes < 1) { + pr_err("gpib: serial poll failed\n"); + os_remove_timer(board); + return -EIO; + } + os_remove_timer(board); + + return 0; +} + +static int cleanup_serial_poll(gpib_board_t *board, unsigned int usec_timeout) +{ + u8 cmd_string[8]; + int ret; + size_t bytes_written; + + dev_dbg(board->gpib_dev, "entering %s()\n", __func__); + + os_start_timer(board, usec_timeout); + ret = ibcac(board, 1, 1); + if (ret < 0) { + os_remove_timer(board); + return ret; + } + + cmd_string[0] = SPD; /* disable serial poll bytes */ + cmd_string[1] = UNT; + ret = board->interface->command(board, cmd_string, 2, &bytes_written); + if (ret < 0 || bytes_written < 2) { + pr_err("gpib: failed to disable serial poll\n"); + os_remove_timer(board); + return -EIO; + } + os_remove_timer(board); + + return 0; +} + +static int serial_poll_single(gpib_board_t *board, unsigned int pad, int sad, + unsigned int usec_timeout, uint8_t *result) +{ + int retval, cleanup_retval; + + retval = setup_serial_poll(board, usec_timeout); + if (retval < 0) + return retval; + retval = read_serial_poll_byte(board, pad, sad, usec_timeout, result); + cleanup_retval = cleanup_serial_poll(board, usec_timeout); + if (retval < 0) + return retval; + if (cleanup_retval < 0) + return retval; + + return 0; +} + +int serial_poll_all(gpib_board_t *board, unsigned int usec_timeout) +{ + int retval = 0; + struct list_head *cur; + const struct list_head *head = NULL; + gpib_status_queue_t *device; + u8 result; + unsigned int num_bytes = 0; + + dev_dbg(board->gpib_dev, "entering %s()\n", __func__); + + head = &board->device_list; + if (head->next == head) + return 0; + + retval = setup_serial_poll(board, usec_timeout); + if (retval < 0) + return retval; + + for (cur = head->next; cur != head; cur = cur->next) { + device = list_entry(cur, gpib_status_queue_t, list); + retval = read_serial_poll_byte(board, + device->pad, device->sad, usec_timeout, &result); + if (retval < 0) + continue; + if (result & request_service_bit) { + retval = push_status_byte(board, device, result); + if (retval < 0) + continue; + num_bytes++; + } + } + + retval = cleanup_serial_poll(board, usec_timeout); + if (retval < 0) + return retval; + + return num_bytes; +} + +/* + * DVRSP + * This function performs a serial poll of the device with primary + * address pad and secondary address sad. If the device has no + * secondary address, pass a negative number in for this argument. At the + * end of a successful serial poll the response is returned in result. + * SPD and UNT are sent at the completion of the poll. + */ + +int dvrsp(gpib_board_t *board, unsigned int pad, int sad, + unsigned int usec_timeout, uint8_t *result) +{ + int status = ibstatus(board); + int retval; + + if ((status & CIC) == 0) { + pr_err("gpib: not CIC during serial poll\n"); + return -1; + } + + if (pad > MAX_GPIB_PRIMARY_ADDRESS || sad > MAX_GPIB_SECONDARY_ADDRESS) { + pr_err("gpib: bad address for serial poll"); + return -1; + } + + retval = serial_poll_single(board, pad, sad, usec_timeout, result); + if (io_timed_out(board)) + retval = -ETIMEDOUT; + + return retval; +} + +static gpib_descriptor_t *handle_to_descriptor(const gpib_file_private_t *file_priv, + int handle) +{ + if (handle < 0 || handle >= GPIB_MAX_NUM_DESCRIPTORS) { + pr_err("gpib: invalid handle %i\n", handle); + return NULL; + } + + return file_priv->descriptors[handle]; +} + +static int init_gpib_file_private(gpib_file_private_t *priv) +{ + memset(priv, 0, sizeof(*priv)); + atomic_set(&priv->holding_mutex, 0); + priv->descriptors[0] = kmalloc(sizeof(gpib_descriptor_t), GFP_KERNEL); + if (!priv->descriptors[0]) { + pr_err("gpib: failed to allocate default board descriptor\n"); + return -ENOMEM; + } + init_gpib_descriptor(priv->descriptors[0]); + priv->descriptors[0]->is_board = 1; + mutex_init(&priv->descriptors_mutex); + return 0; +} + +int ibopen(struct inode *inode, struct file *filep) +{ + unsigned int minor = iminor(inode); + gpib_board_t *board; + gpib_file_private_t *priv; + + if (minor >= GPIB_MAX_NUM_BOARDS) { + pr_err("gpib: invalid minor number of device file\n"); + return -ENXIO; + } + + board = &board_array[minor]; + + filep->private_data = kmalloc(sizeof(gpib_file_private_t), GFP_KERNEL); + if (!filep->private_data) + return -ENOMEM; + + priv = filep->private_data; + init_gpib_file_private((gpib_file_private_t *)filep->private_data); + + dev_dbg(board->gpib_dev, "pid %i, gpib: opening minor %d\n", current->pid, minor); + + if (board->use_count == 0) { + int retval; + + retval = request_module("gpib%i", minor); + if (retval) { + dev_dbg(board->gpib_dev, "pid %i, gpib: request module returned %i\n", + current->pid, retval); + } + } + if (board->interface) { + if (!try_module_get(board->provider_module)) { + pr_err("gpib: try_module_get() failed\n"); + return -EIO; + } + board->use_count++; + priv->got_module = 1; + } + return 0; +} + +int ibclose(struct inode *inode, struct file *filep) +{ + unsigned int minor = iminor(inode); + gpib_board_t *board; + gpib_file_private_t *priv = filep->private_data; + gpib_descriptor_t *desc; + + if (minor >= GPIB_MAX_NUM_BOARDS) { + pr_err("gpib: invalid minor number of device file\n"); + return -ENODEV; + } + + board = &board_array[minor]; + + dev_dbg(board->gpib_dev, "pid %i, closing minor %d\n", current->pid, minor); + + if (priv) { + desc = handle_to_descriptor(priv, 0); + if (desc) { + if (desc->autopoll_enabled) { + dev_dbg(board->gpib_dev, "pid %i, decrementing autospollers\n", + current->pid); + if (board->autospollers > 0) + board->autospollers--; + else + pr_err("gpib: Attempt to decrement zero autospollers\n"); + } + } else { + pr_err("gpib: Unexpected null gpib_descriptor\n"); + } + + cleanup_open_devices(priv, board); + + if (atomic_read(&priv->holding_mutex)) + mutex_unlock(&board->user_mutex); + + if (priv->got_module && board->use_count) { + module_put(board->provider_module); + --board->use_count; + } + + kfree(filep->private_data); + filep->private_data = NULL; + } + + return 0; +} + +long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + unsigned int minor = iminor(filep->f_path.dentry->d_inode); + gpib_board_t *board; + gpib_file_private_t *file_priv = filep->private_data; + long retval = -ENOTTY; + + if (minor >= GPIB_MAX_NUM_BOARDS) { + pr_err("gpib: invalid minor number of device file\n"); + return -ENODEV; + } + board = &board_array[minor]; + + if (mutex_lock_interruptible(&board->big_gpib_mutex)) + return -ERESTARTSYS; + + dev_dbg(board->gpib_dev, "pid %i, ioctl %d, interface=%s, use=%d, onl=%d\n", + current->pid, cmd & 0xff, + board->interface ? board->interface->name : "", + board->use_count, + board->online); + + switch (cmd) { + case CFCBOARDTYPE: + retval = board_type_ioctl(file_priv, board, arg); + goto done; + case IBONL: + retval = online_ioctl(board, arg); + goto done; + default: + break; + } + if (!board->interface) { + pr_err("gpib: no gpib board configured on /dev/gpib%i\n", minor); + retval = -ENODEV; + goto done; + } + if (file_priv->got_module == 0) { + if (!try_module_get(board->provider_module)) { + pr_err("gpib: try_module_get() failed\n"); + retval = -EIO; + goto done; + } + file_priv->got_module = 1; + board->use_count++; + } + switch (cmd) { + case CFCBASE: + retval = iobase_ioctl(&board->config, arg); + goto done; + case CFCIRQ: + retval = irq_ioctl(&board->config, arg); + goto done; + case CFCDMA: + retval = dma_ioctl(&board->config, arg); + goto done; + case IBAUTOSPOLL: + retval = autospoll_ioctl(board, file_priv, arg); + goto done; + case IBBOARD_INFO: + retval = board_info_ioctl(board, arg); + goto done; + case IBMUTEX: + /* Need to unlock board->big_gpib_mutex before potentially locking board->user_mutex + * to maintain consistent locking order + */ + mutex_unlock(&board->big_gpib_mutex); + return mutex_ioctl(board, file_priv, arg); + case IBPAD: + retval = pad_ioctl(board, file_priv, arg); + goto done; + case IBSAD: + retval = sad_ioctl(board, file_priv, arg); + goto done; + case IBSELECT_PCI: + retval = select_pci_ioctl(&board->config, arg); + goto done; + case IBSELECT_DEVICE_PATH: + retval = select_device_path_ioctl(&board->config, arg); + goto done; + default: + break; + } + + if (!board->online) { + pr_err("gpib: ioctl %i invalid for offline board\n", + cmd & 0xff); + retval = -EINVAL; + goto done; + } + + switch (cmd) { + case IBEVENT: + retval = event_ioctl(board, arg); + goto done; + case IBCLOSEDEV: + retval = close_dev_ioctl(filep, board, arg); + goto done; + case IBOPENDEV: + retval = open_dev_ioctl(filep, board, arg); + goto done; + case IBSPOLL_BYTES: + retval = status_bytes_ioctl(board, arg); + goto done; + case IBWAIT: + retval = wait_ioctl(file_priv, board, arg); + if (retval == -ERESTARTSYS) + return retval; + goto done; + case IBLINES: + retval = line_status_ioctl(board, arg); + goto done; + case IBLOC: + board->interface->return_to_local(board); + retval = 0; + goto done; + default: + break; + } + + spin_lock(&board->locking_pid_spinlock); + if (current->pid != board->locking_pid) { + spin_unlock(&board->locking_pid_spinlock); + pr_err("gpib: need to hold board lock to perform ioctl %i\n", + cmd & 0xff); + retval = -EPERM; + goto done; + } + spin_unlock(&board->locking_pid_spinlock); + + switch (cmd) { + case IB_T1_DELAY: + retval = t1_delay_ioctl(board, arg); + goto done; + case IBCAC: + retval = take_control_ioctl(board, arg); + goto done; + case IBCMD: + /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex + * before we call them. + */ + mutex_unlock(&board->big_gpib_mutex); + return command_ioctl(file_priv, board, arg); + case IBEOS: + retval = eos_ioctl(board, arg); + goto done; + case IBGTS: + retval = ibgts(board); + goto done; + case IBPPC: + retval = ppc_ioctl(board, arg); + goto done; + case IBPP2_SET: + retval = set_local_ppoll_mode_ioctl(board, arg); + goto done; + case IBPP2_GET: + retval = get_local_ppoll_mode_ioctl(board, arg); + goto done; + case IBQUERY_BOARD_RSV: + retval = query_board_rsv_ioctl(board, arg); + goto done; + case IBRD: + /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex + * before we call them. + */ + mutex_unlock(&board->big_gpib_mutex); + return read_ioctl(file_priv, board, arg); + case IBRPP: + retval = parallel_poll_ioctl(board, arg); + goto done; + case IBRSC: + retval = request_system_control_ioctl(board, arg); + goto done; + case IBRSP: + retval = serial_poll_ioctl(board, arg); + goto done; + case IBRSV: + retval = request_service_ioctl(board, arg); + goto done; + case IBRSV2: + retval = request_service2_ioctl(board, arg); + goto done; + case IBSIC: + retval = interface_clear_ioctl(board, arg); + goto done; + case IBSRE: + retval = remote_enable_ioctl(board, arg); + goto done; + case IBTMO: + retval = timeout_ioctl(board, arg); + goto done; + case IBWRT: + /* IO ioctls can take a long time, we need to unlock board->big_gpib_mutex + * before we call them. + */ + mutex_unlock(&board->big_gpib_mutex); + return write_ioctl(file_priv, board, arg); + default: + retval = -ENOTTY; + goto done; + } + +done: + mutex_unlock(&board->big_gpib_mutex); + dev_dbg(board->gpib_dev, "ioctl done status = 0x%lx\n", board->status); + return retval; +} + +static int board_type_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, unsigned long arg) +{ + struct list_head *list_ptr; + board_type_ioctl_t cmd; + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (board->online) { + pr_err("gpib: can't change board type while board is online.\n"); + return -EBUSY; + } + + retval = copy_from_user(&cmd, (void *)arg, sizeof(board_type_ioctl_t)); + if (retval) + return retval; + + for (list_ptr = registered_drivers.next; list_ptr != ®istered_drivers; + list_ptr = list_ptr->next) { + gpib_interface_list_t *entry; + + entry = list_entry(list_ptr, gpib_interface_list_t, list); + if (strcmp(entry->interface->name, cmd.name) == 0) { + int i; + int had_module = file_priv->got_module; + + if (board->use_count) { + for (i = 0; i < board->use_count; ++i) + module_put(board->provider_module); + board->interface = NULL; + file_priv->got_module = 0; + } + board->interface = entry->interface; + board->provider_module = entry->module; + for (i = 0; i < board->use_count; ++i) { + if (!try_module_get(entry->module)) { + board->use_count = i; + return -EIO; + } + } + if (had_module == 0) { + if (!try_module_get(entry->module)) + return -EIO; + ++board->use_count; + } + file_priv->got_module = 1; + return 0; + } + } + + return -EINVAL; +} + +static int read_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, + unsigned long arg) +{ + read_write_ioctl_t read_cmd; + u8 *userbuf; + unsigned long remain; + int end_flag = 0; + int retval; + ssize_t read_ret = 0; + gpib_descriptor_t *desc; + size_t nbytes; + + retval = copy_from_user(&read_cmd, (void *)arg, sizeof(read_cmd)); + if (retval) + return -EFAULT; + + if (read_cmd.completed_transfer_count > read_cmd.requested_transfer_count) + return -EINVAL; + + desc = handle_to_descriptor(file_priv, read_cmd.handle); + if (!desc) + return -EINVAL; + + if (WARN_ON_ONCE(sizeof(userbuf) > sizeof(read_cmd.buffer_ptr))) + return -EFAULT; + + userbuf = (u8 *)(unsigned long)read_cmd.buffer_ptr; + userbuf += read_cmd.completed_transfer_count; + + remain = read_cmd.requested_transfer_count - read_cmd.completed_transfer_count; + + /* Check write access to buffer */ + if (!access_ok(userbuf, remain)) + return -EFAULT; + + atomic_set(&desc->io_in_progress, 1); + + /* Read buffer loads till we fill the user supplied buffer */ + while (remain > 0 && end_flag == 0) { + nbytes = 0; + read_ret = ibrd(board, board->buffer, (board->buffer_length < remain) ? + board->buffer_length : remain, &end_flag, &nbytes); + if (nbytes == 0) + break; + retval = copy_to_user(userbuf, board->buffer, nbytes); + if (retval) { + retval = -EFAULT; + break; + } + remain -= nbytes; + userbuf += nbytes; + if (read_ret < 0) + break; + } + read_cmd.completed_transfer_count = read_cmd.requested_transfer_count - remain; + read_cmd.end = end_flag; + /* suppress errors (for example due to timeout or interruption by device clear) + * if all bytes got sent. This prevents races that can occur in the various drivers + * if a device receives a device clear immediately after a transfer completes and + * the driver code wasn't careful enough to handle that case. + */ + if (remain == 0 || end_flag) + read_ret = 0; + if (retval == 0) + retval = copy_to_user((void *)arg, &read_cmd, sizeof(read_cmd)); + + atomic_set(&desc->io_in_progress, 0); + + wake_up_interruptible(&board->wait); + if (retval) + return -EFAULT; + + return read_ret; +} + +static int command_ioctl(gpib_file_private_t *file_priv, + gpib_board_t *board, unsigned long arg) +{ + read_write_ioctl_t cmd; + u8 *userbuf; + unsigned long remain; + int retval; + int fault = 0; + gpib_descriptor_t *desc; + size_t bytes_written; + int no_clear_io_in_prog; + + retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd)); + if (retval) + return -EFAULT; + + if (cmd.completed_transfer_count > cmd.requested_transfer_count) + return -EINVAL; + + desc = handle_to_descriptor(file_priv, cmd.handle); + if (!desc) + return -EINVAL; + + userbuf = (u8 *)(unsigned long)cmd.buffer_ptr; + userbuf += cmd.completed_transfer_count; + + no_clear_io_in_prog = cmd.end; + cmd.end = 0; + + remain = cmd.requested_transfer_count - cmd.completed_transfer_count; + + /* Check read access to buffer */ + if (!access_ok(userbuf, remain)) + return -EFAULT; + + /* Write buffer loads till we empty the user supplied buffer. + * Call drivers at least once, even if remain is zero, in + * order to allow them to insure previous commands were + * completely finished, in the case of a restarted ioctl. + */ + + atomic_set(&desc->io_in_progress, 1); + + do { + fault = copy_from_user(board->buffer, userbuf, (board->buffer_length < remain) ? + board->buffer_length : remain); + if (fault) { + retval = -EFAULT; + bytes_written = 0; + } else { + retval = ibcmd(board, board->buffer, (board->buffer_length < remain) ? + board->buffer_length : remain, &bytes_written); + } + remain -= bytes_written; + userbuf += bytes_written; + if (retval < 0) { + atomic_set(&desc->io_in_progress, 0); + + wake_up_interruptible(&board->wait); + break; + } + } while (remain > 0); + + cmd.completed_transfer_count = cmd.requested_transfer_count - remain; + + if (fault == 0) + fault = copy_to_user((void *)arg, &cmd, sizeof(cmd)); + + /* + * no_clear_io_in_prog (cmd.end) is true when io_in_progress should + * not be set to zero because the cmd in progress is the address setup + * operation for an async read or write. This causes CMPL not to be set + * in general_ibstatus until the async read or write completes. + */ + if (!no_clear_io_in_prog || fault) + atomic_set(&desc->io_in_progress, 0); + + wake_up_interruptible(&board->wait); + if (fault) + return -EFAULT; + + return retval; +} + +static int write_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, + unsigned long arg) +{ + read_write_ioctl_t write_cmd; + u8 *userbuf; + unsigned long remain; + int retval = 0; + int fault; + gpib_descriptor_t *desc; + + fault = copy_from_user(&write_cmd, (void *)arg, sizeof(write_cmd)); + if (fault) + return -EFAULT; + + if (write_cmd.completed_transfer_count > write_cmd.requested_transfer_count) + return -EINVAL; + + desc = handle_to_descriptor(file_priv, write_cmd.handle); + if (!desc) + return -EINVAL; + + userbuf = (u8 *)(unsigned long)write_cmd.buffer_ptr; + userbuf += write_cmd.completed_transfer_count; + + remain = write_cmd.requested_transfer_count - write_cmd.completed_transfer_count; + + /* Check read access to buffer */ + if (!access_ok(userbuf, remain)) + return -EFAULT; + + atomic_set(&desc->io_in_progress, 1); + + /* Write buffer loads till we empty the user supplied buffer */ + while (remain > 0) { + int send_eoi; + size_t bytes_written = 0; + + send_eoi = remain <= board->buffer_length && write_cmd.end; + fault = copy_from_user(board->buffer, userbuf, (board->buffer_length < remain) ? + board->buffer_length : remain); + if (fault) { + retval = -EFAULT; + break; + } + retval = ibwrt(board, board->buffer, (board->buffer_length < remain) ? + board->buffer_length : remain, send_eoi, &bytes_written); + remain -= bytes_written; + userbuf += bytes_written; + if (retval < 0) + break; + } + write_cmd.completed_transfer_count = write_cmd.requested_transfer_count - remain; + /* suppress errors (for example due to timeout or interruption by device clear) + * if all bytes got sent. This prevents races that can occur in the various drivers + * if a device receives a device clear immediately after a transfer completes and + * the driver code wasn't careful enough to handle that case. + */ + if (remain == 0) + retval = 0; + if (fault == 0) + fault = copy_to_user((void *)arg, &write_cmd, sizeof(write_cmd)); + + atomic_set(&desc->io_in_progress, 0); + + wake_up_interruptible(&board->wait); + if (fault) + return -EFAULT; + + return retval; +} + +static int status_bytes_ioctl(gpib_board_t *board, unsigned long arg) +{ + gpib_status_queue_t *device; + spoll_bytes_ioctl_t cmd; + int retval; + + retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd)); + if (retval) + return -EFAULT; + + device = get_gpib_status_queue(board, cmd.pad, cmd.sad); + if (!device) + cmd.num_bytes = 0; + else + cmd.num_bytes = num_status_bytes(device); + + retval = copy_to_user((void *)arg, &cmd, sizeof(cmd)); + if (retval) + return -EFAULT; + + return 0; +} + +static int increment_open_device_count(gpib_board_t *board, struct list_head *head, + unsigned int pad, int sad) +{ + struct list_head *list_ptr; + gpib_status_queue_t *device; + + /* first see if address has already been opened, then increment + * open count + */ + for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) { + device = list_entry(list_ptr, gpib_status_queue_t, list); + if (gpib_address_equal(device->pad, device->sad, pad, sad)) { + dev_dbg(board->gpib_dev, "pid %i, incrementing open count for pad %i, sad %i\n", + current->pid, device->pad, device->sad); + device->reference_count++; + return 0; + } + } + + /* otherwise we need to allocate a new gpib_status_queue_t */ + device = kmalloc(sizeof(gpib_status_queue_t), GFP_ATOMIC); + if (!device) + return -ENOMEM; + init_gpib_status_queue(device); + device->pad = pad; + device->sad = sad; + device->reference_count = 1; + + list_add(&device->list, head); + + dev_dbg(board->gpib_dev, "pid %i, opened pad %i, sad %i\n", + current->pid, device->pad, device->sad); + + return 0; +} + +static int subtract_open_device_count(gpib_board_t *board, struct list_head *head, + unsigned int pad, int sad, unsigned int count) +{ + gpib_status_queue_t *device; + struct list_head *list_ptr; + + for (list_ptr = head->next; list_ptr != head; list_ptr = list_ptr->next) { + device = list_entry(list_ptr, gpib_status_queue_t, list); + if (gpib_address_equal(device->pad, device->sad, pad, sad)) { + dev_dbg(board->gpib_dev, "pid %i, decrementing open count for pad %i, sad %i\n", + current->pid, device->pad, device->sad); + if (count > device->reference_count) { + pr_err("gpib: bug! in %s()\n", __func__); + return -EINVAL; + } + device->reference_count -= count; + if (device->reference_count == 0) { + dev_dbg(board->gpib_dev, "pid %i, closing pad %i, sad %i\n", + current->pid, device->pad, device->sad); + list_del(list_ptr); + kfree(device); + } + return 0; + } + } + pr_err("gpib: bug! tried to close address that was never opened!\n"); + return -EINVAL; +} + +static inline int decrement_open_device_count(gpib_board_t *board, struct list_head *head, + unsigned int pad, int sad) +{ + return subtract_open_device_count(board, head, pad, sad, 1); +} + +static int cleanup_open_devices(gpib_file_private_t *file_priv, gpib_board_t *board) +{ + int retval = 0; + int i; + + for (i = 0; i < GPIB_MAX_NUM_DESCRIPTORS; i++) { + gpib_descriptor_t *desc; + + desc = file_priv->descriptors[i]; + if (!desc) + continue; + + if (desc->is_board == 0) { + retval = decrement_open_device_count(board, &board->device_list, desc->pad, + desc->sad); + if (retval < 0) + return retval; + } + kfree(desc); + file_priv->descriptors[i] = NULL; + } + + return 0; +} + +static int open_dev_ioctl(struct file *filep, gpib_board_t *board, unsigned long arg) +{ + open_dev_ioctl_t open_dev_cmd; + int retval; + gpib_file_private_t *file_priv = filep->private_data; + int i; + + retval = copy_from_user(&open_dev_cmd, (void *)arg, sizeof(open_dev_cmd)); + if (retval) + return -EFAULT; + + if (mutex_lock_interruptible(&file_priv->descriptors_mutex)) + return -ERESTARTSYS; + for (i = 0; i < GPIB_MAX_NUM_DESCRIPTORS; i++) + if (!file_priv->descriptors[i]) + break; + if (i == GPIB_MAX_NUM_DESCRIPTORS) { + mutex_unlock(&file_priv->descriptors_mutex); + return -ERANGE; + } + file_priv->descriptors[i] = kmalloc(sizeof(gpib_descriptor_t), GFP_KERNEL); + if (!file_priv->descriptors[i]) { + mutex_unlock(&file_priv->descriptors_mutex); + return -ENOMEM; + } + init_gpib_descriptor(file_priv->descriptors[i]); + + file_priv->descriptors[i]->pad = open_dev_cmd.pad; + file_priv->descriptors[i]->sad = open_dev_cmd.sad; + file_priv->descriptors[i]->is_board = open_dev_cmd.is_board; + mutex_unlock(&file_priv->descriptors_mutex); + + retval = increment_open_device_count(board, &board->device_list, open_dev_cmd.pad, + open_dev_cmd.sad); + if (retval < 0) + return retval; + + /* clear stuck srq state, since we may be able to find service request on + * the new device + */ + atomic_set(&board->stuck_srq, 0); + + open_dev_cmd.handle = i; + retval = copy_to_user((void *)arg, &open_dev_cmd, sizeof(open_dev_cmd)); + if (retval) + return -EFAULT; + + return 0; +} + +static int close_dev_ioctl(struct file *filep, gpib_board_t *board, unsigned long arg) +{ + close_dev_ioctl_t cmd; + gpib_file_private_t *file_priv = filep->private_data; + int retval; + + retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd)); + if (retval) + return -EFAULT; + + if (cmd.handle >= GPIB_MAX_NUM_DESCRIPTORS) + return -EINVAL; + if (!file_priv->descriptors[cmd.handle]) + return -EINVAL; + + retval = decrement_open_device_count(board, &board->device_list, + file_priv->descriptors[cmd.handle]->pad, + file_priv->descriptors[cmd.handle]->sad); + if (retval < 0) + return retval; + + kfree(file_priv->descriptors[cmd.handle]); + file_priv->descriptors[cmd.handle] = NULL; + + return 0; +} + +static int serial_poll_ioctl(gpib_board_t *board, unsigned long arg) +{ + serial_poll_ioctl_t serial_cmd; + int retval; + + dev_dbg(board->gpib_dev, "pid %i, entering %s()\n", current->pid, __func__); + + retval = copy_from_user(&serial_cmd, (void *)arg, sizeof(serial_cmd)); + if (retval) + return -EFAULT; + + retval = get_serial_poll_byte(board, serial_cmd.pad, serial_cmd.sad, board->usec_timeout, + &serial_cmd.status_byte); + if (retval < 0) + return retval; + + retval = copy_to_user((void *)arg, &serial_cmd, sizeof(serial_cmd)); + if (retval) + return -EFAULT; + + return 0; +} + +static int wait_ioctl(gpib_file_private_t *file_priv, gpib_board_t *board, + unsigned long arg) +{ + wait_ioctl_t wait_cmd; + int retval; + gpib_descriptor_t *desc; + + retval = copy_from_user(&wait_cmd, (void *)arg, sizeof(wait_cmd)); + if (retval) + return -EFAULT; + + desc = handle_to_descriptor(file_priv, wait_cmd.handle); + if (!desc) + return -EINVAL; + + retval = ibwait(board, wait_cmd.wait_mask, wait_cmd.clear_mask, + wait_cmd.set_mask, &wait_cmd.ibsta, wait_cmd.usec_timeout, desc); + if (retval < 0) + return retval; + + retval = copy_to_user((void *)arg, &wait_cmd, sizeof(wait_cmd)); + if (retval) + return -EFAULT; + + return 0; +} + +static int parallel_poll_ioctl(gpib_board_t *board, unsigned long arg) +{ + u8 poll_byte; + int retval; + + retval = ibrpp(board, &poll_byte); + if (retval < 0) + return retval; + + retval = copy_to_user((void *)arg, &poll_byte, sizeof(poll_byte)); + if (retval) + return -EFAULT; + + return 0; +} + +static int online_ioctl(gpib_board_t *board, unsigned long arg) +{ + online_ioctl_t online_cmd; + int retval; + void *init_data = NULL; + + board->config.init_data = NULL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + retval = copy_from_user(&online_cmd, (void *)arg, sizeof(online_cmd)); + if (retval) + return -EFAULT; + if (online_cmd.init_data_length > 0) { + board->config.init_data = vmalloc(online_cmd.init_data_length); + if (!board->config.init_data) + return -ENOMEM; + if (WARN_ON_ONCE(sizeof(init_data) > sizeof(online_cmd.init_data_ptr))) + return -EFAULT; + init_data = (void *)(unsigned long)(online_cmd.init_data_ptr); + retval = copy_from_user(board->config.init_data, init_data, + online_cmd.init_data_length); + if (retval) { + vfree(board->config.init_data); + return -EFAULT; + } + board->config.init_data_length = online_cmd.init_data_length; + } else { + board->config.init_data = NULL; + board->config.init_data_length = 0; + } + if (online_cmd.online) + retval = ibonline(board); + else + retval = iboffline(board); + if (board->config.init_data) { + vfree(board->config.init_data); + board->config.init_data = NULL; + board->config.init_data_length = 0; + } + return retval; +} + +static int remote_enable_ioctl(gpib_board_t *board, unsigned long arg) +{ + int enable; + int retval; + + retval = copy_from_user(&enable, (void *)arg, sizeof(enable)); + if (retval) + return -EFAULT; + + return ibsre(board, enable); +} + +static int take_control_ioctl(gpib_board_t *board, unsigned long arg) +{ + int synchronous; + int retval; + + retval = copy_from_user(&synchronous, (void *)arg, sizeof(synchronous)); + if (retval) + return -EFAULT; + + return ibcac(board, synchronous, 1); +} + +static int line_status_ioctl(gpib_board_t *board, unsigned long arg) +{ + short lines; + int retval; + + retval = iblines(board, &lines); + if (retval < 0) + return retval; + + retval = copy_to_user((void *)arg, &lines, sizeof(lines)); + if (retval) + return -EFAULT; + + return 0; +} + +static int pad_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv, + unsigned long arg) +{ + pad_ioctl_t cmd; + int retval; + gpib_descriptor_t *desc; + + retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd)); + if (retval) + return -EFAULT; + + desc = handle_to_descriptor(file_priv, cmd.handle); + if (!desc) + return -EINVAL; + + if (desc->is_board) { + retval = ibpad(board, cmd.pad); + if (retval < 0) + return retval; + } else { + retval = decrement_open_device_count(board, &board->device_list, desc->pad, + desc->sad); + if (retval < 0) + return retval; + + desc->pad = cmd.pad; + + retval = increment_open_device_count(board, &board->device_list, desc->pad, + desc->sad); + if (retval < 0) + return retval; + } + + return 0; +} + +static int sad_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv, + unsigned long arg) +{ + sad_ioctl_t cmd; + int retval; + gpib_descriptor_t *desc; + + retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd)); + if (retval) + return -EFAULT; + + desc = handle_to_descriptor(file_priv, cmd.handle); + if (!desc) + return -EINVAL; + + if (desc->is_board) { + retval = ibsad(board, cmd.sad); + if (retval < 0) + return retval; + } else { + retval = decrement_open_device_count(board, &board->device_list, desc->pad, + desc->sad); + if (retval < 0) + return retval; + + desc->sad = cmd.sad; + + retval = increment_open_device_count(board, &board->device_list, desc->pad, + desc->sad); + if (retval < 0) + return retval; + } + return 0; +} + +static int eos_ioctl(gpib_board_t *board, unsigned long arg) +{ + eos_ioctl_t eos_cmd; + int retval; + + retval = copy_from_user(&eos_cmd, (void *)arg, sizeof(eos_cmd)); + if (retval) + return -EFAULT; + + return ibeos(board, eos_cmd.eos, eos_cmd.eos_flags); +} + +static int request_service_ioctl(gpib_board_t *board, unsigned long arg) +{ + u8 status_byte; + int retval; + + retval = copy_from_user(&status_byte, (void *)arg, sizeof(status_byte)); + if (retval) + return -EFAULT; + + return ibrsv2(board, status_byte, status_byte & request_service_bit); +} + +static int request_service2_ioctl(gpib_board_t *board, unsigned long arg) +{ + request_service2_t request_service2_cmd; + int retval; + + retval = copy_from_user(&request_service2_cmd, (void *)arg, sizeof(request_service2_t)); + if (retval) + return -EFAULT; + + return ibrsv2(board, request_service2_cmd.status_byte, + request_service2_cmd.new_reason_for_service); +} + +static int iobase_ioctl(gpib_board_config_t *config, unsigned long arg) +{ + u64 base_addr; + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + retval = copy_from_user(&base_addr, (void *)arg, sizeof(base_addr)); + if (retval) + return -EFAULT; + + if (WARN_ON_ONCE(sizeof(void *) > sizeof(base_addr))) + return -EFAULT; + config->ibbase = (void *)(unsigned long)(base_addr); + + return 0; +} + +static int irq_ioctl(gpib_board_config_t *config, unsigned long arg) +{ + unsigned int irq; + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + retval = copy_from_user(&irq, (void *)arg, sizeof(irq)); + if (retval) + return -EFAULT; + + config->ibirq = irq; + + return 0; +} + +static int dma_ioctl(gpib_board_config_t *config, unsigned long arg) +{ + unsigned int dma_channel; + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + retval = copy_from_user(&dma_channel, (void *)arg, sizeof(dma_channel)); + if (retval) + return -EFAULT; + + config->ibdma = dma_channel; + + return 0; +} + +static int autospoll_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv, + unsigned long arg) +{ + autospoll_ioctl_t enable; + int retval; + gpib_descriptor_t *desc; + + retval = copy_from_user(&enable, (void *)arg, sizeof(enable)); + if (retval) + return -EFAULT; + + desc = handle_to_descriptor(file_priv, 0); /* board handle is 0 */ + + if (enable) { + if (!desc->autopoll_enabled) { + board->autospollers++; + desc->autopoll_enabled = 1; + } + retval = 0; + } else { + if (desc->autopoll_enabled) { + desc->autopoll_enabled = 0; + if (board->autospollers > 0) { + board->autospollers--; + retval = 0; + } else { + pr_err("gpib: tried to set number of autospollers negative\n"); + retval = -EINVAL; + } + } else { + pr_err("gpib: autopoll disable requested before enable\n"); + retval = -EINVAL; + } + } + return retval; +} + +static int mutex_ioctl(gpib_board_t *board, gpib_file_private_t *file_priv, + unsigned long arg) +{ + int retval, lock_mutex; + + retval = copy_from_user(&lock_mutex, (void *)arg, sizeof(lock_mutex)); + if (retval) + return -EFAULT; + + if (lock_mutex) { + retval = mutex_lock_interruptible(&board->user_mutex); + if (retval) { + pr_warn("gpib: ioctl interrupted while waiting on lock\n"); + return -ERESTARTSYS; + } + + spin_lock(&board->locking_pid_spinlock); + board->locking_pid = current->pid; + spin_unlock(&board->locking_pid_spinlock); + + atomic_set(&file_priv->holding_mutex, 1); + + dev_dbg(board->gpib_dev, "pid %i, locked board %d mutex\n", + current->pid, board->minor); + } else { + spin_lock(&board->locking_pid_spinlock); + if (current->pid != board->locking_pid) { + pr_err("gpib: bug! pid %i tried to release mutex held by pid %i\n", + current->pid, board->locking_pid); + spin_unlock(&board->locking_pid_spinlock); + return -EPERM; + } + board->locking_pid = 0; + spin_unlock(&board->locking_pid_spinlock); + + atomic_set(&file_priv->holding_mutex, 0); + + mutex_unlock(&board->user_mutex); + dev_dbg(board->gpib_dev, "pid %i, unlocked board %i mutex\n", + current->pid, board->minor); + } + return 0; +} + +static int timeout_ioctl(gpib_board_t *board, unsigned long arg) +{ + unsigned int timeout; + int retval; + + retval = copy_from_user(&timeout, (void *)arg, sizeof(timeout)); + if (retval) + return -EFAULT; + + board->usec_timeout = timeout; + dev_dbg(board->gpib_dev, "pid %i, timeout set to %i usec\n", current->pid, timeout); + + return 0; +} + +static int ppc_ioctl(gpib_board_t *board, unsigned long arg) +{ + ppoll_config_ioctl_t cmd; + int retval; + + retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd)); + if (retval) + return -EFAULT; + + if (cmd.set_ist) { + board->ist = 1; + board->interface->parallel_poll_response(board, board->ist); + } else if (cmd.clear_ist) { + board->ist = 0; + board->interface->parallel_poll_response(board, board->ist); + } + + if (cmd.config) { + retval = ibppc(board, cmd.config); + if (retval < 0) + return retval; + } + + return 0; +} + +static int set_local_ppoll_mode_ioctl(gpib_board_t *board, unsigned long arg) +{ + local_ppoll_mode_ioctl_t cmd; + int retval; + + retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd)); + if (retval) + return -EFAULT; + + if (!board->interface->local_parallel_poll_mode) { + pr_warn("gpib: local/remote parallel poll mode not supported by driver."); + return -EIO; + } + board->local_ppoll_mode = cmd != 0; + board->interface->local_parallel_poll_mode(board, board->local_ppoll_mode); + + return 0; +} + +static int get_local_ppoll_mode_ioctl(gpib_board_t *board, unsigned long arg) +{ + local_ppoll_mode_ioctl_t cmd; + int retval; + + cmd = board->local_ppoll_mode; + retval = copy_to_user((void *)arg, &cmd, sizeof(cmd)); + if (retval) + return -EFAULT; + + return 0; +} + +static int query_board_rsv_ioctl(gpib_board_t *board, unsigned long arg) +{ + int status; + int retval; + + status = board->interface->serial_poll_status(board); + + retval = copy_to_user((void *)arg, &status, sizeof(status)); + if (retval) + return -EFAULT; + + return 0; +} + +static int board_info_ioctl(const gpib_board_t *board, unsigned long arg) +{ + board_info_ioctl_t info; + int retval; + + info.pad = board->pad; + info.sad = board->sad; + info.parallel_poll_configuration = board->parallel_poll_configuration; + info.is_system_controller = board->master; + if (board->autospollers) + info.autopolling = 1; + else + info.autopolling = 0; + info.t1_delay = board->t1_nano_sec; + info.ist = board->ist; + info.no_7_bit_eos = board->interface->no_7_bit_eos; + retval = copy_to_user((void *)arg, &info, sizeof(info)); + if (retval) + return -EFAULT; + + return 0; +} + +static int interface_clear_ioctl(gpib_board_t *board, unsigned long arg) +{ + unsigned int usec_duration; + int retval; + + retval = copy_from_user(&usec_duration, (void *)arg, sizeof(usec_duration)); + if (retval) + return -EFAULT; + + return ibsic(board, usec_duration); +} + +static int select_pci_ioctl(gpib_board_config_t *config, unsigned long arg) +{ + select_pci_ioctl_t selection; + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + retval = copy_from_user(&selection, (void *)arg, sizeof(selection)); + if (retval) + return -EFAULT; + + config->pci_bus = selection.pci_bus; + config->pci_slot = selection.pci_slot; + + return 0; +} + +static int select_device_path_ioctl(gpib_board_config_t *config, unsigned long arg) +{ + select_device_path_ioctl_t *selection; + int retval; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + selection = vmalloc(sizeof(select_device_path_ioctl_t)); + if (!selection) + return -ENOMEM; + + retval = copy_from_user(selection, (void *)arg, sizeof(select_device_path_ioctl_t)); + if (retval) { + vfree(selection); + return -EFAULT; + } + + selection->device_path[sizeof(selection->device_path) - 1] = '\0'; + kfree(config->device_path); + config->device_path = NULL; + if (strlen(selection->device_path) > 0) + config->device_path = kstrdup(selection->device_path, GFP_KERNEL); + + vfree(selection); + return 0; +} + +unsigned int num_gpib_events(const gpib_event_queue_t *queue) +{ + return queue->num_events; +} + +static int push_gpib_event_nolock(gpib_board_t *board, short event_type) +{ + gpib_event_queue_t *queue = &board->event_queue; + struct list_head *head = &queue->event_head; + gpib_event_t *event; + static const unsigned int max_num_events = 1024; + int retval; + + if (num_gpib_events(queue) >= max_num_events) { + short lost_event; + + queue->dropped_event = 1; + retval = pop_gpib_event_nolock(board, queue, &lost_event); + if (retval < 0) + return retval; + } + + event = kmalloc(sizeof(gpib_event_t), GFP_ATOMIC); + if (!event) { + queue->dropped_event = 1; + pr_err("gpib: failed to allocate memory for event\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&event->list); + event->event_type = event_type; + + list_add_tail(&event->list, head); + + queue->num_events++; + + dev_dbg(board->gpib_dev, "pushed event %i, %i in queue\n", + (int)event_type, num_gpib_events(queue)); + + return 0; +} + +// push event onto back of event queue +int push_gpib_event(gpib_board_t *board, short event_type) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&board->event_queue.lock, flags); + retval = push_gpib_event_nolock(board, event_type); + spin_unlock_irqrestore(&board->event_queue.lock, flags); + + if (event_type == EventDevTrg) + board->status |= DTAS; + if (event_type == EventDevClr) + board->status |= DCAS; + + return retval; +} +EXPORT_SYMBOL(push_gpib_event); + +static int pop_gpib_event_nolock(gpib_board_t *board, gpib_event_queue_t *queue, short *event_type) +{ + struct list_head *head = &queue->event_head; + struct list_head *front = head->next; + gpib_event_t *event; + + if (num_gpib_events(queue) == 0) { + *event_type = EventNone; + return 0; + } + + if (front == head) + return -EIO; + + if (queue->dropped_event) { + queue->dropped_event = 0; + return -EPIPE; + } + + event = list_entry(front, gpib_event_t, list); + *event_type = event->event_type; + + list_del(front); + kfree(event); + + queue->num_events--; + + dev_dbg(board->gpib_dev, "popped event %i, %i in queue\n", + (int)*event_type, num_gpib_events(queue)); + + return 0; +} + +// pop event from front of event queue +int pop_gpib_event(gpib_board_t *board, gpib_event_queue_t *queue, short *event_type) +{ + unsigned long flags; + int retval; + + spin_lock_irqsave(&queue->lock, flags); + retval = pop_gpib_event_nolock(board, queue, event_type); + spin_unlock_irqrestore(&queue->lock, flags); + return retval; +} + +static int event_ioctl(gpib_board_t *board, unsigned long arg) +{ + event_ioctl_t user_event; + int retval; + short event; + + retval = pop_gpib_event(board, &board->event_queue, &event); + if (retval < 0) + return retval; + + user_event = event; + + retval = copy_to_user((void *)arg, &user_event, sizeof(user_event)); + if (retval) + return -EFAULT; + + return 0; +} + +static int request_system_control_ioctl(gpib_board_t *board, unsigned long arg) +{ + rsc_ioctl_t request_control; + int retval; + + retval = copy_from_user(&request_control, (void *)arg, sizeof(request_control)); + if (retval) + return -EFAULT; + + ibrsc(board, request_control); + + return 0; +} + +static int t1_delay_ioctl(gpib_board_t *board, unsigned long arg) +{ + t1_delay_ioctl_t cmd; + unsigned int delay; + int retval; + + if (!board->interface->t1_delay) { + pr_warn("gpib: t1 delay not implemented in driver!\n"); + return -EIO; + } + + retval = copy_from_user(&cmd, (void *)arg, sizeof(cmd)); + if (retval) + return -EFAULT; + + delay = cmd; + + board->t1_nano_sec = board->interface->t1_delay(board, delay); + + return 0; +} + +const struct file_operations ib_fops = { +owner: THIS_MODULE, +llseek : NULL, +unlocked_ioctl : &ibioctl, +compat_ioctl : &ibioctl, +open : &ibopen, +release : &ibclose, +}; + +gpib_board_t board_array[GPIB_MAX_NUM_BOARDS]; + +LIST_HEAD(registered_drivers); + +void init_gpib_descriptor(gpib_descriptor_t *desc) +{ + desc->pad = 0; + desc->sad = -1; + desc->is_board = 0; + desc->autopoll_enabled = 0; + atomic_set(&desc->io_in_progress, 0); +} + +void gpib_register_driver(gpib_interface_t *interface, struct module *provider_module) +{ + struct gpib_interface_list_struct *entry; + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return; + + entry->interface = interface; + entry->module = provider_module; + list_add(&entry->list, ®istered_drivers); + pr_info("gpib: registered %s interface\n", interface->name); +} +EXPORT_SYMBOL(gpib_register_driver); + +void gpib_unregister_driver(gpib_interface_t *interface) +{ + int i; + struct list_head *list_ptr; + + for (i = 0; i < GPIB_MAX_NUM_BOARDS; i++) { + gpib_board_t *board = &board_array[i]; + + if (board->interface == interface) { + if (board->use_count > 0) + pr_warn("gpib: Warning: deregistered interface %s in use\n", + interface->name); + iboffline(board); + board->interface = NULL; + } + } + for (list_ptr = registered_drivers.next; list_ptr != ®istered_drivers;) { + gpib_interface_list_t *entry; + + entry = list_entry(list_ptr, gpib_interface_list_t, list); + list_ptr = list_ptr->next; + if (entry->interface == interface) { + list_del(&entry->list); + kfree(entry); + } + } + pr_info("gpib: unregistered %s interface\n", interface->name); +} +EXPORT_SYMBOL(gpib_unregister_driver); + +static void init_gpib_board_config(gpib_board_config_t *config) +{ + memset(config, 0, sizeof(gpib_board_config_t)); + config->pci_bus = -1; + config->pci_slot = -1; +} + +void init_gpib_board(gpib_board_t *board) +{ + board->interface = NULL; + board->provider_module = NULL; + board->buffer = NULL; + board->buffer_length = 0; + board->status = 0; + init_waitqueue_head(&board->wait); + mutex_init(&board->user_mutex); + mutex_init(&board->big_gpib_mutex); + board->locking_pid = 0; + spin_lock_init(&board->locking_pid_spinlock); + spin_lock_init(&board->spinlock); + timer_setup(&board->timer, NULL, 0); + board->dev = NULL; + board->gpib_dev = NULL; + init_gpib_board_config(&board->config); + board->private_data = NULL; + board->use_count = 0; + INIT_LIST_HEAD(&board->device_list); + board->pad = 0; + board->sad = -1; + board->usec_timeout = 3000000; + board->parallel_poll_configuration = 0; + board->online = 0; + board->autospollers = 0; + board->autospoll_task = NULL; + init_event_queue(&board->event_queue); + board->minor = -1; + init_gpib_pseudo_irq(&board->pseudo_irq); + board->master = 1; + atomic_set(&board->stuck_srq, 0); + board->local_ppoll_mode = 0; +} + +int gpib_allocate_board(gpib_board_t *board) +{ + if (!board->buffer) { + board->buffer_length = 0x4000; + board->buffer = vmalloc(board->buffer_length); + if (!board->buffer) { + board->buffer_length = 0; + return -ENOMEM; + } + } + return 0; +} + +void gpib_deallocate_board(gpib_board_t *board) +{ + short dummy; + + if (board->buffer) { + vfree(board->buffer); + board->buffer = NULL; + board->buffer_length = 0; + } + while (num_gpib_events(&board->event_queue)) + pop_gpib_event(board, &board->event_queue, &dummy); +} + +static void init_board_array(gpib_board_t *board_array, unsigned int length) +{ + int i; + + for (i = 0; i < length; i++) { + init_gpib_board(&board_array[i]); + board_array[i].minor = i; + } +} + +void init_gpib_status_queue(gpib_status_queue_t *device) +{ + INIT_LIST_HEAD(&device->list); + INIT_LIST_HEAD(&device->status_bytes); + device->num_status_bytes = 0; + device->reference_count = 0; + device->dropped_byte = 0; +} + +static struct class *gpib_class; + +static int __init gpib_common_init_module(void) +{ + int i; + + pr_info("Linux-GPIB core driver\n"); + init_board_array(board_array, GPIB_MAX_NUM_BOARDS); + if (register_chrdev(GPIB_CODE, "gpib", &ib_fops)) { + pr_err("gpib: can't get major %d\n", GPIB_CODE); + return -EIO; + } + gpib_class = class_create("gpib_common"); + if (IS_ERR(gpib_class)) { + pr_err("gpib: failed to create gpib class\n"); + unregister_chrdev(GPIB_CODE, "gpib"); + return PTR_ERR(gpib_class); + } + for (i = 0; i < GPIB_MAX_NUM_BOARDS; ++i) + board_array[i].gpib_dev = device_create(gpib_class, 0, + MKDEV(GPIB_CODE, i), NULL, "gpib%i", i); + + return 0; +} + +static void __exit gpib_common_exit_module(void) +{ + int i; + + for (i = 0; i < GPIB_MAX_NUM_BOARDS; ++i) + device_destroy(gpib_class, MKDEV(GPIB_CODE, i)); + + class_destroy(gpib_class); + unregister_chrdev(GPIB_CODE, "gpib"); +} + +int gpib_match_device_path(struct device *dev, const char *device_path_in) +{ + if (device_path_in) { + char *device_path; + + device_path = kobject_get_path(&dev->kobj, GFP_KERNEL); + if (!device_path) { + dev_err(dev, "kobject_get_path returned NULL."); + return 0; + } + if (strcmp(device_path_in, device_path) != 0) { + kfree(device_path); + return 0; + } + kfree(device_path); + } + return 1; +} +EXPORT_SYMBOL(gpib_match_device_path); + +struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned int vendor_id, + unsigned int device_id, struct pci_dev *from) +{ + struct pci_dev *pci_device = from; + + while ((pci_device = pci_get_device(vendor_id, device_id, pci_device))) { + if (config->pci_bus >= 0 && config->pci_bus != pci_device->bus->number) + continue; + if (config->pci_slot >= 0 && config->pci_slot != + PCI_SLOT(pci_device->devfn)) + continue; + if (gpib_match_device_path(&pci_device->dev, config->device_path) == 0) + continue; + return pci_device; + } + return NULL; +} +EXPORT_SYMBOL(gpib_pci_get_device); + +struct pci_dev *gpib_pci_get_subsys(const gpib_board_config_t *config, unsigned int vendor_id, + unsigned int device_id, unsigned int ss_vendor, + unsigned int ss_device, + struct pci_dev *from) +{ + struct pci_dev *pci_device = from; + + while ((pci_device = pci_get_subsys(vendor_id, device_id, + ss_vendor, ss_device, pci_device))) { + if (config->pci_bus >= 0 && config->pci_bus != pci_device->bus->number) + continue; + if (config->pci_slot >= 0 && config->pci_slot != + PCI_SLOT(pci_device->devfn)) + continue; + if (gpib_match_device_path(&pci_device->dev, config->device_path) == 0) + continue; + return pci_device; + } + return NULL; +} +EXPORT_SYMBOL(gpib_pci_get_subsys); + +module_init(gpib_common_init_module); +module_exit(gpib_common_exit_module); + diff --git a/drivers/staging/gpib/common/iblib.c b/drivers/staging/gpib/common/iblib.c new file mode 100644 index 00000000000000..db1911cc1b2638 --- /dev/null +++ b/drivers/staging/gpib/common/iblib.c @@ -0,0 +1,740 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 2001, 2002 by Frank Mori Hess + ***************************************************************************/ + +#include "ibsys.h" +#include +#include +#include + +/* + * IBCAC + * Return to the controller active state from the + * controller standby state, i.e., turn ATN on. Note + * that in order to enter the controller active state + * from the controller idle state, ibsic must be called. + * If sync is non-zero, attempt to take control synchronously. + * If fallback_to_async is non-zero, try to take control asynchronously + * if synchronous attempt fails. + */ +int ibcac(gpib_board_t *board, int sync, int fallback_to_async) +{ + int status = ibstatus(board); + int retval; + + if ((status & CIC) == 0) { + pr_err("gpib: not CIC during %s()\n", __func__); + return -1; + } + + if (status & ATN) + return 0; + + if (sync && (status & LACS) == 0) + /* tcs (take control synchronously) can only possibly work when + * controller is listener. Error code also needs to be -ETIMEDOUT + * or it will giveout without doing fallback. + */ + retval = -ETIMEDOUT; + else + retval = board->interface->take_control(board, sync); + + if (retval < 0 && fallback_to_async) { + if (sync && retval == -ETIMEDOUT) + retval = board->interface->take_control(board, 0); + } + board->interface->update_status(board, 0); + + return retval; +} + +/* After ATN is asserted, it should cause any connected devices + * to start listening for command bytes and leave acceptor idle state. + * So if ATN is asserted and neither NDAC or NRFD are asserted, + * then there are no devices and ibcmd should error out immediately. + * Some gpib hardware sees itself asserting NDAC/NRFD when it + * is controller in charge, in which case this check will + * do nothing useful (but shouldn't cause any harm either). + * Drivers that don't need this check (ni_usb for example) may + * set the skip_check_for_command_acceptors flag in their + * gpib_interface_struct to avoid useless overhead. + */ +static int check_for_command_acceptors(gpib_board_t *board) +{ + int lines; + + if (board->interface->skip_check_for_command_acceptors) + return 0; + if (!board->interface->line_status) + return 0; + + udelay(2); // allow time for devices to respond to ATN if it was just asserted + + lines = board->interface->line_status(board); + if (lines < 0) + return lines; + + if (lines & ValidATN) { + if ((lines & BusATN) == 0) { + pr_err("gpib: ATN not asserted in %s()?", __func__); + return 0; + } + } + + if ((lines & ValidNRFD) && (lines & ValidNDAC)) { + if ((lines & BusNRFD) == 0 && (lines & BusNDAC) == 0) + return -ENOTCONN; + } + + return 0; +} + +/* + * IBCMD + * Write cnt command bytes from buf to the GPIB. The + * command operation terminates only on I/O complete. + * + * NOTE: + * 1. Prior to beginning the command, the interface is + * placed in the controller active state. + * 2. Before calling ibcmd for the first time, ibsic + * must be called to initialize the GPIB and enable + * the interface to leave the controller idle state. + */ +int ibcmd(gpib_board_t *board, uint8_t *buf, size_t length, size_t *bytes_written) +{ + ssize_t ret = 0; + int status; + + *bytes_written = 0; + + status = ibstatus(board); + + if ((status & CIC) == 0) { + pr_err("gpib: cannot send command when not controller-in-charge\n"); + return -EIO; + } + + os_start_timer(board, board->usec_timeout); + + ret = ibcac(board, 1, 1); + if (ret == 0) { + ret = check_for_command_acceptors(board); + if (ret == 0) + ret = board->interface->command(board, buf, length, bytes_written); + } + + os_remove_timer(board); + + if (io_timed_out(board)) + ret = -ETIMEDOUT; + + return ret; +} + +/* + * IBGTS + * Go to the controller standby state from the controller + * active state, i.e., turn ATN off. + */ + +int ibgts(gpib_board_t *board) +{ + int status = ibstatus(board); + int retval; + + if ((status & CIC) == 0) { + pr_err("gpib: not CIC during %s()\n", __func__); + return -1; + } + + retval = board->interface->go_to_standby(board); /* go to standby */ + if (retval < 0) + pr_err("gpib: error while going to standby\n"); + + board->interface->update_status(board, 0); + + return retval; +} + +static int autospoll_wait_should_wake_up(gpib_board_t *board) +{ + int retval; + + mutex_lock(&board->big_gpib_mutex); + + retval = board->master && board->autospollers > 0 && + !atomic_read(&board->stuck_srq) && + test_and_clear_bit(SRQI_NUM, &board->status); + + mutex_unlock(&board->big_gpib_mutex); + return retval; +} + +static int autospoll_thread(void *board_void) +{ + gpib_board_t *board = board_void; + int retval = 0; + + dev_dbg(board->gpib_dev, "entering autospoll thread\n"); + + while (1) { + wait_event_interruptible(board->wait, + kthread_should_stop() || + autospoll_wait_should_wake_up(board)); + dev_dbg(board->gpib_dev, "autospoll wait satisfied\n"); + if (kthread_should_stop()) + break; + + mutex_lock(&board->big_gpib_mutex); + /* make sure we are still good after we have lock */ + if (board->autospollers <= 0 || board->master == 0) { + mutex_unlock(&board->big_gpib_mutex); + continue; + } + mutex_unlock(&board->big_gpib_mutex); + + if (try_module_get(board->provider_module)) { + retval = autopoll_all_devices(board); + module_put(board->provider_module); + } else { + pr_err("gpib%i: %s: try_module_get() failed!\n", board->minor, __func__); + } + if (retval <= 0) { + pr_err("gpib%i: %s: stuck SRQ\n", board->minor, __func__); + + atomic_set(&board->stuck_srq, 1); // XXX could be better + set_bit(SRQI_NUM, &board->status); + } + } + pr_info("gpib%i: exiting autospoll thread\n", board->minor); + return retval; +} + +int ibonline(gpib_board_t *board) +{ + int retval; + + if (board->online) + return -EBUSY; + if (!board->interface) + return -ENODEV; + retval = gpib_allocate_board(board); + if (retval < 0) + return retval; + + board->dev = NULL; + board->local_ppoll_mode = 0; + retval = board->interface->attach(board, &board->config); + if (retval < 0) { + board->interface->detach(board); + pr_err("gpib: interface attach failed\n"); + return retval; + } + /* nios2nommu on 2.6.11 uclinux kernel has weird problems + * with autospoll thread causing huge slowdowns + */ +#ifndef CONFIG_NIOS2 + board->autospoll_task = kthread_run(&autospoll_thread, board, + "gpib%d_autospoll_kthread", board->minor); + retval = IS_ERR(board->autospoll_task); + if (retval) { + pr_err("gpib: failed to create autospoll thread\n"); + board->interface->detach(board); + return retval; + } +#endif + board->online = 1; + dev_dbg(board->gpib_dev, "gpib: board online\n"); + + return 0; +} + +/* XXX need to make sure board is generally not in use (grab board lock?) */ +int iboffline(gpib_board_t *board) +{ + int retval; + + if (board->online == 0) + return 0; + if (!board->interface) + return -ENODEV; + + if (board->autospoll_task && !IS_ERR(board->autospoll_task)) { + retval = kthread_stop(board->autospoll_task); + if (retval) + pr_err("gpib: kthread_stop returned %i\n", retval); + board->autospoll_task = NULL; + } + + board->interface->detach(board); + gpib_deallocate_board(board); + board->online = 0; + dev_dbg(board->gpib_dev, "gpib: board offline\n"); + + return 0; +} + +/* + * IBLINES + * Poll the GPIB control lines and return their status in buf. + * + * LSB (bits 0-7) - VALID lines mask (lines that can be monitored). + * Next LSB (bits 8-15) - STATUS lines mask (lines that are currently set). + * + */ +int iblines(const gpib_board_t *board, short *lines) +{ + int retval; + + *lines = 0; + if (!board->interface->line_status) + return 0; + retval = board->interface->line_status(board); + if (retval < 0) + return retval; + *lines = retval; + return 0; +} + +/* + * IBRD + * Read up to 'length' bytes of data from the GPIB into buf. End + * on detection of END (EOI and or EOS) and set 'end_flag'. + * + * NOTE: + * 1. The interface is placed in the controller standby + * state prior to beginning the read. + * 2. Prior to calling ibrd, the intended devices as well + * as the interface board itself must be addressed by + * calling ibcmd. + */ + +int ibrd(gpib_board_t *board, uint8_t *buf, size_t length, int *end_flag, size_t *nbytes) +{ + ssize_t ret = 0; + int retval; + size_t bytes_read; + + *nbytes = 0; + *end_flag = 0; + if (length == 0) { + pr_warn("gpib: %s() called with zero length?\n", __func__); + return 0; + } + + if (board->master) { + retval = ibgts(board); + if (retval < 0) + return retval; + } + /* XXX resetting timer here could cause timeouts take longer than they should, + * since read_ioctl calls this + * function in a loop, there is probably a similar problem with writes/commands + */ + os_start_timer(board, board->usec_timeout); + + do { + ret = board->interface->read(board, buf, length - *nbytes, end_flag, &bytes_read); + if (ret < 0) { + pr_err("gpib read error\n"); + goto ibrd_out; + } + buf += bytes_read; + *nbytes += bytes_read; + if (need_resched()) + schedule(); + } while (ret == 0 && *nbytes > 0 && *nbytes < length && *end_flag == 0); +ibrd_out: + os_remove_timer(board); + + return ret; +} + +/* + * IBRPP + * Conduct a parallel poll and return the byte in buf. + * + * NOTE: + * 1. Prior to conducting the poll the interface is placed + * in the controller active state. + */ +int ibrpp(gpib_board_t *board, uint8_t *result) +{ + int retval = 0; + + os_start_timer(board, board->usec_timeout); + retval = ibcac(board, 1, 1); + if (retval) + return -1; + + if (board->interface->parallel_poll(board, result)) { + pr_err("gpib: parallel poll failed\n"); + retval = -1; + } + os_remove_timer(board); + return retval; +} + +int ibppc(gpib_board_t *board, uint8_t configuration) +{ + configuration &= 0x1f; + board->interface->parallel_poll_configure(board, configuration); + board->parallel_poll_configuration = configuration; + + return 0; +} + +int ibrsv2(gpib_board_t *board, uint8_t status_byte, int new_reason_for_service) +{ + int board_status = ibstatus(board); + const unsigned int MSS = status_byte & request_service_bit; + + if ((board_status & CIC)) { + pr_err("gpib: interface requested service while CIC\n"); + return -EINVAL; + } + + if (MSS == 0 && new_reason_for_service) + return -EINVAL; + + if (board->interface->serial_poll_response2) { + board->interface->serial_poll_response2(board, status_byte, new_reason_for_service); + // fall back on simpler serial_poll_response if the behavior would be the same + } else if (board->interface->serial_poll_response && + (MSS == 0 || (MSS && new_reason_for_service))) { + board->interface->serial_poll_response(board, status_byte); + } else { + return -EOPNOTSUPP; + } + + return 0; +} + +/* + * IBSIC + * Send IFC for at least 100 microseconds. + * + * NOTE: + * 1. Ibsic must be called prior to the first call to + * ibcmd in order to initialize the bus and enable the + * interface to leave the controller idle state. + */ +int ibsic(gpib_board_t *board, unsigned int usec_duration) +{ + if (board->master == 0) { + pr_err("gpib: tried to assert IFC when not system controller\n"); + return -1; + } + + if (usec_duration < 100) + usec_duration = 100; + if (usec_duration > 1000) { + usec_duration = 1000; + pr_warn("gpib: warning, shortening long udelay\n"); + } + + dev_dbg(board->gpib_dev, "sending interface clear\n"); + board->interface->interface_clear(board, 1); + udelay(usec_duration); + board->interface->interface_clear(board, 0); + + return 0; +} + +void ibrsc(gpib_board_t *board, int request_control) +{ + board->master = request_control != 0; + if (!board->interface->request_system_control) { + pr_err("gpib: bug! driver does not implement request_system_control()\n"); + return; + } + board->interface->request_system_control(board, request_control); +} + +/* + * IBSRE + * Send REN true if v is non-zero or false if v is zero. + */ +int ibsre(gpib_board_t *board, int enable) +{ + if (board->master == 0) { + pr_err("gpib: tried to set REN when not system controller\n"); + return -1; + } + + board->interface->remote_enable(board, enable); /* set or clear REN */ + if (!enable) + usleep_range(100, 150); + + return 0; +} + +/* + * IBPAD + * change the GPIB address of the interface board. The address + * must be 0 through 30. ibonl resets the address to PAD. + */ +int ibpad(gpib_board_t *board, unsigned int addr) +{ + if (addr > MAX_GPIB_PRIMARY_ADDRESS) { + pr_err("gpib: invalid primary address %u\n", addr); + return -1; + } + board->pad = addr; + if (board->online) + board->interface->primary_address(board, board->pad); + dev_dbg(board->gpib_dev, "set primary addr to %i\n", board->pad); + return 0; +} + +/* + * IBSAD + * change the secondary GPIB address of the interface board. + * The address must be 0 through 30, or negative disables. ibonl resets the + * address to SAD. + */ +int ibsad(gpib_board_t *board, int addr) +{ + if (addr > MAX_GPIB_SECONDARY_ADDRESS) { + pr_err("gpib: invalid secondary address %i\n", addr); + return -1; + } + board->sad = addr; + if (board->online) { + if (board->sad >= 0) + board->interface->secondary_address(board, board->sad, 1); + else + board->interface->secondary_address(board, 0, 0); + } + dev_dbg(board->gpib_dev, "set secondary addr to %i\n", board->sad); + + return 0; +} + +/* + * IBEOS + * Set the end-of-string modes for I/O operations to v. + * + */ +int ibeos(gpib_board_t *board, int eos, int eosflags) +{ + int retval; + + if (eosflags & ~EOS_MASK) { + pr_err("bad EOS modes\n"); + return -EINVAL; + } + if (eosflags & REOS) { + retval = board->interface->enable_eos(board, eos, eosflags & BIN); + } else { + board->interface->disable_eos(board); + retval = 0; + } + return retval; +} + +int ibstatus(gpib_board_t *board) +{ + return general_ibstatus(board, NULL, 0, 0, NULL); +} + +int general_ibstatus(gpib_board_t *board, const gpib_status_queue_t *device, + int clear_mask, int set_mask, gpib_descriptor_t *desc) +{ + int status = 0; + short line_status; + + if (board->private_data) { + status = board->interface->update_status(board, clear_mask); + /* XXX should probably stop having drivers use TIMO bit in + * board->status to avoid confusion + */ + status &= ~TIMO; + /* get real SRQI status if we can */ + if (iblines(board, &line_status) == 0) { + if ((line_status & ValidSRQ)) { + if ((line_status & BusSRQ)) + status |= SRQI; + else + status &= ~SRQI; + } + } + } + if (device) + if (num_status_bytes(device)) + status |= RQS; + + if (desc) { + if (set_mask & CMPL) + atomic_set(&desc->io_in_progress, 0); + else if (clear_mask & CMPL) + atomic_set(&desc->io_in_progress, 1); + + if (atomic_read(&desc->io_in_progress)) + status &= ~CMPL; + else + status |= CMPL; + } + if (num_gpib_events(&board->event_queue)) + status |= EVENT; + else + status &= ~EVENT; + + return status; +} + +struct wait_info { + gpib_board_t *board; + struct timer_list timer; + int timed_out; + unsigned long usec_timeout; +}; + +static void wait_timeout(struct timer_list *t) +{ + struct wait_info *winfo = from_timer(winfo, t, timer); + + winfo->timed_out = 1; + wake_up_interruptible(&winfo->board->wait); +} + +static void init_wait_info(struct wait_info *winfo) +{ + winfo->board = NULL; + winfo->timed_out = 0; + timer_setup_on_stack(&winfo->timer, wait_timeout, 0); +} + +static int wait_satisfied(struct wait_info *winfo, gpib_status_queue_t *status_queue, + int wait_mask, int *status, gpib_descriptor_t *desc) +{ + gpib_board_t *board = winfo->board; + int temp_status; + + if (mutex_lock_interruptible(&board->big_gpib_mutex)) + return -ERESTARTSYS; + + temp_status = general_ibstatus(board, status_queue, 0, 0, desc); + + mutex_unlock(&board->big_gpib_mutex); + + if (winfo->timed_out) + temp_status |= TIMO; + else + temp_status &= ~TIMO; + if (wait_mask & temp_status) { + *status = temp_status; + return 1; + } +//XXX does wait for END work? + return 0; +} + +/* install timer interrupt handler */ +static void start_wait_timer(struct wait_info *winfo) +/* Starts the timeout task */ +{ + winfo->timed_out = 0; + + if (winfo->usec_timeout > 0) + mod_timer(&winfo->timer, jiffies + usec_to_jiffies(winfo->usec_timeout)); +} + +static void remove_wait_timer(struct wait_info *winfo) +{ + del_timer_sync(&winfo->timer); + destroy_timer_on_stack(&winfo->timer); +} + +/* + * IBWAIT + * Check or wait for a GPIB event to occur. The mask argument + * is a bit vector corresponding to the status bit vector. It + * has a bit set for each condition which can terminate the wait + * If the mask is 0 then + * no condition is waited for. + */ +int ibwait(gpib_board_t *board, int wait_mask, int clear_mask, int set_mask, + int *status, unsigned long usec_timeout, gpib_descriptor_t *desc) +{ + int retval = 0; + gpib_status_queue_t *status_queue; + struct wait_info winfo; + + if (desc->is_board) + status_queue = NULL; + else + status_queue = get_gpib_status_queue(board, desc->pad, desc->sad); + + if (wait_mask == 0) { + *status = general_ibstatus(board, status_queue, clear_mask, set_mask, desc); + return 0; + } + + mutex_unlock(&board->big_gpib_mutex); + + init_wait_info(&winfo); + winfo.board = board; + winfo.usec_timeout = usec_timeout; + start_wait_timer(&winfo); + + if (wait_event_interruptible(board->wait, wait_satisfied(&winfo, status_queue, + wait_mask, status, desc))) { + dev_dbg(board->gpib_dev, "wait interrupted\n"); + retval = -ERESTARTSYS; + } + remove_wait_timer(&winfo); + + if (retval) + return retval; + if (mutex_lock_interruptible(&board->big_gpib_mutex)) + return -ERESTARTSYS; + + /* make sure we only clear status bits that we are reporting */ + if (*status & clear_mask || set_mask) + general_ibstatus(board, status_queue, *status & clear_mask, set_mask, 0); + + return 0; +} + +/* + * IBWRT + * Write cnt bytes of data from buf to the GPIB. The write + * operation terminates only on I/O complete. + * + * NOTE: + * 1. Prior to beginning the write, the interface is + * placed in the controller standby state. + * 2. Prior to calling ibwrt, the intended devices as + * well as the interface board itself must be + * addressed by calling ibcmd. + */ +int ibwrt(gpib_board_t *board, uint8_t *buf, size_t cnt, int send_eoi, size_t *bytes_written) +{ + int ret = 0; + int retval; + + if (cnt == 0) { + pr_warn("gpib: %s() called with zero length?\n", __func__); + return 0; + } + + if (board->master) { + retval = ibgts(board); + if (retval < 0) + return retval; + } + os_start_timer(board, board->usec_timeout); + ret = board->interface->write(board, buf, cnt, send_eoi, bytes_written); + + if (io_timed_out(board)) + ret = -ETIMEDOUT; + + os_remove_timer(board); + + return ret; +} + diff --git a/drivers/staging/gpib/common/ibsys.h b/drivers/staging/gpib/common/ibsys.h new file mode 100644 index 00000000000000..da20971e9c7ee0 --- /dev/null +++ b/drivers/staging/gpib/common/ibsys.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include "gpibP.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_GPIB_PRIMARY_ADDRESS 30 +#define MAX_GPIB_SECONDARY_ADDRESS 31 + +int gpib_allocate_board(gpib_board_t *board); +void gpib_deallocate_board(gpib_board_t *board); + +unsigned int num_status_bytes(const gpib_status_queue_t *dev); +int push_status_byte(gpib_board_t *board, gpib_status_queue_t *device, uint8_t poll_byte); +int pop_status_byte(gpib_board_t *board, gpib_status_queue_t *device, uint8_t *poll_byte); +gpib_status_queue_t *get_gpib_status_queue(gpib_board_t *board, unsigned int pad, int sad); +int get_serial_poll_byte(gpib_board_t *board, unsigned int pad, int sad, + unsigned int usec_timeout, uint8_t *poll_byte); +int autopoll_all_devices(gpib_board_t *board); diff --git a/drivers/staging/gpib/eastwood/Makefile b/drivers/staging/gpib/eastwood/Makefile new file mode 100644 index 00000000000000..c74056f959d034 --- /dev/null +++ b/drivers/staging/gpib/eastwood/Makefile @@ -0,0 +1,3 @@ + +obj-m += fluke_gpib.o + diff --git a/drivers/staging/gpib/eastwood/fluke_gpib.c b/drivers/staging/gpib/eastwood/fluke_gpib.c new file mode 100644 index 00000000000000..3f938ab0c84d98 --- /dev/null +++ b/drivers/staging/gpib/eastwood/fluke_gpib.c @@ -0,0 +1,1179 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * GPIB Driver for Fluke cda devices. Basically, its a driver for a (bugfixed) + * cb7210 connected to channel 0 of a pl330 dma controller. + * Author: Frank Mori Hess + * copyright: (C) 2006, 2010, 2015 Fluke Corporation + ***************************************************************************/ + +#include "fluke_gpib.h" + +#include "gpibP.h" +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB Driver for Fluke cda devices"); + +static int fluke_attach_holdoff_all(gpib_board_t *board, const gpib_board_config_t *config); +static int fluke_attach_holdoff_end(gpib_board_t *board, const gpib_board_config_t *config); +static void fluke_detach(gpib_board_t *board); +static int fluke_config_dma(gpib_board_t *board, int output); +static irqreturn_t fluke_gpib_internal_interrupt(gpib_board_t *board); + +static struct platform_device *fluke_gpib_pdev; + +static uint8_t fluke_locking_read_byte(struct nec7210_priv *nec_priv, unsigned int register_number) +{ + u8 retval; + unsigned long flags; + + spin_lock_irqsave(&nec_priv->register_page_lock, flags); + retval = fluke_read_byte_nolock(nec_priv, register_number); + spin_unlock_irqrestore(&nec_priv->register_page_lock, flags); + return retval; +} + +static void fluke_locking_write_byte(struct nec7210_priv *nec_priv, uint8_t byte, + unsigned int register_number) +{ + unsigned long flags; + + spin_lock_irqsave(&nec_priv->register_page_lock, flags); + fluke_write_byte_nolock(nec_priv, byte, register_number); + spin_unlock_irqrestore(&nec_priv->register_page_lock, flags); +} + +// wrappers for interface functions +static int fluke_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); +} + +static int fluke_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); +} + +static int fluke_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); +} + +static int fluke_take_control(gpib_board_t *board, int synchronous) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_take_control(board, &priv->nec7210_priv, synchronous); +} + +static int fluke_go_to_standby(gpib_board_t *board) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_go_to_standby(board, &priv->nec7210_priv); +} + +static void fluke_request_system_control(gpib_board_t *board, int request_control) +{ + struct fluke_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + + nec7210_request_system_control(board, nec_priv, request_control); +} + +static void fluke_interface_clear(gpib_board_t *board, int assert) +{ + struct fluke_priv *priv = board->private_data; + + nec7210_interface_clear(board, &priv->nec7210_priv, assert); +} + +static void fluke_remote_enable(gpib_board_t *board, int enable) +{ + struct fluke_priv *priv = board->private_data; + + nec7210_remote_enable(board, &priv->nec7210_priv, enable); +} + +static int fluke_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); +} + +static void fluke_disable_eos(gpib_board_t *board) +{ + struct fluke_priv *priv = board->private_data; + + nec7210_disable_eos(board, &priv->nec7210_priv); +} + +static unsigned int fluke_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_update_status(board, &priv->nec7210_priv, clear_mask); +} + +static int fluke_primary_address(gpib_board_t *board, unsigned int address) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_primary_address(board, &priv->nec7210_priv, address); +} + +static int fluke_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); +} + +static int fluke_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_parallel_poll(board, &priv->nec7210_priv, result); +} + +static void fluke_parallel_poll_configure(gpib_board_t *board, uint8_t configuration) +{ + struct fluke_priv *priv = board->private_data; + + nec7210_parallel_poll_configure(board, &priv->nec7210_priv, configuration); +} + +static void fluke_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct fluke_priv *priv = board->private_data; + + nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); +} + +static void fluke_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + struct fluke_priv *priv = board->private_data; + + nec7210_serial_poll_response(board, &priv->nec7210_priv, status); +} + +static uint8_t fluke_serial_poll_status(gpib_board_t *board) +{ + struct fluke_priv *priv = board->private_data; + + return nec7210_serial_poll_status(board, &priv->nec7210_priv); +} + +static void fluke_return_to_local(gpib_board_t *board) +{ + struct fluke_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + + write_byte(nec_priv, AUX_RTL2, AUXMR); + udelay(1); + write_byte(nec_priv, AUX_RTL, AUXMR); +} + +static int fluke_line_status(const gpib_board_t *board) +{ + int status = ValidALL; + int bsr_bits; + struct fluke_priv *e_priv; + struct nec7210_priv *nec_priv; + + e_priv = board->private_data; + nec_priv = &e_priv->nec7210_priv; + + bsr_bits = fluke_paged_read_byte(e_priv, BUS_STATUS, BUS_STATUS_PAGE); + + if ((bsr_bits & BSR_REN_BIT) == 0) + status |= BusREN; + if ((bsr_bits & BSR_IFC_BIT) == 0) + status |= BusIFC; + if ((bsr_bits & BSR_SRQ_BIT) == 0) + status |= BusSRQ; + if ((bsr_bits & BSR_EOI_BIT) == 0) + status |= BusEOI; + if ((bsr_bits & BSR_NRFD_BIT) == 0) + status |= BusNRFD; + if ((bsr_bits & BSR_NDAC_BIT) == 0) + status |= BusNDAC; + if ((bsr_bits & BSR_DAV_BIT) == 0) + status |= BusDAV; + if ((bsr_bits & BSR_ATN_BIT) == 0) + status |= BusATN; + + return status; +} + +static unsigned int fluke_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned int retval; + + retval = nec7210_t1_delay(board, nec_priv, nano_sec); + + if (nano_sec <= 350) { + write_byte(nec_priv, AUX_HI_SPEED, AUXMR); + retval = 350; + } else { + write_byte(nec_priv, AUX_LO_SPEED, AUXMR); + } + return retval; +} + +static int lacs_or_read_ready(gpib_board_t *board) +{ + const struct fluke_priv *e_priv = board->private_data; + const struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned long flags; + int retval; + + spin_lock_irqsave(&board->spinlock, flags); + retval = test_bit(LACS_NUM, &board->status) || test_bit(READ_READY_BN, &nec_priv->state); + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +/* Wait until it is possible for a read to do something useful. This + * is not essential, it only exists to prevent RFD holdoff from being released pointlessly. + */ +static int wait_for_read(gpib_board_t *board) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; + + if (wait_event_interruptible(board->wait, + lacs_or_read_ready(board) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + return retval; +} + +/* Check if the SH state machine is in SGNS. We check twice since there is a very small chance + * we could be blowing through SGNS from SIDS to SDYS if there is already a + * byte available in the handshake state machine. We are interested + * in the case where the handshake is stuck in SGNS due to no byte being + * available to the chip (and thus we can be confident a dma transfer will + * result in at least one byte making it into the chip). This matters + * because we want to be confident before sending a "send eoi" auxilary + * command that we will be able to also put the associated data byte + * in the chip before any potential timeout. + */ +static int source_handshake_is_sgns(struct fluke_priv *e_priv) +{ + int i; + + for (i = 0; i < 2; ++i) { + if ((fluke_paged_read_byte(e_priv, STATE1_REG, STATE1_PAGE) & + SOURCE_HANDSHAKE_MASK) != SOURCE_HANDSHAKE_SGNS_BITS) { + return 0; + } + } + return 1; +} + +static int source_handshake_is_sids_or_sgns(struct fluke_priv *e_priv) +{ + unsigned int source_handshake_bits; + + source_handshake_bits = fluke_paged_read_byte(e_priv, STATE1_REG, STATE1_PAGE) & + SOURCE_HANDSHAKE_MASK; + + return (source_handshake_bits == SOURCE_HANDSHAKE_SGNS_BITS) || + (source_handshake_bits == SOURCE_HANDSHAKE_SIDS_BITS); +} + +/* Wait until the gpib chip is ready to accept a data out byte. + * If the chip is SGNS it is probably waiting for a a byte to + * be written to it. + */ +static int wait_for_data_out_ready(gpib_board_t *board) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; +// printk("%s: enter\n", __FUNCTION__); + + if (wait_event_interruptible(board->wait, + (test_bit(TACS_NUM, &board->status) && + source_handshake_is_sgns(e_priv)) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; +// printk("%s: exit, retval=%i\n", __FUNCTION__, retval); + return retval; +} + +static int wait_for_sids_or_sgns(gpib_board_t *board) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; +// printk("%s: enter\n", __FUNCTION__); + + if (wait_event_interruptible(board->wait, + source_handshake_is_sids_or_sgns(e_priv) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) + retval = -ERESTARTSYS; + + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; +// printk("%s: exit, retval=%i\n", __FUNCTION__, retval); + return retval; +} + +static void fluke_dma_callback(void *arg) +{ + gpib_board_t *board = arg; + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); +// printk("%s: enter\n", __FUNCTION__); + + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE | HR_DIIE, HR_DOIE | HR_DIIE); + wake_up_interruptible(&board->wait); + + fluke_gpib_internal_interrupt(board); + clear_bit(DMA_WRITE_IN_PROGRESS_BN, &nec_priv->state); + clear_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state); +// printk("%s: exit\n", __FUNCTION__); + spin_unlock_irqrestore(&board->spinlock, flags); +} + +static int fluke_dma_write(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned long flags; + int retval = 0; + dma_addr_t address; + struct dma_async_tx_descriptor *tx_desc; + + *bytes_written = 0; +// printk("%s: enter\n", __FUNCTION__); + if (WARN_ON_ONCE(length > e_priv->dma_buffer_size)) + return -EFAULT; + dmaengine_terminate_all(e_priv->dma_channel); + // write-clear counter + writel(0x0, e_priv->write_transfer_counter); + + memcpy(e_priv->dma_buffer, buffer, length); + address = dma_map_single(board->dev, e_priv->dma_buffer, + length, DMA_TO_DEVICE); + /* program dma controller */ + retval = fluke_config_dma(board, 1); + if (retval) + goto cleanup; + + tx_desc = dmaengine_prep_slave_single(e_priv->dma_channel, address, length, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx_desc) { + pr_err("fluke_gpib: failed to allocate dma transmit descriptor\n"); + retval = -ENOMEM; + goto cleanup; + } + tx_desc->callback = fluke_dma_callback; + tx_desc->callback_param = board; + + spin_lock_irqsave(&board->spinlock, flags); + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, HR_DMAO); + dmaengine_submit(tx_desc); + dma_async_issue_pending(e_priv->dma_channel); + + clear_bit(WRITE_READY_BN, &nec_priv->state); + set_bit(DMA_WRITE_IN_PROGRESS_BN, &nec_priv->state); + + // printk("%s: in spin lock\n", __FUNCTION__); + spin_unlock_irqrestore(&board->spinlock, flags); + +// printk("%s: waiting for write.\n", __FUNCTION__); + // suspend until message is sent + if (wait_event_interruptible(board->wait, + ((readl(e_priv->write_transfer_counter) & + write_transfer_counter_mask) == length) || + test_bit(BUS_ERROR_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib write interrupted!\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + if (test_and_clear_bit(BUS_ERROR_BN, &nec_priv->state)) + retval = -EIO; + // disable board's dma + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0); + + dmaengine_terminate_all(e_priv->dma_channel); + // make sure fluke_dma_callback got called + if (test_bit(DMA_WRITE_IN_PROGRESS_BN, &nec_priv->state)) + fluke_dma_callback(board); + + /* if everything went fine, try to wait until last byte is actually + * transmitted across gpib (but don't try _too_ hard) + */ + if (retval == 0) + retval = wait_for_sids_or_sgns(board); + + *bytes_written = readl(e_priv->write_transfer_counter) & write_transfer_counter_mask; + if (WARN_ON_ONCE(*bytes_written > length)) + return -EFAULT; + +cleanup: + dma_unmap_single(board->dev, address, length, DMA_TO_DEVICE); +// printk("%s: exit, retval=%d\n", __FUNCTION__, retval); + return retval; +} + +static int fluke_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + size_t remainder = length; + size_t transfer_size; + ssize_t retval = 0; + size_t dma_remainder = remainder; + + if (!e_priv->dma_channel) { + pr_err("fluke_gpib: No dma channel available, cannot do accel write."); + return -ENXIO; + } + + *bytes_written = 0; + if (length < 1) + return 0; + + clear_bit(DEV_CLEAR_BN, &nec_priv->state); // XXX FIXME + + if (send_eoi) + --dma_remainder; +// printk("%s: entering while loop\n", __FUNCTION__); + + while (dma_remainder > 0) { + size_t num_bytes; + + retval = wait_for_data_out_ready(board); + if (retval < 0) + break; + + transfer_size = (e_priv->dma_buffer_size < dma_remainder) ? + e_priv->dma_buffer_size : dma_remainder; + retval = fluke_dma_write(board, buffer, transfer_size, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + break; + dma_remainder -= num_bytes; + remainder -= num_bytes; + buffer += num_bytes; + if (need_resched()) + schedule(); + } + if (retval < 0) + return retval; + //handle sending of last byte with eoi + if (send_eoi) { + size_t num_bytes; + // printk("%s: handling last byte\n", __FUNCTION__); + if (WARN_ON_ONCE(remainder != 1)) + return -EFAULT; + + /* wait until we are sure we will be able to write the data byte + * into the chip before we send AUX_SEOI. This prevents a timeout + * scenerio where we send AUX_SEOI but then timeout without getting + * any bytes into the gpib chip. This will result in the first byte + * of the next write having a spurious EOI set on the first byte. + */ + retval = wait_for_data_out_ready(board); + if (retval < 0) + return retval; + + write_byte(nec_priv, AUX_SEOI, AUXMR); + retval = fluke_dma_write(board, buffer, remainder, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + return retval; + remainder -= num_bytes; + } +// printk("%s: bytes send=%i\n", __FUNCTION__, (int)(length - remainder)); + return 0; +} + +static int fluke_get_dma_residue(struct dma_chan *chan, dma_cookie_t cookie) +{ + struct dma_tx_state state; + int result; + + result = dmaengine_pause(chan); + if (result < 0) { + pr_err("fluke_gpib: dma pause failed?\n"); + return result; + } + dmaengine_tx_status(chan, cookie, &state); + // hardware doesn't support resume, so dont call this + // method unless the dma transfer is done. + return state.residue; +} + +static int fluke_dma_read(gpib_board_t *board, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; + unsigned long flags; + int residue; + dma_addr_t bus_address; + struct dma_async_tx_descriptor *tx_desc; + dma_cookie_t dma_cookie; + int i; + static const int timeout = 10; + + // printk("%s: enter, bus_address=0x%x, length=%i\n", __FUNCTION__, + // (unsigned)bus_address, + // (int)length); + + *bytes_read = 0; + *end = 0; + if (length == 0) + return 0; + + bus_address = dma_map_single(board->dev, e_priv->dma_buffer, + length, DMA_FROM_DEVICE); + + /* program dma controller */ + retval = fluke_config_dma(board, 0); + if (retval) { + dma_unmap_single(board->dev, bus_address, length, DMA_FROM_DEVICE); + return retval; + } + tx_desc = dmaengine_prep_slave_single(e_priv->dma_channel, + bus_address, length, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx_desc) { + pr_err("fluke_gpib: failed to allocate dma transmit descriptor\n"); + dma_unmap_single(NULL, bus_address, length, DMA_FROM_DEVICE); + return -EIO; + } + tx_desc->callback = fluke_dma_callback; + tx_desc->callback_param = board; + + spin_lock_irqsave(&board->spinlock, flags); + // enable nec7210 dma + nec7210_set_reg_bits(nec_priv, IMR1, HR_DIIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, HR_DMAI); + + dma_cookie = dmaengine_submit(tx_desc); + dma_async_issue_pending(e_priv->dma_channel); + + set_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state); + clear_bit(READ_READY_BN, &nec_priv->state); + + spin_unlock_irqrestore(&board->spinlock, flags); +// printk("waiting for data transfer.\n"); + // wait for data to transfer + if (wait_event_interruptible(board->wait, + test_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state) == 0 || + test_bit(RECEIVED_END_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_warn("fluke: dma read wait interrupted\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + + /* If we woke up because of end, wait until the dma transfer has pulled + * the data byte associated with the end before we cancel the dma transfer. + */ + if (test_bit(RECEIVED_END_BN, &nec_priv->state)) { + for (i = 0; i < timeout; ++i) { + if (test_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state) == 0) + break; + if ((read_byte(nec_priv, ADR0) & DATA_IN_STATUS) == 0) + break; + usleep_range(10, 15); + } + if (i == timeout) + pr_warn("fluke_gpib: timeout waiting for dma to transfer end data byte.\n"); + } + + // stop the dma transfer + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + /* delay a little just to make sure any bytes in dma controller's fifo get + * written to memory before we disable it + */ + usleep_range(10, 15); + residue = fluke_get_dma_residue(e_priv->dma_channel, dma_cookie); + if (WARN_ON_ONCE(residue > length || residue < 0)) + return -EFAULT; + *bytes_read += length - residue; + dmaengine_terminate_all(e_priv->dma_channel); + // make sure fluke_dma_callback got called + if (test_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state)) + fluke_dma_callback(board); + + dma_unmap_single(board->dev, bus_address, length, DMA_FROM_DEVICE); + memcpy(buffer, e_priv->dma_buffer, *bytes_read); + + /* If we got an end interrupt, figure out if it was + * associated with the last byte we dma'd or with a + * byte still sitting on the cb7210. + */ + spin_lock_irqsave(&board->spinlock, flags); + if (test_bit(READ_READY_BN, &nec_priv->state) == 0) { + // There is no byte sitting on the cb7210. If we + // saw an end interrupt, we need to deal with it now + if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state)) + *end = 1; + } + spin_unlock_irqrestore(&board->spinlock, flags); + + return retval; +} + +static int fluke_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + size_t remain = length; + size_t transfer_size; + int retval = 0; + size_t dma_nbytes; + +/* printk("%s: enter, buffer=0x%p, length=%i\n", __FUNCTION__, + * buffer, (int)length); + * printk("\t dma_buffer=0x%p\n", e_priv->dma_buffer); + */ + *end = 0; + *bytes_read = 0; + + smp_mb__before_atomic(); + clear_bit(DEV_CLEAR_BN, &nec_priv->state); // XXX FIXME + smp_mb__after_atomic(); + + retval = wait_for_read(board); + if (retval < 0) + return retval; + + nec7210_release_rfd_holdoff(board, nec_priv); + +// printk("%s: entering while loop\n", __FUNCTION__); + while (remain > 0) { + transfer_size = (e_priv->dma_buffer_size < remain) ? + e_priv->dma_buffer_size : remain; + retval = fluke_dma_read(board, buffer, transfer_size, end, &dma_nbytes); + remain -= dma_nbytes; + buffer += dma_nbytes; + *bytes_read += dma_nbytes; + if (*end) + break; + if (retval < 0) { +// printk("%s: early exit, retval=%i\n", __FUNCTION__, (int)retval); + return retval; + } + if (need_resched()) + schedule(); + } +// printk("%s: exit, retval=%i\n", __FUNCTION__, (int)retval); + return retval; +} + +gpib_interface_t fluke_unaccel_interface = { +name: "fluke_unaccel", +attach : fluke_attach_holdoff_all, +detach : fluke_detach, +read : fluke_read, +write : fluke_write, +command : fluke_command, +take_control : fluke_take_control, +go_to_standby : fluke_go_to_standby, +request_system_control : fluke_request_system_control, +interface_clear : fluke_interface_clear, +remote_enable : fluke_remote_enable, +enable_eos : fluke_enable_eos, +disable_eos : fluke_disable_eos, +parallel_poll : fluke_parallel_poll, +parallel_poll_configure : fluke_parallel_poll_configure, +parallel_poll_response : fluke_parallel_poll_response, +line_status : fluke_line_status, +update_status : fluke_update_status, +primary_address : fluke_primary_address, +secondary_address : fluke_secondary_address, +serial_poll_response : fluke_serial_poll_response, +serial_poll_status : fluke_serial_poll_status, +t1_delay : fluke_t1_delay, +return_to_local : fluke_return_to_local, +}; + +/* fluke_hybrid uses dma for writes but not for reads. Added + * to deal with occasional corruption of bytes seen when doing dma + * reads. From looking at the cb7210 vhdl, I believe the corruption + * is due to a hardware bug triggered by the cpu reading a cb7210 + * } + * register just as the dma controller is also doing a read. + */ + +gpib_interface_t fluke_hybrid_interface = { +name: "fluke_hybrid", +attach : fluke_attach_holdoff_all, +detach : fluke_detach, +read : fluke_read, +write : fluke_accel_write, +command : fluke_command, +take_control : fluke_take_control, +go_to_standby : fluke_go_to_standby, +request_system_control : fluke_request_system_control, +interface_clear : fluke_interface_clear, +remote_enable : fluke_remote_enable, +enable_eos : fluke_enable_eos, +disable_eos : fluke_disable_eos, +parallel_poll : fluke_parallel_poll, +parallel_poll_configure : fluke_parallel_poll_configure, +parallel_poll_response : fluke_parallel_poll_response, +line_status : fluke_line_status, +update_status : fluke_update_status, +primary_address : fluke_primary_address, +secondary_address : fluke_secondary_address, +serial_poll_response : fluke_serial_poll_response, +serial_poll_status : fluke_serial_poll_status, +t1_delay : fluke_t1_delay, +return_to_local : fluke_return_to_local, +}; + +gpib_interface_t fluke_interface = { +name: "fluke", +attach : fluke_attach_holdoff_end, +detach : fluke_detach, +read : fluke_accel_read, +write : fluke_accel_write, +command : fluke_command, +take_control : fluke_take_control, +go_to_standby : fluke_go_to_standby, +request_system_control : fluke_request_system_control, +interface_clear : fluke_interface_clear, +remote_enable : fluke_remote_enable, +enable_eos : fluke_enable_eos, +disable_eos : fluke_disable_eos, +parallel_poll : fluke_parallel_poll, +parallel_poll_configure : fluke_parallel_poll_configure, +parallel_poll_response : fluke_parallel_poll_response, +line_status : fluke_line_status, +update_status : fluke_update_status, +primary_address : fluke_primary_address, +secondary_address : fluke_secondary_address, +serial_poll_response : fluke_serial_poll_response, +serial_poll_status : fluke_serial_poll_status, +t1_delay : fluke_t1_delay, +return_to_local : fluke_return_to_local, +}; + +irqreturn_t fluke_gpib_internal_interrupt(gpib_board_t *board) +{ + int status0, status1, status2; + struct fluke_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + int retval = IRQ_NONE; + + if (read_byte(nec_priv, ADR0) & DATA_IN_STATUS) + set_bit(READ_READY_BN, &nec_priv->state); + + status0 = fluke_paged_read_byte(priv, ISR0_IMR0, ISR0_IMR0_PAGE); + status1 = read_byte(nec_priv, ISR1); + status2 = read_byte(nec_priv, ISR2); + + if (status0 & FLUKE_IFCI_BIT) { + push_gpib_event(board, EventIFC); + retval = IRQ_HANDLED; + } + + if (nec7210_interrupt_have_status(board, nec_priv, status1, status2) == IRQ_HANDLED) + retval = IRQ_HANDLED; +/* + * if((status1 & nec_priv->reg_bits[IMR1]) || + * (status2 & (nec_priv->reg_bits[IMR2] & IMR2_ENABLE_INTR_MASK))) + * { + * printk("fluke: status1 0x%x, status2 0x%x\n", status1, status2); + * } + */ + + if (read_byte(nec_priv, ADR0) & DATA_IN_STATUS) { + if (test_bit(RFD_HOLDOFF_BN, &nec_priv->state)) + set_bit(READ_READY_BN, &nec_priv->state); + else + clear_bit(READ_READY_BN, &nec_priv->state); + } + + if (retval == IRQ_HANDLED) + wake_up_interruptible(&board->wait); + + return retval; +} + +static irqreturn_t fluke_gpib_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + unsigned long flags; + irqreturn_t retval; + + spin_lock_irqsave(&board->spinlock, flags); + retval = fluke_gpib_internal_interrupt(board); + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +static int fluke_allocate_private(gpib_board_t *board) +{ + struct fluke_priv *priv; + + board->private_data = kmalloc(sizeof(struct fluke_priv), GFP_KERNEL); + if (!board->private_data) + return -ENOMEM; + priv = board->private_data; + memset(priv, 0, sizeof(struct fluke_priv)); + init_nec7210_private(&priv->nec7210_priv); + priv->dma_buffer_size = 0x7ff; + priv->dma_buffer = kmalloc(priv->dma_buffer_size, GFP_KERNEL); + if (!priv->dma_buffer) + return -ENOMEM; + return 0; +} + +static void fluke_generic_detach(gpib_board_t *board) +{ + if (board->private_data) { + struct fluke_priv *e_priv = board->private_data; + + kfree(e_priv->dma_buffer); + kfree(board->private_data); + board->private_data = NULL; + } +} + +// generic part of attach functions shared by all cb7210 boards +static int fluke_generic_attach(gpib_board_t *board) +{ + struct fluke_priv *e_priv; + struct nec7210_priv *nec_priv; + int retval; + + board->status = 0; + + retval = fluke_allocate_private(board); + if (retval < 0) + return retval; + e_priv = board->private_data; + nec_priv = &e_priv->nec7210_priv; + nec_priv->read_byte = fluke_locking_read_byte; + nec_priv->write_byte = fluke_locking_write_byte; + nec_priv->offset = fluke_reg_offset; + nec_priv->type = CB7210; + return 0; +} + +static int fluke_config_dma(gpib_board_t *board, int output) +{ + struct fluke_priv *e_priv = board->private_data; + struct dma_slave_config config; + + config.src_maxburst = 1; + config.dst_maxburst = 1; + config.device_fc = true; + + if (output) { + config.direction = DMA_MEM_TO_DEV; + config.src_addr = 0; + config.dst_addr = e_priv->dma_port_res->start; + config.src_addr_width = 1; + config.dst_addr_width = 1; + } else { + config.direction = DMA_DEV_TO_MEM; + config.src_addr = e_priv->dma_port_res->start; + config.dst_addr = 0; + config.src_addr_width = 1; + config.dst_addr_width = 1; + } + return dmaengine_slave_config(e_priv->dma_channel, &config); +} + +static int fluke_init(struct fluke_priv *e_priv, gpib_board_t *board, int handshake_mode) +{ + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + + nec7210_board_reset(nec_priv, board); + write_byte(nec_priv, AUX_LO_SPEED, AUXMR); + /* set clock register for driving frequency + * ICR should be set to clock in megahertz (1-15) and to zero + * for clocks faster than 15 MHz (max 20MHz) + */ + write_byte(nec_priv, ICR | 10, AUXMR); + nec7210_set_handshake_mode(board, nec_priv, handshake_mode); + + nec7210_board_online(nec_priv, board); + + /* poll so we can detect ATN changes */ + if (gpib_request_pseudo_irq(board, fluke_gpib_interrupt)) { + pr_err("fluke_gpib: failed to allocate pseudo_irq\n"); + return -EINVAL; + } + + fluke_paged_write_byte(e_priv, FLUKE_IFCIE_BIT, ISR0_IMR0, ISR0_IMR0_PAGE); + return 0; +} + +/* This function is passed to dma_request_channel() in order to + * select the pl330 dma channel which has been hardwired to + * the gpib controller. + */ +static bool gpib_dma_channel_filter(struct dma_chan *chan, void *filter_param) +{ + // select the channel which is wired to the gpib chip + return chan->chan_id == 0; +} + +static int fluke_attach_impl(gpib_board_t *board, const gpib_board_config_t *config, + unsigned int handshake_mode) +{ + struct fluke_priv *e_priv; + struct nec7210_priv *nec_priv; + int isr_flags = 0; + int retval; + int irq; + struct resource *res; + dma_cap_mask_t dma_cap; + + if (!fluke_gpib_pdev) { + pr_err("No gpib platform device was found, attach failed.\n"); + return -ENODEV; + } + + retval = fluke_generic_attach(board); + if (retval) + return retval; + + e_priv = board->private_data; + nec_priv = &e_priv->nec7210_priv; + nec_priv->offset = fluke_reg_offset; + board->dev = &fluke_gpib_pdev->dev; + + res = platform_get_resource(fluke_gpib_pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&fluke_gpib_pdev->dev, "Unable to locate mmio resource for cb7210 gpib\n"); + return -ENODEV; + } + + if (request_mem_region(res->start, + resource_size(res), + fluke_gpib_pdev->name) == NULL) { + dev_err(&fluke_gpib_pdev->dev, "cannot claim registers\n"); + return -ENXIO; + } + e_priv->gpib_iomem_res = res; + + nec_priv->iobase = ioremap(e_priv->gpib_iomem_res->start, + resource_size(e_priv->gpib_iomem_res)); + pr_info("gpib: iobase %lx remapped to %p, length=%d\n", + (unsigned long)e_priv->gpib_iomem_res->start, + nec_priv->iobase, (int)resource_size(e_priv->gpib_iomem_res)); + if (!nec_priv->iobase) { + dev_err(&fluke_gpib_pdev->dev, "Could not map I/O memory\n"); + return -ENOMEM; + } + + res = platform_get_resource(fluke_gpib_pdev, IORESOURCE_MEM, 1); + if (!res) { + dev_err(&fluke_gpib_pdev->dev, "Unable to locate mmio resource for gpib dma port\n"); + return -ENODEV; + } + if (request_mem_region(res->start, + resource_size(res), + fluke_gpib_pdev->name) == NULL) { + dev_err(&fluke_gpib_pdev->dev, "cannot claim registers\n"); + return -ENXIO; + } + e_priv->dma_port_res = res; + + res = platform_get_resource(fluke_gpib_pdev, IORESOURCE_MEM, 2); + if (!res) { + dev_err(&fluke_gpib_pdev->dev, "Unable to locate mmio resource for write transfer counter\n"); + return -ENODEV; + } + + if (request_mem_region(res->start, + resource_size(res), + fluke_gpib_pdev->name) == NULL) { + dev_err(&fluke_gpib_pdev->dev, "cannot claim registers\n"); + return -ENXIO; + } + e_priv->write_transfer_counter_res = res; + + e_priv->write_transfer_counter = ioremap(e_priv->write_transfer_counter_res->start, + resource_size(e_priv->write_transfer_counter_res)); + pr_info("gpib: write transfer counter %lx remapped to %p, length=%d\n", + (unsigned long)e_priv->write_transfer_counter_res->start, + e_priv->write_transfer_counter, + (int)resource_size(e_priv->write_transfer_counter_res)); + if (!e_priv->write_transfer_counter) { + dev_err(&fluke_gpib_pdev->dev, "Could not map I/O memory\n"); + return -ENOMEM; + } + + irq = platform_get_irq(fluke_gpib_pdev, 0); + pr_info("gpib: irq %d\n", irq); + if (irq < 0) { + dev_err(&fluke_gpib_pdev->dev, "fluke_gpib: request for IRQ failed\n"); + return -EBUSY; + } + retval = request_irq(irq, fluke_gpib_interrupt, isr_flags, fluke_gpib_pdev->name, board); + if (retval) { + dev_err(&fluke_gpib_pdev->dev, + "cannot register interrupt handler err=%d\n", + retval); + return retval; + } + e_priv->irq = irq; + + dma_cap_zero(dma_cap); + dma_cap_set(DMA_SLAVE, dma_cap); + e_priv->dma_channel = dma_request_channel(dma_cap, gpib_dma_channel_filter, NULL); + if (!e_priv->dma_channel) { + pr_err("fluke_gpib: failed to allocate a dma channel.\n"); + // we don't error out here because unaccel interface will still + // work without dma + } + + return fluke_init(e_priv, board, handshake_mode); +} + +int fluke_attach_holdoff_all(gpib_board_t *board, const gpib_board_config_t *config) +{ + return fluke_attach_impl(board, config, HR_HLDA); +} + +int fluke_attach_holdoff_end(gpib_board_t *board, const gpib_board_config_t *config) +{ + return fluke_attach_impl(board, config, HR_HLDE); +} + +void fluke_detach(gpib_board_t *board) +{ + struct fluke_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (e_priv) { + if (e_priv->dma_channel) + dma_release_channel(e_priv->dma_channel); + gpib_free_pseudo_irq(board); + nec_priv = &e_priv->nec7210_priv; + + if (nec_priv->iobase) { + fluke_paged_write_byte(e_priv, 0, ISR0_IMR0, ISR0_IMR0_PAGE); + nec7210_board_reset(nec_priv, board); + } + if (e_priv->irq) + free_irq(e_priv->irq, board); + if (e_priv->write_transfer_counter_res) { + release_mem_region(e_priv->write_transfer_counter_res->start, + resource_size(e_priv->write_transfer_counter_res)); + } + if (e_priv->dma_port_res) { + release_mem_region(e_priv->dma_port_res->start, + resource_size(e_priv->dma_port_res)); + } + if (e_priv->gpib_iomem_res) + release_mem_region(e_priv->gpib_iomem_res->start, + resource_size(e_priv->gpib_iomem_res)); + } + fluke_generic_detach(board); +} + +static int fluke_gpib_probe(struct platform_device *pdev) +{ + fluke_gpib_pdev = pdev; + return 0; +} + +static const struct of_device_id fluke_gpib_of_match[] = { + { .compatible = "flk,fgpib-4.0"}, + { {0} } +}; +MODULE_DEVICE_TABLE(of, fluke_gpib_of_match); + +static struct platform_driver fluke_gpib_platform_driver = { + .driver = { + .name = "fluke_gpib", + .owner = THIS_MODULE, + .of_match_table = fluke_gpib_of_match, + }, + .probe = &fluke_gpib_probe +}; + +static int __init fluke_init_module(void) +{ + int result; + + result = platform_driver_register(&fluke_gpib_platform_driver); + if (result) { + pr_err("fluke_gpib: platform_driver_register failed!\n"); + return result; + } + + gpib_register_driver(&fluke_unaccel_interface, THIS_MODULE); + gpib_register_driver(&fluke_hybrid_interface, THIS_MODULE); + gpib_register_driver(&fluke_interface, THIS_MODULE); + + pr_info("fluke_gpib\n"); + return 0; +} + +static void __exit fluke_exit_module(void) +{ + gpib_unregister_driver(&fluke_unaccel_interface); + gpib_unregister_driver(&fluke_hybrid_interface); + gpib_unregister_driver(&fluke_interface); + platform_driver_unregister(&fluke_gpib_platform_driver); +} + +module_init(fluke_init_module); +module_exit(fluke_exit_module); diff --git a/drivers/staging/gpib/eastwood/fluke_gpib.h b/drivers/staging/gpib/eastwood/fluke_gpib.h new file mode 100644 index 00000000000000..fcbd42f8f9af61 --- /dev/null +++ b/drivers/staging/gpib/eastwood/fluke_gpib.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * Author: Frank Mori Hess + * copyright: (C) 2006, 2010, 2015 Fluke Corporation + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include "nec7210.h" + +struct fluke_priv { + struct nec7210_priv nec7210_priv; + struct resource *gpib_iomem_res; + struct resource *write_transfer_counter_res; + struct resource *dma_port_res; + int irq; + struct dma_chan *dma_channel; + u8 *dma_buffer; + int dma_buffer_size; + void *write_transfer_counter; +}; + +// cb7210 specific registers and bits +enum cb7210_regs { + STATE1_REG = 0x4, + ISR0_IMR0 = 0x6, + BUS_STATUS = 0x7 +}; + +enum cb7210_page_in { + ISR0_IMR0_PAGE = 1, + BUS_STATUS_PAGE = 1, + STATE1_PAGE = 1 +}; + +/* IMR0 -- Interrupt Mode Register 0 */ +enum imr0_bits { + FLUKE_IFCIE_BIT = 0x8, /* interface clear interrupt */ +}; + +/* ISR0 -- Interrupt Status Register 0 */ +enum isr0_bits { + FLUKE_IFCI_BIT = 0x8, /* interface clear interrupt */ +}; + +enum state1_bits { + SOURCE_HANDSHAKE_SIDS_BITS = 0x0, /* source idle state */ + SOURCE_HANDSHAKE_SGNS_BITS = 0x1, /* source generate state */ + SOURCE_HANDSHAKE_SDYS_BITS = 0x2, /* source delay state */ + SOURCE_HANDSHAKE_STRS_BITS = 0x5, /* source transfer state */ + SOURCE_HANDSHAKE_MASK = 0x7 +}; + +// we customized the cb7210 vhdl to give the "data in" status +// on the unused bit 7 of the address0 register. +enum cb7210_address0 { + DATA_IN_STATUS = 0x80 +}; + +static inline int cb7210_page_in_bits(unsigned int page) +{ + return 0x50 | (page & 0xf); +} + +// don't use without locking nec_priv->register_page_lock +static inline uint8_t fluke_read_byte_nolock(struct nec7210_priv *nec_priv, + int register_num) +{ + u8 retval; + + retval = readl(nec_priv->iobase + register_num * nec_priv->offset); + return retval; +} + +// don't use without locking nec_priv->register_page_lock +static inline void fluke_write_byte_nolock(struct nec7210_priv *nec_priv, uint8_t data, + int register_num) +{ + writel(data, nec_priv->iobase + register_num * nec_priv->offset); +} + +static inline uint8_t fluke_paged_read_byte(struct fluke_priv *e_priv, + unsigned int register_num, unsigned int page) +{ + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + u8 retval; + unsigned long flags; + + spin_lock_irqsave(&nec_priv->register_page_lock, flags); + fluke_write_byte_nolock(nec_priv, cb7210_page_in_bits(page), AUXMR); + udelay(1); + /* chip auto clears the page after a read */ + retval = fluke_read_byte_nolock(nec_priv, register_num); + spin_unlock_irqrestore(&nec_priv->register_page_lock, flags); + return retval; +} + +static inline void fluke_paged_write_byte(struct fluke_priv *e_priv, uint8_t data, + unsigned int register_num, unsigned int page) +{ + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned long flags; + + spin_lock_irqsave(&nec_priv->register_page_lock, flags); + fluke_write_byte_nolock(nec_priv, cb7210_page_in_bits(page), AUXMR); + udelay(1); + fluke_write_byte_nolock(nec_priv, data, register_num); + spin_unlock_irqrestore(&nec_priv->register_page_lock, flags); +} + +enum bus_status_bits { + BSR_ATN_BIT = 0x1, + BSR_EOI_BIT = 0x2, + BSR_SRQ_BIT = 0x4, + BSR_IFC_BIT = 0x8, + BSR_REN_BIT = 0x10, + BSR_DAV_BIT = 0x20, + BSR_NRFD_BIT = 0x40, + BSR_NDAC_BIT = 0x80, +}; + +enum cb7210_aux_cmds { +/* AUX_RTL2 is an undocumented aux command which causes cb7210 to assert + * (and keep asserted) local rtl message. This is used in conjunction + * with the (stupid) cb7210 implementation + * of the normal nec7210 AUX_RTL aux command, which + * causes the rtl message to toggle between on and off. + */ + AUX_RTL2 = 0xd, + AUX_NBAF = 0xe, // new byte available false (also clears seoi) + AUX_LO_SPEED = 0x40, + AUX_HI_SPEED = 0x41, +}; + +enum { + fluke_reg_offset = 4, + fluke_num_regs = 8, + write_transfer_counter_mask = 0x7ff, +}; diff --git a/drivers/staging/gpib/fmh_gpib/Makefile b/drivers/staging/gpib/fmh_gpib/Makefile new file mode 100644 index 00000000000000..cc4d9e7cd5cdc6 --- /dev/null +++ b/drivers/staging/gpib/fmh_gpib/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_GPIB_FMH) += fmh_gpib.o diff --git a/drivers/staging/gpib/fmh_gpib/fmh_gpib.c b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c new file mode 100644 index 00000000000000..62791db1c34a4f --- /dev/null +++ b/drivers/staging/gpib/fmh_gpib/fmh_gpib.c @@ -0,0 +1,1725 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * GPIB Driver for fmh_gpib_core, see + * https://github.com/fmhess/fmh_gpib_core + * + * More specifically, it is a driver for the hardware arrangement described by + * src/examples/fmh_gpib_top.vhd in the fmh_gpib_core repository. + * + * Author: Frank Mori Hess + * Copyright: (C) 2006, 2010, 2015 Fluke Corporation + * (C) 2017 Frank Mori Hess + ***************************************************************************/ + +#include "fmh_gpib.h" + +#include "gpibP.h" +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static irqreturn_t fmh_gpib_interrupt(int irq, void *arg); +static int fmh_gpib_attach_holdoff_all(gpib_board_t *board, const gpib_board_config_t *config); +static int fmh_gpib_attach_holdoff_end(gpib_board_t *board, const gpib_board_config_t *config); +static void fmh_gpib_detach(gpib_board_t *board); +static int fmh_gpib_pci_attach_holdoff_all(gpib_board_t *board, const gpib_board_config_t *config); +static int fmh_gpib_pci_attach_holdoff_end(gpib_board_t *board, const gpib_board_config_t *config); +static void fmh_gpib_pci_detach(gpib_board_t *board); +static int fmh_gpib_config_dma(gpib_board_t *board, int output); +static irqreturn_t fmh_gpib_internal_interrupt(gpib_board_t *board); +static struct platform_driver fmh_gpib_platform_driver; +static struct pci_driver fmh_gpib_pci_driver; + +// wrappers for interface functions +static int fmh_gpib_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); +} + +static int fmh_gpib_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); +} + +static int fmh_gpib_command(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); +} + +static int fmh_gpib_take_control(gpib_board_t *board, int synchronous) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_take_control(board, &priv->nec7210_priv, synchronous); +} + +static int fmh_gpib_go_to_standby(gpib_board_t *board) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_go_to_standby(board, &priv->nec7210_priv); +} + +static void fmh_gpib_request_system_control(gpib_board_t *board, int request_control) +{ + struct fmh_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + + nec7210_request_system_control(board, nec_priv, request_control); +} + +static void fmh_gpib_interface_clear(gpib_board_t *board, int assert) +{ + struct fmh_priv *priv = board->private_data; + + nec7210_interface_clear(board, &priv->nec7210_priv, assert); +} + +static void fmh_gpib_remote_enable(gpib_board_t *board, int enable) +{ + struct fmh_priv *priv = board->private_data; + + nec7210_remote_enable(board, &priv->nec7210_priv, enable); +} + +static int fmh_gpib_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); +} + +static void fmh_gpib_disable_eos(gpib_board_t *board) +{ + struct fmh_priv *priv = board->private_data; + + nec7210_disable_eos(board, &priv->nec7210_priv); +} + +static unsigned int fmh_gpib_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_update_status(board, &priv->nec7210_priv, clear_mask); +} + +static int fmh_gpib_primary_address(gpib_board_t *board, unsigned int address) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_primary_address(board, &priv->nec7210_priv, address); +} + +static int fmh_gpib_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); +} + +static int fmh_gpib_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_parallel_poll(board, &priv->nec7210_priv, result); +} + +static void fmh_gpib_parallel_poll_configure(gpib_board_t *board, uint8_t configuration) +{ + struct fmh_priv *priv = board->private_data; + + nec7210_parallel_poll_configure(board, &priv->nec7210_priv, configuration); +} + +static void fmh_gpib_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct fmh_priv *priv = board->private_data; + + nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); +} + +static void fmh_gpib_local_parallel_poll_mode(gpib_board_t *board, int local) +{ + struct fmh_priv *priv = board->private_data; + + if (local) { + write_byte(&priv->nec7210_priv, AUX_I_REG | LOCAL_PPOLL_MODE_BIT, AUXMR); + } else { + /* For fmh_gpib_core, remote parallel poll config mode is unaffected by the + * state of the disable bit of the parallel poll register (unlike the tnt4882). + * So, we don't need to worry about that. + */ + write_byte(&priv->nec7210_priv, AUX_I_REG | 0x0, AUXMR); + } +} + +static void fmh_gpib_serial_poll_response2(gpib_board_t *board, uint8_t status, + int new_reason_for_service) +{ + struct fmh_priv *priv = board->private_data; + unsigned long flags; + const int MSS = status & request_service_bit; + const int reqt = MSS && new_reason_for_service; + const int reqf = MSS == 0; + + spin_lock_irqsave(&board->spinlock, flags); + if (reqt) { + priv->nec7210_priv.srq_pending = 1; + clear_bit(SPOLL_NUM, &board->status); + } else if (reqf) { + priv->nec7210_priv.srq_pending = 0; + } + + if (reqt) { + /* It may seem like a race to issue reqt before updating + * the status byte, but it is not. The chip does not + * issue the reqt until the SPMR is written to at + * a later time. + */ + write_byte(&priv->nec7210_priv, AUX_REQT, AUXMR); + } else if (reqf) { + write_byte(&priv->nec7210_priv, AUX_REQF, AUXMR); + } + /* We need to always zero bit 6 of the status byte before writing it to + * the SPMR to insure we are using + * serial poll mode SP1, and not accidentally triggering mode SP3. + */ + write_byte(&priv->nec7210_priv, status & ~request_service_bit, SPMR); + spin_unlock_irqrestore(&board->spinlock, flags); +} + +static uint8_t fmh_gpib_serial_poll_status(gpib_board_t *board) +{ + struct fmh_priv *priv = board->private_data; + + return nec7210_serial_poll_status(board, &priv->nec7210_priv); +} + +static void fmh_gpib_return_to_local(gpib_board_t *board) +{ + struct fmh_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + + write_byte(nec_priv, AUX_RTL2, AUXMR); + udelay(1); + write_byte(nec_priv, AUX_RTL, AUXMR); +} + +static int fmh_gpib_line_status(const gpib_board_t *board) +{ + int status = ValidALL; + int bsr_bits; + struct fmh_priv *e_priv; + struct nec7210_priv *nec_priv; + + e_priv = board->private_data; + nec_priv = &e_priv->nec7210_priv; + + bsr_bits = read_byte(nec_priv, BUS_STATUS_REG); + + if ((bsr_bits & BSR_REN_BIT) == 0) + status |= BusREN; + if ((bsr_bits & BSR_IFC_BIT) == 0) + status |= BusIFC; + if ((bsr_bits & BSR_SRQ_BIT) == 0) + status |= BusSRQ; + if ((bsr_bits & BSR_EOI_BIT) == 0) + status |= BusEOI; + if ((bsr_bits & BSR_NRFD_BIT) == 0) + status |= BusNRFD; + if ((bsr_bits & BSR_NDAC_BIT) == 0) + status |= BusNDAC; + if ((bsr_bits & BSR_DAV_BIT) == 0) + status |= BusDAV; + if ((bsr_bits & BSR_ATN_BIT) == 0) + status |= BusATN; + + return status; +} + +static unsigned int fmh_gpib_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned int retval; + + retval = nec7210_t1_delay(board, nec_priv, nano_sec); + + if (nano_sec <= 350) { + write_byte(nec_priv, AUX_HI_SPEED, AUXMR); + retval = 350; + } else { + write_byte(nec_priv, AUX_LO_SPEED, AUXMR); + } + return retval; +} + +static int lacs_or_read_ready(gpib_board_t *board) +{ + const struct fmh_priv *e_priv = board->private_data; + const struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + retval = test_bit(LACS_NUM, &board->status) || + test_bit(READ_READY_BN, &nec_priv->state); + spin_unlock_irqrestore(&board->spinlock, flags); + + return retval; +} + +static int wait_for_read(gpib_board_t *board) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; + + if (wait_event_interruptible(board->wait, + lacs_or_read_ready(board) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) + retval = -ERESTARTSYS; + + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + return retval; +} + +static int wait_for_rx_fifo_half_full_or_end(gpib_board_t *board) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; + + if (wait_event_interruptible(board->wait, + (fifos_read(e_priv, FIFO_CONTROL_STATUS_REG) & + RX_FIFO_HALF_FULL) || + test_bit(RECEIVED_END_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) + retval = -ERESTARTSYS; + + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + return retval; +} + +/* Wait until the gpib chip is ready to accept a data out byte. + */ +static int wait_for_data_out_ready(gpib_board_t *board) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; +// printk("%s: enter\n", __FUNCTION__); + + if (wait_event_interruptible(board->wait, + (test_bit(TACS_NUM, &board->status) && + (read_byte(nec_priv, EXT_STATUS_1_REG) & + DATA_OUT_STATUS_BIT)) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) + retval = -ERESTARTSYS; + + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; +// printk("%s: exit, retval=%i\n", __FUNCTION__, retval); + return retval; +} + +static void fmh_gpib_dma_callback(void *arg) +{ + gpib_board_t *board = arg; + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); +// printk("%s: enter\n", __FUNCTION__); + + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE | HR_DIIE, HR_DOIE | HR_DIIE); + wake_up_interruptible(&board->wait); + + fmh_gpib_internal_interrupt(board); + + clear_bit(DMA_WRITE_IN_PROGRESS_BN, &nec_priv->state); + clear_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state); + + // printk("%s: exit\n", __FUNCTION__); + spin_unlock_irqrestore(&board->spinlock, flags); +} + +/* returns true when all the bytes of a write have been transferred to + * the chip and successfully transferred out over the gpib bus. + */ +static int fmh_gpib_all_bytes_are_sent(struct fmh_priv *e_priv) +{ + if (fifos_read(e_priv, FIFO_XFER_COUNTER_REG) & fifo_xfer_counter_mask) + return 0; + + if ((read_byte(&e_priv->nec7210_priv, EXT_STATUS_1_REG) & DATA_OUT_STATUS_BIT) == 0) + return 0; + + return 1; +} + +static int fmh_gpib_dma_write(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned long flags; + int retval = 0; + dma_addr_t address; + struct dma_async_tx_descriptor *tx_desc; + + *bytes_written = 0; +// printk("%s: enter\n", __FUNCTION__); + if (WARN_ON_ONCE(length > e_priv->dma_buffer_size)) + return -EFAULT; + dmaengine_terminate_all(e_priv->dma_channel); + memcpy(e_priv->dma_buffer, buffer, length); + address = dma_map_single(board->dev, e_priv->dma_buffer, length, DMA_TO_DEVICE); + if (dma_mapping_error(board->dev, address)) + pr_err("dma mapping error in dma write!\n"); + /* program dma controller */ + retval = fmh_gpib_config_dma(board, 1); + if (retval) + goto cleanup; + + tx_desc = dmaengine_prep_slave_single(e_priv->dma_channel, address, length, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx_desc) { + pr_err("fmh_gpib_gpib: failed to allocate dma transmit descriptor\n"); + retval = -ENOMEM; + goto cleanup; + } + tx_desc->callback = fmh_gpib_dma_callback; + tx_desc->callback_param = board; + + spin_lock_irqsave(&board->spinlock, flags); + fifos_write(e_priv, length & fifo_xfer_counter_mask, FIFO_XFER_COUNTER_REG); + fifos_write(e_priv, TX_FIFO_DMA_REQUEST_ENABLE | TX_FIFO_CLEAR, FIFO_CONTROL_STATUS_REG); + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, HR_DMAO); + + dmaengine_submit(tx_desc); + dma_async_issue_pending(e_priv->dma_channel); + clear_bit(WRITE_READY_BN, &nec_priv->state); + set_bit(DMA_WRITE_IN_PROGRESS_BN, &nec_priv->state); +// printk("%s: in spin lock\n", __FUNCTION__); + spin_unlock_irqrestore(&board->spinlock, flags); + +// printk("%s: waiting for write.\n", __FUNCTION__); + // suspend until message is sent + if (wait_event_interruptible(board->wait, + fmh_gpib_all_bytes_are_sent(e_priv) || + test_bit(BUS_ERROR_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib write interrupted!\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + if (test_and_clear_bit(BUS_ERROR_BN, &nec_priv->state)) + retval = -EIO; + // disable board's dma + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0); + fifos_write(e_priv, 0, FIFO_CONTROL_STATUS_REG); + + dmaengine_terminate_all(e_priv->dma_channel); + // make sure fmh_gpib_dma_callback got called + if (test_bit(DMA_WRITE_IN_PROGRESS_BN, &nec_priv->state)) + fmh_gpib_dma_callback(board); + + *bytes_written = length - (fifos_read(e_priv, FIFO_XFER_COUNTER_REG) & + fifo_xfer_counter_mask); + if (WARN_ON_ONCE(*bytes_written > length)) + return -EFAULT; + /* printk("length=%i, *bytes_written=%i, residue=%i, retval=%i\n", + * length, *bytes_written, get_dma_residue(e_priv->dma_channel), retval); + */ +cleanup: + dma_unmap_single(board->dev, address, length, DMA_TO_DEVICE); +// printk("%s: exit, retval=%d\n", __FUNCTION__, retval); + return retval; +} + +static int fmh_gpib_accel_write(gpib_board_t *board, uint8_t *buffer, + size_t length, int send_eoi, size_t *bytes_written) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + size_t remainder = length; + size_t transfer_size; + ssize_t retval = 0; + size_t dma_remainder = remainder; + + if (!e_priv->dma_channel) { + pr_err("fmh_gpib_gpib: No dma channel available, cannot do accel write."); + return -ENXIO; + } + + *bytes_written = 0; + if (length < 1) + return 0; + + smp_mb__before_atomic(); + clear_bit(DEV_CLEAR_BN, &nec_priv->state); // XXX FIXME + smp_mb__after_atomic(); + + if (send_eoi) + --dma_remainder; +// printk("%s: entering while loop\n", __FUNCTION__); + + while (dma_remainder > 0) { + size_t num_bytes; + + retval = wait_for_data_out_ready(board); + if (retval < 0) + break; + + transfer_size = (e_priv->dma_buffer_size < dma_remainder) ? + e_priv->dma_buffer_size : dma_remainder; + retval = fmh_gpib_dma_write(board, buffer, transfer_size, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + break; + dma_remainder -= num_bytes; + remainder -= num_bytes; + buffer += num_bytes; + if (need_resched()) + schedule(); + } + if (retval < 0) + return retval; + //handle sending of last byte with eoi + if (send_eoi) { + size_t num_bytes; + // printk("%s: handling last byte\n", __FUNCTION__); + if (WARN_ON_ONCE(remainder != 1)) + return -EFAULT; + + /* wait until we are sure we will be able to write the data byte + * into the chip before we send AUX_SEOI. This prevents a timeout + * scenario where we send AUX_SEOI but then timeout without getting + * any bytes into the gpib chip. This will result in the first byte + * of the next write having a spurious EOI set on the first byte. + */ + retval = wait_for_data_out_ready(board); + if (retval < 0) + return retval; + + write_byte(nec_priv, AUX_SEOI, AUXMR); + retval = fmh_gpib_dma_write(board, buffer, remainder, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + return retval; + remainder -= num_bytes; + } +// printk("%s: bytes send=%i\n", __FUNCTION__, (int)(length - remainder)); + return 0; +} + +static int fmh_gpib_get_dma_residue(struct dma_chan *chan, dma_cookie_t cookie) +{ + struct dma_tx_state state; + int result; + + result = dmaengine_pause(chan); + if (result < 0) { + pr_err("fmh_gpib_gpib: dma pause failed?\n"); + return result; + } + dmaengine_tx_status(chan, cookie, &state); + // dma330 hardware doesn't support resume, so dont call this + // method unless the dma transfer is done. + return state.residue; +} + +static int wait_for_tx_fifo_half_empty(gpib_board_t *board) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; +// printk("%s: enter\n", __FUNCTION__); + + if (wait_event_interruptible(board->wait, + (test_bit(TACS_NUM, &board->status) && + (fifos_read(e_priv, FIFO_CONTROL_STATUS_REG) & + TX_FIFO_HALF_EMPTY)) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) + retval = -ERESTARTSYS; + + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; +// printk("%s: exit, retval=%i\n", __FUNCTION__, retval); + return retval; +} + +/* supports writing a chunk of data whose length must fit into the hardware'd xfer counter, + * called in a loop by fmh_gpib_fifo_write() + */ +static int fmh_gpib_fifo_write_countable(gpib_board_t *board, uint8_t *buffer, + size_t length, int send_eoi, size_t *bytes_written) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; + unsigned int remainder; + + *bytes_written = 0; +// printk("%s: enter\n", __FUNCTION__); + if (WARN_ON_ONCE(length > fifo_xfer_counter_mask)) + return -EFAULT; + + fifos_write(e_priv, length & fifo_xfer_counter_mask, FIFO_XFER_COUNTER_REG); + fifos_write(e_priv, TX_FIFO_CLEAR, FIFO_CONTROL_STATUS_REG); + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, HR_DMAO); + + remainder = length; + while (remainder > 0) { + int i; + + fifos_write(e_priv, TX_FIFO_HALF_EMPTY_INTERRUPT_ENABLE, FIFO_CONTROL_STATUS_REG); + retval = wait_for_tx_fifo_half_empty(board); + if (retval < 0) + goto cleanup; + + for (i = 0; i < fmh_gpib_half_fifo_size(e_priv) && remainder > 0; ++i) { + unsigned int data_value = *buffer; + + if (send_eoi && remainder == 1) + data_value |= FIFO_DATA_EOI_FLAG; + fifos_write(e_priv, data_value, FIFO_DATA_REG); + ++buffer; + --remainder; + } + } + + // suspend until last byte is sent + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE, HR_DOIE); + if (wait_event_interruptible(board->wait, + fmh_gpib_all_bytes_are_sent(e_priv) || + test_bit(BUS_ERROR_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib write interrupted!\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + if (test_and_clear_bit(BUS_ERROR_BN, &nec_priv->state)) + retval = -EIO; + +cleanup: + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0); + fifos_write(e_priv, 0, FIFO_CONTROL_STATUS_REG); + + *bytes_written = length - (fifos_read(e_priv, FIFO_XFER_COUNTER_REG) & + fifo_xfer_counter_mask); + if (WARN_ON_ONCE(*bytes_written > length)) + return -EFAULT; + /* printk("length=%i, *bytes_written=%i, residue=%i, retval=%i\n", + * length, *bytes_written, get_dma_residue(e_priv->dma_channel), retval); + */ + +// printk("%s: exit, retval=%d\n", __FUNCTION__, retval); + return retval; +} + +static int fmh_gpib_fifo_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + size_t remainder = length; + size_t transfer_size; + ssize_t retval = 0; + + *bytes_written = 0; + if (length < 1) + return 0; + + clear_bit(DEV_CLEAR_BN, &nec_priv->state); // XXX FIXME + +// printk("%s: entering while loop\n", __FUNCTION__); + + while (remainder > 0) { + size_t num_bytes; + int last_pass; + + retval = wait_for_data_out_ready(board); + if (retval < 0) + break; + + if (fifo_xfer_counter_mask < remainder) { + // round transfer size to a multiple of half fifo size + transfer_size = (fifo_xfer_counter_mask / + fmh_gpib_half_fifo_size(e_priv)) * + fmh_gpib_half_fifo_size(e_priv); + last_pass = 0; + } else { + transfer_size = remainder; + last_pass = 1; + } + retval = fmh_gpib_fifo_write_countable(board, buffer, transfer_size, + last_pass && send_eoi, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + break; + remainder -= num_bytes; + buffer += num_bytes; + if (need_resched()) + schedule(); + } +// printk("%s: bytes send=%i\n", __FUNCTION__, (int)(length - remainder)); + return retval; +} + +static int fmh_gpib_dma_read(gpib_board_t *board, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; + unsigned long flags; + int residue; + int wait_retval; + dma_addr_t bus_address; + struct dma_async_tx_descriptor *tx_desc; + dma_cookie_t dma_cookie; + + // printk("%s: enter, bus_address=0x%x, length=%i\n", __FUNCTION__, + //(unsigned)bus_address, +// (int)length); + + *bytes_read = 0; + *end = 0; + if (length == 0) + return 0; + + bus_address = dma_map_single(board->dev, e_priv->dma_buffer, + length, DMA_FROM_DEVICE); + if (dma_mapping_error(board->dev, bus_address)) + pr_err("dma mapping error in dma read!"); + + /* program dma controller */ + retval = fmh_gpib_config_dma(board, 0); + if (retval) { + dma_unmap_single(board->dev, bus_address, length, DMA_FROM_DEVICE); + return retval; + } + tx_desc = dmaengine_prep_slave_single(e_priv->dma_channel, bus_address, + length, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!tx_desc) { + pr_err("fmh_gpib_gpib: failed to allocate dma transmit descriptor\n"); + dma_unmap_single(board->dev, bus_address, length, DMA_FROM_DEVICE); + return -EIO; + } + tx_desc->callback = fmh_gpib_dma_callback; + tx_desc->callback_param = board; + + spin_lock_irqsave(&board->spinlock, flags); + // enable nec7210 dma + fifos_write(e_priv, length & fifo_xfer_counter_mask, FIFO_XFER_COUNTER_REG); + fifos_write(e_priv, RX_FIFO_DMA_REQUEST_ENABLE | RX_FIFO_CLEAR, FIFO_CONTROL_STATUS_REG); + nec7210_set_reg_bits(nec_priv, IMR1, HR_DIIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, HR_DMAI); + + dma_cookie = dmaengine_submit(tx_desc); + dma_async_issue_pending(e_priv->dma_channel); + + set_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state); + + spin_unlock_irqrestore(&board->spinlock, flags); +// printk("waiting for data transfer.\n"); + // wait for data to transfer + wait_retval = wait_event_interruptible(board->wait, + test_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state) + == 0 || + test_bit(RECEIVED_END_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status)); + if (wait_retval) { + pr_warn("fmh_gpib: dma read wait interrupted\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) + retval = -EINTR; + // stop the dma transfer + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + fifos_write(e_priv, 0, FIFO_CONTROL_STATUS_REG); + // give time for pl330 to transfer any in-flight data, since + // pl330 will throw it away when dmaengine_pause is called. + usleep_range(10, 15); + residue = fmh_gpib_get_dma_residue(e_priv->dma_channel, dma_cookie); + if (WARN_ON_ONCE(residue > length || residue < 0)) + return -EFAULT; + *bytes_read += length - residue; + dmaengine_terminate_all(e_priv->dma_channel); + // make sure fmh_gpib_dma_callback got called + if (test_bit(DMA_READ_IN_PROGRESS_BN, &nec_priv->state)) + fmh_gpib_dma_callback(board); + + dma_unmap_single(board->dev, bus_address, length, DMA_FROM_DEVICE); + memcpy(buffer, e_priv->dma_buffer, *bytes_read); + + /* Manually read any dregs out of fifo. */ + while ((fifos_read(e_priv, FIFO_CONTROL_STATUS_REG) & RX_FIFO_EMPTY) == 0) { + if ((*bytes_read) >= length) { + dev_err(board->dev, "unexpected extra bytes in rx fifo, discarding! bytes_read=%d length=%d residue=%d\n", + (int)(*bytes_read), (int)length, (int)residue); + break; + } + buffer[(*bytes_read)++] = fifos_read(e_priv, FIFO_DATA_REG) & fifo_data_mask; + } + + /* If we got an end interrupt, figure out if it was + * associated with the last byte we dma'd or with a + * byte still sitting on the cb7210. + */ + spin_lock_irqsave(&board->spinlock, flags); + if (*bytes_read > 0 && test_bit(READ_READY_BN, &nec_priv->state) == 0) { + // If there is no byte sitting on the cb7210 and we + // saw an end, we need to deal with it now + if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state)) + *end = 1; + } + spin_unlock_irqrestore(&board->spinlock, flags); +// printk("\tbytes_read=%i, residue=%i, end=%i, retval=%i, wait_retval=%i\n", +// *bytes_read, residue, *end, retval, wait_retval); + + return retval; +} + +static void fmh_gpib_release_rfd_holdoff(gpib_board_t *board, struct fmh_priv *e_priv) +{ + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned int ext_status_1; + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + + ext_status_1 = read_byte(nec_priv, EXT_STATUS_1_REG); + + /* if there is an end byte sitting on the chip, don't release + * holdoff. We want it left set after we read out the end + * byte. + */ + if ((ext_status_1 & (DATA_IN_STATUS_BIT | END_STATUS_BIT)) != + (DATA_IN_STATUS_BIT | END_STATUS_BIT)) { + if (ext_status_1 & RFD_HOLDOFF_STATUS_BIT) + write_byte(nec_priv, AUX_FH, AUXMR); + + /* Check if an end byte raced in before we executed the AUX_FH command. + * If it did, we want to make sure the rfd holdoff is in effect. The end + * byte can arrive since + * AUX_RFD_HOLDOFF_ASAP doesn't immediately force the acceptor handshake + * to leave ACRS. + */ + if ((read_byte(nec_priv, EXT_STATUS_1_REG) & + (RFD_HOLDOFF_STATUS_BIT | DATA_IN_STATUS_BIT | END_STATUS_BIT)) == + (DATA_IN_STATUS_BIT | END_STATUS_BIT)) { + write_byte(nec_priv, AUX_RFD_HOLDOFF_ASAP, AUXMR); + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + } else { + clear_bit(RFD_HOLDOFF_BN, &nec_priv->state); + } + } + spin_unlock_irqrestore(&board->spinlock, flags); +} + +static int fmh_gpib_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + size_t remain = length; + size_t transfer_size; + int retval = 0; + size_t dma_nbytes; + unsigned long flags; + + smp_mb__before_atomic(); + clear_bit(DEV_CLEAR_BN, &nec_priv->state); // XXX FIXME + smp_mb__after_atomic(); + *end = 0; + *bytes_read = 0; + + retval = wait_for_read(board); + if (retval < 0) + return retval; + + fmh_gpib_release_rfd_holdoff(board, e_priv); + while (remain > 0) { + transfer_size = (e_priv->dma_buffer_size < remain) ? + e_priv->dma_buffer_size : remain; + retval = fmh_gpib_dma_read(board, buffer, transfer_size, end, &dma_nbytes); + remain -= dma_nbytes; + buffer += dma_nbytes; + *bytes_read += dma_nbytes; + if (*end) + break; + if (retval < 0) + break; + if (need_resched()) + schedule(); + } + + spin_lock_irqsave(&board->spinlock, flags); + if (test_bit(RFD_HOLDOFF_BN, &nec_priv->state) == 0) { + write_byte(nec_priv, AUX_RFD_HOLDOFF_ASAP, AUXMR); + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + } + spin_unlock_irqrestore(&board->spinlock, flags); + + return retval; +} + +/* Read a chunk of data whose length is within the limits of the hardware's + * xfer counter. Called in a loop from fmh_gpib_fifo_read(). + */ +static int fmh_gpib_fifo_read_countable(gpib_board_t *board, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + int retval = 0; + + // printk("%s: enter, bus_address=0x%x, length=%i\n", __FUNCTION__, + // (unsigned)bus_address, +// (int)length); + + *bytes_read = 0; + *end = 0; + if (length == 0) + return 0; + + fifos_write(e_priv, length & fifo_xfer_counter_mask, FIFO_XFER_COUNTER_REG); + fifos_write(e_priv, RX_FIFO_CLEAR, FIFO_CONTROL_STATUS_REG); + nec7210_set_reg_bits(nec_priv, IMR1, HR_DIIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, HR_DMAI); + + while (*bytes_read < length && *end == 0) { + int i; + + fifos_write(e_priv, RX_FIFO_HALF_FULL_INTERRUPT_ENABLE, FIFO_CONTROL_STATUS_REG); + retval = wait_for_rx_fifo_half_full_or_end(board); + if (retval < 0) + goto cleanup; + + for (i = 0; i < fmh_gpib_half_fifo_size(e_priv) && *end == 0; ++i) { + unsigned int data_value; + + data_value = fifos_read(e_priv, FIFO_DATA_REG); + buffer[(*bytes_read)++] = data_value & fifo_data_mask; + if (data_value & FIFO_DATA_EOI_FLAG) + *end = 1; + } + } + +cleanup: + // stop the transfer + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + fifos_write(e_priv, 0, FIFO_CONTROL_STATUS_REG); + + /* Manually read any dregs out of fifo. */ + while ((fifos_read(e_priv, FIFO_CONTROL_STATUS_REG) & RX_FIFO_EMPTY) == 0) { + unsigned int data_value; + + if ((*bytes_read) >= length) { + dev_err(board->dev, "unexpected extra bytes in rx fifo, discarding! bytes_read=%d length=%d\n", + (int)(*bytes_read), (int)length); + break; + } + data_value = fifos_read(e_priv, FIFO_DATA_REG); + buffer[(*bytes_read)++] = data_value & fifo_data_mask; + if (data_value & FIFO_DATA_EOI_FLAG) + *end = 1; + } + +// printk("\tbytes_read=%i, end=%i, retval=%i, wait_retval=%i\n", +// *bytes_read, *end, retval, wait_retval); + + return retval; +} + +static int fmh_gpib_fifo_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + size_t remain = length; + size_t transfer_size; + int retval = 0; + size_t nbytes; + unsigned long flags; + + clear_bit(DEV_CLEAR_BN, &nec_priv->state); // XXX FIXME + *end = 0; + *bytes_read = 0; + + /* Do a little prep with data in interrupt so that following wait_for_read() + * will wake up if a data byte is received. + */ + nec7210_set_reg_bits(nec_priv, IMR1, HR_DIIE, HR_DIIE); + fmh_gpib_interrupt(0, board); + + retval = wait_for_read(board); + if (retval < 0) + return retval; + + fmh_gpib_release_rfd_holdoff(board, e_priv); + while (remain > 0) { + if (fifo_xfer_counter_mask < remain) { + // round transfer size to a multiple of half fifo size + transfer_size = (fifo_xfer_counter_mask / + fmh_gpib_half_fifo_size(e_priv)) * + fmh_gpib_half_fifo_size(e_priv); + } else { + transfer_size = remain; + } + retval = fmh_gpib_fifo_read_countable(board, buffer, transfer_size, end, &nbytes); + remain -= nbytes; + buffer += nbytes; + *bytes_read += nbytes; + if (*end) + break; + if (retval < 0) + break; + if (need_resched()) + schedule(); + } + + if (*end == 0) { + spin_lock_irqsave(&board->spinlock, flags); + write_byte(nec_priv, AUX_RFD_HOLDOFF_ASAP, AUXMR); + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + spin_unlock_irqrestore(&board->spinlock, flags); + } + + return retval; +} + +gpib_interface_t fmh_gpib_unaccel_interface = { +name: "fmh_gpib_unaccel", +attach : fmh_gpib_attach_holdoff_all, +detach : fmh_gpib_detach, +read : fmh_gpib_read, +write : fmh_gpib_write, +command : fmh_gpib_command, +take_control : fmh_gpib_take_control, +go_to_standby : fmh_gpib_go_to_standby, +request_system_control : fmh_gpib_request_system_control, +interface_clear : fmh_gpib_interface_clear, +remote_enable : fmh_gpib_remote_enable, +enable_eos : fmh_gpib_enable_eos, +disable_eos : fmh_gpib_disable_eos, +parallel_poll : fmh_gpib_parallel_poll, +parallel_poll_configure : fmh_gpib_parallel_poll_configure, +parallel_poll_response : fmh_gpib_parallel_poll_response, +local_parallel_poll_mode : fmh_gpib_local_parallel_poll_mode, +line_status : fmh_gpib_line_status, +update_status : fmh_gpib_update_status, +primary_address : fmh_gpib_primary_address, +secondary_address : fmh_gpib_secondary_address, +serial_poll_response2 : fmh_gpib_serial_poll_response2, +serial_poll_status : fmh_gpib_serial_poll_status, +t1_delay : fmh_gpib_t1_delay, +return_to_local : fmh_gpib_return_to_local, +}; + +gpib_interface_t fmh_gpib_interface = { +name: "fmh_gpib", +attach : fmh_gpib_attach_holdoff_end, +detach : fmh_gpib_detach, +read : fmh_gpib_accel_read, +write : fmh_gpib_accel_write, +command : fmh_gpib_command, +take_control : fmh_gpib_take_control, +go_to_standby : fmh_gpib_go_to_standby, +request_system_control : fmh_gpib_request_system_control, +interface_clear : fmh_gpib_interface_clear, +remote_enable : fmh_gpib_remote_enable, +enable_eos : fmh_gpib_enable_eos, +disable_eos : fmh_gpib_disable_eos, +parallel_poll : fmh_gpib_parallel_poll, +parallel_poll_configure : fmh_gpib_parallel_poll_configure, +parallel_poll_response : fmh_gpib_parallel_poll_response, +local_parallel_poll_mode : fmh_gpib_local_parallel_poll_mode, +line_status : fmh_gpib_line_status, +update_status : fmh_gpib_update_status, +primary_address : fmh_gpib_primary_address, +secondary_address : fmh_gpib_secondary_address, +serial_poll_response2 : fmh_gpib_serial_poll_response2, +serial_poll_status : fmh_gpib_serial_poll_status, +t1_delay : fmh_gpib_t1_delay, +return_to_local : fmh_gpib_return_to_local, +}; + +gpib_interface_t fmh_gpib_pci_interface = { +name: "fmh_gpib_pci", +attach : fmh_gpib_pci_attach_holdoff_end, +detach : fmh_gpib_pci_detach, +read : fmh_gpib_fifo_read, +write : fmh_gpib_fifo_write, +command : fmh_gpib_command, +take_control : fmh_gpib_take_control, +go_to_standby : fmh_gpib_go_to_standby, +request_system_control : fmh_gpib_request_system_control, +interface_clear : fmh_gpib_interface_clear, +remote_enable : fmh_gpib_remote_enable, +enable_eos : fmh_gpib_enable_eos, +disable_eos : fmh_gpib_disable_eos, +parallel_poll : fmh_gpib_parallel_poll, +parallel_poll_configure : fmh_gpib_parallel_poll_configure, +parallel_poll_response : fmh_gpib_parallel_poll_response, +local_parallel_poll_mode : fmh_gpib_local_parallel_poll_mode, +line_status : fmh_gpib_line_status, +update_status : fmh_gpib_update_status, +primary_address : fmh_gpib_primary_address, +secondary_address : fmh_gpib_secondary_address, +serial_poll_response2 : fmh_gpib_serial_poll_response2, +serial_poll_status : fmh_gpib_serial_poll_status, +t1_delay : fmh_gpib_t1_delay, +return_to_local : fmh_gpib_return_to_local, +}; + +gpib_interface_t fmh_gpib_pci_unaccel_interface = { +name: "fmh_gpib_pci_unaccel", +attach : fmh_gpib_pci_attach_holdoff_all, +detach : fmh_gpib_pci_detach, +read : fmh_gpib_read, +write : fmh_gpib_write, +command : fmh_gpib_command, +take_control : fmh_gpib_take_control, +go_to_standby : fmh_gpib_go_to_standby, +request_system_control : fmh_gpib_request_system_control, +interface_clear : fmh_gpib_interface_clear, +remote_enable : fmh_gpib_remote_enable, +enable_eos : fmh_gpib_enable_eos, +disable_eos : fmh_gpib_disable_eos, +parallel_poll : fmh_gpib_parallel_poll, +parallel_poll_configure : fmh_gpib_parallel_poll_configure, +parallel_poll_response : fmh_gpib_parallel_poll_response, +local_parallel_poll_mode : fmh_gpib_local_parallel_poll_mode, +line_status : fmh_gpib_line_status, +update_status : fmh_gpib_update_status, +primary_address : fmh_gpib_primary_address, +secondary_address : fmh_gpib_secondary_address, +serial_poll_response2 : fmh_gpib_serial_poll_response2, +serial_poll_status : fmh_gpib_serial_poll_status, +t1_delay : fmh_gpib_t1_delay, +return_to_local : fmh_gpib_return_to_local, +}; + +irqreturn_t fmh_gpib_internal_interrupt(gpib_board_t *board) +{ + unsigned int status0, status1, status2, ext_status_1, fifo_status; + struct fmh_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + int retval = IRQ_NONE; + + status0 = read_byte(nec_priv, ISR0_IMR0_REG); + status1 = read_byte(nec_priv, ISR1); + status2 = read_byte(nec_priv, ISR2); + fifo_status = fifos_read(priv, FIFO_CONTROL_STATUS_REG); + + if (status0 & IFC_INTERRUPT_BIT) { + push_gpib_event(board, EventIFC); + retval = IRQ_HANDLED; + } + + if (nec7210_interrupt_have_status(board, nec_priv, status1, status2) == IRQ_HANDLED) + retval = IRQ_HANDLED; + + ext_status_1 = read_byte(nec_priv, EXT_STATUS_1_REG); + + if (ext_status_1 & DATA_IN_STATUS_BIT) + set_bit(READ_READY_BN, &nec_priv->state); + else + clear_bit(READ_READY_BN, &nec_priv->state); + + if (ext_status_1 & DATA_OUT_STATUS_BIT) + set_bit(WRITE_READY_BN, &nec_priv->state); + else + clear_bit(WRITE_READY_BN, &nec_priv->state); + + if (ext_status_1 & COMMAND_OUT_STATUS_BIT) + set_bit(COMMAND_READY_BN, &nec_priv->state); + else + clear_bit(COMMAND_READY_BN, &nec_priv->state); + + if (ext_status_1 & RFD_HOLDOFF_STATUS_BIT) + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + else + clear_bit(RFD_HOLDOFF_BN, &nec_priv->state); + + if (ext_status_1 & END_STATUS_BIT) { + /* only set RECEIVED_END while there is still a data + * byte sitting in the chip, to avoid spuriously + * setting it multiple times after it has been cleared + * during a read. + */ + if (ext_status_1 & DATA_IN_STATUS_BIT) + set_bit(RECEIVED_END_BN, &nec_priv->state); + } else { + clear_bit(RECEIVED_END_BN, &nec_priv->state); + } + + if ((fifo_status & TX_FIFO_HALF_EMPTY_INTERRUPT_IS_ENABLED) && + (fifo_status & TX_FIFO_HALF_EMPTY)) { + /* We really only want to clear the + * TX_FIFO_HALF_EMPTY_INTERRUPT_ENABLE bit in the + * FIFO_CONTROL_STATUS_REG. Since we are not being + * careful, this also has a side effect of disabling + * DMA requests and the RX fifo interrupt. That is + * fine though, since they should never be in use at + * the same time as the TX fifo interrupt. + */ + fifos_write(priv, 0x0, FIFO_CONTROL_STATUS_REG); + retval = IRQ_HANDLED; + } + + if ((fifo_status & RX_FIFO_HALF_FULL_INTERRUPT_IS_ENABLED) && + (fifo_status & RX_FIFO_HALF_FULL)) { + /* We really only want to clear the + * RX_FIFO_HALF_FULL_INTERRUPT_ENABLE bit in the + * FIFO_CONTROL_STATUS_REG. Since we are not being + * careful, this also has a side effect of disabling + * DMA requests and the TX fifo interrupt. That is + * fine though, since they should never be in use at + * the same time as the RX fifo interrupt. + */ + fifos_write(priv, 0x0, FIFO_CONTROL_STATUS_REG); + retval = IRQ_HANDLED; + } + + if (retval == IRQ_HANDLED) + wake_up_interruptible(&board->wait); + + return retval; +} + +irqreturn_t fmh_gpib_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + unsigned long flags; + irqreturn_t retval; + + spin_lock_irqsave(&board->spinlock, flags); + retval = fmh_gpib_internal_interrupt(board); + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +static int fmh_gpib_allocate_private(gpib_board_t *board) +{ + struct fmh_priv *priv; + + board->private_data = kmalloc(sizeof(struct fmh_priv), GFP_KERNEL); + if (!board->private_data) + return -ENOMEM; + priv = board->private_data; + memset(priv, 0, sizeof(struct fmh_priv)); + init_nec7210_private(&priv->nec7210_priv); + priv->dma_buffer_size = 0x800; + priv->dma_buffer = kmalloc(priv->dma_buffer_size, GFP_KERNEL); + if (!priv->dma_buffer) + return -ENOMEM; + return 0; +} + +static void fmh_gpib_generic_detach(gpib_board_t *board) +{ + if (board->private_data) { + struct fmh_priv *e_priv = board->private_data; + + kfree(e_priv->dma_buffer); + kfree(board->private_data); + board->private_data = NULL; + } + if (board->dev) + dev_set_drvdata(board->dev, NULL); +} + +// generic part of attach functions +static int fmh_gpib_generic_attach(gpib_board_t *board) +{ + struct fmh_priv *e_priv; + struct nec7210_priv *nec_priv; + int retval; + + board->status = 0; + + retval = fmh_gpib_allocate_private(board); + if (retval < 0) + return retval; + e_priv = board->private_data; + nec_priv = &e_priv->nec7210_priv; + nec_priv->read_byte = gpib_cs_read_byte; + nec_priv->write_byte = gpib_cs_write_byte; + nec_priv->offset = 1; + nec_priv->type = CB7210; + return 0; +} + +static int fmh_gpib_config_dma(gpib_board_t *board, int output) +{ + struct fmh_priv *e_priv = board->private_data; + struct dma_slave_config config; + + config.device_fc = true; + + if (e_priv->dma_burst_length < 1) { + config.src_maxburst = 1; + config.dst_maxburst = 1; + } else { + config.src_maxburst = e_priv->dma_burst_length; + config.dst_maxburst = e_priv->dma_burst_length; + } + + config.src_addr_width = 1; + config.dst_addr_width = 1; + + if (output) { + config.direction = DMA_MEM_TO_DEV; + config.src_addr = 0; + config.dst_addr = e_priv->dma_port_res->start + FIFO_DATA_REG * fifo_reg_offset; + } else { + config.direction = DMA_DEV_TO_MEM; + config.src_addr = e_priv->dma_port_res->start + FIFO_DATA_REG * fifo_reg_offset; + config.dst_addr = 0; + } + return dmaengine_slave_config(e_priv->dma_channel, &config); +} + +static int fmh_gpib_init(struct fmh_priv *e_priv, gpib_board_t *board, int handshake_mode) +{ + struct nec7210_priv *nec_priv = &e_priv->nec7210_priv; + unsigned long flags; + unsigned int fifo_status_bits; + + fifos_write(e_priv, RX_FIFO_CLEAR | TX_FIFO_CLEAR, FIFO_CONTROL_STATUS_REG); + + nec7210_board_reset(nec_priv, board); + write_byte(nec_priv, AUX_LO_SPEED, AUXMR); + nec7210_set_handshake_mode(board, nec_priv, handshake_mode); + + /* Hueristically check if hardware supports fifo half full/empty interrupts */ + fifo_status_bits = fifos_read(e_priv, FIFO_CONTROL_STATUS_REG); + e_priv->supports_fifo_interrupts = (fifo_status_bits & TX_FIFO_EMPTY) && + (fifo_status_bits & TX_FIFO_HALF_EMPTY); + + nec7210_board_online(nec_priv, board); + + write_byte(nec_priv, IFC_INTERRUPT_ENABLE_BIT | ATN_INTERRUPT_ENABLE_BIT, ISR0_IMR0_REG); + + spin_lock_irqsave(&board->spinlock, flags); + write_byte(nec_priv, AUX_RFD_HOLDOFF_ASAP, AUXMR); + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + spin_unlock_irqrestore(&board->spinlock, flags); + return 0; +} + +/* Match callback for driver_find_device */ +static int fmh_gpib_device_match(struct device *dev, const void *data) +{ + const gpib_board_config_t *config = data; + + if (dev_get_drvdata(dev)) + return 0; + + if (gpib_match_device_path(dev, config->device_path) == 0) + return 0; + + // driver doesn't support selection by serial number + if (config->serial_number) + return 0; + + dev_notice(dev, "matched: %s\n", of_node_full_name(dev_of_node((dev)))); + return 1; +} + +static int fmh_gpib_attach_impl(gpib_board_t *board, const gpib_board_config_t *config, + unsigned int handshake_mode, int acquire_dma) +{ + struct fmh_priv *e_priv; + struct nec7210_priv *nec_priv; + int retval; + int irq; + struct resource *res; + struct platform_device *pdev; + + board->dev = driver_find_device(&fmh_gpib_platform_driver.driver, + NULL, (const void *)config, &fmh_gpib_device_match); + if (!board->dev) { + pr_err("No matching fmh_gpib_core device was found, attach failed."); + return -ENODEV; + } + // currently only used to mark the device as already attached + dev_set_drvdata(board->dev, board); + pdev = to_platform_device(board->dev); + + retval = fmh_gpib_generic_attach(board); + if (retval) + return retval; + + e_priv = board->private_data; + nec_priv = &e_priv->nec7210_priv; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpib_control_status"); + if (!res) { + dev_err(board->dev, "Unable to locate mmio resource for cb7210 gpib\n"); + return -ENODEV; + } + + if (request_mem_region(res->start, + resource_size(res), + pdev->name) == NULL) { + dev_err(board->dev, "cannot claim registers\n"); + return -ENXIO; + } + e_priv->gpib_iomem_res = res; + + nec_priv->iobase = ioremap(e_priv->gpib_iomem_res->start, + resource_size(e_priv->gpib_iomem_res)); + if (!nec_priv->iobase) { + dev_err(board->dev, "Could not map I/O memory for gpib\n"); + return -ENOMEM; + } + dev_info(board->dev, "iobase 0x%lx remapped to %p, length=%ld\n", + (unsigned long)e_priv->gpib_iomem_res->start, + nec_priv->iobase, (unsigned long)resource_size(e_priv->gpib_iomem_res)); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma_fifos"); + if (!res) { + dev_err(board->dev, "Unable to locate mmio resource for gpib dma port\n"); + return -ENODEV; + } + if (request_mem_region(res->start, + resource_size(res), + pdev->name) == NULL) { + dev_err(board->dev, "cannot claim registers\n"); + return -ENXIO; + } + e_priv->dma_port_res = res; + e_priv->fifo_base = ioremap(e_priv->dma_port_res->start, + resource_size(e_priv->dma_port_res)); + if (!e_priv->fifo_base) { + dev_err(board->dev, "Could not map I/O memory for fifos\n"); + return -ENOMEM; + } + dev_info(board->dev, "dma fifos 0x%lx remapped to %p, length=%ld\n", + (unsigned long)e_priv->dma_port_res->start, e_priv->fifo_base, + (unsigned long)resource_size(e_priv->dma_port_res)); + + irq = platform_get_irq(pdev, 0); + pr_info("gpib: irq %d\n", irq); + if (irq < 0) { + dev_err(board->dev, "fmh_gpib_gpib: request for IRQ failed\n"); + return -EBUSY; + } + retval = request_irq(irq, fmh_gpib_interrupt, IRQF_SHARED, pdev->name, board); + if (retval) { + dev_err(board->dev, + "cannot register interrupt handler err=%d\n", + retval); + return retval; + } + e_priv->irq = irq; + + if (acquire_dma) { + e_priv->dma_channel = dma_request_slave_channel(board->dev, "rxtx"); + if (!e_priv->dma_channel) { + dev_err(board->dev, "failed to acquire dma channel \"rxtx\".\n"); + return -EIO; + } + } + /* in the future we might want to know the half-fifo size + * (dma_burst_length) even when not using dma, so go ahead an + * initialize it unconditionally. + */ + e_priv->dma_burst_length = fifos_read(e_priv, FIFO_MAX_BURST_LENGTH_REG) & + fifo_max_burst_length_mask; + + return fmh_gpib_init(e_priv, board, handshake_mode); +} + +int fmh_gpib_attach_holdoff_all(gpib_board_t *board, const gpib_board_config_t *config) +{ + return fmh_gpib_attach_impl(board, config, HR_HLDA, 0); +} + +int fmh_gpib_attach_holdoff_end(gpib_board_t *board, const gpib_board_config_t *config) +{ + return fmh_gpib_attach_impl(board, config, HR_HLDE, 1); +} + +void fmh_gpib_detach(gpib_board_t *board) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (e_priv) { + if (e_priv->dma_channel) + dma_release_channel(e_priv->dma_channel); + nec_priv = &e_priv->nec7210_priv; + + if (e_priv->irq) + free_irq(e_priv->irq, board); + if (e_priv->fifo_base) + fifos_write(e_priv, 0, FIFO_CONTROL_STATUS_REG); + if (nec_priv->iobase) { + write_byte(nec_priv, 0, ISR0_IMR0_REG); + nec7210_board_reset(nec_priv, board); + } + if (e_priv->fifo_base) + iounmap(e_priv->fifo_base); + if (nec_priv->iobase) + iounmap(nec_priv->iobase); + if (e_priv->dma_port_res) { + release_mem_region(e_priv->dma_port_res->start, + resource_size(e_priv->dma_port_res)); + } + if (e_priv->gpib_iomem_res) + release_mem_region(e_priv->gpib_iomem_res->start, + resource_size(e_priv->gpib_iomem_res)); + } + fmh_gpib_generic_detach(board); +} + +static int fmh_gpib_pci_attach_impl(gpib_board_t *board, const gpib_board_config_t *config, + unsigned int handshake_mode) +{ + struct fmh_priv *e_priv; + struct nec7210_priv *nec_priv; + int retval; + struct pci_dev *pci_device; + + retval = fmh_gpib_generic_attach(board); + if (retval) + return retval; + + e_priv = board->private_data; + nec_priv = &e_priv->nec7210_priv; + + // find board + pci_device = gpib_pci_get_device(config, BOGUS_PCI_VENDOR_ID_FLUKE, + BOGUS_PCI_DEVICE_ID_FLUKE_BLADERUNNER, NULL); + if (!pci_device) { + pr_err("No matching fmh_gpib_core pci device was found, attach failed."); + return -ENODEV; + } + board->dev = &pci_device->dev; + + // bladerunner prototype has offset of 4 between gpib control/status registers + nec_priv->offset = 4; + + if (pci_enable_device(pci_device)) { + dev_err(board->dev, "error enabling pci device\n"); + return -EIO; + } + if (pci_request_regions(pci_device, KBUILD_MODNAME)) { + dev_err(board->dev, "pci_request_regions failed\n"); + return -EIO; + } + e_priv->gpib_iomem_res = &pci_device->resource[gpib_control_status_pci_resource_index]; + e_priv->dma_port_res = &pci_device->resource[gpib_fifo_pci_resource_index]; + + nec_priv->iobase = ioremap(pci_resource_start(pci_device, + gpib_control_status_pci_resource_index), + pci_resource_len(pci_device, + gpib_control_status_pci_resource_index)); + dev_info(board->dev, "base address for gpib control/status registers remapped to 0x%p\n", + nec_priv->iobase); + + if (e_priv->dma_port_res->flags & IORESOURCE_MEM) { + e_priv->fifo_base = ioremap(pci_resource_start(pci_device, + gpib_fifo_pci_resource_index), + pci_resource_len(pci_device, + gpib_fifo_pci_resource_index)); + dev_info(board->dev, "base address for gpib fifo registers remapped to 0x%p\n", + e_priv->fifo_base); + } else { + e_priv->fifo_base = NULL; + dev_info(board->dev, "hardware has no gpib fifo registers.\n"); + } + + if (pci_device->irq) { + retval = request_irq(pci_device->irq, fmh_gpib_interrupt, IRQF_SHARED, + KBUILD_MODNAME, board); + if (retval) { + dev_err(board->dev, + "cannot register interrupt handler err=%d\n", + retval); + return retval; + } + } + e_priv->irq = pci_device->irq; + + e_priv->dma_burst_length = fifos_read(e_priv, FIFO_MAX_BURST_LENGTH_REG) & + fifo_max_burst_length_mask; + + return fmh_gpib_init(e_priv, board, handshake_mode); +} + +int fmh_gpib_pci_attach_holdoff_all(gpib_board_t *board, const gpib_board_config_t *config) +{ + return fmh_gpib_pci_attach_impl(board, config, HR_HLDA); +} + +int fmh_gpib_pci_attach_holdoff_end(gpib_board_t *board, const gpib_board_config_t *config) +{ + int retval; + struct fmh_priv *e_priv; + + retval = fmh_gpib_pci_attach_impl(board, config, HR_HLDE); + e_priv = board->private_data; + if (retval == 0 && e_priv && e_priv->supports_fifo_interrupts == 0) { + pr_err("fmh_gpib: your fmh_gpib_core does not appear to support fifo interrupts. Try the fmh_gpib_pci_unaccel board type instead."); + return -EIO; + } + return retval; +} + +void fmh_gpib_pci_detach(gpib_board_t *board) +{ + struct fmh_priv *e_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (e_priv) { + nec_priv = &e_priv->nec7210_priv; + + if (e_priv->irq) + free_irq(e_priv->irq, board); + if (e_priv->fifo_base) + fifos_write(e_priv, 0, FIFO_CONTROL_STATUS_REG); + if (nec_priv->iobase) { + write_byte(nec_priv, 0, ISR0_IMR0_REG); + nec7210_board_reset(nec_priv, board); + } + if (e_priv->fifo_base) + iounmap(e_priv->fifo_base); + if (nec_priv->iobase) + iounmap(nec_priv->iobase); + if (e_priv->dma_port_res || e_priv->gpib_iomem_res) + pci_release_regions(to_pci_dev(board->dev)); + if (board->dev) + pci_dev_put(to_pci_dev(board->dev)); + } + fmh_gpib_generic_detach(board); +} + +static int fmh_gpib_platform_probe(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id fmh_gpib_of_match[] = { + { .compatible = "fmhess,fmh_gpib_core"}, + { {0} } +}; +MODULE_DEVICE_TABLE(of, fmh_gpib_of_match); + +static struct platform_driver fmh_gpib_platform_driver = { + .driver = { + .name = "fmh_gpib", + .owner = THIS_MODULE, + .of_match_table = fmh_gpib_of_match, + }, + .probe = &fmh_gpib_platform_probe +}; + +static int fmh_gpib_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return 0; +} + +static const struct pci_device_id fmh_gpib_pci_match[] = { + { BOGUS_PCI_VENDOR_ID_FLUKE, BOGUS_PCI_DEVICE_ID_FLUKE_BLADERUNNER, 0, 0, 0 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, fmh_gpib_pci_match); + +static struct pci_driver fmh_gpib_pci_driver = { + .name = "fmh_gpib", + .id_table = fmh_gpib_pci_match, + .probe = &fmh_gpib_pci_probe +}; + +static int __init fmh_gpib_init_module(void) +{ + int result; + + result = platform_driver_register(&fmh_gpib_platform_driver); + if (result) { + pr_err("fmh_gpib: platform_driver_register failed!\n"); + return result; + } + + result = pci_register_driver(&fmh_gpib_pci_driver); + if (result) { + pr_err("fmh_gpib: pci_driver_register failed!\n"); + return result; + } + + gpib_register_driver(&fmh_gpib_unaccel_interface, THIS_MODULE); + gpib_register_driver(&fmh_gpib_interface, THIS_MODULE); + gpib_register_driver(&fmh_gpib_pci_unaccel_interface, THIS_MODULE); + gpib_register_driver(&fmh_gpib_pci_interface, THIS_MODULE); + + pr_info("fmh_gpib\n"); + return 0; +} + +static void __exit fmh_gpib_exit_module(void) +{ + gpib_unregister_driver(&fmh_gpib_pci_interface); + gpib_unregister_driver(&fmh_gpib_pci_unaccel_interface); + gpib_unregister_driver(&fmh_gpib_unaccel_interface); + gpib_unregister_driver(&fmh_gpib_interface); + + pci_unregister_driver(&fmh_gpib_pci_driver); + platform_driver_unregister(&fmh_gpib_platform_driver); +} + +module_init(fmh_gpib_init_module); +module_exit(fmh_gpib_exit_module); diff --git a/drivers/staging/gpib/fmh_gpib/fmh_gpib.h b/drivers/staging/gpib/fmh_gpib/fmh_gpib.h new file mode 100644 index 00000000000000..43bfc89d2a6feb --- /dev/null +++ b/drivers/staging/gpib/fmh_gpib/fmh_gpib.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * Author: Frank Mori Hess + * Copyright: (C) 2006, 2010, 2015 Fluke Corporation + * (C) 2017 Frank Mori Hess + ***************************************************************************/ + +#include +#include +#include +#include +#include "nec7210.h" + +static const int fifo_reg_offset = 2; + +static const int gpib_control_status_pci_resource_index; +static const int gpib_fifo_pci_resource_index = 1; + +/* We don't have a real pci vendor/device id, the following will need to be + * patched to match prototype hardware. + */ +#define BOGUS_PCI_VENDOR_ID_FLUKE 0xffff +#define BOGUS_PCI_DEVICE_ID_FLUKE_BLADERUNNER 0x0 + +struct fmh_priv { + struct nec7210_priv nec7210_priv; + struct resource *gpib_iomem_res; + struct resource *write_transfer_counter_res; + struct resource *dma_port_res; + int irq; + struct dma_chan *dma_channel; + u8 *dma_buffer; + int dma_buffer_size; + int dma_burst_length; + void *fifo_base; + unsigned supports_fifo_interrupts : 1; +}; + +static inline int fmh_gpib_half_fifo_size(struct fmh_priv *priv) +{ + return priv->dma_burst_length; +} + +// registers beyond the nec7210 register set +enum fmh_gpib_regs { + EXT_STATUS_1_REG = 0x9, + STATE1_REG = 0xc, + ISR0_IMR0_REG = 0xe, + BUS_STATUS_REG = 0xf +}; + +/* IMR0 -- Interrupt Mode Register 0 */ +enum imr0_bits { + ATN_INTERRUPT_ENABLE_BIT = 0x4, + IFC_INTERRUPT_ENABLE_BIT = 0x8 +}; + +/* ISR0 -- Interrupt Status Register 0 */ +enum isr0_bits { + ATN_INTERRUPT_BIT = 0x4, + IFC_INTERRUPT_BIT = 0x8 +}; + +enum state1_bits { + SOURCE_HANDSHAKE_SIDS_BITS = 0x0, /* source idle state */ + SOURCE_HANDSHAKE_SGNS_BITS = 0x1, /* source generate state */ + SOURCE_HANDSHAKE_SDYS_BITS = 0x2, /* source delay state */ + SOURCE_HANDSHAKE_STRS_BITS = 0x5, /* source transfer state */ + SOURCE_HANDSHAKE_MASK = 0x7 +}; + +enum fmh_gpib_auxmr_bits { + AUX_I_REG = 0xe0, +}; + +enum aux_reg_i_bits { + LOCAL_PPOLL_MODE_BIT = 0x4 +}; + +enum ext_status_1_bits { + DATA_IN_STATUS_BIT = 0x01, + DATA_OUT_STATUS_BIT = 0x02, + COMMAND_OUT_STATUS_BIT = 0x04, + RFD_HOLDOFF_STATUS_BIT = 0x08, + END_STATUS_BIT = 0x10 +}; + +/* dma fifo reg and bits */ +enum dma_fifo_regs { + FIFO_DATA_REG = 0x0, + FIFO_CONTROL_STATUS_REG = 0x1, + FIFO_XFER_COUNTER_REG = 0x2, + FIFO_MAX_BURST_LENGTH_REG = 0x3 +}; + +enum fifo_data_bits { + FIFO_DATA_EOI_FLAG = 0x100 +}; + +enum fifo_control_bits { + TX_FIFO_DMA_REQUEST_ENABLE = 0x0001, + TX_FIFO_CLEAR = 0x0002, + TX_FIFO_HALF_EMPTY_INTERRUPT_ENABLE = 0x0008, + RX_FIFO_DMA_REQUEST_ENABLE = 0x0100, + RX_FIFO_CLEAR = 0x0200, + RX_FIFO_HALF_FULL_INTERRUPT_ENABLE = 0x0800 +}; + +enum fifo_status_bits { + TX_FIFO_EMPTY = 0x0001, + TX_FIFO_FULL = 0x0002, + TX_FIFO_HALF_EMPTY = 0x0004, + TX_FIFO_HALF_EMPTY_INTERRUPT_IS_ENABLED = 0x0008, + TX_FIFO_DMA_REQUEST_IS_ENABLED = 0x0010, + RX_FIFO_EMPTY = 0x0100, + RX_FIFO_FULL = 0x0200, + RX_FIFO_HALF_FULL = 0x0400, + RX_FIFO_HALF_FULL_INTERRUPT_IS_ENABLED = 0x0800, + RX_FIFO_DMA_REQUEST_IS_ENABLED = 0x1000 +}; + +static const unsigned int fifo_data_mask = 0x00ff; +static const unsigned int fifo_xfer_counter_mask = 0x0fff; +static const unsigned int fifo_max_burst_length_mask = 0x00ff; + +static inline uint8_t gpib_cs_read_byte(struct nec7210_priv *nec_priv, + unsigned int register_num) +{ + return readb(nec_priv->iobase + register_num * nec_priv->offset); +} + +static inline void gpib_cs_write_byte(struct nec7210_priv *nec_priv, uint8_t data, + unsigned int register_num) +{ + writeb(data, nec_priv->iobase + register_num * nec_priv->offset); +} + +static inline uint16_t fifos_read(struct fmh_priv *fmh_priv, int register_num) +{ + if (!fmh_priv->fifo_base) + return 0; + return readw(fmh_priv->fifo_base + register_num * fifo_reg_offset); +} + +static inline void fifos_write(struct fmh_priv *fmh_priv, uint16_t data, int register_num) +{ + if (!fmh_priv->fifo_base) + return; + writew(data, fmh_priv->fifo_base + register_num * fifo_reg_offset); +} + +enum bus_status_bits { + BSR_ATN_BIT = 0x01, + BSR_EOI_BIT = 0x02, + BSR_SRQ_BIT = 0x04, + BSR_IFC_BIT = 0x08, + BSR_REN_BIT = 0x10, + BSR_DAV_BIT = 0x20, + BSR_NRFD_BIT = 0x40, + BSR_NDAC_BIT = 0x80, +}; + +enum fmh_gpib_aux_cmds { + /* AUX_RTL2 is an auxiliary command which causes the cb7210 to assert + * (and keep asserted) the local rtl message. This is used in conjunction + * with the normal nec7210 AUX_RTL command, which + * pulses the rtl message, having the effect of clearing rtl if it was left + * asserted by AUX_RTL2. + */ + AUX_RTL2 = 0x0d, + AUX_RFD_HOLDOFF_ASAP = 0x15, + AUX_REQT = 0x18, + AUX_REQF = 0x19, + AUX_LO_SPEED = 0x40, + AUX_HI_SPEED = 0x41 +}; diff --git a/drivers/staging/gpib/gpio/Makefile b/drivers/staging/gpib/gpio/Makefile new file mode 100644 index 00000000000000..a31ded6e59245e --- /dev/null +++ b/drivers/staging/gpib/gpio/Makefile @@ -0,0 +1,4 @@ + +obj-m += gpib_bitbang.o + + diff --git a/drivers/staging/gpib/gpio/gpib_bitbang.c b/drivers/staging/gpib/gpio/gpib_bitbang.c new file mode 100644 index 00000000000000..a2d562cbd65b43 --- /dev/null +++ b/drivers/staging/gpib/gpio/gpib_bitbang.c @@ -0,0 +1,1476 @@ +// SPDX-License-Identifier: GPL-2.0 + +/************************************************************************* + * This code has been developed at the Institute of Sensor and Actuator * + * Systems (Technical University of Vienna, Austria) to enable the GPIO * + * lines (e.g. of a raspberry pi) to function as a GPIO master device * + * * + * authors : Thomas Klima * + * Marcello Carla' * + * Dave Penkler * + * * + * copyright : (C) 2016 Thomas Klima * + * * + *************************************************************************/ + +/* + * limitations: + * works only on RPi + * cannot function as non-CIC system controller with SN7516x because + * SN75161B cannot simultaneously make ATN input with IFC and REN as + * outputs. + * not implemented: + * parallel poll + * return2local + * device support (non master operation) + */ + +#define NAME KBUILD_MODNAME + +#define ENABLE_IRQ(IRQ, TYPE) irq_set_irq_type(IRQ, TYPE) +#define DISABLE_IRQ(IRQ) irq_set_irq_type(IRQ, IRQ_TYPE_NONE) + +/* Debug print levels: + * 0 = load/unload info and errors that make the driver fail; + * 1 = + warnings for unforeseen events that may break the current + * operation and lead to a timeout, but do not affect the + * driver integrity (mainly unexpected interrupts); + * 2 = + trace of function calls; + * 3 = + trace of protocol codes; + * 4 = + trace of interrupt operation. + */ +#define dbg_printk(level, frm, ...) \ + do { if (debug >= (level)) \ + pr_info("%s:%s - " frm, NAME, __func__, ## __VA_ARGS__); } \ + while (0) + +#define LINVAL gpiod_get_value(DAV), \ + gpiod_get_value(NRFD), \ + gpiod_get_value(NDAC), \ + gpiod_get_value(SRQ) +#define LINFMT "DAV: %d NRFD:%d NDAC: %d SRQ: %d" + +#include "gpibP.h" +#include "gpib_state_machines.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int sn7516x_used = 1, sn7516x; +module_param(sn7516x_used, int, 0660); + +#define PINMAP_0 "elektronomikon" +#define PINMAP_1 "gpib4pi-1.1" +#define PINMAP_2 "yoga" +static char *pin_map = PINMAP_0; +module_param(pin_map, charp, 0660); +MODULE_PARM_DESC(pin_map, " valid values: " PINMAP_0 " " PINMAP_1 " " PINMAP_2); + +/********************************************** + * Signal pairing and pin wiring between the * + * Raspberry-Pi connector and the GPIB bus * + * * + * signal pin wiring * + * GPIB Pi-gpio GPIB -> RPi * + ********************************************** + */ +enum lines_t { + D01_pin_nr = 20, /* 1 -> 38 */ + D02_pin_nr = 26, /* 2 -> 37 */ + D03_pin_nr = 16, /* 3 -> 36 */ + D04_pin_nr = 19, /* 4 -> 35 */ + D05_pin_nr = 13, /* 13 -> 33 */ + D06_pin_nr = 12, /* 14 -> 32 */ + D07_pin_nr = 6, /* 15 -> 31 */ + D08_pin_nr = 5, /* 16 -> 29 */ + EOI_pin_nr = 9, /* 5 -> 21 */ + DAV_pin_nr = 10, /* 6 -> 19 */ + NRFD_pin_nr = 24, /* 7 -> 18 */ + NDAC_pin_nr = 23, /* 8 -> 16 */ + IFC_pin_nr = 22, /* 9 -> 15 */ + SRQ_pin_nr = 11, /* 10 -> 23 */ + _ATN_pin_nr = 25, /* 11 -> 22 */ + REN_pin_nr = 27, /* 17 -> 13 */ +/* + * GROUND PINS + * 12,18,19,20,21,22,23,24 => 14,20,25,30,34,39 + */ + +/* + * These lines are used to control the external + * SN75160/161 driver chips when used. + * When not used there is reduced fan out; + * currently tested with up to 4 devices. + */ + +/* Pi GPIO RPI 75161B 75160B Description */ + PE_pin_nr = 7, /* 26 -> nc 11 Pullup Enable */ + DC_pin_nr = 8, /* 24 -> 12 nc Direction control */ + TE_pin_nr = 18, /* 12 -> 2 1 Talk Enable */ + ACT_LED_pin_nr = 4, /* 7 -> LED */ + +/* YOGA adapter uses different pinout to ease layout */ + YOGA_D03_pin_nr = 13, + YOGA_D04_pin_nr = 12, + YOGA_D05_pin_nr = 21, + YOGA_D06_pin_nr = 19, +}; + +/* + * GPIO descriptors and pins - WARNING: STRICTLY KEEP ITEMS ORDER + */ + +#define GPIB_PINS 16 +#define SN7516X_PINS 4 +#define NUM_PINS (GPIB_PINS + SN7516X_PINS) + +DEFINE_LED_TRIGGER(ledtrig_gpib); +#define ACT_LED_ON do { \ + if (ACT_LED) \ + gpiod_direction_output(ACT_LED, 1); \ + else \ + led_trigger_event(ledtrig_gpib, LED_FULL); } \ + while (0) +#define ACT_LED_OFF do { \ + if (ACT_LED) \ + gpiod_direction_output(ACT_LED, 0); \ + else \ + led_trigger_event(ledtrig_gpib, LED_OFF); } \ + while (0) + +struct gpio_desc *all_descriptors[GPIB_PINS + SN7516X_PINS]; + +#define D01 all_descriptors[0] +#define D02 all_descriptors[1] +#define D03 all_descriptors[2] +#define D04 all_descriptors[3] +#define D05 all_descriptors[4] +#define D06 all_descriptors[5] +#define D07 all_descriptors[6] +#define D08 all_descriptors[7] + +#define EOI all_descriptors[8] +#define NRFD all_descriptors[9] +#define IFC all_descriptors[10] +#define _ATN all_descriptors[11] +#define REN all_descriptors[12] +#define DAV all_descriptors[13] +#define NDAC all_descriptors[14] +#define SRQ all_descriptors[15] + +#define PE all_descriptors[16] +#define DC all_descriptors[17] +#define TE all_descriptors[18] +#define ACT_LED all_descriptors[19] + +/* YOGA dapter uses a global enable for the buffer chips, re-using the TE pin */ +#define YOGA_ENABLE TE + +int gpios_vector[] = { + D01_pin_nr, + D02_pin_nr, + D03_pin_nr, + D04_pin_nr, + D05_pin_nr, + D06_pin_nr, + D07_pin_nr, + D08_pin_nr, + + EOI_pin_nr, + NRFD_pin_nr, + IFC_pin_nr, + _ATN_pin_nr, + REN_pin_nr, + DAV_pin_nr, + NDAC_pin_nr, + SRQ_pin_nr, + + PE_pin_nr, + DC_pin_nr, + TE_pin_nr, + ACT_LED_pin_nr +}; + +/* Lookup table for general GPIOs */ + +static struct gpiod_lookup_table gpib_gpio_table_1 = { + // for bcm2835/6 + .dev_id = "", // device id of board device + .table = { + GPIO_LOOKUP_IDX("GPIO_GCLK", U16_MAX, NULL, 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO5", U16_MAX, NULL, 5, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO6", U16_MAX, NULL, 6, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("SPI_CE1_N", U16_MAX, NULL, 7, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("SPI_CE0_N", U16_MAX, NULL, 8, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("SPI_MISO", U16_MAX, NULL, 9, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("SPI_MOSI", U16_MAX, NULL, 10, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("SPI_SCLK", U16_MAX, NULL, 11, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO12", U16_MAX, NULL, 12, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO13", U16_MAX, NULL, 13, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO16", U16_MAX, NULL, 16, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO17", U16_MAX, NULL, 17, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO18", U16_MAX, NULL, 18, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO19", U16_MAX, NULL, 19, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO20", U16_MAX, NULL, 20, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO21", U16_MAX, NULL, 21, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO22", U16_MAX, NULL, 22, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO23", U16_MAX, NULL, 23, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO24", U16_MAX, NULL, 24, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO25", U16_MAX, NULL, 25, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO26", U16_MAX, NULL, 26, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO27", U16_MAX, NULL, 27, GPIO_ACTIVE_HIGH), + { } + }, +}; + +static struct gpiod_lookup_table gpib_gpio_table_0 = { + .dev_id = "", // device id of board device + .table = { + // for bcm27xx based pis (b b+ 2b 3b 3b+ 4 5) + GPIO_LOOKUP_IDX("GPIO4", U16_MAX, NULL, 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO5", U16_MAX, NULL, 5, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO6", U16_MAX, NULL, 6, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO7", U16_MAX, NULL, 7, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO8", U16_MAX, NULL, 8, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO9", U16_MAX, NULL, 9, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO10", U16_MAX, NULL, 10, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO11", U16_MAX, NULL, 11, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO12", U16_MAX, NULL, 12, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO13", U16_MAX, NULL, 13, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO16", U16_MAX, NULL, 16, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO17", U16_MAX, NULL, 17, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO18", U16_MAX, NULL, 18, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO19", U16_MAX, NULL, 19, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO20", U16_MAX, NULL, 20, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO21", U16_MAX, NULL, 21, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO22", U16_MAX, NULL, 22, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO23", U16_MAX, NULL, 23, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO24", U16_MAX, NULL, 24, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO25", U16_MAX, NULL, 25, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO26", U16_MAX, NULL, 26, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIO27", U16_MAX, NULL, 27, GPIO_ACTIVE_HIGH), + { } + }, +}; + +static struct gpiod_lookup_table *lookup_tables[] = { + &gpib_gpio_table_0, + &gpib_gpio_table_1, + 0 +}; + +/* struct which defines private_data for gpio driver */ + +struct bb_priv { + int irq_NRFD; + int irq_NDAC; + int irq_DAV; + int irq_SRQ; + int dav_mode; /* dav interrupt mode 0/1 -> edge/levels */ + int nrfd_mode; /* nrfd interrupt mode 0/1 -> edge/levels */ + int ndac_mode; /* nrfd interrupt mode 0/1 -> edge/levels */ + int dav_tx; /* keep trace of DAV status while sending */ + int dav_rx; /* keep trace of DAV status while receiving */ + u8 eos; // eos character + short eos_flags; // eos mode + short eos_check; /* eos check required in current operation ... */ + short eos_check_8; /* ... with byte comparison */ + short eos_mask_7; /* ... with 7 bit masked character */ + short int end; + int request; + int count; + int direction; + int t1_delay; + u8 *rbuf; + u8 *wbuf; + int end_flag; + int r_busy; /* 0==idle 1==busy */ + int w_busy; + int write_done; + int cmd; /* 1 = cmd write in progress */ + size_t w_cnt; + size_t length; + u8 *w_buf; + spinlock_t rw_lock; // protect mods to rw_lock + int phase; + int ndac_idle; + int ndac_seq; + int nrfd_idle; + int nrfd_seq; + int dav_seq; + long all_irqs; + int dav_idle; + int atn_asserted; + + enum talker_function_state talker_state; + enum listener_function_state listener_state; +}; + +inline long usec_diff(struct timespec64 *a, struct timespec64 *b); +static void bb_buffer_print(unsigned char *buffer, size_t length, int cmd, int eoi); +static void set_data_lines(u8 byte); +static u8 get_data_lines(void); +static void set_data_lines_input(void); +static void set_data_lines_output(void); +static inline int check_for_eos(struct bb_priv *priv, uint8_t byte); +static void set_atn(struct bb_priv *priv, int atn_asserted); + +static inline void SET_DIR_WRITE(struct bb_priv *priv); +static inline void SET_DIR_READ(struct bb_priv *priv); + +#define DIR_READ 0 +#define DIR_WRITE 1 + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB helper functions for bitbanging I/O"); + +/**** global variables ****/ +#ifdef CONFIG_GPIB_DEBUG +static int debug = 1; +#else +static int debug; +#endif +module_param(debug, int, 0644); + +static char printable(char x) +{ + if (x < 32 || x > 126) + return ' '; + return x; +} + +/*************************************************************************** + * * + * READ * + * * + ***************************************************************************/ + +static int bb_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read) +{ + struct bb_priv *priv = board->private_data; + unsigned long flags; + int retval = 0; + + ACT_LED_ON; + SET_DIR_READ(priv); + + dbg_printk(2, "board: %p lock %d length: %zu\n", + board, mutex_is_locked(&board->user_mutex), length); + + priv->end = 0; + priv->count = 0; + priv->rbuf = buffer; + if (length == 0) + goto read_end; + priv->request = length; + priv->eos_check = (priv->eos_flags & REOS) == 0; /* do eos check */ + priv->eos_check_8 = priv->eos_flags & BIN; /* over 8 bits */ + priv->eos_mask_7 = priv->eos & 0x7f; /* with this 7 bit eos */ + + dbg_printk(3, ".........." LINFMT "\n", LINVAL); + + spin_lock_irqsave(&priv->rw_lock, flags); + priv->dav_mode = 1; + priv->dav_rx = 1; + ENABLE_IRQ(priv->irq_DAV, IRQ_TYPE_LEVEL_LOW); + priv->end_flag = 0; + gpiod_set_value(NRFD, 1); // ready for data + priv->r_busy = 1; + priv->phase = 100; + spin_unlock_irqrestore(&priv->rw_lock, flags); + + /* wait for the interrupt routines finish their work */ + + retval = wait_event_interruptible(board->wait, + (priv->end_flag || board->status & TIMO)); + + dbg_printk(3, "awake from wait queue: %d\n", retval); + + if (retval == 0 && board->status & TIMO) { + retval = -ETIMEDOUT; + dbg_printk(1, "timeout\n"); + } else if (retval) { + retval = -ERESTARTSYS; + } + + DISABLE_IRQ(priv->irq_DAV); + spin_lock_irqsave(&priv->rw_lock, flags); + gpiod_set_value(NRFD, 0); // DIR_READ line state + priv->r_busy = 0; + spin_unlock_irqrestore(&priv->rw_lock, flags); + +read_end: + ACT_LED_OFF; + *bytes_read = priv->count; + *end = priv->end; + priv->r_busy = 0; + dbg_printk(2, "return: %d eoi|eos: %d count: %d\n\n", retval, priv->end, priv->count); + return retval; +} + +/*************************************************************************** + * * + * READ interrupt routine (DAV line) * + * * + ***************************************************************************/ + +static irqreturn_t bb_DAV_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + struct bb_priv *priv = board->private_data; + int val; + unsigned long flags; + + spin_lock_irqsave(&priv->rw_lock, flags); + + priv->all_irqs++; + + if (priv->dav_mode) { + ENABLE_IRQ(priv->irq_DAV, IRQ_TYPE_EDGE_BOTH); + priv->dav_mode = 0; + } + + if (priv->r_busy == 0) { + dbg_printk(1, "interrupt while idle after %d at %d\n", + priv->count, priv->phase); + priv->dav_idle++; + priv->phase = 200; + goto dav_exit; /* idle */ + } + + val = gpiod_get_value(DAV); + if (val == priv->dav_rx) { + dbg_printk(1, "out of order DAV interrupt %d/%d after %zu/%zu at %d cmd %d " + LINFMT ".\n", val, priv->dav_rx, priv->w_cnt, priv->length, + priv->phase, priv->cmd, LINVAL); + priv->dav_seq++; + } + priv->dav_rx = val; + + dbg_printk(3, "> irq: %d DAV: %d st: %4lx dir: %d busy: %d:%d\n", + irq, val, board->status, priv->direction, priv->r_busy, priv->w_busy); + + if (val == 0) { + gpiod_set_value(NRFD, 0); // not ready for data + priv->rbuf[priv->count++] = get_data_lines(); + priv->end = !gpiod_get_value(EOI); + gpiod_set_value(NDAC, 1); // data accepted + priv->end |= check_for_eos(priv, priv->rbuf[priv->count - 1]); + priv->end_flag = ((priv->count >= priv->request) || priv->end); + priv->phase = 210; + } else { + gpiod_set_value(NDAC, 0); // data not accepted + if (priv->end_flag) { + priv->r_busy = 0; + wake_up_interruptible(&board->wait); + priv->phase = 220; + } else { + gpiod_set_value(NRFD, 1); // ready for data + priv->phase = 230; + } + } + +dav_exit: + spin_unlock_irqrestore(&priv->rw_lock, flags); + dbg_printk(3, "< irq: %d count %d\n", irq, priv->count); + return IRQ_HANDLED; +} + +/*************************************************************************** + * * + * WRITE * + * * + ***************************************************************************/ + +static int bb_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + unsigned long flags; + int retval = 0; + + struct bb_priv *priv = board->private_data; + + ACT_LED_ON; + + priv->w_cnt = 0; + priv->w_buf = buffer; + dbg_printk(2, "board %p lock %d length: %zu\n", + board, mutex_is_locked(&board->user_mutex), length); + + if (debug > 1) + bb_buffer_print(buffer, length, priv->cmd, send_eoi); + priv->count = 0; + priv->phase = 300; + + if (length == 0) + goto write_end; + priv->end = send_eoi; + priv->length = length; + + SET_DIR_WRITE(priv); + + dbg_printk(2, "Enabling interrupts - NRFD: %d NDAC: %d\n", + gpiod_get_value(NRFD), gpiod_get_value(NDAC)); + + if (gpiod_get_value(NRFD) && gpiod_get_value(NDAC)) { /* check for listener */ + retval = -ENODEV; + goto write_end; + } + + spin_lock_irqsave(&priv->rw_lock, flags); + priv->w_busy = 1; /* make the interrupt routines active */ + priv->write_done = 0; + priv->nrfd_mode = 1; + priv->ndac_mode = 1; + priv->dav_tx = 1; + ENABLE_IRQ(priv->irq_NDAC, IRQ_TYPE_LEVEL_HIGH); + ENABLE_IRQ(priv->irq_NRFD, IRQ_TYPE_LEVEL_HIGH); + spin_unlock_irqrestore(&priv->rw_lock, flags); + + /* wait for the interrupt routines finish their work */ + + retval = wait_event_interruptible(board->wait, + priv->write_done || (board->status & TIMO)); + + dbg_printk(3, "awake from wait queue: %d\n", retval); + + if (retval == 0) { + if (board->status & TIMO) { + retval = -ETIMEDOUT; + dbg_printk(1, "timeout after %zu/%zu at %d " LINFMT " eoi: %d\n", + priv->w_cnt, length, priv->phase, LINVAL, send_eoi); + } else { + // dbg_printk(1,"written %zu\n", priv->w_cnt); + retval = priv->w_cnt; + } + } else { + retval = -ERESTARTSYS; + } + + DISABLE_IRQ(priv->irq_NRFD); + DISABLE_IRQ(priv->irq_NDAC); + + spin_lock_irqsave(&priv->rw_lock, flags); + priv->w_busy = 0; + gpiod_set_value(DAV, 1); // DIR_WRITE line state + gpiod_set_value(EOI, 1); // De-assert EOI (in case) + spin_unlock_irqrestore(&priv->rw_lock, flags); + +write_end: + *bytes_written = priv->w_cnt; + ACT_LED_OFF; + dbg_printk(2, "sent %zu bytes\r\n\r\n", *bytes_written); + priv->phase = 310; + return retval; +} + +/*************************************************************************** + * * + * WRITE interrupt routine (NRFD line) * + * * + ***************************************************************************/ + +static irqreturn_t bb_NRFD_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + struct bb_priv *priv = board->private_data; + unsigned long flags; + int nrfd; + + spin_lock_irqsave(&priv->rw_lock, flags); + + nrfd = gpiod_get_value(NRFD); + priv->all_irqs++; + + dbg_printk(3, "> irq: %d NRFD: %d NDAC: %d st: %4lx dir: %d busy: %d:%d\n", + irq, nrfd, gpiod_get_value(NDAC), board->status, priv->direction, + priv->w_busy, priv->r_busy); + + if (priv->nrfd_mode) { + ENABLE_IRQ(priv->irq_NRFD, IRQ_TYPE_EDGE_RISING); + priv->nrfd_mode = 0; + } + + if (priv->w_busy == 0) { + dbg_printk(1, "interrupt while idle after %zu/%zu at %d\n", + priv->w_cnt, priv->length, priv->phase); + priv->nrfd_idle++; + goto nrfd_exit; /* idle */ + } + if (nrfd == 0) { + dbg_printk(1, "out of order interrupt after %zu/%zu at %d cmd %d " LINFMT ".\n", + priv->w_cnt, priv->length, priv->phase, priv->cmd, LINVAL); + priv->phase = 400; + priv->nrfd_seq++; + goto nrfd_exit; + } + if (!priv->dav_tx) { + dbg_printk(1, "DAV low after %zu/%zu cmd %d " LINFMT ". No action.\n", + priv->w_cnt, priv->length, priv->cmd, LINVAL); + priv->dav_seq++; + goto nrfd_exit; + } + + if (priv->atn_asserted && priv->w_cnt >= priv->length) { // test for end of transfer + priv->write_done = 1; + priv->w_busy = 0; + wake_up_interruptible(&board->wait); + goto nrfd_exit; + } + + dbg_printk(3, "sending %zu\n", priv->w_cnt); + + set_data_lines(priv->w_buf[priv->w_cnt++]); // put the data on the lines + + if (priv->w_cnt == priv->length && priv->end) { + dbg_printk(3, "Asserting EOI\n"); + gpiod_set_value(EOI, 0); // Assert EOI + } + + gpiod_set_value(DAV, 0); // Data available + priv->dav_tx = 0; + priv->phase = 410; + +nrfd_exit: + spin_unlock_irqrestore(&priv->rw_lock, flags); + + return IRQ_HANDLED; +} + +/*************************************************************************** + * * + * WRITE interrupt routine (NDAC line) * + * * + ***************************************************************************/ + +static irqreturn_t bb_NDAC_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + struct bb_priv *priv = board->private_data; + unsigned long flags; + int ndac; + + spin_lock_irqsave(&priv->rw_lock, flags); + + ndac = gpiod_get_value(NDAC); + priv->all_irqs++; + dbg_printk(3, "> irq: %d NRFD: %d NDAC: %d st: %4lx dir: %d busy: %d:%d\n", + irq, gpiod_get_value(NRFD), ndac, board->status, priv->direction, + priv->w_busy, priv->r_busy); + + if (priv->ndac_mode) { + ENABLE_IRQ(priv->irq_NDAC, IRQ_TYPE_EDGE_RISING); + priv->ndac_mode = 0; + } + + if (priv->w_busy == 0) { + dbg_printk(1, "interrupt while idle.\n"); + priv->ndac_idle++; + goto ndac_exit; + } + if (ndac == 0) { + dbg_printk(1, "out of order interrupt at %zu:%d.\n", priv->w_cnt, priv->phase); + priv->phase = 500; + priv->ndac_seq++; + goto ndac_exit; + } + if (priv->dav_tx) { + dbg_printk(1, "DAV high after %zu/%zu cmd %d " LINFMT ". No action.\n", + priv->w_cnt, priv->length, priv->cmd, LINVAL); + priv->dav_seq++; + goto ndac_exit; + } + + dbg_printk(3, "accepted %zu\n", priv->w_cnt - 1); + + if (!priv->atn_asserted && priv->w_cnt >= priv->length) { // test for end of transfer + priv->write_done = 1; + priv->w_busy = 0; + wake_up_interruptible(&board->wait); + } else { + gpiod_set_value(DAV, 1); // Data not available + priv->dav_tx = 1; + priv->phase = 510; + } + +ndac_exit: + spin_unlock_irqrestore(&priv->rw_lock, flags); + return IRQ_HANDLED; +} + +/*************************************************************************** + * * + * interrupt routine for SRQ line * + * * + ***************************************************************************/ + +static irqreturn_t bb_SRQ_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + + int val = gpiod_get_value(SRQ); + + dbg_printk(3, "> %d st: %4lx\n", val, board->status); + + if (!val) + set_bit(SRQI_NUM, &board->status); /* set_bit() is atomic */ + + wake_up_interruptible(&board->wait); + + return IRQ_HANDLED; +} + +static int bb_command(gpib_board_t *board, uint8_t *buffer, + size_t length, size_t *bytes_written) +{ + size_t ret; + struct bb_priv *priv = board->private_data; + int i; + + dbg_printk(2, "%p %p\n", buffer, board->buffer); + + /* the _ATN line has already been asserted by bb_take_control() */ + + priv->cmd = 1; + + ret = bb_write(board, buffer, length, 0, bytes_written); // no eoi + + for (i = 0; i < length; i++) { + if (buffer[i] == UNT) { + priv->talker_state = talker_idle; + } else { + if (buffer[i] == UNL) { + priv->listener_state = listener_idle; + } else { + if (buffer[i] == (MTA(board->pad))) { + priv->talker_state = talker_addressed; + priv->listener_state = listener_idle; + } else if (buffer[i] == (MLA(board->pad))) { + priv->listener_state = listener_addressed; + priv->talker_state = talker_idle; + } + } + } + } + + /* the _ATN line will be released by bb_go_to_stby */ + + priv->cmd = 0; + + return ret; +} + +/*************************************************************************** + * * + * Buffer print with decode for debug/trace * + * * + ***************************************************************************/ + +static char *cmd_string[32] = { + "", // 0x00 + "GTL", // 0x01 + "", // 0x02 + "", // 0x03 + "SDC", // 0x04 + "PPC", // 0x05 + "", // 0x06 + "", // 0x07 + "GET", // 0x08 + "TCT", // 0x09 + "", // 0x0a + "", // 0x0b + "", // 0x0c + "", // 0x0d + "", // 0x0e + "", // 0x0f + "", // 0x10 + "LLO", // 0x11 + "", // 0x12 + "", // 0x13 + "DCL", // 0x14 + "PPU", // 0x15 + "", // 0x16 + "", // 0x17 + "SPE", // 0x18 + "SPD", // 0x19 + "", // 0x1a + "", // 0x1b + "", // 0x1c + "", // 0x1d + "", // 0x1e + "CFE" // 0x1f +}; + +static void bb_buffer_print(unsigned char *buffer, size_t length, int cmd, int eoi) +{ + int i; + + if (cmd) { + dbg_printk(2, "\n", length); + for (i = 0; i < length; i++) { + if (buffer[i] < 0x20) { + dbg_printk(3, "0x%x=%s\n", buffer[i], cmd_string[buffer[i]]); + } else if (buffer[i] == 0x3f) { + dbg_printk(3, "0x%x=%s\n", buffer[i], "UNL"); + } else if (buffer[i] == 0x5f) { + dbg_printk(3, "0x%x=%s\n", buffer[i], "UNT"); + } else if (buffer[i] < 0x60) { + dbg_printk(3, "0x%x=%s%d\n", buffer[i], + (buffer[i] & 0x40) ? "TLK" : "LSN", buffer[i] & 0x1F); + } else { + dbg_printk(3, "0x%x\n", buffer[i]); + } + } + } else { + dbg_printk(2, "\n", length, (eoi) ? "w.EOI" : " "); + for (i = 0; i < length; i++) + dbg_printk(2, "%3d 0x%x->%c\n", i, buffer[i], printable(buffer[i])); + } +} + +/*************************************************************************** + * * + * STATUS Management * + * * + ***************************************************************************/ +static void set_atn(struct bb_priv *priv, int atn_asserted) +{ + if (priv->listener_state != listener_idle && + priv->talker_state != talker_idle) { + dbg_printk(0, "listener/talker state machine conflict\n"); + } + if (atn_asserted) { + if (priv->listener_state == listener_active) + priv->listener_state = listener_addressed; + if (priv->talker_state == talker_active) + priv->talker_state = talker_addressed; + } else { + if (priv->listener_state == listener_addressed) { + priv->listener_state = listener_active; + SET_DIR_READ(priv); // make sure holdoff is active when we unassert ATN + } + if (priv->talker_state == talker_addressed) + priv->talker_state = talker_active; + } + gpiod_direction_output(_ATN, !atn_asserted); + priv->atn_asserted = atn_asserted; +} + +static int bb_take_control(gpib_board_t *board, int synchronous) +{ + dbg_printk(2, "%d\n", synchronous); + set_atn(board->private_data, 1); + set_bit(CIC_NUM, &board->status); + return 0; +} + +static int bb_go_to_standby(gpib_board_t *board) +{ + dbg_printk(2, "\n"); + set_atn(board->private_data, 0); + return 0; +} + +static void bb_request_system_control(gpib_board_t *board, int request_control) +{ + dbg_printk(2, "%d\n", request_control); + if (request_control) { + set_bit(CIC_NUM, &board->status); + // drive DAV & EOI false, enable NRFD & NDAC irqs + SET_DIR_WRITE(board->private_data); + } else { + clear_bit(CIC_NUM, &board->status); + } +} + +static void bb_interface_clear(gpib_board_t *board, int assert) +{ + struct bb_priv *priv = board->private_data; + + dbg_printk(2, "%d\n", assert); + if (assert) { + gpiod_direction_output(IFC, 0); + priv->talker_state = talker_idle; + priv->listener_state = listener_idle; + } else { + gpiod_direction_output(IFC, 1); + } +} + +static void bb_remote_enable(gpib_board_t *board, int enable) +{ + dbg_printk(2, "%d\n", enable); + if (enable) { + set_bit(REM_NUM, &board->status); + gpiod_direction_output(REN, 0); + } else { + clear_bit(REM_NUM, &board->status); + gpiod_direction_output(REN, 1); + } +} + +static int bb_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct bb_priv *priv = board->private_data; + + dbg_printk(2, "%s\n", "EOS_en"); + priv->eos = eos_byte; + priv->eos_flags = REOS; + if (compare_8_bits) + priv->eos_flags |= BIN; + + return 0; +} + +static void bb_disable_eos(gpib_board_t *board) +{ + struct bb_priv *priv = board->private_data; + + dbg_printk(2, "\n"); + priv->eos_flags &= ~REOS; +} + +static unsigned int bb_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct bb_priv *priv = board->private_data; + + board->status &= ~clear_mask; + + if (gpiod_get_value(SRQ)) /* SRQ asserted low */ + clear_bit(SRQI_NUM, &board->status); + else + set_bit(SRQI_NUM, &board->status); + if (gpiod_get_value(_ATN)) /* ATN asserted low */ + clear_bit(ATN_NUM, &board->status); + else + set_bit(ATN_NUM, &board->status); + if (priv->talker_state == talker_active || + priv->talker_state == talker_addressed) + set_bit(TACS_NUM, &board->status); + else + clear_bit(TACS_NUM, &board->status); + + if (priv->listener_state == listener_active || + priv->listener_state == listener_addressed) + set_bit(LACS_NUM, &board->status); + else + clear_bit(LACS_NUM, &board->status); + + dbg_printk(2, "0x%lx mask 0x%x\n", board->status, clear_mask); + + return board->status; +} + +static int bb_primary_address(gpib_board_t *board, unsigned int address) +{ + dbg_printk(2, "%d\n", address); + board->pad = address; + return 0; +} + +static int bb_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + dbg_printk(2, "%d %d\n", address, enable); + if (enable) + board->sad = address; + return 0; +} + +static int bb_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + dbg_printk(1, "%s\n", "not implemented"); + return -EPERM; +} + +static void bb_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + dbg_printk(1, "%s\n", "not implemented"); +} + +static void bb_parallel_poll_response(gpib_board_t *board, int ist) +{ +} + +static void bb_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + dbg_printk(1, "%s\n", "not implemented"); +} + +static uint8_t bb_serial_poll_status(gpib_board_t *board) +{ + dbg_printk(1, "%s\n", "not implemented"); + return 0; // -ENOSYS; +} + +static unsigned int bb_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct bb_priv *priv = board->private_data; + + if (nano_sec <= 350) + priv->t1_delay = 350; + else if (nano_sec <= 1100) + priv->t1_delay = 1100; + else + priv->t1_delay = 2000; + + dbg_printk(2, "t1 delay set to %d nanosec\n", priv->t1_delay); + + return priv->t1_delay; +} + +static void bb_return_to_local(gpib_board_t *board) +{ + dbg_printk(1, "%s\n", "not implemented"); +} + +static int bb_line_status(const gpib_board_t *board) +{ + int line_status = ValidALL; + +// dbg_printk(1,"\n"); + + if (gpiod_get_value(REN) == 0) + line_status |= BusREN; + if (gpiod_get_value(IFC) == 0) + line_status |= BusIFC; + if (gpiod_get_value(NDAC) == 0) + line_status |= BusNDAC; + if (gpiod_get_value(NRFD) == 0) + line_status |= BusNRFD; + if (gpiod_get_value(DAV) == 0) + line_status |= BusDAV; + if (gpiod_get_value(EOI) == 0) + line_status |= BusEOI; + if (gpiod_get_value(_ATN) == 0) + line_status |= BusATN; + if (gpiod_get_value(SRQ) == 0) + line_status |= BusSRQ; + + dbg_printk(2, "status lines: %4x\n", line_status); + + return line_status; +} + +/*************************************************************************** + * * + * Module Management * + * * + ***************************************************************************/ + +static int allocate_private(gpib_board_t *board) +{ + board->private_data = kzalloc(sizeof(struct bb_priv), GFP_KERNEL); + if (!board->private_data) + return -1; + return 0; +} + +static void free_private(gpib_board_t *board) +{ + kfree(board->private_data); + board->private_data = NULL; +} + +static int bb_get_irq(gpib_board_t *board, char *name, + struct gpio_desc *gpio, int *irq, + irq_handler_t handler, irq_handler_t thread_fn, unsigned long flags) +{ + if (!gpio) + return -1; + gpiod_direction_input(gpio); + *irq = gpiod_to_irq(gpio); + dbg_printk(2, "IRQ %s: %d\n", name, *irq); + if (*irq < 0) { + dbg_printk(0, "gpib: can't get IRQ for %s\n", name); + return -1; + } + if (request_threaded_irq(*irq, handler, thread_fn, flags, name, board)) { + dbg_printk(0, "gpib: can't request IRQ for %s %d\n", name, *irq); + *irq = 0; + return -1; + } + DISABLE_IRQ(*irq); + return 0; +} + +static void bb_free_irq(gpib_board_t *board, int *irq, char *name) +{ + if (*irq) { + free_irq(*irq, board); + dbg_printk(2, "IRQ %d(%s) freed\n", *irq, name); + *irq = 0; + } +} + +static void release_gpios(void) +{ + int j; + + for (j = 0 ; j < NUM_PINS ; j++) { + if (all_descriptors[j]) { + gpiod_put(all_descriptors[j]); + all_descriptors[j] = 0; + } + } +} + +static int allocate_gpios(gpib_board_t *board) +{ + int j, retval = 0; + bool error = false; + int table_index = 0; + char name[256]; + struct gpio_desc *desc; + struct gpiod_lookup_table *lookup_table; + + if (!board->gpib_dev) { + pr_err("NULL gpib dev for board\n"); + return -ENOENT; + } + + lookup_table = lookup_tables[0]; + lookup_table->dev_id = dev_name(board->gpib_dev); + gpiod_add_lookup_table(lookup_table); + dbg_printk(1, "Allocating gpios using table index %d\n", table_index); + + for (j = 0 ; j < NUM_PINS ; j++) { + if (gpios_vector[j] < 0) + continue; + /* name not really used in gpiod_get_index() */ + sprintf(name, "GPIO%d", gpios_vector[j]); +try_again: + dbg_printk(1, "Allocating gpio %s pin no %d\n", name, gpios_vector[j]); + desc = gpiod_get_index(board->gpib_dev, name, gpios_vector[j], GPIOD_IN); + + if (IS_ERR(desc)) { + gpiod_remove_lookup_table(lookup_table); + table_index++; + lookup_table = lookup_tables[table_index]; + if (lookup_table) { + dbg_printk(1, "Allocation failed, now using table_index %d\n", + table_index); + lookup_table->dev_id = dev_name(board->gpib_dev); + gpiod_add_lookup_table(lookup_table); + goto try_again; + } + dbg_printk(0, "Unable to obtain gpio descriptor for pin %d error %ld\n", + gpios_vector[j], PTR_ERR(desc)); + error = true; + break; + } + all_descriptors[j] = desc; + } + + if (error) { /* undo what already done */ + release_gpios(); + retval = -1; + } + if (lookup_table) + gpiod_remove_lookup_table(lookup_table); + // Initialize LED trigger + led_trigger_register_simple("gpib", &ledtrig_gpib); + return retval; +} + +static void bb_detach(gpib_board_t *board) +{ + struct bb_priv *priv = board->private_data; + + dbg_printk(2, "Enter with data %p\n", board->private_data); + if (!board->private_data) + return; + + led_trigger_unregister_simple(ledtrig_gpib); + + bb_free_irq(board, &priv->irq_DAV, NAME "_DAV"); + bb_free_irq(board, &priv->irq_NRFD, NAME "_NRFD"); + bb_free_irq(board, &priv->irq_NDAC, NAME "_NDAC"); + bb_free_irq(board, &priv->irq_SRQ, NAME "_SRQ"); + + if (strcmp(PINMAP_2, pin_map) == 0) { /* YOGA */ + gpiod_set_value(YOGA_ENABLE, 0); + } + + release_gpios(); + + dbg_printk(2, "detached board: %d\n", board->minor); + dbg_printk(0, "NRFD: idle %d, seq %d, NDAC: idle %d, seq %d DAV: idle %d seq: %d all: %ld", + priv->nrfd_idle, priv->nrfd_seq, + priv->ndac_idle, priv->ndac_seq, + priv->dav_idle, priv->dav_seq, priv->all_irqs); + + free_private(board); +} + +static int bb_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct bb_priv *priv; + int retval = 0; + + dbg_printk(2, "%s\n", "Enter ..."); + + board->status = 0; + + if (allocate_private(board)) + return -ENOMEM; + priv = board->private_data; + priv->direction = -1; + priv->t1_delay = 2000; + priv->listener_state = listener_idle; + priv->talker_state = talker_idle; + + sn7516x = sn7516x_used; + if (strcmp(PINMAP_0, pin_map) == 0) { + if (!sn7516x) { + gpios_vector[&(PE) - &all_descriptors[0]] = -1; + gpios_vector[&(DC) - &all_descriptors[0]] = -1; + gpios_vector[&(TE) - &all_descriptors[0]] = -1; + } + } else if (strcmp(PINMAP_1, pin_map) == 0) { + if (!sn7516x) { + gpios_vector[&(PE) - &all_descriptors[0]] = -1; + gpios_vector[&(DC) - &all_descriptors[0]] = -1; + gpios_vector[&(TE) - &all_descriptors[0]] = -1; + } + gpios_vector[&(REN) - &all_descriptors[0]] = 0; /* 27 -> 0 REN on GPIB pin 0 */ + } else if (strcmp(PINMAP_2, pin_map) == 0) { /* YOGA */ + sn7516x = 0; + gpios_vector[&(D03) - &all_descriptors[0]] = YOGA_D03_pin_nr; + gpios_vector[&(D04) - &all_descriptors[0]] = YOGA_D04_pin_nr; + gpios_vector[&(D05) - &all_descriptors[0]] = YOGA_D05_pin_nr; + gpios_vector[&(D06) - &all_descriptors[0]] = YOGA_D06_pin_nr; + gpios_vector[&(PE) - &all_descriptors[0]] = -1; + gpios_vector[&(DC) - &all_descriptors[0]] = -1; + gpios_vector[&(ACT_LED) - &all_descriptors[0]] = -1; + } else { + dbg_printk(0, "Unrecognized pin mapping.\n"); + goto bb_attach_fail; + } + dbg_printk(0, "Using pin map \"%s\" %s\n", pin_map, (sn7516x) ? + " with SN7516x driver support" : ""); + + if (allocate_gpios(board)) + goto bb_attach_fail; + +/* Configure SN7516X control lines. + * drive ATN, IFC and REN as outputs only when master + * i.e. system controller. In this mode can only be the CIC + * When not master then enable device mode ATN, IFC & REN as inputs + */ + if (sn7516x) { + gpiod_direction_output(DC, 0); + gpiod_direction_output(TE, 1); + gpiod_direction_output(PE, 1); + } + + if (strcmp(PINMAP_2, pin_map) == 0) { /* YOGA: enable level shifters */ + gpiod_direction_output(YOGA_ENABLE, 1); + } + + spin_lock_init(&priv->rw_lock); + + /* request DAV interrupt for read */ + if (bb_get_irq(board, NAME "_DAV", DAV, &priv->irq_DAV, bb_DAV_interrupt, NULL, + IRQF_TRIGGER_NONE)) + goto bb_attach_fail_r; + + /* request NRFD interrupt for write */ + if (bb_get_irq(board, NAME "_NRFD", NRFD, &priv->irq_NRFD, bb_NRFD_interrupt, NULL, + IRQF_TRIGGER_NONE)) + goto bb_attach_fail_r; + + /* request NDAC interrupt for write */ + if (bb_get_irq(board, NAME "_NDAC", NDAC, &priv->irq_NDAC, bb_NDAC_interrupt, NULL, + IRQF_TRIGGER_NONE)) + goto bb_attach_fail_r; + + /* request SRQ interrupt for Service Request */ + if (bb_get_irq(board, NAME "_SRQ", SRQ, &priv->irq_SRQ, bb_SRQ_interrupt, NULL, + IRQF_TRIGGER_NONE)) + goto bb_attach_fail_r; + + ENABLE_IRQ(priv->irq_SRQ, IRQ_TYPE_EDGE_FALLING); + + dbg_printk(0, "attached board %d\n", board->minor); + goto bb_attach_out; + +bb_attach_fail_r: + release_gpios(); +bb_attach_fail: + retval = -1; +bb_attach_out: + return retval; +} + +gpib_interface_t bb_interface = { +name: NAME, +attach : bb_attach, +detach : bb_detach, +read : bb_read, +write : bb_write, +command : bb_command, +take_control : bb_take_control, +go_to_standby : bb_go_to_standby, +request_system_control : bb_request_system_control, +interface_clear : bb_interface_clear, +remote_enable : bb_remote_enable, +enable_eos : bb_enable_eos, +disable_eos : bb_disable_eos, +parallel_poll : bb_parallel_poll, +parallel_poll_configure : bb_parallel_poll_configure, +parallel_poll_response : bb_parallel_poll_response, +line_status : bb_line_status, +update_status : bb_update_status, +primary_address : bb_primary_address, +secondary_address : bb_secondary_address, +serial_poll_response : bb_serial_poll_response, +serial_poll_status : bb_serial_poll_status, +t1_delay : bb_t1_delay, +return_to_local : bb_return_to_local, +}; + +static int __init bb_init_module(void) +{ + gpib_register_driver(&bb_interface, THIS_MODULE); + + dbg_printk(0, "module loaded with pin map \"%s\"%s\n", + pin_map, (sn7516x_used) ? " and SN7516x driver support" : ""); + return 0; +} + +static void __exit bb_exit_module(void) +{ + dbg_printk(0, "module unloaded!"); + + gpib_unregister_driver(&bb_interface); +} + +module_init(bb_init_module); +module_exit(bb_exit_module); + +/*************************************************************************** + * * + * UTILITY Functions * + * * + ***************************************************************************/ +inline long usec_diff(struct timespec64 *a, struct timespec64 *b) +{ + return ((a->tv_sec - b->tv_sec) * 1000000 + + (a->tv_nsec - b->tv_nsec) / 1000); +} + +static inline int check_for_eos(struct bb_priv *priv, uint8_t byte) +{ + if (priv->eos_check) + return 0; + + if (priv->eos_check_8) { + if (priv->eos == byte) + return 1; + } else { + if (priv->eos_mask_7 == (byte & 0x7f)) + return 1; + } + return 0; +} + +static void set_data_lines_output(void) +{ + gpiod_direction_output(D01, 1); + gpiod_direction_output(D02, 1); + gpiod_direction_output(D03, 1); + gpiod_direction_output(D04, 1); + gpiod_direction_output(D05, 1); + gpiod_direction_output(D06, 1); + gpiod_direction_output(D07, 1); + gpiod_direction_output(D08, 1); +} + +static void set_data_lines(u8 byte) +{ + gpiod_set_value(D01, !(byte & 0x01)); + gpiod_set_value(D02, !(byte & 0x02)); + gpiod_set_value(D03, !(byte & 0x04)); + gpiod_set_value(D04, !(byte & 0x08)); + gpiod_set_value(D05, !(byte & 0x10)); + gpiod_set_value(D06, !(byte & 0x20)); + gpiod_set_value(D07, !(byte & 0x40)); + gpiod_set_value(D08, !(byte & 0x80)); +} + +static u8 get_data_lines(void) +{ + u8 ret; + + ret = gpiod_get_value(D01); + ret |= gpiod_get_value(D02) << 1; + ret |= gpiod_get_value(D03) << 2; + ret |= gpiod_get_value(D04) << 3; + ret |= gpiod_get_value(D05) << 4; + ret |= gpiod_get_value(D06) << 5; + ret |= gpiod_get_value(D07) << 6; + ret |= gpiod_get_value(D08) << 7; + return ~ret; +} + +static void set_data_lines_input(void) +{ + gpiod_direction_input(D01); + gpiod_direction_input(D02); + gpiod_direction_input(D03); + gpiod_direction_input(D04); + gpiod_direction_input(D05); + gpiod_direction_input(D06); + gpiod_direction_input(D07); + gpiod_direction_input(D08); +} + +static inline void SET_DIR_WRITE(struct bb_priv *priv) +{ + if (priv->direction == DIR_WRITE) + return; + + gpiod_direction_input(NRFD); + gpiod_direction_input(NDAC); + set_data_lines_output(); + gpiod_direction_output(DAV, 1); + gpiod_direction_output(EOI, 1); + + if (sn7516x) { + gpiod_set_value(PE, 1); /* set data lines to transmit on sn75160b */ + gpiod_set_value(TE, 1); /* set NDAC and NRFD to receive and DAV to transmit */ + } + + priv->direction = DIR_WRITE; +} + +static inline void SET_DIR_READ(struct bb_priv *priv) +{ + if (priv->direction == DIR_READ) + return; + + gpiod_direction_input(DAV); + gpiod_direction_input(EOI); + + set_data_lines_input(); + + if (sn7516x) { + gpiod_set_value(PE, 0); /* set data lines to receive on sn75160b */ + gpiod_set_value(TE, 0); /* set NDAC and NRFD to transmit and DAV to receive */ + } + + gpiod_direction_output(NRFD, 0); // hold off the talker + gpiod_direction_output(NDAC, 0); // data not accepted + + priv->direction = DIR_READ; +} diff --git a/drivers/staging/gpib/hp_82335/Makefile b/drivers/staging/gpib/hp_82335/Makefile new file mode 100644 index 00000000000000..8b7a552e935566 --- /dev/null +++ b/drivers/staging/gpib/hp_82335/Makefile @@ -0,0 +1,4 @@ + +obj-m += hp82335.o + + diff --git a/drivers/staging/gpib/hp_82335/hp82335.c b/drivers/staging/gpib/hp_82335/hp82335.c new file mode 100644 index 00000000000000..40afe42aea4788 --- /dev/null +++ b/drivers/staging/gpib/hp_82335/hp82335.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess * + ***************************************************************************/ + +/*should enable ATN interrupts (and update board->status on occurrence), + * implement recovery from bus errors (if necessary) + */ + +#include "hp82335.h" +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for HP 82335 interface cards"); + +static int hp82335_attach(gpib_board_t *board, const gpib_board_config_t *config); + +static void hp82335_detach(gpib_board_t *board); + +// wrappers for interface functions +int hp82335_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read); +} + +int hp82335_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written); +} + +int hp82335_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_command(board, &priv->tms9914_priv, buffer, length, bytes_written); +} + +int hp82335_take_control(gpib_board_t *board, int synchronous) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_take_control(board, &priv->tms9914_priv, synchronous); +} + +int hp82335_go_to_standby(gpib_board_t *board) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_go_to_standby(board, &priv->tms9914_priv); +} + +void hp82335_request_system_control(gpib_board_t *board, int request_control) +{ + struct hp82335_priv *priv = board->private_data; + + tms9914_request_system_control(board, &priv->tms9914_priv, request_control); +} + +void hp82335_interface_clear(gpib_board_t *board, int assert) +{ + struct hp82335_priv *priv = board->private_data; + + tms9914_interface_clear(board, &priv->tms9914_priv, assert); +} + +void hp82335_remote_enable(gpib_board_t *board, int enable) +{ + struct hp82335_priv *priv = board->private_data; + + tms9914_remote_enable(board, &priv->tms9914_priv, enable); +} + +int hp82335_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_enable_eos(board, &priv->tms9914_priv, eos_byte, compare_8_bits); +} + +void hp82335_disable_eos(gpib_board_t *board) +{ + struct hp82335_priv *priv = board->private_data; + + tms9914_disable_eos(board, &priv->tms9914_priv); +} + +unsigned int hp82335_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_update_status(board, &priv->tms9914_priv, clear_mask); +} + +int hp82335_primary_address(gpib_board_t *board, unsigned int address) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_primary_address(board, &priv->tms9914_priv, address); +} + +int hp82335_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable); +} + +int hp82335_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_parallel_poll(board, &priv->tms9914_priv, result); +} + +void hp82335_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + struct hp82335_priv *priv = board->private_data; + + tms9914_parallel_poll_configure(board, &priv->tms9914_priv, config); +} + +void hp82335_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct hp82335_priv *priv = board->private_data; + + tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist); +} + +void hp82335_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + struct hp82335_priv *priv = board->private_data; + + tms9914_serial_poll_response(board, &priv->tms9914_priv, status); +} + +static uint8_t hp82335_serial_poll_status(gpib_board_t *board) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_serial_poll_status(board, &priv->tms9914_priv); +} + +static int hp82335_line_status(const gpib_board_t *board) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_line_status(board, &priv->tms9914_priv); +} + +static unsigned int hp82335_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct hp82335_priv *priv = board->private_data; + + return tms9914_t1_delay(board, &priv->tms9914_priv, nano_sec); +} + +void hp82335_return_to_local(gpib_board_t *board) +{ + struct hp82335_priv *priv = board->private_data; + + tms9914_return_to_local(board, &priv->tms9914_priv); +} + +gpib_interface_t hp82335_interface = { +name: "hp82335", +attach : hp82335_attach, +detach : hp82335_detach, +read : hp82335_read, +write : hp82335_write, +command : hp82335_command, +request_system_control : hp82335_request_system_control, +take_control : hp82335_take_control, +go_to_standby : hp82335_go_to_standby, +interface_clear : hp82335_interface_clear, +remote_enable : hp82335_remote_enable, +enable_eos : hp82335_enable_eos, +disable_eos : hp82335_disable_eos, +parallel_poll : hp82335_parallel_poll, +parallel_poll_configure : hp82335_parallel_poll_configure, +parallel_poll_response : hp82335_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : hp82335_line_status, +update_status : hp82335_update_status, +primary_address : hp82335_primary_address, +secondary_address : hp82335_secondary_address, +serial_poll_response : hp82335_serial_poll_response, +serial_poll_status : hp82335_serial_poll_status, +t1_delay : hp82335_t1_delay, +return_to_local : hp82335_return_to_local, +}; + +int hp82335_allocate_private(gpib_board_t *board) +{ + board->private_data = kzalloc(sizeof(struct hp82335_priv), GFP_KERNEL); + if (!board->private_data) + return -1; + return 0; +} + +void hp82335_free_private(gpib_board_t *board) +{ + kfree(board->private_data); + board->private_data = NULL; +} + +static inline unsigned int tms9914_to_hp82335_offset(unsigned int register_num) +{ + return 0x1ff8 + register_num; +} + +static uint8_t hp82335_read_byte(struct tms9914_priv *priv, unsigned int register_num) +{ + return tms9914_iomem_read_byte(priv, tms9914_to_hp82335_offset(register_num)); +} + +static void hp82335_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num) +{ + tms9914_iomem_write_byte(priv, data, tms9914_to_hp82335_offset(register_num)); +} + +static void hp82335_clear_interrupt(struct hp82335_priv *hp_priv) +{ + struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv; + + writeb(0, tms_priv->iobase + HPREG_INTR_CLEAR); +} + +int hp82335_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct hp82335_priv *hp_priv; + struct tms9914_priv *tms_priv; + int retval; + const unsigned long upper_iomem_base = (unsigned long)config->ibbase + hp82335_rom_size; + + board->status = 0; + + if (hp82335_allocate_private(board)) + return -ENOMEM; + hp_priv = board->private_data; + tms_priv = &hp_priv->tms9914_priv; + tms_priv->read_byte = hp82335_read_byte; + tms_priv->write_byte = hp82335_write_byte; + tms_priv->offset = 1; + + switch ((unsigned long)(config->ibbase)) { + case 0xc4000: + case 0xc8000: + case 0xcc000: + case 0xd0000: + case 0xd4000: + case 0xd8000: + case 0xdc000: + case 0xe0000: + case 0xe4000: + case 0xe8000: + case 0xec000: + case 0xf0000: + case 0xf4000: + case 0xf8000: + case 0xfc000: + break; + default: + pr_err("hp82335: invalid base io address 0x%p\n", config->ibbase); + return -EINVAL; + } + if (!request_mem_region(upper_iomem_base, hp82335_upper_iomem_size, "hp82335")) { + pr_err("hp82335: failed to allocate io memory region 0x%lx-0x%lx\n", + upper_iomem_base, upper_iomem_base + hp82335_upper_iomem_size - 1); + return -EBUSY; + } + hp_priv->raw_iobase = upper_iomem_base; + tms_priv->iobase = ioremap(upper_iomem_base, hp82335_upper_iomem_size); + pr_info("hp82335: upper half of 82335 iomem region 0x%lx remapped to 0x%p\n", + hp_priv->raw_iobase, tms_priv->iobase); + + retval = request_irq(config->ibirq, hp82335_interrupt, 0, "hp82335", board); + if (retval) { + pr_err("hp82335: can't request IRQ %d\n", config->ibirq); + return retval; + } + hp_priv->irq = config->ibirq; + pr_info("hp82335: IRQ %d\n", config->ibirq); + + tms9914_board_reset(tms_priv); + + hp82335_clear_interrupt(hp_priv); + + writeb(INTR_ENABLE, tms_priv->iobase + HPREG_CCR); + + tms9914_online(board, tms_priv); + + return 0; +} + +void hp82335_detach(gpib_board_t *board) +{ + struct hp82335_priv *hp_priv = board->private_data; + struct tms9914_priv *tms_priv; + + if (hp_priv) { + tms_priv = &hp_priv->tms9914_priv; + if (hp_priv->irq) + free_irq(hp_priv->irq, board); + if (tms_priv->iobase) { + writeb(0, tms_priv->iobase + HPREG_CCR); + tms9914_board_reset(tms_priv); + iounmap((void *)tms_priv->iobase); + } + if (hp_priv->raw_iobase) + release_mem_region(hp_priv->raw_iobase, hp82335_upper_iomem_size); + } + hp82335_free_private(board); +} + +static int __init hp82335_init_module(void) +{ + gpib_register_driver(&hp82335_interface, THIS_MODULE); + return 0; +} + +static void __exit hp82335_exit_module(void) +{ + gpib_unregister_driver(&hp82335_interface); +} + +module_init(hp82335_init_module); +module_exit(hp82335_exit_module); + +/* + * GPIB interrupt service routines + */ + +irqreturn_t hp82335_interrupt(int irq, void *arg) +{ + int status1, status2; + gpib_board_t *board = arg; + struct hp82335_priv *priv = board->private_data; + unsigned long flags; + irqreturn_t retval; + + spin_lock_irqsave(&board->spinlock, flags); + status1 = read_byte(&priv->tms9914_priv, ISR0); + status2 = read_byte(&priv->tms9914_priv, ISR1); + hp82335_clear_interrupt(priv); + retval = tms9914_interrupt_have_status(board, &priv->tms9914_priv, status1, status2); + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + diff --git a/drivers/staging/gpib/hp_82335/hp82335.h b/drivers/staging/gpib/hp_82335/hp82335.h new file mode 100644 index 00000000000000..5e5297af731ae2 --- /dev/null +++ b/drivers/staging/gpib/hp_82335/hp82335.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess * + ***************************************************************************/ + +#ifndef _HP82335_H +#define _HP82335_H + +#include "tms9914.h" +#include "gpibP.h" + +// struct which defines private_data for board +struct hp82335_priv { + struct tms9914_priv tms9914_priv; + unsigned int irq; + unsigned long raw_iobase; +}; + +// interfaces +extern gpib_interface_t hp82335_interface; + +// interface functions +int hp82335_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read); +int hp82335_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written); +int hp82335_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written); +int hp82335_take_control(gpib_board_t *board, int synchronous); +int hp82335_go_to_standby(gpib_board_t *board); +void hp82335_request_system_control(gpib_board_t *board, int request_control); +void hp82335_interface_clear(gpib_board_t *board, int assert); +void hp82335_remote_enable(gpib_board_t *board, int enable); +int hp82335_enable_eos(gpib_board_t *board, uint8_t eos_byte, int + compare_8_bits); +void hp82335_disable_eos(gpib_board_t *board); +unsigned int hp82335_update_status(gpib_board_t *board, unsigned int clear_mask); +int hp82335_primary_address(gpib_board_t *board, unsigned int address); +int hp82335_secondary_address(gpib_board_t *board, unsigned int address, int + enable); +int hp82335_parallel_poll(gpib_board_t *board, uint8_t *result); +void hp82335_parallel_poll_configure(gpib_board_t *board, uint8_t config); +void hp82335_parallel_poll_response(gpib_board_t *board, int ist); +void hp82335_serial_poll_response(gpib_board_t *board, uint8_t status); +void hp82335_return_to_local(gpib_board_t *board); + +// interrupt service routines +irqreturn_t hp82335_interrupt(int irq, void *arg); + +// utility functions +int hp82335_allocate_private(gpib_board_t *board); +void hp82335_free_private(gpib_board_t *board); + +// size of io memory region used +static const int hp82335_rom_size = 0x2000; +static const int hp82335_upper_iomem_size = 0x2000; + +// hp82335 register offsets +enum hp_read_regs { + HPREG_CSR = 0x17f8, + HPREG_STATUS = 0x1ffc, +}; + +enum hp_write_regs { + HPREG_INTR_CLEAR = 0x17f7, + HPREG_CCR = HPREG_CSR, +}; + +enum ccr_bits { + DMA_ENABLE = (1 << 0), /* DMA enable */ + DMA_CHAN_SELECT = (1 << 1), /* DMA channel select O=3,1=2 */ + INTR_ENABLE = (1 << 2), /* interrupt enable */ + SYS_DISABLE = (1 << 3), /* system controller disable */ +}; + +enum csr_bits { + SWITCH6 = (1 << 0), /* switch 6 position */ + SWITCH5 = (1 << 1), /* switch 5 position */ + SYS_CONTROLLER = (1 << 2), /* system controller bit */ + DMA_ENABLE_STATUS = (1 << 4), /* DMA enabled */ + DMA_CHAN_STATUS = (1 << 5), /* DMA channel 0=3,1=2 */ + INTR_ENABLE_STATUS = (1 << 6), /* Interrupt enable */ + INTR_PENDING = (1 << 7), /* Interrupt Pending */ +}; + +#endif // _HP82335_H diff --git a/drivers/staging/gpib/hp_82341/Makefile b/drivers/staging/gpib/hp_82341/Makefile new file mode 100644 index 00000000000000..1fe7db4f8ca473 --- /dev/null +++ b/drivers/staging/gpib/hp_82341/Makefile @@ -0,0 +1,2 @@ + +obj-m += hp_82341.o diff --git a/drivers/staging/gpib/hp_82341/hp_82341.c b/drivers/staging/gpib/hp_82341/hp_82341.c new file mode 100644 index 00000000000000..8ad1c885a9fb60 --- /dev/null +++ b/drivers/staging/gpib/hp_82341/hp_82341.c @@ -0,0 +1,895 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * Driver for hp 82341a/b/c/d boards. * + * Might be worth merging with Agilent 82350b driver. * + * copyright : (C) 2002, 2005 by Frank Mori Hess * + ***************************************************************************/ + +#include "hp_82341.h" +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +int hp_82341_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read) +{ + struct hp_82341_priv *hp_priv = board->private_data; + struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv; + int retval = 0; + unsigned short event_status; + int i; + int num_fifo_bytes; + //hardware doesn't support checking for end-of-string character when using fifo + if (tms_priv->eos_flags & REOS) + return tms9914_read(board, tms_priv, buffer, length, end, bytes_read); + + clear_bit(DEV_CLEAR_BN, &tms_priv->state); + + read_and_clear_event_status(board); + *end = 0; + *bytes_read = 0; + if (length == 0) + return 0; + //disable fifo for the moment + outb(DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG); + // Handle corner case of board not in holdoff and one byte has slipped in already. + // Also, board sometimes has problems (spurious 1 byte reads) when read fifo is + // started up with board in + // TACS under certain data holdoff conditions. Doing a 1 byte tms9914-style + // read avoids these problems. + if (/*tms_priv->holdoff_active == 0 && */length > 1) { + size_t num_bytes; + + retval = tms9914_read(board, tms_priv, buffer, 1, end, &num_bytes); + *bytes_read += num_bytes; + if (retval < 0) + pr_err("tms9914_read failed retval=%i\n", retval); + if (retval < 0 || *end) + return retval; + ++buffer; + --length; + } + tms9914_set_holdoff_mode(tms_priv, TMS9914_HOLDOFF_EOI); + tms9914_release_holdoff(tms_priv); + outb(0x00, hp_priv->iobase[3] + BUFFER_FLUSH_REG); + i = 0; + num_fifo_bytes = length - 1; + while (i < num_fifo_bytes && *end == 0) { + int block_size; + int j; + int count; + + if (num_fifo_bytes - i < hp_82341_fifo_size) + block_size = num_fifo_bytes - i; + else + block_size = hp_82341_fifo_size; + set_transfer_counter(hp_priv, block_size); + outb(ENABLE_TI_BUFFER_BIT | DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + + BUFFER_CONTROL_REG); + if (inb(hp_priv->iobase[0] + STREAM_STATUS_REG) & HALTED_STATUS_BIT) + outb(RESTART_STREAM_BIT, hp_priv->iobase[0] + STREAM_STATUS_REG); + + clear_bit(READ_READY_BN, &tms_priv->state); + + retval = wait_event_interruptible(board->wait, + ((event_status = + read_and_clear_event_status(board)) & + (TERMINAL_COUNT_EVENT_BIT | + BUFFER_END_EVENT_BIT)) || + test_bit(DEV_CLEAR_BN, &tms_priv->state) || + test_bit(TIMO_NUM, &board->status)); + if (retval) { + pr_warn("%s: read wait interrupted\n", __func__); + retval = -ERESTARTSYS; + break; + } + // have to disable buffer before we can read from buffer port + outb(DIRECTION_GPIB_TO_HOST_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG); + count = block_size - read_transfer_counter(hp_priv); + j = 0; + while (j < count && i < num_fifo_bytes) { + unsigned short data_word = inw(hp_priv->iobase[3] + BUFFER_PORT_LOW_REG); + + buffer[i++] = data_word & 0xff; + ++j; + if (j < count && i < num_fifo_bytes) { + buffer[i++] = (data_word >> 8) & 0xff; + ++j; + } + } + if (event_status & BUFFER_END_EVENT_BIT) { + clear_bit(RECEIVED_END_BN, &tms_priv->state); + + *end = 1; + tms_priv->holdoff_active = 1; + } + if (test_bit(TIMO_NUM, &board->status)) { + pr_debug("%s: minor %i: read timed out\n", __FILE__, board->minor); + retval = -ETIMEDOUT; + break; + } + if (test_bit(DEV_CLEAR_BN, &tms_priv->state)) { + pr_warn("%s: device clear interrupted read\n", __FILE__); + retval = -EINTR; + break; + } + } + *bytes_read += i; + buffer += i; + length -= i; + if (retval < 0) + return retval; + // read last byte if we havn't received an END yet + if (*end == 0) { + size_t num_bytes; + // try to make sure we holdoff after last byte read + retval = tms9914_read(board, tms_priv, buffer, length, end, &num_bytes); + *bytes_read += num_bytes; + if (retval < 0) + return retval; + } + return 0; +} + +static int restart_write_fifo(gpib_board_t *board, struct hp_82341_priv *hp_priv) +{ + struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv; + + if ((inb(hp_priv->iobase[0] + STREAM_STATUS_REG) & HALTED_STATUS_BIT) == 0) + return 0; + while (1) { + int status; + + //restart doesn't work if data holdoff is in effect + status = tms9914_line_status(board, tms_priv); + if ((status & BusNRFD) == 0) { + outb(RESTART_STREAM_BIT, hp_priv->iobase[0] + STREAM_STATUS_REG); + return 0; + } + if (test_bit(DEV_CLEAR_BN, &tms_priv->state)) + return -EINTR; + if (test_bit(TIMO_NUM, &board->status)) + return -ETIMEDOUT; + if (msleep_interruptible(1)) + return -EINTR; + } + return 0; +} + +int hp_82341_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + struct hp_82341_priv *hp_priv = board->private_data; + struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv; + int i, j; + unsigned short event_status; + int retval = 0; + int fifo_xfer_len = length; + + *bytes_written = 0; + if (send_eoi) + --fifo_xfer_len; + + clear_bit(DEV_CLEAR_BN, &tms_priv->state); + + read_and_clear_event_status(board); + outb(0, hp_priv->iobase[3] + BUFFER_CONTROL_REG); + outb(0x00, hp_priv->iobase[3] + BUFFER_FLUSH_REG); + for (i = 0; i < fifo_xfer_len;) { + int block_size; + + if (fifo_xfer_len - i < hp_82341_fifo_size) + block_size = fifo_xfer_len - i; + else + block_size = hp_82341_fifo_size; + set_transfer_counter(hp_priv, block_size); + // load data into board's fifo + for (j = 0; j < block_size;) { + unsigned short data_word = buffer[i++]; + ++j; + if (j < block_size) { + data_word |= buffer[i++] << 8; + ++j; + } + outw(data_word, hp_priv->iobase[3] + BUFFER_PORT_LOW_REG); + } + clear_bit(WRITE_READY_BN, &tms_priv->state); + outb(ENABLE_TI_BUFFER_BIT, hp_priv->iobase[3] + BUFFER_CONTROL_REG); + retval = restart_write_fifo(board, hp_priv); + if (retval < 0) { + pr_err("hp82341: failed to restart write stream\n"); + break; + } + retval = wait_event_interruptible(board->wait, + ((event_status = + read_and_clear_event_status(board)) & + TERMINAL_COUNT_EVENT_BIT) || + test_bit(DEV_CLEAR_BN, &tms_priv->state) || + test_bit(TIMO_NUM, &board->status)); + outb(0, hp_priv->iobase[3] + BUFFER_CONTROL_REG); + *bytes_written += block_size - read_transfer_counter(hp_priv); + if (retval) { + pr_warn("%s: write wait interrupted\n", __FILE__); + retval = -ERESTARTSYS; + break; + } + if (test_bit(TIMO_NUM, &board->status)) { + pr_debug("%s: minor %i: write timed out\n", __FILE__, board->minor); + retval = -ETIMEDOUT; + break; + } + if (test_bit(DEV_CLEAR_BN, &tms_priv->state)) { + pr_warn("%s: device clear interrupted write\n", __FILE__); + retval = -EINTR; + break; + } + } + if (retval) + return retval; + if (send_eoi) { + size_t num_bytes; + + retval = hp_82341_write(board, buffer + fifo_xfer_len, 1, 1, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + return retval; + } + return 0; +} + +static int hp_82341_attach(gpib_board_t *board, const gpib_board_config_t *config); + +static void hp_82341_detach(gpib_board_t *board); + +// wrappers for interface functions +int hp_82341_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_read(board, &priv->tms9914_priv, buffer, length, end, bytes_read); +} + +int hp_82341_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_write(board, &priv->tms9914_priv, buffer, length, send_eoi, bytes_written); +} + +int hp_82341_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_command(board, &priv->tms9914_priv, buffer, length, bytes_written); +} + +int hp_82341_take_control(gpib_board_t *board, int synchronous) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_take_control(board, &priv->tms9914_priv, synchronous); +} + +int hp_82341_go_to_standby(gpib_board_t *board) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_go_to_standby(board, &priv->tms9914_priv); +} + +void hp_82341_request_system_control(gpib_board_t *board, int request_control) +{ + struct hp_82341_priv *priv = board->private_data; + + if (request_control) + priv->mode_control_bits |= SYSTEM_CONTROLLER_BIT; + else + priv->mode_control_bits &= ~SYSTEM_CONTROLLER_BIT; + outb(priv->mode_control_bits, priv->iobase[0] + MODE_CONTROL_STATUS_REG); + tms9914_request_system_control(board, &priv->tms9914_priv, request_control); +} + +void hp_82341_interface_clear(gpib_board_t *board, int assert) +{ + struct hp_82341_priv *priv = board->private_data; + + tms9914_interface_clear(board, &priv->tms9914_priv, assert); +} + +void hp_82341_remote_enable(gpib_board_t *board, int enable) +{ + struct hp_82341_priv *priv = board->private_data; + + tms9914_remote_enable(board, &priv->tms9914_priv, enable); +} + +int hp_82341_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_enable_eos(board, &priv->tms9914_priv, eos_byte, compare_8_bits); +} + +void hp_82341_disable_eos(gpib_board_t *board) +{ + struct hp_82341_priv *priv = board->private_data; + + tms9914_disable_eos(board, &priv->tms9914_priv); +} + +unsigned int hp_82341_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_update_status(board, &priv->tms9914_priv, clear_mask); +} + +int hp_82341_primary_address(gpib_board_t *board, unsigned int address) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_primary_address(board, &priv->tms9914_priv, address); +} + +int hp_82341_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_secondary_address(board, &priv->tms9914_priv, address, enable); +} + +int hp_82341_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_parallel_poll(board, &priv->tms9914_priv, result); +} + +void hp_82341_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + struct hp_82341_priv *priv = board->private_data; + + tms9914_parallel_poll_configure(board, &priv->tms9914_priv, config); +} + +void hp_82341_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct hp_82341_priv *priv = board->private_data; + + tms9914_parallel_poll_response(board, &priv->tms9914_priv, ist); +} + +void hp_82341_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + struct hp_82341_priv *priv = board->private_data; + + tms9914_serial_poll_response(board, &priv->tms9914_priv, status); +} + +static uint8_t hp_82341_serial_poll_status(gpib_board_t *board) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_serial_poll_status(board, &priv->tms9914_priv); +} + +static int hp_82341_line_status(const gpib_board_t *board) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_line_status(board, &priv->tms9914_priv); +} + +static unsigned int hp_82341_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct hp_82341_priv *priv = board->private_data; + + return tms9914_t1_delay(board, &priv->tms9914_priv, nano_sec); +} + +void hp_82341_return_to_local(gpib_board_t *board) +{ + struct hp_82341_priv *priv = board->private_data; + + tms9914_return_to_local(board, &priv->tms9914_priv); +} + +gpib_interface_t hp_82341_unaccel_interface = { +name: "hp_82341_unaccel", +attach : hp_82341_attach, +detach : hp_82341_detach, +read : hp_82341_read, +write : hp_82341_write, +command : hp_82341_command, +request_system_control : hp_82341_request_system_control, +take_control : hp_82341_take_control, +go_to_standby : hp_82341_go_to_standby, +interface_clear : hp_82341_interface_clear, +remote_enable : hp_82341_remote_enable, +enable_eos : hp_82341_enable_eos, +disable_eos : hp_82341_disable_eos, +parallel_poll : hp_82341_parallel_poll, +parallel_poll_configure : hp_82341_parallel_poll_configure, +parallel_poll_response : hp_82341_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : hp_82341_line_status, +update_status : hp_82341_update_status, +primary_address : hp_82341_primary_address, +secondary_address : hp_82341_secondary_address, +serial_poll_response : hp_82341_serial_poll_response, +serial_poll_status : hp_82341_serial_poll_status, +t1_delay : hp_82341_t1_delay, +return_to_local : hp_82341_return_to_local, +}; + +gpib_interface_t hp_82341_interface = { +name: "hp_82341", +attach : hp_82341_attach, +detach : hp_82341_detach, +read : hp_82341_accel_read, +write : hp_82341_accel_write, +command : hp_82341_command, +request_system_control : hp_82341_request_system_control, +take_control : hp_82341_take_control, +go_to_standby : hp_82341_go_to_standby, +interface_clear : hp_82341_interface_clear, +remote_enable : hp_82341_remote_enable, +enable_eos : hp_82341_enable_eos, +disable_eos : hp_82341_disable_eos, +parallel_poll : hp_82341_parallel_poll, +parallel_poll_configure : hp_82341_parallel_poll_configure, +parallel_poll_response : hp_82341_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : hp_82341_line_status, +update_status : hp_82341_update_status, +primary_address : hp_82341_primary_address, +secondary_address : hp_82341_secondary_address, +serial_poll_response : hp_82341_serial_poll_response, +t1_delay : hp_82341_t1_delay, +return_to_local : hp_82341_return_to_local, +}; + +int hp_82341_allocate_private(gpib_board_t *board) +{ + board->private_data = kzalloc(sizeof(struct hp_82341_priv), GFP_KERNEL); + if (!board->private_data) + return -ENOMEM; + return 0; +} + +void hp_82341_free_private(gpib_board_t *board) +{ + kfree(board->private_data); + board->private_data = NULL; +} + +static uint8_t hp_82341_read_byte(struct tms9914_priv *priv, unsigned int register_num) +{ + return inb((unsigned long)(priv->iobase) + register_num); +} + +static void hp_82341_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num) +{ + outb(data, (unsigned long)(priv->iobase) + register_num); +} + +static int hp_82341_find_isapnp_board(struct pnp_dev **dev) +{ + *dev = pnp_find_dev(NULL, ISAPNP_VENDOR('H', 'W', 'P'), + ISAPNP_FUNCTION(0x1411), NULL); + if (!*dev || !(*dev)->card) { + pr_err("hp_82341: failed to find isapnp board\n"); + return -ENODEV; + } + if (pnp_device_attach(*dev) < 0) { + pr_err("hp_82341: board already active, skipping\n"); + return -EBUSY; + } + if (pnp_activate_dev(*dev) < 0) { + pnp_device_detach(*dev); + pr_err("hp_82341: failed to activate() atgpib/tnt, aborting\n"); + return -EAGAIN; + } + if (!pnp_port_valid(*dev, 0) || !pnp_irq_valid(*dev, 0)) { + pnp_device_detach(*dev); + pr_err("hp_82341: invalid port or irq for atgpib/tnt, aborting\n"); + return -ENOMEM; + } + return 0; +} + +static int xilinx_ready(struct hp_82341_priv *hp_priv) +{ + switch (hp_priv->hw_version) { + case HW_VERSION_82341C: + if (inb(hp_priv->iobase[0] + CONFIG_CONTROL_STATUS_REG) & XILINX_READY_BIT) + return 1; + else + return 0; + break; + case HW_VERSION_82341D: + if (isapnp_read_byte(PIO_DATA_REG) & HP_82341D_XILINX_READY_BIT) + return 1; + else + return 0; + default: + pr_err("hp_82341: %s: bug! unknown hw_version\n", __func__); + break; + } + return 0; +} + +static int xilinx_done(struct hp_82341_priv *hp_priv) +{ + switch (hp_priv->hw_version) { + case HW_VERSION_82341C: + if (inb(hp_priv->iobase[0] + CONFIG_CONTROL_STATUS_REG) & DONE_PGL_BIT) + return 1; + else + return 0; + case HW_VERSION_82341D: + if (isapnp_read_byte(PIO_DATA_REG) & HP_82341D_XILINX_DONE_BIT) + return 1; + else + return 0; + default: + pr_err("hp_82341: %s: bug! unknown hw_version\n", __func__); + break; + } + return 0; +} + +static int irq_valid(struct hp_82341_priv *hp_priv, int irq) +{ + switch (hp_priv->hw_version) { + case HW_VERSION_82341C: + switch (irq) { + case 3: + case 5: + case 7: + case 9: + case 10: + case 11: + case 12: + case 15: + return 1; + default: + pr_err("hp_82341: invalid irq=%i for 82341C, irq must be 3, 5, 7, 9, 10, 11, 12, or 15.\n", + irq); + return 0; + } + break; + case HW_VERSION_82341D: + return 1; + default: + pr_err("hp_82341: %s: bug! unknown hw_version\n", __func__); + break; + } + return 0; +} + +static int hp_82341_load_firmware_array(struct hp_82341_priv *hp_priv, + const unsigned char *firmware_data, + unsigned int firmware_length) +{ + int i, j; + static const int timeout = 100; + + for (i = 0; i < firmware_length; ++i) { + for (j = 0; j < timeout; ++j) { + if (need_resched()) + schedule(); + if (xilinx_ready(hp_priv)) + break; + usleep_range(10, 15); + } + if (j == timeout) { + pr_err("hp_82341: timed out waiting for Xilinx ready.\n"); + return -ETIMEDOUT; + } + outb(firmware_data[i], hp_priv->iobase[0] + XILINX_DATA_REG); + } + for (j = 0; j < timeout; ++j) { + if (xilinx_done(hp_priv)) + break; + if (need_resched()) + schedule(); + usleep_range(10, 15); + } + if (j == timeout) { + pr_err("hp_82341: timed out waiting for Xilinx done.\n"); + return -ETIMEDOUT; + } + return 0; +} + +static int hp_82341_load_firmware(struct hp_82341_priv *hp_priv, const gpib_board_config_t *config) +{ + if (config->init_data_length == 0) { + if (xilinx_done(hp_priv)) + return 0; + pr_err("hp_82341: board needs be initialized with firmware upload.\n" + "\tUse the --init-data option of gpib_config.\n"); + return -EINVAL; + } + switch (hp_priv->hw_version) { + case HW_VERSION_82341C: + if (config->init_data_length != hp_82341c_firmware_length) { + pr_err("hp_82341: bad firmware length=%i for 82341c (expected %i).\n", + config->init_data_length, hp_82341c_firmware_length); + return -EINVAL; + } + break; + case HW_VERSION_82341D: + if (config->init_data_length != hp_82341d_firmware_length) { + pr_err("hp_82341: bad firmware length=%i for 82341d (expected %i).\n", + config->init_data_length, hp_82341d_firmware_length); + return -EINVAL; + } + break; + default: + pr_err("hp_82341: %s: bug! unknown hw_version\n", __func__); + break; + } + return hp_82341_load_firmware_array(hp_priv, config->init_data, config->init_data_length); +} + +static void set_xilinx_not_prog(struct hp_82341_priv *hp_priv, int assert) +{ + switch (hp_priv->hw_version) { + case HW_VERSION_82341C: + if (assert) + hp_priv->config_control_bits |= DONE_PGL_BIT; + else + hp_priv->config_control_bits &= ~DONE_PGL_BIT; + outb(hp_priv->config_control_bits, hp_priv->iobase[0] + CONFIG_CONTROL_STATUS_REG); + break; + case HW_VERSION_82341D: + if (assert) + isapnp_write_byte(PIO_DATA_REG, HP_82341D_NOT_PROG_BIT); + else + isapnp_write_byte(PIO_DATA_REG, 0x0); + break; + default: + break; + } +} + +// clear xilinx firmware +static int clear_xilinx(struct hp_82341_priv *hp_priv) +{ + set_xilinx_not_prog(hp_priv, 1); + if (msleep_interruptible(1)) + return -EINTR; + set_xilinx_not_prog(hp_priv, 0); + if (msleep_interruptible(1)) + return -EINTR; + set_xilinx_not_prog(hp_priv, 1); + if (msleep_interruptible(1)) + return -EINTR; + return 0; +} + +int hp_82341_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct hp_82341_priv *hp_priv; + struct tms9914_priv *tms_priv; + unsigned long start_addr; + void *iobase; + int irq; + int i; + int retval; + + board->status = 0; + if (hp_82341_allocate_private(board)) + return -ENOMEM; + hp_priv = board->private_data; + tms_priv = &hp_priv->tms9914_priv; + tms_priv->read_byte = hp_82341_read_byte; + tms_priv->write_byte = hp_82341_write_byte; + tms_priv->offset = 1; + + if (config->ibbase == 0) { + struct pnp_dev *dev; + int retval = hp_82341_find_isapnp_board(&dev); + + if (retval < 0) + return retval; + hp_priv->pnp_dev = dev; + iobase = (void *)(pnp_port_start(dev, 0)); + irq = pnp_irq(dev, 0); + hp_priv->hw_version = HW_VERSION_82341D; + hp_priv->io_region_offset = 0x8; + } else { + iobase = config->ibbase; + irq = config->ibirq; + hp_priv->hw_version = HW_VERSION_82341C; + hp_priv->io_region_offset = 0x400; + } + pr_info("hp_82341: base io 0x%p\n", iobase); + for (i = 0; i < hp_82341_num_io_regions; ++i) { + start_addr = (unsigned long)(iobase) + i * hp_priv->io_region_offset; + if (!request_region(start_addr, hp_82341_region_iosize, "hp_82341")) { + pr_err("hp_82341: failed to allocate io ports 0x%lx-0x%lx\n", + start_addr, + start_addr + hp_82341_region_iosize - 1); + return -EIO; + } + hp_priv->iobase[i] = start_addr; + } + tms_priv->iobase = (void *)(hp_priv->iobase[2]); + if (hp_priv->hw_version == HW_VERSION_82341D) { + retval = isapnp_cfg_begin(hp_priv->pnp_dev->card->number, + hp_priv->pnp_dev->number); + if (retval < 0) { + pr_err("hp_82341: isapnp_cfg_begin returned error\n"); + return retval; + } + isapnp_write_byte(PIO_DIRECTION_REG, HP_82341D_XILINX_READY_BIT | + HP_82341D_XILINX_DONE_BIT); + } + retval = clear_xilinx(hp_priv); + if (retval < 0) + return retval; + retval = hp_82341_load_firmware(hp_priv, config); + if (hp_priv->hw_version == HW_VERSION_82341D) + isapnp_cfg_end(); + if (retval < 0) + return retval; + if (irq_valid(hp_priv, irq) == 0) + return -EINVAL; + if (request_irq(irq, hp_82341_interrupt, 0, "hp_82341", board)) { + pr_err("hp_82341: failed to allocate IRQ %d\n", irq); + return -EIO; + } + hp_priv->irq = irq; + pr_info("hp_82341: IRQ %d\n", irq); + hp_priv->config_control_bits &= ~IRQ_SELECT_MASK; + hp_priv->config_control_bits |= IRQ_SELECT_BITS(irq); + outb(hp_priv->config_control_bits, hp_priv->iobase[0] + CONFIG_CONTROL_STATUS_REG); + hp_priv->mode_control_bits |= ENABLE_IRQ_CONFIG_BIT; + outb(hp_priv->mode_control_bits, hp_priv->iobase[0] + MODE_CONTROL_STATUS_REG); + tms9914_board_reset(tms_priv); + outb(ENABLE_BUFFER_END_EVENT_BIT | ENABLE_TERMINAL_COUNT_EVENT_BIT | + ENABLE_TI_INTERRUPT_EVENT_BIT, hp_priv->iobase[0] + EVENT_ENABLE_REG); + outb(ENABLE_BUFFER_END_INTERRUPT_BIT | ENABLE_TERMINAL_COUNT_INTERRUPT_BIT | + ENABLE_TI_INTERRUPT_BIT, hp_priv->iobase[0] + INTERRUPT_ENABLE_REG); + //write clear event register + outb((TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT | + BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT), + hp_priv->iobase[0] + EVENT_STATUS_REG); + + tms9914_online(board, tms_priv); + pr_info("hp_82341: board id %x %x %x %x\n", inb(hp_priv->iobase[1] + ID0_REG), + inb(hp_priv->iobase[1] + ID1_REG), inb(hp_priv->iobase[2] + ID2_REG), + inb(hp_priv->iobase[2] + ID3_REG)); + return 0; +} + +void hp_82341_detach(gpib_board_t *board) +{ + struct hp_82341_priv *hp_priv = board->private_data; + struct tms9914_priv *tms_priv; + int i; + + if (hp_priv) { + tms_priv = &hp_priv->tms9914_priv; + if (hp_priv->iobase[0]) { + outb(0, hp_priv->iobase[0] + INTERRUPT_ENABLE_REG); + if (tms_priv->iobase) + tms9914_board_reset(tms_priv); + if (hp_priv->irq) + free_irq(hp_priv->irq, board); + } + for (i = 0; i < hp_82341_num_io_regions; ++i) { + if (hp_priv->iobase[i]) + release_region(hp_priv->iobase[i], hp_82341_region_iosize); + } + if (hp_priv->pnp_dev) + pnp_device_detach(hp_priv->pnp_dev); + } + hp_82341_free_private(board); +} + +static const struct pnp_device_id hp_82341_pnp_table[] = { + {.id = "HWP1411"}, + {.id = ""} +}; +MODULE_DEVICE_TABLE(pnp, hp_82341_pnp_table); + +static int __init hp_82341_init_module(void) +{ + gpib_register_driver(&hp_82341_unaccel_interface, THIS_MODULE); + gpib_register_driver(&hp_82341_interface, THIS_MODULE); + return 0; +} + +static void __exit hp_82341_exit_module(void) +{ + gpib_unregister_driver(&hp_82341_interface); + gpib_unregister_driver(&hp_82341_unaccel_interface); +} + +module_init(hp_82341_init_module); +module_exit(hp_82341_exit_module); + +/* + * GPIB interrupt service routines + */ +unsigned short read_and_clear_event_status(gpib_board_t *board) +{ + struct hp_82341_priv *hp_priv = board->private_data; + unsigned long flags; + unsigned short status; + + spin_lock_irqsave(&board->spinlock, flags); + status = hp_priv->event_status_bits; + hp_priv->event_status_bits = 0; + spin_unlock_irqrestore(&board->spinlock, flags); + return status; +} + +irqreturn_t hp_82341_interrupt(int irq, void *arg) +{ + int status1, status2; + gpib_board_t *board = arg; + struct hp_82341_priv *hp_priv = board->private_data; + struct tms9914_priv *tms_priv = &hp_priv->tms9914_priv; + unsigned long flags; + irqreturn_t retval = IRQ_NONE; + int event_status; + + spin_lock_irqsave(&board->spinlock, flags); + event_status = inb(hp_priv->iobase[0] + EVENT_STATUS_REG); +// printk("hp_82341: interrupt event_status=0x%x\n", event_status); + if (event_status & INTERRUPT_PENDING_EVENT_BIT) + retval = IRQ_HANDLED; + //write-clear status bits + if (event_status & (TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT | + BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT)) { + outb(event_status & (TI_INTERRUPT_EVENT_BIT | POINTERS_EQUAL_EVENT_BIT | + BUFFER_END_EVENT_BIT | TERMINAL_COUNT_EVENT_BIT), + hp_priv->iobase[0] + EVENT_STATUS_REG); + hp_priv->event_status_bits |= event_status; + } + if (event_status & TI_INTERRUPT_EVENT_BIT) { + status1 = read_byte(tms_priv, ISR0); + status2 = read_byte(tms_priv, ISR1); + tms9914_interrupt_have_status(board, tms_priv, status1, status2); +/* printk("hp_82341: interrupt status1=0x%x status2=0x%x\n", + * status1, status2); + */ + } + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +int read_transfer_counter(struct hp_82341_priv *hp_priv) +{ + int lo, mid, value; + + lo = inb(hp_priv->iobase[1] + TRANSFER_COUNT_LOW_REG); + mid = inb(hp_priv->iobase[1] + TRANSFER_COUNT_MID_REG); + value = (lo & 0xff) | ((mid << 8) & 0x7f00); + value = ~(value - 1) & 0x7fff; + return value; +} + +void set_transfer_counter(struct hp_82341_priv *hp_priv, int count) +{ + int complement = -count; + + outb(complement & 0xff, hp_priv->iobase[1] + TRANSFER_COUNT_LOW_REG); + outb((complement >> 8) & 0xff, hp_priv->iobase[1] + TRANSFER_COUNT_MID_REG); + //I don't think the hi count reg is even used, but oh well + outb((complement >> 16) & 0xf, hp_priv->iobase[1] + TRANSFER_COUNT_HIGH_REG); +} + diff --git a/drivers/staging/gpib/hp_82341/hp_82341.h b/drivers/staging/gpib/hp_82341/hp_82341.h new file mode 100644 index 00000000000000..7c391860b3994e --- /dev/null +++ b/drivers/staging/gpib/hp_82341/hp_82341.h @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002, 2005 by Frank Mori Hess * + ***************************************************************************/ + +#include "tms9914.h" +#include "gpibP.h" + +enum hp_82341_hardware_version { + HW_VERSION_UNKNOWN, + HW_VERSION_82341C, + HW_VERSION_82341D, +}; + +// struct which defines private_data for board +struct hp_82341_priv { + struct tms9914_priv tms9914_priv; + unsigned int irq; + unsigned short config_control_bits; + unsigned short mode_control_bits; + unsigned short event_status_bits; + struct pnp_dev *pnp_dev; + unsigned long iobase[4]; + unsigned long io_region_offset; + enum hp_82341_hardware_version hw_version; +}; + +// interfaces +extern gpib_interface_t hp_82341_interface; + +// interface functions +int hp_82341_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read); +int hp_82341_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written); +int hp_82341_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read); +int hp_82341_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written); +int hp_82341_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written); +int hp_82341_take_control(gpib_board_t *board, int synchronous); +int hp_82341_go_to_standby(gpib_board_t *board); +void hp_82341_request_system_control(gpib_board_t *board, int request_control); +void hp_82341_interface_clear(gpib_board_t *board, int assert); +void hp_82341_remote_enable(gpib_board_t *board, int enable); +int hp_82341_enable_eos(gpib_board_t *board, uint8_t eos_byte, int + compare_8_bits); +void hp_82341_disable_eos(gpib_board_t *board); +unsigned int hp_82341_update_status(gpib_board_t *board, unsigned int clear_mask); +int hp_82341_primary_address(gpib_board_t *board, unsigned int address); +int hp_82341_secondary_address(gpib_board_t *board, unsigned int address, int + enable); +int hp_82341_parallel_poll(gpib_board_t *board, uint8_t *result); +void hp_82341_parallel_poll_configure(gpib_board_t *board, uint8_t config); +void hp_82341_parallel_poll_response(gpib_board_t *board, int ist); +void hp_82341_serial_poll_response(gpib_board_t *board, uint8_t status); +void hp_82341_return_to_local(gpib_board_t *board); + +// interrupt service routines +irqreturn_t hp_82341_interrupt(int irq, void *arg); + +// utility functions +int hp_82341_allocate_private(gpib_board_t *board); +void hp_82341_free_private(gpib_board_t *board); + +static const int hp_82341_region_iosize = 0x8; +static const int hp_82341_num_io_regions = 4; +static const int hp_82341_fifo_size = 0xffe; +static const int hp_82341c_firmware_length = 5764; +static const int hp_82341d_firmware_length = 5302; + +// hp 82341 register offsets +enum hp_82341_region_0_registers { + CONFIG_CONTROL_STATUS_REG = 0x0, + MODE_CONTROL_STATUS_REG = 0x1, + MONITOR_REG = 0x2, // after initialization + XILINX_DATA_REG = 0x2, // before initialization, write only + INTERRUPT_ENABLE_REG = 0x3, + EVENT_STATUS_REG = 0x4, + EVENT_ENABLE_REG = 0x5, + STREAM_STATUS_REG = 0x7, +}; + +enum hp_82341_region_1_registers { + ID0_REG = 0x2, + ID1_REG = 0x3, + TRANSFER_COUNT_LOW_REG = 0x4, + TRANSFER_COUNT_MID_REG = 0x5, + TRANSFER_COUNT_HIGH_REG = 0x6, +}; + +enum hp_82341_region_3_registers { + BUFFER_PORT_LOW_REG = 0x0, + BUFFER_PORT_HIGH_REG = 0x1, + ID2_REG = 0x2, + ID3_REG = 0x3, + BUFFER_FLUSH_REG = 0x4, + BUFFER_CONTROL_REG = 0x7 +}; + +enum config_control_status_bits { + IRQ_SELECT_MASK = 0x7, + DMA_CONFIG_MASK = 0x18, + ENABLE_DMA_CONFIG_BIT = 0x20, + XILINX_READY_BIT = 0x40, //read only + DONE_PGL_BIT = 0x80 +}; + +static inline unsigned int IRQ_SELECT_BITS(int irq) +{ + switch (irq) { + case 3: + return 0x3; + case 5: + return 0x2; + case 7: + return 0x1; + case 9: + return 0x0; + case 10: + return 0x7; + case 11: + return 0x6; + case 12: + return 0x5; + case 15: + return 0x4; + default: + return 0x0; + } +}; + +enum mode_control_status_bits { + SLOT8_BIT = 0x1, // read only + ACTIVE_CONTROLLER_BIT = 0x2, // read only + ENABLE_DMA_BIT = 0x4, + SYSTEM_CONTROLLER_BIT = 0x8, + MONITOR_BIT = 0x10, + ENABLE_IRQ_CONFIG_BIT = 0x20, + ENABLE_TI_STREAM_BIT = 0x40 +}; + +enum monitor_bits { + MONITOR_INTERRUPT_PENDING_BIT = 0x1, // read only + MONITOR_CLEAR_HOLDOFF_BIT = 0x2, // write only + MONITOR_PPOLL_BIT = 0x4, // write clear + MONITOR_SRQ_BIT = 0x8, // write clear + MONITOR_IFC_BIT = 0x10, // write clear + MONITOR_REN_BIT = 0x20, // write clear + MONITOR_END_BIT = 0x40, // write clear + MONITOR_DAV_BIT = 0x80 // write clear +}; + +enum interrupt_enable_bits { + ENABLE_TI_INTERRUPT_BIT = 0x1, + ENABLE_POINTERS_EQUAL_INTERRUPT_BIT = 0x4, + ENABLE_BUFFER_END_INTERRUPT_BIT = 0x10, + ENABLE_TERMINAL_COUNT_INTERRUPT_BIT = 0x20, + ENABLE_DMA_TERMINAL_COUNT_INTERRUPT_BIT = 0x80, +}; + +enum event_status_bits { + TI_INTERRUPT_EVENT_BIT = 0x1, //write clear + INTERRUPT_PENDING_EVENT_BIT = 0x2, // read only + POINTERS_EQUAL_EVENT_BIT = 0x4, //write clear + BUFFER_END_EVENT_BIT = 0x10, //write clear + TERMINAL_COUNT_EVENT_BIT = 0x20, // write clear + DMA_TERMINAL_COUNT_EVENT_BIT = 0x80, // write clear +}; + +enum event_enable_bits { + ENABLE_TI_INTERRUPT_EVENT_BIT = 0x1, //write clear + ENABLE_POINTERS_EQUAL_EVENT_BIT = 0x4, //write clear + ENABLE_BUFFER_END_EVENT_BIT = 0x10, //write clear + ENABLE_TERMINAL_COUNT_EVENT_BIT = 0x20, // write clear + ENABLE_DMA_TERMINAL_COUNT_EVENT_BIT = 0x80, // write clear +}; + +enum stream_status_bits { + HALTED_STATUS_BIT = 0x1, //read + RESTART_STREAM_BIT = 0x1 //write +}; + +enum buffer_control_bits { + DIRECTION_GPIB_TO_HOST_BIT = 0x20, // transfer direction (set for gpib to host) + ENABLE_TI_BUFFER_BIT = 0x40, //enable fifo + FAST_WR_EN_BIT = 0x80, // 350 ns t1 delay? +}; + +// registers accessible through isapnp chip on 82341d +enum hp_82341d_pnp_registers { + PIO_DATA_REG = 0x20, //read/write pio data lines + PIO_DIRECTION_REG = 0x21, // set pio data line directions (set for input) +}; + +enum hp_82341d_pnp_pio_bits { + HP_82341D_XILINX_READY_BIT = 0x1, + HP_82341D_XILINX_DONE_BIT = 0x2, + // use register layout compatible with C and older versions instead of 32 contiguous ioports + HP_82341D_LEGACY_MODE_BIT = 0x4, + HP_82341D_NOT_PROG_BIT = 0x8, // clear to reinitialize xilinx +}; + +unsigned short read_and_clear_event_status(gpib_board_t *board); +int read_transfer_counter(struct hp_82341_priv *hp_priv); +void set_transfer_counter(struct hp_82341_priv *hp_priv, int count); diff --git a/drivers/staging/gpib/include/amcc5920.h b/drivers/staging/gpib/include/amcc5920.h new file mode 100644 index 00000000000000..766b3799223f14 --- /dev/null +++ b/drivers/staging/gpib/include/amcc5920.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * Header for amcc5920 pci chip + * + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +// plx pci chip registers and bits +enum amcc_registers { + AMCC_INTCS_REG = 0x38, + AMCC_PASS_THRU_REG = 0x60, +}; + +enum amcc_incsr_bits { + AMCC_ADDON_INTR_ENABLE_BIT = 0x2000, + AMCC_ADDON_INTR_ACTIVE_BIT = 0x400000, + AMCC_INTR_ACTIVE_BIT = 0x800000, +}; + +static const int bits_per_region = 8; + +static inline uint32_t amcc_wait_state_bits(unsigned int region, unsigned int num_wait_states) +{ + return (num_wait_states & 0x7) << (-region * bits_per_region); +}; + +enum amcc_prefetch_bits { + PREFETCH_DISABLED = 0x0, + PREFETCH_SMALL = 0x8, + PREFETCH_MEDIUM = 0x10, + PREFETCH_LARGE = 0x18, +}; + +static inline uint32_t amcc_prefetch_bits(unsigned int region, enum amcc_prefetch_bits prefetch) +{ + return prefetch << (--region * bits_per_region); +}; + +static inline uint32_t amcc_PTADR_mode_bit(unsigned int region) +{ + return 0x80 << (--region * bits_per_region); +}; + +static inline uint32_t amcc_disable_write_fifo_bit(unsigned int region) +{ + return 0x20 << (--region * bits_per_region); +}; + diff --git a/drivers/staging/gpib/include/amccs5933.h b/drivers/staging/gpib/include/amccs5933.h new file mode 100644 index 00000000000000..4de0f679745847 --- /dev/null +++ b/drivers/staging/gpib/include/amccs5933.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * Registers and bits for amccs5933 pci chip + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +// register offsets +enum { + MBEF_REG = 0x34, // mailbux empty/full + INTCSR_REG = 0x38, // interrupt control and status + BMCSR_REG = 0x3c, // bus master control and status +}; + +// incoming mailbox 0-3 register offsets +extern inline int INCOMING_MAILBOX_REG(unsigned int mailbox) +{ + return (0x10 + 4 * mailbox); +}; + +// bit definitions + +// INTCSR bits +enum { + OUTBOX_EMPTY_INTR_BIT = 0x10, // enable outbox empty interrupt + INBOX_FULL_INTR_BIT = 0x1000, // enable inbox full interrupt + INBOX_INTR_CS_BIT = 0x20000, // read, or write clear inbox full interrupt + INTR_ASSERTED_BIT = 0x800000, // read only, interrupt asserted +}; + +// select byte 0 to 3 of incoming mailbox +extern inline int INBOX_BYTE_BITS(unsigned int byte) +{ + return (byte & 0x3) << 8; +}; + +// select incoming mailbox 0 to 3 +extern inline int INBOX_SELECT_BITS(unsigned int mailbox) +{ + return (mailbox & 0x3) << 10; +}; + +// select byte 0 to 3 of outgoing mailbox +extern inline int OUTBOX_BYTE_BITS(unsigned int byte) +{ + return (byte & 0x3); +}; + +// select outgoing mailbox 0 to 3 +extern inline int OUTBOX_SELECT_BITS(unsigned int mailbox) +{ + return (mailbox & 0x3) << 2; +}; + +//BMCSR bits +enum { + MBOX_FLAGS_RESET_BIT = 0x08000000, // resets mailbox empty/full flags +}; + diff --git a/drivers/staging/gpib/include/gpibP.h b/drivers/staging/gpib/include/gpibP.h new file mode 100644 index 00000000000000..5fc42b645ab70c --- /dev/null +++ b/drivers/staging/gpib/include/gpibP.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002,2003 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _GPIB_P_H +#define _GPIB_P_H + +#include + +#include "gpib_types.h" +#include "gpib_proto.h" +#include "gpib_user.h" +#include "gpib_ioctl.h" + +#include +#include + +void gpib_register_driver(gpib_interface_t *interface, struct module *mod); +void gpib_unregister_driver(gpib_interface_t *interface); +struct pci_dev *gpib_pci_get_device(const gpib_board_config_t *config, unsigned int vendor_id, + unsigned int device_id, struct pci_dev *from); +struct pci_dev *gpib_pci_get_subsys(const gpib_board_config_t *config, unsigned int vendor_id, + unsigned int device_id, unsigned int ss_vendor, + unsigned int ss_device, struct pci_dev *from); +unsigned int num_gpib_events(const gpib_event_queue_t *queue); +int push_gpib_event(gpib_board_t *board, short event_type); +int pop_gpib_event(gpib_board_t *board, gpib_event_queue_t *queue, short *event_type); +int gpib_request_pseudo_irq(gpib_board_t *board, irqreturn_t (*handler)(int, void *)); +void gpib_free_pseudo_irq(gpib_board_t *board); +int gpib_match_device_path(struct device *dev, const char *device_path_in); + +extern gpib_board_t board_array[GPIB_MAX_NUM_BOARDS]; + +extern struct list_head registered_drivers; + +#include + +void writeb_wrapper(unsigned int value, void *address); +unsigned int readb_wrapper(void *address); +void outb_wrapper(unsigned int value, void *address); +unsigned int inb_wrapper(void *address); +void writew_wrapper(unsigned int value, void *address); +unsigned int readw_wrapper(void *address); +void outw_wrapper(unsigned int value, void *address); +unsigned int inw_wrapper(void *address); + +#endif // _GPIB_P_H + diff --git a/drivers/staging/gpib/include/gpib_pci_ids.h b/drivers/staging/gpib/include/gpib_pci_ids.h new file mode 100644 index 00000000000000..52dcab07a7d188 --- /dev/null +++ b/drivers/staging/gpib/include/gpib_pci_ids.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __GPIB_PCI_IDS_H +#define __GPIB_PCI_IDS_H + +#ifndef PCI_VENDOR_ID_AMCC +#define PCI_VENDOR_ID_AMCC 0x10e8 +#endif + +#ifndef PCI_VENDOR_ID_CBOARDS +#define PCI_VENDOR_ID_CBOARDS 0x1307 +#endif + +#ifndef PCI_VENDOR_ID_QUANCOM +#define PCI_VENDOR_ID_QUANCOM 0x8008 +#endif + +#ifndef PCI_DEVICE_ID_QUANCOM_GPIB +#define PCI_DEVICE_ID_QUANCOM_GPIB 0x3302 +#endif + +#endif // __GPIB_PCI_IDS_H + diff --git a/drivers/staging/gpib/include/gpib_proto.h b/drivers/staging/gpib/include/gpib_proto.h new file mode 100644 index 00000000000000..1499f954210b8c --- /dev/null +++ b/drivers/staging/gpib/include/gpib_proto.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef GPIB_PROTO_INCLUDED +#define GPIB_PROTO_INCLUDED + +#include + +int ibopen(struct inode *inode, struct file *filep); +int ibclose(struct inode *inode, struct file *file); +long ibioctl(struct file *filep, unsigned int cmd, unsigned long arg); +int osInit(void); +void osReset(void); +void os_start_timer(gpib_board_t *board, unsigned int usec_timeout); +void os_remove_timer(gpib_board_t *board); +void osSendEOI(void); +void osSendEOI(void); +void init_gpib_board(gpib_board_t *board); +static inline unsigned long usec_to_jiffies(unsigned int usec) +{ + unsigned long usec_per_jiffy = 1000000 / HZ; + + return 1 + (usec + usec_per_jiffy - 1) / usec_per_jiffy; +}; + +int serial_poll_all(gpib_board_t *board, unsigned int usec_timeout); +void init_gpib_descriptor(gpib_descriptor_t *desc); +int dvrsp(gpib_board_t *board, unsigned int pad, int sad, + unsigned int usec_timeout, uint8_t *result); +int ibAPWait(gpib_board_t *board, int pad); +int ibAPrsp(gpib_board_t *board, int padsad, char *spb); +void ibAPE(gpib_board_t *board, int pad, int v); +int ibcac(gpib_board_t *board, int sync, int fallback_to_async); +int ibcmd(gpib_board_t *board, uint8_t *buf, size_t length, size_t *bytes_written); +int ibgts(gpib_board_t *board); +int ibonline(gpib_board_t *board); +int iboffline(gpib_board_t *board); +int iblines(const gpib_board_t *board, short *lines); +int ibrd(gpib_board_t *board, uint8_t *buf, size_t length, int *end_flag, size_t *bytes_read); +int ibrpp(gpib_board_t *board, uint8_t *buf); +int ibrsv2(gpib_board_t *board, uint8_t status_byte, int new_reason_for_service); +void ibrsc(gpib_board_t *board, int request_control); +int ibsic(gpib_board_t *board, unsigned int usec_duration); +int ibsre(gpib_board_t *board, int enable); +int ibpad(gpib_board_t *board, unsigned int addr); +int ibsad(gpib_board_t *board, int addr); +int ibeos(gpib_board_t *board, int eos, int eosflags); +int ibwait(gpib_board_t *board, int wait_mask, int clear_mask, int set_mask, + int *status, unsigned long usec_timeout, gpib_descriptor_t *desc); +int ibwrt(gpib_board_t *board, uint8_t *buf, size_t cnt, int send_eoi, size_t *bytes_written); +int ibstatus(gpib_board_t *board); +int general_ibstatus(gpib_board_t *board, const gpib_status_queue_t *device, + int clear_mask, int set_mask, gpib_descriptor_t *desc); +int io_timed_out(gpib_board_t *board); +int ibppc(gpib_board_t *board, uint8_t configuration); + +#endif /* GPIB_PROTO_INCLUDED */ diff --git a/drivers/staging/gpib/include/gpib_state_machines.h b/drivers/staging/gpib/include/gpib_state_machines.h new file mode 100644 index 00000000000000..7488c00f191e80 --- /dev/null +++ b/drivers/staging/gpib/include/gpib_state_machines.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2006 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _GPIB_STATE_MACHINES_H +#define _GPIB_STATE_MACHINES_H + +enum talker_function_state { + talker_idle, + talker_addressed, + talker_active, + serial_poll_active +}; + +enum listener_function_state { + listener_idle, + listener_addressed, + listener_active +}; + +#endif // _GPIB_STATE_MACHINES_H diff --git a/drivers/staging/gpib/include/gpib_types.h b/drivers/staging/gpib/include/gpib_types.h new file mode 100644 index 00000000000000..ee2643da6d7106 --- /dev/null +++ b/drivers/staging/gpib/include/gpib_types.h @@ -0,0 +1,353 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _GPIB_TYPES_H +#define _GPIB_TYPES_H + +#ifdef __KERNEL__ +/* gpib_interface_t defines the interface + * between the board-specific details dealt with in the drivers + * and generic interface provided by gpib-common. + * This really should be in a different header file. + */ +#include "gpib_user.h" +#include +#include +#include +#include +#include +#include +#include + +typedef struct gpib_interface_struct gpib_interface_t; +typedef struct gpib_board_struct gpib_board_t; + +/* config parameters that are only used by driver attach functions */ +typedef struct { + /* firmware blob */ + void *init_data; + int init_data_length; + /* IO base address to use for non-pnp cards (set by core, driver should make local copy) */ + void *ibbase; + /* IRQ to use for non-pnp cards (set by core, driver should make local copy) */ + unsigned int ibirq; + /* dma channel to use for non-pnp cards (set by core, driver should make local copy) */ + unsigned int ibdma; + /* pci bus of card, useful for distinguishing multiple identical pci cards + * (negative means don't care) + */ + int pci_bus; + /* pci slot of card, useful for distinguishing multiple identical pci cards + * (negative means don't care) + */ + int pci_slot; + /* sysfs device path of hardware to attach */ + char *device_path; + /* serial number of hardware to attach */ + char *serial_number; +} gpib_board_config_t; + +struct gpib_interface_struct { + /* name of board */ + char *name; + /* attach() initializes board and allocates resources */ + int (*attach)(gpib_board_t *board, const gpib_board_config_t *config); + /* detach() shuts down board and frees resources */ + void (*detach)(gpib_board_t *board); + /* read() should read at most 'length' bytes from the bus into + * 'buffer'. It should return when it fills the buffer or + * encounters an END (EOI and or EOS if appropriate). It should set 'end' + * to be nonzero if the read was terminated by an END, otherwise 'end' + * should be zero. + * Ultimately, this will be changed into or replaced by an asynchronous + * read. Zero return value for success, negative + * return indicates error. + * nbytes returns number of bytes read + */ + int (*read)(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read); + /* write() should write 'length' bytes from buffer to the bus. + * If the boolean value send_eoi is nonzero, then EOI should + * be sent along with the last byte. Returns number of bytes + * written or negative value on error. + */ + int (*write)(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written); + /* command() writes the command bytes in 'buffer' to the bus + * Returns zero on success or negative value on error. + */ + int (*command)(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written); + /* Take control (assert ATN). If 'asyncronous' is nonzero, take + * control asyncronously (assert ATN immediately without waiting + * for other processes to complete first). Should not return + * until board becomes controller in charge. Returns zero no success, + * nonzero on error. + */ + int (*take_control)(gpib_board_t *board, int asyncronous); + /* De-assert ATN. Returns zero on success, nonzer on error. + */ + int (*go_to_standby)(gpib_board_t *board); + /* request/release control of the IFC and REN lines (system controller) */ + void (*request_system_control)(gpib_board_t *board, int request_control); + /* Asserts or de-asserts 'interface clear' (IFC) depending on + * boolean value of 'assert' + */ + void (*interface_clear)(gpib_board_t *board, int assert); + /* Sends remote enable command if 'enable' is nonzero, disables remote mode + * if 'enable' is zero + */ + void (*remote_enable)(gpib_board_t *board, int enable); + /* enable END for reads, when byte 'eos' is received. If + * 'compare_8_bits' is nonzero, then all 8 bits are compared + * with the eos bytes. Otherwise only the 7 least significant + * bits are compared. + */ + int (*enable_eos)(gpib_board_t *board, uint8_t eos, int compare_8_bits); + /* disable END on eos byte (END on EOI only)*/ + void (*disable_eos)(gpib_board_t *board); + /* configure parallel poll */ + void (*parallel_poll_configure)(gpib_board_t *board, uint8_t configuration); + /* conduct parallel poll */ + int (*parallel_poll)(gpib_board_t *board, uint8_t *result); + /* set/clear ist (individual status bit) */ + void (*parallel_poll_response)(gpib_board_t *board, int ist); + /* select local parallel poll configuration mode PP2 versus remote PP1 */ + void (*local_parallel_poll_mode)(gpib_board_t *board, int local); + /* Returns current status of the bus lines. Should be set to + * NULL if your board does not have the ability to query the + * state of the bus lines. + */ + int (*line_status)(const gpib_board_t *board); + /* updates and returns the board's current status. + * The meaning of the bits are specified in gpib_user.h + * in the IBSTA section. The driver does not need to + * worry about setting the CMPL, END, TIMO, or ERR bits. + */ + unsigned int (*update_status)(gpib_board_t *board, unsigned int clear_mask); + /* Sets primary address 0-30 for gpib interface card. + */ + int (*primary_address)(gpib_board_t *board, unsigned int address); + /* Sets and enables, or disables secondary address 0-30 + * for gpib interface card. + */ + int (*secondary_address)(gpib_board_t *board, unsigned int address, + int enable); + /* Sets the byte the board should send in response to a serial poll. + * This function should also start or stop requests for service via + * IEEE 488.2 reqt/reqf, based on MSS (bit 6 of the status_byte). + * If the more flexible serial_poll_response2 is implemented by the + * driver, then this method should be left NULL since it will not + * be used. This method can generate spurious service requests + * which are allowed by IEEE 488.2, but not ideal. + * + * This method should implement the serial poll response method described + * by IEEE 488.2 section 11.3.3.4.3 "Allowed Coupled Control of + * STB, reqt, and reqf". + */ + void (*serial_poll_response)(gpib_board_t *board, uint8_t status_byte); + /* Sets the byte the board should send in response to a serial poll. + * This function should also request service via IEEE 488.2 reqt/reqf + * based on MSS (bit 6 of the status_byte) and new_reason_for_service. + * reqt should be set true if new_reason_for_service is true, + * and reqf should be set true if MSS is false. This function + * will never be called with MSS false and new_reason_for_service + * true simultaneously, so don't worry about that case. + * + * This method implements the serial poll response method described + * by IEEE 488.2 section 11.3.3.4.1 "Preferred Implementation". + * + * If this method is left NULL by the driver, then the user library + * function ibrsv2 will not work. + */ + void (*serial_poll_response2)(gpib_board_t *board, uint8_t status_byte, + int new_reason_for_service); + /* returns the byte the board will send in response to a serial poll. + */ + uint8_t (*serial_poll_status)(gpib_board_t *board); + /* adjust T1 delay */ + unsigned int (*t1_delay)(gpib_board_t *board, unsigned int nano_sec); + /* go to local mode */ + void (*return_to_local)(gpib_board_t *board); + /* board does not support 7 bit eos comparisons */ + unsigned no_7_bit_eos : 1; + /* skip check for listeners before trying to send command bytes */ + unsigned skip_check_for_command_acceptors : 1; +}; + +typedef struct { + struct list_head event_head; + spinlock_t lock; // for access to event list + unsigned int num_events; + unsigned dropped_event : 1; +} gpib_event_queue_t; + +static inline void init_event_queue(gpib_event_queue_t *queue) +{ + INIT_LIST_HEAD(&queue->event_head); + queue->num_events = 0; + queue->dropped_event = 0; + spin_lock_init(&queue->lock); +} + +/* struct for supporting polling operation when irq is not available */ +struct gpib_pseudo_irq { + struct timer_list timer; + irqreturn_t (*handler)(int irq, void *arg); + gpib_board_t *board; + atomic_t active; +}; + +static inline void init_gpib_pseudo_irq(struct gpib_pseudo_irq *pseudo_irq) +{ + pseudo_irq->handler = NULL; + timer_setup(&pseudo_irq->timer, NULL, 0); + atomic_set(&pseudo_irq->active, 0); +} + +/* list so we can make a linked list of drivers */ +typedef struct gpib_interface_list_struct { + struct list_head list; + gpib_interface_t *interface; + struct module *module; +} gpib_interface_list_t; + +/* One gpib_board_t is allocated for each physical board in the computer. + * It provides storage for variables local to each board, and interface + * functions for performing operations on the board + */ +struct gpib_board_struct { + /* functions used by this board */ + gpib_interface_t *interface; + /* Pointer to module whose use count we should increment when + * interface is in use + */ + struct module *provider_module; + /* buffer used to store read/write data for this board */ + u8 *buffer; + /* length of buffer */ + unsigned int buffer_length; + /* Used to hold the board's current status (see update_status() above) + */ + unsigned long status; + /* Driver should only sleep on this wait queue. It is special in that the + * core will wake this queue and set the TIMO bit in 'status' when the + * watchdog timer times out. + */ + wait_queue_head_t wait; + /* Lock that only allows one process to access this board at a time. + * Has to be first in any locking order, since it can be locked over + * multiple ioctls. + */ + struct mutex user_mutex; + /* Mutex which compensates for removal of "big kernel lock" from kernel. + * Should not be held for extended waits. + */ + struct mutex big_gpib_mutex; + /* pid of last process to lock the board mutex */ + pid_t locking_pid; + spinlock_t locking_pid_spinlock; // lock for setting locking pid + /* Spin lock for dealing with races with the interrupt handler */ + spinlock_t spinlock; + /* Watchdog timer to enable timeouts */ + struct timer_list timer; + /* device of attached driver if any */ + struct device *dev; + /* gpib_common device gpibN */ + struct device *gpib_dev; + /* 'private_data' can be used as seen fit by the driver to + * store additional variables for this board + */ + void *private_data; + /* Number of open file descriptors using this board */ + unsigned int use_count; + /* list of open devices connected to this board */ + struct list_head device_list; + /* primary address */ + unsigned int pad; + /* secondary address */ + int sad; + /* timeout for io operations, in microseconds */ + unsigned int usec_timeout; + /* board's parallel poll configuration byte */ + u8 parallel_poll_configuration; + /* t1 delay we are using */ + unsigned int t1_nano_sec; + /* Count that keeps track of whether board is up and running or not */ + unsigned int online; + /* number of processes trying to autopoll */ + int autospollers; + /* autospoll kernel thread */ + struct task_struct *autospoll_task; + /* queue for recording received trigger/clear/ifc events */ + gpib_event_queue_t event_queue; + /* minor number for this board's device file */ + int minor; + /* struct to deal with polling mode*/ + struct gpib_pseudo_irq pseudo_irq; + /* error dong autopoll */ + atomic_t stuck_srq; + gpib_board_config_t config; + /* Flag that indicates whether board is system controller of the bus */ + unsigned master : 1; + /* individual status bit */ + unsigned ist : 1; + /* one means local parallel poll mode ieee 488.1 PP2 (or no parallel poll PP0), + * zero means remote parallel poll configuration mode ieee 488.1 PP1 + */ + unsigned local_ppoll_mode : 1; +}; + +/* element of event queue */ +typedef struct { + struct list_head list; + short event_type; +} gpib_event_t; + +/* Each board has a list of gpib_status_queue_t to keep track of all open devices + * on the bus, so we know what address to poll when we get a service request + */ +typedef struct { + /* list_head so we can make a linked list of devices */ + struct list_head list; + unsigned int pad; /* primary gpib address */ + int sad; /* secondary gpib address (negative means disabled) */ + /* stores serial poll bytes for this device */ + struct list_head status_bytes; + unsigned int num_status_bytes; + /* number of times this address is opened */ + unsigned int reference_count; + /* flags loss of status byte error due to limit on size of queue */ + unsigned dropped_byte : 1; +} gpib_status_queue_t; + +typedef struct { + struct list_head list; + u8 poll_byte; +} status_byte_t; + +void init_gpib_status_queue(gpib_status_queue_t *device); + +/* Used to store device-descriptor-specific information */ +typedef struct { + unsigned int pad; /* primary gpib address */ + int sad; /* secondary gpib address (negative means disabled) */ + atomic_t io_in_progress; + unsigned is_board : 1; + unsigned autopoll_enabled : 1; +} gpib_descriptor_t; + +typedef struct { + atomic_t holding_mutex; + gpib_descriptor_t *descriptors[GPIB_MAX_NUM_DESCRIPTORS]; + /* locked while descriptors are being allocated/deallocated */ + struct mutex descriptors_mutex; + unsigned got_module : 1; +} gpib_file_private_t; + +#endif /* __KERNEL__ */ + +#endif /* _GPIB_TYPES_H */ diff --git a/drivers/staging/gpib/include/nec7210.h b/drivers/staging/gpib/include/nec7210.h new file mode 100644 index 00000000000000..c00aba4ce846dc --- /dev/null +++ b/drivers/staging/gpib/include/nec7210.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _NEC7210_H +#define _NEC7210_H + +#include "gpib_state_machines.h" +#include +#include +#include +#include + +#include "gpib_types.h" +#include "nec7210_registers.h" + +/* struct used to provide variables local to a nec7210 chip */ +struct nec7210_priv { + void *iobase; + unsigned int offset; // offset between successive nec7210 io addresses + unsigned int dma_channel; + u8 *dma_buffer; + unsigned int dma_buffer_length; // length of dma buffer + dma_addr_t dma_buffer_addr; // bus address of board->buffer for use with dma + // software copy of bits written to registers + u8 reg_bits[8]; + u8 auxa_bits; // bits written to auxiliary register A + u8 auxb_bits; // bits written to auxiliary register B + // used to keep track of board's state, bit definitions given below + unsigned long state; + /* lock for chips that extend the nec7210 registers by paging in alternate regs */ + spinlock_t register_page_lock; + // wrappers for outb, inb, readb, or writeb + u8 (*read_byte)(struct nec7210_priv *priv, unsigned int register_number); + void (*write_byte)(struct nec7210_priv *priv, u8 byte, unsigned int register_number); + enum nec7210_chipset type; + enum talker_function_state talker_state; + enum listener_function_state listener_state; + void *private; + unsigned srq_pending : 1; +}; + +static inline void init_nec7210_private(struct nec7210_priv *priv) +{ + memset(priv, 0, sizeof(struct nec7210_priv)); + spin_lock_init(&priv->register_page_lock); +} + +// slightly shorter way to access read_byte and write_byte +static inline u8 read_byte(struct nec7210_priv *priv, unsigned int register_number) +{ + return priv->read_byte(priv, register_number); +} + +static inline void write_byte(struct nec7210_priv *priv, u8 byte, unsigned int register_number) +{ + priv->write_byte(priv, byte, register_number); +} + +// struct nec7210_priv.state bit numbers +enum { + PIO_IN_PROGRESS_BN, // pio transfer in progress + DMA_READ_IN_PROGRESS_BN, // dma read transfer in progress + DMA_WRITE_IN_PROGRESS_BN, // dma write transfer in progress + READ_READY_BN, // board has data byte available to read + WRITE_READY_BN, // board is ready to send a data byte + COMMAND_READY_BN, // board is ready to send a command byte + RECEIVED_END_BN, // received END + BUS_ERROR_BN, // output error has occurred + RFD_HOLDOFF_BN, // rfd holdoff in effect + DEV_CLEAR_BN, // device clear received + ADR_CHANGE_BN, // address state change occurred +}; + +// interface functions +int nec7210_read(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read); +int nec7210_write(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, + size_t length, int send_eoi, size_t *bytes_written); +int nec7210_command(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, + size_t length, size_t *bytes_written); +int nec7210_take_control(gpib_board_t *board, struct nec7210_priv *priv, int syncronous); +int nec7210_go_to_standby(gpib_board_t *board, struct nec7210_priv *priv); +void nec7210_request_system_control(gpib_board_t *board, + struct nec7210_priv *priv, int request_control); +void nec7210_interface_clear(gpib_board_t *board, struct nec7210_priv *priv, int assert); +void nec7210_remote_enable(gpib_board_t *board, struct nec7210_priv *priv, int enable); +int nec7210_enable_eos(gpib_board_t *board, struct nec7210_priv *priv, uint8_t eos_bytes, + int compare_8_bits); +void nec7210_disable_eos(gpib_board_t *board, struct nec7210_priv *priv); +unsigned int nec7210_update_status(gpib_board_t *board, struct nec7210_priv *priv, + unsigned int clear_mask); +unsigned int nec7210_update_status_nolock(gpib_board_t *board, struct nec7210_priv *priv); +int nec7210_primary_address(const gpib_board_t *board, + struct nec7210_priv *priv, unsigned int address); +int nec7210_secondary_address(const gpib_board_t *board, struct nec7210_priv *priv, + unsigned int address, int enable); +int nec7210_parallel_poll(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *result); +void nec7210_serial_poll_response(gpib_board_t *board, struct nec7210_priv *priv, uint8_t status); +void nec7210_parallel_poll_configure(gpib_board_t *board, + struct nec7210_priv *priv, unsigned int configuration); +void nec7210_parallel_poll_response(gpib_board_t *board, + struct nec7210_priv *priv, int ist); +uint8_t nec7210_serial_poll_status(gpib_board_t *board, + struct nec7210_priv *priv); +unsigned int nec7210_t1_delay(gpib_board_t *board, + struct nec7210_priv *priv, unsigned int nano_sec); +void nec7210_return_to_local(const gpib_board_t *board, struct nec7210_priv *priv); + +// utility functions +void nec7210_board_reset(struct nec7210_priv *priv, const gpib_board_t *board); +void nec7210_board_online(struct nec7210_priv *priv, const gpib_board_t *board); +unsigned int nec7210_set_reg_bits(struct nec7210_priv *priv, unsigned int reg, + unsigned int mask, unsigned int bits); +void nec7210_set_handshake_mode(gpib_board_t *board, struct nec7210_priv *priv, int mode); +void nec7210_release_rfd_holdoff(gpib_board_t *board, struct nec7210_priv *priv); +uint8_t nec7210_read_data_in(gpib_board_t *board, struct nec7210_priv *priv, int *end); + +// wrappers for io functions +uint8_t nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num); +void nec7210_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num); +uint8_t nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num); +void nec7210_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num); +uint8_t nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num); +void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, + unsigned int register_num); +uint8_t nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num); +void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, + unsigned int register_num); + +// interrupt service routine +irqreturn_t nec7210_interrupt(gpib_board_t *board, struct nec7210_priv *priv); +irqreturn_t nec7210_interrupt_have_status(gpib_board_t *board, + struct nec7210_priv *priv, int status1, int status2); + +#endif //_NEC7210_H diff --git a/drivers/staging/gpib/include/nec7210_registers.h b/drivers/staging/gpib/include/nec7210_registers.h new file mode 100644 index 00000000000000..888803dd97f9e7 --- /dev/null +++ b/drivers/staging/gpib/include/nec7210_registers.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _NEC7210_REGISTERS_H +#define _NEC7210_REGISTERS_H + +enum nec7210_chipset { + NEC7210, // The original + TNT4882, // NI + NAT4882, // NI + CB7210, // measurement computing + IOT7210, // iotech + IGPIB7210, // Ines + TNT5004, // NI (minor differences to TNT4882) +}; + +/* nec7210 register numbers (might need to be multiplied by + * a board-dependent offset to get actually io address offset) + */ +// write registers +enum nec7210_write_regs { + CDOR, // command/data out + IMR1, // interrupt mask 1 + IMR2, // interrupt mask 2 + SPMR, // serial poll mode + ADMR, // address mode + AUXMR, // auxiliary mode + ADR, // address + EOSR, // end-of-string + + // nec7210 has 8 registers + nec7210_num_registers = 8, +}; + +// read registers +enum nec7210_read_regs { + DIR, // data in + ISR1, // interrupt status 1 + ISR2, // interrupt status 2 + SPSR, // serial poll status + ADSR, // address status + CPTR, // command pass though + ADR0, // address 1 + ADR1, // address 2 +}; + +//bit definitions common to nec-7210 compatible registers + +// ISR1: interrupt status register 1 +enum isr1_bits { + HR_DI = (1 << 0), + HR_DO = (1 << 1), + HR_ERR = (1 << 2), + HR_DEC = (1 << 3), + HR_END = (1 << 4), + HR_DET = (1 << 5), + HR_APT = (1 << 6), + HR_CPT = (1 << 7), +}; + +// IMR1: interrupt mask register 1 +enum imr1_bits { + HR_DIIE = (1 << 0), + HR_DOIE = (1 << 1), + HR_ERRIE = (1 << 2), + HR_DECIE = (1 << 3), + HR_ENDIE = (1 << 4), + HR_DETIE = (1 << 5), + HR_APTIE = (1 << 6), + HR_CPTIE = (1 << 7), +}; + +// ISR2, interrupt status register 2 +enum isr2_bits { + HR_ADSC = (1 << 0), + HR_REMC = (1 << 1), + HR_LOKC = (1 << 2), + HR_CO = (1 << 3), + HR_REM = (1 << 4), + HR_LOK = (1 << 5), + HR_SRQI = (1 << 6), + HR_INT = (1 << 7), +}; + +// IMR2, interrupt mask register 2 +enum imr2_bits { + // all the bits in this register that enable interrupts + IMR2_ENABLE_INTR_MASK = 0x4f, + HR_ACIE = (1 << 0), + HR_REMIE = (1 << 1), + HR_LOKIE = (1 << 2), + HR_COIE = (1 << 3), + HR_DMAI = (1 << 4), + HR_DMAO = (1 << 5), + HR_SRQIE = (1 << 6), +}; + +// SPSR, serial poll status register +enum spsr_bits { + HR_PEND = (1 << 6), +}; + +// SPMR, serial poll mode register +enum spmr_bits { + HR_RSV = (1 << 6), +}; + +// ADSR, address status register +enum adsr_bits { + HR_MJMN = (1 << 0), + HR_TA = (1 << 1), + HR_LA = (1 << 2), + HR_TPAS = (1 << 3), + HR_LPAS = (1 << 4), + HR_SPMS = (1 << 5), + HR_NATN = (1 << 6), + HR_CIC = (1 << 7), +}; + +// ADMR, address mode register +enum admr_bits { + HR_ADM0 = (1 << 0), + HR_ADM1 = (1 << 1), + HR_TRM0 = (1 << 4), + HR_TRM1 = (1 << 5), + HR_TRM_EOIOE_TRIG = 0, + HR_TRM_CIC_TRIG = HR_TRM0, + HR_TRM_CIC_EOIOE = HR_TRM1, + HR_TRM_CIC_PE = HR_TRM0 | HR_TRM1, + HR_LON = (1 << 6), + HR_TON = (1 << 7), +}; + +// ADR, bits used in address0, address1 and address0/1 registers +enum adr_bits { + ADDRESS_MASK = 0x1f, /* mask to specify lower 5 bits */ + HR_DL = (1 << 5), + HR_DT = (1 << 6), + HR_ARS = (1 << 7), +}; + +// ADR1, address1 register +enum adr1_bits { + HR_EOI = (1 << 7), +}; + +// AUXMR, auxiliary mode register +enum auxmr_bits { + ICR = 0x20, + PPR = 0x60, + AUXRA = 0x80, + AUXRB = 0xa0, + AUXRE = 0xc0, +}; + +// auxra, auxiliary register A +enum auxra_bits { + HR_HANDSHAKE_MASK = 0x3, + HR_HLDA = 0x1, + HR_HLDE = 0x2, + HR_LCM = 0x3, /* auxra listen continuous */ + HR_REOS = 0x4, + HR_XEOS = 0x8, + HR_BIN = 0x10, +}; + +// auxrb, auxiliary register B +enum auxrb_bits { + HR_CPTE = (1 << 0), + HR_SPEOI = (1 << 1), + HR_TRI = (1 << 2), + HR_INV = (1 << 3), + HR_ISS = (1 << 4), +}; + +enum auxre_bits { + HR_DAC_HLD_DCAS = 0x1, /* perform DAC holdoff on receiving clear */ + HR_DAC_HLD_DTAS = 0x2, /* perform DAC holdoff on receiving trigger */ +}; + +// parallel poll register +enum ppr_bits { + HR_PPS = (1 << 3), + HR_PPU = (1 << 4), +}; + +/* 7210 Auxiliary Commands */ +enum aux_cmds { + AUX_PON = 0x0, /* Immediate Execute pon */ + AUX_CPPF = 0x1, /* Clear Parallel Poll Flag */ + AUX_CR = 0x2, /* Chip Reset */ + AUX_FH = 0x3, /* Finish Handshake */ + AUX_TRIG = 0x4, /* Trigger */ + AUX_RTL = 0x5, /* Return to local */ + AUX_SEOI = 0x6, /* Send EOI */ + AUX_NVAL = 0x7, /* Non-Valid Secondary Command or Address */ + AUX_SPPF = 0x9, /* Set Parallel Poll Flag */ + AUX_VAL = 0xf, /* Valid Secondary Command or Address */ + AUX_GTS = 0x10, /* Go To Standby */ + AUX_TCA = 0x11, /* Take Control Asynchronously */ + AUX_TCS = 0x12, /* Take Control Synchronously */ + AUX_LTN = 0x13, /* Listen */ + AUX_DSC = 0x14, /* Disable System Control */ + AUX_CIFC = 0x16, /* Clear IFC */ + AUX_CREN = 0x17, /* Clear REN */ + AUX_TCSE = 0x1a, /* Take Control Synchronously on End */ + AUX_LTNC = 0x1b, /* Listen in Continuous Mode */ + AUX_LUN = 0x1c, /* Local Unlisten */ + AUX_EPP = 0x1d, /* Execute Parallel Poll */ + AUX_SIFC = 0x1e, /* Set IFC */ + AUX_SREN = 0x1f, /* Set REN */ +}; + +#endif //_NEC7210_REGISTERS_H diff --git a/drivers/staging/gpib/include/plx9050.h b/drivers/staging/gpib/include/plx9050.h new file mode 100644 index 00000000000000..66c56335f5c0b4 --- /dev/null +++ b/drivers/staging/gpib/include/plx9050.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * Header for plx9050 pci chip + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _PLX9050_GPIB_H +#define _PLX9050_GPIB_H + +// plx pci chip registers and bits +enum { + PLX9050_INTCSR_REG = 0x4c, + PLX9050_CNTRL_REG = 0x50 +}; + +enum plx9050_intcsr_bits { + PLX9050_LINTR1_EN_BIT = 0x1, + PLX9050_LINTR1_POLARITY_BIT = 0x2, + PLX9050_LINTR1_STATUS_BIT = 0x4, + PLX9050_LINTR2_EN_BIT = 0x8, + PLX9050_LINTR2_POLARITY_BIT = 0x10, + PLX9050_LINTR2_STATUS_BIT = 0x20, + PLX9050_PCI_INTR_EN_BIT = 0x40, + PLX9050_SOFT_INTR_BIT = 0x80, + PLX9050_LINTR1_SELECT_ENABLE_BIT = 0x100, //9052 extension + PLX9050_LINTR2_SELECT_ENABLE_BIT = 0x200, //9052 extension + PLX9050_LINTR1_EDGE_CLEAR_BIT = 0x400, //9052 extension + PLX9050_LINTR2_EDGE_CLEAR_BIT = 0x800, //9052 extension +}; + +enum plx9050_cntrl_bits { + PLX9050_WAITO_NOT_USER0_SELECT_BIT = 0x1, + PLX9050_USER0_OUTPUT_BIT = 0x2, + PLX9050_USER0_DATA_BIT = 0x4, + PLX9050_LLOCK_NOT_USER1_SELECT_BIT = 0x8, + PLX9050_USER1_OUTPUT_BIT = 0x10, + PLX9050_USER1_DATA_BIT = 0x20, + PLX9050_CS2_NOT_USER2_SELECT_BIT = 0x40, + PLX9050_USER2_OUTPUT_BIT = 0x80, + PLX9050_USER2_DATA_BIT = 0x100, + PLX9050_CS3_NOT_USER3_SELECT_BIT = 0x200, + PLX9050_USER3_OUTPUT_BIT = 0x400, + PLX9050_USER3_DATA_BIT = 0x800, + PLX9050_PCIBAR_ENABLE_MASK = 0x3000, + PLX9050_PCIBAR_MEMORY_AND_IO_ENABLE_BITS = 0x0, + PLX9050_PCIBAR_MEMORY_NO_IO_ENABLE_BITS = 0x1000, + PLX9050_PCIBAR_IO_NO_MEMORY_ENABLE_BITS = 0x2000, + PLX9050_PCIBAR_MEMORY_AND_IO_TOO_ENABLE_BITS = 0x3000, + PLX9050_PCI_READ_MODE_BIT = 0x4000, + PLX9050_PCI_READ_WITH_WRITE_FLUSH_MODE_BIT = 0x8000, + PLX9050_PCI_READ_NO_FLUSH_MODE_BIT = 0x10000, + PLX9050_PCI_READ_NO_WRITE_MODE_BIT = 0x20000, + PLX9050_PCI_WRITE_MODE_BIT = 0x40000, + PLX9050_PCI_RETRY_DELAY_MASK = 0x780000, + PLX9050_DIRECT_SLAVE_LOCK_ENABLE_BIT = 0x800000, + PLX9050_EEPROM_CLOCK_BIT = 0x1000000, + PLX9050_EEPROM_CHIP_SELECT_BIT = 0x2000000, + PLX9050_WRITE_TO_EEPROM_BIT = 0x4000000, + PLX9050_READ_EEPROM_DATA_BIT = 0x8000000, + PLX9050_EEPROM_VALID_BIT = 0x10000000, + PLX9050_RELOAD_CONFIG_REGISTERS_BIT = 0x20000000, + PLX9050_PCI_SOFTWARE_RESET_BIT = 0x40000000, + PLX9050_MASK_REVISION_BIT = 0x80000000 +}; + +static inline unsigned int PLX9050_PCI_RETRY_DELAY_BITS(unsigned int clocks) +{ + return ((clocks / 8) << 19) & PLX9050_PCI_RETRY_DELAY_MASK; +} + +#endif // _PLX9050_GPIB_H diff --git a/drivers/staging/gpib/include/quancom_pci.h b/drivers/staging/gpib/include/quancom_pci.h new file mode 100644 index 00000000000000..cdaf0d056be9e7 --- /dev/null +++ b/drivers/staging/gpib/include/quancom_pci.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * Quancom pci stuff + * copyright (C) 2005 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _QUANCOM_PCI_H +#define _QUANCOM_PCI_H + +/* quancom registers */ +enum quancom_regs { + QUANCOM_IRQ_CONTROL_STATUS_REG = 0xfc, +}; + +enum quancom_irq_control_status_bits { + QUANCOM_IRQ_ASSERTED_BIT = 0x1, /* readable */ + /* (any write to the register clears the interrupt)*/ + QUANCOM_IRQ_ENABLE_BIT = 0x4, /* writeable */ +}; + +#endif // _QUANCOM_PCI_H diff --git a/drivers/staging/gpib/include/tms9914.h b/drivers/staging/gpib/include/tms9914.h new file mode 100644 index 00000000000000..456b488212d2b7 --- /dev/null +++ b/drivers/staging/gpib/include/tms9914.h @@ -0,0 +1,274 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _TMS9914_H +#define _TMS9914_H + +#include +#include +#include "gpib_state_machines.h" +#include "gpib_types.h" + +enum tms9914_holdoff_mode { + TMS9914_HOLDOFF_NONE, + TMS9914_HOLDOFF_EOI, + TMS9914_HOLDOFF_ALL, +}; + +/* struct used to provide variables local to a tms9914 chip */ +struct tms9914_priv { + void *iobase; + unsigned int offset; // offset between successive tms9914 io addresses + unsigned int dma_channel; + // software copy of bits written to interrupt mask registers + u8 imr0_bits, imr1_bits; + // bits written to address mode register + u8 admr_bits; + u8 auxa_bits; // bits written to auxiliary register A + // used to keep track of board's state, bit definitions given below + unsigned long state; + u8 eos; // eos character + short eos_flags; + u8 spoll_status; + enum tms9914_holdoff_mode holdoff_mode; + unsigned int ppoll_line; + enum talker_function_state talker_state; + enum listener_function_state listener_state; + unsigned ppoll_sense : 1; + unsigned ppoll_enable : 1; + unsigned ppoll_configure_state : 1; + unsigned primary_listen_addressed : 1; + unsigned primary_talk_addressed : 1; + unsigned holdoff_on_end : 1; + unsigned holdoff_on_all : 1; + unsigned holdoff_active : 1; + // wrappers for outb, inb, readb, or writeb + u8 (*read_byte)(struct tms9914_priv *priv, unsigned int register_number); + void (*write_byte)(struct tms9914_priv *priv, u8 byte, unsigned int + register_number); +}; + +// slightly shorter way to access read_byte and write_byte +static inline u8 read_byte(struct tms9914_priv *priv, unsigned int register_number) +{ + return priv->read_byte(priv, register_number); +} + +static inline void write_byte(struct tms9914_priv *priv, u8 byte, unsigned int register_number) +{ + priv->write_byte(priv, byte, register_number); +} + +// struct tms9914_priv.state bit numbers +enum { + PIO_IN_PROGRESS_BN, // pio transfer in progress + DMA_READ_IN_PROGRESS_BN, // dma read transfer in progress + DMA_WRITE_IN_PROGRESS_BN, // dma write transfer in progress + READ_READY_BN, // board has data byte available to read + WRITE_READY_BN, // board is ready to send a data byte + COMMAND_READY_BN, // board is ready to send a command byte + RECEIVED_END_BN, // received END + BUS_ERROR_BN, // bus error + DEV_CLEAR_BN, // device clear received +}; + +// interface functions +int tms9914_read(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read); +int tms9914_write(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *buffer, + size_t length, int send_eoi, size_t *bytes_written); +int tms9914_command(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *buffer, + size_t length, size_t *bytes_written); +int tms9914_take_control(gpib_board_t *board, struct tms9914_priv *priv, int syncronous); +/* alternate version of tms9914_take_control which works around buggy tcs + * implementation. + */ +int tms9914_take_control_workaround(gpib_board_t *board, struct tms9914_priv *priv, + int syncronous); +int tms9914_go_to_standby(gpib_board_t *board, struct tms9914_priv *priv); +void tms9914_request_system_control(gpib_board_t *board, struct tms9914_priv *priv, + int request_control); +void tms9914_interface_clear(gpib_board_t *board, struct tms9914_priv *priv, int assert); +void tms9914_remote_enable(gpib_board_t *board, struct tms9914_priv *priv, int enable); +int tms9914_enable_eos(gpib_board_t *board, struct tms9914_priv *priv, uint8_t eos_bytes, + int compare_8_bits); +void tms9914_disable_eos(gpib_board_t *board, struct tms9914_priv *priv); +unsigned int tms9914_update_status(gpib_board_t *board, struct tms9914_priv *priv, + unsigned int clear_mask); +int tms9914_primary_address(gpib_board_t *board, + struct tms9914_priv *priv, unsigned int address); +int tms9914_secondary_address(gpib_board_t *board, struct tms9914_priv *priv, + unsigned int address, int enable); +int tms9914_parallel_poll(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *result); +void tms9914_parallel_poll_configure(gpib_board_t *board, + struct tms9914_priv *priv, uint8_t config); +void tms9914_parallel_poll_response(gpib_board_t *board, + struct tms9914_priv *priv, int ist); +void tms9914_serial_poll_response(gpib_board_t *board, struct tms9914_priv *priv, uint8_t status); +uint8_t tms9914_serial_poll_status(gpib_board_t *board, struct tms9914_priv *priv); +int tms9914_line_status(const gpib_board_t *board, struct tms9914_priv *priv); +unsigned int tms9914_t1_delay(gpib_board_t *board, struct tms9914_priv *priv, + unsigned int nano_sec); +void tms9914_return_to_local(const gpib_board_t *board, struct tms9914_priv *priv); + +// utility functions +void tms9914_board_reset(struct tms9914_priv *priv); +void tms9914_online(gpib_board_t *board, struct tms9914_priv *priv); +void tms9914_release_holdoff(struct tms9914_priv *priv); +void tms9914_set_holdoff_mode(struct tms9914_priv *priv, enum tms9914_holdoff_mode mode); + +// wrappers for io functions +uint8_t tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num); +void tms9914_ioport_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num); +uint8_t tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num); +void tms9914_iomem_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num); + +// interrupt service routine +irqreturn_t tms9914_interrupt(gpib_board_t *board, struct tms9914_priv *priv); +irqreturn_t tms9914_interrupt_have_status(gpib_board_t *board, struct tms9914_priv *priv, + int status1, int status2); + +// tms9914 has 8 registers +enum { + ms9914_num_registers = 8, +}; + +/* tms9914 register numbers (might need to be multiplied by + * a board-dependent offset to get actually io address offset) + */ +// write registers +enum { + IMR0 = 0, /* interrupt mask 0 */ + IMR1 = 1, /* interrupt mask 1 */ + AUXCR = 3, /* auxiliary command */ + ADR = 4, // address register + SPMR = 5, // serial poll mode register + PPR = 6, /* parallel poll */ + CDOR = 7, /* data out register */ +}; + +// read registers +enum { + ISR0 = 0, /* interrupt status 0 */ + ISR1 = 1, /* interrupt status 1 */ + ADSR = 2, /* address status */ + BSR = 3, /* bus status */ + CPTR = 6, /* command pass thru */ + DIR = 7, /* data in register */ +}; + +//bit definitions common to tms9914 compatible registers + +/* ISR0 - Register bits */ +enum isr0_bits { + HR_MAC = (1 << 0), /* My Address Change */ + HR_RLC = (1 << 1), /* Remote/Local change */ + HR_SPAS = (1 << 2), /* Serial Poll active State */ + HR_END = (1 << 3), /* END (EOI or EOS) */ + HR_BO = (1 << 4), /* Byte Out */ + HR_BI = (1 << 5), /* Byte In */ +}; + +/* IMR0 - Register bits */ +enum imr0_bits { + HR_MACIE = (1 << 0), /* */ + HR_RLCIE = (1 << 1), /* */ + HR_SPASIE = (1 << 2), /* */ + HR_ENDIE = (1 << 3), /* */ + HR_BOIE = (1 << 4), /* */ + HR_BIIE = (1 << 5), /* */ +}; + +/* ISR1 - Register bits */ +enum isr1_bits { + HR_IFC = (1 << 0), /* IFC asserted */ + HR_SRQ = (1 << 1), /* SRQ asserted */ + HR_MA = (1 << 2), /* My Address */ + HR_DCAS = (1 << 3), /* Device Clear active State */ + HR_APT = (1 << 4), /* Address pass Through */ + HR_UNC = (1 << 5), /* Unrecognized Command */ + HR_ERR = (1 << 6), /* Data Transmission Error */ + HR_GET = (1 << 7), /* Group execute Trigger */ +}; + +/* IMR1 - Register bits */ +enum imr1_bits { + HR_IFCIE = (1 << 0), /* */ + HR_SRQIE = (1 << 1), /* */ + HR_MAIE = (1 << 2), /* */ + HR_DCASIE = (1 << 3), /* */ + HR_APTIE = (1 << 4), /* */ + HR_UNCIE = (1 << 5), /* */ + HR_ERRIE = (1 << 6), /* */ + HR_GETIE = (1 << 7), /* */ +}; + +/* ADSR - Register bits */ +enum adsr_bits { + HR_ULPA = (1 << 0), /* Store last address LSB */ + HR_TA = (1 << 1), /* Talker Adressed */ + HR_LA = (1 << 2), /* Listener adressed */ + HR_TPAS = (1 << 3), /* talker primary address state */ + HR_LPAS = (1 << 4), /* listener " */ + HR_ATN = (1 << 5), /* ATN active */ + HR_LLO = (1 << 6), /* LLO active */ + HR_REM = (1 << 7), /* REM active */ +}; + +/* ADR - Register bits */ +enum adr_bits { + ADDRESS_MASK = 0x1f, /* mask to specify lower 5 bits for ADR */ + HR_DAT = (1 << 5), /* disable talker */ + HR_DAL = (1 << 6), /* disable listener */ + HR_EDPA = (1 << 7), /* enable dual primary addressing */ +}; + +enum bus_status_bits { + BSR_REN_BIT = 0x1, + BSR_IFC_BIT = 0x2, + BSR_SRQ_BIT = 0x4, + BSR_EOI_BIT = 0x8, + BSR_NRFD_BIT = 0x10, + BSR_NDAC_BIT = 0x20, + BSR_DAV_BIT = 0x40, + BSR_ATN_BIT = 0x80, +}; + +/*---------------------------------------------------------*/ +/* TMS 9914 Auxiliary Commands */ +/*---------------------------------------------------------*/ + +enum aux_cmd_bits { + AUX_CS = 0x80, /* set bit instead of clearing it, used with commands marked 'd' below */ + AUX_CHIP_RESET = 0x0, /* d Chip reset */ + AUX_INVAL = 0x1, // release dac holdoff, invalid command byte + AUX_VAL = (AUX_INVAL | AUX_CS), // release dac holdoff, valid command byte + AUX_RHDF = 0x2, /* X Release RFD holdoff */ + AUX_HLDA = 0x3, /* d holdoff on all data */ + AUX_HLDE = 0x4, /* d holdoff on EOI only */ + AUX_NBAF = 0x5, /* X Set new byte available false */ + AUX_FGET = 0x6, /* d force GET */ + AUX_RTL = 0x7, /* d return to local */ + AUX_SEOI = 0x8, /* X send EOI with next byte */ + AUX_LON = 0x9, /* d Listen only */ + AUX_TON = 0xa, /* d Talk only */ + AUX_GTS = 0xb, /* X goto standby */ + AUX_TCA = 0xc, /* X take control asynchronously */ + AUX_TCS = 0xd, /* X take " synchronously */ + AUX_RPP = 0xe, /* d Request parallel poll */ + AUX_SIC = 0xf, /* d send interface clear */ + AUX_SRE = 0x10, /* d send remote enable */ + AUX_RQC = 0x11, /* X request control */ + AUX_RLC = 0x12, /* X release control */ + AUX_DAI = 0x13, /* d disable all interrupts */ + AUX_PTS = 0x14, /* X pass through next secondary */ + AUX_STDL = 0x15, /* d short T1 delay */ + AUX_SHDW = 0x16, /* d shadow handshake */ + AUX_VSTDL = 0x17, /* d very short T1 delay (smj9914 extension) */ + AUX_RSV2 = 0x18, /* d request service bit 2 (smj9914 extension) */ +}; + +#endif //_TMS9914_H diff --git a/drivers/staging/gpib/include/tnt4882_registers.h b/drivers/staging/gpib/include/tnt4882_registers.h new file mode 100644 index 00000000000000..1b1441cd03d50e --- /dev/null +++ b/drivers/staging/gpib/include/tnt4882_registers.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002, 2004 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _TNT4882_REGISTERS_H +#define _TNT4882_REGISTERS_H + +// tnt4882 register offsets +enum { + ACCWR = 0x5, + // offset of auxiliary command register in 9914 mode + AUXCR = 0x6, + INTRT = 0x7, + // register number for auxiliary command register when swap bit is set (9914 mode) + SWAPPED_AUXCR = 0xa, + HSSEL = 0xd, // handshake select register + CNT2 = 0x9, + CNT3 = 0xb, + CFG = 0x10, + SASR = 0x1b, + IMR0 = 0x1d, + IMR3 = 0x12, + CNT0 = 0x14, + CNT1 = 0x16, + KEYREG = 0x17, // key control register (7210 mode only) + CSR = KEYREG, + FIFOB = 0x18, + FIFOA = 0x19, + CCR = 0x1a, // carry cycle register + CMDR = 0x1c, // command register + TIMER = 0x1e, // timer register + + STS1 = 0x10, /* T488 Status Register 1 */ + STS2 = 0x1c, /* T488 Status Register 2 */ + ISR0 = IMR0, + ISR3 = 0x1a, /* T488 Interrupt Status Register 3 */ + BCR = 0x1f, /* bus control/status register */ + BSR = BCR, +}; + +enum { + tnt_pagein_offset = 0x11, +}; + +/*============================================================*/ + +/* TURBO-488 registers bit definitions */ + +enum bus_control_status_bits { + BCSR_REN_BIT = 0x1, + BCSR_IFC_BIT = 0x2, + BCSR_SRQ_BIT = 0x4, + BCSR_EOI_BIT = 0x8, + BCSR_NRFD_BIT = 0x10, + BCSR_NDAC_BIT = 0x20, + BCSR_DAV_BIT = 0x40, + BCSR_ATN_BIT = 0x80, +}; + +/* CFG -- Configuration Register (write only) */ +enum cfg_bits { + TNT_COMMAND = 0x80, /* bytes are command bytes instead of data bytes + * (tnt4882 one-chip and newer only?) + */ + TNT_TLCHE = (1 << 6), /* halt transfer on imr0, imr1, or imr2 interrupt */ + TNT_IN = (1 << 5), /* transfer is GPIB read */ + TNT_A_B = (1 << 4), /* order to use fifos 1=fifo A first(big endian), + * 0=fifo b first(little endian) + */ + TNT_CCEN = (1 << 3), /* enable carry cycle */ + TNT_TMOE = (1 << 2), /* enable CPU bus time limit */ + TNT_TIM_BYTN = (1 << 1), /* tmot reg is: 1=125ns clocks, 0=num bytes */ + TNT_B_16BIT = (1 << 0), /* 1=FIFO is 16-bit register, 0=8-bit */ +}; + +/* CMDR -- Command Register */ +enum cmdr_bits { + CLRSC = 0x2, /* clear the system controller bit */ + SETSC = 0x3, /* set the system controller bit */ + GO = 0x4, /* start fifos */ + STOP = 0x8, /* stop fifos */ + RESET_FIFO = 0x10, /* reset the FIFOs */ + SOFT_RESET = 0x22, /* issue a software reset */ + HARD_RESET = 0x40 /* 500x only? */ +}; + +/* HSSEL -- handshake select register (write only) */ +enum hssel_bits { + TNT_ONE_CHIP_BIT = 0x1, + NODMA = 0x10, + TNT_GO2SIDS_BIT = 0x20, +}; + +/* IMR0 -- Interrupt Mode Register 0 */ +enum imr0_bits { + TNT_SYNCIE_BIT = 0x1, /* handshake sync */ + TNT_TOIE_BIT = 0x2, /* timeout */ + TNT_ATNIE_BIT = 0x4, /* ATN interrupt */ + TNT_IFCIE_BIT = 0x8, /* interface clear interrupt */ + TNT_BTO_BIT = 0x10, /* byte timeout */ + TNT_NLEN_BIT = 0x20, /* treat new line as EOS char */ + TNT_STBOIE_BIT = 0x40, /* status byte out */ + TNT_IMR0_ALWAYS_BITS = 0x80, /* always set this bit on write */ +}; + +/* ISR0 -- Interrupt Status Register 0 */ +enum isr0_bits { + TNT_SYNC_BIT = 0x1, /* handshake sync */ + TNT_TO_BIT = 0x2, /* timeout */ + TNT_ATNI_BIT = 0x4, /* ATN interrupt */ + TNT_IFCI_BIT = 0x8, /* interface clear interrupt */ + TNT_EOS_BIT = 0x10, /* end of string */ + TNT_NL_BIT = 0x20, /* new line receive */ + TNT_STBO_BIT = 0x40, /* status byte out */ + TNT_NBA_BIT = 0x80, /* new byte available */ +}; + +/* ISR3 -- Interrupt Status Register 3 (read only) */ +enum isr3_bits { + HR_DONE = (1 << 0), /* transfer done */ + HR_TLCI = (1 << 1), /* isr0, isr1, or isr2 interrupt asserted */ + HR_NEF = (1 << 2), /* NOT empty fifo */ + HR_NFF = (1 << 3), /* NOT full fifo */ + HR_STOP = (1 << 4), /* fifo empty or STOP command issued */ + HR_SRQI_CIC = (1 << 5), /* SRQ asserted and we are CIC (500x only?)*/ + HR_INTR = (1 << 7), /* isr3 interrupt active */ +}; + +enum keyreg_bits { + MSTD = 0x20, // enable 350ns T1 delay +}; + +/* STS1 -- Status Register 1 (read only) */ +enum sts1_bits { + S_DONE = 0x80, /* DMA done */ + S_SC = 0x40, /* is system controller */ + S_IN = 0x20, /* DMA in (to memory) */ + S_DRQ = 0x10, /* DRQ line (for diagnostics) */ + S_STOP = 0x08, /* DMA stopped */ + S_NDAV = 0x04, /* inverse of DAV */ + S_HALT = 0x02, /* status of transfer machine */ + S_GSYNC = 0x01, /* indicates if GPIB is in sync w I/O */ +}; + +/* STS2 -- Status Register 2 */ +enum sts2_bits { + AFFN = (1 << 3), /* "A full FIFO NOT" (0=FIFO full) */ + AEFN = (1 << 2), /* "A empty FIFO NOT" (0=FIFO empty) */ + BFFN = (1 << 1), /* "B full FIFO NOT" (0=FIFO full) */ + BEFN = (1 << 0), /* "B empty FIFO NOT" (0=FIFO empty) */ +}; + +// Auxiliary commands +enum tnt4882_aux_cmds { + AUX_9914 = 0x15, // switch to 9914 mode + AUX_REQT = 0x18, + AUX_REQF = 0x19, + AUX_PAGEIN = 0x50, /* page in alternate registers */ + AUX_HLDI = 0x51, // rfd holdoff immediately + AUX_CLEAR_END = 0x55, + AUX_7210 = 0x99, // switch to 7210 mode +}; + +enum tnt4882_aux_regs { + AUXRG = 0x40, + AUXRI = 0xe0, +}; + +enum auxg_bits { + /* no talking when no listeners bit (prevents bus errors when data written at wrong time) */ + NTNL_BIT = 0x8, + RPP2_BIT = 0x4, /* set/clear local rpp message */ + CHES_BIT = 0x1, /*clear holdoff on end select bit*/ +}; + +enum auxi_bits { + SISB = 0x1, // static interrupt bits (don't clear isr1, isr2 on read) + PP2 = 0x4, // ignore remote parallel poll configuration + USTD = 0x8, // ultra short (1100 nanosec) T1 delay +}; + +enum sasr_bits { + ACRDY_BIT = 0x4, /* acceptor ready state */ + ADHS_BIT = 0x8, /* acceptor data holdoff state */ + ANHS2_BIT = 0x10, /* acceptor not ready holdoff immediately state */ + ANHS1_BIT = 0x20, /* acceptor not ready holdoff state */ + AEHS_BIT = 0x40, /* acceptor end holdoff state */ +}; + +#endif // _TNT4882_REGISTERS_H diff --git a/drivers/staging/gpib/ines/Makefile b/drivers/staging/gpib/ines/Makefile new file mode 100644 index 00000000000000..cdcaa59a4e39c5 --- /dev/null +++ b/drivers/staging/gpib/ines/Makefile @@ -0,0 +1,4 @@ +ccflags-$(CONFIG_GPIB_PCMCIA) := -DGPIB_PCMCIA +obj-m += ines_gpib.o + + diff --git a/drivers/staging/gpib/ines/ines.h b/drivers/staging/gpib/ines/ines.h new file mode 100644 index 00000000000000..7e8302619998fe --- /dev/null +++ b/drivers/staging/gpib/ines/ines.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * Header for ines GPIB boards + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _INES_GPIB_H +#define _INES_GPIB_H + +#include "nec7210.h" +#include "gpibP.h" +#include "plx9050.h" +#include "amcc5920.h" +#include "quancom_pci.h" +#include + +enum ines_pci_chip { + PCI_CHIP_NONE, + PCI_CHIP_PLX9050, + PCI_CHIP_AMCC5920, + PCI_CHIP_QUANCOM, + PCI_CHIP_QUICKLOGIC5030, +}; + +struct ines_priv { + struct nec7210_priv nec7210_priv; + struct pci_dev *pci_device; + // base address for plx9052 pci chip + unsigned long plx_iobase; + // base address for amcc5920 pci chip + unsigned long amcc_iobase; + unsigned int irq; + enum ines_pci_chip pci_chip_type; + u8 extend_mode_bits; +}; + +// interfaces +extern gpib_interface_t ines_pci_interface; +extern gpib_interface_t ines_pci_accel_interface; +extern gpib_interface_t ines_pcmcia_interface; +extern gpib_interface_t ines_pcmcia_accel_interface; +extern gpib_interface_t ines_pcmcia_unaccel_interface; + +// interface functions +int ines_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read); +int ines_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written); +int ines_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read); +int ines_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written); +int ines_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written); +int ines_take_control(gpib_board_t *board, int synchronous); +int ines_go_to_standby(gpib_board_t *board); +void ines_request_system_control(gpib_board_t *board, int request_control); +void ines_interface_clear(gpib_board_t *board, int assert); +void ines_remote_enable(gpib_board_t *board, int enable); +int ines_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits); +void ines_disable_eos(gpib_board_t *board); +unsigned int ines_update_status(gpib_board_t *board, unsigned int clear_mask); +int ines_primary_address(gpib_board_t *board, unsigned int address); +int ines_secondary_address(gpib_board_t *board, unsigned int address, int enable); +int ines_parallel_poll(gpib_board_t *board, uint8_t *result); +void ines_parallel_poll_configure(gpib_board_t *board, uint8_t config); +void ines_parallel_poll_response(gpib_board_t *board, int ist); +void ines_serial_poll_response(gpib_board_t *board, uint8_t status); +uint8_t ines_serial_poll_status(gpib_board_t *board); +int ines_line_status(const gpib_board_t *board); +unsigned int ines_t1_delay(gpib_board_t *board, unsigned int nano_sec); +void ines_return_to_local(gpib_board_t *board); + +// interrupt service routines +irqreturn_t ines_pci_interrupt(int irq, void *arg); +irqreturn_t ines_interrupt(gpib_board_t *board); + +// utility functions +void ines_free_private(gpib_board_t *board); +int ines_generic_attach(gpib_board_t *board); +void ines_online(struct ines_priv *priv, const gpib_board_t *board, int use_accel); +void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count); + +/* inb/outb wrappers */ +static inline unsigned int ines_inb(struct ines_priv *priv, unsigned int register_number) +{ + return inb((unsigned long)(priv->nec7210_priv.iobase) + + register_number * priv->nec7210_priv.offset); +} + +static inline void ines_outb(struct ines_priv *priv, unsigned int value, + unsigned int register_number) +{ + outb(value, (unsigned long)(priv->nec7210_priv.iobase) + + register_number * priv->nec7210_priv.offset); +} + +// pcmcia init/cleanup + +int ines_pcmcia_init_module(void); +void ines_pcmcia_cleanup_module(void); + +enum ines_regs { + // read + FIFO_STATUS = 0x8, + ISR3 = 0x9, + ISR4 = 0xa, + IN_FIFO_COUNT = 0x10, + OUT_FIFO_COUNT = 0x11, + EXTEND_STATUS = 0xf, + + // write + XDMA_CONTROL = 0x8, + IMR3 = ISR3, + IMR4 = ISR4, + IN_FIFO_WATERMARK = IN_FIFO_COUNT, + OUT_FIFO_WATERMARK = OUT_FIFO_COUNT, + EXTEND_MODE = 0xf, + + // read-write + XFER_COUNT_LOWER = 0xb, + XFER_COUNT_UPPER = 0xc, + BUS_CONTROL_MONITOR = 0x13, +}; + +enum isr3_imr3_bits { + HW_TIMEOUT_BIT = 0x1, + XFER_COUNT_BIT = 0x2, + CMD_RECEIVED_BIT = 0x4, + TCT_RECEIVED_BIT = 0x8, + IFC_ACTIVE_BIT = 0x10, + ATN_ACTIVE_BIT = 0x20, + FIFO_ERROR_BIT = 0x40, +}; + +enum isr4_imr4_bits { + IN_FIFO_WATERMARK_BIT = 0x1, + OUT_FIFO_WATERMARK_BIT = 0x2, + IN_FIFO_FULL_BIT = 0x4, + OUT_FIFO_EMPTY_BIT = 0x8, + IN_FIFO_READY_BIT = 0x10, + OUT_FIFO_READY_BIT = 0x20, + IN_FIFO_EXIT_WATERMARK_BIT = 0x40, + OUT_FIFO_EXIT_WATERMARK_BIT = 0x80, +}; + +enum extend_mode_bits { + TR3_TRIG_ENABLE_BIT = 0x1, // enable generation of trigger pulse T/R3 pin + // clear message available status bit when chip writes byte with EOI true + MAV_ENABLE_BIT = 0x2, + EOS1_ENABLE_BIT = 0x4, // enable eos register 1 + EOS2_ENABLE_BIT = 0x8, // enable eos register 2 + EOIDIS_BIT = 0x10, // disable EOI interrupt when doing rfd holdoff on end? + XFER_COUNTER_ENABLE_BIT = 0x20, + XFER_COUNTER_OUTPUT_BIT = 0x40, // use counter for output, clear for input + // when xfer counter hits 0, assert EOI on write or RFD holdoff on read + LAST_BYTE_HANDLING_BIT = 0x80, +}; + +enum extend_status_bits { + OUTPUT_MESSAGE_IN_PROGRESS_BIT = 0x1, + SCSEL_BIT = 0x2, // statue of SCSEL pin + LISTEN_DISABLED = 0x4, + IN_FIFO_EMPTY_BIT = 0x8, + OUT_FIFO_FULL_BIT = 0x10, +}; + +// ines adds fifo enable bits to address mode register +enum ines_admr_bits { + IN_FIFO_ENABLE_BIT = 0x8, + OUT_FIFO_ENABLE_BIT = 0x4, +}; + +enum xdma_control_bits { + DMA_OUTPUT_BIT = 0x1, // use dma for output, clear for input + ENABLE_SYNC_DMA_BIT = 0x2, + DMA_ACCESS_EVERY_CYCLE = 0x4,// dma accesses fifo every cycle, clear for every other cycle + DMA_16BIT = 0x8, // clear for 8 bit transfers +}; + +enum bus_control_monitor_bits { + BCM_DAV_BIT = 0x1, + BCM_NRFD_BIT = 0x2, + BCM_NDAC_BIT = 0x4, + BCM_IFC_BIT = 0x8, + BCM_ATN_BIT = 0x10, + BCM_SRQ_BIT = 0x20, + BCM_REN_BIT = 0x40, + BCM_EOI_BIT = 0x80, +}; + +enum ines_aux_reg_bits { + INES_AUXD = 0x40, +}; + +enum ines_aux_cmds { + INES_RFD_HLD_IMMEDIATE = 0x4, + INES_AUX_CLR_OUT_FIFO = 0x5, + INES_AUX_CLR_IN_FIFO = 0x6, + INES_AUX_XMODE = 0xa, +}; + +enum ines_auxd_bits { + INES_FOLLOWING_T1_MASK = 0x3, + INES_FOLLOWING_T1_500ns = 0x0, + INES_FOLLOWING_T1_350ns = 0x1, + INES_FOLLOWING_T1_250ns = 0x2, + INES_INITIAL_TI_MASK = 0xc, + INES_INITIAL_T1_2000ns = 0x0, + INES_INITIAL_T1_1100ns = 0x4, + INES_INITIAL_T1_700ns = 0x8, + INES_T6_2us = 0x0, + INES_T6_50us = 0x10, +}; + +#endif // _INES_GPIB_H diff --git a/drivers/staging/gpib/ines/ines_gpib.c b/drivers/staging/gpib/ines/ines_gpib.c new file mode 100644 index 00000000000000..9d8387c3bf019b --- /dev/null +++ b/drivers/staging/gpib/ines/ines_gpib.c @@ -0,0 +1,1464 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 1999 Axel Dziemba (axel.dziemba@ines.de) + * (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#include "ines.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gpib_pci_ids.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for Ines iGPIB 72010"); + +int ines_line_status(const gpib_board_t *board) +{ + int status = ValidALL; + int bcm_bits; + struct ines_priv *ines_priv; + struct nec7210_priv *nec_priv; + + ines_priv = board->private_data; + nec_priv = &ines_priv->nec7210_priv; + + bcm_bits = ines_inb(ines_priv, BUS_CONTROL_MONITOR); + + if (bcm_bits & BCM_REN_BIT) + status |= BusREN; + if (bcm_bits & BCM_IFC_BIT) + status |= BusIFC; + if (bcm_bits & BCM_SRQ_BIT) + status |= BusSRQ; + if (bcm_bits & BCM_EOI_BIT) + status |= BusEOI; + if (bcm_bits & BCM_NRFD_BIT) + status |= BusNRFD; + if (bcm_bits & BCM_NDAC_BIT) + status |= BusNDAC; + if (bcm_bits & BCM_DAV_BIT) + status |= BusDAV; + if (bcm_bits & BCM_ATN_BIT) + status |= BusATN; + + return status; +} + +void ines_set_xfer_counter(struct ines_priv *priv, unsigned int count) +{ + if (count > 0xffff) { + pr_err("ines: bug! tried to set xfer counter > 0xffff\n"); + return; + } + ines_outb(priv, (count >> 8) & 0xff, XFER_COUNT_UPPER); + ines_outb(priv, count & 0xff, XFER_COUNT_LOWER); +} + +unsigned int ines_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct ines_priv *ines_priv = board->private_data; + struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv; + unsigned int retval; + + retval = nec7210_t1_delay(board, nec_priv, nano_sec); + + if (nano_sec <= 250) { + write_byte(nec_priv, INES_AUXD | INES_FOLLOWING_T1_250ns | + INES_INITIAL_T1_2000ns, AUXMR); + retval = 250; + } else if (nano_sec <= 350) { + write_byte(nec_priv, INES_AUXD | INES_FOLLOWING_T1_350ns | + INES_INITIAL_T1_2000ns, AUXMR); + retval = 350; + } else { + write_byte(nec_priv, INES_AUXD | INES_FOLLOWING_T1_500ns | + INES_INITIAL_T1_2000ns, AUXMR); + retval = 500; + } + + return retval; +} + +static inline unsigned short num_in_fifo_bytes(struct ines_priv *ines_priv) +{ + return ines_inb(ines_priv, IN_FIFO_COUNT); +} + +static ssize_t pio_read(gpib_board_t *board, struct ines_priv *ines_priv, uint8_t *buffer, + size_t length, size_t *nbytes) +{ + ssize_t retval = 0; + unsigned int num_fifo_bytes, i; + struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv; + + *nbytes = 0; + while (*nbytes < length) { + if (wait_event_interruptible(board->wait, + num_in_fifo_bytes(ines_priv) || + test_bit(RECEIVED_END_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_warn("gpib: pio read wait interrupted\n"); + return -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + return -ETIMEDOUT; + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) + return -EINTR; + + num_fifo_bytes = num_in_fifo_bytes(ines_priv); + if (num_fifo_bytes + *nbytes > length) { + pr_warn("ines: counter allowed %li extra byte(s)\n", + (long)(num_fifo_bytes - (length - *nbytes))); + num_fifo_bytes = length - *nbytes; + } + for (i = 0; i < num_fifo_bytes; i++) + buffer[(*nbytes)++] = read_byte(nec_priv, DIR); + if (test_bit(RECEIVED_END_BN, &nec_priv->state) && + num_in_fifo_bytes(ines_priv) == 0) + break; + if (need_resched()) + schedule(); + } + /* make sure RECEIVED_END is in sync */ + ines_interrupt(board); + return retval; +} + +int ines_accel_read(gpib_board_t *board, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + ssize_t retval = 0; + struct ines_priv *ines_priv = board->private_data; + struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv; + int counter_setting; + + *end = 0; + *bytes_read = 0; + if (length == 0) + return 0; + + clear_bit(DEV_CLEAR_BN, &nec_priv->state); + + write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR); + + //clear in fifo + nec7210_set_reg_bits(nec_priv, ADMR, IN_FIFO_ENABLE_BIT, 0); + nec7210_set_reg_bits(nec_priv, ADMR, IN_FIFO_ENABLE_BIT, IN_FIFO_ENABLE_BIT); + + ines_priv->extend_mode_bits |= LAST_BYTE_HANDLING_BIT; + ines_priv->extend_mode_bits &= ~XFER_COUNTER_OUTPUT_BIT & ~XFER_COUNTER_ENABLE_BIT; + ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE); + + counter_setting = length - num_in_fifo_bytes(ines_priv); + if (counter_setting > 0) { + ines_set_xfer_counter(ines_priv, length); + ines_priv->extend_mode_bits |= XFER_COUNTER_ENABLE_BIT; + ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE); + + // holdoff on END + nec7210_set_handshake_mode(board, nec_priv, HR_HLDE); + /* release rfd holdoff */ + write_byte(nec_priv, AUX_FH, AUXMR); + } + + retval = pio_read(board, ines_priv, buffer, length, bytes_read); + ines_priv->extend_mode_bits &= ~XFER_COUNTER_ENABLE_BIT; + ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE); + if (retval < 0) { + write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR); + return retval; + } + if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state)) + *end = 1; + + return retval; +} + +static const int out_fifo_size = 0xff; + +static inline unsigned short num_out_fifo_bytes(struct ines_priv *ines_priv) +{ + return ines_inb(ines_priv, OUT_FIFO_COUNT); +} + +static int ines_write_wait(gpib_board_t *board, struct ines_priv *ines_priv, + unsigned int fifo_threshold) +{ + struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv; + + // wait until byte is ready to be sent + if (wait_event_interruptible(board->wait, + num_out_fifo_bytes(ines_priv) < fifo_threshold || + test_bit(BUS_ERROR_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib write interrupted\n"); + return -ERESTARTSYS; + } + if (test_bit(BUS_ERROR_BN, &nec_priv->state)) + return -EIO; + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) + return -EINTR; + if (test_bit(TIMO_NUM, &board->status)) + return -ETIMEDOUT; + + return 0; +} + +int ines_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + size_t count = 0; + ssize_t retval = 0; + struct ines_priv *ines_priv = board->private_data; + struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv; + unsigned int num_bytes, i; + + *bytes_written = 0; + //clear out fifo + nec7210_set_reg_bits(nec_priv, ADMR, OUT_FIFO_ENABLE_BIT, 0); + nec7210_set_reg_bits(nec_priv, ADMR, OUT_FIFO_ENABLE_BIT, OUT_FIFO_ENABLE_BIT); + + ines_priv->extend_mode_bits |= XFER_COUNTER_OUTPUT_BIT; + ines_priv->extend_mode_bits &= ~XFER_COUNTER_ENABLE_BIT; + ines_priv->extend_mode_bits &= ~LAST_BYTE_HANDLING_BIT; + ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE); + + ines_set_xfer_counter(ines_priv, length); + if (send_eoi) + ines_priv->extend_mode_bits |= LAST_BYTE_HANDLING_BIT; + ines_priv->extend_mode_bits |= XFER_COUNTER_ENABLE_BIT; + ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE); + + while (count < length) { + retval = ines_write_wait(board, ines_priv, out_fifo_size); + if (retval < 0) + break; + + num_bytes = out_fifo_size - num_out_fifo_bytes(ines_priv); + if (num_bytes + count > length) + num_bytes = length - count; + for (i = 0; i < num_bytes; i++) + write_byte(nec_priv, buffer[count++], CDOR); + } + if (retval < 0) { + ines_priv->extend_mode_bits &= ~XFER_COUNTER_ENABLE_BIT; + ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE); + *bytes_written = length - num_out_fifo_bytes(ines_priv); + return retval; + } + // wait last byte has been sent + retval = ines_write_wait(board, ines_priv, 1); + ines_priv->extend_mode_bits &= ~XFER_COUNTER_ENABLE_BIT; + ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE); + *bytes_written = length - num_out_fifo_bytes(ines_priv); + + return retval; +} + +irqreturn_t ines_pci_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + struct ines_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + + if (priv->pci_chip_type == PCI_CHIP_QUANCOM) { + if ((inb((unsigned long)nec_priv->iobase + + QUANCOM_IRQ_CONTROL_STATUS_REG) & + QUANCOM_IRQ_ASSERTED_BIT)) + outb(QUANCOM_IRQ_ENABLE_BIT, (unsigned long)(nec_priv->iobase) + + QUANCOM_IRQ_CONTROL_STATUS_REG); + } + + return ines_interrupt(board); +} + +irqreturn_t ines_interrupt(gpib_board_t *board) +{ + struct ines_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + unsigned int isr3_bits, isr4_bits; + unsigned long flags; + int wake = 0; + + spin_lock_irqsave(&board->spinlock, flags); + + nec7210_interrupt(board, nec_priv); + isr3_bits = ines_inb(priv, ISR3); + isr4_bits = ines_inb(priv, ISR4); + if (isr3_bits & IFC_ACTIVE_BIT) { + push_gpib_event(board, EventIFC); + wake++; + } + if (isr3_bits & FIFO_ERROR_BIT) + pr_err("ines gpib: fifo error\n"); + if (isr3_bits & XFER_COUNT_BIT) + wake++; + + if (isr4_bits & (IN_FIFO_WATERMARK_BIT | IN_FIFO_FULL_BIT | OUT_FIFO_WATERMARK_BIT | + OUT_FIFO_EMPTY_BIT)) + wake++; + + if (wake) + wake_up_interruptible(&board->wait); + spin_unlock_irqrestore(&board->spinlock, flags); + return IRQ_HANDLED; +} + +static int ines_pci_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int ines_pci_accel_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int ines_isa_attach(gpib_board_t *board, const gpib_board_config_t *config); + +static void ines_pci_detach(gpib_board_t *board); +static void ines_isa_detach(gpib_board_t *board); + +enum ines_pci_vendor_ids { + PCI_VENDOR_ID_INES_QUICKLOGIC = 0x16da +}; + +enum ines_pci_device_ids { + PCI_DEVICE_ID_INES_GPIB_AMCC = 0x8507, + PCI_DEVICE_ID_INES_GPIB_QL5030 = 0x11, +}; + +enum ines_pci_subdevice_ids { + PCI_SUBDEVICE_ID_INES_GPIB = 0x1072 +}; + +static struct pci_device_id ines_pci_table[] = { + {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_VENDOR_ID_PLX, + PCI_SUBDEVICE_ID_INES_GPIB, 0, 0, 0}, + {PCI_VENDOR_ID_AMCC, PCI_DEVICE_ID_INES_GPIB_AMCC, PCI_VENDOR_ID_AMCC, + PCI_SUBDEVICE_ID_INES_GPIB, 0, 0, 0}, + {PCI_VENDOR_ID_INES_QUICKLOGIC, PCI_DEVICE_ID_INES_GPIB_QL5030, + PCI_VENDOR_ID_INES_QUICKLOGIC, PCI_DEVICE_ID_INES_GPIB_QL5030, 0, 0, 0}, + {PCI_DEVICE(PCI_VENDOR_ID_QUANCOM, PCI_DEVICE_ID_QUANCOM_GPIB)}, + {0} +}; +MODULE_DEVICE_TABLE(pci, ines_pci_table); + +struct ines_pci_id { + unsigned int vendor_id; + unsigned int device_id; + int subsystem_vendor_id; + int subsystem_device_id; + unsigned int gpib_region; + unsigned int io_offset; + enum ines_pci_chip pci_chip_type; +}; + +struct ines_pci_id pci_ids[] = { + {vendor_id: PCI_VENDOR_ID_PLX, + device_id : PCI_DEVICE_ID_PLX_9050, + subsystem_vendor_id : PCI_VENDOR_ID_PLX, + subsystem_device_id : PCI_SUBDEVICE_ID_INES_GPIB, + gpib_region : 2, + io_offset : 1, + pci_chip_type : PCI_CHIP_PLX9050, + }, + {vendor_id: PCI_VENDOR_ID_AMCC, + device_id : PCI_DEVICE_ID_INES_GPIB_AMCC, + subsystem_vendor_id : PCI_VENDOR_ID_AMCC, + subsystem_device_id : PCI_SUBDEVICE_ID_INES_GPIB, + gpib_region : 1, + io_offset : 1, + pci_chip_type : PCI_CHIP_AMCC5920, + }, + {vendor_id: PCI_VENDOR_ID_INES_QUICKLOGIC, + device_id : PCI_DEVICE_ID_INES_GPIB_QL5030, + subsystem_vendor_id : PCI_VENDOR_ID_INES_QUICKLOGIC, + subsystem_device_id : PCI_DEVICE_ID_INES_GPIB_QL5030, + gpib_region : 1, + io_offset : 1, + pci_chip_type : PCI_CHIP_QUICKLOGIC5030, + }, + {vendor_id: PCI_VENDOR_ID_QUANCOM, + device_id : PCI_DEVICE_ID_QUANCOM_GPIB, + subsystem_vendor_id : -1, + subsystem_device_id : -1, + gpib_region : 0, + io_offset : 4, + pci_chip_type : PCI_CHIP_QUANCOM, + }, +}; + +static const int num_pci_chips = ARRAY_SIZE(pci_ids); + +// wrappers for interface functions +int ines_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) +{ + struct ines_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + ssize_t retval; + int dummy; + + retval = nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); + if (retval < 0) { + write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR); + + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + + nec7210_read_data_in(board, nec_priv, &dummy); + } + return retval; +} + +int ines_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); +} + +int ines_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); +} + +int ines_take_control(gpib_board_t *board, int synchronous) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_take_control(board, &priv->nec7210_priv, synchronous); +} + +int ines_go_to_standby(gpib_board_t *board) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_go_to_standby(board, &priv->nec7210_priv); +} + +void ines_request_system_control(gpib_board_t *board, int request_control) +{ + struct ines_priv *priv = board->private_data; + + nec7210_request_system_control(board, &priv->nec7210_priv, request_control); +} + +void ines_interface_clear(gpib_board_t *board, int assert) +{ + struct ines_priv *priv = board->private_data; + + nec7210_interface_clear(board, &priv->nec7210_priv, assert); +} + +void ines_remote_enable(gpib_board_t *board, int enable) +{ + struct ines_priv *priv = board->private_data; + + nec7210_remote_enable(board, &priv->nec7210_priv, enable); +} + +int ines_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); +} + +void ines_disable_eos(gpib_board_t *board) +{ + struct ines_priv *priv = board->private_data; + + nec7210_disable_eos(board, &priv->nec7210_priv); +} + +unsigned int ines_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_update_status(board, &priv->nec7210_priv, clear_mask); +} + +int ines_primary_address(gpib_board_t *board, unsigned int address) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_primary_address(board, &priv->nec7210_priv, address); +} + +int ines_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); +} + +int ines_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_parallel_poll(board, &priv->nec7210_priv, result); +} + +void ines_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + struct ines_priv *priv = board->private_data; + + nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config); +} + +void ines_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct ines_priv *priv = board->private_data; + + nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); +} + +void ines_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + struct ines_priv *priv = board->private_data; + + nec7210_serial_poll_response(board, &priv->nec7210_priv, status); +} + +uint8_t ines_serial_poll_status(gpib_board_t *board) +{ + struct ines_priv *priv = board->private_data; + + return nec7210_serial_poll_status(board, &priv->nec7210_priv); +} + +void ines_return_to_local(gpib_board_t *board) +{ + struct ines_priv *priv = board->private_data; + + nec7210_return_to_local(board, &priv->nec7210_priv); +} + +gpib_interface_t ines_pci_unaccel_interface = { +name: "ines_pci_unaccel", +attach : ines_pci_attach, +detach : ines_pci_detach, +read : ines_read, +write : ines_write, +command : ines_command, +take_control : ines_take_control, +go_to_standby : ines_go_to_standby, +request_system_control : ines_request_system_control, +interface_clear : ines_interface_clear, +remote_enable : ines_remote_enable, +enable_eos : ines_enable_eos, +disable_eos : ines_disable_eos, +parallel_poll : ines_parallel_poll, +parallel_poll_configure : ines_parallel_poll_configure, +parallel_poll_response : ines_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : ines_line_status, +update_status : ines_update_status, +primary_address : ines_primary_address, +secondary_address : ines_secondary_address, +serial_poll_response : ines_serial_poll_response, +serial_poll_status : ines_serial_poll_status, +t1_delay : ines_t1_delay, +return_to_local : ines_return_to_local, +}; + +gpib_interface_t ines_pci_interface = { +name: "ines_pci", +attach : ines_pci_accel_attach, +detach : ines_pci_detach, +read : ines_accel_read, +write : ines_accel_write, +command : ines_command, +take_control : ines_take_control, +go_to_standby : ines_go_to_standby, +request_system_control : ines_request_system_control, +interface_clear : ines_interface_clear, +remote_enable : ines_remote_enable, +enable_eos : ines_enable_eos, +disable_eos : ines_disable_eos, +parallel_poll : ines_parallel_poll, +parallel_poll_configure : ines_parallel_poll_configure, +parallel_poll_response : ines_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : ines_line_status, +update_status : ines_update_status, +primary_address : ines_primary_address, +secondary_address : ines_secondary_address, +serial_poll_response : ines_serial_poll_response, +serial_poll_status : ines_serial_poll_status, +t1_delay : ines_t1_delay, +return_to_local : ines_return_to_local, +}; + +gpib_interface_t ines_pci_accel_interface = { +name: "ines_pci_accel", +attach : ines_pci_accel_attach, +detach : ines_pci_detach, +read : ines_accel_read, +write : ines_accel_write, +command : ines_command, +take_control : ines_take_control, +go_to_standby : ines_go_to_standby, +request_system_control : ines_request_system_control, +interface_clear : ines_interface_clear, +remote_enable : ines_remote_enable, +enable_eos : ines_enable_eos, +disable_eos : ines_disable_eos, +parallel_poll : ines_parallel_poll, +parallel_poll_configure : ines_parallel_poll_configure, +parallel_poll_response : ines_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : ines_line_status, +update_status : ines_update_status, +primary_address : ines_primary_address, +secondary_address : ines_secondary_address, +serial_poll_response : ines_serial_poll_response, +serial_poll_status : ines_serial_poll_status, +t1_delay : ines_t1_delay, +return_to_local : ines_return_to_local, +}; + +gpib_interface_t ines_isa_interface = { +name: "ines_isa", +attach : ines_isa_attach, +detach : ines_isa_detach, +read : ines_accel_read, +write : ines_accel_write, +command : ines_command, +take_control : ines_take_control, +go_to_standby : ines_go_to_standby, +request_system_control : ines_request_system_control, +interface_clear : ines_interface_clear, +remote_enable : ines_remote_enable, +enable_eos : ines_enable_eos, +disable_eos : ines_disable_eos, +parallel_poll : ines_parallel_poll, +parallel_poll_configure : ines_parallel_poll_configure, +parallel_poll_response : ines_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : ines_line_status, +update_status : ines_update_status, +primary_address : ines_primary_address, +secondary_address : ines_secondary_address, +serial_poll_response : ines_serial_poll_response, +serial_poll_status : ines_serial_poll_status, +t1_delay : ines_t1_delay, +return_to_local : ines_return_to_local, +}; + +static int ines_allocate_private(gpib_board_t *board) +{ + struct ines_priv *priv; + + board->private_data = kmalloc(sizeof(struct ines_priv), GFP_KERNEL); + if (!board->private_data) + return -1; + priv = board->private_data; + memset(priv, 0, sizeof(struct ines_priv)); + init_nec7210_private(&priv->nec7210_priv); + return 0; +} + +void ines_free_private(gpib_board_t *board) +{ + kfree(board->private_data); + board->private_data = NULL; +} + +int ines_generic_attach(gpib_board_t *board) +{ + struct ines_priv *ines_priv; + struct nec7210_priv *nec_priv; + + board->status = 0; + + if (ines_allocate_private(board)) + return -ENOMEM; + ines_priv = board->private_data; + nec_priv = &ines_priv->nec7210_priv; + nec_priv->read_byte = nec7210_ioport_read_byte; + nec_priv->write_byte = nec7210_ioport_write_byte; + nec_priv->offset = 1; + nec_priv->type = IGPIB7210; + ines_priv->pci_chip_type = PCI_CHIP_NONE; + + return 0; +} + +void ines_online(struct ines_priv *ines_priv, const gpib_board_t *board, int use_accel) +{ + struct nec7210_priv *nec_priv = &ines_priv->nec7210_priv; + + /* ines doesn't seem to use internal count register */ + write_byte(nec_priv, ICR | 0, AUXMR); + + write_byte(nec_priv, INES_AUX_XMODE, AUXMR); + write_byte(nec_priv, INES_RFD_HLD_IMMEDIATE, AUXMR); + + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + + write_byte(nec_priv, INES_AUXD | 0, AUXMR); + ines_outb(ines_priv, 0, XDMA_CONTROL); + ines_priv->extend_mode_bits = 0; + ines_outb(ines_priv, ines_priv->extend_mode_bits, EXTEND_MODE); + if (use_accel) { + ines_outb(ines_priv, 0x80, OUT_FIFO_WATERMARK); + ines_outb(ines_priv, 0x80, IN_FIFO_WATERMARK); + ines_outb(ines_priv, IFC_ACTIVE_BIT | ATN_ACTIVE_BIT | + FIFO_ERROR_BIT | XFER_COUNT_BIT, IMR3); + ines_outb(ines_priv, IN_FIFO_WATERMARK_BIT | IN_FIFO_FULL_BIT | + OUT_FIFO_WATERMARK_BIT | OUT_FIFO_EMPTY_BIT, IMR4); + } else { + nec7210_set_reg_bits(nec_priv, ADMR, IN_FIFO_ENABLE_BIT | OUT_FIFO_ENABLE_BIT, 0); + ines_outb(ines_priv, IFC_ACTIVE_BIT | FIFO_ERROR_BIT, IMR3); + ines_outb(ines_priv, 0, IMR4); + } + + nec7210_board_online(nec_priv, board); + if (use_accel) + nec7210_set_reg_bits(nec_priv, IMR1, HR_DOIE | HR_DIIE, 0); +} + +static int ines_common_pci_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct ines_priv *ines_priv; + struct nec7210_priv *nec_priv; + int isr_flags = 0; + int retval; + struct ines_pci_id found_id; + unsigned int i; + struct pci_dev *pdev; + + memset(&found_id, 0, sizeof(found_id)); + + retval = ines_generic_attach(board); + if (retval) + return retval; + + ines_priv = board->private_data; + nec_priv = &ines_priv->nec7210_priv; + + // find board + ines_priv->pci_device = NULL; + for (i = 0; i < num_pci_chips && !ines_priv->pci_device; i++) { + pdev = NULL; + do { + if (pci_ids[i].subsystem_vendor_id >= 0 && + pci_ids[i].subsystem_device_id >= 0) + pdev = pci_get_subsys(pci_ids[i].vendor_id, pci_ids[i].device_id, + pci_ids[i].subsystem_vendor_id, + pci_ids[i].subsystem_device_id, pdev); + else + pdev = pci_get_device(pci_ids[i].vendor_id, pci_ids[i].device_id, + pdev); + if (!pdev) + break; + if (config->pci_bus >= 0 && config->pci_bus != pdev->bus->number) + continue; + if (config->pci_slot >= 0 && config->pci_slot != PCI_SLOT(pdev->devfn)) + continue; + found_id = pci_ids[i]; + ines_priv->pci_device = pdev; + break; + } while (1); + } + if (!ines_priv->pci_device) { + pr_err("gpib: could not find ines PCI board\n"); + return -1; + } + + if (pci_enable_device(ines_priv->pci_device)) { + pr_err("error enabling pci device\n"); + return -1; + } + + if (pci_request_regions(ines_priv->pci_device, "ines-gpib")) + return -1; + nec_priv->iobase = (void *)(pci_resource_start(ines_priv->pci_device, + found_id.gpib_region)); + + ines_priv->pci_chip_type = found_id.pci_chip_type; + nec_priv->offset = found_id.io_offset; + switch (ines_priv->pci_chip_type) { + case PCI_CHIP_PLX9050: + ines_priv->plx_iobase = pci_resource_start(ines_priv->pci_device, 1); + break; + case PCI_CHIP_AMCC5920: + ines_priv->amcc_iobase = pci_resource_start(ines_priv->pci_device, 0); + break; + case PCI_CHIP_QUANCOM: + break; + case PCI_CHIP_QUICKLOGIC5030: + break; + default: + pr_err("gpib: unspecified chip type? (bug)\n"); + nec_priv->iobase = 0; + pci_release_regions(ines_priv->pci_device); + return -1; + } + + nec7210_board_reset(nec_priv, board); +#ifdef QUANCOM_PCI + if (ines_priv->pci_chip_type == PCI_CHIP_QUANCOM) { + /* change interrupt polarity */ + nec_priv->auxb_bits |= HR_INV; + ines_outb(ines_priv, nec_priv->auxb_bits, AUXMR); + } +#endif + isr_flags |= IRQF_SHARED; + if (request_irq(ines_priv->pci_device->irq, ines_pci_interrupt, isr_flags, + "pci-gpib", board)) { + pr_err("gpib: can't request IRQ %d\n", ines_priv->pci_device->irq); + return -1; + } + ines_priv->irq = ines_priv->pci_device->irq; + + // enable interrupts on pci chip + switch (ines_priv->pci_chip_type) { + case PCI_CHIP_PLX9050: + outl(PLX9050_LINTR1_EN_BIT | PLX9050_LINTR1_POLARITY_BIT | PLX9050_PCI_INTR_EN_BIT, + ines_priv->plx_iobase + PLX9050_INTCSR_REG); + break; + case PCI_CHIP_AMCC5920: + { + static const int region = 1; + static const int num_wait_states = 7; + u32 bits; + + bits = amcc_prefetch_bits(region, PREFETCH_DISABLED); + bits |= amcc_PTADR_mode_bit(region); + bits |= amcc_disable_write_fifo_bit(region); + bits |= amcc_wait_state_bits(region, num_wait_states); + outl(bits, ines_priv->amcc_iobase + AMCC_PASS_THRU_REG); + outl(AMCC_ADDON_INTR_ENABLE_BIT, ines_priv->amcc_iobase + AMCC_INTCS_REG); + } + break; + case PCI_CHIP_QUANCOM: + outb(QUANCOM_IRQ_ENABLE_BIT, (unsigned long)(nec_priv->iobase) + + QUANCOM_IRQ_CONTROL_STATUS_REG); + break; + case PCI_CHIP_QUICKLOGIC5030: + break; + default: + pr_err("gpib: unspecified chip type? (bug)\n"); + return -1; + } + + return 0; +} + +int ines_pci_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct ines_priv *ines_priv; + int retval; + + retval = ines_common_pci_attach(board, config); + if (retval < 0) + return retval; + + ines_priv = board->private_data; + ines_online(ines_priv, board, 0); + + return 0; +} + +int ines_pci_accel_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct ines_priv *ines_priv; + int retval; + + retval = ines_common_pci_attach(board, config); + if (retval < 0) + return retval; + + ines_priv = board->private_data; + ines_online(ines_priv, board, 1); + + return 0; +} + +static const int ines_isa_iosize = 0x20; + +int ines_isa_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct ines_priv *ines_priv; + struct nec7210_priv *nec_priv; + int isr_flags = 0; + int retval; + + retval = ines_generic_attach(board); + if (retval) + return retval; + + ines_priv = board->private_data; + nec_priv = &ines_priv->nec7210_priv; + + if (!request_region((unsigned long)config->ibbase, ines_isa_iosize, "ines_gpib")) { + pr_err("ines_gpib: ioports at 0x%p already in use\n", config->ibbase); + return -1; + } + nec_priv->iobase = config->ibbase; + nec_priv->offset = 1; + nec7210_board_reset(nec_priv, board); + if (request_irq(config->ibirq, ines_pci_interrupt, isr_flags, "ines_gpib", board)) { + pr_err("ines_gpib: failed to allocate IRQ %d\n", config->ibirq); + return -1; + } + ines_priv->irq = config->ibirq; + ines_online(ines_priv, board, 1); + return 0; +} + +void ines_pci_detach(gpib_board_t *board) +{ + struct ines_priv *ines_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (ines_priv) { + nec_priv = &ines_priv->nec7210_priv; + if (ines_priv->irq) { + // disable interrupts + switch (ines_priv->pci_chip_type) { + case PCI_CHIP_AMCC5920: + if (ines_priv->plx_iobase) + outl(0, ines_priv->plx_iobase + PLX9050_INTCSR_REG); + break; + case PCI_CHIP_QUANCOM: + if (nec_priv->iobase) + outb(0, (unsigned long)(nec_priv->iobase) + + QUANCOM_IRQ_CONTROL_STATUS_REG); + break; + default: + break; + } + free_irq(ines_priv->irq, board); + } + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + pci_release_regions(ines_priv->pci_device); + } + if (ines_priv->pci_device) + pci_dev_put(ines_priv->pci_device); + } + ines_free_private(board); +} + +void ines_isa_detach(gpib_board_t *board) +{ + struct ines_priv *ines_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (ines_priv) { + nec_priv = &ines_priv->nec7210_priv; + if (ines_priv->irq) + free_irq(ines_priv->irq, board); + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + release_region((unsigned long)(nec_priv->iobase), ines_isa_iosize); + } + } + ines_free_private(board); +} + +static int ines_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return 0; +} + +static struct pci_driver ines_pci_driver = { + .name = "ines_gpib", + .id_table = ines_pci_table, + .probe = &ines_pci_probe +}; + +#ifdef GPIB_PCMCIA + +#include +#include +#include +#include + +#include +#include +#include + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +#define DEBUG(n, args...) do {if (pc_debug > (n)) pr_debug(args)} while (0) +#else +#define DEBUG(args...) +#endif + +static const int ines_pcmcia_iosize = 0x20; + +/* The event() function is this driver's Card Services event handler. + * It will be called by Card Services when an appropriate card status + * event is received. The config() and release() entry points are + * used to configure or release a socket, in response to card insertion + * and ejection events. They are invoked from the gpib event + * handler. + */ + +static int ines_gpib_config(struct pcmcia_device *link); +static void ines_gpib_release(struct pcmcia_device *link); +static int ines_pcmcia_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int ines_pcmcia_accel_attach(gpib_board_t *board, const gpib_board_config_t *config); +static void ines_pcmcia_detach(gpib_board_t *board); +static irqreturn_t ines_pcmcia_interrupt(int irq, void *arg); +static int ines_common_pcmcia_attach(gpib_board_t *board); +/* + * A linked list of "instances" of the gpib device. Each actual + * PCMCIA card corresponds to one device instance, and is described + * by one dev_link_t structure (defined in ds.h). + * + * You may not want to use a linked list for this -- for example, the + * memory card driver uses an array of dev_link_t pointers, where minor + * device numbers are used to derive the corresponding array index. + */ + +static struct pcmcia_device *curr_dev; + +/* + * A dev_link_t structure has fields for most things that are needed + * to keep track of a socket, but there will usually be some device + * specific information that also needs to be kept track of. The + * 'priv' pointer in a dev_link_t structure can be used to point to + * a device-specific private data structure, like this. + * + * A driver needs to provide a dev_node_t structure for each device + * on a card. In some cases, there is only one device per card (for + * example, ethernet cards, modems). In other cases, there may be + * many actual or logical devices (SCSI adapters, memory cards with + * multiple partitions). The dev_node_t structures need to be kept + * in a linked list starting at the 'dev' field of a dev_link_t + * structure. We allocate them in the card's private data structure, + * because they generally can't be allocated dynamically. + */ + +struct local_info { + struct pcmcia_device *p_dev; + gpib_board_t *dev; + u_short manfid; + u_short cardid; +}; + +/* + * gpib_attach() creates an "instance" of the driver, allocating + * local data structures for one device. The device is registered + * with Card Services. + * + * The dev_link structure is initialized, but we don't actually + * configure the card at this point -- we wait until we receive a + * card insertion event. + */ +static int ines_gpib_probe(struct pcmcia_device *link) +{ + struct local_info *info; + +// int ret, i; + + DEBUG(0, "%s(0x%p)\n", __func__ link); + + /* Allocate space for private device-specific data */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->p_dev = link; + link->priv = info; + + /* The io structure describes IO port mapping */ + link->resource[0]->end = 32; + link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + link->io_lines = 5; + + /* General socket configuration */ + link->config_flags = CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + + /* Register with Card Services */ + curr_dev = link; + return ines_gpib_config(link); +} + +/* + * This deletes a driver "instance". The device is de-registered + * with Card Services. If it has been released, all local data + * structures are freed. Otherwise, the structures will be freed + * when the device is released. + */ +static void ines_gpib_remove(struct pcmcia_device *link) +{ + struct local_info *info = link->priv; + //struct gpib_board_t *dev = info->dev; + + DEBUG(0, "%s(0x%p)\n", __func__, link); + + if (info->dev) + ines_pcmcia_detach(info->dev); + ines_gpib_release(link); + + //free_netdev(dev); + kfree(info); +} + +static int ines_gpib_config_iteration(struct pcmcia_device *link, void *priv_data) +{ + return pcmcia_request_io(link); +} + +/* + * gpib_config() is scheduled to run after a CARD_INSERTION event + * is received, to configure the PCMCIA socket, and to make the + * device available to the system. + */ +static int ines_gpib_config(struct pcmcia_device *link) +{ + struct local_info *dev; + int retval; + void *virt; + + dev = link->priv; + DEBUG(0, "%s(0x%p)\n", __func__, link); + + retval = pcmcia_loop_config(link, &ines_gpib_config_iteration, NULL); + if (retval) { + dev_warn(&link->dev, "no configuration found\n"); + ines_gpib_release(link); + return -ENODEV; + } + + pr_debug("ines_cs: manufacturer: 0x%x card: 0x%x\n", + link->manf_id, link->card_id); + + /* for the ines card we have to setup the configuration registers in + * attribute memory here + */ + link->resource[2]->flags |= WIN_MEMORY_TYPE_AM | WIN_DATA_WIDTH_8 | WIN_ENABLE; + link->resource[2]->end = 0x1000; + retval = pcmcia_request_window(link, link->resource[2], 250); + if (retval) { + dev_warn(&link->dev, "pcmcia_request_window failed\n"); + ines_gpib_release(link); + return -ENODEV; + } + retval = pcmcia_map_mem_page(link, link->resource[2], 0); + if (retval) { + dev_warn(&link->dev, "pcmcia_map_mem_page failed\n"); + ines_gpib_release(link); + return -ENODEV; + } + virt = ioremap(link->resource[2]->start, resource_size(link->resource[2])); + writeb((link->resource[2]->start >> 2) & 0xff, virt + 0xf0); // IOWindow base + iounmap((void *)virt); + + /* + * This actually configures the PCMCIA socket -- setting up + * the I/O windows and the interrupt mapping. + */ + retval = pcmcia_enable_device(link); + if (retval) { + ines_gpib_release(link); + return -ENODEV; + } + pr_info("ines gpib device loaded\n"); + return 0; +} /* gpib_config */ + +/* + * After a card is removed, gpib_release() will unregister the net + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ + +static void ines_gpib_release(struct pcmcia_device *link) +{ + DEBUG(0, "%s(0x%p)\n", __func__, link); + pcmcia_disable_device(link); +} /* gpib_release */ + +static int ines_gpib_suspend(struct pcmcia_device *link) +{ + //struct local_info *info = link->priv; + //struct gpib_board_t *dev = info->dev; + DEBUG(0, "%s(0x%p)\n", __func__, link); + + if (link->open) + pr_err("Device still open ???\n"); + //netif_device_detach(dev); + + return 0; +} + +static int ines_gpib_resume(struct pcmcia_device *link) +{ + //struct local_info_t *info = link->priv; + //struct gpib_board_t *dev = info->dev; + DEBUG(0, "%s(0x%p)\n", __func__, link); + + /*if (link->open) { + * ni_gpib_probe(dev); / really? + * printk("Gpib resumed ???\n"); + * //netif_device_attach(dev); + *} + */ + return ines_gpib_config(link); +} + +static struct pcmcia_device_id ines_pcmcia_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x01b4, 0x4730), + PCMCIA_DEVICE_NULL +}; +MODULE_DEVICE_TABLE(pcmcia, ines_pcmcia_ids); + +static struct pcmcia_driver ines_gpib_cs_driver = { + .owner = THIS_MODULE, + .name = "ines_gpib_cs", + .id_table = ines_pcmcia_ids, + .probe = ines_gpib_probe, + .remove = ines_gpib_remove, + .suspend = ines_gpib_suspend, + .resume = ines_gpib_resume, +}; + +int ines_pcmcia_init_module(void) +{ + pcmcia_register_driver(&ines_gpib_cs_driver); + return 0; +} + +void ines_pcmcia_cleanup_module(void) +{ + DEBUG(0, "ines_cs: unloading\n"); + pcmcia_unregister_driver(&ines_gpib_cs_driver); +} + +gpib_interface_t ines_pcmcia_unaccel_interface = { +name: "ines_pcmcia_unaccel", +attach : ines_pcmcia_attach, +detach : ines_pcmcia_detach, +read : ines_read, +write : ines_write, +command : ines_command, +take_control : ines_take_control, +go_to_standby : ines_go_to_standby, +request_system_control : ines_request_system_control, +interface_clear : ines_interface_clear, +remote_enable : ines_remote_enable, +enable_eos : ines_enable_eos, +disable_eos : ines_disable_eos, +parallel_poll : ines_parallel_poll, +parallel_poll_configure : ines_parallel_poll_configure, +parallel_poll_response : ines_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : ines_line_status, +update_status : ines_update_status, +primary_address : ines_primary_address, +secondary_address : ines_secondary_address, +serial_poll_response : ines_serial_poll_response, +serial_poll_status : ines_serial_poll_status, +t1_delay : ines_t1_delay, +return_to_local : ines_return_to_local, +}; + +gpib_interface_t ines_pcmcia_accel_interface = { +name: "ines_pcmcia_accel", +attach : ines_pcmcia_accel_attach, +detach : ines_pcmcia_detach, +read : ines_accel_read, +write : ines_accel_write, +command : ines_command, +take_control : ines_take_control, +go_to_standby : ines_go_to_standby, +request_system_control : ines_request_system_control, +interface_clear : ines_interface_clear, +remote_enable : ines_remote_enable, +enable_eos : ines_enable_eos, +disable_eos : ines_disable_eos, +parallel_poll : ines_parallel_poll, +parallel_poll_configure : ines_parallel_poll_configure, +parallel_poll_response : ines_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : ines_line_status, +update_status : ines_update_status, +primary_address : ines_primary_address, +secondary_address : ines_secondary_address, +serial_poll_response : ines_serial_poll_response, +serial_poll_status : ines_serial_poll_status, +t1_delay : ines_t1_delay, +return_to_local : ines_return_to_local, +}; + +gpib_interface_t ines_pcmcia_interface = { +name: "ines_pcmcia", +attach : ines_pcmcia_accel_attach, +detach : ines_pcmcia_detach, +read : ines_accel_read, +write : ines_accel_write, +command : ines_command, +take_control : ines_take_control, +go_to_standby : ines_go_to_standby, +request_system_control : ines_request_system_control, +interface_clear : ines_interface_clear, +remote_enable : ines_remote_enable, +enable_eos : ines_enable_eos, +disable_eos : ines_disable_eos, +parallel_poll : ines_parallel_poll, +parallel_poll_configure : ines_parallel_poll_configure, +parallel_poll_response : ines_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : ines_line_status, +update_status : ines_update_status, +primary_address : ines_primary_address, +secondary_address : ines_secondary_address, +serial_poll_response : ines_serial_poll_response, +serial_poll_status : ines_serial_poll_status, +t1_delay : ines_t1_delay, +return_to_local : ines_return_to_local, +}; + +irqreturn_t ines_pcmcia_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + + return ines_interrupt(board); +} + +int ines_common_pcmcia_attach(gpib_board_t *board) +{ + struct ines_priv *ines_priv; + struct nec7210_priv *nec_priv; + int retval; + + if (!curr_dev) { + pr_err("no ines pcmcia cards found\n"); + return -1; + } + + retval = ines_generic_attach(board); + if (retval) + return retval; + + ines_priv = board->private_data; + nec_priv = &ines_priv->nec7210_priv; + + if (request_region(curr_dev->resource[0]->start, + resource_size(curr_dev->resource[0]), "ines_gpib") == 0) { + pr_err("ines_gpib: ioports at 0x%lx already in use\n", + (unsigned long)(curr_dev->resource[0]->start)); + return -1; + } + + nec_priv->iobase = (void *)(unsigned long)curr_dev->resource[0]->start; + + nec7210_board_reset(nec_priv, board); + + if (request_irq(curr_dev->irq, ines_pcmcia_interrupt, IRQF_SHARED, + "pcmcia-gpib", board)) { + pr_err("gpib: can't request IRQ %d\n", curr_dev->irq); + return -1; + } + ines_priv->irq = curr_dev->irq; + + return 0; +} + +int ines_pcmcia_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct ines_priv *ines_priv; + int retval; + + retval = ines_common_pcmcia_attach(board); + if (retval < 0) + return retval; + + ines_priv = board->private_data; + ines_online(ines_priv, board, 0); + + return 0; +} + +int ines_pcmcia_accel_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct ines_priv *ines_priv; + int retval; + + retval = ines_common_pcmcia_attach(board); + if (retval < 0) + return retval; + + ines_priv = board->private_data; + ines_online(ines_priv, board, 1); + + return 0; +} + +void ines_pcmcia_detach(gpib_board_t *board) +{ + struct ines_priv *ines_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (ines_priv) { + nec_priv = &ines_priv->nec7210_priv; + if (ines_priv->irq) + free_irq(ines_priv->irq, board); + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + release_region((unsigned long)(nec_priv->iobase), ines_pcmcia_iosize); + } + } + ines_free_private(board); +} + +#endif /* GPIB_PCMCIA */ + +static int __init ines_init_module(void) +{ + int err = 0; + + err = pci_register_driver(&ines_pci_driver); + if (err) { + pr_err("ines_gpib: pci_driver_register failed!\n"); + return err; + } + + gpib_register_driver(&ines_pci_interface, THIS_MODULE); + gpib_register_driver(&ines_pci_unaccel_interface, THIS_MODULE); + gpib_register_driver(&ines_pci_accel_interface, THIS_MODULE); + gpib_register_driver(&ines_isa_interface, THIS_MODULE); +#ifdef GPIB_PCMCIA + gpib_register_driver(&ines_pcmcia_interface, THIS_MODULE); + gpib_register_driver(&ines_pcmcia_unaccel_interface, THIS_MODULE); + gpib_register_driver(&ines_pcmcia_accel_interface, THIS_MODULE); + err += ines_pcmcia_init_module(); +#endif + if (err) + return -1; + + return 0; +} + +static void __exit ines_exit_module(void) +{ + gpib_unregister_driver(&ines_pci_interface); + gpib_unregister_driver(&ines_pci_unaccel_interface); + gpib_unregister_driver(&ines_pci_accel_interface); + gpib_unregister_driver(&ines_isa_interface); +#ifdef GPIB__PCMCIA + gpib_unregister_driver(&ines_pcmcia_interface); + gpib_unregister_driver(&ines_pcmcia_unaccel_interface); + gpib_unregister_driver(&ines_pcmcia_accel_interface); + ines_pcmcia_cleanup_module(); +#endif + + pci_unregister_driver(&ines_pci_driver); +} + +module_init(ines_init_module); +module_exit(ines_exit_module); diff --git a/drivers/staging/gpib/lpvo_usb_gpib/Makefile b/drivers/staging/gpib/lpvo_usb_gpib/Makefile new file mode 100644 index 00000000000000..137511acce6352 --- /dev/null +++ b/drivers/staging/gpib/lpvo_usb_gpib/Makefile @@ -0,0 +1,3 @@ + +obj-m += lpvo_usb_gpib.o + diff --git a/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c b/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c new file mode 100644 index 00000000000000..267651a15fa00e --- /dev/null +++ b/drivers/staging/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c @@ -0,0 +1,2136 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * This code has been developed at the Department of Physics (University * + * of Florence, Italy) to support in linux-gpib the open usb-gpib adapter * + * implemented at the University of Ljubljana (lpvo.fe.uni-lj.si/gpib) * + * * + * copyright : (C) 2011 Marcello Carla' * + ***************************************************************************/ + +/* base module includes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpibP.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for LPVO usb devices"); + +#define NAME "lpvo_usb_gpib" + +/* + * Table of devices that work with this driver. + * + * Currently, only one device is known to be used in the + * lpvo_usb_gpib adapter (FTDI 0403:6001). + * If your adapter uses a different chip, insert a line + * in the following table with proper , . + * + * To have your chip automatically handled by the driver, + * update files "/usr/local/etc/modprobe.d/lpvo_usb_gpib.conf" + * and /usr/local/etc/udev/rules.d/99-lpvo_usb_gpib.rules. + * + */ + +static const struct usb_device_id skel_table[] = { + { USB_DEVICE(0x0403, 0x6001) }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, skel_table); + +/* + * *** Diagnostics and Debug *** + * + * The module parameter "debug" controls the sending of debug messages to + * syslog. By default it is set to 0 or 1 according to GPIB_CONFIG_KERNEL_DEBUG. + * debug = 0: only register/deregister messages are generated + * 1: every action is logged + * 2: extended logging; each single exchanged byte is documented + * (about twice the log volume of [1]) + * To switch debug level: + * At module loading: modprobe lpvo_usb_gpib debug={0,1,2} + * On the fly: echo {0,1,2} > /sys/modules/lpvo_usb_gpib/parameters/debug + */ + +static int debug; +module_param(debug, int, 0644); + +#define DIA_LOG(level, format, ...) \ + do { if (debug >= (level)) \ + pr_alert("%s:%s - " format, NAME, __func__, ## __VA_ARGS__); } \ + while (0) + +/* standard and extended command sets of the usb-gpib adapter */ + +#define USB_GPIB_ON "\nIB\n" +#define USB_GPIB_OFF "\nIBO\n" +#define USB_GPIB_IBm0 "\nIBm0\n" /* do not assert REN with IFC */ +#define USB_GPIB_IBm1 "\nIBm1\n" /* assert REN with IFC */ +#define USB_GPIB_IBCL "\nIBZ\n" +#define USB_GPIB_STATUS "\nIBS\n" +#define USB_GPIB_READ "\nIB?\n" +#define USB_GPIB_READ_1 "\nIBB\n" +#define USB_GPIB_EOI "\nIBe0\n" +#define USB_GPIB_FTMO "\nIBf0\n" /* disable first byte timeout */ +#define USB_GPIB_TTMOZ "\nIBt0\n" /* disable byte timeout */ + +/* incomplete commands */ + +#define USB_GPIB_BTMO "\nIBt" /* set byte timeout */ +#define USB_GPIB_TTMO "\nIBT" /* set total timeout */ + +#define USB_GPIB_DEBUG_ON "\nIBDE\xAA\n" +#define USB_GPIB_SET_LISTEN "\nIBDT0\n" +#define USB_GPIB_SET_TALK "\nIBDT1\n" +#define USB_GPIB_SET_LINES "\nIBDC\n" +#define USB_GPIB_SET_DATA "\nIBDM\n" +#define USB_GPIB_READ_LINES "\nIBD?C\n" +#define USB_GPIB_READ_DATA "\nIBD?M\n" +#define USB_GPIB_READ_BUS "\nIBD??\n" + +/* command sequences */ + +#define USB_GPIB_UNTALK "\nIBC_\n" +#define USB_GPIB_UNLISTEN "\nIBC?\n" + +/* special characters used by the adapter */ + +#define DLE ('\020') +#define STX ('\02') +#define ETX ('\03') +#define ACK ('\06') +#define NODATA ('\03') +#define NODAV ('\011') + +#define IB_BUS_REN 0x01 +#define IB_BUS_IFC 0x02 +#define IB_BUS_NDAC 0x04 +#define IB_BUS_NRFD 0x08 +#define IB_BUS_DAV 0x10 +#define IB_BUS_EOI 0x20 +#define IB_BUS_ATN 0x40 +#define IB_BUS_SRQ 0x80 + +#define INBUF_SIZE 128 + +struct char_buf { /* used by one_char() routine */ + char *inbuf; + int last; + int nchar; +}; + +struct usb_gpib_priv { /* private data to the device */ + u8 eos; /* eos character */ + short eos_flags; /* eos mode */ + int timeout; /* current value for timeout */ + void *dev; /* the usb device private data structure */ +}; + +#define GPIB_DEV (((struct usb_gpib_priv *)board->private_data)->dev) + +#define SHOW_STATUS(board) { \ + DIA_LOG(2, "# - board %p\n", board); \ + DIA_LOG(2, "# - buffer_length %d\n", board->buffer_length); \ + DIA_LOG(2, "# - status %lx\n", board->status); \ + DIA_LOG(2, "# - use_count %d\n", board->use_count); \ + DIA_LOG(2, "# - pad %x\n", board->pad); \ + DIA_LOG(2, "# - sad %x\n", board->sad); \ + DIA_LOG(2, "# - timeout %d\n", board->usec_timeout); \ + DIA_LOG(2, "# - ppc %d\n", board->parallel_poll_configuration); \ + DIA_LOG(2, "# - t1delay %d\n", board->t1_nano_sec); \ + DIA_LOG(2, "# - online %d\n", board->online); \ + DIA_LOG(2, "# - autopoll %d\n", board->autospollers); \ + DIA_LOG(2, "# - autopoll task %p\n", board->autospoll_task); \ + DIA_LOG(2, "# - minor %d\n", board->minor); \ + DIA_LOG(2, "# - master %d\n", board->master); \ + DIA_LOG(2, "# - list %d\n", board->ist); \ + } +/* + * n = 0; + * list_for_each (l, &board->device_list) n++; + * TTY_LOG ("%s:%s - devices in list %d\n", a, b, n); + */ + +/* + * TTY_LOG - write a message to the current work terminal (if any) + */ + +#define TTY_LOG(format, ...) { \ + char buf[128]; \ + struct tty_struct *tty = get_current_tty(); \ + if (tty) { \ + snprintf(buf, 128, format, __VA_ARGS__); \ + tty->driver->ops->write(tty, buf, strlen(buf)); \ + tty->driver->ops->write(tty, "\r", 1); \ + } \ + } + +/* + * GLOBAL VARIABLES: required for + * pairing among gpib minor and usb minor. + * MAX_DEV is the max number of usb-gpib adapters; free + * to change as you like, but no more than 32 + */ + +#define MAX_DEV 8 +static struct usb_interface *lpvo_usb_interfaces[MAX_DEV]; /* registered interfaces */ +static int usb_minors[MAX_DEV]; /* usb minors */ +static int assigned_usb_minors; /* mask of filled slots */ +static struct mutex minors_lock; /* operations on usb_minors are to be protected */ + +/* + * usb-skeleton prototypes + */ + +struct usb_skel; +static ssize_t skel_do_write(struct usb_skel *, const char *, size_t); +static ssize_t skel_do_read(struct usb_skel *, char *, size_t); +static int skel_do_open(gpib_board_t *, int); +static int skel_do_release(gpib_board_t *); + +/* + * usec_diff : take difference in MICROsec between two 'timespec' + * (unix time in sec and NANOsec) + */ + +inline int usec_diff(struct timespec64 *a, struct timespec64 *b) +{ + return ((a->tv_sec - b->tv_sec) * 1000000 + + (a->tv_nsec - b->tv_nsec) / 1000); +} + +/* + * *** these routines are specific to the usb-gpib adapter *** + */ + +/** + * write_loop() - Send a byte sequence to the adapter + * + * @dev: the private device structure + * @msg: the byte sequence. + * @leng: the byte sequence length. + * + */ + +static int write_loop(void *dev, char *msg, int leng) +{ +// int nchar = 0, val; + +// do { + + return skel_do_write(dev, msg, leng); + +// if (val < 1) { +// printk (KERN_ALERT "%s:%s - write error: %d %d/%d\n", +// NAME, __func__, val, nchar, leng); +// return -EIO; +// } +// nchar +=val; +// } while (nchar < leng); +// return leng; +} + +static char printable(char x) +{ + if (x < 32 || x > 126) + return ' '; + return x; +} + +/** + * send_command() - Send a byte sequence and return a single byte reply. + * + * @board: the gpib_board_struct data area for this gpib interface + * @msg: the byte sequence. + * @leng the byte sequence length; can be given as zero and is + * computed automatically, but if 'msg' contains a zero byte, + * it has to be given explicitly. + */ + +static int send_command(gpib_board_t *board, char *msg, int leng) +{ + char buffer[64]; + int nchar, j; + int retval; + struct timespec64 before, after; + + ktime_get_real_ts64 (&before); + + if (!leng) + leng = strlen(msg); + retval = write_loop(GPIB_DEV, msg, leng); + if (retval < 0) + return retval; + + nchar = skel_do_read(GPIB_DEV, buffer, 64); + + if (nchar < 0) { + DIA_LOG(0, " return from read: %d\n", nchar); + return nchar; + } else if (nchar != 1) { + for (j = 0 ; j < leng ; j++) { + DIA_LOG(0, " Irregular reply to command: %d %x %c\n", + j, msg[j], printable(msg[j])); + } + for (j = 0 ; j < nchar ; j++) { + DIA_LOG(0, " Irregular command reply: %d %x %c\n", + j, buffer[j] & 0xff, printable(buffer[j])); + } + return -EIO; + } + ktime_get_real_ts64 (&after); + + DIA_LOG(1, "Sent %d - done %d us.\n", leng, usec_diff(&after, &before)); + + return buffer[0] & 0xff; +} + +/* + * + * set_control_line() - Set the value of a single gpib control line + * + * @board: the gpib_board_struct data area for this gpib interface + * @line: line mask + * @value: line new value (0/1) + * + */ + +static int set_control_line(gpib_board_t *board, int line, int value) +{ + char msg[] = USB_GPIB_SET_LINES; + int retval; + int leng = strlen(msg); + + DIA_LOG(1, "setting line %x to %x\n", line, value); + + retval = send_command(board, USB_GPIB_READ_LINES, 0); + + DIA_LOG(1, "old line values: %x\n", retval); + + if (retval == -EIO) + return retval; + + msg[leng - 2] = value ? (retval & ~line) : retval | line; + + retval = send_command(board, msg, 0); + + DIA_LOG(1, "operation result: %x\n", retval); + + return retval; +} + +/* + * one_char() - read one single byte from input buffer + * + * @board: the gpib_board_struct data area for this gpib interface + * @char_buf: the routine private data structure + */ + +static int one_char(gpib_board_t *board, struct char_buf *b) +{ + struct timespec64 before, after; + + if (b->nchar) { + DIA_LOG(2, "-> %x\n", b->inbuf[b->last - b->nchar]); + return b->inbuf[b->last - b->nchar--]; + } + ktime_get_real_ts64 (&before); + b->nchar = skel_do_read(GPIB_DEV, b->inbuf, INBUF_SIZE); + b->last = b->nchar; + ktime_get_real_ts64 (&after); + + DIA_LOG(2, "read %d bytes in %d usec\n", + b->nchar, usec_diff(&after, &before)); + + if (b->nchar > 0) { + DIA_LOG(2, "--> %x\n", b->inbuf[b->last - b->nchar]); + return b->inbuf[b->last - b->nchar--]; + } else if (b->nchar == 0) { + dev_alert(board->gpib_dev, "%s:%s - read returned EOF\n", NAME, __func__); + return -EIO; + } + dev_alert(board->gpib_dev, "%s:%s - read error %d\n", NAME, __func__, b->nchar); + TTY_LOG("\n *** %s *** Read Error - %s\n", NAME, + "Reset the adapter with 'gpib_config'\n"); + return -EIO; +} + +/** + * set_timeout() - set single byte / total timeouts on the adapter + * + * @board: the gpib_board_struct data area for this gpib interface + * + * For sake of speed, the operation is performed only if it + * modifies the current (saved) value. Minimum allowed timeout + * is 30 ms (T30ms -> 8); timeout disable (TNONE -> 0) currently + * not supported. + */ + +static void set_timeout(gpib_board_t *board) +{ + int n, val; + char command[sizeof(USB_GPIB_TTMO) + 6]; + struct usb_gpib_priv *data = board->private_data; + + if (data->timeout == board->usec_timeout) + return; + + n = (board->usec_timeout + 32767) / 32768; + if (n < 2) + n = 2; + + DIA_LOG(1, "Set timeout to %d us -> %d\n", board->usec_timeout, n); + + sprintf(command, "%s%d\n", USB_GPIB_BTMO, n > 255 ? 255 : n); + val = send_command(board, command, 0); + + if (val == ACK) { + if (n > 65535) + n = 65535; + sprintf(command, "%s%d\n", USB_GPIB_TTMO, n); + val = send_command(board, command, 0); + } + + if (val != ACK) { + dev_alert(board->gpib_dev, "%s:%s - error in timeout set: <%s>\n", + NAME, __func__, command); + } else { + data->timeout = board->usec_timeout; + } +} + +/* + * now the standard interface functions - attach and detach + */ + +/** + * usb_gpib_attach() - activate the usb-gpib converter board + * + * @board: the gpib_board_struct data area for this gpib interface + * @config: firmware data, if any (from gpib_config -I ) + * + * The channel name is ttyUSBn, with n=0 by default. Other values for n + * passed with gpib_config -b . + * + * In this routine I trust that when an error code is returned + * detach() will be called. Always. + */ + +static int usb_gpib_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + int retval, j; + int base = (long)config->ibbase; + char *device_path; + int match; + struct usb_device *udev; + + DIA_LOG(0, "Board %p -t %s -m %d -a %p -u %d -l %d -b %d\n", + board, board->interface->name, board->minor, config->device_path, + config->pci_bus, config->pci_slot, base); + + board->private_data = NULL; /* to be sure - we can detach before setting */ + + /* identify device to be attached */ + + mutex_lock(&minors_lock); + + if (config->device_path) { + /* if config->device_path given, try that first */ + dev_alert(board->gpib_dev, "%s:%s - Looking for device_path: %s\n", + NAME, __func__, config->device_path); + for (j = 0 ; j < MAX_DEV ; j++) { + if ((assigned_usb_minors & 1 << j) == 0) + continue; + udev = usb_get_dev(interface_to_usbdev(lpvo_usb_interfaces[j])); + device_path = kobject_get_path(&udev->dev.kobj, GFP_KERNEL); + match = gpib_match_device_path(&lpvo_usb_interfaces[j]->dev, + config->device_path); + DIA_LOG(1, "dev. %d: minor %d path: %s --> %d\n", j, + lpvo_usb_interfaces[j]->minor, device_path, match); + kfree(device_path); + if (match) + break; + } + } else if (config->pci_bus != -1 && config->pci_slot != -1) { + /* second: look for bus and slot */ + for (j = 0 ; j < MAX_DEV ; j++) { + if ((assigned_usb_minors & 1 << j) == 0) + continue; + udev = usb_get_dev(interface_to_usbdev(lpvo_usb_interfaces[j])); + DIA_LOG(1, "dev. %d: bus %d -> %d dev: %d -> %d\n", j, + udev->bus->busnum, config->pci_bus, udev->devnum, config->pci_slot); + if (config->pci_bus == udev->bus->busnum && + config->pci_slot == udev->devnum) + break; + } + } else { /* last chance: usb_minor, given as ibbase */ + for (j = 0 ; j < MAX_DEV ; j++) { + if (usb_minors[j] == base && assigned_usb_minors & 1 << j) + break; + } + } + mutex_unlock(&minors_lock); + + if (j == MAX_DEV) { + dev_alert(board->gpib_dev, "%s:%s - Requested device is not registered.\n", + NAME, __func__); + return -EIO; + } + + board->private_data = kzalloc(sizeof(struct usb_gpib_priv), GFP_KERNEL); + if (!board->private_data) + return -ENOMEM; + + retval = skel_do_open(board, usb_minors[j]); + + DIA_LOG(1, "Skel open: %d\n", retval); + + if (retval) { + TTY_LOG("%s:%s - skel open failed.\n", NAME, __func__); + kfree(board->private_data); + board->private_data = NULL; + return -ENODEV; + } + + SHOW_STATUS(board); + + retval = send_command(board, USB_GPIB_ON, 0); + DIA_LOG(1, "USB_GPIB_ON returns %x\n", retval); + if (retval != ACK) + return -EIO; + + /* We must setup debug mode because we need the extended instruction + * set to cope with the Core (gpib_common) point of view + */ + + retval = send_command(board, USB_GPIB_DEBUG_ON, 0); + DIA_LOG(1, "USB_GPIB_DEBUG_ON returns %x\n", retval); + if (retval != ACK) + return -EIO; + + /* We must keep REN off after an IFC because so it is + * assumed by the Core + */ + + retval = send_command(board, USB_GPIB_IBm0, 0); + DIA_LOG(1, "USB_GPIB_IBm0 returns %x\n", retval); + if (retval != ACK) + return -EIO; + + retval = set_control_line(board, IB_BUS_REN, 0); + if (retval != ACK) + return -EIO; + + retval = send_command(board, USB_GPIB_FTMO, 0); + DIA_LOG(1, "USB_GPIB_FTMO returns %x\n", retval); + if (retval != ACK) + return -EIO; + + SHOW_STATUS(board); + TTY_LOG("Module '%s' has been sucesfully configured\n", NAME); + return 0; +} + +/** + * usb_gpib_detach() - deactivate the usb-gpib converter board + * + * @board: the gpib_board data area for this gpib interface + * + */ + +static void usb_gpib_detach(gpib_board_t *board) +{ + int retval; + + SHOW_STATUS(board); + + DIA_LOG(0, "detaching %p\n", board); + + if (board->private_data) { + if (GPIB_DEV) { + write_loop(GPIB_DEV, USB_GPIB_OFF, strlen(USB_GPIB_OFF)); + msleep(100); + DIA_LOG(1, "%s", "GPIB off\n"); + retval = skel_do_release(board); + DIA_LOG(1, "skel release -> %d\n", retval); + } + kfree(board->private_data); + board->private_data = NULL; + } + + DIA_LOG(0, "done %p\n", board); + TTY_LOG("Module '%s' has been detached\n", NAME); +} + +/* + * Other functions follow in alphabetical order + */ +/* command */ +static int usb_gpib_command(gpib_board_t *board, + u8 *buffer, + size_t length, + size_t *bytes_written) +{ + int i, retval; + char command[6] = "IBc\n"; + + DIA_LOG(1, "enter %p\n", board); + + set_timeout(board); + + *bytes_written = 0; + for (i = 0 ; i < length ; i++) { + command[3] = buffer[i]; + retval = send_command(board, command, 5); + DIA_LOG(2, "%d ==> %x %x\n", i, buffer[i], retval); + if (retval != 0x06) + return retval; + ++(*bytes_written); + } + return 0; +} + +/** + * disable_eos() - Disable END on eos byte (END on EOI only) + * + * @board: the gpib_board data area for this gpib interface + * + * With the lpvo adapter eos can only be handled via software. + * Cannot do nothing here, but remember for future use. + */ + +static void usb_gpib_disable_eos(gpib_board_t *board) +{ + ((struct usb_gpib_priv *)board->private_data)->eos_flags &= ~REOS; + DIA_LOG(1, "done: %x\n", + ((struct usb_gpib_priv *)board->private_data)->eos_flags); +} + +/** + * enable_eos() - Enable END for reads when eos byte is received. + * + * @board: the gpib_board data area for this gpib interface + * @eos_byte: the 'eos' byte + * @compare_8_bits: if zero ignore eigthth bit when comparing + * + */ + +static int usb_gpib_enable_eos(gpib_board_t *board, + u8 eos_byte, + int compare_8_bits) +{ + struct usb_gpib_priv *pd = (struct usb_gpib_priv *)board->private_data; + + DIA_LOG(1, "enter with %x\n", eos_byte); + pd->eos = eos_byte; + pd->eos_flags = REOS; + if (compare_8_bits) + pd->eos_flags |= BIN; + return 0; +} + +/** + * go_to_standby() - De-assert ATN + * + * @board: the gpib_board data area for this gpib interface + */ + +static int usb_gpib_go_to_standby(gpib_board_t *board) +{ + int retval = set_control_line(board, IB_BUS_ATN, 0); + + DIA_LOG(1, "done with %x\n", retval); + + if (retval == ACK) + return 0; + return -EIO; +} + +/** + * interface_clear() - Assert or de-assert IFC + * + * @board: the gpib_board data area for this gpib interface + * assert: 1: assert IFC; 0: de-assert IFC + * + * Currently on the assert request we issue the lpvo IBZ + * command that cycles IFC low for 100 usec, then we ignore + * the de-assert request. + */ + +static void usb_gpib_interface_clear(gpib_board_t *board, int assert) +{ + int retval = 0; + + DIA_LOG(1, "enter with %d\n", assert); + + if (assert) { + retval = send_command(board, USB_GPIB_IBCL, 0); + + set_bit(CIC_NUM, &board->status); + } + + DIA_LOG(1, "done with %d %d\n", assert, retval); +} + +/** + * line_status() - Read the status of the bus lines. + * + * @board: the gpib_board data area for this gpib interface + * + * We can read all lines. + */ + +#define WQT wait_queue_entry_t +#define WQH head +#define WQE entry + +static int usb_gpib_line_status(const gpib_board_t *board) +{ + int buffer; + int line_status = ValidALL; /* all lines will be read */ + struct list_head *p, *q; + WQT *item; + unsigned long flags; + int sleep = 0; + + DIA_LOG(1, "%s\n", "request"); + + /* if we are on the wait queue (board->wait), do not hurry + * reading status line; instead, pause a little + */ + + spin_lock_irqsave((spinlock_t *)&board->wait.lock, flags); + q = (struct list_head *)&board->wait.WQH; + list_for_each(p, q) { + item = container_of(p, WQT, WQE); + if (item->private == current) { + sleep = 20; + break; + } + /* pid is: ((struct task_struct *) item->private)->pid); */ + } + spin_unlock_irqrestore((spinlock_t *)&board->wait.lock, flags); + if (sleep) { + DIA_LOG(1, "we are on the wait queue - sleep %d ms\n", sleep); + msleep(sleep); + } + + buffer = send_command((gpib_board_t *)board, USB_GPIB_STATUS, 0); + + if (buffer < 0) { + dev_alert(board->gpib_dev, "%s:%s - line status read failed with %d\n", + NAME, __func__, buffer); + return -1; + } + + if ((buffer & 0x01) == 0) + line_status |= BusREN; + if ((buffer & 0x02) == 0) + line_status |= BusIFC; + if ((buffer & 0x04) == 0) + line_status |= BusNDAC; + if ((buffer & 0x08) == 0) + line_status |= BusNRFD; + if ((buffer & 0x10) == 0) + line_status |= BusDAV; + if ((buffer & 0x20) == 0) + line_status |= BusEOI; + if ((buffer & 0x40) == 0) + line_status |= BusATN; + if ((buffer & 0x80) == 0) + line_status |= BusSRQ; + + DIA_LOG(1, "done with %x %x\n", buffer, line_status); + + return line_status; +} + +/* parallel_poll */ + +static int usb_gpib_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + /* request parallel poll asserting ATN | EOI; + * we suppose ATN already asserted + */ + + int retval; + + DIA_LOG(1, "enter %p\n", board); + + retval = set_control_line(board, IB_BUS_EOI, 1); + if (retval != ACK) { + dev_alert(board->gpib_dev, "%s:%s - assert EOI failed\n", NAME, __func__); + return -EIO; + } + + *result = send_command(board, USB_GPIB_READ_DATA, 0); + + DIA_LOG(1, "done with %x\n", *result); + + retval = set_control_line(board, IB_BUS_EOI, 0); + if (retval != 0x06) { + dev_alert(board->gpib_dev, "%s:%s - unassert EOI failed\n", NAME, __func__); + return -EIO; + } + + return 0; +} + +/* read */ + +static int usb_gpib_read(gpib_board_t *board, + u8 *buffer, + size_t length, + int *end, + size_t *bytes_read) +{ +#define MAX_READ_EXCESS 16384 + + struct char_buf b = {NULL, 0}; + + int retval; + char c, nc; + int ic; + struct timespec64 before, after; + int read_count = MAX_READ_EXCESS; + struct usb_gpib_priv *pd = (struct usb_gpib_priv *)board->private_data; + + DIA_LOG(1, "enter %p -> %zu\n", board, length); + + *bytes_read = 0; /* by default, things go wrong */ + *end = 0; + + set_timeout(board); + + /* single byte read has a special handling */ + + if (length == 1) { + char inbuf[2] = {0, 0}; + + /* read a single character */ + + ktime_get_real_ts64 (&before); + + retval = write_loop(GPIB_DEV, USB_GPIB_READ_1, strlen(USB_GPIB_READ_1)); + if (retval < 0) + return retval; + + retval = skel_do_read(GPIB_DEV, inbuf, 1); + retval += skel_do_read(GPIB_DEV, inbuf + 1, 1); + + ktime_get_real_ts64 (&after); + + DIA_LOG(1, "single read: %x %x %x in %d\n", retval, + inbuf[0], inbuf[1], + usec_diff(&after, &before)); + + /* good char / last char? */ + + if (retval == 2 && inbuf[1] == ACK) { + buffer[0] = inbuf[0]; + *bytes_read = 1; + return 0; + } + if (retval < 2) + return -EIO; + else + return -ETIME; + return 0; + } + + /* allocate buffer for multibyte read */ + + b.inbuf = kmalloc(INBUF_SIZE, GFP_KERNEL); + if (!b.inbuf) + return -ENOMEM; + + /* send read command and check sequence */ + + retval = write_loop(GPIB_DEV, USB_GPIB_READ, strlen(USB_GPIB_READ)); + if (retval < 0) + goto read_return; + + if (one_char(board, &b) != DLE || one_char(board, &b) != STX) { + dev_alert(board->gpib_dev, "%s:%s - wrong sequence\n", + NAME, __func__); + retval = -EIO; + goto read_return; + } + + /* get data flow */ + + while (1) { + ic = one_char(board, &b); + if (ic == -EIO) { + retval = -EIO; + goto read_return; + } + c = ic; + + if (c == DLE) + nc = one_char(board, &b); + if (c != DLE || nc == DLE) { + /* data byte - store into buffer */ + + if (*bytes_read == length) + break; /* data overflow */ + if (c == DLE) + c = nc; + buffer[(*bytes_read)++] = c; + if (c == pd->eos) { + *end = 1; + break; + } + + } else { + /* we are in the closing sequence */ + c = nc; + if (c == ETX) { + c = one_char(board, &b); + if (c == ACK) { + *end = 1; + retval = 0; + goto read_return; + } else { + dev_alert(board->gpib_dev, "%s:%s - %s %x\n", + NAME, __func__, + "Wrong end of message", c); + retval = -ETIME; + goto read_return; + } + } else { + dev_alert(board->gpib_dev, "%s:%s - %s\n", NAME, __func__, + "lone in stream"); + retval = -EIO; + goto read_return; + } + } + } + + /* we had a data overflow - flush excess data */ + + while (read_count--) { + if (one_char(board, &b) != DLE) + continue; + c = one_char(board, &b); + if (c == DLE) + continue; + if (c == ETX) { + c = one_char(board, &b); + if (c == ACK) { + if (MAX_READ_EXCESS - read_count > 1) + dev_alert(board->gpib_dev, "%s:%s - %s\n", NAME, __func__, + "small buffer - maybe some data lost"); + retval = 0; + goto read_return; + } + break; + } + } + + dev_alert(board->gpib_dev, "%s:%s - no input end - GPIB board in odd state\n", + NAME, __func__); + retval = -EIO; + +read_return: + kfree(b.inbuf); + + DIA_LOG(1, "done with byte/status: %d %x %d\n", + (int)*bytes_read, retval, *end); + + if (retval == 0 || retval == -ETIME) { + if (send_command(board, USB_GPIB_UNTALK, sizeof(USB_GPIB_UNTALK)) == 0x06) + return retval; + return -EIO; + } + + return retval; +} + +/* remote_enable */ + +static void usb_gpib_remote_enable(gpib_board_t *board, int enable) +{ + int retval; + + retval = set_control_line(board, IB_BUS_REN, enable ? 1 : 0); + if (retval != ACK) + dev_alert(board->gpib_dev, "%s:%s - could not set REN line: %x\n", + NAME, __func__, retval); + + DIA_LOG(1, "done with %x\n", retval); +} + +/* request_system_control */ + +static void usb_gpib_request_system_control(gpib_board_t *board, + int request_control) +{ + if (request_control) + set_bit(CIC_NUM, &board->status); + else + clear_bit(CIC_NUM, &board->status); + + DIA_LOG(1, "done with %d -> %lx\n", request_control, board->status); +} + +/* take_control */ +/* beware: the sync flag is ignored; what is its real meaning? */ + +static int usb_gpib_take_control(gpib_board_t *board, int sync) +{ + int retval; + + retval = set_control_line(board, IB_BUS_ATN, 1); + + DIA_LOG(1, "done with %d %x\n", sync, retval); + + if (retval == ACK) + return 0; + return -EIO; +} + +/* update_status */ + +static unsigned int usb_gpib_update_status(gpib_board_t *board, + unsigned int clear_mask) +{ + /* There is nothing we can do here, I guess */ + + board->status &= ~clear_mask; + + DIA_LOG(1, "done with %x %lx\n", clear_mask, board->status); + + return board->status; +} + +/* write */ +/* beware: DLE characters are not escaped - can only send ASCII data */ + +static int usb_gpib_write(gpib_board_t *board, + u8 *buffer, + size_t length, + int send_eoi, + size_t *bytes_written) +{ + int retval; + char *msg; + + DIA_LOG(1, "enter %p -> %zu\n", board, length); + + set_timeout(board); + + msg = kmalloc(length + 8, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + memcpy(msg, "\nIB\020\002", 5); + memcpy(msg + 5, buffer, length); + memcpy(msg + 5 + length, "\020\003\n", 3); + + retval = send_command(board, msg, length + 8); + kfree(msg); + + DIA_LOG(1, "<%.*s> -> %x\n", (int)length, buffer, retval); + + if (retval != ACK) + return -EPIPE; + + *bytes_written = length; + + if (send_command(board, USB_GPIB_UNLISTEN, sizeof(USB_GPIB_UNLISTEN)) + != 0x06) + return -EPIPE; + + return length; +} + +/* + * *** following functions not implemented yet *** + */ + +/* parallel_poll configure */ + +static void usb_gpib_parallel_poll_configure(gpib_board_t *board, + uint8_t configuration) +{ + dev_alert(board->gpib_dev, "%s:%s - currently a NOP\n", NAME, __func__); +} + +/* parallel_poll_response */ + +static void usb_gpib_parallel_poll_response(gpib_board_t *board, int ist) +{ + dev_alert(board->gpib_dev, "%s:%s - currently a NOP\n", NAME, __func__); +} + +/* primary_address */ + +static int usb_gpib_primary_address(gpib_board_t *board, unsigned int address) +{ + dev_alert(board->gpib_dev, "%s:%s - currently a NOP\n", NAME, __func__); + return 0; +} + +/* return_to_local */ + +static void usb_gpib_return_to_local(gpib_board_t *board) +{ + dev_alert(board->gpib_dev, "%s:%s - currently a NOP\n", NAME, __func__); +} + +/* secondary_address */ + +static int usb_gpib_secondary_address(gpib_board_t *board, + unsigned int address, + int enable) +{ + dev_alert(board->gpib_dev, "%s:%s - currently a NOP\n", NAME, __func__); + return 0; +} + +/* serial_poll_response */ + +static void usb_gpib_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + dev_alert(board->gpib_dev, "%s:%s - currently a NOP\n", NAME, __func__); +} + +/* serial_poll_status */ + +static uint8_t usb_gpib_serial_poll_status(gpib_board_t *board) +{ + dev_alert(board->gpib_dev, "%s:%s - currently a NOP\n", NAME, __func__); + return 0; +} + +/* t1_delay */ + +static unsigned int usb_gpib_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + dev_alert(board->gpib_dev, "%s:%s - currently a NOP\n", NAME, __func__); + return 0; +} + +/* + * *** module dispatch table and init/exit functions *** + */ + +gpib_interface_t usb_gpib_interface = { +name: NAME, +attach : usb_gpib_attach, +detach : usb_gpib_detach, +read : usb_gpib_read, +write : usb_gpib_write, +command : usb_gpib_command, +take_control : usb_gpib_take_control, +go_to_standby : usb_gpib_go_to_standby, +request_system_control : usb_gpib_request_system_control, +interface_clear : usb_gpib_interface_clear, +remote_enable : usb_gpib_remote_enable, +enable_eos : usb_gpib_enable_eos, +disable_eos : usb_gpib_disable_eos, +parallel_poll : usb_gpib_parallel_poll, +parallel_poll_configure : usb_gpib_parallel_poll_configure, +parallel_poll_response : usb_gpib_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : usb_gpib_line_status, +update_status : usb_gpib_update_status, +primary_address : usb_gpib_primary_address, +secondary_address : usb_gpib_secondary_address, +serial_poll_response : usb_gpib_serial_poll_response, +serial_poll_status : usb_gpib_serial_poll_status, +t1_delay : usb_gpib_t1_delay, +return_to_local : usb_gpib_return_to_local, +skip_check_for_command_acceptors : 1 +}; + +/* + * usb_gpib_init_module(), usb_gpib_exit_module() + * + * This functions are called every time a new device is detected + * and registered or is removed and unregistered. + * We must take note of created and destroyed usb minors to be used + * when usb_gpib_attach() and usb_gpib_detach() will be called on + * request by gpib_config. + */ + +static int usb_gpib_init_module(struct usb_interface *interface) +{ + int j, mask, rv; + + rv = mutex_lock_interruptible(&minors_lock); + if (rv < 0) + return rv; + + if (!assigned_usb_minors) { + gpib_register_driver(&usb_gpib_interface, THIS_MODULE); + } else { + /* check if minor is already registered - maybe useless, but if + * it happens the code is inconsistent somewhere + */ + + for (j = 0 ; j < MAX_DEV ; j++) { + if (usb_minors[j] == interface->minor && assigned_usb_minors & 1 << j) { + pr_alert("%s:%s - CODE BUG: USB minor %d registered at %d.\n", + NAME, __func__, interface->minor, j); + rv = -1; + goto exit; + } + } + } + + /* find a free slot */ + + for (j = 0 ; j < MAX_DEV ; j++) { + mask = 1 << j; + if ((assigned_usb_minors & mask) == 0) { + usb_minors[j] = interface->minor; + lpvo_usb_interfaces[j] = interface; + assigned_usb_minors |= mask; + DIA_LOG(0, "usb minor %d registered at %d\n", interface->minor, j); + rv = 0; + goto exit; + } + } + pr_alert("%s:%s - No slot available for interface %p minor %d\n", + NAME, __func__, interface, interface->minor); + rv = -1; + +exit: + mutex_unlock(&minors_lock); + return rv; +} + +static void usb_gpib_exit_module(int minor) +{ + int j; + + mutex_lock(&minors_lock); + for (j = 0 ; j < MAX_DEV ; j++) { + if (usb_minors[j] == minor && assigned_usb_minors & 1 << j) { + assigned_usb_minors &= ~(1 << j); + usb_minors[j] = -1; + if (assigned_usb_minors == 0) + gpib_unregister_driver(&usb_gpib_interface); + goto exit; + } + } + pr_alert("%s:%s - CODE BUG: USB minor %d not found.\n", NAME, __func__, minor); + +exit: + mutex_unlock(&minors_lock); +} + +/* + * Default latency time (16 msec) is too long. + * We must use 1 msec (best); anyhow, no more than 5 msec. + * + * Defines and function taken and modified from the kernel tree + * (see ftdi_sio.h and ftdi_sio.c). + * + */ + +#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40 +#define WDR_TIMEOUT 5000 /* default urb timeout */ +#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ + +#define LATENCY_TIMER 1 /* use a small latency timer: 1 ... 5 msec */ +#define LATENCY_CHANNEL 0 /* channel selection in multichannel devices */ +static int write_latency_timer(struct usb_device *udev) +{ + int rv = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + FTDI_SIO_SET_LATENCY_TIMER_REQUEST, + FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, + LATENCY_TIMER, LATENCY_CHANNEL, + NULL, 0, WDR_TIMEOUT); + if (rv < 0) + pr_alert("Unable to write latency timer: %i\n", rv); + return rv; +} + +/***************************************************************************** + * * + * The following code is a modified version of the USB Skeleton driver * + * written by Greg Kroah-Hartman and available in the kernel tree. * + * * + * Functions skel_open() and skel_release() have been rewritten and named * + * skel_do_open() and skel_do_release() to process the attach and detach * + * requests coming from gpib_config. * + * * + * Functions skel_read() and skel_write() have been split into a * + * skel_do_read() and skel_do_write(), that cover the kernel stuff of read * + * and write operations, and the original skel_read() and skel_write(), * + * that handle communication with user space and call their _do_ companion. * + * * + * Only the _do_ versions are used by the lpvo_usb_gpib driver; other ones * + * can be (optionally) maintained in the compilation to have direct access * + * to a gpib controller for debug and diagnostics. * + * * + * To avoid collisions in names, devices in user space have been renamed * + * lpvo_raw1, lpvo_raw2 .... and the usb driver has been renamed with the * + * gpib module name. * + * * + *****************************************************************************/ + +/* + * USB Skeleton driver - 2.2 + * + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * + * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c + * but has been rewritten to be easier to read and use. + */ + +#include +#include +#include +#include + +/* Get a minor range for your devices from the usb maintainer */ +#define USB_SKEL_MINOR_BASE 192 + +/* private defines */ + +#define MAX_TRANSFER (PAGE_SIZE - 512) +/* MAX_TRANSFER is chosen so that the VM is not stressed by + * allocations > PAGE_SIZE and the number of packets in a page + * is an integer 512 is the largest possible packet on EHCI + */ + +#define WRITES_IN_FLIGHT 1 /* we do not want more than one pending write */ +#define USER_DEVICE 1 /* compile for device(s) in user space */ + +/* Structure to hold all of our device specific stuff */ +struct usb_skel { + struct usb_device *udev; /* the usb device for this device */ + struct usb_interface *interface; /* the interface for this device */ + struct semaphore limit_sem; /* limiting the number of writes in progress */ + struct usb_anchor submitted; /* in case need to retract our submissions */ + struct urb *bulk_in_urb; /* the urb to read data with */ + unsigned char *bulk_in_buffer; /* the buffer to receive data */ + size_t bulk_in_size; /* the size of the receive buffer */ + size_t bulk_in_filled; /* number of bytes in the buffer */ + size_t bulk_in_copied; /* already copied to user space */ + __u8 bulk_in_endpoint_addr; /* the address of the bulk in endpoint */ + __u8 bulk_out_endpoint_addr; /* the address of the bulk out endpoint */ + int errors; /* the last request tanked */ + bool ongoing_read; /* a read is going on */ + spinlock_t err_lock; /* lock for errors */ + struct kref kref; + struct mutex io_mutex; /* synchronize I/O with disconnect */ + wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */ +}; + +#define to_skel_dev(d) container_of(d, struct usb_skel, kref) + +static struct usb_driver skel_driver; +static void skel_draw_down(struct usb_skel *dev); + +static void skel_delete(struct kref *kref) +{ + struct usb_skel *dev = to_skel_dev(kref); + + usb_free_urb(dev->bulk_in_urb); + usb_put_dev(dev->udev); + kfree(dev->bulk_in_buffer); + kfree(dev); +} + +/* + * skel_do_open() - to be called by usb_gpib_attach + */ + +static int skel_do_open(gpib_board_t *board, int subminor) +{ + struct usb_skel *dev; + struct usb_interface *interface; + int retval = 0; + + DIA_LOG(0, "Required minor: %d\n", subminor); + + interface = usb_find_interface(&skel_driver, subminor); + if (!interface) { + pr_err("%s - error, can't find device for minor %d\n", + __func__, subminor); + retval = -ENODEV; + goto exit; + } + + dev = usb_get_intfdata(interface); + if (!dev) { + retval = -ENODEV; + goto exit; + } + + retval = usb_autopm_get_interface(interface); + if (retval) + goto exit; + + /* increment our usage count for the device */ + kref_get(&dev->kref); + + /* save our object in the file's private structure */ + GPIB_DEV = dev; + +exit: + return retval; +} + +/* + * skel_do_release() - to be called by usb_gpib_detach + */ + +static int skel_do_release(gpib_board_t *board) +{ + struct usb_skel *dev; + + dev = GPIB_DEV; + if (!dev) + return -ENODEV; + + /* allow the device to be autosuspended */ + mutex_lock(&dev->io_mutex); + if (dev->interface) + usb_autopm_put_interface(dev->interface); + mutex_unlock(&dev->io_mutex); + + /* decrement the count on our device */ + kref_put(&dev->kref, skel_delete); + return 0; +} + +/* + * read functions + */ + +static void skel_read_bulk_callback(struct urb *urb) +{ + struct usb_skel *dev; + unsigned long flags; + + dev = urb->context; + + spin_lock_irqsave(&dev->err_lock, flags); + /* sync/async unlink faults aren't errors */ + if (urb->status) { + if (!(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) + dev_err(&dev->interface->dev, + "%s - nonzero read bulk status received: %d\n", + __func__, urb->status); + + dev->errors = urb->status; + } else { + dev->bulk_in_filled = urb->actual_length; + } + dev->ongoing_read = 0; + spin_unlock_irqrestore(&dev->err_lock, flags); + + wake_up_interruptible(&dev->bulk_in_wait); +} + +static int skel_do_read_io(struct usb_skel *dev, size_t count) +{ + int rv; + + /* prepare a read */ + usb_fill_bulk_urb(dev->bulk_in_urb, + dev->udev, + usb_rcvbulkpipe(dev->udev, + dev->bulk_in_endpoint_addr), + dev->bulk_in_buffer, + min(dev->bulk_in_size, count), + skel_read_bulk_callback, + dev); + /* tell everybody to leave the URB alone */ + spin_lock_irq(&dev->err_lock); + dev->ongoing_read = 1; + spin_unlock_irq(&dev->err_lock); + + /* submit bulk in urb, which means no data to deliver */ + dev->bulk_in_filled = 0; + dev->bulk_in_copied = 0; + + /* do it */ + rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); + if (rv < 0) { + dev_err(&dev->interface->dev, + "%s - failed submitting read urb, error %d\n", + __func__, rv); + rv = (rv == -ENOMEM) ? rv : -EIO; + spin_lock_irq(&dev->err_lock); + dev->ongoing_read = 0; + spin_unlock_irq(&dev->err_lock); + } + + return rv; +} + +/* + * skel_do_read() - read operations from lpvo_usb_gpib + */ + +static ssize_t skel_do_read(struct usb_skel *dev, char *buffer, size_t count) +{ + int rv; + bool ongoing_io; + + /* if we cannot read at all, return EOF */ + + if (!dev->bulk_in_urb || !count) + return 0; + + DIA_LOG(1, "enter for %zu.\n", count); + +restart: /* added to comply with ftdi timeout technique */ + + /* no concurrent readers */ + + DIA_LOG(2, "restart with %zd %zd.\n", dev->bulk_in_filled, dev->bulk_in_copied); + + rv = mutex_lock_interruptible(&dev->io_mutex); + if (rv < 0) + return rv; + + if (!dev->interface) { /* disconnect() was called */ + rv = -ENODEV; + goto exit; + } + +retry: + /* if IO is under way, we must not touch things */ + spin_lock_irq(&dev->err_lock); + ongoing_io = dev->ongoing_read; + spin_unlock_irq(&dev->err_lock); + + DIA_LOG(2, "retry with %d.\n", ongoing_io); + + if (ongoing_io) { +// /* nonblocking IO shall not wait */ +// /* no file, no O_NONBLOCK; maybe provide when from user space */ +// if (file->f_flags & O_NONBLOCK) { +// rv = -EAGAIN; +// goto exit; +// } + + /* + * IO may take forever + * hence wait in an interruptible state + */ + rv = wait_event_interruptible(dev->bulk_in_wait, (!dev->ongoing_read)); + if (rv < 0) + goto exit; + } + + /* errors must be reported */ + rv = dev->errors; + if (rv < 0) { + /* any error is reported once */ + dev->errors = 0; + /* to preserve notifications about reset */ + rv = (rv == -EPIPE) ? rv : -EIO; + /* report it */ + goto exit; + } + + /* + * if the buffer is filled we may satisfy the read + * else we need to start IO + */ + + if (dev->bulk_in_filled) { + /* we had read data */ + + size_t available = dev->bulk_in_filled - dev->bulk_in_copied; +// size_t chunk = min(available, count); /* compute chunk later */ + size_t chunk; + + DIA_LOG(2, "we have data: %zu %zu.\n", dev->bulk_in_filled, dev->bulk_in_copied); + + if (!available) { + /* + * all data has been used + * actual IO needs to be done + */ + /* it seems that requests for less than dev->bulk_in_size + * are not accepted + */ + rv = skel_do_read_io(dev, dev->bulk_in_size); + if (rv < 0) + goto exit; + else + goto retry; + } + + /* + * data is available - chunk tells us how much shall be copied + */ + + /* Condition dev->bulk_in_copied > 0 maybe will never happen. In case, + * signal the event and copy using the original procedure, i.e., copy + * first two bytes also + */ + + if (dev->bulk_in_copied) { + int j; + + for (j = 0 ; j < dev->bulk_in_filled ; j++) { + pr_alert("copy -> %x %zu %x\n", + j, dev->bulk_in_copied, dev->bulk_in_buffer[j]); + } + chunk = min(available, count); + memcpy(buffer, dev->bulk_in_buffer + dev->bulk_in_copied, chunk); + rv = chunk; + dev->bulk_in_copied += chunk; + + /* copy discarding first two bytes that contain ftdi chip status */ + + } else { + /* account for two bytes to be discarded */ + chunk = min(available, count + 2); + if (chunk < 2) { + pr_alert("BAD READ - chunk: %zu\n", chunk); + rv = -EIO; + goto exit; + } + + memcpy(buffer, dev->bulk_in_buffer + 2, chunk - 2); + rv = chunk; + dev->bulk_in_copied += chunk; + } + + /* + * if we are asked for more than we have, + * we start IO but don't wait + * + * No, no read ahead allowed; if the case, more data will be + * asked for by the lpvo_usb_gpib layer. + */ +// if (available < count) +// skel_do_read_io(dev, dev->bulk_in_size); + } else { + DIA_LOG(1, "no data - start read - copied: %zd.\n", dev->bulk_in_copied); + + /* no data in the buffer */ + rv = skel_do_read_io(dev, dev->bulk_in_size); + if (rv < 0) + goto exit; + else + goto retry; + } +exit: + mutex_unlock(&dev->io_mutex); + if (rv == 2) + goto restart; /* ftdi chip returns two status bytes after a latency anyhow */ + DIA_LOG(1, "exit with %d.\n", rv); + if (rv > 0) + return rv - 2; /* account for 2 discarded bytes in a valid buffer */ + return rv; +} + +/* + * write functions + */ + +static void skel_write_bulk_callback(struct urb *urb) +{ + struct usb_skel *dev; + unsigned long flags; + + dev = urb->context; + + /* sync/async unlink faults aren't errors */ + if (urb->status) { + if (!(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) + dev_err(&dev->interface->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, urb->status); + + spin_lock_irqsave(&dev->err_lock, flags); + dev->errors = urb->status; + spin_unlock_irqrestore(&dev->err_lock, flags); + } + + /* free up our allocated buffer */ + usb_free_coherent(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); + up(&dev->limit_sem); +} + +/* + * skel_do_write() - write operations from lpvo_usb_gpib + */ + +static ssize_t skel_do_write(struct usb_skel *dev, const char *buffer, size_t count) +{ + int retval = 0; + struct urb *urb = NULL; + char *buf = NULL; + size_t writesize = min_t(size_t, count, (size_t)MAX_TRANSFER); + + /* verify that we actually have some data to write */ + if (count == 0) + goto exit; + + /* + * limit the number of URBs in flight to stop a user from using up all + * RAM + */ + /* Only one URB is used, because we can't have a pending write() and go on */ + +// if (!(file->f_flags & O_NONBLOCK)) { /* no NONBLOCK provided */ + if (down_interruptible(&dev->limit_sem)) { + retval = -ERESTARTSYS; + goto exit; + } +// } else { +// if (down_trylock(&dev->limit_sem)) { +// retval = -EAGAIN; +// goto exit; +// } +// } + + spin_lock_irq(&dev->err_lock); + retval = dev->errors; + if (retval < 0) { + /* any error is reported once */ + dev->errors = 0; + /* to preserve notifications about reset */ + retval = (retval == -EPIPE) ? retval : -EIO; + } + spin_unlock_irq(&dev->err_lock); + if (retval < 0) + goto error; + + /* create a urb, and a buffer for it, and copy the data to the urb */ + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + retval = -ENOMEM; + goto error; + } + + buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL, + &urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + goto error; + } + + memcpy(buf, buffer, count); + + /* this lock makes sure we don't submit URBs to gone devices */ + mutex_lock(&dev->io_mutex); + if (!dev->interface) { /* disconnect() was called */ + mutex_unlock(&dev->io_mutex); + retval = -ENODEV; + goto error; + } + + /* initialize the urb properly */ + usb_fill_bulk_urb(urb, dev->udev, + usb_sndbulkpipe(dev->udev, dev->bulk_out_endpoint_addr), + buf, writesize, skel_write_bulk_callback, dev); + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(urb, &dev->submitted); + + /* send the data out the bulk port */ + retval = usb_submit_urb(urb, GFP_KERNEL); + mutex_unlock(&dev->io_mutex); + if (retval) { + dev_err(&dev->interface->dev, + "%s - failed submitting write urb, error %d\n", + __func__, retval); + goto error_unanchor; + } + + /* + * release our reference to this urb, the USB core will eventually free + * it entirely + */ + usb_free_urb(urb); + + return writesize; + +error_unanchor: + usb_unanchor_urb(urb); +error: + if (urb) { + usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma); + usb_free_urb(urb); + } + up(&dev->limit_sem); + +exit: + return retval; +} + +/* + * services for the user space devices + */ + +#if USER_DEVICE /* conditional compilation of user space device */ + +static int skel_flush(struct file *file, fl_owner_t id) +{ + struct usb_skel *dev; + int res; + + dev = file->private_data; + if (!dev) + return -ENODEV; + + /* wait for io to stop */ + mutex_lock(&dev->io_mutex); + skel_draw_down(dev); + + /* read out errors, leave subsequent opens a clean slate */ + spin_lock_irq(&dev->err_lock); + res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0; + dev->errors = 0; + spin_unlock_irq(&dev->err_lock); + + mutex_unlock(&dev->io_mutex); + + return res; +} + +static int skel_open(struct inode *inode, struct file *file) +{ + struct usb_skel *dev; + struct usb_interface *interface; + int subminor; + int retval = 0; + + subminor = iminor(inode); + + interface = usb_find_interface(&skel_driver, subminor); + if (!interface) { + pr_err("%s - error, can't find device for minor %d\n", + __func__, subminor); + retval = -ENODEV; + goto exit; + } + + dev = usb_get_intfdata(interface); + if (!dev) { + retval = -ENODEV; + goto exit; + } + + retval = usb_autopm_get_interface(interface); + if (retval) + goto exit; + + /* increment our usage count for the device */ + kref_get(&dev->kref); + + /* save our object in the file's private structure */ + file->private_data = dev; + +exit: + return retval; +} + +static int skel_release(struct inode *inode, struct file *file) +{ + struct usb_skel *dev; + + dev = file->private_data; + if (!dev) + return -ENODEV; + + /* allow the device to be autosuspended */ + mutex_lock(&dev->io_mutex); + if (dev->interface) + usb_autopm_put_interface(dev->interface); + mutex_unlock(&dev->io_mutex); + + /* decrement the count on our device */ + kref_put(&dev->kref, skel_delete); + return 0; +} + +/* + * user space access to read function + */ + +static ssize_t skel_read(struct file *file, char *buffer, size_t count, + loff_t *ppos) +{ + struct usb_skel *dev; + char *buf; + ssize_t rv; + + dev = file->private_data; + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rv = skel_do_read(dev, buf, count); + + pr_alert("%s - return with %zu\n", __func__, rv); + + if (rv > 0) { + if (copy_to_user(buffer, buf, rv)) { + kfree(buf); + return -EFAULT; + } + } + kfree(buf); + return rv; +} + +/* + * user space access to write function + */ + +static ssize_t skel_write(struct file *file, const char *user_buffer, + size_t count, loff_t *ppos) +{ + struct usb_skel *dev; + char *buf; + ssize_t rv; + + dev = file->private_data; + + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, user_buffer, count)) { + kfree(buf); + return -EFAULT; + } + + rv = skel_do_write(dev, buf, count); + kfree(buf); + return rv; +} +#endif + +static const struct file_operations skel_fops = { + .owner = THIS_MODULE, +#if USER_DEVICE + .read = skel_read, + .write = skel_write, + .open = skel_open, + .release = skel_release, + .flush = skel_flush, + .llseek = noop_llseek, +#endif +}; + +/* + * 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 + */ +#if USER_DEVICE +static struct usb_class_driver skel_class = { + .name = "lpvo_raw%d", + .fops = &skel_fops, + .minor_base = USB_SKEL_MINOR_BASE, +}; +#endif + +static int skel_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_skel *dev; + struct usb_endpoint_descriptor *bulk_in, *bulk_out; + int retval; + char *device_path; + + mutex_init(&minors_lock); /* required for handling minor numbers table */ + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + kref_init(&dev->kref); + sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); + mutex_init(&dev->io_mutex); + spin_lock_init(&dev->err_lock); + init_usb_anchor(&dev->submitted); + init_waitqueue_head(&dev->bulk_in_wait); + + dev->udev = usb_get_dev(interface_to_usbdev(interface)); + dev->interface = interface; + + /* set up the endpoint information */ + /* use only the first bulk-in and bulk-out endpoints */ + retval = usb_find_common_endpoints(interface->cur_altsetting, + &bulk_in, &bulk_out, NULL, NULL); + if (retval) { + dev_err(&interface->dev, + "Could not find both bulk-in and bulk-out endpoints\n"); + goto error; + } + + dev->bulk_in_size = usb_endpoint_maxp(bulk_in); + dev->bulk_in_endpoint_addr = bulk_in->bEndpointAddress; + dev->bulk_in_buffer = kmalloc(dev->bulk_in_size, GFP_KERNEL); + if (!dev->bulk_in_buffer) { + retval = -ENOMEM; + goto error; + } + dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->bulk_in_urb) { + retval = -ENOMEM; + goto error; + } + + dev->bulk_out_endpoint_addr = bulk_out->bEndpointAddress; + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + /* let the world know */ + + device_path = kobject_get_path(&dev->udev->dev.kobj, GFP_KERNEL); + pr_alert("%s:%s - New lpvo_usb_device -> bus: %d dev: %d path: %s\n", NAME, __func__, + dev->udev->bus->busnum, dev->udev->devnum, device_path); + kfree(device_path); + +#if USER_DEVICE + /* we can register the device now, as it is ready */ + retval = usb_register_dev(interface, &skel_class); + if (retval) { + /* something prevented us from registering this driver */ + dev_err(&interface->dev, + "Not able to get a minor for this device.\n"); + usb_set_intfdata(interface, NULL); + goto error; + } + + /* let the user know what node this device is now attached to */ + dev_info(&interface->dev, + "lpvo_usb_gpib device now attached to lpvo_raw%d", + interface->minor); +#endif + + write_latency_timer(dev->udev); /* adjust the latency timer */ + + usb_gpib_init_module(interface); /* last, init the lpvo for this minor */ + + return 0; + +error: + /* this frees allocated memory */ + kref_put(&dev->kref, skel_delete); + + return retval; +} + +static void skel_disconnect(struct usb_interface *interface) +{ + struct usb_skel *dev; + int minor = interface->minor; + + usb_gpib_exit_module(minor); /* first, disactivate the lpvo */ + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + +#if USER_DEVICE + /* give back our minor */ + usb_deregister_dev(interface, &skel_class); +#endif + + /* prevent more I/O from starting */ + mutex_lock(&dev->io_mutex); + dev->interface = NULL; + mutex_unlock(&dev->io_mutex); + + usb_kill_anchored_urbs(&dev->submitted); + + /* decrement our usage count */ + kref_put(&dev->kref, skel_delete); + + dev_info(&interface->dev, "USB lpvo_raw #%d now disconnected", minor); +} + +static void skel_draw_down(struct usb_skel *dev) +{ + int time; + + time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); + if (!time) + usb_kill_anchored_urbs(&dev->submitted); + usb_kill_urb(dev->bulk_in_urb); +} + +static int skel_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usb_skel *dev = usb_get_intfdata(intf); + + if (!dev) + return 0; + skel_draw_down(dev); + return 0; +} + +static int skel_resume(struct usb_interface *intf) +{ + return 0; +} + +static int skel_pre_reset(struct usb_interface *intf) +{ + struct usb_skel *dev = usb_get_intfdata(intf); + + mutex_lock(&dev->io_mutex); + skel_draw_down(dev); + + return 0; +} + +static int skel_post_reset(struct usb_interface *intf) +{ + struct usb_skel *dev = usb_get_intfdata(intf); + + /* we are sure no URBs are active - no locking needed */ + dev->errors = -EPIPE; + mutex_unlock(&dev->io_mutex); + + return 0; +} + +static struct usb_driver skel_driver = { + .name = NAME, + .probe = skel_probe, + .disconnect = skel_disconnect, + .suspend = skel_suspend, + .resume = skel_resume, + .pre_reset = skel_pre_reset, + .post_reset = skel_post_reset, + .id_table = skel_table, + .supports_autosuspend = 1, +}; + +module_usb_driver(skel_driver); diff --git a/drivers/staging/gpib/nec7210/Makefile b/drivers/staging/gpib/nec7210/Makefile new file mode 100644 index 00000000000000..64330f2e89d10e --- /dev/null +++ b/drivers/staging/gpib/nec7210/Makefile @@ -0,0 +1,4 @@ + +obj-$(CONFIG_GPIB_NEC7210) += nec7210.o + + diff --git a/drivers/staging/gpib/nec7210/board.h b/drivers/staging/gpib/nec7210/board.h new file mode 100644 index 00000000000000..ac3fe38ade5726 --- /dev/null +++ b/drivers/staging/gpib/nec7210/board.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2001, 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _GPIB_PCIIA_BOARD_H +#define _GPIB_PCIIA_BOARD_H + +#include "gpibP.h" +#include +#include +#include +#include + +#include "nec7210.h" + +#endif //_GPIB_PCIIA_BOARD_H + diff --git a/drivers/staging/gpib/nec7210/nec7210.c b/drivers/staging/gpib/nec7210/nec7210.c new file mode 100644 index 00000000000000..1d995103549746 --- /dev/null +++ b/drivers/staging/gpib/nec7210/nec7210.c @@ -0,0 +1,1134 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 2001, 2002 by Frank Mori Hess + ***************************************************************************/ + +#include "board.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB library code for NEC uPD7210"); + +int nec7210_enable_eos(gpib_board_t *board, struct nec7210_priv *priv, uint8_t eos_byte, + int compare_8_bits) +{ + write_byte(priv, eos_byte, EOSR); + priv->auxa_bits |= HR_REOS; + if (compare_8_bits) + priv->auxa_bits |= HR_BIN; + else + priv->auxa_bits &= ~HR_BIN; + write_byte(priv, priv->auxa_bits, AUXMR); + return 0; +} +EXPORT_SYMBOL(nec7210_enable_eos); + +void nec7210_disable_eos(gpib_board_t *board, struct nec7210_priv *priv) +{ + priv->auxa_bits &= ~HR_REOS; + write_byte(priv, priv->auxa_bits, AUXMR); +} +EXPORT_SYMBOL(nec7210_disable_eos); + +int nec7210_parallel_poll(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *result) +{ + int ret; + + clear_bit(COMMAND_READY_BN, &priv->state); + + // execute parallel poll + write_byte(priv, AUX_EPP, AUXMR); + // wait for result FIXME: support timeouts + ret = wait_event_interruptible(board->wait, test_bit(COMMAND_READY_BN, &priv->state)); + if (ret) { + dev_dbg(board->gpib_dev, "gpib: parallel poll interrupted\n"); + return -ERESTARTSYS; + } + *result = read_byte(priv, CPTR); + + return 0; +} +EXPORT_SYMBOL(nec7210_parallel_poll); + +void nec7210_parallel_poll_configure(gpib_board_t *board, + struct nec7210_priv *priv, unsigned int configuration) +{ + write_byte(priv, PPR | configuration, AUXMR); +} +EXPORT_SYMBOL(nec7210_parallel_poll_configure); + +void nec7210_parallel_poll_response(gpib_board_t *board, struct nec7210_priv *priv, int ist) +{ + if (ist) + write_byte(priv, AUX_SPPF, AUXMR); + else + write_byte(priv, AUX_CPPF, AUXMR); +} +EXPORT_SYMBOL(nec7210_parallel_poll_response); +/* This is really only adequate for chips that do a 488.2 style reqt/reqf + * based on bit 6 of the SPMR (see chapter 11.3.3 of 488.2). For simpler chips that simply + * set rsv directly based on bit 6, we either need to do more hardware setup to expose + * the 488.2 capability (for example with NI chips), or we need to implement the + * 488.2 set srv state machine in the driver (if that is even viable). + */ +void nec7210_serial_poll_response(gpib_board_t *board, struct nec7210_priv *priv, uint8_t status) +{ + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + if (status & request_service_bit) { + priv->srq_pending = 1; + clear_bit(SPOLL_NUM, &board->status); + + } else { + priv->srq_pending = 0; + } + write_byte(priv, status, SPMR); + spin_unlock_irqrestore(&board->spinlock, flags); +} +EXPORT_SYMBOL(nec7210_serial_poll_response); + +uint8_t nec7210_serial_poll_status(gpib_board_t *board, struct nec7210_priv *priv) +{ + return read_byte(priv, SPSR); +} +EXPORT_SYMBOL(nec7210_serial_poll_status); + +int nec7210_primary_address(const gpib_board_t *board, struct nec7210_priv *priv, + unsigned int address) +{ + // put primary address in address0 + write_byte(priv, address & ADDRESS_MASK, ADR); + return 0; +} +EXPORT_SYMBOL(nec7210_primary_address); + +int nec7210_secondary_address(const gpib_board_t *board, struct nec7210_priv *priv, + unsigned int address, int enable) +{ + if (enable) { + // put secondary address in address1 + write_byte(priv, HR_ARS | (address & ADDRESS_MASK), ADR); + // go to address mode 2 + priv->reg_bits[ADMR] &= ~HR_ADM0; + priv->reg_bits[ADMR] |= HR_ADM1; + } else { + // disable address1 register + write_byte(priv, HR_ARS | HR_DT | HR_DL, ADR); + // go to address mode 1 + priv->reg_bits[ADMR] |= HR_ADM0; + priv->reg_bits[ADMR] &= ~HR_ADM1; + } + write_byte(priv, priv->reg_bits[ADMR], ADMR); + return 0; +} +EXPORT_SYMBOL(nec7210_secondary_address); + +static void update_talker_state(struct nec7210_priv *priv, unsigned int address_status_bits) +{ + if ((address_status_bits & HR_TA)) { + if ((address_status_bits & HR_NATN)) { + if (address_status_bits & HR_SPMS) + priv->talker_state = serial_poll_active; + else + priv->talker_state = talker_active; + } else { + priv->talker_state = talker_addressed; + } + } else { + priv->talker_state = talker_idle; + } +} + +static void update_listener_state(struct nec7210_priv *priv, unsigned int address_status_bits) +{ + if (address_status_bits & HR_LA) { + if ((address_status_bits & HR_NATN)) + priv->listener_state = listener_active; + else + priv->listener_state = listener_addressed; + } else { + priv->listener_state = listener_idle; + } +} + +unsigned int nec7210_update_status_nolock(gpib_board_t *board, struct nec7210_priv *priv) +{ + int address_status_bits; + u8 spoll_status; + + if (!priv) + return 0; + + address_status_bits = read_byte(priv, ADSR); + if (address_status_bits & HR_CIC) + set_bit(CIC_NUM, &board->status); + else + clear_bit(CIC_NUM, &board->status); + // check for talker/listener addressed + update_talker_state(priv, address_status_bits); + if (priv->talker_state == talker_active || priv->talker_state == talker_addressed) + set_bit(TACS_NUM, &board->status); + else + clear_bit(TACS_NUM, &board->status); + update_listener_state(priv, address_status_bits); + if (priv->listener_state == listener_active || + priv->listener_state == listener_addressed) + set_bit(LACS_NUM, &board->status); + else + clear_bit(LACS_NUM, &board->status); + if (address_status_bits & HR_NATN) + clear_bit(ATN_NUM, &board->status); + else + set_bit(ATN_NUM, &board->status); + spoll_status = nec7210_serial_poll_status(board, priv); + if (priv->srq_pending && (spoll_status & request_service_bit) == 0) { + priv->srq_pending = 0; + set_bit(SPOLL_NUM, &board->status); + } +// dev_dbg(board->gpib_dev, "status 0x%x, state 0x%x\n", board->status, priv->state); + + /* we rely on the interrupt handler to set the + * rest of the status bits + */ + + return board->status; +} +EXPORT_SYMBOL(nec7210_update_status_nolock); + +unsigned int nec7210_update_status(gpib_board_t *board, struct nec7210_priv *priv, + unsigned int clear_mask) +{ + unsigned long flags; + unsigned int retval; + + spin_lock_irqsave(&board->spinlock, flags); + board->status &= ~clear_mask; + retval = nec7210_update_status_nolock(board, priv); + spin_unlock_irqrestore(&board->spinlock, flags); + + return retval; +} +EXPORT_SYMBOL(nec7210_update_status); + +unsigned int nec7210_set_reg_bits(struct nec7210_priv *priv, unsigned int reg, + unsigned int mask, unsigned int bits) +{ + priv->reg_bits[reg] &= ~mask; + priv->reg_bits[reg] |= mask & bits; + write_byte(priv, priv->reg_bits[reg], reg); + return priv->reg_bits[reg]; +} +EXPORT_SYMBOL(nec7210_set_reg_bits); + +void nec7210_set_handshake_mode(gpib_board_t *board, struct nec7210_priv *priv, int mode) +{ + unsigned long flags; + + mode &= HR_HANDSHAKE_MASK; + + spin_lock_irqsave(&board->spinlock, flags); + if ((priv->auxa_bits & HR_HANDSHAKE_MASK) != mode) { + priv->auxa_bits &= ~HR_HANDSHAKE_MASK; + priv->auxa_bits |= mode; + write_byte(priv, priv->auxa_bits, AUXMR); + } + spin_unlock_irqrestore(&board->spinlock, flags); +} +EXPORT_SYMBOL(nec7210_set_handshake_mode); + +uint8_t nec7210_read_data_in(gpib_board_t *board, struct nec7210_priv *priv, int *end) +{ + unsigned long flags; + u8 data; + + spin_lock_irqsave(&board->spinlock, flags); + data = read_byte(priv, DIR); + clear_bit(READ_READY_BN, &priv->state); + if (test_and_clear_bit(RECEIVED_END_BN, &priv->state)) + *end = 1; + else + *end = 0; + spin_unlock_irqrestore(&board->spinlock, flags); + + return data; +} +EXPORT_SYMBOL(nec7210_read_data_in); + +int nec7210_take_control(gpib_board_t *board, struct nec7210_priv *priv, int syncronous) +{ + int i; + const int timeout = 100; + int retval = 0; + unsigned int adsr_bits = 0; + + if (syncronous) + write_byte(priv, AUX_TCS, AUXMR); + else + write_byte(priv, AUX_TCA, AUXMR); + // busy wait until ATN is asserted + for (i = 0; i < timeout; i++) { + adsr_bits = read_byte(priv, ADSR); + if ((adsr_bits & HR_NATN) == 0) + break; + udelay(1); + } + if (i == timeout) + return -ETIMEDOUT; + + clear_bit(WRITE_READY_BN, &priv->state); + + return retval; +} +EXPORT_SYMBOL(nec7210_take_control); + +int nec7210_go_to_standby(gpib_board_t *board, struct nec7210_priv *priv) +{ + int i; + const int timeout = 1000; + unsigned int adsr_bits = 0; + int retval = 0; + + write_byte(priv, AUX_GTS, AUXMR); + // busy wait until ATN is released + for (i = 0; i < timeout; i++) { + adsr_bits = read_byte(priv, ADSR); + if (adsr_bits & HR_NATN) + break; + udelay(1); + } + // if busy wait has failed, try sleeping + if (i == timeout) { + for (i = 0; i < HZ; i++) { + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout(1)) + return -ERESTARTSYS; + adsr_bits = read_byte(priv, ADSR); + if (adsr_bits & HR_NATN) + break; + } + if (i == HZ) { + pr_err("nec7210: error waiting for NATN\n"); + return -ETIMEDOUT; + } + } + + clear_bit(COMMAND_READY_BN, &priv->state); + return retval; +} +EXPORT_SYMBOL(nec7210_go_to_standby); + +void nec7210_request_system_control(gpib_board_t *board, struct nec7210_priv *priv, + int request_control) +{ + if (request_control == 0) { + write_byte(priv, AUX_CREN, AUXMR); + write_byte(priv, AUX_CIFC, AUXMR); + write_byte(priv, AUX_DSC, AUXMR); + } +} +EXPORT_SYMBOL(nec7210_request_system_control); + +void nec7210_interface_clear(gpib_board_t *board, struct nec7210_priv *priv, int assert) +{ + if (assert) + write_byte(priv, AUX_SIFC, AUXMR); + else + write_byte(priv, AUX_CIFC, AUXMR); +} +EXPORT_SYMBOL(nec7210_interface_clear); + +void nec7210_remote_enable(gpib_board_t *board, struct nec7210_priv *priv, int enable) +{ + if (enable) + write_byte(priv, AUX_SREN, AUXMR); + else + write_byte(priv, AUX_CREN, AUXMR); +} +EXPORT_SYMBOL(nec7210_remote_enable); + +void nec7210_release_rfd_holdoff(gpib_board_t *board, struct nec7210_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + if (test_bit(RFD_HOLDOFF_BN, &priv->state) && + test_bit(READ_READY_BN, &priv->state) == 0) { + write_byte(priv, AUX_FH, AUXMR); + clear_bit(RFD_HOLDOFF_BN, &priv->state); + } + spin_unlock_irqrestore(&board->spinlock, flags); +} +EXPORT_SYMBOL(nec7210_release_rfd_holdoff); + +unsigned int nec7210_t1_delay(gpib_board_t *board, struct nec7210_priv *priv, + unsigned int nano_sec) +{ + unsigned int retval; + + if (nano_sec <= 500) { + priv->auxb_bits |= HR_TRI; + retval = 500; + } else { + priv->auxb_bits &= ~HR_TRI; + retval = 2000; + } + write_byte(priv, priv->auxb_bits, AUXMR); + + return retval; +} +EXPORT_SYMBOL(nec7210_t1_delay); + +void nec7210_return_to_local(const gpib_board_t *board, struct nec7210_priv *priv) +{ + write_byte(priv, AUX_RTL, AUXMR); +} +EXPORT_SYMBOL(nec7210_return_to_local); + +static inline short nec7210_atn_has_changed(gpib_board_t *board, struct nec7210_priv *priv) +{ + short address_status_bits = read_byte(priv, ADSR); + + if (address_status_bits & HR_NATN) { + if (test_bit(ATN_NUM, &board->status)) + return 1; + else + return 0; + } else { + if (test_bit(ATN_NUM, &board->status)) + return 0; + else + return 1; + } + return -1; +} + +int nec7210_command(gpib_board_t *board, struct nec7210_priv *priv, uint8_t + *buffer, size_t length, size_t *bytes_written) +{ + int retval = 0; + unsigned long flags; + + *bytes_written = 0; + + clear_bit(BUS_ERROR_BN, &priv->state); + + while (*bytes_written < length) { + if (wait_event_interruptible(board->wait, + test_bit(COMMAND_READY_BN, &priv->state) || + test_bit(BUS_ERROR_BN, &priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib command wait interrupted\n"); + retval = -ERESTARTSYS; + break; + } + if (test_bit(TIMO_NUM, &board->status)) + break; + if (test_and_clear_bit(BUS_ERROR_BN, &priv->state)) { + pr_err("nec7210: bus error on command byte\n"); + break; + } + + spin_lock_irqsave(&board->spinlock, flags); + clear_bit(COMMAND_READY_BN, &priv->state); + write_byte(priv, buffer[*bytes_written], CDOR); + spin_unlock_irqrestore(&board->spinlock, flags); + + ++(*bytes_written); + + if (need_resched()) + schedule(); + } + // wait for last byte to get sent + if (wait_event_interruptible(board->wait, test_bit(COMMAND_READY_BN, &priv->state) || + test_bit(BUS_ERROR_BN, &priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib command wait interrupted\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) { + dev_dbg(board->gpib_dev, "gpib command timed out\n"); + retval = -ETIMEDOUT; + } + if (test_and_clear_bit(BUS_ERROR_BN, &priv->state)) { + pr_err("nec7210: bus error on command byte\n"); + retval = -EIO; + } + + return retval; +} +EXPORT_SYMBOL(nec7210_command); + +static int pio_read(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + ssize_t retval = 0; + + *bytes_read = 0; + *end = 0; + + while (*bytes_read < length) { + if (wait_event_interruptible(board->wait, + test_bit(READ_READY_BN, &priv->state) || + test_bit(DEV_CLEAR_BN, &priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "nec7210: pio read wait interrupted\n"); + retval = -ERESTARTSYS; + break; + } + if (test_bit(READ_READY_BN, &priv->state)) { + if (*bytes_read == 0) { + /* We set the handshake mode here because we know + * no new bytes will arrive (it has already arrived + * and is awaiting being read out of the chip) while we are changing + * modes. This ensures we can reliably keep track + * of the holdoff state. + */ + nec7210_set_handshake_mode(board, priv, HR_HLDA); + } + buffer[(*bytes_read)++] = nec7210_read_data_in(board, priv, end); + if (*end) + break; + } + if (test_bit(TIMO_NUM, &board->status)) { + dev_dbg(board->gpib_dev, "interrupted by timeout\n"); + retval = -ETIMEDOUT; + break; + } + if (test_bit(DEV_CLEAR_BN, &priv->state)) { + dev_dbg(board->gpib_dev, "interrupted by device clear\n"); + retval = -EINTR; + break; + } + + if (*bytes_read < length) + nec7210_release_rfd_holdoff(board, priv); + + if (need_resched()) + schedule(); + } + return retval; +} + +#ifdef NEC_DMA +static ssize_t __dma_read(gpib_board_t *board, struct nec7210_priv *priv, size_t length) +{ + ssize_t retval = 0; + size_t count = 0; + unsigned long flags, dma_irq_flags; + + if (length == 0) + return 0; + + spin_lock_irqsave(&board->spinlock, flags); + + dma_irq_flags = claim_dma_lock(); + disable_dma(priv->dma_channel); + /* program dma controller */ + clear_dma_ff(priv->dma_channel); + set_dma_count(priv->dma_channel, length); + set_dma_addr(priv->dma_channel, priv->dma_buffer_addr); + set_dma_mode(priv->dma_channel, DMA_MODE_READ); + release_dma_lock(dma_irq_flags); + + enable_dma(priv->dma_channel); + + set_bit(DMA_READ_IN_PROGRESS_BN, &priv->state); + clear_bit(READ_READY_BN, &priv->state); + + // enable nec7210 dma + nec7210_set_reg_bits(priv, IMR2, HR_DMAI, HR_DMAI); + + spin_unlock_irqrestore(&board->spinlock, flags); + + // wait for data to transfer + if (wait_event_interruptible(board->wait, + test_bit(DMA_READ_IN_PROGRESS_BN, &priv->state) == 0 || + test_bit(DEV_CLEAR_BN, &priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "nec7210: dma read wait interrupted\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_bit(DEV_CLEAR_BN, &priv->state)) + retval = -EINTR; + + // disable nec7210 dma + nec7210_set_reg_bits(priv, IMR2, HR_DMAI, 0); + + // record how many bytes we transferred + flags = claim_dma_lock(); + clear_dma_ff(priv->dma_channel); + disable_dma(priv->dma_channel); + count += length - get_dma_residue(priv->dma_channel); + release_dma_lock(flags); + + return retval ? retval : count; +} + +static ssize_t dma_read(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, + size_t length) +{ + size_t remain = length; + size_t transfer_size; + ssize_t retval = 0; + + while (remain > 0) { + transfer_size = (priv->dma_buffer_length < remain) ? + priv->dma_buffer_length : remain; + retval = __dma_read(board, priv, transfer_size); + if (retval < 0) + break; + memcpy(buffer, priv->dma_buffer, transfer_size); + remain -= retval; + buffer += retval; + if (test_bit(RECEIVED_END_BN, &priv->state)) + break; + } + + if (retval < 0) + return retval; + + return length - remain; +} +#endif + +int nec7210_read(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + ssize_t retval = 0; + + *end = 0; + *bytes_read = 0; + + if (length == 0) + return 0; + + clear_bit(DEV_CLEAR_BN, &priv->state); // XXX wrong + + nec7210_release_rfd_holdoff(board, priv); + + retval = pio_read(board, priv, buffer, length, end, bytes_read); + + return retval; +} +EXPORT_SYMBOL(nec7210_read); + +static int pio_write_wait(gpib_board_t *board, struct nec7210_priv *priv, + short wake_on_lacs, short wake_on_atn, short wake_on_bus_error) +{ + // wait until byte is ready to be sent + if (wait_event_interruptible(board->wait, + (test_bit(TACS_NUM, &board->status) && + test_bit(WRITE_READY_BN, &priv->state)) || + test_bit(DEV_CLEAR_BN, &priv->state) || + (wake_on_bus_error && test_bit(BUS_ERROR_BN, &priv->state)) || + (wake_on_lacs && test_bit(LACS_NUM, &board->status)) || + (wake_on_atn && test_bit(ATN_NUM, &board->status)) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib write interrupted\n"); + return -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) { + dev_dbg(board->gpib_dev, "nec7210: write timed out\n"); + return -ETIMEDOUT; + } + if (test_bit(DEV_CLEAR_BN, &priv->state)) { + dev_dbg(board->gpib_dev, "nec7210: write interrupted by clear\n"); + return -EINTR; + } + if (wake_on_bus_error && test_and_clear_bit(BUS_ERROR_BN, &priv->state)) { + dev_dbg(board->gpib_dev, "nec7210: bus error on write\n"); + return -EIO; + } + return 0; +} + +static int pio_write(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, + size_t length, size_t *bytes_written) +{ + size_t last_count = 0; + ssize_t retval = 0; + unsigned long flags; + const int max_bus_errors = (length > 1000) ? length : 1000; + int bus_error_count = 0; + *bytes_written = 0; + + clear_bit(BUS_ERROR_BN, &priv->state); + + while (*bytes_written < length) { + if (need_resched()) + schedule(); + + retval = pio_write_wait(board, priv, 0, 0, priv->type == NEC7210); + if (retval == -EIO) { + /* resend last byte on bus error */ + *bytes_written = last_count; + dev_dbg(board->gpib_dev, "resending %c\n", buffer[*bytes_written]); + /* we can get unrecoverable bus errors, + * so give up after a while + */ + bus_error_count++; + if (bus_error_count > max_bus_errors) + return retval; + continue; + } else { + if (retval < 0) + return retval; + } + spin_lock_irqsave(&board->spinlock, flags); + clear_bit(BUS_ERROR_BN, &priv->state); + clear_bit(WRITE_READY_BN, &priv->state); + last_count = *bytes_written; + write_byte(priv, buffer[(*bytes_written)++], CDOR); + spin_unlock_irqrestore(&board->spinlock, flags); + } + retval = pio_write_wait(board, priv, 1, 1, priv->type == NEC7210); + return retval; +} + +#ifdef NEC_DMA +static ssize_t __dma_write(gpib_board_t *board, struct nec7210_priv *priv, dma_addr_t address, + size_t length) +{ + unsigned long flags, dma_irq_flags; + int residue = 0; + int retval = 0; + + spin_lock_irqsave(&board->spinlock, flags); + + /* program dma controller */ + dma_irq_flags = claim_dma_lock(); + disable_dma(priv->dma_channel); + clear_dma_ff(priv->dma_channel); + set_dma_count(priv->dma_channel, length); + set_dma_addr(priv->dma_channel, address); + set_dma_mode(priv->dma_channel, DMA_MODE_WRITE); + enable_dma(priv->dma_channel); + release_dma_lock(dma_irq_flags); + + // enable board's dma for output + nec7210_set_reg_bits(priv, IMR2, HR_DMAO, HR_DMAO); + + clear_bit(WRITE_READY_BN, &priv->state); + set_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state); + + spin_unlock_irqrestore(&board->spinlock, flags); + + // suspend until message is sent + if (wait_event_interruptible(board->wait, + test_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state) == 0 || + test_bit(BUS_ERROR_BN, &priv->state) || + test_bit(DEV_CLEAR_BN, &priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib write interrupted!\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + if (test_and_clear_bit(DEV_CLEAR_BN, &priv->state)) + retval = -EINTR; + if (test_and_clear_bit(BUS_ERROR_BN, &priv->state)) + retval = -EIO; + + // disable board's dma + nec7210_set_reg_bits(priv, IMR2, HR_DMAO, 0); + + dma_irq_flags = claim_dma_lock(); + clear_dma_ff(priv->dma_channel); + disable_dma(priv->dma_channel); + residue = get_dma_residue(priv->dma_channel); + release_dma_lock(dma_irq_flags); + + if (residue) + retval = -EPIPE; + + return retval ? retval : length; +} + +static ssize_t dma_write(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, + size_t length) +{ + size_t remain = length; + size_t transfer_size; + ssize_t retval = 0; + + while (remain > 0) { + transfer_size = (priv->dma_buffer_length < remain) ? + priv->dma_buffer_length : remain; + memcpy(priv->dma_buffer, buffer, transfer_size); + retval = __dma_write(board, priv, priv->dma_buffer_addr, transfer_size); + if (retval < 0) + break; + remain -= retval; + buffer += retval; + } + + if (retval < 0) + return retval; + + return length - remain; +} +#endif +int nec7210_write(gpib_board_t *board, struct nec7210_priv *priv, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + int retval = 0; + + *bytes_written = 0; + + clear_bit(DEV_CLEAR_BN, &priv->state); //XXX + + if (send_eoi) + length-- ; /* save the last byte for sending EOI */ + + if (length > 0) { + // isa dma transfer + if (0 /*priv->dma_channel*/) { +/* + * dma writes are unreliable since they can't recover from bus errors + * (which happen when ATN is asserted in the middle of a write) + */ +#ifdef NEC_DMA + retval = dma_write(board, priv, buffer, length); + if (retval < 0) + return retval; + count += retval; +#endif + } else { // PIO transfer + size_t num_bytes; + + retval = pio_write(board, priv, buffer, length, &num_bytes); + + *bytes_written += num_bytes; + if (retval < 0) + return retval; + } + } + if (send_eoi) { + size_t num_bytes; + + /* We need to wait to make sure we will immediately be able to write the data byte + * into the chip before sending the associated AUX_SEOI command. This is really + * only needed for length==1 since otherwise the earlier calls to pio_write + * will have dont the wait already. + */ + retval = pio_write_wait(board, priv, 0, 0, priv->type == NEC7210); + if (retval < 0) + return retval; + /*send EOI */ + write_byte(priv, AUX_SEOI, AUXMR); + + retval = pio_write(board, priv, &buffer[*bytes_written], 1, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + return retval; + } + + return retval; +} +EXPORT_SYMBOL(nec7210_write); + +/* + * interrupt service routine + */ +irqreturn_t nec7210_interrupt(gpib_board_t *board, struct nec7210_priv *priv) +{ + int status1, status2; + + // read interrupt status (also clears status) + status1 = read_byte(priv, ISR1); + status2 = read_byte(priv, ISR2); + + return nec7210_interrupt_have_status(board, priv, status1, status2); +} +EXPORT_SYMBOL(nec7210_interrupt); + +irqreturn_t nec7210_interrupt_have_status(gpib_board_t *board, + struct nec7210_priv *priv, int status1, int status2) +{ +#ifdef NEC_DMA + unsigned long dma_flags; +#endif + int retval = IRQ_NONE; + + // record service request in status + if (status2 & HR_SRQI) + set_bit(SRQI_NUM, &board->status); + + // change in lockout status + if (status2 & HR_LOKC) { + if (status2 & HR_LOK) + set_bit(LOK_NUM, &board->status); + else + clear_bit(LOK_NUM, &board->status); + } + + // change in remote status + if (status2 & HR_REMC) { + if (status2 & HR_REM) + set_bit(REM_NUM, &board->status); + else + clear_bit(REM_NUM, &board->status); + } + + // record reception of END + if (status1 & HR_END) { + set_bit(RECEIVED_END_BN, &priv->state); + if ((priv->auxa_bits & HR_HANDSHAKE_MASK) == HR_HLDE) + set_bit(RFD_HOLDOFF_BN, &priv->state); + } + + // get incoming data in PIO mode + if ((status1 & HR_DI)) { + set_bit(READ_READY_BN, &priv->state); + if ((priv->auxa_bits & HR_HANDSHAKE_MASK) == HR_HLDA) + set_bit(RFD_HOLDOFF_BN, &priv->state); + } +#ifdef NEC_DMA + // check for dma read transfer complete + if (test_bit(DMA_READ_IN_PROGRESS_BN, &priv->state)) { + dma_flags = claim_dma_lock(); + disable_dma(priv->dma_channel); + clear_dma_ff(priv->dma_channel); + if ((status1 & HR_END) || get_dma_residue(priv->dma_channel) == 0) + clear_bit(DMA_READ_IN_PROGRESS_BN, &priv->state); + else + enable_dma(priv->dma_channel); + release_dma_lock(dma_flags); + } +#endif + if ((status1 & HR_DO)) { + if (test_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state) == 0) + set_bit(WRITE_READY_BN, &priv->state); +#ifdef NEC_DMA + if (test_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state)) { // write data, isa dma mode + // check if dma transfer is complete + dma_flags = claim_dma_lock(); + disable_dma(priv->dma_channel); + clear_dma_ff(priv->dma_channel); + if (get_dma_residue(priv->dma_channel) == 0) { + clear_bit(DMA_WRITE_IN_PROGRESS_BN, &priv->state); + // XXX race? byte may still be in CDOR reg + } else { + clear_bit(WRITE_READY_BN, &priv->state); + enable_dma(priv->dma_channel); + } + release_dma_lock(dma_flags); + } +#endif + } + + // outgoing command can be sent + if (status2 & HR_CO) + set_bit(COMMAND_READY_BN, &priv->state); + + // command pass through received + if (status1 & HR_CPT) { + unsigned int command; + + command = read_byte(priv, CPTR) & gpib_command_mask; + write_byte(priv, AUX_NVAL, AUXMR); +// printk("gpib: command pass through 0x%x\n", command); + } + + if (status1 & HR_ERR) + set_bit(BUS_ERROR_BN, &priv->state); + + if (status1 & HR_DEC) { + unsigned short address_status_bits = read_byte(priv, ADSR); + + // ignore device clear events if we are controller in charge + if ((address_status_bits & HR_CIC) == 0) { + push_gpib_event(board, EventDevClr); + set_bit(DEV_CLEAR_BN, &priv->state); + } + } + + if (status1 & HR_DET) + push_gpib_event(board, EventDevTrg); + + // Addressing status has changed + if (status2 & HR_ADSC) + set_bit(ADR_CHANGE_BN, &priv->state); + + if ((status1 & priv->reg_bits[IMR1]) || + (status2 & (priv->reg_bits[IMR2] & IMR2_ENABLE_INTR_MASK)) || + nec7210_atn_has_changed(board, priv)) { + nec7210_update_status_nolock(board, priv); + dev_dbg(board->gpib_dev, "minor %i, stat %lx, isr1 0x%x, imr1 0x%x, isr2 0x%x, imr2 0x%x\n", + board->minor, board->status, status1, priv->reg_bits[IMR1], status2, + priv->reg_bits[IMR2]); + wake_up_interruptible(&board->wait); /* wake up sleeping process */ + retval = IRQ_HANDLED; + } + + return retval; +} +EXPORT_SYMBOL(nec7210_interrupt_have_status); + +void nec7210_board_reset(struct nec7210_priv *priv, const gpib_board_t *board) +{ + /* 7210 chip reset */ + write_byte(priv, AUX_CR, AUXMR); + + /* disable all interrupts */ + priv->reg_bits[IMR1] = 0; + write_byte(priv, priv->reg_bits[IMR1], IMR1); + priv->reg_bits[IMR2] = 0; + write_byte(priv, priv->reg_bits[IMR2], IMR2); + write_byte(priv, 0, SPMR); + + /* clear registers by reading */ + read_byte(priv, CPTR); + read_byte(priv, ISR1); + read_byte(priv, ISR2); + + /* parallel poll unconfigure */ + write_byte(priv, PPR | HR_PPU, AUXMR); + + priv->reg_bits[ADMR] = HR_TRM0 | HR_TRM1; + + priv->auxa_bits = AUXRA | HR_HLDA; + write_byte(priv, priv->auxa_bits, AUXMR); + + write_byte(priv, AUXRE | 0, AUXMR); + + /* set INT pin to active high, enable command pass through of unknown commands */ + priv->auxb_bits = AUXRB | HR_CPTE; + write_byte(priv, priv->auxb_bits, AUXMR); + write_byte(priv, AUXRE, AUXMR); +} +EXPORT_SYMBOL(nec7210_board_reset); + +void nec7210_board_online(struct nec7210_priv *priv, const gpib_board_t *board) +{ + /* set GPIB address */ + nec7210_primary_address(board, priv, board->pad); + nec7210_secondary_address(board, priv, board->sad, board->sad >= 0); + + // enable interrupts + priv->reg_bits[IMR1] = HR_ERRIE | HR_DECIE | HR_ENDIE | + HR_DETIE | HR_CPTIE | HR_DOIE | HR_DIIE; + priv->reg_bits[IMR2] = IMR2_ENABLE_INTR_MASK; + write_byte(priv, priv->reg_bits[IMR1], IMR1); + write_byte(priv, priv->reg_bits[IMR2], IMR2); + + write_byte(priv, AUX_PON, AUXMR); +} +EXPORT_SYMBOL(nec7210_board_online); + +#ifdef CONFIG_HAS_IOPORT +/* wrappers for io */ +uint8_t nec7210_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num) +{ + return inb((unsigned long)(priv->iobase) + register_num * priv->offset); +} +EXPORT_SYMBOL(nec7210_ioport_read_byte); + +void nec7210_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num) +{ + if (register_num == AUXMR) + /* locking makes absolutely sure noone accesses the + * AUXMR register faster than once per microsecond + */ + nec7210_locking_ioport_write_byte(priv, data, register_num); + else + outb(data, (unsigned long)(priv->iobase) + register_num * priv->offset); +} +EXPORT_SYMBOL(nec7210_ioport_write_byte); + +/* locking variants of io wrappers, for chips that page-in registers */ +uint8_t nec7210_locking_ioport_read_byte(struct nec7210_priv *priv, unsigned int register_num) +{ + u8 retval; + unsigned long flags; + + spin_lock_irqsave(&priv->register_page_lock, flags); + retval = inb((unsigned long)(priv->iobase) + register_num * priv->offset); + spin_unlock_irqrestore(&priv->register_page_lock, flags); + return retval; +} +EXPORT_SYMBOL(nec7210_locking_ioport_read_byte); + +void nec7210_locking_ioport_write_byte(struct nec7210_priv *priv, uint8_t data, + unsigned int register_num) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->register_page_lock, flags); + if (register_num == AUXMR) + udelay(1); + outb(data, (unsigned long)(priv->iobase) + register_num * priv->offset); + spin_unlock_irqrestore(&priv->register_page_lock, flags); +} +EXPORT_SYMBOL(nec7210_locking_ioport_write_byte); +#endif + +uint8_t nec7210_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num) +{ + return readb(priv->iobase + register_num * priv->offset); +} +EXPORT_SYMBOL(nec7210_iomem_read_byte); + +void nec7210_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, unsigned int register_num) +{ + if (register_num == AUXMR) + /* locking makes absolutely sure noone accesses the + * AUXMR register faster than once per microsecond + */ + nec7210_locking_iomem_write_byte(priv, data, register_num); + else + writeb(data, priv->iobase + register_num * priv->offset); +} +EXPORT_SYMBOL(nec7210_iomem_write_byte); + +uint8_t nec7210_locking_iomem_read_byte(struct nec7210_priv *priv, unsigned int register_num) +{ + u8 retval; + unsigned long flags; + + spin_lock_irqsave(&priv->register_page_lock, flags); + retval = readb(priv->iobase + register_num * priv->offset); + spin_unlock_irqrestore(&priv->register_page_lock, flags); + return retval; +} +EXPORT_SYMBOL(nec7210_locking_iomem_read_byte); + +void nec7210_locking_iomem_write_byte(struct nec7210_priv *priv, uint8_t data, + unsigned int register_num) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->register_page_lock, flags); + if (register_num == AUXMR) + udelay(1); + writeb(data, priv->iobase + register_num * priv->offset); + spin_unlock_irqrestore(&priv->register_page_lock, flags); +} +EXPORT_SYMBOL(nec7210_locking_iomem_write_byte); + +static int __init nec7210_init_module(void) +{ + return 0; +} + +static void __exit nec7210_exit_module(void) +{ +} + +module_init(nec7210_init_module); +module_exit(nec7210_exit_module); diff --git a/drivers/staging/gpib/ni_usb/Makefile b/drivers/staging/gpib/ni_usb/Makefile new file mode 100644 index 00000000000000..e22b3b21a62c6b --- /dev/null +++ b/drivers/staging/gpib/ni_usb/Makefile @@ -0,0 +1,4 @@ + +obj-m += ni_usb_gpib.o + + diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.c b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c new file mode 100644 index 00000000000000..b7b6fb1be37903 --- /dev/null +++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.c @@ -0,0 +1,2640 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * driver for National Instruments usb to gpib adapters + * copyright : (C) 2004 by Frank Mori Hess + ***************************************************************************/ + +#include +#include +#include +#include "ni_usb_gpib.h" +#include "gpibP.h" +#include "nec7210.h" +#include "tnt4882_registers.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for National Instruments USB devices"); + +#define MAX_NUM_NI_USB_INTERFACES 128 +static struct usb_interface *ni_usb_driver_interfaces[MAX_NUM_NI_USB_INTERFACES]; + +static int ni_usb_parse_status_block(const u8 *buffer, struct ni_usb_status_block *status); +static int ni_usb_set_interrupt_monitor(gpib_board_t *board, unsigned int monitored_bits); +static void ni_usb_stop(struct ni_usb_priv *ni_priv); + +static DEFINE_MUTEX(ni_usb_hotplug_lock); + +//calculates a reasonable timeout in that can be passed to usb functions +static inline unsigned long ni_usb_timeout_msecs(unsigned int usec) +{ + if (usec == 0) + return 0; + return 2000 + usec / 500; +}; + +// returns timeout code byte for use in ni-usb-b instructions +static unsigned short ni_usb_timeout_code(unsigned int usec) +{ + if (usec == 0) + return 0xf0; + else if (usec <= 10) + return 0xf1; + else if (usec <= 30) + return 0xf2; + else if (usec <= 100) + return 0xf3; + else if (usec <= 300) + return 0xf4; + else if (usec <= 1000) + return 0xf5; + else if (usec <= 3000) + return 0xf6; + else if (usec <= 10000) + return 0xf7; + else if (usec <= 30000) + return 0xf8; + else if (usec <= 100000) + return 0xf9; + else if (usec <= 300000) + return 0xfa; + else if (usec <= 1000000) + return 0xfb; + else if (usec <= 3000000) + return 0xfc; + else if (usec <= 10000000) + return 0xfd; + else if (usec <= 30000000) + return 0xfe; + else if (usec <= 100000000) + return 0xff; + else if (usec <= 300000000) + return 0x01; + /* NI driver actually uses 0xff for timeout T1000s, which is a bug in their code. + * I've verified on a usb-b that a code of 0x2 is correct for a 1000 sec timeout + */ + else if (usec <= 1000000000) + return 0x02; + pr_err("%s: bug? usec is greater than 1e9\n", __func__); + return 0xf0; +} + +static void ni_usb_bulk_complete(struct urb *urb) +{ + struct ni_usb_urb_ctx *context = urb->context; + +// printk("debug: %s: status=0x%x, error_count=%i, actual_length=%i\n", __func__, +// urb->status, urb->error_count, urb->actual_length); + up(&context->complete); +} + +static void ni_usb_timeout_handler(struct timer_list *t) +{ + struct ni_usb_priv *ni_priv = from_timer(ni_priv, t, bulk_timer); + struct ni_usb_urb_ctx *context = &ni_priv->context; + + context->timed_out = 1; + up(&context->complete); +}; + +// I'm using nonblocking loosely here, it only means -EAGAIN can be returned in certain cases +static int ni_usb_nonblocking_send_bulk_msg(struct ni_usb_priv *ni_priv, void *data, + int data_length, int *actual_data_length, + int timeout_msecs) +{ + struct usb_device *usb_dev; + int retval; + unsigned int out_pipe; + struct ni_usb_urb_ctx *context = &ni_priv->context; + + *actual_data_length = 0; + mutex_lock(&ni_priv->bulk_transfer_lock); + if (!ni_priv->bus_interface) { + mutex_unlock(&ni_priv->bulk_transfer_lock); + return -ENODEV; + } + if (ni_priv->bulk_urb) { + mutex_unlock(&ni_priv->bulk_transfer_lock); + return -EAGAIN; + } + ni_priv->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ni_priv->bulk_urb) { + mutex_unlock(&ni_priv->bulk_transfer_lock); + return -ENOMEM; + } + usb_dev = interface_to_usbdev(ni_priv->bus_interface); + out_pipe = usb_sndbulkpipe(usb_dev, ni_priv->bulk_out_endpoint); + sema_init(&context->complete, 0); + context->timed_out = 0; + usb_fill_bulk_urb(ni_priv->bulk_urb, usb_dev, out_pipe, data, data_length, + &ni_usb_bulk_complete, context); + + if (timeout_msecs) + mod_timer(&ni_priv->bulk_timer, jiffies + msecs_to_jiffies(timeout_msecs)); + + retval = usb_submit_urb(ni_priv->bulk_urb, GFP_KERNEL); + if (retval) { + del_timer_sync(&ni_priv->bulk_timer); + usb_free_urb(ni_priv->bulk_urb); + ni_priv->bulk_urb = NULL; + dev_err(&usb_dev->dev, "%s: failed to submit bulk out urb, retval=%i\n", + __func__, retval); + mutex_unlock(&ni_priv->bulk_transfer_lock); + return retval; + } + mutex_unlock(&ni_priv->bulk_transfer_lock); + down(&context->complete); // wait for ni_usb_bulk_complete + if (context->timed_out) { + usb_kill_urb(ni_priv->bulk_urb); + dev_err(&usb_dev->dev, "%s: killed urb due to timeout\n", __func__); + retval = -ETIMEDOUT; + } else { + retval = ni_priv->bulk_urb->status; + } + + del_timer_sync(&ni_priv->bulk_timer); + *actual_data_length = ni_priv->bulk_urb->actual_length; + mutex_lock(&ni_priv->bulk_transfer_lock); + usb_free_urb(ni_priv->bulk_urb); + ni_priv->bulk_urb = NULL; + mutex_unlock(&ni_priv->bulk_transfer_lock); + return retval; +} + +static int ni_usb_send_bulk_msg(struct ni_usb_priv *ni_priv, void *data, int data_length, + int *actual_data_length, int timeout_msecs) +{ + int retval; + int timeout_msecs_remaining = timeout_msecs; + + retval = ni_usb_nonblocking_send_bulk_msg(ni_priv, data, data_length, actual_data_length, + timeout_msecs_remaining); + while (retval == -EAGAIN && (timeout_msecs == 0 || timeout_msecs_remaining > 0)) { + usleep_range(1000, 1500); + retval = ni_usb_nonblocking_send_bulk_msg(ni_priv, data, data_length, + actual_data_length, + timeout_msecs_remaining); + if (timeout_msecs != 0) + --timeout_msecs_remaining; + } + if (timeout_msecs != 0 && timeout_msecs_remaining <= 0) + return -ETIMEDOUT; + return retval; +} + +// I'm using nonblocking loosely here, it only means -EAGAIN can be returned in certain cases +static int ni_usb_nonblocking_receive_bulk_msg(struct ni_usb_priv *ni_priv, + void *data, int data_length, + int *actual_data_length, int timeout_msecs, + int interruptible) +{ + struct usb_device *usb_dev; + int retval; + unsigned int in_pipe; + struct ni_usb_urb_ctx *context = &ni_priv->context; + + *actual_data_length = 0; + mutex_lock(&ni_priv->bulk_transfer_lock); + if (!ni_priv->bus_interface) { + mutex_unlock(&ni_priv->bulk_transfer_lock); + return -ENODEV; + } + if (ni_priv->bulk_urb) { + mutex_unlock(&ni_priv->bulk_transfer_lock); + return -EAGAIN; + } + ni_priv->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ni_priv->bulk_urb) { + mutex_unlock(&ni_priv->bulk_transfer_lock); + return -ENOMEM; + } + usb_dev = interface_to_usbdev(ni_priv->bus_interface); + in_pipe = usb_rcvbulkpipe(usb_dev, ni_priv->bulk_in_endpoint); + sema_init(&context->complete, 0); + context->timed_out = 0; + usb_fill_bulk_urb(ni_priv->bulk_urb, usb_dev, in_pipe, data, data_length, + &ni_usb_bulk_complete, context); + + if (timeout_msecs) + mod_timer(&ni_priv->bulk_timer, jiffies + msecs_to_jiffies(timeout_msecs)); + + //printk("%s: submitting urb\n", __func__); + retval = usb_submit_urb(ni_priv->bulk_urb, GFP_KERNEL); + if (retval) { + del_timer_sync(&ni_priv->bulk_timer); + usb_free_urb(ni_priv->bulk_urb); + ni_priv->bulk_urb = NULL; + dev_err(&usb_dev->dev, "%s: failed to submit bulk out urb, retval=%i\n", + __func__, retval); + mutex_unlock(&ni_priv->bulk_transfer_lock); + return retval; + } + mutex_unlock(&ni_priv->bulk_transfer_lock); + if (interruptible) { + if (down_interruptible(&context->complete)) { + /* If we got interrupted by a signal while + * waiting for the usb gpib to respond, we + * should send a stop command so it will + * finish up with whatever it was doing and + * send its response now. + */ + ni_usb_stop(ni_priv); + retval = -ERESTARTSYS; + /* now do an uninterruptible wait, it shouldn't take long + * for the board to respond now. + */ + down(&context->complete); + } + } else { + down(&context->complete); + } + if (context->timed_out) { + usb_kill_urb(ni_priv->bulk_urb); + dev_err(&usb_dev->dev, "%s: killed urb due to timeout\n", __func__); + retval = -ETIMEDOUT; + } else { + if (ni_priv->bulk_urb->status) + retval = ni_priv->bulk_urb->status; + } + del_timer_sync(&ni_priv->bulk_timer); + *actual_data_length = ni_priv->bulk_urb->actual_length; + mutex_lock(&ni_priv->bulk_transfer_lock); + usb_free_urb(ni_priv->bulk_urb); + ni_priv->bulk_urb = NULL; + mutex_unlock(&ni_priv->bulk_transfer_lock); + return retval; +} + +static int ni_usb_receive_bulk_msg(struct ni_usb_priv *ni_priv, void *data, + int data_length, int *actual_data_length, int timeout_msecs, + int interruptible) +{ + int retval; + int timeout_msecs_remaining = timeout_msecs; + + retval = ni_usb_nonblocking_receive_bulk_msg(ni_priv, data, data_length, + actual_data_length, timeout_msecs_remaining, + interruptible); + while (retval == -EAGAIN && (timeout_msecs == 0 || timeout_msecs_remaining > 0)) { + usleep_range(1000, 1500); + retval = ni_usb_nonblocking_receive_bulk_msg(ni_priv, data, data_length, + actual_data_length, + timeout_msecs_remaining, + interruptible); + if (timeout_msecs != 0) + --timeout_msecs_remaining; + } + if (timeout_msecs && timeout_msecs_remaining <= 0) + return -ETIMEDOUT; + return retval; +} + +static int ni_usb_receive_control_msg(struct ni_usb_priv *ni_priv, __u8 request, + __u8 requesttype, __u16 value, __u16 index, + void *data, __u16 size, int timeout_msecs) +{ + struct usb_device *usb_dev; + int retval; + unsigned int in_pipe; + + mutex_lock(&ni_priv->control_transfer_lock); + if (!ni_priv->bus_interface) { + mutex_unlock(&ni_priv->control_transfer_lock); + return -ENODEV; + } + usb_dev = interface_to_usbdev(ni_priv->bus_interface); + in_pipe = usb_rcvctrlpipe(usb_dev, 0); + retval = usb_control_msg(usb_dev, in_pipe, request, requesttype, value, index, data, + size, timeout_msecs); + mutex_unlock(&ni_priv->control_transfer_lock); + return retval; +} + +static void ni_usb_soft_update_status(gpib_board_t *board, unsigned int ni_usb_ibsta, + unsigned int clear_mask) +{ + static const unsigned int ni_usb_ibsta_mask = SRQI | ATN | CIC | REM | LACS | TACS | LOK; + + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + unsigned int need_monitoring_bits = ni_usb_ibsta_monitor_mask; + unsigned long flags; + + board->status &= ~clear_mask; + board->status &= ~ni_usb_ibsta_mask; + board->status |= ni_usb_ibsta & ni_usb_ibsta_mask; + //FIXME should generate events on DTAS and DCAS + + spin_lock_irqsave(&board->spinlock, flags); +/* remove set status bits from monitored set why ?***/ + ni_priv->monitored_ibsta_bits &= ~ni_usb_ibsta; + need_monitoring_bits &= ~ni_priv->monitored_ibsta_bits; /* mm - monitored set */ + spin_unlock_irqrestore(&board->spinlock, flags); + dev_dbg(&usb_dev->dev, "%s: need_monitoring_bits=0x%x\n", __func__, need_monitoring_bits); + + if (need_monitoring_bits & ~ni_usb_ibsta) + ni_usb_set_interrupt_monitor(board, ni_usb_ibsta_monitor_mask); + else if (need_monitoring_bits & ni_usb_ibsta) + wake_up_interruptible(&board->wait); + + dev_dbg(&usb_dev->dev, "%s: ni_usb_ibsta=0x%x\n", __func__, ni_usb_ibsta); +} + +static int ni_usb_parse_status_block(const u8 *buffer, struct ni_usb_status_block *status) +{ + u16 count; + + status->id = buffer[0]; + status->ibsta = (buffer[1] << 8) | buffer[2]; + status->error_code = buffer[3]; + count = buffer[4] | (buffer[5] << 8); + count = ~count; + count++; + status->count = count; + return 8; +}; + +static void ni_usb_dump_raw_block(const u8 *raw_data, int length) +{ + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 8, 1, raw_data, length, true); +} + +static int ni_usb_parse_register_read_block(const u8 *raw_data, unsigned int *results, + int num_results) +{ + int i = 0; + int j; + int unexpected = 0; + static const int results_per_chunk = 3; + + for (j = 0; j < num_results;) { + int k; + + if (raw_data[i++] != NIUSB_REGISTER_READ_DATA_START_ID) { + pr_err("%s: parse error: wrong start id\n", __func__); + unexpected = 1; + } + for (k = 0; k < results_per_chunk && j < num_results; ++k) + results[j++] = raw_data[i++]; + } + while (i % 4) + i++; + if (raw_data[i++] != NIUSB_REGISTER_READ_DATA_END_ID) { + pr_err("%s: parse error: wrong end id\n", __func__); + unexpected = 1; + } + if (raw_data[i++] % results_per_chunk != num_results % results_per_chunk) { + pr_err("%s: parse error: wrong count=%i for NIUSB_REGISTER_READ_DATA_END\n", + __func__, (int)raw_data[i - 1]); + unexpected = 1; + } + while (i % 4) { + if (raw_data[i++] != 0) { + pr_err("%s: unexpected data: raw_data[%i]=0x%x, expected 0\n", + __func__, i - 1, (int)raw_data[i - 1]); + unexpected = 1; + } + } + if (unexpected) + ni_usb_dump_raw_block(raw_data, i); + return i; +} + +static int ni_usb_parse_termination_block(const u8 *buffer) +{ + int i = 0; + + if (buffer[i++] != NIUSB_TERM_ID || + buffer[i++] != 0x0 || + buffer[i++] != 0x0 || + buffer[i++] != 0x0) { + pr_err("%s: received unexpected termination block\n", __func__); + pr_err(" expected: 0x%x 0x%x 0x%x 0x%x\n", + NIUSB_TERM_ID, 0x0, 0x0, 0x0); + pr_err(" received: 0x%x 0x%x 0x%x 0x%x\n", + buffer[i - 4], buffer[i - 3], buffer[i - 2], buffer[i - 1]); + } + return i; +}; + +static int parse_board_ibrd_readback(const u8 *raw_data, struct ni_usb_status_block *status, + u8 *parsed_data, int parsed_data_length, + int *actual_bytes_read) +{ + static const int ibrd_data_block_length = 0xf; + static const int ibrd_extended_data_block_length = 0x1e; + int data_block_length = 0; + int i = 0; + int j = 0; + int k; + unsigned int adr1_bits; + int num_data_blocks = 0; + struct ni_usb_status_block register_write_status; + int unexpected = 0; + + while (raw_data[i] == NIUSB_IBRD_DATA_ID || raw_data[i] == NIUSB_IBRD_EXTENDED_DATA_ID) { + if (raw_data[i] == NIUSB_IBRD_DATA_ID) { + data_block_length = ibrd_data_block_length; + } else if (raw_data[i] == NIUSB_IBRD_EXTENDED_DATA_ID) { + data_block_length = ibrd_extended_data_block_length; + if (raw_data[++i] != 0) { + pr_err("%s: unexpected data: raw_data[%i]=0x%x, expected 0\n", + __func__, i, (int)raw_data[i]); + unexpected = 1; + } + } else { + pr_err("%s: logic bug!\n", __func__); + return -EINVAL; + } + ++i; + for (k = 0; k < data_block_length; k++) { + if (j < parsed_data_length) + parsed_data[j++] = raw_data[i++]; + else + ++i; + } + ++num_data_blocks; + } + i += ni_usb_parse_status_block(&raw_data[i], status); + if (status->id != NIUSB_IBRD_STATUS_ID) { + pr_err("%s: bug: status->id=%i, != ibrd_status_id\n", __func__, status->id); + return -EIO; + } + adr1_bits = raw_data[i++]; + if (num_data_blocks) { + *actual_bytes_read = (num_data_blocks - 1) * data_block_length + raw_data[i++]; + } else { + ++i; + *actual_bytes_read = 0; + } + if (*actual_bytes_read > j) + pr_err("%s: bug: discarded data. actual_bytes_read=%i, j=%i\n", + __func__, *actual_bytes_read, j); + for (k = 0; k < 2; k++) + if (raw_data[i++] != 0) { + pr_err("%s: unexpected data: raw_data[%i]=0x%x, expected 0\n", + __func__, i - 1, (int)raw_data[i - 1]); + unexpected = 1; + } + i += ni_usb_parse_status_block(&raw_data[i], ®ister_write_status); + if (register_write_status.id != NIUSB_REG_WRITE_ID) { + pr_err("%s: unexpected data: register write status id=0x%x, expected 0x%x\n", + __func__, register_write_status.id, NIUSB_REG_WRITE_ID); + unexpected = 1; + } + if (raw_data[i++] != 2) { + pr_err("%s: unexpected data: register write count=%i, expected 2\n", + __func__, (int)raw_data[i - 1]); + unexpected = 1; + } + for (k = 0; k < 3; k++) + if (raw_data[i++] != 0) { + pr_err("%s: unexpected data: raw_data[%i]=0x%x, expected 0\n", + __func__, i - 1, (int)raw_data[i - 1]); + unexpected = 1; + } + i += ni_usb_parse_termination_block(&raw_data[i]); + if (unexpected) + ni_usb_dump_raw_block(raw_data, i); + return i; +} + +static int ni_usb_parse_reg_write_status_block(const u8 *raw_data, + struct ni_usb_status_block *status, + int *writes_completed) +{ + int i = 0; + + i += ni_usb_parse_status_block(raw_data, status); + *writes_completed = raw_data[i++]; + while (i % 4) + i++; + return i; +} + +static int ni_usb_write_registers(struct ni_usb_priv *ni_priv, + const struct ni_usb_register *writes, int num_writes, + unsigned int *ibsta) +{ + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int retval; + u8 *out_data, *in_data; + int out_data_length; + static const int in_data_length = 0x20; + int bytes_written = 0, bytes_read = 0; + int i = 0; + int j; + struct ni_usb_status_block status; + static const int bytes_per_write = 3; + int reg_writes_completed; + + out_data_length = num_writes * bytes_per_write + 0x10; + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) { + dev_err(&usb_dev->dev, "%s: kmalloc failed\n", __func__); + return -ENOMEM; + } + i += ni_usb_bulk_register_write_header(&out_data[i], num_writes); + for (j = 0; j < num_writes; j++) + i += ni_usb_bulk_register_write(&out_data[i], writes[j]); + while (i % 4) + out_data[i++] = 0x00; + i += ni_usb_bulk_termination(&out_data[i]); + if (i > out_data_length) + dev_err(&usb_dev->dev, "%s: bug! buffer overrun\n", __func__); + + mutex_lock(&ni_priv->addressed_transfer_lock); + + retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000); + kfree(out_data); + if (retval) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + return retval; + } + + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: kmalloc failed\n", __func__); + return -ENOMEM; + } + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 0); + if (retval || bytes_read != 16) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + ni_usb_dump_raw_block(in_data, bytes_read); + kfree(in_data); + return retval; + } + + mutex_unlock(&ni_priv->addressed_transfer_lock); + + ni_usb_parse_reg_write_status_block(in_data, &status, ®_writes_completed); + //FIXME parse extra 09 status bits and termination + kfree(in_data); + if (status.id != NIUSB_REG_WRITE_ID) { + dev_err(&usb_dev->dev, "%s: parse error, id=0x%x != NIUSB_REG_WRITE_ID\n", + __func__, status.id); + return -EIO; + } + if (status.error_code) { + dev_err(&usb_dev->dev, "%s: nonzero error code 0x%x\n", + __func__, status.error_code); + return -EIO; + } + if (reg_writes_completed != num_writes) { + dev_err(&usb_dev->dev, "%s: reg_writes_completed=%i, num_writes=%i\n", + __func__, reg_writes_completed, num_writes); + return -EIO; + } + if (ibsta) + *ibsta = status.ibsta; + return 0; +} + +// interface functions +static int ni_usb_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read) +{ + int retval, parse_retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + u8 *out_data, *in_data; + static const int out_data_length = 0x20; + int in_data_length; + int usb_bytes_written = 0, usb_bytes_read = 0; + int i = 0; + int complement_count; + int actual_length; + struct ni_usb_status_block status; + static const int max_read_length = 0xffff; + struct ni_usb_register reg; + + *bytes_read = 0; + if (length > max_read_length) { + length = max_read_length; + dev_err(&usb_dev->dev, "%s: read length too long\n", __func__); + } + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + out_data[i++] = 0x0a; + out_data[i++] = ni_priv->eos_mode >> 8; + out_data[i++] = ni_priv->eos_char; + out_data[i++] = ni_usb_timeout_code(board->usec_timeout); + complement_count = length - 1; + complement_count = ~complement_count; + out_data[i++] = complement_count & 0xff; + out_data[i++] = (complement_count >> 8) & 0xff; + out_data[i++] = 0x0; + out_data[i++] = 0x0; + i += ni_usb_bulk_register_write_header(&out_data[i], 2); + reg.device = NIUSB_SUBDEV_TNT4882; + reg.address = nec7210_to_tnt4882_offset(AUXMR); + reg.value = AUX_HLDI; + i += ni_usb_bulk_register_write(&out_data[i], reg); + reg.value = AUX_CLEAR_END; + i += ni_usb_bulk_register_write(&out_data[i], reg); + while (i % 4) // pad with zeros to 4-byte boundary + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + + mutex_lock(&ni_priv->addressed_transfer_lock); + + retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &usb_bytes_written, 1000); + kfree(out_data); + if (retval || usb_bytes_written != i) { + if (retval == 0) + retval = -EIO; + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, usb_bytes_written=%i, i=%i\n", + __func__, retval, usb_bytes_written, i); + mutex_unlock(&ni_priv->addressed_transfer_lock); + return retval; + } + + in_data_length = (length / 30 + 1) * 0x20 + 0x20; + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + return -ENOMEM; + } + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &usb_bytes_read, + ni_usb_timeout_msecs(board->usec_timeout), 1); + + mutex_unlock(&ni_priv->addressed_transfer_lock); + + if (retval == -ERESTARTSYS) { + } else if (retval) { + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, usb_bytes_read=%i\n", + __func__, retval, usb_bytes_read); + kfree(in_data); + return retval; + } + parse_retval = parse_board_ibrd_readback(in_data, &status, buffer, length, &actual_length); + if (parse_retval != usb_bytes_read) { + if (parse_retval >= 0) + parse_retval = -EIO; + dev_err(&usb_dev->dev, "%s: retval=%i usb_bytes_read=%i\n", + __func__, parse_retval, usb_bytes_read); + kfree(in_data); + return parse_retval; + } + if (actual_length != length - status.count) { + dev_err(&usb_dev->dev, "%s: actual_length=%i expected=%li\n", + __func__, actual_length, (long)(length - status.count)); + ni_usb_dump_raw_block(in_data, usb_bytes_read); + } + kfree(in_data); + switch (status.error_code) { + case NIUSB_NO_ERROR: + retval = 0; + break; + case NIUSB_ABORTED_ERROR: + /* this is expected if ni_usb_receive_bulk_msg got + * interrupted by a signal and returned -ERESTARTSYS + */ + break; + case NIUSB_ATN_STATE_ERROR: + retval = -EIO; + dev_err(&usb_dev->dev, "%s: read when ATN set\n", __func__); + break; + case NIUSB_ADDRESSING_ERROR: + retval = -EIO; + break; + case NIUSB_TIMEOUT_ERROR: + retval = -ETIMEDOUT; + break; + case NIUSB_EOSMODE_ERROR: + dev_err(&usb_dev->dev, "%s: driver bug, we should have been able to avoid NIUSB_EOSMODE_ERROR.\n", + __func__); + retval = -EINVAL; + break; + default: + dev_err(&usb_dev->dev, "%s: unknown error code=%i\n", __func__, status.error_code); + retval = -EIO; + break; + } + ni_usb_soft_update_status(board, status.ibsta, 0); + if (status.ibsta & END) + *end = 1; + else + *end = 0; + *bytes_read = actual_length; + return retval; +} + +static int ni_usb_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + u8 *out_data, *in_data; + int out_data_length; + static const int in_data_length = 0x10; + int usb_bytes_written = 0, usb_bytes_read = 0; + int i = 0, j; + int complement_count; + struct ni_usb_status_block status; + static const int max_write_length = 0xffff; + + *bytes_written = 0; + if (length > max_write_length) { + length = max_write_length; + send_eoi = 0; + dev_err(&usb_dev->dev, "%s: write length too long\n", __func__); + } + out_data_length = length + 0x10; + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + out_data[i++] = 0x0d; + complement_count = length - 1; + complement_count = ~complement_count; + out_data[i++] = complement_count & 0xff; + out_data[i++] = (complement_count >> 8) & 0xff; + out_data[i++] = ni_usb_timeout_code(board->usec_timeout); + out_data[i++] = 0x0; + out_data[i++] = 0x0; + if (send_eoi) + out_data[i++] = 0x8; + else + out_data[i++] = 0x0; + out_data[i++] = 0x0; + for (j = 0; j < length; j++) + out_data[i++] = buffer[j]; + while (i % 4) // pad with zeros to 4-byte boundary + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + + mutex_lock(&ni_priv->addressed_transfer_lock); + + retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &usb_bytes_written, + ni_usb_timeout_msecs(board->usec_timeout)); + kfree(out_data); + if (retval || usb_bytes_written != i) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, usb_bytes_written=%i, i=%i\n", + __func__, retval, usb_bytes_written, i); + return retval; + } + + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) + return -ENOMEM; + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &usb_bytes_read, + ni_usb_timeout_msecs(board->usec_timeout), 1); + + mutex_unlock(&ni_priv->addressed_transfer_lock); + + if ((retval && retval != -ERESTARTSYS) || usb_bytes_read != 12) { + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, usb_bytes_read=%i\n", + __func__, retval, usb_bytes_read); + kfree(in_data); + return retval; + } + ni_usb_parse_status_block(in_data, &status); + kfree(in_data); + switch (status.error_code) { + case NIUSB_NO_ERROR: + retval = 0; + break; + case NIUSB_ABORTED_ERROR: + /* this is expected if ni_usb_receive_bulk_msg got + * interrupted by a signal and returned -ERESTARTSYS + */ + break; + case NIUSB_ADDRESSING_ERROR: + dev_err(&usb_dev->dev, "%s: Addressing error retval %d error code=%i\n", + __func__, retval, status.error_code); + retval = -ENXIO; + break; + case NIUSB_NO_LISTENER_ERROR: + retval = -ECOMM; + break; + case NIUSB_TIMEOUT_ERROR: + retval = -ETIMEDOUT; + break; + default: + dev_err(&usb_dev->dev, "%s: unknown error code=%i\n", + __func__, status.error_code); + retval = -EPIPE; + break; + } + ni_usb_soft_update_status(board, status.ibsta, 0); + *bytes_written = length - status.count; + return retval; +} + +static int ni_usb_command_chunk(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *command_bytes_written) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + u8 *out_data, *in_data; + int out_data_length; + static const int in_data_length = 0x10; + int bytes_written = 0, bytes_read = 0; + int i = 0, j; + unsigned int complement_count; + struct ni_usb_status_block status; + // usb-b gives error 4 if you try to send more than 16 command bytes at once + static const int max_command_length = 0x10; + + *command_bytes_written = 0; + if (length > max_command_length) + length = max_command_length; + out_data_length = length + 0x10; + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + out_data[i++] = 0x0c; + complement_count = length - 1; + complement_count = ~complement_count; + out_data[i++] = complement_count; + out_data[i++] = 0x0; + out_data[i++] = ni_usb_timeout_code(board->usec_timeout); + for (j = 0; j < length; j++) + out_data[i++] = buffer[j]; + while (i % 4) // pad with zeros to 4-byte boundary + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + + mutex_lock(&ni_priv->addressed_transfer_lock); + + retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, + ni_usb_timeout_msecs(board->usec_timeout)); + kfree(out_data); + if (retval || bytes_written != i) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + return retval; + } + + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + return -ENOMEM; + } + + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, + ni_usb_timeout_msecs(board->usec_timeout), 1); + + mutex_unlock(&ni_priv->addressed_transfer_lock); + + if ((retval && retval != -ERESTARTSYS) || bytes_read != 12) { + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + kfree(in_data); + return retval; + } + ni_usb_parse_status_block(in_data, &status); + kfree(in_data); + *command_bytes_written = length - status.count; + switch (status.error_code) { + case NIUSB_NO_ERROR: + break; + case NIUSB_ABORTED_ERROR: + /* this is expected if ni_usb_receive_bulk_msg got + * interrupted by a signal and returned -ERESTARTSYS + */ + break; + case NIUSB_NO_BUS_ERROR: + return -ENOTCONN; + case NIUSB_EOSMODE_ERROR: + dev_err(&usb_dev->dev, "%s: got eosmode error. Driver bug?\n", __func__); + return -EIO; + case NIUSB_TIMEOUT_ERROR: + return -ETIMEDOUT; + default: + dev_err(&usb_dev->dev, "%s: unknown error code=%i\n", __func__, status.error_code); + return -EIO; + } + ni_usb_soft_update_status(board, status.ibsta, 0); + return 0; +} + +static int ni_usb_command(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written) +{ + size_t count; + int retval; + + *bytes_written = 0; + while (*bytes_written < length) { + retval = ni_usb_command_chunk(board, buffer + *bytes_written, + length - *bytes_written, &count); + *bytes_written += count; + if (retval < 0) + return retval; + } + return 0; +} + +static int ni_usb_take_control(gpib_board_t *board, int synchronous) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + u8 *out_data, *in_data; + static const int out_data_length = 0x10; + static const int in_data_length = 0x10; + int bytes_written = 0, bytes_read = 0; + int i = 0; + struct ni_usb_status_block status; + + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + out_data[i++] = NIUSB_IBCAC_ID; + if (synchronous) + out_data[i++] = 0x1; + else + out_data[i++] = 0x0; + out_data[i++] = 0x0; + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + + mutex_lock(&ni_priv->addressed_transfer_lock); + + retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000); + kfree(out_data); + if (retval || bytes_written != i) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + return retval; + } + + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: kmalloc failed\n", __func__); + return -ENOMEM; + } + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 1); + + mutex_unlock(&ni_priv->addressed_transfer_lock); + + if ((retval && retval != -ERESTARTSYS) || bytes_read != 12) { + if (retval == 0) + retval = -EIO; + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + kfree(in_data); + return retval; + } + ni_usb_parse_status_block(in_data, &status); + kfree(in_data); + ni_usb_soft_update_status(board, status.ibsta, 0); + return retval; +} + +static int ni_usb_go_to_standby(gpib_board_t *board) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + u8 *out_data, *in_data; + static const int out_data_length = 0x10; + static const int in_data_length = 0x20; + int bytes_written = 0, bytes_read = 0; + int i = 0; + struct ni_usb_status_block status; + + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + + out_data[i++] = NIUSB_IBGTS_ID; + out_data[i++] = 0x0; + out_data[i++] = 0x0; + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + + mutex_lock(&ni_priv->addressed_transfer_lock); + + retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000); + kfree(out_data); + if (retval || bytes_written != i) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + return retval; + } + + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: kmalloc failed\n", __func__); + return -ENOMEM; + } + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 0); + + mutex_unlock(&ni_priv->addressed_transfer_lock); + + if (retval || bytes_read != 12) { + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + kfree(in_data); + return retval; + } + ni_usb_parse_status_block(in_data, &status); + kfree(in_data); + if (status.id != NIUSB_IBGTS_ID) + dev_err(&usb_dev->dev, "%s: bug: status.id 0x%x != INUSB_IBGTS_ID\n", + __func__, status.id); + ni_usb_soft_update_status(board, status.ibsta, 0); + return 0; +} + +static void ni_usb_request_system_control(gpib_board_t *board, int request_control) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int i = 0; + struct ni_usb_register writes[4]; + unsigned int ibsta; + + if (request_control) { + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = CMDR; + writes[i].value = SETSC; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_CIFC; + i++; + } else { + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_CREN; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_CIFC; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_DSC; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = CMDR; + writes[i].value = CLRSC; + i++; + } + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return; // retval; + } + if (!request_control) + ni_priv->ren_state = 0; + ni_usb_soft_update_status(board, ibsta, 0); + return; // 0; +} + +//FIXME maybe the interface should have a "pulse interface clear" function that can return an error? +static void ni_usb_interface_clear(gpib_board_t *board, int assert) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + u8 *out_data, *in_data; + static const int out_data_length = 0x10; + static const int in_data_length = 0x10; + int bytes_written = 0, bytes_read = 0; + int i = 0; + struct ni_usb_status_block status; + + // FIXME: we are going to pulse when assert is true, and ignore otherwise + if (assert == 0) + return; + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) { + dev_err(&usb_dev->dev, "%s: kmalloc failed\n", __func__); + return; + } + out_data[i++] = NIUSB_IBSIC_ID; + out_data[i++] = 0x0; + out_data[i++] = 0x0; + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000); + kfree(out_data); + if (retval || bytes_written != i) { + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + return; + } + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) + return; + + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 0); + if (retval || bytes_read != 12) { + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + kfree(in_data); + return; + } + ni_usb_parse_status_block(in_data, &status); + kfree(in_data); + ni_usb_soft_update_status(board, status.ibsta, 0); +} + +static void ni_usb_remote_enable(gpib_board_t *board, int enable) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + struct ni_usb_register reg; + unsigned int ibsta; + + reg.device = NIUSB_SUBDEV_TNT4882; + reg.address = nec7210_to_tnt4882_offset(AUXMR); + if (enable) + reg.value = AUX_SREN; + else + reg.value = AUX_CREN; + retval = ni_usb_write_registers(ni_priv, ®, 1, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return; //retval; + } + ni_priv->ren_state = enable; + ni_usb_soft_update_status(board, ibsta, 0); + return;// 0; +} + +static int ni_usb_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct ni_usb_priv *ni_priv = board->private_data; + + ni_priv->eos_char = eos_byte; + ni_priv->eos_mode |= REOS; + if (compare_8_bits) + ni_priv->eos_mode |= BIN; + else + ni_priv->eos_mode &= ~BIN; + return 0; +} + +static void ni_usb_disable_eos(gpib_board_t *board) +{ + struct ni_usb_priv *ni_priv = board->private_data; + /* adapter gets unhappy if you don't zero all the bits + * for the eos mode and eos char (returns error 4 on reads). + */ + ni_priv->eos_mode = 0; + ni_priv->eos_char = 0; +} + +static unsigned int ni_usb_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + static const int buffer_length = 8; + u8 *buffer; + struct ni_usb_status_block status; + + //printk("%s: receive control pipe is %i\n", __func__, pipe); + buffer = kmalloc(buffer_length, GFP_KERNEL); + if (!buffer) + return board->status; + + retval = ni_usb_receive_control_msg(ni_priv, NI_USB_WAIT_REQUEST, USB_DIR_IN | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x200, 0x0, buffer, buffer_length, 1000); + if (retval != buffer_length) { + dev_err(&usb_dev->dev, "%s: usb_control_msg returned %i\n", __func__, retval); + kfree(buffer); + return board->status; + } + ni_usb_parse_status_block(buffer, &status); + kfree(buffer); + ni_usb_soft_update_status(board, status.ibsta, clear_mask); + return board->status; +} + +// tells ni-usb to immediately stop an ongoing i/o operation +static void ni_usb_stop(struct ni_usb_priv *ni_priv) +{ + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int retval; + static const int buffer_length = 8; + u8 *buffer; + struct ni_usb_status_block status; + + //printk("%s: receive control pipe is %i\n", __func__, pipe); + buffer = kmalloc(buffer_length, GFP_KERNEL); + if (!buffer) + return; + + retval = ni_usb_receive_control_msg(ni_priv, NI_USB_STOP_REQUEST, USB_DIR_IN | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0, 0x0, buffer, buffer_length, 1000); + if (retval != buffer_length) { + dev_err(&usb_dev->dev, "%s: usb_control_msg returned %i\n", __func__, retval); + kfree(buffer); + return; + } + ni_usb_parse_status_block(buffer, &status); + kfree(buffer); +} + +static int ni_usb_primary_address(gpib_board_t *board, unsigned int address) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int i = 0; + struct ni_usb_register writes[2]; + unsigned int ibsta; + + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(ADR); + writes[i].value = address; + i++; + writes[i].device = NIUSB_SUBDEV_UNKNOWN2; + writes[i].address = 0x0; + writes[i].value = address; + i++; + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return retval; + } + ni_usb_soft_update_status(board, ibsta, 0); + return 0; +} + +static int ni_usb_write_sad(struct ni_usb_register *writes, int address, int enable) +{ + unsigned int adr_bits, admr_bits; + int i = 0; + + adr_bits = HR_ARS; + admr_bits = HR_TRM0 | HR_TRM1; + if (enable) { + adr_bits |= address; + admr_bits |= HR_ADM1; + } else { + adr_bits |= HR_DT | HR_DL; + admr_bits |= HR_ADM0; + } + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(ADR); + writes[i].value = adr_bits; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(ADMR); + writes[i].value = admr_bits; + i++; + writes[i].device = NIUSB_SUBDEV_UNKNOWN2; + writes[i].address = 0x1; + writes[i].value = enable ? MSA(address) : 0x0; + i++; + return i; +} + +static int ni_usb_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int i = 0; + struct ni_usb_register writes[3]; + unsigned int ibsta; + + i += ni_usb_write_sad(writes, address, enable); + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return retval; + } + ni_usb_soft_update_status(board, ibsta, 0); + return 0; +} + +static int ni_usb_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + u8 *out_data, *in_data; + static const int out_data_length = 0x10; + static const int in_data_length = 0x20; + int bytes_written = 0, bytes_read = 0; + int i = 0; + int j = 0; + struct ni_usb_status_block status; + + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + + out_data[i++] = NIUSB_IBRPP_ID; + out_data[i++] = 0xf0; //FIXME: this should be the parallel poll timeout code + out_data[i++] = 0x0; + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + /*FIXME: 1000 should use parallel poll timeout (not supported yet)*/ + retval = ni_usb_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000); + + kfree(out_data); + if (retval || bytes_written != i) { + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + return retval; + } + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) + return -ENOMEM; + + /*FIXME: should use parallel poll timeout (not supported yet)*/ + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, + &bytes_read, 1000, 1); + + if (retval && retval != -ERESTARTSYS) { + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + kfree(in_data); + return retval; + } + j += ni_usb_parse_status_block(in_data, &status); + *result = in_data[j++]; + kfree(in_data); + ni_usb_soft_update_status(board, status.ibsta, 0); + return retval; +} + +static void ni_usb_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int i = 0; + struct ni_usb_register writes[1]; + unsigned int ibsta; + + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = PPR | config; + i++; + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return;// retval; + } + ni_usb_soft_update_status(board, ibsta, 0); + return;// 0; +} + +static void ni_usb_parallel_poll_response(gpib_board_t *board, int ist) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int i = 0; + struct ni_usb_register writes[1]; + unsigned int ibsta; + + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + if (ist) + writes[i].value = AUX_SPPF; + else + writes[i].value = AUX_CPPF; + i++; + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return;// retval; + } + ni_usb_soft_update_status(board, ibsta, 0); + return;// 0; +} + +static void ni_usb_serial_poll_response(gpib_board_t *board, u8 status) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int i = 0; + struct ni_usb_register writes[1]; + unsigned int ibsta; + + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(SPMR); + writes[i].value = status; + i++; + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return;// retval; + } + ni_usb_soft_update_status(board, ibsta, 0); + return;// 0; +} + +static uint8_t ni_usb_serial_poll_status(gpib_board_t *board) +{ + return 0; +} + +static void ni_usb_return_to_local(gpib_board_t *board) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int i = 0; + struct ni_usb_register writes[1]; + unsigned int ibsta; + + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_RTL; + i++; + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return;// retval; + } + ni_usb_soft_update_status(board, ibsta, 0); + return;// 0; +} + +static int ni_usb_line_status(const gpib_board_t *board) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + u8 *out_data, *in_data; + static const int out_data_length = 0x20; + static const int in_data_length = 0x20; + int bytes_written = 0, bytes_read = 0; + int i = 0; + unsigned int bsr_bits; + int line_status = ValidALL; + // NI windows driver reads 0xd(HSSEL), 0xc (ARD0), 0x1f (BSR) + + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) + return -ENOMEM; + + /* line status gets called during ibwait */ + retval = mutex_trylock(&ni_priv->addressed_transfer_lock); + + if (retval == 0) { + kfree(out_data); + return -EBUSY; + } + i += ni_usb_bulk_register_read_header(&out_data[i], 1); + i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_TNT4882, BSR); + while (i % 4) + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + retval = ni_usb_nonblocking_send_bulk_msg(ni_priv, out_data, i, &bytes_written, 1000); + kfree(out_data); + if (retval || bytes_written != i) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + if (retval != -EAGAIN) + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, bytes_written=%i, i=%i\n", + __func__, retval, bytes_written, i); + return retval; + } + + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) { + mutex_unlock(&ni_priv->addressed_transfer_lock); + dev_err(&usb_dev->dev, "%s: kmalloc failed\n", __func__); + return -ENOMEM; + } + retval = ni_usb_nonblocking_receive_bulk_msg(ni_priv, in_data, in_data_length, + &bytes_read, 1000, 0); + + mutex_unlock(&ni_priv->addressed_transfer_lock); + + if (retval) { + if (retval != -EAGAIN) + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + kfree(in_data); + return retval; + } + + ni_usb_parse_register_read_block(in_data, &bsr_bits, 1); + kfree(in_data); + if (bsr_bits & BCSR_REN_BIT) + line_status |= BusREN; + if (bsr_bits & BCSR_IFC_BIT) + line_status |= BusIFC; + if (bsr_bits & BCSR_SRQ_BIT) + line_status |= BusSRQ; + if (bsr_bits & BCSR_EOI_BIT) + line_status |= BusEOI; + if (bsr_bits & BCSR_NRFD_BIT) + line_status |= BusNRFD; + if (bsr_bits & BCSR_NDAC_BIT) + line_status |= BusNDAC; + if (bsr_bits & BCSR_DAV_BIT) + line_status |= BusDAV; + if (bsr_bits & BCSR_ATN_BIT) + line_status |= BusATN; + return line_status; +} + +static int ni_usb_setup_t1_delay(struct ni_usb_register *reg, unsigned int nano_sec, + unsigned int *actual_ns) +{ + int i = 0; + + *actual_ns = 2000; + + reg[i].device = NIUSB_SUBDEV_TNT4882; + reg[i].address = nec7210_to_tnt4882_offset(AUXMR); + if (nano_sec <= 1100) { + reg[i].value = AUXRI | USTD | SISB; + *actual_ns = 1100; + } else { + reg[i].value = AUXRI | SISB; + } + i++; + reg[i].device = NIUSB_SUBDEV_TNT4882; + reg[i].address = nec7210_to_tnt4882_offset(AUXMR); + if (nano_sec <= 500) { + reg[i].value = AUXRB | HR_TRI; + *actual_ns = 500; + } else { + reg[i].value = AUXRB; + } + i++; + reg[i].device = NIUSB_SUBDEV_TNT4882; + reg[i].address = KEYREG; + if (nano_sec <= 350) { + reg[i].value = MSTD; + *actual_ns = 350; + } else { + reg[i].value = 0x0; + } + i++; + return i; +} + +static unsigned int ni_usb_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + struct ni_usb_register writes[3]; + unsigned int ibsta; + unsigned int actual_ns; + int i; + + i = ni_usb_setup_t1_delay(writes, nano_sec, &actual_ns); + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return -1; //FIXME should change return type to int for error reporting + } + board->t1_nano_sec = actual_ns; + ni_usb_soft_update_status(board, ibsta, 0); + return actual_ns; +} + +static int ni_usb_allocate_private(gpib_board_t *board) +{ + struct ni_usb_priv *ni_priv; + + board->private_data = kmalloc(sizeof(struct ni_usb_priv), GFP_KERNEL); + if (!board->private_data) + return -ENOMEM; + ni_priv = board->private_data; + memset(ni_priv, 0, sizeof(struct ni_usb_priv)); + mutex_init(&ni_priv->bulk_transfer_lock); + mutex_init(&ni_priv->control_transfer_lock); + mutex_init(&ni_priv->interrupt_transfer_lock); + mutex_init(&ni_priv->addressed_transfer_lock); + return 0; +} + +static void ni_usb_free_private(struct ni_usb_priv *ni_priv) +{ + usb_free_urb(ni_priv->interrupt_urb); + kfree(ni_priv); +} + +#define NUM_INIT_WRITES 26 +static int ni_usb_setup_init(gpib_board_t *board, struct ni_usb_register *writes) +{ + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + unsigned int mask, actual_ns; + int i = 0; + + writes[i].device = NIUSB_SUBDEV_UNKNOWN3; + writes[i].address = 0x10; + writes[i].value = 0x0; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = CMDR; + writes[i].value = SOFT_RESET; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + mask = AUXRA | HR_HLDA; + if (ni_priv->eos_mode & BIN) + mask |= HR_BIN; + writes[i].value = mask; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = AUXCR; + writes[i].value = mask; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = HSSEL; + writes[i].value = TNT_ONE_CHIP_BIT; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_CR; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = IMR0; + writes[i].value = TNT_IMR0_ALWAYS_BITS; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(IMR1); + writes[i].value = 0x0; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(IMR2); + writes[i].value = 0x0; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = IMR3; + writes[i].value = 0x0; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_HLDI; + i++; + + i += ni_usb_setup_t1_delay(&writes[i], board->t1_nano_sec, &actual_ns); + + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUXRG | NTNL_BIT; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = CMDR; + if (board->master) + mask = SETSC; // set system controller + else + mask = CLRSC; // clear system controller + writes[i].value = mask; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_CIFC; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(ADR); + writes[i].value = board->pad; + i++; + writes[i].device = NIUSB_SUBDEV_UNKNOWN2; + writes[i].address = 0x0; + writes[i].value = board->pad; + i++; + + i += ni_usb_write_sad(&writes[i], board->sad, board->sad >= 0); + + writes[i].device = NIUSB_SUBDEV_UNKNOWN2; + writes[i].address = 0x2; // could this be a timeout ? + writes[i].value = 0xfd; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = 0xf; // undocumented address + writes[i].value = 0x11; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_PON; + i++; + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_CPPF; + i++; + if (i > NUM_INIT_WRITES) { + dev_err(&usb_dev->dev, "%s: bug!, buffer overrun, i=%i\n", __func__, i); + return 0; + } + return i; +} + +static int ni_usb_init(gpib_board_t *board) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + struct ni_usb_register *writes; + unsigned int ibsta; + int writes_len; + + writes = kmalloc_array(NUM_INIT_WRITES, sizeof(*writes), GFP_KERNEL); + if (!writes) + return -ENOMEM; + + writes_len = ni_usb_setup_init(board, writes); + if (writes_len) + retval = ni_usb_write_registers(ni_priv, writes, writes_len, &ibsta); + else + return -EFAULT; + kfree(writes); + if (retval) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return retval; + } + ni_usb_soft_update_status(board, ibsta, 0); + return 0; +} + +static void ni_usb_interrupt_complete(struct urb *urb) +{ + gpib_board_t *board = urb->context; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int retval; + struct ni_usb_status_block status; + unsigned long flags; + +// printk("debug: %s: status=0x%x, error_count=%i, actual_length=%i\n", __func__, +// urb->status, urb->error_count, urb->actual_length); + + switch (urb->status) { + /* success */ + case 0: + break; + /* unlinked, don't resubmit */ + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* other error, resubmit */ + retval = usb_submit_urb(ni_priv->interrupt_urb, GFP_ATOMIC); + if (retval) + dev_err(&usb_dev->dev, "%s: failed to resubmit interrupt urb\n", __func__); + return; + } + + ni_usb_parse_status_block(urb->transfer_buffer, &status); +// printk("debug: ibsta=0x%x\n", status.ibsta); + + spin_lock_irqsave(&board->spinlock, flags); + ni_priv->monitored_ibsta_bits &= ~status.ibsta; +// printk("debug: monitored_ibsta_bits=0x%x\n", ni_priv->monitored_ibsta_bits); + spin_unlock_irqrestore(&board->spinlock, flags); + + wake_up_interruptible(&board->wait); + + retval = usb_submit_urb(ni_priv->interrupt_urb, GFP_ATOMIC); + if (retval) + dev_err(&usb_dev->dev, "%s: failed to resubmit interrupt urb\n", __func__); +} + +static int ni_usb_set_interrupt_monitor(gpib_board_t *board, unsigned int monitored_bits) +{ + int retval; + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + static const int buffer_length = 8; + u8 *buffer; + struct ni_usb_status_block status; + unsigned long flags; + //printk("%s: receive control pipe is %i\n", __func__, pipe); + buffer = kmalloc(buffer_length, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + spin_lock_irqsave(&board->spinlock, flags); + ni_priv->monitored_ibsta_bits = ni_usb_ibsta_monitor_mask & monitored_bits; +// dev_err(&usb_dev->dev, "debug: %s: monitored_ibsta_bits=0x%x\n", +// __func__, ni_priv->monitored_ibsta_bits); + spin_unlock_irqrestore(&board->spinlock, flags); + retval = ni_usb_receive_control_msg(ni_priv, NI_USB_WAIT_REQUEST, USB_DIR_IN | + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x300, ni_usb_ibsta_monitor_mask & monitored_bits, + buffer, buffer_length, 1000); + if (retval != buffer_length) { + dev_err(&usb_dev->dev, "%s: usb_control_msg returned %i\n", __func__, retval); + kfree(buffer); + return -1; + } + ni_usb_parse_status_block(buffer, &status); + kfree(buffer); + return 0; +} + +static int ni_usb_setup_urbs(gpib_board_t *board) +{ + struct ni_usb_priv *ni_priv = board->private_data; + struct usb_device *usb_dev; + int int_pipe; + int retval; + + if (ni_priv->interrupt_in_endpoint < 0) + return 0; + + mutex_lock(&ni_priv->interrupt_transfer_lock); + if (!ni_priv->bus_interface) { + mutex_unlock(&ni_priv->interrupt_transfer_lock); + return -ENODEV; + } + ni_priv->interrupt_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ni_priv->interrupt_urb) { + mutex_unlock(&ni_priv->interrupt_transfer_lock); + return -ENOMEM; + } + usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int_pipe = usb_rcvintpipe(usb_dev, ni_priv->interrupt_in_endpoint); + usb_fill_int_urb(ni_priv->interrupt_urb, usb_dev, int_pipe, ni_priv->interrupt_buffer, + sizeof(ni_priv->interrupt_buffer), &ni_usb_interrupt_complete, board, 1); + retval = usb_submit_urb(ni_priv->interrupt_urb, GFP_KERNEL); + mutex_unlock(&ni_priv->interrupt_transfer_lock); + if (retval) { + dev_err(&usb_dev->dev, "%s: failed to submit first interrupt urb, retval=%i\n", + __func__, retval); + return retval; + } + return 0; +} + +static void ni_usb_cleanup_urbs(struct ni_usb_priv *ni_priv) +{ + if (ni_priv && ni_priv->bus_interface) { + if (ni_priv->interrupt_urb) + usb_kill_urb(ni_priv->interrupt_urb); + if (ni_priv->bulk_urb) + usb_kill_urb(ni_priv->bulk_urb); + } +} + +static int ni_usb_b_read_serial_number(struct ni_usb_priv *ni_priv) +{ + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int retval; + u8 *out_data; + u8 *in_data; + static const int out_data_length = 0x20; + static const int in_data_length = 0x20; + int bytes_written = 0, bytes_read = 0; + int i = 0; + static const int num_reads = 4; + unsigned int results[4]; + int j; + unsigned int serial_number; + +// printk("%s: %s\n", __func__); + in_data = kmalloc(in_data_length, GFP_KERNEL); + if (!in_data) + return -ENOMEM; + + out_data = kmalloc(out_data_length, GFP_KERNEL); + if (!out_data) { + kfree(in_data); + return -ENOMEM; + } + i += ni_usb_bulk_register_read_header(&out_data[i], num_reads); + i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_UNKNOWN3, SERIAL_NUMBER_1_REG); + i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_UNKNOWN3, SERIAL_NUMBER_2_REG); + i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_UNKNOWN3, SERIAL_NUMBER_3_REG); + i += ni_usb_bulk_register_read(&out_data[i], NIUSB_SUBDEV_UNKNOWN3, SERIAL_NUMBER_4_REG); + while (i % 4) + out_data[i++] = 0x0; + i += ni_usb_bulk_termination(&out_data[i]); + retval = ni_usb_send_bulk_msg(ni_priv, out_data, out_data_length, &bytes_written, 1000); + if (retval) { + dev_err(&usb_dev->dev, "%s: ni_usb_send_bulk_msg returned %i, bytes_written=%i, i=%li\n", + __func__, + retval, bytes_written, (long)out_data_length); + goto serial_out; + } + retval = ni_usb_receive_bulk_msg(ni_priv, in_data, in_data_length, &bytes_read, 1000, 0); + if (retval) { + dev_err(&usb_dev->dev, "%s: ni_usb_receive_bulk_msg returned %i, bytes_read=%i\n", + __func__, retval, bytes_read); + ni_usb_dump_raw_block(in_data, bytes_read); + goto serial_out; + } + if (ARRAY_SIZE(results) < num_reads) { + dev_err(&usb_dev->dev, "Setup bug\n"); + retval = -EINVAL; + goto serial_out; + } + ni_usb_parse_register_read_block(in_data, results, num_reads); + serial_number = 0; + for (j = 0; j < num_reads; ++j) + serial_number |= (results[j] & 0xff) << (8 * j); + dev_info(&usb_dev->dev, "%s: board serial number is 0x%x\n", __func__, serial_number); + retval = 0; +serial_out: + kfree(in_data); + kfree(out_data); + return retval; +} + +static int ni_usb_hs_wait_for_ready(struct ni_usb_priv *ni_priv) +{ + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + static const int buffer_size = 0x10; + static const int timeout = 50; + static const int msec_sleep_duration = 100; + int i; int retval; + int j; + int unexpected = 0; + unsigned int serial_number; + u8 *buffer; + + buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + retval = ni_usb_receive_control_msg(ni_priv, NI_USB_SERIAL_NUMBER_REQUEST, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0, 0x0, buffer, buffer_size, 1000); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: usb_control_msg request 0x%x returned %i\n", + __func__, NI_USB_SERIAL_NUMBER_REQUEST, retval); + goto ready_out; + } + j = 0; + if (buffer[j] != NI_USB_SERIAL_NUMBER_REQUEST) { + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x%x\n", + __func__, j, (int)buffer[j], NI_USB_SERIAL_NUMBER_REQUEST); + unexpected = 1; + } + if (unexpected) + ni_usb_dump_raw_block(buffer, retval); + // NI-USB-HS+ pads the serial with 0x0 to make 16 bytes + if (retval != 5 && retval != 16) { + dev_err(&usb_dev->dev, "%s: received unexpected number of bytes = %i, expected 5 or 16\n", + __func__, retval); + ni_usb_dump_raw_block(buffer, retval); + } + serial_number = 0; + serial_number |= buffer[++j]; + serial_number |= (buffer[++j] << 8); + serial_number |= (buffer[++j] << 16); + serial_number |= (buffer[++j] << 24); + dev_info(&usb_dev->dev, "%s: board serial number is 0x%x\n", __func__, serial_number); + for (i = 0; i < timeout; ++i) { + int ready = 0; + + retval = ni_usb_receive_control_msg(ni_priv, NI_USB_POLL_READY_REQUEST, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0, 0x0, buffer, buffer_size, 100); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: usb_control_msg request 0x%x returned %i\n", + __func__, NI_USB_POLL_READY_REQUEST, retval); + goto ready_out; + } + j = 0; + unexpected = 0; + if (buffer[j] != NI_USB_POLL_READY_REQUEST) { // [0] + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x%x\n", + __func__, j, (int)buffer[j], NI_USB_POLL_READY_REQUEST); + unexpected = 1; + } + ++j; + if (buffer[j] != 0x1 && buffer[j] != 0x0) { // [1] HS+ sends 0x0 + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x1 or 0x0\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + if (buffer[++j] != 0x0) { // [2] + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x%x\n", + __func__, j, (int)buffer[j], 0x0); + unexpected = 1; + } + ++j; + // MC usb-488 (and sometimes NI-USB-HS?) sends 0x8 here; MC usb-488A sends 0x7 here + // NI-USB-HS+ sends 0x0 + if (buffer[j] != 0x1 && buffer[j] != 0x8 && buffer[j] != 0x7 && buffer[j] != 0x0) { + // [3] + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x0, 0x1, 0x7 or 0x8\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + ++j; + // NI-USB-HS+ sends 0 here + if (buffer[j] != 0x30 && buffer[j] != 0x0) { // [4] + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x0 or 0x30\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + ++j; + // MC usb-488 (and sometimes NI-USB-HS?) and NI-USB-HS+ sends 0x0 here + if (buffer[j] != 0x1 && buffer[j] != 0x0) { // [5] + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x1 or 0x0\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + if (buffer[++j] != 0x0) { // [6] + ready = 1; + // NI-USB-HS+ sends 0xf here + if (buffer[j] != 0x2 && buffer[j] != 0xe && buffer[j] != 0xf && + buffer[j] != 0x16) { + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x2, 0xe, 0xf or 0x16\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + } + if (buffer[++j] != 0x0) { // [7] + ready = 1; + // MC usb-488 sends 0x5 here; MC usb-488A sends 0x6 here + if (buffer[j] != 0x3 && buffer[j] != 0x5 && buffer[j] != 0x6 && + buffer[j] != 0x8) { + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x3 or 0x5, 0x6 or 0x08\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + } + ++j; + if (buffer[j] != 0x0 && buffer[j] != 0x2) { // [8] MC usb-488 sends 0x2 here + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x0 or 0x2\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + ++j; + // MC usb-488A and NI-USB-HS sends 0x3 here; NI-USB-HS+ sends 0x30 here + if (buffer[j] != 0x0 && buffer[j] != 0x3 && buffer[j] != 0x30) { // [9] + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x0, 0x3 or 0x30\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + if (buffer[++j] != 0x0) { + ready = 1; + if (buffer[j] != 0x96 && buffer[j] != 0x7 && buffer[j] != 0x6e) { +// [10] MC usb-488 sends 0x7 here + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[%i]=0x%x, expected 0x96, 0x07 or 0x6e\n", + __func__, j, (int)buffer[j]); + unexpected = 1; + } + } + if (unexpected) + ni_usb_dump_raw_block(buffer, retval); + if (ready) + break; + retval = msleep_interruptible(msec_sleep_duration); + if (retval) { + dev_err(&usb_dev->dev, "ni_usb_gpib: msleep interrupted\n"); + retval = -ERESTARTSYS; + goto ready_out; + } + } + retval = 0; + +ready_out: + kfree(buffer); + dev_dbg(&usb_dev->dev, "%s: exit retval=%d\n", __func__, retval); + return retval; +} + +/* This does some extra init for HS+ models, as observed on Windows. One of the + * control requests causes the LED to stop blinking. + * I'm not sure what the other 2 requests do. None of these requests are actually required + * for the adapter to work, maybe they do some init for the analyzer interface + * (which we don't use). + */ +static int ni_usb_hs_plus_extra_init(struct ni_usb_priv *ni_priv) +{ + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int retval; + u8 *buffer; + static const int buffer_size = 16; + int transfer_size; + + buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + do { + transfer_size = 16; + + retval = ni_usb_receive_control_msg(ni_priv, NI_USB_HS_PLUS_0x48_REQUEST, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0, 0x0, buffer, transfer_size, 1000); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: usb_control_msg request 0x%x returned %i\n", + __func__, NI_USB_HS_PLUS_0x48_REQUEST, retval); + break; + } + // expected response data: 48 f3 30 00 00 00 00 00 00 00 00 00 00 00 00 00 + if (buffer[0] != NI_USB_HS_PLUS_0x48_REQUEST) + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[0]=0x%x, expected 0x%x\n", + __func__, (int)buffer[0], NI_USB_HS_PLUS_0x48_REQUEST); + + transfer_size = 2; + + retval = ni_usb_receive_control_msg(ni_priv, NI_USB_HS_PLUS_LED_REQUEST, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x1, 0x0, buffer, transfer_size, 1000); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: usb_control_msg request 0x%x returned %i\n", + __func__, NI_USB_HS_PLUS_LED_REQUEST, retval); + break; + } + // expected response data: 4b 00 + if (buffer[0] != NI_USB_HS_PLUS_LED_REQUEST) + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[0]=0x%x, expected 0x%x\n", + __func__, (int)buffer[0], NI_USB_HS_PLUS_LED_REQUEST); + + transfer_size = 9; + + retval = ni_usb_receive_control_msg(ni_priv, NI_USB_HS_PLUS_0xf8_REQUEST, + USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_INTERFACE, + 0x0, 0x1, buffer, transfer_size, 1000); + if (retval < 0) { + dev_err(&usb_dev->dev, "%s: usb_control_msg request 0x%x returned %i\n", + __func__, NI_USB_HS_PLUS_0xf8_REQUEST, retval); + break; + } + // expected response data: f8 01 00 00 00 01 00 00 00 + if (buffer[0] != NI_USB_HS_PLUS_0xf8_REQUEST) + dev_err(&usb_dev->dev, "%s: unexpected data: buffer[0]=0x%x, expected 0x%x\n", + __func__, (int)buffer[0], NI_USB_HS_PLUS_0xf8_REQUEST); + + } while (0); + + // cleanup + kfree(buffer); + return retval; +} + +static inline int ni_usb_device_match(struct usb_interface *interface, + const gpib_board_config_t *config) +{ + if (gpib_match_device_path(&interface->dev, config->device_path) == 0) + return 0; + return 1; +} + +static int ni_usb_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + int retval; + int i; + struct ni_usb_priv *ni_priv; + int product_id; + struct usb_device *usb_dev; + + mutex_lock(&ni_usb_hotplug_lock); + retval = ni_usb_allocate_private(board); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + ni_priv = board->private_data; + for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) { + if (ni_usb_driver_interfaces[i] && + !usb_get_intfdata(ni_usb_driver_interfaces[i]) && + ni_usb_device_match(ni_usb_driver_interfaces[i], config)) { + ni_priv->bus_interface = ni_usb_driver_interfaces[i]; + usb_set_intfdata(ni_usb_driver_interfaces[i], board); + usb_dev = interface_to_usbdev(ni_priv->bus_interface); + dev_info(&usb_dev->dev, + "bus %d dev num %d attached to gpib minor %d, NI usb interface %i\n", + usb_dev->bus->busnum, usb_dev->devnum, board->minor, i); + break; + } + } + if (i == MAX_NUM_NI_USB_INTERFACES) { + mutex_unlock(&ni_usb_hotplug_lock); + pr_err("No supported NI usb gpib adapters found, have you loaded its firmware?\n"); + return -ENODEV; + } + if (usb_reset_configuration(interface_to_usbdev(ni_priv->bus_interface))) + dev_err(&usb_dev->dev, "ni_usb_gpib: usb_reset_configuration() failed.\n"); + + product_id = le16_to_cpu(usb_dev->descriptor.idProduct); + ni_priv->product_id = product_id; + + timer_setup(&ni_priv->bulk_timer, ni_usb_timeout_handler, 0); + + switch (product_id) { + case USB_DEVICE_ID_NI_USB_B: + ni_priv->bulk_out_endpoint = NIUSB_B_BULK_OUT_ENDPOINT; + ni_priv->bulk_in_endpoint = NIUSB_B_BULK_IN_ENDPOINT; + ni_priv->interrupt_in_endpoint = NIUSB_B_INTERRUPT_IN_ENDPOINT; + ni_usb_b_read_serial_number(ni_priv); + break; + case USB_DEVICE_ID_NI_USB_HS: + case USB_DEVICE_ID_MC_USB_488: + case USB_DEVICE_ID_KUSB_488A: + ni_priv->bulk_out_endpoint = NIUSB_HS_BULK_OUT_ENDPOINT; + ni_priv->bulk_in_endpoint = NIUSB_HS_BULK_IN_ENDPOINT; + ni_priv->interrupt_in_endpoint = NIUSB_HS_INTERRUPT_IN_ENDPOINT; + retval = ni_usb_hs_wait_for_ready(ni_priv); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + break; + case USB_DEVICE_ID_NI_USB_HS_PLUS: + ni_priv->bulk_out_endpoint = NIUSB_HS_PLUS_BULK_OUT_ENDPOINT; + ni_priv->bulk_in_endpoint = NIUSB_HS_PLUS_BULK_IN_ENDPOINT; + ni_priv->interrupt_in_endpoint = NIUSB_HS_PLUS_INTERRUPT_IN_ENDPOINT; + retval = ni_usb_hs_wait_for_ready(ni_priv); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + retval = ni_usb_hs_plus_extra_init(ni_priv); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + break; + default: + mutex_unlock(&ni_usb_hotplug_lock); + dev_err(&usb_dev->dev, "\tDriver bug: unknown endpoints for usb device id %x\n", + product_id); + return -EINVAL; + } + + retval = ni_usb_setup_urbs(board); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + retval = ni_usb_set_interrupt_monitor(board, 0); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + + board->t1_nano_sec = 500; + + retval = ni_usb_init(board); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + retval = ni_usb_set_interrupt_monitor(board, ni_usb_ibsta_monitor_mask); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + + mutex_unlock(&ni_usb_hotplug_lock); + dev_info(&usb_dev->dev, "%s: attached\n", __func__); + return retval; +} + +static int ni_usb_shutdown_hardware(struct ni_usb_priv *ni_priv) +{ + struct usb_device *usb_dev = interface_to_usbdev(ni_priv->bus_interface); + int retval; + int i = 0; + struct ni_usb_register writes[2]; + static const int writes_length = ARRAY_SIZE(writes); + unsigned int ibsta; + +// printk("%s: %s\n", __func__); + writes[i].device = NIUSB_SUBDEV_TNT4882; + writes[i].address = nec7210_to_tnt4882_offset(AUXMR); + writes[i].value = AUX_CR; + i++; + writes[i].device = NIUSB_SUBDEV_UNKNOWN3; + writes[i].address = 0x10; + writes[i].value = 0x0; + i++; + if (i > writes_length) { + dev_err(&usb_dev->dev, "%s: bug!, buffer overrun, i=%i\n", __func__, i); + return -EINVAL; + } + retval = ni_usb_write_registers(ni_priv, writes, i, &ibsta); + if (retval) { + dev_err(&usb_dev->dev, "%s: register write failed, retval=%i\n", __func__, retval); + return retval; + } + return 0; +} + +static void ni_usb_detach(gpib_board_t *board) +{ + struct ni_usb_priv *ni_priv; + + mutex_lock(&ni_usb_hotplug_lock); +// under windows, software unplug does chip_reset nec7210 aux command, +// then writes 0x0 to address 0x10 of device 3 + ni_priv = board->private_data; + if (ni_priv) { + if (ni_priv->bus_interface) { + ni_usb_set_interrupt_monitor(board, 0); + ni_usb_shutdown_hardware(ni_priv); + usb_set_intfdata(ni_priv->bus_interface, NULL); + } + mutex_lock(&ni_priv->bulk_transfer_lock); + mutex_lock(&ni_priv->control_transfer_lock); + mutex_lock(&ni_priv->interrupt_transfer_lock); + ni_usb_cleanup_urbs(ni_priv); + ni_usb_free_private(ni_priv); + } + mutex_unlock(&ni_usb_hotplug_lock); +} + +gpib_interface_t ni_usb_gpib_interface = { +name: "ni_usb_b", +attach : ni_usb_attach, +detach : ni_usb_detach, +read : ni_usb_read, +write : ni_usb_write, +command : ni_usb_command, +take_control : ni_usb_take_control, +go_to_standby : ni_usb_go_to_standby, +request_system_control : ni_usb_request_system_control, +interface_clear : ni_usb_interface_clear, +remote_enable : ni_usb_remote_enable, +enable_eos : ni_usb_enable_eos, +disable_eos : ni_usb_disable_eos, +parallel_poll : ni_usb_parallel_poll, +parallel_poll_configure : ni_usb_parallel_poll_configure, +parallel_poll_response : ni_usb_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : ni_usb_line_status, +update_status : ni_usb_update_status, +primary_address : ni_usb_primary_address, +secondary_address : ni_usb_secondary_address, +serial_poll_response : ni_usb_serial_poll_response, +serial_poll_status : ni_usb_serial_poll_status, +t1_delay : ni_usb_t1_delay, +return_to_local : ni_usb_return_to_local, +skip_check_for_command_acceptors : 1 +}; + +// Table with the USB-devices: just now only testing IDs +static struct usb_device_id ni_usb_driver_device_table[] = { + {USB_DEVICE(USB_VENDOR_ID_NI, USB_DEVICE_ID_NI_USB_B)}, + {USB_DEVICE(USB_VENDOR_ID_NI, USB_DEVICE_ID_NI_USB_HS)}, + // gpib-usb-hs+ has a second interface for the analyzer, which we ignore + {USB_DEVICE_INTERFACE_NUMBER(USB_VENDOR_ID_NI, USB_DEVICE_ID_NI_USB_HS_PLUS, 0)}, + {USB_DEVICE(USB_VENDOR_ID_NI, USB_DEVICE_ID_KUSB_488A)}, + {USB_DEVICE(USB_VENDOR_ID_NI, USB_DEVICE_ID_MC_USB_488)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, ni_usb_driver_device_table); + +static int ni_usb_driver_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + struct usb_device *usb_dev = interface_to_usbdev(interface); + int i; + char *path; + static const int path_length = 1024; + + mutex_lock(&ni_usb_hotplug_lock); + usb_get_dev(usb_dev); + for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) { + if (!ni_usb_driver_interfaces[i]) { + ni_usb_driver_interfaces[i] = interface; + usb_set_intfdata(interface, NULL); + break; + } + } + if (i == MAX_NUM_NI_USB_INTERFACES) { + usb_put_dev(usb_dev); + mutex_unlock(&ni_usb_hotplug_lock); + dev_err(&usb_dev->dev, "%s: ni_usb_driver_interfaces[] full\n", __func__); + return -1; + } + path = kmalloc(path_length, GFP_KERNEL); + if (!path) { + usb_put_dev(usb_dev); + mutex_unlock(&ni_usb_hotplug_lock); + return -ENOMEM; + } + usb_make_path(usb_dev, path, path_length); + dev_info(&usb_dev->dev, "ni_usb_gpib: probe succeeded for path: %s\n", path); + kfree(path); + mutex_unlock(&ni_usb_hotplug_lock); + return 0; +} + +static void ni_usb_driver_disconnect(struct usb_interface *interface) +{ + struct usb_device *usb_dev = interface_to_usbdev(interface); + int i; + + mutex_lock(&ni_usb_hotplug_lock); + for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) { + if (ni_usb_driver_interfaces[i] == interface) { + gpib_board_t *board = usb_get_intfdata(interface); + + if (board) { + struct ni_usb_priv *ni_priv = board->private_data; + + if (ni_priv) { + mutex_lock(&ni_priv->bulk_transfer_lock); + mutex_lock(&ni_priv->control_transfer_lock); + mutex_lock(&ni_priv->interrupt_transfer_lock); + ni_usb_cleanup_urbs(ni_priv); + ni_priv->bus_interface = NULL; + mutex_unlock(&ni_priv->interrupt_transfer_lock); + mutex_unlock(&ni_priv->control_transfer_lock); + mutex_unlock(&ni_priv->bulk_transfer_lock); + } + } + ni_usb_driver_interfaces[i] = NULL; + break; + } + } + if (i == MAX_NUM_NI_USB_INTERFACES) + dev_err(&usb_dev->dev, "%s: unable to find interface in ni_usb_driver_interfaces[]? bug?\n", + __func__); + usb_put_dev(usb_dev); + mutex_unlock(&ni_usb_hotplug_lock); +} + +static int ni_usb_driver_suspend(struct usb_interface *interface, pm_message_t message) +{ + struct usb_device *usb_dev = interface_to_usbdev(interface); + gpib_board_t *board; + int i, retval; + + mutex_lock(&ni_usb_hotplug_lock); + + for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) { + if (ni_usb_driver_interfaces[i] == interface) { + board = usb_get_intfdata(interface); + if (board) + break; + } + } + if (i == MAX_NUM_NI_USB_INTERFACES) { + mutex_unlock(&ni_usb_hotplug_lock); + return 0; + } + + struct ni_usb_priv *ni_priv = board->private_data; + + if (ni_priv) { + ni_usb_set_interrupt_monitor(board, 0); + retval = ni_usb_shutdown_hardware(ni_priv); + if (retval) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + if (ni_priv->interrupt_urb) { + mutex_lock(&ni_priv->interrupt_transfer_lock); + ni_usb_cleanup_urbs(ni_priv); + mutex_unlock(&ni_priv->interrupt_transfer_lock); + } + dev_info(&usb_dev->dev, + "bus %d dev num %d gpib minor %d, ni usb interface %i suspended\n", + usb_dev->bus->busnum, usb_dev->devnum, board->minor, i); + } + + mutex_unlock(&ni_usb_hotplug_lock); + return 0; +} + +static int ni_usb_driver_resume(struct usb_interface *interface) +{ + struct usb_device *usb_dev = interface_to_usbdev(interface); + + gpib_board_t *board; + int i, retval; + + mutex_lock(&ni_usb_hotplug_lock); + + for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) { + if (ni_usb_driver_interfaces[i] == interface) { + board = usb_get_intfdata(interface); + if (board) + break; + } + } + if (i == MAX_NUM_NI_USB_INTERFACES) { + mutex_unlock(&ni_usb_hotplug_lock); + return 0; + } + + struct ni_usb_priv *ni_priv = board->private_data; + + if (ni_priv) { + if (ni_priv->interrupt_urb) { + mutex_lock(&ni_priv->interrupt_transfer_lock); + retval = usb_submit_urb(ni_priv->interrupt_urb, GFP_KERNEL); + if (retval) { + dev_err(&usb_dev->dev, "%s: failed to resubmit interrupt urb, retval=%i\n", + __func__, retval); + mutex_unlock(&ni_priv->interrupt_transfer_lock); + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + mutex_unlock(&ni_priv->interrupt_transfer_lock); + } else { + dev_err(&usb_dev->dev, "%s: bug! int urb not set up\n", __func__); + mutex_unlock(&ni_usb_hotplug_lock); + return -EINVAL; + } + + switch (ni_priv->product_id) { + case USB_DEVICE_ID_NI_USB_B: + ni_usb_b_read_serial_number(ni_priv); + break; + case USB_DEVICE_ID_NI_USB_HS: + case USB_DEVICE_ID_MC_USB_488: + case USB_DEVICE_ID_KUSB_488A: + retval = ni_usb_hs_wait_for_ready(ni_priv); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + break; + case USB_DEVICE_ID_NI_USB_HS_PLUS: + retval = ni_usb_hs_wait_for_ready(ni_priv); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + retval = ni_usb_hs_plus_extra_init(ni_priv); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + break; + default: + mutex_unlock(&ni_usb_hotplug_lock); + dev_err(&usb_dev->dev, "\tDriver bug: unknown endpoints for usb device id\n"); + return -EINVAL; + } + + retval = ni_usb_set_interrupt_monitor(board, 0); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + + retval = ni_usb_init(board); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + retval = ni_usb_set_interrupt_monitor(board, ni_usb_ibsta_monitor_mask); + if (retval < 0) { + mutex_unlock(&ni_usb_hotplug_lock); + return retval; + } + if (board->master) + ni_usb_interface_clear(board, 1); // this is a pulsed action + if (ni_priv->ren_state) + ni_usb_remote_enable(board, 1); + + dev_info(&usb_dev->dev, + "bus %d dev num %d gpib minor %d, ni usb interface %i resumed\n", + usb_dev->bus->busnum, usb_dev->devnum, board->minor, i); + } + + mutex_unlock(&ni_usb_hotplug_lock); + return 0; +} + +static struct usb_driver ni_usb_bus_driver = { + .name = "ni_usb_gpib", + .probe = ni_usb_driver_probe, + .disconnect = ni_usb_driver_disconnect, + .suspend = ni_usb_driver_suspend, + .resume = ni_usb_driver_resume, + .id_table = ni_usb_driver_device_table, +}; + +static int __init ni_usb_init_module(void) +{ + int i; + + pr_info("ni_usb_gpib driver loading\n"); + for (i = 0; i < MAX_NUM_NI_USB_INTERFACES; i++) + ni_usb_driver_interfaces[i] = NULL; + usb_register(&ni_usb_bus_driver); + gpib_register_driver(&ni_usb_gpib_interface, THIS_MODULE); + + return 0; +} + +static void __exit ni_usb_exit_module(void) +{ + pr_info("ni_usb_gpib driver unloading\n"); + gpib_unregister_driver(&ni_usb_gpib_interface); + usb_deregister(&ni_usb_bus_driver); +} + +module_init(ni_usb_init_module); +module_exit(ni_usb_exit_module); diff --git a/drivers/staging/gpib/ni_usb/ni_usb_gpib.h b/drivers/staging/gpib/ni_usb/ni_usb_gpib.h new file mode 100644 index 00000000000000..9b21dfa0f3f6d1 --- /dev/null +++ b/drivers/staging/gpib/ni_usb/ni_usb_gpib.h @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2004 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _NI_USB_GPIB_H +#define _NI_USB_GPIB_H + +#include +#include +#include +#include +#include "gpibP.h" + +enum { + USB_VENDOR_ID_NI = 0x3923 +}; + +enum { + USB_DEVICE_ID_NI_USB_B = 0x702a, + USB_DEVICE_ID_NI_USB_B_PREINIT = 0x702b, // device id before firmware is loaded + USB_DEVICE_ID_NI_USB_HS = 0x709b, + USB_DEVICE_ID_NI_USB_HS_PLUS = 0x7618, + USB_DEVICE_ID_KUSB_488A = 0x725c, + USB_DEVICE_ID_MC_USB_488 = 0x725d +}; + +enum ni_usb_device { + NIUSB_SUBDEV_TNT4882 = 1, + NIUSB_SUBDEV_UNKNOWN2 = 2, + NIUSB_SUBDEV_UNKNOWN3 = 3, +}; + +enum endpoint_addresses { + NIUSB_B_BULK_OUT_ENDPOINT = 0x2, + NIUSB_B_BULK_IN_ENDPOINT = 0x2, + NIUSB_B_BULK_IN_ALT_ENDPOINT = 0x6, + NIUSB_B_INTERRUPT_IN_ENDPOINT = 0x4, +}; + +enum hs_enpoint_addresses { + NIUSB_HS_BULK_OUT_ENDPOINT = 0x2, + NIUSB_HS_BULK_OUT_ALT_ENDPOINT = 0x6, + NIUSB_HS_BULK_IN_ENDPOINT = 0x4, + NIUSB_HS_BULK_IN_ALT_ENDPOINT = 0x8, + NIUSB_HS_INTERRUPT_IN_ENDPOINT = 0x1, +}; + +enum hs_plus_endpoint_addresses { + NIUSB_HS_PLUS_BULK_OUT_ENDPOINT = 0x1, + NIUSB_HS_PLUS_BULK_OUT_ALT_ENDPOINT = 0x4, + NIUSB_HS_PLUS_BULK_IN_ENDPOINT = 0x2, + NIUSB_HS_PLUS_BULK_IN_ALT_ENDPOINT = 0x5, + NIUSB_HS_PLUS_INTERRUPT_IN_ENDPOINT = 0x3, +}; + +struct ni_usb_urb_ctx { + struct semaphore complete; + unsigned timed_out : 1; +}; + +// struct which defines private_data for ni_usb devices +struct ni_usb_priv { + struct usb_interface *bus_interface; + int bulk_out_endpoint; + int bulk_in_endpoint; + int interrupt_in_endpoint; + u8 eos_char; + unsigned short eos_mode; + unsigned int monitored_ibsta_bits; + struct urb *bulk_urb; + struct urb *interrupt_urb; + u8 interrupt_buffer[0x11]; + struct mutex addressed_transfer_lock; // protect transfer lock + struct mutex bulk_transfer_lock; // protect bulk message sends + struct mutex control_transfer_lock; // protect control messages + struct mutex interrupt_transfer_lock; // protect interrupt messages + struct timer_list bulk_timer; + struct ni_usb_urb_ctx context; + int product_id; + unsigned short ren_state; +}; + +struct ni_usb_status_block { + short id; + unsigned short ibsta; + short error_code; + unsigned short count; +}; + +struct ni_usb_register { + enum ni_usb_device device; + short address; + unsigned short value; +}; + +enum ni_usb_bulk_ids { + NIUSB_IBCAC_ID = 0x1, + NIUSB_UNKNOWN3_ID = 0x3, // device level function id? + NIUSB_TERM_ID = 0x4, + NIUSB_IBGTS_ID = 0x6, + NIUSB_IBRPP_ID = 0x7, + NIUSB_REG_READ_ID = 0x8, + NIUSB_REG_WRITE_ID = 0x9, + NIUSB_IBSIC_ID = 0xf, + NIUSB_REGISTER_READ_DATA_START_ID = 0x34, + NIUSB_REGISTER_READ_DATA_END_ID = 0x35, + NIUSB_IBRD_DATA_ID = 0x36, + NIUSB_IBRD_EXTENDED_DATA_ID = 0x37, + NIUSB_IBRD_STATUS_ID = 0x38 +}; + +enum ni_usb_error_codes { + NIUSB_NO_ERROR = 0, + /* NIUSB_ABORTED_ERROR occurs when I/O is interrupted early by + * doing a NI_USB_STOP_REQUEST on the control endpoint. + */ + NIUSB_ABORTED_ERROR = 1, + // NIUSB_READ_ATN_ERROR occurs when you do a board read while + // ATN is set + NIUSB_ATN_STATE_ERROR = 2, + // NIUSB_ADDRESSING_ERROR occurs when you do a board + // read/write as CIC but are not in LACS/TACS + NIUSB_ADDRESSING_ERROR = 3, + /* NIUSB_EOSMODE_ERROR occurs on reads if any eos mode or char + * bits are set when REOS is not set. + * Have also seen error 4 if you try to send more than 16 + * command bytes at once on a usb-b. + */ + NIUSB_EOSMODE_ERROR = 4, + // NIUSB_NO_BUS_ERROR occurs when you try to write a command + // byte but there are no devices connected to the gpib bus + NIUSB_NO_BUS_ERROR = 5, + // NIUSB_NO_LISTENER_ERROR occurs when you do a board write as + // CIC with no listener + NIUSB_NO_LISTENER_ERROR = 8, + // get NIUSB_TIMEOUT_ERROR on board read/write timeout + NIUSB_TIMEOUT_ERROR = 10, +}; + +enum ni_usb_control_requests { + NI_USB_STOP_REQUEST = 0x20, + NI_USB_WAIT_REQUEST = 0x21, + NI_USB_POLL_READY_REQUEST = 0x40, + NI_USB_SERIAL_NUMBER_REQUEST = 0x41, + NI_USB_HS_PLUS_0x48_REQUEST = 0x48, + NI_USB_HS_PLUS_LED_REQUEST = 0x4b, + NI_USB_HS_PLUS_0xf8_REQUEST = 0xf8 +}; + +static const unsigned int ni_usb_ibsta_monitor_mask = + SRQI | LOK | REM | CIC | ATN | TACS | LACS | DTAS | DCAS; + +static inline int nec7210_to_tnt4882_offset(int offset) +{ + return 2 * offset; +}; + +static inline int ni_usb_bulk_termination(u8 *buffer) +{ + int i = 0; + + buffer[i++] = NIUSB_TERM_ID; + buffer[i++] = 0x0; + buffer[i++] = 0x0; + buffer[i++] = 0x0; + return i; +} + +enum ni_usb_unknown3_register { + SERIAL_NUMBER_4_REG = 0x8, + SERIAL_NUMBER_3_REG = 0x9, + SERIAL_NUMBER_2_REG = 0xa, + SERIAL_NUMBER_1_REG = 0xb, +}; + +static inline int ni_usb_bulk_register_write_header(u8 *buffer, int num_writes) +{ + int i = 0; + + buffer[i++] = NIUSB_REG_WRITE_ID; + buffer[i++] = num_writes; + buffer[i++] = 0x0; + return i; +} + +static inline int ni_usb_bulk_register_write(u8 *buffer, struct ni_usb_register reg) +{ + int i = 0; + + buffer[i++] = reg.device; + buffer[i++] = reg.address; + buffer[i++] = reg.value; + return i; +} + +static inline int ni_usb_bulk_register_read_header(u8 *buffer, int num_reads) +{ + int i = 0; + + buffer[i++] = NIUSB_REG_READ_ID; + buffer[i++] = num_reads; + return i; +} + +static inline int ni_usb_bulk_register_read(u8 *buffer, int device, int address) +{ + int i = 0; + + buffer[i++] = device; + buffer[i++] = address; + return i; +} + +#endif // _NI_USB_GPIB_H diff --git a/drivers/staging/gpib/pc2/Makefile b/drivers/staging/gpib/pc2/Makefile new file mode 100644 index 00000000000000..8148425e0f8760 --- /dev/null +++ b/drivers/staging/gpib/pc2/Makefile @@ -0,0 +1,5 @@ + +obj-m += pc2_gpib.o + + + diff --git a/drivers/staging/gpib/pc2/pc2_gpib.c b/drivers/staging/gpib/pc2/pc2_gpib.c new file mode 100644 index 00000000000000..7b3b34f4734168 --- /dev/null +++ b/drivers/staging/gpib/pc2/pc2_gpib.c @@ -0,0 +1,656 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 2001, 2002 by Frank Mori Hess + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nec7210.h" +#include "gpibP.h" + +// struct which defines private_data for pc2 driver +struct pc2_priv { + struct nec7210_priv nec7210_priv; + unsigned int irq; + // io address that clears interrupt for pc2a (0x2f0 + irq) + unsigned int clear_intr_addr; +}; + +// pc2 uses 8 consecutive io addresses +static const int pc2_iosize = 8; +static const int pc2a_iosize = 8; +static const int pc2_2a_iosize = 16; + +// offset between io addresses of successive nec7210 registers +static const int pc2a_reg_offset = 0x400; +static const int pc2_reg_offset = 1; + +//interrupt service routine +static irqreturn_t pc2_interrupt(int irq, void *arg); +static irqreturn_t pc2a_interrupt(int irq, void *arg); + +// pc2 specific registers and bits + +// interrupt clear register address +static const int pc2a_clear_intr_iobase = 0x2f0; +static inline unsigned int CLEAR_INTR_REG(unsigned int irq) +{ + return pc2a_clear_intr_iobase + irq; +} + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for PC2/PC2a and compatible devices"); + +static int pc2_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int pc2a_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int pc2a_cb7210_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int pc2_2a_attach(gpib_board_t *board, const gpib_board_config_t *config); + +static void pc2_detach(gpib_board_t *board); +static void pc2a_detach(gpib_board_t *board); +static void pc2_2a_detach(gpib_board_t *board); + +/* + * GPIB interrupt service routines + */ + +irqreturn_t pc2_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + struct pc2_priv *priv = board->private_data; + unsigned long flags; + irqreturn_t retval; + + spin_lock_irqsave(&board->spinlock, flags); + retval = nec7210_interrupt(board, &priv->nec7210_priv); + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +irqreturn_t pc2a_interrupt(int irq, void *arg) +{ + gpib_board_t *board = arg; + struct pc2_priv *priv = board->private_data; + int status1, status2; + unsigned long flags; + irqreturn_t retval; + + spin_lock_irqsave(&board->spinlock, flags); + // read interrupt status (also clears status) + status1 = read_byte(&priv->nec7210_priv, ISR1); + status2 = read_byte(&priv->nec7210_priv, ISR2); + /* clear interrupt circuit */ + if (priv->irq) + outb(0xff, CLEAR_INTR_REG(priv->irq)); + retval = nec7210_interrupt_have_status(board, &priv->nec7210_priv, status1, status2); + spin_unlock_irqrestore(&board->spinlock, flags); + return retval; +} + +// wrappers for interface functions +static int pc2_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); +} + +static int pc2_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); +} + +static int pc2_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); +} + +static int pc2_take_control(gpib_board_t *board, int synchronous) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_take_control(board, &priv->nec7210_priv, synchronous); +} + +static int pc2_go_to_standby(gpib_board_t *board) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_go_to_standby(board, &priv->nec7210_priv); +} + +static void pc2_request_system_control(gpib_board_t *board, int request_control) +{ + struct pc2_priv *priv = board->private_data; + + nec7210_request_system_control(board, &priv->nec7210_priv, request_control); +} + +static void pc2_interface_clear(gpib_board_t *board, int assert) +{ + struct pc2_priv *priv = board->private_data; + + nec7210_interface_clear(board, &priv->nec7210_priv, assert); +} + +static void pc2_remote_enable(gpib_board_t *board, int enable) +{ + struct pc2_priv *priv = board->private_data; + + nec7210_remote_enable(board, &priv->nec7210_priv, enable); +} + +static int pc2_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); +} + +static void pc2_disable_eos(gpib_board_t *board) +{ + struct pc2_priv *priv = board->private_data; + + nec7210_disable_eos(board, &priv->nec7210_priv); +} + +static unsigned int pc2_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_update_status(board, &priv->nec7210_priv, clear_mask); +} + +static int pc2_primary_address(gpib_board_t *board, unsigned int address) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_primary_address(board, &priv->nec7210_priv, address); +} + +static int pc2_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); +} + +static int pc2_parallel_poll(gpib_board_t *board, uint8_t *result) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_parallel_poll(board, &priv->nec7210_priv, result); +} + +static void pc2_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + struct pc2_priv *priv = board->private_data; + + nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config); +} + +static void pc2_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct pc2_priv *priv = board->private_data; + + nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); +} + +static void pc2_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + struct pc2_priv *priv = board->private_data; + + nec7210_serial_poll_response(board, &priv->nec7210_priv, status); +} + +static uint8_t pc2_serial_poll_status(gpib_board_t *board) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_serial_poll_status(board, &priv->nec7210_priv); +} + +static unsigned int pc2_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct pc2_priv *priv = board->private_data; + + return nec7210_t1_delay(board, &priv->nec7210_priv, nano_sec); +} + +static void pc2_return_to_local(gpib_board_t *board) +{ + struct pc2_priv *priv = board->private_data; + + nec7210_return_to_local(board, &priv->nec7210_priv); +} + +gpib_interface_t pc2_interface = { +name: "pcII", +attach : pc2_attach, +detach : pc2_detach, +read : pc2_read, +write : pc2_write, +command : pc2_command, +take_control : pc2_take_control, +go_to_standby : pc2_go_to_standby, +request_system_control : pc2_request_system_control, +interface_clear : pc2_interface_clear, +remote_enable : pc2_remote_enable, +enable_eos : pc2_enable_eos, +disable_eos : pc2_disable_eos, +parallel_poll : pc2_parallel_poll, +parallel_poll_configure : pc2_parallel_poll_configure, +parallel_poll_response : pc2_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : NULL, +update_status : pc2_update_status, +primary_address : pc2_primary_address, +secondary_address : pc2_secondary_address, +serial_poll_response : pc2_serial_poll_response, +serial_poll_status : pc2_serial_poll_status, +t1_delay : pc2_t1_delay, +return_to_local : pc2_return_to_local, +}; + +gpib_interface_t pc2a_interface = { +name: "pcIIa", +attach : pc2a_attach, +detach : pc2a_detach, +read : pc2_read, +write : pc2_write, +command : pc2_command, +take_control : pc2_take_control, +go_to_standby : pc2_go_to_standby, +request_system_control : pc2_request_system_control, +interface_clear : pc2_interface_clear, +remote_enable : pc2_remote_enable, +enable_eos : pc2_enable_eos, +disable_eos : pc2_disable_eos, +parallel_poll : pc2_parallel_poll, +parallel_poll_configure : pc2_parallel_poll_configure, +parallel_poll_response : pc2_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : NULL, +update_status : pc2_update_status, +primary_address : pc2_primary_address, +secondary_address : pc2_secondary_address, +serial_poll_response : pc2_serial_poll_response, +serial_poll_status : pc2_serial_poll_status, +t1_delay : pc2_t1_delay, +return_to_local : pc2_return_to_local, +}; + +gpib_interface_t pc2a_cb7210_interface = { +name: "pcIIa_cb7210", +attach : pc2a_cb7210_attach, +detach : pc2a_detach, +read : pc2_read, +write : pc2_write, +command : pc2_command, +take_control : pc2_take_control, +go_to_standby : pc2_go_to_standby, +request_system_control : pc2_request_system_control, +interface_clear : pc2_interface_clear, +remote_enable : pc2_remote_enable, +enable_eos : pc2_enable_eos, +disable_eos : pc2_disable_eos, +parallel_poll : pc2_parallel_poll, +parallel_poll_configure : pc2_parallel_poll_configure, +parallel_poll_response : pc2_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : NULL, //XXX +update_status : pc2_update_status, +primary_address : pc2_primary_address, +secondary_address : pc2_secondary_address, +serial_poll_response : pc2_serial_poll_response, +serial_poll_status : pc2_serial_poll_status, +t1_delay : pc2_t1_delay, +return_to_local : pc2_return_to_local, +}; + +gpib_interface_t pc2_2a_interface = { +name: "pcII_IIa", +attach : pc2_2a_attach, +detach : pc2_2a_detach, +read : pc2_read, +write : pc2_write, +command : pc2_command, +take_control : pc2_take_control, +go_to_standby : pc2_go_to_standby, +request_system_control : pc2_request_system_control, +interface_clear : pc2_interface_clear, +remote_enable : pc2_remote_enable, +enable_eos : pc2_enable_eos, +disable_eos : pc2_disable_eos, +parallel_poll : pc2_parallel_poll, +parallel_poll_configure : pc2_parallel_poll_configure, +parallel_poll_response : pc2_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : NULL, +update_status : pc2_update_status, +primary_address : pc2_primary_address, +secondary_address : pc2_secondary_address, +serial_poll_response : pc2_serial_poll_response, +serial_poll_status : pc2_serial_poll_status, +t1_delay : pc2_t1_delay, +return_to_local : pc2_return_to_local, +}; + +static int allocate_private(gpib_board_t *board) +{ + struct pc2_priv *priv; + + board->private_data = kmalloc(sizeof(struct pc2_priv), GFP_KERNEL); + if (!board->private_data) + return -1; + priv = board->private_data; + memset(priv, 0, sizeof(struct pc2_priv)); + init_nec7210_private(&priv->nec7210_priv); + return 0; +} + +static void free_private(gpib_board_t *board) +{ + kfree(board->private_data); + board->private_data = NULL; +} + +static int pc2_generic_attach(gpib_board_t *board, const gpib_board_config_t *config, + enum nec7210_chipset chipset) +{ + struct pc2_priv *pc2_priv; + struct nec7210_priv *nec_priv; + + board->status = 0; + if (allocate_private(board)) + return -ENOMEM; + pc2_priv = board->private_data; + nec_priv = &pc2_priv->nec7210_priv; + nec_priv->read_byte = nec7210_ioport_read_byte; + nec_priv->write_byte = nec7210_ioport_write_byte; + nec_priv->type = chipset; + +#ifndef PC2_DMA + /* board->dev hasn't been initialized, so forget about DMA until this driver + * is adapted to use isa_register_driver. + */ + if (config->ibdma) + pr_err("DMA disabled for pc2 gpib, driver needs to be adapted to use isa_register_driver to get a struct device*"); +#else + if (config->ibdma) { + nec_priv->dma_buffer_length = 0x1000; + nec_priv->dma_buffer = dma_alloc_coherent(board->dev, + nec_priv->dma_buffer_length, & + nec_priv->dma_buffer_addr, GFP_ATOMIC); + if (!nec_priv->dma_buffer) + return -ENOMEM; + + // request isa dma channel + if (request_dma(config->ibdma, "pc2")) { + pr_err("gpib: can't request DMA %d\n", config->ibdma); + return -1; + } + nec_priv->dma_channel = config->ibdma; + } +#endif + + return 0; +} + +int pc2_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + int isr_flags = 0; + struct pc2_priv *pc2_priv; + struct nec7210_priv *nec_priv; + int retval; + + retval = pc2_generic_attach(board, config, NEC7210); + if (retval) + return retval; + + pc2_priv = board->private_data; + nec_priv = &pc2_priv->nec7210_priv; + nec_priv->offset = pc2_reg_offset; + + if (request_region((unsigned long)config->ibbase, pc2_iosize, "pc2") == 0) { + pr_err("gpib: ioports are already in use\n"); + return -1; + } + nec_priv->iobase = config->ibbase; + + nec7210_board_reset(nec_priv, board); + + // install interrupt handler + if (config->ibirq) { + if (request_irq(config->ibirq, pc2_interrupt, isr_flags, "pc2", board)) { + pr_err("gpib: can't request IRQ %d\n", config->ibirq); + return -1; + } + } + pc2_priv->irq = config->ibirq; + /* poll so we can detect assertion of ATN */ + if (gpib_request_pseudo_irq(board, pc2_interrupt)) { + pr_err("pc2_gpib: failed to allocate pseudo_irq\n"); + return -1; + } + /* set internal counter register for 8 MHz input clock */ + write_byte(nec_priv, ICR | 8, AUXMR); + + nec7210_board_online(nec_priv, board); + + return 0; +} + +void pc2_detach(gpib_board_t *board) +{ + struct pc2_priv *pc2_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (pc2_priv) { + nec_priv = &pc2_priv->nec7210_priv; +#ifdef PC2_DMA + if (nec_priv->dma_channel) + free_dma(nec_priv->dma_channel); +#endif + gpib_free_pseudo_irq(board); + if (pc2_priv->irq) + free_irq(pc2_priv->irq, board); + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + release_region((unsigned long)(nec_priv->iobase), pc2_iosize); + } + if (nec_priv->dma_buffer) { + dma_free_coherent(board->dev, nec_priv->dma_buffer_length, + nec_priv->dma_buffer, nec_priv->dma_buffer_addr); + nec_priv->dma_buffer = NULL; + } + } + free_private(board); +} + +static int pc2a_common_attach(gpib_board_t *board, const gpib_board_config_t *config, + unsigned int num_registers, enum nec7210_chipset chipset) +{ + unsigned int i, j; + struct pc2_priv *pc2_priv; + struct nec7210_priv *nec_priv; + int retval; + + retval = pc2_generic_attach(board, config, chipset); + if (retval) + return retval; + + pc2_priv = board->private_data; + nec_priv = &pc2_priv->nec7210_priv; + nec_priv->offset = pc2a_reg_offset; + + switch ((unsigned long)(config->ibbase)) { + case 0x02e1: + case 0x22e1: + case 0x42e1: + case 0x62e1: + break; + default: + pr_err("PCIIa base range invalid, must be one of 0x[0246]2e1, but is 0x%p\n", + config->ibbase); + return -1; + } + + if (config->ibirq) { + if (config->ibirq < 2 || config->ibirq > 7) { + pr_err("pc2_gpib: illegal interrupt level %i\n", config->ibirq); + return -1; + } + } else { + pr_err("pc2_gpib: interrupt disabled, using polling mode (slow)\n"); + } +#ifdef CHECK_IOPORTS + unsigned int err = 0; + + for (i = 0; i < num_registers; i++) { + if (check_region((unsigned long)config->ibbase + i * pc2a_reg_offset, 1)) + err++; + } + if (config->ibirq && check_region(pc2a_clear_intr_iobase + config->ibirq, 1)) + err++; + if (err) { + pr_err("gpib: ioports are already in use"); + return -1; + } +#endif + for (i = 0; i < num_registers; i++) { + if (!request_region((unsigned long)config->ibbase + + i * pc2a_reg_offset, 1, "pc2a")) { + pr_err("gpib: ioports are already in use"); + for (j = 0; j < i; j++) + release_region((unsigned long)(config->ibbase) + + j * pc2a_reg_offset, 1); + return -1; + } + } + nec_priv->iobase = config->ibbase; + if (config->ibirq) { + if (!request_region(pc2a_clear_intr_iobase + config->ibirq, 1, "pc2a")) { + pr_err("gpib: ioports are already in use"); + return -1; + } + pc2_priv->clear_intr_addr = pc2a_clear_intr_iobase + config->ibirq; + if (request_irq(config->ibirq, pc2a_interrupt, 0, "pc2a", board)) { + pr_err("gpib: can't request IRQ %d\n", config->ibirq); + return -1; + } + } + pc2_priv->irq = config->ibirq; + /* poll so we can detect assertion of ATN */ + if (gpib_request_pseudo_irq(board, pc2_interrupt)) { + pr_err("pc2_gpib: failed to allocate pseudo_irq\n"); + return -1; + } + + // make sure interrupt is clear + if (pc2_priv->irq) + outb(0xff, CLEAR_INTR_REG(pc2_priv->irq)); + + nec7210_board_reset(nec_priv, board); + + /* set internal counter register for 8 MHz input clock */ + write_byte(nec_priv, ICR | 8, AUXMR); + + nec7210_board_online(nec_priv, board); + + return 0; +} + +int pc2a_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + return pc2a_common_attach(board, config, pc2a_iosize, NEC7210); +} + +int pc2a_cb7210_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + return pc2a_common_attach(board, config, pc2a_iosize, CB7210); +} + +int pc2_2a_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + return pc2a_common_attach(board, config, pc2_2a_iosize, NAT4882); +} + +static void pc2a_common_detach(gpib_board_t *board, unsigned int num_registers) +{ + int i; + struct pc2_priv *pc2_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (pc2_priv) { + nec_priv = &pc2_priv->nec7210_priv; +#ifdef PC2_DMA + if (nec_priv->dma_channel) + free_dma(nec_priv->dma_channel); +#endif + gpib_free_pseudo_irq(board); + if (pc2_priv->irq) + free_irq(pc2_priv->irq, board); + if (nec_priv->iobase) { + nec7210_board_reset(nec_priv, board); + for (i = 0; i < num_registers; i++) + release_region((unsigned long)nec_priv->iobase + + i * pc2a_reg_offset, 1); + } + if (pc2_priv->clear_intr_addr) + release_region(pc2_priv->clear_intr_addr, 1); + if (nec_priv->dma_buffer) { + dma_free_coherent(board->dev, nec_priv->dma_buffer_length, + nec_priv->dma_buffer, + nec_priv->dma_buffer_addr); + nec_priv->dma_buffer = NULL; + } + } + free_private(board); +} + +void pc2a_detach(gpib_board_t *board) +{ + pc2a_common_detach(board, pc2a_iosize); +} + +void pc2_2a_detach(gpib_board_t *board) +{ + pc2a_common_detach(board, pc2_2a_iosize); +} + +static int __init pc2_init_module(void) +{ + gpib_register_driver(&pc2_interface, THIS_MODULE); + gpib_register_driver(&pc2a_interface, THIS_MODULE); + gpib_register_driver(&pc2a_cb7210_interface, THIS_MODULE); + gpib_register_driver(&pc2_2a_interface, THIS_MODULE); + + return 0; +} + +static void __exit pc2_exit_module(void) +{ + gpib_unregister_driver(&pc2_interface); + gpib_unregister_driver(&pc2a_interface); + gpib_unregister_driver(&pc2a_cb7210_interface); + gpib_unregister_driver(&pc2_2a_interface); +} + +module_init(pc2_init_module); +module_exit(pc2_exit_module); + diff --git a/drivers/staging/gpib/tms9914/Makefile b/drivers/staging/gpib/tms9914/Makefile new file mode 100644 index 00000000000000..81b7e3cf104c0e --- /dev/null +++ b/drivers/staging/gpib/tms9914/Makefile @@ -0,0 +1,6 @@ + +obj-m += tms9914.o + + + + diff --git a/drivers/staging/gpib/tms9914/tms9914.c b/drivers/staging/gpib/tms9914/tms9914.c new file mode 100644 index 00000000000000..152b243b845b50 --- /dev/null +++ b/drivers/staging/gpib/tms9914/tms9914.c @@ -0,0 +1,910 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * copyright : (C) 2001, 2002 by Frank Mori Hess + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpibP.h" +#include "tms9914.h" + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB library for tms9914"); + +static unsigned int update_status_nolock(gpib_board_t *board, struct tms9914_priv *priv); + +int tms9914_take_control(gpib_board_t *board, struct tms9914_priv *priv, int synchronous) +{ + int i; + const int timeout = 100; + + if (synchronous) + write_byte(priv, AUX_TCS, AUXCR); + else + write_byte(priv, AUX_TCA, AUXCR); + // busy wait until ATN is asserted + for (i = 0; i < timeout; i++) { + if ((read_byte(priv, ADSR) & HR_ATN)) + break; + udelay(1); + } + if (i == timeout) + return -ETIMEDOUT; + + clear_bit(WRITE_READY_BN, &priv->state); + + return 0; +} +EXPORT_SYMBOL_GPL(tms9914_take_control); + +/* The agilent 82350B has a buggy implementation of tcs which interferes with the + * operation of tca. It appears to be based on the controller state machine + * described in the TI 9900 TMS9914A data manual published in 1982. This + * manual describes tcs as putting the controller into a CWAS + * state where it waits indefinitely for ANRS and ignores tca. Since a + * functioning tca is far more important than tcs, we work around the + * problem by never issuing tcs. + * + * I don't know if this problem exists in the real tms9914a or just in the fpga + * of the 82350B. For now, only the agilent_82350b uses this workaround. + * The rest of the tms9914 based drivers still use tms9914_take_control + * directly (which does issue tcs). + */ +int tms9914_take_control_workaround(gpib_board_t *board, struct tms9914_priv *priv, int synchronous) +{ + if (synchronous) + return -ETIMEDOUT; + return tms9914_take_control(board, priv, synchronous); +} +EXPORT_SYMBOL_GPL(tms9914_take_control_workaround); + +int tms9914_go_to_standby(gpib_board_t *board, struct tms9914_priv *priv) +{ + int i; + const int timeout = 1000; + + write_byte(priv, AUX_GTS, AUXCR); + // busy wait until ATN is released + for (i = 0; i < timeout; i++) { + if ((read_byte(priv, ADSR) & HR_ATN) == 0) + break; + udelay(1); + } + if (i == timeout) { + pr_err("error waiting for NATN\n"); + return -ETIMEDOUT; + } + + clear_bit(COMMAND_READY_BN, &priv->state); + + return 0; +} +EXPORT_SYMBOL_GPL(tms9914_go_to_standby); + +void tms9914_interface_clear(gpib_board_t *board, struct tms9914_priv *priv, int assert) +{ + if (assert) { + write_byte(priv, AUX_SIC | AUX_CS, AUXCR); + + set_bit(CIC_NUM, &board->status); + } else { + write_byte(priv, AUX_SIC, AUXCR); + } +} +EXPORT_SYMBOL_GPL(tms9914_interface_clear); + +void tms9914_remote_enable(gpib_board_t *board, struct tms9914_priv *priv, int enable) +{ + if (enable) + write_byte(priv, AUX_SRE | AUX_CS, AUXCR); + else + write_byte(priv, AUX_SRE, AUXCR); +} +EXPORT_SYMBOL_GPL(tms9914_remote_enable); + +void tms9914_request_system_control(gpib_board_t *board, struct tms9914_priv *priv, + int request_control) +{ + if (request_control) { + write_byte(priv, AUX_RQC, AUXCR); + } else { + clear_bit(CIC_NUM, &board->status); + write_byte(priv, AUX_RLC, AUXCR); + } +} +EXPORT_SYMBOL_GPL(tms9914_request_system_control); + +unsigned int tms9914_t1_delay(gpib_board_t *board, struct tms9914_priv *priv, + unsigned int nano_sec) +{ + static const int clock_period = 200; // assuming 5Mhz input clock + int num_cycles; + + num_cycles = 12; + + if (nano_sec <= 8 * clock_period) { + write_byte(priv, AUX_STDL | AUX_CS, AUXCR); + num_cycles = 8; + } else { + write_byte(priv, AUX_STDL, AUXCR); + } + + if (nano_sec <= 4 * clock_period) { + write_byte(priv, AUX_VSTDL | AUX_CS, AUXCR); + num_cycles = 4; + } else { + write_byte(priv, AUX_VSTDL, AUXCR); + } + + return num_cycles * clock_period; +} +EXPORT_SYMBOL_GPL(tms9914_t1_delay); + +void tms9914_return_to_local(const gpib_board_t *board, struct tms9914_priv *priv) +{ + write_byte(priv, AUX_RTL, AUXCR); +} +EXPORT_SYMBOL_GPL(tms9914_return_to_local); + +void tms9914_set_holdoff_mode(struct tms9914_priv *priv, enum tms9914_holdoff_mode mode) +{ + switch (mode) { + case TMS9914_HOLDOFF_NONE: + write_byte(priv, AUX_HLDE, AUXCR); + write_byte(priv, AUX_HLDA, AUXCR); + break; + case TMS9914_HOLDOFF_EOI: + write_byte(priv, AUX_HLDE | AUX_CS, AUXCR); + write_byte(priv, AUX_HLDA, AUXCR); + break; + case TMS9914_HOLDOFF_ALL: + write_byte(priv, AUX_HLDE, AUXCR); + write_byte(priv, AUX_HLDA | AUX_CS, AUXCR); + break; + default: + pr_err("%s: bug! bad holdoff mode %i\n", __func__, mode); + break; + } + priv->holdoff_mode = mode; +} +EXPORT_SYMBOL_GPL(tms9914_set_holdoff_mode); + +void tms9914_release_holdoff(struct tms9914_priv *priv) +{ + if (priv->holdoff_active) { + write_byte(priv, AUX_RHDF, AUXCR); + priv->holdoff_active = 0; + } +} +EXPORT_SYMBOL_GPL(tms9914_release_holdoff); + +int tms9914_enable_eos(gpib_board_t *board, struct tms9914_priv *priv, uint8_t eos_byte, + int compare_8_bits) +{ + priv->eos = eos_byte; + priv->eos_flags = REOS; + if (compare_8_bits) + priv->eos_flags |= BIN; + return 0; +} +EXPORT_SYMBOL(tms9914_enable_eos); + +void tms9914_disable_eos(gpib_board_t *board, struct tms9914_priv *priv) +{ + priv->eos_flags &= ~REOS; +} +EXPORT_SYMBOL(tms9914_disable_eos); + +int tms9914_parallel_poll(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *result) +{ + // execute parallel poll + write_byte(priv, AUX_CS | AUX_RPP, AUXCR); + udelay(2); + *result = read_byte(priv, CPTR); + // clear parallel poll state + write_byte(priv, AUX_RPP, AUXCR); + return 0; +} +EXPORT_SYMBOL(tms9914_parallel_poll); + +static void set_ppoll_reg(struct tms9914_priv *priv, int enable, + unsigned int dio_line, int sense, int ist) +{ + u8 dio_byte; + + if (enable && ((sense && ist) || (!sense && !ist))) { + dio_byte = 1 << (dio_line - 1); + write_byte(priv, dio_byte, PPR); + } else { + write_byte(priv, 0, PPR); + } +} + +void tms9914_parallel_poll_configure(gpib_board_t *board, + struct tms9914_priv *priv, uint8_t config) +{ + priv->ppoll_enable = (config & PPC_DISABLE) == 0; + priv->ppoll_line = (config & PPC_DIO_MASK) + 1; + priv->ppoll_sense = (config & PPC_SENSE) != 0; + set_ppoll_reg(priv, priv->ppoll_enable, priv->ppoll_line, priv->ppoll_sense, board->ist); +} +EXPORT_SYMBOL(tms9914_parallel_poll_configure); + +void tms9914_parallel_poll_response(gpib_board_t *board, + struct tms9914_priv *priv, int ist) +{ + set_ppoll_reg(priv, priv->ppoll_enable, priv->ppoll_line, priv->ppoll_sense, ist); +} +EXPORT_SYMBOL(tms9914_parallel_poll_response); + +void tms9914_serial_poll_response(gpib_board_t *board, struct tms9914_priv *priv, uint8_t status) +{ + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + write_byte(priv, status, SPMR); + priv->spoll_status = status; + if (status & request_service_bit) + write_byte(priv, AUX_RSV2 | AUX_CS, AUXCR); + else + write_byte(priv, AUX_RSV2, AUXCR); + spin_unlock_irqrestore(&board->spinlock, flags); +} +EXPORT_SYMBOL(tms9914_serial_poll_response); + +uint8_t tms9914_serial_poll_status(gpib_board_t *board, struct tms9914_priv *priv) +{ + u8 status; + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + status = priv->spoll_status; + spin_unlock_irqrestore(&board->spinlock, flags); + + return status; +} +EXPORT_SYMBOL(tms9914_serial_poll_status); + +int tms9914_primary_address(gpib_board_t *board, struct tms9914_priv *priv, unsigned int address) +{ + // put primary address in address0 + write_byte(priv, address & ADDRESS_MASK, ADR); + return 0; +} +EXPORT_SYMBOL(tms9914_primary_address); + +int tms9914_secondary_address(gpib_board_t *board, struct tms9914_priv *priv, + unsigned int address, int enable) +{ + if (enable) + priv->imr1_bits |= HR_APTIE; + else + priv->imr1_bits &= ~HR_APTIE; + + write_byte(priv, priv->imr1_bits, IMR1); + return 0; +} +EXPORT_SYMBOL(tms9914_secondary_address); + +unsigned int tms9914_update_status(gpib_board_t *board, struct tms9914_priv *priv, + unsigned int clear_mask) +{ + unsigned long flags; + unsigned int retval; + + spin_lock_irqsave(&board->spinlock, flags); + retval = update_status_nolock(board, priv); + board->status &= ~clear_mask; + spin_unlock_irqrestore(&board->spinlock, flags); + + return retval; +} +EXPORT_SYMBOL(tms9914_update_status); + +static void update_talker_state(struct tms9914_priv *priv, unsigned int address_status_bits) +{ + if (address_status_bits & HR_TA) { + if (address_status_bits & HR_ATN) + priv->talker_state = talker_addressed; + else + /* this could also be serial_poll_active, but the tms9914 provides no + * way to distinguish, so we'll assume talker_active + */ + priv->talker_state = talker_active; + } else { + priv->talker_state = talker_idle; + } +} + +static void update_listener_state(struct tms9914_priv *priv, unsigned int address_status_bits) +{ + if (address_status_bits & HR_LA) { + if (address_status_bits & HR_ATN) + priv->listener_state = listener_addressed; + else + priv->listener_state = listener_active; + } else { + priv->listener_state = listener_idle; + } +} + +static unsigned int update_status_nolock(gpib_board_t *board, struct tms9914_priv *priv) +{ + int address_status; + int bsr_bits; + + address_status = read_byte(priv, ADSR); + + // check for remote/local + if (address_status & HR_REM) + set_bit(REM_NUM, &board->status); + else + clear_bit(REM_NUM, &board->status); + // check for lockout + if (address_status & HR_LLO) + set_bit(LOK_NUM, &board->status); + else + clear_bit(LOK_NUM, &board->status); + // check for ATN + if (address_status & HR_ATN) + set_bit(ATN_NUM, &board->status); + else + clear_bit(ATN_NUM, &board->status); + // check for talker/listener addressed + update_talker_state(priv, address_status); + if (priv->talker_state == talker_active || priv->talker_state == talker_addressed) + set_bit(TACS_NUM, &board->status); + else + clear_bit(TACS_NUM, &board->status); + + update_listener_state(priv, address_status); + if (priv->listener_state == listener_active || priv->listener_state == listener_addressed) + set_bit(LACS_NUM, &board->status); + else + clear_bit(LACS_NUM, &board->status); + // Check for SRQI - not reset elsewhere except in autospoll + if (board->status & SRQI) { + bsr_bits = read_byte(priv, BSR); + if (!(bsr_bits & BSR_SRQ_BIT)) + clear_bit(SRQI_NUM, &board->status); + } + + dev_dbg(board->gpib_dev, "status 0x%lx, state 0x%lx\n", board->status, priv->state); + + return board->status; +} + +int tms9914_line_status(const gpib_board_t *board, struct tms9914_priv *priv) +{ + int bsr_bits; + int status = ValidALL; + + bsr_bits = read_byte(priv, BSR); + + if (bsr_bits & BSR_REN_BIT) + status |= BusREN; + if (bsr_bits & BSR_IFC_BIT) + status |= BusIFC; + if (bsr_bits & BSR_SRQ_BIT) + status |= BusSRQ; + if (bsr_bits & BSR_EOI_BIT) + status |= BusEOI; + if (bsr_bits & BSR_NRFD_BIT) + status |= BusNRFD; + if (bsr_bits & BSR_NDAC_BIT) + status |= BusNDAC; + if (bsr_bits & BSR_DAV_BIT) + status |= BusDAV; + if (bsr_bits & BSR_ATN_BIT) + status |= BusATN; + + return status; +} +EXPORT_SYMBOL(tms9914_line_status); + +static int check_for_eos(struct tms9914_priv *priv, uint8_t byte) +{ + static const u8 seven_bit_compare_mask = 0x7f; + + if ((priv->eos_flags & REOS) == 0) + return 0; + + if (priv->eos_flags & BIN) { + if (priv->eos == byte) + return 1; + } else { + if ((priv->eos & seven_bit_compare_mask) == (byte & seven_bit_compare_mask)) + return 1; + } + return 0; +} + +static int wait_for_read_byte(gpib_board_t *board, struct tms9914_priv *priv) +{ + if (wait_event_interruptible(board->wait, + test_bit(READ_READY_BN, &priv->state) || + test_bit(DEV_CLEAR_BN, &priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_debug("gpib: pio read wait interrupted\n"); + return -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + return -ETIMEDOUT; + + if (test_bit(DEV_CLEAR_BN, &priv->state)) + return -EINTR; + return 0; +} + +static inline uint8_t tms9914_read_data_in(gpib_board_t *board, struct tms9914_priv *priv, int *end) +{ + unsigned long flags; + u8 data; + + spin_lock_irqsave(&board->spinlock, flags); + clear_bit(READ_READY_BN, &priv->state); + data = read_byte(priv, DIR); + if (test_and_clear_bit(RECEIVED_END_BN, &priv->state)) + *end = 1; + else + *end = 0; + switch (priv->holdoff_mode) { + case TMS9914_HOLDOFF_EOI: + if (*end) + priv->holdoff_active = 1; + break; + case TMS9914_HOLDOFF_ALL: + priv->holdoff_active = 1; + break; + case TMS9914_HOLDOFF_NONE: + break; + default: + pr_err("%s: bug! bad holdoff mode %i\n", __func__, priv->holdoff_mode); + break; + } + spin_unlock_irqrestore(&board->spinlock, flags); + + return data; +} + +static int pio_read(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + ssize_t retval = 0; + + *bytes_read = 0; + *end = 0; + while (*bytes_read < length && *end == 0) { + tms9914_release_holdoff(priv); + retval = wait_for_read_byte(board, priv); + if (retval < 0) + return retval; + buffer[(*bytes_read)++] = tms9914_read_data_in(board, priv, end); + + if (check_for_eos(priv, buffer[*bytes_read - 1])) + *end = 1; + } + + return retval; +} + +int tms9914_read(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *buffer, + size_t length, int *end, size_t *bytes_read) +{ + ssize_t retval = 0; + size_t num_bytes; + + *end = 0; + *bytes_read = 0; + if (length == 0) + return 0; + + clear_bit(DEV_CLEAR_BN, &priv->state); + + // transfer data (except for last byte) + if (length > 1) { + if (priv->eos_flags & REOS) + tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_ALL); + else + tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_EOI); + // PIO transfer + retval = pio_read(board, priv, buffer, length - 1, end, &num_bytes); + *bytes_read += num_bytes; + if (retval < 0) + return retval; + buffer += num_bytes; + length -= num_bytes; + } + // read last bytes if we havn't received an END yet + if (*end == 0) { + // make sure we holdoff after last byte read + tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_ALL); + retval = pio_read(board, priv, buffer, length, end, &num_bytes); + *bytes_read += num_bytes; + if (retval < 0) + return retval; + } + return 0; +} +EXPORT_SYMBOL(tms9914_read); + +static int pio_write_wait(gpib_board_t *board, struct tms9914_priv *priv) +{ + // wait until next byte is ready to be sent + if (wait_event_interruptible(board->wait, + test_bit(WRITE_READY_BN, &priv->state) || + test_bit(BUS_ERROR_BN, &priv->state) || + test_bit(DEV_CLEAR_BN, &priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib write interrupted!\n"); + return -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + return -ETIMEDOUT; + if (test_bit(BUS_ERROR_BN, &priv->state)) + return -EIO; + if (test_bit(DEV_CLEAR_BN, &priv->state)) + return -EINTR; + + return 0; +} + +static int pio_write(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *buffer, + size_t length, size_t *bytes_written) +{ + ssize_t retval = 0; + unsigned long flags; + + *bytes_written = 0; + while (*bytes_written < length) { + retval = pio_write_wait(board, priv); + if (retval < 0) + break; + + spin_lock_irqsave(&board->spinlock, flags); + clear_bit(WRITE_READY_BN, &priv->state); + write_byte(priv, buffer[(*bytes_written)++], CDOR); + spin_unlock_irqrestore(&board->spinlock, flags); + } + retval = pio_write_wait(board, priv); + if (retval < 0) + return retval; + + return length; +} + +int tms9914_write(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written) +{ + ssize_t retval = 0; + + *bytes_written = 0; + if (length == 0) + return 0; + + clear_bit(BUS_ERROR_BN, &priv->state); + clear_bit(DEV_CLEAR_BN, &priv->state); + + if (send_eoi) + length-- ; /* save the last byte for sending EOI */ + + if (length > 0) { + size_t num_bytes; + // PIO transfer + retval = pio_write(board, priv, buffer, length, &num_bytes); + *bytes_written += num_bytes; + if (retval < 0) + return retval; + } + if (send_eoi) { + size_t num_bytes; + /*send EOI */ + write_byte(priv, AUX_SEOI, AUXCR); + + retval = pio_write(board, priv, &buffer[*bytes_written], 1, &num_bytes); + *bytes_written += num_bytes; + } + return retval; +} +EXPORT_SYMBOL(tms9914_write); + +static void check_my_address_state(gpib_board_t *board, struct tms9914_priv *priv, int cmd_byte) +{ + if (cmd_byte == MLA(board->pad)) { + priv->primary_listen_addressed = 1; + // become active listener + if (board->sad < 0) + write_byte(priv, AUX_LON | AUX_CS, AUXCR); + } else if (board->sad >= 0 && priv->primary_listen_addressed && + cmd_byte == MSA(board->sad)) { + // become active listener + write_byte(priv, AUX_LON | AUX_CS, AUXCR); + } else if (cmd_byte != MLA(board->pad) && (cmd_byte & 0xe0) == LAD) { + priv->primary_listen_addressed = 0; + } else if (cmd_byte == UNL) { + priv->primary_listen_addressed = 0; + write_byte(priv, AUX_LON, AUXCR); + } else if (cmd_byte == MTA(board->pad)) { + priv->primary_talk_addressed = 1; + if (board->sad < 0) + //make active talker + write_byte(priv, AUX_TON | AUX_CS, AUXCR); + } else if (board->sad >= 0 && priv->primary_talk_addressed && + cmd_byte == MSA(board->sad)) { + // become active talker + write_byte(priv, AUX_TON | AUX_CS, AUXCR); + } else if (cmd_byte != MTA(board->pad) && (cmd_byte & 0xe0) == TAD) { + // Other Talk Address + priv->primary_talk_addressed = 0; + write_byte(priv, AUX_TON, AUXCR); + } else if (cmd_byte == UNT) { + priv->primary_talk_addressed = 0; + write_byte(priv, AUX_TON, AUXCR); + } +} + +int tms9914_command(gpib_board_t *board, struct tms9914_priv *priv, uint8_t *buffer, + size_t length, size_t *bytes_written) +{ + int retval = 0; + unsigned long flags; + + *bytes_written = 0; + while (*bytes_written < length) { + if (wait_event_interruptible(board->wait, + test_bit(COMMAND_READY_BN, + &priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_debug("gpib command wait interrupted\n"); + break; + } + if (test_bit(TIMO_NUM, &board->status)) + break; + + spin_lock_irqsave(&board->spinlock, flags); + clear_bit(COMMAND_READY_BN, &priv->state); + write_byte(priv, buffer[*bytes_written], CDOR); + spin_unlock_irqrestore(&board->spinlock, flags); + + check_my_address_state(board, priv, buffer[*bytes_written]); + + ++(*bytes_written); + } + // wait until last command byte is written + if (wait_event_interruptible(board->wait, + test_bit(COMMAND_READY_BN, + &priv->state) || test_bit(TIMO_NUM, &board->status))) + retval = -ERESTARTSYS; + if (test_bit(TIMO_NUM, &board->status)) + retval = -ETIMEDOUT; + + return retval; +} +EXPORT_SYMBOL(tms9914_command); + +irqreturn_t tms9914_interrupt(gpib_board_t *board, struct tms9914_priv *priv) +{ + int status0, status1; + + // read interrupt status (also clears status) + status0 = read_byte(priv, ISR0); + status1 = read_byte(priv, ISR1); + return tms9914_interrupt_have_status(board, priv, status0, status1); +} +EXPORT_SYMBOL(tms9914_interrupt); + +irqreturn_t tms9914_interrupt_have_status(gpib_board_t *board, struct tms9914_priv *priv, + int status0, int status1) +{ + // record reception of END + if (status0 & HR_END) + set_bit(RECEIVED_END_BN, &priv->state); + // get incoming data in PIO mode + if ((status0 & HR_BI)) + set_bit(READ_READY_BN, &priv->state); + if ((status0 & HR_BO)) { + if (read_byte(priv, ADSR) & HR_ATN) + set_bit(COMMAND_READY_BN, &priv->state); + else + set_bit(WRITE_READY_BN, &priv->state); + } + + if (status0 & HR_SPAS) { + priv->spoll_status &= ~request_service_bit; + write_byte(priv, priv->spoll_status, SPMR); + //FIXME: set SPOLL status bit + } + // record service request in status + if (status1 & HR_SRQ) + set_bit(SRQI_NUM, &board->status); + // have been addressed (with secondary addressing disabled) + if (status1 & HR_MA) + // clear dac holdoff + write_byte(priv, AUX_VAL, AUXCR); + // unrecognized command received + if (status1 & HR_UNC) { + unsigned short command_byte = read_byte(priv, CPTR) & gpib_command_mask; + + switch (command_byte) { + case PPConfig: + priv->ppoll_configure_state = 1; + /* AUX_PTS generates another UNC interrupt on the next command byte + * if it is in the secondary address group (such as PPE and PPD). + */ + write_byte(priv, AUX_PTS, AUXCR); + write_byte(priv, AUX_VAL, AUXCR); + break; + case PPU: + tms9914_parallel_poll_configure(board, priv, command_byte); + write_byte(priv, AUX_VAL, AUXCR); + break; + default: + if (is_PPE(command_byte) || is_PPD(command_byte)) { + if (priv->ppoll_configure_state) { + tms9914_parallel_poll_configure(board, priv, command_byte); + write_byte(priv, AUX_VAL, AUXCR); + } else {// bad parallel poll configure byte + // clear dac holdoff + write_byte(priv, AUX_INVAL, AUXCR); + } + } else { + // printk("tms9914: unrecognized gpib command pass thru 0x%x\n", + // command_byte); + // clear dac holdoff + write_byte(priv, AUX_INVAL, AUXCR); + } + break; + } + + if (in_primary_command_group(command_byte) && command_byte != PPConfig) + priv->ppoll_configure_state = 0; + } + + if (status1 & HR_ERR) { + dev_dbg(board->gpib_dev, "gpib bus error\n"); + set_bit(BUS_ERROR_BN, &priv->state); + } + + if (status1 & HR_IFC) { + push_gpib_event(board, EventIFC); + clear_bit(CIC_NUM, &board->status); + } + + if (status1 & HR_GET) { + push_gpib_event(board, EventDevTrg); + // clear dac holdoff + write_byte(priv, AUX_VAL, AUXCR); + } + + if (status1 & HR_DCAS) { + push_gpib_event(board, EventDevClr); + // clear dac holdoff + write_byte(priv, AUX_VAL, AUXCR); + set_bit(DEV_CLEAR_BN, &priv->state); + } + + // check for being addressed with secondary addressing + if (status1 & HR_APT) { + if (board->sad < 0) + pr_err("tms9914: bug, APT interrupt without secondary addressing?\n"); + if ((read_byte(priv, CPTR) & gpib_command_mask) == MSA(board->sad)) + write_byte(priv, AUX_VAL, AUXCR); + else + write_byte(priv, AUX_INVAL, AUXCR); + } + + if ((status0 & priv->imr0_bits) || (status1 & priv->imr1_bits)) { +// dev_dbg(board->gpib_dev, "isr0 0x%x, imr0 0x%x, isr1 0x%x, imr1 0x%x\n", +// status0, priv->imr0_bits, status1, priv->imr1_bits); + update_status_nolock(board, priv); + wake_up_interruptible(&board->wait); + } + return IRQ_HANDLED; +} +EXPORT_SYMBOL(tms9914_interrupt_have_status); + +void tms9914_board_reset(struct tms9914_priv *priv) +{ + /* chip reset */ + write_byte(priv, AUX_CHIP_RESET | AUX_CS, AUXCR); + + /* disable all interrupts */ + priv->imr0_bits = 0; + write_byte(priv, priv->imr0_bits, IMR0); + priv->imr1_bits = 0; + write_byte(priv, priv->imr1_bits, IMR1); + write_byte(priv, AUX_DAI | AUX_CS, AUXCR); + + /* clear registers by reading */ + read_byte(priv, CPTR); + read_byte(priv, ISR0); + read_byte(priv, ISR1); + + write_byte(priv, 0, SPMR); + + /* parallel poll unconfigure */ + write_byte(priv, 0, PPR); + // request for data holdoff + tms9914_set_holdoff_mode(priv, TMS9914_HOLDOFF_ALL); +} +EXPORT_SYMBOL_GPL(tms9914_board_reset); + +void tms9914_online(gpib_board_t *board, struct tms9914_priv *priv) +{ + /* set GPIB address */ + tms9914_primary_address(board, priv, board->pad); + tms9914_secondary_address(board, priv, board->sad, board->sad >= 0); + + // enable tms9914 interrupts + priv->imr0_bits |= HR_MACIE | HR_RLCIE | HR_ENDIE | HR_BOIE | HR_BIIE | + HR_SPASIE; + priv->imr1_bits |= HR_MAIE | HR_SRQIE | HR_UNCIE | HR_ERRIE | HR_IFCIE | + HR_GETIE | HR_DCASIE; + write_byte(priv, priv->imr0_bits, IMR0); + write_byte(priv, priv->imr1_bits, IMR1); + write_byte(priv, AUX_DAI, AUXCR); + + // turn off reset state + write_byte(priv, AUX_CHIP_RESET, AUXCR); +} +EXPORT_SYMBOL_GPL(tms9914_online); + +#ifdef CONFIG_HAS_IOPORT +// wrapper for inb +uint8_t tms9914_ioport_read_byte(struct tms9914_priv *priv, unsigned int register_num) +{ + return inb((unsigned long)(priv->iobase) + register_num * priv->offset); +} +EXPORT_SYMBOL_GPL(tms9914_ioport_read_byte); + +// wrapper for outb +void tms9914_ioport_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num) +{ + outb(data, (unsigned long)(priv->iobase) + register_num * priv->offset); + if (register_num == AUXCR) + udelay(1); +} +EXPORT_SYMBOL_GPL(tms9914_ioport_write_byte); +#endif + +// wrapper for readb +uint8_t tms9914_iomem_read_byte(struct tms9914_priv *priv, unsigned int register_num) +{ + return readb(priv->iobase + register_num * priv->offset); +} +EXPORT_SYMBOL_GPL(tms9914_iomem_read_byte); + +// wrapper for writeb +void tms9914_iomem_write_byte(struct tms9914_priv *priv, uint8_t data, unsigned int register_num) +{ + writeb(data, priv->iobase + register_num * priv->offset); + if (register_num == AUXCR) + udelay(1); +} +EXPORT_SYMBOL_GPL(tms9914_iomem_write_byte); + +static int __init tms9914_init_module(void) +{ + return 0; +} + +static void __exit tms9914_exit_module(void) +{ +} + +module_init(tms9914_init_module); +module_exit(tms9914_exit_module); + diff --git a/drivers/staging/gpib/tnt4882/Makefile b/drivers/staging/gpib/tnt4882/Makefile new file mode 100644 index 00000000000000..f767c990db7a09 --- /dev/null +++ b/drivers/staging/gpib/tnt4882/Makefile @@ -0,0 +1,7 @@ +ccflags-$(CONFIG_GPIB_PCMCIA) := -DGPIB_PCMCIA +obj-m += tnt4882.o + +tnt4882-objs := tnt4882_gpib.o mite.o + + + diff --git a/drivers/staging/gpib/tnt4882/mite.c b/drivers/staging/gpib/tnt4882/mite.c new file mode 100644 index 00000000000000..0edf34d243e9e8 --- /dev/null +++ b/drivers/staging/gpib/tnt4882/mite.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2 + +/* + * Hardware driver for NI Mite PCI interface chip, + * adapted from COMEDI + * + * Copyright (C) 1997-8 David A. Schleef + * Copyright (C) 2002 Frank Mori Hess + * + * The PCI-MIO E series driver was originally written by + * Tomasz Motylewski <...>, and ported to comedi by ds. + * + * References for specifications: + * + * 321747b.pdf Register Level Programmer Manual (obsolete) + * 321747c.pdf Register Level Programmer Manual (new) + * DAQ-STC reference manual + * + * Other possibly relevant info: + * + * 320517c.pdf User manual (obsolete) + * 320517f.pdf User manual (new) + * 320889a.pdf delete + * 320906c.pdf maximum signal ratings + * 321066a.pdf about 16x + * 321791a.pdf discontinuation of at-mio-16e-10 rev. c + * 321808a.pdf about at-mio-16e-10 rev P + * 321837a.pdf discontinuation of at-mio-16de-10 rev d + * 321838a.pdf about at-mio-16de-10 rev N + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mite.h" + +#define PCI_MITE_SIZE 4096 +#define PCI_DAQ_SIZE 4096 + +struct mite_struct *mite_devices; + +#define TOP_OF_PAGE(x) ((x) | (~(PAGE_MASK))) + +void mite_init(void) +{ + struct pci_dev *pcidev; + struct mite_struct *mite; + + for (pcidev = pci_get_device(PCI_VENDOR_ID_NATINST, PCI_ANY_ID, NULL); + pcidev; + pcidev = pci_get_device(PCI_VENDOR_ID_NATINST, PCI_ANY_ID, pcidev)) { + mite = kzalloc(sizeof(*mite), GFP_KERNEL); + if (!mite) + return; + + mite->pcidev = pcidev; + pci_dev_get(mite->pcidev); + mite->next = mite_devices; + mite_devices = mite; + } +} + +int mite_setup(struct mite_struct *mite) +{ + u32 addr; + + if (pci_enable_device(mite->pcidev)) { + pr_err("mite: error enabling mite.\n"); + return -EIO; + } + pci_set_master(mite->pcidev); + if (pci_request_regions(mite->pcidev, "mite")) { + pr_err("mite: failed to request mite io regions.\n"); + return -EIO; + } + addr = pci_resource_start(mite->pcidev, 0); + mite->mite_phys_addr = addr; + mite->mite_io_addr = ioremap(addr, pci_resource_len(mite->pcidev, 0)); + if (!mite->mite_io_addr) { + pr_err("mite: failed to remap mite io memory address.\n"); + return -ENOMEM; + } + pr_info("mite: 0x%08lx mapped to %p\n", mite->mite_phys_addr, mite->mite_io_addr); + addr = pci_resource_start(mite->pcidev, 1); + mite->daq_phys_addr = addr; + mite->daq_io_addr = ioremap(mite->daq_phys_addr, pci_resource_len(mite->pcidev, 1)); + if (!mite->daq_io_addr) { + pr_err("mite: failed to remap daq io memory address.\n"); + return -ENOMEM; + } + pr_info("mite: daq: 0x%08lx mapped to %p\n", mite->daq_phys_addr, mite->daq_io_addr); + writel(mite->daq_phys_addr | WENAB, mite->mite_io_addr + MITE_IODWBSR); + mite->used = 1; + return 0; +} + +void mite_cleanup(void) +{ + struct mite_struct *mite, *next; + + for (mite = mite_devices; mite; mite = next) { + next = mite->next; + if (mite->pcidev) + pci_dev_put(mite->pcidev); + kfree(mite); + } +} + +void mite_unsetup(struct mite_struct *mite) +{ + if (!mite) + return; + if (mite->mite_io_addr) { + iounmap(mite->mite_io_addr); + mite->mite_io_addr = NULL; + } + if (mite->daq_io_addr) { + iounmap(mite->daq_io_addr); + mite->daq_io_addr = NULL; + } + if (mite->mite_phys_addr) { + pci_release_regions(mite->pcidev); + pci_disable_device(mite->pcidev); + mite->mite_phys_addr = 0; + } + mite->used = 0; +} + +void mite_list_devices(void) +{ + struct mite_struct *mite, *next; + + pr_info("Available NI PCI device IDs:"); + if (mite_devices) + for (mite = mite_devices; mite; mite = next) { + next = mite->next; + pr_info(" 0x%04x", mite_device_id(mite)); + if (mite->used) + pr_info("(used)"); + } + pr_info("\n"); +} + +int mite_bytes_transferred(struct mite_struct *mite, int chan) +{ + int dar, fcr; + + dar = readl(mite->mite_io_addr + MITE_DAR + CHAN_OFFSET(chan)); + fcr = readl(mite->mite_io_addr + MITE_FCR + CHAN_OFFSET(chan)) & 0x000000FF; + return dar - fcr; +} + +int mite_dma_tcr(struct mite_struct *mite) +{ + int tcr; + int lkar; + + lkar = readl(mite->mite_io_addr + CHAN_OFFSET(0) + MITE_LKAR); + tcr = readl(mite->mite_io_addr + CHAN_OFFSET(0) + MITE_TCR); + MDPRINTK("lkar=0x%08x tcr=%d\n", lkar, tcr); + + return tcr; +} + +void mite_dma_disarm(struct mite_struct *mite) +{ + int chor; + + /* disarm */ + chor = CHOR_ABORT; + writel(chor, mite->mite_io_addr + CHAN_OFFSET(0) + MITE_CHOR); +} + +void mite_dump_regs(struct mite_struct *mite) +{ + void *addr = 0; + unsigned long temp = 0; + + pr_info("mite address is =0x%p\n", mite->mite_io_addr); + + addr = mite->mite_io_addr + MITE_CHOR + CHAN_OFFSET(0); + pr_info("mite status[CHOR]at 0x%p =0x%08lx\n", addr, temp = readl(addr)); + //mite_decode(mite_CHOR_strings,temp); + addr = mite->mite_io_addr + MITE_CHCR + CHAN_OFFSET(0); + pr_info("mite status[CHCR]at 0x%p =0x%08lx\n", addr, temp = readl(addr)); + //mite_decode(mite_CHCR_strings,temp); + addr = mite->mite_io_addr + MITE_TCR + CHAN_OFFSET(0); + pr_info("mite status[TCR] at 0x%p =0x%08x\n", addr, readl(addr)); + addr = mite->mite_io_addr + MITE_MCR + CHAN_OFFSET(0); + pr_info("mite status[MCR] at 0x%p =0x%08lx\n", addr, temp = readl(addr)); + //mite_decode(mite_MCR_strings,temp); + addr = mite->mite_io_addr + MITE_MAR + CHAN_OFFSET(0); + pr_info("mite status[MAR] at 0x%p =0x%08x\n", addr, readl(addr)); + addr = mite->mite_io_addr + MITE_DCR + CHAN_OFFSET(0); + pr_info("mite status[DCR] at 0x%p =0x%08lx\n", addr, temp = readl(addr)); + //mite_decode(mite_CR_strings,temp); + addr = mite->mite_io_addr + MITE_DAR + CHAN_OFFSET(0); + pr_info("mite status[DAR] at 0x%p =0x%08x\n", addr, readl(addr)); + addr = mite->mite_io_addr + MITE_LKCR + CHAN_OFFSET(0); + pr_info("mite status[LKCR]at 0x%p =0x%08lx\n", addr, temp = readl(addr)); + //mite_decode(mite_CR_strings,temp); + addr = mite->mite_io_addr + MITE_LKAR + CHAN_OFFSET(0); + pr_info("mite status[LKAR]at 0x%p =0x%08x\n", addr, readl(addr)); + + addr = mite->mite_io_addr + MITE_CHSR + CHAN_OFFSET(0); + pr_info("mite status[CHSR]at 0x%p =0x%08lx\n", addr, temp = readl(addr)); + //mite_decode(mite_CHSR_strings,temp); + addr = mite->mite_io_addr + MITE_FCR + CHAN_OFFSET(0); + pr_info("mite status[FCR] at 0x%p =0x%08x\n\n", addr, readl(addr)); +} + diff --git a/drivers/staging/gpib/tnt4882/mite.h b/drivers/staging/gpib/tnt4882/mite.h new file mode 100644 index 00000000000000..6454d069b8cc4e --- /dev/null +++ b/drivers/staging/gpib/tnt4882/mite.h @@ -0,0 +1,243 @@ +/* SPDX-License-Identifier: GPL-2 */ + +/* + * Hardware driver for NI Mite PCI interface chip + * + * Copyright (C) 1999 David A. Schleef + */ + +#ifndef _MITE_H_ +#define _MITE_H_ + +#include + +#define PCI_VENDOR_ID_NATINST 0x1093 + +//#define DEBUG_MITE + +#ifdef DEBUG_MITE +#define MDPRINTK(format, args...) pr_debug(format, ## args) +#else +#define MDPRINTK(args...) +#endif + +#define MITE_RING_SIZE 3000 +struct mite_dma_chain { + u32 count; + u32 addr; + u32 next; +}; + +struct mite_struct { + struct mite_struct *next; + int used; + + struct pci_dev *pcidev; + unsigned long mite_phys_addr; + void *mite_io_addr; + unsigned long daq_phys_addr; + void *daq_io_addr; + + int DMA_CheckNearEnd; + + struct mite_dma_chain ring[MITE_RING_SIZE]; +}; + +extern struct mite_struct *mite_devices; + +extern inline unsigned int mite_irq(struct mite_struct *mite) +{ + return mite->pcidev->irq; +}; + +extern inline unsigned int mite_device_id(struct mite_struct *mite) +{ + return mite->pcidev->device; +}; + +void mite_init(void); +void mite_cleanup(void); +int mite_setup(struct mite_struct *mite); +void mite_unsetup(struct mite_struct *mite); +void mite_list_devices(void); + +int mite_dma_tcr(struct mite_struct *mite); + +void mite_dma_arm(struct mite_struct *mite); +void mite_dma_disarm(struct mite_struct *mite); + +void mite_dump_regs(struct mite_struct *mite); +void mite_setregs(struct mite_struct *mite, unsigned long ll_start, int chan, int dir); +int mite_bytes_transferred(struct mite_struct *mite, int chan); + +#define CHAN_OFFSET(x) (0x100 * (x)) + +/* DMA base for chan 0 is 0x500, chan 1 is 0x600 */ + +#define MITE_CHOR 0x500 +#define CHOR_DMARESET BIT(31) +#define CHOR_SET_SEND_TC BIT(11) +#define CHOR_CLR_SEND_TC BIT(10) +#define CHOR_SET_LPAUSE BIT(9) +#define CHOR_CLR_LPAUSE BIT(8) +#define CHOR_CLRDONE BIT(7) +#define CHOR_CLRRB BIT(6) +#define CHOR_CLRLC BIT(5) +#define CHOR_FRESET BIT(4) +#define CHOR_ABORT BIT(3) +#define CHOR_STOP BIT(2) +#define CHOR_CONT BIT(1) +#define CHOR_START BIT(0) +#define CHOR_PON (CHOR_CLR_SEND_TC | CHOR_CLR_LPAUSE) + +#define MITE_CHCR 0x504 +#define CHCR_SET_DMA_IE BIT(31) +#define CHCR_CLR_DMA_IE BIT(30) +#define CHCR_SET_LINKP_IE BIT(29) +#define CHCR_CLR_LINKP_IE BIT(28) +#define CHCR_SET_SAR_IE BIT(27) +#define CHCR_CLR_SAR_IE BIT(26) +#define CHCR_SET_DONE_IE BIT(25) +#define CHCR_CLR_DONE_IE BIT(24) +#define CHCR_SET_MRDY_IE BIT(23) +#define CHCR_CLR_MRDY_IE BIT(22) +#define CHCR_SET_DRDY_IE BIT(21) +#define CHCR_CLR_DRDY_IE BIT(20) +#define CHCR_SET_LC_IE BIT(19) +#define CHCR_CLR_LC_IE BIT(18) +#define CHCR_SET_CONT_RB_IE BIT(17) +#define CHCR_CLR_CONT_RB_IE BIT(16) +#define CHCR_FIFODIS BIT(15) +#define CHCR_FIFO_ON 0 +#define CHCR_BURSTEN BIT(14) +#define CHCR_NO_BURSTEN 0 +#define CHCR_NFTP(x) ((x) << 11) +#define CHCR_NFTP0 CHCR_NFTP(0) +#define CHCR_NFTP1 CHCR_NFTP(1) +#define CHCR_NFTP2 CHCR_NFTP(2) +#define CHCR_NFTP4 CHCR_NFTP(3) +#define CHCR_NFTP8 CHCR_NFTP(4) +#define CHCR_NFTP16 CHCR_NFTP(5) +#define CHCR_NETP(x) ((x) << 11) +#define CHCR_NETP0 CHCR_NETP(0) +#define CHCR_NETP1 CHCR_NETP(1) +#define CHCR_NETP2 CHCR_NETP(2) +#define CHCR_NETP4 CHCR_NETP(3) +#define CHCR_NETP8 CHCR_NETP(4) +#define CHCR_CHEND1 BIT(5) +#define CHCR_CHEND0 BIT(4) +#define CHCR_DIR BIT(3) +#define CHCR_DEV_TO_MEM CHCR_DIR +#define CHCR_MEM_TO_DEV 0 +#define CHCR_NORMAL ((0) << 0) +#define CHCR_CONTINUE ((1) << 0) +#define CHCR_RINGBUFF ((2) << 0) +#define CHCR_LINKSHORT ((4) << 0) +#define CHCR_LINKLONG ((5) << 0) +#define CHCRPON (CHCR_CLR_DMA_IE | CHCR_CLR_LINKP_IE | CHCR_CLR_SAR_IE | \ + CHCR_CLR_DONE_IE | CHCR_CLR_MRDY_IE | CHCR_CLR_DRDY_IE | \ + CHCR_CLR_LC_IE | CHCR_CLR_CONT_IE) + +#define MITE_TCR 0x508 + +/* CR bits */ +#define CR_RL(x) ((x) << 21) +#define CR_RL0 CR_RL(0) +#define CR_RL1 CR_RL(1) +#define CR_RL2 CR_RL(2) +#define CR_RL4 CR_RL(3) +#define CR_RL8 CR_RL(4) +#define CR_RL16 CR_RL(5) +#define CR_RL32 CR_RL(6) +#define CR_RL64 CR_RL(7) +#define CR_RD(x) ((x) << 19) +#define CR_RD0 CR_RD(0) +#define CR_RD32 CR_RD(1) +#define CR_RD512 CR_RD(2) +#define CR_RD8192 CR_RD(3) +#define CR_REQS(x) ((x) << 16) +#define CR_REQSDRQ0 CR_REQS(4) +#define CR_REQSDRQ1 CR_REQS(5) +#define CR_REQSDRQ2 CR_REQS(6) +#define CR_REQSDRQ3 CR_REQS(7) +#define CR_ASEQX(x) ((x) << 10) +#define CR_ASEQX0 CR_ASEQX(0) +#define CR_ASEQDONT CR_ASEQX0 +#define CR_ASEQXP1 CR_ASEQX(1) +#define CR_ASEQUP CR_ASEQXP1 +#define CR_ASEQXP2 CR_ASEQX(2) +#define CR_ASEQDOWN CR_ASEQXP2 +#define CR_ASEQXP4 CR_ASEQX(3) +#define CR_ASEQXP8 CR_ASEQX(4) +#define CR_ASEQXP16 CR_ASEQX(5) +#define CR_ASEQXP32 CR_ASEQX(6) +#define CR_ASEQXP64 CR_ASEQX(7) +#define CR_ASEQXM1 CR_ASEQX(9) +#define CR_ASEQXM2 CR_ASEQX(10) +#define CR_ASEQXM4 CR_ASEQX(11) +#define CR_ASEQXM8 CR_ASEQX(12) +#define CR_ASEQXM16 CR_ASEQX(13) +#define CR_ASEQXM32 CR_ASEQX(14) +#define CR_ASEQXM64 CR_ASEQX(15) +#define CR_PSIZEBYTE BIT(8) +#define CR_PSIZEHALF (2 << 8) +#define CR_PSIZEWORD (3 << 8) +#define CR_PORTCPU (0 << 6) +#define CR_PORTIO BIT(6) +#define CR_PORTVXI (2 << 6) +#define CR_PORTMXI (3 << 6) +#define CR_AMDEVICE BIT(0) + +#define CHSR_INT 0x80000000 +#define CHSR_DONE 0x02000000 +#define CHSR_LINKC 0x00080000 + +#define MITE_MCR 0x50c +#define MCRPON 0 + +#define MITE_MAR 0x510 + +#define MITE_DCR 0x514 +#define DCR_NORMAL BIT(29) +#define DCRPON 0 + +#define MITE_DAR 0x518 + +#define MITE_LKCR 0x51c + +#define MITE_LKAR 0x520 +#define MITE_LLKAR 0x524 +#define MITE_BAR 0x528 +#define MITE_BCR 0x52c +#define MITE_SAR 0x530 +#define MITE_WSCR 0x534 +#define MITE_WSER 0x538 +#define MITE_CHSR 0x53c +#define MITE_FCR 0x540 + +#define MITE_FIFO 0x80 +#define MITE_FIFOEND 0xff + +#define MITE_AMRAM 0x00 +#define MITE_AMDEVICE 0x01 +#define MITE_AMHOST_A32_SINGLE 0x09 +#define MITE_AMHOST_A24_SINGLE 0x39 +#define MITE_AMHOST_A16_SINGLE 0x29 +#define MITE_AMHOST_A32_BLOCK 0x0b +#define MITE_AMHOST_A32D64_BLOCK 0x08 +#define MITE_AMHOST_A24_BLOCK 0x3b + +enum mite_registers { + MITE_IODWBSR = 0xc0, //IO Device Window Base Size Register + MITE_CSIGR = 0x460, //chip signature + MITE_IODWBSR_1 = 0xc4, // IO Device Window Base Size Register 1 (used by 6602 boards) + MITE_IODWCR_1 = 0xf4 +}; + +enum MITE_IODWBSR_bits { + WENAB = 0x80, // window enable + WENAB_6602 = 0x8c // window enable for 6602 boards +}; + +#endif + diff --git a/drivers/staging/gpib/tnt4882/tnt4882_gpib.c b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c new file mode 100644 index 00000000000000..e49a952fa0d838 --- /dev/null +++ b/drivers/staging/gpib/tnt4882/tnt4882_gpib.c @@ -0,0 +1,1874 @@ +// SPDX-License-Identifier: GPL-2.0 + +/*************************************************************************** + * National Instruments boards using tnt4882 or compatible chips (at-gpib, etc). + * copyright : (C) 2001, 2002 by Frank Mori Hess + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nec7210.h" +#include "gpibP.h" +#include "mite.h" +#include "tnt4882_registers.h" + +static const int ISAPNP_VENDOR_ID_NI = ISAPNP_VENDOR('N', 'I', 'C'); +static const int ISAPNP_ID_NI_ATGPIB_TNT = 0xc601; +enum { + PCI_DEVICE_ID_NI_GPIB = 0xc801, + PCI_DEVICE_ID_NI_GPIB_PLUS = 0xc811, + PCI_DEVICE_ID_NI_GPIB_PLUS2 = 0x71ad, + PCI_DEVICE_ID_NI_PXIGPIB = 0xc821, + PCI_DEVICE_ID_NI_PMCGPIB = 0xc831, + PCI_DEVICE_ID_NI_PCIEGPIB = 0x70cf, + PCI_DEVICE_ID_NI_PCIE2GPIB = 0x710e, +// Measurement Computing PCI-488 same design as PCI-GPIB with TNT5004 + PCI_DEVICE_ID_MC_PCI488 = 0x7259, + PCI_DEVICE_ID_CEC_NI_GPIB = 0x7258 +}; + +// struct which defines private_data for tnt4882 devices +struct tnt4882_priv { + struct nec7210_priv nec7210_priv; + struct mite_struct *mite; + struct pnp_dev *pnp_dev; + unsigned int irq; + unsigned short imr0_bits; + unsigned short imr3_bits; + unsigned short auxg_bits; // bits written to auxiliary register G + void (*io_writeb)(unsigned int value, void *address); + void (*io_writew)(unsigned int value, void *address); + unsigned int (*io_readb)(void *address); + unsigned int (*io_readw)(void *address); +}; + +// interface functions +static int tnt4882_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read); +static int tnt4882_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, + int *end, size_t *bytes_read); +static int tnt4882_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written); +static int tnt4882_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, size_t *bytes_written); +static int tnt4882_command(gpib_board_t *board, uint8_t *buffer, size_t length, + size_t *bytes_written); +static int tnt4882_command_unaccel(gpib_board_t *board, uint8_t *buffer, + size_t length, size_t *bytes_written); +static int tnt4882_take_control(gpib_board_t *board, int synchronous); +static int tnt4882_go_to_standby(gpib_board_t *board); +static void tnt4882_request_system_control(gpib_board_t *board, int request_control); +static void tnt4882_interface_clear(gpib_board_t *board, int assert); +static void tnt4882_remote_enable(gpib_board_t *board, int enable); +static int tnt4882_enable_eos(gpib_board_t *board, uint8_t eos_byte, int + compare_8_bits); +static void tnt4882_disable_eos(gpib_board_t *board); +static unsigned int tnt4882_update_status(gpib_board_t *board, unsigned int clear_mask); +static int tnt4882_primary_address(gpib_board_t *board, unsigned int address); +static int tnt4882_secondary_address(gpib_board_t *board, unsigned int address, + int enable); +static int tnt4882_parallel_poll(gpib_board_t *board, uint8_t *result); +static void tnt4882_parallel_poll_configure(gpib_board_t *board, uint8_t config); +static void tnt4882_parallel_poll_response(gpib_board_t *board, int ist); +static void tnt4882_serial_poll_response(gpib_board_t *board, uint8_t status); +static uint8_t tnt4882_serial_poll_status(gpib_board_t *board); +static int tnt4882_line_status(const gpib_board_t *board); +static unsigned int tnt4882_t1_delay(gpib_board_t *board, unsigned int nano_sec); +static void tnt4882_return_to_local(gpib_board_t *board); + +// interrupt service routines +static irqreturn_t tnt4882_internal_interrupt(gpib_board_t *board); +static irqreturn_t tnt4882_interrupt(int irq, void *arg); + +// utility functions +static int tnt4882_allocate_private(gpib_board_t *board); +static void tnt4882_free_private(gpib_board_t *board); +static void tnt4882_init(struct tnt4882_priv *tnt_priv, const gpib_board_t *board); +static void tnt4882_board_reset(struct tnt4882_priv *tnt_priv, gpib_board_t *board); + +// register offset for nec7210 compatible registers +static const int atgpib_reg_offset = 2; + +// number of ioports used +static const int atgpib_iosize = 32; + +/* paged io */ +static inline unsigned int tnt_paged_readb(struct tnt4882_priv *priv, unsigned long offset) +{ + priv->io_writeb(AUX_PAGEIN, priv->nec7210_priv.iobase + AUXMR * priv->nec7210_priv.offset); + udelay(1); + return priv->io_readb(priv->nec7210_priv.iobase + offset); +} + +static inline void tnt_paged_writeb(struct tnt4882_priv *priv, unsigned int value, + unsigned long offset) +{ + priv->io_writeb(AUX_PAGEIN, priv->nec7210_priv.iobase + AUXMR * priv->nec7210_priv.offset); + udelay(1); + priv->io_writeb(value, priv->nec7210_priv.iobase + offset); +} + +/* readb/writeb wrappers */ +static inline unsigned short tnt_readb(struct tnt4882_priv *priv, unsigned long offset) +{ + void *address = priv->nec7210_priv.iobase + offset; + unsigned long flags; + unsigned short retval; + spinlock_t *register_lock = &priv->nec7210_priv.register_page_lock; + + spin_lock_irqsave(register_lock, flags); + switch (offset) { + case CSR: + case SASR: + case ISR0: + case BSR: + switch (priv->nec7210_priv.type) { + case TNT4882: + case TNT5004: + retval = priv->io_readb(address); + break; + case NAT4882: + retval = tnt_paged_readb(priv, offset - tnt_pagein_offset); + break; + case NEC7210: + retval = 0; + break; + default: + pr_err("tnt4882: bug! unsupported ni_chipset\n"); + retval = 0; + break; + } + break; + default: + retval = priv->io_readb(address); + break; + } + spin_unlock_irqrestore(register_lock, flags); + return retval; +} + +static inline void tnt_writeb(struct tnt4882_priv *priv, unsigned short value, unsigned long offset) +{ + void *address = priv->nec7210_priv.iobase + offset; + unsigned long flags; + spinlock_t *register_lock = &priv->nec7210_priv.register_page_lock; + + spin_lock_irqsave(register_lock, flags); + switch (offset) { + case KEYREG: + case IMR0: + case BCR: + switch (priv->nec7210_priv.type) { + case TNT4882: + case TNT5004: + priv->io_writeb(value, address); + break; + case NAT4882: + tnt_paged_writeb(priv, value, offset - tnt_pagein_offset); + break; + case NEC7210: + break; + default: + pr_err("tnt4882: bug! unsupported ni_chipset\n"); + break; + } + break; + default: + priv->io_writeb(value, address); + break; + } + spin_unlock_irqrestore(register_lock, flags); +} + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("GPIB driver for National Instruments boards using tnt4882 or compatible chips"); + +int tnt4882_line_status(const gpib_board_t *board) +{ + int status = ValidALL; + int bcsr_bits; + struct tnt4882_priv *tnt_priv; + + tnt_priv = board->private_data; + + bcsr_bits = tnt_readb(tnt_priv, BSR); + + if (bcsr_bits & BCSR_REN_BIT) + status |= BusREN; + if (bcsr_bits & BCSR_IFC_BIT) + status |= BusIFC; + if (bcsr_bits & BCSR_SRQ_BIT) + status |= BusSRQ; + if (bcsr_bits & BCSR_EOI_BIT) + status |= BusEOI; + if (bcsr_bits & BCSR_NRFD_BIT) + status |= BusNRFD; + if (bcsr_bits & BCSR_NDAC_BIT) + status |= BusNDAC; + if (bcsr_bits & BCSR_DAV_BIT) + status |= BusDAV; + if (bcsr_bits & BCSR_ATN_BIT) + status |= BusATN; + + return status; +} + +unsigned int tnt4882_t1_delay(gpib_board_t *board, unsigned int nano_sec) +{ + struct tnt4882_priv *tnt_priv = board->private_data; + struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; + unsigned int retval; + + retval = nec7210_t1_delay(board, nec_priv, nano_sec); + if (nec_priv->type == NEC7210) + return retval; + + if (nano_sec <= 350) { + tnt_writeb(tnt_priv, MSTD, KEYREG); + retval = 350; + } else { + tnt_writeb(tnt_priv, 0, KEYREG); + } + if (nano_sec > 500 && nano_sec <= 1100) { + write_byte(nec_priv, AUXRI | USTD, AUXMR); + retval = 1100; + } else { + write_byte(nec_priv, AUXRI, AUXMR); + } + return retval; +} + +static int fifo_word_available(struct tnt4882_priv *tnt_priv) +{ + int status2; + int retval; + + status2 = tnt_readb(tnt_priv, STS2); + retval = (status2 & AEFN) && (status2 & BEFN); + + return retval; +} + +static int fifo_byte_available(struct tnt4882_priv *tnt_priv) +{ + int status2; + int retval; + + status2 = tnt_readb(tnt_priv, STS2); + retval = (status2 & AEFN) || (status2 & BEFN); + + return retval; +} + +static int fifo_xfer_done(struct tnt4882_priv *tnt_priv) +{ + int status1; + int retval; + + status1 = tnt_readb(tnt_priv, STS1); + retval = status1 & (S_DONE | S_HALT); + + return retval; +} + +static int drain_fifo_words(struct tnt4882_priv *tnt_priv, uint8_t *buffer, int num_bytes) +{ + int count = 0; + struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; + + while (fifo_word_available(tnt_priv) && count + 2 <= num_bytes) { + short word; + + word = tnt_priv->io_readw(nec_priv->iobase + FIFOB); + buffer[count++] = word & 0xff; + buffer[count++] = (word >> 8) & 0xff; + } + return count; +} + +static void tnt4882_release_holdoff(gpib_board_t *board, struct tnt4882_priv *tnt_priv) +{ + struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; + unsigned short sasr_bits; + + sasr_bits = tnt_readb(tnt_priv, SASR); + + /*tnt4882 not in one-chip mode won't always release holdoff unless we + * are in the right mode when release handshake command is given + */ + if (sasr_bits & AEHS_BIT) /* holding off due to holdoff on end mode*/ { + nec7210_set_handshake_mode(board, nec_priv, HR_HLDE); + write_byte(nec_priv, AUX_FH, AUXMR); + } else if (sasr_bits & ANHS1_BIT) { /* held off due to holdoff on all data mode*/ + nec7210_set_handshake_mode(board, nec_priv, HR_HLDA); + write_byte(nec_priv, AUX_FH, AUXMR); + nec7210_set_handshake_mode(board, nec_priv, HR_HLDE); + } else { /* held off due to holdoff immediately command */ + nec7210_set_handshake_mode(board, nec_priv, HR_HLDE); + write_byte(nec_priv, AUX_FH, AUXMR); + } +} + +int tnt4882_accel_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, + size_t *bytes_read) +{ + size_t count = 0; + ssize_t retval = 0; + struct tnt4882_priv *tnt_priv = board->private_data; + struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; + unsigned int bits; + s32 hw_count; + unsigned long flags; + + *bytes_read = 0; + // FIXME: really, DEV_CLEAR_BN should happen elsewhere to prevent race + clear_bit(DEV_CLEAR_BN, &nec_priv->state); + clear_bit(ADR_CHANGE_BN, &nec_priv->state); + + nec7210_set_reg_bits(nec_priv, IMR1, HR_ENDIE, HR_ENDIE); + if (nec_priv->type != TNT4882 && nec_priv->type != TNT5004) + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, HR_DMAI); + else + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + tnt_writeb(tnt_priv, nec_priv->auxa_bits | HR_HLDA, CCR); + bits = TNT_B_16BIT | TNT_IN | TNT_CCEN; + tnt_writeb(tnt_priv, bits, CFG); + tnt_writeb(tnt_priv, RESET_FIFO, CMDR); + udelay(1); + // load 2's complement of count into hardware counters + hw_count = -length; + tnt_writeb(tnt_priv, hw_count & 0xff, CNT0); + tnt_writeb(tnt_priv, (hw_count >> 8) & 0xff, CNT1); + tnt_writeb(tnt_priv, (hw_count >> 16) & 0xff, CNT2); + tnt_writeb(tnt_priv, (hw_count >> 24) & 0xff, CNT3); + + tnt4882_release_holdoff(board, tnt_priv); + + tnt_writeb(tnt_priv, GO, CMDR); + udelay(1); + + spin_lock_irqsave(&board->spinlock, flags); + tnt_priv->imr3_bits |= HR_DONE | HR_NEF; + tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); + spin_unlock_irqrestore(&board->spinlock, flags); + + while (count + 2 <= length && + test_bit(RECEIVED_END_BN, &nec_priv->state) == 0 && + fifo_xfer_done(tnt_priv) == 0) { + // wait until a word is ready + if (wait_event_interruptible(board->wait, + fifo_word_available(tnt_priv) || + fifo_xfer_done(tnt_priv) || + test_bit(RECEIVED_END_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(ADR_CHANGE_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_err("tnt4882: read interrupted\n"); + retval = -ERESTARTSYS; + break; + } + if (test_bit(TIMO_NUM, &board->status)) { + //pr_info("tnt4882: minor %i read timed out\n", board->minor); + retval = -ETIMEDOUT; + break; + } + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) { + pr_err("tnt4882: device clear interrupted read\n"); + retval = -EINTR; + break; + } + if (test_bit(ADR_CHANGE_BN, &nec_priv->state)) { + pr_err("tnt4882: address change interrupted read\n"); + retval = -EINTR; + break; + } + + spin_lock_irqsave(&board->spinlock, flags); + count += drain_fifo_words(tnt_priv, &buffer[count], length - count); + tnt_priv->imr3_bits |= HR_NEF; + tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); + spin_unlock_irqrestore(&board->spinlock, flags); + + if (need_resched()) + schedule(); + } + // wait for last byte + if (count < length) { + spin_lock_irqsave(&board->spinlock, flags); + tnt_priv->imr3_bits |= HR_DONE | HR_NEF; + tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); + spin_unlock_irqrestore(&board->spinlock, flags); + + if (wait_event_interruptible(board->wait, + fifo_xfer_done(tnt_priv) || + test_bit(RECEIVED_END_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(ADR_CHANGE_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + pr_err("tnt4882: read interrupted\n"); + retval = -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) + //pr_info("tnt4882: read timed out\n"); + retval = -ETIMEDOUT; + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) { + pr_err("tnt4882: device clear interrupted read\n"); + retval = -EINTR; + } + if (test_bit(ADR_CHANGE_BN, &nec_priv->state)) { + pr_err("tnt4882: address change interrupted read\n"); + retval = -EINTR; + } + count += drain_fifo_words(tnt_priv, &buffer[count], length - count); + if (fifo_byte_available(tnt_priv) && count < length) + buffer[count++] = tnt_readb(tnt_priv, FIFOB); + } + if (count < length) + tnt_writeb(tnt_priv, STOP, CMDR); + udelay(1); + + nec7210_set_reg_bits(nec_priv, IMR1, HR_ENDIE, 0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAI, 0); + /* force handling of any pending interrupts (seems to be needed + * to keep interrupts from getting hosed, plus for syncing + * with RECEIVED_END below) + */ + tnt4882_internal_interrupt(board); + /* RECEIVED_END should be in sync now */ + if (test_and_clear_bit(RECEIVED_END_BN, &nec_priv->state)) + *end = 1; + if (retval < 0) { + // force immediate holdoff + write_byte(nec_priv, AUX_HLDI, AUXMR); + + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + } + *bytes_read = count; + + return retval; +} + +static int fifo_space_available(struct tnt4882_priv *tnt_priv) +{ + int status2; + int retval; + + status2 = tnt_readb(tnt_priv, STS2); + retval = (status2 & AFFN) && (status2 & BFFN); + + return retval; +} + +static unsigned int tnt_transfer_count(struct tnt4882_priv *tnt_priv) +{ + unsigned int count = 0; + + count |= tnt_readb(tnt_priv, CNT0) & 0xff; + count |= (tnt_readb(tnt_priv, CNT1) << 8) & 0xff00; + count |= (tnt_readb(tnt_priv, CNT2) << 16) & 0xff0000; + count |= (tnt_readb(tnt_priv, CNT3) << 24) & 0xff000000; + // return two's complement + return -count; +}; + +static int write_wait(gpib_board_t *board, struct tnt4882_priv *tnt_priv, + int wait_for_done, int send_commands) +{ + struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; + + if (wait_event_interruptible(board->wait, + (!wait_for_done && fifo_space_available(tnt_priv)) || + fifo_xfer_done(tnt_priv) || + test_bit(BUS_ERROR_BN, &nec_priv->state) || + test_bit(DEV_CLEAR_BN, &nec_priv->state) || + test_bit(TIMO_NUM, &board->status))) { + dev_dbg(board->gpib_dev, "gpib write interrupted\n"); + return -ERESTARTSYS; + } + if (test_bit(TIMO_NUM, &board->status)) { + pr_info("tnt4882: write timed out\n"); + return -ETIMEDOUT; + } + if (test_and_clear_bit(BUS_ERROR_BN, &nec_priv->state)) { + pr_err("tnt4882: write bus error\n"); + return (send_commands) ? -ENOTCONN : -ECOMM; + } + if (test_bit(DEV_CLEAR_BN, &nec_priv->state)) { + pr_err("tnt4882: device clear interrupted write\n"); + return -EINTR; + } + return 0; +} + +static int generic_write(gpib_board_t *board, uint8_t *buffer, size_t length, + int send_eoi, int send_commands, size_t *bytes_written) +{ + size_t count = 0; + ssize_t retval = 0; + struct tnt4882_priv *tnt_priv = board->private_data; + struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; + unsigned int bits; + s32 hw_count; + unsigned long flags; + + *bytes_written = 0; + // FIXME: really, DEV_CLEAR_BN should happen elsewhere to prevent race + clear_bit(DEV_CLEAR_BN, &nec_priv->state); + + nec7210_set_reg_bits(nec_priv, IMR1, HR_ERRIE, HR_ERRIE); + + if (nec_priv->type != TNT4882 && nec_priv->type != TNT5004) + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, HR_DMAO); + else + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0); + + tnt_writeb(tnt_priv, RESET_FIFO, CMDR); + udelay(1); + + bits = TNT_B_16BIT; + if (send_eoi) { + bits |= TNT_CCEN; + if (nec_priv->type != TNT4882 && nec_priv->type != TNT5004) + tnt_writeb(tnt_priv, AUX_SEOI, CCR); + } + if (send_commands) + bits |= TNT_COMMAND; + tnt_writeb(tnt_priv, bits, CFG); + + // load 2's complement of count into hardware counters + hw_count = -length; + tnt_writeb(tnt_priv, hw_count & 0xff, CNT0); + tnt_writeb(tnt_priv, (hw_count >> 8) & 0xff, CNT1); + tnt_writeb(tnt_priv, (hw_count >> 16) & 0xff, CNT2); + tnt_writeb(tnt_priv, (hw_count >> 24) & 0xff, CNT3); + + tnt_writeb(tnt_priv, GO, CMDR); + udelay(1); + + spin_lock_irqsave(&board->spinlock, flags); + tnt_priv->imr3_bits |= HR_DONE; + tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); + spin_unlock_irqrestore(&board->spinlock, flags); + + while (count < length) { + // wait until byte is ready to be sent + retval = write_wait(board, tnt_priv, 0, send_commands); + if (retval < 0) + break; + if (fifo_xfer_done(tnt_priv)) + break; + spin_lock_irqsave(&board->spinlock, flags); + while (fifo_space_available(tnt_priv) && count < length) { + u16 word; + + word = buffer[count++] & 0xff; + if (count < length) + word |= (buffer[count++] << 8) & 0xff00; + tnt_priv->io_writew(word, nec_priv->iobase + FIFOB); + } +// avoid unnecessary HR_NFF interrupts +// tnt_priv->imr3_bits |= HR_NFF; +// tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); + spin_unlock_irqrestore(&board->spinlock, flags); + + if (need_resched()) + schedule(); + } + // wait last byte has been sent + if (retval == 0) + retval = write_wait(board, tnt_priv, 1, send_commands); + + tnt_writeb(tnt_priv, STOP, CMDR); + udelay(1); + + nec7210_set_reg_bits(nec_priv, IMR1, HR_ERR, 0x0); + nec7210_set_reg_bits(nec_priv, IMR2, HR_DMAO, 0x0); + /* force handling of any interrupts that happened + * while they were masked (this appears to be needed) + */ + tnt4882_internal_interrupt(board); + *bytes_written = length - tnt_transfer_count(tnt_priv); + return retval; +} + +int tnt4882_accel_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) +{ + return generic_write(board, buffer, length, send_eoi, 0, bytes_written); +} + +int tnt4882_command(gpib_board_t *board, uint8_t *buffer, size_t length, size_t *bytes_written) +{ + return generic_write(board, buffer, length, 0, 1, bytes_written); +} + +irqreturn_t tnt4882_internal_interrupt(gpib_board_t *board) +{ + struct tnt4882_priv *priv = board->private_data; + int isr0_bits, isr3_bits, imr3_bits; + unsigned long flags; + + spin_lock_irqsave(&board->spinlock, flags); + + nec7210_interrupt(board, &priv->nec7210_priv); + + isr0_bits = tnt_readb(priv, ISR0); + isr3_bits = tnt_readb(priv, ISR3); + imr3_bits = priv->imr3_bits; + + if (isr0_bits & TNT_IFCI_BIT) + push_gpib_event(board, EventIFC); + //XXX don't need this wakeup, one below should do? +// wake_up_interruptible(&board->wait); + + if (isr3_bits & HR_NFF) + priv->imr3_bits &= ~HR_NFF; + if (isr3_bits & HR_NEF) + priv->imr3_bits &= ~HR_NEF; + if (isr3_bits & HR_DONE) + priv->imr3_bits &= ~HR_DONE; + if (isr3_bits & (HR_INTR | HR_TLCI)) { + dev_dbg(board->gpib_dev, "tnt4882: minor %i isr0 0x%x imr0 0x%x isr3 0x%x imr3 0x%x\n", + board->minor, isr0_bits, priv->imr0_bits, isr3_bits, imr3_bits); + tnt_writeb(priv, priv->imr3_bits, IMR3); + wake_up_interruptible(&board->wait); + } + spin_unlock_irqrestore(&board->spinlock, flags); + return IRQ_HANDLED; +} + +irqreturn_t tnt4882_interrupt(int irq, void *arg) +{ + return tnt4882_internal_interrupt(arg); +} + +static int ni_tnt_isa_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int ni_nat4882_isa_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int ni_nec_isa_attach(gpib_board_t *board, const gpib_board_config_t *config); +static int ni_pci_attach(gpib_board_t *board, const gpib_board_config_t *config); + +static void ni_isa_detach(gpib_board_t *board); +static void ni_pci_detach(gpib_board_t *board); + +#ifdef GPIB_PCMCIA +static int ni_pcmcia_attach(gpib_board_t *board, const gpib_board_config_t *config); +static void ni_pcmcia_detach(gpib_board_t *board); +static int init_ni_gpib_cs(void); +static void __exit exit_ni_gpib_cs(void); +#endif + +// wrappers for interface functions +int tnt4882_read(gpib_board_t *board, uint8_t *buffer, size_t length, int *end, size_t *bytes_read) +{ + struct tnt4882_priv *priv = board->private_data; + struct nec7210_priv *nec_priv = &priv->nec7210_priv; + int retval; + int dummy; + + retval = nec7210_read(board, &priv->nec7210_priv, buffer, length, end, bytes_read); + + if (retval < 0) { // force immediate holdoff + write_byte(nec_priv, AUX_HLDI, AUXMR); + + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + + nec7210_read_data_in(board, nec_priv, &dummy); + } + return retval; +} + +int tnt4882_write(gpib_board_t *board, uint8_t *buffer, size_t length, int send_eoi, + size_t *bytes_written) +{ + struct tnt4882_priv *priv = board->private_data; + + return nec7210_write(board, &priv->nec7210_priv, buffer, length, send_eoi, bytes_written); +} + +int tnt4882_command_unaccel(gpib_board_t *board, uint8_t *buffer, + size_t length, size_t *bytes_written) +{ + struct tnt4882_priv *priv = board->private_data; + + return nec7210_command(board, &priv->nec7210_priv, buffer, length, bytes_written); +} + +int tnt4882_take_control(gpib_board_t *board, int synchronous) +{ + struct tnt4882_priv *priv = board->private_data; + + return nec7210_take_control(board, &priv->nec7210_priv, synchronous); +} + +int tnt4882_go_to_standby(gpib_board_t *board) +{ + struct tnt4882_priv *priv = board->private_data; + + return nec7210_go_to_standby(board, &priv->nec7210_priv); +} + +void tnt4882_request_system_control(gpib_board_t *board, int request_control) +{ + struct tnt4882_priv *priv = board->private_data; + + if (request_control) { + tnt_writeb(priv, SETSC, CMDR); + udelay(1); + } + nec7210_request_system_control(board, &priv->nec7210_priv, request_control); + if (!request_control) { + tnt_writeb(priv, CLRSC, CMDR); + udelay(1); + } +} + +void tnt4882_interface_clear(gpib_board_t *board, int assert) +{ + struct tnt4882_priv *priv = board->private_data; + + nec7210_interface_clear(board, &priv->nec7210_priv, assert); +} + +void tnt4882_remote_enable(gpib_board_t *board, int enable) +{ + struct tnt4882_priv *priv = board->private_data; + + nec7210_remote_enable(board, &priv->nec7210_priv, enable); +} + +int tnt4882_enable_eos(gpib_board_t *board, uint8_t eos_byte, int compare_8_bits) +{ + struct tnt4882_priv *priv = board->private_data; + + return nec7210_enable_eos(board, &priv->nec7210_priv, eos_byte, compare_8_bits); +} + +void tnt4882_disable_eos(gpib_board_t *board) +{ + struct tnt4882_priv *priv = board->private_data; + + nec7210_disable_eos(board, &priv->nec7210_priv); +} + +unsigned int tnt4882_update_status(gpib_board_t *board, unsigned int clear_mask) +{ + unsigned long flags; + u8 line_status; + unsigned int retval; + struct tnt4882_priv *priv = board->private_data; + + spin_lock_irqsave(&board->spinlock, flags); + board->status &= ~clear_mask; + retval = nec7210_update_status_nolock(board, &priv->nec7210_priv); + /* set / clear SRQ state since it is not cleared by interrupt */ + line_status = tnt_readb(priv, BSR); + if (line_status & BCSR_SRQ_BIT) + set_bit(SRQI_NUM, &board->status); + else + clear_bit(SRQI_NUM, &board->status); + spin_unlock_irqrestore(&board->spinlock, flags); + return board->status; +} + +int tnt4882_primary_address(gpib_board_t *board, unsigned int address) +{ + struct tnt4882_priv *priv = board->private_data; + + return nec7210_primary_address(board, &priv->nec7210_priv, address); +} + +int tnt4882_secondary_address(gpib_board_t *board, unsigned int address, int enable) +{ + struct tnt4882_priv *priv = board->private_data; + + return nec7210_secondary_address(board, &priv->nec7210_priv, address, enable); +} + +int tnt4882_parallel_poll(gpib_board_t *board, uint8_t *result) + +{ + struct tnt4882_priv *tnt_priv = board->private_data; + + if (tnt_priv->nec7210_priv.type != NEC7210) { + tnt_priv->auxg_bits |= RPP2_BIT; + write_byte(&tnt_priv->nec7210_priv, tnt_priv->auxg_bits, AUXMR); + udelay(2); //FIXME use parallel poll timeout + *result = read_byte(&tnt_priv->nec7210_priv, CPTR); + tnt_priv->auxg_bits &= ~RPP2_BIT; + write_byte(&tnt_priv->nec7210_priv, tnt_priv->auxg_bits, AUXMR); + return 0; + } else { + return nec7210_parallel_poll(board, &tnt_priv->nec7210_priv, result); + } +} + +void tnt4882_parallel_poll_configure(gpib_board_t *board, uint8_t config) +{ + struct tnt4882_priv *priv = board->private_data; + + if (priv->nec7210_priv.type == TNT5004) { + /* configure locally */ + write_byte(&priv->nec7210_priv, AUXRI | 0x4, AUXMR); + if (config) + /* set response + clear sense */ + write_byte(&priv->nec7210_priv, PPR | config, AUXMR); + else + /* disable ppoll */ + write_byte(&priv->nec7210_priv, PPR | 0x10, AUXMR); + } else { + nec7210_parallel_poll_configure(board, &priv->nec7210_priv, config); + } +} + +void tnt4882_parallel_poll_response(gpib_board_t *board, int ist) +{ + struct tnt4882_priv *priv = board->private_data; + + nec7210_parallel_poll_response(board, &priv->nec7210_priv, ist); +} + +/* this is just used by the old nec7210 isa interfaces, the newer + * boards use tnt4882_serial_poll_response2 + */ +void tnt4882_serial_poll_response(gpib_board_t *board, uint8_t status) +{ + struct tnt4882_priv *priv = board->private_data; + + nec7210_serial_poll_response(board, &priv->nec7210_priv, status); +} + +static void tnt4882_serial_poll_response2(gpib_board_t *board, uint8_t status, + int new_reason_for_service) +{ + struct tnt4882_priv *priv = board->private_data; + unsigned long flags; + const int MSS = status & request_service_bit; + const int reqt = MSS && new_reason_for_service; + const int reqf = MSS == 0; + + spin_lock_irqsave(&board->spinlock, flags); + if (reqt) { + priv->nec7210_priv.srq_pending = 1; + clear_bit(SPOLL_NUM, &board->status); + } else { + if (reqf) + priv->nec7210_priv.srq_pending = 0; + } + if (reqt) + /* It may seem like a race to issue reqt before updating + * the status byte, but it is not. The chip does not + * issue the reqt until the SPMR is written to at + * a later time. + */ + write_byte(&priv->nec7210_priv, AUX_REQT, AUXMR); + else if (reqf) + write_byte(&priv->nec7210_priv, AUX_REQF, AUXMR); + /* We need to always zero bit 6 of the status byte before writing it to + * the SPMR to insure we are using + * serial poll mode SP1, and not accidentally triggering mode SP3. + */ + write_byte(&priv->nec7210_priv, status & ~request_service_bit, SPMR); + spin_unlock_irqrestore(&board->spinlock, flags); +} + +uint8_t tnt4882_serial_poll_status(gpib_board_t *board) +{ + struct tnt4882_priv *priv = board->private_data; + + return nec7210_serial_poll_status(board, &priv->nec7210_priv); +} + +void tnt4882_return_to_local(gpib_board_t *board) +{ + struct tnt4882_priv *priv = board->private_data; + + nec7210_return_to_local(board, &priv->nec7210_priv); +} + +gpib_interface_t ni_pci_interface = { +name: "ni_pci", +attach : ni_pci_attach, +detach : ni_pci_detach, +read : tnt4882_accel_read, +write : tnt4882_accel_write, +command : tnt4882_command, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : tnt4882_line_status, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response2 : tnt4882_serial_poll_response2, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +gpib_interface_t ni_pci_accel_interface = { +name: "ni_pci_accel", +attach : ni_pci_attach, +detach : ni_pci_detach, +read : tnt4882_accel_read, +write : tnt4882_accel_write, +command : tnt4882_command, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : tnt4882_line_status, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response2 : tnt4882_serial_poll_response2, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +gpib_interface_t ni_isa_interface = { +name: "ni_isa", +attach : ni_tnt_isa_attach, +detach : ni_isa_detach, +read : tnt4882_accel_read, +write : tnt4882_accel_write, +command : tnt4882_command, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : tnt4882_line_status, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response2 : tnt4882_serial_poll_response2, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +gpib_interface_t ni_nat4882_isa_interface = { +name: "ni_nat4882_isa", +attach : ni_nat4882_isa_attach, +detach : ni_isa_detach, +read : tnt4882_read, +write : tnt4882_write, +command : tnt4882_command_unaccel, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : tnt4882_line_status, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response2 : tnt4882_serial_poll_response2, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +gpib_interface_t ni_nec_isa_interface = { +name: "ni_nec_isa", +attach : ni_nec_isa_attach, +detach : ni_isa_detach, +read : tnt4882_read, +write : tnt4882_write, +command : tnt4882_command_unaccel, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : NULL, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response : tnt4882_serial_poll_response, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +gpib_interface_t ni_isa_accel_interface = { +name: "ni_isa_accel", +attach : ni_tnt_isa_attach, +detach : ni_isa_detach, +read : tnt4882_accel_read, +write : tnt4882_accel_write, +command : tnt4882_command, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : tnt4882_line_status, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response2 : tnt4882_serial_poll_response2, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +gpib_interface_t ni_nat4882_isa_accel_interface = { +name: "ni_nat4882_isa_accel", +attach : ni_nat4882_isa_attach, +detach : ni_isa_detach, +read : tnt4882_accel_read, +write : tnt4882_accel_write, +command : tnt4882_command_unaccel, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : tnt4882_line_status, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response2 : tnt4882_serial_poll_response2, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +gpib_interface_t ni_nec_isa_accel_interface = { +name: "ni_nec_isa_accel", +attach : ni_nec_isa_attach, +detach : ni_isa_detach, +read : tnt4882_accel_read, +write : tnt4882_accel_write, +command : tnt4882_command_unaccel, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : NULL, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response : tnt4882_serial_poll_response, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +#ifdef GPIB_PCMCIA +gpib_interface_t ni_pcmcia_interface = { +name: "ni_pcmcia", +attach : ni_pcmcia_attach, +detach : ni_pcmcia_detach, +read : tnt4882_accel_read, +write : tnt4882_accel_write, +command : tnt4882_command, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : tnt4882_line_status, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response : tnt4882_serial_poll_response, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; + +gpib_interface_t ni_pcmcia_accel_interface = { +name: "ni_pcmcia_accel", +attach : ni_pcmcia_attach, +detach : ni_pcmcia_detach, +read : tnt4882_accel_read, +write : tnt4882_accel_write, +command : tnt4882_command, +take_control : tnt4882_take_control, +go_to_standby : tnt4882_go_to_standby, +request_system_control : tnt4882_request_system_control, +interface_clear : tnt4882_interface_clear, +remote_enable : tnt4882_remote_enable, +enable_eos : tnt4882_enable_eos, +disable_eos : tnt4882_disable_eos, +parallel_poll : tnt4882_parallel_poll, +parallel_poll_configure : tnt4882_parallel_poll_configure, +parallel_poll_response : tnt4882_parallel_poll_response, +local_parallel_poll_mode : NULL, // XXX +line_status : tnt4882_line_status, +update_status : tnt4882_update_status, +primary_address : tnt4882_primary_address, +secondary_address : tnt4882_secondary_address, +serial_poll_response : tnt4882_serial_poll_response, +serial_poll_status : tnt4882_serial_poll_status, +t1_delay : tnt4882_t1_delay, +return_to_local : tnt4882_return_to_local, +}; +#endif + +void tnt4882_board_reset(struct tnt4882_priv *tnt_priv, gpib_board_t *board) +{ + struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; + + tnt_priv->imr0_bits = 0; + tnt_writeb(tnt_priv, tnt_priv->imr0_bits, IMR0); + tnt_priv->imr3_bits = 0; + tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); + tnt_readb(tnt_priv, IMR0); + tnt_readb(tnt_priv, IMR3); + nec7210_board_reset(nec_priv, board); +} + +int tnt4882_allocate_private(gpib_board_t *board) +{ + struct tnt4882_priv *tnt_priv; + + board->private_data = kmalloc(sizeof(struct tnt4882_priv), GFP_KERNEL); + if (!board->private_data) + return -1; + tnt_priv = board->private_data; + memset(tnt_priv, 0, sizeof(struct tnt4882_priv)); + init_nec7210_private(&tnt_priv->nec7210_priv); + return 0; +} + +void tnt4882_free_private(gpib_board_t *board) +{ + kfree(board->private_data); + board->private_data = NULL; +} + +void tnt4882_init(struct tnt4882_priv *tnt_priv, const gpib_board_t *board) +{ + struct nec7210_priv *nec_priv = &tnt_priv->nec7210_priv; + + /* Turbo488 software reset */ + tnt_writeb(tnt_priv, SOFT_RESET, CMDR); + udelay(1); + + // turn off one-chip mode + tnt_writeb(tnt_priv, NODMA, HSSEL); + tnt_writeb(tnt_priv, 0, ACCWR); + // make sure we are in 7210 mode + tnt_writeb(tnt_priv, AUX_7210, AUXCR); + udelay(1); + // registers might be swapped, so write it to the swapped address too + tnt_writeb(tnt_priv, AUX_7210, SWAPPED_AUXCR); + udelay(1); + // turn on one-chip mode + if (nec_priv->type == TNT4882 || nec_priv->type == TNT5004) + tnt_writeb(tnt_priv, NODMA | TNT_ONE_CHIP_BIT, HSSEL); + else + tnt_writeb(tnt_priv, NODMA, HSSEL); + + nec7210_board_reset(nec_priv, board); + // read-clear isr0 + tnt_readb(tnt_priv, ISR0); + + // enable passing of nat4882 interrupts + tnt_priv->imr3_bits = HR_TLCI; + tnt_writeb(tnt_priv, tnt_priv->imr3_bits, IMR3); + + // enable interrupt + tnt_writeb(tnt_priv, 0x1, INTRT); + + // force immediate holdoff + write_byte(&tnt_priv->nec7210_priv, AUX_HLDI, AUXMR); + + set_bit(RFD_HOLDOFF_BN, &nec_priv->state); + + tnt_priv->auxg_bits = AUXRG | NTNL_BIT; + write_byte(&tnt_priv->nec7210_priv, tnt_priv->auxg_bits, AUXMR); + + nec7210_board_online(nec_priv, board); + // enable interface clear interrupt for event queue + tnt_priv->imr0_bits = TNT_IMR0_ALWAYS_BITS | TNT_ATNI_BIT | TNT_IFCIE_BIT; + tnt_writeb(tnt_priv, tnt_priv->imr0_bits, IMR0); +} + +int ni_pci_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct tnt4882_priv *tnt_priv; + struct nec7210_priv *nec_priv; + int isr_flags = IRQF_SHARED; + int retval; + struct mite_struct *mite; + + board->status = 0; + + if (tnt4882_allocate_private(board)) + return -ENOMEM; + tnt_priv = board->private_data; + tnt_priv->io_writeb = writeb_wrapper; + tnt_priv->io_readb = readb_wrapper; + tnt_priv->io_writew = writew_wrapper; + tnt_priv->io_readw = readw_wrapper; + nec_priv = &tnt_priv->nec7210_priv; + nec_priv->type = TNT4882; + nec_priv->read_byte = nec7210_locking_iomem_read_byte; + nec_priv->write_byte = nec7210_locking_iomem_write_byte; + nec_priv->offset = atgpib_reg_offset; + + if (!mite_devices) { + pr_err("no National Instruments PCI boards found\n"); + return -1; + } + + for (mite = mite_devices; mite; mite = mite->next) { + short found_board; + + if (mite->used) + continue; + if (config->pci_bus >= 0 && config->pci_bus != mite->pcidev->bus->number) + continue; + if (config->pci_slot >= 0 && config->pci_slot != PCI_SLOT(mite->pcidev->devfn)) + continue; + switch (mite_device_id(mite)) { + case PCI_DEVICE_ID_NI_GPIB: + case PCI_DEVICE_ID_NI_GPIB_PLUS: + case PCI_DEVICE_ID_NI_GPIB_PLUS2: + case PCI_DEVICE_ID_NI_PXIGPIB: + case PCI_DEVICE_ID_NI_PMCGPIB: + case PCI_DEVICE_ID_NI_PCIEGPIB: + case PCI_DEVICE_ID_NI_PCIE2GPIB: +// support for Measurement Computing PCI-488 + case PCI_DEVICE_ID_MC_PCI488: + case PCI_DEVICE_ID_CEC_NI_GPIB: + found_board = 1; + break; + default: + found_board = 0; + break; + } + if (found_board) + break; + } + if (!mite) { + pr_err("no NI PCI-GPIB boards found\n"); + return -1; + } + tnt_priv->mite = mite; + retval = mite_setup(tnt_priv->mite); + if (retval < 0) { + pr_err("tnt4882: error setting up mite.\n"); + return retval; + } + + nec_priv->iobase = tnt_priv->mite->daq_io_addr; + + // get irq + if (request_irq(mite_irq(tnt_priv->mite), tnt4882_interrupt, isr_flags, + "ni-pci-gpib", board)) { + pr_err("gpib: can't request IRQ %d\n", mite_irq(tnt_priv->mite)); + return -1; + } + tnt_priv->irq = mite_irq(tnt_priv->mite); + pr_info("tnt4882: irq %i\n", tnt_priv->irq); + + // TNT5004 detection + switch (tnt_readb(tnt_priv, CSR) & 0xf0) { + case 0x30: + nec_priv->type = TNT4882; + pr_info("tnt4882: TNT4882 chipset detected\n"); + break; + case 0x40: + nec_priv->type = TNT5004; + pr_info("tnt4882: TNT5004 chipset detected\n"); + break; + } + tnt4882_init(tnt_priv, board); + + return 0; +} + +void ni_pci_detach(gpib_board_t *board) +{ + struct tnt4882_priv *tnt_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (tnt_priv) { + nec_priv = &tnt_priv->nec7210_priv; + + if (nec_priv->iobase) + tnt4882_board_reset(tnt_priv, board); + if (tnt_priv->irq) + free_irq(tnt_priv->irq, board); + if (tnt_priv->mite) + mite_unsetup(tnt_priv->mite); + } + tnt4882_free_private(board); +} + +static int ni_isapnp_find(struct pnp_dev **dev) +{ + *dev = pnp_find_dev(NULL, ISAPNP_VENDOR_ID_NI, + ISAPNP_FUNCTION(ISAPNP_ID_NI_ATGPIB_TNT), NULL); + if (!*dev || !(*dev)->card) { + pr_err("tnt4882: failed to find isapnp board\n"); + return -ENODEV; + } + if (pnp_device_attach(*dev) < 0) { + pr_err("tnt4882: atgpib/tnt board already active, skipping\n"); + return -EBUSY; + } + if (pnp_activate_dev(*dev) < 0) { + pnp_device_detach(*dev); + pr_err("tnt4882: failed to activate() atgpib/tnt, aborting\n"); + return -EAGAIN; + } + if (!pnp_port_valid(*dev, 0) || !pnp_irq_valid(*dev, 0)) { + pnp_device_detach(*dev); + pr_err("tnt4882: invalid port or irq for atgpib/tnt, aborting\n"); + return -ENOMEM; + } + return 0; +} + +static int ni_isa_attach_common(gpib_board_t *board, const gpib_board_config_t *config, + enum nec7210_chipset chipset) +{ + struct tnt4882_priv *tnt_priv; + struct nec7210_priv *nec_priv; + int isr_flags = 0; + void *iobase; + int irq; + + board->status = 0; + + if (tnt4882_allocate_private(board)) + return -ENOMEM; + tnt_priv = board->private_data; + tnt_priv->io_writeb = outb_wrapper; + tnt_priv->io_readb = inb_wrapper; + tnt_priv->io_writew = outw_wrapper; + tnt_priv->io_readw = inw_wrapper; + nec_priv = &tnt_priv->nec7210_priv; + nec_priv->type = chipset; + nec_priv->read_byte = nec7210_locking_ioport_read_byte; + nec_priv->write_byte = nec7210_locking_ioport_write_byte; + nec_priv->offset = atgpib_reg_offset; + + // look for plug-n-play board + if (config->ibbase == 0) { + struct pnp_dev *dev; + int retval; + + retval = ni_isapnp_find(&dev); + if (retval < 0) + return retval; + tnt_priv->pnp_dev = dev; + iobase = (void *)(pnp_port_start(dev, 0)); + irq = pnp_irq(dev, 0); + } else { + iobase = config->ibbase; + irq = config->ibirq; + } + // allocate ioports + if (!request_region((unsigned long)(iobase), atgpib_iosize, "atgpib")) { + pr_err("tnt4882: failed to allocate ioports\n"); + return -1; + } + nec_priv->iobase = iobase; + + // get irq + if (request_irq(irq, tnt4882_interrupt, isr_flags, "atgpib", board)) { + pr_err("gpib: can't request IRQ %d\n", irq); + return -1; + } + tnt_priv->irq = irq; + + tnt4882_init(tnt_priv, board); + + return 0; +} + +int ni_tnt_isa_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + return ni_isa_attach_common(board, config, TNT4882); +} + +int ni_nat4882_isa_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + return ni_isa_attach_common(board, config, NAT4882); +} + +int ni_nec_isa_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + return ni_isa_attach_common(board, config, NEC7210); +} + +void ni_isa_detach(gpib_board_t *board) +{ + struct tnt4882_priv *tnt_priv = board->private_data; + struct nec7210_priv *nec_priv; + + if (tnt_priv) { + nec_priv = &tnt_priv->nec7210_priv; + if (nec_priv->iobase) + tnt4882_board_reset(tnt_priv, board); + if (tnt_priv->irq) + free_irq(tnt_priv->irq, board); + if (nec_priv->iobase) + release_region((unsigned long)(nec_priv->iobase), atgpib_iosize); + if (tnt_priv->pnp_dev) + pnp_device_detach(tnt_priv->pnp_dev); + } + tnt4882_free_private(board); +} + +static int tnt4882_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return 0; +} + +static const struct pci_device_id tnt4882_pci_table[] = { + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_GPIB)}, + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_GPIB_PLUS)}, + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_GPIB_PLUS2)}, + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_PXIGPIB)}, + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_PMCGPIB)}, + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_PCIEGPIB)}, + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_NI_PCIE2GPIB)}, + // support for Measurement Computing PCI-488 + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_MC_PCI488)}, + {PCI_DEVICE(PCI_VENDOR_ID_NATINST, PCI_DEVICE_ID_CEC_NI_GPIB)}, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, tnt4882_pci_table); + +static struct pci_driver tnt4882_pci_driver = { + .name = "tnt4882", + .id_table = tnt4882_pci_table, + .probe = &tnt4882_pci_probe +}; + +static const struct pnp_device_id tnt4882_pnp_table[] = { + {.id = "NICC601"}, + {.id = ""} +}; +MODULE_DEVICE_TABLE(pnp, tnt4882_pnp_table); + +static int __init tnt4882_init_module(void) +{ + int result; + + result = pci_register_driver(&tnt4882_pci_driver); + if (result) { + pr_err("tnt4882: pci_driver_register failed!\n"); + return result; + } + + gpib_register_driver(&ni_isa_interface, THIS_MODULE); + gpib_register_driver(&ni_isa_accel_interface, THIS_MODULE); + gpib_register_driver(&ni_nat4882_isa_interface, THIS_MODULE); + gpib_register_driver(&ni_nat4882_isa_accel_interface, THIS_MODULE); + gpib_register_driver(&ni_nec_isa_interface, THIS_MODULE); + gpib_register_driver(&ni_nec_isa_accel_interface, THIS_MODULE); + gpib_register_driver(&ni_pci_interface, THIS_MODULE); + gpib_register_driver(&ni_pci_accel_interface, THIS_MODULE); +#ifdef GPIB_PCMCIA + gpib_register_driver(&ni_pcmcia_interface, THIS_MODULE); + gpib_register_driver(&ni_pcmcia_accel_interface, THIS_MODULE); + if (init_ni_gpib_cs() < 0) + return -1; +#endif + + mite_init(); + mite_list_devices(); + + return 0; +} + +static void __exit tnt4882_exit_module(void) +{ + gpib_unregister_driver(&ni_isa_interface); + gpib_unregister_driver(&ni_isa_accel_interface); + gpib_unregister_driver(&ni_nat4882_isa_interface); + gpib_unregister_driver(&ni_nat4882_isa_accel_interface); + gpib_unregister_driver(&ni_nec_isa_interface); + gpib_unregister_driver(&ni_nec_isa_accel_interface); + gpib_unregister_driver(&ni_pci_interface); + gpib_unregister_driver(&ni_pci_accel_interface); +#ifdef GPIB_PCMCIA + gpib_unregister_driver(&ni_pcmcia_interface); + gpib_unregister_driver(&ni_pcmcia_accel_interface); + exit_ni_gpib_cs(); +#endif + + mite_cleanup(); + + pci_unregister_driver(&tnt4882_pci_driver); +} + +#ifdef GPIB_PCMCIA + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + * you do not define PCMCIA_DEBUG at all, all the debug code will be + * left out. If you compile with PCMCIA_DEBUG=0, the debug code will + * be present but disabled -- but it can then be enabled for specific + * modules at load time with a 'pc_debug=#' option to insmod. + */ +#define PCMCIA_DEBUG 1 +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +module_param(pc_debug, int, 0); +#define DEBUG(n, args...) \ + do {if (pc_debug > (n)) \ + pr_debug(args); } \ + while (0) +#else +#define DEBUG(args...) +#endif + +static int ni_gpib_config(struct pcmcia_device *link); +static void ni_gpib_release(struct pcmcia_device *link); +static int ni_pcmcia_attach(gpib_board_t *board, const gpib_board_config_t *config); +static void ni_pcmcia_detach(gpib_board_t *board); + +/* + * A linked list of "instances" of the dummy device. Each actual + * PCMCIA card corresponds to one device instance, and is described + * by one dev_link_t structure (defined in ds.h). + * + * You may not want to use a linked list for this -- for example, the + * memory card driver uses an array of dev_link_t pointers, where minor + * device numbers are used to derive the corresponding array index. + * + * I think this dev_list is obsolete but the pointer is needed to keep + * the module instance for the ni_pcmcia_attach function. + */ + +static struct pcmcia_device *curr_dev; + +struct local_info_t { + struct pcmcia_device *p_dev; + gpib_board_t *dev; + int stop; + struct bus_operations *bus; +}; + +/* + * ni_gpib_probe() creates an "instance" of the driver, allocating + * local data structures for one device. The device is registered + * with Card Services. + */ + +static int ni_gpib_probe(struct pcmcia_device *link) +{ + struct local_info_t *info; + //struct gpib_board_t *dev; + + DEBUG(0, "%s(0x%p)\n", __func__, link); + + /* Allocate space for private device-specific data */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->p_dev = link; + link->priv = info; + + /* + * General socket configuration defaults can go here. In this + * client, we assume very little, and rely on the CIS for almost + * everything. In most clients, many details (i.e., number, sizes, + * and attributes of IO windows) are fixed by the nature of the + * device, and can be hard-wired here. + */ + link->config_flags = CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + + /* Register with Card Services */ + curr_dev = link; + return ni_gpib_config(link); +} + +/* + * This deletes a driver "instance". The device is de-registered + * with Card Services. If it has been released, all local data + * structures are freed. Otherwise, the structures will be freed + * when the device is released. + */ +static void ni_gpib_remove(struct pcmcia_device *link) +{ + struct local_info_t *info = link->priv; + //struct gpib_board_t *dev = info->dev; + + DEBUG(0, "%s(%p)\n", __func__, link); + + if (info->dev) + ni_pcmcia_detach(info->dev); + ni_gpib_release(link); + + //free_netdev(dev); + kfree(info); +} + +static int ni_gpib_config_iteration(struct pcmcia_device *link, void *priv_data) +{ + int retval; + + retval = pcmcia_request_io(link); + if (retval != 0) + return retval; + + return 0; +} + +/* + * ni_gpib_config() is scheduled to run after a CARD_INSERTION event + * is received, to configure the PCMCIA socket, and to make the + * device available to the system. + */ +static int ni_gpib_config(struct pcmcia_device *link) +{ + //struct local_info_t *info = link->priv; + //gpib_board_t *dev = info->dev; + int last_ret; + + DEBUG(0, "%s(0x%p)\n", __func__, link); + + last_ret = pcmcia_loop_config(link, &ni_gpib_config_iteration, NULL); + if (last_ret) { + dev_warn(&link->dev, "no configuration found\n"); + ni_gpib_release(link); + return last_ret; + } + + last_ret = pcmcia_enable_device(link); + if (last_ret) { + ni_gpib_release(link); + return last_ret; + } + return 0; +} /* ni_gpib_config */ + +/* + * After a card is removed, ni_gpib_release() will unregister the + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ +static void ni_gpib_release(struct pcmcia_device *link) +{ + DEBUG(0, "%s(0x%p)\n", __func__, link); + pcmcia_disable_device(link); +} /* ni_gpib_release */ + +static int ni_gpib_suspend(struct pcmcia_device *link) +{ + //struct local_info_t *info = link->priv; + //struct gpib_board_t *dev = info->dev; + DEBUG(0, "%s(0x%p)\n", __func__, link); + + if (link->open) + pr_err("Device still open ???\n"); + //netif_device_detach(dev); + + return 0; +} + +static int ni_gpib_resume(struct pcmcia_device *link) +{ + //struct local_info_t *info = link->priv; + //struct gpib_board_t *dev = info->dev; + DEBUG(0, "%s(0x%p)\n", __func__, link); + + /*if (link->open) { + * ni_gpib_probe(dev); / really? + * printk("Gpib resumed ???\n"); + * //netif_device_attach(dev); + *} + */ + return ni_gpib_config(link); +} + +static struct pcmcia_device_id ni_pcmcia_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4882), + PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0c71), // NI PCMCIA-GPIB+ + PCMCIA_DEVICE_NULL +}; + +MODULE_DEVICE_TABLE(pcmcia, ni_pcmcia_ids); + +static struct pcmcia_driver ni_gpib_cs_driver = { + .name = "ni_gpib_cs", + .owner = THIS_MODULE, + .drv = { .name = "ni_gpib_cs", }, + .id_table = ni_pcmcia_ids, + .probe = ni_gpib_probe, + .remove = ni_gpib_remove, + .suspend = ni_gpib_suspend, + .resume = ni_gpib_resume, +}; + +int __init init_ni_gpib_cs(void) +{ + return pcmcia_register_driver(&ni_gpib_cs_driver); +} + +void __exit exit_ni_gpib_cs(void) +{ + DEBUG(0, "ni_gpib_cs: unloading\n"); + pcmcia_unregister_driver(&ni_gpib_cs_driver); +} + +static const int pcmcia_gpib_iosize = 32; + +int ni_pcmcia_attach(gpib_board_t *board, const gpib_board_config_t *config) +{ + struct local_info_t *info; + struct tnt4882_priv *tnt_priv; + struct nec7210_priv *nec_priv; + int isr_flags = IRQF_SHARED; + + DEBUG(0, "%s(0x%p)\n", __func__, board); + + if (!curr_dev) { + pr_err("gpib: no NI PCMCIA board found\n"); + return -1; + } + + info = curr_dev->priv; + info->dev = board; + + board->status = 0; + + if (tnt4882_allocate_private(board)) + return -ENOMEM; + tnt_priv = board->private_data; + tnt_priv->io_writeb = outb_wrapper; + tnt_priv->io_readb = inb_wrapper; + tnt_priv->io_writew = outw_wrapper; + tnt_priv->io_readw = inw_wrapper; + nec_priv = &tnt_priv->nec7210_priv; + nec_priv->type = TNT4882; + nec_priv->read_byte = nec7210_locking_ioport_read_byte; + nec_priv->write_byte = nec7210_locking_ioport_write_byte; + nec_priv->offset = atgpib_reg_offset; + + DEBUG(0, "ioport1 window attributes: 0x%lx\n", curr_dev->resource[0]->flags); + if (request_region(curr_dev->resource[0]->start, resource_size(curr_dev->resource[0]), + "tnt4882") == 0) { + pr_err("gpib: ioports starting at 0x%lx are already in use\n", + (unsigned long)curr_dev->resource[0]->start); + return -EIO; + } + + nec_priv->iobase = (void *)(unsigned long)curr_dev->resource[0]->start; + + // get irq + if (request_irq(curr_dev->irq, tnt4882_interrupt, isr_flags, "tnt4882", board)) { + pr_err("gpib: can't request IRQ %d\n", curr_dev->irq); + return -1; + } + tnt_priv->irq = curr_dev->irq; + + tnt4882_init(tnt_priv, board); + + return 0; +} + +void ni_pcmcia_detach(gpib_board_t *board) +{ + struct tnt4882_priv *tnt_priv = board->private_data; + struct nec7210_priv *nec_priv; + + DEBUG(0, "%s(0x%p)\n", __func__, board); + + if (tnt_priv) { + nec_priv = &tnt_priv->nec7210_priv; + if (tnt_priv->irq) + free_irq(tnt_priv->irq, board); + if (nec_priv->iobase) { + tnt4882_board_reset(tnt_priv, board); + release_region((unsigned long)nec_priv->iobase, pcmcia_gpib_iosize); + } + } + tnt4882_free_private(board); +} + +#endif // GPIB_PCMCIA + +module_init(tnt4882_init_module); +module_exit(tnt4882_exit_module); diff --git a/drivers/staging/gpib/uapi/gpib_ioctl.h b/drivers/staging/gpib/uapi/gpib_ioctl.h new file mode 100644 index 00000000000000..6202865278ea7c --- /dev/null +++ b/drivers/staging/gpib/uapi/gpib_ioctl.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _GPIB_IOCTL_H +#define _GPIB_IOCTL_H + +#include +#include + +#define GPIB_CODE 160 + +typedef struct { + char name[100]; +} board_type_ioctl_t; + +/* argument for read/write/command ioctls */ +typedef struct { + uint64_t buffer_ptr; + unsigned int requested_transfer_count; + unsigned int completed_transfer_count; + int end; /* end flag return for reads, end io suppression request for cmd*/ + int handle; +} read_write_ioctl_t; + +typedef struct { + unsigned int handle; + unsigned int pad; + int sad; + unsigned is_board : 1; +} open_dev_ioctl_t; + +typedef struct { + unsigned int handle; +} close_dev_ioctl_t; + +typedef struct { + unsigned int pad; + int sad; + uint8_t status_byte; +} serial_poll_ioctl_t; + +typedef struct { + int eos; + int eos_flags; +} eos_ioctl_t; + +typedef struct { + int handle; + int wait_mask; + int clear_mask; + int set_mask; + int ibsta; + int pad; + int sad; + unsigned int usec_timeout; +} wait_ioctl_t; + +typedef struct { + uint64_t init_data_ptr; + int init_data_length; + int online; +} online_ioctl_t; + +typedef struct { + unsigned int num_bytes; + unsigned int pad; + int sad; +} spoll_bytes_ioctl_t; + +typedef struct { + unsigned int pad; + int sad; + int parallel_poll_configuration; + int autopolling; + int is_system_controller; + unsigned int t1_delay; + unsigned ist : 1; + unsigned no_7_bit_eos : 1; +} board_info_ioctl_t; + +typedef struct { + int pci_bus; + int pci_slot; +} select_pci_ioctl_t; + +typedef struct { + uint8_t config; + unsigned set_ist : 1; + unsigned clear_ist : 1; +} ppoll_config_ioctl_t; + +typedef struct { + unsigned int handle; + unsigned int pad; +} pad_ioctl_t; + +typedef struct { + unsigned int handle; + int sad; +} sad_ioctl_t; + +// select a piece of hardware to attach by its sysfs device path +typedef struct { + char device_path[0x1000]; +} select_device_path_ioctl_t; + +typedef short event_ioctl_t; +typedef int rsc_ioctl_t; +typedef unsigned int t1_delay_ioctl_t; +typedef short autospoll_ioctl_t; +typedef short local_ppoll_mode_ioctl_t; + +// update status byte and request service +typedef struct { + uint8_t status_byte; + int new_reason_for_service; +} request_service2_t; + +/* Standard functions. */ +enum gpib_ioctl { + IBRD = _IOWR(GPIB_CODE, 100, read_write_ioctl_t), + IBWRT = _IOWR(GPIB_CODE, 101, read_write_ioctl_t), + IBCMD = _IOWR(GPIB_CODE, 102, read_write_ioctl_t), + IBOPENDEV = _IOWR(GPIB_CODE, 3, open_dev_ioctl_t), + IBCLOSEDEV = _IOW(GPIB_CODE, 4, close_dev_ioctl_t), + IBWAIT = _IOWR(GPIB_CODE, 5, wait_ioctl_t), + IBRPP = _IOWR(GPIB_CODE, 6, uint8_t), + + IBSIC = _IOW(GPIB_CODE, 9, unsigned int), + IBSRE = _IOW(GPIB_CODE, 10, int), + IBGTS = _IO(GPIB_CODE, 11), + IBCAC = _IOW(GPIB_CODE, 12, int), + IBLINES = _IOR(GPIB_CODE, 14, short), + IBPAD = _IOW(GPIB_CODE, 15, pad_ioctl_t), + IBSAD = _IOW(GPIB_CODE, 16, sad_ioctl_t), + IBTMO = _IOW(GPIB_CODE, 17, unsigned int), + IBRSP = _IOWR(GPIB_CODE, 18, serial_poll_ioctl_t), + IBEOS = _IOW(GPIB_CODE, 19, eos_ioctl_t), + IBRSV = _IOW(GPIB_CODE, 20, uint8_t), + CFCBASE = _IOW(GPIB_CODE, 21, uint64_t), + CFCIRQ = _IOW(GPIB_CODE, 22, unsigned int), + CFCDMA = _IOW(GPIB_CODE, 23, unsigned int), + CFCBOARDTYPE = _IOW(GPIB_CODE, 24, board_type_ioctl_t), + + IBMUTEX = _IOW(GPIB_CODE, 26, int), + IBSPOLL_BYTES = _IOWR(GPIB_CODE, 27, spoll_bytes_ioctl_t), + IBPPC = _IOW(GPIB_CODE, 28, ppoll_config_ioctl_t), + IBBOARD_INFO = _IOR(GPIB_CODE, 29, board_info_ioctl_t), + + IBQUERY_BOARD_RSV = _IOR(GPIB_CODE, 31, int), + IBSELECT_PCI = _IOWR(GPIB_CODE, 32, select_pci_ioctl_t), + IBEVENT = _IOR(GPIB_CODE, 33, event_ioctl_t), + IBRSC = _IOW(GPIB_CODE, 34, rsc_ioctl_t), + IB_T1_DELAY = _IOW(GPIB_CODE, 35, t1_delay_ioctl_t), + IBLOC = _IO(GPIB_CODE, 36), + + IBAUTOSPOLL = _IOW(GPIB_CODE, 38, autospoll_ioctl_t), + IBONL = _IOW(GPIB_CODE, 39, online_ioctl_t), + IBPP2_SET = _IOW(GPIB_CODE, 40, local_ppoll_mode_ioctl_t), + IBPP2_GET = _IOR(GPIB_CODE, 41, local_ppoll_mode_ioctl_t), + IBSELECT_DEVICE_PATH = _IOW(GPIB_CODE, 43, select_device_path_ioctl_t), + // 44 was IBSELECT_SERIAL_NUMBER + IBRSV2 = _IOW(GPIB_CODE, 45, request_service2_t) +}; + +#endif /* _GPIB_IOCTL_H */ diff --git a/drivers/staging/gpib/uapi/gpib_user.h b/drivers/staging/gpib/uapi/gpib_user.h new file mode 100644 index 00000000000000..0896a55a758fee --- /dev/null +++ b/drivers/staging/gpib/uapi/gpib_user.h @@ -0,0 +1,363 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/*************************************************************************** + * copyright : (C) 2002 by Frank Mori Hess + ***************************************************************************/ + +#ifndef _GPIB_USER_H +#define _GPIB_USER_H + +#define GPIB_MAX_NUM_BOARDS 16 +#define GPIB_MAX_NUM_DESCRIPTORS 0x1000 + +enum ibsta_bit_numbers { + DCAS_NUM = 0, + DTAS_NUM = 1, + LACS_NUM = 2, + TACS_NUM = 3, + ATN_NUM = 4, + CIC_NUM = 5, + REM_NUM = 6, + LOK_NUM = 7, + CMPL_NUM = 8, + EVENT_NUM = 9, + SPOLL_NUM = 10, + RQS_NUM = 11, + SRQI_NUM = 12, + END_NUM = 13, + TIMO_NUM = 14, + ERR_NUM = 15 +}; + +/* IBSTA status bits (returned by all functions) */ +enum ibsta_bits { + DCAS = (1 << DCAS_NUM), /* device clear state */ + DTAS = (1 << DTAS_NUM), /* device trigger state */ + LACS = (1 << LACS_NUM), /* GPIB interface is addressed as Listener */ + TACS = (1 << TACS_NUM), /* GPIB interface is addressed as Talker */ + ATN = (1 << ATN_NUM), /* Attention is asserted */ + CIC = (1 << CIC_NUM), /* GPIB interface is Controller-in-Charge */ + REM = (1 << REM_NUM), /* remote state */ + LOK = (1 << LOK_NUM), /* lockout state */ + CMPL = (1 << CMPL_NUM), /* I/O is complete */ + EVENT = (1 << EVENT_NUM), /* DCAS, DTAS, or IFC has occurred */ + SPOLL = (1 << SPOLL_NUM), /* board serial polled by busmaster */ + RQS = (1 << RQS_NUM), /* Device requesting service */ + SRQI = (1 << SRQI_NUM), /* SRQ is asserted */ + END = (1 << END_NUM), /* EOI or EOS encountered */ + TIMO = (1 << TIMO_NUM), /* Time limit on I/O or wait function exceeded */ + ERR = (1 << ERR_NUM), /* Function call terminated on error */ + + device_status_mask = ERR | TIMO | END | CMPL | RQS, + board_status_mask = ERR | TIMO | END | CMPL | SPOLL | + EVENT | LOK | REM | CIC | ATN | TACS | LACS | DTAS | DCAS | SRQI, +}; + +/* IBERR error codes */ +enum iberr_code { + EDVR = 0, /* system error */ + ECIC = 1, /* not CIC */ + ENOL = 2, /* no listeners */ + EADR = 3, /* CIC and not addressed before I/O */ + EARG = 4, /* bad argument to function call */ + ESAC = 5, /* not SAC */ + EABO = 6, /* I/O operation was aborted */ + ENEB = 7, /* non-existent board (GPIB interface offline) */ + EDMA = 8, /* DMA hardware error detected */ + EOIP = 10, /* new I/O attempted with old I/O in progress */ + ECAP = 11, /* no capability for intended opeation */ + EFSO = 12, /* file system operation error */ + EBUS = 14, /* bus error */ + ESTB = 15, /* lost serial poll bytes */ + ESRQ = 16, /* SRQ stuck on */ + ETAB = 20 /* Table Overflow */ +}; + +/* Timeout values and meanings */ +enum gpib_timeout { + TNONE = 0, /* Infinite timeout (disabled) */ + T10us = 1, /* Timeout of 10 usec (ideal) */ + T30us = 2, /* Timeout of 30 usec (ideal) */ + T100us = 3, /* Timeout of 100 usec (ideal) */ + T300us = 4, /* Timeout of 300 usec (ideal) */ + T1ms = 5, /* Timeout of 1 msec (ideal) */ + T3ms = 6, /* Timeout of 3 msec (ideal) */ + T10ms = 7, /* Timeout of 10 msec (ideal) */ + T30ms = 8, /* Timeout of 30 msec (ideal) */ + T100ms = 9, /* Timeout of 100 msec (ideal) */ + T300ms = 10, /* Timeout of 300 msec (ideal) */ + T1s = 11, /* Timeout of 1 sec (ideal) */ + T3s = 12, /* Timeout of 3 sec (ideal) */ + T10s = 13, /* Timeout of 10 sec (ideal) */ + T30s = 14, /* Timeout of 30 sec (ideal) */ + T100s = 15, /* Timeout of 100 sec (ideal) */ + T300s = 16, /* Timeout of 300 sec (ideal) */ + T1000s = 17 /* Timeout of 1000 sec (maximum) */ +}; + +/* End-of-string (EOS) modes for use with ibeos */ + +enum eos_flags { + EOS_MASK = 0x1c00, + REOS = 0x0400, /* Terminate reads on EOS */ + XEOS = 0x800, /* assert EOI when EOS char is sent */ + BIN = 0x1000 /* Do 8-bit compare on EOS */ +}; + +/* GPIB Bus Control Lines bit vector */ +enum bus_control_line { + ValidDAV = 0x01, + ValidNDAC = 0x02, + ValidNRFD = 0x04, + ValidIFC = 0x08, + ValidREN = 0x10, + ValidSRQ = 0x20, + ValidATN = 0x40, + ValidEOI = 0x80, + ValidALL = 0xff, + BusDAV = 0x0100, /* DAV line status bit */ + BusNDAC = 0x0200, /* NDAC line status bit */ + BusNRFD = 0x0400, /* NRFD line status bit */ + BusIFC = 0x0800, /* IFC line status bit */ + BusREN = 0x1000, /* REN line status bit */ + BusSRQ = 0x2000, /* SRQ line status bit */ + BusATN = 0x4000, /* ATN line status bit */ + BusEOI = 0x8000 /* EOI line status bit */ +}; + +enum old_bus_control_line { + BUS_DAV = 0x0100, /* DAV line status bit */ + BUS_NDAC = 0x0200, /* NDAC line status bit */ + BUS_NRFD = 0x0400, /* NRFD line status bit */ + BUS_IFC = 0x0800, /* IFC line status bit */ + BUS_REN = 0x1000, /* REN line status bit */ + BUS_SRQ = 0x2000, /* SRQ line status bit */ + BUS_ATN = 0x4000, /* ATN line status bit */ + BUS_EOI = 0x8000 /* EOI line status bit */ +}; + +/* Possible GPIB command messages */ + +enum cmd_byte { + GTL = 0x1, /* go to local */ + SDC = 0x4, /* selected device clear */ + PPConfig = 0x5, +#ifndef PPC + PPC = PPConfig, /* parallel poll configure */ +#endif + GET = 0x8, /* group execute trigger */ + TCT = 0x9, /* take control */ + LLO = 0x11, /* local lockout */ + DCL = 0x14, /* device clear */ + PPU = 0x15, /* parallel poll unconfigure */ + SPE = 0x18, /* serial poll enable */ + SPD = 0x19, /* serial poll disable */ + CFE = 0x1f, /* configure enable */ + LAD = 0x20, /* value to be 'ored' in to obtain listen address */ + UNL = 0x3F, /* unlisten */ + TAD = 0x40, /* value to be 'ored' in to obtain talk address */ + UNT = 0x5F, /* untalk */ + SAD = 0x60, /* my secondary address (base) */ + PPE = 0x60, /* parallel poll enable (base) */ + PPD = 0x70 /* parallel poll disable */ +}; + +enum ppe_bits { + PPC_DISABLE = 0x10, + PPC_SENSE = 0x8, /* parallel poll sense bit */ + PPC_DIO_MASK = 0x7 +}; + +/* confine address to range 0 to 30. */ +static inline unsigned int gpib_address_restrict(unsigned int addr) +{ + addr &= 0x1f; + if (addr == 0x1f) + addr = 0; + return addr; +} + +static inline uint8_t MLA(unsigned int addr) +{ + return gpib_address_restrict(addr) | LAD; +} + +static inline uint8_t MTA(unsigned int addr) +{ + return gpib_address_restrict(addr) | TAD; +} + +static inline uint8_t MSA(unsigned int addr) +{ + return gpib_address_restrict(addr) | SAD; +} + +static inline uint8_t PPE_byte(unsigned int dio_line, int sense) +{ + uint8_t cmd; + + cmd = PPE; + if (sense) + cmd |= PPC_SENSE; + cmd |= (dio_line - 1) & 0x7; + return cmd; +} + +static inline uint8_t CFGn(unsigned int meters) +{ + return 0x6 | (meters & 0xf); +} + +/* mask of bits that actually matter in a command byte */ +enum { + gpib_command_mask = 0x7f, +}; + +static inline int is_PPE(uint8_t command) +{ + return (command & 0x70) == 0x60; +} + +static inline int is_PPD(uint8_t command) +{ + return (command & 0x70) == 0x70; +} + +static inline int in_addressed_command_group(uint8_t command) +{ + return (command & 0x70) == 0x0; +} + +static inline int in_universal_command_group(uint8_t command) +{ + return (command & 0x70) == 0x10; +} + +static inline int in_listen_address_group(uint8_t command) +{ + return (command & 0x60) == 0x20; +} + +static inline int in_talk_address_group(uint8_t command) +{ + return (command & 0x60) == 0x40; +} + +static inline int in_primary_command_group(uint8_t command) +{ + return in_addressed_command_group(command) || + in_universal_command_group(command) || + in_listen_address_group(command) || + in_talk_address_group(command); +} + +static inline int gpib_address_equal(unsigned int pad1, int sad1, unsigned int pad2, int sad2) +{ + if (pad1 == pad2) { + if (sad1 == sad2) + return 1; + if (sad1 < 0 && sad2 < 0) + return 1; + } + + return 0; +} + +enum ibask_option { + IbaPAD = 0x1, + IbaSAD = 0x2, + IbaTMO = 0x3, + IbaEOT = 0x4, + IbaPPC = 0x5, /* board only */ + IbaREADDR = 0x6, /* device only */ + IbaAUTOPOLL = 0x7, /* board only */ + IbaCICPROT = 0x8, /* board only */ + IbaIRQ = 0x9, /* board only */ + IbaSC = 0xa, /* board only */ + IbaSRE = 0xb, /* board only */ + IbaEOSrd = 0xc, + IbaEOSwrt = 0xd, + IbaEOScmp = 0xe, + IbaEOSchar = 0xf, + IbaPP2 = 0x10, /* board only */ + IbaTIMING = 0x11, /* board only */ + IbaDMA = 0x12, /* board only */ + IbaReadAdjust = 0x13, + IbaWriteAdjust = 0x14, + IbaEventQueue = 0x15, /* board only */ + IbaSPollBit = 0x16, /* board only */ + IbaSpollBit = 0x16, /* board only */ + IbaSendLLO = 0x17, /* board only */ + IbaSPollTime = 0x18, /* device only */ + IbaPPollTime = 0x19, /* board only */ + IbaEndBitIsNormal = 0x1a, + IbaUnAddr = 0x1b, /* device only */ + IbaHSCableLength = 0x1f, /* board only */ + IbaIst = 0x20, /* board only */ + IbaRsv = 0x21, /* board only */ + IbaBNA = 0x200, /* device only */ + /* linux-gpib extensions */ + Iba7BitEOS = 0x1000 /* board only. Returns 1 if board supports 7 bit eos compares*/ +}; + +enum ibconfig_option { + IbcPAD = 0x1, + IbcSAD = 0x2, + IbcTMO = 0x3, + IbcEOT = 0x4, + IbcPPC = 0x5, /* board only */ + IbcREADDR = 0x6, /* device only */ + IbcAUTOPOLL = 0x7, /* board only */ + IbcCICPROT = 0x8, /* board only */ + IbcIRQ = 0x9, /* board only */ + IbcSC = 0xa, /* board only */ + IbcSRE = 0xb, /* board only */ + IbcEOSrd = 0xc, + IbcEOSwrt = 0xd, + IbcEOScmp = 0xe, + IbcEOSchar = 0xf, + IbcPP2 = 0x10, /* board only */ + IbcTIMING = 0x11, /* board only */ + IbcDMA = 0x12, /* board only */ + IbcReadAdjust = 0x13, + IbcWriteAdjust = 0x14, + IbcEventQueue = 0x15, /* board only */ + IbcSPollBit = 0x16, /* board only */ + IbcSpollBit = 0x16, /* board only */ + IbcSendLLO = 0x17, /* board only */ + IbcSPollTime = 0x18, /* device only */ + IbcPPollTime = 0x19, /* board only */ + IbcEndBitIsNormal = 0x1a, + IbcUnAddr = 0x1b, /* device only */ + IbcHSCableLength = 0x1f, /* board only */ + IbcIst = 0x20, /* board only */ + IbcRsv = 0x21, /* board only */ + IbcBNA = 0x200 /* device only */ +}; + +enum t1_delays { + T1_DELAY_2000ns = 1, + T1_DELAY_500ns = 2, + T1_DELAY_350ns = 3 +}; + +enum { + request_service_bit = 0x40, +}; + +enum gpib_events { + EventNone = 0, + EventDevTrg = 1, + EventDevClr = 2, + EventIFC = 3 +}; + +enum gpib_stb { + IbStbRQS = 0x40, /* IEEE 488.1 & 2 */ + IbStbESB = 0x20, /* IEEE 488.2 only */ + IbStbMAV = 0x10 /* IEEE 488.2 only */ +}; + +#endif /* _GPIB_USER_H */ + +/* Check for errors */ diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c index aa6f266b62a141..90ab32638d3f59 100644 --- a/drivers/staging/greybus/arche-apb-ctrl.c +++ b/drivers/staging/greybus/arche-apb-ctrl.c @@ -470,7 +470,7 @@ MODULE_DEVICE_TABLE(of, arche_apb_ctrl_of_match); static struct platform_driver arche_apb_ctrl_device_driver = { .probe = arche_apb_ctrl_probe, - .remove_new = arche_apb_ctrl_remove, + .remove = 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 b33977ccd52710..d48464390f58e2 100644 --- a/drivers/staging/greybus/arche-platform.c +++ b/drivers/staging/greybus/arche-platform.c @@ -623,7 +623,7 @@ MODULE_DEVICE_TABLE(of, arche_platform_of_match); static struct platform_driver arche_platform_device_driver = { .probe = arche_platform_probe, - .remove_new = arche_platform_remove, + .remove = arche_platform_remove, .shutdown = arche_platform_shutdown, .driver = { .name = "arche-platform-ctrl", diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c index 9b26e148d40fba..16bcf7fc815865 100644 --- a/drivers/staging/greybus/gpio.c +++ b/drivers/staging/greybus/gpio.c @@ -42,11 +42,6 @@ struct gb_gpio_controller { struct mutex irq_lock; }; -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) { return d->domain->host_data; @@ -278,7 +273,7 @@ static void _gb_gpio_irq_set_type(struct gb_gpio_controller *ggc, static void gb_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *chip = irq_data_to_gpio_chip(d); - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); struct gb_gpio_line *line = &ggc->lines[d->hwirq]; line->masked = true; @@ -288,7 +283,7 @@ static void gb_gpio_irq_mask(struct irq_data *d) static void gb_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *chip = irq_data_to_gpio_chip(d); - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); struct gb_gpio_line *line = &ggc->lines[d->hwirq]; line->masked = false; @@ -298,7 +293,7 @@ static void gb_gpio_irq_unmask(struct irq_data *d) static int gb_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct gpio_chip *chip = irq_data_to_gpio_chip(d); - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); struct gb_gpio_line *line = &ggc->lines[d->hwirq]; struct device *dev = &ggc->gbphy_dev->dev; u8 irq_type; @@ -336,7 +331,7 @@ static int gb_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void gb_gpio_irq_bus_lock(struct irq_data *d) { struct gpio_chip *chip = irq_data_to_gpio_chip(d); - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); mutex_lock(&ggc->irq_lock); } @@ -344,7 +339,7 @@ static void gb_gpio_irq_bus_lock(struct irq_data *d) static void gb_gpio_irq_bus_sync_unlock(struct irq_data *d) { struct gpio_chip *chip = irq_data_to_gpio_chip(d); - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); struct gb_gpio_line *line = &ggc->lines[d->hwirq]; if (line->irq_type_pending) { @@ -407,21 +402,21 @@ static int gb_gpio_request_handler(struct gb_operation *op) static int gb_gpio_request(struct gpio_chip *chip, unsigned int offset) { - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); return gb_gpio_activate_operation(ggc, (u8)offset); } static void gb_gpio_free(struct gpio_chip *chip, unsigned int offset) { - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); gb_gpio_deactivate_operation(ggc, (u8)offset); } static int gb_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); u8 which; int ret; @@ -435,7 +430,7 @@ static int gb_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) static int gb_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); return gb_gpio_direction_in_operation(ggc, (u8)offset); } @@ -443,14 +438,14 @@ static int gb_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) static int gb_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); return gb_gpio_direction_out_operation(ggc, (u8)offset, !!value); } static int gb_gpio_get(struct gpio_chip *chip, unsigned int offset) { - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); u8 which; int ret; @@ -464,7 +459,7 @@ static int gb_gpio_get(struct gpio_chip *chip, unsigned int offset) static void gb_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); gb_gpio_set_value_operation(ggc, (u8)offset, !!value); } @@ -472,7 +467,7 @@ static void gb_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) static int gb_gpio_set_config(struct gpio_chip *chip, unsigned int offset, unsigned long config) { - struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip); + struct gb_gpio_controller *ggc = gpiochip_get_data(chip); u32 debounce; if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) @@ -579,7 +574,7 @@ static int gb_gpio_probe(struct gbphy_device *gbphy_dev, if (ret) goto exit_line_free; - ret = gpiochip_add_data(gpio, NULL); + ret = gpiochip_add_data(gpio, ggc); if (ret) { dev_err(&gbphy_dev->dev, "failed to add gpio chip: %d\n", ret); goto exit_line_free; diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index cdf4ebb93b104e..8eab94cb06faf6 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -596,11 +596,13 @@ static int get_serial_info(struct tty_struct *tty, struct gb_tty *gb_tty = tty->driver_data; ss->line = gb_tty->minor; + mutex_lock(&gb_tty->port.mutex); ss->close_delay = jiffies_to_msecs(gb_tty->port.close_delay) / 10; ss->closing_wait = gb_tty->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : jiffies_to_msecs(gb_tty->port.closing_wait) / 10; + mutex_unlock(&gb_tty->port.mutex); return 0; } diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO deleted file mode 100644 index 0fa6a5500bdb10..00000000000000 --- a/drivers/staging/iio/TODO +++ /dev/null @@ -1,5 +0,0 @@ -2020-02-25 - - -Contact: Jonathan Cameron . -Mailing list: linux-iio@vger.kernel.org diff --git a/drivers/staging/iio/accel/adis16203.c b/drivers/staging/iio/accel/adis16203.c index c0e4c9266b5f4a..c1c73308800c50 100644 --- a/drivers/staging/iio/accel/adis16203.c +++ b/drivers/staging/iio/accel/adis16203.c @@ -312,4 +312,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16203"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/staging/iio/accel/adis16240.c b/drivers/staging/iio/accel/adis16240.c index 337492785f04c9..3be3eaf5d9d4d4 100644 --- a/drivers/staging/iio/accel/adis16240.c +++ b/drivers/staging/iio/accel/adis16240.c @@ -440,4 +440,4 @@ MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); MODULE_DESCRIPTION("Analog Devices Programmable Impact Sensor and Recorder"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:adis16240"); -MODULE_IMPORT_NS(IIO_ADISLIB); +MODULE_IMPORT_NS("IIO_ADISLIB"); diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 4ae1a7039418b1..d5544fc2fe989b 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -628,9 +628,9 @@ static void ad5933_work(struct work_struct *work) int scan_count = bitmap_weight(indio_dev->active_scan_mask, iio_get_masklength(indio_dev)); ret = ad5933_i2c_read(st->client, - test_bit(1, indio_dev->active_scan_mask) ? - AD5933_REG_REAL_DATA : AD5933_REG_IMAG_DATA, - scan_count * 2, (u8 *)buf); + test_bit(1, indio_dev->active_scan_mask) ? + AD5933_REG_REAL_DATA : AD5933_REG_IMAG_DATA, + scan_count * 2, (u8 *)buf); if (ret) return; diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 554c2e475ce3bf..b4421485439954 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -32,8 +32,6 @@ source "drivers/staging/media/max96712/Kconfig" source "drivers/staging/media/meson/vdec/Kconfig" -source "drivers/staging/media/omap4iss/Kconfig" - source "drivers/staging/media/rkvdec/Kconfig" source "drivers/staging/media/starfive/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index dcaeeca0ee6d72..ad4e9619a9e07d 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_INTEL_ATOMISP) += atomisp/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ -obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 8710c483015c69..f5ab23592f29f4 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -27,16 +27,6 @@ config VIDEO_ATOMISP_GC2235 It currently only works with the atomisp driver. -config VIDEO_ATOMISP_MSRLIST_HELPER - tristate "Helper library to load, parse and apply large register lists." - depends on I2C - help - This is a helper library to be used from a sensor driver to load, parse - and apply large register lists. - - To compile this driver as a module, choose M here: the - module will be called libmsrlisthelper. - config VIDEO_ATOMISP_MT9M114 tristate "Aptina mt9m114 sensor support" depends on ACPI diff --git a/drivers/staging/media/atomisp/i2c/Makefile b/drivers/staging/media/atomisp/i2c/Makefile index 3073cfa75ecfa9..021a7ea0a075d0 100644 --- a/drivers/staging/media/atomisp/i2c/Makefile +++ b/drivers/staging/media/atomisp/i2c/Makefile @@ -7,5 +7,3 @@ obj-$(CONFIG_VIDEO_ATOMISP_MT9M114) += atomisp-mt9m114.o obj-$(CONFIG_VIDEO_ATOMISP_GC2235) += atomisp-gc2235.o obj-$(CONFIG_VIDEO_ATOMISP_OV2722) += atomisp-ov2722.o obj-$(CONFIG_VIDEO_ATOMISP_GC0310) += atomisp-gc0310.o - -obj-$(CONFIG_VIDEO_ATOMISP_MSRLIST_HELPER) += atomisp-libmsrlisthelper.o diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 5bcd634a2a44df..d35394f1ddbb84 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -4,16 +4,6 @@ * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. * Copyright (c) 2023 Hans de Goede - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 994b8bceb4f5fe..857d7175942cd8 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -3,16 +3,6 @@ * Support for GalaxyCore GC2235 2M camera sensor. * * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c deleted file mode 100644 index 3499353f8ea5ba..00000000000000 --- a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c +++ /dev/null @@ -1,211 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ -#include -#include -#include -#include -#include "../include/linux/libmsrlisthelper.h" -#include -#include - -/* Tagged binary data container structure definitions. */ -struct tbd_header { - u32 tag; /*!< Tag identifier, also checks endianness */ - u32 size; /*!< Container size including this header */ - u32 version; /*!< Version, format 0xYYMMDDVV */ - u32 revision; /*!< Revision, format 0xYYMMDDVV */ - u32 config_bits; /*!< Configuration flag bits set */ - u32 checksum; /*!< Global checksum, header included */ -} __packed; - -struct tbd_record_header { - u32 size; /*!< Size of record including header */ - u8 format_id; /*!< tbd_format_t enumeration values used */ - u8 packing_key; /*!< Packing method; 0 = no packing */ - u16 class_id; /*!< tbd_class_t enumeration values used */ -} __packed; - -struct tbd_data_record_header { - u16 next_offset; - u16 flags; - u16 data_offset; - u16 data_size; -} __packed; - -#define TBD_CLASS_DRV_ID 2 - -static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr, - unsigned int size) -{ - /* - * The configuration data contains any number of sequences where - * the first byte (that is, uint8_t) that marks the number of bytes - * in the sequence to follow, is indeed followed by the indicated - * number of bytes of actual data to be written to sensor. - * By convention, the first two bytes of actual data should be - * understood as an address in the sensor address space (hibyte - * followed by lobyte) where the remaining data in the sequence - * will be written. - */ - - u8 *ptr = bufptr; - - while (ptr < bufptr + size) { - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - }; - int ret; - - /* How many bytes */ - msg.len = *ptr++; - /* Where the bytes are located */ - msg.buf = ptr; - ptr += msg.len; - - if (ptr > bufptr + size) - /* Accessing data beyond bounds is not tolerated */ - return -EINVAL; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_err(&client->dev, "i2c write error: %d", ret); - return ret; - } - } - return 0; -} - -static int parse_and_apply(struct i2c_client *client, uint8_t *buffer, - unsigned int size) -{ - u8 *endptr8 = buffer + size; - struct tbd_data_record_header *header = - (struct tbd_data_record_header *)buffer; - - /* There may be any number of datasets present */ - unsigned int dataset = 0; - - do { - /* In below, four variables are read from buffer */ - if ((uint8_t *)header + sizeof(*header) > endptr8) - return -EINVAL; - - /* All data should be located within given buffer */ - if ((uint8_t *)header + header->data_offset + - header->data_size > endptr8) - return -EINVAL; - - /* We have a new valid dataset */ - dataset++; - /* See whether there is MSR data */ - /* If yes, update the reg info */ - if (header->data_size && (header->flags & 1)) { - int ret; - - dev_info(&client->dev, - "New MSR data for sensor driver (dataset %02d) size:%d\n", - dataset, header->data_size); - ret = set_msr_configuration(client, - buffer + header->data_offset, - header->data_size); - if (ret) - return ret; - } - header = (struct tbd_data_record_header *)(buffer + - header->next_offset); - } while (header->next_offset); - - return 0; -} - -int apply_msr_data(struct i2c_client *client, const struct firmware *fw) -{ - struct tbd_header *header; - struct tbd_record_header *record; - - if (!fw) { - dev_warn(&client->dev, "Drv data is not loaded.\n"); - return -EINVAL; - } - - if (sizeof(*header) > fw->size) - return -EINVAL; - - header = (struct tbd_header *)fw->data; - /* Check that we have drvb block. */ - if (memcmp(&header->tag, "DRVB", 4)) - return -EINVAL; - - /* Check the size */ - if (header->size != fw->size) - return -EINVAL; - - if (sizeof(*header) + sizeof(*record) > fw->size) - return -EINVAL; - - record = (struct tbd_record_header *)(header + 1); - /* Check that class id mathes tbd's drv id. */ - if (record->class_id != TBD_CLASS_DRV_ID) - return -EINVAL; - - /* Size 0 shall not be treated as an error */ - if (!record->size) - return 0; - - return parse_and_apply(client, (uint8_t *)(record + 1), record->size); -} -EXPORT_SYMBOL_GPL(apply_msr_data); - -int load_msr_list(struct i2c_client *client, char *name, - const struct firmware **fw) -{ - int ret = request_firmware(fw, name, &client->dev); - - if (ret) { - dev_err(&client->dev, - "Error %d while requesting firmware %s\n", - ret, name); - return ret; - } - dev_info(&client->dev, "Received %lu bytes drv data\n", - (unsigned long)(*fw)->size); - - return 0; -} -EXPORT_SYMBOL_GPL(load_msr_list); - -void release_msr_list(struct i2c_client *client, const struct firmware *fw) -{ - release_firmware(fw); -} -EXPORT_SYMBOL_GPL(release_msr_list); - -static int init_msrlisthelper(void) -{ - return 0; -} - -static void exit_msrlisthelper(void) -{ -} - -module_init(init_msrlisthelper); -module_exit(exit_msrlisthelper); - -MODULE_AUTHOR("Jukka Kaartinen "); -MODULE_DESCRIPTION("Helper library to load, parse and apply large register lists"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 918ea4fa9f6beb..4658aeeb88fdb3 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -3,17 +3,6 @@ * Support for mt9m114 Camera Sensor. * * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include @@ -30,6 +19,7 @@ #include #include #include +#include #include "../include/linux/atomisp_gmin_platform.h" #include @@ -664,6 +654,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd, fmt->width = res->width; fmt->height = res->height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { *v4l2_subdev_state_get_format(sd_state, 0) = *fmt; @@ -1224,6 +1215,7 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { .def = 0, .flags = 0, }, +#if 0 /* Causes v4l2_ctrl_new_custom() to fail with -ERANGE, disable for now */ { .ops = &ctrl_ops, .id = V4L2_CID_3A_LOCK, @@ -1235,6 +1227,7 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { .def = 0, .flags = 0, }, +#endif }; static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client) @@ -1525,7 +1518,6 @@ static void mt9m114_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); media_entity_cleanup(&dev->sd.entity); v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); } static int mt9m114_probe(struct i2c_client *client) @@ -1536,10 +1528,14 @@ static int mt9m114_probe(struct i2c_client *client) void *pdata; /* Setup sensor configuration structure */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; + ret = devm_mutex_init(&client->dev, &dev->input_lock); + if (ret) + return ret; + v4l2_i2c_subdev_init(&dev->sd, client, &mt9m114_ops); pdata = gmin_camera_platform_data(&dev->sd, ATOMISP_INPUT_FORMAT_RAW_10, @@ -1548,14 +1544,12 @@ static int mt9m114_probe(struct i2c_client *client) ret = mt9m114_s_config(&dev->sd, client->irq, pdata); if (!pdata || ret) { v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); return ret; } ret = atomisp_register_i2c_module(&dev->sd, pdata); if (ret) { v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); /* Coverity CID 298095 - return on error */ return ret; } diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index c31a81d64950f1..c7de7800799aad 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -3,16 +3,6 @@ * Support for OmniVision OV2722 1080p HD camera sensor. * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index ade28950db7329..6c743a17f198be 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -3,19 +3,6 @@ * Support for GalaxyCore GC2235 2M camera sensor. * * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. - * */ #ifndef __GC2235_H__ diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h index b0cd1b7243945c..97820db90827e2 100644 --- a/drivers/staging/media/atomisp/i2c/mt9m114.h +++ b/drivers/staging/media/atomisp/i2c/mt9m114.h @@ -3,17 +3,6 @@ * Support for mt9m114 Camera Sensor. * * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __A1040_H__ diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index 5920a4d45d06e4..bc36133f372222 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -3,17 +3,6 @@ * Support for OmniVision OV2722 1080p HD camera sensor. * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __OV2722_H__ diff --git a/drivers/staging/media/atomisp/include/hmm/hmm.h b/drivers/staging/media/atomisp/include/hmm/hmm.h index 2bc323b34f8944..a7aef27f54de83 100644 --- a/drivers/staging/media/atomisp/include/hmm/hmm.h +++ b/drivers/staging/media/atomisp/include/hmm/hmm.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __HMM_H__ diff --git a/drivers/staging/media/atomisp/include/hmm/hmm_bo.h b/drivers/staging/media/atomisp/include/hmm/hmm_bo.h index b4c03e0ca9c017..e09ac29ac43d4a 100644 --- a/drivers/staging/media/atomisp/include/hmm/hmm_bo.h +++ b/drivers/staging/media/atomisp/include/hmm/hmm_bo.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __HMM_BO_H__ @@ -159,12 +148,12 @@ void hmm_bo_device_exit(struct hmm_bo_device *bdev); int hmm_bo_device_inited(struct hmm_bo_device *bdev); /* - * increse buffer object reference. + * increase buffer object reference. */ void hmm_bo_ref(struct hmm_buffer_object *bo); /* - * decrese buffer object reference. if reference reaches 0, + * decrease buffer object reference. if reference reaches 0, * release function of the buffer object will be called. * * this call is also used to release hmm_buffer_object or its diff --git a/drivers/staging/media/atomisp/include/hmm/hmm_common.h b/drivers/staging/media/atomisp/include/hmm/hmm_common.h index d8610b135de03a..b251e96cc19d75 100644 --- a/drivers/staging/media/atomisp/include/hmm/hmm_common.h +++ b/drivers/staging/media/atomisp/include/hmm/hmm_common.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __HMM_BO_COMMON_H__ diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index 4cfe9a0e0d56fa..3c8fa3f5808d0b 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -3,17 +3,6 @@ * Support for Medifield PNW Camera Imaging ISP subsystem. * * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef _ATOM_ISP_H diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h index ecd82220f04a99..426c5ee4ec1882 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h @@ -3,15 +3,6 @@ * Support for Intel MID SoC Camera Imaging ISP subsystem. * * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ATOMISP_GMIN_PLATFORM_H_ #define ATOMISP_GMIN_PLATFORM_H_ diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 064449fd51afc1..049246774cede9 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -3,17 +3,6 @@ * Support for Medifield PNW Camera Imaging ISP subsystem. * * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef ATOMISP_PLATFORM_H_ #define ATOMISP_PLATFORM_H_ diff --git a/drivers/staging/media/atomisp/include/linux/libmsrlisthelper.h b/drivers/staging/media/atomisp/include/linux/libmsrlisthelper.h deleted file mode 100644 index abc8fa809bcef8..00000000000000 --- a/drivers/staging/media/atomisp/include/linux/libmsrlisthelper.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ -#ifndef __LIBMSRLISTHELPER_H__ -#define __LIBMSRLISTHELPER_H__ - -struct i2c_client; -struct firmware; - -int load_msr_list(struct i2c_client *client, char *path, - const struct firmware **fw); -int apply_msr_data(struct i2c_client *client, const struct firmware *fw); -void release_msr_list(struct i2c_client *client, - const struct firmware *fw); - -#endif /* ifndef __LIBMSRLISTHELPER_H__ */ diff --git a/drivers/staging/media/atomisp/include/mmu/isp_mmu.h b/drivers/staging/media/atomisp/include/mmu/isp_mmu.h index 2685609547922d..ee9839b080a6f3 100644 --- a/drivers/staging/media/atomisp/include/mmu/isp_mmu.h +++ b/drivers/staging/media/atomisp/include/mmu/isp_mmu.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ /* * ISP MMU driver for classic two-level page tables diff --git a/drivers/staging/media/atomisp/include/mmu/sh_mmu_mrfld.h b/drivers/staging/media/atomisp/include/mmu/sh_mmu_mrfld.h index 84fe7a368c14c0..bdec30ff8309d8 100644 --- a/drivers/staging/media/atomisp/include/mmu/sh_mmu_mrfld.h +++ b/drivers/staging/media/atomisp/include/mmu/sh_mmu_mrfld.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __SH_MMU_MRFLD_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp-regs.h b/drivers/staging/media/atomisp/pci/atomisp-regs.h index a7b0196686beee..15e61098a67562 100644 --- a/drivers/staging/media/atomisp/pci/atomisp-regs.h +++ b/drivers/staging/media/atomisp/pci/atomisp-regs.h @@ -3,17 +3,6 @@ * Support for Medifield PNW Camera Imaging ISP subsystem. * * Copyright (c) 2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef ATOMISP_REGS_H diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index 102d39a45c9c03..02ccf80e655955 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include #include diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index e69ca14645b9f0..82199dc9284e9f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_CMD_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_common.h b/drivers/staging/media/atomisp/pci/atomisp_common.h index 2d0a77df6c8823..a2462fc306fb21 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_common.h +++ b/drivers/staging/media/atomisp/pci/atomisp_common.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_COMMON_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat.h b/drivers/staging/media/atomisp/pci/atomisp_compat.h index e9e4bfb0f5f979..f0704a7e3bff31 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat.h @@ -3,17 +3,6 @@ * Support for Clovertrail PNW Camera Imaging ISP subsystem. * * Copyright (c) 2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_COMPAT_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index a62a5c0b3c002f..2eb44bccff0e29 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -3,17 +3,6 @@ * Support for Clovertrail PNW Camera Imaging ISP subsystem. * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.h b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.h index e0601534380f4c..75781807544aa6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.h @@ -3,17 +3,6 @@ * Support for Clovertrail PNW Camera Imaging ISP subsystem. * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_COMPAT_CSS20_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h b/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h index 762520ed87a5a4..23d798f3085c22 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h @@ -3,17 +3,6 @@ * Support for Intel Camera Imaging ISP subsystem. * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_COMPAT_IOCTL32_H__ #define __ATOMISP_COMPAT_IOCTL32_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 9288910eeb6c06..28afc0bfc43b1b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -3,17 +3,6 @@ * Support for Medifield PNW Camera Imaging ISP subsystem. * * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h index 8a112acba1e0d6..bb998c82a438f4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h @@ -3,17 +3,6 @@ * Support for Medifield PNW Camera Imaging ISP subsystem. * * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_CSI2_H__ #define __ATOMISP_CSI2_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_dfs_tables.h b/drivers/staging/media/atomisp/pci/atomisp_dfs_tables.h index 8f1cc3fca13a68..03d7c08b67e6de 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_dfs_tables.h +++ b/drivers/staging/media/atomisp/pci/atomisp_dfs_tables.h @@ -3,17 +3,6 @@ * Support for Intel Camera Imaging ISP subsystem. * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_DFS_TABLES_H__ #define __ATOMISP_DFS_TABLES_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c index ba7dd569a55a19..31c82c3c0d33fd 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c +++ b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c @@ -3,17 +3,6 @@ * Support for atomisp driver sysfs interface * * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include diff --git a/drivers/staging/media/atomisp/pci/atomisp_drvfs.h b/drivers/staging/media/atomisp/pci/atomisp_drvfs.h index 8495cc133c0608..46ad59b8df284d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_drvfs.h +++ b/drivers/staging/media/atomisp/pci/atomisp_drvfs.h @@ -3,17 +3,6 @@ * Support for atomisp driver sysfs interface. * * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_DRVFS_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index b180fcbea9b1e6..57da7ddb150334 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include @@ -441,8 +430,6 @@ const struct vb2_ops atomisp_vb2_ops = { .buf_queue = atomisp_buf_queue, .start_streaming = atomisp_start_streaming, .stop_streaming = atomisp_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static void atomisp_dev_init_struct(struct atomisp_device *isp) diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp_fops.h index ad1cb1ac8aa46c..a5c84029b025dc 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.h +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_FOPS_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h index 9c2bc5332fa4e7..775506757471fb 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_INTERNAL_H__ #define __ATOMISP_INTERNAL_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index d7e8a9871522d9..1a960a01854fd0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include @@ -43,7 +32,7 @@ static const char *CARD = "ATOM ISP"; /* max size 31 */ /* * FIXME: ISP should not know beforehand all CIDs supported by sensor. - * Instead, it needs to propagate to sensor unkonwn CIDs. + * Instead, it needs to propagate to sensor unknown CIDs. */ static struct v4l2_queryctrl ci_v4l2_controls[] = { { @@ -112,7 +101,7 @@ static struct v4l2_queryctrl ci_v4l2_controls[] = { { .id = V4L2_CID_ATOMISP_VIDEO_STABLIZATION, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Video Stablization", + .name = "Video Stabilization", .minimum = 0, .maximum = 1, .step = 1, @@ -678,7 +667,7 @@ static int atomisp_g_fmt_cap(struct file *file, void *fh, f->fmt.pix = pipe->pix; - /* If s_fmt was issued, just return whatever is was previouly set */ + /* If s_fmt was issued, just return whatever is was previously set */ if (f->fmt.pix.sizeimage) return 0; @@ -881,8 +870,10 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) mutex_lock(&isp->mutex); ret = atomisp_pipe_check(pipe, false); - if (ret) + if (ret) { + atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); goto out_unlock; + } /* * When running a classic v4l2 app after a media-controller aware @@ -895,6 +886,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) mutex_unlock(&isp->media_dev.graph_mutex); if (ret) { dev_err(isp->dev, "Error starting mc pipeline: %d\n", ret); + atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); goto out_unlock; } @@ -1028,7 +1020,7 @@ void atomisp_stop_streaming(struct vb2_queue *vq) /* * ISP work around, need to reset ISP to allow next stream on to work. * Streams have already been destroyed by atomisp_css_stop(). - * Disable PUNIT/ISP acknowlede/handshake - SRSE=3 and then reset. + * Disable PUNIT/ISP acknowledge/handshake - SRSE=3 and then reset. */ pci_write_config_dword(pdev, PCI_I_CONTROL, isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK); diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.h b/drivers/staging/media/atomisp/pci/atomisp_ioctl.h index 56d3df86c7064a..4feaa0338cb427 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.h +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_IOCTL_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index 202497695e46fb..22c0ae0b1b7b75 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -3,17 +3,6 @@ * Support for Medifield PNW Camera Imaging ISP subsystem. * * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include #include diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index b6c66a5d523c37..bd1a198cda30e5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -3,17 +3,6 @@ * Support for Medifield PNW Camera Imaging ISP subsystem. * * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_SUBDEV_H__ #define __ATOMISP_SUBDEV_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_tables.h b/drivers/staging/media/atomisp/pci/atomisp_tables.h index e718a3f661f95c..33e6079aa73b0e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_tables.h +++ b/drivers/staging/media/atomisp/pci/atomisp_tables.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_TABLES_H__ #define __ATOMISP_TABLES_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp_trace_event.h b/drivers/staging/media/atomisp/pci/atomisp_trace_event.h index 538d45e008b5e4..4c58a8f5c7e84d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_trace_event.h +++ b/drivers/staging/media/atomisp/pci/atomisp_trace_event.h @@ -3,17 +3,6 @@ * Support Camera Imaging tracer core. * * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #undef TRACE_SYSTEM #define TRACE_SYSTEM atomisp diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index c9984f1557b0a1..2841824cd0ca5c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -5,17 +5,6 @@ * Copyright (c) 2010-2017 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include #include @@ -55,7 +44,7 @@ /* G-Min addition: pull this in from intel_mid_pm.h */ #define CSTATE_EXIT_LATENCY_C1 1 -/* cross componnet debug message flag */ +/* cross component debug message flag */ int dbg_level; module_param(dbg_level, int, 0644); MODULE_PARM_DESC(dbg_level, "debug message level (default:0)"); @@ -1493,4 +1482,4 @@ MODULE_AUTHOR("Wen Wang "); MODULE_AUTHOR("Xiaolin Zhang "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver"); -MODULE_IMPORT_NS(INTEL_IPU_BRIDGE); +MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.h b/drivers/staging/media/atomisp/pci/atomisp_v4l2.h index fad9573374b321..f1b74036000903 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.h +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.h @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #ifndef __ATOMISP_V4L2_H__ diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h index e9846951f4ed9b..86300991d30eb9 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_CIRCBUF_H diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h index b0f20563c3a3d4..971e07f2acc535 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_CIRCBUF_COMM_H diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h index 1071813a284cac..5645a7bf493cc4 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_CIRCBUF_DESC_H_ diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/src/circbuf.c b/drivers/staging/media/atomisp/pci/base/circbuf/src/circbuf.c index 198c9f6e619116..cb34d0b5abb5ef 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/src/circbuf.c +++ b/drivers/staging/media/atomisp/pci/base/circbuf/src/circbuf.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_circbuf.h" diff --git a/drivers/staging/media/atomisp/pci/base/refcount/interface/ia_css_refcount.h b/drivers/staging/media/atomisp/pci/base/refcount/interface/ia_css_refcount.h index 78cf0cbfb3bec4..d78859e3a5b02e 100644 --- a/drivers/staging/media/atomisp/pci/base/refcount/interface/ia_css_refcount.h +++ b/drivers/staging/media/atomisp/pci/base/refcount/interface/ia_css_refcount.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_REFCOUNT_H_ diff --git a/drivers/staging/media/atomisp/pci/base/refcount/src/refcount.c b/drivers/staging/media/atomisp/pci/base/refcount/src/refcount.c index a9c881631f4a32..58e4e3173b405e 100644 --- a/drivers/staging/media/atomisp/pci/base/refcount/src/refcount.c +++ b/drivers/staging/media/atomisp/pci/base/refcount/src/refcount.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/bits.h b/drivers/staging/media/atomisp/pci/bits.h index f7a66287d76388..ebd9393d910fbf 100644 --- a/drivers/staging/media/atomisp/pci/bits.h +++ b/drivers/staging/media/atomisp/pci/bits.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _HRT_BITS_H diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h index e42eeaeb3ee471..4e687f318c0e19 100644 --- a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h +++ b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_binarydesc.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PIPE_BINARYDESC_H__ diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h index 7a0c988d89ee01..61d1bf66fbd64e 100644 --- a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h +++ b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_stagedesc.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PIPE_STAGEDESC_H__ diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_util.h b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_util.h index c23d1bd915a357..a0bdcc37553f07 100644 --- a/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_util.h +++ b/drivers/staging/media/atomisp/pci/camera/pipe/interface/ia_css_pipe_util.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PIPE_UTIL_H__ diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c index 06664ce75b6085..8d7925a7ee0c94 100644 --- a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c +++ b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_binarydesc.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c index 6c93fa1c683b14..a9f736398f5047 100644 --- a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c +++ b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_stagedesc.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_pipe_stagedesc.h" diff --git a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_util.c b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_util.c index 03d9d168fcc9fb..c7c42b472cc7cf 100644 --- a/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_util.c +++ b/drivers/staging/media/atomisp/pci/camera/pipe/src/pipe_util.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_pipe_util.h" diff --git a/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h b/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h index d4de1e9293a1c0..24cd99a659cabf 100644 --- a/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h +++ b/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_UTIL_H__ diff --git a/drivers/staging/media/atomisp/pci/camera/util/src/util.c b/drivers/staging/media/atomisp/pci/camera/util/src/util.c index 9d7025a00bebf1..3a7abdc8f6b3ff 100644 --- a/drivers/staging/media/atomisp/pci/camera/util/src/util.c +++ b/drivers/staging/media/atomisp/pci/camera/util/src/util.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_util.h" diff --git a/drivers/staging/media/atomisp/pci/cell_params.h b/drivers/staging/media/atomisp/pci/cell_params.h index 3c21a18990ba0e..a2a07b78f2a07b 100644 --- a/drivers/staging/media/atomisp/pci/cell_params.h +++ b/drivers/staging/media/atomisp/pci/cell_params.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _cell_params_h diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/csi_rx_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/csi_rx_global.h index 3aabd0248e4fc8..ab9d091acb4e75 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/csi_rx_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/csi_rx_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __CSI_RX_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx.c b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx.c index 9a8d8f546da7ed..f82522e2da9407 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx.c +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_local.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_local.h index 6489ee644a4a44..81e83554d31794 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_local.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __CSI_RX_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h index ece45d80eb2ab2..989f55bec5190b 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __CSI_RX_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/ibuf_ctrl.c b/drivers/staging/media/atomisp/pci/css_2401_system/host/ibuf_ctrl.c index 8d19c9875a719b..a99928a13e75ce 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/ibuf_ctrl.c +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/ibuf_ctrl.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/ibuf_ctrl_local.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/ibuf_ctrl_local.h index f71841195ac152..814687251ec50c 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/ibuf_ctrl_local.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/ibuf_ctrl_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IBUF_CTRL_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma.c b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma.c index 2a5159945a44fc..dfa7edefdff864 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma.c +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_local.h" diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h index d65fe9ec9049e3..da51b44d48a933 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_DMA_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq.c b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq.c index b6135c4b6eeac8..3847884e2dc07d 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq.c +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_local.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_local.h index 0f585a7e0fa405..0c5f1094f90175 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_local.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_IRQ_LOCAL_H__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h index d94c8e6add72b9..4bd8209aaa0193 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_IRQ_PRIVATE_H__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio.c b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio.c index b7d893aea88d2e..21b19b4abeaa9a 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio.c +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "isys_stream2mmio.h" diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_local.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_local.h index 4fbbcc2338d395..de985674bddd16 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_local.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_STREAM2MMIO_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h index 4a5646a229b8ff..3210dd6bf9ca7b 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_STREAM2MMIO_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_local.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_local.h index efaa4da8d36d79..4e091406efa990 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_local.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __PIXELGEN_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h index 8f79424bedb2dd..b8b98106bd318f 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __PIXELGEN_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/PixelGen_SysBlock_defs.h b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/PixelGen_SysBlock_defs.h index ae471dd5173742..323925ba297179 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/PixelGen_SysBlock_defs.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/PixelGen_SysBlock_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _PixelGen_SysBlock_defs_h diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/ibuf_cntrl_defs.h b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/ibuf_cntrl_defs.h index 374466e6b7bf54..a41e2b957bd179 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/ibuf_cntrl_defs.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/ibuf_cntrl_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _ibuf_cntrl_defs_h_ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/mipi_backend_common_defs.h b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/mipi_backend_common_defs.h index ac8be2d4922717..bc7639adcd8dad 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/mipi_backend_common_defs.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/mipi_backend_common_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _css_receiver_2400_common_defs_h_ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/mipi_backend_defs.h b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/mipi_backend_defs.h index 6fae1c26244652..91747af997c57c 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/mipi_backend_defs.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/mipi_backend_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _mipi_backend_defs_h diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/rx_csi_defs.h b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/rx_csi_defs.h index d0e5b54d1afcca..12df1ab491a0d8 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/rx_csi_defs.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/rx_csi_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _csi_rx_defs_h diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/stream2mmio_defs.h b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/stream2mmio_defs.h index e17783f96b23e1..495db4770e84c9 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/hrt/stream2mmio_defs.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/hrt/stream2mmio_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _STREAM2MMMIO_DEFS_H diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/ibuf_ctrl_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/ibuf_ctrl_global.h index 56c5ed89b3ccf1..cab7236dc292dd 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/ibuf_ctrl_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/ibuf_ctrl_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IBUF_CTRL_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/isys_dma_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/isys_dma_global.h index f423f34134d323..de89bc4829f03f 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/isys_dma_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/isys_dma_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_DMA_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/isys_irq_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/isys_irq_global.h index 16336ed7303636..bd584ccc1a9ab6 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/isys_irq_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/isys_irq_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_IRQ_GLOBAL_H__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/isys_stream2mmio_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/isys_stream2mmio_global.h index 0611047eabbcfa..c6d8d9e729810e 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/isys_stream2mmio_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/isys_stream2mmio_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_STREAM2MMIO_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h index f131f03cb8fafe..59e0b44bfdc3d4 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __PIXELGEN_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/css_receiver_2400_common_defs.h b/drivers/staging/media/atomisp/pci/css_receiver_2400_common_defs.h index d2c39f9600bd23..fc733a72d1e381 100644 --- a/drivers/staging/media/atomisp/pci/css_receiver_2400_common_defs.h +++ b/drivers/staging/media/atomisp/pci/css_receiver_2400_common_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _css_receiver_2400_common_defs_h_ diff --git a/drivers/staging/media/atomisp/pci/css_receiver_2400_defs.h b/drivers/staging/media/atomisp/pci/css_receiver_2400_defs.h index 180ff7cd9ff580..6dd6e7290eb821 100644 --- a/drivers/staging/media/atomisp/pci/css_receiver_2400_defs.h +++ b/drivers/staging/media/atomisp/pci/css_receiver_2400_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _css_receiver_2400_defs_h_ diff --git a/drivers/staging/media/atomisp/pci/css_trace.h b/drivers/staging/media/atomisp/pci/css_trace.h index d2ce50fcfb7a90..5b878a6735a13d 100644 --- a/drivers/staging/media/atomisp/pci/css_trace.h +++ b/drivers/staging/media/atomisp/pci/css_trace.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __CSS_TRACE_H_ diff --git a/drivers/staging/media/atomisp/pci/dma_v2_defs.h b/drivers/staging/media/atomisp/pci/dma_v2_defs.h index 27299e3a185d30..79cbdc7242d572 100644 --- a/drivers/staging/media/atomisp/pci/dma_v2_defs.h +++ b/drivers/staging/media/atomisp/pci/dma_v2_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _dma_v2_defs_h diff --git a/drivers/staging/media/atomisp/pci/gdc_v2_defs.h b/drivers/staging/media/atomisp/pci/gdc_v2_defs.h index 804df8179e36fb..ca2fee141f7660 100644 --- a/drivers/staging/media/atomisp/pci/gdc_v2_defs.h +++ b/drivers/staging/media/atomisp/pci/gdc_v2_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef HRT_GDC_v2_defs_h_ diff --git a/drivers/staging/media/atomisp/pci/gp_timer_defs.h b/drivers/staging/media/atomisp/pci/gp_timer_defs.h index 9bc04e5b42921a..4b1b8ae1c194d1 100644 --- a/drivers/staging/media/atomisp/pci/gp_timer_defs.h +++ b/drivers/staging/media/atomisp/pci/gp_timer_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _gp_timer_defs_h diff --git a/drivers/staging/media/atomisp/pci/gpio_block_defs.h b/drivers/staging/media/atomisp/pci/gpio_block_defs.h index 55c39067a9bf1b..a4ce5a6dbd93de 100644 --- a/drivers/staging/media/atomisp/pci/gpio_block_defs.h +++ b/drivers/staging/media/atomisp/pci/gpio_block_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _gpio_block_defs_h_ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/debug_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/debug_global.h index f2e17945fd4539..15fb0ad4a5f0ed 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/debug_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/debug_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DEBUG_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/dma_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/dma_global.h index 135034c7245a3e..05b10e3d19dc95 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/dma_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/dma_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DMA_GLOBAL_H_INCLUDED__ @@ -34,7 +25,6 @@ * param id[4] channel id[5] cmd id[6] * | b14 .. b11 | b10 ... b6 | b5 ... b0 | * - * * fast transfer: * height[5] width[8] width[8] channel id[5] cmd id[6] * | b31 .. b26 | b25 .. b18 | b17 .. b11 | b10 ... b6 | b5 ... b0 | diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/event_fifo_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/event_fifo_global.h index a50635b717e3d8..f4ec956b6035b8 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/event_fifo_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/event_fifo_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __EVENT_FIFO_GLOBAL_H diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/fifo_monitor_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/fifo_monitor_global.h index d941c82d530bf3..6ac588579b9dfe 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/fifo_monitor_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/fifo_monitor_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __FIFO_MONITOR_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gdc_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gdc_global.h index 599d993b832ef2..06f88305e18b9e 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gdc_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gdc_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GDC_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gp_device_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gp_device_global.h index c8f416515e2cae..958837a40feb66 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gp_device_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gp_device_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_DEVICE_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gp_timer_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gp_timer_global.h index 163003f2c75907..1bc698530e4c9c 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gp_timer_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gp_timer_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_TIMER_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h index 06b6cb3842f410..a756f175362d24 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GPIO_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/hmem_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/hmem_global.h index 746b0709768122..0cbd06b50bbad5 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/hmem_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/hmem_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __HMEM_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug.c index a502ba9f8c7fb9..8513e78856b2b9 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2016, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "debug.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug_local.h index 536a4dcf0f6221..f80becfb7cab1e 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DEBUG_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug_private.h index 3fea43a2125e31..568f9bf92ad82f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/debug_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DEBUG_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma.c index 0b6647b2eb7641..f7a8cb38d068dc 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2016, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h index 1a71dbebbbe2cf..7e51dea39b1af1 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DMA_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_private.h index 1f62bc2f176f98..02553f2d9375e7 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/dma_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DMA_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo.c index 62d4809e33dd93..8f61d9054e557d 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "event_fifo.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo_local.h index 25d3823026e857..ce1916637a9206 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _EVENT_FIFO_LOCAL_H diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo_private.h index f59d45cc78b7ac..439c69444942e1 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/event_fifo_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __EVENT_FIFO_PRIVATE_H diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor.c index 01698064bbe17f..f0de788154560d 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "fifo_monitor.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor_local.h index dfdca944a40b42..e02ccaee34abbe 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __FIFO_MONITOR_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor_private.h index 10d9c076c140ed..53a3fb796aabfa 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/fifo_monitor_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __FIFO_MONITOR_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc.c index 25e082d6a94a10..8bb78b4d7c677f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* The name "gdc.h is already taken" */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc_local.h index 4b2b3282c1b2f3..bde637b519b391 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GDC_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc_private.h index 73051112f35447..03ffb16c956dc7 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gdc_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GDC_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device.c index a80e547d47b3d1..b934d20c88ea27 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "assert_support.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device_local.h index 320ed35269eaa6..2fcb95cf1b958f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_DEVICE_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device_private.h index f11a19f21d1027..71f20992ee9871 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_device_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_DEVICE_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer.c index 2a58dba3c87b28..d04c179a5ecdf6 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include /*uint32_t */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer_local.h index efede25587fdeb..779eeee650d474 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_TIMER_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer_private.h index 3e1b36105bb614..45ea7daaaa1b4e 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gp_timer_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_TIMER_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h index 85fcde0b86153f..bcf6538ac0dc30 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GPIO_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem.c index be102d5cec8794..8b999acd625309 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmem.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem_local.h index a3ee274bdf1945..e9f8024a01b4cf 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __HMEM_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem_private.h index 80d81983bd06ea..0d58b321552f25 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/hmem_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __HMEM_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter.c index e01f30f137a00f..40b3f1e48c5669 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter_local.h index dfb593c109af78..84cd031f8b8ddd 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_FORMATTER_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter_private.h index e2bc952e66943a..6b6ba49656e5e1 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_formatter_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_FORMATTER_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index 8f2f4e8eddd9a4..9f1199c4761c43 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" @@ -406,7 +397,7 @@ input_system_err_t input_system_configuration_reset(void) config.unallocated_ib_mem_words = IB_CAPACITY_IN_WORDS; //config.acq_allocated_ib_mem_words = 0; - // Set the start of the session cofiguration. + /* Set the start of the session configuration. */ config.session_flags = INPUT_SYSTEM_CFG_FLAG_REQUIRED; return INPUT_SYSTEM_ERR_NO_ERROR; diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq.c index 4697d8d7b915be..b66560bca62590 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "assert_support.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_local.h index 8fd1bce8521450..c74cd18c7aecb7 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IRQ_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_private.h index e98663ef0fcde1..ae0a8466a70a02 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/irq_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IRQ_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp.c index b78cc324da6a71..39cccbfa3fcaa1 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_local.h index fb98696cc44d10..b5c1ba55c99126 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISP_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_private.h index 2f9aeb3bd9d461..177770a9bc1d64 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/isp_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISP_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/mmu.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/mmu.c index eb02835aa98a14..064e88a5e06442 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/mmu.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/mmu.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* The name "mmu.h is already taken" */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/mmu_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/mmu_local.h index 913150504f0fd4..f6265195387394 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/mmu_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/mmu_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __MMU_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp.c index 3dc4d1289ea1b0..0fb8a675439e2f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "sp.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_local.h index e22d25a902f406..48546491eb8384 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SP_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_private.h index 05e6b438d2c87e..c69778411f2f08 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/sp_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SP_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl.c index bc9e7f10f1ab02..948b0b0a0272e1 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "timed_ctrl.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl_local.h index f58ee6afcff9ff..bf97f272adbade 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TIMED_CTRL_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl_private.h index c19eeafed3a304..7b90b4cf040248 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/timed_ctrl_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TIMED_CTRL_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vamem_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vamem_local.h index c68ed984ca4898..2882849660ce95 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vamem_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vamem_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VAMEM_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c index d9cdfbc50197c9..722b684fbc37b9 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2016, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "isp.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem_local.h index 6f0a8fe868bd79..0163d31cd169dd 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VMEM_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem_private.h index 39cf1316b4045e..ca685cf156766c 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VMEM_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/input_formatter_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/input_formatter_global.h index 605cf02e520c2f..b8ed8964c7b8aa 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/input_formatter_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/input_formatter_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_FORMATTER_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/irq_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/irq_global.h index 4a1dea6dfd4085..2c47e7820bd755 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/irq_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/irq_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IRQ_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/isp_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/isp_global.h index 5c6891c9b451b8..2df468bd76d650 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/isp_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/isp_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISP_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/mmu_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/mmu_global.h index 8738fed6afdf70..be8977f6233da8 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/mmu_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/mmu_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __MMU_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/sp_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/sp_global.h index b8338f9b5c0cbf..db72d7b29f7362 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/sp_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/sp_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SP_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h index 3f2915a7803190..2dc0fb88399fa7 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TIMED_CTRL_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/vamem_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/vamem_global.h index 0d290e815767d9..0042925f1d2b97 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/vamem_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/vamem_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VAMEM_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/vmem_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/vmem_global.h index 537b074211da8b..6d8bde959b5287 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/vmem_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/vmem_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VMEM_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_defs.h b/drivers/staging/media/atomisp/pci/hive_isp_css_defs.h index e9cf2743868cb4..0e2c8ec534a17a 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_defs.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _hive_isp_css_defs_h__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h index c5ab13511db83a..4010976eb4f3c2 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ASSERT_SUPPORT_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/bitop_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/bitop_support.h index 29f14e900580cd..fda1adf6c601ae 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/bitop_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/bitop_support.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __BITOP_SUPPORT_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/csi_rx.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/csi_rx.h index 4602885d50e8cb..8fd1b846d82786 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/csi_rx.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/csi_rx.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __CSI_RX_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/debug.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/debug.h index 0f8195ba8d1ad9..fc6de151ac6422 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/debug.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/debug.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DEBUG_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h index 492f9e26cfff79..ca33a1e03d8d6e 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef __DEVICE_ACCESS_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/dma.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/dma.h index 2f5ebfcd7e8be8..1e0731391ad838 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/dma.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/dma.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DMA_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/event_fifo.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/event_fifo.h index 0a085abd3adea3..cd1a0fb57267c7 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/event_fifo.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/event_fifo.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __EVENT_FIFO_H diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/fifo_monitor.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/fifo_monitor.h index 19a1bdd9171ab7..e85b50d780033d 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/fifo_monitor.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/fifo_monitor.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __FIFO_MONITOR_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/gdc_device.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/gdc_device.h index 4ed57fb4530e6f..d8633859c393c0 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/gdc_device.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/gdc_device.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GDC_DEVICE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/gp_device.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/gp_device.h index d122bdeae7e743..33ab0642a93173 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/gp_device.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/gp_device.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_DEVICE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/gp_timer.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/gp_timer.h index 0b7e92b963d0b4..94f81af70007fa 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/gp_timer.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/gp_timer.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_TIMER_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/hmem.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/hmem.h index 898facd7b17aac..c916618a0fb9e8 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/hmem.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/hmem.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __HMEM_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h index 7e37f08090342a..2002960f078e7c 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __CSI_RX_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h index 5660bd4221be70..947381e5b8a8be 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DEBUG_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/dma_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/dma_public.h index 6fed47f045945a..fe3b1b8ecc5038 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/dma_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/dma_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __DMA_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/event_fifo_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/event_fifo_public.h index 22f1875f038ea0..9c2365e59b6341 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/event_fifo_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/event_fifo_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __EVENT_FIFO_PUBLIC_H diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/fifo_monitor_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/fifo_monitor_public.h index 7c1c3d2f24c647..37cb9eb1391994 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/fifo_monitor_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/fifo_monitor_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __FIFO_MONITOR_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gdc_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gdc_public.h index 385b7925445592..77654b16359859 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gdc_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gdc_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GDC_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gp_device_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gp_device_public.h index f017742d9ac45d..b93cd00a0b1ded 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gp_device_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gp_device_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_DEVICE_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gp_timer_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gp_timer_public.h index 13baf723637531..cc016eb9e84d6a 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gp_timer_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gp_timer_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __GP_TIMER_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/hmem_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/hmem_public.h index 8d271fb8420902..7cfc2228c0b87f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/hmem_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/hmem_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __HMEM_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/input_formatter_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/input_formatter_public.h index 81dc58640d83ea..e67d252aa43f75 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/input_formatter_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/input_formatter_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_FORMATTER_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/irq_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/irq_public.h index 43787ab64078a4..901e10f8743cbb 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/irq_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/irq_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IRQ_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isp_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isp_public.h index 34dd7f912df607..78abd77c5bdbf4 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isp_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isp_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISP_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_dma_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_dma_public.h index f18a057adb0f77..fceab6dcbddb6f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_dma_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_dma_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_DMA_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_irq_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_irq_public.h index 2b13688256cffb..a728b9b9fd5256 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_irq_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_irq_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_IRQ_PUBLIC_H__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h index 73bcc424e4720e..7ed55d427cf637 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_STREAM2MMIO_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/mmu_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/mmu_public.h index b8c7bbb71b01c5..1a435a34831828 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/mmu_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/mmu_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __MMU_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h index da10e6b98c63f6..dc31ce3cd741e5 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __PIXELGEN_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/sp_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/sp_public.h index e9166535ce099c..15faa52d4ab647 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/sp_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/sp_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SP_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h index b18b4a4e13ac74..ad83ff97bbd6a5 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TAG_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/timed_ctrl_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/timed_ctrl_public.h index 563a2833d1d97f..51e0bc0d0f9718 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/timed_ctrl_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/timed_ctrl_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TIMED_CTRL_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/vamem_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/vamem_public.h index 823e3857e83c90..7aede5b00deedd 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/vamem_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/vamem_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VAMEM_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/vmem_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/vmem_public.h index c510d6a08017cf..0257079437be98 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/vmem_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/vmem_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VMEM_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/input_formatter.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/input_formatter.h index daeb919b538493..21d9ea26f929f5 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/input_formatter.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/input_formatter.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_FORMATTER_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/input_system.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/input_system.h index 0d951fbf42e9b3..97a698ce83d980 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/input_system.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/input_system.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_SYSTEM_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/irq.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/irq.h index 3a83a85111a220..0f6c8f081a0739 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/irq.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/irq.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IRQ_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/isp.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/isp.h index cb64e62c556987..0ffea40ff0015d 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/isp.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/isp.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISP_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h index 952b633fdca709..a4a8e92df592c8 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_irq.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ISYS_IRQ_H__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_stream2mmio.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_stream2mmio.h index b0f09ffb4f1818..e88710c65cb9d2 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_stream2mmio.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/isys_stream2mmio.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_STREAM2MMIO_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h index 907f9ebcc60db4..6d45d0d8d060bb 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __MATH_SUPPORT_H diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/misc_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/misc_support.h index 393452d7a3d6b7..f8c5a88ae1ad33 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/misc_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/misc_support.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __MISC_SUPPORT_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/mmu_device.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/mmu_device.h index b6f6eda4c55ee4..761909efac4428 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/mmu_device.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/mmu_device.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __MMU_DEVICE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/pixelgen.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/pixelgen.h index e34cd3c58dd733..3215098ee60ab1 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/pixelgen.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/pixelgen.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __PIXELGEN_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h index 0cdef4a5e8b1be..473d8d4fb9baad 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __PLATFORM_SUPPORT_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/print_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/print_support.h index a3c7f3de6d1734..e6ce7b51d34155 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/print_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/print_support.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __PRINT_SUPPORT_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/queue.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/queue.h index e6978750a362f8..d778bcb5664691 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/queue.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/queue.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __QUEUE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/resource.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/resource.h index 9be45b67938697..c7a92b530f8989 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/resource.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/resource.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __RESOURCE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/sp.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/sp.h index a7d00c7bb8bc0c..92724ae59e6b93 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/sp.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/sp.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SP_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/tag.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/tag.h index 98d7e922aed955..b335222c733475 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/tag.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/tag.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TAG_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/timed_ctrl.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/timed_ctrl.h index 65b2871fb4eaf7..b8f48b3c9f1e97 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/timed_ctrl.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/timed_ctrl.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TIMED_CTRL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h index 9a640f18eed9f6..097be6bd3cb529 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TYPE_SUPPORT_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/vamem.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/vamem.h index 3ea6758aa79898..0c3328074571c1 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/vamem.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/vamem.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VAMEM_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/vmem.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/vmem.h index da479b37019253..8e8d187d12217d 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/vmem.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/vmem.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VMEM_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/queue_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/queue_local.h index 31121a22d13dc5..fe10cad60f5cd7 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/queue_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/queue_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __QUEUE_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/queue_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/queue_private.h index be6162dfbc662c..e0a8d8493d4500 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/queue_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/queue_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __QUEUE_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag.c b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag.c index 8931539a4c0163..c68b096444de0f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "tag.h" diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag_local.h index 921e50a4554a0a..138b55be5d9dba 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag_local.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TAG_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag_private.h index b14f09adef0727..bc98fcab9a5557 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag_private.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/host/tag_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TAG_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/queue_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/queue_global.h index 6ae45378251533..f133348f4c0440 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/queue_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/queue_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __QUEUE_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/sw_event_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/sw_event_global.h index b256ea19c0eb75..c9ee03d6049833 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/sw_event_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/sw_event_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SW_EVENT_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/tag_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/tag_global.h index af5a47ace32a52..7aef49429f98da 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_shared/tag_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_shared/tag_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __TAG_GLOBAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_streaming_to_mipi_types_hrt.h b/drivers/staging/media/atomisp/pci/hive_isp_css_streaming_to_mipi_types_hrt.h index 301dd923950c00..7579b1ec25961f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_streaming_to_mipi_types_hrt.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_streaming_to_mipi_types_hrt.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _hive_isp_css_streaming_to_mipi_types_hrt_h_ diff --git a/drivers/staging/media/atomisp/pci/hive_types.h b/drivers/staging/media/atomisp/pci/hive_types.h index 34f462c0c9f9e0..c5c5ce3f2228c1 100644 --- a/drivers/staging/media/atomisp/pci/hive_types.h +++ b/drivers/staging/media/atomisp/pci/hive_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _HRT_HIVE_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm.c b/drivers/staging/media/atomisp/pci/hmm/hmm.c index e8c5d728fd55be..84102c3aaf9759 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm.c @@ -5,17 +5,6 @@ * Copyright (c) 2010-2017 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ /* * This file contains entry functions for memory management of ISP driver diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c index b90efac771e275..07ed33464d7116 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ /* * This file contains functions for buffer object structure management diff --git a/drivers/staging/media/atomisp/pci/ia_css.h b/drivers/staging/media/atomisp/pci/ia_css.h index 421056287853ed..0186f7e5ce063a 100644 --- a/drivers/staging/media/atomisp/pci/ia_css.h +++ b/drivers/staging/media/atomisp/pci/ia_css.h @@ -3,15 +3,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_H_ diff --git a/drivers/staging/media/atomisp/pci/ia_css_3a.h b/drivers/staging/media/atomisp/pci/ia_css_3a.h index fc2075c7bd0118..1a10f91a77d447 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_3a.h +++ b/drivers/staging/media/atomisp/pci/ia_css_3a.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_3A_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_acc_types.h b/drivers/staging/media/atomisp/pci/ia_css_acc_types.h index f6838a8fc9d5d3..e13ca0d8484777 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_acc_types.h +++ b/drivers/staging/media/atomisp/pci/ia_css_acc_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_ACC_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_buffer.h b/drivers/staging/media/atomisp/pci/ia_css_buffer.h index b1e8357b94b502..7c00dd1d33fd07 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_buffer.h +++ b/drivers/staging/media/atomisp/pci/ia_css_buffer.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BUFFER_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_control.h b/drivers/staging/media/atomisp/pci/ia_css_control.h index 6a473459b346a9..d374ceaf7574fe 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_control.h +++ b/drivers/staging/media/atomisp/pci/ia_css_control.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CONTROL_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_device_access.c b/drivers/staging/media/atomisp/pci/ia_css_device_access.c index 9cd2d3caa5c97e..8ee7656f614b89 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_device_access.c +++ b/drivers/staging/media/atomisp/pci/ia_css_device_access.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_device_access.h" diff --git a/drivers/staging/media/atomisp/pci/ia_css_device_access.h b/drivers/staging/media/atomisp/pci/ia_css_device_access.h index 07d611fdd19f35..f2ea16c093b68b 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_device_access.h +++ b/drivers/staging/media/atomisp/pci/ia_css_device_access.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_DEVICE_ACCESS_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_dvs.h b/drivers/staging/media/atomisp/pci/ia_css_dvs.h index 41a81561bbef06..6930f1ec3aee30 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_dvs.h +++ b/drivers/staging/media/atomisp/pci/ia_css_dvs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DVS_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_env.h b/drivers/staging/media/atomisp/pci/ia_css_env.h index 42bb1ec1c22d9c..42bf739c51f528 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_env.h +++ b/drivers/staging/media/atomisp/pci/ia_css_env.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ENV_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_err.h b/drivers/staging/media/atomisp/pci/ia_css_err.h index 98401a4a171d7b..5d3ffed9e7fb23 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_err.h +++ b/drivers/staging/media/atomisp/pci/ia_css_err.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ERR_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_event_public.h b/drivers/staging/media/atomisp/pci/ia_css_event_public.h index b052648d4fc2ac..f7215dd9673923 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_event_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_event_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_EVENT_PUBLIC_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_firmware.h b/drivers/staging/media/atomisp/pci/ia_css_firmware.h index d3a66128b4de65..fcfa400cfdd1eb 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_firmware.h +++ b/drivers/staging/media/atomisp/pci/ia_css_firmware.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FIRMWARE_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_frac.h b/drivers/staging/media/atomisp/pci/ia_css_frac.h index 661af9225b195a..f3f92da6a3f06f 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_frac.h +++ b/drivers/staging/media/atomisp/pci/ia_css_frac.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_FRAC_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_frame_format.h b/drivers/staging/media/atomisp/pci/ia_css_frame_format.h index 093e23a9b07949..0cb9c0fbe88cde 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_frame_format.h +++ b/drivers/staging/media/atomisp/pci/ia_css_frame_format.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FRAME_FORMAT_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h index a26d9598e40057..7acfedb541d863 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FRAME_PUBLIC_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_host_data.h b/drivers/staging/media/atomisp/pci/ia_css_host_data.h index f54cc504f5d4e4..0e45650cc1ab27 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_host_data.h +++ b/drivers/staging/media/atomisp/pci/ia_css_host_data.h @@ -3,15 +3,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SH_CSS_HOST_DATA_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_input_port.h b/drivers/staging/media/atomisp/pci/ia_css_input_port.h index 9772b69282391b..f138dfa8f6b245 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_input_port.h +++ b/drivers/staging/media/atomisp/pci/ia_css_input_port.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* For MIPI_PORT0_ID to MIPI_PORT2_ID */ diff --git a/drivers/staging/media/atomisp/pci/ia_css_irq.h b/drivers/staging/media/atomisp/pci/ia_css_irq.h index 00e2fd1f9647ad..2a4f11f9d78506 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_irq.h +++ b/drivers/staging/media/atomisp/pci/ia_css_irq.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_IRQ_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_isp_configs.c b/drivers/staging/media/atomisp/pci/ia_css_isp_configs.c index d28a76a68e434c..38c9c62366d65e 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_isp_configs.c +++ b/drivers/staging/media/atomisp/pci/ia_css_isp_configs.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* Generated code: do not edit or commmit. */ diff --git a/drivers/staging/media/atomisp/pci/ia_css_isp_configs.h b/drivers/staging/media/atomisp/pci/ia_css_isp_configs.h index fffcfc871bd2c2..226902d2100b4f 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_isp_configs.h +++ b/drivers/staging/media/atomisp/pci/ia_css_isp_configs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifdef IA_CSS_INCLUDE_CONFIGURATIONS diff --git a/drivers/staging/media/atomisp/pci/ia_css_isp_params.c b/drivers/staging/media/atomisp/pci/ia_css_isp_params.c index 503ac65da69b91..1cd3322b0da051 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_isp_params.c +++ b/drivers/staging/media/atomisp/pci/ia_css_isp_params.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #define IA_CSS_INCLUDE_PARAMETERS diff --git a/drivers/staging/media/atomisp/pci/ia_css_isp_params.h b/drivers/staging/media/atomisp/pci/ia_css_isp_params.h index c2de689877d152..a542f8979905ee 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_isp_params.h +++ b/drivers/staging/media/atomisp/pci/ia_css_isp_params.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* Generated code: do not edit or commmit. */ diff --git a/drivers/staging/media/atomisp/pci/ia_css_isp_states.c b/drivers/staging/media/atomisp/pci/ia_css_isp_states.c index a6bc2e9eddea91..af17650404643c 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_isp_states.c +++ b/drivers/staging/media/atomisp/pci/ia_css_isp_states.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* Generated code: do not edit or commmit. */ diff --git a/drivers/staging/media/atomisp/pci/ia_css_isp_states.h b/drivers/staging/media/atomisp/pci/ia_css_isp_states.h index 9f6c342a170599..d637ea1d13f6be 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_isp_states.h +++ b/drivers/staging/media/atomisp/pci/ia_css_isp_states.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #define IA_CSS_INCLUDE_STATES diff --git a/drivers/staging/media/atomisp/pci/ia_css_metadata.h b/drivers/staging/media/atomisp/pci/ia_css_metadata.h index a3e759a3eee7d8..34883617577001 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_metadata.h +++ b/drivers/staging/media/atomisp/pci/ia_css_metadata.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_METADATA_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_mipi.h b/drivers/staging/media/atomisp/pci/ia_css_mipi.h index cd6e0111d9f4e5..9fb178c8f3a5a6 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_mipi.h +++ b/drivers/staging/media/atomisp/pci/ia_css_mipi.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MIPI_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_mmu.h b/drivers/staging/media/atomisp/pci/ia_css_mmu.h index 8f04d196c6467a..8dc02c8f60a090 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_mmu.h +++ b/drivers/staging/media/atomisp/pci/ia_css_mmu.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MMU_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_mmu_private.h b/drivers/staging/media/atomisp/pci/ia_css_mmu_private.h index dc6542aa64f2de..4b5e09e051b5ea 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_mmu_private.h +++ b/drivers/staging/media/atomisp/pci/ia_css_mmu_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MMU_PRIVATE_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_morph.h b/drivers/staging/media/atomisp/pci/ia_css_morph.h index 9c4b41b9425631..68997b26c70a8b 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_morph.h +++ b/drivers/staging/media/atomisp/pci/ia_css_morph.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MORPH_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_pipe.h b/drivers/staging/media/atomisp/pci/ia_css_pipe.h index 22522968b9e6a9..c97d2ae356fd2d 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_pipe.h +++ b/drivers/staging/media/atomisp/pci/ia_css_pipe.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PIPE_H__ diff --git a/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h b/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h index 8ac1586dce4e3a..2bb06b0ff5dba5 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PIPE_PUBLIC_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_prbs.h b/drivers/staging/media/atomisp/pci/ia_css_prbs.h index 53bbf1dce3bf31..abdbcb8fda5332 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_prbs.h +++ b/drivers/staging/media/atomisp/pci/ia_css_prbs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PRBS_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_properties.h b/drivers/staging/media/atomisp/pci/ia_css_properties.h index 2cd014f7ae291c..3f087e2df99a9b 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_properties.h +++ b/drivers/staging/media/atomisp/pci/ia_css_properties.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PROPERTIES_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_shading.h b/drivers/staging/media/atomisp/pci/ia_css_shading.h index de7ae5cabf7d90..99ad21c4bd680e 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_shading.h +++ b/drivers/staging/media/atomisp/pci/ia_css_shading.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SHADING_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_stream.h b/drivers/staging/media/atomisp/pci/ia_css_stream.h index cf847586dc610a..c8de632a8e1253 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_stream.h +++ b/drivers/staging/media/atomisp/pci/ia_css_stream.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_STREAM_H_ diff --git a/drivers/staging/media/atomisp/pci/ia_css_stream_format.h b/drivers/staging/media/atomisp/pci/ia_css_stream_format.h index aac22d8581a087..6188e281189bb7 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_stream_format.h +++ b/drivers/staging/media/atomisp/pci/ia_css_stream_format.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_STREAM_FORMAT_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_stream_public.h b/drivers/staging/media/atomisp/pci/ia_css_stream_public.h index aad860e54d3a71..a505f3797962fd 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_stream_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_stream_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_STREAM_PUBLIC_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_timer.h b/drivers/staging/media/atomisp/pci/ia_css_timer.h index c78fbda907a17e..da752834adf458 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_timer.h +++ b/drivers/staging/media/atomisp/pci/ia_css_timer.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef __IA_CSS_TIMER_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_types.h b/drivers/staging/media/atomisp/pci/ia_css_types.h index f5df564c86e85c..676d7e20b282d2 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_types.h +++ b/drivers/staging/media/atomisp/pci/ia_css_types.h @@ -3,15 +3,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_version.h b/drivers/staging/media/atomisp/pci/ia_css_version.h index cf1d010bacebf1..13b192dec8f6d8 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_version.h +++ b/drivers/staging/media/atomisp/pci/ia_css_version.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_VERSION_H diff --git a/drivers/staging/media/atomisp/pci/ia_css_version_data.h b/drivers/staging/media/atomisp/pci/ia_css_version_data.h index 428d78e1616f71..33fabac99bb797 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_version_data.h +++ b/drivers/staging/media/atomisp/pci/ia_css_version_data.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ // diff --git a/drivers/staging/media/atomisp/pci/if_defs.h b/drivers/staging/media/atomisp/pci/if_defs.h index e21efa74936833..7a6b237485500a 100644 --- a/drivers/staging/media/atomisp/pci/if_defs.h +++ b/drivers/staging/media/atomisp/pci/if_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IF_DEFS_H diff --git a/drivers/staging/media/atomisp/pci/input_formatter_subsystem_defs.h b/drivers/staging/media/atomisp/pci/input_formatter_subsystem_defs.h index 594fc36a01c79b..f29a3cab76ee6c 100644 --- a/drivers/staging/media/atomisp/pci/input_formatter_subsystem_defs.h +++ b/drivers/staging/media/atomisp/pci/input_formatter_subsystem_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _if_subsystem_defs_h__ diff --git a/drivers/staging/media/atomisp/pci/input_selector_defs.h b/drivers/staging/media/atomisp/pci/input_selector_defs.h index 61882e4cb81358..8d67aabb898e3f 100644 --- a/drivers/staging/media/atomisp/pci/input_selector_defs.h +++ b/drivers/staging/media/atomisp/pci/input_selector_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _input_selector_defs_h diff --git a/drivers/staging/media/atomisp/pci/input_switch_2400_defs.h b/drivers/staging/media/atomisp/pci/input_switch_2400_defs.h index 8ea1d7991d38fd..c56e00913204d5 100644 --- a/drivers/staging/media/atomisp/pci/input_switch_2400_defs.h +++ b/drivers/staging/media/atomisp/pci/input_switch_2400_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _input_switch_2400_defs_h diff --git a/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h b/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h index b2076a96987c44..e26b9ba3356aa5 100644 --- a/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h +++ b/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _input_system_ctrl_defs_h diff --git a/drivers/staging/media/atomisp/pci/input_system_defs.h b/drivers/staging/media/atomisp/pci/input_system_defs.h index 0c6a74b1891fae..ae07d195214656 100644 --- a/drivers/staging/media/atomisp/pci/input_system_defs.h +++ b/drivers/staging/media/atomisp/pci/input_system_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _input_system_defs_h diff --git a/drivers/staging/media/atomisp/pci/irq_controller_defs.h b/drivers/staging/media/atomisp/pci/irq_controller_defs.h index e49e61e17ee79a..4703d991a8b84e 100644 --- a/drivers/staging/media/atomisp/pci/irq_controller_defs.h +++ b/drivers/staging/media/atomisp/pci/irq_controller_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _irq_controller_defs_h diff --git a/drivers/staging/media/atomisp/pci/irq_types_hrt.h b/drivers/staging/media/atomisp/pci/irq_types_hrt.h index 4212bb01c8d831..3579fdaee37a5c 100644 --- a/drivers/staging/media/atomisp/pci/irq_types_hrt.h +++ b/drivers/staging/media/atomisp/pci/irq_types_hrt.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _HIVE_ISP_CSS_IRQ_TYPES_HRT_H_ diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2.host.c index daf2f25c1ed6fc..968766c1bd2a18 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2.host.h index 3abc125debd030..2232d725c5f45d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_AA_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2_param.h index 4f8bb4de4edcbf..be0db730494619 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_AA_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2_types.h index 900ba8f5e30c68..2f568a7062da72 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/aa/aa_2/ia_css_aa2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_AA2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr.host.c index 3f079c954c1fac..899d566234b9d3 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr.host.h index a4720c4a948ab7..4f77900871c8b9 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ANR_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_param.h index 37dcb013b76dc4..39ebcb0efc10db 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ANR_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h index 9b22f2da45d56f..6e573ceaa9ea2e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ANR_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2.host.c index 9cdefedc631284..09599884bdaefe 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2.host.h index 2b3ab01c279d87..2b1105f21c1e2b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ANR2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_param.h index 4b83b8100160ec..f0e0f2a0f30b5f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ANR2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_table.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_table.host.c index 649283bd44f2ee..87cc5cb5dd5d25 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_table.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_table.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_table.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_table.host.h index 9e383e030ac47c..bda174abd54dd6 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_table.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_table.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ANR2_TABLE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_types.h index e12aae819dcec5..2c7c3c3fd8ce54 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_2/ia_css_anr2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ANR2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh.host.c index 2091f001502d42..69c87e53f3c22f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh.host.h index 736b6e3f9512dd..36b360cfe62e65 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BH_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh_param.h index 05d5c43e6b16a2..634783fd0b5b96 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_HB_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh_types.h index 4c0e92f13d6c0d..c717c636f666b9 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bh/bh_2/ia_css_bh_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BH_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm.host.c index 45e37dc4f1e3ee..cd867937ee13fe 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "type_support.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm.host.h index 3632bf27cc2183..2e47ce5e55249a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BNLM_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm_param.h index 30672db269df9f..1d389a60d2bcf0 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BNLM_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm_types.h index 407b5a3b0fcdcb..150d3960caee97 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnlm/ia_css_bnlm_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BNLM_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2.host.c index c42fcb1d9100ee..b3a9b2f794a0ac 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "type_support.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2.host.h index f6ab5d2bb218df..08d2c4c7f493d2 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BNR2_2_HOST_H #define __IA_CSS_BNR2_2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2_param.h index 087723795476c1..1b1c1beae66718 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BNR2_2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2_types.h index 5f3dfa59f95053..387909c35c1ab9 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr2_2/ia_css_bnr2_2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BNR2_2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr.host.c index b75cfd3096d8c3..0c08077c741b71 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr.host.h index 7fc2a728a6c247..a5f0a12f42b1db 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BNR_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr_param.h index 4f6469315386e6..2afda71921719f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/bnr/bnr_1.0/ia_css_bnr_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BNR_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr.host.c index 0eb40517e08ccd..54789d28a9bcd4 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr.host.h index 4d046b730f0669..d4ffe59ff8a01b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CNR_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr_param.h index 971ab87af2c542..6a8daab667a1bb 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_1.0/ia_css_cnr_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CNR_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2.host.c index 495dc1f33ca6de..a333c3aa57096e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2.host.h index 38f848137edad4..213009192f09c1 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CNR2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2_param.h index 3709aa4d36526b..5346f98ab8aa1a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CNR2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2_types.h index d0a25616727cc6..9bb9ca7f7ad298 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/cnr/cnr_2/ia_css_cnr2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CNR2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion.host.c index ff452e2cc23ac9..958120b82e4796 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion.host.h index 520623e2734978..69eadaffa4cee7 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CONVERSION_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_param.h index fcbec189eff8c7..f0601e236d73ce 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CONVERSION_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h index 34152d6d09be07..374261d25520ee 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CONVERSION_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output.host.c index cc415c72ad8f62..a42064dd1c851f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_copy_output.host.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output.host.h index 44e3e45b0ec328..9257b99bf8ddde 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_COPY_OUTPUT_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output_param.h index 56daa1d9674746..32e526717f59fb 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/copy_output/copy_output_1.0/ia_css_copy_output_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_COPY_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop.host.c index 8c1d50f7aae4b8..7ec23098687202 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop.host.h index e700149c1e95fb..9f51ecfdad1481 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CROP_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop_param.h index 7416e74dd782ae..b766847e5bcbc1 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CROP_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop_types.h index aaaae5e2abb983..0571302014f82f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/crop/crop_1.0/ia_css_crop_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CROP_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc.host.c index 284c17970e5599..0f5ea8b3e5b3e5 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc.host.h index 6b0256a73e5210..9dcef66939396a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CSC_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc_param.h index 3809ef73e49040..f0380b2c571df7 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CSC_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc_types.h index 160f19bdfca009..1e56d78e5ab9ac 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/csc/csc_1.0/ia_css_csc_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CSC_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5.host.c index 149adbc57730a9..0089402bc12d83 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5.host.h index 8c17e7b921b51e..6dba55261c0837 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC1_5_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5_param.h index c18cfc930db67d..35ef610ed226b3 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc1_5/ia_css_ctc1_5_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC1_5_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2.host.c index e3d3f1253422ab..38751b8e9e6aca 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2.host.h index eb10c388402005..84ab060d6c888d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2_param.h index 94844da665e5e6..41337538abbbe2 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2_types.h index f9f329a58737a4..187c22f8da51fc 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc2/ia_css_ctc2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc.host.c index 82f2adbbfac36b..f60cbe49ffab3d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc.host.h index 57d1d08e1bc8bf..6ed1fe8b0b3c4c 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_param.h index eaad708c611cc1..ae3d183b414205 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_table.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_table.host.c index 6a7925c8493a87..632807fbbd1d66 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_table.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_table.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include /* for memcpy() */ diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_table.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_table.host.h index 33e8a05455a386..b78fc46231d4b7 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_table.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_table.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC_TABLE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_types.h index b2d42f3c1f4d81..67f4e01a319711 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ctc/ctc_1.0/ia_css_ctc_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_CTC_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de.host.c index e66faeda361347..52a07feb48ec6c 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de.host.h index cb91062029cfe0..b00d1c0fa24934 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de_param.h index 2070ce040470c3..07db16340ef2f5 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DE_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de_types.h index daac1275c12921..e1f025846b8365 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_1.0/ia_css_de_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DE_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2.host.c index f90da39296ec9d..16426b2cbfb4b4 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2.host.h index 294f619a3b1508..0ce9e363aa2c3c 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DE2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2_param.h index 4c9d5c630cb073..ff6c6ed2fc132e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DE2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2_types.h index 372cd9d2b803fe..ca36c001607c39 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/de/de_2/ia_css_de2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DE2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp.host.c index eff428c67c8631..98144a1a9db445 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp.host.h index e5f5a27160107b..93c48de872ccaa 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DP_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp_param.h index e0e7f2d48237f8..ff8061e820ec3a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DP_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp_types.h index c1666ebf1d3b5d..036727f3772d8e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dp/dp_1.0/ia_css_dp_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DP_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2.host.c index f6fe064bdda49b..82521aed7aff98 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_dpc2.host.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2.host.h index f6e019a65208ff..85419182c1f5a7 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DPC2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_param.h index 1ccceadbb7bfcf..099f32b8de1a6b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DPC2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_types.h index f742a8dc1d675c..c261899bcaa02f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dpc2/ia_css_dpc2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DPC2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.c index 07ce5b4f0816b3..30c84639d7e88a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.h index 332aa5496c04a2..98995c9ed0a1b9 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DVS_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs_param.h index 2963bb10b12948..368f5b2b1ee83a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DVS_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs_types.h index e99ff0ce8baba5..7057fac6e293fa 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/dvs/dvs_1.0/ia_css_dvs_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_DVS_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c index b79d78e5b77f5b..8e4451fcc8e331 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef IA_CSS_NO_DEBUG diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.h index f1ad07e78b3a04..4af4bae1519057 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_EED1_8_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_param.h index b9eeeb592ec818..df87770446dd65 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_EED1_8_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h index 836e348c184f73..0b977eb7ad717a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_EED1_8_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats.host.c index bae1ca2cd505b4..6a10d3545278e7 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_formats.host.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats.host.h index 540423d85e9d76..17a57ddaa3212c 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FORMATS_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats_param.h index 5275a1dadefabf..2a16d93abf825b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FORMATS_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats_types.h index 16b6a3ddcd083d..5958e7b2ddfe94 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fc/fc_1.0/ia_css_formats_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FORMATS_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_param.h index 6cd635f3ee2713..f7e5669d512579 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FIXEDBDS_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_types.h index 3a55d4c698e69f..7626dfe82642e1 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FIXEDBDS_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.c index 8ccfa99c61efa2..b34feba5340bc8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.h index bd341fa287fe8e..cdd4350c082cad 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FPN_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn_param.h index b2141574370570..94edd1d21e9adf 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FPN_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn_types.h index 14dc5e18318471..8b246c80e105e4 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/fpn/fpn_1.0/ia_css_fpn_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FPN_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc.host.c index 7f3f87920dc7b9..afef48ebd8180a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc.host.h index c2dc1574a3daf5..785bc5329dd3f9 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_GC_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_param.h index a81233add43766..fcd16196cc5ab8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_GC_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_table.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_table.host.c index 7dbe2dc0591d7e..b0427a9d6628df 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_table.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_table.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include /* for memcpy() */ diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_table.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_table.host.h index ee6fa07b35112d..f24e6d84e40a55 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_table.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_table.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_GC_TABLE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_types.h index ccd3d91a24d33c..09d3fb41b73fdb 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_1.0/ia_css_gc_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_GC_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2.host.c index 76209b7c14cb80..3a32026a8f6021 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2.host.h index eabf78737bfccb..a7ac7241d47797 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_GC2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_param.h index af456e75e476e2..76c8521f0e153a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_GC2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_table.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_table.host.c index 34795011907a26..101f703443ec21 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_table.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_table.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include /* for memcpy() */ diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_table.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_table.host.h index 13049fbfab84ed..f2ce0cc47f86b3 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_table.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_table.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_GC2_TABLE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_types.h index ae16409d84a595..abb0d3d871b311 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/gc/gc_2/ia_css_gc2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_GC2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr.host.c index 85a02b6adb528d..7a53928ef26c6b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr.host.c @@ -3,15 +3,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_hdr.host.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr.host.h index 83277b683c4764..916b72b082ecfd 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr.host.h @@ -3,15 +3,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_HDR_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_param.h index 998c6d801756c8..da787654440cd8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_param.h @@ -3,15 +3,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_HDR_PARAMS_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h index ecc98686f5cf53..e32290d1c86b09 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h @@ -3,15 +3,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_HDR_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c index c32659894c29d5..38f371b6d6d586 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.h index 9c7e5a1ad57b73..3c82bbd79c4ca9 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __BAYER_IO_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io_param.h index 283ace8385b011..1586decb3c1ee8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BAYER_IO_PARAM diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io_types.h index d06d25c9b81c48..ec84c120d4f6ce 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/bayer_io_ls/ia_css_bayer_io_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_BAYER_IO_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h index 5e0e4cd5bfbae3..c9a3f7bfaa902a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef __IA_CSS_COMMON_IO_PARAM diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h index 0801481c4b4932..c1c93b2245c5e0 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef __IA_CSS_COMMON_IO_TYPES diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c index 5b2d5023b5eeed..13054ffc0b358f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.c @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h index 13e50590f91e10..e6ce0cba44b952 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef __YUV444_IO_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h index 9b7537d508ad57..429fcdb73f60bc 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef __IA_CSS_YUV444_IO_PARAM diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h index 137a2a05c65baa..485ad17cb29baf 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef __IA_CSS_YUV444_IO_TYPES diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator.host.c index 15386a773dc510..b8ba26f56cfabe 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_iterator.host.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator.host.h index 1419fa9a07f0e9..01b1dc76651a82 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ITERATOR_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator_param.h index e062f8d0612861..45151d90394422 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/iterator/iterator_1.0/ia_css_iterator_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ITERATOR_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c index a70bce1179dab0..c4f3afb8582858 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.h index 6c1189e1d26396..631839aa3c5726 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MACC1_5_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_param.h index 66b8fb259218f0..0f38cd7ea9b183 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MACC1_5_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_table.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_table.host.c index d205d64e0b9443..aea74be18fe954 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_table.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_table.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_table.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_table.host.h index d451efbaa184bb..76a3a5035d10a5 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_table.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_table.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MACC1_5_TABLE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_types.h index 5492af0dfa9f39..b0538808ae561b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MACC1_5_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc.host.c index f2d3832a0039ae..6e2159f7b395b9 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc.host.h index 912db92540e6c3..faba2dc79ed3f1 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MACC_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_param.h index 71665204e4ddf4..e8c91a12b944ed 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MACC_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_table.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_table.host.c index d25bf59273baad..1720fa9d4f7244 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_table.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_table.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_table.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_table.host.h index 35099cb79d6af1..620a72f7cb1fc0 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_table.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_table.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MACC_TABLE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_types.h index 172a518cb93580..20e34f53bec248 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc_1.0/ia_css_macc_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_MACC_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm.host.c index 69283b631da7f3..16e400b3cdaab1 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_norm.host.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm.host.h index 3987abcae85cc9..7e1d334273e69d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_NORM_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm_param.h index 06c39fdfc9e391..0481213edf93a5 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/norm/norm_1.0/ia_css_norm_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_NORM_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2.host.c index c4ffff630b6427..5c9e56a0bd599f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2.host.h index 26c2e43202dc65..3bb192250d6855 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OB2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2_param.h index c3c9fc3f90643a..e64fb1a9a26c23 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OB2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2_types.h index 51e4c35cf659bc..9e5cd58df56312 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob2/ia_css_ob2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OB2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob.host.c index 12191cd36d5cb8..6801a5d6051374 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob.host.h index dfcac0c6404083..636c6d5242f740 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OB_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob_param.h index 991aa3c4051b98..366b5900fd2852 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OB_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob_types.h index b74296517b030d..b1470f8b424c90 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ob/ob_1.0/ia_css_ob_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OB_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output.host.c index be9e4ef29fcea8..d09365e0c47104 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_frame.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output.host.h index c8523e95a3948c..25408f1aede55a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OUTPUT_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output_param.h index df125674bb35f8..940d03e909b1af 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OUTPUT_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output_types.h index e5f9c05d2120ae..7c17ef200571ea 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/output/output_1.0/ia_css_output_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_OUTPUT_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane.host.c index 9fd4435e96b046..6296deb72bd4fc 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_frame.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane.host.h index b3f8fa30c8cea7..2fa1de5e3633b5 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_QPLANE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane_param.h index 9ae29045086585..a50c98ea3f3092 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_QPLANE_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane_types.h index 549f1a36bb7e15..ae9707e1f76190 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/qplane/qplane_2/ia_css_qplane_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_QPLANE_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.c index 40d4a052156274..a00f8d049a3369 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_frame.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.h index 23da51aabc8db0..cae9c7fcb7f1d1 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_RAW_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw_param.h index c4b5f719a336bc..24b34083d0e96b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_RAW_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw_types.h index 1ccaa3c48407ec..ee25414ea8cdee 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/raw/raw_1.0/ia_css_raw_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_RAW_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/raw_aa_binning/raw_aa_binning_1.0/ia_css_raa.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/raw_aa_binning/raw_aa_binning_1.0/ia_css_raa.host.c index 9b756daddee06a..cd7d1c13605a19 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/raw_aa_binning/raw_aa_binning_1.0/ia_css_raa.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/raw_aa_binning/raw_aa_binning_1.0/ia_css_raa.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/raw_aa_binning/raw_aa_binning_1.0/ia_css_raa.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/raw_aa_binning/raw_aa_binning_1.0/ia_css_raa.host.h index 4c2b3de7281ed4..f800a05fe1dd5d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/raw_aa_binning/raw_aa_binning_1.0/ia_css_raa.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/raw_aa_binning/raw_aa_binning_1.0/ia_css_raa.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_RAA_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c index 9288a7a37b37a1..d9b68b08dd3c1a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.h index 388cd4c367bae0..f0556bbcc86879 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_REF_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_param.h index c727e27a8e140b..ec1be8b6c65c7a 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_REF_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_state.h b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_state.h index d4f7a66763eb85..b057e440a22feb 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_state.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_state.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_REF_STATE_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_types.h index 07d040bcf281c2..abc6af2da91b7b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ref/ref_1.0/ia_css_ref_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_REF_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c index bd7b89d9475bf6..13678138c48c42 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.h index f9926e29756802..f000b4347472fe 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_S3A_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a_param.h index 9cb75b22067879..f88264781a20b8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_S3A_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h index f369e9b95ca81b..b8206d2f3d3106 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/s3a/s3a_1.0/ia_css_s3a_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_S3A_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc.host.c index 6974b3424d910c..16b7d36e1cc265 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc.host.h index d103103c9a87b2..1730b368d191f4 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SC_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_param.h index fab11d3350fd3d..61e9c04d251575 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SC_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_types.h index 1d70f6b9a0ecb2..2f91934f2c06a8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sc/sc_1.0/ia_css_sc_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SC_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/common/ia_css_sdis_common.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/common/ia_css_sdis_common.host.h index 7b661e49b4d028..bad400b2fd377e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/common/ia_css_sdis_common.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/common/ia_css_sdis_common.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_SDIS_COMMON_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/common/ia_css_sdis_common_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/common/ia_css_sdis_common_types.h index c2ec30b4abd41d..1a3790c1c353bd 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/common/ia_css_sdis_common_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/common/ia_css_sdis_common_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SDIS_COMMON_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c index bf0a768f8fe18c..a4e019e74e6b6d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.h index 0d0ed96e08fe05..c8566dafcbe584 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SDIS_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis_types.h index a8f2b8afcfd693..02a91968c37aed 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SDIS_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c index c13de289a3dbe9..027eae0ca69e27 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.h index e0e6b9c338ad71..e8ec4066c1cbdf 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SDIS2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2_types.h index d75b72e9551bed..f378028785280f 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SDIS2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf.host.c index fef8c5457cdae8..ce93a07a7961cf 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_debug.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf.host.h index 7e44d78c5d5de3..22ec8745a08394 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_TDF_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf_param.h index e904f71221423d..512063894ee5a9 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_TDF_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf_types.h index 0f69f9128f0e5d..a462365783afa0 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tdf/tdf_1.0/ia_css_tdf_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_TDF_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h index 4b53fddfcd2da4..42b760ffac67d4 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef _IA_CSS_TNR3_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c index a5fea753ec6447..31b96d93c3cc12 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.h index acf92052b44202..3ab82458b94550 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_TNR_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_param.h index 551dd5cfa9f138..1782a95aa0f2e8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_TNR_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_state.h b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_state.h index d5723842394773..867a6211c0eab8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_state.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_state.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_TNR_STATE_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_types.h index 92dbe13895c6f6..57444475098661 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr_1.0/ia_css_tnr_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_TNR_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/uds/uds_1.0/ia_css_uds_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/uds/uds_1.0/ia_css_uds_param.h index 784b5c4facd22e..520324949aa75c 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/uds/uds_1.0/ia_css_uds_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/uds/uds_1.0/ia_css_uds_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_UDS_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.c index aecdcbe04ce154..ece5e3da34eeb4 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "atomisp_internal.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.h index d6b45d3754b0cb..d2085b7f45014e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_VF_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf_param.h index 487ddf1633245e..cf1e4f401cd190 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_VF_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf_types.h index 24fbb61d349c54..0319fb1a33dbe5 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/vf/vf_1.0/ia_css_vf_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_VF_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb.host.c index 01d1a2d361c3b7..bc18bdaaaf0da2 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb.host.h index ffd75c8a64fb8f..841b6c6f7e7c6e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_WB_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb_param.h index 51b2ba8efc1805..7a57c47e924622 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_WB_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb_types.h index 20ae73c0ef8ccb..3a59c7de7387c3 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/wb/wb_1.0/ia_css_wb_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_WB_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr.host.c index 1cd59660857f4d..9f9f3af9fb41bc 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr.host.h index 686101c0b6a993..b8e63486a8a5bc 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_XNR_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_param.h index 93754f7c797d6b..0e92c32242f303 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_XNR_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_table.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_table.host.c index e5c15308693deb..ce8eef985e5dfc 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_table.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_table.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include /* for memcpy() */ diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_table.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_table.host.h index 2f4ab8ad402b3b..dbe236f80d3016 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_table.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_table.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_XNR_TABLE_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_types.h index 9a4d2e470524c5..42ad8b9b51d388 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_1.0/ia_css_xnr_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_XNR_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c index def2c8fb4b389d..e90dea58215b93 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.h index 6b57990b72da4e..a5e1294527fca2 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_XNR3_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_param.h index c728db7ce917c4..8997099dff5a51 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_XNR3_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h index 4447ba31ad690f..c012c1865d1ec4 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_XNR3_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.c index 048ffbc90b8ee9..d43a3539c6d4cd 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.h index 049706e1ffa983..ed5c17cc081fd4 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_YNR_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr_param.h index 8d9069ec28a101..51221f83fc87ba 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_YNR_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr_types.h index da1ba21a072691..bf5c388938ef71 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_1.0/ia_css_ynr_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_YNR_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2.host.c index 08e9d72c143f22..9e75cb64157769 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2.host.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2.host.h index eaf253d59c4dae..cad590e76fcfd3 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2.host.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_YNR2_HOST_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2_param.h index 96c80b3af426f8..9553f16f9d2f0d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_YNR2_PARAM_H diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2_types.h index ab77f4e85319e5..502e104d7226ba 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ynr/ynr_2/ia_css_ynr2_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_YNR2_TYPES_H diff --git a/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h b/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h index f86cf9bf13a5c3..c7ade6ce6c68a9 100644 --- a/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h +++ b/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef _INPUT_BUF_ISP_H_ diff --git a/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h b/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h index 73432dc35ae36e..b767b0d35bb495 100644 --- a/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h +++ b/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef _COMMON_ISP_CONST_H_ diff --git a/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_types.h b/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_types.h index d1c42c77fa507e..e5c77a95d7026d 100644 --- a/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_types.h +++ b/drivers/staging/media/atomisp/pci/isp/modes/interface/isp_types.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _ISP_TYPES_H_ diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_global.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_global.h index c00acf764b93ae..df4378fd3540b7 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_global.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index f9b9c3ae50aa79..56a4db03304486 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_SYSTEM_2400_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_private.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_private.h index e011920f00e191..a6762683a0ac5f 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_private.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_SYSTEM_2400_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h index 03b7ab7a70d9b6..2147929392e16e 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_public.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_SYSTEM_2400_PUBLIC_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/isp2400_support.h b/drivers/staging/media/atomisp/pci/isp2400_support.h index 06d04853d4ee2c..6e0b563c6c485d 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_support.h +++ b/drivers/staging/media/atomisp/pci/isp2400_support.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _isp2400_support_h diff --git a/drivers/staging/media/atomisp/pci/isp2401_input_system_global.h b/drivers/staging/media/atomisp/pci/isp2401_input_system_global.h index b116be41507458..4aadeb1336ba78 100644 --- a/drivers/staging/media/atomisp/pci/isp2401_input_system_global.h +++ b/drivers/staging/media/atomisp/pci/isp2401_input_system_global.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* CSI reveiver has 3 ports. */ diff --git a/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h index d9a8d575c58e41..50e58553075040 100644 --- a/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2401_input_system_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_SYSTEM_2401_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h b/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h index 845ed0add027bd..36ae5445fdb418 100644 --- a/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h +++ b/drivers/staging/media/atomisp/pci/isp2401_input_system_private.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __INPUT_SYSTEM_2401_PRIVATE_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h b/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h index 7e8f6f2178aa8a..b04404ad59d948 100644 --- a/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h +++ b/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _isp_acquisition_defs_h diff --git a/drivers/staging/media/atomisp/pci/isp_capture_defs.h b/drivers/staging/media/atomisp/pci/isp_capture_defs.h index b9e5ed932702f6..b1fbf492a80952 100644 --- a/drivers/staging/media/atomisp/pci/isp_capture_defs.h +++ b/drivers/staging/media/atomisp/pci/isp_capture_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _isp_capture_defs_h diff --git a/drivers/staging/media/atomisp/pci/mamoiada_params.h b/drivers/staging/media/atomisp/pci/mamoiada_params.h index e18e5f3576df28..a4831f1e02dbab 100644 --- a/drivers/staging/media/atomisp/pci/mamoiada_params.h +++ b/drivers/staging/media/atomisp/pci/mamoiada_params.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* Version */ diff --git a/drivers/staging/media/atomisp/pci/mmu/isp_mmu.c b/drivers/staging/media/atomisp/pci/mmu/isp_mmu.c index 72287de75a6383..5193a7eb7d9fca 100644 --- a/drivers/staging/media/atomisp/pci/mmu/isp_mmu.c +++ b/drivers/staging/media/atomisp/pci/mmu/isp_mmu.c @@ -5,17 +5,6 @@ * Copyright (c) 2010 Intel Corporation. All Rights Reserved. * * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ /* * ISP MMU management wrap code diff --git a/drivers/staging/media/atomisp/pci/mmu/sh_mmu_mrfld.c b/drivers/staging/media/atomisp/pci/mmu/sh_mmu_mrfld.c index 0fbb361f5661ba..c9890892c8aadd 100644 --- a/drivers/staging/media/atomisp/pci/mmu/sh_mmu_mrfld.c +++ b/drivers/staging/media/atomisp/pci/mmu/sh_mmu_mrfld.c @@ -5,17 +5,6 @@ * Copyright (c) 2012 Intel Corporation. All Rights Reserved. * * Copyright (c) 2012 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * */ #include "type_support.h" #include "mmu/isp_mmu.h" diff --git a/drivers/staging/media/atomisp/pci/mmu_defs.h b/drivers/staging/media/atomisp/pci/mmu_defs.h index 03cfb58330279a..6a26f2cad52a1b 100644 --- a/drivers/staging/media/atomisp/pci/mmu_defs.h +++ b/drivers/staging/media/atomisp/pci/mmu_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _mmu_defs_h diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h b/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h index 9935ac860bc262..9c682f2ecbb2c6 100644 --- a/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h +++ b/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef _IA_CSS_BINARY_H_ @@ -186,7 +178,6 @@ ia_css_binary_find(struct ia_css_binary_descr *descr, * @param[out] pipe_config: The pipe configuration. * The shading information related to ISP (but, not necessary as API) is stored in the pipe_config. * @return 0 or error code upon error. - * */ int ia_css_binary_get_shading_info(const struct ia_css_binary *binary, diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c index 7ce2b2d6da11ae..af93ca96747c43 100644 --- a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c +++ b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include @@ -951,7 +942,7 @@ int ia_css_binary_find(struct ia_css_binary_descr *descr, struct ia_css_binary * unsigned int i; assert(descr); - /* MW: used after an error check, may accept NULL, but doubtfull */ + /* MW: used after an error check, may accept NULL, but doubtful */ assert(binary); dev_dbg(atomisp_dev, "ia_css_binary_find() enter: descr=%p, (mode=%d), binary=%p\n", diff --git a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h index a461b0ed03f1e6..3e7dadca6d707b 100644 --- a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h +++ b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_BUFQ_H diff --git a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq_comm.h b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq_comm.h index 567d94d91e3cfa..fb8067fd64a1c3 100644 --- a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq_comm.h +++ b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq_comm.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_BUFQ_COMM_H diff --git a/drivers/staging/media/atomisp/pci/runtime/bufq/src/bufq.c b/drivers/staging/media/atomisp/pci/runtime/bufq/src/bufq.c index 6a75cba4886f32..bda35614c86245 100644 --- a/drivers/staging/media/atomisp/pci/runtime/bufq/src/bufq.c +++ b/drivers/staging/media/atomisp/pci/runtime/bufq/src/bufq.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "assert_support.h" /* assert */ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h index e9a09117e5e51e..2d0e906530af45 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_DEBUG_H_ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_internal.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_internal.h index 8ec487ad429814..d4accfc5d9a703 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_internal.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_internal.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /* TO DO: Move debug related code from ia_css_internal.h in */ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h index 538918cfb2fc61..80c58cb934d5e9 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_DEBUG_PIPE_H_ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c index 35c98fb8d6e8f4..9818771a35e550 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "debug.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/event/interface/ia_css_event.h b/drivers/staging/media/atomisp/pci/runtime/event/interface/ia_css_event.h index ebbd90b14bffe7..d0c3278b0fd95d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/event/interface/ia_css_event.h +++ b/drivers/staging/media/atomisp/pci/runtime/event/interface/ia_css_event.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_EVENT_H diff --git a/drivers/staging/media/atomisp/pci/runtime/event/src/event.c b/drivers/staging/media/atomisp/pci/runtime/event/src/event.c index e702297b0a7652..6154dda2d968ba 100644 --- a/drivers/staging/media/atomisp/pci/runtime/event/src/event.c +++ b/drivers/staging/media/atomisp/pci/runtime/event/src/event.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "sh_css_sp.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h b/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h index fd001ae3522dfc..9b058e296c93d7 100644 --- a/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h +++ b/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_EVENTQ_H diff --git a/drivers/staging/media/atomisp/pci/runtime/eventq/src/eventq.c b/drivers/staging/media/atomisp/pci/runtime/eventq/src/eventq.c index df75cef46a511a..fb1710ddcf4805 100644 --- a/drivers/staging/media/atomisp/pci/runtime/eventq/src/eventq.c +++ b/drivers/staging/media/atomisp/pci/runtime/eventq/src/eventq.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_types.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h index 90c17884968b06..45d4bb87af7aa0 100644 --- a/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h +++ b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FRAME_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame_comm.h b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame_comm.h index ce6110efbfc91d..d1031f824896d3 100644 --- a/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame_comm.h +++ b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame_comm.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_FRAME_COMM_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c index 2d7fddb114f655..4f610f57e6c117 100644 --- a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c +++ b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" @@ -362,7 +353,7 @@ void ia_css_frame_free_multiple(unsigned int num_frames, int ia_css_frame_allocate_with_buffer_size(struct ia_css_frame **frame, const unsigned int buffer_size_bytes) { - /* AM: Body coppied from frame_allocate_with_data(). */ + /* AM: Body copied from frame_allocate_with_data(). */ int err; struct ia_css_frame *me = frame_create(0, 0, IA_CSS_FRAME_FORMAT_NUM,/* Not valid format yet */ diff --git a/drivers/staging/media/atomisp/pci/runtime/ifmtr/interface/ia_css_ifmtr.h b/drivers/staging/media/atomisp/pci/runtime/ifmtr/interface/ia_css_ifmtr.h index 2c440feec3ceeb..01b89cdaf83589 100644 --- a/drivers/staging/media/atomisp/pci/runtime/ifmtr/interface/ia_css_ifmtr.h +++ b/drivers/staging/media/atomisp/pci/runtime/ifmtr/interface/ia_css_ifmtr.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_IFMTR_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c b/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c index 7b5603e4e1730d..d57ffb335fc0cc 100644 --- a/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c +++ b/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/inputfifo/interface/ia_css_inputfifo.h b/drivers/staging/media/atomisp/pci/runtime/inputfifo/interface/ia_css_inputfifo.h index 7950c5c36693dd..a95c3098c82ab1 100644 --- a/drivers/staging/media/atomisp/pci/runtime/inputfifo/interface/ia_css_inputfifo.h +++ b/drivers/staging/media/atomisp/pci/runtime/inputfifo/interface/ia_css_inputfifo.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_INPUTFIFO_H diff --git a/drivers/staging/media/atomisp/pci/runtime/inputfifo/src/inputfifo.c b/drivers/staging/media/atomisp/pci/runtime/inputfifo/src/inputfifo.c index 2d06e124007eb9..8e1efeb6372c00 100644 --- a/drivers/staging/media/atomisp/pci/runtime/inputfifo/src/inputfifo.c +++ b/drivers/staging/media/atomisp/pci/runtime/inputfifo/src/inputfifo.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "platform_support.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param.h b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param.h index 0ea5d6fdc88bc0..ff9050fede1059 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param.h +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_ISP_PARAM_H_ diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h index 8cdeae98bda8e7..d6d60508c1bf0c 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h @@ -3,14 +3,6 @@ Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. -This program is free software; you can redistribute it and/or modify it -under the terms and conditions of the GNU General Public License, -version 2, as published by the Free Software Foundation. - -This program is distributed in the hope it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. */ #ifndef _IA_CSS_ISP_PARAM_TYPES_H_ diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c b/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c index 99c2f3a533abaa..251dd75a761356 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h index d067b9fc43c795..29eebe8f90782e 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ISYS_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h index 784afc82c8d2f9..3d4c0cd2f2a6a5 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_ISYS_COMM_H diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c index 881036c67baf62..7490d189f39d49 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.h index 11f730dc1c08b6..e68386e544691b 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __CSI_RX_RMGR_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.c index 9710493c47ac7d..b8d431dcd6c14b 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.h index 7c754ec7224a81..2345dee7ba08c0 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IBUF_CTRL_RMGR_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c index 4df0a9188ee66e..2ce2f32a194631 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.h index 88c3d558199954..070a06df5f0c8b 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_DMA_RMGR_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c index 18bfe101098922..46bb3569e13948 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "input_system.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c index b6be63746c3eed..9217d26cf632ba 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_global.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.h index 78a4c867fb1bc2..c07ee12746d447 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __ISYS_STREAM2MMIO_RMGR_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index deb4130f710cd5..9cfb8bc97e24ff 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #define __INLINE_INPUT_SYSTEM__ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c index 2e0193671f4b0d..b5395aea89fc70 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.h index fbdbca0cfcc86d..a911766b7d4909 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __VIRTUAL_ISYS_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h index 5f5dab7252aad4..316eaa2070ea79 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PIPELINE_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline_common.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline_common.h index cc44f03c3b344f..dff453b37db146 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline_common.h +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline_common.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_PIPELINE_COMMON_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c index 9d2b5f9cbb146f..aabebe61ec779e 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue.h b/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue.h index 08112be4633fd4..c097d912d87f89 100644 --- a/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue.h +++ b/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_QUEUE_H diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue_comm.h b/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue_comm.h index 1379ae8f8c0125..0bed6425a07f02 100644 --- a/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue_comm.h +++ b/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue_comm.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_QUEUE_COMM_H diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue.c b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue.c index 0e430388b331b5..afe77d4373f8dd 100644 --- a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue.c +++ b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_queue.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.c b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.c index 424e7a15a38975..2591d157870ce5 100644 --- a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.c +++ b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.h b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.h index d5107adccef9ef..d62133a8fe6f86 100644 --- a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.h +++ b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __QUEUE_ACCESS_H diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h index 9cd3d92b34c9f4..00b903d950df78 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_RMGR_H diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h index ac969afc8bb494..6820bfc7743224 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _IA_CSS_RMGR_VBUF_H diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr.c b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr.c index c94a428aaddef3..3e014fd0e548d3 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr.c +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_rmgr.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c index 1f24db77fe3878..940b28c66e9975 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010-2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl.h b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl.h index efe6c4a82caf8a..3cd69284f4b4fb 100644 --- a/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl.h +++ b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SPCTRL_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h index de68616482f0c8..f358785fa5b6b5 100644 --- a/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h +++ b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_SPCTRL_COMM_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c b/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c index c34bfc5f970d0a..78f00f07baaa75 100644 --- a/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c +++ b/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h b/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h index 49801fbc192402..79006c325de60e 100644 --- a/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h +++ b/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2010 - 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __IA_CSS_TAGGER_COMMON_H__ diff --git a/drivers/staging/media/atomisp/pci/runtime/timer/src/timer.c b/drivers/staging/media/atomisp/pci/runtime/timer/src/timer.c index 08f5c3ea6d2948..391308e563cb03 100644 --- a/drivers/staging/media/atomisp/pci/runtime/timer/src/timer.c +++ b/drivers/staging/media/atomisp/pci/runtime/timer/src/timer.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include /* for uint32_t */ diff --git a/drivers/staging/media/atomisp/pci/scalar_processor_2400_params.h b/drivers/staging/media/atomisp/pci/scalar_processor_2400_params.h index 7e7188797b0a2f..e31da83d31067d 100644 --- a/drivers/staging/media/atomisp/pci/scalar_processor_2400_params.h +++ b/drivers/staging/media/atomisp/pci/scalar_processor_2400_params.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _scalar_processor_2400_params_h diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index ca97ea082cf4d6..5a8e8e67aa1389 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ /*! \file */ @@ -6308,9 +6299,6 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) } } - if (err) - goto ERR; - ERR: if (need_scaler) ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr); diff --git a/drivers/staging/media/atomisp/pci/sh_css_defs.h b/drivers/staging/media/atomisp/pci/sh_css_defs.h index 2afde974e75d24..51491dfe05cc96 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_defs.h +++ b/drivers/staging/media/atomisp/pci/sh_css_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_DEFS_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/sh_css_firmware.c index 197ab2085e8d22..bed5992237175a 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include /* for memcpy() */ diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.h b/drivers/staging/media/atomisp/pci/sh_css_firmware.h index a73ce703adfb63..1c6bc29f68d5e3 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.h +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_FIRMWARE_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_frac.h b/drivers/staging/media/atomisp/pci/sh_css_frac.h index 8ba65161f7a988..c2cf244ac06ee1 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_frac.h +++ b/drivers/staging/media/atomisp/pci/sh_css_frac.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SH_CSS_FRAC_H @@ -37,7 +28,8 @@ static inline int sDIGIT_FITTING(int v, int a, int b) int fit_shift = sFRACTION_BITS_FITTING(a) - b; v >>= sSHIFT; - v >>= fit_shift > 0 ? fit_shift : 0; + if (fit_shift > 0) + v >>= fit_shift; return clamp_t(int, v, sISP_VAL_MIN, sISP_VAL_MAX); } @@ -47,7 +39,8 @@ static inline unsigned int uDIGIT_FITTING(unsigned int v, int a, int b) int fit_shift = uFRACTION_BITS_FITTING(a) - b; v >>= uSHIFT; - v >>= fit_shift > 0 ? fit_shift : 0; + if (fit_shift > 0) + v >>= fit_shift; return clamp_t(unsigned int, v, uISP_VAL_MIN, uISP_VAL_MAX); } diff --git a/drivers/staging/media/atomisp/pci/sh_css_host_data.c b/drivers/staging/media/atomisp/pci/sh_css_host_data.c index 39a9b981268204..39efd8933034d6 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_host_data.c +++ b/drivers/staging/media/atomisp/pci/sh_css_host_data.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/sh_css_hrt.c b/drivers/staging/media/atomisp/pci/sh_css_hrt.c index 879c853110384e..d4633572f8f39a 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_hrt.c +++ b/drivers/staging/media/atomisp/pci/sh_css_hrt.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "platform_support.h" diff --git a/drivers/staging/media/atomisp/pci/sh_css_hrt.h b/drivers/staging/media/atomisp/pci/sh_css_hrt.h index 168bbd57979821..c2d88b4607c4d6 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_hrt.h +++ b/drivers/staging/media/atomisp/pci/sh_css_hrt.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_HRT_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_internal.h b/drivers/staging/media/atomisp/pci/sh_css_internal.h index 959e7f549641c1..7b348358574844 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_internal.h +++ b/drivers/staging/media/atomisp/pci/sh_css_internal.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_INTERNAL_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_legacy.h b/drivers/staging/media/atomisp/pci/sh_css_legacy.h index cdf239b070a897..1d3549c52a4606 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_legacy.h +++ b/drivers/staging/media/atomisp/pci/sh_css_legacy.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_LEGACY_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_metrics.c b/drivers/staging/media/atomisp/pci/sh_css_metrics.c index 8ded6cdd15755b..edf473dd86ca45 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_metrics.c +++ b/drivers/staging/media/atomisp/pci/sh_css_metrics.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "assert_support.h" diff --git a/drivers/staging/media/atomisp/pci/sh_css_metrics.h b/drivers/staging/media/atomisp/pci/sh_css_metrics.h index f4bcd08384e910..0ae995b80d077d 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_metrics.h +++ b/drivers/staging/media/atomisp/pci/sh_css_metrics.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_METRICS_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.c b/drivers/staging/media/atomisp/pci/sh_css_mipi.c index 80f0395cc560ed..42f14ed853e1c9 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.c +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_mipi.h" @@ -169,7 +160,7 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, /* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */ mem_words_for_first_line = (words_for_first_line + 7) >> 3; mem_words_per_even_line = (words_per_even_line + 7) >> 3; - mem_words_for_EOF = 1; /* last line consisit of the optional (EOL) and EOF */ + mem_words_for_EOF = 1; /* last line consist of the optional (EOL) and EOF */ mem_words = ((embedded_data_size_words + 7) >> 3) + mem_words_for_first_line + diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.h b/drivers/staging/media/atomisp/pci/sh_css_mipi.h index e6c86d0ac483db..6f7389f44baa7c 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.h +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SH_CSS_MIPI_H diff --git a/drivers/staging/media/atomisp/pci/sh_css_mmu.c b/drivers/staging/media/atomisp/pci/sh_css_mmu.c index 1da7459eaa25a4..f2a84c1d6e525a 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mmu.c +++ b/drivers/staging/media/atomisp/pci/sh_css_mmu.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_mmu.h" diff --git a/drivers/staging/media/atomisp/pci/sh_css_param_dvs.c b/drivers/staging/media/atomisp/pci/sh_css_param_dvs.c index 5174bc210ae171..7fa4aab35b0611 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_param_dvs.c +++ b/drivers/staging/media/atomisp/pci/sh_css_param_dvs.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "sh_css_param_dvs.h" diff --git a/drivers/staging/media/atomisp/pci/sh_css_param_dvs.h b/drivers/staging/media/atomisp/pci/sh_css_param_dvs.h index 25e5b4570f7da1..b7057887adea68 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_param_dvs.h +++ b/drivers/staging/media/atomisp/pci/sh_css_param_dvs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_PARAMS_DVS_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_param_shading.c b/drivers/staging/media/atomisp/pci/sh_css_param_shading.c index 5b43cc65626902..513e272f2fdc0c 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_param_shading.c +++ b/drivers/staging/media/atomisp/pci/sh_css_param_shading.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include diff --git a/drivers/staging/media/atomisp/pci/sh_css_param_shading.h b/drivers/staging/media/atomisp/pci/sh_css_param_shading.h index 7cdfaaec0b1cac..b4ca8815dc1bbf 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_param_shading.h +++ b/drivers/staging/media/atomisp/pci/sh_css_param_shading.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SH_CSS_PARAMS_SHADING_H diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 232744973ab887..0d4a936ad80f53 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "gdc_device.h" /* gdc_lut_store(), ... */ @@ -4181,6 +4172,8 @@ ia_css_3a_statistics_allocate(const struct ia_css_3a_grid_info *grid) goto err; /* No weighted histogram, no structure, treat the histogram data as a byte dump in a byte array */ me->rgby_data = kvmalloc(sizeof_hmem(HMEM0_ID), GFP_KERNEL); + if (!me->rgby_data) + goto err; IA_CSS_LEAVE("return=%p", me); return me; diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.h b/drivers/staging/media/atomisp/pci/sh_css_params.h index bbca19d0e8fc56..75957dea3c387e 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.h +++ b/drivers/staging/media/atomisp/pci/sh_css_params.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_PARAMS_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_params_internal.h b/drivers/staging/media/atomisp/pci/sh_css_params_internal.h index 8e5e6f273a950c..b832e18b42e482 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params_internal.h +++ b/drivers/staging/media/atomisp/pci/sh_css_params_internal.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_PARAMS_INTERNAL_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_properties.c b/drivers/staging/media/atomisp/pci/sh_css_properties.c index 8ecd93d65a6855..caeeaf9a953609 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_properties.c +++ b/drivers/staging/media/atomisp/pci/sh_css_properties.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "ia_css_properties.h" diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.c b/drivers/staging/media/atomisp/pci/sh_css_sp.c index c2ab70f8fafef6..6da151e7a87328 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.c +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "hmm.h" diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.h b/drivers/staging/media/atomisp/pci/sh_css_sp.h index c12f57f5befc84..78aec5b7e8fa7e 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.h +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_SP_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_stream_format.c b/drivers/staging/media/atomisp/pci/sh_css_stream_format.c index a798f0537050ee..24ec09703d9a5d 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_stream_format.c +++ b/drivers/staging/media/atomisp/pci/sh_css_stream_format.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "sh_css_stream_format.h" diff --git a/drivers/staging/media/atomisp/pci/sh_css_stream_format.h b/drivers/staging/media/atomisp/pci/sh_css_stream_format.h index 84b7942147ad0f..7f5a3be00c6ba1 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_stream_format.h +++ b/drivers/staging/media/atomisp/pci/sh_css_stream_format.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SH_CSS_STREAM_FORMAT_H diff --git a/drivers/staging/media/atomisp/pci/sh_css_struct.h b/drivers/staging/media/atomisp/pci/sh_css_struct.h index eb8960ebae3410..c51fcb72520894 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_struct.h +++ b/drivers/staging/media/atomisp/pci/sh_css_struct.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SH_CSS_STRUCT_H diff --git a/drivers/staging/media/atomisp/pci/sh_css_uds.h b/drivers/staging/media/atomisp/pci/sh_css_uds.h index 8d9c5c92b6924e..951f32da9aed47 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_uds.h +++ b/drivers/staging/media/atomisp/pci/sh_css_uds.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _SH_CSS_UDS_H_ diff --git a/drivers/staging/media/atomisp/pci/sh_css_version.c b/drivers/staging/media/atomisp/pci/sh_css_version.c index f5ff8ca66b5086..ba8660f0cb8174 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_version.c +++ b/drivers/staging/media/atomisp/pci/sh_css_version.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "../../include/linux/atomisp.h" diff --git a/drivers/staging/media/atomisp/pci/str2mem_defs.h b/drivers/staging/media/atomisp/pci/str2mem_defs.h index e8cb456ac9c77a..fc06d4e4589f7a 100644 --- a/drivers/staging/media/atomisp/pci/str2mem_defs.h +++ b/drivers/staging/media/atomisp/pci/str2mem_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _ST2MEM_DEFS_H diff --git a/drivers/staging/media/atomisp/pci/streaming_to_mipi_defs.h b/drivers/staging/media/atomisp/pci/streaming_to_mipi_defs.h index e0e3a6a662450b..8efbaa55f7520a 100644 --- a/drivers/staging/media/atomisp/pci/streaming_to_mipi_defs.h +++ b/drivers/staging/media/atomisp/pci/streaming_to_mipi_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _streaming_to_mipi_defs_h diff --git a/drivers/staging/media/atomisp/pci/system_local.c b/drivers/staging/media/atomisp/pci/system_local.c index 4ca8569d7feb93..a8a93760d5b107 100644 --- a/drivers/staging/media/atomisp/pci/system_local.c +++ b/drivers/staging/media/atomisp/pci/system_local.c @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include "system_local.h" diff --git a/drivers/staging/media/atomisp/pci/system_local.h b/drivers/staging/media/atomisp/pci/system_local.h index a47258c2e8a871..970f4ef990ec9b 100644 --- a/drivers/staging/media/atomisp/pci/system_local.h +++ b/drivers/staging/media/atomisp/pci/system_local.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef __SYSTEM_LOCAL_H_INCLUDED__ diff --git a/drivers/staging/media/atomisp/pci/timed_controller_defs.h b/drivers/staging/media/atomisp/pci/timed_controller_defs.h index 9ddad87702dea1..37a9226c694185 100644 --- a/drivers/staging/media/atomisp/pci/timed_controller_defs.h +++ b/drivers/staging/media/atomisp/pci/timed_controller_defs.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef _timed_controller_defs_h diff --git a/drivers/staging/media/atomisp/pci/version.h b/drivers/staging/media/atomisp/pci/version.h index a74a7bbfdb0e5c..90688034c49168 100644 --- a/drivers/staging/media/atomisp/pci/version.h +++ b/drivers/staging/media/atomisp/pci/version.h @@ -2,15 +2,6 @@ /* * Support for Intel Camera Imaging ISP subsystem. * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #ifndef HRT_VERSION_H diff --git a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c index 305b103153d7ed..fb9ee8547392b4 100644 --- a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c +++ b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c @@ -477,8 +477,6 @@ static struct isc_format *find_format_by_fourcc(struct isc_device *isc, static const struct vb2_ops isc_vb2_ops = { .queue_setup = isc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = isc_buffer_prepare, .start_streaming = isc_start_streaming, .stop_streaming = isc_stop_streaming, diff --git a/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c b/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c index 712f916f0935f5..71e6e278a4b3cc 100644 --- a/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c +++ b/drivers/staging/media/deprecated/atmel/atmel-sama5d2-isc.c @@ -629,7 +629,7 @@ MODULE_DEVICE_TABLE(of, atmel_isc_of_match); static struct platform_driver atmel_isc_driver = { .probe = atmel_isc_probe, - .remove_new = atmel_isc_remove, + .remove = atmel_isc_remove, .driver = { .name = "atmel-sama5d2-isc", .pm = &atmel_isc_dev_pm_ops, diff --git a/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c b/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c index 9485167d5b7d73..1f74c2dd044cfb 100644 --- a/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c +++ b/drivers/staging/media/deprecated/atmel/atmel-sama7g5-isc.c @@ -592,7 +592,7 @@ MODULE_DEVICE_TABLE(of, microchip_xisc_of_match); static struct platform_driver microchip_xisc_driver = { .probe = microchip_xisc_probe, - .remove_new = microchip_xisc_remove, + .remove = microchip_xisc_remove, .driver = { .name = "microchip-sama7g5-xisc", .pm = µchip_xisc_dev_pm_ops, diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index efa7623b5cee1b..e9cef7af000a91 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -768,8 +768,6 @@ static const struct vb2_ops capture_qops = { .buf_init = capture_buf_init, .buf_prepare = capture_buf_prepare, .buf_queue = capture_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = capture_start_streaming, .stop_streaming = capture_stop_streaming, }; diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c index 95cca281e8a378..e5e08c6f79f222 100644 --- a/drivers/staging/media/imx/imx-media-csc-scaler.c +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -572,8 +572,6 @@ static const struct vb2_ops ipu_csc_scaler_qops = { .queue_setup = ipu_csc_scaler_queue_setup, .buf_prepare = ipu_csc_scaler_buf_prepare, .buf_queue = ipu_csc_scaler_buf_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = ipu_csc_scaler_start_streaming, .stop_streaming = ipu_csc_scaler_stop_streaming, }; diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 785aac88192212..3edbc57be2caa7 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -2076,7 +2076,7 @@ MODULE_DEVICE_TABLE(platform, imx_csi_ids); static struct platform_driver imx_csi_driver = { .probe = imx_csi_probe, - .remove_new = imx_csi_remove, + .remove = imx_csi_remove, .id_table = imx_csi_ids, .driver = { .name = "imx-ipuv3-csi", diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index be54dca11465dc..a08389b99d14ac 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -129,7 +129,7 @@ MODULE_DEVICE_TABLE(of, imx_media_dt_ids); static struct platform_driver imx_media_pdrv = { .probe = imx_media_probe, - .remove_new = imx_media_remove, + .remove = imx_media_remove, .driver = { .name = "imx-media", .of_match_table = imx_media_dt_ids, diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index 0d8b420616235d..dd8c7b3233bccf 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -836,7 +836,7 @@ static struct platform_driver csi2_driver = { .of_match_table = csi2_dt_ids, }, .probe = csi2_probe, - .remove_new = csi2_remove, + .remove = csi2_remove, }; module_platform_driver(csi2_driver); diff --git a/drivers/staging/media/ipu3/ipu3-css-params.c b/drivers/staging/media/ipu3/ipu3-css-params.c index 34f574b0b5216c..2c48d57a3180f8 100644 --- a/drivers/staging/media/ipu3/ipu3-css-params.c +++ b/drivers/staging/media/ipu3/ipu3-css-params.c @@ -639,7 +639,7 @@ static int imgu_css_osys_calc_frame_and_stripe_params( /* * FW workaround for a HW bug: if the first * chroma pixel is generated exactly at the end - * of chunck scaler HW may not output the pixel + * of chunk scaler HW may not output the pixel * for downscale factors smaller than 1.5 * (timing issue). */ @@ -1416,7 +1416,7 @@ imgu_css_shd_ops_calc(struct imgu_abi_shd_intra_frame_operations_data *ops, } /* - * The follow handshake procotol is the same for AF, AWB and AWB FR. + * The following handshake protocol is the same for AF, AWB and AWB FR. * * for n sets of meta-data, the flow is: * --> init @@ -2626,7 +2626,7 @@ int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe, return -EINVAL; acc->awb.config.grid.height_per_slice = - IMGU_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width, + IMGU_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width; imgu_css_grid_end_calc(&acc->awb.config.grid); for (i = 0; i < stripes; i++) diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index e7aee7e3db5bbd..ad6095bf717db6 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -937,8 +937,6 @@ static const struct vb2_ops imgu_vb2_ops = { .queue_setup = imgu_vb2_queue_setup, .start_streaming = imgu_vb2_start_streaming, .stop_streaming = imgu_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /****************** v4l2_file_operations *****************/ diff --git a/drivers/staging/media/max96712/max96712.c b/drivers/staging/media/max96712/max96712.c index 6bdbccbee05ac3..ede02e8c891cbb 100644 --- a/drivers/staging/media/max96712/max96712.c +++ b/drivers/staging/media/max96712/max96712.c @@ -16,20 +16,27 @@ #include #include -#define MAX96712_ID 0x20 - -#define MAX96712_DPLL_FREQ 1000 +#define DEBUG_EXTRA_REG 0x09 +#define DEBUG_EXTRA_PCLK_25MHZ 0x00 +#define DEBUG_EXTRA_PCLK_75MHZ 0x01 enum max96712_pattern { MAX96712_PATTERN_CHECKERBOARD = 0, MAX96712_PATTERN_GRADIENT, }; +struct max96712_info { + unsigned int dpllfreq; + bool have_debug_extra; +}; + struct max96712_priv { struct i2c_client *client; struct regmap *regmap; struct gpio_desc *gpiod_pwdn; + const struct max96712_info *info; + bool cphy; struct v4l2_mbus_config_mipi_csi2 mipi; @@ -40,19 +47,6 @@ struct max96712_priv { enum max96712_pattern pattern; }; -static int max96712_read(struct max96712_priv *priv, int reg) -{ - int ret, val; - - ret = regmap_read(priv->regmap, reg, &val); - if (ret) { - dev_err(&priv->client->dev, "read 0x%04x failed\n", reg); - return ret; - } - - return val; -} - static int max96712_write(struct max96712_priv *priv, unsigned int reg, u8 val) { int ret; @@ -153,9 +147,9 @@ static void max96712_mipi_configure(struct max96712_priv *priv) /* Set link frequency for PHY0 and PHY1. */ max96712_update_bits(priv, 0x415, 0x3f, - ((MAX96712_DPLL_FREQ / 100) & 0x1f) | BIT(5)); + ((priv->info->dpllfreq / 100) & 0x1f) | BIT(5)); max96712_update_bits(priv, 0x418, 0x3f, - ((MAX96712_DPLL_FREQ / 100) & 0x1f) | BIT(5)); + ((priv->info->dpllfreq / 100) & 0x1f) | BIT(5)); /* Enable PHY0 and PHY1 */ max96712_update_bits(priv, 0x8a2, 0xf0, 0x30); @@ -180,8 +174,9 @@ static void max96712_pattern_enable(struct max96712_priv *priv, bool enable) return; } - /* PCLK 75MHz. */ - max96712_write(priv, 0x0009, 0x01); + /* Set PCLK to 75MHz if device have DEBUG_EXTRA register. */ + if (priv->info->have_debug_extra) + max96712_write(priv, DEBUG_EXTRA_REG, DEBUG_EXTRA_PCLK_75MHZ); /* Configure Video Timing Generator for 1920x1080 @ 30 fps. */ max96712_write_bulk_value(priv, 0x1052, 0, 3); @@ -317,7 +312,7 @@ static int max96712_v4l2_register(struct max96712_priv *priv) * TODO: Once V4L2_CID_LINK_FREQ is changed from a menu control to an * INT64 control it should be used here instead of V4L2_CID_PIXEL_RATE. */ - pixel_rate = MAX96712_DPLL_FREQ / priv->mipi.num_data_lanes * 1000000; + pixel_rate = priv->info->dpllfreq / priv->mipi.num_data_lanes * 1000000; v4l2_ctrl_new_std(&priv->ctrl_handler, NULL, V4L2_CID_PIXEL_RATE, pixel_rate, pixel_rate, 1, pixel_rate); @@ -420,6 +415,8 @@ static int max96712_probe(struct i2c_client *client) if (!priv) return -ENOMEM; + priv->info = of_device_get_match_data(&client->dev); + priv->client = client; i2c_set_clientdata(client, priv); @@ -438,9 +435,6 @@ static int max96712_probe(struct i2c_client *client) if (priv->gpiod_pwdn) usleep_range(4000, 5000); - if (max96712_read(priv, 0x4a) != MAX96712_ID) - return -ENODEV; - max96712_reset(priv); ret = max96712_parse_dt(priv); @@ -461,9 +455,19 @@ static void max96712_remove(struct i2c_client *client) gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); } +static const struct max96712_info max96712_info_max96712 = { + .dpllfreq = 1000, + .have_debug_extra = true, +}; + +static const struct max96712_info max96712_info_max96724 = { + .dpllfreq = 1200, +}; + static const struct of_device_id max96712_of_table[] = { - { .compatible = "maxim,max96712" }, - { /* sentinel */ }, + { .compatible = "maxim,max96712", .data = &max96712_info_max96712 }, + { .compatible = "maxim,max96724", .data = &max96712_info_max96724 }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, max96712_of_table); diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index 5e5b296f93bab4..6d34a482492e88 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -450,8 +450,6 @@ static const struct vb2_ops vdec_vb2_ops = { .stop_streaming = vdec_stop_streaming, .buf_queue = vdec_vb2_buf_queue, .buf_prepare = vdec_vb2_buf_prepare, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int @@ -1119,7 +1117,7 @@ static void vdec_remove(struct platform_device *pdev) static struct platform_driver meson_vdec_driver = { .probe = vdec_probe, - .remove_new = vdec_remove, + .remove = vdec_remove, .driver = { .name = "meson-vdec", .of_match_table = vdec_dt_match, diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig deleted file mode 100644 index 6d1f55b091324a..00000000000000 --- a/drivers/staging/media/omap4iss/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -config VIDEO_OMAP4 - tristate "OMAP 4 Camera support" - depends on VIDEO_DEV && I2C - depends on ARCH_OMAP4 || COMPILE_TEST - select MEDIA_CONTROLLER - select VIDEO_V4L2_SUBDEV_API - select MFD_SYSCON - select VIDEOBUF2_DMA_CONTIG - help - Driver for an OMAP 4 ISS controller. diff --git a/drivers/staging/media/omap4iss/Makefile b/drivers/staging/media/omap4iss/Makefile deleted file mode 100644 index e64d489a4a7604..00000000000000 --- a/drivers/staging/media/omap4iss/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for OMAP4 ISS driver -# - -omap4-iss-objs += \ - iss.o iss_csi2.o iss_csiphy.o iss_ipipeif.o iss_ipipe.o iss_resizer.o iss_video.o - -obj-$(CONFIG_VIDEO_OMAP4) += omap4-iss.o diff --git a/drivers/staging/media/omap4iss/TODO b/drivers/staging/media/omap4iss/TODO deleted file mode 100644 index 4d220ef82653ec..00000000000000 --- a/drivers/staging/media/omap4iss/TODO +++ /dev/null @@ -1,3 +0,0 @@ -* Fix FIFO/buffer overflows and underflows -* Replace dummy resizer code with a real implementation -* Fix checkpatch errors and warnings diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c deleted file mode 100644 index 0c4283bb48ad39..00000000000000 --- a/drivers/staging/media/omap4iss/iss.c +++ /dev/null @@ -1,1354 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * TI OMAP4 ISS V4L2 Driver - * - * Copyright (C) 2012, Texas Instruments - * - * Author: Sergio Aguirre - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "iss.h" -#include "iss_regs.h" - -#define ISS_PRINT_REGISTER(iss, name)\ - dev_dbg(iss->dev, "###ISS " #name "=0x%08x\n", \ - iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_##name)) - -static void iss_print_status(struct iss_device *iss) -{ - dev_dbg(iss->dev, "-------------ISS HL Register dump-------------\n"); - - ISS_PRINT_REGISTER(iss, HL_REVISION); - ISS_PRINT_REGISTER(iss, HL_SYSCONFIG); - ISS_PRINT_REGISTER(iss, HL_IRQSTATUS(5)); - ISS_PRINT_REGISTER(iss, HL_IRQENABLE_SET(5)); - ISS_PRINT_REGISTER(iss, HL_IRQENABLE_CLR(5)); - ISS_PRINT_REGISTER(iss, CTRL); - ISS_PRINT_REGISTER(iss, CLKCTRL); - ISS_PRINT_REGISTER(iss, CLKSTAT); - - dev_dbg(iss->dev, "-----------------------------------------------\n"); -} - -/* - * omap4iss_flush - Post pending L3 bus writes by doing a register readback - * @iss: OMAP4 ISS device - * - * In order to force posting of pending writes, we need to write and - * readback the same register, in this case the revision register. - * - * See this link for reference: - * https://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html - */ -static void omap4iss_flush(struct iss_device *iss) -{ - iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION, 0); - iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION); -} - -/* - * iss_isp_enable_interrupts - Enable ISS ISP interrupts. - * @iss: OMAP4 ISS device - */ -static void omap4iss_isp_enable_interrupts(struct iss_device *iss) -{ - static const u32 isp_irq = ISP5_IRQ_OCP_ERR | - ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR | - ISP5_IRQ_RSZ_FIFO_OVF | - ISP5_IRQ_RSZ_INT_DMA | - ISP5_IRQ_ISIF_INT(0); - - /* Enable ISP interrupts */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0), isp_irq); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQENABLE_SET(0), - isp_irq); -} - -/* - * iss_isp_disable_interrupts - Disable ISS interrupts. - * @iss: OMAP4 ISS device - */ -static void omap4iss_isp_disable_interrupts(struct iss_device *iss) -{ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQENABLE_CLR(0), ~0); -} - -/* - * iss_enable_interrupts - Enable ISS interrupts. - * @iss: OMAP4 ISS device - */ -static void iss_enable_interrupts(struct iss_device *iss) -{ - static const u32 hl_irq = ISS_HL_IRQ_CSIA | ISS_HL_IRQ_CSIB - | ISS_HL_IRQ_ISP(0); - - /* Enable HL interrupts */ - iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5), hl_irq); - iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQENABLE_SET(5), hl_irq); - - if (iss->regs[OMAP4_ISS_MEM_ISP_SYS1]) - omap4iss_isp_enable_interrupts(iss); -} - -/* - * iss_disable_interrupts - Disable ISS interrupts. - * @iss: OMAP4 ISS device - */ -static void iss_disable_interrupts(struct iss_device *iss) -{ - if (iss->regs[OMAP4_ISS_MEM_ISP_SYS1]) - omap4iss_isp_disable_interrupts(iss); - - iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQENABLE_CLR(5), ~0); -} - -int omap4iss_get_external_info(struct iss_pipeline *pipe, - struct media_link *link) -{ - struct iss_device *iss = - container_of(pipe, struct iss_video, pipe)->iss; - struct v4l2_subdev_format fmt; - struct v4l2_ctrl *ctrl; - int ret; - - if (!pipe->external) - return 0; - - if (pipe->external_rate) - return 0; - - memset(&fmt, 0, sizeof(fmt)); - - fmt.pad = link->source->index; - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(link->sink->entity), - pad, get_fmt, NULL, &fmt); - if (ret < 0) - return -EPIPE; - - pipe->external_bpp = omap4iss_video_format_info(fmt.format.code)->bpp; - - ctrl = v4l2_ctrl_find(pipe->external->ctrl_handler, - V4L2_CID_PIXEL_RATE); - if (!ctrl) { - dev_warn(iss->dev, "no pixel rate control in subdev %s\n", - pipe->external->name); - return -EPIPE; - } - - pipe->external_rate = v4l2_ctrl_g_ctrl_int64(ctrl); - - return 0; -} - -/* - * Configure the bridge. Valid inputs are - * - * IPIPEIF_INPUT_CSI2A: CSI2a receiver - * IPIPEIF_INPUT_CSI2B: CSI2b receiver - * - * The bridge and lane shifter are configured according to the selected input - * and the ISP platform data. - */ -void omap4iss_configure_bridge(struct iss_device *iss, - enum ipipeif_input_entity input) -{ - u32 issctrl_val; - u32 isp5ctrl_val; - - issctrl_val = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CTRL); - issctrl_val &= ~ISS_CTRL_INPUT_SEL_MASK; - issctrl_val &= ~ISS_CTRL_CLK_DIV_MASK; - - isp5ctrl_val = iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL); - - switch (input) { - case IPIPEIF_INPUT_CSI2A: - issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2A; - break; - - case IPIPEIF_INPUT_CSI2B: - issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2B; - break; - - default: - return; - } - - issctrl_val |= ISS_CTRL_SYNC_DETECT_VS_RAISING; - - isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT | ISP5_CTRL_PSYNC_CLK_SEL | - ISP5_CTRL_SYNC_ENABLE; - - iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_CTRL, issctrl_val); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, isp5ctrl_val); -} - -#ifdef ISS_ISR_DEBUG -static void iss_isr_dbg(struct iss_device *iss, u32 irqstatus) -{ - static const char * const name[] = { - "ISP_0", - "ISP_1", - "ISP_2", - "ISP_3", - "CSIA", - "CSIB", - "CCP2_0", - "CCP2_1", - "CCP2_2", - "CCP2_3", - "CBUFF", - "BTE", - "SIMCOP_0", - "SIMCOP_1", - "SIMCOP_2", - "SIMCOP_3", - "CCP2_8", - "HS_VS", - "18", - "19", - "20", - "21", - "22", - "23", - "24", - "25", - "26", - "27", - "28", - "29", - "30", - "31", - }; - unsigned int i; - - dev_dbg(iss->dev, "ISS IRQ: "); - - for (i = 0; i < ARRAY_SIZE(name); i++) { - if ((1 << i) & irqstatus) - pr_cont("%s ", name[i]); - } - pr_cont("\n"); -} - -static void iss_isp_isr_dbg(struct iss_device *iss, u32 irqstatus) -{ - static const char * const name[] = { - "ISIF_0", - "ISIF_1", - "ISIF_2", - "ISIF_3", - "IPIPEREQ", - "IPIPELAST_PIX", - "IPIPEDMA", - "IPIPEBSC", - "IPIPEHST", - "IPIPEIF", - "AEW", - "AF", - "H3A", - "RSZ_REG", - "RSZ_LAST_PIX", - "RSZ_DMA", - "RSZ_CYC_RZA", - "RSZ_CYC_RZB", - "RSZ_FIFO_OVF", - "RSZ_FIFO_IN_BLK_ERR", - "20", - "21", - "RSZ_EOF0", - "RSZ_EOF1", - "H3A_EOF", - "IPIPE_EOF", - "26", - "IPIPE_DPC_INI", - "IPIPE_DPC_RNEW0", - "IPIPE_DPC_RNEW1", - "30", - "OCP_ERR", - }; - unsigned int i; - - dev_dbg(iss->dev, "ISP IRQ: "); - - for (i = 0; i < ARRAY_SIZE(name); i++) { - if ((1 << i) & irqstatus) - pr_cont("%s ", name[i]); - } - pr_cont("\n"); -} -#endif - -/* - * iss_isr - Interrupt Service Routine for ISS module. - * @irq: Not used currently. - * @_iss: Pointer to the OMAP4 ISS device - * - * Handles the corresponding callback if plugged in. - * - * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the - * IRQ wasn't handled. - */ -static irqreturn_t iss_isr(int irq, void *_iss) -{ - static const u32 ipipeif_events = ISP5_IRQ_IPIPEIF_IRQ | - ISP5_IRQ_ISIF_INT(0); - static const u32 resizer_events = ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR | - ISP5_IRQ_RSZ_FIFO_OVF | - ISP5_IRQ_RSZ_INT_DMA; - struct iss_device *iss = _iss; - u32 irqstatus; - - irqstatus = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5)); - iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5), irqstatus); - - if (irqstatus & ISS_HL_IRQ_CSIA) - omap4iss_csi2_isr(&iss->csi2a); - - if (irqstatus & ISS_HL_IRQ_CSIB) - omap4iss_csi2_isr(&iss->csi2b); - - if (irqstatus & ISS_HL_IRQ_ISP(0)) { - u32 isp_irqstatus = iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, - ISP5_IRQSTATUS(0)); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0), - isp_irqstatus); - - if (isp_irqstatus & ISP5_IRQ_OCP_ERR) - dev_dbg(iss->dev, "ISP5 OCP Error!\n"); - - if (isp_irqstatus & ipipeif_events) { - omap4iss_ipipeif_isr(&iss->ipipeif, - isp_irqstatus & ipipeif_events); - } - - if (isp_irqstatus & resizer_events) - omap4iss_resizer_isr(&iss->resizer, - isp_irqstatus & resizer_events); - -#ifdef ISS_ISR_DEBUG - iss_isp_isr_dbg(iss, isp_irqstatus); -#endif - } - - omap4iss_flush(iss); - -#ifdef ISS_ISR_DEBUG - iss_isr_dbg(iss, irqstatus); -#endif - - return IRQ_HANDLED; -} - -static const struct media_device_ops iss_media_ops = { - .link_notify = v4l2_pipeline_link_notify, -}; - -/* ----------------------------------------------------------------------------- - * Pipeline stream management - */ - -/* - * iss_pipeline_disable - Disable streaming on a pipeline - * @pipe: ISS pipeline - * @until: entity at which to stop pipeline walk - * - * Walk the entities chain starting at the pipeline output video node and stop - * all modules in the chain. Wait synchronously for the modules to be stopped if - * necessary. - * - * If the until argument isn't NULL, stop the pipeline walk when reaching the - * until entity. This is used to disable a partially started pipeline due to a - * subdev start error. - */ -static int iss_pipeline_disable(struct iss_pipeline *pipe, - struct media_entity *until) -{ - struct iss_device *iss = pipe->output->iss; - struct media_entity *entity; - struct media_pad *pad; - struct v4l2_subdev *subdev; - int failure = 0; - int ret; - - entity = &pipe->output->video.entity; - while (1) { - pad = &entity->pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - pad = media_pad_remote_pad_first(pad); - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) - break; - - entity = pad->entity; - if (entity == until) - break; - - subdev = media_entity_to_v4l2_subdev(entity); - ret = v4l2_subdev_call(subdev, video, s_stream, 0); - if (ret < 0) { - dev_warn(iss->dev, "%s: module stop timeout.\n", - subdev->name); - /* If the entity failed to stopped, assume it has - * crashed. Mark it as such, the ISS will be reset when - * applications will release it. - */ - media_entity_enum_set(&iss->crashed, &subdev->entity); - failure = -ETIMEDOUT; - } - } - - return failure; -} - -/* - * iss_pipeline_enable - Enable streaming on a pipeline - * @pipe: ISS pipeline - * @mode: Stream mode (single shot or continuous) - * - * Walk the entities chain starting at the pipeline output video node and start - * all modules in the chain in the given mode. - * - * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. - */ -static int iss_pipeline_enable(struct iss_pipeline *pipe, - enum iss_pipeline_stream_state mode) -{ - struct iss_device *iss = pipe->output->iss; - struct media_entity *entity; - struct media_pad *pad; - struct v4l2_subdev *subdev; - unsigned long flags; - int ret; - - /* If one of the entities in the pipeline has crashed it will not work - * properly. Refuse to start streaming in that case. This check must be - * performed before the loop below to avoid starting entities if the - * pipeline won't start anyway (those entities would then likely fail to - * stop, making the problem worse). - */ - if (media_entity_enum_intersects(&pipe->ent_enum, &iss->crashed)) - return -EIO; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT); - spin_unlock_irqrestore(&pipe->lock, flags); - - pipe->do_propagation = false; - - mutex_lock(&iss->media_dev.graph_mutex); - - entity = &pipe->output->video.entity; - while (1) { - pad = &entity->pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - pad = media_pad_remote_pad_first(pad); - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) - break; - - entity = pad->entity; - subdev = media_entity_to_v4l2_subdev(entity); - - ret = v4l2_subdev_call(subdev, video, s_stream, mode); - if (ret < 0 && ret != -ENOIOCTLCMD) { - iss_pipeline_disable(pipe, entity); - mutex_unlock(&iss->media_dev.graph_mutex); - return ret; - } - - if (subdev == &iss->csi2a.subdev || - subdev == &iss->csi2b.subdev) - pipe->do_propagation = true; - } - - mutex_unlock(&iss->media_dev.graph_mutex); - iss_print_status(pipe->output->iss); - - return 0; -} - -/* - * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline - * @pipe: ISS pipeline - * @state: Stream state (stopped, single shot or continuous) - * - * Set the pipeline to the given stream state. Pipelines can be started in - * single-shot or continuous mode. - * - * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. The pipeline state is not updated when the operation - * fails, except when stopping the pipeline. - */ -int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe, - enum iss_pipeline_stream_state state) -{ - int ret; - - if (state == ISS_PIPELINE_STREAM_STOPPED) - ret = iss_pipeline_disable(pipe, NULL); - else - ret = iss_pipeline_enable(pipe, state); - - if (ret == 0 || state == ISS_PIPELINE_STREAM_STOPPED) - pipe->stream_state = state; - - return ret; -} - -/* - * omap4iss_pipeline_cancel_stream - Cancel stream on a pipeline - * @pipe: ISS pipeline - * - * Cancelling a stream mark all buffers on all video nodes in the pipeline as - * erroneous and makes sure no new buffer can be queued. This function is called - * when a fatal error that prevents any further operation on the pipeline - * occurs. - */ -void omap4iss_pipeline_cancel_stream(struct iss_pipeline *pipe) -{ - if (pipe->input) - omap4iss_video_cancel_stream(pipe->input); - if (pipe->output) - omap4iss_video_cancel_stream(pipe->output); -} - -/* - * iss_pipeline_is_last - Verify if entity has an enabled link to the output - * video node - * @me: ISS module's media entity - * - * Returns 1 if the entity has an enabled link to the output video node or 0 - * otherwise. It's true only while pipeline can have no more than one output - * node. - */ -static int iss_pipeline_is_last(struct media_entity *me) -{ - struct iss_pipeline *pipe; - struct media_pad *pad; - - pipe = to_iss_pipeline(me); - if (!pipe || pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED) - return 0; - pad = media_pad_remote_pad_first(&pipe->output->pad); - return pad->entity == me; -} - -static int iss_reset(struct iss_device *iss) -{ - unsigned int timeout; - - iss_reg_set(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG, - ISS_HL_SYSCONFIG_SOFTRESET); - - timeout = iss_poll_condition_timeout( - !(iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG) & - ISS_HL_SYSCONFIG_SOFTRESET), 1000, 10, 100); - if (timeout) { - dev_err(iss->dev, "ISS reset timeout\n"); - return -ETIMEDOUT; - } - - media_entity_enum_zero(&iss->crashed); - - return 0; -} - -static int iss_isp_reset(struct iss_device *iss) -{ - unsigned int timeout; - - /* Fist, ensure that the ISP is IDLE (no transactions happening) */ - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG, - ISP5_SYSCONFIG_STANDBYMODE_MASK, - ISP5_SYSCONFIG_STANDBYMODE_SMART); - - iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, ISP5_CTRL_MSTANDBY); - - timeout = iss_poll_condition_timeout( - iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL) & - ISP5_CTRL_MSTANDBY_WAIT, 1000000, 1000, 1500); - if (timeout) { - dev_err(iss->dev, "ISP5 standby timeout\n"); - return -ETIMEDOUT; - } - - /* Now finally, do the reset */ - iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG, - ISP5_SYSCONFIG_SOFTRESET); - - timeout = iss_poll_condition_timeout( - !(iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG) & - ISP5_SYSCONFIG_SOFTRESET), 1000000, 1000, 1500); - if (timeout) { - dev_err(iss->dev, "ISP5 reset timeout\n"); - return -ETIMEDOUT; - } - - return 0; -} - -/* - * iss_module_sync_idle - Helper to sync module with its idle state - * @me: ISS submodule's media entity - * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization - * @stopping: flag which tells module wants to stop - * - * This function checks if ISS submodule needs to wait for next interrupt. If - * yes, makes the caller to sleep while waiting for such event. - */ -int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, - atomic_t *stopping) -{ - struct iss_pipeline *pipe = to_iss_pipeline(me); - struct iss_video *video = pipe->output; - unsigned long flags; - - if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED || - (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT && - !iss_pipeline_ready(pipe))) - return 0; - - /* - * atomic_set() doesn't include memory barrier on ARM platform for SMP - * scenario. We'll call it here to avoid race conditions. - */ - atomic_set(stopping, 1); - smp_wmb(); - - /* - * If module is the last one, it's writing to memory. In this case, - * it's necessary to check if the module is already paused due to - * DMA queue underrun or if it has to wait for next interrupt to be - * idle. - * If it isn't the last one, the function won't sleep but *stopping - * will still be set to warn next submodule caller's interrupt the - * module wants to be idle. - */ - if (!iss_pipeline_is_last(me)) - return 0; - - spin_lock_irqsave(&video->qlock, flags); - if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { - spin_unlock_irqrestore(&video->qlock, flags); - atomic_set(stopping, 0); - smp_wmb(); - return 0; - } - spin_unlock_irqrestore(&video->qlock, flags); - if (!wait_event_timeout(*wait, !atomic_read(stopping), - msecs_to_jiffies(1000))) { - atomic_set(stopping, 0); - smp_wmb(); - return -ETIMEDOUT; - } - - return 0; -} - -/* - * omap4iss_module_sync_is_stopped - Helper to verify if module was stopping - * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization - * @stopping: flag which tells module wants to stop - * - * This function checks if ISS submodule was stopping. In case of yes, it - * notices the caller by setting stopping to 0 and waking up the wait queue. - * Returns 1 if it was stopping or 0 otherwise. - */ -int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait, - atomic_t *stopping) -{ - if (atomic_cmpxchg(stopping, 1, 0)) { - wake_up(wait); - return 1; - } - - return 0; -} - -/* -------------------------------------------------------------------------- - * Clock management - */ - -#define ISS_CLKCTRL_MASK (ISS_CLKCTRL_CSI2_A |\ - ISS_CLKCTRL_CSI2_B |\ - ISS_CLKCTRL_ISP) - -static int __iss_subclk_update(struct iss_device *iss) -{ - u32 clk = 0; - int ret = 0, timeout = 1000; - - if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A) - clk |= ISS_CLKCTRL_CSI2_A; - - if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B) - clk |= ISS_CLKCTRL_CSI2_B; - - if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP) - clk |= ISS_CLKCTRL_ISP; - - iss_reg_update(iss, OMAP4_ISS_MEM_TOP, ISS_CLKCTRL, - ISS_CLKCTRL_MASK, clk); - - /* Wait for HW assertion */ - while (--timeout > 0) { - udelay(1); - if ((iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CLKSTAT) & - ISS_CLKCTRL_MASK) == clk) - break; - } - - if (!timeout) - ret = -EBUSY; - - return ret; -} - -int omap4iss_subclk_enable(struct iss_device *iss, - enum iss_subclk_resource res) -{ - iss->subclk_resources |= res; - - return __iss_subclk_update(iss); -} - -int omap4iss_subclk_disable(struct iss_device *iss, - enum iss_subclk_resource res) -{ - iss->subclk_resources &= ~res; - - return __iss_subclk_update(iss); -} - -#define ISS_ISP5_CLKCTRL_MASK (ISP5_CTRL_BL_CLK_ENABLE |\ - ISP5_CTRL_ISIF_CLK_ENABLE |\ - ISP5_CTRL_H3A_CLK_ENABLE |\ - ISP5_CTRL_RSZ_CLK_ENABLE |\ - ISP5_CTRL_IPIPE_CLK_ENABLE |\ - ISP5_CTRL_IPIPEIF_CLK_ENABLE) - -static void __iss_isp_subclk_update(struct iss_device *iss) -{ - u32 clk = 0; - - if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF) - clk |= ISP5_CTRL_ISIF_CLK_ENABLE; - - if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A) - clk |= ISP5_CTRL_H3A_CLK_ENABLE; - - if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ) - clk |= ISP5_CTRL_RSZ_CLK_ENABLE; - - if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE) - clk |= ISP5_CTRL_IPIPE_CLK_ENABLE; - - if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF) - clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE; - - if (clk) - clk |= ISP5_CTRL_BL_CLK_ENABLE; - - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, - ISS_ISP5_CLKCTRL_MASK, clk); -} - -void omap4iss_isp_subclk_enable(struct iss_device *iss, - enum iss_isp_subclk_resource res) -{ - iss->isp_subclk_resources |= res; - - __iss_isp_subclk_update(iss); -} - -void omap4iss_isp_subclk_disable(struct iss_device *iss, - enum iss_isp_subclk_resource res) -{ - iss->isp_subclk_resources &= ~res; - - __iss_isp_subclk_update(iss); -} - -/* - * iss_enable_clocks - Enable ISS clocks - * @iss: OMAP4 ISS device - * - * Return 0 if successful, or clk_enable return value if any of tthem fails. - */ -static int iss_enable_clocks(struct iss_device *iss) -{ - int ret; - - ret = clk_enable(iss->iss_fck); - if (ret) { - dev_err(iss->dev, "clk_enable iss_fck failed\n"); - return ret; - } - - ret = clk_enable(iss->iss_ctrlclk); - if (ret) { - dev_err(iss->dev, "clk_enable iss_ctrlclk failed\n"); - clk_disable(iss->iss_fck); - return ret; - } - - return 0; -} - -/* - * iss_disable_clocks - Disable ISS clocks - * @iss: OMAP4 ISS device - */ -static void iss_disable_clocks(struct iss_device *iss) -{ - clk_disable(iss->iss_ctrlclk); - clk_disable(iss->iss_fck); -} - -static int iss_get_clocks(struct iss_device *iss) -{ - iss->iss_fck = devm_clk_get(iss->dev, "iss_fck"); - if (IS_ERR(iss->iss_fck)) { - dev_err(iss->dev, "Unable to get iss_fck clock info\n"); - return PTR_ERR(iss->iss_fck); - } - - iss->iss_ctrlclk = devm_clk_get(iss->dev, "iss_ctrlclk"); - if (IS_ERR(iss->iss_ctrlclk)) { - dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n"); - return PTR_ERR(iss->iss_ctrlclk); - } - - return 0; -} - -/* - * omap4iss_get - Acquire the ISS resource. - * - * Initializes the clocks for the first acquire. - * - * Increment the reference count on the ISS. If the first reference is taken, - * enable clocks and power-up all submodules. - * - * Return a pointer to the ISS device structure, or NULL if an error occurred. - */ -struct iss_device *omap4iss_get(struct iss_device *iss) -{ - struct iss_device *__iss = iss; - - if (!iss) - return NULL; - - mutex_lock(&iss->iss_mutex); - if (iss->ref_count > 0) - goto out; - - if (iss_enable_clocks(iss) < 0) { - __iss = NULL; - goto out; - } - - iss_enable_interrupts(iss); - -out: - if (__iss) - iss->ref_count++; - mutex_unlock(&iss->iss_mutex); - - return __iss; -} - -/* - * omap4iss_put - Release the ISS - * - * Decrement the reference count on the ISS. If the last reference is released, - * power-down all submodules, disable clocks and free temporary buffers. - */ -void omap4iss_put(struct iss_device *iss) -{ - if (!iss) - return; - - mutex_lock(&iss->iss_mutex); - WARN_ON(iss->ref_count == 0); - if (--iss->ref_count == 0) { - iss_disable_interrupts(iss); - /* Reset the ISS if an entity has failed to stop. This is the - * only way to recover from such conditions, although it would - * be worth investigating whether resetting the ISP only can't - * fix the problem in some cases. - */ - if (!media_entity_enum_empty(&iss->crashed)) - iss_reset(iss); - iss_disable_clocks(iss); - } - mutex_unlock(&iss->iss_mutex); -} - -static int iss_map_mem_resource(struct platform_device *pdev, - struct iss_device *iss, - enum iss_mem_resources res) -{ - iss->regs[res] = devm_platform_ioremap_resource(pdev, res); - - return PTR_ERR_OR_ZERO(iss->regs[res]); -} - -static void iss_unregister_entities(struct iss_device *iss) -{ - omap4iss_resizer_unregister_entities(&iss->resizer); - omap4iss_ipipe_unregister_entities(&iss->ipipe); - omap4iss_ipipeif_unregister_entities(&iss->ipipeif); - omap4iss_csi2_unregister_entities(&iss->csi2a); - omap4iss_csi2_unregister_entities(&iss->csi2b); - - v4l2_device_unregister(&iss->v4l2_dev); - media_device_unregister(&iss->media_dev); -} - -/* - * iss_register_subdev_group - Register a group of subdevices - * @iss: OMAP4 ISS device - * @board_info: I2C subdevs board information array - * - * Register all I2C subdevices in the board_info array. The array must be - * terminated by a NULL entry, and the first entry must be the sensor. - * - * Return a pointer to the sensor media entity if it has been successfully - * registered, or NULL otherwise. - */ -static struct v4l2_subdev * -iss_register_subdev_group(struct iss_device *iss, - struct iss_subdev_i2c_board_info *board_info) -{ - struct v4l2_subdev *sensor = NULL; - unsigned int first; - - if (!board_info->board_info) - return NULL; - - for (first = 1; board_info->board_info; ++board_info, first = 0) { - struct v4l2_subdev *subdev; - struct i2c_adapter *adapter; - - adapter = i2c_get_adapter(board_info->i2c_adapter_id); - if (!adapter) { - dev_err(iss->dev, - "%s: Unable to get I2C adapter %d for device %s\n", - __func__, board_info->i2c_adapter_id, - board_info->board_info->type); - continue; - } - - subdev = v4l2_i2c_new_subdev_board(&iss->v4l2_dev, adapter, - board_info->board_info, NULL); - if (!subdev) { - dev_err(iss->dev, "Unable to register subdev %s\n", - board_info->board_info->type); - continue; - } - - if (first) - sensor = subdev; - } - - return sensor; -} - -static int iss_register_entities(struct iss_device *iss) -{ - struct iss_platform_data *pdata = iss->pdata; - struct iss_v4l2_subdevs_group *subdevs; - int ret; - - iss->media_dev.dev = iss->dev; - strscpy(iss->media_dev.model, "TI OMAP4 ISS", - sizeof(iss->media_dev.model)); - iss->media_dev.hw_revision = iss->revision; - iss->media_dev.ops = &iss_media_ops; - ret = media_device_register(&iss->media_dev); - if (ret < 0) { - dev_err(iss->dev, "Media device registration failed (%d)\n", - ret); - return ret; - } - - iss->v4l2_dev.mdev = &iss->media_dev; - ret = v4l2_device_register(iss->dev, &iss->v4l2_dev); - if (ret < 0) { - dev_err(iss->dev, "V4L2 device registration failed (%d)\n", - ret); - goto done; - } - - /* Register internal entities */ - ret = omap4iss_csi2_register_entities(&iss->csi2a, &iss->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap4iss_csi2_register_entities(&iss->csi2b, &iss->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap4iss_ipipeif_register_entities(&iss->ipipeif, &iss->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap4iss_ipipe_register_entities(&iss->ipipe, &iss->v4l2_dev); - if (ret < 0) - goto done; - - ret = omap4iss_resizer_register_entities(&iss->resizer, &iss->v4l2_dev); - if (ret < 0) - goto done; - - /* Register external entities */ - for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) { - struct v4l2_subdev *sensor; - struct media_entity *input; - unsigned int flags; - unsigned int pad; - - sensor = iss_register_subdev_group(iss, subdevs->subdevs); - if (!sensor) - continue; - - sensor->host_priv = subdevs; - - /* Connect the sensor to the correct interface module. - * CSI2a receiver through CSIPHY1, or - * CSI2b receiver through CSIPHY2 - */ - switch (subdevs->interface) { - case ISS_INTERFACE_CSI2A_PHY1: - input = &iss->csi2a.subdev.entity; - pad = CSI2_PAD_SINK; - flags = MEDIA_LNK_FL_IMMUTABLE - | MEDIA_LNK_FL_ENABLED; - break; - - case ISS_INTERFACE_CSI2B_PHY2: - input = &iss->csi2b.subdev.entity; - pad = CSI2_PAD_SINK; - flags = MEDIA_LNK_FL_IMMUTABLE - | MEDIA_LNK_FL_ENABLED; - break; - - default: - dev_err(iss->dev, "invalid interface type %u\n", - subdevs->interface); - ret = -EINVAL; - goto done; - } - - ret = media_create_pad_link(&sensor->entity, 0, input, pad, - flags); - if (ret < 0) - goto done; - } - - ret = v4l2_device_register_subdev_nodes(&iss->v4l2_dev); - -done: - if (ret < 0) - iss_unregister_entities(iss); - - return ret; -} - -/* - * iss_create_links() - Pads links creation for the subdevices - * @iss : Pointer to ISS device - * - * return negative error code or zero on success - */ -static int iss_create_links(struct iss_device *iss) -{ - int ret; - - ret = omap4iss_csi2_create_links(iss); - if (ret < 0) { - dev_err(iss->dev, "CSI2 pads links creation failed\n"); - return ret; - } - - ret = omap4iss_ipipeif_create_links(iss); - if (ret < 0) { - dev_err(iss->dev, "ISP IPIPEIF pads links creation failed\n"); - return ret; - } - - ret = omap4iss_resizer_create_links(iss); - if (ret < 0) { - dev_err(iss->dev, "ISP RESIZER pads links creation failed\n"); - return ret; - } - - /* Connect the submodules. */ - ret = media_create_pad_link( - &iss->csi2a.subdev.entity, CSI2_PAD_SOURCE, - &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0); - if (ret < 0) - return ret; - - ret = media_create_pad_link( - &iss->csi2b.subdev.entity, CSI2_PAD_SOURCE, - &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0); - if (ret < 0) - return ret; - - ret = media_create_pad_link( - &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP, - &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0); - if (ret < 0) - return ret; - - ret = media_create_pad_link( - &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP, - &iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0); - if (ret < 0) - return ret; - - ret = media_create_pad_link( - &iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP, - &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0); - if (ret < 0) - return ret; - - return 0; -}; - -static void iss_cleanup_modules(struct iss_device *iss) -{ - omap4iss_csi2_cleanup(iss); - omap4iss_ipipeif_cleanup(iss); - omap4iss_ipipe_cleanup(iss); - omap4iss_resizer_cleanup(iss); -} - -static int iss_initialize_modules(struct iss_device *iss) -{ - int ret; - - ret = omap4iss_csiphy_init(iss); - if (ret < 0) { - dev_err(iss->dev, "CSI PHY initialization failed\n"); - goto error_csiphy; - } - - ret = omap4iss_csi2_init(iss); - if (ret < 0) { - dev_err(iss->dev, "CSI2 initialization failed\n"); - goto error_csi2; - } - - ret = omap4iss_ipipeif_init(iss); - if (ret < 0) { - dev_err(iss->dev, "ISP IPIPEIF initialization failed\n"); - goto error_ipipeif; - } - - ret = omap4iss_ipipe_init(iss); - if (ret < 0) { - dev_err(iss->dev, "ISP IPIPE initialization failed\n"); - goto error_ipipe; - } - - ret = omap4iss_resizer_init(iss); - if (ret < 0) { - dev_err(iss->dev, "ISP RESIZER initialization failed\n"); - goto error_resizer; - } - - return 0; - -error_resizer: - omap4iss_ipipe_cleanup(iss); -error_ipipe: - omap4iss_ipipeif_cleanup(iss); -error_ipipeif: - omap4iss_csi2_cleanup(iss); -error_csi2: -error_csiphy: - return ret; -} - -static int iss_probe(struct platform_device *pdev) -{ - struct iss_platform_data *pdata = pdev->dev.platform_data; - struct iss_device *iss; - unsigned int i; - int ret; - - if (!pdata) - return -EINVAL; - - iss = devm_kzalloc(&pdev->dev, sizeof(*iss), GFP_KERNEL); - if (!iss) - return -ENOMEM; - - mutex_init(&iss->iss_mutex); - - iss->dev = &pdev->dev; - iss->pdata = pdata; - - iss->raw_dmamask = DMA_BIT_MASK(32); - iss->dev->dma_mask = &iss->raw_dmamask; - iss->dev->coherent_dma_mask = DMA_BIT_MASK(32); - - platform_set_drvdata(pdev, iss); - - /* - * TODO: When implementing DT support switch to syscon regmap lookup by - * phandle. - */ - iss->syscon = syscon_regmap_lookup_by_compatible("syscon"); - if (IS_ERR(iss->syscon)) { - ret = PTR_ERR(iss->syscon); - goto error; - } - - /* Clocks */ - ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP); - if (ret < 0) - goto error; - - ret = iss_get_clocks(iss); - if (ret < 0) - goto error; - - if (!omap4iss_get(iss)) { - ret = -EINVAL; - goto error; - } - - ret = iss_reset(iss); - if (ret < 0) - goto error_iss; - - iss->revision = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION); - dev_info(iss->dev, "Revision %08x found\n", iss->revision); - - for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) { - ret = iss_map_mem_resource(pdev, iss, i); - if (ret) - goto error_iss; - } - - /* Configure BTE BW_LIMITER field to max recommended value (1 GB) */ - iss_reg_update(iss, OMAP4_ISS_MEM_BTE, BTE_CTRL, - BTE_CTRL_BW_LIMITER_MASK, - 18 << BTE_CTRL_BW_LIMITER_SHIFT); - - /* Perform ISP reset */ - ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP); - if (ret < 0) - goto error_iss; - - ret = iss_isp_reset(iss); - if (ret < 0) - goto error_iss; - - dev_info(iss->dev, "ISP Revision %08x found\n", - iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_REVISION)); - - /* Interrupt */ - ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - ret = -ENODEV; - goto error_iss; - } - iss->irq_num = ret; - - if (devm_request_irq(iss->dev, iss->irq_num, iss_isr, IRQF_SHARED, - "OMAP4 ISS", iss)) { - dev_err(iss->dev, "Unable to request IRQ\n"); - ret = -EINVAL; - goto error_iss; - } - - /* Entities */ - ret = iss_initialize_modules(iss); - if (ret < 0) - goto error_iss; - - ret = iss_register_entities(iss); - if (ret < 0) - goto error_modules; - - ret = media_entity_enum_init(&iss->crashed, &iss->media_dev); - if (ret) - goto error_entities; - - ret = iss_create_links(iss); - if (ret < 0) - goto error_entities; - - omap4iss_put(iss); - - return 0; - -error_entities: - iss_unregister_entities(iss); - media_entity_enum_cleanup(&iss->crashed); -error_modules: - iss_cleanup_modules(iss); -error_iss: - omap4iss_put(iss); -error: - mutex_destroy(&iss->iss_mutex); - - return ret; -} - -static void iss_remove(struct platform_device *pdev) -{ - struct iss_device *iss = platform_get_drvdata(pdev); - - iss_unregister_entities(iss); - media_entity_enum_cleanup(&iss->crashed); - iss_cleanup_modules(iss); -} - -static const struct platform_device_id omap4iss_id_table[] = { - { "omap4iss", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(platform, omap4iss_id_table); - -static struct platform_driver iss_driver = { - .probe = iss_probe, - .remove_new = iss_remove, - .id_table = omap4iss_id_table, - .driver = { - .name = "omap4iss", - }, -}; - -module_platform_driver(iss_driver); - -MODULE_DESCRIPTION("TI OMAP4 ISS driver"); -MODULE_AUTHOR("Sergio Aguirre "); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h deleted file mode 100644 index 3f587e00072954..00000000000000 --- a/drivers/staging/media/omap4iss/iss.h +++ /dev/null @@ -1,247 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * TI OMAP4 ISS V4L2 Driver - * - * Copyright (C) 2012 Texas Instruments. - * - * Author: Sergio Aguirre - */ - -#ifndef _OMAP4_ISS_H_ -#define _OMAP4_ISS_H_ - -#include -#include - -#include -#include -#include -#include - -#include - -#include "iss_regs.h" -#include "iss_csiphy.h" -#include "iss_csi2.h" -#include "iss_ipipeif.h" -#include "iss_ipipe.h" -#include "iss_resizer.h" - -struct regmap; - -#define to_iss_device(ptr_module) \ - container_of(ptr_module, struct iss_device, ptr_module) -#define to_device(ptr_module) \ - (to_iss_device(ptr_module)->dev) - -enum iss_mem_resources { - OMAP4_ISS_MEM_TOP, - OMAP4_ISS_MEM_CSI2_A_REGS1, - OMAP4_ISS_MEM_CAMERARX_CORE1, - OMAP4_ISS_MEM_CSI2_B_REGS1, - OMAP4_ISS_MEM_CAMERARX_CORE2, - OMAP4_ISS_MEM_BTE, - OMAP4_ISS_MEM_ISP_SYS1, - OMAP4_ISS_MEM_ISP_RESIZER, - OMAP4_ISS_MEM_ISP_IPIPE, - OMAP4_ISS_MEM_ISP_ISIF, - OMAP4_ISS_MEM_ISP_IPIPEIF, - OMAP4_ISS_MEM_LAST, -}; - -enum iss_subclk_resource { - OMAP4_ISS_SUBCLK_SIMCOP = (1 << 0), - OMAP4_ISS_SUBCLK_ISP = (1 << 1), - OMAP4_ISS_SUBCLK_CSI2_A = (1 << 2), - OMAP4_ISS_SUBCLK_CSI2_B = (1 << 3), - OMAP4_ISS_SUBCLK_CCP2 = (1 << 4), -}; - -enum iss_isp_subclk_resource { - OMAP4_ISS_ISP_SUBCLK_BL = (1 << 0), - OMAP4_ISS_ISP_SUBCLK_ISIF = (1 << 1), - OMAP4_ISS_ISP_SUBCLK_H3A = (1 << 2), - OMAP4_ISS_ISP_SUBCLK_RSZ = (1 << 3), - OMAP4_ISS_ISP_SUBCLK_IPIPE = (1 << 4), - OMAP4_ISS_ISP_SUBCLK_IPIPEIF = (1 << 5), -}; - -/* - * struct iss_reg - Structure for ISS register values. - * @reg: 32-bit Register address. - * @val: 32-bit Register value. - */ -struct iss_reg { - enum iss_mem_resources mmio_range; - u32 reg; - u32 val; -}; - -/* - * struct iss_device - ISS device structure. - * @syscon: Regmap for the syscon register space - * @crashed: Crashed entities - */ -struct iss_device { - struct v4l2_device v4l2_dev; - struct media_device media_dev; - struct device *dev; - u32 revision; - - /* platform HW resources */ - struct iss_platform_data *pdata; - unsigned int irq_num; - - struct resource *res[OMAP4_ISS_MEM_LAST]; - void __iomem *regs[OMAP4_ISS_MEM_LAST]; - struct regmap *syscon; - - u64 raw_dmamask; - - struct mutex iss_mutex; /* For handling ref_count field */ - struct media_entity_enum crashed; - int has_context; - int ref_count; - - struct clk *iss_fck; - struct clk *iss_ctrlclk; - - /* ISS modules */ - struct iss_csi2_device csi2a; - struct iss_csi2_device csi2b; - struct iss_csiphy csiphy1; - struct iss_csiphy csiphy2; - struct iss_ipipeif_device ipipeif; - struct iss_ipipe_device ipipe; - struct iss_resizer_device resizer; - - unsigned int subclk_resources; - unsigned int isp_subclk_resources; -}; - -int omap4iss_get_external_info(struct iss_pipeline *pipe, - struct media_link *link); - -int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, - atomic_t *stopping); - -int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait, - atomic_t *stopping); - -int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe, - enum iss_pipeline_stream_state state); -void omap4iss_pipeline_cancel_stream(struct iss_pipeline *pipe); - -void omap4iss_configure_bridge(struct iss_device *iss, - enum ipipeif_input_entity input); - -struct iss_device *omap4iss_get(struct iss_device *iss); -void omap4iss_put(struct iss_device *iss); -int omap4iss_subclk_enable(struct iss_device *iss, - enum iss_subclk_resource res); -int omap4iss_subclk_disable(struct iss_device *iss, - enum iss_subclk_resource res); -void omap4iss_isp_subclk_enable(struct iss_device *iss, - enum iss_isp_subclk_resource res); -void omap4iss_isp_subclk_disable(struct iss_device *iss, - enum iss_isp_subclk_resource res); - -int omap4iss_register_entities(struct platform_device *pdev, - struct v4l2_device *v4l2_dev); -void omap4iss_unregister_entities(struct platform_device *pdev); - -/* - * iss_reg_read - Read the value of an OMAP4 ISS register - * @iss: the ISS device - * @res: memory resource in which the register is located - * @offset: register offset in the memory resource - * - * Return the register value. - */ -static inline -u32 iss_reg_read(struct iss_device *iss, enum iss_mem_resources res, - u32 offset) -{ - return readl(iss->regs[res] + offset); -} - -/* - * iss_reg_write - Write a value to an OMAP4 ISS register - * @iss: the ISS device - * @res: memory resource in which the register is located - * @offset: register offset in the memory resource - * @value: value to be written - */ -static inline -void iss_reg_write(struct iss_device *iss, enum iss_mem_resources res, - u32 offset, u32 value) -{ - writel(value, iss->regs[res] + offset); -} - -/* - * iss_reg_clr - Clear bits in an OMAP4 ISS register - * @iss: the ISS device - * @res: memory resource in which the register is located - * @offset: register offset in the memory resource - * @clr: bit mask to be cleared - */ -static inline -void iss_reg_clr(struct iss_device *iss, enum iss_mem_resources res, - u32 offset, u32 clr) -{ - u32 v = iss_reg_read(iss, res, offset); - - iss_reg_write(iss, res, offset, v & ~clr); -} - -/* - * iss_reg_set - Set bits in an OMAP4 ISS register - * @iss: the ISS device - * @res: memory resource in which the register is located - * @offset: register offset in the memory resource - * @set: bit mask to be set - */ -static inline -void iss_reg_set(struct iss_device *iss, enum iss_mem_resources res, - u32 offset, u32 set) -{ - u32 v = iss_reg_read(iss, res, offset); - - iss_reg_write(iss, res, offset, v | set); -} - -/* - * iss_reg_update - Clear and set bits in an OMAP4 ISS register - * @iss: the ISS device - * @res: memory resource in which the register is located - * @offset: register offset in the memory resource - * @clr: bit mask to be cleared - * @set: bit mask to be set - * - * Clear the clr mask first and then set the set mask. - */ -static inline -void iss_reg_update(struct iss_device *iss, enum iss_mem_resources res, - u32 offset, u32 clr, u32 set) -{ - u32 v = iss_reg_read(iss, res, offset); - - iss_reg_write(iss, res, offset, (v & ~clr) | set); -} - -#define iss_poll_condition_timeout(cond, timeout, min_ival, max_ival) \ -({ \ - unsigned long __timeout = jiffies + usecs_to_jiffies(timeout); \ - unsigned int __min_ival = (min_ival); \ - unsigned int __max_ival = (max_ival); \ - bool __cond; \ - while (!(__cond = (cond))) { \ - if (time_after(jiffies, __timeout)) \ - break; \ - usleep_range(__min_ival, __max_ival); \ - } \ - !__cond; \ -}) - -#endif /* _OMAP4_ISS_H_ */ diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c deleted file mode 100644 index 0e6c5bd81930c3..00000000000000 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ /dev/null @@ -1,1379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * TI OMAP4 ISS V4L2 Driver - CSI PHY module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#include -#include -#include -#include - -#include "iss.h" -#include "iss_regs.h" -#include "iss_csi2.h" - -/* - * csi2_if_enable - Enable CSI2 Receiver interface. - * @enable: enable flag - * - */ -static void csi2_if_enable(struct iss_csi2_device *csi2, u8 enable) -{ - struct iss_csi2_ctrl_cfg *currctrl = &csi2->ctrl; - - iss_reg_update(csi2->iss, csi2->regs1, CSI2_CTRL, CSI2_CTRL_IF_EN, - enable ? CSI2_CTRL_IF_EN : 0); - - currctrl->if_enable = enable; -} - -/* - * csi2_recv_config - CSI2 receiver module configuration. - * @currctrl: iss_csi2_ctrl_cfg structure - * - */ -static void csi2_recv_config(struct iss_csi2_device *csi2, - struct iss_csi2_ctrl_cfg *currctrl) -{ - u32 reg = 0; - - if (currctrl->frame_mode) - reg |= CSI2_CTRL_FRAME; - else - reg &= ~CSI2_CTRL_FRAME; - - if (currctrl->vp_clk_enable) - reg |= CSI2_CTRL_VP_CLK_EN; - else - reg &= ~CSI2_CTRL_VP_CLK_EN; - - if (currctrl->vp_only_enable) - reg |= CSI2_CTRL_VP_ONLY_EN; - else - reg &= ~CSI2_CTRL_VP_ONLY_EN; - - reg &= ~CSI2_CTRL_VP_OUT_CTRL_MASK; - reg |= currctrl->vp_out_ctrl << CSI2_CTRL_VP_OUT_CTRL_SHIFT; - - if (currctrl->ecc_enable) - reg |= CSI2_CTRL_ECC_EN; - else - reg &= ~CSI2_CTRL_ECC_EN; - - /* - * Set MFlag assertion boundaries to: - * Low: 4/8 of FIFO size - * High: 6/8 of FIFO size - */ - reg &= ~(CSI2_CTRL_MFLAG_LEVH_MASK | CSI2_CTRL_MFLAG_LEVL_MASK); - reg |= (2 << CSI2_CTRL_MFLAG_LEVH_SHIFT) | - (4 << CSI2_CTRL_MFLAG_LEVL_SHIFT); - - /* Generation of 16x64-bit bursts (Recommended) */ - reg |= CSI2_CTRL_BURST_SIZE_EXPAND; - - /* Do Non-Posted writes (Recommended) */ - reg |= CSI2_CTRL_NON_POSTED_WRITE; - - /* - * Enforce Little endian for all formats, including: - * YUV4:2:2 8-bit and YUV4:2:0 Legacy - */ - reg |= CSI2_CTRL_ENDIANNESS; - - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTRL, reg); -} - -static const unsigned int csi2_input_fmts[] = { - MEDIA_BUS_FMT_SGRBG10_1X10, - MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - MEDIA_BUS_FMT_SRGGB10_1X10, - MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, - MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, - MEDIA_BUS_FMT_SGBRG10_1X10, - MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, - MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_SGBRG8_1X8, - MEDIA_BUS_FMT_SGRBG8_1X8, - MEDIA_BUS_FMT_SRGGB8_1X8, - MEDIA_BUS_FMT_UYVY8_1X16, - MEDIA_BUS_FMT_YUYV8_1X16, -}; - -/* To set the format on the CSI2 requires a mapping function that takes - * the following inputs: - * - 3 different formats (at this time) - * - 2 destinations (mem, vp+mem) (vp only handled separately) - * - 2 decompression options (on, off) - * Output should be CSI2 frame format code - * Array indices as follows: [format][dest][decompr] - * Not all combinations are valid. 0 means invalid. - */ -static const u16 __csi2_fmt_map[][2][2] = { - /* RAW10 formats */ - { - /* Output to memory */ - { - /* No DPCM decompression */ - CSI2_PIX_FMT_RAW10_EXP16, - /* DPCM decompression */ - 0, - }, - /* Output to both */ - { - /* No DPCM decompression */ - CSI2_PIX_FMT_RAW10_EXP16_VP, - /* DPCM decompression */ - 0, - }, - }, - /* RAW10 DPCM8 formats */ - { - /* Output to memory */ - { - /* No DPCM decompression */ - CSI2_USERDEF_8BIT_DATA1, - /* DPCM decompression */ - CSI2_USERDEF_8BIT_DATA1_DPCM10, - }, - /* Output to both */ - { - /* No DPCM decompression */ - CSI2_PIX_FMT_RAW8_VP, - /* DPCM decompression */ - CSI2_USERDEF_8BIT_DATA1_DPCM10_VP, - }, - }, - /* RAW8 formats */ - { - /* Output to memory */ - { - /* No DPCM decompression */ - CSI2_PIX_FMT_RAW8, - /* DPCM decompression */ - 0, - }, - /* Output to both */ - { - /* No DPCM decompression */ - CSI2_PIX_FMT_RAW8_VP, - /* DPCM decompression */ - 0, - }, - }, - /* YUV422 formats */ - { - /* Output to memory */ - { - /* No DPCM decompression */ - CSI2_PIX_FMT_YUV422_8BIT, - /* DPCM decompression */ - 0, - }, - /* Output to both */ - { - /* No DPCM decompression */ - CSI2_PIX_FMT_YUV422_8BIT_VP16, - /* DPCM decompression */ - 0, - }, - }, -}; - -/* - * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID - * @csi2: ISS CSI2 device - * - * Returns CSI2 physical format id - */ -static u16 csi2_ctx_map_format(struct iss_csi2_device *csi2) -{ - const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK]; - int fmtidx, destidx; - - switch (fmt->code) { - case MEDIA_BUS_FMT_SGRBG10_1X10: - case MEDIA_BUS_FMT_SRGGB10_1X10: - case MEDIA_BUS_FMT_SBGGR10_1X10: - case MEDIA_BUS_FMT_SGBRG10_1X10: - fmtidx = 0; - break; - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: - case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: - fmtidx = 1; - break; - case MEDIA_BUS_FMT_SBGGR8_1X8: - case MEDIA_BUS_FMT_SGBRG8_1X8: - case MEDIA_BUS_FMT_SGRBG8_1X8: - case MEDIA_BUS_FMT_SRGGB8_1X8: - fmtidx = 2; - break; - case MEDIA_BUS_FMT_UYVY8_1X16: - case MEDIA_BUS_FMT_YUYV8_1X16: - fmtidx = 3; - break; - default: - WARN(1, "CSI2: pixel format %08x unsupported!\n", - fmt->code); - return 0; - } - - if (!(csi2->output & CSI2_OUTPUT_IPIPEIF) && - !(csi2->output & CSI2_OUTPUT_MEMORY)) { - /* Neither output enabled is a valid combination */ - return CSI2_PIX_FMT_OTHERS; - } - - /* If we need to skip frames at the beginning of the stream disable the - * video port to avoid sending the skipped frames to the IPIPEIF. - */ - destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_IPIPEIF); - - return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress]; -} - -/* - * csi2_set_outaddr - Set memory address to save output image - * @csi2: Pointer to ISS CSI2a device. - * @addr: 32-bit memory address aligned on 32 byte boundary. - * - * Sets the memory address where the output will be saved. - * - * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte - * boundary. - */ -static void csi2_set_outaddr(struct iss_csi2_device *csi2, u32 addr) -{ - struct iss_csi2_ctx_cfg *ctx = &csi2->contexts[0]; - - ctx->ping_addr = addr; - ctx->pong_addr = addr; - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PING_ADDR(ctx->ctxnum), - ctx->ping_addr); - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PONG_ADDR(ctx->ctxnum), - ctx->pong_addr); -} - -/* - * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should - * be enabled by CSI2. - * @format_id: mapped format id - * - */ -static inline int is_usr_def_mapping(u32 format_id) -{ - return (format_id & 0xf0) == 0x40 ? 1 : 0; -} - -/* - * csi2_ctx_enable - Enable specified CSI2 context - * @ctxnum: Context number, valid between 0 and 7 values. - * @enable: enable - * - */ -static void csi2_ctx_enable(struct iss_csi2_device *csi2, u8 ctxnum, u8 enable) -{ - struct iss_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum]; - u32 reg; - - reg = iss_reg_read(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctxnum)); - - if (enable) { - unsigned int skip = 0; - - if (csi2->frame_skip) - skip = csi2->frame_skip; - else if (csi2->output & CSI2_OUTPUT_MEMORY) - skip = 1; - - reg &= ~CSI2_CTX_CTRL1_COUNT_MASK; - reg |= CSI2_CTX_CTRL1_COUNT_UNLOCK - | (skip << CSI2_CTX_CTRL1_COUNT_SHIFT) - | CSI2_CTX_CTRL1_CTX_EN; - } else { - reg &= ~CSI2_CTX_CTRL1_CTX_EN; - } - - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctxnum), reg); - ctx->enabled = enable; -} - -/* - * csi2_ctx_config - CSI2 context configuration. - * @ctx: context configuration - * - */ -static void csi2_ctx_config(struct iss_csi2_device *csi2, - struct iss_csi2_ctx_cfg *ctx) -{ - u32 reg = 0; - - ctx->frame = 0; - - /* Set up CSI2_CTx_CTRL1 */ - if (ctx->eof_enabled) - reg = CSI2_CTX_CTRL1_EOF_EN; - - if (ctx->eol_enabled) - reg |= CSI2_CTX_CTRL1_EOL_EN; - - if (ctx->checksum_enabled) - reg |= CSI2_CTX_CTRL1_CS_EN; - - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctx->ctxnum), reg); - - /* Set up CSI2_CTx_CTRL2 */ - reg = ctx->virtual_id << CSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; - reg |= ctx->format_id << CSI2_CTX_CTRL2_FORMAT_SHIFT; - - if (ctx->dpcm_decompress && ctx->dpcm_predictor) - reg |= CSI2_CTX_CTRL2_DPCM_PRED; - - if (is_usr_def_mapping(ctx->format_id)) - reg |= 2 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT; - - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL2(ctx->ctxnum), reg); - - /* Set up CSI2_CTx_CTRL3 */ - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL3(ctx->ctxnum), - ctx->alpha << CSI2_CTX_CTRL3_ALPHA_SHIFT); - - /* Set up CSI2_CTx_DAT_OFST */ - iss_reg_update(csi2->iss, csi2->regs1, CSI2_CTX_DAT_OFST(ctx->ctxnum), - CSI2_CTX_DAT_OFST_MASK, ctx->data_offset); - - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PING_ADDR(ctx->ctxnum), - ctx->ping_addr); - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PONG_ADDR(ctx->ctxnum), - ctx->pong_addr); -} - -/* - * csi2_timing_config - CSI2 timing configuration. - * @timing: csi2_timing_cfg structure - */ -static void csi2_timing_config(struct iss_csi2_device *csi2, - struct iss_csi2_timing_cfg *timing) -{ - u32 reg; - - reg = iss_reg_read(csi2->iss, csi2->regs1, CSI2_TIMING); - - if (timing->force_rx_mode) - reg |= CSI2_TIMING_FORCE_RX_MODE_IO1; - else - reg &= ~CSI2_TIMING_FORCE_RX_MODE_IO1; - - if (timing->stop_state_16x) - reg |= CSI2_TIMING_STOP_STATE_X16_IO1; - else - reg &= ~CSI2_TIMING_STOP_STATE_X16_IO1; - - if (timing->stop_state_4x) - reg |= CSI2_TIMING_STOP_STATE_X4_IO1; - else - reg &= ~CSI2_TIMING_STOP_STATE_X4_IO1; - - reg &= ~CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK; - reg |= timing->stop_state_counter << - CSI2_TIMING_STOP_STATE_COUNTER_IO1_SHIFT; - - iss_reg_write(csi2->iss, csi2->regs1, CSI2_TIMING, reg); -} - -/* - * csi2_irq_ctx_set - Enables CSI2 Context IRQs. - * @enable: Enable/disable CSI2 Context interrupts - */ -static void csi2_irq_ctx_set(struct iss_csi2_device *csi2, int enable) -{ - const u32 mask = CSI2_CTX_IRQ_FE | CSI2_CTX_IRQ_FS; - int i; - - for (i = 0; i < 8; i++) { - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(i), - mask); - if (enable) - iss_reg_set(csi2->iss, csi2->regs1, - CSI2_CTX_IRQENABLE(i), mask); - else - iss_reg_clr(csi2->iss, csi2->regs1, - CSI2_CTX_IRQENABLE(i), mask); - } -} - -/* - * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs. - * @enable: Enable/disable CSI2 ComplexIO #1 interrupts - */ -static void csi2_irq_complexio1_set(struct iss_csi2_device *csi2, int enable) -{ - u32 reg; - - reg = CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT | - CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER | - CSI2_COMPLEXIO_IRQ_STATEULPM5 | - CSI2_COMPLEXIO_IRQ_ERRCONTROL5 | - CSI2_COMPLEXIO_IRQ_ERRESC5 | - CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5 | - CSI2_COMPLEXIO_IRQ_ERRSOTHS5 | - CSI2_COMPLEXIO_IRQ_STATEULPM4 | - CSI2_COMPLEXIO_IRQ_ERRCONTROL4 | - CSI2_COMPLEXIO_IRQ_ERRESC4 | - CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4 | - CSI2_COMPLEXIO_IRQ_ERRSOTHS4 | - CSI2_COMPLEXIO_IRQ_STATEULPM3 | - CSI2_COMPLEXIO_IRQ_ERRCONTROL3 | - CSI2_COMPLEXIO_IRQ_ERRESC3 | - CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3 | - CSI2_COMPLEXIO_IRQ_ERRSOTHS3 | - CSI2_COMPLEXIO_IRQ_STATEULPM2 | - CSI2_COMPLEXIO_IRQ_ERRCONTROL2 | - CSI2_COMPLEXIO_IRQ_ERRESC2 | - CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2 | - CSI2_COMPLEXIO_IRQ_ERRSOTHS2 | - CSI2_COMPLEXIO_IRQ_STATEULPM1 | - CSI2_COMPLEXIO_IRQ_ERRCONTROL1 | - CSI2_COMPLEXIO_IRQ_ERRESC1 | - CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1 | - CSI2_COMPLEXIO_IRQ_ERRSOTHS1; - iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQSTATUS, reg); - if (enable) - iss_reg_set(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQENABLE, - reg); - else - iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQENABLE, - 0); -} - -/* - * csi2_irq_status_set - Enables CSI2 Status IRQs. - * @enable: Enable/disable CSI2 Status interrupts - */ -static void csi2_irq_status_set(struct iss_csi2_device *csi2, int enable) -{ - u32 reg; - - reg = CSI2_IRQ_OCP_ERR | - CSI2_IRQ_SHORT_PACKET | - CSI2_IRQ_ECC_CORRECTION | - CSI2_IRQ_ECC_NO_CORRECTION | - CSI2_IRQ_COMPLEXIO_ERR | - CSI2_IRQ_FIFO_OVF | - CSI2_IRQ_CONTEXT0; - iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQSTATUS, reg); - if (enable) - iss_reg_set(csi2->iss, csi2->regs1, CSI2_IRQENABLE, reg); - else - iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQENABLE, 0); -} - -/* - * omap4iss_csi2_reset - Resets the CSI2 module. - * - * Must be called with the phy lock held. - * - * Returns 0 if successful, or -EBUSY if power command didn't respond. - */ -int omap4iss_csi2_reset(struct iss_csi2_device *csi2) -{ - unsigned int timeout; - - if (!csi2->available) - return -ENODEV; - - if (csi2->phy->phy_in_use) - return -EBUSY; - - iss_reg_set(csi2->iss, csi2->regs1, CSI2_SYSCONFIG, - CSI2_SYSCONFIG_SOFT_RESET); - - timeout = iss_poll_condition_timeout( - iss_reg_read(csi2->iss, csi2->regs1, CSI2_SYSSTATUS) & - CSI2_SYSSTATUS_RESET_DONE, 500, 100, 200); - if (timeout) { - dev_err(csi2->iss->dev, "CSI2: Soft reset timeout!\n"); - return -EBUSY; - } - - iss_reg_set(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_CFG, - CSI2_COMPLEXIO_CFG_RESET_CTRL); - - timeout = iss_poll_condition_timeout( - iss_reg_read(csi2->iss, csi2->phy->phy_regs, REGISTER1) & - REGISTER1_RESET_DONE_CTRLCLK, 10000, 100, 500); - if (timeout) { - dev_err(csi2->iss->dev, "CSI2: CSI2_96M_FCLK reset timeout!\n"); - return -EBUSY; - } - - iss_reg_update(csi2->iss, csi2->regs1, CSI2_SYSCONFIG, - CSI2_SYSCONFIG_MSTANDBY_MODE_MASK | - CSI2_SYSCONFIG_AUTO_IDLE, - CSI2_SYSCONFIG_MSTANDBY_MODE_NO); - - return 0; -} - -static int csi2_configure(struct iss_csi2_device *csi2) -{ - const struct iss_v4l2_subdevs_group *pdata; - struct iss_csi2_timing_cfg *timing = &csi2->timing[0]; - struct v4l2_subdev *sensor; - struct media_pad *pad; - - /* - * CSI2 fields that can be updated while the context has - * been enabled or the interface has been enabled are not - * updated dynamically currently. So we do not allow to - * reconfigure if either has been enabled - */ - if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) - return -EBUSY; - - pad = media_pad_remote_pad_first(&csi2->pads[CSI2_PAD_SINK]); - sensor = media_entity_to_v4l2_subdev(pad->entity); - pdata = sensor->host_priv; - - csi2->frame_skip = 0; - v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); - - csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div; - csi2->ctrl.frame_mode = ISS_CSI2_FRAME_IMMEDIATE; - csi2->ctrl.ecc_enable = pdata->bus.csi2.crc; - - timing->force_rx_mode = 1; - timing->stop_state_16x = 1; - timing->stop_state_4x = 1; - timing->stop_state_counter = 0x1ff; - - /* - * The CSI2 receiver can't do any format conversion except DPCM - * decompression, so every set_format call configures both pads - * and enables DPCM decompression as a special case: - */ - if (csi2->formats[CSI2_PAD_SINK].code != - csi2->formats[CSI2_PAD_SOURCE].code) - csi2->dpcm_decompress = true; - else - csi2->dpcm_decompress = false; - - csi2->contexts[0].format_id = csi2_ctx_map_format(csi2); - - if (csi2->video_out.bpl_padding == 0) - csi2->contexts[0].data_offset = 0; - else - csi2->contexts[0].data_offset = csi2->video_out.bpl_value; - - /* - * Enable end of frame and end of line signals generation for - * context 0. These signals are generated from CSI2 receiver to - * qualify the last pixel of a frame and the last pixel of a line. - * Without enabling the signals CSI2 receiver writes data to memory - * beyond buffer size and/or data line offset is not handled correctly. - */ - csi2->contexts[0].eof_enabled = 1; - csi2->contexts[0].eol_enabled = 1; - - csi2_irq_complexio1_set(csi2, 1); - csi2_irq_ctx_set(csi2, 1); - csi2_irq_status_set(csi2, 1); - - /* Set configuration (timings, format and links) */ - csi2_timing_config(csi2, timing); - csi2_recv_config(csi2, &csi2->ctrl); - csi2_ctx_config(csi2, &csi2->contexts[0]); - - return 0; -} - -/* - * csi2_print_status - Prints CSI2 debug information. - */ -#define CSI2_PRINT_REGISTER(iss, regs, name)\ - dev_dbg(iss->dev, "###CSI2 " #name "=0x%08x\n", \ - iss_reg_read(iss, regs, CSI2_##name)) - -static void csi2_print_status(struct iss_csi2_device *csi2) -{ - struct iss_device *iss = csi2->iss; - - if (!csi2->available) - return; - - dev_dbg(iss->dev, "-------------CSI2 Register dump-------------\n"); - - CSI2_PRINT_REGISTER(iss, csi2->regs1, SYSCONFIG); - CSI2_PRINT_REGISTER(iss, csi2->regs1, SYSSTATUS); - CSI2_PRINT_REGISTER(iss, csi2->regs1, IRQENABLE); - CSI2_PRINT_REGISTER(iss, csi2->regs1, IRQSTATUS); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTRL); - CSI2_PRINT_REGISTER(iss, csi2->regs1, DBG_H); - CSI2_PRINT_REGISTER(iss, csi2->regs1, COMPLEXIO_CFG); - CSI2_PRINT_REGISTER(iss, csi2->regs1, COMPLEXIO_IRQSTATUS); - CSI2_PRINT_REGISTER(iss, csi2->regs1, SHORT_PACKET); - CSI2_PRINT_REGISTER(iss, csi2->regs1, COMPLEXIO_IRQENABLE); - CSI2_PRINT_REGISTER(iss, csi2->regs1, DBG_P); - CSI2_PRINT_REGISTER(iss, csi2->regs1, TIMING); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_CTRL1(0)); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_CTRL2(0)); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_DAT_OFST(0)); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_PING_ADDR(0)); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_PONG_ADDR(0)); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_IRQENABLE(0)); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_IRQSTATUS(0)); - CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_CTRL3(0)); - - dev_dbg(iss->dev, "--------------------------------------------\n"); -} - -/* ----------------------------------------------------------------------------- - * Interrupt handling - */ - -/* - * csi2_isr_buffer - Does buffer handling at end-of-frame - * when writing to memory. - */ -static void csi2_isr_buffer(struct iss_csi2_device *csi2) -{ - struct iss_buffer *buffer; - - csi2_ctx_enable(csi2, 0, 0); - - buffer = omap4iss_video_buffer_next(&csi2->video_out); - - /* - * Let video queue operation restart engine if there is an underrun - * condition. - */ - if (!buffer) - return; - - csi2_set_outaddr(csi2, buffer->iss_addr); - csi2_ctx_enable(csi2, 0, 1); -} - -static void csi2_isr_ctx(struct iss_csi2_device *csi2, - struct iss_csi2_ctx_cfg *ctx) -{ - unsigned int n = ctx->ctxnum; - u32 status; - - status = iss_reg_read(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n)); - iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n), status); - - if (omap4iss_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) - return; - - /* Propagate frame number */ - if (status & CSI2_CTX_IRQ_FS) { - struct iss_pipeline *pipe = - to_iss_pipeline(&csi2->subdev.entity); - u16 frame; - u16 delta; - - frame = iss_reg_read(csi2->iss, csi2->regs1, - CSI2_CTX_CTRL2(ctx->ctxnum)) - >> CSI2_CTX_CTRL2_FRAME_SHIFT; - - if (frame == 0) { - /* A zero value means that the counter isn't implemented - * by the source. Increment the frame number in software - * in that case. - */ - atomic_inc(&pipe->frame_number); - } else { - /* Extend the 16 bit frame number to 32 bits by - * computing the delta between two consecutive CSI2 - * frame numbers and adding it to the software frame - * number. The hardware counter starts at 1 and wraps - * from 0xffff to 1 without going through 0, so subtract - * 1 when the counter wraps. - */ - delta = frame - ctx->frame; - if (frame < ctx->frame) - delta--; - ctx->frame = frame; - - atomic_add(delta, &pipe->frame_number); - } - } - - if (!(status & CSI2_CTX_IRQ_FE)) - return; - - /* Skip interrupts until we reach the frame skip count. The CSI2 will be - * automatically disabled, as the frame skip count has been programmed - * in the CSI2_CTx_CTRL1::COUNT field, so re-enable it. - * - * It would have been nice to rely on the FRAME_NUMBER interrupt instead - * but it turned out that the interrupt is only generated when the CSI2 - * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased - * correctly and reaches 0 when data is forwarded to the video port only - * but no interrupt arrives). Maybe a CSI2 hardware bug. - */ - if (csi2->frame_skip) { - csi2->frame_skip--; - if (csi2->frame_skip == 0) { - ctx->format_id = csi2_ctx_map_format(csi2); - csi2_ctx_config(csi2, ctx); - csi2_ctx_enable(csi2, n, 1); - } - return; - } - - if (csi2->output & CSI2_OUTPUT_MEMORY) - csi2_isr_buffer(csi2); -} - -/* - * omap4iss_csi2_isr - CSI2 interrupt handling. - */ -void omap4iss_csi2_isr(struct iss_csi2_device *csi2) -{ - struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); - u32 csi2_irqstatus, cpxio1_irqstatus; - struct iss_device *iss = csi2->iss; - - if (!csi2->available) - return; - - csi2_irqstatus = iss_reg_read(csi2->iss, csi2->regs1, CSI2_IRQSTATUS); - iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQSTATUS, csi2_irqstatus); - - /* Failure Cases */ - if (csi2_irqstatus & CSI2_IRQ_COMPLEXIO_ERR) { - cpxio1_irqstatus = iss_reg_read(csi2->iss, csi2->regs1, - CSI2_COMPLEXIO_IRQSTATUS); - iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQSTATUS, - cpxio1_irqstatus); - dev_dbg(iss->dev, "CSI2: ComplexIO Error IRQ %x\n", - cpxio1_irqstatus); - pipe->error = true; - } - - if (csi2_irqstatus & (CSI2_IRQ_OCP_ERR | - CSI2_IRQ_SHORT_PACKET | - CSI2_IRQ_ECC_NO_CORRECTION | - CSI2_IRQ_COMPLEXIO_ERR | - CSI2_IRQ_FIFO_OVF)) { - dev_dbg(iss->dev, - "CSI2 Err: OCP:%d SHORT:%d ECC:%d CPXIO:%d OVF:%d\n", - csi2_irqstatus & CSI2_IRQ_OCP_ERR ? 1 : 0, - csi2_irqstatus & CSI2_IRQ_SHORT_PACKET ? 1 : 0, - csi2_irqstatus & CSI2_IRQ_ECC_NO_CORRECTION ? 1 : 0, - csi2_irqstatus & CSI2_IRQ_COMPLEXIO_ERR ? 1 : 0, - csi2_irqstatus & CSI2_IRQ_FIFO_OVF ? 1 : 0); - pipe->error = true; - } - - /* Successful cases */ - if (csi2_irqstatus & CSI2_IRQ_CONTEXT0) - csi2_isr_ctx(csi2, &csi2->contexts[0]); - - if (csi2_irqstatus & CSI2_IRQ_ECC_CORRECTION) - dev_dbg(iss->dev, "CSI2: ECC correction done\n"); -} - -/* ----------------------------------------------------------------------------- - * ISS video operations - */ - -/* - * csi2_queue - Queues the first buffer when using memory output - * @video: The video node - * @buffer: buffer to queue - */ -static int csi2_queue(struct iss_video *video, struct iss_buffer *buffer) -{ - struct iss_csi2_device *csi2 = container_of(video, - struct iss_csi2_device, video_out); - - csi2_set_outaddr(csi2, buffer->iss_addr); - - /* - * If streaming was enabled before there was a buffer queued - * or underrun happened in the ISR, the hardware was not enabled - * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set. - * Enable it now. - */ - if (csi2->video_out.dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { - /* Enable / disable context 0 and IRQs */ - csi2_if_enable(csi2, 1); - csi2_ctx_enable(csi2, 0, 1); - iss_video_dmaqueue_flags_clr(&csi2->video_out); - } - - return 0; -} - -static const struct iss_video_operations csi2_issvideo_ops = { - .queue = csi2_queue, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -static struct v4l2_mbus_framefmt * -__csi2_get_format(struct iss_csi2_device *csi2, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_state_get_format(sd_state, pad); - - return &csi2->formats[pad]; -} - -static void -csi2_try_format(struct iss_csi2_device *csi2, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - u32 pixelcode; - struct v4l2_mbus_framefmt *format; - const struct iss_format_info *info; - unsigned int i; - - switch (pad) { - case CSI2_PAD_SINK: - /* Clamp the width and height to valid range (1-8191). */ - for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) { - if (fmt->code == csi2_input_fmts[i]) - break; - } - - /* If not found, use SGRBG10 as default */ - if (i >= ARRAY_SIZE(csi2_input_fmts)) - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - - fmt->width = clamp_t(u32, fmt->width, 1, 8191); - fmt->height = clamp_t(u32, fmt->height, 1, 8191); - break; - - case CSI2_PAD_SOURCE: - /* Source format same as sink format, except for DPCM - * compression. - */ - pixelcode = fmt->code; - format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK, - which); - memcpy(fmt, format, sizeof(*fmt)); - - /* - * Only Allow DPCM decompression, and check that the - * pattern is preserved - */ - info = omap4iss_video_format_info(fmt->code); - if (info->uncompressed == pixelcode) - fmt->code = pixelcode; - break; - } - - /* RGB, non-interlaced */ - fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->field = V4L2_FIELD_NONE; -} - -/* - * csi2_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @sd_state: V4L2 subdev state - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int csi2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - const struct iss_format_info *info; - - if (code->pad == CSI2_PAD_SINK) { - if (code->index >= ARRAY_SIZE(csi2_input_fmts)) - return -EINVAL; - - code->code = csi2_input_fmts[code->index]; - } else { - format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SINK, - code->which); - switch (code->index) { - case 0: - /* Passthrough sink pad code */ - code->code = format->code; - break; - case 1: - /* Uncompressed code */ - info = omap4iss_video_format_info(format->code); - if (info->uncompressed == format->code) - return -EINVAL; - - code->code = info->uncompressed; - break; - default: - return -EINVAL; - } - } - - return 0; -} - -static int csi2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - csi2_try_format(csi2, sd_state, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * csi2_get_format - Handle get format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @sd_state: V4L2 subdev state - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int csi2_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * csi2_set_format - Handle set format by pads subdev method - * @sd : pointer to v4l2 subdev structure - * @sd_state: V4L2 subdev state - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int csi2_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __csi2_get_format(csi2, sd_state, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - csi2_try_format(csi2, sd_state, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - /* Propagate the format from sink to source */ - if (fmt->pad == CSI2_PAD_SINK) { - format = __csi2_get_format(csi2, sd_state, CSI2_PAD_SOURCE, - fmt->which); - *format = fmt->format; - csi2_try_format(csi2, sd_state, CSI2_PAD_SOURCE, format, - fmt->which); - } - - return 0; -} - -static int csi2_link_validate(struct v4l2_subdev *sd, struct media_link *link, - struct v4l2_subdev_format *source_fmt, - struct v4l2_subdev_format *sink_fmt) -{ - struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity); - int rval; - - pipe->external = media_entity_to_v4l2_subdev(link->source->entity); - rval = omap4iss_get_external_info(pipe, link); - if (rval < 0) - return rval; - - return v4l2_subdev_link_validate_default(sd, link, source_fmt, - sink_fmt); -} - -/* - * csi2_init_formats - Initialize formats on all pads - * @sd: ISS CSI2 V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = CSI2_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - format.format.width = 4096; - format.format.height = 4096; - csi2_set_format(sd, fh ? fh->state : NULL, &format); - - return 0; -} - -/* - * csi2_set_stream - Enable/Disable streaming on the CSI2 module - * @sd: ISS CSI2 V4L2 subdevice - * @enable: ISS pipeline stream state - * - * Return 0 on success or a negative error code otherwise. - */ -static int csi2_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct iss_device *iss = csi2->iss; - struct iss_video *video_out = &csi2->video_out; - int ret = 0; - - if (csi2->state == ISS_PIPELINE_STREAM_STOPPED) { - if (enable == ISS_PIPELINE_STREAM_STOPPED) - return 0; - - omap4iss_subclk_enable(iss, csi2->subclk); - } - - switch (enable) { - case ISS_PIPELINE_STREAM_CONTINUOUS: { - ret = omap4iss_csiphy_config(iss, sd); - if (ret < 0) - return ret; - - if (omap4iss_csiphy_acquire(csi2->phy) < 0) - return -ENODEV; - csi2_configure(csi2); - csi2_print_status(csi2); - - /* - * When outputting to memory with no buffer available, let the - * buffer queue handler start the hardware. A DMA queue flag - * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is - * a buffer available. - */ - if (csi2->output & CSI2_OUTPUT_MEMORY && - !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED)) - break; - /* Enable context 0 and IRQs */ - atomic_set(&csi2->stopping, 0); - csi2_ctx_enable(csi2, 0, 1); - csi2_if_enable(csi2, 1); - iss_video_dmaqueue_flags_clr(video_out); - break; - } - case ISS_PIPELINE_STREAM_STOPPED: - if (csi2->state == ISS_PIPELINE_STREAM_STOPPED) - return 0; - if (omap4iss_module_sync_idle(&sd->entity, &csi2->wait, - &csi2->stopping)) - ret = -ETIMEDOUT; - csi2_ctx_enable(csi2, 0, 0); - csi2_if_enable(csi2, 0); - csi2_irq_ctx_set(csi2, 0); - omap4iss_csiphy_release(csi2->phy); - omap4iss_subclk_disable(iss, csi2->subclk); - iss_video_dmaqueue_flags_clr(video_out); - break; - } - - csi2->state = enable; - return ret; -} - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops csi2_video_ops = { - .s_stream = csi2_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops csi2_pad_ops = { - .enum_mbus_code = csi2_enum_mbus_code, - .enum_frame_size = csi2_enum_frame_size, - .get_fmt = csi2_get_format, - .set_fmt = csi2_set_format, - .link_validate = csi2_link_validate, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops csi2_ops = { - .video = &csi2_video_ops, - .pad = &csi2_pad_ops, -}; - -/* subdev internal operations */ -static const struct v4l2_subdev_internal_ops csi2_internal_ops = { - .open = csi2_init_formats, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * csi2_link_setup - Setup CSI2 connections. - * @entity : Pointer to media entity structure - * @local : Pointer to local pad array - * @remote : Pointer to remote pad array - * @flags : Link flags - * return -EINVAL or zero on success - */ -static int csi2_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); - struct iss_csi2_ctrl_cfg *ctrl = &csi2->ctrl; - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - /* - * The ISS core doesn't support pipelines with multiple video outputs. - * Revisit this when it will be implemented, and return -EBUSY for now. - */ - - switch (index) { - case CSI2_PAD_SOURCE: - if (flags & MEDIA_LNK_FL_ENABLED) { - if (csi2->output & ~CSI2_OUTPUT_MEMORY) - return -EBUSY; - csi2->output |= CSI2_OUTPUT_MEMORY; - } else { - csi2->output &= ~CSI2_OUTPUT_MEMORY; - } - break; - - case CSI2_PAD_SOURCE | 2 << 16: - if (flags & MEDIA_LNK_FL_ENABLED) { - if (csi2->output & ~CSI2_OUTPUT_IPIPEIF) - return -EBUSY; - csi2->output |= CSI2_OUTPUT_IPIPEIF; - } else { - csi2->output &= ~CSI2_OUTPUT_IPIPEIF; - } - break; - - default: - /* Link from camera to CSI2 is fixed... */ - return -EINVAL; - } - - ctrl->vp_only_enable = csi2->output & CSI2_OUTPUT_MEMORY ? false : true; - ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_IPIPEIF); - - return 0; -} - -/* media operations */ -static const struct media_entity_operations csi2_media_ops = { - .link_setup = csi2_link_setup, - .link_validate = v4l2_subdev_link_validate, -}; - -void omap4iss_csi2_unregister_entities(struct iss_csi2_device *csi2) -{ - v4l2_device_unregister_subdev(&csi2->subdev); - omap4iss_video_unregister(&csi2->video_out); -} - -int omap4iss_csi2_register_entities(struct iss_csi2_device *csi2, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video nodes. */ - ret = v4l2_device_register_subdev(vdev, &csi2->subdev); - if (ret < 0) - goto error; - - ret = omap4iss_video_register(&csi2->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap4iss_csi2_unregister_entities(csi2); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISS CSI2 initialisation and cleanup - */ - -/* - * csi2_init_entities - Initialize subdev and media entity. - * @csi2: Pointer to csi2 structure. - * return -ENOMEM or zero on success - */ -static int csi2_init_entities(struct iss_csi2_device *csi2, const char *subname) -{ - struct v4l2_subdev *sd = &csi2->subdev; - struct media_pad *pads = csi2->pads; - struct media_entity *me = &sd->entity; - int ret; - char name[32]; - - v4l2_subdev_init(sd, &csi2_ops); - sd->internal_ops = &csi2_internal_ops; - snprintf(name, sizeof(name), "CSI2%s", subname); - snprintf(sd->name, sizeof(sd->name), "OMAP4 ISS %s", name); - - sd->grp_id = BIT(16); /* group ID for iss subdevs */ - v4l2_set_subdevdata(sd, csi2); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - - me->ops = &csi2_media_ops; - ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads); - if (ret < 0) - return ret; - - csi2_init_formats(sd, NULL); - - /* Video device node */ - csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - csi2->video_out.ops = &csi2_issvideo_ops; - csi2->video_out.bpl_alignment = 32; - csi2->video_out.bpl_zero_padding = 1; - csi2->video_out.bpl_max = 0x1ffe0; - csi2->video_out.iss = csi2->iss; - csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; - - ret = omap4iss_video_init(&csi2->video_out, name); - if (ret < 0) - goto error_video; - - return 0; - -error_video: - media_entity_cleanup(&csi2->subdev.entity); - return ret; -} - -/* - * omap4iss_csi2_init - Routine for module driver init - */ -int omap4iss_csi2_init(struct iss_device *iss) -{ - struct iss_csi2_device *csi2a = &iss->csi2a; - struct iss_csi2_device *csi2b = &iss->csi2b; - int ret; - - csi2a->iss = iss; - csi2a->available = 1; - csi2a->regs1 = OMAP4_ISS_MEM_CSI2_A_REGS1; - csi2a->phy = &iss->csiphy1; - csi2a->subclk = OMAP4_ISS_SUBCLK_CSI2_A; - csi2a->state = ISS_PIPELINE_STREAM_STOPPED; - init_waitqueue_head(&csi2a->wait); - - ret = csi2_init_entities(csi2a, "a"); - if (ret < 0) - return ret; - - csi2b->iss = iss; - csi2b->available = 1; - csi2b->regs1 = OMAP4_ISS_MEM_CSI2_B_REGS1; - csi2b->phy = &iss->csiphy2; - csi2b->subclk = OMAP4_ISS_SUBCLK_CSI2_B; - csi2b->state = ISS_PIPELINE_STREAM_STOPPED; - init_waitqueue_head(&csi2b->wait); - - ret = csi2_init_entities(csi2b, "b"); - if (ret < 0) - return ret; - - return 0; -} - -/* - * omap4iss_csi2_create_links() - CSI2 pads links creation - * @iss: Pointer to ISS device - * - * return negative error code or zero on success - */ -int omap4iss_csi2_create_links(struct iss_device *iss) -{ - struct iss_csi2_device *csi2a = &iss->csi2a; - struct iss_csi2_device *csi2b = &iss->csi2b; - int ret; - - /* Connect the CSI2a subdev to the video node. */ - ret = media_create_pad_link(&csi2a->subdev.entity, CSI2_PAD_SOURCE, - &csi2a->video_out.video.entity, 0, 0); - if (ret < 0) - return ret; - - /* Connect the CSI2b subdev to the video node. */ - ret = media_create_pad_link(&csi2b->subdev.entity, CSI2_PAD_SOURCE, - &csi2b->video_out.video.entity, 0, 0); - if (ret < 0) - return ret; - - return 0; -} - -/* - * omap4iss_csi2_cleanup - Routine for module driver cleanup - */ -void omap4iss_csi2_cleanup(struct iss_device *iss) -{ - struct iss_csi2_device *csi2a = &iss->csi2a; - struct iss_csi2_device *csi2b = &iss->csi2b; - - omap4iss_video_cleanup(&csi2a->video_out); - media_entity_cleanup(&csi2a->subdev.entity); - - omap4iss_video_cleanup(&csi2b->video_out); - media_entity_cleanup(&csi2b->subdev.entity); -} diff --git a/drivers/staging/media/omap4iss/iss_csi2.h b/drivers/staging/media/omap4iss/iss_csi2.h deleted file mode 100644 index 3f7fd9cff41d9a..00000000000000 --- a/drivers/staging/media/omap4iss/iss_csi2.h +++ /dev/null @@ -1,155 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * TI OMAP4 ISS V4L2 Driver - CSI2 module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#ifndef OMAP4_ISS_CSI2_H -#define OMAP4_ISS_CSI2_H - -#include -#include - -#include "iss_video.h" - -struct iss_csiphy; - -/* This is not an exhaustive list */ -enum iss_csi2_pix_formats { - CSI2_PIX_FMT_OTHERS = 0, - CSI2_PIX_FMT_YUV422_8BIT = 0x1e, - CSI2_PIX_FMT_YUV422_8BIT_VP = 0x9e, - CSI2_PIX_FMT_YUV422_8BIT_VP16 = 0xde, - CSI2_PIX_FMT_RAW10_EXP16 = 0xab, - CSI2_PIX_FMT_RAW10_EXP16_VP = 0x12f, - CSI2_PIX_FMT_RAW8 = 0x2a, - CSI2_PIX_FMT_RAW8_DPCM10_EXP16 = 0x2aa, - CSI2_PIX_FMT_RAW8_DPCM10_VP = 0x32a, - CSI2_PIX_FMT_RAW8_VP = 0x12a, - CSI2_USERDEF_8BIT_DATA1_DPCM10_VP = 0x340, - CSI2_USERDEF_8BIT_DATA1_DPCM10 = 0x2c0, - CSI2_USERDEF_8BIT_DATA1 = 0x40, -}; - -enum iss_csi2_irqevents { - OCP_ERR_IRQ = 0x4000, - SHORT_PACKET_IRQ = 0x2000, - ECC_CORRECTION_IRQ = 0x1000, - ECC_NO_CORRECTION_IRQ = 0x800, - COMPLEXIO2_ERR_IRQ = 0x400, - COMPLEXIO1_ERR_IRQ = 0x200, - FIFO_OVF_IRQ = 0x100, - CONTEXT7 = 0x80, - CONTEXT6 = 0x40, - CONTEXT5 = 0x20, - CONTEXT4 = 0x10, - CONTEXT3 = 0x8, - CONTEXT2 = 0x4, - CONTEXT1 = 0x2, - CONTEXT0 = 0x1, -}; - -enum iss_csi2_ctx_irqevents { - CTX_ECC_CORRECTION = 0x100, - CTX_LINE_NUMBER = 0x80, - CTX_FRAME_NUMBER = 0x40, - CTX_CS = 0x20, - CTX_LE = 0x8, - CTX_LS = 0x4, - CTX_FE = 0x2, - CTX_FS = 0x1, -}; - -enum iss_csi2_frame_mode { - ISS_CSI2_FRAME_IMMEDIATE, - ISS_CSI2_FRAME_AFTERFEC, -}; - -#define ISS_CSI2_MAX_CTX_NUM 7 - -struct iss_csi2_ctx_cfg { - u8 ctxnum; /* context number 0 - 7 */ - u8 dpcm_decompress; - - /* Fields in CSI2_CTx_CTRL2 - locked by CSI2_CTx_CTRL1.CTX_EN */ - u8 virtual_id; - u16 format_id; /* as in CSI2_CTx_CTRL2[9:0] */ - u8 dpcm_predictor; /* 1: simple, 0: advanced */ - u16 frame; - - /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */ - u16 alpha; - u16 data_offset; - u32 ping_addr; - u32 pong_addr; - u8 eof_enabled; - u8 eol_enabled; - u8 checksum_enabled; - u8 enabled; -}; - -struct iss_csi2_timing_cfg { - u8 ionum; /* IO1 or IO2 as in CSI2_TIMING */ - unsigned force_rx_mode:1; - unsigned stop_state_16x:1; - unsigned stop_state_4x:1; - u16 stop_state_counter; -}; - -struct iss_csi2_ctrl_cfg { - bool vp_clk_enable; - bool vp_only_enable; - u8 vp_out_ctrl; - enum iss_csi2_frame_mode frame_mode; - bool ecc_enable; - bool if_enable; -}; - -#define CSI2_PAD_SINK 0 -#define CSI2_PAD_SOURCE 1 -#define CSI2_PADS_NUM 2 - -#define CSI2_OUTPUT_IPIPEIF BIT(0) -#define CSI2_OUTPUT_MEMORY BIT(1) - -struct iss_csi2_device { - struct v4l2_subdev subdev; - struct media_pad pads[CSI2_PADS_NUM]; - struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM]; - - struct iss_video video_out; - struct iss_device *iss; - - u8 available; /* Is the IP present on the silicon? */ - - /* memory resources, as defined in enum iss_mem_resources */ - unsigned int regs1; - unsigned int regs2; - /* ISP subclock, as defined in enum iss_isp_subclk_resource */ - unsigned int subclk; - - u32 output; /* output to IPIPEIF, memory or both? */ - bool dpcm_decompress; - unsigned int frame_skip; - - struct iss_csiphy *phy; - struct iss_csi2_ctx_cfg contexts[ISS_CSI2_MAX_CTX_NUM + 1]; - struct iss_csi2_timing_cfg timing[2]; - struct iss_csi2_ctrl_cfg ctrl; - enum iss_pipeline_stream_state state; - wait_queue_head_t wait; - atomic_t stopping; -}; - -void omap4iss_csi2_isr(struct iss_csi2_device *csi2); -int omap4iss_csi2_reset(struct iss_csi2_device *csi2); -int omap4iss_csi2_init(struct iss_device *iss); -int omap4iss_csi2_create_links(struct iss_device *iss); -void omap4iss_csi2_cleanup(struct iss_device *iss); -void omap4iss_csi2_unregister_entities(struct iss_csi2_device *csi2); -int omap4iss_csi2_register_entities(struct iss_csi2_device *csi2, - struct v4l2_device *vdev); -#endif /* OMAP4_ISS_CSI2_H */ diff --git a/drivers/staging/media/omap4iss/iss_csiphy.c b/drivers/staging/media/omap4iss/iss_csiphy.c deleted file mode 100644 index 96f2ce0451384d..00000000000000 --- a/drivers/staging/media/omap4iss/iss_csiphy.c +++ /dev/null @@ -1,277 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * TI OMAP4 ISS V4L2 Driver - CSI PHY module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#include -#include -#include - -#include "../../../../arch/arm/mach-omap2/control.h" - -#include "iss.h" -#include "iss_regs.h" -#include "iss_csiphy.h" - -/* - * csiphy_lanes_config - Configuration of CSIPHY lanes. - * - * Updates HW configuration. - * Called with phy->mutex taken. - */ -static void csiphy_lanes_config(struct iss_csiphy *phy) -{ - unsigned int i; - u32 reg; - - reg = iss_reg_read(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG); - - for (i = 0; i < phy->max_data_lanes; i++) { - reg &= ~(CSI2_COMPLEXIO_CFG_DATA_POL(i + 1) | - CSI2_COMPLEXIO_CFG_DATA_POSITION_MASK(i + 1)); - reg |= (phy->lanes.data[i].pol ? - CSI2_COMPLEXIO_CFG_DATA_POL(i + 1) : 0); - reg |= (phy->lanes.data[i].pos << - CSI2_COMPLEXIO_CFG_DATA_POSITION_SHIFT(i + 1)); - } - - reg &= ~(CSI2_COMPLEXIO_CFG_CLOCK_POL | - CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK); - reg |= phy->lanes.clk.pol ? CSI2_COMPLEXIO_CFG_CLOCK_POL : 0; - reg |= phy->lanes.clk.pos << CSI2_COMPLEXIO_CFG_CLOCK_POSITION_SHIFT; - - iss_reg_write(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG, reg); -} - -/* - * csiphy_set_power - * @power: Power state to be set. - * - * Returns 0 if successful, or -EBUSY if the retry count is exceeded. - */ -static int csiphy_set_power(struct iss_csiphy *phy, u32 power) -{ - u32 reg; - u8 retry_count; - - iss_reg_update(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG, - CSI2_COMPLEXIO_CFG_PWD_CMD_MASK, - power | CSI2_COMPLEXIO_CFG_PWR_AUTO); - - retry_count = 0; - do { - udelay(1); - reg = iss_reg_read(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG) - & CSI2_COMPLEXIO_CFG_PWD_STATUS_MASK; - - if (reg != power >> 2) - retry_count++; - - } while ((reg != power >> 2) && (retry_count < 250)); - - if (retry_count == 250) { - dev_err(phy->iss->dev, "CSI2 CIO set power failed!\n"); - return -EBUSY; - } - - return 0; -} - -/* - * csiphy_dphy_config - Configure CSI2 D-PHY parameters. - * - * Called with phy->mutex taken. - */ -static void csiphy_dphy_config(struct iss_csiphy *phy) -{ - u32 reg; - - /* Set up REGISTER0 */ - reg = phy->dphy.ths_term << REGISTER0_THS_TERM_SHIFT; - reg |= phy->dphy.ths_settle << REGISTER0_THS_SETTLE_SHIFT; - - iss_reg_write(phy->iss, phy->phy_regs, REGISTER0, reg); - - /* Set up REGISTER1 */ - reg = phy->dphy.tclk_term << REGISTER1_TCLK_TERM_SHIFT; - reg |= phy->dphy.tclk_miss << REGISTER1_CTRLCLK_DIV_FACTOR_SHIFT; - reg |= phy->dphy.tclk_settle << REGISTER1_TCLK_SETTLE_SHIFT; - reg |= 0xb8 << REGISTER1_DPHY_HS_SYNC_PATTERN_SHIFT; - - iss_reg_write(phy->iss, phy->phy_regs, REGISTER1, reg); -} - -/* - * TCLK values are OK at their reset values - */ -#define TCLK_TERM 0 -#define TCLK_MISS 1 -#define TCLK_SETTLE 14 - -int omap4iss_csiphy_config(struct iss_device *iss, - struct v4l2_subdev *csi2_subdev) -{ - struct iss_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev); - struct iss_pipeline *pipe = to_iss_pipeline(&csi2_subdev->entity); - struct iss_v4l2_subdevs_group *subdevs = pipe->external->host_priv; - struct iss_csiphy_dphy_cfg csi2phy; - int csi2_ddrclk_khz; - struct iss_csiphy_lanes_cfg *lanes; - unsigned int used_lanes = 0; - u32 cam_rx_ctrl; - unsigned int i; - - lanes = &subdevs->bus.csi2.lanecfg; - - /* - * SCM.CONTROL_CAMERA_RX - * - bit [31] : CSIPHY2 lane 2 enable (4460+ only) - * - bit [30:29] : CSIPHY2 per-lane enable (1 to 0) - * - bit [28:24] : CSIPHY1 per-lane enable (4 to 0) - * - bit [21] : CSIPHY2 CTRLCLK enable - * - bit [20:19] : CSIPHY2 config: 00 d-phy, 01/10 ccp2 - * - bit [18] : CSIPHY1 CTRLCLK enable - * - bit [17:16] : CSIPHY1 config: 00 d-phy, 01/10 ccp2 - */ - /* - * TODO: When implementing DT support specify the CONTROL_CAMERA_RX - * register offset in the syscon property instead of hardcoding it. - */ - regmap_read(iss->syscon, 0x68, &cam_rx_ctrl); - - if (subdevs->interface == ISS_INTERFACE_CSI2A_PHY1) { - cam_rx_ctrl &= ~(OMAP4_CAMERARX_CSI21_LANEENABLE_MASK | - OMAP4_CAMERARX_CSI21_CAMMODE_MASK); - /* NOTE: Leave CSIPHY1 config to 0x0: D-PHY mode */ - /* Enable all lanes for now */ - cam_rx_ctrl |= - 0x1f << OMAP4_CAMERARX_CSI21_LANEENABLE_SHIFT; - /* Enable CTRLCLK */ - cam_rx_ctrl |= OMAP4_CAMERARX_CSI21_CTRLCLKEN_MASK; - } - - if (subdevs->interface == ISS_INTERFACE_CSI2B_PHY2) { - cam_rx_ctrl &= ~(OMAP4_CAMERARX_CSI22_LANEENABLE_MASK | - OMAP4_CAMERARX_CSI22_CAMMODE_MASK); - /* NOTE: Leave CSIPHY2 config to 0x0: D-PHY mode */ - /* Enable all lanes for now */ - cam_rx_ctrl |= - 0x3 << OMAP4_CAMERARX_CSI22_LANEENABLE_SHIFT; - /* Enable CTRLCLK */ - cam_rx_ctrl |= OMAP4_CAMERARX_CSI22_CTRLCLKEN_MASK; - } - - regmap_write(iss->syscon, 0x68, cam_rx_ctrl); - - /* Reset used lane count */ - csi2->phy->used_data_lanes = 0; - - /* Clock and data lanes verification */ - for (i = 0; i < csi2->phy->max_data_lanes; i++) { - if (lanes->data[i].pos == 0) - continue; - - if (lanes->data[i].pol > 1 || - lanes->data[i].pos > (csi2->phy->max_data_lanes + 1)) - return -EINVAL; - - if (used_lanes & (1 << lanes->data[i].pos)) - return -EINVAL; - - used_lanes |= 1 << lanes->data[i].pos; - csi2->phy->used_data_lanes++; - } - - if (lanes->clk.pol > 1 || - lanes->clk.pos > (csi2->phy->max_data_lanes + 1)) - return -EINVAL; - - if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos)) - return -EINVAL; - - csi2_ddrclk_khz = pipe->external_rate / 1000 - / (2 * csi2->phy->used_data_lanes) - * pipe->external_bpp; - - /* - * THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1. - * THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3. - */ - csi2phy.ths_term = DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1; - csi2phy.ths_settle = DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3; - csi2phy.tclk_term = TCLK_TERM; - csi2phy.tclk_miss = TCLK_MISS; - csi2phy.tclk_settle = TCLK_SETTLE; - - mutex_lock(&csi2->phy->mutex); - csi2->phy->dphy = csi2phy; - csi2->phy->lanes = *lanes; - mutex_unlock(&csi2->phy->mutex); - - return 0; -} - -int omap4iss_csiphy_acquire(struct iss_csiphy *phy) -{ - int rval; - - mutex_lock(&phy->mutex); - - rval = omap4iss_csi2_reset(phy->csi2); - if (rval) - goto done; - - csiphy_dphy_config(phy); - csiphy_lanes_config(phy); - - rval = csiphy_set_power(phy, CSI2_COMPLEXIO_CFG_PWD_CMD_ON); - if (rval) - goto done; - - phy->phy_in_use = 1; - -done: - mutex_unlock(&phy->mutex); - return rval; -} - -void omap4iss_csiphy_release(struct iss_csiphy *phy) -{ - mutex_lock(&phy->mutex); - if (phy->phy_in_use) { - csiphy_set_power(phy, CSI2_COMPLEXIO_CFG_PWD_CMD_OFF); - phy->phy_in_use = 0; - } - mutex_unlock(&phy->mutex); -} - -/* - * omap4iss_csiphy_init - Initialize the CSI PHY frontends - */ -int omap4iss_csiphy_init(struct iss_device *iss) -{ - struct iss_csiphy *phy1 = &iss->csiphy1; - struct iss_csiphy *phy2 = &iss->csiphy2; - - phy1->iss = iss; - phy1->csi2 = &iss->csi2a; - phy1->max_data_lanes = ISS_CSIPHY1_NUM_DATA_LANES; - phy1->used_data_lanes = 0; - phy1->cfg_regs = OMAP4_ISS_MEM_CSI2_A_REGS1; - phy1->phy_regs = OMAP4_ISS_MEM_CAMERARX_CORE1; - mutex_init(&phy1->mutex); - - phy2->iss = iss; - phy2->csi2 = &iss->csi2b; - phy2->max_data_lanes = ISS_CSIPHY2_NUM_DATA_LANES; - phy2->used_data_lanes = 0; - phy2->cfg_regs = OMAP4_ISS_MEM_CSI2_B_REGS1; - phy2->phy_regs = OMAP4_ISS_MEM_CAMERARX_CORE2; - mutex_init(&phy2->mutex); - - return 0; -} diff --git a/drivers/staging/media/omap4iss/iss_csiphy.h b/drivers/staging/media/omap4iss/iss_csiphy.h deleted file mode 100644 index 44408e4fcf3b1d..00000000000000 --- a/drivers/staging/media/omap4iss/iss_csiphy.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * TI OMAP4 ISS V4L2 Driver - CSI PHY module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#ifndef OMAP4_ISS_CSI_PHY_H -#define OMAP4_ISS_CSI_PHY_H - -#include - -struct iss_csi2_device; - -struct iss_csiphy_dphy_cfg { - u8 ths_term; - u8 ths_settle; - u8 tclk_term; - unsigned tclk_miss:1; - u8 tclk_settle; -}; - -struct iss_csiphy { - struct iss_device *iss; - struct mutex mutex; /* serialize csiphy configuration */ - u8 phy_in_use; - struct iss_csi2_device *csi2; - - /* memory resources, as defined in enum iss_mem_resources */ - unsigned int cfg_regs; - unsigned int phy_regs; - - u8 max_data_lanes; /* number of CSI2 Data Lanes supported */ - u8 used_data_lanes; /* number of CSI2 Data Lanes used */ - struct iss_csiphy_lanes_cfg lanes; - struct iss_csiphy_dphy_cfg dphy; -}; - -int omap4iss_csiphy_config(struct iss_device *iss, - struct v4l2_subdev *csi2_subdev); -int omap4iss_csiphy_acquire(struct iss_csiphy *phy); -void omap4iss_csiphy_release(struct iss_csiphy *phy); -int omap4iss_csiphy_init(struct iss_device *iss); - -#endif /* OMAP4_ISS_CSI_PHY_H */ diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c deleted file mode 100644 index 4a4eae290d65ae..00000000000000 --- a/drivers/staging/media/omap4iss/iss_ipipe.c +++ /dev/null @@ -1,579 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * TI OMAP4 ISS V4L2 Driver - ISP IPIPE module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "iss.h" -#include "iss_regs.h" -#include "iss_ipipe.h" - -static struct v4l2_mbus_framefmt * -__ipipe_get_format(struct iss_ipipe_device *ipipe, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - enum v4l2_subdev_format_whence which); - -static const unsigned int ipipe_fmts[] = { - MEDIA_BUS_FMT_SGRBG10_1X10, - MEDIA_BUS_FMT_SRGGB10_1X10, - MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SGBRG10_1X10, -}; - -/* - * ipipe_print_status - Print current IPIPE Module register values. - * @ipipe: Pointer to ISS ISP IPIPE device. - * - * Also prints other debug information stored in the IPIPE module. - */ -#define IPIPE_PRINT_REGISTER(iss, name)\ - dev_dbg(iss->dev, "###IPIPE " #name "=0x%08x\n", \ - iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_##name)) - -static void ipipe_print_status(struct iss_ipipe_device *ipipe) -{ - struct iss_device *iss = to_iss_device(ipipe); - - dev_dbg(iss->dev, "-------------IPIPE Register dump-------------\n"); - - IPIPE_PRINT_REGISTER(iss, SRC_EN); - IPIPE_PRINT_REGISTER(iss, SRC_MODE); - IPIPE_PRINT_REGISTER(iss, SRC_FMT); - IPIPE_PRINT_REGISTER(iss, SRC_COL); - IPIPE_PRINT_REGISTER(iss, SRC_VPS); - IPIPE_PRINT_REGISTER(iss, SRC_VSZ); - IPIPE_PRINT_REGISTER(iss, SRC_HPS); - IPIPE_PRINT_REGISTER(iss, SRC_HSZ); - IPIPE_PRINT_REGISTER(iss, GCK_MMR); - IPIPE_PRINT_REGISTER(iss, YUV_PHS); - - dev_dbg(iss->dev, "-----------------------------------------------\n"); -} - -/* - * ipipe_enable - Enable/Disable IPIPE. - * @enable: enable flag - * - */ -static void ipipe_enable(struct iss_ipipe_device *ipipe, u8 enable) -{ - struct iss_device *iss = to_iss_device(ipipe); - - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_EN, - IPIPE_SRC_EN_EN, enable ? IPIPE_SRC_EN_EN : 0); -} - -/* ----------------------------------------------------------------------------- - * Format- and pipeline-related configuration helpers - */ - -static void ipipe_configure(struct iss_ipipe_device *ipipe) -{ - struct iss_device *iss = to_iss_device(ipipe); - struct v4l2_mbus_framefmt *format; - - /* IPIPE_PAD_SINK */ - format = &ipipe->formats[IPIPE_PAD_SINK]; - - /* NOTE: Currently just supporting pipeline IN: RGB, OUT: YUV422 */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_FMT, - IPIPE_SRC_FMT_RAW2YUV); - - /* Enable YUV444 -> YUV422 conversion */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_YUV_PHS, - IPIPE_YUV_PHS_LPF); - - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VPS, 0); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HPS, 0); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VSZ, - (format->height - 2) & IPIPE_SRC_VSZ_MASK); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HSZ, - (format->width - 1) & IPIPE_SRC_HSZ_MASK); - - /* Ignore ipipeif_wrt signal, and operate on-the-fly. */ - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_MODE, - IPIPE_SRC_MODE_WRT | IPIPE_SRC_MODE_OST); - - /* HACK: Values tuned for Ducati SW (OV) */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_COL, - IPIPE_SRC_COL_EE_B | IPIPE_SRC_COL_EO_GB | - IPIPE_SRC_COL_OE_GR | IPIPE_SRC_COL_OO_R); - - /* IPIPE_PAD_SOURCE_VP */ - format = &ipipe->formats[IPIPE_PAD_SOURCE_VP]; - /* Do nothing? */ -} - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -/* - * ipipe_set_stream - Enable/Disable streaming on the IPIPE module - * @sd: ISP IPIPE V4L2 subdevice - * @enable: Enable/disable stream - */ -static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct iss_device *iss = to_iss_device(ipipe); - int ret = 0; - - if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) { - if (enable == ISS_PIPELINE_STREAM_STOPPED) - return 0; - - omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE); - - /* Enable clk_arm_g0 */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_MMR, - IPIPE_GCK_MMR_REG); - - /* Enable clk_pix_g[3:0] */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_PIX, - IPIPE_GCK_PIX_G3 | IPIPE_GCK_PIX_G2 | - IPIPE_GCK_PIX_G1 | IPIPE_GCK_PIX_G0); - } - - switch (enable) { - case ISS_PIPELINE_STREAM_CONTINUOUS: - - ipipe_configure(ipipe); - ipipe_print_status(ipipe); - - atomic_set(&ipipe->stopping, 0); - ipipe_enable(ipipe, 1); - break; - - case ISS_PIPELINE_STREAM_STOPPED: - if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) - return 0; - if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait, - &ipipe->stopping)) - ret = -ETIMEDOUT; - - ipipe_enable(ipipe, 0); - omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE); - break; - } - - ipipe->state = enable; - return ret; -} - -static struct v4l2_mbus_framefmt * -__ipipe_get_format(struct iss_ipipe_device *ipipe, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_state_get_format(sd_state, pad); - - return &ipipe->formats[pad]; -} - -/* - * ipipe_try_format - Try video format on a pad - * @ipipe: ISS IPIPE device - * @sd_state: V4L2 subdev state - * @pad: Pad number - * @fmt: Format - */ -static void -ipipe_try_format(struct iss_ipipe_device *ipipe, - struct v4l2_subdev_state *sd_state, - unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - struct v4l2_mbus_framefmt *format; - unsigned int width = fmt->width; - unsigned int height = fmt->height; - unsigned int i; - - switch (pad) { - case IPIPE_PAD_SINK: - for (i = 0; i < ARRAY_SIZE(ipipe_fmts); i++) { - if (fmt->code == ipipe_fmts[i]) - break; - } - - /* If not found, use SGRBG10 as default */ - if (i >= ARRAY_SIZE(ipipe_fmts)) - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - - /* Clamp the input size. */ - fmt->width = clamp_t(u32, width, 1, 8192); - fmt->height = clamp_t(u32, height, 1, 8192); - fmt->colorspace = V4L2_COLORSPACE_SRGB; - break; - - case IPIPE_PAD_SOURCE_VP: - format = __ipipe_get_format(ipipe, sd_state, IPIPE_PAD_SINK, - which); - memcpy(fmt, format, sizeof(*fmt)); - - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - fmt->width = clamp_t(u32, width, 32, fmt->width); - fmt->height = clamp_t(u32, height, 32, fmt->height); - fmt->colorspace = V4L2_COLORSPACE_JPEG; - break; - } - - fmt->field = V4L2_FIELD_NONE; -} - -/* - * ipipe_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @sd_state: V4L2 subdev state - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int ipipe_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - switch (code->pad) { - case IPIPE_PAD_SINK: - if (code->index >= ARRAY_SIZE(ipipe_fmts)) - return -EINVAL; - - code->code = ipipe_fmts[code->index]; - break; - - case IPIPE_PAD_SOURCE_VP: - /* FIXME: Forced format conversion inside IPIPE ? */ - if (code->index != 0) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_UYVY8_1X16; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int ipipe_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - ipipe_try_format(ipipe, sd_state, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * ipipe_get_format - Retrieve the video format on a pad - * @sd : ISP IPIPE V4L2 subdevice - * @sd_state: V4L2 subdev state - * @fmt: Format - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int ipipe_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * ipipe_set_format - Set the video format on a pad - * @sd : ISP IPIPE V4L2 subdevice - * @sd_state: V4L2 subdev state - * @fmt: Format - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int ipipe_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ipipe_get_format(ipipe, sd_state, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - ipipe_try_format(ipipe, sd_state, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - /* Propagate the format from sink to source */ - if (fmt->pad == IPIPE_PAD_SINK) { - format = __ipipe_get_format(ipipe, sd_state, - IPIPE_PAD_SOURCE_VP, - fmt->which); - *format = fmt->format; - ipipe_try_format(ipipe, sd_state, IPIPE_PAD_SOURCE_VP, format, - fmt->which); - } - - return 0; -} - -static int ipipe_link_validate(struct v4l2_subdev *sd, struct media_link *link, - struct v4l2_subdev_format *source_fmt, - struct v4l2_subdev_format *sink_fmt) -{ - /* Check if the two ends match */ - if (source_fmt->format.width != sink_fmt->format.width || - source_fmt->format.height != sink_fmt->format.height) - return -EPIPE; - - if (source_fmt->format.code != sink_fmt->format.code) - return -EPIPE; - - return 0; -} - -/* - * ipipe_init_formats - Initialize formats on all pads - * @sd: ISP IPIPE V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = IPIPE_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - format.format.width = 4096; - format.format.height = 4096; - ipipe_set_format(sd, fh ? fh->state : NULL, &format); - - return 0; -} - -/* V4L2 subdev video operations */ -static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = { - .s_stream = ipipe_set_stream, -}; - -/* V4L2 subdev pad operations */ -static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = { - .enum_mbus_code = ipipe_enum_mbus_code, - .enum_frame_size = ipipe_enum_frame_size, - .get_fmt = ipipe_get_format, - .set_fmt = ipipe_set_format, - .link_validate = ipipe_link_validate, -}; - -/* V4L2 subdev operations */ -static const struct v4l2_subdev_ops ipipe_v4l2_ops = { - .video = &ipipe_v4l2_video_ops, - .pad = &ipipe_v4l2_pad_ops, -}; - -/* V4L2 subdev internal operations */ -static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = { - .open = ipipe_init_formats, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * ipipe_link_setup - Setup IPIPE connections - * @entity: IPIPE media entity - * @local: Pad at the local end of the link - * @remote: Pad at the remote end of the link - * @flags: Link flags - * - * return -EINVAL or zero on success - */ -static int ipipe_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct iss_device *iss = to_iss_device(ipipe); - - if (!is_media_entity_v4l2_subdev(remote->entity)) - return -EINVAL; - - switch (local->index) { - case IPIPE_PAD_SINK: - /* Read from IPIPEIF. */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipe->input = IPIPE_INPUT_NONE; - break; - } - - if (ipipe->input != IPIPE_INPUT_NONE) - return -EBUSY; - - if (remote->entity == &iss->ipipeif.subdev.entity) - ipipe->input = IPIPE_INPUT_IPIPEIF; - - break; - - case IPIPE_PAD_SOURCE_VP: - /* Send to RESIZER */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (ipipe->output & ~IPIPE_OUTPUT_VP) - return -EBUSY; - ipipe->output |= IPIPE_OUTPUT_VP; - } else { - ipipe->output &= ~IPIPE_OUTPUT_VP; - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* media operations */ -static const struct media_entity_operations ipipe_media_ops = { - .link_setup = ipipe_link_setup, - .link_validate = v4l2_subdev_link_validate, -}; - -/* - * ipipe_init_entities - Initialize V4L2 subdev and media entity - * @ipipe: ISS ISP IPIPE module - * - * Return 0 on success and a negative error code on failure. - */ -static int ipipe_init_entities(struct iss_ipipe_device *ipipe) -{ - struct v4l2_subdev *sd = &ipipe->subdev; - struct media_pad *pads = ipipe->pads; - struct media_entity *me = &sd->entity; - int ret; - - ipipe->input = IPIPE_INPUT_NONE; - - v4l2_subdev_init(sd, &ipipe_v4l2_ops); - sd->internal_ops = &ipipe_v4l2_internal_ops; - strscpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name)); - sd->grp_id = BIT(16); /* group ID for iss subdevs */ - v4l2_set_subdevdata(sd, ipipe); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; - - me->ops = &ipipe_media_ops; - ret = media_entity_pads_init(me, IPIPE_PADS_NUM, pads); - if (ret < 0) - return ret; - - ipipe_init_formats(sd, NULL); - - return 0; -} - -void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe) -{ - v4l2_device_unregister_subdev(&ipipe->subdev); -} - -int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video node. */ - ret = v4l2_device_register_subdev(vdev, &ipipe->subdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap4iss_ipipe_unregister_entities(ipipe); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP IPIPE initialisation and cleanup - */ - -/* - * omap4iss_ipipe_init - IPIPE module initialization. - * @iss: Device pointer specific to the OMAP4 ISS. - * - * TODO: Get the initialisation values from platform data. - * - * Return 0 on success or a negative error code otherwise. - */ -int omap4iss_ipipe_init(struct iss_device *iss) -{ - struct iss_ipipe_device *ipipe = &iss->ipipe; - - ipipe->state = ISS_PIPELINE_STREAM_STOPPED; - init_waitqueue_head(&ipipe->wait); - - return ipipe_init_entities(ipipe); -} - -/* - * omap4iss_ipipe_cleanup - IPIPE module cleanup. - * @iss: Device pointer specific to the OMAP4 ISS. - */ -void omap4iss_ipipe_cleanup(struct iss_device *iss) -{ - struct iss_ipipe_device *ipipe = &iss->ipipe; - - media_entity_cleanup(&ipipe->subdev.entity); -} diff --git a/drivers/staging/media/omap4iss/iss_ipipe.h b/drivers/staging/media/omap4iss/iss_ipipe.h deleted file mode 100644 index 53b42aac169686..00000000000000 --- a/drivers/staging/media/omap4iss/iss_ipipe.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * TI OMAP4 ISS V4L2 Driver - ISP IPIPE module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#ifndef OMAP4_ISS_IPIPE_H -#define OMAP4_ISS_IPIPE_H - -#include "iss_video.h" - -enum ipipe_input_entity { - IPIPE_INPUT_NONE, - IPIPE_INPUT_IPIPEIF, -}; - -#define IPIPE_OUTPUT_VP BIT(0) - -/* Sink and source IPIPE pads */ -#define IPIPE_PAD_SINK 0 -#define IPIPE_PAD_SOURCE_VP 1 -#define IPIPE_PADS_NUM 2 - -/* - * struct iss_ipipe_device - Structure for the IPIPE module to store its own - * information - * @subdev: V4L2 subdevice - * @pads: Sink and source media entity pads - * @formats: Active video formats - * @input: Active input - * @output: Active outputs - * @error: A hardware error occurred during capture - * @state: Streaming state - * @wait: Wait queue used to stop the module - * @stopping: Stopping state - */ -struct iss_ipipe_device { - struct v4l2_subdev subdev; - struct media_pad pads[IPIPE_PADS_NUM]; - struct v4l2_mbus_framefmt formats[IPIPE_PADS_NUM]; - - enum ipipe_input_entity input; - unsigned int output; - unsigned int error; - - enum iss_pipeline_stream_state state; - wait_queue_head_t wait; - atomic_t stopping; -}; - -struct iss_device; - -int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe, - struct v4l2_device *vdev); -void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe); - -int omap4iss_ipipe_init(struct iss_device *iss); -void omap4iss_ipipe_cleanup(struct iss_device *iss); - -#endif /* OMAP4_ISS_IPIPE_H */ diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c deleted file mode 100644 index 8fa99532d9d4af..00000000000000 --- a/drivers/staging/media/omap4iss/iss_ipipeif.c +++ /dev/null @@ -1,844 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * TI OMAP4 ISS V4L2 Driver - ISP IPIPEIF module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "iss.h" -#include "iss_regs.h" -#include "iss_ipipeif.h" - -static const unsigned int ipipeif_fmts[] = { - MEDIA_BUS_FMT_SGRBG10_1X10, - MEDIA_BUS_FMT_SRGGB10_1X10, - MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SGBRG10_1X10, - MEDIA_BUS_FMT_UYVY8_1X16, - MEDIA_BUS_FMT_YUYV8_1X16, -}; - -/* - * ipipeif_print_status - Print current IPIPEIF Module register values. - * @ipipeif: Pointer to ISS ISP IPIPEIF device. - * - * Also prints other debug information stored in the IPIPEIF module. - */ -#define IPIPEIF_PRINT_REGISTER(iss, name)\ - dev_dbg(iss->dev, "###IPIPEIF " #name "=0x%08x\n", \ - iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_##name)) - -#define ISIF_PRINT_REGISTER(iss, name)\ - dev_dbg(iss->dev, "###ISIF " #name "=0x%08x\n", \ - iss_reg_read(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_##name)) - -#define ISP5_PRINT_REGISTER(iss, name)\ - dev_dbg(iss->dev, "###ISP5 " #name "=0x%08x\n", \ - iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_##name)) - -static void ipipeif_print_status(struct iss_ipipeif_device *ipipeif) -{ - struct iss_device *iss = to_iss_device(ipipeif); - - dev_dbg(iss->dev, "-------------IPIPEIF Register dump-------------\n"); - - IPIPEIF_PRINT_REGISTER(iss, CFG1); - IPIPEIF_PRINT_REGISTER(iss, CFG2); - - ISIF_PRINT_REGISTER(iss, SYNCEN); - ISIF_PRINT_REGISTER(iss, CADU); - ISIF_PRINT_REGISTER(iss, CADL); - ISIF_PRINT_REGISTER(iss, MODESET); - ISIF_PRINT_REGISTER(iss, CCOLP); - ISIF_PRINT_REGISTER(iss, SPH); - ISIF_PRINT_REGISTER(iss, LNH); - ISIF_PRINT_REGISTER(iss, LNV); - ISIF_PRINT_REGISTER(iss, VDINT(0)); - ISIF_PRINT_REGISTER(iss, HSIZE); - - ISP5_PRINT_REGISTER(iss, SYSCONFIG); - ISP5_PRINT_REGISTER(iss, CTRL); - ISP5_PRINT_REGISTER(iss, IRQSTATUS(0)); - ISP5_PRINT_REGISTER(iss, IRQENABLE_SET(0)); - ISP5_PRINT_REGISTER(iss, IRQENABLE_CLR(0)); - - dev_dbg(iss->dev, "-----------------------------------------------\n"); -} - -static void ipipeif_write_enable(struct iss_ipipeif_device *ipipeif, u8 enable) -{ - struct iss_device *iss = to_iss_device(ipipeif); - - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN, - ISIF_SYNCEN_DWEN, enable ? ISIF_SYNCEN_DWEN : 0); -} - -/* - * ipipeif_enable - Enable/Disable IPIPEIF. - * @enable: enable flag - * - */ -static void ipipeif_enable(struct iss_ipipeif_device *ipipeif, u8 enable) -{ - struct iss_device *iss = to_iss_device(ipipeif); - - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN, - ISIF_SYNCEN_SYEN, enable ? ISIF_SYNCEN_SYEN : 0); -} - -/* ----------------------------------------------------------------------------- - * Format- and pipeline-related configuration helpers - */ - -/* - * ipipeif_set_outaddr - Set memory address to save output image - * @ipipeif: Pointer to ISP IPIPEIF device. - * @addr: 32-bit memory address aligned on 32 byte boundary. - * - * Sets the memory address where the output will be saved. - */ -static void ipipeif_set_outaddr(struct iss_ipipeif_device *ipipeif, u32 addr) -{ - struct iss_device *iss = to_iss_device(ipipeif); - - /* Save address split in Base Address H & L */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CADU, - (addr >> (16 + 5)) & ISIF_CADU_MASK); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CADL, - (addr >> 5) & ISIF_CADL_MASK); -} - -static void ipipeif_configure(struct iss_ipipeif_device *ipipeif) -{ - struct iss_device *iss = to_iss_device(ipipeif); - const struct iss_format_info *info; - struct v4l2_mbus_framefmt *format; - u32 isif_ccolp = 0; - - omap4iss_configure_bridge(iss, ipipeif->input); - - /* IPIPEIF_PAD_SINK */ - format = &ipipeif->formats[IPIPEIF_PAD_SINK]; - - /* IPIPEIF with YUV422 input from ISIF */ - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG1, - IPIPEIF_CFG1_INPSRC1_MASK | IPIPEIF_CFG1_INPSRC2_MASK); - - /* Select ISIF/IPIPEIF input format */ - switch (format->code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - case MEDIA_BUS_FMT_YUYV8_1X16: - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, - ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | - ISIF_MODESET_CCDW_MASK, - ISIF_MODESET_INPMOD_YCBCR16); - - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, - IPIPEIF_CFG2_YUV8, IPIPEIF_CFG2_YUV16); - - break; - case MEDIA_BUS_FMT_SGRBG10_1X10: - isif_ccolp = ISIF_CCOLP_CP0_F0_GR | - ISIF_CCOLP_CP1_F0_R | - ISIF_CCOLP_CP2_F0_B | - ISIF_CCOLP_CP3_F0_GB; - goto cont_raw; - case MEDIA_BUS_FMT_SRGGB10_1X10: - isif_ccolp = ISIF_CCOLP_CP0_F0_R | - ISIF_CCOLP_CP1_F0_GR | - ISIF_CCOLP_CP2_F0_GB | - ISIF_CCOLP_CP3_F0_B; - goto cont_raw; - case MEDIA_BUS_FMT_SBGGR10_1X10: - isif_ccolp = ISIF_CCOLP_CP0_F0_B | - ISIF_CCOLP_CP1_F0_GB | - ISIF_CCOLP_CP2_F0_GR | - ISIF_CCOLP_CP3_F0_R; - goto cont_raw; - case MEDIA_BUS_FMT_SGBRG10_1X10: - isif_ccolp = ISIF_CCOLP_CP0_F0_GB | - ISIF_CCOLP_CP1_F0_B | - ISIF_CCOLP_CP2_F0_R | - ISIF_CCOLP_CP3_F0_GR; -cont_raw: - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, - IPIPEIF_CFG2_YUV16); - - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, - ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | - ISIF_MODESET_CCDW_MASK, ISIF_MODESET_INPMOD_RAW | - ISIF_MODESET_CCDW_2BIT); - - info = omap4iss_video_format_info(format->code); - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CGAMMAWD, - ISIF_CGAMMAWD_GWDI_MASK, - ISIF_CGAMMAWD_GWDI(info->bpp)); - - /* Set RAW Bayer pattern */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CCOLP, - isif_ccolp); - break; - } - - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SPH, 0 & ISIF_SPH_MASK); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNH, - (format->width - 1) & ISIF_LNH_MASK); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNV, - (format->height - 1) & ISIF_LNV_MASK); - - /* Generate ISIF0 on the last line of the image */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_VDINT(0), - format->height - 1); - - /* IPIPEIF_PAD_SOURCE_ISIF_SF */ - format = &ipipeif->formats[IPIPEIF_PAD_SOURCE_ISIF_SF]; - - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_HSIZE, - (ipipeif->video_out.bpl_value >> 5) & - ISIF_HSIZE_HSIZE_MASK); - - /* IPIPEIF_PAD_SOURCE_VP */ - /* Do nothing? */ -} - -/* ----------------------------------------------------------------------------- - * Interrupt handling - */ - -static void ipipeif_isr_buffer(struct iss_ipipeif_device *ipipeif) -{ - struct iss_buffer *buffer; - - /* The ISIF generates VD0 interrupts even when writes are disabled. - * deal with it anyway). Disabling the ISIF when no buffer is available - * is thus not be enough, we need to handle the situation explicitly. - */ - if (list_empty(&ipipeif->video_out.dmaqueue)) - return; - - ipipeif_write_enable(ipipeif, 0); - - buffer = omap4iss_video_buffer_next(&ipipeif->video_out); - if (!buffer) - return; - - ipipeif_set_outaddr(ipipeif, buffer->iss_addr); - - ipipeif_write_enable(ipipeif, 1); -} - -/* - * omap4iss_ipipeif_isr - Configure ipipeif during interframe time. - * @ipipeif: Pointer to ISP IPIPEIF device. - * @events: IPIPEIF events - */ -void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events) -{ - if (omap4iss_module_sync_is_stopping(&ipipeif->wait, - &ipipeif->stopping)) - return; - - if ((events & ISP5_IRQ_ISIF_INT(0)) && - (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) - ipipeif_isr_buffer(ipipeif); -} - -/* ----------------------------------------------------------------------------- - * ISP video operations - */ - -static int ipipeif_video_queue(struct iss_video *video, - struct iss_buffer *buffer) -{ - struct iss_ipipeif_device *ipipeif = container_of(video, - struct iss_ipipeif_device, video_out); - - if (!(ipipeif->output & IPIPEIF_OUTPUT_MEMORY)) - return -ENODEV; - - ipipeif_set_outaddr(ipipeif, buffer->iss_addr); - - /* - * If streaming was enabled before there was a buffer queued - * or underrun happened in the ISR, the hardware was not enabled - * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set. - * Enable it now. - */ - if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { - if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) - ipipeif_write_enable(ipipeif, 1); - ipipeif_enable(ipipeif, 1); - iss_video_dmaqueue_flags_clr(video); - } - - return 0; -} - -static const struct iss_video_operations ipipeif_video_ops = { - .queue = ipipeif_video_queue, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -#define IPIPEIF_DRV_SUBCLK_MASK (OMAP4_ISS_ISP_SUBCLK_IPIPEIF |\ - OMAP4_ISS_ISP_SUBCLK_ISIF) -/* - * ipipeif_set_stream - Enable/Disable streaming on the IPIPEIF module - * @sd: ISP IPIPEIF V4L2 subdevice - * @enable: Enable/disable stream - */ -static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct iss_device *iss = to_iss_device(ipipeif); - struct iss_video *video_out = &ipipeif->video_out; - int ret = 0; - - if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) { - if (enable == ISS_PIPELINE_STREAM_STOPPED) - return 0; - - omap4iss_isp_subclk_enable(iss, IPIPEIF_DRV_SUBCLK_MASK); - } - - switch (enable) { - case ISS_PIPELINE_STREAM_CONTINUOUS: - - ipipeif_configure(ipipeif); - ipipeif_print_status(ipipeif); - - /* - * When outputting to memory with no buffer available, let the - * buffer queue handler start the hardware. A DMA queue flag - * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is - * a buffer available. - */ - if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY && - !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED)) - break; - - atomic_set(&ipipeif->stopping, 0); - if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) - ipipeif_write_enable(ipipeif, 1); - ipipeif_enable(ipipeif, 1); - iss_video_dmaqueue_flags_clr(video_out); - break; - - case ISS_PIPELINE_STREAM_STOPPED: - if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) - return 0; - if (omap4iss_module_sync_idle(&sd->entity, &ipipeif->wait, - &ipipeif->stopping)) - ret = -ETIMEDOUT; - - if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY) - ipipeif_write_enable(ipipeif, 0); - ipipeif_enable(ipipeif, 0); - omap4iss_isp_subclk_disable(iss, IPIPEIF_DRV_SUBCLK_MASK); - iss_video_dmaqueue_flags_clr(video_out); - break; - } - - ipipeif->state = enable; - return ret; -} - -static struct v4l2_mbus_framefmt * -__ipipeif_get_format(struct iss_ipipeif_device *ipipeif, - struct v4l2_subdev_state *sd_state, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_state_get_format(sd_state, pad); - return &ipipeif->formats[pad]; -} - -/* - * ipipeif_try_format - Try video format on a pad - * @ipipeif: ISS IPIPEIF device - * @sd_state: V4L2 subdev state - * @pad: Pad number - * @fmt: Format - */ -static void -ipipeif_try_format(struct iss_ipipeif_device *ipipeif, - struct v4l2_subdev_state *sd_state, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - struct v4l2_mbus_framefmt *format; - unsigned int width = fmt->width; - unsigned int height = fmt->height; - unsigned int i; - - switch (pad) { - case IPIPEIF_PAD_SINK: - /* TODO: If the IPIPEIF output formatter pad is connected - * directly to the resizer, only YUV formats can be used. - */ - for (i = 0; i < ARRAY_SIZE(ipipeif_fmts); i++) { - if (fmt->code == ipipeif_fmts[i]) - break; - } - - /* If not found, use SGRBG10 as default */ - if (i >= ARRAY_SIZE(ipipeif_fmts)) - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - - /* Clamp the input size. */ - fmt->width = clamp_t(u32, width, 1, 8192); - fmt->height = clamp_t(u32, height, 1, 8192); - break; - - case IPIPEIF_PAD_SOURCE_ISIF_SF: - format = __ipipeif_get_format(ipipeif, sd_state, - IPIPEIF_PAD_SINK, - which); - memcpy(fmt, format, sizeof(*fmt)); - - /* The data formatter truncates the number of horizontal output - * pixels to a multiple of 16. To avoid clipping data, allow - * callers to request an output size bigger than the input size - * up to the nearest multiple of 16. - */ - fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); - fmt->width &= ~15; - fmt->height = clamp_t(u32, height, 32, fmt->height); - break; - - case IPIPEIF_PAD_SOURCE_VP: - format = __ipipeif_get_format(ipipeif, sd_state, - IPIPEIF_PAD_SINK, - which); - memcpy(fmt, format, sizeof(*fmt)); - - fmt->width = clamp_t(u32, width, 32, fmt->width); - fmt->height = clamp_t(u32, height, 32, fmt->height); - break; - } - - /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is - * stored on 2 bytes. - */ - fmt->colorspace = V4L2_COLORSPACE_SRGB; - fmt->field = V4L2_FIELD_NONE; -} - -/* - * ipipeif_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @sd_state: V4L2 subdev state - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - switch (code->pad) { - case IPIPEIF_PAD_SINK: - if (code->index >= ARRAY_SIZE(ipipeif_fmts)) - return -EINVAL; - - code->code = ipipeif_fmts[code->index]; - break; - - case IPIPEIF_PAD_SOURCE_ISIF_SF: - case IPIPEIF_PAD_SOURCE_VP: - /* No format conversion inside IPIPEIF */ - if (code->index != 0) - return -EINVAL; - - format = __ipipeif_get_format(ipipeif, sd_state, - IPIPEIF_PAD_SINK, - code->which); - - code->code = format->code; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - ipipeif_try_format(ipipeif, sd_state, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * ipipeif_get_format - Retrieve the video format on a pad - * @sd : ISP IPIPEIF V4L2 subdevice - * @sd_state: V4L2 subdev state - * @fmt: Format - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int ipipeif_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * ipipeif_set_format - Set the video format on a pad - * @sd : ISP IPIPEIF V4L2 subdevice - * @sd_state: V4L2 subdev state - * @fmt: Format - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int ipipeif_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ipipeif_get_format(ipipeif, sd_state, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - ipipeif_try_format(ipipeif, sd_state, fmt->pad, &fmt->format, - fmt->which); - *format = fmt->format; - - /* Propagate the format from sink to source */ - if (fmt->pad == IPIPEIF_PAD_SINK) { - format = __ipipeif_get_format(ipipeif, sd_state, - IPIPEIF_PAD_SOURCE_ISIF_SF, - fmt->which); - *format = fmt->format; - ipipeif_try_format(ipipeif, sd_state, - IPIPEIF_PAD_SOURCE_ISIF_SF, - format, fmt->which); - - format = __ipipeif_get_format(ipipeif, sd_state, - IPIPEIF_PAD_SOURCE_VP, - fmt->which); - *format = fmt->format; - ipipeif_try_format(ipipeif, sd_state, IPIPEIF_PAD_SOURCE_VP, - format, - fmt->which); - } - - return 0; -} - -static int ipipeif_link_validate(struct v4l2_subdev *sd, - struct media_link *link, - struct v4l2_subdev_format *source_fmt, - struct v4l2_subdev_format *sink_fmt) -{ - /* Check if the two ends match */ - if (source_fmt->format.width != sink_fmt->format.width || - source_fmt->format.height != sink_fmt->format.height) - return -EPIPE; - - if (source_fmt->format.code != sink_fmt->format.code) - return -EPIPE; - - return 0; -} - -/* - * ipipeif_init_formats - Initialize formats on all pads - * @sd: ISP IPIPEIF V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int ipipeif_init_formats(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = IPIPEIF_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - format.format.width = 4096; - format.format.height = 4096; - ipipeif_set_format(sd, fh ? fh->state : NULL, &format); - - return 0; -} - -/* V4L2 subdev video operations */ -static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = { - .s_stream = ipipeif_set_stream, -}; - -/* V4L2 subdev pad operations */ -static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = { - .enum_mbus_code = ipipeif_enum_mbus_code, - .enum_frame_size = ipipeif_enum_frame_size, - .get_fmt = ipipeif_get_format, - .set_fmt = ipipeif_set_format, - .link_validate = ipipeif_link_validate, -}; - -/* V4L2 subdev operations */ -static const struct v4l2_subdev_ops ipipeif_v4l2_ops = { - .video = &ipipeif_v4l2_video_ops, - .pad = &ipipeif_v4l2_pad_ops, -}; - -/* V4L2 subdev internal operations */ -static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = { - .open = ipipeif_init_formats, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * ipipeif_link_setup - Setup IPIPEIF connections - * @entity: IPIPEIF media entity - * @local: Pad at the local end of the link - * @remote: Pad at the remote end of the link - * @flags: Link flags - * - * return -EINVAL or zero on success - */ -static int ipipeif_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct iss_device *iss = to_iss_device(ipipeif); - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - switch (index) { - case IPIPEIF_PAD_SINK | 2 << 16: - /* Read from the sensor CSI2a or CSI2b. */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipeif->input = IPIPEIF_INPUT_NONE; - break; - } - - if (ipipeif->input != IPIPEIF_INPUT_NONE) - return -EBUSY; - - if (remote->entity == &iss->csi2a.subdev.entity) - ipipeif->input = IPIPEIF_INPUT_CSI2A; - else if (remote->entity == &iss->csi2b.subdev.entity) - ipipeif->input = IPIPEIF_INPUT_CSI2B; - - break; - - case IPIPEIF_PAD_SOURCE_ISIF_SF: - /* Write to memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (ipipeif->output & ~IPIPEIF_OUTPUT_MEMORY) - return -EBUSY; - ipipeif->output |= IPIPEIF_OUTPUT_MEMORY; - } else { - ipipeif->output &= ~IPIPEIF_OUTPUT_MEMORY; - } - break; - - case IPIPEIF_PAD_SOURCE_VP | 2 << 16: - /* Send to IPIPE/RESIZER */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (ipipeif->output & ~IPIPEIF_OUTPUT_VP) - return -EBUSY; - ipipeif->output |= IPIPEIF_OUTPUT_VP; - } else { - ipipeif->output &= ~IPIPEIF_OUTPUT_VP; - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* media operations */ -static const struct media_entity_operations ipipeif_media_ops = { - .link_setup = ipipeif_link_setup, - .link_validate = v4l2_subdev_link_validate, -}; - -/* - * ipipeif_init_entities - Initialize V4L2 subdev and media entity - * @ipipeif: ISS ISP IPIPEIF module - * - * Return 0 on success and a negative error code on failure. - */ -static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif) -{ - struct v4l2_subdev *sd = &ipipeif->subdev; - struct media_pad *pads = ipipeif->pads; - struct media_entity *me = &sd->entity; - int ret; - - ipipeif->input = IPIPEIF_INPUT_NONE; - - v4l2_subdev_init(sd, &ipipeif_v4l2_ops); - sd->internal_ops = &ipipeif_v4l2_internal_ops; - strscpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name)); - sd->grp_id = BIT(16); /* group ID for iss subdevs */ - v4l2_set_subdevdata(sd, ipipeif); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[IPIPEIF_PAD_SOURCE_ISIF_SF].flags = MEDIA_PAD_FL_SOURCE; - pads[IPIPEIF_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; - - me->ops = &ipipeif_media_ops; - ret = media_entity_pads_init(me, IPIPEIF_PADS_NUM, pads); - if (ret < 0) - return ret; - - ipipeif_init_formats(sd, NULL); - - ipipeif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ipipeif->video_out.ops = &ipipeif_video_ops; - ipipeif->video_out.iss = to_iss_device(ipipeif); - ipipeif->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; - ipipeif->video_out.bpl_alignment = 32; - ipipeif->video_out.bpl_zero_padding = 1; - ipipeif->video_out.bpl_max = 0x1ffe0; - - return omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF"); -} - -void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif) -{ - v4l2_device_unregister_subdev(&ipipeif->subdev); - omap4iss_video_unregister(&ipipeif->video_out); -} - -int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video node. */ - ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev); - if (ret < 0) - goto error; - - ret = omap4iss_video_register(&ipipeif->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap4iss_ipipeif_unregister_entities(ipipeif); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP IPIPEIF initialisation and cleanup - */ - -/* - * omap4iss_ipipeif_init - IPIPEIF module initialization. - * @iss: Device pointer specific to the OMAP4 ISS. - * - * TODO: Get the initialisation values from platform data. - * - * Return 0 on success or a negative error code otherwise. - */ -int omap4iss_ipipeif_init(struct iss_device *iss) -{ - struct iss_ipipeif_device *ipipeif = &iss->ipipeif; - - ipipeif->state = ISS_PIPELINE_STREAM_STOPPED; - init_waitqueue_head(&ipipeif->wait); - - return ipipeif_init_entities(ipipeif); -} - -/* - * omap4iss_ipipeif_create_links() - IPIPEIF pads links creation - * @iss: Pointer to ISS device - * - * return negative error code or zero on success - */ -int omap4iss_ipipeif_create_links(struct iss_device *iss) -{ - struct iss_ipipeif_device *ipipeif = &iss->ipipeif; - - /* Connect the IPIPEIF subdev to the video node. */ - return media_create_pad_link(&ipipeif->subdev.entity, - IPIPEIF_PAD_SOURCE_ISIF_SF, - &ipipeif->video_out.video.entity, 0, 0); -} - -/* - * omap4iss_ipipeif_cleanup - IPIPEIF module cleanup. - * @iss: Device pointer specific to the OMAP4 ISS. - */ -void omap4iss_ipipeif_cleanup(struct iss_device *iss) -{ - struct iss_ipipeif_device *ipipeif = &iss->ipipeif; - - media_entity_cleanup(&ipipeif->subdev.entity); -} diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.h b/drivers/staging/media/omap4iss/iss_ipipeif.h deleted file mode 100644 index 69792333a62ee1..00000000000000 --- a/drivers/staging/media/omap4iss/iss_ipipeif.h +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * TI OMAP4 ISS V4L2 Driver - ISP IPIPEIF module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#ifndef OMAP4_ISS_IPIPEIF_H -#define OMAP4_ISS_IPIPEIF_H - -#include "iss_video.h" - -enum ipipeif_input_entity { - IPIPEIF_INPUT_NONE, - IPIPEIF_INPUT_CSI2A, - IPIPEIF_INPUT_CSI2B -}; - -#define IPIPEIF_OUTPUT_MEMORY BIT(0) -#define IPIPEIF_OUTPUT_VP BIT(1) - -/* Sink and source IPIPEIF pads */ -#define IPIPEIF_PAD_SINK 0 -#define IPIPEIF_PAD_SOURCE_ISIF_SF 1 -#define IPIPEIF_PAD_SOURCE_VP 2 -#define IPIPEIF_PADS_NUM 3 - -/* - * struct iss_ipipeif_device - Structure for the IPIPEIF module to store its own - * information - * @subdev: V4L2 subdevice - * @pads: Sink and source media entity pads - * @formats: Active video formats - * @input: Active input - * @output: Active outputs - * @video_out: Output video node - * @error: A hardware error occurred during capture - * @alaw: A-law compression enabled (1) or disabled (0) - * @lpf: Low pass filter enabled (1) or disabled (0) - * @obclamp: Optical-black clamp enabled (1) or disabled (0) - * @fpc_en: Faulty pixels correction enabled (1) or disabled (0) - * @blcomp: Black level compensation configuration - * @clamp: Optical-black or digital clamp configuration - * @fpc: Faulty pixels correction configuration - * @lsc: Lens shading compensation configuration - * @update: Bitmask of controls to update during the next interrupt - * @shadow_update: Controls update in progress by userspace - * @syncif: Interface synchronization configuration - * @vpcfg: Video port configuration - * @underrun: A buffer underrun occurred and a new buffer has been queued - * @state: Streaming state - * @lock: Serializes shadow_update with interrupt handler - * @wait: Wait queue used to stop the module - * @stopping: Stopping state - * @ioctl_lock: Serializes ioctl calls and LSC requests freeing - */ -struct iss_ipipeif_device { - struct v4l2_subdev subdev; - struct media_pad pads[IPIPEIF_PADS_NUM]; - struct v4l2_mbus_framefmt formats[IPIPEIF_PADS_NUM]; - - enum ipipeif_input_entity input; - unsigned int output; - struct iss_video video_out; - unsigned int error; - - enum iss_pipeline_stream_state state; - wait_queue_head_t wait; - atomic_t stopping; -}; - -struct iss_device; - -int omap4iss_ipipeif_init(struct iss_device *iss); -int omap4iss_ipipeif_create_links(struct iss_device *iss); -void omap4iss_ipipeif_cleanup(struct iss_device *iss); -int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif, - struct v4l2_device *vdev); -void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif); - -int omap4iss_ipipeif_busy(struct iss_ipipeif_device *ipipeif); -void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events); -void omap4iss_ipipeif_restore_context(struct iss_device *iss); -void omap4iss_ipipeif_max_rate(struct iss_ipipeif_device *ipipeif, - unsigned int *max_rate); - -#endif /* OMAP4_ISS_IPIPEIF_H */ diff --git a/drivers/staging/media/omap4iss/iss_regs.h b/drivers/staging/media/omap4iss/iss_regs.h deleted file mode 100644 index cfe0bb0750723c..00000000000000 --- a/drivers/staging/media/omap4iss/iss_regs.h +++ /dev/null @@ -1,899 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * TI OMAP4 ISS V4L2 Driver - Register defines - * - * Copyright (C) 2012 Texas Instruments. - * - * Author: Sergio Aguirre - */ - -#ifndef _OMAP4_ISS_REGS_H_ -#define _OMAP4_ISS_REGS_H_ - -/* ISS */ -#define ISS_HL_REVISION 0x0 - -#define ISS_HL_SYSCONFIG 0x10 -#define ISS_HL_SYSCONFIG_IDLEMODE_SHIFT 2 -#define ISS_HL_SYSCONFIG_IDLEMODE_FORCEIDLE 0x0 -#define ISS_HL_SYSCONFIG_IDLEMODE_NOIDLE 0x1 -#define ISS_HL_SYSCONFIG_IDLEMODE_SMARTIDLE 0x2 -#define ISS_HL_SYSCONFIG_SOFTRESET BIT(0) - -#define ISS_HL_IRQSTATUS_RAW(i) (0x20 + (0x10 * (i))) -#define ISS_HL_IRQSTATUS(i) (0x24 + (0x10 * (i))) -#define ISS_HL_IRQENABLE_SET(i) (0x28 + (0x10 * (i))) -#define ISS_HL_IRQENABLE_CLR(i) (0x2c + (0x10 * (i))) - -#define ISS_HL_IRQ_HS_VS BIT(17) -#define ISS_HL_IRQ_SIMCOP(i) BIT(12 + (i)) -#define ISS_HL_IRQ_BTE BIT(11) -#define ISS_HL_IRQ_CBUFF BIT(10) -#define ISS_HL_IRQ_CCP2(i) BIT((i) > 3 ? 16 : 14 + (i)) -#define ISS_HL_IRQ_CSIB BIT(5) -#define ISS_HL_IRQ_CSIA BIT(4) -#define ISS_HL_IRQ_ISP(i) BIT(i) - -#define ISS_CTRL 0x80 -#define ISS_CTRL_CLK_DIV_MASK (3 << 4) -#define ISS_CTRL_INPUT_SEL_MASK (3 << 2) -#define ISS_CTRL_INPUT_SEL_CSI2A (0 << 2) -#define ISS_CTRL_INPUT_SEL_CSI2B (1 << 2) -#define ISS_CTRL_SYNC_DETECT_VS_RAISING (3 << 0) - -#define ISS_CLKCTRL 0x84 -#define ISS_CLKCTRL_VPORT2_CLK BIT(30) -#define ISS_CLKCTRL_VPORT1_CLK BIT(29) -#define ISS_CLKCTRL_VPORT0_CLK BIT(28) -#define ISS_CLKCTRL_CCP2 BIT(4) -#define ISS_CLKCTRL_CSI2_B BIT(3) -#define ISS_CLKCTRL_CSI2_A BIT(2) -#define ISS_CLKCTRL_ISP BIT(1) -#define ISS_CLKCTRL_SIMCOP BIT(0) - -#define ISS_CLKSTAT 0x88 -#define ISS_CLKSTAT_VPORT2_CLK BIT(30) -#define ISS_CLKSTAT_VPORT1_CLK BIT(29) -#define ISS_CLKSTAT_VPORT0_CLK BIT(28) -#define ISS_CLKSTAT_CCP2 BIT(4) -#define ISS_CLKSTAT_CSI2_B BIT(3) -#define ISS_CLKSTAT_CSI2_A BIT(2) -#define ISS_CLKSTAT_ISP BIT(1) -#define ISS_CLKSTAT_SIMCOP BIT(0) - -#define ISS_PM_STATUS 0x8c -#define ISS_PM_STATUS_CBUFF_PM_MASK (3 << 12) -#define ISS_PM_STATUS_BTE_PM_MASK (3 << 10) -#define ISS_PM_STATUS_SIMCOP_PM_MASK (3 << 8) -#define ISS_PM_STATUS_ISP_PM_MASK (3 << 6) -#define ISS_PM_STATUS_CCP2_PM_MASK (3 << 4) -#define ISS_PM_STATUS_CSI2_B_PM_MASK (3 << 2) -#define ISS_PM_STATUS_CSI2_A_PM_MASK (3 << 0) - -#define REGISTER0 0x0 -#define REGISTER0_HSCLOCKCONFIG BIT(24) -#define REGISTER0_THS_TERM_MASK (0xff << 8) -#define REGISTER0_THS_TERM_SHIFT 8 -#define REGISTER0_THS_SETTLE_MASK (0xff << 0) -#define REGISTER0_THS_SETTLE_SHIFT 0 - -#define REGISTER1 0x4 -#define REGISTER1_RESET_DONE_CTRLCLK BIT(29) -#define REGISTER1_CLOCK_MISS_DETECTOR_STATUS BIT(25) -#define REGISTER1_TCLK_TERM_MASK (0x3f << 18) -#define REGISTER1_TCLK_TERM_SHIFT 18 -#define REGISTER1_DPHY_HS_SYNC_PATTERN_SHIFT 10 -#define REGISTER1_CTRLCLK_DIV_FACTOR_MASK (0x3 << 8) -#define REGISTER1_CTRLCLK_DIV_FACTOR_SHIFT 8 -#define REGISTER1_TCLK_SETTLE_MASK (0xff << 0) -#define REGISTER1_TCLK_SETTLE_SHIFT 0 - -#define REGISTER2 0x8 - -#define CSI2_SYSCONFIG 0x10 -#define CSI2_SYSCONFIG_MSTANDBY_MODE_MASK (3 << 12) -#define CSI2_SYSCONFIG_MSTANDBY_MODE_FORCE (0 << 12) -#define CSI2_SYSCONFIG_MSTANDBY_MODE_NO (1 << 12) -#define CSI2_SYSCONFIG_MSTANDBY_MODE_SMART (2 << 12) -#define CSI2_SYSCONFIG_SOFT_RESET (1 << 1) -#define CSI2_SYSCONFIG_AUTO_IDLE (1 << 0) - -#define CSI2_SYSSTATUS 0x14 -#define CSI2_SYSSTATUS_RESET_DONE BIT(0) - -#define CSI2_IRQSTATUS 0x18 -#define CSI2_IRQENABLE 0x1c - -/* Shared bits across CSI2_IRQENABLE and IRQSTATUS */ - -#define CSI2_IRQ_OCP_ERR BIT(14) -#define CSI2_IRQ_SHORT_PACKET BIT(13) -#define CSI2_IRQ_ECC_CORRECTION BIT(12) -#define CSI2_IRQ_ECC_NO_CORRECTION BIT(11) -#define CSI2_IRQ_COMPLEXIO_ERR BIT(9) -#define CSI2_IRQ_FIFO_OVF BIT(8) -#define CSI2_IRQ_CONTEXT0 BIT(0) - -#define CSI2_CTRL 0x40 -#define CSI2_CTRL_MFLAG_LEVH_MASK (7 << 20) -#define CSI2_CTRL_MFLAG_LEVH_SHIFT 20 -#define CSI2_CTRL_MFLAG_LEVL_MASK (7 << 17) -#define CSI2_CTRL_MFLAG_LEVL_SHIFT 17 -#define CSI2_CTRL_BURST_SIZE_EXPAND (1 << 16) -#define CSI2_CTRL_VP_CLK_EN (1 << 15) -#define CSI2_CTRL_NON_POSTED_WRITE (1 << 13) -#define CSI2_CTRL_VP_ONLY_EN (1 << 11) -#define CSI2_CTRL_VP_OUT_CTRL_MASK (3 << 8) -#define CSI2_CTRL_VP_OUT_CTRL_SHIFT 8 -#define CSI2_CTRL_DBG_EN (1 << 7) -#define CSI2_CTRL_BURST_SIZE_MASK (3 << 5) -#define CSI2_CTRL_ENDIANNESS (1 << 4) -#define CSI2_CTRL_FRAME (1 << 3) -#define CSI2_CTRL_ECC_EN (1 << 2) -#define CSI2_CTRL_IF_EN (1 << 0) - -#define CSI2_DBG_H 0x44 - -#define CSI2_COMPLEXIO_CFG 0x50 -#define CSI2_COMPLEXIO_CFG_RESET_CTRL (1 << 30) -#define CSI2_COMPLEXIO_CFG_RESET_DONE (1 << 29) -#define CSI2_COMPLEXIO_CFG_PWD_CMD_MASK (3 << 27) -#define CSI2_COMPLEXIO_CFG_PWD_CMD_OFF (0 << 27) -#define CSI2_COMPLEXIO_CFG_PWD_CMD_ON (1 << 27) -#define CSI2_COMPLEXIO_CFG_PWD_CMD_ULP (2 << 27) -#define CSI2_COMPLEXIO_CFG_PWD_STATUS_MASK (3 << 25) -#define CSI2_COMPLEXIO_CFG_PWD_STATUS_OFF (0 << 25) -#define CSI2_COMPLEXIO_CFG_PWD_STATUS_ON (1 << 25) -#define CSI2_COMPLEXIO_CFG_PWD_STATUS_ULP (2 << 25) -#define CSI2_COMPLEXIO_CFG_PWR_AUTO (1 << 24) -#define CSI2_COMPLEXIO_CFG_DATA_POL(i) (1 << (((i) * 4) + 3)) -#define CSI2_COMPLEXIO_CFG_DATA_POSITION_MASK(i) (7 << ((i) * 4)) -#define CSI2_COMPLEXIO_CFG_DATA_POSITION_SHIFT(i) ((i) * 4) -#define CSI2_COMPLEXIO_CFG_CLOCK_POL (1 << 3) -#define CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK (7 << 0) -#define CSI2_COMPLEXIO_CFG_CLOCK_POSITION_SHIFT 0 - -#define CSI2_COMPLEXIO_IRQSTATUS 0x54 - -#define CSI2_SHORT_PACKET 0x5c - -#define CSI2_COMPLEXIO_IRQENABLE 0x60 - -/* Shared bits across CSI2_COMPLEXIO_IRQENABLE and IRQSTATUS */ -#define CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT BIT(26) -#define CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER BIT(25) -#define CSI2_COMPLEXIO_IRQ_STATEULPM5 BIT(24) -#define CSI2_COMPLEXIO_IRQ_STATEULPM4 BIT(23) -#define CSI2_COMPLEXIO_IRQ_STATEULPM3 BIT(22) -#define CSI2_COMPLEXIO_IRQ_STATEULPM2 BIT(21) -#define CSI2_COMPLEXIO_IRQ_STATEULPM1 BIT(20) -#define CSI2_COMPLEXIO_IRQ_ERRCONTROL5 BIT(19) -#define CSI2_COMPLEXIO_IRQ_ERRCONTROL4 BIT(18) -#define CSI2_COMPLEXIO_IRQ_ERRCONTROL3 BIT(17) -#define CSI2_COMPLEXIO_IRQ_ERRCONTROL2 BIT(16) -#define CSI2_COMPLEXIO_IRQ_ERRCONTROL1 BIT(15) -#define CSI2_COMPLEXIO_IRQ_ERRESC5 BIT(14) -#define CSI2_COMPLEXIO_IRQ_ERRESC4 BIT(13) -#define CSI2_COMPLEXIO_IRQ_ERRESC3 BIT(12) -#define CSI2_COMPLEXIO_IRQ_ERRESC2 BIT(11) -#define CSI2_COMPLEXIO_IRQ_ERRESC1 BIT(10) -#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5 BIT(9) -#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4 BIT(8) -#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3 BIT(7) -#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2 BIT(6) -#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1 BIT(5) -#define CSI2_COMPLEXIO_IRQ_ERRSOTHS5 BIT(4) -#define CSI2_COMPLEXIO_IRQ_ERRSOTHS4 BIT(3) -#define CSI2_COMPLEXIO_IRQ_ERRSOTHS3 BIT(2) -#define CSI2_COMPLEXIO_IRQ_ERRSOTHS2 BIT(1) -#define CSI2_COMPLEXIO_IRQ_ERRSOTHS1 BIT(0) - -#define CSI2_DBG_P 0x68 - -#define CSI2_TIMING 0x6c -#define CSI2_TIMING_FORCE_RX_MODE_IO1 BIT(15) -#define CSI2_TIMING_STOP_STATE_X16_IO1 BIT(14) -#define CSI2_TIMING_STOP_STATE_X4_IO1 BIT(13) -#define CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK (0x1fff << 0) -#define CSI2_TIMING_STOP_STATE_COUNTER_IO1_SHIFT 0 - -#define CSI2_CTX_CTRL1(i) (0x70 + (0x20 * (i))) -#define CSI2_CTX_CTRL1_GENERIC BIT(30) -#define CSI2_CTX_CTRL1_TRANSCODE (0xf << 24) -#define CSI2_CTX_CTRL1_FEC_NUMBER_MASK (0xff << 16) -#define CSI2_CTX_CTRL1_COUNT_MASK (0xff << 8) -#define CSI2_CTX_CTRL1_COUNT_SHIFT 8 -#define CSI2_CTX_CTRL1_EOF_EN BIT(7) -#define CSI2_CTX_CTRL1_EOL_EN BIT(6) -#define CSI2_CTX_CTRL1_CS_EN BIT(5) -#define CSI2_CTX_CTRL1_COUNT_UNLOCK BIT(4) -#define CSI2_CTX_CTRL1_PING_PONG BIT(3) -#define CSI2_CTX_CTRL1_CTX_EN BIT(0) - -#define CSI2_CTX_CTRL2(i) (0x74 + (0x20 * (i))) -#define CSI2_CTX_CTRL2_FRAME_MASK (0xffff << 16) -#define CSI2_CTX_CTRL2_FRAME_SHIFT 16 -#define CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13 -#define CSI2_CTX_CTRL2_USER_DEF_MAP_MASK \ - (0x3 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT) -#define CSI2_CTX_CTRL2_VIRTUAL_ID_MASK (3 << 11) -#define CSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT 11 -#define CSI2_CTX_CTRL2_DPCM_PRED (1 << 10) -#define CSI2_CTX_CTRL2_FORMAT_MASK (0x3ff << 0) -#define CSI2_CTX_CTRL2_FORMAT_SHIFT 0 - -#define CSI2_CTX_DAT_OFST(i) (0x78 + (0x20 * (i))) -#define CSI2_CTX_DAT_OFST_MASK (0xfff << 5) - -#define CSI2_CTX_PING_ADDR(i) (0x7c + (0x20 * (i))) -#define CSI2_CTX_PING_ADDR_MASK 0xffffffe0 - -#define CSI2_CTX_PONG_ADDR(i) (0x80 + (0x20 * (i))) -#define CSI2_CTX_PONG_ADDR_MASK CSI2_CTX_PING_ADDR_MASK - -#define CSI2_CTX_IRQENABLE(i) (0x84 + (0x20 * (i))) -#define CSI2_CTX_IRQSTATUS(i) (0x88 + (0x20 * (i))) - -#define CSI2_CTX_CTRL3(i) (0x8c + (0x20 * (i))) -#define CSI2_CTX_CTRL3_ALPHA_SHIFT 5 -#define CSI2_CTX_CTRL3_ALPHA_MASK \ - (0x3fff << CSI2_CTX_CTRL3_ALPHA_SHIFT) - -/* Shared bits across CSI2_CTX_IRQENABLE and IRQSTATUS */ -#define CSI2_CTX_IRQ_ECC_CORRECTION BIT(8) -#define CSI2_CTX_IRQ_LINE_NUMBER BIT(7) -#define CSI2_CTX_IRQ_FRAME_NUMBER BIT(6) -#define CSI2_CTX_IRQ_CS BIT(5) -#define CSI2_CTX_IRQ_LE BIT(3) -#define CSI2_CTX_IRQ_LS BIT(2) -#define CSI2_CTX_IRQ_FE BIT(1) -#define CSI2_CTX_IRQ_FS BIT(0) - -/* ISS BTE */ -#define BTE_CTRL (0x0030) -#define BTE_CTRL_BW_LIMITER_MASK (0x3ff << 22) -#define BTE_CTRL_BW_LIMITER_SHIFT 22 - -/* ISS ISP_SYS1 */ -#define ISP5_REVISION (0x0000) -#define ISP5_SYSCONFIG (0x0010) -#define ISP5_SYSCONFIG_STANDBYMODE_MASK (3 << 4) -#define ISP5_SYSCONFIG_STANDBYMODE_FORCE (0 << 4) -#define ISP5_SYSCONFIG_STANDBYMODE_NO (1 << 4) -#define ISP5_SYSCONFIG_STANDBYMODE_SMART (2 << 4) -#define ISP5_SYSCONFIG_SOFTRESET (1 << 1) - -#define ISP5_IRQSTATUS(i) (0x0028 + (0x10 * (i))) -#define ISP5_IRQENABLE_SET(i) (0x002c + (0x10 * (i))) -#define ISP5_IRQENABLE_CLR(i) (0x0030 + (0x10 * (i))) - -/* Bits shared for ISP5_IRQ* registers */ -#define ISP5_IRQ_OCP_ERR BIT(31) -#define ISP5_IRQ_IPIPE_INT_DPC_RNEW1 BIT(29) -#define ISP5_IRQ_IPIPE_INT_DPC_RNEW0 BIT(28) -#define ISP5_IRQ_IPIPE_INT_DPC_INIT BIT(27) -#define ISP5_IRQ_IPIPE_INT_EOF BIT(25) -#define ISP5_IRQ_H3A_INT_EOF BIT(24) -#define ISP5_IRQ_RSZ_INT_EOF1 BIT(23) -#define ISP5_IRQ_RSZ_INT_EOF0 BIT(22) -#define ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR BIT(19) -#define ISP5_IRQ_RSZ_FIFO_OVF BIT(18) -#define ISP5_IRQ_RSZ_INT_CYC_RSZB BIT(17) -#define ISP5_IRQ_RSZ_INT_CYC_RSZA BIT(16) -#define ISP5_IRQ_RSZ_INT_DMA BIT(15) -#define ISP5_IRQ_RSZ_INT_LAST_PIX BIT(14) -#define ISP5_IRQ_RSZ_INT_REG BIT(13) -#define ISP5_IRQ_H3A_INT BIT(12) -#define ISP5_IRQ_AF_INT BIT(11) -#define ISP5_IRQ_AEW_INT BIT(10) -#define ISP5_IRQ_IPIPEIF_IRQ BIT(9) -#define ISP5_IRQ_IPIPE_INT_HST BIT(8) -#define ISP5_IRQ_IPIPE_INT_BSC BIT(7) -#define ISP5_IRQ_IPIPE_INT_DMA BIT(6) -#define ISP5_IRQ_IPIPE_INT_LAST_PIX BIT(5) -#define ISP5_IRQ_IPIPE_INT_REG BIT(4) -#define ISP5_IRQ_ISIF_INT(i) BIT(i) - -#define ISP5_CTRL (0x006c) -#define ISP5_CTRL_MSTANDBY BIT(24) -#define ISP5_CTRL_VD_PULSE_EXT BIT(23) -#define ISP5_CTRL_MSTANDBY_WAIT BIT(20) -#define ISP5_CTRL_BL_CLK_ENABLE BIT(15) -#define ISP5_CTRL_ISIF_CLK_ENABLE BIT(14) -#define ISP5_CTRL_H3A_CLK_ENABLE BIT(13) -#define ISP5_CTRL_RSZ_CLK_ENABLE BIT(12) -#define ISP5_CTRL_IPIPE_CLK_ENABLE BIT(11) -#define ISP5_CTRL_IPIPEIF_CLK_ENABLE BIT(10) -#define ISP5_CTRL_SYNC_ENABLE BIT(9) -#define ISP5_CTRL_PSYNC_CLK_SEL BIT(8) - -/* ISS ISP ISIF register offsets */ -#define ISIF_SYNCEN (0x0000) -#define ISIF_SYNCEN_DWEN BIT(1) -#define ISIF_SYNCEN_SYEN BIT(0) - -#define ISIF_MODESET (0x0004) -#define ISIF_MODESET_INPMOD_MASK (3 << 12) -#define ISIF_MODESET_INPMOD_RAW (0 << 12) -#define ISIF_MODESET_INPMOD_YCBCR16 (1 << 12) -#define ISIF_MODESET_INPMOD_YCBCR8 (2 << 12) -#define ISIF_MODESET_CCDW_MASK (7 << 8) -#define ISIF_MODESET_CCDW_2BIT (2 << 8) -#define ISIF_MODESET_CCDMD (1 << 7) -#define ISIF_MODESET_SWEN (1 << 5) -#define ISIF_MODESET_HDPOL (1 << 3) -#define ISIF_MODESET_VDPOL (1 << 2) - -#define ISIF_SPH (0x0018) -#define ISIF_SPH_MASK (0x7fff) - -#define ISIF_LNH (0x001c) -#define ISIF_LNH_MASK (0x7fff) - -#define ISIF_LNV (0x0028) -#define ISIF_LNV_MASK (0x7fff) - -#define ISIF_HSIZE (0x0034) -#define ISIF_HSIZE_ADCR BIT(12) -#define ISIF_HSIZE_HSIZE_MASK (0xfff) - -#define ISIF_CADU (0x003c) -#define ISIF_CADU_MASK (0x7ff) - -#define ISIF_CADL (0x0040) -#define ISIF_CADL_MASK (0xffff) - -#define ISIF_CCOLP (0x004c) -#define ISIF_CCOLP_CP0_F0_R (0 << 6) -#define ISIF_CCOLP_CP0_F0_GR (1 << 6) -#define ISIF_CCOLP_CP0_F0_B (3 << 6) -#define ISIF_CCOLP_CP0_F0_GB (2 << 6) -#define ISIF_CCOLP_CP1_F0_R (0 << 4) -#define ISIF_CCOLP_CP1_F0_GR (1 << 4) -#define ISIF_CCOLP_CP1_F0_B (3 << 4) -#define ISIF_CCOLP_CP1_F0_GB (2 << 4) -#define ISIF_CCOLP_CP2_F0_R (0 << 2) -#define ISIF_CCOLP_CP2_F0_GR (1 << 2) -#define ISIF_CCOLP_CP2_F0_B (3 << 2) -#define ISIF_CCOLP_CP2_F0_GB (2 << 2) -#define ISIF_CCOLP_CP3_F0_R (0 << 0) -#define ISIF_CCOLP_CP3_F0_GR (1 << 0) -#define ISIF_CCOLP_CP3_F0_B (3 << 0) -#define ISIF_CCOLP_CP3_F0_GB (2 << 0) - -#define ISIF_VDINT(i) (0x0070 + (i) * 4) -#define ISIF_VDINT_MASK (0x7fff) - -#define ISIF_CGAMMAWD (0x0080) -#define ISIF_CGAMMAWD_GWDI_MASK (0xf << 1) -#define ISIF_CGAMMAWD_GWDI(bpp) ((16 - (bpp)) << 1) - -#define ISIF_CCDCFG (0x0088) -#define ISIF_CCDCFG_Y8POS BIT(11) - -/* ISS ISP IPIPEIF register offsets */ -#define IPIPEIF_ENABLE (0x0000) - -#define IPIPEIF_CFG1 (0x0004) -#define IPIPEIF_CFG1_INPSRC1_MASK (3 << 14) -#define IPIPEIF_CFG1_INPSRC1_VPORT_RAW (0 << 14) -#define IPIPEIF_CFG1_INPSRC1_SDRAM_RAW (1 << 14) -#define IPIPEIF_CFG1_INPSRC1_ISIF_DARKFM (2 << 14) -#define IPIPEIF_CFG1_INPSRC1_SDRAM_YUV (3 << 14) -#define IPIPEIF_CFG1_INPSRC2_MASK (3 << 2) -#define IPIPEIF_CFG1_INPSRC2_ISIF (0 << 2) -#define IPIPEIF_CFG1_INPSRC2_SDRAM_RAW (1 << 2) -#define IPIPEIF_CFG1_INPSRC2_ISIF_DARKFM (2 << 2) -#define IPIPEIF_CFG1_INPSRC2_SDRAM_YUV (3 << 2) - -#define IPIPEIF_CFG2 (0x0030) -#define IPIPEIF_CFG2_YUV8P BIT(7) -#define IPIPEIF_CFG2_YUV8 BIT(6) -#define IPIPEIF_CFG2_YUV16 BIT(3) -#define IPIPEIF_CFG2_VDPOL BIT(2) -#define IPIPEIF_CFG2_HDPOL BIT(1) -#define IPIPEIF_CFG2_INTSW BIT(0) - -#define IPIPEIF_CLKDIV (0x0040) - -/* ISS ISP IPIPE register offsets */ -#define IPIPE_SRC_EN (0x0000) -#define IPIPE_SRC_EN_EN BIT(0) - -#define IPIPE_SRC_MODE (0x0004) -#define IPIPE_SRC_MODE_WRT BIT(1) -#define IPIPE_SRC_MODE_OST BIT(0) - -#define IPIPE_SRC_FMT (0x0008) -#define IPIPE_SRC_FMT_RAW2YUV (0 << 0) -#define IPIPE_SRC_FMT_RAW2RAW (1 << 0) -#define IPIPE_SRC_FMT_RAW2STATS (2 << 0) -#define IPIPE_SRC_FMT_YUV2YUV (3 << 0) - -#define IPIPE_SRC_COL (0x000c) -#define IPIPE_SRC_COL_OO_R (0 << 6) -#define IPIPE_SRC_COL_OO_GR (1 << 6) -#define IPIPE_SRC_COL_OO_B (3 << 6) -#define IPIPE_SRC_COL_OO_GB (2 << 6) -#define IPIPE_SRC_COL_OE_R (0 << 4) -#define IPIPE_SRC_COL_OE_GR (1 << 4) -#define IPIPE_SRC_COL_OE_B (3 << 4) -#define IPIPE_SRC_COL_OE_GB (2 << 4) -#define IPIPE_SRC_COL_EO_R (0 << 2) -#define IPIPE_SRC_COL_EO_GR (1 << 2) -#define IPIPE_SRC_COL_EO_B (3 << 2) -#define IPIPE_SRC_COL_EO_GB (2 << 2) -#define IPIPE_SRC_COL_EE_R (0 << 0) -#define IPIPE_SRC_COL_EE_GR (1 << 0) -#define IPIPE_SRC_COL_EE_B (3 << 0) -#define IPIPE_SRC_COL_EE_GB (2 << 0) - -#define IPIPE_SRC_VPS (0x0010) -#define IPIPE_SRC_VPS_MASK (0xffff) - -#define IPIPE_SRC_VSZ (0x0014) -#define IPIPE_SRC_VSZ_MASK (0x1fff) - -#define IPIPE_SRC_HPS (0x0018) -#define IPIPE_SRC_HPS_MASK (0xffff) - -#define IPIPE_SRC_HSZ (0x001c) -#define IPIPE_SRC_HSZ_MASK (0x1ffe) - -#define IPIPE_SEL_SBU (0x0020) - -#define IPIPE_SRC_STA (0x0024) - -#define IPIPE_GCK_MMR (0x0028) -#define IPIPE_GCK_MMR_REG BIT(0) - -#define IPIPE_GCK_PIX (0x002c) -#define IPIPE_GCK_PIX_G3 BIT(3) -#define IPIPE_GCK_PIX_G2 BIT(2) -#define IPIPE_GCK_PIX_G1 BIT(1) -#define IPIPE_GCK_PIX_G0 BIT(0) - -#define IPIPE_DPC_LUT_EN (0x0034) -#define IPIPE_DPC_LUT_SEL (0x0038) -#define IPIPE_DPC_LUT_ADR (0x003c) -#define IPIPE_DPC_LUT_SIZ (0x0040) - -#define IPIPE_DPC_OTF_EN (0x0044) -#define IPIPE_DPC_OTF_TYP (0x0048) -#define IPIPE_DPC_OTF_2_D_THR_R (0x004c) -#define IPIPE_DPC_OTF_2_D_THR_GR (0x0050) -#define IPIPE_DPC_OTF_2_D_THR_GB (0x0054) -#define IPIPE_DPC_OTF_2_D_THR_B (0x0058) -#define IPIPE_DPC_OTF_2_C_THR_R (0x005c) -#define IPIPE_DPC_OTF_2_C_THR_GR (0x0060) -#define IPIPE_DPC_OTF_2_C_THR_GB (0x0064) -#define IPIPE_DPC_OTF_2_C_THR_B (0x0068) -#define IPIPE_DPC_OTF_3_SHF (0x006c) -#define IPIPE_DPC_OTF_3_D_THR (0x0070) -#define IPIPE_DPC_OTF_3_D_SPL (0x0074) -#define IPIPE_DPC_OTF_3_D_MIN (0x0078) -#define IPIPE_DPC_OTF_3_D_MAX (0x007c) -#define IPIPE_DPC_OTF_3_C_THR (0x0080) -#define IPIPE_DPC_OTF_3_C_SLP (0x0084) -#define IPIPE_DPC_OTF_3_C_MIN (0x0088) -#define IPIPE_DPC_OTF_3_C_MAX (0x008c) - -#define IPIPE_LSC_VOFT (0x0090) -#define IPIPE_LSC_VA2 (0x0094) -#define IPIPE_LSC_VA1 (0x0098) -#define IPIPE_LSC_VS (0x009c) -#define IPIPE_LSC_HOFT (0x00a0) -#define IPIPE_LSC_HA2 (0x00a4) -#define IPIPE_LSC_HA1 (0x00a8) -#define IPIPE_LSC_HS (0x00ac) -#define IPIPE_LSC_GAN_R (0x00b0) -#define IPIPE_LSC_GAN_GR (0x00b4) -#define IPIPE_LSC_GAN_GB (0x00b8) -#define IPIPE_LSC_GAN_B (0x00bc) -#define IPIPE_LSC_OFT_R (0x00c0) -#define IPIPE_LSC_OFT_GR (0x00c4) -#define IPIPE_LSC_OFT_GB (0x00c8) -#define IPIPE_LSC_OFT_B (0x00cc) -#define IPIPE_LSC_SHF (0x00d0) -#define IPIPE_LSC_MAX (0x00d4) - -#define IPIPE_D2F_1ST_EN (0x00d8) -#define IPIPE_D2F_1ST_TYP (0x00dc) -#define IPIPE_D2F_1ST_THR_00 (0x00e0) -#define IPIPE_D2F_1ST_THR_01 (0x00e4) -#define IPIPE_D2F_1ST_THR_02 (0x00e8) -#define IPIPE_D2F_1ST_THR_03 (0x00ec) -#define IPIPE_D2F_1ST_THR_04 (0x00f0) -#define IPIPE_D2F_1ST_THR_05 (0x00f4) -#define IPIPE_D2F_1ST_THR_06 (0x00f8) -#define IPIPE_D2F_1ST_THR_07 (0x00fc) -#define IPIPE_D2F_1ST_STR_00 (0x0100) -#define IPIPE_D2F_1ST_STR_01 (0x0104) -#define IPIPE_D2F_1ST_STR_02 (0x0108) -#define IPIPE_D2F_1ST_STR_03 (0x010c) -#define IPIPE_D2F_1ST_STR_04 (0x0110) -#define IPIPE_D2F_1ST_STR_05 (0x0114) -#define IPIPE_D2F_1ST_STR_06 (0x0118) -#define IPIPE_D2F_1ST_STR_07 (0x011c) -#define IPIPE_D2F_1ST_SPR_00 (0x0120) -#define IPIPE_D2F_1ST_SPR_01 (0x0124) -#define IPIPE_D2F_1ST_SPR_02 (0x0128) -#define IPIPE_D2F_1ST_SPR_03 (0x012c) -#define IPIPE_D2F_1ST_SPR_04 (0x0130) -#define IPIPE_D2F_1ST_SPR_05 (0x0134) -#define IPIPE_D2F_1ST_SPR_06 (0x0138) -#define IPIPE_D2F_1ST_SPR_07 (0x013c) -#define IPIPE_D2F_1ST_EDG_MIN (0x0140) -#define IPIPE_D2F_1ST_EDG_MAX (0x0144) -#define IPIPE_D2F_2ND_EN (0x0148) -#define IPIPE_D2F_2ND_TYP (0x014c) -#define IPIPE_D2F_2ND_THR00 (0x0150) -#define IPIPE_D2F_2ND_THR01 (0x0154) -#define IPIPE_D2F_2ND_THR02 (0x0158) -#define IPIPE_D2F_2ND_THR03 (0x015c) -#define IPIPE_D2F_2ND_THR04 (0x0160) -#define IPIPE_D2F_2ND_THR05 (0x0164) -#define IPIPE_D2F_2ND_THR06 (0x0168) -#define IPIPE_D2F_2ND_THR07 (0x016c) -#define IPIPE_D2F_2ND_STR_00 (0x0170) -#define IPIPE_D2F_2ND_STR_01 (0x0174) -#define IPIPE_D2F_2ND_STR_02 (0x0178) -#define IPIPE_D2F_2ND_STR_03 (0x017c) -#define IPIPE_D2F_2ND_STR_04 (0x0180) -#define IPIPE_D2F_2ND_STR_05 (0x0184) -#define IPIPE_D2F_2ND_STR_06 (0x0188) -#define IPIPE_D2F_2ND_STR_07 (0x018c) -#define IPIPE_D2F_2ND_SPR_00 (0x0190) -#define IPIPE_D2F_2ND_SPR_01 (0x0194) -#define IPIPE_D2F_2ND_SPR_02 (0x0198) -#define IPIPE_D2F_2ND_SPR_03 (0x019c) -#define IPIPE_D2F_2ND_SPR_04 (0x01a0) -#define IPIPE_D2F_2ND_SPR_05 (0x01a4) -#define IPIPE_D2F_2ND_SPR_06 (0x01a8) -#define IPIPE_D2F_2ND_SPR_07 (0x01ac) -#define IPIPE_D2F_2ND_EDG_MIN (0x01b0) -#define IPIPE_D2F_2ND_EDG_MAX (0x01b4) - -#define IPIPE_GIC_EN (0x01b8) -#define IPIPE_GIC_TYP (0x01bc) -#define IPIPE_GIC_GAN (0x01c0) -#define IPIPE_GIC_NFGAIN (0x01c4) -#define IPIPE_GIC_THR (0x01c8) -#define IPIPE_GIC_SLP (0x01cc) - -#define IPIPE_WB2_OFT_R (0x01d0) -#define IPIPE_WB2_OFT_GR (0x01d4) -#define IPIPE_WB2_OFT_GB (0x01d8) -#define IPIPE_WB2_OFT_B (0x01dc) - -#define IPIPE_WB2_WGN_R (0x01e0) -#define IPIPE_WB2_WGN_GR (0x01e4) -#define IPIPE_WB2_WGN_GB (0x01e8) -#define IPIPE_WB2_WGN_B (0x01ec) - -#define IPIPE_CFA_MODE (0x01f0) -#define IPIPE_CFA_2DIR_HPF_THR (0x01f4) -#define IPIPE_CFA_2DIR_HPF_SLP (0x01f8) -#define IPIPE_CFA_2DIR_MIX_THR (0x01fc) -#define IPIPE_CFA_2DIR_MIX_SLP (0x0200) -#define IPIPE_CFA_2DIR_DIR_TRH (0x0204) -#define IPIPE_CFA_2DIR_DIR_SLP (0x0208) -#define IPIPE_CFA_2DIR_NDWT (0x020c) -#define IPIPE_CFA_MONO_HUE_FRA (0x0210) -#define IPIPE_CFA_MONO_EDG_THR (0x0214) -#define IPIPE_CFA_MONO_THR_MIN (0x0218) - -#define IPIPE_CFA_MONO_THR_SLP (0x021c) -#define IPIPE_CFA_MONO_SLP_MIN (0x0220) -#define IPIPE_CFA_MONO_SLP_SLP (0x0224) -#define IPIPE_CFA_MONO_LPWT (0x0228) - -#define IPIPE_RGB1_MUL_RR (0x022c) -#define IPIPE_RGB1_MUL_GR (0x0230) -#define IPIPE_RGB1_MUL_BR (0x0234) -#define IPIPE_RGB1_MUL_RG (0x0238) -#define IPIPE_RGB1_MUL_GG (0x023c) -#define IPIPE_RGB1_MUL_BG (0x0240) -#define IPIPE_RGB1_MUL_RB (0x0244) -#define IPIPE_RGB1_MUL_GB (0x0248) -#define IPIPE_RGB1_MUL_BB (0x024c) -#define IPIPE_RGB1_OFT_OR (0x0250) -#define IPIPE_RGB1_OFT_OG (0x0254) -#define IPIPE_RGB1_OFT_OB (0x0258) -#define IPIPE_GMM_CFG (0x025c) -#define IPIPE_RGB2_MUL_RR (0x0260) -#define IPIPE_RGB2_MUL_GR (0x0264) -#define IPIPE_RGB2_MUL_BR (0x0268) -#define IPIPE_RGB2_MUL_RG (0x026c) -#define IPIPE_RGB2_MUL_GG (0x0270) -#define IPIPE_RGB2_MUL_BG (0x0274) -#define IPIPE_RGB2_MUL_RB (0x0278) -#define IPIPE_RGB2_MUL_GB (0x027c) -#define IPIPE_RGB2_MUL_BB (0x0280) -#define IPIPE_RGB2_OFT_OR (0x0284) -#define IPIPE_RGB2_OFT_OG (0x0288) -#define IPIPE_RGB2_OFT_OB (0x028c) - -#define IPIPE_YUV_ADJ (0x0294) -#define IPIPE_YUV_MUL_RY (0x0298) -#define IPIPE_YUV_MUL_GY (0x029c) -#define IPIPE_YUV_MUL_BY (0x02a0) -#define IPIPE_YUV_MUL_RCB (0x02a4) -#define IPIPE_YUV_MUL_GCB (0x02a8) -#define IPIPE_YUV_MUL_BCB (0x02ac) -#define IPIPE_YUV_MUL_RCR (0x02b0) -#define IPIPE_YUV_MUL_GCR (0x02b4) -#define IPIPE_YUV_MUL_BCR (0x02b8) -#define IPIPE_YUV_OFT_Y (0x02bc) -#define IPIPE_YUV_OFT_CB (0x02c0) -#define IPIPE_YUV_OFT_CR (0x02c4) - -#define IPIPE_YUV_PHS (0x02c8) -#define IPIPE_YUV_PHS_LPF BIT(1) -#define IPIPE_YUV_PHS_POS BIT(0) - -#define IPIPE_YEE_EN (0x02d4) -#define IPIPE_YEE_TYP (0x02d8) -#define IPIPE_YEE_SHF (0x02dc) -#define IPIPE_YEE_MUL_00 (0x02e0) -#define IPIPE_YEE_MUL_01 (0x02e4) -#define IPIPE_YEE_MUL_02 (0x02e8) -#define IPIPE_YEE_MUL_10 (0x02ec) -#define IPIPE_YEE_MUL_11 (0x02f0) -#define IPIPE_YEE_MUL_12 (0x02f4) -#define IPIPE_YEE_MUL_20 (0x02f8) -#define IPIPE_YEE_MUL_21 (0x02fc) -#define IPIPE_YEE_MUL_22 (0x0300) -#define IPIPE_YEE_THR (0x0304) -#define IPIPE_YEE_E_GAN (0x0308) -#define IPIPE_YEE_E_THR_1 (0x030c) -#define IPIPE_YEE_E_THR_2 (0x0310) -#define IPIPE_YEE_G_GAN (0x0314) -#define IPIPE_YEE_G_OFT (0x0318) - -#define IPIPE_CAR_EN (0x031c) -#define IPIPE_CAR_TYP (0x0320) -#define IPIPE_CAR_SW (0x0324) -#define IPIPE_CAR_HPF_TYP (0x0328) -#define IPIPE_CAR_HPF_SHF (0x032c) -#define IPIPE_CAR_HPF_THR (0x0330) -#define IPIPE_CAR_GN1_GAN (0x0334) -#define IPIPE_CAR_GN1_SHF (0x0338) -#define IPIPE_CAR_GN1_MIN (0x033c) -#define IPIPE_CAR_GN2_GAN (0x0340) -#define IPIPE_CAR_GN2_SHF (0x0344) -#define IPIPE_CAR_GN2_MIN (0x0348) -#define IPIPE_CGS_EN (0x034c) -#define IPIPE_CGS_GN1_L_THR (0x0350) -#define IPIPE_CGS_GN1_L_GAIN (0x0354) -#define IPIPE_CGS_GN1_L_SHF (0x0358) -#define IPIPE_CGS_GN1_L_MIN (0x035c) -#define IPIPE_CGS_GN1_H_THR (0x0360) -#define IPIPE_CGS_GN1_H_GAIN (0x0364) -#define IPIPE_CGS_GN1_H_SHF (0x0368) -#define IPIPE_CGS_GN1_H_MIN (0x036c) -#define IPIPE_CGS_GN2_L_THR (0x0370) -#define IPIPE_CGS_GN2_L_GAIN (0x0374) -#define IPIPE_CGS_GN2_L_SHF (0x0378) -#define IPIPE_CGS_GN2_L_MIN (0x037c) - -#define IPIPE_BOX_EN (0x0380) -#define IPIPE_BOX_MODE (0x0384) -#define IPIPE_BOX_TYP (0x0388) -#define IPIPE_BOX_SHF (0x038c) -#define IPIPE_BOX_SDR_SAD_H (0x0390) -#define IPIPE_BOX_SDR_SAD_L (0x0394) - -#define IPIPE_HST_EN (0x039c) -#define IPIPE_HST_MODE (0x03a0) -#define IPIPE_HST_SEL (0x03a4) -#define IPIPE_HST_PARA (0x03a8) -#define IPIPE_HST_0_VPS (0x03ac) -#define IPIPE_HST_0_VSZ (0x03b0) -#define IPIPE_HST_0_HPS (0x03b4) -#define IPIPE_HST_0_HSZ (0x03b8) -#define IPIPE_HST_1_VPS (0x03bc) -#define IPIPE_HST_1_VSZ (0x03c0) -#define IPIPE_HST_1_HPS (0x03c4) -#define IPIPE_HST_1_HSZ (0x03c8) -#define IPIPE_HST_2_VPS (0x03cc) -#define IPIPE_HST_2_VSZ (0x03d0) -#define IPIPE_HST_2_HPS (0x03d4) -#define IPIPE_HST_2_HSZ (0x03d8) -#define IPIPE_HST_3_VPS (0x03dc) -#define IPIPE_HST_3_VSZ (0x03e0) -#define IPIPE_HST_3_HPS (0x03e4) -#define IPIPE_HST_3_HSZ (0x03e8) -#define IPIPE_HST_TBL (0x03ec) -#define IPIPE_HST_MUL_R (0x03f0) -#define IPIPE_HST_MUL_GR (0x03f4) -#define IPIPE_HST_MUL_GB (0x03f8) -#define IPIPE_HST_MUL_B (0x03fc) - -#define IPIPE_BSC_EN (0x0400) -#define IPIPE_BSC_MODE (0x0404) -#define IPIPE_BSC_TYP (0x0408) -#define IPIPE_BSC_ROW_VCT (0x040c) -#define IPIPE_BSC_ROW_SHF (0x0410) -#define IPIPE_BSC_ROW_VPO (0x0414) -#define IPIPE_BSC_ROW_VNU (0x0418) -#define IPIPE_BSC_ROW_VSKIP (0x041c) -#define IPIPE_BSC_ROW_HPO (0x0420) -#define IPIPE_BSC_ROW_HNU (0x0424) -#define IPIPE_BSC_ROW_HSKIP (0x0428) -#define IPIPE_BSC_COL_VCT (0x042c) -#define IPIPE_BSC_COL_SHF (0x0430) -#define IPIPE_BSC_COL_VPO (0x0434) -#define IPIPE_BSC_COL_VNU (0x0438) -#define IPIPE_BSC_COL_VSKIP (0x043c) -#define IPIPE_BSC_COL_HPO (0x0440) -#define IPIPE_BSC_COL_HNU (0x0444) -#define IPIPE_BSC_COL_HSKIP (0x0448) - -#define IPIPE_BSC_EN (0x0400) - -/* ISS ISP Resizer register offsets */ -#define RSZ_REVISION (0x0000) -#define RSZ_SYSCONFIG (0x0004) -#define RSZ_SYSCONFIG_RSZB_CLK_EN BIT(9) -#define RSZ_SYSCONFIG_RSZA_CLK_EN BIT(8) - -#define RSZ_IN_FIFO_CTRL (0x000c) -#define RSZ_IN_FIFO_CTRL_THRLD_LOW_MASK (0x1ff << 16) -#define RSZ_IN_FIFO_CTRL_THRLD_LOW_SHIFT 16 -#define RSZ_IN_FIFO_CTRL_THRLD_HIGH_MASK (0x1ff << 0) -#define RSZ_IN_FIFO_CTRL_THRLD_HIGH_SHIFT 0 - -#define RSZ_FRACDIV (0x0008) -#define RSZ_FRACDIV_MASK (0xffff) - -#define RSZ_SRC_EN (0x0020) -#define RSZ_SRC_EN_SRC_EN BIT(0) - -#define RSZ_SRC_MODE (0x0024) -#define RSZ_SRC_MODE_OST BIT(0) -#define RSZ_SRC_MODE_WRT BIT(1) - -#define RSZ_SRC_FMT0 (0x0028) -#define RSZ_SRC_FMT0_BYPASS BIT(1) -#define RSZ_SRC_FMT0_SEL BIT(0) - -#define RSZ_SRC_FMT1 (0x002c) -#define RSZ_SRC_FMT1_IN420 BIT(1) - -#define RSZ_SRC_VPS (0x0030) -#define RSZ_SRC_VSZ (0x0034) -#define RSZ_SRC_HPS (0x0038) -#define RSZ_SRC_HSZ (0x003c) -#define RSZ_DMA_RZA (0x0040) -#define RSZ_DMA_RZB (0x0044) -#define RSZ_DMA_STA (0x0048) -#define RSZ_GCK_MMR (0x004c) -#define RSZ_GCK_MMR_MMR BIT(0) - -#define RSZ_GCK_SDR (0x0054) -#define RSZ_GCK_SDR_CORE BIT(0) - -#define RSZ_IRQ_RZA (0x0058) -#define RSZ_IRQ_RZA_MASK (0x1fff) - -#define RSZ_IRQ_RZB (0x005c) -#define RSZ_IRQ_RZB_MASK (0x1fff) - -#define RSZ_YUV_Y_MIN (0x0060) -#define RSZ_YUV_Y_MAX (0x0064) -#define RSZ_YUV_C_MIN (0x0068) -#define RSZ_YUV_C_MAX (0x006c) - -#define RSZ_SEQ (0x0074) -#define RSZ_SEQ_HRVB BIT(2) -#define RSZ_SEQ_HRVA BIT(0) - -#define RZA_EN (0x0078) -#define RZA_MODE (0x007c) -#define RZA_MODE_ONE_SHOT BIT(0) - -#define RZA_420 (0x0080) -#define RZA_I_VPS (0x0084) -#define RZA_I_HPS (0x0088) -#define RZA_O_VSZ (0x008c) -#define RZA_O_HSZ (0x0090) -#define RZA_V_PHS_Y (0x0094) -#define RZA_V_PHS_C (0x0098) -#define RZA_V_DIF (0x009c) -#define RZA_V_TYP (0x00a0) -#define RZA_V_LPF (0x00a4) -#define RZA_H_PHS (0x00a8) -#define RZA_H_DIF (0x00b0) -#define RZA_H_TYP (0x00b4) -#define RZA_H_LPF (0x00b8) -#define RZA_DWN_EN (0x00bc) -#define RZA_SDR_Y_BAD_H (0x00d0) -#define RZA_SDR_Y_BAD_L (0x00d4) -#define RZA_SDR_Y_SAD_H (0x00d8) -#define RZA_SDR_Y_SAD_L (0x00dc) -#define RZA_SDR_Y_OFT (0x00e0) -#define RZA_SDR_Y_PTR_S (0x00e4) -#define RZA_SDR_Y_PTR_E (0x00e8) -#define RZA_SDR_C_BAD_H (0x00ec) -#define RZA_SDR_C_BAD_L (0x00f0) -#define RZA_SDR_C_SAD_H (0x00f4) -#define RZA_SDR_C_SAD_L (0x00f8) -#define RZA_SDR_C_OFT (0x00fc) -#define RZA_SDR_C_PTR_S (0x0100) -#define RZA_SDR_C_PTR_E (0x0104) - -#define RZB_EN (0x0108) -#define RZB_MODE (0x010c) -#define RZB_420 (0x0110) -#define RZB_I_VPS (0x0114) -#define RZB_I_HPS (0x0118) -#define RZB_O_VSZ (0x011c) -#define RZB_O_HSZ (0x0120) - -#define RZB_V_DIF (0x012c) -#define RZB_V_TYP (0x0130) -#define RZB_V_LPF (0x0134) - -#define RZB_H_DIF (0x0140) -#define RZB_H_TYP (0x0144) -#define RZB_H_LPF (0x0148) - -#define RZB_SDR_Y_BAD_H (0x0160) -#define RZB_SDR_Y_BAD_L (0x0164) -#define RZB_SDR_Y_SAD_H (0x0168) -#define RZB_SDR_Y_SAD_L (0x016c) -#define RZB_SDR_Y_OFT (0x0170) -#define RZB_SDR_Y_PTR_S (0x0174) -#define RZB_SDR_Y_PTR_E (0x0178) -#define RZB_SDR_C_BAD_H (0x017c) -#define RZB_SDR_C_BAD_L (0x0180) -#define RZB_SDR_C_SAD_H (0x0184) -#define RZB_SDR_C_SAD_L (0x0188) - -#define RZB_SDR_C_PTR_S (0x0190) -#define RZB_SDR_C_PTR_E (0x0194) - -/* Shared Bitmasks between RZA & RZB */ -#define RSZ_EN_EN BIT(0) - -#define RSZ_420_CEN BIT(1) -#define RSZ_420_YEN BIT(0) - -#define RSZ_I_VPS_MASK (0x1fff) - -#define RSZ_I_HPS_MASK (0x1fff) - -#define RSZ_O_VSZ_MASK (0x1fff) - -#define RSZ_O_HSZ_MASK (0x1ffe) - -#define RSZ_V_PHS_Y_MASK (0x3fff) - -#define RSZ_V_PHS_C_MASK (0x3fff) - -#define RSZ_V_DIF_MASK (0x3fff) - -#define RSZ_V_TYP_C BIT(1) -#define RSZ_V_TYP_Y BIT(0) - -#define RSZ_V_LPF_C_MASK (0x3f << 6) -#define RSZ_V_LPF_C_SHIFT 6 -#define RSZ_V_LPF_Y_MASK (0x3f << 0) -#define RSZ_V_LPF_Y_SHIFT 0 - -#define RSZ_H_PHS_MASK (0x3fff) - -#define RSZ_H_DIF_MASK (0x3fff) - -#define RSZ_H_TYP_C BIT(1) -#define RSZ_H_TYP_Y BIT(0) - -#define RSZ_H_LPF_C_MASK (0x3f << 6) -#define RSZ_H_LPF_C_SHIFT 6 -#define RSZ_H_LPF_Y_MASK (0x3f << 0) -#define RSZ_H_LPF_Y_SHIFT 0 - -#define RSZ_DWN_EN_DWN_EN BIT(0) - -#endif /* _OMAP4_ISS_REGS_H_ */ diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c deleted file mode 100644 index 58e698ef910852..00000000000000 --- a/drivers/staging/media/omap4iss/iss_resizer.c +++ /dev/null @@ -1,884 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * TI OMAP4 ISS V4L2 Driver - ISP RESIZER module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "iss.h" -#include "iss_regs.h" -#include "iss_resizer.h" - -static const unsigned int resizer_fmts[] = { - MEDIA_BUS_FMT_UYVY8_1X16, - MEDIA_BUS_FMT_YUYV8_1X16, -}; - -/* - * resizer_print_status - Print current RESIZER Module register values. - * @resizer: Pointer to ISS ISP RESIZER device. - * - * Also prints other debug information stored in the RESIZER module. - */ -#define RSZ_PRINT_REGISTER(iss, name)\ - dev_dbg(iss->dev, "###RSZ " #name "=0x%08x\n", \ - iss_reg_read(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_##name)) - -#define RZA_PRINT_REGISTER(iss, name)\ - dev_dbg(iss->dev, "###RZA " #name "=0x%08x\n", \ - iss_reg_read(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_##name)) - -static void resizer_print_status(struct iss_resizer_device *resizer) -{ - struct iss_device *iss = to_iss_device(resizer); - - dev_dbg(iss->dev, "-------------RESIZER Register dump-------------\n"); - - RSZ_PRINT_REGISTER(iss, SYSCONFIG); - RSZ_PRINT_REGISTER(iss, IN_FIFO_CTRL); - RSZ_PRINT_REGISTER(iss, FRACDIV); - RSZ_PRINT_REGISTER(iss, SRC_EN); - RSZ_PRINT_REGISTER(iss, SRC_MODE); - RSZ_PRINT_REGISTER(iss, SRC_FMT0); - RSZ_PRINT_REGISTER(iss, SRC_FMT1); - RSZ_PRINT_REGISTER(iss, SRC_VPS); - RSZ_PRINT_REGISTER(iss, SRC_VSZ); - RSZ_PRINT_REGISTER(iss, SRC_HPS); - RSZ_PRINT_REGISTER(iss, SRC_HSZ); - RSZ_PRINT_REGISTER(iss, DMA_RZA); - RSZ_PRINT_REGISTER(iss, DMA_RZB); - RSZ_PRINT_REGISTER(iss, DMA_STA); - RSZ_PRINT_REGISTER(iss, GCK_MMR); - RSZ_PRINT_REGISTER(iss, GCK_SDR); - RSZ_PRINT_REGISTER(iss, IRQ_RZA); - RSZ_PRINT_REGISTER(iss, IRQ_RZB); - RSZ_PRINT_REGISTER(iss, YUV_Y_MIN); - RSZ_PRINT_REGISTER(iss, YUV_Y_MAX); - RSZ_PRINT_REGISTER(iss, YUV_C_MIN); - RSZ_PRINT_REGISTER(iss, YUV_C_MAX); - RSZ_PRINT_REGISTER(iss, SEQ); - - RZA_PRINT_REGISTER(iss, EN); - RZA_PRINT_REGISTER(iss, MODE); - RZA_PRINT_REGISTER(iss, 420); - RZA_PRINT_REGISTER(iss, I_VPS); - RZA_PRINT_REGISTER(iss, I_HPS); - RZA_PRINT_REGISTER(iss, O_VSZ); - RZA_PRINT_REGISTER(iss, O_HSZ); - RZA_PRINT_REGISTER(iss, V_PHS_Y); - RZA_PRINT_REGISTER(iss, V_PHS_C); - RZA_PRINT_REGISTER(iss, V_DIF); - RZA_PRINT_REGISTER(iss, V_TYP); - RZA_PRINT_REGISTER(iss, V_LPF); - RZA_PRINT_REGISTER(iss, H_PHS); - RZA_PRINT_REGISTER(iss, H_DIF); - RZA_PRINT_REGISTER(iss, H_TYP); - RZA_PRINT_REGISTER(iss, H_LPF); - RZA_PRINT_REGISTER(iss, DWN_EN); - RZA_PRINT_REGISTER(iss, SDR_Y_BAD_H); - RZA_PRINT_REGISTER(iss, SDR_Y_BAD_L); - RZA_PRINT_REGISTER(iss, SDR_Y_SAD_H); - RZA_PRINT_REGISTER(iss, SDR_Y_SAD_L); - RZA_PRINT_REGISTER(iss, SDR_Y_OFT); - RZA_PRINT_REGISTER(iss, SDR_Y_PTR_S); - RZA_PRINT_REGISTER(iss, SDR_Y_PTR_E); - RZA_PRINT_REGISTER(iss, SDR_C_BAD_H); - RZA_PRINT_REGISTER(iss, SDR_C_BAD_L); - RZA_PRINT_REGISTER(iss, SDR_C_SAD_H); - RZA_PRINT_REGISTER(iss, SDR_C_SAD_L); - RZA_PRINT_REGISTER(iss, SDR_C_OFT); - RZA_PRINT_REGISTER(iss, SDR_C_PTR_S); - RZA_PRINT_REGISTER(iss, SDR_C_PTR_E); - - dev_dbg(iss->dev, "-----------------------------------------------\n"); -} - -/* - * resizer_enable - Enable/Disable RESIZER. - * @enable: enable flag - * - */ -static void resizer_enable(struct iss_resizer_device *resizer, u8 enable) -{ - struct iss_device *iss = to_iss_device(resizer); - - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_EN, - RSZ_SRC_EN_SRC_EN, enable ? RSZ_SRC_EN_SRC_EN : 0); - - /* TODO: Enable RSZB */ - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_EN, RSZ_EN_EN, - enable ? RSZ_EN_EN : 0); -} - -/* ----------------------------------------------------------------------------- - * Format- and pipeline-related configuration helpers - */ - -/* - * resizer_set_outaddr - Set memory address to save output image - * @resizer: Pointer to ISP RESIZER device. - * @addr: 32-bit memory address aligned on 32 byte boundary. - * - * Sets the memory address where the output will be saved. - */ -static void resizer_set_outaddr(struct iss_resizer_device *resizer, u32 addr) -{ - struct iss_device *iss = to_iss_device(resizer); - struct v4l2_mbus_framefmt *informat, *outformat; - - informat = &resizer->formats[RESIZER_PAD_SINK]; - outformat = &resizer->formats[RESIZER_PAD_SOURCE_MEM]; - - /* Save address split in Base Address H & L */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_BAD_H, - (addr >> 16) & 0xffff); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_BAD_L, - addr & 0xffff); - - /* SAD = BAD */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_SAD_H, - (addr >> 16) & 0xffff); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_SAD_L, - addr & 0xffff); - - /* Program UV buffer address... Hardcoded to be contiguous! */ - if ((informat->code == MEDIA_BUS_FMT_UYVY8_1X16) && - (outformat->code == MEDIA_BUS_FMT_YUYV8_1_5X8)) { - u32 c_addr = addr + resizer->video_out.bpl_value - * outformat->height; - - /* Ensure Y_BAD_L[6:0] = C_BAD_L[6:0]*/ - if ((c_addr ^ addr) & 0x7f) { - c_addr &= ~0x7f; - c_addr += 0x80; - c_addr |= addr & 0x7f; - } - - /* Save address split in Base Address H & L */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_BAD_H, - (c_addr >> 16) & 0xffff); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_BAD_L, - c_addr & 0xffff); - - /* SAD = BAD */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_SAD_H, - (c_addr >> 16) & 0xffff); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_SAD_L, - c_addr & 0xffff); - } -} - -static void resizer_configure(struct iss_resizer_device *resizer) -{ - struct iss_device *iss = to_iss_device(resizer); - struct v4l2_mbus_framefmt *informat, *outformat; - - informat = &resizer->formats[RESIZER_PAD_SINK]; - outformat = &resizer->formats[RESIZER_PAD_SOURCE_MEM]; - - /* Disable pass-through more. Despite its name, the BYPASS bit controls - * pass-through mode, not bypass mode. - */ - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_FMT0, - RSZ_SRC_FMT0_BYPASS); - - /* Select RSZ input */ - iss_reg_update(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_FMT0, - RSZ_SRC_FMT0_SEL, - resizer->input == RESIZER_INPUT_IPIPEIF ? - RSZ_SRC_FMT0_SEL : 0); - - /* RSZ ignores WEN signal from IPIPE/IPIPEIF */ - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_MODE, - RSZ_SRC_MODE_WRT); - - /* Set Resizer in free-running mode */ - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_MODE, - RSZ_SRC_MODE_OST); - - /* Init Resizer A */ - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_MODE, - RZA_MODE_ONE_SHOT); - - /* Set size related things now */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_VPS, 0); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_HPS, 0); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_VSZ, - informat->height - 2); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_HSZ, - informat->width - 1); - - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_I_VPS, 0); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_I_HPS, 0); - - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_O_VSZ, - outformat->height - 2); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_O_HSZ, - outformat->width - 1); - - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_V_DIF, 0x100); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_H_DIF, 0x100); - - /* Buffer output settings */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_PTR_S, 0); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_PTR_E, - outformat->height - 1); - - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_OFT, - resizer->video_out.bpl_value); - - /* UYVY -> NV12 conversion */ - if ((informat->code == MEDIA_BUS_FMT_UYVY8_1X16) && - (outformat->code == MEDIA_BUS_FMT_YUYV8_1_5X8)) { - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_420, - RSZ_420_CEN | RSZ_420_YEN); - - /* UV Buffer output settings */ - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_PTR_S, - 0); - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_PTR_E, - outformat->height - 1); - - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_OFT, - resizer->video_out.bpl_value); - } else { - iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_420, 0); - } -} - -/* ----------------------------------------------------------------------------- - * Interrupt handling - */ - -static void resizer_isr_buffer(struct iss_resizer_device *resizer) -{ - struct iss_buffer *buffer; - - /* The whole resizer needs to be stopped. Disabling RZA only produces - * input FIFO overflows, most probably when the next frame is received. - */ - resizer_enable(resizer, 0); - - buffer = omap4iss_video_buffer_next(&resizer->video_out); - if (!buffer) - return; - - resizer_set_outaddr(resizer, buffer->iss_addr); - - resizer_enable(resizer, 1); -} - -/* - * omap4iss_resizer_isr - Configure resizer during interframe time. - * @resizer: Pointer to ISP RESIZER device. - * @events: RESIZER events - */ -void omap4iss_resizer_isr(struct iss_resizer_device *resizer, u32 events) -{ - struct iss_device *iss = to_iss_device(resizer); - struct iss_pipeline *pipe = - to_iss_pipeline(&resizer->subdev.entity); - - if (events & (ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR | - ISP5_IRQ_RSZ_FIFO_OVF)) { - dev_dbg(iss->dev, "RSZ Err: FIFO_IN_BLK:%d, FIFO_OVF:%d\n", - events & ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR ? 1 : 0, - events & ISP5_IRQ_RSZ_FIFO_OVF ? 1 : 0); - omap4iss_pipeline_cancel_stream(pipe); - } - - if (omap4iss_module_sync_is_stopping(&resizer->wait, - &resizer->stopping)) - return; - - if (events & ISP5_IRQ_RSZ_INT_DMA) - resizer_isr_buffer(resizer); -} - -/* ----------------------------------------------------------------------------- - * ISS video operations - */ - -static int resizer_video_queue(struct iss_video *video, - struct iss_buffer *buffer) -{ - struct iss_resizer_device *resizer = container_of(video, - struct iss_resizer_device, video_out); - - if (!(resizer->output & RESIZER_OUTPUT_MEMORY)) - return -ENODEV; - - resizer_set_outaddr(resizer, buffer->iss_addr); - - /* - * If streaming was enabled before there was a buffer queued - * or underrun happened in the ISR, the hardware was not enabled - * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set. - * Enable it now. - */ - if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { - resizer_enable(resizer, 1); - iss_video_dmaqueue_flags_clr(video); - } - - return 0; -} - -static const struct iss_video_operations resizer_video_ops = { - .queue = resizer_video_queue, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -/* - * resizer_set_stream - Enable/Disable streaming on the RESIZER module - * @sd: ISP RESIZER V4L2 subdevice - * @enable: Enable/disable stream - */ -static int resizer_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct iss_device *iss = to_iss_device(resizer); - struct iss_video *video_out = &resizer->video_out; - int ret = 0; - - if (resizer->state == ISS_PIPELINE_STREAM_STOPPED) { - if (enable == ISS_PIPELINE_STREAM_STOPPED) - return 0; - - omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_RSZ); - - iss_reg_set(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_GCK_MMR, - RSZ_GCK_MMR_MMR); - iss_reg_set(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_GCK_SDR, - RSZ_GCK_SDR_CORE); - - /* FIXME: Enable RSZB also */ - iss_reg_set(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SYSCONFIG, - RSZ_SYSCONFIG_RSZA_CLK_EN); - } - - switch (enable) { - case ISS_PIPELINE_STREAM_CONTINUOUS: - - resizer_configure(resizer); - resizer_print_status(resizer); - - /* - * When outputting to memory with no buffer available, let the - * buffer queue handler start the hardware. A DMA queue flag - * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is - * a buffer available. - */ - if (resizer->output & RESIZER_OUTPUT_MEMORY && - !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED)) - break; - - atomic_set(&resizer->stopping, 0); - resizer_enable(resizer, 1); - iss_video_dmaqueue_flags_clr(video_out); - break; - - case ISS_PIPELINE_STREAM_STOPPED: - if (resizer->state == ISS_PIPELINE_STREAM_STOPPED) - return 0; - if (omap4iss_module_sync_idle(&sd->entity, &resizer->wait, - &resizer->stopping)) - ret = -ETIMEDOUT; - - resizer_enable(resizer, 0); - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SYSCONFIG, - RSZ_SYSCONFIG_RSZA_CLK_EN); - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_GCK_SDR, - RSZ_GCK_SDR_CORE); - iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_GCK_MMR, - RSZ_GCK_MMR_MMR); - omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_RSZ); - iss_video_dmaqueue_flags_clr(video_out); - break; - } - - resizer->state = enable; - return ret; -} - -static struct v4l2_mbus_framefmt * -__resizer_get_format(struct iss_resizer_device *resizer, - struct v4l2_subdev_state *sd_state, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_state_get_format(sd_state, pad); - return &resizer->formats[pad]; -} - -/* - * resizer_try_format - Try video format on a pad - * @resizer: ISS RESIZER device - * @sd_state: V4L2 subdev state - * @pad: Pad number - * @fmt: Format - */ -static void -resizer_try_format(struct iss_resizer_device *resizer, - struct v4l2_subdev_state *sd_state, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - u32 pixelcode; - struct v4l2_mbus_framefmt *format; - unsigned int width = fmt->width; - unsigned int height = fmt->height; - unsigned int i; - - switch (pad) { - case RESIZER_PAD_SINK: - for (i = 0; i < ARRAY_SIZE(resizer_fmts); i++) { - if (fmt->code == resizer_fmts[i]) - break; - } - - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(resizer_fmts)) - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - - /* Clamp the input size. */ - fmt->width = clamp_t(u32, width, 1, 8192); - fmt->height = clamp_t(u32, height, 1, 8192); - break; - - case RESIZER_PAD_SOURCE_MEM: - pixelcode = fmt->code; - format = __resizer_get_format(resizer, sd_state, - RESIZER_PAD_SINK, - which); - memcpy(fmt, format, sizeof(*fmt)); - - if ((pixelcode == MEDIA_BUS_FMT_YUYV8_1_5X8) && - (fmt->code == MEDIA_BUS_FMT_UYVY8_1X16)) - fmt->code = pixelcode; - - /* The data formatter truncates the number of horizontal output - * pixels to a multiple of 16. To avoid clipping data, allow - * callers to request an output size bigger than the input size - * up to the nearest multiple of 16. - */ - fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); - fmt->width &= ~15; - fmt->height = clamp_t(u32, height, 32, fmt->height); - break; - } - - fmt->colorspace = V4L2_COLORSPACE_JPEG; - fmt->field = V4L2_FIELD_NONE; -} - -/* - * resizer_enum_mbus_code - Handle pixel format enumeration - * @sd : pointer to v4l2 subdev structure - * @sd_state: V4L2 subdev state - * @code : pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - switch (code->pad) { - case RESIZER_PAD_SINK: - if (code->index >= ARRAY_SIZE(resizer_fmts)) - return -EINVAL; - - code->code = resizer_fmts[code->index]; - break; - - case RESIZER_PAD_SOURCE_MEM: - format = __resizer_get_format(resizer, sd_state, - RESIZER_PAD_SINK, - code->which); - - if (code->index == 0) { - code->code = format->code; - break; - } - - switch (format->code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - if (code->index == 1) - code->code = MEDIA_BUS_FMT_YUYV8_1_5X8; - else - return -EINVAL; - break; - default: - if (code->index != 0) - return -EINVAL; - } - - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - resizer_try_format(resizer, sd_state, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - resizer_try_format(resizer, sd_state, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * resizer_get_format - Retrieve the video format on a pad - * @sd : ISP RESIZER V4L2 subdevice - * @sd_state: V4L2 subdev state - * @fmt: Format - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int resizer_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __resizer_get_format(resizer, sd_state, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - fmt->format = *format; - return 0; -} - -/* - * resizer_set_format - Set the video format on a pad - * @sd : ISP RESIZER V4L2 subdevice - * @sd_state: V4L2 subdev state - * @fmt: Format - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int resizer_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __resizer_get_format(resizer, sd_state, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - resizer_try_format(resizer, sd_state, fmt->pad, &fmt->format, - fmt->which); - *format = fmt->format; - - /* Propagate the format from sink to source */ - if (fmt->pad == RESIZER_PAD_SINK) { - format = __resizer_get_format(resizer, sd_state, - RESIZER_PAD_SOURCE_MEM, - fmt->which); - *format = fmt->format; - resizer_try_format(resizer, sd_state, RESIZER_PAD_SOURCE_MEM, - format, - fmt->which); - } - - return 0; -} - -static int resizer_link_validate(struct v4l2_subdev *sd, - struct media_link *link, - struct v4l2_subdev_format *source_fmt, - struct v4l2_subdev_format *sink_fmt) -{ - /* Check if the two ends match */ - if (source_fmt->format.width != sink_fmt->format.width || - source_fmt->format.height != sink_fmt->format.height) - return -EPIPE; - - if (source_fmt->format.code != sink_fmt->format.code) - return -EPIPE; - - return 0; -} - -/* - * resizer_init_formats - Initialize formats on all pads - * @sd: ISP RESIZER V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. - */ -static int resizer_init_formats(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - format.format.code = MEDIA_BUS_FMT_UYVY8_1X16; - format.format.width = 4096; - format.format.height = 4096; - resizer_set_format(sd, fh ? fh->state : NULL, &format); - - return 0; -} - -/* V4L2 subdev video operations */ -static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = { - .s_stream = resizer_set_stream, -}; - -/* V4L2 subdev pad operations */ -static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = { - .enum_mbus_code = resizer_enum_mbus_code, - .enum_frame_size = resizer_enum_frame_size, - .get_fmt = resizer_get_format, - .set_fmt = resizer_set_format, - .link_validate = resizer_link_validate, -}; - -/* V4L2 subdev operations */ -static const struct v4l2_subdev_ops resizer_v4l2_ops = { - .video = &resizer_v4l2_video_ops, - .pad = &resizer_v4l2_pad_ops, -}; - -/* V4L2 subdev internal operations */ -static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = { - .open = resizer_init_formats, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -/* - * resizer_link_setup - Setup RESIZER connections - * @entity: RESIZER media entity - * @local: Pad at the local end of the link - * @remote: Pad at the remote end of the link - * @flags: Link flags - * - * return -EINVAL or zero on success - */ -static int resizer_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct iss_device *iss = to_iss_device(resizer); - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - switch (index) { - case RESIZER_PAD_SINK | 2 << 16: - /* Read from IPIPE or IPIPEIF. */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->input = RESIZER_INPUT_NONE; - break; - } - - if (resizer->input != RESIZER_INPUT_NONE) - return -EBUSY; - - if (remote->entity == &iss->ipipeif.subdev.entity) - resizer->input = RESIZER_INPUT_IPIPEIF; - else if (remote->entity == &iss->ipipe.subdev.entity) - resizer->input = RESIZER_INPUT_IPIPE; - - break; - - case RESIZER_PAD_SOURCE_MEM: - /* Write to memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (resizer->output & ~RESIZER_OUTPUT_MEMORY) - return -EBUSY; - resizer->output |= RESIZER_OUTPUT_MEMORY; - } else { - resizer->output &= ~RESIZER_OUTPUT_MEMORY; - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* media operations */ -static const struct media_entity_operations resizer_media_ops = { - .link_setup = resizer_link_setup, - .link_validate = v4l2_subdev_link_validate, -}; - -/* - * resizer_init_entities - Initialize V4L2 subdev and media entity - * @resizer: ISS ISP RESIZER module - * - * Return 0 on success and a negative error code on failure. - */ -static int resizer_init_entities(struct iss_resizer_device *resizer) -{ - struct v4l2_subdev *sd = &resizer->subdev; - struct media_pad *pads = resizer->pads; - struct media_entity *me = &sd->entity; - int ret; - - resizer->input = RESIZER_INPUT_NONE; - - v4l2_subdev_init(sd, &resizer_v4l2_ops); - sd->internal_ops = &resizer_v4l2_internal_ops; - strscpy(sd->name, "OMAP4 ISS ISP resizer", sizeof(sd->name)); - sd->grp_id = BIT(16); /* group ID for iss subdevs */ - v4l2_set_subdevdata(sd, resizer); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[RESIZER_PAD_SOURCE_MEM].flags = MEDIA_PAD_FL_SOURCE; - - me->ops = &resizer_media_ops; - ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads); - if (ret < 0) - return ret; - - resizer_init_formats(sd, NULL); - - resizer->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - resizer->video_out.ops = &resizer_video_ops; - resizer->video_out.iss = to_iss_device(resizer); - resizer->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; - resizer->video_out.bpl_alignment = 32; - resizer->video_out.bpl_zero_padding = 1; - resizer->video_out.bpl_max = 0x1ffe0; - - return omap4iss_video_init(&resizer->video_out, "ISP resizer a"); -} - -void omap4iss_resizer_unregister_entities(struct iss_resizer_device *resizer) -{ - v4l2_device_unregister_subdev(&resizer->subdev); - omap4iss_video_unregister(&resizer->video_out); -} - -int omap4iss_resizer_register_entities(struct iss_resizer_device *resizer, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev and video node. */ - ret = v4l2_device_register_subdev(vdev, &resizer->subdev); - if (ret < 0) - goto error; - - ret = omap4iss_video_register(&resizer->video_out, vdev); - if (ret < 0) - goto error; - - return 0; - -error: - omap4iss_resizer_unregister_entities(resizer); - return ret; -} - -/* ----------------------------------------------------------------------------- - * ISP RESIZER initialisation and cleanup - */ - -/* - * omap4iss_resizer_init - RESIZER module initialization. - * @iss: Device pointer specific to the OMAP4 ISS. - * - * TODO: Get the initialisation values from platform data. - * - * Return 0 on success or a negative error code otherwise. - */ -int omap4iss_resizer_init(struct iss_device *iss) -{ - struct iss_resizer_device *resizer = &iss->resizer; - - resizer->state = ISS_PIPELINE_STREAM_STOPPED; - init_waitqueue_head(&resizer->wait); - - return resizer_init_entities(resizer); -} - -/* - * omap4iss_resizer_create_links() - RESIZER pads links creation - * @iss: Pointer to ISS device - * - * return negative error code or zero on success - */ -int omap4iss_resizer_create_links(struct iss_device *iss) -{ - struct iss_resizer_device *resizer = &iss->resizer; - - /* Connect the RESIZER subdev to the video node. */ - return media_create_pad_link(&resizer->subdev.entity, - RESIZER_PAD_SOURCE_MEM, - &resizer->video_out.video.entity, 0, 0); -} - -/* - * omap4iss_resizer_cleanup - RESIZER module cleanup. - * @iss: Device pointer specific to the OMAP4 ISS. - */ -void omap4iss_resizer_cleanup(struct iss_device *iss) -{ - struct iss_resizer_device *resizer = &iss->resizer; - - media_entity_cleanup(&resizer->subdev.entity); -} diff --git a/drivers/staging/media/omap4iss/iss_resizer.h b/drivers/staging/media/omap4iss/iss_resizer.h deleted file mode 100644 index cb937fccc21ff7..00000000000000 --- a/drivers/staging/media/omap4iss/iss_resizer.h +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * TI OMAP4 ISS V4L2 Driver - ISP RESIZER module - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#ifndef OMAP4_ISS_RESIZER_H -#define OMAP4_ISS_RESIZER_H - -#include "iss_video.h" - -enum resizer_input_entity { - RESIZER_INPUT_NONE, - RESIZER_INPUT_IPIPE, - RESIZER_INPUT_IPIPEIF -}; - -#define RESIZER_OUTPUT_MEMORY BIT(0) - -/* Sink and source RESIZER pads */ -#define RESIZER_PAD_SINK 0 -#define RESIZER_PAD_SOURCE_MEM 1 -#define RESIZER_PADS_NUM 2 - -/* - * struct iss_resizer_device - Structure for the RESIZER module to store its own - * information - * @subdev: V4L2 subdevice - * @pads: Sink and source media entity pads - * @formats: Active video formats - * @input: Active input - * @output: Active outputs - * @video_out: Output video node - * @error: A hardware error occurred during capture - * @state: Streaming state - * @wait: Wait queue used to stop the module - * @stopping: Stopping state - */ -struct iss_resizer_device { - struct v4l2_subdev subdev; - struct media_pad pads[RESIZER_PADS_NUM]; - struct v4l2_mbus_framefmt formats[RESIZER_PADS_NUM]; - - enum resizer_input_entity input; - unsigned int output; - struct iss_video video_out; - unsigned int error; - - enum iss_pipeline_stream_state state; - wait_queue_head_t wait; - atomic_t stopping; -}; - -struct iss_device; - -int omap4iss_resizer_init(struct iss_device *iss); -int omap4iss_resizer_create_links(struct iss_device *iss); -void omap4iss_resizer_cleanup(struct iss_device *iss); -int omap4iss_resizer_register_entities(struct iss_resizer_device *resizer, - struct v4l2_device *vdev); -void omap4iss_resizer_unregister_entities(struct iss_resizer_device *resizer); - -int omap4iss_resizer_busy(struct iss_resizer_device *resizer); -void omap4iss_resizer_isr(struct iss_resizer_device *resizer, u32 events); -void omap4iss_resizer_restore_context(struct iss_device *iss); -void omap4iss_resizer_max_rate(struct iss_resizer_device *resizer, - unsigned int *max_rate); - -#endif /* OMAP4_ISS_RESIZER_H */ diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c deleted file mode 100644 index 22fa4d6cae10b9..00000000000000 --- a/drivers/staging/media/omap4iss/iss_video.c +++ /dev/null @@ -1,1274 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * TI OMAP4 ISS V4L2 Driver - Generic video node - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "iss_video.h" -#include "iss.h" - -/* ----------------------------------------------------------------------------- - * Helper functions - */ - -static struct iss_format_info formats[] = { - { MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_GREY, 8, }, - { MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10, - MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_Y10, 10, }, - { MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10, - MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_Y12, 12, }, - { MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR8, 8, }, - { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, - MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG8, 8, }, - { MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, - MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG8, 8, }, - { MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, - MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB8, 8, }, - { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - MEDIA_BUS_FMT_SGRBG10_1X10, 0, - V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, - { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR10, 10, }, - { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, - MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG10, 10, }, - { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, - MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG10, 10, }, - { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, - MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB10, 10, }, - { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR12, 12, }, - { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10, - MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG12, 12, }, - { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10, - MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG12, 12, }, - { MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10, - MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB12, 12, }, - { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, - MEDIA_BUS_FMT_UYVY8_1X16, 0, - V4L2_PIX_FMT_UYVY, 16, }, - { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, - MEDIA_BUS_FMT_YUYV8_1X16, 0, - V4L2_PIX_FMT_YUYV, 16, }, - { MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8, - MEDIA_BUS_FMT_YUYV8_1_5X8, 0, - V4L2_PIX_FMT_NV12, 8, }, -}; - -const struct iss_format_info * -omap4iss_video_format_info(u32 code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (formats[i].code == code) - return &formats[i]; - } - - return NULL; -} - -/* - * iss_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format - * @video: ISS video instance - * @mbus: v4l2_mbus_framefmt format (input) - * @pix: v4l2_pix_format format (output) - * - * Fill the output pix structure with information from the input mbus format. - * The bytesperline and sizeimage fields are computed from the requested bytes - * per line value in the pix format and information from the video instance. - * - * Return the number of padding bytes at end of line. - */ -static unsigned int iss_video_mbus_to_pix(const struct iss_video *video, - const struct v4l2_mbus_framefmt *mbus, - struct v4l2_pix_format *pix) -{ - unsigned int bpl = pix->bytesperline; - unsigned int min_bpl; - unsigned int i; - - memset(pix, 0, sizeof(*pix)); - pix->width = mbus->width; - pix->height = mbus->height; - - /* - * Skip the last format in the loop so that it will be selected if no - * match is found. - */ - for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) { - if (formats[i].code == mbus->code) - break; - } - - min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8; - - /* - * Clamp the requested bytes per line value. If the maximum bytes per - * line value is zero, the module doesn't support user configurable line - * sizes. Override the requested value with the minimum in that case. - */ - if (video->bpl_max) - bpl = clamp(bpl, min_bpl, video->bpl_max); - else - bpl = min_bpl; - - if (!video->bpl_zero_padding || bpl != min_bpl) - bpl = ALIGN(bpl, video->bpl_alignment); - - pix->pixelformat = formats[i].pixelformat; - pix->bytesperline = bpl; - pix->sizeimage = pix->bytesperline * pix->height; - pix->colorspace = mbus->colorspace; - pix->field = mbus->field; - - /* FIXME: Special case for NV12! We should make this nicer... */ - if (pix->pixelformat == V4L2_PIX_FMT_NV12) - pix->sizeimage += (pix->bytesperline * pix->height) / 2; - - return bpl - min_bpl; -} - -static void iss_video_pix_to_mbus(const struct v4l2_pix_format *pix, - struct v4l2_mbus_framefmt *mbus) -{ - unsigned int i; - - memset(mbus, 0, sizeof(*mbus)); - mbus->width = pix->width; - mbus->height = pix->height; - - /* - * Skip the last format in the loop so that it will be selected if no - * match is found. - */ - for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) { - if (formats[i].pixelformat == pix->pixelformat) - break; - } - - mbus->code = formats[i].code; - mbus->colorspace = pix->colorspace; - mbus->field = pix->field; -} - -static struct v4l2_subdev * -iss_video_remote_subdev(struct iss_video *video, u32 *pad) -{ - struct media_pad *remote; - - remote = media_pad_remote_pad_first(&video->pad); - - if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) - return NULL; - - if (pad) - *pad = remote->index; - - return media_entity_to_v4l2_subdev(remote->entity); -} - -/* Return a pointer to the ISS video instance at the far end of the pipeline. */ -static struct iss_video * -iss_video_far_end(struct iss_video *video, struct iss_pipeline *pipe) -{ - struct media_pipeline_entity_iter iter; - struct media_entity *entity; - struct iss_video *far_end = NULL; - int ret; - - ret = media_pipeline_entity_iter_init(&pipe->pipe, &iter); - if (ret) - return ERR_PTR(-ENOMEM); - - media_pipeline_for_each_entity(&pipe->pipe, &iter, entity) { - struct iss_video *other; - - if (entity == &video->video.entity) - continue; - - if (!is_media_entity_v4l2_video_device(entity)) - continue; - - other = to_iss_video(media_entity_to_video_device(entity)); - if (other->type != video->type) { - far_end = other; - break; - } - } - - media_pipeline_entity_iter_cleanup(&iter); - - return far_end; -} - -static int -__iss_video_get_format(struct iss_video *video, - struct v4l2_mbus_framefmt *format) -{ - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_subdev *subdev; - u32 pad; - int ret; - - subdev = iss_video_remote_subdev(video, &pad); - if (!subdev) - return -EINVAL; - - fmt.pad = pad; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); - mutex_unlock(&video->mutex); - - if (ret) - return ret; - - *format = fmt.format; - return 0; -} - -static int -iss_video_check_format(struct iss_video *video, struct iss_video_fh *vfh) -{ - struct v4l2_mbus_framefmt format; - struct v4l2_pix_format pixfmt; - int ret; - - ret = __iss_video_get_format(video, &format); - if (ret < 0) - return ret; - - pixfmt.bytesperline = 0; - ret = iss_video_mbus_to_pix(video, &format, &pixfmt); - - if (vfh->format.fmt.pix.pixelformat != pixfmt.pixelformat || - vfh->format.fmt.pix.height != pixfmt.height || - vfh->format.fmt.pix.width != pixfmt.width || - vfh->format.fmt.pix.bytesperline != pixfmt.bytesperline || - vfh->format.fmt.pix.sizeimage != pixfmt.sizeimage) - return -EINVAL; - - return ret; -} - -/* ----------------------------------------------------------------------------- - * Video queue operations - */ - -static int iss_video_queue_setup(struct vb2_queue *vq, - unsigned int *count, unsigned int *num_planes, - unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct iss_video_fh *vfh = vb2_get_drv_priv(vq); - struct iss_video *video = vfh->video; - - /* Revisit multi-planar support for NV12 */ - *num_planes = 1; - - sizes[0] = vfh->format.fmt.pix.sizeimage; - if (sizes[0] == 0) - return -EINVAL; - - *count = min(*count, video->capture_mem / PAGE_ALIGN(sizes[0])); - - return 0; -} - -static void iss_video_buf_cleanup(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb); - - if (buffer->iss_addr) - buffer->iss_addr = 0; -} - -static int iss_video_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue); - struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb); - struct iss_video *video = vfh->video; - unsigned long size = vfh->format.fmt.pix.sizeimage; - dma_addr_t addr; - - if (vb2_plane_size(vb, 0) < size) - return -ENOBUFS; - - addr = vb2_dma_contig_plane_dma_addr(vb, 0); - if (!IS_ALIGNED(addr, 32)) { - dev_dbg(video->iss->dev, - "Buffer address must be aligned to 32 bytes boundary.\n"); - return -EINVAL; - } - - vb2_set_plane_payload(vb, 0, size); - buffer->iss_addr = addr; - return 0; -} - -static void iss_video_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue); - struct iss_video *video = vfh->video; - struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb); - struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); - unsigned long flags; - bool empty; - - spin_lock_irqsave(&video->qlock, flags); - - /* - * Mark the buffer is faulty and give it back to the queue immediately - * if the video node has registered an error. vb2 will perform the same - * check when preparing the buffer, but that is inherently racy, so we - * need to handle the race condition with an authoritative check here. - */ - if (unlikely(video->error)) { - vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); - spin_unlock_irqrestore(&video->qlock, flags); - return; - } - - empty = list_empty(&video->dmaqueue); - list_add_tail(&buffer->list, &video->dmaqueue); - - spin_unlock_irqrestore(&video->qlock, flags); - - if (empty) { - enum iss_pipeline_state state; - unsigned int start; - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - state = ISS_PIPELINE_QUEUE_OUTPUT; - else - state = ISS_PIPELINE_QUEUE_INPUT; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state |= state; - video->ops->queue(video, buffer); - video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_QUEUED; - - start = iss_pipeline_ready(pipe); - if (start) - pipe->state |= ISS_PIPELINE_STREAM; - spin_unlock_irqrestore(&pipe->lock, flags); - - if (start) - omap4iss_pipeline_set_stream(pipe, - ISS_PIPELINE_STREAM_SINGLESHOT); - } -} - -static const struct vb2_ops iss_video_vb2ops = { - .queue_setup = iss_video_queue_setup, - .buf_prepare = iss_video_buf_prepare, - .buf_queue = iss_video_buf_queue, - .buf_cleanup = iss_video_buf_cleanup, -}; - -/* - * omap4iss_video_buffer_next - Complete the current buffer and return the next - * @video: ISS video object - * - * Remove the current video buffer from the DMA queue and fill its timestamp, - * field count and state fields before waking up its completion handler. - * - * For capture video nodes, the buffer state is set to VB2_BUF_STATE_DONE if no - * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise. - * - * The DMA queue is expected to contain at least one buffer. - * - * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is - * empty. - */ -struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video) -{ - struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); - enum iss_pipeline_state state; - struct iss_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&video->qlock, flags); - if (WARN_ON(list_empty(&video->dmaqueue))) { - spin_unlock_irqrestore(&video->qlock, flags); - return NULL; - } - - buf = list_first_entry(&video->dmaqueue, struct iss_buffer, - list); - list_del(&buf->list); - spin_unlock_irqrestore(&video->qlock, flags); - - buf->vb.vb2_buf.timestamp = ktime_get_ns(); - - /* - * Do frame number propagation only if this is the output video node. - * Frame number either comes from the CSI receivers or it gets - * incremented here if H3A is not active. - * Note: There is no guarantee that the output buffer will finish - * first, so the input number might lag behind by 1 in some cases. - */ - if (video == pipe->output && !pipe->do_propagation) - buf->vb.sequence = - atomic_inc_return(&pipe->frame_number); - else - buf->vb.sequence = atomic_read(&pipe->frame_number); - - vb2_buffer_done(&buf->vb.vb2_buf, pipe->error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - pipe->error = false; - - spin_lock_irqsave(&video->qlock, flags); - if (list_empty(&video->dmaqueue)) { - spin_unlock_irqrestore(&video->qlock, flags); - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - state = ISS_PIPELINE_QUEUE_OUTPUT - | ISS_PIPELINE_STREAM; - else - state = ISS_PIPELINE_QUEUE_INPUT - | ISS_PIPELINE_STREAM; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~state; - if (video->pipe.stream_state == ISS_PIPELINE_STREAM_CONTINUOUS) - video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN; - spin_unlock_irqrestore(&pipe->lock, flags); - return NULL; - } - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input) { - spin_lock(&pipe->lock); - pipe->state &= ~ISS_PIPELINE_STREAM; - spin_unlock(&pipe->lock); - } - - buf = list_first_entry(&video->dmaqueue, struct iss_buffer, - list); - spin_unlock_irqrestore(&video->qlock, flags); - buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - return buf; -} - -/* - * omap4iss_video_cancel_stream - Cancel stream on a video node - * @video: ISS video object - * - * Cancelling a stream mark all buffers on the video node as erroneous and makes - * sure no new buffer can be queued. - */ -void omap4iss_video_cancel_stream(struct iss_video *video) -{ - unsigned long flags; - - spin_lock_irqsave(&video->qlock, flags); - - while (!list_empty(&video->dmaqueue)) { - struct iss_buffer *buf; - - buf = list_first_entry(&video->dmaqueue, struct iss_buffer, - list); - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - } - - vb2_queue_error(video->queue); - video->error = true; - - spin_unlock_irqrestore(&video->qlock, flags); -} - -/* ----------------------------------------------------------------------------- - * V4L2 ioctls - */ - -static int -iss_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) -{ - struct iss_video *video = video_drvdata(file); - - strscpy(cap->driver, ISS_VIDEO_DRIVER_NAME, sizeof(cap->driver)); - strscpy(cap->card, video->video.name, sizeof(cap->card)); - strscpy(cap->bus_info, "media", sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING - | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT; - - return 0; -} - -static int -iss_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_mbus_framefmt format; - unsigned int index = f->index; - unsigned int i; - int ret; - - if (f->type != video->type) - return -EINVAL; - - ret = __iss_video_get_format(video, &format); - if (ret < 0) - return ret; - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - const struct iss_format_info *info = &formats[i]; - - if (format.code != info->code) - continue; - - if (index == 0) { - f->pixelformat = info->pixelformat; - return 0; - } - - index--; - } - - return -EINVAL; -} - -static int -iss_video_get_format(struct file *file, void *fh, struct v4l2_format *format) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - struct iss_video *video = video_drvdata(file); - - if (format->type != video->type) - return -EINVAL; - - mutex_lock(&video->mutex); - *format = vfh->format; - mutex_unlock(&video->mutex); - - return 0; -} - -static int -iss_video_set_format(struct file *file, void *fh, struct v4l2_format *format) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - struct iss_video *video = video_drvdata(file); - struct v4l2_mbus_framefmt fmt; - - if (format->type != video->type) - return -EINVAL; - - mutex_lock(&video->mutex); - - /* - * Fill the bytesperline and sizeimage fields by converting to media bus - * format and back to pixel format. - */ - iss_video_pix_to_mbus(&format->fmt.pix, &fmt); - iss_video_mbus_to_pix(video, &fmt, &format->fmt.pix); - - vfh->format = *format; - - mutex_unlock(&video->mutex); - return 0; -} - -static int -iss_video_try_format(struct file *file, void *fh, struct v4l2_format *format) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_subdev *subdev; - u32 pad; - int ret; - - if (format->type != video->type) - return -EINVAL; - - subdev = iss_video_remote_subdev(video, &pad); - if (!subdev) - return -EINVAL; - - iss_video_pix_to_mbus(&format->fmt.pix, &fmt.format); - - fmt.pad = pad; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); - if (ret) - return ret; - - iss_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix); - return 0; -} - -static int -iss_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_subdev *subdev; - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = sel->target, - }; - u32 pad; - int ret; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - break; - case V4L2_SEL_TGT_COMPOSE: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - break; - default: - return -EINVAL; - } - subdev = iss_video_remote_subdev(video, &pad); - if (!subdev) - return -EINVAL; - - /* - * Try the get selection operation first and fallback to get format if - * not implemented. - */ - sdsel.pad = pad; - ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel); - if (!ret) - sel->r = sdsel.r; - if (ret != -ENOIOCTLCMD) - return ret; - - format.pad = pad; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format); - if (ret < 0) - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; - - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = format.format.width; - sel->r.height = format.format.height; - - return 0; -} - -static int -iss_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = sel->target, - .flags = sel->flags, - .r = sel->r, - }; - u32 pad; - int ret; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - break; - case V4L2_SEL_TGT_COMPOSE: - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - break; - default: - return -EINVAL; - } - subdev = iss_video_remote_subdev(video, &pad); - if (!subdev) - return -EINVAL; - - sdsel.pad = pad; - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, pad, set_selection, NULL, &sdsel); - mutex_unlock(&video->mutex); - if (!ret) - sel->r = sdsel.r; - - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; -} - -static int -iss_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - struct iss_video *video = video_drvdata(file); - - if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - video->type != a->type) - return -EINVAL; - - memset(a, 0, sizeof(*a)); - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; - a->parm.output.timeperframe = vfh->timeperframe; - - return 0; -} - -static int -iss_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - struct iss_video *video = video_drvdata(file); - - if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - video->type != a->type) - return -EINVAL; - - if (a->parm.output.timeperframe.denominator == 0) - a->parm.output.timeperframe.denominator = 1; - - vfh->timeperframe = a->parm.output.timeperframe; - - return 0; -} - -static int -iss_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - - return vb2_reqbufs(&vfh->queue, rb); -} - -static int -iss_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - - return vb2_querybuf(&vfh->queue, b); -} - -static int -iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct iss_video *video = video_drvdata(file); - struct iss_video_fh *vfh = to_iss_video_fh(fh); - - return vb2_qbuf(&vfh->queue, video->video.v4l2_dev->mdev, b); -} - -static int -iss_video_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *e) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - - return vb2_expbuf(&vfh->queue, e); -} - -static int -iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - - return vb2_dqbuf(&vfh->queue, b, file->f_flags & O_NONBLOCK); -} - -/* - * Stream management - * - * Every ISS pipeline has a single input and a single output. The input can be - * either a sensor or a video node. The output is always a video node. - * - * As every pipeline has an output video node, the ISS video objects at the - * pipeline output stores the pipeline state. It tracks the streaming state of - * both the input and output, as well as the availability of buffers. - * - * In sensor-to-memory mode, frames are always available at the pipeline input. - * Starting the sensor usually requires I2C transfers and must be done in - * interruptible context. The pipeline is started and stopped synchronously - * to the stream on/off commands. All modules in the pipeline will get their - * subdev set stream handler called. The module at the end of the pipeline must - * delay starting the hardware until buffers are available at its output. - * - * In memory-to-memory mode, starting/stopping the stream requires - * synchronization between the input and output. ISS modules can't be stopped - * in the middle of a frame, and at least some of the modules seem to become - * busy as soon as they're started, even if they don't receive a frame start - * event. For that reason frames need to be processed in single-shot mode. The - * driver needs to wait until a frame is completely processed and written to - * memory before restarting the pipeline for the next frame. Pipelined - * processing might be possible but requires more testing. - * - * Stream start must be delayed until buffers are available at both the input - * and output. The pipeline must be started in the vb2 queue callback with - * the buffers queue spinlock held. The modules subdev set stream operation must - * not sleep. - */ -static int -iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - struct iss_video *video = video_drvdata(file); - struct media_device *mdev = video->video.entity.graph_obj.mdev; - struct media_pipeline_pad_iter iter; - enum iss_pipeline_state state; - struct iss_pipeline *pipe; - struct iss_video *far_end; - struct media_pad *pad; - unsigned long flags; - int ret; - - if (type != video->type) - return -EINVAL; - - mutex_lock(&video->stream_lock); - - /* - * Start streaming on the pipeline. No link touching an entity in the - * pipeline can be activated or deactivated once streaming is started. - */ - pipe = to_iss_pipeline(&video->video.entity) ? : &video->pipe; - pipe->external = NULL; - pipe->external_rate = 0; - pipe->external_bpp = 0; - - ret = media_entity_enum_init(&pipe->ent_enum, mdev); - if (ret) - goto err_entity_enum_init; - - if (video->iss->pdata->set_constraints) - video->iss->pdata->set_constraints(video->iss, true); - - ret = video_device_pipeline_start(&video->video, &pipe->pipe); - if (ret < 0) - goto err_media_pipeline_start; - - media_pipeline_for_each_pad(&pipe->pipe, &iter, pad) - media_entity_enum_set(&pipe->ent_enum, pad->entity); - - /* - * Verify that the currently configured format matches the output of - * the connected subdev. - */ - ret = iss_video_check_format(video, vfh); - if (ret < 0) - goto err_iss_video_check_format; - - video->bpl_padding = ret; - video->bpl_value = vfh->format.fmt.pix.bytesperline; - - /* - * Find the ISS video node connected at the far end of the pipeline and - * update the pipeline. - */ - far_end = iss_video_far_end(video, pipe); - if (IS_ERR(far_end)) { - ret = PTR_ERR(far_end); - goto err_iss_video_check_format; - } - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT; - pipe->input = far_end; - pipe->output = video; - } else { - if (!far_end) { - ret = -EPIPE; - goto err_iss_video_check_format; - } - - state = ISS_PIPELINE_STREAM_INPUT | ISS_PIPELINE_IDLE_INPUT; - pipe->input = video; - pipe->output = far_end; - } - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~ISS_PIPELINE_STREAM; - pipe->state |= state; - spin_unlock_irqrestore(&pipe->lock, flags); - - /* - * Set the maximum time per frame as the value requested by userspace. - * This is a soft limit that can be overridden if the hardware doesn't - * support the request limit. - */ - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - pipe->max_timeperframe = vfh->timeperframe; - - video->queue = &vfh->queue; - INIT_LIST_HEAD(&video->dmaqueue); - video->error = false; - atomic_set(&pipe->frame_number, -1); - - ret = vb2_streamon(&vfh->queue, type); - if (ret < 0) - goto err_iss_video_check_format; - - /* - * In sensor-to-memory mode, the stream can be started synchronously - * to the stream on command. In memory-to-memory mode, it will be - * started when buffers are queued on both the input and output. - */ - if (!pipe->input) { - unsigned long flags; - - ret = omap4iss_pipeline_set_stream(pipe, - ISS_PIPELINE_STREAM_CONTINUOUS); - if (ret < 0) - goto err_omap4iss_set_stream; - spin_lock_irqsave(&video->qlock, flags); - if (list_empty(&video->dmaqueue)) - video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN; - spin_unlock_irqrestore(&video->qlock, flags); - } - - mutex_unlock(&video->stream_lock); - - return 0; - -err_omap4iss_set_stream: - vb2_streamoff(&vfh->queue, type); -err_iss_video_check_format: - video_device_pipeline_stop(&video->video); -err_media_pipeline_start: - if (video->iss->pdata->set_constraints) - video->iss->pdata->set_constraints(video->iss, false); - video->queue = NULL; - -err_entity_enum_init: - media_entity_enum_cleanup(&pipe->ent_enum); - - mutex_unlock(&video->stream_lock); - - return ret; -} - -static int -iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) -{ - struct iss_video_fh *vfh = to_iss_video_fh(fh); - struct iss_video *video = video_drvdata(file); - struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity); - enum iss_pipeline_state state; - unsigned long flags; - - if (type != video->type) - return -EINVAL; - - mutex_lock(&video->stream_lock); - - if (!vb2_is_streaming(&vfh->queue)) - goto done; - - /* Update the pipeline state. */ - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - state = ISS_PIPELINE_STREAM_OUTPUT - | ISS_PIPELINE_QUEUE_OUTPUT; - else - state = ISS_PIPELINE_STREAM_INPUT - | ISS_PIPELINE_QUEUE_INPUT; - - spin_lock_irqsave(&pipe->lock, flags); - pipe->state &= ~state; - spin_unlock_irqrestore(&pipe->lock, flags); - - /* Stop the stream. */ - omap4iss_pipeline_set_stream(pipe, ISS_PIPELINE_STREAM_STOPPED); - vb2_streamoff(&vfh->queue, type); - video->queue = NULL; - - media_entity_enum_cleanup(&pipe->ent_enum); - - if (video->iss->pdata->set_constraints) - video->iss->pdata->set_constraints(video->iss, false); - video_device_pipeline_stop(&video->video); - -done: - mutex_unlock(&video->stream_lock); - return 0; -} - -static int -iss_video_enum_input(struct file *file, void *fh, struct v4l2_input *input) -{ - if (input->index > 0) - return -EINVAL; - - strscpy(input->name, "camera", sizeof(input->name)); - input->type = V4L2_INPUT_TYPE_CAMERA; - - return 0; -} - -static int -iss_video_g_input(struct file *file, void *fh, unsigned int *input) -{ - *input = 0; - - return 0; -} - -static int -iss_video_s_input(struct file *file, void *fh, unsigned int input) -{ - return input == 0 ? 0 : -EINVAL; -} - -static const struct v4l2_ioctl_ops iss_video_ioctl_ops = { - .vidioc_querycap = iss_video_querycap, - .vidioc_enum_fmt_vid_cap = iss_video_enum_format, - .vidioc_g_fmt_vid_cap = iss_video_get_format, - .vidioc_s_fmt_vid_cap = iss_video_set_format, - .vidioc_try_fmt_vid_cap = iss_video_try_format, - .vidioc_g_fmt_vid_out = iss_video_get_format, - .vidioc_s_fmt_vid_out = iss_video_set_format, - .vidioc_try_fmt_vid_out = iss_video_try_format, - .vidioc_g_selection = iss_video_get_selection, - .vidioc_s_selection = iss_video_set_selection, - .vidioc_g_parm = iss_video_get_param, - .vidioc_s_parm = iss_video_set_param, - .vidioc_reqbufs = iss_video_reqbufs, - .vidioc_querybuf = iss_video_querybuf, - .vidioc_qbuf = iss_video_qbuf, - .vidioc_expbuf = iss_video_expbuf, - .vidioc_dqbuf = iss_video_dqbuf, - .vidioc_streamon = iss_video_streamon, - .vidioc_streamoff = iss_video_streamoff, - .vidioc_enum_input = iss_video_enum_input, - .vidioc_g_input = iss_video_g_input, - .vidioc_s_input = iss_video_s_input, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 file operations - */ - -static int iss_video_open(struct file *file) -{ - struct iss_video *video = video_drvdata(file); - struct iss_video_fh *handle; - struct vb2_queue *q; - int ret = 0; - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - v4l2_fh_init(&handle->vfh, &video->video); - v4l2_fh_add(&handle->vfh); - - /* If this is the first user, initialise the pipeline. */ - if (!omap4iss_get(video->iss)) { - ret = -EBUSY; - goto done; - } - - ret = v4l2_pipeline_pm_get(&video->video.entity); - if (ret < 0) { - omap4iss_put(video->iss); - goto done; - } - - q = &handle->queue; - - q->type = video->type; - q->io_modes = VB2_MMAP | VB2_DMABUF; - q->drv_priv = handle; - q->ops = &iss_video_vb2ops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct iss_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->dev = video->iss->dev; - - ret = vb2_queue_init(q); - if (ret) { - omap4iss_put(video->iss); - goto done; - } - - memset(&handle->format, 0, sizeof(handle->format)); - handle->format.type = video->type; - handle->timeperframe.denominator = 1; - - handle->video = video; - file->private_data = &handle->vfh; - -done: - if (ret < 0) { - v4l2_fh_del(&handle->vfh); - v4l2_fh_exit(&handle->vfh); - kfree(handle); - } - - return ret; -} - -static int iss_video_release(struct file *file) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_fh *vfh = file->private_data; - struct iss_video_fh *handle = to_iss_video_fh(vfh); - - /* Disable streaming and free the buffers queue resources. */ - iss_video_streamoff(file, vfh, video->type); - - v4l2_pipeline_pm_put(&video->video.entity); - - /* Release the videobuf2 queue */ - vb2_queue_release(&handle->queue); - - v4l2_fh_del(vfh); - v4l2_fh_exit(vfh); - kfree(handle); - file->private_data = NULL; - - omap4iss_put(video->iss); - - return 0; -} - -static __poll_t iss_video_poll(struct file *file, poll_table *wait) -{ - struct iss_video_fh *vfh = to_iss_video_fh(file->private_data); - - return vb2_poll(&vfh->queue, file, wait); -} - -static int iss_video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct iss_video_fh *vfh = to_iss_video_fh(file->private_data); - - return vb2_mmap(&vfh->queue, vma); -} - -static const struct v4l2_file_operations iss_video_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .open = iss_video_open, - .release = iss_video_release, - .poll = iss_video_poll, - .mmap = iss_video_mmap, -}; - -/* ----------------------------------------------------------------------------- - * ISS video core - */ - -static const struct iss_video_operations iss_video_dummy_ops = { -}; - -int omap4iss_video_init(struct iss_video *video, const char *name) -{ - const char *direction; - int ret; - - switch (video->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - direction = "output"; - video->pad.flags = MEDIA_PAD_FL_SINK; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - direction = "input"; - video->pad.flags = MEDIA_PAD_FL_SOURCE; - break; - - default: - return -EINVAL; - } - - ret = media_entity_pads_init(&video->video.entity, 1, &video->pad); - if (ret < 0) - return ret; - - spin_lock_init(&video->qlock); - mutex_init(&video->mutex); - atomic_set(&video->active, 0); - - spin_lock_init(&video->pipe.lock); - mutex_init(&video->stream_lock); - - /* Initialize the video device. */ - if (!video->ops) - video->ops = &iss_video_dummy_ops; - - video->video.fops = &iss_video_fops; - snprintf(video->video.name, sizeof(video->video.name), - "OMAP4 ISS %s %s", name, direction); - video->video.vfl_type = VFL_TYPE_VIDEO; - video->video.release = video_device_release_empty; - video->video.ioctl_ops = &iss_video_ioctl_ops; - video->pipe.stream_state = ISS_PIPELINE_STREAM_STOPPED; - - video_set_drvdata(&video->video, video); - - return 0; -} - -void omap4iss_video_cleanup(struct iss_video *video) -{ - media_entity_cleanup(&video->video.entity); - mutex_destroy(&video->stream_lock); - mutex_destroy(&video->mutex); -} - -int omap4iss_video_register(struct iss_video *video, struct v4l2_device *vdev) -{ - int ret; - - video->video.v4l2_dev = vdev; - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE; - else - video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT; - video->video.device_caps |= V4L2_CAP_STREAMING; - - ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1); - if (ret < 0) - dev_err(video->iss->dev, - "could not register video device (%d)\n", ret); - - return ret; -} - -void omap4iss_video_unregister(struct iss_video *video) -{ - video_unregister_device(&video->video); -} diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h deleted file mode 100644 index 19668d28b68242..00000000000000 --- a/drivers/staging/media/omap4iss/iss_video.h +++ /dev/null @@ -1,203 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * TI OMAP4 ISS V4L2 Driver - Generic video node - * - * Copyright (C) 2012 Texas Instruments, Inc. - * - * Author: Sergio Aguirre - */ - -#ifndef OMAP4_ISS_VIDEO_H -#define OMAP4_ISS_VIDEO_H - -#include -#include -#include -#include -#include -#include - -#define ISS_VIDEO_DRIVER_NAME "issvideo" - -struct iss_device; -struct iss_video; -struct v4l2_mbus_framefmt; -struct v4l2_pix_format; - -/* - * struct iss_format_info - ISS media bus format information - * @code: V4L2 media bus format code - * @truncated: V4L2 media bus format code for the same format truncated to 10 - * bits. Identical to @code if the format is 10 bits wide or less. - * @uncompressed: V4L2 media bus format code for the corresponding uncompressed - * format. Identical to @code if the format is not DPCM compressed. - * @flavor: V4L2 media bus format code for the same pixel layout but - * shifted to be 8 bits per pixel. =0 if format is not shiftable. - * @pixelformat: V4L2 pixel format FCC identifier - * @bpp: Bits per pixel - */ -struct iss_format_info { - u32 code; - u32 truncated; - u32 uncompressed; - u32 flavor; - u32 pixelformat; - unsigned int bpp; -}; - -enum iss_pipeline_stream_state { - ISS_PIPELINE_STREAM_STOPPED = 0, - ISS_PIPELINE_STREAM_CONTINUOUS = 1, - ISS_PIPELINE_STREAM_SINGLESHOT = 2, -}; - -enum iss_pipeline_state { - /* The stream has been started on the input video node. */ - ISS_PIPELINE_STREAM_INPUT = BIT(0), - /* The stream has been started on the output video node. */ - ISS_PIPELINE_STREAM_OUTPUT = BIT(1), - /* At least one buffer is queued on the input video node. */ - ISS_PIPELINE_QUEUE_INPUT = BIT(2), - /* At least one buffer is queued on the output video node. */ - ISS_PIPELINE_QUEUE_OUTPUT = BIT(3), - /* The input entity is idle, ready to be started. */ - ISS_PIPELINE_IDLE_INPUT = BIT(4), - /* The output entity is idle, ready to be started. */ - ISS_PIPELINE_IDLE_OUTPUT = BIT(5), - /* The pipeline is currently streaming. */ - ISS_PIPELINE_STREAM = BIT(6), -}; - -/* - * struct iss_pipeline - An OMAP4 ISS hardware pipeline - * @ent_enum: Entities in the pipeline - * @error: A hardware error occurred during capture - */ -struct iss_pipeline { - struct media_pipeline pipe; - spinlock_t lock; /* Pipeline state and queue flags */ - unsigned int state; - enum iss_pipeline_stream_state stream_state; - struct iss_video *input; - struct iss_video *output; - struct media_entity_enum ent_enum; - atomic_t frame_number; - bool do_propagation; /* of frame number */ - bool error; - struct v4l2_fract max_timeperframe; - struct v4l2_subdev *external; - unsigned int external_rate; - int external_bpp; -}; - -static inline struct iss_pipeline *to_iss_pipeline(struct media_entity *entity) -{ - struct media_pipeline *pipe = media_entity_pipeline(entity); - - if (!pipe) - return NULL; - - return container_of(pipe, struct iss_pipeline, pipe); -} - -static inline int iss_pipeline_ready(struct iss_pipeline *pipe) -{ - return pipe->state == (ISS_PIPELINE_STREAM_INPUT | - ISS_PIPELINE_STREAM_OUTPUT | - ISS_PIPELINE_QUEUE_INPUT | - ISS_PIPELINE_QUEUE_OUTPUT | - ISS_PIPELINE_IDLE_INPUT | - ISS_PIPELINE_IDLE_OUTPUT); -} - -/* - * struct iss_buffer - ISS buffer - * @buffer: ISS video buffer - * @iss_addr: Physical address of the buffer. - */ -struct iss_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_v4l2_buffer vb; - struct list_head list; - dma_addr_t iss_addr; -}; - -#define to_iss_buffer(buf) container_of(buf, struct iss_buffer, vb) - -enum iss_video_dmaqueue_flags { - /* Set if DMA queue becomes empty when ISS_PIPELINE_STREAM_CONTINUOUS */ - ISS_VIDEO_DMAQUEUE_UNDERRUN = BIT(0), - /* Set when queuing buffer to an empty DMA queue */ - ISS_VIDEO_DMAQUEUE_QUEUED = BIT(1), -}; - -#define iss_video_dmaqueue_flags_clr(video) \ - ({ (video)->dmaqueue_flags = 0; }) - -/* - * struct iss_video_operations - ISS video operations - * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF - * if there was no buffer previously queued. - */ -struct iss_video_operations { - int (*queue)(struct iss_video *video, struct iss_buffer *buffer); -}; - -struct iss_video { - struct video_device video; - enum v4l2_buf_type type; - struct media_pad pad; - - struct mutex mutex; /* format and crop settings */ - atomic_t active; - - struct iss_device *iss; - - unsigned int capture_mem; - unsigned int bpl_alignment; /* alignment value */ - unsigned int bpl_zero_padding; /* whether the alignment is optional */ - unsigned int bpl_max; /* maximum bytes per line value */ - unsigned int bpl_value; /* bytes per line value */ - unsigned int bpl_padding; /* padding at end of line */ - - /* Pipeline state */ - struct iss_pipeline pipe; - struct mutex stream_lock; /* pipeline and stream states */ - bool error; - - /* Video buffers queue */ - struct vb2_queue *queue; - spinlock_t qlock; /* protects dmaqueue and error */ - struct list_head dmaqueue; - enum iss_video_dmaqueue_flags dmaqueue_flags; - - const struct iss_video_operations *ops; -}; - -#define to_iss_video(vdev) container_of(vdev, struct iss_video, video) - -struct iss_video_fh { - struct v4l2_fh vfh; - struct iss_video *video; - struct vb2_queue queue; - struct v4l2_format format; - struct v4l2_fract timeperframe; -}; - -#define to_iss_video_fh(fh) container_of(fh, struct iss_video_fh, vfh) -#define iss_video_queue_to_iss_video_fh(q) \ - container_of(q, struct iss_video_fh, queue) - -int omap4iss_video_init(struct iss_video *video, const char *name); -void omap4iss_video_cleanup(struct iss_video *video); -int omap4iss_video_register(struct iss_video *video, - struct v4l2_device *vdev); -void omap4iss_video_unregister(struct iss_video *video); -struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video); -void omap4iss_video_cancel_stream(struct iss_video *video); -struct media_pad *omap4iss_video_remote_pad(struct iss_video *video); - -const struct iss_format_info * -omap4iss_video_format_info(u32 code); - -#endif /* OMAP4_ISS_VIDEO_H */ diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index ac398b5a973604..f9bef5173bf25c 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -617,8 +617,6 @@ static const struct vb2_ops rkvdec_queue_ops = { .buf_request_complete = rkvdec_buf_request_complete, .start_streaming = rkvdec_start_streaming, .stop_streaming = rkvdec_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static int rkvdec_request_validate(struct media_request *req) @@ -1103,7 +1101,7 @@ static const struct dev_pm_ops rkvdec_pm_ops = { static struct platform_driver rkvdec_driver = { .probe = rkvdec_probe, - .remove_new = rkvdec_remove, + .remove = rkvdec_remove, .driver = { .name = "rkvdec", .of_match_table = of_rkvdec_match, diff --git a/drivers/staging/media/starfive/camss/stf-camss.c b/drivers/staging/media/starfive/camss/stf-camss.c index b6d34145bc191e..259aaad010d2f0 100644 --- a/drivers/staging/media/starfive/camss/stf-camss.c +++ b/drivers/staging/media/starfive/camss/stf-camss.c @@ -422,7 +422,7 @@ static const struct dev_pm_ops stfcamss_pm_ops = { static struct platform_driver stfcamss_driver = { .probe = stfcamss_probe, - .remove_new = stfcamss_remove, + .remove = stfcamss_remove, .driver = { .name = "starfive-camss", .pm = &stfcamss_pm_ops, diff --git a/drivers/staging/media/starfive/camss/stf-video.c b/drivers/staging/media/starfive/camss/stf-video.c index 989b5e82bae98f..a0420eb6a0aa03 100644 --- a/drivers/staging/media/starfive/camss/stf-video.c +++ b/drivers/staging/media/starfive/camss/stf-video.c @@ -321,8 +321,6 @@ static void video_stop_streaming(struct vb2_queue *q) static const struct vb2_ops stf_video_vb2_q_ops = { .queue_setup = video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_init = video_buf_init, .buf_prepare = video_buf_prepare, .buf_queue = video_buf_queue, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index f52df683604525..52a9588462ce58 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -705,7 +705,7 @@ static const struct dev_pm_ops cedrus_dev_pm_ops = { static struct platform_driver cedrus_driver = { .probe = cedrus_probe, - .remove_new = cedrus_remove, + .remove = cedrus_remove, .driver = { .name = CEDRUS_NAME, .of_match_table = cedrus_dt_match, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index b00feaf4072c99..77f78266f40628 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -570,8 +570,6 @@ static const struct vb2_ops cedrus_qops = { .buf_request_complete = cedrus_buf_request_complete, .start_streaming = cedrus_start_streaming, .stop_streaming = cedrus_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c index 58f8ae92320d67..6877f2beee8c8c 100644 --- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c +++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp.c @@ -536,7 +536,7 @@ MODULE_DEVICE_TABLE(of, sun6i_isp_of_match); static struct platform_driver sun6i_isp_platform_driver = { .probe = sun6i_isp_probe, - .remove_new = sun6i_isp_remove, + .remove = sun6i_isp_remove, .driver = { .name = SUN6I_ISP_NAME, .of_match_table = sun6i_isp_of_match, diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c index 0eea4c2c362718..24899f41dc1c12 100644 --- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c +++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c @@ -368,8 +368,6 @@ static const struct vb2_ops sun6i_isp_capture_queue_ops = { .buf_queue = sun6i_isp_capture_buffer_queue, .start_streaming = sun6i_isp_capture_start_streaming, .stop_streaming = sun6i_isp_capture_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* Video Device */ diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c index 53d05e8a364bb7..3d95ed0b023e31 100644 --- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c +++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c @@ -379,8 +379,6 @@ static const struct vb2_ops sun6i_isp_params_queue_ops = { .buf_queue = sun6i_isp_params_buffer_queue, .start_streaming = sun6i_isp_params_start_streaming, .stop_streaming = sun6i_isp_params_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* Video Device */ diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c index 255cccd0c5fda8..604185c00a1a39 100644 --- a/drivers/staging/media/tegra-video/csi.c +++ b/drivers/staging/media/tegra-video/csi.c @@ -858,5 +858,5 @@ struct platform_driver tegra_csi_driver = { .pm = &tegra_csi_pm_ops, }, .probe = tegra_csi_probe, - .remove_new = tegra_csi_remove, + .remove = tegra_csi_remove, }; diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 57a856a21e9013..c9276ff76157fa 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -287,8 +287,6 @@ static const struct vb2_ops tegra_channel_queue_qops = { .queue_setup = tegra_channel_queue_setup, .buf_prepare = tegra_channel_buffer_prepare, .buf_queue = tegra_channel_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .start_streaming = tegra_channel_start_streaming, .stop_streaming = tegra_channel_stop_streaming, }; @@ -1979,5 +1977,5 @@ struct platform_driver tegra_vi_driver = { .pm = &tegra_vi_pm_ops, }, .probe = tegra_vi_probe, - .remove_new = tegra_vi_remove, + .remove = tegra_vi_remove, }; diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c index 8504b9ea9cea2c..5ec717f3afd503 100644 --- a/drivers/staging/media/tegra-video/vip.c +++ b/drivers/staging/media/tegra-video/vip.c @@ -281,5 +281,5 @@ struct platform_driver tegra_vip_driver = { .of_match_table = tegra_vip_of_id_table, }, .probe = tegra_vip_probe, - .remove_new = tegra_vip_remove, + .remove = tegra_vip_remove, }; diff --git a/drivers/staging/most/TODO b/drivers/staging/most/TODO index 4fa11a9d2cf741..a6448a05ed4612 100644 --- a/drivers/staging/most/TODO +++ b/drivers/staging/most/TODO @@ -1,8 +1 @@ * Get through code review with Greg Kroah-Hartman - -Contact: -To: -Christian Gromm -Cc: -Michael Fabry -Christian Gromm diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c index ed6a9cc8854129..dad2abe6c0c90e 100644 --- a/drivers/staging/most/dim2/dim2.c +++ b/drivers/staging/most/dim2/dim2.c @@ -1090,7 +1090,7 @@ MODULE_DEVICE_TABLE(of, dim2_of_match); static struct platform_driver dim2_driver = { .probe = dim2_probe, - .remove_new = dim2_remove, + .remove = dim2_remove, .driver = { .name = "hdm_dim2", .of_match_table = dim2_of_match, diff --git a/drivers/staging/most/i2c/i2c.c b/drivers/staging/most/i2c/i2c.c index ce869280a056b6..184b2dd11fc34a 100644 --- a/drivers/staging/most/i2c/i2c.c +++ b/drivers/staging/most/i2c/i2c.c @@ -352,8 +352,8 @@ static void i2c_remove(struct i2c_client *client) } static const struct i2c_device_id i2c_id[] = { - { "most_i2c", 0 }, - { }, /* Terminating entry */ + { "most_i2c" }, + { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(i2c, i2c_id); diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 977f8fc29e631f..263774e6a78cae 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -952,7 +952,7 @@ MODULE_DEVICE_TABLE(of, nvidia_nvec_of_match); static struct platform_driver nvec_device_driver = { .probe = tegra_nvec_probe, - .remove_new = tegra_nvec_remove, + .remove = 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 d0259c80f8105e..d2b91318f1516f 100644 --- a/drivers/staging/nvec/nvec_kbd.c +++ b/drivers/staging/nvec/nvec_kbd.c @@ -175,7 +175,7 @@ static void nvec_kbd_remove(struct platform_device *pdev) static struct platform_driver nvec_kbd_driver = { .probe = nvec_kbd_probe, - .remove_new = nvec_kbd_remove, + .remove = nvec_kbd_remove, .driver = { .name = "nvec-kbd", }, diff --git a/drivers/staging/nvec/nvec_power.c b/drivers/staging/nvec/nvec_power.c index 9943b1fff1905d..e0e67a3eb7222b 100644 --- a/drivers/staging/nvec/nvec_power.c +++ b/drivers/staging/nvec/nvec_power.c @@ -433,7 +433,7 @@ static void nvec_power_remove(struct platform_device *pdev) static struct platform_driver nvec_power_driver = { .probe = nvec_power_probe, - .remove_new = nvec_power_remove, + .remove = nvec_power_remove, .driver = { .name = "nvec-power", } diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c index f34016c4a26b6e..575233fa1677ea 100644 --- a/drivers/staging/nvec/nvec_ps2.c +++ b/drivers/staging/nvec/nvec_ps2.c @@ -175,7 +175,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_new = nvec_mouse_remove, + .remove = nvec_mouse_remove, .driver = { .name = "nvec-mouse", .pm = &nvec_mouse_pm_ops, diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index bbf33b88bb7c2a..261f8dbdc38273 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -40,8 +40,8 @@ #define GET_SKBUFF_QOS(skb) 0 #endif -static void cvm_oct_tx_do_cleanup(unsigned long arg); -static DECLARE_TASKLET_OLD(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup); +static void cvm_oct_tx_do_cleanup(struct tasklet_struct *clean); +static DECLARE_TASKLET(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup); /* Maximum number of SKBs to try to free per xmit packet. */ #define MAX_SKB_TO_FREE (MAX_OUT_QUEUE_DEPTH * 2) @@ -670,7 +670,7 @@ void cvm_oct_tx_shutdown_dev(struct net_device *dev) } } -static void cvm_oct_tx_do_cleanup(unsigned long arg) +static void cvm_oct_tx_do_cleanup(struct tasklet_struct *clean) { int port; diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index a5e99cc78a454f..eadb74fc14c8d9 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -977,7 +977,7 @@ MODULE_DEVICE_TABLE(of, cvm_oct_match); static struct platform_driver cvm_oct_driver = { .probe = cvm_oct_probe, - .remove_new = cvm_oct_remove, + .remove = cvm_oct_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = cvm_oct_match, diff --git a/drivers/staging/olpc_dcon/Kconfig b/drivers/staging/olpc_dcon/Kconfig deleted file mode 100644 index d0ba34cc32f7a8..00000000000000 --- a/drivers/staging/olpc_dcon/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config FB_OLPC_DCON - tristate "One Laptop Per Child Display CONtroller support" - depends on OLPC && FB && BROKEN - depends on I2C - depends on GPIO_CS5535 && ACPI - select BACKLIGHT_CLASS_DEVICE - help - In order to support very low power operation, the XO laptop uses a - secondary Display CONtroller, or DCON. This secondary controller - is present in the video pipeline between the primary display - controller (integrate into the processor or chipset) and the LCD - panel. It allows the main processor/display controller to be - completely powered off while still retaining an image on the display. - This controller is only available on OLPC platforms. Unless you have - one of these platforms, you will want to say 'N'. - diff --git a/drivers/staging/olpc_dcon/Makefile b/drivers/staging/olpc_dcon/Makefile deleted file mode 100644 index 734b2ce26066f3..00000000000000 --- a/drivers/staging/olpc_dcon/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -olpc-dcon-objs += olpc_dcon.o olpc_dcon_xo_1.o olpc_dcon_xo_1_5.o -obj-$(CONFIG_FB_OLPC_DCON) += olpc-dcon.o - - diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO deleted file mode 100644 index 7c263358b44a96..00000000000000 --- a/drivers/staging/olpc_dcon/TODO +++ /dev/null @@ -1,15 +0,0 @@ -TODO: - - complete rewrite: - 1. The underlying fbdev drivers need to be converted into drm kernel - modesetting drivers. - 2. The dcon low-power display mode can then be integrated using the - drm damage tracking and self-refresh helpers. - This bolted-on self-refresh support that digs around in fbdev - internals, but isn't properly integrated, is not the correct solution. - - see if vx855 gpio API can be made similar enough to cs5535 so we can - share more code - -Please send patches to Greg Kroah-Hartman and -copy: - Daniel Drake - Jens Frederich diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c deleted file mode 100644 index 4cb904a5f8f402..00000000000000 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ /dev/null @@ -1,807 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Mainly by David Woodhouse, somewhat modified by Jordan Crouse - * - * Copyright © 2006-2007 Red Hat, Inc. - * Copyright © 2006-2007 Advanced Micro Devices, Inc. - * Copyright © 2009 VIA Technology, Inc. - * Copyright (c) 2010-2011 Andres Salomon - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "olpc_dcon.h" - -/* Module definitions */ - -static ushort resumeline = 898; -module_param(resumeline, ushort, 0444); - -static struct dcon_platform_data *pdata; - -/* I2C structures */ - -/* Platform devices */ -static struct platform_device *dcon_device; - -static unsigned short normal_i2c[] = { 0x0d, I2C_CLIENT_END }; - -static s32 dcon_write(struct dcon_priv *dcon, u8 reg, u16 val) -{ - return i2c_smbus_write_word_data(dcon->client, reg, val); -} - -static s32 dcon_read(struct dcon_priv *dcon, u8 reg) -{ - return i2c_smbus_read_word_data(dcon->client, reg); -} - -/* ===== API functions - these are called by a variety of users ==== */ - -static int dcon_hw_init(struct dcon_priv *dcon, int is_init) -{ - u16 ver; - int rc = 0; - - ver = dcon_read(dcon, DCON_REG_ID); - if ((ver >> 8) != 0xDC) { - pr_err("DCON ID not 0xDCxx: 0x%04x instead.\n", ver); - rc = -ENXIO; - goto err; - } - - if (is_init) { - pr_info("Discovered DCON version %x\n", ver & 0xFF); - rc = pdata->init(dcon); - if (rc != 0) { - pr_err("Unable to init.\n"); - goto err; - } - } - - if (ver < 0xdc02) { - dev_err(&dcon->client->dev, - "DCON v1 is unsupported, giving up..\n"); - rc = -ENODEV; - goto err; - } - - /* SDRAM setup/hold time */ - dcon_write(dcon, 0x3a, 0xc040); - dcon_write(dcon, DCON_REG_MEM_OPT_A, 0x0000); /* clear option bits */ - dcon_write(dcon, DCON_REG_MEM_OPT_A, - MEM_DLL_CLOCK_DELAY | MEM_POWER_DOWN); - dcon_write(dcon, DCON_REG_MEM_OPT_B, MEM_SOFT_RESET); - - /* Colour swizzle, AA, no passthrough, backlight */ - if (is_init) { - dcon->disp_mode = MODE_PASSTHRU | MODE_BL_ENABLE | - MODE_CSWIZZLE | MODE_COL_AA; - } - dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); - - /* Set the scanline to interrupt on during resume */ - dcon_write(dcon, DCON_REG_SCAN_INT, resumeline); - -err: - return rc; -} - -/* - * The smbus doesn't always come back due to what is believed to be - * hardware (power rail) bugs. For older models where this is known to - * occur, our solution is to attempt to wait for the bus to stabilize; - * if it doesn't happen, cut power to the dcon, repower it, and wait - * for the bus to stabilize. Rinse, repeat until we have a working - * smbus. For newer models, we simply BUG(); we want to know if this - * still happens despite the power fixes that have been made! - */ -static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down) -{ - unsigned long timeout; - u8 pm; - int x; - -power_up: - if (is_powered_down) { - pm = 1; - x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); - if (x) { - pr_warn("unable to force dcon to power up: %d!\n", x); - return x; - } - usleep_range(10000, 11000); /* we'll be conservative */ - } - - pdata->bus_stabilize_wiggle(); - - for (x = -1, timeout = 50; timeout && x < 0; timeout--) { - usleep_range(1000, 1100); - x = dcon_read(dcon, DCON_REG_ID); - } - if (x < 0) { - pr_err("unable to stabilize dcon's smbus, reasserting power and praying.\n"); - BUG_ON(olpc_board_at_least(olpc_board(0xc2))); - pm = 0; - olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); - msleep(100); - is_powered_down = 1; - goto power_up; /* argh, stupid hardware.. */ - } - - if (is_powered_down) - return dcon_hw_init(dcon, 0); - return 0; -} - -static void dcon_set_backlight(struct dcon_priv *dcon, u8 level) -{ - dcon->bl_val = level; - dcon_write(dcon, DCON_REG_BRIGHT, dcon->bl_val); - - /* Purposely turn off the backlight when we go to level 0 */ - if (dcon->bl_val == 0) { - dcon->disp_mode &= ~MODE_BL_ENABLE; - dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); - } else if (!(dcon->disp_mode & MODE_BL_ENABLE)) { - dcon->disp_mode |= MODE_BL_ENABLE; - dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); - } -} - -/* Set the output type to either color or mono */ -static int dcon_set_mono_mode(struct dcon_priv *dcon, bool enable_mono) -{ - if (dcon->mono == enable_mono) - return 0; - - dcon->mono = enable_mono; - - if (enable_mono) { - dcon->disp_mode &= ~(MODE_CSWIZZLE | MODE_COL_AA); - dcon->disp_mode |= MODE_MONO_LUMA; - } else { - dcon->disp_mode &= ~(MODE_MONO_LUMA); - dcon->disp_mode |= MODE_CSWIZZLE | MODE_COL_AA; - } - - dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode); - return 0; -} - -/* For now, this will be really stupid - we need to address how - * DCONLOAD works in a sleep and account for it accordingly - */ - -static void dcon_sleep(struct dcon_priv *dcon, bool sleep) -{ - int x; - - /* Turn off the backlight and put the DCON to sleep */ - - if (dcon->asleep == sleep) - return; - - if (!olpc_board_at_least(olpc_board(0xc2))) - return; - - if (sleep) { - u8 pm = 0; - - x = olpc_ec_cmd(EC_DCON_POWER_MODE, &pm, 1, NULL, 0); - if (x) - pr_warn("unable to force dcon to power down: %d!\n", x); - else - dcon->asleep = sleep; - } else { - /* Only re-enable the backlight if the backlight value is set */ - if (dcon->bl_val != 0) - dcon->disp_mode |= MODE_BL_ENABLE; - x = dcon_bus_stabilize(dcon, 1); - if (x) - pr_warn("unable to reinit dcon hardware: %d!\n", x); - else - dcon->asleep = sleep; - - /* Restore backlight */ - dcon_set_backlight(dcon, dcon->bl_val); - } - - /* We should turn off some stuff in the framebuffer - but what? */ -} - -/* the DCON seems to get confused if we change DCONLOAD too - * frequently -- i.e., approximately faster than frame time. - * normally we don't change it this fast, so in general we won't - * delay here. - */ -static void dcon_load_holdoff(struct dcon_priv *dcon) -{ - ktime_t delta_t, now; - - while (1) { - now = ktime_get(); - delta_t = ktime_sub(now, dcon->load_time); - if (ktime_to_ns(delta_t) > NSEC_PER_MSEC * 20) - break; - mdelay(4); - } -} - -static bool dcon_blank_fb(struct dcon_priv *dcon, bool blank) -{ - int err; - - console_lock(); - lock_fb_info(dcon->fbinfo); - - dcon->ignore_fb_events = true; - err = fb_blank(dcon->fbinfo, - blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); - dcon->ignore_fb_events = false; - unlock_fb_info(dcon->fbinfo); - console_unlock(); - - if (err) { - dev_err(&dcon->client->dev, "couldn't %sblank framebuffer\n", - blank ? "" : "un"); - return false; - } - return true; -} - -/* Set the source of the display (CPU or DCON) */ -static void dcon_source_switch(struct work_struct *work) -{ - struct dcon_priv *dcon = container_of(work, struct dcon_priv, - switch_source); - int source = dcon->pending_src; - - if (dcon->curr_src == source) - return; - - dcon_load_holdoff(dcon); - - dcon->switched = false; - - switch (source) { - case DCON_SOURCE_CPU: - pr_info("%s to CPU\n", __func__); - /* Enable the scanline interrupt bit */ - if (dcon_write(dcon, DCON_REG_MODE, - dcon->disp_mode | MODE_SCAN_INT)) - pr_err("couldn't enable scanline interrupt!\n"); - else - /* Wait up to one second for the scanline interrupt */ - wait_event_timeout(dcon->waitq, dcon->switched, HZ); - - if (!dcon->switched) - pr_err("Timeout entering CPU mode; expect a screen glitch.\n"); - - /* Turn off the scanline interrupt */ - if (dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode)) - pr_err("couldn't disable scanline interrupt!\n"); - - /* - * Ideally we'd like to disable interrupts here so that the - * fb unblanking and DCON turn on happen at a known time value; - * however, we can't do that right now with fb_blank - * messing with semaphores. - * - * For now, we just hope.. - */ - if (!dcon_blank_fb(dcon, false)) { - pr_err("Failed to enter CPU mode\n"); - dcon->pending_src = DCON_SOURCE_DCON; - return; - } - - /* And turn off the DCON */ - pdata->set_dconload(1); - dcon->load_time = ktime_get(); - - pr_info("The CPU has control\n"); - break; - case DCON_SOURCE_DCON: - { - ktime_t delta_t; - - pr_info("%s to DCON\n", __func__); - - /* Clear DCONLOAD - this implies that the DCON is in control */ - pdata->set_dconload(0); - dcon->load_time = ktime_get(); - - wait_event_timeout(dcon->waitq, dcon->switched, HZ / 2); - - if (!dcon->switched) { - pr_err("Timeout entering DCON mode; expect a screen glitch.\n"); - } else { - /* sometimes the DCON doesn't follow its own rules, - * and doesn't wait for two vsync pulses before - * ack'ing the frame load with an IRQ. the result - * is that the display shows the *previously* - * loaded frame. we can detect this by looking at - * the time between asserting DCONLOAD and the IRQ -- - * if it's less than 20msec, then the DCON couldn't - * have seen two VSYNC pulses. in that case we - * deassert and reassert, and hope for the best. - * see http://dev.laptop.org/ticket/9664 - */ - delta_t = ktime_sub(dcon->irq_time, dcon->load_time); - if (dcon->switched && ktime_to_ns(delta_t) - < NSEC_PER_MSEC * 20) { - pr_err("missed loading, retrying\n"); - pdata->set_dconload(1); - mdelay(41); - pdata->set_dconload(0); - dcon->load_time = ktime_get(); - mdelay(41); - } - } - - dcon_blank_fb(dcon, true); - pr_info("The DCON has control\n"); - break; - } - default: - BUG(); - } - - dcon->curr_src = source; -} - -static void dcon_set_source(struct dcon_priv *dcon, int arg) -{ - if (dcon->pending_src == arg) - return; - - dcon->pending_src = arg; - - if (dcon->curr_src != arg) - schedule_work(&dcon->switch_source); -} - -static void dcon_set_source_sync(struct dcon_priv *dcon, int arg) -{ - dcon_set_source(dcon, arg); - flush_work(&dcon->switch_source); -} - -static ssize_t dcon_mode_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct dcon_priv *dcon = dev_get_drvdata(dev); - - return sprintf(buf, "%4.4X\n", dcon->disp_mode); -} - -static ssize_t dcon_sleep_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct dcon_priv *dcon = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", dcon->asleep); -} - -static ssize_t dcon_freeze_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct dcon_priv *dcon = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", dcon->curr_src == DCON_SOURCE_DCON ? 1 : 0); -} - -static ssize_t dcon_mono_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct dcon_priv *dcon = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", dcon->mono); -} - -static ssize_t dcon_resumeline_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", resumeline); -} - -static ssize_t dcon_mono_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long enable_mono; - int rc; - - rc = kstrtoul(buf, 10, &enable_mono); - if (rc) - return rc; - - dcon_set_mono_mode(dev_get_drvdata(dev), enable_mono ? true : false); - - return count; -} - -static ssize_t dcon_freeze_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct dcon_priv *dcon = dev_get_drvdata(dev); - unsigned long output; - int ret; - - ret = kstrtoul(buf, 10, &output); - if (ret) - return ret; - - switch (output) { - case 0: - dcon_set_source(dcon, DCON_SOURCE_CPU); - break; - case 1: - dcon_set_source_sync(dcon, DCON_SOURCE_DCON); - break; - case 2: /* normally unused */ - dcon_set_source(dcon, DCON_SOURCE_DCON); - break; - default: - return -EINVAL; - } - - return count; -} - -static ssize_t dcon_resumeline_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned short rl; - int rc; - - rc = kstrtou16(buf, 10, &rl); - if (rc) - return rc; - - resumeline = rl; - dcon_write(dev_get_drvdata(dev), DCON_REG_SCAN_INT, resumeline); - - return count; -} - -static ssize_t dcon_sleep_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long output; - int ret; - - ret = kstrtoul(buf, 10, &output); - if (ret) - return ret; - - dcon_sleep(dev_get_drvdata(dev), output ? true : false); - return count; -} - -static struct device_attribute dcon_device_files[] = { - __ATTR(mode, 0444, dcon_mode_show, NULL), - __ATTR(sleep, 0644, dcon_sleep_show, dcon_sleep_store), - __ATTR(freeze, 0644, dcon_freeze_show, dcon_freeze_store), - __ATTR(monochrome, 0644, dcon_mono_show, dcon_mono_store), - __ATTR(resumeline, 0644, dcon_resumeline_show, dcon_resumeline_store), -}; - -static int dcon_bl_update(struct backlight_device *dev) -{ - struct dcon_priv *dcon = bl_get_data(dev); - u8 level = backlight_get_brightness(dev) & 0x0F; - - if (level != dcon->bl_val) - dcon_set_backlight(dcon, level); - - /* power down the DCON when the screen is blanked */ - if (!dcon->ignore_fb_events) - dcon_sleep(dcon, !!(dev->props.state & BL_CORE_FBBLANK)); - - return 0; -} - -static int dcon_bl_get(struct backlight_device *dev) -{ - struct dcon_priv *dcon = bl_get_data(dev); - - return dcon->bl_val; -} - -static const struct backlight_ops dcon_bl_ops = { - .update_status = dcon_bl_update, - .get_brightness = dcon_bl_get, -}; - -static struct backlight_properties dcon_bl_props = { - .max_brightness = 15, - .type = BACKLIGHT_RAW, - .power = BACKLIGHT_POWER_ON, -}; - -static int dcon_reboot_notify(struct notifier_block *nb, - unsigned long foo, void *bar) -{ - struct dcon_priv *dcon = container_of(nb, struct dcon_priv, reboot_nb); - - if (!dcon || !dcon->client) - return NOTIFY_DONE; - - /* Turn off the DCON. Entirely. */ - dcon_write(dcon, DCON_REG_MODE, 0x39); - dcon_write(dcon, DCON_REG_MODE, 0x32); - return NOTIFY_DONE; -} - -static int unfreeze_on_panic(struct notifier_block *nb, - unsigned long e, void *p) -{ - pdata->set_dconload(1); - return NOTIFY_DONE; -} - -static struct notifier_block dcon_panic_nb = { - .notifier_call = unfreeze_on_panic, -}; - -static int dcon_detect(struct i2c_client *client, struct i2c_board_info *info) -{ - strscpy(info->type, "olpc_dcon", I2C_NAME_SIZE); - - return 0; -} - -static int dcon_probe(struct i2c_client *client) -{ - struct dcon_priv *dcon; - int rc, i, j; - - if (!pdata) - return -ENXIO; - - dcon = kzalloc(sizeof(*dcon), GFP_KERNEL); - if (!dcon) - return -ENOMEM; - - dcon->client = client; - init_waitqueue_head(&dcon->waitq); - INIT_WORK(&dcon->switch_source, dcon_source_switch); - dcon->reboot_nb.notifier_call = dcon_reboot_notify; - dcon->reboot_nb.priority = -1; - - i2c_set_clientdata(client, dcon); - - if (num_registered_fb < 1) { - dev_err(&client->dev, "DCON driver requires a registered fb\n"); - rc = -EIO; - goto einit; - } - dcon->fbinfo = registered_fb[0]; - - rc = dcon_hw_init(dcon, 1); - if (rc) - goto einit; - - /* Add the DCON device */ - - dcon_device = platform_device_alloc("dcon", -1); - - if (!dcon_device) { - pr_err("Unable to create the DCON device\n"); - rc = -ENOMEM; - goto eirq; - } - rc = platform_device_add(dcon_device); - platform_set_drvdata(dcon_device, dcon); - - if (rc) { - pr_err("Unable to add the DCON device\n"); - goto edev; - } - - for (i = 0; i < ARRAY_SIZE(dcon_device_files); i++) { - rc = device_create_file(&dcon_device->dev, - &dcon_device_files[i]); - if (rc) { - dev_err(&dcon_device->dev, "Cannot create sysfs file\n"); - goto ecreate; - } - } - - dcon->bl_val = dcon_read(dcon, DCON_REG_BRIGHT) & 0x0F; - - /* Add the backlight device for the DCON */ - dcon_bl_props.brightness = dcon->bl_val; - dcon->bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev, - dcon, &dcon_bl_ops, - &dcon_bl_props); - if (IS_ERR(dcon->bl_dev)) { - dev_err(&client->dev, "cannot register backlight dev (%ld)\n", - PTR_ERR(dcon->bl_dev)); - dcon->bl_dev = NULL; - } - - register_reboot_notifier(&dcon->reboot_nb); - atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb); - - return 0; - - ecreate: - for (j = 0; j < i; j++) - device_remove_file(&dcon_device->dev, &dcon_device_files[j]); - platform_device_del(dcon_device); - edev: - platform_device_put(dcon_device); - dcon_device = NULL; - eirq: - free_irq(DCON_IRQ, dcon); - einit: - kfree(dcon); - return rc; -} - -static void dcon_remove(struct i2c_client *client) -{ - struct dcon_priv *dcon = i2c_get_clientdata(client); - - unregister_reboot_notifier(&dcon->reboot_nb); - atomic_notifier_chain_unregister(&panic_notifier_list, &dcon_panic_nb); - - free_irq(DCON_IRQ, dcon); - - backlight_device_unregister(dcon->bl_dev); - - if (dcon_device) - platform_device_unregister(dcon_device); - cancel_work_sync(&dcon->switch_source); - - kfree(dcon); -} - -#ifdef CONFIG_PM -static int dcon_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dcon_priv *dcon = i2c_get_clientdata(client); - - if (!dcon->asleep) { - /* Set up the DCON to have the source */ - dcon_set_source_sync(dcon, DCON_SOURCE_DCON); - } - - return 0; -} - -static int dcon_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dcon_priv *dcon = i2c_get_clientdata(client); - - if (!dcon->asleep) { - dcon_bus_stabilize(dcon, 0); - dcon_set_source(dcon, DCON_SOURCE_CPU); - } - - return 0; -} - -#else - -#define dcon_suspend NULL -#define dcon_resume NULL - -#endif /* CONFIG_PM */ - -irqreturn_t dcon_interrupt(int irq, void *id) -{ - struct dcon_priv *dcon = id; - u8 status; - - if (pdata->read_status(&status)) - return IRQ_NONE; - - switch (status & 3) { - case 3: - pr_debug("DCONLOAD_MISSED interrupt\n"); - break; - - case 2: /* switch to DCON mode */ - case 1: /* switch to CPU mode */ - dcon->switched = true; - dcon->irq_time = ktime_get(); - wake_up(&dcon->waitq); - break; - - case 0: - /* workaround resume case: the DCON (on 1.5) doesn't - * ever assert status 0x01 when switching to CPU mode - * during resume. this is because DCONLOAD is de-asserted - * _immediately_ upon exiting S3, so the actual release - * of the DCON happened long before this point. - * see http://dev.laptop.org/ticket/9869 - */ - if (dcon->curr_src != dcon->pending_src && !dcon->switched) { - dcon->switched = true; - dcon->irq_time = ktime_get(); - wake_up(&dcon->waitq); - pr_debug("switching w/ status 0/0\n"); - } else { - pr_debug("scanline interrupt w/CPU\n"); - } - } - - return IRQ_HANDLED; -} - -static const struct dev_pm_ops dcon_pm_ops = { - .suspend = dcon_suspend, - .resume = dcon_resume, -}; - -static const struct i2c_device_id dcon_idtable[] = { - { "olpc_dcon", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, dcon_idtable); - -static struct i2c_driver dcon_driver = { - .driver = { - .name = "olpc_dcon", - .pm = &dcon_pm_ops, - }, - .class = I2C_CLASS_HWMON, - .id_table = dcon_idtable, - .probe = dcon_probe, - .remove = dcon_remove, - .detect = dcon_detect, - .address_list = normal_i2c, -}; - -static int __init olpc_dcon_init(void) -{ - /* XO-1.5 */ - if (olpc_board_at_least(olpc_board(0xd0))) - pdata = &dcon_pdata_xo_1_5; - else - pdata = &dcon_pdata_xo_1; - - return i2c_add_driver(&dcon_driver); -} - -static void __exit olpc_dcon_exit(void) -{ - i2c_del_driver(&dcon_driver); -} - -module_init(olpc_dcon_init); -module_exit(olpc_dcon_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h deleted file mode 100644 index 41bd1360b56e47..00000000000000 --- a/drivers/staging/olpc_dcon/olpc_dcon.h +++ /dev/null @@ -1,112 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef OLPC_DCON_H_ -#define OLPC_DCON_H_ - -#include -#include - -/* DCON registers */ - -#define DCON_REG_ID 0 -#define DCON_REG_MODE 1 - -#define MODE_PASSTHRU BIT(0) -#define MODE_SLEEP BIT(1) -#define MODE_SLEEP_AUTO BIT(2) -#define MODE_BL_ENABLE BIT(3) -#define MODE_BLANK BIT(4) -#define MODE_CSWIZZLE BIT(5) -#define MODE_COL_AA BIT(6) -#define MODE_MONO_LUMA BIT(7) -#define MODE_SCAN_INT BIT(8) -#define MODE_CLOCKDIV BIT(9) -#define MODE_DEBUG BIT(14) -#define MODE_SELFTEST BIT(15) - -#define DCON_REG_HRES 0x2 -#define DCON_REG_HTOTAL 0x3 -#define DCON_REG_HSYNC_WIDTH 0x4 -#define DCON_REG_VRES 0x5 -#define DCON_REG_VTOTAL 0x6 -#define DCON_REG_VSYNC_WIDTH 0x7 -#define DCON_REG_TIMEOUT 0x8 -#define DCON_REG_SCAN_INT 0x9 -#define DCON_REG_BRIGHT 0xa -#define DCON_REG_MEM_OPT_A 0x41 -#define DCON_REG_MEM_OPT_B 0x42 - -/* Load Delay Locked Loop (DLL) settings for clock delay */ -#define MEM_DLL_CLOCK_DELAY BIT(0) -/* Memory controller power down function */ -#define MEM_POWER_DOWN BIT(8) -/* Memory controller software reset */ -#define MEM_SOFT_RESET BIT(0) - -/* Status values */ - -#define DCONSTAT_SCANINT 0 -#define DCONSTAT_SCANINT_DCON 1 -#define DCONSTAT_DISPLAYLOAD 2 -#define DCONSTAT_MISSED 3 - -/* Source values */ - -#define DCON_SOURCE_DCON 0 -#define DCON_SOURCE_CPU 1 - -/* Interrupt */ -#define DCON_IRQ 6 - -struct dcon_priv { - struct i2c_client *client; - struct fb_info *fbinfo; - struct backlight_device *bl_dev; - - wait_queue_head_t waitq; - struct work_struct switch_source; - struct notifier_block reboot_nb; - - /* Shadow register for the DCON_REG_MODE register */ - u8 disp_mode; - - /* The current backlight value - this saves us some smbus traffic */ - u8 bl_val; - - /* Current source, initialized at probe time */ - int curr_src; - - /* Desired source */ - int pending_src; - - /* Variables used during switches */ - bool switched; - ktime_t irq_time; - ktime_t load_time; - - /* Current output type; true == mono, false == color */ - bool mono; - bool asleep; - /* This get set while controlling fb blank state from the driver */ - bool ignore_fb_events; -}; - -struct dcon_platform_data { - int (*init)(struct dcon_priv *dcon); - void (*bus_stabilize_wiggle)(void); - void (*set_dconload)(int load); - int (*read_status)(u8 *status); -}; - -struct dcon_gpio { - const char *name; - unsigned long flags; -}; - -#include - -irqreturn_t dcon_interrupt(int irq, void *id); - -extern struct dcon_platform_data dcon_pdata_xo_1; -extern struct dcon_platform_data dcon_pdata_xo_1_5; - -#endif diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c deleted file mode 100644 index 02c059897784d1..00000000000000 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Mainly by David Woodhouse, somewhat modified by Jordan Crouse - * - * Copyright © 2006-2007 Red Hat, Inc. - * Copyright © 2006-2007 Advanced Micro Devices, Inc. - * Copyright © 2009 VIA Technology, Inc. - * Copyright (c) 2010 Andres Salomon - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include - -#include "olpc_dcon.h" - -enum dcon_gpios { - OLPC_DCON_STAT0, - OLPC_DCON_STAT1, - OLPC_DCON_IRQ, - OLPC_DCON_LOAD, - OLPC_DCON_BLANK, -}; - -static const struct dcon_gpio gpios_asis[] = { - [OLPC_DCON_STAT0] = { .name = "dcon_stat0", .flags = GPIOD_ASIS }, - [OLPC_DCON_STAT1] = { .name = "dcon_stat1", .flags = GPIOD_ASIS }, - [OLPC_DCON_IRQ] = { .name = "dcon_irq", .flags = GPIOD_ASIS }, - [OLPC_DCON_LOAD] = { .name = "dcon_load", .flags = GPIOD_ASIS }, - [OLPC_DCON_BLANK] = { .name = "dcon_blank", .flags = GPIOD_ASIS }, -}; - -static struct gpio_desc *gpios[5]; - -static int dcon_init_xo_1(struct dcon_priv *dcon) -{ - unsigned char lob; - int ret, i; - const struct dcon_gpio *pin = &gpios_asis[0]; - - for (i = 0; i < ARRAY_SIZE(gpios_asis); i++) { - gpios[i] = devm_gpiod_get(&dcon->client->dev, pin[i].name, - pin[i].flags); - if (IS_ERR(gpios[i])) { - ret = PTR_ERR(gpios[i]); - pr_err("failed to request %s GPIO: %d\n", pin[i].name, - ret); - return ret; - } - } - - /* Turn off the event enable for GPIO7 just to be safe */ - cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE); - - /* - * Determine the current state by reading the GPIO bit; earlier - * stages of the boot process have established the state. - * - * Note that we read GPIO_OUTPUT_VAL rather than GPIO_READ_BACK here; - * this is because OFW will disable input for the pin and set a value.. - * READ_BACK will only contain a valid value if input is enabled and - * then a value is set. So, future readings of the pin can use - * READ_BACK, but the first one cannot. Awesome, huh? - */ - dcon->curr_src = cs5535_gpio_isset(OLPC_GPIO_DCON_LOAD, GPIO_OUTPUT_VAL) - ? DCON_SOURCE_CPU - : DCON_SOURCE_DCON; - dcon->pending_src = dcon->curr_src; - - /* Set the directions for the GPIO pins */ - gpiod_direction_input(gpios[OLPC_DCON_STAT0]); - gpiod_direction_input(gpios[OLPC_DCON_STAT1]); - gpiod_direction_input(gpios[OLPC_DCON_IRQ]); - gpiod_direction_input(gpios[OLPC_DCON_BLANK]); - gpiod_direction_output(gpios[OLPC_DCON_LOAD], - dcon->curr_src == DCON_SOURCE_CPU); - - /* Set up the interrupt mappings */ - - /* Set the IRQ to pair 2 */ - cs5535_gpio_setup_event(OLPC_GPIO_DCON_IRQ, 2, 0); - - /* Enable group 2 to trigger the DCON interrupt */ - cs5535_gpio_set_irq(2, DCON_IRQ); - - /* Select edge level for interrupt (in PIC) */ - lob = inb(0x4d0); - lob &= ~(1 << DCON_IRQ); - outb(lob, 0x4d0); - - /* Register the interrupt handler */ - if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", dcon)) { - pr_err("failed to request DCON's irq\n"); - return -EIO; - } - - /* Clear INV_EN for GPIO7 (DCONIRQ) */ - cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_INVERT); - - /* Enable filter for GPIO12 (DCONBLANK) */ - cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_FILTER); - - /* Disable filter for GPIO7 */ - cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_FILTER); - - /* Disable event counter for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */ - cs5535_gpio_clear(OLPC_GPIO_DCON_IRQ, GPIO_INPUT_EVENT_COUNT); - cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_INPUT_EVENT_COUNT); - - /* Add GPIO12 to the Filter Event Pair #7 */ - cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_FE7_SEL); - - /* Turn off negative Edge Enable for GPIO12 */ - cs5535_gpio_clear(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_EN); - - /* Enable negative Edge Enable for GPIO7 */ - cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_EN); - - /* Zero the filter amount for Filter Event Pair #7 */ - cs5535_gpio_set(0, GPIO_FLTR7_AMOUNT); - - /* Clear the negative edge status for GPIO7 and GPIO12 */ - cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); - cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS); - - /* FIXME: Clear the positive status as well, just to be sure */ - cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS); - cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS); - - /* Enable events for GPIO7 (DCONIRQ) and GPIO12 (DCONBLANK) */ - cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_EVENTS_ENABLE); - cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_EVENTS_ENABLE); - - return 0; -} - -static void dcon_wiggle_xo_1(void) -{ - int x; - - /* - * According to HiMax, when powering the DCON up we should hold - * SMB_DATA high for 8 SMB_CLK cycles. This will force the DCON - * state machine to reset to a (sane) initial state. Mitch Bradley - * did some testing and discovered that holding for 16 SMB_CLK cycles - * worked a lot more reliably, so that's what we do here. - * - * According to the cs5536 spec, to set GPIO14 to SMB_CLK we must - * simultaneously set AUX1 IN/OUT to GPIO14; ditto for SMB_DATA and - * GPIO15. - */ - cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); - cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_VAL); - cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_ENABLE); - cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_ENABLE); - cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1); - cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); - cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX2); - cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX2); - cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1); - cs5535_gpio_clear(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); - - for (x = 0; x < 16; x++) { - udelay(5); - cs5535_gpio_clear(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); - udelay(5); - cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_VAL); - } - udelay(5); - cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_OUTPUT_AUX1); - cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_OUTPUT_AUX1); - cs5535_gpio_set(OLPC_GPIO_SMB_CLK, GPIO_INPUT_AUX1); - cs5535_gpio_set(OLPC_GPIO_SMB_DATA, GPIO_INPUT_AUX1); -} - -static void dcon_set_dconload_1(int val) -{ - gpiod_set_value(gpios[OLPC_DCON_LOAD], val); -} - -static int dcon_read_status_xo_1(u8 *status) -{ - *status = gpiod_get_value(gpios[OLPC_DCON_STAT0]); - *status |= gpiod_get_value(gpios[OLPC_DCON_STAT1]) << 1; - - /* Clear the negative edge status for GPIO7 */ - cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS); - - return 0; -} - -struct dcon_platform_data dcon_pdata_xo_1 = { - .init = dcon_init_xo_1, - .bus_stabilize_wiggle = dcon_wiggle_xo_1, - .set_dconload = dcon_set_dconload_1, - .read_status = dcon_read_status_xo_1, -}; diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c deleted file mode 100644 index 52cdcd2a89d6f3..00000000000000 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2009,2010 One Laptop per Child - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -/* TODO: this eventually belongs in linux/vx855.h */ -#define NR_VX855_GPI 14 -#define NR_VX855_GPO 13 -#define NR_VX855_GPIO 15 - -#define VX855_GPI(n) (n) -#define VX855_GPO(n) (NR_VX855_GPI + (n)) -#define VX855_GPIO(n) (NR_VX855_GPI + NR_VX855_GPO + (n)) - -#include "olpc_dcon.h" - -/* Hardware setup on the XO 1.5: - * DCONLOAD connects to VX855_GPIO1 (not SMBCK2) - * DCONBLANK connects to VX855_GPIO8 (not SSPICLK) unused in driver - * DCONSTAT0 connects to VX855_GPI10 (not SSPISDI) - * DCONSTAT1 connects to VX855_GPI11 (not nSSPISS) - * DCONIRQ connects to VX855_GPIO12 - * DCONSMBDATA connects to VX855 graphics CRTSPD - * DCONSMBCLK connects to VX855 graphics CRTSPCLK - */ - -#define VX855_GENL_PURPOSE_OUTPUT 0x44c /* PMIO_Rx4c-4f */ -#define VX855_GPI_STATUS_CHG 0x450 /* PMIO_Rx50 */ -#define VX855_GPI_SCI_SMI 0x452 /* PMIO_Rx52 */ -#define BIT_GPIO12 0x40 - -#define PREFIX "OLPC DCON:" - -enum dcon_gpios { - OLPC_DCON_STAT0, - OLPC_DCON_STAT1, - OLPC_DCON_LOAD, -}; - -struct gpiod_lookup_table gpios_table = { - .dev_id = NULL, - .table = { - GPIO_LOOKUP("VX855 South Bridge", VX855_GPIO(1), "dcon_load", - GPIO_ACTIVE_LOW), - GPIO_LOOKUP("VX855 South Bridge", VX855_GPI(10), "dcon_stat0", - GPIO_ACTIVE_LOW), - GPIO_LOOKUP("VX855 South Bridge", VX855_GPI(11), "dcon_stat1", - GPIO_ACTIVE_LOW), - { }, - }, -}; - -static const struct dcon_gpio gpios_asis[] = { - [OLPC_DCON_STAT0] = { .name = "dcon_stat0", .flags = GPIOD_ASIS }, - [OLPC_DCON_STAT1] = { .name = "dcon_stat1", .flags = GPIOD_ASIS }, - [OLPC_DCON_LOAD] = { .name = "dcon_load", .flags = GPIOD_ASIS }, -}; - -static struct gpio_desc *gpios[3]; - -static void dcon_clear_irq(void) -{ - /* irq status will appear in PMIO_Rx50[6] (RW1C) on gpio12 */ - outb(BIT_GPIO12, VX855_GPI_STATUS_CHG); -} - -static int dcon_was_irq(void) -{ - u8 tmp; - - /* irq status will appear in PMIO_Rx50[6] on gpio12 */ - tmp = inb(VX855_GPI_STATUS_CHG); - - return !!(tmp & BIT_GPIO12); -} - -static int dcon_init_xo_1_5(struct dcon_priv *dcon) -{ - unsigned int irq; - const struct dcon_gpio *pin = &gpios_asis[0]; - int i; - int ret; - - /* Add GPIO look up table */ - gpios_table.dev_id = dev_name(&dcon->client->dev); - gpiod_add_lookup_table(&gpios_table); - - /* Get GPIO descriptor */ - for (i = 0; i < ARRAY_SIZE(gpios_asis); i++) { - gpios[i] = devm_gpiod_get(&dcon->client->dev, pin[i].name, - pin[i].flags); - if (IS_ERR(gpios[i])) { - ret = PTR_ERR(gpios[i]); - pr_err("failed to request %s GPIO: %d\n", pin[i].name, - ret); - return ret; - } - } - - dcon_clear_irq(); - - /* set PMIO_Rx52[6] to enable SCI/SMI on gpio12 */ - outb(inb(VX855_GPI_SCI_SMI) | BIT_GPIO12, VX855_GPI_SCI_SMI); - - /* Determine the current state of DCONLOAD, likely set by firmware */ - /* GPIO1 */ - dcon->curr_src = (inl(VX855_GENL_PURPOSE_OUTPUT) & 0x1000) ? - DCON_SOURCE_CPU : DCON_SOURCE_DCON; - dcon->pending_src = dcon->curr_src; - - /* we're sharing the IRQ with ACPI */ - irq = acpi_gbl_FADT.sci_interrupt; - if (request_irq(irq, &dcon_interrupt, IRQF_SHARED, "DCON", dcon)) { - pr_err("DCON (IRQ%d) allocation failed\n", irq); - return 1; - } - - return 0; -} - -static void set_i2c_line(int sda, int scl) -{ - unsigned char tmp; - unsigned int port = 0x26; - - /* FIXME: This directly accesses the CRT GPIO controller !!! */ - outb(port, 0x3c4); - tmp = inb(0x3c5); - - if (scl) - tmp |= 0x20; - else - tmp &= ~0x20; - - if (sda) - tmp |= 0x10; - else - tmp &= ~0x10; - - tmp |= 0x01; - - outb(port, 0x3c4); - outb(tmp, 0x3c5); -} - -static void dcon_wiggle_xo_1_5(void) -{ - int x; - - /* - * According to HiMax, when powering the DCON up we should hold - * SMB_DATA high for 8 SMB_CLK cycles. This will force the DCON - * state machine to reset to a (sane) initial state. Mitch Bradley - * did some testing and discovered that holding for 16 SMB_CLK cycles - * worked a lot more reliably, so that's what we do here. - */ - set_i2c_line(1, 1); - - for (x = 0; x < 16; x++) { - udelay(5); - set_i2c_line(1, 0); - udelay(5); - set_i2c_line(1, 1); - } - udelay(5); - - /* set PMIO_Rx52[6] to enable SCI/SMI on gpio12 */ - outb(inb(VX855_GPI_SCI_SMI) | BIT_GPIO12, VX855_GPI_SCI_SMI); -} - -static void dcon_set_dconload_xo_1_5(int val) -{ - gpiod_set_value(gpios[OLPC_DCON_LOAD], val); -} - -static int dcon_read_status_xo_1_5(u8 *status) -{ - if (!dcon_was_irq()) - return -1; - - /* i believe this is the same as "inb(0x44b) & 3" */ - *status = gpiod_get_value(gpios[OLPC_DCON_STAT0]); - *status |= gpiod_get_value(gpios[OLPC_DCON_STAT1]) << 1; - - dcon_clear_irq(); - - return 0; -} - -struct dcon_platform_data dcon_pdata_xo_1_5 = { - .init = dcon_init_xo_1_5, - .bus_stabilize_wiggle = dcon_wiggle_xo_1_5, - .set_dconload = dcon_set_dconload_xo_1_5, - .read_status = dcon_read_status_xo_1_5, -}; diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig deleted file mode 100644 index e06c189b4ce442..00000000000000 --- a/drivers/staging/rtl8192e/Kconfig +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config RTLLIB - tristate "Support for rtllib wireless devices" - depends on WLAN && m - select LIB80211 - select CRC32 - help - If you have a wireless card that uses rtllib, say - Y. Currently the only card is the rtl8192e. - - If unsure, say N. - - This driver adds support for rtllib wireless cards. - Only the rtl8192e is supported as of now. - -if RTLLIB - -config RTLLIB_CRYPTO_CCMP - tristate "Support for rtllib CCMP crypto" - depends on RTLLIB - select CRYPTO - select CRYPTO_AES - select CRYPTO_CCM - default y - help - CCMP crypto driver for rtllib. - - If you enabled RTLLIB, you want this. - Adds support for the CCM mode Protocol crypto driver for - use in wireless cards (including rtllib cards). - -config RTLLIB_CRYPTO_TKIP - tristate "Support for rtllib TKIP crypto" - depends on RTLLIB - select CRYPTO - select CRYPTO_LIB_ARC4 - select CRYPTO_MICHAEL_MIC - default y - help - TKIP crypto driver for rtllib. - - If you enabled RTLLIB, you want this. - Adds support for the Temporal Key Integrity Protocol for - the IEEE 802.11i standard for use on wireless cards. - -config RTLLIB_CRYPTO_WEP - tristate "Support for rtllib WEP crypto" - select CRYPTO_LIB_ARC4 - depends on RTLLIB - default y - help - WEP crypto driver for rtllib. - - If you enabled RTLLIB, you want this. - Adds support for the (now weak) Wired Equivalent Privacy - (WEP) crypto protocol for wireless cards. - NOTE: This protocol is now considered insecure. - -source "drivers/staging/rtl8192e/rtl8192e/Kconfig" - -endif diff --git a/drivers/staging/rtl8192e/Makefile b/drivers/staging/rtl8192e/Makefile deleted file mode 100644 index a1492215dab108..00000000000000 --- a/drivers/staging/rtl8192e/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -rtllib-objs := \ - rtllib_module.o \ - rtllib_rx.o \ - rtllib_tx.o \ - rtllib_wx.o \ - rtllib_softmac.o \ - rtllib_softmac_wx.o \ - rtl819x_BAProc.o \ - rtl819x_HTProc.o \ - rtl819x_TSProc.o - -obj-$(CONFIG_RTLLIB) += rtllib.o - -obj-$(CONFIG_RTLLIB_CRYPTO_CCMP) += rtllib_crypt_ccmp.o -obj-$(CONFIG_RTLLIB_CRYPTO_TKIP) += rtllib_crypt_tkip.o -obj-$(CONFIG_RTLLIB_CRYPTO_WEP) += rtllib_crypt_wep.o - -obj-$(CONFIG_RTL8192E) += rtl8192e/ diff --git a/drivers/staging/rtl8192e/TODO b/drivers/staging/rtl8192e/TODO deleted file mode 100644 index 7221ae65d63ebf..00000000000000 --- a/drivers/staging/rtl8192e/TODO +++ /dev/null @@ -1,18 +0,0 @@ -To-do list: - -* merge into drivers/net/wireless/realtek/rtlwifi/rtl8192* -* clean up function naming -* Correct the coding style according to Linux guidelines; please read the document - at https://www.kernel.org/doc/html/latest/process/coding-style.html. -* Remove unnecessary debugging/printing macros; for those that are still needed - use the proper kernel API (pr_debug(), dev_dbg(), netdev_dbg()). -* Remove dead code such as unusued functions, variables, fields, etc.. -* Use in-kernel API and remove unnecessary wrappers where possible. -* Fix bugs due to code that sleeps in atomic context. -* Remove the HAL layer and migrate its functionality into the relevant parts of - the driver. -* Switch to use LIB80211. -* Switch to use MAC80211. -* Switch to use CFG80211. -* Improve the error handling of various functions, particularly those that use - existing kernel APIs. diff --git a/drivers/staging/rtl8192e/rtl8192e/Kconfig b/drivers/staging/rtl8192e/rtl8192e/Kconfig deleted file mode 100644 index f8f774a16295be..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config RTL8192E - tristate "RealTek RTL8192E Wireless LAN NIC driver" - depends on PCI && WLAN && RTLLIB - depends on m - select CFG80211 - select WIRELESS_EXT - select WEXT_PRIV - select CRYPTO - select FW_LOADER diff --git a/drivers/staging/rtl8192e/rtl8192e/Makefile b/drivers/staging/rtl8192e/rtl8192e/Makefile deleted file mode 100644 index a442d79ea71e21..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -r8192e_pci-objs := \ - r8192E_dev.o \ - r8192E_phy.o \ - r8192E_firmware.o \ - r8192E_cmdpkt.o \ - table.o \ - r8190P_rtl8256.o \ - rtl_cam.o \ - rtl_core.o \ - rtl_dm.o \ - rtl_eeprom.o \ - rtl_ethtool.o \ - rtl_pci.o \ - rtl_pm.o \ - rtl_ps.o \ - rtl_wx.o \ - -obj-$(CONFIG_RTL8192E) += r8192e_pci.o diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h deleted file mode 100644 index 552fd9b6e3e514..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h +++ /dev/null @@ -1,266 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef R8190P_DEF_H -#define R8190P_DEF_H - -#include -#include "r8192E_phy.h" - -#define MAX_SILENT_RESET_RX_SLOT_NUM 10 - -enum rtl819x_loopback { - RTL819X_NO_LOOPBACK = 0, - RTL819X_MAC_LOOPBACK = 1, - RTL819X_DMA_LOOPBACK = 2, - RTL819X_CCK_LOOPBACK = 3, -}; - -#define DESC90_RATE1M 0x00 -#define DESC90_RATE2M 0x01 -#define DESC90_RATE5_5M 0x02 -#define DESC90_RATE11M 0x03 -#define DESC90_RATE6M 0x04 -#define DESC90_RATE9M 0x05 -#define DESC90_RATE12M 0x06 -#define DESC90_RATE18M 0x07 -#define DESC90_RATE24M 0x08 -#define DESC90_RATE36M 0x09 -#define DESC90_RATE48M 0x0a -#define DESC90_RATE54M 0x0b -#define DESC90_RATEMCS0 0x00 -#define DESC90_RATEMCS1 0x01 -#define DESC90_RATEMCS2 0x02 -#define DESC90_RATEMCS3 0x03 -#define DESC90_RATEMCS4 0x04 -#define DESC90_RATEMCS5 0x05 -#define DESC90_RATEMCS6 0x06 -#define DESC90_RATEMCS7 0x07 -#define DESC90_RATEMCS8 0x08 -#define DESC90_RATEMCS9 0x09 -#define DESC90_RATEMCS10 0x0a -#define DESC90_RATEMCS11 0x0b -#define DESC90_RATEMCS12 0x0c -#define DESC90_RATEMCS13 0x0d -#define DESC90_RATEMCS14 0x0e -#define DESC90_RATEMCS15 0x0f -#define DESC90_RATEMCS32 0x20 - -#define SHORT_SLOT_TIME 9 -#define NON_SHORT_SLOT_TIME 20 - -#define RX_SMOOTH 20 - -#define QSLT_BK 0x1 -#define QSLT_BE 0x0 -#define QSLT_VI 0x4 -#define QSLT_VO 0x6 -#define QSLT_BEACON 0x10 -#define QSLT_HIGH 0x11 -#define QSLT_MGNT 0x12 -#define QSLT_CMD 0x13 - -#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x007 -#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x0aa -#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x024 -#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x007 -#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x10 -#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x4 -#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xd - -#define APPLIED_RESERVED_QUEUE_IN_FW 0x80000000 -#define RSVD_FW_QUEUE_PAGE_BK_SHIFT 0x00 -#define RSVD_FW_QUEUE_PAGE_BE_SHIFT 0x08 -#define RSVD_FW_QUEUE_PAGE_VI_SHIFT 0x10 -#define RSVD_FW_QUEUE_PAGE_VO_SHIFT 0x18 -#define RSVD_FW_QUEUE_PAGE_MGNT_SHIFT 0x10 -#define RSVD_FW_QUEUE_PAGE_BCN_SHIFT 0x00 -#define RSVD_FW_QUEUE_PAGE_PUB_SHIFT 0x08 - -#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 -#define HAL_PRIME_CHNL_OFFSET_LOWER 1 -#define HAL_PRIME_CHNL_OFFSET_UPPER 2 - -enum version_8190_loopback { - VERSION_8190_BD = 0x3, - VERSION_8190_BE -}; - -#define IC_VersionCut_D 0x3 - -enum rf_optype { - RF_OP_By_SW_3wire = 0, - RF_OP_By_FW, - RF_OP_MAX -}; - -struct bb_reg_definition { - u32 rfintfs; - u32 rfintfo; - u32 rfintfe; - u32 rf3wireOffset; - u32 rfHSSIPara2; - u32 rfLSSIReadBack; - u32 rfLSSIReadBackPi; -}; - -struct tx_fwinfo_8190pci { - u8 TxRate:7; - u8 CtsEnable:1; - u8 RtsRate:7; - u8 RtsEnable:1; - u8 TxHT:1; - u8 Short:1; - u8 TxBandwidth:1; - u8 TxSubCarrier:2; - u8 STBC:2; - u8 AllowAggregation:1; - u8 RtsHT:1; - u8 RtsShort:1; - u8 RtsBandwidth:1; - u8 RtsSubcarrier:2; - u8 RtsSTBC:2; - u8 EnableCPUDur:1; - - u32 RxMF:2; - u32 RxAMD:3; - u32 TxPerPktInfoFeedback:1; - u32 Reserved1:2; - u32 TxAGCOffset:4; - u32 TxAGCSign:1; - u32 RAW_TXD:1; - u32 Retry_Limit:4; - u32 Reserved2:1; - u32 PacketID:13; -}; - -struct phy_sts_ofdm_819xpci { - u8 trsw_gain_X[RF90_PATH_MAX]; - u8 pwdb_all; - u8 cfosho_X[4]; - u8 cfotail_X[4]; - u8 rxevm_X[2]; - u8 rxsnr_X[4]; - u8 pdsnr_X[2]; - u8 csi_current_X[2]; - u8 csi_target_X[2]; - u8 sigevm; - u8 max_ex_pwr; - u8 sgi_en; - u8 rxsc_sgien_exflg; -}; - -struct phy_sts_cck_819xpci { - u8 adc_pwdb_X[4]; - u8 sq_rpt; - u8 cck_agc_rpt; -}; - -#define PHY_RSSI_SLID_WIN_MAX 100 -#define PHY_Beacon_RSSI_SLID_WIN_MAX 10 - -struct tx_desc { - u16 PktSize; - u8 Offset; - u8 Reserved1:3; - u8 CmdInit:1; - u8 LastSeg:1; - u8 FirstSeg:1; - u8 LINIP:1; - u8 OWN:1; - - u8 TxFWInfoSize; - u8 RATid:3; - u8 DISFB:1; - u8 USERATE:1; - u8 MOREFRAG:1; - u8 NoEnc:1; - u8 PIFS:1; - u8 QueueSelect:5; - u8 NoACM:1; - u8 Resv:2; - u8 SecCAMID:5; - u8 SecDescAssign:1; - u8 SecType:2; - - u16 TxBufferSize; - u8 PktId:7; - u8 Resv1:1; - u8 Reserved2; - - u32 TxBuffAddr; - - u32 NextDescAddress; - - u32 Reserved5; - u32 Reserved6; - u32 Reserved7; -}; - -struct tx_desc_cmd { - u16 PktSize; - u8 Reserved1; - u8 CmdType:3; - u8 CmdInit:1; - u8 LastSeg:1; - u8 FirstSeg:1; - u8 LINIP:1; - u8 OWN:1; - - u16 ElementReport; - u16 Reserved2; - - u16 TxBufferSize; - u16 Reserved3; - - u32 TxBuffAddr; - u32 NextDescAddress; - u32 Reserved4; - u32 Reserved5; - u32 Reserved6; -}; - -struct rx_desc { - u16 Length:14; - u16 CRC32:1; - u16 ICV:1; - u8 rx_drv_info_size; - u8 Shift:2; - u8 PHYStatus:1; - u8 SWDec:1; - u8 LastSeg:1; - u8 FirstSeg:1; - u8 EOR:1; - u8 OWN:1; - - u32 Reserved2; - - u32 Reserved3; - - u32 BufferAddress; -}; - -struct rx_fwinfo { - u16 Reserved1:12; - u16 PartAggr:1; - u16 FirstAGGR:1; - u16 Reserved2:2; - - u8 RxRate:7; - u8 RxHT:1; - - u8 BW:1; - u8 SPLCP:1; - u8 Reserved3:2; - u8 PAM:1; - u8 Mcast:1; - u8 Bcast:1; - u8 Reserved4:1; - - u32 TSFL; -}; - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c deleted file mode 100644 index 7061f1cf4d3a56..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include "rtl_core.h" -#include "r8192E_phyreg.h" -#include "r8192E_phy.h" -#include "r8190P_rtl8256.h" - -void rtl92e_set_bandwidth(struct net_device *dev, - enum ht_channel_width bandwidth) -{ - u8 eRFPath; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->card_8192_version != VERSION_8190_BD && - priv->card_8192_version != VERSION_8190_BE) { - netdev_warn(dev, "%s(): Unknown HW version.\n", __func__); - return; - } - - for (eRFPath = 0; eRFPath < priv->num_total_rf_path; eRFPath++) { - switch (bandwidth) { - case HT_CHANNEL_WIDTH_20: - rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, - 0x0b, bMask12Bits, 0x100); - rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, - 0x2c, bMask12Bits, 0x3d7); - rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, - 0x0e, bMask12Bits, 0x021); - break; - case HT_CHANNEL_WIDTH_20_40: - rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, - 0x0b, bMask12Bits, 0x300); - rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, - 0x2c, bMask12Bits, 0x3ff); - rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, - 0x0e, bMask12Bits, 0x0e1); - break; - default: - netdev_err(dev, "%s(): Unknown bandwidth: %#X\n", - __func__, bandwidth); - break; - } - } -} - -bool rtl92e_config_rf(struct net_device *dev) -{ - u32 u4RegValue = 0; - u8 eRFPath; - bool rtStatus = true; - struct bb_reg_definition *pPhyReg; - struct r8192_priv *priv = rtllib_priv(dev); - u32 RegOffSetToBeCheck = 0x3; - u32 RegValueToBeCheck = 0x7f1; - u32 RF3_Final_Value = 0; - u8 ConstRetryTimes = 5, RetryTimes = 5; - u8 ret = 0; - - priv->num_total_rf_path = RTL819X_TOTAL_RF_PATH; - - for (eRFPath = (enum rf90_radio_path)RF90_PATH_A; - eRFPath < priv->num_total_rf_path; eRFPath++) { - pPhyReg = &priv->phy_reg_def[eRFPath]; - - switch (eRFPath) { - case RF90_PATH_A: - u4RegValue = rtl92e_get_bb_reg(dev, pPhyReg->rfintfs, - bRFSI_RFENV); - break; - case RF90_PATH_B: - u4RegValue = rtl92e_get_bb_reg(dev, pPhyReg->rfintfs, - bRFSI_RFENV << 16); - break; - } - - rtl92e_set_bb_reg(dev, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1); - - rtl92e_set_bb_reg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); - - rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, - b3WireAddressLength, 0x0); - rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, - b3WireDataLength, 0x0); - - rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, 0x0, - bMask12Bits, 0xbf); - - rtStatus = rtl92e_check_bb_and_rf(dev, HW90_BLOCK_RF, - (enum rf90_radio_path)eRFPath); - if (!rtStatus) { - netdev_err(dev, "%s(): Failed to check RF Path %d.\n", - __func__, eRFPath); - goto fail; - } - - RetryTimes = ConstRetryTimes; - RF3_Final_Value = 0; - while (RF3_Final_Value != RegValueToBeCheck && - RetryTimes != 0) { - ret = rtl92e_config_rf_path(dev, - (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl92e_get_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - RegOffSetToBeCheck, - bMask12Bits); - RetryTimes--; - } - - switch (eRFPath) { - case RF90_PATH_A: - rtl92e_set_bb_reg(dev, pPhyReg->rfintfs, bRFSI_RFENV, - u4RegValue); - break; - case RF90_PATH_B: - rtl92e_set_bb_reg(dev, pPhyReg->rfintfs, - bRFSI_RFENV << 16, u4RegValue); - break; - } - - if (ret) { - netdev_err(dev, - "%s(): Failed to initialize RF Path %d.\n", - __func__, eRFPath); - goto fail; - } - } - return true; - -fail: - return false; -} - -void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel) -{ - u32 TxAGC = 0; - struct r8192_priv *priv = rtllib_priv(dev); - - TxAGC = powerlevel; - if (priv->dynamic_tx_low_pwr) { - if (priv->customer_id == RT_CID_819X_NETCORE) - TxAGC = 0x22; - else - TxAGC += priv->cck_pwr_enl; - } - if (TxAGC > 0x24) - TxAGC = 0x24; - rtl92e_set_bb_reg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); -} - -void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u32 writeVal, powerBase0, powerBase1, writeVal_tmp; - u8 index = 0; - u16 RegOffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c}; - u8 byte0, byte1, byte2, byte3; - - powerBase0 = powerlevel + priv->legacy_ht_tx_pwr_diff; - powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | - (powerBase0 << 8) | powerBase0; - powerBase1 = powerlevel; - powerBase1 = (powerBase1 << 24) | (powerBase1 << 16) | - (powerBase1 << 8) | powerBase1; - - for (index = 0; index < 6; index++) { - writeVal = (u32)(priv->mcs_tx_pwr_level_org_offset[index] + - ((index < 2) ? powerBase0 : powerBase1)); - byte0 = writeVal & 0x7f; - byte1 = (writeVal & 0x7f00) >> 8; - byte2 = (writeVal & 0x7f0000) >> 16; - byte3 = (writeVal & 0x7f000000) >> 24; - if (byte0 > 0x24) - byte0 = 0x24; - if (byte1 > 0x24) - byte1 = 0x24; - if (byte2 > 0x24) - byte2 = 0x24; - if (byte3 > 0x24) - byte3 = 0x24; - - if (index == 3) { - writeVal_tmp = (byte3 << 24) | (byte2 << 16) | - (byte1 << 8) | byte0; - priv->pwr_track = writeVal_tmp; - } - - if (priv->dynamic_tx_high_pwr) - writeVal = 0x03030303; - else - writeVal = (byte3 << 24) | (byte2 << 16) | - (byte1 << 8) | byte0; - rtl92e_set_bb_reg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); - } -} diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h deleted file mode 100644 index 3c52e2b4309599..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef RTL8225H -#define RTL8225H - -#define RTL819X_TOTAL_RF_PATH 2 -void rtl92e_set_bandwidth(struct net_device *dev, - enum ht_channel_width bandwidth); -bool rtl92e_config_rf(struct net_device *dev); -void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel); -void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel); - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c deleted file mode 100644 index 533cc4e723f684..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include "rtl_core.h" -#include "r8192E_hw.h" -#include "r8192E_cmdpkt.h" - -bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data, - u32 len) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u16 frag_length = 0, frag_offset = 0; - struct sk_buff *skb; - unsigned char *seg_ptr; - struct cb_desc *tcb_desc; - u8 last_ini_pkt; - - struct tx_fwinfo_8190pci *pTxFwInfo = NULL; - - do { - if ((len - frag_offset) > CMDPACKET_FRAG_SIZE) { - frag_length = CMDPACKET_FRAG_SIZE; - last_ini_pkt = 0; - - } else { - frag_length = (u16)(len - frag_offset); - last_ini_pkt = 1; - } - - if (type == DESC_PACKET_TYPE_NORMAL) - skb = dev_alloc_skb(frag_length + - priv->rtllib->tx_headroom + 4); - else - skb = dev_alloc_skb(frag_length + 4); - - if (!skb) - return false; - - memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); - tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); - tcb_desc->queue_index = TXCMD_QUEUE; - tcb_desc->cmd_or_init = type; - tcb_desc->last_ini_pkt = last_ini_pkt; - - if (type == DESC_PACKET_TYPE_NORMAL) { - tcb_desc->pkt_size = frag_length; - - seg_ptr = skb_put(skb, priv->rtllib->tx_headroom); - pTxFwInfo = (struct tx_fwinfo_8190pci *)seg_ptr; - memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci)); - memset(pTxFwInfo, 0x12, 8); - } else { - tcb_desc->txbuf_size = frag_length; - } - - skb_put_data(skb, data, frag_length); - - if (type == DESC_PACKET_TYPE_INIT && - (!priv->rtllib->check_nic_enough_desc(dev, TXCMD_QUEUE) || - (!skb_queue_empty(&priv->rtllib->skb_waitq[TXCMD_QUEUE])) || - (priv->rtllib->queue_stop))) { - skb_queue_tail(&priv->rtllib->skb_waitq[TXCMD_QUEUE], - skb); - } else { - priv->rtllib->softmac_hard_start_xmit(skb, dev); - } - - data += frag_length; - frag_offset += frag_length; - - } while (frag_offset < len); - - rtl92e_writeb(dev, TP_POLL, TP_POLL_CQ); - - return true; -} diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h deleted file mode 100644 index c63909199e9365..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef R819XUSB_CMDPKT_H -#define R819XUSB_CMDPKT_H - -bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data, - u32 len); -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c deleted file mode 100644 index 2672b1ddf88e39..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ /dev/null @@ -1,1915 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#include "rtl_core.h" -#include "r8192E_phy.h" -#include "r8192E_phyreg.h" -#include "r8190P_rtl8256.h" -#include "r8192E_cmdpkt.h" -#include "rtl_dm.h" -#include "rtl_wx.h" - -static int WDCAPARA_ADD[] = {EDCAPARA_BE, EDCAPARA_BK, EDCAPARA_VI, - EDCAPARA_VO}; - -static void _rtl92e_update_msr(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 msr; - - msr = rtl92e_readb(dev, MSR); - msr &= ~MSR_LINK_MASK; - - switch (priv->rtllib->iw_mode) { - case IW_MODE_INFRA: - if (priv->rtllib->link_state == MAC80211_LINKED) - msr |= MSR_LINK_MANAGED; - break; - default: - break; - } - - rtl92e_writeb(dev, MSR, msr); -} - -void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - switch (variable) { - case HW_VAR_BSSID: - /* BSSIDR 2 byte alignment */ - rtl92e_writew(dev, BSSIDR, *(u16 *)val); - rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(val + 2)); - break; - - case HW_VAR_MEDIA_STATUS: - { - enum rt_op_mode op_mode = *((enum rt_op_mode *)(val)); - u8 btMsr = rtl92e_readb(dev, MSR); - - btMsr &= 0xfc; - - switch (op_mode) { - case RT_OP_MODE_INFRASTRUCTURE: - btMsr |= MSR_INFRA; - break; - - case RT_OP_MODE_IBSS: - btMsr |= MSR_ADHOC; - break; - - case RT_OP_MODE_AP: - btMsr |= MSR_AP; - break; - - default: - btMsr |= MSR_NOLINK; - break; - } - - rtl92e_writeb(dev, MSR, btMsr); - } - break; - - case HW_VAR_CECHK_BSSID: - { - u32 RegRCR, Type; - - Type = val[0]; - RegRCR = rtl92e_readl(dev, RCR); - priv->receive_config = RegRCR; - - if (Type) - RegRCR |= (RCR_CBSSID); - else - RegRCR &= (~RCR_CBSSID); - - rtl92e_writel(dev, RCR, RegRCR); - priv->receive_config = RegRCR; - } - break; - - case HW_VAR_SLOT_TIME: - - priv->slot_time = val[0]; - rtl92e_writeb(dev, SLOT_TIME, val[0]); - - break; - - case HW_VAR_ACK_PREAMBLE: - { - u32 regTmp; - - priv->short_preamble = (bool)*val; - regTmp = priv->basic_rate; - if (priv->short_preamble) - regTmp |= BRSR_AckShortPmb; - rtl92e_writel(dev, RRSR, regTmp); - break; - } - - case HW_VAR_CPU_RST: - rtl92e_writel(dev, CPU_GEN, ((u32 *)(val))[0]); - break; - - case HW_VAR_AC_PARAM: - { - u8 pAcParam = *val; - u32 eACI = pAcParam; - u8 u1bAIFS; - u32 u4bAcParam; - u8 mode = priv->rtllib->mode; - struct rtllib_qos_parameters *qop = - &priv->rtllib->current_network.qos_data.parameters; - - u1bAIFS = qop->aifs[pAcParam] * - ((mode & (WIRELESS_MODE_G | WIRELESS_MODE_N_24G)) ? 9 : 20) + asifs_time; - - rtl92e_dm_init_edca_turbo(dev); - - u4bAcParam = (le16_to_cpu(qop->tx_op_limit[pAcParam]) << - AC_PARAM_TXOP_LIMIT_OFFSET) | - ((le16_to_cpu(qop->cw_max[pAcParam])) << - AC_PARAM_ECW_MAX_OFFSET) | - ((le16_to_cpu(qop->cw_min[pAcParam])) << - AC_PARAM_ECW_MIN_OFFSET) | - (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET); - - switch (eACI) { - case AC1_BK: - rtl92e_writel(dev, EDCAPARA_BK, u4bAcParam); - break; - - case AC0_BE: - rtl92e_writel(dev, EDCAPARA_BE, u4bAcParam); - break; - - case AC2_VI: - rtl92e_writel(dev, EDCAPARA_VI, u4bAcParam); - break; - - case AC3_VO: - rtl92e_writel(dev, EDCAPARA_VO, u4bAcParam); - break; - - default: - netdev_info(dev, "SetHwReg8185(): invalid ACI: %d !\n", - eACI); - break; - } - priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACM_CTRL, - &pAcParam); - break; - } - - case HW_VAR_ACM_CTRL: - { - struct rtllib_qos_parameters *qos_parameters = - &priv->rtllib->current_network.qos_data.parameters; - u8 pAcParam = *val; - u32 eACI = pAcParam; - union aci_aifsn *pAciAifsn = (union aci_aifsn *)& - (qos_parameters->aifs[0]); - u8 acm = pAciAifsn->f.acm; - u8 AcmCtrl = rtl92e_readb(dev, ACM_HW_CTRL); - - if (acm) { - switch (eACI) { - case AC0_BE: - AcmCtrl |= ACM_HW_BEQ_EN; - break; - - case AC2_VI: - AcmCtrl |= ACM_HW_VIQ_EN; - break; - - case AC3_VO: - AcmCtrl |= ACM_HW_VOQ_EN; - break; - } - } else { - switch (eACI) { - case AC0_BE: - AcmCtrl &= (~ACM_HW_BEQ_EN); - break; - - case AC2_VI: - AcmCtrl &= (~ACM_HW_VIQ_EN); - break; - - case AC3_VO: - AcmCtrl &= (~ACM_HW_BEQ_EN); - break; - - default: - break; - } - } - rtl92e_writeb(dev, ACM_HW_CTRL, AcmCtrl); - break; - } - - case HW_VAR_SIFS: - rtl92e_writeb(dev, SIFS, val[0]); - rtl92e_writeb(dev, SIFS + 1, val[0]); - break; - - case HW_VAR_RF_TIMING: - { - u8 Rf_Timing = *val; - - rtl92e_writeb(dev, rFPGA0_RFTiming1, Rf_Timing); - break; - } - - default: - break; - } -} - -static void _rtl92e_read_eeprom_info(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - const u8 bMac_Tmp_Addr[ETH_ALEN] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x01}; - u8 tempval; - u8 ICVer8192, ICVer8256; - u16 i, usValue, IC_Version; - u16 EEPROMId; - - EEPROMId = rtl92e_eeprom_read(dev, 0); - if (EEPROMId != RTL8190_EEPROM_ID) { - netdev_err(dev, "%s(): Invalid EEPROM ID: %x\n", __func__, - EEPROMId); - priv->autoload_fail_flag = true; - } else { - priv->autoload_fail_flag = false; - } - - if (!priv->autoload_fail_flag) { - priv->eeprom_vid = rtl92e_eeprom_read(dev, EEPROM_VID >> 1); - priv->eeprom_did = rtl92e_eeprom_read(dev, EEPROM_DID >> 1); - - usValue = rtl92e_eeprom_read(dev, - (EEPROM_Customer_ID >> 1)) >> 8; - priv->eeprom_customer_id = usValue & 0xff; - usValue = rtl92e_eeprom_read(dev, - EEPROM_ICVersion_ChannelPlan >> 1); - IC_Version = (usValue & 0xff00) >> 8; - - ICVer8192 = IC_Version & 0xf; - ICVer8256 = (IC_Version & 0xf0) >> 4; - if (ICVer8192 == 0x2) { - if (ICVer8256 == 0x5) - priv->card_8192_version = VERSION_8190_BE; - } - switch (priv->card_8192_version) { - case VERSION_8190_BD: - case VERSION_8190_BE: - break; - default: - priv->card_8192_version = VERSION_8190_BD; - break; - } - } else { - priv->card_8192_version = VERSION_8190_BD; - priv->eeprom_vid = 0; - priv->eeprom_did = 0; - priv->eeprom_customer_id = 0; - } - - if (!priv->autoload_fail_flag) { - u8 addr[ETH_ALEN]; - - for (i = 0; i < 6; i += 2) { - usValue = rtl92e_eeprom_read(dev, - (EEPROM_NODE_ADDRESS_BYTE_0 + i) >> 1); - *(u16 *)(&addr[i]) = usValue; - } - eth_hw_addr_set(dev, addr); - } else { - eth_hw_addr_set(dev, bMac_Tmp_Addr); - } - - if (priv->card_8192_version > VERSION_8190_BD) - priv->tx_pwr_data_read_from_eeprom = true; - else - priv->tx_pwr_data_read_from_eeprom = false; - - 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; - } else { - priv->eeprom_legacy_ht_tx_pwr_diff = 0x04; - } - - if (!priv->autoload_fail_flag) - priv->eeprom_thermal_meter = ((rtl92e_eeprom_read(dev, - (EEPROM_ThermalMeter >> 1))) & - 0xff00) >> 8; - else - priv->eeprom_thermal_meter = EEPROM_Default_ThermalMeter; - priv->tssi_13dBm = priv->eeprom_thermal_meter * 100; - - if (priv->epromtype == EEPROM_93C46) { - if (!priv->autoload_fail_flag) { - usValue = rtl92e_eeprom_read(dev, - EEPROM_TxPwDiff_CrystalCap >> 1); - priv->eeprom_ant_pwr_diff = usValue & 0x0fff; - priv->eeprom_crystal_cap = (usValue & 0xf000) - >> 12; - } else { - priv->eeprom_ant_pwr_diff = - EEPROM_Default_AntTxPowerDiff; - priv->eeprom_crystal_cap = - EEPROM_Default_TxPwDiff_CrystalCap; - } - - for (i = 0; i < 14; i += 2) { - if (!priv->autoload_fail_flag) - usValue = rtl92e_eeprom_read(dev, - (EEPROM_TxPwIndex_CCK + i) >> 1); - else - usValue = EEPROM_Default_TxPower; - *((u16 *)(&priv->eeprom_tx_pwr_level_cck[i])) = - usValue; - } - for (i = 0; i < 14; i += 2) { - if (!priv->autoload_fail_flag) - usValue = rtl92e_eeprom_read(dev, - (EEPROM_TxPwIndex_OFDM_24G + i) >> 1); - else - usValue = EEPROM_Default_TxPower; - *((u16 *)(&priv->eeprom_tx_pwr_level_ofdm24g[i])) - = usValue; - } - } - if (priv->epromtype == EEPROM_93C46) { - for (i = 0; i < 14; i++) { - priv->tx_pwr_level_cck[i] = - priv->eeprom_tx_pwr_level_cck[i]; - priv->tx_pwr_level_ofdm_24g[i] = - priv->eeprom_tx_pwr_level_ofdm24g[i]; - } - priv->legacy_ht_tx_pwr_diff = - priv->eeprom_legacy_ht_tx_pwr_diff; - priv->antenna_tx_pwr_diff[0] = priv->eeprom_ant_pwr_diff & 0xf; - priv->antenna_tx_pwr_diff[1] = (priv->eeprom_ant_pwr_diff & - 0xf0) >> 4; - priv->antenna_tx_pwr_diff[2] = (priv->eeprom_ant_pwr_diff & - 0xf00) >> 8; - priv->crystal_cap = priv->eeprom_crystal_cap; - priv->thermal_meter[0] = priv->eeprom_thermal_meter & 0xf; - priv->thermal_meter[1] = (priv->eeprom_thermal_meter & - 0xf0) >> 4; - } else if (priv->epromtype == EEPROM_93C56) { - priv->legacy_ht_tx_pwr_diff = - priv->eeprom_legacy_ht_tx_pwr_diff; - priv->antenna_tx_pwr_diff[0] = 0; - priv->antenna_tx_pwr_diff[1] = 0; - priv->antenna_tx_pwr_diff[2] = 0; - priv->crystal_cap = priv->eeprom_crystal_cap; - priv->thermal_meter[0] = priv->eeprom_thermal_meter & 0xf; - priv->thermal_meter[1] = (priv->eeprom_thermal_meter & - 0xf0) >> 4; - } - } - - rtl92e_init_adaptive_rate(dev); - - switch (priv->eeprom_customer_id) { - case EEPROM_CID_NetCore: - priv->customer_id = RT_CID_819X_NETCORE; - break; - case EEPROM_CID_TOSHIBA: - priv->customer_id = RT_CID_TOSHIBA; - break; - } - - if (priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304) - priv->rtllib->bSupportRemoteWakeUp = true; - else - priv->rtllib->bSupportRemoteWakeUp = false; -} - -void rtl92e_get_eeprom_size(struct net_device *dev) -{ - u16 curCR; - struct r8192_priv *priv = rtllib_priv(dev); - - curCR = rtl92e_readw(dev, EPROM_CMD); - priv->epromtype = (curCR & EPROM_CMD_9356SEL) ? EEPROM_93C56 : - EEPROM_93C46; - _rtl92e_read_eeprom_info(dev); -} - -static void _rtl92e_hwconfig(struct net_device *dev) -{ - u32 regRATR = 0, regRRSR = 0; - u8 regBwOpMode = 0, regTmp = 0; - struct r8192_priv *priv = rtllib_priv(dev); - - switch (priv->rtllib->mode) { - case WIRELESS_MODE_B: - regBwOpMode = BW_OPMODE_20MHZ; - regRATR = RATE_ALL_CCK; - regRRSR = RATE_ALL_CCK; - break; - case WIRELESS_MODE_AUTO: - case WIRELESS_MODE_N_24G: - regBwOpMode = BW_OPMODE_20MHZ; - regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG | - RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS; - regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; - break; - case WIRELESS_MODE_G: - default: - regBwOpMode = BW_OPMODE_20MHZ; - regRATR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; - regRRSR = RATE_ALL_CCK | RATE_ALL_OFDM_AG; - break; - } - - rtl92e_writeb(dev, BW_OPMODE, regBwOpMode); - { - u32 ratr_value; - - ratr_value = regRATR; - ratr_value &= ~(RATE_ALL_OFDM_2SS); - rtl92e_writel(dev, RATR0, ratr_value); - rtl92e_writeb(dev, UFWP, 1); - } - regTmp = rtl92e_readb(dev, 0x313); - regRRSR = ((regTmp) << 24) | (regRRSR & 0x00ffffff); - rtl92e_writel(dev, RRSR, regRRSR); - - rtl92e_writew(dev, RETRY_LIMIT, - priv->short_retry_limit << RETRY_LIMIT_SHORT_SHIFT | - priv->long_retry_limit << RETRY_LIMIT_LONG_SHIFT); -} - -bool rtl92e_start_adapter(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u32 ulRegRead; - bool rtStatus = true; - u8 tmpvalue; - u8 ICVersion, SwitchingRegulatorOutput; - bool bfirmwareok = true; - u32 tmpRegA, TempCCk; - int i = 0; - u32 retry_times = 0; - - priv->being_init_adapter = true; - -start: - rtl92e_reset_desc_ring(dev); - priv->rf_mode = RF_OP_By_SW_3wire; - - rtl92e_writeb(dev, ANAPAR, 0x37); - mdelay(500); - - priv->fw_info->status = FW_STATUS_0_INIT; - - ulRegRead = rtl92e_readl(dev, CPU_GEN); - if (priv->fw_info->status == FW_STATUS_0_INIT) - ulRegRead |= CPU_GEN_SYSTEM_RESET; - else if (priv->fw_info->status == FW_STATUS_5_READY) - ulRegRead |= CPU_GEN_FIRMWARE_RESET; - else - netdev_err(dev, "%s(): undefined firmware state: %d.\n", - __func__, priv->fw_info->status); - - rtl92e_writel(dev, CPU_GEN, ulRegRead); - - ICVersion = rtl92e_readb(dev, IC_VERRSION); - if (ICVersion >= 0x4) { - SwitchingRegulatorOutput = rtl92e_readb(dev, SWREGULATOR); - if (SwitchingRegulatorOutput != 0xb8) { - rtl92e_writeb(dev, SWREGULATOR, 0xa8); - mdelay(1); - rtl92e_writeb(dev, SWREGULATOR, 0xb8); - } - } - rtStatus = rtl92e_config_bb(dev); - if (!rtStatus) { - netdev_warn(dev, "%s(): Failed to configure BB\n", __func__); - return rtStatus; - } - - priv->loopback_mode = RTL819X_NO_LOOPBACK; - ulRegRead = rtl92e_readl(dev, CPU_GEN); - if (priv->loopback_mode == RTL819X_NO_LOOPBACK) - ulRegRead = (ulRegRead & CPU_GEN_NO_LOOPBACK_MSK) | - CPU_GEN_NO_LOOPBACK_SET; - else if (priv->loopback_mode == RTL819X_MAC_LOOPBACK) - ulRegRead |= CPU_CCK_LOOPBACK; - else - netdev_err(dev, "%s: Invalid loopback mode setting.\n", - __func__); - - rtl92e_writel(dev, CPU_GEN, ulRegRead); - - udelay(500); - - _rtl92e_hwconfig(dev); - rtl92e_writeb(dev, CMDR, CR_RE | CR_TE); - - rtl92e_writeb(dev, PCIF, ((MXDMA2_NO_LIMIT << MXDMA2_RX_SHIFT) | - (MXDMA2_NO_LIMIT << MXDMA2_TX_SHIFT))); - rtl92e_writel(dev, MAC0, ((u32 *)dev->dev_addr)[0]); - rtl92e_writew(dev, MAC4, ((u16 *)(dev->dev_addr + 4))[0]); - rtl92e_writel(dev, RCR, priv->receive_config); - - rtl92e_writel(dev, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK << - RSVD_FW_QUEUE_PAGE_BK_SHIFT | - NUM_OF_PAGE_IN_FW_QUEUE_BE << - RSVD_FW_QUEUE_PAGE_BE_SHIFT | - NUM_OF_PAGE_IN_FW_QUEUE_VI << - RSVD_FW_QUEUE_PAGE_VI_SHIFT | - NUM_OF_PAGE_IN_FW_QUEUE_VO << - RSVD_FW_QUEUE_PAGE_VO_SHIFT); - rtl92e_writel(dev, RQPN2, NUM_OF_PAGE_IN_FW_QUEUE_MGNT << - RSVD_FW_QUEUE_PAGE_MGNT_SHIFT); - rtl92e_writel(dev, RQPN3, APPLIED_RESERVED_QUEUE_IN_FW | - NUM_OF_PAGE_IN_FW_QUEUE_BCN << - RSVD_FW_QUEUE_PAGE_BCN_SHIFT | - NUM_OF_PAGE_IN_FW_QUEUE_PUB << - RSVD_FW_QUEUE_PAGE_PUB_SHIFT); - - rtl92e_tx_enable(dev); - rtl92e_rx_enable(dev); - ulRegRead = (0xFFF00000 & rtl92e_readl(dev, RRSR)) | - RATE_ALL_OFDM_AG | RATE_ALL_CCK; - rtl92e_writel(dev, RRSR, ulRegRead); - rtl92e_writel(dev, RATR0 + 4 * 7, (RATE_ALL_OFDM_AG | RATE_ALL_CCK)); - - rtl92e_writeb(dev, ACK_TIMEOUT, 0x30); - - rtl92e_set_wireless_mode(dev, priv->rtllib->mode); - rtl92e_cam_reset(dev); - { - u8 SECR_value = 0x0; - - SECR_value |= SCR_TxEncEnable; - SECR_value |= SCR_RxDecEnable; - SECR_value |= SCR_NoSKMC; - rtl92e_writeb(dev, SECR, SECR_value); - } - rtl92e_writew(dev, ATIMWND, 2); - rtl92e_writew(dev, BCN_INTERVAL, 100); - - for (i = 0; i < QOS_QUEUE_NUM; i++) - rtl92e_writel(dev, WDCAPARA_ADD[i], 0x005e4332); - - rtl92e_writeb(dev, 0xbe, 0xc0); - - rtl92e_config_mac(dev); - - if (priv->card_8192_version > VERSION_8190_BD) { - rtl92e_get_tx_power(dev); - rtl92e_set_tx_power(dev, priv->chan); - } - - tmpvalue = rtl92e_readb(dev, IC_VERRSION); - priv->ic_cut = tmpvalue; - - bfirmwareok = rtl92e_init_fw(dev); - if (!bfirmwareok) { - if (retry_times < 10) { - retry_times++; - goto start; - } else { - rtStatus = false; - goto end; - } - } - - rtStatus = rtl92e_config_rf(dev); - if (!rtStatus) { - netdev_info(dev, "RF Config failed\n"); - return rtStatus; - } - - rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); - rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); - - rtl92e_writeb(dev, 0x87, 0x0); - - if (priv->rtllib->rf_off_reason > RF_CHANGE_BY_PS) { - rtl92e_set_rf_state(dev, rf_off, priv->rtllib->rf_off_reason); - } else if (priv->rtllib->rf_off_reason >= RF_CHANGE_BY_IPS) { - rtl92e_set_rf_state(dev, rf_off, priv->rtllib->rf_off_reason); - } else { - priv->rtllib->rf_power_state = rf_on; - priv->rtllib->rf_off_reason = 0; - } - - if (priv->rtllib->FwRWRF) - priv->rf_mode = RF_OP_By_FW; - else - priv->rf_mode = RF_OP_By_SW_3wire; - - rtl92e_dm_init_txpower_tracking(dev); - - if (priv->ic_cut >= IC_VersionCut_D) { - tmpRegA = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord); - rtl92e_get_bb_reg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord); - - for (i = 0; i < TX_BB_GAIN_TABLE_LEN; i++) { - if (tmpRegA == dm_tx_bb_gain[i]) { - priv->rfa_txpowertrackingindex = i; - priv->rfa_txpowertrackingindex_real = i; - priv->rfa_txpowertracking_default = - priv->rfa_txpowertrackingindex; - break; - } - } - - TempCCk = rtl92e_get_bb_reg(dev, rCCK0_TxFilter1, - bMaskByte2); - - for (i = 0; i < CCK_TX_BB_GAIN_TABLE_LEN; i++) { - if (TempCCk == dm_cck_tx_bb_gain[i][0]) { - priv->cck_present_attn_20m_def = i; - break; - } - } - priv->cck_present_attn_40m_def = 0; - priv->cck_present_attn_diff = 0; - priv->cck_present_attn = - priv->cck_present_attn_20m_def; - priv->btxpower_tracking = false; - } - rtl92e_irq_enable(dev); -end: - priv->being_init_adapter = false; - return rtStatus; -} - -static void _rtl92e_net_update(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_network *net; - u16 rate_config = 0; - - net = &priv->rtllib->current_network; - rtl92e_config_rate(dev, &rate_config); - priv->dot11_current_preamble_mode = PREAMBLE_AUTO; - priv->basic_rate = rate_config &= 0x15f; - rtl92e_writew(dev, BSSIDR, *(u16 *)net->bssid); - rtl92e_writel(dev, BSSIDR + 2, *(u32 *)(net->bssid + 2)); -} - -void rtl92e_link_change(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - - if (!priv->up) - return; - - if (ieee->link_state == MAC80211_LINKED) { - _rtl92e_net_update(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); - } else { - rtl92e_writeb(dev, 0x173, 0); - } - _rtl92e_update_msr(dev); - - if (ieee->iw_mode == IW_MODE_INFRA) { - u32 reg; - - reg = rtl92e_readl(dev, RCR); - if (priv->rtllib->link_state == MAC80211_LINKED) - priv->receive_config = reg |= RCR_CBSSID; - else - priv->receive_config = reg &= ~RCR_CBSSID; - - rtl92e_writel(dev, RCR, reg); - } -} - -void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da, - bool write_into_reg) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (allow_all_da) - priv->receive_config |= RCR_AAP; - else - priv->receive_config &= ~RCR_AAP; - - if (write_into_reg) - rtl92e_writel(dev, RCR, priv->receive_config); -} - -static u8 _rtl92e_rate_mgn_to_hw(u8 rate) -{ - u8 ret = DESC90_RATE1M; - - switch (rate) { - case MGN_1M: - ret = DESC90_RATE1M; - break; - case MGN_2M: - ret = DESC90_RATE2M; - break; - case MGN_5_5M: - ret = DESC90_RATE5_5M; - break; - case MGN_11M: - ret = DESC90_RATE11M; - break; - case MGN_6M: - ret = DESC90_RATE6M; - break; - case MGN_9M: - ret = DESC90_RATE9M; - break; - case MGN_12M: - ret = DESC90_RATE12M; - break; - case MGN_18M: - ret = DESC90_RATE18M; - break; - case MGN_24M: - ret = DESC90_RATE24M; - break; - case MGN_36M: - ret = DESC90_RATE36M; - break; - case MGN_48M: - ret = DESC90_RATE48M; - break; - case MGN_54M: - ret = DESC90_RATE54M; - break; - case MGN_MCS0: - ret = DESC90_RATEMCS0; - break; - case MGN_MCS1: - ret = DESC90_RATEMCS1; - break; - case MGN_MCS2: - ret = DESC90_RATEMCS2; - break; - case MGN_MCS3: - ret = DESC90_RATEMCS3; - break; - case MGN_MCS4: - ret = DESC90_RATEMCS4; - break; - case MGN_MCS5: - ret = DESC90_RATEMCS5; - break; - case MGN_MCS6: - ret = DESC90_RATEMCS6; - break; - case MGN_MCS7: - ret = DESC90_RATEMCS7; - break; - case MGN_MCS8: - ret = DESC90_RATEMCS8; - break; - case MGN_MCS9: - ret = DESC90_RATEMCS9; - break; - case MGN_MCS10: - ret = DESC90_RATEMCS10; - break; - case MGN_MCS11: - ret = DESC90_RATEMCS11; - break; - case MGN_MCS12: - ret = DESC90_RATEMCS12; - break; - case MGN_MCS13: - ret = DESC90_RATEMCS13; - break; - case MGN_MCS14: - ret = DESC90_RATEMCS14; - break; - case MGN_MCS15: - ret = DESC90_RATEMCS15; - break; - case (0x80 | 0x20): - ret = DESC90_RATEMCS32; - break; - default: - break; - } - return ret; -} - -static u8 _rtl92e_hw_queue_to_fw_queue(struct net_device *dev, u8 QueueID, - u8 priority) -{ - u8 QueueSelect = 0x0; - - switch (QueueID) { - case BE_QUEUE: - QueueSelect = QSLT_BE; - break; - - case BK_QUEUE: - QueueSelect = QSLT_BK; - break; - - case VO_QUEUE: - QueueSelect = QSLT_VO; - break; - - case VI_QUEUE: - QueueSelect = QSLT_VI; - break; - case MGNT_QUEUE: - QueueSelect = QSLT_MGNT; - break; - case BEACON_QUEUE: - QueueSelect = QSLT_BEACON; - break; - case TXCMD_QUEUE: - QueueSelect = QSLT_CMD; - break; - case HIGH_QUEUE: - QueueSelect = QSLT_HIGH; - break; - default: - netdev_warn(dev, "%s(): Impossible Queue Selection: %d\n", - __func__, QueueID); - break; - } - return QueueSelect; -} - -static u8 _rtl92e_query_is_short(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc) -{ - u8 tmp_Short; - - tmp_Short = (TxHT == 1) ? ((tcb_desc->use_short_gi) ? 1 : 0) : - ((tcb_desc->use_short_preamble) ? 1 : 0); - if (TxHT == 1 && TxRate != DESC90_RATEMCS15) - tmp_Short = 0; - - return tmp_Short; -} - -void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, - struct cb_desc *cb_desc, struct sk_buff *skb) -{ - struct r8192_priv *priv = rtllib_priv(dev); - dma_addr_t mapping; - struct tx_fwinfo_8190pci *pTxFwInfo; - - pTxFwInfo = (struct tx_fwinfo_8190pci *)skb->data; - memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci)); - pTxFwInfo->TxHT = (cb_desc->data_rate & 0x80) ? 1 : 0; - pTxFwInfo->TxRate = _rtl92e_rate_mgn_to_hw(cb_desc->data_rate); - pTxFwInfo->EnableCPUDur = cb_desc->tx_enable_fw_calc_dur; - pTxFwInfo->Short = _rtl92e_query_is_short(pTxFwInfo->TxHT, - pTxFwInfo->TxRate, cb_desc); - - if (cb_desc->ampdu_enable) { - pTxFwInfo->AllowAggregation = 1; - pTxFwInfo->RxMF = cb_desc->ampdu_factor; - pTxFwInfo->RxAMD = cb_desc->ampdu_density; - } else { - pTxFwInfo->AllowAggregation = 0; - pTxFwInfo->RxMF = 0; - pTxFwInfo->RxAMD = 0; - } - - pTxFwInfo->RtsEnable = (cb_desc->rts_enable) ? 1 : 0; - pTxFwInfo->CtsEnable = (cb_desc->cts_enable) ? 1 : 0; - pTxFwInfo->RtsSTBC = (cb_desc->rtsstbc) ? 1 : 0; - pTxFwInfo->RtsHT = (cb_desc->rts_rate & 0x80) ? 1 : 0; - pTxFwInfo->RtsRate = _rtl92e_rate_mgn_to_hw(cb_desc->rts_rate); - pTxFwInfo->RtsBandwidth = 0; - pTxFwInfo->RtsSubcarrier = cb_desc->RTSSC; - pTxFwInfo->RtsShort = (pTxFwInfo->RtsHT == 0) ? - (cb_desc->rts_use_short_preamble ? 1 : 0) : - (cb_desc->rts_use_short_gi ? 1 : 0); - if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20_40) { - if (cb_desc->packet_bw) { - pTxFwInfo->TxBandwidth = 1; - pTxFwInfo->TxSubCarrier = 0; - } else { - pTxFwInfo->TxBandwidth = 0; - pTxFwInfo->TxSubCarrier = priv->n_cur_40mhz_prime_sc; - } - } else { - pTxFwInfo->TxBandwidth = 0; - pTxFwInfo->TxSubCarrier = 0; - } - - memset((u8 *)pdesc, 0, 12); - - mapping = dma_map_single(&priv->pdev->dev, skb->data, skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(&priv->pdev->dev, mapping)) { - netdev_err(dev, "%s(): DMA Mapping error\n", __func__); - return; - } - - pdesc->LINIP = 0; - pdesc->CmdInit = 1; - pdesc->Offset = sizeof(struct tx_fwinfo_8190pci) + 8; - pdesc->PktSize = skb->len - sizeof(struct tx_fwinfo_8190pci); - - pdesc->SecCAMID = 0; - pdesc->RATid = cb_desc->ratr_index; - - pdesc->NoEnc = 1; - pdesc->SecType = 0x0; - if (cb_desc->hw_sec) { - static u8 tmp; - - if (!tmp) - tmp = 1; - switch (priv->rtllib->pairwise_key_type) { - case KEY_TYPE_WEP40: - case KEY_TYPE_WEP104: - pdesc->SecType = 0x1; - pdesc->NoEnc = 0; - break; - case KEY_TYPE_TKIP: - pdesc->SecType = 0x2; - pdesc->NoEnc = 0; - break; - case KEY_TYPE_CCMP: - pdesc->SecType = 0x3; - pdesc->NoEnc = 0; - break; - case KEY_TYPE_NA: - pdesc->SecType = 0x0; - pdesc->NoEnc = 1; - break; - } - } - - pdesc->PktId = 0x0; - - pdesc->QueueSelect = _rtl92e_hw_queue_to_fw_queue(dev, - cb_desc->queue_index, - cb_desc->priority); - pdesc->TxFWInfoSize = sizeof(struct tx_fwinfo_8190pci); - - pdesc->DISFB = cb_desc->tx_dis_rate_fallback; - pdesc->USERATE = cb_desc->tx_use_drv_assinged_rate; - - pdesc->FirstSeg = 1; - pdesc->LastSeg = 1; - pdesc->TxBufferSize = skb->len; - - pdesc->TxBuffAddr = mapping; -} - -void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry, - struct cb_desc *cb_desc, struct sk_buff *skb) -{ - struct r8192_priv *priv = rtllib_priv(dev); - dma_addr_t mapping = dma_map_single(&priv->pdev->dev, skb->data, - skb->len, DMA_TO_DEVICE); - - if (dma_mapping_error(&priv->pdev->dev, mapping)) - netdev_err(dev, "%s(): DMA Mapping error\n", __func__); - memset(entry, 0, 12); - entry->LINIP = cb_desc->last_ini_pkt; - entry->FirstSeg = 1; - entry->LastSeg = 1; - if (cb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) { - entry->CmdInit = DESC_PACKET_TYPE_INIT; - } else { - struct tx_desc *entry_tmp = (struct tx_desc *)entry; - - entry_tmp->CmdInit = DESC_PACKET_TYPE_NORMAL; - entry_tmp->Offset = sizeof(struct tx_fwinfo_8190pci) + 8; - entry_tmp->PktSize = cb_desc->pkt_size + entry_tmp->Offset; - entry_tmp->QueueSelect = QSLT_CMD; - entry_tmp->TxFWInfoSize = 0x08; - entry_tmp->RATid = DESC_PACKET_TYPE_INIT; - } - entry->TxBufferSize = skb->len; - entry->TxBuffAddr = mapping; - entry->OWN = 1; -} - -static u8 _rtl92e_rate_hw_to_mgn(bool bIsHT, u8 rate) -{ - u8 ret_rate = 0x02; - - if (!bIsHT) { - switch (rate) { - case DESC90_RATE1M: - ret_rate = MGN_1M; - break; - case DESC90_RATE2M: - ret_rate = MGN_2M; - break; - case DESC90_RATE5_5M: - ret_rate = MGN_5_5M; - break; - case DESC90_RATE11M: - ret_rate = MGN_11M; - break; - case DESC90_RATE6M: - ret_rate = MGN_6M; - break; - case DESC90_RATE9M: - ret_rate = MGN_9M; - break; - case DESC90_RATE12M: - ret_rate = MGN_12M; - break; - case DESC90_RATE18M: - ret_rate = MGN_18M; - break; - case DESC90_RATE24M: - ret_rate = MGN_24M; - break; - case DESC90_RATE36M: - ret_rate = MGN_36M; - break; - case DESC90_RATE48M: - ret_rate = MGN_48M; - break; - case DESC90_RATE54M: - ret_rate = MGN_54M; - break; - } - - } else { - switch (rate) { - case DESC90_RATEMCS0: - ret_rate = MGN_MCS0; - break; - case DESC90_RATEMCS1: - ret_rate = MGN_MCS1; - break; - case DESC90_RATEMCS2: - ret_rate = MGN_MCS2; - break; - case DESC90_RATEMCS3: - ret_rate = MGN_MCS3; - break; - case DESC90_RATEMCS4: - ret_rate = MGN_MCS4; - break; - case DESC90_RATEMCS5: - ret_rate = MGN_MCS5; - break; - case DESC90_RATEMCS6: - ret_rate = MGN_MCS6; - break; - case DESC90_RATEMCS7: - ret_rate = MGN_MCS7; - break; - case DESC90_RATEMCS8: - ret_rate = MGN_MCS8; - break; - case DESC90_RATEMCS9: - ret_rate = MGN_MCS9; - break; - case DESC90_RATEMCS10: - ret_rate = MGN_MCS10; - break; - case DESC90_RATEMCS11: - ret_rate = MGN_MCS11; - break; - case DESC90_RATEMCS12: - ret_rate = MGN_MCS12; - break; - case DESC90_RATEMCS13: - ret_rate = MGN_MCS13; - break; - case DESC90_RATEMCS14: - ret_rate = MGN_MCS14; - break; - case DESC90_RATEMCS15: - ret_rate = MGN_MCS15; - break; - case DESC90_RATEMCS32: - ret_rate = 0x80 | 0x20; - break; - } - } - - return ret_rate; -} - -static long _rtl92e_signal_scale_mapping(struct r8192_priv *priv, long currsig) -{ - long retsig; - - if (currsig >= 61 && currsig <= 100) - retsig = 90 + ((currsig - 60) / 4); - else if (currsig >= 41 && currsig <= 60) - retsig = 78 + ((currsig - 40) / 2); - else if (currsig >= 31 && currsig <= 40) - retsig = 66 + (currsig - 30); - else if (currsig >= 21 && currsig <= 30) - retsig = 54 + (currsig - 20); - else if (currsig >= 5 && currsig <= 20) - retsig = 42 + (((currsig - 5) * 2) / 3); - else if (currsig == 4) - retsig = 36; - else if (currsig == 3) - retsig = 27; - else if (currsig == 2) - retsig = 18; - else if (currsig == 1) - retsig = 9; - else - retsig = currsig; - - return retsig; -} - -#define rx_hal_is_cck_rate(_pdrvinfo)\ - ((_pdrvinfo->RxRate == DESC90_RATE1M ||\ - _pdrvinfo->RxRate == DESC90_RATE2M ||\ - _pdrvinfo->RxRate == DESC90_RATE5_5M ||\ - _pdrvinfo->RxRate == DESC90_RATE11M) &&\ - !_pdrvinfo->RxHT) - -static void _rtl92e_query_rxphystatus(struct r8192_priv *priv, - struct rtllib_rx_stats *pstats, - struct rx_desc *pdesc, - struct rx_fwinfo *pdrvinfo, - struct rtllib_rx_stats *precord_stats, - bool bpacket_match_bssid, - bool bpacket_toself, - bool bPacketBeacon, - bool bToSelfBA) -{ - struct phy_sts_ofdm_819xpci *pofdm_buf; - struct phy_sts_cck_819xpci *pcck_buf; - u8 *prxpkt; - u8 i, max_spatial_stream, tmp_rxevm; - s8 rx_pwr[RF90_PATH_MAX], rx_pwr_all = 0; - s8 rx_evmX; - u8 evm, pwdb_all; - u32 RSSI, total_rssi = 0; - u8 is_cck_rate = 0; - u8 rf_rx_num = 0; - static u8 check_reg824; - static u32 reg824_bit9; - - is_cck_rate = rx_hal_is_cck_rate(pdrvinfo); - memset(precord_stats, 0, sizeof(struct rtllib_rx_stats)); - pstats->bPacketMatchBSSID = precord_stats->bPacketMatchBSSID = - bpacket_match_bssid; - pstats->packet_to_self = precord_stats->packet_to_self = bpacket_toself; - pstats->bIsCCK = precord_stats->bIsCCK = is_cck_rate; - pstats->bPacketBeacon = precord_stats->bPacketBeacon = bPacketBeacon; - pstats->bToSelfBA = precord_stats->bToSelfBA = bToSelfBA; - if (check_reg824 == 0) { - reg824_bit9 = rtl92e_get_bb_reg(priv->rtllib->dev, - rFPGA0_XA_HSSIParameter2, - 0x200); - check_reg824 = 1; - } - - prxpkt = (u8 *)pdrvinfo; - - prxpkt += sizeof(struct rx_fwinfo); - - pcck_buf = (struct phy_sts_cck_819xpci *)prxpkt; - pofdm_buf = (struct phy_sts_ofdm_819xpci *)prxpkt; - - pstats->RxMIMOSignalQuality[0] = -1; - pstats->RxMIMOSignalQuality[1] = -1; - precord_stats->RxMIMOSignalQuality[0] = -1; - precord_stats->RxMIMOSignalQuality[1] = -1; - - if (is_cck_rate) { - u8 report; - - if (!reg824_bit9) { - report = pcck_buf->cck_agc_rpt & 0xc0; - report >>= 6; - switch (report) { - case 0x3: - rx_pwr_all = -35 - (pcck_buf->cck_agc_rpt & - 0x3e); - break; - case 0x2: - rx_pwr_all = -23 - (pcck_buf->cck_agc_rpt & - 0x3e); - break; - case 0x1: - rx_pwr_all = -11 - (pcck_buf->cck_agc_rpt & - 0x3e); - break; - case 0x0: - rx_pwr_all = 8 - (pcck_buf->cck_agc_rpt & 0x3e); - break; - } - } else { - report = pcck_buf->cck_agc_rpt & 0x60; - report >>= 5; - switch (report) { - case 0x3: - rx_pwr_all = -35 - - ((pcck_buf->cck_agc_rpt & - 0x1f) << 1); - break; - case 0x2: - rx_pwr_all = -23 - - ((pcck_buf->cck_agc_rpt & - 0x1f) << 1); - break; - case 0x1: - rx_pwr_all = -11 - - ((pcck_buf->cck_agc_rpt & - 0x1f) << 1); - break; - case 0x0: - rx_pwr_all = -8 - - ((pcck_buf->cck_agc_rpt & - 0x1f) << 1); - break; - } - } - - pwdb_all = rtl92e_rx_db_to_percent(rx_pwr_all); - pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; - pstats->RecvSignalPower = rx_pwr_all; - - if (bpacket_match_bssid) { - u8 sq; - - if (pstats->RxPWDBAll > 40) { - sq = 100; - } else { - sq = pcck_buf->sq_rpt; - - if (pcck_buf->sq_rpt > 64) - sq = 0; - else if (pcck_buf->sq_rpt < 20) - sq = 100; - else - sq = ((64 - sq) * 100) / 44; - } - pstats->signal_quality = sq; - precord_stats->signal_quality = sq; - pstats->RxMIMOSignalQuality[0] = sq; - precord_stats->RxMIMOSignalQuality[0] = sq; - pstats->RxMIMOSignalQuality[1] = -1; - precord_stats->RxMIMOSignalQuality[1] = -1; - } - } else { - for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) { - if (priv->brfpath_rxenable[i]) - rf_rx_num++; - - rx_pwr[i] = ((pofdm_buf->trsw_gain_X[i] & 0x3F) * - 2) - 110; - - RSSI = rtl92e_rx_db_to_percent(rx_pwr[i]); - if (priv->brfpath_rxenable[i]) - total_rssi += RSSI; - - if (bpacket_match_bssid) { - pstats->RxMIMOSignalStrength[i] = RSSI; - precord_stats->RxMIMOSignalStrength[i] = RSSI; - } - } - - rx_pwr_all = (((pofdm_buf->pwdb_all) >> 1) & 0x7f) - 106; - pwdb_all = rtl92e_rx_db_to_percent(rx_pwr_all); - - pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; - pstats->RecvSignalPower = rx_pwr_all; - if (pdrvinfo->RxHT && pdrvinfo->RxRate >= DESC90_RATEMCS8 && - pdrvinfo->RxRate <= DESC90_RATEMCS15) - max_spatial_stream = 2; - else - max_spatial_stream = 1; - - for (i = 0; i < max_spatial_stream; i++) { - tmp_rxevm = pofdm_buf->rxevm_X[i]; - rx_evmX = (s8)(tmp_rxevm); - - rx_evmX /= 2; - - evm = rtl92e_evm_db_to_percent(rx_evmX); - if (bpacket_match_bssid) { - if (i == 0) { - pstats->signal_quality = evm & 0xff; - precord_stats->signal_quality = evm & 0xff; - } - pstats->RxMIMOSignalQuality[i] = evm & 0xff; - precord_stats->RxMIMOSignalQuality[i] = evm & 0xff; - } - } - } - - if (is_cck_rate) { - pstats->signal_strength = precord_stats->signal_strength = - _rtl92e_signal_scale_mapping(priv, (long)pwdb_all); - - } else { - if (rf_rx_num != 0) - pstats->signal_strength = precord_stats->signal_strength = - _rtl92e_signal_scale_mapping(priv, - (long)(total_rssi /= rf_rx_num)); - } -} - -static void _rtl92e_process_phyinfo(struct r8192_priv *priv, u8 *buffer, - struct rtllib_rx_stats *prev_st, - struct rtllib_rx_stats *curr_st) -{ - bool bcheck = false; - u8 rfpath; - u32 ij, tmp_val; - static u32 slide_rssi_index, slide_rssi_statistics; - static u32 slide_evm_index, slide_evm_statistics; - static u32 last_rssi, last_evm; - static u32 slide_beacon_adc_pwdb_index; - static u32 slide_beacon_adc_pwdb_statistics; - static u32 last_beacon_adc_pwdb; - - if (!prev_st->bIsAMPDU) - bcheck = true; - - if (slide_rssi_statistics++ >= PHY_RSSI_SLID_WIN_MAX) { - slide_rssi_statistics = PHY_RSSI_SLID_WIN_MAX; - last_rssi = priv->stats.slide_signal_strength[slide_rssi_index]; - priv->stats.slide_rssi_total -= last_rssi; - } - priv->stats.slide_rssi_total += prev_st->signal_strength; - - priv->stats.slide_signal_strength[slide_rssi_index++] = - prev_st->signal_strength; - if (slide_rssi_index >= PHY_RSSI_SLID_WIN_MAX) - slide_rssi_index = 0; - - tmp_val = priv->stats.slide_rssi_total / slide_rssi_statistics; - priv->stats.signal_strength = rtl92e_translate_to_dbm(priv, tmp_val); - curr_st->rssi = priv->stats.signal_strength; - if (!prev_st->bPacketMatchBSSID) { - if (!prev_st->bToSelfBA) - return; - } - - if (!bcheck) - return; - - if (!prev_st->bIsCCK && prev_st->packet_to_self) { - 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]; - } - if (prev_st->RxMIMOSignalStrength[rfpath] > - priv->stats.rx_rssi_percentage[rfpath]) { - priv->stats.rx_rssi_percentage[rfpath] = - ((priv->stats.rx_rssi_percentage[rfpath] - * (RX_SMOOTH - 1)) + - (prev_st->RxMIMOSignalStrength - [rfpath])) / (RX_SMOOTH); - priv->stats.rx_rssi_percentage[rfpath] = - priv->stats.rx_rssi_percentage[rfpath] - + 1; - } else { - priv->stats.rx_rssi_percentage[rfpath] = - ((priv->stats.rx_rssi_percentage[rfpath] * - (RX_SMOOTH - 1)) + - (prev_st->RxMIMOSignalStrength[rfpath])) / - (RX_SMOOTH); - } - } - } - - if (prev_st->bPacketBeacon) { - if (slide_beacon_adc_pwdb_statistics++ >= - PHY_Beacon_RSSI_SLID_WIN_MAX) { - slide_beacon_adc_pwdb_statistics = - PHY_Beacon_RSSI_SLID_WIN_MAX; - last_beacon_adc_pwdb = priv->stats.slide_beacon_pwdb - [slide_beacon_adc_pwdb_index]; - priv->stats.slide_beacon_total -= last_beacon_adc_pwdb; - } - priv->stats.slide_beacon_total += prev_st->RxPWDBAll; - priv->stats.slide_beacon_pwdb[slide_beacon_adc_pwdb_index] = - prev_st->RxPWDBAll; - slide_beacon_adc_pwdb_index++; - if (slide_beacon_adc_pwdb_index >= PHY_Beacon_RSSI_SLID_WIN_MAX) - slide_beacon_adc_pwdb_index = 0; - prev_st->RxPWDBAll = priv->stats.slide_beacon_total / - slide_beacon_adc_pwdb_statistics; - if (prev_st->RxPWDBAll >= 3) - prev_st->RxPWDBAll -= 3; - } - if (prev_st->packet_to_self || prev_st->bPacketBeacon || - prev_st->bToSelfBA) { - if (priv->undecorated_smoothed_pwdb < 0) - priv->undecorated_smoothed_pwdb = prev_st->RxPWDBAll; - if (prev_st->RxPWDBAll > (u32)priv->undecorated_smoothed_pwdb) { - priv->undecorated_smoothed_pwdb = - (((priv->undecorated_smoothed_pwdb) * - (RX_SMOOTH - 1)) + - (prev_st->RxPWDBAll)) / (RX_SMOOTH); - priv->undecorated_smoothed_pwdb = - priv->undecorated_smoothed_pwdb + 1; - } else { - priv->undecorated_smoothed_pwdb = - (((priv->undecorated_smoothed_pwdb) * - (RX_SMOOTH - 1)) + - (prev_st->RxPWDBAll)) / (RX_SMOOTH); - } - rtl92e_update_rx_statistics(priv, prev_st); - } - - if (prev_st->signal_quality != 0) { - if (prev_st->packet_to_self || prev_st->bPacketBeacon || - prev_st->bToSelfBA) { - if (slide_evm_statistics++ >= PHY_RSSI_SLID_WIN_MAX) { - slide_evm_statistics = PHY_RSSI_SLID_WIN_MAX; - last_evm = - priv->stats.slide_evm[slide_evm_index]; - priv->stats.slide_evm_total -= last_evm; - } - - priv->stats.slide_evm_total += prev_st->signal_quality; - - priv->stats.slide_evm[slide_evm_index++] = - prev_st->signal_quality; - if (slide_evm_index >= PHY_RSSI_SLID_WIN_MAX) - slide_evm_index = 0; - - tmp_val = priv->stats.slide_evm_total / - slide_evm_statistics; - priv->stats.last_signal_strength_inpercent = tmp_val; - } - - if (prev_st->packet_to_self || - prev_st->bPacketBeacon || - prev_st->bToSelfBA) { - for (ij = 0; ij < 2; ij++) { - if (prev_st->RxMIMOSignalQuality[ij] != -1) { - if (priv->stats.rx_evm_percentage[ij] == 0) - priv->stats.rx_evm_percentage[ij] = - prev_st->RxMIMOSignalQuality[ij]; - priv->stats.rx_evm_percentage[ij] = - ((priv->stats.rx_evm_percentage[ij] * - (RX_SMOOTH - 1)) + - (prev_st->RxMIMOSignalQuality[ij])) / - (RX_SMOOTH); - } - } - } - } -} - -static void _rtl92e_translate_rx_signal_stats(struct net_device *dev, - struct sk_buff *skb, - struct rtllib_rx_stats *pstats, - struct rx_desc *pdesc, - struct rx_fwinfo *pdrvinfo) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - bool bpacket_match_bssid, bpacket_toself; - bool bPacketBeacon = false; - struct ieee80211_hdr_3addr *hdr; - bool bToSelfBA = false; - static struct rtllib_rx_stats previous_stats; - u16 fc, type; - u8 *tmp_buf; - u8 *praddr; - - tmp_buf = skb->data + pstats->rx_drv_info_size + pstats->rx_buf_shift; - - hdr = (struct ieee80211_hdr_3addr *)tmp_buf; - fc = le16_to_cpu(hdr->frame_control); - type = WLAN_FC_GET_TYPE(fc); - praddr = hdr->addr1; - - bpacket_match_bssid = - ((type != RTLLIB_FTYPE_CTL) && - ether_addr_equal(priv->rtllib->current_network.bssid, - (fc & IEEE80211_FCTL_TODS) ? hdr->addr1 : - (fc & IEEE80211_FCTL_FROMDS) ? hdr->addr2 : - hdr->addr3) && - (!pstats->hw_error) && (!pstats->bCRC) && (!pstats->bICV)); - bpacket_toself = bpacket_match_bssid && /* check this */ - ether_addr_equal(praddr, priv->rtllib->dev->dev_addr); - if (ieee80211_is_beacon(hdr->frame_control)) - bPacketBeacon = true; - _rtl92e_process_phyinfo(priv, tmp_buf, &previous_stats, pstats); - _rtl92e_query_rxphystatus(priv, pstats, pdesc, pdrvinfo, - &previous_stats, bpacket_match_bssid, - bpacket_toself, bPacketBeacon, bToSelfBA); - rtl92e_copy_mpdu_stats(pstats, &previous_stats); -} - -static void _rtl92e_update_received_rate_histogram_stats(struct net_device *dev, - struct rtllib_rx_stats *pstats) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - u32 rcvType = 1; - u32 rate_index; - - if (pstats->bCRC) - rcvType = 2; - else if (pstats->bICV) - rcvType = 3; - - switch (pstats->rate) { - case MGN_1M: - rate_index = 0; - break; - case MGN_2M: - rate_index = 1; - break; - case MGN_5_5M: - rate_index = 2; - break; - case MGN_11M: - rate_index = 3; - break; - case MGN_6M: - rate_index = 4; - break; - case MGN_9M: - rate_index = 5; - break; - case MGN_12M: - rate_index = 6; - break; - case MGN_18M: - rate_index = 7; - break; - case MGN_24M: - rate_index = 8; - break; - case MGN_36M: - rate_index = 9; - break; - case MGN_48M: - rate_index = 10; - break; - case MGN_54M: - rate_index = 11; - break; - case MGN_MCS0: - rate_index = 12; - break; - case MGN_MCS1: - rate_index = 13; - break; - case MGN_MCS2: - rate_index = 14; - break; - case MGN_MCS3: - rate_index = 15; - break; - case MGN_MCS4: - rate_index = 16; - break; - case MGN_MCS5: - rate_index = 17; - break; - case MGN_MCS6: - rate_index = 18; - break; - case MGN_MCS7: - rate_index = 19; - break; - case MGN_MCS8: - rate_index = 20; - break; - case MGN_MCS9: - rate_index = 21; - break; - case MGN_MCS10: - rate_index = 22; - break; - case MGN_MCS11: - rate_index = 23; - break; - case MGN_MCS12: - rate_index = 24; - break; - case MGN_MCS13: - rate_index = 25; - break; - case MGN_MCS14: - rate_index = 26; - break; - case MGN_MCS15: - rate_index = 27; - break; - default: - rate_index = 28; - break; - } - priv->stats.received_rate_histogram[0][rate_index]++; - priv->stats.received_rate_histogram[rcvType][rate_index]++; -} - -bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, - struct rx_desc *pdesc, struct sk_buff *skb) -{ - struct rx_fwinfo *pDrvInfo = NULL; - - stats->bICV = pdesc->ICV; - stats->bCRC = pdesc->CRC32; - stats->hw_error = pdesc->CRC32 | pdesc->ICV; - - stats->Length = pdesc->Length; - if (stats->Length < 24) - stats->hw_error |= 1; - - if (stats->hw_error) - return false; - - stats->rx_drv_info_size = pdesc->rx_drv_info_size; - stats->rx_buf_shift = (pdesc->Shift) & 0x03; - stats->decrypted = !pdesc->SWDec; - - pDrvInfo = (struct rx_fwinfo *)(skb->data + stats->rx_buf_shift); - - stats->rate = _rtl92e_rate_hw_to_mgn((bool)pDrvInfo->RxHT, - pDrvInfo->RxRate); - - _rtl92e_update_received_rate_histogram_stats(dev, stats); - - stats->bIsAMPDU = (pDrvInfo->PartAggr == 1); - stats->bFirstMPDU = (pDrvInfo->PartAggr == 1) && - (pDrvInfo->FirstAGGR == 1); - - stats->time_stamp_low = pDrvInfo->TSFL; - stats->time_stamp_high = rtl92e_readl(dev, TSFR + 4); - - _rtl92e_translate_rx_signal_stats(dev, skb, stats, pdesc, pDrvInfo); - skb_trim(skb, skb->len - S_CRC_LEN); - - return true; -} - -void rtl92e_stop_adapter(struct net_device *dev, bool reset) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int i; - u8 op_mode; - u8 u1bTmp; - u32 ulRegRead; - - op_mode = RT_OP_MODE_NO_LINK; - priv->rtllib->set_hw_reg_handler(dev, HW_VAR_MEDIA_STATUS, &op_mode); - - if (!priv->rtllib->bSupportRemoteWakeUp) { - u1bTmp = 0x0; - rtl92e_writeb(dev, CMDR, u1bTmp); - } - - mdelay(20); - - if (!reset) { - mdelay(150); - - priv->hw_rf_off_action = 2; - - if (!priv->rtllib->bSupportRemoteWakeUp) { - rtl92e_set_rf_off(dev); - ulRegRead = rtl92e_readl(dev, CPU_GEN); - ulRegRead |= CPU_GEN_SYSTEM_RESET; - rtl92e_writel(dev, CPU_GEN, ulRegRead); - } else { - rtl92e_writel(dev, WFCRC0, 0xffffffff); - rtl92e_writel(dev, WFCRC1, 0xffffffff); - rtl92e_writel(dev, WFCRC2, 0xffffffff); - - rtl92e_writeb(dev, PMR, 0x5); - rtl92e_writeb(dev, MAC_BLK_CTRL, 0xa); - } - } - - for (i = 0; i < MAX_QUEUE_SIZE; i++) - skb_queue_purge(&priv->rtllib->skb_waitq[i]); - - skb_queue_purge(&priv->skb_queue); -} - -void rtl92e_update_ratr_table(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - u8 *pMcsRate = ieee->dot11ht_oper_rate_set; - u32 ratr_value = 0; - u16 rate_config = 0; - u8 rate_index = 0; - - rtl92e_config_rate(dev, &rate_config); - ratr_value = rate_config | *pMcsRate << 12; - switch (ieee->mode) { - case WIRELESS_MODE_B: - ratr_value &= 0x0000000F; - break; - case WIRELESS_MODE_G: - case WIRELESS_MODE_G | WIRELESS_MODE_B: - ratr_value &= 0x00000FF7; - break; - case WIRELESS_MODE_N_24G: - ratr_value &= 0x000FF007; - break; - default: - break; - } - ratr_value &= 0x0FFFFFFF; - if (ieee->ht_info->cur_tx_bw40mhz && - ieee->ht_info->cur_short_gi_40mhz) - ratr_value |= 0x80000000; - else if (!ieee->ht_info->cur_tx_bw40mhz && - ieee->ht_info->cur_short_gi_20mhz) - ratr_value |= 0x80000000; - rtl92e_writel(dev, RATR0 + rate_index * 4, ratr_value); - rtl92e_writeb(dev, UFWP, 1); -} - -void -rtl92e_init_variables(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - strscpy(priv->nick, "rtl8192E", sizeof(priv->nick)); - - priv->rtllib->softmac_features = IEEE_SOFTMAC_SCAN | - IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | - IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE; - - priv->rtllib->tx_headroom = sizeof(struct tx_fwinfo_8190pci); - - priv->short_retry_limit = 0x30; - priv->long_retry_limit = 0x30; - - priv->receive_config = RCR_ADD3 | - RCR_AMF | RCR_ADF | - RCR_AICV | - RCR_AB | RCR_AM | RCR_APM | - RCR_AAP | ((u32)7 << RCR_MXDMA_OFFSET) | - ((u32)7 << RCR_FIFO_OFFSET) | RCR_ONLYERLPKT; - - priv->irq_mask[0] = (u32)(IMR_ROK | IMR_VODOK | IMR_VIDOK | - IMR_BEDOK | IMR_BKDOK | IMR_HCCADOK | - IMR_MGNTDOK | IMR_COMDOK | IMR_HIGHDOK | - IMR_BDOK | IMR_RXCMDOK | IMR_TIMEOUT0 | - IMR_RDU | IMR_RXFOVW | IMR_TXFOVW | - IMR_TBDOK | IMR_TBDER); - - priv->bfirst_after_down = false; -} - -void rtl92e_irq_enable(struct net_device *dev) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - - priv->irq_enabled = 1; - - rtl92e_writel(dev, INTA_MASK, priv->irq_mask[0]); -} - -void rtl92e_irq_disable(struct net_device *dev) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - - rtl92e_writel(dev, INTA_MASK, 0); - - priv->irq_enabled = 0; -} - -void rtl92e_enable_rx(struct net_device *dev) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - - rtl92e_writel(dev, RDQDA, priv->rx_ring_dma); -} - -static const u32 TX_DESC_BASE[] = { - BKQDA, BEQDA, VIQDA, VOQDA, HCCAQDA, CQDA, MQDA, HQDA, BQDA -}; - -void rtl92e_enable_tx(struct net_device *dev) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - u32 i; - - for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) - rtl92e_writel(dev, TX_DESC_BASE[i], priv->tx_ring[i].dma); -} - -void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta) -{ - *p_inta = rtl92e_readl(dev, ISR); - rtl92e_writel(dev, ISR, *p_inta); -} - -bool rtl92e_is_rx_stuck(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u16 RegRxCounter = rtl92e_readw(dev, 0x130); - bool bStuck = false; - static u8 rx_chk_cnt; - u32 slot_index = 0, TotalRxStuckCount = 0; - u8 i; - u8 SilentResetRxSoltNum = 4; - - rx_chk_cnt++; - if (priv->undecorated_smoothed_pwdb >= (RATE_ADAPTIVE_TH_HIGH + 5)) { - rx_chk_cnt = 0; - } else if ((priv->undecorated_smoothed_pwdb < (RATE_ADAPTIVE_TH_HIGH + 5)) && - (((priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) && - (priv->undecorated_smoothed_pwdb >= RATE_ADAPTIVE_TH_LOW_40M)) - || ((priv->current_chnl_bw == HT_CHANNEL_WIDTH_20) && - (priv->undecorated_smoothed_pwdb >= RATE_ADAPTIVE_TH_LOW_20M)))) { - if (rx_chk_cnt < 2) - return bStuck; - rx_chk_cnt = 0; - } else if ((((priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) && - (priv->undecorated_smoothed_pwdb < RATE_ADAPTIVE_TH_LOW_40M)) || - ((priv->current_chnl_bw == HT_CHANNEL_WIDTH_20) && - (priv->undecorated_smoothed_pwdb < RATE_ADAPTIVE_TH_LOW_20M))) && - priv->undecorated_smoothed_pwdb >= VERY_LOW_RSSI) { - if (rx_chk_cnt < 4) - return bStuck; - rx_chk_cnt = 0; - } else { - if (rx_chk_cnt < 8) - return bStuck; - rx_chk_cnt = 0; - } - - slot_index = (priv->silent_reset_rx_slot_index++) % SilentResetRxSoltNum; - - if (priv->rx_ctr == RegRxCounter) { - priv->silent_reset_rx_stuck_event[slot_index] = 1; - - for (i = 0; i < SilentResetRxSoltNum; i++) - TotalRxStuckCount += priv->silent_reset_rx_stuck_event[i]; - - if (TotalRxStuckCount == SilentResetRxSoltNum) { - bStuck = true; - for (i = 0; i < SilentResetRxSoltNum; i++) - TotalRxStuckCount += - priv->silent_reset_rx_stuck_event[i]; - } - } else { - priv->silent_reset_rx_stuck_event[slot_index] = 0; - } - - priv->rx_ctr = RegRxCounter; - - return bStuck; -} - -bool rtl92e_is_tx_stuck(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - bool bStuck = false; - u16 RegTxCounter = rtl92e_readw(dev, 0x128); - - if (priv->tx_counter == RegTxCounter) - bStuck = true; - - priv->tx_counter = RegTxCounter; - - return bStuck; -} - -bool rtl92e_get_nmode_support_by_sec(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - - if (ieee->rtllib_ap_sec_type && - (ieee->rtllib_ap_sec_type(priv->rtllib) & (SEC_ALG_WEP | - SEC_ALG_TKIP))) { - return false; - } else { - return true; - } -} - -bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - - return ieee->half_wireless_n24g_mode; -} diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h deleted file mode 100644 index 9d9c5051c7fe0d..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef _RTL8192E_H -#define _RTL8192E_H - -#include "r8190P_def.h" - -bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev); -bool rtl92e_get_nmode_support_by_sec(struct net_device *dev); -bool rtl92e_is_tx_stuck(struct net_device *dev); -bool rtl92e_is_rx_stuck(struct net_device *dev); -void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta); -void rtl92e_enable_rx(struct net_device *dev); -void rtl92e_enable_tx(struct net_device *dev); -void rtl92e_init_variables(struct net_device *dev); -void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val); -void rtl92e_get_eeprom_size(struct net_device *dev); -bool rtl92e_start_adapter(struct net_device *dev); -void rtl92e_link_change(struct net_device *dev); -void rtl92e_set_monitor_mode(struct net_device *dev, bool allow_all_da, - bool write_into_reg); -void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, - struct cb_desc *cb_desc, struct sk_buff *skb); -void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry, - struct cb_desc *cb_desc, struct sk_buff *skb); -bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, - struct rx_desc *pdesc, struct sk_buff *skb); -void rtl92e_stop_adapter(struct net_device *dev, bool reset); -void rtl92e_update_ratr_table(struct net_device *dev); -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c deleted file mode 100644 index ddf998cf20415d..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include "rtl_core.h" -#include "r8192E_hw.h" -#include "table.h" -#include "r8192E_firmware.h" -#include "r8192E_cmdpkt.h" -#include - -static bool _rtl92e_wait_for_fw(struct net_device *dev, u32 mask, u32 timeout) -{ - unsigned long deadline = jiffies + msecs_to_jiffies(timeout); - - while (time_before(jiffies, deadline)) { - if (rtl92e_readl(dev, CPU_GEN) & mask) - return true; - mdelay(2); - } - return false; -} - -static bool _rtl92e_fw_boot_cpu(struct net_device *dev) -{ - u32 CPU_status = 0; - - if (!_rtl92e_wait_for_fw(dev, CPU_GEN_PUT_CODE_OK, 200)) { - netdev_err(dev, "Firmware download failed.\n"); - return false; - } - netdev_dbg(dev, "Download Firmware: Put code ok!\n"); - - CPU_status = rtl92e_readl(dev, CPU_GEN); - rtl92e_writeb(dev, CPU_GEN, (CPU_status | CPU_GEN_PWR_STB_CPU) & 0xff); - mdelay(1); - - if (!_rtl92e_wait_for_fw(dev, CPU_GEN_BOOT_RDY, 200)) { - netdev_err(dev, "Firmware boot failed.\n"); - return false; - } - - netdev_dbg(dev, "Download Firmware: Boot ready!\n"); - - return true; -} - -static bool _rtl92e_fw_check_ready(struct net_device *dev, - u8 load_fw_status) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_firmware *pfirmware = priv->fw_info; - bool rt_status = true; - - switch (load_fw_status) { - case FW_INIT_STEP0_BOOT: - pfirmware->status = FW_STATUS_1_MOVE_BOOT_CODE; - break; - - case FW_INIT_STEP1_MAIN: - pfirmware->status = FW_STATUS_2_MOVE_MAIN_CODE; - - rt_status = _rtl92e_fw_boot_cpu(dev); - if (rt_status) - pfirmware->status = FW_STATUS_3_TURNON_CPU; - else - netdev_dbg(dev, "_rtl92e_fw_boot_cpu fail!\n"); - - break; - - case FW_INIT_STEP2_DATA: - pfirmware->status = FW_STATUS_4_MOVE_DATA_CODE; - mdelay(1); - - rt_status = _rtl92e_wait_for_fw(dev, CPU_GEN_FIRM_RDY, 20); - if (rt_status) - pfirmware->status = FW_STATUS_5_READY; - break; - default: - rt_status = false; - netdev_dbg(dev, "Unknown firmware status"); - break; - } - - return rt_status; -} - -static bool _rtl92e_fw_prepare(struct net_device *dev, struct rt_fw_blob *blob, - const char *name, u8 padding) -{ - const struct firmware *fw; - int rc, i; - bool ret = true; - - rc = request_firmware(&fw, name, &dev->dev); - if (rc < 0) - return false; - - if (round_up(fw->size, 4) > MAX_FW_SIZE - padding) { - netdev_err(dev, "Firmware image %s too big for the device.\n", - name); - ret = false; - goto out; - } - - if (padding) - memset(blob->data, 0, padding); - if (fw->size % 4) - memset(blob->data + padding + fw->size, 0, 4); - memcpy(blob->data + padding, fw->data, fw->size); - - blob->size = round_up(fw->size, 4) + padding; - - /* Swap endian - firmware is packaged in invalid endiannes*/ - for (i = padding; i < blob->size; i += 4) { - u32 *data = (u32 *)(blob->data + i); - *data = swab32p(data); - } -out: - release_firmware(fw); - return ret; -} - -bool rtl92e_init_fw(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - bool rt_status = true; - - u32 file_length = 0; - u8 *mapped_file = NULL; - u8 i = 0; - enum opt_rst_type rst_opt = OPT_SYSTEM_RESET; - enum firmware_init_step starting_state = FW_INIT_STEP0_BOOT; - - struct rt_firmware *pfirmware = priv->fw_info; - - netdev_dbg(dev, " PlatformInitFirmware()==>\n"); - - if (pfirmware->status == FW_STATUS_0_INIT) { - rst_opt = OPT_SYSTEM_RESET; - starting_state = FW_INIT_STEP0_BOOT; - - } else if (pfirmware->status == FW_STATUS_5_READY) { - rst_opt = OPT_FIRMWARE_RESET; - starting_state = FW_INIT_STEP2_DATA; - } - - for (i = starting_state; i <= FW_INIT_STEP2_DATA; i++) { - if (rst_opt == OPT_SYSTEM_RESET) { - if (pfirmware->blobs[i].size == 0) { - const char *fw_name[3] = { - RTL8192E_BOOT_IMG_FW, - RTL8192E_MAIN_IMG_FW, - RTL8192E_DATA_IMG_FW - }; - int pad = 0; - - if (i == FW_INIT_STEP1_MAIN) - pad = 128; - - if (!_rtl92e_fw_prepare(dev, - &pfirmware->blobs[i], - fw_name[i], - pad)) - goto download_firmware_fail; - } - } - - mapped_file = pfirmware->blobs[i].data; - file_length = pfirmware->blobs[i].size; - - rt_status = rtl92e_send_cmd_pkt(dev, DESC_PACKET_TYPE_INIT, - mapped_file, file_length); - if (!rt_status) - goto download_firmware_fail; - - if (!_rtl92e_fw_check_ready(dev, i)) - goto download_firmware_fail; - } - - netdev_dbg(dev, "Firmware Download Success\n"); - return rt_status; - -download_firmware_fail: - netdev_err(dev, "%s: Failed to initialize firmware.\n", __func__); - return false; -} diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h deleted file mode 100644 index b9059abc901b5e..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef __INC_FIRMWARE_H -#define __INC_FIRMWARE_H - -#define RTL8192E_BOOT_IMG_FW "RTL8192E/boot.img" -#define RTL8192E_MAIN_IMG_FW "RTL8192E/main.img" -#define RTL8192E_DATA_IMG_FW "RTL8192E/data.img" - -enum firmware_init_step { - FW_INIT_STEP0_BOOT = 0, - FW_INIT_STEP1_MAIN = 1, - FW_INIT_STEP2_DATA = 2, -}; - -enum opt_rst_type { - OPT_SYSTEM_RESET = 0, - OPT_FIRMWARE_RESET = 1, -}; - -enum desc_packet_type { - DESC_PACKET_TYPE_INIT = 0, - DESC_PACKET_TYPE_NORMAL = 1, -}; - -enum firmware_status { - FW_STATUS_0_INIT = 0, - FW_STATUS_1_MOVE_BOOT_CODE = 1, - FW_STATUS_2_MOVE_MAIN_CODE = 2, - FW_STATUS_3_TURNON_CPU = 3, - FW_STATUS_4_MOVE_DATA_CODE = 4, - FW_STATUS_5_READY = 5, -}; - -#define MAX_FW_SIZE 64000 -struct rt_fw_blob { - u16 size; - u8 data[MAX_FW_SIZE]; -}; - -#define FW_BLOBS 3 -struct rt_firmware { - enum firmware_status status; - struct rt_fw_blob blobs[FW_BLOBS]; -}; - -bool rtl92e_init_fw(struct net_device *dev); -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h deleted file mode 100644 index e507593b939cd6..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h +++ /dev/null @@ -1,244 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef R8180_HW -#define R8180_HW - -enum baseband_config { - BB_CONFIG_PHY_REG = 0, - BB_CONFIG_AGC_TAB = 1, -}; - -#define RTL8190_EEPROM_ID 0x8129 -#define EEPROM_VID 0x02 -#define EEPROM_DID 0x04 -#define EEPROM_NODE_ADDRESS_BYTE_0 0x0C - -#define EEPROM_Default_ThermalMeter 0x77 -#define EEPROM_Default_AntTxPowerDiff 0x0 -#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 -#define EEPROM_Default_TxPower 0x1010 -#define EEPROM_ICVersion_ChannelPlan 0x7C -#define EEPROM_Customer_ID 0x7B -#define EEPROM_RFInd_PowerDiff 0x28 - -#define EEPROM_ThermalMeter 0x29 -#define EEPROM_TxPwDiff_CrystalCap 0x2A -#define EEPROM_TxPwIndex_CCK 0x2C -#define EEPROM_TxPwIndex_OFDM_24G 0x3A - -#define EEPROM_CID_TOSHIBA 0x4 -#define EEPROM_CID_NetCore 0x5 -enum _RTL8192PCI_HW { - MAC0 = 0x000, - MAC4 = 0x004, - PCIF = 0x009, -#define MXDMA2_NO_LIMIT 0x7 - -#define MXDMA2_RX_SHIFT 4 -#define MXDMA2_TX_SHIFT 0 - PMR = 0x00c, - EPROM_CMD = 0x00e, - -#define EPROM_CMD_9356SEL BIT(4) -#define EPROM_CMD_OPERATING_MODE_SHIFT 6 -#define EPROM_CMD_NORMAL 0 -#define EPROM_CMD_PROGRAM 2 -#define EPROM_CS_BIT 3 -#define EPROM_CK_BIT 2 -#define EPROM_W_BIT 1 -#define EPROM_R_BIT 0 - - ANAPAR = 0x17, -#define BB_GLOBAL_RESET_BIT 0x1 - BB_GLOBAL_RESET = 0x020, - BSSIDR = 0x02E, - CMDR = 0x037, -#define CR_RE 0x08 -#define CR_TE 0x04 - SIFS = 0x03E, - RCR = 0x044, -#define RCR_ONLYERLPKT BIT(31) -#define RCR_CBSSID BIT(23) -#define RCR_ADD3 BIT(21) -#define RCR_AMF BIT(20) -#define RCR_ADF BIT(18) -#define RCR_AICV BIT(12) -#define RCR_AB BIT(3) -#define RCR_AM BIT(2) -#define RCR_APM BIT(1) -#define RCR_AAP BIT(0) -#define RCR_MXDMA_OFFSET 8 -#define RCR_FIFO_OFFSET 13 - SLOT_TIME = 0x049, - ACK_TIMEOUT = 0x04c, - EDCAPARA_BE = 0x050, - EDCAPARA_BK = 0x054, - EDCAPARA_VO = 0x058, - EDCAPARA_VI = 0x05C, -#define AC_PARAM_TXOP_LIMIT_OFFSET 16 -#define AC_PARAM_ECW_MAX_OFFSET 12 -#define AC_PARAM_ECW_MIN_OFFSET 8 -#define AC_PARAM_AIFS_OFFSET 0 - BCN_TCFG = 0x062, -#define BCN_TCFG_CW_SHIFT 8 -#define BCN_TCFG_IFS 0 - BCN_INTERVAL = 0x070, - ATIMWND = 0x072, - BCN_DRV_EARLY_INT = 0x074, - BCN_DMATIME = 0x076, - BCN_ERR_THRESH = 0x078, - RWCAM = 0x0A0, -#define TOTAL_CAM_ENTRY 32 - WCAMI = 0x0A4, - SECR = 0x0B0, -#define SCR_TxUseDK BIT(0) -#define SCR_RxUseDK BIT(1) -#define SCR_TxEncEnable BIT(2) -#define SCR_RxDecEnable BIT(3) -#define SCR_NoSKMC BIT(5) - SWREGULATOR = 0x0BD, - INTA_MASK = 0x0f4, -#define IMR_TBDOK BIT(27) -#define IMR_TBDER BIT(26) -#define IMR_TXFOVW BIT(15) -#define IMR_TIMEOUT0 BIT(14) -#define IMR_BcnInt BIT(13) -#define IMR_RXFOVW BIT(12) -#define IMR_RDU BIT(11) -#define IMR_RXCMDOK BIT(10) -#define IMR_BDOK BIT(9) -#define IMR_HIGHDOK BIT(8) -#define IMR_COMDOK BIT(7) -#define IMR_MGNTDOK BIT(6) -#define IMR_HCCADOK BIT(5) -#define IMR_BKDOK BIT(4) -#define IMR_BEDOK BIT(3) -#define IMR_VIDOK BIT(2) -#define IMR_VODOK BIT(1) -#define IMR_ROK BIT(0) - ISR = 0x0f8, - TP_POLL = 0x0fd, -#define TP_POLL_CQ BIT(5) - PSR = 0x0ff, - CPU_GEN = 0x100, -#define CPU_CCK_LOOPBACK 0x00030000 -#define CPU_GEN_SYSTEM_RESET 0x00000001 -#define CPU_GEN_FIRMWARE_RESET 0x00000008 -#define CPU_GEN_BOOT_RDY 0x00000010 -#define CPU_GEN_FIRM_RDY 0x00000020 -#define CPU_GEN_PUT_CODE_OK 0x00000080 -#define CPU_GEN_BB_RST 0x00000100 -#define CPU_GEN_PWR_STB_CPU 0x00000004 -#define CPU_GEN_NO_LOOPBACK_MSK 0xFFF8FFFF -#define CPU_GEN_NO_LOOPBACK_SET 0x00080000 - ACM_HW_CTRL = 0x171, -#define ACM_HW_BEQ_EN BIT(1) -#define ACM_HW_VIQ_EN BIT(2) -#define ACM_HW_VOQ_EN BIT(3) - RQPN1 = 0x180, - RQPN2 = 0x184, - RQPN3 = 0x188, - QPNR = 0x1F0, - BQDA = 0x200, - HQDA = 0x204, - CQDA = 0x208, - MQDA = 0x20C, - HCCAQDA = 0x210, - VOQDA = 0x214, - VIQDA = 0x218, - BEQDA = 0x21C, - BKQDA = 0x220, - RDQDA = 0x228, - - WFCRC0 = 0x2f0, - WFCRC1 = 0x2f4, - WFCRC2 = 0x2f8, - - BW_OPMODE = 0x300, -#define BW_OPMODE_20MHZ BIT(2) - IC_VERRSION = 0x301, - MSR = 0x303, -#define MSR_LINK_MASK (BIT(1) | BIT(0)) -#define MSR_LINK_MANAGED 2 -#define MSR_LINK_ADHOC 1 -#define MSR_LINK_MASTER 3 - -#define MSR_NOLINK 0x00 -#define MSR_ADHOC 0x01 -#define MSR_INFRA 0x02 -#define MSR_AP 0x03 - - RETRY_LIMIT = 0x304, -#define RETRY_LIMIT_SHORT_SHIFT 8 -#define RETRY_LIMIT_LONG_SHIFT 0 - TSFR = 0x308, - RRSR = 0x310, -#define RRSR_SHORT_OFFSET 23 -#define RRSR_1M BIT(0) -#define RRSR_2M BIT(1) -#define RRSR_5_5M BIT(2) -#define RRSR_11M BIT(3) -#define RRSR_6M BIT(4) -#define RRSR_9M BIT(5) -#define RRSR_12M BIT(6) -#define RRSR_18M BIT(7) -#define RRSR_24M BIT(8) -#define RRSR_36M BIT(9) -#define RRSR_48M BIT(10) -#define RRSR_54M BIT(11) -#define BRSR_AckShortPmb BIT(23) - UFWP = 0x318, - RATR0 = 0x320, -#define RATR_1M 0x00000001 -#define RATR_2M 0x00000002 -#define RATR_55M 0x00000004 -#define RATR_11M 0x00000008 -#define RATR_6M 0x00000010 -#define RATR_9M 0x00000020 -#define RATR_12M 0x00000040 -#define RATR_18M 0x00000080 -#define RATR_24M 0x00000100 -#define RATR_36M 0x00000200 -#define RATR_48M 0x00000400 -#define RATR_54M 0x00000800 -#define RATR_MCS0 0x00001000 -#define RATR_MCS1 0x00002000 -#define RATR_MCS2 0x00004000 -#define RATR_MCS3 0x00008000 -#define RATR_MCS4 0x00010000 -#define RATR_MCS5 0x00020000 -#define RATR_MCS6 0x00040000 -#define RATR_MCS7 0x00080000 -#define RATR_MCS8 0x00100000 -#define RATR_MCS9 0x00200000 -#define RATR_MCS10 0x00400000 -#define RATR_MCS11 0x00800000 -#define RATR_MCS12 0x01000000 -#define RATR_MCS13 0x02000000 -#define RATR_MCS14 0x04000000 -#define RATR_MCS15 0x08000000 -#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M) -#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M | \ - RATR_24M | RATR_36M | RATR_48M | RATR_54M) -#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \ - RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \ - RATR_MCS6 | RATR_MCS7) -#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \ - RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \ - RATR_MCS14 | RATR_MCS15) - - DRIVER_RSSI = 0x32c, - MCS_TXAGC = 0x340, - CCK_TXAGC = 0x348, - MAC_BLK_CTRL = 0x403, -}; - -#define GPI 0x108 - -#define ANAPAR_FOR_8192PCIE 0x17 - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c deleted file mode 100644 index fbe624e235df0d..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ /dev/null @@ -1,1110 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include -#include "rtl_core.h" -#include "r8192E_hw.h" -#include "r8192E_phyreg.h" -#include "r8190P_rtl8256.h" -#include "r8192E_phy.h" -#include "rtl_dm.h" - -#include "table.h" - -/*************************Define local function prototype**********************/ - -static u32 _rtl92e_phy_rf_fw_read(struct net_device *dev, - enum rf90_radio_path eRFPath, u32 Offset); -static void _rtl92e_phy_rf_fw_write(struct net_device *dev, - enum rf90_radio_path eRFPath, u32 Offset, - u32 Data); - -static u32 _rtl92e_calculate_bit_shift(u32 dwBitMask) -{ - if (!dwBitMask) - return 32; - return ffs(dwBitMask) - 1; -} - -void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, - u32 dwData) -{ - u32 OriginalValue, BitShift, NewValue; - - if (dwBitMask != bMaskDWord) { - OriginalValue = rtl92e_readl(dev, dwRegAddr); - BitShift = _rtl92e_calculate_bit_shift(dwBitMask); - NewValue = (OriginalValue & ~dwBitMask) | (dwData << BitShift); - rtl92e_writel(dev, dwRegAddr, NewValue); - } else { - rtl92e_writel(dev, dwRegAddr, dwData); - } -} - -u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask) -{ - u32 OriginalValue, BitShift; - - OriginalValue = rtl92e_readl(dev, dwRegAddr); - BitShift = _rtl92e_calculate_bit_shift(dwBitMask); - - return (OriginalValue & dwBitMask) >> BitShift; -} - -static u32 _rtl92e_phy_rf_read(struct net_device *dev, - enum rf90_radio_path eRFPath, u32 Offset) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u32 ret = 0; - u32 NewOffset = 0; - struct bb_reg_definition *pPhyReg = &priv->phy_reg_def[eRFPath]; - - Offset &= 0x3f; - - 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, pPhyReg->rfHSSIPara2, bLSSIReadAddress, - NewOffset); - rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0); - rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1); - - mdelay(1); - - ret = rtl92e_get_bb_reg(dev, pPhyReg->rfLSSIReadBack, - bLSSIReadBackData); - - 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); - - return ret; -} - -static void _rtl92e_phy_rf_write(struct net_device *dev, - enum rf90_radio_path eRFPath, u32 Offset, - u32 Data) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u32 DataAndAddr = 0, NewOffset = 0; - struct bb_reg_definition *pPhyReg = &priv->phy_reg_def[eRFPath]; - - Offset &= 0x3f; - - 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; - } - - DataAndAddr = (NewOffset & 0x3f) | (Data << 16); - - rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); - - if (Offset == 0x0) - priv->rf_reg_0value[eRFPath] = Data; - - 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, - u32 RegAddr, u32 BitMask, u32 Data) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u32 Original_Value, BitShift, New_Value; - - if (priv->rtllib->rf_power_state != rf_on && !priv->being_init_adapter) - return; - - if (priv->rf_mode == RF_OP_By_FW) { - if (BitMask != bMask12Bits) { - Original_Value = _rtl92e_phy_rf_fw_read(dev, eRFPath, - RegAddr); - BitShift = _rtl92e_calculate_bit_shift(BitMask); - New_Value = (Original_Value & ~BitMask) | (Data << BitShift); - - _rtl92e_phy_rf_fw_write(dev, eRFPath, RegAddr, - New_Value); - } else { - _rtl92e_phy_rf_fw_write(dev, eRFPath, RegAddr, Data); - } - udelay(200); - } else { - if (BitMask != bMask12Bits) { - Original_Value = _rtl92e_phy_rf_read(dev, eRFPath, - RegAddr); - BitShift = _rtl92e_calculate_bit_shift(BitMask); - New_Value = (Original_Value & ~BitMask) | (Data << BitShift); - - _rtl92e_phy_rf_write(dev, eRFPath, RegAddr, New_Value); - } else { - _rtl92e_phy_rf_write(dev, eRFPath, RegAddr, Data); - } - } -} - -u32 rtl92e_get_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, - u32 RegAddr, u32 BitMask) -{ - u32 Original_Value, Readback_Value, BitShift; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->rtllib->rf_power_state != rf_on && !priv->being_init_adapter) - return 0; - mutex_lock(&priv->rf_mutex); - if (priv->rf_mode == RF_OP_By_FW) { - Original_Value = _rtl92e_phy_rf_fw_read(dev, eRFPath, RegAddr); - udelay(200); - } else { - Original_Value = _rtl92e_phy_rf_read(dev, eRFPath, RegAddr); - } - BitShift = _rtl92e_calculate_bit_shift(BitMask); - Readback_Value = (Original_Value & BitMask) >> BitShift; - mutex_unlock(&priv->rf_mutex); - return Readback_Value; -} - -static u32 _rtl92e_phy_rf_fw_read(struct net_device *dev, - enum rf90_radio_path eRFPath, u32 Offset) -{ - u32 Data = 0; - u8 time = 0; - - Data |= ((Offset & 0xFF) << 12); - Data |= ((eRFPath & 0x3) << 20); - Data |= 0x80000000; - while (rtl92e_readl(dev, QPNR) & 0x80000000) { - if (time++ < 100) - udelay(10); - else - break; - } - rtl92e_writel(dev, QPNR, Data); - while (rtl92e_readl(dev, QPNR) & 0x80000000) { - if (time++ < 100) - udelay(10); - else - return 0; - } - return rtl92e_readl(dev, RF_DATA); -} - -static void _rtl92e_phy_rf_fw_write(struct net_device *dev, - enum rf90_radio_path eRFPath, u32 Offset, - u32 Data) -{ - u8 time = 0; - - Data |= ((Offset & 0xFF) << 12); - Data |= ((eRFPath & 0x3) << 20); - Data |= 0x400000; - Data |= 0x80000000; - - while (rtl92e_readl(dev, QPNR) & 0x80000000) { - if (time++ < 100) - udelay(10); - else - break; - } - rtl92e_writel(dev, QPNR, Data); -} - -void rtl92e_config_mac(struct net_device *dev) -{ - u32 dwArrayLen = 0, i = 0; - u32 *pdwArray = NULL; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->tx_pwr_data_read_from_eeprom) { - dwArrayLen = RTL8192E_MACPHY_ARR_PG_LEN; - pdwArray = RTL8192E_MACPHY_ARR_PG; - - } else { - dwArrayLen = RTL8192E_MACPHY_ARR_LEN; - pdwArray = RTL8192E_MACPHY_ARR; - } - for (i = 0; i < dwArrayLen; i += 3) { - if (pdwArray[i] == 0x318) - pdwArray[i + 2] = 0x00000800; - rtl92e_set_bb_reg(dev, pdwArray[i], pdwArray[i + 1], - pdwArray[i + 2]); - } -} - -static void _rtl92e_phy_config_bb(struct net_device *dev, u8 ConfigType) -{ - int i; - u32 *Rtl819XPHY_REGArray_Table = NULL; - u32 *Rtl819XAGCTAB_Array_Table = NULL; - u16 AGCTAB_ArrayLen, PHY_REGArrayLen = 0; - - 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) { - rtl92e_set_bb_reg(dev, Rtl819XPHY_REGArray_Table[i], - bMaskDWord, - Rtl819XPHY_REGArray_Table[i + 1]); - } - } else if (ConfigType == BB_CONFIG_AGC_TAB) { - for (i = 0; i < AGCTAB_ArrayLen; i += 2) { - rtl92e_set_bb_reg(dev, Rtl819XAGCTAB_Array_Table[i], - bMaskDWord, - Rtl819XAGCTAB_Array_Table[i + 1]); - } - } -} - -static void _rtl92e_init_bb_rf_reg_def(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(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_A].rfintfo = rFPGA0_XA_RFInterfaceOE; - priv->phy_reg_def[RF90_PATH_B].rfintfo = rFPGA0_XB_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_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; - priv->phy_reg_def[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; - - 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_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; - priv->phy_reg_def[RF90_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; -} - -bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, - enum rf90_radio_path eRFPath) -{ - bool ret = true; - u32 i, CheckTimes = 4, dwRegRead = 0; - u32 WriteAddr[4]; - u32 WriteData[] = {0xfffff027, 0xaa55a02f, 0x00000027, 0x55aa502f}; - - WriteAddr[HW90_BLOCK_MAC] = 0x100; - WriteAddr[HW90_BLOCK_PHY0] = 0x900; - WriteAddr[HW90_BLOCK_PHY1] = 0x800; - WriteAddr[HW90_BLOCK_RF] = 0x3; - - if (CheckBlock == HW90_BLOCK_MAC) { - netdev_warn(dev, "%s(): No checks available for MAC block.\n", - __func__); - return ret; - } - - for (i = 0; i < CheckTimes; i++) { - switch (CheckBlock) { - case HW90_BLOCK_PHY0: - case HW90_BLOCK_PHY1: - rtl92e_writel(dev, WriteAddr[CheckBlock], - WriteData[i]); - dwRegRead = rtl92e_readl(dev, WriteAddr[CheckBlock]); - break; - - case HW90_BLOCK_RF: - WriteData[i] &= 0xfff; - rtl92e_set_rf_reg(dev, eRFPath, - WriteAddr[HW90_BLOCK_RF], - bMask12Bits, WriteData[i]); - mdelay(10); - dwRegRead = rtl92e_get_rf_reg(dev, eRFPath, - WriteAddr[HW90_BLOCK_RF], - bMaskDWord); - mdelay(10); - break; - - default: - ret = false; - break; - } - - if (dwRegRead != WriteData[i]) { - netdev_warn(dev, "%s(): Check failed.\n", __func__); - ret = false; - break; - } - } - - return ret; -} - -static bool _rtl92e_bb_config_para_file(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - bool rtStatus = true; - u8 bRegValue = 0, eCheckItem = 0; - u32 dwRegValue = 0; - - bRegValue = rtl92e_readb(dev, BB_GLOBAL_RESET); - rtl92e_writeb(dev, BB_GLOBAL_RESET, (bRegValue | BB_GLOBAL_RESET_BIT)); - - dwRegValue = rtl92e_readl(dev, CPU_GEN); - rtl92e_writel(dev, CPU_GEN, (dwRegValue & (~CPU_GEN_BB_RST))); - - for (eCheckItem = (enum hw90_block)HW90_BLOCK_PHY0; - eCheckItem <= HW90_BLOCK_PHY1; eCheckItem++) { - rtStatus = rtl92e_check_bb_and_rf(dev, - (enum hw90_block)eCheckItem, - (enum rf90_radio_path)0); - if (!rtStatus) - return rtStatus; - } - rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn | bOFDMEn, 0x0); - _rtl92e_phy_config_bb(dev, BB_CONFIG_PHY_REG); - - dwRegValue = rtl92e_readl(dev, CPU_GEN); - rtl92e_writel(dev, CPU_GEN, (dwRegValue | CPU_GEN_BB_RST)); - - _rtl92e_phy_config_bb(dev, BB_CONFIG_AGC_TAB); - - if (priv->ic_cut > VERSION_8190_BD) { - dwRegValue = 0x0; - rtl92e_set_bb_reg(dev, rFPGA0_TxGainStage, - (bXBTxAGC | bXCTxAGC | bXDTxAGC), dwRegValue); - - dwRegValue = priv->crystal_cap; - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, bXtalCap92x, - dwRegValue); - } - - return rtStatus; -} - -bool rtl92e_config_bb(struct net_device *dev) -{ - _rtl92e_init_bb_rf_reg_def(dev); - return _rtl92e_bb_config_para_file(dev); -} - -void rtl92e_get_tx_power(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->mcs_tx_pwr_level_org_offset[0] = - rtl92e_readl(dev, rTxAGC_Rate18_06); - priv->mcs_tx_pwr_level_org_offset[1] = - rtl92e_readl(dev, rTxAGC_Rate54_24); - priv->mcs_tx_pwr_level_org_offset[2] = - rtl92e_readl(dev, rTxAGC_Mcs03_Mcs00); - priv->mcs_tx_pwr_level_org_offset[3] = - rtl92e_readl(dev, rTxAGC_Mcs07_Mcs04); - priv->mcs_tx_pwr_level_org_offset[4] = - rtl92e_readl(dev, rTxAGC_Mcs11_Mcs08); - priv->mcs_tx_pwr_level_org_offset[5] = - rtl92e_readl(dev, rTxAGC_Mcs15_Mcs12); - - priv->def_initial_gain[0] = rtl92e_readb(dev, rOFDM0_XAAGCCore1); - priv->def_initial_gain[1] = rtl92e_readb(dev, rOFDM0_XBAGCCore1); - priv->def_initial_gain[2] = rtl92e_readb(dev, rOFDM0_XCAGCCore1); - priv->def_initial_gain[3] = rtl92e_readb(dev, rOFDM0_XDAGCCore1); - - priv->framesync = rtl92e_readb(dev, rOFDM0_RxDetector3); -} - -void rtl92e_set_tx_power(struct net_device *dev, u8 channel) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 powerlevel = 0, powerlevelOFDM24G = 0; - - if (priv->epromtype == EEPROM_93C46) { - powerlevel = priv->tx_pwr_level_cck[channel - 1]; - powerlevelOFDM24G = priv->tx_pwr_level_ofdm_24g[channel - 1]; - } - - 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) -{ - int i; - - switch (eRFPath) { - case RF90_PATH_A: - 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, RTL8192E_RADIO_A_ARR[i], - bMask12Bits, - RTL8192E_RADIO_A_ARR[i + 1]); - } - break; - case RF90_PATH_B: - 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, RTL8192E_RADIO_B_ARR[i], - bMask12Bits, - RTL8192E_RADIO_B_ARR[i + 1]); - } - break; - default: - break; - } - - return 0; -} - -static void _rtl92e_set_tx_power_level(struct net_device *dev, u8 channel) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 powerlevel = priv->tx_pwr_level_cck[channel - 1]; - u8 powerlevelOFDM24G = priv->tx_pwr_level_ofdm_24g[channel - 1]; - - 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, - struct sw_chnl_cmd *CmdTable, - u32 CmdTableIdx, u32 CmdTableSz, - enum sw_chnl_cmd_id cmd_id, - u32 para1, u32 para2, u32 ms_delay) -{ - struct sw_chnl_cmd *pCmd; - - if (!CmdTable) { - netdev_err(dev, "%s(): CmdTable cannot be NULL.\n", __func__); - return false; - } - if (CmdTableIdx >= CmdTableSz) { - netdev_err(dev, "%s(): Invalid index requested.\n", __func__); - return false; - } - - pCmd = CmdTable + CmdTableIdx; - pCmd->cmd_id = cmd_id; - pCmd->para1 = para1; - pCmd->para2 = para2; - pCmd->ms_delay = ms_delay; - - return true; -} - -static u8 _rtl92e_phy_switch_channel_step(struct net_device *dev, u8 channel, - u8 *stage, u8 *step, u32 *delay) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - u32 PreCommonCmdCnt; - u32 PostCommonCmdCnt; - u32 RfDependCmdCnt; - struct sw_chnl_cmd *CurrentCmd = NULL; - u8 eRFPath; - - if (!rtllib_legal_channel(priv->rtllib, channel)) { - netdev_err(dev, "Invalid channel requested: %d\n", channel); - return true; - } - - { - PreCommonCmdCnt = 0; - _rtl92e_phy_set_sw_chnl_cmd_array(dev, ieee->PreCommonCmd, - PreCommonCmdCnt++, - MAX_PRECMD_CNT, - cmd_id_set_tx_power_level, - 0, 0, 0); - _rtl92e_phy_set_sw_chnl_cmd_array(dev, ieee->PreCommonCmd, - PreCommonCmdCnt++, - MAX_PRECMD_CNT, cmd_id_end, - 0, 0, 0); - - PostCommonCmdCnt = 0; - - _rtl92e_phy_set_sw_chnl_cmd_array(dev, ieee->PostCommonCmd, - PostCommonCmdCnt++, - MAX_POSTCMD_CNT, cmd_id_end, - 0, 0, 0); - - RfDependCmdCnt = 0; - - 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, - cmd_id_rf_write_reg, - rZebra1_Channel, - channel, 10); - _rtl92e_phy_set_sw_chnl_cmd_array(dev, - ieee->RfDependCmd, - RfDependCmdCnt++, - MAX_RFDEPENDCMD_CNT, - cmd_id_end, 0, 0, 0); - - do { - switch (*stage) { - case 0: - CurrentCmd = &ieee->PreCommonCmd[*step]; - break; - case 1: - CurrentCmd = &ieee->RfDependCmd[*step]; - break; - case 2: - CurrentCmd = &ieee->PostCommonCmd[*step]; - break; - } - - if (CurrentCmd && CurrentCmd->cmd_id == cmd_id_end) { - if ((*stage) == 2) - return true; - (*stage)++; - (*step) = 0; - continue; - } - - if (!CurrentCmd) - continue; - switch (CurrentCmd->cmd_id) { - case cmd_id_set_tx_power_level: - if (priv->ic_cut > VERSION_8190_BD) - _rtl92e_set_tx_power_level(dev, - channel); - break; - case cmd_id_write_port_ulong: - rtl92e_writel(dev, CurrentCmd->para1, - CurrentCmd->para2); - break; - case cmd_id_write_port_ushort: - rtl92e_writew(dev, CurrentCmd->para1, - CurrentCmd->para2); - break; - case cmd_id_write_port_uchar: - rtl92e_writeb(dev, CurrentCmd->para1, - CurrentCmd->para2); - break; - case cmd_id_rf_write_reg: - for (eRFPath = 0; eRFPath < - priv->num_total_rf_path; eRFPath++) - rtl92e_set_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - CurrentCmd->para1, bMask12Bits, - CurrentCmd->para2 << 7); - break; - default: - break; - } - - break; - } while (true); - } /*for (Number of RF paths)*/ - - (*delay) = CurrentCmd->ms_delay; - (*step)++; - return false; -} - -static void _rtl92e_phy_switch_channel(struct net_device *dev, u8 channel) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u32 delay = 0; - - while (!_rtl92e_phy_switch_channel_step(dev, channel, - &priv->sw_chnl_stage, - &priv->sw_chnl_step, &delay)) { - if (delay > 0) - msleep(delay); - if (!priv->up) - break; - } -} - -static void _rtl92e_phy_switch_channel_work_item(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - _rtl92e_phy_switch_channel(dev, priv->chan); -} - -void rtl92e_set_channel(struct net_device *dev, u8 channel) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (!priv->up) { - netdev_err(dev, "%s(): Driver is not initialized\n", __func__); - return; - } - if (priv->sw_chnl_in_progress) - return; - - switch (priv->rtllib->mode) { - case WIRELESS_MODE_B: - if (channel > 14) { - netdev_warn(dev, - "Channel %d not available in 802.11b.\n", - channel); - return; - } - break; - case WIRELESS_MODE_G: - case WIRELESS_MODE_N_24G: - if (channel > 14) { - netdev_warn(dev, - "Channel %d not available in 802.11g.\n", - channel); - return; - } - break; - } - - priv->sw_chnl_in_progress = true; - if (channel == 0) - channel = 1; - - priv->chan = channel; - - priv->sw_chnl_stage = 0; - priv->sw_chnl_step = 0; - - if (priv->up) - _rtl92e_phy_switch_channel_work_item(dev); - priv->sw_chnl_in_progress = false; -} - -static void _rtl92e_cck_tx_power_track_bw_switch_tssi(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - switch (priv->current_chnl_bw) { - case HT_CHANNEL_WIDTH_20: - priv->cck_present_attn = - priv->cck_present_attn_20m_def + - priv->cck_present_attn_diff; - - if (priv->cck_present_attn > - (CCK_TX_BB_GAIN_TABLE_LEN - 1)) - priv->cck_present_attn = - CCK_TX_BB_GAIN_TABLE_LEN - 1; - if (priv->cck_present_attn < 0) - priv->cck_present_attn = 0; - - if (priv->rtllib->current_network.channel == 14 && - !priv->bcck_in_ch14) { - priv->bcck_in_ch14 = true; - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } else if (priv->rtllib->current_network.channel != - 14 && priv->bcck_in_ch14) { - priv->bcck_in_ch14 = false; - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } else { - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } - break; - - case HT_CHANNEL_WIDTH_20_40: - priv->cck_present_attn = - priv->cck_present_attn_40m_def + - priv->cck_present_attn_diff; - - if (priv->cck_present_attn > - (CCK_TX_BB_GAIN_TABLE_LEN - 1)) - priv->cck_present_attn = - CCK_TX_BB_GAIN_TABLE_LEN - 1; - if (priv->cck_present_attn < 0) - priv->cck_present_attn = 0; - - if (priv->rtllib->current_network.channel == 14 && - !priv->bcck_in_ch14) { - priv->bcck_in_ch14 = true; - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } else if (priv->rtllib->current_network.channel != 14 - && priv->bcck_in_ch14) { - priv->bcck_in_ch14 = false; - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } else { - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } - break; - } -} - -static void _rtl92e_cck_tx_power_track_bw_switch_thermal(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->rtllib->current_network.channel == 14 && - !priv->bcck_in_ch14) - priv->bcck_in_ch14 = true; - else if (priv->rtllib->current_network.channel != 14 && - priv->bcck_in_ch14) - priv->bcck_in_ch14 = false; - - switch (priv->current_chnl_bw) { - case HT_CHANNEL_WIDTH_20: - if (priv->rec_cck_20m_idx == 0) - priv->rec_cck_20m_idx = 6; - priv->cck_index = priv->rec_cck_20m_idx; - break; - - case HT_CHANNEL_WIDTH_20_40: - priv->cck_index = priv->rec_cck_40m_idx; - break; - } - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); -} - -static void _rtl92e_cck_tx_power_track_bw_switch(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->ic_cut >= IC_VersionCut_D) - _rtl92e_cck_tx_power_track_bw_switch_tssi(dev); - else - _rtl92e_cck_tx_power_track_bw_switch_thermal(dev); -} - -static void _rtl92e_set_bw_mode_work_item(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 regBwOpMode; - - if (!priv->up) { - netdev_err(dev, "%s(): Driver is not initialized\n", __func__); - return; - } - regBwOpMode = rtl92e_readb(dev, BW_OPMODE); - - switch (priv->current_chnl_bw) { - case HT_CHANNEL_WIDTH_20: - regBwOpMode |= BW_OPMODE_20MHZ; - rtl92e_writeb(dev, BW_OPMODE, regBwOpMode); - break; - - case HT_CHANNEL_WIDTH_20_40: - regBwOpMode &= ~BW_OPMODE_20MHZ; - rtl92e_writeb(dev, BW_OPMODE, regBwOpMode); - break; - - default: - netdev_err(dev, "%s(): unknown Bandwidth: %#X\n", __func__, - priv->current_chnl_bw); - break; - } - - switch (priv->current_chnl_bw) { - case HT_CHANNEL_WIDTH_20: - rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); - rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); - - if (!priv->btxpower_tracking) { - rtl92e_writel(dev, rCCK0_TxFilter1, 0x1a1b0000); - rtl92e_writel(dev, rCCK0_TxFilter2, 0x090e1317); - rtl92e_writel(dev, rCCK0_DebugPort, 0x00000204); - } else { - _rtl92e_cck_tx_power_track_bw_switch(dev); - } - - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1); - - break; - case HT_CHANNEL_WIDTH_20_40: - rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); - rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); - - if (!priv->btxpower_tracking) { - rtl92e_writel(dev, rCCK0_TxFilter1, 0x35360000); - rtl92e_writel(dev, rCCK0_TxFilter2, 0x121c252e); - rtl92e_writel(dev, rCCK0_DebugPort, 0x00000409); - } else { - _rtl92e_cck_tx_power_track_bw_switch(dev); - } - - rtl92e_set_bb_reg(dev, rCCK0_System, bCCKSideBand, - (priv->n_cur_40mhz_prime_sc >> 1)); - rtl92e_set_bb_reg(dev, rOFDM1_LSTF, 0xC00, - priv->n_cur_40mhz_prime_sc); - - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0); - break; - default: - netdev_err(dev, "%s(): unknown Bandwidth: %#X\n", __func__, - priv->current_chnl_bw); - break; - } - - rtl92e_set_bandwidth(dev, priv->current_chnl_bw); - - atomic_dec(&(priv->rtllib->atm_swbw)); - priv->set_bw_mode_in_progress = false; -} - -void rtl92e_set_bw_mode(struct net_device *dev, enum ht_channel_width bandwidth, - enum ht_extchnl_offset Offset) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->set_bw_mode_in_progress) - return; - - atomic_inc(&(priv->rtllib->atm_swbw)); - priv->set_bw_mode_in_progress = true; - - priv->current_chnl_bw = bandwidth; - - if (Offset == HT_EXTCHNL_OFFSET_LOWER) - priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_UPPER; - else if (Offset == HT_EXTCHNL_OFFSET_UPPER) - priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_LOWER; - else - priv->n_cur_40mhz_prime_sc = HAL_PRIME_CHNL_OFFSET_DONT_CARE; - - _rtl92e_set_bw_mode_work_item(dev); -} - -void rtl92e_init_gain(struct net_device *dev, u8 Operation) -{ -#define SCAN_RX_INITIAL_GAIN 0x17 -#define POWER_DETECTION_TH 0x08 - struct r8192_priv *priv = rtllib_priv(dev); - u32 BitMask; - u8 initial_gain; - - if (priv->up) { - switch (Operation) { - case IG_Backup: - initial_gain = SCAN_RX_INITIAL_GAIN; - BitMask = bMaskByte0; - priv->initgain_backup.xaagccore1 = - rtl92e_get_bb_reg(dev, rOFDM0_XAAGCCore1, - BitMask); - priv->initgain_backup.xbagccore1 = - rtl92e_get_bb_reg(dev, rOFDM0_XBAGCCore1, - BitMask); - priv->initgain_backup.xcagccore1 = - rtl92e_get_bb_reg(dev, rOFDM0_XCAGCCore1, - BitMask); - priv->initgain_backup.xdagccore1 = - rtl92e_get_bb_reg(dev, rOFDM0_XDAGCCore1, - BitMask); - BitMask = bMaskByte2; - priv->initgain_backup.cca = (u8)rtl92e_get_bb_reg(dev, - rCCK0_CCA, BitMask); - - rtl92e_writeb(dev, rOFDM0_XAAGCCore1, initial_gain); - rtl92e_writeb(dev, rOFDM0_XBAGCCore1, initial_gain); - rtl92e_writeb(dev, rOFDM0_XCAGCCore1, initial_gain); - rtl92e_writeb(dev, rOFDM0_XDAGCCore1, initial_gain); - rtl92e_writeb(dev, 0xa0a, POWER_DETECTION_TH); - break; - case IG_Restore: - BitMask = 0x7f; - rtl92e_set_bb_reg(dev, rOFDM0_XAAGCCore1, BitMask, - (u32)priv->initgain_backup.xaagccore1); - rtl92e_set_bb_reg(dev, rOFDM0_XBAGCCore1, BitMask, - (u32)priv->initgain_backup.xbagccore1); - rtl92e_set_bb_reg(dev, rOFDM0_XCAGCCore1, BitMask, - (u32)priv->initgain_backup.xcagccore1); - rtl92e_set_bb_reg(dev, rOFDM0_XDAGCCore1, BitMask, - (u32)priv->initgain_backup.xdagccore1); - BitMask = bMaskByte2; - rtl92e_set_bb_reg(dev, rCCK0_CCA, BitMask, - (u32)priv->initgain_backup.cca); - - rtl92e_set_tx_power(dev, - priv->rtllib->current_network.channel); - break; - } - } -} - -void rtl92e_set_rf_off(struct net_device *dev) -{ - rtl92e_set_bb_reg(dev, rFPGA0_XA_RFInterfaceOE, BIT(4), 0x0); - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x0); - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x18, 0x0); - rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0); - rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0); - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); - rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x4, 0x0); - rtl92e_writeb(dev, ANAPAR_FOR_8192PCIE, 0x07); -} - -static bool _rtl92e_set_rf_power_state(struct net_device *dev, - enum rt_rf_power_state rf_power_state) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - (&priv->rtllib->pwr_save_ctrl); - bool bResult = true; - u8 i = 0, QueueID = 0; - struct rtl8192_tx_ring *ring = NULL; - - if (priv->set_rf_pwr_state_in_progress) - return false; - priv->set_rf_pwr_state_in_progress = true; - - 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, - BIT(4), 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: - 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; - - priv->set_rf_pwr_state_in_progress = false; - return bResult; -} - -bool rtl92e_set_rf_power_state(struct net_device *dev, - enum rt_rf_power_state rf_power_state) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - bool bResult = false; - - if (rf_power_state == priv->rtllib->rf_power_state && - priv->hw_rf_off_action == 0) { - return bResult; - } - - bResult = _rtl92e_set_rf_power_state(dev, rf_power_state); - return bResult; -} - -void rtl92e_scan_op_backup(struct net_device *dev, u8 Operation) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->up) { - switch (Operation) { - case SCAN_OPT_BACKUP: - priv->rtllib->init_gain_handler(dev, IG_Backup); - break; - - case SCAN_OPT_RESTORE: - priv->rtllib->init_gain_handler(dev, IG_Restore); - break; - } - } -} diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h deleted file mode 100644 index 956dfbdd5b6838..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef _R819XU_PHY_H -#define _R819XU_PHY_H - -#define MAX_DOZE_WAITING_TIMES_9x 64 - -enum hw90_block { - HW90_BLOCK_MAC = 0, - HW90_BLOCK_PHY0 = 1, - HW90_BLOCK_PHY1 = 2, - HW90_BLOCK_RF = 3, - HW90_BLOCK_MAXIMUM = 4, -}; - -enum rf90_radio_path { - RF90_PATH_A = 0, - RF90_PATH_B = 1, - RF90_PATH_MAX -}; - -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); -void rtl92e_set_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, - u32 RegAddr, u32 BitMask, u32 Data); -u32 rtl92e_get_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, - u32 RegAddr, u32 BitMask); -void rtl92e_config_mac(struct net_device *dev); -bool rtl92e_check_bb_and_rf(struct net_device *dev, - enum hw90_block CheckBlock, - enum rf90_radio_path eRFPath); -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); -u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath); - -void rtl92e_set_channel(struct net_device *dev, u8 channel); -void rtl92e_set_bw_mode(struct net_device *dev, - enum ht_channel_width bandwidth, - enum ht_extchnl_offset Offset); -void rtl92e_init_gain(struct net_device *dev, u8 operation); - -void rtl92e_set_rf_off(struct net_device *dev); - -bool rtl92e_set_rf_power_state(struct net_device *dev, - enum rt_rf_power_state rf_power_state); - -void rtl92e_scan_op_backup(struct net_device *dev, u8 operation); - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h deleted file mode 100644 index c48c56869c19ea..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phyreg.h +++ /dev/null @@ -1,773 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef _R819XU_PHYREG_H -#define _R819XU_PHYREG_H - -#define RF_DATA 0x1d4 - -#define rPMAC_Reset 0x100 -#define rPMAC_TxStart 0x104 -#define rPMAC_TxLegacySIG 0x108 -#define rPMAC_TxHTSIG1 0x10c -#define rPMAC_TxHTSIG2 0x110 -#define rPMAC_PHYDebug 0x114 -#define rPMAC_TxPacketNum 0x118 -#define rPMAC_TxIdle 0x11c -#define rPMAC_TxMACHeader0 0x120 -#define rPMAC_TxMACHeader1 0x124 -#define rPMAC_TxMACHeader2 0x128 -#define rPMAC_TxMACHeader3 0x12c -#define rPMAC_TxMACHeader4 0x130 -#define rPMAC_TxMACHeader5 0x134 -#define rPMAC_TxDataType 0x138 -#define rPMAC_TxRandomSeed 0x13c -#define rPMAC_CCKPLCPPreamble 0x140 -#define rPMAC_CCKPLCPHeader 0x144 -#define rPMAC_CCKCRC16 0x148 -#define rPMAC_OFDMRxCRC32OK 0x170 -#define rPMAC_OFDMRxCRC32Er 0x174 -#define rPMAC_OFDMRxParityEr 0x178 -#define rPMAC_OFDMRxCRC8Er 0x17c -#define rPMAC_CCKCRxRC16Er 0x180 -#define rPMAC_CCKCRxRC32Er 0x184 -#define rPMAC_CCKCRxRC32OK 0x188 -#define rPMAC_TxStatus 0x18c - -#define MCS_TXAGC 0x340 -#define CCK_TXAGC 0x348 - -/* Mac block on/off control register */ -#define rFPGA0_RFMOD 0x800 /* RF mode & CCK TxSC */ -#define rFPGA0_TxInfo 0x804 -#define rFPGA0_PSDFunction 0x808 -#define rFPGA0_TxGainStage 0x80c -#define rFPGA0_RFTiming1 0x810 -#define rFPGA0_RFTiming2 0x814 -#define rFPGA0_XA_HSSIParameter2 0x824 -#define rFPGA0_XB_HSSIParameter2 0x82c -#define rFPGA0_XA_LSSIParameter 0x840 -#define rFPGA0_XB_LSSIParameter 0x844 -#define rFPGA0_RFWakeUpParameter 0x850 -#define rFPGA0_RFSleepUpParameter 0x854 -#define rFPGA0_XA_RFInterfaceOE 0x860 -#define rFPGA0_XB_RFInterfaceOE 0x864 -#define rFPGA0_XAB_RFInterfaceSW 0x870 -#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_PSDReport 0x8b4 - -/* Page 9 - RF mode & OFDM TxSC */ -#define rFPGA1_RFMOD 0x900 -#define rFPGA1_TxBlock 0x904 -#define rFPGA1_DebugSelect 0x908 -#define rFPGA1_TxInfo 0x90c - -#define rCCK0_System 0xa00 -#define rCCK0_AFESetting 0xa04 -#define rCCK0_CCA 0xa08 -/* AGC default value, saturation level */ -#define rCCK0_RxAGC1 0xa0c -#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */ -#define rCCK0_RxHP 0xa14 -/* Timing recovery & channel estimation threshold */ -#define rCCK0_DSPParameter1 0xa18 -#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ -#define rCCK0_TxFilter1 0xa20 -#define rCCK0_TxFilter2 0xa24 -#define rCCK0_DebugPort 0xa28 /* Debug port and TX filter 3 */ -#define rCCK0_FalseAlarmReport 0xa2c -#define rCCK0_TRSSIReport 0xa50 -#define rCCK0_RxReport 0xa54 -#define rCCK0_FACounterLower 0xa5c -#define rCCK0_FACounterUpper 0xa58 - -#define rOFDM0_LSTF 0xc00 -#define rOFDM0_TRxPathEnable 0xc04 -#define rOFDM0_TRMuxPar 0xc08 -#define rOFDM0_TRSWIsolation 0xc0c -#define rOFDM0_RxDetector1 0xc30 /* PD, BW & SBD */ -#define rOFDM0_RxDetector2 0xc34 /* SBD */ -#define rOFDM0_RxDetector3 0xc38 /* Frame Sync */ -/* PD, SBD, Frame Sync & Short-GI */ -#define rOFDM0_RxDetector4 0xc3c -#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ -#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ -#define rOFDM0_CCADropThreshold 0xc48 -#define rOFDM0_ECCAThreshold 0xc4c /* Energy CCA */ -#define rOFDM0_XAAGCCore1 0xc50 -#define rOFDM0_XBAGCCore1 0xc58 -#define rOFDM0_XCAGCCore1 0xc60 -#define rOFDM0_XDAGCCore1 0xc68 -#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_XCTxIQImbalance 0xc90 -#define rOFDM0_RxHPParameter 0xce0 -#define rOFDM0_TxPseudoNoiseWgt 0xce4 -#define rOFDM0_FrameSync 0xcf0 -#define rOFDM0_DFSReport 0xcf4 -#define rOFDM0_TxCoeff1 0xca4 -#define rOFDM0_TxCoeff2 0xca8 -#define rOFDM0_TxCoeff3 0xcac -#define rOFDM0_TxCoeff4 0xcb0 -#define rOFDM0_TxCoeff5 0xcb4 -#define rOFDM0_TxCoeff6 0xcb8 - -#define rOFDM1_LSTF 0xd00 -#define rOFDM1_TRxPathEnable 0xd04 -#define rOFDM1_CFO 0xd08 -#define rOFDM1_CSI1 0xd10 -#define rOFDM1_SBD 0xd14 -#define rOFDM1_CSI2 0xd18 -#define rOFDM1_CFOTracking 0xd2c -#define rOFDM1_TRxMesaure1 0xd34 -#define rOFDM1_IntfDet 0xd3c -#define rOFDM1_PseudoNoiseStateAB 0xd50 -#define rOFDM1_PseudoNoiseStateCD 0xd54 -#define rOFDM1_RxPseudoNoiseWgt 0xd58 -#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */ -#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */ -#define rOFDM_PHYCounter3 0xda8 /* MCS not supported */ -#define rOFDM_ShortCFOAB 0xdac -#define rOFDM_ShortCFOCD 0xdb0 -#define rOFDM_LongCFOAB 0xdb4 -#define rOFDM_LongCFOCD 0xdb8 -#define rOFDM_TailCFOAB 0xdbc -#define rOFDM_TailCFOCD 0xdc0 -#define rOFDM_PWMeasure1 0xdc4 -#define rOFDM_PWMeasure2 0xdc8 -#define rOFDM_BWReport 0xdcc -#define rOFDM_AGCReport 0xdd0 -#define rOFDM_RxSNR 0xdd4 -#define rOFDM_RxEVMCSI 0xdd8 -#define rOFDM_SIGReport 0xddc - -#define rTxAGC_Rate18_06 0xe00 -#define rTxAGC_Rate54_24 0xe04 -#define rTxAGC_CCK_Mcs32 0xe08 -#define rTxAGC_Mcs03_Mcs00 0xe10 -#define rTxAGC_Mcs07_Mcs04 0xe14 -#define rTxAGC_Mcs11_Mcs08 0xe18 -#define rTxAGC_Mcs15_Mcs12 0xe1c - -#define rZebra1_HSSIEnable 0x0 -#define rZebra1_TRxEnable1 0x1 -#define rZebra1_TRxEnable2 0x2 -#define rZebra1_AGC 0x4 -#define rZebra1_ChargePump 0x5 -#define rZebra1_Channel 0x7 -#define rZebra1_TxGain 0x8 -#define rZebra1_TxLPF 0x9 -#define rZebra1_RxLPF 0xb -#define rZebra1_RxHPFCorner 0xc - -/* Zebra 4 */ -#define rGlobalCtrl 0 -#define rRTL8256_TxLPF 19 -#define rRTL8256_RxLPF 11 - -/* RTL8258 */ -#define rRTL8258_TxLPF 0x11 -#define rRTL8258_RxLPF 0x13 -#define rRTL8258_RSSILPF 0xa - -/* Bit Mask - Page 1*/ -#define bBBResetB 0x100 -#define bGlobalResetB 0x200 -#define bOFDMTxStart 0x4 -#define bCCKTxStart 0x8 -#define bCRC32Debug 0x100 -#define bPMACLoopback 0x10 -#define bTxLSIG 0xffffff -#define bOFDMTxRate 0xf -#define bOFDMTxReserved 0x10 -#define bOFDMTxLength 0x1ffe0 -#define bOFDMTxParity 0x20000 -#define bTxHTSIG1 0xffffff -#define bTxHTMCSRate 0x7f -#define bTxHTBW 0x80 -#define bTxHTLength 0xffff00 -#define bTxHTSIG2 0xffffff -#define bTxHTSmoothing 0x1 -#define bTxHTSounding 0x2 -#define bTxHTReserved 0x4 -#define bTxHTAggreation 0x8 -#define bTxHTSTBC 0x30 -#define bTxHTAdvanceCoding 0x40 -#define bTxHTShortGI 0x80 -#define bTxHTNumberHT_LTF 0x300 -#define bTxHTCRC8 0x3fc00 -#define bCounterReset 0x10000 -#define bNumOfOFDMTx 0xffff -#define bNumOfCCKTx 0xffff0000 -#define bTxIdleInterval 0xffff -#define bOFDMService 0xffff0000 -#define bTxMACHeader 0xffffffff -#define bTxDataInit 0xff -#define bTxHTMode 0x100 -#define bTxDataType 0x30000 -#define bTxRandomSeed 0xffffffff -#define bCCKTxPreamble 0x1 -#define bCCKTxSFD 0xffff0000 -#define bCCKTxSIG 0xff -#define bCCKTxService 0xff00 -#define bCCKLengthExt 0x8000 -#define bCCKTxLength 0xffff0000 -#define bCCKTxCRC16 0xffff -#define bCCKTxStatus 0x1 -#define bOFDMTxStatus 0x2 -/* Bit Mask - Page 8 */ -#define bRFMOD 0x1 -#define bJapanMode 0x2 -#define bCCKTxSC 0x30 -#define bCCKEn 0x1000000 -#define bOFDMEn 0x2000000 -#define bOFDMRxADCPhase 0x10000 -#define bOFDMTxDACPhase 0x40000 -#define bXATxAGC 0x3f -#define bXBTxAGC 0xf00 -#define bXCTxAGC 0xf000 -#define bXDTxAGC 0xf0000 -#define bPAStart 0xf0000000 -#define bTRStart 0x00f00000 -#define bRFStart 0x0000f000 -#define bBBStart 0x000000f0 -#define bBBCCKStart 0x0000000f -/* Bit Mask - rFPGA0_RFTiming2 */ -#define bPAEnd 0xf -#define bTREnd 0x0f000000 -#define bRFEnd 0x000f0000 -/* Channel gain at continue TX. */ -#define b3WireDataLength 0x800 -#define b3WireAddressLength 0x400 -/* 3-wire total control */ -#define bRFSI_RFENV 0x10 -#define bLSSIReadAddress 0x3f000000 /* LSSI "read" address */ -#define bLSSIReadEdge 0x80000000 /* LSSI "read" edge signal */ -#define bLSSIReadBackData 0xfff - -#define bDA6Swing 0x380000 -#define bADClkPhase 0x4000000 -#define b80MClkDelay 0x18000000 -#define bAFEWatchDogEnable 0x20000000 -#define bXtalCap 0x0f000000 -#define bXtalCap01 0xc0000000 -#define bXtalCap23 0x3 -#define bXtalCap92x 0x0f000000 -#define bIntDifClkEnable 0x400 -#define bExtSigClkEnable 0x800 -#define bBandgapMbiasPowerUp 0x10000 -#define bAD11SHGain 0xc0000 -#define bAD11InputRange 0x700000 -#define bAD11OPCurrent 0x3800000 -#define bIPathLoopback 0x4000000 -#define bQPathLoopback 0x8000000 -#define bAFELoopback 0x10000000 -#define bDA10Swing 0x7e0 -#define bDA10Reverse 0x800 -#define bDAClkSource 0x1000 -#define bAD7InputRange 0x6000 -#define bAD7Gain 0x38000 -#define bAD7OutputCMMode 0x40000 -#define bAD7InputCMMode 0x380000 -#define bAD7Current 0xc00000 -#define bRegulatorAdjust 0x7000000 -#define bAD11PowerUpAtTx 0x1 -#define bDA10PSAtTx 0x10 -#define bAD11PowerUpAtRx 0x100 -#define bDA10PSAtRx 0x1000 - -#define bCCKRxAGCFormat 0x200 - -#define bPSDFFTSamplepPoint 0xc000 -#define bPSDAverageNum 0x3000 -#define bIQPathControl 0xc00 -#define bPSDFreq 0x3ff -#define bPSDAntennaPath 0x30 -#define bPSDIQSwitch 0x40 -#define bPSDRxTrigger 0x400000 -#define bPSDTxTrigger 0x80000000 -#define bPSDSineToneScale 0x7f000000 -#define bPSDReport 0xffff - -/* Page 8 */ -#define bOFDMTxSC 0x30000000 -#define bCCKTxOn 0x1 -#define bOFDMTxOn 0x2 -/* Reset debug page and also HWord, LWord */ -#define bDebugPage 0xfff -/* Reset debug page and LWord */ -#define bDebugItem 0xff -#define bAntL 0x10 -#define bAntNonHT 0x100 -#define bAntHT1 0x1000 -#define bAntHT2 0x10000 -#define bAntHT1S1 0x100000 -#define bAntNonHTS1 0x1000000 - -/* Page a */ -#define bCCKBBMode 0x3 -#define bCCKTxPowerSaving 0x80 -#define bCCKRxPowerSaving 0x40 -#define bCCKSideBand 0x10 -#define bCCKScramble 0x8 -#define bCCKAntDiversity 0x8000 -#define bCCKCarrierRecovery 0x4000 -#define bCCKTxRate 0x3000 -#define bCCKDCCancel 0x0800 -#define bCCKISICancel 0x0400 -#define bCCKMatchFilter 0x0200 -#define bCCKEqualizer 0x0100 -#define bCCKPreambleDetect 0x800000 -#define bCCKFastFalseCCA 0x400000 -#define bCCKChEstStart 0x300000 -#define bCCKCCACount 0x080000 -#define bCCKcs_lim 0x070000 -#define bCCKBistMode 0x80000000 -#define bCCKCCAMask 0x40000000 -#define bCCKTxDACPhase 0x4 -#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ -#define bCCKr_cp_mode0 0x0100 -#define bCCKTxDCOffset 0xf0 -#define bCCKRxDCOffset 0xf -#define bCCKCCAMode 0xc000 -#define bCCKFalseCS_lim 0x3f00 -#define bCCKCS_ratio 0xc00000 -#define bCCKCorgBit_sel 0x300000 -#define bCCKPD_lim 0x0f0000 -#define bCCKNewCCA 0x80000000 -#define bCCKRxHPofIG 0x8000 -#define bCCKRxIG 0x7f00 -#define bCCKLNAPolarity 0x800000 -#define bCCKRx1stGain 0x7f0000 -/* CCK Rx Initial gain polarity */ -#define bCCKRFExtend 0x20000000 -#define bCCKRxAGCSatLevel 0x1f000000 -#define bCCKRxAGCSatCount 0xe0 -/* AGCSAmp_dly */ -#define bCCKRxRFSettle 0x1f -#define bCCKFixedRxAGC 0x8000 -/*#define bCCKRxAGCFormat 0x4000 remove to HSSI register 0x824 */ -#define bCCKAntennaPolarity 0x2000 -#define bCCKTxFilterType 0x0c00 -#define bCCKRxAGCReportType 0x0300 -#define bCCKRxDAGCEn 0x80000000 -#define bCCKRxDAGCPeriod 0x20000000 -#define bCCKRxDAGCSatLevel 0x1f000000 -#define bCCKTimingRecovery 0x800000 -#define bCCKTxC0 0x3f0000 -#define bCCKTxC1 0x3f000000 -#define bCCKTxC2 0x3f -#define bCCKTxC3 0x3f00 -#define bCCKTxC4 0x3f0000 -#define bCCKTxC5 0x3f000000 -#define bCCKTxC6 0x3f -#define bCCKTxC7 0x3f00 -#define bCCKDebugPort 0xff0000 -#define bCCKDACDebug 0x0f000000 -#define bCCKFalseAlarmEnable 0x8000 -#define bCCKFalseAlarmRead 0x4000 -#define bCCKTRSSI 0x7f -#define bCCKRxAGCReport 0xfe -#define bCCKRxReport_AntSel 0x80000000 -#define bCCKRxReport_MFOff 0x40000000 -#define bCCKRxRxReport_SQLoss 0x20000000 -#define bCCKRxReport_Pktloss 0x10000000 -#define bCCKRxReport_Lockedbit 0x08000000 -#define bCCKRxReport_RateError 0x04000000 -#define bCCKRxReport_RxRate 0x03000000 -#define bCCKRxFACounterLower 0xff -#define bCCKRxFACounterUpper 0xff000000 -#define bCCKRxHPAGCStart 0xe000 -#define bCCKRxHPAGCFinal 0x1c00 - -#define bCCKRxFalseAlarmEnable 0x8000 -#define bCCKFACounterFreeze 0x4000 - -#define bCCKTxPathSel 0x10000000 -#define bCCKDefaultRxPath 0xc000000 -#define bCCKOptionRxPath 0x3000000 - -/* Page c */ -#define bNumOfSTF 0x3 -#define bShift_L 0xc0 -#define bGI_TH 0xc -#define bRxPathA 0x1 -#define bRxPathB 0x2 -#define bRxPathC 0x4 -#define bRxPathD 0x8 -#define bTxPathA 0x1 -#define bTxPathB 0x2 -#define bTxPathC 0x4 -#define bTxPathD 0x8 -#define bTRSSIFreq 0x200 -#define bADCBackoff 0x3000 -#define bDFIRBackoff 0xc000 -#define bTRSSILatchPhase 0x10000 -#define bRxIDCOffset 0xff -#define bRxQDCOffset 0xff00 -#define bRxDFIRMode 0x1800000 -#define bRxDCNFType 0xe000000 -#define bRXIQImb_A 0x3ff -#define bRXIQImb_B 0xfc00 -#define bRXIQImb_C 0x3f0000 -#define bRXIQImb_D 0xffc00000 -#define bDC_dc_Notch 0x60000 -#define bRxNBINotch 0x1f000000 -#define bPD_TH 0xf -#define bPD_TH_Opt2 0xc000 -#define bPWED_TH 0x700 -#define bIfMF_Win_L 0x800 -#define bPD_Option 0x1000 -#define bMF_Win_L 0xe000 -#define bBW_Search_L 0x30000 -#define bwin_enh_L 0xc0000 -#define bBW_TH 0x700000 -#define bED_TH2 0x3800000 -#define bBW_option 0x4000000 -#define bRatio_TH 0x18000000 -#define bWindow_L 0xe0000000 -#define bSBD_Option 0x1 -#define bFrame_TH 0x1c -#define bFS_Option 0x60 -#define bDC_Slope_check 0x80 -#define bFGuard_Counter_DC_L 0xe00 -#define bFrame_Weight_Short 0x7000 -#define bSub_Tune 0xe00000 -#define bFrame_DC_Length 0xe000000 -#define bSBD_start_offset 0x30000000 -#define bFrame_TH_2 0x7 -#define bFrame_GI2_TH 0x38 -#define bGI2_Sync_en 0x40 -#define bSarch_Short_Early 0x300 -#define bSarch_Short_Late 0xc00 -#define bSarch_GI2_Late 0x70000 -#define bCFOAntSum 0x1 -#define bCFOAcc 0x2 -#define bCFOStartOffset 0xc -#define bCFOLookBack 0x70 -#define bCFOSumWeight 0x80 -#define bDAGCEnable 0x10000 -#define bTXIQImb_A 0x3ff -#define bTXIQImb_B 0xfc00 -#define bTXIQImb_C 0x3f0000 -#define bTXIQImb_D 0xffc00000 -#define bTxIDCOffset 0xff -#define bTxQDCOffset 0xff00 -#define bTxDFIRMode 0x10000 -#define bTxPesudoNoiseOn 0x4000000 -#define bTxPesudoNoise_A 0xff -#define bTxPesudoNoise_B 0xff00 -#define bTxPesudoNoise_C 0xff0000 -#define bTxPesudoNoise_D 0xff000000 -#define bCCADropOption 0x20000 -#define bCCADropThres 0xfff00000 -#define bEDCCA_H 0xf -#define bEDCCA_L 0xf0 -#define bLambda_ED 0x300 -#define bRxInitialGain 0x7f -#define bRxAntDivEn 0x80 -#define bRxAGCAddressForLNA 0x7f00 -#define bRxHighPowerFlow 0x8000 -#define bRxAGCFreezeThres 0xc0000 -#define bRxFreezeStep_AGC1 0x300000 -#define bRxFreezeStep_AGC2 0xc00000 -#define bRxFreezeStep_AGC3 0x3000000 -#define bRxFreezeStep_AGC0 0xc000000 -#define bRxRssi_Cmp_En 0x10000000 -#define bRxQuickAGCEn 0x20000000 -#define bRxAGCFreezeThresMode 0x40000000 -#define bRxOverFlowCheckType 0x80000000 -#define bRxAGCShift 0x7f -#define bTRSW_Tri_Only 0x80 -#define bPowerThres 0x300 -#define bRxAGCEn 0x1 -#define bRxAGCTogetherEn 0x2 -#define bRxAGCMin 0x4 -#define bRxHP_Ini 0x7 -#define bRxHP_TRLNA 0x70 -#define bRxHP_RSSI 0x700 -#define bRxHP_BBP1 0x7000 -#define bRxHP_BBP2 0x70000 -#define bRxHP_BBP3 0x700000 -/* The threshold for high power */ -#define bRSSI_H 0x7f0000 -/* The threshold for ant diversity */ -#define bRSSI_Gen 0x7f000000 -#define bRxSettle_TRSW 0x7 -#define bRxSettle_LNA 0x38 -#define bRxSettle_RSSI 0x1c0 -#define bRxSettle_BBP 0xe00 -#define bRxSettle_RxHP 0x7000 -#define bRxSettle_AntSW_RSSI 0x38000 -#define bRxSettle_AntSW 0xc0000 -#define bRxProcessTime_DAGC 0x300000 -#define bRxSettle_HSSI 0x400000 -#define bRxProcessTime_BBPPW 0x800000 -#define bRxAntennaPowerShift 0x3000000 -#define bRSSITableSelect 0xc000000 -#define bRxHP_Final 0x7000000 -#define bRxHTSettle_BBP 0x7 -#define bRxHTSettle_HSSI 0x8 -#define bRxHTSettle_RxHP 0x70 -#define bRxHTSettle_BBPPW 0x80 -#define bRxHTSettle_Idle 0x300 -#define bRxHTSettle_Reserved 0x1c00 -#define bRxHTRxHPEn 0x8000 -#define bRxHTAGCFreezeThres 0x30000 -#define bRxHTAGCTogetherEn 0x40000 -#define bRxHTAGCMin 0x80000 -#define bRxHTAGCEn 0x100000 -#define bRxHTDAGCEn 0x200000 -#define bRxHTRxHP_BBP 0x1c00000 -#define bRxHTRxHP_Final 0xe0000000 -#define bRxPWRatioTH 0x3 -#define bRxPWRatioEn 0x4 -#define bRxMFHold 0x3800 -#define bRxPD_Delay_TH1 0x38 -#define bRxPD_Delay_TH2 0x1c0 -#define bRxPD_DC_COUNT_MAX 0x600 -/*#define bRxMF_Hold 0x3800*/ -#define bRxPD_Delay_TH 0x8000 -#define bRxProcess_Delay 0xf0000 -#define bRxSearchrange_GI2_Early 0x700000 -#define bRxFrame_Guard_Counter_L 0x3800000 -#define bRxSGI_Guard_L 0xc000000 -#define bRxSGI_Search_L 0x30000000 -#define bRxSGI_TH 0xc0000000 -#define bDFSCnt0 0xff -#define bDFSCnt1 0xff00 -#define bDFSFlag 0xf0000 - -#define bMFWeightSum 0x300000 -#define bMinIdxTH 0x7f000000 - -#define bDAFormat 0x40000 - -#define bTxChEmuEnable 0x01000000 - -#define bTRSWIsolation_A 0x7f -#define bTRSWIsolation_B 0x7f00 -#define bTRSWIsolation_C 0x7f0000 -#define bTRSWIsolation_D 0x7f000000 - -#define bExtLNAGain 0x7c00 - -/* Page d */ -#define bSTBCEn 0x4 -#define bAntennaMapping 0x10 -#define bNss 0x20 -#define bCFOAntSumD 0x200 -#define bPHYCounterReset 0x8000000 -#define bCFOReportGet 0x4000000 -#define bOFDMContinueTx 0x10000000 -#define bOFDMSingleCarrier 0x20000000 -#define bOFDMSingleTone 0x40000000 -/* #define bRxPath1 0x01 - * #define bRxPath2 0x02 - * #define bRxPath3 0x04 - * #define bRxPath4 0x08 - * #define bTxPath1 0x10 - * #define bTxPath2 0x20 - */ -#define bHTDetect 0x100 -#define bCFOEn 0x10000 -#define bCFOValue 0xfff00000 -#define bSigTone_Re 0x3f -#define bSigTone_Im 0x7f00 -#define bCounter_CCA 0xffff -#define bCounter_ParityFail 0xffff0000 -#define bCounter_RateIllegal 0xffff -#define bCounter_CRC8Fail 0xffff0000 -#define bCounter_MCSNoSupport 0xffff -#define bCounter_FastSync 0xffff -#define bShortCFO 0xfff -#define bShortCFOTLength 12 /* total */ -#define bShortCFOFLength 11 /* fraction */ -#define bLongCFO 0x7ff -#define bLongCFOTLength 11 -#define bLongCFOFLength 11 -#define bTailCFO 0x1fff -#define bTailCFOTLength 13 -#define bTailCFOFLength 12 - -#define bmax_en_pwdB 0xffff -#define bCC_power_dB 0xffff0000 -#define bnoise_pwdB 0xffff -#define bPowerMeasTLength 10 -#define bPowerMeasFLength 3 -#define bRx_HT_BW 0x1 -#define bRxSC 0x6 -#define bRx_HT 0x8 - -#define bNB_intf_det_on 0x1 -#define bIntf_win_len_cfg 0x30 -#define bNB_Intf_TH_cfg 0x1c0 - -#define bRFGain 0x3f -#define bTableSel 0x40 -#define bTRSW 0x80 - -#define bRxSNR_A 0xff -#define bRxSNR_B 0xff00 -#define bRxSNR_C 0xff0000 -#define bRxSNR_D 0xff000000 -#define bSNREVMTLength 8 -#define bSNREVMFLength 1 - -#define bCSI1st 0xff -#define bCSI2nd 0xff00 -#define bRxEVM1st 0xff0000 -#define bRxEVM2nd 0xff000000 - -#define bSIGEVM 0xff -#define bPWDB 0xff00 -#define bSGIEN 0x10000 - -#define bSFactorQAM1 0xf -#define bSFactorQAM2 0xf0 -#define bSFactorQAM3 0xf00 -#define bSFactorQAM4 0xf000 -#define bSFactorQAM5 0xf0000 -#define bSFactorQAM6 0xf0000 -#define bSFactorQAM7 0xf00000 -#define bSFactorQAM8 0xf000000 -#define bSFactorQAM9 0xf0000000 -#define bCSIScheme 0x100000 - -#define bNoiseLvlTopSet 0x3 -#define bChSmooth 0x4 -#define bChSmoothCfg1 0x38 -#define bChSmoothCfg2 0x1c0 -#define bChSmoothCfg3 0xe00 -#define bChSmoothCfg4 0x7000 -#define bMRCMode 0x800000 -#define bTHEVMCfg 0x7000000 - -#define bLoopFitType 0x1 -#define bUpdCFO 0x40 -#define bUpdCFOOffData 0x80 -#define bAdvUpdCFO 0x100 -#define bAdvTimeCtrl 0x800 -#define bUpdClko 0x1000 -#define bFC 0x6000 -#define bTrackingMode 0x8000 -#define bPhCmpEnable 0x10000 -#define bUpdClkoLTF 0x20000 -#define bComChCFO 0x40000 -#define bCSIEstiMode 0x80000 -#define bAdvUpdEqz 0x100000 -#define bUChCfg 0x7000000 -#define bUpdEqz 0x8000000 - -/* Page e */ -#define bTxAGCRate18_06 0x7f7f7f7f -#define bTxAGCRate54_24 0x7f7f7f7f -#define bTxAGCRateMCS32 0x7f -#define bTxAGCRateCCK 0x7f00 -#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f -#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f -#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f -#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f - -#define bRxPesudoNoiseOn 0x20000000 /* Rx Pseduo noise */ -#define bRxPesudoNoise_A 0xff -#define bRxPesudoNoise_B 0xff00 -#define bRxPesudoNoise_C 0xff0000 -#define bRxPesudoNoise_D 0xff000000 -#define bPesudoNoiseState_A 0xffff -#define bPesudoNoiseState_B 0xffff0000 -#define bPesudoNoiseState_C 0xffff -#define bPesudoNoiseState_D 0xffff0000 - -/* RF Zebra 1 */ -#define bZebra1_HSSIEnable 0x8 -#define bZebra1_TRxControl 0xc00 -#define bZebra1_TRxGainSetting 0x07f -#define bZebra1_RxCorner 0xc00 -#define bZebra1_TxChargePump 0x38 -#define bZebra1_RxChargePump 0x7 -#define bZebra1_ChannelNum 0xf80 -#define bZebra1_TxLPFBW 0x400 -#define bZebra1_RxLPFBW 0x600 - -/* Zebra4 */ -#define bRTL8256RegModeCtrl1 0x100 -#define bRTL8256RegModeCtrl0 0x40 -#define bRTL8256_TxLPFBW 0x18 -#define bRTL8256_RxLPFBW 0x600 - -/* RTL8258 */ -#define bRTL8258_TxLPFBW 0xc -#define bRTL8258_RxLPFBW 0xc00 -#define bRTL8258_RSSILPFBW 0xc0 - -/* byte enable for sb_write */ -#define bByte0 0x1 -#define bByte1 0x2 -#define bByte2 0x4 -#define bByte3 0x8 -#define bWord0 0x3 -#define bWord1 0xc -#define bDWord 0xf - -/* for PutRegsetting & GetRegSetting BitMask */ -#define bMaskByte0 0xff -#define bMaskByte1 0xff00 -#define bMaskByte2 0xff0000 -#define bMaskByte3 0xff000000 -#define bMaskHWord 0xffff0000 -#define bMaskLWord 0x0000ffff -#define bMaskDWord 0xffffffff - -/* for PutRFRegsetting & GetRFRegSetting BitMask */ -#define bMask12Bits 0xfff - -#define bEnable 0x1 -#define bDisable 0x0 - -#define LeftAntenna 0x0 -#define RightAntenna 0x1 - -#define tCheckTxStatus 500 /* 500 ms */ -#define tUpdateRxCounter 100 /* 100 ms */ - -#define rateCCK 0 -#define rateOFDM 1 -#define rateHT 2 - -#define bPMAC_End 0x1ff /* define Register-End */ -#define bFPGAPHY0_End 0x8ff -#define bFPGAPHY1_End 0x9ff -#define bCCKPHY0_End 0xaff -#define bOFDMPHY0_End 0xcff -#define bOFDMPHY1_End 0xdff - -#define bPMACControl 0x0 -#define bWMACControl 0x1 -#define bWNICControl 0x2 - -#define PathA 0x0 -#define PathB 0x1 -#define PathC 0x2 -#define PathD 0x3 - -#define rRTL8256RxMixerPole 0xb -#define bZebraRxMixerPole 0x6 -#define rRTL8256TxBBOPBias 0x9 -#define bRTL8256TxBBOPBias 0x400 -#define rRTL8256TxBBBW 19 -#define bRTL8256TxBBBW 0x18 - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c deleted file mode 100644 index 69298c7c129ad7..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#include "rtl_core.h" -#include "r8192E_phy.h" -#include "r8192E_phyreg.h" -#include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */ -#include "r8192E_cmdpkt.h" - -void rtl92e_cam_reset(struct net_device *dev) -{ - u32 ulcommand = 0; - - ulcommand |= BIT(31) | BIT(30); - rtl92e_writel(dev, RWCAM, ulcommand); -} - -void rtl92e_enable_hw_security_config(struct net_device *dev) -{ - u8 SECR_value = 0x0; - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - - SECR_value = SCR_TxEncEnable | SCR_RxDecEnable; - if (((ieee->pairwise_key_type == KEY_TYPE_WEP40) || - (ieee->pairwise_key_type == KEY_TYPE_WEP104)) && - (priv->rtllib->auth_mode != 2)) { - SECR_value |= SCR_RxUseDK; - SECR_value |= SCR_TxUseDK; - } - - ieee->hwsec_active = 1; - if ((ieee->ht_info->iot_action & HT_IOT_ACT_PURE_N_MODE) || !hwwep) { - ieee->hwsec_active = 0; - SECR_value &= ~SCR_RxDecEnable; - } - rtl92e_writeb(dev, SECR, SECR_value); -} - -void rtl92e_set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, - u16 KeyType, const u8 *MacAddr, u32 *KeyContent) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - - if (EntryNo >= TOTAL_CAM_ENTRY) - return; - - ieee->swcamtable[EntryNo].bused = true; - ieee->swcamtable[EntryNo].key_index = KeyIndex; - ieee->swcamtable[EntryNo].key_type = KeyType; - memcpy(ieee->swcamtable[EntryNo].macaddr, MacAddr, 6); - ieee->swcamtable[EntryNo].useDK = 0; - memcpy(ieee->swcamtable[EntryNo].key_buf, (u8 *)KeyContent, 16); -} - -void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex, - u16 KeyType, const u8 *MacAddr, u8 DefaultKey, - u32 *KeyContent) -{ - u32 TargetCommand = 0; - u32 TargetContent = 0; - u16 usConfig = 0; - u8 i; - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - enum rt_rf_power_state rt_state; - - rt_state = priv->rtllib->rf_power_state; - if (rt_state == rf_off) { - if (priv->rtllib->rf_off_reason > RF_CHANGE_BY_IPS) { - netdev_warn(dev, "%s(): RF is OFF.\n", - __func__); - return; - } - mutex_lock(&priv->rtllib->ips_mutex); - rtl92e_ips_leave(dev); - mutex_unlock(&priv->rtllib->ips_mutex); - } - priv->rtllib->is_set_key = true; - if (EntryNo >= TOTAL_CAM_ENTRY) { - netdev_info(dev, "%s(): Invalid CAM entry\n", __func__); - return; - } - - if (DefaultKey) - usConfig |= BIT(15) | (KeyType << 2); - else - usConfig |= BIT(15) | (KeyType << 2) | KeyIndex; - - for (i = 0; i < CAM_CONTENT_COUNT; i++) { - TargetCommand = i + CAM_CONTENT_COUNT * EntryNo; - TargetCommand |= BIT(31) | BIT(16); - - if (i == 0) { - TargetContent = (u32)(*(MacAddr + 0)) << 16 | - (u32)(*(MacAddr + 1)) << 24 | - (u32)usConfig; - - rtl92e_writel(dev, WCAMI, TargetContent); - rtl92e_writel(dev, RWCAM, TargetCommand); - } else if (i == 1) { - TargetContent = (u32)(*(MacAddr + 2)) | - (u32)(*(MacAddr + 3)) << 8 | - (u32)(*(MacAddr + 4)) << 16 | - (u32)(*(MacAddr + 5)) << 24; - rtl92e_writel(dev, WCAMI, TargetContent); - rtl92e_writel(dev, RWCAM, TargetCommand); - } else { - if (KeyContent) { - rtl92e_writel(dev, WCAMI, - (u32)(*(KeyContent + i - 2))); - rtl92e_writel(dev, RWCAM, TargetCommand); - udelay(100); - } - } - } -} diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h deleted file mode 100644 index 9deffdf96072a5..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#ifndef _RTL_CAM_H -#define _RTL_CAM_H - -#include - -struct net_device; - -void rtl92e_cam_reset(struct net_device *dev); -void rtl92e_enable_hw_security_config(struct net_device *dev); -void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex, - u16 KeyType, const u8 *MacAddr, u8 DefaultKey, - u32 *KeyContent); -void rtl92e_set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, - u16 KeyType, const u8 *MacAddr, u32 *KeyContent); - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c deleted file mode 100644 index dc1301f1a0c16b..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ /dev/null @@ -1,2016 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#include -#include -#include -#include -#include "rtl_core.h" -#include "r8192E_phy.h" -#include "r8192E_phyreg.h" -#include "r8190P_rtl8256.h" -#include "r8192E_cmdpkt.h" - -#include "rtl_wx.h" -#include "rtl_dm.h" - -#include "rtl_pm.h" - -int hwwep = 1; -static char *ifname = "wlan%d"; - -static const struct pci_device_id rtl8192_pci_id_tbl[] = { - {PCI_DEVICE(0x10ec, 0x8192)}, - {PCI_DEVICE(0x07aa, 0x0044)}, - {PCI_DEVICE(0x07aa, 0x0047)}, - {} -}; - -MODULE_DEVICE_TABLE(pci, rtl8192_pci_id_tbl); - -static int _rtl92e_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id); -static void _rtl92e_pci_disconnect(struct pci_dev *pdev); -static irqreturn_t _rtl92e_irq(int irq, void *netdev); - -static SIMPLE_DEV_PM_OPS(rtl92e_pm_ops, rtl92e_suspend, rtl92e_resume); - -static struct pci_driver rtl8192_pci_driver = { - .name = DRV_NAME, /* Driver name */ - .id_table = rtl8192_pci_id_tbl, /* PCI_ID table */ - .probe = _rtl92e_pci_probe, /* probe fn */ - .remove = _rtl92e_pci_disconnect, /* remove fn */ - .driver.pm = &rtl92e_pm_ops, -}; - -static short _rtl92e_is_tx_queue_empty(struct net_device *dev); -static void _rtl92e_watchdog_wq_cb(void *data); -static void _rtl92e_watchdog_timer_cb(struct timer_list *t); -static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, - int rate); -static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void _rtl92e_tx_cmd(struct net_device *dev, struct sk_buff *skb); -static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb); -static short _rtl92e_pci_initdescring(struct net_device *dev); -static void _rtl92e_irq_tx_tasklet(struct tasklet_struct *t); -static void _rtl92e_irq_rx_tasklet(struct tasklet_struct *t); -static void _rtl92e_cancel_deferred_work(struct r8192_priv *priv); -static int _rtl92e_up(struct net_device *dev); -static int _rtl92e_try_up(struct net_device *dev); -static int _rtl92e_down(struct net_device *dev, bool shutdownrf); -static void _rtl92e_restart(void *data); - -/**************************************************************************** - * -----------------------------IO STUFF------------------------- - ****************************************************************************/ - -u8 rtl92e_readb(struct net_device *dev, int x) -{ - return 0xff & readb((u8 __iomem *)dev->mem_start + x); -} - -u32 rtl92e_readl(struct net_device *dev, int x) -{ - return readl((u8 __iomem *)dev->mem_start + x); -} - -u16 rtl92e_readw(struct net_device *dev, int x) -{ - return readw((u8 __iomem *)dev->mem_start + x); -} - -void rtl92e_writeb(struct net_device *dev, int x, u8 y) -{ - writeb(y, (u8 __iomem *)dev->mem_start + x); - - udelay(20); -} - -void rtl92e_writel(struct net_device *dev, int x, u32 y) -{ - writel(y, (u8 __iomem *)dev->mem_start + x); - - udelay(20); -} - -void rtl92e_writew(struct net_device *dev, int x, u16 y) -{ - writew(y, (u8 __iomem *)dev->mem_start + x); - - udelay(20); -} - -/**************************************************************************** - * -----------------------------GENERAL FUNCTION------------------------- - ****************************************************************************/ -bool rtl92e_set_rf_state(struct net_device *dev, - enum rt_rf_power_state state_to_set, - RT_RF_CHANGE_SOURCE change_source) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - bool action_allowed = false; - bool connect_by_ssid = false; - enum rt_rf_power_state rt_state; - u16 rf_wait_counter = 0; - unsigned long flag; - - while (true) { - spin_lock_irqsave(&priv->rf_ps_lock, flag); - if (priv->rf_change_in_progress) { - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - - while (priv->rf_change_in_progress) { - rf_wait_counter++; - mdelay(1); - - if (rf_wait_counter > 100) { - netdev_warn(dev, - "%s(): Timeout waiting for RF change.\n", - __func__); - return false; - } - } - } else { - priv->rf_change_in_progress = true; - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - break; - } - } - - rt_state = priv->rtllib->rf_power_state; - - switch (state_to_set) { - case rf_on: - priv->rtllib->rf_off_reason &= (~change_source); - - if ((change_source == RF_CHANGE_BY_HW) && priv->hw_radio_off) - priv->hw_radio_off = false; - - if (!priv->rtllib->rf_off_reason) { - priv->rtllib->rf_off_reason = 0; - action_allowed = true; - - if (rt_state == rf_off && - change_source >= RF_CHANGE_BY_HW) - connect_by_ssid = true; - } - break; - - case rf_off: - - if (priv->rtllib->iw_mode == IW_MODE_INFRA) { - if ((priv->rtllib->rf_off_reason > RF_CHANGE_BY_IPS) || - (change_source > RF_CHANGE_BY_IPS)) { - if (ieee->link_state == MAC80211_LINKED) - priv->blinked_ingpio = true; - else - priv->blinked_ingpio = false; - rtllib_mgnt_disconnect(priv->rtllib, - WLAN_REASON_DISASSOC_STA_HAS_LEFT); - } - } - if ((change_source == RF_CHANGE_BY_HW) && !priv->hw_radio_off) - priv->hw_radio_off = true; - priv->rtllib->rf_off_reason |= change_source; - action_allowed = true; - break; - - case rf_sleep: - priv->rtllib->rf_off_reason |= change_source; - action_allowed = true; - break; - - default: - break; - } - - if (action_allowed) { - rtl92e_set_rf_power_state(dev, state_to_set); - if (state_to_set == rf_on) { - if (connect_by_ssid && priv->blinked_ingpio) { - schedule_delayed_work( - &ieee->associate_procedure_wq, 0); - priv->blinked_ingpio = false; - } - } - } - - spin_lock_irqsave(&priv->rf_ps_lock, flag); - priv->rf_change_in_progress = false; - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - return action_allowed; -} - -static short _rtl92e_check_nic_enough_desc(struct net_device *dev, int prio) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; - - if (ring->entries - skb_queue_len(&ring->queue) >= 2) - return 1; - return 0; -} - -static void _rtl92e_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - schedule_work(&priv->reset_wq); - netdev_info(dev, "TXTIMEOUT"); -} - -static void _rtl92e_update_cap(struct net_device *dev, u16 cap) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_network *net = &priv->rtllib->current_network; - bool ShortPreamble; - - if (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) { - if (priv->dot11_current_preamble_mode != PREAMBLE_SHORT) { - ShortPreamble = true; - priv->dot11_current_preamble_mode = PREAMBLE_SHORT; - priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACK_PREAMBLE, - (unsigned char *)&ShortPreamble); - } - } else { - if (priv->dot11_current_preamble_mode != PREAMBLE_LONG) { - ShortPreamble = false; - priv->dot11_current_preamble_mode = PREAMBLE_LONG; - priv->rtllib->set_hw_reg_handler(dev, HW_VAR_ACK_PREAMBLE, - (unsigned char *)&ShortPreamble); - } - } - - if (net->mode & (WIRELESS_MODE_G | WIRELESS_MODE_N_24G)) { - u8 slot_time_val; - u8 cur_slot_time = priv->slot_time; - - if ((cap & WLAN_CAPABILITY_SHORT_SLOT_TIME) && - (!priv->rtllib->ht_info->current_rt2rt_long_slot_time)) { - if (cur_slot_time != SHORT_SLOT_TIME) { - slot_time_val = SHORT_SLOT_TIME; - priv->rtllib->set_hw_reg_handler(dev, - HW_VAR_SLOT_TIME, &slot_time_val); - } - } else { - if (cur_slot_time != NON_SHORT_SLOT_TIME) { - slot_time_val = NON_SHORT_SLOT_TIME; - priv->rtllib->set_hw_reg_handler(dev, - HW_VAR_SLOT_TIME, &slot_time_val); - } - } - } -} - -static const struct rtllib_qos_parameters def_qos_parameters = { - {cpu_to_le16(3), cpu_to_le16(3), cpu_to_le16(3), cpu_to_le16(3)}, - {cpu_to_le16(7), cpu_to_le16(7), cpu_to_le16(7), cpu_to_le16(7)}, - {2, 2, 2, 2}, - {0, 0, 0, 0}, - {0, 0, 0, 0} -}; - -static void _rtl92e_update_beacon(void *data) -{ - 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; - - if (ieee->ht_info->current_ht_support) - HT_update_self_and_peer_setting(ieee, net); - ieee->ht_info->current_rt2rt_long_slot_time = net->bssht.bd_rt2rt_long_slot_time; - _rtl92e_update_cap(dev, net->capability); -} - -static void _rtl92e_qos_activate(void *data) -{ - struct r8192_priv *priv = container_of(data, struct r8192_priv, qos_activate); - struct net_device *dev = priv->rtllib->dev; - int i; - - mutex_lock(&priv->mutex); - if (priv->rtllib->link_state != MAC80211_LINKED) - goto success; - - for (i = 0; i < QOS_QUEUE_NUM; i++) - priv->rtllib->set_hw_reg_handler(dev, HW_VAR_AC_PARAM, (u8 *)(&i)); - -success: - mutex_unlock(&priv->mutex); -} - -static int _rtl92e_qos_handle_probe_response(struct r8192_priv *priv, - int active_network, - struct rtllib_network *network) -{ - int ret = 0; - u32 size = sizeof(struct rtllib_qos_parameters); - - if (priv->rtllib->link_state != MAC80211_LINKED) - return ret; - - if (priv->rtllib->iw_mode != IW_MODE_INFRA) - return ret; - - if (network->flags & NETWORK_HAS_QOS_MASK) { - if (active_network && - (network->flags & NETWORK_HAS_QOS_PARAMETERS)) - network->qos_data.active = network->qos_data.supported; - - if ((network->qos_data.active == 1) && (active_network == 1) && - (network->flags & NETWORK_HAS_QOS_PARAMETERS) && - (network->qos_data.old_param_count != - network->qos_data.param_count)) { - network->qos_data.old_param_count = - network->qos_data.param_count; - priv->rtllib->wmm_acm = network->qos_data.wmm_acm; - schedule_work(&priv->qos_activate); - } - } else { - memcpy(&priv->rtllib->current_network.qos_data.parameters, - &def_qos_parameters, size); - - if ((network->qos_data.active == 1) && (active_network == 1)) - schedule_work(&priv->qos_activate); - - network->qos_data.active = 0; - network->qos_data.supported = 0; - } - - return 0; -} - -static int _rtl92e_handle_beacon(struct net_device *dev, - struct rtllib_beacon *beacon, - struct rtllib_network *network) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - _rtl92e_qos_handle_probe_response(priv, 1, network); - - schedule_delayed_work(&priv->update_beacon_wq, 0); - return 0; -} - -static int _rtl92e_qos_assoc_resp(struct r8192_priv *priv, - struct rtllib_network *network) -{ - unsigned long flags; - u32 size = sizeof(struct rtllib_qos_parameters); - int set_qos_param = 0; - - if (!priv || !network) - return 0; - - if (priv->rtllib->link_state != MAC80211_LINKED) - return 0; - - if (priv->rtllib->iw_mode != IW_MODE_INFRA) - return 0; - - spin_lock_irqsave(&priv->rtllib->lock, flags); - if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { - memcpy(&priv->rtllib->current_network.qos_data.parameters, - &network->qos_data.parameters, - sizeof(struct rtllib_qos_parameters)); - priv->rtllib->current_network.qos_data.active = 1; - priv->rtllib->wmm_acm = network->qos_data.wmm_acm; - set_qos_param = 1; - priv->rtllib->current_network.qos_data.old_param_count = - priv->rtllib->current_network.qos_data.param_count; - priv->rtllib->current_network.qos_data.param_count = - network->qos_data.param_count; - } else { - memcpy(&priv->rtllib->current_network.qos_data.parameters, - &def_qos_parameters, size); - priv->rtllib->current_network.qos_data.active = 0; - priv->rtllib->current_network.qos_data.supported = 0; - set_qos_param = 1; - } - - spin_unlock_irqrestore(&priv->rtllib->lock, flags); - - if (set_qos_param == 1) { - rtl92e_dm_init_edca_turbo(priv->rtllib->dev); - schedule_work(&priv->qos_activate); - } - return 0; -} - -static int _rtl92e_handle_assoc_response(struct net_device *dev, - struct rtllib_assoc_response_frame *resp, - struct rtllib_network *network) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - _rtl92e_qos_assoc_resp(priv, network); - return 0; -} - -void rtl92e_config_rate(struct net_device *dev, u16 *rate_config) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_network *net; - u8 i = 0, basic_rate = 0; - - net = &priv->rtllib->current_network; - - for (i = 0; i < net->rates_len; i++) { - basic_rate = net->rates[i] & 0x7f; - switch (basic_rate) { - case MGN_1M: - *rate_config |= RRSR_1M; - break; - case MGN_2M: - *rate_config |= RRSR_2M; - break; - case MGN_5_5M: - *rate_config |= RRSR_5_5M; - break; - case MGN_11M: - *rate_config |= RRSR_11M; - break; - case MGN_6M: - *rate_config |= RRSR_6M; - break; - case MGN_9M: - *rate_config |= RRSR_9M; - break; - case MGN_12M: - *rate_config |= RRSR_12M; - break; - case MGN_18M: - *rate_config |= RRSR_18M; - break; - case MGN_24M: - *rate_config |= RRSR_24M; - break; - case MGN_36M: - *rate_config |= RRSR_36M; - break; - case MGN_48M: - *rate_config |= RRSR_48M; - break; - case MGN_54M: - *rate_config |= RRSR_54M; - break; - } - } - - for (i = 0; i < net->rates_ex_len; i++) { - basic_rate = net->rates_ex[i] & 0x7f; - switch (basic_rate) { - case MGN_1M: - *rate_config |= RRSR_1M; - break; - case MGN_2M: - *rate_config |= RRSR_2M; - break; - case MGN_5_5M: - *rate_config |= RRSR_5_5M; - break; - case MGN_11M: - *rate_config |= RRSR_11M; - break; - case MGN_6M: - *rate_config |= RRSR_6M; - break; - case MGN_9M: - *rate_config |= RRSR_9M; - break; - case MGN_12M: - *rate_config |= RRSR_12M; - break; - case MGN_18M: - *rate_config |= RRSR_18M; - break; - case MGN_24M: - *rate_config |= RRSR_24M; - break; - case MGN_36M: - *rate_config |= RRSR_36M; - break; - case MGN_48M: - *rate_config |= RRSR_48M; - break; - case MGN_54M: - *rate_config |= RRSR_54M; - break; - } - } -} - -static void _rtl92e_refresh_support_rate(struct r8192_priv *priv) -{ - struct rtllib_device *ieee = priv->rtllib; - - 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, - ieee->reg_ht_supp_rate_set, 16); - - } else { - memset(ieee->reg_dot11ht_oper_rate_set, 0, 16); - } -} - -void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode) -{ - struct r8192_priv *priv = rtllib_priv(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)) - wireless_mode = WIRELESS_MODE_N_24G; - - if ((wireless_mode & (WIRELESS_MODE_B | WIRELESS_MODE_G)) == - (WIRELESS_MODE_G | WIRELESS_MODE_B)) - wireless_mode = WIRELESS_MODE_G; - - priv->rtllib->mode = wireless_mode; - - if (wireless_mode == WIRELESS_MODE_N_24G) - priv->rtllib->ht_info->enable_ht = 1; - else - priv->rtllib->ht_info->enable_ht = 0; - - _rtl92e_refresh_support_rate(priv); -} - -static int _rtl92e_sta_up(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - (&priv->rtllib->pwr_save_ctrl); - bool init_status; - - priv->up = 1; - priv->rtllib->ieee_up = 1; - - priv->up_first_time = 0; - init_status = rtl92e_start_adapter(dev); - if (!init_status) { - netdev_err(dev, "%s(): Initialization failed!\n", __func__); - return -1; - } - - RT_CLEAR_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC); - - if (priv->polling_timer_on == 0) - rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer); - - if (priv->rtllib->link_state != MAC80211_LINKED) - rtllib_softmac_start_protocol(priv->rtllib); - rtllib_reset_queue(priv->rtllib); - _rtl92e_watchdog_timer_cb(&priv->watch_dog_timer); - - if (!netif_queue_stopped(dev)) - netif_start_queue(dev); - else - netif_wake_queue(dev); - - priv->bfirst_after_down = false; - return 0; -} - -static int _rtl92e_sta_down(struct net_device *dev, bool shutdownrf) -{ - struct r8192_priv *priv = rtllib_priv(dev); - unsigned long flags = 0; - u8 rf_in_progress_timeout = 0; - - if (priv->up == 0) - return -1; - - priv->rtllib->rtllib_ips_leave(dev); - - if (priv->rtllib->link_state == MAC80211_LINKED) - rtl92e_leisure_ps_leave(dev); - - priv->up = 0; - priv->rtllib->ieee_up = 0; - priv->bfirst_after_down = true; - if (!netif_queue_stopped(dev)) - netif_stop_queue(dev); - - priv->rtllib->wpa_ie_len = 0; - kfree(priv->rtllib->wpa_ie); - priv->rtllib->wpa_ie = NULL; - rtl92e_cam_reset(dev); - memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); - rtl92e_irq_disable(dev); - - del_timer_sync(&priv->watch_dog_timer); - _rtl92e_cancel_deferred_work(priv); - cancel_delayed_work(&priv->rtllib->hw_wakeup_wq); - - rtllib_softmac_stop_protocol(priv->rtllib); - spin_lock_irqsave(&priv->rf_ps_lock, flags); - while (priv->rf_change_in_progress) { - spin_unlock_irqrestore(&priv->rf_ps_lock, flags); - if (rf_in_progress_timeout > 100) { - spin_lock_irqsave(&priv->rf_ps_lock, flags); - break; - } - mdelay(1); - rf_in_progress_timeout++; - spin_lock_irqsave(&priv->rf_ps_lock, flags); - } - priv->rf_change_in_progress = true; - spin_unlock_irqrestore(&priv->rf_ps_lock, flags); - 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); - udelay(100); - memset(&priv->rtllib->current_network, 0, - offsetof(struct rtllib_network, list)); - - return 0; -} - -static void _rtl92e_init_priv_handler(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->rtllib->softmac_hard_start_xmit = _rtl92e_hard_start_xmit; - priv->rtllib->set_chan = rtl92e_set_channel; - 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; - priv->rtllib->handle_beacon = _rtl92e_handle_beacon; - priv->rtllib->set_wireless_mode = rtl92e_set_wireless_mode; - priv->rtllib->leisure_ps_leave = rtl92e_leisure_ps_leave; - priv->rtllib->set_bw_mode_handler = rtl92e_set_bw_mode; - - priv->rtllib->sta_wake_up = rtl92e_hw_wakeup; - priv->rtllib->enter_sleep_state = rtl92e_enter_sleep; - priv->rtllib->ps_is_queue_empty = _rtl92e_is_tx_queue_empty; - - priv->rtllib->get_nmode_support_by_sec_cfg = rtl92e_get_nmode_support_by_sec; - priv->rtllib->get_half_nmode_support_by_aps_handler = - rtl92e_is_halfn_supported_by_ap; - - priv->rtllib->set_hw_reg_handler = rtl92e_set_reg; - priv->rtllib->allow_all_dest_addr_handler = rtl92e_set_monitor_mode; - priv->rtllib->init_gain_handler = rtl92e_init_gain; - priv->rtllib->rtllib_ips_leave_wq = rtl92e_rtllib_ips_leave_wq; - priv->rtllib->rtllib_ips_leave = rtl92e_rtllib_ips_leave; - priv->rtllib->scan_operation_backup_handler = rtl92e_scan_op_backup; -} - -static void _rtl92e_init_priv_variable(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 i; - - priv->dot11_current_preamble_mode = PREAMBLE_AUTO; - priv->rtllib->status = 0; - priv->polling_timer_on = 0; - priv->up_first_time = 1; - priv->blinked_ingpio = false; - priv->being_init_adapter = false; - priv->txringcount = 64; - priv->rxbuffersize = 9100; - priv->rxringcount = MAX_RX_COUNT; - priv->irq_enabled = 0; - priv->chan = 1; - priv->rtllib->mode = WIRELESS_MODE_AUTO; - priv->rtllib->iw_mode = IW_MODE_INFRA; - priv->rtllib->ieee_up = 0; - priv->retry_rts = DEFAULT_RETRY_RTS; - priv->retry_data = DEFAULT_RETRY_DATA; - priv->rtllib->rts = DEFAULT_RTS_THRESHOLD; - priv->rtllib->rate = 110; - priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; - priv->bcck_in_ch14 = false; - priv->cck_present_attn = 0; - priv->rfa_txpowertrackingindex = 0; - priv->cck_pwr_enl = 6; - memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); - priv->rx_ctr = 0; - priv->rtllib->wx_set_enc = 0; - priv->hw_radio_off = false; - priv->rtllib->rf_off_reason = 0; - priv->rf_change_in_progress = false; - priv->hw_rf_off_action = 0; - priv->set_rf_pwr_state_in_progress = false; - priv->rtllib->pwr_save_ctrl.bLeisurePs = true; - priv->rtllib->lps_delay_cnt = 0; - priv->rtllib->sta_sleep = LPS_IS_WAKE; - priv->rtllib->rf_power_state = rf_on; - - priv->rtllib->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; - priv->rtllib->iw_mode = IW_MODE_INFRA; - priv->rtllib->be_scan_inprogress = false; - - priv->rtllib->fts = DEFAULT_FRAG_THRESHOLD; - - priv->fw_info = vzalloc(sizeof(struct rt_firmware)); - if (!priv->fw_info) - netdev_err(dev, - "rtl8192e: Unable to allocate space for firmware\n"); - - skb_queue_head_init(&priv->skb_queue); - - for (i = 0; i < MAX_QUEUE_SIZE; i++) - skb_queue_head_init(&priv->rtllib->skb_waitq[i]); -} - -static void _rtl92e_init_priv_lock(struct r8192_priv *priv) -{ - spin_lock_init(&priv->tx_lock); - spin_lock_init(&priv->irq_th_lock); - spin_lock_init(&priv->rf_ps_lock); - spin_lock_init(&priv->ps_lock); - mutex_init(&priv->wx_mutex); - mutex_init(&priv->rf_mutex); - mutex_init(&priv->mutex); -} - -static void _rtl92e_init_priv_task(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(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); -} - -static short _rtl92e_get_channel_map(struct net_device *dev) -{ - int i; - - struct r8192_priv *priv = rtllib_priv(dev); - - for (i = 1; i <= 11; i++) - (priv->rtllib->active_channel_map)[i] = 1; - (priv->rtllib->active_channel_map)[12] = 2; - (priv->rtllib->active_channel_map)[13] = 2; - - return 0; -} - -static short _rtl92e_init(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - memset(&priv->stats, 0, sizeof(struct rt_stats)); - - _rtl92e_init_priv_handler(dev); - _rtl92e_init_priv_variable(dev); - _rtl92e_init_priv_lock(priv); - _rtl92e_init_priv_task(dev); - rtl92e_get_eeprom_size(dev); - rtl92e_init_variables(dev); - _rtl92e_get_channel_map(dev); - - rtl92e_dm_init(dev); - - timer_setup(&priv->watch_dog_timer, _rtl92e_watchdog_timer_cb, 0); - - timer_setup(&priv->gpio_polling_timer, rtl92e_check_rfctrl_gpio_timer, - 0); - - rtl92e_irq_disable(dev); - if (request_irq(dev->irq, _rtl92e_irq, IRQF_SHARED, dev->name, dev)) { - netdev_err(dev, "Error allocating IRQ %d", dev->irq); - return -1; - } - - priv->irq = dev->irq; - - if (_rtl92e_pci_initdescring(dev) != 0) { - netdev_err(dev, "Endopoints initialization failed"); - free_irq(dev->irq, dev); - return -1; - } - - return 0; -} - -/*************************************************************************** - * -------------------------------WATCHDOG STUFF--------------------------- - **************************************************************************/ -static short _rtl92e_is_tx_queue_empty(struct net_device *dev) -{ - int i = 0; - struct r8192_priv *priv = rtllib_priv(dev); - - for (i = 0; i <= MGNT_QUEUE; i++) { - if ((i == TXCMD_QUEUE) || (i == HCCA_QUEUE)) - continue; - if (skb_queue_len(&(&priv->tx_ring[i])->queue) > 0) { - netdev_info(dev, "===>tx queue is not empty:%d, %d\n", - i, skb_queue_len(&(&priv->tx_ring[i])->queue)); - return 0; - } - } - return 1; -} - -static enum reset_type _rtl92e_tx_check_stuck(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 QueueID; - bool bCheckFwTxCnt = false; - struct rtl8192_tx_ring *ring = NULL; - struct sk_buff *skb = NULL; - struct cb_desc *tcb_desc = NULL; - unsigned long flags = 0; - - switch (priv->rtllib->ps) { - case RTLLIB_PS_DISABLED: - break; - case (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST): - break; - default: - break; - } - spin_lock_irqsave(&priv->irq_th_lock, flags); - for (QueueID = 0; QueueID < MAX_TX_QUEUE; QueueID++) { - if (QueueID == TXCMD_QUEUE) - continue; - - if (QueueID == BEACON_QUEUE) - continue; - - ring = &priv->tx_ring[QueueID]; - - if (skb_queue_len(&ring->queue) == 0) { - continue; - } else { - skb = __skb_peek(&ring->queue); - tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - tcb_desc->stuck_count++; - bCheckFwTxCnt = true; - if (tcb_desc->stuck_count > 1) - netdev_info(dev, - "%s: QueueID=%d tcb_desc->stuck_count=%d\n", - __func__, QueueID, - tcb_desc->stuck_count); - } - } - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - - if (bCheckFwTxCnt) { - if (rtl92e_is_tx_stuck(dev)) - return RESET_TYPE_SILENT; - } - - return RESET_TYPE_NORESET; -} - -static enum reset_type _rtl92e_rx_check_stuck(struct net_device *dev) -{ - if (rtl92e_is_rx_stuck(dev)) - return RESET_TYPE_SILENT; - - return RESET_TYPE_NORESET; -} - -static void _rtl92e_if_check_reset(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - enum reset_type TxResetType = RESET_TYPE_NORESET; - enum reset_type RxResetType = RESET_TYPE_NORESET; - enum rt_rf_power_state rfState; - - rfState = priv->rtllib->rf_power_state; - - if (rfState == rf_on) - TxResetType = _rtl92e_tx_check_stuck(dev); - - if (rfState == rf_on && - (priv->rtllib->iw_mode == IW_MODE_INFRA) && - (priv->rtllib->link_state == MAC80211_LINKED)) - RxResetType = _rtl92e_rx_check_stuck(dev); - - if (TxResetType == RESET_TYPE_SILENT || - RxResetType == RESET_TYPE_SILENT) { - netdev_info(dev, "%s(): TxResetType is %d, RxResetType is %d\n", - __func__, TxResetType, RxResetType); - } -} - -static void _rtl92e_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum, - u32 *TotalRxDataNum) -{ - u16 slot_index; - u8 i; - - *TotalRxBcnNum = 0; - *TotalRxDataNum = 0; - - slot_index = (priv->rtllib->link_detect_info.slot_index++) % - (priv->rtllib->link_detect_info.slot_num); - priv->rtllib->link_detect_info.RxBcnNum[slot_index] = - priv->rtllib->link_detect_info.num_recv_bcn_in_period; - priv->rtllib->link_detect_info.RxDataNum[slot_index] = - priv->rtllib->link_detect_info.num_recv_data_in_period; - for (i = 0; i < priv->rtllib->link_detect_info.slot_num; i++) { - *TotalRxBcnNum += priv->rtllib->link_detect_info.RxBcnNum[i]; - *TotalRxDataNum += priv->rtllib->link_detect_info.RxDataNum[i]; - } -} - -static void _rtl92e_watchdog_wq_cb(void *data) -{ - struct r8192_priv *priv = container_of_dwork_rsl(data, - struct r8192_priv, watch_dog_wq); - struct net_device *dev = priv->rtllib->dev; - struct rtllib_device *ieee = priv->rtllib; - static u8 check_reset_cnt; - unsigned long flags; - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - (&priv->rtllib->pwr_save_ctrl); - bool busy_traffic = false; - bool bHigherBusyTraffic = false; - bool bHigherBusyRxTraffic = false; - bool bEnterPS = false; - - if (!priv->up || priv->hw_radio_off) - return; - - if (priv->rtllib->link_state >= MAC80211_LINKED) { - if (priv->rtllib->cnt_after_link < 2) - priv->rtllib->cnt_after_link++; - } else { - priv->rtllib->cnt_after_link = 0; - } - - rtl92e_dm_watchdog(dev); - - if (!rtllib_act_scanning(priv->rtllib, false)) { - if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->link_state == - MAC80211_NOLINK) && - (ieee->rf_power_state == rf_on) && !ieee->is_set_key && - (!ieee->proto_stoppping) && !ieee->wx_set_enc) { - if (ieee->pwr_save_ctrl.return_point == IPS_CALLBACK_NONE) - rtl92e_ips_enter(dev); - } - } - if ((ieee->link_state == MAC80211_LINKED) && (ieee->iw_mode == IW_MODE_INFRA)) { - if (ieee->link_detect_info.num_rx_ok_in_period > 100 || - ieee->link_detect_info.num_tx_ok_in_period > 100) - busy_traffic = true; - - if (ieee->link_detect_info.num_rx_ok_in_period > 4000 || - ieee->link_detect_info.num_tx_ok_in_period > 4000) { - bHigherBusyTraffic = true; - if (ieee->link_detect_info.num_rx_ok_in_period > 5000) - bHigherBusyRxTraffic = true; - else - bHigherBusyRxTraffic = false; - } - - if (((ieee->link_detect_info.num_rx_unicast_ok_in_period + - ieee->link_detect_info.num_tx_ok_in_period) > 8) || - (ieee->link_detect_info.num_rx_unicast_ok_in_period > 2)) - bEnterPS = false; - else - bEnterPS = true; - - if (ieee->current_network.beacon_interval < 95) - bEnterPS = false; - - if (bEnterPS) - rtl92e_leisure_ps_enter(dev); - else - rtl92e_leisure_ps_leave(dev); - - } else { - rtl92e_leisure_ps_leave(dev); - } - - ieee->link_detect_info.num_rx_ok_in_period = 0; - ieee->link_detect_info.num_tx_ok_in_period = 0; - ieee->link_detect_info.num_rx_unicast_ok_in_period = 0; - ieee->link_detect_info.busy_traffic = busy_traffic; - - ieee->link_detect_info.bHigherBusyTraffic = bHigherBusyTraffic; - ieee->link_detect_info.bHigherBusyRxTraffic = bHigherBusyRxTraffic; - - if (ieee->link_state == MAC80211_LINKED && ieee->iw_mode == IW_MODE_INFRA) { - u32 TotalRxBcnNum = 0; - u32 TotalRxDataNum = 0; - - _rtl92e_update_rxcounts(priv, &TotalRxBcnNum, &TotalRxDataNum); - - if ((TotalRxBcnNum + TotalRxDataNum) == 0) - priv->check_roaming_cnt++; - else - priv->check_roaming_cnt = 0; - - if (priv->check_roaming_cnt > 0) { - if (ieee->rf_power_state == rf_off) - netdev_info(dev, "%s(): RF is off\n", __func__); - - netdev_info(dev, - "===>%s(): AP is power off, chan:%d, connect another one\n", - __func__, priv->chan); - - ieee->link_state = RTLLIB_ASSOCIATING; - - remove_peer_ts(priv->rtllib, - priv->rtllib->current_network.bssid); - ieee->is_roaming = true; - ieee->is_set_key = false; - ieee->link_change(dev); - notify_wx_assoc_event(ieee); - - if (!(ieee->rtllib_ap_sec_type(ieee) & - (SEC_ALG_CCMP | SEC_ALG_TKIP))) - schedule_delayed_work( - &ieee->associate_procedure_wq, 0); - - priv->check_roaming_cnt = 0; - } - ieee->link_detect_info.num_recv_bcn_in_period = 0; - ieee->link_detect_info.num_recv_data_in_period = 0; - } - - spin_lock_irqsave(&priv->tx_lock, flags); - if ((check_reset_cnt++ >= 3) && (!ieee->is_roaming) && - (!priv->rf_change_in_progress) && (!psc->bSwRfProcessing)) { - _rtl92e_if_check_reset(dev); - check_reset_cnt = 3; - } - spin_unlock_irqrestore(&priv->tx_lock, flags); -} - -static void _rtl92e_watchdog_timer_cb(struct timer_list *t) -{ - struct r8192_priv *priv = from_timer(priv, t, watch_dog_timer); - - schedule_delayed_work(&priv->watch_dog_wq, 0); - mod_timer(&priv->watch_dog_timer, jiffies + - msecs_to_jiffies(RTLLIB_WATCH_DOG_TIME)); -} - -/**************************************************************************** - * ---------------------------- NIC TX/RX STUFF--------------------------- - ****************************************************************************/ -void rtl92e_rx_enable(struct net_device *dev) -{ - rtl92e_enable_rx(dev); -} - -void rtl92e_tx_enable(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - rtl92e_enable_tx(dev); - - rtllib_reset_queue(priv->rtllib); -} - -static void _rtl92e_free_rx_ring(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int i; - - for (i = 0; i < priv->rxringcount; i++) { - struct sk_buff *skb = priv->rx_buf[i]; - - if (!skb) - continue; - - dma_unmap_single(&priv->pdev->dev, - *((dma_addr_t *)skb->cb), - priv->rxbuffersize, DMA_FROM_DEVICE); - kfree_skb(skb); - } - - dma_free_coherent(&priv->pdev->dev, - sizeof(*priv->rx_ring) * priv->rxringcount, - priv->rx_ring, - priv->rx_ring_dma); - priv->rx_ring = NULL; -} - -static void _rtl92e_free_tx_ring(struct net_device *dev, unsigned int prio) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; - - while (skb_queue_len(&ring->queue)) { - struct tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb = __skb_dequeue(&ring->queue); - - dma_unmap_single(&priv->pdev->dev, entry->TxBuffAddr, - skb->len, DMA_TO_DEVICE); - kfree_skb(skb); - ring->idx = (ring->idx + 1) % ring->entries; - } - - dma_free_coherent(&priv->pdev->dev, - sizeof(*ring->desc) * ring->entries, ring->desc, - ring->dma); - ring->desc = NULL; -} - -static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, - int rate) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int ret; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - u8 queue_index = tcb_desc->queue_index; - - if ((priv->rtllib->rf_power_state == rf_off) || !priv->up) { - kfree_skb(skb); - return; - } - - if (queue_index == TXCMD_QUEUE) - netdev_warn(dev, "%s(): queue index == TXCMD_QUEUE\n", - __func__); - - memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); - skb_push(skb, priv->rtllib->tx_headroom); - ret = _rtl92e_tx(dev, skb); - - if (queue_index != MGNT_QUEUE) { - priv->rtllib->stats.tx_bytes += (skb->len - - priv->rtllib->tx_headroom); - priv->rtllib->stats.tx_packets++; - } - - if (ret != 0) - kfree_skb(skb); -} - -static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int ret; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - u8 queue_index = tcb_desc->queue_index; - - if (queue_index != TXCMD_QUEUE) { - if ((priv->rtllib->rf_power_state == rf_off) || - !priv->up) { - kfree_skb(skb); - return 0; - } - } - - memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); - if (queue_index == TXCMD_QUEUE) { - _rtl92e_tx_cmd(dev, skb); - return 0; - } - - tcb_desc->ratr_index = 7; - tcb_desc->tx_dis_rate_fallback = 1; - tcb_desc->tx_use_drv_assinged_rate = 1; - tcb_desc->tx_enable_fw_calc_dur = 1; - skb_push(skb, priv->rtllib->tx_headroom); - ret = _rtl92e_tx(dev, skb); - if (ret != 0) - kfree_skb(skb); - return ret; -} - -static void _rtl92e_tx_isr(struct net_device *dev, int prio) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - struct rtl8192_tx_ring *ring = &priv->tx_ring[prio]; - - while (skb_queue_len(&ring->queue)) { - struct tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb; - - if (prio != BEACON_QUEUE) { - if (entry->OWN) - return; - ring->idx = (ring->idx + 1) % ring->entries; - } - - skb = __skb_dequeue(&ring->queue); - dma_unmap_single(&priv->pdev->dev, entry->TxBuffAddr, - skb->len, DMA_TO_DEVICE); - - kfree_skb(skb); - } - if (prio != BEACON_QUEUE) - tasklet_schedule(&priv->irq_tx_tasklet); -} - -static void _rtl92e_tx_cmd(struct net_device *dev, struct sk_buff *skb) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtl8192_tx_ring *ring; - struct tx_desc_cmd *entry; - unsigned int idx; - struct cb_desc *tcb_desc; - unsigned long flags; - - spin_lock_irqsave(&priv->irq_th_lock, flags); - ring = &priv->tx_ring[TXCMD_QUEUE]; - - idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; - entry = (struct tx_desc_cmd *)&ring->desc[idx]; - - tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); - - rtl92e_fill_tx_cmd_desc(dev, entry, tcb_desc, skb); - - __skb_queue_tail(&ring->queue, skb); - spin_unlock_irqrestore(&priv->irq_th_lock, flags); -} - -static short _rtl92e_tx(struct net_device *dev, struct sk_buff *skb) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtl8192_tx_ring *ring; - unsigned long flags; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - struct tx_desc *pdesc = NULL; - struct ieee80211_hdr *header = NULL; - u8 *pda_addr = NULL; - int idx; - u32 fwinfo_size = 0; - - priv->rtllib->awake_pkt_sent = true; - - fwinfo_size = sizeof(struct tx_fwinfo_8190pci); - - header = (struct ieee80211_hdr *)(((u8 *)skb->data) + fwinfo_size); - pda_addr = header->addr1; - - if (!is_broadcast_ether_addr(pda_addr) && !is_multicast_ether_addr(pda_addr)) - priv->stats.txbytesunicast += skb->len - fwinfo_size; - - spin_lock_irqsave(&priv->irq_th_lock, flags); - ring = &priv->tx_ring[tcb_desc->queue_index]; - if (tcb_desc->queue_index != BEACON_QUEUE) - idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; - else - idx = 0; - - pdesc = &ring->desc[idx]; - if ((pdesc->OWN == 1) && (tcb_desc->queue_index != BEACON_QUEUE)) { - netdev_warn(dev, - "No more TX desc@%d, ring->idx = %d, idx = %d, skblen = 0x%x queuelen=%d", - tcb_desc->queue_index, ring->idx, idx, skb->len, - skb_queue_len(&ring->queue)); - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - return skb->len; - } - 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); - netif_trans_update(dev); - - rtl92e_writew(dev, TP_POLL, 0x01 << tcb_desc->queue_index); - return 0; -} - -static short _rtl92e_alloc_rx_ring(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rx_desc *entry = NULL; - int i; - - priv->rx_ring = dma_alloc_coherent(&priv->pdev->dev, - sizeof(*priv->rx_ring) * priv->rxringcount, - &priv->rx_ring_dma, - GFP_ATOMIC); - if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { - netdev_warn(dev, "Cannot allocate RX ring\n"); - return -ENOMEM; - } - - priv->rx_idx = 0; - - for (i = 0; i < priv->rxringcount; i++) { - struct sk_buff *skb = dev_alloc_skb(priv->rxbuffersize); - dma_addr_t *mapping; - - entry = &priv->rx_ring[i]; - if (!skb) - return 0; - skb->dev = dev; - priv->rx_buf[i] = skb; - mapping = (dma_addr_t *)skb->cb; - *mapping = dma_map_single(&priv->pdev->dev, - skb_tail_pointer(skb), - priv->rxbuffersize, DMA_FROM_DEVICE); - if (dma_mapping_error(&priv->pdev->dev, *mapping)) { - dev_kfree_skb_any(skb); - return -1; - } - entry->BufferAddress = *mapping; - - entry->Length = priv->rxbuffersize; - entry->OWN = 1; - } - - if (entry) - entry->EOR = 1; - return 0; -} - -static int _rtl92e_alloc_tx_ring(struct net_device *dev, unsigned int prio, - unsigned int entries) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct tx_desc *ring; - dma_addr_t dma; - int i; - - ring = dma_alloc_coherent(&priv->pdev->dev, sizeof(*ring) * entries, - &dma, GFP_ATOMIC); - if (!ring || (unsigned long)ring & 0xFF) { - netdev_warn(dev, "Cannot allocate TX ring (prio = %d)\n", prio); - return -ENOMEM; - } - - priv->tx_ring[prio].desc = ring; - priv->tx_ring[prio].dma = dma; - priv->tx_ring[prio].idx = 0; - priv->tx_ring[prio].entries = entries; - skb_queue_head_init(&priv->tx_ring[prio].queue); - - for (i = 0; i < entries; i++) - ring[i].NextDescAddress = - (u32)dma + ((i + 1) % entries) * - sizeof(*ring); - - return 0; -} - -static short _rtl92e_pci_initdescring(struct net_device *dev) -{ - u32 ret; - int i; - struct r8192_priv *priv = rtllib_priv(dev); - - ret = _rtl92e_alloc_rx_ring(dev); - if (ret) - return ret; - - for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { - ret = _rtl92e_alloc_tx_ring(dev, i, priv->txringcount); - if (ret) - goto err_free_rings; - } - - return 0; - -err_free_rings: - _rtl92e_free_rx_ring(dev); - for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) - if (priv->tx_ring[i].desc) - _rtl92e_free_tx_ring(dev, i); - return 1; -} - -void rtl92e_reset_desc_ring(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int i; - unsigned long flags = 0; - - if (priv->rx_ring) { - struct rx_desc *entry = NULL; - - for (i = 0; i < priv->rxringcount; i++) { - entry = &priv->rx_ring[i]; - entry->OWN = 1; - } - priv->rx_idx = 0; - } - - spin_lock_irqsave(&priv->irq_th_lock, flags); - for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) { - if (priv->tx_ring[i].desc) { - struct rtl8192_tx_ring *ring = &priv->tx_ring[i]; - - while (skb_queue_len(&ring->queue)) { - struct tx_desc *entry = &ring->desc[ring->idx]; - struct sk_buff *skb = - __skb_dequeue(&ring->queue); - - dma_unmap_single(&priv->pdev->dev, - entry->TxBuffAddr, skb->len, - DMA_TO_DEVICE); - kfree_skb(skb); - ring->idx = (ring->idx + 1) % ring->entries; - } - ring->idx = 0; - } - } - spin_unlock_irqrestore(&priv->irq_th_lock, flags); -} - -long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index) -{ - long signal_power; - - signal_power = (long)((signal_strength_index + 1) >> 1); - signal_power -= 95; - - return signal_power; -} - -void rtl92e_update_rx_statistics(struct r8192_priv *priv, - struct rtllib_rx_stats *pprevious_stats) -{ - int weighting = 0; - - if (priv->stats.recv_signal_power == 0) - priv->stats.recv_signal_power = - pprevious_stats->RecvSignalPower; - - if (pprevious_stats->RecvSignalPower > priv->stats.recv_signal_power) - weighting = 5; - else if (pprevious_stats->RecvSignalPower < - priv->stats.recv_signal_power) - weighting = (-5); - priv->stats.recv_signal_power = (priv->stats.recv_signal_power * 5 + - pprevious_stats->RecvSignalPower + - weighting) / 6; -} - -u8 rtl92e_rx_db_to_percent(s8 antpower) -{ - if ((antpower <= -100) || (antpower >= 20)) - return 0; - else if (antpower >= 0) - return 100; - else - return 100 + antpower; - -} /* QueryRxPwrPercentage */ - -u8 rtl92e_evm_db_to_percent(s8 value) -{ - s8 ret_val = clamp(-value, 0, 33) * 3; - - if (ret_val == 99) - ret_val = 100; - - return ret_val; -} - -void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats, - struct rtllib_rx_stats *ptarget_stats) -{ - ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU; - ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU; -} - -static void _rtl92e_rx_normal(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct ieee80211_hdr *rtllib_hdr = NULL; - bool unicast_packet = false; - u32 skb_len = 0; - - struct rtllib_rx_stats stats = { - .signal = 0, - .noise = (u8)-98, - .rate = 0, - }; - unsigned int count = priv->rxringcount; - - while (count--) { - struct rx_desc *pdesc = &priv->rx_ring - [priv->rx_idx]; - struct sk_buff *skb = priv->rx_buf - [priv->rx_idx]; - struct sk_buff *new_skb; - - if (pdesc->OWN) - return; - 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 - * and reuse skb - */ - if (unlikely(!new_skb)) - goto done; - - dma_unmap_single(&priv->pdev->dev, *((dma_addr_t *)skb->cb), - priv->rxbuffersize, DMA_FROM_DEVICE); - - skb_put(skb, pdesc->Length); - skb_reserve(skb, stats.rx_drv_info_size + - stats.rx_buf_shift); - skb_trim(skb, skb->len - S_CRC_LEN); - rtllib_hdr = (struct ieee80211_hdr *)skb->data; - if (!is_multicast_ether_addr(rtllib_hdr->addr1)) { - /* unicast packet */ - unicast_packet = true; - } - skb_len = skb->len; - - if (!rtllib_rx(priv->rtllib, skb, &stats)) { - dev_kfree_skb_any(skb); - } else { - if (unicast_packet) - priv->stats.rxbytesunicast += skb_len; - } - - skb = new_skb; - skb->dev = dev; - - priv->rx_buf[priv->rx_idx] = skb; - *((dma_addr_t *)skb->cb) = dma_map_single(&priv->pdev->dev, - 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); - return; - } -done: - pdesc->BufferAddress = *((dma_addr_t *)skb->cb); - pdesc->OWN = 1; - pdesc->Length = priv->rxbuffersize; - if (priv->rx_idx == priv->rxringcount - 1) - pdesc->EOR = 1; - priv->rx_idx = (priv->rx_idx + 1) % - priv->rxringcount; - } -} - -static void _rtl92e_tx_resume(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - struct sk_buff *skb; - int queue_index; - - for (queue_index = BK_QUEUE; - queue_index < MAX_QUEUE_SIZE; queue_index++) { - while ((!skb_queue_empty(&ieee->skb_waitq[queue_index])) && - (priv->rtllib->check_nic_enough_desc(dev, queue_index) > 0)) { - skb = skb_dequeue(&ieee->skb_waitq[queue_index]); - ieee->softmac_data_hard_start_xmit(skb, dev, 0); - } - } -} - -static void _rtl92e_irq_tx_tasklet(struct tasklet_struct *t) -{ - struct r8192_priv *priv = from_tasklet(priv, t, irq_tx_tasklet); - - _rtl92e_tx_resume(priv->rtllib->dev); -} - -static void _rtl92e_irq_rx_tasklet(struct tasklet_struct *t) -{ - struct r8192_priv *priv = from_tasklet(priv, t, irq_rx_tasklet); - - _rtl92e_rx_normal(priv->rtllib->dev); - - rtl92e_writel(priv->rtllib->dev, INTA_MASK, - rtl92e_readl(priv->rtllib->dev, INTA_MASK) | IMR_RDU); -} - -/**************************************************************************** - * ---------------------------- NIC START/CLOSE STUFF--------------------------- - ****************************************************************************/ -static void _rtl92e_cancel_deferred_work(struct r8192_priv *priv) -{ - cancel_delayed_work_sync(&priv->watch_dog_wq); - cancel_delayed_work_sync(&priv->update_beacon_wq); - cancel_delayed_work(&priv->rtllib->hw_sleep_wq); - cancel_work_sync(&priv->reset_wq); - cancel_work_sync(&priv->qos_activate); -} - -static int _rtl92e_up(struct net_device *dev) -{ - if (_rtl92e_sta_up(dev) == -1) - return -1; - return 0; -} - -static int _rtl92e_open(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int ret; - - mutex_lock(&priv->wx_mutex); - ret = _rtl92e_try_up(dev); - mutex_unlock(&priv->wx_mutex); - return ret; -} - -static int _rtl92e_try_up(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->up == 1) - return -1; - return _rtl92e_up(dev); -} - -static int _rtl92e_close(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int ret; - - if ((rtllib_act_scanning(priv->rtllib, false)) && - !(priv->rtllib->softmac_features & IEEE_SOFTMAC_SCAN)) { - rtllib_stop_scan(priv->rtllib); - } - - mutex_lock(&priv->wx_mutex); - - ret = _rtl92e_down(dev, true); - - mutex_unlock(&priv->wx_mutex); - - return ret; -} - -static int _rtl92e_down(struct net_device *dev, bool shutdownrf) -{ - if (_rtl92e_sta_down(dev, shutdownrf) == -1) - return -1; - - return 0; -} - -void rtl92e_commit(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->up == 0) - return; - rtllib_softmac_stop_protocol(priv->rtllib); - rtl92e_irq_disable(dev); - rtl92e_stop_adapter(dev, true); - _rtl92e_up(dev); -} - -static void _rtl92e_restart(void *data) -{ - struct r8192_priv *priv = container_of(data, struct r8192_priv, reset_wq); - struct net_device *dev = priv->rtllib->dev; - - mutex_lock(&priv->wx_mutex); - - rtl92e_commit(dev); - - mutex_unlock(&priv->wx_mutex); -} - -static void _rtl92e_set_multicast(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - short promisc; - - promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; - priv->promisc = promisc; -} - -static int _rtl92e_set_mac_adr(struct net_device *dev, void *mac) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct sockaddr *addr = mac; - - mutex_lock(&priv->wx_mutex); - - eth_hw_addr_set(dev, addr->sa_data); - - schedule_work(&priv->reset_wq); - mutex_unlock(&priv->wx_mutex); - - return 0; -} - -static irqreturn_t _rtl92e_irq(int irq, void *netdev) -{ - struct net_device *dev = netdev; - struct r8192_priv *priv = rtllib_priv(dev); - unsigned long flags; - u32 inta; - - if (priv->irq_enabled == 0) - goto done; - - spin_lock_irqsave(&priv->irq_th_lock, flags); - - rtl92e_ack_irq(dev, &inta); - - if (!inta) { - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - goto done; - } - - if (inta == 0xffff) { - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - goto done; - } - - if (!netif_running(dev)) { - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - goto done; - } - - if (inta & IMR_MGNTDOK) { - _rtl92e_tx_isr(dev, MGNT_QUEUE); - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - if (priv->rtllib->ack_tx_to_ieee) { - if (_rtl92e_is_tx_queue_empty(dev)) { - priv->rtllib->ack_tx_to_ieee = 0; - rtllib_ps_tx_ack(priv->rtllib, 1); - } - } - spin_lock_irqsave(&priv->irq_th_lock, flags); - } - - if (inta & IMR_COMDOK) - _rtl92e_tx_isr(dev, TXCMD_QUEUE); - - if (inta & IMR_HIGHDOK) - _rtl92e_tx_isr(dev, HIGH_QUEUE); - - if (inta & IMR_ROK) - tasklet_schedule(&priv->irq_rx_tasklet); - - if (inta & IMR_RDU) { - rtl92e_writel(dev, INTA_MASK, - rtl92e_readl(dev, INTA_MASK) & ~IMR_RDU); - tasklet_schedule(&priv->irq_rx_tasklet); - } - - if (inta & IMR_RXFOVW) - tasklet_schedule(&priv->irq_rx_tasklet); - - if (inta & IMR_BKDOK) { - priv->rtllib->link_detect_info.num_tx_ok_in_period++; - _rtl92e_tx_isr(dev, BK_QUEUE); - } - - if (inta & IMR_BEDOK) { - priv->rtllib->link_detect_info.num_tx_ok_in_period++; - _rtl92e_tx_isr(dev, BE_QUEUE); - } - - if (inta & IMR_VIDOK) { - priv->rtllib->link_detect_info.num_tx_ok_in_period++; - _rtl92e_tx_isr(dev, VI_QUEUE); - } - - if (inta & IMR_VODOK) { - priv->rtllib->link_detect_info.num_tx_ok_in_period++; - _rtl92e_tx_isr(dev, VO_QUEUE); - } - - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - -done: - - return IRQ_HANDLED; -} - -/**************************************************************************** - * ---------------------------- PCI_STUFF--------------------------- - ****************************************************************************/ -static const struct net_device_ops rtl8192_netdev_ops = { - .ndo_open = _rtl92e_open, - .ndo_stop = _rtl92e_close, - .ndo_tx_timeout = _rtl92e_tx_timeout, - .ndo_set_rx_mode = _rtl92e_set_multicast, - .ndo_set_mac_address = _rtl92e_set_mac_adr, - .ndo_validate_addr = eth_validate_addr, - .ndo_start_xmit = rtllib_xmit, -}; - -static int _rtl92e_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned long ioaddr = 0; - struct net_device *dev = NULL; - struct r8192_priv *priv = NULL; - unsigned long pmem_start, pmem_len, pmem_flags; - int err = -ENOMEM; - - if (pci_enable_device(pdev)) { - dev_err(&pdev->dev, "Failed to enable PCI device"); - return -EIO; - } - - pci_set_master(pdev); - - if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { - if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) { - dev_info(&pdev->dev, - "Unable to obtain 32bit DMA for consistent allocations\n"); - goto err_pci_disable; - } - } - dev = alloc_rtllib(sizeof(struct r8192_priv)); - if (!dev) - goto err_pci_disable; - - err = -ENODEV; - - pci_set_drvdata(pdev, dev); - SET_NETDEV_DEV(dev, &pdev->dev); - priv = rtllib_priv(dev); - priv->rtllib = (struct rtllib_device *)netdev_priv_rsl(dev); - priv->pdev = pdev; - priv->rtllib->pdev = pdev; - if ((pdev->subsystem_vendor == PCI_VENDOR_ID_DLINK) && - (pdev->subsystem_device == 0x3304)) - priv->rtllib->bSupportRemoteWakeUp = 1; - else - priv->rtllib->bSupportRemoteWakeUp = 0; - - pmem_start = pci_resource_start(pdev, 1); - pmem_len = pci_resource_len(pdev, 1); - pmem_flags = pci_resource_flags(pdev, 1); - - if (!(pmem_flags & IORESOURCE_MEM)) { - netdev_err(dev, "region #1 not a MMIO resource, aborting"); - goto err_rel_rtllib; - } - - dev_info(&pdev->dev, "Memory mapped space start: 0x%08lx\n", - pmem_start); - if (!request_mem_region(pmem_start, pmem_len, DRV_NAME)) { - netdev_err(dev, "request_mem_region failed!"); - goto err_rel_rtllib; - } - - ioaddr = (unsigned long)ioremap(pmem_start, pmem_len); - if (ioaddr == (unsigned long)NULL) { - netdev_err(dev, "ioremap failed!"); - goto err_rel_mem; - } - - dev->mem_start = ioaddr; - dev->mem_end = ioaddr + pci_resource_len(pdev, 0); - - if (!rtl92e_check_adapter(pdev, dev)) - goto err_unmap; - - dev->irq = pdev->irq; - priv->irq = 0; - - dev->netdev_ops = &rtl8192_netdev_ops; - - dev->wireless_handlers = &r8192_wx_handlers_def; - dev->ethtool_ops = &rtl819x_ethtool_ops; - - dev->type = ARPHRD_ETHER; - dev->watchdog_timeo = HZ * 3; - - if (dev_alloc_name(dev, ifname) < 0) - dev_alloc_name(dev, ifname); - - if (_rtl92e_init(dev) != 0) { - netdev_warn(dev, "Initialization failed"); - goto err_free_irq; - } - - netif_carrier_off(dev); - netif_stop_queue(dev); - - if (register_netdev(dev)) - goto err_free_irq; - - if (priv->polling_timer_on == 0) - rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer); - - return 0; - -err_free_irq: - free_irq(dev->irq, dev); - priv->irq = 0; -err_unmap: - iounmap((void __iomem *)ioaddr); -err_rel_mem: - release_mem_region(pmem_start, pmem_len); -err_rel_rtllib: - free_rtllib(dev); -err_pci_disable: - pci_disable_device(pdev); - return err; -} - -static void _rtl92e_pci_disconnect(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct r8192_priv *priv; - u32 i; - - if (dev) { - unregister_netdev(dev); - - priv = rtllib_priv(dev); - - del_timer_sync(&priv->gpio_polling_timer); - cancel_delayed_work_sync(&priv->gpio_change_rf_wq); - priv->polling_timer_on = 0; - _rtl92e_down(dev, true); - rtl92e_dm_deinit(dev); - vfree(priv->fw_info); - priv->fw_info = NULL; - _rtl92e_free_rx_ring(dev); - for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) - _rtl92e_free_tx_ring(dev, i); - - if (priv->irq) { - dev_info(&pdev->dev, "Freeing irq %d\n", dev->irq); - free_irq(dev->irq, dev); - priv->irq = 0; - } - - if (dev->mem_start != 0) { - iounmap((void __iomem *)dev->mem_start); - release_mem_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); - } - - free_rtllib(dev); - } - - pci_disable_device(pdev); -} - -bool rtl92e_enable_nic(struct net_device *dev) -{ - bool init_status = true; - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - (&priv->rtllib->pwr_save_ctrl); - - if (!priv->up) { - netdev_warn(dev, "%s(): Driver is already down!\n", __func__); - return false; - } - - init_status = rtl92e_start_adapter(dev); - if (!init_status) { - netdev_warn(dev, "%s(): Initialization failed!\n", __func__); - return false; - } - RT_CLEAR_PS_LEVEL(psc, RT_RF_OFF_LEVL_HALT_NIC); - - rtl92e_irq_enable(dev); - return init_status; -} - -module_pci_driver(rtl8192_pci_driver); - -void rtl92e_check_rfctrl_gpio_timer(struct timer_list *t) -{ - struct r8192_priv *priv = from_timer(priv, t, gpio_polling_timer); - - priv->polling_timer_on = 1; - - schedule_delayed_work(&priv->gpio_change_rf_wq, 0); - - mod_timer(&priv->gpio_polling_timer, jiffies + - msecs_to_jiffies(RTLLIB_WATCH_DOG_TIME)); -} - -/*************************************************************************** - * ------------------- module init / exit stubs ---------------- - ***************************************************************************/ -MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards"); -MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); -MODULE_VERSION(DRV_VERSION); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(RTL8192E_BOOT_IMG_FW); -MODULE_FIRMWARE(RTL8192E_MAIN_IMG_FW); -MODULE_FIRMWARE(RTL8192E_DATA_IMG_FW); - -module_param(ifname, charp, 0644); -module_param(hwwep, int, 0644); - -MODULE_PARM_DESC(ifname, " Net interface name, wlan%d=default"); -MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support(default use hw. set 0 to use software security)"); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h deleted file mode 100644 index 8297d7e5941596..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ /dev/null @@ -1,402 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#ifndef _RTL_CORE_H -#define _RTL_CORE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Need this defined before including local include files */ -#define DRV_NAME "rtl819xE" - -#include "../rtllib.h" - -#include "r8192E_firmware.h" -#include "r8192E_hw.h" - -#include "r8190P_def.h" -#include "r8192E_dev.h" - -#include "rtl_eeprom.h" -#include "rtl_ps.h" -#include "rtl_pci.h" -#include "rtl_cam.h" - -#define DRV_COPYRIGHT \ - "Copyright(c) 2008 - 2010 Realsil Semiconductor Corporation" -#define DRV_AUTHOR "" -#define DRV_VERSION "0014.0401.2010" - -#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 RTLLIB_WATCH_DOG_TIME 2000 - -#define MAX_DEV_ADDR_SIZE 8 /*support till 64 bit bus width OS*/ -#define MAX_FIRMWARE_INFORMATION_SIZE 32 -#define MAX_802_11_HEADER_LENGTH (40 + MAX_FIRMWARE_INFORMATION_SIZE) -#define ENCRYPTION_MAX_OVERHEAD 128 -#define MAX_FRAGMENT_COUNT 8 -#define MAX_TRANSMIT_BUFFER_SIZE \ - (1600 + (MAX_802_11_HEADER_LENGTH + ENCRYPTION_MAX_OVERHEAD) * \ - MAX_FRAGMENT_COUNT) - -#define CMDPACKET_FRAG_SIZE (4 * (MAX_TRANSMIT_BUFFER_SIZE / 4) - 8) - -#define DEFAULT_FRAG_THRESHOLD 2342U -#define MIN_FRAG_THRESHOLD 256U -#define DEFAULT_BEACONINTERVAL 0x64U - -#define DEFAULT_RETRY_RTS 7 -#define DEFAULT_RETRY_DATA 7 - -#define PHY_RSSI_SLID_WIN_MAX 100 - -#define TX_BB_GAIN_TABLE_LEN 37 -#define CCK_TX_BB_GAIN_TABLE_LEN 23 - -#define CHANNEL_PLAN_LEN 10 -#define S_CRC_LEN 4 - -#define NIC_SEND_HANG_THRESHOLD_NORMAL 4 -#define NIC_SEND_HANG_THRESHOLD_POWERSAVE 8 - -#define MAX_TX_QUEUE 9 - -#define MAX_RX_COUNT 64 -#define MAX_TX_QUEUE_COUNT 9 - -extern int hwwep; - -enum nic_t { - NIC_UNKNOWN = 0, - NIC_8192E = 1, - NIC_8190P = 2, - NIC_8192SE = 4, - NIC_8192CE = 5, - NIC_8192CU = 6, - NIC_8192DE = 7, - NIC_8192DU = 8, -}; - -enum rt_eeprom_type { - EEPROM_93C46, - EEPROM_93C56, -}; - -enum dcmg_txcmd_op { - TXCMD_TXRA_HISTORY_CTRL = 0xFF900000, - TXCMD_RESET_TX_PKT_BUFF = 0xFF900001, - TXCMD_RESET_RX_PKT_BUFF = 0xFF900002, - TXCMD_SET_TX_DURATION = 0xFF900003, - TXCMD_SET_RX_RSSI = 0xFF900004, - TXCMD_SET_TX_PWR_TRACKING = 0xFF900005, - TXCMD_XXXX_CTRL, -}; - -enum rt_customer_id { - RT_CID_DEFAULT = 0, - RT_CID_TOSHIBA = 9, - RT_CID_819X_NETCORE = 10, -}; - -enum reset_type { - RESET_TYPE_NORESET = 0x00, - RESET_TYPE_SILENT = 0x02 -}; - -struct rt_stats { - unsigned long received_rate_histogram[4][32]; - unsigned long txbytesunicast; - unsigned long rxbytesunicast; - unsigned long txretrycount; - u8 last_packet_rate; - unsigned long slide_signal_strength[100]; - unsigned long slide_evm[100]; - unsigned long slide_rssi_total; - unsigned long slide_evm_total; - long signal_strength; - long last_signal_strength_inpercent; - long recv_signal_power; - u8 rx_rssi_percentage[4]; - u8 rx_evm_percentage[2]; - u32 slide_beacon_pwdb[100]; - u32 slide_beacon_total; - u32 CurrentShowTxate; -}; - -struct init_gain { - u8 xaagccore1; - u8 xbagccore1; - u8 xcagccore1; - u8 xdagccore1; - u8 cca; - -}; - -struct tx_ring { - u32 *desc; - u8 nStuckCount; - struct tx_ring *next; -} __packed; - -struct rtl8192_tx_ring { - struct tx_desc *desc; - dma_addr_t dma; - unsigned int idx; - unsigned int entries; - struct sk_buff_head queue; -}; - -struct r8192_priv { - struct pci_dev *pdev; - struct pci_dev *bridge_pdev; - - bool bfirst_after_down; - bool being_init_adapter; - - int irq; - short irq_enabled; - - short up; - short up_first_time; - struct delayed_work update_beacon_wq; - struct delayed_work watch_dog_wq; - struct delayed_work txpower_tracking_wq; - struct delayed_work rfpath_check_wq; - struct delayed_work gpio_change_rf_wq; - struct rtllib_device *rtllib; - - struct work_struct reset_wq; - - enum rt_customer_id customer_id; - - enum ht_channel_width current_chnl_bw; - struct bb_reg_definition phy_reg_def[4]; - struct rate_adaptive rate_adaptive; - - struct rt_firmware *fw_info; - enum rtl819x_loopback loopback_mode; - - struct timer_list watch_dog_timer; - struct timer_list fsync_timer; - struct timer_list gpio_polling_timer; - - spinlock_t irq_th_lock; - spinlock_t tx_lock; - spinlock_t rf_ps_lock; - spinlock_t ps_lock; - - struct sk_buff_head skb_queue; - - struct tasklet_struct irq_rx_tasklet; - struct tasklet_struct irq_tx_tasklet; - - struct mutex wx_mutex; - struct mutex rf_mutex; - struct mutex mutex; - - struct rt_stats stats; - struct iw_statistics wstats; - - struct rx_desc *rx_ring; - struct sk_buff *rx_buf[MAX_RX_COUNT]; - dma_addr_t rx_ring_dma; - unsigned int rx_idx; - int rxringcount; - u16 rxbuffersize; - - u32 receive_config; - u8 retry_data; - u8 retry_rts; - u16 rts; - - struct rtl8192_tx_ring tx_ring[MAX_TX_QUEUE_COUNT]; - int txringcount; - atomic_t tx_pending[0x10]; - - u16 short_retry_limit; - u16 long_retry_limit; - - bool hw_radio_off; - bool blinked_ingpio; - u8 polling_timer_on; - - /**********************************************************/ - struct work_struct qos_activate; - - short promisc; - - short chan; - - u32 irq_mask[2]; - - u8 rf_mode; - enum nic_t card_8192; - u8 card_8192_version; - - u8 ic_cut; - char nick[IW_ESSID_MAX_SIZE + 1]; - u8 check_roaming_cnt; - - u32 silent_reset_rx_slot_index; - u32 silent_reset_rx_stuck_event[MAX_SILENT_RESET_RX_SLOT_NUM]; - - u16 basic_rate; - u8 short_preamble; - u8 dot11_current_preamble_mode; - u8 slot_time; - - bool autoload_fail_flag; - - short epromtype; - u16 eeprom_vid; - u16 eeprom_did; - u8 eeprom_customer_id; - - u8 eeprom_tx_pwr_level_cck[14]; - u8 eeprom_tx_pwr_level_ofdm24g[14]; - u16 eeprom_ant_pwr_diff; - u8 eeprom_thermal_meter; - u8 eeprom_crystal_cap; - - u8 eeprom_legacy_ht_tx_pwr_diff; - - u8 crystal_cap; - u8 thermal_meter[2]; - - u8 sw_chnl_in_progress; - u8 sw_chnl_stage; - u8 sw_chnl_step; - u8 set_bw_mode_in_progress; - - u8 n_cur_40mhz_prime_sc; - - u32 rf_reg_0value[4]; - u8 num_total_rf_path; - bool brfpath_rxenable[RF90_PATH_MAX]; - - bool tx_pwr_data_read_from_eeprom; - - u8 hw_rf_off_action; - - bool rf_change_in_progress; - bool set_rf_pwr_state_in_progress; - - u8 cck_pwr_enl; - u16 tssi_13dBm; - u32 pwr_track; - u8 cck_present_attn_20m_def; - u8 cck_present_attn_40m_def; - s8 cck_present_attn_diff; - s8 cck_present_attn; - long undecorated_smoothed_pwdb; - - u32 mcs_tx_pwr_level_org_offset[6]; - u8 tx_pwr_level_cck[14]; - u8 tx_pwr_level_ofdm_24g[14]; - u8 legacy_ht_tx_pwr_diff; - u8 antenna_tx_pwr_diff[3]; - - bool dynamic_tx_high_pwr; - bool dynamic_tx_low_pwr; - bool last_dtp_flag_high; - bool last_dtp_flag_low; - - u8 rfa_txpowertrackingindex; - u8 rfa_txpowertrackingindex_real; - u8 rfa_txpowertracking_default; - bool btxpower_tracking; - bool bcck_in_ch14; - - u8 txpower_count; - bool tx_pwr_tracking_init; - - u8 ofdm_index[2]; - u8 cck_index; - - u8 rec_cck_20m_idx; - u8 rec_cck_40m_idx; - - struct init_gain initgain_backup; - u8 def_initial_gain[4]; - bool bis_any_nonbepkts; - bool bcurrent_turbo_EDCA; - bool bis_cur_rdlstate; - - u32 rate_record; - u32 rate_count_diff_rec; - u32 continue_diff_count; - bool bswitch_fsync; - u8 framesync; - - u16 tx_counter; - u16 rx_ctr; -}; - -extern const struct ethtool_ops rtl819x_ethtool_ops; - -u8 rtl92e_readb(struct net_device *dev, int x); -u32 rtl92e_readl(struct net_device *dev, int x); -u16 rtl92e_readw(struct net_device *dev, int x); -void rtl92e_writeb(struct net_device *dev, int x, u8 y); -void rtl92e_writew(struct net_device *dev, int x, u16 y); -void rtl92e_writel(struct net_device *dev, int x, u32 y); - -void force_pci_posting(struct net_device *dev); - -void rtl92e_rx_enable(struct net_device *dev); -void rtl92e_tx_enable(struct net_device *dev); - -void rtl92e_hw_sleep_wq(void *data); -void rtl92e_commit(struct net_device *dev); - -void rtl92e_check_rfctrl_gpio_timer(struct timer_list *t); - -void rtl92e_hw_wakeup_wq(void *data); - -void rtl92e_reset_desc_ring(struct net_device *dev); -void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode); -void rtl92e_irq_enable(struct net_device *dev); -void rtl92e_config_rate(struct net_device *dev, u16 *rate_config); -void rtl92e_irq_disable(struct net_device *dev); - -long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index); -void rtl92e_update_rx_statistics(struct r8192_priv *priv, - struct rtllib_rx_stats *pprevious_stats); -u8 rtl92e_evm_db_to_percent(s8 value); -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_set_rf_state(struct net_device *dev, - enum rt_rf_power_state state_to_set, - RT_RF_CHANGE_SOURCE change_source); -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c deleted file mode 100644 index e9ca5a8768ad13..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ /dev/null @@ -1,1856 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include "rtl_core.h" -#include "rtl_dm.h" -#include "r8192E_hw.h" -#include "r8192E_phy.h" -#include "r8192E_phyreg.h" -#include "r8190P_rtl8256.h" -#include "r8192E_cmdpkt.h" - -/*---------------------------Define Local Constant---------------------------*/ -static u32 edca_setting_DL[HT_IOT_PEER_MAX] = { - 0x5e4322, - 0x5e4322, - 0x5ea44f, - 0x5e4322, - 0x604322, - 0xa44f, - 0x5e4322, - 0x5e4332 -}; - -static u32 edca_setting_DL_GMode[HT_IOT_PEER_MAX] = { - 0x5e4322, - 0x5e4322, - 0x5e4322, - 0x5e4322, - 0x604322, - 0xa44f, - 0x5e4322, - 0x5e4322 -}; - -static u32 edca_setting_UL[HT_IOT_PEER_MAX] = { - 0x5e4322, - 0xa44f, - 0x5ea44f, - 0x5e4322, - 0x604322, - 0x5e4322, - 0x5e4322, - 0x5e4332 -}; - -const u32 dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN] = { - 0x7f8001fe, /* 12 dB */ - 0x788001e2, /* 11 dB */ - 0x71c001c7, - 0x6b8001ae, - 0x65400195, - 0x5fc0017f, - 0x5a400169, - 0x55400155, - 0x50800142, - 0x4c000130, - 0x47c0011f, - 0x43c0010f, - 0x40000100, - 0x3c8000f2, - 0x390000e4, - 0x35c000d7, - 0x32c000cb, - 0x300000c0, - 0x2d4000b5, - 0x2ac000ab, - 0x288000a2, - 0x26000098, - 0x24000090, - 0x22000088, - 0x20000080, - 0x1a00006c, - 0x1c800072, - 0x18000060, - 0x19800066, - 0x15800056, - 0x26c0005b, - 0x14400051, - 0x24400051, - 0x1300004c, - 0x12000048, - 0x11000044, - 0x10000040, /* -24 dB */ -}; - -const u8 dm_cck_tx_bb_gain[CCK_TX_BB_GAIN_TABLE_LEN][8] = { - {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, - {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, - {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, - {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, - {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, - {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, - {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, - {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, - {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, - {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, - {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, - {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, - {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, - {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, - {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, - {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, - {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, - {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, - {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, - {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, - {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, - {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, - {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} -}; - -const u8 dm_cck_tx_bb_gain_ch14[CCK_TX_BB_GAIN_TABLE_LEN][8] = { - {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, - {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, - {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, - {0x2d, 0x2d, 0x27, 0x17, 0x00, 0x00, 0x00, 0x00}, - {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, - {0x28, 0x28, 0x22, 0x14, 0x00, 0x00, 0x00, 0x00}, - {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, - {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, - {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, - {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, - {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, - {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, - {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, - {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, - {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, - {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, - {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, - {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, - {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, - {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, - {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, - {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, - {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} -}; - -/*---------------------------Define Local Constant---------------------------*/ - - -/*------------------------Define global variable-----------------------------*/ -struct dig_t dm_digtable; - -static struct drx_path_sel dm_rx_path_sel_table; -/*------------------------Define global variable-----------------------------*/ - - -/*------------------------Define local variable------------------------------*/ -/*------------------------Define local variable------------------------------*/ - - - -/*---------------------Define local function prototype-----------------------*/ -static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev); - -static void _rtl92e_dm_init_bandwidth_autoswitch(struct net_device *dev); -static void _rtl92e_dm_bandwidth_autoswitch(struct net_device *dev); - -static void _rtl92e_dm_check_tx_power_tracking(struct net_device *dev); - -static void _rtl92e_dm_dig_init(struct net_device *dev); -static void _rtl92e_dm_ctrl_initgain_byrssi(struct net_device *dev); -static void _rtl92e_dm_initial_gain(struct net_device *dev); -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_check_edca_turbo(struct net_device *dev); -static void _rtl92e_dm_check_rx_path_selection(struct net_device *dev); -static void _rtl92e_dm_init_rx_path_selection(struct net_device *dev); -static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev); - -static void _rtl92e_dm_init_fsync(struct net_device *dev); -static void _rtl92e_dm_deinit_fsync(struct net_device *dev); - -static void _rtl92e_dm_check_txrateandretrycount(struct net_device *dev); -static void _rtl92e_dm_check_fsync(struct net_device *dev); -static void _rtl92e_dm_check_rf_ctrl_gpio(void *data); -static void _rtl92e_dm_fsync_timer_callback(struct timer_list *t); - -/*---------------------Define local function prototype-----------------------*/ - -static void _rtl92e_dm_init_dynamic_tx_power(struct net_device *dev); -static void _rtl92e_dm_dynamic_tx_power(struct net_device *dev); - -static void _rtl92e_dm_send_rssi_to_fw(struct net_device *dev); -static void _rtl92e_dm_cts_to_self(struct net_device *dev); -/*---------------------------Define function prototype------------------------*/ - -void rtl92e_dm_init(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->undecorated_smoothed_pwdb = -1; - - _rtl92e_dm_init_dynamic_tx_power(dev); - - rtl92e_init_adaptive_rate(dev); - - _rtl92e_dm_dig_init(dev); - rtl92e_dm_init_edca_turbo(dev); - _rtl92e_dm_init_bandwidth_autoswitch(dev); - _rtl92e_dm_init_fsync(dev); - _rtl92e_dm_init_rx_path_selection(dev); - _rtl92e_dm_init_cts_to_self(dev); - - INIT_DELAYED_WORK(&priv->gpio_change_rf_wq, (void *)_rtl92e_dm_check_rf_ctrl_gpio); -} - -void rtl92e_dm_deinit(struct net_device *dev) -{ - _rtl92e_dm_deinit_fsync(dev); -} - -void rtl92e_dm_watchdog(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->being_init_adapter) - return; - - _rtl92e_dm_check_txrateandretrycount(dev); - _rtl92e_dm_check_edca_turbo(dev); - - _rtl92e_dm_check_rate_adaptive(dev); - _rtl92e_dm_dynamic_tx_power(dev); - _rtl92e_dm_check_tx_power_tracking(dev); - - _rtl92e_dm_ctrl_initgain_byrssi(dev); - _rtl92e_dm_bandwidth_autoswitch(dev); - - _rtl92e_dm_check_rx_path_selection(dev); - _rtl92e_dm_check_fsync(dev); - - _rtl92e_dm_send_rssi_to_fw(dev); - _rtl92e_dm_cts_to_self(dev); -} - -void rtl92e_init_adaptive_rate(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rate_adaptive *pra = &priv->rate_adaptive; - - pra->ratr_state = DM_RATR_STA_MAX; - pra->high2low_rssi_thresh_for_ra = RATE_ADAPTIVE_TH_HIGH; - pra->low2high_rssi_thresh_for_ra20M = RATE_ADAPTIVE_TH_LOW_20M + 5; - pra->low2high_rssi_thresh_for_ra40M = RATE_ADAPTIVE_TH_LOW_40M + 5; - - pra->high_rssi_thresh_for_ra = RATE_ADAPTIVE_TH_HIGH + 5; - pra->low_rssi_thresh_for_ra20M = RATE_ADAPTIVE_TH_LOW_20M; - pra->low_rssi_thresh_for_ra40M = RATE_ADAPTIVE_TH_LOW_40M; - - if (priv->customer_id == RT_CID_819X_NETCORE) - pra->ping_rssi_enable = 1; - else - pra->ping_rssi_enable = 0; - pra->ping_rssi_thresh_for_ra = 15; - - 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); - struct rt_hi_throughput *ht_info = priv->rtllib->ht_info; - struct rate_adaptive *pra = &priv->rate_adaptive; - u32 current_ratr, target_ratr = 0; - u32 low_rssi_thresh_for_ra = 0, high_rssi_thresh_for_ra = 0; - bool bshort_gi_enabled = false; - static u8 ping_rssi_state; - - if (!priv->up) - return; - - if (priv->rtllib->mode != WIRELESS_MODE_N_24G) - return; - - if (priv->rtllib->link_state == MAC80211_LINKED) { - bshort_gi_enabled = (ht_info->cur_tx_bw40mhz && - ht_info->cur_short_gi_40mhz) || - (!ht_info->cur_tx_bw40mhz && - ht_info->cur_short_gi_20mhz); - - pra->upper_rssi_threshold_ratr = - (pra->upper_rssi_threshold_ratr & (~BIT(31))) | - ((bshort_gi_enabled) ? BIT(31) : 0); - - pra->middle_rssi_threshold_ratr = - (pra->middle_rssi_threshold_ratr & (~BIT(31))) | - ((bshort_gi_enabled) ? BIT(31) : 0); - - if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) { - pra->low_rssi_threshold_ratr = - (pra->low_rssi_threshold_ratr_40M & (~BIT(31))) | - ((bshort_gi_enabled) ? BIT(31) : 0); - } else { - pra->low_rssi_threshold_ratr = - (pra->low_rssi_threshold_ratr_20M & (~BIT(31))) | - ((bshort_gi_enabled) ? BIT(31) : 0); - } - pra->ping_rssi_ratr = - (pra->ping_rssi_ratr & (~BIT(31))) | - ((bshort_gi_enabled) ? BIT(31) : 0); - - if (pra->ratr_state == DM_RATR_STA_HIGH) { - high_rssi_thresh_for_ra = pra->high2low_rssi_thresh_for_ra; - low_rssi_thresh_for_ra = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ? - (pra->low_rssi_thresh_for_ra40M) : (pra->low_rssi_thresh_for_ra20M); - } else if (pra->ratr_state == DM_RATR_STA_LOW) { - high_rssi_thresh_for_ra = pra->high_rssi_thresh_for_ra; - low_rssi_thresh_for_ra = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ? - (pra->low2high_rssi_thresh_for_ra40M) : (pra->low2high_rssi_thresh_for_ra20M); - } else { - high_rssi_thresh_for_ra = pra->high_rssi_thresh_for_ra; - low_rssi_thresh_for_ra = (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) ? - (pra->low_rssi_thresh_for_ra40M) : (pra->low_rssi_thresh_for_ra20M); - } - - if (priv->undecorated_smoothed_pwdb >= - (long)high_rssi_thresh_for_ra) { - pra->ratr_state = DM_RATR_STA_HIGH; - target_ratr = pra->upper_rssi_threshold_ratr; - } else if (priv->undecorated_smoothed_pwdb >= - (long)low_rssi_thresh_for_ra) { - pra->ratr_state = DM_RATR_STA_MIDDLE; - target_ratr = pra->middle_rssi_threshold_ratr; - } else { - pra->ratr_state = DM_RATR_STA_LOW; - target_ratr = pra->low_rssi_threshold_ratr; - } - - if (pra->ping_rssi_enable) { - 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) { - pra->ratr_state = DM_RATR_STA_LOW; - target_ratr = pra->ping_rssi_ratr; - ping_rssi_state = 1; - } - } else { - ping_rssi_state = 0; - } - } - - if (priv->rtllib->get_half_nmode_support_by_aps_handler(dev)) - target_ratr &= 0xf00fffff; - - current_ratr = rtl92e_readl(dev, RATR0); - if (target_ratr != current_ratr) { - u32 ratr_value; - - ratr_value = target_ratr; - ratr_value &= ~(RATE_ALL_OFDM_2SS); - rtl92e_writel(dev, RATR0, ratr_value); - rtl92e_writeb(dev, UFWP, 1); - } - - } else { - pra->ratr_state = DM_RATR_STA_MAX; - } -} - -static void _rtl92e_dm_init_bandwidth_autoswitch(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->rtllib->bandwidth_auto_switch.threshold_20Mhzto40Mhz = BW_AUTO_SWITCH_LOW_HIGH; - priv->rtllib->bandwidth_auto_switch.threshold_40Mhzto20Mhz = BW_AUTO_SWITCH_HIGH_LOW; - priv->rtllib->bandwidth_auto_switch.forced_tx_20MHz = false; - priv->rtllib->bandwidth_auto_switch.bautoswitch_enable = false; -} - -static void _rtl92e_dm_bandwidth_autoswitch(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->current_chnl_bw == HT_CHANNEL_WIDTH_20 || - !priv->rtllib->bandwidth_auto_switch.bautoswitch_enable) - return; - if (!priv->rtllib->bandwidth_auto_switch.forced_tx_20MHz) { - if (priv->undecorated_smoothed_pwdb <= - priv->rtllib->bandwidth_auto_switch.threshold_40Mhzto20Mhz) - priv->rtllib->bandwidth_auto_switch.forced_tx_20MHz = true; - } else { - if (priv->undecorated_smoothed_pwdb >= - priv->rtllib->bandwidth_auto_switch.threshold_20Mhzto40Mhz) - priv->rtllib->bandwidth_auto_switch.forced_tx_20MHz = false; - } -} - -static u32 OFDMSwingTable[OFDM_TABLE_LEN] = { - 0x7f8001fe, - 0x71c001c7, - 0x65400195, - 0x5a400169, - 0x50800142, - 0x47c0011f, - 0x40000100, - 0x390000e4, - 0x32c000cb, - 0x2d4000b5, - 0x288000a2, - 0x24000090, - 0x20000080, - 0x1c800072, - 0x19800066, - 0x26c0005b, - 0x24400051, - 0x12000048, - 0x10000040 -}; - -static u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_LEN][8] = { - {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, - {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, - {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, - {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, - {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, - {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, - {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, - {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, - {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, - {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, - {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, - {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} -}; - -static u8 CCKSwingTable_Ch14[CCK_TABLE_LEN][8] = { - {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, - {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, - {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, - {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, - {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, - {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, - {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, - {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, - {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, - {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, - {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, - {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} -}; - -#define Pw_Track_Flag 0x11d -#define Tssi_Mea_Value 0x13c -#define Tssi_Report_Value1 0x134 -#define Tssi_Report_Value2 0x13e -#define FW_Busy_Flag 0x13f - -static void _rtl92e_dm_tx_update_tssi_weak_signal(struct net_device *dev) -{ - struct r8192_priv *p = rtllib_priv(dev); - - 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]); - } -} - -static void _rtl92e_dm_tx_update_tssi_strong_signal(struct net_device *dev) -{ - struct r8192_priv *p = rtllib_priv(dev); - - 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]); - } -} - -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; - int i = 0, j = 0, k = 0; - 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; - - rtl92e_writeb(dev, Pw_Track_Flag, 0); - rtl92e_writeb(dev, FW_Busy_Flag, 0); - priv->rtllib->bdynamic_txpower_enable = false; - - for (j = 0; j <= 30; j++) { - tx_cmd.op = TXCMD_SET_TX_PWR_TRACKING; - tx_cmd.length = 4; - 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); - for (i = 0; i <= 30; i++) { - Pwr_Flag = rtl92e_readb(dev, Pw_Track_Flag); - - if (Pwr_Flag == 0) { - mdelay(1); - - if (priv->rtllib->rf_power_state != rf_on) { - rtl92e_writeb(dev, Pw_Track_Flag, 0); - rtl92e_writeb(dev, FW_Busy_Flag, 0); - return; - } - - continue; - } - - Avg_TSSI_Meas = rtl92e_readw(dev, Tssi_Mea_Value); - - if (Avg_TSSI_Meas == 0) { - rtl92e_writeb(dev, Pw_Track_Flag, 0); - rtl92e_writeb(dev, FW_Busy_Flag, 0); - return; - } - - for (k = 0; k < 5; k++) { - if (k != 4) - tmp_report[k] = rtl92e_readb(dev, - Tssi_Report_Value1 + k); - else - tmp_report[k] = rtl92e_readb(dev, - Tssi_Report_Value2); - - if (tmp_report[k] <= 20) { - viviflag = true; - break; - } - } - - if (viviflag) { - rtl92e_writeb(dev, Pw_Track_Flag, 0); - viviflag = false; - for (k = 0; k < 5; k++) - tmp_report[k] = 0; - break; - } - - for (k = 0; k < 5; k++) - Avg_TSSI_Meas_from_driver += tmp_report[k]; - - Avg_TSSI_Meas_from_driver *= 100 / 5; - tssi_13dBm = priv->tssi_13dBm; - - if (Avg_TSSI_Meas_from_driver > tssi_13dBm) - delta = Avg_TSSI_Meas_from_driver - tssi_13dBm; - else - delta = tssi_13dBm - Avg_TSSI_Meas_from_driver; - - if (delta <= E_FOR_TX_POWER_TRACK) { - priv->rtllib->bdynamic_txpower_enable = true; - rtl92e_writeb(dev, Pw_Track_Flag, 0); - rtl92e_writeb(dev, FW_Busy_Flag, 0); - return; - } - if (Avg_TSSI_Meas_from_driver < tssi_13dBm - E_FOR_TX_POWER_TRACK) - _rtl92e_dm_tx_update_tssi_weak_signal(dev); - else - _rtl92e_dm_tx_update_tssi_strong_signal(dev); - - 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 = - priv->cck_present_attn_20m_def + - priv->cck_present_attn_diff; - else - priv->cck_present_attn = - priv->cck_present_attn_40m_def + - priv->cck_present_attn_diff; - - if (priv->cck_present_attn > (CCK_TX_BB_GAIN_TABLE_LEN - 1)) - priv->cck_present_attn = CCK_TX_BB_GAIN_TABLE_LEN - 1; - if (priv->cck_present_attn < 0) - priv->cck_present_attn = 0; - - if (priv->cck_present_attn > -1 && - priv->cck_present_attn < CCK_TX_BB_GAIN_TABLE_LEN) { - if (priv->rtllib->current_network.channel == 14 && - !priv->bcck_in_ch14) { - priv->bcck_in_ch14 = true; - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } else if (priv->rtllib->current_network.channel != 14 && priv->bcck_in_ch14) { - priv->bcck_in_ch14 = false; - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } else { - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - } - } - - if (priv->cck_present_attn_diff <= -12 || - priv->cck_present_attn_diff >= 24) { - priv->rtllib->bdynamic_txpower_enable = true; - rtl92e_writeb(dev, Pw_Track_Flag, 0); - rtl92e_writeb(dev, FW_Busy_Flag, 0); - return; - } - - rtl92e_writeb(dev, Pw_Track_Flag, 0); - Avg_TSSI_Meas_from_driver = 0; - for (k = 0; k < 5; k++) - tmp_report[k] = 0; - break; - } - rtl92e_writeb(dev, FW_Busy_Flag, 0); - } - priv->rtllib->bdynamic_txpower_enable = true; - rtl92e_writeb(dev, Pw_Track_Flag, 0); -} - -static void _rtl92e_dm_tx_power_tracking_cb_thermal(struct net_device *dev) -{ -#define ThermalMeterVal 9 - struct r8192_priv *priv = rtllib_priv(dev); - u32 tmp_reg, tmp_cck; - u8 tmp_ofdm_index, tmp_cck_index, tmp_cck_20m_index, tmp_cck_40m_index, tmpval; - int i = 0, CCKSwingNeedUpdate = 0; - - if (!priv->tx_pwr_tracking_init) { - tmp_reg = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord); - for (i = 0; i < OFDM_TABLE_LEN; i++) { - if (tmp_reg == OFDMSwingTable[i]) - priv->ofdm_index[0] = i; - } - - tmp_cck = rtl92e_get_bb_reg(dev, rCCK0_TxFilter1, bMaskByte2); - for (i = 0; i < CCK_TABLE_LEN; i++) { - if (tmp_cck == (u32)CCKSwingTable_Ch1_Ch13[i][0]) { - priv->cck_index = i; - break; - } - } - priv->tx_pwr_tracking_init = true; - return; - } - - tmp_reg = rtl92e_get_rf_reg(dev, RF90_PATH_A, 0x12, 0x078); - if (tmp_reg < 3 || tmp_reg > 13) - return; - if (tmp_reg >= 12) - tmp_reg = 12; - priv->thermal_meter[0] = ThermalMeterVal; - priv->thermal_meter[1] = ThermalMeterVal; - - if (priv->thermal_meter[0] >= (u8)tmp_reg) { - tmp_ofdm_index = 6 + (priv->thermal_meter[0] - (u8)tmp_reg); - tmp_cck_20m_index = tmp_ofdm_index; - tmp_cck_40m_index = tmp_cck_20m_index - 6; - if (tmp_ofdm_index >= OFDM_TABLE_LEN) - tmp_ofdm_index = OFDM_TABLE_LEN - 1; - if (tmp_cck_20m_index >= CCK_TABLE_LEN) - tmp_cck_20m_index = CCK_TABLE_LEN - 1; - if (tmp_cck_40m_index >= CCK_TABLE_LEN) - tmp_cck_40m_index = CCK_TABLE_LEN - 1; - } else { - tmpval = (u8)tmp_reg - priv->thermal_meter[0]; - if (tmpval >= 6) { - tmp_ofdm_index = 0; - tmp_cck_20m_index = 0; - } else { - tmp_ofdm_index = 6 - tmpval; - tmp_cck_20m_index = 6 - tmpval; - } - tmp_cck_40m_index = 0; - } - if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) - tmp_cck_index = tmp_cck_40m_index; - else - tmp_cck_index = tmp_cck_20m_index; - - priv->rec_cck_20m_idx = tmp_cck_20m_index; - priv->rec_cck_40m_idx = tmp_cck_40m_index; - - if (priv->rtllib->current_network.channel == 14 && - !priv->bcck_in_ch14) { - priv->bcck_in_ch14 = true; - CCKSwingNeedUpdate = 1; - } else if (priv->rtllib->current_network.channel != 14 && - priv->bcck_in_ch14) { - priv->bcck_in_ch14 = false; - CCKSwingNeedUpdate = 1; - } - - if (priv->cck_index != tmp_cck_index) { - priv->cck_index = tmp_cck_index; - CCKSwingNeedUpdate = 1; - } - - if (CCKSwingNeedUpdate) - rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - if (priv->ofdm_index[0] != tmp_ofdm_index) { - priv->ofdm_index[0] = tmp_ofdm_index; - rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, - OFDMSwingTable[priv->ofdm_index[0]]); - } - priv->txpower_count = 0; -} - -void rtl92e_dm_txpower_tracking_wq(void *data) -{ - struct r8192_priv *priv = container_of_dwork_rsl(data, - struct r8192_priv, txpower_tracking_wq); - struct net_device *dev = priv->rtllib->dev; - - if (priv->ic_cut >= IC_VersionCut_D) - _rtl92e_dm_tx_power_tracking_callback_tssi(dev); - else - _rtl92e_dm_tx_power_tracking_cb_thermal(dev); -} - -static void _rtl92e_dm_initialize_tx_power_tracking_tssi(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->btxpower_tracking = true; - priv->txpower_count = 0; - priv->tx_pwr_tracking_init = false; -} - -static void _rtl92e_dm_init_tx_power_tracking_thermal(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->rtllib->FwRWRF) - priv->btxpower_tracking = true; - else - priv->btxpower_tracking = false; - priv->txpower_count = 0; - priv->tx_pwr_tracking_init = false; -} - -void rtl92e_dm_init_txpower_tracking(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->ic_cut >= IC_VersionCut_D) - _rtl92e_dm_initialize_tx_power_tracking_tssi(dev); - else - _rtl92e_dm_init_tx_power_tracking_thermal(dev); -} - -static void _rtl92e_dm_check_tx_power_tracking_tssi(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - static u32 tx_power_track_counter; - - if (rtl92e_readb(dev, 0x11e) == 1) - return; - if (!priv->btxpower_tracking) - return; - tx_power_track_counter++; - - if (tx_power_track_counter >= 180) { - schedule_delayed_work(&priv->txpower_tracking_wq, 0); - tx_power_track_counter = 0; - } -} - -static void _rtl92e_dm_check_tx_power_tracking_thermal(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - static u8 TM_Trigger; - u8 TxPowerCheckCnt = 0; - - TxPowerCheckCnt = 2; - if (!priv->btxpower_tracking) - return; - - if (priv->txpower_count <= TxPowerCheckCnt) { - priv->txpower_count++; - return; - } - - if (!TM_Trigger) { - rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); - rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); - rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); - rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); - TM_Trigger = 1; - return; - } - netdev_info(dev, "===============>Schedule TxPowerTrackingWorkItem\n"); - schedule_delayed_work(&priv->txpower_tracking_wq, 0); - TM_Trigger = 0; -} - -static void _rtl92e_dm_check_tx_power_tracking(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->ic_cut >= IC_VersionCut_D) - _rtl92e_dm_check_tx_power_tracking_tssi(dev); - else - _rtl92e_dm_check_tx_power_tracking_thermal(dev); -} - -static void _rtl92e_dm_cck_tx_power_adjust_tssi(struct net_device *dev, - bool bInCH14) -{ - u32 TempVal; - struct r8192_priv *priv = rtllib_priv(dev); - u8 attenuation = priv->cck_present_attn; - - TempVal = 0; - if (!bInCH14) { - TempVal = (u32)(dm_cck_tx_bb_gain[attenuation][0] + - (dm_cck_tx_bb_gain[attenuation][1] << 8)); - - rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); - TempVal = (u32)((dm_cck_tx_bb_gain[attenuation][2]) + - (dm_cck_tx_bb_gain[attenuation][3] << 8) + - (dm_cck_tx_bb_gain[attenuation][4] << 16) + - (dm_cck_tx_bb_gain[attenuation][5] << 24)); - rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); - TempVal = (u32)(dm_cck_tx_bb_gain[attenuation][6] + - (dm_cck_tx_bb_gain[attenuation][7] << 8)); - - rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); - } else { - TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][0]) + - (dm_cck_tx_bb_gain_ch14[attenuation][1] << 8)); - - rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); - TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][2]) + - (dm_cck_tx_bb_gain_ch14[attenuation][3] << 8) + - (dm_cck_tx_bb_gain_ch14[attenuation][4] << 16) + - (dm_cck_tx_bb_gain_ch14[attenuation][5] << 24)); - rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); - TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][6]) + - (dm_cck_tx_bb_gain_ch14[attenuation][7] << 8)); - - rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); - } -} - -static void _rtl92e_dm_cck_tx_power_adjust_thermal_meter(struct net_device *dev, - bool bInCH14) -{ - u32 TempVal; - struct r8192_priv *priv = rtllib_priv(dev); - - TempVal = 0; - if (!bInCH14) { - TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][0] + - (CCKSwingTable_Ch1_Ch13[priv->cck_index][1] << 8); - rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); - TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][2] + - (CCKSwingTable_Ch1_Ch13[priv->cck_index][3] << 8) + - (CCKSwingTable_Ch1_Ch13[priv->cck_index][4] << 16) + - (CCKSwingTable_Ch1_Ch13[priv->cck_index][5] << 24); - rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); - TempVal = CCKSwingTable_Ch1_Ch13[priv->cck_index][6] + - (CCKSwingTable_Ch1_Ch13[priv->cck_index][7] << 8); - - rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); - } else { - TempVal = CCKSwingTable_Ch14[priv->cck_index][0] + - (CCKSwingTable_Ch14[priv->cck_index][1] << 8); - - rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); - TempVal = CCKSwingTable_Ch14[priv->cck_index][2] + - (CCKSwingTable_Ch14[priv->cck_index][3] << 8) + - (CCKSwingTable_Ch14[priv->cck_index][4] << 16) + - (CCKSwingTable_Ch14[priv->cck_index][5] << 24); - rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); - TempVal = CCKSwingTable_Ch14[priv->cck_index][6] + - (CCKSwingTable_Ch14[priv->cck_index][7] << 8); - - rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); - } -} - -void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->ic_cut >= IC_VersionCut_D) - _rtl92e_dm_cck_tx_power_adjust_tssi(dev, binch14); - else - _rtl92e_dm_cck_tx_power_adjust_thermal_meter(dev, binch14); -} - -static void _rtl92e_dm_dig_init(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - dm_digtable.cur_sta_connect_state = DIG_STA_DISCONNECT; - dm_digtable.pre_sta_connect_state = DIG_STA_DISCONNECT; - - dm_digtable.rssi_low_thresh = DM_DIG_THRESH_LOW; - dm_digtable.rssi_high_thresh = DM_DIG_THRESH_HIGH; - - dm_digtable.rssi_high_power_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW; - dm_digtable.rssi_high_power_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH; - - dm_digtable.rssi_val = 50; - dm_digtable.backoff_val = DM_DIG_BACKOFF; - dm_digtable.rx_gain_range_max = DM_DIG_MAX; - if (priv->customer_id == RT_CID_819X_NETCORE) - dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore; - else - dm_digtable.rx_gain_range_min = DM_DIG_MIN; -} - -/*----------------------------------------------------------------------------- - * Function: dm_CtrlInitGainBeforeConnectByRssiAndFalseAlarm() - * - * Overview: Driver monitor RSSI and False Alarm to change initial gain. - Only change initial gain during link in progress. - * - * Input: IN PADAPTER pAdapter - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 03/04/2009 hpfan Create Version 0. - * - ******************************************************************************/ - -static void _rtl92e_dm_ctrl_initgain_byrssi(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 i; - static u8 fw_dig; - - if (fw_dig <= 3) { - for (i = 0; i < 3; i++) - rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8); - fw_dig++; - } - - if (priv->rtllib->link_state == MAC80211_LINKED) - dm_digtable.cur_sta_connect_state = DIG_STA_CONNECT; - else - dm_digtable.cur_sta_connect_state = DIG_STA_DISCONNECT; - - dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb; - _rtl92e_dm_initial_gain(dev); - _rtl92e_dm_pd_th(dev); - _rtl92e_dm_cs_ratio(dev); - dm_digtable.pre_sta_connect_state = dm_digtable.cur_sta_connect_state; -} - -static void _rtl92e_dm_initial_gain(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 initial_gain = 0; - static u8 initialized, force_write; - - if (rtllib_act_scanning(priv->rtllib, true)) { - force_write = 1; - return; - } - - if (dm_digtable.pre_sta_connect_state == dm_digtable.cur_sta_connect_state) { - if (dm_digtable.cur_sta_connect_state == DIG_STA_CONNECT) { - long gain_range = dm_digtable.rssi_val + 10 - - dm_digtable.backoff_val; - gain_range = clamp_t(long, gain_range, - dm_digtable.rx_gain_range_min, - dm_digtable.rx_gain_range_max); - dm_digtable.cur_ig_value = gain_range; - } else { - if (dm_digtable.cur_ig_value == 0) - dm_digtable.cur_ig_value = priv->def_initial_gain[0]; - else - dm_digtable.cur_ig_value = dm_digtable.pre_ig_value; - } - } else { - dm_digtable.cur_ig_value = priv->def_initial_gain[0]; - dm_digtable.pre_ig_value = 0; - } - - if (dm_digtable.pre_ig_value != rtl92e_readb(dev, rOFDM0_XAAGCCore1)) - force_write = 1; - - if ((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value) - || !initialized || force_write) { - initial_gain = dm_digtable.cur_ig_value; - rtl92e_writeb(dev, rOFDM0_XAAGCCore1, initial_gain); - rtl92e_writeb(dev, rOFDM0_XBAGCCore1, initial_gain); - rtl92e_writeb(dev, rOFDM0_XCAGCCore1, initial_gain); - rtl92e_writeb(dev, rOFDM0_XDAGCCore1, initial_gain); - dm_digtable.pre_ig_value = dm_digtable.cur_ig_value; - initialized = 1; - force_write = 0; - } -} - -static void _rtl92e_dm_pd_th(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - static u8 initialized, force_write; - - if (dm_digtable.pre_sta_connect_state == dm_digtable.cur_sta_connect_state) { - if (dm_digtable.cur_sta_connect_state == DIG_STA_CONNECT) { - if (dm_digtable.rssi_val >= - dm_digtable.rssi_high_power_highthresh) - dm_digtable.curpd_thstate = - DIG_PD_AT_HIGH_POWER; - else if (dm_digtable.rssi_val <= - dm_digtable.rssi_low_thresh) - dm_digtable.curpd_thstate = - DIG_PD_AT_LOW_POWER; - else if ((dm_digtable.rssi_val >= - dm_digtable.rssi_high_thresh) && - (dm_digtable.rssi_val < - dm_digtable.rssi_high_power_lowthresh)) - dm_digtable.curpd_thstate = - DIG_PD_AT_NORMAL_POWER; - else - dm_digtable.curpd_thstate = - dm_digtable.prepd_thstate; - } else { - dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; - } - } else { - dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER; - } - - if ((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) || - (initialized <= 3) || force_write) { - if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) { - if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) - rtl92e_writeb(dev, (rOFDM0_XATxAFE + 3), 0x00); - else - rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x42); - } else if (dm_digtable.curpd_thstate == - DIG_PD_AT_NORMAL_POWER) { - if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) - rtl92e_writeb(dev, (rOFDM0_XATxAFE + 3), 0x20); - else - rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x44); - } else if (dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) { - if (priv->current_chnl_bw != HT_CHANNEL_WIDTH_20) - rtl92e_writeb(dev, (rOFDM0_XATxAFE + 3), 0x10); - else - rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x43); - } - dm_digtable.prepd_thstate = dm_digtable.curpd_thstate; - if (initialized <= 3) - initialized++; - force_write = 0; - } -} - -static void _rtl92e_dm_cs_ratio(struct net_device *dev) -{ - static u8 initialized, force_write; - - if (dm_digtable.pre_sta_connect_state == dm_digtable.cur_sta_connect_state) { - if (dm_digtable.cur_sta_connect_state == DIG_STA_CONNECT) { - if (dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh) - dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; - else if (dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) - dm_digtable.curcs_ratio_state = DIG_CS_RATIO_HIGHER; - else - dm_digtable.curcs_ratio_state = dm_digtable.precs_ratio_state; - } else { - dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; - } - } else { - dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER; - } - - if ((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) || - !initialized || force_write) { - if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER) - rtl92e_writeb(dev, 0xa0a, 0x08); - else if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER) - rtl92e_writeb(dev, 0xa0a, 0xcd); - dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state; - initialized = 1; - force_write = 0; - } -} - -void rtl92e_dm_init_edca_turbo(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->bcurrent_turbo_EDCA = false; - priv->rtllib->bis_any_nonbepkts = false; - priv->bis_cur_rdlstate = false; -} - -static void _rtl92e_dm_check_edca_turbo(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_hi_throughput *ht_info = priv->rtllib->ht_info; - - static unsigned long lastTxOkCnt; - static unsigned long lastRxOkCnt; - unsigned long curTxOkCnt = 0; - unsigned long curRxOkCnt = 0; - - if (priv->rtllib->link_state != MAC80211_LINKED) - goto dm_CheckEdcaTurbo_EXIT; - if (priv->rtllib->ht_info->iot_action & HT_IOT_ACT_DISABLE_EDCA_TURBO) - goto dm_CheckEdcaTurbo_EXIT; - - if (!priv->rtllib->bis_any_nonbepkts) { - curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; - curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; - if (ht_info->iot_action & HT_IOT_ACT_EDCA_BIAS_ON_RX) { - if (curTxOkCnt > 4 * curRxOkCnt) { - if (priv->bis_cur_rdlstate || - !priv->bcurrent_turbo_EDCA) { - rtl92e_writel(dev, EDCAPARA_BE, - edca_setting_UL[ht_info->iot_peer]); - priv->bis_cur_rdlstate = false; - } - } else { - if (!priv->bis_cur_rdlstate || - !priv->bcurrent_turbo_EDCA) { - if (priv->rtllib->mode == WIRELESS_MODE_G) - rtl92e_writel(dev, EDCAPARA_BE, - edca_setting_DL_GMode[ht_info->iot_peer]); - else - rtl92e_writel(dev, EDCAPARA_BE, - edca_setting_DL[ht_info->iot_peer]); - priv->bis_cur_rdlstate = true; - } - } - priv->bcurrent_turbo_EDCA = true; - } else { - if (curRxOkCnt > 4 * curTxOkCnt) { - if (!priv->bis_cur_rdlstate || - !priv->bcurrent_turbo_EDCA) { - if (priv->rtllib->mode == WIRELESS_MODE_G) - rtl92e_writel(dev, EDCAPARA_BE, - edca_setting_DL_GMode[ht_info->iot_peer]); - else - rtl92e_writel(dev, EDCAPARA_BE, - edca_setting_DL[ht_info->iot_peer]); - priv->bis_cur_rdlstate = true; - } - } else { - if (priv->bis_cur_rdlstate || - !priv->bcurrent_turbo_EDCA) { - rtl92e_writel(dev, EDCAPARA_BE, - edca_setting_UL[ht_info->iot_peer]); - priv->bis_cur_rdlstate = false; - } - } - - priv->bcurrent_turbo_EDCA = true; - } - } else { - if (priv->bcurrent_turbo_EDCA) { - u8 tmp = AC0_BE; - - priv->rtllib->set_hw_reg_handler(dev, HW_VAR_AC_PARAM, - (u8 *)(&tmp)); - priv->bcurrent_turbo_EDCA = false; - } - } - -dm_CheckEdcaTurbo_EXIT: - priv->rtllib->bis_any_nonbepkts = false; - lastTxOkCnt = priv->stats.txbytesunicast; - lastRxOkCnt = priv->stats.rxbytesunicast; -} - -static void _rtl92e_dm_init_cts_to_self(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv((struct net_device *)dev); - - priv->rtllib->bCTSToSelfEnable = true; -} - -static void _rtl92e_dm_cts_to_self(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv((struct net_device *)dev); - struct rt_hi_throughput *ht_info = priv->rtllib->ht_info; - static unsigned long lastTxOkCnt; - static unsigned long lastRxOkCnt; - unsigned long curTxOkCnt = 0; - unsigned long curRxOkCnt = 0; - - if (!priv->rtllib->bCTSToSelfEnable) { - ht_info->iot_action &= ~HT_IOT_ACT_FORCED_CTS2SELF; - return; - } - if (ht_info->iot_peer == HT_IOT_PEER_BROADCOM) { - curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt; - curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt; - if (curRxOkCnt > 4 * curTxOkCnt) - ht_info->iot_action &= ~HT_IOT_ACT_FORCED_CTS2SELF; - else - ht_info->iot_action |= HT_IOT_ACT_FORCED_CTS2SELF; - - lastTxOkCnt = priv->stats.txbytesunicast; - lastRxOkCnt = priv->stats.rxbytesunicast; - } -} - -static void _rtl92e_dm_check_rf_ctrl_gpio(void *data) -{ - struct r8192_priv *priv = container_of_dwork_rsl(data, - struct r8192_priv, gpio_change_rf_wq); - struct net_device *dev = priv->rtllib->dev; - u8 tmp1byte; - enum rt_rf_power_state rf_power_state_to_set; - bool bActuallySet = false; - - if ((priv->up_first_time == 1) || (priv->being_init_adapter)) - return; - - if (priv->bfirst_after_down) - return; - - tmp1byte = rtl92e_readb(dev, GPI); - - rf_power_state_to_set = (tmp1byte & BIT(1)) ? rf_on : rf_off; - - if (priv->hw_radio_off && (rf_power_state_to_set == rf_on)) { - netdev_info(dev, "gpiochangeRF - HW Radio ON\n"); - priv->hw_radio_off = false; - bActuallySet = true; - } else if (!priv->hw_radio_off && (rf_power_state_to_set == rf_off)) { - netdev_info(dev, "gpiochangeRF - HW Radio OFF\n"); - priv->hw_radio_off = true; - bActuallySet = true; - } - - if (bActuallySet) { - mdelay(1000); - priv->hw_rf_off_action = 1; - rtl92e_set_rf_state(dev, rf_power_state_to_set, RF_CHANGE_BY_HW); - } -} - -void rtl92e_dm_rf_pathcheck_wq(void *data) -{ - struct r8192_priv *priv = container_of_dwork_rsl(data, - struct r8192_priv, - rfpath_check_wq); - struct net_device *dev = priv->rtllib->dev; - u8 rfpath, i; - - rfpath = rtl92e_readb(dev, 0xc04); - - for (i = 0; i < RF90_PATH_MAX; i++) { - if (rfpath & (0x01 << i)) - priv->brfpath_rxenable[i] = true; - else - priv->brfpath_rxenable[i] = false; - } - if (!dm_rx_path_sel_table.enable) - return; - - _rtl92e_dm_rx_path_sel_byrssi(dev); -} - -static void _rtl92e_dm_init_rx_path_selection(struct net_device *dev) -{ - u8 i; - struct r8192_priv *priv = rtllib_priv(dev); - - dm_rx_path_sel_table.enable = 1; - dm_rx_path_sel_table.ss_th_low = RX_PATH_SEL_SS_TH_LOW; - dm_rx_path_sel_table.diff_th = RX_PATH_SEL_DIFF_TH; - if (priv->customer_id == RT_CID_819X_NETCORE) - dm_rx_path_sel_table.cck_method = CCK_Rx_Version_2; - else - dm_rx_path_sel_table.cck_method = CCK_Rx_Version_1; - dm_rx_path_sel_table.disabled_rf = 0; - for (i = 0; i < 4; i++) { - dm_rx_path_sel_table.rf_rssi[i] = 50; - dm_rx_path_sel_table.cck_pwdb_sta[i] = -64; - dm_rx_path_sel_table.rf_enable_rssi_th[i] = 100; - } -} - -#define PWDB_IN_RANGE ((cur_cck_pwdb < tmp_cck_max_pwdb) && \ - (cur_cck_pwdb > tmp_cck_sec_pwdb)) - -static void _rtl92e_dm_rx_path_sel_byrssi(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u8 i, max_rssi_index = 0, min_rssi_index = 0; - u8 sec_rssi_index = 0, rf_num = 0; - u8 tmp_max_rssi = 0, tmp_min_rssi = 0, tmp_sec_rssi = 0; - u8 cck_default_Rx = 0x2; - u8 cck_optional_Rx = 0x3; - long tmp_cck_max_pwdb = 0, tmp_cck_min_pwdb = 0, tmp_cck_sec_pwdb = 0; - u8 cck_rx_ver2_max_index = 0; - u8 cck_rx_ver2_sec_index = 0; - u8 cur_rf_rssi; - long cur_cck_pwdb; - static u8 disabled_rf_cnt, cck_Rx_Path_initialized; - u8 update_cck_rx_path; - - if (!cck_Rx_Path_initialized) { - dm_rx_path_sel_table.cck_rx_path = (rtl92e_readb(dev, 0xa07) & 0xf); - cck_Rx_Path_initialized = 1; - } - - dm_rx_path_sel_table.disabled_rf = 0xf; - dm_rx_path_sel_table.disabled_rf &= ~(rtl92e_readb(dev, 0xc04)); - - if (priv->rtllib->mode == WIRELESS_MODE_B) - dm_rx_path_sel_table.cck_method = CCK_Rx_Version_2; - - for (i = 0; i < RF90_PATH_MAX; i++) { - dm_rx_path_sel_table.rf_rssi[i] = priv->stats.rx_rssi_percentage[i]; - - if (!priv->brfpath_rxenable[i]) - continue; - - rf_num++; - cur_rf_rssi = dm_rx_path_sel_table.rf_rssi[i]; - - if (rf_num == 1) { - max_rssi_index = min_rssi_index = sec_rssi_index = i; - tmp_max_rssi = tmp_min_rssi = tmp_sec_rssi = cur_rf_rssi; - } else if (rf_num == 2) { - if (cur_rf_rssi >= tmp_max_rssi) { - tmp_max_rssi = cur_rf_rssi; - max_rssi_index = i; - } else { - tmp_sec_rssi = tmp_min_rssi = cur_rf_rssi; - sec_rssi_index = min_rssi_index = i; - } - } else { - if (cur_rf_rssi > tmp_max_rssi) { - tmp_sec_rssi = tmp_max_rssi; - sec_rssi_index = max_rssi_index; - tmp_max_rssi = cur_rf_rssi; - max_rssi_index = i; - } else if (cur_rf_rssi == tmp_max_rssi) { - tmp_sec_rssi = cur_rf_rssi; - sec_rssi_index = i; - } else if ((cur_rf_rssi < tmp_max_rssi) && - (cur_rf_rssi > tmp_sec_rssi)) { - tmp_sec_rssi = cur_rf_rssi; - sec_rssi_index = i; - } else if (cur_rf_rssi == tmp_sec_rssi) { - if (tmp_sec_rssi == tmp_min_rssi) { - tmp_sec_rssi = cur_rf_rssi; - sec_rssi_index = i; - } - } else if ((cur_rf_rssi < tmp_sec_rssi) && - (cur_rf_rssi > tmp_min_rssi)) { - ; - } else if (cur_rf_rssi == tmp_min_rssi) { - if (tmp_sec_rssi == tmp_min_rssi) { - tmp_min_rssi = cur_rf_rssi; - min_rssi_index = i; - } - } else if (cur_rf_rssi < tmp_min_rssi) { - tmp_min_rssi = cur_rf_rssi; - min_rssi_index = i; - } - } - } - - rf_num = 0; - if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_2) { - for (i = 0; i < RF90_PATH_MAX; i++) { - if (!priv->brfpath_rxenable[i]) - continue; - - rf_num++; - cur_cck_pwdb = dm_rx_path_sel_table.cck_pwdb_sta[i]; - - if (rf_num == 1) { - cck_rx_ver2_max_index = i; - cck_rx_ver2_sec_index = i; - tmp_cck_max_pwdb = cur_cck_pwdb; - tmp_cck_min_pwdb = cur_cck_pwdb; - tmp_cck_sec_pwdb = cur_cck_pwdb; - } else if (rf_num == 2) { - if (cur_cck_pwdb >= tmp_cck_max_pwdb) { - tmp_cck_max_pwdb = cur_cck_pwdb; - cck_rx_ver2_max_index = i; - } else { - tmp_cck_sec_pwdb = cur_cck_pwdb; - tmp_cck_min_pwdb = cur_cck_pwdb; - cck_rx_ver2_sec_index = i; - } - } else { - if (cur_cck_pwdb > tmp_cck_max_pwdb) { - tmp_cck_sec_pwdb = tmp_cck_max_pwdb; - cck_rx_ver2_sec_index = cck_rx_ver2_max_index; - tmp_cck_max_pwdb = cur_cck_pwdb; - cck_rx_ver2_max_index = i; - } else if (cur_cck_pwdb == tmp_cck_max_pwdb) { - tmp_cck_sec_pwdb = cur_cck_pwdb; - cck_rx_ver2_sec_index = i; - } else if (PWDB_IN_RANGE) { - tmp_cck_sec_pwdb = cur_cck_pwdb; - cck_rx_ver2_sec_index = i; - } else if (cur_cck_pwdb == tmp_cck_sec_pwdb) { - if (tmp_cck_sec_pwdb == tmp_cck_min_pwdb) { - tmp_cck_sec_pwdb = cur_cck_pwdb; - cck_rx_ver2_sec_index = i; - } - } else if ((cur_cck_pwdb < tmp_cck_sec_pwdb) && - (cur_cck_pwdb > tmp_cck_min_pwdb)) { - ; - } else if (cur_cck_pwdb == tmp_cck_min_pwdb) { - if (tmp_cck_sec_pwdb == tmp_cck_min_pwdb) - tmp_cck_min_pwdb = cur_cck_pwdb; - } else if (cur_cck_pwdb < tmp_cck_min_pwdb) { - tmp_cck_min_pwdb = cur_cck_pwdb; - } - } - } - } - - update_cck_rx_path = 0; - if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_2) { - cck_default_Rx = cck_rx_ver2_max_index; - cck_optional_Rx = cck_rx_ver2_sec_index; - if (tmp_cck_max_pwdb != -64) - update_cck_rx_path = 1; - } - - if (tmp_min_rssi < dm_rx_path_sel_table.ss_th_low && disabled_rf_cnt < 2) { - if ((tmp_max_rssi - tmp_min_rssi) >= - dm_rx_path_sel_table.diff_th) { - dm_rx_path_sel_table.rf_enable_rssi_th[min_rssi_index] = - tmp_max_rssi + 5; - rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable, - 0x1 << min_rssi_index, 0x0); - rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, - 0x1 << min_rssi_index, 0x0); - disabled_rf_cnt++; - } - if (dm_rx_path_sel_table.cck_method == CCK_Rx_Version_1) { - cck_default_Rx = max_rssi_index; - cck_optional_Rx = sec_rssi_index; - if (tmp_max_rssi) - update_cck_rx_path = 1; - } - } - - if (update_cck_rx_path) { - dm_rx_path_sel_table.cck_rx_path = (cck_default_Rx << 2) | - (cck_optional_Rx); - rtl92e_set_bb_reg(dev, rCCK0_AFESetting, 0x0f000000, - dm_rx_path_sel_table.cck_rx_path); - } - - if (dm_rx_path_sel_table.disabled_rf) { - for (i = 0; i < 4; i++) { - if ((dm_rx_path_sel_table.disabled_rf >> i) & 0x1) { - if (tmp_max_rssi >= - dm_rx_path_sel_table.rf_enable_rssi_th[i]) { - rtl92e_set_bb_reg(dev, - rOFDM0_TRxPathEnable, - 0x1 << i, 0x1); - rtl92e_set_bb_reg(dev, - rOFDM1_TRxPathEnable, - 0x1 << i, 0x1); - dm_rx_path_sel_table.rf_enable_rssi_th[i] = 100; - disabled_rf_cnt--; - } - } - } - } -} - -static void _rtl92e_dm_check_rx_path_selection(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - schedule_delayed_work(&priv->rfpath_check_wq, 0); -} - -static void _rtl92e_dm_init_fsync(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->rtllib->fsync_time_interval = 500; - priv->rtllib->fsync_rate_bitmap = 0x0f000800; - priv->rtllib->fsync_rssi_threshold = 30; - priv->rtllib->bfsync_enable = false; - priv->rtllib->fsync_multiple_timeinterval = 3; - priv->rtllib->fsync_firstdiff_ratethreshold = 100; - priv->rtllib->fsync_seconddiff_ratethreshold = 200; - priv->rtllib->fsync_state = DEFAULT_FSYNC; - - timer_setup(&priv->fsync_timer, _rtl92e_dm_fsync_timer_callback, 0); -} - -static void _rtl92e_dm_deinit_fsync(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - del_timer_sync(&priv->fsync_timer); -} - -static void _rtl92e_dm_fsync_timer_callback(struct timer_list *t) -{ - struct r8192_priv *priv = from_timer(priv, t, fsync_timer); - struct net_device *dev = priv->rtllib->dev; - u32 rate_index, rate_count = 0, rate_count_diff = 0; - bool bSwitchFromCountDiff = false; - bool bDoubleTimeInterval = false; - - if (priv->rtllib->link_state == MAC80211_LINKED && - priv->rtllib->bfsync_enable && - (priv->rtllib->ht_info->iot_action & HT_IOT_ACT_CDD_FSYNC)) { - u32 rate_bitmap; - - for (rate_index = 0; rate_index <= 27; rate_index++) { - rate_bitmap = 1 << rate_index; - if (priv->rtllib->fsync_rate_bitmap & rate_bitmap) - rate_count += - priv->stats.received_rate_histogram[1] - [rate_index]; - } - - if (rate_count < priv->rate_record) - rate_count_diff = 0xffffffff - rate_count + - priv->rate_record; - else - rate_count_diff = rate_count - priv->rate_record; - if (rate_count_diff < priv->rate_count_diff_rec) { - u32 DiffNum = priv->rate_count_diff_rec - - rate_count_diff; - if (DiffNum >= - priv->rtllib->fsync_seconddiff_ratethreshold) - priv->continue_diff_count++; - else - priv->continue_diff_count = 0; - - if (priv->continue_diff_count >= 2) { - bSwitchFromCountDiff = true; - priv->continue_diff_count = 0; - } - } else { - priv->continue_diff_count = 0; - } - - if (rate_count_diff <= - priv->rtllib->fsync_firstdiff_ratethreshold) { - bSwitchFromCountDiff = true; - priv->continue_diff_count = 0; - } - priv->rate_record = rate_count; - priv->rate_count_diff_rec = rate_count_diff; - if (priv->undecorated_smoothed_pwdb > - priv->rtllib->fsync_rssi_threshold && - bSwitchFromCountDiff) { - bDoubleTimeInterval = true; - priv->bswitch_fsync = !priv->bswitch_fsync; - if (priv->bswitch_fsync) { - rtl92e_writeb(dev, 0xC36, 0x1c); - rtl92e_writeb(dev, 0xC3e, 0x90); - } else { - rtl92e_writeb(dev, 0xC36, 0x5c); - rtl92e_writeb(dev, 0xC3e, 0x96); - } - } else if (priv->undecorated_smoothed_pwdb <= - priv->rtllib->fsync_rssi_threshold) { - if (priv->bswitch_fsync) { - priv->bswitch_fsync = false; - rtl92e_writeb(dev, 0xC36, 0x5c); - rtl92e_writeb(dev, 0xC3e, 0x96); - } - } - if (bDoubleTimeInterval) { - if (timer_pending(&priv->fsync_timer)) - del_timer_sync(&priv->fsync_timer); - priv->fsync_timer.expires = jiffies + - msecs_to_jiffies(priv->rtllib->fsync_time_interval * - priv->rtllib->fsync_multiple_timeinterval); - add_timer(&priv->fsync_timer); - } else { - if (timer_pending(&priv->fsync_timer)) - del_timer_sync(&priv->fsync_timer); - priv->fsync_timer.expires = jiffies + - msecs_to_jiffies(priv->rtllib->fsync_time_interval); - add_timer(&priv->fsync_timer); - } - } else { - if (priv->bswitch_fsync) { - priv->bswitch_fsync = false; - rtl92e_writeb(dev, 0xC36, 0x5c); - rtl92e_writeb(dev, 0xC3e, 0x96); - } - priv->continue_diff_count = 0; - rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd); - } -} - -static void _rtl92e_dm_start_hw_fsync(struct net_device *dev) -{ - u8 rf_timing = 0x77; - struct r8192_priv *priv = rtllib_priv(dev); - - rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c12cf); - priv->rtllib->set_hw_reg_handler(dev, HW_VAR_RF_TIMING, - (u8 *)(&rf_timing)); - rtl92e_writeb(dev, 0xc3b, 0x41); -} - -static void _rtl92e_dm_end_hw_fsync(struct net_device *dev) -{ - u8 rf_timing = 0xaa; - struct r8192_priv *priv = rtllib_priv(dev); - - rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd); - priv->rtllib->set_hw_reg_handler(dev, HW_VAR_RF_TIMING, (u8 *) - (&rf_timing)); - rtl92e_writeb(dev, 0xc3b, 0x49); -} - -static void _rtl92e_dm_end_sw_fsync(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - del_timer_sync(&(priv->fsync_timer)); - - if (priv->bswitch_fsync) { - priv->bswitch_fsync = false; - - rtl92e_writeb(dev, 0xC36, 0x5c); - - rtl92e_writeb(dev, 0xC3e, 0x96); - } - - priv->continue_diff_count = 0; - rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd); -} - -static void _rtl92e_dm_start_sw_fsync(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u32 rate_index; - u32 rate_bitmap; - - priv->rate_record = 0; - priv->continue_diff_count = 0; - priv->rate_count_diff_rec = 0; - priv->bswitch_fsync = false; - - if (priv->rtllib->mode == WIRELESS_MODE_N_24G) { - priv->rtllib->fsync_firstdiff_ratethreshold = 600; - priv->rtllib->fsync_seconddiff_ratethreshold = 0xffff; - } else { - priv->rtllib->fsync_firstdiff_ratethreshold = 200; - priv->rtllib->fsync_seconddiff_ratethreshold = 200; - } - for (rate_index = 0; rate_index <= 27; rate_index++) { - rate_bitmap = 1 << rate_index; - if (priv->rtllib->fsync_rate_bitmap & rate_bitmap) - priv->rate_record += - priv->stats.received_rate_histogram[1] - [rate_index]; - } - if (timer_pending(&priv->fsync_timer)) - del_timer_sync(&priv->fsync_timer); - priv->fsync_timer.expires = jiffies + - msecs_to_jiffies(priv->rtllib->fsync_time_interval); - add_timer(&priv->fsync_timer); - - rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c12cd); -} - -static void _rtl92e_dm_check_fsync(struct net_device *dev) -{ -#define RegC38_Default 0 -#define RegC38_NonFsync_Other_AP 1 -#define RegC38_Fsync_AP_BCM 2 - struct r8192_priv *priv = rtllib_priv(dev); - static u8 reg_c38_State = RegC38_Default; - - if (priv->rtllib->link_state == MAC80211_LINKED && - priv->rtllib->ht_info->iot_peer == HT_IOT_PEER_BROADCOM) { - if (priv->rtllib->bfsync_enable == 0) { - switch (priv->rtllib->fsync_state) { - case DEFAULT_FSYNC: - _rtl92e_dm_start_hw_fsync(dev); - priv->rtllib->fsync_state = HW_FSYNC; - break; - case SW_FSYNC: - _rtl92e_dm_end_sw_fsync(dev); - _rtl92e_dm_start_hw_fsync(dev); - priv->rtllib->fsync_state = HW_FSYNC; - break; - default: - break; - } - } else { - switch (priv->rtllib->fsync_state) { - case DEFAULT_FSYNC: - _rtl92e_dm_start_sw_fsync(dev); - priv->rtllib->fsync_state = SW_FSYNC; - break; - case HW_FSYNC: - _rtl92e_dm_end_hw_fsync(dev); - _rtl92e_dm_start_sw_fsync(dev); - priv->rtllib->fsync_state = SW_FSYNC; - break; - default: - break; - } - } - if (reg_c38_State != RegC38_Fsync_AP_BCM) { - rtl92e_writeb(dev, rOFDM0_RxDetector3, 0x95); - - reg_c38_State = RegC38_Fsync_AP_BCM; - } - } else { - switch (priv->rtllib->fsync_state) { - case HW_FSYNC: - _rtl92e_dm_end_hw_fsync(dev); - priv->rtllib->fsync_state = DEFAULT_FSYNC; - break; - case SW_FSYNC: - _rtl92e_dm_end_sw_fsync(dev); - priv->rtllib->fsync_state = DEFAULT_FSYNC; - break; - default: - break; - } - - if (priv->rtllib->link_state == MAC80211_LINKED) { - if (priv->undecorated_smoothed_pwdb <= - REG_C38_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 >= - (REG_C38_TH + 5)) { - if (reg_c38_State) { - 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; - } - } - } -} - -/*---------------------------Define function prototype------------------------*/ -static void _rtl92e_dm_init_dynamic_tx_power(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->rtllib->bdynamic_txpower_enable = true; - priv->last_dtp_flag_high = false; - priv->last_dtp_flag_low = false; - priv->dynamic_tx_high_pwr = false; - priv->dynamic_tx_low_pwr = false; -} - -static void _rtl92e_dm_dynamic_tx_power(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - unsigned int txhipower_threshold = 0; - unsigned int txlowpower_threshold = 0; - - if (!priv->rtllib->bdynamic_txpower_enable) { - priv->dynamic_tx_high_pwr = false; - priv->dynamic_tx_low_pwr = false; - return; - } - if ((priv->rtllib->ht_info->iot_peer == HT_IOT_PEER_ATHEROS) && - (priv->rtllib->mode == WIRELESS_MODE_G)) { - txhipower_threshold = TX_POWER_ATHEROAP_THRESH_HIGH; - txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW; - } else { - txhipower_threshold = TX_POWER_NEAR_FIELD_THRESH_HIGH; - txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW; - } - - if (priv->rtllib->link_state == MAC80211_LINKED) { - if (priv->undecorated_smoothed_pwdb >= txhipower_threshold) { - priv->dynamic_tx_high_pwr = true; - priv->dynamic_tx_low_pwr = false; - } else { - if (priv->undecorated_smoothed_pwdb < - txlowpower_threshold && priv->dynamic_tx_high_pwr) - priv->dynamic_tx_high_pwr = false; - if (priv->undecorated_smoothed_pwdb < 35) - priv->dynamic_tx_low_pwr = true; - else if (priv->undecorated_smoothed_pwdb >= 40) - priv->dynamic_tx_low_pwr = false; - } - } else { - priv->dynamic_tx_high_pwr = false; - priv->dynamic_tx_low_pwr = false; - } - - if ((priv->dynamic_tx_high_pwr != priv->last_dtp_flag_high) || - (priv->dynamic_tx_low_pwr != priv->last_dtp_flag_low)) { - rtl92e_set_tx_power(dev, priv->rtllib->current_network.channel); - } - priv->last_dtp_flag_high = priv->dynamic_tx_high_pwr; - priv->last_dtp_flag_low = priv->dynamic_tx_low_pwr; -} - -static void _rtl92e_dm_check_txrateandretrycount(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - - ieee->softmac_stats.CurrentShowTxate = rtl92e_readb(dev, CURRENT_TX_RATE_REG); - ieee->softmac_stats.last_packet_rate = rtl92e_readb(dev, INITIAL_TX_RATE_REG); - ieee->softmac_stats.txretrycount = rtl92e_readl(dev, TX_RETRY_COUNT_REG); -} - -static void _rtl92e_dm_send_rssi_to_fw(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - rtl92e_writeb(dev, DRIVER_RSSI, priv->undecorated_smoothed_pwdb); -} diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h deleted file mode 100644 index 55641f17412b48..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ /dev/null @@ -1,155 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef __R8192UDM_H__ -#define __R8192UDM_H__ - -/*--------------------------Define Parameters-------------------------------*/ -#define OFDM_TABLE_LEN 19 -#define CCK_TABLE_LEN 12 - -#define DM_DIG_THRESH_HIGH 40 -#define DM_DIG_THRESH_LOW 35 - -#define DM_DIG_HIGH_PWR_THRESH_HIGH 75 -#define DM_DIG_HIGH_PWR_THRESH_LOW 70 - -#define BW_AUTO_SWITCH_HIGH_LOW 25 -#define BW_AUTO_SWITCH_LOW_HIGH 30 - -#define DM_DIG_BACKOFF 12 -#define DM_DIG_MAX 0x36 -#define DM_DIG_MIN 0x1c -#define DM_DIG_MIN_Netcore 0x12 - -#define RX_PATH_SEL_SS_TH_LOW 30 -#define RX_PATH_SEL_DIFF_TH 18 - -#define RATE_ADAPTIVE_TH_HIGH 50 -#define RATE_ADAPTIVE_TH_LOW_20M 30 -#define RATE_ADAPTIVE_TH_LOW_40M 10 -#define VERY_LOW_RSSI 15 - -#define E_FOR_TX_POWER_TRACK 300 -#define TX_POWER_NEAR_FIELD_THRESH_HIGH 68 -#define TX_POWER_NEAR_FIELD_THRESH_LOW 62 -#define TX_POWER_ATHEROAP_THRESH_HIGH 78 -#define TX_POWER_ATHEROAP_THRESH_LOW 72 - -#define CURRENT_TX_RATE_REG 0x1e0 -#define INITIAL_TX_RATE_REG 0x1e1 -#define TX_RETRY_COUNT_REG 0x1ac -#define REG_C38_TH 20 - -/*--------------------------Define Parameters-------------------------------*/ - -/*------------------------------Define structure----------------------------*/ -struct dig_t { - long rssi_low_thresh; - long rssi_high_thresh; - - long rssi_high_power_lowthresh; - long rssi_high_power_highthresh; - - u8 cur_sta_connect_state; - u8 pre_sta_connect_state; - - u8 curpd_thstate; - u8 prepd_thstate; - u8 curcs_ratio_state; - u8 precs_ratio_state; - - u32 pre_ig_value; - u32 cur_ig_value; - - u8 backoff_val; - u8 rx_gain_range_max; - u8 rx_gain_range_min; - - long rssi_val; -}; - -enum dm_ratr_sta { - DM_RATR_STA_HIGH = 0, - DM_RATR_STA_MIDDLE = 1, - DM_RATR_STA_LOW = 2, - DM_RATR_STA_MAX -}; - -enum dm_dig_connect { - DIG_STA_DISCONNECT = 0, - DIG_STA_CONNECT = 1, -}; - -enum dm_dig_pd_th { - DIG_PD_AT_LOW_POWER = 0, - DIG_PD_AT_NORMAL_POWER = 1, - DIG_PD_AT_HIGH_POWER = 2, - DIG_PD_MAX -}; - -enum dm_dig_cs_ratio { - DIG_CS_RATIO_LOWER = 0, - DIG_CS_RATIO_HIGHER = 1, - DIG_CS_MAX -}; - -struct drx_path_sel { - u8 enable; - u8 cck_method; - u8 cck_rx_path; - - u8 ss_th_low; - u8 diff_th; - u8 disabled_rf; - u8 reserved; - - u8 rf_rssi[4]; - u8 rf_enable_rssi_th[4]; - long cck_pwdb_sta[4]; -}; - -enum dm_cck_rx_path_method { - CCK_Rx_Version_1 = 0, - CCK_Rx_Version_2 = 1, - CCK_Rx_Version_MAX -}; - -struct dcmd_txcmd { - u32 op; - u32 length; - u32 value; -}; - -/*------------------------------Define structure----------------------------*/ - -/*------------------------Export global variable----------------------------*/ -extern struct dig_t dm_digtable; - -/* Pre-calculated gain tables */ -extern const u32 dm_tx_bb_gain[TX_BB_GAIN_TABLE_LEN]; -extern const u8 dm_cck_tx_bb_gain[CCK_TX_BB_GAIN_TABLE_LEN][8]; -extern const u8 dm_cck_tx_bb_gain_ch14[CCK_TX_BB_GAIN_TABLE_LEN][8]; - -/*------------------------Export global variable----------------------------*/ - -/*--------------------------Exported Function prototype---------------------*/ -/*--------------------------Exported Function prototype---------------------*/ - -void rtl92e_dm_init(struct net_device *dev); -void rtl92e_dm_deinit(struct net_device *dev); - -void rtl92e_dm_watchdog(struct net_device *dev); - -void rtl92e_init_adaptive_rate(struct net_device *dev); -void rtl92e_dm_txpower_tracking_wq(void *data); - -void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14); - -void rtl92e_dm_init_edca_turbo(struct net_device *dev); -void rtl92e_dm_rf_pathcheck_wq(void *data); -void rtl92e_dm_init_txpower_tracking(struct net_device *dev); -#endif /*__R8192UDM_H__ */ diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c deleted file mode 100644 index db57c655c6953a..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#include "rtl_core.h" -#include "rtl_eeprom.h" - -static void _rtl92e_gpio_write_bit(struct net_device *dev, int no, bool val) -{ - u8 reg = rtl92e_readb(dev, EPROM_CMD); - - if (val) - reg |= 1 << no; - else - reg &= ~(1 << no); - - rtl92e_writeb(dev, EPROM_CMD, reg); - udelay(EPROM_DELAY); -} - -static bool _rtl92e_gpio_get_bit(struct net_device *dev, int no) -{ - u8 reg = rtl92e_readb(dev, EPROM_CMD); - - return (reg >> no) & 0x1; -} - -static void _rtl92e_eeprom_ck_cycle(struct net_device *dev) -{ - _rtl92e_gpio_write_bit(dev, EPROM_CK_BIT, 1); - _rtl92e_gpio_write_bit(dev, EPROM_CK_BIT, 0); -} - -static u16 _rtl92e_eeprom_xfer(struct net_device *dev, u16 data, int tx_len) -{ - u16 ret = 0; - int rx_len = 16; - - _rtl92e_gpio_write_bit(dev, EPROM_CS_BIT, 1); - _rtl92e_eeprom_ck_cycle(dev); - - while (tx_len--) { - _rtl92e_gpio_write_bit(dev, EPROM_W_BIT, - (data >> tx_len) & 0x1); - _rtl92e_eeprom_ck_cycle(dev); - } - - _rtl92e_gpio_write_bit(dev, EPROM_W_BIT, 0); - - while (rx_len--) { - _rtl92e_eeprom_ck_cycle(dev); - ret |= _rtl92e_gpio_get_bit(dev, EPROM_R_BIT) << rx_len; - } - - _rtl92e_gpio_write_bit(dev, EPROM_CS_BIT, 0); - _rtl92e_eeprom_ck_cycle(dev); - - return ret; -} - -u32 rtl92e_eeprom_read(struct net_device *dev, u32 addr) -{ - struct r8192_priv *priv = rtllib_priv(dev); - u32 ret = 0; - - rtl92e_writeb(dev, EPROM_CMD, - (EPROM_CMD_PROGRAM << EPROM_CMD_OPERATING_MODE_SHIFT)); - udelay(EPROM_DELAY); - - /* EEPROM is configured as x16 */ - if (priv->epromtype == EEPROM_93C56) - ret = _rtl92e_eeprom_xfer(dev, (addr & 0xFF) | (0x6 << 8), 11); - else - ret = _rtl92e_eeprom_xfer(dev, (addr & 0x3F) | (0x6 << 6), 9); - - rtl92e_writeb(dev, EPROM_CMD, - (EPROM_CMD_NORMAL << EPROM_CMD_OPERATING_MODE_SHIFT)); - return ret; -} diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h deleted file mode 100644 index 66f1979bb1d573..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#define EPROM_DELAY 10 - -u32 rtl92e_eeprom_read(struct net_device *dev, u32 addr); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c deleted file mode 100644 index fab8932e67dae5..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ethtool.c +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#include -#include -#include - -#include "rtl_core.h" - -static void _rtl92e_ethtool_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - strscpy(info->driver, DRV_NAME, sizeof(info->driver)); - strscpy(info->version, DRV_VERSION, sizeof(info->version)); - strscpy(info->bus_info, pci_name(priv->pdev), sizeof(info->bus_info)); -} - -static u32 _rtl92e_ethtool_get_link(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return ((priv->rtllib->link_state == MAC80211_LINKED) || - (priv->rtllib->link_state == MAC80211_LINKED_SCANNING)); -} - -const struct ethtool_ops rtl819x_ethtool_ops = { - .get_drvinfo = _rtl92e_ethtool_get_drvinfo, - .get_link = _rtl92e_ethtool_get_link, -}; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c deleted file mode 100644 index 1aa73561581b2a..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#include "rtl_pci.h" -#include "rtl_core.h" - -static void _rtl92e_parse_pci_configuration(struct pci_dev *pdev, - struct net_device *dev) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - - u8 tmp; - u16 link_ctrl_reg; - - pcie_capability_read_word(priv->pdev, PCI_EXP_LNKCTL, &link_ctrl_reg); - - pci_read_config_byte(pdev, 0x98, &tmp); - tmp |= BIT(4); - pci_write_config_byte(pdev, 0x98, tmp); - - tmp = 0x17; - pci_write_config_byte(pdev, 0x70f, tmp); -} - -bool rtl92e_check_adapter(struct pci_dev *pdev, struct net_device *dev) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - u16 device_id; - u8 revision_id; - u16 irq_line; - - device_id = pdev->device; - revision_id = pdev->revision; - pci_read_config_word(pdev, 0x3C, &irq_line); - - priv->card_8192 = NIC_8192E; - - if (device_id == 0x8192) { - switch (revision_id) { - case HAL_HW_PCI_REVISION_ID_8192PCIE: - dev_info(&pdev->dev, - "Adapter(8192 PCI-E) is found - DeviceID=%x\n", - device_id); - priv->card_8192 = NIC_8192E; - break; - case HAL_HW_PCI_REVISION_ID_8192SE: - dev_info(&pdev->dev, - "Adapter(8192SE) is found - DeviceID=%x\n", - device_id); - priv->card_8192 = NIC_8192SE; - break; - default: - dev_info(&pdev->dev, - "UNKNOWN nic type(%4x:%4x)\n", - pdev->vendor, pdev->device); - priv->card_8192 = NIC_UNKNOWN; - return false; - } - } - - if (priv->card_8192 != NIC_8192E) { - dev_info(&pdev->dev, - "Detect info(%x) and hardware info(%x) not match!\n", - NIC_8192E, priv->card_8192); - dev_info(&pdev->dev, - "Please select proper driver before install!!!!\n"); - return false; - } - - _rtl92e_parse_pci_configuration(pdev, dev); - - return true; -} diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h deleted file mode 100644 index 3e39c4835ac817..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#ifndef _RTL_PCI_H -#define _RTL_PCI_H - -#include -#include - -struct net_device; - -bool rtl92e_check_adapter(struct pci_dev *pdev, struct net_device *dev); - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c deleted file mode 100644 index d124b5eee0cc9b..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include "rtl_core.h" -#include "r8192E_hw.h" -#include "r8190P_rtl8256.h" -#include "rtl_pm.h" - -int rtl92e_suspend(struct device *dev_d) -{ - struct net_device *dev = dev_get_drvdata(dev_d); - struct r8192_priv *priv = rtllib_priv(dev); - u32 ulRegRead; - - netdev_info(dev, "============> r8192E suspend call.\n"); - del_timer_sync(&priv->gpio_polling_timer); - cancel_delayed_work_sync(&priv->gpio_change_rf_wq); - priv->polling_timer_on = 0; - - if (!netif_running(dev)) { - netdev_info(dev, - "RTL819XE:UI is open out of suspend function\n"); - goto out_pci_suspend; - } - - if (dev->netdev_ops->ndo_stop) - dev->netdev_ops->ndo_stop(dev); - netif_device_detach(dev); - - if (!priv->rtllib->bSupportRemoteWakeUp) { - rtl92e_set_rf_state(dev, rf_off, RF_CHANGE_BY_INIT); - ulRegRead = rtl92e_readl(dev, CPU_GEN); - ulRegRead |= CPU_GEN_SYSTEM_RESET; - rtl92e_writel(dev, CPU_GEN, ulRegRead); - } else { - rtl92e_writel(dev, WFCRC0, 0xffffffff); - rtl92e_writel(dev, WFCRC1, 0xffffffff); - rtl92e_writel(dev, WFCRC2, 0xffffffff); - rtl92e_writeb(dev, PMR, 0x5); - rtl92e_writeb(dev, MAC_BLK_CTRL, 0xa); - } -out_pci_suspend: - netdev_info(dev, "WOL is %s\n", priv->rtllib->bSupportRemoteWakeUp ? - "Supported" : "Not supported"); - device_set_wakeup_enable(dev_d, priv->rtllib->bSupportRemoteWakeUp); - - mdelay(20); - - return 0; -} - -int rtl92e_resume(struct device *dev_d) -{ - struct pci_dev *pdev = to_pci_dev(dev_d); - struct net_device *dev = dev_get_drvdata(dev_d); - struct r8192_priv *priv = rtllib_priv(dev); - u32 val; - - netdev_info(dev, "================>r8192E resume call.\n"); - - pci_read_config_dword(pdev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - - device_wakeup_disable(dev_d); - - if (priv->polling_timer_on == 0) - rtl92e_check_rfctrl_gpio_timer(&priv->gpio_polling_timer); - - if (!netif_running(dev)) { - netdev_info(dev, - "RTL819XE:UI is open out of resume function\n"); - goto out; - } - - netif_device_attach(dev); - if (dev->netdev_ops->ndo_open) - dev->netdev_ops->ndo_open(dev); - - if (!priv->rtllib->bSupportRemoteWakeUp) - rtl92e_set_rf_state(dev, rf_on, RF_CHANGE_BY_INIT); - -out: - return 0; -} - diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h deleted file mode 100644 index fd86114959753f..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef R8192E_PM_H -#define R8192E_PM_H - -#include -#include - -int rtl92e_suspend(struct device *dev_d); -int rtl92e_resume(struct device *dev_d); - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c deleted file mode 100644 index 7b6247acf6f4a2..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#include "rtl_ps.h" -#include "rtl_core.h" -#include "r8192E_phy.h" -#include "r8192E_phyreg.h" -#include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */ -#include "r8192E_cmdpkt.h" -#include - -static void _rtl92e_hw_sleep(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - unsigned long flags = 0; - - spin_lock_irqsave(&priv->rf_ps_lock, flags); - if (priv->rf_change_in_progress) { - spin_unlock_irqrestore(&priv->rf_ps_lock, flags); - return; - } - spin_unlock_irqrestore(&priv->rf_ps_lock, flags); - rtl92e_set_rf_state(dev, rf_sleep, RF_CHANGE_BY_PS); -} - -void rtl92e_hw_sleep_wq(void *data) -{ - struct rtllib_device *ieee = container_of_dwork_rsl(data, - struct rtllib_device, hw_sleep_wq); - struct net_device *dev = ieee->dev; - - _rtl92e_hw_sleep(dev); -} - -void rtl92e_hw_wakeup(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - unsigned long flags = 0; - - spin_lock_irqsave(&priv->rf_ps_lock, flags); - if (priv->rf_change_in_progress) { - spin_unlock_irqrestore(&priv->rf_ps_lock, flags); - schedule_delayed_work(&priv->rtllib->hw_wakeup_wq, - msecs_to_jiffies(10)); - return; - } - spin_unlock_irqrestore(&priv->rf_ps_lock, flags); - rtl92e_set_rf_state(dev, rf_on, RF_CHANGE_BY_PS); -} - -void rtl92e_hw_wakeup_wq(void *data) -{ - struct rtllib_device *ieee = container_of_dwork_rsl(data, - struct rtllib_device, hw_wakeup_wq); - struct net_device *dev = ieee->dev; - - rtl92e_hw_wakeup(dev); -} - -#define MIN_SLEEP_TIME 50 -#define MAX_SLEEP_TIME 10000 -void rtl92e_enter_sleep(struct net_device *dev, u64 time) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - u32 tmp; - unsigned long flags; - unsigned long timeout; - - spin_lock_irqsave(&priv->ps_lock, flags); - - time -= msecs_to_jiffies(8 + 16 + 7); - - timeout = jiffies + msecs_to_jiffies(MIN_SLEEP_TIME); - if (time_before((unsigned long)time, timeout)) { - spin_unlock_irqrestore(&priv->ps_lock, flags); - netdev_info(dev, "too short to sleep::%lld < %ld\n", - time - jiffies, msecs_to_jiffies(MIN_SLEEP_TIME)); - return; - } - timeout = jiffies + msecs_to_jiffies(MAX_SLEEP_TIME); - if (time_after((unsigned long)time, timeout)) { - netdev_info(dev, "========>too long to sleep:%lld > %ld\n", - time - jiffies, msecs_to_jiffies(MAX_SLEEP_TIME)); - spin_unlock_irqrestore(&priv->ps_lock, flags); - return; - } - tmp = time - jiffies; - schedule_delayed_work(&priv->rtllib->hw_wakeup_wq, tmp); - schedule_delayed_work(&priv->rtllib->hw_sleep_wq, 0); - spin_unlock_irqrestore(&priv->ps_lock, flags); -} - -static void _rtl92e_ps_update_rf_state(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - &priv->rtllib->pwr_save_ctrl; - - psc->bSwRfProcessing = true; - rtl92e_set_rf_state(dev, psc->eInactivePowerState, RF_CHANGE_BY_IPS); - - psc->bSwRfProcessing = false; -} - -void rtl92e_ips_enter(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - &priv->rtllib->pwr_save_ctrl; - enum rt_rf_power_state rt_state; - - rt_state = priv->rtllib->rf_power_state; - if (rt_state == rf_on && !psc->bSwRfProcessing && - (priv->rtllib->link_state != MAC80211_LINKED)) { - psc->eInactivePowerState = rf_off; - _rtl92e_ps_update_rf_state(dev); - } -} - -void rtl92e_ips_leave(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - &priv->rtllib->pwr_save_ctrl; - enum rt_rf_power_state rt_state; - - rt_state = priv->rtllib->rf_power_state; - if (rt_state != rf_on && !psc->bSwRfProcessing && - priv->rtllib->rf_off_reason <= RF_CHANGE_BY_IPS) { - psc->eInactivePowerState = rf_on; - _rtl92e_ps_update_rf_state(dev); - } -} - -void rtl92e_ips_leave_wq(void *data) -{ - 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); - - mutex_lock(&priv->rtllib->ips_mutex); - rtl92e_ips_leave(dev); - mutex_unlock(&priv->rtllib->ips_mutex); -} - -void rtl92e_rtllib_ips_leave_wq(struct net_device *dev) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - enum rt_rf_power_state rt_state; - - rt_state = priv->rtllib->rf_power_state; - if (rt_state == rf_off) { - if (priv->rtllib->rf_off_reason > RF_CHANGE_BY_IPS) { - netdev_warn(dev, "%s(): RF is OFF.\n", - __func__); - return; - } - netdev_info(dev, "=========>%s(): rtl92e_ips_leave\n", - __func__); - schedule_work(&priv->rtllib->ips_leave_wq); - } -} - -void rtl92e_rtllib_ips_leave(struct net_device *dev) -{ - struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - - mutex_lock(&priv->rtllib->ips_mutex); - rtl92e_ips_leave(dev); - mutex_unlock(&priv->rtllib->ips_mutex); -} - -static bool _rtl92e_ps_set_mode(struct net_device *dev, u8 rtPsMode) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->rtllib->ps = rtPsMode; - if (priv->rtllib->sta_sleep != LPS_IS_WAKE && - rtPsMode == RTLLIB_PS_DISABLED) { - unsigned long flags; - - rtl92e_hw_wakeup(dev); - priv->rtllib->sta_sleep = LPS_IS_WAKE; - - spin_lock_irqsave(&(priv->rtllib->mgmt_tx_lock), flags); - rtllib_sta_ps_send_null_frame(priv->rtllib, 0); - spin_unlock_irqrestore(&(priv->rtllib->mgmt_tx_lock), flags); - } - - return true; -} - -void rtl92e_leisure_ps_enter(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - &priv->rtllib->pwr_save_ctrl; - - if (!((priv->rtllib->iw_mode == IW_MODE_INFRA) && - (priv->rtllib->link_state == MAC80211_LINKED))) - return; - - if (psc->bLeisurePs) { - if (psc->lps_idle_count >= RT_CHECK_FOR_HANG_PERIOD) { - if (priv->rtllib->ps == RTLLIB_PS_DISABLED) - _rtl92e_ps_set_mode(dev, RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST); - } else { - psc->lps_idle_count++; - } - } -} - -void rtl92e_leisure_ps_leave(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rt_pwr_save_ctrl *psc = (struct rt_pwr_save_ctrl *) - &priv->rtllib->pwr_save_ctrl; - - if (psc->bLeisurePs) { - if (priv->rtllib->ps != RTLLIB_PS_DISABLED) - _rtl92e_ps_set_mode(dev, RTLLIB_PS_DISABLED); - } -} diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h deleted file mode 100644 index 70fe5d39be9a8d..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Based on the r8180 driver, which is: - * Copyright 2004-2005 Andrea Merello , et al. - * - * Contact Information: wlanfae - */ -#ifndef _RTL_PS_H -#define _RTL_PS_H - -#include - -struct net_device; - -#define RT_CHECK_FOR_HANG_PERIOD 2 - -void rtl92e_hw_wakeup(struct net_device *dev); -void rtl92e_enter_sleep(struct net_device *dev, u64 time); -void rtl92e_rtllib_ips_leave_wq(struct net_device *dev); -void rtl92e_rtllib_ips_leave(struct net_device *dev); -void rtl92e_ips_leave_wq(void *data); - -void rtl92e_ips_enter(struct net_device *dev); -void rtl92e_ips_leave(struct net_device *dev); - -void rtl92e_leisure_ps_enter(struct net_device *dev); -void rtl92e_leisure_ps_leave(struct net_device *dev); - -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c deleted file mode 100644 index fe3a42a4fcd5a9..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ /dev/null @@ -1,867 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include -#include "rtl_core.h" -#include "rtl_wx.h" - -#define RATE_COUNT 12 -static u32 rtl8192_rates[] = { - 1000000, 2000000, 5500000, 11000000, 6000000, 9000000, 12000000, - 18000000, 24000000, 36000000, 48000000, 54000000 -}; - -#ifndef ENETDOWN -#define ENETDOWN 1 -#endif - -static int _rtl92e_wx_get_freq(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return rtllib_wx_get_freq(priv->rtllib, a, wrqu, b); -} - -static int _rtl92e_wx_get_mode(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return rtllib_wx_get_mode(priv->rtllib, a, wrqu, b); -} - -static int _rtl92e_wx_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return rtllib_wx_get_rate(priv->rtllib, info, wrqu, extra); -} - -static int _rtl92e_wx_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - - ret = rtllib_wx_set_rate(priv->rtllib, info, wrqu, extra); - - mutex_unlock(&priv->wx_mutex); - - return ret; -} - -static int _rtl92e_wx_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - - ret = rtllib_wx_set_rts(priv->rtllib, info, wrqu, extra); - - mutex_unlock(&priv->wx_mutex); - - return ret; -} - -static int _rtl92e_wx_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return rtllib_wx_get_rts(priv->rtllib, info, wrqu, extra); -} - -static int _rtl92e_wx_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) { - netdev_warn(dev, "%s(): Can't set Power: Radio is Off.\n", - __func__); - return 0; - } - mutex_lock(&priv->wx_mutex); - - ret = rtllib_wx_set_power(priv->rtllib, info, wrqu, extra); - - mutex_unlock(&priv->wx_mutex); - - return ret; -} - -static int _rtl92e_wx_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return rtllib_wx_get_power(priv->rtllib, info, wrqu, extra); -} - -static int _rtl92e_wx_set_mode(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - enum rt_rf_power_state rt_state; - int ret; - - if (priv->hw_radio_off) - return 0; - rt_state = priv->rtllib->rf_power_state; - mutex_lock(&priv->wx_mutex); - if (wrqu->mode == IW_MODE_MONITOR) { - if (rt_state == rf_off) { - if (priv->rtllib->rf_off_reason > - RF_CHANGE_BY_IPS) { - netdev_warn(dev, "%s(): RF is OFF.\n", - __func__); - mutex_unlock(&priv->wx_mutex); - return -1; - } - netdev_info(dev, - "=========>%s(): rtl92e_ips_leave\n", - __func__); - mutex_lock(&priv->rtllib->ips_mutex); - rtl92e_ips_leave(dev); - mutex_unlock(&priv->rtllib->ips_mutex); - } - } - ret = rtllib_wx_set_mode(priv->rtllib, a, wrqu, b); - - mutex_unlock(&priv->wx_mutex); - return ret; -} - -static int _rtl92e_wx_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - struct r8192_priv *priv = rtllib_priv(dev); - u16 val; - int i; - - wrqu->data.length = sizeof(*range); - memset(range, 0, sizeof(*range)); - - /* ~130 Mb/s real (802.11n) */ - range->throughput = 130 * 1000 * 1000; - - range->max_qual.qual = 100; - range->max_qual.level = 0; - range->max_qual.noise = 0; - range->max_qual.updated = 7; /* Updated all three */ - - range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */ - range->avg_qual.level = 0; - range->avg_qual.noise = 0; - range->avg_qual.updated = 7; /* Updated all three */ - - range->num_bitrates = min(RATE_COUNT, IW_MAX_BITRATES); - - for (i = 0; i < range->num_bitrates; i++) - range->bitrate[i] = rtl8192_rates[i]; - - range->max_rts = DEFAULT_RTS_THRESHOLD; - range->min_frag = MIN_FRAG_THRESHOLD; - range->max_frag = MAX_FRAG_THRESHOLD; - - range->min_pmp = 0; - range->max_pmp = 5000000; - range->min_pmt = 0; - range->max_pmt = 65535 * 1000; - range->pmp_flags = IW_POWER_PERIOD; - range->pmt_flags = IW_POWER_TIMEOUT; - range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 18; - - for (i = 0, val = 0; i < 14; i++) { - if ((priv->rtllib->active_channel_map)[i + 1]) { - s32 freq_khz; - - range->freq[val].i = i + 1; - freq_khz = ieee80211_channel_to_freq_khz(i + 1, NL80211_BAND_2GHZ); - range->freq[val].m = freq_khz * 100; - range->freq[val].e = 1; - val++; - } - - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - range->num_channels = val; - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE; - - /* Event capability (kernel + driver) */ - - return 0; -} - -static int _rtl92e_wx_set_scan(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - enum rt_rf_power_state rt_state; - int ret; - - if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) { - if ((ieee->link_state >= RTLLIB_ASSOCIATING) && - (ieee->link_state <= RTLLIB_ASSOCIATING_AUTHENTICATED)) - return 0; - if ((priv->rtllib->link_state == MAC80211_LINKED) && - (priv->rtllib->cnt_after_link < 2)) - return 0; - } - - if (priv->hw_radio_off) { - netdev_info(dev, "================>%s(): hwradio off\n", - __func__); - return 0; - } - rt_state = priv->rtllib->rf_power_state; - if (!priv->up) - return -ENETDOWN; - if (priv->rtllib->link_detect_info.busy_traffic) - return -EAGAIN; - - if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { - struct iw_scan_req *req = (struct iw_scan_req *)b; - - if (req->essid_len) { - int len = min_t(int, req->essid_len, IW_ESSID_MAX_SIZE); - - ieee->current_network.ssid_len = len; - memcpy(ieee->current_network.ssid, req->essid, len); - } - } - - mutex_lock(&priv->wx_mutex); - - priv->rtllib->first_ie_in_scan = true; - - if (priv->rtllib->link_state != MAC80211_LINKED) { - if (rt_state == rf_off) { - if (priv->rtllib->rf_off_reason > - RF_CHANGE_BY_IPS) { - netdev_warn(dev, "%s(): RF is OFF.\n", - __func__); - mutex_unlock(&priv->wx_mutex); - return -1; - } - mutex_lock(&priv->rtllib->ips_mutex); - rtl92e_ips_leave(dev); - mutex_unlock(&priv->rtllib->ips_mutex); - } - rtllib_stop_scan(priv->rtllib); - if (priv->rtllib->rf_power_state != rf_off) { - priv->rtllib->actscanning = true; - - ieee->scan_operation_backup_handler(ieee->dev, SCAN_OPT_BACKUP); - - rtllib_start_scan_syncro(priv->rtllib); - - ieee->scan_operation_backup_handler(ieee->dev, SCAN_OPT_RESTORE); - } - ret = 0; - } else { - priv->rtllib->actscanning = true; - ret = rtllib_wx_set_scan(priv->rtllib, a, wrqu, b); - } - - mutex_unlock(&priv->wx_mutex); - return ret; -} - -static int _rtl92e_wx_get_scan(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int ret; - struct r8192_priv *priv = rtllib_priv(dev); - - if (!priv->up) - return -ENETDOWN; - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - - ret = rtllib_wx_get_scan(priv->rtllib, a, wrqu, b); - - mutex_unlock(&priv->wx_mutex); - - return ret; -} - -static int _rtl92e_wx_set_essid(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int ret; - - if (priv->hw_radio_off) { - netdev_info(dev, - "=========>%s():hw radio off,or Rf state is rf_off, return\n", - __func__); - return 0; - } - mutex_lock(&priv->wx_mutex); - ret = rtllib_wx_set_essid(priv->rtllib, a, wrqu, b); - - mutex_unlock(&priv->wx_mutex); - - return ret; -} - -static int _rtl92e_wx_get_essid(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int ret; - struct r8192_priv *priv = rtllib_priv(dev); - - mutex_lock(&priv->wx_mutex); - - ret = rtllib_wx_get_essid(priv->rtllib, a, wrqu, b); - - mutex_unlock(&priv->wx_mutex); - - return ret; -} - -static int _rtl92e_wx_set_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (wrqu->data.length > IW_ESSID_MAX_SIZE) - return -E2BIG; - mutex_lock(&priv->wx_mutex); - wrqu->data.length = min_t(size_t, wrqu->data.length, - sizeof(priv->nick)); - memset(priv->nick, 0, sizeof(priv->nick)); - memcpy(priv->nick, extra, wrqu->data.length); - mutex_unlock(&priv->wx_mutex); - return 0; -} - -static int _rtl92e_wx_get_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - mutex_lock(&priv->wx_mutex); - wrqu->data.length = strlen(priv->nick); - memcpy(extra, priv->nick, wrqu->data.length); - wrqu->data.flags = 1; /* active */ - mutex_unlock(&priv->wx_mutex); - return 0; -} - -static int _rtl92e_wx_set_freq(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int ret; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - - ret = rtllib_wx_set_freq(priv->rtllib, a, wrqu, b); - - mutex_unlock(&priv->wx_mutex); - return ret; -} - -static int _rtl92e_wx_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return rtllib_wx_get_name(priv->rtllib, info, wrqu, extra); -} - -static int _rtl92e_wx_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) - return 0; - - if (wrqu->frag.disabled) { - priv->rtllib->fts = DEFAULT_FRAG_THRESHOLD; - } else { - if (wrqu->frag.value < MIN_FRAG_THRESHOLD || - wrqu->frag.value > MAX_FRAG_THRESHOLD) - return -EINVAL; - - priv->rtllib->fts = wrqu->frag.value & ~0x1; - } - - return 0; -} - -static int _rtl92e_wx_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - wrqu->frag.value = priv->rtllib->fts; - wrqu->frag.fixed = 0; /* no auto select */ - wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); - - return 0; -} - -static int _rtl92e_wx_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *awrq, char *extra) -{ - int ret; - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - - ret = rtllib_wx_set_wap(priv->rtllib, info, awrq, extra); - - mutex_unlock(&priv->wx_mutex); - - return ret; -} - -static int _rtl92e_wx_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return rtllib_wx_get_wap(priv->rtllib, info, wrqu, extra); -} - -static int _rtl92e_wx_get_enc(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - return rtllib_wx_get_encode(priv->rtllib, info, wrqu, key); -} - -static int _rtl92e_wx_set_enc(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int ret; - - struct rtllib_device *ieee = priv->rtllib; - u32 hwkey[4] = {0, 0, 0, 0}; - u8 mask = 0xff; - u32 key_idx = 0; - u8 zero_addr[4][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x02}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x03} }; - int i; - - if (priv->hw_radio_off) - return 0; - - if (!priv->up) - return -ENETDOWN; - - priv->rtllib->wx_set_enc = 1; - mutex_lock(&priv->rtllib->ips_mutex); - rtl92e_ips_leave(dev); - mutex_unlock(&priv->rtllib->ips_mutex); - mutex_lock(&priv->wx_mutex); - - ret = rtllib_wx_set_encode(priv->rtllib, info, wrqu, key); - mutex_unlock(&priv->wx_mutex); - - if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { - ieee->pairwise_key_type = KEY_TYPE_NA; - ieee->group_key_type = KEY_TYPE_NA; - rtl92e_cam_reset(dev); - memset(priv->rtllib->swcamtable, 0, - sizeof(struct sw_cam_table) * 32); - goto end_hw_sec; - } - if (wrqu->encoding.length != 0) { - for (i = 0; i < 4; i++) { - hwkey[i] |= key[4 * i + 0] & mask; - if (i == 1 && (4 * i + 1) == wrqu->encoding.length) - mask = 0x00; - if (i == 3 && (4 * i + 1) == wrqu->encoding.length) - mask = 0x00; - hwkey[i] |= (key[4 * i + 1] & mask) << 8; - hwkey[i] |= (key[4 * i + 2] & mask) << 16; - hwkey[i] |= (key[4 * i + 3] & mask) << 24; - } - - switch (wrqu->encoding.flags & IW_ENCODE_INDEX) { - case 0: - key_idx = ieee->crypt_info.tx_keyidx; - break; - case 1: - key_idx = 0; - break; - case 2: - key_idx = 1; - break; - case 3: - key_idx = 2; - break; - case 4: - key_idx = 3; - break; - default: - break; - } - if (wrqu->encoding.length == 0x5) { - ieee->pairwise_key_type = KEY_TYPE_WEP40; - rtl92e_enable_hw_security_config(dev); - } - - else if (wrqu->encoding.length == 0xd) { - ieee->pairwise_key_type = KEY_TYPE_WEP104; - rtl92e_enable_hw_security_config(dev); - rtl92e_set_key(dev, key_idx, key_idx, KEY_TYPE_WEP104, - zero_addr[key_idx], 0, hwkey); - rtl92e_set_swcam(dev, key_idx, key_idx, KEY_TYPE_WEP104, - zero_addr[key_idx], hwkey); - } else { - netdev_info(dev, - "wrong type in WEP, not WEP40 and WEP104\n"); - } - } - -end_hw_sec: - priv->rtllib->wx_set_enc = 0; - return ret; -} - -#define R8192_MAX_RETRY 255 -static int _rtl92e_wx_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - int err = 0; - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - - if (wrqu->retry.flags & IW_RETRY_LIFETIME || - wrqu->retry.disabled) { - err = -EINVAL; - goto exit; - } - if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) { - err = -EINVAL; - goto exit; - } - - if (wrqu->retry.value > R8192_MAX_RETRY) { - err = -EINVAL; - goto exit; - } - if (wrqu->retry.flags & IW_RETRY_MAX) - priv->retry_rts = wrqu->retry.value; - else - priv->retry_data = wrqu->retry.value; - - rtl92e_commit(dev); -exit: - mutex_unlock(&priv->wx_mutex); - - return err; -} - -static int _rtl92e_wx_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - wrqu->retry.disabled = 0; /* can't be disabled */ - - if ((wrqu->retry.flags & IW_RETRY_TYPE) == - IW_RETRY_LIFETIME) - return -EINVAL; - - if (wrqu->retry.flags & IW_RETRY_MAX) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - wrqu->retry.value = priv->retry_rts; - } else { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; - wrqu->retry.value = priv->retry_data; - } - return 0; -} - -static int _rtl92e_wx_set_encode_ext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - - priv->rtllib->wx_set_enc = 1; - mutex_lock(&priv->rtllib->ips_mutex); - rtl92e_ips_leave(dev); - mutex_unlock(&priv->rtllib->ips_mutex); - - ret = rtllib_wx_set_encode_ext(ieee, info, wrqu, extra); - { - const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - const u8 zero[ETH_ALEN] = {0}; - u32 key[4] = {0}; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct iw_point *encoding = &wrqu->encoding; - u8 idx = 0, alg = 0, group = 0; - - if ((encoding->flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE) { - ieee->pairwise_key_type = KEY_TYPE_NA; - ieee->group_key_type = KEY_TYPE_NA; - rtl92e_cam_reset(dev); - memset(priv->rtllib->swcamtable, 0, - sizeof(struct sw_cam_table) * 32); - goto end_hw_sec; - } - alg = (ext->alg == IW_ENCODE_ALG_CCMP) ? KEY_TYPE_CCMP : - ext->alg; - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) - idx--; - group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY; - - if ((!group) || (alg == KEY_TYPE_WEP40)) { - if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40)) - alg = KEY_TYPE_WEP104; - ieee->pairwise_key_type = alg; - rtl92e_enable_hw_security_config(dev); - } - memcpy((u8 *)key, ext->key, 16); - - if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode != 2)) { - if (ext->key_len == 13) - ieee->pairwise_key_type = alg = KEY_TYPE_WEP104; - rtl92e_set_key(dev, idx, idx, alg, zero, 0, key); - rtl92e_set_swcam(dev, idx, idx, alg, zero, key); - } else if (group) { - ieee->group_key_type = alg; - rtl92e_set_key(dev, idx, idx, alg, broadcast_addr, 0, - key); - rtl92e_set_swcam(dev, idx, idx, alg, broadcast_addr, key); - } else { - if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && - ieee->ht_info->current_ht_support) - rtl92e_writeb(dev, 0x173, 1); - rtl92e_set_key(dev, 4, idx, alg, - (u8 *)ieee->ap_mac_addr, 0, key); - rtl92e_set_swcam(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, key); - } - } - -end_hw_sec: - priv->rtllib->wx_set_enc = 0; - mutex_unlock(&priv->wx_mutex); - return ret; -} - -static int _rtl92e_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - int ret = 0; - - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - ret = rtllib_wx_set_auth(priv->rtllib, info, &data->param, extra); - mutex_unlock(&priv->wx_mutex); - return ret; -} - -static int _rtl92e_wx_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - ret = rtllib_wx_set_mlme(priv->rtllib, info, wrqu, extra); - mutex_unlock(&priv->wx_mutex); - return ret; -} - -static int _rtl92e_wx_set_gen_ie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - int ret = 0; - - struct r8192_priv *priv = rtllib_priv(dev); - - if (priv->hw_radio_off) - return 0; - - mutex_lock(&priv->wx_mutex); - ret = rtllib_wx_set_gen_ie(priv->rtllib, extra, data->data.length); - mutex_unlock(&priv->wx_mutex); - return ret; -} - -static int _rtl92e_wx_get_gen_ie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - int ret = 0; - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - - if (ieee->wpa_ie_len == 0 || !ieee->wpa_ie) { - data->data.length = 0; - return 0; - } - - if (data->data.length < ieee->wpa_ie_len) - return -E2BIG; - - data->data.length = ieee->wpa_ie_len; - memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); - return ret; -} - -#define IW_IOCTL(x) ((x) - SIOCSIWCOMMIT) -static iw_handler r8192_wx_handlers[] = { - [IW_IOCTL(SIOCGIWNAME)] = _rtl92e_wx_get_name, - [IW_IOCTL(SIOCSIWFREQ)] = _rtl92e_wx_set_freq, - [IW_IOCTL(SIOCGIWFREQ)] = _rtl92e_wx_get_freq, - [IW_IOCTL(SIOCSIWMODE)] = _rtl92e_wx_set_mode, - [IW_IOCTL(SIOCGIWMODE)] = _rtl92e_wx_get_mode, - [IW_IOCTL(SIOCGIWRANGE)] = _rtl92e_wx_get_range, - [IW_IOCTL(SIOCSIWAP)] = _rtl92e_wx_set_wap, - [IW_IOCTL(SIOCGIWAP)] = _rtl92e_wx_get_wap, - [IW_IOCTL(SIOCSIWSCAN)] = _rtl92e_wx_set_scan, - [IW_IOCTL(SIOCGIWSCAN)] = _rtl92e_wx_get_scan, - [IW_IOCTL(SIOCSIWESSID)] = _rtl92e_wx_set_essid, - [IW_IOCTL(SIOCGIWESSID)] = _rtl92e_wx_get_essid, - [IW_IOCTL(SIOCSIWNICKN)] = _rtl92e_wx_set_nick, - [IW_IOCTL(SIOCGIWNICKN)] = _rtl92e_wx_get_nick, - [IW_IOCTL(SIOCSIWRATE)] = _rtl92e_wx_set_rate, - [IW_IOCTL(SIOCGIWRATE)] = _rtl92e_wx_get_rate, - [IW_IOCTL(SIOCSIWRTS)] = _rtl92e_wx_set_rts, - [IW_IOCTL(SIOCGIWRTS)] = _rtl92e_wx_get_rts, - [IW_IOCTL(SIOCSIWFRAG)] = _rtl92e_wx_set_frag, - [IW_IOCTL(SIOCGIWFRAG)] = _rtl92e_wx_get_frag, - [IW_IOCTL(SIOCSIWRETRY)] = _rtl92e_wx_set_retry, - [IW_IOCTL(SIOCGIWRETRY)] = _rtl92e_wx_get_retry, - [IW_IOCTL(SIOCSIWENCODE)] = _rtl92e_wx_set_enc, - [IW_IOCTL(SIOCGIWENCODE)] = _rtl92e_wx_get_enc, - [IW_IOCTL(SIOCSIWPOWER)] = _rtl92e_wx_set_power, - [IW_IOCTL(SIOCGIWPOWER)] = _rtl92e_wx_get_power, - [IW_IOCTL(SIOCSIWGENIE)] = _rtl92e_wx_set_gen_ie, - [IW_IOCTL(SIOCGIWGENIE)] = _rtl92e_wx_get_gen_ie, - [IW_IOCTL(SIOCSIWMLME)] = _rtl92e_wx_set_mlme, - [IW_IOCTL(SIOCSIWAUTH)] = _rtl92e_wx_set_auth, - [IW_IOCTL(SIOCSIWENCODEEXT)] = _rtl92e_wx_set_encode_ext, -}; - -static struct iw_statistics *_rtl92e_get_wireless_stats(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - struct rtllib_device *ieee = priv->rtllib; - struct iw_statistics *wstats = &priv->wstats; - int tmp_level = 0; - int tmp_qual = 0; - int tmp_noise = 0; - - if (ieee->link_state < MAC80211_LINKED) { - wstats->qual.qual = 10; - wstats->qual.level = 0; - wstats->qual.noise = 0x100 - 100; /* -100 dBm */ - wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - return wstats; - } - - tmp_level = (&ieee->current_network)->stats.rssi; - tmp_qual = (&ieee->current_network)->stats.signal; - tmp_noise = (&ieee->current_network)->stats.noise; - - wstats->qual.level = tmp_level; - wstats->qual.qual = tmp_qual; - wstats->qual.noise = tmp_noise; - wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - return wstats; -} - -const struct iw_handler_def r8192_wx_handlers_def = { - .standard = r8192_wx_handlers, - .num_standard = ARRAY_SIZE(r8192_wx_handlers), - .get_wireless_stats = _rtl92e_get_wireless_stats, -}; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h deleted file mode 100644 index d70a747ac1dd09..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef R819x_WX_H -#define R819x_WX_H - -struct iw_handler_def; - -extern const struct iw_handler_def r8192_wx_handlers_def; -#endif diff --git a/drivers/staging/rtl8192e/rtl8192e/table.c b/drivers/staging/rtl8192e/rtl8192e/table.c deleted file mode 100644 index 0b5cc60492323a..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/table.c +++ /dev/null @@ -1,543 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include "table.h" - -u32 RTL8192E_PHY_REG_1T2R_ARR[RTL8192E_PHY_REG_1T2R_ARR_LEN] = { - 0x800, 0x00000000, - 0x804, 0x00000001, - 0x808, 0x0000fc00, - 0x80c, 0x0000001c, - 0x810, 0x801010aa, - 0x814, 0x008514d0, - 0x818, 0x00000040, - 0x81c, 0x00000000, - 0x820, 0x00000004, - 0x824, 0x00690000, - 0x828, 0x00000004, - 0x82c, 0x00e90000, - 0x830, 0x00000004, - 0x834, 0x00690000, - 0x838, 0x00000004, - 0x83c, 0x00e90000, - 0x840, 0x00000000, - 0x844, 0x00000000, - 0x848, 0x00000000, - 0x84c, 0x00000000, - 0x850, 0x00000000, - 0x854, 0x00000000, - 0x858, 0x65a965a9, - 0x85c, 0x65a965a9, - 0x860, 0x001f0010, - 0x864, 0x007f0010, - 0x868, 0x001f0010, - 0x86c, 0x007f0010, - 0x870, 0x0f100f70, - 0x874, 0x0f100f70, - 0x878, 0x00000000, - 0x87c, 0x00000000, - 0x880, 0x6870e36c, - 0x884, 0xe3573600, - 0x888, 0x4260c340, - 0x88c, 0x0000ff00, - 0x890, 0x00000000, - 0x894, 0xfffffffe, - 0x898, 0x4c42382f, - 0x89c, 0x00656056, - 0x8b0, 0x00000000, - 0x8e0, 0x00000000, - 0x8e4, 0x00000000, - 0x900, 0x00000000, - 0x904, 0x00000023, - 0x908, 0x00000000, - 0x90c, 0x31121311, - 0xa00, 0x00d0c7d8, - 0xa04, 0x811f0008, - 0xa08, 0x80cd8300, - 0xa0c, 0x2e62740f, - 0xa10, 0x95009b78, - 0xa14, 0x11145008, - 0xa18, 0x00881117, - 0xa1c, 0x89140fa0, - 0xa20, 0x1a1b0000, - 0xa24, 0x090e1317, - 0xa28, 0x00000204, - 0xa2c, 0x00000000, - 0xc00, 0x00000040, - 0xc04, 0x00005433, - 0xc08, 0x000000e4, - 0xc0c, 0x6c6c6c6c, - 0xc10, 0x08800000, - 0xc14, 0x40000100, - 0xc18, 0x08000000, - 0xc1c, 0x40000100, - 0xc20, 0x08000000, - 0xc24, 0x40000100, - 0xc28, 0x08000000, - 0xc2c, 0x40000100, - 0xc30, 0x6de9ac44, - 0xc34, 0x465c52cd, - 0xc38, 0x497f5994, - 0xc3c, 0x0a969764, - 0xc40, 0x1f7c403f, - 0xc44, 0x000100b7, - 0xc48, 0xec020000, - 0xc4c, 0x00000300, - 0xc50, 0x69543420, - 0xc54, 0x433c0094, - 0xc58, 0x69543420, - 0xc5c, 0x433c0094, - 0xc60, 0x69543420, - 0xc64, 0x433c0094, - 0xc68, 0x69543420, - 0xc6c, 0x433c0094, - 0xc70, 0x2c7f000d, - 0xc74, 0x0186175b, - 0xc78, 0x0000001f, - 0xc7c, 0x00b91612, - 0xc80, 0x40000100, - 0xc84, 0x20000000, - 0xc88, 0x40000100, - 0xc8c, 0x20200000, - 0xc90, 0x40000100, - 0xc94, 0x00000000, - 0xc98, 0x40000100, - 0xc9c, 0x00000000, - 0xca0, 0x00492492, - 0xca4, 0x00000000, - 0xca8, 0x00000000, - 0xcac, 0x00000000, - 0xcb0, 0x00000000, - 0xcb4, 0x00000000, - 0xcb8, 0x00000000, - 0xcbc, 0x00492492, - 0xcc0, 0x00000000, - 0xcc4, 0x00000000, - 0xcc8, 0x00000000, - 0xccc, 0x00000000, - 0xcd0, 0x00000000, - 0xcd4, 0x00000000, - 0xcd8, 0x64b22427, - 0xcdc, 0x00766932, - 0xce0, 0x00222222, - 0xd00, 0x00000750, - 0xd04, 0x00000403, - 0xd08, 0x0000907f, - 0xd0c, 0x00000001, - 0xd10, 0xa0633333, - 0xd14, 0x33333c63, - 0xd18, 0x6a8f5b6b, - 0xd1c, 0x00000000, - 0xd20, 0x00000000, - 0xd24, 0x00000000, - 0xd28, 0x00000000, - 0xd2c, 0xcc979975, - 0xd30, 0x00000000, - 0xd34, 0x00000000, - 0xd38, 0x00000000, - 0xd3c, 0x00027293, - 0xd40, 0x00000000, - 0xd44, 0x00000000, - 0xd48, 0x00000000, - 0xd4c, 0x00000000, - 0xd50, 0x6437140a, - 0xd54, 0x024dbd02, - 0xd58, 0x00000000, - 0xd5c, 0x04032064, - 0xe00, 0x161a1a1a, - 0xe04, 0x12121416, - 0xe08, 0x00001800, - 0xe0c, 0x00000000, - 0xe10, 0x161a1a1a, - 0xe14, 0x12121416, - 0xe18, 0x161a1a1a, - 0xe1c, 0x12121416, -}; - -u32 RTL8192E_RADIO_A_ARR[RTL8192E_RADIO_A_ARR_LEN] = { - 0x019, 0x00000003, - 0x000, 0x000000bf, - 0x001, 0x00000ee0, - 0x002, 0x0000004c, - 0x003, 0x000007f1, - 0x004, 0x00000975, - 0x005, 0x00000c58, - 0x006, 0x00000ae6, - 0x007, 0x000000ca, - 0x008, 0x00000e1c, - 0x009, 0x000007f0, - 0x00a, 0x000009d0, - 0x00b, 0x000001ba, - 0x00c, 0x00000240, - 0x00e, 0x00000020, - 0x00f, 0x00000990, - 0x012, 0x00000806, - 0x014, 0x000005ab, - 0x015, 0x00000f80, - 0x016, 0x00000020, - 0x017, 0x00000597, - 0x018, 0x0000050a, - 0x01a, 0x00000f80, - 0x01b, 0x00000f5e, - 0x01c, 0x00000008, - 0x01d, 0x00000607, - 0x01e, 0x000006cc, - 0x01f, 0x00000000, - 0x020, 0x000001a5, - 0x01f, 0x00000001, - 0x020, 0x00000165, - 0x01f, 0x00000002, - 0x020, 0x000000c6, - 0x01f, 0x00000003, - 0x020, 0x00000086, - 0x01f, 0x00000004, - 0x020, 0x00000046, - 0x01f, 0x00000005, - 0x020, 0x000001e6, - 0x01f, 0x00000006, - 0x020, 0x000001a6, - 0x01f, 0x00000007, - 0x020, 0x00000166, - 0x01f, 0x00000008, - 0x020, 0x000000c7, - 0x01f, 0x00000009, - 0x020, 0x00000087, - 0x01f, 0x0000000a, - 0x020, 0x000000f7, - 0x01f, 0x0000000b, - 0x020, 0x000000d7, - 0x01f, 0x0000000c, - 0x020, 0x000000b7, - 0x01f, 0x0000000d, - 0x020, 0x00000097, - 0x01f, 0x0000000e, - 0x020, 0x00000077, - 0x01f, 0x0000000f, - 0x020, 0x00000057, - 0x01f, 0x00000010, - 0x020, 0x00000037, - 0x01f, 0x00000011, - 0x020, 0x000000fb, - 0x01f, 0x00000012, - 0x020, 0x000000db, - 0x01f, 0x00000013, - 0x020, 0x000000bb, - 0x01f, 0x00000014, - 0x020, 0x000000ff, - 0x01f, 0x00000015, - 0x020, 0x000000e3, - 0x01f, 0x00000016, - 0x020, 0x000000c3, - 0x01f, 0x00000017, - 0x020, 0x000000a3, - 0x01f, 0x00000018, - 0x020, 0x00000083, - 0x01f, 0x00000019, - 0x020, 0x00000063, - 0x01f, 0x0000001a, - 0x020, 0x00000043, - 0x01f, 0x0000001b, - 0x020, 0x00000023, - 0x01f, 0x0000001c, - 0x020, 0x00000003, - 0x01f, 0x0000001d, - 0x020, 0x000001e3, - 0x01f, 0x0000001e, - 0x020, 0x000001c3, - 0x01f, 0x0000001f, - 0x020, 0x000001a3, - 0x01f, 0x00000020, - 0x020, 0x00000183, - 0x01f, 0x00000021, - 0x020, 0x00000163, - 0x01f, 0x00000022, - 0x020, 0x00000143, - 0x01f, 0x00000023, - 0x020, 0x00000123, - 0x01f, 0x00000024, - 0x020, 0x00000103, - 0x023, 0x00000203, - 0x024, 0x00000100, - 0x00b, 0x000001ba, - 0x02c, 0x000003d7, - 0x02d, 0x00000ff0, - 0x000, 0x00000037, - 0x004, 0x00000160, - 0x007, 0x00000080, - 0x002, 0x0000088d, - 0x0fe, 0x00000000, - 0x0fe, 0x00000000, - 0x016, 0x00000200, - 0x016, 0x00000380, - 0x016, 0x00000020, - 0x016, 0x000001a0, - 0x000, 0x000000bf, - 0x00d, 0x0000001f, - 0x00d, 0x00000c9f, - 0x002, 0x0000004d, - 0x000, 0x00000cbf, - 0x004, 0x00000975, - 0x007, 0x00000700, -}; - -u32 RTL8192E_RADIO_B_ARR[RTL8192E_RADIO_B_ARR_LEN] = { - 0x019, 0x00000003, - 0x000, 0x000000bf, - 0x001, 0x000006e0, - 0x002, 0x0000004c, - 0x003, 0x000007f1, - 0x004, 0x00000975, - 0x005, 0x00000c58, - 0x006, 0x00000ae6, - 0x007, 0x000000ca, - 0x008, 0x00000e1c, - 0x000, 0x000000b7, - 0x00a, 0x00000850, - 0x000, 0x000000bf, - 0x00b, 0x000001ba, - 0x00c, 0x00000240, - 0x00e, 0x00000020, - 0x015, 0x00000f80, - 0x016, 0x00000020, - 0x017, 0x00000597, - 0x018, 0x0000050a, - 0x01a, 0x00000e00, - 0x01b, 0x00000f5e, - 0x01d, 0x00000607, - 0x01e, 0x000006cc, - 0x00b, 0x000001ba, - 0x023, 0x00000203, - 0x024, 0x00000100, - 0x000, 0x00000037, - 0x004, 0x00000160, - 0x016, 0x00000200, - 0x016, 0x00000380, - 0x016, 0x00000020, - 0x016, 0x000001a0, - 0x00d, 0x00000ccc, - 0x000, 0x000000bf, - 0x002, 0x0000004d, - 0x000, 0x00000cbf, - 0x004, 0x00000975, - 0x007, 0x00000700, -}; - -u32 RTL8192E_MACPHY_ARR[] = { - 0x03c, 0xffff0000, 0x00000f0f, - 0x340, 0xffffffff, 0x161a1a1a, - 0x344, 0xffffffff, 0x12121416, - 0x348, 0x0000ffff, 0x00001818, - 0x12c, 0xffffffff, 0x04000802, - 0x318, 0x00000fff, 0x00000100, -}; - -u32 RTL8192E_MACPHY_ARR_PG[] = { - 0x03c, 0xffff0000, 0x00000f0f, - 0xe00, 0xffffffff, 0x06090909, - 0xe04, 0xffffffff, 0x00030306, - 0xe08, 0x0000ff00, 0x00000000, - 0xe10, 0xffffffff, 0x0a0c0d0f, - 0xe14, 0xffffffff, 0x06070809, - 0xe18, 0xffffffff, 0x0a0c0d0f, - 0xe1c, 0xffffffff, 0x06070809, - 0x12c, 0xffffffff, 0x04000802, - 0x318, 0x00000fff, 0x00000800, -}; - -u32 RTL8192E_AGCTAB_ARR[RTL8192E_AGCTAB_ARR_LEN] = { - 0xc78, 0x7d000001, - 0xc78, 0x7d010001, - 0xc78, 0x7d020001, - 0xc78, 0x7d030001, - 0xc78, 0x7d040001, - 0xc78, 0x7d050001, - 0xc78, 0x7c060001, - 0xc78, 0x7b070001, - 0xc78, 0x7a080001, - 0xc78, 0x79090001, - 0xc78, 0x780a0001, - 0xc78, 0x770b0001, - 0xc78, 0x760c0001, - 0xc78, 0x750d0001, - 0xc78, 0x740e0001, - 0xc78, 0x730f0001, - 0xc78, 0x72100001, - 0xc78, 0x71110001, - 0xc78, 0x70120001, - 0xc78, 0x6f130001, - 0xc78, 0x6e140001, - 0xc78, 0x6d150001, - 0xc78, 0x6c160001, - 0xc78, 0x6b170001, - 0xc78, 0x6a180001, - 0xc78, 0x69190001, - 0xc78, 0x681a0001, - 0xc78, 0x671b0001, - 0xc78, 0x661c0001, - 0xc78, 0x651d0001, - 0xc78, 0x641e0001, - 0xc78, 0x491f0001, - 0xc78, 0x48200001, - 0xc78, 0x47210001, - 0xc78, 0x46220001, - 0xc78, 0x45230001, - 0xc78, 0x44240001, - 0xc78, 0x43250001, - 0xc78, 0x28260001, - 0xc78, 0x27270001, - 0xc78, 0x26280001, - 0xc78, 0x25290001, - 0xc78, 0x242a0001, - 0xc78, 0x232b0001, - 0xc78, 0x222c0001, - 0xc78, 0x212d0001, - 0xc78, 0x202e0001, - 0xc78, 0x0a2f0001, - 0xc78, 0x08300001, - 0xc78, 0x06310001, - 0xc78, 0x05320001, - 0xc78, 0x04330001, - 0xc78, 0x03340001, - 0xc78, 0x02350001, - 0xc78, 0x01360001, - 0xc78, 0x00370001, - 0xc78, 0x00380001, - 0xc78, 0x00390001, - 0xc78, 0x003a0001, - 0xc78, 0x003b0001, - 0xc78, 0x003c0001, - 0xc78, 0x003d0001, - 0xc78, 0x003e0001, - 0xc78, 0x003f0001, - 0xc78, 0x7d400001, - 0xc78, 0x7d410001, - 0xc78, 0x7d420001, - 0xc78, 0x7d430001, - 0xc78, 0x7d440001, - 0xc78, 0x7d450001, - 0xc78, 0x7c460001, - 0xc78, 0x7b470001, - 0xc78, 0x7a480001, - 0xc78, 0x79490001, - 0xc78, 0x784a0001, - 0xc78, 0x774b0001, - 0xc78, 0x764c0001, - 0xc78, 0x754d0001, - 0xc78, 0x744e0001, - 0xc78, 0x734f0001, - 0xc78, 0x72500001, - 0xc78, 0x71510001, - 0xc78, 0x70520001, - 0xc78, 0x6f530001, - 0xc78, 0x6e540001, - 0xc78, 0x6d550001, - 0xc78, 0x6c560001, - 0xc78, 0x6b570001, - 0xc78, 0x6a580001, - 0xc78, 0x69590001, - 0xc78, 0x685a0001, - 0xc78, 0x675b0001, - 0xc78, 0x665c0001, - 0xc78, 0x655d0001, - 0xc78, 0x645e0001, - 0xc78, 0x495f0001, - 0xc78, 0x48600001, - 0xc78, 0x47610001, - 0xc78, 0x46620001, - 0xc78, 0x45630001, - 0xc78, 0x44640001, - 0xc78, 0x43650001, - 0xc78, 0x28660001, - 0xc78, 0x27670001, - 0xc78, 0x26680001, - 0xc78, 0x25690001, - 0xc78, 0x246a0001, - 0xc78, 0x236b0001, - 0xc78, 0x226c0001, - 0xc78, 0x216d0001, - 0xc78, 0x206e0001, - 0xc78, 0x0a6f0001, - 0xc78, 0x08700001, - 0xc78, 0x06710001, - 0xc78, 0x05720001, - 0xc78, 0x04730001, - 0xc78, 0x03740001, - 0xc78, 0x02750001, - 0xc78, 0x01760001, - 0xc78, 0x00770001, - 0xc78, 0x00780001, - 0xc78, 0x00790001, - 0xc78, 0x007a0001, - 0xc78, 0x007b0001, - 0xc78, 0x007c0001, - 0xc78, 0x007d0001, - 0xc78, 0x007e0001, - 0xc78, 0x007f0001, - 0xc78, 0x2e00001e, - 0xc78, 0x2e01001e, - 0xc78, 0x2e02001e, - 0xc78, 0x2e03001e, - 0xc78, 0x2e04001e, - 0xc78, 0x2e05001e, - 0xc78, 0x3006001e, - 0xc78, 0x3407001e, - 0xc78, 0x3908001e, - 0xc78, 0x3c09001e, - 0xc78, 0x3f0a001e, - 0xc78, 0x420b001e, - 0xc78, 0x440c001e, - 0xc78, 0x450d001e, - 0xc78, 0x460e001e, - 0xc78, 0x460f001e, - 0xc78, 0x4710001e, - 0xc78, 0x4811001e, - 0xc78, 0x4912001e, - 0xc78, 0x4a13001e, - 0xc78, 0x4b14001e, - 0xc78, 0x4b15001e, - 0xc78, 0x4c16001e, - 0xc78, 0x4d17001e, - 0xc78, 0x4e18001e, - 0xc78, 0x4f19001e, - 0xc78, 0x4f1a001e, - 0xc78, 0x501b001e, - 0xc78, 0x511c001e, - 0xc78, 0x521d001e, - 0xc78, 0x521e001e, - 0xc78, 0x531f001e, - 0xc78, 0x5320001e, - 0xc78, 0x5421001e, - 0xc78, 0x5522001e, - 0xc78, 0x5523001e, - 0xc78, 0x5624001e, - 0xc78, 0x5725001e, - 0xc78, 0x5726001e, - 0xc78, 0x5827001e, - 0xc78, 0x5828001e, - 0xc78, 0x5929001e, - 0xc78, 0x592a001e, - 0xc78, 0x5a2b001e, - 0xc78, 0x5b2c001e, - 0xc78, 0x5c2d001e, - 0xc78, 0x5c2e001e, - 0xc78, 0x5d2f001e, - 0xc78, 0x5e30001e, - 0xc78, 0x5f31001e, - 0xc78, 0x6032001e, - 0xc78, 0x6033001e, - 0xc78, 0x6134001e, - 0xc78, 0x6235001e, - 0xc78, 0x6336001e, - 0xc78, 0x6437001e, - 0xc78, 0x6438001e, - 0xc78, 0x6539001e, - 0xc78, 0x663a001e, - 0xc78, 0x673b001e, - 0xc78, 0x673c001e, - 0xc78, 0x683d001e, - 0xc78, 0x693e001e, - 0xc78, 0x6a3f001e, -}; diff --git a/drivers/staging/rtl8192e/rtl8192e/table.h b/drivers/staging/rtl8192e/rtl8192e/table.h deleted file mode 100644 index 82be44a9d4e8d5..00000000000000 --- a/drivers/staging/rtl8192e/rtl8192e/table.h +++ /dev/null @@ -1,27 +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 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_BA.h b/drivers/staging/rtl8192e/rtl819x_BA.h deleted file mode 100644 index 8a35d7a3eee10f..00000000000000 --- a/drivers/staging/rtl8192e/rtl819x_BA.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef _BATYPE_H_ -#define _BATYPE_H_ - -#define BA_SETUP_TIMEOUT 200 - -#define BA_POLICY_DELAYED 0 -#define BA_POLICY_IMMEDIATE 1 - -#define ADDBA_STATUS_SUCCESS 0 -#define ADDBA_STATUS_REFUSED 37 -#define ADDBA_STATUS_INVALID_PARAM 38 - -#define DELBA_REASON_END_BA 37 -#define DELBA_REASON_UNKNOWN_BA 38 -#define DELBA_REASON_TIMEOUT 39 -union sequence_control { - u16 short_data; - struct { - u16 frag_num:4; - u16 seq_num:12; - } field; -}; - -union ba_param_set { - u8 char_data[2]; - u16 short_data; - struct { - u16 amsdu_support:1; - u16 ba_policy:1; - u16 tid:4; - u16 buffer_size:10; - } field; -}; - -union delba_param_set { - u8 char_data[2]; - u16 short_data; - struct { - u16 reserved:11; - u16 initiator:1; - u16 tid:4; - } field; -}; - -struct ba_record { - struct timer_list timer; - u8 b_valid; - u8 dialog_token; - union ba_param_set ba_param_set; - u16 ba_timeout_value; - union sequence_control ba_start_seq_ctrl; -}; - -#endif diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c deleted file mode 100644 index c400d4f8ff9a24..00000000000000 --- a/drivers/staging/rtl8192e/rtl819x_BAProc.c +++ /dev/null @@ -1,544 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include -#include -#include -#include "rtllib.h" -#include "rtl819x_BA.h" - -static void activate_ba_entry(struct ba_record *ba, u16 time) -{ - ba->b_valid = true; - if (time != 0) - mod_timer(&ba->timer, jiffies + msecs_to_jiffies(time)); -} - -static void deactivate_ba_entry(struct rtllib_device *ieee, struct ba_record *ba) -{ - ba->b_valid = false; - del_timer_sync(&ba->timer); -} - -static u8 tx_ts_delete_ba(struct rtllib_device *ieee, struct tx_ts_record *ts) -{ - struct ba_record *admitted_ba = &ts->tx_admitted_ba_record; - struct ba_record *pending_ba = &ts->tx_pending_ba_record; - u8 send_del_ba = false; - - if (pending_ba->b_valid) { - deactivate_ba_entry(ieee, pending_ba); - send_del_ba = true; - } - - if (admitted_ba->b_valid) { - deactivate_ba_entry(ieee, admitted_ba); - send_del_ba = true; - } - return send_del_ba; -} - -static u8 rx_ts_delete_ba(struct rtllib_device *ieee, struct rx_ts_record *ts) -{ - struct ba_record *ba = &ts->rx_admitted_ba_record; - u8 send_del_ba = false; - - if (ba->b_valid) { - deactivate_ba_entry(ieee, ba); - send_del_ba = true; - } - - return send_del_ba; -} - -void rtllib_reset_ba_entry(struct ba_record *ba) -{ - ba->b_valid = false; - ba->ba_param_set.short_data = 0; - ba->ba_timeout_value = 0; - ba->dialog_token = 0; - ba->ba_start_seq_ctrl.short_data = 0; -} - -static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *dst, - struct ba_record *ba, - u16 status_code, u8 type) -{ - struct sk_buff *skb = NULL; - struct ieee80211_hdr_3addr *ba_req = NULL; - u8 *tag = NULL; - u16 len = ieee->tx_headroom + 9; - - netdev_dbg(ieee->dev, "%s(): frame(%d) sentd to: %pM, ieee->dev:%p\n", - __func__, type, dst, ieee->dev); - - if (!ba) { - netdev_warn(ieee->dev, "ba is NULL\n"); - return NULL; - } - skb = dev_alloc_skb(len + sizeof(struct ieee80211_hdr_3addr)); - if (!skb) - return NULL; - - memset(skb->data, 0, sizeof(struct ieee80211_hdr_3addr)); - - skb_reserve(skb, ieee->tx_headroom); - - ba_req = skb_put(skb, sizeof(struct ieee80211_hdr_3addr)); - - ether_addr_copy(ba_req->addr1, dst); - ether_addr_copy(ba_req->addr2, ieee->dev->dev_addr); - - ether_addr_copy(ba_req->addr3, ieee->current_network.bssid); - ba_req->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); - - tag = skb_put(skb, 9); - *tag++ = ACT_CAT_BA; - *tag++ = type; - *tag++ = ba->dialog_token; - - if (type == ACT_ADDBARSP) { - put_unaligned_le16(status_code, tag); - tag += 2; - } - - put_unaligned_le16(ba->ba_param_set.short_data, tag); - tag += 2; - - put_unaligned_le16(ba->ba_timeout_value, tag); - tag += 2; - - if (type == ACT_ADDBAREQ) { - memcpy(tag, (u8 *)&ba->ba_start_seq_ctrl, 2); - tag += 2; - } - -#ifdef VERBOSE_DEBUG - print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data, - __func__, skb->len); -#endif - return skb; -} - -static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, - struct ba_record *ba, - enum tr_select tx_rx_select, u16 reason_code) -{ - union delba_param_set del_ba_param_set; - struct sk_buff *skb = NULL; - struct ieee80211_hdr_3addr *del_ba = NULL; - u8 *tag = NULL; - u16 len = 6 + ieee->tx_headroom; - - if (net_ratelimit()) - netdev_dbg(ieee->dev, "%s(): reason_code(%d) sentd to: %pM\n", - __func__, reason_code, dst); - - memset(&del_ba_param_set, 0, 2); - - del_ba_param_set.field.initiator = (tx_rx_select == TX_DIR) ? 1 : 0; - del_ba_param_set.field.tid = ba->ba_param_set.field.tid; - - skb = dev_alloc_skb(len + sizeof(struct ieee80211_hdr_3addr)); - if (!skb) - return NULL; - - skb_reserve(skb, ieee->tx_headroom); - - del_ba = skb_put(skb, sizeof(struct ieee80211_hdr_3addr)); - - ether_addr_copy(del_ba->addr1, dst); - ether_addr_copy(del_ba->addr2, ieee->dev->dev_addr); - ether_addr_copy(del_ba->addr3, ieee->current_network.bssid); - del_ba->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); - - tag = skb_put(skb, 6); - - *tag++ = ACT_CAT_BA; - *tag++ = ACT_DELBA; - - put_unaligned_le16(del_ba_param_set.short_data, tag); - tag += 2; - - put_unaligned_le16(reason_code, tag); - tag += 2; - -#ifdef VERBOSE_DEBUG - print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data, - __func__, skb->len); -#endif - return skb; -} - -static void rtllib_send_add_ba_req(struct rtllib_device *ieee, u8 *dst, - struct ba_record *ba) -{ - struct sk_buff *skb; - - skb = rtllib_ADDBA(ieee, dst, ba, 0, ACT_ADDBAREQ); - - if (skb) - softmac_mgmt_xmit(skb, ieee); - else - netdev_dbg(ieee->dev, "Failed to generate ADDBAReq packet.\n"); -} - -static void rtllib_send_add_ba_rsp(struct rtllib_device *ieee, u8 *dst, - struct ba_record *ba, u16 status_code) -{ - struct sk_buff *skb; - - skb = rtllib_ADDBA(ieee, dst, ba, status_code, ACT_ADDBARSP); - if (skb) - softmac_mgmt_xmit(skb, ieee); - else - netdev_dbg(ieee->dev, "Failed to generate ADDBARsp packet.\n"); -} - -static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst, - struct ba_record *ba, enum tr_select tx_rx_select, - u16 reason_code) -{ - struct sk_buff *skb; - - skb = rtllib_DELBA(ieee, dst, ba, tx_rx_select, reason_code); - if (skb) - softmac_mgmt_xmit(skb, ieee); - else - netdev_dbg(ieee->dev, "Failed to generate DELBA packet.\n"); -} - -int rtllib_rx_add_ba_req(struct rtllib_device *ieee, struct sk_buff *skb) -{ - struct ieee80211_hdr_3addr *req = NULL; - u16 rc = 0; - u8 *dst = NULL, *dialog_token = NULL, *tag = NULL; - struct ba_record *ba = NULL; - union ba_param_set *ba_param_set = NULL; - u16 *ba_timeout_value = NULL; - union sequence_control *ba_start_seq_ctrl = NULL; - struct rx_ts_record *ts = NULL; - - if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 9) { - netdev_warn(ieee->dev, "Invalid skb len in BAREQ(%d / %d)\n", - (int)skb->len, - (int)(sizeof(struct ieee80211_hdr_3addr) + 9)); - return -1; - } - -#ifdef VERBOSE_DEBUG - print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, __func__, - skb->data, skb->len); -#endif - - req = (struct ieee80211_hdr_3addr *)skb->data; - tag = (u8 *)req; - dst = (u8 *)(&req->addr2[0]); - tag += sizeof(struct ieee80211_hdr_3addr); - dialog_token = tag + 2; - ba_param_set = (union ba_param_set *)(tag + 3); - ba_timeout_value = (u16 *)(tag + 5); - ba_start_seq_ctrl = (union sequence_control *)(req + 7); - - if (!ieee->current_network.qos_data.active || - !ieee->ht_info->current_ht_support || - (ieee->ht_info->iot_action & HT_IOT_ACT_REJECT_ADDBA_REQ)) { - rc = ADDBA_STATUS_REFUSED; - netdev_warn(ieee->dev, - "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", - ieee->current_network.qos_data.active, - ieee->ht_info->current_ht_support); - goto on_add_ba_req_fail; - } - if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst, - (u8)(ba_param_set->field.tid), RX_DIR, true)) { - rc = ADDBA_STATUS_REFUSED; - netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__); - goto on_add_ba_req_fail; - } - ba = &ts->rx_admitted_ba_record; - - if (ba_param_set->field.ba_policy == BA_POLICY_DELAYED) { - rc = ADDBA_STATUS_INVALID_PARAM; - netdev_warn(ieee->dev, "%s(): BA Policy is not correct\n", - __func__); - goto on_add_ba_req_fail; - } - - rtllib_flush_rx_ts_pending_pkts(ieee, ts); - - deactivate_ba_entry(ieee, ba); - ba->dialog_token = *dialog_token; - ba->ba_param_set = *ba_param_set; - ba->ba_timeout_value = *ba_timeout_value; - ba->ba_start_seq_ctrl = *ba_start_seq_ctrl; - - if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev) || - (ieee->ht_info->iot_action & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT)) - ba->ba_param_set.field.buffer_size = 1; - else - ba->ba_param_set.field.buffer_size = 32; - - activate_ba_entry(ba, 0); - rtllib_send_add_ba_rsp(ieee, dst, ba, ADDBA_STATUS_SUCCESS); - - return 0; - -on_add_ba_req_fail: - { - struct ba_record BA; - - BA.ba_param_set = *ba_param_set; - BA.ba_timeout_value = *ba_timeout_value; - BA.dialog_token = *dialog_token; - BA.ba_param_set.field.ba_policy = BA_POLICY_IMMEDIATE; - rtllib_send_add_ba_rsp(ieee, dst, &BA, rc); - return 0; - } -} - -int rtllib_rx_add_ba_rsp(struct rtllib_device *ieee, struct sk_buff *skb) -{ - struct ieee80211_hdr_3addr *rsp = NULL; - struct ba_record *pending_ba, *admitted_ba; - struct tx_ts_record *ts = NULL; - u8 *dst = NULL, *dialog_token = NULL, *tag = NULL; - u16 *status_code = NULL, *ba_timeout_value = NULL; - union ba_param_set *ba_param_set = NULL; - u16 reason_code; - - if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 9) { - netdev_warn(ieee->dev, "Invalid skb len in BARSP(%d / %d)\n", - (int)skb->len, - (int)(sizeof(struct ieee80211_hdr_3addr) + 9)); - return -1; - } - rsp = (struct ieee80211_hdr_3addr *)skb->data; - tag = (u8 *)rsp; - dst = (u8 *)(&rsp->addr2[0]); - tag += sizeof(struct ieee80211_hdr_3addr); - dialog_token = tag + 2; - status_code = (u16 *)(tag + 3); - ba_param_set = (union ba_param_set *)(tag + 5); - ba_timeout_value = (u16 *)(tag + 7); - - if (!ieee->current_network.qos_data.active || - !ieee->ht_info->current_ht_support || - !ieee->ht_info->current_ampdu_enable) { - netdev_warn(ieee->dev, - "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n", - ieee->current_network.qos_data.active, - ieee->ht_info->current_ht_support, - ieee->ht_info->current_ampdu_enable); - reason_code = DELBA_REASON_UNKNOWN_BA; - goto on_add_ba_rsp_reject; - } - - if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst, - (u8)(ba_param_set->field.tid), TX_DIR, false)) { - netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__); - reason_code = DELBA_REASON_UNKNOWN_BA; - goto on_add_ba_rsp_reject; - } - - ts->add_ba_req_in_progress = false; - pending_ba = &ts->tx_pending_ba_record; - admitted_ba = &ts->tx_admitted_ba_record; - - if (admitted_ba->b_valid) { - netdev_dbg(ieee->dev, "%s(): ADDBA response already admitted\n", - __func__); - return -1; - } else if (!pending_ba->b_valid || - (*dialog_token != pending_ba->dialog_token)) { - netdev_warn(ieee->dev, - "%s(): ADDBA Rsp. BA invalid, DELBA!\n", - __func__); - reason_code = DELBA_REASON_UNKNOWN_BA; - goto on_add_ba_rsp_reject; - } else { - netdev_dbg(ieee->dev, - "%s(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n", - __func__, *status_code); - deactivate_ba_entry(ieee, pending_ba); - } - - if (*status_code == ADDBA_STATUS_SUCCESS) { - if (ba_param_set->field.ba_policy == BA_POLICY_DELAYED) { - ts->add_ba_req_delayed = true; - deactivate_ba_entry(ieee, admitted_ba); - reason_code = DELBA_REASON_END_BA; - goto on_add_ba_rsp_reject; - } - - admitted_ba->dialog_token = *dialog_token; - admitted_ba->ba_timeout_value = *ba_timeout_value; - admitted_ba->ba_start_seq_ctrl = pending_ba->ba_start_seq_ctrl; - admitted_ba->ba_param_set = *ba_param_set; - deactivate_ba_entry(ieee, admitted_ba); - activate_ba_entry(admitted_ba, *ba_timeout_value); - } else { - ts->add_ba_req_delayed = true; - ts->disable_add_ba = true; - reason_code = DELBA_REASON_END_BA; - goto on_add_ba_rsp_reject; - } - - return 0; - -on_add_ba_rsp_reject: - { - struct ba_record BA; - - BA.ba_param_set = *ba_param_set; - rtllib_send_DELBA(ieee, dst, &BA, TX_DIR, reason_code); - return 0; - } -} - -int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) -{ - struct ieee80211_hdr_3addr *delba = NULL; - union delba_param_set *del_ba_param_set = NULL; - u8 *dst = NULL; - - if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 6) { - netdev_warn(ieee->dev, "Invalid skb len in DELBA(%d / %d)\n", - (int)skb->len, - (int)(sizeof(struct ieee80211_hdr_3addr) + 6)); - return -1; - } - - if (!ieee->current_network.qos_data.active || - !ieee->ht_info->current_ht_support) { - netdev_warn(ieee->dev, - "received DELBA while QOS or HT is not supported(%d, %d)\n", - ieee->current_network. qos_data.active, - ieee->ht_info->current_ht_support); - return -1; - } - -#ifdef VERBOSE_DEBUG - print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data, - __func__, skb->len); -#endif - delba = (struct ieee80211_hdr_3addr *)skb->data; - dst = (u8 *)(&delba->addr2[0]); - del_ba_param_set = (union delba_param_set *)&delba->seq_ctrl + 2; - - if (del_ba_param_set->field.initiator == 1) { - struct rx_ts_record *ts; - - if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst, - (u8)del_ba_param_set->field.tid, RX_DIR, false)) { - netdev_warn(ieee->dev, - "%s(): can't get TS for RXTS. dst:%pM TID:%d\n", - __func__, dst, - (u8)del_ba_param_set->field.tid); - return -1; - } - - rx_ts_delete_ba(ieee, ts); - } else { - struct tx_ts_record *ts; - - if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst, - (u8)del_ba_param_set->field.tid, TX_DIR, false)) { - netdev_warn(ieee->dev, "%s(): can't get TS for TXTS\n", - __func__); - return -1; - } - - ts->using_ba = false; - ts->add_ba_req_in_progress = false; - ts->add_ba_req_delayed = false; - del_timer_sync(&ts->ts_add_ba_timer); - tx_ts_delete_ba(ieee, ts); - } - return 0; -} - -void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts, - u8 policy, u8 overwrite_pending) -{ - struct ba_record *ba = &ts->tx_pending_ba_record; - - if (ba->b_valid && !overwrite_pending) - return; - - deactivate_ba_entry(ieee, ba); - - ba->dialog_token++; - ba->ba_param_set.field.amsdu_support = 0; - ba->ba_param_set.field.ba_policy = policy; - ba->ba_param_set.field.tid = ts->ts_common_info.tspec.ts_id; - ba->ba_param_set.field.buffer_size = 32; - ba->ba_timeout_value = 0; - ba->ba_start_seq_ctrl.field.seq_num = (ts->tx_cur_seq + 3) % 4096; - - activate_ba_entry(ba, BA_SETUP_TIMEOUT); - - rtllib_send_add_ba_req(ieee, ts->ts_common_info.addr, ba); -} - -void rtllib_ts_init_del_ba(struct rtllib_device *ieee, - struct ts_common_info *ts_common_info, - enum tr_select tx_rx_select) -{ - if (tx_rx_select == TX_DIR) { - struct tx_ts_record *ts = - (struct tx_ts_record *)ts_common_info; - - if (tx_ts_delete_ba(ieee, ts)) - rtllib_send_DELBA(ieee, ts_common_info->addr, - (ts->tx_admitted_ba_record.b_valid) ? - (&ts->tx_admitted_ba_record) : - (&ts->tx_pending_ba_record), - tx_rx_select, DELBA_REASON_END_BA); - } else if (tx_rx_select == RX_DIR) { - struct rx_ts_record *ts = - (struct rx_ts_record *)ts_common_info; - if (rx_ts_delete_ba(ieee, ts)) - rtllib_send_DELBA(ieee, ts_common_info->addr, - &ts->rx_admitted_ba_record, - tx_rx_select, DELBA_REASON_END_BA); - } -} - -void rtllib_ba_setup_timeout(struct timer_list *t) -{ - struct tx_ts_record *ts = from_timer(ts, t, - tx_pending_ba_record.timer); - - ts->add_ba_req_in_progress = false; - ts->add_ba_req_delayed = true; - ts->tx_pending_ba_record.b_valid = false; -} - -void rtllib_tx_ba_inact_timeout(struct timer_list *t) -{ - struct tx_ts_record *ts = from_timer(ts, t, - tx_admitted_ba_record.timer); - struct rtllib_device *ieee = container_of(ts, struct rtllib_device, - tx_ts_records[ts->num]); - tx_ts_delete_ba(ieee, ts); - rtllib_send_DELBA(ieee, ts->ts_common_info.addr, - &ts->tx_admitted_ba_record, TX_DIR, - DELBA_REASON_TIMEOUT); -} - -void rtllib_rx_ba_inact_timeout(struct timer_list *t) -{ - struct rx_ts_record *ts = from_timer(ts, t, - rx_admitted_ba_record.timer); - struct rtllib_device *ieee = container_of(ts, struct rtllib_device, - rx_ts_records[ts->num]); - - rx_ts_delete_ba(ieee, ts); - rtllib_send_DELBA(ieee, ts->ts_common_info.addr, - &ts->rx_admitted_ba_record, RX_DIR, - DELBA_REASON_TIMEOUT); -} diff --git a/drivers/staging/rtl8192e/rtl819x_HT.h b/drivers/staging/rtl8192e/rtl819x_HT.h deleted file mode 100644 index a6e0077630c7f4..00000000000000 --- a/drivers/staging/rtl8192e/rtl819x_HT.h +++ /dev/null @@ -1,223 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef _RTL819XU_HTTYPE_H_ -#define _RTL819XU_HTTYPE_H_ - -#define MIMO_PS_STATIC 0 - -#define sHTCLng 4 - -enum ht_channel_width { - HT_CHANNEL_WIDTH_20 = 0, - HT_CHANNEL_WIDTH_20_40 = 1, -}; - -enum ht_extchnl_offset { - HT_EXTCHNL_OFFSET_NO_EXT = 0, - HT_EXTCHNL_OFFSET_UPPER = 1, - HT_EXTCHNL_OFFSET_NO_DEF = 2, - HT_EXTCHNL_OFFSET_LOWER = 3, -}; - -struct ht_capab_ele { - u8 adv_coding:1; - u8 chl_width:1; - u8 mimo_pwr_save:2; - u8 green_field:1; - u8 short_gi_20mhz:1; - u8 short_gi_40mhz:1; - u8 tx_stbc:1; - u8 rx_stbc:2; - u8 delay_ba:1; - u8 max_amsdu_size:1; - u8 dss_cck:1; - u8 PSMP:1; - u8 Rsvd1:1; - u8 lsig_txop_protect:1; - - u8 max_rx_ampdu_factor:2; - u8 mpdu_density:3; - u8 Rsvd2:3; - - u8 MCS[16]; - - u16 ext_ht_cap_info; - - u8 TxBFCap[4]; - - u8 ASCap; - -} __packed; - -struct ht_info_ele { - u8 ControlChl; - - u8 ExtChlOffset:2; - u8 RecommemdedTxWidth:1; - u8 RIFS:1; - u8 PSMPAccessOnly:1; - u8 SrvIntGranularity:3; - - u8 opt_mode:2; - u8 NonGFDevPresent:1; - u8 Revd1:5; - u8 Revd2:8; - - u8 Rsvd3:6; - u8 DualBeacon:1; - u8 DualCTSProtect:1; - - u8 SecondaryBeacon:1; - u8 LSigTxopProtectFull:1; - u8 PcoActive:1; - u8 PcoPhase:1; - u8 Rsvd4:4; - - u8 BasicMSC[16]; -} __packed; - -enum ht_spec_ver { - HT_SPEC_VER_IEEE = 0, - HT_SPEC_VER_EWC = 1, -}; - -enum ht_aggre_mode { - HT_AGG_AUTO = 0, - HT_AGG_FORCE_ENABLE = 1, - HT_AGG_FORCE_DISABLE = 2, -}; - -struct rt_hi_throughput { - u8 enable_ht; - u8 current_ht_support; - u8 cur_bw_40mhz; - u8 cur_short_gi_40mhz; - u8 cur_short_gi_20mhz; - enum ht_spec_ver peer_ht_spec_ver; - struct ht_capab_ele self_ht_cap; - u8 peer_ht_cap_buf[32]; - u8 peer_ht_info_buf[32]; - u8 ampdu_enable; - u8 current_ampdu_enable; - u8 ampdu_factor; - u8 current_ampdu_factor; - u8 current_mpdu_density; - u8 forced_ampdu_factor; - u8 forced_mpdu_density; - u8 current_op_mode; - enum ht_extchnl_offset cur_sta_ext_chnl_offset; - u8 cur_tx_bw40mhz; - u8 sw_bw_in_progress; - u8 current_rt2rt_aggregation; - u8 current_rt2rt_long_slot_time; - u8 sz_rt2rt_agg_buf[10]; - u8 cur_rx_reorder_enable; - u8 rx_reorder_win_size; - u8 rx_reorder_pending_time; - u16 rx_reorder_drop_counter; - u8 iot_peer; - u32 iot_action; - u8 iot_ra_func; -} __packed; - -struct bss_ht { - u8 bd_support_ht; - - u8 bd_ht_cap_buf[32]; - u16 bd_ht_cap_len; - u8 bd_ht_info_buf[32]; - u16 bd_ht_info_len; - - enum ht_spec_ver bd_ht_spec_ver; - enum ht_channel_width bd_bandwidth; - - u8 bd_rt2rt_aggregation; - u8 bd_rt2rt_long_slot_time; - u8 rt2rt_ht_mode; - u8 bd_ht_1r; -}; - -extern u8 MCS_FILTER_ALL[16]; -extern u8 MCS_FILTER_1SS[16]; - -#define RATE_ADPT_1SS_MASK 0xFF -#define RATE_ADPT_2SS_MASK 0xF0 -#define RATE_ADPT_MCS32_MASK 0x01 - -enum ht_aggre_size { - HT_AGG_SIZE_8K = 0, - HT_AGG_SIZE_16K = 1, - HT_AGG_SIZE_32K = 2, - HT_AGG_SIZE_64K = 3, -}; - -enum ht_iot_peer { - HT_IOT_PEER_UNKNOWN = 0, - HT_IOT_PEER_REALTEK = 1, - HT_IOT_PEER_REALTEK_92SE = 2, - HT_IOT_PEER_BROADCOM = 3, - HT_IOT_PEER_RALINK = 4, - HT_IOT_PEER_ATHEROS = 5, - HT_IOT_PEER_CISCO = 6, - HT_IOT_PEER_MARVELL = 7, - HT_IOT_PEER_92U_SOFTAP = 8, - HT_IOT_PEER_SELF_SOFTAP = 9, - HT_IOT_PEER_AIRGO = 10, - HT_IOT_PEER_MAX = 11, -}; - -enum ht_iot_action { - HT_IOT_ACT_TX_USE_AMSDU_4K = 0x00000001, - HT_IOT_ACT_TX_USE_AMSDU_8K = 0x00000002, - HT_IOT_ACT_DISABLE_MCS14 = 0x00000004, - HT_IOT_ACT_DISABLE_MCS15 = 0x00000008, - HT_IOT_ACT_DISABLE_ALL_2SS = 0x00000010, - HT_IOT_ACT_DISABLE_EDCA_TURBO = 0x00000020, - HT_IOT_ACT_MGNT_USE_CCK_6M = 0x00000040, - HT_IOT_ACT_CDD_FSYNC = 0x00000080, - HT_IOT_ACT_PURE_N_MODE = 0x00000100, - HT_IOT_ACT_FORCED_CTS2SELF = 0x00000200, - HT_IOT_ACT_FORCED_RTS = 0x00000400, - HT_IOT_ACT_AMSDU_ENABLE = 0x00000800, - HT_IOT_ACT_REJECT_ADDBA_REQ = 0x00001000, - HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT = 0x00002000, - HT_IOT_ACT_EDCA_BIAS_ON_RX = 0x00004000, - - HT_IOT_ACT_HYBRID_AGGREGATION = 0x00010000, - HT_IOT_ACT_DISABLE_SHORT_GI = 0x00020000, - HT_IOT_ACT_DISABLE_HIGH_POWER = 0x00040000, - HT_IOT_ACT_DISABLE_TX_40_MHZ = 0x00080000, - HT_IOT_ACT_TX_NO_AGGREGATION = 0x00100000, - HT_IOT_ACT_DISABLE_TX_2SS = 0x00200000, - - HT_IOT_ACT_MID_HIGHPOWER = 0x00400000, - HT_IOT_ACT_NULL_DATA_POWER_SAVING = 0x00800000, - - HT_IOT_ACT_DISABLE_CCK_RATE = 0x01000000, - HT_IOT_ACT_FORCED_ENABLE_BE_TXOP = 0x02000000, - HT_IOT_ACT_WA_IOT_Broadcom = 0x04000000, - - HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI = 0x08000000, - -}; - -enum ht_iot_rafunc { - HT_IOT_RAFUNC_DISABLE_ALL = 0x00, - HT_IOT_RAFUNC_PEER_1R = 0x01, - HT_IOT_RAFUNC_TX_AMSDU = 0x02, -}; - -enum rt_ht_capability { - RT_HT_CAP_USE_TURBO_AGGR = 0x01, - RT_HT_CAP_USE_LONG_PREAMBLE = 0x02, - RT_HT_CAP_USE_AMPDU = 0x04, - RT_HT_CAP_USE_WOW = 0x8, - RT_HT_CAP_USE_SOFTAP = 0x10, - RT_HT_CAP_USE_92SE = 0x20, -}; - -#endif diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c deleted file mode 100644 index 9c9c0bc0cfde31..00000000000000 --- a/drivers/staging/rtl8192e/rtl819x_HTProc.c +++ /dev/null @@ -1,699 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include "rtllib.h" -#include "rtl819x_HT.h" -u8 MCS_FILTER_ALL[16] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -u8 MCS_FILTER_1SS[16] = { - 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -; - -u16 MCS_DATA_RATE[2][2][77] = { - {{13, 26, 39, 52, 78, 104, 117, 130, 26, 52, 78, 104, 156, 208, 234, - 260, 39, 78, 117, 234, 312, 351, 390, 52, 104, 156, 208, 312, 416, - 468, 520, 0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182, - 182, 208, 156, 195, 195, 234, 273, 273, 312, 130, 156, 181, 156, - 181, 208, 234, 208, 234, 260, 260, 286, 195, 234, 273, 234, 273, - 312, 351, 312, 351, 390, 390, 429}, - {14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289, - 43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520, - 578, 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231, - 173, 217, 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260, - 231, 260, 289, 289, 318, 217, 260, 303, 260, 303, 347, 390, 347, 390, - 433, 433, 477} }, - {{27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486, - 540, 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648, - 864, 972, 1080, 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324, - 378, 378, 432, 324, 405, 405, 486, 567, 567, 648, 270, 324, 378, 324, - 378, 432, 486, 432, 486, 540, 540, 594, 405, 486, 567, 486, 567, 648, - 729, 648, 729, 810, 810, 891}, - {30, 60, 90, 120, 180, 240, 270, 300, 60, 120, 180, 240, 360, 480, 540, - 600, 90, 180, 270, 360, 540, 720, 810, 900, 120, 240, 360, 480, 720, - 960, 1080, 1200, 13, 180, 240, 300, 270, 360, 450, 240, 300, 300, 360, - 420, 420, 480, 360, 450, 450, 540, 630, 630, 720, 300, 360, 420, 360, - 420, 480, 540, 480, 540, 600, 600, 660, 450, 540, 630, 540, 630, 720, - 810, 720, 810, 900, 900, 990} } -}; - -static u8 UNKNOWN_BORADCOM[3] = {0x00, 0x14, 0xbf}; - -static u8 LINKSYSWRT330_LINKSYSWRT300_BROADCOM[3] = {0x00, 0x1a, 0x70}; - -static u8 LINKSYSWRT350_LINKSYSWRT150_BROADCOM[3] = {0x00, 0x1d, 0x7e}; - -static u8 BELKINF5D8233V1_RALINK[3] = {0x00, 0x17, 0x3f}; - -static u8 BELKINF5D82334V3_RALINK[3] = {0x00, 0x1c, 0xdf}; - -static u8 PCI_RALINK[3] = {0x00, 0x90, 0xcc}; - -static u8 EDIMAX_RALINK[3] = {0x00, 0x0e, 0x2e}; - -static u8 AIRLINK_RALINK[3] = {0x00, 0x18, 0x02}; - -static u8 DLINK_ATHEROS_1[3] = {0x00, 0x1c, 0xf0}; - -static u8 DLINK_ATHEROS_2[3] = {0x00, 0x21, 0x91}; - -static u8 CISCO_BROADCOM[3] = {0x00, 0x17, 0x94}; - -static u8 LINKSYS_MARVELL_4400N[3] = {0x00, 0x14, 0xa4}; - -void ht_update_default_setting(struct rtllib_device *ieee) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - - ht_info->ampdu_enable = 1; - ht_info->ampdu_factor = 2; - - ieee->tx_dis_rate_fallback = 0; - ieee->tx_use_drv_assinged_rate = 0; - - ieee->tx_enable_fw_calc_dur = 1; - - ht_info->rx_reorder_win_size = 64; - ht_info->rx_reorder_pending_time = 30; -} - -static u16 ht_mcs_to_data_rate(struct rtllib_device *ieee, u8 mcs_rate) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - - u8 is40MHz = (ht_info->cur_bw_40mhz) ? 1 : 0; - u8 isShortGI = (ht_info->cur_bw_40mhz) ? - ((ht_info->cur_short_gi_40mhz) ? 1 : 0) : - ((ht_info->cur_short_gi_20mhz) ? 1 : 0); - return MCS_DATA_RATE[is40MHz][isShortGI][(mcs_rate & 0x7f)]; -} - -u16 tx_count_to_data_rate(struct rtllib_device *ieee, u8 data_rate) -{ - u16 cck_of_dm_rate[12] = {0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, - 0x24, 0x30, 0x48, 0x60, 0x6c}; - u8 is40MHz = 0; - u8 isShortGI = 0; - - if (data_rate < 12) - return cck_of_dm_rate[data_rate]; - if (data_rate >= 0x10 && data_rate <= 0x1f) { - is40MHz = 0; - isShortGI = 0; - } else if (data_rate >= 0x20 && data_rate <= 0x2f) { - is40MHz = 1; - isShortGI = 0; - } else if (data_rate >= 0x30 && data_rate <= 0x3f) { - is40MHz = 0; - isShortGI = 1; - } else if (data_rate >= 0x40 && data_rate <= 0x4f) { - is40MHz = 1; - isShortGI = 1; - } - return MCS_DATA_RATE[is40MHz][isShortGI][data_rate & 0xf]; -} - -bool is_ht_half_nmode_aps(struct rtllib_device *ieee) -{ - bool retValue = false; - struct rtllib_network *net = &ieee->current_network; - - if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) || - (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) || - (memcmp(net->bssid, PCI_RALINK, 3) == 0) || - (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) || - (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) || - (net->ralink_cap_exist)) - retValue = true; - else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) || - !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) || - !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3) || - (net->broadcom_cap_exist)) - retValue = true; - else if (net->bssht.bd_rt2rt_aggregation) - retValue = true; - else - retValue = false; - - return retValue; -} - -static void ht_iot_peer_determine(struct rtllib_device *ieee) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - struct rtllib_network *net = &ieee->current_network; - - if (net->bssht.bd_rt2rt_aggregation) { - ht_info->iot_peer = HT_IOT_PEER_REALTEK; - if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_92SE) - ht_info->iot_peer = HT_IOT_PEER_REALTEK_92SE; - if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_SOFTAP) - ht_info->iot_peer = HT_IOT_PEER_92U_SOFTAP; - } else if (net->broadcom_cap_exist) { - ht_info->iot_peer = HT_IOT_PEER_BROADCOM; - } else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) || - !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) || - !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)) { - ht_info->iot_peer = HT_IOT_PEER_BROADCOM; - } else if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) || - (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) || - (memcmp(net->bssid, PCI_RALINK, 3) == 0) || - (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) || - (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) || - net->ralink_cap_exist) { - ht_info->iot_peer = HT_IOT_PEER_RALINK; - } else if ((net->atheros_cap_exist) || - (memcmp(net->bssid, DLINK_ATHEROS_1, 3) == 0) || - (memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0)) { - ht_info->iot_peer = HT_IOT_PEER_ATHEROS; - } else if ((memcmp(net->bssid, CISCO_BROADCOM, 3) == 0) || - net->cisco_cap_exist) { - ht_info->iot_peer = HT_IOT_PEER_CISCO; - } else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) || - net->marvell_cap_exist) { - ht_info->iot_peer = HT_IOT_PEER_MARVELL; - } else if (net->airgo_cap_exist) { - ht_info->iot_peer = HT_IOT_PEER_AIRGO; - } else { - ht_info->iot_peer = HT_IOT_PEER_UNKNOWN; - } - - netdev_dbg(ieee->dev, "IOTPEER: %x\n", ht_info->iot_peer); -} - -static u8 ht_iot_act_is_mgnt_use_cck_6m(struct rtllib_device *ieee, - struct rtllib_network *network) -{ - u8 retValue = 0; - - if (ieee->ht_info->iot_peer == HT_IOT_PEER_BROADCOM) - retValue = 1; - - return retValue; -} - -static u8 ht_iot_act_is_ccd_fsync(struct rtllib_device *ieee) -{ - u8 retValue = 0; - - if (ieee->ht_info->iot_peer == HT_IOT_PEER_BROADCOM) - retValue = 1; - return retValue; -} - -static void ht_iot_act_determine_ra_func(struct rtllib_device *ieee, bool bPeerRx2ss) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - - ht_info->iot_ra_func &= HT_IOT_RAFUNC_DISABLE_ALL; - - if (ht_info->iot_peer == HT_IOT_PEER_RALINK && !bPeerRx2ss) - ht_info->iot_ra_func |= HT_IOT_RAFUNC_PEER_1R; - - if (ht_info->iot_action & HT_IOT_ACT_AMSDU_ENABLE) - ht_info->iot_ra_func |= HT_IOT_RAFUNC_TX_AMSDU; -} - -void ht_reset_iot_setting(struct rt_hi_throughput *ht_info) -{ - ht_info->iot_action = 0; - ht_info->iot_peer = HT_IOT_PEER_UNKNOWN; - ht_info->iot_ra_func = 0; -} - -void ht_construct_capability_element(struct rtllib_device *ieee, u8 *pos_ht_cap, - u8 *len, u8 is_encrypt, bool assoc) -{ - struct rt_hi_throughput *ht = ieee->ht_info; - struct ht_capab_ele *cap_ele = NULL; - - if (!pos_ht_cap || !ht) { - netdev_warn(ieee->dev, - "%s(): pos_ht_cap and ht_info are null\n", __func__); - return; - } - memset(pos_ht_cap, 0, *len); - - if ((assoc) && (ht->peer_ht_spec_ver == HT_SPEC_VER_EWC)) { - static const u8 EWC11NHTCap[] = { 0x00, 0x90, 0x4c, 0x33 }; - - memcpy(pos_ht_cap, EWC11NHTCap, sizeof(EWC11NHTCap)); - cap_ele = (struct ht_capab_ele *)&pos_ht_cap[4]; - *len = 30 + 2; - } else { - cap_ele = (struct ht_capab_ele *)pos_ht_cap; - *len = 26 + 2; - } - - cap_ele->adv_coding = 0; - if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) - cap_ele->chl_width = 0; - else - cap_ele->chl_width = 1; - - cap_ele->mimo_pwr_save = 3; - cap_ele->green_field = 0; - cap_ele->short_gi_20mhz = 1; - cap_ele->short_gi_40mhz = 1; - - cap_ele->tx_stbc = 1; - cap_ele->rx_stbc = 0; - cap_ele->delay_ba = 0; - cap_ele->max_amsdu_size = (MAX_RECEIVE_BUFFER_SIZE >= 7935) ? 1 : 0; - cap_ele->dss_cck = 1; - cap_ele->PSMP = 0; - cap_ele->lsig_txop_protect = 0; - - netdev_dbg(ieee->dev, - "TX HT cap/info ele BW=%d max_amsdu_size:%d dss_cck:%d\n", - cap_ele->chl_width, cap_ele->max_amsdu_size, cap_ele->dss_cck); - - if (is_encrypt) { - cap_ele->mpdu_density = 7; - cap_ele->max_rx_ampdu_factor = 2; - } else { - cap_ele->max_rx_ampdu_factor = 3; - cap_ele->mpdu_density = 0; - } - - memcpy(cap_ele->MCS, ieee->reg_dot11ht_oper_rate_set, 16); - memset(&cap_ele->ext_ht_cap_info, 0, 2); - memset(cap_ele->TxBFCap, 0, 4); - - cap_ele->ASCap = 0; - - if (assoc) { - if (ht->iot_action & HT_IOT_ACT_DISABLE_MCS15) - cap_ele->MCS[1] &= 0x7f; - - if (ht->iot_action & HT_IOT_ACT_DISABLE_MCS14) - cap_ele->MCS[1] &= 0xbf; - - if (ht->iot_action & HT_IOT_ACT_DISABLE_ALL_2SS) - cap_ele->MCS[1] &= 0x00; - - if (ht->iot_action & HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI) - cap_ele->short_gi_40mhz = 0; - - if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) { - cap_ele->chl_width = 0; - cap_ele->MCS[1] = 0; - } - } -} - -void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee, u8 *posRT2RTAgg, - u8 *len) -{ - if (!posRT2RTAgg) { - netdev_warn(ieee->dev, "%s(): posRT2RTAgg is null\n", __func__); - return; - } - memset(posRT2RTAgg, 0, *len); - *posRT2RTAgg++ = 0x00; - *posRT2RTAgg++ = 0xe0; - *posRT2RTAgg++ = 0x4c; - *posRT2RTAgg++ = 0x02; - *posRT2RTAgg++ = 0x01; - - *posRT2RTAgg = 0x30; - - if (ieee->bSupportRemoteWakeUp) - *posRT2RTAgg |= RT_HT_CAP_USE_WOW; - - *len = 6 + 2; -} - -static u8 ht_pick_mcs_rate(struct rtllib_device *ieee, u8 *pOperateMCS) -{ - u8 i; - - if (!pOperateMCS) { - netdev_warn(ieee->dev, "%s(): pOperateMCS is null\n", __func__); - return false; - } - - switch (ieee->mode) { - case WIRELESS_MODE_B: - case WIRELESS_MODE_G: - for (i = 0; i <= 15; i++) - pOperateMCS[i] = 0; - break; - case WIRELESS_MODE_N_24G: - pOperateMCS[0] &= RATE_ADPT_1SS_MASK; - pOperateMCS[1] &= RATE_ADPT_2SS_MASK; - pOperateMCS[3] &= RATE_ADPT_MCS32_MASK; - break; - default: - break; - } - - return true; -} - -u8 ht_get_highest_mcs_rate(struct rtllib_device *ieee, u8 *pMCSRateSet, - u8 *pMCSFilter) -{ - u8 i, j; - u8 bitMap; - u8 mcsRate = 0; - u8 availableMcsRate[16]; - - if (!pMCSRateSet || !pMCSFilter) { - netdev_warn(ieee->dev, - "%s(): pMCSRateSet and pMCSFilter are null\n", - __func__); - return false; - } - for (i = 0; i < 16; i++) - availableMcsRate[i] = pMCSRateSet[i] & pMCSFilter[i]; - - for (i = 0; i < 16; i++) { - if (availableMcsRate[i] != 0) - break; - } - if (i == 16) - return false; - - for (i = 0; i < 16; i++) { - if (availableMcsRate[i] != 0) { - bitMap = availableMcsRate[i]; - for (j = 0; j < 8; j++) { - if ((bitMap % 2) != 0) { - if (ht_mcs_to_data_rate(ieee, (8 * i + j)) > - ht_mcs_to_data_rate(ieee, mcsRate)) - mcsRate = 8 * i + j; - } - bitMap >>= 1; - } - } - } - return mcsRate | 0x80; -} - -static u8 ht_filter_mcs_rate(struct rtllib_device *ieee, u8 *pSupportMCS, - u8 *pOperateMCS) -{ - u8 i; - - for (i = 0; i <= 15; i++) - pOperateMCS[i] = ieee->reg_dot11tx_ht_oper_rate_set[i] & - pSupportMCS[i]; - - ht_pick_mcs_rate(ieee, pOperateMCS); - - if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) - pOperateMCS[1] = 0; - - for (i = 2; i <= 15; i++) - pOperateMCS[i] = 0; - - return true; -} - -void ht_set_connect_bw_mode(struct rtllib_device *ieee, - enum ht_channel_width bandwidth, - enum ht_extchnl_offset Offset); - -void ht_on_assoc_rsp(struct rtllib_device *ieee) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - struct ht_capab_ele *pPeerHTCap = NULL; - struct ht_info_ele *pPeerHTInfo = NULL; - u8 *pMcsFilter = NULL; - - static const u8 EWC11NHTCap[] = { 0x00, 0x90, 0x4c, 0x33 }; - static const u8 EWC11NHTInfo[] = { 0x00, 0x90, 0x4c, 0x34 }; - - if (!ht_info->current_ht_support) { - netdev_warn(ieee->dev, "%s(): HT_DISABLE\n", __func__); - return; - } - netdev_dbg(ieee->dev, "%s(): HT_ENABLE\n", __func__); - - if (!memcmp(ht_info->peer_ht_cap_buf, EWC11NHTCap, sizeof(EWC11NHTCap))) - pPeerHTCap = (struct ht_capab_ele *)(&ht_info->peer_ht_cap_buf[4]); - else - pPeerHTCap = (struct ht_capab_ele *)(ht_info->peer_ht_cap_buf); - - if (!memcmp(ht_info->peer_ht_info_buf, EWC11NHTInfo, sizeof(EWC11NHTInfo))) - pPeerHTInfo = (struct ht_info_ele *) - (&ht_info->peer_ht_info_buf[4]); - else - pPeerHTInfo = (struct ht_info_ele *)(ht_info->peer_ht_info_buf); - -#ifdef VERBOSE_DEBUG - print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE, - pPeerHTCap, sizeof(struct ht_capab_ele)); -#endif - ht_set_connect_bw_mode(ieee, (enum ht_channel_width)(pPeerHTCap->chl_width), - (enum ht_extchnl_offset)(pPeerHTInfo->ExtChlOffset)); - ht_info->cur_tx_bw40mhz = ((pPeerHTInfo->RecommemdedTxWidth == 1) ? - true : false); - - ht_info->cur_short_gi_20mhz = ((pPeerHTCap->short_gi_20mhz == 1) ? true : false); - ht_info->cur_short_gi_40mhz = ((pPeerHTCap->short_gi_40mhz == 1) ? true : false); - - ht_info->current_ampdu_enable = ht_info->ampdu_enable; - if (ieee->rtllib_ap_sec_type && - (ieee->rtllib_ap_sec_type(ieee) & (SEC_ALG_WEP | SEC_ALG_TKIP))) { - if ((ht_info->iot_peer == HT_IOT_PEER_ATHEROS) || - (ht_info->iot_peer == HT_IOT_PEER_UNKNOWN)) - ht_info->current_ampdu_enable = false; - } - - if (ieee->current_network.bssht.bd_rt2rt_aggregation) { - if (ieee->pairwise_key_type != KEY_TYPE_NA) - ht_info->current_ampdu_factor = - pPeerHTCap->max_rx_ampdu_factor; - else - ht_info->current_ampdu_factor = HT_AGG_SIZE_64K; - } else { - ht_info->current_ampdu_factor = min_t(u32, pPeerHTCap->max_rx_ampdu_factor, - HT_AGG_SIZE_32K); - } - - ht_info->current_mpdu_density = pPeerHTCap->mpdu_density; - if (ht_info->iot_action & HT_IOT_ACT_TX_USE_AMSDU_8K) - ht_info->current_ampdu_enable = false; - - ht_info->cur_rx_reorder_enable = 1; - - if (pPeerHTCap->MCS[0] == 0) - pPeerHTCap->MCS[0] = 0xff; - - ht_iot_act_determine_ra_func(ieee, ((pPeerHTCap->MCS[1]) != 0)); - - ht_filter_mcs_rate(ieee, pPeerHTCap->MCS, ieee->dot11ht_oper_rate_set); - - pMcsFilter = MCS_FILTER_ALL; - ieee->HTHighestOperaRate = ht_get_highest_mcs_rate(ieee, - ieee->dot11ht_oper_rate_set, - pMcsFilter); - ieee->ht_curr_op_rate = ieee->HTHighestOperaRate; - - ht_info->current_op_mode = pPeerHTInfo->opt_mode; -} - -void ht_initialize_ht_info(struct rtllib_device *ieee) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - - ht_info->current_ht_support = false; - - ht_info->cur_bw_40mhz = false; - ht_info->cur_tx_bw40mhz = false; - - ht_info->cur_short_gi_20mhz = false; - ht_info->cur_short_gi_40mhz = false; - - ht_info->current_mpdu_density = 0; - ht_info->current_ampdu_factor = ht_info->ampdu_factor; - - memset((void *)(&ht_info->self_ht_cap), 0, - sizeof(ht_info->self_ht_cap)); - memset((void *)(&ht_info->peer_ht_cap_buf), 0, - sizeof(ht_info->peer_ht_cap_buf)); - memset((void *)(&ht_info->peer_ht_info_buf), 0, - sizeof(ht_info->peer_ht_info_buf)); - - ht_info->sw_bw_in_progress = false; - - ht_info->peer_ht_spec_ver = HT_SPEC_VER_IEEE; - - ht_info->current_rt2rt_aggregation = false; - ht_info->current_rt2rt_long_slot_time = false; - - ht_info->iot_peer = 0; - ht_info->iot_action = 0; - ht_info->iot_ra_func = 0; - - { - u8 *RegHTSuppRateSets = &ieee->reg_ht_supp_rate_set[0]; - - RegHTSuppRateSets[0] = 0xFF; - RegHTSuppRateSets[1] = 0xFF; - RegHTSuppRateSets[4] = 0x01; - } -} - -void ht_initialize_bss_desc(struct bss_ht *bss_ht) -{ - bss_ht->bd_support_ht = false; - memset(bss_ht->bd_ht_cap_buf, 0, sizeof(bss_ht->bd_ht_cap_buf)); - bss_ht->bd_ht_cap_len = 0; - memset(bss_ht->bd_ht_info_buf, 0, sizeof(bss_ht->bd_ht_info_buf)); - bss_ht->bd_ht_info_len = 0; - - bss_ht->bd_ht_spec_ver = HT_SPEC_VER_IEEE; - - bss_ht->bd_rt2rt_aggregation = false; - bss_ht->bd_rt2rt_long_slot_time = false; - bss_ht->rt2rt_ht_mode = (enum rt_ht_capability)0; -} - -void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee, - struct rtllib_network *network) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - u8 bIOTAction = 0; - - /* unmark enable_ht flag here is the same reason why unmarked in - * function rtllib_softmac_new_net. WB 2008.09.10 - */ - if (network->bssht.bd_support_ht) { - ht_info->current_ht_support = true; - ht_info->peer_ht_spec_ver = network->bssht.bd_ht_spec_ver; - - if (network->bssht.bd_ht_cap_len > 0 && - network->bssht.bd_ht_cap_len <= sizeof(ht_info->peer_ht_cap_buf)) - memcpy(ht_info->peer_ht_cap_buf, - network->bssht.bd_ht_cap_buf, - network->bssht.bd_ht_cap_len); - - if (network->bssht.bd_ht_info_len > 0 && - network->bssht.bd_ht_info_len <= - sizeof(ht_info->peer_ht_info_buf)) - memcpy(ht_info->peer_ht_info_buf, - network->bssht.bd_ht_info_buf, - network->bssht.bd_ht_info_len); - - ht_info->current_rt2rt_aggregation = - network->bssht.bd_rt2rt_aggregation; - ht_info->current_rt2rt_long_slot_time = - network->bssht.bd_rt2rt_long_slot_time; - - ht_iot_peer_determine(ieee); - - ht_info->iot_action = 0; - bIOTAction = ht_iot_act_is_mgnt_use_cck_6m(ieee, network); - if (bIOTAction) - ht_info->iot_action |= HT_IOT_ACT_MGNT_USE_CCK_6M; - bIOTAction = ht_iot_act_is_ccd_fsync(ieee); - if (bIOTAction) - ht_info->iot_action |= HT_IOT_ACT_CDD_FSYNC; - } else { - ht_info->current_ht_support = false; - ht_info->current_rt2rt_aggregation = false; - ht_info->current_rt2rt_long_slot_time = false; - - ht_info->iot_action = 0; - ht_info->iot_ra_func = 0; - } -} - -void HT_update_self_and_peer_setting(struct rtllib_device *ieee, - struct rtllib_network *network) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - struct ht_info_ele *pPeerHTInfo = - (struct ht_info_ele *)network->bssht.bd_ht_info_buf; - - if (ht_info->current_ht_support) { - if (network->bssht.bd_ht_info_len != 0) - ht_info->current_op_mode = pPeerHTInfo->opt_mode; - } -} -EXPORT_SYMBOL(HT_update_self_and_peer_setting); - -u8 ht_c_check(struct rtllib_device *ieee, u8 *frame) -{ - if (ieee->ht_info->current_ht_support) { - if ((is_qos_data_frame(frame) && frame_order(frame)) == 1) { - netdev_dbg(ieee->dev, "HT CONTROL FILED EXIST!!\n"); - return true; - } - } - return false; -} - -static void ht_set_connect_bw_mode_callback(struct rtllib_device *ieee) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - - if (ht_info->cur_bw_40mhz) { - if (ht_info->cur_sta_ext_chnl_offset == HT_EXTCHNL_OFFSET_UPPER) - ieee->set_chan(ieee->dev, - ieee->current_network.channel + 2); - else if (ht_info->cur_sta_ext_chnl_offset == - HT_EXTCHNL_OFFSET_LOWER) - ieee->set_chan(ieee->dev, - ieee->current_network.channel - 2); - else - ieee->set_chan(ieee->dev, - ieee->current_network.channel); - - ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20_40, - ht_info->cur_sta_ext_chnl_offset); - } else { - ieee->set_chan(ieee->dev, ieee->current_network.channel); - ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20, - HT_EXTCHNL_OFFSET_NO_EXT); - } - - ht_info->sw_bw_in_progress = false; -} - -void ht_set_connect_bw_mode(struct rtllib_device *ieee, - enum ht_channel_width bandwidth, - enum ht_extchnl_offset Offset) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - - if (ieee->get_half_nmode_support_by_aps_handler(ieee->dev)) - bandwidth = HT_CHANNEL_WIDTH_20; - - if (ht_info->sw_bw_in_progress) { - pr_info("%s: sw_bw_in_progress!!\n", __func__); - return; - } - if (bandwidth == HT_CHANNEL_WIDTH_20_40) { - if (ieee->current_network.channel < 2 && - Offset == HT_EXTCHNL_OFFSET_LOWER) - Offset = HT_EXTCHNL_OFFSET_NO_EXT; - if (Offset == HT_EXTCHNL_OFFSET_UPPER || - Offset == HT_EXTCHNL_OFFSET_LOWER) { - ht_info->cur_bw_40mhz = true; - ht_info->cur_sta_ext_chnl_offset = Offset; - } else { - ht_info->cur_bw_40mhz = false; - ht_info->cur_sta_ext_chnl_offset = HT_EXTCHNL_OFFSET_NO_EXT; - } - } else { - ht_info->cur_bw_40mhz = false; - ht_info->cur_sta_ext_chnl_offset = HT_EXTCHNL_OFFSET_NO_EXT; - } - - netdev_dbg(ieee->dev, "%s():ht_info->bCurBW40MHz:%x\n", __func__, - ht_info->cur_bw_40mhz); - - ht_info->sw_bw_in_progress = true; - - ht_set_connect_bw_mode_callback(ieee); -} diff --git a/drivers/staging/rtl8192e/rtl819x_Qos.h b/drivers/staging/rtl8192e/rtl819x_Qos.h deleted file mode 100644 index dc991100742f43..00000000000000 --- a/drivers/staging/rtl8192e/rtl819x_Qos.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef __INC_QOS_TYPE_H -#define __INC_QOS_TYPE_H - -struct qos_tsinfo { - u8 ts_id:4; - u8 ucDirection:2; -}; - -struct octet_string { - u8 *octet; - u16 Length; -}; - -#define AC0_BE 0 -#define AC1_BK 1 -#define AC2_VI 2 -#define AC3_VO 3 - -enum direction_value { - DIR_UP = 0, - DIR_DOWN = 1, - DIR_DIRECT = 2, - DIR_BI_DIR = 3, -}; - -union aci_aifsn { - u8 charData; - - struct { - u8 AIFSN:4; - u8 acm:1; - u8 ACI:2; - u8 Reserved:1; - } f; -}; - -#endif diff --git a/drivers/staging/rtl8192e/rtl819x_TS.h b/drivers/staging/rtl8192e/rtl819x_TS.h deleted file mode 100644 index 5b0e4cb572d26f..00000000000000 --- a/drivers/staging/rtl8192e/rtl819x_TS.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#ifndef _TSTYPE_H_ -#define _TSTYPE_H_ -#include "rtl819x_Qos.h" -#define TS_ADDBA_DELAY 60 - -#define TOTAL_TS_NUM 16 - -enum tr_select { - TX_DIR = 0, - RX_DIR = 1, -}; - -struct ts_common_info { - struct list_head list; - u8 addr[ETH_ALEN]; - struct qos_tsinfo tspec; -}; - -struct tx_ts_record { - struct ts_common_info ts_common_info; - u16 tx_cur_seq; - struct ba_record tx_pending_ba_record; - struct ba_record tx_admitted_ba_record; - u8 add_ba_req_in_progress; - u8 add_ba_req_delayed; - u8 using_ba; - u8 disable_add_ba; - struct timer_list ts_add_ba_timer; - u8 num; -}; - -struct rx_ts_record { - struct ts_common_info ts_common_info; - u16 rx_indicate_seq; - u16 rx_timeout_indicate_seq; - struct list_head rx_pending_pkt_list; - struct timer_list rx_pkt_pending_timer; - struct ba_record rx_admitted_ba_record; - u16 rx_last_seq_num; - u8 rx_last_frag_num; - u8 num; -}; - -#endif diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c deleted file mode 100644 index 89092cd434de1f..00000000000000 --- a/drivers/staging/rtl8192e/rtl819x_TSProc.c +++ /dev/null @@ -1,450 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. - * - * Contact Information: wlanfae - */ -#include "rtllib.h" -#include -#include "rtl819x_TS.h" - -static void RxPktPendingTimeout(struct timer_list *t) -{ - struct rx_ts_record *ts = from_timer(ts, t, rx_pkt_pending_timer); - struct rtllib_device *ieee = container_of(ts, struct rtllib_device, - rx_ts_records[ts->num]); - - struct rx_reorder_entry *reorder_entry = NULL; - - unsigned long flags = 0; - u8 index = 0; - bool pkt_in_buf = false; - - spin_lock_irqsave(&(ieee->reorder_spinlock), flags); - if (ts->rx_timeout_indicate_seq != 0xffff) { - while (!list_empty(&ts->rx_pending_pkt_list)) { - reorder_entry = (struct rx_reorder_entry *) - list_entry(ts->rx_pending_pkt_list.prev, - struct rx_reorder_entry, list); - if (index == 0) - ts->rx_indicate_seq = reorder_entry->seq_num; - - if (SN_LESS(reorder_entry->seq_num, - ts->rx_indicate_seq) || - SN_EQUAL(reorder_entry->seq_num, - ts->rx_indicate_seq)) { - list_del_init(&reorder_entry->list); - - if (SN_EQUAL(reorder_entry->seq_num, - ts->rx_indicate_seq)) - ts->rx_indicate_seq = - (ts->rx_indicate_seq + 1) % 4096; - - netdev_dbg(ieee->dev, - "%s(): Indicate seq_num: %d\n", - __func__, reorder_entry->seq_num); - ieee->stats_IndicateArray[index] = - reorder_entry->prxb; - index++; - - list_add_tail(&reorder_entry->list, - &ieee->RxReorder_Unused_List); - } else { - pkt_in_buf = true; - break; - } - } - } - - if (index > 0) { - ts->rx_timeout_indicate_seq = 0xffff; - - if (index > REORDER_WIN_SIZE) { - netdev_warn(ieee->dev, - "%s(): Rx Reorder struct buffer full\n", - __func__); - spin_unlock_irqrestore(&(ieee->reorder_spinlock), - flags); - return; - } - rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index); - pkt_in_buf = false; - } - - if (pkt_in_buf && (ts->rx_timeout_indicate_seq == 0xffff)) { - ts->rx_timeout_indicate_seq = ts->rx_indicate_seq; - mod_timer(&ts->rx_pkt_pending_timer, jiffies + - msecs_to_jiffies(ieee->ht_info->rx_reorder_pending_time) - ); - } - spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); -} - -static void TsAddBaProcess(struct timer_list *t) -{ - struct tx_ts_record *ts = from_timer(ts, t, ts_add_ba_timer); - u8 num = ts->num; - struct rtllib_device *ieee = container_of(ts, struct rtllib_device, - tx_ts_records[num]); - - rtllib_ts_init_add_ba(ieee, ts, BA_POLICY_IMMEDIATE, false); - netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__); -} - -static void ResetTsCommonInfo(struct ts_common_info *ts_common_info) -{ - eth_zero_addr(ts_common_info->addr); - memset(&ts_common_info->tspec, 0, sizeof(struct qos_tsinfo)); -} - -static void ResetTxTsEntry(struct tx_ts_record *ts) -{ - ResetTsCommonInfo(&ts->ts_common_info); - ts->tx_cur_seq = 0; - ts->add_ba_req_in_progress = false; - ts->add_ba_req_delayed = false; - ts->using_ba = false; - ts->disable_add_ba = false; - rtllib_reset_ba_entry(&ts->tx_admitted_ba_record); - rtllib_reset_ba_entry(&ts->tx_pending_ba_record); -} - -static void ResetRxTsEntry(struct rx_ts_record *ts) -{ - ResetTsCommonInfo(&ts->ts_common_info); - ts->rx_indicate_seq = 0xffff; - ts->rx_timeout_indicate_seq = 0xffff; - rtllib_reset_ba_entry(&ts->rx_admitted_ba_record); -} - -void rtllib_ts_init(struct rtllib_device *ieee) -{ - struct tx_ts_record *pTxTS = ieee->tx_ts_records; - struct rx_ts_record *rxts = ieee->rx_ts_records; - struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry; - u8 count = 0; - - INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List); - INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List); - INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List); - - for (count = 0; count < TOTAL_TS_NUM; count++) { - pTxTS->num = count; - timer_setup(&pTxTS->ts_add_ba_timer, TsAddBaProcess, 0); - - timer_setup(&pTxTS->tx_pending_ba_record.timer, rtllib_ba_setup_timeout, - 0); - timer_setup(&pTxTS->tx_admitted_ba_record.timer, - rtllib_tx_ba_inact_timeout, 0); - - ResetTxTsEntry(pTxTS); - list_add_tail(&pTxTS->ts_common_info.list, - &ieee->Tx_TS_Unused_List); - pTxTS++; - } - - INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List); - INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List); - INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List); - for (count = 0; count < TOTAL_TS_NUM; count++) { - rxts->num = count; - INIT_LIST_HEAD(&rxts->rx_pending_pkt_list); - timer_setup(&rxts->rx_admitted_ba_record.timer, - rtllib_rx_ba_inact_timeout, 0); - - timer_setup(&rxts->rx_pkt_pending_timer, RxPktPendingTimeout, 0); - - ResetRxTsEntry(rxts); - list_add_tail(&rxts->ts_common_info.list, - &ieee->Rx_TS_Unused_List); - rxts++; - } - INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); - for (count = 0; count < REORDER_ENTRY_NUM; count++) { - list_add_tail(&pRxReorderEntry->list, - &ieee->RxReorder_Unused_List); - if (count == (REORDER_ENTRY_NUM - 1)) - break; - pRxReorderEntry = &ieee->RxReorderEntry[count + 1]; - } -} - -static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee, - u8 *addr, u8 TID, - enum tr_select tx_rx_select) -{ - u8 dir; - bool search_dir[4] = {0}; - struct list_head *psearch_list; - struct ts_common_info *pRet = NULL; - - if (tx_rx_select == TX_DIR) { - search_dir[DIR_UP] = true; - search_dir[DIR_BI_DIR] = true; - search_dir[DIR_DIRECT] = true; - } else { - search_dir[DIR_DOWN] = true; - search_dir[DIR_BI_DIR] = true; - search_dir[DIR_DIRECT] = true; - } - - if (tx_rx_select == TX_DIR) - psearch_list = &ieee->Tx_TS_Admit_List; - else - psearch_list = &ieee->Rx_TS_Admit_List; - - for (dir = 0; dir <= DIR_BI_DIR; dir++) { - if (!search_dir[dir]) - continue; - list_for_each_entry(pRet, psearch_list, list) { - if (memcmp(pRet->addr, addr, 6) == 0 && - pRet->tspec.ts_id == TID && - pRet->tspec.ucDirection == dir) - break; - } - if (&pRet->list != psearch_list) - break; - } - - if (pRet && &pRet->list != psearch_list) - return pRet; - return NULL; -} - -static void MakeTSEntry(struct ts_common_info *ts_common_info, u8 *addr, - struct qos_tsinfo *pTSPEC) -{ - if (!ts_common_info) - return; - - memcpy(ts_common_info->addr, addr, 6); - - if (pTSPEC) - memcpy((u8 *)(&(ts_common_info->tspec)), (u8 *)pTSPEC, - sizeof(struct qos_tsinfo)); -} - -bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS, - u8 *addr, u8 TID, enum tr_select tx_rx_select, bool add_new_ts) -{ - u8 UP = 0; - struct qos_tsinfo tspec; - struct qos_tsinfo *ts_info = &tspec; - struct list_head *pUnusedList; - struct list_head *pAddmitList; - enum direction_value Dir; - - if (is_multicast_ether_addr(addr)) { - netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n"); - return false; - } - if (ieee->current_network.qos_data.supported == 0) { - UP = 0; - } else { - switch (TID) { - case 0: - case 3: - UP = 0; - break; - case 1: - case 2: - UP = 2; - break; - case 4: - case 5: - UP = 5; - break; - case 6: - case 7: - UP = 7; - break; - default: - netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n", - __func__, TID); - return false; - } - } - - *ppTS = SearchAdmitTRStream(ieee, addr, UP, tx_rx_select); - if (*ppTS) - return true; - - if (!add_new_ts) { - netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP); - return false; - } - - pUnusedList = (tx_rx_select == TX_DIR) ? - (&ieee->Tx_TS_Unused_List) : - (&ieee->Rx_TS_Unused_List); - - pAddmitList = (tx_rx_select == TX_DIR) ? - (&ieee->Tx_TS_Admit_List) : - (&ieee->Rx_TS_Admit_List); - - Dir = ((tx_rx_select == TX_DIR) ? DIR_UP : DIR_DOWN); - - if (!list_empty(pUnusedList)) { - (*ppTS) = list_entry(pUnusedList->next, - struct ts_common_info, list); - list_del_init(&(*ppTS)->list); - if (tx_rx_select == TX_DIR) { - struct tx_ts_record *tmp = - container_of(*ppTS, - struct tx_ts_record, - ts_common_info); - ResetTxTsEntry(tmp); - } else { - struct rx_ts_record *ts = - container_of(*ppTS, - struct rx_ts_record, - ts_common_info); - ResetRxTsEntry(ts); - } - - netdev_dbg(ieee->dev, - "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n", - UP, Dir, addr, *ppTS); - ts_info->ts_id = UP; - ts_info->ucDirection = Dir; - - MakeTSEntry(*ppTS, addr, &tspec); - list_add_tail(&((*ppTS)->list), pAddmitList); - - return true; - } - - netdev_warn(ieee->dev, - "There is not enough dir=%d(0=up down=1) TS record to be used!", - Dir); - return false; -} - -static void RemoveTsEntry(struct rtllib_device *ieee, - struct ts_common_info *pTs, enum tr_select tx_rx_select) -{ - rtllib_ts_init_del_ba(ieee, pTs, tx_rx_select); - - if (tx_rx_select == RX_DIR) { - struct rx_reorder_entry *pRxReorderEntry; - struct rx_ts_record *ts = (struct rx_ts_record *)pTs; - - if (timer_pending(&ts->rx_pkt_pending_timer)) - del_timer_sync(&ts->rx_pkt_pending_timer); - - while (!list_empty(&ts->rx_pending_pkt_list)) { - pRxReorderEntry = (struct rx_reorder_entry *) - list_entry(ts->rx_pending_pkt_list.prev, - struct rx_reorder_entry, list); - netdev_dbg(ieee->dev, "%s(): Delete seq_num %d!\n", - __func__, pRxReorderEntry->seq_num); - list_del_init(&pRxReorderEntry->list); - { - int i = 0; - struct rtllib_rxb *prxb = pRxReorderEntry->prxb; - - if (unlikely(!prxb)) - return; - for (i = 0; i < prxb->nr_subframes; i++) - dev_kfree_skb(prxb->subframes[i]); - kfree(prxb); - prxb = NULL; - } - list_add_tail(&pRxReorderEntry->list, - &ieee->RxReorder_Unused_List); - } - } else { - struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs; - - del_timer_sync(&pTxTS->ts_add_ba_timer); - } -} - -void remove_peer_ts(struct rtllib_device *ieee, u8 *addr) -{ - struct ts_common_info *ts, *pTmpTS; - - netdev_info(ieee->dev, "===========>%s, %pM\n", __func__, addr); - - list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, list) { - if (memcmp(ts->addr, addr, 6) == 0) { - RemoveTsEntry(ieee, ts, TX_DIR); - list_del_init(&ts->list); - list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List); - } - } - - list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, list) { - if (memcmp(ts->addr, addr, 6) == 0) { - netdev_info(ieee->dev, - "====>remove Tx_TS_admin_list\n"); - RemoveTsEntry(ieee, ts, TX_DIR); - list_del_init(&ts->list); - list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List); - } - } - - list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, list) { - if (memcmp(ts->addr, addr, 6) == 0) { - RemoveTsEntry(ieee, ts, RX_DIR); - list_del_init(&ts->list); - list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List); - } - } - - list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, list) { - if (memcmp(ts->addr, addr, 6) == 0) { - RemoveTsEntry(ieee, ts, RX_DIR); - list_del_init(&ts->list); - list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List); - } - } -} -EXPORT_SYMBOL(remove_peer_ts); - -void remove_all_ts(struct rtllib_device *ieee) -{ - struct ts_common_info *ts, *pTmpTS; - - list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, list) { - RemoveTsEntry(ieee, ts, TX_DIR); - list_del_init(&ts->list); - list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List); - } - - list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, list) { - RemoveTsEntry(ieee, ts, TX_DIR); - list_del_init(&ts->list); - list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List); - } - - list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, list) { - RemoveTsEntry(ieee, ts, RX_DIR); - list_del_init(&ts->list); - list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List); - } - - list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, list) { - RemoveTsEntry(ieee, ts, RX_DIR); - list_del_init(&ts->list); - list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List); - } -} - -void rtllib_ts_start_add_ba_process(struct rtllib_device *ieee, struct tx_ts_record *pTxTS) -{ - if (pTxTS->add_ba_req_in_progress == false) { - pTxTS->add_ba_req_in_progress = true; - - if (pTxTS->add_ba_req_delayed) { - netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n"); - mod_timer(&pTxTS->ts_add_ba_timer, jiffies + - msecs_to_jiffies(TS_ADDBA_DELAY)); - } else { - netdev_dbg(ieee->dev, "Immediately Start ADDBA\n"); - mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 10); - } - } 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 deleted file mode 100644 index d6615f787d5302..00000000000000 --- a/drivers/staging/rtl8192e/rtllib.h +++ /dev/null @@ -1,1799 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Merged with mainline rtllib.h in Aug 2004. Original ieee802_11 - * remains copyright by the original authors - * - * Portions of the merged code are based on Host AP (software wireless - * LAN access point) driver for Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * - * Adaption to a generic IEEE 802.11 stack by James Ketrenos - * - * Copyright (c) 2004, Intel Corporation - * - * Modified for Realtek's wi-fi cards by Andrea Merello - * - */ -#ifndef RTLLIB_H -#define RTLLIB_H -#include /* ETH_ALEN */ -#include /* ARRAY_SIZE */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "rtl819x_HT.h" -#include "rtl819x_BA.h" -#include "rtl819x_TS.h" - -#include -#include /* ARPHRD_ETHER */ -#include -#include - -#define MAX_PRECMD_CNT 16 -#define MAX_RFDEPENDCMD_CNT 16 -#define MAX_POSTCMD_CNT 16 - -#ifndef WIRELESS_SPY -#define WIRELESS_SPY -#endif -#include - -#ifndef IW_MODE_MONITOR -#define IW_MODE_MONITOR 6 -#endif - -#ifndef IWEVCUSTOM -#define IWEVCUSTOM 0x8c02 -#endif - -#ifndef IW_CUSTOM_MAX -/* Max number of char in custom event - use multiple of them if needed */ -#define IW_CUSTOM_MAX 256 /* In bytes */ -#endif - -#define container_of_dwork_rsl(x, y, z) \ - container_of(to_delayed_work(x), y, z) - -static inline void *netdev_priv_rsl(struct net_device *dev) -{ - return netdev_priv(dev); -} - -#define KEY_TYPE_NA 0x0 -#define KEY_TYPE_WEP40 0x1 -#define KEY_TYPE_TKIP 0x2 -#define KEY_TYPE_CCMP 0x4 -#define KEY_TYPE_WEP104 0x5 -/* added for rtl819x tx procedure */ -#define MAX_QUEUE_SIZE 0x10 - -#define BK_QUEUE 0 -#define BE_QUEUE 1 -#define VI_QUEUE 2 -#define VO_QUEUE 3 -#define HCCA_QUEUE 4 -#define TXCMD_QUEUE 5 -#define MGNT_QUEUE 6 -#define HIGH_QUEUE 7 -#define BEACON_QUEUE 8 - -#define IE_CISCO_FLAG_POSITION 0x08 -#define SUPPORT_CKIP_MIC 0x08 -#define SUPPORT_CKIP_PK 0x10 -#define RT_RF_OFF_LEVL_HALT_NIC BIT(3) -#define RT_IN_PS_LEVEL(psc, _PS_FLAG) \ - ((psc->cur_ps_level & _PS_FLAG) ? true : false) -#define RT_CLEAR_PS_LEVEL(psc, _PS_FLAG) \ - (psc->cur_ps_level &= (~(_PS_FLAG))) - -/* defined for skb cb field */ -/* At most 28 byte */ -struct cb_desc { - /* Tx Desc Related flags (8-9) */ - u8 last_ini_pkt:1; - u8 cmd_or_init:1; - u8 tx_dis_rate_fallback:1; - u8 tx_use_drv_assinged_rate:1; - u8 hw_sec:1; - - u8 stuck_count; - - /* Tx Firmware Related flags (10-11)*/ - u8 cts_enable:1; - u8 rts_enable:1; - u8 use_short_gi:1; - u8 use_short_preamble:1; - u8 tx_enable_fw_calc_dur:1; - u8 ampdu_enable:1; - u8 rtsstbc:1; - u8 RTSSC:1; - - u8 rts_bw:1; - u8 packet_bw:1; - u8 rts_use_short_preamble:1; - u8 rts_use_short_gi:1; - u8 multicast:1; - u8 broadcast:1; - u8 drv_agg_enable:1; - u8 reserved2:1; - - /* Tx Desc related element(12-19) */ - u8 rata_index; - u8 queue_index; - u16 txbuf_size; - u8 ratr_index; - u8 bAMSDU:1; - u8 bFromAggrQ:1; - u8 reserved6:6; - u8 priority; - - /* Tx firmware related element(20-27) */ - u8 data_rate; - u8 rts_rate; - u8 ampdu_factor; - u8 ampdu_density; - u8 DrvAggrNum; - u8 bdhcp; - u16 pkt_size; - u8 bIsSpecialDataFrame; - - u8 bBTTxPacket; - u8 bIsBTProbRsp; -}; - -enum sw_chnl_cmd_id { - cmd_id_end, - cmd_id_set_tx_power_level, - cmd_id_bbreg_write10, - cmd_id_write_port_ulong, - cmd_id_write_port_ushort, - cmd_id_write_port_uchar, - cmd_id_rf_write_reg, -}; - -struct sw_chnl_cmd { - enum sw_chnl_cmd_id cmd_id; - u32 para1; - u32 para2; - u32 ms_delay; -}; - -/*--------------------------Define -------------------------------------------*/ -#define MGN_1M 0x02 -#define MGN_2M 0x04 -#define MGN_5_5M 0x0b -#define MGN_11M 0x16 - -#define MGN_6M 0x0c -#define MGN_9M 0x12 -#define MGN_12M 0x18 -#define MGN_18M 0x24 -#define MGN_24M 0x30 -#define MGN_36M 0x48 -#define MGN_48M 0x60 -#define MGN_54M 0x6c - -#define MGN_MCS0 0x80 -#define MGN_MCS1 0x81 -#define MGN_MCS2 0x82 -#define MGN_MCS3 0x83 -#define MGN_MCS4 0x84 -#define MGN_MCS5 0x85 -#define MGN_MCS6 0x86 -#define MGN_MCS7 0x87 -#define MGN_MCS8 0x88 -#define MGN_MCS9 0x89 -#define MGN_MCS10 0x8a -#define MGN_MCS11 0x8b -#define MGN_MCS12 0x8c -#define MGN_MCS13 0x8d -#define MGN_MCS14 0x8e -#define MGN_MCS15 0x8f - -enum hw_variables { - HW_VAR_ETHER_ADDR, - HW_VAR_MULTICAST_REG, - HW_VAR_BASIC_RATE, - HW_VAR_BSSID, - HW_VAR_MEDIA_STATUS, - HW_VAR_SECURITY_CONF, - HW_VAR_BEACON_INTERVAL, - HW_VAR_ATIM_WINDOW, - HW_VAR_LISTEN_INTERVAL, - HW_VAR_CS_COUNTER, - HW_VAR_DEFAULTKEY0, - HW_VAR_DEFAULTKEY1, - HW_VAR_DEFAULTKEY2, - HW_VAR_DEFAULTKEY3, - HW_VAR_SIFS, - HW_VAR_DIFS, - HW_VAR_EIFS, - HW_VAR_SLOT_TIME, - HW_VAR_ACK_PREAMBLE, - HW_VAR_CW_CONFIG, - HW_VAR_CW_VALUES, - HW_VAR_RATE_FALLBACK_CONTROL, - HW_VAR_CONTENTION_WINDOW, - HW_VAR_RETRY_COUNT, - HW_VAR_TR_SWITCH, - HW_VAR_COMMAND, - HW_VAR_WPA_CONFIG, - HW_VAR_AMPDU_MIN_SPACE, - HW_VAR_SHORTGI_DENSITY, - HW_VAR_AMPDU_FACTOR, - HW_VAR_MCS_RATE_AVAILABLE, - HW_VAR_AC_PARAM, - HW_VAR_ACM_CTRL, - HW_VAR_DIS_Req_Qsize, - HW_VAR_CCX_CHNL_LOAD, - HW_VAR_CCX_NOISE_HISTOGRAM, - HW_VAR_CCX_CLM_NHM, - HW_VAR_TxOPLimit, - HW_VAR_TURBO_MODE, - HW_VAR_RF_STATE, - HW_VAR_RF_OFF_BY_HW, - HW_VAR_BUS_SPEED, - HW_VAR_SET_DEV_POWER, - - HW_VAR_RCR, - HW_VAR_RATR_0, - HW_VAR_RRSR, - HW_VAR_CPU_RST, - HW_VAR_CECHK_BSSID, - HW_VAR_LBK_MODE, - HW_VAR_AES_11N_FIX, - HW_VAR_USB_RX_AGGR, - HW_VAR_USER_CONTROL_TURBO_MODE, - HW_VAR_RETRY_LIMIT, - HW_VAR_INIT_TX_RATE, - HW_VAR_TX_RATE_REG, - HW_VAR_EFUSE_USAGE, - HW_VAR_EFUSE_BYTES, - HW_VAR_AUTOLOAD_STATUS, - HW_VAR_RF_2R_DISABLE, - HW_VAR_SET_RPWM, - HW_VAR_H2C_FW_PWRMODE, - HW_VAR_H2C_FW_JOINBSSRPT, - HW_VAR_1X1_RECV_COMBINE, - HW_VAR_STOP_SEND_BEACON, - HW_VAR_TSF_TIMER, - HW_VAR_IO_CMD, - - HW_VAR_RF_RECOVERY, - HW_VAR_H2C_FW_UPDATE_GTK, - HW_VAR_WF_MASK, - HW_VAR_WF_CRC, - HW_VAR_WF_IS_MAC_ADDR, - HW_VAR_H2C_FW_OFFLOAD, - HW_VAR_RESET_WFCRC, - - HW_VAR_HANDLE_FW_C2H, - HW_VAR_DL_FW_RSVD_PAGE, - HW_VAR_AID, - HW_VAR_HW_SEQ_ENABLE, - HW_VAR_CORRECT_TSF, - HW_VAR_BCN_VALID, - HW_VAR_FWLPS_RF_ON, - HW_VAR_DUAL_TSF_RST, - HW_VAR_SWITCH_EPHY_WoWLAN, - HW_VAR_INT_MIGRATION, - HW_VAR_INT_AC, - HW_VAR_RF_TIMING, -}; - -enum rt_op_mode { - RT_OP_MODE_AP, - RT_OP_MODE_INFRASTRUCTURE, - RT_OP_MODE_IBSS, - RT_OP_MODE_NO_LINK, -}; - -#define asifs_time \ - ((priv->rtllib->current_network.mode == WIRELESS_MODE_N_24G) ? 16 : 10) - -#define MGMT_QUEUE_NUM 5 - -#define MAX_IE_LEN 0xff - -#define msleep_interruptible_rsl msleep_interruptible - -/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section - * 6.2.1.1.2. - * - * The figure in section 7.1.2 suggests a body size of up to 2312 - * bytes is allowed, which is a bit confusing, I suspect this - * represents the 2304 bytes of real data, plus a possible 8 bytes of - * WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) - */ -#define RTLLIB_1ADDR_LEN 10 -#define RTLLIB_2ADDR_LEN 16 -#define RTLLIB_3ADDR_LEN 24 -#define RTLLIB_4ADDR_LEN 30 -#define RTLLIB_FCS_LEN 4 - -#define RTLLIB_SKBBUFFER_SIZE 2500 - -#define MIN_FRAG_THRESHOLD 256U -#define MAX_FRAG_THRESHOLD 2346U - -#define RTLLIB_FTYPE_MGMT 0x0000 -#define RTLLIB_FTYPE_CTL 0x0004 -#define RTLLIB_FTYPE_DATA 0x0008 - -#define RTLLIB_SCTL_FRAG 0x000F -#define RTLLIB_SCTL_SEQ 0xFFF0 - -/* QOS control */ -#define RTLLIB_QCTL_TID 0x000F - -#define FC_QOS_BIT BIT(7) -#define is_data_frame(pdu) (((pdu[0] & 0x0C) == 0x08) ? true : false) -#define is_legacy_data_frame(pdu) (is_data_frame(pdu) && (!(pdu[0] & FC_QOS_BIT))) -#define is_qos_data_frame(pframe) \ - ((*(u16 *)pframe & (IEEE80211_STYPE_QOS_DATA | RTLLIB_FTYPE_DATA)) == \ - (IEEE80211_STYPE_QOS_DATA | RTLLIB_FTYPE_DATA)) -#define frame_order(pframe) (*(u16 *)pframe & IEEE80211_FCTL_ORDER) -#define SN_LESS(a, b) (((a - b) & 0x800) != 0) -#define SN_EQUAL(a, b) (a == b) -#define MAX_DEV_ADDR_SIZE 8 - -enum act_category { - ACT_CAT_QOS = 1, - ACT_CAT_DLS = 2, - ACT_CAT_BA = 3, - ACT_CAT_HT = 7, - ACT_CAT_WMM = 17, -}; - -enum ba_action { - ACT_ADDBAREQ = 0, - ACT_ADDBARSP = 1, - ACT_DELBA = 2, -}; - -enum init_gain_op_type { - IG_Backup = 0, - IG_Restore, - IG_Max -}; - -enum wireless_mode { - WIRELESS_MODE_UNKNOWN = 0x00, - WIRELESS_MODE_A = 0x01, - WIRELESS_MODE_B = 0x02, - WIRELESS_MODE_G = 0x04, - WIRELESS_MODE_AUTO = 0x08, - WIRELESS_MODE_N_24G = 0x10, -}; - -#ifndef ETH_P_PAE -#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#define ETH_P_ARP 0x0806 /* Address Resolution packet */ -#endif /* ETH_P_PAE */ - -#ifndef ETH_P_80211_RAW -#define ETH_P_80211_RAW (ETH_P_ECONET + 1) -#endif - -/* IEEE 802.11 defines */ - -#define P80211_OUI_LEN 3 - -struct rtllib_snap_hdr { - u8 dsap; /* always 0xAA */ - u8 ssap; /* always 0xAA */ - u8 ctrl; /* always 0x03 */ - u8 oui[P80211_OUI_LEN]; /* organizational universal id */ - -} __packed; - -enum _REG_PREAMBLE_MODE { - PREAMBLE_LONG = 1, - PREAMBLE_AUTO = 2, - PREAMBLE_SHORT = 3, -}; - -#define SNAP_SIZE sizeof(struct rtllib_snap_hdr) - -#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) -#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) -#define WLAN_FC_MORE_DATA(fc) ((fc) & IEEE80211_FCTL_MOREDATA) - -#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTLLIB_SCTL_FRAG) -#define WLAN_GET_SEQ_SEQ(seq) (((seq) & RTLLIB_SCTL_SEQ) >> 4) - -#define RTLLIB_STATMASK_SIGNAL (1 << 0) -#define RTLLIB_STATMASK_RSSI (1 << 1) -#define RTLLIB_STATMASK_NOISE (1 << 2) -#define RTLLIB_STATMASK_WEMASK 0x7 - -#define RTLLIB_CCK_MODULATION (1 << 0) -#define RTLLIB_OFDM_MODULATION (1 << 1) - -#define RTLLIB_CCK_RATE_LEN 4 -#define RTLLIB_CCK_RATE_1MB 0x02 -#define RTLLIB_CCK_RATE_2MB 0x04 -#define RTLLIB_CCK_RATE_5MB 0x0B -#define RTLLIB_CCK_RATE_11MB 0x16 -#define RTLLIB_OFDM_RATE_LEN 8 -#define RTLLIB_OFDM_RATE_6MB 0x0C -#define RTLLIB_OFDM_RATE_9MB 0x12 -#define RTLLIB_OFDM_RATE_12MB 0x18 -#define RTLLIB_OFDM_RATE_18MB 0x24 -#define RTLLIB_OFDM_RATE_24MB 0x30 -#define RTLLIB_OFDM_RATE_36MB 0x48 -#define RTLLIB_OFDM_RATE_48MB 0x60 -#define RTLLIB_OFDM_RATE_54MB 0x6C -#define RTLLIB_BASIC_RATE_MASK 0x80 - -/* this is stolen and modified from the madwifi driver*/ -#define RTLLIB_FC0_TYPE_MASK 0x0c -#define RTLLIB_FC0_TYPE_DATA 0x08 -#define RTLLIB_FC0_SUBTYPE_MASK 0xB0 -#define RTLLIB_FC0_SUBTYPE_QOS 0x80 - -#define RTLLIB_QOS_HAS_SEQ(fc) \ - (((fc) & (RTLLIB_FC0_TYPE_MASK | RTLLIB_FC0_SUBTYPE_MASK)) == \ - (RTLLIB_FC0_TYPE_DATA | RTLLIB_FC0_SUBTYPE_QOS)) - -/* this is stolen from ipw2200 driver */ -#define IEEE_IBSS_MAC_HASH_SIZE 31 - -/* NOTE: This data is for statistical purposes; not all hardware provides this - * information for frames received. Not setting these will not cause - * any adverse affects. - */ -struct rtllib_rx_stats { - s8 rssi; - u8 signal; - u8 noise; - u16 rate; /* in 100 kbps */ - u8 control; - u8 mask; - u16 len; - u16 Length; - u8 signal_quality; - s32 RecvSignalPower; - u8 signal_strength; - u16 hw_error:1; - u16 bCRC:1; - u16 bICV:1; - u16 decrypted:1; - u32 time_stamp_low; - u32 time_stamp_high; - - u8 rx_drv_info_size; - u8 rx_buf_shift; - bool bIsAMPDU; - bool bFirstMPDU; - bool contain_htc; - u32 RxPWDBAll; - u8 RxMIMOSignalStrength[2]; - s8 RxMIMOSignalQuality[2]; - bool bPacketMatchBSSID; - bool bIsCCK; - bool packet_to_self; - bool bPacketBeacon; - bool bToSelfBA; -}; - -/* IEEE 802.11 requires that STA supports concurrent reception of at least - * three fragmented frames. This define can be increased to support more - * concurrent frames, but it should be noted that each entry can consume about - * 2 kB of RAM and increasing cache size will slow down frame reassembly. - */ -#define RTLLIB_FRAG_CACHE_LEN 4 - -struct rtllib_frag_entry { - unsigned long first_frag_time; - unsigned int seq; - unsigned int last_frag; - struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; -}; - -struct rtllib_device; - -#define SEC_ACTIVE_KEY (1 << 4) -#define SEC_AUTH_MODE (1 << 5) -#define SEC_UNICAST_GROUP (1 << 6) -#define SEC_LEVEL (1 << 7) -#define SEC_ENABLED (1 << 8) - -#define SEC_LEVEL_0 0 /* None */ -#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ -#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ -#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ -#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ - -#define SEC_ALG_NONE 0 -#define SEC_ALG_WEP 1 -#define SEC_ALG_TKIP 2 -#define SEC_ALG_CCMP 4 - -#define WEP_KEY_LEN 13 -#define SCM_KEY_LEN 32 - -struct rtllib_security { - u16 active_key:2, - enabled:1, - auth_mode:2, - auth_algo:4, - unicast_uses_group:1, - encrypt:1; - u8 key_sizes[NUM_WEP_KEYS]; - u8 keys[NUM_WEP_KEYS][SCM_KEY_LEN]; - u8 level; - u16 flags; -} __packed; - -/* 802.11 data frame from AP - * ,-------------------------------------------------------------------. - * Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | - * |------|------|---------|---------|---------|------|---------|------| - * Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | - * | | tion | (BSSID) | | | ence | data | | - * `-------------------------------------------------------------------' - * Total: 28-2340 bytes - */ - -/* Management Frame Information Element Types */ -enum rtllib_mfie { - MFIE_TYPE_SSID = 0, - MFIE_TYPE_RATES = 1, - MFIE_TYPE_FH_SET = 2, - MFIE_TYPE_DS_SET = 3, - MFIE_TYPE_CF_SET = 4, - MFIE_TYPE_TIM = 5, - MFIE_TYPE_IBSS_SET = 6, - MFIE_TYPE_COUNTRY = 7, - MFIE_TYPE_HOP_PARAMS = 8, - MFIE_TYPE_HOP_TABLE = 9, - MFIE_TYPE_REQUEST = 10, - MFIE_TYPE_CHALLENGE = 16, - MFIE_TYPE_POWER_CONSTRAINT = 32, - MFIE_TYPE_POWER_CAPABILITY = 33, - MFIE_TYPE_TPC_REQUEST = 34, - MFIE_TYPE_TPC_REPORT = 35, - MFIE_TYPE_SUPP_CHANNELS = 36, - MFIE_TYPE_CSA = 37, - MFIE_TYPE_MEASURE_REQUEST = 38, - MFIE_TYPE_MEASURE_REPORT = 39, - MFIE_TYPE_QUIET = 40, - MFIE_TYPE_IBSS_DFS = 41, - MFIE_TYPE_ERP = 42, - MFIE_TYPE_HT_CAP = 45, - MFIE_TYPE_RSN = 48, - MFIE_TYPE_RATES_EX = 50, - MFIE_TYPE_HT_INFO = 61, - MFIE_TYPE_AIRONET = 133, - MFIE_TYPE_GENERIC = 221, - MFIE_TYPE_QOS_PARAMETER = 222, -}; - -/* Minimal header; can be used for passing 802.11 frames with sufficient - * information to determine what type of underlying data type is actually - * stored in the data. - */ -struct rtllib_info_element { - u8 id; - u8 len; - u8 data[]; -} __packed; - -struct rtllib_authentication { - struct ieee80211_hdr_3addr header; - __le16 algorithm; - __le16 transaction; - __le16 status; - /*challenge*/ - struct rtllib_info_element info_element[]; -} __packed __aligned(2); - -struct rtllib_disauth { - struct ieee80211_hdr_3addr header; - __le16 reason; -} __packed __aligned(2); - -struct rtllib_disassoc { - struct ieee80211_hdr_3addr header; - __le16 reason; -} __packed __aligned(2); - -struct rtllib_probe_request { - struct ieee80211_hdr_3addr header; - /* SSID, supported rates */ - struct rtllib_info_element info_element[]; -} __packed __aligned(2); - -struct rtllib_probe_response { - struct ieee80211_hdr_3addr header; - u32 time_stamp[2]; - __le16 beacon_interval; - __le16 capability; - /* SSID, supported rates, FH params, DS params, - * CF params, IBSS params, TIM (if beacon), RSN - */ - struct rtllib_info_element info_element[]; -} __packed __aligned(2); - -/* Alias beacon for probe_response */ -#define rtllib_beacon rtllib_probe_response - -struct rtllib_assoc_request_frame { - struct ieee80211_hdr_3addr header; - __le16 capability; - __le16 listen_interval; - /* SSID, supported rates, RSN */ - struct rtllib_info_element info_element[]; -} __packed __aligned(2); - -struct rtllib_assoc_response_frame { - struct ieee80211_hdr_3addr header; - __le16 capability; - __le16 status; - __le16 aid; - struct rtllib_info_element info_element[]; /* supported rates */ -} __packed __aligned(2); - -struct rtllib_txb { - u8 nr_frags; - u8 encrypted; - u8 queue_index; - u8 rts_included; - u16 reserved; - __le16 frag_size; - __le16 payload_size; - struct sk_buff *fragments[] __counted_by(nr_frags); -}; - -#define MAX_SUBFRAME_COUNT 64 -struct rtllib_rxb { - u8 nr_subframes; - struct sk_buff *subframes[MAX_SUBFRAME_COUNT]; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; -}; - -union frameqos { - u16 shortdata; - u8 chardata[2]; - struct { - u16 tid:4; - u16 eosp:1; - u16 ack_policy:2; - u16 reserved:1; - u16 txop:8; - } field; -}; - -/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs - * only use 8, and then use extended rates for the remaining supported - * rates. Other APs, however, stick all of their supported rates on the - * main rates information element... - */ -#define MAX_RATES_LENGTH ((u8)12) -#define MAX_RATES_EX_LENGTH ((u8)16) -#define MAX_NETWORK_COUNT 96 - -#define MAX_CHANNEL_NUMBER 161 -#define RTLLIB_SOFTMAC_SCAN_TIME 100 -#define RTLLIB_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) - -#define MAX_WPA_IE_LEN 64 -#define MAX_WZC_IE_LEN 256 - -#define NETWORK_EMPTY_ESSID (1 << 0) -#define NETWORK_HAS_OFDM (1 << 1) -#define NETWORK_HAS_CCK (1 << 2) - -/* QoS structure */ -#define NETWORK_HAS_QOS_PARAMETERS (1 << 3) -#define NETWORK_HAS_QOS_INFORMATION (1 << 4) -#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \ - NETWORK_HAS_QOS_INFORMATION) -/* 802.11h */ -#define NETWORK_HAS_ERP_VALUE (1 << 10) - -#define QOS_QUEUE_NUM 4 -#define QOS_OUI_LEN 3 -#define QOS_OUI_TYPE 2 -#define QOS_ELEMENT_ID 221 -#define QOS_OUI_INFO_SUB_TYPE 0 -#define QOS_OUI_PARAM_SUB_TYPE 1 -#define QOS_VERSION_1 1 - -struct rtllib_qos_information_element { - u8 element_id; - u8 length; - u8 qui[QOS_OUI_LEN]; - u8 qui_type; - u8 qui_subtype; - u8 version; - u8 ac_info; -} __packed; - -struct rtllib_qos_ac_parameter { - u8 aci_aifsn; - u8 ecw_min_max; - __le16 tx_op_limit; -} __packed; - -struct rtllib_qos_parameter_info { - struct rtllib_qos_information_element info_element; - u8 reserved; - struct rtllib_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; -} __packed; - -struct rtllib_qos_parameters { - __le16 cw_min[QOS_QUEUE_NUM]; - __le16 cw_max[QOS_QUEUE_NUM]; - u8 aifs[QOS_QUEUE_NUM]; - u8 flag[QOS_QUEUE_NUM]; - __le16 tx_op_limit[QOS_QUEUE_NUM]; -} __packed; - -struct rtllib_qos_data { - struct rtllib_qos_parameters parameters; - unsigned int wmm_acm; - int active; - int supported; - u8 param_count; - u8 old_param_count; -}; - -struct rtllib_tim_parameters { - u8 tim_count; - u8 tim_period; -} __packed; - -struct rtllib_wmm_ac_param { - u8 ac_aci_acm_aifsn; - u8 ac_ecwmin_ecwmax; - u16 ac_txop_limit; -}; - -enum eap_type { - EAP_PACKET = 0, - EAPOL_START, - EAPOL_LOGOFF, - EAPOL_KEY, - EAPOL_ENCAP_ASF_ALERT -}; - -static const char * const eap_types[] = { - [EAP_PACKET] = "EAP-Packet", - [EAPOL_START] = "EAPOL-Start", - [EAPOL_LOGOFF] = "EAPOL-Logoff", - [EAPOL_KEY] = "EAPOL-Key", - [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" -}; - -static inline const char *eap_get_type(int type) -{ - return ((u32)type >= ARRAY_SIZE(eap_types)) ? "Unknown" : - eap_types[type]; -} - -static inline u8 frame_qos_tid(u8 *buf) -{ - struct ieee80211_hdr_3addr *hdr; - u16 fc; - - hdr = (struct ieee80211_hdr_3addr *)buf; - fc = le16_to_cpu(hdr->frame_control); - return (u8)((union frameqos *)(buf + (((fc & IEEE80211_FCTL_TODS) && - (fc & IEEE80211_FCTL_FROMDS)) ? 30 : 24)))->field.tid; -} - -struct eapol { - u8 snap[6]; - u16 ethertype; - u8 version; - u8 type; - u16 length; -} __packed; - -struct rtllib_softmac_stats { - unsigned int rx_ass_ok; - unsigned int rx_ass_err; - unsigned int rx_probe_rq; - unsigned int tx_probe_rs; - unsigned int tx_beacons; - unsigned int rx_auth_rq; - unsigned int rx_auth_rs_ok; - unsigned int rx_auth_rs_err; - unsigned int tx_auth_rq; - unsigned int no_auth_rs; - unsigned int no_ass_rs; - unsigned int tx_ass_rq; - unsigned int rx_ass_rq; - unsigned int tx_probe_rq; - unsigned int reassoc; - unsigned int swtxstop; - unsigned int swtxawake; - unsigned char CurrentShowTxate; - unsigned char last_packet_rate; - unsigned int txretrycount; -}; - -/* These are the data types that can make up management packets - * - * u16 auth_algorithm; - * u16 auth_sequence; - * u16 beacon_interval; - * u16 capability; - * u8 current_ap[ETH_ALEN]; - * u16 listen_interval; - * struct { - * u16 association_id:14, reserved:2; - * } __packed; - * u32 time_stamp[2]; - * u16 reason; - * u16 status; - */ - -#define RTLLIB_DEFAULT_TX_ESSID "Penguin" -#define RTLLIB_DEFAULT_BASIC_RATE 2 - -enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; -#define MAX_SP_Len (WMM_all_frame << 4) -#define RTLLIB_QOS_TID 0x0f -#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) - -#define RTLLIB_DTIM_MBCAST 4 -#define RTLLIB_DTIM_UCAST 2 -#define RTLLIB_DTIM_VALID 1 -#define RTLLIB_DTIM_INVALID 0 - -#define RTLLIB_PS_DISABLED 0 -#define RTLLIB_PS_UNICAST RTLLIB_DTIM_UCAST -#define RTLLIB_PS_MBCAST RTLLIB_DTIM_MBCAST - -#define WME_AC_BK 0x00 -#define WME_AC_BE 0x01 -#define WME_AC_VI 0x02 -#define WME_AC_VO 0x03 -#define WME_AC_PRAM_LEN 16 - -#define MAX_RECEIVE_BUFFER_SIZE 9100 - -#define UP2AC(up) ( \ - ((up) < 1) ? WME_AC_BE : \ - ((up) < 3) ? WME_AC_BK : \ - ((up) < 4) ? WME_AC_BE : \ - ((up) < 6) ? WME_AC_VI : \ - WME_AC_VO) - -#define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address - * plus ether type - */ - -enum erp_t { - ERP_NonERPpresent = 0x01, - ERP_UseProtection = 0x02, - ERP_BarkerPreambleMode = 0x04, -}; - -struct rtllib_network { - /* These entries are used to identify a unique network */ - u8 bssid[ETH_ALEN]; - u8 channel; - /* Ensure null-terminated for any debug msgs */ - u8 ssid[IW_ESSID_MAX_SIZE + 1]; - u8 ssid_len; - u8 hidden_ssid[IW_ESSID_MAX_SIZE + 1]; - u8 hidden_ssid_len; - struct rtllib_qos_data qos_data; - - bool with_aironet_ie; - bool ckip_supported; - bool ccx_rm_enable; - u8 ccx_rm_state[2]; - bool mb_ssid_valid; - u8 mb_ssid_mask; - u8 mb_ssid[ETH_ALEN]; - bool with_ccx_ver_num; - u8 bss_ccx_ver_number; - /* These are network statistics */ - struct rtllib_rx_stats stats; - u16 capability; - u8 rates[MAX_RATES_LENGTH]; - u8 rates_len; - u8 rates_ex[MAX_RATES_EX_LENGTH]; - u8 rates_ex_len; - unsigned long last_scanned; - u8 mode; - u32 flags; - u32 time_stamp[2]; - u16 beacon_interval; - u16 listen_interval; - u16 atim_window; - u8 erp_value; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - u8 wzc_ie[MAX_WZC_IE_LEN]; - size_t wzc_ie_len; - - struct rtllib_tim_parameters tim; - u8 dtim_period; - u8 dtim_data; - u64 last_dtim_sta_time; - - u8 wmm_info; - struct rtllib_wmm_ac_param wmm_param[4]; - u8 turbo_enable; - u16 country_ie_len; - u8 country_ie_buf[MAX_IE_LEN]; - struct bss_ht bssht; - bool broadcom_cap_exist; - bool realtek_cap_exit; - bool marvell_cap_exist; - bool ralink_cap_exist; - bool atheros_cap_exist; - bool cisco_cap_exist; - bool airgo_cap_exist; - bool unknown_cap_exist; - bool berp_info_valid; - bool buseprotection; - u8 signal_strength; - u8 RSSI; - struct list_head list; -}; - -enum rtl_link_state { - /* the card is not linked at all */ - MAC80211_NOLINK = 0, - - /* RTLLIB_ASSOCIATING* are for BSS client mode - * the driver shall not perform RX filtering unless - * the state is LINKED. - * The driver shall just check for the state LINKED and - * defaults to NOLINK for ALL the other states (including - * LINKED_SCANNING) - */ - - /* the association procedure will start (wq scheduling)*/ - RTLLIB_ASSOCIATING, - RTLLIB_ASSOCIATING_RETRY, - - /* the association procedure is sending AUTH request*/ - RTLLIB_ASSOCIATING_AUTHENTICATING, - - /* the association procedure has successfully authenticated - * and is sending association request - */ - RTLLIB_ASSOCIATING_AUTHENTICATED, - - /* the link is ok. the card associated to a BSS or linked - * to a ibss cell or acting as an AP and creating the bss - */ - MAC80211_LINKED, - - /* same as LINKED, but the driver shall apply RX filter - * rules as we are in NO_LINK mode. As the card is still - * logically linked, but it is doing a syncro site survey - * then it will be back to LINKED state. - */ - MAC80211_LINKED_SCANNING, -}; - -#define DEFAULT_MAX_SCAN_AGE (15 * HZ) -#define DEFAULT_FTS 2346 - -#define CFG_RTLLIB_RESERVE_FCS (1 << 0) -#define CFG_RTLLIB_COMPUTE_FCS (1 << 1) - -struct tx_pending { - int frag; - struct rtllib_txb *txb; -}; - -struct bandwidth_autoswitch { - long threshold_20Mhzto40Mhz; - long threshold_40Mhzto20Mhz; - bool forced_tx_20MHz; - bool bautoswitch_enable; -}; - -#define REORDER_WIN_SIZE 128 -#define REORDER_ENTRY_NUM 128 -struct rx_reorder_entry { - struct list_head list; - u16 seq_num; - struct rtllib_rxb *prxb; -}; - -enum fsync_state { - DEFAULT_FSYNC, - HW_FSYNC, - SW_FSYNC -}; - -enum ips_callback_function { - IPS_CALLBACK_NONE = 0, - IPS_CALLBACK_MGNT_LINK_REQUEST = 1, - IPS_CALLBACK_JOIN_REQUEST = 2, -}; - -enum rt_rf_power_state { - rf_on, - rf_sleep, - rf_off -}; - -struct rt_pwr_save_ctrl { - bool bSwRfProcessing; - enum rt_rf_power_state eInactivePowerState; - enum ips_callback_function return_point; - - bool bLeisurePs; - u8 lps_idle_count; - u8 lps_awake_intvl; - - u32 cur_ps_level; -}; - -#define RT_RF_CHANGE_SOURCE u32 - -#define RF_CHANGE_BY_SW BIT(31) -#define RF_CHANGE_BY_HW BIT(30) -#define RF_CHANGE_BY_PS BIT(29) -#define RF_CHANGE_BY_IPS BIT(28) -#define RF_CHANGE_BY_INIT 0 - -enum country_code_type { - COUNTRY_CODE_FCC = 0, - COUNTRY_CODE_IC = 1, - COUNTRY_CODE_ETSI = 2, - COUNTRY_CODE_SPAIN = 3, - COUNTRY_CODE_FRANCE = 4, - COUNTRY_CODE_MKK = 5, - COUNTRY_CODE_MKK1 = 6, - COUNTRY_CODE_ISRAEL = 7, - COUNTRY_CODE_TELEC = 8, - COUNTRY_CODE_MIC = 9, - COUNTRY_CODE_GLOBAL_DOMAIN = 10, - COUNTRY_CODE_WORLD_WIDE_13 = 11, - COUNTRY_CODE_TELEC_NETGEAR = 12, - COUNTRY_CODE_MAX -}; - -enum scan_op_backup_opt { - SCAN_OPT_BACKUP = 0, - SCAN_OPT_RESTORE, - SCAN_OPT_MAX -}; - -#define RT_MAX_LD_SLOT_NUM 10 -struct rt_link_detect { - u32 num_recv_bcn_in_period; - u32 num_recv_data_in_period; - - u32 RxBcnNum[RT_MAX_LD_SLOT_NUM]; - u32 RxDataNum[RT_MAX_LD_SLOT_NUM]; - u16 slot_num; - u16 slot_index; - - u32 num_tx_ok_in_period; - u32 num_rx_ok_in_period; - u32 num_rx_unicast_ok_in_period; - bool busy_traffic; - bool bHigherBusyTraffic; - bool bHigherBusyRxTraffic; -}; - -struct sw_cam_table { - u8 macaddr[ETH_ALEN]; - bool bused; - u8 key_buf[16]; - u16 key_type; - u8 useDK; - u8 key_index; - -}; - -#define TOTAL_CAM_ENTRY 32 -struct rate_adaptive { - u8 ratr_state; - u16 reserve; - - u32 high_rssi_thresh_for_ra; - u32 high2low_rssi_thresh_for_ra; - u8 low2high_rssi_thresh_for_ra40M; - u32 low_rssi_thresh_for_ra40M; - u8 low2high_rssi_thresh_for_ra20M; - u32 low_rssi_thresh_for_ra20M; - u32 upper_rssi_threshold_ratr; - u32 middle_rssi_threshold_ratr; - u32 low_rssi_threshold_ratr; - u32 low_rssi_threshold_ratr_40M; - u32 low_rssi_threshold_ratr_20M; - u8 ping_rssi_enable; - u32 ping_rssi_ratr; - u32 ping_rssi_thresh_for_ra; - u8 PreRATRState; - -}; - -#define NUM_PMKID_CACHE 16 -struct rt_pmkid_list { - u8 bssid[ETH_ALEN]; - u8 PMKID[16]; - u8 SsidBuf[33]; - u8 used; -}; - -/*************** DRIVER STATUS *****/ -#define STATUS_SCANNING 0 -/*************** DRIVER STATUS *****/ - -enum { - LPS_IS_WAKE = 0, - LPS_IS_SLEEP = 1, - LPS_WAIT_NULL_DATA_SEND = 2, -}; - -struct rtllib_device { - struct pci_dev *pdev; - struct net_device *dev; - struct rtllib_security sec; - - bool disable_mgnt_queue; - - unsigned long status; - u8 cnt_after_link; - - enum rt_op_mode op_mode; - - /* The last AssocReq/Resp IEs */ - u8 *assocreq_ies, *assocresp_ies; - size_t assocreq_ies_len, assocresp_ies_len; - - bool forced_bg_mode; - - u8 hwsec_active; - bool is_roaming; - bool ieee_up; - bool cannot_notify; - bool bSupportRemoteWakeUp; - bool actscanning; - bool first_ie_in_scan; - bool be_scan_inprogress; - bool beinretry; - enum rt_rf_power_state rf_power_state; - RT_RF_CHANGE_SOURCE rf_off_reason; - bool is_set_key; - bool wx_set_enc; - struct rt_hi_throughput *ht_info; - - spinlock_t reorder_spinlock; - u8 reg_dot11ht_oper_rate_set[16]; - u8 reg_dot11tx_ht_oper_rate_set[16]; - u8 dot11ht_oper_rate_set[16]; - u8 reg_ht_supp_rate_set[16]; - u8 ht_curr_op_rate; - u8 HTHighestOperaRate; - u8 tx_dis_rate_fallback; - u8 tx_use_drv_assinged_rate; - u8 tx_enable_fw_calc_dur; - atomic_t atm_swbw; - - struct list_head Tx_TS_Admit_List; - struct list_head Tx_TS_Pending_List; - struct list_head Tx_TS_Unused_List; - struct tx_ts_record tx_ts_records[TOTAL_TS_NUM]; - struct list_head Rx_TS_Admit_List; - struct list_head Rx_TS_Pending_List; - struct list_head Rx_TS_Unused_List; - struct rx_ts_record rx_ts_records[TOTAL_TS_NUM]; - 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; - - /* Probe / Beacon management */ - struct list_head network_free_list; - struct list_head network_list; - struct rtllib_network *networks; - int scans; - int scan_age; - - int iw_mode; /* operating mode (IW_MODE_*) */ - - spinlock_t lock; - spinlock_t wpax_suitlist_lock; - - int tx_headroom; /* Set to size of any additional room needed at front - * of allocated Tx SKBs - */ - u32 config; - - /* WEP and other encryption related settings at the device level */ - int open_wep; /* Set to 1 to allow unencrypted frames */ - int auth_mode; - int reset_on_keychange; /* Set to 1 if the HW needs to be reset on - * WEP key changes - */ - - int ieee802_1x; /* is IEEE 802.1X used */ - - /* WPA data */ - bool half_wireless_n24g_mode; - int wpa_enabled; - int drop_unencrypted; - int tkip_countermeasures; - int privacy_invoked; - size_t wpa_ie_len; - u8 *wpa_ie; - size_t wps_ie_len; - u8 *wps_ie; - u8 ap_mac_addr[ETH_ALEN]; - u16 pairwise_key_type; - u16 group_key_type; - - struct lib80211_crypt_info crypt_info; - - struct sw_cam_table swcamtable[TOTAL_CAM_ENTRY]; - - struct rt_pmkid_list pmkid_list[NUM_PMKID_CACHE]; - - /* Fragmentation structures */ - struct rtllib_frag_entry frag_cache[17][RTLLIB_FRAG_CACHE_LEN]; - unsigned int frag_next_idx[17]; - u16 fts; /* Fragmentation Threshold */ -#define DEFAULT_RTS_THRESHOLD 2346U -#define MIN_RTS_THRESHOLD 1 -#define MAX_RTS_THRESHOLD 2346U - u16 rts; /* RTS threshold */ - - /* Association info */ - u8 bssid[ETH_ALEN]; - - /* This stores infos for the current network. - * Either the network we are associated in INFRASTRUCTURE - * or the network that we are creating in MASTER mode. - * ad-hoc is a mixture ;-). - * Note that in infrastructure mode, even when not associated, - * fields bssid and essid may be valid (if wpa_set and essid_set - * are true) as thy carry the value set by the user via iwconfig - */ - struct rtllib_network current_network; - - enum rtl_link_state link_state; - - int mode; /* A, B, G */ - - /* used for forcing the ibss workqueue to terminate - * without wait for the syncro scan to terminate - */ - short sync_scan_hurryup; - u16 scan_watch_dog; - - /* map of allowed channels. 0 is dummy */ - u8 active_channel_map[MAX_CHANNEL_NUMBER + 1]; - - int rate; /* current rate */ - int basic_rate; - - /* this contains flags for selectively enable softmac support */ - u16 softmac_features; - - /* if the sequence control field is not filled by HW */ - u16 seq_ctrl[5]; - - /* association procedure transaction sequence number */ - u16 associate_seq; - - /* AID for RTXed association responses */ - u16 assoc_id; - - /* power save mode related*/ - u8 ack_tx_to_ieee; - short ps; - short sta_sleep; - int ps_timeout; - int ps_period; - struct work_struct ps_task; - u64 ps_time; - bool polling; - - /* used if IEEE_SOFTMAC_TX_QUEUE is set */ - short queue_stop; - short scanning_continue; - short proto_started; - short proto_stoppping; - - struct mutex wx_mutex; - struct mutex scan_mutex; - struct mutex ips_mutex; - - spinlock_t mgmt_tx_lock; - spinlock_t beacon_lock; - - short beacon_txing; - - short wap_set; - short ssid_set; - - /* set on initialization */ - unsigned int wmm_acm; - - /* for discarding duplicated packets in IBSS */ - struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; - - /* for discarding duplicated packets in BSS */ - u16 last_rxseq_num[17]; /* rx seq previous per-tid */ - u16 last_rxfrag_num[17];/* tx frag previous per-tid */ - unsigned long last_packet_time[17]; - - /* for PS mode */ - unsigned long last_rx_ps_time; - bool awake_pkt_sent; - u8 lps_delay_cnt; - - /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ - struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; - int mgmt_queue_head; - int mgmt_queue_tail; - u8 asoc_retry_count; - struct sk_buff_head skb_waitq[MAX_QUEUE_SIZE]; - - bool bdynamic_txpower_enable; - - bool bCTSToSelfEnable; - - u32 fsync_time_interval; - u32 fsync_rate_bitmap; - u8 fsync_rssi_threshold; - bool bfsync_enable; - - u8 fsync_multiple_timeinterval; - u32 fsync_firstdiff_ratethreshold; - u32 fsync_seconddiff_ratethreshold; - enum fsync_state fsync_state; - bool bis_any_nonbepkts; - struct bandwidth_autoswitch bandwidth_auto_switch; - bool FwRWRF; - - struct rt_link_detect link_detect_info; - bool is_aggregate_frame; - struct rt_pwr_save_ctrl pwr_save_ctrl; - - /* used if IEEE_SOFTMAC_TX_QUEUE is set */ - struct tx_pending tx_pending; - - /* used if IEEE_SOFTMAC_ASSOCIATE is set */ - struct timer_list associate_timer; - - /* used if IEEE_SOFTMAC_BEACONS is set */ - u8 need_sw_enc; - struct work_struct associate_complete_wq; - struct work_struct ips_leave_wq; - struct delayed_work associate_procedure_wq; - struct delayed_work softmac_scan_wq; - struct delayed_work associate_retry_wq; - struct delayed_work hw_wakeup_wq; - struct delayed_work hw_sleep_wq; - struct delayed_work link_change_wq; - struct work_struct wx_sync_scan_wq; - - union { - struct rtllib_rxb *rfd_array[REORDER_WIN_SIZE]; - struct rtllib_rxb *stats_IndicateArray[REORDER_WIN_SIZE]; - struct rtllib_rxb *prxb_indicate_array[REORDER_WIN_SIZE]; - struct { - struct sw_chnl_cmd PreCommonCmd[MAX_PRECMD_CNT]; - struct sw_chnl_cmd PostCommonCmd[MAX_POSTCMD_CNT]; - struct sw_chnl_cmd RfDependCmd[MAX_RFDEPENDCMD_CNT]; - }; - }; - - /* Callback functions */ - - /* Softmac-generated frames (management) are TXed via this - * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is - * not set. As some cards may have different HW queues that - * one might want to use for data and management frames - * the option to have two callbacks might be useful. - * This function can't sleep. - */ - int (*softmac_hard_start_xmit)(struct sk_buff *skb, - struct net_device *dev); - - /* used instead of hard_start_xmit (not softmac_hard_start_xmit) - * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data - * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set - * then also management frames are sent via this callback. - * This function can't sleep. - */ - void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, - struct net_device *dev, int rate); - - /* ask to the driver to retune the radio. - * This function can sleep. the driver should ensure - * the radio has been switched before return. - */ - void (*set_chan)(struct net_device *dev, u8 ch); - - /* indicate the driver that the link state is changed - * for example it may indicate the card is associated now. - * Driver might be interested in this to apply RX filter - * rules or simply light the LINK led - */ - void (*link_change)(struct net_device *dev); - - /* power save mode related */ - void (*sta_wake_up)(struct net_device *dev); - void (*enter_sleep_state)(struct net_device *dev, u64 time); - short (*ps_is_queue_empty)(struct net_device *dev); - int (*handle_beacon)(struct net_device *dev, - struct rtllib_beacon *beacon, - struct rtllib_network *network); - int (*handle_assoc_response)(struct net_device *dev, - 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 (*set_bw_mode_handler)(struct net_device *dev, - enum ht_channel_width bandwidth, - enum ht_extchnl_offset Offset); - bool (*get_nmode_support_by_sec_cfg)(struct net_device *dev); - void (*set_wireless_mode)(struct net_device *dev, u8 wireless_mode); - bool (*get_half_nmode_support_by_aps_handler)(struct net_device *dev); - u8 (*rtllib_ap_sec_type)(struct rtllib_device *ieee); - void (*init_gain_handler)(struct net_device *dev, u8 operation); - void (*scan_operation_backup_handler)(struct net_device *dev, - u8 operation); - void (*set_hw_reg_handler)(struct net_device *dev, u8 variable, u8 *val); - - void (*allow_all_dest_addr_handler)(struct net_device *dev, - bool allow_all_da, - bool write_into_reg); - - void (*rtllib_ips_leave_wq)(struct net_device *dev); - void (*rtllib_ips_leave)(struct net_device *dev); - void (*leisure_ps_leave)(struct net_device *dev); - - /* This must be the last item so that it points to the data - * allocated beyond this structure by alloc_rtllib - */ - u8 priv[]; -}; - -#define IEEE_MODE_MASK (WIRELESS_MODE_B | WIRELESS_MODE_G) - -/* Generate a 802.11 header */ - -/* Uses the channel change callback directly - * instead of [start/stop] scan callbacks - */ -#define IEEE_SOFTMAC_SCAN (1 << 2) - -/* Perform authentication and association handshake */ -#define IEEE_SOFTMAC_ASSOCIATE (1 << 3) - -/* Generate probe requests */ -#define IEEE_SOFTMAC_PROBERQ (1 << 4) - -/* Generate response to probe requests */ -#define IEEE_SOFTMAC_PROBERS (1 << 5) - -/* The ieee802.11 stack will manage the netif queue - * wake/stop for the driver, taking care of 802.11 - * fragmentation. See softmac.c for details. - */ -#define IEEE_SOFTMAC_TX_QUEUE (1 << 7) - -/* Uses only the softmac_data_hard_start_xmit - * even for TX management frames. - */ -#define IEEE_SOFTMAC_SINGLE_QUEUE (1 << 8) - -/* Generate beacons. The stack will enqueue beacons - * to the card - */ -#define IEEE_SOFTMAC_BEACONS (1 << 6) - -static inline void *rtllib_priv(struct net_device *dev) -{ - return ((struct rtllib_device *)netdev_priv(dev))->priv; -} - -static inline int rtllib_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - -static inline int rtllib_get_hdrlen(u16 fc) -{ - int hdrlen = RTLLIB_3ADDR_LEN; - - switch (WLAN_FC_GET_TYPE(fc)) { - case RTLLIB_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = RTLLIB_4ADDR_LEN; /* Addr4 */ - if (RTLLIB_QOS_HAS_SEQ(fc)) - hdrlen += 2; /* QOS ctrl*/ - break; - case RTLLIB_FTYPE_CTL: - switch (WLAN_FC_GET_STYPE(fc)) { - case IEEE80211_STYPE_CTS: - case IEEE80211_STYPE_ACK: - hdrlen = RTLLIB_1ADDR_LEN; - break; - default: - hdrlen = RTLLIB_2ADDR_LEN; - break; - } - break; - } - - return hdrlen; -} - -static inline int rtllib_is_ofdm_rate(u8 rate) -{ - switch (rate & ~RTLLIB_BASIC_RATE_MASK) { - case RTLLIB_OFDM_RATE_6MB: - case RTLLIB_OFDM_RATE_9MB: - case RTLLIB_OFDM_RATE_12MB: - case RTLLIB_OFDM_RATE_18MB: - case RTLLIB_OFDM_RATE_24MB: - case RTLLIB_OFDM_RATE_36MB: - case RTLLIB_OFDM_RATE_48MB: - case RTLLIB_OFDM_RATE_54MB: - return 1; - } - return 0; -} - -static inline int rtllib_is_cck_rate(u8 rate) -{ - switch (rate & ~RTLLIB_BASIC_RATE_MASK) { - case RTLLIB_CCK_RATE_1MB: - case RTLLIB_CCK_RATE_2MB: - case RTLLIB_CCK_RATE_5MB: - case RTLLIB_CCK_RATE_11MB: - return 1; - } - 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); - -netdev_tx_t rtllib_xmit(struct sk_buff *skb, struct net_device *dev); -void rtllib_txb_free(struct rtllib_txb *txb); - -/* rtllib_rx.c */ -int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats); -int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel); - -/* rtllib_wx.c */ -int rtllib_wx_get_scan(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -int rtllib_wx_set_encode(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -int rtllib_wx_get_encode(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -int rtllib_wx_set_auth(struct rtllib_device *ieee, - struct iw_request_info *info, - struct iw_param *data, char *extra); -int rtllib_wx_set_mlme(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len); - -/* rtllib_softmac.c */ -int rtllib_rx_frame_softmac(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats, u16 type, - u16 stype); -void rtllib_softmac_new_net(struct rtllib_device *ieee, - struct rtllib_network *net); - -void send_disassociation(struct rtllib_device *ieee, bool deauth, u16 rsn); -void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee); - -int rtllib_softmac_init(struct rtllib_device *ieee); -void rtllib_softmac_free(struct rtllib_device *ieee); -void rtllib_disassociate(struct rtllib_device *ieee); -void rtllib_stop_scan(struct rtllib_device *ieee); -bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan); -void rtllib_stop_scan_syncro(struct rtllib_device *ieee); -void rtllib_start_scan_syncro(struct rtllib_device *ieee); -void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr); -void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee); -void rtllib_start_protocol(struct rtllib_device *ieee); -void rtllib_stop_protocol(struct rtllib_device *ieee); - -void rtllib_enable_net_monitor_mode(struct net_device *dev, bool init_state); -void rtllib_disable_net_monitor_mode(struct net_device *dev, bool init_state); - -void rtllib_softmac_stop_protocol(struct rtllib_device *ieee); -void rtllib_softmac_start_protocol(struct rtllib_device *ieee); - -void rtllib_reset_queue(struct rtllib_device *ieee); -void rtllib_wake_all_queues(struct rtllib_device *ieee); -void rtllib_stop_all_queues(struct rtllib_device *ieee); - -void notify_wx_assoc_event(struct rtllib_device *ieee); -void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success); - -void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee); -u8 rtllib_ap_sec_type(struct rtllib_device *ieee); - -/* rtllib_softmac_wx.c */ - -int rtllib_wx_get_wap(struct rtllib_device *ieee, struct iw_request_info *info, - union iwreq_data *wrqu, char *ext); - -int rtllib_wx_set_wap(struct rtllib_device *ieee, struct iw_request_info *info, - union iwreq_data *awrq, char *extra); - -int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -int rtllib_wx_set_rate(struct rtllib_device *ieee, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -int rtllib_wx_get_rate(struct rtllib_device *ieee, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -int rtllib_wx_set_essid(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *extra); - -int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -int rtllib_wx_get_freq(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b); -void rtllib_wx_sync_scan_wq(void *data); - -int rtllib_wx_get_name(struct rtllib_device *ieee, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -int rtllib_wx_set_power(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -int rtllib_wx_get_power(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -int rtllib_wx_set_rts(struct rtllib_device *ieee, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -int rtllib_wx_get_rts(struct rtllib_device *ieee, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -#define MAX_RECEIVE_BUFFER_SIZE 9100 - -void ht_set_connect_bw_mode(struct rtllib_device *ieee, - enum ht_channel_width bandwidth, - enum ht_extchnl_offset Offset); -void ht_update_default_setting(struct rtllib_device *ieee); -void ht_construct_capability_element(struct rtllib_device *ieee, - u8 *pos_ht_cap, u8 *len, - u8 is_encrypt, bool assoc); -void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee, - u8 *posRT2RTAgg, u8 *len); -void ht_on_assoc_rsp(struct rtllib_device *ieee); -void ht_initialize_ht_info(struct rtllib_device *ieee); -void ht_initialize_bss_desc(struct bss_ht *bss_ht); -void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee, - struct rtllib_network *network); -void HT_update_self_and_peer_setting(struct rtllib_device *ieee, - struct rtllib_network *network); -u8 ht_get_highest_mcs_rate(struct rtllib_device *ieee, u8 *pMCSRateSet, - u8 *pMCSFilter); -extern u8 MCS_FILTER_ALL[]; -extern u16 MCS_DATA_RATE[2][2][77]; -u8 ht_c_check(struct rtllib_device *ieee, u8 *frame); -void ht_reset_iot_setting(struct rt_hi_throughput *ht_info); -bool is_ht_half_nmode_aps(struct rtllib_device *ieee); -u16 tx_count_to_data_rate(struct rtllib_device *ieee, u8 nDataRate); -int rtllib_rx_add_ba_req(struct rtllib_device *ieee, struct sk_buff *skb); -int rtllib_rx_add_ba_rsp(struct rtllib_device *ieee, struct sk_buff *skb); -int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb); -void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts, - u8 policy, u8 overwrite_pending); -void rtllib_ts_init_del_ba(struct rtllib_device *ieee, - struct ts_common_info *ts_common_info, - enum tr_select tx_rx_select); -void rtllib_ba_setup_timeout(struct timer_list *t); -void rtllib_tx_ba_inact_timeout(struct timer_list *t); -void rtllib_rx_ba_inact_timeout(struct timer_list *t); -void rtllib_reset_ba_entry(struct ba_record *ba); -bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS, u8 *addr, - u8 TID, enum tr_select tx_rx_select, bool add_new_ts); -void rtllib_ts_init(struct rtllib_device *ieee); -void rtllib_ts_start_add_ba_process(struct rtllib_device *ieee, - struct tx_ts_record *pTxTS); -void remove_peer_ts(struct rtllib_device *ieee, u8 *addr); -void remove_all_ts(struct rtllib_device *ieee); - -static inline const char *escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - - if (rtllib_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - snprintf(escaped, sizeof(escaped), "%*pE", essid_len, essid); - return escaped; -} - -/* fun with the built-in rtllib stack... */ -bool rtllib_mgnt_disconnect(struct rtllib_device *rtllib, u8 rsn); - -/* For the function is more related to hardware setting, it's better to use the - * ieee handler to refer to it. - */ -void rtllib_flush_rx_ts_pending_pkts(struct rtllib_device *ieee, - struct rx_ts_record *ts); -int rtllib_parse_info_param(struct rtllib_device *ieee, - struct rtllib_info_element *info_element, - u16 length, - struct rtllib_network *network, - struct rtllib_rx_stats *stats); - -void rtllib_indicate_packets(struct rtllib_device *ieee, - struct rtllib_rxb **prxb_indicate_array, u8 index); -#define RT_ASOC_RETRY_LIMIT 5 -u8 mgnt_query_tx_rate_exclude_cck_rates(struct rtllib_device *ieee); - -#endif /* RTLLIB_H */ diff --git a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c b/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c deleted file mode 100644 index 138733cb00e272..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_crypt_ccmp.c +++ /dev/null @@ -1,411 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Host AP crypt: host-based CCMP encryption implementation for Host AP driver - * - * Copyright (c) 2003-2004, Jouni Malinen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rtllib.h" - -#include -#include - -#include - -#define AES_BLOCK_LEN 16 -#define CCMP_HDR_LEN 8 -#define CCMP_MIC_LEN 8 -#define CCMP_TK_LEN 16 -#define CCMP_PN_LEN 6 - -struct rtllib_ccmp_data { - u8 key[CCMP_TK_LEN]; - int key_set; - - u8 tx_pn[CCMP_PN_LEN]; - u8 rx_pn[CCMP_PN_LEN]; - - u32 dot11rsna_stats_ccmp_format_errors; - u32 dot11rsna_stats_ccmp_replays; - u32 dot11rsna_stats_ccmp_decrypt_errors; - - int key_idx; - - struct crypto_aead *tfm; - - /* scratch buffers for virt_to_page() (crypto API) */ - u8 tx_aad[2 * AES_BLOCK_LEN]; - u8 rx_aad[2 * AES_BLOCK_LEN]; -}; - -static void *rtllib_ccmp_init(int key_idx) -{ - struct rtllib_ccmp_data *priv; - - priv = kzalloc(sizeof(*priv), GFP_ATOMIC); - if (!priv) - goto fail; - priv->key_idx = key_idx; - - priv->tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(priv->tfm)) { - pr_debug("Could not allocate crypto API aes\n"); - priv->tfm = NULL; - goto fail; - } - return priv; - -fail: - if (priv) { - if (priv->tfm) - crypto_free_aead(priv->tfm); - kfree(priv); - } - - return NULL; -} - -static void rtllib_ccmp_deinit(void *priv) -{ - struct rtllib_ccmp_data *_priv = priv; - - if (_priv && _priv->tfm) - crypto_free_aead(_priv->tfm); - kfree(priv); -} - -static int ccmp_init_iv_and_aad(struct ieee80211_hdr *hdr, - u8 *pn, u8 *iv, u8 *aad) -{ - u8 *pos, qc = 0; - size_t aad_len; - u16 fc; - int a4_included, qc_included; - - fc = le16_to_cpu(hdr->frame_control); - a4_included = ieee80211_has_a4(hdr->frame_control); - - qc_included = ((WLAN_FC_GET_TYPE(fc) == RTLLIB_FTYPE_DATA) && - (WLAN_FC_GET_STYPE(fc) & 0x80)); - aad_len = 22; - if (a4_included) - aad_len += 6; - if (qc_included) { - pos = (u8 *)&hdr->addr4; - if (a4_included) - pos += 6; - qc = *pos & 0x0f; - aad_len += 2; - } - /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC - * mode authentication are not allowed to collide, yet both are derived - * from the same vector. We only set L := 1 here to indicate that the - * data size can be represented in (L+1) bytes. The CCM layer will take - * care of storing the data length in the top (L+1) bytes and setting - * and clearing the other bits as is required to derive the two IVs. - */ - iv[0] = 0x1; - - /* Nonce: QC | A2 | PN */ - iv[1] = qc; - memcpy(iv + 2, hdr->addr2, ETH_ALEN); - memcpy(iv + 8, pn, CCMP_PN_LEN); - - /* AAD: - * FC with bits 4..6 and 11..13 masked to zero; 14 is always one - * A1 | A2 | A3 - * SC with bits 4..15 (seq#) masked to zero - * A4 (if present) - * QC (if present) - */ - pos = (u8 *)hdr; - aad[0] = pos[0] & 0x8f; - aad[1] = pos[1] & 0xc7; - memcpy(&aad[2], &hdr->addr1, ETH_ALEN); - memcpy(&aad[8], &hdr->addr2, ETH_ALEN); - memcpy(&aad[14], &hdr->addr3, ETH_ALEN); - pos = (u8 *)&hdr->seq_ctrl; - aad[20] = pos[0] & 0x0f; - aad[21] = 0; /* all bits masked */ - memset(aad + 22, 0, 8); - if (a4_included) - memcpy(aad + 22, hdr->addr4, ETH_ALEN); - if (qc_included) { - aad[a4_included ? 28 : 22] = qc; - /* rest of QC masked */ - } - - return aad_len; -} - -static int rtllib_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct rtllib_ccmp_data *key = priv; - int i; - u8 *pos; - struct ieee80211_hdr *hdr; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - if (skb_headroom(skb) < CCMP_HDR_LEN || - skb_tailroom(skb) < CCMP_MIC_LEN || - skb->len < hdr_len) - return -1; - - pos = skb_push(skb, CCMP_HDR_LEN); - memmove(pos, pos + CCMP_HDR_LEN, hdr_len); - pos += hdr_len; - - i = CCMP_PN_LEN - 1; - while (i >= 0) { - key->tx_pn[i]++; - if (key->tx_pn[i] != 0) - break; - i--; - } - - *pos++ = key->tx_pn[5]; - *pos++ = key->tx_pn[4]; - *pos++ = 0; - *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; - *pos++ = key->tx_pn[3]; - *pos++ = key->tx_pn[2]; - *pos++ = key->tx_pn[1]; - *pos++ = key->tx_pn[0]; - - hdr = (struct ieee80211_hdr *)skb->data; - if (!tcb_desc->hw_sec) { - struct aead_request *req; - struct scatterlist sg[2]; - u8 *aad = key->tx_aad; - u8 iv[AES_BLOCK_LEN]; - int aad_len, ret; - int data_len = skb->len - hdr_len - CCMP_HDR_LEN; - - req = aead_request_alloc(key->tfm, GFP_ATOMIC); - if (!req) - return -ENOMEM; - - aad_len = ccmp_init_iv_and_aad(hdr, key->tx_pn, iv, aad); - - skb_put(skb, CCMP_MIC_LEN); - sg_init_table(sg, 2); - sg_set_buf(&sg[0], aad, aad_len); - sg_set_buf(&sg[1], skb->data + hdr_len + CCMP_HDR_LEN, - data_len + CCMP_MIC_LEN); - - aead_request_set_callback(req, 0, NULL, NULL); - aead_request_set_ad(req, aad_len); - aead_request_set_crypt(req, sg, sg, data_len, iv); - - ret = crypto_aead_encrypt(req); - aead_request_free(req); - - return ret; - } - - return 0; -} - -static int rtllib_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct rtllib_ccmp_data *key = priv; - u8 keyidx, *pos; - struct ieee80211_hdr *hdr; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - u8 pn[6]; - - if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { - key->dot11rsna_stats_ccmp_format_errors++; - return -1; - } - - hdr = (struct ieee80211_hdr *)skb->data; - pos = skb->data + hdr_len; - keyidx = pos[3]; - if (!(keyidx & (1 << 5))) { - if (net_ratelimit()) { - pr_debug("CCMP: received packet without ExtIV flag from %pM\n", - hdr->addr2); - } - key->dot11rsna_stats_ccmp_format_errors++; - return -2; - } - keyidx >>= 6; - if (key->key_idx != keyidx) { - pr_debug("CCMP: RX tkey->key_idx=%d frame keyidx=%d priv=%p\n", - key->key_idx, keyidx, priv); - return -6; - } - if (!key->key_set) { - if (net_ratelimit()) { - pr_debug("CCMP: received packet from %pM with keyid=%d that does not have a configured key\n", - hdr->addr2, keyidx); - } - return -3; - } - - pn[0] = pos[7]; - pn[1] = pos[6]; - pn[2] = pos[5]; - pn[3] = pos[4]; - pn[4] = pos[1]; - pn[5] = pos[0]; - pos += 8; - if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { - key->dot11rsna_stats_ccmp_replays++; - return -4; - } - if (!tcb_desc->hw_sec) { - size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN; - struct aead_request *req; - struct scatterlist sg[2]; - u8 *aad = key->rx_aad; - u8 iv[AES_BLOCK_LEN]; - int aad_len, ret; - - req = aead_request_alloc(key->tfm, GFP_ATOMIC); - if (!req) - return -ENOMEM; - - aad_len = ccmp_init_iv_and_aad(hdr, pn, iv, aad); - - sg_init_table(sg, 2); - sg_set_buf(&sg[0], aad, aad_len); - sg_set_buf(&sg[1], pos, data_len); - - aead_request_set_callback(req, 0, NULL, NULL); - aead_request_set_ad(req, aad_len); - aead_request_set_crypt(req, sg, sg, data_len, iv); - - ret = crypto_aead_decrypt(req); - aead_request_free(req); - - if (ret) { - if (net_ratelimit()) { - pr_debug("CCMP: decrypt failed: STA= %pM\n", - hdr->addr2); - } - key->dot11rsna_stats_ccmp_decrypt_errors++; - return -5; - } - - memcpy(key->rx_pn, pn, CCMP_PN_LEN); - } - /* Remove hdr and MIC */ - memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); - skb_pull(skb, CCMP_HDR_LEN); - skb_trim(skb, skb->len - CCMP_MIC_LEN); - - return keyidx; -} - -static int rtllib_ccmp_set_key(void *key, int len, u8 *seq, void *priv) -{ - struct rtllib_ccmp_data *data = priv; - int keyidx; - struct crypto_aead *tfm = data->tfm; - - keyidx = data->key_idx; - memset(data, 0, sizeof(*data)); - data->key_idx = keyidx; - data->tfm = tfm; - if (len == CCMP_TK_LEN) { - memcpy(data->key, key, CCMP_TK_LEN); - data->key_set = 1; - if (seq) { - data->rx_pn[0] = seq[5]; - data->rx_pn[1] = seq[4]; - data->rx_pn[2] = seq[3]; - data->rx_pn[3] = seq[2]; - data->rx_pn[4] = seq[1]; - 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)) - return -1; - } else if (len == 0) { - data->key_set = 0; - } else { - return -1; - } - - return 0; -} - -static int rtllib_ccmp_get_key(void *key, int len, u8 *seq, void *priv) -{ - struct rtllib_ccmp_data *data = priv; - - if (len < CCMP_TK_LEN) - return -1; - - if (!data->key_set) - return 0; - memcpy(key, data->key, CCMP_TK_LEN); - - if (seq) { - seq[0] = data->tx_pn[5]; - seq[1] = data->tx_pn[4]; - seq[2] = data->tx_pn[3]; - seq[3] = data->tx_pn[2]; - seq[4] = data->tx_pn[1]; - seq[5] = data->tx_pn[0]; - } - - return CCMP_TK_LEN; -} - -static void rtllib_ccmp_print_stats(struct seq_file *m, void *priv) -{ - struct rtllib_ccmp_data *ccmp = priv; - - seq_printf(m, - "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->dot11rsna_stats_ccmp_format_errors, - ccmp->dot11rsna_stats_ccmp_replays, - ccmp->dot11rsna_stats_ccmp_decrypt_errors); -} - -static const struct lib80211_crypto_ops rtllib_crypt_ccmp = { - .name = "R-CCMP", - .init = rtllib_ccmp_init, - .deinit = rtllib_ccmp_deinit, - .encrypt_mpdu = rtllib_ccmp_encrypt, - .decrypt_mpdu = rtllib_ccmp_decrypt, - .encrypt_msdu = NULL, - .decrypt_msdu = NULL, - .set_key = rtllib_ccmp_set_key, - .get_key = rtllib_ccmp_get_key, - .print_stats = rtllib_ccmp_print_stats, - .extra_mpdu_prefix_len = CCMP_HDR_LEN, - .extra_mpdu_postfix_len = CCMP_MIC_LEN, - .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); -} - -module_init(rtllib_crypto_ccmp_init); -module_exit(rtllib_crypto_ccmp_exit); - -MODULE_DESCRIPTION("Support module for rtllib CCMP crypto"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c b/drivers/staging/rtl8192e/rtllib_crypt_tkip.c deleted file mode 100644 index e544379bfa91aa..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_crypt_tkip.c +++ /dev/null @@ -1,706 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Host AP crypt: host-based TKIP encryption implementation for Host AP driver - * - * Copyright (c) 2003-2004, Jouni Malinen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rtllib.h" - -struct rtllib_tkip_data { -#define TKIP_KEY_LEN 32 - u8 key[TKIP_KEY_LEN]; - int key_set; - - u32 tx_iv32; - u16 tx_iv16; - u16 tx_ttak[5]; - int tx_phase1_done; - - u32 rx_iv32; - u16 rx_iv16; - bool initialized; - u16 rx_ttak[5]; - int rx_phase1_done; - u32 rx_iv32_new; - u16 rx_iv16_new; - - u32 dot11RSNAStatsTKIPReplays; - u32 dot11RSNAStatsTKIPICVErrors; - u32 dot11RSNAStatsTKIPLocalMICFailures; - - int key_idx; - struct arc4_ctx rx_ctx_arc4; - struct arc4_ctx tx_ctx_arc4; - struct crypto_shash *rx_tfm_michael; - struct crypto_shash *tx_tfm_michael; - /* scratch buffers for virt_to_page() (crypto API) */ - u8 rx_hdr[16]; - u8 tx_hdr[16]; -}; - -static void *rtllib_tkip_init(int key_idx) -{ - struct rtllib_tkip_data *priv; - - if (fips_enabled) - return NULL; - - priv = kzalloc(sizeof(*priv), GFP_ATOMIC); - if (!priv) - goto fail; - priv->key_idx = key_idx; - - priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->tx_tfm_michael)) { - pr_debug("Could not allocate crypto API michael_mic\n"); - priv->tx_tfm_michael = NULL; - goto fail; - } - - priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->rx_tfm_michael)) { - pr_debug("Could not allocate crypto API michael_mic\n"); - priv->rx_tfm_michael = NULL; - goto fail; - } - return priv; - -fail: - if (priv) { - crypto_free_shash(priv->tx_tfm_michael); - crypto_free_shash(priv->rx_tfm_michael); - kfree(priv); - } - - return NULL; -} - -static void rtllib_tkip_deinit(void *priv) -{ - struct rtllib_tkip_data *_priv = priv; - - if (_priv) { - crypto_free_shash(_priv->tx_tfm_michael); - crypto_free_shash(_priv->rx_tfm_michael); - } - kfree_sensitive(priv); -} - -static inline u16 RotR1(u16 val) -{ - return (val >> 1) | (val << 15); -} - -static inline u8 Lo8(u16 val) -{ - return val & 0xff; -} - -static inline u8 Hi8(u16 val) -{ - return val >> 8; -} - -static inline u16 Lo16(u32 val) -{ - return val & 0xffff; -} - -static inline u16 Hi16(u32 val) -{ - return val >> 16; -} - -static inline u16 Mk16(u8 hi, u8 lo) -{ - return lo | (hi << 8); -} - -static inline u16 Mk16_le(u16 *v) -{ - return *v; -} - -static const u16 Sbox[256] = { - 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, - 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, - 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, - 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, - 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, - 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, - 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, - 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, - 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, - 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, - 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, - 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, - 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, - 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, - 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, - 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, - 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, - 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, - 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, - 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, - 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, - 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, - 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, - 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, - 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, - 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, - 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, - 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, - 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, - 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, - 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, - 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, -}; - -static inline u16 _S_(u16 v) -{ - u16 t = Sbox[Hi8(v)]; - return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); -} - -#define PHASE1_LOOP_COUNT 8 - -static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) -{ - int i, j; - - /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ - TTAK[0] = Lo16(IV32); - TTAK[1] = Hi16(IV32); - TTAK[2] = Mk16(TA[1], TA[0]); - TTAK[3] = Mk16(TA[3], TA[2]); - TTAK[4] = Mk16(TA[5], TA[4]); - - for (i = 0; i < PHASE1_LOOP_COUNT; i++) { - j = 2 * (i & 1); - TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); - TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); - TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); - TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); - TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; - } -} - -static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, - u16 IV16) -{ - /* Make temporary area overlap WEP seed so that the final copy can be - * avoided on little endian hosts. - */ - u16 *PPK = (u16 *)&WEPSeed[4]; - - /* Step 1 - make copy of TTAK and bring in TSC */ - PPK[0] = TTAK[0]; - PPK[1] = TTAK[1]; - PPK[2] = TTAK[2]; - PPK[3] = TTAK[3]; - PPK[4] = TTAK[4]; - PPK[5] = TTAK[4] + IV16; - - /* Step 2 - 96-bit bijective mixing using S-box */ - PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *)&TK[0])); - PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *)&TK[2])); - PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *)&TK[4])); - PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *)&TK[6])); - PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *)&TK[8])); - PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *)&TK[10])); - - PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *)&TK[12])); - PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *)&TK[14])); - PPK[2] += RotR1(PPK[1]); - PPK[3] += RotR1(PPK[2]); - PPK[4] += RotR1(PPK[3]); - PPK[5] += RotR1(PPK[4]); - - /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value - * WEPSeed[0..2] is transmitted as WEP IV - */ - WEPSeed[0] = Hi8(IV16); - WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; - WEPSeed[2] = Lo8(IV16); - WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *)&TK[0])) >> 1); - -#ifdef __BIG_ENDIAN - { - int i; - - for (i = 0; i < 6; i++) - PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); - } -#endif -} - -static int rtllib_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct rtllib_tkip_data *tkey = priv; - int len; - u8 *pos; - struct ieee80211_hdr *hdr; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - int ret = 0; - u8 rc4key[16], *icv; - u32 crc; - - if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || - skb->len < hdr_len) - return -1; - - hdr = (struct ieee80211_hdr *)skb->data; - - if (!tcb_desc->hw_sec) { - if (!tkey->tx_phase1_done) { - tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, - tkey->tx_iv32); - tkey->tx_phase1_done = 1; - } - tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, - tkey->tx_iv16); - } else { - tkey->tx_phase1_done = 1; - } - - len = skb->len - hdr_len; - pos = skb_push(skb, 8); - memmove(pos, pos + 8, hdr_len); - pos += hdr_len; - - if (tcb_desc->hw_sec) { - *pos++ = Hi8(tkey->tx_iv16); - *pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F; - *pos++ = Lo8(tkey->tx_iv16); - } else { - *pos++ = rc4key[0]; - *pos++ = rc4key[1]; - *pos++ = rc4key[2]; - } - - *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; - *pos++ = tkey->tx_iv32 & 0xff; - *pos++ = (tkey->tx_iv32 >> 8) & 0xff; - *pos++ = (tkey->tx_iv32 >> 16) & 0xff; - *pos++ = (tkey->tx_iv32 >> 24) & 0xff; - - if (!tcb_desc->hw_sec) { - icv = skb_put(skb, 4); - crc = ~crc32_le(~0, pos, len); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - - arc4_setkey(&tkey->tx_ctx_arc4, rc4key, 16); - arc4_crypt(&tkey->tx_ctx_arc4, pos, pos, len + 4); - } - - tkey->tx_iv16++; - if (tkey->tx_iv16 == 0) { - tkey->tx_phase1_done = 0; - tkey->tx_iv32++; - } - - if (!tcb_desc->hw_sec) - return ret; - return 0; -} - -static int rtllib_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct rtllib_tkip_data *tkey = priv; - u8 keyidx, *pos; - u32 iv32; - u16 iv16; - struct ieee80211_hdr *hdr; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - u8 rc4key[16]; - u8 icv[4]; - u32 crc; - int plen; - - if (skb->len < hdr_len + 8 + 4) - return -1; - - hdr = (struct ieee80211_hdr *)skb->data; - pos = skb->data + hdr_len; - keyidx = pos[3]; - if (!(keyidx & (1 << 5))) { - if (net_ratelimit()) { - netdev_dbg(skb->dev, - "Received packet without ExtIV flag from %pM\n", - hdr->addr2); - } - return -2; - } - keyidx >>= 6; - if (tkey->key_idx != keyidx) { - netdev_dbg(skb->dev, - "RX tkey->key_idx=%d frame keyidx=%d priv=%p\n", - tkey->key_idx, keyidx, priv); - return -6; - } - if (!tkey->key_set) { - if (net_ratelimit()) { - netdev_dbg(skb->dev, - "Received packet from %pM with keyid=%d that does not have a configured key\n", - hdr->addr2, keyidx); - } - return -3; - } - iv16 = (pos[0] << 8) | pos[2]; - iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); - pos += 8; - - if (!tcb_desc->hw_sec || (skb->cb[0] == 1)) { - if ((iv32 < tkey->rx_iv32 || - (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) && - tkey->initialized) { - if (net_ratelimit()) { - netdev_dbg(skb->dev, - "Replay detected: STA= %pM previous TSC %08x%04x received TSC %08x%04x\n", - hdr->addr2, tkey->rx_iv32, - tkey->rx_iv16, iv32, iv16); - } - tkey->dot11RSNAStatsTKIPReplays++; - return -4; - } - tkey->initialized = true; - - if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { - tkip_mixing_phase1(tkey->rx_ttak, tkey->key, - hdr->addr2, iv32); - tkey->rx_phase1_done = 1; - } - tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); - - plen = skb->len - hdr_len - 12; - - arc4_setkey(&tkey->rx_ctx_arc4, rc4key, 16); - arc4_crypt(&tkey->rx_ctx_arc4, pos, pos, plen + 4); - - crc = ~crc32_le(~0, pos, plen); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - - if (memcmp(icv, pos + plen, 4) != 0) { - if (iv32 != tkey->rx_iv32) { - /* Previously cached Phase1 result was already - * lost, so it needs to be recalculated for the - * next packet. - */ - tkey->rx_phase1_done = 0; - } - if (net_ratelimit()) { - netdev_dbg(skb->dev, - "ICV error detected: STA= %pM\n", - hdr->addr2); - } - tkey->dot11RSNAStatsTKIPICVErrors++; - return -5; - } - } - - /* Update real counters only after Michael MIC verification has - * completed - */ - tkey->rx_iv32_new = iv32; - tkey->rx_iv16_new = iv16; - - /* Remove IV and ICV */ - memmove(skb->data + 8, skb->data, hdr_len); - skb_pull(skb, 8); - skb_trim(skb, skb->len - 4); - - return keyidx; -} - -static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr, - u8 *data, size_t data_len, u8 *mic) -{ - SHASH_DESC_ON_STACK(desc, tfm_michael); - int err; - - desc->tfm = tfm_michael; - - if (crypto_shash_setkey(tfm_michael, key, 8)) - return -1; - - err = crypto_shash_init(desc); - if (err) - goto out; - err = crypto_shash_update(desc, hdr, 16); - if (err) - goto out; - err = crypto_shash_update(desc, data, data_len); - if (err) - goto out; - err = crypto_shash_final(desc, mic); - -out: - shash_desc_zero(desc); - return err; -} - -static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) -{ - struct ieee80211_hdr *hdr11; - - hdr11 = (struct ieee80211_hdr *)skb->data; - switch (le16_to_cpu(hdr11->frame_control) & - (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - case IEEE80211_FCTL_TODS: - ether_addr_copy(hdr, hdr11->addr3); /* DA */ - ether_addr_copy(hdr + ETH_ALEN, hdr11->addr2); /* SA */ - break; - case IEEE80211_FCTL_FROMDS: - ether_addr_copy(hdr, hdr11->addr1); /* DA */ - ether_addr_copy(hdr + ETH_ALEN, hdr11->addr3); /* SA */ - break; - case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - ether_addr_copy(hdr, hdr11->addr3); /* DA */ - ether_addr_copy(hdr + ETH_ALEN, hdr11->addr4); /* SA */ - break; - case 0: - ether_addr_copy(hdr, hdr11->addr1); /* DA */ - ether_addr_copy(hdr + ETH_ALEN, hdr11->addr2); /* SA */ - break; - } - - /* priority */ - hdr[12] = 0; - - /* reserved */ - hdr[13] = 0; - hdr[14] = 0; - hdr[15] = 0; -} - -static int rtllib_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct rtllib_tkip_data *tkey = priv; - u8 *pos; - struct ieee80211_hdr *hdr; - - hdr = (struct ieee80211_hdr *)skb->data; - - if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { - netdev_dbg(skb->dev, - "Invalid packet for Michael MIC add (tailroom=%d hdr_len=%d skb->len=%d)\n", - skb_tailroom(skb), hdr_len, skb->len); - return -1; - } - - michael_mic_hdr(skb, tkey->tx_hdr); - - if (RTLLIB_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_control))) - tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; - pos = skb_put(skb, 8); - if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, - skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) - return -1; - - return 0; -} - -static void rtllib_michael_mic_failure(struct net_device *dev, - struct ieee80211_hdr *hdr, - int keyidx) -{ - union iwreq_data wrqu; - struct iw_michaelmicfailure ev; - - /* TODO: needed parameters: count, keyid, key type, TSC */ - memset(&ev, 0, sizeof(ev)); - ev.flags = keyidx & IW_MICFAILURE_KEY_ID; - if (hdr->addr1[0] & 0x01) - ev.flags |= IW_MICFAILURE_GROUP; - else - ev.flags |= IW_MICFAILURE_PAIRWISE; - ev.src_addr.sa_family = ARPHRD_ETHER; - ether_addr_copy(ev.src_addr.sa_data, hdr->addr2); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(ev); - wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); -} - -static int rtllib_michael_mic_verify(struct sk_buff *skb, int keyidx, - int hdr_len, void *priv) -{ - struct rtllib_tkip_data *tkey = priv; - u8 mic[8]; - struct ieee80211_hdr *hdr; - - hdr = (struct ieee80211_hdr *)skb->data; - - if (!tkey->key_set) - return -1; - - michael_mic_hdr(skb, tkey->rx_hdr); - if (RTLLIB_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_control))) - tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; - - if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, - skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) - return -1; - - if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { - struct ieee80211_hdr *hdr; - - hdr = (struct ieee80211_hdr *)skb->data; - netdev_dbg(skb->dev, - "Michael MIC verification failed for MSDU from %pM keyidx=%d\n", - hdr->addr2, keyidx); - netdev_dbg(skb->dev, "%d\n", - memcmp(mic, skb->data + skb->len - 8, 8) != 0); - if (skb->dev) { - pr_info("skb->dev != NULL\n"); - rtllib_michael_mic_failure(skb->dev, hdr, keyidx); - } - tkey->dot11RSNAStatsTKIPLocalMICFailures++; - return -1; - } - - /* Update TSC counters for RX now that the packet verification has - * completed. - */ - tkey->rx_iv32 = tkey->rx_iv32_new; - tkey->rx_iv16 = tkey->rx_iv16_new; - - skb_trim(skb, skb->len - 8); - - return 0; -} - -static int rtllib_tkip_set_key(void *key, int len, u8 *seq, void *priv) -{ - struct rtllib_tkip_data *tkey = priv; - int keyidx; - struct crypto_shash *tfm = tkey->tx_tfm_michael; - struct crypto_shash *tfm3 = tkey->rx_tfm_michael; - - keyidx = tkey->key_idx; - memset(tkey, 0, sizeof(*tkey)); - tkey->key_idx = keyidx; - tkey->tx_tfm_michael = tfm; - tkey->rx_tfm_michael = tfm3; - - if (len == TKIP_KEY_LEN) { - memcpy(tkey->key, key, TKIP_KEY_LEN); - tkey->key_set = 1; - tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ - if (seq) { - tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | - (seq[3] << 8) | seq[2]; - tkey->rx_iv16 = (seq[1] << 8) | seq[0]; - } - } else if (len == 0) { - tkey->key_set = 0; - } else { - return -1; - } - - return 0; -} - -static int rtllib_tkip_get_key(void *key, int len, u8 *seq, void *priv) -{ - struct rtllib_tkip_data *tkey = priv; - - if (len < TKIP_KEY_LEN) - return -1; - - if (!tkey->key_set) - return 0; - memcpy(key, tkey->key, TKIP_KEY_LEN); - - if (seq) { - /* Return the sequence number of the last transmitted frame. */ - seq[0] = tkey->tx_iv16; - seq[1] = tkey->tx_iv16 >> 8; - seq[2] = tkey->tx_iv32; - seq[3] = tkey->tx_iv32 >> 8; - seq[4] = tkey->tx_iv32 >> 16; - seq[5] = tkey->tx_iv32 >> 24; - } - - return TKIP_KEY_LEN; -} - -static void rtllib_tkip_print_stats(struct seq_file *m, void *priv) -{ - struct rtllib_tkip_data *tkip = priv; - - seq_printf(m, - "key[%d] alg=TKIP key_set=%d tx_pn=%02x%02x%02x%02x%02x%02x rx_pn=%02x%02x%02x%02x%02x%02x replays=%d icv_errors=%d local_mic_failures=%d\n", - tkip->key_idx, tkip->key_set, - (tkip->tx_iv32 >> 24) & 0xff, - (tkip->tx_iv32 >> 16) & 0xff, - (tkip->tx_iv32 >> 8) & 0xff, - tkip->tx_iv32 & 0xff, - (tkip->tx_iv16 >> 8) & 0xff, - tkip->tx_iv16 & 0xff, - (tkip->rx_iv32 >> 24) & 0xff, - (tkip->rx_iv32 >> 16) & 0xff, - (tkip->rx_iv32 >> 8) & 0xff, - tkip->rx_iv32 & 0xff, - (tkip->rx_iv16 >> 8) & 0xff, - tkip->rx_iv16 & 0xff, - tkip->dot11RSNAStatsTKIPReplays, - tkip->dot11RSNAStatsTKIPICVErrors, - tkip->dot11RSNAStatsTKIPLocalMICFailures); -} - -static const struct lib80211_crypto_ops rtllib_crypt_tkip = { - .name = "R-TKIP", - .init = rtllib_tkip_init, - .deinit = rtllib_tkip_deinit, - .encrypt_mpdu = rtllib_tkip_encrypt, - .decrypt_mpdu = rtllib_tkip_decrypt, - .encrypt_msdu = rtllib_michael_mic_add, - .decrypt_msdu = rtllib_michael_mic_verify, - .set_key = rtllib_tkip_set_key, - .get_key = rtllib_tkip_get_key, - .print_stats = rtllib_tkip_print_stats, - .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ - .extra_mpdu_postfix_len = 4, /* ICV */ - .extra_msdu_postfix_len = 8, /* MIC */ - .owner = THIS_MODULE, -}; - -static int __init rtllib_crypto_tkip_init(void) -{ - return lib80211_register_crypto_ops(&rtllib_crypt_tkip); -} - -static void __exit rtllib_crypto_tkip_exit(void) -{ - lib80211_unregister_crypto_ops(&rtllib_crypt_tkip); -} - -module_init(rtllib_crypto_tkip_init); -module_exit(rtllib_crypto_tkip_exit); - -MODULE_DESCRIPTION("Support module for rtllib TKIP crypto"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_crypt_wep.c b/drivers/staging/rtl8192e/rtllib_crypt_wep.c deleted file mode 100644 index aa18c060d72706..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_crypt_wep.c +++ /dev/null @@ -1,242 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Host AP crypt: host-based WEP encryption implementation for Host AP driver - * - * Copyright (c) 2002-2004, Jouni Malinen - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "rtllib.h" - -#include - -struct prism2_wep_data { - u32 iv; -#define WEP_KEY_LEN 13 - u8 key[WEP_KEY_LEN + 1]; - u8 key_len; - u8 key_idx; - struct arc4_ctx rx_ctx_arc4; - struct arc4_ctx tx_ctx_arc4; -}; - -static void *prism2_wep_init(int keyidx) -{ - struct prism2_wep_data *priv; - - if (fips_enabled) - return NULL; - - priv = kzalloc(sizeof(*priv), GFP_ATOMIC); - if (!priv) - return NULL; - priv->key_idx = keyidx; - - /* start WEP IV from a random value */ - get_random_bytes(&priv->iv, 4); - - return priv; -} - -static void prism2_wep_deinit(void *priv) -{ - kfree_sensitive(priv); -} - -/* Perform WEP encryption on given skb that has at least 4 bytes of headroom - * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, - * so the payload length increases with 8 bytes. - * - * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) - */ -static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct prism2_wep_data *wep = priv; - u32 klen, len; - u8 key[WEP_KEY_LEN + 3]; - u8 *pos; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - u32 crc; - u8 *icv; - - if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || - skb->len < hdr_len){ - pr_err("Error!!! headroom=%d tailroom=%d skblen=%d hdr_len=%d\n", - skb_headroom(skb), skb_tailroom(skb), skb->len, hdr_len); - return -1; - } - len = skb->len - hdr_len; - pos = skb_push(skb, 4); - memmove(pos, pos + 4, hdr_len); - pos += hdr_len; - - klen = 3 + wep->key_len; - - wep->iv++; - - /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key - * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) - * can be used to speedup attacks, so avoid using them. - */ - if ((wep->iv & 0xff00) == 0xff00) { - u8 B = (wep->iv >> 16) & 0xff; - - if (B >= 3 && B < klen) - wep->iv += 0x0100; - } - - /* Prepend 24-bit IV to RC4 key and TX frame */ - *pos++ = key[0] = (wep->iv >> 16) & 0xff; - *pos++ = key[1] = (wep->iv >> 8) & 0xff; - *pos++ = key[2] = wep->iv & 0xff; - *pos++ = wep->key_idx << 6; - - /* Copy rest of the WEP key (the secret part) */ - memcpy(key + 3, wep->key, wep->key_len); - - if (!tcb_desc->hw_sec) { - /* Append little-endian CRC32 and encrypt it to produce ICV */ - crc = ~crc32_le(~0, pos, len); - icv = skb_put(skb, 4); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - - arc4_setkey(&wep->tx_ctx_arc4, key, klen); - arc4_crypt(&wep->tx_ctx_arc4, pos, pos, len + 4); - } - - return 0; -} - -/* Perform WEP decryption on given struct buffer. Buffer includes whole WEP - * part of the frame: IV (4 bytes), encrypted payload (including SNAP header), - * ICV (4 bytes). len includes both IV and ICV. - * - * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on - * failure. If frame is OK, IV and ICV will be removed. - */ -static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct prism2_wep_data *wep = priv; - u32 klen, plen; - u8 key[WEP_KEY_LEN + 3]; - u8 keyidx, *pos; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + - MAX_DEV_ADDR_SIZE); - u32 crc; - u8 icv[4]; - - if (skb->len < hdr_len + 8) - return -1; - - pos = skb->data + hdr_len; - key[0] = *pos++; - key[1] = *pos++; - key[2] = *pos++; - keyidx = *pos++ >> 6; - if (keyidx != wep->key_idx) - return -1; - - klen = 3 + wep->key_len; - - /* Copy rest of the WEP key (the secret part) */ - memcpy(key + 3, wep->key, wep->key_len); - - /* Apply RC4 to data and compute CRC32 over decrypted data */ - plen = skb->len - hdr_len - 8; - - if (!tcb_desc->hw_sec) { - arc4_setkey(&wep->rx_ctx_arc4, key, klen); - arc4_crypt(&wep->rx_ctx_arc4, pos, pos, plen + 4); - - crc = ~crc32_le(~0, pos, plen); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - if (memcmp(icv, pos + plen, 4) != 0) { - /* ICV mismatch - drop frame */ - return -2; - } - } - /* Remove IV and ICV */ - memmove(skb->data + 4, skb->data, hdr_len); - skb_pull(skb, 4); - skb_trim(skb, skb->len - 4); - - return 0; -} - -static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) -{ - struct prism2_wep_data *wep = priv; - - if (len < 0 || len > WEP_KEY_LEN) - return -1; - - memcpy(wep->key, key, len); - wep->key_len = len; - - return 0; -} - -static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) -{ - struct prism2_wep_data *wep = priv; - - if (len < wep->key_len) - return -1; - - memcpy(key, wep->key, wep->key_len); - - return wep->key_len; -} - -static void prism2_wep_print_stats(struct seq_file *m, void *priv) -{ - struct prism2_wep_data *wep = priv; - - seq_printf(m, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); -} - -static const struct lib80211_crypto_ops rtllib_crypt_wep = { - .name = "R-WEP", - .init = prism2_wep_init, - .deinit = prism2_wep_deinit, - .encrypt_mpdu = prism2_wep_encrypt, - .decrypt_mpdu = prism2_wep_decrypt, - .encrypt_msdu = NULL, - .decrypt_msdu = NULL, - .set_key = prism2_wep_set_key, - .get_key = prism2_wep_get_key, - .print_stats = prism2_wep_print_stats, - .extra_mpdu_prefix_len = 4, /* IV */ - .extra_mpdu_postfix_len = 4, /* ICV */ - .owner = THIS_MODULE, -}; - -static int __init rtllib_crypto_wep_init(void) -{ - return lib80211_register_crypto_ops(&rtllib_crypt_wep); -} - -static void __exit rtllib_crypto_wep_exit(void) -{ - lib80211_unregister_crypto_ops(&rtllib_crypt_wep); -} - -module_init(rtllib_crypto_wep_init); -module_exit(rtllib_crypto_wep_exit); - -MODULE_DESCRIPTION("Support module for rtllib WEP crypto"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c deleted file mode 100644 index 469a69726c16cf..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_module.c +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2004 Intel Corporation. All rights reserved. - * - * Portions of this file are based on the WEP enablement code provided by the - * Host AP project hostap-drivers v0.1.3 - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rtllib.h" - -static inline int rtllib_networks_allocate(struct rtllib_device *ieee) -{ - if (ieee->networks) - return 0; - - ieee->networks = kcalloc(MAX_NETWORK_COUNT, - sizeof(struct rtllib_network), GFP_KERNEL); - if (!ieee->networks) - return -ENOMEM; - - return 0; -} - -static inline void rtllib_networks_free(struct rtllib_device *ieee) -{ - if (!ieee->networks) - return; - kfree(ieee->networks); - ieee->networks = NULL; -} - -static inline void rtllib_networks_initialize(struct rtllib_device *ieee) -{ - int i; - - INIT_LIST_HEAD(&ieee->network_free_list); - INIT_LIST_HEAD(&ieee->network_list); - for (i = 0; i < MAX_NETWORK_COUNT; i++) - list_add_tail(&ieee->networks[i].list, - &ieee->network_free_list); -} - -struct net_device *alloc_rtllib(int sizeof_priv) -{ - struct rtllib_device *ieee = NULL; - struct net_device *dev; - int i, err; - - pr_debug("rtllib: Initializing...\n"); - - dev = alloc_etherdev(sizeof(struct rtllib_device) + sizeof_priv); - if (!dev) { - pr_err("Unable to allocate net_device.\n"); - return NULL; - } - ieee = (struct rtllib_device *)netdev_priv_rsl(dev); - ieee->dev = dev; - - err = rtllib_networks_allocate(ieee); - if (err) { - pr_err("Unable to allocate beacon storage: %d\n", err); - goto free_netdev; - } - rtllib_networks_initialize(ieee); - - /* Default fragmentation threshold is maximum payload size */ - ieee->fts = DEFAULT_FTS; - ieee->scan_age = DEFAULT_MAX_SCAN_AGE; - ieee->open_wep = 1; - - ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ - - ieee->rtllib_ap_sec_type = rtllib_ap_sec_type; - - spin_lock_init(&ieee->lock); - spin_lock_init(&ieee->wpax_suitlist_lock); - spin_lock_init(&ieee->reorder_spinlock); - atomic_set(&ieee->atm_swbw, 0); - - /* SAM FIXME */ - lib80211_crypt_info_init(&ieee->crypt_info, "RTLLIB", &ieee->lock); - - ieee->wpa_enabled = 0; - ieee->tkip_countermeasures = 0; - ieee->drop_unencrypted = 0; - ieee->privacy_invoked = 0; - ieee->ieee802_1x = 1; - ieee->hwsec_active = 0; - - memset(ieee->swcamtable, 0, sizeof(struct sw_cam_table) * 32); - err = rtllib_softmac_init(ieee); - if (err) - goto free_crypt_info; - - ieee->ht_info = kzalloc(sizeof(struct rt_hi_throughput), GFP_KERNEL); - if (!ieee->ht_info) - goto free_softmac; - - ht_update_default_setting(ieee); - ht_initialize_ht_info(ieee); - rtllib_ts_init(ieee); - for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) - INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]); - - for (i = 0; i < 17; i++) { - ieee->last_rxseq_num[i] = -1; - ieee->last_rxfrag_num[i] = -1; - ieee->last_packet_time[i] = 0; - } - - return dev; - -free_softmac: - rtllib_softmac_free(ieee); -free_crypt_info: - lib80211_crypt_info_free(&ieee->crypt_info); - rtllib_networks_free(ieee); -free_netdev: - free_netdev(dev); - - return NULL; -} -EXPORT_SYMBOL(alloc_rtllib); - -void free_rtllib(struct net_device *dev) -{ - struct rtllib_device *ieee = (struct rtllib_device *) - netdev_priv_rsl(dev); - - kfree(ieee->ht_info); - rtllib_softmac_free(ieee); - - lib80211_crypt_info_free(&ieee->crypt_info); - - rtllib_networks_free(ieee); - free_netdev(dev); -} -EXPORT_SYMBOL(free_rtllib); - -static int __init rtllib_init(void) -{ - return 0; -} - -static void __exit rtllib_exit(void) -{ -} - -module_init(rtllib_init); -module_exit(rtllib_exit); - -MODULE_DESCRIPTION("Support module for rtllib wireless devices"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c deleted file mode 100644 index 8fe224a83dd691..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ /dev/null @@ -1,2564 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Original code based Host AP (software wireless LAN access point) driver - * for Intersil Prism2/2.5/3 - hostap.o module, common routines - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * Copyright (c) 2004, Intel Corporation - * - * Few modifications for Realtek's Wi-Fi drivers by - * Andrea Merello - * - * A special thanks goes to Realtek for their support ! - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rtllib.h" - -static void rtllib_rx_mgt(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *stats); - -static inline void rtllib_monitor_rx(struct rtllib_device *ieee, - struct sk_buff *skb, - struct rtllib_rx_stats *rx_status, - size_t hdr_length) -{ - skb->dev = ieee->dev; - skb_reset_mac_header(skb); - skb_pull(skb, hdr_length); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_80211_RAW); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - -/* Called only as a tasklet (software IRQ) */ -static struct rtllib_frag_entry * -rtllib_frag_cache_find(struct rtllib_device *ieee, unsigned int seq, - unsigned int frag, u8 tid, u8 *src, u8 *dst) -{ - struct rtllib_frag_entry *entry; - int i; - - for (i = 0; i < RTLLIB_FRAG_CACHE_LEN; i++) { - entry = &ieee->frag_cache[tid][i]; - if (entry->skb && - time_after(jiffies, entry->first_frag_time + 2 * HZ)) { - netdev_dbg(ieee->dev, - "expiring fragment cache entry seq=%u last_frag=%u\n", - entry->seq, entry->last_frag); - dev_kfree_skb_any(entry->skb); - entry->skb = NULL; - } - - if (entry->skb && entry->seq == seq && - (entry->last_frag + 1 == frag || frag == -1) && - memcmp(entry->src_addr, src, ETH_ALEN) == 0 && - memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) - return entry; - } - - return NULL; -} - -/* Called only as a tasklet (software IRQ) */ -static struct sk_buff * -rtllib_frag_cache_get(struct rtllib_device *ieee, - struct ieee80211_hdr *hdr) -{ - struct sk_buff *skb = NULL; - u16 fc = le16_to_cpu(hdr->frame_control); - u16 sc = le16_to_cpu(hdr->seq_ctrl); - unsigned int frag = WLAN_GET_SEQ_FRAG(sc); - unsigned int seq = WLAN_GET_SEQ_SEQ(sc); - struct rtllib_frag_entry *entry; - struct ieee80211_qos_hdr *hdr_3addrqos; - struct ieee80211_qos_hdr_4addr *hdr_4addrqos; - u8 tid; - - if (ieee80211_has_a4(hdr->frame_control) && - RTLLIB_QOS_HAS_SEQ(fc)) { - hdr_4addrqos = (struct ieee80211_qos_hdr_4addr *)hdr; - tid = le16_to_cpu(hdr_4addrqos->qos_ctrl) & RTLLIB_QCTL_TID; - tid = UP2AC(tid); - tid++; - } else if (RTLLIB_QOS_HAS_SEQ(fc)) { - hdr_3addrqos = (struct ieee80211_qos_hdr *)hdr; - tid = le16_to_cpu(hdr_3addrqos->qos_ctrl) & RTLLIB_QCTL_TID; - tid = UP2AC(tid); - tid++; - } else { - tid = 0; - } - - if (frag == 0) { - /* Reserve enough space to fit maximum frame length */ - skb = dev_alloc_skb(ieee->dev->mtu + - sizeof(struct ieee80211_hdr) + - 8 /* LLC */ + - 2 /* alignment */ + - 8 /* WEP */ + - ETH_ALEN /* WDS */ + - /* QOS Control */ - (RTLLIB_QOS_HAS_SEQ(fc) ? 2 : 0)); - if (!skb) - return NULL; - - entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]]; - ieee->frag_next_idx[tid]++; - if (ieee->frag_next_idx[tid] >= RTLLIB_FRAG_CACHE_LEN) - ieee->frag_next_idx[tid] = 0; - - if (entry->skb) - dev_kfree_skb_any(entry->skb); - - entry->first_frag_time = jiffies; - entry->seq = seq; - entry->last_frag = frag; - entry->skb = skb; - ether_addr_copy(entry->src_addr, hdr->addr2); - ether_addr_copy(entry->dst_addr, hdr->addr1); - } else { - /* received a fragment of a frame for which the head fragment - * should have already been received - */ - entry = rtllib_frag_cache_find(ieee, seq, frag, tid, hdr->addr2, - hdr->addr1); - if (entry) { - entry->last_frag = frag; - skb = entry->skb; - } - } - - return skb; -} - -/* Called only as a tasklet (software IRQ) */ -static int rtllib_frag_cache_invalidate(struct rtllib_device *ieee, - struct ieee80211_hdr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - u16 sc = le16_to_cpu(hdr->seq_ctrl); - unsigned int seq = WLAN_GET_SEQ_SEQ(sc); - struct rtllib_frag_entry *entry; - struct ieee80211_qos_hdr *hdr_3addrqos; - struct ieee80211_qos_hdr_4addr *hdr_4addrqos; - u8 tid; - - if (ieee80211_has_a4(hdr->frame_control) && - RTLLIB_QOS_HAS_SEQ(fc)) { - hdr_4addrqos = (struct ieee80211_qos_hdr_4addr *)hdr; - tid = le16_to_cpu(hdr_4addrqos->qos_ctrl) & RTLLIB_QCTL_TID; - tid = UP2AC(tid); - tid++; - } else if (RTLLIB_QOS_HAS_SEQ(fc)) { - hdr_3addrqos = (struct ieee80211_qos_hdr *)hdr; - tid = le16_to_cpu(hdr_3addrqos->qos_ctrl) & RTLLIB_QCTL_TID; - tid = UP2AC(tid); - tid++; - } else { - tid = 0; - } - - entry = rtllib_frag_cache_find(ieee, seq, -1, tid, hdr->addr2, - hdr->addr1); - - if (!entry) { - netdev_dbg(ieee->dev, - "Couldn't invalidate fragment cache entry (seq=%u)\n", - seq); - return -1; - } - - entry->skb = NULL; - return 0; -} - -/* rtllib_rx_frame_mgtmt - * - * Responsible for handling management control frames - * - * Called by rtllib_rx - */ -static inline int -rtllib_rx_frame_mgmt(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats, u16 type, u16 stype) -{ - /* On the struct stats definition there is written that - * this is not mandatory.... but seems that the probe - * response parser uses it - */ - struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)skb->data; - - rx_stats->len = skb->len; - rtllib_rx_mgt(ieee, skb, rx_stats); - if ((memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN))) { - dev_kfree_skb_any(skb); - return 0; - } - rtllib_rx_frame_softmac(ieee, skb, rx_stats, type, stype); - - dev_kfree_skb_any(skb); - - return 0; -} - -/* No encapsulation header if EtherType < 0x600 (=length) */ - -/* Called by rtllib_rx_frame_decrypt */ -static int rtllib_is_eapol_frame(struct rtllib_device *ieee, - struct sk_buff *skb, size_t hdrlen) -{ - struct net_device *dev = ieee->dev; - u16 fc, ethertype; - struct ieee80211_hdr *hdr; - u8 *pos; - - if (skb->len < 24) - return 0; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = le16_to_cpu(hdr->frame_control); - - /* check that the frame is unicast frame to us */ - if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS && - memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && - memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { - /* ToDS frame with own addr BSSID and DA */ - } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && - memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { - /* FromDS frame with own addr as DA */ - } else { - return 0; - } - - if (skb->len < 24 + 8) - return 0; - - /* check for port access entity Ethernet type */ - pos = skb->data + hdrlen; - ethertype = (pos[6] << 8) | pos[7]; - if (ethertype == ETH_P_PAE) - return 1; - - return 0; -} - -/* Called only as a tasklet (software IRQ), by rtllib_rx */ -static inline int -rtllib_rx_frame_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, - struct lib80211_crypt_data *crypt) -{ - struct ieee80211_hdr *hdr; - int res, hdrlen; - - if (!crypt || !crypt->ops->decrypt_mpdu) - return 0; - - if (ieee->hwsec_active) { - struct cb_desc *tcb_desc = (struct cb_desc *) - (skb->cb + MAX_DEV_ADDR_SIZE); - - tcb_desc->hw_sec = 1; - - if (ieee->need_sw_enc) - tcb_desc->hw_sec = 0; - } - - hdr = (struct ieee80211_hdr *)skb->data; - hdrlen = rtllib_get_hdrlen(le16_to_cpu(hdr->frame_control)); - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - netdev_dbg(ieee->dev, "decryption failed (SA= %pM) res=%d\n", - hdr->addr2, res); - if (res == -2) - netdev_dbg(ieee->dev, - "Decryption failed ICV mismatch (key %d)\n", - skb->data[hdrlen + 3] >> 6); - return -1; - } - - 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, - int keyidx, struct lib80211_crypt_data *crypt) -{ - struct ieee80211_hdr *hdr; - int res, hdrlen; - - if (!crypt || !crypt->ops->decrypt_msdu) - return 0; - if (ieee->hwsec_active) { - struct cb_desc *tcb_desc = (struct cb_desc *) - (skb->cb + MAX_DEV_ADDR_SIZE); - - tcb_desc->hw_sec = 1; - - if (ieee->need_sw_enc) - tcb_desc->hw_sec = 0; - } - - hdr = (struct ieee80211_hdr *)skb->data; - hdrlen = rtllib_get_hdrlen(le16_to_cpu(hdr->frame_control)); - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - netdev_dbg(ieee->dev, - "MSDU decryption/MIC verification failed (SA= %pM keyidx=%d)\n", - hdr->addr2, keyidx); - return -1; - } - - return 0; -} - -/* this function is stolen from ipw2200 driver*/ -#define IEEE_PACKET_RETRY_TIME (5 * HZ) -static int is_duplicate_packet(struct rtllib_device *ieee, - struct ieee80211_hdr *header) -{ - u16 fc = le16_to_cpu(header->frame_control); - u16 sc = le16_to_cpu(header->seq_ctrl); - u16 seq = WLAN_GET_SEQ_SEQ(sc); - u16 frag = WLAN_GET_SEQ_FRAG(sc); - u16 *last_seq, *last_frag; - unsigned long *last_time; - struct ieee80211_qos_hdr *hdr_3addrqos; - struct ieee80211_qos_hdr_4addr *hdr_4addrqos; - u8 tid; - - if (ieee80211_has_a4(header->frame_control) && - RTLLIB_QOS_HAS_SEQ(fc)) { - hdr_4addrqos = (struct ieee80211_qos_hdr_4addr *)header; - tid = le16_to_cpu(hdr_4addrqos->qos_ctrl) & RTLLIB_QCTL_TID; - tid = UP2AC(tid); - tid++; - } else if (RTLLIB_QOS_HAS_SEQ(fc)) { - hdr_3addrqos = (struct ieee80211_qos_hdr *)header; - tid = le16_to_cpu(hdr_3addrqos->qos_ctrl) & RTLLIB_QCTL_TID; - tid = UP2AC(tid); - tid++; - } else { - tid = 0; - } - - switch (ieee->iw_mode) { - case IW_MODE_INFRA: - last_seq = &ieee->last_rxseq_num[tid]; - last_frag = &ieee->last_rxfrag_num[tid]; - last_time = &ieee->last_packet_time[tid]; - break; - default: - return 0; - } - - if ((*last_seq == seq) && - time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) { - if (*last_frag == frag) - goto drop; - if (*last_frag + 1 != frag) - /* out-of-order fragment */ - goto drop; - } else { - *last_seq = seq; - } - - *last_frag = frag; - *last_time = jiffies; - return 0; - -drop: - - return 1; -} - -static bool add_reorder_entry(struct rx_ts_record *ts, - struct rx_reorder_entry *reorder_entry) -{ - struct list_head *list = &ts->rx_pending_pkt_list; - - while (list->next != &ts->rx_pending_pkt_list) { - if (SN_LESS(reorder_entry->seq_num, ((struct rx_reorder_entry *) - list_entry(list->next, struct rx_reorder_entry, - list))->seq_num)) - list = list->next; - else if (SN_EQUAL(reorder_entry->seq_num, - ((struct rx_reorder_entry *)list_entry(list->next, - struct rx_reorder_entry, list))->seq_num)) - return false; - else - break; - } - reorder_entry->list.next = list->next; - reorder_entry->list.next->prev = &reorder_entry->list; - reorder_entry->list.prev = list; - list->next = &reorder_entry->list; - - return true; -} - -void rtllib_indicate_packets(struct rtllib_device *ieee, - struct rtllib_rxb **prxb_indicate_array, u8 index) -{ - struct net_device_stats *stats = &ieee->stats; - u8 i = 0, j = 0; - u16 ethertype; - - for (j = 0; j < index; j++) { - struct rtllib_rxb *prxb = prxb_indicate_array[j]; - - for (i = 0; i < prxb->nr_subframes; i++) { - struct sk_buff *sub_skb = prxb->subframes[i]; - - /* convert hdr + possible LLC headers into Ethernet header */ - ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7]; - if (sub_skb->len >= 8 && - ((memcmp(sub_skb->data, rfc1042_header, - SNAP_SIZE) == 0 && - ethertype != ETH_P_AARP && - ethertype != ETH_P_IPX) || - memcmp(sub_skb->data, bridge_tunnel_header, - SNAP_SIZE) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation - * and replace EtherType - */ - skb_pull(sub_skb, SNAP_SIZE); - memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN); - memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); - } else { - u16 len; - /* Leave Ethernet header part of hdr and full payload */ - len = sub_skb->len; - memcpy(skb_push(sub_skb, 2), &len, 2); - memcpy(skb_push(sub_skb, ETH_ALEN), prxb->src, ETH_ALEN); - memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN); - } - - /* Indicate the packets to upper layer */ - if (sub_skb) { - stats->rx_packets++; - stats->rx_bytes += sub_skb->len; - - memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); - sub_skb->protocol = eth_type_trans(sub_skb, - ieee->dev); - sub_skb->dev = ieee->dev; - sub_skb->dev->stats.rx_packets++; - sub_skb->dev->stats.rx_bytes += sub_skb->len; - /* 802.11 crc not sufficient */ - sub_skb->ip_summed = CHECKSUM_NONE; - ieee->last_rx_ps_time = jiffies; - netif_rx(sub_skb); - } - } - kfree(prxb); - prxb = NULL; - } -} - -void rtllib_flush_rx_ts_pending_pkts(struct rtllib_device *ieee, - struct rx_ts_record *ts) -{ - struct rx_reorder_entry *pRxReorderEntry; - u8 rfd_cnt = 0; - - del_timer_sync(&ts->rx_pkt_pending_timer); - while (!list_empty(&ts->rx_pending_pkt_list)) { - if (rfd_cnt >= REORDER_WIN_SIZE) { - netdev_info(ieee->dev, - "-------------->%s() error! rfd_cnt >= REORDER_WIN_SIZE\n", - __func__); - break; - } - - pRxReorderEntry = (struct rx_reorder_entry *) - list_entry(ts->rx_pending_pkt_list.prev, - struct rx_reorder_entry, list); - netdev_dbg(ieee->dev, "%s(): Indicate seq_num %d!\n", __func__, - pRxReorderEntry->seq_num); - list_del_init(&pRxReorderEntry->list); - - ieee->rfd_array[rfd_cnt] = pRxReorderEntry->prxb; - - rfd_cnt = rfd_cnt + 1; - list_add_tail(&pRxReorderEntry->list, - &ieee->RxReorder_Unused_List); - } - rtllib_indicate_packets(ieee, ieee->rfd_array, rfd_cnt); - - ts->rx_indicate_seq = 0xffff; -} - -static void rx_reorder_indicate_packet(struct rtllib_device *ieee, - struct rtllib_rxb *prxb, - struct rx_ts_record *ts, u16 seq_num) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - struct rx_reorder_entry *reorder_entry = NULL; - u8 win_size = ht_info->rx_reorder_win_size; - u16 win_end = 0; - u8 index = 0; - bool match_win_start = false, pkt_in_buf = false; - unsigned long flags; - - netdev_dbg(ieee->dev, - "%s(): Seq is %d, ts->rx_indicate_seq is %d, win_size is %d\n", - __func__, seq_num, ts->rx_indicate_seq, win_size); - - spin_lock_irqsave(&(ieee->reorder_spinlock), flags); - - win_end = (ts->rx_indicate_seq + win_size - 1) % 4096; - /* Rx Reorder initialize condition.*/ - if (ts->rx_indicate_seq == 0xffff) - ts->rx_indicate_seq = seq_num; - - /* Drop out the packet which seq_num is smaller than WinStart */ - if (SN_LESS(seq_num, ts->rx_indicate_seq)) { - netdev_dbg(ieee->dev, - "Packet Drop! IndicateSeq: %d, NewSeq: %d\n", - ts->rx_indicate_seq, seq_num); - ht_info->rx_reorder_drop_counter++; - { - int i; - - for (i = 0; i < prxb->nr_subframes; i++) - dev_kfree_skb(prxb->subframes[i]); - kfree(prxb); - prxb = NULL; - } - spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); - return; - } - - /* Sliding window manipulation. Conditions includes: - * 1. Incoming seq_num is equal to WinStart =>Window shift 1 - * 2. Incoming seq_num is larger than the win_end => Window shift N - */ - if (SN_EQUAL(seq_num, ts->rx_indicate_seq)) { - ts->rx_indicate_seq = (ts->rx_indicate_seq + 1) % 4096; - match_win_start = true; - } else if (SN_LESS(win_end, seq_num)) { - if (seq_num >= (win_size - 1)) - ts->rx_indicate_seq = seq_num + 1 - win_size; - else - ts->rx_indicate_seq = 4095 - - (win_size - (seq_num + 1)) + 1; - netdev_dbg(ieee->dev, - "Window Shift! IndicateSeq: %d, NewSeq: %d\n", - ts->rx_indicate_seq, seq_num); - } - - /* Indication process. - * After Packet dropping and Sliding Window shifting as above, we can - * now just indicate the packets with the seq_num smaller than latest - * WinStart and struct buffer other packets. - * - * For Rx Reorder condition: - * 1. All packets with seq_num smaller than WinStart => Indicate - * 2. All packets with seq_num larger than or equal to - * WinStart => Buffer it. - */ - if (match_win_start) { - /* Current packet is going to be indicated.*/ - netdev_dbg(ieee->dev, - "Packets indication! IndicateSeq: %d, NewSeq: %d\n", - ts->rx_indicate_seq, seq_num); - ieee->prxb_indicate_array[0] = prxb; - index = 1; - } else { - /* Current packet is going to be inserted into pending list.*/ - if (!list_empty(&ieee->RxReorder_Unused_List)) { - reorder_entry = (struct rx_reorder_entry *) - list_entry(ieee->RxReorder_Unused_List.next, - struct rx_reorder_entry, list); - list_del_init(&reorder_entry->list); - - /* Make a reorder entry and insert - * into a the packet list. - */ - reorder_entry->seq_num = seq_num; - reorder_entry->prxb = prxb; - - if (!add_reorder_entry(ts, reorder_entry)) { - int i; - - netdev_dbg(ieee->dev, - "%s(): Duplicate packet is dropped. IndicateSeq: %d, NewSeq: %d\n", - __func__, ts->rx_indicate_seq, - seq_num); - list_add_tail(&reorder_entry->list, - &ieee->RxReorder_Unused_List); - - for (i = 0; i < prxb->nr_subframes; i++) - dev_kfree_skb(prxb->subframes[i]); - kfree(prxb); - prxb = NULL; - } else { - netdev_dbg(ieee->dev, - "Pkt insert into struct buffer. IndicateSeq: %d, NewSeq: %d\n", - ts->rx_indicate_seq, seq_num); - } - } else { - /* Packets are dropped if there are not enough reorder - * entries. This part should be modified!! We can just - * indicate all the packets in struct buffer and get - * reorder entries. - */ - netdev_err(ieee->dev, - "%s(): There is no reorder entry! Packet is dropped!\n", - __func__); - { - int i; - - for (i = 0; i < prxb->nr_subframes; i++) - dev_kfree_skb(prxb->subframes[i]); - kfree(prxb); - prxb = NULL; - } - } - } - - /* Check if there is any packet need indicate.*/ - while (!list_empty(&ts->rx_pending_pkt_list)) { - netdev_dbg(ieee->dev, "%s(): start RREORDER indicate\n", - __func__); - - reorder_entry = (struct rx_reorder_entry *) - list_entry(ts->rx_pending_pkt_list.prev, - struct rx_reorder_entry, - list); - if (SN_LESS(reorder_entry->seq_num, ts->rx_indicate_seq) || - SN_EQUAL(reorder_entry->seq_num, ts->rx_indicate_seq)) { - /* This protect struct buffer from overflow. */ - if (index >= REORDER_WIN_SIZE) { - netdev_err(ieee->dev, - "%s(): Buffer overflow!\n", - __func__); - pkt_in_buf = true; - break; - } - - list_del_init(&reorder_entry->list); - - if (SN_EQUAL(reorder_entry->seq_num, ts->rx_indicate_seq)) - ts->rx_indicate_seq = (ts->rx_indicate_seq + 1) % - 4096; - - ieee->prxb_indicate_array[index] = reorder_entry->prxb; - netdev_dbg(ieee->dev, "%s(): Indicate seq_num %d!\n", - __func__, reorder_entry->seq_num); - index++; - - list_add_tail(&reorder_entry->list, - &ieee->RxReorder_Unused_List); - } else { - pkt_in_buf = true; - break; - } - } - - /* Handling pending timer. Set this timer to prevent from long time - * Rx buffering. - */ - if (index > 0) { - spin_unlock_irqrestore(&ieee->reorder_spinlock, flags); - if (timer_pending(&ts->rx_pkt_pending_timer)) - del_timer_sync(&ts->rx_pkt_pending_timer); - spin_lock_irqsave(&ieee->reorder_spinlock, flags); - ts->rx_timeout_indicate_seq = 0xffff; - - if (index > REORDER_WIN_SIZE) { - netdev_err(ieee->dev, - "%s(): Rx Reorder struct buffer full!\n", - __func__); - spin_unlock_irqrestore(&(ieee->reorder_spinlock), - flags); - return; - } - rtllib_indicate_packets(ieee, ieee->prxb_indicate_array, index); - pkt_in_buf = false; - } - - if (pkt_in_buf && ts->rx_timeout_indicate_seq == 0xffff) { - netdev_dbg(ieee->dev, "%s(): SET rx timeout timer\n", __func__); - ts->rx_timeout_indicate_seq = ts->rx_indicate_seq; - spin_unlock_irqrestore(&ieee->reorder_spinlock, flags); - mod_timer(&ts->rx_pkt_pending_timer, jiffies + - msecs_to_jiffies(ht_info->rx_reorder_pending_time)); - spin_lock_irqsave(&ieee->reorder_spinlock, flags); - } - spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); -} - -static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats, - struct rtllib_rxb *rxb, u8 *src, u8 *dst) -{ - struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_control); - - u16 llc_offset = sizeof(struct ieee80211_hdr_3addr); - bool is_aggregate_frame = false; - u16 subframe_len; - u8 pad_len = 0; - u16 seq_num = 0; - struct sk_buff *sub_skb; - /* just for debug purpose */ - seq_num = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctrl)); - if ((RTLLIB_QOS_HAS_SEQ(fc)) && - (((union frameqos *)(skb->data + RTLLIB_3ADDR_LEN))->field.reserved)) - is_aggregate_frame = true; - - if (RTLLIB_QOS_HAS_SEQ(fc)) - llc_offset += 2; - if (rx_stats->contain_htc) - llc_offset += sHTCLng; - - if (skb->len <= llc_offset) - return 0; - - skb_pull(skb, llc_offset); - ieee->is_aggregate_frame = is_aggregate_frame; - if (!is_aggregate_frame) { - rxb->nr_subframes = 1; - - /* altered by clark 3/30/2010 - * The struct buffer size of the skb indicated to upper layer - * must be less than 5000, or the defraged IP datagram - * in the IP layer will exceed "ipfrag_high_tresh" and be - * discarded. so there must not use the function - * "skb_copy" and "skb_clone" for "skb". - */ - - /* Allocate new skb for releasing to upper layer */ - sub_skb = dev_alloc_skb(RTLLIB_SKBBUFFER_SIZE); - if (!sub_skb) - return 0; - skb_reserve(sub_skb, 12); - skb_put_data(sub_skb, skb->data, skb->len); - sub_skb->dev = ieee->dev; - - rxb->subframes[0] = sub_skb; - - memcpy(rxb->src, src, ETH_ALEN); - memcpy(rxb->dst, dst, ETH_ALEN); - rxb->subframes[0]->dev = ieee->dev; - return 1; - } - - rxb->nr_subframes = 0; - memcpy(rxb->src, src, ETH_ALEN); - memcpy(rxb->dst, dst, ETH_ALEN); - while (skb->len > ETHERNET_HEADER_SIZE) { - /* Offset 12 denote 2 mac address */ - subframe_len = *((u16 *)(skb->data + 12)); - subframe_len = (subframe_len >> 8) + - (subframe_len << 8); - - if (skb->len < (ETHERNET_HEADER_SIZE + subframe_len)) { - netdev_info(ieee->dev, - "%s: A-MSDU parse error!! pRfd->nTotalSubframe : %d\n", - __func__, rxb->nr_subframes); - netdev_info(ieee->dev, - "%s: A-MSDU parse error!! Subframe Length: %d\n", - __func__, subframe_len); - netdev_info(ieee->dev, - "nRemain_Length is %d and subframe_len is : %d\n", - skb->len, subframe_len); - netdev_info(ieee->dev, - "The Packet seq_num is %d\n", - seq_num); - return 0; - } - - /* move the data point to data content */ - skb_pull(skb, ETHERNET_HEADER_SIZE); - - /* altered by clark 3/30/2010 - * The struct buffer size of the skb indicated to upper layer - * must be less than 5000, or the defraged IP datagram - * in the IP layer will exceed "ipfrag_high_tresh" and be - * discarded. so there must not use the function - * "skb_copy" and "skb_clone" for "skb". - */ - - /* Allocate new skb for releasing to upper layer */ - sub_skb = dev_alloc_skb(subframe_len + 12); - if (!sub_skb) - return 0; - skb_reserve(sub_skb, 12); - skb_put_data(sub_skb, skb->data, subframe_len); - - sub_skb->dev = ieee->dev; - rxb->subframes[rxb->nr_subframes++] = sub_skb; - if (rxb->nr_subframes >= MAX_SUBFRAME_COUNT) { - netdev_dbg(ieee->dev, - "ParseSubframe(): Too many Subframes! Packets dropped!\n"); - break; - } - skb_pull(skb, subframe_len); - - if (skb->len != 0) { - pad_len = 4 - ((subframe_len + - ETHERNET_HEADER_SIZE) % 4); - if (pad_len == 4) - pad_len = 0; - - if (skb->len < pad_len) - return 0; - - skb_pull(skb, pad_len); - } - } - - 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) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_control); - size_t hdrlen; - - hdrlen = rtllib_get_hdrlen(fc); - if (ht_c_check(ieee, skb->data)) { - if (net_ratelimit()) - netdev_info(ieee->dev, "%s: find HTCControl!\n", - __func__); - hdrlen += 4; - rx_stats->contain_htc = true; - } - - return hdrlen; -} - -static int rtllib_rx_check_duplicate(struct rtllib_device *ieee, - struct sk_buff *skb, u8 multicast) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc, sc; - u8 frag; - - fc = le16_to_cpu(hdr->frame_control); - sc = le16_to_cpu(hdr->seq_ctrl); - frag = WLAN_GET_SEQ_FRAG(sc); - - if (!ieee->ht_info->cur_rx_reorder_enable || - !ieee->current_network.qos_data.active || - !is_data_frame(skb->data) || - is_legacy_data_frame(skb->data)) { - if (!ieee80211_is_beacon(hdr->frame_control)) { - if (is_duplicate_packet(ieee, hdr)) - return -1; - } - } else { - struct rx_ts_record *ts = NULL; - - if (rtllib_get_ts(ieee, (struct ts_common_info **)&ts, hdr->addr2, - (u8)frame_qos_tid((u8 *)(skb->data)), RX_DIR, true)) { - if ((fc & (1 << 11)) && (frag == ts->rx_last_frag_num) && - (WLAN_GET_SEQ_SEQ(sc) == ts->rx_last_seq_num)) - return -1; - ts->rx_last_frag_num = frag; - ts->rx_last_seq_num = WLAN_GET_SEQ_SEQ(sc); - } else { - netdev_warn(ieee->dev, "%s(): No TS! Skip the check!\n", - __func__); - return -1; - } - } - - return 0; -} - -static void rtllib_rx_extract_addr(struct rtllib_device *ieee, - struct ieee80211_hdr *hdr, u8 *dst, - u8 *src, u8 *bssid) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - - switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - case IEEE80211_FCTL_FROMDS: - ether_addr_copy(dst, hdr->addr1); - ether_addr_copy(src, hdr->addr3); - ether_addr_copy(bssid, hdr->addr2); - break; - case IEEE80211_FCTL_TODS: - ether_addr_copy(dst, hdr->addr3); - ether_addr_copy(src, hdr->addr2); - ether_addr_copy(bssid, hdr->addr1); - break; - case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - ether_addr_copy(dst, hdr->addr3); - ether_addr_copy(src, hdr->addr4); - ether_addr_copy(bssid, ieee->current_network.bssid); - break; - default: - ether_addr_copy(dst, hdr->addr1); - ether_addr_copy(src, hdr->addr2); - ether_addr_copy(bssid, hdr->addr3); - break; - } -} - -static int rtllib_rx_data_filter(struct rtllib_device *ieee, struct ieee80211_hdr *hdr, - u8 *dst, u8 *src, u8 *bssid, u8 *addr2) -{ - u16 fc = le16_to_cpu(hdr->frame_control); - u8 type = WLAN_FC_GET_TYPE(fc); - u8 stype = WLAN_FC_GET_STYPE(fc); - - /* Filter frames from different BSS */ - if (ieee80211_has_a4(hdr->frame_control) && - !ether_addr_equal(ieee->current_network.bssid, bssid) && - !is_zero_ether_addr(ieee->current_network.bssid)) { - return -1; - } - - /* Nullfunc frames may have PS-bit set, so they must be passed to - * hostap_handle_sta_rx() before being dropped here. - */ - if (stype != IEEE80211_STYPE_DATA && - stype != IEEE80211_STYPE_DATA_CFACK && - stype != IEEE80211_STYPE_DATA_CFPOLL && - stype != IEEE80211_STYPE_DATA_CFACKPOLL && - stype != IEEE80211_STYPE_QOS_DATA) { - if (stype != IEEE80211_STYPE_NULLFUNC) - netdev_dbg(ieee->dev, - "RX: dropped data frame with no data (type=0x%02x, subtype=0x%02x)\n", - type, stype); - return -1; - } - - /* packets from our adapter are dropped (echo) */ - if (!memcmp(src, ieee->dev->dev_addr, ETH_ALEN)) - return -1; - - /* {broad,multi}cast packets to our BSS go through */ - if (is_multicast_ether_addr(dst)) { - if (memcmp(bssid, ieee->current_network.bssid, - ETH_ALEN)) - return -1; - } - return 0; -} - -static int rtllib_rx_get_crypt(struct rtllib_device *ieee, struct sk_buff *skb, - struct lib80211_crypt_data **crypt, size_t hdrlen) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_control); - int idx = 0; - - if (skb->len >= hdrlen + 3) - idx = skb->data[hdrlen + 3] >> 6; - - *crypt = ieee->crypt_info.crypt[idx]; - /* allow NULL decrypt to indicate an station specific override - * for default encryption - */ - if (*crypt && (!(*crypt)->ops || !(*crypt)->ops->decrypt_mpdu)) - *crypt = NULL; - - if (!*crypt && (fc & IEEE80211_FCTL_PROTECTED)) { - /* This seems to be triggered by some (multicast?) - * frames from other than current BSS, so just drop the - * frames silently instead of filling system log with - * these reports. - */ - netdev_dbg(ieee->dev, - "Decryption failed (not set) (SA= %pM)\n", - hdr->addr2); - return -1; - } - - return 0; -} - -static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats, - struct lib80211_crypt_data *crypt, size_t hdrlen) -{ - struct ieee80211_hdr *hdr; - int keyidx = 0; - u16 fc, sc; - u8 frag; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = le16_to_cpu(hdr->frame_control); - sc = le16_to_cpu(hdr->seq_ctrl); - frag = WLAN_GET_SEQ_FRAG(sc); - - if ((!rx_stats->decrypted)) - ieee->need_sw_enc = 1; - else - ieee->need_sw_enc = 0; - - keyidx = rtllib_rx_frame_decrypt(ieee, skb, crypt); - if ((fc & IEEE80211_FCTL_PROTECTED) && (keyidx < 0)) { - netdev_info(ieee->dev, "%s: decrypt frame error\n", __func__); - return -1; - } - - hdr = (struct ieee80211_hdr *)skb->data; - if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { - int flen; - struct sk_buff *frag_skb = rtllib_frag_cache_get(ieee, hdr); - - netdev_dbg(ieee->dev, "Rx Fragment received (%u)\n", frag); - - if (!frag_skb) { - netdev_dbg(ieee->dev, - "Rx cannot get skb from fragment cache (morefrag=%d seq=%u frag=%u)\n", - (fc & IEEE80211_FCTL_MOREFRAGS) != 0, - WLAN_GET_SEQ_SEQ(sc), frag); - return -1; - } - flen = skb->len; - if (frag != 0) - flen -= hdrlen; - - if (frag_skb->tail + flen > frag_skb->end) { - netdev_warn(ieee->dev, - "%s: host decrypted and reassembled frame did not fit skb\n", - __func__); - rtllib_frag_cache_invalidate(ieee, hdr); - return -1; - } - - if (frag == 0) { - /* copy first fragment (including full headers) into - * beginning of the fragment cache skb - */ - skb_put_data(frag_skb, skb->data, flen); - } else { - /* append frame payload to the end of the fragment - * cache skb - */ - skb_put_data(frag_skb, skb->data + hdrlen, flen); - } - dev_kfree_skb_any(skb); - skb = NULL; - - if (fc & IEEE80211_FCTL_MOREFRAGS) { - /* more fragments expected - leave the skb in fragment - * cache for now; it will be delivered to upper layers - * after all fragments have been received - */ - return -2; - } - - /* this was the last fragment and the frame will be - * delivered, so remove skb from fragment cache - */ - skb = frag_skb; - hdr = (struct ieee80211_hdr *)skb->data; - rtllib_frag_cache_invalidate(ieee, hdr); - } - - /* skb: hdr + (possible reassembled) full MSDU payload; possibly still - * encrypted/authenticated - */ - if ((fc & IEEE80211_FCTL_PROTECTED) && - rtllib_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) { - netdev_info(ieee->dev, "%s: ==>decrypt msdu error\n", __func__); - return -1; - } - - hdr = (struct ieee80211_hdr *)skb->data; - if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) { - if (/*ieee->ieee802_1x &&*/ - rtllib_is_eapol_frame(ieee, skb, hdrlen)) { - /* pass unencrypted EAPOL frames even if encryption is - * configured - */ - struct eapol *eap = (struct eapol *)(skb->data + - 24); - netdev_dbg(ieee->dev, - "RX: IEEE 802.1X EAPOL frame: %s\n", - eap_get_type(eap->type)); - } else { - netdev_dbg(ieee->dev, - "encryption configured, but RX frame not encrypted (SA= %pM)\n", - hdr->addr2); - return -1; - } - } - - if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && - rtllib_is_eapol_frame(ieee, skb, hdrlen)) { - struct eapol *eap = (struct eapol *)(skb->data + 24); - - netdev_dbg(ieee->dev, "RX: IEEE 802.1X EAPOL frame: %s\n", - eap_get_type(eap->type)); - } - - if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep && - !rtllib_is_eapol_frame(ieee, skb, hdrlen)) { - netdev_dbg(ieee->dev, - "dropped unencrypted RX data frame from %pM (drop_unencrypted=1)\n", - hdr->addr2); - return -1; - } - - return 0; -} - -static void rtllib_rx_check_leave_lps(struct rtllib_device *ieee, u8 unicast, - u8 nr_subframes) -{ - if (unicast) { - if (ieee->link_state == MAC80211_LINKED) { - if (((ieee->link_detect_info.num_rx_unicast_ok_in_period + - ieee->link_detect_info.num_tx_ok_in_period) > 8) || - (ieee->link_detect_info.num_rx_unicast_ok_in_period > 2)) { - ieee->leisure_ps_leave(ieee->dev); - } - } - } - ieee->last_rx_ps_time = jiffies; -} - -static void rtllib_rx_indicate_pkt_legacy(struct rtllib_device *ieee, - struct rtllib_rx_stats *rx_stats, - struct rtllib_rxb *rxb, - u8 *dst, - u8 *src) -{ - struct net_device *dev = ieee->dev; - u16 ethertype; - int i = 0; - - if (!rxb) { - netdev_info(dev, "%s: rxb is NULL!!\n", __func__); - return; - } - - for (i = 0; i < rxb->nr_subframes; i++) { - struct sk_buff *sub_skb = rxb->subframes[i]; - - if (sub_skb) { - /* convert hdr + possible LLC headers - * into Ethernet header - */ - ethertype = (sub_skb->data[6] << 8) | sub_skb->data[7]; - if (sub_skb->len >= 8 && - ((memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation - * and replace EtherType - */ - skb_pull(sub_skb, SNAP_SIZE); - ether_addr_copy(skb_push(sub_skb, ETH_ALEN), - src); - ether_addr_copy(skb_push(sub_skb, ETH_ALEN), - dst); - } else { - u16 len; - /* Leave Ethernet header part of hdr - * and full payload - */ - len = sub_skb->len; - memcpy(skb_push(sub_skb, 2), &len, 2); - ether_addr_copy(skb_push(sub_skb, ETH_ALEN), - src); - ether_addr_copy(skb_push(sub_skb, ETH_ALEN), - dst); - } - - ieee->stats.rx_packets++; - ieee->stats.rx_bytes += sub_skb->len; - - if (is_multicast_ether_addr(dst)) - ieee->stats.multicast++; - - /* Indicate the packets to upper layer */ - memset(sub_skb->cb, 0, sizeof(sub_skb->cb)); - sub_skb->protocol = eth_type_trans(sub_skb, dev); - sub_skb->dev = dev; - sub_skb->dev->stats.rx_packets++; - sub_skb->dev->stats.rx_bytes += sub_skb->len; - /* 802.11 crc not sufficient */ - sub_skb->ip_summed = CHECKSUM_NONE; - netif_rx(sub_skb); - } - } - kfree(rxb); -} - -static int rtllib_rx_infra_adhoc(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats) -{ - struct net_device *dev = ieee->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct lib80211_crypt_data *crypt = NULL; - struct rtllib_rxb *rxb = NULL; - struct rx_ts_record *ts = NULL; - u16 fc, sc, seq_num = 0; - u8 type, stype, multicast = 0, unicast = 0, nr_subframes = 0, TID = 0; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - u8 bssid[ETH_ALEN] = {0}; - - size_t hdrlen = 0; - int ret = 0, i = 0; - - fc = le16_to_cpu(hdr->frame_control); - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - sc = le16_to_cpu(hdr->seq_ctrl); - - /*Filter pkt not to me*/ - multicast = is_multicast_ether_addr(hdr->addr1); - unicast = !multicast; - if (unicast && !ether_addr_equal(dev->dev_addr, hdr->addr1)) - goto rx_dropped; - - /*Filter pkt has too small length */ - hdrlen = rtllib_rx_get_hdrlen(ieee, skb, rx_stats); - if (skb->len < hdrlen) { - netdev_info(dev, - "%s():ERR!!! skb->len is smaller than hdrlen\n", - __func__); - goto rx_dropped; - } - - /* Filter Duplicate pkt */ - ret = rtllib_rx_check_duplicate(ieee, skb, multicast); - if (ret < 0) - goto rx_dropped; - - /* Filter CTRL Frame */ - if (type == RTLLIB_FTYPE_CTL) - goto rx_dropped; - - /* Filter MGNT Frame */ - if (type == RTLLIB_FTYPE_MGMT) { - if (rtllib_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) - goto rx_dropped; - else - goto rx_exit; - } - - /* Filter WAPI DATA Frame */ - - /* Update statstics for AP roaming */ - ieee->link_detect_info.num_recv_data_in_period++; - ieee->link_detect_info.num_rx_ok_in_period++; - - /* Data frame - extract src/dst addresses */ - rtllib_rx_extract_addr(ieee, hdr, dst, src, bssid); - - /* Filter Data frames */ - ret = rtllib_rx_data_filter(ieee, hdr, dst, src, bssid, hdr->addr2); - if (ret < 0) - goto rx_dropped; - - if (skb->len == hdrlen) - goto rx_dropped; - - /* Send pspoll based on moredata */ - if ((ieee->iw_mode == IW_MODE_INFRA) && - (ieee->sta_sleep == LPS_IS_SLEEP) && - (ieee->polling)) { - if (WLAN_FC_MORE_DATA(fc)) { - /* more data bit is set, let's request a new frame - * from the AP - */ - rtllib_sta_ps_send_pspoll_frame(ieee); - } else { - ieee->polling = false; - } - } - - /* Get crypt if encrypted */ - ret = rtllib_rx_get_crypt(ieee, skb, &crypt, hdrlen); - if (ret == -1) - goto rx_dropped; - - /* Decrypt data frame (including reassemble) */ - ret = rtllib_rx_decrypt(ieee, skb, rx_stats, crypt, hdrlen); - if (ret == -1) - goto rx_dropped; - else if (ret == -2) - goto rx_exit; - - /* Get TS for Rx Reorder */ - hdr = (struct ieee80211_hdr *)skb->data; - if (ieee->current_network.qos_data.active && is_qos_data_frame(skb->data) - && !is_multicast_ether_addr(hdr->addr1)) { - TID = frame_qos_tid(skb->data); - seq_num = WLAN_GET_SEQ_SEQ(sc); - rtllib_get_ts(ieee, (struct ts_common_info **)&ts, hdr->addr2, TID, - RX_DIR, true); - if (TID != 0 && TID != 3) - ieee->bis_any_nonbepkts = true; - } - - /* Parse rx data frame (For AMSDU) */ - /* skb: hdr + (possible reassembled) full plaintext payload */ - rxb = kmalloc(sizeof(struct rtllib_rxb), GFP_ATOMIC); - if (!rxb) - goto rx_dropped; - - /* to parse amsdu packets */ - /* qos data packets & reserved bit is 1 */ - if (parse_subframe(ieee, skb, rx_stats, rxb, src, dst) == 0) { - /* only to free rxb, and not submit the packets - * to upper layer - */ - for (i = 0; i < rxb->nr_subframes; i++) - dev_kfree_skb(rxb->subframes[i]); - kfree(rxb); - rxb = NULL; - goto rx_dropped; - } - - /* Update WAPI PN */ - - /* Check if leave LPS */ - if (ieee->is_aggregate_frame) - nr_subframes = rxb->nr_subframes; - else - nr_subframes = 1; - if (unicast) - ieee->link_detect_info.num_rx_unicast_ok_in_period += nr_subframes; - rtllib_rx_check_leave_lps(ieee, unicast, nr_subframes); - - /* Indicate packets to upper layer or Rx Reorder */ - if (!ieee->ht_info->cur_rx_reorder_enable || !ts) - rtllib_rx_indicate_pkt_legacy(ieee, rx_stats, rxb, dst, src); - else - rx_reorder_indicate_packet(ieee, rxb, ts, seq_num); - - dev_kfree_skb(skb); - - rx_exit: - return 1; - - rx_dropped: - ieee->stats.rx_dropped++; - - /* Returning 0 indicates to caller that we have not handled the SKB-- - * so it is still allocated and can be used again by underlying - * hardware as a DMA target - */ - return 0; -} - -static int rtllib_rx_monitor(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_control); - size_t hdrlen = rtllib_get_hdrlen(fc); - - if (skb->len < hdrlen) { - netdev_info(ieee->dev, - "%s():ERR!!! skb->len is smaller than hdrlen\n", - __func__); - return 0; - } - - if (ht_c_check(ieee, skb->data)) { - if (net_ratelimit()) - netdev_info(ieee->dev, "%s: Find HTCControl!\n", - __func__); - hdrlen += 4; - } - - ieee->stats.rx_packets++; - ieee->stats.rx_bytes += skb->len; - rtllib_monitor_rx(ieee, skb, rx_stats, hdrlen); - - return 1; -} - -/* All received frames are sent to this function. @skb contains the frame in - * IEEE 802.11 format, i.e., in the format it was sent over air. - * This function is called only as a tasklet (software IRQ). - */ -int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats) -{ - int ret = 0; - - if (!ieee || !skb || !rx_stats) { - pr_info("%s: Input parameters NULL!\n", __func__); - goto rx_dropped; - } - if (skb->len < 10) { - netdev_info(ieee->dev, "%s: SKB length < 10\n", __func__); - goto rx_dropped; - } - - switch (ieee->iw_mode) { - case IW_MODE_INFRA: - ret = rtllib_rx_infra_adhoc(ieee, skb, rx_stats); - break; - case IW_MODE_MONITOR: - ret = rtllib_rx_monitor(ieee, skb, rx_stats); - break; - default: - netdev_info(ieee->dev, "%s: ERR iw mode!!!\n", __func__); - break; - } - - return ret; - - rx_dropped: - if (ieee) - ieee->stats.rx_dropped++; - return 0; -} -EXPORT_SYMBOL(rtllib_rx); - -static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; - -/* Make ther structure we read from the beacon packet has the right values */ -static int rtllib_verify_qos_info(struct rtllib_qos_information_element - *info_element, int sub_type) -{ - if (info_element->element_id != QOS_ELEMENT_ID) - return -1; - if (info_element->qui_subtype != sub_type) - return -1; - if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) - return -1; - if (info_element->qui_type != QOS_OUI_TYPE) - return -1; - if (info_element->version != QOS_VERSION_1) - return -1; - - return 0; -} - -/* Parse a QoS parameter element */ -static int rtllib_read_qos_param_element( - struct rtllib_qos_parameter_info *element_param, - struct rtllib_info_element *info_element) -{ - size_t size = sizeof(*element_param); - - if (!element_param || !info_element || info_element->len != size - 2) - return -1; - - memcpy(element_param, info_element, size); - return rtllib_verify_qos_info(&element_param->info_element, - QOS_OUI_PARAM_SUB_TYPE); -} - -/* Parse a QoS information element */ -static int rtllib_read_qos_info_element( - struct rtllib_qos_information_element *element_info, - struct rtllib_info_element *info_element) -{ - size_t size = sizeof(*element_info); - - if (!element_info || !info_element || info_element->len != size - 2) - return -1; - - memcpy(element_info, info_element, size); - 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) -{ - struct rtllib_qos_ac_parameter *ac_params; - struct rtllib_qos_parameters *qos_param = &(qos_data->parameters); - int i; - u8 aci; - u8 acm; - - qos_data->wmm_acm = 0; - for (i = 0; i < QOS_QUEUE_NUM; i++) { - ac_params = &(param_elm->ac_params_record[i]); - - aci = (ac_params->aci_aifsn & 0x60) >> 5; - acm = (ac_params->aci_aifsn & 0x10) >> 4; - - if (aci >= QOS_QUEUE_NUM) - continue; - switch (aci) { - case 1: - /* BIT(0) | BIT(3) */ - if (acm) - 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); - break; - case 3: - /* BIT(6) | BIT(7) */ - if (acm) - 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); - break; - } - - qos_param->aifs[aci] = (ac_params->aci_aifsn) & 0x0f; - - /* WMM spec P.11: The minimum value for AIFSN shall be 2 */ - qos_param->aifs[aci] = max_t(u8, qos_param->aifs[aci], 2); - - qos_param->cw_min[aci] = cpu_to_le16(ac_params->ecw_min_max & - 0x0F); - - qos_param->cw_max[aci] = cpu_to_le16((ac_params->ecw_min_max & - 0xF0) >> 4); - - qos_param->flag[aci] = - (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00; - qos_param->tx_op_limit[aci] = ac_params->tx_op_limit; - } - return 0; -} - -/* we have a generic data element which it may contain QoS information or - * parameters element. check the information element length to decide - * which type to read - */ -static int rtllib_parse_qos_info_param_IE(struct rtllib_device *ieee, - struct rtllib_info_element - *info_element, - struct rtllib_network *network) -{ - int rc = 0; - struct rtllib_qos_information_element qos_info_element; - - rc = rtllib_read_qos_info_element(&qos_info_element, info_element); - - if (rc == 0) { - network->qos_data.param_count = qos_info_element.ac_info & 0x0F; - network->flags |= NETWORK_HAS_QOS_INFORMATION; - } else { - struct rtllib_qos_parameter_info param_element; - - rc = rtllib_read_qos_param_element(¶m_element, - info_element); - if (rc == 0) { - rtllib_qos_convert_ac_to_parameters(¶m_element, - &(network->qos_data)); - network->flags |= NETWORK_HAS_QOS_PARAMETERS; - network->qos_data.param_count = - param_element.info_element.ac_info & 0x0F; - } - } - - if (rc == 0) { - netdev_dbg(ieee->dev, "QoS is supported\n"); - network->qos_data.supported = 1; - } - return rc; -} - -static const char *get_info_element_string(u16 id) -{ - switch (id) { - case MFIE_TYPE_SSID: - return "SSID"; - case MFIE_TYPE_RATES: - return "RATES"; - case MFIE_TYPE_FH_SET: - return "FH_SET"; - case MFIE_TYPE_DS_SET: - return "DS_SET"; - case MFIE_TYPE_CF_SET: - return "CF_SET"; - case MFIE_TYPE_TIM: - return "TIM"; - case MFIE_TYPE_IBSS_SET: - return "IBSS_SET"; - case MFIE_TYPE_COUNTRY: - return "COUNTRY"; - case MFIE_TYPE_HOP_PARAMS: - return "HOP_PARAMS"; - case MFIE_TYPE_HOP_TABLE: - return "HOP_TABLE"; - case MFIE_TYPE_REQUEST: - return "REQUEST"; - case MFIE_TYPE_CHALLENGE: - return "CHALLENGE"; - case MFIE_TYPE_POWER_CONSTRAINT: - return "POWER_CONSTRAINT"; - case MFIE_TYPE_POWER_CAPABILITY: - return "POWER_CAPABILITY"; - case MFIE_TYPE_TPC_REQUEST: - return "TPC_REQUEST"; - case MFIE_TYPE_TPC_REPORT: - return "TPC_REPORT"; - case MFIE_TYPE_SUPP_CHANNELS: - return "SUPP_CHANNELS"; - case MFIE_TYPE_CSA: - return "CSA"; - case MFIE_TYPE_MEASURE_REQUEST: - return "MEASURE_REQUEST"; - case MFIE_TYPE_MEASURE_REPORT: - return "MEASURE_REPORT"; - case MFIE_TYPE_QUIET: - return "QUIET"; - case MFIE_TYPE_IBSS_DFS: - return "IBSS_DFS"; - case MFIE_TYPE_RSN: - return "RSN"; - case MFIE_TYPE_RATES_EX: - return "RATES_EX"; - case MFIE_TYPE_GENERIC: - return "GENERIC"; - case MFIE_TYPE_QOS_PARAMETER: - return "QOS_PARAMETER"; - default: - return "UNKNOWN"; - } -} - -static void rtllib_parse_mife_generic(struct rtllib_device *ieee, - struct rtllib_info_element *info_element, - struct rtllib_network *network, - u16 *tmp_htcap_len, - u16 *tmp_htinfo_len) -{ - u16 ht_realtek_agg_len = 0; - u8 ht_realtek_agg_buf[MAX_IE_LEN]; - - if (!rtllib_parse_qos_info_param_IE(ieee, info_element, network)) - return; - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x01) { - network->wpa_ie_len = min(info_element->len + 2, - MAX_WPA_IE_LEN); - memcpy(network->wpa_ie, info_element, network->wpa_ie_len); - return; - } - if (info_element->len == 7 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0xe0 && - info_element->data[2] == 0x4c && - info_element->data[3] == 0x01 && - info_element->data[4] == 0x02) - network->turbo_enable = 1; - - if (*tmp_htcap_len == 0) { - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x90 && - info_element->data[2] == 0x4c && - info_element->data[3] == 0x033) { - *tmp_htcap_len = min_t(u8, info_element->len, - MAX_IE_LEN); - if (*tmp_htcap_len != 0) { - network->bssht.bd_ht_spec_ver = HT_SPEC_VER_EWC; - network->bssht.bd_ht_cap_len = min_t(u16, *tmp_htcap_len, - sizeof(network->bssht.bd_ht_cap_buf)); - memcpy(network->bssht.bd_ht_cap_buf, - info_element->data, - network->bssht.bd_ht_cap_len); - } - } - if (*tmp_htcap_len != 0) { - network->bssht.bd_support_ht = true; - network->bssht.bd_ht_1r = ((((struct ht_capab_ele *)(network->bssht.bd_ht_cap_buf))->MCS[1]) == 0); - } else { - network->bssht.bd_support_ht = false; - network->bssht.bd_ht_1r = false; - } - } - - if (*tmp_htinfo_len == 0) { - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x90 && - info_element->data[2] == 0x4c && - info_element->data[3] == 0x034) { - *tmp_htinfo_len = min_t(u8, info_element->len, - MAX_IE_LEN); - if (*tmp_htinfo_len != 0) { - network->bssht.bd_ht_spec_ver = HT_SPEC_VER_EWC; - network->bssht.bd_ht_info_len = min_t(u16, *tmp_htinfo_len, - sizeof(network->bssht.bd_ht_info_buf)); - memcpy(network->bssht.bd_ht_info_buf, - info_element->data, - network->bssht.bd_ht_info_len); - } - } - } - - if (network->bssht.bd_support_ht) { - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0xe0 && - info_element->data[2] == 0x4c && - info_element->data[3] == 0x02) { - ht_realtek_agg_len = min_t(u8, info_element->len, - MAX_IE_LEN); - memcpy(ht_realtek_agg_buf, info_element->data, - info_element->len); - } - if (ht_realtek_agg_len >= 5) { - network->realtek_cap_exit = true; - network->bssht.bd_rt2rt_aggregation = true; - - if ((ht_realtek_agg_buf[4] == 1) && - (ht_realtek_agg_buf[5] & 0x02)) - network->bssht.bd_rt2rt_long_slot_time = true; - - if ((ht_realtek_agg_buf[4] == 1) && - (ht_realtek_agg_buf[5] & RT_HT_CAP_USE_92SE)) - network->bssht.rt2rt_ht_mode |= RT_HT_CAP_USE_92SE; - } - } - if (ht_realtek_agg_len >= 5) { - if ((ht_realtek_agg_buf[5] & RT_HT_CAP_USE_SOFTAP)) - network->bssht.rt2rt_ht_mode |= RT_HT_CAP_USE_SOFTAP; - } - - if ((info_element->len >= 3 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x05 && - info_element->data[2] == 0xb5) || - (info_element->len >= 3 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x0a && - info_element->data[2] == 0xf7) || - (info_element->len >= 3 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x10 && - info_element->data[2] == 0x18)) { - network->broadcom_cap_exist = true; - } - if (info_element->len >= 3 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x0c && - info_element->data[2] == 0x43) - network->ralink_cap_exist = true; - if ((info_element->len >= 3 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x03 && - info_element->data[2] == 0x7f) || - (info_element->len >= 3 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x13 && - info_element->data[2] == 0x74)) - network->atheros_cap_exist = true; - - if ((info_element->len >= 3 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0x43)) - network->marvell_cap_exist = true; - if (info_element->len >= 3 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x40 && - 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 && - info_element->data[2] == 0xf5) - network->airgo_cap_exist = true; - - if (info_element->len > 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x40 && - info_element->data[2] == 0x96 && - info_element->data[3] == 0x01) { - if (info_element->len == 6) { - memcpy(network->ccx_rm_state, &info_element->data[4], 2); - if (network->ccx_rm_state[0] != 0) - network->ccx_rm_enable = true; - else - network->ccx_rm_enable = false; - network->mb_ssid_mask = network->ccx_rm_state[1] & 0x07; - if (network->mb_ssid_mask != 0) { - network->mb_ssid_valid = true; - network->mb_ssid_mask = 0xff << - (network->mb_ssid_mask); - ether_addr_copy(network->mb_ssid, - network->bssid); - network->mb_ssid[5] &= network->mb_ssid_mask; - } else { - network->mb_ssid_valid = false; - } - } else { - network->ccx_rm_enable = false; - } - } - if (info_element->len > 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x40 && - info_element->data[2] == 0x96 && - info_element->data[3] == 0x03) { - if (info_element->len == 5) { - network->with_ccx_ver_num = true; - network->bss_ccx_ver_number = info_element->data[4]; - } else { - network->with_ccx_ver_num = false; - network->bss_ccx_ver_number = 0; - } - } - if (info_element->len > 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - 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); - memcpy(network->wzc_ie, info_element, network->wzc_ie_len); - } -} - -static void rtllib_parse_mfie_ht_cap(struct rtllib_info_element *info_element, - struct rtllib_network *network, - u16 *tmp_htcap_len) -{ - struct bss_ht *ht = &network->bssht; - - *tmp_htcap_len = min_t(u8, info_element->len, MAX_IE_LEN); - if (*tmp_htcap_len != 0) { - ht->bd_ht_spec_ver = HT_SPEC_VER_EWC; - ht->bd_ht_cap_len = min_t(u16, *tmp_htcap_len, - sizeof(ht->bd_ht_cap_buf)); - memcpy(ht->bd_ht_cap_buf, info_element->data, ht->bd_ht_cap_len); - - ht->bd_support_ht = true; - ht->bd_ht_1r = ((((struct ht_capab_ele *) - ht->bd_ht_cap_buf))->MCS[1]) == 0; - - ht->bd_bandwidth = (enum ht_channel_width) - (((struct ht_capab_ele *) - (ht->bd_ht_cap_buf))->chl_width); - } else { - ht->bd_support_ht = false; - ht->bd_ht_1r = false; - ht->bd_bandwidth = HT_CHANNEL_WIDTH_20; - } -} - -int rtllib_parse_info_param(struct rtllib_device *ieee, - struct rtllib_info_element *info_element, - u16 length, - struct rtllib_network *network, - struct rtllib_rx_stats *stats) -{ - u8 i; - short offset; - u16 tmp_htcap_len = 0; - u16 tmp_htinfo_len = 0; - char rates_str[64]; - char *p; - - while (length >= sizeof(*info_element)) { - if (sizeof(*info_element) + info_element->len > length) { - netdev_dbg(ieee->dev, - "Info elem: parse failed: info_element->len + 2 > left : info_element->len+2=%zd left=%d, id=%d.\n", - info_element->len + sizeof(*info_element), - length, info_element->id); - /* We stop processing but don't return an error here - * because some misbehaviour APs break this rule. ie. - * Orinoco AP1000. - */ - break; - } - - switch (info_element->id) { - case MFIE_TYPE_SSID: - if (rtllib_is_empty_essid(info_element->data, - info_element->len)) { - network->flags |= NETWORK_EMPTY_ESSID; - break; - } - - network->ssid_len = min(info_element->len, - (u8)IW_ESSID_MAX_SIZE); - memcpy(network->ssid, info_element->data, - network->ssid_len); - if (network->ssid_len < IW_ESSID_MAX_SIZE) - memset(network->ssid + network->ssid_len, 0, - IW_ESSID_MAX_SIZE - network->ssid_len); - - netdev_dbg(ieee->dev, "MFIE_TYPE_SSID: '%s' len=%d.\n", - network->ssid, network->ssid_len); - break; - - case MFIE_TYPE_RATES: - p = rates_str; - network->rates_len = min(info_element->len, - MAX_RATES_LENGTH); - for (i = 0; i < network->rates_len; i++) { - network->rates[i] = info_element->data[i]; - p += scnprintf(p, sizeof(rates_str) - - (p - rates_str), "%02X ", - network->rates[i]); - if (rtllib_is_ofdm_rate - (info_element->data[i])) { - network->flags |= NETWORK_HAS_OFDM; - if (info_element->data[i] & - RTLLIB_BASIC_RATE_MASK) - network->flags &= - ~NETWORK_HAS_CCK; - } - - if (rtllib_is_cck_rate - (info_element->data[i])) { - network->flags |= NETWORK_HAS_CCK; - } - } - - netdev_dbg(ieee->dev, "MFIE_TYPE_RATES: '%s' (%d)\n", - rates_str, network->rates_len); - break; - - case MFIE_TYPE_RATES_EX: - p = rates_str; - network->rates_ex_len = min(info_element->len, - MAX_RATES_EX_LENGTH); - for (i = 0; i < network->rates_ex_len; i++) { - network->rates_ex[i] = info_element->data[i]; - p += scnprintf(p, sizeof(rates_str) - - (p - rates_str), "%02X ", - network->rates_ex[i]); - if (rtllib_is_ofdm_rate - (info_element->data[i])) { - network->flags |= NETWORK_HAS_OFDM; - if (info_element->data[i] & - RTLLIB_BASIC_RATE_MASK) - network->flags &= - ~NETWORK_HAS_CCK; - } - } - - netdev_dbg(ieee->dev, "MFIE_TYPE_RATES_EX: '%s' (%d)\n", - rates_str, network->rates_ex_len); - break; - - case MFIE_TYPE_DS_SET: - netdev_dbg(ieee->dev, "MFIE_TYPE_DS_SET: %d\n", - info_element->data[0]); - network->channel = info_element->data[0]; - break; - - case MFIE_TYPE_FH_SET: - netdev_dbg(ieee->dev, "MFIE_TYPE_FH_SET: ignored\n"); - break; - - case MFIE_TYPE_CF_SET: - netdev_dbg(ieee->dev, "MFIE_TYPE_CF_SET: ignored\n"); - break; - - case MFIE_TYPE_TIM: - if (info_element->len < 4) - break; - - network->tim.tim_count = info_element->data[0]; - network->tim.tim_period = info_element->data[1]; - - network->dtim_period = info_element->data[1]; - if (ieee->link_state != MAC80211_LINKED) - break; - network->last_dtim_sta_time = jiffies; - - 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; - - if (ieee->assoc_id < 8 * offset || - ieee->assoc_id > 8 * (offset + info_element->len - 3)) - break; - - offset = (ieee->assoc_id / 8) - offset; - if (info_element->data[3 + offset] & - (1 << (ieee->assoc_id % 8))) - network->dtim_data |= RTLLIB_DTIM_UCAST; - - network->listen_interval = network->dtim_period; - break; - - case MFIE_TYPE_ERP: - network->erp_value = info_element->data[0]; - network->flags |= NETWORK_HAS_ERP_VALUE; - netdev_dbg(ieee->dev, "MFIE_TYPE_ERP_SET: %d\n", - network->erp_value); - break; - case MFIE_TYPE_IBSS_SET: - network->atim_window = info_element->data[0]; - netdev_dbg(ieee->dev, "MFIE_TYPE_IBSS_SET: %d\n", - network->atim_window); - break; - - case MFIE_TYPE_CHALLENGE: - netdev_dbg(ieee->dev, "MFIE_TYPE_CHALLENGE: ignored\n"); - break; - - case MFIE_TYPE_GENERIC: - netdev_dbg(ieee->dev, "MFIE_TYPE_GENERIC: %d bytes\n", - info_element->len); - - rtllib_parse_mife_generic(ieee, info_element, network, - &tmp_htcap_len, - &tmp_htinfo_len); - break; - - case MFIE_TYPE_RSN: - netdev_dbg(ieee->dev, "MFIE_TYPE_RSN: %d bytes\n", - info_element->len); - network->rsn_ie_len = min(info_element->len + 2, - MAX_WPA_IE_LEN); - memcpy(network->rsn_ie, info_element, - network->rsn_ie_len); - break; - - case MFIE_TYPE_HT_CAP: - netdev_dbg(ieee->dev, "MFIE_TYPE_HT_CAP: %d bytes\n", - info_element->len); - - rtllib_parse_mfie_ht_cap(info_element, network, - &tmp_htcap_len); - break; - - case MFIE_TYPE_HT_INFO: - netdev_dbg(ieee->dev, "MFIE_TYPE_HT_INFO: %d bytes\n", - info_element->len); - tmp_htinfo_len = min_t(u8, info_element->len, - MAX_IE_LEN); - if (tmp_htinfo_len) { - network->bssht.bd_ht_spec_ver = HT_SPEC_VER_IEEE; - network->bssht.bd_ht_info_len = tmp_htinfo_len > - sizeof(network->bssht.bd_ht_info_buf) ? - sizeof(network->bssht.bd_ht_info_buf) : - tmp_htinfo_len; - memcpy(network->bssht.bd_ht_info_buf, - info_element->data, - network->bssht.bd_ht_info_len); - } - break; - - case MFIE_TYPE_AIRONET: - netdev_dbg(ieee->dev, "MFIE_TYPE_AIRONET: %d bytes\n", - info_element->len); - if (info_element->len > IE_CISCO_FLAG_POSITION) { - network->with_aironet_ie = true; - - if ((info_element->data[IE_CISCO_FLAG_POSITION] - & SUPPORT_CKIP_MIC) || - (info_element->data[IE_CISCO_FLAG_POSITION] - & SUPPORT_CKIP_PK)) - network->ckip_supported = true; - else - network->ckip_supported = false; - } else { - network->with_aironet_ie = false; - network->ckip_supported = false; - } - break; - case MFIE_TYPE_QOS_PARAMETER: - netdev_err(ieee->dev, - "QoS Error need to parse QOS_PARAMETER IE\n"); - break; - - case MFIE_TYPE_COUNTRY: - netdev_dbg(ieee->dev, "MFIE_TYPE_COUNTRY: %d bytes\n", - info_element->len); - break; -/* TODO */ - default: - netdev_dbg(ieee->dev, - "Unsupported info element: %s (%d)\n", - get_info_element_string(info_element->id), - info_element->id); - break; - } - - length -= sizeof(*info_element) + info_element->len; - info_element = - (struct rtllib_info_element *)&info_element->data[info_element->len]; - } - - if (!network->atheros_cap_exist && !network->broadcom_cap_exist && - !network->cisco_cap_exist && !network->ralink_cap_exist && - !network->bssht.bd_rt2rt_aggregation) - network->unknown_cap_exist = true; - else - network->unknown_cap_exist = false; - return 0; -} - -static long rtllib_translate_todbm(u8 signal_strength_index) -{ - long signal_power; - - signal_power = (long)((signal_strength_index + 1) >> 1); - signal_power -= 95; - - return signal_power; -} - -static inline int rtllib_network_init( - struct rtllib_device *ieee, - struct rtllib_probe_response *beacon, - struct rtllib_network *network, - struct rtllib_rx_stats *stats) -{ - memset(&network->qos_data, 0, sizeof(struct rtllib_qos_data)); - - /* Pull out fixed field data */ - ether_addr_copy(network->bssid, beacon->header.addr3); - network->capability = le16_to_cpu(beacon->capability); - network->last_scanned = jiffies; - network->time_stamp[0] = beacon->time_stamp[0]; - network->time_stamp[1] = beacon->time_stamp[1]; - network->beacon_interval = le16_to_cpu(beacon->beacon_interval); - /* Where to pull this? beacon->listen_interval;*/ - network->listen_interval = 0x0A; - network->rates_len = network->rates_ex_len = 0; - network->ssid_len = 0; - network->hidden_ssid_len = 0; - memset(network->hidden_ssid, 0, sizeof(network->hidden_ssid)); - network->flags = 0; - network->atim_window = 0; - network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ? - 0x3 : 0x0; - network->berp_info_valid = false; - network->broadcom_cap_exist = false; - network->ralink_cap_exist = false; - network->atheros_cap_exist = false; - network->cisco_cap_exist = false; - network->unknown_cap_exist = false; - network->realtek_cap_exit = false; - network->marvell_cap_exist = false; - network->airgo_cap_exist = false; - network->turbo_enable = 0; - network->signal_strength = stats->signal_strength; - network->RSSI = stats->signal_strength; - network->country_ie_len = 0; - memset(network->country_ie_buf, 0, MAX_IE_LEN); - ht_initialize_bss_desc(&network->bssht); - network->flags |= NETWORK_HAS_CCK; - - network->wpa_ie_len = 0; - network->rsn_ie_len = 0; - network->wzc_ie_len = 0; - - if (rtllib_parse_info_param(ieee, - beacon->info_element, - (stats->len - sizeof(*beacon)), - network, - stats)) - return 1; - - network->mode = 0; - - if (network->flags & NETWORK_HAS_OFDM) - network->mode |= WIRELESS_MODE_G; - if (network->flags & NETWORK_HAS_CCK) - network->mode |= WIRELESS_MODE_B; - - if (network->mode == 0) { - netdev_dbg(ieee->dev, "Filtered out '%s (%pM)' network.\n", - escape_essid(network->ssid, network->ssid_len), - network->bssid); - return 1; - } - - if (network->bssht.bd_support_ht) { - if (network->mode & (WIRELESS_MODE_G | WIRELESS_MODE_B)) - network->mode = WIRELESS_MODE_N_24G; - } - if (rtllib_is_empty_essid(network->ssid, network->ssid_len)) - network->flags |= NETWORK_EMPTY_ESSID; - stats->signal = 30 + (stats->signal_strength * 70) / 100; - stats->noise = rtllib_translate_todbm((u8)(100 - stats->signal)) - 25; - - memcpy(&network->stats, stats, sizeof(network->stats)); - - return 0; -} - -static inline int is_same_network(struct rtllib_network *src, - struct rtllib_network *dst, u8 ssidbroad) -{ - /* A network is only a duplicate if the channel, BSSID, ESSID - * and the capability field (in particular IBSS and BSS) all match. - * We treat all with the same BSSID and channel - * as one network - */ - return (((src->ssid_len == dst->ssid_len) || (!ssidbroad)) && - (src->channel == dst->channel) && - !memcmp(src->bssid, dst->bssid, ETH_ALEN) && - (!memcmp(src->ssid, dst->ssid, src->ssid_len) || - (!ssidbroad)) && - ((src->capability & WLAN_CAPABILITY_IBSS) == - (dst->capability & WLAN_CAPABILITY_IBSS)) && - ((src->capability & WLAN_CAPABILITY_ESS) == - (dst->capability & WLAN_CAPABILITY_ESS))); -} - -static inline void update_network(struct rtllib_device *ieee, - struct rtllib_network *dst, - struct rtllib_network *src) -{ - int qos_active; - u8 old_param; - - memcpy(&dst->stats, &src->stats, sizeof(struct rtllib_rx_stats)); - dst->capability = src->capability; - memcpy(dst->rates, src->rates, src->rates_len); - dst->rates_len = src->rates_len; - memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); - dst->rates_ex_len = src->rates_ex_len; - if (src->ssid_len > 0) { - if (dst->ssid_len == 0) { - memset(dst->hidden_ssid, 0, sizeof(dst->hidden_ssid)); - dst->hidden_ssid_len = src->ssid_len; - memcpy(dst->hidden_ssid, src->ssid, src->ssid_len); - } else { - memset(dst->ssid, 0, dst->ssid_len); - dst->ssid_len = src->ssid_len; - memcpy(dst->ssid, src->ssid, src->ssid_len); - } - } - dst->mode = src->mode; - dst->flags = src->flags; - dst->time_stamp[0] = src->time_stamp[0]; - dst->time_stamp[1] = src->time_stamp[1]; - if (src->flags & NETWORK_HAS_ERP_VALUE) { - dst->erp_value = src->erp_value; - dst->berp_info_valid = src->berp_info_valid = true; - } - dst->beacon_interval = src->beacon_interval; - dst->listen_interval = src->listen_interval; - dst->atim_window = src->atim_window; - dst->dtim_period = src->dtim_period; - dst->dtim_data = src->dtim_data; - dst->last_dtim_sta_time = src->last_dtim_sta_time; - memcpy(&dst->tim, &src->tim, sizeof(struct rtllib_tim_parameters)); - - dst->bssht.bd_support_ht = src->bssht.bd_support_ht; - dst->bssht.bd_rt2rt_aggregation = src->bssht.bd_rt2rt_aggregation; - dst->bssht.bd_ht_cap_len = src->bssht.bd_ht_cap_len; - memcpy(dst->bssht.bd_ht_cap_buf, src->bssht.bd_ht_cap_buf, - src->bssht.bd_ht_cap_len); - dst->bssht.bd_ht_info_len = src->bssht.bd_ht_info_len; - memcpy(dst->bssht.bd_ht_info_buf, src->bssht.bd_ht_info_buf, - src->bssht.bd_ht_info_len); - dst->bssht.bd_ht_spec_ver = src->bssht.bd_ht_spec_ver; - dst->bssht.bd_rt2rt_long_slot_time = src->bssht.bd_rt2rt_long_slot_time; - dst->broadcom_cap_exist = src->broadcom_cap_exist; - dst->ralink_cap_exist = src->ralink_cap_exist; - dst->atheros_cap_exist = src->atheros_cap_exist; - dst->realtek_cap_exit = src->realtek_cap_exit; - dst->marvell_cap_exist = src->marvell_cap_exist; - dst->cisco_cap_exist = src->cisco_cap_exist; - dst->airgo_cap_exist = src->airgo_cap_exist; - dst->unknown_cap_exist = src->unknown_cap_exist; - memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); - dst->wpa_ie_len = src->wpa_ie_len; - memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); - dst->rsn_ie_len = src->rsn_ie_len; - memcpy(dst->wzc_ie, src->wzc_ie, src->wzc_ie_len); - dst->wzc_ie_len = src->wzc_ie_len; - - dst->last_scanned = jiffies; - /* qos related parameters */ - qos_active = dst->qos_data.active; - old_param = dst->qos_data.param_count; - dst->qos_data.supported = src->qos_data.supported; - if (dst->flags & NETWORK_HAS_QOS_PARAMETERS) - memcpy(&dst->qos_data, &src->qos_data, - sizeof(struct rtllib_qos_data)); - if (dst->qos_data.supported == 1) { - if (dst->ssid_len) - netdev_dbg(ieee->dev, - "QoS the network %s is QoS supported\n", - dst->ssid); - else - netdev_dbg(ieee->dev, - "QoS the network is QoS supported\n"); - } - dst->qos_data.active = qos_active; - dst->qos_data.old_param_count = old_param; - - dst->wmm_info = src->wmm_info; - if (src->wmm_param[0].ac_aci_acm_aifsn || - src->wmm_param[1].ac_aci_acm_aifsn || - src->wmm_param[2].ac_aci_acm_aifsn || - src->wmm_param[3].ac_aci_acm_aifsn) - memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); - - dst->signal_strength = src->signal_strength; - dst->RSSI = src->RSSI; - dst->turbo_enable = src->turbo_enable; - - dst->country_ie_len = src->country_ie_len; - memcpy(dst->country_ie_buf, src->country_ie_buf, src->country_ie_len); - - dst->with_aironet_ie = src->with_aironet_ie; - dst->ckip_supported = src->ckip_supported; - memcpy(dst->ccx_rm_state, src->ccx_rm_state, 2); - dst->ccx_rm_enable = src->ccx_rm_enable; - dst->mb_ssid_mask = src->mb_ssid_mask; - dst->mb_ssid_valid = src->mb_ssid_valid; - memcpy(dst->mb_ssid, src->mb_ssid, 6); - dst->with_ccx_ver_num = src->with_ccx_ver_num; - dst->bss_ccx_ver_number = src->bss_ccx_ver_number; -} - -static int is_passive_channel(struct rtllib_device *rtllib, u8 channel) -{ - if (channel > MAX_CHANNEL_NUMBER) { - netdev_info(rtllib->dev, "%s(): Invalid Channel\n", __func__); - return 0; - } - - if (rtllib->active_channel_map[channel] == 2) - return 1; - - return 0; -} - -int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel) -{ - if (channel > MAX_CHANNEL_NUMBER) { - netdev_info(rtllib->dev, "%s(): Invalid Channel\n", __func__); - return 0; - } - if (rtllib->active_channel_map[channel] > 0) - return 1; - - return 0; -} -EXPORT_SYMBOL(rtllib_legal_channel); - -static inline void rtllib_process_probe_response( - struct rtllib_device *ieee, - struct rtllib_probe_response *beacon, - struct rtllib_rx_stats *stats) -{ - struct rtllib_network *target; - struct rtllib_network *oldest = NULL; - struct rtllib_info_element *info_element = &beacon->info_element[0]; - unsigned long flags; - short renew; - struct rtllib_network *network = kzalloc(sizeof(struct rtllib_network), - GFP_ATOMIC); - __le16 frame_ctl = beacon->header.frame_control; - - if (!network) - return; - - netdev_dbg(ieee->dev, - "'%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'); - - if (rtllib_network_init(ieee, beacon, network, stats)) { - netdev_dbg(ieee->dev, "Dropped '%s' ( %pM) via %s.\n", - escape_essid(info_element->data, info_element->len), - beacon->header.addr3, - ieee80211_is_beacon(frame_ctl) ? "BEACON" : "PROBE RESPONSE"); - goto free_network; - } - - if (!rtllib_legal_channel(ieee, network->channel)) - goto free_network; - - if (ieee80211_is_probe_resp(frame_ctl)) { - if (is_passive_channel(ieee, network->channel)) { - netdev_info(ieee->dev, - "GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", - network->channel); - goto free_network; - } - } - - /* The network parsed correctly -- so now we scan our known networks - * to see if we can find it in our list. - * - * NOTE: This search is definitely not optimized. Once its doing - * the "right thing" we'll optimize it for efficiency if - * necessary - */ - - /* Search for this entry in the list and update it if it is - * already there. - */ - - spin_lock_irqsave(&ieee->lock, flags); - if (is_same_network(&ieee->current_network, network, - (network->ssid_len ? 1 : 0))) { - update_network(ieee, &ieee->current_network, network); - if ((ieee->current_network.mode == WIRELESS_MODE_N_24G || - ieee->current_network.mode == WIRELESS_MODE_G) && - ieee->current_network.berp_info_valid) { - if (ieee->current_network.erp_value & ERP_UseProtection) - ieee->current_network.buseprotection = true; - else - ieee->current_network.buseprotection = false; - } - if (ieee80211_is_beacon(frame_ctl)) { - if (ieee->link_state >= MAC80211_LINKED) - ieee->link_detect_info.num_recv_bcn_in_period++; - } - } - list_for_each_entry(target, &ieee->network_list, list) { - if (is_same_network(target, network, - (target->ssid_len ? 1 : 0))) - break; - if (!oldest || (target->last_scanned < oldest->last_scanned)) - oldest = target; - } - - /* If we didn't find a match, then get a new network slot to initialize - * with this beacon's information - */ - if (&target->list == &ieee->network_list) { - if (list_empty(&ieee->network_free_list)) { - /* If there are no more slots, expire the oldest */ - list_del(&oldest->list); - target = oldest; - netdev_dbg(ieee->dev, - "Expired '%s' ( %pM) from network list.\n", - escape_essid(target->ssid, target->ssid_len), - target->bssid); - } else { - /* Otherwise just pull from the free list */ - target = list_entry(ieee->network_free_list.next, - struct rtllib_network, list); - list_del(ieee->network_free_list.next); - } - - netdev_dbg(ieee->dev, "Adding '%s' ( %pM) via %s.\n", - escape_essid(network->ssid, network->ssid_len), - network->bssid, - ieee80211_is_beacon(frame_ctl) ? "BEACON" : "PROBE RESPONSE"); - - memcpy(target, network, sizeof(*target)); - list_add_tail(&target->list, &ieee->network_list); - if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) - rtllib_softmac_new_net(ieee, network); - } else { - netdev_dbg(ieee->dev, "Updating '%s' ( %pM) via %s.\n", - escape_essid(target->ssid, target->ssid_len), - target->bssid, - ieee80211_is_beacon(frame_ctl) ? "BEACON" : "PROBE RESPONSE"); - - /* we have an entry and we are going to update it. But this - * entry may be already expired. In this case we do the same - * as we found a new net and call the new_net handler - */ - renew = !time_after(target->last_scanned + ieee->scan_age, - jiffies); - if ((!target->ssid_len) && - (((network->ssid_len > 0) && (target->hidden_ssid_len == 0)) - || ((ieee->current_network.ssid_len == network->ssid_len) && - (strncmp(ieee->current_network.ssid, network->ssid, - network->ssid_len) == 0) && - (ieee->link_state == MAC80211_NOLINK)))) - renew = 1; - update_network(ieee, target, network); - if (renew && (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE)) - rtllib_softmac_new_net(ieee, network); - } - - spin_unlock_irqrestore(&ieee->lock, flags); - if (ieee80211_is_beacon(frame_ctl) && - is_same_network(&ieee->current_network, network, - (network->ssid_len ? 1 : 0)) && - (ieee->link_state == MAC80211_LINKED)) { - ieee->handle_beacon(ieee->dev, beacon, &ieee->current_network); - } -free_network: - kfree(network); -} - -static void rtllib_rx_mgt(struct rtllib_device *ieee, - struct sk_buff *skb, - struct rtllib_rx_stats *stats) -{ - struct ieee80211_hdr *header = (struct ieee80211_hdr *)skb->data; - - if (!ieee80211_is_probe_resp(header->frame_control) && - (!ieee80211_is_beacon(header->frame_control))) - ieee->last_rx_ps_time = jiffies; - - if (ieee80211_is_beacon(header->frame_control)) { - netdev_dbg(ieee->dev, "received BEACON\n"); - rtllib_process_probe_response( - ieee, (struct rtllib_probe_response *)header, - stats); - - if (ieee->sta_sleep || (ieee->ps != RTLLIB_PS_DISABLED && - ieee->iw_mode == IW_MODE_INFRA && - ieee->link_state == MAC80211_LINKED)) - schedule_work(&ieee->ps_task); - } else if (ieee80211_is_probe_resp(header->frame_control)) { - netdev_dbg(ieee->dev, "received PROBE RESPONSE\n"); - rtllib_process_probe_response(ieee, (struct rtllib_probe_response *)header, - stats); - } -} diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c deleted file mode 100644 index 0fc97c868f813f..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ /dev/null @@ -1,2309 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello - * - * Mostly extracted from the rtl8180-sa2400 driver for the - * in-kernel generic ieee802.11 stack. - * - * Few lines might be stolen from other part of the rtllib - * stack. Copyright who own it's copyright - * - * WPA code stolen from the ipw2200 driver. - * Copyright who own it's copyright. - */ -#include "rtllib.h" - -#include -#include -#include -#include -#include - -static void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl); - -static short rtllib_is_54g(struct rtllib_network *net) -{ - return (net->rates_ex_len > 0) || (net->rates_len > 4); -} - -/* returns the total length needed for placing the RATE MFIE - * tag and the EXTENDED RATE MFIE tag if needed. - * It encludes two bytes per tag for the tag itself and its len - */ -static unsigned int rtllib_MFIE_rate_len(struct rtllib_device *ieee) -{ - unsigned int rate_len = 0; - - rate_len = RTLLIB_CCK_RATE_LEN + 2; - rate_len += RTLLIB_OFDM_RATE_LEN + 2; - - return rate_len; -} - -/* place the MFIE rate, tag to the memory (double) pointed. - * Then it updates the pointer so that - * it points after the new MFIE tag added. - */ -static void rtllib_mfie_brate(struct rtllib_device *ieee, u8 **tag_p) -{ - u8 *tag = *tag_p; - - *tag++ = MFIE_TYPE_RATES; - *tag++ = 4; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_1MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_2MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_5MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_CCK_RATE_11MB; - - /* We may add an option for custom rates that specific HW - * might support - */ - *tag_p = tag; -} - -static void rtllib_mfie_grate(struct rtllib_device *ieee, u8 **tag_p) -{ - u8 *tag = *tag_p; - - *tag++ = MFIE_TYPE_RATES_EX; - *tag++ = 8; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_6MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_9MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_12MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_18MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_24MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_36MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_48MB; - *tag++ = RTLLIB_BASIC_RATE_MASK | RTLLIB_OFDM_RATE_54MB; - - /* We may add an option for custom rates that specific HW might - * support - */ - *tag_p = tag; -} - -static void rtllib_wmm_info(struct rtllib_device *ieee, u8 **tag_p) -{ - u8 *tag = *tag_p; - - *tag++ = MFIE_TYPE_GENERIC; - *tag++ = 7; - *tag++ = 0x00; - *tag++ = 0x50; - *tag++ = 0xf2; - *tag++ = 0x02; - *tag++ = 0x00; - *tag++ = 0x01; - *tag++ = MAX_SP_Len; - *tag_p = tag; -} - -static void rtllib_turbo_info(struct rtllib_device *ieee, u8 **tag_p) -{ - u8 *tag = *tag_p; - - *tag++ = MFIE_TYPE_GENERIC; - *tag++ = 7; - *tag++ = 0x00; - *tag++ = 0xe0; - *tag++ = 0x4c; - *tag++ = 0x01; - *tag++ = 0x02; - *tag++ = 0x11; - *tag++ = 0x00; - - *tag_p = tag; - netdev_alert(ieee->dev, "This is enable turbo mode IE process\n"); -} - -static void enqueue_mgmt(struct rtllib_device *ieee, struct sk_buff *skb) -{ - int nh; - - nh = (ieee->mgmt_queue_head + 1) % MGMT_QUEUE_NUM; - -/* if the queue is full but we have newer frames then - * just overwrites the oldest. - * - * if (nh == ieee->mgmt_queue_tail) - * return -1; - */ - ieee->mgmt_queue_head = nh; - ieee->mgmt_queue_ring[nh] = skb; -} - -static void init_mgmt_queue(struct rtllib_device *ieee) -{ - ieee->mgmt_queue_tail = 0; - ieee->mgmt_queue_head = 0; -} - -u8 mgnt_query_tx_rate_exclude_cck_rates(struct rtllib_device *ieee) -{ - u16 i; - u8 query_rate = 0; - u8 basic_rate; - - for (i = 0; i < ieee->current_network.rates_len; i++) { - basic_rate = ieee->current_network.rates[i] & 0x7F; - if (!rtllib_is_cck_rate(basic_rate)) { - if (query_rate == 0) { - query_rate = basic_rate; - } else { - if (basic_rate < query_rate) - query_rate = basic_rate; - } - } - } - - if (query_rate == 0) { - query_rate = 12; - netdev_info(ieee->dev, "No basic_rate found!!\n"); - } - return query_rate; -} - -static u8 mgnt_query_mgnt_frame_tx_rate(struct rtllib_device *ieee) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - u8 rate; - - if (ht_info->iot_action & HT_IOT_ACT_MGNT_USE_CCK_6M) - rate = 0x0c; - else - rate = ieee->basic_rate & 0x7f; - - if (rate == 0) - rate = 0x02; - - return rate; -} - -inline void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee) -{ - unsigned long flags; - short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; - struct ieee80211_hdr_3addr *header = - (struct ieee80211_hdr_3addr *)skb->data; - - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + 8); - - spin_lock_irqsave(&ieee->lock, flags); - - /* called with 2nd param 0, no mgmt lock required */ - rtllib_sta_wakeup(ieee, 0); - - if (ieee80211_is_beacon(header->frame_control)) - tcb_desc->queue_index = BEACON_QUEUE; - else - tcb_desc->queue_index = MGNT_QUEUE; - - if (ieee->disable_mgnt_queue) - tcb_desc->queue_index = HIGH_QUEUE; - - tcb_desc->data_rate = mgnt_query_mgnt_frame_tx_rate(ieee); - tcb_desc->ratr_index = 7; - tcb_desc->tx_dis_rate_fallback = 1; - tcb_desc->tx_use_drv_assinged_rate = 1; - if (single) { - if (ieee->queue_stop) { - enqueue_mgmt(ieee, skb); - } else { - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - - /* avoid watchdog triggers */ - ieee->softmac_data_hard_start_xmit(skb, ieee->dev, - ieee->basic_rate); - } - - spin_unlock_irqrestore(&ieee->lock, flags); - } else { - spin_unlock_irqrestore(&ieee->lock, flags); - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); - - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - - /* check whether the managed packet queued greater than 5 */ - if (!ieee->check_nic_enough_desc(ieee->dev, - tcb_desc->queue_index) || - skb_queue_len(&ieee->skb_waitq[tcb_desc->queue_index]) || - ieee->queue_stop) { - /* insert the skb packet to the management queue - * - * as for the completion function, it does not need - * to check it any more. - */ - netdev_info(ieee->dev, - "%s():insert to waitqueue, queue_index:%d!\n", - __func__, tcb_desc->queue_index); - skb_queue_tail(&ieee->skb_waitq[tcb_desc->queue_index], - skb); - } else { - ieee->softmac_hard_start_xmit(skb, ieee->dev); - } - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); - } -} - -static inline void -softmac_ps_mgmt_xmit(struct sk_buff *skb, - struct rtllib_device *ieee) -{ - short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; - struct ieee80211_hdr_3addr *header = - (struct ieee80211_hdr_3addr *)skb->data; - u16 fc, type, stype; - struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + 8); - - fc = le16_to_cpu(header->frame_control); - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - - if (stype != IEEE80211_STYPE_PSPOLL) - tcb_desc->queue_index = MGNT_QUEUE; - else - tcb_desc->queue_index = HIGH_QUEUE; - - if (ieee->disable_mgnt_queue) - tcb_desc->queue_index = HIGH_QUEUE; - - tcb_desc->data_rate = mgnt_query_mgnt_frame_tx_rate(ieee); - tcb_desc->ratr_index = 7; - tcb_desc->tx_dis_rate_fallback = 1; - tcb_desc->tx_use_drv_assinged_rate = 1; - if (single) { - if (type != RTLLIB_FTYPE_CTL) { - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - } - /* avoid watchdog triggers */ - ieee->softmac_data_hard_start_xmit(skb, ieee->dev, - ieee->basic_rate); - - } else { - if (type != RTLLIB_FTYPE_CTL) { - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - } - ieee->softmac_hard_start_xmit(skb, ieee->dev); - } -} - -static inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee) -{ - unsigned int len, rate_len; - u8 *tag; - struct sk_buff *skb; - struct rtllib_probe_request *req; - - len = ieee->current_network.ssid_len; - - rate_len = rtllib_MFIE_rate_len(ieee); - - skb = dev_alloc_skb(sizeof(struct rtllib_probe_request) + - 2 + len + rate_len + ieee->tx_headroom); - - if (!skb) - return NULL; - - skb_reserve(skb, ieee->tx_headroom); - - req = skb_put(skb, sizeof(struct rtllib_probe_request)); - req->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - req->header.duration_id = 0; - - eth_broadcast_addr(req->header.addr1); - ether_addr_copy(req->header.addr2, ieee->dev->dev_addr); - eth_broadcast_addr(req->header.addr3); - - tag = skb_put(skb, len + 2 + rate_len); - - *tag++ = MFIE_TYPE_SSID; - *tag++ = len; - memcpy(tag, ieee->current_network.ssid, len); - tag += len; - - rtllib_mfie_brate(ieee, &tag); - rtllib_mfie_grate(ieee, &tag); - - return skb; -} - -/* Enables network monitor mode, all rx packets will be received. */ -void rtllib_enable_net_monitor_mode(struct net_device *dev, - bool init_state) -{ - struct rtllib_device *ieee = netdev_priv_rsl(dev); - - netdev_info(dev, "========>Enter Monitor Mode\n"); - - ieee->allow_all_dest_addr_handler(dev, true, !init_state); -} - -/* Disables network monitor mode. Only packets destinated to - * us will be received. - */ -void rtllib_disable_net_monitor_mode(struct net_device *dev, bool init_state) -{ - struct rtllib_device *ieee = netdev_priv_rsl(dev); - - netdev_info(dev, "========>Exit Monitor Mode\n"); - - ieee->allow_all_dest_addr_handler(dev, false, !init_state); -} - -static void rtllib_send_probe(struct rtllib_device *ieee) -{ - struct sk_buff *skb; - - skb = rtllib_probe_req(ieee); - if (skb) { - softmac_mgmt_xmit(skb, ieee); - ieee->softmac_stats.tx_probe_rq++; - } -} - -static void rtllib_send_probe_requests(struct rtllib_device *ieee) -{ - if (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ) { - rtllib_send_probe(ieee); - rtllib_send_probe(ieee); - } -} - -/* this performs syncro scan blocking the caller until all channels - * in the allowed channel map has been checked. - */ -static void rtllib_softmac_scan_syncro(struct rtllib_device *ieee) -{ - union iwreq_data wrqu; - short ch = 0; - - ieee->be_scan_inprogress = true; - - mutex_lock(&ieee->scan_mutex); - - while (1) { - do { - ch++; - if (ch > MAX_CHANNEL_NUMBER) - goto out; /* scan completed */ - } while (!ieee->active_channel_map[ch]); - - /* this function can be called in two situations - * 1- We have switched to ad-hoc mode and we are - * performing a complete syncro scan before conclude - * there are no interesting cell and to create a - * new one. In this case the link state is - * MAC80211_NOLINK until we found an interesting cell. - * If so the ieee8021_new_net, called by the RX path - * will set the state to MAC80211_LINKED, so we stop - * scanning - * 2- We are linked and the root uses run iwlist scan. - * So we switch to MAC80211_LINKED_SCANNING to remember - * that we are still logically linked (not interested in - * new network events, despite for updating the net list, - * but we are temporarily 'unlinked' as the driver shall - * not filter RX frames and the channel is changing. - * So the only situation in which are interested is to check - * if the state become LINKED because of the #1 situation - */ - - if (ieee->link_state == MAC80211_LINKED) - goto out; - if (ieee->sync_scan_hurryup) { - netdev_info(ieee->dev, - "============>sync_scan_hurryup out\n"); - goto out; - } - - ieee->set_chan(ieee->dev, ch); - if (ieee->active_channel_map[ch] == 1) - rtllib_send_probe_requests(ieee); - - /* this prevent excessive time wait when we - * need to wait for a syncro scan to end.. - */ - msleep_interruptible_rsl(RTLLIB_SOFTMAC_SCAN_TIME); - } -out: - ieee->actscanning = false; - ieee->sync_scan_hurryup = 0; - - mutex_unlock(&ieee->scan_mutex); - - ieee->be_scan_inprogress = false; - - memset(&wrqu, 0, sizeof(wrqu)); - wireless_send_event(ieee->dev, SIOCGIWSCAN, &wrqu, NULL); -} - -static void rtllib_softmac_scan_wq(void *data) -{ - struct rtllib_device *ieee = container_of_dwork_rsl(data, - struct rtllib_device, softmac_scan_wq); - u8 last_channel = ieee->current_network.channel; - - if (!ieee->ieee_up) - return; - if (rtllib_act_scanning(ieee, true)) - return; - - mutex_lock(&ieee->scan_mutex); - - if (ieee->rf_power_state == rf_off) { - netdev_info(ieee->dev, - "======>%s():rf state is rf_off, return\n", - __func__); - goto out1; - } - - do { - ieee->current_network.channel = - (ieee->current_network.channel + 1) % - MAX_CHANNEL_NUMBER; - if (ieee->scan_watch_dog++ > MAX_CHANNEL_NUMBER) { - if (!ieee->active_channel_map[ieee->current_network.channel]) - ieee->current_network.channel = 6; - goto out; /* no good chans */ - } - } while (!ieee->active_channel_map[ieee->current_network.channel]); - - if (ieee->scanning_continue == 0) - goto out; - - ieee->set_chan(ieee->dev, ieee->current_network.channel); - - if (ieee->active_channel_map[ieee->current_network.channel] == 1) - rtllib_send_probe_requests(ieee); - - schedule_delayed_work(&ieee->softmac_scan_wq, - msecs_to_jiffies(RTLLIB_SOFTMAC_SCAN_TIME)); - - mutex_unlock(&ieee->scan_mutex); - return; - -out: - ieee->current_network.channel = last_channel; - -out1: - ieee->actscanning = false; - ieee->scan_watch_dog = 0; - ieee->scanning_continue = 0; - mutex_unlock(&ieee->scan_mutex); -} - -static void rtllib_softmac_stop_scan(struct rtllib_device *ieee) -{ - mutex_lock(&ieee->scan_mutex); - ieee->scan_watch_dog = 0; - if (ieee->scanning_continue == 1) { - ieee->scanning_continue = 0; - ieee->actscanning = false; - mutex_unlock(&ieee->scan_mutex); - cancel_delayed_work_sync(&ieee->softmac_scan_wq); - } else { - mutex_unlock(&ieee->scan_mutex); - } -} - -void rtllib_stop_scan(struct rtllib_device *ieee) -{ - if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) - rtllib_softmac_stop_scan(ieee); -} -EXPORT_SYMBOL(rtllib_stop_scan); - -void rtllib_stop_scan_syncro(struct rtllib_device *ieee) -{ - if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) - ieee->sync_scan_hurryup = 1; -} -EXPORT_SYMBOL(rtllib_stop_scan_syncro); - -bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan) -{ - if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { - if (sync_scan) - return ieee->be_scan_inprogress; - else - return ieee->actscanning || ieee->be_scan_inprogress; - } else { - return test_bit(STATUS_SCANNING, &ieee->status); - } -} -EXPORT_SYMBOL(rtllib_act_scanning); - -/* called with ieee->lock held */ -static void rtllib_start_scan(struct rtllib_device *ieee) -{ - ieee->rtllib_ips_leave_wq(ieee->dev); - - if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { - if (ieee->scanning_continue == 0) { - ieee->actscanning = true; - ieee->scanning_continue = 1; - schedule_delayed_work(&ieee->softmac_scan_wq, 0); - } - } -} - -/* called with wx_mutex held */ -void rtllib_start_scan_syncro(struct rtllib_device *ieee) -{ - ieee->sync_scan_hurryup = 0; - if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) - rtllib_softmac_scan_syncro(ieee); -} -EXPORT_SYMBOL(rtllib_start_scan_syncro); - -static inline struct sk_buff * -rtllib_authentication_req(struct rtllib_network *beacon, - struct rtllib_device *ieee, - int challengelen, u8 *daddr) -{ - struct sk_buff *skb; - struct rtllib_authentication *auth; - int len; - - len = sizeof(struct rtllib_authentication) + challengelen + - ieee->tx_headroom + 4; - skb = dev_alloc_skb(len); - - if (!skb) - return NULL; - - skb_reserve(skb, ieee->tx_headroom); - - auth = skb_put(skb, sizeof(struct rtllib_authentication)); - - auth->header.frame_control = cpu_to_le16(IEEE80211_STYPE_AUTH); - if (challengelen) - auth->header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - - auth->header.duration_id = cpu_to_le16(0x013a); - ether_addr_copy(auth->header.addr1, beacon->bssid); - ether_addr_copy(auth->header.addr2, ieee->dev->dev_addr); - ether_addr_copy(auth->header.addr3, beacon->bssid); - if (ieee->auth_mode == 0) - auth->algorithm = WLAN_AUTH_OPEN; - else if (ieee->auth_mode == 1) - auth->algorithm = cpu_to_le16(WLAN_AUTH_SHARED_KEY); - else if (ieee->auth_mode == 2) - auth->algorithm = WLAN_AUTH_OPEN; - auth->transaction = cpu_to_le16(ieee->associate_seq); - ieee->associate_seq++; - - auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); - - return skb; -} - -static struct sk_buff *rtllib_null_func(struct rtllib_device *ieee, short pwr) -{ - struct sk_buff *skb; - struct ieee80211_hdr_3addr *hdr; - - skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr) + ieee->tx_headroom); - if (!skb) - return NULL; - - skb_reserve(skb, ieee->tx_headroom); - - hdr = skb_put(skb, sizeof(struct ieee80211_hdr_3addr)); - - ether_addr_copy(hdr->addr1, ieee->current_network.bssid); - ether_addr_copy(hdr->addr2, ieee->dev->dev_addr); - ether_addr_copy(hdr->addr3, ieee->current_network.bssid); - - hdr->frame_control = cpu_to_le16(RTLLIB_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | - (pwr ? IEEE80211_FCTL_PM : 0)); - - return skb; -} - -static struct sk_buff *rtllib_pspoll_func(struct rtllib_device *ieee) -{ - struct sk_buff *skb; - struct ieee80211_pspoll *hdr; - - skb = dev_alloc_skb(sizeof(struct ieee80211_pspoll) + ieee->tx_headroom); - if (!skb) - return NULL; - - skb_reserve(skb, ieee->tx_headroom); - - hdr = skb_put(skb, sizeof(struct ieee80211_pspoll)); - - ether_addr_copy(hdr->bssid, ieee->current_network.bssid); - ether_addr_copy(hdr->ta, ieee->dev->dev_addr); - - hdr->aid = cpu_to_le16(ieee->assoc_id | 0xc000); - hdr->frame_control = cpu_to_le16(RTLLIB_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | - IEEE80211_FCTL_PM); - - return skb; -} - -static inline int sec_is_in_pmkid_list(struct rtllib_device *ieee, u8 *bssid) -{ - int i = 0; - - do { - if ((ieee->pmkid_list[i].used) && - (memcmp(ieee->pmkid_list[i].bssid, bssid, ETH_ALEN) == 0)) - break; - i++; - } while (i < NUM_PMKID_CACHE); - - if (i == NUM_PMKID_CACHE) - i = -1; - return i; -} - -static inline struct sk_buff * -rtllib_association_req(struct rtllib_network *beacon, - struct rtllib_device *ieee) -{ - struct sk_buff *skb; - struct rtllib_assoc_request_frame *hdr; - u8 *tag, *ies; - int i; - u8 *ht_cap_buf = NULL; - u8 ht_cap_len = 0; - u8 *realtek_ie_buf = NULL; - u8 realtek_ie_len = 0; - int wpa_ie_len = ieee->wpa_ie_len; - int wps_ie_len = ieee->wps_ie_len; - unsigned int ckip_ie_len = 0; - unsigned int ccxrm_ie_len = 0; - unsigned int cxvernum_ie_len = 0; - struct lib80211_crypt_data *crypt; - int encrypt; - int pmk_cache_idx; - - unsigned int rate_len = (beacon->rates_len ? - (beacon->rates_len + 2) : 0) + - (beacon->rates_ex_len ? (beacon->rates_ex_len) + - 2 : 0); - - unsigned int wmm_info_len = beacon->qos_data.supported ? 9 : 0; - unsigned int turbo_info_len = beacon->turbo_enable ? 9 : 0; - - int len = 0; - - crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; - if (crypt) - encrypt = crypt && crypt->ops && - ((strcmp(crypt->ops->name, "R-WEP") == 0 || - wpa_ie_len)); - else - encrypt = 0; - - if ((ieee->rtllib_ap_sec_type && - (ieee->rtllib_ap_sec_type(ieee) & SEC_ALG_TKIP)) || - ieee->forced_bg_mode) { - ieee->ht_info->enable_ht = 0; - ieee->mode = WIRELESS_MODE_G; - } - - if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) { - ht_cap_buf = (u8 *)&ieee->ht_info->self_ht_cap; - ht_cap_len = sizeof(ieee->ht_info->self_ht_cap); - ht_construct_capability_element(ieee, ht_cap_buf, &ht_cap_len, - encrypt, true); - if (ieee->ht_info->current_rt2rt_aggregation) { - realtek_ie_buf = ieee->ht_info->sz_rt2rt_agg_buf; - realtek_ie_len = - sizeof(ieee->ht_info->sz_rt2rt_agg_buf); - ht_construct_rt2rt_agg_element(ieee, realtek_ie_buf, - &realtek_ie_len); - } - } - - if (beacon->ckip_supported) - ckip_ie_len = 30 + 2; - if (beacon->ccx_rm_enable) - ccxrm_ie_len = 6 + 2; - if (beacon->bss_ccx_ver_number >= 2) - cxvernum_ie_len = 5 + 2; - - pmk_cache_idx = sec_is_in_pmkid_list(ieee, ieee->current_network.bssid); - if (pmk_cache_idx >= 0) { - wpa_ie_len += 18; - netdev_info(ieee->dev, "[PMK cache]: WPA2 IE length: %x\n", - wpa_ie_len); - } - len = sizeof(struct rtllib_assoc_request_frame) + 2 - + beacon->ssid_len - + rate_len - + wpa_ie_len - + wps_ie_len - + wmm_info_len - + turbo_info_len - + ht_cap_len - + realtek_ie_len - + ckip_ie_len - + ccxrm_ie_len - + cxvernum_ie_len - + ieee->tx_headroom; - - skb = dev_alloc_skb(len); - - if (!skb) - return NULL; - - skb_reserve(skb, ieee->tx_headroom); - - hdr = skb_put(skb, sizeof(struct rtllib_assoc_request_frame) + 2); - - hdr->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ); - hdr->header.duration_id = cpu_to_le16(37); - ether_addr_copy(hdr->header.addr1, beacon->bssid); - ether_addr_copy(hdr->header.addr2, ieee->dev->dev_addr); - ether_addr_copy(hdr->header.addr3, beacon->bssid); - - ether_addr_copy(ieee->ap_mac_addr, beacon->bssid); - - hdr->capability = cpu_to_le16(WLAN_CAPABILITY_ESS); - if (beacon->capability & WLAN_CAPABILITY_PRIVACY) - hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - - if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - - if (beacon->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) - hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); - - hdr->listen_interval = cpu_to_le16(beacon->listen_interval); - - hdr->info_element[0].id = MFIE_TYPE_SSID; - - hdr->info_element[0].len = beacon->ssid_len; - skb_put_data(skb, beacon->ssid, beacon->ssid_len); - - tag = skb_put(skb, rate_len); - - if (beacon->rates_len) { - *tag++ = MFIE_TYPE_RATES; - *tag++ = beacon->rates_len; - for (i = 0; i < beacon->rates_len; i++) - *tag++ = beacon->rates[i]; - } - - if (beacon->rates_ex_len) { - *tag++ = MFIE_TYPE_RATES_EX; - *tag++ = beacon->rates_ex_len; - for (i = 0; i < beacon->rates_ex_len; i++) - *tag++ = beacon->rates_ex[i]; - } - - if (beacon->ckip_supported) { - static const u8 aironet_ie_oui[] = {0x00, 0x01, 0x66}; - u8 ccx_aironet_buf[30]; - struct octet_string os_ccx_aironet_ie; - - memset(ccx_aironet_buf, 0, 30); - os_ccx_aironet_ie.octet = ccx_aironet_buf; - os_ccx_aironet_ie.Length = sizeof(ccx_aironet_buf); - memcpy(os_ccx_aironet_ie.octet, aironet_ie_oui, - sizeof(aironet_ie_oui)); - - os_ccx_aironet_ie.octet[IE_CISCO_FLAG_POSITION] |= - (SUPPORT_CKIP_PK | SUPPORT_CKIP_MIC); - tag = skb_put(skb, ckip_ie_len); - *tag++ = MFIE_TYPE_AIRONET; - *tag++ = os_ccx_aironet_ie.Length; - memcpy(tag, os_ccx_aironet_ie.octet, os_ccx_aironet_ie.Length); - tag += os_ccx_aironet_ie.Length; - } - - if (beacon->ccx_rm_enable) { - static const u8 ccx_rm_cap_buf[] = {0x00, 0x40, 0x96, 0x01, 0x01, - 0x00}; - struct octet_string os_ccx_rm_cap; - - os_ccx_rm_cap.octet = (u8 *)ccx_rm_cap_buf; - os_ccx_rm_cap.Length = sizeof(ccx_rm_cap_buf); - tag = skb_put(skb, ccxrm_ie_len); - *tag++ = MFIE_TYPE_GENERIC; - *tag++ = os_ccx_rm_cap.Length; - memcpy(tag, os_ccx_rm_cap.octet, os_ccx_rm_cap.Length); - tag += os_ccx_rm_cap.Length; - } - - if (beacon->bss_ccx_ver_number >= 2) { - u8 ccx_ver_num_buf[] = {0x00, 0x40, 0x96, 0x03, 0x00}; - struct octet_string os_ccx_ver_num; - - ccx_ver_num_buf[4] = beacon->bss_ccx_ver_number; - os_ccx_ver_num.octet = ccx_ver_num_buf; - os_ccx_ver_num.Length = sizeof(ccx_ver_num_buf); - tag = skb_put(skb, cxvernum_ie_len); - *tag++ = MFIE_TYPE_GENERIC; - *tag++ = os_ccx_ver_num.Length; - memcpy(tag, os_ccx_ver_num.octet, os_ccx_ver_num.Length); - tag += os_ccx_ver_num.Length; - } - if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) { - if (ieee->ht_info->peer_ht_spec_ver != HT_SPEC_VER_EWC) { - tag = skb_put(skb, ht_cap_len); - *tag++ = MFIE_TYPE_HT_CAP; - *tag++ = ht_cap_len - 2; - memcpy(tag, ht_cap_buf, ht_cap_len - 2); - tag += ht_cap_len - 2; - } - } - - if (wpa_ie_len) { - skb_put_data(skb, ieee->wpa_ie, ieee->wpa_ie_len); - - if (pmk_cache_idx >= 0) { - tag = skb_put(skb, 18); - *tag = 1; - *(tag + 1) = 0; - memcpy((tag + 2), &ieee->pmkid_list[pmk_cache_idx].PMKID, - 16); - } - } - if (wmm_info_len) { - tag = skb_put(skb, wmm_info_len); - rtllib_wmm_info(ieee, &tag); - } - - if (wps_ie_len && ieee->wps_ie) - skb_put_data(skb, ieee->wps_ie, wps_ie_len); - - if (turbo_info_len) { - tag = skb_put(skb, turbo_info_len); - rtllib_turbo_info(ieee, &tag); - } - - if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) { - if (ieee->ht_info->peer_ht_spec_ver == HT_SPEC_VER_EWC) { - tag = skb_put(skb, ht_cap_len); - *tag++ = MFIE_TYPE_GENERIC; - *tag++ = ht_cap_len - 2; - memcpy(tag, ht_cap_buf, ht_cap_len - 2); - tag += ht_cap_len - 2; - } - - if (ieee->ht_info->current_rt2rt_aggregation) { - tag = skb_put(skb, realtek_ie_len); - *tag++ = MFIE_TYPE_GENERIC; - *tag++ = realtek_ie_len - 2; - memcpy(tag, realtek_ie_buf, realtek_ie_len - 2); - } - } - - kfree(ieee->assocreq_ies); - ieee->assocreq_ies = NULL; - ies = &hdr->info_element[0].id; - ieee->assocreq_ies_len = (skb->data + skb->len) - ies; - ieee->assocreq_ies = kmemdup(ies, ieee->assocreq_ies_len, GFP_ATOMIC); - if (!ieee->assocreq_ies) - ieee->assocreq_ies_len = 0; - - return skb; -} - -static void rtllib_associate_abort(struct rtllib_device *ieee) -{ - unsigned long flags; - - spin_lock_irqsave(&ieee->lock, flags); - - ieee->associate_seq++; - - /* don't scan, and avoid to have the RX path possibly - * try again to associate. Even do not react to AUTH or - * ASSOC response. Just wait for the retry wq to be scheduled. - * Here we will check if there are good nets to associate - * with, so we retry or just get back to NO_LINK and scanning - */ - if (ieee->link_state == RTLLIB_ASSOCIATING_AUTHENTICATING) { - netdev_dbg(ieee->dev, "Authentication failed\n"); - ieee->softmac_stats.no_auth_rs++; - } else { - netdev_dbg(ieee->dev, "Association failed\n"); - ieee->softmac_stats.no_ass_rs++; - } - - ieee->link_state = RTLLIB_ASSOCIATING_RETRY; - - schedule_delayed_work(&ieee->associate_retry_wq, - RTLLIB_SOFTMAC_ASSOC_RETRY_TIME); - - spin_unlock_irqrestore(&ieee->lock, flags); -} - -static void rtllib_associate_abort_cb(struct timer_list *t) -{ - struct rtllib_device *dev = from_timer(dev, t, associate_timer); - - rtllib_associate_abort(dev); -} - -static void rtllib_associate_step1(struct rtllib_device *ieee, u8 *daddr) -{ - struct rtllib_network *beacon = &ieee->current_network; - struct sk_buff *skb; - - netdev_dbg(ieee->dev, "Stopping scan\n"); - - ieee->softmac_stats.tx_auth_rq++; - - skb = rtllib_authentication_req(beacon, ieee, 0, daddr); - - if (!skb) { - rtllib_associate_abort(ieee); - } else { - ieee->link_state = RTLLIB_ASSOCIATING_AUTHENTICATING; - netdev_dbg(ieee->dev, "Sending authentication request\n"); - softmac_mgmt_xmit(skb, ieee); - if (!timer_pending(&ieee->associate_timer)) { - ieee->associate_timer.expires = jiffies + (HZ / 2); - add_timer(&ieee->associate_timer); - } - } -} - -static void rtllib_auth_challenge(struct rtllib_device *ieee, u8 *challenge, - int chlen) -{ - u8 *c; - struct sk_buff *skb; - struct rtllib_network *beacon = &ieee->current_network; - - ieee->associate_seq++; - ieee->softmac_stats.tx_auth_rq++; - - skb = rtllib_authentication_req(beacon, ieee, chlen + 2, beacon->bssid); - - if (!skb) { - rtllib_associate_abort(ieee); - } else { - c = skb_put(skb, chlen + 2); - *(c++) = MFIE_TYPE_CHALLENGE; - *(c++) = chlen; - memcpy(c, challenge, chlen); - - netdev_dbg(ieee->dev, - "Sending authentication challenge response\n"); - - rtllib_encrypt_fragment(ieee, skb, - sizeof(struct ieee80211_hdr_3addr)); - - softmac_mgmt_xmit(skb, ieee); - mod_timer(&ieee->associate_timer, jiffies + (HZ / 2)); - } - kfree(challenge); -} - -static void rtllib_associate_step2(struct rtllib_device *ieee) -{ - struct sk_buff *skb; - struct rtllib_network *beacon = &ieee->current_network; - - del_timer_sync(&ieee->associate_timer); - - netdev_dbg(ieee->dev, "Sending association request\n"); - - ieee->softmac_stats.tx_ass_rq++; - skb = rtllib_association_req(beacon, ieee); - if (!skb) { - rtllib_associate_abort(ieee); - } else { - softmac_mgmt_xmit(skb, ieee); - mod_timer(&ieee->associate_timer, jiffies + (HZ / 2)); - } -} - -static void rtllib_associate_complete_wq(void *data) -{ - struct rtllib_device *ieee = (struct rtllib_device *) - container_of(data, - struct rtllib_device, - associate_complete_wq); - struct rt_pwr_save_ctrl *psc = &ieee->pwr_save_ctrl; - - netdev_info(ieee->dev, "Associated successfully with %pM\n", - ieee->current_network.bssid); - netdev_info(ieee->dev, "normal associate\n"); - notify_wx_assoc_event(ieee); - - netif_carrier_on(ieee->dev); - ieee->is_roaming = false; - if (rtllib_is_54g(&ieee->current_network)) { - ieee->rate = 108; - netdev_info(ieee->dev, "Using G rates:%d\n", ieee->rate); - } else { - ieee->rate = 22; - ieee->set_wireless_mode(ieee->dev, WIRELESS_MODE_B); - netdev_info(ieee->dev, "Using B rates:%d\n", ieee->rate); - } - if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) { - netdev_info(ieee->dev, "Successfully associated, ht enabled\n"); - ht_on_assoc_rsp(ieee); - } else { - netdev_info(ieee->dev, - "Successfully associated, ht not enabled(%d, %d)\n", - ieee->ht_info->current_ht_support, - ieee->ht_info->enable_ht); - memset(ieee->dot11ht_oper_rate_set, 0, 16); - } - ieee->link_detect_info.slot_num = 2 * (1 + - ieee->current_network.beacon_interval / - 500); - if (ieee->link_detect_info.num_recv_bcn_in_period == 0 || - ieee->link_detect_info.num_recv_data_in_period == 0) { - ieee->link_detect_info.num_recv_bcn_in_period = 1; - ieee->link_detect_info.num_recv_data_in_period = 1; - } - psc->lps_idle_count = 0; - ieee->link_change(ieee->dev); -} - -static void rtllib_sta_send_associnfo(struct rtllib_device *ieee) -{ -} - -static void rtllib_associate_complete(struct rtllib_device *ieee) -{ - del_timer_sync(&ieee->associate_timer); - - ieee->link_state = MAC80211_LINKED; - rtllib_sta_send_associnfo(ieee); - - schedule_work(&ieee->associate_complete_wq); -} - -static void rtllib_associate_procedure_wq(void *data) -{ - struct rtllib_device *ieee = container_of_dwork_rsl(data, - struct rtllib_device, - associate_procedure_wq); - rtllib_stop_scan_syncro(ieee); - ieee->rtllib_ips_leave(ieee->dev); - mutex_lock(&ieee->wx_mutex); - - rtllib_stop_scan(ieee); - ht_set_connect_bw_mode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT); - if (ieee->rf_power_state == rf_off) { - ieee->rtllib_ips_leave_wq(ieee->dev); - mutex_unlock(&ieee->wx_mutex); - return; - } - ieee->associate_seq = 1; - - rtllib_associate_step1(ieee, ieee->current_network.bssid); - - mutex_unlock(&ieee->wx_mutex); -} - -inline void rtllib_softmac_new_net(struct rtllib_device *ieee, - struct rtllib_network *net) -{ - u8 tmp_ssid[IW_ESSID_MAX_SIZE + 1]; - int tmp_ssid_len = 0; - - short apset, ssidset, ssidbroad, apmatch, ssidmatch; - - /* we are interested in new only if we are not associated - * and we are not associating / authenticating - */ - if (ieee->link_state != MAC80211_NOLINK) - return; - - if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & - WLAN_CAPABILITY_ESS)) - return; - - if (ieee->iw_mode == IW_MODE_INFRA) { - /* if the user specified the AP MAC, we need also the essid - * This could be obtained by beacons or, if the network does not - * broadcast it, it can be put manually. - */ - apset = ieee->wap_set; - ssidset = ieee->ssid_set; - ssidbroad = !(net->ssid_len == 0 || net->ssid[0] == '\0'); - apmatch = (memcmp(ieee->current_network.bssid, net->bssid, - ETH_ALEN) == 0); - if (!ssidbroad) { - ssidmatch = (ieee->current_network.ssid_len == - net->hidden_ssid_len) && - (!strncmp(ieee->current_network.ssid, - net->hidden_ssid, net->hidden_ssid_len)); - if (net->hidden_ssid_len > 0) { - strncpy(net->ssid, net->hidden_ssid, - net->hidden_ssid_len); - net->ssid_len = net->hidden_ssid_len; - ssidbroad = 1; - } - } else { - ssidmatch = - (ieee->current_network.ssid_len == net->ssid_len) && - (!strncmp(ieee->current_network.ssid, net->ssid, - net->ssid_len)); - } - - /* if the user set the AP check if match. - * if the network does not broadcast essid we check the - * user supplied ANY essid - * if the network does broadcast and the user does not set - * essid it is OK - * if the network does broadcast and the user did set essid - * check if essid match - * if the ap is not set, check that the user set the bssid - * and the network does broadcast and that those two bssid match - */ - if ((apset && apmatch && - ((ssidset && ssidbroad && ssidmatch) || - (ssidbroad && !ssidset) || (!ssidbroad && ssidset))) || - (!apset && ssidset && ssidbroad && ssidmatch) || - (ieee->is_roaming && ssidset && ssidbroad && ssidmatch)) { - /* Save the essid so that if it is hidden, it is - * replaced with the essid provided by the user. - */ - if (!ssidbroad) { - memcpy(tmp_ssid, ieee->current_network.ssid, - ieee->current_network.ssid_len); - tmp_ssid_len = ieee->current_network.ssid_len; - } - memcpy(&ieee->current_network, net, - sizeof(ieee->current_network)); - if (!ssidbroad) { - memcpy(ieee->current_network.ssid, tmp_ssid, - tmp_ssid_len); - ieee->current_network.ssid_len = tmp_ssid_len; - } - netdev_info(ieee->dev, - "Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d, mode:%x cur_net.flags:0x%x\n", - ieee->current_network.ssid, - ieee->current_network.channel, - ieee->current_network.qos_data.supported, - ieee->ht_info->enable_ht, - ieee->current_network.bssht.bd_support_ht, - ieee->current_network.mode, - ieee->current_network.flags); - - if ((rtllib_act_scanning(ieee, false)) && - !(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) - rtllib_stop_scan_syncro(ieee); - - ht_reset_iot_setting(ieee->ht_info); - ieee->wmm_acm = 0; - if (ieee->iw_mode == IW_MODE_INFRA) { - /* Join the network for the first time */ - ieee->asoc_retry_count = 0; - if ((ieee->current_network.qos_data.supported == 1) && - ieee->current_network.bssht.bd_support_ht) - ht_reset_self_and_save_peer_setting(ieee, - &ieee->current_network); - else - ieee->ht_info->current_ht_support = false; - - ieee->link_state = RTLLIB_ASSOCIATING; - schedule_delayed_work(&ieee->associate_procedure_wq, 0); - } else { - if (rtllib_is_54g(&ieee->current_network)) { - ieee->rate = 108; - ieee->set_wireless_mode(ieee->dev, WIRELESS_MODE_G); - netdev_info(ieee->dev, - "Using G rates\n"); - } else { - ieee->rate = 22; - ieee->set_wireless_mode(ieee->dev, WIRELESS_MODE_B); - netdev_info(ieee->dev, - "Using B rates\n"); - } - memset(ieee->dot11ht_oper_rate_set, 0, 16); - ieee->link_state = MAC80211_LINKED; - } - } - } -} - -static void rtllib_softmac_check_all_nets(struct rtllib_device *ieee) -{ - unsigned long flags; - struct rtllib_network *target; - - spin_lock_irqsave(&ieee->lock, flags); - - list_for_each_entry(target, &ieee->network_list, list) { - /* if the state become different that NOLINK means - * we had found what we are searching for - */ - - if (ieee->link_state != MAC80211_NOLINK) - break; - - if (ieee->scan_age == 0 || time_after(target->last_scanned + - ieee->scan_age, jiffies)) - rtllib_softmac_new_net(ieee, target); - } - spin_unlock_irqrestore(&ieee->lock, flags); -} - -static inline int auth_parse(struct net_device *dev, struct sk_buff *skb, - u8 **challenge, int *chlen) -{ - struct rtllib_authentication *a; - u8 *t; - - if (skb->len < (sizeof(struct rtllib_authentication) - - sizeof(struct rtllib_info_element))) { - netdev_dbg(dev, "invalid len in auth resp: %d\n", skb->len); - return -EINVAL; - } - *challenge = NULL; - a = (struct rtllib_authentication *)skb->data; - if (skb->len > (sizeof(struct rtllib_authentication) + 3)) { - t = skb->data + sizeof(struct rtllib_authentication); - - if (*(t++) == MFIE_TYPE_CHALLENGE) { - *chlen = *(t++); - *challenge = kmemdup(t, *chlen, GFP_ATOMIC); - if (!*challenge) - return -ENOMEM; - } - } - - if (a->status) { - netdev_dbg(dev, "auth_parse() failed\n"); - return -EINVAL; - } - - return 0; -} - -static inline u16 assoc_parse(struct rtllib_device *ieee, struct sk_buff *skb, - int *aid) -{ - struct rtllib_assoc_response_frame *response_head; - u16 status_code; - - if (skb->len < sizeof(struct rtllib_assoc_response_frame)) { - netdev_dbg(ieee->dev, "Invalid len in auth resp: %d\n", - skb->len); - return 0xcafe; - } - - response_head = (struct rtllib_assoc_response_frame *)skb->data; - *aid = le16_to_cpu(response_head->aid) & 0x3fff; - - status_code = le16_to_cpu(response_head->status); - if ((status_code == WLAN_STATUS_ASSOC_DENIED_RATES || - status_code == WLAN_STATUS_CAPS_UNSUPPORTED) && - ((ieee->mode == WIRELESS_MODE_G) && - (ieee->current_network.mode == WIRELESS_MODE_N_24G) && - (ieee->asoc_retry_count++ < (RT_ASOC_RETRY_LIMIT - 1)))) { - ieee->ht_info->iot_action |= HT_IOT_ACT_PURE_N_MODE; - } else { - ieee->asoc_retry_count = 0; - } - - return le16_to_cpu(response_head->status); -} - -void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr) -{ - struct sk_buff *buf = rtllib_null_func(ieee, pwr); - - if (buf) - softmac_ps_mgmt_xmit(buf, ieee); -} -EXPORT_SYMBOL(rtllib_sta_ps_send_null_frame); - -void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee) -{ - struct sk_buff *buf = rtllib_pspoll_func(ieee); - - if (buf) - softmac_ps_mgmt_xmit(buf, ieee); -} - -static short rtllib_sta_ps_sleep(struct rtllib_device *ieee, u64 *time) -{ - int timeout; - u8 dtim; - struct rt_pwr_save_ctrl *psc = &ieee->pwr_save_ctrl; - - if (ieee->lps_delay_cnt) { - ieee->lps_delay_cnt--; - return 0; - } - - dtim = ieee->current_network.dtim_data; - if (!(dtim & RTLLIB_DTIM_VALID)) - return 0; - timeout = ieee->current_network.beacon_interval; - ieee->current_network.dtim_data = RTLLIB_DTIM_INVALID; - /* there's no need to notify AP that I find you buffered - * with broadcast packet - */ - if (dtim & (RTLLIB_DTIM_UCAST & ieee->ps)) - return 2; - - if (!time_after(jiffies, - dev_trans_start(ieee->dev) + msecs_to_jiffies(timeout))) - return 0; - if (!time_after(jiffies, - ieee->last_rx_ps_time + msecs_to_jiffies(timeout))) - return 0; - if ((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE) && - (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) - return 0; - - if (time) { - if (ieee->awake_pkt_sent) { - psc->lps_awake_intvl = 1; - } else { - u8 max_period = 5; - - if (psc->lps_awake_intvl == 0) - psc->lps_awake_intvl = 1; - psc->lps_awake_intvl = (psc->lps_awake_intvl >= - max_period) ? max_period : - (psc->lps_awake_intvl + 1); - } - { - u8 lps_awake_intvl_tmp = 0; - u8 period = ieee->current_network.dtim_period; - u8 count = ieee->current_network.tim.tim_count; - - if (count == 0) { - if (psc->lps_awake_intvl > period) - lps_awake_intvl_tmp = period + - (psc->lps_awake_intvl - - period) - - ((psc->lps_awake_intvl - period) % - period); - else - lps_awake_intvl_tmp = psc->lps_awake_intvl; - - } else { - if (psc->lps_awake_intvl > - ieee->current_network.tim.tim_count) - lps_awake_intvl_tmp = count + - (psc->lps_awake_intvl - count) - - ((psc->lps_awake_intvl - count) % period); - else - lps_awake_intvl_tmp = psc->lps_awake_intvl; - } - - *time = ieee->current_network.last_dtim_sta_time - + msecs_to_jiffies(ieee->current_network.beacon_interval * - lps_awake_intvl_tmp); - } - } - - return 1; -} - -static inline void rtllib_sta_ps(struct work_struct *work) -{ - struct rtllib_device *ieee; - u64 time; - short sleep; - unsigned long flags, flags2; - - ieee = container_of(work, struct rtllib_device, ps_task); - - spin_lock_irqsave(&ieee->lock, flags); - - if ((ieee->ps == RTLLIB_PS_DISABLED || - ieee->iw_mode != IW_MODE_INFRA || - ieee->link_state != MAC80211_LINKED)) { - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); - rtllib_sta_wakeup(ieee, 1); - - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); - } - sleep = rtllib_sta_ps_sleep(ieee, &time); - /* 2 wake, 1 sleep, 0 do nothing */ - if (sleep == 0) - goto out; - if (sleep == 1) { - if (ieee->sta_sleep == LPS_IS_SLEEP) { - ieee->enter_sleep_state(ieee->dev, time); - } else if (ieee->sta_sleep == LPS_IS_WAKE) { - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); - - if (ieee->ps_is_queue_empty(ieee->dev)) { - ieee->sta_sleep = LPS_WAIT_NULL_DATA_SEND; - ieee->ack_tx_to_ieee = 1; - rtllib_sta_ps_send_null_frame(ieee, 1); - ieee->ps_time = time; - } - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); - } - - ieee->awake_pkt_sent = false; - - } else if (sleep == 2) { - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); - - rtllib_sta_wakeup(ieee, 1); - - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); - } - -out: - spin_unlock_irqrestore(&ieee->lock, flags); -} - -static void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl) -{ - if (ieee->sta_sleep == LPS_IS_WAKE) { - if (nl) { - if (ieee->ht_info->iot_action & - HT_IOT_ACT_NULL_DATA_POWER_SAVING) { - ieee->ack_tx_to_ieee = 1; - rtllib_sta_ps_send_null_frame(ieee, 0); - } else { - ieee->ack_tx_to_ieee = 1; - rtllib_sta_ps_send_pspoll_frame(ieee); - } - } - return; - } - - if (ieee->sta_sleep == LPS_IS_SLEEP) - ieee->sta_wake_up(ieee->dev); - if (nl) { - if (ieee->ht_info->iot_action & - HT_IOT_ACT_NULL_DATA_POWER_SAVING) { - ieee->ack_tx_to_ieee = 1; - rtllib_sta_ps_send_null_frame(ieee, 0); - } else { - ieee->ack_tx_to_ieee = 1; - ieee->polling = true; - rtllib_sta_ps_send_pspoll_frame(ieee); - } - - } else { - ieee->sta_sleep = LPS_IS_WAKE; - ieee->polling = false; - } -} - -void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success) -{ - unsigned long flags, flags2; - - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->sta_sleep == LPS_WAIT_NULL_DATA_SEND) { - /* Null frame with PS bit set */ - if (success) { - ieee->sta_sleep = LPS_IS_SLEEP; - ieee->enter_sleep_state(ieee->dev, ieee->ps_time); - } - /* if the card report not success we can't be sure the AP - * has not RXed so we can't assume the AP believe us awake - */ - } else {/* 21112005 - tx again null without PS bit if lost */ - - if ((ieee->sta_sleep == LPS_IS_WAKE) && !success) { - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); - if (ieee->ht_info->iot_action & - HT_IOT_ACT_NULL_DATA_POWER_SAVING) - rtllib_sta_ps_send_null_frame(ieee, 0); - else - rtllib_sta_ps_send_pspoll_frame(ieee); - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); - } - } - spin_unlock_irqrestore(&ieee->lock, flags); -} -EXPORT_SYMBOL(rtllib_ps_tx_ack); - -static void rtllib_process_action(struct rtllib_device *ieee, - struct sk_buff *skb) -{ - u8 *act = skb->data + RTLLIB_3ADDR_LEN; - u8 category = 0; - - category = *act; - act++; - switch (category) { - case ACT_CAT_BA: - switch (*act) { - case ACT_ADDBAREQ: - rtllib_rx_add_ba_req(ieee, skb); - break; - case ACT_ADDBARSP: - rtllib_rx_add_ba_rsp(ieee, skb); - break; - case ACT_DELBA: - rtllib_rx_DELBA(ieee, skb); - break; - } - break; - default: - break; - } -} - -static inline int -rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats) -{ - u16 errcode; - int aid; - u8 *ies; - struct rtllib_assoc_response_frame *assoc_resp; - struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *)skb->data; - u16 frame_ctl = le16_to_cpu(header->frame_control); - - netdev_dbg(ieee->dev, "received [RE]ASSOCIATION RESPONSE (%d)\n", - WLAN_FC_GET_STYPE(frame_ctl)); - - if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && - ieee->link_state == RTLLIB_ASSOCIATING_AUTHENTICATED && - (ieee->iw_mode == IW_MODE_INFRA)) { - errcode = assoc_parse(ieee, skb, &aid); - if (!errcode) { - struct rtllib_network *network = - kzalloc(sizeof(struct rtllib_network), - GFP_ATOMIC); - - if (!network) - return 1; - ieee->link_state = MAC80211_LINKED; - ieee->assoc_id = aid; - ieee->softmac_stats.rx_ass_ok++; - /* station support qos */ - /* Let the register setting default with Legacy station */ - assoc_resp = (struct rtllib_assoc_response_frame *)skb->data; - if (ieee->current_network.qos_data.supported == 1) { - if (rtllib_parse_info_param(ieee, assoc_resp->info_element, - rx_stats->len - sizeof(*assoc_resp), - network, rx_stats)) { - kfree(network); - return 1; - } - memcpy(ieee->ht_info->peer_ht_cap_buf, - network->bssht.bd_ht_cap_buf, - network->bssht.bd_ht_cap_len); - memcpy(ieee->ht_info->peer_ht_info_buf, - network->bssht.bd_ht_info_buf, - network->bssht.bd_ht_info_len); - ieee->handle_assoc_response(ieee->dev, - (struct rtllib_assoc_response_frame *)header, network); - } - kfree(network); - - kfree(ieee->assocresp_ies); - ieee->assocresp_ies = NULL; - ies = &assoc_resp->info_element[0].id; - ieee->assocresp_ies_len = (skb->data + skb->len) - ies; - ieee->assocresp_ies = kmemdup(ies, - ieee->assocresp_ies_len, - GFP_ATOMIC); - if (!ieee->assocresp_ies) - ieee->assocresp_ies_len = 0; - - rtllib_associate_complete(ieee); - } else { - /* aid could not been allocated */ - ieee->softmac_stats.rx_ass_err++; - netdev_info(ieee->dev, - "Association response status code 0x%x\n", - errcode); - if (ieee->asoc_retry_count < RT_ASOC_RETRY_LIMIT) - schedule_delayed_work(&ieee->associate_procedure_wq, 0); - else - rtllib_associate_abort(ieee); - } - } - return 0; -} - -static void rtllib_rx_auth_resp(struct rtllib_device *ieee, struct sk_buff *skb) -{ - int errcode; - u8 *challenge; - int chlen = 0; - bool support_nmode = true, half_support_nmode = false; - - errcode = auth_parse(ieee->dev, skb, &challenge, &chlen); - - if (errcode) { - ieee->softmac_stats.rx_auth_rs_err++; - netdev_info(ieee->dev, - "Authentication response status code %d", errcode); - rtllib_associate_abort(ieee); - return; - } - - if (ieee->open_wep || !challenge) { - ieee->link_state = RTLLIB_ASSOCIATING_AUTHENTICATED; - ieee->softmac_stats.rx_auth_rs_ok++; - if (!(ieee->ht_info->iot_action & HT_IOT_ACT_PURE_N_MODE)) { - if (!ieee->get_nmode_support_by_sec_cfg(ieee->dev)) { - if (is_ht_half_nmode_aps(ieee)) { - support_nmode = true; - half_support_nmode = true; - } else { - support_nmode = false; - half_support_nmode = false; - } - } - } - /* Dummy wirless mode setting to avoid encryption issue */ - if (support_nmode) { - ieee->set_wireless_mode(ieee->dev, - ieee->current_network.mode); - } else { - /*TODO*/ - ieee->set_wireless_mode(ieee->dev, WIRELESS_MODE_G); - } - - if ((ieee->current_network.mode == WIRELESS_MODE_N_24G) && - half_support_nmode) { - netdev_info(ieee->dev, "======>enter half N mode\n"); - ieee->half_wireless_n24g_mode = true; - } else { - ieee->half_wireless_n24g_mode = false; - } - rtllib_associate_step2(ieee); - } else { - rtllib_auth_challenge(ieee, challenge, chlen); - } -} - -static inline int -rtllib_rx_auth(struct rtllib_device *ieee, struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats) -{ - if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) { - if (ieee->link_state == RTLLIB_ASSOCIATING_AUTHENTICATING && - (ieee->iw_mode == IW_MODE_INFRA)) { - netdev_dbg(ieee->dev, - "Received authentication response"); - rtllib_rx_auth_resp(ieee, skb); - } - } - return 0; -} - -static inline int -rtllib_rx_deauth(struct rtllib_device *ieee, struct sk_buff *skb) -{ - struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *)skb->data; - u16 frame_ctl; - - if (memcmp(header->addr3, ieee->current_network.bssid, ETH_ALEN) != 0) - return 0; - - /* FIXME for now repeat all the association procedure - * both for disassociation and deauthentication - */ - if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && - ieee->link_state == MAC80211_LINKED && - (ieee->iw_mode == IW_MODE_INFRA)) { - frame_ctl = le16_to_cpu(header->frame_control); - netdev_info(ieee->dev, - "==========>received disassoc/deauth(%x) frame, reason code:%x\n", - WLAN_FC_GET_STYPE(frame_ctl), - ((struct rtllib_disassoc *)skb->data)->reason); - ieee->link_state = RTLLIB_ASSOCIATING; - ieee->softmac_stats.reassoc++; - ieee->is_roaming = true; - ieee->link_detect_info.busy_traffic = false; - rtllib_disassociate(ieee); - remove_peer_ts(ieee, header->addr2); - if (!(ieee->rtllib_ap_sec_type(ieee) & (SEC_ALG_CCMP | SEC_ALG_TKIP))) - schedule_delayed_work(&ieee->associate_procedure_wq, 5); - } - return 0; -} - -inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee, - struct sk_buff *skb, - struct rtllib_rx_stats *rx_stats, u16 type, - u16 stype) -{ - struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *)skb->data; - u16 frame_ctl; - - if (!ieee->proto_started) - return 0; - - frame_ctl = le16_to_cpu(header->frame_control); - switch (WLAN_FC_GET_STYPE(frame_ctl)) { - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - if (rtllib_rx_assoc_resp(ieee, skb, rx_stats) == 1) - return 1; - break; - case IEEE80211_STYPE_ASSOC_REQ: - case IEEE80211_STYPE_REASSOC_REQ: - break; - case IEEE80211_STYPE_AUTH: - rtllib_rx_auth(ieee, skb, rx_stats); - break; - case IEEE80211_STYPE_DISASSOC: - case IEEE80211_STYPE_DEAUTH: - rtllib_rx_deauth(ieee, skb); - break; - case IEEE80211_STYPE_ACTION: - rtllib_process_action(ieee, skb); - break; - default: - return -1; - } - return 0; -} - -/* following are for a simpler TX queue management. - * Instead of using netif_[stop/wake]_queue the driver - * will use these two functions (plus a reset one), that - * will internally use the kernel netif_* and takes - * care of the ieee802.11 fragmentation. - * So the driver receives a fragment per time and might - * call the stop function when it wants to not - * have enough room to TX an entire packet. - * This might be useful if each fragment needs it's own - * descriptor, thus just keep a total free memory > than - * the max fragmentation threshold is not enough.. If the - * ieee802.11 stack passed a TXB struct then you need - * to keep N free descriptors where - * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD - * In this way you need just one and the 802.11 stack - * will take care of buffering fragments and pass them to - * the driver later, when it wakes the queue. - */ -void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee) -{ - unsigned int queue_index = txb->queue_index; - unsigned long flags; - int i; - struct cb_desc *tcb_desc = NULL; - unsigned long queue_len = 0; - - spin_lock_irqsave(&ieee->lock, flags); - - /* called with 2nd param 0, no tx mgmt lock required */ - rtllib_sta_wakeup(ieee, 0); - - /* update the tx status */ - tcb_desc = (struct cb_desc *)(txb->fragments[0]->cb + - MAX_DEV_ADDR_SIZE); - if (tcb_desc->multicast) - ieee->stats.multicast++; - - /* if xmit available, just xmit it immediately, else just insert it to - * the wait queue - */ - for (i = 0; i < txb->nr_frags; i++) { - queue_len = skb_queue_len(&ieee->skb_waitq[queue_index]); - if ((queue_len != 0) || - (!ieee->check_nic_enough_desc(ieee->dev, queue_index)) || - (ieee->queue_stop)) { - /* insert the skb packet to the wait queue - * as for the completion function, it does not need - * to check it any more. - */ - if (queue_len < 200) - skb_queue_tail(&ieee->skb_waitq[queue_index], - txb->fragments[i]); - else - kfree_skb(txb->fragments[i]); - } else { - ieee->softmac_data_hard_start_xmit(txb->fragments[i], - ieee->dev, ieee->rate); - } - } - - rtllib_txb_free(txb); - - spin_unlock_irqrestore(&ieee->lock, flags); -} - -void rtllib_reset_queue(struct rtllib_device *ieee) -{ - unsigned long flags; - - spin_lock_irqsave(&ieee->lock, flags); - init_mgmt_queue(ieee); - if (ieee->tx_pending.txb) { - rtllib_txb_free(ieee->tx_pending.txb); - ieee->tx_pending.txb = NULL; - } - ieee->queue_stop = 0; - spin_unlock_irqrestore(&ieee->lock, flags); -} -EXPORT_SYMBOL(rtllib_reset_queue); - -void rtllib_stop_all_queues(struct rtllib_device *ieee) -{ - unsigned int i; - - for (i = 0; i < ieee->dev->num_tx_queues; i++) - txq_trans_cond_update(netdev_get_tx_queue(ieee->dev, i)); - - netif_tx_stop_all_queues(ieee->dev); -} - -void rtllib_wake_all_queues(struct rtllib_device *ieee) -{ - netif_tx_wake_all_queues(ieee->dev); -} - -/* this is called only in user context, with wx_mutex held */ -static void rtllib_start_bss(struct rtllib_device *ieee) -{ - unsigned long flags; - - /* check if we have already found the net we - * are interested in (if any). - * if not (we are disassociated and we are not - * in associating / authenticating phase) start the background scanning. - */ - rtllib_softmac_check_all_nets(ieee); - - /* ensure no-one start an associating process (thus setting - * the ieee->link_state to rtllib_ASSOCIATING) while we - * have just checked it and we are going to enable scan. - * The rtllib_new_net function is always called with - * lock held (from both rtllib_softmac_check_all_nets and - * the rx path), so we cannot be in the middle of such function - */ - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->link_state == MAC80211_NOLINK) - rtllib_start_scan(ieee); - spin_unlock_irqrestore(&ieee->lock, flags); -} - -static void rtllib_link_change_wq(void *data) -{ - struct rtllib_device *ieee = container_of_dwork_rsl(data, - struct rtllib_device, link_change_wq); - ieee->link_change(ieee->dev); -} - -/* called only in userspace context */ -void rtllib_disassociate(struct rtllib_device *ieee) -{ - netif_carrier_off(ieee->dev); - if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) - rtllib_reset_queue(ieee); - - ieee->link_state = MAC80211_NOLINK; - ieee->is_set_key = false; - ieee->wap_set = 0; - - schedule_delayed_work(&ieee->link_change_wq, 0); - - notify_wx_assoc_event(ieee); -} - -static void rtllib_associate_retry_wq(void *data) -{ - struct rtllib_device *ieee = container_of_dwork_rsl(data, - struct rtllib_device, associate_retry_wq); - unsigned long flags; - - mutex_lock(&ieee->wx_mutex); - if (!ieee->proto_started) - goto exit; - - if (ieee->link_state != RTLLIB_ASSOCIATING_RETRY) - goto exit; - - /* until we do not set the state to MAC80211_NOLINK - * there are no possibility to have someone else trying - * to start an association procedure (we get here with - * ieee->link_state = RTLLIB_ASSOCIATING). - * When we set the state to MAC80211_NOLINK it is possible - * that the RX path run an attempt to associate, but - * both rtllib_softmac_check_all_nets and the - * RX path works with ieee->lock held so there are no - * problems. If we are still disassociated then start a scan. - * the lock here is necessary to ensure no one try to start - * an association procedure when we have just checked the - * state and we are going to start the scan. - */ - ieee->beinretry = true; - ieee->link_state = MAC80211_NOLINK; - - rtllib_softmac_check_all_nets(ieee); - - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->link_state == MAC80211_NOLINK) - rtllib_start_scan(ieee); - spin_unlock_irqrestore(&ieee->lock, flags); - - ieee->beinretry = false; -exit: - mutex_unlock(&ieee->wx_mutex); -} - -void rtllib_softmac_stop_protocol(struct rtllib_device *ieee) -{ - rtllib_stop_scan_syncro(ieee); - mutex_lock(&ieee->wx_mutex); - rtllib_stop_protocol(ieee); - mutex_unlock(&ieee->wx_mutex); -} -EXPORT_SYMBOL(rtllib_softmac_stop_protocol); - -void rtllib_stop_protocol(struct rtllib_device *ieee) -{ - if (!ieee->proto_started) - return; - - ieee->proto_started = 0; - ieee->proto_stoppping = 1; - ieee->rtllib_ips_leave(ieee->dev); - - del_timer_sync(&ieee->associate_timer); - mutex_unlock(&ieee->wx_mutex); - cancel_delayed_work_sync(&ieee->associate_retry_wq); - mutex_lock(&ieee->wx_mutex); - cancel_delayed_work_sync(&ieee->link_change_wq); - rtllib_stop_scan(ieee); - - if (ieee->link_state <= RTLLIB_ASSOCIATING_AUTHENTICATED) - ieee->link_state = MAC80211_NOLINK; - - if (ieee->link_state == MAC80211_LINKED) { - if (ieee->iw_mode == IW_MODE_INFRA) - send_disassociation(ieee, 1, WLAN_REASON_DEAUTH_LEAVING); - rtllib_disassociate(ieee); - } - - remove_all_ts(ieee); - ieee->proto_stoppping = 0; - - kfree(ieee->assocreq_ies); - ieee->assocreq_ies = NULL; - ieee->assocreq_ies_len = 0; - kfree(ieee->assocresp_ies); - ieee->assocresp_ies = NULL; - ieee->assocresp_ies_len = 0; -} - -void rtllib_softmac_start_protocol(struct rtllib_device *ieee) -{ - mutex_lock(&ieee->wx_mutex); - rtllib_start_protocol(ieee); - mutex_unlock(&ieee->wx_mutex); -} -EXPORT_SYMBOL(rtllib_softmac_start_protocol); - -void rtllib_start_protocol(struct rtllib_device *ieee) -{ - short ch = 0; - int i = 0; - - if (ieee->proto_started) - return; - - ieee->proto_started = 1; - - if (ieee->current_network.channel == 0) { - do { - ch++; - if (ch > MAX_CHANNEL_NUMBER) - return; /* no channel found */ - } while (!ieee->active_channel_map[ch]); - ieee->current_network.channel = ch; - } - - if (ieee->current_network.beacon_interval == 0) - ieee->current_network.beacon_interval = 100; - - for (i = 0; i < 17; i++) { - ieee->last_rxseq_num[i] = -1; - ieee->last_rxfrag_num[i] = -1; - ieee->last_packet_time[i] = 0; - } - - ieee->wmm_acm = 0; - /* if the user set the MAC of the ad-hoc cell and then - * switch to managed mode, shall we make sure that association - * attempts does not fail just because the user provide the essid - * and the nic is still checking for the AP MAC ?? - */ - switch (ieee->iw_mode) { - case IW_MODE_INFRA: - rtllib_start_bss(ieee); - break; - } -} - -int rtllib_softmac_init(struct rtllib_device *ieee) -{ - int i; - - memset(&ieee->current_network, 0, sizeof(struct rtllib_network)); - - ieee->link_state = MAC80211_NOLINK; - for (i = 0; i < 5; i++) - ieee->seq_ctrl[i] = 0; - - ieee->link_detect_info.slot_index = 0; - ieee->link_detect_info.slot_num = 2; - ieee->link_detect_info.num_recv_bcn_in_period = 0; - ieee->link_detect_info.num_recv_data_in_period = 0; - ieee->link_detect_info.num_tx_ok_in_period = 0; - ieee->link_detect_info.num_rx_ok_in_period = 0; - ieee->link_detect_info.num_rx_unicast_ok_in_period = 0; - ieee->is_aggregate_frame = false; - ieee->assoc_id = 0; - ieee->queue_stop = 0; - ieee->scanning_continue = 0; - ieee->softmac_features = 0; - ieee->wap_set = 0; - ieee->ssid_set = 0; - ieee->proto_started = 0; - ieee->proto_stoppping = 0; - ieee->basic_rate = RTLLIB_DEFAULT_BASIC_RATE; - ieee->rate = 22; - ieee->ps = RTLLIB_PS_DISABLED; - ieee->sta_sleep = LPS_IS_WAKE; - - ieee->reg_dot11ht_oper_rate_set[0] = 0xff; - ieee->reg_dot11ht_oper_rate_set[1] = 0xff; - ieee->reg_dot11ht_oper_rate_set[4] = 0x01; - - ieee->reg_dot11tx_ht_oper_rate_set[0] = 0xff; - ieee->reg_dot11tx_ht_oper_rate_set[1] = 0xff; - ieee->reg_dot11tx_ht_oper_rate_set[4] = 0x01; - - ieee->first_ie_in_scan = false; - ieee->actscanning = false; - ieee->beinretry = false; - ieee->is_set_key = false; - init_mgmt_queue(ieee); - - ieee->tx_pending.txb = NULL; - - timer_setup(&ieee->associate_timer, rtllib_associate_abort_cb, 0); - - INIT_DELAYED_WORK(&ieee->link_change_wq, (void *)rtllib_link_change_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); - mutex_init(&ieee->ips_mutex); - - spin_lock_init(&ieee->mgmt_tx_lock); - spin_lock_init(&ieee->beacon_lock); - - INIT_WORK(&ieee->ps_task, rtllib_sta_ps); - - return 0; -} - -void rtllib_softmac_free(struct rtllib_device *ieee) -{ - del_timer_sync(&ieee->associate_timer); - - cancel_delayed_work_sync(&ieee->associate_retry_wq); - cancel_delayed_work_sync(&ieee->associate_procedure_wq); - cancel_delayed_work_sync(&ieee->softmac_scan_wq); - cancel_delayed_work_sync(&ieee->hw_wakeup_wq); - cancel_delayed_work_sync(&ieee->hw_sleep_wq); - cancel_delayed_work_sync(&ieee->link_change_wq); - cancel_work_sync(&ieee->associate_complete_wq); - cancel_work_sync(&ieee->ips_leave_wq); - cancel_work_sync(&ieee->wx_sync_scan_wq); - cancel_work_sync(&ieee->ps_task); -} - -static inline struct sk_buff * -rtllib_disauth_skb(struct rtllib_network *beacon, - struct rtllib_device *ieee, u16 rsn) -{ - struct sk_buff *skb; - struct rtllib_disauth *disauth; - int len = sizeof(struct rtllib_disauth) + ieee->tx_headroom; - - skb = dev_alloc_skb(len); - if (!skb) - return NULL; - - skb_reserve(skb, ieee->tx_headroom); - - disauth = skb_put(skb, sizeof(struct rtllib_disauth)); - disauth->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DEAUTH); - disauth->header.duration_id = 0; - - ether_addr_copy(disauth->header.addr1, beacon->bssid); - ether_addr_copy(disauth->header.addr2, ieee->dev->dev_addr); - ether_addr_copy(disauth->header.addr3, beacon->bssid); - - disauth->reason = cpu_to_le16(rsn); - return skb; -} - -static inline struct sk_buff * -rtllib_disassociate_skb(struct rtllib_network *beacon, - struct rtllib_device *ieee, u16 rsn) -{ - struct sk_buff *skb; - struct rtllib_disassoc *disass; - int len = sizeof(struct rtllib_disassoc) + ieee->tx_headroom; - - skb = dev_alloc_skb(len); - - if (!skb) - return NULL; - - skb_reserve(skb, ieee->tx_headroom); - - disass = skb_put(skb, sizeof(struct rtllib_disassoc)); - disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC); - disass->header.duration_id = 0; - - ether_addr_copy(disass->header.addr1, beacon->bssid); - ether_addr_copy(disass->header.addr2, ieee->dev->dev_addr); - ether_addr_copy(disass->header.addr3, beacon->bssid); - - disass->reason = cpu_to_le16(rsn); - return skb; -} - -void send_disassociation(struct rtllib_device *ieee, bool deauth, u16 rsn) -{ - struct rtllib_network *beacon = &ieee->current_network; - struct sk_buff *skb; - - if (deauth) - skb = rtllib_disauth_skb(beacon, ieee, rsn); - else - skb = rtllib_disassociate_skb(beacon, ieee, rsn); - - if (skb) - softmac_mgmt_xmit(skb, ieee); -} - -u8 rtllib_ap_sec_type(struct rtllib_device *ieee) -{ - static u8 ccmp_ie[4] = {0x00, 0x50, 0xf2, 0x04}; - static u8 ccmp_rsn_ie[4] = {0x00, 0x0f, 0xac, 0x04}; - int wpa_ie_len = ieee->wpa_ie_len; - struct lib80211_crypt_data *crypt; - int encrypt; - - crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; - encrypt = (ieee->current_network.capability & WLAN_CAPABILITY_PRIVACY) - || (crypt && crypt->ops && (strcmp(crypt->ops->name, "R-WEP") == 0)); - - /* simply judge */ - if (encrypt && (wpa_ie_len == 0)) { - return SEC_ALG_WEP; - } else if ((wpa_ie_len != 0)) { - if (((ieee->wpa_ie[0] == 0xdd) && - (!memcmp(&ieee->wpa_ie[14], ccmp_ie, 4))) || - ((ieee->wpa_ie[0] == 0x30) && - (!memcmp(&ieee->wpa_ie[10], ccmp_rsn_ie, 4)))) - return SEC_ALG_CCMP; - else - return SEC_ALG_TKIP; - } else { - return SEC_ALG_NONE; - } -} - -static void rtllib_mlme_disassociate_request(struct rtllib_device *rtllib, - u8 *addr, u8 rsn) -{ - u8 i; - u8 op_mode; - - remove_peer_ts(rtllib, addr); - - if (memcmp(rtllib->current_network.bssid, addr, 6) == 0) { - rtllib->link_state = MAC80211_NOLINK; - - for (i = 0; i < 6; i++) - rtllib->current_network.bssid[i] = 0x22; - op_mode = RT_OP_MODE_NO_LINK; - rtllib->op_mode = RT_OP_MODE_NO_LINK; - rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_MEDIA_STATUS, - (u8 *)(&op_mode)); - rtllib_disassociate(rtllib); - - rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_BSSID, - rtllib->current_network.bssid); - } -} - -static void rtllib_mgnt_disconnect_ap(struct rtllib_device *rtllib, u8 rsn) -{ - bool filter_out_nonassociated_bssid = false; - - filter_out_nonassociated_bssid = false; - rtllib->set_hw_reg_handler(rtllib->dev, HW_VAR_CECHK_BSSID, - (u8 *)(&filter_out_nonassociated_bssid)); - rtllib_mlme_disassociate_request(rtllib, rtllib->current_network.bssid, - rsn); - - rtllib->link_state = MAC80211_NOLINK; -} - -bool rtllib_mgnt_disconnect(struct rtllib_device *rtllib, u8 rsn) -{ - if (rtllib->ps != RTLLIB_PS_DISABLED) - rtllib->sta_wake_up(rtllib->dev); - - if (rtllib->link_state == MAC80211_LINKED) { - if (rtllib->iw_mode == IW_MODE_INFRA) - rtllib_mgnt_disconnect_ap(rtllib, rsn); - } - - return true; -} -EXPORT_SYMBOL(rtllib_mgnt_disconnect); - -void notify_wx_assoc_event(struct rtllib_device *ieee) -{ - union iwreq_data wrqu; - - if (ieee->cannot_notify) - return; - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (ieee->link_state == MAC80211_LINKED) { - memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, - ETH_ALEN); - } else { - netdev_info(ieee->dev, "%s(): Tell user space disconnected\n", - __func__); - eth_zero_addr(wrqu.ap_addr.sa_data); - } - wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); -} -EXPORT_SYMBOL(notify_wx_assoc_event); diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c deleted file mode 100644 index c59686d68a33b9..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c +++ /dev/null @@ -1,534 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello - * - * Mostly extracted from the rtl8180-sa2400 driver for the - * in-kernel generic ieee802.11 stack. - * - * Some pieces of code might be stolen from ipw2100 driver - * copyright of who own it's copyright ;-) - * - * PS wx handler mostly stolen from hostap, copyright who - * own it's copyright ;-) - */ -#include - -#include "rtllib.h" - -int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int ret; - struct iw_freq *fwrq = &wrqu->freq; - - mutex_lock(&ieee->wx_mutex); - - if (ieee->iw_mode == IW_MODE_INFRA) { - ret = 0; - goto out; - } - - /* if setting by freq convert to channel */ - if (fwrq->e == 1) { - if ((fwrq->m >= (int)2.412e8 && - fwrq->m <= (int)2.487e8)) { - fwrq->m = ieee80211_freq_khz_to_channel(fwrq->m / 100); - fwrq->e = 0; - } - } - - if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) { - ret = -EOPNOTSUPP; - goto out; - - } else { /* Set the channel */ - - if (ieee->active_channel_map[fwrq->m] != 1) { - ret = -EINVAL; - goto out; - } - ieee->current_network.channel = fwrq->m; - ieee->set_chan(ieee->dev, ieee->current_network.channel); - } - - ret = 0; -out: - mutex_unlock(&ieee->wx_mutex); - return ret; -} -EXPORT_SYMBOL(rtllib_wx_set_freq); - -int rtllib_wx_get_freq(struct rtllib_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct iw_freq *fwrq = &wrqu->freq; - - if (ieee->current_network.channel == 0) - return -1; - fwrq->m = ieee80211_channel_to_freq_khz(ieee->current_network.channel, - NL80211_BAND_2GHZ) * 100; - fwrq->e = 1; - return 0; -} -EXPORT_SYMBOL(rtllib_wx_get_freq); - -int rtllib_wx_get_wap(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - unsigned long flags; - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - - if (ieee->iw_mode == IW_MODE_MONITOR) - return -1; - - /* We want avoid to give to the user inconsistent infos*/ - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->link_state != MAC80211_LINKED && - ieee->link_state != MAC80211_LINKED_SCANNING && - ieee->wap_set == 0) - - eth_zero_addr(wrqu->ap_addr.sa_data); - else - memcpy(wrqu->ap_addr.sa_data, - ieee->current_network.bssid, ETH_ALEN); - - spin_unlock_irqrestore(&ieee->lock, flags); - - return 0; -} -EXPORT_SYMBOL(rtllib_wx_get_wap); - -int rtllib_wx_set_wap(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *awrq, - char *extra) -{ - int ret = 0; - unsigned long flags; - - short ifup = ieee->proto_started; - struct sockaddr *temp = (struct sockaddr *)awrq; - - rtllib_stop_scan_syncro(ieee); - - mutex_lock(&ieee->wx_mutex); - /* use ifconfig hw ether */ - - if (temp->sa_family != ARPHRD_ETHER) { - ret = -EINVAL; - goto out; - } - - if (is_zero_ether_addr(temp->sa_data)) { - spin_lock_irqsave(&ieee->lock, flags); - ether_addr_copy(ieee->current_network.bssid, temp->sa_data); - ieee->wap_set = 0; - spin_unlock_irqrestore(&ieee->lock, flags); - ret = -1; - goto out; - } - - if (ifup) - rtllib_stop_protocol(ieee); - - /* just to avoid to give inconsistent infos in the - * get wx method. not really needed otherwise - */ - spin_lock_irqsave(&ieee->lock, flags); - - ieee->cannot_notify = false; - ether_addr_copy(ieee->current_network.bssid, temp->sa_data); - ieee->wap_set = !is_zero_ether_addr(temp->sa_data); - - spin_unlock_irqrestore(&ieee->lock, flags); - - if (ifup) - rtllib_start_protocol(ieee); -out: - mutex_unlock(&ieee->wx_mutex); - return ret; -} -EXPORT_SYMBOL(rtllib_wx_set_wap); - -int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int len, ret = 0; - unsigned long flags; - - if (ieee->iw_mode == IW_MODE_MONITOR) - return -1; - - /* We want avoid to give to the user inconsistent infos*/ - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->current_network.ssid[0] == '\0' || - ieee->current_network.ssid_len == 0) { - ret = -1; - goto out; - } - - if (ieee->link_state != MAC80211_LINKED && - ieee->link_state != MAC80211_LINKED_SCANNING && - ieee->ssid_set == 0) { - ret = -1; - goto out; - } - len = ieee->current_network.ssid_len; - wrqu->essid.length = len; - strncpy(b, ieee->current_network.ssid, len); - wrqu->essid.flags = 1; - -out: - spin_unlock_irqrestore(&ieee->lock, flags); - - return ret; -} -EXPORT_SYMBOL(rtllib_wx_get_essid); - -int rtllib_wx_set_rate(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u32 target_rate = wrqu->bitrate.value; - - ieee->rate = target_rate / 100000; - return 0; -} -EXPORT_SYMBOL(rtllib_wx_set_rate); - -int rtllib_wx_get_rate(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u32 tmp_rate; - - tmp_rate = tx_count_to_data_rate(ieee, - ieee->softmac_stats.CurrentShowTxate); - wrqu->bitrate.value = tmp_rate * 500000; - - return 0; -} -EXPORT_SYMBOL(rtllib_wx_get_rate); - -int rtllib_wx_set_rts(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - if (wrqu->rts.disabled || !wrqu->rts.fixed) { - ieee->rts = DEFAULT_RTS_THRESHOLD; - } else { - if (wrqu->rts.value < MIN_RTS_THRESHOLD || - wrqu->rts.value > MAX_RTS_THRESHOLD) - return -EINVAL; - ieee->rts = wrqu->rts.value; - } - return 0; -} -EXPORT_SYMBOL(rtllib_wx_set_rts); - -int rtllib_wx_get_rts(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - wrqu->rts.value = ieee->rts; - wrqu->rts.fixed = 0; /* no auto select */ - wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); - return 0; -} -EXPORT_SYMBOL(rtllib_wx_get_rts); - -int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int set_mode_status = 0; - - rtllib_stop_scan_syncro(ieee); - mutex_lock(&ieee->wx_mutex); - switch (wrqu->mode) { - case IW_MODE_MONITOR: - case IW_MODE_INFRA: - break; - case IW_MODE_AUTO: - wrqu->mode = IW_MODE_INFRA; - break; - default: - set_mode_status = -EINVAL; - goto out; - } - - if (wrqu->mode == ieee->iw_mode) - goto out; - - if (wrqu->mode == IW_MODE_MONITOR) { - ieee->dev->type = ARPHRD_IEEE80211; - rtllib_enable_net_monitor_mode(ieee->dev, false); - } else { - ieee->dev->type = ARPHRD_ETHER; - if (ieee->iw_mode == IW_MODE_MONITOR) - rtllib_disable_net_monitor_mode(ieee->dev, false); - } - - if (!ieee->proto_started) { - ieee->iw_mode = wrqu->mode; - } else { - rtllib_stop_protocol(ieee); - ieee->iw_mode = wrqu->mode; - rtllib_start_protocol(ieee); - } - -out: - mutex_unlock(&ieee->wx_mutex); - return set_mode_status; -} -EXPORT_SYMBOL(rtllib_wx_set_mode); - -void rtllib_wx_sync_scan_wq(void *data) -{ - 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; - int b40M = 0; - - mutex_lock(&ieee->wx_mutex); - if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) { - rtllib_start_scan_syncro(ieee); - goto out; - } - - chan = ieee->current_network.channel; - - ieee->leisure_ps_leave(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); - - rtllib_stop_all_queues(ieee); - ieee->link_state = MAC80211_LINKED_SCANNING; - ieee->link_change(ieee->dev); - /* wait for ps packet to be kicked out successfully */ - msleep(50); - - ieee->scan_operation_backup_handler(ieee->dev, SCAN_OPT_BACKUP); - - if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht && - ieee->ht_info->cur_bw_40mhz) { - b40M = 1; - chan_offset = ieee->ht_info->cur_sta_ext_chnl_offset; - bandwidth = (enum ht_channel_width)ieee->ht_info->cur_bw_40mhz; - ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20, - HT_EXTCHNL_OFFSET_NO_EXT); - } - - rtllib_start_scan_syncro(ieee); - - if (b40M) { - if (chan_offset == HT_EXTCHNL_OFFSET_UPPER) - ieee->set_chan(ieee->dev, chan + 2); - else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER) - ieee->set_chan(ieee->dev, chan - 2); - else - ieee->set_chan(ieee->dev, chan); - ieee->set_bw_mode_handler(ieee->dev, bandwidth, chan_offset); - } else { - ieee->set_chan(ieee->dev, chan); - } - - ieee->scan_operation_backup_handler(ieee->dev, SCAN_OPT_RESTORE); - - ieee->link_state = MAC80211_LINKED; - ieee->link_change(ieee->dev); - - /* Notify AP that I wake up again */ - rtllib_sta_ps_send_null_frame(ieee, 0); - - if (ieee->link_detect_info.num_recv_bcn_in_period == 0 || - ieee->link_detect_info.num_recv_data_in_period == 0) { - ieee->link_detect_info.num_recv_bcn_in_period = 1; - ieee->link_detect_info.num_recv_data_in_period = 1; - } - rtllib_wake_all_queues(ieee); - -out: - mutex_unlock(&ieee->wx_mutex); -} - -int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int ret = 0; - - if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) { - ret = -1; - goto out; - } - - if (ieee->link_state == MAC80211_LINKED) { - schedule_work(&ieee->wx_sync_scan_wq); - /* intentionally forget to up sem */ - return 0; - } - -out: - return ret; -} -EXPORT_SYMBOL(rtllib_wx_set_scan); - -int rtllib_wx_set_essid(struct rtllib_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0, len; - short proto_started; - unsigned long flags; - - rtllib_stop_scan_syncro(ieee); - mutex_lock(&ieee->wx_mutex); - - proto_started = ieee->proto_started; - - len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE); - - if (ieee->iw_mode == IW_MODE_MONITOR) { - ret = -1; - goto out; - } - - if (proto_started) - rtllib_stop_protocol(ieee); - - /* this is just to be sure that the GET wx callback - * has consistent infos. not needed otherwise - */ - spin_lock_irqsave(&ieee->lock, flags); - - if (wrqu->essid.flags && wrqu->essid.length) { - strncpy(ieee->current_network.ssid, extra, len); - ieee->current_network.ssid_len = len; - ieee->cannot_notify = false; - ieee->ssid_set = 1; - } else { - ieee->ssid_set = 0; - ieee->current_network.ssid[0] = '\0'; - ieee->current_network.ssid_len = 0; - } - spin_unlock_irqrestore(&ieee->lock, flags); - - if (proto_started) - rtllib_start_protocol(ieee); -out: - mutex_unlock(&ieee->wx_mutex); - return ret; -} -EXPORT_SYMBOL(rtllib_wx_set_essid); - -int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - wrqu->mode = ieee->iw_mode; - return 0; -} -EXPORT_SYMBOL(rtllib_wx_get_mode); - -int rtllib_wx_get_name(struct rtllib_device *ieee, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - const char *n = ieee->mode & (WIRELESS_MODE_N_24G) ? "n" : ""; - - scnprintf(wrqu->name, sizeof(wrqu->name), "802.11bg%s", n); - return 0; -} -EXPORT_SYMBOL(rtllib_wx_get_name); - -/* this is mostly stolen from hostap */ -int rtllib_wx_set_power(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - - if ((!ieee->sta_wake_up) || - (!ieee->enter_sleep_state) || - (!ieee->ps_is_queue_empty)) { - netdev_warn(ieee->dev, - "%s(): PS mode is tried to be use but driver missed a callback\n", - __func__); - return -1; - } - - mutex_lock(&ieee->wx_mutex); - - if (wrqu->power.disabled) { - ieee->ps = RTLLIB_PS_DISABLED; - goto exit; - } - if (wrqu->power.flags & IW_POWER_TIMEOUT) - ieee->ps_timeout = wrqu->power.value / 1000; - - if (wrqu->power.flags & IW_POWER_PERIOD) - ieee->ps_period = wrqu->power.value / 1000; - - switch (wrqu->power.flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - ieee->ps = RTLLIB_PS_UNICAST; - break; - case IW_POWER_MULTICAST_R: - ieee->ps = RTLLIB_PS_MBCAST; - break; - case IW_POWER_ALL_R: - ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST; - break; - - case IW_POWER_ON: - break; - - default: - ret = -EINVAL; - goto exit; - } -exit: - mutex_unlock(&ieee->wx_mutex); - return ret; -} -EXPORT_SYMBOL(rtllib_wx_set_power); - -/* this is stolen from hostap */ -int rtllib_wx_get_power(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - mutex_lock(&ieee->wx_mutex); - - if (ieee->ps == RTLLIB_PS_DISABLED) { - wrqu->power.disabled = 1; - goto exit; - } - - wrqu->power.disabled = 0; - - if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - wrqu->power.flags = IW_POWER_TIMEOUT; - wrqu->power.value = ieee->ps_timeout * 1000; - } else { - wrqu->power.flags = IW_POWER_PERIOD; - wrqu->power.value = ieee->ps_period * 1000; - } - - if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) == - (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) - wrqu->power.flags |= IW_POWER_ALL_R; - else if (ieee->ps & RTLLIB_PS_MBCAST) - wrqu->power.flags |= IW_POWER_MULTICAST_R; - else - wrqu->power.flags |= IW_POWER_UNICAST_R; - -exit: - mutex_unlock(&ieee->wx_mutex); - return 0; -} -EXPORT_SYMBOL(rtllib_wx_get_power); diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c deleted file mode 100644 index 8e2abd16eb86f0..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ /dev/null @@ -1,901 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * Few modifications for Realtek's Wi-Fi drivers by - * Andrea Merello - * - * A special thanks goes to Realtek for their support ! - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rtllib.h" - -/* 802.11 Data Frame - * - * - * 802.11 frame_control for data frames - 2 bytes - * ,--------------------------------------------------------------------. - * bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | - * |---|---|---|---|---|---|---|---|---|----|----|-----|-----|-----|----| - * val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x | - * |---|---|---|---|---|---|---|---|---|----|----|-----|-----|-----|----| - * desc | ver | type | ^-subtype-^ |to |from|more|retry| pwr |more |wep | - * | | | x=0 data |DS | DS |frag| | mgm |data | | - * | | | x=1 data+ack | | | | | | | | - * '--------------------------------------------------------------------' - * /\ - * | - * 802.11 Data Frame | - * ,--------- 'ctrl' expands to >---' - * | - * ,--'---,-------------------------------------------------------------. - * Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | - * |------|------|---------|---------|---------|------|---------|------| - * Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | - * | | tion | (BSSID) | | | ence | data | | - * `--------------------------------------------------| |------' - * Total: 28 non-data bytes `----.----' - * | - * .- 'Frame data' expands to <---------------------------' - * | - * V - * ,---------------------------------------------------. - * Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | - * |------|------|---------|----------|------|---------| - * Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | - * | DSAP | SSAP | | | | Packet | - * | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | - * `-----------------------------------------| | - * Total: 8 non-data bytes `----.----' - * | - * .- 'IP Packet' expands, if WEP enabled, to <--' - * | - * V - * ,-----------------------. - * Bytes | 4 | 0-2296 | 4 | - * |-----|-----------|-----| - * Desc. | IV | Encrypted | ICV | - * | | IP Packet | | - * `-----------------------' - * Total: 8 non-data bytes - * - * - * 802.3 Ethernet Data Frame - * - * ,-----------------------------------------. - * Bytes | 6 | 6 | 2 | Variable | 4 | - * |-------|-------|------|-----------|------| - * Desc. | Dest. | Source| Type | IP Packet | fcs | - * | MAC | MAC | | | | - * `-----------------------------------------' - * Total: 18 non-data bytes - * - * In the event that fragmentation is required, the incoming payload is split - * into N parts of size ieee->fts. The first fragment contains the SNAP header - * and the remaining packets are just data. - * - * If encryption is enabled, each fragment payload size is reduced by enough - * space to add the prefix and postfix (IV and ICV totalling 8 bytes in - * the case of WEP) So if you have 1500 bytes of payload with ieee->fts set to - * 500 without encryption it will take 3 frames. With WEP it will take 4 frames - * as the payload of each frame is reduced to 492 bytes. - * - * SKB visualization - * - * ,- skb->data - * | - * | ETHERNET HEADER ,-<-- PAYLOAD - * | | 14 bytes from skb->data - * | 2 bytes for Type --> ,T. | (sizeof ethhdr) - * | | | | - * |,-Dest.--. ,--Src.---. | | | - * | 6 bytes| | 6 bytes | | | | - * v | | | | | | - * 0 | v 1 | v | v 2 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * ^ | ^ | ^ | - * | | | | | | - * | | | | `T' <---- 2 bytes for Type - * | | | | - * | | '---SNAP--' <-------- 6 bytes for SNAP - * | | - * `-IV--' <-------------------- 4 bytes for IV (WEP) - * - * SNAP HEADER - * - */ - -static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; -static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; - -static int rtllib_put_snap(u8 *data, u16 h_proto) -{ - struct rtllib_snap_hdr *snap; - u8 *oui; - - snap = (struct rtllib_snap_hdr *)data; - snap->dsap = 0xaa; - snap->ssap = 0xaa; - snap->ctrl = 0x03; - - if (h_proto == 0x8137 || h_proto == 0x80f3) - oui = P802_1H_OUI; - else - oui = RFC1042_OUI; - snap->oui[0] = oui[0]; - snap->oui[1] = oui[1]; - snap->oui[2] = oui[2]; - - *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); - - return SNAP_SIZE + sizeof(u16); -} - -int rtllib_encrypt_fragment(struct rtllib_device *ieee, struct sk_buff *frag, - int hdr_len) -{ - struct lib80211_crypt_data *crypt = NULL; - int res; - - crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; - - if (!(crypt && crypt->ops)) { - netdev_info(ieee->dev, "=========>%s(), crypt is null\n", - __func__); - return -1; - } - /* To encrypt, frame format is: - * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) - */ - - /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so - * call both MSDU and MPDU encryption functions from here. - */ - atomic_inc(&crypt->refcnt); - res = 0; - if (crypt->ops->encrypt_msdu) - res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); - if (res == 0 && crypt->ops->encrypt_mpdu) - res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); - - atomic_dec(&crypt->refcnt); - if (res < 0) { - netdev_info(ieee->dev, "%s: Encryption failed: len=%d.\n", - ieee->dev->name, frag->len); - return -1; - } - - return 0; -} - -void rtllib_txb_free(struct rtllib_txb *txb) -{ - if (unlikely(!txb)) - return; - kfree(txb); -} - -static struct rtllib_txb *rtllib_alloc_txb(int nr_frags, int txb_size, - gfp_t gfp_mask) -{ - struct rtllib_txb *txb; - int i; - - txb = kzalloc(struct_size(txb, fragments, nr_frags), gfp_mask); - if (!txb) - return NULL; - - txb->nr_frags = nr_frags; - txb->frag_size = cpu_to_le16(txb_size); - - for (i = 0; i < nr_frags; i++) { - txb->fragments[i] = dev_alloc_skb(txb_size); - if (unlikely(!txb->fragments[i])) - goto err_free; - memset(txb->fragments[i]->cb, 0, sizeof(txb->fragments[i]->cb)); - } - - return txb; - -err_free: - while (--i >= 0) - dev_kfree_skb_any(txb->fragments[i]); - kfree(txb); - - return NULL; -} - -static int rtllib_classify(struct sk_buff *skb) -{ - struct ethhdr *eth; - struct iphdr *ip; - - eth = (struct ethhdr *)skb->data; - if (eth->h_proto != htons(ETH_P_IP)) - return 0; - -#ifdef VERBOSE_DEBUG - print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE, skb->data, - skb->len); -#endif - ip = ip_hdr(skb); - switch (ip->tos & 0xfc) { - case 0x20: - return 2; - case 0x40: - return 1; - case 0x60: - return 3; - case 0x80: - return 4; - case 0xa0: - return 5; - case 0xc0: - return 6; - case 0xe0: - return 7; - default: - return 0; - } -} - -static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee, - struct sk_buff *skb, - struct cb_desc *tcb_desc) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - struct tx_ts_record *ts = NULL; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - - if (rtllib_act_scanning(ieee, false)) - return; - - if (!ht_info->current_ht_support || !ht_info->enable_ht) - return; - if (!is_qos_data_frame(skb->data)) - return; - if (is_multicast_ether_addr(hdr->addr1)) - return; - - if (tcb_desc->bdhcp || ieee->cnt_after_link < 2) - return; - - if (ht_info->iot_action & HT_IOT_ACT_TX_NO_AGGREGATION) - return; - - if (!ieee->get_nmode_support_by_sec_cfg(ieee->dev)) - return; - if (ht_info->current_ampdu_enable) { - if (!rtllib_get_ts(ieee, (struct ts_common_info **)(&ts), hdr->addr1, - skb->priority, TX_DIR, true)) { - netdev_info(ieee->dev, "%s: can't get TS\n", __func__); - return; - } - if (!ts->tx_admitted_ba_record.b_valid) { - if (ieee->wpa_ie_len && (ieee->pairwise_key_type == - KEY_TYPE_NA)) { - ; - } else if (tcb_desc->bdhcp == 1) { - ; - } else if (!ts->disable_add_ba) { - rtllib_ts_start_add_ba_process(ieee, ts); - } - return; - } else if (!ts->using_ba) { - if (SN_LESS(ts->tx_admitted_ba_record.ba_start_seq_ctrl.field.seq_num, - (ts->tx_cur_seq + 1) % 4096)) - ts->using_ba = true; - else - return; - } - if (ieee->iw_mode == IW_MODE_INFRA) { - tcb_desc->ampdu_enable = true; - tcb_desc->ampdu_factor = ht_info->current_ampdu_factor; - tcb_desc->ampdu_density = ht_info->current_mpdu_density; - } - } -} - -static void rtllib_query_short_preamble_mode(struct rtllib_device *ieee, - struct cb_desc *tcb_desc) -{ - tcb_desc->use_short_preamble = false; - if (tcb_desc->data_rate == 2) - return; - else if (ieee->current_network.capability & - WLAN_CAPABILITY_SHORT_PREAMBLE) - tcb_desc->use_short_preamble = true; -} - -static void rtllib_query_ht_cap_short_gi(struct rtllib_device *ieee, - struct cb_desc *tcb_desc) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - - tcb_desc->use_short_gi = false; - - if (!ht_info->current_ht_support || !ht_info->enable_ht) - return; - - if (ht_info->cur_bw_40mhz && ht_info->cur_short_gi_40mhz) - tcb_desc->use_short_gi = true; - else if (!ht_info->cur_bw_40mhz && ht_info->cur_short_gi_20mhz) - tcb_desc->use_short_gi = true; -} - -static void rtllib_query_bandwidth_mode(struct rtllib_device *ieee, - struct cb_desc *tcb_desc) -{ - struct rt_hi_throughput *ht_info = ieee->ht_info; - - tcb_desc->packet_bw = false; - - if (!ht_info->current_ht_support || !ht_info->enable_ht) - return; - - if (tcb_desc->multicast || tcb_desc->broadcast) - return; - - if ((tcb_desc->data_rate & 0x80) == 0) - return; - if (ht_info->cur_bw_40mhz && ht_info->cur_tx_bw40mhz && - !ieee->bandwidth_auto_switch.forced_tx_20MHz) - tcb_desc->packet_bw = true; -} - -static void rtllib_query_protectionmode(struct rtllib_device *ieee, - struct cb_desc *tcb_desc, - struct sk_buff *skb) -{ - struct rt_hi_throughput *ht_info; - - tcb_desc->rtsstbc = false; - tcb_desc->rts_use_short_gi = false; - tcb_desc->cts_enable = false; - tcb_desc->RTSSC = 0; - tcb_desc->rts_bw = false; - - if (tcb_desc->broadcast || tcb_desc->multicast) - return; - - if (is_broadcast_ether_addr(skb->data + 16)) - return; - - if (ieee->mode < WIRELESS_MODE_N_24G) { - if (skb->len > ieee->rts) { - tcb_desc->rts_enable = true; - tcb_desc->rts_rate = MGN_24M; - } else if (ieee->current_network.buseprotection) { - tcb_desc->rts_enable = true; - tcb_desc->cts_enable = true; - tcb_desc->rts_rate = MGN_24M; - } - return; - } - - ht_info = ieee->ht_info; - - while (true) { - if (ht_info->iot_action & HT_IOT_ACT_FORCED_CTS2SELF) { - tcb_desc->cts_enable = true; - tcb_desc->rts_rate = MGN_24M; - tcb_desc->rts_enable = true; - break; - } else if (ht_info->iot_action & (HT_IOT_ACT_FORCED_RTS | - HT_IOT_ACT_PURE_N_MODE)) { - tcb_desc->rts_enable = true; - tcb_desc->rts_rate = MGN_24M; - break; - } - if (ieee->current_network.buseprotection) { - tcb_desc->rts_enable = true; - tcb_desc->cts_enable = true; - tcb_desc->rts_rate = MGN_24M; - break; - } - if (ht_info->current_ht_support && ht_info->enable_ht) { - u8 ht_op_mode = ht_info->current_op_mode; - - if ((ht_info->cur_bw_40mhz && (ht_op_mode == 2 || - ht_op_mode == 3)) || - (!ht_info->cur_bw_40mhz && ht_op_mode == 3)) { - tcb_desc->rts_rate = MGN_24M; - tcb_desc->rts_enable = true; - break; - } - } - if (skb->len > ieee->rts) { - tcb_desc->rts_rate = MGN_24M; - tcb_desc->rts_enable = true; - break; - } - if (tcb_desc->ampdu_enable) { - tcb_desc->rts_rate = MGN_24M; - tcb_desc->rts_enable = false; - break; - } - goto NO_PROTECTION; - } - if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - tcb_desc->use_short_preamble = true; - return; -NO_PROTECTION: - tcb_desc->rts_enable = false; - tcb_desc->cts_enable = false; - tcb_desc->rts_rate = 0; - tcb_desc->RTSSC = 0; - tcb_desc->rts_bw = false; -} - -static void rtllib_txrate_selectmode(struct rtllib_device *ieee, - struct cb_desc *tcb_desc) -{ - if (ieee->tx_dis_rate_fallback) - tcb_desc->tx_dis_rate_fallback = true; - - if (ieee->tx_use_drv_assinged_rate) - tcb_desc->tx_use_drv_assinged_rate = true; - if (!tcb_desc->tx_dis_rate_fallback || - !tcb_desc->tx_use_drv_assinged_rate) { - if (ieee->iw_mode == IW_MODE_INFRA) - tcb_desc->ratr_index = 0; - } -} - -static u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb, - u8 *dst) -{ - u16 seqnum = 0; - - if (is_multicast_ether_addr(dst)) - return 0; - if (is_qos_data_frame(skb->data)) { - struct tx_ts_record *ts = NULL; - - if (!rtllib_get_ts(ieee, (struct ts_common_info **)(&ts), dst, - skb->priority, TX_DIR, true)) - return 0; - seqnum = ts->tx_cur_seq; - ts->tx_cur_seq = (ts->tx_cur_seq + 1) % 4096; - return seqnum; - } - return 0; -} - -static int wme_downgrade_ac(struct sk_buff *skb) -{ - switch (skb->priority) { - case 6: - case 7: - skb->priority = 5; /* VO -> VI */ - return 0; - case 4: - case 5: - skb->priority = 3; /* VI -> BE */ - return 0; - case 0: - case 3: - skb->priority = 1; /* BE -> BK */ - return 0; - default: - return -1; - } -} - -static u8 rtllib_current_rate(struct rtllib_device *ieee) -{ - if (ieee->mode & IEEE_MODE_MASK) - return ieee->rate; - - if (ieee->ht_curr_op_rate) - return ieee->ht_curr_op_rate; - else - return ieee->rate & 0x7F; -} - -static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) -{ - struct rtllib_device *ieee = (struct rtllib_device *) - netdev_priv_rsl(dev); - struct rtllib_txb *txb = NULL; - struct ieee80211_qos_hdr *frag_hdr; - int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; - unsigned long flags; - struct net_device_stats *stats = &ieee->stats; - int ether_type = 0, encrypt; - int bytes, fc, qos_ctl = 0, hdr_len; - struct sk_buff *skb_frag; - struct ieee80211_qos_hdr header = { /* Ensure zero initialized */ - .duration_id = 0, - .seq_ctrl = 0, - .qos_ctrl = 0 - }; - int qos_activated = ieee->current_network.qos_data.active; - u8 dest[ETH_ALEN]; - u8 src[ETH_ALEN]; - struct lib80211_crypt_data *crypt = NULL; - struct cb_desc *tcb_desc; - u8 is_multicast = false; - bool bdhcp = false; - - spin_lock_irqsave(&ieee->lock, flags); - - /* If there is no driver handler to take the TXB, don't bother - * creating it... - */ - if (!(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) || - ((!ieee->softmac_data_hard_start_xmit && - (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { - netdev_warn(ieee->dev, "No xmit handler.\n"); - goto success; - } - - if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { - netdev_warn(ieee->dev, "skb too small (%d).\n", - skb->len); - goto success; - } - /* Save source and destination addresses */ - ether_addr_copy(dest, skb->data); - ether_addr_copy(src, skb->data + ETH_ALEN); - - memset(skb->cb, 0, sizeof(skb->cb)); - ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); - - if (ieee->iw_mode == IW_MODE_MONITOR) { - txb = rtllib_alloc_txb(1, skb->len, GFP_ATOMIC); - if (unlikely(!txb)) { - netdev_warn(ieee->dev, - "Could not allocate TXB\n"); - goto failed; - } - - txb->encrypted = 0; - txb->payload_size = cpu_to_le16(skb->len); - skb_put_data(txb->fragments[0], skb->data, skb->len); - - goto success; - } - - if (skb->len > 282) { - if (ether_type == ETH_P_IP) { - const struct iphdr *ip = (struct iphdr *) - ((u8 *)skb->data + 14); - if (ip->protocol == IPPROTO_UDP) { - struct udphdr *udp; - - udp = (struct udphdr *)((u8 *)ip + - (ip->ihl << 2)); - if (((((u8 *)udp)[1] == 68) && - (((u8 *)udp)[3] == 67)) || - ((((u8 *)udp)[1] == 67) && - (((u8 *)udp)[3] == 68))) { - bdhcp = true; - ieee->lps_delay_cnt = 200; - } - } - } else if (ether_type == ETH_P_ARP) { - netdev_info(ieee->dev, - "=================>DHCP Protocol start tx ARP pkt!!\n"); - bdhcp = true; - ieee->lps_delay_cnt = - ieee->current_network.tim.tim_count; - } - } - - skb->priority = rtllib_classify(skb); - crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; - encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && crypt && crypt->ops; - if (!encrypt && ieee->ieee802_1x && - ieee->drop_unencrypted && ether_type != ETH_P_PAE) { - stats->tx_dropped++; - goto success; - } - if (crypt && !encrypt && ether_type == ETH_P_PAE) { - struct eapol *eap = (struct eapol *)(skb->data + - sizeof(struct ethhdr) - SNAP_SIZE - - sizeof(u16)); - netdev_dbg(ieee->dev, - "TX: IEEE 802.11 EAPOL frame: %s\n", - eap_get_type(eap->type)); - } - - /* Advance the SKB to the start of the payload */ - skb_pull(skb, sizeof(struct ethhdr)); - - /* Determine total amount of storage required for TXB packets */ - bytes = skb->len + SNAP_SIZE + sizeof(u16); - - if (encrypt) - fc = RTLLIB_FTYPE_DATA | IEEE80211_FCTL_PROTECTED; - else - fc = RTLLIB_FTYPE_DATA; - - if (qos_activated) - fc |= IEEE80211_STYPE_QOS_DATA; - else - fc |= IEEE80211_STYPE_DATA; - - if (ieee->iw_mode == IW_MODE_INFRA) { - fc |= IEEE80211_FCTL_TODS; - /* To DS: Addr1 = BSSID, Addr2 = SA, - * Addr3 = DA - */ - ether_addr_copy(header.addr1, - ieee->current_network.bssid); - ether_addr_copy(header.addr2, src); - ether_addr_copy(header.addr3, dest); - } - - is_multicast = is_multicast_ether_addr(header.addr1); - - header.frame_control = cpu_to_le16(fc); - - /* Determine fragmentation size based on destination (multicast - * and broadcast are not fragmented) - */ - if (is_multicast) { - frag_size = MAX_FRAG_THRESHOLD; - qos_ctl |= QOS_CTL_NOTCONTAIN_ACK; - } else { - frag_size = ieee->fts; - qos_ctl = 0; - } - - if (qos_activated) { - hdr_len = RTLLIB_3ADDR_LEN + 2; - - /* in case we are a client verify acm is not set for this ac */ - while (unlikely(ieee->wmm_acm & (0x01 << skb->priority))) { - netdev_info(ieee->dev, "skb->priority = %x\n", - skb->priority); - if (wme_downgrade_ac(skb)) - break; - netdev_info(ieee->dev, "converted skb->priority = %x\n", - skb->priority); - } - - qos_ctl |= skb->priority; - header.qos_ctrl = cpu_to_le16(qos_ctl & RTLLIB_QOS_TID); - - } else { - hdr_len = RTLLIB_3ADDR_LEN; - } - /* Determine amount of payload per fragment. Regardless of if - * this stack is providing the full 802.11 header, one will - * eventually be affixed to this fragment -- so we must account - * for it when determining the amount of payload space. - */ - bytes_per_frag = frag_size - hdr_len; - if (ieee->config & - (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS)) - bytes_per_frag -= RTLLIB_FCS_LEN; - - /* Each fragment may need to have room for encrypting - * pre/postfix - */ - if (encrypt) { - bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len + - crypt->ops->extra_mpdu_postfix_len + - crypt->ops->extra_msdu_prefix_len + - crypt->ops->extra_msdu_postfix_len; - } - /* Number of fragments is the total bytes_per_frag / - * payload_per_fragment - */ - nr_frags = bytes / bytes_per_frag; - bytes_last_frag = bytes % bytes_per_frag; - if (bytes_last_frag) - nr_frags++; - else - bytes_last_frag = bytes_per_frag; - - /* When we allocate the TXB we allocate enough space for the - * reserve and full fragment bytes (bytes_per_frag doesn't - * include prefix, postfix, header, FCS, etc.) - */ - txb = rtllib_alloc_txb(nr_frags, frag_size + - ieee->tx_headroom, GFP_ATOMIC); - if (unlikely(!txb)) { - netdev_warn(ieee->dev, "Could not allocate TXB\n"); - goto failed; - } - txb->encrypted = encrypt; - txb->payload_size = cpu_to_le16(bytes); - - if (qos_activated) - txb->queue_index = UP2AC(skb->priority); - else - txb->queue_index = WME_AC_BE; - - for (i = 0; i < nr_frags; i++) { - skb_frag = txb->fragments[i]; - tcb_desc = (struct cb_desc *)(skb_frag->cb + - MAX_DEV_ADDR_SIZE); - if (qos_activated) { - skb_frag->priority = skb->priority; - tcb_desc->queue_index = UP2AC(skb->priority); - } else { - skb_frag->priority = WME_AC_BE; - tcb_desc->queue_index = WME_AC_BE; - } - skb_reserve(skb_frag, ieee->tx_headroom); - - if (encrypt) { - if (ieee->hwsec_active) - tcb_desc->hw_sec = 1; - else - tcb_desc->hw_sec = 0; - skb_reserve(skb_frag, - crypt->ops->extra_mpdu_prefix_len + - crypt->ops->extra_msdu_prefix_len); - } else { - tcb_desc->hw_sec = 0; - } - frag_hdr = skb_put_data(skb_frag, &header, hdr_len); - - /* If this is not the last fragment, then add the - * MOREFRAGS bit to the frame control - */ - if (i != nr_frags - 1) { - frag_hdr->frame_control = cpu_to_le16(fc | - IEEE80211_FCTL_MOREFRAGS); - bytes = bytes_per_frag; - - } else { - /* The last fragment has the remaining length */ - bytes = bytes_last_frag; - } - if ((qos_activated) && (!is_multicast)) { - frag_hdr->seq_ctrl = - cpu_to_le16(rtllib_query_seqnum(ieee, skb_frag, - header.addr1)); - frag_hdr->seq_ctrl = - cpu_to_le16(le16_to_cpu(frag_hdr->seq_ctrl) << 4 | i); - } else { - frag_hdr->seq_ctrl = - cpu_to_le16(ieee->seq_ctrl[0] << 4 | i); - } - /* Put a SNAP header on the first fragment */ - if (i == 0) { - rtllib_put_snap(skb_put(skb_frag, - SNAP_SIZE + - sizeof(u16)), ether_type); - bytes -= SNAP_SIZE + sizeof(u16); - } - - skb_put_data(skb_frag, skb->data, bytes); - - /* Advance the SKB... */ - skb_pull(skb, bytes); - - /* Encryption routine will move the header forward in - * order to insert the IV between the header and the - * payload - */ - if (encrypt) - rtllib_encrypt_fragment(ieee, skb_frag, - hdr_len); - if (ieee->config & - (CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS)) - skb_put(skb_frag, 4); - } - - if ((qos_activated) && (!is_multicast)) { - if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF) - ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0; - else - ieee->seq_ctrl[UP2AC(skb->priority) + 1]++; - } else { - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - } - - success: - if (txb) { - tcb_desc = (struct cb_desc *) - (txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE); - tcb_desc->tx_enable_fw_calc_dur = 1; - tcb_desc->priority = skb->priority; - - if (ether_type == ETH_P_PAE) { - if (ieee->ht_info->iot_action & - HT_IOT_ACT_WA_IOT_Broadcom) { - tcb_desc->data_rate = - mgnt_query_tx_rate_exclude_cck_rates(ieee); - tcb_desc->tx_dis_rate_fallback = false; - } else { - tcb_desc->data_rate = ieee->basic_rate; - tcb_desc->tx_dis_rate_fallback = 1; - } - - tcb_desc->ratr_index = 7; - tcb_desc->tx_use_drv_assinged_rate = 1; - } else { - if (is_multicast_ether_addr(header.addr1)) - tcb_desc->multicast = 1; - if (is_broadcast_ether_addr(header.addr1)) - tcb_desc->broadcast = 1; - rtllib_txrate_selectmode(ieee, tcb_desc); - if (tcb_desc->multicast || tcb_desc->broadcast) - tcb_desc->data_rate = ieee->basic_rate; - else - tcb_desc->data_rate = rtllib_current_rate(ieee); - - if (bdhcp) { - if (ieee->ht_info->iot_action & - HT_IOT_ACT_WA_IOT_Broadcom) { - tcb_desc->data_rate = - mgnt_query_tx_rate_exclude_cck_rates(ieee); - tcb_desc->tx_dis_rate_fallback = false; - } else { - tcb_desc->data_rate = MGN_1M; - tcb_desc->tx_dis_rate_fallback = 1; - } - - tcb_desc->ratr_index = 7; - tcb_desc->tx_use_drv_assinged_rate = 1; - tcb_desc->bdhcp = 1; - } - - rtllib_query_short_preamble_mode(ieee, tcb_desc); - rtllib_tx_query_agg_cap(ieee, txb->fragments[0], - tcb_desc); - rtllib_query_ht_cap_short_gi(ieee, tcb_desc); - rtllib_query_bandwidth_mode(ieee, tcb_desc); - rtllib_query_protectionmode(ieee, tcb_desc, - txb->fragments[0]); - } - } - spin_unlock_irqrestore(&ieee->lock, flags); - dev_kfree_skb_any(skb); - if (txb) { - if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) { - dev->stats.tx_packets++; - dev->stats.tx_bytes += le16_to_cpu(txb->payload_size); - rtllib_softmac_xmit(txb, ieee); - } else { - rtllib_txb_free(txb); - } - } - - return 0; - - failed: - spin_unlock_irqrestore(&ieee->lock, flags); - netif_stop_queue(dev); - stats->tx_errors++; - return 1; -} - -netdev_tx_t rtllib_xmit(struct sk_buff *skb, struct net_device *dev) -{ - memset(skb->cb, 0, sizeof(skb->cb)); - return rtllib_xmit_inter(skb, dev) ? NETDEV_TX_BUSY : NETDEV_TX_OK; -} -EXPORT_SYMBOL(rtllib_xmit); diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c deleted file mode 100644 index c730d921463dd4..00000000000000 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ /dev/null @@ -1,752 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright(c) 2004 Intel Corporation. All rights reserved. - * - * Portions of this file are based on the WEP enablement code provided by the - * Host AP project hostap-drivers v0.1.3 - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - */ -#include -#include -#include -#include -#include "rtllib.h" - -static const char * const rtllib_modes[] = { - "a", "b", "g", "?", "N-24G" -}; - -#define MAX_CUSTOM_LEN 64 -static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, - char *start, char *stop, - struct rtllib_network *network, - struct iw_request_info *info) -{ - char custom[MAX_CUSTOM_LEN]; - char proto_name[6]; - char *pname = proto_name; - char *p; - struct iw_event iwe; - int i, j; - u16 max_rate, rate; - static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; - - /* First entry *MUST* be the AP MAC address */ - 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(info, start, stop, &iwe, IW_EV_ADDR_LEN); - /* Remaining entries will be displayed in the order we provide them */ - - /* Add the ESSID */ - iwe.cmd = SIOCGIWESSID; - 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(info, start, stop, &iwe, network->ssid); - } else if (network->hidden_ssid_len == 0) { - iwe.u.data.length = sizeof(""); - 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(info, start, stop, &iwe, network->hidden_ssid); - } - /* Add the protocol name */ - iwe.cmd = SIOCGIWNAME; - for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) { - if (network->mode & BIT(i)) { - strcpy(pname, rtllib_modes[i]); - pname += strlen(rtllib_modes[i]); - } - } - *pname = '\0'; - snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name); - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - if (network->capability & - (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { - if (network->capability & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); - } - - /* Add frequency/channel */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = network->channel; - iwe.u.freq.e = 0; - iwe.u.freq.i = 0; - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (network->capability & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); - /* Add basic and extended rates */ - max_rate = 0; - p = custom; - p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); - for (i = 0, j = 0; i < network->rates_len;) { - if (j < network->rates_ex_len && - ((network->rates_ex[j] & 0x7F) < - (network->rates[i] & 0x7F))) - rate = network->rates_ex[j++] & 0x7F; - else - rate = network->rates[i++] & 0x7F; - if (rate > max_rate) - max_rate = rate; - p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), - "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); - } - for (; j < network->rates_ex_len; j++) { - rate = network->rates_ex[j] & 0x7F; - p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), - "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); - if (rate > max_rate) - max_rate = rate; - } - - if (network->mode >= WIRELESS_MODE_N_24G) { - struct ht_capab_ele *ht_cap = NULL; - bool is40M = false, isShortGI = false; - u8 max_mcs = 0; - - if (!memcmp(network->bssht.bd_ht_cap_buf, EWC11NHTCap, 4)) - ht_cap = (struct ht_capab_ele *) - &network->bssht.bd_ht_cap_buf[4]; - else - ht_cap = (struct ht_capab_ele *) - &network->bssht.bd_ht_cap_buf[0]; - is40M = (ht_cap->chl_width) ? 1 : 0; - isShortGI = (ht_cap->chl_width) ? - ((ht_cap->short_gi_40mhz) ? 1 : 0) : - ((ht_cap->short_gi_20mhz) ? 1 : 0); - - max_mcs = ht_get_highest_mcs_rate(ieee, ht_cap->MCS, - MCS_FILTER_ALL); - rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f]; - if (rate > max_rate) - max_rate = rate; - } - iwe.cmd = SIOCGIWRATE; - iwe.u.bitrate.disabled = 0; - iwe.u.bitrate.fixed = 0; - iwe.u.bitrate.value = max_rate * 500000; - 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(info, start, stop, &iwe, custom); - /* Add quality statistics */ - /* TODO: Fix these values... */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = network->stats.signal; - iwe.u.qual.level = network->stats.rssi; - iwe.u.qual.noise = network->stats.noise; - iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK; - if (!(network->stats.mask & RTLLIB_STATMASK_RSSI)) - iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; - if (!(network->stats.mask & RTLLIB_STATMASK_NOISE)) - iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; - 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(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(info, start, stop, &iwe, custom); - - memset(&iwe, 0, sizeof(iwe)); - if (network->wpa_ie_len) { - char buf[MAX_WPA_IE_LEN]; - - 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(info, start, stop, &iwe, buf); - } - memset(&iwe, 0, sizeof(iwe)); - if (network->rsn_ie_len) { - char buf[MAX_WPA_IE_LEN]; - - 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(info, start, stop, &iwe, buf); - } - - /* add info for WZC */ - memset(&iwe, 0, sizeof(iwe)); - if (network->wzc_ie_len) { - char buf[MAX_WZC_IE_LEN]; - - 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(info, start, stop, &iwe, buf); - } - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. - */ - iwe.cmd = IWEVCUSTOM; - p = custom; - p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), - " Last beacon: %lums ago", - (100 * (jiffies - network->last_scanned)) / HZ); - iwe.u.data.length = p - custom; - if (iwe.u.data.length) - start = iwe_stream_add_point(info, start, stop, &iwe, custom); - - return start; -} - -int rtllib_wx_get_scan(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct rtllib_network *network; - unsigned long flags; - - char *ev = extra; - char *stop = ev + wrqu->data.length; - int i = 0; - int err = 0; - - netdev_dbg(ieee->dev, "Getting scan\n"); - mutex_lock(&ieee->wx_mutex); - spin_lock_irqsave(&ieee->lock, flags); - - list_for_each_entry(network, &ieee->network_list, list) { - i++; - if ((stop - ev) < 200) { - err = -E2BIG; - break; - } - if (ieee->scan_age == 0 || - time_after(network->last_scanned + ieee->scan_age, jiffies)) - ev = rtl819x_translate_scan(ieee, ev, stop, network, - info); - else - netdev_dbg(ieee->dev, - "Network '%s ( %pM)' hidden due to age (%lums).\n", - escape_essid(network->ssid, - network->ssid_len), - network->bssid, - (100 * (jiffies - network->last_scanned)) / - HZ); - } - - spin_unlock_irqrestore(&ieee->lock, flags); - mutex_unlock(&ieee->wx_mutex); - wrqu->data.length = ev - extra; - wrqu->data.flags = 0; - - netdev_dbg(ieee->dev, "%s(): %d networks returned.\n", __func__, i); - - return err; -} -EXPORT_SYMBOL(rtllib_wx_get_scan); - -int rtllib_wx_set_encode(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - struct net_device *dev = ieee->dev; - struct rtllib_security sec = { - .flags = 0 - }; - int i, key, key_provided, len; - struct lib80211_crypt_data **crypt; - - key = erq->flags & IW_ENCODE_INDEX; - if (key) { - if (key > NUM_WEP_KEYS) - return -EINVAL; - key--; - key_provided = 1; - } else { - key_provided = 0; - key = ieee->crypt_info.tx_keyidx; - } - - netdev_dbg(ieee->dev, "Key: %d [%s]\n", key, key_provided ? - "provided" : "default"); - crypt = &ieee->crypt_info.crypt[key]; - if (erq->flags & IW_ENCODE_DISABLED) { - if (key_provided && *crypt) { - netdev_dbg(ieee->dev, - "Disabling encryption on key %d.\n", key); - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); - } else { - netdev_dbg(ieee->dev, "Disabling encryption.\n"); - } - - /* Check all the keys to see if any are still configured, - * and if no key index was provided, de-init them all - */ - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ieee->crypt_info.crypt[i]) { - if (key_provided) - break; - lib80211_crypt_delayed_deinit(&ieee->crypt_info, - &ieee->crypt_info.crypt[i]); - } - } - - if (i == NUM_WEP_KEYS) { - sec.enabled = 0; - sec.level = SEC_LEVEL_0; - sec.flags |= SEC_ENABLED | SEC_LEVEL; - } - - goto done; - } - - sec.enabled = 1; - sec.flags |= SEC_ENABLED; - - if (*crypt && (*crypt)->ops && - strcmp((*crypt)->ops->name, "R-WEP") != 0) { - /* changing to use WEP; deinit previously used algorithm - * on this key - */ - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); - } - - if (!*crypt) { - struct lib80211_crypt_data *new_crypt; - - /* take WEP into use */ - new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); - if (!new_crypt) - return -ENOMEM; - new_crypt->ops = lib80211_get_crypto_ops("R-WEP"); - if (!new_crypt->ops) { - request_module("rtllib_crypt_wep"); - new_crypt->ops = lib80211_get_crypto_ops("R-WEP"); - } - - if (new_crypt->ops) - new_crypt->priv = new_crypt->ops->init(key); - - if (!new_crypt->ops || !new_crypt->priv) { - kfree(new_crypt); - new_crypt = NULL; - - netdev_warn(dev, - "%s: could not initialize WEP: load module rtllib_crypt_wep\n", - dev->name); - return -EOPNOTSUPP; - } - *crypt = new_crypt; - } - - /* If a new key was provided, set it up */ - if (erq->length > 0) { - len = erq->length <= 5 ? 5 : 13; - memcpy(sec.keys[key], keybuf, erq->length); - if (len > erq->length) - memset(sec.keys[key] + erq->length, 0, - len - erq->length); - netdev_dbg(ieee->dev, "Setting key %d to '%s' (%d:%d bytes)\n", - key, escape_essid(sec.keys[key], len), erq->length, - len); - sec.key_sizes[key] = len; - (*crypt)->ops->set_key(sec.keys[key], len, NULL, - (*crypt)->priv); - sec.flags |= (1 << key); - /* This ensures a key will be activated if no key is - * explicitly set - */ - if (key == sec.active_key) - sec.flags |= SEC_ACTIVE_KEY; - ieee->crypt_info.tx_keyidx = key; - - } else { - len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, - NULL, (*crypt)->priv); - if (len == 0) { - /* Set a default key of all 0 */ - netdev_info(ieee->dev, "Setting key %d to all zero.\n", key); - - memset(sec.keys[key], 0, 13); - (*crypt)->ops->set_key(sec.keys[key], 13, NULL, - (*crypt)->priv); - sec.key_sizes[key] = 13; - sec.flags |= (1 << key); - } - - /* No key data - just set the default TX key index */ - if (key_provided) { - netdev_dbg(ieee->dev, - "Setting key %d as default Tx key.\n", key); - ieee->crypt_info.tx_keyidx = key; - sec.active_key = key; - sec.flags |= SEC_ACTIVE_KEY; - } - } - done: - ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); - ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : - WLAN_AUTH_SHARED_KEY; - sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; - sec.flags |= SEC_AUTH_MODE; - netdev_dbg(ieee->dev, "Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? - "OPEN" : "SHARED KEY"); - - /* For now we just support WEP, so only set that security level... - * TODO: When WPA is added this is one place that needs to change - */ - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ - return 0; -} -EXPORT_SYMBOL(rtllib_wx_set_encode); - -int rtllib_wx_get_encode(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct iw_point *erq = &wrqu->encoding; - int len, key; - struct lib80211_crypt_data *crypt; - - if (ieee->iw_mode == IW_MODE_MONITOR) - return -1; - - key = erq->flags & IW_ENCODE_INDEX; - if (key) { - if (key > NUM_WEP_KEYS) - return -EINVAL; - key--; - } else { - key = ieee->crypt_info.tx_keyidx; - } - crypt = ieee->crypt_info.crypt[key]; - - erq->flags = key + 1; - - if (!crypt || !crypt->ops) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv); - - erq->length = max(len, 0); - - erq->flags |= IW_ENCODE_ENABLED; - - if (ieee->open_wep) - erq->flags |= IW_ENCODE_OPEN; - else - erq->flags |= IW_ENCODE_RESTRICTED; - - return 0; -} -EXPORT_SYMBOL(rtllib_wx_get_encode); - -int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - struct net_device *dev = ieee->dev; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int i, idx; - int group_key = 0; - const char *alg, *module; - const struct lib80211_crypto_ops *ops; - struct lib80211_crypt_data **crypt; - - struct rtllib_security sec = { - .flags = 0, - }; - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (idx < 1 || idx > NUM_WEP_KEYS) - return -EINVAL; - idx--; - } else { - idx = ieee->crypt_info.tx_keyidx; - } - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - crypt = &ieee->crypt_info.crypt[idx]; - group_key = 1; - } else { - /* some Cisco APs use idx>0 for unicast in dynamic WEP */ - if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) - return -EINVAL; - if (ieee->iw_mode == IW_MODE_INFRA) - crypt = &ieee->crypt_info.crypt[idx]; - else - return -EINVAL; - } - - sec.flags |= SEC_ENABLED; - if ((encoding->flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE) { - if (*crypt) - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); - - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ieee->crypt_info.crypt[i]) - break; - } - if (i == NUM_WEP_KEYS) { - sec.enabled = 0; - sec.level = SEC_LEVEL_0; - sec.flags |= SEC_LEVEL; - } - goto done; - } - - sec.enabled = 1; - switch (ext->alg) { - case IW_ENCODE_ALG_WEP: - alg = "R-WEP"; - module = "rtllib_crypt_wep"; - break; - case IW_ENCODE_ALG_TKIP: - alg = "R-TKIP"; - module = "rtllib_crypt_tkip"; - break; - case IW_ENCODE_ALG_CCMP: - alg = "R-CCMP"; - module = "rtllib_crypt_ccmp"; - break; - default: - netdev_dbg(ieee->dev, "Unknown crypto alg %d\n", ext->alg); - ret = -EINVAL; - goto done; - } - netdev_dbg(dev, "alg name:%s\n", alg); - - ops = lib80211_get_crypto_ops(alg); - if (!ops) { - char tempbuf[100]; - - memset(tempbuf, 0x00, 100); - sprintf(tempbuf, "%s", module); - request_module("%s", tempbuf); - ops = lib80211_get_crypto_ops(alg); - } - if (!ops) { - netdev_info(dev, "========>unknown crypto alg %d\n", ext->alg); - ret = -EINVAL; - goto done; - } - - if (!*crypt || (*crypt)->ops != ops) { - struct lib80211_crypt_data *new_crypt; - - lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); - - new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); - if (!new_crypt) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) - new_crypt->priv = new_crypt->ops->init(idx); - - if (!new_crypt->priv) { - kfree(new_crypt); - ret = -EINVAL; - goto done; - } - *crypt = new_crypt; - } - - if (ext->key_len > 0 && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, - (*crypt)->priv) < 0) { - netdev_info(dev, "key setting failed\n"); - ret = -EINVAL; - goto done; - } - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - ieee->crypt_info.tx_keyidx = idx; - sec.active_key = idx; - sec.flags |= SEC_ACTIVE_KEY; - } - if (ext->alg != IW_ENCODE_ALG_NONE) { - sec.key_sizes[idx] = ext->key_len; - sec.flags |= (1 << idx); - if (ext->alg == IW_ENCODE_ALG_WEP) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } else if (ext->alg == IW_ENCODE_ALG_TKIP) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_2; - } else if (ext->alg == IW_ENCODE_ALG_CCMP) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_3; - } - /* Don't set sec level for group keys. */ - if (group_key) - sec.flags &= ~SEC_LEVEL; - } -done: - return ret; -} -EXPORT_SYMBOL(rtllib_wx_set_encode_ext); - -int rtllib_wx_set_mlme(struct rtllib_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - u8 i = 0; - bool deauth = false; - struct iw_mlme *mlme = (struct iw_mlme *)extra; - - if (ieee->link_state != MAC80211_LINKED) - return -ENOLINK; - - mutex_lock(&ieee->wx_mutex); - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - deauth = true; - fallthrough; - case IW_MLME_DISASSOC: - if (deauth) - netdev_info(ieee->dev, "disauth packet !\n"); - else - netdev_info(ieee->dev, "dis associate packet!\n"); - - ieee->cannot_notify = true; - - send_disassociation(ieee, deauth, mlme->reason_code); - rtllib_disassociate(ieee); - - ieee->wap_set = 0; - for (i = 0; i < 6; i++) - ieee->current_network.bssid[i] = 0x55; - - ieee->ssid_set = 0; - ieee->current_network.ssid[0] = '\0'; - ieee->current_network.ssid_len = 0; - break; - default: - mutex_unlock(&ieee->wx_mutex); - return -EOPNOTSUPP; - } - - mutex_unlock(&ieee->wx_mutex); - - return 0; -} -EXPORT_SYMBOL(rtllib_wx_set_mlme); - -int rtllib_wx_set_auth(struct rtllib_device *ieee, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - break; - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - break; - case IW_AUTH_TKIP_COUNTERMEASURES: - ieee->tkip_countermeasures = data->value; - break; - case IW_AUTH_DROP_UNENCRYPTED: - ieee->drop_unencrypted = data->value; - break; - - case IW_AUTH_80211_AUTH_ALG: - if (data->value & IW_AUTH_ALG_SHARED_KEY) { - ieee->open_wep = 0; - ieee->auth_mode = 1; - } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) { - ieee->open_wep = 1; - ieee->auth_mode = 0; - } else if (data->value & IW_AUTH_ALG_LEAP) { - ieee->open_wep = 1; - ieee->auth_mode = 2; - } else { - return -EINVAL; - } - break; - - case IW_AUTH_WPA_ENABLED: - ieee->wpa_enabled = (data->value) ? 1 : 0; - break; - - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - ieee->ieee802_1x = data->value; - break; - case IW_AUTH_PRIVACY_INVOKED: - ieee->privacy_invoked = data->value; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} -EXPORT_SYMBOL(rtllib_wx_set_auth); - -int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len) -{ - u8 *buf; - u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; - - if (len > MAX_WPA_IE_LEN || (len && !ie)) - return -EINVAL; - - if (len) { - eid = ie[0]; - if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2], wps_oui, 4))) { - ieee->wps_ie_len = min_t(size_t, len, MAX_WZC_IE_LEN); - buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - ieee->wps_ie = buf; - return 0; - } - } - ieee->wps_ie_len = 0; - kfree(ieee->wps_ie); - ieee->wps_ie = NULL; - if (len) { - if (len != ie[1] + 2) - return -EINVAL; - buf = kmemdup(ie, len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - kfree(ieee->wpa_ie); - ieee->wpa_ie = buf; - ieee->wpa_ie_len = len; - } else { - kfree(ieee->wpa_ie); - ieee->wpa_ie = NULL; - ieee->wpa_ie_len = 0; - } - return 0; -} -EXPORT_SYMBOL(rtllib_wx_set_gen_ie); diff --git a/drivers/staging/rtl8712/Kconfig b/drivers/staging/rtl8712/Kconfig deleted file mode 100644 index 8de26425225b38..00000000000000 --- a/drivers/staging/rtl8712/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config R8712U - tristate "RealTek RTL8712U (RTL8192SU) Wireless LAN NIC driver" - depends on WLAN && USB && CFG80211 - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - help - This option adds the Realtek RTL8712 USB device such as the - D-Link DWA-130. - - If built as a module, it will be called r8712u. - -config R8712_TX_AGGR - bool "Realtek RTL8712U Transmit Aggregation code" - depends on R8712U && BROKEN - help - This option provides transmit aggregation for the Realtek - RTL8712 USB device. - - diff --git a/drivers/staging/rtl8712/Makefile b/drivers/staging/rtl8712/Makefile deleted file mode 100644 index 3ae216b6621b1c..00000000000000 --- a/drivers/staging/rtl8712/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -r8712u-y := \ - rtl871x_cmd.o \ - rtl8712_cmd.o \ - rtl871x_security.o \ - rtl871x_eeprom.o \ - rtl8712_efuse.o \ - hal_init.o \ - usb_halinit.o \ - usb_ops.o \ - usb_ops_linux.o \ - rtl871x_io.o \ - rtl8712_io.o \ - rtl871x_ioctl_linux.o \ - rtl871x_ioctl_rtl.o \ - rtl871x_ioctl_set.o \ - rtl8712_led.o \ - rtl871x_mlme.o \ - ieee80211.o \ - rtl871x_mp_ioctl.o \ - rtl871x_mp.o \ - mlme_linux.o \ - recv_linux.o \ - xmit_linux.o \ - usb_intf.o \ - os_intfs.o \ - rtl871x_pwrctrl.o \ - rtl8712_recv.o \ - rtl871x_recv.o \ - rtl871x_sta_mgt.o \ - rtl871x_xmit.o \ - rtl8712_xmit.o - -obj-$(CONFIG_R8712U) := r8712u.o - diff --git a/drivers/staging/rtl8712/TODO b/drivers/staging/rtl8712/TODO deleted file mode 100644 index 847c8c41f4f7ff..00000000000000 --- a/drivers/staging/rtl8712/TODO +++ /dev/null @@ -1,13 +0,0 @@ -TODO: -- merge Realtek's bugfixes and new features into the driver -- switch to use LIB80211 -- switch to use MAC80211 -- checkpatch.pl fixes - only a few remain - -A replacement for this driver with MAC80211 support is available -at https://github.com/chunkeey/rtl8192su - -Please send any patches to Greg Kroah-Hartman , -Larry Finger , -Florian Schilhabel and -Linux Driver Project Developer List . diff --git a/drivers/staging/rtl8712/basic_types.h b/drivers/staging/rtl8712/basic_types.h deleted file mode 100644 index aecded87dd4c87..00000000000000 --- a/drivers/staging/rtl8712/basic_types.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __BASIC_TYPES_H__ -#define __BASIC_TYPES_H__ - -#include - -#define sint signed int - -/* Should we extend this to be host_addr_t and target_addr_t for case: - * host : x86_64 - * target : mips64 - */ -#define addr_t unsigned long - -#endif /*__BASIC_TYPES_H__*/ - diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h deleted file mode 100644 index 76ac798642bd2b..00000000000000 --- a/drivers/staging/rtl8712/drv_types.h +++ /dev/null @@ -1,175 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -/* --------------------------------------------------------------------- - * - * For type defines and data structure defines - * - * --------------------------------------------------------------------- - */ -#ifndef __DRV_TYPES_H__ -#define __DRV_TYPES_H__ - -struct _adapter; - -#include "osdep_service.h" -#include "wlan_bssdef.h" -#include "rtl8712_spec.h" -#include "rtl8712_hal.h" -#include -#include - -enum _NIC_VERSION { - RTL8711_NIC, - RTL8712_NIC, - RTL8713_NIC, - RTL8716_NIC -}; - -struct qos_priv { - /* bit mask option: u-apsd, s-apsd, ts, block ack... */ - unsigned int qos_option; -}; - -#include "rtl871x_ht.h" -#include "rtl871x_cmd.h" -#include "rtl871x_xmit.h" -#include "rtl871x_recv.h" -#include "rtl871x_security.h" -#include "rtl871x_pwrctrl.h" -#include "rtl871x_io.h" -#include "rtl871x_eeprom.h" -#include "sta_info.h" -#include "rtl871x_mlme.h" -#include "rtl871x_mp.h" -#include "rtl871x_debug.h" -#include "rtl871x_rf.h" -#include "rtl871x_event.h" -#include "rtl871x_led.h" - -#define SPEC_DEV_ID_DISABLE_HT BIT(1) - -struct specific_device_id { - u32 flags; - u16 idVendor; - u16 idProduct; - -}; - -struct registry_priv { - u8 chip_version; - u8 rfintfs; - u8 lbkmode; - u8 hci; - u8 network_mode; /*infra, ad-hoc, auto*/ - struct ndis_802_11_ssid ssid; - u8 channel;/* ad-hoc support requirement */ - u8 wireless_mode;/* A, B, G, auto */ - u8 vrtl_carrier_sense; /*Enable, Disable, Auto*/ - u8 vcs_type;/*RTS/CTS, CTS-to-self*/ - u16 rts_thresh; - u16 frag_thresh; - u8 preamble;/*long, short, auto*/ - u8 scan_mode;/*active, passive*/ - u8 adhoc_tx_pwr; - u8 soft_ap; - u8 smart_ps; - u8 power_mgnt; - u8 radio_enable; - u8 long_retry_lmt; - u8 short_retry_lmt; - u16 busy_thresh; - u8 ack_policy; - u8 mp_mode; - u8 software_encrypt; - u8 software_decrypt; - /* UAPSD */ - u8 wmm_enable; - u8 uapsd_enable; - u8 uapsd_max_sp; - u8 uapsd_acbk_en; - u8 uapsd_acbe_en; - u8 uapsd_acvi_en; - u8 uapsd_acvo_en; - - struct wlan_bssid_ex dev_network; - - u8 ht_enable; - u8 cbw40_enable; - u8 ampdu_enable;/*for tx*/ - u8 rf_config; - u8 low_power; - u8 wifi_test; -}; - -struct dvobj_priv { - struct _adapter *padapter; - u32 nr_endpoint; - u8 ishighspeed; - uint (*inirp_init)(struct _adapter *adapter); - uint (*inirp_deinit)(struct _adapter *adapter); - struct usb_device *pusbdev; -}; - -/** - * struct _adapter - the main adapter structure for this device. - * - * bup: True indicates that the interface is up. - */ -struct _adapter { - struct dvobj_priv dvobjpriv; - struct mlme_priv mlmepriv; - struct cmd_priv cmdpriv; - struct evt_priv evtpriv; - struct io_queue *pio_queue; - struct xmit_priv xmitpriv; - struct recv_priv recvpriv; - struct sta_priv stapriv; - struct security_priv securitypriv; - struct registry_priv registrypriv; - struct wlan_acl_pool acl_list; - struct pwrctrl_priv pwrctrlpriv; - struct eeprom_priv eeprompriv; - struct hal_priv halpriv; - struct led_priv ledpriv; - struct mp_priv mppriv; - bool driver_stopped; - bool surprise_removed; - bool suspended; - u8 eeprom_address_size; - u8 hw_init_completed; - struct task_struct *cmd_thread; - uint (*dvobj_init)(struct _adapter *adapter); - void (*dvobj_deinit)(struct _adapter *adapter); - struct net_device *pnetdev; - int bup; - struct net_device_stats stats; - struct iw_statistics iwstats; - int pid; /*process id from UI*/ - struct work_struct wk_filter_rx_ff0; - const struct firmware *fw; - struct usb_interface *pusb_intf; - struct mutex mutex_start; - struct completion rtl8712_fw_ready; - struct completion rx_filter_ready; -}; - -static inline u8 *myid(struct eeprom_priv *peepriv) -{ - return peepriv->mac_addr; -} - -u8 r8712_usb_hal_bus_init(struct _adapter *adapter); - -#endif /*__DRV_TYPES_H__*/ - diff --git a/drivers/staging/rtl8712/ethernet.h b/drivers/staging/rtl8712/ethernet.h deleted file mode 100644 index 4b9b8a97a0bc6c..00000000000000 --- a/drivers/staging/rtl8712/ethernet.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __INC_ETHERNET_H -#define __INC_ETHERNET_H - -#define ETHERNET_HEADER_SIZE 14 /*!< Ethernet Header Length*/ -#define LLC_HEADER_SIZE 6 /*!< LLC Header Length*/ - -#endif /* #ifndef __INC_ETHERNET_H */ - diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c deleted file mode 100644 index 1148075f0cd64c..00000000000000 --- a/drivers/staging/rtl8712/hal_init.c +++ /dev/null @@ -1,401 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE . - * Larry Finger - * - ******************************************************************************/ - -#define _HAL_INIT_C_ - -#include -#include -#include -#include -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "usb_osintf.h" - -#define FWBUFF_ALIGN_SZ 512 -#define MAX_DUMP_FWSZ (48 * 1024) - -static void rtl871x_load_fw_fail(struct _adapter *adapter) -{ - struct usb_device *udev = adapter->dvobjpriv.pusbdev; - struct device *dev = &udev->dev; - struct device *parent = dev->parent; - - complete(&adapter->rtl8712_fw_ready); - - dev_err(&udev->dev, "r8712u: Firmware request failed\n"); - - if (parent) - device_lock(parent); - - device_release_driver(dev); - - if (parent) - device_unlock(parent); -} - -static void rtl871x_load_fw_cb(const struct firmware *firmware, void *context) -{ - struct _adapter *adapter = context; - - if (!firmware) { - rtl871x_load_fw_fail(adapter); - return; - } - adapter->fw = firmware; - /* firmware available - start netdev */ - register_netdev(adapter->pnetdev); - complete(&adapter->rtl8712_fw_ready); -} - -static const char firmware_file[] = "rtlwifi/rtl8712u.bin"; - -int rtl871x_load_fw(struct _adapter *padapter) -{ - struct device *dev = &padapter->dvobjpriv.pusbdev->dev; - int rc; - - init_completion(&padapter->rtl8712_fw_ready); - dev_info(dev, "r8712u: Loading firmware from \"%s\"\n", firmware_file); - rc = request_firmware_nowait(THIS_MODULE, 1, firmware_file, dev, - GFP_KERNEL, padapter, rtl871x_load_fw_cb); - if (rc) - dev_err(dev, "r8712u: Firmware request error %d\n", rc); - return rc; -} -MODULE_FIRMWARE("rtlwifi/rtl8712u.bin"); - -static u32 rtl871x_open_fw(struct _adapter *adapter, const u8 **mappedfw) -{ - if (adapter->fw->size > 200000) { - dev_err(&adapter->pnetdev->dev, "r8712u: Bad fw->size of %zu\n", - adapter->fw->size); - return 0; - } - *mappedfw = adapter->fw->data; - return adapter->fw->size; -} - -static void fill_fwpriv(struct _adapter *adapter, struct fw_priv *fwpriv) -{ - struct dvobj_priv *dvobj = &adapter->dvobjpriv; - struct registry_priv *regpriv = &adapter->registrypriv; - - memset(fwpriv, 0, sizeof(struct fw_priv)); - /* todo: check if needs endian conversion */ - fwpriv->hci_sel = RTL8712_HCI_TYPE_72USB; - fwpriv->usb_ep_num = (u8)dvobj->nr_endpoint; - fwpriv->bw_40MHz_en = regpriv->cbw40_enable; - switch (regpriv->rf_config) { - case RTL8712_RF_1T1R: - fwpriv->rf_config = RTL8712_RFC_1T1R; - break; - case RTL8712_RF_2T2R: - fwpriv->rf_config = RTL8712_RFC_2T2R; - break; - case RTL8712_RF_1T2R: - default: - fwpriv->rf_config = RTL8712_RFC_1T2R; - } - fwpriv->mp_mode = (regpriv->mp_mode == 1); - /* 0:off 1:on 2:auto */ - fwpriv->vcs_type = regpriv->vrtl_carrier_sense; - fwpriv->vcs_mode = regpriv->vcs_type; /* 1:RTS/CTS 2:CTS to self */ - /* default enable turbo_mode */ - fwpriv->turbo_mode = (regpriv->wifi_test != 1); - fwpriv->low_power_mode = regpriv->low_power; -} - -static void update_fwhdr(struct fw_hdr *pfwhdr, const u8 *pmappedfw) -{ - pfwhdr->signature = le16_to_cpu(*(__le16 *)pmappedfw); - pfwhdr->version = le16_to_cpu(*(__le16 *)(pmappedfw + 2)); - /* define the size of boot loader */ - pfwhdr->dmem_size = le32_to_cpu(*(__le32 *)(pmappedfw + 4)); - /* define the size of FW in IMEM */ - pfwhdr->img_IMEM_size = le32_to_cpu(*(__le32 *)(pmappedfw + 8)); - /* define the size of FW in SRAM */ - pfwhdr->img_SRAM_size = le32_to_cpu(*(__le32 *)(pmappedfw + 12)); - /* define the size of DMEM variable */ - pfwhdr->fw_priv_sz = le32_to_cpu(*(__le32 *)(pmappedfw + 16)); -} - -static u8 chk_fwhdr(struct fw_hdr *pfwhdr, u32 ulfilelength) -{ - u32 fwhdrsz, fw_sz; - - /* check signature */ - if ((pfwhdr->signature != 0x8712) && (pfwhdr->signature != 0x8192)) - return _FAIL; - /* check fw_priv_sze & sizeof(struct fw_priv) */ - if (pfwhdr->fw_priv_sz != sizeof(struct fw_priv)) - return _FAIL; - /* check fw_sz & image_fw_sz */ - fwhdrsz = offsetof(struct fw_hdr, fwpriv) + pfwhdr->fw_priv_sz; - fw_sz = fwhdrsz + pfwhdr->img_IMEM_size + pfwhdr->img_SRAM_size + - pfwhdr->dmem_size; - if (fw_sz != ulfilelength) - return _FAIL; - return _SUCCESS; -} - -static u8 rtl8712_dl_fw(struct _adapter *adapter) -{ - sint i; - u8 tmp8, tmp8_a; - u16 tmp16; - u32 maxlen = 0; /* for compare usage */ - uint dump_imem_sz, imem_sz, dump_emem_sz, emem_sz; /* max = 49152; */ - struct fw_hdr fwhdr; - u32 ulfilelength; /* FW file size */ - const u8 *mappedfw = NULL; - u8 *tmpchar = NULL, *payload, *ptr; - struct tx_desc *txdesc; - u32 txdscp_sz = sizeof(struct tx_desc); - u8 ret = _FAIL; - - ulfilelength = rtl871x_open_fw(adapter, &mappedfw); - if (mappedfw && (ulfilelength > 0)) { - update_fwhdr(&fwhdr, mappedfw); - if (chk_fwhdr(&fwhdr, ulfilelength) == _FAIL) - return ret; - fill_fwpriv(adapter, &fwhdr.fwpriv); - /* firmware check ok */ - maxlen = (fwhdr.img_IMEM_size > fwhdr.img_SRAM_size) ? - fwhdr.img_IMEM_size : fwhdr.img_SRAM_size; - maxlen += txdscp_sz; - tmpchar = kmalloc(maxlen + FWBUFF_ALIGN_SZ, GFP_KERNEL); - if (!tmpchar) - return ret; - - txdesc = (struct tx_desc *)(tmpchar + FWBUFF_ALIGN_SZ - - ((addr_t)(tmpchar) & (FWBUFF_ALIGN_SZ - 1))); - payload = (u8 *)(txdesc) + txdscp_sz; - ptr = (u8 *)mappedfw + offsetof(struct fw_hdr, fwpriv) + - fwhdr.fw_priv_sz; - /* Download FirmWare */ - /* 1. determine IMEM code size and Load IMEM Code Section */ - imem_sz = fwhdr.img_IMEM_size; - do { - memset(txdesc, 0, TXDESC_SIZE); - if (imem_sz > MAX_DUMP_FWSZ/*49152*/) { - dump_imem_sz = MAX_DUMP_FWSZ; - } else { - dump_imem_sz = imem_sz; - txdesc->txdw0 |= cpu_to_le32(BIT(28)); - } - txdesc->txdw0 |= cpu_to_le32(dump_imem_sz & - 0x0000ffff); - memcpy(payload, ptr, dump_imem_sz); - r8712_write_mem(adapter, RTL8712_DMA_VOQ, - dump_imem_sz + TXDESC_SIZE, - (u8 *)txdesc); - ptr += dump_imem_sz; - imem_sz -= dump_imem_sz; - } while (imem_sz > 0); - i = 10; - tmp16 = r8712_read16(adapter, TCR); - while (((tmp16 & _IMEM_CODE_DONE) == 0) && (i > 0)) { - usleep_range(10, 1000); - tmp16 = r8712_read16(adapter, TCR); - i--; - } - if (i == 0 || (tmp16 & _IMEM_CHK_RPT) == 0) - goto exit_fail; - - /* 2.Download EMEM code size and Load EMEM Code Section */ - emem_sz = fwhdr.img_SRAM_size; - do { - memset(txdesc, 0, TXDESC_SIZE); - if (emem_sz > MAX_DUMP_FWSZ) { /* max=48k */ - dump_emem_sz = MAX_DUMP_FWSZ; - } else { - dump_emem_sz = emem_sz; - txdesc->txdw0 |= cpu_to_le32(BIT(28)); - } - txdesc->txdw0 |= cpu_to_le32(dump_emem_sz & - 0x0000ffff); - memcpy(payload, ptr, dump_emem_sz); - r8712_write_mem(adapter, RTL8712_DMA_VOQ, - dump_emem_sz + TXDESC_SIZE, - (u8 *)txdesc); - ptr += dump_emem_sz; - emem_sz -= dump_emem_sz; - } while (emem_sz > 0); - i = 5; - tmp16 = r8712_read16(adapter, TCR); - while (((tmp16 & _EMEM_CODE_DONE) == 0) && (i > 0)) { - usleep_range(10, 1000); - tmp16 = r8712_read16(adapter, TCR); - i--; - } - if (i == 0 || (tmp16 & _EMEM_CHK_RPT) == 0) - goto exit_fail; - - /* 3.Enable CPU */ - tmp8 = r8712_read8(adapter, SYS_CLKR); - r8712_write8(adapter, SYS_CLKR, tmp8 | BIT(2)); - tmp8_a = r8712_read8(adapter, SYS_CLKR); - if (tmp8_a != (tmp8 | BIT(2))) - goto exit_fail; - - tmp8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - r8712_write8(adapter, SYS_FUNC_EN + 1, tmp8 | BIT(2)); - tmp8_a = r8712_read8(adapter, SYS_FUNC_EN + 1); - if (tmp8_a != (tmp8 | BIT(2))) - goto exit_fail; - - r8712_read32(adapter, TCR); - - /* 4.polling IMEM Ready */ - i = 100; - tmp16 = r8712_read16(adapter, TCR); - while (((tmp16 & _IMEM_RDY) == 0) && (i > 0)) { - msleep(20); - tmp16 = r8712_read16(adapter, TCR); - i--; - } - if (i == 0) { - r8712_write16(adapter, 0x10250348, 0xc000); - r8712_write16(adapter, 0x10250348, 0xc001); - r8712_write16(adapter, 0x10250348, 0x2000); - r8712_write16(adapter, 0x10250348, 0x2001); - r8712_write16(adapter, 0x10250348, 0x2002); - r8712_write16(adapter, 0x10250348, 0x2003); - goto exit_fail; - } - /* 5.Download DMEM code size and Load EMEM Code Section */ - memset(txdesc, 0, TXDESC_SIZE); - txdesc->txdw0 |= cpu_to_le32(fwhdr.fw_priv_sz & 0x0000ffff); - txdesc->txdw0 |= cpu_to_le32(BIT(28)); - memcpy(payload, &fwhdr.fwpriv, fwhdr.fw_priv_sz); - r8712_write_mem(adapter, RTL8712_DMA_VOQ, - fwhdr.fw_priv_sz + TXDESC_SIZE, (u8 *)txdesc); - - /* polling dmem code done */ - i = 100; - tmp16 = r8712_read16(adapter, TCR); - while (((tmp16 & _DMEM_CODE_DONE) == 0) && (i > 0)) { - msleep(20); - tmp16 = r8712_read16(adapter, TCR); - i--; - } - if (i == 0) - goto exit_fail; - - tmp8 = r8712_read8(adapter, 0x1025000A); - if (tmp8 & BIT(4)) /* When boot from EEPROM, - * & FW need more time to read EEPROM - */ - i = 60; - else /* boot from EFUSE */ - i = 30; - tmp16 = r8712_read16(adapter, TCR); - while (((tmp16 & _FWRDY) == 0) && (i > 0)) { - msleep(100); - tmp16 = r8712_read16(adapter, TCR); - i--; - } - if (i == 0) - goto exit_fail; - } else { - goto exit_fail; - } - ret = _SUCCESS; - -exit_fail: - kfree(tmpchar); - return ret; -} - -uint rtl8712_hal_init(struct _adapter *padapter) -{ - u32 val32; - int i; - - /* r8712 firmware download */ - if (rtl8712_dl_fw(padapter) != _SUCCESS) - return _FAIL; - - netdev_info(padapter->pnetdev, "1 RCR=0x%x\n", - r8712_read32(padapter, RCR)); - val32 = r8712_read32(padapter, RCR); - r8712_write32(padapter, RCR, (val32 | BIT(26))); /* Enable RX TCP - * Checksum offload - */ - netdev_info(padapter->pnetdev, "2 RCR=0x%x\n", - r8712_read32(padapter, RCR)); - val32 = r8712_read32(padapter, RCR); - r8712_write32(padapter, RCR, (val32 | BIT(25))); /* Append PHY status */ - val32 = r8712_read32(padapter, 0x10250040); - r8712_write32(padapter, 0x10250040, (val32 & 0x00FFFFFF)); - /* for usb rx aggregation */ - r8712_write8(padapter, 0x102500B5, r8712_read8(padapter, 0x102500B5) | - BIT(0)); /* page = 128bytes */ - r8712_write8(padapter, 0x102500BD, r8712_read8(padapter, 0x102500BD) | - BIT(7)); /* enable usb rx aggregation */ - r8712_write8(padapter, 0x102500D9, 1); /* TH=1 => means that invalidate - * usb rx aggregation - */ - r8712_write8(padapter, 0x1025FE5B, 0x04); /* 1.7ms/4 */ - /* Fix the RX FIFO issue(USB error) */ - r8712_write8(padapter, 0x1025fe5C, r8712_read8(padapter, 0x1025fe5C) - | BIT(7)); - for (i = 0; i < ETH_ALEN; i++) - padapter->eeprompriv.mac_addr[i] = r8712_read8(padapter, - MACID + i); - return _SUCCESS; -} - -uint rtl8712_hal_deinit(struct _adapter *padapter) -{ - r8712_write8(padapter, RF_CTRL, 0x00); - /* Turn off BB */ - msleep(20); - /* Turn off MAC */ - r8712_write8(padapter, SYS_CLKR + 1, 0x38); /* Switch Control Path */ - r8712_write8(padapter, SYS_FUNC_EN + 1, 0x70); - r8712_write8(padapter, PMC_FSM, 0x06); /* Enable Loader Data Keep */ - r8712_write8(padapter, SYS_ISO_CTRL, 0xF9); /* Isolation signals from - * CORE, PLL - */ - r8712_write8(padapter, SYS_ISO_CTRL + 1, 0xe8); /* Enable EFUSE 1.2V */ - r8712_write8(padapter, AFE_PLL_CTRL, 0x00); /* Disable AFE PLL. */ - r8712_write8(padapter, LDOA15_CTRL, 0x54); /* Disable A15V */ - r8712_write8(padapter, SYS_FUNC_EN + 1, 0x50); /* Disable E-Fuse 1.2V */ - r8712_write8(padapter, LDOV12D_CTRL, 0x24); /* Disable LDO12(for CE) */ - r8712_write8(padapter, AFE_MISC, 0x30); /* Disable AFE BG&MB */ - /* Option for Disable 1.6V LDO. */ - r8712_write8(padapter, SPS0_CTRL, 0x56); /* Disable 1.6V LDO */ - r8712_write8(padapter, SPS0_CTRL + 1, 0x43); /* Set SW PFM */ - return _SUCCESS; -} - -uint rtl871x_hal_init(struct _adapter *padapter) -{ - padapter->hw_init_completed = false; - if (!padapter->halpriv.hal_bus_init) - return _FAIL; - if (padapter->halpriv.hal_bus_init(padapter) != _SUCCESS) - return _FAIL; - if (rtl8712_hal_init(padapter) == _SUCCESS) { - padapter->hw_init_completed = true; - } else { - padapter->hw_init_completed = false; - return _FAIL; - } - return _SUCCESS; -} diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c deleted file mode 100644 index 7d8f1a29d18a90..00000000000000 --- a/drivers/staging/rtl8712/ieee80211.c +++ /dev/null @@ -1,415 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * ieee80211.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE . - * Larry Finger - * - ******************************************************************************/ - -#define _IEEE80211_C - -#include "drv_types.h" -#include "ieee80211.h" -#include "wifi.h" -#include "osdep_service.h" -#include "wlan_bssdef.h" - -static const u8 WPA_OUI_TYPE[] = {0x00, 0x50, 0xf2, 1}; -static const u8 WPA_CIPHER_SUITE_NONE[] = {0x00, 0x50, 0xf2, 0}; -static const u8 WPA_CIPHER_SUITE_WEP40[] = {0x00, 0x50, 0xf2, 1}; -static const u8 WPA_CIPHER_SUITE_TKIP[] = {0x00, 0x50, 0xf2, 2}; -static const u8 WPA_CIPHER_SUITE_CCMP[] = {0x00, 0x50, 0xf2, 4}; -static const u8 WPA_CIPHER_SUITE_WEP104[] = {0x00, 0x50, 0xf2, 5}; - -static const u8 RSN_CIPHER_SUITE_NONE[] = {0x00, 0x0f, 0xac, 0}; -static const u8 RSN_CIPHER_SUITE_WEP40[] = {0x00, 0x0f, 0xac, 1}; -static const u8 RSN_CIPHER_SUITE_TKIP[] = {0x00, 0x0f, 0xac, 2}; -static const u8 RSN_CIPHER_SUITE_CCMP[] = {0x00, 0x0f, 0xac, 4}; -static const u8 RSN_CIPHER_SUITE_WEP104[] = {0x00, 0x0f, 0xac, 5}; - -/*----------------------------------------------------------- - * for adhoc-master to generate ie and provide supported-rate to fw - *----------------------------------------------------------- - */ - -static u8 WIFI_CCKRATES[] = { - (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), - (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), - (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), - (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK) -}; - -static u8 WIFI_OFDMRATES[] = { - (IEEE80211_OFDM_RATE_6MB), - (IEEE80211_OFDM_RATE_9MB), - (IEEE80211_OFDM_RATE_12MB), - (IEEE80211_OFDM_RATE_18MB), - (IEEE80211_OFDM_RATE_24MB), - (IEEE80211_OFDM_RATE_36MB), - (IEEE80211_OFDM_RATE_48MB), - (IEEE80211_OFDM_RATE_54MB) -}; - -uint r8712_is_cckrates_included(u8 *rate) -{ - u32 i = 0; - - while (rate[i] != 0) { - if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || - (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) - return true; - i++; - } - return false; -} - -uint r8712_is_cckratesonly_included(u8 *rate) -{ - u32 i = 0; - - while (rate[i] != 0) { - if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && - (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) - return false; - i++; - } - return true; -} - -/* r8712_set_ie will update frame length */ -u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen) -{ - *pbuf = (u8)index; - *(pbuf + 1) = (u8)len; - if (len > 0) - memcpy((void *)(pbuf + 2), (void *)source, len); - *frlen = *frlen + (len + 2); - return pbuf + len + 2; -} - -/* --------------------------------------------------------------------------- - * index: the information element id index, limit is the limit for search - * --------------------------------------------------------------------------- - */ -u8 *r8712_get_ie(u8 *pbuf, sint index, uint *len, sint limit) -{ - sint tmp, i; - u8 *p; - - if (limit < 1) - return NULL; - p = pbuf; - i = 0; - *len = 0; - while (1) { - if (*p == index) { - *len = *(p + 1); - return p; - } - tmp = *(p + 1); - p += (tmp + 2); - i += (tmp + 2); - if (i >= limit) - break; - } - return NULL; -} - -static void set_supported_rate(u8 *rates, uint mode) -{ - memset(rates, 0, NDIS_802_11_LENGTH_RATES_EX); - switch (mode) { - case WIRELESS_11B: - memcpy(rates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); - break; - case WIRELESS_11G: - case WIRELESS_11A: - memcpy(rates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); - break; - case WIRELESS_11BG: - memcpy(rates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); - memcpy(rates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, - IEEE80211_NUM_OFDM_RATESLEN); - break; - } -} - -static uint r8712_get_rateset_len(u8 *rateset) -{ - uint i = 0; - - while (1) { - if ((rateset[i]) == 0) - break; - if (i > 12) - break; - i++; - } - return i; -} - -int r8712_generate_ie(struct registry_priv *registrypriv) -{ - int rate_len; - uint sz = 0; - struct wlan_bssid_ex *dev_network = ®istrypriv->dev_network; - u8 *ie = dev_network->IEs; - u16 beacon_period = (u16)dev_network->Configuration.BeaconPeriod; - - /*timestamp will be inserted by hardware*/ - sz += 8; - ie += sz; - /*beacon interval : 2bytes*/ - *(__le16 *)ie = cpu_to_le16(beacon_period); - sz += 2; - ie += 2; - /*capability info*/ - *(u16 *)ie = 0; - *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_IBSS); - if (registrypriv->preamble == PREAMBLE_SHORT) - *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - if (dev_network->Privacy) - *(__le16 *)ie |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - sz += 2; - ie += 2; - /*SSID*/ - ie = r8712_set_ie(ie, WLAN_EID_SSID, dev_network->Ssid.SsidLength, - dev_network->Ssid.Ssid, &sz); - /*supported rates*/ - set_supported_rate(dev_network->rates, registrypriv->wireless_mode); - rate_len = r8712_get_rateset_len(dev_network->rates); - if (rate_len > 8) { - ie = r8712_set_ie(ie, WLAN_EID_SUPP_RATES, 8, - dev_network->rates, &sz); - ie = r8712_set_ie(ie, WLAN_EID_EXT_SUPP_RATES, (rate_len - 8), - (dev_network->rates + 8), &sz); - } else { - ie = r8712_set_ie(ie, WLAN_EID_SUPP_RATES, - rate_len, dev_network->rates, &sz); - } - /*DS parameter set*/ - ie = r8712_set_ie(ie, WLAN_EID_DS_PARAMS, 1, - (u8 *)&dev_network->Configuration.DSConfig, &sz); - /*IBSS Parameter Set*/ - ie = r8712_set_ie(ie, WLAN_EID_IBSS_PARAMS, 2, - (u8 *)&dev_network->Configuration.ATIMWindow, &sz); - return sz; -} - -unsigned char *r8712_get_wpa_ie(unsigned char *ie, uint *wpa_ie_len, int limit) -{ - u32 len; - u16 val16; - unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; - u8 *buf = ie; - - while (1) { - buf = r8712_get_ie(buf, _WPA_IE_ID_, &len, limit); - if (buf) { - /*check if oui matches...*/ - if (memcmp((buf + 2), wpa_oui_type, - sizeof(wpa_oui_type))) - goto check_next_ie; - /*check version...*/ - memcpy((u8 *)&val16, (buf + 6), sizeof(val16)); - le16_to_cpus(&val16); - if (val16 != 0x0001) - goto check_next_ie; - *wpa_ie_len = *(buf + 1); - return buf; - } - *wpa_ie_len = 0; - return NULL; -check_next_ie: - limit = limit - (buf - ie) - 2 - len; - if (limit <= 0) - break; - buf += (2 + len); - } - *wpa_ie_len = 0; - return NULL; -} - -unsigned char *r8712_get_wpa2_ie(unsigned char *pie, uint *rsn_ie_len, - int limit) -{ - return r8712_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); -} - -static int r8712_get_wpa_cipher_suite(u8 *s) -{ - if (!memcmp(s, (void *)WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN)) - return WPA_CIPHER_NONE; - if (!memcmp(s, (void *)WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN)) - return WPA_CIPHER_WEP40; - if (!memcmp(s, (void *)WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN)) - return WPA_CIPHER_TKIP; - if (!memcmp(s, (void *)WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN)) - return WPA_CIPHER_CCMP; - if (!memcmp(s, (void *)WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN)) - return WPA_CIPHER_WEP104; - return 0; -} - -static int r8712_get_wpa2_cipher_suite(u8 *s) -{ - if (!memcmp(s, (void *)RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN)) - return WPA_CIPHER_NONE; - if (!memcmp(s, (void *)RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN)) - return WPA_CIPHER_WEP40; - if (!memcmp(s, (void *)RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN)) - return WPA_CIPHER_TKIP; - if (!memcmp(s, (void *)RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN)) - return WPA_CIPHER_CCMP; - if (!memcmp(s, (void *)RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN)) - return WPA_CIPHER_WEP104; - return 0; -} - -int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, - int *pairwise_cipher) -{ - int i; - int left, count; - u8 *pos; - - if (wpa_ie_len <= 0) { - /* No WPA IE - fail silently */ - return -EINVAL; - } - if ((*wpa_ie != _WPA_IE_ID_) || - (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) || - (memcmp(wpa_ie + 2, (void *)WPA_OUI_TYPE, WPA_SELECTOR_LEN))) - return -EINVAL; - pos = wpa_ie; - pos += 8; - left = wpa_ie_len - 8; - /*group_cipher*/ - if (left >= WPA_SELECTOR_LEN) { - *group_cipher = r8712_get_wpa_cipher_suite(pos); - pos += WPA_SELECTOR_LEN; - left -= WPA_SELECTOR_LEN; - } else if (left > 0) { - return -EINVAL; - } - /*pairwise_cipher*/ - if (left >= 2) { - count = le16_to_cpu(*(__le16 *)pos); - pos += 2; - left -= 2; - if (count == 0 || left < count * WPA_SELECTOR_LEN) - return -EINVAL; - for (i = 0; i < count; i++) { - *pairwise_cipher |= r8712_get_wpa_cipher_suite(pos); - pos += WPA_SELECTOR_LEN; - left -= WPA_SELECTOR_LEN; - } - } else if (left == 1) { - return -EINVAL; - } - return 0; -} - -int r8712_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, - int *pairwise_cipher) -{ - int i; - int left, count; - u8 *pos; - - if (rsn_ie_len <= 0) { - /* No RSN IE - fail silently */ - return -EINVAL; - } - if ((*rsn_ie != _WPA2_IE_ID_) || - (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2))) - return -EINVAL; - pos = rsn_ie; - pos += 4; - left = rsn_ie_len - 4; - /*group_cipher*/ - if (left >= RSN_SELECTOR_LEN) { - *group_cipher = r8712_get_wpa2_cipher_suite(pos); - pos += RSN_SELECTOR_LEN; - left -= RSN_SELECTOR_LEN; - } else if (left > 0) { - return -EINVAL; - } - /*pairwise_cipher*/ - if (left >= 2) { - count = le16_to_cpu(*(__le16 *)pos); - pos += 2; - left -= 2; - if (count == 0 || left < count * RSN_SELECTOR_LEN) - return -EINVAL; - for (i = 0; i < count; i++) { - *pairwise_cipher |= r8712_get_wpa2_cipher_suite(pos); - pos += RSN_SELECTOR_LEN; - left -= RSN_SELECTOR_LEN; - } - } else if (left == 1) { - return -EINVAL; - } - return 0; -} - -int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, - u8 *wpa_ie, u16 *wpa_len) -{ - u8 authmode; - u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; - uint cnt; - - /*Search required WPA or WPA2 IE and copy to sec_ie[ ]*/ - cnt = _TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_; - while (cnt < in_len) { - authmode = in_ie[cnt]; - if ((authmode == _WPA_IE_ID_) && - (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) { - memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); - *wpa_len = in_ie[cnt + 1] + 2; - cnt += in_ie[cnt + 1] + 2; /*get next */ - } else { - if (authmode == _WPA2_IE_ID_) { - memcpy(rsn_ie, &in_ie[cnt], - in_ie[cnt + 1] + 2); - *rsn_len = in_ie[cnt + 1] + 2; - cnt += in_ie[cnt + 1] + 2; /*get next*/ - } else { - cnt += in_ie[cnt + 1] + 2; /*get next*/ - } - } - } - return *rsn_len + *wpa_len; -} - -int r8712_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) -{ - int match; - uint cnt; - u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; - - cnt = 12; - match = false; - while (cnt < in_len) { - eid = in_ie[cnt]; - if ((eid == _WPA_IE_ID_) && - (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) { - memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); - *wps_ielen = in_ie[cnt + 1] + 2; - cnt += in_ie[cnt + 1] + 2; - match = true; - break; - } - cnt += in_ie[cnt + 1] + 2; /* goto next */ - } - return match; -} diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h deleted file mode 100644 index 65ceaca9b51ea7..00000000000000 --- a/drivers/staging/rtl8712/ieee80211.h +++ /dev/null @@ -1,165 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __IEEE80211_H -#define __IEEE80211_H - -#include - -#define IEEE_CMD_SET_WPA_PARAM 1 -#define IEEE_CMD_SET_WPA_IE 2 -#define IEEE_CMD_SET_ENCRYPTION 3 -#define IEEE_CMD_MLME 4 - -#define IEEE_PARAM_WPA_ENABLED 1 -#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 -#define IEEE_PARAM_DROP_UNENCRYPTED 3 -#define IEEE_PARAM_PRIVACY_INVOKED 4 -#define IEEE_PARAM_AUTH_ALGS 5 -#define IEEE_PARAM_IEEE_802_1X 6 -#define IEEE_PARAM_WPAX_SELECT 7 - -#define AUTH_ALG_OPEN_SYSTEM 0x1 -#define AUTH_ALG_SHARED_KEY 0x2 -#define AUTH_ALG_LEAP 0x00000004 - -#define IEEE_MLME_STA_DEAUTH 1 -#define IEEE_MLME_STA_DISASSOC 2 - -#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 -#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 -#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 -#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 -#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 -#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 - -#define IEEE_CRYPT_ALG_NAME_LEN 16 - -#define WPA_CIPHER_NONE BIT(0) -#define WPA_CIPHER_WEP40 BIT(1) -#define WPA_CIPHER_WEP104 BIT(2) -#define WPA_CIPHER_TKIP BIT(3) -#define WPA_CIPHER_CCMP BIT(4) - -#define WPA_SELECTOR_LEN 4 -#define RSN_HEADER_LEN 4 - -#define RSN_SELECTOR_LEN 4 - -enum NETWORK_TYPE { - WIRELESS_INVALID = 0, - WIRELESS_11B = 1, - WIRELESS_11G = 2, - WIRELESS_11BG = (WIRELESS_11B | WIRELESS_11G), - WIRELESS_11A = 4, - WIRELESS_11N = 8, - WIRELESS_11GN = (WIRELESS_11G | WIRELESS_11N), - WIRELESS_11BGN = (WIRELESS_11B | WIRELESS_11G | WIRELESS_11N), -}; - -struct ieee_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u8 name; - u32 value; - } wpa_param; - struct { - u32 len; - u8 reserved[32]; - u8 data[]; - } wpa_ie; - struct { - int command; - int reason_code; - } mlme; - struct { - u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; - u8 set_tx; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[]; - } crypt; - } u; -}; - -#define MIN_FRAG_THRESHOLD 256U -#define MAX_FRAG_THRESHOLD 2346U - -/* QoS,QOS */ -#define NORMAL_ACK 0 - -/* IEEE 802.11 defines */ - -#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 */ -} __packed; - -#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) - -#define IEEE80211_CCK_RATE_LEN 4 -#define IEEE80211_NUM_OFDM_RATESLEN 8 - -#define IEEE80211_CCK_RATE_1MB 0x02 -#define IEEE80211_CCK_RATE_2MB 0x04 -#define IEEE80211_CCK_RATE_5MB 0x0B -#define IEEE80211_CCK_RATE_11MB 0x16 -#define IEEE80211_OFDM_RATE_6MB 0x0C -#define IEEE80211_OFDM_RATE_9MB 0x12 -#define IEEE80211_OFDM_RATE_12MB 0x18 -#define IEEE80211_OFDM_RATE_18MB 0x24 -#define IEEE80211_OFDM_RATE_24MB 0x30 -#define IEEE80211_OFDM_RATE_36MB 0x48 -#define IEEE80211_OFDM_RATE_48MB 0x60 -#define IEEE80211_OFDM_RATE_54MB 0x6C -#define IEEE80211_BASIC_RATE_MASK 0x80 - -#define WEP_KEYS 4 - -/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs - * only use 8, and then use extended rates for the remaining supported - * rates. Other APs, however, stick all of their supported rates on the - * main rates information element... - */ -#define MAX_RATES_LENGTH ((u8)12) -#define MAX_WPA_IE_LEN 128 - -struct registry_priv; - -u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen); -u8 *r8712_get_ie(u8 *pbuf, sint index, uint *len, sint limit); -unsigned char *r8712_get_wpa_ie(unsigned char *pie, uint *rsn_ie_len, - int limit); -unsigned char *r8712_get_wpa2_ie(unsigned char *pie, uint *rsn_ie_len, - int limit); -int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, - int *pairwise_cipher); -int r8712_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, - int *pairwise_cipher); -int r8712_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, - u8 *wpa_ie, u16 *wpa_len); -int r8712_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen); -int r8712_generate_ie(struct registry_priv *pregistrypriv); -uint r8712_is_cckrates_included(u8 *rate); -uint r8712_is_cckratesonly_included(u8 *rate); - -#endif /* IEEE80211_H */ - diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c deleted file mode 100644 index 436816d14cdf35..00000000000000 --- a/drivers/staging/rtl8712/mlme_linux.c +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * mlme_linux.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE . - * Larry Finger - * - ******************************************************************************/ - -#define _MLME_OSDEP_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "mlme_osdep.h" - -static void sitesurvey_ctrl_handler(struct timer_list *t) -{ - struct _adapter *adapter = - from_timer(adapter, t, - mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer); - - _r8712_sitesurvey_ctrl_handler(adapter); - mod_timer(&adapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, - jiffies + msecs_to_jiffies(3000)); -} - -static void join_timeout_handler (struct timer_list *t) -{ - struct _adapter *adapter = - from_timer(adapter, t, mlmepriv.assoc_timer); - - _r8712_join_timeout_handler(adapter); -} - -static void _scan_timeout_handler (struct timer_list *t) -{ - struct _adapter *adapter = - from_timer(adapter, t, mlmepriv.scan_to_timer); - - r8712_scan_timeout_handler(adapter); -} - -static void dhcp_timeout_handler (struct timer_list *t) -{ - struct _adapter *adapter = - from_timer(adapter, t, mlmepriv.dhcp_timer); - - _r8712_dhcp_timeout_handler(adapter); -} - -static void wdg_timeout_handler (struct timer_list *t) -{ - struct _adapter *adapter = - from_timer(adapter, t, mlmepriv.wdg_timer); - - r8712_wdg_wk_cmd(adapter); - - mod_timer(&adapter->mlmepriv.wdg_timer, - jiffies + msecs_to_jiffies(2000)); -} - -void r8712_init_mlme_timer(struct _adapter *adapter) -{ - struct mlme_priv *mlmepriv = &adapter->mlmepriv; - - timer_setup(&mlmepriv->assoc_timer, join_timeout_handler, 0); - timer_setup(&mlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer, - sitesurvey_ctrl_handler, 0); - timer_setup(&mlmepriv->scan_to_timer, _scan_timeout_handler, 0); - timer_setup(&mlmepriv->dhcp_timer, dhcp_timeout_handler, 0); - timer_setup(&mlmepriv->wdg_timer, wdg_timeout_handler, 0); -} - -void r8712_os_indicate_connect(struct _adapter *adapter) -{ - r8712_indicate_wx_assoc_event(adapter); - netif_carrier_on(adapter->pnetdev); -} - -static struct RT_PMKID_LIST backup_PMKID_list[NUM_PMKID_CACHE]; -void r8712_os_indicate_disconnect(struct _adapter *adapter) -{ - u8 backup_PMKID_index = 0; - u8 backup_TKIP_countermeasure = 0x00; - - r8712_indicate_wx_disassoc_event(adapter); - netif_carrier_off(adapter->pnetdev); - if (adapter->securitypriv.AuthAlgrthm == 2) { /*/802.1x*/ - /* We have to backup the PMK information for WiFi PMK Caching - * test item. Backup the btkip_countermeasure information. - * When the countermeasure is trigger, the driver have to - * disconnect with AP for 60 seconds. - */ - - memcpy(&backup_PMKID_list[0], - &adapter->securitypriv.PMKIDList[0], - sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); - backup_PMKID_index = adapter->securitypriv.PMKIDIndex; - backup_TKIP_countermeasure = - adapter->securitypriv.btkip_countermeasure; - memset((unsigned char *)&adapter->securitypriv, 0, - sizeof(struct security_priv)); - timer_setup(&adapter->securitypriv.tkip_timer, - r8712_use_tkipkey_handler, 0); - /* Restore the PMK information to securitypriv structure - * for the following connection. - */ - memcpy(&adapter->securitypriv.PMKIDList[0], - &backup_PMKID_list[0], - sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); - adapter->securitypriv.PMKIDIndex = backup_PMKID_index; - adapter->securitypriv.btkip_countermeasure = - backup_TKIP_countermeasure; - } else { /*reset values in securitypriv*/ - struct security_priv *sec_priv = &adapter->securitypriv; - - sec_priv->AuthAlgrthm = 0; /*open system*/ - sec_priv->PrivacyAlgrthm = _NO_PRIVACY_; - sec_priv->PrivacyKeyIndex = 0; - sec_priv->XGrpPrivacy = _NO_PRIVACY_; - sec_priv->XGrpKeyid = 1; - sec_priv->ndisauthtype = Ndis802_11AuthModeOpen; - sec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; - sec_priv->wps_phase = false; - } -} - -void r8712_report_sec_ie(struct _adapter *adapter, u8 authmode, u8 *sec_ie) -{ - uint len; - u8 *buff, *p, i; - union iwreq_data wrqu; - - buff = NULL; - if (authmode == _WPA_IE_ID_) { - buff = kzalloc(IW_CUSTOM_MAX, GFP_ATOMIC); - if (!buff) - return; - p = buff; - p += sprintf(p, "ASSOCINFO(ReqIEs="); - len = sec_ie[1] + 2; - len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX; - for (i = 0; i < len; i++) - p += sprintf(p, "%02x", sec_ie[i]); - p += sprintf(p, ")"); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = p - buff; - wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? - wrqu.data.length : IW_CUSTOM_MAX; - wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff); - kfree(buff); - } -} diff --git a/drivers/staging/rtl8712/mlme_osdep.h b/drivers/staging/rtl8712/mlme_osdep.h deleted file mode 100644 index a02c782588ddbf..00000000000000 --- a/drivers/staging/rtl8712/mlme_osdep.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __MLME_OSDEP_H_ -#define __MLME_OSDEP_H_ - -#include "osdep_service.h" -#include "drv_types.h" - -void r8712_init_mlme_timer(struct _adapter *padapter); -void r8712_os_indicate_disconnect(struct _adapter *adapter); -void r8712_os_indicate_connect(struct _adapter *adapter); -void r8712_report_sec_ie(struct _adapter *adapter, u8 authmode, u8 *sec_ie); -int r8712_recv_indicatepkts_in_order(struct _adapter *adapter, - struct recv_reorder_ctrl *precvreorder_ctrl, - int bforced); -void r8712_indicate_wx_assoc_event(struct _adapter *padapter); -void r8712_indicate_wx_disassoc_event(struct _adapter *padapter); - -#endif /*_MLME_OSDEP_H_*/ - diff --git a/drivers/staging/rtl8712/mp_custom_oid.h b/drivers/staging/rtl8712/mp_custom_oid.h deleted file mode 100644 index a9fac87fcabc59..00000000000000 --- a/drivers/staging/rtl8712/mp_custom_oid.h +++ /dev/null @@ -1,287 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __CUSTOM_OID_H -#define __CUSTOM_OID_H - -/* 0xFF818000 - 0xFF81802F RTL8180 Mass Production Kit - * 0xFF818500 - 0xFF81850F RTL8185 Setup Utility - * 0xFF818580 - 0xFF81858F RTL8185 Phy Status Utility - * - * by Owen for Production Kit - * For Production Kit with Agilent Equipments - * in order to make our custom oids hopefully somewhat unique - * we will use 0xFF (indicating implementation specific OID) - * 81(first byte of non zero Realtek unique identifier) - * 80 (second byte of non zero Realtek unique identifier) - * XX (the custom OID number - providing 255 possible custom oids) - */ -#define OID_RT_PRO_RESET_DUT 0xFF818000 -#define OID_RT_PRO_SET_DATA_RATE 0xFF818001 -#define OID_RT_PRO_START_TEST 0xFF818002 -#define OID_RT_PRO_STOP_TEST 0xFF818003 -#define OID_RT_PRO_SET_PREAMBLE 0xFF818004 -#define OID_RT_PRO_SET_SCRAMBLER 0xFF818005 -#define OID_RT_PRO_SET_FILTER_BB 0xFF818006 -#define OID_RT_PRO_SET_MANUAL_DIVERSITY_BB 0xFF818007 -#define OID_RT_PRO_SET_CHANNEL_DIRECT_CALL 0xFF818008 -#define OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL 0xFF818009 -#define OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL 0xFF81800A - -#define OID_RT_PRO_SET_TX_ANTENNA_BB 0xFF81800D -#define OID_RT_PRO_SET_ANTENNA_BB 0xFF81800E -#define OID_RT_PRO_SET_CR_SCRAMBLER 0xFF81800F -#define OID_RT_PRO_SET_CR_NEW_FILTER 0xFF818010 -#define OID_RT_PRO_SET_TX_POWER_CONTROL 0xFF818011 -#define OID_RT_PRO_SET_CR_TX_CONFIG 0xFF818012 -#define OID_RT_PRO_GET_TX_POWER_CONTROL 0xFF818013 -#define OID_RT_PRO_GET_CR_SIGNAL_QUALITY 0xFF818014 -#define OID_RT_PRO_SET_CR_SETPOINT 0xFF818015 -#define OID_RT_PRO_SET_INTEGRATOR 0xFF818016 -#define OID_RT_PRO_SET_SIGNAL_QUALITY 0xFF818017 -#define OID_RT_PRO_GET_INTEGRATOR 0xFF818018 -#define OID_RT_PRO_GET_SIGNAL_QUALITY 0xFF818019 -#define OID_RT_PRO_QUERY_EEPROM_TYPE 0xFF81801A -#define OID_RT_PRO_WRITE_MAC_ADDRESS 0xFF81801B -#define OID_RT_PRO_READ_MAC_ADDRESS 0xFF81801C -#define OID_RT_PRO_WRITE_CIS_DATA 0xFF81801D -#define OID_RT_PRO_READ_CIS_DATA 0xFF81801E -#define OID_RT_PRO_WRITE_POWER_CONTROL 0xFF81801F -#define OID_RT_PRO_READ_POWER_CONTROL 0xFF818020 -#define OID_RT_PRO_WRITE_EEPROM 0xFF818021 -#define OID_RT_PRO_READ_EEPROM 0xFF818022 -#define OID_RT_PRO_RESET_TX_PACKET_SENT 0xFF818023 -#define OID_RT_PRO_QUERY_TX_PACKET_SENT 0xFF818024 -#define OID_RT_PRO_RESET_RX_PACKET_RECEIVED 0xFF818025 -#define OID_RT_PRO_QUERY_RX_PACKET_RECEIVED 0xFF818026 -#define OID_RT_PRO_QUERY_RX_PACKET_CRC32_ERROR 0xFF818027 -#define OID_RT_PRO_QUERY_CURRENT_ADDRESS 0xFF818028 -#define OID_RT_PRO_QUERY_PERMANENT_ADDRESS 0xFF818029 -#define OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS 0xFF81802A -#define OID_RT_PRO_RECEIVE_PACKET 0xFF81802C -#define OID_RT_PRO_WRITE_EEPROM_BYTE 0xFF81802D -#define OID_RT_PRO_READ_EEPROM_BYTE 0xFF81802E -#define OID_RT_PRO_SET_MODULATION 0xFF81802F -#define OID_RT_DRIVER_OPTION 0xFF818080 -#define OID_RT_RF_OFF 0xFF818081 -#define OID_RT_AUTH_STATUS 0xFF818082 -#define OID_RT_PRO_SET_CONTINUOUS_TX 0xFF81800B -#define OID_RT_PRO_SET_SINGLE_CARRIER_TX 0xFF81800C -#define OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX 0xFF81802B -#define OID_RT_PRO_SET_SINGLE_TONE_TX 0xFF818043 -#define OID_RT_UTILITY_FALSE_ALARM_COUNTERS 0xFF818580 -#define OID_RT_UTILITY_SELECT_DEBUG_MODE 0xFF818581 -#define OID_RT_UTILITY_SELECT_SUBCARRIER_NUMBER 0xFF818582 -#define OID_RT_UTILITY_GET_RSSI_STATUS 0xFF818583 -#define OID_RT_UTILITY_GET_FRAME_DETECTION_STATUS 0xFF818584 -#define OID_RT_UTILITY_GET_AGC_AND_FREQUENCY_OFFSET_ESTIMATION_STATUS \ - 0xFF818585 -#define OID_RT_UTILITY_GET_CHANNEL_ESTIMATION_STATUS 0xFF818586 -#define OID_RT_WIRELESS_MODE 0xFF818500 -#define OID_RT_SUPPORTED_RATES 0xFF818501 -#define OID_RT_DESIRED_RATES 0xFF818502 -#define OID_RT_WIRELESS_MODE_STARTING_ADHOC 0xFF818503 -#define OID_RT_GET_CONNECT_STATE 0xFF030001 -#define OID_RT_RESCAN 0xFF030002 -#define OID_RT_SET_KEY_LENGTH 0xFF030003 -#define OID_RT_SET_DEFAULT_KEY_ID 0xFF030004 -#define OID_RT_SET_CHANNEL 0xFF010182 -#define OID_RT_SET_SNIFFER_MODE 0xFF010183 -#define OID_RT_GET_SIGNAL_QUALITY 0xFF010184 -#define OID_RT_GET_SMALL_PACKET_CRC 0xFF010185 -#define OID_RT_GET_MIDDLE_PACKET_CRC 0xFF010186 -#define OID_RT_GET_LARGE_PACKET_CRC 0xFF010187 -#define OID_RT_GET_TX_RETRY 0xFF010188 -#define OID_RT_GET_RX_RETRY 0xFF010189 -#define OID_RT_PRO_SET_FW_DIG_STATE 0xFF01018A -#define OID_RT_PRO_SET_FW_RA_STATE 0xFF01018B -#define OID_RT_GET_RX_TOTAL_PACKET 0xFF010190 -#define OID_RT_GET_TX_BEACON_OK 0xFF010191 -#define OID_RT_GET_TX_BEACON_ERR 0xFF010192 -#define OID_RT_GET_RX_ICV_ERR 0xFF010193 -#define OID_RT_SET_ENCRYPTION_ALGORITHM 0xFF010194 -#define OID_RT_SET_NO_AUTO_RESCAN 0xFF010195 -#define OID_RT_GET_PREAMBLE_MODE 0xFF010196 -#define OID_RT_GET_DRIVER_UP_DELTA_TIME 0xFF010197 -#define OID_RT_GET_AP_IP 0xFF010198 -#define OID_RT_GET_CHANNELPLAN 0xFF010199 -#define OID_RT_SET_PREAMBLE_MODE 0xFF01019A -#define OID_RT_SET_BCN_INTVL 0xFF01019B -#define OID_RT_GET_RF_VENDER 0xFF01019C -#define OID_RT_DEDICATE_PROBE 0xFF01019D -#define OID_RT_PRO_RX_FILTER_PATTERN 0xFF01019E -#define OID_RT_GET_DCST_CURRENT_THRESHOLD 0xFF01019F -#define OID_RT_GET_CCA_ERR 0xFF0101A0 -#define OID_RT_GET_CCA_UPGRADE_THRESHOLD 0xFF0101A1 -#define OID_RT_GET_CCA_FALLBACK_THRESHOLD 0xFF0101A2 -#define OID_RT_GET_CCA_UPGRADE_EVALUATE_TIMES 0xFF0101A3 -#define OID_RT_GET_CCA_FALLBACK_EVALUATE_TIMES 0xFF0101A4 -#define OID_RT_SET_RATE_ADAPTIVE 0xFF0101A5 -#define OID_RT_GET_DCST_EVALUATE_PERIOD 0xFF0101A5 -#define OID_RT_GET_DCST_TIME_UNIT_INDEX 0xFF0101A6 -#define OID_RT_GET_TOTAL_TX_BYTES 0xFF0101A7 -#define OID_RT_GET_TOTAL_RX_BYTES 0xFF0101A8 -#define OID_RT_CURRENT_TX_POWER_LEVEL 0xFF0101A9 -#define OID_RT_GET_ENC_KEY_MISMATCH_COUNT 0xFF0101AA -#define OID_RT_GET_ENC_KEY_MATCH_COUNT 0xFF0101AB -#define OID_RT_GET_CHANNEL 0xFF0101AC -#define OID_RT_SET_CHANNELPLAN 0xFF0101AD -#define OID_RT_GET_HARDWARE_RADIO_OFF 0xFF0101AE -#define OID_RT_CHANNELPLAN_BY_COUNTRY 0xFF0101AF -#define OID_RT_SCAN_AVAILABLE_BSSID 0xFF0101B0 -#define OID_RT_GET_HARDWARE_VERSION 0xFF0101B1 -#define OID_RT_GET_IS_ROAMING 0xFF0101B2 -#define OID_RT_GET_IS_PRIVACY 0xFF0101B3 -#define OID_RT_GET_KEY_MISMATCH 0xFF0101B4 -#define OID_RT_SET_RSSI_ROAM_TRAFFIC_TH 0xFF0101B5 -#define OID_RT_SET_RSSI_ROAM_SIGNAL_TH 0xFF0101B6 -#define OID_RT_RESET_LOG 0xFF0101B7 -#define OID_RT_GET_LOG 0xFF0101B8 -#define OID_RT_SET_INDICATE_HIDDEN_AP 0xFF0101B9 -#define OID_RT_GET_HEADER_FAIL 0xFF0101BA -#define OID_RT_SUPPORTED_WIRELESS_MODE 0xFF0101BB -#define OID_RT_GET_CHANNEL_LIST 0xFF0101BC -#define OID_RT_GET_SCAN_IN_PROGRESS 0xFF0101BD -#define OID_RT_GET_TX_INFO 0xFF0101BE -#define OID_RT_RF_READ_WRITE_OFFSET 0xFF0101BF -#define OID_RT_RF_READ_WRITE 0xFF0101C0 -#define OID_RT_FORCED_DATA_RATE 0xFF0101C1 -#define OID_RT_WIRELESS_MODE_FOR_SCAN_LIST 0xFF0101C2 -#define OID_RT_GET_BSS_WIRELESS_MODE 0xFF0101C3 -#define OID_RT_SCAN_WITH_MAGIC_PACKET 0xFF0101C4 -#define OID_RT_PRO_RX_FILTER 0xFF0111C0 -#define OID_CE_USB_WRITE_REGISTRY 0xFF0111C1 -#define OID_CE_USB_READ_REGISTRY 0xFF0111C2 -#define OID_RT_PRO_SET_INITIAL_GAIN 0xFF0111C3 -#define OID_RT_PRO_SET_BB_RF_STANDBY_MODE 0xFF0111C4 -#define OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE 0xFF0111C5 -#define OID_RT_PRO_SET_TX_CHARGE_PUMP 0xFF0111C6 -#define OID_RT_PRO_SET_RX_CHARGE_PUMP 0xFF0111C7 -#define OID_RT_PRO_RF_WRITE_REGISTRY 0xFF0111C8 -#define OID_RT_PRO_RF_READ_REGISTRY 0xFF0111C9 -#define OID_RT_PRO_QUERY_RF_TYPE 0xFF0111CA -#define OID_RT_AP_GET_ASSOCIATED_STATION_LIST 0xFF010300 -#define OID_RT_AP_GET_CURRENT_TIME_STAMP 0xFF010301 -#define OID_RT_AP_SWITCH_INTO_AP_MODE 0xFF010302 -#define OID_RT_AP_SET_DTIM_PERIOD 0xFF010303 -#define OID_RT_AP_SUPPORTED 0xFF010304 -#define OID_RT_AP_SET_PASSPHRASE 0xFF010305 -#define OID_RT_PRO8187_WI_POLL 0xFF818780 -#define OID_RT_PRO_WRITE_BB_REG 0xFF818781 -#define OID_RT_PRO_READ_BB_REG 0xFF818782 -#define OID_RT_PRO_WRITE_RF_REG 0xFF818783 -#define OID_RT_PRO_READ_RF_REG 0xFF818784 -#define OID_RT_MH_VENDER_ID 0xFFEDC100 -#define OID_RT_PRO8711_JOIN_BSS 0xFF871100 -#define OID_RT_PRO_READ_REGISTER 0xFF871101 -#define OID_RT_PRO_WRITE_REGISTER 0xFF871102 -#define OID_RT_PRO_BURST_READ_REGISTER 0xFF871103 -#define OID_RT_PRO_BURST_WRITE_REGISTER 0xFF871104 -#define OID_RT_PRO_WRITE_TXCMD 0xFF871105 -#define OID_RT_PRO_READ16_EEPROM 0xFF871106 -#define OID_RT_PRO_WRITE16_EEPROM 0xFF871107 -#define OID_RT_PRO_H2C_SET_COMMAND 0xFF871108 -#define OID_RT_PRO_H2C_QUERY_RESULT 0xFF871109 -#define OID_RT_PRO8711_WI_POLL 0xFF87110A -#define OID_RT_PRO8711_PKT_LOSS 0xFF87110B -#define OID_RT_RD_ATTRIB_MEM 0xFF87110C -#define OID_RT_WR_ATTRIB_MEM 0xFF87110D -/*Method 2 for H2C/C2H*/ -#define OID_RT_PRO_H2C_CMD_MODE 0xFF871110 -#define OID_RT_PRO_H2C_CMD_RSP_MODE 0xFF871111 -#define OID_RT_PRO_H2C_CMD_EVENT_MODE 0xFF871112 -#define OID_RT_PRO_WAIT_C2H_EVENT 0xFF871113 -#define OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST 0xFF871114 -#define OID_RT_PRO_SCSI_ACCESS_TEST 0xFF871115 -#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT 0xFF871116 -#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN 0xFF871117 -#define OID_RT_RRO_RX_PKT_VIA_IOCTRL 0xFF871118 -#define OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL 0xFF871119 -#define OID_RT_RPO_SET_PWRMGT_TEST 0xFF87111A -#define OID_RT_PRO_QRY_PWRMGT_TEST 0XFF87111B -#define OID_RT_RPO_ASYNC_RWIO_TEST 0xFF87111C -#define OID_RT_RPO_ASYNC_RWIO_POLL 0xFF87111D -#define OID_RT_PRO_SET_RF_INTFS 0xFF87111E -#define OID_RT_POLL_RX_STATUS 0xFF87111F -#define OID_RT_PRO_CFG_DEBUG_MESSAGE 0xFF871120 -#define OID_RT_PRO_SET_DATA_RATE_EX 0xFF871121 -#define OID_RT_PRO_SET_BASIC_RATE 0xFF871122 -#define OID_RT_PRO_READ_TSSI 0xFF871123 -#define OID_RT_PRO_SET_POWER_TRACKING 0xFF871124 -#define OID_RT_PRO_QRY_PWRSTATE 0xFF871150 -#define OID_RT_PRO_SET_PWRSTATE 0xFF871151 -/*Method 2 , using workitem */ -#define OID_RT_SET_READ_REG 0xFF871181 -#define OID_RT_SET_WRITE_REG 0xFF871182 -#define OID_RT_SET_BURST_READ_REG 0xFF871183 -#define OID_RT_SET_BURST_WRITE_REG 0xFF871184 -#define OID_RT_SET_WRITE_TXCMD 0xFF871185 -#define OID_RT_SET_READ16_EEPROM 0xFF871186 -#define OID_RT_SET_WRITE16_EEPROM 0xFF871187 -#define OID_RT_QRY_POLL_WKITEM 0xFF871188 - -/*For SDIO INTERFACE only*/ -#define OID_RT_PRO_SYNCPAGERW_SRAM 0xFF8711A0 -#define OID_RT_PRO_871X_DRV_EXT 0xFF8711A1 - -/*For USB INTERFACE only*/ -#define OID_RT_PRO_USB_VENDOR_REQ 0xFF8711B0 -#define OID_RT_PRO_SCSI_AUTO_TEST 0xFF8711B1 -#define OID_RT_PRO_USB_MAC_AC_FIFO_WRITE 0xFF8711B2 -#define OID_RT_PRO_USB_MAC_RX_FIFO_READ 0xFF8711B3 -#define OID_RT_PRO_USB_MAC_RX_FIFO_POLLING 0xFF8711B4 - -#define OID_RT_PRO_H2C_SET_RATE_TABLE 0xFF8711FB -#define OID_RT_PRO_H2C_GET_RATE_TABLE 0xFF8711FC -#define OID_RT_PRO_H2C_C2H_LBK_TEST 0xFF8711FE - -#define OID_RT_PRO_ENCRYPTION_CTRL 0xFF871200 -#define OID_RT_PRO_ADD_STA_INFO 0xFF871201 -#define OID_RT_PRO_DELE_STA_INFO 0xFF871202 -#define OID_RT_PRO_QUERY_DR_VARIABLE 0xFF871203 - -#define OID_RT_PRO_RX_PACKET_TYPE 0xFF871204 - -#define OID_RT_PRO_READ_EFUSE 0xFF871205 -#define OID_RT_PRO_WRITE_EFUSE 0xFF871206 -#define OID_RT_PRO_RW_EFUSE_PGPKT 0xFF871207 -#define OID_RT_GET_EFUSE_CURRENT_SIZE 0xFF871208 - -#define OID_RT_SET_BANDWIDTH 0xFF871209 -#define OID_RT_SET_CRYSTAL_CAP 0xFF87120A - -#define OID_RT_SET_RX_PACKET_TYPE 0xFF87120B - -#define OID_RT_GET_EFUSE_MAX_SIZE 0xFF87120C - -#define OID_RT_PRO_SET_TX_AGC_OFFSET 0xFF87120D - -#define OID_RT_PRO_SET_PKT_TEST_MODE 0xFF87120E - -#define OID_RT_PRO_FOR_EVM_TEST_SETTING 0xFF87120F - -#define OID_RT_PRO_GET_THERMAL_METER 0xFF871210 - -#define OID_RT_RESET_PHY_RX_PACKET_COUNT 0xFF871211 -#define OID_RT_GET_PHY_RX_PACKET_RECEIVED 0xFF871212 -#define OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR 0xFF871213 - -#define OID_RT_SET_POWER_DOWN 0xFF871214 - -#define OID_RT_GET_POWER_MODE 0xFF871215 - -#define OID_RT_PRO_EFUSE 0xFF871216 -#define OID_RT_PRO_EFUSE_MAP 0xFF871217 - -#endif /*#ifndef __CUSTOM_OID_H */ - diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c deleted file mode 100644 index 1b11f8b04e13f2..00000000000000 --- a/drivers/staging/rtl8712/os_intfs.c +++ /dev/null @@ -1,482 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * os_intfs.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE . - * Larry Finger - * - ******************************************************************************/ - -#define _OS_INTFS_C_ - -#include -#include -#include -#include "osdep_service.h" -#include "drv_types.h" -#include "xmit_osdep.h" -#include "recv_osdep.h" -#include "rtl871x_ioctl.h" -#include "usb_osintf.h" - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("rtl871x wireless lan driver"); -MODULE_AUTHOR("Larry Finger"); - -static char ifname[IFNAMSIZ] = "wlan%d"; - -/* module param defaults */ -static int chip_version = RTL8712_2ndCUT; -static int rfintfs = HWPI; -static int lbkmode = RTL8712_AIR_TRX; -static int hci = RTL8712_USB; -static int ampdu_enable = 1;/*for enable tx_ampdu*/ - -/* The video_mode variable is for video mode.*/ -/* It may be specify when inserting module with video_mode=1 parameter.*/ -static int video_mode = 1; /* enable video mode*/ - -/*Ndis802_11Infrastructure; infra, ad-hoc, auto*/ -static int network_mode = Ndis802_11IBSS; -static int channel = 1;/*ad-hoc support requirement*/ -static int wireless_mode = WIRELESS_11BG; -static int vrtl_carrier_sense = AUTO_VCS; -static int vcs_type = RTS_CTS; -static int frag_thresh = 2346; -static int preamble = PREAMBLE_LONG;/*long, short, auto*/ -static int scan_mode = 1;/*active, passive*/ -static int adhoc_tx_pwr = 1; -static int soft_ap; -static int smart_ps = 1; -static int power_mgnt = PS_MODE_ACTIVE; -static int radio_enable = 1; -static int long_retry_lmt = 7; -static int short_retry_lmt = 7; -static int busy_thresh = 40; -static int ack_policy = NORMAL_ACK; -static int mp_mode; -static int software_encrypt; -static int software_decrypt; - -static int wmm_enable;/* default is set to disable the wmm.*/ -static int uapsd_enable; -static int uapsd_max_sp = NO_LIMIT; -static int uapsd_acbk_en; -static int uapsd_acbe_en; -static int uapsd_acvi_en; -static int uapsd_acvo_en; - -static int ht_enable = 1; -static int cbw40_enable = 1; -static int rf_config = RTL8712_RF_1T2R; /* 1T2R*/ -static int low_power; -/* mac address to use instead of the one stored in Efuse */ -char *r8712_initmac; -static char *initmac; -/* if wifi_test = 1, driver will disable the turbo mode and pass it to - * firmware private. - */ -static int wifi_test; - -module_param_string(ifname, ifname, sizeof(ifname), 0644); -module_param(wifi_test, int, 0644); -module_param(initmac, charp, 0644); -module_param(video_mode, int, 0644); -module_param(chip_version, int, 0644); -module_param(rfintfs, int, 0644); -module_param(lbkmode, int, 0644); -module_param(hci, int, 0644); -module_param(network_mode, int, 0644); -module_param(channel, int, 0644); -module_param(mp_mode, int, 0644); -module_param(wmm_enable, int, 0644); -module_param(vrtl_carrier_sense, int, 0644); -module_param(vcs_type, int, 0644); -module_param(busy_thresh, int, 0644); -module_param(ht_enable, int, 0644); -module_param(cbw40_enable, int, 0644); -module_param(ampdu_enable, int, 0644); -module_param(rf_config, int, 0644); -module_param(power_mgnt, int, 0644); -module_param(low_power, int, 0644); - -MODULE_PARM_DESC(ifname, " Net interface name, wlan%d=default"); -MODULE_PARM_DESC(initmac, "MAC-Address, default: use FUSE"); - -static int netdev_open(struct net_device *pnetdev); -static int netdev_close(struct net_device *pnetdev); - -static void loadparam(struct _adapter *padapter, struct net_device *pnetdev) -{ - struct registry_priv *registry_par = &padapter->registrypriv; - - registry_par->chip_version = (u8)chip_version; - registry_par->rfintfs = (u8)rfintfs; - registry_par->lbkmode = (u8)lbkmode; - registry_par->hci = (u8)hci; - registry_par->network_mode = (u8)network_mode; - memcpy(registry_par->ssid.Ssid, "ANY", 3); - registry_par->ssid.SsidLength = 3; - registry_par->channel = (u8)channel; - registry_par->wireless_mode = (u8)wireless_mode; - registry_par->vrtl_carrier_sense = (u8)vrtl_carrier_sense; - registry_par->vcs_type = (u8)vcs_type; - registry_par->frag_thresh = (u16)frag_thresh; - registry_par->preamble = (u8)preamble; - registry_par->scan_mode = (u8)scan_mode; - registry_par->adhoc_tx_pwr = (u8)adhoc_tx_pwr; - registry_par->soft_ap = (u8)soft_ap; - registry_par->smart_ps = (u8)smart_ps; - registry_par->power_mgnt = (u8)power_mgnt; - registry_par->radio_enable = (u8)radio_enable; - registry_par->long_retry_lmt = (u8)long_retry_lmt; - registry_par->short_retry_lmt = (u8)short_retry_lmt; - registry_par->busy_thresh = (u16)busy_thresh; - registry_par->ack_policy = (u8)ack_policy; - registry_par->mp_mode = (u8)mp_mode; - registry_par->software_encrypt = (u8)software_encrypt; - registry_par->software_decrypt = (u8)software_decrypt; - /*UAPSD*/ - registry_par->wmm_enable = (u8)wmm_enable; - registry_par->uapsd_enable = (u8)uapsd_enable; - registry_par->uapsd_max_sp = (u8)uapsd_max_sp; - registry_par->uapsd_acbk_en = (u8)uapsd_acbk_en; - registry_par->uapsd_acbe_en = (u8)uapsd_acbe_en; - registry_par->uapsd_acvi_en = (u8)uapsd_acvi_en; - registry_par->uapsd_acvo_en = (u8)uapsd_acvo_en; - registry_par->ht_enable = (u8)ht_enable; - registry_par->cbw40_enable = (u8)cbw40_enable; - registry_par->ampdu_enable = (u8)ampdu_enable; - registry_par->rf_config = (u8)rf_config; - registry_par->low_power = (u8)low_power; - registry_par->wifi_test = (u8)wifi_test; - r8712_initmac = initmac; -} - -static int r871x_net_set_mac_address(struct net_device *pnetdev, void *p) -{ - struct _adapter *padapter = netdev_priv(pnetdev); - struct sockaddr *addr = p; - - if (!padapter->bup) - eth_hw_addr_set(pnetdev, addr->sa_data); - return 0; -} - -static struct net_device_stats *r871x_net_get_stats(struct net_device *pnetdev) -{ - struct _adapter *padapter = netdev_priv(pnetdev); - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct recv_priv *precvpriv = &padapter->recvpriv; - - padapter->stats.tx_packets = pxmitpriv->tx_pkts; - padapter->stats.rx_packets = precvpriv->rx_pkts; - padapter->stats.tx_dropped = pxmitpriv->tx_drop; - padapter->stats.rx_dropped = precvpriv->rx_drop; - padapter->stats.tx_bytes = pxmitpriv->tx_bytes; - padapter->stats.rx_bytes = precvpriv->rx_bytes; - return &padapter->stats; -} - -static const struct net_device_ops rtl8712_netdev_ops = { - .ndo_open = netdev_open, - .ndo_stop = netdev_close, - .ndo_start_xmit = r8712_xmit_entry, - .ndo_set_mac_address = r871x_net_set_mac_address, - .ndo_get_stats = r871x_net_get_stats, - .ndo_do_ioctl = r871x_ioctl, -}; - -struct net_device *r8712_init_netdev(void) -{ - struct _adapter *padapter; - struct net_device *pnetdev; - - pnetdev = alloc_etherdev(sizeof(struct _adapter)); - if (!pnetdev) - return NULL; - if (dev_alloc_name(pnetdev, ifname) < 0) { - strscpy(ifname, "wlan%d", sizeof(ifname)); - dev_alloc_name(pnetdev, ifname); - } - padapter = netdev_priv(pnetdev); - padapter->pnetdev = pnetdev; - pr_info("r8712u: register rtl8712_netdev_ops to netdev_ops\n"); - pnetdev->netdev_ops = &rtl8712_netdev_ops; - pnetdev->watchdog_timeo = HZ; /* 1 second timeout */ - pnetdev->wireless_handlers = (struct iw_handler_def *) - &r871x_handlers_def; - loadparam(padapter, pnetdev); - netif_carrier_off(pnetdev); - padapter->pid = 0; /* Initial the PID value used for HW PBC.*/ - return pnetdev; -} - -static u32 start_drv_threads(struct _adapter *padapter) -{ - padapter->cmd_thread = kthread_run(r8712_cmd_thread, padapter, "%s", - padapter->pnetdev->name); - if (IS_ERR(padapter->cmd_thread)) - return _FAIL; - return _SUCCESS; -} - -void r8712_stop_drv_threads(struct _adapter *padapter) -{ - struct completion *completion = - &padapter->cmdpriv.terminate_cmdthread_comp; - - /*Below is to terminate r8712_cmd_thread & event_thread...*/ - complete(&padapter->cmdpriv.cmd_queue_comp); - if (padapter->cmd_thread) - wait_for_completion_interruptible(completion); - padapter->cmdpriv.cmd_seq = 1; -} - -static void start_drv_timers(struct _adapter *padapter) -{ - mod_timer(&padapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, - jiffies + msecs_to_jiffies(5000)); - mod_timer(&padapter->mlmepriv.wdg_timer, - jiffies + msecs_to_jiffies(2000)); -} - -void r8712_stop_drv_timers(struct _adapter *padapter) -{ - del_timer_sync(&padapter->mlmepriv.assoc_timer); - del_timer_sync(&padapter->securitypriv.tkip_timer); - del_timer_sync(&padapter->mlmepriv.scan_to_timer); - del_timer_sync(&padapter->mlmepriv.dhcp_timer); - del_timer_sync(&padapter->mlmepriv.wdg_timer); - del_timer_sync(&padapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer); -} - -static void init_default_value(struct _adapter *padapter) -{ - struct registry_priv *pregistrypriv = &padapter->registrypriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - - /*xmit_priv*/ - pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; - pxmitpriv->vcs = pregistrypriv->vcs_type; - pxmitpriv->vcs_type = pregistrypriv->vcs_type; - pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; - pxmitpriv->frag_len = pregistrypriv->frag_thresh; - /* mlme_priv */ - /* Maybe someday we should rename this variable to "active_mode"(Jeff)*/ - pmlmepriv->passive_mode = 1; /* 1: active, 0: passive. */ - /*ht_priv*/ - { - int i; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - - phtpriv->ampdu_enable = false;/*set to disabled*/ - for (i = 0; i < 16; i++) - phtpriv->baddbareq_issued[i] = false; - } - /*security_priv*/ - psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt; - psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt; - psecuritypriv->binstallGrpkey = _FAIL; - /*pwrctrl_priv*/ - /*registry_priv*/ - r8712_init_registrypriv_dev_network(padapter); - r8712_update_registrypriv_dev_network(padapter); - /*misc.*/ -} - -int r8712_init_drv_sw(struct _adapter *padapter) -{ - int ret; - - ret = r8712_init_cmd_priv(&padapter->cmdpriv); - if (ret) - return ret; - padapter->cmdpriv.padapter = padapter; - ret = r8712_init_evt_priv(&padapter->evtpriv); - if (ret) - goto free_cmd; - ret = r8712_init_mlme_priv(padapter); - if (ret) - goto free_evt; - ret = _r8712_init_xmit_priv(&padapter->xmitpriv, padapter); - if (ret) - goto free_mlme; - ret = _r8712_init_recv_priv(&padapter->recvpriv, padapter); - if (ret) - goto free_xmit; - memset((unsigned char *)&padapter->securitypriv, 0, - sizeof(struct security_priv)); - timer_setup(&padapter->securitypriv.tkip_timer, - r8712_use_tkipkey_handler, 0); - ret = _r8712_init_sta_priv(&padapter->stapriv); - if (ret) - goto free_recv; - padapter->stapriv.padapter = padapter; - r8712_init_bcmc_stainfo(padapter); - r8712_init_pwrctrl_priv(padapter); - mp871xinit(padapter); - init_default_value(padapter); - r8712_InitSwLeds(padapter); - mutex_init(&padapter->mutex_start); - - return 0; - -free_recv: - _r8712_free_recv_priv(&padapter->recvpriv); -free_xmit: - _free_xmit_priv(&padapter->xmitpriv); -free_mlme: - r8712_free_mlme_priv(&padapter->mlmepriv); -free_evt: - r8712_free_evt_priv(&padapter->evtpriv); -free_cmd: - r8712_free_cmd_priv(&padapter->cmdpriv); - return ret; -} - -void r8712_free_drv_sw(struct _adapter *padapter) -{ - r8712_free_cmd_priv(&padapter->cmdpriv); - r8712_free_evt_priv(&padapter->evtpriv); - r8712_DeInitSwLeds(padapter); - r8712_free_mlme_priv(&padapter->mlmepriv); - _free_xmit_priv(&padapter->xmitpriv); - _r8712_free_sta_priv(&padapter->stapriv); - _r8712_free_recv_priv(&padapter->recvpriv); - mp871xdeinit(padapter); -} - -static void enable_video_mode(struct _adapter *padapter, int cbw40_value) -{ - /* bit 8: - * 1 -> enable video mode to 96B AP - * 0 -> disable video mode to 96B AP - * bit 9: - * 1 -> enable 40MHz mode - * 0 -> disable 40MHz mode - * bit 10: - * 1 -> enable STBC - * 0 -> disable STBC - */ - u32 intcmd = 0xf4000500; /* enable bit8, bit10*/ - - if (cbw40_value) { - /* if the driver supports the 40M bandwidth, - * we can enable the bit 9. - */ - intcmd |= 0x200; - } - r8712_fw_cmd(padapter, intcmd); -} - -/* - * - * This function intends to handle the activation of an interface - * i.e. when it is brought Up/Active from a Down state. - * - */ -static int netdev_open(struct net_device *pnetdev) -{ - struct _adapter *padapter = netdev_priv(pnetdev); - - mutex_lock(&padapter->mutex_start); - if (!padapter->bup) { - padapter->driver_stopped = false; - padapter->surprise_removed = false; - padapter->bup = true; - if (rtl871x_hal_init(padapter) != _SUCCESS) - goto netdev_open_error; - if (!r8712_initmac) { - /* Use the mac address stored in the Efuse */ - eth_hw_addr_set(pnetdev, - padapter->eeprompriv.mac_addr); - } else { - /* We have to inform f/w to use user-supplied MAC - * address. - */ - msleep(200); - r8712_setMacAddr_cmd(padapter, - (const u8 *)pnetdev->dev_addr); - /* - * The "myid" function will get the wifi mac address - * from eeprompriv structure instead of netdev - * structure. So, we have to overwrite the mac_addr - * stored in the eeprompriv structure. In this case, - * the real mac address won't be used anymore. So that, - * the eeprompriv.mac_addr should store the mac which - * users specify. - */ - memcpy(padapter->eeprompriv.mac_addr, - pnetdev->dev_addr, ETH_ALEN); - } - if (start_drv_threads(padapter) != _SUCCESS) - goto netdev_open_error; - if (!padapter->dvobjpriv.inirp_init) - goto netdev_open_error; - else - padapter->dvobjpriv.inirp_init(padapter); - r8712_set_ps_mode(padapter, padapter->registrypriv.power_mgnt, - padapter->registrypriv.smart_ps); - } - if (!netif_queue_stopped(pnetdev)) - netif_start_queue(pnetdev); - else - netif_wake_queue(pnetdev); - - if (video_mode) - enable_video_mode(padapter, cbw40_enable); - /* start driver mlme relation timer */ - start_drv_timers(padapter); - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); - mutex_unlock(&padapter->mutex_start); - return 0; -netdev_open_error: - padapter->bup = false; - netif_carrier_off(pnetdev); - netif_stop_queue(pnetdev); - mutex_unlock(&padapter->mutex_start); - return -1; -} - -/* - * - * This function intends to handle the shutdown of an interface - * i.e. when it is brought Down from an Up/Active state. - * - */ -static int netdev_close(struct net_device *pnetdev) -{ - struct _adapter *padapter = netdev_priv(pnetdev); - - /* Close LED*/ - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_POWER_OFF); - msleep(200); - - /*s1.*/ - if (pnetdev) { - if (!netif_queue_stopped(pnetdev)) - netif_stop_queue(pnetdev); - } - /*s2.*/ - /*s2-1. issue disassoc_cmd to fw*/ - r8712_disassoc_cmd(padapter); - /*s2-2. indicate disconnect to os*/ - r8712_ind_disconnect(padapter); - /*s2-3.*/ - r8712_free_assoc_resources(padapter); - /*s2-4.*/ - r8712_free_network_queue(padapter); - return 0; -} - -#include "mlme_osdep.h" diff --git a/drivers/staging/rtl8712/osdep_intf.h b/drivers/staging/rtl8712/osdep_intf.h deleted file mode 100644 index 9e75116c987ec3..00000000000000 --- a/drivers/staging/rtl8712/osdep_intf.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __OSDEP_INTF_H_ -#define __OSDEP_INTF_H_ - -#include "osdep_service.h" -#include "drv_types.h" - -#define RND4(x) (((x >> 2) + ((x & 3) != 0)) << 2) - -struct intf_priv { - u8 *intf_dev; - /* when in USB, IO is through interrupt in/out endpoints */ - struct usb_device *udev; - struct urb *piorw_urb; - struct completion io_retevt_comp; -}; - -int r871x_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); - -#endif /*_OSDEP_INTF_H_*/ diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h deleted file mode 100644 index 0d9bb42cbc589e..00000000000000 --- a/drivers/staging/rtl8712/osdep_service.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __OSDEP_SERVICE_H_ -#define __OSDEP_SERVICE_H_ - -#define _SUCCESS 1 -#define _FAIL 0 - -#include - -#include -#include -#include -#include -#include -#include -#include -#include /* Necessary because we use the proc fs */ - -#include "basic_types.h" - -struct __queue { - struct list_head queue; - spinlock_t lock; -}; - -#define _pkt struct sk_buff -#define _buffer unsigned char - -#define _init_queue(pqueue) \ - do { \ - INIT_LIST_HEAD(&((pqueue)->queue)); \ - spin_lock_init(&((pqueue)->lock)); \ - } while (0) - -static inline u32 end_of_queue_search(struct list_head *head, - struct list_head *plist) -{ - return (head == plist); -} - -static inline void flush_signals_thread(void) -{ - if (signal_pending(current)) - flush_signals(current); -} - -#endif - diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c deleted file mode 100644 index 215fca4abb3a06..00000000000000 --- a/drivers/staging/rtl8712/recv_linux.c +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * recv_linux.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE . - * Larry Finger - * - ******************************************************************************/ - -#define _RECV_OSDEP_C_ - -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "wifi.h" -#include "recv_osdep.h" -#include "osdep_intf.h" -#include "ethernet.h" -#include -#include "usb_ops.h" - -/*init os related resource in struct recv_priv*/ -/*alloc os related resource in union recv_frame*/ -void r8712_os_recv_resource_alloc(struct _adapter *padapter, - union recv_frame *precvframe) -{ - precvframe->u.hdr.pkt_newalloc = NULL; - precvframe->u.hdr.pkt = NULL; -} - -/*alloc os related resource in struct recv_buf*/ -int r8712_os_recvbuf_resource_alloc(struct _adapter *padapter, - struct recv_buf *precvbuf) -{ - int res = 0; - - precvbuf->irp_pending = false; - precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); - if (!precvbuf->purb) - res = -ENOMEM; - precvbuf->pskb = NULL; - precvbuf->pallocated_buf = NULL; - precvbuf->pbuf = NULL; - precvbuf->pdata = NULL; - precvbuf->phead = NULL; - precvbuf->ptail = NULL; - precvbuf->pend = NULL; - precvbuf->transfer_len = 0; - precvbuf->len = 0; - return res; -} - -/*free os related resource in struct recv_buf*/ -void r8712_os_recvbuf_resource_free(struct _adapter *padapter, - struct recv_buf *precvbuf) -{ - if (precvbuf->pskb) - dev_kfree_skb_any(precvbuf->pskb); - if (precvbuf->purb) { - usb_kill_urb(precvbuf->purb); - usb_free_urb(precvbuf->purb); - } -} - -void r8712_handle_tkip_mic_err(struct _adapter *adapter, u8 bgroup) -{ - union iwreq_data wrqu; - struct iw_michaelmicfailure ev; - struct mlme_priv *mlmepriv = &adapter->mlmepriv; - - memset(&ev, 0x00, sizeof(ev)); - if (bgroup) - ev.flags |= IW_MICFAILURE_GROUP; - else - ev.flags |= IW_MICFAILURE_PAIRWISE; - ev.src_addr.sa_family = ARPHRD_ETHER; - ether_addr_copy(ev.src_addr.sa_data, &mlmepriv->assoc_bssid[0]); - memset(&wrqu, 0x00, sizeof(wrqu)); - wrqu.data.length = sizeof(ev); - wireless_send_event(adapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu, - (char *)&ev); -} - -void r8712_recv_indicatepkt(struct _adapter *adapter, - union recv_frame *recvframe) -{ - struct recv_priv *recvpriv; - struct __queue *free_recv_queue; - _pkt *skb; - struct rx_pkt_attrib *attrib = &recvframe->u.hdr.attrib; - - recvpriv = &adapter->recvpriv; - free_recv_queue = &recvpriv->free_recv_queue; - skb = recvframe->u.hdr.pkt; - if (!skb) - goto _recv_indicatepkt_drop; - skb->data = recvframe->u.hdr.rx_data; - skb->len = recvframe->u.hdr.len; - skb_set_tail_pointer(skb, skb->len); - if ((attrib->tcpchk_valid == 1) && (attrib->tcp_chkrpt == 1)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb->ip_summed = CHECKSUM_NONE; - skb->dev = adapter->pnetdev; - skb->protocol = eth_type_trans(skb, adapter->pnetdev); - netif_rx(skb); - recvframe->u.hdr.pkt = NULL; /* pointers to NULL before - * r8712_free_recvframe() - */ - r8712_free_recvframe(recvframe, free_recv_queue); - return; -_recv_indicatepkt_drop: - /*enqueue back to free_recv_queue*/ - if (recvframe) - r8712_free_recvframe(recvframe, free_recv_queue); - recvpriv->rx_drop++; -} - -static void _r8712_reordering_ctrl_timeout_handler (struct timer_list *t) -{ - struct recv_reorder_ctrl *reorder_ctrl = - from_timer(reorder_ctrl, t, reordering_ctrl_timer); - - r8712_reordering_ctrl_timeout_handler(reorder_ctrl); -} - -void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl) -{ - timer_setup(&preorder_ctrl->reordering_ctrl_timer, - _r8712_reordering_ctrl_timeout_handler, 0); -} diff --git a/drivers/staging/rtl8712/recv_osdep.h b/drivers/staging/rtl8712/recv_osdep.h deleted file mode 100644 index fbe3f286850647..00000000000000 --- a/drivers/staging/rtl8712/recv_osdep.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RECV_OSDEP_H_ -#define __RECV_OSDEP_H_ - -#include "osdep_service.h" -#include "drv_types.h" -#include - -int _r8712_init_recv_priv(struct recv_priv *precvpriv, - struct _adapter *padapter); -void _r8712_free_recv_priv(struct recv_priv *precvpriv); -void r8712_recv_entry(union recv_frame *precv_frame); -void r8712_recv_indicatepkt(struct _adapter *adapter, - union recv_frame *precv_frame); -void r8712_handle_tkip_mic_err(struct _adapter *padapter, u8 bgroup); -int r8712_init_recv_priv(struct recv_priv *precvpriv, - struct _adapter *padapter); -void r8712_free_recv_priv(struct recv_priv *precvpriv); -void r8712_os_recv_resource_alloc(struct _adapter *padapter, - union recv_frame *precvframe); -int r8712_os_recvbuf_resource_alloc(struct _adapter *padapter, - struct recv_buf *precvbuf); -void r8712_os_recvbuf_resource_free(struct _adapter *padapter, - struct recv_buf *precvbuf); -void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl); - -#endif diff --git a/drivers/staging/rtl8712/rtl8712_bitdef.h b/drivers/staging/rtl8712/rtl8712_bitdef.h deleted file mode 100644 index a4a687dcc2e7bb..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_bitdef.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ - -#ifndef __RTL8712_BITDEF_H__ -#define __RTL8712_BITDEF_H__ - -#include "rtl8712_cmdctrl_bitdef.h" -#include "rtl8712_syscfg_bitdef.h" -#include "rtl8712_macsetting_bitdef.h" -#include "rtl8712_timectrl_bitdef.h" -#include "rtl8712_fifoctrl_bitdef.h" -#include "rtl8712_ratectrl_bitdef.h" -#include "rtl8712_edcasetting_bitdef.h" -#include "rtl8712_wmac_bitdef.h" -#include "rtl8712_security_bitdef.h" -#include "rtl8712_powersave_bitdef.h" -#include "rtl8712_gp_bitdef.h" -#include "rtl8712_interrupt_bitdef.h" -#include "rtl8712_debugctrl_bitdef.h" - -#endif /* __RTL8712_BITDEF_H__ */ - diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c deleted file mode 100644 index bb7db96ed8219f..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_cmd.c +++ /dev/null @@ -1,409 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl8712_cmd.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE . - * Larry Finger - * - ******************************************************************************/ - -#define _RTL8712_CMD_C_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "recv_osdep.h" -#include "mlme_osdep.h" -#include "rtl871x_ioctl_set.h" - -static void check_hw_pbc(struct _adapter *padapter) -{ - u8 tmp1byte; - - r8712_write8(padapter, MAC_PINMUX_CTRL, (GPIOMUX_EN | GPIOSEL_GPIO)); - tmp1byte = r8712_read8(padapter, GPIO_IO_SEL); - tmp1byte &= ~(HAL_8192S_HW_GPIO_WPS_BIT); - r8712_write8(padapter, GPIO_IO_SEL, tmp1byte); - tmp1byte = r8712_read8(padapter, GPIO_CTRL); - if (tmp1byte == 0xff) - return; - if (tmp1byte & HAL_8192S_HW_GPIO_WPS_BIT) { - /* Here we only set bPbcPressed to true - * After trigger PBC, the variable will be set to false - */ - netdev_dbg(padapter->pnetdev, "CheckPbcGPIO - PBC is pressed !!!!\n"); - /* 0 is the default value and it means the application monitors - * the HW PBC doesn't provide its pid to driver. - */ - if (padapter->pid == 0) - return; - kill_pid(find_vpid(padapter->pid), SIGUSR1, 1); - } -} - -/* query rx phy status from fw. - * Adhoc mode: beacon. - * Infrastructure mode: beacon , data. - */ -static void query_fw_rx_phy_status(struct _adapter *padapter) -{ - u32 val32 = 0; - int pollingcnts = 50; - - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { - r8712_write32(padapter, IOCMD_CTRL_REG, 0xf4000001); - msleep(100); - /* Wait FW complete IO Cmd */ - while ((r8712_read32(padapter, IOCMD_CTRL_REG)) && - (pollingcnts > 0)) { - pollingcnts--; - msleep(20); - } - if (pollingcnts != 0) - val32 = r8712_read32(padapter, IOCMD_DATA_REG); - else /* time out */ - val32 = 0; - val32 >>= 4; - padapter->recvpriv.fw_rssi = - (u8)r8712_signal_scale_mapping(val32); - } -} - -/* check mlme, hw, phy, or dynamic algorithm status. */ -static void StatusWatchdogCallback(struct _adapter *padapter) -{ - check_hw_pbc(padapter); - query_fw_rx_phy_status(padapter); -} - -static void r871x_internal_cmd_hdl(struct _adapter *padapter, u8 *pbuf) -{ - struct drvint_cmd_parm *pdrvcmd; - - if (!pbuf) - return; - pdrvcmd = (struct drvint_cmd_parm *)pbuf; - switch (pdrvcmd->i_cid) { - case WDG_WK_CID: - StatusWatchdogCallback(padapter); - break; - default: - break; - } - kfree(pdrvcmd->pbuf); -} - -static u8 read_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) -{ - struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; - - r8712_free_cmd_obj(pcmd); - return H2C_SUCCESS; -} - -static u8 write_bbreg_hdl(struct _adapter *padapter, u8 *pbuf) -{ - void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); - struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; - - pcmd_callback = cmd_callback[pcmd->cmdcode].callback; - if (!pcmd_callback) - r8712_free_cmd_obj(pcmd); - else - pcmd_callback(padapter, pcmd); - return H2C_SUCCESS; -} - -static u8 read_rfreg_hdl(struct _adapter *padapter, u8 *pbuf) -{ - u32 val; - void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); - struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; - - if (pcmd->rsp && pcmd->rspsz > 0) - memcpy(pcmd->rsp, (u8 *)&val, pcmd->rspsz); - pcmd_callback = cmd_callback[pcmd->cmdcode].callback; - if (!pcmd_callback) - r8712_free_cmd_obj(pcmd); - else - pcmd_callback(padapter, pcmd); - return H2C_SUCCESS; -} - -static u8 write_rfreg_hdl(struct _adapter *padapter, u8 *pbuf) -{ - void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); - struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; - - pcmd_callback = cmd_callback[pcmd->cmdcode].callback; - if (!pcmd_callback) - r8712_free_cmd_obj(pcmd); - else - pcmd_callback(padapter, pcmd); - return H2C_SUCCESS; -} - -static u8 sys_suspend_hdl(struct _adapter *padapter, u8 *pbuf) -{ - struct cmd_obj *pcmd = (struct cmd_obj *)pbuf; - - r8712_free_cmd_obj(pcmd); - return H2C_SUCCESS; -} - -static struct cmd_obj *cmd_hdl_filter(struct _adapter *padapter, - struct cmd_obj *pcmd) -{ - struct cmd_obj *pcmd_r; - - if (!pcmd) - return pcmd; - pcmd_r = NULL; - - switch (pcmd->cmdcode) { - case GEN_CMD_CODE(_Read_BBREG): - read_bbreg_hdl(padapter, (u8 *)pcmd); - break; - case GEN_CMD_CODE(_Write_BBREG): - write_bbreg_hdl(padapter, (u8 *)pcmd); - break; - case GEN_CMD_CODE(_Read_RFREG): - read_rfreg_hdl(padapter, (u8 *)pcmd); - break; - case GEN_CMD_CODE(_Write_RFREG): - write_rfreg_hdl(padapter, (u8 *)pcmd); - break; - case GEN_CMD_CODE(_SetUsbSuspend): - sys_suspend_hdl(padapter, (u8 *)pcmd); - break; - case GEN_CMD_CODE(_JoinBss): - r8712_joinbss_reset(padapter); - /* Before set JoinBss_CMD to FW, driver must ensure FW is in - * PS_MODE_ACTIVE. Directly write rpwm to radio on and assign - * new pwr_mode to Driver, instead of use workitem to change - * state. - */ - if (padapter->pwrctrlpriv.pwr_mode > PS_MODE_ACTIVE) { - padapter->pwrctrlpriv.pwr_mode = PS_MODE_ACTIVE; - mutex_lock(&padapter->pwrctrlpriv.mutex_lock); - r8712_set_rpwm(padapter, PS_STATE_S4); - mutex_unlock(&padapter->pwrctrlpriv.mutex_lock); - } - pcmd_r = pcmd; - break; - case _DRV_INT_CMD_: - r871x_internal_cmd_hdl(padapter, pcmd->parmbuf); - r8712_free_cmd_obj(pcmd); - pcmd_r = NULL; - break; - default: - pcmd_r = pcmd; - break; - } - return pcmd_r; /* if returning pcmd_r == NULL, pcmd must be free. */ -} - -u8 r8712_fw_cmd(struct _adapter *pAdapter, u32 cmd) -{ - int pollingcnts = 50; - - r8712_write32(pAdapter, IOCMD_CTRL_REG, cmd); - msleep(100); - while ((r8712_read32(pAdapter, IOCMD_CTRL_REG != 0)) && - (pollingcnts > 0)) { - pollingcnts--; - msleep(20); - } - if (pollingcnts == 0) - return false; - return true; -} - -void r8712_fw_cmd_data(struct _adapter *pAdapter, u32 *value, u8 flag) -{ - if (flag == 0) /* set */ - r8712_write32(pAdapter, IOCMD_DATA_REG, *value); - else /* query */ - *value = r8712_read32(pAdapter, IOCMD_DATA_REG); -} - -int r8712_cmd_thread(void *context) -{ - struct cmd_obj *pcmd; - unsigned int cmdsz, wr_sz; - __le32 *pcmdbuf; - struct tx_desc *pdesc; - void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); - struct _adapter *padapter = context; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct completion *cmd_queue_comp = - &pcmdpriv->cmd_queue_comp; - struct mutex *pwctrl_lock = &padapter->pwrctrlpriv.mutex_lock; - - allow_signal(SIGTERM); - while (1) { - if (wait_for_completion_interruptible(cmd_queue_comp)) - break; - if (padapter->driver_stopped || padapter->surprise_removed) - break; - if (r8712_register_cmd_alive(padapter)) - continue; -_next: - pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue); - if (!(pcmd)) { - r8712_unregister_cmd_alive(padapter); - continue; - } - pcmdbuf = (__le32 *)pcmdpriv->cmd_buf; - pdesc = (struct tx_desc *)pcmdbuf; - memset(pdesc, 0, TXDESC_SIZE); - pcmd = cmd_hdl_filter(padapter, pcmd); - if (pcmd) { /* if pcmd != NULL, cmd will be handled by f/w */ - struct dvobj_priv *pdvobj = &padapter->dvobjpriv; - u8 blnPending = 0; - u16 cmdcode = pcmd->cmdcode; - - pcmdpriv->cmd_issued_cnt++; - cmdsz = round_up(pcmd->cmdsz, 8); - wr_sz = TXDESC_SIZE + 8 + cmdsz; - pdesc->txdw0 |= cpu_to_le32((wr_sz - TXDESC_SIZE) & - 0x0000ffff); - if (pdvobj->ishighspeed) { - if ((wr_sz % 512) == 0) - blnPending = 1; - } else { - if ((wr_sz % 64) == 0) - blnPending = 1; - } - if (blnPending) { /* 32 bytes for TX Desc - 8 offset */ - pdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + - OFFSET_SZ + 8) << OFFSET_SHT) & - 0x00ff0000); - } else { - pdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + - OFFSET_SZ) << - OFFSET_SHT) & - 0x00ff0000); - } - pdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); - pdesc->txdw1 |= cpu_to_le32((0x13 << QSEL_SHT) & - 0x00001f00); - pcmdbuf += (TXDESC_SIZE >> 2); - *pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) | - (pcmd->cmdcode << 16) | - (pcmdpriv->cmd_seq << 24)); - pcmdbuf += 2; /* 8 bytes alignment */ - memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); - if (blnPending) - wr_sz += 8; /* Append 8 bytes */ - r8712_write_mem(padapter, RTL8712_DMA_H2CCMD, wr_sz, - (u8 *)pdesc); - pcmdpriv->cmd_seq++; - if (cmdcode == GEN_CMD_CODE(_CreateBss)) { - pcmd->res = H2C_SUCCESS; - pcmd_callback = cmd_callback[cmdcode].callback; - if (pcmd_callback) - pcmd_callback(padapter, pcmd); - continue; - } - if (cmdcode == GEN_CMD_CODE(_SetPwrMode)) { - if (padapter->pwrctrlpriv.bSleep) { - mutex_lock(pwctrl_lock); - r8712_set_rpwm(padapter, PS_STATE_S2); - mutex_unlock(pwctrl_lock); - } - } - r8712_free_cmd_obj(pcmd); - if (list_empty(&pcmdpriv->cmd_queue.queue)) { - r8712_unregister_cmd_alive(padapter); - continue; - } else { - goto _next; - } - } else { - goto _next; - } - flush_signals_thread(); - } - /* free all cmd_obj resources */ - do { - pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue); - if (!pcmd) - break; - r8712_free_cmd_obj(pcmd); - } while (1); - complete(&pcmdpriv->terminate_cmdthread_comp); - return 0; -} - -void r8712_event_handle(struct _adapter *padapter, __le32 *peventbuf) -{ - u8 evt_code, evt_seq; - u16 evt_sz; - void (*event_callback)(struct _adapter *dev, u8 *pbuf); - struct evt_priv *pevt_priv = &padapter->evtpriv; - - if (!peventbuf) - goto _abort_event_; - evt_sz = (u16)(le32_to_cpu(*peventbuf) & 0xffff); - evt_seq = (u8)((le32_to_cpu(*peventbuf) >> 24) & 0x7f); - evt_code = (u8)((le32_to_cpu(*peventbuf) >> 16) & 0xff); - /* checking event sequence... */ - if ((evt_seq & 0x7f) != pevt_priv->event_seq) { - pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); - goto _abort_event_; - } - /* checking if event code is valid */ - if (evt_code >= MAX_C2HEVT) { - pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); - goto _abort_event_; - } else if ((evt_code == GEN_EVT_CODE(_Survey)) && - (evt_sz > sizeof(struct wlan_bssid_ex))) { - pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); - goto _abort_event_; - } - /* checking if event size match the event parm size */ - if ((wlanevents[evt_code].parmsize) && - (wlanevents[evt_code].parmsize != evt_sz)) { - pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); - goto _abort_event_; - } else if ((evt_sz == 0) && (evt_code != GEN_EVT_CODE(_WPS_PBC))) { - pevt_priv->event_seq = ((evt_seq + 1) & 0x7f); - goto _abort_event_; - } - pevt_priv->event_seq++; /* update evt_seq */ - if (pevt_priv->event_seq > 127) - pevt_priv->event_seq = 0; - /* move to event content, 8 bytes alignment */ - peventbuf = peventbuf + 2; - event_callback = wlanevents[evt_code].event_callback; - if (event_callback) - event_callback(padapter, (u8 *)peventbuf); - pevt_priv->evt_done_cnt++; -_abort_event_: - return; -} diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h deleted file mode 100644 index a34d0dd023f33b..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_cmd.h +++ /dev/null @@ -1,231 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_CMD_H_ -#define __RTL8712_CMD_H_ - -#define CMD_HDR_SZ 8 - -u8 r8712_fw_cmd(struct _adapter *pAdapter, u32 cmd); -void r8712_fw_cmd_data(struct _adapter *pAdapter, u32 *value, u8 flag); - -struct cmd_hdr { - u32 cmd_dw0; - u32 cmd_dw1; -}; - -enum rtl8712_h2c_cmd { - GEN_CMD_CODE(_Read_MACREG), /*0*/ - GEN_CMD_CODE(_Write_MACREG), - GEN_CMD_CODE(_Read_BBREG), - GEN_CMD_CODE(_Write_BBREG), - GEN_CMD_CODE(_Read_RFREG), - GEN_CMD_CODE(_Write_RFREG), /*5*/ - GEN_CMD_CODE(_Read_EEPROM), - GEN_CMD_CODE(_Write_EEPROM), - GEN_CMD_CODE(_Read_EFUSE), - GEN_CMD_CODE(_Write_EFUSE), - - GEN_CMD_CODE(_Read_CAM), /*10*/ - GEN_CMD_CODE(_Write_CAM), - GEN_CMD_CODE(_setBCNITV), - GEN_CMD_CODE(_setMBIDCFG), - GEN_CMD_CODE(_JoinBss), /*14*/ - GEN_CMD_CODE(_DisConnect), /*15*/ - GEN_CMD_CODE(_CreateBss), - GEN_CMD_CODE(_SetOpMode), - GEN_CMD_CODE(_SiteSurvey), /*18*/ - GEN_CMD_CODE(_SetAuth), - - GEN_CMD_CODE(_SetKey), /*20*/ - GEN_CMD_CODE(_SetStaKey), - GEN_CMD_CODE(_SetAssocSta), - GEN_CMD_CODE(_DelAssocSta), - GEN_CMD_CODE(_SetStaPwrState), - GEN_CMD_CODE(_SetBasicRate), /*25*/ - GEN_CMD_CODE(_GetBasicRate), - GEN_CMD_CODE(_SetDataRate), - GEN_CMD_CODE(_GetDataRate), - GEN_CMD_CODE(_SetPhyInfo), - - GEN_CMD_CODE(_GetPhyInfo), /*30*/ - GEN_CMD_CODE(_SetPhy), - GEN_CMD_CODE(_GetPhy), - GEN_CMD_CODE(_readRssi), - GEN_CMD_CODE(_readGain), - GEN_CMD_CODE(_SetAtim), /*35*/ - GEN_CMD_CODE(_SetPwrMode), - GEN_CMD_CODE(_JoinbssRpt), - GEN_CMD_CODE(_SetRaTable), - GEN_CMD_CODE(_GetRaTable), - - GEN_CMD_CODE(_GetCCXReport), /*40*/ - GEN_CMD_CODE(_GetDTMReport), - GEN_CMD_CODE(_GetTXRateStatistics), - GEN_CMD_CODE(_SetUsbSuspend), - GEN_CMD_CODE(_SetH2cLbk), - GEN_CMD_CODE(_AddBAReq), /*45*/ - - GEN_CMD_CODE(_SetChannel), /*46*/ -/* MP_OFFLOAD Start (47~54)*/ - GEN_CMD_CODE(_SetTxPower), - GEN_CMD_CODE(_SwitchAntenna), - GEN_CMD_CODE(_SetCrystalCap), - GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/ - GEN_CMD_CODE(_SetSingleToneTx), - GEN_CMD_CODE(_SetCarrierSuppressionTx), - GEN_CMD_CODE(_SetContinuousTx), - GEN_CMD_CODE(_SwitchBandwidth), /*54*/ -/* MP_OFFLOAD End*/ - GEN_CMD_CODE(_TX_Beacon), /*55*/ - GEN_CMD_CODE(_SetPowerTracking), - GEN_CMD_CODE(_AMSDU_TO_AMPDU), /*57*/ - GEN_CMD_CODE(_SetMacAddress), /*58*/ - - GEN_CMD_CODE(_DisconnectCtrl), /*59*/ - GEN_CMD_CODE(_SetChannelPlan), /*60*/ - GEN_CMD_CODE(_DisconnectCtrlEx), /*61*/ - - /* To do, modify these h2c cmd, add or delete */ - GEN_CMD_CODE(_GetH2cLbk), - - /* WPS extra IE */ - GEN_CMD_CODE(_SetProbeReqExtraIE), - GEN_CMD_CODE(_SetAssocReqExtraIE), - GEN_CMD_CODE(_SetProbeRspExtraIE), - GEN_CMD_CODE(_SetAssocRspExtraIE), - - /* the following is driver will do */ - GEN_CMD_CODE(_GetCurDataRate), - - GEN_CMD_CODE(_GetTxRetrycnt), /* to record times that Tx retry to - * transmit packet after association - */ - GEN_CMD_CODE(_GetRxRetrycnt), /* to record total number of the - * received frame with ReTry bit set in - * the WLAN header - */ - - GEN_CMD_CODE(_GetBCNOKcnt), - GEN_CMD_CODE(_GetBCNERRcnt), - GEN_CMD_CODE(_GetCurTxPwrLevel), - - GEN_CMD_CODE(_SetDIG), - GEN_CMD_CODE(_SetRA), - GEN_CMD_CODE(_SetPT), - GEN_CMD_CODE(_ReadTSSI), - - MAX_H2CCMD -}; - -#define _GetBBReg_CMD_ _Read_BBREG_CMD_ -#define _SetBBReg_CMD_ _Write_BBREG_CMD_ -#define _GetRFReg_CMD_ _Read_RFREG_CMD_ -#define _SetRFReg_CMD_ _Write_RFREG_CMD_ -#define _DRV_INT_CMD_ (MAX_H2CCMD + 1) -#define _SetRFIntFs_CMD_ (MAX_H2CCMD + 2) - -#ifdef _RTL8712_CMD_C_ -static struct _cmd_callback cmd_callback[] = { - {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ - {GEN_CMD_CODE(_Write_MACREG), NULL}, - {GEN_CMD_CODE(_Read_BBREG), NULL}, - {GEN_CMD_CODE(_Write_BBREG), NULL}, - {GEN_CMD_CODE(_Read_RFREG), &r8712_getbbrfreg_cmdrsp_callback}, - {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/ - {GEN_CMD_CODE(_Read_EEPROM), NULL}, - {GEN_CMD_CODE(_Write_EEPROM), NULL}, - {GEN_CMD_CODE(_Read_EFUSE), NULL}, - {GEN_CMD_CODE(_Write_EFUSE), NULL}, - - {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/ - {GEN_CMD_CODE(_Write_CAM), NULL}, - {GEN_CMD_CODE(_setBCNITV), NULL}, - {GEN_CMD_CODE(_setMBIDCFG), NULL}, - {GEN_CMD_CODE(_JoinBss), &r8712_joinbss_cmd_callback}, /*14*/ - {GEN_CMD_CODE(_DisConnect), &r8712_disassoc_cmd_callback}, /*15*/ - {GEN_CMD_CODE(_CreateBss), &r8712_createbss_cmd_callback}, - {GEN_CMD_CODE(_SetOpMode), NULL}, - {GEN_CMD_CODE(_SiteSurvey), &r8712_survey_cmd_callback}, /*18*/ - {GEN_CMD_CODE(_SetAuth), NULL}, - - {GEN_CMD_CODE(_SetKey), NULL}, /*20*/ - {GEN_CMD_CODE(_SetStaKey), &r8712_setstaKey_cmdrsp_callback}, - {GEN_CMD_CODE(_SetAssocSta), &r8712_setassocsta_cmdrsp_callback}, - {GEN_CMD_CODE(_DelAssocSta), NULL}, - {GEN_CMD_CODE(_SetStaPwrState), NULL}, - {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/ - {GEN_CMD_CODE(_GetBasicRate), NULL}, - {GEN_CMD_CODE(_SetDataRate), NULL}, - {GEN_CMD_CODE(_GetDataRate), NULL}, - {GEN_CMD_CODE(_SetPhyInfo), NULL}, - - {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/ - {GEN_CMD_CODE(_SetPhy), NULL}, - {GEN_CMD_CODE(_GetPhy), NULL}, - {GEN_CMD_CODE(_readRssi), NULL}, - {GEN_CMD_CODE(_readGain), NULL}, - {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/ - {GEN_CMD_CODE(_SetPwrMode), NULL}, - {GEN_CMD_CODE(_JoinbssRpt), NULL}, - {GEN_CMD_CODE(_SetRaTable), NULL}, - {GEN_CMD_CODE(_GetRaTable), NULL}, - - {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/ - {GEN_CMD_CODE(_GetDTMReport), NULL}, - {GEN_CMD_CODE(_GetTXRateStatistics), NULL}, - {GEN_CMD_CODE(_SetUsbSuspend), NULL}, - {GEN_CMD_CODE(_SetH2cLbk), NULL}, - {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/ - - {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/ -/* MP_OFFLOAD Start (47~54)*/ - {GEN_CMD_CODE(_SetTxPower), NULL}, - {GEN_CMD_CODE(_SwitchAntenna), NULL}, - {GEN_CMD_CODE(_SetCrystalCap), NULL}, - {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/ - {GEN_CMD_CODE(_SetSingleToneTx), NULL}, - {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL}, - {GEN_CMD_CODE(_SetContinuousTx), NULL}, - {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/ -/* MP_OFFLOAD End*/ - {GEN_CMD_CODE(_TX_Beacon), NULL}, /*55*/ - {GEN_CMD_CODE(_SetPowerTracking), NULL}, - {GEN_CMD_CODE(_AMSDU_TO_AMPDU), NULL}, /*57*/ - {GEN_CMD_CODE(_SetMacAddress), NULL}, /*58*/ - - {GEN_CMD_CODE(_DisconnectCtrl), NULL}, /*59*/ - {GEN_CMD_CODE(_SetChannelPlan), NULL}, /*60*/ - {GEN_CMD_CODE(_DisconnectCtrlEx), NULL}, /*61*/ - - /* To do, modify these h2c cmd, add or delete */ - {GEN_CMD_CODE(_GetH2cLbk), NULL}, - - {_SetProbeReqExtraIE_CMD_, NULL}, - {_SetAssocReqExtraIE_CMD_, NULL}, - {_SetProbeRspExtraIE_CMD_, NULL}, - {_SetAssocRspExtraIE_CMD_, NULL}, - {_GetCurDataRate_CMD_, NULL}, - {_GetTxRetrycnt_CMD_, NULL}, - {_GetRxRetrycnt_CMD_, NULL}, - {_GetBCNOKcnt_CMD_, NULL}, - {_GetBCNERRcnt_CMD_, NULL}, - {_GetCurTxPwrLevel_CMD_, NULL}, - {_SetDIG_CMD_, NULL}, - {_SetRA_CMD_, NULL}, - {_SetPT_CMD_, NULL}, - {GEN_CMD_CODE(_ReadTSSI), &r8712_readtssi_cmdrsp_callback} -}; -#endif - -#endif diff --git a/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h deleted file mode 100644 index 68bdec07f51e85..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_CMDCTRL_BITDEF_H__ -#define __RTL8712_CMDCTRL_BITDEF_H__ - -/* - * 2. Command Control Registers (Offset: 0x0040 - 0x004F) - */ -/*--------------------------------------------------------------------------*/ -/* 8192S (CMD) command register bits (Offset 0x40, 16 bits)*/ -/*--------------------------------------------------------------------------*/ -#define _APSDOFF_STATUS BIT(15) -#define _APSDOFF BIT(14) -#define _BBRSTn BIT(13) /*Enable OFDM/CCK*/ -#define _BB_GLB_RSTn BIT(12) /*Enable BB*/ -#define _SCHEDULE_EN BIT(10) /*Enable MAC scheduler*/ -#define _MACRXEN BIT(9) -#define _MACTXEN BIT(8) -#define _DDMA_EN BIT(7) /*FW off load function enable*/ -#define _FW2HW_EN BIT(6) /*MAC every module reset */ -#define _RXDMA_EN BIT(5) -#define _TXDMA_EN BIT(4) -#define _HCI_RXDMA_EN BIT(3) -#define _HCI_TXDMA_EN BIT(2) - -/*TXPAUSE*/ -#define _STOPHCCA BIT(6) -#define _STOPHIGH BIT(5) -#define _STOPMGT BIT(4) -#define _STOPVO BIT(3) -#define _STOPVI BIT(2) -#define _STOPBE BIT(1) -#define _STOPBK BIT(0) - -/*TCR*/ -#define _DISCW BIT(20) -#define _ICV BIT(19) -#define _CFEND_FMT BIT(17) -#define _CRC BIT(16) -#define _FWRDY BIT(7) -#define _BASECHG BIT(6) -#define _IMEM_RDY BIT(5) -#define _DMEM_CODE_DONE BIT(4) -#define _EMEM_CHK_RPT BIT(3) -#define _EMEM_CODE_DONE BIT(2) -#define _IMEM_CHK_RPT BIT(1) -#define _IMEM_CODE_DONE BIT(0) - -#define _TXDMA_INIT_VALUE (_IMEM_CHK_RPT | _EMEM_CHK_RPT) - -/*RCR*/ -#define _ENMBID BIT(27) -#define _APP_PHYST_RXFF BIT(25) -#define _APP_PHYST_STAFF BIT(24) -#define _CBSSID BIT(23) -#define _APWRMGT BIT(22) -#define _ADD3 BIT(21) -#define _AMF BIT(20) -#define _ACF BIT(19) -#define _ADF BIT(18) -#define _APP_MIC BIT(17) -#define _APP_ICV BIT(16) -#define _RXFTH_MSK 0x0000E000 -#define _RXFTH_SHT 13 -#define _AICV BIT(12) -#define _RXPKTLMT_MSK 0x00000FC0 -#define _RXPKTLMT_SHT 6 -#define _ACRC32 BIT(5) -#define _AB BIT(3) -#define _AM BIT(2) -#define _APM BIT(1) -#define _AAP BIT(0) - -/*MSR*/ -#define _NETTYPE_MSK 0x03 -#define _NETTYPE_SHT 0 - -/*BT*/ -#define _BTMODE_MSK 0x06 -#define _BTMODE_SHT 1 -#define _ENBT BIT(0) - -/*MBIDCTRL*/ -#define _ENMBID_MODE BIT(15) -#define _BCNNO_MSK 0x7000 -#define _BCNNO_SHT 12 -#define _BCNSPACE_MSK 0x0FFF -#define _BCNSPACE_SHT 0 - -#endif /* __RTL8712_CMDCTRL_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h deleted file mode 100644 index fc67771c89b785..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_CMDCTRL_REGDEF_H__ -#define __RTL8712_CMDCTRL_REGDEF_H__ - -#define CR (RTL8712_CMDCTRL_ + 0x0000) -#define TXPAUSE (RTL8712_CMDCTRL_ + 0x0002) -#define TCR (RTL8712_CMDCTRL_ + 0x0004) -#define RCR (RTL8712_CMDCTRL_ + 0x0008) -#define MSR (RTL8712_CMDCTRL_ + 0x000C) -#define SYSF_CFG (RTL8712_CMDCTRL_ + 0x000D) -#define MBIDCTRL (RTL8712_CMDCTRL_ + 0x000E) - -#endif /* __RTL8712_CMDCTRL_REGDEF_H__ */ - diff --git a/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h deleted file mode 100644 index bb3863467f0d67..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_DEBUGCTRL_BITDEF_H__ -#define __RTL8712_DEBUGCTRL_BITDEF_H__ - -/*BIST*/ -#define _BIST_RST BIT(0) - -/*LMS*/ -#define _LMS_MSK 0x03 - -/*WDG_CTRL*/ -#define _OVSEL_MSK 0x0600 -#define _OVSEL_SHT 9 -#define _WDGCLR BIT(8) -#define _WDGEN_MSK 0x00FF -#define _WDGEN_SHT 0 - -/*INTM*/ -#define _TXTIMER_MSK 0xF000 -#define _TXTIMER_SHT 12 -#define _TXNUM_MSK 0x0F00 -#define _TXNUM_SHT 8 -#define _RXTIMER_MSK 0x00F0 -#define _RXTIMER_SHT 4 -#define _RXNUM_MSK 0x000F -#define _RXNUM_SHT 0 - -/*FDLOCKTURN0*/ -/*FDLOCKTURN1*/ -#define _TURN1 BIT(0) - -/*FDLOCKFLAG0*/ -/*FDLOCKFLAG1*/ -#define _LOCKFLAG1_MSK 0x03 - -#endif /* __RTL8712_DEBUGCTRL_BITDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h deleted file mode 100644 index 319220e9d53de3..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_DEBUGCTRL_REGDEF_H__ -#define __RTL8712_DEBUGCTRL_REGDEF_H__ - -#define BIST (RTL8712_DEBUGCTRL_ + 0x00) -#define DBS (RTL8712_DEBUGCTRL_ + 0x04) -#define LMS (RTL8712_DEBUGCTRL_ + 0x05) -#define CPUINST (RTL8712_DEBUGCTRL_ + 0x08) -#define CPUCAUSE (RTL8712_DEBUGCTRL_ + 0x0C) -#define LBUS_ERR_ADDR (RTL8712_DEBUGCTRL_ + 0x10) -#define LBUS_ERR_CMD (RTL8712_DEBUGCTRL_ + 0x14) -#define LBUS_ERR_DATA_L (RTL8712_DEBUGCTRL_ + 0x18) -#define LBUS_ERR_DATA_H (RTL8712_DEBUGCTRL_ + 0x1C) -#define LBUS_EXCEPTION_ADDR (RTL8712_DEBUGCTRL_ + 0x20) -#define WDG_CTRL (RTL8712_DEBUGCTRL_ + 0x24) -#define INTMTU (RTL8712_DEBUGCTRL_ + 0x28) -#define INTM (RTL8712_DEBUGCTRL_ + 0x2A) -#define FDLOCKTURN0 (RTL8712_DEBUGCTRL_ + 0x2C) -#define FDLOCKTURN1 (RTL8712_DEBUGCTRL_ + 0x2D) -#define FDLOCKFLAG0 (RTL8712_DEBUGCTRL_ + 0x2E) -#define FDLOCKFLAG1 (RTL8712_DEBUGCTRL_ + 0x2F) -#define TRXPKTBUF_DBG_DATA (RTL8712_DEBUGCTRL_ + 0x30) -#define TRXPKTBUF_DBG_CTRL (RTL8712_DEBUGCTRL_ + 0x38) -#define DPLL_MON (RTL8712_DEBUGCTRL_ + 0x3A) - -#endif /* __RTL8712_DEBUGCTRL_REGDEF_H__ */ - diff --git a/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h b/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h deleted file mode 100644 index 9048d6a6529697..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_edcasetting_bitdef.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_EDCASETTING_BITDEF_H__ -#define __RTL8712_EDCASETTING_BITDEF_H__ - -/*EDCAPARAM*/ -#define _TXOPLIMIT_MSK 0xFFFF0000 -#define _TXOPLIMIT_SHT 16 -#define _ECWIN_MSK 0x0000FF00 -#define _ECWIN_SHT 8 -#define _AIFS_MSK 0x000000FF -#define _AIFS_SHT 0 - -/*BCNTCFG*/ -#define _BCNECW_MSK 0xFF00 -#define _BCNECW_SHT 8 -#define _BCNIFS_MSK 0x00FF -#define _BCNIFS_SHT 0 - -/*CWRR*/ -#define _CWRR_MSK 0x03FF - -/*ACMAVG*/ -#define _AVG_TIME_UP BIT(3) -#define _AVGPERIOD_MSK 0x03 - -/*ACMHWCTRL*/ -#define _VOQ_ACM_STATUS BIT(6) -#define _VIQ_ACM_STATUS BIT(5) -#define _BEQ_ACM_STATUS BIT(4) -#define _VOQ_ACM_EN BIT(3) -#define _VIQ_ACM_EN BIT(2) -#define _BEQ_ACM_EN BIT(1) -#define _ACMHWEN BIT(0) - -/*VO_ADMTIME*/ -#define _VO_ACM_RUT BIT(18) -#define _VO_ADMTIME_MSK 0x0003FFF - -/*VI_ADMTIME*/ -#define _VI_ACM_RUT BIT(18) -#define _VI_ADMTIME_MSK 0x0003FFF - -/*BE_ADMTIME*/ -#define _BE_ACM_RUT BIT(18) -#define _BE_ADMTIME_MSK 0x0003FFF - -/*Retry limit reg*/ -#define _SRL_MSK 0xFF00 -#define _SRL_SHT 8 -#define _LRL_MSK 0x00FF -#define _LRL_SHT 0 - -#endif /* __RTL8712_EDCASETTING_BITDEF_H__*/ diff --git a/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h b/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h deleted file mode 100644 index 02ec9f3bba6659..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_edcasetting_regdef.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_EDCASETTING_REGDEF_H__ -#define __RTL8712_EDCASETTING_REGDEF_H__ - -#define EDCA_VO_PARAM (RTL8712_EDCASETTING_ + 0x00) -#define EDCA_VI_PARAM (RTL8712_EDCASETTING_ + 0x04) -#define EDCA_BE_PARAM (RTL8712_EDCASETTING_ + 0x08) -#define EDCA_BK_PARAM (RTL8712_EDCASETTING_ + 0x0C) -#define BCNTCFG (RTL8712_EDCASETTING_ + 0x10) -#define CWRR (RTL8712_EDCASETTING_ + 0x12) -#define ACMAVG (RTL8712_EDCASETTING_ + 0x16) -#define ACMHWCTRL (RTL8712_EDCASETTING_ + 0x17) -#define VO_ADMTIME (RTL8712_EDCASETTING_ + 0x18) -#define VI_ADMTIME (RTL8712_EDCASETTING_ + 0x1C) -#define BE_ADMTIME (RTL8712_EDCASETTING_ + 0x20) -#define RL (RTL8712_EDCASETTING_ + 0x24) - -#endif /* __RTL8712_EDCASETTING_REGDEF_H__ */ - diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c deleted file mode 100644 index a39d6c06648f5d..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_efuse.c +++ /dev/null @@ -1,563 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * rtl8712_efuse.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE . - * Larry Finger - * - ******************************************************************************/ - -#define _RTL8712_EFUSE_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "rtl8712_efuse.h" - -/* reserve 3 bytes for HW stop read */ -static int efuse_available_max_size = EFUSE_MAX_SIZE - 3 /*0x1FD*/; - -static void efuse_reg_ctrl(struct _adapter *adapter, u8 bPowerOn) -{ - u8 tmpu8 = 0; - - if (bPowerOn) { - /* -----------------e-fuse pwr & clk reg ctrl --------------- - * Enable LDOE25 Macro Block - */ - tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3); - tmpu8 |= 0x80; - r8712_write8(adapter, EFUSE_TEST + 3, tmpu8); - msleep(20); /* for some platform , need some delay time */ - /* Change Efuse Clock for write action to 40MHZ */ - r8712_write8(adapter, EFUSE_CLK_CTRL, 0x03); - msleep(20); /* for some platform , need some delay time */ - } else { - /* -----------------e-fuse pwr & clk reg ctrl ----------------- - * Disable LDOE25 Macro Block - */ - tmpu8 = r8712_read8(adapter, EFUSE_TEST + 3); - tmpu8 &= 0x7F; - r8712_write8(adapter, EFUSE_TEST + 3, tmpu8); - /* Change Efuse Clock for write action to 500K */ - r8712_write8(adapter, EFUSE_CLK_CTRL, 0x02); - } -} - -/* - * Before write E-Fuse, this function must be called. - */ -u8 r8712_efuse_reg_init(struct _adapter *adapter) -{ - return true; -} - -void r8712_efuse_reg_uninit(struct _adapter *adapter) -{ - efuse_reg_ctrl(adapter, false); -} - -static u8 efuse_one_byte_read(struct _adapter *adapter, u16 addr, u8 *data) -{ - u8 tmpidx = 0, bResult; - - /* -----------------e-fuse reg ctrl --------------------------------- */ - r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */ - r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | - (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC)); - r8712_write8(adapter, EFUSE_CTRL + 3, 0x72); /* read cmd */ - /* wait for complete */ - while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) && - (tmpidx < 100)) - tmpidx++; - if (tmpidx < 100) { - *data = r8712_read8(adapter, EFUSE_CTRL); - bResult = true; - } else { - *data = 0xff; - bResult = false; - } - return bResult; -} - -static u8 efuse_one_byte_write(struct _adapter *adapter, u16 addr, u8 data) -{ - u8 tmpidx = 0, bResult; - - /* -----------------e-fuse reg ctrl -------------------------------- */ - r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */ - r8712_write8(adapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | - (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC)); - r8712_write8(adapter, EFUSE_CTRL, data); /* data */ - r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */ - /* wait for complete */ - while ((0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) && - (tmpidx < 100)) - tmpidx++; - if (tmpidx < 100) - bResult = true; - else - bResult = false; - return bResult; -} - -static u8 efuse_one_byte_rw(struct _adapter *adapter, u8 bRead, u16 addr, - u8 *data) -{ - u8 tmpidx = 0, tmpv8 = 0, bResult; - - /* -----------------e-fuse reg ctrl --------------------------------- */ - r8712_write8(adapter, EFUSE_CTRL + 1, (u8)(addr & 0xFF)); /* address */ - tmpv8 = ((u8)((addr >> 8) & 0x03)) | - (r8712_read8(adapter, EFUSE_CTRL + 2) & 0xFC); - r8712_write8(adapter, EFUSE_CTRL + 2, tmpv8); - if (bRead) { - r8712_write8(adapter, EFUSE_CTRL + 3, 0x72); /* read cmd */ - while (!(0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) && - (tmpidx < 100)) - tmpidx++; - if (tmpidx < 100) { - *data = r8712_read8(adapter, EFUSE_CTRL); - bResult = true; - } else { - *data = 0; - bResult = false; - } - } else { - r8712_write8(adapter, EFUSE_CTRL, *data); /* data */ - r8712_write8(adapter, EFUSE_CTRL + 3, 0xF2); /* write cmd */ - while ((0x80 & r8712_read8(adapter, EFUSE_CTRL + 3)) && - (tmpidx < 100)) - tmpidx++; - if (tmpidx < 100) - bResult = true; - else - bResult = false; - } - return bResult; -} - -static u8 efuse_is_empty(struct _adapter *adapter, u8 *empty) -{ - u8 value, ret = true; - - /* read one byte to check if E-Fuse is empty */ - if (efuse_one_byte_rw(adapter, true, 0, &value)) { - if (value == 0xFF) - *empty = true; - else - *empty = false; - } else { - ret = false; - } - return ret; -} - -void r8712_efuse_change_max_size(struct _adapter *adapter) -{ - u16 pre_pg_data_saddr = 0x1FB; - u16 i; - u16 pre_pg_data_size = 5; - u8 pre_pg_data[5]; - - for (i = 0; i < pre_pg_data_size; i++) - efuse_one_byte_read(adapter, pre_pg_data_saddr + i, - &pre_pg_data[i]); - if ((pre_pg_data[0] == 0x03) && (pre_pg_data[1] == 0x00) && - (pre_pg_data[2] == 0x00) && (pre_pg_data[3] == 0x00) && - (pre_pg_data[4] == 0x0C)) - efuse_available_max_size -= pre_pg_data_size; -} - -int r8712_efuse_get_max_size(struct _adapter *adapter) -{ - return efuse_available_max_size; -} - -static u8 calculate_word_cnts(const u8 word_en) -{ - u8 word_cnts = 0; - u8 word_idx; - - for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) - if (!(word_en & BIT(word_idx))) - word_cnts++; /* 0 : write enable */ - return word_cnts; -} - -static void pgpacket_copy_data(const u8 word_en, const u8 *sourdata, - u8 *targetdata) -{ - u8 tmpindex = 0; - u8 word_idx, byte_idx; - - for (word_idx = 0; word_idx < PGPKG_MAX_WORDS; word_idx++) { - if (!(word_en & BIT(word_idx))) { - byte_idx = word_idx * 2; - targetdata[byte_idx] = sourdata[tmpindex++]; - targetdata[byte_idx + 1] = sourdata[tmpindex++]; - } - } -} - -u16 r8712_efuse_get_current_size(struct _adapter *adapter) -{ - int bContinual = true; - u16 efuse_addr = 0; - u8 hworden = 0; - u8 efuse_data, word_cnts = 0; - - while (bContinual && efuse_one_byte_read(adapter, efuse_addr, &efuse_data) && - (efuse_addr < efuse_available_max_size)) { - if (efuse_data != 0xFF) { - hworden = efuse_data & 0x0F; - word_cnts = calculate_word_cnts(hworden); - /* read next header */ - efuse_addr = efuse_addr + (word_cnts * 2) + 1; - } else { - bContinual = false; - } - } - return efuse_addr; -} - -u8 r8712_efuse_pg_packet_read(struct _adapter *adapter, u8 offset, u8 *data) -{ - u8 hoffset = 0, hworden = 0, word_cnts = 0; - u16 efuse_addr = 0; - u8 efuse_data; - u8 tmpidx = 0; - u8 tmpdata[PGPKT_DATA_SIZE]; - u8 ret = true; - - if (!data) - return false; - if (offset > 0x0f) - return false; - memset(data, 0xFF, sizeof(u8) * PGPKT_DATA_SIZE); - while (efuse_addr < efuse_available_max_size) { - if (efuse_one_byte_read(adapter, efuse_addr, &efuse_data)) { - if (efuse_data == 0xFF) - break; - hoffset = (efuse_data >> 4) & 0x0F; - hworden = efuse_data & 0x0F; - word_cnts = calculate_word_cnts(hworden); - if (hoffset == offset) { - memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); - for (tmpidx = 0; tmpidx < word_cnts * 2; - tmpidx++) { - if (efuse_one_byte_read(adapter, efuse_addr + 1 + tmpidx, - &efuse_data)) { - tmpdata[tmpidx] = efuse_data; - } else { - ret = false; - } - } - pgpacket_copy_data(hworden, tmpdata, data); - } - efuse_addr += 1 + (word_cnts * 2); - } else { - ret = false; - break; - } - } - return ret; -} - -static u8 fix_header(struct _adapter *adapter, u8 header, u16 header_addr) -{ - struct PGPKT_STRUCT pkt; - u8 offset, word_en, value; - u16 addr; - int i; - u8 ret = true; - - pkt.offset = GET_EFUSE_OFFSET(header); - pkt.word_en = GET_EFUSE_WORD_EN(header); - addr = header_addr + 1 + calculate_word_cnts(pkt.word_en) * 2; - if (addr > efuse_available_max_size) - return false; - /* retrieve original data */ - addr = 0; - while (addr < header_addr) { - if (!efuse_one_byte_read(adapter, addr++, &value)) { - ret = false; - break; - } - offset = GET_EFUSE_OFFSET(value); - word_en = GET_EFUSE_WORD_EN(value); - if (pkt.offset != offset) { - addr += calculate_word_cnts(word_en) * 2; - continue; - } - for (i = 0; i < PGPKG_MAX_WORDS; i++) { - if (!(BIT(i) & word_en)) - continue; - if (BIT(i) & pkt.word_en) { - if (efuse_one_byte_read(adapter, - addr, - &value)) - pkt.data[i * 2] = value; - else - return false; - if (efuse_one_byte_read(adapter, - addr + 1, - &value)) - pkt.data[i * 2 + 1] = value; - else - return false; - } - addr += 2; - } - } - if (addr != header_addr) - return false; - addr++; - /* fill original data */ - for (i = 0; i < PGPKG_MAX_WORDS; i++) { - if (BIT(i) & pkt.word_en) { - efuse_one_byte_write(adapter, addr, pkt.data[i * 2]); - efuse_one_byte_write(adapter, addr + 1, - pkt.data[i * 2 + 1]); - /* additional check */ - if (!efuse_one_byte_read(adapter, addr, &value)) { - ret = false; - } else if (pkt.data[i * 2] != value) { - ret = false; - if (value == 0xFF) /* write again */ - efuse_one_byte_write(adapter, addr, - pkt.data[i * 2]); - } - if (!efuse_one_byte_read(adapter, addr + 1, &value)) { - ret = false; - } else if (pkt.data[i * 2 + 1] != value) { - ret = false; - if (value == 0xFF) /* write again */ - efuse_one_byte_write(adapter, addr + 1, - pkt.data[i * 2 + - 1]); - } - } - addr += 2; - } - return ret; -} - -u8 r8712_efuse_pg_packet_write(struct _adapter *adapter, const u8 offset, - const u8 word_en, const u8 *data) -{ - u8 pg_header = 0; - u16 efuse_addr = 0, curr_size = 0; - u8 efuse_data, target_word_cnts = 0; - int repeat_times; - int sub_repeat; - u8 bResult = true; - - /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */ - efuse_data = r8712_read8(adapter, EFUSE_CLK_CTRL); - if (efuse_data != 0x03) - return false; - pg_header = MAKE_EFUSE_HEADER(offset, word_en); - target_word_cnts = calculate_word_cnts(word_en); - repeat_times = 0; - efuse_addr = 0; - while (efuse_addr < efuse_available_max_size) { - curr_size = r8712_efuse_get_current_size(adapter); - if ((curr_size + 1 + target_word_cnts * 2) > - efuse_available_max_size) - return false; /*target_word_cnts + pg header(1 byte)*/ - efuse_addr = curr_size; /* current size is also the last addr*/ - efuse_one_byte_write(adapter, efuse_addr, pg_header); /*hdr*/ - sub_repeat = 0; - /* check if what we read is what we write */ - while (!efuse_one_byte_read(adapter, efuse_addr, - &efuse_data)) { - if (++sub_repeat > _REPEAT_THRESHOLD_) { - bResult = false; /* continue to blind write */ - break; /* continue to blind write */ - } - } - if ((sub_repeat > _REPEAT_THRESHOLD_) || - (pg_header == efuse_data)) { - /* write header ok OR can't check header(creep) */ - u8 i; - - /* go to next address */ - efuse_addr++; - for (i = 0; i < target_word_cnts * 2; i++) { - efuse_one_byte_write(adapter, - efuse_addr + i, - *(data + i)); - if (!efuse_one_byte_read(adapter, - efuse_addr + i, - &efuse_data)) - bResult = false; - else if (*(data + i) != efuse_data) /* fail */ - bResult = false; - } - break; - } - /* write header fail */ - bResult = false; - if (efuse_data == 0xFF) - return bResult; /* nothing damaged. */ - /* call rescue procedure */ - if (!fix_header(adapter, efuse_data, efuse_addr)) - return false; /* rescue fail */ - - if (++repeat_times > _REPEAT_THRESHOLD_) /* fail */ - break; - /* otherwise, take another risk... */ - } - return bResult; -} - -u8 r8712_efuse_access(struct _adapter *adapter, u8 bRead, u16 start_addr, - u16 cnts, u8 *data) -{ - int i; - u8 res = true; - - if (start_addr > EFUSE_MAX_SIZE) - return false; - if (!bRead && ((start_addr + cnts) > - efuse_available_max_size)) - return false; - if (!bRead && !r8712_efuse_reg_init(adapter)) - return false; - /* -----------------e-fuse one byte read / write ---------------------*/ - for (i = 0; i < cnts; i++) { - if ((start_addr + i) > EFUSE_MAX_SIZE) { - res = false; - break; - } - res = efuse_one_byte_rw(adapter, bRead, start_addr + i, - data + i); - if (!bRead && !res) - break; - } - if (!bRead) - r8712_efuse_reg_uninit(adapter); - return res; -} - -u8 r8712_efuse_map_read(struct _adapter *adapter, u16 addr, u16 cnts, u8 *data) -{ - u8 offset, ret = true; - u8 pktdata[PGPKT_DATA_SIZE]; - int i, idx; - - if ((addr + cnts) > EFUSE_MAP_MAX_SIZE) - return false; - if (efuse_is_empty(adapter, &offset) && offset) { - for (i = 0; i < cnts; i++) - data[i] = 0xFF; - return ret; - } - offset = (addr >> 3) & 0xF; - ret = r8712_efuse_pg_packet_read(adapter, offset, pktdata); - i = addr & 0x7; /* pktdata index */ - idx = 0; /* data index */ - - do { - for (; i < PGPKT_DATA_SIZE; i++) { - data[idx++] = pktdata[i]; - if (idx == cnts) - return ret; - } - offset++; - if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata)) - ret = false; - i = 0; - } while (1); - return ret; -} - -u8 r8712_efuse_map_write(struct _adapter *adapter, u16 addr, u16 cnts, - u8 *data) -{ - u8 offset, word_en, empty; - u8 pktdata[PGPKT_DATA_SIZE], newdata[PGPKT_DATA_SIZE]; - int i, j, idx; - - if ((addr + cnts) > EFUSE_MAP_MAX_SIZE) - return false; - /* check if E-Fuse Clock Enable and E-Fuse Clock is 40M */ - empty = r8712_read8(adapter, EFUSE_CLK_CTRL); - if (empty != 0x03) - return false; - if (efuse_is_empty(adapter, &empty)) { - if (empty) - memset(pktdata, 0xFF, PGPKT_DATA_SIZE); - } else { - return false; - } - offset = (addr >> 3) & 0xF; - if (!empty) - if (!r8712_efuse_pg_packet_read(adapter, offset, pktdata)) - return false; - word_en = 0xF; - memset(newdata, 0xFF, PGPKT_DATA_SIZE); - i = addr & 0x7; /* pktdata index */ - j = 0; /* newdata index */ - idx = 0; /* data index */ - - if (i & 0x1) { - /* odd start */ - if (data[idx] != pktdata[i]) { - word_en &= ~BIT(i >> 1); - newdata[j++] = pktdata[i - 1]; - newdata[j++] = data[idx]; - } - i++; - idx++; - } - do { - for (; i < PGPKT_DATA_SIZE; i += 2) { - if ((cnts - idx) == 1) { - if (data[idx] != pktdata[i]) { - word_en &= ~BIT(i >> 1); - newdata[j++] = data[idx]; - newdata[j++] = pktdata[1 + 1]; - } - idx++; - break; - } - - if ((data[idx] != pktdata[i]) || (data[idx + 1] != - pktdata[i + 1])) { - word_en &= ~BIT(i >> 1); - newdata[j++] = data[idx]; - newdata[j++] = data[idx + 1]; - } - idx += 2; - - if (idx == cnts) - break; - } - - if (word_en != 0xF) - if (!r8712_efuse_pg_packet_write(adapter, offset, - word_en, newdata)) - return false; - if (idx == cnts) - break; - offset++; - if (!empty) - if (!r8712_efuse_pg_packet_read(adapter, offset, - pktdata)) - return false; - i = 0; - j = 0; - word_en = 0xF; - memset(newdata, 0xFF, PGPKT_DATA_SIZE); - } while (1); - - return true; -} diff --git a/drivers/staging/rtl8712/rtl8712_efuse.h b/drivers/staging/rtl8712/rtl8712_efuse.h deleted file mode 100644 index 7a49740212eb5c..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_efuse.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __RTL8712_EFUSE_H__ -#define __RTL8712_EFUSE_H__ - -#include "osdep_service.h" - -#define _REPEAT_THRESHOLD_ 3 - -#define EFUSE_MAX_SIZE 512 -#define EFUSE_MAP_MAX_SIZE 128 - -#define PGPKG_MAX_WORDS 4 -#define PGPKT_DATA_SIZE 8 /* PGPKG_MAX_WORDS*2; BYTES sizeof(u8)*8*/ -#define MAX_PGPKT_SIZE 9 /* 1 + PGPKT_DATA_SIZE; header + 2 * 4 words (BYTES)*/ - -#define GET_EFUSE_OFFSET(header) ((header & 0xF0) >> 4) -#define GET_EFUSE_WORD_EN(header) (header & 0x0F) -#define MAKE_EFUSE_HEADER(offset, word_en) ((((offset) & 0x0F) << 4) | \ - ((word_en) & 0x0F)) -/*--------------------------------------------------------------------------*/ -struct PGPKT_STRUCT { - u8 offset; - u8 word_en; - u8 data[PGPKT_DATA_SIZE]; -}; - -/*--------------------------------------------------------------------------*/ -u8 r8712_efuse_reg_init(struct _adapter *padapter); -void r8712_efuse_reg_uninit(struct _adapter *padapter); -u16 r8712_efuse_get_current_size(struct _adapter *padapter); -int r8712_efuse_get_max_size(struct _adapter *padapter); -void r8712_efuse_change_max_size(struct _adapter *padapter); -u8 r8712_efuse_pg_packet_read(struct _adapter *padapter, - u8 offset, u8 *data); -u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, - const u8 offset, const u8 word_en, - const u8 *data); -u8 r8712_efuse_access(struct _adapter *padapter, u8 bRead, - u16 start_addr, u16 cnts, u8 *data); -u8 r8712_efuse_map_read(struct _adapter *padapter, u16 addr, - u16 cnts, u8 *data); -u8 r8712_efuse_map_write(struct _adapter *padapter, u16 addr, - u16 cnts, u8 *data); -#endif diff --git a/drivers/staging/rtl8712/rtl8712_event.h b/drivers/staging/rtl8712/rtl8712_event.h deleted file mode 100644 index 0d3e5feadcc010..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_event.h +++ /dev/null @@ -1,86 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL8712_EVENT_H_ -#define _RTL8712_EVENT_H_ - -void r8712_event_handle(struct _adapter *padapter, __le32 *peventbuf); -void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf); - -enum rtl8712_c2h_event { - GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/ - GEN_EVT_CODE(_Read_BBREG), - GEN_EVT_CODE(_Read_RFREG), - GEN_EVT_CODE(_Read_EEPROM), - GEN_EVT_CODE(_Read_EFUSE), - GEN_EVT_CODE(_Read_CAM), /*5*/ - GEN_EVT_CODE(_Get_BasicRate), - GEN_EVT_CODE(_Get_DataRate), - GEN_EVT_CODE(_Survey), /*8*/ - GEN_EVT_CODE(_SurveyDone), /*9*/ - - GEN_EVT_CODE(_JoinBss), /*10*/ - GEN_EVT_CODE(_AddSTA), - GEN_EVT_CODE(_DelSTA), - GEN_EVT_CODE(_AtimDone), - GEN_EVT_CODE(_TX_Report), - GEN_EVT_CODE(_CCX_Report), /*15*/ - GEN_EVT_CODE(_DTM_Report), - GEN_EVT_CODE(_TX_Rate_Statistics), - GEN_EVT_CODE(_C2HLBK), - GEN_EVT_CODE(_FWDBG), - GEN_EVT_CODE(_C2HFEEDBACK), /*20*/ - GEN_EVT_CODE(_ADDBA), - GEN_EVT_CODE(_C2HBCN), - GEN_EVT_CODE(_ReportPwrState), /*filen: only for PCIE, USB*/ - GEN_EVT_CODE(_WPS_PBC), /*24*/ - GEN_EVT_CODE(_ADDBAReq_Report), /*25*/ - MAX_C2HEVT -}; - -#ifdef _RTL8712_CMD_C_ - -static struct fwevent wlanevents[] = { - {0, NULL}, /*0*/ - {0, NULL}, - {0, NULL}, - {0, NULL}, - {0, NULL}, - {0, NULL}, - {0, NULL}, - {0, NULL}, - {0, &r8712_survey_event_callback}, /*8*/ - {sizeof(struct surveydone_event), - &r8712_surveydone_event_callback}, /*9*/ - - {0, &r8712_joinbss_event_callback}, /*10*/ - {sizeof(struct stassoc_event), &r8712_stassoc_event_callback}, - {sizeof(struct stadel_event), &r8712_stadel_event_callback}, - {0, &r8712_atimdone_event_callback}, - {0, NULL}, - {0, NULL}, /*15*/ - {0, NULL}, - {0, NULL}, - {0, NULL}, - {0, NULL}, /*fwdbg_event_callback},*/ - {0, NULL}, /*20*/ - {0, NULL}, - {0, NULL}, - {0, &r8712_cpwm_event_callback}, - {0, &r8712_wpspbc_event_callback}, - {0, &r8712_got_addbareq_event_callback}, -}; - -#endif/*_RTL8712_CMD_C_*/ - -#endif diff --git a/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h deleted file mode 100644 index f09645fa1886e4..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h +++ /dev/null @@ -1,131 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_FIFOCTRL_BITDEF_H__ -#define __RTL8712_FIFOCTRL_BITDEF_H__ - -/*PBP*/ -#define _PSTX_MSK 0xF0 -#define _PSTX_SHT 4 -#define _PSRX_MSK 0x0F -#define _PSRX_SHT 0 - -/*TXFF_STATUS*/ -#define _TXSTATUS_OVF BIT(15) - -/*RXFF_STATUS*/ -#define _STATUSFF1_OVF BIT(7) -#define _STATUSFF1_EMPTY BIT(6) -#define _STATUSFF0_OVF BIT(5) -#define _STATUSFF0_EMPTY BIT(4) -#define _RXFF1_OVF BIT(3) -#define _RXFF1_EMPTY BIT(2) -#define _RXFF0_OVF BIT(1) -#define _RXFF0_EMPTY BIT(0) - -/*TXFF_EMPTY_TH*/ -#define _BKQ_EMPTY_TH_MSK 0x0F0000 -#define _BKQ_EMPTY_TH_SHT 16 -#define _BEQ_EMPTY_TH_MSK 0x00F000 -#define _BEQ_EMPTY_TH_SHT 12 -#define _VIQ_EMPTY_TH_MSK 0x000F00 -#define _VIQ_EMPTY_TH_SHT 8 -#define _VOQ_EMPTY_TH_MSK 0x0000F0 -#define _VOQ_EMPTY_TH_SHT 4 -#define _BMCQ_EMPTY_TH_MSK 0x00000F -#define _BMCQ_EMPTY_TH_SHT 0 - -/*SDIO_RX_BLKSZ*/ -#define _SDIO_RX_BLKSZ_MSK 0x07 - -/*RXDMA_CTRL*/ -#define _C2HFF_POLL BIT(4) -#define _RXPKT_POLL BIT(0) - -/*RXPKT_NUM*/ -#define _RXCMD_NUM_MSK 0xFF00 -#define _RXCMD_NUM_SHT 8 -#define _RXFF0_NUM_MSK 0x00FF -#define _RXFF0_NUM_SHT 0 - -/*FIFOPAGE2*/ -#define _PUB_AVAL_PG_MSK 0xFFFF0000 -#define _PUB_AVAL_PG_SHT 16 -#define _BCN_AVAL_PG_MSK 0x0000FFFF -#define _BCN_AVAL_PG_SHT 0 - -/*RX0PKTNUM*/ -#define _RXFF0_DEC_POLL BIT(15) -#define _RXFF0_PKT_DEC_NUM_MSK 0x3F00 -#define _RXFF0_PKT_DEC_NUM_SHT 8 -#define _RXFF0_PKTNUM_RPT_MSK 0x00FF -#define _RXFF0_PKTNUM_RPT_SHT 0 - -/*RX1PKTNUM*/ -#define _RXFF1_DEC_POLL BIT(15) -#define _RXFF1_PKT_DEC_NUM_MSK 0x3F00 -#define _RXFF1_PKT_DEC_NUM_SHT 8 -#define _RXFF1_PKTNUM_RPT_MSK 0x00FF -#define _RXFF1_PKTNUM_RPT_SHT 0 - -/*RXFLTMAP0*/ -#define _MGTFLT13EN BIT(13) -#define _MGTFLT12EN BIT(12) -#define _MGTFLT11EN BIT(11) -#define _MGTFLT10EN BIT(10) -#define _MGTFLT9EN BIT(9) -#define _MGTFLT8EN BIT(8) -#define _MGTFLT5EN BIT(5) -#define _MGTFLT4EN BIT(4) -#define _MGTFLT3EN BIT(3) -#define _MGTFLT2EN BIT(2) -#define _MGTFLT1EN BIT(1) -#define _MGTFLT0EN BIT(0) - -/*RXFLTMAP1*/ -#define _CTRLFLT15EN BIT(15) -#define _CTRLFLT14EN BIT(14) -#define _CTRLFLT13EN BIT(13) -#define _CTRLFLT12EN BIT(12) -#define _CTRLFLT11EN BIT(11) -#define _CTRLFLT10EN BIT(10) -#define _CTRLFLT9EN BIT(9) -#define _CTRLFLT8EN BIT(8) -#define _CTRLFLT7EN BIT(7) -#define _CTRLFLT6EN BIT(6) - -/*RXFLTMAP2*/ -#define _DATAFLT15EN BIT(15) -#define _DATAFLT14EN BIT(14) -#define _DATAFLT13EN BIT(13) -#define _DATAFLT12EN BIT(12) -#define _DATAFLT11EN BIT(11) -#define _DATAFLT10EN BIT(10) -#define _DATAFLT9EN BIT(9) -#define _DATAFLT8EN BIT(8) -#define _DATAFLT7EN BIT(7) -#define _DATAFLT6EN BIT(6) -#define _DATAFLT5EN BIT(5) -#define _DATAFLT4EN BIT(4) -#define _DATAFLT3EN BIT(3) -#define _DATAFLT2EN BIT(2) -#define _DATAFLT1EN BIT(1) -#define _DATAFLT0EN BIT(0) - -/*RXFLTMAP3*/ -#define _MESHAFLT1EN BIT(1) -#define _MESHAFLT0EN BIT(0) - -/*TXPKT_NUM_CTRL*/ -#define _TXPKTNUM_DEC BIT(8) -#define _TXPKTNUM_MSK 0x00FF -#define _TXPKTNUM_SHT 0 - -/*TXFF_PG_NUM*/ -#define _TXFF_PG_NUM_MSK 0x0FFF - -#endif /* __RTL8712_FIFOCTRL_BITDEF_H__ */ - diff --git a/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h deleted file mode 100644 index 189fdeb16d7d31..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_FIFOCTRL_REGDEF_H__ -#define __RTL8712_FIFOCTRL_REGDEF_H__ - -#define RQPN (RTL8712_FIFOCTRL_ + 0x00) -#define RXFF_BNDY (RTL8712_FIFOCTRL_ + 0x0C) -#define RXRPT_BNDY (RTL8712_FIFOCTRL_ + 0x10) -#define TXPKTBUF_PGBNDY (RTL8712_FIFOCTRL_ + 0x14) -#define PBP (RTL8712_FIFOCTRL_ + 0x15) -#define RX_DRVINFO_SZ (RTL8712_FIFOCTRL_ + 0x16) -#define TXFF_STATUS (RTL8712_FIFOCTRL_ + 0x17) -#define RXFF_STATUS (RTL8712_FIFOCTRL_ + 0x18) -#define TXFF_EMPTY_TH (RTL8712_FIFOCTRL_ + 0x19) -#define SDIO_RX_BLKSZ (RTL8712_FIFOCTRL_ + 0x1C) -#define RXDMA_RXCTRL (RTL8712_FIFOCTRL_ + 0x1D) -#define RXPKT_NUM (RTL8712_FIFOCTRL_ + 0x1E) -#define RXPKT_NUM_C2H (RTL8712_FIFOCTRL_ + 0x1F) -#define C2HCMD_UDT_SIZE (RTL8712_FIFOCTRL_ + 0x20) -#define C2HCMD_UDT_ADDR (RTL8712_FIFOCTRL_ + 0x22) -#define FIFOPAGE2 (RTL8712_FIFOCTRL_ + 0x24) -#define FIFOPAGE1 (RTL8712_FIFOCTRL_ + 0x28) -#define FW_RSVD_PG_CTRL (RTL8712_FIFOCTRL_ + 0x30) -#define TXRPTFF_RDPTR (RTL8712_FIFOCTRL_ + 0x40) -#define TXRPTFF_WTPTR (RTL8712_FIFOCTRL_ + 0x44) -#define C2HFF_RDPTR (RTL8712_FIFOCTRL_ + 0x48) -#define C2HFF_WTPTR (RTL8712_FIFOCTRL_ + 0x4C) -#define RXFF0_RDPTR (RTL8712_FIFOCTRL_ + 0x50) -#define RXFF0_WTPTR (RTL8712_FIFOCTRL_ + 0x54) -#define RXFF1_RDPTR (RTL8712_FIFOCTRL_ + 0x58) -#define RXFF1_WTPTR (RTL8712_FIFOCTRL_ + 0x5C) -#define RXRPT0FF_RDPTR (RTL8712_FIFOCTRL_ + 0x60) -#define RXRPT0FF_WTPTR (RTL8712_FIFOCTRL_ + 0x64) -#define RXRPT1FF_RDPTR (RTL8712_FIFOCTRL_ + 0x68) -#define RXRPT1FF_WTPTR (RTL8712_FIFOCTRL_ + 0x6C) -#define RX0PKTNUM (RTL8712_FIFOCTRL_ + 0x72) -#define RX1PKTNUM (RTL8712_FIFOCTRL_ + 0x74) -#define RXFLTMAP0 (RTL8712_FIFOCTRL_ + 0x76) -#define RXFLTMAP1 (RTL8712_FIFOCTRL_ + 0x78) -#define RXFLTMAP2 (RTL8712_FIFOCTRL_ + 0x7A) -#define RXFLTMAP3 (RTL8712_FIFOCTRL_ + 0x7c) -#define TBDA (RTL8712_FIFOCTRL_ + 0x84) -#define THPDA (RTL8712_FIFOCTRL_ + 0x88) -#define TCDA (RTL8712_FIFOCTRL_ + 0x8C) -#define TMDA (RTL8712_FIFOCTRL_ + 0x90) -#define HDA (RTL8712_FIFOCTRL_ + 0x94) -#define TVODA (RTL8712_FIFOCTRL_ + 0x98) -#define TVIDA (RTL8712_FIFOCTRL_ + 0x9C) -#define TBEDA (RTL8712_FIFOCTRL_ + 0xA0) -#define TBKDA (RTL8712_FIFOCTRL_ + 0xA4) -#define RCDA (RTL8712_FIFOCTRL_ + 0xA8) -#define RDSA (RTL8712_FIFOCTRL_ + 0xAC) -#define TXPKT_NUM_CTRL (RTL8712_FIFOCTRL_ + 0xB0) -#define TXQ_PGADD (RTL8712_FIFOCTRL_ + 0xB3) -#define TXFF_PG_NUM (RTL8712_FIFOCTRL_ + 0xB4) - -#endif /* __RTL8712_FIFOCTRL_REGDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h deleted file mode 100644 index ee651fb3fde3fc..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_GP_BITDEF_H__ -#define __RTL8712_GP_BITDEF_H__ - -/*GPIO_CTRL*/ -#define _GPIO_MOD_MSK 0xFF000000 -#define _GPIO_MOD_SHT 24 -#define _GPIO_IO_SEL_MSK 0x00FF0000 -#define _GPIO_IO_SEL_SHT 16 -#define _GPIO_OUT_MSK 0x0000FF00 -#define _GPIO_OUT_SHT 8 -#define _GPIO_IN_MSK 0x000000FF -#define _GPIO_IN_SHT 0 - -/*SYS_PINMUX_CFG*/ -#define _GPIOSEL_MSK 0x0003 -#define _GPIOSEL_SHT 0 - -/*LED_CFG*/ -#define _LED1SV BIT(7) -#define _LED1CM_MSK 0x0070 -#define _LED1CM_SHT 4 -#define _LED0SV BIT(3) -#define _LED0CM_MSK 0x0007 -#define _LED0CM_SHT 0 - -/*PHY_REG*/ -#define _HST_RDRDY_SHT 0 -#define _HST_RDRDY_MSK 0xFF -#define _HST_RDRDY BIT(_HST_RDRDY_SHT) -#define _CPU_WTBUSY_SHT 1 -#define _CPU_WTBUSY_MSK 0xFF -#define _CPU_WTBUSY BIT(_CPU_WTBUSY_SHT) - -/* 11. General Purpose Registers (Offset: 0x02E0 - 0x02FF)*/ - -/* 8192S GPIO Config Setting (offset 0x2F1, 1 byte)*/ - -/*----------------------------------------------------------------------------*/ - -#define GPIOMUX_EN BIT(3) /* When this bit is set to "1", - * GPIO PINs will switch to MAC - * GPIO Function - */ -#define GPIOSEL_GPIO 0 /* UART or JTAG or pure GPIO*/ -#define GPIOSEL_PHYDBG 1 /* PHYDBG*/ -#define GPIOSEL_BT 2 /* BT_coex*/ -#define GPIOSEL_WLANDBG 3 /* WLANDBG*/ -#define GPIOSEL_GPIO_MASK (~(BIT(0) | BIT(1))) -/* HW Radio OFF switch (GPIO BIT) */ -#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3) -#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7 -#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4) - -#endif /*__RTL8712_GP_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_gp_regdef.h b/drivers/staging/rtl8712/rtl8712_gp_regdef.h deleted file mode 100644 index 892a7fb1392355..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_gp_regdef.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_GP_REGDEF_H__ -#define __RTL8712_GP_REGDEF_H__ - -#define PSTIMER (RTL8712_GP_ + 0x00) -#define TIMER1 (RTL8712_GP_ + 0x04) -#define TIMER2 (RTL8712_GP_ + 0x08) -#define GPIO_CTRL (RTL8712_GP_ + 0x0C) -#define GPIO_IO_SEL (RTL8712_GP_ + 0x0E) -#define GPIO_INTCTRL (RTL8712_GP_ + 0x10) -#define MAC_PINMUX_CTRL (RTL8712_GP_ + 0x11) -#define LEDCFG (RTL8712_GP_ + 0x12) -#define PHY_REG_RPT (RTL8712_GP_ + 0x13) -#define PHY_REG_DATA (RTL8712_GP_ + 0x14) - -#endif /*__RTL8712_GP_REGDEF_H__ */ - diff --git a/drivers/staging/rtl8712/rtl8712_hal.h b/drivers/staging/rtl8712/rtl8712_hal.h deleted file mode 100644 index 66cc4645e2d1c9..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_hal.h +++ /dev/null @@ -1,142 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_HAL_H__ -#define __RTL8712_HAL_H__ - -enum _HW_VERSION { - RTL8712_FPGA, - RTL8712_1stCUT, /*A Cut (RTL8712_ASIC)*/ - RTL8712_2ndCUT, /*B Cut*/ - RTL8712_3rdCUT, /*C Cut*/ -}; - -enum _LOOPBACK_TYPE { - RTL8712_AIR_TRX = 0, - RTL8712_MAC_LBK, - RTL8712_BB_LBK, - RTL8712_MAC_FW_LBK = 4, - RTL8712_BB_FW_LBK = 8, -}; - -enum RTL871X_HCI_TYPE { - RTL8712_SDIO, - RTL8712_USB, -}; - -enum RTL8712_RF_CONFIG { - RTL8712_RF_1T1R, - RTL8712_RF_1T2R, - RTL8712_RF_2T2R -}; - -enum _RTL8712_HCI_TYPE_ { - RTL8712_HCI_TYPE_PCIE = 0x01, - RTL8712_HCI_TYPE_AP_PCIE = 0x81, - RTL8712_HCI_TYPE_USB = 0x02, - RTL8712_HCI_TYPE_92USB = 0x02, - RTL8712_HCI_TYPE_AP_USB = 0x82, - RTL8712_HCI_TYPE_72USB = 0x12, - RTL8712_HCI_TYPE_SDIO = 0x04, - RTL8712_HCI_TYPE_72SDIO = 0x14 -}; - -struct fw_priv { /*8-bytes alignment required*/ - /*--- long word 0 ----*/ - unsigned char signature_0; /*0x12: CE product, 0x92: IT product*/ - unsigned char signature_1; /*0x87: CE product, 0x81: IT product*/ - unsigned char hci_sel; /*0x81: PCI-AP, 01:PCIe, 02: 92S-U, 0x82: USB-AP, - * 0x12: 72S-U, 03:SDIO - */ - unsigned char chip_version; /*the same value as register value*/ - unsigned char customer_ID_0; /*customer ID low byte*/ - unsigned char customer_ID_1; /*customer ID high byte*/ - unsigned char rf_config; /*0x11: 1T1R, 0x12: 1T2R, 0x92: 1T2R turbo, - * 0x22: 2T2R - */ - unsigned char usb_ep_num; /* 4: 4EP, 6: 6EP, 11: 11EP*/ - /*--- long word 1 ----*/ - unsigned char regulatory_class_0; /*regulatory class bit map 0*/ - unsigned char regulatory_class_1; /*regulatory class bit map 1*/ - unsigned char regulatory_class_2; /*regulatory class bit map 2*/ - unsigned char regulatory_class_3; /*regulatory class bit map 3*/ - unsigned char rfintfs; /* 0:SWSI, 1:HWSI, 2:HWPI*/ - unsigned char def_nettype; - unsigned char turbo_mode; - unsigned char low_power_mode;/* 0: normal mode, 1: low power mode*/ - /*--- long word 2 ----*/ - unsigned char lbk_mode; /*0x00: normal, 0x03: MACLBK, 0x01: PHYLBK*/ - unsigned char mp_mode; /* 1: for MP use, 0: for normal driver */ - unsigned char vcs_type; /* 0:off 1:on 2:auto */ - unsigned char vcs_mode; /* 1:RTS/CTS 2:CTS to self */ - unsigned char rsvd022; - unsigned char rsvd023; - unsigned char rsvd024; - unsigned char rsvd025; - /*--- long word 3 ----*/ - unsigned char qos_en; /*1: QoS enable*/ - unsigned char bw_40MHz_en; /*1: 40MHz BW enable*/ - unsigned char AMSDU2AMPDU_en; /*1: 4181 convert AMSDU to AMPDU, - * 0: disable - */ - unsigned char AMPDU_en; /*1: 11n AMPDU enable*/ - unsigned char rate_control_offload; /*1: FW offloads,0: driver handles*/ - unsigned char aggregation_offload; /*1: FW offloads,0: driver handles*/ - unsigned char rsvd030; - unsigned char rsvd031; - /*--- long word 4 ----*/ - unsigned char beacon_offload; /* 1. FW offloads, 0: driver handles*/ - unsigned char MLME_offload; /* 2. FW offloads, 0: driver handles*/ - unsigned char hwpc_offload; /* 3. FW offloads, 0: driver handles*/ - unsigned char tcp_checksum_offload; /*4. FW offloads,0: driver handles*/ - unsigned char tcp_offload; /* 5. FW offloads, 0: driver handles*/ - unsigned char ps_control_offload; /* 6. FW offloads, 0: driver handles*/ - unsigned char WWLAN_offload; /* 7. FW offloads, 0: driver handles*/ - unsigned char rsvd040; - /*--- long word 5 ----*/ - unsigned char tcp_tx_frame_len_L; /*tcp tx packet length low byte*/ - unsigned char tcp_tx_frame_len_H; /*tcp tx packet length high byte*/ - unsigned char tcp_rx_frame_len_L; /*tcp rx packet length low byte*/ - unsigned char tcp_rx_frame_len_H; /*tcp rx packet length high byte*/ - unsigned char rsvd050; - unsigned char rsvd051; - unsigned char rsvd052; - unsigned char rsvd053; -}; - -struct fw_hdr {/*8-byte alignment required*/ - unsigned short signature; - unsigned short version; /* 0x8000 ~ 0x8FFF for FPGA version, - * 0x0000 ~ 0x7FFF for ASIC version, - */ - unsigned int dmem_size; /*define the size of boot loader*/ - unsigned int img_IMEM_size; /*define the size of FW in IMEM*/ - unsigned int img_SRAM_size; /*define the size of FW in SRAM*/ - unsigned int fw_priv_sz; /*define the size of DMEM variable*/ - unsigned short efuse_addr; - unsigned short h2ccnd_resp_addr; - unsigned int SVNRevision; - unsigned int release_time; /*Mon:Day:Hr:Min*/ - struct fw_priv fwpriv; -}; - -struct hal_priv { - /*Endpoint handles*/ - struct net_device *pipehdls_r8712[10]; - u8 (*hal_bus_init)(struct _adapter *adapter); -}; - -uint rtl8712_hal_init(struct _adapter *padapter); -int rtl871x_load_fw(struct _adapter *padapter); - -#endif diff --git a/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h b/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h deleted file mode 100644 index e9732a1bcd7ef8..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_INTERRUPT_BITDEF_H__ -#define __RTL8712_INTERRUPT_BITDEF_H__ - -/*HIMR*/ -/*HISR*/ -#define _CPUERR BIT(29) -#define _ATIMEND BIT(28) -#define _TXBCNOK BIT(27) -#define _TXBCNERR BIT(26) -#define _BCNDMAINT4 BIT(25) -#define _BCNDMAINT3 BIT(24) -#define _BCNDMAINT2 BIT(23) -#define _BCNDMAINT1 BIT(22) -#define _BCNDOK4 BIT(21) -#define _BCNDOK3 BIT(20) -#define _BCNDOK2 BIT(19) -#define _BCNDOK1 BIT(18) -#define _TIMEOUT2 BIT(17) -#define _TIMEOUT1 BIT(16) -#define _TXFOVW BIT(15) -#define _PSTIMEOUT BIT(14) -#define _BCNDMAINT0 BIT(13) -#define _FOVW BIT(12) -#define _RDU BIT(11) -#define _RXCMDOK BIT(10) -#define _BCNDOK0 BIT(9) -#define _HIGHDOK BIT(8) -#define _COMDOK BIT(7) -#define _MGTDOK BIT(6) -#define _HCCADOK BIT(5) -#define _BKDOK BIT(4) -#define _BEDOK BIT(3) -#define _VIDOK BIT(2) -#define _VODOK BIT(1) -#define _RXOK BIT(0) - -#endif /*__RTL8712_INTERRUPT_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_io.c b/drivers/staging/rtl8712/rtl8712_io.c deleted file mode 100644 index 384cbdb05e1963..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_io.c +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl8712_io.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE . - * Larry Finger - * - ******************************************************************************/ - -#define _RTL8712_IO_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "rtl871x_io.h" -#include "osdep_intf.h" -#include "usb_ops.h" - -u8 r8712_read8(struct _adapter *adapter, u32 addr) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - return hdl->io_ops._read8(hdl, addr); -} - -u16 r8712_read16(struct _adapter *adapter, u32 addr) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - return hdl->io_ops._read16(hdl, addr); -} - -u32 r8712_read32(struct _adapter *adapter, u32 addr) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - return hdl->io_ops._read32(hdl, addr); -} - -void r8712_write8(struct _adapter *adapter, u32 addr, u8 val) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - hdl->io_ops._write8(hdl, addr, val); -} - -void r8712_write16(struct _adapter *adapter, u32 addr, u16 val) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - hdl->io_ops._write16(hdl, addr, val); -} - -void r8712_write32(struct _adapter *adapter, u32 addr, u32 val) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - hdl->io_ops._write32(hdl, addr, val); -} - -void r8712_read_mem(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - if (adapter->driver_stopped || adapter->surprise_removed) - return; - - hdl->io_ops._read_mem(hdl, addr, cnt, pmem); -} - -void r8712_write_mem(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - hdl->io_ops._write_mem(hdl, addr, cnt, pmem); -} - -void r8712_read_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - if (adapter->driver_stopped || adapter->surprise_removed) - return; - - hdl->io_ops._read_port(hdl, addr, cnt, pmem); -} - -void r8712_write_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem) -{ - struct intf_hdl *hdl = &adapter->pio_queue->intf; - - hdl->io_ops._write_port(hdl, addr, cnt, pmem); -} diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c deleted file mode 100644 index 6d9be5dec4e728..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_led.c +++ /dev/null @@ -1,1830 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl8712_led.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#include "drv_types.h" - -/*=========================================================================== - * Constant. - *=========================================================================== - - * - * Default LED behavior. - */ -#define LED_BLINK_NORMAL_INTERVAL 100 -#define LED_BLINK_SLOWLY_INTERVAL 200 -#define LED_BLINK_LONG_INTERVAL 400 - -#define LED_BLINK_NO_LINK_INTERVAL_ALPHA 1000 -#define LED_BLINK_LINK_INTERVAL_ALPHA 500 -#define LED_BLINK_SCAN_INTERVAL_ALPHA 180 -#define LED_BLINK_FASTER_INTERVAL_ALPHA 50 -#define LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA 5000 - -/*=========================================================================== - * LED object. - *=========================================================================== - */ -enum _LED_STATE_871x { - LED_UNKNOWN = 0, - LED_STATE_ON = 1, - LED_STATE_OFF = 2, - LED_BLINK_NORMAL = 3, - LED_BLINK_SLOWLY = 4, - LED_POWER_ON_BLINK = 5, - LED_SCAN_BLINK = 6, /* LED is blinking during scanning period, - * the # of times to blink is depend on time - * for scanning. - */ - LED_NO_LINK_BLINK = 7, /* LED is blinking during no link state. */ - LED_BLINK_StartToBlink = 8,/* Customized for Sercomm Printer - * Server case - */ - LED_BLINK_WPS = 9, /* LED is blinkg during WPS communication */ - LED_TXRX_BLINK = 10, - LED_BLINK_WPS_STOP = 11, /*for ALPHA */ - LED_BLINK_WPS_STOP_OVERLAP = 12, /*for BELKIN */ -}; - -/*=========================================================================== - * Prototype of protected function. - *=========================================================================== - */ -static void BlinkTimerCallback(struct timer_list *t); - -static void BlinkWorkItemCallback(struct work_struct *work); -/*=========================================================================== - * LED_819xUsb routines. - *=========================================================================== - * - * - * - * Description: - * Initialize an LED_871x object. - */ -static void InitLed871x(struct _adapter *padapter, struct LED_871x *pLed, - enum LED_PIN_871x LedPin) -{ - pLed->padapter = padapter; - pLed->LedPin = LedPin; - pLed->CurrLedState = LED_STATE_OFF; - pLed->bLedOn = false; - pLed->bLedBlinkInProgress = false; - pLed->BlinkTimes = 0; - pLed->BlinkingLedState = LED_UNKNOWN; - timer_setup(&pLed->BlinkTimer, BlinkTimerCallback, 0); - INIT_WORK(&pLed->BlinkWorkItem, BlinkWorkItemCallback); -} - -/* - * Description: - * DeInitialize an LED_871x object. - */ -static void DeInitLed871x(struct LED_871x *pLed) -{ - del_timer_sync(&pLed->BlinkTimer); - /* We should reset bLedBlinkInProgress if we cancel - * the LedControlTimer, - */ - pLed->bLedBlinkInProgress = false; -} - -/* - * Description: - * Turn on LED according to LedPin specified. - */ -static void SwLedOn(struct _adapter *padapter, struct LED_871x *pLed) -{ - u8 LedCfg; - - if (padapter->surprise_removed || padapter->driver_stopped) - return; - LedCfg = r8712_read8(padapter, LEDCFG); - switch (pLed->LedPin) { - case LED_PIN_GPIO0: - break; - case LED_PIN_LED0: - /* SW control led0 on.*/ - r8712_write8(padapter, LEDCFG, LedCfg & 0xf0); - break; - case LED_PIN_LED1: - /* SW control led1 on.*/ - r8712_write8(padapter, LEDCFG, LedCfg & 0x0f); - break; - default: - break; - } - pLed->bLedOn = true; -} - -/* - * Description: - * Turn off LED according to LedPin specified. - */ -static void SwLedOff(struct _adapter *padapter, struct LED_871x *pLed) -{ - u8 LedCfg; - - if (padapter->surprise_removed || padapter->driver_stopped) - return; - LedCfg = r8712_read8(padapter, LEDCFG); - switch (pLed->LedPin) { - case LED_PIN_GPIO0: - break; - case LED_PIN_LED0: - LedCfg &= 0xf0; /* Set to software control.*/ - r8712_write8(padapter, LEDCFG, (LedCfg | BIT(3))); - break; - case LED_PIN_LED1: - LedCfg &= 0x0f; /* Set to software control.*/ - r8712_write8(padapter, LEDCFG, (LedCfg | BIT(7))); - break; - default: - break; - } - pLed->bLedOn = false; -} - -/*=========================================================================== - * Interface to manipulate LED objects. - *=========================================================================== - * - * Description: - * Initialize all LED_871x objects. - */ -void r8712_InitSwLeds(struct _adapter *padapter) -{ - struct led_priv *pledpriv = &padapter->ledpriv; - - pledpriv->LedControlHandler = LedControl871x; - InitLed871x(padapter, &pledpriv->SwLed0, LED_PIN_LED0); - InitLed871x(padapter, &pledpriv->SwLed1, LED_PIN_LED1); -} - -/* Description: - * DeInitialize all LED_819xUsb objects. - */ -void r8712_DeInitSwLeds(struct _adapter *padapter) -{ - struct led_priv *ledpriv = &padapter->ledpriv; - - DeInitLed871x(&ledpriv->SwLed0); - DeInitLed871x(&ledpriv->SwLed1); -} - -/* Description: - * Implementation of LED blinking behavior. - * It toggle off LED and schedule corresponding timer if necessary. - */ -static void SwLedBlink(struct LED_871x *pLed) -{ - struct _adapter *padapter = pLed->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == LED_STATE_ON) - SwLedOn(padapter, pLed); - else - SwLedOff(padapter, pLed); - /* Determine if we shall change LED state again. */ - pLed->BlinkTimes--; - switch (pLed->CurrLedState) { - case LED_BLINK_NORMAL: - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - break; - case LED_BLINK_StartToBlink: - if (check_fwstate(pmlmepriv, _FW_LINKED) && - (pmlmepriv->fw_state & WIFI_STATION_STATE)) - bStopBlinking = true; - if (check_fwstate(pmlmepriv, _FW_LINKED) && - ((pmlmepriv->fw_state & WIFI_ADHOC_STATE) || - (pmlmepriv->fw_state & WIFI_ADHOC_MASTER_STATE))) - bStopBlinking = true; - else if (pLed->BlinkTimes == 0) - bStopBlinking = true; - break; - case LED_BLINK_WPS: - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - break; - default: - bStopBlinking = true; - break; - } - if (bStopBlinking) { - if (check_fwstate(pmlmepriv, _FW_LINKED) && - !pLed->bLedOn) - SwLedOn(padapter, pLed); - else if (check_fwstate(pmlmepriv, _FW_LINKED) && pLed->bLedOn) - SwLedOff(padapter, pLed); - pLed->BlinkTimes = 0; - pLed->bLedBlinkInProgress = false; - } else { - /* Assign LED state to toggle. */ - if (pLed->BlinkingLedState == LED_STATE_ON) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - - /* Schedule a timer to toggle LED state. */ - switch (pLed->CurrLedState) { - case LED_BLINK_NORMAL: - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - break; - case LED_BLINK_SLOWLY: - case LED_BLINK_StartToBlink: - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); - break; - case LED_BLINK_WPS: - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_LONG_INTERVAL)); - break; - default: - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); - break; - } - } -} - -static void SwLedBlink1(struct LED_871x *pLed) -{ - struct _adapter *padapter = pLed->padapter; - struct led_priv *ledpriv = &padapter->ledpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct eeprom_priv *peeprompriv = &padapter->eeprompriv; - struct LED_871x *pLed1 = &ledpriv->SwLed1; - u8 bStopBlinking = false; - - if (peeprompriv->CustomerID == RT_CID_819x_CAMEO) - pLed = &ledpriv->SwLed1; - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == LED_STATE_ON) - SwLedOn(padapter, pLed); - else - SwLedOff(padapter, pLed); - if (peeprompriv->CustomerID == RT_CID_DEFAULT) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - if (!pLed1->bSWLedCtrl) { - SwLedOn(padapter, pLed1); - pLed1->bSWLedCtrl = true; - } else if (!pLed1->bLedOn) { - SwLedOn(padapter, pLed1); - } - } else { - if (!pLed1->bSWLedCtrl) { - SwLedOff(padapter, pLed1); - pLed1->bSWLedCtrl = true; - } else if (pLed1->bLedOn) { - SwLedOff(padapter, pLed1); - } - } - } - switch (pLed->CurrLedState) { - case LED_BLINK_SLOWLY: - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - break; - case LED_BLINK_NORMAL: - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); - break; - case LED_SCAN_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->bLedLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_NORMAL; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - } - pLed->bLedScanBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_TXRX_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->bLedLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_NORMAL; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - } - pLed->BlinkTimes = 0; - pLed->bLedBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - case LED_BLINK_WPS: - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - break; - case LED_BLINK_WPS_STOP: /* WPS success */ - if (pLed->BlinkingLedState == LED_STATE_ON) { - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA)); - bStopBlinking = false; - } else { - bStopBlinking = true; - } - if (bStopBlinking) { - pLed->bLedLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_NORMAL; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); - } - pLed->bLedWPSBlinkInProgress = false; - break; - default: - break; - } -} - -static void SwLedBlink2(struct LED_871x *pLed) -{ - struct _adapter *padapter = pLed->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == LED_STATE_ON) - SwLedOn(padapter, pLed); - else - SwLedOff(padapter, pLed); - switch (pLed->CurrLedState) { - case LED_SCAN_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - SwLedOn(padapter, pLed); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - SwLedOff(padapter, pLed); - } - pLed->bLedScanBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_TXRX_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - SwLedOn(padapter, pLed); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - SwLedOff(padapter, pLed); - } - pLed->bLedBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - default: - break; - } -} - -static void SwLedBlink3(struct LED_871x *pLed) -{ - struct _adapter *padapter = pLed->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == LED_STATE_ON) - SwLedOn(padapter, pLed); - else - if (pLed->CurrLedState != LED_BLINK_WPS_STOP) - SwLedOff(padapter, pLed); - switch (pLed->CurrLedState) { - case LED_SCAN_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - if (!pLed->bLedOn) - SwLedOn(padapter, pLed); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - if (pLed->bLedOn) - SwLedOff(padapter, pLed); - } - pLed->bLedScanBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_TXRX_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - if (!pLed->bLedOn) - SwLedOn(padapter, pLed); - } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - if (pLed->bLedOn) - SwLedOff(padapter, pLed); - } - pLed->bLedBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - case LED_BLINK_WPS: - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - break; - case LED_BLINK_WPS_STOP: /*WPS success*/ - if (pLed->BlinkingLedState == LED_STATE_ON) { - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA)); - bStopBlinking = false; - } else { - bStopBlinking = true; - } - if (bStopBlinking) { - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - SwLedOn(padapter, pLed); - pLed->bLedWPSBlinkInProgress = false; - } - break; - default: - break; - } -} - -static void SwLedBlink4(struct LED_871x *pLed) -{ - struct _adapter *padapter = pLed->padapter; - struct led_priv *ledpriv = &padapter->ledpriv; - struct LED_871x *pLed1 = &ledpriv->SwLed1; - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == LED_STATE_ON) - SwLedOn(padapter, pLed); - else - SwLedOff(padapter, pLed); - if (!pLed1->bLedWPSBlinkInProgress && - pLed1->BlinkingLedState == LED_UNKNOWN) { - pLed1->BlinkingLedState = LED_STATE_OFF; - pLed1->CurrLedState = LED_STATE_OFF; - SwLedOff(padapter, pLed1); - } - switch (pLed->CurrLedState) { - case LED_BLINK_SLOWLY: - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - break; - case LED_BLINK_StartToBlink: - if (pLed->bLedOn) { - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); - } else { - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - } - break; - case LED_SCAN_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - pLed->bLedScanBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_TXRX_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - pLed->bLedBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - case LED_BLINK_WPS: - if (pLed->bLedOn) { - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); - } else { - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - } - break; - case LED_BLINK_WPS_STOP: /*WPS authentication fail*/ - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - break; - case LED_BLINK_WPS_STOP_OVERLAP: /*WPS session overlap */ - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) { - if (pLed->bLedOn) - pLed->BlinkTimes = 1; - else - bStopBlinking = true; - } - if (bStopBlinking) { - pLed->BlinkTimes = 10; - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - } - break; - default: - break; - } -} - -static void SwLedBlink5(struct LED_871x *pLed) -{ - struct _adapter *padapter = pLed->padapter; - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == LED_STATE_ON) - SwLedOn(padapter, pLed); - else - SwLedOff(padapter, pLed); - switch (pLed->CurrLedState) { - case LED_SCAN_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - if (!pLed->bLedOn) - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - pLed->bLedScanBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_TXRX_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - if (!pLed->bLedOn) - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - pLed->bLedBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - default: - break; - } -} - -static void SwLedBlink6(struct LED_871x *pLed) -{ - struct _adapter *padapter = pLed->padapter; - u8 bStopBlinking = false; - - /* Change LED according to BlinkingLedState specified. */ - if (pLed->BlinkingLedState == LED_STATE_ON) - SwLedOn(padapter, pLed); - else - SwLedOff(padapter, pLed); - switch (pLed->CurrLedState) { - case LED_TXRX_BLINK: - pLed->BlinkTimes--; - if (pLed->BlinkTimes == 0) - bStopBlinking = true; - if (bStopBlinking) { - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - if (!pLed->bLedOn) - SwLedOn(padapter, pLed); - pLed->bLedBlinkInProgress = false; - } else { - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - case LED_BLINK_WPS: - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - break; - - default: - break; - } -} - -/* Description: - * Callback function of LED BlinkTimer, - * it just schedules to corresponding BlinkWorkItem. - */ -static void BlinkTimerCallback(struct timer_list *t) -{ - struct LED_871x *pLed = from_timer(pLed, t, BlinkTimer); - - /* This fixed the crash problem on Fedora 12 when trying to do the - * insmod;ifconfig up;rmmod commands. - */ - if (pLed->padapter->surprise_removed || pLed->padapter->driver_stopped) - return; - schedule_work(&pLed->BlinkWorkItem); -} - -/* Description: - * Callback function of LED BlinkWorkItem. - * We dispatch actual LED blink action according to LedStrategy. - */ -static void BlinkWorkItemCallback(struct work_struct *work) -{ - struct LED_871x *pLed = container_of(work, struct LED_871x, - BlinkWorkItem); - struct led_priv *ledpriv = &pLed->padapter->ledpriv; - - switch (ledpriv->LedStrategy) { - case SW_LED_MODE0: - SwLedBlink(pLed); - break; - case SW_LED_MODE1: - SwLedBlink1(pLed); - break; - case SW_LED_MODE2: - SwLedBlink2(pLed); - break; - case SW_LED_MODE3: - SwLedBlink3(pLed); - break; - case SW_LED_MODE4: - SwLedBlink4(pLed); - break; - case SW_LED_MODE5: - SwLedBlink5(pLed); - break; - case SW_LED_MODE6: - SwLedBlink6(pLed); - break; - default: - SwLedBlink(pLed); - break; - } -} - -/*============================================================================ - * Default LED behavior. - *============================================================================ - * - * Description: - * Implement each led action for SW_LED_MODE0. - * This is default strategy. - */ - -static void SwLedControlMode1(struct _adapter *padapter, - enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &padapter->ledpriv; - struct LED_871x *pLed = &ledpriv->SwLed0; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct sitesurvey_ctrl *psitesurveyctrl = &pmlmepriv->sitesurveyctrl; - - if (padapter->eeprompriv.CustomerID == RT_CID_819x_CAMEO) - pLed = &ledpriv->SwLed1; - switch (LedAction) { - case LED_CTL_START_TO_LINK: - case LED_CTL_NO_LINK: - if (!pLed->bLedNoLinkBlinkInProgress) { - if (pLed->CurrLedState == LED_SCAN_BLINK || - IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - } - break; - case LED_CTL_LINK: - if (!pLed->bLedLinkBlinkInProgress) { - if (pLed->CurrLedState == LED_SCAN_BLINK || - IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_NORMAL; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_LINK_INTERVAL_ALPHA)); - } - break; - case LED_CTL_SITE_SURVEY: - if (psitesurveyctrl->traffic_busy && - check_fwstate(pmlmepriv, _FW_LINKED)) - ; /* dummy branch */ - else if (!pLed->bLedScanBlinkInProgress) { - if (IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_SCAN_BLINK; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_CTL_TX: - case LED_CTL_RX: - if (!pLed->bLedBlinkInProgress) { - if (pLed->CurrLedState == LED_SCAN_BLINK || - IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; - } - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_TXRX_BLINK; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - - case LED_CTL_START_WPS: /*wait until xinpin finish */ - case LED_CTL_START_WPS_BOTTON: - if (!pLed->bLedWPSBlinkInProgress) { - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_WPS; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_CTL_STOP_WPS: - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) - del_timer(&pLed->BlinkTimer); - else - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_WPS_STOP; - if (pLed->bLedOn) { - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA)); - } else { - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - } - break; - case LED_CTL_STOP_WPS_FAIL: - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - default: - break; - } -} - -static void SwLedControlMode2(struct _adapter *padapter, - enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &padapter->ledpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &ledpriv->SwLed0; - - switch (LedAction) { - case LED_CTL_SITE_SURVEY: - if (pmlmepriv->sitesurveyctrl.traffic_busy) - ; /* dummy branch */ - else if (!pLed->bLedScanBlinkInProgress) { - if (IS_LED_WPS_BLINKING(pLed)) - return; - - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_SCAN_BLINK; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - - case LED_CTL_TX: - case LED_CTL_RX: - if (!pLed->bLedBlinkInProgress && - check_fwstate(pmlmepriv, _FW_LINKED)) { - if (pLed->CurrLedState == LED_SCAN_BLINK || - IS_LED_WPS_BLINKING(pLed)) - return; - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_TXRX_BLINK; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - - case LED_CTL_LINK: - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - - case LED_CTL_START_WPS: /*wait until xinpin finish*/ - case LED_CTL_START_WPS_BOTTON: - if (!pLed->bLedWPSBlinkInProgress) { - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - } - break; - - case LED_CTL_STOP_WPS: - pLed->bLedWPSBlinkInProgress = false; - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - - case LED_CTL_STOP_WPS_FAIL: - pLed->bLedWPSBlinkInProgress = false; - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - - case LED_CTL_START_TO_LINK: - case LED_CTL_NO_LINK: - if (!IS_LED_BLINKING(pLed)) { - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - } - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - default: - break; - } -} - -static void SwLedControlMode3(struct _adapter *padapter, - enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &padapter->ledpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &ledpriv->SwLed0; - - switch (LedAction) { - case LED_CTL_SITE_SURVEY: - if (pmlmepriv->sitesurveyctrl.traffic_busy) - ; /* dummy branch */ - else if (!pLed->bLedScanBlinkInProgress) { - if (IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_SCAN_BLINK; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_CTL_TX: - case LED_CTL_RX: - if (!pLed->bLedBlinkInProgress && - check_fwstate(pmlmepriv, _FW_LINKED)) { - if (pLed->CurrLedState == LED_SCAN_BLINK || - IS_LED_WPS_BLINKING(pLed)) - return; - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_TXRX_BLINK; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - case LED_CTL_LINK: - if (IS_LED_WPS_BLINKING(pLed)) - return; - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - case LED_CTL_START_WPS: /* wait until xinpin finish */ - case LED_CTL_START_WPS_BOTTON: - if (!pLed->bLedWPSBlinkInProgress) { - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_WPS; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_CTL_STOP_WPS: - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } else { - pLed->bLedWPSBlinkInProgress = true; - } - pLed->CurrLedState = LED_BLINK_WPS_STOP; - if (pLed->bLedOn) { - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_WPS_SUCCESS_INTERVAL_ALPHA)); - } else { - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - } - break; - case LED_CTL_STOP_WPS_FAIL: - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - case LED_CTL_START_TO_LINK: - case LED_CTL_NO_LINK: - if (!IS_LED_BLINKING(pLed)) { - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - } - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - default: - break; - } -} - -static void SwLedControlMode4(struct _adapter *padapter, - enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &padapter->ledpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &ledpriv->SwLed0; - struct LED_871x *pLed1 = &ledpriv->SwLed1; - - switch (LedAction) { - case LED_CTL_START_TO_LINK: - if (pLed1->bLedWPSBlinkInProgress) { - pLed1->bLedWPSBlinkInProgress = false; - del_timer(&pLed1->BlinkTimer); - pLed1->BlinkingLedState = LED_STATE_OFF; - pLed1->CurrLedState = LED_STATE_OFF; - if (pLed1->bLedOn) - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - } - if (!pLed->bLedStartToLinkBlinkInProgress) { - if (pLed->CurrLedState == LED_SCAN_BLINK || - IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - pLed->bLedStartToLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_StartToBlink; - if (pLed->bLedOn) { - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); - } else { - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - } - } - break; - case LED_CTL_LINK: - case LED_CTL_NO_LINK: - /*LED1 settings*/ - if (LedAction == LED_CTL_LINK) { - if (pLed1->bLedWPSBlinkInProgress) { - pLed1->bLedWPSBlinkInProgress = false; - del_timer(&pLed1->BlinkTimer); - pLed1->BlinkingLedState = LED_STATE_OFF; - pLed1->CurrLedState = LED_STATE_OFF; - if (pLed1->bLedOn) - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - } - } - if (!pLed->bLedNoLinkBlinkInProgress) { - if (pLed->CurrLedState == LED_SCAN_BLINK || - IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - } - break; - case LED_CTL_SITE_SURVEY: - if (pmlmepriv->sitesurveyctrl.traffic_busy && - check_fwstate(pmlmepriv, _FW_LINKED)) - ; - else if (!pLed->bLedScanBlinkInProgress) { - if (IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_SCAN_BLINK; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_CTL_TX: - case LED_CTL_RX: - if (!pLed->bLedBlinkInProgress) { - if (pLed->CurrLedState == LED_SCAN_BLINK || - IS_LED_WPS_BLINKING(pLed)) - return; - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_TXRX_BLINK; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - case LED_CTL_START_WPS: /*wait until xinpin finish*/ - case LED_CTL_START_WPS_BOTTON: - if (pLed1->bLedWPSBlinkInProgress) { - pLed1->bLedWPSBlinkInProgress = false; - del_timer(&pLed1->BlinkTimer); - pLed1->BlinkingLedState = LED_STATE_OFF; - pLed1->CurrLedState = LED_STATE_OFF; - if (pLed1->bLedOn) - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - } - if (!pLed->bLedWPSBlinkInProgress) { - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_WPS; - if (pLed->bLedOn) { - pLed->BlinkingLedState = LED_STATE_OFF; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL)); - } else { - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - } - } - break; - case LED_CTL_STOP_WPS: /*WPS connect success*/ - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - break; - case LED_CTL_STOP_WPS_FAIL: /*WPS authentication fail*/ - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - /*LED1 settings*/ - if (pLed1->bLedWPSBlinkInProgress) - del_timer(&pLed1->BlinkTimer); - else - pLed1->bLedWPSBlinkInProgress = true; - pLed1->CurrLedState = LED_BLINK_WPS_STOP; - if (pLed1->bLedOn) - pLed1->BlinkingLedState = LED_STATE_OFF; - else - pLed1->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - break; - case LED_CTL_STOP_WPS_FAIL_OVERLAP: /*WPS session overlap*/ - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - pLed->bLedNoLinkBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_SLOWLY; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA)); - /*LED1 settings*/ - if (pLed1->bLedWPSBlinkInProgress) - del_timer(&pLed1->BlinkTimer); - else - pLed1->bLedWPSBlinkInProgress = true; - pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; - pLed1->BlinkTimes = 10; - if (pLed1->bLedOn) - pLed1->BlinkingLedState = LED_STATE_OFF; - else - pLed1->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL)); - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - if (pLed->bLedNoLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedNoLinkBlinkInProgress = false; - } - if (pLed->bLedLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedLinkBlinkInProgress = false; - } - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - if (pLed->bLedScanBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedScanBlinkInProgress = false; - } - if (pLed->bLedStartToLinkBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedStartToLinkBlinkInProgress = false; - } - if (pLed1->bLedWPSBlinkInProgress) { - del_timer(&pLed1->BlinkTimer); - pLed1->bLedWPSBlinkInProgress = false; - } - pLed1->BlinkingLedState = LED_UNKNOWN; - SwLedOff(padapter, pLed); - SwLedOff(padapter, pLed1); - break; - default: - break; - } -} - -static void SwLedControlMode5(struct _adapter *padapter, - enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &padapter->ledpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &ledpriv->SwLed0; - - if (padapter->eeprompriv.CustomerID == RT_CID_819x_CAMEO) - pLed = &ledpriv->SwLed1; - - switch (LedAction) { - case LED_CTL_POWER_ON: - case LED_CTL_NO_LINK: - case LED_CTL_LINK: /* solid blue */ - if (pLed->CurrLedState == LED_SCAN_BLINK) - return; - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - pLed->bLedBlinkInProgress = false; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - case LED_CTL_SITE_SURVEY: - if (pmlmepriv->sitesurveyctrl.traffic_busy && - check_fwstate(pmlmepriv, _FW_LINKED)) - ; /* dummy branch */ - else if (!pLed->bLedScanBlinkInProgress) { - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedScanBlinkInProgress = true; - pLed->CurrLedState = LED_SCAN_BLINK; - pLed->BlinkTimes = 24; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_CTL_TX: - case LED_CTL_RX: - if (!pLed->bLedBlinkInProgress) { - if (pLed->CurrLedState == LED_SCAN_BLINK) - return; - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_TXRX_BLINK; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - SwLedOff(padapter, pLed); - break; - default: - break; - } -} - -static void SwLedControlMode6(struct _adapter *padapter, - enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &padapter->ledpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &ledpriv->SwLed0; - - switch (LedAction) { - case LED_CTL_POWER_ON: - case LED_CTL_NO_LINK: - case LED_CTL_LINK: /*solid blue*/ - case LED_CTL_SITE_SURVEY: - if (IS_LED_WPS_BLINKING(pLed)) - return; - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - pLed->bLedBlinkInProgress = false; - mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(0)); - break; - case LED_CTL_TX: - case LED_CTL_RX: - if (!pLed->bLedBlinkInProgress && - check_fwstate(pmlmepriv, _FW_LINKED)) { - if (IS_LED_WPS_BLINKING(pLed)) - return; - pLed->bLedBlinkInProgress = true; - pLed->CurrLedState = LED_TXRX_BLINK; - pLed->BlinkTimes = 2; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA)); - } - break; - case LED_CTL_START_WPS: /*wait until xinpin finish*/ - case LED_CTL_START_WPS_BOTTON: - if (!pLed->bLedWPSBlinkInProgress) { - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - pLed->bLedWPSBlinkInProgress = true; - pLed->CurrLedState = LED_BLINK_WPS; - if (pLed->bLedOn) - pLed->BlinkingLedState = LED_STATE_OFF; - else - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, jiffies + - msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA)); - } - break; - case LED_CTL_STOP_WPS_FAIL: - case LED_CTL_STOP_WPS: - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - pLed->CurrLedState = LED_STATE_ON; - pLed->BlinkingLedState = LED_STATE_ON; - mod_timer(&pLed->BlinkTimer, - jiffies + msecs_to_jiffies(0)); - break; - case LED_CTL_POWER_OFF: - pLed->CurrLedState = LED_STATE_OFF; - pLed->BlinkingLedState = LED_STATE_OFF; - if (pLed->bLedBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedBlinkInProgress = false; - } - if (pLed->bLedWPSBlinkInProgress) { - del_timer(&pLed->BlinkTimer); - pLed->bLedWPSBlinkInProgress = false; - } - SwLedOff(padapter, pLed); - break; - default: - break; - } -} - -/* Description: - * Dispatch LED action according to pHalData->LedStrategy. - */ -void LedControl871x(struct _adapter *padapter, enum LED_CTL_MODE LedAction) -{ - struct led_priv *ledpriv = &padapter->ledpriv; - - if (!ledpriv->bRegUseLed) - return; - switch (ledpriv->LedStrategy) { - case SW_LED_MODE0: - break; - case SW_LED_MODE1: - SwLedControlMode1(padapter, LedAction); - break; - case SW_LED_MODE2: - SwLedControlMode2(padapter, LedAction); - break; - case SW_LED_MODE3: - SwLedControlMode3(padapter, LedAction); - break; - case SW_LED_MODE4: - SwLedControlMode4(padapter, LedAction); - break; - case SW_LED_MODE5: - SwLedControlMode5(padapter, LedAction); - break; - case SW_LED_MODE6: - SwLedControlMode6(padapter, LedAction); - break; - default: - break; - } -} - -void r8712_flush_led_works(struct _adapter *padapter) -{ - struct led_priv *pledpriv = &padapter->ledpriv; - - flush_work(&pledpriv->SwLed0.BlinkWorkItem); - flush_work(&pledpriv->SwLed1.BlinkWorkItem); -} diff --git a/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h b/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h deleted file mode 100644 index 46d758d3f3a4dd..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_macsetting_bitdef.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_MACSETTING_BITDEF_H__ -#define __RTL8712_MACSETTING_BITDEF_H__ - -/*MACID*/ -/*BSSID*/ - -/*HWVID*/ -#define _HWVID_MSK 0x0F - -/*MAR*/ -/*MBIDCANCONTENT*/ - -/*MBIDCANCFG*/ -#define _POOLING BIT(31) -#define _WRITE_EN BIT(16) -#define _CAM_ADDR_MSK 0x001F -#define _CAM_ADDR_SHT 0 - -/*BUILDTIME*/ -#define _BUILDTIME_MSK 0x3FFFFFFF - -/*BUILDUSER*/ - -#endif /* __RTL8712_MACSETTING_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h b/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h deleted file mode 100644 index 64740d99c25233..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_macsetting_regdef.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_MACSETTING_REGDEF_H__ -#define __RTL8712_MACSETTING_REGDEF_H__ - -#define MACID (RTL8712_MACIDSETTING_ + 0x0000) -#define BSSIDR (RTL8712_MACIDSETTING_ + 0x0008) -#define HWVID (RTL8712_MACIDSETTING_ + 0x000E) -#define MAR (RTL8712_MACIDSETTING_ + 0x0010) -#define MBIDCANCONTENT (RTL8712_MACIDSETTING_ + 0x0018) -#define MBIDCANCFG (RTL8712_MACIDSETTING_ + 0x0020) -#define BUILDTIME (RTL8712_MACIDSETTING_ + 0x0024) -#define BUILDUSER (RTL8712_MACIDSETTING_ + 0x0028) - -#endif /*__RTL8712_MACSETTING_REGDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h b/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h deleted file mode 100644 index 53e0d6b440f34e..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_powersave_bitdef.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_POWERSAVE_BITDEF_H__ -#define __RTL8712_POWERSAVE_BITDEF_H__ - -/*WOWCTRL*/ -#define _UWF BIT(3) -#define _MAGIC BIT(2) -#define _WOW_EN BIT(1) -#define _PMEN BIT(0) - -/*PSSTATUS*/ -#define _PSSTATUS_SEL_MSK 0x0F - -/*PSSWITCH*/ -#define _PSSWITCH_ACT BIT(7) -#define _PSSWITCH_SEL_MSK 0x0F -#define _PSSWITCH_SEL_SHT 0 - -/*LPNAV_CTRL*/ -#define _LPNAV_EN BIT(31) -#define _LPNAV_EARLY_MSK 0x7FFF0000 -#define _LPNAV_EARLY_SHT 16 -#define _LPNAV_TH_MSK 0x0000FFFF -#define _LPNAV_TH_SHT 0 - -/*RPWM*/ -/*CPWM*/ -#define _TOGGLING BIT(7) -#define _WWLAN BIT(3) -#define _RPS_ST BIT(2) -#define _WLAN_TRX BIT(1) -#define _SYS_CLK BIT(0) - -#endif /* __RTL8712_POWERSAVE_BITDEF_H__*/ diff --git a/drivers/staging/rtl8712/rtl8712_powersave_regdef.h b/drivers/staging/rtl8712/rtl8712_powersave_regdef.h deleted file mode 100644 index 1bcfde4b1c11f1..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_powersave_regdef.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_POWERSAVE_REGDEF_H__ -#define __RTL8712_POWERSAVE_REGDEF_H__ - -#define WOWCTRL (RTL8712_POWERSAVE_ + 0x00) -#define PSSTATUS (RTL8712_POWERSAVE_ + 0x01) -#define PSSWITCH (RTL8712_POWERSAVE_ + 0x02) -#define MIMOPS_WAITPERIOD (RTL8712_POWERSAVE_ + 0x03) -#define LPNAV_CTRL (RTL8712_POWERSAVE_ + 0x04) -#define WFM0 (RTL8712_POWERSAVE_ + 0x10) -#define WFM1 (RTL8712_POWERSAVE_ + 0x20) -#define WFM2 (RTL8712_POWERSAVE_ + 0x30) -#define WFM3 (RTL8712_POWERSAVE_ + 0x40) -#define WFM4 (RTL8712_POWERSAVE_ + 0x50) -#define WFM5 (RTL8712_POWERSAVE_ + 0x60) -#define WFCRC (RTL8712_POWERSAVE_ + 0x70) -#define RPWM (RTL8712_POWERSAVE_ + 0x7C) -#define CPWM (RTL8712_POWERSAVE_ + 0x7D) - -#endif /* __RTL8712_POWERSAVE_REGDEF_H__ */ - diff --git a/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h deleted file mode 100644 index 1de51c48f9c1b2..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_ratectrl_bitdef.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_RATECTRL_BITDEF_H__ -#define __RTL8712_RATECTRL_BITDEF_H__ - -/*INIRTSMCS_SEL*/ -#define _INIRTSMCS_SEL_MSK 0x3F - -/* RRSR*/ -#define _RRSR_SHORT BIT(23) -#define _RRSR_RSC_MSK 0x600000 -#define _RRSR_RSC_SHT 21 -#define _RRSR_BITMAP_MSK 0x0FFFFF -#define _RRSR_BITMAP_SHT 0 - -/* AGGLEN_LMT_H*/ -#define _AGGLMT_MCS32_MSK 0xF0 -#define _AGGLMT_MCS32_SHT 4 -#define _AGGLMT_MCS15_SGI_MSK 0x0F -#define _AGGLMT_MCS15_SGI_SHT 0 - -/* DARFRC*/ -/* RARFRC*/ -/* MCS_TXAGC*/ -/* CCK_TXAGC*/ -#define _CCK_MSK 0xFF00 -#define _CCK_SHT 8 -#define _BARKER_MSK 0x00FF -#define _BARKER_SHT 0 - -#endif /* __RTL8712_RATECTRL_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h b/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h deleted file mode 100644 index 9ed5653f3f7f11..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_ratectrl_regdef.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_RATECTRL_REGDEF_H__ -#define __RTL8712_RATECTRL_REGDEF_H__ - -#define INIMCS_SEL (RTL8712_RATECTRL_ + 0x00) -#define INIRTSMCS_SEL (RTL8712_RATECTRL_ + 0x20) -#define RRSR (RTL8712_RATECTRL_ + 0x21) -#define ARFR0 (RTL8712_RATECTRL_ + 0x24) -#define ARFR1 (RTL8712_RATECTRL_ + 0x28) -#define ARFR2 (RTL8712_RATECTRL_ + 0x2C) -#define ARFR3 (RTL8712_RATECTRL_ + 0x30) -#define ARFR4 (RTL8712_RATECTRL_ + 0x34) -#define ARFR5 (RTL8712_RATECTRL_ + 0x38) -#define ARFR6 (RTL8712_RATECTRL_ + 0x3C) -#define ARFR7 (RTL8712_RATECTRL_ + 0x40) -#define AGGLEN_LMT_H (RTL8712_RATECTRL_ + 0x47) -#define AGGLEN_LMT_L (RTL8712_RATECTRL_ + 0x48) -#define DARFRC (RTL8712_RATECTRL_ + 0x50) -#define RARFRC (RTL8712_RATECTRL_ + 0x58) -#define MCS_TXAGC0 (RTL8712_RATECTRL_ + 0x60) -#define MCS_TXAGC1 (RTL8712_RATECTRL_ + 0x61) -#define MCS_TXAGC2 (RTL8712_RATECTRL_ + 0x62) -#define MCS_TXAGC3 (RTL8712_RATECTRL_ + 0x63) -#define MCS_TXAGC4 (RTL8712_RATECTRL_ + 0x64) -#define MCS_TXAGC5 (RTL8712_RATECTRL_ + 0x65) -#define MCS_TXAGC6 (RTL8712_RATECTRL_ + 0x66) -#define MCS_TXAGC7 (RTL8712_RATECTRL_ + 0x67) -#define CCK_TXAGC (RTL8712_RATECTRL_ + 0x68) - -#endif /*__RTL8712_RATECTRL_REGDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c deleted file mode 100644 index ab344d676bb946..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ /dev/null @@ -1,1075 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl8712_recv.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL8712_RECV_C_ - -#include -#include -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "recv_osdep.h" -#include "mlme_osdep.h" -#include "ethernet.h" -#include "usb_ops.h" -#include "wifi.h" - -static void recv_tasklet(struct tasklet_struct *t); - -int r8712_init_recv_priv(struct recv_priv *precvpriv, - struct _adapter *padapter) -{ - int i; - struct recv_buf *precvbuf; - addr_t tmpaddr = 0; - int alignment = 0; - struct sk_buff *pskb = NULL; - - /*init recv_buf*/ - _init_queue(&precvpriv->free_recv_buf_queue); - precvpriv->pallocated_recv_buf = - kzalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4, GFP_ATOMIC); - if (!precvpriv->pallocated_recv_buf) - return -ENOMEM; - precvpriv->precv_buf = precvpriv->pallocated_recv_buf + 4 - - ((addr_t)(precvpriv->pallocated_recv_buf) & 3); - precvbuf = (struct recv_buf *)precvpriv->precv_buf; - for (i = 0; i < NR_RECVBUFF; i++) { - INIT_LIST_HEAD(&precvbuf->list); - spin_lock_init(&precvbuf->recvbuf_lock); - if (r8712_os_recvbuf_resource_alloc(padapter, precvbuf)) - break; - precvbuf->ref_cnt = 0; - precvbuf->adapter = padapter; - list_add_tail(&precvbuf->list, - &precvpriv->free_recv_buf_queue.queue); - precvbuf++; - } - precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; - tasklet_setup(&precvpriv->recv_tasklet, recv_tasklet); - skb_queue_head_init(&precvpriv->rx_skb_queue); - - skb_queue_head_init(&precvpriv->free_recv_skb_queue); - for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) { - pskb = netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ + - RECVBUFF_ALIGN_SZ); - if (pskb) { - tmpaddr = (addr_t)pskb->data; - alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1); - skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); - skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); - } - pskb = NULL; - } - return 0; -} - -void r8712_free_recv_priv(struct recv_priv *precvpriv) -{ - int i; - struct recv_buf *precvbuf; - struct _adapter *padapter = precvpriv->adapter; - - precvbuf = (struct recv_buf *)precvpriv->precv_buf; - for (i = 0; i < NR_RECVBUFF; i++) { - r8712_os_recvbuf_resource_free(padapter, precvbuf); - precvbuf++; - } - kfree(precvpriv->pallocated_recv_buf); - skb_queue_purge(&precvpriv->rx_skb_queue); - if (skb_queue_len(&precvpriv->rx_skb_queue)) - netdev_warn(padapter->pnetdev, "r8712u: rx_skb_queue not empty\n"); - skb_queue_purge(&precvpriv->free_recv_skb_queue); - if (skb_queue_len(&precvpriv->free_recv_skb_queue)) - netdev_warn(padapter->pnetdev, "r8712u: free_recv_skb_queue not empty %d\n", - skb_queue_len(&precvpriv->free_recv_skb_queue)); -} - -void r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf) -{ - precvbuf->transfer_len = 0; - precvbuf->len = 0; - precvbuf->ref_cnt = 0; - if (precvbuf->pbuf) { - precvbuf->pdata = precvbuf->pbuf; - precvbuf->phead = precvbuf->pbuf; - precvbuf->ptail = precvbuf->pbuf; - precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ; - } -} - -void r8712_free_recvframe(union recv_frame *precvframe, - struct __queue *pfree_recv_queue) -{ - unsigned long irqL; - struct _adapter *padapter = precvframe->u.hdr.adapter; - struct recv_priv *precvpriv = &padapter->recvpriv; - - if (precvframe->u.hdr.pkt) { - dev_kfree_skb_any(precvframe->u.hdr.pkt);/*free skb by driver*/ - precvframe->u.hdr.pkt = NULL; - } - spin_lock_irqsave(&pfree_recv_queue->lock, irqL); - list_del_init(&precvframe->u.hdr.list); - list_add_tail(&precvframe->u.hdr.list, &pfree_recv_queue->queue); - if (padapter) { - if (pfree_recv_queue == &precvpriv->free_recv_queue) - precvpriv->free_recvframe_cnt++; - } - spin_unlock_irqrestore(&pfree_recv_queue->lock, irqL); -} - -static void update_recvframe_attrib_from_recvstat(struct rx_pkt_attrib *pattrib, - struct recv_stat *prxstat) -{ - /*TODO: - * Offset 0 - */ - pattrib->bdecrypted = (le32_to_cpu(prxstat->rxdw0) & BIT(27)) == 0; - pattrib->crc_err = (le32_to_cpu(prxstat->rxdw0) & BIT(14)) != 0; - /*Offset 4*/ - /*Offset 8*/ - /*Offset 12*/ - if (le32_to_cpu(prxstat->rxdw3) & BIT(13)) { - pattrib->tcpchk_valid = 1; /* valid */ - if (le32_to_cpu(prxstat->rxdw3) & BIT(11)) - pattrib->tcp_chkrpt = 1; /* correct */ - else - pattrib->tcp_chkrpt = 0; /* incorrect */ - if (le32_to_cpu(prxstat->rxdw3) & BIT(12)) - pattrib->ip_chkrpt = 1; /* correct */ - else - pattrib->ip_chkrpt = 0; /* incorrect */ - } else { - pattrib->tcpchk_valid = 0; /* invalid */ - } - pattrib->mcs_rate = (u8)((le32_to_cpu(prxstat->rxdw3)) & 0x3f); - pattrib->htc = (u8)((le32_to_cpu(prxstat->rxdw3) >> 14) & 0x1); - /*Offset 16*/ - /*Offset 20*/ - /*phy_info*/ -} - -/*perform defrag*/ -static union recv_frame *recvframe_defrag(struct _adapter *adapter, - struct __queue *defrag_q) -{ - struct list_head *plist, *phead; - u8 wlanhdr_offset; - u8 curfragnum; - struct recv_frame_hdr *pfhdr, *pnfhdr; - union recv_frame *prframe, *pnextrframe; - struct __queue *pfree_recv_queue; - - pfree_recv_queue = &adapter->recvpriv.free_recv_queue; - phead = &defrag_q->queue; - plist = phead->next; - prframe = container_of(plist, union recv_frame, u.list); - list_del_init(&prframe->u.list); - pfhdr = &prframe->u.hdr; - curfragnum = 0; - if (curfragnum != pfhdr->attrib.frag_num) { - /*the first fragment number must be 0 - *free the whole queue - */ - r8712_free_recvframe(prframe, pfree_recv_queue); - r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); - return NULL; - } - curfragnum++; - plist = &defrag_q->queue; - plist = plist->next; - while (!end_of_queue_search(phead, plist)) { - pnextrframe = container_of(plist, union recv_frame, u.list); - pnfhdr = &pnextrframe->u.hdr; - /*check the fragment sequence (2nd ~n fragment frame) */ - if (curfragnum != pnfhdr->attrib.frag_num) { - /* the fragment number must increase (after decache) - * release the defrag_q & prframe - */ - r8712_free_recvframe(prframe, pfree_recv_queue); - r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); - return NULL; - } - curfragnum++; - /* copy the 2nd~n fragment frame's payload to the first fragment - * get the 2nd~last fragment frame's payload - */ - wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; - recvframe_pull(pnextrframe, wlanhdr_offset); - /* append to first fragment frame's tail (if privacy frame, - * pull the ICV) - */ - recvframe_pull_tail(prframe, pfhdr->attrib.icv_len); - memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); - recvframe_put(prframe, pnfhdr->len); - pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; - plist = plist->next; - } - /* free the defrag_q queue and return the prframe */ - r8712_free_recvframe_queue(defrag_q, pfree_recv_queue); - return prframe; -} - -/* check if need to defrag, if needed queue the frame to defrag_q */ -union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *padapter, - union recv_frame *precv_frame) -{ - u8 ismfrag; - u8 fragnum; - u8 *psta_addr; - struct recv_frame_hdr *pfhdr; - struct sta_info *psta; - struct sta_priv *pstapriv; - struct list_head *phead; - union recv_frame *prtnframe = NULL; - struct __queue *pfree_recv_queue, *pdefrag_q; - - pstapriv = &padapter->stapriv; - pfhdr = &precv_frame->u.hdr; - pfree_recv_queue = &padapter->recvpriv.free_recv_queue; - /* need to define struct of wlan header frame ctrl */ - ismfrag = pfhdr->attrib.mfrag; - fragnum = pfhdr->attrib.frag_num; - psta_addr = pfhdr->attrib.ta; - psta = r8712_get_stainfo(pstapriv, psta_addr); - if (!psta) - pdefrag_q = NULL; - else - pdefrag_q = &psta->sta_recvpriv.defrag_q; - - if ((ismfrag == 0) && (fragnum == 0)) - prtnframe = precv_frame;/*isn't a fragment frame*/ - if (ismfrag == 1) { - /* 0~(n-1) fragment frame - * enqueue to defraf_g - */ - if (pdefrag_q) { - if (fragnum == 0) { - /*the first fragment*/ - if (!list_empty(&pdefrag_q->queue)) { - /*free current defrag_q */ - r8712_free_recvframe_queue(pdefrag_q, pfree_recv_queue); - } - } - /* Then enqueue the 0~(n-1) fragment to the defrag_q */ - phead = &pdefrag_q->queue; - list_add_tail(&pfhdr->list, phead); - prtnframe = NULL; - } else { - /* can't find this ta's defrag_queue, so free this - * recv_frame - */ - r8712_free_recvframe(precv_frame, pfree_recv_queue); - prtnframe = NULL; - } - } - if ((ismfrag == 0) && (fragnum != 0)) { - /* the last fragment frame - * enqueue the last fragment - */ - if (pdefrag_q) { - phead = &pdefrag_q->queue; - list_add_tail(&pfhdr->list, phead); - /*call recvframe_defrag to defrag*/ - precv_frame = recvframe_defrag(padapter, pdefrag_q); - prtnframe = precv_frame; - } else { - /* can't find this ta's defrag_queue, so free this - * recv_frame - */ - r8712_free_recvframe(precv_frame, pfree_recv_queue); - prtnframe = NULL; - } - } - if (prtnframe && (prtnframe->u.hdr.attrib.privacy)) { - /* after defrag we must check tkip mic code */ - if (r8712_recvframe_chkmic(padapter, prtnframe) == _FAIL) { - r8712_free_recvframe(prtnframe, pfree_recv_queue); - prtnframe = NULL; - } - } - return prtnframe; -} - -static void amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe) -{ - int a_len, padding_len; - u16 eth_type, nSubframe_Length; - u8 nr_subframes, i; - unsigned char *pdata; - struct rx_pkt_attrib *pattrib; - _pkt *sub_skb, *subframes[MAX_SUBFRAME_COUNT]; - struct recv_priv *precvpriv = &padapter->recvpriv; - struct __queue *pfree_recv_queue = &precvpriv->free_recv_queue; - - nr_subframes = 0; - pattrib = &prframe->u.hdr.attrib; - recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen); - if (prframe->u.hdr.attrib.iv_len > 0) - recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len); - a_len = prframe->u.hdr.len; - pdata = prframe->u.hdr.rx_data; - while (a_len > ETH_HLEN) { - /* Offset 12 denote 2 mac address */ - nSubframe_Length = *((u16 *)(pdata + 12)); - /*==m==>change the length order*/ - nSubframe_Length = (nSubframe_Length >> 8) + - (nSubframe_Length << 8); - if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) { - netdev_warn(padapter->pnetdev, "r8712u: nRemain_Length is %d and nSubframe_Length is: %d\n", - a_len, nSubframe_Length); - goto exit; - } - /* move the data point to data content */ - pdata += ETH_HLEN; - a_len -= ETH_HLEN; - /* Allocate new skb for releasing to upper layer */ - sub_skb = dev_alloc_skb(nSubframe_Length + 12); - if (!sub_skb) - break; - skb_reserve(sub_skb, 12); - skb_put_data(sub_skb, pdata, nSubframe_Length); - subframes[nr_subframes++] = sub_skb; - if (nr_subframes >= MAX_SUBFRAME_COUNT) { - netdev_warn(padapter->pnetdev, "r8712u: ParseSubframe(): Too many Subframes! Packets dropped!\n"); - break; - } - pdata += nSubframe_Length; - a_len -= nSubframe_Length; - if (a_len != 0) { - padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & 3); - if (padding_len == 4) - padding_len = 0; - if (a_len < padding_len) - goto exit; - pdata += padding_len; - a_len -= padding_len; - } - } - for (i = 0; i < nr_subframes; i++) { - sub_skb = subframes[i]; - /* convert hdr + possible LLC headers into Ethernet header */ - eth_type = (sub_skb->data[6] << 8) | sub_skb->data[7]; - if (sub_skb->len >= 8 && - ((!memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) && - eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || - !memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE))) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType - */ - skb_pull(sub_skb, SNAP_SIZE); - memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, - ETH_ALEN); - memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, - ETH_ALEN); - } else { - __be16 len; - /* Leave Ethernet header part of hdr and full payload */ - len = htons(sub_skb->len); - memcpy(skb_push(sub_skb, 2), &len, 2); - memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, - ETH_ALEN); - memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, - ETH_ALEN); - } - /* Indicate the packets to upper layer */ - if (sub_skb) { - sub_skb->protocol = - eth_type_trans(sub_skb, padapter->pnetdev); - sub_skb->dev = padapter->pnetdev; - if ((pattrib->tcpchk_valid == 1) && - (pattrib->tcp_chkrpt == 1)) { - sub_skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { - sub_skb->ip_summed = CHECKSUM_NONE; - } - netif_rx(sub_skb); - } - } -exit: - prframe->u.hdr.len = 0; - r8712_free_recvframe(prframe, pfree_recv_queue); -} - -void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf) -{ - __le32 voffset; - u8 *poffset; - u16 cmd_len, drvinfo_sz; - struct recv_stat *prxstat; - - poffset = prxcmdbuf; - voffset = *(__le32 *)poffset; - prxstat = prxcmdbuf; - drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16; - drvinfo_sz <<= 3; - poffset += RXDESC_SIZE + drvinfo_sz; - do { - voffset = *(__le32 *)poffset; - cmd_len = (u16)(le32_to_cpu(voffset) & 0xffff); - r8712_event_handle(padapter, (__le32 *)poffset); - poffset += (cmd_len + 8);/*8 bytes alignment*/ - } while (le32_to_cpu(voffset) & BIT(31)); -} - -static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, - u16 seq_num) -{ - u8 wsize = preorder_ctrl->wsize_b; - u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) % 4096; - - /* Rx Reorder initialize condition.*/ - if (preorder_ctrl->indicate_seq == 0xffff) - preorder_ctrl->indicate_seq = seq_num; - /* Drop out the packet which SeqNum is smaller than WinStart */ - if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) - return false; - /* - * Sliding window manipulation. Conditions includes: - * 1. Incoming SeqNum is equal to WinStart =>Window shift 1 - * 2. Incoming SeqNum is larger than the WinEnd => Window shift N - */ - if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) - preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + - 1) % 4096; - else if (SN_LESS(wend, seq_num)) { - if (seq_num >= (wsize - 1)) - preorder_ctrl->indicate_seq = seq_num + 1 - wsize; - else - preorder_ctrl->indicate_seq = 4095 - (wsize - - (seq_num + 1)) + 1; - } - return true; -} - -static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, - union recv_frame *prframe) -{ - struct list_head *phead, *plist; - union recv_frame *pnextrframe; - struct rx_pkt_attrib *pnextattrib; - struct __queue *ppending_recvframe_queue = - &preorder_ctrl->pending_recvframe_queue; - struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; - - phead = &ppending_recvframe_queue->queue; - plist = phead->next; - while (!end_of_queue_search(phead, plist)) { - pnextrframe = container_of(plist, union recv_frame, u.list); - pnextattrib = &pnextrframe->u.hdr.attrib; - - if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) - return false; - - if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) - plist = plist->next; - else - break; - } - list_del_init(&prframe->u.hdr.list); - list_add_tail(&prframe->u.hdr.list, plist); - return true; -} - -int r8712_recv_indicatepkts_in_order(struct _adapter *padapter, - struct recv_reorder_ctrl *preorder_ctrl, - int bforced) -{ - struct list_head *phead, *plist; - union recv_frame *prframe; - struct rx_pkt_attrib *pattrib; - int bPktInBuf = false; - struct __queue *ppending_recvframe_queue = - &preorder_ctrl->pending_recvframe_queue; - - phead = &ppending_recvframe_queue->queue; - plist = phead->next; - /* Handling some condition for forced indicate case.*/ - if (bforced) { - if (list_empty(phead)) - return true; - - prframe = container_of(plist, union recv_frame, u.list); - pattrib = &prframe->u.hdr.attrib; - preorder_ctrl->indicate_seq = pattrib->seq_num; - } - /* Prepare indication list and indication. - * Check if there is any packet need indicate. - */ - while (!list_empty(phead)) { - prframe = container_of(plist, union recv_frame, u.list); - pattrib = &prframe->u.hdr.attrib; - if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { - plist = plist->next; - list_del_init(&prframe->u.hdr.list); - if (SN_EQUAL(preorder_ctrl->indicate_seq, - pattrib->seq_num)) - preorder_ctrl->indicate_seq = - (preorder_ctrl->indicate_seq + 1) % 4096; - /*indicate this recv_frame*/ - if (!pattrib->amsdu) { - if (!padapter->driver_stopped && - !padapter->surprise_removed) { - /* indicate this recv_frame */ - r8712_recv_indicatepkt(padapter, - prframe); - } - } else if (pattrib->amsdu == 1) { - amsdu_to_msdu(padapter, prframe); - } - /* Update local variables. */ - bPktInBuf = false; - } else { - bPktInBuf = true; - break; - } - } - return bPktInBuf; -} - -static int recv_indicatepkt_reorder(struct _adapter *padapter, - union recv_frame *prframe) -{ - unsigned long irql; - struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; - struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl; - struct __queue *ppending_recvframe_queue = - &preorder_ctrl->pending_recvframe_queue; - - if (!pattrib->amsdu) { - /* s1. */ - r8712_wlanhdr_to_ethhdr(prframe); - if (pattrib->qos != 1) { - if (!padapter->driver_stopped && - !padapter->surprise_removed) { - r8712_recv_indicatepkt(padapter, prframe); - return 0; - } else { - return -EINVAL; - } - } - } - spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); - /*s2. check if winstart_b(indicate_seq) needs to be updated*/ - if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) - goto _err_exit; - /*s3. Insert all packet into Reorder Queue to maintain its ordering.*/ - if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) - goto _err_exit; - /*s4. - * Indication process. - * After Packet dropping and Sliding Window shifting as above, we can - * now just indicate the packets with the SeqNum smaller than latest - * WinStart and buffer other packets. - * - * For Rx Reorder condition: - * 1. All packets with SeqNum smaller than WinStart => Indicate - * 2. All packets with SeqNum larger than or equal to - * WinStart => Buffer it. - */ - if (r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, false)) { - mod_timer(&preorder_ctrl->reordering_ctrl_timer, - jiffies + msecs_to_jiffies(REORDER_WAIT_TIME)); - spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); - } else { - spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); - del_timer(&preorder_ctrl->reordering_ctrl_timer); - } - return 0; -_err_exit: - spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); - return -ENOMEM; -} - -void r8712_reordering_ctrl_timeout_handler(void *pcontext) -{ - unsigned long irql; - struct recv_reorder_ctrl *preorder_ctrl = pcontext; - struct _adapter *padapter = preorder_ctrl->padapter; - struct __queue *ppending_recvframe_queue = - &preorder_ctrl->pending_recvframe_queue; - - if (padapter->driver_stopped || padapter->surprise_removed) - return; - spin_lock_irqsave(&ppending_recvframe_queue->lock, irql); - r8712_recv_indicatepkts_in_order(padapter, preorder_ctrl, true); - spin_unlock_irqrestore(&ppending_recvframe_queue->lock, irql); -} - -static int r8712_process_recv_indicatepkts(struct _adapter *padapter, - union recv_frame *prframe) -{ - int retval = _SUCCESS; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - - if (phtpriv->ht_option == 1) { /*B/G/N Mode*/ - if (recv_indicatepkt_reorder(padapter, prframe)) { - /* including perform A-MPDU Rx Ordering Buffer Control*/ - if (!padapter->driver_stopped && - !padapter->surprise_removed) - return _FAIL; - } - } else { /*B/G mode*/ - retval = r8712_wlanhdr_to_ethhdr(prframe); - if (retval) - return _FAIL; - if (!padapter->driver_stopped && !padapter->surprise_removed) { - /* indicate this recv_frame */ - r8712_recv_indicatepkt(padapter, prframe); - } else { - return _FAIL; - } - } - return retval; -} - -static u8 query_rx_pwr_percentage(s8 antpower) -{ - if ((antpower <= -100) || (antpower >= 20)) - return 0; - else if (antpower >= 0) - return 100; - else - return 100 + antpower; -} - -static u8 evm_db2percentage(s8 value) -{ - /* - * -33dB~0dB to 0%~99% - */ - s8 ret_val = clamp(-value, 0, 33) * 3; - - if (ret_val == 99) - ret_val = 100; - - return ret_val; -} - -s32 r8712_signal_scale_mapping(s32 cur_sig) -{ - s32 ret_sig; - - if (cur_sig >= 51 && cur_sig <= 100) - ret_sig = 100; - else if (cur_sig >= 41 && cur_sig <= 50) - ret_sig = 80 + ((cur_sig - 40) * 2); - else if (cur_sig >= 31 && cur_sig <= 40) - ret_sig = 66 + (cur_sig - 30); - else if (cur_sig >= 21 && cur_sig <= 30) - ret_sig = 54 + (cur_sig - 20); - else if (cur_sig >= 10 && cur_sig <= 20) - ret_sig = 42 + (((cur_sig - 10) * 2) / 3); - else if (cur_sig >= 5 && cur_sig <= 9) - ret_sig = 22 + (((cur_sig - 5) * 3) / 2); - else if (cur_sig >= 1 && cur_sig <= 4) - ret_sig = 6 + (((cur_sig - 1) * 3) / 2); - else - ret_sig = cur_sig; - return ret_sig; -} - -static s32 translate2dbm(struct _adapter *padapter, u8 signal_strength_idx) -{ - s32 signal_power; /* in dBm.*/ - /* Translate to dBm (x=0.5y-95).*/ - signal_power = (s32)((signal_strength_idx + 1) >> 1); - signal_power -= 95; - return signal_power; -} - -static void query_rx_phy_status(struct _adapter *padapter, - union recv_frame *prframe) -{ - u8 i, max_spatial_stream, evm; - struct recv_stat *prxstat = (struct recv_stat *)prframe->u.hdr.rx_head; - struct phy_stat *pphy_stat = (struct phy_stat *)(prxstat + 1); - u8 *pphy_head = (u8 *)(prxstat + 1); - s8 rx_pwr[4], rx_pwr_all; - u8 pwdb_all; - u32 rssi, total_rssi = 0; - u8 bcck_rate = 0, rf_rx_num = 0, cck_highpwr = 0; - struct phy_cck_rx_status *pcck_buf; - u8 sq; - - /* Record it for next packet processing*/ - bcck_rate = (prframe->u.hdr.attrib.mcs_rate <= 3 ? 1 : 0); - if (bcck_rate) { - u8 report; - - /* CCK Driver info Structure is not the same as OFDM packet.*/ - pcck_buf = (struct phy_cck_rx_status *)pphy_stat; - /* (1)Hardware does not provide RSSI for CCK - * (2)PWDB, Average PWDB calculated by hardware - * (for rate adaptive) - */ - if (!cck_highpwr) { - report = pcck_buf->cck_agc_rpt & 0xc0; - report >>= 6; - switch (report) { - /* Modify the RF RNA gain value to -40, -20, - * -2, 14 by Jenyu's suggestion - * Note: different RF with the different - * RNA gain. - */ - case 0x3: - rx_pwr_all = -40 - (pcck_buf->cck_agc_rpt & - 0x3e); - break; - case 0x2: - rx_pwr_all = -20 - (pcck_buf->cck_agc_rpt & - 0x3e); - break; - case 0x1: - rx_pwr_all = -2 - (pcck_buf->cck_agc_rpt & - 0x3e); - break; - case 0x0: - rx_pwr_all = 14 - (pcck_buf->cck_agc_rpt & - 0x3e); - break; - } - } else { - report = ((u8)(le32_to_cpu(pphy_stat->phydw1) >> 8)) & - 0x60; - report >>= 5; - switch (report) { - case 0x3: - rx_pwr_all = -40 - ((pcck_buf->cck_agc_rpt & - 0x1f) << 1); - break; - case 0x2: - rx_pwr_all = -20 - ((pcck_buf->cck_agc_rpt & - 0x1f) << 1); - break; - case 0x1: - rx_pwr_all = -2 - ((pcck_buf->cck_agc_rpt & - 0x1f) << 1); - break; - case 0x0: - rx_pwr_all = 14 - ((pcck_buf->cck_agc_rpt & - 0x1f) << 1); - break; - } - } - pwdb_all = query_rx_pwr_percentage(rx_pwr_all); - /* CCK gain is smaller than OFDM/MCS gain,*/ - /* so we add gain diff by experiences, the val is 6 */ - pwdb_all += 6; - if (pwdb_all > 100) - pwdb_all = 100; - /* modify the offset to make the same gain index with OFDM.*/ - if (pwdb_all > 34 && pwdb_all <= 42) - pwdb_all -= 2; - else if (pwdb_all > 26 && pwdb_all <= 34) - pwdb_all -= 6; - else if (pwdb_all > 14 && pwdb_all <= 26) - pwdb_all -= 8; - else if (pwdb_all > 4 && pwdb_all <= 14) - pwdb_all -= 4; - /* - * (3) Get Signal Quality (EVM) - */ - if (pwdb_all > 40) { - sq = 100; - } else { - sq = pcck_buf->sq_rpt; - if (pcck_buf->sq_rpt > 64) - sq = 0; - else if (pcck_buf->sq_rpt < 20) - sq = 100; - else - sq = ((64 - sq) * 100) / 44; - } - prframe->u.hdr.attrib.signal_qual = sq; - prframe->u.hdr.attrib.rx_mimo_signal_qual[0] = sq; - prframe->u.hdr.attrib.rx_mimo_signal_qual[1] = -1; - } else { - /* (1)Get RSSI for HT rate */ - for (i = 0; i < ((padapter->registrypriv.rf_config) & - 0x0f); i++) { - rf_rx_num++; - rx_pwr[i] = ((pphy_head[PHY_STAT_GAIN_TRSW_SHT + i] - & 0x3F) * 2) - 110; - /* Translate DBM to percentage. */ - rssi = query_rx_pwr_percentage(rx_pwr[i]); - total_rssi += rssi; - } - /* (2)PWDB, Average PWDB calculated by hardware (for - * rate adaptive) - */ - rx_pwr_all = (((pphy_head[PHY_STAT_PWDB_ALL_SHT]) >> 1) & 0x7f) - - 106; - pwdb_all = query_rx_pwr_percentage(rx_pwr_all); - - { - /* (3)EVM of HT rate */ - if (prframe->u.hdr.attrib.htc && - prframe->u.hdr.attrib.mcs_rate >= 20 && - prframe->u.hdr.attrib.mcs_rate <= 27) { - /* both spatial stream make sense */ - max_spatial_stream = 2; - } else { - /* only spatial stream 1 makes sense */ - max_spatial_stream = 1; - } - for (i = 0; i < max_spatial_stream; i++) { - evm = evm_db2percentage((pphy_head - [PHY_STAT_RXEVM_SHT + i]));/*dbm*/ - prframe->u.hdr.attrib.signal_qual = - (u8)(evm & 0xff); - prframe->u.hdr.attrib.rx_mimo_signal_qual[i] = - (u8)(evm & 0xff); - } - } - } - /* UI BSS List signal strength(in percentage), make it good looking, - * from 0~100. It is assigned to the BSS List in - * GetValueFromBeaconOrProbeRsp(). - */ - if (bcck_rate) { - prframe->u.hdr.attrib.signal_strength = - (u8)r8712_signal_scale_mapping(pwdb_all); - } else { - if (rf_rx_num != 0) - prframe->u.hdr.attrib.signal_strength = - (u8)(r8712_signal_scale_mapping(total_rssi /= - rf_rx_num)); - } -} - -static void process_link_qual(struct _adapter *padapter, - union recv_frame *prframe) -{ - u32 last_evm = 0, avg_val; - struct rx_pkt_attrib *pattrib; - struct smooth_rssi_data *sqd = &padapter->recvpriv.signal_qual_data; - - if (!prframe || !padapter) - return; - pattrib = &prframe->u.hdr.attrib; - if (pattrib->signal_qual != 0) { - /* - * 1. Record the general EVM to the sliding window. - */ - if (sqd->total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) { - sqd->total_num = PHY_LINKQUALITY_SLID_WIN_MAX; - last_evm = sqd->elements[sqd->index]; - sqd->total_val -= last_evm; - } - sqd->total_val += pattrib->signal_qual; - sqd->elements[sqd->index++] = pattrib->signal_qual; - if (sqd->index >= PHY_LINKQUALITY_SLID_WIN_MAX) - sqd->index = 0; - - /* <1> Showed on UI for user, in percentage. */ - avg_val = sqd->total_val / sqd->total_num; - padapter->recvpriv.signal = (u8)avg_val; - } -} - -static void process_rssi(struct _adapter *padapter, union recv_frame *prframe) -{ - u32 last_rssi, tmp_val; - struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; - struct smooth_rssi_data *ssd = &padapter->recvpriv.signal_strength_data; - - if (ssd->total_num++ >= PHY_RSSI_SLID_WIN_MAX) { - ssd->total_num = PHY_RSSI_SLID_WIN_MAX; - last_rssi = ssd->elements[ssd->index]; - ssd->total_val -= last_rssi; - } - ssd->total_val += pattrib->signal_strength; - ssd->elements[ssd->index++] = pattrib->signal_strength; - if (ssd->index >= PHY_RSSI_SLID_WIN_MAX) - ssd->index = 0; - tmp_val = ssd->total_val / ssd->total_num; - padapter->recvpriv.rssi = (s8)translate2dbm(padapter, (u8)tmp_val); -} - -static void process_phy_info(struct _adapter *padapter, - union recv_frame *prframe) -{ - query_rx_phy_status(padapter, prframe); - process_rssi(padapter, prframe); - process_link_qual(padapter, prframe); -} - -int recv_func(struct _adapter *padapter, void *pcontext) -{ - struct rx_pkt_attrib *pattrib; - union recv_frame *prframe, *orig_prframe; - int retval = _SUCCESS; - struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - prframe = pcontext; - orig_prframe = prframe; - pattrib = &prframe->u.hdr.attrib; - if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { - if (pattrib->crc_err == 1) - padapter->mppriv.rx_crcerrpktcount++; - else - padapter->mppriv.rx_pktcount++; - if (!check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE)) { - /* free this recv_frame */ - r8712_free_recvframe(orig_prframe, pfree_recv_queue); - goto _exit_recv_func; - } - } - /* check the frame crtl field and decache */ - retval = r8712_validate_recv_frame(padapter, prframe); - if (retval != _SUCCESS) { - /* free this recv_frame */ - r8712_free_recvframe(orig_prframe, pfree_recv_queue); - goto _exit_recv_func; - } - process_phy_info(padapter, prframe); - prframe = r8712_decryptor(padapter, prframe); - if (!prframe) { - retval = _FAIL; - goto _exit_recv_func; - } - prframe = r8712_recvframe_chk_defrag(padapter, prframe); - if (!prframe) - goto _exit_recv_func; - prframe = r8712_portctrl(padapter, prframe); - if (!prframe) { - retval = _FAIL; - goto _exit_recv_func; - } - retval = r8712_process_recv_indicatepkts(padapter, prframe); - if (retval != _SUCCESS) { - r8712_free_recvframe(orig_prframe, pfree_recv_queue); - goto _exit_recv_func; - } -_exit_recv_func: - return retval; -} - -static void recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb) -{ - u8 *pbuf, shift_sz = 0; - u8 frag, mf; - uint pkt_len; - u32 transfer_len; - struct recv_stat *prxstat; - u16 pkt_cnt, drvinfo_sz, pkt_offset, tmp_len, alloc_sz; - struct __queue *pfree_recv_queue; - _pkt *pkt_copy = NULL; - union recv_frame *precvframe = NULL; - struct recv_priv *precvpriv = &padapter->recvpriv; - - pfree_recv_queue = &precvpriv->free_recv_queue; - pbuf = pskb->data; - prxstat = (struct recv_stat *)pbuf; - pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff; - pkt_len = le32_to_cpu(prxstat->rxdw0) & 0x00003fff; - transfer_len = pskb->len; - /* Test throughput with Netgear 3700 (No security) with Chariot 3T3R - * pairs. The packet count will be a big number so that the containing - * packet will effect the Rx reordering. - */ - if (transfer_len < pkt_len) { - /* In this case, it means the MAX_RECVBUF_SZ is too small to - * get the data from 8712u. - */ - return; - } - do { - prxstat = (struct recv_stat *)pbuf; - pkt_len = le32_to_cpu(prxstat->rxdw0) & 0x00003fff; - /* more fragment bit */ - mf = (le32_to_cpu(prxstat->rxdw1) >> 27) & 0x1; - /* ragmentation number */ - frag = (le32_to_cpu(prxstat->rxdw2) >> 12) & 0xf; - /* uint 2^3 = 8 bytes */ - drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16; - drvinfo_sz <<= 3; - if (pkt_len <= 0) - return; - /* Qos data, wireless lan header length is 26 */ - if ((le32_to_cpu(prxstat->rxdw0) >> 23) & 0x01) - shift_sz = 2; - precvframe = r8712_alloc_recvframe(pfree_recv_queue); - if (!precvframe) - return; - INIT_LIST_HEAD(&precvframe->u.hdr.list); - precvframe->u.hdr.precvbuf = NULL; /*can't access the precvbuf*/ - precvframe->u.hdr.len = 0; - tmp_len = pkt_len + drvinfo_sz + RXDESC_SIZE; - pkt_offset = (u16)round_up(tmp_len, 128); - /* for first fragment packet, driver need allocate 1536 + - * drvinfo_sz + RXDESC_SIZE to defrag packet. - */ - if ((mf == 1) && (frag == 0)) - /*1658+6=1664, 1664 is 128 alignment.*/ - alloc_sz = max_t(u16, tmp_len, 1658); - else - alloc_sz = tmp_len; - /* 2 is for IP header 4 bytes alignment in QoS packet case. - * 4 is for skb->data 4 bytes alignment. - */ - alloc_sz += 6; - pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz); - if (!pkt_copy) - return; - - precvframe->u.hdr.pkt = pkt_copy; - skb_reserve(pkt_copy, 4 - ((addr_t)(pkt_copy->data) % 4)); - skb_reserve(pkt_copy, shift_sz); - memcpy(pkt_copy->data, pbuf, tmp_len); - precvframe->u.hdr.rx_head = pkt_copy->data; - precvframe->u.hdr.rx_data = pkt_copy->data; - precvframe->u.hdr.rx_tail = pkt_copy->data; - precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz; - - recvframe_put(precvframe, tmp_len); - recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); - /* because the endian issue, driver avoid reference to the - * rxstat after calling update_recvframe_attrib_from_recvstat(); - */ - update_recvframe_attrib_from_recvstat(&precvframe->u.hdr.attrib, - prxstat); - r8712_recv_entry(precvframe); - transfer_len -= pkt_offset; - pbuf += pkt_offset; - pkt_cnt--; - precvframe = NULL; - pkt_copy = NULL; - } while ((transfer_len > 0) && pkt_cnt > 0); -} - -static void recv_tasklet(struct tasklet_struct *t) -{ - struct sk_buff *pskb; - struct _adapter *padapter = from_tasklet(padapter, t, - recvpriv.recv_tasklet); - struct recv_priv *precvpriv = &padapter->recvpriv; - - while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) { - recvbuf2recvframe(padapter, pskb); - skb_reset_tail_pointer(pskb); - pskb->len = 0; - if (!skb_cloned(pskb)) - skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); - else - consume_skb(pskb); - } -} diff --git a/drivers/staging/rtl8712/rtl8712_recv.h b/drivers/staging/rtl8712/rtl8712_recv.h deleted file mode 100644 index a1360dcf91cec4..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_recv.h +++ /dev/null @@ -1,145 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL8712_RECV_H_ -#define _RTL8712_RECV_H_ - -#include "osdep_service.h" -#include "drv_types.h" - -/* Realtek's v2.6.6 reduced this to 4. However, under heavy network and CPU - * loads, even 8 receive buffers might not be enough; cutting it to 4 seemed - * unwise. - */ -#define NR_RECVBUFF (8) - -#define NR_PREALLOC_RECV_SKB (8) -#define RXDESC_SIZE 24 -#define RXDESC_OFFSET RXDESC_SIZE -#define RECV_BLK_SZ 512 -#define RECV_BLK_CNT 16 -#define RECV_BLK_TH RECV_BLK_CNT -#define MAX_RECVBUF_SZ 9100 -#define RECVBUFF_ALIGN_SZ 512 -#define RSVD_ROOM_SZ (0) -/*These definition is used for Rx packet reordering.*/ -#define SN_LESS(a, b) (((a-b) & 0x800) != 0) -#define SN_EQUAL(a, b) (a == b) -#define REORDER_WAIT_TIME 30 /* (ms)*/ - -struct recv_stat { - __le32 rxdw0; - __le32 rxdw1; - __le32 rxdw2; - __le32 rxdw3; - __le32 rxdw4; - __le32 rxdw5; -}; - -struct phy_cck_rx_status { - /* For CCK rate descriptor. This is a unsigned 8:1 variable. - * LSB bit present 0.5. And MSB 7 bts present a signed value. - * Range from -64~+63.5. - */ - u8 adc_pwdb_X[4]; - u8 sq_rpt; - u8 cck_agc_rpt; -}; - -struct phy_stat { - __le32 phydw0; - __le32 phydw1; - __le32 phydw2; - __le32 phydw3; - __le32 phydw4; - __le32 phydw5; - __le32 phydw6; - __le32 phydw7; -}; - -#define PHY_STAT_GAIN_TRSW_SHT 0 -#define PHY_STAT_PWDB_ALL_SHT 4 -#define PHY_STAT_CFOSHO_SHT 5 -#define PHY_STAT_CCK_AGC_RPT_SHT 5 -#define PHY_STAT_CFOTAIL_SHT 9 -#define PHY_STAT_RXEVM_SHT 13 -#define PHY_STAT_RXSNR_SHT 15 -#define PHY_STAT_PDSNR_SHT 19 -#define PHY_STAT_CSI_CURRENT_SHT 21 -#define PHY_STAT_CSI_TARGET_SHT 23 -#define PHY_STAT_SIGEVM_SHT 25 -#define PHY_STAT_MAX_EX_PWR_SHT 26 - -union recvstat { - struct recv_stat recv_stat; - unsigned int value[RXDESC_SIZE >> 2]; -}; - -struct recv_buf { - struct list_head list; - spinlock_t recvbuf_lock; - u32 ref_cnt; - struct _adapter *adapter; - struct urb *purb; - _pkt *pskb; - u8 irp_pending; - u32 transfer_len; - uint len; - u8 *phead; - u8 *pdata; - u8 *ptail; - u8 *pend; - u8 *pbuf; - u8 *pallocated_buf; -}; - -/* - * head -----> - * data -----> - * payload - * tail -----> - * end -----> - * len = (unsigned int )(tail - data); - */ -struct recv_frame_hdr { - struct list_head list; - _pkt *pkt; - _pkt *pkt_newalloc; - struct _adapter *adapter; - u8 fragcnt; - struct rx_pkt_attrib attrib; - uint len; - u8 *rx_head; - u8 *rx_data; - u8 *rx_tail; - u8 *rx_end; - void *precvbuf; - struct sta_info *psta; - /*for A-MPDU Rx reordering buffer control*/ - struct recv_reorder_ctrl *preorder_ctrl; -}; - -union recv_frame { - union { - struct list_head list; - struct recv_frame_hdr hdr; - } u; -}; - -void r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf); -void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf); -s32 r8712_signal_scale_mapping(s32 cur_sig); -void r8712_reordering_ctrl_timeout_handler(void *pcontext); - -#endif - diff --git a/drivers/staging/rtl8712/rtl8712_regdef.h b/drivers/staging/rtl8712/rtl8712_regdef.h deleted file mode 100644 index 28aec9aa539fd3..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_regdef.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_REGDEF_H__ -#define __RTL8712_REGDEF_H__ - -#include "rtl8712_syscfg_regdef.h" -#include "rtl8712_cmdctrl_regdef.h" -#include "rtl8712_macsetting_regdef.h" -#include "rtl8712_timectrl_regdef.h" -#include "rtl8712_fifoctrl_regdef.h" -#include "rtl8712_ratectrl_regdef.h" -#include "rtl8712_edcasetting_regdef.h" -#include "rtl8712_wmac_regdef.h" -#include "rtl8712_powersave_regdef.h" -#include "rtl8712_gp_regdef.h" -#include "rtl8712_debugctrl_regdef.h" - -#define HIMR (RTL8712_INTERRUPT_ + 0x08) - -#endif /* __RTL8712_REGDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_security_bitdef.h b/drivers/staging/rtl8712/rtl8712_security_bitdef.h deleted file mode 100644 index 44275ef455a0ae..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_security_bitdef.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_SECURITY_BITDEF_H__ -#define __RTL8712_SECURITY_BITDEF_H__ - -/*CAMCMD*/ -#define _SECCAM_POLLING BIT(31) -#define _SECCAM_CLR BIT(30) -#define _SECCAM_WE BIT(16) -#define _SECCAM_ADR_MSK 0x000000FF -#define _SECCAM_ADR_SHT 0 - -/*CAMDBG*/ -#define _SECCAM_INFO BIT(31) -#define _SEC_KEYFOUND BIT(30) -#define _SEC_CONFIG_MSK 0x3F000000 -#define _SEC_CONFIG_SHT 24 -#define _SEC_KEYCONTENT_MSK 0x00FFFFFF -#define _SEC_KEYCONTENT_SHT 0 - -/*SECCFG*/ -#define _NOSKMC BIT(5) -#define _SKBYA2 BIT(4) -#define _RXDEC BIT(3) -#define _TXENC BIT(2) -#define _RXUSEDK BIT(1) -#define _TXUSEDK BIT(0) - -#endif /*__RTL8712_SECURITY_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_spec.h b/drivers/staging/rtl8712/rtl8712_spec.h deleted file mode 100644 index 613a410e5714bc..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_spec.h +++ /dev/null @@ -1,121 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_SPEC_H__ -#define __RTL8712_SPEC_H__ - -#define RTL8712_IOBASE_TXPKT 0x10200000 /*IOBASE_TXPKT*/ -#define RTL8712_IOBASE_RXPKT 0x10210000 /*IOBASE_RXPKT*/ -#define RTL8712_IOBASE_RXCMD 0x10220000 /*IOBASE_RXCMD*/ -#define RTL8712_IOBASE_TXSTATUS 0x10230000 /*IOBASE_TXSTATUS*/ -#define RTL8712_IOBASE_RXSTATUS 0x10240000 /*IOBASE_RXSTATUS*/ -#define RTL8712_IOBASE_IOREG 0x10250000 /*IOBASE_IOREG ADDR*/ -#define RTL8712_IOBASE_SCHEDULER 0x10260000 /*IOBASE_SCHEDULE*/ - -#define RTL8712_IOBASE_TRXDMA 0x10270000 /*IOBASE_TRXDMA*/ -#define RTL8712_IOBASE_TXLLT 0x10280000 /*IOBASE_TXLLT*/ -#define RTL8712_IOBASE_WMAC 0x10290000 /*IOBASE_WMAC*/ -#define RTL8712_IOBASE_FW2HW 0x102A0000 /*IOBASE_FW2HW*/ -#define RTL8712_IOBASE_ACCESS_PHYREG 0x102B0000 /*IOBASE_ACCESS_PHYREG*/ - -#define RTL8712_IOBASE_FF 0x10300000 /*IOBASE_FIFO 0x1031000~0x103AFFFF*/ - -/*IOREG Offset for 8712*/ -#define RTL8712_SYSCFG_ RTL8712_IOBASE_IOREG -#define RTL8712_CMDCTRL_ (RTL8712_IOBASE_IOREG + 0x40) -#define RTL8712_MACIDSETTING_ (RTL8712_IOBASE_IOREG + 0x50) -#define RTL8712_TIMECTRL_ (RTL8712_IOBASE_IOREG + 0x80) -#define RTL8712_FIFOCTRL_ (RTL8712_IOBASE_IOREG + 0xA0) -#define RTL8712_RATECTRL_ (RTL8712_IOBASE_IOREG + 0x160) -#define RTL8712_EDCASETTING_ (RTL8712_IOBASE_IOREG + 0x1D0) -#define RTL8712_WMAC_ (RTL8712_IOBASE_IOREG + 0x200) -#define RTL8712_SECURITY_ (RTL8712_IOBASE_IOREG + 0x240) -#define RTL8712_POWERSAVE_ (RTL8712_IOBASE_IOREG + 0x260) -#define RTL8712_GP_ (RTL8712_IOBASE_IOREG + 0x2E0) -#define RTL8712_INTERRUPT_ (RTL8712_IOBASE_IOREG + 0x300) -#define RTL8712_DEBUGCTRL_ (RTL8712_IOBASE_IOREG + 0x310) -#define RTL8712_OFFLOAD_ (RTL8712_IOBASE_IOREG + 0x2D0) - -/*FIFO for 8712*/ -#define RTL8712_DMA_BCNQ (RTL8712_IOBASE_FF + 0x10000) -#define RTL8712_DMA_MGTQ (RTL8712_IOBASE_FF + 0x20000) -#define RTL8712_DMA_BMCQ (RTL8712_IOBASE_FF + 0x30000) -#define RTL8712_DMA_VOQ (RTL8712_IOBASE_FF + 0x40000) -#define RTL8712_DMA_VIQ (RTL8712_IOBASE_FF + 0x50000) -#define RTL8712_DMA_BEQ (RTL8712_IOBASE_FF + 0x60000) -#define RTL8712_DMA_BKQ (RTL8712_IOBASE_FF + 0x70000) -#define RTL8712_DMA_RX0FF (RTL8712_IOBASE_FF + 0x80000) -#define RTL8712_DMA_H2CCMD (RTL8712_IOBASE_FF + 0x90000) -#define RTL8712_DMA_C2HCMD (RTL8712_IOBASE_FF + 0xA0000) - -/*------------------------------*/ - -/*BIT 16 15*/ -#define DID_SDIO_LOCAL 0 /* 0 0*/ -#define DID_WLAN_IOREG 1 /* 0 1*/ -#define DID_WLAN_FIFO 3 /* 1 1*/ -#define DID_UNDEFINE (-1) - -#define CMD_ADDR_MAPPING_SHIFT 2 /*SDIO CMD ADDR MAPPING, - *shift 2 bit for match - * offset[14:2] - */ - -/*Offset for SDIO LOCAL*/ -#define OFFSET_SDIO_LOCAL 0x0FFF - -/*Offset for WLAN IOREG*/ -#define OFFSET_WLAN_IOREG 0x0FFF - -/*Offset for WLAN FIFO*/ -#define OFFSET_TX_BCNQ 0x0300 -#define OFFSET_TX_HIQ 0x0310 -#define OFFSET_TX_CMDQ 0x0320 -#define OFFSET_TX_MGTQ 0x0330 -#define OFFSET_TX_HCCAQ 0x0340 -#define OFFSET_TX_VOQ 0x0350 -#define OFFSET_TX_VIQ 0x0360 -#define OFFSET_TX_BEQ 0x0370 -#define OFFSET_TX_BKQ 0x0380 -#define OFFSET_RX_RX0FFQ 0x0390 -#define OFFSET_RX_C2HFFQ 0x03A0 - -#define BK_QID_01 1 -#define BK_QID_02 2 -#define BE_QID_01 0 -#define BE_QID_02 3 -#define VI_QID_01 4 -#define VI_QID_02 5 -#define VO_QID_01 6 -#define VO_QID_02 7 -#define HCCA_QID_01 8 -#define HCCA_QID_02 9 -#define HCCA_QID_03 10 -#define HCCA_QID_04 11 -#define HCCA_QID_05 12 -#define HCCA_QID_06 13 -#define HCCA_QID_07 14 -#define HCCA_QID_08 15 -#define HI_QID 17 -#define CMD_QID 19 -#define MGT_QID 18 -#define BCN_QID 16 - -#include "rtl8712_regdef.h" - -#include "rtl8712_bitdef.h" - -#include "basic_types.h" - -#endif /* __RTL8712_SPEC_H__ */ - diff --git a/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h b/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h deleted file mode 100644 index d92df3fbd2b193..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_syscfg_bitdef.h +++ /dev/null @@ -1,163 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_SYSCFG_BITDEF_H__ -#define __RTL8712_SYSCFG_BITDEF_H__ - -/*SYS_PWR_CTRL*/ -/*SRCTRL0*/ -/*SRCTRL1*/ -/*SYS_CLKR*/ - -/*SYS_IOS_CTRL*/ -#define iso_LDR2RP_SHT 8 /* EE Loader to Retention Path*/ -#define iso_LDR2RP BIT(iso_LDR2RP_SHT) /* 1:isolation, 0:attach*/ - -/*SYS_CTRL*/ -#define FEN_DIO_SDIO_SHT 0 -#define FEN_DIO_SDIO BIT(FEN_DIO_SDIO_SHT) -#define FEN_SDIO_SHT 1 -#define FEN_SDIO BIT(FEN_SDIO_SHT) -#define FEN_USBA_SHT 2 -#define FEN_USBA BIT(FEN_USBA_SHT) -#define FEN_UPLL_SHT 3 -#define FEN_UPLL BIT(FEN_UPLL_SHT) -#define FEN_USBD_SHT 4 -#define FEN_USBD BIT(FEN_USBD_SHT) -#define FEN_DIO_PCIE_SHT 5 -#define FEN_DIO_PCIE BIT(FEN_DIO_PCIE_SHT) -#define FEN_PCIEA_SHT 6 -#define FEN_PCIEA BIT(FEN_PCIEA_SHT) -#define FEN_PPLL_SHT 7 -#define FEN_PPLL BIT(FEN_PPLL_SHT) -#define FEN_PCIED_SHT 8 -#define FEN_PCIED BIT(FEN_PCIED_SHT) -#define FEN_CPUEN_SHT 10 -#define FEN_CPUEN BIT(FEN_CPUEN_SHT) -#define FEN_DCORE_SHT 11 -#define FEN_DCORE BIT(FEN_DCORE_SHT) -#define FEN_ELDR_SHT 12 -#define FEN_ELDR BIT(FEN_ELDR_SHT) -#define PWC_DV2LDR_SHT 13 -#define PWC_DV2LDR BIT(PWC_DV2LDR_SHT) /* Loader Power Enable*/ - -/*=== SYS_CLKR ===*/ -#define SYS_CLKSEL_SHT 0 -#define SYS_CLKSEL BIT(SYS_CLKSEL_SHT) /* System Clock 80MHz*/ -#define PS_CLKSEL_SHT 1 -#define PS_CLKSEL BIT(PS_CLKSEL_SHT) /*System power save - * clock select. - */ -#define CPU_CLKSEL_SHT 2 -#define CPU_CLKSEL BIT(CPU_CLKSEL_SHT) /* System Clock select, - * 1: AFE source, - * 0: System clock(L-Bus) - */ -#define INT32K_EN_SHT 3 -#define INT32K_EN BIT(INT32K_EN_SHT) -#define MACSLP_SHT 4 -#define MACSLP BIT(MACSLP_SHT) -#define MAC_CLK_EN_SHT 11 -#define MAC_CLK_EN BIT(MAC_CLK_EN_SHT) /* MAC Clock Enable.*/ -#define SYS_CLK_EN_SHT 12 -#define SYS_CLK_EN BIT(SYS_CLK_EN_SHT) -#define RING_CLK_EN_SHT 13 -#define RING_CLK_EN BIT(RING_CLK_EN_SHT) -#define SWHW_SEL_SHT 14 -#define SWHW_SEL BIT(SWHW_SEL_SHT) /* Load done, - * control path switch. - */ -#define FWHW_SEL_SHT 15 -#define FWHW_SEL BIT(FWHW_SEL_SHT) /* Sleep exit, - * control path switch. - */ - -/*9346CR*/ -#define _VPDIDX_MSK 0xFF00 -#define _VPDIDX_SHT 8 -#define _EEM_MSK 0x00C0 -#define _EEM_SHT 6 -#define _EEM0 BIT(6) -#define _EEM1 BIT(7) -#define _EEPROM_EN BIT(5) -#define _9356SEL BIT(4) -#define _EECS BIT(3) -#define _EESK BIT(2) -#define _EEDI BIT(1) -#define _EEDO BIT(0) - -/*AFE_MISC*/ -#define AFE_MISC_USB_MBEN_SHT 7 -#define AFE_MISC_USB_MBEN BIT(AFE_MISC_USB_MBEN_SHT) -#define AFE_MISC_USB_BGEN_SHT 6 -#define AFE_MISC_USB_BGEN BIT(AFE_MISC_USB_BGEN_SHT) -#define AFE_MISC_LD12_VDAJ_SHT 4 -#define AFE_MISC_LD12_VDAJ_MSK 0X0030 -#define AFE_MISC_LD12_VDAJ BIT(AFE_MISC_LD12_VDAJ_SHT) -#define AFE_MISC_I32_EN_SHT 3 -#define AFE_MISC_I32_EN BIT(AFE_MISC_I32_EN_SHT) -#define AFE_MISC_E32_EN_SHT 2 -#define AFE_MISC_E32_EN BIT(AFE_MISC_E32_EN_SHT) -#define AFE_MISC_MBEN_SHT 1 -#define AFE_MISC_MBEN BIT(AFE_MISC_MBEN_SHT)/* Enable AFE Macro - * Block's Mbias. - */ -#define AFE_MISC_BGEN_SHT 0 -#define AFE_MISC_BGEN BIT(AFE_MISC_BGEN_SHT)/* Enable AFE Macro - * Block's Bandgap. - */ - -/*--------------------------------------------------------------------------*/ -/* SPS1_CTRL bits (Offset 0x18-1E, 56bits)*/ -/*--------------------------------------------------------------------------*/ -#define SPS1_SWEN BIT(1) /* Enable vsps18 SW Macro Block.*/ -#define SPS1_LDEN BIT(0) /* Enable VSPS12 LDO Macro block.*/ - -/*----------------------------------------------------------------------------*/ -/* LDOA15_CTRL bits (Offset 0x20, 8bits)*/ -/*----------------------------------------------------------------------------*/ -#define LDA15_EN BIT(0) /* Enable LDOA15 Macro Block*/ - -/*----------------------------------------------------------------------------*/ -/* 8192S LDOV12D_CTRL bit (Offset 0x21, 8bits)*/ -/*----------------------------------------------------------------------------*/ -#define LDV12_EN BIT(0) /* Enable LDOVD12 Macro Block*/ -#define LDV12_SDBY BIT(1) /* LDOVD12 standby mode*/ - -/*CLK_PS_CTRL*/ -#define _CLK_GATE_EN BIT(0) - -/* EFUSE_CTRL*/ -#define EF_FLAG BIT(31) /* Access Flag, Write:1; - * Read:0 - */ -#define EF_PGPD 0x70000000 /* E-fuse Program time*/ -#define EF_RDT 0x0F000000 /* E-fuse read time: in the - * unit of cycle time - */ -#define EF_PDN_EN BIT(19) /* EFuse Power down enable*/ -#define ALD_EN BIT(18) /* Autoload Enable*/ -#define EF_ADDR 0x0003FF00 /* Access Address*/ -#define EF_DATA 0x000000FF /* Access Data*/ - -/* EFUSE_TEST*/ -#define LDOE25_EN BIT(31) /* Enable LDOE25 Macro Block*/ - -/* EFUSE_CLK_CTRL*/ -#define EFUSE_CLK_EN BIT(1) /* E-Fuse Clock Enable*/ -#define EFUSE_CLK_SEL BIT(0) /* E-Fuse Clock Select, - * 0:500K, 1:40M - */ - -#endif /*__RTL8712_SYSCFG_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h b/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h deleted file mode 100644 index da5efcdedabe2f..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_syscfg_regdef.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_SYSCFG_REGDEF_H__ -#define __RTL8712_SYSCFG_REGDEF_H__ - -#define SYS_ISO_CTRL (RTL8712_SYSCFG_ + 0x0000) -#define SYS_FUNC_EN (RTL8712_SYSCFG_ + 0x0002) -#define PMC_FSM (RTL8712_SYSCFG_ + 0x0004) -#define SYS_CLKR (RTL8712_SYSCFG_ + 0x0008) -#define EE_9346CR (RTL8712_SYSCFG_ + 0x000A) -#define EE_VPD (RTL8712_SYSCFG_ + 0x000C) -#define AFE_MISC (RTL8712_SYSCFG_ + 0x0010) -#define SPS0_CTRL (RTL8712_SYSCFG_ + 0x0011) -#define SPS1_CTRL (RTL8712_SYSCFG_ + 0x0018) -#define RF_CTRL (RTL8712_SYSCFG_ + 0x001F) -#define LDOA15_CTRL (RTL8712_SYSCFG_ + 0x0020) -#define LDOV12D_CTRL (RTL8712_SYSCFG_ + 0x0021) -#define LDOHCI12_CTRL (RTL8712_SYSCFG_ + 0x0022) -#define LDO_USB_CTRL (RTL8712_SYSCFG_ + 0x0023) -#define LPLDO_CTRL (RTL8712_SYSCFG_ + 0x0024) -#define AFE_XTAL_CTRL (RTL8712_SYSCFG_ + 0x0026) -#define AFE_PLL_CTRL (RTL8712_SYSCFG_ + 0x0028) -#define EFUSE_CTRL (RTL8712_SYSCFG_ + 0x0030) -#define EFUSE_TEST (RTL8712_SYSCFG_ + 0x0034) -#define PWR_DATA (RTL8712_SYSCFG_ + 0x0038) -#define DPS_TIMER (RTL8712_SYSCFG_ + 0x003C) -#define RCLK_MON (RTL8712_SYSCFG_ + 0x003E) -#define EFUSE_CLK_CTRL (RTL8712_SYSCFG_ + 0x02F8) - -#endif /*__RTL8712_SYSCFG_REGDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h deleted file mode 100644 index d7bc9dd5cecd21..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_timectrl_bitdef.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_TIMECTRL_BITDEF_H__ -#define __RTL8712_TIMECTRL_BITDEF_H__ - -/*TSFTR*/ -/*SLOT*/ -/*USTIME*/ - -/*TUBASE*/ -#define _TUBASE_MSK 0x07FF - -/*SIFS_CCK*/ -#define _SIFS_CCK_TRX_MSK 0xFF00 -#define _SIFS_CCK_TRX_SHT 0x8 -#define _SIFS_CCK_CTX_MSK 0x00FF -#define _SIFS_CCK_CTX_SHT 0 - -/*SIFS_OFDM*/ -#define _SIFS_OFDM_TRX_MSK 0xFF00 -#define _SIFS_OFDM_TRX_SHT 0x8 -#define _SIFS_OFDM_CTX_MSK 0x00FF -#define _SIFS_OFDM_CTX_SHT 0 - -/*PIFS*/ -/*ACKTO*/ -/*EIFS*/ -/*BCNITV*/ -/*ATIMWND*/ - -/*DRVERLYINT*/ -#define _ENSWBCN BIT(15) -#define _DRVERLY_TU_MSK 0x0FF0 -#define _DRVERLY_TU_SHT 4 -#define _DRVERLY_US_MSK 0x000F -#define _DRVERLY_US_SHT 0 - -/*BCNDMATIM*/ -#define _BCNDMATIM_MSK 0x03FF - -/*BCNERRTH*/ -/*MLT*/ - -#endif /* __RTL8712_TIMECTRL_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h b/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h deleted file mode 100644 index b51603f1b88004..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_timectrl_regdef.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL8712_TIMECTRL_REGDEF_H__ -#define __RTL8712_TIMECTRL_REGDEF_H__ - -#define TSFTR (RTL8712_TIMECTRL_ + 0x00) -#define USTIME (RTL8712_TIMECTRL_ + 0x08) -#define SLOT (RTL8712_TIMECTRL_ + 0x09) -#define TUBASE (RTL8712_TIMECTRL_ + 0x0A) -#define SIFS_CCK (RTL8712_TIMECTRL_ + 0x0C) -#define SIFS_OFDM (RTL8712_TIMECTRL_ + 0x0E) -#define PIFS (RTL8712_TIMECTRL_ + 0x10) -#define ACKTO (RTL8712_TIMECTRL_ + 0x11) -#define EIFS (RTL8712_TIMECTRL_ + 0x12) -#define BCNITV (RTL8712_TIMECTRL_ + 0x14) -#define ATIMWND (RTL8712_TIMECTRL_ + 0x16) -#define DRVERLYINT (RTL8712_TIMECTRL_ + 0x18) -#define BCNDMATIM (RTL8712_TIMECTRL_ + 0x1A) -#define BCNERRTH (RTL8712_TIMECTRL_ + 0x1C) -#define MLT (RTL8712_TIMECTRL_ + 0x1D) - -#endif /* __RTL8712_TIMECTRL_REGDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h b/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h deleted file mode 100644 index ea164e48234766..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_wmac_bitdef.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_WMAC_BITDEF_H__ -#define __RTL8712_WMAC_BITDEF_H__ - -/*NAVCTRL*/ -#define _NAV_UPPER_EN BIT(18) -#define _NAV_MTO_EN BIT(17) -#define _NAV_UPPER BIT(16) -#define _NAV_MTO_MSK 0xFF00 -#define _NAV_MTO_SHT 8 -#define _RTSRST_MSK 0x00FF -#define _RTSRST_SHT 0 - -/*BWOPMODE*/ -#define _20MHZBW BIT(2) - -/*BACAMCMD*/ -#define _BACAM_POLL BIT(31) -#define _BACAM_RST BIT(17) -#define _BACAM_RW BIT(16) -#define _BACAM_ADDR_MSK 0x0000007F -#define _BACAM_ADDR_SHT 0 - -/*LBDLY*/ -#define _LBDLY_MSK 0x1F - -/*FWDLY*/ -#define _FWDLY_MSK 0x0F - -/*RXERR_RPT*/ -#define _RXERR_RPT_SEL_MSK 0xF0000000 -#define _RXERR_RPT_SEL_SHT 28 -#define _RPT_CNT_MSK 0x000FFFFF -#define _RPT_CNT_SHT 0 - -#endif /*__RTL8712_WMAC_BITDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_wmac_regdef.h b/drivers/staging/rtl8712/rtl8712_wmac_regdef.h deleted file mode 100644 index dfe3e9fbed4313..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_wmac_regdef.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_WMAC_REGDEF_H__ -#define __RTL8712_WMAC_REGDEF_H__ - -#define NAVCTRL (RTL8712_WMAC_ + 0x00) -#define BWOPMODE (RTL8712_WMAC_ + 0x03) -#define BACAMCMD (RTL8712_WMAC_ + 0x04) -#define BACAMCONTENT (RTL8712_WMAC_ + 0x08) -#define LBDLY (RTL8712_WMAC_ + 0x10) -#define FWDLY (RTL8712_WMAC_ + 0x11) -#define HWPC_RX_CTRL (RTL8712_WMAC_ + 0x18) -#define MQ (RTL8712_WMAC_ + 0x20) -#define MA (RTL8712_WMAC_ + 0x22) -#define MS (RTL8712_WMAC_ + 0x24) -#define CLM_RESULT (RTL8712_WMAC_ + 0x27) -#define NHM_RPI_CNT (RTL8712_WMAC_ + 0x28) -#define RXERR_RPT (RTL8712_WMAC_ + 0x30) -#define NAV_PROT_LEN (RTL8712_WMAC_ + 0x34) -#define CFEND_TH (RTL8712_WMAC_ + 0x36) -#define AMPDU_MIN_SPACE (RTL8712_WMAC_ + 0x37) -#define TXOP_STALL_CTRL (RTL8712_WMAC_ + 0x38) - -#endif /*__RTL8712_WMAC_REGDEF_H__*/ - diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c deleted file mode 100644 index 12f2fdb1b3cbcc..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_xmit.c +++ /dev/null @@ -1,732 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl8712_xmit.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL8712_XMIT_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "wifi.h" -#include "osdep_intf.h" -#include "usb_ops.h" - -static void dump_xframe(struct _adapter *padapter, - struct xmit_frame *pxmitframe); -static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz); - -sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag) -{ - phw_txqueue->ac_tag = ac_tag; - switch (ac_tag) { - case BE_QUEUE_INX: - phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ; - break; - case BK_QUEUE_INX: - phw_txqueue->ff_hwaddr = RTL8712_DMA_BKQ; - break; - case VI_QUEUE_INX: - phw_txqueue->ff_hwaddr = RTL8712_DMA_VIQ; - break; - case VO_QUEUE_INX: - phw_txqueue->ff_hwaddr = RTL8712_DMA_VOQ; - break; - case BMC_QUEUE_INX: - phw_txqueue->ff_hwaddr = RTL8712_DMA_BEQ; - break; - } - return _SUCCESS; -} - -int r8712_txframes_sta_ac_pending(struct _adapter *padapter, - struct pkt_attrib *pattrib) -{ - struct sta_info *psta; - struct tx_servq *ptxservq; - int priority = pattrib->priority; - - psta = pattrib->psta; - switch (priority) { - case 1: - case 2: - ptxservq = &psta->sta_xmitpriv.bk_q; - break; - case 4: - case 5: - ptxservq = &psta->sta_xmitpriv.vi_q; - break; - case 6: - case 7: - ptxservq = &psta->sta_xmitpriv.vo_q; - break; - case 0: - case 3: - default: - ptxservq = &psta->sta_xmitpriv.be_q; - break; - } - return ptxservq->qcnt; -} - -static u32 get_ff_hwaddr(struct xmit_frame *pxmitframe) -{ - u32 addr = 0; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - struct _adapter *padapter = pxmitframe->padapter; - struct dvobj_priv *pdvobj = &padapter->dvobjpriv; - - if (pxmitframe->frame_tag == TXAGG_FRAMETAG) { - addr = RTL8712_DMA_H2CCMD; - } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { - addr = RTL8712_DMA_MGTQ; - } else if (pdvobj->nr_endpoint == 6) { - switch (pattrib->priority) { - case 0: - case 3: - addr = RTL8712_DMA_BEQ; - break; - case 1: - case 2: - addr = RTL8712_DMA_BKQ; - break; - case 4: - case 5: - addr = RTL8712_DMA_VIQ; - break; - case 6: - case 7: - addr = RTL8712_DMA_VOQ; - break; - case 0x10: - case 0x11: - case 0x12: - case 0x13: - addr = RTL8712_DMA_H2CCMD; - break; - default: - addr = RTL8712_DMA_BEQ; - break; - } - } else if (pdvobj->nr_endpoint == 4) { - switch (pattrib->qsel) { - case 0: - case 3: - case 1: - case 2: - addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/ - break; - case 4: - case 5: - case 6: - case 7: - addr = RTL8712_DMA_VOQ;/*RTL8712_EP_HI;*/ - break; - case 0x10: - case 0x11: - case 0x12: - case 0x13: - addr = RTL8712_DMA_H2CCMD; - break; - default: - addr = RTL8712_DMA_BEQ;/*RTL8712_EP_LO;*/ - break; - } - } - return addr; -} - -static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, - struct hw_xmit *phwxmit, struct tx_servq *ptxservq, - struct __queue *pframe_queue) -{ - struct list_head *xmitframe_plist, *xmitframe_phead; - struct xmit_frame *pxmitframe = NULL; - - xmitframe_phead = &pframe_queue->queue; - xmitframe_plist = xmitframe_phead->next; - if (!end_of_queue_search(xmitframe_phead, xmitframe_plist)) { - pxmitframe = container_of(xmitframe_plist, - struct xmit_frame, list); - list_del_init(&pxmitframe->list); - ptxservq->qcnt--; - phwxmit->txcmdcnt++; - } - return pxmitframe; -} - -static struct xmit_frame *dequeue_xframe_ex(struct xmit_priv *pxmitpriv, - struct hw_xmit *phwxmit_i, sint entry) -{ - unsigned long irqL0; - struct list_head *sta_plist, *sta_phead; - struct hw_xmit *phwxmit; - struct tx_servq *ptxservq = NULL; - struct __queue *pframe_queue = NULL; - struct xmit_frame *pxmitframe = NULL; - int i, inx[4]; - int j, acirp_cnt[4]; - - /*entry indx: 0->vo, 1->vi, 2->be, 3->bk.*/ - inx[0] = 0; acirp_cnt[0] = pxmitpriv->voq_cnt; - inx[1] = 1; acirp_cnt[1] = pxmitpriv->viq_cnt; - inx[2] = 2; acirp_cnt[2] = pxmitpriv->beq_cnt; - inx[3] = 3; acirp_cnt[3] = pxmitpriv->bkq_cnt; - for (i = 0; i < 4; i++) { - for (j = i + 1; j < 4; j++) { - if (acirp_cnt[j] < acirp_cnt[i]) { - swap(acirp_cnt[i], acirp_cnt[j]); - swap(inx[i], inx[j]); - } - } - } - spin_lock_irqsave(&pxmitpriv->lock, irqL0); - for (i = 0; i < entry; i++) { - phwxmit = phwxmit_i + inx[i]; - sta_phead = &phwxmit->sta_queue->queue; - sta_plist = sta_phead->next; - while (!end_of_queue_search(sta_phead, sta_plist)) { - ptxservq = container_of(sta_plist, struct tx_servq, tx_pending); - pframe_queue = &ptxservq->sta_pending; - pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, - pframe_queue); - if (pxmitframe) { - phwxmit->accnt--; - goto exit_dequeue_xframe_ex; - } - sta_plist = sta_plist->next; - /*Remove sta node when there are no pending packets.*/ - if (list_empty(&pframe_queue->queue)) { - /* must be done after sta_plist->next - * and before break - */ - list_del_init(&ptxservq->tx_pending); - } - } - } -exit_dequeue_xframe_ex: - spin_unlock_irqrestore(&pxmitpriv->lock, irqL0); - return pxmitframe; -} - -void r8712_do_queue_select(struct _adapter *padapter, struct pkt_attrib *pattrib) -{ - unsigned int qsel = 0; - struct dvobj_priv *pdvobj = &padapter->dvobjpriv; - - if (pdvobj->nr_endpoint == 6) { - qsel = (unsigned int)pattrib->priority; - } else if (pdvobj->nr_endpoint == 4) { - qsel = (unsigned int)pattrib->priority; - if (qsel == 0 || qsel == 3) - qsel = 3; - else if (qsel == 1 || qsel == 2) - qsel = 1; - else if (qsel == 4 || qsel == 5) - qsel = 5; - else if (qsel == 6 || qsel == 7) - qsel = 7; - else - qsel = 3; - } - pattrib->qsel = qsel; -} - -#ifdef CONFIG_R8712_TX_AGGR -void r8712_construct_txaggr_cmd_desc(struct xmit_buf *pxmitbuf) -{ - struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; - - /* Fill up TxCmd Descriptor according as USB FW Tx Aggregation info.*/ - /* dw0 */ - ptx_desc->txdw0 = cpu_to_le32(CMD_HDR_SZ & 0xffff); - ptx_desc->txdw0 |= - cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & - 0x00ff0000); - ptx_desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); - - /* dw1 */ - ptx_desc->txdw1 |= cpu_to_le32((0x13 << QSEL_SHT) & 0x00001f00); -} - -void r8712_construct_txaggr_cmd_hdr(struct xmit_buf *pxmitbuf) -{ - struct xmit_frame *pxmitframe = (struct xmit_frame *) - pxmitbuf->priv_data; - struct _adapter *padapter = pxmitframe->padapter; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) - (pxmitbuf->pbuf + TXDESC_SIZE); - - /* Fill up Cmd Header for USB FW Tx Aggregation.*/ - /* dw0 */ - pcmd_hdr->cmd_dw0 = cpu_to_le32((GEN_CMD_CODE(_AMSDU_TO_AMPDU) << 16) | - (pcmdpriv->cmd_seq << 24)); - pcmdpriv->cmd_seq++; -} - -void r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf, - struct xmit_frame *pxmitframe) -{ - struct _adapter *padapter = pxmitframe->padapter; - struct tx_desc *ptx_desc = (struct tx_desc *)pxmitbuf->pbuf; - int last_txcmdsz = 0; - int padding_sz = 0; - - /* 802.3->802.11 converter */ - r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); - /* free skb struct */ - r8712_xmit_complete(padapter, pxmitframe); - if (pxmitframe->attrib.ether_type != 0x0806) { - if ((pxmitframe->attrib.ether_type != 0x888e) && - (pxmitframe->attrib.dhcp_pkt != 1)) { - r8712_issue_addbareq_cmd(padapter, pxmitframe->attrib.priority); - } - } - pxmitframe->last[0] = 1; - update_txdesc(pxmitframe, (uint *)(pxmitframe->buf_addr), pxmitframe->attrib.last_txcmdsz); - /*padding zero */ - last_txcmdsz = pxmitframe->attrib.last_txcmdsz; - padding_sz = (8 - (last_txcmdsz % 8)); - if ((last_txcmdsz % 8) != 0) { - int i; - - for (i = 0; i < padding_sz; i++) - *(pxmitframe->buf_addr + TXDESC_SIZE + last_txcmdsz + - i) = 0; - } - /* Add the new mpdu's length */ - ptx_desc->txdw0 = cpu_to_le32((ptx_desc->txdw0 & 0xffff0000) | - ((ptx_desc->txdw0 & 0x0000ffff) + - ((TXDESC_SIZE + last_txcmdsz + padding_sz) & - 0x0000ffff))); -} - -void r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, - struct xmit_frame *pxmitframe) -{ - /* linux complete context doesn't need to protect */ - pxmitframe->pxmitbuf = pxmitbuf; - pxmitbuf->priv_data = pxmitframe; - pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; - /* buffer addr assoc */ - pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE + CMD_HDR_SZ; - /*RTL8712_DMA_H2CCMD */ - r8712_construct_txaggr_cmd_desc(pxmitbuf); - r8712_construct_txaggr_cmd_hdr(pxmitbuf); - r8712_append_mpdu_unit(pxmitbuf, pxmitframe); - pxmitbuf->aggr_nr = 1; -} - -u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf, struct xmit_frame *pxmitframe) -{ - pxmitframe->pxmitbuf = pxmitbuf; - pxmitbuf->priv_data = pxmitframe; - pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; - /* buffer addr assoc */ - pxmitframe->buf_addr = pxmitbuf->pbuf + TXDESC_SIZE + - (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); - r8712_append_mpdu_unit(pxmitbuf, pxmitframe); - r8712_free_xmitframe_ex(&pxmitframe->padapter->xmitpriv, - pxmitframe); - pxmitbuf->aggr_nr++; - - return TXDESC_SIZE + - (((struct tx_desc *)pxmitbuf->pbuf)->txdw0 & 0x0000ffff); -} - -void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, - struct xmit_frame *pxmitframe) -{ - struct _adapter *padapter = pxmitframe->padapter; - struct dvobj_priv *pdvobj = &padapter->dvobjpriv; - struct tx_desc *ptxdesc = pxmitbuf->pbuf; - struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) - (pxmitbuf->pbuf + TXDESC_SIZE); - u16 total_length = (u16)(ptxdesc->txdw0 & 0xffff); - - /* use 1st xmitframe as media */ - xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); - pcmd_hdr->cmd_dw0 = cpu_to_le32(((total_length - CMD_HDR_SZ) & - 0x0000ffff) | (pcmd_hdr->cmd_dw0 & - 0xffff0000)); - - /* urb length in cmd_dw1 */ - pcmd_hdr->cmd_dw1 = cpu_to_le32((pxmitbuf->aggr_nr & 0xff) | - ((total_length + TXDESC_SIZE) << 16)); - pxmitframe->last[0] = 1; - pxmitframe->bpending[0] = false; - pxmitframe->mem_addr = pxmitbuf->pbuf; - - if ((pdvobj->ishighspeed && ((total_length + TXDESC_SIZE) % 0x200) == 0) || - ((!pdvobj->ishighspeed && ((total_length + TXDESC_SIZE) % - 0x40) == 0))) { - ptxdesc->txdw0 |= cpu_to_le32 - (((TXDESC_SIZE + OFFSET_SZ + 8) << OFFSET_SHT) & - 0x00ff0000); - /*32 bytes for TX Desc + 8 bytes pending*/ - } else { - ptxdesc->txdw0 |= cpu_to_le32 - (((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & - 0x00ff0000); - /*default = 32 bytes for TX Desc*/ - } - r8712_write_port(pxmitframe->padapter, RTL8712_DMA_H2CCMD, total_length + TXDESC_SIZE, - (u8 *)pxmitframe); -} - -#endif - -static void update_txdesc(struct xmit_frame *pxmitframe, uint *pmem, int sz) -{ - uint qsel; - struct _adapter *padapter = pxmitframe->padapter; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct qos_priv *pqospriv = &pmlmepriv->qospriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - struct tx_desc *ptxdesc = (struct tx_desc *)pmem; - struct dvobj_priv *pdvobj = &padapter->dvobjpriv; -#ifdef CONFIG_R8712_TX_AGGR - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; -#endif - u8 blnSetTxDescOffset; - bool bmcst = is_multicast_ether_addr(pattrib->ra); - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - struct tx_desc txdesc_mp; - - memcpy(&txdesc_mp, ptxdesc, sizeof(struct tx_desc)); - memset(ptxdesc, 0, sizeof(struct tx_desc)); - /* offset 0 */ - ptxdesc->txdw0 |= cpu_to_le32(sz & 0x0000ffff); - if (pdvobj->ishighspeed) { - if (((sz + TXDESC_SIZE) % 512) == 0) - blnSetTxDescOffset = 1; - else - blnSetTxDescOffset = 0; - } else { - if (((sz + TXDESC_SIZE) % 64) == 0) - blnSetTxDescOffset = 1; - else - blnSetTxDescOffset = 0; - } - if (blnSetTxDescOffset) { - /* 32 bytes for TX Desc + 8 bytes pending */ - ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ + 8) << - OFFSET_SHT) & 0x00ff0000); - } else { - /* default = 32 bytes for TX Desc */ - ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << - OFFSET_SHT) & 0x00ff0000); - } - ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); - if (pxmitframe->frame_tag == DATA_FRAMETAG) { - /* offset 4 */ - ptxdesc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x1f); - -#ifdef CONFIG_R8712_TX_AGGR - /* dirty workaround, need to check if it is aggr cmd. */ - if ((u8 *)pmem != (u8 *)pxmitframe->pxmitbuf->pbuf) { - ptxdesc->txdw0 |= cpu_to_le32 - ((0x3 << TYPE_SHT) & TYPE_MSK); - qsel = (uint)(pattrib->qsel & 0x0000001f); - if (qsel == 2) - qsel = 0; - ptxdesc->txdw1 |= cpu_to_le32 - ((qsel << QSEL_SHT) & 0x00001f00); - ptxdesc->txdw2 = cpu_to_le32 - ((qsel << RTS_RC_SHT) & 0x001f0000); - ptxdesc->txdw6 |= cpu_to_le32 - ((0x5 << RSVD6_SHT) & RSVD6_MSK); - } else { - ptxdesc->txdw0 |= cpu_to_le32 - ((0x3 << TYPE_SHT) & TYPE_MSK); - ptxdesc->txdw1 |= cpu_to_le32 - ((0x13 << QSEL_SHT) & 0x00001f00); - qsel = (uint)(pattrib->qsel & 0x0000001f); - if (qsel == 2) - qsel = 0; - ptxdesc->txdw2 = cpu_to_le32 - ((qsel << RTS_RC_SHT) & 0x0001f000); - ptxdesc->txdw7 |= cpu_to_le32 - (pcmdpriv->cmd_seq << 24); - pcmdpriv->cmd_seq++; - } - pattrib->qsel = 0x13; -#else - qsel = (uint)(pattrib->qsel & 0x0000001f); - ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); -#endif - if (!pqospriv->qos_option) - ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/*Non-QoS*/ - if ((pattrib->encrypt > 0) && !pattrib->bswenc) { - switch (pattrib->encrypt) { /*SEC_TYPE*/ - case _WEP40_: - case _WEP104_: - ptxdesc->txdw1 |= cpu_to_le32((0x01 << 22) & - 0x00c00000); - /*KEY_ID when WEP is used;*/ - ptxdesc->txdw1 |= - cpu_to_le32((psecuritypriv->PrivacyKeyIndex << 17) & - 0x00060000); - break; - case _TKIP_: - case _TKIP_WTMIC_: - ptxdesc->txdw1 |= cpu_to_le32((0x02 << 22) & - 0x00c00000); - break; - case _AES_: - ptxdesc->txdw1 |= cpu_to_le32((0x03 << 22) & - 0x00c00000); - break; - case _NO_PRIVACY_: - default: - break; - } - } - /*offset 8*/ - if (bmcst) - ptxdesc->txdw2 |= cpu_to_le32(BMC); - - /*offset 12*/ - /* f/w will increase the seqnum by itself, driver pass the - * correct priority to fw. - * fw will check the correct priority for increasing the - * seqnum per tid. about usb using 4-endpoint, qsel points out - * the correct mapping between AC&Endpoint, - * the purpose is that correct mapping lets the MAC release - * the AC Queue list correctly. - */ - ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) & - 0x0fff0000); - if ((pattrib->ether_type != 0x888e) && - (pattrib->ether_type != 0x0806) && - (pattrib->dhcp_pkt != 1)) { - /*Not EAP & ARP type data packet*/ - if (phtpriv->ht_option == 1) { /*B/G/N Mode*/ - if (!phtpriv->ampdu_enable) - ptxdesc->txdw2 |= cpu_to_le32(BK); - } - } else { - /* EAP data packet and ARP packet. - * Use the 1M data rate to send the EAP/ARP packet. - * This will maybe make the handshake smooth. - */ - /*driver uses data rate*/ - ptxdesc->txdw4 = cpu_to_le32(0x80000000); - ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/*1M*/ - } - if (pattrib->pctrl == 1) { /* mp tx packets */ - struct tx_desc *ptxdesc_mp; - - ptxdesc_mp = &txdesc_mp; - /* offset 8 */ - ptxdesc->txdw2 = ptxdesc_mp->txdw2; - if (bmcst) - ptxdesc->txdw2 |= cpu_to_le32(BMC); - ptxdesc->txdw2 |= cpu_to_le32(BK); - /* offset 16 */ - ptxdesc->txdw4 = ptxdesc_mp->txdw4; - /* offset 20 */ - ptxdesc->txdw5 = ptxdesc_mp->txdw5; - pattrib->pctrl = 0;/* reset to zero; */ - } - } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { - /* offset 4 */ - /* CAM_ID(MAC_ID), default=5; */ - ptxdesc->txdw1 |= cpu_to_le32((0x05) & 0x1f); - qsel = (uint)(pattrib->qsel & 0x0000001f); - ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); - ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/* Non-QoS */ - /* offset 8 */ - if (bmcst) - ptxdesc->txdw2 |= cpu_to_le32(BMC); - /* offset 12 */ - /* f/w will increase the seqnum by itself, driver pass the - * correct priority to fw. - * fw will check the correct priority for increasing the seqnum - * per tid. about usb using 4-endpoint, qsel points out the - * correct mapping between AC&Endpoint, - * the purpose is that correct mapping let the MAC releases - * the AC Queue list correctly. - */ - ptxdesc->txdw3 = cpu_to_le32((pattrib->priority << SEQ_SHT) & - 0x0fff0000); - /* offset 16 */ - ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/ - /* offset 20 */ - ptxdesc->txdw5 = cpu_to_le32(0x001f8000);/* gtest 1M */ - } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) { - /* offset 4 */ - qsel = 0x13; - ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); - } else { - /* offset 4 */ - qsel = (uint)(pattrib->priority & 0x0000001f); - ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); - /*offset 8*/ - /*offset 12*/ - ptxdesc->txdw3 = cpu_to_le32((pattrib->seqnum << SEQ_SHT) & - 0x0fff0000); - /*offset 16*/ - ptxdesc->txdw4 = cpu_to_le32(0x80002040);/*gtest*/ - /*offset 20*/ - ptxdesc->txdw5 = cpu_to_le32(0x001f9600);/*gtest*/ - } -} - -int r8712_xmitframe_complete(struct _adapter *padapter, - struct xmit_priv *pxmitpriv, - struct xmit_buf *pxmitbuf) -{ - struct hw_xmit *phwxmits; - sint hwentry; - struct xmit_frame *pxmitframe = NULL; -#ifdef CONFIG_R8712_TX_AGGR - struct xmit_frame *p2ndxmitframe = NULL; -#else - int res = _SUCCESS; -#endif - - phwxmits = pxmitpriv->hwxmits; - hwentry = pxmitpriv->hwxmit_entry; - if (!pxmitbuf) { - pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); - if (!pxmitbuf) - return false; -#ifdef CONFIG_R8712_TX_AGGR - pxmitbuf->aggr_nr = 0; -#endif - } - /* 1st frame dequeued */ - pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry); - /* need to remember the 1st frame */ - if (pxmitframe) { -#ifdef CONFIG_R8712_TX_AGGR - /* 1. dequeue 2nd frame - * 2. aggr if 2nd xframe is dequeued, else dump directly - */ - if (AGGR_NR_HIGH_BOUND > 1) - p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry); - if (pxmitframe->frame_tag != DATA_FRAMETAG) { - r8712_free_xmitbuf(pxmitpriv, pxmitbuf); - return false; - } - if (p2ndxmitframe) - if (p2ndxmitframe->frame_tag != DATA_FRAMETAG) { - r8712_free_xmitbuf(pxmitpriv, pxmitbuf); - return false; - } - r8712_xmitframe_aggr_1st(pxmitbuf, pxmitframe); - if (p2ndxmitframe) { - u16 total_length; - - total_length = r8712_xmitframe_aggr_next(pxmitbuf, p2ndxmitframe); - do { - p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry); - if (p2ndxmitframe) - total_length = - r8712_xmitframe_aggr_next(pxmitbuf, p2ndxmitframe); - else - break; - } while (total_length <= 0x1800 && - pxmitbuf->aggr_nr <= AGGR_NR_HIGH_BOUND); - } - if (pxmitbuf->aggr_nr > 0) - r8712_dump_aggr_xframe(pxmitbuf, pxmitframe); - -#else - - xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); - if (pxmitframe->frame_tag == DATA_FRAMETAG) { - if (pxmitframe->attrib.priority <= 15) - res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, - pxmitframe); - /* always return ndis_packet after - * r8712_xmitframe_coalesce - */ - r8712_xmit_complete(padapter, pxmitframe); - } - if (res == _SUCCESS) - dump_xframe(padapter, pxmitframe); - else - r8712_free_xmitframe_ex(pxmitpriv, pxmitframe); -#endif - - } else { /* pxmitframe == NULL && p2ndxmitframe == NULL */ - r8712_free_xmitbuf(pxmitpriv, pxmitbuf); - return false; - } - return true; -} - -static void dump_xframe(struct _adapter *padapter, - struct xmit_frame *pxmitframe) -{ - int t, sz, w_sz; - u8 *mem_addr; - u32 ff_hwaddr; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - - if (pxmitframe->attrib.ether_type != 0x0806) { - if (pxmitframe->attrib.ether_type != 0x888e) - r8712_issue_addbareq_cmd(padapter, pattrib->priority); - } - mem_addr = pxmitframe->buf_addr; - for (t = 0; t < pattrib->nr_frags; t++) { - if (t != (pattrib->nr_frags - 1)) { - sz = pxmitpriv->frag_len; - sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : - pattrib->icv_len); - pxmitframe->last[t] = 0; - } else { - sz = pattrib->last_txcmdsz; - pxmitframe->last[t] = 1; - } - update_txdesc(pxmitframe, (uint *)mem_addr, sz); - w_sz = sz + TXDESC_SIZE; - pxmitframe->mem_addr = mem_addr; - pxmitframe->bpending[t] = false; - ff_hwaddr = get_ff_hwaddr(pxmitframe); -#ifdef CONFIG_R8712_TX_AGGR - r8712_write_port(padapter, RTL8712_DMA_H2CCMD, w_sz, - (unsigned char *)pxmitframe); -#else - r8712_write_port(padapter, ff_hwaddr, w_sz, - (unsigned char *)pxmitframe); -#endif - mem_addr += w_sz; - mem_addr = (u8 *)RND4(((addr_t)(mem_addr))); - } -} - -void r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe) -{ - int res; - - res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); - pxmitframe->pkt = NULL; - if (res == _SUCCESS) - dump_xframe(padapter, pxmitframe); -} - -int r8712_xmit_enqueue(struct _adapter *padapter, struct xmit_frame *pxmitframe) -{ - if (r8712_xmit_classifier(padapter, pxmitframe)) { - pxmitframe->pkt = NULL; - return _FAIL; - } - return _SUCCESS; -} diff --git a/drivers/staging/rtl8712/rtl8712_xmit.h b/drivers/staging/rtl8712/rtl8712_xmit.h deleted file mode 100644 index 5cd651a0de75a9..00000000000000 --- a/drivers/staging/rtl8712/rtl8712_xmit.h +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL8712_XMIT_H_ -#define _RTL8712_XMIT_H_ - -#define HWXMIT_ENTRY 4 - -#define VO_QUEUE_INX 0 -#define VI_QUEUE_INX 1 -#define BE_QUEUE_INX 2 -#define BK_QUEUE_INX 3 -#define TS_QUEUE_INX 4 -#define MGT_QUEUE_INX 5 -#define BMC_QUEUE_INX 6 -#define BCN_QUEUE_INX 7 - -#define HW_QUEUE_ENTRY 8 - -#define TXDESC_SIZE 32 -#define TXDESC_OFFSET TXDESC_SIZE - -#define NR_AMSDU_XMITFRAME 8 -#define NR_TXAGG_XMITFRAME 8 - -#define MAX_AMSDU_XMITBUF_SZ 8704 -#define MAX_TXAGG_XMITBUF_SZ 16384 /*16k*/ - -#define tx_cmd tx_desc - -/* - *defined for TX DESC Operation - */ - -#define MAX_TID (15) - -/*OFFSET 0*/ -#define OFFSET_SZ (0) -#define OFFSET_SHT (16) -#define OWN BIT(31) -#define FSG BIT(27) -#define LSG BIT(26) -#define TYPE_SHT (24) -#define TYPE_MSK (0x03000000) - -/*OFFSET 4*/ -#define PKT_OFFSET_SZ (0) -#define QSEL_SHT (8) -#define HWPC BIT(31) - -/*OFFSET 8*/ -#define BMC BIT(7) -#define BK BIT(30) -#define AGG_EN BIT(29) -#define RTS_RC_SHT (16) - -/*OFFSET 12*/ -#define SEQ_SHT (16) - -/*OFFSET 16*/ -#define TXBW BIT(18) - -/*OFFSET 20*/ -#define DISFB BIT(15) -#define RSVD6_MSK (0x00E00000) -#define RSVD6_SHT (21) - -struct tx_desc { - /*DWORD 0*/ - __le32 txdw0; - __le32 txdw1; - __le32 txdw2; - __le32 txdw3; - __le32 txdw4; - __le32 txdw5; - __le32 txdw6; - __le32 txdw7; -}; - -union txdesc { - struct tx_desc txdesc; - unsigned int value[TXDESC_SIZE >> 2]; -}; - -int r8712_xmitframe_complete(struct _adapter *padapter, - struct xmit_priv *pxmitpriv, - struct xmit_buf *pxmitbuf); -void r8712_do_queue_select(struct _adapter *padapter, - struct pkt_attrib *pattrib); - -#ifdef CONFIG_R8712_TX_AGGR -void r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf, - struct xmit_frame *pxmitframe); -void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, - struct xmit_frame *pxmitframe); -#endif - -#endif diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c deleted file mode 100644 index ffeb91dd28c438..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_cmd.c +++ /dev/null @@ -1,750 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_cmd.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_CMD_C_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "recv_osdep.h" -#include "mlme_osdep.h" - -/* - * Caller and the r8712_cmd_thread can protect cmd_q by spin_lock. - * No irqsave is necessary. - */ - -int r8712_init_cmd_priv(struct cmd_priv *pcmdpriv) -{ - init_completion(&pcmdpriv->cmd_queue_comp); - init_completion(&pcmdpriv->terminate_cmdthread_comp); - - _init_queue(&(pcmdpriv->cmd_queue)); - - /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ - pcmdpriv->cmd_seq = 1; - pcmdpriv->cmd_allocated_buf = kmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ, - GFP_ATOMIC); - if (!pcmdpriv->cmd_allocated_buf) - return -ENOMEM; - pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - - ((addr_t)(pcmdpriv->cmd_allocated_buf) & - (CMDBUFF_ALIGN_SZ - 1)); - pcmdpriv->rsp_allocated_buf = kmalloc(MAX_RSPSZ + 4, GFP_ATOMIC); - if (!pcmdpriv->rsp_allocated_buf) { - kfree(pcmdpriv->cmd_allocated_buf); - pcmdpriv->cmd_allocated_buf = NULL; - return -ENOMEM; - } - pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - - ((addr_t)(pcmdpriv->rsp_allocated_buf) & 3); - pcmdpriv->cmd_issued_cnt = 0; - pcmdpriv->cmd_done_cnt = 0; - pcmdpriv->rsp_cnt = 0; - return 0; -} - -int r8712_init_evt_priv(struct evt_priv *pevtpriv) -{ - /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ - pevtpriv->event_seq = 0; - pevtpriv->evt_allocated_buf = kmalloc(MAX_EVTSZ + 4, GFP_ATOMIC); - - if (!pevtpriv->evt_allocated_buf) - return -ENOMEM; - pevtpriv->evt_buf = pevtpriv->evt_allocated_buf + 4 - - ((addr_t)(pevtpriv->evt_allocated_buf) & 3); - pevtpriv->evt_done_cnt = 0; - return 0; -} - -void r8712_free_evt_priv(struct evt_priv *pevtpriv) -{ - kfree(pevtpriv->evt_allocated_buf); -} - -void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv) -{ - if (pcmdpriv) { - kfree(pcmdpriv->cmd_allocated_buf); - kfree(pcmdpriv->rsp_allocated_buf); - } -} - -/* - * Calling Context: - * - * r8712_enqueue_cmd can only be called between kernel thread, - * since only spin_lock is used. - * - * ISR/Call-Back functions can't call this sub-function. - * - */ - -void r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj) -{ - struct __queue *queue; - unsigned long irqL; - - if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag) - return; - if (!obj) - return; - queue = &pcmdpriv->cmd_queue; - spin_lock_irqsave(&queue->lock, irqL); - list_add_tail(&obj->list, &queue->queue); - spin_unlock_irqrestore(&queue->lock, irqL); - complete(&pcmdpriv->cmd_queue_comp); -} - -struct cmd_obj *r8712_dequeue_cmd(struct __queue *queue) -{ - unsigned long irqL; - struct cmd_obj *obj; - - spin_lock_irqsave(&queue->lock, irqL); - obj = list_first_entry_or_null(&queue->queue, - struct cmd_obj, list); - if (obj) - list_del_init(&obj->list); - spin_unlock_irqrestore(&queue->lock, irqL); - return obj; -} - -void r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj) -{ - unsigned long irqL; - struct __queue *queue; - - if (!obj) - return; - if (pcmdpriv->padapter->eeprompriv.bautoload_fail_flag) - return; - queue = &pcmdpriv->cmd_queue; - spin_lock_irqsave(&queue->lock, irqL); - list_add_tail(&obj->list, &queue->queue); - spin_unlock_irqrestore(&queue->lock, irqL); - complete(&pcmdpriv->cmd_queue_comp); -} - -void r8712_free_cmd_obj(struct cmd_obj *pcmd) -{ - if ((pcmd->cmdcode != _JoinBss_CMD_) && - (pcmd->cmdcode != _CreateBss_CMD_)) - kfree(pcmd->parmbuf); - if (pcmd->rsp) { - if (pcmd->rspsz != 0) - kfree(pcmd->rsp); - } - kfree(pcmd); -} - -u8 r8712_sitesurvey_cmd(struct _adapter *padapter, - struct ndis_802_11_ssid *pssid) - __must_hold(&padapter->mlmepriv.lock) -{ - struct cmd_obj *ph2c; - struct sitesurvey_parm *psurveyPara; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return _FAIL; - psurveyPara = kmalloc(sizeof(*psurveyPara), GFP_ATOMIC); - if (!psurveyPara) { - kfree(ph2c); - return _FAIL; - } - init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, - GEN_CMD_CODE(_SiteSurvey)); - psurveyPara->bsslimit = cpu_to_le32(48); - psurveyPara->passive_mode = cpu_to_le32(pmlmepriv->passive_mode); - psurveyPara->ss_ssidlen = 0; - memset(psurveyPara->ss_ssid, 0, IW_ESSID_MAX_SIZE + 1); - if (pssid && pssid->SsidLength) { - int len = min_t(int, pssid->SsidLength, IW_ESSID_MAX_SIZE); - - memcpy(psurveyPara->ss_ssid, pssid->Ssid, len); - psurveyPara->ss_ssidlen = cpu_to_le32(len); - } - set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); - r8712_enqueue_cmd(pcmdpriv, ph2c); - mod_timer(&pmlmepriv->scan_to_timer, - jiffies + msecs_to_jiffies(SCANNING_TIMEOUT)); - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_SITE_SURVEY); - complete(&padapter->rx_filter_ready); - return _SUCCESS; -} - -int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset) -{ - struct cmd_obj *ph2c; - struct setdatarate_parm *pbsetdataratepara; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return -ENOMEM; - pbsetdataratepara = kmalloc(sizeof(*pbsetdataratepara), GFP_ATOMIC); - if (!pbsetdataratepara) { - kfree(ph2c); - return -ENOMEM; - } - init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, - GEN_CMD_CODE(_SetDataRate)); - pbsetdataratepara->mac_id = 5; - memcpy(pbsetdataratepara->datarates, rateset, NumRates); - r8712_enqueue_cmd(pcmdpriv, ph2c); - return 0; -} - -void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan) -{ - struct cmd_obj *ph2c; - struct SetChannelPlan_param *psetchplanpara; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return; - psetchplanpara = kmalloc(sizeof(*psetchplanpara), GFP_ATOMIC); - if (!psetchplanpara) { - kfree(ph2c); - return; - } - init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara, GEN_CMD_CODE(_SetChannelPlan)); - psetchplanpara->ChannelPlan = chplan; - r8712_enqueue_cmd(pcmdpriv, ph2c); -} - -int r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val) -{ - struct cmd_obj *ph2c; - struct writeRF_parm *pwriterfparm; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return -ENOMEM; - pwriterfparm = kmalloc(sizeof(*pwriterfparm), GFP_ATOMIC); - if (!pwriterfparm) { - kfree(ph2c); - return -ENOMEM; - } - init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg)); - pwriterfparm->offset = offset; - pwriterfparm->value = val; - r8712_enqueue_cmd(pcmdpriv, ph2c); - return 0; -} - -int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval) -{ - struct cmd_obj *ph2c; - struct readRF_parm *prdrfparm; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return -ENOMEM; - prdrfparm = kmalloc(sizeof(*prdrfparm), GFP_ATOMIC); - if (!prdrfparm) { - kfree(ph2c); - return -ENOMEM; - } - INIT_LIST_HEAD(&ph2c->list); - ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg); - ph2c->parmbuf = (unsigned char *)prdrfparm; - ph2c->cmdsz = sizeof(struct readRF_parm); - ph2c->rsp = pval; - ph2c->rspsz = sizeof(struct readRF_rsp); - prdrfparm->offset = offset; - r8712_enqueue_cmd(pcmdpriv, ph2c); - return 0; -} - -void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter, - struct cmd_obj *pcmd) -{ - kfree(pcmd->parmbuf); - kfree(pcmd); - padapter->mppriv.workparam.bcompleted = true; -} - -void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd) -{ - kfree(pcmd->parmbuf); - kfree(pcmd); - - padapter->mppriv.workparam.bcompleted = true; -} - -int r8712_createbss_cmd(struct _adapter *padapter) -{ - struct cmd_obj *pcmd; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct wlan_bssid_ex *pdev_network = - &padapter->registrypriv.dev_network; - - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK); - pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); - if (!pcmd) - return -ENOMEM; - INIT_LIST_HEAD(&pcmd->list); - pcmd->cmdcode = _CreateBss_CMD_; - pcmd->parmbuf = (unsigned char *)pdev_network; - pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(pdev_network); - pcmd->rsp = NULL; - pcmd->rspsz = 0; - /* notes: translate IELength & Length after assign to cmdsz; */ - pdev_network->Length = pcmd->cmdsz; - pdev_network->IELength = pdev_network->IELength; - pdev_network->Ssid.SsidLength = pdev_network->Ssid.SsidLength; - r8712_enqueue_cmd(pcmdpriv, pcmd); - return 0; -} - -int r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) -{ - struct wlan_bssid_ex *psecnetwork; - struct cmd_obj *pcmd; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct qos_priv *pqospriv = &pmlmepriv->qospriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct registry_priv *pregistrypriv = &padapter->registrypriv; - enum NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = - pnetwork->network.InfrastructureMode; - - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_START_TO_LINK); - pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); - if (!pcmd) - return -ENOMEM; - - /* for hidden ap to set fw_state here */ - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) != - true) { - switch (ndis_network_mode) { - case Ndis802_11IBSS: - pmlmepriv->fw_state |= WIFI_ADHOC_STATE; - break; - case Ndis802_11Infrastructure: - pmlmepriv->fw_state |= WIFI_STATION_STATE; - break; - case Ndis802_11APMode: - case Ndis802_11AutoUnknown: - case Ndis802_11InfrastructureMax: - break; - } - } - psecnetwork = &psecuritypriv->sec_bss; - memcpy(psecnetwork, &pnetwork->network, sizeof(*psecnetwork)); - psecuritypriv->authenticator_ie[0] = (unsigned char) - psecnetwork->IELength; - if ((psecnetwork->IELength - 12) < (256 - 1)) - memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], - psecnetwork->IELength - 12); - else - memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256 - 1)); - psecnetwork->IELength = 0; - /* - * If the driver wants to use the bssid to create the connection. - * If not, we copy the connecting AP's MAC address to it so that - * the driver just has the bssid information for PMKIDList searching. - */ - if (!pmlmepriv->assoc_by_bssid) - ether_addr_copy(&pmlmepriv->assoc_bssid[0], - &pnetwork->network.MacAddress[0]); - psecnetwork->IELength = r8712_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], - &psecnetwork->IEs[0], pnetwork->network.IELength); - pqospriv->qos_option = 0; - if (pregistrypriv->wmm_enable) { - u32 tmp_len; - - tmp_len = r8712_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], - &psecnetwork->IEs[0], pnetwork->network.IELength, - psecnetwork->IELength); - if (psecnetwork->IELength != tmp_len) { - psecnetwork->IELength = tmp_len; - pqospriv->qos_option = 1; /* WMM IE in beacon */ - } else { - pqospriv->qos_option = 0; /* no WMM IE in beacon */ - } - } - if (pregistrypriv->ht_enable) { - /* - * For WEP mode, we will use the bg mode to do the connection - * to avoid some IOT issues, especially for Realtek 8192u - * SoftAP. - */ - if ((padapter->securitypriv.PrivacyAlgrthm != _WEP40_) && - (padapter->securitypriv.PrivacyAlgrthm != _WEP104_)) { - /* restructure_ht_ie */ - r8712_restructure_ht_ie(padapter, - &pnetwork->network.IEs[0], - &psecnetwork->IEs[0], - pnetwork->network.IELength, - &psecnetwork->IELength); - } - } - psecuritypriv->supplicant_ie[0] = (u8)psecnetwork->IELength; - if (psecnetwork->IELength < 255) - memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], - psecnetwork->IELength); - else - memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], - 255); - /* get cmdsz before endian conversion */ - pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(psecnetwork); -#ifdef __BIG_ENDIAN - /* wlan_network endian conversion */ - psecnetwork->Length = cpu_to_le32(psecnetwork->Length); - psecnetwork->Ssid.SsidLength = cpu_to_le32(psecnetwork->Ssid.SsidLength); - psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy); - psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi); - psecnetwork->NetworkTypeInUse = cpu_to_le32(psecnetwork->NetworkTypeInUse); - psecnetwork->Configuration.ATIMWindow = cpu_to_le32(psecnetwork->Configuration.ATIMWindow); - psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(psecnetwork->Configuration.BeaconPeriod); - psecnetwork->Configuration.DSConfig = cpu_to_le32(psecnetwork->Configuration.DSConfig); - psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32(psecnetwork->Configuration.FHConfig.DwellTime); - psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopPattern); - psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopSet); - psecnetwork->Configuration.FHConfig.Length = cpu_to_le32(psecnetwork->Configuration.FHConfig.Length); - psecnetwork->Configuration.Length = cpu_to_le32(psecnetwork->Configuration.Length); - psecnetwork->InfrastructureMode = cpu_to_le32(psecnetwork->InfrastructureMode); - psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength); -#endif - INIT_LIST_HEAD(&pcmd->list); - pcmd->cmdcode = _JoinBss_CMD_; - pcmd->parmbuf = (unsigned char *)psecnetwork; - pcmd->rsp = NULL; - pcmd->rspsz = 0; - r8712_enqueue_cmd(pcmdpriv, pcmd); - return 0; -} - -void r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */ -{ - struct cmd_obj *pdisconnect_cmd; - struct disconnect_parm *pdisconnect; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - pdisconnect_cmd = kmalloc(sizeof(*pdisconnect_cmd), GFP_ATOMIC); - if (!pdisconnect_cmd) - return; - pdisconnect = kmalloc(sizeof(*pdisconnect), GFP_ATOMIC); - if (!pdisconnect) { - kfree(pdisconnect_cmd); - return; - } - init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect, _DisConnect_CMD_); - r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd); -} - -void r8712_setopmode_cmd(struct _adapter *padapter, - enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) -{ - struct cmd_obj *ph2c; - struct setopmode_parm *psetop; - - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return; - psetop = kmalloc(sizeof(*psetop), GFP_ATOMIC); - if (!psetop) { - kfree(ph2c); - return; - } - init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); - psetop->mode = (u8)networktype; - r8712_enqueue_cmd(pcmdpriv, ph2c); -} - -void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key) -{ - struct cmd_obj *ph2c; - struct set_stakey_parm *psetstakey_para; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct set_stakey_rsp *psetstakey_rsp = NULL; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct sta_info *sta = (struct sta_info *)psta; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return; - psetstakey_para = kmalloc(sizeof(*psetstakey_para), GFP_ATOMIC); - if (!psetstakey_para) { - kfree(ph2c); - return; - } - psetstakey_rsp = kmalloc(sizeof(*psetstakey_rsp), GFP_ATOMIC); - if (!psetstakey_rsp) { - kfree(ph2c); - kfree(psetstakey_para); - return; - } - init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); - ph2c->rsp = (u8 *)psetstakey_rsp; - ph2c->rspsz = sizeof(struct set_stakey_rsp); - ether_addr_copy(psetstakey_para->addr, sta->hwaddr); - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) - psetstakey_para->algorithm = (unsigned char) - psecuritypriv->PrivacyAlgrthm; - else - GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false); - if (unicast_key) - memcpy(&psetstakey_para->key, &sta->x_UncstKey, 16); - else - memcpy(&psetstakey_para->key, - &psecuritypriv->XGrpKey[psecuritypriv->XGrpKeyid - 1].skey, - 16); - r8712_enqueue_cmd(pcmdpriv, ph2c); -} - -void r8712_setMacAddr_cmd(struct _adapter *padapter, const u8 *mac_addr) -{ - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct cmd_obj *ph2c; - struct SetMacAddr_param *psetMacAddr_para; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return; - psetMacAddr_para = kmalloc(sizeof(*psetMacAddr_para), GFP_ATOMIC); - if (!psetMacAddr_para) { - kfree(ph2c); - return; - } - init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para, _SetMacAddress_CMD_); - ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr); - r8712_enqueue_cmd(pcmdpriv, ph2c); -} - -void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid) -{ - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - struct cmd_obj *ph2c; - struct addBaReq_parm *paddbareq_parm; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return; - paddbareq_parm = kmalloc(sizeof(*paddbareq_parm), GFP_ATOMIC); - if (!paddbareq_parm) { - kfree(ph2c); - return; - } - paddbareq_parm->tid = tid; - init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq)); - r8712_enqueue_cmd_ex(pcmdpriv, ph2c); -} - -void r8712_wdg_wk_cmd(struct _adapter *padapter) -{ - struct cmd_obj *ph2c; - struct drvint_cmd_parm *pdrvintcmd_param; - struct cmd_priv *pcmdpriv = &padapter->cmdpriv; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return; - pdrvintcmd_param = kmalloc(sizeof(*pdrvintcmd_param), GFP_ATOMIC); - if (!pdrvintcmd_param) { - kfree(ph2c); - return; - } - pdrvintcmd_param->i_cid = WDG_WK_CID; - pdrvintcmd_param->sz = 0; - pdrvintcmd_param->pbuf = NULL; - init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvintcmd_param, _DRV_INT_CMD_); - r8712_enqueue_cmd_ex(pcmdpriv, ph2c); -} - -void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if (pcmd->res != H2C_SUCCESS) - clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY); - r8712_free_cmd_obj(pcmd); -} - -void r8712_disassoc_cmd_callback(struct _adapter *padapter, - struct cmd_obj *pcmd) -{ - unsigned long irqL; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if (pcmd->res != H2C_SUCCESS) { - spin_lock_irqsave(&pmlmepriv->lock, irqL); - set_fwstate(pmlmepriv, _FW_LINKED); - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - return; - } - r8712_free_cmd_obj(pcmd); -} - -void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if (pcmd->res != H2C_SUCCESS) - mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(1)); - r8712_free_cmd_obj(pcmd); -} - -void r8712_createbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd) -{ - unsigned long irqL; - struct sta_info *psta = NULL; - struct wlan_network *pwlan = NULL; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf; - struct wlan_network *tgt_network = &(pmlmepriv->cur_network); - - if (pcmd->res != H2C_SUCCESS) - mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(1)); - del_timer(&pmlmepriv->assoc_timer); -#ifdef __BIG_ENDIAN - /* endian_convert */ - pnetwork->Length = le32_to_cpu(pnetwork->Length); - pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength); - pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy); - pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi); - pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse); - pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork->Configuration.ATIMWindow); - pnetwork->Configuration.DSConfig = le32_to_cpu(pnetwork->Configuration.DSConfig); - pnetwork->Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime); - pnetwork->Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern); - pnetwork->Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet); - pnetwork->Configuration.FHConfig.Length = le32_to_cpu(pnetwork->Configuration.FHConfig.Length); - pnetwork->Configuration.Length = le32_to_cpu(pnetwork->Configuration.Length); - pnetwork->InfrastructureMode = le32_to_cpu(pnetwork->InfrastructureMode); - pnetwork->IELength = le32_to_cpu(pnetwork->IELength); -#endif - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if ((pmlmepriv->fw_state) & WIFI_AP_STATE) { - psta = r8712_get_stainfo(&padapter->stapriv, pnetwork->MacAddress); - if (!psta) { - psta = r8712_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress); - if (!psta) - goto createbss_cmd_fail; - } - r8712_indicate_connect(padapter); - } else { - pwlan = _r8712_alloc_network(pmlmepriv); - if (!pwlan) { - pwlan = r8712_get_oldest_wlan_network(&pmlmepriv->scanned_queue); - if (!pwlan) - goto createbss_cmd_fail; - pwlan->last_scanned = jiffies; - } else { - list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); - } - pnetwork->Length = r8712_get_wlan_bssid_ex_sz(pnetwork); - memcpy(&(pwlan->network), pnetwork, pnetwork->Length); - pwlan->fixed = true; - memcpy(&tgt_network->network, pnetwork, (r8712_get_wlan_bssid_ex_sz(pnetwork))); - if (pmlmepriv->fw_state & _FW_UNDER_LINKING) - pmlmepriv->fw_state ^= _FW_UNDER_LINKING; - /* - * we will set _FW_LINKED when there is one more sat to - * join us (stassoc_event_callback) - */ - } -createbss_cmd_fail: - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - r8712_free_cmd_obj(pcmd); -} - -void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd) -{ - struct sta_priv *pstapriv = &padapter->stapriv; - struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *) (pcmd->rsp); - struct sta_info *psta = r8712_get_stainfo(pstapriv, psetstakey_rsp->addr); - - if (!psta) - goto exit; - psta->aid = psta->mac_id = psetstakey_rsp->keyid; /*CAM_ID(CAM_ENTRY)*/ -exit: - r8712_free_cmd_obj(pcmd); -} - -void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter, - struct cmd_obj *pcmd) -{ - unsigned long irqL; - struct sta_priv *pstapriv = &padapter->stapriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf); - struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *) (pcmd->rsp); - struct sta_info *psta = r8712_get_stainfo(pstapriv, passocsta_parm->addr); - - if (!psta) - return; - psta->aid = psta->mac_id = passocsta_rsp->cam_id; - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if ((check_fwstate(pmlmepriv, WIFI_MP_STATE)) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) - pmlmepriv->fw_state ^= _FW_UNDER_LINKING; - set_fwstate(pmlmepriv, _FW_LINKED); - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - r8712_free_cmd_obj(pcmd); -} - -void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl, u32 tryPktCnt, - u32 tryPktInterval, u32 firstStageTO) -{ - struct cmd_obj *ph2c; - struct DisconnectCtrlEx_param *param; - struct cmd_priv *pcmdpriv = &adapter->cmdpriv; - - ph2c = kmalloc(sizeof(*ph2c), GFP_ATOMIC); - if (!ph2c) - return; - param = kzalloc(sizeof(*param), GFP_ATOMIC); - if (!param) { - kfree(ph2c); - return; - } - - param->EnableDrvCtrl = (unsigned char)enableDrvCtrl; - param->TryPktCnt = (unsigned char)tryPktCnt; - param->TryPktInterval = (unsigned char)tryPktInterval; - param->FirstStageTO = (unsigned int)firstStageTO; - - init_h2fwcmd_w_parm_no_rsp(ph2c, param, GEN_CMD_CODE(_DisconnectCtrlEx)); - r8712_enqueue_cmd(pcmdpriv, ph2c); -} diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h deleted file mode 100644 index 268844af57f006..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_cmd.h +++ /dev/null @@ -1,750 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL871X_CMD_H_ -#define __RTL871X_CMD_H_ - -#include "wlan_bssdef.h" -#include "rtl871x_rf.h" -#define C2H_MEM_SZ (16*1024) - -#include "osdep_service.h" -#include "ieee80211.h" - -#define FREE_CMDOBJ_SZ 128 -#define MAX_CMDSZ 512 -#define MAX_RSPSZ 512 -#define MAX_EVTSZ 1024 -#define CMDBUFF_ALIGN_SZ 512 - -struct cmd_obj { - u16 cmdcode; - u8 res; - u8 *parmbuf; - u32 cmdsz; - u8 *rsp; - u32 rspsz; - struct list_head list; -}; - -struct cmd_priv { - struct completion cmd_queue_comp; - struct completion terminate_cmdthread_comp; - struct __queue cmd_queue; - u8 cmd_seq; - u8 *cmd_buf; /*shall be non-paged, and 4 bytes aligned*/ - u8 *cmd_allocated_buf; - u8 *rsp_buf; /*shall be non-paged, and 4 bytes aligned*/ - u8 *rsp_allocated_buf; - u32 cmd_issued_cnt; - u32 cmd_done_cnt; - u32 rsp_cnt; - struct _adapter *padapter; -}; - -struct evt_obj { - u16 evtcode; - u8 res; - u8 *parmbuf; - u32 evtsz; - struct list_head list; -}; - -struct evt_priv { - struct __queue evt_queue; - u8 event_seq; - u8 *evt_buf; /*shall be non-paged, and 4 bytes aligned*/ - u8 *evt_allocated_buf; - u32 evt_done_cnt; -}; - -#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \ -do {\ - INIT_LIST_HEAD(&pcmd->list);\ - pcmd->cmdcode = code;\ - pcmd->parmbuf = (u8 *)(pparm);\ - pcmd->cmdsz = sizeof(*pparm);\ - pcmd->rsp = NULL;\ - pcmd->rspsz = 0;\ -} while (0) - -void r8712_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); -void r8712_enqueue_cmd_ex(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); -struct cmd_obj *r8712_dequeue_cmd(struct __queue *queue); -void r8712_free_cmd_obj(struct cmd_obj *pcmd); -int r8712_cmd_thread(void *context); -int r8712_init_cmd_priv(struct cmd_priv *pcmdpriv); -void r8712_free_cmd_priv(struct cmd_priv *pcmdpriv); -int r8712_init_evt_priv(struct evt_priv *pevtpriv); -void r8712_free_evt_priv(struct evt_priv *pevtpriv); - -enum rtl871x_drvint_cid { - NONE_WK_CID, - WDG_WK_CID, - MAX_WK_CID -}; - -enum RFINTFS { - SWSI, - HWSI, - HWPI, -}; - -/* - * Caller Mode: Infra, Ad-HoC(C) - * Notes: To enter USB suspend mode - * Command Mode - */ -struct usb_suspend_parm { - u32 action; /* 1: sleep, 0:resume */ -}; - -/* - * Caller Mode: Infra, Ad-HoC(C) - * Notes: To disconnect the current associated BSS - * Command Mode - */ -struct disconnect_parm { - u32 rsvd; -}; - -/* - * Caller Mode: AP, Ad-HoC, Infra - * Notes: To set the NIC mode of RTL8711 - * Command Mode - * The definition of mode: - * - * #define IW_MODE_AUTO 0 // Let the driver decides which AP to join - * #define IW_MODE_ADHOC 1 // Single cell network (Ad-Hoc Clients) - * #define IW_MODE_INFRA 2 // Multi cell network, roaming, .. - * #define IW_MODE_MASTER 3 // Synchronisation master or AP - * #define IW_MODE_REPEAT 4 // Wireless Repeater (forwarder) - * #define IW_MODE_SECOND 5 // Secondary master/repeater (backup) - * #define IW_MODE_MONITOR 6 // Passive monitor (listen only) - */ -struct setopmode_parm { - u8 mode; - u8 rsvd[3]; -}; - -/* - * Caller Mode: AP, Ad-HoC, Infra - * Notes: To ask RTL8711 performing site-survey - * Command-Event Mode - */ -struct sitesurvey_parm { - __le32 passive_mode; /*active: 1, passive: 0 */ - __le32 bsslimit; /* 1 ~ 48 */ - __le32 ss_ssidlen; - u8 ss_ssid[IW_ESSID_MAX_SIZE + 1]; -}; - -/* - * Caller Mode: Any - * Notes: To set the auth type of RTL8711. open/shared/802.1x - * Command Mode - */ -struct setauth_parm { - u8 mode; /*0: legacy open, 1: legacy shared 2: 802.1x*/ - u8 _1x; /*0: PSK, 1: TLS*/ - u8 rsvd[2]; -}; - -/* - * Caller Mode: Infra - * a. algorithm: wep40, wep104, tkip & aes - * b. keytype: grp key/unicast key - * c. key contents - * - * when shared key ==> keyid is the camid - * when 802.1x ==> keyid [0:1] ==> grp key - * when 802.1x ==> keyid > 2 ==> unicast key - */ -struct setkey_parm { - u8 algorithm; /* encryption algorithm, could be none, wep40, - * TKIP, CCMP, wep104 - */ - u8 keyid; - u8 grpkey; /* 1: this is the grpkey for 802.1x. - * 0: this is the unicast key for 802.1x - */ - u8 key[16]; /* this could be 40 or 104 */ -}; - -/* - * When in AP or Ad-Hoc mode, this is used to - * allocate an sw/hw entry for a newly associated sta. - * Command - * when shared key ==> algorithm/keyid - */ -struct set_stakey_parm { - u8 addr[ETH_ALEN]; - u8 algorithm; - u8 key[16]; -}; - -struct set_stakey_rsp { - u8 addr[ETH_ALEN]; - u8 keyid; - u8 rsvd; -}; - -struct SetMacAddr_param { - u8 MacAddr[ETH_ALEN]; -}; - -/* - * Caller Ad-Hoc/AP - * - * Command -Rsp(AID == CAMID) mode - * - * This is to force fw to add an sta_data entry per driver's request. - * - * FW will write an cam entry associated with it. - * - */ -struct set_assocsta_parm { - u8 addr[ETH_ALEN]; -}; - -struct set_assocsta_rsp { - u8 cam_id; - u8 rsvd[3]; -}; - -/* - * Caller Ad-Hoc/AP - * - * Command mode - * - * This is to force fw to del an sta_data entry per driver's request - * - * FW will invalidate the cam entry associated with it. - * - */ -struct del_assocsta_parm { - u8 addr[ETH_ALEN]; -}; - -/* - * Caller Mode: AP/Ad-HoC(M) - * - * Notes: To notify fw that given staid has changed its power state - * - * Command Mode - * - */ -struct setstapwrstate_parm { - u8 staid; - u8 status; - u8 hwaddr[6]; -}; - -/* - * Caller Mode: Any - * - * Notes: To setup the basic rate of RTL8711 - * - * Command Mode - * - */ -struct setbasicrate_parm { - u8 basicrates[NumRates]; -}; - -/* - * Caller Mode: Any - * - * Notes: To read the current basic rate - * - * Command-Rsp Mode - * - */ -struct getbasicrate_parm { - u32 rsvd; -}; - -struct getbasicrate_rsp { - u8 basicrates[NumRates]; -}; - -/* - * Caller Mode: Any - * - * Notes: To setup the data rate of RTL8711 - * - * Command Mode - * - */ -struct setdatarate_parm { - u8 mac_id; - u8 datarates[NumRates]; -}; - -enum _RT_CHANNEL_DOMAIN { - RT_CHANNEL_DOMAIN_FCC = 0, - RT_CHANNEL_DOMAIN_IC = 1, - RT_CHANNEL_DOMAIN_ETSI = 2, - RT_CHANNEL_DOMAIN_SPAIN = 3, - RT_CHANNEL_DOMAIN_FRANCE = 4, - RT_CHANNEL_DOMAIN_MKK = 5, - RT_CHANNEL_DOMAIN_MKK1 = 6, - RT_CHANNEL_DOMAIN_ISRAEL = 7, - RT_CHANNEL_DOMAIN_TELEC = 8, - - /* Be compatible with old channel plan. No good! */ - RT_CHANNEL_DOMAIN_MIC = 9, - RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 10, - RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 11, - RT_CHANNEL_DOMAIN_TELEC_NETGEAR = 12, - - RT_CHANNEL_DOMAIN_NCC = 13, - RT_CHANNEL_DOMAIN_5G = 14, - RT_CHANNEL_DOMAIN_5G_40M = 15, - /*===== Add new channel plan above this line===============*/ - RT_CHANNEL_DOMAIN_MAX, -}; - -struct SetChannelPlan_param { - enum _RT_CHANNEL_DOMAIN ChannelPlan; -}; - -/* - * Caller Mode: Any - * - * Notes: To read the current data rate - * - * Command-Rsp Mode - * - */ -struct getdatarate_parm { - u32 rsvd; - -}; - -struct getdatarate_rsp { - u8 datarates[NumRates]; -}; - -/* - * Caller Mode: Any - * AP: AP can use the info for the contents of beacon frame - * Infra: STA can use the info when sitesurveying - * Ad-HoC(M): Like AP - * Ad-HoC(C): Like STA - * - * - * Notes: To set the phy capability of the NIC - * - * Command Mode - * - */ - -/* - * Caller Mode: Any - * - * Notes: To set the channel/modem/band - * This command will be used when channel/modem/band is changed. - * - * Command Mode - * - */ -/* - * Caller Mode: Any - * - * Notes: To get the current setting of channel/modem/band - * - * Command-Rsp Mode - * - */ -struct getphy_rsp { - u8 rfchannel; - u8 modem; -}; - -struct readBB_parm { - u8 offset; -}; - -struct readBB_rsp { - u8 value; -}; - -struct readTSSI_parm { - u8 offset; -}; - -struct readTSSI_rsp { - u8 value; -}; - -struct writeBB_parm { - u8 offset; - u8 value; -}; - -struct writePTM_parm { - u8 type; -}; - -struct readRF_parm { - u8 offset; -}; - -struct readRF_rsp { - u32 value; -}; - -struct writeRF_parm { - u32 offset; - u32 value; -}; - -struct setrfintfs_parm { - u8 rfintfs; -}; - -struct getrfintfs_parm { - u8 rfintfs; -}; - -/* - * Notes: This command is used for H2C/C2H loopback testing - * - * mac[0] == 0 - * ==> CMD mode, return H2C_SUCCESS. - * The following condition must be true under CMD mode - * mac[1] == mac[4], mac[2] == mac[3], mac[0]=mac[5]= 0; - * s0 == 0x1234, s1 == 0xabcd, w0 == 0x78563412, w1 == 0x5aa5def7; - * s2 == (b1 << 8 | b0); - * - * mac[0] == 1 - * ==> CMD_RSP mode, return H2C_SUCCESS_RSP - * - * The rsp layout shall be: - * rsp: parm: - * mac[0] = mac[5]; - * mac[1] = mac[4]; - * mac[2] = mac[3]; - * mac[3] = mac[2]; - * mac[4] = mac[1]; - * mac[5] = mac[0]; - * s0 = s1; - * s1 = swap16(s0); - * w0 = swap32(w1); - * b0 = b1 - * s2 = s0 + s1 - * b1 = b0 - * w1 = w0 - * - * mac[0] == 2 - * ==> CMD_EVENT mode, return H2C_SUCCESS - * The event layout shall be: - * event: parm: - * mac[0] = mac[5]; - * mac[1] = mac[4]; - * mac[2] = event's sequence number, starting from 1 to parm's marc[3] - * mac[3] = mac[2]; - * mac[4] = mac[1]; - * mac[5] = mac[0]; - * s0 = swap16(s0) - event.mac[2]; - * s1 = s1 + event.mac[2]; - * w0 = swap32(w0); - * b0 = b1 - * s2 = s0 + event.mac[2] - * b1 = b0 - * w1 = swap32(w1) - event.mac[2]; - * - * parm->mac[3] is the total event counts that host requested. - * - * - * event will be the same with the cmd's param. - * - */ - -/* CMD param Formart for DRV INTERNAL CMD HDL*/ -struct drvint_cmd_parm { - int i_cid; /*internal cmd id*/ - int sz; /* buf sz*/ - unsigned char *pbuf; -}; - -/*------------------- Below are used for RF/BB tuning ---------------------*/ - -struct setantenna_parm { - u8 tx_antset; - u8 rx_antset; - u8 tx_antenna; - u8 rx_antenna; -}; - -struct enrateadaptive_parm { - u32 en; -}; - -struct settxagctbl_parm { - u32 txagc[MAX_RATES_LENGTH]; -}; - -struct gettxagctbl_parm { - u32 rsvd; -}; - -struct gettxagctbl_rsp { - u32 txagc[MAX_RATES_LENGTH]; -}; - -struct setagcctrl_parm { - u32 agcctrl; /* 0: pure hw, 1: fw */ -}; - -struct setssup_parm { - u32 ss_ForceUp[MAX_RATES_LENGTH]; -}; - -struct getssup_parm { - u32 rsvd; -}; - -struct getssup_rsp { - u8 ss_ForceUp[MAX_RATES_LENGTH]; -}; - -struct setssdlevel_parm { - u8 ss_DLevel[MAX_RATES_LENGTH]; -}; - -struct getssdlevel_parm { - u32 rsvd; -}; - -struct getssdlevel_rsp { - u8 ss_DLevel[MAX_RATES_LENGTH]; -}; - -struct setssulevel_parm { - u8 ss_ULevel[MAX_RATES_LENGTH]; -}; - -struct getssulevel_parm { - u32 rsvd; -}; - -struct getssulevel_rsp { - u8 ss_ULevel[MAX_RATES_LENGTH]; -}; - -struct setcountjudge_parm { - u8 count_judge[MAX_RATES_LENGTH]; -}; - -struct getcountjudge_parm { - u32 rsvd; -}; - -struct getcountjudge_rsp { - u8 count_judge[MAX_RATES_LENGTH]; -}; - -struct setpwrmode_parm { - u8 mode; - u8 flag_low_traffic_en; - u8 flag_lpnav_en; - u8 flag_rf_low_snr_en; - u8 flag_dps_en; /* 1: dps, 0: 32k */ - u8 bcn_rx_en; - u8 bcn_pass_cnt; /* fw report one beacon information to - * driver when it receives bcn_pass_cnt - * beacons. - */ - u8 bcn_to; /* beacon TO (ms). ¡§=0¡¨ no limit.*/ - u16 bcn_itv; - u8 app_itv; /* only for VOIP mode. */ - u8 awake_bcn_itv; - u8 smart_ps; - u8 bcn_pass_time; /* unit: 100ms */ -}; - -struct setatim_parm { - u8 op; /*0: add, 1:del*/ - u8 txid; /* id of dest station.*/ -}; - -struct setratable_parm { - u8 ss_ForceUp[NumRates]; - u8 ss_ULevel[NumRates]; - u8 ss_DLevel[NumRates]; - u8 count_judge[NumRates]; -}; - -struct getratable_parm { - uint rsvd; -}; - -struct getratable_rsp { - u8 ss_ForceUp[NumRates]; - u8 ss_ULevel[NumRates]; - u8 ss_DLevel[NumRates]; - u8 count_judge[NumRates]; -}; - -/*to get TX,RX retry count*/ -struct gettxretrycnt_parm { - unsigned int rsvd; -}; - -struct gettxretrycnt_rsp { - unsigned long tx_retrycnt; -}; - -struct getrxretrycnt_parm { - unsigned int rsvd; -}; - -struct getrxretrycnt_rsp { - unsigned long rx_retrycnt; -}; - -/*to get BCNOK,BCNERR count*/ -struct getbcnokcnt_parm { - unsigned int rsvd; -}; - -struct getbcnokcnt_rsp { - unsigned long bcnokcnt; -}; - -struct getbcnerrcnt_parm { - unsigned int rsvd; -}; - -struct getbcnerrcnt_rsp { - unsigned long bcnerrcnt; -}; - -/* to get current TX power level*/ -struct getcurtxpwrlevel_parm { - unsigned int rsvd; -}; - -struct getcurtxpwrlevel_rsp { - unsigned short tx_power; -}; - -/*dynamic on/off DIG*/ -struct setdig_parm { - unsigned char dig_on; /* 1:on , 0:off */ -}; - -/*dynamic on/off RA*/ -struct setra_parm { - unsigned char ra_on; /* 1:on , 0:off */ -}; - -struct setprobereqextraie_parm { - unsigned char e_id; - unsigned char ie_len; - unsigned char ie[]; -}; - -struct setassocreqextraie_parm { - unsigned char e_id; - unsigned char ie_len; - unsigned char ie[]; -}; - -struct setproberspextraie_parm { - unsigned char e_id; - unsigned char ie_len; - unsigned char ie[]; -}; - -struct setassocrspextraie_parm { - unsigned char e_id; - unsigned char ie_len; - unsigned char ie[]; -}; - -struct addBaReq_parm { - unsigned int tid; -}; - -/*H2C Handler index: 46 */ -struct SetChannel_parm { - u32 curr_ch; -}; - -/*H2C Handler index: 61 */ -struct DisconnectCtrlEx_param { - /* MAXTIME = (2 * FirstStageTO) + (TryPktCnt * TryPktInterval) */ - unsigned char EnableDrvCtrl; - unsigned char TryPktCnt; - unsigned char TryPktInterval; /* Unit: ms */ - unsigned char rsvd; - unsigned int FirstStageTO; /* Unit: ms */ -}; - -#define GEN_CMD_CODE(cmd) cmd ## _CMD_ - -/* - * Result: - * 0x00: success - * 0x01: success, and check Response. - * 0x02: cmd ignored due to duplicated sequence number - * 0x03: cmd dropped due to invalid cmd code - * 0x04: reserved. - */ - -#define H2C_RSP_OFFSET 512 -#define H2C_SUCCESS 0x00 -#define H2C_SUCCESS_RSP 0x01 -#define H2C_DUPLICATED 0x02 -#define H2C_DROPPED 0x03 -#define H2C_PARAMETERS_ERROR 0x04 -#define H2C_REJECTED 0x05 -#define H2C_CMD_OVERFLOW 0x06 -#define H2C_RESERVED 0x07 - -void r8712_setMacAddr_cmd(struct _adapter *padapter, const u8 *mac_addr); -u8 r8712_sitesurvey_cmd(struct _adapter *padapter, struct ndis_802_11_ssid *pssid); -int r8712_createbss_cmd(struct _adapter *padapter); -void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key); -int r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork); -void r8712_disassoc_cmd(struct _adapter *padapter); -void r8712_setopmode_cmd(struct _adapter *padapter, enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype); -int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset); -void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan); -int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval); -int r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val); -void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid); -void r8712_wdg_wk_cmd(struct _adapter *padapter); -void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd); -void r8712_disassoc_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd); -void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd); -void r8712_createbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd); -void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd); -void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd); -void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd); -void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd); -void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl, u32 tryPktCnt, - u32 tryPktInterval, u32 firstStageTO); - -struct _cmd_callback { - u32 cmd_code; - void (*callback)(struct _adapter *padapter, struct cmd_obj *cmd); -}; - -#include "rtl8712_cmd.h" - -#endif /* _CMD_H_ */ - diff --git a/drivers/staging/rtl8712/rtl871x_debug.h b/drivers/staging/rtl8712/rtl871x_debug.h deleted file mode 100644 index 69c631af2a2acf..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_debug.h +++ /dev/null @@ -1,130 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL871X_DEBUG_H__ -#define __RTL871X_DEBUG_H__ - -#include "osdep_service.h" -#include "drv_types.h" - -#define _drv_emerg_ 1 -#define _drv_alert_ 2 -#define _drv_crit_ 3 -#define _drv_err_ 4 -#define _drv_warning_ 5 -#define _drv_notice_ 6 -#define _drv_info_ 7 -#define _drv_dump_ 8 -#define _drv_debug_ 9 - -#define _module_rtl871x_xmit_c_ BIT(0) -#define _module_xmit_osdep_c_ BIT(1) -#define _module_rtl871x_recv_c_ BIT(2) -#define _module_recv_osdep_c_ BIT(3) -#define _module_rtl871x_mlme_c_ BIT(4) -#define _module_mlme_osdep_c_ BIT(5) -#define _module_rtl871x_sta_mgt_c_ BIT(6) -#define _module_rtl871x_cmd_c_ BIT(7) -#define _module_cmd_osdep_c_ BIT(8) -#define _module_rtl871x_io_c_ BIT(9) -#define _module_io_osdep_c_ BIT(10) -#define _module_os_intfs_c_ BIT(11) -#define _module_rtl871x_security_c_ BIT(12) -#define _module_rtl871x_eeprom_c_ BIT(13) -#define _module_hal_init_c_ BIT(14) -#define _module_hci_hal_init_c_ BIT(15) -#define _module_rtl871x_ioctl_c_ BIT(16) -#define _module_rtl871x_ioctl_set_c_ BIT(17) -#define _module_rtl871x_pwrctrl_c_ BIT(19) -#define _module_hci_intfs_c_ BIT(20) -#define _module_hci_ops_c_ BIT(21) -#define _module_osdep_service_c_ BIT(22) -#define _module_rtl871x_mp_ioctl_c_ BIT(23) -#define _module_hci_ops_os_c_ BIT(24) -#define _module_rtl871x_ioctl_os_c BIT(25) -#define _module_rtl8712_cmd_c_ BIT(26) -#define _module_rtl871x_mp_c_ BIT(27) -#define _module_rtl8712_xmit_c_ BIT(28) -#define _module_rtl8712_efuse_c_ BIT(29) -#define _module_rtl8712_recv_c_ BIT(30) -#define _module_rtl8712_led_c_ BIT(31) - -#undef _MODULE_DEFINE_ - -#if defined _RTL871X_XMIT_C_ - #define _MODULE_DEFINE_ _module_rtl871x_xmit_c_ -#elif defined _XMIT_OSDEP_C_ - #define _MODULE_DEFINE_ _module_xmit_osdep_c_ -#elif defined _RTL871X_RECV_C_ - #define _MODULE_DEFINE_ _module_rtl871x_recv_c_ -#elif defined _RECV_OSDEP_C_ - #define _MODULE_DEFINE_ _module_recv_osdep_c_ -#elif defined _RTL871X_MLME_C_ - #define _MODULE_DEFINE_ _module_rtl871x_mlme_c_ -#elif defined _MLME_OSDEP_C_ - #define _MODULE_DEFINE_ _module_mlme_osdep_c_ -#elif defined _RTL871X_STA_MGT_C_ - #define _MODULE_DEFINE_ _module_rtl871x_sta_mgt_c_ -#elif defined _RTL871X_CMD_C_ - #define _MODULE_DEFINE_ _module_rtl871x_cmd_c_ -#elif defined _CMD_OSDEP_C_ - #define _MODULE_DEFINE_ _module_cmd_osdep_c_ -#elif defined _RTL871X_IO_C_ - #define _MODULE_DEFINE_ _module_rtl871x_io_c_ -#elif defined _IO_OSDEP_C_ - #define _MODULE_DEFINE_ _module_io_osdep_c_ -#elif defined _OS_INTFS_C_ - #define _MODULE_DEFINE_ _module_os_intfs_c_ -#elif defined _RTL871X_SECURITY_C_ - #define _MODULE_DEFINE_ _module_rtl871x_security_c_ -#elif defined _RTL871X_EEPROM_C_ - #define _MODULE_DEFINE_ _module_rtl871x_eeprom_c_ -#elif defined _HAL_INIT_C_ - #define _MODULE_DEFINE_ _module_hal_init_c_ -#elif defined _HCI_HAL_INIT_C_ - #define _MODULE_DEFINE_ _module_hci_hal_init_c_ -#elif defined _RTL871X_IOCTL_C_ - #define _MODULE_DEFINE_ _module_rtl871x_ioctl_c_ -#elif defined _RTL871X_IOCTL_SET_C_ - #define _MODULE_DEFINE_ _module_rtl871x_ioctl_set_c_ -#elif defined _RTL871X_PWRCTRL_C_ - #define _MODULE_DEFINE_ _module_rtl871x_pwrctrl_c_ -#elif defined _HCI_INTF_C_ - #define _MODULE_DEFINE_ _module_hci_intfs_c_ -#elif defined _HCI_OPS_C_ - #define _MODULE_DEFINE_ _module_hci_ops_c_ -#elif defined _OSDEP_HCI_INTF_C_ - #define _MODULE_DEFINE_ _module_hci_intfs_c_ -#elif defined _OSDEP_SERVICE_C_ - #define _MODULE_DEFINE_ _module_osdep_service_c_ -#elif defined _RTL871X_MP_IOCTL_C_ - #define _MODULE_DEFINE_ _module_rtl871x_mp_ioctl_c_ -#elif defined _HCI_OPS_OS_C_ - #define _MODULE_DEFINE_ _module_hci_ops_os_c_ -#elif defined _RTL871X_IOCTL_LINUX_C_ - #define _MODULE_DEFINE_ _module_rtl871x_ioctl_os_c -#elif defined _RTL871X_MP_C_ - #define _MODULE_DEFINE_ _module_rtl871x_mp_c_ -#elif defined _RTL8712_CMD_C_ - #define _MODULE_DEFINE_ _module_rtl8712_cmd_c_ -#elif defined _RTL8712_XMIT_C_ - #define _MODULE_DEFINE_ _module_rtl8712_xmit_c_ -#elif defined _RTL8712_EFUSE_C_ - #define _MODULE_DEFINE_ _module_rtl8712_efuse_c_ -#elif defined _RTL8712_RECV_C_ - #define _MODULE_DEFINE_ _module_rtl8712_recv_c_ -#else - #undef _MODULE_DEFINE_ -#endif - -#endif /*__RTL871X_DEBUG_H__*/ diff --git a/drivers/staging/rtl8712/rtl871x_eeprom.c b/drivers/staging/rtl8712/rtl871x_eeprom.c deleted file mode 100644 index 221bf92e1b1c3f..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_eeprom.c +++ /dev/null @@ -1,220 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_eeprom.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_EEPROM_C_ - -#include "osdep_service.h" -#include "drv_types.h" - -static void up_clk(struct _adapter *padapter, u16 *x) -{ - *x = *x | _EESK; - r8712_write8(padapter, EE_9346CR, (u8)*x); - udelay(CLOCK_RATE); -} - -static void down_clk(struct _adapter *padapter, u16 *x) -{ - *x = *x & ~_EESK; - r8712_write8(padapter, EE_9346CR, (u8)*x); - udelay(CLOCK_RATE); -} - -static void shift_out_bits(struct _adapter *padapter, u16 data, u16 count) -{ - u16 x, mask; - - if (padapter->surprise_removed) - goto out; - mask = 0x01 << (count - 1); - x = r8712_read8(padapter, EE_9346CR); - x &= ~(_EEDO | _EEDI); - do { - x &= ~_EEDI; - if (data & mask) - x |= _EEDI; - if (padapter->surprise_removed) - goto out; - r8712_write8(padapter, EE_9346CR, (u8)x); - udelay(CLOCK_RATE); - up_clk(padapter, &x); - down_clk(padapter, &x); - mask >>= 1; - } while (mask); - if (padapter->surprise_removed) - goto out; - x &= ~_EEDI; - r8712_write8(padapter, EE_9346CR, (u8)x); -out:; -} - -static u16 shift_in_bits(struct _adapter *padapter) -{ - u16 x, d = 0, i; - - if (padapter->surprise_removed) - goto out; - x = r8712_read8(padapter, EE_9346CR); - x &= ~(_EEDO | _EEDI); - d = 0; - for (i = 0; i < 16; i++) { - d <<= 1; - up_clk(padapter, &x); - if (padapter->surprise_removed) - goto out; - x = r8712_read8(padapter, EE_9346CR); - x &= ~(_EEDI); - if (x & _EEDO) - d |= 1; - down_clk(padapter, &x); - } -out: - return d; -} - -static void standby(struct _adapter *padapter) -{ - u8 x; - - x = r8712_read8(padapter, EE_9346CR); - x &= ~(_EECS | _EESK); - r8712_write8(padapter, EE_9346CR, x); - udelay(CLOCK_RATE); - x |= _EECS; - r8712_write8(padapter, EE_9346CR, x); - udelay(CLOCK_RATE); -} - -static u16 wait_eeprom_cmd_done(struct _adapter *padapter) -{ - u8 x; - u16 i; - - standby(padapter); - for (i = 0; i < 200; i++) { - x = r8712_read8(padapter, EE_9346CR); - if (x & _EEDO) - return true; - udelay(CLOCK_RATE); - } - return false; -} - -static void eeprom_clean(struct _adapter *padapter) -{ - u16 x; - - if (padapter->surprise_removed) - return; - x = r8712_read8(padapter, EE_9346CR); - if (padapter->surprise_removed) - return; - x &= ~(_EECS | _EEDI); - r8712_write8(padapter, EE_9346CR, (u8)x); - if (padapter->surprise_removed) - return; - up_clk(padapter, &x); - if (padapter->surprise_removed) - return; - down_clk(padapter, &x); -} - -void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data) -{ - u8 x; - u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new; - - tmp8_ori = r8712_read8(padapter, 0x102502f1); - tmp8_new = tmp8_ori & 0xf7; - if (tmp8_ori != tmp8_new) - r8712_write8(padapter, 0x102502f1, tmp8_new); - tmp8_clk_ori = r8712_read8(padapter, 0x10250003); - tmp8_clk_new = tmp8_clk_ori | 0x20; - if (tmp8_clk_new != tmp8_clk_ori) - r8712_write8(padapter, 0x10250003, tmp8_clk_new); - x = r8712_read8(padapter, EE_9346CR); - x &= ~(_EEDI | _EEDO | _EESK | _EEM0); - x |= _EEM1 | _EECS; - r8712_write8(padapter, EE_9346CR, x); - shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5); - if (padapter->eeprom_address_size == 8) /*CF+ and SDIO*/ - shift_out_bits(padapter, 0, 6); - else /* USB */ - shift_out_bits(padapter, 0, 4); - standby(padapter); - /* Erase this particular word. Write the erase opcode and register - * number in that order. The opcode is 3bits in length; reg is 6 - * bits long. - */ - standby(padapter); - /* write the new word to the EEPROM - * send the write opcode the EEPORM - */ - shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3); - /* select which word in the EEPROM that we are writing to. */ - shift_out_bits(padapter, reg, padapter->eeprom_address_size); - /* write the data to the selected EEPROM word. */ - shift_out_bits(padapter, data, 16); - if (wait_eeprom_cmd_done(padapter)) { - standby(padapter); - shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5); - shift_out_bits(padapter, reg, 4); - eeprom_clean(padapter); - } - if (tmp8_clk_new != tmp8_clk_ori) - r8712_write8(padapter, 0x10250003, tmp8_clk_ori); - if (tmp8_new != tmp8_ori) - r8712_write8(padapter, 0x102502f1, tmp8_ori); -} - -u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg) /*ReadEEprom*/ -{ - u16 x; - u16 data = 0; - u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new; - - tmp8_ori = r8712_read8(padapter, 0x102502f1); - tmp8_new = tmp8_ori & 0xf7; - if (tmp8_ori != tmp8_new) - r8712_write8(padapter, 0x102502f1, tmp8_new); - tmp8_clk_ori = r8712_read8(padapter, 0x10250003); - tmp8_clk_new = tmp8_clk_ori | 0x20; - if (tmp8_clk_new != tmp8_clk_ori) - r8712_write8(padapter, 0x10250003, tmp8_clk_new); - if (padapter->surprise_removed) - goto out; - /* select EEPROM, reset bits, set _EECS */ - x = r8712_read8(padapter, EE_9346CR); - if (padapter->surprise_removed) - goto out; - x &= ~(_EEDI | _EEDO | _EESK | _EEM0); - x |= _EEM1 | _EECS; - r8712_write8(padapter, EE_9346CR, (unsigned char)x); - /* write the read opcode and register number in that order - * The opcode is 3bits in length, reg is 6 bits long - */ - shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); - shift_out_bits(padapter, reg, padapter->eeprom_address_size); - /* Now read the data (16 bits) in from the selected EEPROM word */ - data = shift_in_bits(padapter); - eeprom_clean(padapter); -out: - if (tmp8_clk_new != tmp8_clk_ori) - r8712_write8(padapter, 0x10250003, tmp8_clk_ori); - if (tmp8_new != tmp8_ori) - r8712_write8(padapter, 0x102502f1, tmp8_ori); - return data; -} diff --git a/drivers/staging/rtl8712/rtl871x_eeprom.h b/drivers/staging/rtl8712/rtl871x_eeprom.h deleted file mode 100644 index 7bdeb2aaa0259b..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_eeprom.h +++ /dev/null @@ -1,88 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - ******************************************************************************/ -#ifndef __RTL871X_EEPROM_H__ -#define __RTL871X_EEPROM_H__ - -#include "osdep_service.h" - -#define RTL8712_EEPROM_ID 0x8712 -#define EEPROM_MAX_SIZE 256 -#define CLOCK_RATE 50 /*100us*/ - -/*- EEPROM opcodes*/ -#define EEPROM_READ_OPCODE 06 -#define EEPROM_WRITE_OPCODE 05 -#define EEPROM_ERASE_OPCODE 07 -#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable*/ -#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable*/ - -#define EEPROM_CID_DEFAULT 0x0 -#define EEPROM_CID_ALPHA 0x1 -#define EEPROM_CID_Senao 0x3 -#define EEPROM_CID_NetCore 0x5 -#define EEPROM_CID_CAMEO 0X8 -#define EEPROM_CID_SITECOM 0x9 -#define EEPROM_CID_COREGA 0xB -#define EEPROM_CID_EDIMAX_BELKIN 0xC -#define EEPROM_CID_SERCOMM_BELKIN 0xE -#define EEPROM_CID_CAMEO1 0xF -#define EEPROM_CID_WNC_COREGA 0x12 -#define EEPROM_CID_CLEVO 0x13 -#define EEPROM_CID_WHQL 0xFE - -enum RT_CUSTOMER_ID { - RT_CID_DEFAULT = 0, - RT_CID_8187_ALPHA0 = 1, - RT_CID_8187_SERCOMM_PS = 2, - RT_CID_8187_HW_LED = 3, - RT_CID_8187_NETGEAR = 4, - RT_CID_WHQL = 5, - RT_CID_819x_CAMEO = 6, - RT_CID_819x_RUNTOP = 7, - RT_CID_819x_Senao = 8, - RT_CID_TOSHIBA = 9, - RT_CID_819x_Netcore = 10, - RT_CID_Nettronix = 11, - RT_CID_DLINK = 12, - RT_CID_PRONET = 13, - RT_CID_COREGA = 14, - RT_CID_819x_ALPHA = 15, - RT_CID_819x_Sitecom = 16, - RT_CID_CCX = 17, - RT_CID_819x_Lenovo = 18, - RT_CID_819x_QMI = 19, - RT_CID_819x_Edimax_Belkin = 20, - RT_CID_819x_Sercomm_Belkin = 21, - RT_CID_819x_CAMEO1 = 22, - RT_CID_819x_MSI = 23, - RT_CID_819x_Acer = 24, - RT_CID_819x_AzWave_ASUS = 25, - RT_CID_819x_AzWave = 26, - RT_CID_819x_WNC_COREGA = 27, - RT_CID_819x_CLEVO = 28, -}; - -struct eeprom_priv { - u8 bautoload_fail_flag; - u8 bempty; - u8 sys_config; - u8 mac_addr[6]; - u8 config0; - u16 channel_plan; - u8 country_string[3]; - u8 tx_power_b[15]; - u8 tx_power_g[15]; - u8 tx_power_a[201]; - u8 efuse_eeprom_data[EEPROM_MAX_SIZE]; - enum RT_CUSTOMER_ID CustomerID; -}; - -void r8712_eeprom_write16(struct _adapter *padapter, u16 reg, u16 data); -u16 r8712_eeprom_read16(struct _adapter *padapter, u16 reg); - -#endif /*__RTL871X_EEPROM_H__*/ - diff --git a/drivers/staging/rtl8712/rtl871x_event.h b/drivers/staging/rtl8712/rtl871x_event.h deleted file mode 100644 index 0cc780cf434180..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_event.h +++ /dev/null @@ -1,109 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL871x_EVENT_H_ -#define _RTL871x_EVENT_H_ - -#include "osdep_service.h" - -#include "wlan_bssdef.h" -#include -#include - -/* - * Used to report a bss has been scanned - */ -struct survey_event { - struct wlan_bssid_ex bss; -}; - -/* - * Used to report that the requested site survey has been done. - * bss_cnt indicates the number of bss that has been reported. - */ -struct surveydone_event { - unsigned int bss_cnt; - -}; - -/* - * Used to report the link result of joining the given bss - * join_res: - * -1: authentication fail - * -2: association fail - * > 0: TID - */ -struct joinbss_event { - struct wlan_network network; -}; - -/* - * Used to report a given STA has joinned the created BSS. - * It is used in AP/Ad-HoC(M) mode. - */ -struct stassoc_event { - unsigned char macaddr[6]; - unsigned char rsvd[2]; - __le32 cam_id; -}; - -struct stadel_event { - unsigned char macaddr[6]; - unsigned char rsvd[2]; -}; - -struct addba_event { - unsigned int tid; -}; - -#define GEN_EVT_CODE(event) event ## _EVT_ - -struct fwevent { - u32 parmsize; - void (*event_callback)(struct _adapter *dev, u8 *pbuf); -}; - -#define C2HEVENT_SZ 32 -struct event_node { - unsigned char *node; - unsigned char evt_code; - unsigned short evt_sz; - /*volatile*/ int *caller_ff_tail; - int caller_ff_sz; -}; - -struct c2hevent_queue { - /*volatile*/ int head; - /*volatile*/ int tail; - struct event_node nodes[C2HEVENT_SZ]; - unsigned char seq; -}; - -#define NETWORK_QUEUE_SZ 4 - -struct network_queue { - /*volatile*/ int head; - /*volatile*/ int tail; - struct wlan_bssid_ex networks[NETWORK_QUEUE_SZ]; -}; - -struct ADDBA_Req_Report_parm { - unsigned char MacAddress[ETH_ALEN]; - unsigned short StartSeqNum; - unsigned char tid; -}; - -#include "rtl8712_event.h" - -#endif /* _WLANEVENT_H_ */ - diff --git a/drivers/staging/rtl8712/rtl871x_ht.h b/drivers/staging/rtl8712/rtl871x_ht.h deleted file mode 100644 index ebd78665775dd0..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_ht.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL871X_HT_H_ -#define _RTL871X_HT_H_ - -#include "osdep_service.h" -#include "wifi.h" - -struct ht_priv { - unsigned int ht_option; - unsigned int ampdu_enable;/*for enable Tx A-MPDU*/ - unsigned char baddbareq_issued[16]; - unsigned int tx_amsdu_enable;/*for enable Tx A-MSDU */ - unsigned int tx_amdsu_maxlen; /* 1: 8k, 0:4k ; default:8k, for tx */ - unsigned int rx_ampdu_maxlen; /* for rx reordering ctrl win_sz, - * updated when join_callback. - */ - struct ieee80211_ht_cap ht_cap; -}; - -#endif /*_RTL871X_HT_H_ */ - diff --git a/drivers/staging/rtl8712/rtl871x_io.c b/drivers/staging/rtl8712/rtl871x_io.c deleted file mode 100644 index 20e080e284dd43..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_io.c +++ /dev/null @@ -1,147 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_io.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -/* - * - * The purpose of rtl871x_io.c - * - * a. provides the API - * b. provides the protocol engine - * c. provides the software interface between caller and the hardware interface - * - * For r8712u, both sync/async operations are provided. - * - * Only sync read/write_mem operations are provided. - * - */ - -#define _RTL871X_IO_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "rtl871x_io.h" -#include "osdep_intf.h" -#include "usb_ops.h" - -static uint _init_intf_hdl(struct _adapter *padapter, - struct intf_hdl *pintf_hdl) -{ - struct intf_priv *pintf_priv; - void (*set_intf_option)(u32 *poption) = NULL; - void (*set_intf_funs)(struct intf_hdl *pintf_hdl); - void (*set_intf_ops)(struct _io_ops *pops); - uint (*init_intf_priv)(struct intf_priv *pintfpriv); - - set_intf_option = &(r8712_usb_set_intf_option); - set_intf_funs = &(r8712_usb_set_intf_funs); - set_intf_ops = &r8712_usb_set_intf_ops; - init_intf_priv = &r8712_usb_init_intf_priv; - pintf_priv = kmalloc(sizeof(*pintf_priv), GFP_ATOMIC); - pintf_hdl->pintfpriv = pintf_priv; - if (!pintf_priv) - goto _init_intf_hdl_fail; - pintf_hdl->adapter = (u8 *)padapter; - set_intf_option(&pintf_hdl->intf_option); - set_intf_funs(pintf_hdl); - set_intf_ops(&pintf_hdl->io_ops); - pintf_priv->intf_dev = (u8 *)&padapter->dvobjpriv; - if (init_intf_priv(pintf_priv) == _FAIL) - goto _init_intf_hdl_fail; - return _SUCCESS; -_init_intf_hdl_fail: - kfree(pintf_priv); - return _FAIL; -} - -static void _unload_intf_hdl(struct intf_priv *pintfpriv) -{ - void (*unload_intf_priv)(struct intf_priv *pintfpriv); - - unload_intf_priv = &r8712_usb_unload_intf_priv; - unload_intf_priv(pintfpriv); - kfree(pintfpriv); -} - -static uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl) -{ - struct _adapter *adapter = (struct _adapter *)dev; - - pintfhdl->intf_option = 0; - pintfhdl->adapter = dev; - pintfhdl->intf_dev = (u8 *)&adapter->dvobjpriv; - if (!_init_intf_hdl(adapter, pintfhdl)) - goto register_intf_hdl_fail; - return _SUCCESS; -register_intf_hdl_fail: - return false; -} - -static void unregister_intf_hdl(struct intf_hdl *pintfhdl) -{ - _unload_intf_hdl(pintfhdl->pintfpriv); - memset((u8 *)pintfhdl, 0, sizeof(struct intf_hdl)); -} - -uint r8712_alloc_io_queue(struct _adapter *adapter) -{ - u32 i; - struct io_queue *pio_queue; - struct io_req *pio_req; - - pio_queue = kmalloc(sizeof(*pio_queue), GFP_ATOMIC); - if (!pio_queue) - goto alloc_io_queue_fail; - INIT_LIST_HEAD(&pio_queue->free_ioreqs); - INIT_LIST_HEAD(&pio_queue->processing); - INIT_LIST_HEAD(&pio_queue->pending); - spin_lock_init(&pio_queue->lock); - pio_queue->pallocated_free_ioreqs_buf = kzalloc(NUM_IOREQ * - (sizeof(struct io_req)) + 4, - GFP_ATOMIC); - if ((pio_queue->pallocated_free_ioreqs_buf) == NULL) - goto alloc_io_queue_fail; - pio_queue->free_ioreqs_buf = pio_queue->pallocated_free_ioreqs_buf + 4 - - ((addr_t)(pio_queue->pallocated_free_ioreqs_buf) - & 3); - pio_req = (struct io_req *)(pio_queue->free_ioreqs_buf); - for (i = 0; i < NUM_IOREQ; i++) { - INIT_LIST_HEAD(&pio_req->list); - list_add_tail(&pio_req->list, &pio_queue->free_ioreqs); - pio_req++; - } - if ((register_intf_hdl((u8 *)adapter, &pio_queue->intf)) == _FAIL) - goto alloc_io_queue_fail; - adapter->pio_queue = pio_queue; - return _SUCCESS; -alloc_io_queue_fail: - if (pio_queue) { - kfree(pio_queue->pallocated_free_ioreqs_buf); - kfree(pio_queue); - } - adapter->pio_queue = NULL; - return _FAIL; -} - -void r8712_free_io_queue(struct _adapter *adapter) -{ - struct io_queue *pio_queue = adapter->pio_queue; - - if (pio_queue) { - kfree(pio_queue->pallocated_free_ioreqs_buf); - adapter->pio_queue = NULL; - unregister_intf_hdl(&pio_queue->intf); - kfree(pio_queue); - } -} diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h deleted file mode 100644 index f09d50a29b82c6..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_io.h +++ /dev/null @@ -1,236 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL871X_IO_H_ -#define _RTL871X_IO_H_ - -#include "osdep_service.h" -#include "osdep_intf.h" - -#define NUM_IOREQ 8 - -#define MAX_PROT_SZ (64-16) - -#define _IOREADY 0 -#define _IO_WAIT_COMPLETE 1 -#define _IO_WAIT_RSP 2 - -/* IO COMMAND TYPE */ -#define _IOSZ_MASK_ (0x7F) -#define _IO_WRITE_ BIT(7) -#define _IO_FIXED_ BIT(8) -#define _IO_BURST_ BIT(9) -#define _IO_BYTE_ BIT(10) -#define _IO_HW_ BIT(11) -#define _IO_WORD_ BIT(12) -#define _IO_SYNC_ BIT(13) -#define _IO_CMDMASK_ (0x1F80) - -/* - * For prompt mode accessing, caller shall free io_req - * Otherwise, io_handler will free io_req - */ -/* IO STATUS TYPE */ -#define _IO_ERR_ BIT(2) -#define _IO_SUCCESS_ BIT(1) -#define _IO_DONE_ BIT(0) -#define IO_RD32 (_IO_SYNC_ | _IO_WORD_) -#define IO_RD16 (_IO_SYNC_ | _IO_HW_) -#define IO_RD8 (_IO_SYNC_ | _IO_BYTE_) -#define IO_RD32_ASYNC (_IO_WORD_) -#define IO_RD16_ASYNC (_IO_HW_) -#define IO_RD8_ASYNC (_IO_BYTE_) -#define IO_WR32 (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_) -#define IO_WR16 (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_) -#define IO_WR8 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_) -#define IO_WR32_ASYNC (_IO_WRITE_ | _IO_WORD_) -#define IO_WR16_ASYNC (_IO_WRITE_ | _IO_HW_) -#define IO_WR8_ASYNC (_IO_WRITE_ | _IO_BYTE_) -/* - * Only Sync. burst accessing is provided. - */ -#define IO_WR_BURST(x) (IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | \ - ((x) & _IOSZ_MASK_)) -#define IO_RD_BURST(x) (_IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_)) -/*below is for the intf_option bit definition...*/ -#define _INTF_ASYNC_ BIT(0) /*support async io*/ -struct intf_priv; -struct intf_hdl; -struct io_queue; -struct _io_ops { - uint (*_sdbus_read_bytes_to_membuf)(struct intf_priv *pintfpriv, - u32 addr, u32 cnt, u8 *pbuf); - uint (*_sdbus_read_blocks_to_membuf)(struct intf_priv *pintfpriv, - u32 addr, u32 cnt, u8 *pbuf); - u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); - u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); - u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); - uint (*_sdbus_write_blocks_from_membuf)(struct intf_priv *pintfpriv, - u32 addr, u32 cnt, u8 *pbuf, - u8 async); - uint (*_sdbus_write_bytes_from_membuf)(struct intf_priv *pintfpriv, - u32 addr, u32 cnt, u8 *pbuf); - u8 (*_cmd52r)(struct intf_priv *pintfpriv, u32 addr); - void (*_cmd52w)(struct intf_priv *pintfpriv, u32 addr, u8 val8); - u8 (*_cmdfunc152r)(struct intf_priv *pintfpriv, u32 addr); - void (*_cmdfunc152w)(struct intf_priv *pintfpriv, u32 addr, u8 val8); - void (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); - void (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); - void (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); - void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, - u8 *pmem); - void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, - u8 *pmem); - void (*_sync_irp_protocol_rw)(struct io_queue *pio_q); - u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, - u8 *pmem); - u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, - u8 *pmem); -}; - -struct io_req { - struct list_head list; - u32 addr; - /*volatile*/ u32 val; - u32 command; - u32 status; - u8 *pbuf; - void (*_async_io_callback)(struct _adapter *padapter, - struct io_req *pio_req, u8 *cnxt); - u8 *cnxt; -}; - -struct intf_hdl { - u32 intf_option; - u8 *adapter; - u8 *intf_dev; - struct intf_priv *pintfpriv; - void (*intf_hdl_init)(u8 *priv); - void (*intf_hdl_unload)(u8 *priv); - void (*intf_hdl_open)(u8 *priv); - void (*intf_hdl_close)(u8 *priv); - struct _io_ops io_ops; -}; - -struct reg_protocol_rd { -#ifdef __LITTLE_ENDIAN - /* DW1 */ - u32 NumOfTrans:4; - u32 Reserved1:4; - u32 Reserved2:24; - /* DW2 */ - u32 ByteCount:7; - u32 WriteEnable:1; /*0:read, 1:write*/ - u32 FixOrContinuous:1; /*0:continuous, 1: Fix*/ - u32 BurstMode:1; - u32 Byte1Access:1; - u32 Byte2Access:1; - u32 Byte4Access:1; - u32 Reserved3:3; - u32 Reserved4:16; - /*DW3*/ - u32 BusAddress; - /*DW4*/ -#else -/*DW1*/ - u32 Reserved1:4; - u32 NumOfTrans:4; - u32 Reserved2:24; - /*DW2*/ - u32 WriteEnable:1; - u32 ByteCount:7; - u32 Reserved3:3; - u32 Byte4Access:1; - u32 Byte2Access:1; - u32 Byte1Access:1; - u32 BurstMode:1; - u32 FixOrContinuous:1; - u32 Reserved4:16; - /*DW3*/ - u32 BusAddress; - /*DW4*/ -#endif -}; - -struct reg_protocol_wt { -#ifdef __LITTLE_ENDIAN - /*DW1*/ - u32 NumOfTrans:4; - u32 Reserved1:4; - u32 Reserved2:24; - /*DW2*/ - u32 ByteCount:7; - u32 WriteEnable:1; /*0:read, 1:write*/ - u32 FixOrContinuous:1; /*0:continuous, 1: Fix*/ - u32 BurstMode:1; - u32 Byte1Access:1; - u32 Byte2Access:1; - u32 Byte4Access:1; - u32 Reserved3:3; - u32 Reserved4:16; - /*DW3*/ - u32 BusAddress; - /*DW4*/ - u32 Value; -#else - /*DW1*/ - u32 Reserved1:4; - u32 NumOfTrans:4; - u32 Reserved2:24; - /*DW2*/ - u32 WriteEnable:1; - u32 ByteCount:7; - u32 Reserved3:3; - u32 Byte4Access:1; - u32 Byte2Access:1; - u32 Byte1Access:1; - u32 BurstMode:1; - u32 FixOrContinuous:1; - u32 Reserved4:16; - /*DW3*/ - u32 BusAddress; - /*DW4*/ - u32 Value; -#endif -}; - -/* - * Below is the data structure used by _io_handler - */ - -struct io_queue { - spinlock_t lock; - struct list_head free_ioreqs; - /*The io_req list that will be served in the single protocol r/w.*/ - struct list_head pending; - struct list_head processing; - u8 *free_ioreqs_buf; /* 4-byte aligned */ - u8 *pallocated_free_ioreqs_buf; - struct intf_hdl intf; -}; - -u8 r8712_read8(struct _adapter *adapter, u32 addr); -u16 r8712_read16(struct _adapter *adapter, u32 addr); -u32 r8712_read32(struct _adapter *adapter, u32 addr); -void r8712_read_mem(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem); -void r8712_read_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem); -void r8712_write8(struct _adapter *adapter, u32 addr, u8 val); -void r8712_write16(struct _adapter *adapter, u32 addr, u16 val); -void r8712_write32(struct _adapter *adapter, u32 addr, u32 val); -void r8712_write_mem(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem); -void r8712_write_port(struct _adapter *adapter, u32 addr, u32 cnt, u8 *pmem); -/*ioreq */ -uint r8712_alloc_io_queue(struct _adapter *adapter); -void r8712_free_io_queue(struct _adapter *adapter); - -#endif /*_RTL871X_IO_H_*/ diff --git a/drivers/staging/rtl8712/rtl871x_ioctl.h b/drivers/staging/rtl8712/rtl871x_ioctl.h deleted file mode 100644 index d6332a8c7f4f71..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_ioctl.h +++ /dev/null @@ -1,94 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __IOCTL_H -#define __IOCTL_H - -#include "osdep_service.h" -#include "drv_types.h" - -#ifndef OID_802_11_CAPABILITY - #define OID_802_11_CAPABILITY 0x0d010122 -#endif - -#ifndef OID_802_11_PMKID - #define OID_802_11_PMKID 0x0d010123 -#endif - -/* For DDK-defined OIDs*/ -#define OID_NDIS_SEG1 0x00010100 -#define OID_NDIS_SEG2 0x00010200 -#define OID_NDIS_SEG3 0x00020100 -#define OID_NDIS_SEG4 0x01010100 -#define OID_NDIS_SEG5 0x01020100 -#define OID_NDIS_SEG6 0x01020200 -#define OID_NDIS_SEG7 0xFD010100 -#define OID_NDIS_SEG8 0x0D010100 -#define OID_NDIS_SEG9 0x0D010200 -#define OID_NDIS_SEG10 0x0D020200 -#define SZ_OID_NDIS_SEG1 23 -#define SZ_OID_NDIS_SEG2 3 -#define SZ_OID_NDIS_SEG3 6 -#define SZ_OID_NDIS_SEG4 6 -#define SZ_OID_NDIS_SEG5 4 -#define SZ_OID_NDIS_SEG6 8 -#define SZ_OID_NDIS_SEG7 7 -#define SZ_OID_NDIS_SEG8 36 -#define SZ_OID_NDIS_SEG9 24 -#define SZ_OID_NDIS_SEG10 19 - -/* For Realtek-defined OIDs*/ -#define OID_MP_SEG1 0xFF871100 -#define OID_MP_SEG2 0xFF818000 -#define OID_MP_SEG3 0xFF818700 -#define OID_MP_SEG4 0xFF011100 - -enum oid_type { - QUERY_OID, - SET_OID -}; - -struct oid_funs_node { - unsigned int oid_start; /*the starting number for OID*/ - unsigned int oid_end; /*the ending number for OID*/ - struct oid_obj_priv *node_array; - unsigned int array_sz; /*the size of node_array*/ - int query_counter; /*count the number of query hits for this segment*/ - int set_counter; /*count the number of set hits for this segment*/ -}; - -struct oid_par_priv { - void *adapter_context; - uint oid; - void *information_buf; - unsigned long information_buf_len; - unsigned long *bytes_rw; - unsigned long *bytes_needed; - enum oid_type type_of_oid; - unsigned int dbg; -}; - -struct oid_obj_priv { - unsigned char dbg; /* 0: without OID debug message - * 1: with OID debug message - */ - uint (*oidfuns)(struct oid_par_priv *poid_par_priv); -}; - -uint oid_null_function(struct oid_par_priv *poid_par_priv); - -extern struct iw_handler_def r871x_handlers_def; - -uint drv_query_info(struct net_device *MiniportAdapterContext, - uint Oid, - void *InformationBuffer, - u32 InformationBufferLength, - u32 *BytesWritten, - u32 *BytesNeeded); - -uint drv_set_info(struct net_device *MiniportAdapterContext, - uint Oid, - void *InformationBuffer, - u32 InformationBufferLength, - u32 *BytesRead, - u32 *BytesNeeded); - -#endif diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c deleted file mode 100644 index 0653aa27b1fa29..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ /dev/null @@ -1,2275 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_ioctl_linux.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_IOCTL_LINUX_C_ -#define _RTL871X_MP_IOCTL_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "wlan_bssdef.h" -#include "rtl871x_debug.h" -#include "wifi.h" -#include "rtl871x_mlme.h" -#include "rtl871x_ioctl.h" -#include "rtl871x_ioctl_set.h" -#include "rtl871x_mp_ioctl.h" -#include "mlme_osdep.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 0x1E) - -#define SCAN_ITEM_SIZE 768 -#define MAX_CUSTOM_LEN 64 -#define RATE_COUNT 4 - -static const u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000, - 6000000, 9000000, 12000000, 18000000, - 24000000, 36000000, 48000000, 54000000}; - -static const long ieee80211_wlan_frequencies[] = { - 2412, 2417, 2422, 2427, - 2432, 2437, 2442, 2447, - 2452, 2457, 2462, 2467, - 2472, 2484 -}; - -void r8712_indicate_wx_assoc_event(struct _adapter *padapter) -{ - union iwreq_data wrqu; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN); - wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL); -} - -void r8712_indicate_wx_disassoc_event(struct _adapter *padapter) -{ - union iwreq_data wrqu; - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - eth_zero_addr(wrqu.ap_addr.sa_data); - wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL); -} - -static inline void handle_pairwise_key(struct sta_info *psta, - struct ieee_param *param, - struct _adapter *padapter) -{ - /* pairwise key */ - memcpy(psta->x_UncstKey.skey, param->u.crypt.key, - (param->u.crypt. key_len > 16 ? 16 : param->u.crypt.key_len)); - if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */ - memcpy(psta->tkiptxmickey. skey, - ¶m->u.crypt.key[16], 8); - memcpy(psta->tkiprxmickey. skey, - ¶m->u.crypt.key[24], 8); - padapter->securitypriv. busetkipkey = false; - mod_timer(&padapter->securitypriv.tkip_timer, - jiffies + msecs_to_jiffies(50)); - } - r8712_setstakey_cmd(padapter, (unsigned char *)psta, true); -} - -static inline void handle_group_key(struct ieee_param *param, - struct _adapter *padapter) -{ - union Keytype *gk = padapter->securitypriv.XGrpKey; - union Keytype *gtk = padapter->securitypriv.XGrptxmickey; - union Keytype *grk = padapter->securitypriv.XGrprxmickey; - - if (param->u.crypt.idx > 0 && - param->u.crypt.idx < 3) { - /* group key idx is 1 or 2 */ - memcpy(gk[param->u.crypt.idx - 1].skey, - param->u.crypt.key, - (param->u.crypt.key_len > 16 ? 16 : - param->u.crypt.key_len)); - memcpy(gtk[param->u.crypt.idx - 1].skey, - ¶m->u.crypt.key[16], 8); - memcpy(grk[param->u.crypt.idx - 1].skey, - ¶m->u.crypt.key[24], 8); - padapter->securitypriv.binstallGrpkey = true; - r8712_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx); - if (padapter->registrypriv.power_mgnt > PS_MODE_ACTIVE) { - if (padapter->registrypriv.power_mgnt != padapter->pwrctrlpriv.pwr_mode) - mod_timer(&padapter->mlmepriv.dhcp_timer, - jiffies + msecs_to_jiffies(60000)); - } - } -} - -static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info, - struct wlan_network *pnetwork, - struct iw_event *iwe, - char *start, char *stop) -{ - /* parsing WPA/WPA2 IE */ - u8 buf[MAX_WPA_IE_LEN]; - u8 wpa_ie[255], rsn_ie[255]; - u16 wpa_len = 0, rsn_len = 0; - int n, i; - - r8712_get_sec_ie(pnetwork->network.IEs, - pnetwork->network.IELength, rsn_ie, &rsn_len, - wpa_ie, &wpa_len); - if (wpa_len > 0) { - memset(buf, 0, MAX_WPA_IE_LEN); - n = sprintf(buf, "wpa_ie="); - for (i = 0; i < wpa_len; i++) { - n += scnprintf(buf + n, MAX_WPA_IE_LEN - n, - "%02x", wpa_ie[i]); - if (n == MAX_WPA_IE_LEN - 1) - break; - } - memset(iwe, 0, sizeof(*iwe)); - iwe->cmd = IWEVCUSTOM; - iwe->u.data.length = (u16)strlen(buf); - start = iwe_stream_add_point(info, start, stop, iwe, buf); - memset(iwe, 0, sizeof(*iwe)); - iwe->cmd = IWEVGENIE; - iwe->u.data.length = (u16)wpa_len; - start = iwe_stream_add_point(info, start, stop, iwe, wpa_ie); - } - if (rsn_len > 0) { - memset(buf, 0, MAX_WPA_IE_LEN); - n = sprintf(buf, "rsn_ie="); - for (i = 0; i < rsn_len; i++) { - n += scnprintf(buf + n, MAX_WPA_IE_LEN - n, - "%02x", rsn_ie[i]); - if (n == MAX_WPA_IE_LEN - 1) - break; - } - memset(iwe, 0, sizeof(*iwe)); - iwe->cmd = IWEVCUSTOM; - iwe->u.data.length = strlen(buf); - start = iwe_stream_add_point(info, start, stop, iwe, buf); - memset(iwe, 0, sizeof(*iwe)); - iwe->cmd = IWEVGENIE; - iwe->u.data.length = rsn_len; - start = iwe_stream_add_point(info, start, stop, iwe, rsn_ie); - } - - return start; -} - -static noinline_for_stack char *translate_scan_wps(struct iw_request_info *info, - struct wlan_network *pnetwork, - struct iw_event *iwe, - char *start, char *stop) -{ - /* parsing WPS IE */ - u8 wps_ie[512]; - uint wps_ielen; - - if (r8712_get_wps_ie(pnetwork->network.IEs, pnetwork->network.IELength, wps_ie, &wps_ielen)) { - if (wps_ielen > 2) { - iwe->cmd = IWEVGENIE; - iwe->u.data.length = (u16)wps_ielen; - start = iwe_stream_add_point(info, start, stop, iwe, wps_ie); - } - } - - return start; -} - -static char *translate_scan(struct _adapter *padapter, - struct iw_request_info *info, - struct wlan_network *pnetwork, - char *start, char *stop) -{ - struct iw_event iwe; - char *current_val; - s8 *p; - u32 i = 0, ht_ielen = 0; - u16 cap, ht_cap = false; - u8 rssi; - - if ((pnetwork->network.Configuration.DSConfig < 1) || - (pnetwork->network.Configuration.DSConfig > 14)) { - if (pnetwork->network.Configuration.DSConfig < 1) - pnetwork->network.Configuration.DSConfig = 1; - else - pnetwork->network.Configuration.DSConfig = 14; - } - /* AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - ether_addr_copy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress); - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); - /* Add the ESSID */ - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - iwe.u.data.length = min_t(u32, pnetwork->network.Ssid.SsidLength, 32); - start = iwe_stream_add_point(info, start, stop, &iwe, - pnetwork->network.Ssid.Ssid); - /* parsing HT_CAP_IE */ - p = r8712_get_ie(&pnetwork->network.IEs[12], WLAN_EID_HT_CAPABILITY, - &ht_ielen, pnetwork->network.IELength - 12); - if (p && ht_ielen > 0) - ht_cap = true; - /* Add the protocol name */ - iwe.cmd = SIOCGIWNAME; - if (r8712_is_cckratesonly_included(pnetwork->network.rates)) { - if (ht_cap) - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn"); - else - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); - } else if (r8712_is_cckrates_included(pnetwork->network.rates)) { - if (ht_cap) - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn"); - else - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg"); - } else { - if (ht_cap) - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn"); - else - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g"); - } - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs), 2); - le16_to_cpus(&cap); - if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_ESS)) { - if (cap & WLAN_CAPABILITY_ESS) - iwe.u.mode = (u32)IW_MODE_MASTER; - else - iwe.u.mode = (u32)IW_MODE_ADHOC; - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); - } - /* Add frequency/channel */ - iwe.cmd = SIOCGIWFREQ; - { - /* check legal index */ - u8 dsconfig = pnetwork->network.Configuration.DSConfig; - - if (dsconfig >= 1 && dsconfig <= sizeof(ieee80211_wlan_frequencies) / sizeof(long)) - iwe.u.freq.m = (s32)(ieee80211_wlan_frequencies[dsconfig - 1] * 100000); - else - iwe.u.freq.m = 0; - } - iwe.u.freq.e = (s16)1; - iwe.u.freq.i = (u8)pnetwork->network.Configuration.DSConfig; - start = iwe_stream_add_event(info, start, stop, &iwe, - IW_EV_FREQ_LEN); - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (cap & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = (u16)(IW_ENCODE_ENABLED | IW_ENCODE_NOKEY); - else - iwe.u.data.flags = (u16)(IW_ENCODE_DISABLED); - iwe.u.data.length = (u16)0; - start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); - /*Add basic and extended rates */ - current_val = start + iwe_stream_lcp_len(info); - iwe.cmd = SIOCGIWRATE; - iwe.u.bitrate.fixed = 0; - iwe.u.bitrate.disabled = 0; - iwe.u.bitrate.value = 0; - i = 0; - while (pnetwork->network.rates[i] != 0) { - /* Bit rate given in 500 kb/s units */ - iwe.u.bitrate.value = (pnetwork->network.rates[i++] & 0x7F) * 500000; - current_val = iwe_stream_add_value(info, start, current_val, stop, &iwe, - IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - start) > iwe_stream_lcp_len(info)) - start = current_val; - - start = translate_scan_wpa(info, pnetwork, &iwe, start, stop); - - start = translate_scan_wps(info, pnetwork, &iwe, start, stop); - - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi); - /* we only update signal_level (signal strength) that is rssi. */ - iwe.u.qual.updated = (u8)(IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID); - iwe.u.qual.level = rssi; /* signal strength */ - iwe.u.qual.qual = 0; /* signal quality */ - iwe.u.qual.noise = 0; /* noise level */ - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); - /* how to translate rssi to ?% */ - return start; -} - -static int wpa_set_auth_algs(struct net_device *dev, u32 value) -{ - struct _adapter *padapter = netdev_priv(dev); - int ret = 0; - - if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) { - padapter->securitypriv.ndisencryptstatus = - Ndis802_11Encryption1Enabled; - padapter->securitypriv.ndisauthtype = - Ndis802_11AuthModeAutoSwitch; - padapter->securitypriv.AuthAlgrthm = 3; - } else if (value & AUTH_ALG_SHARED_KEY) { - padapter->securitypriv.ndisencryptstatus = - Ndis802_11Encryption1Enabled; - padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; - padapter->securitypriv.AuthAlgrthm = 1; - } else if (value & AUTH_ALG_OPEN_SYSTEM) { - if (padapter->securitypriv.ndisauthtype < - Ndis802_11AuthModeWPAPSK) { - padapter->securitypriv.ndisauthtype = - Ndis802_11AuthModeOpen; - padapter->securitypriv.AuthAlgrthm = 0; - } - } else { - ret = -EINVAL; - } - return ret; -} - -static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, - u32 param_len) -{ - int ret = 0; - u32 wep_key_idx, wep_key_len = 0; - struct NDIS_802_11_WEP *pwep = NULL; - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - - param->u.crypt.err = 0; - param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; - if (param_len != (u32)((u8 *) param->u.crypt.key - (u8 *)param) + - param->u.crypt.key_len) - return -EINVAL; - if (!is_broadcast_ether_addr(param->sta_addr)) - return -EINVAL; - - if (param->u.crypt.idx >= WEP_KEYS) { - /* for large key indices, set the default (0) */ - param->u.crypt.idx = 0; - } - if (strcmp(param->u.crypt.alg, "WEP") == 0) { - netdev_info(dev, "r8712u: %s: crypt.alg = WEP\n", __func__); - padapter->securitypriv.ndisencryptstatus = - Ndis802_11Encryption1Enabled; - padapter->securitypriv.PrivacyAlgrthm = _WEP40_; - padapter->securitypriv.XGrpPrivacy = _WEP40_; - wep_key_idx = param->u.crypt.idx; - wep_key_len = param->u.crypt.key_len; - if (wep_key_idx >= WEP_KEYS) - wep_key_idx = 0; - if (wep_key_len <= 0) - return -EINVAL; - - wep_key_len = wep_key_len <= 5 ? 5 : 13; - pwep = kzalloc(sizeof(*pwep), GFP_ATOMIC); - if (!pwep) - return -ENOMEM; - pwep->KeyLength = wep_key_len; - pwep->Length = wep_key_len + - offsetof(struct NDIS_802_11_WEP, KeyMaterial); - if (wep_key_len == 13) { - padapter->securitypriv.PrivacyAlgrthm = _WEP104_; - padapter->securitypriv.XGrpPrivacy = _WEP104_; - } - pwep->KeyIndex = wep_key_idx; - pwep->KeyIndex |= 0x80000000; - memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); - if (param->u.crypt.set_tx) { - if (r8712_set_802_11_add_wep(padapter, pwep)) - ret = -EOPNOTSUPP; - } else { - /* don't update "psecuritypriv->PrivacyAlgrthm" and - * "psecuritypriv->PrivacyKeyIndex=keyid", but can - * r8712_set_key to fw/cam - */ - if (wep_key_idx >= WEP_KEYS) { - ret = -EOPNOTSUPP; - goto exit; - } - memcpy(&psecuritypriv->DefKey[wep_key_idx].skey[0], - pwep->KeyMaterial, - pwep->KeyLength); - psecuritypriv->DefKeylen[wep_key_idx] = - pwep->KeyLength; - r8712_set_key(padapter, psecuritypriv, wep_key_idx); - } - goto exit; - } - if (padapter->securitypriv.AuthAlgrthm == 2) { /* 802_1x */ - struct sta_info *psta, *pbcmc_sta; - struct sta_priv *pstapriv = &padapter->stapriv; - struct security_priv *spriv = &padapter->securitypriv; - - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | - WIFI_MP_STATE)) { /* sta mode */ - psta = r8712_get_stainfo(pstapriv, - get_bssid(pmlmepriv)); - if (psta) { - psta->ieee8021x_blocked = false; - if (spriv->ndisencryptstatus == - Ndis802_11Encryption2Enabled || - spriv->ndisencryptstatus == - Ndis802_11Encryption3Enabled) - psta->XPrivacy = spriv->PrivacyAlgrthm; - if (param->u.crypt.set_tx == 1) - handle_pairwise_key(psta, param, - padapter); - else /* group key */ - handle_group_key(param, padapter); - } - pbcmc_sta = r8712_get_bcmc_stainfo(padapter); - if (pbcmc_sta) { - pbcmc_sta->ieee8021x_blocked = false; - if (spriv->ndisencryptstatus == - Ndis802_11Encryption2Enabled || - spriv->ndisencryptstatus == - Ndis802_11Encryption3Enabled) - pbcmc_sta->XPrivacy = - spriv->PrivacyAlgrthm; - } - } - } -exit: - kfree(pwep); - return ret; -} - -static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie, - unsigned short ielen) -{ - u8 *buf = NULL; - int group_cipher = 0, pairwise_cipher = 0; - int ret = 0; - - if (ielen > MAX_WPA_IE_LEN || !pie) - return -EINVAL; - if (ielen) { - buf = kmemdup(pie, ielen, GFP_ATOMIC); - if (!buf) - return -ENOMEM; - if (ielen < RSN_HEADER_LEN) { - ret = -EINVAL; - goto exit; - } - if (r8712_parse_wpa_ie(buf, ielen, &group_cipher, - &pairwise_cipher) == 0) { - padapter->securitypriv.AuthAlgrthm = 2; - padapter->securitypriv.ndisauthtype = - Ndis802_11AuthModeWPAPSK; - } - if (r8712_parse_wpa2_ie(buf, ielen, &group_cipher, - &pairwise_cipher) == 0) { - padapter->securitypriv.AuthAlgrthm = 2; - padapter->securitypriv.ndisauthtype = - Ndis802_11AuthModeWPA2PSK; - } - switch (group_cipher) { - case WPA_CIPHER_NONE: - padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; - break; - case WPA_CIPHER_WEP40: - padapter->securitypriv.XGrpPrivacy = _WEP40_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; - break; - case WPA_CIPHER_TKIP: - padapter->securitypriv.XGrpPrivacy = _TKIP_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; - break; - case WPA_CIPHER_CCMP: - padapter->securitypriv.XGrpPrivacy = _AES_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; - break; - case WPA_CIPHER_WEP104: - padapter->securitypriv.XGrpPrivacy = _WEP104_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; - break; - } - switch (pairwise_cipher) { - case WPA_CIPHER_NONE: - padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; - break; - case WPA_CIPHER_WEP40: - padapter->securitypriv.PrivacyAlgrthm = _WEP40_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; - break; - case WPA_CIPHER_TKIP: - padapter->securitypriv.PrivacyAlgrthm = _TKIP_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; - break; - case WPA_CIPHER_CCMP: - padapter->securitypriv.PrivacyAlgrthm = _AES_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; - break; - case WPA_CIPHER_WEP104: - padapter->securitypriv.PrivacyAlgrthm = _WEP104_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; - break; - } - padapter->securitypriv.wps_phase = false; - {/* set wps_ie */ - u16 cnt = 0; - u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; - - while (cnt < ielen) { - eid = buf[cnt]; - - if ((eid == WLAN_EID_VENDOR_SPECIFIC) && - (!memcmp(&buf[cnt + 2], wps_oui, 4))) { - netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE\n"); - padapter->securitypriv.wps_ie_len = - ((buf[cnt + 1] + 2) < - (MAX_WPA_IE_LEN << 2)) ? - (buf[cnt + 1] + 2) : - (MAX_WPA_IE_LEN << 2); - memcpy(padapter->securitypriv.wps_ie, - &buf[cnt], - padapter->securitypriv.wps_ie_len); - padapter->securitypriv.wps_phase = - true; - netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE, wps_phase==true\n"); - cnt += buf[cnt + 1] + 2; - break; - } - - cnt += buf[cnt + 1] + 2; - } - } - } -exit: - kfree(buf); - return ret; -} - -static int r8711_wx_get_name(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - u32 ht_ielen = 0; - char *p; - u8 ht_cap = false; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - u8 *prates; - - if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) == true) { - /* parsing HT_CAP_IE */ - p = r8712_get_ie(&pcur_bss->IEs[12], WLAN_EID_HT_CAPABILITY, - &ht_ielen, pcur_bss->IELength - 12); - if (p && ht_ielen > 0) - ht_cap = true; - prates = pcur_bss->rates; - if (r8712_is_cckratesonly_included(prates)) { - if (ht_cap) - snprintf(wrqu->name, IFNAMSIZ, - "IEEE 802.11bn"); - else - snprintf(wrqu->name, IFNAMSIZ, - "IEEE 802.11b"); - } else if (r8712_is_cckrates_included(prates)) { - if (ht_cap) - snprintf(wrqu->name, IFNAMSIZ, - "IEEE 802.11bgn"); - else - snprintf(wrqu->name, IFNAMSIZ, - "IEEE 802.11bg"); - } else { - if (ht_cap) - snprintf(wrqu->name, IFNAMSIZ, - "IEEE 802.11gn"); - else - snprintf(wrqu->name, IFNAMSIZ, - "IEEE 802.11g"); - } - } else { - snprintf(wrqu->name, IFNAMSIZ, "unassociated"); - } - return 0; -} - -static const long frequency_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, - 2467, 2472, 2484, 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980, - 5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, - 5220, 5230, 5240, 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, - 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745, 5765, 5785, 5805, - 5825 -}; - -static int r8711_wx_set_freq(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct iw_freq *fwrq = &wrqu->freq; - int rc = 0; - -/* If setting by frequency, convert to a channel */ - if ((fwrq->e == 1) && (fwrq->m >= 241200000) && (fwrq->m <= 248700000)) { - int f = fwrq->m / 100000; - int c = 0; - - while ((c < 14) && (f != frequency_list[c])) - c++; - fwrq->e = 0; - fwrq->m = c + 1; - } - /* Setting by channel number */ - if ((fwrq->m > 14) || (fwrq->e > 0)) { - rc = -EOPNOTSUPP; - } else { - int channel = fwrq->m; - - if ((channel < 1) || (channel > 14)) { - rc = -EINVAL; - } else { - /* Yes ! We can set it !!! */ - padapter->registrypriv.channel = channel; - } - } - return rc; -} - -static int r8711_wx_get_freq(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - - if (!check_fwstate(pmlmepriv, _FW_LINKED)) - return -ENOLINK; - - wrqu->freq.m = ieee80211_wlan_frequencies[ - pcur_bss->Configuration.DSConfig - 1] * 100000; - wrqu->freq.e = 1; - wrqu->freq.i = pcur_bss->Configuration.DSConfig; - - return 0; -} - -static int r8711_wx_set_mode(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct _adapter *padapter = netdev_priv(dev); - enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType; - - switch (wrqu->mode) { - case IW_MODE_AUTO: - networkType = Ndis802_11AutoUnknown; - break; - case IW_MODE_ADHOC: - networkType = Ndis802_11IBSS; - break; - case IW_MODE_MASTER: - networkType = Ndis802_11APMode; - break; - case IW_MODE_INFRA: - networkType = Ndis802_11Infrastructure; - break; - default: - return -EINVAL; - } - if (Ndis802_11APMode == networkType) - r8712_setopmode_cmd(padapter, networkType); - else - r8712_setopmode_cmd(padapter, Ndis802_11AutoUnknown); - - r8712_set_802_11_infrastructure_mode(padapter, networkType); - return 0; -} - -static int r8711_wx_get_mode(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) - wrqu->mode = IW_MODE_INFRA; - else if (check_fwstate(pmlmepriv, - WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE)) - wrqu->mode = IW_MODE_ADHOC; - else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) - wrqu->mode = IW_MODE_MASTER; - else - wrqu->mode = IW_MODE_AUTO; - return 0; -} - -static int r871x_wx_set_pmkid(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct iw_pmksa *pPMK = (struct iw_pmksa *) extra; - struct RT_PMKID_LIST *pl = psecuritypriv->PMKIDList; - u8 strZeroMacAddress[ETH_ALEN] = {0x00}; - u8 strIssueBssid[ETH_ALEN] = {0x00}; - u8 j, blInserted = false; - int intReturn = false; - -/* - * There are the BSSID information in the bssid.sa_data array. - * If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear - * all the PMKID information. If cmd is IW_PMKSA_ADD, it means the - * wpa_supplicant wants to add a PMKID/BSSID to driver. - * If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to - * remove a PMKID/BSSID from driver. - */ - if (!pPMK) - return -EINVAL; - memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN); - switch (pPMK->cmd) { - case IW_PMKSA_ADD: - if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN)) - return intReturn; - intReturn = true; - blInserted = false; - /* overwrite PMKID */ - for (j = 0; j < NUM_PMKID_CACHE; j++) { - if (!memcmp(pl[j].Bssid, strIssueBssid, ETH_ALEN)) { - /* BSSID is matched, the same AP => rewrite - * with new PMKID. - */ - netdev_info(dev, "r8712u: %s: BSSID exists in the PMKList.\n", - __func__); - memcpy(pl[j].PMKID, pPMK->pmkid, IW_PMKID_LEN); - pl[j].bUsed = true; - psecuritypriv->PMKIDIndex = j + 1; - blInserted = true; - break; - } - } - if (!blInserted) { - /* Find a new entry */ - netdev_info(dev, "r8712u: %s: Use the new entry index = %d for this PMKID.\n", - __func__, psecuritypriv->PMKIDIndex); - memcpy(pl[psecuritypriv->PMKIDIndex].Bssid, - strIssueBssid, ETH_ALEN); - memcpy(pl[psecuritypriv->PMKIDIndex].PMKID, - pPMK->pmkid, IW_PMKID_LEN); - pl[psecuritypriv->PMKIDIndex].bUsed = true; - psecuritypriv->PMKIDIndex++; - if (psecuritypriv->PMKIDIndex == NUM_PMKID_CACHE) - psecuritypriv->PMKIDIndex = 0; - } - break; - case IW_PMKSA_REMOVE: - intReturn = true; - for (j = 0; j < NUM_PMKID_CACHE; j++) { - if (!memcmp(pl[j].Bssid, strIssueBssid, ETH_ALEN)) { - /* BSSID is matched, the same AP => Remove - * this PMKID information and reset it. - */ - eth_zero_addr(pl[j].Bssid); - pl[j].bUsed = false; - break; - } - } - break; - case IW_PMKSA_FLUSH: - memset(psecuritypriv->PMKIDList, 0, - sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE); - psecuritypriv->PMKIDIndex = 0; - intReturn = true; - break; - default: - netdev_info(dev, "r8712u: %s: unknown Command\n", __func__); - intReturn = false; - break; - } - return intReturn; -} - -static int r8711_wx_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - wrqu->sens.value = 0; - wrqu->sens.fixed = 0; /* no auto select */ - wrqu->sens.disabled = 1; - return 0; -} - -static int r8711_wx_get_range(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - u16 val; - int i; - - wrqu->data.length = sizeof(*range); - memset(range, 0, sizeof(*range)); - /* Let's try to keep this struct in the same order as in - * linux/include/wireless.h - */ - - /* TODO: See what values we can set, and remove the ones we can't - * set, or fill them with some default data. - */ - /* ~5 Mb/s real (802.11b) */ - range->throughput = 5 * 1000 * 1000; - /* TODO: 8711 sensitivity ? */ - /* signal level threshold range */ - /* percent values between 0 and 100. */ - range->max_qual.qual = 100; - range->max_qual.level = 100; - range->max_qual.noise = 100; - range->max_qual.updated = 7; /* Updated all three */ - range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ - /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ - range->avg_qual.level = 0x100 - 78; - range->avg_qual.noise = 0; - range->avg_qual.updated = 7; /* Updated all three */ - range->num_bitrates = RATE_COUNT; - for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) - range->bitrate[i] = rtl8180_rates[i]; - range->min_frag = MIN_FRAG_THRESHOLD; - range->max_frag = MAX_FRAG_THRESHOLD; - range->pm_capa = 0; - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 16; - range->num_channels = 14; - for (i = 0, val = 0; i < 14; i++) { - /* Include only legal frequencies for some countries */ - range->freq[val].i = i + 1; - range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; - range->freq[val].e = 1; - val++; - if (val == IW_MAX_FREQUENCIES) - break; - } - range->num_frequency = val; - range->enc_capa = IW_ENC_CAPA_WPA | - IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | - IW_ENC_CAPA_CIPHER_CCMP; - return 0; -} - -static int r8711_wx_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -static int r871x_wx_set_priv(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *awrq, - char *extra) -{ - int ret = 0, len = 0; - char *ext; - struct _adapter *padapter = netdev_priv(dev); - struct iw_point *dwrq = (struct iw_point *)awrq; - - len = dwrq->length; - ext = strndup_user(dwrq->pointer, len); - if (IS_ERR(ext)) - return PTR_ERR(ext); - - if (!strcasecmp(ext, "RSSI")) { - /*Return received signal strength indicator in -db for */ - /* current AP */ - /* Rssi xx */ - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct wlan_network *pcur_network = &pmlmepriv->cur_network; - /*static u8 xxxx; */ - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - sprintf(ext, "%s rssi %d", - pcur_network->network.Ssid.Ssid, - /*(xxxx=xxxx+10) */ - ((padapter->recvpriv.fw_rssi) >> 1) - 95 - /*pcur_network->network.Rssi */ - ); - } else { - sprintf(ext, "OK"); - } - } else if (!strcasecmp(ext, "LINKSPEED")) { - /*Return link speed in MBPS */ - /*LinkSpeed xx */ - union iwreq_data wrqd; - int ret_inner; - int mbps; - - ret_inner = r8711_wx_get_rate(dev, info, &wrqd, extra); - if (ret_inner != 0) - mbps = 0; - else - mbps = wrqd.bitrate.value / 1000000; - sprintf(ext, "LINKSPEED %d", mbps); - } else if (!strcasecmp(ext, "MACADDR")) { - /*Return mac address of the station */ - /* Macaddr = xx:xx:xx:xx:xx:xx */ - sprintf(ext, "MACADDR = %pM", dev->dev_addr); - } else if (!strcasecmp(ext, "SCAN-ACTIVE")) { - /*Set scan type to active */ - /*OK if successful */ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - pmlmepriv->passive_mode = 1; - sprintf(ext, "OK"); - } else if (!strcasecmp(ext, "SCAN-PASSIVE")) { - /*Set scan type to passive */ - /*OK if successful */ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - pmlmepriv->passive_mode = 0; - sprintf(ext, "OK"); - } else if (!strncmp(ext, "DCE-E", 5)) { - /*Set scan type to passive */ - /*OK if successful */ - r8712_disconnectCtrlEx_cmd(padapter - , 1 /*u32 enableDrvCtrl */ - , 5 /*u32 tryPktCnt */ - , 100 /*u32 tryPktInterval */ - , 5000 /*u32 firstStageTO */ - ); - sprintf(ext, "OK"); - } else if (!strncmp(ext, "DCE-D", 5)) { - /*Set scan type to passive */ - /*OK if successfu */ - r8712_disconnectCtrlEx_cmd(padapter - , 0 /*u32 enableDrvCtrl */ - , 5 /*u32 tryPktCnt */ - , 100 /*u32 tryPktInterval */ - , 5000 /*u32 firstStageTO */ - ); - sprintf(ext, "OK"); - } else { - netdev_info(dev, "r8712u: %s: unknown Command %s.\n", __func__, ext); - goto FREE_EXT; - } - if (copy_to_user(dwrq->pointer, ext, min(dwrq->length, (__u16)(strlen(ext) + 1)))) - ret = -EFAULT; - -FREE_EXT: - kfree(ext); - return ret; -} - -/* set bssid flow - * s1. set_802_11_infrastructure_mode() - * s2. set_802_11_authentication_mode() - * s3. set_802_11_encryption_mode() - * s4. set_802_11_bssid() - * - * This function intends to handle the Set AP command, which specifies the - * MAC# of a preferred Access Point. - * Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl. - * - * For this operation to succeed, there is no need for the interface to be up. - * - */ -static int r8711_wx_set_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *awrq, char *extra) -{ - int ret = -EINPROGRESS; - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct __queue *queue = &pmlmepriv->scanned_queue; - struct sockaddr *temp = (struct sockaddr *)awrq; - unsigned long irqL; - struct list_head *phead; - u8 *dst_bssid; - struct wlan_network *pnetwork = NULL; - enum NDIS_802_11_AUTHENTICATION_MODE authmode; - - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) - return -EBUSY; - if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) - return ret; - if (temp->sa_family != ARPHRD_ETHER) - return -EINVAL; - authmode = padapter->securitypriv.ndisauthtype; - spin_lock_irqsave(&queue->lock, irqL); - phead = &queue->queue; - pmlmepriv->pscanned = phead->next; - while (1) { - if (end_of_queue_search(phead, pmlmepriv->pscanned)) - break; - pnetwork = container_of(pmlmepriv->pscanned, - struct wlan_network, list); - pmlmepriv->pscanned = pmlmepriv->pscanned->next; - dst_bssid = pnetwork->network.MacAddress; - if (!memcmp(dst_bssid, temp->sa_data, ETH_ALEN)) { - r8712_set_802_11_infrastructure_mode(padapter, - pnetwork->network.InfrastructureMode); - break; - } - } - spin_unlock_irqrestore(&queue->lock, irqL); - if (!ret) { - if (!r8712_set_802_11_authentication_mode(padapter, authmode)) { - ret = -ENOMEM; - } else { - if (!r8712_set_802_11_bssid(padapter, temp->sa_data)) - ret = -1; - } - } - return ret; -} - -static int r8711_wx_get_wap(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE)) - ether_addr_copy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress); - else - eth_zero_addr(wrqu->ap_addr.sa_data); - return 0; -} - -static int r871x_wx_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - struct _adapter *padapter = netdev_priv(dev); - struct iw_mlme *mlme = (struct iw_mlme *) extra; - - if (!mlme) - return -1; - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - if (!r8712_set_802_11_disassociate(padapter)) - ret = -1; - break; - case IW_MLME_DISASSOC: - if (!r8712_set_802_11_disassociate(padapter)) - ret = -1; - break; - default: - return -EOPNOTSUPP; - } - return ret; -} - -/* - * - * This function intends to handle the Set Scan command. - * Currently, the request comes via Wireless Extensions' SIOCSIWSCAN ioctl. - * - * For this operation to succeed, the interface is brought Up beforehand. - * - */ -static int r8711_wx_set_scan(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - u8 status = true; - - if (padapter->driver_stopped) { - netdev_info(dev, "In %s: driver_stopped=%d\n", - __func__, padapter->driver_stopped); - return -1; - } - if (!padapter->bup) - return -ENETDOWN; - if (!padapter->hw_init_completed) - return -1; - if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) || - (pmlmepriv->sitesurveyctrl.traffic_busy)) - return 0; - if (wrqu->data.length == sizeof(struct iw_scan_req)) { - struct iw_scan_req *req = (struct iw_scan_req *)extra; - - if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { - struct ndis_802_11_ssid ssid; - unsigned long irqL; - u32 len = min_t(u8, req->essid_len, IW_ESSID_MAX_SIZE); - - memset((unsigned char *)&ssid, 0, sizeof(struct ndis_802_11_ssid)); - memcpy(ssid.Ssid, req->essid, len); - ssid.SsidLength = len; - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | - _FW_UNDER_LINKING)) || - (pmlmepriv->sitesurveyctrl.traffic_busy)) { - if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) - status = false; - } else { - status = r8712_sitesurvey_cmd(padapter, &ssid); - } - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - } - } else { - status = r8712_set_802_11_bssid_list_scan(padapter); - } - if (!status) - return -1; - return 0; -} - -static int r8711_wx_get_scan(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct __queue *queue = &pmlmepriv->scanned_queue; - struct wlan_network *pnetwork = NULL; - unsigned long irqL; - struct list_head *plist, *phead; - char *ev = extra; - char *stop = ev + wrqu->data.length; - u32 ret = 0, cnt = 0; - - if (padapter->driver_stopped) - return -EINVAL; - while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) { - msleep(30); - cnt++; - if (cnt > 100) - break; - } - spin_lock_irqsave(&queue->lock, irqL); - phead = &queue->queue; - plist = phead->next; - while (1) { - if (end_of_queue_search(phead, plist)) - break; - if ((stop - ev) < SCAN_ITEM_SIZE) { - ret = -E2BIG; - break; - } - pnetwork = container_of(plist, struct wlan_network, list); - ev = translate_scan(padapter, a, pnetwork, ev, stop); - plist = plist->next; - } - spin_unlock_irqrestore(&queue->lock, irqL); - wrqu->data.length = ev - extra; - wrqu->data.flags = 0; - return ret; -} - -/* set ssid flow - * s1. set_802_11_infrastructure_mode() - * s2. set_802_11_authenticaion_mode() - * s3. set_802_11_encryption_mode() - * s4. set_802_11_ssid() - * - * This function intends to handle the Set ESSID command. - * Currently, the request comes via the Wireless Extensions' SIOCSIWESSID ioctl. - * - * For this operation to succeed, there is no need for the interface to be Up. - * - */ -static int r8711_wx_set_essid(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct __queue *queue = &pmlmepriv->scanned_queue; - struct wlan_network *pnetwork = NULL; - enum NDIS_802_11_AUTHENTICATION_MODE authmode; - struct ndis_802_11_ssid ndis_ssid; - u8 *dst_ssid, *src_ssid; - struct list_head *phead; - u32 len; - - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) - return -EBUSY; - if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) - return 0; - if (wrqu->essid.length > IW_ESSID_MAX_SIZE) - return -E2BIG; - authmode = padapter->securitypriv.ndisauthtype; - if (wrqu->essid.flags && wrqu->essid.length) { - len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? - wrqu->essid.length : IW_ESSID_MAX_SIZE; - memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid)); - ndis_ssid.SsidLength = len; - memcpy(ndis_ssid.Ssid, extra, len); - src_ssid = ndis_ssid.Ssid; - phead = &queue->queue; - pmlmepriv->pscanned = phead->next; - while (1) { - if (end_of_queue_search(phead, pmlmepriv->pscanned)) - break; - pnetwork = container_of(pmlmepriv->pscanned, - struct wlan_network, list); - pmlmepriv->pscanned = pmlmepriv->pscanned->next; - dst_ssid = pnetwork->network.Ssid.Ssid; - if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) - && (pnetwork->network.Ssid.SsidLength == - ndis_ssid.SsidLength)) { - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { - if (pnetwork->network. - InfrastructureMode - != - padapter->mlmepriv. - cur_network.network. - InfrastructureMode) - continue; - } - - r8712_set_802_11_infrastructure_mode( - padapter, - pnetwork->network.InfrastructureMode); - break; - } - } - r8712_set_802_11_authentication_mode(padapter, authmode); - r8712_set_802_11_ssid(padapter, &ndis_ssid); - } - return -EINPROGRESS; -} - -static int r8711_wx_get_essid(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - u32 len, ret = 0; - - if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) { - len = pcur_bss->Ssid.SsidLength; - wrqu->essid.length = len; - memcpy(extra, pcur_bss->Ssid.Ssid, len); - wrqu->essid.flags = 1; - } else { - ret = -ENOLINK; - } - return ret; -} - -static int r8711_wx_set_rate(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - u32 target_rate = wrqu->bitrate.value; - u32 fixed = wrqu->bitrate.fixed; - u32 ratevalue = 0; - u8 datarates[NumRates]; - u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff}; - int i; - - if (target_rate == -1) { - ratevalue = 11; - goto set_rate; - } - target_rate = target_rate / 100000; - switch (target_rate) { - case 10: - ratevalue = 0; - break; - case 20: - ratevalue = 1; - break; - case 55: - ratevalue = 2; - break; - case 60: - ratevalue = 3; - break; - case 90: - ratevalue = 4; - break; - case 110: - ratevalue = 5; - break; - case 120: - ratevalue = 6; - break; - case 180: - ratevalue = 7; - break; - case 240: - ratevalue = 8; - break; - case 360: - ratevalue = 9; - break; - case 480: - ratevalue = 10; - break; - case 540: - ratevalue = 11; - break; - default: - ratevalue = 11; - break; - } -set_rate: - for (i = 0; i < NumRates; i++) { - if (ratevalue == mpdatarate[i]) { - datarates[i] = mpdatarate[i]; - if (fixed == 0) - break; - } else { - datarates[i] = 0xff; - } - } - return r8712_setdatarate_cmd(padapter, datarates); -} - -static int r8711_wx_get_rate(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - struct ieee80211_ht_cap *pht_capie; - unsigned char rf_type = padapter->registrypriv.rf_config; - int i; - u8 *p; - u16 rate, max_rate = 0, ht_cap = false; - u32 ht_ielen = 0; - u8 bw_40MHz = 0, short_GI = 0; - u16 mcs_rate = 0; - - i = 0; - if (!check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) - return -ENOLINK; - p = r8712_get_ie(&pcur_bss->IEs[12], WLAN_EID_HT_CAPABILITY, &ht_ielen, - pcur_bss->IELength - 12); - if (p && ht_ielen > 0) { - ht_cap = true; - pht_capie = (struct ieee80211_ht_cap *)(p + 2); - memcpy(&mcs_rate, &pht_capie->mcs, 2); - bw_40MHz = (le16_to_cpu(pht_capie->cap_info) & - IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0; - short_GI = (le16_to_cpu(pht_capie->cap_info) & - (IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; - } - while ((pcur_bss->rates[i] != 0) && - (pcur_bss->rates[i] != 0xFF)) { - rate = pcur_bss->rates[i] & 0x7F; - if (rate > max_rate) - max_rate = rate; - wrqu->bitrate.fixed = 0; /* no auto select */ - wrqu->bitrate.value = rate * 500000; - i++; - } - if (ht_cap) { - if (mcs_rate & 0x8000 /* MCS15 */ - && - rf_type == RTL8712_RF_2T2R) - max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : - ((short_GI) ? 144 : 130); - else /* default MCS7 */ - max_rate = (bw_40MHz) ? ((short_GI) ? 150 : 135) : - ((short_GI) ? 72 : 65); - max_rate *= 2; /* Mbps/2 */ - } - wrqu->bitrate.value = max_rate * 500000; - return 0; -} - -static int r8711_wx_get_rts(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - - wrqu->rts.value = padapter->registrypriv.rts_thresh; - wrqu->rts.fixed = 0; /* no auto select */ - return 0; -} - -static int r8711_wx_set_frag(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - - if (wrqu->frag.disabled) { - padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD; - } else { - if (wrqu->frag.value < MIN_FRAG_THRESHOLD || - wrqu->frag.value > MAX_FRAG_THRESHOLD) - return -EINVAL; - padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1; - } - return 0; -} - -static int r8711_wx_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - - wrqu->frag.value = padapter->xmitpriv.frag_len; - wrqu->frag.fixed = 0; /* no auto select */ - return 0; -} - -static int r8711_wx_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - wrqu->retry.value = 7; - wrqu->retry.fixed = 0; /* no auto select */ - wrqu->retry.disabled = 1; - return 0; -} - -static int r8711_wx_set_enc(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - u32 key; - u32 keyindex_provided; - struct NDIS_802_11_WEP wep; - enum NDIS_802_11_AUTHENTICATION_MODE authmode; - struct iw_point *erq = &wrqu->encoding; - struct _adapter *padapter = netdev_priv(dev); - - key = erq->flags & IW_ENCODE_INDEX; - memset(&wep, 0, sizeof(struct NDIS_802_11_WEP)); - if (erq->flags & IW_ENCODE_DISABLED) { - netdev_info(dev, "r8712u: %s: EncryptionDisabled\n", __func__); - padapter->securitypriv.ndisencryptstatus = - Ndis802_11EncryptionDisabled; - padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_; - padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_; - padapter->securitypriv.AuthAlgrthm = 0; /* open system */ - authmode = Ndis802_11AuthModeOpen; - padapter->securitypriv.ndisauthtype = authmode; - return 0; - } - if (key) { - if (key > WEP_KEYS) - return -EINVAL; - key--; - keyindex_provided = 1; - } else { - keyindex_provided = 0; - key = padapter->securitypriv.PrivacyKeyIndex; - } - /* set authentication mode */ - if (erq->flags & IW_ENCODE_OPEN) { - netdev_info(dev, "r8712u: %s: IW_ENCODE_OPEN\n", __func__); - padapter->securitypriv.ndisencryptstatus = - Ndis802_11Encryption1Enabled; - padapter->securitypriv.AuthAlgrthm = 0; /* open system */ - padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_; - padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_; - authmode = Ndis802_11AuthModeOpen; - padapter->securitypriv.ndisauthtype = authmode; - } else if (erq->flags & IW_ENCODE_RESTRICTED) { - netdev_info(dev, - "r8712u: %s: IW_ENCODE_RESTRICTED\n", __func__); - padapter->securitypriv.ndisencryptstatus = - Ndis802_11Encryption1Enabled; - padapter->securitypriv.AuthAlgrthm = 1; /* shared system */ - padapter->securitypriv.PrivacyAlgrthm = _WEP40_; - padapter->securitypriv.XGrpPrivacy = _WEP40_; - authmode = Ndis802_11AuthModeShared; - padapter->securitypriv.ndisauthtype = authmode; - } else { - padapter->securitypriv.ndisencryptstatus = - Ndis802_11Encryption1Enabled; - padapter->securitypriv.AuthAlgrthm = 0; /* open system */ - padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_; - padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_; - authmode = Ndis802_11AuthModeOpen; - padapter->securitypriv.ndisauthtype = authmode; - } - wep.KeyIndex = key; - if (erq->length > 0) { - wep.KeyLength = erq->length <= 5 ? 5 : 13; - wep.Length = wep.KeyLength + - offsetof(struct NDIS_802_11_WEP, KeyMaterial); - } else { - wep.KeyLength = 0; - if (keyindex_provided == 1) { /* set key_id only, no given - * KeyMaterial(erq->length==0). - */ - padapter->securitypriv.PrivacyKeyIndex = key; - switch (padapter->securitypriv.DefKeylen[key]) { - case 5: - padapter->securitypriv.PrivacyAlgrthm = - _WEP40_; - break; - case 13: - padapter->securitypriv.PrivacyAlgrthm = - _WEP104_; - break; - default: - padapter->securitypriv.PrivacyAlgrthm = - _NO_PRIVACY_; - break; - } - return 0; - } - } - wep.KeyIndex |= 0x80000000; /* transmit key */ - memcpy(wep.KeyMaterial, keybuf, wep.KeyLength); - if (r8712_set_802_11_add_wep(padapter, &wep)) - return -EOPNOTSUPP; - return 0; -} - -static int r8711_wx_get_enc(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - uint key; - struct _adapter *padapter = netdev_priv(dev); - struct iw_point *erq = &wrqu->encoding; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - union Keytype *dk = padapter->securitypriv.DefKey; - - if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - } - key = erq->flags & IW_ENCODE_INDEX; - if (key) { - if (key > WEP_KEYS) - return -EINVAL; - key--; - } else { - key = padapter->securitypriv.PrivacyKeyIndex; - } - erq->flags = key + 1; - switch (padapter->securitypriv.ndisencryptstatus) { - case Ndis802_11EncryptionNotSupported: - case Ndis802_11EncryptionDisabled: - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - break; - case Ndis802_11Encryption1Enabled: - erq->length = padapter->securitypriv.DefKeylen[key]; - if (erq->length) { - memcpy(keybuf, dk[key].skey, - padapter->securitypriv.DefKeylen[key]); - erq->flags |= IW_ENCODE_ENABLED; - if (padapter->securitypriv.ndisauthtype == - Ndis802_11AuthModeOpen) - erq->flags |= IW_ENCODE_OPEN; - else if (padapter->securitypriv.ndisauthtype == - Ndis802_11AuthModeShared) - erq->flags |= IW_ENCODE_RESTRICTED; - } else { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - } - break; - case Ndis802_11Encryption2Enabled: - case Ndis802_11Encryption3Enabled: - erq->length = 16; - erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN | - IW_ENCODE_NOKEY); - break; - default: - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - break; - } - return 0; -} - -static int r8711_wx_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - wrqu->power.value = 0; - wrqu->power.fixed = 0; /* no auto select */ - wrqu->power.disabled = 1; - return 0; -} - -static int r871x_wx_set_gen_ie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - - return r871x_set_wpa_ie(padapter, extra, wrqu->data.length); -} - -static int r871x_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct iw_param *param = (struct iw_param *)&wrqu->param; - int paramid; - int paramval; - int ret = 0; - - paramid = param->flags & IW_AUTH_INDEX; - paramval = param->value; - switch (paramid) { - case IW_AUTH_WPA_VERSION: - break; - case IW_AUTH_CIPHER_PAIRWISE: - break; - case IW_AUTH_CIPHER_GROUP: - break; - case IW_AUTH_KEY_MGMT: - /* - * ??? does not use these parameters - */ - break; - case IW_AUTH_TKIP_COUNTERMEASURES: - if (paramval) { - /* wpa_supplicant is enabling tkip countermeasure. */ - padapter->securitypriv.btkip_countermeasure = true; - } else { - /* wpa_supplicant is disabling tkip countermeasure. */ - padapter->securitypriv.btkip_countermeasure = false; - } - break; - case IW_AUTH_DROP_UNENCRYPTED: - /* HACK: - * - * wpa_supplicant calls set_wpa_enabled when the driver - * is loaded and unloaded, regardless of if WPA is being - * used. No other calls are made which can be used to - * determine if encryption will be used or not prior to - * association being expected. If encryption is not being - * used, drop_unencrypted is set to false, else true -- we - * can use this to determine if the CAP_PRIVACY_ON bit should - * be set. - */ - if (padapter->securitypriv.ndisencryptstatus == - Ndis802_11Encryption1Enabled) { - /* it means init value, or using wep, - * ndisencryptstatus = - * Ndis802_11Encryption1Enabled, - * then it needn't reset it; - */ - break; - } - - if (paramval) { - padapter->securitypriv.ndisencryptstatus = - Ndis802_11EncryptionDisabled; - padapter->securitypriv.PrivacyAlgrthm = - _NO_PRIVACY_; - padapter->securitypriv.XGrpPrivacy = - _NO_PRIVACY_; - padapter->securitypriv.AuthAlgrthm = 0; - padapter->securitypriv.ndisauthtype = - Ndis802_11AuthModeOpen; - } - break; - case IW_AUTH_80211_AUTH_ALG: - ret = wpa_set_auth_algs(dev, (u32)paramval); - break; - case IW_AUTH_WPA_ENABLED: - break; - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - break; - case IW_AUTH_PRIVACY_INVOKED: - break; - default: - return -EOPNOTSUPP; - } - - return ret; -} - -static int r871x_wx_set_enc_ext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_point *pencoding = &wrqu->encoding; - struct iw_encode_ext *pext = (struct iw_encode_ext *)extra; - struct ieee_param *param = NULL; - char *alg_name; - u32 param_len; - int ret = 0; - - switch (pext->alg) { - case IW_ENCODE_ALG_NONE: - alg_name = "none"; - break; - case IW_ENCODE_ALG_WEP: - alg_name = "WEP"; - break; - case IW_ENCODE_ALG_TKIP: - alg_name = "TKIP"; - break; - case IW_ENCODE_ALG_CCMP: - alg_name = "CCMP"; - break; - default: - return -EINVAL; - } - - param_len = sizeof(struct ieee_param) + pext->key_len; - param = kzalloc(param_len, GFP_ATOMIC); - if (!param) - return -ENOMEM; - param->cmd = IEEE_CMD_SET_ENCRYPTION; - eth_broadcast_addr(param->sta_addr); - strscpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); - if (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) - param->u.crypt.set_tx = 0; - if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) - param->u.crypt.set_tx = 1; - param->u.crypt.idx = (pencoding->flags & 0x00FF) - 1; - if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) - memcpy(param->u.crypt.seq, pext->rx_seq, 8); - if (pext->key_len) { - param->u.crypt.key_len = pext->key_len; - memcpy(param + 1, pext + 1, pext->key_len); - } - ret = wpa_set_encryption(dev, param, param_len); - kfree(param); - return ret; -} - -static int r871x_wx_get_nick(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - if (extra) { - wrqu->data.length = 8; - wrqu->data.flags = 1; - memcpy(extra, "rtl_wifi", 8); - } - return 0; -} - -static int r8711_wx_read32(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct _adapter *padapter = netdev_priv(dev); - u32 addr; - u32 data32; - - get_user(addr, (u32 __user *)wrqu->data.pointer); - data32 = r8712_read32(padapter, addr); - put_user(data32, (u32 __user *)wrqu->data.pointer); - wrqu->data.length = (data32 & 0xffff0000) >> 16; - wrqu->data.flags = data32 & 0xffff; - get_user(addr, (u32 __user *)wrqu->data.pointer); - return 0; -} - -static int r8711_wx_write32(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct _adapter *padapter = netdev_priv(dev); - u32 addr; - u32 data32; - - get_user(addr, (u32 __user *)wrqu->data.pointer); - data32 = ((u32)wrqu->data.length << 16) | (u32)wrqu->data.flags; - r8712_write32(padapter, addr, data32); - return 0; -} - -static int dummy(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - return -EINVAL; -} - -static int r8711_drvext_hdl(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - return 0; -} - -static int r871x_mp_ioctl_hdl(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct iw_point *p = &wrqu->data; - struct oid_par_priv oid_par; - struct mp_ioctl_handler *phandler; - struct mp_ioctl_param *poidparam; - unsigned long BytesRead, BytesWritten, BytesNeeded; - u8 *pparmbuf, bset; - u16 len; - uint status; - int ret = 0; - - if ((!p->length) || (!p->pointer)) - return -EINVAL; - - bset = (u8)(p->flags & 0xFFFF); - len = p->length; - pparmbuf = memdup_user(p->pointer, len); - if (IS_ERR(pparmbuf)) - return PTR_ERR(pparmbuf); - - poidparam = (struct mp_ioctl_param *)pparmbuf; - if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) { - ret = -EINVAL; - goto _r871x_mp_ioctl_hdl_exit; - } - phandler = mp_ioctl_hdl + poidparam->subcode; - if ((phandler->paramsize != 0) && - (poidparam->len < phandler->paramsize)) { - ret = -EINVAL; - goto _r871x_mp_ioctl_hdl_exit; - } - if (phandler->oid == 0 && phandler->handler) { - status = phandler->handler(&oid_par); - } else if (phandler->handler) { - oid_par.adapter_context = padapter; - oid_par.oid = phandler->oid; - oid_par.information_buf = poidparam->data; - oid_par.information_buf_len = poidparam->len; - oid_par.dbg = 0; - BytesWritten = 0; - BytesNeeded = 0; - if (bset) { - oid_par.bytes_rw = &BytesRead; - oid_par.bytes_needed = &BytesNeeded; - oid_par.type_of_oid = SET_OID; - } else { - oid_par.bytes_rw = &BytesWritten; - oid_par.bytes_needed = &BytesNeeded; - oid_par.type_of_oid = QUERY_OID; - } - status = phandler->handler(&oid_par); - /* todo:check status, BytesNeeded, etc. */ - } else { - netdev_info(dev, "r8712u: %s: err!, subcode=%d, oid=%d, handler=%p\n", - __func__, poidparam->subcode, phandler->oid, - phandler->handler); - ret = -EFAULT; - goto _r871x_mp_ioctl_hdl_exit; - } - if (bset == 0x00) { /* query info */ - if (copy_to_user(p->pointer, pparmbuf, len)) - ret = -EFAULT; - } - if (status) { - ret = -EFAULT; - goto _r871x_mp_ioctl_hdl_exit; - } -_r871x_mp_ioctl_hdl_exit: - kfree(pparmbuf); - return ret; -} - -static int r871x_get_ap_info(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct __queue *queue = &pmlmepriv->scanned_queue; - struct iw_point *pdata = &wrqu->data; - struct wlan_network *pnetwork = NULL; - u32 cnt = 0, wpa_ielen; - unsigned long irqL; - struct list_head *plist, *phead; - unsigned char *pbuf; - u8 bssid[ETH_ALEN]; - char data[33]; - - if (padapter->driver_stopped || !pdata) - return -EINVAL; - while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | - _FW_UNDER_LINKING)) { - msleep(30); - cnt++; - if (cnt > 100) - break; - } - pdata->flags = 0; - if (pdata->length < 32) - return -EINVAL; - if (copy_from_user(data, pdata->pointer, 32)) - return -EINVAL; - data[32] = 0; - - spin_lock_irqsave(&pmlmepriv->scanned_queue.lock, irqL); - phead = &queue->queue; - plist = phead->next; - while (1) { - if (end_of_queue_search(phead, plist)) - break; - pnetwork = container_of(plist, struct wlan_network, list); - if (!mac_pton(data, bssid)) { - netdev_info(dev, "r8712u: Invalid BSSID '%s'.\n", - (u8 *)data); - spin_unlock_irqrestore(&pmlmepriv->scanned_queue.lock, - irqL); - return -EINVAL; - } - netdev_info(dev, "r8712u: BSSID:%pM\n", bssid); - if (ether_addr_equal(bssid, pnetwork->network.MacAddress)) { - /* BSSID match, then check if supporting wpa/wpa2 */ - pbuf = r8712_get_wpa_ie(&pnetwork->network.IEs[12], - &wpa_ielen, pnetwork->network.IELength - 12); - if (pbuf && (wpa_ielen > 0)) { - pdata->flags = 1; - break; - } - pbuf = r8712_get_wpa2_ie(&pnetwork->network.IEs[12], - &wpa_ielen, pnetwork->network.IELength - 12); - if (pbuf && (wpa_ielen > 0)) { - pdata->flags = 2; - break; - } - } - plist = plist->next; - } - spin_unlock_irqrestore(&pmlmepriv->scanned_queue.lock, irqL); - if (pdata->length >= 34) { - if (copy_to_user((u8 __user *)pdata->pointer + 32, - (u8 *)&pdata->flags, 1)) - return -EINVAL; - } - return 0; -} - -static int r871x_set_pid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct iw_point *pdata = &wrqu->data; - - if (padapter->driver_stopped || !pdata) - return -EINVAL; - if (copy_from_user(&padapter->pid, pdata->pointer, sizeof(int))) - return -EINVAL; - return 0; -} - -static int r871x_set_chplan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - struct _adapter *padapter = netdev_priv(dev); - struct iw_point *pdata = &wrqu->data; - int ch_plan = -1; - - if (padapter->driver_stopped || !pdata) { - ret = -EINVAL; - goto exit; - } - ch_plan = (int)*extra; - r8712_set_chplan_cmd(padapter, ch_plan); - -exit: - - return ret; -} - -static int r871x_wps_start(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct _adapter *padapter = netdev_priv(dev); - struct iw_point *pdata = &wrqu->data; - u32 u32wps_start = 0; - - if (padapter->driver_stopped || !pdata) - return -EINVAL; - if (copy_from_user((void *)&u32wps_start, pdata->pointer, 4)) - return -EFAULT; - if (u32wps_start == 0) - u32wps_start = *extra; - if (u32wps_start == 1) /* WPS Start */ - padapter->ledpriv.LedControlHandler(padapter, - LED_CTL_START_WPS); - else if (u32wps_start == 2) /* WPS Stop because of wps success */ - padapter->ledpriv.LedControlHandler(padapter, - LED_CTL_STOP_WPS); - else if (u32wps_start == 3) /* WPS Stop because of wps fail */ - padapter->ledpriv.LedControlHandler(padapter, - LED_CTL_STOP_WPS_FAIL); - return 0; -} - -static int wpa_set_param(struct net_device *dev, u8 name, u32 value) -{ - struct _adapter *padapter = netdev_priv(dev); - - switch (name) { - case IEEE_PARAM_WPA_ENABLED: - padapter->securitypriv.AuthAlgrthm = 2; /* 802.1x */ - switch ((value) & 0xff) { - case 1: /* WPA */ - padapter->securitypriv.ndisauthtype = - Ndis802_11AuthModeWPAPSK; /* WPA_PSK */ - padapter->securitypriv.ndisencryptstatus = - Ndis802_11Encryption2Enabled; - break; - case 2: /* WPA2 */ - padapter->securitypriv.ndisauthtype = - Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */ - padapter->securitypriv.ndisencryptstatus = - Ndis802_11Encryption3Enabled; - break; - } - break; - case IEEE_PARAM_TKIP_COUNTERMEASURES: - break; - case IEEE_PARAM_DROP_UNENCRYPTED: - /* HACK: - * - * wpa_supplicant calls set_wpa_enabled when the driver - * is loaded and unloaded, regardless of if WPA is being - * used. No other calls are made which can be used to - * determine if encryption will be used or not prior to - * association being expected. If encryption is not being - * used, drop_unencrypted is set to false, else true -- we - * can use this to determine if the CAP_PRIVACY_ON bit should - * be set. - */ - break; - case IEEE_PARAM_PRIVACY_INVOKED: - break; - case IEEE_PARAM_AUTH_ALGS: - return wpa_set_auth_algs(dev, value); - case IEEE_PARAM_IEEE_802_1X: - break; - case IEEE_PARAM_WPAX_SELECT: - /* added for WPA2 mixed mode */ - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - -static int wpa_mlme(struct net_device *dev, u32 command, u32 reason) -{ - struct _adapter *padapter = netdev_priv(dev); - - switch (command) { - case IEEE_MLME_STA_DEAUTH: - if (!r8712_set_802_11_disassociate(padapter)) - return -1; - break; - case IEEE_MLME_STA_DISASSOC: - if (!r8712_set_802_11_disassociate(padapter)) - return -1; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - -static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p) -{ - struct ieee_param *param; - int ret = 0; - struct _adapter *padapter = netdev_priv(dev); - - if (p->length < sizeof(struct ieee_param) || !p->pointer) - return -EINVAL; - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) - return PTR_ERR(param); - switch (param->cmd) { - case IEEE_CMD_SET_WPA_PARAM: - ret = wpa_set_param(dev, param->u.wpa_param.name, - param->u.wpa_param.value); - break; - case IEEE_CMD_SET_WPA_IE: - ret = r871x_set_wpa_ie(padapter, (char *)param->u.wpa_ie.data, - (u16)param->u.wpa_ie.len); - break; - case IEEE_CMD_SET_ENCRYPTION: - ret = wpa_set_encryption(dev, param, p->length); - break; - case IEEE_CMD_MLME: - ret = wpa_mlme(dev, param->u.mlme.command, - param->u.mlme.reason_code); - break; - default: - ret = -EOPNOTSUPP; - break; - } - if (ret == 0 && copy_to_user(p->pointer, param, p->length)) - ret = -EFAULT; - kfree(param); - return ret; -} - -/* based on "driver_ipw" and for hostapd */ -int r871x_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct iwreq *wrq = (struct iwreq *)rq; - - switch (cmd) { - case RTL_IOCTL_WPA_SUPPLICANT: - return wpa_supplicant_ioctl(dev, &wrq->u.data); - default: - return -EOPNOTSUPP; - } - return 0; -} - -static iw_handler r8711_handlers[] = { - NULL, /* SIOCSIWCOMMIT */ - r8711_wx_get_name, /* SIOCGIWNAME */ - dummy, /* SIOCSIWNWID */ - dummy, /* SIOCGIWNWID */ - r8711_wx_set_freq, /* SIOCSIWFREQ */ - r8711_wx_get_freq, /* SIOCGIWFREQ */ - r8711_wx_set_mode, /* SIOCSIWMODE */ - r8711_wx_get_mode, /* SIOCGIWMODE */ - dummy, /* SIOCSIWSENS */ - r8711_wx_get_sens, /* SIOCGIWSENS */ - NULL, /* SIOCSIWRANGE */ - r8711_wx_get_range, /* SIOCGIWRANGE */ - r871x_wx_set_priv, /* SIOCSIWPRIV */ - NULL, /* SIOCGIWPRIV */ - NULL, /* SIOCSIWSTATS */ - NULL, /* SIOCGIWSTATS */ - dummy, /* SIOCSIWSPY */ - dummy, /* SIOCGIWSPY */ - NULL, /* SIOCGIWTHRSPY */ - NULL, /* SIOCWIWTHRSPY */ - r8711_wx_set_wap, /* SIOCSIWAP */ - r8711_wx_get_wap, /* SIOCGIWAP */ - r871x_wx_set_mlme, /* request MLME operation; - * uses struct iw_mlme - */ - dummy, /* SIOCGIWAPLIST -- deprecated */ - r8711_wx_set_scan, /* SIOCSIWSCAN */ - r8711_wx_get_scan, /* SIOCGIWSCAN */ - r8711_wx_set_essid, /* SIOCSIWESSID */ - r8711_wx_get_essid, /* SIOCGIWESSID */ - dummy, /* SIOCSIWNICKN */ - r871x_wx_get_nick, /* SIOCGIWNICKN */ - NULL, /* -- hole -- */ - NULL, /* -- hole -- */ - r8711_wx_set_rate, /* SIOCSIWRATE */ - r8711_wx_get_rate, /* SIOCGIWRATE */ - dummy, /* SIOCSIWRTS */ - r8711_wx_get_rts, /* SIOCGIWRTS */ - r8711_wx_set_frag, /* SIOCSIWFRAG */ - r8711_wx_get_frag, /* SIOCGIWFRAG */ - dummy, /* SIOCSIWTXPOW */ - dummy, /* SIOCGIWTXPOW */ - dummy, /* SIOCSIWRETRY */ - r8711_wx_get_retry, /* SIOCGIWRETRY */ - r8711_wx_set_enc, /* SIOCSIWENCODE */ - r8711_wx_get_enc, /* SIOCGIWENCODE */ - dummy, /* SIOCSIWPOWER */ - r8711_wx_get_power, /* SIOCGIWPOWER */ - NULL, /*---hole---*/ - NULL, /*---hole---*/ - r871x_wx_set_gen_ie, /* SIOCSIWGENIE */ - NULL, /* SIOCGIWGENIE */ - r871x_wx_set_auth, /* SIOCSIWAUTH */ - NULL, /* SIOCGIWAUTH */ - r871x_wx_set_enc_ext, /* SIOCSIWENCODEEXT */ - NULL, /* SIOCGIWENCODEEXT */ - r871x_wx_set_pmkid, /* SIOCSIWPMKSA */ - NULL, /*---hole---*/ -}; - -static const struct iw_priv_args r8711_private_args[] = { - { - SIOCIWFIRSTPRIV + 0x0, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "read32" - }, - { - SIOCIWFIRSTPRIV + 0x1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "write32" - }, - { - SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext" - }, - { - SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl" - }, - { - SIOCIWFIRSTPRIV + 0x4, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" - }, - { - SIOCIWFIRSTPRIV + 0x5, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setpid" - }, - { - SIOCIWFIRSTPRIV + 0x6, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start" - }, - { - SIOCIWFIRSTPRIV + 0x7, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "chplan" - } -}; - -static iw_handler r8711_private_handler[] = { - r8711_wx_read32, - r8711_wx_write32, - r8711_drvext_hdl, - r871x_mp_ioctl_hdl, - r871x_get_ap_info, /*for MM DTV platform*/ - r871x_set_pid, - r871x_wps_start, - r871x_set_chplan -}; - -static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev) -{ - struct _adapter *padapter = netdev_priv(dev); - struct iw_statistics *piwstats = &padapter->iwstats; - int tmp_level = 0; - int tmp_qual = 0; - int tmp_noise = 0; - - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) { - piwstats->qual.qual = 0; - piwstats->qual.level = 0; - piwstats->qual.noise = 0; - } else { - /* show percentage, we need transfer dbm to original value. */ - tmp_level = padapter->recvpriv.fw_rssi; - tmp_qual = padapter->recvpriv.signal; - tmp_noise = padapter->recvpriv.noise; - piwstats->qual.level = tmp_level; - piwstats->qual.qual = tmp_qual; - piwstats->qual.noise = tmp_noise; - } - piwstats->qual.updated = IW_QUAL_ALL_UPDATED; - return &padapter->iwstats; -} - -struct iw_handler_def r871x_handlers_def = { - .standard = r8711_handlers, - .num_standard = ARRAY_SIZE(r8711_handlers), - .private = r8711_private_handler, - .private_args = (struct iw_priv_args *)r8711_private_args, - .num_private = ARRAY_SIZE(r8711_private_handler), - .num_private_args = sizeof(r8711_private_args) / - sizeof(struct iw_priv_args), - .get_wireless_stats = r871x_get_wireless_stats -}; diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c deleted file mode 100644 index 2b539335206aa1..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.c +++ /dev/null @@ -1,519 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_ioctl_rtl.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_IOCTL_RTL_C_ - -#include -#include "osdep_service.h" -#include "drv_types.h" -#include "wlan_bssdef.h" -#include "wifi.h" -#include "rtl871x_ioctl.h" -#include "rtl871x_ioctl_set.h" -#include "rtl871x_ioctl_rtl.h" -#include "mp_custom_oid.h" -#include "rtl871x_mp.h" -#include "rtl871x_mp_ioctl.h" - -uint oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - padapter->recvpriv.rx_smallpacket_crcerr; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - padapter->recvpriv.rx_middlepacket_crcerr; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - padapter->recvpriv.rx_largepacket_crcerr; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - padapter->recvpriv.rx_pkts + - padapter->recvpriv.rx_drop; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - *(uint *)poid_par_priv->information_buf = - padapter->recvpriv.rx_icv_err; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv - *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - u32 preamblemode = 0; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - if (padapter->registrypriv.preamble == PREAMBLE_LONG) - preamblemode = 0; - else if (padapter->registrypriv.preamble == PREAMBLE_AUTO) - preamblemode = 1; - else if (padapter->registrypriv.preamble == PREAMBLE_SHORT) - preamblemode = 2; - *(u32 *)poid_par_priv->information_buf = preamblemode; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - struct eeprom_priv *peeprompriv = &padapter->eeprompriv; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - *(u16 *)poid_par_priv->information_buf = peeprompriv->channel_plan; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_set_channelplan_hdl(struct oid_par_priv - *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - struct eeprom_priv *peeprompriv = &padapter->eeprompriv; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - peeprompriv->channel_plan = *(u16 *)poid_par_priv->information_buf; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_set_preamble_mode_hdl(struct oid_par_priv - *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - u32 preamblemode = 0; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - preamblemode = *(u32 *)poid_par_priv->information_buf; - if (preamblemode == 0) - padapter->registrypriv.preamble = PREAMBLE_LONG; - else if (preamblemode == 1) - padapter->registrypriv.preamble = PREAMBLE_AUTO; - else if (preamblemode == 2) - padapter->registrypriv.preamble = PREAMBLE_SHORT; - *(u32 *)poid_par_priv->information_buf = preamblemode; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_dedicate_probe_hdl(struct oid_par_priv - *poid_par_priv) -{ - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv - *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - padapter->xmitpriv.tx_bytes; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv - *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - padapter->recvpriv.rx_bytes; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_current_tx_power_level_hdl(struct oid_par_priv - *poid_par_priv) -{ - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv - *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv - *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct NDIS_802_11_CONFIGURATION *pnic_Config; - u32 channelnum; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (check_fwstate(pmlmepriv, _FW_LINKED) || - check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) - pnic_Config = &pmlmepriv->cur_network.network.Configuration; - else - pnic_Config = &padapter->registrypriv.dev_network.Configuration; - channelnum = pnic_Config->DSConfig; - *(u32 *)poid_par_priv->information_buf = channelnum; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv - *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_supported_wireless_mode_hdl(struct oid_par_priv - *poid_par_priv) -{ - u32 ulInfo = 0; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len >= sizeof(u32)) { - ulInfo |= 0x0100; /* WIRELESS_MODE_B */ - ulInfo |= 0x0200; /* WIRELESS_MODE_G */ - ulInfo |= 0x0400; /* WIRELESS_MODE_A */ - *(u32 *) poid_par_priv->information_buf = ulInfo; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv) -{ - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv - *poid_par_priv) -{ - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv - *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv - *poid_par_priv) -{ - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv - *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv* - poid_par_priv) -{ - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv) -{ - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv* - poid_par_priv) -{ - uint status = RNDIS_STATUS_SUCCESS; - struct _adapter *Adapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */ - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len == - (sizeof(unsigned long) * 3)) { - if (r8712_setrfreg_cmd(Adapter, - *(unsigned char *)poid_par_priv->information_buf, - (unsigned long)(*((unsigned long *) - poid_par_priv->information_buf + 2)))) - status = RNDIS_STATUS_NOT_ACCEPTED; - } else { - status = RNDIS_STATUS_INVALID_LENGTH; - } - return status; -} - -uint oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv) -{ - uint status = RNDIS_STATUS_SUCCESS; - struct _adapter *Adapter = poid_par_priv->adapter_context; - - if (poid_par_priv->type_of_oid != SET_OID) /* QUERY_OID */ - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len == (sizeof(unsigned long) * - 3)) { - if (Adapter->mppriv.act_in_progress) { - status = RNDIS_STATUS_NOT_ACCEPTED; - } else { - /* init workparam */ - Adapter->mppriv.act_in_progress = true; - Adapter->mppriv.workparam.bcompleted = false; - Adapter->mppriv.workparam.act_type = MPT_READ_RF; - Adapter->mppriv.workparam.io_offset = *(unsigned long *) - poid_par_priv->information_buf; - Adapter->mppriv.workparam.io_value = 0xcccccccc; - - /* RegOffsetValue - The offset of RF register to read. - * RegDataWidth - The data width of RF register to read. - * RegDataValue - The value to read. - * RegOffsetValue = *((unsigned long *)InformationBuffer); - * RegDataWidth = *((unsigned long *)InformationBuffer+1); - * RegDataValue = *((unsigned long *)InformationBuffer+2); - */ - if (r8712_getrfreg_cmd(Adapter, - *(unsigned char *)poid_par_priv->information_buf, - (unsigned char *)&Adapter->mppriv.workparam.io_value - )) - status = RNDIS_STATUS_NOT_ACCEPTED; - } - } else { - status = RNDIS_STATUS_INVALID_LENGTH; - } - return status; -} - -enum _CONNECT_STATE_ { - CHECKINGSTATUS, - ASSOCIATED, - ADHOCMODE, - NOTASSOCIATED -}; - -uint oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *padapter = poid_par_priv->adapter_context; - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - u32 ulInfo; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - /* nStatus==0 CheckingStatus - * nStatus==1 Associated - * nStatus==2 AdHocMode - * nStatus==3 NotAssociated - */ - if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) - ulInfo = CHECKINGSTATUS; - else if (check_fwstate(pmlmepriv, _FW_LINKED)) - ulInfo = ASSOCIATED; - else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) - ulInfo = ADHOCMODE; - else - ulInfo = NOTASSOCIATED; - *(u32 *)poid_par_priv->information_buf = ulInfo; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h b/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h deleted file mode 100644 index 7c0b880ac68659..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_ioctl_rtl.h +++ /dev/null @@ -1,109 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL871X_IOCTL_RTL_H -#define _RTL871X_IOCTL_RTL_H - -#include "osdep_service.h" -#include "drv_types.h" - -/*************** oid_rtl_seg_01_01 **************/ -uint oid_rt_get_signal_quality_hdl( - struct oid_par_priv *poid_par_priv);/*84*/ -uint oid_rt_get_small_packet_crc_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_middle_packet_crc_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_large_packet_crc_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_tx_retry_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_rx_retry_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_rx_total_packet_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_tx_beacon_ok_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_tx_beacon_err_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_rx_icv_err_hdl( - struct oid_par_priv *poid_par_priv);/*93*/ -uint oid_rt_set_encryption_algorithm_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_preamble_mode_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_ap_ip_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_channelplan_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_set_channelplan_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_set_preamble_mode_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_set_bcn_intvl_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_dedicate_probe_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_total_tx_bytes_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_total_rx_bytes_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_current_tx_power_level_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_enc_key_mismatch_count_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_enc_key_match_count_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_channel_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_hardware_radio_off_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_key_mismatch_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_supported_wireless_mode_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_channel_list_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_scan_in_progress_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_forced_data_rate_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_wireless_mode_for_scan_list_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_bss_wireless_mode_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_scan_with_magic_packet_hdl( - struct oid_par_priv *poid_par_priv); - -/************** oid_rtl_seg_01_03 section start **************/ -uint oid_rt_ap_get_associated_station_list_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_ap_switch_into_ap_mode_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_ap_supported_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_ap_set_passphrase_hdl( - struct oid_par_priv *poid_par_priv); -/* oid_rtl_seg_01_11 */ -uint oid_rt_pro_rf_write_registry_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_rf_read_registry_hdl( - struct oid_par_priv *poid_par_priv); -/*************** oid_rtl_seg_03_00 section start **************/ -uint oid_rt_get_connect_state_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_set_default_key_id_hdl( - struct oid_par_priv *poid_par_priv); - -#endif - diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c deleted file mode 100644 index 34c9a52b4c42a6..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c +++ /dev/null @@ -1,354 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_ioctl_set.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_IOCTL_SET_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "rtl871x_ioctl_set.h" -#include "usb_osintf.h" -#include "usb_ops.h" - -static u8 validate_ssid(struct ndis_802_11_ssid *ssid) -{ - u8 i; - - if (ssid->SsidLength > 32) - return false; - for (i = 0; i < ssid->SsidLength; i++) { - /* wifi, printable ascii code must be supported */ - if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) - return false; - } - return true; -} - -static u8 do_join(struct _adapter *padapter) -{ - struct list_head *plist, *phead; - u8 *pibss = NULL; - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct __queue *queue = &(pmlmepriv->scanned_queue); - int ret; - - phead = &queue->queue; - plist = phead->next; - pmlmepriv->cur_network.join_res = -2; - pmlmepriv->fw_state |= _FW_UNDER_LINKING; - pmlmepriv->pscanned = plist; - pmlmepriv->to_join = true; - - /* adhoc mode will start with an empty queue, but skip checking */ - if (!check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) && - list_empty(&queue->queue)) { - if (pmlmepriv->fw_state & _FW_UNDER_LINKING) - pmlmepriv->fw_state ^= _FW_UNDER_LINKING; - /* when set_ssid/set_bssid for do_join(), but scanning queue - * is empty we try to issue sitesurvey firstly - */ - if (!pmlmepriv->sitesurveyctrl.traffic_busy) - r8712_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid); - return true; - } - - ret = r8712_select_and_join_from_scan(pmlmepriv); - if (!ret) { - mod_timer(&pmlmepriv->assoc_timer, - jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); - } else { - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { - /* submit r8712_createbss_cmd to change to an - * ADHOC_MASTER pmlmepriv->lock has been - * acquired by caller... - */ - struct wlan_bssid_ex *pdev_network = - &padapter->registrypriv.dev_network; - pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; - pibss = padapter->registrypriv.dev_network.MacAddress; - memcpy(&pdev_network->Ssid, - &pmlmepriv->assoc_ssid, - sizeof(struct ndis_802_11_ssid)); - r8712_update_registrypriv_dev_network(padapter); - r8712_generate_random_ibss(pibss); - if (r8712_createbss_cmd(padapter)) - return false; - pmlmepriv->to_join = false; - } else { - /* can't associate ; reset under-linking */ - if (pmlmepriv->fw_state & _FW_UNDER_LINKING) - pmlmepriv->fw_state ^= - _FW_UNDER_LINKING; - /* when set_ssid/set_bssid for do_join(), but - * there are no desired bss in scanning queue - * we try to issue sitesurvey first - */ - if (!pmlmepriv->sitesurveyctrl.traffic_busy) - r8712_sitesurvey_cmd(padapter, - &pmlmepriv->assoc_ssid); - } - } - return true; -} - -u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid) -{ - unsigned long irqL; - u8 status = true; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) { - status = false; - return status; - } - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | - _FW_UNDER_LINKING)) { - status = check_fwstate(pmlmepriv, _FW_UNDER_LINKING); - goto _Abort_Set_BSSID; - } - if (check_fwstate(pmlmepriv, - _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) { - if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, - ETH_ALEN)) { - if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) - /* driver is in - * WIFI_ADHOC_MASTER_STATE - */ - goto _Abort_Set_BSSID; - } else { - r8712_disassoc_cmd(padapter); - if (check_fwstate(pmlmepriv, _FW_LINKED)) - r8712_ind_disconnect(padapter); - r8712_free_assoc_resources(padapter); - if ((check_fwstate(pmlmepriv, - WIFI_ADHOC_MASTER_STATE))) { - _clr_fwstate_(pmlmepriv, - WIFI_ADHOC_MASTER_STATE); - set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); - } - } - } - memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); - pmlmepriv->assoc_by_bssid = true; - status = do_join(padapter); - goto done; -_Abort_Set_BSSID: -done: - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - return status; -} - -void r8712_set_802_11_ssid(struct _adapter *padapter, - struct ndis_802_11_ssid *ssid) -{ - unsigned long irqL; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_network *pnetwork = &pmlmepriv->cur_network; - - if (!padapter->hw_init_completed) - return; - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) { - check_fwstate(pmlmepriv, _FW_UNDER_LINKING); - goto _Abort_Set_SSID; - } - if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) { - if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && - (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, - ssid->SsidLength))) { - if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - if (!r8712_is_same_ibss(padapter, - pnetwork)) { - /* if in WIFI_ADHOC_MASTER_STATE or - * WIFI_ADHOC_STATE, create bss or - * rejoin again - */ - r8712_disassoc_cmd(padapter); - if (check_fwstate(pmlmepriv, - _FW_LINKED)) - r8712_ind_disconnect(padapter); - r8712_free_assoc_resources(padapter); - if (check_fwstate(pmlmepriv, - WIFI_ADHOC_MASTER_STATE)) { - _clr_fwstate_(pmlmepriv, - WIFI_ADHOC_MASTER_STATE); - set_fwstate(pmlmepriv, - WIFI_ADHOC_STATE); - } - } else { - /* driver is in - * WIFI_ADHOC_MASTER_STATE - */ - goto _Abort_Set_SSID; - } - } - } else { - r8712_disassoc_cmd(padapter); - if (check_fwstate(pmlmepriv, _FW_LINKED)) - r8712_ind_disconnect(padapter); - r8712_free_assoc_resources(padapter); - if (check_fwstate(pmlmepriv, - WIFI_ADHOC_MASTER_STATE)) { - _clr_fwstate_(pmlmepriv, - WIFI_ADHOC_MASTER_STATE); - set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); - } - } - } - if (padapter->securitypriv.btkip_countermeasure) - goto _Abort_Set_SSID; - if (!validate_ssid(ssid)) - goto _Abort_Set_SSID; - memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid)); - pmlmepriv->assoc_by_bssid = false; - do_join(padapter); - goto done; -_Abort_Set_SSID: -done: - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); -} - -void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter, - enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) -{ - unsigned long irqL; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_network *cur_network = &pmlmepriv->cur_network; - enum NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state = - &(cur_network->network.InfrastructureMode); - - if (*pold_state != networktype) { - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (check_fwstate(pmlmepriv, _FW_LINKED) || - (*pold_state == Ndis802_11IBSS)) - r8712_disassoc_cmd(padapter); - if (check_fwstate(pmlmepriv, - _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) - r8712_free_assoc_resources(padapter); - if (check_fwstate(pmlmepriv, _FW_LINKED) || - (*pold_state == Ndis802_11Infrastructure) || - (*pold_state == Ndis802_11IBSS)) { - /* will clr Linked_state before this function, - * we must have checked whether issue dis-assoc_cmd or - * not - */ - r8712_ind_disconnect(padapter); - } - *pold_state = networktype; - /* clear WIFI_STATION_STATE; WIFI_AP_STATE; WIFI_ADHOC_STATE; - * WIFI_ADHOC_MASTER_STATE - */ - _clr_fwstate_(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE | - WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE); - switch (networktype) { - case Ndis802_11IBSS: - set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); - break; - case Ndis802_11Infrastructure: - set_fwstate(pmlmepriv, WIFI_STATION_STATE); - break; - case Ndis802_11APMode: - set_fwstate(pmlmepriv, WIFI_AP_STATE); - break; - case Ndis802_11AutoUnknown: - case Ndis802_11InfrastructureMax: - break; - } - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - } -} - -u8 r8712_set_802_11_disassociate(struct _adapter *padapter) -{ - unsigned long irqL; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - r8712_disassoc_cmd(padapter); - r8712_ind_disconnect(padapter); - r8712_free_assoc_resources(padapter); - } - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - return true; -} - -u8 r8712_set_802_11_bssid_list_scan(struct _adapter *padapter) -{ - struct mlme_priv *pmlmepriv = NULL; - unsigned long irqL; - u8 ret = true; - - if (!padapter) - return false; - pmlmepriv = &padapter->mlmepriv; - if (!padapter->hw_init_completed) - return false; - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) || - pmlmepriv->sitesurveyctrl.traffic_busy) { - /* Scan or linking is in progress, do nothing. */ - ret = (u8)check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); - } else { - r8712_free_network_queue(padapter); - ret = r8712_sitesurvey_cmd(padapter, NULL); - } - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - return ret; -} - -u8 r8712_set_802_11_authentication_mode(struct _adapter *padapter, - enum NDIS_802_11_AUTHENTICATION_MODE authmode) -{ - struct security_priv *psecuritypriv = &padapter->securitypriv; - u8 ret; - - psecuritypriv->ndisauthtype = authmode; - if (psecuritypriv->ndisauthtype > 3) - psecuritypriv->AuthAlgrthm = 2; /* 802.1x */ - if (r8712_set_auth(padapter, psecuritypriv)) - ret = false; - else - ret = true; - return ret; -} - -int r8712_set_802_11_add_wep(struct _adapter *padapter, - struct NDIS_802_11_WEP *wep) -{ - sint keyid; - struct security_priv *psecuritypriv = &padapter->securitypriv; - - keyid = wep->KeyIndex & 0x3fffffff; - if (keyid >= WEP_KEYS) - return -EINVAL; - switch (wep->KeyLength) { - case 5: - psecuritypriv->PrivacyAlgrthm = _WEP40_; - break; - case 13: - psecuritypriv->PrivacyAlgrthm = _WEP104_; - break; - default: - psecuritypriv->PrivacyAlgrthm = _NO_PRIVACY_; - break; - } - memcpy(psecuritypriv->DefKey[keyid].skey, &wep->KeyMaterial, - wep->KeyLength); - psecuritypriv->DefKeylen[keyid] = wep->KeyLength; - psecuritypriv->PrivacyKeyIndex = keyid; - return r8712_set_key(padapter, psecuritypriv, keyid); -} diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.h b/drivers/staging/rtl8712/rtl871x_ioctl_set.h deleted file mode 100644 index e2de820f61d985..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_ioctl_set.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __IOCTL_SET_H -#define __IOCTL_SET_H - -#include "drv_types.h" - -typedef u8 NDIS_802_11_PMKID_VALUE[16]; - -struct BSSIDInfo { - unsigned char BSSID[6]; - NDIS_802_11_PMKID_VALUE PMKID; -}; - -u8 r8712_set_802_11_authentication_mode(struct _adapter *pdapter, - enum NDIS_802_11_AUTHENTICATION_MODE authmode); - -u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid); - -int r8712_set_802_11_add_wep(struct _adapter *padapter, - struct NDIS_802_11_WEP *wep); - -u8 r8712_set_802_11_disassociate(struct _adapter *padapter); - -u8 r8712_set_802_11_bssid_list_scan(struct _adapter *padapter); - -void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter, - enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype); - -void r8712_set_802_11_ssid(struct _adapter *padapter, - struct ndis_802_11_ssid *ssid); - -#endif - diff --git a/drivers/staging/rtl8712/rtl871x_led.h b/drivers/staging/rtl8712/rtl871x_led.h deleted file mode 100644 index 2f0768132ad8ff..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_led.h +++ /dev/null @@ -1,118 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL8712_LED_H -#define __RTL8712_LED_H - -#include "osdep_service.h" -#include "drv_types.h" - -/*=========================================================================== - * LED customization. - *=========================================================================== - */ -enum LED_CTL_MODE { - LED_CTL_POWER_ON = 1, - LED_CTL_LINK = 2, - LED_CTL_NO_LINK = 3, - LED_CTL_TX = 4, - LED_CTL_RX = 5, - LED_CTL_SITE_SURVEY = 6, - LED_CTL_POWER_OFF = 7, - LED_CTL_START_TO_LINK = 8, - LED_CTL_START_WPS = 9, - LED_CTL_STOP_WPS = 10, - LED_CTL_START_WPS_BOTTON = 11, - LED_CTL_STOP_WPS_FAIL = 12, - LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, -}; - -#define IS_LED_WPS_BLINKING(_LED_871x) \ - (((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS \ - || ((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS_STOP \ - || ((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress) - -#define IS_LED_BLINKING(_LED_871x) \ - (((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress \ - || ((struct LED_871x *)_LED_871x)->bLedScanBlinkInProgress) - -enum LED_PIN_871x { - LED_PIN_GPIO0, - LED_PIN_LED0, - LED_PIN_LED1 -}; - -/*=========================================================================== - * LED customization. - *=========================================================================== - */ -enum LED_STRATEGY_871x { - SW_LED_MODE0, /* SW control 1 LED via GPIO0. It is default option. */ - SW_LED_MODE1, /* 2 LEDs, through LED0 and LED1. For ALPHA. */ - SW_LED_MODE2, /* SW control 1 LED via GPIO0, - * custom for AzWave 8187 minicard. - */ - SW_LED_MODE3, /* SW control 1 LED via GPIO0, - * customized for Sercomm Printer Server case. - */ - SW_LED_MODE4, /*for Edimax / Belkin*/ - SW_LED_MODE5, /*for Sercomm / Belkin*/ - SW_LED_MODE6, /*for WNC / Corega*/ - HW_LED, /* HW control 2 LEDs, LED0 and LED1 (there are 4 different - * control modes, see MAC.CONFIG1 for details.) - */ -}; - -struct LED_871x { - struct _adapter *padapter; - enum LED_PIN_871x LedPin; /* Implementation for this SW led. */ - u32 CurrLedState; /* Current LED state. */ - u8 bLedOn; /* true if LED is ON */ - u8 bSWLedCtrl; - u8 bLedBlinkInProgress; /*true if blinking */ - u8 bLedNoLinkBlinkInProgress; - u8 bLedLinkBlinkInProgress; - u8 bLedStartToLinkBlinkInProgress; - u8 bLedScanBlinkInProgress; - u8 bLedWPSBlinkInProgress; - u32 BlinkTimes; /* No. times to toggle for blink.*/ - u32 BlinkingLedState; /* Next state for blinking, - * either LED_ON or OFF. - */ - - struct timer_list BlinkTimer; /* Timer object for led blinking.*/ - struct work_struct BlinkWorkItem; /* Workitem used by BlinkTimer */ -}; - -struct led_priv { - /* add for led control */ - struct LED_871x SwLed0; - struct LED_871x SwLed1; - enum LED_STRATEGY_871x LedStrategy; - u8 bRegUseLed; - void (*LedControlHandler)(struct _adapter *padapter, - enum LED_CTL_MODE LedAction); - /* add for led control */ -}; - -/*=========================================================================== - * Interface to manipulate LED objects. - *=========================================================================== - */ -void r8712_InitSwLeds(struct _adapter *padapter); -void r8712_DeInitSwLeds(struct _adapter *padapter); -void LedControl871x(struct _adapter *padapter, enum LED_CTL_MODE LedAction); -void r8712_flush_led_works(struct _adapter *padapter); - -#endif - diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c deleted file mode 100644 index 70c295e9706857..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ /dev/null @@ -1,1710 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_mlme.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_MLME_C_ - -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "recv_osdep.h" -#include "xmit_osdep.h" -#include "mlme_osdep.h" -#include "sta_info.h" -#include "wifi.h" -#include "wlan_bssdef.h" - -static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len); - -int r8712_init_mlme_priv(struct _adapter *padapter) -{ - sint i; - u8 *pbuf; - struct wlan_network *pnetwork; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - memset((u8 *)pmlmepriv, 0, sizeof(struct mlme_priv)); - pmlmepriv->nic_hdl = (u8 *)padapter; - pmlmepriv->pscanned = NULL; - pmlmepriv->fw_state = 0; - pmlmepriv->cur_network.network.InfrastructureMode = - Ndis802_11AutoUnknown; - /* Maybe someday we should rename this variable to "active_mode"(Jeff)*/ - pmlmepriv->passive_mode = 1; /* 1: active, 0: passive. */ - spin_lock_init(&(pmlmepriv->lock)); - spin_lock_init(&(pmlmepriv->lock2)); - _init_queue(&(pmlmepriv->free_bss_pool)); - _init_queue(&(pmlmepriv->scanned_queue)); - set_scanned_network_val(pmlmepriv, 0); - memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); - pbuf = kmalloc_array(MAX_BSS_CNT, sizeof(struct wlan_network), - GFP_ATOMIC); - if (!pbuf) - return -ENOMEM; - pmlmepriv->free_bss_buf = pbuf; - pnetwork = (struct wlan_network *)pbuf; - for (i = 0; i < MAX_BSS_CNT; i++) { - INIT_LIST_HEAD(&(pnetwork->list)); - list_add_tail(&(pnetwork->list), - &(pmlmepriv->free_bss_pool.queue)); - pnetwork++; - } - pmlmepriv->sitesurveyctrl.last_rx_pkts = 0; - pmlmepriv->sitesurveyctrl.last_tx_pkts = 0; - pmlmepriv->sitesurveyctrl.traffic_busy = false; - /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ - r8712_init_mlme_timer(padapter); - return 0; -} - -struct wlan_network *_r8712_alloc_network(struct mlme_priv *pmlmepriv) -{ - unsigned long irqL; - struct wlan_network *pnetwork; - struct __queue *free_queue = &pmlmepriv->free_bss_pool; - - spin_lock_irqsave(&free_queue->lock, irqL); - pnetwork = list_first_entry_or_null(&free_queue->queue, - struct wlan_network, list); - if (pnetwork) { - list_del_init(&pnetwork->list); - pnetwork->last_scanned = jiffies; - pmlmepriv->num_of_scanned++; - } - spin_unlock_irqrestore(&free_queue->lock, irqL); - return pnetwork; -} - -static void _free_network(struct mlme_priv *pmlmepriv, - struct wlan_network *pnetwork) -{ - u32 curr_time, delta_time; - unsigned long irqL; - struct __queue *free_queue = &(pmlmepriv->free_bss_pool); - - if (!pnetwork) - return; - if (pnetwork->fixed) - return; - curr_time = jiffies; - delta_time = (curr_time - (u32)pnetwork->last_scanned) / HZ; - if (delta_time < SCANQUEUE_LIFETIME) - return; - spin_lock_irqsave(&free_queue->lock, irqL); - list_del_init(&pnetwork->list); - list_add_tail(&pnetwork->list, &free_queue->queue); - pmlmepriv->num_of_scanned--; - spin_unlock_irqrestore(&free_queue->lock, irqL); -} - -static void free_network_nolock(struct mlme_priv *pmlmepriv, - struct wlan_network *pnetwork) -{ - struct __queue *free_queue = &pmlmepriv->free_bss_pool; - - if (!pnetwork) - return; - if (pnetwork->fixed) - return; - list_del_init(&pnetwork->list); - list_add_tail(&pnetwork->list, &free_queue->queue); - pmlmepriv->num_of_scanned--; -} - -/* return the wlan_network with the matching addr - * Shall be called under atomic context... - * to avoid possible racing condition... - */ -static struct wlan_network *r8712_find_network(struct __queue *scanned_queue, - u8 *addr) -{ - unsigned long irqL; - struct list_head *phead, *plist; - struct wlan_network *pnetwork = NULL; - - if (is_zero_ether_addr(addr)) - return NULL; - spin_lock_irqsave(&scanned_queue->lock, irqL); - phead = &scanned_queue->queue; - list_for_each(plist, phead) { - pnetwork = list_entry(plist, struct wlan_network, list); - if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN)) - break; - } - if (plist == phead) - pnetwork = NULL; - spin_unlock_irqrestore(&scanned_queue->lock, irqL); - return pnetwork; -} - -void r8712_free_network_queue(struct _adapter *padapter) -{ - unsigned long irqL; - struct list_head *phead, *plist; - struct wlan_network *pnetwork; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct __queue *scanned_queue = &pmlmepriv->scanned_queue; - - spin_lock_irqsave(&scanned_queue->lock, irqL); - phead = &scanned_queue->queue; - plist = phead->next; - while (!end_of_queue_search(phead, plist)) { - pnetwork = container_of(plist, struct wlan_network, list); - plist = plist->next; - _free_network(pmlmepriv, pnetwork); - } - spin_unlock_irqrestore(&scanned_queue->lock, irqL); -} - -sint r8712_if_up(struct _adapter *padapter) -{ - sint res; - - if (padapter->driver_stopped || padapter->surprise_removed || - !check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { - res = false; - } else { - res = true; - } - return res; -} - -void r8712_generate_random_ibss(u8 *pibss) -{ - u32 curtime = jiffies; - - pibss[0] = 0x02; /*in ad-hoc mode bit1 must set to 1 */ - pibss[1] = 0x11; - pibss[2] = 0x87; - pibss[3] = (u8)(curtime & 0xff); - pibss[4] = (u8)((curtime >> 8) & 0xff); - pibss[5] = (u8)((curtime >> 16) & 0xff); -} - -uint r8712_get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss) -{ - return sizeof(*bss) + bss->IELength - MAX_IE_SZ; -} - -u8 *r8712_get_capability_from_ie(u8 *ie) -{ - return ie + 8 + 2; -} - -void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv) -{ - kfree(pmlmepriv->free_bss_buf); -} - -static struct wlan_network *alloc_network(struct mlme_priv *pmlmepriv) -{ - return _r8712_alloc_network(pmlmepriv); -} - -int r8712_is_same_ibss(struct _adapter *adapter, struct wlan_network *pnetwork) -{ - int ret = true; - struct security_priv *psecuritypriv = &adapter->securitypriv; - - if ((psecuritypriv->PrivacyAlgrthm != _NO_PRIVACY_) && - (pnetwork->network.Privacy == cpu_to_le32(0))) - ret = false; - else if ((psecuritypriv->PrivacyAlgrthm == _NO_PRIVACY_) && - (pnetwork->network.Privacy == cpu_to_le32(1))) - ret = false; - else - ret = true; - return ret; - -} - -static int is_same_network(struct wlan_bssid_ex *src, - struct wlan_bssid_ex *dst) -{ - u16 s_cap, d_cap; - - memcpy((u8 *)&s_cap, r8712_get_capability_from_ie(src->IEs), 2); - memcpy((u8 *)&d_cap, r8712_get_capability_from_ie(dst->IEs), 2); - return (src->Ssid.SsidLength == dst->Ssid.SsidLength) && - (src->Configuration.DSConfig == - dst->Configuration.DSConfig) && - ((!memcmp(src->MacAddress, dst->MacAddress, - ETH_ALEN))) && - ((!memcmp(src->Ssid.Ssid, - dst->Ssid.Ssid, - src->Ssid.SsidLength))) && - ((s_cap & WLAN_CAPABILITY_IBSS) == - (d_cap & WLAN_CAPABILITY_IBSS)) && - ((s_cap & WLAN_CAPABILITY_ESS) == - (d_cap & WLAN_CAPABILITY_ESS)); - -} - -struct wlan_network *r8712_get_oldest_wlan_network( - struct __queue *scanned_queue) -{ - struct list_head *plist, *phead; - struct wlan_network *pwlan = NULL; - struct wlan_network *oldest = NULL; - - phead = &scanned_queue->queue; - plist = phead->next; - while (1) { - if (end_of_queue_search(phead, plist)) - break; - pwlan = container_of(plist, struct wlan_network, list); - if (!pwlan->fixed) { - if (!oldest || - time_after((unsigned long)oldest->last_scanned, - (unsigned long)pwlan->last_scanned)) - oldest = pwlan; - } - plist = plist->next; - } - return oldest; -} - -static void update_network(struct wlan_bssid_ex *dst, - struct wlan_bssid_ex *src, - struct _adapter *padapter) -{ - u32 last_evm = 0, tmpVal; - struct smooth_rssi_data *sqd = &padapter->recvpriv.signal_qual_data; - - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && - is_same_network(&(padapter->mlmepriv.cur_network.network), src)) { - if (padapter->recvpriv.signal_qual_data.total_num++ >= - PHY_LINKQUALITY_SLID_WIN_MAX) { - padapter->recvpriv.signal_qual_data.total_num = - PHY_LINKQUALITY_SLID_WIN_MAX; - last_evm = sqd->elements[sqd->index]; - padapter->recvpriv.signal_qual_data.total_val -= - last_evm; - } - padapter->recvpriv.signal_qual_data.total_val += src->Rssi; - - sqd->elements[sqd->index++] = src->Rssi; - if (padapter->recvpriv.signal_qual_data.index >= - PHY_LINKQUALITY_SLID_WIN_MAX) - padapter->recvpriv.signal_qual_data.index = 0; - /* <1> Showed on UI for user, in percentage. */ - tmpVal = padapter->recvpriv.signal_qual_data.total_val / - padapter->recvpriv.signal_qual_data.total_num; - padapter->recvpriv.signal = (u8)tmpVal; - - src->Rssi = padapter->recvpriv.signal; - } else { - src->Rssi = (src->Rssi + dst->Rssi) / 2; - } - memcpy((u8 *)dst, (u8 *)src, r8712_get_wlan_bssid_ex_sz(src)); -} - -static void update_current_network(struct _adapter *adapter, - struct wlan_bssid_ex *pnetwork) -{ - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - - if (is_same_network(&(pmlmepriv->cur_network.network), pnetwork)) { - update_network(&(pmlmepriv->cur_network.network), - pnetwork, adapter); - r8712_update_protection(adapter, - (pmlmepriv->cur_network.network.IEs) + - sizeof(struct NDIS_802_11_FIXED_IEs), - pmlmepriv->cur_network.network.IELength); - } -} - -/* Caller must hold pmlmepriv->lock first */ -static void update_scanned_network(struct _adapter *adapter, - struct wlan_bssid_ex *target) -{ - struct list_head *plist, *phead; - - u32 bssid_ex_sz; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct __queue *queue = &pmlmepriv->scanned_queue; - struct wlan_network *pnetwork = NULL; - struct wlan_network *oldest = NULL; - - phead = &queue->queue; - plist = phead->next; - - while (1) { - if (end_of_queue_search(phead, plist)) - break; - - pnetwork = container_of(plist, struct wlan_network, list); - if (is_same_network(&pnetwork->network, target)) - break; - if ((oldest == ((struct wlan_network *)0)) || - time_after((unsigned long)oldest->last_scanned, - (unsigned long)pnetwork->last_scanned)) - oldest = pnetwork; - - plist = plist->next; - } - - /* If we didn't find a match, then get a new network slot to initialize - * with this beacon's information - */ - if (end_of_queue_search(phead, plist)) { - if (list_empty(&pmlmepriv->free_bss_pool.queue)) { - /* If there are no more slots, expire the oldest */ - pnetwork = oldest; - target->Rssi = (pnetwork->network.Rssi + - target->Rssi) / 2; - memcpy(&pnetwork->network, target, - r8712_get_wlan_bssid_ex_sz(target)); - pnetwork->last_scanned = jiffies; - } else { - /* Otherwise just pull from the free list */ - /* update scan_time */ - pnetwork = alloc_network(pmlmepriv); - if (!pnetwork) - return; - bssid_ex_sz = r8712_get_wlan_bssid_ex_sz(target); - target->Length = bssid_ex_sz; - memcpy(&pnetwork->network, target, bssid_ex_sz); - list_add_tail(&pnetwork->list, &queue->queue); - } - } else { - /* we have an entry and we are going to update it. But - * this entry may be already expired. In this case we - * do the same as we found a new net and call the new_net - * handler - */ - update_network(&pnetwork->network, target, adapter); - pnetwork->last_scanned = jiffies; - } -} - -static void rtl8711_add_network(struct _adapter *adapter, - struct wlan_bssid_ex *pnetwork) -{ - unsigned long irqL; - struct mlme_priv *pmlmepriv = &(((struct _adapter *)adapter)->mlmepriv); - struct __queue *queue = &pmlmepriv->scanned_queue; - - spin_lock_irqsave(&queue->lock, irqL); - update_current_network(adapter, pnetwork); - update_scanned_network(adapter, pnetwork); - spin_unlock_irqrestore(&queue->lock, irqL); -} - -/*select the desired network based on the capability of the (i)bss. - * check items: (1) security - * (2) network_type - * (3) WMM - * (4) HT - * (5) others - */ -static int is_desired_network(struct _adapter *adapter, - struct wlan_network *pnetwork) -{ - u8 wps_ie[512]; - uint wps_ielen; - int bselected = true; - struct security_priv *psecuritypriv = &adapter->securitypriv; - - if (psecuritypriv->wps_phase) { - if (r8712_get_wps_ie(pnetwork->network.IEs, - pnetwork->network.IELength, wps_ie, - &wps_ielen)) - return true; - return false; - } - if ((psecuritypriv->PrivacyAlgrthm != _NO_PRIVACY_) && - (pnetwork->network.Privacy == 0)) - bselected = false; - if (check_fwstate(&adapter->mlmepriv, WIFI_ADHOC_STATE)) { - if (pnetwork->network.InfrastructureMode != - adapter->mlmepriv.cur_network.network.InfrastructureMode) - bselected = false; - } - return bselected; -} - -/* TODO: Perry : For Power Management */ -void r8712_atimdone_event_callback(struct _adapter *adapter, u8 *pbuf) -{ -} - -void r8712_survey_event_callback(struct _adapter *adapter, u8 *pbuf) -{ - unsigned long flags; - u32 len; - struct wlan_bssid_ex *pnetwork; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - - pnetwork = (struct wlan_bssid_ex *)pbuf; -#ifdef __BIG_ENDIAN - /* endian_convert */ - pnetwork->Length = le32_to_cpu(pnetwork->Length); - pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength); - pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy); - pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi); - pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse); - pnetwork->Configuration.ATIMWindow = - le32_to_cpu(pnetwork->Configuration.ATIMWindow); - pnetwork->Configuration.BeaconPeriod = - le32_to_cpu(pnetwork->Configuration.BeaconPeriod); - pnetwork->Configuration.DSConfig = - le32_to_cpu(pnetwork->Configuration.DSConfig); - pnetwork->Configuration.FHConfig.DwellTime = - le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime); - pnetwork->Configuration.FHConfig.HopPattern = - le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern); - pnetwork->Configuration.FHConfig.HopSet = - le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet); - pnetwork->Configuration.FHConfig.Length = - le32_to_cpu(pnetwork->Configuration.FHConfig.Length); - pnetwork->Configuration.Length = - le32_to_cpu(pnetwork->Configuration.Length); - pnetwork->InfrastructureMode = - le32_to_cpu(pnetwork->InfrastructureMode); - pnetwork->IELength = le32_to_cpu(pnetwork->IELength); -#endif - len = r8712_get_wlan_bssid_ex_sz(pnetwork); - if (len > sizeof(struct wlan_bssid_ex)) - return; - spin_lock_irqsave(&pmlmepriv->lock2, flags); - /* update IBSS_network 's timestamp */ - if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { - if (!memcmp(&(pmlmepriv->cur_network.network.MacAddress), - pnetwork->MacAddress, ETH_ALEN)) { - struct wlan_network *ibss_wlan = NULL; - - memcpy(pmlmepriv->cur_network.network.IEs, - pnetwork->IEs, 8); - ibss_wlan = r8712_find_network( - &pmlmepriv->scanned_queue, - pnetwork->MacAddress); - if (ibss_wlan) { - memcpy(ibss_wlan->network.IEs, - pnetwork->IEs, 8); - goto exit; - } - } - } - /* lock pmlmepriv->lock when you accessing network_q */ - if (!check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { - if (pnetwork->Ssid.Ssid[0] != 0) { - rtl8711_add_network(adapter, pnetwork); - } else { - pnetwork->Ssid.SsidLength = 8; - memcpy(pnetwork->Ssid.Ssid, "", 8); - rtl8711_add_network(adapter, pnetwork); - } - } -exit: - spin_unlock_irqrestore(&pmlmepriv->lock2, flags); -} - -void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf) -{ - unsigned long irqL; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - - spin_lock_irqsave(&pmlmepriv->lock, irqL); - - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { - del_timer(&pmlmepriv->scan_to_timer); - - _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); - } - - if (pmlmepriv->to_join) { - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { - if (!check_fwstate(pmlmepriv, _FW_LINKED)) { - set_fwstate(pmlmepriv, _FW_UNDER_LINKING); - - if (!r8712_select_and_join_from_scan(pmlmepriv)) { - mod_timer(&pmlmepriv->assoc_timer, jiffies + - msecs_to_jiffies(MAX_JOIN_TIMEOUT)); - } else { - struct wlan_bssid_ex *pdev_network = - &(adapter->registrypriv.dev_network); - u8 *pibss = - adapter->registrypriv.dev_network.MacAddress; - pmlmepriv->fw_state ^= _FW_UNDER_SURVEY; - memcpy(&pdev_network->Ssid, - &pmlmepriv->assoc_ssid, - sizeof(struct - ndis_802_11_ssid)); - r8712_update_registrypriv_dev_network - (adapter); - r8712_generate_random_ibss(pibss); - pmlmepriv->fw_state = - WIFI_ADHOC_MASTER_STATE; - pmlmepriv->to_join = false; - } - } - } else { - pmlmepriv->to_join = false; - set_fwstate(pmlmepriv, _FW_UNDER_LINKING); - if (!r8712_select_and_join_from_scan(pmlmepriv)) - mod_timer(&pmlmepriv->assoc_timer, jiffies + - msecs_to_jiffies(MAX_JOIN_TIMEOUT)); - else - _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); - } - } - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); -} - -/* - *r8712_free_assoc_resources: the caller has to lock pmlmepriv->lock - */ -void r8712_free_assoc_resources(struct _adapter *adapter) -{ - unsigned long irqL; - struct wlan_network *pwlan = NULL; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct sta_priv *pstapriv = &adapter->stapriv; - struct wlan_network *tgt_network = &pmlmepriv->cur_network; - - pwlan = r8712_find_network(&pmlmepriv->scanned_queue, - tgt_network->network.MacAddress); - - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE)) { - struct sta_info *psta; - - psta = r8712_get_stainfo(&adapter->stapriv, - tgt_network->network.MacAddress); - - spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); - r8712_free_stainfo(adapter, psta); - spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); - } - - if (check_fwstate(pmlmepriv, - WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE)) - r8712_free_all_stainfo(adapter); - if (pwlan) - pwlan->fixed = false; - - if (((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) && - (adapter->stapriv.asoc_sta_count == 1))) - free_network_nolock(pmlmepriv, pwlan); -} - -/* - * r8712_indicate_connect: the caller has to lock pmlmepriv->lock - */ -void r8712_indicate_connect(struct _adapter *padapter) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - pmlmepriv->to_join = false; - set_fwstate(pmlmepriv, _FW_LINKED); - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_LINK); - r8712_os_indicate_connect(padapter); - if (padapter->registrypriv.power_mgnt > PS_MODE_ACTIVE) - mod_timer(&pmlmepriv->dhcp_timer, - jiffies + msecs_to_jiffies(60000)); -} - -/* - * r8712_ind_disconnect: the caller has to lock pmlmepriv->lock - */ -void r8712_ind_disconnect(struct _adapter *padapter) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - _clr_fwstate_(pmlmepriv, _FW_LINKED); - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_NO_LINK); - r8712_os_indicate_disconnect(padapter); - } - if (padapter->pwrctrlpriv.pwr_mode != - padapter->registrypriv.power_mgnt) { - del_timer(&pmlmepriv->dhcp_timer); - r8712_set_ps_mode(padapter, padapter->registrypriv.power_mgnt, - padapter->registrypriv.smart_ps); - } -} - -/*Notes: - *pnetwork : returns from r8712_joinbss_event_callback - *ptarget_wlan: found from scanned_queue - *if join_res > 0, for (fw_state==WIFI_STATION_STATE), we check if - * "ptarget_sta" & "ptarget_wlan" exist. - *if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), we only check - * if "ptarget_wlan" exist. - *if join_res > 0, update "cur_network->network" from - * "pnetwork->network" if (ptarget_wlan !=NULL). - */ -void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) -{ - unsigned long irqL = 0, irqL2; - struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL; - struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct wlan_network *cur_network = &pmlmepriv->cur_network; - struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; - unsigned int the_same_macaddr = false; - struct wlan_network *pnetwork; - - if (sizeof(struct list_head) == 4 * sizeof(u32)) { - pnetwork = kmalloc(sizeof(struct wlan_network), GFP_ATOMIC); - if (!pnetwork) - return; - memcpy((u8 *)pnetwork + 16, (u8 *)pbuf + 8, - sizeof(struct wlan_network) - 16); - } else { - pnetwork = (struct wlan_network *)pbuf; - } - -#ifdef __BIG_ENDIAN - /* endian_convert */ - pnetwork->join_res = le32_to_cpu(pnetwork->join_res); - 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); - 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); - pnetwork->network.Configuration.ATIMWindow = - le32_to_cpu(pnetwork->network.Configuration.ATIMWindow); - pnetwork->network.Configuration.BeaconPeriod = - le32_to_cpu(pnetwork->network.Configuration.BeaconPeriod); - pnetwork->network.Configuration.DSConfig = - le32_to_cpu(pnetwork->network.Configuration.DSConfig); - 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); - 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); - pnetwork->network.Configuration.Length = - le32_to_cpu(pnetwork->network.Configuration.Length); - 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); - pnetwork->network.Length = - 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; - if (pnetwork->join_res > 0) { - if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { - /*s1. find ptarget_wlan*/ - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - if (the_same_macaddr) { - ptarget_wlan = - r8712_find_network(&pmlmepriv->scanned_queue, - cur_network->network.MacAddress); - } else { - pcur_wlan = - 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); - 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); - if (ptarget_wlan) - ptarget_wlan->fixed = true; - } - } else { - ptarget_wlan = r8712_find_network(&pmlmepriv->scanned_queue, - pnetwork->network.MacAddress); - if (ptarget_wlan) - ptarget_wlan->fixed = true; - } - - if (!ptarget_wlan) { - if (check_fwstate(pmlmepriv, - _FW_UNDER_LINKING)) - pmlmepriv->fw_state ^= - _FW_UNDER_LINKING; - goto ignore_joinbss_callback; - } - - /*s2. find ptarget_sta & update ptarget_sta*/ - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - if (the_same_macaddr) { - ptarget_sta = - r8712_get_stainfo(pstapriv, - pnetwork->network.MacAddress); - if (!ptarget_sta) - ptarget_sta = - r8712_alloc_stainfo(pstapriv, - pnetwork->network.MacAddress); - } else { - ptarget_sta = - r8712_alloc_stainfo(pstapriv, - pnetwork->network.MacAddress); - } - if (ptarget_sta) /*update ptarget_sta*/ { - ptarget_sta->aid = pnetwork->join_res; - ptarget_sta->qos_option = 1; - ptarget_sta->mac_id = 5; - if (adapter->securitypriv.AuthAlgrthm == 2) { - adapter->securitypriv.binstallGrpkey = false; - adapter->securitypriv.busetkipkey = false; - adapter->securitypriv.bgrpkey_handshake = false; - ptarget_sta->ieee8021x_blocked = true; - ptarget_sta->XPrivacy = - adapter->securitypriv.PrivacyAlgrthm; - memset((u8 *)&ptarget_sta->x_UncstKey, - 0, - sizeof(union Keytype)); - memset((u8 *)&ptarget_sta->tkiprxmickey, - 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)); - } - } else { - if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) - pmlmepriv->fw_state ^= - _FW_UNDER_LINKING; - goto ignore_joinbss_callback; - } - } - - /*s3. update cur_network & indicate connect*/ - memcpy(&cur_network->network, &pnetwork->network, - pnetwork->network.Length); - cur_network->aid = pnetwork->join_res; - /*update fw_state will clr _FW_UNDER_LINKING*/ - switch (pnetwork->network.InfrastructureMode) { - case Ndis802_11Infrastructure: - pmlmepriv->fw_state = WIFI_STATION_STATE; - break; - case Ndis802_11IBSS: - pmlmepriv->fw_state = WIFI_ADHOC_STATE; - break; - default: - pmlmepriv->fw_state = WIFI_NULL_STATE; - break; - } - r8712_update_protection(adapter, - (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); - /*indicate connect*/ - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) - r8712_indicate_connect(adapter); - del_timer(&pmlmepriv->assoc_timer); - } else { - goto ignore_joinbss_callback; - } - } else { - if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { - mod_timer(&pmlmepriv->assoc_timer, - jiffies + msecs_to_jiffies(1)); - _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); - } - } -ignore_joinbss_callback: - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - if (sizeof(struct list_head) == 4 * sizeof(u32)) - kfree(pnetwork); -} - -void r8712_stassoc_event_callback(struct _adapter *adapter, u8 *pbuf) -{ - unsigned long irqL; - struct sta_info *psta; - struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); - struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf; - - /* to do: */ - if (!r8712_access_ctrl(&adapter->acl_list, pstassoc->macaddr)) - return; - psta = r8712_get_stainfo(&adapter->stapriv, pstassoc->macaddr); - if (psta) { - /*the sta have been in sta_info_queue => do nothing - *(between drv has received this event before and - * fw have not yet to set key to CAM_ENTRY) - */ - return; - } - - psta = r8712_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr); - if (!psta) - return; - /* to do : init sta_info variable */ - psta->qos_option = 0; - psta->mac_id = le32_to_cpu(pstassoc->cam_id); - /* psta->aid = (uint)pstassoc->cam_id; */ - - if (adapter->securitypriv.AuthAlgrthm == 2) - psta->XPrivacy = adapter->securitypriv.PrivacyAlgrthm; - psta->ieee8021x_blocked = false; - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || - check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { - if (adapter->stapriv.asoc_sta_count == 2) { - /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ - r8712_indicate_connect(adapter); - } - } - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); -} - -void r8712_stadel_event_callback(struct _adapter *adapter, u8 *pbuf) -{ - unsigned long irqL, irqL2; - struct sta_info *psta; - struct wlan_network *pwlan = NULL; - struct wlan_bssid_ex *pdev_network = NULL; - u8 *pibss = NULL; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct stadel_event *pstadel = (struct stadel_event *)pbuf; - struct sta_priv *pstapriv = &adapter->stapriv; - struct wlan_network *tgt_network = &pmlmepriv->cur_network; - - spin_lock_irqsave(&pmlmepriv->lock, irqL2); - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - r8712_ind_disconnect(adapter); - r8712_free_assoc_resources(adapter); - } - if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | - WIFI_ADHOC_STATE)) { - psta = r8712_get_stainfo(&adapter->stapriv, pstadel->macaddr); - spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); - r8712_free_stainfo(adapter, psta); - spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); - if (adapter->stapriv.asoc_sta_count == 1) { - /*a sta + bc/mc_stainfo (not Ibss_stainfo) */ - pwlan = r8712_find_network(&pmlmepriv->scanned_queue, - tgt_network->network.MacAddress); - if (pwlan) { - pwlan->fixed = false; - free_network_nolock(pmlmepriv, pwlan); - } - /*re-create ibss*/ - pdev_network = &(adapter->registrypriv.dev_network); - pibss = adapter->registrypriv.dev_network.MacAddress; - memcpy(pdev_network, &tgt_network->network, - r8712_get_wlan_bssid_ex_sz(&tgt_network->network)); - memcpy(&pdev_network->Ssid, - &pmlmepriv->assoc_ssid, - sizeof(struct ndis_802_11_ssid)); - r8712_update_registrypriv_dev_network(adapter); - r8712_generate_random_ibss(pibss); - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { - _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); - set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); - } - } - } - spin_unlock_irqrestore(&pmlmepriv->lock, irqL2); -} - -void r8712_cpwm_event_callback(struct _adapter *adapter, u8 *pbuf) -{ - struct reportpwrstate_parm *preportpwrstate = - (struct reportpwrstate_parm *)pbuf; - - preportpwrstate->state |= (u8)(adapter->pwrctrlpriv.cpwm_tog + 0x80); - r8712_cpwm_int_hdl(adapter, preportpwrstate); -} - -/* When the Netgear 3500 AP is with WPA2PSK-AES mode, it will send - * the ADDBA req frame with start seq control = 0 to wifi client after - * the WPA handshake and the sequence number of following data packet - * will be 0. In this case, the Rx reorder sequence is not longer than 0 - * and the WiFi client will drop the data with seq number 0. - * So, the 8712 firmware has to inform driver with receiving the - * ADDBA-Req frame so that the driver can reset the - * sequence value of Rx reorder control. - */ -void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf) -{ - struct ADDBA_Req_Report_parm *pAddbareq_pram = - (struct ADDBA_Req_Report_parm *)pbuf; - struct sta_info *psta; - struct sta_priv *pstapriv = &adapter->stapriv; - struct recv_reorder_ctrl *precvreorder_ctrl = NULL; - - psta = r8712_get_stainfo(pstapriv, pAddbareq_pram->MacAddress); - if (psta) { - precvreorder_ctrl = - &psta->recvreorder_ctrl[pAddbareq_pram->tid]; - /* set the indicate_seq to 0xffff so that the rx reorder - * can store any following data packet. - */ - precvreorder_ctrl->indicate_seq = 0xffff; - } -} - -void r8712_wpspbc_event_callback(struct _adapter *adapter, u8 *pbuf) -{ - if (!adapter->securitypriv.wps_hw_pbc_pressed) - adapter->securitypriv.wps_hw_pbc_pressed = true; -} - -void _r8712_sitesurvey_ctrl_handler(struct _adapter *adapter) -{ - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct sitesurvey_ctrl *psitesurveyctrl = &pmlmepriv->sitesurveyctrl; - struct registry_priv *pregistrypriv = &adapter->registrypriv; - u64 current_tx_pkts; - uint current_rx_pkts; - - current_tx_pkts = (adapter->xmitpriv.tx_pkts) - - (psitesurveyctrl->last_tx_pkts); - current_rx_pkts = (adapter->recvpriv.rx_pkts) - - (psitesurveyctrl->last_rx_pkts); - psitesurveyctrl->last_tx_pkts = adapter->xmitpriv.tx_pkts; - psitesurveyctrl->last_rx_pkts = adapter->recvpriv.rx_pkts; - if ((current_tx_pkts > pregistrypriv->busy_thresh) || - (current_rx_pkts > pregistrypriv->busy_thresh)) - psitesurveyctrl->traffic_busy = true; - else - psitesurveyctrl->traffic_busy = false; -} - -void _r8712_join_timeout_handler(struct _adapter *adapter) -{ - unsigned long irqL; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - - if (adapter->driver_stopped || adapter->surprise_removed) - return; - spin_lock_irqsave(&pmlmepriv->lock, irqL); - _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); - pmlmepriv->to_join = false; - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - r8712_os_indicate_disconnect(adapter); - _clr_fwstate_(pmlmepriv, _FW_LINKED); - } - if (adapter->pwrctrlpriv.pwr_mode != adapter->registrypriv.power_mgnt) { - r8712_set_ps_mode(adapter, adapter->registrypriv.power_mgnt, - adapter->registrypriv.smart_ps); - } - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); -} - -void r8712_scan_timeout_handler (struct _adapter *adapter) -{ - unsigned long irqL; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - - spin_lock_irqsave(&pmlmepriv->lock, irqL); - _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); - pmlmepriv->to_join = false; /* scan fail, so clear to_join flag */ - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); -} - -void _r8712_dhcp_timeout_handler (struct _adapter *adapter) -{ - if (adapter->driver_stopped || adapter->surprise_removed) - return; - if (adapter->pwrctrlpriv.pwr_mode != adapter->registrypriv.power_mgnt) - r8712_set_ps_mode(adapter, adapter->registrypriv.power_mgnt, - adapter->registrypriv.smart_ps); -} - -int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv) -{ - struct list_head *phead; - unsigned char *dst_ssid, *src_ssid; - struct _adapter *adapter; - struct __queue *queue = NULL; - struct wlan_network *pnetwork = NULL; - struct wlan_network *pnetwork_max_rssi = NULL; - - adapter = (struct _adapter *)pmlmepriv->nic_hdl; - queue = &pmlmepriv->scanned_queue; - phead = &queue->queue; - pmlmepriv->pscanned = phead->next; - while (1) { - if (end_of_queue_search(phead, pmlmepriv->pscanned)) { - if (pmlmepriv->assoc_by_rssi && pnetwork_max_rssi) { - pnetwork = pnetwork_max_rssi; - goto ask_for_joinbss; - } - return -EINVAL; - } - pnetwork = container_of(pmlmepriv->pscanned, - struct wlan_network, list); - pmlmepriv->pscanned = pmlmepriv->pscanned->next; - if (pmlmepriv->assoc_by_bssid) { - dst_ssid = pnetwork->network.MacAddress; - src_ssid = pmlmepriv->assoc_bssid; - if (!memcmp(dst_ssid, src_ssid, ETH_ALEN)) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - if (is_same_network(&pmlmepriv->cur_network.network, - &pnetwork->network)) { - _clr_fwstate_(pmlmepriv, - _FW_UNDER_LINKING); - /*r8712_indicate_connect again*/ - r8712_indicate_connect(adapter); - return 2; - } - r8712_disassoc_cmd(adapter); - r8712_ind_disconnect(adapter); - r8712_free_assoc_resources(adapter); - } - goto ask_for_joinbss; - } - } else if (pmlmepriv->assoc_ssid.SsidLength == 0) { - goto ask_for_joinbss; - } - dst_ssid = pnetwork->network.Ssid.Ssid; - src_ssid = pmlmepriv->assoc_ssid.Ssid; - if ((pnetwork->network.Ssid.SsidLength == - pmlmepriv->assoc_ssid.SsidLength) && - (!memcmp(dst_ssid, src_ssid, - pmlmepriv->assoc_ssid.SsidLength))) { - if (pmlmepriv->assoc_by_rssi) { - /* if the ssid is the same, select the bss - * which has the max rssi - */ - if (pnetwork_max_rssi) { - if (pnetwork->network.Rssi > - pnetwork_max_rssi->network.Rssi) - pnetwork_max_rssi = pnetwork; - } else { - pnetwork_max_rssi = pnetwork; - } - } else if (is_desired_network(adapter, pnetwork)) { - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - r8712_disassoc_cmd(adapter); - r8712_free_assoc_resources(adapter); - } - goto ask_for_joinbss; - } - } - } - -ask_for_joinbss: - return r8712_joinbss_cmd(adapter, pnetwork); -} - -int r8712_set_auth(struct _adapter *adapter, - struct security_priv *psecuritypriv) -{ - struct cmd_priv *pcmdpriv = &adapter->cmdpriv; - struct cmd_obj *pcmd; - struct setauth_parm *psetauthparm; - - pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); - if (!pcmd) - return -ENOMEM; - - psetauthparm = kzalloc(sizeof(*psetauthparm), GFP_ATOMIC); - if (!psetauthparm) { - kfree(pcmd); - return -ENOMEM; - } - psetauthparm->mode = (u8)psecuritypriv->AuthAlgrthm; - pcmd->cmdcode = _SetAuth_CMD_; - pcmd->parmbuf = (unsigned char *)psetauthparm; - pcmd->cmdsz = sizeof(struct setauth_parm); - pcmd->rsp = NULL; - pcmd->rspsz = 0; - INIT_LIST_HEAD(&pcmd->list); - r8712_enqueue_cmd(pcmdpriv, pcmd); - return 0; -} - -int r8712_set_key(struct _adapter *adapter, - struct security_priv *psecuritypriv, - sint keyid) -{ - struct cmd_priv *pcmdpriv = &adapter->cmdpriv; - struct cmd_obj *pcmd; - struct setkey_parm *psetkeyparm; - u8 keylen; - int ret; - - pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); - if (!pcmd) - return -ENOMEM; - psetkeyparm = kzalloc(sizeof(*psetkeyparm), GFP_ATOMIC); - if (!psetkeyparm) { - ret = -ENOMEM; - goto err_free_cmd; - } - if (psecuritypriv->AuthAlgrthm == 2) { /* 802.1X */ - psetkeyparm->algorithm = - (u8)psecuritypriv->XGrpPrivacy; - } else { /* WEP */ - psetkeyparm->algorithm = - (u8)psecuritypriv->PrivacyAlgrthm; - } - psetkeyparm->keyid = (u8)keyid; - - switch (psetkeyparm->algorithm) { - case _WEP40_: - keylen = 5; - memcpy(psetkeyparm->key, - psecuritypriv->DefKey[keyid].skey, keylen); - break; - case _WEP104_: - keylen = 13; - memcpy(psetkeyparm->key, - psecuritypriv->DefKey[keyid].skey, keylen); - break; - case _TKIP_: - if (keyid < 1 || keyid > 2) { - ret = -EINVAL; - goto err_free_parm; - } - keylen = 16; - memcpy(psetkeyparm->key, - &psecuritypriv->XGrpKey[keyid - 1], keylen); - psetkeyparm->grpkey = 1; - break; - case _AES_: - if (keyid < 1 || keyid > 2) { - ret = -EINVAL; - goto err_free_parm; - } - keylen = 16; - memcpy(psetkeyparm->key, - &psecuritypriv->XGrpKey[keyid - 1], keylen); - psetkeyparm->grpkey = 1; - break; - default: - ret = -EINVAL; - goto err_free_parm; - } - pcmd->cmdcode = _SetKey_CMD_; - pcmd->parmbuf = (u8 *)psetkeyparm; - pcmd->cmdsz = (sizeof(struct setkey_parm)); - pcmd->rsp = NULL; - pcmd->rspsz = 0; - INIT_LIST_HEAD(&pcmd->list); - r8712_enqueue_cmd(pcmdpriv, pcmd); - return 0; - -err_free_parm: - kfree(psetkeyparm); -err_free_cmd: - kfree(pcmd); - return ret; -} - -/* adjust IEs for r8712_joinbss_cmd in WMM */ -int r8712_restruct_wmm_ie(struct _adapter *adapter, u8 *in_ie, u8 *out_ie, - uint in_len, uint initial_out_len) -{ - unsigned int ielength = 0; - unsigned int i, j; - - i = 12; /* after the fixed IE */ - while (i < in_len) { - ielength = initial_out_len; - if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 && - in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 && - in_ie[i + 5] == 0x02 && i + 5 < in_len) { - /*WMM element ID and OUI*/ - for (j = i; j < i + 9; j++) { - out_ie[ielength] = in_ie[j]; - ielength++; - } - out_ie[initial_out_len + 1] = 0x07; - out_ie[initial_out_len + 6] = 0x00; - out_ie[initial_out_len + 8] = 0x00; - break; - } - i += (in_ie[i + 1] + 2); /* to the next IE element */ - } - return ielength; -} - -/* - * Ported from 8185: IsInPreAuthKeyList(). - * - * Search by BSSID, - * Return Value: - * -1 :if there is no pre-auth key in the table - * >=0 :if there is pre-auth key, and return the entry id - */ -static int SecIsInPMKIDList(struct _adapter *Adapter, u8 *bssid) -{ - struct security_priv *p = &Adapter->securitypriv; - int i; - - for (i = 0; i < NUM_PMKID_CACHE; i++) - if (p->PMKIDList[i].bUsed && !memcmp(p->PMKIDList[i].Bssid, bssid, ETH_ALEN)) - return i; - return -1; -} - -sint r8712_restruct_sec_ie(struct _adapter *adapter, u8 *in_ie, - u8 *out_ie, uint in_len) -{ - u8 authmode = 0, match; - u8 sec_ie[IW_CUSTOM_MAX], uncst_oui[4], bkup_ie[255]; - u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; - uint ielength, cnt, remove_cnt; - int iEntry; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - struct security_priv *psecuritypriv = &adapter->securitypriv; - uint ndisauthmode = psecuritypriv->ndisauthtype; - uint ndissecuritytype = psecuritypriv->ndisencryptstatus; - - if ((ndisauthmode == Ndis802_11AuthModeWPA) || - (ndisauthmode == Ndis802_11AuthModeWPAPSK)) { - authmode = _WPA_IE_ID_; - uncst_oui[0] = 0x0; - uncst_oui[1] = 0x50; - uncst_oui[2] = 0xf2; - } - if ((ndisauthmode == Ndis802_11AuthModeWPA2) || - (ndisauthmode == Ndis802_11AuthModeWPA2PSK)) { - authmode = _WPA2_IE_ID_; - uncst_oui[0] = 0x0; - uncst_oui[1] = 0x0f; - uncst_oui[2] = 0xac; - } - switch (ndissecuritytype) { - case Ndis802_11Encryption1Enabled: - case Ndis802_11Encryption1KeyAbsent: - uncst_oui[3] = 0x1; - break; - case Ndis802_11Encryption2Enabled: - case Ndis802_11Encryption2KeyAbsent: - uncst_oui[3] = 0x2; - break; - case Ndis802_11Encryption3Enabled: - case Ndis802_11Encryption3KeyAbsent: - uncst_oui[3] = 0x4; - break; - default: - break; - } - /*Search required WPA or WPA2 IE and copy to sec_ie[] */ - cnt = 12; - match = false; - while (cnt < in_len) { - if (in_ie[cnt] == authmode) { - if ((authmode == _WPA_IE_ID_) && - (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) { - memcpy(&sec_ie[0], &in_ie[cnt], - in_ie[cnt + 1] + 2); - match = true; - break; - } - if (authmode == _WPA2_IE_ID_) { - memcpy(&sec_ie[0], &in_ie[cnt], - in_ie[cnt + 1] + 2); - match = true; - break; - } - if (((authmode == _WPA_IE_ID_) && - (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) || - (authmode == _WPA2_IE_ID_)) - memcpy(&bkup_ie[0], &in_ie[cnt], - in_ie[cnt + 1] + 2); - } - cnt += in_ie[cnt + 1] + 2; /*get next*/ - } - /*restruct WPA IE or WPA2 IE in sec_ie[] */ - if (match) { - if (sec_ie[0] == _WPA_IE_ID_) { - /* parsing SSN IE to select required encryption - * algorithm, and set the bc/mc encryption algorithm - */ - while (true) { - /*check wpa_oui tag*/ - if (memcmp(&sec_ie[2], &wpa_oui[0], 4)) { - match = false; - break; - } - if ((sec_ie[6] != 0x01) || (sec_ie[7] != 0x0)) { - /*IE Ver error*/ - match = false; - break; - } - if (!memcmp(&sec_ie[8], &wpa_oui[0], 3)) { - /* get bc/mc encryption type (group - * key type) - */ - switch (sec_ie[11]) { - case 0x0: /*none*/ - psecuritypriv->XGrpPrivacy = - _NO_PRIVACY_; - break; - case 0x1: /*WEP_40*/ - psecuritypriv->XGrpPrivacy = - _WEP40_; - break; - case 0x2: /*TKIP*/ - psecuritypriv->XGrpPrivacy = - _TKIP_; - break; - case 0x3: /*AESCCMP*/ - case 0x4: - psecuritypriv->XGrpPrivacy = - _AES_; - break; - case 0x5: /*WEP_104*/ - psecuritypriv->XGrpPrivacy = - _WEP104_; - break; - } - } else { - match = false; - break; - } - if (sec_ie[12] == 0x01) { - /*check the unicast encryption type*/ - if (memcmp(&sec_ie[14], - &uncst_oui[0], 4)) { - match = false; - break; - - } /*else the uncst_oui is match*/ - } else { /*mixed mode, unicast_enc_type > 1*/ - /*select the uncst_oui and remove - * the other uncst_oui - */ - cnt = sec_ie[12]; - remove_cnt = (cnt - 1) * 4; - sec_ie[12] = 0x01; - memcpy(&sec_ie[14], &uncst_oui[0], 4); - /*remove the other unicast suit*/ - memcpy(&sec_ie[18], - &sec_ie[18 + remove_cnt], - sec_ie[1] - 18 + 2 - - remove_cnt); - sec_ie[1] = sec_ie[1] - remove_cnt; - } - break; - } - } - if (authmode == _WPA2_IE_ID_) { - /* parsing RSN IE to select required encryption - * algorithm, and set the bc/mc encryption algorithm - */ - while (true) { - if ((sec_ie[2] != 0x01) || (sec_ie[3] != 0x0)) { - /*IE Ver error*/ - match = false; - break; - } - if (!memcmp(&sec_ie[4], &uncst_oui[0], 3)) { - /*get bc/mc encryption type*/ - switch (sec_ie[7]) { - case 0x1: /*WEP_40*/ - psecuritypriv->XGrpPrivacy = - _WEP40_; - break; - case 0x2: /*TKIP*/ - psecuritypriv->XGrpPrivacy = - _TKIP_; - break; - case 0x4: /*AESWRAP*/ - psecuritypriv->XGrpPrivacy = - _AES_; - break; - case 0x5: /*WEP_104*/ - psecuritypriv->XGrpPrivacy = - _WEP104_; - break; - default: /*one*/ - psecuritypriv->XGrpPrivacy = - _NO_PRIVACY_; - break; - } - } else { - match = false; - break; - } - if (sec_ie[8] == 0x01) { - /*check the unicast encryption type*/ - if (memcmp(&sec_ie[10], - &uncst_oui[0], 4)) { - match = false; - break; - } /*else the uncst_oui is match*/ - } else { /*mixed mode, unicast_enc_type > 1*/ - /*select the uncst_oui and remove the - * other uncst_oui - */ - cnt = sec_ie[8]; - remove_cnt = (cnt - 1) * 4; - sec_ie[8] = 0x01; - memcpy(&sec_ie[10], &uncst_oui[0], 4); - /*remove the other unicast suit*/ - memcpy(&sec_ie[14], - &sec_ie[14 + remove_cnt], - (sec_ie[1] - 14 + 2 - - remove_cnt)); - sec_ie[1] = sec_ie[1] - remove_cnt; - } - break; - } - } - } - if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) { - /*copy fixed ie*/ - memcpy(out_ie, in_ie, 12); - ielength = 12; - /*copy RSN or SSN*/ - if (match) { - memcpy(&out_ie[ielength], &sec_ie[0], sec_ie[1] + 2); - ielength += sec_ie[1] + 2; - if (authmode == _WPA2_IE_ID_) { - /*the Pre-Authentication bit should be zero*/ - out_ie[ielength - 1] = 0; - out_ie[ielength - 2] = 0; - } - r8712_report_sec_ie(adapter, authmode, sec_ie); - } - } else { - /*copy fixed ie only*/ - memcpy(out_ie, in_ie, 12); - ielength = 12; - if (psecuritypriv->wps_phase) { - memcpy(out_ie + ielength, psecuritypriv->wps_ie, - psecuritypriv->wps_ie_len); - ielength += psecuritypriv->wps_ie_len; - } - } - iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); - if (iEntry < 0) - return ielength; - if (authmode == _WPA2_IE_ID_) { - out_ie[ielength] = 1; - ielength++; - out_ie[ielength] = 0; /*PMKID count = 0x0100*/ - ielength++; - memcpy(&out_ie[ielength], - &psecuritypriv->PMKIDList[iEntry].PMKID, 16); - ielength += 16; - out_ie[13] += 18;/*PMKID length = 2+16*/ - } - return ielength; -} - -void r8712_init_registrypriv_dev_network(struct _adapter *adapter) -{ - struct registry_priv *pregistrypriv = &adapter->registrypriv; - struct eeprom_priv *peepriv = &adapter->eeprompriv; - struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; - u8 *myhwaddr = myid(peepriv); - - memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN); - memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, - sizeof(struct ndis_802_11_ssid)); - pdev_network->Configuration.Length = - sizeof(struct NDIS_802_11_CONFIGURATION); - pdev_network->Configuration.BeaconPeriod = 100; - pdev_network->Configuration.FHConfig.Length = 0; - pdev_network->Configuration.FHConfig.HopPattern = 0; - pdev_network->Configuration.FHConfig.HopSet = 0; - pdev_network->Configuration.FHConfig.DwellTime = 0; -} - -void r8712_update_registrypriv_dev_network(struct _adapter *adapter) -{ - int sz = 0; - struct registry_priv *pregistrypriv = &adapter->registrypriv; - struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; - struct security_priv *psecuritypriv = &adapter->securitypriv; - struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; - - pdev_network->Privacy = cpu_to_le32(psecuritypriv->PrivacyAlgrthm - > 0 ? 1 : 0); /* adhoc no 802.1x */ - pdev_network->Rssi = 0; - switch (pregistrypriv->wireless_mode) { - case WIRELESS_11B: - pdev_network->NetworkTypeInUse = Ndis802_11DS; - break; - case WIRELESS_11G: - case WIRELESS_11BG: - pdev_network->NetworkTypeInUse = Ndis802_11OFDM24; - break; - case WIRELESS_11A: - pdev_network->NetworkTypeInUse = Ndis802_11OFDM5; - break; - default: - /* TODO */ - break; - } - pdev_network->Configuration.DSConfig = pregistrypriv->channel; - if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) - pdev_network->Configuration.ATIMWindow = 3; - pdev_network->InfrastructureMode = cur_network->network.InfrastructureMode; - /* 1. Supported rates - * 2. IE - */ - sz = r8712_generate_ie(pregistrypriv); - pdev_network->IELength = sz; - pdev_network->Length = r8712_get_wlan_bssid_ex_sz(pdev_network); -} - -/*the function is at passive_level*/ -void r8712_joinbss_reset(struct _adapter *padapter) -{ - int i; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - - /* todo: if you want to do something io/reg/hw setting before join_bss, - * please add code here - */ - phtpriv->ampdu_enable = false;/*reset to disabled*/ - for (i = 0; i < 16; i++) - phtpriv->baddbareq_issued[i] = false;/*reset it*/ - if (phtpriv->ht_option) { - /* validate usb rx aggregation */ - r8712_write8(padapter, 0x102500D9, 48);/*TH = 48 pages, 6k*/ - } else { - /* invalidate usb rx aggregation */ - /* TH=1 => means that invalidate usb rx aggregation */ - r8712_write8(padapter, 0x102500D9, 1); - } -} - -/*the function is >= passive_level*/ -unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie, - u8 *out_ie, uint in_len, uint *pout_len) -{ - u32 ielen, out_len; - unsigned char *p; - struct ieee80211_ht_cap ht_capie; - unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct qos_priv *pqospriv = &pmlmepriv->qospriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - - phtpriv->ht_option = 0; - p = r8712_get_ie(in_ie + 12, WLAN_EID_HT_CAPABILITY, &ielen, in_len - 12); - if (p && (ielen > 0)) { - if (pqospriv->qos_option == 0) { - out_len = *pout_len; - r8712_set_ie(out_ie + out_len, WLAN_EID_VENDOR_SPECIFIC, - _WMM_IE_Length_, WMM_IE, pout_len); - pqospriv->qos_option = 1; - } - out_len = *pout_len; - memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap)); - ht_capie.cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40 | - IEEE80211_HT_CAP_TX_STBC | - IEEE80211_HT_CAP_MAX_AMSDU | - IEEE80211_HT_CAP_DSSSCCK40); - ht_capie.ampdu_params_info = (IEEE80211_HT_AMPDU_PARM_FACTOR & - 0x03) | (IEEE80211_HT_AMPDU_PARM_DENSITY & 0x00); - r8712_set_ie(out_ie + out_len, WLAN_EID_HT_CAPABILITY, - sizeof(struct ieee80211_ht_cap), - (unsigned char *)&ht_capie, pout_len); - phtpriv->ht_option = 1; - } - return phtpriv->ht_option; -} - -/* the function is > passive_level (in critical_section) */ -static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) -{ - u8 *p, max_ampdu_sz; - int i; - uint len; - struct sta_info *bmc_sta, *psta; - struct ieee80211_ht_cap *pht_capie; - struct recv_reorder_ctrl *preorder_ctrl; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - struct registry_priv *pregistrypriv = &padapter->registrypriv; - struct wlan_network *pcur_network = &(pmlmepriv->cur_network); - - if (!phtpriv->ht_option) - return; - /* maybe needs check if ap supports rx ampdu. */ - if (!phtpriv->ampdu_enable && - (pregistrypriv->ampdu_enable == 1)) - phtpriv->ampdu_enable = true; - /*check Max Rx A-MPDU Size*/ - len = 0; - p = r8712_get_ie(pie + sizeof(struct NDIS_802_11_FIXED_IEs), - WLAN_EID_HT_CAPABILITY, - &len, ie_len - - sizeof(struct NDIS_802_11_FIXED_IEs)); - if (p && len > 0) { - pht_capie = (struct ieee80211_ht_cap *)(p + 2); - max_ampdu_sz = (pht_capie->ampdu_params_info & - IEEE80211_HT_AMPDU_PARM_FACTOR); - /* max_ampdu_sz (kbytes); */ - max_ampdu_sz = 1 << (max_ampdu_sz + 3); - phtpriv->rx_ampdu_maxlen = max_ampdu_sz; - } - /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info - * if A-MPDU Rx is enabled, resetting rx_ordering_ctrl - * wstart_b(indicate_seq) to default value=0xffff - * todo: check if AP can send A-MPDU packets - */ - bmc_sta = r8712_get_bcmc_stainfo(padapter); - if (bmc_sta) { - for (i = 0; i < 16; i++) { - preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; - preorder_ctrl->indicate_seq = 0xffff; - preorder_ctrl->wend_b = 0xffff; - } - } - psta = r8712_get_stainfo(&padapter->stapriv, - pcur_network->network.MacAddress); - if (psta) { - for (i = 0; i < 16; i++) { - preorder_ctrl = &psta->recvreorder_ctrl[i]; - preorder_ctrl->indicate_seq = 0xffff; - preorder_ctrl->wend_b = 0xffff; - } - } - len = 0; - p = r8712_get_ie(pie + sizeof(struct NDIS_802_11_FIXED_IEs), - WLAN_EID_HT_OPERATION, &len, - ie_len - sizeof(struct NDIS_802_11_FIXED_IEs)); -} - -void r8712_issue_addbareq_cmd(struct _adapter *padapter, int priority) -{ - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; - - if ((phtpriv->ht_option == 1) && (phtpriv->ampdu_enable)) { - if (!phtpriv->baddbareq_issued[priority]) { - r8712_addbareq_cmd(padapter, (u8)priority); - phtpriv->baddbareq_issued[priority] = true; - } - } -} diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h deleted file mode 100644 index d7d25f240111fa..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_mlme.h +++ /dev/null @@ -1,205 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL871X_MLME_H_ -#define __RTL871X_MLME_H_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "wlan_bssdef.h" - -#define MAX_BSS_CNT 64 -#define MAX_JOIN_TIMEOUT 6000 - -#define SCANNING_TIMEOUT 4500 - -#define SCANQUEUE_LIFETIME 20 /* unit:sec */ - -#define WIFI_NULL_STATE 0x00000000 -#define WIFI_ASOC_STATE 0x00000001 /* Under Linked state...*/ -#define WIFI_REASOC_STATE 0x00000002 -#define WIFI_SLEEP_STATE 0x00000004 -#define WIFI_STATION_STATE 0x00000008 -#define WIFI_AP_STATE 0x00000010 -#define WIFI_ADHOC_STATE 0x00000020 -#define WIFI_ADHOC_MASTER_STATE 0x00000040 -#define WIFI_UNDER_LINKING 0x00000080 -#define WIFI_SITE_MONITOR 0x00000800 /* to indicate the station - * is under site surveying - */ -#define WIFI_MP_STATE 0x00010000 -#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in cont. tx background*/ -#define WIFI_MP_CTX_ST 0x00040000 /* in cont. tx with - * single-tone - */ -#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in cont, tx - * background due - * to out of skb - */ -#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continuous tx*/ -#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in cont, tx with carrier - * suppression - */ -#define WIFI_MP_LPBK_STATE 0x00400000 - -#define _FW_UNDER_LINKING WIFI_UNDER_LINKING -#define _FW_LINKED WIFI_ASOC_STATE -#define _FW_UNDER_SURVEY WIFI_SITE_MONITOR - -/* - * there are several "locks" in mlme_priv, - * since mlme_priv is a shared resource between many threads, - * like ISR/Call-Back functions, the OID handlers, and even timer functions. - * Each _queue has its own locks, already. - * Other items are protected by mlme_priv.lock. - * To avoid possible dead lock, any thread trying to modify mlme_priv - * SHALL not lock up more than one lock at a time! - */ - -#define traffic_threshold 10 -#define traffic_scan_period 500 - -struct sitesurvey_ctrl { - u64 last_tx_pkts; - uint last_rx_pkts; - sint traffic_busy; - struct timer_list sitesurvey_ctrl_timer; -}; - -struct mlme_priv { - spinlock_t lock; - spinlock_t lock2; - sint fw_state; /*shall we protect this variable? */ - u8 to_join; /*flag*/ - u8 *nic_hdl; - struct list_head *pscanned; - struct __queue free_bss_pool; - struct __queue scanned_queue; - u8 *free_bss_buf; - unsigned long num_of_scanned; - u8 passive_mode; /*add for Android's SCAN-ACTIVE/SCAN-PASSIVE */ - struct ndis_802_11_ssid assoc_ssid; - u8 assoc_bssid[6]; - struct wlan_network cur_network; - struct sitesurvey_ctrl sitesurveyctrl; - struct timer_list assoc_timer; - uint assoc_by_bssid; - uint assoc_by_rssi; - struct timer_list scan_to_timer; /* driver handles scan_timeout.*/ - struct timer_list dhcp_timer; /* set dhcp to if driver in ps mode.*/ - struct qos_priv qospriv; - struct ht_priv htpriv; - struct timer_list wdg_timer; /*watchdog periodic timer*/ -}; - -static inline u8 *get_bssid(struct mlme_priv *pmlmepriv) -{ - return pmlmepriv->cur_network.network.MacAddress; -} - -static inline u8 check_fwstate(struct mlme_priv *pmlmepriv, sint state) -{ - if (pmlmepriv->fw_state & state) - return true; - return false; -} - -static inline sint get_fwstate(struct mlme_priv *pmlmepriv) -{ - return pmlmepriv->fw_state; -} - -/* - * No Limit on the calling context, - * therefore set it to be the critical section... - * - * ### NOTE:#### (!!!!) - * TAKE CARE BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock - */ -static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state) -{ - pmlmepriv->fw_state |= state; -} - -static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state) -{ - pmlmepriv->fw_state &= ~state; -} - -/* - * No Limit on the calling context, - * therefore set it to be the critical section... - */ -static inline void clr_fwstate(struct mlme_priv *pmlmepriv, sint state) -{ - unsigned long irqL; - - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (check_fwstate(pmlmepriv, state)) - pmlmepriv->fw_state ^= state; - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); -} - -static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, - sint val) -{ - unsigned long irqL; - - spin_lock_irqsave(&pmlmepriv->lock, irqL); - pmlmepriv->num_of_scanned = val; - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); -} - -void r8712_survey_event_callback(struct _adapter *adapter, u8 *pbuf); -void r8712_surveydone_event_callback(struct _adapter *adapter, u8 *pbuf); -void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf); -void r8712_stassoc_event_callback(struct _adapter *adapter, u8 *pbuf); -void r8712_stadel_event_callback(struct _adapter *adapter, u8 *pbuf); -void r8712_atimdone_event_callback(struct _adapter *adapter, u8 *pbuf); -void r8712_cpwm_event_callback(struct _adapter *adapter, u8 *pbuf); -void r8712_wpspbc_event_callback(struct _adapter *adapter, u8 *pbuf); -void r8712_free_network_queue(struct _adapter *adapter); -int r8712_init_mlme_priv(struct _adapter *adapter); -void r8712_free_mlme_priv(struct mlme_priv *pmlmepriv); -int r8712_select_and_join_from_scan(struct mlme_priv *pmlmepriv); -int r8712_set_key(struct _adapter *adapter, - struct security_priv *psecuritypriv, sint keyid); -int r8712_set_auth(struct _adapter *adapter, - struct security_priv *psecuritypriv); -uint r8712_get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss); -void r8712_generate_random_ibss(u8 *pibss); -u8 *r8712_get_capability_from_ie(u8 *ie); -struct wlan_network *r8712_get_oldest_wlan_network( - struct __queue *scanned_queue); -void r8712_free_assoc_resources(struct _adapter *adapter); -void r8712_ind_disconnect(struct _adapter *adapter); -void r8712_indicate_connect(struct _adapter *adapter); -int r8712_restruct_sec_ie(struct _adapter *adapter, u8 *in_ie, - u8 *out_ie, uint in_len); -int r8712_restruct_wmm_ie(struct _adapter *adapter, u8 *in_ie, - u8 *out_ie, uint in_len, uint initial_out_len); -void r8712_init_registrypriv_dev_network(struct _adapter *adapter); -void r8712_update_registrypriv_dev_network(struct _adapter *adapter); -void _r8712_sitesurvey_ctrl_handler(struct _adapter *adapter); -void _r8712_join_timeout_handler(struct _adapter *adapter); -void r8712_scan_timeout_handler(struct _adapter *adapter); -void _r8712_dhcp_timeout_handler(struct _adapter *adapter); -struct wlan_network *_r8712_alloc_network(struct mlme_priv *pmlmepriv); -sint r8712_if_up(struct _adapter *padapter); -void r8712_joinbss_reset(struct _adapter *padapter); -unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie, - u8 *out_ie, uint in_len, uint *pout_len); -void r8712_issue_addbareq_cmd(struct _adapter *padapter, int priority); -int r8712_is_same_ibss(struct _adapter *adapter, struct wlan_network *pnetwork); - -#endif /*__RTL871X_MLME_H_*/ diff --git a/drivers/staging/rtl8712/rtl871x_mp.c b/drivers/staging/rtl8712/rtl871x_mp.c deleted file mode 100644 index 099c512c8519fa..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_mp.c +++ /dev/null @@ -1,724 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#define _RTL871X_MP_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "rtl871x_mp_phy_regdef.h" -#include "rtl8712_cmd.h" - -static void _init_mp_priv_(struct mp_priv *pmp_priv) -{ - pmp_priv->mode = _LOOPBOOK_MODE_; - pmp_priv->curr_ch = 1; - pmp_priv->curr_modem = MIXED_PHY; - pmp_priv->curr_rateidx = 0; - pmp_priv->curr_txpoweridx = 0x14; - pmp_priv->antenna_tx = ANTENNA_A; - pmp_priv->antenna_rx = ANTENNA_AB; - pmp_priv->check_mp_pkt = 0; - pmp_priv->tx_pktcount = 0; - pmp_priv->rx_pktcount = 0; - pmp_priv->rx_crcerrpktcount = 0; -} - -static int init_mp_priv(struct mp_priv *pmp_priv) -{ - int i; - struct mp_xmit_frame *pmp_xmitframe; - - _init_mp_priv_(pmp_priv); - _init_queue(&pmp_priv->free_mp_xmitqueue); - pmp_priv->pallocated_mp_xmitframe_buf = NULL; - pmp_priv->pallocated_mp_xmitframe_buf = kmalloc(NR_MP_XMITFRAME * - sizeof(struct mp_xmit_frame) + 4, - GFP_ATOMIC); - if (!pmp_priv->pallocated_mp_xmitframe_buf) - return -ENOMEM; - - pmp_priv->pmp_xmtframe_buf = pmp_priv->pallocated_mp_xmitframe_buf + - 4 - - ((addr_t)(pmp_priv->pallocated_mp_xmitframe_buf) & 3); - pmp_xmitframe = (struct mp_xmit_frame *)pmp_priv->pmp_xmtframe_buf; - for (i = 0; i < NR_MP_XMITFRAME; i++) { - INIT_LIST_HEAD(&(pmp_xmitframe->list)); - list_add_tail(&(pmp_xmitframe->list), - &(pmp_priv->free_mp_xmitqueue.queue)); - pmp_xmitframe->pkt = NULL; - pmp_xmitframe->frame_tag = MP_FRAMETAG; - pmp_xmitframe->padapter = pmp_priv->papdater; - pmp_xmitframe++; - } - pmp_priv->free_mp_xmitframe_cnt = NR_MP_XMITFRAME; - return 0; -} - -static int free_mp_priv(struct mp_priv *pmp_priv) -{ - kfree(pmp_priv->pallocated_mp_xmitframe_buf); - return 0; -} - -void mp871xinit(struct _adapter *padapter) -{ - struct mp_priv *pmppriv = &padapter->mppriv; - - pmppriv->papdater = padapter; - init_mp_priv(pmppriv); -} - -void mp871xdeinit(struct _adapter *padapter) -{ - struct mp_priv *pmppriv = &padapter->mppriv; - - free_mp_priv(pmppriv); -} - -/* - * Special for bb and rf reg read/write - */ -static u32 fw_iocmd_read(struct _adapter *pAdapter, struct IOCMD_STRUCT iocmd) -{ - u32 cmd32 = 0, val32 = 0; - u8 iocmd_class = iocmd.cmdclass; - u16 iocmd_value = iocmd.value; - u8 iocmd_idx = iocmd.index; - - cmd32 = (iocmd_class << 24) | (iocmd_value << 8) | iocmd_idx; - if (r8712_fw_cmd(pAdapter, cmd32)) - r8712_fw_cmd_data(pAdapter, &val32, 1); - else - val32 = 0; - return val32; -} - -static u8 fw_iocmd_write(struct _adapter *pAdapter, - struct IOCMD_STRUCT iocmd, u32 value) -{ - u32 cmd32 = 0; - u8 iocmd_class = iocmd.cmdclass; - u32 iocmd_value = iocmd.value; - u8 iocmd_idx = iocmd.index; - - r8712_fw_cmd_data(pAdapter, &value, 0); - msleep(100); - cmd32 = (iocmd_class << 24) | (iocmd_value << 8) | iocmd_idx; - return r8712_fw_cmd(pAdapter, cmd32); -} - -/* offset : 0X800~0XFFF */ -u32 r8712_bb_reg_read(struct _adapter *pAdapter, u16 offset) -{ - u8 shift = offset & 0x0003; /* 4 byte access */ - u16 bb_addr = offset & 0x0FFC; /* 4 byte access */ - u32 bb_val = 0; - struct IOCMD_STRUCT iocmd; - - iocmd.cmdclass = IOCMD_CLASS_BB_RF; - iocmd.value = bb_addr; - iocmd.index = IOCMD_BB_READ_IDX; - bb_val = fw_iocmd_read(pAdapter, iocmd); - if (shift != 0) { - u32 bb_val2 = 0; - - bb_val >>= (shift * 8); - iocmd.value += 4; - bb_val2 = fw_iocmd_read(pAdapter, iocmd); - bb_val2 <<= ((4 - shift) * 8); - bb_val |= bb_val2; - } - return bb_val; -} - -/* offset : 0X800~0XFFF */ -u8 r8712_bb_reg_write(struct _adapter *pAdapter, u16 offset, u32 value) -{ - u8 shift = offset & 0x0003; /* 4 byte access */ - u16 bb_addr = offset & 0x0FFC; /* 4 byte access */ - struct IOCMD_STRUCT iocmd; - - iocmd.cmdclass = IOCMD_CLASS_BB_RF; - iocmd.value = bb_addr; - iocmd.index = IOCMD_BB_WRITE_IDX; - if (shift != 0) { - u32 oldValue = 0; - u32 newValue = value; - - oldValue = r8712_bb_reg_read(pAdapter, iocmd.value); - oldValue &= (0xFFFFFFFF >> ((4 - shift) * 8)); - value = oldValue | (newValue << (shift * 8)); - if (!fw_iocmd_write(pAdapter, iocmd, value)) - return false; - iocmd.value += 4; - oldValue = r8712_bb_reg_read(pAdapter, iocmd.value); - oldValue &= (0xFFFFFFFF << (shift * 8)); - value = oldValue | (newValue >> ((4 - shift) * 8)); - } - return fw_iocmd_write(pAdapter, iocmd, value); -} - -/* offset : 0x00 ~ 0xFF */ -u32 r8712_rf_reg_read(struct _adapter *pAdapter, u8 path, u8 offset) -{ - u16 rf_addr = (path << 8) | offset; - struct IOCMD_STRUCT iocmd; - - iocmd.cmdclass = IOCMD_CLASS_BB_RF; - iocmd.value = rf_addr; - iocmd.index = IOCMD_RF_READ_IDX; - return fw_iocmd_read(pAdapter, iocmd); -} - -u8 r8712_rf_reg_write(struct _adapter *pAdapter, u8 path, u8 offset, u32 value) -{ - u16 rf_addr = (path << 8) | offset; - struct IOCMD_STRUCT iocmd; - - iocmd.cmdclass = IOCMD_CLASS_BB_RF; - iocmd.value = rf_addr; - iocmd.index = IOCMD_RF_WRIT_IDX; - return fw_iocmd_write(pAdapter, iocmd, value); -} - -static u32 bitshift(u32 bitmask) -{ - u32 i; - - for (i = 0; i <= 31; i++) - if (((bitmask >> i) & 0x1) == 1) - break; - return i; -} - -static u32 get_bb_reg(struct _adapter *pAdapter, u16 offset, u32 bitmask) -{ - u32 org_value, bit_shift; - - org_value = r8712_bb_reg_read(pAdapter, offset); - bit_shift = bitshift(bitmask); - return (org_value & bitmask) >> bit_shift; -} - -static u8 set_bb_reg(struct _adapter *pAdapter, - u16 offset, - u32 bitmask, - u32 value) -{ - u32 org_value, bit_shift, new_value; - - if (bitmask != bMaskDWord) { - org_value = r8712_bb_reg_read(pAdapter, offset); - bit_shift = bitshift(bitmask); - new_value = (org_value & (~bitmask)) | (value << bit_shift); - } else { - new_value = value; - } - return r8712_bb_reg_write(pAdapter, offset, new_value); -} - -static u32 get_rf_reg(struct _adapter *pAdapter, u8 path, u8 offset, - u32 bitmask) -{ - u32 org_value, bit_shift; - - org_value = r8712_rf_reg_read(pAdapter, path, offset); - bit_shift = bitshift(bitmask); - return (org_value & bitmask) >> bit_shift; -} - -static u8 set_rf_reg(struct _adapter *pAdapter, u8 path, u8 offset, u32 bitmask, - u32 value) -{ - u32 org_value, bit_shift, new_value; - - if (bitmask != bMaskDWord) { - org_value = r8712_rf_reg_read(pAdapter, path, offset); - bit_shift = bitshift(bitmask); - new_value = (org_value & (~bitmask)) | (value << bit_shift); - } else { - new_value = value; - } - return r8712_rf_reg_write(pAdapter, path, offset, new_value); -} - -/* - * SetChannel - * Description - * Use H2C command to change channel, - * not only modify rf register, but also other setting need to be done. - */ -void r8712_SetChannel(struct _adapter *pAdapter) -{ - struct cmd_priv *pcmdpriv = &pAdapter->cmdpriv; - struct cmd_obj *pcmd = NULL; - struct SetChannel_parm *pparm = NULL; - u16 code = GEN_CMD_CODE(_SetChannel); - - pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); - if (!pcmd) - return; - pparm = kmalloc(sizeof(*pparm), GFP_ATOMIC); - if (!pparm) { - kfree(pcmd); - return; - } - pparm->curr_ch = pAdapter->mppriv.curr_ch; - init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code); - r8712_enqueue_cmd(pcmdpriv, pcmd); -} - -static void SetCCKTxPower(struct _adapter *pAdapter, u8 TxPower) -{ - u16 TxAGC = 0; - - TxAGC = TxPower; - set_bb_reg(pAdapter, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); -} - -static void SetOFDMTxPower(struct _adapter *pAdapter, u8 TxPower) -{ - u32 TxAGC = 0; - - TxAGC |= ((TxPower << 24) | (TxPower << 16) | (TxPower << 8) | - TxPower); - set_bb_reg(pAdapter, rTxAGC_Rate18_06, bTxAGCRate18_06, TxAGC); - set_bb_reg(pAdapter, rTxAGC_Rate54_24, bTxAGCRate54_24, TxAGC); - set_bb_reg(pAdapter, rTxAGC_Mcs03_Mcs00, bTxAGCRateMCS3_MCS0, TxAGC); - set_bb_reg(pAdapter, rTxAGC_Mcs07_Mcs04, bTxAGCRateMCS7_MCS4, TxAGC); - set_bb_reg(pAdapter, rTxAGC_Mcs11_Mcs08, bTxAGCRateMCS11_MCS8, TxAGC); - set_bb_reg(pAdapter, rTxAGC_Mcs15_Mcs12, bTxAGCRateMCS15_MCS12, TxAGC); -} - -void r8712_SetTxPower(struct _adapter *pAdapter) -{ - u8 TxPower = pAdapter->mppriv.curr_txpoweridx; - - SetCCKTxPower(pAdapter, TxPower); - SetOFDMTxPower(pAdapter, TxPower); -} - -void r8712_SetTxAGCOffset(struct _adapter *pAdapter, u32 ulTxAGCOffset) -{ - u32 TxAGCOffset_B, TxAGCOffset_C, TxAGCOffset_D, tmpAGC; - - TxAGCOffset_B = ulTxAGCOffset & 0x000000ff; - TxAGCOffset_C = (ulTxAGCOffset & 0x0000ff00) >> 8; - TxAGCOffset_D = (ulTxAGCOffset & 0x00ff0000) >> 16; - tmpAGC = TxAGCOffset_D << 8 | TxAGCOffset_C << 4 | TxAGCOffset_B; - set_bb_reg(pAdapter, rFPGA0_TxGainStage, - (bXBTxAGC | bXCTxAGC | bXDTxAGC), tmpAGC); -} - -void r8712_SetDataRate(struct _adapter *pAdapter) -{ - u8 path = RF_PATH_A; - u8 offset = RF_SYN_G2; - u32 value; - - value = (pAdapter->mppriv.curr_rateidx < 4) ? 0x4440 : 0xF200; - r8712_rf_reg_write(pAdapter, path, offset, value); -} - -void r8712_SwitchBandwidth(struct _adapter *pAdapter) -{ - /* 3 1.Set MAC register : BWOPMODE bit2:1 20MhzBW */ - u8 regBwOpMode = 0; - u8 Bandwidth = pAdapter->mppriv.curr_bandwidth; - - regBwOpMode = r8712_read8(pAdapter, 0x10250203); - if (Bandwidth == HT_CHANNEL_WIDTH_20) - regBwOpMode |= BIT(2); - else - regBwOpMode &= ~(BIT(2)); - r8712_write8(pAdapter, 0x10250203, regBwOpMode); - /* 3 2.Set PHY related register */ - switch (Bandwidth) { - /* 20 MHz channel*/ - case HT_CHANNEL_WIDTH_20: - set_bb_reg(pAdapter, rFPGA0_RFMOD, bRFMOD, 0x0); - set_bb_reg(pAdapter, rFPGA1_RFMOD, bRFMOD, 0x0); - /* Use PHY_REG.txt default value. Do not need to change. - * Correct the tx power for CCK rate in 40M. - * It is set in Tx descriptor for 8192x series - */ - set_bb_reg(pAdapter, rFPGA0_AnalogParameter2, bMaskDWord, 0x58); - break; - /* 40 MHz channel*/ - case HT_CHANNEL_WIDTH_40: - set_bb_reg(pAdapter, rFPGA0_RFMOD, bRFMOD, 0x1); - set_bb_reg(pAdapter, rFPGA1_RFMOD, bRFMOD, 0x1); - /* Use PHY_REG.txt default value. Do not need to change. - * Correct the tx power for CCK rate in 40M. - * Set Control channel to upper or lower. These settings are - * required only for 40MHz - */ - set_bb_reg(pAdapter, rCCK0_System, bCCKSideBand, - (HAL_PRIME_CHNL_OFFSET_DONT_CARE >> 1)); - set_bb_reg(pAdapter, rOFDM1_LSTF, 0xC00, - HAL_PRIME_CHNL_OFFSET_DONT_CARE); - set_bb_reg(pAdapter, rFPGA0_AnalogParameter2, bMaskDWord, 0x18); - break; - default: - break; - } - - /* 3 3.Set RF related register */ - switch (Bandwidth) { - case HT_CHANNEL_WIDTH_20: - set_rf_reg(pAdapter, RF_PATH_A, RF_CHNLBW, - BIT(10) | BIT(11), 0x01); - break; - case HT_CHANNEL_WIDTH_40: - set_rf_reg(pAdapter, RF_PATH_A, RF_CHNLBW, - BIT(10) | BIT(11), 0x00); - break; - default: - break; - } -} - -/*------------------------------Define structure----------------------------*/ -struct R_ANTENNA_SELECT_OFDM { - u32 r_tx_antenna:4; - u32 r_ant_l:4; - u32 r_ant_non_ht:4; - u32 r_ant_ht1:4; - u32 r_ant_ht2:4; - u32 r_ant_ht_s1:4; - u32 r_ant_non_ht_s1:4; - u32 OFDM_TXSC:2; - u32 Reserved:2; -}; - -struct R_ANTENNA_SELECT_CCK { - u8 r_cckrx_enable_2:2; - u8 r_cckrx_enable:2; - u8 r_ccktx_enable:4; -}; - -void r8712_SwitchAntenna(struct _adapter *pAdapter) -{ - u32 ofdm_tx_en_val = 0, ofdm_tx_ant_sel_val = 0; - u8 ofdm_rx_ant_sel_val = 0; - u8 cck_ant_select_val = 0; - u32 cck_ant_sel_val = 0; - struct R_ANTENNA_SELECT_CCK *p_cck_txrx; - - p_cck_txrx = (struct R_ANTENNA_SELECT_CCK *)&cck_ant_select_val; - - switch (pAdapter->mppriv.antenna_tx) { - case ANTENNA_A: - /* From SD3 Willis suggestion !!! Set RF A=TX and B as standby*/ - set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); - set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1); - ofdm_tx_en_val = 0x3; - ofdm_tx_ant_sel_val = 0x11111111;/* Power save */ - p_cck_txrx->r_ccktx_enable = 0x8; - break; - case ANTENNA_B: - set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1); - set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); - ofdm_tx_en_val = 0x3; - ofdm_tx_ant_sel_val = 0x22222222;/* Power save */ - p_cck_txrx->r_ccktx_enable = 0x4; - break; - case ANTENNA_AB: /* For 8192S */ - set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); - set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); - ofdm_tx_en_val = 0x3; - ofdm_tx_ant_sel_val = 0x3321333; /* Disable Power save */ - p_cck_txrx->r_ccktx_enable = 0xC; - break; - default: - break; - } - /*OFDM Tx*/ - set_bb_reg(pAdapter, rFPGA1_TxInfo, 0xffffffff, ofdm_tx_ant_sel_val); - /*OFDM Tx*/ - set_bb_reg(pAdapter, rFPGA0_TxInfo, 0x0000000f, ofdm_tx_en_val); - switch (pAdapter->mppriv.antenna_rx) { - case ANTENNA_A: - ofdm_rx_ant_sel_val = 0x1; /* A */ - p_cck_txrx->r_cckrx_enable = 0x0; /* default: A */ - p_cck_txrx->r_cckrx_enable_2 = 0x0; /* option: A */ - break; - case ANTENNA_B: - ofdm_rx_ant_sel_val = 0x2; /* B */ - p_cck_txrx->r_cckrx_enable = 0x1; /* default: B */ - p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option: B */ - break; - case ANTENNA_AB: - ofdm_rx_ant_sel_val = 0x3; /* AB */ - p_cck_txrx->r_cckrx_enable = 0x0; /* default:A */ - p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option:B */ - break; - default: - break; - } - /*OFDM Rx*/ - set_bb_reg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, - ofdm_rx_ant_sel_val); - /*OFDM Rx*/ - set_bb_reg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, - ofdm_rx_ant_sel_val); - - cck_ant_sel_val = cck_ant_select_val; - /*CCK TxRx*/ - set_bb_reg(pAdapter, rCCK0_AFESetting, bMaskByte3, cck_ant_sel_val); -} - -static void TriggerRFThermalMeter(struct _adapter *pAdapter) -{ - /* 0x24: RF Reg[6:5] */ - set_rf_reg(pAdapter, RF_PATH_A, RF_T_METER, bRFRegOffsetMask, 0x60); -} - -static u32 ReadRFThermalMeter(struct _adapter *pAdapter) -{ - /* 0x24: RF Reg[4:0] */ - return get_rf_reg(pAdapter, RF_PATH_A, RF_T_METER, 0x1F); -} - -void r8712_GetThermalMeter(struct _adapter *pAdapter, u32 *value) -{ - TriggerRFThermalMeter(pAdapter); - msleep(1000); - *value = ReadRFThermalMeter(pAdapter); -} - -void r8712_SetSingleCarrierTx(struct _adapter *pAdapter, u8 bStart) -{ - if (bStart) { /* Start Single Carrier. */ - /* 1. if OFDM block on? */ - if (!get_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) - /*set OFDM block on*/ - set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable); - /* 2. set CCK test mode off, set to CCK normal mode */ - set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); - /* 3. turn on scramble setting */ - set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, bEnable); - /* 4. Turn On Single Carrier Tx and off the other test modes. */ - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bEnable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); - } else { /* Stop Single Carrier.*/ - /* Turn off all test modes.*/ - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, - bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); - msleep(20); - /*BB Reset*/ - set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); - set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); - } -} - -void r8712_SetSingleToneTx(struct _adapter *pAdapter, u8 bStart) -{ - u8 rfPath; - - switch (pAdapter->mppriv.antenna_tx) { - case ANTENNA_B: - rfPath = RF_PATH_B; - break; - case ANTENNA_A: - default: - rfPath = RF_PATH_A; - break; - } - if (bStart) { /* Start Single Tone.*/ - set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, bDisable); - set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bDisable); - set_rf_reg(pAdapter, rfPath, RF_TX_G2, bRFRegOffsetMask, - 0xd4000); - msleep(100); - /* PAD all on.*/ - set_rf_reg(pAdapter, rfPath, RF_AC, bRFRegOffsetMask, 0x2001f); - msleep(100); - } else { /* Stop Single Tone.*/ - set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable); - set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable); - set_rf_reg(pAdapter, rfPath, RF_TX_G2, bRFRegOffsetMask, - 0x54000); - msleep(100); - /* PAD all on.*/ - set_rf_reg(pAdapter, rfPath, RF_AC, bRFRegOffsetMask, 0x30000); - msleep(100); - } -} - -void r8712_SetCarrierSuppressionTx(struct _adapter *pAdapter, u8 bStart) -{ - if (bStart) { /* Start Carrier Suppression.*/ - if (pAdapter->mppriv.curr_rateidx <= MPT_RATE_11M) { - /* 1. if CCK block on? */ - if (!get_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn)) { - /*set CCK block on*/ - set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, - bEnable); - } - /* Turn Off All Test Mode */ - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, - bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, - bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, - bDisable); - /*transmit mode*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); - /*turn off scramble setting*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, - bDisable); - /*Set CCK Tx Test Rate*/ - /*Set FTxRate to 1Mbps*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKTxRate, 0x0); - } - } else { /* Stop Carrier Suppression. */ - if (pAdapter->mppriv.curr_rateidx <= MPT_RATE_11M) { - /*normal mode*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); - /*turn on scramble setting*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, - bEnable); - /*BB Reset*/ - set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); - set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); - } - } -} - -static void SetCCKContinuousTx(struct _adapter *pAdapter, u8 bStart) -{ - u32 cckrate; - - if (bStart) { - /* 1. if CCK block on? */ - if (!get_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn)) { - /*set CCK block on*/ - set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable); - } - /* Turn Off All Test Mode */ - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); - /*Set CCK Tx Test Rate*/ - cckrate = pAdapter->mppriv.curr_rateidx; - set_bb_reg(pAdapter, rCCK0_System, bCCKTxRate, cckrate); - /*transmit mode*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); - /*turn on scramble setting*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, bEnable); - } else { - /*normal mode*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); - /*turn on scramble setting*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, bEnable); - /*BB Reset*/ - set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); - set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); - } -} /* mpt_StartCckContTx */ - -static void SetOFDMContinuousTx(struct _adapter *pAdapter, u8 bStart) -{ - if (bStart) { - /* 1. if OFDM block on? */ - if (!get_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) { - /*set OFDM block on*/ - set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable); - } - /* 2. set CCK test mode off, set to CCK normal mode*/ - set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); - /* 3. turn on scramble setting */ - set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, bEnable); - /* 4. Turn On Continue Tx and turn off the other test modes.*/ - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bEnable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); - } else { - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, - bDisable); - set_bb_reg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); - msleep(20); - /*BB Reset*/ - set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); - set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); - } -} /* mpt_StartOfdmContTx */ - -void r8712_SetContinuousTx(struct _adapter *pAdapter, u8 bStart) -{ - /* ADC turn off [bit24-21] adc port0 ~ port1 */ - if (bStart) { - r8712_bb_reg_write(pAdapter, rRx_Wait_CCCA, - r8712_bb_reg_read(pAdapter, - rRx_Wait_CCCA) & 0xFE1FFFFF); - msleep(100); - } - if (pAdapter->mppriv.curr_rateidx <= MPT_RATE_11M) - SetCCKContinuousTx(pAdapter, bStart); - else if ((pAdapter->mppriv.curr_rateidx >= MPT_RATE_6M) && - (pAdapter->mppriv.curr_rateidx <= MPT_RATE_MCS15)) - SetOFDMContinuousTx(pAdapter, bStart); - /* ADC turn on [bit24-21] adc port0 ~ port1 */ - if (!bStart) - r8712_bb_reg_write(pAdapter, rRx_Wait_CCCA, - r8712_bb_reg_read(pAdapter, - rRx_Wait_CCCA) | 0x01E00000); -} - -void r8712_ResetPhyRxPktCount(struct _adapter *pAdapter) -{ - u32 i, phyrx_set = 0; - - for (i = OFDM_PPDU_BIT; i <= HT_MPDU_FAIL_BIT; i++) { - phyrx_set = 0; - phyrx_set |= (i << 28); /*select*/ - phyrx_set |= 0x08000000; /* set counter to zero*/ - r8712_write32(pAdapter, RXERR_RPT, phyrx_set); - } -} - -static u32 GetPhyRxPktCounts(struct _adapter *pAdapter, u32 selbit) -{ - /*selection*/ - u32 phyrx_set = 0; - u32 SelectBit; - - SelectBit = selbit << 28; - phyrx_set |= (SelectBit & 0xF0000000); - r8712_write32(pAdapter, RXERR_RPT, phyrx_set); - /*Read packet count*/ - return r8712_read32(pAdapter, RXERR_RPT) & RPTMaxCount; -} - -u32 r8712_GetPhyRxPktReceived(struct _adapter *pAdapter) -{ - u32 OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_OK_BIT); - u32 CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_OK_BIT); - u32 HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_OK_BIT); - - return OFDM_cnt + CCK_cnt + HT_cnt; -} - -u32 r8712_GetPhyRxPktCRC32Error(struct _adapter *pAdapter) -{ - u32 OFDM_cnt = GetPhyRxPktCounts(pAdapter, OFDM_MPDU_FAIL_BIT); - u32 CCK_cnt = GetPhyRxPktCounts(pAdapter, CCK_MPDU_FAIL_BIT); - u32 HT_cnt = GetPhyRxPktCounts(pAdapter, HT_MPDU_FAIL_BIT); - - return OFDM_cnt + CCK_cnt + HT_cnt; -} diff --git a/drivers/staging/rtl8712/rtl871x_mp.h b/drivers/staging/rtl8712/rtl871x_mp.h deleted file mode 100644 index 0a60b1e6ccafc5..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_mp.h +++ /dev/null @@ -1,275 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL871X_MP_H_ -#define __RTL871X_MP_H_ - -#define MPT_NOOP 0 -#define MPT_READ_MAC_1BYTE 1 -#define MPT_READ_MAC_2BYTE 2 -#define MPT_READ_MAC_4BYTE 3 -#define MPT_WRITE_MAC_1BYTE 4 -#define MPT_WRITE_MAC_2BYTE 5 -#define MPT_WRITE_MAC_4BYTE 6 -#define MPT_READ_BB_CCK 7 -#define MPT_WRITE_BB_CCK 8 -#define MPT_READ_BB_OFDM 9 -#define MPT_WRITE_BB_OFDM 10 -#define MPT_READ_RF 11 -#define MPT_WRITE_RF 12 -#define MPT_READ_EEPROM_1BYTE 13 -#define MPT_WRITE_EEPROM_1BYTE 14 -#define MPT_READ_EEPROM_2BYTE 15 -#define MPT_WRITE_EEPROM_2BYTE 16 -#define MPT_SET_CSTHRESHOLD 21 -#define MPT_SET_INITGAIN 22 -#define MPT_SWITCH_BAND 23 -#define MPT_SWITCH_CHANNEL 24 -#define MPT_SET_DATARATE 25 -#define MPT_SWITCH_ANTENNA 26 -#define MPT_SET_TX_POWER 27 -#define MPT_SET_CONT_TX 28 -#define MPT_SET_SINGLE_CARRIER 29 -#define MPT_SET_CARRIER_SUPPRESSION 30 -#define MPT_GET_RATE_TABLE 31 -#define MPT_READ_TSSI 32 -#define MPT_GET_THERMAL_METER 33 -#define MAX_MP_XMITBUF_SZ 2048 -#define NR_MP_XMITFRAME 8 - -struct mp_xmit_frame { - struct list_head list; - struct pkt_attrib attrib; - _pkt *pkt; - int frame_tag; - struct _adapter *padapter; - u8 *mem_addr; - u16 sz[8]; - struct urb *pxmit_urb[8]; - u8 bpending[8]; - u8 last[8]; -}; - -struct mp_wiparam { - u32 bcompleted; - u32 act_type; - u32 io_offset; - u32 io_value; -}; - -struct mp_priv { - struct _adapter *papdater; - /*OID cmd handler*/ - struct mp_wiparam workparam; - u8 act_in_progress; - /*Tx Section*/ - u8 TID; - u32 tx_pktcount; - /*Rx Section*/ - u32 rx_pktcount; - u32 rx_crcerrpktcount; - u32 rx_pktloss; - struct recv_stat rxstat; - /*RF/BB relative*/ - u32 curr_ch; - u32 curr_rateidx; - u8 curr_bandwidth; - u8 curr_modem; - u8 curr_txpoweridx; - u32 curr_crystalcap; - u16 antenna_tx; - u16 antenna_rx; - u8 curr_rfpath; - u8 check_mp_pkt; - uint ForcedDataRate; - struct wlan_network mp_network; - unsigned char network_macaddr[6]; - /*Testing Flag*/ - u32 mode;/*0 for normal type packet, - * 1 for loopback packet (16bytes TXCMD) - */ - sint prev_fw_state; - u8 *pallocated_mp_xmitframe_buf; - u8 *pmp_xmtframe_buf; - struct __queue free_mp_xmitqueue; - u32 free_mp_xmitframe_cnt; -}; - -struct IOCMD_STRUCT { - u8 cmdclass; - u16 value; - u8 index; -}; - -struct rf_reg_param { - u32 path; - u32 offset; - u32 value; -}; - -struct bb_reg_param { - u32 offset; - u32 value; -}; - -/* ======================================================================= */ - -#define LOWER true -#define RAISE false -#define IOCMD_CTRL_REG 0x10250370 -#define IOCMD_DATA_REG 0x10250374 -#define IOCMD_GET_THERMAL_METER 0xFD000028 -#define IOCMD_CLASS_BB_RF 0xF0 -#define IOCMD_BB_READ_IDX 0x00 -#define IOCMD_BB_WRITE_IDX 0x01 -#define IOCMD_RF_READ_IDX 0x02 -#define IOCMD_RF_WRIT_IDX 0x03 -#define BB_REG_BASE_ADDR 0x800 -#define RF_PATH_A 0 -#define RF_PATH_B 1 -#define RF_PATH_C 2 -#define RF_PATH_D 3 -#define MAX_RF_PATH_NUMS 2 -#define _2MAC_MODE_ 0 -#define _LOOPBOOK_MODE_ 1 - -/* MP set force data rate base on the definition. */ -enum { - /* CCK rate. */ - MPT_RATE_1M, /* 0 */ - MPT_RATE_2M, - MPT_RATE_55M, - MPT_RATE_11M, /* 3 */ - - /* OFDM rate. */ - MPT_RATE_6M, /* 4 */ - MPT_RATE_9M, - MPT_RATE_12M, - MPT_RATE_18M, - MPT_RATE_24M, - MPT_RATE_36M, - MPT_RATE_48M, - MPT_RATE_54M, /* 11 */ - - /* HT rate. */ - MPT_RATE_MCS0, /* 12 */ - MPT_RATE_MCS1, - MPT_RATE_MCS2, - MPT_RATE_MCS3, - MPT_RATE_MCS4, - MPT_RATE_MCS5, - MPT_RATE_MCS6, - MPT_RATE_MCS7, /* 19 */ - MPT_RATE_MCS8, - MPT_RATE_MCS9, - MPT_RATE_MCS10, - MPT_RATE_MCS11, - MPT_RATE_MCS12, - MPT_RATE_MCS13, - MPT_RATE_MCS14, - MPT_RATE_MCS15, /* 27 */ - MPT_RATE_LAST -}; - -/* Represent Channel Width in HT Capabilities */ -enum HT_CHANNEL_WIDTH { - HT_CHANNEL_WIDTH_20 = 0, - HT_CHANNEL_WIDTH_40 = 1, -}; - -#define MAX_TX_PWR_INDEX_N_MODE 64 /* 0x3F */ - -enum POWER_MODE { - POWER_LOW = 0, - POWER_NORMAL -}; - -#define RX_PKT_BROADCAST 1 -#define RX_PKT_DEST_ADDR 2 -#define RX_PKT_PHY_MATCH 3 - -#define RPTMaxCount 0x000FFFFF - -/* parameter 1 : BitMask - * bit 0 : OFDM PPDU - * bit 1 : OFDM False Alarm - * bit 2 : OFDM MPDU OK - * bit 3 : OFDM MPDU Fail - * bit 4 : CCK PPDU - * bit 5 : CCK False Alarm - * bit 6 : CCK MPDU ok - * bit 7 : CCK MPDU fail - * bit 8 : HT PPDU counter - * bit 9 : HT false alarm - * bit 10 : HT MPDU total - * bit 11 : HT MPDU OK - * bit 12 : HT MPDU fail - * bit 15 : RX full drop - */ -enum RXPHY_BITMASK { - OFDM_PPDU_BIT = 0, - OFDM_MPDU_OK_BIT, - OFDM_MPDU_FAIL_BIT, - CCK_PPDU_BIT, - CCK_MPDU_OK_BIT, - CCK_MPDU_FAIL_BIT, - HT_PPDU_BIT, - HT_MPDU_BIT, - HT_MPDU_OK_BIT, - HT_MPDU_FAIL_BIT, -}; - -enum ENCRY_CTRL_STATE { - HW_CONTROL, /*hw encryption& decryption*/ - SW_CONTROL, /*sw encryption& decryption*/ - HW_ENCRY_SW_DECRY, /*hw encryption & sw decryption*/ - SW_ENCRY_HW_DECRY /*sw encryption & hw decryption*/ -}; - -/* Bandwidth Offset */ -#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 -#define HAL_PRIME_CHNL_OFFSET_LOWER 1 -#define HAL_PRIME_CHNL_OFFSET_UPPER 2 -/*=======================================================================*/ -void mp871xinit(struct _adapter *padapter); -void mp871xdeinit(struct _adapter *padapter); -u32 r8712_bb_reg_read(struct _adapter *Adapter, u16 offset); -u8 r8712_bb_reg_write(struct _adapter *Adapter, u16 offset, u32 value); -u32 r8712_rf_reg_read(struct _adapter *Adapter, u8 path, u8 offset); -u8 r8712_rf_reg_write(struct _adapter *Adapter, u8 path, - u8 offset, u32 value); -u32 r8712_get_bb_reg(struct _adapter *Adapter, u16 offset, u32 bitmask); -u8 r8712_set_bb_reg(struct _adapter *Adapter, u16 offset, - u32 bitmask, u32 value); -u32 r8712_get_rf_reg(struct _adapter *Adapter, u8 path, u8 offset, - u32 bitmask); -u8 r8712_set_rf_reg(struct _adapter *Adapter, u8 path, u8 offset, - u32 bitmask, u32 value); - -void r8712_SetChannel(struct _adapter *pAdapter); -void r8712_SetTxPower(struct _adapter *pAdapte); -void r8712_SetTxAGCOffset(struct _adapter *pAdapter, u32 ulTxAGCOffset); -void r8712_SetDataRate(struct _adapter *pAdapter); -void r8712_SwitchBandwidth(struct _adapter *pAdapter); -void r8712_SwitchAntenna(struct _adapter *pAdapter); -void r8712_GetThermalMeter(struct _adapter *pAdapter, u32 *value); -void r8712_SetContinuousTx(struct _adapter *pAdapter, u8 bStart); -void r8712_SetSingleCarrierTx(struct _adapter *pAdapter, u8 bStart); -void r8712_SetSingleToneTx(struct _adapter *pAdapter, u8 bStart); -void r8712_SetCarrierSuppressionTx(struct _adapter *pAdapter, u8 bStart); -void r8712_ResetPhyRxPktCount(struct _adapter *pAdapter); -u32 r8712_GetPhyRxPktReceived(struct _adapter *pAdapter); -u32 r8712_GetPhyRxPktCRC32Error(struct _adapter *pAdapter); - -#endif /*__RTL871X_MP_H_*/ - diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c deleted file mode 100644 index 26fa09b45c9080..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c +++ /dev/null @@ -1,883 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_mp_ioctl.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#include -#include "osdep_service.h" -#include "drv_types.h" -#include "mlme_osdep.h" -#include "rtl871x_mp.h" -#include "rtl871x_mp_ioctl.h" - -uint oid_null_function(struct oid_par_priv *poid_par_priv) -{ - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv) -{ - uint status = RNDIS_STATUS_SUCCESS; - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid == SET_OID) { - if (poid_par_priv->information_buf_len >= sizeof(u8)) - Adapter->registrypriv.wireless_mode = - *(u8 *)poid_par_priv->information_buf; - else - status = RNDIS_STATUS_INVALID_LENGTH; - } else if (poid_par_priv->type_of_oid == QUERY_OID) { - if (poid_par_priv->information_buf_len >= sizeof(u8)) { - *(u8 *)poid_par_priv->information_buf = - Adapter->registrypriv.wireless_mode; - *poid_par_priv->bytes_rw = - poid_par_priv->information_buf_len; - } else { - status = RNDIS_STATUS_INVALID_LENGTH; - } - } else { - status = RNDIS_STATUS_NOT_ACCEPTED; - } - return status; -} - -uint oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - struct bb_reg_param *pbbreg; - u16 offset; - u32 value; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) - return RNDIS_STATUS_INVALID_LENGTH; - pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); - offset = (u16)(pbbreg->offset) & 0xFFF; /*0ffset :0x800~0xfff*/ - if (offset < BB_REG_BASE_ADDR) - offset |= BB_REG_BASE_ADDR; - value = pbbreg->value; - r8712_bb_reg_write(Adapter, offset, value); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - struct bb_reg_param *pbbreg; - u16 offset; - u32 value; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) - return RNDIS_STATUS_INVALID_LENGTH; - pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); - offset = (u16)(pbbreg->offset) & 0xFFF; /*0ffset :0x800~0xfff*/ - if (offset < BB_REG_BASE_ADDR) - offset |= BB_REG_BASE_ADDR; - value = r8712_bb_reg_read(Adapter, offset); - pbbreg->value = value; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - struct rf_reg_param *pbbreg; - u8 path; - u8 offset; - u32 value; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) - return RNDIS_STATUS_INVALID_LENGTH; - pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); - path = (u8)pbbreg->path; - if (path > RF_PATH_B) - return RNDIS_STATUS_NOT_ACCEPTED; - offset = (u8)pbbreg->offset; - value = pbbreg->value; - r8712_rf_reg_write(Adapter, path, offset, value); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - struct rf_reg_param *pbbreg; - u8 path; - u8 offset; - u32 value; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) - return RNDIS_STATUS_INVALID_LENGTH; - pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); - path = (u8)pbbreg->path; - if (path > RF_PATH_B) /* 1T2R path_a /path_b */ - return RNDIS_STATUS_NOT_ACCEPTED; - offset = (u8)pbbreg->offset; - value = r8712_rf_reg_read(Adapter, path, offset); - pbbreg->value = value; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -/*This function initializes the DUT to the MP test mode*/ -static int mp_start_test(struct _adapter *padapter) -{ - struct mp_priv *pmppriv = &padapter->mppriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_network *tgt_network = &pmlmepriv->cur_network; - struct wlan_bssid_ex *bssid; - struct sta_info *psta; - unsigned long length; - unsigned long irqL; - int res = 0; - - bssid = kzalloc(sizeof(*bssid), GFP_KERNEL); - if (!bssid) - return -ENOMEM; - - /* 3 1. initialize a new struct wlan_bssid_ex */ - memcpy(bssid->MacAddress, pmppriv->network_macaddr, ETH_ALEN); - bssid->Ssid.SsidLength = 16; - memcpy(bssid->Ssid.Ssid, (unsigned char *)"mp_pseudo_adhoc", - bssid->Ssid.SsidLength); - bssid->InfrastructureMode = Ndis802_11IBSS; - bssid->NetworkTypeInUse = Ndis802_11DS; - bssid->IELength = 0; - length = r8712_get_wlan_bssid_ex_sz(bssid); - if (length % 4) { - /*round up to multiple of 4 bytes.*/ - bssid->Length = ((length >> 2) + 1) << 2; - } else { - bssid->Length = length; - } - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) - goto end_of_mp_start_test; - /*init mp_start_test status*/ - pmppriv->prev_fw_state = get_fwstate(pmlmepriv); - pmlmepriv->fw_state = WIFI_MP_STATE; - if (pmppriv->mode == _LOOPBOOK_MODE_) - set_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE); /*append txdesc*/ - set_fwstate(pmlmepriv, _FW_UNDER_LINKING); - /* 3 2. create a new psta for mp driver */ - /* clear psta in the cur_network, if any */ - psta = r8712_get_stainfo(&padapter->stapriv, - tgt_network->network.MacAddress); - if (psta) - r8712_free_stainfo(padapter, psta); - psta = r8712_alloc_stainfo(&padapter->stapriv, bssid->MacAddress); - if (!psta) { - res = -ENOMEM; - goto end_of_mp_start_test; - } - /* 3 3. join pseudo AdHoc */ - tgt_network->join_res = 1; - tgt_network->aid = psta->aid = 1; - memcpy(&tgt_network->network, bssid, length); - _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); - r8712_os_indicate_connect(padapter); - /* Set to LINKED STATE for MP TRX Testing */ - set_fwstate(pmlmepriv, _FW_LINKED); -end_of_mp_start_test: - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - kfree(bssid); - return res; -} - -/*This function change the DUT from the MP test mode into normal mode */ -static int mp_stop_test(struct _adapter *padapter) -{ - struct mp_priv *pmppriv = &padapter->mppriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct wlan_network *tgt_network = &pmlmepriv->cur_network; - struct sta_info *psta; - unsigned long irqL; - - spin_lock_irqsave(&pmlmepriv->lock, irqL); - if (!check_fwstate(pmlmepriv, WIFI_MP_STATE)) - goto end_of_mp_stop_test; - /* 3 1. disconnect pseudo AdHoc */ - r8712_os_indicate_disconnect(padapter); - /* 3 2. clear psta used in mp test mode. */ - psta = r8712_get_stainfo(&padapter->stapriv, - tgt_network->network.MacAddress); - if (psta) - r8712_free_stainfo(padapter, psta); - /* 3 3. return to normal state (default:station mode) */ - pmlmepriv->fw_state = pmppriv->prev_fw_state; /* WIFI_STATION_STATE;*/ - /*flush the cur_network*/ - memset(tgt_network, 0, sizeof(struct wlan_network)); -end_of_mp_stop_test: - spin_unlock_irqrestore(&pmlmepriv->lock, irqL); - return _SUCCESS; -} - -uint oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 ratevalue; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len != sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - ratevalue = *((u32 *)poid_par_priv->information_buf); - if (ratevalue >= MPT_RATE_LAST) - return RNDIS_STATUS_INVALID_DATA; - Adapter->mppriv.curr_rateidx = ratevalue; - r8712_SetDataRate(Adapter); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - uint status = RNDIS_STATUS_SUCCESS; - u32 mode; - u8 val8; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - mode = *((u32 *)poid_par_priv->information_buf); - Adapter->mppriv.mode = mode;/* 1 for loopback*/ - if (mp_start_test(Adapter)) - status = RNDIS_STATUS_NOT_ACCEPTED; - r8712_write8(Adapter, MSR, 1); /* Link in ad hoc network, 0x1025004C */ - r8712_write8(Adapter, RCR, 0); /* RCR : disable all pkt, 0x10250048 */ - /* RCR disable Check BSSID, 0x1025004a */ - r8712_write8(Adapter, RCR + 2, 0x57); - /* disable RX filter map , mgt frames will put in RX FIFO 0 */ - r8712_write16(Adapter, RXFLTMAP0, 0x0); - val8 = r8712_read8(Adapter, EE_9346CR); - if (!(val8 & _9356SEL)) { /*boot from EFUSE*/ - r8712_efuse_reg_init(Adapter); - r8712_efuse_change_max_size(Adapter); - r8712_efuse_reg_uninit(Adapter); - } - return status; -} - -uint oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (mp_stop_test(Adapter) == _FAIL) - return RNDIS_STATUS_NOT_ACCEPTED; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 Channel; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len != sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - Channel = *((u32 *)poid_par_priv->information_buf); - if (Channel > 14) - return RNDIS_STATUS_NOT_ACCEPTED; - Adapter->mppriv.curr_ch = Channel; - r8712_SetChannel(Adapter); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 antenna; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len != sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - antenna = *((u32 *)poid_par_priv->information_buf); - Adapter->mppriv.antenna_tx = (u16)((antenna & 0xFFFF0000) >> 16); - Adapter->mppriv.antenna_rx = (u16)(antenna & 0x0000FFFF); - r8712_SwitchAntenna(Adapter); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 tx_pwr_idx; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len != sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - tx_pwr_idx = *((u32 *)poid_par_priv->information_buf); - if (tx_pwr_idx > MAX_TX_PWR_INDEX_N_MODE) - return RNDIS_STATUS_NOT_ACCEPTED; - Adapter->mppriv.curr_txpoweridx = (u8)tx_pwr_idx; - r8712_SetTxPower(Adapter); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - - if (poid_par_priv->information_buf_len == sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - Adapter->mppriv.tx_pktcount; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - - if (poid_par_priv->information_buf_len == sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - Adapter->mppriv.rx_pktcount; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - - if (poid_par_priv->information_buf_len == sizeof(u32)) { - *(u32 *)poid_par_priv->information_buf = - Adapter->mppriv.rx_crcerrpktcount; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - Adapter->mppriv.tx_pktcount = 0; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len == sizeof(u32)) { - Adapter->mppriv.rx_pktcount = 0; - Adapter->mppriv.rx_crcerrpktcount = 0; - } else { - return RNDIS_STATUS_INVALID_LENGTH; - } - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - r8712_ResetPhyRxPktCount(Adapter); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len != sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - *(u32 *)poid_par_priv->information_buf = - r8712_GetPhyRxPktReceived(Adapter); - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len != sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - *(u32 *)poid_par_priv->information_buf = - r8712_GetPhyRxPktCRC32Error(Adapter); - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - - Adapter->mppriv.curr_modem = *((u8 *)poid_par_priv->information_buf); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 bStartTest; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - bStartTest = *((u32 *)poid_par_priv->information_buf); - r8712_SetContinuousTx(Adapter, (u8)bStartTest); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 bStartTest; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - bStartTest = *((u32 *)poid_par_priv->information_buf); - r8712_SetSingleCarrierTx(Adapter, (u8)bStartTest); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 bStartTest; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - bStartTest = *((u32 *)poid_par_priv->information_buf); - r8712_SetCarrierSuppressionTx(Adapter, (u8)bStartTest); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 bStartTest; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - bStartTest = *((u32 *)poid_par_priv->information_buf); - r8712_SetSingleToneTx(Adapter, (u8)bStartTest); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - uint status = RNDIS_STATUS_SUCCESS; - struct mp_rw_reg *RegRWStruct; - u16 offset; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf; - if ((RegRWStruct->offset >= 0x10250800) && - (RegRWStruct->offset <= 0x10250FFF)) { - /*baseband register*/ - /*0ffset :0x800~0xfff*/ - offset = (u16)(RegRWStruct->offset) & 0xFFF; - RegRWStruct->value = r8712_bb_reg_read(Adapter, offset); - } else { - switch (RegRWStruct->width) { - case 1: - RegRWStruct->value = r8712_read8(Adapter, - RegRWStruct->offset); - break; - case 2: - RegRWStruct->value = r8712_read16(Adapter, - RegRWStruct->offset); - break; - case 4: - RegRWStruct->value = r8712_read32(Adapter, - RegRWStruct->offset); - break; - default: - status = RNDIS_STATUS_NOT_ACCEPTED; - break; - } - } - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return status; -} - -uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - uint status = RNDIS_STATUS_SUCCESS; - struct mp_rw_reg *RegRWStruct; - u16 offset; - u32 value; - u32 oldValue = 0; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf; - if ((RegRWStruct->offset >= 0x10250800) && - (RegRWStruct->offset <= 0x10250FFF)) { - /*baseband register*/ - offset = (u16)(RegRWStruct->offset) & 0xFFF; - value = RegRWStruct->value; - switch (RegRWStruct->width) { - case 1: - oldValue = r8712_bb_reg_read(Adapter, offset); - oldValue &= 0xFFFFFF00; - value &= 0x000000FF; - value |= oldValue; - break; - case 2: - oldValue = r8712_bb_reg_read(Adapter, offset); - oldValue &= 0xFFFF0000; - value &= 0x0000FFFF; - value |= oldValue; - break; - } - r8712_bb_reg_write(Adapter, offset, value); - } else { - switch (RegRWStruct->width) { - case 1: - r8712_write8(Adapter, RegRWStruct->offset, - (unsigned char)RegRWStruct->value); - break; - case 2: - r8712_write16(Adapter, RegRWStruct->offset, - (unsigned short)RegRWStruct->value); - break; - case 4: - r8712_write32(Adapter, RegRWStruct->offset, - (unsigned int)RegRWStruct->value); - break; - default: - status = RNDIS_STATUS_NOT_ACCEPTED; - break; - } - } - return status; -} - -uint oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - - if (Adapter->mppriv.act_in_progress) - return RNDIS_STATUS_NOT_ACCEPTED; - - if (poid_par_priv->information_buf_len < sizeof(u8)) - return RNDIS_STATUS_INVALID_LENGTH; - /*init workparam*/ - Adapter->mppriv.act_in_progress = true; - Adapter->mppriv.workparam.bcompleted = false; - Adapter->mppriv.workparam.act_type = MPT_GET_THERMAL_METER; - Adapter->mppriv.workparam.io_offset = 0; - Adapter->mppriv.workparam.io_value = 0xFFFFFFFF; - r8712_GetThermalMeter(Adapter, &Adapter->mppriv.workparam.io_value); - Adapter->mppriv.workparam.bcompleted = true; - Adapter->mppriv.act_in_progress = false; - *(u32 *)poid_par_priv->information_buf = - Adapter->mppriv.workparam.io_value; - *poid_par_priv->bytes_rw = sizeof(u32); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - uint status = RNDIS_STATUS_SUCCESS; - - struct EFUSE_ACCESS_STRUCT *pefuse; - u8 *data; - u16 addr = 0, cnts = 0; - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < - sizeof(struct EFUSE_ACCESS_STRUCT)) - return RNDIS_STATUS_INVALID_LENGTH; - pefuse = (struct EFUSE_ACCESS_STRUCT *)poid_par_priv->information_buf; - addr = pefuse->start_addr; - cnts = pefuse->cnts; - data = pefuse->data; - memset(data, 0xFF, cnts); - if ((addr > 511) || (cnts < 1) || (cnts > 512) || (addr + cnts) > - EFUSE_MAX_SIZE) - return RNDIS_STATUS_NOT_ACCEPTED; - if (!r8712_efuse_access(Adapter, true, addr, cnts, data)) - status = RNDIS_STATUS_FAILURE; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return status; -} - -/*------------------------------------------------------------------------*/ -uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - uint status = RNDIS_STATUS_SUCCESS; - - struct EFUSE_ACCESS_STRUCT *pefuse; - u8 *data; - u16 addr = 0, cnts = 0; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - - pefuse = (struct EFUSE_ACCESS_STRUCT *)poid_par_priv->information_buf; - addr = pefuse->start_addr; - cnts = pefuse->cnts; - data = pefuse->data; - - if ((addr > 511) || (cnts < 1) || (cnts > 512) || - (addr + cnts) > r8712_efuse_get_max_size(Adapter)) - return RNDIS_STATUS_NOT_ACCEPTED; - if (!r8712_efuse_access(Adapter, false, addr, cnts, data)) - status = RNDIS_STATUS_FAILURE; - return status; -} - -/*----------------------------------------------------------------------*/ - -uint oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(int)) - return RNDIS_STATUS_INVALID_LENGTH; - r8712_efuse_reg_init(Adapter); - *(int *)poid_par_priv->information_buf = - r8712_efuse_get_current_size(Adapter); - r8712_efuse_reg_uninit(Adapter); - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - *(int *)poid_par_priv->information_buf = - r8712_efuse_get_max_size(Adapter); - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv) -{ - uint status = RNDIS_STATUS_SUCCESS; - - if (poid_par_priv->type_of_oid == QUERY_OID) - status = oid_rt_pro_read_efuse_hdl(poid_par_priv); - else - status = oid_rt_pro_write_efuse_hdl(poid_par_priv); - return status; -} - -uint oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - uint status = RNDIS_STATUS_SUCCESS; - u8 *data; - - *poid_par_priv->bytes_rw = 0; - if (poid_par_priv->information_buf_len < EFUSE_MAP_MAX_SIZE) - return RNDIS_STATUS_INVALID_LENGTH; - data = (u8 *)poid_par_priv->information_buf; - if (poid_par_priv->type_of_oid == QUERY_OID) { - if (r8712_efuse_map_read(Adapter, 0, EFUSE_MAP_MAX_SIZE, data)) - *poid_par_priv->bytes_rw = EFUSE_MAP_MAX_SIZE; - else - status = RNDIS_STATUS_FAILURE; - } else { - /* SET_OID */ - if (r8712_efuse_reg_init(Adapter)) { - if (r8712_efuse_map_write(Adapter, 0, - EFUSE_MAP_MAX_SIZE, data)) - *poid_par_priv->bytes_rw = EFUSE_MAP_MAX_SIZE; - else - status = RNDIS_STATUS_FAILURE; - r8712_efuse_reg_uninit(Adapter); - } else { - status = RNDIS_STATUS_FAILURE; - } - } - return status; -} - -uint oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u32 bandwidth; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - bandwidth = *((u32 *)poid_par_priv->information_buf);/*4*/ - if (bandwidth != HT_CHANNEL_WIDTH_20) - bandwidth = HT_CHANNEL_WIDTH_40; - Adapter->mppriv.curr_bandwidth = (u8)bandwidth; - r8712_SwitchBandwidth(Adapter); - return RNDIS_STATUS_SUCCESS; -} - -uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - u8 rx_pkt_type; - u32 rcr_val32; - - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(u8)) - return RNDIS_STATUS_INVALID_LENGTH; - rx_pkt_type = *((u8 *)poid_par_priv->information_buf);/*4*/ - rcr_val32 = r8712_read32(Adapter, RCR);/*RCR = 0x10250048*/ - rcr_val32 &= ~(RCR_CBSSID | RCR_AB | RCR_AM | RCR_APM | RCR_AAP); - switch (rx_pkt_type) { - case RX_PKT_BROADCAST: - rcr_val32 |= (RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_ACRC32); - break; - case RX_PKT_DEST_ADDR: - rcr_val32 |= (RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_ACRC32); - break; - case RX_PKT_PHY_MATCH: - rcr_val32 |= (RCR_APM | RCR_ACRC32); - break; - default: - rcr_val32 &= ~(RCR_AAP | - RCR_APM | - RCR_AM | - RCR_AB | - RCR_ACRC32); - break; - } - if (rx_pkt_type == RX_PKT_DEST_ADDR) - Adapter->mppriv.check_mp_pkt = 1; - else - Adapter->mppriv.check_mp_pkt = 0; - r8712_write32(Adapter, RCR, rcr_val32); - return RNDIS_STATUS_SUCCESS; -} - -/*--------------------------------------------------------------------------*/ -/*Linux*/ -unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv) -{ - return _SUCCESS; -} - -/*-------------------------------------------------------------------------*/ -uint oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv) -{ - if (poid_par_priv->type_of_oid != SET_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - /*CALL the power_down function*/ - return RNDIS_STATUS_SUCCESS; -} - -/*-------------------------------------------------------------------------- */ -uint oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv) -{ - struct _adapter *Adapter = (struct _adapter *) - (poid_par_priv->adapter_context); - - if (poid_par_priv->type_of_oid != QUERY_OID) - return RNDIS_STATUS_NOT_ACCEPTED; - if (poid_par_priv->information_buf_len < sizeof(u32)) - return RNDIS_STATUS_INVALID_LENGTH; - *(int *)poid_par_priv->information_buf = - Adapter->registrypriv.low_power ? POWER_LOW : POWER_NORMAL; - *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; - return RNDIS_STATUS_SUCCESS; -} diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h deleted file mode 100644 index aa4d5ce471f2fa..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h +++ /dev/null @@ -1,328 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL871X_MP_IOCTL_H -#define _RTL871X_MP_IOCTL_H - -#include "osdep_service.h" -#include "drv_types.h" -#include "mp_custom_oid.h" -#include "rtl871x_ioctl.h" -#include "rtl871x_ioctl_rtl.h" -#include "rtl8712_efuse.h" - -#define TESTFWCMDNUMBER 1000000 -#define TEST_H2CINT_WAIT_TIME 500 -#define TEST_C2HINT_WAIT_TIME 500 -#define HCI_TEST_SYSCFG_HWMASK 1 -#define _BUSCLK_40M (4 << 2) - -struct CFG_DBG_MSG_STRUCT { - u32 DebugLevel; - u32 DebugComponent_H32; - u32 DebugComponent_L32; -}; - -struct mp_rw_reg { - uint offset; - uint width; - u32 value; -}; - -/* for OID_RT_PRO_READ16_EEPROM & OID_RT_PRO_WRITE16_EEPROM */ -struct eeprom_rw_param { - uint offset; - u16 value; -}; - -struct EFUSE_ACCESS_STRUCT { - u16 start_addr; - u16 cnts; - u8 data[]; -}; - -struct burst_rw_reg { - uint offset; - uint len; - u8 Data[256]; -}; - -struct usb_vendor_req { - u8 bRequest; - u16 wValue; - u16 wIndex; - u16 wLength; - u8 u8Dir;/*0:OUT, 1:IN */ - u8 u8InData; -}; - -struct DR_VARIABLE_STRUCT { - u8 offset; - u32 variable; -}; - -/* oid_rtl_seg_87_11_00 */ -uint oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv); -/* oid_rtl_seg_81_80_00 */ -uint oid_rt_pro_set_data_rate_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_set_channel_direct_call_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_set_antenna_bb_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_set_tx_power_control_hdl( - struct oid_par_priv *poid_par_priv); -/* oid_rtl_seg_81_80_20 */ -uint oid_rt_pro_query_tx_packet_sent_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_query_rx_packet_received_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_query_rx_packet_crc32_error_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_reset_tx_packet_sent_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_reset_rx_packet_received_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_set_continuous_tx_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_set_single_carrier_tx_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_set_carrier_suppression_tx_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_set_single_tone_tx_hdl( - struct oid_par_priv *poid_par_priv); -/* oid_rtl_seg_81_87 */ -uint oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv); -/* oid_rtl_seg_81_85 */ -uint oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_get_efuse_current_size_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv); -uint oid_rt_get_thermal_meter_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_reset_phy_rx_packet_count_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_phy_rx_packet_received_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_phy_rx_packet_crc32_error_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_set_power_down_hdl( - struct oid_par_priv *poid_par_priv); -uint oid_rt_get_power_mode_hdl( - struct oid_par_priv *poid_par_priv); -#ifdef _RTL871X_MP_IOCTL_C_ /* CAUTION!!! */ -/* This ifdef _MUST_ be left in!! */ - -#else /* _RTL871X_MP_IOCTL_C_ */ -extern struct oid_obj_priv oid_rtl_seg_81_87[5]; -extern struct oid_obj_priv oid_rtl_seg_87_11_00[32]; -extern struct oid_obj_priv oid_rtl_seg_87_11_20[5]; -extern struct oid_obj_priv oid_rtl_seg_87_11_50[2]; -extern struct oid_obj_priv oid_rtl_seg_87_11_80[1]; -extern struct oid_obj_priv oid_rtl_seg_87_11_B0[1]; -extern struct oid_obj_priv oid_rtl_seg_87_11_F0[16]; -extern struct oid_obj_priv oid_rtl_seg_87_12_00[32]; - -#endif /* _RTL871X_MP_IOCTL_C_ */ - -enum MP_MODE { - MP_START_MODE, - MP_STOP_MODE, - MP_ERR_MODE -}; - -struct rwreg_param { - unsigned int offset; - unsigned int width; - unsigned int value; -}; - -struct bbreg_param { - unsigned int offset; - unsigned int phymask; - unsigned int value; -}; - -struct txpower_param { - unsigned int pwr_index; -}; - -struct datarate_param { - unsigned int rate_index; -}; - -struct rfintfs_parm { - unsigned int rfintfs; -}; - -struct mp_xmit_packet { - unsigned int len; -}; - -struct psmode_param { - unsigned int ps_mode; - unsigned int smart_ps; -}; - -struct mp_ioctl_handler { - unsigned int paramsize; - unsigned int (*handler)(struct oid_par_priv *poid_par_priv); - unsigned int oid; -}; - -struct mp_ioctl_param { - unsigned int subcode; - unsigned int len; - unsigned char data[]; -}; - -#define GEN_MP_IOCTL_SUBCODE(code) _MP_IOCTL_ ## code ## _CMD_ - -enum RTL871X_MP_IOCTL_SUBCODE { - GEN_MP_IOCTL_SUBCODE(MP_START), /*0*/ - GEN_MP_IOCTL_SUBCODE(MP_STOP), /*1*/ - GEN_MP_IOCTL_SUBCODE(READ_REG), /*2*/ - GEN_MP_IOCTL_SUBCODE(WRITE_REG), - GEN_MP_IOCTL_SUBCODE(SET_CHANNEL), /*4*/ - GEN_MP_IOCTL_SUBCODE(SET_TXPOWER), /*5*/ - GEN_MP_IOCTL_SUBCODE(SET_DATARATE), /*6*/ - GEN_MP_IOCTL_SUBCODE(READ_BB_REG), /*7*/ - GEN_MP_IOCTL_SUBCODE(WRITE_BB_REG), - GEN_MP_IOCTL_SUBCODE(READ_RF_REG), /*9*/ - GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG), - GEN_MP_IOCTL_SUBCODE(SET_RF_INTFS), - GEN_MP_IOCTL_SUBCODE(IOCTL_XMIT_PACKET), /*12*/ - GEN_MP_IOCTL_SUBCODE(PS_STATE), /*13*/ - GEN_MP_IOCTL_SUBCODE(READ16_EEPROM), /*14*/ - GEN_MP_IOCTL_SUBCODE(WRITE16_EEPROM), /*15*/ - GEN_MP_IOCTL_SUBCODE(SET_PTM), /*16*/ - GEN_MP_IOCTL_SUBCODE(READ_TSSI), /*17*/ - GEN_MP_IOCTL_SUBCODE(CNTU_TX), /*18*/ - GEN_MP_IOCTL_SUBCODE(SET_BANDWIDTH), /*19*/ - GEN_MP_IOCTL_SUBCODE(SET_RX_PKT_TYPE), /*20*/ - GEN_MP_IOCTL_SUBCODE(RESET_PHY_RX_PKT_CNT), /*21*/ - GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_RECV), /*22*/ - GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_ERROR), /*23*/ - GEN_MP_IOCTL_SUBCODE(SET_POWER_DOWN), /*24*/ - GEN_MP_IOCTL_SUBCODE(GET_THERMAL_METER), /*25*/ - GEN_MP_IOCTL_SUBCODE(GET_POWER_MODE), /*26*/ - GEN_MP_IOCTL_SUBCODE(EFUSE), /*27*/ - GEN_MP_IOCTL_SUBCODE(EFUSE_MAP), /*28*/ - GEN_MP_IOCTL_SUBCODE(GET_EFUSE_MAX_SIZE), /*29*/ - GEN_MP_IOCTL_SUBCODE(GET_EFUSE_CURRENT_SIZE), /*30*/ - GEN_MP_IOCTL_SUBCODE(SC_TX), /*31*/ - GEN_MP_IOCTL_SUBCODE(CS_TX), /*32*/ - GEN_MP_IOCTL_SUBCODE(ST_TX), /*33*/ - GEN_MP_IOCTL_SUBCODE(SET_ANTENNA), /*34*/ - MAX_MP_IOCTL_SUBCODE, -}; - -unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv); - -#ifdef _RTL871X_MP_IOCTL_C_ /* CAUTION!!! */ -/* This ifdef _MUST_ be left in!! */ - -static struct mp_ioctl_handler mp_ioctl_hdl[] = { - {sizeof(u32), oid_rt_pro_start_test_hdl, - OID_RT_PRO_START_TEST},/*0*/ - {sizeof(u32), oid_rt_pro_stop_test_hdl, - OID_RT_PRO_STOP_TEST},/*1*/ - {sizeof(struct rwreg_param), - oid_rt_pro_read_register_hdl, - OID_RT_PRO_READ_REGISTER},/*2*/ - {sizeof(struct rwreg_param), - oid_rt_pro_write_register_hdl, - OID_RT_PRO_WRITE_REGISTER}, - {sizeof(u32), - oid_rt_pro_set_channel_direct_call_hdl, - OID_RT_PRO_SET_CHANNEL_DIRECT_CALL}, - {sizeof(struct txpower_param), - oid_rt_pro_set_tx_power_control_hdl, - OID_RT_PRO_SET_TX_POWER_CONTROL}, - {sizeof(u32), - oid_rt_pro_set_data_rate_hdl, - OID_RT_PRO_SET_DATA_RATE}, - {sizeof(struct bb_reg_param), - oid_rt_pro_read_bb_reg_hdl, - OID_RT_PRO_READ_BB_REG},/*7*/ - {sizeof(struct bb_reg_param), - oid_rt_pro_write_bb_reg_hdl, - OID_RT_PRO_WRITE_BB_REG}, - {sizeof(struct rwreg_param), - oid_rt_pro_read_rf_reg_hdl, - OID_RT_PRO_RF_READ_REGISTRY},/*9*/ - {sizeof(struct rwreg_param), - oid_rt_pro_write_rf_reg_hdl, - OID_RT_PRO_RF_WRITE_REGISTRY}, - {sizeof(struct rfintfs_parm), NULL, 0}, - {0, mp_ioctl_xmit_packet_hdl, 0},/*12*/ - {sizeof(struct psmode_param), NULL, 0},/*13*/ - {sizeof(struct eeprom_rw_param), NULL, 0},/*14*/ - {sizeof(struct eeprom_rw_param), NULL, 0},/*15*/ - {sizeof(unsigned char), NULL, 0},/*16*/ - {sizeof(u32), NULL, 0},/*17*/ - {sizeof(u32), oid_rt_pro_set_continuous_tx_hdl, - OID_RT_PRO_SET_CONTINUOUS_TX},/*18*/ - {sizeof(u32), oid_rt_set_bandwidth_hdl, - OID_RT_SET_BANDWIDTH},/*19*/ - {sizeof(u32), oid_rt_set_rx_packet_type_hdl, - OID_RT_SET_RX_PACKET_TYPE},/*20*/ - {0, oid_rt_reset_phy_rx_packet_count_hdl, - OID_RT_RESET_PHY_RX_PACKET_COUNT},/*21*/ - {sizeof(u32), oid_rt_get_phy_rx_packet_received_hdl, - OID_RT_GET_PHY_RX_PACKET_RECEIVED},/*22*/ - {sizeof(u32), oid_rt_get_phy_rx_packet_crc32_error_hdl, - OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR},/*23*/ - {sizeof(unsigned char), oid_rt_set_power_down_hdl, - OID_RT_SET_POWER_DOWN},/*24*/ - {sizeof(u32), oid_rt_get_thermal_meter_hdl, - OID_RT_PRO_GET_THERMAL_METER},/*25*/ - {sizeof(u32), oid_rt_get_power_mode_hdl, - OID_RT_GET_POWER_MODE},/*26*/ - {sizeof(struct EFUSE_ACCESS_STRUCT), - oid_rt_pro_efuse_hdl, OID_RT_PRO_EFUSE},/*27*/ - {EFUSE_MAP_MAX_SIZE, oid_rt_pro_efuse_map_hdl, - OID_RT_PRO_EFUSE_MAP},/*28*/ - {sizeof(u32), oid_rt_get_efuse_max_size_hdl, - OID_RT_GET_EFUSE_MAX_SIZE},/*29*/ - {sizeof(u32), oid_rt_get_efuse_current_size_hdl, - OID_RT_GET_EFUSE_CURRENT_SIZE},/*30*/ - {sizeof(u32), oid_rt_pro_set_single_carrier_tx_hdl, - OID_RT_PRO_SET_SINGLE_CARRIER_TX},/*31*/ - {sizeof(u32), oid_rt_pro_set_carrier_suppression_tx_hdl, - OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX},/*32*/ - {sizeof(u32), oid_rt_pro_set_single_tone_tx_hdl, - OID_RT_PRO_SET_SINGLE_TONE_TX},/*33*/ - {sizeof(u32), oid_rt_pro_set_antenna_bb_hdl, - OID_RT_PRO_SET_ANTENNA_BB},/*34*/ -}; - -#else /* _RTL871X_MP_IOCTL_C_ */ -extern struct mp_ioctl_handler mp_ioctl_hdl[]; -#endif /* _RTL871X_MP_IOCTL_C_ */ - -#endif - diff --git a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h deleted file mode 100644 index bb9f83d58225dc..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h +++ /dev/null @@ -1,1034 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/***************************************************************************** - * Copyright(c) 2008, RealTEK Technology Inc. All Right Reserved. - * - * Module: __INC_HAL8192SPHYREG_H - * - * - * Note: 1. Define PMAC/BB register map - * 2. Define RF register map - * 3. PMAC/BB register bit mask. - * 4. RF reg bit mask. - * 5. Other BB/RF relative definition. - * - * - * Export: Constants, macro, functions(API), global variables(None). - * - * Abbrev: - * - * History: - * Data Who Remark - * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. - * 2. Reorganize code architecture. - * 09/25/2008 MH 1. Add RL6052 register definition - * - *****************************************************************************/ -#ifndef __RTL871X_MP_PHY_REGDEF_H -#define __RTL871X_MP_PHY_REGDEF_H - -/*--------------------------Define Parameters-------------------------------*/ - -/*============================================================ - * 8192S Register offset definition - *============================================================ - * - * - * BB-PHY register PMAC 0x100 PHY 0x800 - 0xEFF - * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF - * 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 - * 3. RF register 0x00-2E - * 4. Bit Mask for BB/RF register - * 5. Other definition for BB/RF R/W - * - * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF - * 1. Page1(0x100) - */ -#define rPMAC_Reset 0x100 -#define rPMAC_TxStart 0x104 -#define rPMAC_TxLegacySIG 0x108 -#define rPMAC_TxHTSIG1 0x10c -#define rPMAC_TxHTSIG2 0x110 -#define rPMAC_PHYDebug 0x114 -#define rPMAC_TxPacketNum 0x118 -#define rPMAC_TxIdle 0x11c -#define rPMAC_TxMACHeader0 0x120 -#define rPMAC_TxMACHeader1 0x124 -#define rPMAC_TxMACHeader2 0x128 -#define rPMAC_TxMACHeader3 0x12c -#define rPMAC_TxMACHeader4 0x130 -#define rPMAC_TxMACHeader5 0x134 -#define rPMAC_TxDataType 0x138 -#define rPMAC_TxRandomSeed 0x13c -#define rPMAC_CCKPLCPPreamble 0x140 -#define rPMAC_CCKPLCPHeader 0x144 -#define rPMAC_CCKCRC16 0x148 -#define rPMAC_OFDMRxCRC32OK 0x170 -#define rPMAC_OFDMRxCRC32Er 0x174 -#define rPMAC_OFDMRxParityEr 0x178 -#define rPMAC_OFDMRxCRC8Er 0x17c -#define rPMAC_CCKCRxRC16Er 0x180 -#define rPMAC_CCKCRxRC32Er 0x184 -#define rPMAC_CCKCRxRC32OK 0x188 -#define rPMAC_TxStatus 0x18c - -/* - * 2. Page2(0x200) - * - * The following two definition are only used for USB interface. - *#define RF_BB_CMD_ADDR 0x02c0 // RF/BB read/write command address. - *#define RF_BB_CMD_DATA 0x02c4 // RF/BB read/write command data. - * - * - * 3. Page8(0x800) - */ -#define rFPGA0_RFMOD 0x800 /*RF mode & CCK TxSC RF - * BW Setting?? - */ -#define rFPGA0_TxInfo 0x804 /* Status report?? */ -#define rFPGA0_PSDFunction 0x808 -#define rFPGA0_TxGainStage 0x80c /* Set TX PWR init gain? */ -#define rFPGA0_RFTiming1 0x810 /* Useless now */ -#define rFPGA0_RFTiming2 0x814 -#define rFPGA0_XA_HSSIParameter1 0x820 /* RF 3 wire register */ -#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 /* Useless now */ -#define rFPGA0_RFSleepUpParameter 0x854 - -#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ -#define rFPGA0_XCD_SwitchControl 0x85c - -#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ -#define rFPGA0_XB_RFInterfaceOE 0x864 -#define rFPGA0_XC_RFInterfaceOE 0x868 -#define rFPGA0_XD_RFInterfaceOE 0x86c -#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Interface Software Ctrl */ -#define rFPGA0_XCD_RFInterfaceSW 0x874 - -#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ -#define rFPGA0_XCD_RFParameter 0x87c - -#define rFPGA0_AnalogParameter1 0x880 /* Crystal cap setting - * RF-R/W protection - * for parameter4?? - */ -#define rFPGA0_AnalogParameter2 0x884 -#define rFPGA0_AnalogParameter3 0x888 /* Useless now */ -#define rFPGA0_AnalogParameter4 0x88c - -#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Transceiver LSSI Readback */ -#define rFPGA0_XB_LSSIReadBack 0x8a4 -#define rFPGA0_XC_LSSIReadBack 0x8a8 -#define rFPGA0_XD_LSSIReadBack 0x8ac - -#define rFPGA0_PSDReport 0x8b4 /* Useless now */ -#define rFPGA0_XAB_RFInterfaceRB 0x8e0 /* Useless now */ -#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */ - -/* - * 4. Page9(0x900) - */ -#define rFPGA1_RFMOD 0x900 /* RF mode & OFDM TxSC */ - -#define rFPGA1_TxBlock 0x904 /* Useless now */ -#define rFPGA1_DebugSelect 0x908 /* Useless now */ -#define rFPGA1_TxInfo 0x90c /* Useless now */ - -/* - * 5. PageA(0xA00) - * - * Set Control channel to upper or lower. - * These settings are required only for 40MHz - */ -#define rCCK0_System 0xa00 - -#define rCCK0_AFESetting 0xa04 /* Disable init gain now */ -#define rCCK0_CCA 0xa08 /* Disable init gain now */ - -#define rCCK0_RxAGC1 0xa0c -/* AGC default value, saturation level - * Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. - * Not the same as 90 series - */ -#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */ - -#define rCCK0_RxHP 0xa14 - -#define rCCK0_DSPParameter1 0xa18 /* Timing recovery & Channel - * estimation threshold - */ -#define rCCK0_DSPParameter2 0xa1c /* SQ threshold */ - -#define rCCK0_TxFilter1 0xa20 -#define rCCK0_TxFilter2 0xa24 -#define rCCK0_DebugPort 0xa28 /* debug port and Tx filter3 */ -#define rCCK0_FalseAlarmReport 0xa2c /* 0xa2d useless now 0xa30-a4f - * channel report - */ -#define rCCK0_TRSSIReport 0xa50 -#define rCCK0_RxReport 0xa54 /* 0xa57 */ -#define rCCK0_FACounterLower 0xa5c /* 0xa5b */ -#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */ - -/* - * 6. PageC(0xC00) - */ -#define rOFDM0_LSTF 0xc00 -#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 DM tune - * init gain - */ -#define rOFDM0_RxDetector2 0xc34 /* SBD & Fame Sync. */ -#define rOFDM0_RxDetector3 0xc38 /* Frame Sync. */ -#define rOFDM0_RxDetector4 0xc3c /* PD, SBD, Frame Sync & - * Short-GI - */ - -#define rOFDM0_RxDSP 0xc40 /* Rx Sync Path */ -#define rOFDM0_CFOandDAGC 0xc44 /* CFO & DAGC */ -#define rOFDM0_CCADropThreshold 0xc48 /* CCA Drop threshold */ -#define rOFDM0_ECCAThreshold 0xc4c /* energy CCA */ - -#define rOFDM0_XAAGCCore1 0xc50 /* DIG */ -#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 /* TX PWR TRACK and DIG */ -#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 -#define rOFDM0_DFSReport 0xcf4 -#define rOFDM0_TxCoeff1 0xca4 -#define rOFDM0_TxCoeff2 0xca8 -#define rOFDM0_TxCoeff3 0xcac -#define rOFDM0_TxCoeff4 0xcb0 -#define rOFDM0_TxCoeff5 0xcb4 -#define rOFDM0_TxCoeff6 0xcb8 - -/* - * 7. PageD(0xD00) - */ -#define rOFDM1_LSTF 0xd00 -#define rOFDM1_TRxPathEnable 0xd04 - -#define rOFDM1_CFO 0xd08 /* No setting now */ -#define rOFDM1_CSI1 0xd10 -#define rOFDM1_SBD 0xd14 -#define rOFDM1_CSI2 0xd18 -#define rOFDM1_CFOTracking 0xd2c -#define rOFDM1_TRxMesaure1 0xd34 -#define rOFDM1_IntfDet 0xd3c -#define rOFDM1_PseudoNoiseStateAB 0xd50 -#define rOFDM1_PseudoNoiseStateCD 0xd54 -#define rOFDM1_RxPseudoNoiseWgt 0xd58 - -#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */ -#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */ -#define rOFDM_PHYCounter3 0xda8 /* MCS not support */ -#define rOFDM_ShortCFOAB 0xdac /* No setting now */ -#define rOFDM_ShortCFOCD 0xdb0 -#define rOFDM_LongCFOAB 0xdb4 -#define rOFDM_LongCFOCD 0xdb8 -#define rOFDM_TailCFOAB 0xdbc -#define rOFDM_TailCFOCD 0xdc0 -#define rOFDM_PWMeasure1 0xdc4 -#define rOFDM_PWMeasure2 0xdc8 -#define rOFDM_BWReport 0xdcc -#define rOFDM_AGCReport 0xdd0 -#define rOFDM_RxSNR 0xdd4 -#define rOFDM_RxEVMCSI 0xdd8 -#define rOFDM_SIGReport 0xddc - -/* - * 8. PageE(0xE00) - */ -#define rTxAGC_Rate18_06 0xe00 -#define rTxAGC_Rate54_24 0xe04 -#define rTxAGC_CCK_Mcs32 0xe08 -#define rTxAGC_Mcs03_Mcs00 0xe10 -#define rTxAGC_Mcs07_Mcs04 0xe14 -#define rTxAGC_Mcs11_Mcs08 0xe18 -#define rTxAGC_Mcs15_Mcs12 0xe1c - -/* Analog- control in RX_WAIT_CCA : REG: EE0 - * [Analog- Power & Control Register] - */ -#define rRx_Wait_CCCA 0xe70 -#define rAnapar_Ctrl_BB 0xee0 - -/* - * 7. RF Register 0x00-0x2E (RF 8256) - * RF-0222D 0x00-3F - * - * Zebra1 - */ -#define rZebra1_HSSIEnable 0x0 /* Useless now */ -#define rZebra1_TRxEnable1 0x1 -#define rZebra1_TRxEnable2 0x2 -#define rZebra1_AGC 0x4 -#define rZebra1_ChargePump 0x5 -#define rZebra1_Channel 0x7 /* RF channel switch */ -#define rZebra1_TxGain 0x8 /* Useless now */ -#define rZebra1_TxLPF 0x9 -#define rZebra1_RxLPF 0xb -#define rZebra1_RxHPFCorner 0xc - -/* Zebra4 */ -#define rGlobalCtrl 0 /* Useless now */ -#define rRTL8256_TxLPF 19 -#define rRTL8256_RxLPF 11 - -/* RTL8258 */ -#define rRTL8258_TxLPF 0x11 /* Useless now */ -#define rRTL8258_RxLPF 0x13 -#define rRTL8258_RSSILPF 0xa - -/* RL6052 Register definition */ -#define RF_AC 0x00 -#define RF_IQADJ_G1 0x01 -#define RF_IQADJ_G2 0x02 -#define RF_POW_TRSW 0x05 - -#define RF_GAIN_RX 0x06 -#define RF_GAIN_TX 0x07 - -#define RF_TXM_IDAC 0x08 -#define RF_BS_IQGEN 0x0F - -#define RF_MODE1 0x10 -#define RF_MODE2 0x11 - -#define RF_RX_AGC_HP 0x12 -#define RF_TX_AGC 0x13 -#define RF_BIAS 0x14 -#define RF_IPA 0x15 -#define RF_POW_ABILITY 0x17 -#define RF_MODE_AG 0x18 -#define rRfChannel 0x18 /* RF channel and BW switch */ -#define RF_CHNLBW 0x18 /* RF channel and BW switch */ -#define RF_TOP 0x19 -#define RF_RX_G1 0x1A -#define RF_RX_G2 0x1B -#define RF_RX_BB2 0x1C -#define RF_RX_BB1 0x1D - -#define RF_RCK1 0x1E -#define RF_RCK2 0x1F - -#define RF_TX_G1 0x20 -#define RF_TX_G2 0x21 -#define RF_TX_G3 0x22 - -#define RF_TX_BB1 0x23 -#define RF_T_METER 0x24 - -#define RF_SYN_G1 0x25 /* RF TX Power control */ -#define RF_SYN_G2 0x26 /* RF TX Power control */ -#define RF_SYN_G3 0x27 /* RF TX Power control */ -#define RF_SYN_G4 0x28 /* RF TX Power control */ -#define RF_SYN_G5 0x29 /* RF TX Power control */ -#define RF_SYN_G6 0x2A /* RF TX Power control */ -#define RF_SYN_G7 0x2B /* RF TX Power control */ -#define RF_SYN_G8 0x2C /* RF TX Power control */ - -#define RF_RCK_OS 0x30 /* RF TX PA control */ - -#define RF_TXPA_G1 0x31 /* RF TX PA control */ -#define RF_TXPA_G2 0x32 /* RF TX PA control */ -#define RF_TXPA_G3 0x33 /* RF TX PA control */ - -/* - * Bit Mask - * - * 1. Page1(0x100) - */ -#define bBBResetB 0x100 /* Useless now? */ -#define bGlobalResetB 0x200 -#define bOFDMTxStart 0x4 -#define bCCKTxStart 0x8 -#define bCRC32Debug 0x100 -#define bPMACLoopback 0x10 -#define bTxLSIG 0xffffff -#define bOFDMTxRate 0xf -#define bOFDMTxReserved 0x10 -#define bOFDMTxLength 0x1ffe0 -#define bOFDMTxParity 0x20000 -#define bTxHTSIG1 0xffffff -#define bTxHTMCSRate 0x7f -#define bTxHTBW 0x80 -#define bTxHTLength 0xffff00 -#define bTxHTSIG2 0xffffff -#define bTxHTSmoothing 0x1 -#define bTxHTSounding 0x2 -#define bTxHTReserved 0x4 -#define bTxHTAggreation 0x8 -#define bTxHTSTBC 0x30 -#define bTxHTAdvanceCoding 0x40 -#define bTxHTShortGI 0x80 -#define bTxHTNumberHT_LTF 0x300 -#define bTxHTCRC8 0x3fc00 -#define bCounterReset 0x10000 -#define bNumOfOFDMTx 0xffff -#define bNumOfCCKTx 0xffff0000 -#define bTxIdleInterval 0xffff -#define bOFDMService 0xffff0000 -#define bTxMACHeader 0xffffffff -#define bTxDataInit 0xff -#define bTxHTMode 0x100 -#define bTxDataType 0x30000 -#define bTxRandomSeed 0xffffffff -#define bCCKTxPreamble 0x1 -#define bCCKTxSFD 0xffff0000 -#define bCCKTxSIG 0xff -#define bCCKTxService 0xff00 -#define bCCKLengthExt 0x8000 -#define bCCKTxLength 0xffff0000 -#define bCCKTxCRC16 0xffff -#define bCCKTxStatus 0x1 -#define bOFDMTxStatus 0x2 -#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && \ - (_Offset <= 0xfff)) - -/* 2. Page8(0x800) */ -#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ -#define bJapanMode 0x2 -#define bCCKTxSC 0x30 -#define bCCKEn 0x1000000 -#define bOFDMEn 0x2000000 - -#define bOFDMRxADCPhase 0x10000 /* Useless now */ -#define bOFDMTxDACPhase 0x40000 -#define bXATxAGC 0x3f -#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ -#define bXCTxAGC 0xf000 -#define bXDTxAGC 0xf0000 - -#define bPAStart 0xf0000000 /* Useless now */ -#define bTRStart 0x00f00000 -#define bRFStart 0x0000f000 -#define bBBStart 0x000000f0 -#define bBBCCKStart 0x0000000f -#define bPAEnd 0xf /* Reg0x814 */ -#define bTREnd 0x0f000000 -#define bRFEnd 0x000f0000 -#define bCCAMask 0x000000f0 /* T2R */ -#define bR2RCCAMask 0x00000f00 -#define bHSSI_R2TDelay 0xf8000000 -#define bHSSI_T2RDelay 0xf80000 -#define bContTxHSSI 0x400 /* change gain at continue Tx */ -#define bIGFromCCK 0x200 -#define bAGCAddress 0x3f -#define bRxHPTx 0x7000 -#define bRxHPT2R 0x38000 -#define bRxHPCCKIni 0xc0000 -#define bAGCTxCode 0xc00000 -#define bAGCRxCode 0x300000 -#define b3WireDataLength 0x800 /* Reg 0x820~84f rFPGA0_XA_HSSIParm1 */ -#define b3WireAddressLength 0x400 -#define b3WireRFPowerDown 0x1 /* Useless now */ -#define b5GPAPEPolarity 0x40000000 -#define b2GPAPEPolarity 0x80000000 -#define bRFSW_TxDefaultAnt 0x3 -#define bRFSW_TxOptionAnt 0x30 -#define bRFSW_RxDefaultAnt 0x300 -#define bRFSW_RxOptionAnt 0x3000 -#define bRFSI_3WireData 0x1 -#define bRFSI_3WireClock 0x2 -#define bRFSI_3WireLoad 0x4 -#define bRFSI_3WireRW 0x8 -#define bRFSI_3Wire 0xf -#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */ -#define bRFSI_TRSW 0x20 /* Useless now */ -#define bRFSI_TRSWB 0x40 -#define bRFSI_ANTSW 0x100 -#define bRFSI_ANTSWB 0x200 -#define bRFSI_PAPE 0x400 -#define bRFSI_PAPE5G 0x800 -#define bBandSelect 0x1 -#define bHTSIG2_GI 0x80 -#define bHTSIG2_Smoothing 0x01 -#define bHTSIG2_Sounding 0x02 -#define bHTSIG2_Aggreaton 0x08 -#define bHTSIG2_STBC 0x30 -#define bHTSIG2_AdvCoding 0x40 -#define bHTSIG2_NumOfHTLTF 0x300 -#define bHTSIG2_CRC8 0x3fc -#define bHTSIG1_MCS 0x7f -#define bHTSIG1_BandWidth 0x80 -#define bHTSIG1_HTLength 0xffff -#define bLSIG_Rate 0xf -#define bLSIG_Reserved 0x10 -#define bLSIG_Length 0x1fffe -#define bLSIG_Parity 0x20 -#define bCCKRxPhase 0x4 -#define bLSSIReadAddress 0x7f800000 /* T65 RF */ -#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */ -#define bLSSIReadBackData 0xfffff /* T65 RF */ -#define bLSSIReadOKFlag 0x1000 /* Useless now */ -#define bCCKSampleRate 0x8 /*0: 44MHz, 1:88MHz*/ -#define bRegulator0Standby 0x1 -#define bRegulatorPLLStandby 0x2 -#define bRegulator1Standby 0x4 -#define bPLLPowerUp 0x8 -#define bDPLLPowerUp 0x10 -#define bDA10PowerUp 0x20 -#define bAD7PowerUp 0x200 -#define bDA6PowerUp 0x2000 -#define bXtalPowerUp 0x4000 -#define b40MDClkPowerUP 0x8000 -#define bDA6DebugMode 0x20000 -#define bDA6Swing 0x380000 - -/* Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */ -#define bADClkPhase 0x4000000 - -#define b80MClkDelay 0x18000000 /* Useless */ -#define bAFEWatchDogEnable 0x20000000 - -/* Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */ -#define bXtalCap01 0xc0000000 -#define bXtalCap23 0x3 -#define bXtalCap92x 0x0f000000 -#define bXtalCap 0x0f000000 -#define bIntDifClkEnable 0x400 /* Useless */ -#define bExtSigClkEnable 0x800 -#define bBandgapMbiasPowerUp 0x10000 -#define bAD11SHGain 0xc0000 -#define bAD11InputRange 0x700000 -#define bAD11OPCurrent 0x3800000 -#define bIPathLoopback 0x4000000 -#define bQPathLoopback 0x8000000 -#define bAFELoopback 0x10000000 -#define bDA10Swing 0x7e0 -#define bDA10Reverse 0x800 -#define bDAClkSource 0x1000 -#define bAD7InputRange 0x6000 -#define bAD7Gain 0x38000 -#define bAD7OutputCMMode 0x40000 -#define bAD7InputCMMode 0x380000 -#define bAD7Current 0xc00000 -#define bRegulatorAdjust 0x7000000 -#define bAD11PowerUpAtTx 0x1 -#define bDA10PSAtTx 0x10 -#define bAD11PowerUpAtRx 0x100 -#define bDA10PSAtRx 0x1000 -#define bCCKRxAGCFormat 0x200 -#define bPSDFFTSamplepPoint 0xc000 -#define bPSDAverageNum 0x3000 -#define bIQPathControl 0xc00 -#define bPSDFreq 0x3ff -#define bPSDAntennaPath 0x30 -#define bPSDIQSwitch 0x40 -#define bPSDRxTrigger 0x400000 -#define bPSDTxTrigger 0x80000000 -#define bPSDSineToneScale 0x7f000000 -#define bPSDReport 0xffff - -/* 3. Page9(0x900) */ -#define bOFDMTxSC 0x30000000 /* Useless */ -#define bCCKTxOn 0x1 -#define bOFDMTxOn 0x2 -#define bDebugPage 0xfff /* reset debug page and HWord, LWord */ -#define bDebugItem 0xff /* reset debug page and LWord */ -#define bAntL 0x10 -#define bAntNonHT 0x100 -#define bAntHT1 0x1000 -#define bAntHT2 0x10000 -#define bAntHT1S1 0x100000 -#define bAntNonHTS1 0x1000000 - -/* 4. PageA(0xA00) */ -#define bCCKBBMode 0x3 /* Useless */ -#define bCCKTxPowerSaving 0x80 -#define bCCKRxPowerSaving 0x40 - -#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 switch*/ -#define bCCKScramble 0x8 /* Useless */ -#define bCCKAntDiversity 0x8000 -#define bCCKCarrierRecovery 0x4000 -#define bCCKTxRate 0x3000 -#define bCCKDCCancel 0x0800 -#define bCCKISICancel 0x0400 -#define bCCKMatchFilter 0x0200 -#define bCCKEqualizer 0x0100 -#define bCCKPreambleDetect 0x800000 -#define bCCKFastFalseCCA 0x400000 -#define bCCKChEstStart 0x300000 -#define bCCKCCACount 0x080000 -#define bCCKcs_lim 0x070000 -#define bCCKBistMode 0x80000000 -#define bCCKCCAMask 0x40000000 -#define bCCKTxDACPhase 0x4 -#define bCCKRxADCPhase 0x20000000 /* r_rx_clk */ -#define bCCKr_cp_mode0 0x0100 -#define bCCKTxDCOffset 0xf0 -#define bCCKRxDCOffset 0xf -#define bCCKCCAMode 0xc000 -#define bCCKFalseCS_lim 0x3f00 -#define bCCKCS_ratio 0xc00000 -#define bCCKCorgBit_sel 0x300000 -#define bCCKPD_lim 0x0f0000 -#define bCCKNewCCA 0x80000000 -#define bCCKRxHPofIG 0x8000 -#define bCCKRxIG 0x7f00 -#define bCCKLNAPolarity 0x800000 -#define bCCKRx1stGain 0x7f0000 -#define bCCKRFExtend 0x20000000 /* CCK Rx initial gain polarity */ -#define bCCKRxAGCSatLevel 0x1f000000 -#define bCCKRxAGCSatCount 0xe0 -#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ -#define bCCKFixedRxAGC 0x8000 -#define bCCKAntennaPolarity 0x2000 -#define bCCKTxFilterType 0x0c00 -#define bCCKRxAGCReportType 0x0300 -#define bCCKRxDAGCEn 0x80000000 -#define bCCKRxDAGCPeriod 0x20000000 -#define bCCKRxDAGCSatLevel 0x1f000000 -#define bCCKTimingRecovery 0x800000 -#define bCCKTxC0 0x3f0000 -#define bCCKTxC1 0x3f000000 -#define bCCKTxC2 0x3f -#define bCCKTxC3 0x3f00 -#define bCCKTxC4 0x3f0000 -#define bCCKTxC5 0x3f000000 -#define bCCKTxC6 0x3f -#define bCCKTxC7 0x3f00 -#define bCCKDebugPort 0xff0000 -#define bCCKDACDebug 0x0f000000 -#define bCCKFalseAlarmEnable 0x8000 -#define bCCKFalseAlarmRead 0x4000 -#define bCCKTRSSI 0x7f -#define bCCKRxAGCReport 0xfe -#define bCCKRxReport_AntSel 0x80000000 -#define bCCKRxReport_MFOff 0x40000000 -#define bCCKRxRxReport_SQLoss 0x20000000 -#define bCCKRxReport_Pktloss 0x10000000 -#define bCCKRxReport_Lockedbit 0x08000000 -#define bCCKRxReport_RateError 0x04000000 -#define bCCKRxReport_RxRate 0x03000000 -#define bCCKRxFACounterLower 0xff -#define bCCKRxFACounterUpper 0xff000000 -#define bCCKRxHPAGCStart 0xe000 -#define bCCKRxHPAGCFinal 0x1c00 -#define bCCKRxFalseAlarmEnable 0x8000 -#define bCCKFACounterFreeze 0x4000 -#define bCCKTxPathSel 0x10000000 -#define bCCKDefaultRxPath 0xc000000 -#define bCCKOptionRxPath 0x3000000 - -/* 5. PageC(0xC00) */ -#define bNumOfSTF 0x3 /* Useless */ -#define bShift_L 0xc0 -#define bGI_TH 0xc -#define bRxPathA 0x1 -#define bRxPathB 0x2 -#define bRxPathC 0x4 -#define bRxPathD 0x8 -#define bTxPathA 0x1 -#define bTxPathB 0x2 -#define bTxPathC 0x4 -#define bTxPathD 0x8 -#define bTRSSIFreq 0x200 -#define bADCBackoff 0x3000 -#define bDFIRBackoff 0xc000 -#define bTRSSILatchPhase 0x10000 -#define bRxIDCOffset 0xff -#define bRxQDCOffset 0xff00 -#define bRxDFIRMode 0x1800000 -#define bRxDCNFType 0xe000000 -#define bRXIQImb_A 0x3ff -#define bRXIQImb_B 0xfc00 -#define bRXIQImb_C 0x3f0000 -#define bRXIQImb_D 0xffc00000 -#define bDC_dc_Notch 0x60000 -#define bRxNBINotch 0x1f000000 -#define bPD_TH 0xf -#define bPD_TH_Opt2 0xc000 -#define bPWED_TH 0x700 -#define bIfMF_Win_L 0x800 -#define bPD_Option 0x1000 -#define bMF_Win_L 0xe000 -#define bBW_Search_L 0x30000 -#define bwin_enh_L 0xc0000 -#define bBW_TH 0x700000 -#define bED_TH2 0x3800000 -#define bBW_option 0x4000000 -#define bRatio_TH 0x18000000 -#define bWindow_L 0xe0000000 -#define bSBD_Option 0x1 -#define bFrame_TH 0x1c -#define bFS_Option 0x60 -#define bDC_Slope_check 0x80 -#define bFGuard_Counter_DC_L 0xe00 -#define bFrame_Weight_Short 0x7000 -#define bSub_Tune 0xe00000 -#define bFrame_DC_Length 0xe000000 -#define bSBD_start_offset 0x30000000 -#define bFrame_TH_2 0x7 -#define bFrame_GI2_TH 0x38 -#define bGI2_Sync_en 0x40 -#define bSarch_Short_Early 0x300 -#define bSarch_Short_Late 0xc00 -#define bSarch_GI2_Late 0x70000 -#define bCFOAntSum 0x1 -#define bCFOAcc 0x2 -#define bCFOStartOffset 0xc -#define bCFOLookBack 0x70 -#define bCFOSumWeight 0x80 -#define bDAGCEnable 0x10000 -#define bTXIQImb_A 0x3ff -#define bTXIQImb_B 0xfc00 -#define bTXIQImb_C 0x3f0000 -#define bTXIQImb_D 0xffc00000 -#define bTxIDCOffset 0xff -#define bTxQDCOffset 0xff00 -#define bTxDFIRMode 0x10000 -#define bTxPesudoNoiseOn 0x4000000 -#define bTxPesudoNoise_A 0xff -#define bTxPesudoNoise_B 0xff00 -#define bTxPesudoNoise_C 0xff0000 -#define bTxPesudoNoise_D 0xff000000 -#define bCCADropOption 0x20000 -#define bCCADropThres 0xfff00000 -#define bEDCCA_H 0xf -#define bEDCCA_L 0xf0 -#define bLambda_ED 0x300 -#define bRxInitialGain 0x7f -#define bRxAntDivEn 0x80 -#define bRxAGCAddressForLNA 0x7f00 -#define bRxHighPowerFlow 0x8000 -#define bRxAGCFreezeThres 0xc0000 -#define bRxFreezeStep_AGC1 0x300000 -#define bRxFreezeStep_AGC2 0xc00000 -#define bRxFreezeStep_AGC3 0x3000000 -#define bRxFreezeStep_AGC0 0xc000000 -#define bRxRssi_Cmp_En 0x10000000 -#define bRxQuickAGCEn 0x20000000 -#define bRxAGCFreezeThresMode 0x40000000 -#define bRxOverFlowCheckType 0x80000000 -#define bRxAGCShift 0x7f -#define bTRSW_Tri_Only 0x80 -#define bPowerThres 0x300 -#define bRxAGCEn 0x1 -#define bRxAGCTogetherEn 0x2 -#define bRxAGCMin 0x4 -#define bRxHP_Ini 0x7 -#define bRxHP_TRLNA 0x70 -#define bRxHP_RSSI 0x700 -#define bRxHP_BBP1 0x7000 -#define bRxHP_BBP2 0x70000 -#define bRxHP_BBP3 0x700000 -#define bRSSI_H 0x7f0000 /* the threshold for high power */ -#define bRSSI_Gen 0x7f000000 /* the threshold for ant divers */ -#define bRxSettle_TRSW 0x7 -#define bRxSettle_LNA 0x38 -#define bRxSettle_RSSI 0x1c0 -#define bRxSettle_BBP 0xe00 -#define bRxSettle_RxHP 0x7000 -#define bRxSettle_AntSW_RSSI 0x38000 -#define bRxSettle_AntSW 0xc0000 -#define bRxProcessTime_DAGC 0x300000 -#define bRxSettle_HSSI 0x400000 -#define bRxProcessTime_BBPPW 0x800000 -#define bRxAntennaPowerShift 0x3000000 -#define bRSSITableSelect 0xc000000 -#define bRxHP_Final 0x7000000 -#define bRxHTSettle_BBP 0x7 -#define bRxHTSettle_HSSI 0x8 -#define bRxHTSettle_RxHP 0x70 -#define bRxHTSettle_BBPPW 0x80 -#define bRxHTSettle_Idle 0x300 -#define bRxHTSettle_Reserved 0x1c00 -#define bRxHTRxHPEn 0x8000 -#define bRxHTAGCFreezeThres 0x30000 -#define bRxHTAGCTogetherEn 0x40000 -#define bRxHTAGCMin 0x80000 -#define bRxHTAGCEn 0x100000 -#define bRxHTDAGCEn 0x200000 -#define bRxHTRxHP_BBP 0x1c00000 -#define bRxHTRxHP_Final 0xe0000000 -#define bRxPWRatioTH 0x3 -#define bRxPWRatioEn 0x4 -#define bRxMFHold 0x3800 -#define bRxPD_Delay_TH1 0x38 -#define bRxPD_Delay_TH2 0x1c0 -#define bRxPD_DC_COUNT_MAX 0x600 -#define bRxPD_Delay_TH 0x8000 -#define bRxProcess_Delay 0xf0000 -#define bRxSearchrange_GI2_Early 0x700000 -#define bRxFrame_Guard_Counter_L 0x3800000 -#define bRxSGI_Guard_L 0xc000000 -#define bRxSGI_Search_L 0x30000000 -#define bRxSGI_TH 0xc0000000 -#define bDFSCnt0 0xff -#define bDFSCnt1 0xff00 -#define bDFSFlag 0xf0000 -#define bMFWeightSum 0x300000 -#define bMinIdxTH 0x7f000000 -#define bDAFormat 0x40000 -#define bTxChEmuEnable 0x01000000 -#define bTRSWIsolation_A 0x7f -#define bTRSWIsolation_B 0x7f00 -#define bTRSWIsolation_C 0x7f0000 -#define bTRSWIsolation_D 0x7f000000 -#define bExtLNAGain 0x7c00 - -/* 6. PageE(0xE00) */ -#define bSTBCEn 0x4 /* Useless */ -#define bAntennaMapping 0x10 -#define bNss 0x20 -#define bCFOAntSumD 0x200 -#define bPHYCounterReset 0x8000000 -#define bCFOReportGet 0x4000000 -#define bOFDMContinueTx 0x10000000 -#define bOFDMSingleCarrier 0x20000000 -#define bOFDMSingleTone 0x40000000 -#define bHTDetect 0x100 -#define bCFOEn 0x10000 -#define bCFOValue 0xfff00000 -#define bSigTone_Re 0x3f -#define bSigTone_Im 0x7f00 -#define bCounter_CCA 0xffff -#define bCounter_ParityFail 0xffff0000 -#define bCounter_RateIllegal 0xffff -#define bCounter_CRC8Fail 0xffff0000 -#define bCounter_MCSNoSupport 0xffff -#define bCounter_FastSync 0xffff -#define bShortCFO 0xfff -#define bShortCFOTLength 12 /* total */ -#define bShortCFOFLength 11 /* fraction */ -#define bLongCFO 0x7ff -#define bLongCFOTLength 11 -#define bLongCFOFLength 11 -#define bTailCFO 0x1fff -#define bTailCFOTLength 13 -#define bTailCFOFLength 12 -#define bmax_en_pwdB 0xffff -#define bCC_power_dB 0xffff0000 -#define bnoise_pwdB 0xffff -#define bPowerMeasTLength 10 -#define bPowerMeasFLength 3 -#define bRx_HT_BW 0x1 -#define bRxSC 0x6 -#define bRx_HT 0x8 -#define bNB_intf_det_on 0x1 -#define bIntf_win_len_cfg 0x30 -#define bNB_Intf_TH_cfg 0x1c0 -#define bRFGain 0x3f -#define bTableSel 0x40 -#define bTRSW 0x80 -#define bRxSNR_A 0xff -#define bRxSNR_B 0xff00 -#define bRxSNR_C 0xff0000 -#define bRxSNR_D 0xff000000 -#define bSNREVMTLength 8 -#define bSNREVMFLength 1 -#define bCSI1st 0xff -#define bCSI2nd 0xff00 -#define bRxEVM1st 0xff0000 -#define bRxEVM2nd 0xff000000 -#define bSIGEVM 0xff -#define bPWDB 0xff00 -#define bSGIEN 0x10000 - -#define bSFactorQAM1 0xf /* Useless */ -#define bSFactorQAM2 0xf0 -#define bSFactorQAM3 0xf00 -#define bSFactorQAM4 0xf000 -#define bSFactorQAM5 0xf0000 -#define bSFactorQAM6 0xf0000 -#define bSFactorQAM7 0xf00000 -#define bSFactorQAM8 0xf000000 -#define bSFactorQAM9 0xf0000000 -#define bCSIScheme 0x100000 - -#define bNoiseLvlTopSet 0x3 /* Useless */ -#define bChSmooth 0x4 -#define bChSmoothCfg1 0x38 -#define bChSmoothCfg2 0x1c0 -#define bChSmoothCfg3 0xe00 -#define bChSmoothCfg4 0x7000 -#define bMRCMode 0x800000 -#define bTHEVMCfg 0x7000000 - -#define bLoopFitType 0x1 /* Useless */ -#define bUpdCFO 0x40 -#define bUpdCFOOffData 0x80 -#define bAdvUpdCFO 0x100 -#define bAdvTimeCtrl 0x800 -#define bUpdClko 0x1000 -#define bFC 0x6000 -#define bTrackingMode 0x8000 -#define bPhCmpEnable 0x10000 -#define bUpdClkoLTF 0x20000 -#define bComChCFO 0x40000 -#define bCSIEstiMode 0x80000 -#define bAdvUpdEqz 0x100000 -#define bUChCfg 0x7000000 -#define bUpdEqz 0x8000000 - -#define bTxAGCRate18_06 0x7f7f7f7f /* Useless */ -#define bTxAGCRate54_24 0x7f7f7f7f -#define bTxAGCRateMCS32 0x7f -#define bTxAGCRateCCK 0x7f00 -#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f -#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f -#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f -#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f - -/* Rx Pseduo noise */ -#define bRxPesudoNoiseOn 0x20000000 /* Useless */ -#define bRxPesudoNoise_A 0xff -#define bRxPesudoNoise_B 0xff00 -#define bRxPesudoNoise_C 0xff0000 -#define bRxPesudoNoise_D 0xff000000 -#define bPesudoNoiseState_A 0xffff -#define bPesudoNoiseState_B 0xffff0000 -#define bPesudoNoiseState_C 0xffff -#define bPesudoNoiseState_D 0xffff0000 - -/* 7. RF Register - * Zebra1 - */ -#define bZebra1_HSSIEnable 0x8 /* Useless */ -#define bZebra1_TRxControl 0xc00 -#define bZebra1_TRxGainSetting 0x07f -#define bZebra1_RxCorner 0xc00 -#define bZebra1_TxChargePump 0x38 -#define bZebra1_RxChargePump 0x7 -#define bZebra1_ChannelNum 0xf80 -#define bZebra1_TxLPFBW 0x400 -#define bZebra1_RxLPFBW 0x600 - -/*Zebra4 */ -#define bRTL8256RegModeCtrl1 0x100 /* Useless */ -#define bRTL8256RegModeCtrl0 0x40 -#define bRTL8256_TxLPFBW 0x18 -#define bRTL8256_RxLPFBW 0x600 - -/* RTL8258 */ -#define bRTL8258_TxLPFBW 0xc /* Useless */ -#define bRTL8258_RxLPFBW 0xc00 -#define bRTL8258_RSSILPFBW 0xc0 - -/* - * Other Definition - */ - -/* byte endable for sb_write */ -#define bByte0 0x1 /* Useless */ -#define bByte1 0x2 -#define bByte2 0x4 -#define bByte3 0x8 -#define bWord0 0x3 -#define bWord1 0xc -#define bDWord 0xf - -/* for PutRegsetting & GetRegSetting BitMask */ -#define bMaskByte0 0xff /* Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */ -#define bMaskByte1 0xff00 -#define bMaskByte2 0xff0000 -#define bMaskByte3 0xff000000 -#define bMaskHWord 0xffff0000 -#define bMaskLWord 0x0000ffff -#define bMaskDWord 0xffffffff - -/* for PutRFRegsetting & GetRFRegSetting BitMask */ -#define bRFRegOffsetMask 0xfffff -#define bEnable 0x1 /* Useless */ -#define bDisable 0x0 - -#define LeftAntenna 0x0 /* Useless */ -#define RightAntenna 0x1 - -#define tCheckTxStatus 500 /* 500ms Useless */ -#define tUpdateRxCounter 100 /* 100ms */ - -#define rateCCK 0 /* Useless */ -#define rateOFDM 1 -#define rateHT 2 - -/* define Register-End */ -#define bPMAC_End 0x1ff /* Useless */ -#define bFPGAPHY0_End 0x8ff -#define bFPGAPHY1_End 0x9ff -#define bCCKPHY0_End 0xaff -#define bOFDMPHY0_End 0xcff -#define bOFDMPHY1_End 0xdff - -#define bPMACControl 0x0 /* Useless */ -#define bWMACControl 0x1 -#define bWNICControl 0x2 - -#define ANTENNA_A 0x1 /* Useless */ -#define ANTENNA_B 0x2 -#define ANTENNA_AB 0x3 /* ANTENNA_A |ANTENNA_B */ - -#define ANTENNA_C 0x4 -#define ANTENNA_D 0x8 - -/* accept all physical address */ -#define RCR_AAP BIT(0) -#define RCR_APM BIT(1) /* accept physical match */ -#define RCR_AM BIT(2) /* accept multicast */ -#define RCR_AB BIT(3) /* accept broadcast */ -#define RCR_ACRC32 BIT(5) /* accept error packet */ -#define RCR_9356SEL BIT(6) -#define RCR_AICV BIT(12) /* Accept ICV error packet */ -#define RCR_RXFTH0 (BIT(13)|BIT(14)|BIT(15)) /* Rx FIFO threshold */ -#define RCR_ADF BIT(18) /* Accept Data(frame type) frame */ -#define RCR_ACF BIT(19) /* Accept control frame */ -#define RCR_AMF BIT(20) /* Accept management frame */ -#define RCR_ADD3 BIT(21) -#define RCR_APWRMGT BIT(22) /* Accept power management packet */ -#define RCR_CBSSID BIT(23) /* Accept BSSID match packet */ -#define RCR_ENMARP BIT(28) /* enable mac auto reset phy */ -#define RCR_EnCS1 BIT(29) /* enable carrier sense method 1 */ -#define RCR_EnCS2 BIT(30) /* enable carrier sense method 2 */ -/* Rx Early mode is performed for packet size greater than 1536 */ -#define RCR_OnlyErlPkt BIT(31) - -/*--------------------------Define Parameters-------------------------------*/ - -#endif /*__INC_HAL8192SPHYREG_H */ - diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.c b/drivers/staging/rtl8712/rtl871x_pwrctrl.c deleted file mode 100644 index cd6d9ff0bebca7..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_pwrctrl.c +++ /dev/null @@ -1,234 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_pwrctrl.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_PWRCTRL_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "osdep_intf.h" - -#define RTL8712_SDIO_LOCAL_BASE 0X10100000 -#define SDIO_HCPWM (RTL8712_SDIO_LOCAL_BASE + 0x0081) - -void r8712_set_rpwm(struct _adapter *padapter, u8 val8) -{ - u8 rpwm; - struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; - - if (pwrpriv->rpwm == val8) { - if (pwrpriv->rpwm_retry == 0) - return; - } - if (padapter->driver_stopped || padapter->surprise_removed) - return; - rpwm = val8 | pwrpriv->tog; - switch (val8) { - case PS_STATE_S1: - pwrpriv->cpwm = val8; - break; - case PS_STATE_S2:/* only for USB normal powersave mode use, - * temp mark some code. - */ - case PS_STATE_S3: - case PS_STATE_S4: - pwrpriv->cpwm = val8; - break; - default: - break; - } - pwrpriv->rpwm_retry = 0; - pwrpriv->rpwm = val8; - r8712_write8(padapter, 0x1025FE58, rpwm); - pwrpriv->tog += 0x80; -} - -void r8712_set_ps_mode(struct _adapter *padapter, uint ps_mode, uint smart_ps) -{ - struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; - - if (ps_mode > PM_Card_Disable) - return; - /* if driver is in active state, we dont need set smart_ps.*/ - if (ps_mode == PS_MODE_ACTIVE) - smart_ps = 0; - if ((pwrpriv->pwr_mode != ps_mode) || (pwrpriv->smart_ps != smart_ps)) { - if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) - pwrpriv->bSleep = true; - else - pwrpriv->bSleep = false; - pwrpriv->pwr_mode = ps_mode; - pwrpriv->smart_ps = smart_ps; - schedule_work(&pwrpriv->SetPSModeWorkItem); - } -} - -/* - * Caller:ISR handler... - * - * This will be called when CPWM interrupt is up. - * - * using to update cpwn of drv; and drv will make a decision to up or - * down pwr level - */ -void r8712_cpwm_int_hdl(struct _adapter *padapter, - struct reportpwrstate_parm *preportpwrstate) -{ - struct pwrctrl_priv *pwrpriv = &(padapter->pwrctrlpriv); - struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); - - if (pwrpriv->cpwm_tog == ((preportpwrstate->state) & 0x80)) - return; - del_timer(&padapter->pwrctrlpriv.rpwm_check_timer); - mutex_lock(&pwrpriv->mutex_lock); - pwrpriv->cpwm = (preportpwrstate->state) & 0xf; - if (pwrpriv->cpwm >= PS_STATE_S2) { - if (pwrpriv->alives & CMD_ALIVE) - complete(&(pcmdpriv->cmd_queue_comp)); - } - pwrpriv->cpwm_tog = (preportpwrstate->state) & 0x80; - mutex_unlock(&pwrpriv->mutex_lock); -} - -static inline void register_task_alive(struct pwrctrl_priv *pwrctrl, uint tag) -{ - pwrctrl->alives |= tag; -} - -static inline void unregister_task_alive(struct pwrctrl_priv *pwrctrl, uint tag) -{ - if (pwrctrl->alives & tag) - pwrctrl->alives ^= tag; -} - -static void _rpwm_check_handler (struct _adapter *padapter) -{ - struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; - - if (padapter->driver_stopped || padapter->surprise_removed) - return; - if (pwrpriv->cpwm != pwrpriv->rpwm) - schedule_work(&pwrpriv->rpwm_workitem); -} - -static void SetPSModeWorkItemCallback(struct work_struct *work) -{ - struct pwrctrl_priv *pwrpriv = container_of(work, - struct pwrctrl_priv, SetPSModeWorkItem); - struct _adapter *padapter = container_of(pwrpriv, - struct _adapter, pwrctrlpriv); - if (!pwrpriv->bSleep) { - mutex_lock(&pwrpriv->mutex_lock); - if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) - r8712_set_rpwm(padapter, PS_STATE_S4); - mutex_unlock(&pwrpriv->mutex_lock); - } -} - -static void rpwm_workitem_callback(struct work_struct *work) -{ - struct pwrctrl_priv *pwrpriv = container_of(work, - struct pwrctrl_priv, rpwm_workitem); - struct _adapter *padapter = container_of(pwrpriv, - struct _adapter, pwrctrlpriv); - if (pwrpriv->cpwm != pwrpriv->rpwm) { - mutex_lock(&pwrpriv->mutex_lock); - r8712_read8(padapter, SDIO_HCPWM); - pwrpriv->rpwm_retry = 1; - r8712_set_rpwm(padapter, pwrpriv->rpwm); - mutex_unlock(&pwrpriv->mutex_lock); - } -} - -static void rpwm_check_handler (struct timer_list *t) -{ - struct _adapter *adapter = - from_timer(adapter, t, pwrctrlpriv.rpwm_check_timer); - - _rpwm_check_handler(adapter); -} - -void r8712_init_pwrctrl_priv(struct _adapter *padapter) -{ - struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; - - memset((unsigned char *)pwrctrlpriv, 0, sizeof(struct pwrctrl_priv)); - mutex_init(&pwrctrlpriv->mutex_lock); - pwrctrlpriv->cpwm = PS_STATE_S4; - pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; - pwrctrlpriv->smart_ps = 0; - pwrctrlpriv->tog = 0x80; -/* clear RPWM to ensure driver and fw back to initial state. */ - r8712_write8(padapter, 0x1025FE58, 0); - INIT_WORK(&pwrctrlpriv->SetPSModeWorkItem, SetPSModeWorkItemCallback); - INIT_WORK(&pwrctrlpriv->rpwm_workitem, rpwm_workitem_callback); - timer_setup(&pwrctrlpriv->rpwm_check_timer, rpwm_check_handler, 0); -} - -/* - * Caller: r8712_cmd_thread - * Check if the fw_pwrstate is okay for issuing cmd. - * If not (cpwm should be is less than P2 state), then the sub-routine - * will raise the cpwm to be greater than or equal to P2. - * Calling Context: Passive - * Return Value: - * 0: r8712_cmd_thread can issue cmds to firmware afterwards. - * -EINVAL: r8712_cmd_thread can not do anything. - */ -int r8712_register_cmd_alive(struct _adapter *padapter) -{ - int res = 0; - struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv; - - mutex_lock(&pwrctrl->mutex_lock); - register_task_alive(pwrctrl, CMD_ALIVE); - if (pwrctrl->cpwm < PS_STATE_S2) { - r8712_set_rpwm(padapter, PS_STATE_S3); - res = -EINVAL; - } - mutex_unlock(&pwrctrl->mutex_lock); - return res; -} - -/* - * Caller: ISR - * If ISR's txdone, - * No more pkts for TX, - * Then driver shall call this fun. to power down firmware again. - */ -void r8712_unregister_cmd_alive(struct _adapter *padapter) -{ - struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv; - - mutex_lock(&pwrctrl->mutex_lock); - unregister_task_alive(pwrctrl, CMD_ALIVE); - if ((pwrctrl->cpwm > PS_STATE_S2) && - (pwrctrl->pwr_mode > PS_MODE_ACTIVE)) { - if ((pwrctrl->alives == 0) && - (check_fwstate(&padapter->mlmepriv, - _FW_UNDER_LINKING) != true)) { - r8712_set_rpwm(padapter, PS_STATE_S0); - } - } - mutex_unlock(&pwrctrl->mutex_lock); -} - -void r8712_flush_rwctrl_works(struct _adapter *padapter) -{ - struct pwrctrl_priv *pwrctrl = &padapter->pwrctrlpriv; - - flush_work(&pwrctrl->SetPSModeWorkItem); - flush_work(&pwrctrl->rpwm_workitem); -} diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h deleted file mode 100644 index b35b9c7920ebbf..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h +++ /dev/null @@ -1,113 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL871X_PWRCTRL_H_ -#define __RTL871X_PWRCTRL_H_ - -#include "osdep_service.h" -#include "drv_types.h" - -#define CMD_ALIVE BIT(2) - -enum Power_Mgnt { - PS_MODE_ACTIVE = 0, - PS_MODE_MIN, - PS_MODE_MAX, - PS_MODE_DTIM, - PS_MODE_VOIP, - PS_MODE_UAPSD_WMM, - PS_MODE_UAPSD, - PS_MODE_IBSS, - PS_MODE_WWLAN, - PM_Radio_Off, - PM_Card_Disable, - PS_MODE_NUM -}; - -/* - * BIT[2:0] = HW state - * BIT[3] = Protocol PS state, 0: register active state, - * 1: register sleep state - * BIT[4] = sub-state - */ - -#define PS_DPS BIT(0) -#define PS_LCLK (PS_DPS) -#define PS_RF_OFF BIT(1) -#define PS_ALL_ON BIT(2) -#define PS_ST_ACTIVE BIT(3) -#define PS_LP BIT(4) /* low performance */ - -#define PS_STATE_MASK (0x0F) -#define PS_STATE_HW_MASK (0x07) -#define PS_SEQ_MASK (0xc0) - -#define PS_STATE(x) (PS_STATE_MASK & (x)) -#define PS_STATE_HW(x) (PS_STATE_HW_MASK & (x)) -#define PS_SEQ(x) (PS_SEQ_MASK & (x)) - -#define PS_STATE_S0 (PS_DPS) -#define PS_STATE_S1 (PS_LCLK) -#define PS_STATE_S2 (PS_RF_OFF) -#define PS_STATE_S3 (PS_ALL_ON) -#define PS_STATE_S4 ((PS_ST_ACTIVE) | (PS_ALL_ON)) - -#define PS_IS_RF_ON(x) ((x) & (PS_ALL_ON)) -#define PS_IS_ACTIVE(x) ((x) & (PS_ST_ACTIVE)) -#define CLR_PS_STATE(x) ((x) = ((x) & (0xF0))) - -struct reportpwrstate_parm { - unsigned char mode; - unsigned char state; /* the CPWM value */ - unsigned short rsvd; -}; - -struct pwrctrl_priv { - struct mutex mutex_lock; - /*volatile*/ u8 rpwm; /* requested power state for fw */ - /* fw current power state. updated when 1. read from HCPWM or - * 2. driver lowers power level - */ - /*volatile*/ u8 cpwm; - /*volatile*/ u8 tog; /* toggling */ - /*volatile*/ u8 cpwm_tog; /* toggling */ - /*volatile*/ u8 tgt_rpwm; /* wanted power state */ - uint pwr_mode; - uint smart_ps; - uint alives; - uint ImrContent; /* used to store original imr. */ - uint bSleep; /* sleep -> active is different from active -> sleep. */ - - struct work_struct SetPSModeWorkItem; - struct work_struct rpwm_workitem; - struct timer_list rpwm_check_timer; - u8 rpwm_retry; - uint bSetPSModeWorkItemInProgress; - - spinlock_t pnp_pwr_mgnt_lock; - s32 pnp_current_pwr_state; - u8 pnp_bstop_trx; - u8 pnp_wwirp_pending; -}; - -void r8712_init_pwrctrl_priv(struct _adapter *adapter); -int r8712_register_cmd_alive(struct _adapter *padapter); -void r8712_unregister_cmd_alive(struct _adapter *padapter); -void r8712_cpwm_int_hdl(struct _adapter *padapter, - struct reportpwrstate_parm *preportpwrstate); -void r8712_set_ps_mode(struct _adapter *padapter, uint ps_mode, - uint smart_ps); -void r8712_set_rpwm(struct _adapter *padapter, u8 val8); -void r8712_flush_rwctrl_works(struct _adapter *padapter); - -#endif /* __RTL871X_PWRCTRL_H_ */ diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c deleted file mode 100644 index 8a3566214af726..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_recv.c +++ /dev/null @@ -1,671 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_recv.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_RECV_C_ - -#include -#include -#include -#include -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "recv_osdep.h" -#include "mlme_osdep.h" -#include "ethernet.h" -#include "usb_ops.h" -#include "wifi.h" - -static const u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37}; - -/* Datagram Delivery Protocol */ -static const u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3}; - -void _r8712_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) -{ - memset((u8 *)psta_recvpriv, 0, sizeof(struct sta_recv_priv)); - spin_lock_init(&psta_recvpriv->lock); - _init_queue(&psta_recvpriv->defrag_q); -} - -int _r8712_init_recv_priv(struct recv_priv *precvpriv, - struct _adapter *padapter) -{ - int ret; - sint i; - union recv_frame *precvframe; - - memset((unsigned char *)precvpriv, 0, sizeof(struct recv_priv)); - spin_lock_init(&precvpriv->lock); - _init_queue(&precvpriv->free_recv_queue); - _init_queue(&precvpriv->recv_pending_queue); - precvpriv->adapter = padapter; - precvpriv->free_recvframe_cnt = NR_RECVFRAME; - precvpriv->pallocated_frame_buf = kzalloc(NR_RECVFRAME * - sizeof(union recv_frame) + RXFRAME_ALIGN_SZ, - GFP_ATOMIC); - if (!precvpriv->pallocated_frame_buf) - return -ENOMEM; - precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf + - RXFRAME_ALIGN_SZ - - ((addr_t)(precvpriv->pallocated_frame_buf) & - (RXFRAME_ALIGN_SZ - 1)); - precvframe = (union recv_frame *)precvpriv->precv_frame_buf; - for (i = 0; i < NR_RECVFRAME; i++) { - INIT_LIST_HEAD(&(precvframe->u.list)); - list_add_tail(&(precvframe->u.list), - &(precvpriv->free_recv_queue.queue)); - r8712_os_recv_resource_alloc(padapter, precvframe); - precvframe->u.hdr.adapter = padapter; - precvframe++; - } - precvpriv->rx_pending_cnt = 1; - ret = r8712_init_recv_priv(precvpriv, padapter); - if (ret) - kfree(precvpriv->pallocated_frame_buf); - - return ret; -} - -void _r8712_free_recv_priv(struct recv_priv *precvpriv) -{ - kfree(precvpriv->pallocated_frame_buf); - r8712_free_recv_priv(precvpriv); -} - -union recv_frame *r8712_alloc_recvframe(struct __queue *pfree_recv_queue) -{ - unsigned long irqL; - union recv_frame *precvframe; - struct _adapter *padapter; - struct recv_priv *precvpriv; - - spin_lock_irqsave(&pfree_recv_queue->lock, irqL); - precvframe = list_first_entry_or_null(&pfree_recv_queue->queue, - union recv_frame, u.hdr.list); - if (precvframe) { - list_del_init(&precvframe->u.hdr.list); - padapter = precvframe->u.hdr.adapter; - if (padapter) { - precvpriv = &padapter->recvpriv; - if (pfree_recv_queue == &precvpriv->free_recv_queue) - precvpriv->free_recvframe_cnt--; - } - } - spin_unlock_irqrestore(&pfree_recv_queue->lock, irqL); - return precvframe; -} - -/* - * caller : defrag; recvframe_chk_defrag in recv_thread (passive) - * pframequeue: defrag_queue : will be accessed in recv_thread (passive) - * using spin_lock to protect - */ -void r8712_free_recvframe_queue(struct __queue *pframequeue, - struct __queue *pfree_recv_queue) -{ - union recv_frame *precvframe; - struct list_head *plist, *phead; - - spin_lock(&pframequeue->lock); - phead = &pframequeue->queue; - plist = phead->next; - while (!end_of_queue_search(phead, plist)) { - precvframe = container_of(plist, union recv_frame, u.list); - plist = plist->next; - r8712_free_recvframe(precvframe, pfree_recv_queue); - } - spin_unlock(&pframequeue->lock); -} - -sint r8712_recvframe_chkmic(struct _adapter *adapter, - union recv_frame *precvframe) -{ - sint i, res = _SUCCESS; - u32 datalen; - u8 miccode[8]; - u8 bmic_err = false; - u8 *pframe, *payload, *pframemic; - u8 *mickey, idx, *iv; - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib; - struct security_priv *psecuritypriv = &adapter->securitypriv; - - stainfo = r8712_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]); - if (prxattrib->encrypt == _TKIP_) { - /* calculate mic code */ - if (stainfo) { - if (is_multicast_ether_addr(prxattrib->ra)) { - iv = precvframe->u.hdr.rx_data + - prxattrib->hdrlen; - idx = iv[3]; - mickey = &psecuritypriv->XGrprxmickey[(((idx >> - 6) & 0x3)) - 1].skey[0]; - if (!psecuritypriv->binstallGrpkey) - return _FAIL; - } else { - mickey = &stainfo->tkiprxmickey.skey[0]; - } - /*icv_len included the mic code*/ - datalen = precvframe->u.hdr.len - prxattrib->hdrlen - - prxattrib->iv_len - prxattrib->icv_len - 8; - pframe = precvframe->u.hdr.rx_data; - payload = pframe + prxattrib->hdrlen + - prxattrib->iv_len; - seccalctkipmic(mickey, pframe, payload, datalen, - &miccode[0], - (unsigned char)prxattrib->priority); - pframemic = payload + datalen; - bmic_err = false; - for (i = 0; i < 8; i++) { - if (miccode[i] != *(pframemic + i)) - bmic_err = true; - } - if (bmic_err) { - if (prxattrib->bdecrypted) - r8712_handle_tkip_mic_err(adapter, - (u8)is_multicast_ether_addr(prxattrib->ra)); - res = _FAIL; - } else { - /* mic checked ok */ - if (!psecuritypriv->bcheck_grpkey && - is_multicast_ether_addr(prxattrib->ra)) - psecuritypriv->bcheck_grpkey = true; - } - recvframe_pull_tail(precvframe, 8); - } - } - return res; -} - -/* decrypt and set the ivlen,icvlen of the recv_frame */ -union recv_frame *r8712_decryptor(struct _adapter *padapter, - union recv_frame *precv_frame) -{ - struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - union recv_frame *return_packet = precv_frame; - - if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || - psecuritypriv->sw_decrypt)) { - psecuritypriv->hw_decrypted = false; - switch (prxattrib->encrypt) { - case _WEP40_: - case _WEP104_: - r8712_wep_decrypt(padapter, (u8 *)precv_frame); - break; - case _TKIP_: - r8712_tkip_decrypt(padapter, (u8 *)precv_frame); - break; - case _AES_: - r8712_aes_decrypt(padapter, (u8 *)precv_frame); - break; - default: - break; - } - } else if (prxattrib->bdecrypted == 1) { - psecuritypriv->hw_decrypted = true; - } - return return_packet; -} - -/*###set the security information in the recv_frame */ -union recv_frame *r8712_portctrl(struct _adapter *adapter, - union recv_frame *precv_frame) -{ - u8 *psta_addr, *ptr; - uint auth_alg; - struct recv_frame_hdr *pfhdr; - struct sta_info *psta; - struct sta_priv *pstapriv; - union recv_frame *prtnframe; - u16 ether_type; - - pstapriv = &adapter->stapriv; - ptr = precv_frame->u.hdr.rx_data; - pfhdr = &precv_frame->u.hdr; - psta_addr = pfhdr->attrib.ta; - psta = r8712_get_stainfo(pstapriv, psta_addr); - auth_alg = adapter->securitypriv.AuthAlgrthm; - if (auth_alg == 2) { - /* get ether_type */ - ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE; - ether_type = get_unaligned_be16(ptr); - - if (psta && psta->ieee8021x_blocked) { - /* blocked - * only accept EAPOL frame - */ - if (ether_type == 0x888e) { - prtnframe = precv_frame; - } else { - /*free this frame*/ - r8712_free_recvframe(precv_frame, - &adapter->recvpriv.free_recv_queue); - prtnframe = NULL; - } - } else { - /* allowed - * check decryption status, and decrypt the - * frame if needed - */ - prtnframe = precv_frame; - /* check is the EAPOL frame or not (Rekey) */ - if (ether_type == 0x888e) { - /* check Rekey */ - prtnframe = precv_frame; - } - } - } else { - prtnframe = precv_frame; - } - return prtnframe; -} - -static sint recv_decache(union recv_frame *precv_frame, u8 bretry, - struct stainfo_rxcache *prxcache) -{ - sint tid = precv_frame->u.hdr.attrib.priority; - u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num & 0xffff) << 4) | - (precv_frame->u.hdr.attrib.frag_num & 0xf); - - if (tid > 15) - return _FAIL; - if (seq_ctrl == prxcache->tid_rxseq[tid]) - return _FAIL; - prxcache->tid_rxseq[tid] = seq_ctrl; - return _SUCCESS; -} - -static sint sta2sta_data_frame(struct _adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta) -{ - u8 *ptr = precv_frame->u.hdr.rx_data; - sint ret = _SUCCESS; - struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - u8 *mybssid = get_bssid(pmlmepriv); - u8 *myhwaddr = myid(&adapter->eeprompriv); - u8 *sta_addr = NULL; - bool bmcast = is_multicast_ether_addr(pattrib->dst); - - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || - check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { - /* filter packets that SA is myself or multicast or broadcast */ - if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) - return _FAIL; - if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) - return _FAIL; - if (is_zero_ether_addr(pattrib->bssid) || - is_zero_ether_addr(mybssid) || - (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) - return _FAIL; - sta_addr = pattrib->src; - } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - /* For Station mode, sa and bssid should always be BSSID, - * and DA is my mac-address - */ - if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) - return _FAIL; - sta_addr = pattrib->bssid; - } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - if (bmcast) { - /* For AP mode, if DA == MCAST, then BSSID should - * be also MCAST - */ - if (!is_multicast_ether_addr(pattrib->bssid)) - return _FAIL; - } else { /* not mc-frame */ - /* For AP mode, if DA is non-MCAST, then it must be - * BSSID, and bssid == BSSID - */ - if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) - return _FAIL; - sta_addr = pattrib->src; - } - } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { - memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); - memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); - memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - sta_addr = mybssid; - } else { - ret = _FAIL; - } - if (bmcast) - *psta = r8712_get_bcmc_stainfo(adapter); - else - *psta = r8712_get_stainfo(pstapriv, sta_addr); /* get ap_info */ - if (!*psta) { - if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) - adapter->mppriv.rx_pktloss++; - return _FAIL; - } - return ret; -} - -static sint ap2sta_data_frame(struct _adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta) -{ - u8 *ptr = precv_frame->u.hdr.rx_data; - struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - u8 *mybssid = get_bssid(pmlmepriv); - u8 *myhwaddr = myid(&adapter->eeprompriv); - bool bmcast = is_multicast_ether_addr(pattrib->dst); - - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && - check_fwstate(pmlmepriv, _FW_LINKED)) { - /* if NULL-frame, drop packet */ - if ((GetFrameSubType(ptr)) == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC)) - return _FAIL; - /* drop QoS-SubType Data, including QoS NULL, - * excluding QoS-Data - */ - if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == - WIFI_QOS_DATA_TYPE) { - if (GetFrameSubType(ptr) & (BIT(4) | BIT(5) | BIT(6))) - return _FAIL; - } - - /* filter packets that SA is myself or multicast or broadcast */ - if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) - return _FAIL; - - /* da should be for me */ - if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) - return _FAIL; - /* check BSSID */ - if (is_zero_ether_addr(pattrib->bssid) || - is_zero_ether_addr(mybssid) || - (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) - return _FAIL; - if (bmcast) - *psta = r8712_get_bcmc_stainfo(adapter); - else - *psta = r8712_get_stainfo(pstapriv, pattrib->bssid); - if (!*psta) - return _FAIL; - } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && - check_fwstate(pmlmepriv, _FW_LINKED)) { - memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); - memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); - memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - memcpy(pattrib->bssid, mybssid, ETH_ALEN); - *psta = r8712_get_stainfo(pstapriv, pattrib->bssid); - if (!*psta) - return _FAIL; - } else { - return _FAIL; - } - return _SUCCESS; -} - -static sint sta2ap_data_frame(struct _adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta) -{ - struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - unsigned char *mybssid = get_bssid(pmlmepriv); - - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - /* For AP mode, if DA is non-MCAST, then it must be BSSID, - * and bssid == BSSID - * For AP mode, RA=BSSID, TX=STA(SRC_ADDR), A3=DST_ADDR - */ - if (memcmp(pattrib->bssid, mybssid, ETH_ALEN)) - return _FAIL; - *psta = r8712_get_stainfo(pstapriv, pattrib->src); - if (!*psta) - return _FAIL; - } - return _SUCCESS; -} - -static sint validate_recv_ctrl_frame(struct _adapter *adapter, - union recv_frame *precv_frame) -{ - return _FAIL; -} - -static sint validate_recv_mgnt_frame(struct _adapter *adapter, - union recv_frame *precv_frame) -{ - return _FAIL; -} - -static sint validate_recv_data_frame(struct _adapter *adapter, - union recv_frame *precv_frame) -{ - int res; - u8 bretry; - u8 *psa, *pda, *pbssid; - struct sta_info *psta = NULL; - u8 *ptr = precv_frame->u.hdr.rx_data; - struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - struct security_priv *psecuritypriv = &adapter->securitypriv; - - bretry = GetRetry(ptr); - pda = ieee80211_get_DA((struct ieee80211_hdr *)ptr); - psa = ieee80211_get_SA((struct ieee80211_hdr *)ptr); - pbssid = get_hdr_bssid(ptr); - if (!pbssid) - return _FAIL; - memcpy(pattrib->dst, pda, ETH_ALEN); - memcpy(pattrib->src, psa, ETH_ALEN); - memcpy(pattrib->bssid, pbssid, ETH_ALEN); - switch (pattrib->to_fr_ds) { - case 0: - memcpy(pattrib->ra, pda, ETH_ALEN); - memcpy(pattrib->ta, psa, ETH_ALEN); - res = sta2sta_data_frame(adapter, precv_frame, &psta); - break; - case 1: - memcpy(pattrib->ra, pda, ETH_ALEN); - memcpy(pattrib->ta, pbssid, ETH_ALEN); - res = ap2sta_data_frame(adapter, precv_frame, &psta); - break; - case 2: - memcpy(pattrib->ra, pbssid, ETH_ALEN); - memcpy(pattrib->ta, psa, ETH_ALEN); - res = sta2ap_data_frame(adapter, precv_frame, &psta); - break; - case 3: - memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); - memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); - return _FAIL; - default: - return _FAIL; - } - if (res == _FAIL) - return _FAIL; - if (!psta) - return _FAIL; - precv_frame->u.hdr.psta = psta; - pattrib->amsdu = 0; - /* parsing QC field */ - if (pattrib->qos == 1) { - pattrib->priority = GetPriority((ptr + 24)); - pattrib->ack_policy = GetAckpolicy((ptr + 24)); - pattrib->amsdu = GetAMsdu((ptr + 24)); - pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26; - } else { - pattrib->priority = 0; - pattrib->hdrlen = (pattrib->to_fr_ds == 3) ? 30 : 24; - } - - if (pattrib->order)/*HT-CTRL 11n*/ - pattrib->hdrlen += 4; - precv_frame->u.hdr.preorder_ctrl = - &psta->recvreorder_ctrl[pattrib->priority]; - - /* decache, drop duplicate recv packets */ - if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == - _FAIL) - return _FAIL; - - if (pattrib->privacy) { - GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, - is_multicast_ether_addr(pattrib->ra)); - SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, - pattrib->encrypt); - } else { - pattrib->encrypt = 0; - pattrib->iv_len = pattrib->icv_len = 0; - } - return _SUCCESS; -} - -sint r8712_validate_recv_frame(struct _adapter *adapter, - union recv_frame *precv_frame) -{ - /*shall check frame subtype, to / from ds, da, bssid */ - /*then call check if rx seq/frag. duplicated.*/ - - u8 type; - u8 subtype; - sint retval = _SUCCESS; - struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - - u8 *ptr = precv_frame->u.hdr.rx_data; - u8 ver = (unsigned char)(*ptr) & 0x3; - - /*add version chk*/ - if (ver != 0) - return _FAIL; - type = GetFrameType(ptr); - subtype = GetFrameSubType(ptr); /*bit(7)~bit(2)*/ - pattrib->to_fr_ds = get_tofr_ds(ptr); - pattrib->frag_num = GetFragNum(ptr); - pattrib->seq_num = GetSequence(ptr); - pattrib->pw_save = GetPwrMgt(ptr); - pattrib->mfrag = GetMFrag(ptr); - pattrib->mdata = GetMData(ptr); - pattrib->privacy = GetPrivacy(ptr); - pattrib->order = GetOrder(ptr); - switch (type) { - case IEEE80211_FTYPE_MGMT: - retval = validate_recv_mgnt_frame(adapter, precv_frame); - break; - case IEEE80211_FTYPE_CTL: - retval = validate_recv_ctrl_frame(adapter, precv_frame); - break; - case IEEE80211_FTYPE_DATA: - pattrib->qos = (subtype & BIT(7)) ? 1 : 0; - retval = validate_recv_data_frame(adapter, precv_frame); - break; - default: - return _FAIL; - } - return retval; -} - -int r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe) -{ - /*remove the wlanhdr and add the eth_hdr*/ - sint rmv_len; - u16 len; - u8 bsnaphdr; - u8 *psnap_type; - struct ieee80211_snap_hdr *psnap; - struct _adapter *adapter = precvframe->u.hdr.adapter; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - - u8 *ptr = precvframe->u.hdr.rx_data; /*point to frame_ctrl field*/ - struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; - - if (pattrib->encrypt) - recvframe_pull_tail(precvframe, pattrib->icv_len); - psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + - pattrib->iv_len); - psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; - /* convert hdr + possible LLC headers into Ethernet header */ - if ((!memcmp(psnap, (void *)rfc1042_header, SNAP_SIZE) && - (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_IPX, 2)) && - (memcmp(psnap_type, (void *)SNAP_ETH_TYPE_APPLETALK_AARP, 2))) || - !memcmp(psnap, (void *)bridge_tunnel_header, SNAP_SIZE)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType - */ - bsnaphdr = true; - } else { - /* Leave Ethernet header part of hdr and full payload */ - bsnaphdr = false; - } - rmv_len = pattrib->hdrlen + pattrib->iv_len + - (bsnaphdr ? SNAP_SIZE : 0); - len = precvframe->u.hdr.len - rmv_len; - if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { - ptr += rmv_len; - *ptr = 0x87; - *(ptr + 1) = 0x12; - /* append rx status for mp test packets */ - ptr = recvframe_pull(precvframe, (rmv_len - - sizeof(struct ethhdr) + 2) - 24); - if (!ptr) - return -ENOMEM; - memcpy(ptr, get_rxmem(precvframe), 24); - ptr += 24; - } else { - ptr = recvframe_pull(precvframe, (rmv_len - - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); - if (!ptr) - return -ENOMEM; - } - - memcpy(ptr, pattrib->dst, ETH_ALEN); - memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN); - if (!bsnaphdr) { - __be16 be_tmp = htons(len); - - memcpy(ptr + 12, &be_tmp, 2); - } - return 0; -} - -void r8712_recv_entry(union recv_frame *precvframe) -{ - struct _adapter *padapter; - struct recv_priv *precvpriv; - - s32 ret = _SUCCESS; - - padapter = precvframe->u.hdr.adapter; - precvpriv = &(padapter->recvpriv); - - padapter->ledpriv.LedControlHandler(padapter, LED_CTL_RX); - - ret = recv_func(padapter, precvframe); - if (ret == _FAIL) - goto _recv_entry_drop; - precvpriv->rx_pkts++; - precvpriv->rx_bytes += (uint)(precvframe->u.hdr.rx_tail - - precvframe->u.hdr.rx_data); - return; -_recv_entry_drop: - precvpriv->rx_drop++; - padapter->mppriv.rx_pktloss = precvpriv->rx_drop; -} diff --git a/drivers/staging/rtl8712/rtl871x_recv.h b/drivers/staging/rtl8712/rtl871x_recv.h deleted file mode 100644 index 0760bccbf389c1..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_recv.h +++ /dev/null @@ -1,208 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _RTL871X_RECV_H_ -#define _RTL871X_RECV_H_ - -#include "osdep_service.h" -#include "drv_types.h" - -#define NR_RECVFRAME 256 - -#define RXFRAME_ALIGN 8 -#define RXFRAME_ALIGN_SZ (1 << RXFRAME_ALIGN) - -#define MAX_SUBFRAME_COUNT 64 - -/* for Rx reordering buffer control */ -struct recv_reorder_ctrl { - struct _adapter *padapter; - u16 indicate_seq; /* =wstart_b, init_value=0xffff */ - u16 wend_b; - u8 wsize_b; - struct __queue pending_recvframe_queue; - struct timer_list reordering_ctrl_timer; -}; - -struct stainfo_rxcache { - u16 tid_rxseq[16]; -}; - -#define PHY_RSSI_SLID_WIN_MAX 100 -#define PHY_LINKQUALITY_SLID_WIN_MAX 20 - -struct smooth_rssi_data { - u32 elements[100]; /* array to store values */ - u32 index; /* index to current array to store */ - u32 total_num; /* num of valid elements */ - u32 total_val; /* sum of valid elements */ -}; - -struct rx_pkt_attrib { - u8 amsdu; - u8 order; - u8 qos; - u8 to_fr_ds; - u8 frag_num; - u16 seq_num; - u8 pw_save; - u8 mfrag; - u8 mdata; - u8 privacy; /* in frame_ctrl field */ - u8 bdecrypted; - int hdrlen; /* the WLAN Header Len */ - int encrypt; /* 0 no encrypt. != 0 encrypt algorithm */ - int iv_len; - int icv_len; - int priority; - int ack_policy; - u8 crc_err; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - u8 ta[ETH_ALEN]; - u8 ra[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - u8 tcpchk_valid; /* 0: invalid, 1: valid */ - u8 ip_chkrpt; /* 0: incorrect, 1: correct */ - u8 tcp_chkrpt; /* 0: incorrect, 1: correct */ - u8 signal_qual; - s8 rx_mimo_signal_qual[2]; - u8 mcs_rate; - u8 htc; - u8 signal_strength; -}; - -/* - * accesser of recv_priv: recv_entry(dispatch / passive level); - * recv_thread(passive) ; returnpkt(dispatch) - * ; halt(passive) ; - * - * using enter_critical section to protect - */ -struct recv_priv { - spinlock_t lock; - struct __queue free_recv_queue; - struct __queue recv_pending_queue; - u8 *pallocated_frame_buf; - u8 *precv_frame_buf; - uint free_recvframe_cnt; - struct _adapter *adapter; - uint rx_bytes; - uint rx_pkts; - uint rx_drop; - uint rx_icv_err; - uint rx_largepacket_crcerr; - uint rx_smallpacket_crcerr; - uint rx_middlepacket_crcerr; - u8 rx_pending_cnt; - uint ff_hwaddr; - struct tasklet_struct recv_tasklet; - struct sk_buff_head free_recv_skb_queue; - struct sk_buff_head rx_skb_queue; - u8 *pallocated_recv_buf; - u8 *precv_buf; /* 4 alignment */ - struct __queue free_recv_buf_queue; - u32 free_recv_buf_queue_cnt; - /* For the phy information */ - s8 rssi; - u8 signal; - u8 noise; - u8 fw_rssi; - struct smooth_rssi_data signal_qual_data; - struct smooth_rssi_data signal_strength_data; -}; - -struct sta_recv_priv { - spinlock_t lock; - sint option; - struct __queue defrag_q; /* keeping the fragment frame until defrag */ - struct stainfo_rxcache rxcache; - uint sta_rx_bytes; - uint sta_rx_pkts; - uint sta_rx_fail; -}; - -#include "rtl8712_recv.h" - -/* get a free recv_frame from pfree_recv_queue */ -union recv_frame *r8712_alloc_recvframe(struct __queue *pfree_recv_queue); -void r8712_free_recvframe(union recv_frame *precvframe, - struct __queue *pfree_recv_queue); -void r8712_free_recvframe_queue(struct __queue *pframequeue, - struct __queue *pfree_recv_queue); -int r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe); -int recv_func(struct _adapter *padapter, void *pcontext); - -static inline u8 *get_rxmem(union recv_frame *precvframe) -{ - /* always return rx_head... */ - if (!precvframe) - return NULL; - return precvframe->u.hdr.rx_head; -} - -static inline u8 *recvframe_pull(union recv_frame *precvframe, sint sz) -{ - /* used for extract sz bytes from rx_data, update rx_data and return - * the updated rx_data to the caller - */ - if (!precvframe) - return NULL; - precvframe->u.hdr.rx_data += sz; - if (precvframe->u.hdr.rx_data > precvframe->u.hdr.rx_tail) { - precvframe->u.hdr.rx_data -= sz; - return NULL; - } - precvframe->u.hdr.len -= sz; - return precvframe->u.hdr.rx_data; -} - -static inline u8 *recvframe_put(union recv_frame *precvframe, sint sz) -{ - /* used for append sz bytes from ptr to rx_tail, update rx_tail and - * return the updated rx_tail to the caller - * after putting, rx_tail must be still larger than rx_end. - */ - if (!precvframe) - return NULL; - precvframe->u.hdr.rx_tail += sz; - if (precvframe->u.hdr.rx_tail > precvframe->u.hdr.rx_end) { - precvframe->u.hdr.rx_tail -= sz; - return NULL; - } - precvframe->u.hdr.len += sz; - return precvframe->u.hdr.rx_tail; -} - -static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz) -{ - /* rmv data from rx_tail (by yitsen) - * used for extract sz bytes from rx_end, update rx_end and return the - * updated rx_end to the caller - * after pulling, rx_end must be still larger than rx_data. - */ - if (!precvframe) - return NULL; - precvframe->u.hdr.rx_tail -= sz; - if (precvframe->u.hdr.rx_tail < precvframe->u.hdr.rx_data) { - precvframe->u.hdr.rx_tail += sz; - return NULL; - } - precvframe->u.hdr.len -= sz; - return precvframe->u.hdr.rx_tail; -} - -struct sta_info; - -void _r8712_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv); -sint r8712_recvframe_chkmic(struct _adapter *adapter, - union recv_frame *precvframe); -union recv_frame *r8712_decryptor(struct _adapter *adapter, - union recv_frame *precv_frame); -union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *adapter, - union recv_frame *precv_frame); -int r8712_validate_recv_frame(struct _adapter *adapter, - union recv_frame *precv_frame); -union recv_frame *r8712_portctrl(struct _adapter *adapter, - union recv_frame *precv_frame); - -#endif - diff --git a/drivers/staging/rtl8712/rtl871x_rf.h b/drivers/staging/rtl8712/rtl871x_rf.h deleted file mode 100644 index 7d98921a48fac0..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_rf.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL871X_RF_H_ -#define __RTL871X_RF_H_ - -#include "rtl871x_cmd.h" -#include "rtl871x_mp_phy_regdef.h" - -#define OFDM_PHY 1 -#define MIXED_PHY 2 -#define CCK_PHY 3 -#define NumRates (13) -#define RTL8711_RF_MAX_SENS 6 -#define RTL8711_RF_DEF_SENS 4 -#define NUM_CHANNELS 15 - -struct regulatory_class { - u32 starting_freq; /*MHz, */ - u8 channel_set[NUM_CHANNELS]; - u8 channel_cck_power[NUM_CHANNELS]; /*dbm*/ - u8 channel_ofdm_power[NUM_CHANNELS];/*dbm*/ - u8 txpower_limit; /*dbm*/ - u8 channel_spacing; /*MHz*/ - u8 modem; -}; - -enum _REG_PREAMBLE_MODE { - PREAMBLE_LONG = 1, - PREAMBLE_AUTO = 2, - PREAMBLE_SHORT = 3, -}; - -enum { - RTL8712_RFC_1T = 0x10, - RTL8712_RFC_2T = 0x20, - RTL8712_RFC_1R = 0x01, - RTL8712_RFC_2R = 0x02, - RTL8712_RFC_1T1R = 0x11, - RTL8712_RFC_1T2R = 0x12, - RTL8712_RFC_TURBO = 0x92, - RTL8712_RFC_2T2R = 0x22 -}; - -#endif /*__RTL871X_RF_H_*/ diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c deleted file mode 100644 index e46a5dbc7b65fa..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_security.c +++ /dev/null @@ -1,1386 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_security.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_SECURITY_C_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "osdep_intf.h" - -/* =====WEP related===== */ - -struct arc4context { - u32 x; - u32 y; - u8 state[256]; -}; - -static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len) -{ - u32 t, u; - u32 keyindex; - u32 stateindex; - u8 *state; - u32 counter; - - state = parc4ctx->state; - parc4ctx->x = 0; - parc4ctx->y = 0; - for (counter = 0; counter < 256; counter++) - state[counter] = (u8)counter; - keyindex = 0; - stateindex = 0; - for (counter = 0; counter < 256; counter++) { - t = state[counter]; - stateindex = (stateindex + key[keyindex] + t) & 0xff; - u = state[stateindex]; - state[stateindex] = (u8)t; - state[counter] = (u8)u; - if (++keyindex >= key_len) - keyindex = 0; - } -} - -static u32 arcfour_byte(struct arc4context *parc4ctx) -{ - u32 x; - u32 y; - u32 sx, sy; - u8 *state; - - state = parc4ctx->state; - x = (parc4ctx->x + 1) & 0xff; - sx = state[x]; - y = (sx + parc4ctx->y) & 0xff; - sy = state[y]; - parc4ctx->x = x; - parc4ctx->y = y; - state[y] = (u8)sx; - state[x] = (u8)sy; - return state[(sx + sy) & 0xff]; -} - -static void arcfour_encrypt(struct arc4context *parc4ctx, - u8 *dest, u8 *src, u32 len) -{ - u32 i; - - for (i = 0; i < len; i++) - dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); -} - -static sint bcrc32initialized; -static u32 crc32_table[256]; - -static u8 crc32_reverseBit(u8 data) -{ - return ((u8)(data << 7) & 0x80) | ((data << 5) & 0x40) | ((data << 3) - & 0x20) | ((data << 1) & 0x10) | ((data >> 1) & 0x08) | - ((data >> 3) & 0x04) | ((data >> 5) & 0x02) | ((data >> 7) & - 0x01); -} - -static void crc32_init(void) -{ - sint i, j; - u32 c; - u8 *p = (u8 *)&c, *p1; - u8 k; - - if (bcrc32initialized == 1) - return; - - for (i = 0; i < 256; ++i) { - k = crc32_reverseBit((u8)i); - for (c = ((u32)k) << 24, j = 8; j > 0; --j) - c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY_BE : (c << 1); - p1 = (u8 *)&crc32_table[i]; - p1[0] = crc32_reverseBit(p[3]); - p1[1] = crc32_reverseBit(p[2]); - p1[2] = crc32_reverseBit(p[1]); - p1[3] = crc32_reverseBit(p[0]); - } - bcrc32initialized = 1; -} - -static u32 getcrc32(u8 *buf, u32 len) -{ - u8 *p; - u32 crc; - - if (!bcrc32initialized) - crc32_init(); - crc = 0xffffffff; /* preload shift register, per CRC-32 spec */ - for (p = buf; len > 0; ++p, --len) - crc = crc32_table[(crc ^ *p) & 0xff] ^ (crc >> 8); - return ~crc; /* transmit complement, per CRC-32 spec */ -} - -/* - * Need to consider the fragment situation - */ -void r8712_wep_encrypt(struct _adapter *padapter, u8 *pxmitframe) -{ /* exclude ICV */ - unsigned char crc[4]; - struct arc4context mycontext; - u32 curfragnum, length, keylength, pki; - u8 *pframe, *payload, *iv; /*,*wepkey*/ - u8 wepkey[16]; - struct pkt_attrib *pattrib = &((struct xmit_frame *) - pxmitframe)->attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - - if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) - return; - pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + TXDESC_OFFSET; - /*start to encrypt each fragment*/ - if ((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) { - pki = psecuritypriv->PrivacyKeyIndex; - keylength = psecuritypriv->DefKeylen[pki]; - for (curfragnum = 0; curfragnum < pattrib->nr_frags; - curfragnum++) { - iv = pframe + pattrib->hdrlen; - memcpy(&wepkey[0], iv, 3); - memcpy(&wepkey[3], &psecuritypriv->DefKey[ - psecuritypriv->PrivacyKeyIndex].skey[0], - keylength); - payload = pframe + pattrib->iv_len + pattrib->hdrlen; - if ((curfragnum + 1) == pattrib->nr_frags) { - length = pattrib->last_txcmdsz - - pattrib->hdrlen - - pattrib->iv_len - - pattrib->icv_len; - *((__le32 *)crc) = cpu_to_le32(getcrc32( - payload, length)); - arcfour_init(&mycontext, wepkey, 3 + keylength); - arcfour_encrypt(&mycontext, payload, payload, - length); - arcfour_encrypt(&mycontext, payload + length, - crc, 4); - } else { - length = pxmitpriv->frag_len - - pattrib->hdrlen - pattrib->iv_len - - pattrib->icv_len; - *((__le32 *)crc) = cpu_to_le32(getcrc32( - payload, length)); - arcfour_init(&mycontext, wepkey, 3 + keylength); - arcfour_encrypt(&mycontext, payload, payload, - length); - arcfour_encrypt(&mycontext, payload + length, - crc, 4); - pframe += pxmitpriv->frag_len; - pframe = (u8 *)RND4((addr_t)(pframe)); - } - } - } -} - -void r8712_wep_decrypt(struct _adapter *padapter, u8 *precvframe) -{ - /* exclude ICV */ - u8 crc[4]; - struct arc4context mycontext; - u32 length, keylength; - u8 *pframe, *payload, *iv, wepkey[16]; - u8 keyindex; - struct rx_pkt_attrib *prxattrib = &(((union recv_frame *) - precvframe)->u.hdr.attrib); - struct security_priv *psecuritypriv = &padapter->securitypriv; - - pframe = (unsigned char *)((union recv_frame *)precvframe)-> - u.hdr.rx_data; - /* start to decrypt recvframe */ - if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == - _WEP104_)) { - iv = pframe + prxattrib->hdrlen; - keyindex = (iv[3] & 0x3); - keylength = psecuritypriv->DefKeylen[keyindex]; - memcpy(&wepkey[0], iv, 3); - memcpy(&wepkey[3], &psecuritypriv->DefKey[ - psecuritypriv->PrivacyKeyIndex].skey[0], - keylength); - length = ((union recv_frame *)precvframe)-> - u.hdr.len - prxattrib->hdrlen - prxattrib->iv_len; - payload = pframe + prxattrib->iv_len + prxattrib->hdrlen; - /* decrypt payload include icv */ - arcfour_init(&mycontext, wepkey, 3 + keylength); - arcfour_encrypt(&mycontext, payload, payload, length); - /* calculate icv and compare the icv */ - *((__le32 *)crc) = cpu_to_le32(getcrc32(payload, length - 4)); - } -} - -/* 3 =====TKIP related===== */ - -static u32 secmicgetuint32(u8 *p) -/* Convert from Byte[] to Us4Byte32 in a portable way */ -{ - s32 i; - u32 res = 0; - - for (i = 0; i < 4; i++) - res |= ((u32)(*p++)) << (8 * i); - return res; -} - -static void secmicputuint32(u8 *p, u32 val) -/* Convert from Us4Byte32 to Byte[] in a portable way */ -{ - long i; - - for (i = 0; i < 4; i++) { - *p++ = (u8)(val & 0xff); - val >>= 8; - } -} - -static void secmicclear(struct mic_data *pmicdata) -{ -/* Reset the state to the empty message. */ - pmicdata->L = pmicdata->K0; - pmicdata->R = pmicdata->K1; - pmicdata->nBytesInM = 0; - pmicdata->M = 0; -} - -void r8712_secmicsetkey(struct mic_data *pmicdata, u8 *key) -{ - /* Set the key */ - pmicdata->K0 = secmicgetuint32(key); - pmicdata->K1 = secmicgetuint32(key + 4); - /* and reset the message */ - secmicclear(pmicdata); -} - -static void secmicappendbyte(struct mic_data *pmicdata, u8 b) -{ - /* Append the byte to our word-sized buffer */ - pmicdata->M |= ((u32)b) << (8 * pmicdata->nBytesInM); - pmicdata->nBytesInM++; - /* Process the word if it is full. */ - if (pmicdata->nBytesInM >= 4) { - pmicdata->L ^= pmicdata->M; - pmicdata->R ^= ROL32(pmicdata->L, 17); - pmicdata->L += pmicdata->R; - pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | - ((pmicdata->L & 0x00ff00ff) << 8); - pmicdata->L += pmicdata->R; - pmicdata->R ^= ROL32(pmicdata->L, 3); - pmicdata->L += pmicdata->R; - pmicdata->R ^= ROR32(pmicdata->L, 2); - pmicdata->L += pmicdata->R; - /* Clear the buffer */ - pmicdata->M = 0; - pmicdata->nBytesInM = 0; - } -} - -void r8712_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes) -{ - /* This is simple */ - while (nbytes > 0) { - secmicappendbyte(pmicdata, *src++); - nbytes--; - } -} - -void r8712_secgetmic(struct mic_data *pmicdata, u8 *dst) -{ - /* Append the minimum padding */ - secmicappendbyte(pmicdata, 0x5a); - secmicappendbyte(pmicdata, 0); - secmicappendbyte(pmicdata, 0); - secmicappendbyte(pmicdata, 0); - secmicappendbyte(pmicdata, 0); - /* and then zeroes until the length is a multiple of 4 */ - while (pmicdata->nBytesInM != 0) - secmicappendbyte(pmicdata, 0); - /* The appendByte function has already computed the result. */ - secmicputuint32(dst, pmicdata->L); - secmicputuint32(dst + 4, pmicdata->R); - /* Reset to the empty message. */ - secmicclear(pmicdata); -} - -void seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, - u8 pri) -{ - - struct mic_data micdata; - u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; - - r8712_secmicsetkey(&micdata, key); - priority[0] = pri; - /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ - if (header[1] & 1) { /* ToDS==1 */ - r8712_secmicappend(&micdata, &header[16], 6); /* DA */ - if (header[1] & 2) /* From Ds==1 */ - r8712_secmicappend(&micdata, &header[24], 6); - else - r8712_secmicappend(&micdata, &header[10], 6); - } else { /* ToDS==0 */ - r8712_secmicappend(&micdata, &header[4], 6); /* DA */ - if (header[1] & 2) /* From Ds==1 */ - r8712_secmicappend(&micdata, &header[16], 6); - else - r8712_secmicappend(&micdata, &header[10], 6); - } - r8712_secmicappend(&micdata, &priority[0], 4); - r8712_secmicappend(&micdata, data, data_len); - r8712_secgetmic(&micdata, mic_code); -} - -/* macros for extraction/creation of unsigned char/unsigned short values */ -#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) -#define Lo8(v16) ((u8)((v16) & 0x00FF)) -#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF)) -#define Lo16(v32) ((u16)((v32) & 0xFFFF)) -#define Hi16(v32) ((u16)(((v32) >> 16) & 0xFFFF)) -#define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8)) - -/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */ -#define TK16(N) Mk16(tk[2 * (N) + 1], tk[2 * (N)]) - -/* S-box lookup: 16 bits --> 16 bits */ -#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)]) - -/* fixed algorithm "parameters" */ -#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ -#define TA_SIZE 6 /* 48-bit transmitter address */ -#define TK_SIZE 16 /* 128-bit temporal key */ -#define P1K_SIZE 10 /* 80-bit Phase1 key */ -#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ - -/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */ -static const unsigned short Sbox1[2][256] = {/* Sbox for hash (can be in ROM) */ - { - 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, - 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, - 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, - 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, - 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, - 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, - 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, - 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, - 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, - 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, - 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, - 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, - 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, - 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, - 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, - 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, - 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, - 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, - 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, - 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, - 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, - 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, - 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, - 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, - 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, - 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, - 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, - 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, - 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, - 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, - 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, - 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, - }, - { /* second half is unsigned char-reversed version of first! */ - 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, - 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, - 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, - 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, - 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83, - 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A, - 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F, - 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA, - 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, - 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, - 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, - 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, - 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, - 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B, - 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1, - 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF, - 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E, - 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, - 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, - 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, - 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, - 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, - 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049, - 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810, - 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197, - 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F, - 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, - 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, - 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, - 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, - 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, - 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C, - } -}; - -/* - ********************************************************************** - * Routine: Phase 1 -- generate P1K, given TA, TK, IV32 - * - * Inputs: - * tk[] = temporal key [128 bits] - * ta[] = transmitter's MAC address [ 48 bits] - * iv32 = upper 32 bits of IV [ 32 bits] - * Output: - * p1k[] = Phase 1 key [ 80 bits] - * - * Note: - * This function only needs to be called every 2**16 packets, - * although in theory it could be called every packet. - * - ********************************************************************** - */ -static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) -{ - sint i; - - /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ - p1k[0] = Lo16(iv32); - p1k[1] = Hi16(iv32); - p1k[2] = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */ - p1k[3] = Mk16(ta[3], ta[2]); - p1k[4] = Mk16(ta[5], ta[4]); - /* Now compute an unbalanced Feistel cipher with 80-bit block */ - /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ - for (i = 0; i < PHASE1_LOOP_CNT; i++) { /* Each add is mod 2**16 */ - p1k[0] += _S_(p1k[4] ^ TK16((i & 1) + 0)); - p1k[1] += _S_(p1k[0] ^ TK16((i & 1) + 2)); - p1k[2] += _S_(p1k[1] ^ TK16((i & 1) + 4)); - p1k[3] += _S_(p1k[2] ^ TK16((i & 1) + 6)); - p1k[4] += _S_(p1k[3] ^ TK16((i & 1) + 0)); - p1k[4] += (unsigned short)i; /* avoid "slide attacks" */ - } -} - -/* - ********************************************************************** - * Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 - * - * Inputs: - * tk[] = Temporal key [128 bits] - * p1k[] = Phase 1 output key [ 80 bits] - * iv16 = low 16 bits of IV counter [ 16 bits] - * Output: - * rc4key[] = the key used to encrypt the packet [128 bits] - * - * Note: - * The value {TA,IV32,IV16} for Phase1/Phase2 must be unique - * across all packets using the same key TK value. Then, for a - * given value of TK[], this TKIP48 construction guarantees that - * the final RC4KEY value is unique across all packets. - * - * Suggested implementation optimization: if PPK[] is "overlaid" - * appropriately on RC4KEY[], there is no need for the final - * for loop below that copies the PPK[] result into RC4KEY[]. - * - ********************************************************************** - */ -static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) -{ - sint i; - u16 PPK[6]; /* temporary key for mixing */ - - /* Note: all adds in the PPK[] equations below are mod 2**16 */ - for (i = 0; i < 5; i++) - PPK[i] = p1k[i]; /* first, copy P1K to PPK */ - PPK[5] = p1k[4] + iv16; /* next, add in IV16 */ - /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ - PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ - PPK[1] += _S_(PPK[0] ^ TK16(1)); - PPK[2] += _S_(PPK[1] ^ TK16(2)); - PPK[3] += _S_(PPK[2] ^ TK16(3)); - PPK[4] += _S_(PPK[3] ^ TK16(4)); - PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ - /* Final sweep: bijective, "linear". Rotates kill LSB correlations */ - PPK[0] += RotR1(PPK[5] ^ TK16(6)); - PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ - PPK[2] += RotR1(PPK[1]); - PPK[3] += RotR1(PPK[2]); - PPK[4] += RotR1(PPK[3]); - PPK[5] += RotR1(PPK[4]); - /* Note: At this point, for a given key TK[0..15], the 96-bit output */ - /* value PPK[0..5] is guaranteed to be unique, as a function */ - /* of the 96-bit "input" value {TA,IV32,IV16}. That is, P1K */ - /* is now a keyed permutation of {TA,IV32,IV16}. */ - /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */ - rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */ - rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */ - rc4key[2] = Lo8(iv16); - rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); - /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ - for (i = 0; i < 6; i++) { - rc4key[4 + 2 * i] = Lo8(PPK[i]); - rc4key[5 + 2 * i] = Hi8(PPK[i]); - } -} - -/*The hlen isn't include the IV*/ -u32 r8712_tkip_encrypt(struct _adapter *padapter, u8 *pxmitframe) -{ /* exclude ICV */ - u16 pnl; - u32 pnh; - u8 rc4key[16]; - u8 ttkey[16]; - u8 crc[4]; - struct arc4context mycontext; - u32 curfragnum, length; - - u8 *pframe, *payload, *iv, *prwskey; - union pn48 txpn; - struct sta_info *stainfo; - struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - u32 res = _SUCCESS; - - if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) - return _FAIL; - - pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + TXDESC_OFFSET; - /* 4 start to encrypt each fragment */ - if (pattrib->encrypt == _TKIP_) { - if (pattrib->psta) - stainfo = pattrib->psta; - else - stainfo = r8712_get_stainfo(&padapter->stapriv, - &pattrib->ra[0]); - if (stainfo) { - prwskey = &stainfo->x_UncstKey.skey[0]; - for (curfragnum = 0; curfragnum < pattrib->nr_frags; - curfragnum++) { - iv = pframe + pattrib->hdrlen; - payload = pframe + pattrib->iv_len + - pattrib->hdrlen; - GET_TKIP_PN(iv, txpn); - pnl = (u16)(txpn.val); - pnh = (u32)(txpn.val >> 16); - phase1((u16 *)&ttkey[0], prwskey, - &pattrib->ta[0], pnh); - phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], - pnl); - if ((curfragnum + 1) == pattrib->nr_frags) { - /* 4 the last fragment */ - length = pattrib->last_txcmdsz - - pattrib->hdrlen - - pattrib->iv_len - - pattrib->icv_len; - *((__le32 *)crc) = cpu_to_le32( - getcrc32(payload, length)); - arcfour_init(&mycontext, rc4key, 16); - arcfour_encrypt(&mycontext, payload, - payload, length); - arcfour_encrypt(&mycontext, payload + - length, crc, 4); - } else { - length = pxmitpriv->frag_len - - pattrib->hdrlen - - pattrib->iv_len - - pattrib->icv_len; - *((__le32 *)crc) = cpu_to_le32(getcrc32( - payload, length)); - arcfour_init(&mycontext, rc4key, 16); - arcfour_encrypt(&mycontext, payload, - payload, length); - arcfour_encrypt(&mycontext, - payload + length, crc, - 4); - pframe += pxmitpriv->frag_len; - pframe = (u8 *)RND4((addr_t)(pframe)); - } - } - } else { - res = _FAIL; - } - } - return res; -} - -/* The hlen doesn't include the IV */ -void r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe) -{ /* exclude ICV */ - u16 pnl; - u32 pnh; - u8 rc4key[16]; - u8 ttkey[16]; - u8 crc[4]; - struct arc4context mycontext; - u32 length; - u8 *pframe, *payload, *iv, *prwskey, idx = 0; - union pn48 txpn; - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &((union recv_frame *) - precvframe)->u.hdr.attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - - pframe = (unsigned char *)((union recv_frame *) - precvframe)->u.hdr.rx_data; - /* 4 start to decrypt recvframe */ - if (prxattrib->encrypt == _TKIP_) { - stainfo = r8712_get_stainfo(&padapter->stapriv, - &prxattrib->ta[0]); - if (stainfo) { - iv = pframe + prxattrib->hdrlen; - payload = pframe + prxattrib->iv_len + - prxattrib->hdrlen; - length = ((union recv_frame *)precvframe)-> - u.hdr.len - prxattrib->hdrlen - - prxattrib->iv_len; - if (is_multicast_ether_addr(prxattrib->ra)) { - idx = iv[3]; - prwskey = &psecuritypriv->XGrpKey[ - ((idx >> 6) & 0x3) - 1].skey[0]; - if (!psecuritypriv->binstallGrpkey) - return; - } else { - prwskey = &stainfo->x_UncstKey.skey[0]; - } - GET_TKIP_PN(iv, txpn); - pnl = (u16)(txpn.val); - pnh = (u32)(txpn.val >> 16); - phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], - pnh); - phase2(&rc4key[0], prwskey, (unsigned short *) - &ttkey[0], pnl); - /* 4 decrypt payload include icv */ - arcfour_init(&mycontext, rc4key, 16); - arcfour_encrypt(&mycontext, payload, payload, length); - *((__le32 *)crc) = cpu_to_le32(getcrc32(payload, - length - 4)); - } - } -} - -/* 3 =====AES related===== */ - -#define MAX_MSG_SIZE 2048 -/*****************************/ -/******** SBOX Table *********/ -/*****************************/ - -static const u8 sbox_table[256] = { - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 -}; - -/****************************************/ -/* aes128k128d() */ -/* Performs a 128 bit AES encrypt with */ -/* 128 bit data. */ -/****************************************/ -static void xor_128(u8 *a, u8 *b, u8 *out) -{ - sint i; - - for (i = 0; i < 16; i++) - out[i] = a[i] ^ b[i]; -} - -static void xor_32(u8 *a, u8 *b, u8 *out) -{ - sint i; - - for (i = 0; i < 4; i++) - out[i] = a[i] ^ b[i]; -} - -static u8 sbox(u8 a) -{ - return sbox_table[(sint)a]; -} - -static void next_key(u8 *key, sint round) -{ - u8 rcon; - u8 sbox_key[4]; - static const u8 rcon_table[12] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, - 0x1b, 0x36, 0x36, 0x36 - }; - - sbox_key[0] = sbox(key[13]); - sbox_key[1] = sbox(key[14]); - sbox_key[2] = sbox(key[15]); - sbox_key[3] = sbox(key[12]); - rcon = rcon_table[round]; - xor_32(&key[0], sbox_key, &key[0]); - key[0] = key[0] ^ rcon; - xor_32(&key[4], &key[0], &key[4]); - xor_32(&key[8], &key[4], &key[8]); - xor_32(&key[12], &key[8], &key[12]); -} - -static void byte_sub(u8 *in, u8 *out) -{ - sint i; - - for (i = 0; i < 16; i++) - out[i] = sbox(in[i]); -} - -static void shift_row(u8 *in, u8 *out) -{ - out[0] = in[0]; - out[1] = in[5]; - out[2] = in[10]; - out[3] = in[15]; - out[4] = in[4]; - out[5] = in[9]; - out[6] = in[14]; - out[7] = in[3]; - out[8] = in[8]; - out[9] = in[13]; - out[10] = in[2]; - out[11] = in[7]; - out[12] = in[12]; - out[13] = in[1]; - out[14] = in[6]; - out[15] = in[11]; -} - -static void mix_column(u8 *in, u8 *out) -{ - sint i; - u8 add1b[4]; - u8 add1bf7[4]; - u8 rotl[4]; - u8 swap_halves[4]; - u8 andf7[4]; - u8 rotr[4]; - u8 temp[4]; - u8 tempb[4]; - - for (i = 0; i < 4; i++) { - if ((in[i] & 0x80) == 0x80) - add1b[i] = 0x1b; - else - add1b[i] = 0x00; - } - swap_halves[0] = in[2]; /* Swap halves */ - swap_halves[1] = in[3]; - swap_halves[2] = in[0]; - swap_halves[3] = in[1]; - rotl[0] = in[3]; /* Rotate left 8 bits */ - rotl[1] = in[0]; - rotl[2] = in[1]; - rotl[3] = in[2]; - andf7[0] = in[0] & 0x7f; - andf7[1] = in[1] & 0x7f; - andf7[2] = in[2] & 0x7f; - andf7[3] = in[3] & 0x7f; - for (i = 3; i > 0; i--) { /* logical shift left 1 bit */ - andf7[i] = andf7[i] << 1; - if ((andf7[i - 1] & 0x80) == 0x80) - andf7[i] = (andf7[i] | 0x01); - } - andf7[0] = andf7[0] << 1; - andf7[0] = andf7[0] & 0xfe; - xor_32(add1b, andf7, add1bf7); - xor_32(in, add1bf7, rotr); - temp[0] = rotr[0]; /* Rotate right 8 bits */ - rotr[0] = rotr[1]; - rotr[1] = rotr[2]; - rotr[2] = rotr[3]; - rotr[3] = temp[0]; - xor_32(add1bf7, rotr, temp); - xor_32(swap_halves, rotl, tempb); - xor_32(temp, tempb, out); -} - -static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) -{ - sint round; - sint i; - u8 intermediatea[16]; - u8 intermediateb[16]; - u8 round_key[16]; - - for (i = 0; i < 16; i++) - round_key[i] = key[i]; - for (round = 0; round < 11; round++) { - if (round == 0) { - xor_128(round_key, data, ciphertext); - next_key(round_key, round); - } else if (round == 10) { - byte_sub(ciphertext, intermediatea); - shift_row(intermediatea, intermediateb); - xor_128(intermediateb, round_key, ciphertext); - } else { /* 1 - 9 */ - byte_sub(ciphertext, intermediatea); - shift_row(intermediatea, intermediateb); - mix_column(&intermediateb[0], &intermediatea[0]); - mix_column(&intermediateb[4], &intermediatea[4]); - mix_column(&intermediateb[8], &intermediatea[8]); - mix_column(&intermediateb[12], &intermediatea[12]); - xor_128(intermediatea, round_key, ciphertext); - next_key(round_key, round); - } - } -} - -/************************************************/ -/* construct_mic_iv() */ -/* Builds the MIC IV from header fields and PN */ -/************************************************/ -static void construct_mic_iv(u8 *mic_iv, sint qc_exists, sint a4_exists, - u8 *mpdu, uint payload_length, u8 *pn_vector) -{ - sint i; - - mic_iv[0] = 0x59; - if (qc_exists && a4_exists) - mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ - if (qc_exists && !a4_exists) - mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ - if (!qc_exists) - mic_iv[1] = 0x00; - for (i = 2; i < 8; i++) - mic_iv[i] = mpdu[i + 8]; - for (i = 8; i < 14; i++) - mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ - mic_iv[14] = (unsigned char)(payload_length / 256); - mic_iv[15] = (unsigned char)(payload_length % 256); -} - -/************************************************/ -/* construct_mic_header1() */ -/* Builds the first MIC header block from */ -/* header fields. */ -/************************************************/ -static void construct_mic_header1(u8 *mic_header1, sint header_length, u8 *mpdu) -{ - mic_header1[0] = (u8)((header_length - 2) / 256); - mic_header1[1] = (u8)((header_length - 2) % 256); - mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ - /* Mute retry, more data and pwr mgt bits */ - mic_header1[3] = mpdu[1] & 0xc7; - mic_header1[4] = mpdu[4]; /* A1 */ - mic_header1[5] = mpdu[5]; - mic_header1[6] = mpdu[6]; - mic_header1[7] = mpdu[7]; - mic_header1[8] = mpdu[8]; - mic_header1[9] = mpdu[9]; - mic_header1[10] = mpdu[10]; /* A2 */ - mic_header1[11] = mpdu[11]; - mic_header1[12] = mpdu[12]; - mic_header1[13] = mpdu[13]; - mic_header1[14] = mpdu[14]; - mic_header1[15] = mpdu[15]; -} - -/************************************************/ -/* construct_mic_header2() */ -/* Builds the last MIC header block from */ -/* header fields. */ -/************************************************/ -static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, sint a4_exists, - sint qc_exists) -{ - sint i; - - for (i = 0; i < 16; i++) - mic_header2[i] = 0x00; - mic_header2[0] = mpdu[16]; /* A3 */ - mic_header2[1] = mpdu[17]; - mic_header2[2] = mpdu[18]; - mic_header2[3] = mpdu[19]; - mic_header2[4] = mpdu[20]; - mic_header2[5] = mpdu[21]; - mic_header2[6] = 0x00; - mic_header2[7] = 0x00; /* mpdu[23]; */ - if (!qc_exists && a4_exists) - for (i = 0; i < 6; i++) - mic_header2[8 + i] = mpdu[24 + i]; /* A4 */ - if (qc_exists && !a4_exists) { - mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ - mic_header2[9] = mpdu[25] & 0x00; - } - if (qc_exists && a4_exists) { - for (i = 0; i < 6; i++) - mic_header2[8 + i] = mpdu[24 + i]; /* A4 */ - mic_header2[14] = mpdu[30] & 0x0f; - mic_header2[15] = mpdu[31] & 0x00; - } -} - -/************************************************/ -/* construct_mic_header2() */ -/* Builds the last MIC header block from */ -/* header fields. */ -/************************************************/ -static void construct_ctr_preload(u8 *ctr_preload, - sint a4_exists, sint qc_exists, - u8 *mpdu, u8 *pn_vector, sint c) -{ - sint i; - - for (i = 0; i < 16; i++) - ctr_preload[i] = 0x00; - i = 0; - ctr_preload[0] = 0x01; /* flag */ - if (qc_exists && a4_exists) - ctr_preload[1] = mpdu[30] & 0x0f; - if (qc_exists && !a4_exists) - ctr_preload[1] = mpdu[24] & 0x0f; - for (i = 2; i < 8; i++) - ctr_preload[i] = mpdu[i + 8]; - for (i = 8; i < 14; i++) - ctr_preload[i] = pn_vector[13 - i]; - ctr_preload[14] = (unsigned char)(c / 256); /* Ctr */ - ctr_preload[15] = (unsigned char)(c % 256); -} - -/************************************/ -/* bitwise_xor() */ -/* A 128 bit, bitwise exclusive or */ -/************************************/ -static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) -{ - sint i; - - for (i = 0; i < 16; i++) - out[i] = ina[i] ^ inb[i]; -} - -static void aes_cipher(u8 *key, uint hdrlen, - u8 *pframe, uint plen) -{ - uint qc_exists, a4_exists, i, j, payload_remainder; - uint num_blocks, payload_index; - - u8 pn_vector[6]; - u8 mic_iv[16]; - u8 mic_header1[16]; - u8 mic_header2[16]; - u8 ctr_preload[16]; - - /* Intermediate Buffers */ - u8 chain_buffer[16]; - u8 aes_out[16]; - u8 padded_buffer[16]; - u8 mic[8]; - u16 frtype = GetFrameType(pframe); - u16 frsubtype = GetFrameSubType(pframe); - - frsubtype >>= 4; - memset((void *)mic_iv, 0, 16); - memset((void *)mic_header1, 0, 16); - memset((void *)mic_header2, 0, 16); - memset((void *)ctr_preload, 0, 16); - memset((void *)chain_buffer, 0, 16); - memset((void *)aes_out, 0, 16); - memset((void *)padded_buffer, 0, 16); - - if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) - a4_exists = 0; - else - a4_exists = 1; - - if ((frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFACK)) || - (frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFPOLL)) || - (frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFACKPOLL))) { - qc_exists = 1; - if (hdrlen != WLAN_HDR_A3_QOS_LEN) - hdrlen += 2; - } else if ((frsubtype == 0x08) || - (frsubtype == 0x09) || - (frsubtype == 0x0a) || - (frsubtype == 0x0b)) { - if (hdrlen != WLAN_HDR_A3_QOS_LEN) - hdrlen += 2; - qc_exists = 1; - } else { - qc_exists = 0; - } - pn_vector[0] = pframe[hdrlen]; - pn_vector[1] = pframe[hdrlen + 1]; - pn_vector[2] = pframe[hdrlen + 4]; - pn_vector[3] = pframe[hdrlen + 5]; - pn_vector[4] = pframe[hdrlen + 6]; - pn_vector[5] = pframe[hdrlen + 7]; - construct_mic_iv(mic_iv, qc_exists, a4_exists, pframe, plen, pn_vector); - construct_mic_header1(mic_header1, hdrlen, pframe); - construct_mic_header2(mic_header2, pframe, a4_exists, qc_exists); - payload_remainder = plen % 16; - num_blocks = plen / 16; - /* Find start of payload */ - payload_index = hdrlen + 8; - /* Calculate MIC */ - aes128k128d(key, mic_iv, aes_out); - bitwise_xor(aes_out, mic_header1, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - bitwise_xor(aes_out, mic_header2, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - for (i = 0; i < num_blocks; i++) { - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); - payload_index += 16; - aes128k128d(key, chain_buffer, aes_out); - } - /* Add on the final payload block if it needs padding */ - if (payload_remainder > 0) { - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = pframe[payload_index++]; - bitwise_xor(aes_out, padded_buffer, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - } - for (j = 0; j < 8; j++) - mic[j] = aes_out[j]; - /* Insert MIC into payload */ - for (j = 0; j < 8; j++) - pframe[payload_index + j] = mic[j]; - payload_index = hdrlen + 8; - for (i = 0; i < num_blocks; i++) { - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, - pframe, pn_vector, i + 1); - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); - for (j = 0; j < 16; j++) - pframe[payload_index++] = chain_buffer[j]; - } - if (payload_remainder > 0) { /* If short final block, then pad it,*/ - /* encrypt and copy unpadded part back */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, - pframe, pn_vector, num_blocks + 1); - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = pframe[payload_index + j]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < payload_remainder; j++) - pframe[payload_index++] = chain_buffer[j]; - } - /* Encrypt the MIC */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, - pframe, pn_vector, 0); - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < 8; j++) - padded_buffer[j] = pframe[j + hdrlen + 8 + plen]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < 8; j++) - pframe[payload_index++] = chain_buffer[j]; -} - -u32 r8712_aes_encrypt(struct _adapter *padapter, u8 *pxmitframe) -{ /* exclude ICV */ - /* Intermediate Buffers */ - sint curfragnum, length; - u8 *pframe, *prwskey; - struct sta_info *stainfo; - struct pkt_attrib *pattrib = &((struct xmit_frame *) - pxmitframe)->attrib; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - u32 res = _SUCCESS; - - if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) - return _FAIL; - pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + TXDESC_OFFSET; - /* 4 start to encrypt each fragment */ - if (pattrib->encrypt == _AES_) { - if (pattrib->psta) - stainfo = pattrib->psta; - else - stainfo = r8712_get_stainfo(&padapter->stapriv, - &pattrib->ra[0]); - if (stainfo) { - prwskey = &stainfo->x_UncstKey.skey[0]; - for (curfragnum = 0; curfragnum < pattrib->nr_frags; - curfragnum++) { - if ((curfragnum + 1) == pattrib->nr_frags) { - length = pattrib->last_txcmdsz - - pattrib->hdrlen - - pattrib->iv_len - - pattrib->icv_len; - aes_cipher(prwskey, pattrib->hdrlen, - pframe, length); - } else { - length = pxmitpriv->frag_len - - pattrib->hdrlen - - pattrib->iv_len - - pattrib->icv_len; - aes_cipher(prwskey, pattrib->hdrlen, - pframe, length); - pframe += pxmitpriv->frag_len; - pframe = (u8 *)RND4((addr_t)(pframe)); - } - } - } else { - res = _FAIL; - } - } - return res; -} - -static void aes_decipher(u8 *key, uint hdrlen, - u8 *pframe, uint plen) -{ - static u8 message[MAX_MSG_SIZE]; - uint qc_exists, a4_exists, i, j, payload_remainder; - uint num_blocks, payload_index; - u8 pn_vector[6]; - u8 mic_iv[16]; - u8 mic_header1[16]; - u8 mic_header2[16]; - u8 ctr_preload[16]; - /* Intermediate Buffers */ - u8 chain_buffer[16]; - u8 aes_out[16]; - u8 padded_buffer[16]; - u8 mic[8]; - uint frtype = GetFrameType(pframe); - uint frsubtype = GetFrameSubType(pframe); - - frsubtype >>= 4; - memset((void *)mic_iv, 0, 16); - memset((void *)mic_header1, 0, 16); - memset((void *)mic_header2, 0, 16); - memset((void *)ctr_preload, 0, 16); - memset((void *)chain_buffer, 0, 16); - memset((void *)aes_out, 0, 16); - memset((void *)padded_buffer, 0, 16); - /* start to decrypt the payload */ - /*(plen including llc, payload and mic) */ - num_blocks = (plen - 8) / 16; - payload_remainder = (plen - 8) % 16; - pn_vector[0] = pframe[hdrlen]; - pn_vector[1] = pframe[hdrlen + 1]; - pn_vector[2] = pframe[hdrlen + 4]; - pn_vector[3] = pframe[hdrlen + 5]; - pn_vector[4] = pframe[hdrlen + 6]; - pn_vector[5] = pframe[hdrlen + 7]; - if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) - a4_exists = 0; - else - a4_exists = 1; - if ((frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFACK)) || - (frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFPOLL)) || - (frtype == (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA_CFACKPOLL))) { - qc_exists = 1; - if (hdrlen != WLAN_HDR_A3_QOS_LEN) - hdrlen += 2; - } else if ((frsubtype == 0x08) || - (frsubtype == 0x09) || - (frsubtype == 0x0a) || - (frsubtype == 0x0b)) { - if (hdrlen != WLAN_HDR_A3_QOS_LEN) - hdrlen += 2; - qc_exists = 1; - } else { - qc_exists = 0; - } - /* now, decrypt pframe with hdrlen offset and plen long */ - payload_index = hdrlen + 8; /* 8 is for extiv */ - for (i = 0; i < num_blocks; i++) { - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, - pframe, pn_vector, i + 1); - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); - for (j = 0; j < 16; j++) - pframe[payload_index++] = chain_buffer[j]; - } - if (payload_remainder > 0) { /* If short final block, pad it,*/ - /* encrypt it and copy the unpadded part back */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, - pframe, pn_vector, num_blocks + 1); - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = pframe[payload_index + j]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < payload_remainder; j++) - pframe[payload_index++] = chain_buffer[j]; - } - /* start to calculate the mic */ - memcpy((void *)message, pframe, (hdrlen + plen + 8)); - pn_vector[0] = pframe[hdrlen]; - pn_vector[1] = pframe[hdrlen + 1]; - pn_vector[2] = pframe[hdrlen + 4]; - pn_vector[3] = pframe[hdrlen + 5]; - pn_vector[4] = pframe[hdrlen + 6]; - pn_vector[5] = pframe[hdrlen + 7]; - construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen - 8, - pn_vector); - construct_mic_header1(mic_header1, hdrlen, message); - construct_mic_header2(mic_header2, message, a4_exists, qc_exists); - payload_remainder = (plen - 8) % 16; - num_blocks = (plen - 8) / 16; - /* Find start of payload */ - payload_index = hdrlen + 8; - /* Calculate MIC */ - aes128k128d(key, mic_iv, aes_out); - bitwise_xor(aes_out, mic_header1, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - bitwise_xor(aes_out, mic_header2, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - for (i = 0; i < num_blocks; i++) { - bitwise_xor(aes_out, &message[payload_index], chain_buffer); - payload_index += 16; - aes128k128d(key, chain_buffer, aes_out); - } - /* Add on the final payload block if it needs padding */ - if (payload_remainder > 0) { - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = message[payload_index++]; - bitwise_xor(aes_out, padded_buffer, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - } - for (j = 0; j < 8; j++) - mic[j] = aes_out[j]; - /* Insert MIC into payload */ - for (j = 0; j < 8; j++) - message[payload_index + j] = mic[j]; - payload_index = hdrlen + 8; - for (i = 0; i < num_blocks; i++) { - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, - message, pn_vector, i + 1); - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &message[payload_index], chain_buffer); - for (j = 0; j < 16; j++) - message[payload_index++] = chain_buffer[j]; - } - if (payload_remainder > 0) { /* If short final block, pad it,*/ - /* encrypt and copy unpadded part back */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, - message, pn_vector, num_blocks + 1); - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = message[payload_index + j]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < payload_remainder; j++) - message[payload_index++] = chain_buffer[j]; - } - /* Encrypt the MIC */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, - pn_vector, 0); - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < 8; j++) - padded_buffer[j] = message[j + hdrlen + plen]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < 8; j++) - message[payload_index++] = chain_buffer[j]; - /* compare the mic */ -} - -void r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe) -{ /* exclude ICV */ - /* Intermediate Buffers */ - sint length; - u8 *pframe, *prwskey, *iv, idx; - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &((union recv_frame *) - precvframe)->u.hdr.attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - - pframe = (unsigned char *)((union recv_frame *)precvframe)-> - u.hdr.rx_data; - /* 4 start to encrypt each fragment */ - if (prxattrib->encrypt == _AES_) { - stainfo = r8712_get_stainfo(&padapter->stapriv, - &prxattrib->ta[0]); - if (stainfo) { - if (is_multicast_ether_addr(prxattrib->ra)) { - iv = pframe + prxattrib->hdrlen; - idx = iv[3]; - prwskey = &psecuritypriv->XGrpKey[ - ((idx >> 6) & 0x3) - 1].skey[0]; - if (!psecuritypriv->binstallGrpkey) - return; - - } else { - prwskey = &stainfo->x_UncstKey.skey[0]; - } - length = ((union recv_frame *)precvframe)-> - u.hdr.len - prxattrib->hdrlen - - prxattrib->iv_len; - aes_decipher(prwskey, prxattrib->hdrlen, pframe, - length); - } - } -} - -void r8712_use_tkipkey_handler(struct timer_list *t) -{ - struct _adapter *padapter = - from_timer(padapter, t, securitypriv.tkip_timer); - - padapter->securitypriv.busetkipkey = true; -} diff --git a/drivers/staging/rtl8712/rtl871x_security.h b/drivers/staging/rtl8712/rtl871x_security.h deleted file mode 100644 index 8461b7f05359a0..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_security.h +++ /dev/null @@ -1,218 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __RTL871X_SECURITY_H_ -#define __RTL871X_SECURITY_H_ - -#include "osdep_service.h" -#include "drv_types.h" - -#define _NO_PRIVACY_ 0x0 -#define _WEP40_ 0x1 -#define _TKIP_ 0x2 -#define _TKIP_WTMIC_ 0x3 -#define _AES_ 0x4 -#define _WEP104_ 0x5 - -#define _WPA_IE_ID_ 0xdd -#define _WPA2_IE_ID_ 0x30 - -#ifndef Ndis802_11AuthModeWPA2 -#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1) -#endif - -#ifndef Ndis802_11AuthModeWPA2PSK -#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2) -#endif - -union pn48 { - u64 val; -#if defined(__BIG_ENDIAN) - struct { - u8 TSC7; - u8 TSC6; - u8 TSC5; - u8 TSC4; - u8 TSC3; - u8 TSC2; - u8 TSC1; - u8 TSC0; - } _byte_; -#else - struct { - u8 TSC0; - u8 TSC1; - u8 TSC2; - u8 TSC3; - u8 TSC4; - u8 TSC5; - u8 TSC6; - u8 TSC7; - } _byte_; -#endif -}; - -union Keytype { - u8 skey[16]; - u32 lkey[4]; -}; - -struct RT_PMKID_LIST { - u8 bUsed; - u8 Bssid[6]; - u8 PMKID[16]; - u8 SsidBuf[33]; - u8 *ssid_octet; - u16 ssid_length; -}; - -struct security_priv { - u32 AuthAlgrthm; /* 802.11 auth, could be open, shared, - * 8021x and authswitch - */ - u32 PrivacyAlgrthm; /* This specify the privacy for shared - * auth. algorithm. - */ - u32 PrivacyKeyIndex; /* this is only valid for legendary - * wep, 0~3 for key id. - */ - union Keytype DefKey[4]; /* this is only valid for def. key */ - u32 DefKeylen[4]; - u32 XGrpPrivacy; /* This specify the privacy algthm. - * used for Grp key - */ - u32 XGrpKeyid; /* key id used for Grp Key */ - union Keytype XGrpKey[2]; /* 802.1x Group Key, for - * inx0 and inx1 - */ - union Keytype XGrptxmickey[2]; - union Keytype XGrprxmickey[2]; - union pn48 Grptxpn; /* PN48 used for Grp Key xmit. */ - union pn48 Grprxpn; /* PN48 used for Grp Key recv. */ - u8 wps_hw_pbc_pressed;/*for hw pbc pressed*/ - u8 wps_phase;/*for wps*/ - u8 wps_ie[MAX_WPA_IE_LEN << 2]; - int wps_ie_len; - u8 binstallGrpkey; - u8 busetkipkey; - struct timer_list tkip_timer; - u8 bcheck_grpkey; - u8 bgrpkey_handshake; - s32 sw_encrypt; /* from registry_priv */ - s32 sw_decrypt; /* from registry_priv */ - s32 hw_decrypted; /* if the rx packets is hw_decrypted==false, - * it means the hw has not been ready. - */ - u32 ndisauthtype; /* keeps the auth_type & enc_status from upper - * layer ioctl(wpa_supplicant or wzc) - */ - u32 ndisencryptstatus; - struct wlan_bssid_ex sec_bss; /* for joinbss (h2c buffer) usage */ - struct NDIS_802_11_WEP ndiswep; - u8 assoc_info[600]; - u8 szofcapability[256]; /* for wpa2 usage */ - u8 oidassociation[512]; /* for wpa/wpa2 usage */ - u8 authenticator_ie[256]; /* store ap security information element */ - u8 supplicant_ie[256]; /* store sta security information element */ - /* for tkip countermeasure */ - u32 last_mic_err_time; - u8 btkip_countermeasure; - u8 btkip_wait_report; - u32 btkip_countermeasure_time; - /*------------------------------------------------------------------- - * For WPA2 Pre-Authentication. - *------------------------------------------------------------------ - **/ - struct RT_PMKID_LIST PMKIDList[NUM_PMKID_CACHE]; - u8 PMKIDIndex; -}; - -#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst) \ -do { \ - switch (psecuritypriv->AuthAlgrthm) { \ - case 0: \ - case 1: \ - case 3: \ - encry_algo = (u8)psecuritypriv->PrivacyAlgrthm; \ - break; \ - case 2: \ - if (bmcst) \ - encry_algo = (u8)psecuritypriv->XGrpPrivacy; \ - else \ - encry_algo = (u8)psta->XPrivacy; \ - break; \ - } \ -} while (0) -#define SET_ICE_IV_LEN(iv_len, icv_len, encrypt)\ -do {\ - switch (encrypt) { \ - case _WEP40_: \ - case _WEP104_: \ - iv_len = 4; \ - icv_len = 4; \ - break; \ - case _TKIP_: \ - iv_len = 8; \ - icv_len = 4; \ - break; \ - case _AES_: \ - iv_len = 8; \ - icv_len = 8; \ - break; \ - default: \ - iv_len = 0; \ - icv_len = 0; \ - break; \ - } \ -} while (0) -#define GET_TKIP_PN(iv, txpn) \ -do {\ - txpn._byte_.TSC0 = iv[2];\ - txpn._byte_.TSC1 = iv[0];\ - txpn._byte_.TSC2 = iv[4];\ - txpn._byte_.TSC3 = iv[5];\ - txpn._byte_.TSC4 = iv[6];\ - txpn._byte_.TSC5 = iv[7];\ -} while (0) - -#define ROL32(A, n) (((A) << (n)) | (((A) >> (32 - (n))) & ((1UL << (n)) - 1))) -#define ROR32(A, n) ROL32((A), 32 - (n)) - -struct mic_data { - u32 K0, K1; /* Key */ - u32 L, R; /* Current state */ - u32 M; /* Message accumulator (single word) */ - u32 nBytesInM; /* # bytes in M */ -}; - -void seccalctkipmic( - u8 *key, - u8 *header, - u8 *data, - u32 data_len, - u8 *Miccode, - u8 priority); - -void r8712_secmicsetkey(struct mic_data *pmicdata, u8 *key); -void r8712_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nBytes); -void r8712_secgetmic(struct mic_data *pmicdata, u8 *dst); -u32 r8712_aes_encrypt(struct _adapter *padapter, u8 *pxmitframe); -u32 r8712_tkip_encrypt(struct _adapter *padapter, u8 *pxmitframe); -void r8712_wep_encrypt(struct _adapter *padapter, u8 *pxmitframe); -void r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe); -void r8712_tkip_decrypt(struct _adapter *padapter, u8 *precvframe); -void r8712_wep_decrypt(struct _adapter *padapter, u8 *precvframe); -void r8712_use_tkipkey_handler(struct timer_list *t); - -#endif /*__RTL871X_SECURITY_H_ */ - diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c deleted file mode 100644 index 2c806a0105bf6c..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c +++ /dev/null @@ -1,263 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_sta_mgt.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_STA_MGT_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "recv_osdep.h" -#include "xmit_osdep.h" -#include "sta_info.h" - -static void _init_stainfo(struct sta_info *psta) -{ - memset((u8 *)psta, 0, sizeof(struct sta_info)); - spin_lock_init(&psta->lock); - INIT_LIST_HEAD(&psta->list); - INIT_LIST_HEAD(&psta->hash_list); - _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); - _r8712_init_sta_recv_priv(&psta->sta_recvpriv); - INIT_LIST_HEAD(&psta->asoc_list); - INIT_LIST_HEAD(&psta->auth_list); -} - -int _r8712_init_sta_priv(struct sta_priv *pstapriv) -{ - struct sta_info *psta; - s32 i; - - pstapriv->pallocated_stainfo_buf = kmalloc(sizeof(struct sta_info) * - NUM_STA + 4, GFP_ATOMIC); - if (!pstapriv->pallocated_stainfo_buf) - return -ENOMEM; - pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - - ((addr_t)(pstapriv->pallocated_stainfo_buf) & 3); - _init_queue(&pstapriv->free_sta_queue); - spin_lock_init(&pstapriv->sta_hash_lock); - pstapriv->asoc_sta_count = 0; - _init_queue(&pstapriv->sleep_q); - _init_queue(&pstapriv->wakeup_q); - psta = (struct sta_info *)(pstapriv->pstainfo_buf); - for (i = 0; i < NUM_STA; i++) { - _init_stainfo(psta); - INIT_LIST_HEAD(&(pstapriv->sta_hash[i])); - list_add_tail(&psta->list, &pstapriv->free_sta_queue.queue); - psta++; - } - INIT_LIST_HEAD(&pstapriv->asoc_list); - INIT_LIST_HEAD(&pstapriv->auth_list); - return 0; -} - -/* this function is used to free the memory of lock || sema for all stainfos */ -static void mfree_all_stainfo(struct sta_priv *pstapriv) -{ - unsigned long irqL; - struct list_head *plist, *phead; - - spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); - phead = &pstapriv->free_sta_queue.queue; - plist = phead->next; - while (!end_of_queue_search(phead, plist)) - plist = plist->next; - - spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); -} - -void _r8712_free_sta_priv(struct sta_priv *pstapriv) -{ - if (pstapriv) { - /* be done before free sta_hash_lock */ - mfree_all_stainfo(pstapriv); - kfree(pstapriv->pallocated_stainfo_buf); - } -} - -struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) -{ - s32 index; - struct list_head *phash_list; - struct sta_info *psta; - struct __queue *pfree_sta_queue; - struct recv_reorder_ctrl *preorder_ctrl; - int i = 0; - u16 wRxSeqInitialValue = 0xffff; - unsigned long flags; - - pfree_sta_queue = &pstapriv->free_sta_queue; - spin_lock_irqsave(&pfree_sta_queue->lock, flags); - psta = list_first_entry_or_null(&pfree_sta_queue->queue, - struct sta_info, list); - if (psta) { - list_del_init(&psta->list); - _init_stainfo(psta); - memcpy(psta->hwaddr, hwaddr, ETH_ALEN); - index = wifi_mac_hash(hwaddr); - if (index >= NUM_STA) { - psta = NULL; - goto exit; - } - phash_list = &pstapriv->sta_hash[index]; - list_add_tail(&psta->hash_list, phash_list); - pstapriv->asoc_sta_count++; - -/* For the SMC router, the sequence number of first packet of WPS handshake - * will be 0. In this case, this packet will be dropped by recv_decache function - * if we use the 0x00 as the default value for tid_rxseq variable. So, we - * initialize the tid_rxseq variable as the 0xffff. - */ - for (i = 0; i < 16; i++) - memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], - &wRxSeqInitialValue, 2); - /* for A-MPDU Rx reordering buffer control */ - for (i = 0; i < 16; i++) { - preorder_ctrl = &psta->recvreorder_ctrl[i]; - preorder_ctrl->padapter = pstapriv->padapter; - preorder_ctrl->indicate_seq = 0xffff; - preorder_ctrl->wend_b = 0xffff; - preorder_ctrl->wsize_b = 64; - _init_queue(&preorder_ctrl->pending_recvframe_queue); - r8712_init_recv_timer(preorder_ctrl); - } - } -exit: - spin_unlock_irqrestore(&pfree_sta_queue->lock, flags); - return psta; -} - -/* using pstapriv->sta_hash_lock to protect */ -void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta) -{ - int i; - unsigned long irqL0; - struct __queue *pfree_sta_queue; - struct recv_reorder_ctrl *preorder_ctrl; - struct sta_xmit_priv *pstaxmitpriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct sta_priv *pstapriv = &padapter->stapriv; - - if (!psta) - return; - pfree_sta_queue = &pstapriv->free_sta_queue; - pstaxmitpriv = &psta->sta_xmitpriv; - spin_lock_irqsave(&(pxmitpriv->vo_pending.lock), irqL0); - r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); - list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); - spin_unlock_irqrestore(&(pxmitpriv->vo_pending.lock), irqL0); - spin_lock_irqsave(&(pxmitpriv->vi_pending.lock), irqL0); - r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); - list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); - spin_unlock_irqrestore(&(pxmitpriv->vi_pending.lock), irqL0); - spin_lock_irqsave(&(pxmitpriv->bk_pending.lock), irqL0); - r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); - list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); - spin_unlock_irqrestore(&(pxmitpriv->bk_pending.lock), irqL0); - spin_lock_irqsave(&(pxmitpriv->be_pending.lock), irqL0); - r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); - list_del_init(&(pstaxmitpriv->be_q.tx_pending)); - spin_unlock_irqrestore(&(pxmitpriv->be_pending.lock), irqL0); - list_del_init(&psta->hash_list); - pstapriv->asoc_sta_count--; - /* re-init sta_info; 20061114 */ - _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); - _r8712_init_sta_recv_priv(&psta->sta_recvpriv); - /* for A-MPDU Rx reordering buffer control, - * cancel reordering_ctrl_timer - */ - for (i = 0; i < 16; i++) { - preorder_ctrl = &psta->recvreorder_ctrl[i]; - del_timer(&preorder_ctrl->reordering_ctrl_timer); - } - spin_lock(&(pfree_sta_queue->lock)); - /* insert into free_sta_queue; 20061114 */ - list_add_tail(&psta->list, &pfree_sta_queue->queue); - spin_unlock(&(pfree_sta_queue->lock)); -} - -/* free all stainfo which in sta_hash[all] */ -void r8712_free_all_stainfo(struct _adapter *padapter) -{ - unsigned long irqL; - struct list_head *plist, *phead; - s32 index; - struct sta_info *psta = NULL; - struct sta_priv *pstapriv = &padapter->stapriv; - struct sta_info *pbcmc_stainfo = r8712_get_bcmc_stainfo(padapter); - - if (pstapriv->asoc_sta_count == 1) - return; - spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); - for (index = 0; index < NUM_STA; index++) { - phead = &(pstapriv->sta_hash[index]); - plist = phead->next; - while (!end_of_queue_search(phead, plist)) { - psta = container_of(plist, - struct sta_info, hash_list); - plist = plist->next; - if (pbcmc_stainfo != psta) - r8712_free_stainfo(padapter, psta); - } - } - spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); -} - -/* any station allocated can be searched by hash list */ -struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) -{ - unsigned long irqL; - struct list_head *plist, *phead; - struct sta_info *psta = NULL; - u32 index; - - if (!hwaddr) - return NULL; - index = wifi_mac_hash(hwaddr); - spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); - phead = &(pstapriv->sta_hash[index]); - plist = phead->next; - while (!end_of_queue_search(phead, plist)) { - psta = container_of(plist, struct sta_info, hash_list); - if ((!memcmp(psta->hwaddr, hwaddr, ETH_ALEN))) { - /* if found the matched address */ - break; - } - psta = NULL; - plist = plist->next; - } - spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); - return psta; -} - -void r8712_init_bcmc_stainfo(struct _adapter *padapter) -{ - unsigned char bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - struct sta_priv *pstapriv = &padapter->stapriv; - - r8712_alloc_stainfo(pstapriv, bcast_addr); -} - -struct sta_info *r8712_get_bcmc_stainfo(struct _adapter *padapter) -{ - struct sta_priv *pstapriv = &padapter->stapriv; - u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - - return r8712_get_stainfo(pstapriv, bc_addr); -} - -u8 r8712_access_ctrl(struct wlan_acl_pool *pacl_list, u8 *mac_addr) -{ - return true; -} diff --git a/drivers/staging/rtl8712/rtl871x_wlan_sme.h b/drivers/staging/rtl8712/rtl871x_wlan_sme.h deleted file mode 100644 index 97ea1451426c05..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_wlan_sme.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL871X_WLAN_SME_H_ -#define _RTL871X_WLAN_SME_H_ - -#define MSR_APMODE 0x0C -#define MSR_STAMODE 0x08 -#define MSR_ADHOCMODE 0x04 -#define MSR_NOLINKMODE 0x00 -#define _1M_RATE_ 0 -#define _2M_RATE_ 1 -#define _5M_RATE_ 2 -#define _11M_RATE_ 3 -#define _6M_RATE_ 4 -#define _9M_RATE_ 5 -#define _12M_RATE_ 6 -#define _18M_RATE_ 7 -#define _24M_RATE_ 8 -#define _36M_RATE_ 9 -#define _48M_RATE_ 10 -#define _54M_RATE_ 11 - -#endif - diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c deleted file mode 100644 index 408616e9afcfff..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_xmit.c +++ /dev/null @@ -1,1056 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * rtl871x_xmit.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _RTL871X_XMIT_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "osdep_intf.h" -#include "usb_ops.h" - -#include -#include - -static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8}; -static const u8 RFC1042_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0x00}; -static void init_hwxmits(struct hw_xmit *phwxmit, sint entry); -static void alloc_hwxmits(struct _adapter *padapter); -static void free_hwxmits(struct _adapter *padapter); - -static void _init_txservq(struct tx_servq *ptxservq) -{ - INIT_LIST_HEAD(&ptxservq->tx_pending); - _init_queue(&ptxservq->sta_pending); - ptxservq->qcnt = 0; -} - -void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) -{ - memset((unsigned char *)psta_xmitpriv, 0, - sizeof(struct sta_xmit_priv)); - spin_lock_init(&psta_xmitpriv->lock); - _init_txservq(&psta_xmitpriv->be_q); - _init_txservq(&psta_xmitpriv->bk_q); - _init_txservq(&psta_xmitpriv->vi_q); - _init_txservq(&psta_xmitpriv->vo_q); - INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); - INIT_LIST_HEAD(&psta_xmitpriv->apsd); -} - -int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv, - struct _adapter *padapter) -{ - sint i; - struct xmit_buf *pxmitbuf; - struct xmit_frame *pxframe; - int j; - - memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); - spin_lock_init(&pxmitpriv->lock); - /* - *Please insert all the queue initialization using _init_queue below - */ - pxmitpriv->adapter = padapter; - _init_queue(&pxmitpriv->be_pending); - _init_queue(&pxmitpriv->bk_pending); - _init_queue(&pxmitpriv->vi_pending); - _init_queue(&pxmitpriv->vo_pending); - _init_queue(&pxmitpriv->bm_pending); - _init_queue(&pxmitpriv->legacy_dz_queue); - _init_queue(&pxmitpriv->apsd_queue); - _init_queue(&pxmitpriv->free_xmit_queue); - /* - * Please allocate memory with sz = (struct xmit_frame) * NR_XMITFRAME, - * and initialize free_xmit_frame below. - * Please also apply free_txobj to link_up all the xmit_frames... - */ - pxmitpriv->pallocated_frame_buf = - kmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4, - GFP_ATOMIC); - if (!pxmitpriv->pallocated_frame_buf) { - pxmitpriv->pxmit_frame_buf = NULL; - return -ENOMEM; - } - pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - - ((addr_t) (pxmitpriv->pallocated_frame_buf) & 3); - pxframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; - for (i = 0; i < NR_XMITFRAME; i++) { - INIT_LIST_HEAD(&(pxframe->list)); - pxframe->padapter = padapter; - pxframe->frame_tag = DATA_FRAMETAG; - pxframe->pkt = NULL; - pxframe->buf_addr = NULL; - pxframe->pxmitbuf = NULL; - list_add_tail(&(pxframe->list), - &(pxmitpriv->free_xmit_queue.queue)); - pxframe++; - } - pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; - /* - * init xmit hw_txqueue - */ - _r8712_init_hw_txqueue(&pxmitpriv->be_txqueue, BE_QUEUE_INX); - _r8712_init_hw_txqueue(&pxmitpriv->bk_txqueue, BK_QUEUE_INX); - _r8712_init_hw_txqueue(&pxmitpriv->vi_txqueue, VI_QUEUE_INX); - _r8712_init_hw_txqueue(&pxmitpriv->vo_txqueue, VO_QUEUE_INX); - _r8712_init_hw_txqueue(&pxmitpriv->bmc_txqueue, BMC_QUEUE_INX); - pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; - pxmitpriv->txirp_cnt = 1; - /*per AC pending irp*/ - pxmitpriv->beq_cnt = 0; - pxmitpriv->bkq_cnt = 0; - pxmitpriv->viq_cnt = 0; - pxmitpriv->voq_cnt = 0; - /*init xmit_buf*/ - _init_queue(&pxmitpriv->free_xmitbuf_queue); - _init_queue(&pxmitpriv->pending_xmitbuf_queue); - pxmitpriv->pxmitbuf = kmalloc(NR_XMITBUFF * sizeof(struct xmit_buf), GFP_ATOMIC); - if (!pxmitpriv->pxmitbuf) - goto clean_up_frame_buf; - pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; - for (i = 0; i < NR_XMITBUFF; i++) { - INIT_LIST_HEAD(&pxmitbuf->list); - pxmitbuf->pallocated_buf = - kmalloc(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ, GFP_ATOMIC); - if (!pxmitbuf->pallocated_buf) { - j = 0; - goto clean_up_alloc_buf; - } - pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ - - ((addr_t) (pxmitbuf->pallocated_buf) & - (XMITBUF_ALIGN_SZ - 1)); - if (r8712_xmit_resource_alloc(padapter, pxmitbuf)) { - j = 1; - goto clean_up_alloc_buf; - } - list_add_tail(&pxmitbuf->list, - &(pxmitpriv->free_xmitbuf_queue.queue)); - pxmitbuf++; - } - pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; - INIT_WORK(&padapter->wk_filter_rx_ff0, r8712_SetFilter); - alloc_hwxmits(padapter); - init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); - tasklet_setup(&pxmitpriv->xmit_tasklet, r8712_xmit_bh); - return 0; - -clean_up_alloc_buf: - if (j) { - /* failure happened in r8712_xmit_resource_alloc() - * delete extra pxmitbuf->pallocated_buf - */ - kfree(pxmitbuf->pallocated_buf); - } - for (j = 0; j < i; j++) { - int k; - - pxmitbuf--; /* reset pointer */ - kfree(pxmitbuf->pallocated_buf); - for (k = 0; k < 8; k++) /* delete xmit urb's */ - usb_free_urb(pxmitbuf->pxmit_urb[k]); - } - kfree(pxmitpriv->pxmitbuf); - pxmitpriv->pxmitbuf = NULL; -clean_up_frame_buf: - kfree(pxmitpriv->pallocated_frame_buf); - pxmitpriv->pallocated_frame_buf = NULL; - return -ENOMEM; -} - -void _free_xmit_priv(struct xmit_priv *pxmitpriv) -{ - int i; - struct _adapter *padapter = pxmitpriv->adapter; - struct xmit_frame *pxmitframe = (struct xmit_frame *) - pxmitpriv->pxmit_frame_buf; - struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; - - if (!pxmitpriv->pxmit_frame_buf) - return; - for (i = 0; i < NR_XMITFRAME; i++) { - r8712_xmit_complete(padapter, pxmitframe); - pxmitframe++; - } - for (i = 0; i < NR_XMITBUFF; i++) { - r8712_xmit_resource_free(padapter, pxmitbuf); - kfree(pxmitbuf->pallocated_buf); - pxmitbuf++; - } - kfree(pxmitpriv->pallocated_frame_buf); - kfree(pxmitpriv->pxmitbuf); - free_hwxmits(padapter); -} - -int r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, - struct pkt_attrib *pattrib) -{ - struct pkt_file pktfile; - struct sta_info *psta = NULL; - struct ethhdr etherhdr; - - struct tx_cmd txdesc; - - bool bmcast; - struct sta_priv *pstapriv = &padapter->stapriv; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct qos_priv *pqospriv = &pmlmepriv->qospriv; - - _r8712_open_pktfile(pkt, &pktfile); - - _r8712_pktfile_read(&pktfile, (unsigned char *)ðerhdr, ETH_HLEN); - - pattrib->ether_type = ntohs(etherhdr.h_proto); - - /* - * If driver xmit ARP packet, driver can set ps mode to initial - * setting. It stands for getting DHCP or fix IP. - */ - if (pattrib->ether_type == 0x0806) { - if (padapter->pwrctrlpriv.pwr_mode != - padapter->registrypriv.power_mgnt) { - del_timer_sync(&pmlmepriv->dhcp_timer); - r8712_set_ps_mode(padapter, - padapter->registrypriv.power_mgnt, - padapter->registrypriv.smart_ps); - } - } - - memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); - memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); - pattrib->pctrl = 0; - if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || - check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); - memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); - } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { - /*firstly, filter packet not belongs to mp*/ - if (pattrib->ether_type != 0x8712) - return -EINVAL; - /* for mp storing the txcmd per packet, - * according to the info of txcmd to update pattrib - */ - /*get MP_TXDESC_SIZE bytes txcmd per packet*/ - _r8712_pktfile_read(&pktfile, (u8 *)&txdesc, TXDESC_SIZE); - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - pattrib->pctrl = 1; - } - /* r8712_xmitframe_coalesce() overwrite this!*/ - pattrib->pktlen = pktfile.pkt_len; - if (pattrib->ether_type == ETH_P_IP) { - /* The following is for DHCP and ARP packet, we use cck1M to - * tx these packets and let LPS awake some time - * to prevent DHCP protocol fail - */ - u8 tmp[24]; - - _r8712_pktfile_read(&pktfile, &tmp[0], 24); - pattrib->dhcp_pkt = 0; - if (pktfile.pkt_len > 282) {/*MINIMUM_DHCP_PACKET_SIZE)*/ - if (pattrib->ether_type == ETH_P_IP) {/* IP header*/ - if (((tmp[21] == 68) && (tmp[23] == 67)) || - ((tmp[21] == 67) && (tmp[23] == 68))) { - /* 68 : UDP BOOTP client - * 67 : UDP BOOTP server - * Use low rate to send DHCP packet. - */ - pattrib->dhcp_pkt = 1; - } - } - } - } - bmcast = is_multicast_ether_addr(pattrib->ra); - /* get sta_info*/ - if (bmcast) { - psta = r8712_get_bcmc_stainfo(padapter); - pattrib->mac_id = 4; - } else { - if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { - psta = r8712_get_stainfo(pstapriv, - get_bssid(pmlmepriv)); - pattrib->mac_id = 5; - } else { - psta = r8712_get_stainfo(pstapriv, pattrib->ra); - if (!psta) /* drop the pkt */ - return -ENOMEM; - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) - pattrib->mac_id = 5; - else - pattrib->mac_id = psta->mac_id; - } - } - - if (psta) { - pattrib->psta = psta; - } else { - /* if we cannot get psta => drrp the pkt */ - return -ENOMEM; - } - - pattrib->ack_policy = 0; - /* get ether_hdr_len */ - pattrib->pkt_hdrlen = ETH_HLEN; - - if (pqospriv->qos_option) { - r8712_set_qos(&pktfile, pattrib); - } else { - pattrib->hdrlen = WLAN_HDR_A3_LEN; - pattrib->subtype = IEEE80211_FTYPE_DATA; - pattrib->priority = 0; - } - if (psta->ieee8021x_blocked) { - pattrib->encrypt = 0; - if ((pattrib->ether_type != 0x888e) && - !check_fwstate(pmlmepriv, WIFI_MP_STATE)) - return -EINVAL; - } else { - GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); - } - switch (pattrib->encrypt) { - case _WEP40_: - case _WEP104_: - pattrib->iv_len = 4; - pattrib->icv_len = 4; - break; - case _TKIP_: - pattrib->iv_len = 8; - pattrib->icv_len = 4; - if (padapter->securitypriv.busetkipkey == _FAIL) - return -EINVAL; - break; - case _AES_: - pattrib->iv_len = 8; - pattrib->icv_len = 8; - break; - default: - pattrib->iv_len = 0; - pattrib->icv_len = 0; - break; - } - - if (pattrib->encrypt && - (padapter->securitypriv.sw_encrypt || - !psecuritypriv->hw_decrypted)) - pattrib->bswenc = true; - else - pattrib->bswenc = false; - /* if in MP_STATE, update pkt_attrib from mp_txcmd, and overwrite - * some settings above. - */ - if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) - pattrib->priority = - (le32_to_cpu(txdesc.txdw1) >> QSEL_SHT) & 0x1f; - return 0; -} - -static int xmitframe_addmic(struct _adapter *padapter, - struct xmit_frame *pxmitframe) -{ - u32 curfragnum, length; - u8 *pframe, *payload, mic[8]; - struct mic_data micdata; - struct sta_info *stainfo; - struct qos_priv *pqospriv = &(padapter->mlmepriv.qospriv); - struct pkt_attrib *pattrib = &pxmitframe->attrib; - struct security_priv *psecpriv = &padapter->securitypriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - u8 priority[4] = {}; - bool bmcst = is_multicast_ether_addr(pattrib->ra); - - if (pattrib->psta) - stainfo = pattrib->psta; - else - stainfo = r8712_get_stainfo(&padapter->stapriv, - &pattrib->ra[0]); - if (pattrib->encrypt == _TKIP_) { - /*encode mic code*/ - if (stainfo) { - u8 null_key[16] = {}; - - pframe = pxmitframe->buf_addr + TXDESC_OFFSET; - if (bmcst) { - if (!memcmp(psecpriv->XGrptxmickey - [psecpriv->XGrpKeyid].skey, - null_key, 16)) - return -ENOMEM; - /*start to calculate the mic code*/ - r8712_secmicsetkey(&micdata, - psecpriv->XGrptxmickey - [psecpriv->XGrpKeyid].skey); - } else { - if (!memcmp(&stainfo->tkiptxmickey.skey[0], - null_key, 16)) - return -ENOMEM; - /* start to calculate the mic code */ - r8712_secmicsetkey(&micdata, - &stainfo->tkiptxmickey.skey[0]); - } - if (pframe[1] & 1) { /* ToDS==1 */ - r8712_secmicappend(&micdata, - &pframe[16], 6); /*DA*/ - if (pframe[1] & 2) /* From Ds==1 */ - r8712_secmicappend(&micdata, - &pframe[24], 6); - else - r8712_secmicappend(&micdata, - &pframe[10], 6); - } else { /* ToDS==0 */ - r8712_secmicappend(&micdata, - &pframe[4], 6); /* DA */ - if (pframe[1] & 2) /* From Ds==1 */ - r8712_secmicappend(&micdata, - &pframe[16], 6); - else - r8712_secmicappend(&micdata, - &pframe[10], 6); - } - if (pqospriv->qos_option == 1) - priority[0] = (u8)pxmitframe->attrib.priority; - r8712_secmicappend(&micdata, &priority[0], 4); - payload = pframe; - for (curfragnum = 0; curfragnum < pattrib->nr_frags; - curfragnum++) { - payload = (u8 *)RND4((addr_t)(payload)); - payload += pattrib->hdrlen + pattrib->iv_len; - if ((curfragnum + 1) == pattrib->nr_frags) { - length = pattrib->last_txcmdsz - - pattrib->hdrlen - - pattrib->iv_len - - ((psecpriv->sw_encrypt) - ? pattrib->icv_len : 0); - r8712_secmicappend(&micdata, payload, - length); - payload = payload + length; - } else { - length = pxmitpriv->frag_len - - pattrib->hdrlen - pattrib->iv_len - - ((psecpriv->sw_encrypt) ? - pattrib->icv_len : 0); - r8712_secmicappend(&micdata, payload, - length); - payload = payload + length + - pattrib->icv_len; - } - } - r8712_secgetmic(&micdata, &(mic[0])); - /* add mic code and add the mic code length in - * last_txcmdsz - */ - memcpy(payload, &(mic[0]), 8); - pattrib->last_txcmdsz += 8; - payload = payload - pattrib->last_txcmdsz + 8; - } - } - return 0; -} - -static sint xmitframe_swencrypt(struct _adapter *padapter, - struct xmit_frame *pxmitframe) -{ - struct pkt_attrib *pattrib = &pxmitframe->attrib; - - if (pattrib->bswenc) { - switch (pattrib->encrypt) { - case _WEP40_: - case _WEP104_: - r8712_wep_encrypt(padapter, (u8 *)pxmitframe); - break; - case _TKIP_: - r8712_tkip_encrypt(padapter, (u8 *)pxmitframe); - break; - case _AES_: - r8712_aes_encrypt(padapter, (u8 *)pxmitframe); - break; - default: - break; - } - } - return _SUCCESS; -} - -static int make_wlanhdr(struct _adapter *padapter, u8 *hdr, - struct pkt_attrib *pattrib) -{ - u16 *qc; - - struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct qos_priv *pqospriv = &pmlmepriv->qospriv; - __le16 *fctrl = &pwlanhdr->frame_control; - u8 *bssid; - - memset(hdr, 0, WLANHDR_OFFSET); - SetFrameSubType(fctrl, pattrib->subtype); - if (!(pattrib->subtype & IEEE80211_FTYPE_DATA)) - return 0; - - bssid = get_bssid(pmlmepriv); - - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { - /* to_ds = 1, fr_ds = 0; */ - SetToDs(fctrl); - ether_addr_copy(pwlanhdr->addr1, bssid); - ether_addr_copy(pwlanhdr->addr2, pattrib->src); - ether_addr_copy(pwlanhdr->addr3, pattrib->dst); - } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { - /* to_ds = 0, fr_ds = 1; */ - SetFrDs(fctrl); - ether_addr_copy(pwlanhdr->addr1, pattrib->dst); - ether_addr_copy(pwlanhdr->addr2, bssid); - ether_addr_copy(pwlanhdr->addr3, pattrib->src); - } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || - check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { - ether_addr_copy(pwlanhdr->addr1, pattrib->dst); - ether_addr_copy(pwlanhdr->addr2, pattrib->src); - ether_addr_copy(pwlanhdr->addr3, bssid); - } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { - ether_addr_copy(pwlanhdr->addr1, pattrib->dst); - ether_addr_copy(pwlanhdr->addr2, pattrib->src); - ether_addr_copy(pwlanhdr->addr3, bssid); - } else { - return -EINVAL; - } - - if (pattrib->encrypt) - SetPrivacy(fctrl); - if (pqospriv->qos_option) { - qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); - if (pattrib->priority) - SetPriority(qc, pattrib->priority); - SetAckpolicy(qc, pattrib->ack_policy); - } - /* TODO: fill HT Control Field */ - /* Update Seq Num will be handled by f/w */ - { - struct sta_info *psta; - bool bmcst = is_multicast_ether_addr(pattrib->ra); - - if (pattrib->psta) - psta = pattrib->psta; - else if (bmcst) - psta = r8712_get_bcmc_stainfo(padapter); - else - psta = r8712_get_stainfo(&padapter->stapriv, - pattrib->ra); - - if (psta) { - u16 *txtid = psta->sta_xmitpriv.txseq_tid; - - txtid[pattrib->priority]++; - txtid[pattrib->priority] &= 0xFFF; - pattrib->seqnum = txtid[pattrib->priority]; - SetSeqNum(hdr, pattrib->seqnum); - } - } - - return 0; -} - -static sint r8712_put_snap(u8 *data, u16 h_proto) -{ - struct ieee80211_snap_hdr *snap; - const u8 *oui; - - snap = (struct ieee80211_snap_hdr *)data; - snap->dsap = 0xaa; - snap->ssap = 0xaa; - snap->ctrl = 0x03; - if (h_proto == 0x8137 || h_proto == 0x80f3) - oui = P802_1H_OUI; - else - oui = RFC1042_OUI; - snap->oui[0] = oui[0]; - snap->oui[1] = oui[1]; - snap->oui[2] = oui[2]; - *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); - return SNAP_SIZE + sizeof(u16); -} - -/* - * This sub-routine will perform all the following: - * 1. remove 802.3 header. - * 2. create wlan_header, based on the info in pxmitframe - * 3. append sta's iv/ext-iv - * 4. append LLC - * 5. move frag chunk from pframe to pxmitframe->mem - * 6. apply sw-encrypt, if necessary. - */ -sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt, - struct xmit_frame *pxmitframe) -{ - struct pkt_file pktfile; - - sint frg_len, mpdu_len, llc_sz; - u32 mem_sz; - u8 frg_inx; - addr_t addr; - u8 *pframe, *mem_start, *ptxdesc; - struct sta_info *psta; - struct security_priv *psecpriv = &padapter->securitypriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - u8 *pbuf_start; - bool bmcst = is_multicast_ether_addr(pattrib->ra); - - if (!pattrib->psta) - return _FAIL; - psta = pattrib->psta; - if (!pxmitframe->buf_addr) - return _FAIL; - pbuf_start = pxmitframe->buf_addr; - ptxdesc = pbuf_start; - mem_start = pbuf_start + TXDESC_OFFSET; - if (make_wlanhdr(padapter, mem_start, pattrib)) - return _FAIL; - _r8712_open_pktfile(pkt, &pktfile); - _r8712_pktfile_read(&pktfile, NULL, (uint) pattrib->pkt_hdrlen); - if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { - /* truncate TXDESC_SIZE bytes txcmd if at mp mode for 871x */ - if (pattrib->ether_type == 0x8712) { - /* take care - update_txdesc overwrite this */ - _r8712_pktfile_read(&pktfile, ptxdesc, TXDESC_SIZE); - } - } - pattrib->pktlen = pktfile.pkt_len; - frg_inx = 0; - frg_len = pxmitpriv->frag_len - 4; - while (1) { - llc_sz = 0; - mpdu_len = frg_len; - pframe = mem_start; - SetMFrag(mem_start); - pframe += pattrib->hdrlen; - mpdu_len -= pattrib->hdrlen; - /* adding icv, if necessary...*/ - if (pattrib->iv_len) { - if (psta) { - switch (pattrib->encrypt) { - case _WEP40_: - case _WEP104_: - WEP_IV(pattrib->iv, psta->txpn, - (u8)psecpriv->PrivacyKeyIndex); - break; - case _TKIP_: - if (bmcst) - TKIP_IV(pattrib->iv, - psta->txpn, - (u8)psecpriv->XGrpKeyid); - else - TKIP_IV(pattrib->iv, psta->txpn, - 0); - break; - case _AES_: - if (bmcst) - AES_IV(pattrib->iv, psta->txpn, - (u8)psecpriv->XGrpKeyid); - else - AES_IV(pattrib->iv, psta->txpn, - 0); - break; - } - } - memcpy(pframe, pattrib->iv, pattrib->iv_len); - pframe += pattrib->iv_len; - mpdu_len -= pattrib->iv_len; - } - if (frg_inx == 0) { - llc_sz = r8712_put_snap(pframe, pattrib->ether_type); - pframe += llc_sz; - mpdu_len -= llc_sz; - } - if ((pattrib->icv_len > 0) && (pattrib->bswenc)) - mpdu_len -= pattrib->icv_len; - if (bmcst) - mem_sz = _r8712_pktfile_read(&pktfile, pframe, - pattrib->pktlen); - else - mem_sz = _r8712_pktfile_read(&pktfile, pframe, - mpdu_len); - pframe += mem_sz; - if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { - memcpy(pframe, pattrib->icv, pattrib->icv_len); - pframe += pattrib->icv_len; - } - frg_inx++; - if (bmcst || r8712_endofpktfile(&pktfile)) { - pattrib->nr_frags = frg_inx; - pattrib->last_txcmdsz = pattrib->hdrlen + - pattrib->iv_len + - ((pattrib->nr_frags == 1) ? - llc_sz : 0) + - ((pattrib->bswenc) ? - pattrib->icv_len : 0) + mem_sz; - ClearMFrag(mem_start); - break; - } - addr = (addr_t)(pframe); - mem_start = (unsigned char *)RND4(addr) + TXDESC_OFFSET; - memcpy(mem_start, pbuf_start + TXDESC_OFFSET, pattrib->hdrlen); - } - - if (xmitframe_addmic(padapter, pxmitframe)) - return _FAIL; - xmitframe_swencrypt(padapter, pxmitframe); - return _SUCCESS; -} - -void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len) -{ - uint protection; - u8 *perp; - uint erp_len; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct registry_priv *pregistrypriv = &padapter->registrypriv; - - switch (pxmitpriv->vcs_setting) { - case DISABLE_VCS: - pxmitpriv->vcs = NONE_VCS; - break; - case ENABLE_VCS: - break; - case AUTO_VCS: - default: - perp = r8712_get_ie(ie, WLAN_EID_ERP_INFO, &erp_len, ie_len); - if (!perp) { - pxmitpriv->vcs = NONE_VCS; - } else { - protection = (*(perp + 2)) & BIT(1); - if (protection) { - if (pregistrypriv->vcs_type == RTS_CTS) - pxmitpriv->vcs = RTS_CTS; - else - pxmitpriv->vcs = CTS_TO_SELF; - } else { - pxmitpriv->vcs = NONE_VCS; - } - } - break; - } -} - -struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv) -{ - unsigned long irqL; - struct xmit_buf *pxmitbuf; - struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; - - spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); - pxmitbuf = list_first_entry_or_null(&pfree_xmitbuf_queue->queue, - struct xmit_buf, list); - if (pxmitbuf) { - list_del_init(&pxmitbuf->list); - pxmitpriv->free_xmitbuf_cnt--; - } - spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); - return pxmitbuf; -} - -void r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) -{ - unsigned long irqL; - struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; - - if (!pxmitbuf) - return; - spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL); - list_del_init(&pxmitbuf->list); - list_add_tail(&(pxmitbuf->list), &pfree_xmitbuf_queue->queue); - pxmitpriv->free_xmitbuf_cnt++; - spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL); -} - -/* - * Calling context: - * 1. OS_TXENTRY - * 2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) - * - * If we turn on USE_RXTHREAD, then, no need for critical section. - * Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... - * - * Must be very very cautious... - * - */ -struct xmit_frame *r8712_alloc_xmitframe(struct xmit_priv *pxmitpriv) -{ - /* - * Please remember to use all the osdep_service api, - * and lock/unlock or _enter/_exit critical to protect - * pfree_xmit_queue - */ - unsigned long irqL; - struct xmit_frame *pxframe; - struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; - - spin_lock_irqsave(&pfree_xmit_queue->lock, irqL); - pxframe = list_first_entry_or_null(&pfree_xmit_queue->queue, - struct xmit_frame, list); - if (pxframe) { - list_del_init(&pxframe->list); - pxmitpriv->free_xmitframe_cnt--; - pxframe->buf_addr = NULL; - pxframe->pxmitbuf = NULL; - pxframe->attrib.psta = NULL; - pxframe->pkt = NULL; - } - spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL); - return pxframe; -} - -void r8712_free_xmitframe(struct xmit_priv *pxmitpriv, - struct xmit_frame *pxmitframe) -{ - unsigned long irqL; - struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; - struct _adapter *padapter = pxmitpriv->adapter; - - if (!pxmitframe) - return; - spin_lock_irqsave(&pfree_xmit_queue->lock, irqL); - list_del_init(&pxmitframe->list); - if (pxmitframe->pkt) - pxmitframe->pkt = NULL; - list_add_tail(&pxmitframe->list, &pfree_xmit_queue->queue); - pxmitpriv->free_xmitframe_cnt++; - spin_unlock_irqrestore(&pfree_xmit_queue->lock, irqL); - if (netif_queue_stopped(padapter->pnetdev)) - netif_wake_queue(padapter->pnetdev); -} - -void r8712_free_xmitframe_ex(struct xmit_priv *pxmitpriv, - struct xmit_frame *pxmitframe) -{ - if (!pxmitframe) - return; - if (pxmitframe->frame_tag == DATA_FRAMETAG) - r8712_free_xmitframe(pxmitpriv, pxmitframe); -} - -void r8712_free_xmitframe_queue(struct xmit_priv *pxmitpriv, - struct __queue *pframequeue) -{ - unsigned long irqL; - struct list_head *plist, *phead; - struct xmit_frame *pxmitframe; - - spin_lock_irqsave(&(pframequeue->lock), irqL); - phead = &pframequeue->queue; - plist = phead->next; - while (!end_of_queue_search(phead, plist)) { - pxmitframe = container_of(plist, struct xmit_frame, list); - plist = plist->next; - r8712_free_xmitframe(pxmitpriv, pxmitframe); - } - spin_unlock_irqrestore(&(pframequeue->lock), irqL); -} - -static inline struct tx_servq *get_sta_pending(struct _adapter *padapter, - struct __queue **ppstapending, - struct sta_info *psta, sint up) -{ - struct tx_servq *ptxservq; - struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; - - switch (up) { - case 1: - case 2: - ptxservq = &(psta->sta_xmitpriv.bk_q); - *ppstapending = &padapter->xmitpriv.bk_pending; - (phwxmits + 3)->accnt++; - break; - case 4: - case 5: - ptxservq = &(psta->sta_xmitpriv.vi_q); - *ppstapending = &padapter->xmitpriv.vi_pending; - (phwxmits + 1)->accnt++; - break; - case 6: - case 7: - ptxservq = &(psta->sta_xmitpriv.vo_q); - *ppstapending = &padapter->xmitpriv.vo_pending; - (phwxmits + 0)->accnt++; - break; - case 0: - case 3: - default: - ptxservq = &(psta->sta_xmitpriv.be_q); - *ppstapending = &padapter->xmitpriv.be_pending; - (phwxmits + 2)->accnt++; - break; - } - return ptxservq; -} - -/* - * Will enqueue pxmitframe to the proper queue, and indicate it - * to xx_pending list..... - */ -int r8712_xmit_classifier(struct _adapter *padapter, - struct xmit_frame *pxmitframe) -{ - unsigned long irqL0; - struct __queue *pstapending; - struct sta_info *psta; - struct tx_servq *ptxservq; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - struct sta_priv *pstapriv = &padapter->stapriv; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - bool bmcst = is_multicast_ether_addr(pattrib->ra); - - if (pattrib->psta) { - psta = pattrib->psta; - } else { - if (bmcst) { - psta = r8712_get_bcmc_stainfo(padapter); - } else { - if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) - psta = r8712_get_stainfo(pstapriv, - get_bssid(pmlmepriv)); - else - psta = r8712_get_stainfo(pstapriv, pattrib->ra); - } - } - if (!psta) - return -EINVAL; - ptxservq = get_sta_pending(padapter, &pstapending, - psta, pattrib->priority); - spin_lock_irqsave(&pstapending->lock, irqL0); - if (list_empty(&ptxservq->tx_pending)) - list_add_tail(&ptxservq->tx_pending, &pstapending->queue); - list_add_tail(&pxmitframe->list, &ptxservq->sta_pending.queue); - ptxservq->qcnt++; - spin_unlock_irqrestore(&pstapending->lock, irqL0); - return 0; -} - -static void alloc_hwxmits(struct _adapter *padapter) -{ - struct hw_xmit *hwxmits; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - - pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; - pxmitpriv->hwxmits = kmalloc_array(pxmitpriv->hwxmit_entry, - sizeof(struct hw_xmit), GFP_ATOMIC); - if (!pxmitpriv->hwxmits) - return; - hwxmits = pxmitpriv->hwxmits; - if (pxmitpriv->hwxmit_entry == 5) { - pxmitpriv->bmc_txqueue.head = 0; - hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; - hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; - pxmitpriv->vo_txqueue.head = 0; - hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; - hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; - pxmitpriv->vi_txqueue.head = 0; - hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; - hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; - pxmitpriv->bk_txqueue.head = 0; - hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; - hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; - pxmitpriv->be_txqueue.head = 0; - hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; - hwxmits[4] .sta_queue = &pxmitpriv->be_pending; - } else if (pxmitpriv->hwxmit_entry == 4) { - pxmitpriv->vo_txqueue.head = 0; - hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; - hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; - pxmitpriv->vi_txqueue.head = 0; - hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; - hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; - pxmitpriv->be_txqueue.head = 0; - hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; - hwxmits[2] .sta_queue = &pxmitpriv->be_pending; - pxmitpriv->bk_txqueue.head = 0; - hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; - hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; - } -} - -static void free_hwxmits(struct _adapter *padapter) -{ - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - - kfree(pxmitpriv->hwxmits); -} - -static void init_hwxmits(struct hw_xmit *phwxmit, sint entry) -{ - sint i; - - for (i = 0; i < entry; i++, phwxmit++) { - spin_lock_init(&phwxmit->xmit_lock); - INIT_LIST_HEAD(&phwxmit->pending); - phwxmit->txcmdcnt = 0; - phwxmit->accnt = 0; - } -} - -void xmitframe_xmitbuf_attach(struct xmit_frame *pxmitframe, - struct xmit_buf *pxmitbuf) -{ - /* pxmitbuf attach to pxmitframe */ - pxmitframe->pxmitbuf = pxmitbuf; - /* urb and irp connection */ - pxmitframe->pxmit_urb[0] = pxmitbuf->pxmit_urb[0]; - /* buffer addr assoc */ - pxmitframe->buf_addr = pxmitbuf->pbuf; - /* pxmitframe attach to pxmitbuf */ - pxmitbuf->priv_data = pxmitframe; -} - -/* - * tx_action == 0 == no frames to transmit - * tx_action > 0 ==> we have frames to transmit - * tx_action < 0 ==> we have frames to transmit, but TXFF is not even enough - * to transmit 1 frame. - */ - -int r8712_pre_xmit(struct _adapter *padapter, struct xmit_frame *pxmitframe) -{ - unsigned long irqL; - int ret; - struct xmit_buf *pxmitbuf = NULL; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - - r8712_do_queue_select(padapter, pattrib); - spin_lock_irqsave(&pxmitpriv->lock, irqL); - if (r8712_txframes_sta_ac_pending(padapter, pattrib) > 0) { - ret = false; - r8712_xmit_enqueue(padapter, pxmitframe); - spin_unlock_irqrestore(&pxmitpriv->lock, irqL); - return ret; - } - pxmitbuf = r8712_alloc_xmitbuf(pxmitpriv); - if (!pxmitbuf) { /*enqueue packet*/ - ret = false; - r8712_xmit_enqueue(padapter, pxmitframe); - spin_unlock_irqrestore(&pxmitpriv->lock, irqL); - } else { /*dump packet directly*/ - spin_unlock_irqrestore(&pxmitpriv->lock, irqL); - ret = true; - xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf); - r8712_xmit_direct(padapter, pxmitframe); - } - return ret; -} diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h deleted file mode 100644 index 784172c385e37c..00000000000000 --- a/drivers/staging/rtl8712/rtl871x_xmit.h +++ /dev/null @@ -1,287 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _RTL871X_XMIT_H_ -#define _RTL871X_XMIT_H_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "xmit_osdep.h" - -#ifdef CONFIG_R8712_TX_AGGR -#define MAX_XMITBUF_SZ (16384) -#else -#define MAX_XMITBUF_SZ (2048) -#endif - -#define NR_XMITBUFF (4) - -#ifdef CONFIG_R8712_TX_AGGR -#define AGGR_NR_HIGH_BOUND (4) /*(8) */ -#define AGGR_NR_LOW_BOUND (2) -#endif - -#define XMITBUF_ALIGN_SZ 512 -#define TX_GUARD_BAND 5 -#define MAX_NUMBLKS (1) - -/* Fixed the Big Endian bug when using the software driver encryption.*/ -#define WEP_IV(pattrib_iv, txpn, keyidx)\ -do { \ - pattrib_iv[0] = txpn._byte_.TSC0;\ - pattrib_iv[1] = txpn._byte_.TSC1;\ - pattrib_iv[2] = txpn._byte_.TSC2;\ - pattrib_iv[3] = ((keyidx & 0x3) << 6);\ - txpn.val = (txpn.val == 0xffffff) ? 0 : (txpn.val + 1);\ -} while (0) - -/* Fixed the Big Endian bug when doing the Tx. - * The Linksys WRH54G will check this. - */ -#define TKIP_IV(pattrib_iv, txpn, keyidx)\ -do { \ - pattrib_iv[0] = txpn._byte_.TSC1;\ - pattrib_iv[1] = (txpn._byte_.TSC1 | 0x20) & 0x7f;\ - pattrib_iv[2] = txpn._byte_.TSC0;\ - pattrib_iv[3] = BIT(5) | ((keyidx & 0x3) << 6);\ - pattrib_iv[4] = txpn._byte_.TSC2;\ - pattrib_iv[5] = txpn._byte_.TSC3;\ - pattrib_iv[6] = txpn._byte_.TSC4;\ - pattrib_iv[7] = txpn._byte_.TSC5;\ - txpn.val = txpn.val == 0xffffffffffffULL ? 0 : \ - (txpn.val + 1);\ -} while (0) - -#define AES_IV(pattrib_iv, txpn, keyidx)\ -do { \ - pattrib_iv[0] = txpn._byte_.TSC0;\ - pattrib_iv[1] = txpn._byte_.TSC1;\ - pattrib_iv[2] = 0;\ - pattrib_iv[3] = BIT(5) | ((keyidx & 0x3) << 6);\ - pattrib_iv[4] = txpn._byte_.TSC2;\ - pattrib_iv[5] = txpn._byte_.TSC3;\ - pattrib_iv[6] = txpn._byte_.TSC4;\ - pattrib_iv[7] = txpn._byte_.TSC5;\ - txpn.val = txpn.val == 0xffffffffffffULL ? 0 : \ - (txpn.val + 1);\ -} while (0) - -struct hw_xmit { - spinlock_t xmit_lock; - struct list_head pending; - struct __queue *sta_queue; - struct hw_txqueue *phwtxqueue; - sint txcmdcnt; - int accnt; -}; - -struct pkt_attrib { - u8 type; - u8 subtype; - u8 bswenc; - u8 dhcp_pkt; - - u16 seqnum; - u16 ether_type; - u16 pktlen; /* the original 802.3 pkt raw_data len - * (not include ether_hdr data) - */ - u16 last_txcmdsz; - - u8 pkt_hdrlen; /*the original 802.3 pkt header len*/ - u8 hdrlen; /*the WLAN Header Len*/ - u8 nr_frags; - u8 ack_policy; - u8 mac_id; - u8 vcs_mode; /*virtual carrier sense method*/ - u8 pctrl;/*per packet txdesc control enable*/ - u8 qsel; - - u8 priority; - u8 encrypt; /* when 0 indicate no encrypt. when non-zero, - * indicate the encrypt algorithm - */ - u8 iv_len; - u8 icv_len; - unsigned char iv[8]; - unsigned char icv[8]; - u8 dst[ETH_ALEN] __aligned(2); /* for ether_addr_copy */ - u8 src[ETH_ALEN]; - u8 ta[ETH_ALEN]; - u8 ra[ETH_ALEN]; - struct sta_info *psta; -}; - -#define WLANHDR_OFFSET 64 -#define DATA_FRAMETAG 0x01 -#define L2_FRAMETAG 0x02 -#define MGNT_FRAMETAG 0x03 -#define AMSDU_FRAMETAG 0x04 -#define EII_FRAMETAG 0x05 -#define IEEE8023_FRAMETAG 0x06 -#define MP_FRAMETAG 0x07 -#define TXAGG_FRAMETAG 0x08 - -struct xmit_buf { - struct list_head list; - - u8 *pallocated_buf; - u8 *pbuf; - void *priv_data; - struct urb *pxmit_urb[8]; - u32 aggr_nr; -}; - -struct xmit_frame { - struct list_head list; - struct pkt_attrib attrib; - _pkt *pkt; - int frame_tag; - struct _adapter *padapter; - u8 *buf_addr; - struct xmit_buf *pxmitbuf; - u8 *mem_addr; - u16 sz[8]; - struct urb *pxmit_urb[8]; - u8 bpending[8]; - u8 last[8]; -}; - -struct tx_servq { - struct list_head tx_pending; - struct __queue sta_pending; - int qcnt; -}; - -struct sta_xmit_priv { - spinlock_t lock; - sint option; - sint apsd_setting; /* When bit mask is on, the associated edca - * queue supports APSD. - */ - struct tx_servq be_q; /* priority == 0,3 */ - struct tx_servq bk_q; /* priority == 1,2*/ - struct tx_servq vi_q; /*priority == 4,5*/ - struct tx_servq vo_q; /*priority == 6,7*/ - struct list_head legacy_dz; - struct list_head apsd; - u16 txseq_tid[16]; - uint sta_tx_bytes; - u64 sta_tx_pkts; - uint sta_tx_fail; -}; - -struct hw_txqueue { - sint head; - sint tail; - sint free_sz; /* in units of 64 bytes */ - sint free_cmdsz; - sint txsz[8]; - uint ff_hwaddr; - uint cmd_hwaddr; - sint ac_tag; -}; - -struct xmit_priv { - spinlock_t lock; - struct __queue be_pending; - struct __queue bk_pending; - struct __queue vi_pending; - struct __queue vo_pending; - struct __queue bm_pending; - struct __queue legacy_dz_queue; - struct __queue apsd_queue; - u8 *pallocated_frame_buf; - u8 *pxmit_frame_buf; - uint free_xmitframe_cnt; - uint mapping_addr; - uint pkt_sz; - struct __queue free_xmit_queue; - struct hw_txqueue be_txqueue; - struct hw_txqueue bk_txqueue; - struct hw_txqueue vi_txqueue; - struct hw_txqueue vo_txqueue; - struct hw_txqueue bmc_txqueue; - uint frag_len; - struct _adapter *adapter; - u8 vcs_setting; - u8 vcs; - u8 vcs_type; - u16 rts_thresh; - uint tx_bytes; - u64 tx_pkts; - uint tx_drop; - struct hw_xmit *hwxmits; - u8 hwxmit_entry; - u8 txirp_cnt; - struct tasklet_struct xmit_tasklet; - struct work_struct xmit_pipe4_reset_wi; - struct work_struct xmit_pipe6_reset_wi; - struct work_struct xmit_piped_reset_wi; - /*per AC pending irp*/ - int beq_cnt; - int bkq_cnt; - int viq_cnt; - int voq_cnt; - struct __queue free_amsdu_xmit_queue; - u8 *pallocated_amsdu_frame_buf; - u8 *pxmit_amsdu_frame_buf; - uint free_amsdu_xmitframe_cnt; - struct __queue free_txagg_xmit_queue; - u8 *pallocated_txagg_frame_buf; - u8 *pxmit_txagg_frame_buf; - uint free_txagg_xmitframe_cnt; - int cmdseq; - struct __queue free_xmitbuf_queue; - struct __queue pending_xmitbuf_queue; - u8 *pxmitbuf; - uint free_xmitbuf_cnt; -}; - -void r8712_free_xmitbuf(struct xmit_priv *pxmitpriv, - struct xmit_buf *pxmitbuf); -struct xmit_buf *r8712_alloc_xmitbuf(struct xmit_priv *pxmitpriv); -void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len); -struct xmit_frame *r8712_alloc_xmitframe(struct xmit_priv *pxmitpriv); -void r8712_free_xmitframe(struct xmit_priv *pxmitpriv, - struct xmit_frame *pxmitframe); -void r8712_free_xmitframe_queue(struct xmit_priv *pxmitpriv, - struct __queue *pframequeue); -int r8712_xmit_classifier(struct _adapter *padapter, - struct xmit_frame *pxmitframe); -sint r8712_xmitframe_coalesce(struct _adapter *padapter, _pkt *pkt, - struct xmit_frame *pxmitframe); -sint _r8712_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag); -void _r8712_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv); -int r8712_update_attrib(struct _adapter *padapter, _pkt *pkt, - struct pkt_attrib *pattrib); -int r8712_txframes_sta_ac_pending(struct _adapter *padapter, - struct pkt_attrib *pattrib); -int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv, - struct _adapter *padapter); -void _free_xmit_priv(struct xmit_priv *pxmitpriv); -void r8712_free_xmitframe_ex(struct xmit_priv *pxmitpriv, - struct xmit_frame *pxmitframe); -int r8712_pre_xmit(struct _adapter *padapter, struct xmit_frame *pxmitframe); -int r8712_xmit_enqueue(struct _adapter *padapter, - struct xmit_frame *pxmitframe); -void r8712_xmit_direct(struct _adapter *padapter, struct xmit_frame *pxmitframe); -void r8712_xmit_bh(struct tasklet_struct *t); - -void xmitframe_xmitbuf_attach(struct xmit_frame *pxmitframe, - struct xmit_buf *pxmitbuf); - -#include "rtl8712_xmit.h" - -#endif /*_RTL871X_XMIT_H_*/ - diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h deleted file mode 100644 index 6286c622475e59..00000000000000 --- a/drivers/staging/rtl8712/sta_info.h +++ /dev/null @@ -1,132 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __STA_INFO_H_ -#define __STA_INFO_H_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "wifi.h" - -#define NUM_STA 32 -#define NUM_ACL 64 - -/* if mode ==0, then the sta is allowed once the addr is hit. - * if mode ==1, then the sta is rejected once the addr is non-hit. - */ -struct wlan_acl_node { - struct list_head list; - u8 addr[ETH_ALEN]; - u8 mode; -}; - -struct wlan_acl_pool { - struct wlan_acl_node aclnode[NUM_ACL]; -}; - -struct stainfo_stats { - uint rx_pkts; - uint rx_bytes; - u64 tx_pkts; - uint tx_bytes; -}; - -struct sta_info { - spinlock_t lock; - struct list_head list; /*free_sta_queue*/ - struct list_head hash_list; /*sta_hash*/ - struct sta_xmit_priv sta_xmitpriv; - struct sta_recv_priv sta_recvpriv; - uint state; - uint aid; - uint mac_id; - uint qos_option; - u8 hwaddr[ETH_ALEN]; - uint ieee8021x_blocked; /*0: allowed, 1:blocked */ - uint XPrivacy; /*aes, tkip...*/ - union Keytype tkiptxmickey; - union Keytype tkiprxmickey; - union Keytype x_UncstKey; - union pn48 txpn; /* PN48 used for Unicast xmit.*/ - union pn48 rxpn; /* PN48 used for Unicast recv.*/ - u8 bssrateset[16]; - uint bssratelen; - s32 rssi; - s32 signal_quality; - struct stainfo_stats sta_stats; - /*for A-MPDU Rx reordering buffer control */ - struct recv_reorder_ctrl recvreorder_ctrl[16]; - struct ht_priv htpriv; - /* Notes: - * STA_Mode: - * curr_network(mlme_priv/security_priv/qos/ht) - * + sta_info: (STA & AP) CAP/INFO - * scan_q: AP CAP/INFO - * AP_Mode: - * curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO - * sta_info: (AP & STA) CAP/INFO - */ - struct list_head asoc_list; - struct list_head auth_list; - unsigned int expire_to; - unsigned int auth_seq; - unsigned int authalg; - unsigned char chg_txt[128]; - unsigned int tx_ra_bitmap; -}; - -struct sta_priv { - u8 *pallocated_stainfo_buf; - u8 *pstainfo_buf; - struct __queue free_sta_queue; - spinlock_t sta_hash_lock; - struct list_head sta_hash[NUM_STA]; - int asoc_sta_count; - struct __queue sleep_q; - struct __queue wakeup_q; - struct _adapter *padapter; - struct list_head asoc_list; - struct list_head auth_list; - unsigned int auth_to; /* sec, time to expire in authenticating. */ - unsigned int assoc_to; /* sec, time to expire before associating. */ - unsigned int expire_to; /* sec , time to expire after associated. */ -}; - -static inline u32 wifi_mac_hash(u8 *mac) -{ - u32 x; - - x = mac[0]; - x = (x << 2) ^ mac[1]; - x = (x << 2) ^ mac[2]; - x = (x << 2) ^ mac[3]; - x = (x << 2) ^ mac[4]; - x = (x << 2) ^ mac[5]; - x ^= x >> 8; - x = x & (NUM_STA - 1); - return x; -} - -int _r8712_init_sta_priv(struct sta_priv *pstapriv); -void _r8712_free_sta_priv(struct sta_priv *pstapriv); -struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, - u8 *hwaddr); -void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta); -void r8712_free_all_stainfo(struct _adapter *padapter); -struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr); -void r8712_init_bcmc_stainfo(struct _adapter *padapter); -struct sta_info *r8712_get_bcmc_stainfo(struct _adapter *padapter); -u8 r8712_access_ctrl(struct wlan_acl_pool *pacl_list, u8 *mac_addr); - -#endif /* _STA_INFO_H_ */ - diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c deleted file mode 100644 index 313c569748e99b..00000000000000 --- a/drivers/staging/rtl8712/usb_halinit.c +++ /dev/null @@ -1,307 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * usb_halinit.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _HCI_HAL_INIT_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "usb_ops.h" -#include "usb_osintf.h" - -u8 r8712_usb_hal_bus_init(struct _adapter *adapter) -{ - u8 val8 = 0; - u8 ret = _SUCCESS; - int PollingCnt = 20; - struct registry_priv *registrypriv = &adapter->registrypriv; - - if (registrypriv->chip_version == RTL8712_FPGA) { - val8 = 0x01; - /* switch to 80M clock */ - r8712_write8(adapter, SYS_CLKR, val8); - val8 = r8712_read8(adapter, SPS1_CTRL); - val8 = val8 | 0x01; - /* enable VSPS12 LDO Macro block */ - r8712_write8(adapter, SPS1_CTRL, val8); - val8 = r8712_read8(adapter, AFE_MISC); - val8 = val8 | 0x01; - /* Enable AFE Macro Block's Bandgap */ - r8712_write8(adapter, AFE_MISC, val8); - val8 = r8712_read8(adapter, LDOA15_CTRL); - val8 = val8 | 0x01; - /* enable LDOA15 block */ - r8712_write8(adapter, LDOA15_CTRL, val8); - val8 = r8712_read8(adapter, SPS1_CTRL); - val8 = val8 | 0x02; - /* Enable VSPS12_SW Macro Block */ - r8712_write8(adapter, SPS1_CTRL, val8); - val8 = r8712_read8(adapter, AFE_MISC); - val8 = val8 | 0x02; - /* Enable AFE Macro Block's Mbias */ - r8712_write8(adapter, AFE_MISC, val8); - val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1); - val8 = val8 | 0x08; - /* isolate PCIe Analog 1.2V to PCIe 3.3V and PCIE Digital */ - r8712_write8(adapter, SYS_ISO_CTRL + 1, val8); - val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1); - val8 = val8 & 0xEF; - /* attach AFE PLL to MACTOP/BB/PCIe Digital */ - r8712_write8(adapter, SYS_ISO_CTRL + 1, val8); - val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1); - val8 = val8 & 0xFB; - /* enable AFE clock */ - r8712_write8(adapter, AFE_XTAL_CTRL + 1, val8); - val8 = r8712_read8(adapter, AFE_PLL_CTRL); - val8 = val8 | 0x01; - /* Enable AFE PLL Macro Block */ - r8712_write8(adapter, AFE_PLL_CTRL, val8); - val8 = 0xEE; - /* release isolation AFE PLL & MD */ - r8712_write8(adapter, SYS_ISO_CTRL, val8); - val8 = r8712_read8(adapter, SYS_CLKR + 1); - val8 = val8 | 0x08; - /* enable MAC clock */ - r8712_write8(adapter, SYS_CLKR + 1, val8); - val8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - val8 = val8 | 0x08; - /* enable Core digital and enable IOREG R/W */ - r8712_write8(adapter, SYS_FUNC_EN + 1, val8); - val8 = val8 | 0x80; - /* enable REG_EN */ - r8712_write8(adapter, SYS_FUNC_EN + 1, val8); - val8 = r8712_read8(adapter, SYS_CLKR + 1); - val8 = (val8 | 0x80) & 0xBF; - /* switch the control path */ - r8712_write8(adapter, SYS_CLKR + 1, val8); - val8 = 0xFC; - r8712_write8(adapter, CR, val8); - val8 = 0x37; - r8712_write8(adapter, CR + 1, val8); - /* reduce EndPoint & init it */ - r8712_write8(adapter, 0x102500ab, r8712_read8(adapter, - 0x102500ab) | BIT(6) | BIT(7)); - /* consideration of power consumption - init */ - r8712_write8(adapter, 0x10250008, r8712_read8(adapter, - 0x10250008) & 0xfffffffb); - } else if (registrypriv->chip_version == RTL8712_1stCUT) { - /* Initialization for power on sequence, */ - r8712_write8(adapter, SPS0_CTRL + 1, 0x53); - r8712_write8(adapter, SPS0_CTRL, 0x57); - /* Enable AFE Macro Block's Bandgap and Enable AFE Macro - * Block's Mbias - */ - val8 = r8712_read8(adapter, AFE_MISC); - r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN | - AFE_MISC_MBEN)); - /* Enable LDOA15 block */ - val8 = r8712_read8(adapter, LDOA15_CTRL); - r8712_write8(adapter, LDOA15_CTRL, (val8 | LDA15_EN)); - val8 = r8712_read8(adapter, SPS1_CTRL); - r8712_write8(adapter, SPS1_CTRL, (val8 | SPS1_LDEN)); - msleep(20); - /* Enable Switch Regulator Block */ - val8 = r8712_read8(adapter, SPS1_CTRL); - r8712_write8(adapter, SPS1_CTRL, (val8 | SPS1_SWEN)); - r8712_write32(adapter, SPS1_CTRL, 0x00a7b267); - val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1); - r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 | 0x08)); - /* Engineer Packet CP test Enable */ - val8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x20)); - val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1); - r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 & 0x6F)); - /* Enable AFE clock */ - val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1); - r8712_write8(adapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb)); - /* Enable AFE PLL Macro Block */ - val8 = r8712_read8(adapter, AFE_PLL_CTRL); - r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11)); - /* Attach AFE PLL to MACTOP/BB/PCIe Digital */ - val8 = r8712_read8(adapter, SYS_ISO_CTRL); - r8712_write8(adapter, SYS_ISO_CTRL, (val8 & 0xEE)); - /* Switch to 40M clock */ - val8 = r8712_read8(adapter, SYS_CLKR); - r8712_write8(adapter, SYS_CLKR, val8 & (~SYS_CLKSEL)); - /* SSC Disable */ - val8 = r8712_read8(adapter, SYS_CLKR); - /* Enable MAC clock */ - val8 = r8712_read8(adapter, SYS_CLKR + 1); - r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x18)); - /* Revised POS, */ - r8712_write8(adapter, PMC_FSM, 0x02); - /* Enable Core digital and enable IOREG R/W */ - val8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x08)); - /* Enable REG_EN */ - val8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x80)); - /* Switch the control path to FW */ - val8 = r8712_read8(adapter, SYS_CLKR + 1); - r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF); - r8712_write8(adapter, CR, 0xFC); - r8712_write8(adapter, CR + 1, 0x37); - /* Fix the RX FIFO issue(usb error), */ - val8 = r8712_read8(adapter, 0x1025FE5c); - r8712_write8(adapter, 0x1025FE5c, (val8 | BIT(7))); - val8 = r8712_read8(adapter, 0x102500ab); - r8712_write8(adapter, 0x102500ab, (val8 | BIT(6) | BIT(7))); - /* For power save, used this in the bit file after 970621 */ - val8 = r8712_read8(adapter, SYS_CLKR); - r8712_write8(adapter, SYS_CLKR, val8 & (~CPU_CLKSEL)); - } else if (registrypriv->chip_version == RTL8712_2ndCUT || - registrypriv->chip_version == RTL8712_3rdCUT) { - /* Initialization for power on sequence, - * E-Fuse leakage prevention sequence - */ - r8712_write8(adapter, 0x37, 0xb0); - msleep(20); - r8712_write8(adapter, 0x37, 0x30); - /* Set control path switch to HW control and reset Digital Core, - * CPU Core and MAC I/O to solve FW download fail when system - * from resume sate. - */ - val8 = r8712_read8(adapter, SYS_CLKR + 1); - if (val8 & 0x80) { - val8 &= 0x3f; - r8712_write8(adapter, SYS_CLKR + 1, val8); - } - val8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - val8 &= 0x73; - r8712_write8(adapter, SYS_FUNC_EN + 1, val8); - msleep(20); - /* Revised POS, */ - /* Enable AFE Macro Block's Bandgap and Enable AFE Macro - * Block's Mbias - */ - r8712_write8(adapter, SPS0_CTRL + 1, 0x53); - r8712_write8(adapter, SPS0_CTRL, 0x57); - val8 = r8712_read8(adapter, AFE_MISC); - /*Bandgap*/ - r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN)); - r8712_write8(adapter, AFE_MISC, (val8 | AFE_MISC_BGEN | - AFE_MISC_MBEN | AFE_MISC_I32_EN)); - /* Enable PLL Power (LDOA15V) */ - val8 = r8712_read8(adapter, LDOA15_CTRL); - r8712_write8(adapter, LDOA15_CTRL, (val8 | LDA15_EN)); - /* Enable LDOV12D block */ - val8 = r8712_read8(adapter, LDOV12D_CTRL); - r8712_write8(adapter, LDOV12D_CTRL, (val8 | LDV12_EN)); - val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1); - r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 | 0x08)); - /* Engineer Packet CP test Enable */ - val8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x20)); - /* Support 64k IMEM */ - val8 = r8712_read8(adapter, SYS_ISO_CTRL + 1); - r8712_write8(adapter, SYS_ISO_CTRL + 1, (val8 & 0x68)); - /* Enable AFE clock */ - val8 = r8712_read8(adapter, AFE_XTAL_CTRL + 1); - r8712_write8(adapter, AFE_XTAL_CTRL + 1, (val8 & 0xfb)); - /* Enable AFE PLL Macro Block */ - val8 = r8712_read8(adapter, AFE_PLL_CTRL); - r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11)); - /* Some sample will download fw failure. The clock will be - * stable with 500 us delay after reset the PLL - * TODO: When usleep is added to kernel, change next 3 - * udelay(500) to usleep(500) - */ - udelay(500); - r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x51)); - udelay(500); - r8712_write8(adapter, AFE_PLL_CTRL, (val8 | 0x11)); - udelay(500); - /* Attach AFE PLL to MACTOP/BB/PCIe Digital */ - val8 = r8712_read8(adapter, SYS_ISO_CTRL); - r8712_write8(adapter, SYS_ISO_CTRL, (val8 & 0xEE)); - /* Switch to 40M clock */ - r8712_write8(adapter, SYS_CLKR, 0x00); - /* CPU Clock and 80M Clock SSC Disable to overcome FW download - * fail timing issue. - */ - val8 = r8712_read8(adapter, SYS_CLKR); - r8712_write8(adapter, SYS_CLKR, (val8 | 0xa0)); - /* Enable MAC clock */ - val8 = r8712_read8(adapter, SYS_CLKR + 1); - r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x18)); - /* Revised POS, */ - r8712_write8(adapter, PMC_FSM, 0x02); - /* Enable Core digital and enable IOREG R/W */ - val8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x08)); - /* Enable REG_EN */ - val8 = r8712_read8(adapter, SYS_FUNC_EN + 1); - r8712_write8(adapter, SYS_FUNC_EN + 1, (val8 | 0x80)); - /* Switch the control path to FW */ - val8 = r8712_read8(adapter, SYS_CLKR + 1); - r8712_write8(adapter, SYS_CLKR + 1, (val8 | 0x80) & 0xBF); - r8712_write8(adapter, CR, 0xFC); - r8712_write8(adapter, CR + 1, 0x37); - /* Fix the RX FIFO issue(usb error), 970410 */ - val8 = r8712_read8(adapter, 0x1025FE5c); - r8712_write8(adapter, 0x1025FE5c, (val8 | BIT(7))); - /* For power save, used this in the bit file after 970621 */ - val8 = r8712_read8(adapter, SYS_CLKR); - r8712_write8(adapter, SYS_CLKR, val8 & (~CPU_CLKSEL)); - /* Revised for 8051 ROM code wrong operation. */ - r8712_write8(adapter, 0x1025fe1c, 0x80); - /* To make sure that TxDMA can ready to download FW. - * We should reset TxDMA if IMEM RPT was not ready. - */ - do { - val8 = r8712_read8(adapter, TCR); - if ((val8 & _TXDMA_INIT_VALUE) == _TXDMA_INIT_VALUE) - break; - udelay(5); /* PlatformStallExecution(5); */ - } while (PollingCnt--); /* Delay 1ms */ - - if (PollingCnt <= 0) { - val8 = r8712_read8(adapter, CR); - r8712_write8(adapter, CR, val8 & (~_TXDMA_EN)); - udelay(2); /* PlatformStallExecution(2); */ - /* Reset TxDMA */ - r8712_write8(adapter, CR, val8 | _TXDMA_EN); - } - } else { - ret = _FAIL; - } - return ret; -} - -unsigned int r8712_usb_inirp_init(struct _adapter *adapter) -{ - u8 i; - struct recv_buf *recvbuf; - struct intf_hdl *intfhdl = &adapter->pio_queue->intf; - struct recv_priv *recvpriv = &(adapter->recvpriv); - - recvpriv->ff_hwaddr = RTL8712_DMA_RX0FF; /* mapping rx fifo address */ - /* issue Rx irp to receive data */ - recvbuf = (struct recv_buf *)recvpriv->precv_buf; - for (i = 0; i < NR_RECVBUFF; i++) { - if (r8712_usb_read_port(intfhdl, recvpriv->ff_hwaddr, 0, - (unsigned char *)recvbuf) == false) - return _FAIL; - recvbuf++; - recvpriv->free_recv_buf_queue_cnt--; - } - return _SUCCESS; -} - -unsigned int r8712_usb_inirp_deinit(struct _adapter *adapter) -{ - r8712_usb_read_port_cancel(adapter); - return _SUCCESS; -} diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c deleted file mode 100644 index df05213f922f45..00000000000000 --- a/drivers/staging/rtl8712/usb_intf.c +++ /dev/null @@ -1,638 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * usb_intf.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _HCI_INTF_C_ - -#include -#include -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "recv_osdep.h" -#include "xmit_osdep.h" -#include "rtl8712_efuse.h" -#include "usb_ops.h" -#include "usb_osintf.h" - -static struct usb_interface *pintf; - -static int r871xu_drv_init(struct usb_interface *pusb_intf, - const struct usb_device_id *pdid); - -static void r871xu_dev_remove(struct usb_interface *pusb_intf); - -static const struct usb_device_id rtl871x_usb_id_tbl[] = { -/* RTL8188SU */ - /* Realtek */ - {USB_DEVICE(0x0BDA, 0x8171)}, - {USB_DEVICE(0x0bda, 0x8173)}, - {USB_DEVICE(0x0bda, 0x8712)}, - {USB_DEVICE(0x0bda, 0x8713)}, - {USB_DEVICE(0x0bda, 0xC512)}, - /* Abocom */ - {USB_DEVICE(0x07B8, 0x8188)}, - /* ASUS */ - {USB_DEVICE(0x0B05, 0x1786)}, - {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ - /* Belkin */ - {USB_DEVICE(0x050D, 0x945A)}, - /* ISY IWL - Belkin clone */ - {USB_DEVICE(0x050D, 0x11F1)}, - /* Corega */ - {USB_DEVICE(0x07AA, 0x0047)}, - /* D-Link */ - {USB_DEVICE(0x2001, 0x3306)}, - {USB_DEVICE(0x07D1, 0x3306)}, /* 11n mode disable */ - /* Edimax */ - {USB_DEVICE(0x7392, 0x7611)}, - /* EnGenius */ - {USB_DEVICE(0x1740, 0x9603)}, - /* Hawking */ - {USB_DEVICE(0x0E66, 0x0016)}, - /* Hercules */ - {USB_DEVICE(0x06F8, 0xE034)}, - {USB_DEVICE(0x06F8, 0xE032)}, - /* Logitec */ - {USB_DEVICE(0x0789, 0x0167)}, - /* PCI */ - {USB_DEVICE(0x2019, 0xAB28)}, - {USB_DEVICE(0x2019, 0xED16)}, - /* Sitecom */ - {USB_DEVICE(0x0DF6, 0x0057)}, - {USB_DEVICE(0x0DF6, 0x0045)}, - {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */ - {USB_DEVICE(0x0DF6, 0x004B)}, - {USB_DEVICE(0x0DF6, 0x005B)}, - {USB_DEVICE(0x0DF6, 0x005D)}, - {USB_DEVICE(0x0DF6, 0x0063)}, - /* Sweex */ - {USB_DEVICE(0x177F, 0x0154)}, - /* Thinkware */ - {USB_DEVICE(0x0BDA, 0x5077)}, - /* Toshiba */ - {USB_DEVICE(0x1690, 0x0752)}, - /* - */ - {USB_DEVICE(0x20F4, 0x646B)}, - {USB_DEVICE(0x083A, 0xC512)}, - {USB_DEVICE(0x25D4, 0x4CA1)}, - {USB_DEVICE(0x25D4, 0x4CAB)}, - -/* RTL8191SU */ - /* Realtek */ - {USB_DEVICE(0x0BDA, 0x8172)}, - {USB_DEVICE(0x0BDA, 0x8192)}, - /* Amigo */ - {USB_DEVICE(0x0EB0, 0x9061)}, - /* ASUS/EKB */ - {USB_DEVICE(0x13D3, 0x3323)}, - {USB_DEVICE(0x13D3, 0x3311)}, /* 11n mode disable */ - {USB_DEVICE(0x13D3, 0x3342)}, - /* ASUS/EKBLenovo */ - {USB_DEVICE(0x13D3, 0x3333)}, - {USB_DEVICE(0x13D3, 0x3334)}, - {USB_DEVICE(0x13D3, 0x3335)}, /* 11n mode disable */ - {USB_DEVICE(0x13D3, 0x3336)}, /* 11n mode disable */ - /* ASUS/Media BOX */ - {USB_DEVICE(0x13D3, 0x3309)}, - /* Belkin */ - {USB_DEVICE(0x050D, 0x815F)}, - /* D-Link */ - {USB_DEVICE(0x07D1, 0x3302)}, - {USB_DEVICE(0x07D1, 0x3300)}, - {USB_DEVICE(0x07D1, 0x3303)}, - /* Edimax */ - {USB_DEVICE(0x7392, 0x7612)}, - /* EnGenius */ - {USB_DEVICE(0x1740, 0x9605)}, - /* Guillemot */ - {USB_DEVICE(0x06F8, 0xE031)}, - /* Hawking */ - {USB_DEVICE(0x0E66, 0x0015)}, - /* Mediao */ - {USB_DEVICE(0x13D3, 0x3306)}, - /* PCI */ - {USB_DEVICE(0x2019, 0xED18)}, - {USB_DEVICE(0x2019, 0x4901)}, - /* Sitecom */ - {USB_DEVICE(0x0DF6, 0x0058)}, - {USB_DEVICE(0x0DF6, 0x0049)}, - {USB_DEVICE(0x0DF6, 0x004C)}, - {USB_DEVICE(0x0DF6, 0x006C)}, - {USB_DEVICE(0x0DF6, 0x0064)}, - /* Skyworth */ - {USB_DEVICE(0x14b2, 0x3300)}, - {USB_DEVICE(0x14b2, 0x3301)}, - {USB_DEVICE(0x14B2, 0x3302)}, - /* - */ - {USB_DEVICE(0x04F2, 0xAFF2)}, - {USB_DEVICE(0x04F2, 0xAFF5)}, - {USB_DEVICE(0x04F2, 0xAFF6)}, - {USB_DEVICE(0x13D3, 0x3339)}, - {USB_DEVICE(0x13D3, 0x3340)}, /* 11n mode disable */ - {USB_DEVICE(0x13D3, 0x3341)}, /* 11n mode disable */ - {USB_DEVICE(0x13D3, 0x3310)}, - {USB_DEVICE(0x13D3, 0x3325)}, - -/* RTL8192SU */ - /* Realtek */ - {USB_DEVICE(0x0BDA, 0x8174)}, - /* Belkin */ - {USB_DEVICE(0x050D, 0x845A)}, - /* Corega */ - {USB_DEVICE(0x07AA, 0x0051)}, - /* Edimax */ - {USB_DEVICE(0x7392, 0x7622)}, - /* NEC */ - {USB_DEVICE(0x0409, 0x02B6)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, rtl871x_usb_id_tbl); - -static struct specific_device_id specific_device_id_tbl[] = { - {.idVendor = 0x0b05, .idProduct = 0x1791, - .flags = SPEC_DEV_ID_DISABLE_HT}, - {.idVendor = 0x0df6, .idProduct = 0x0059, - .flags = SPEC_DEV_ID_DISABLE_HT}, - {.idVendor = 0x13d3, .idProduct = 0x3306, - .flags = SPEC_DEV_ID_DISABLE_HT}, - {.idVendor = 0x13D3, .idProduct = 0x3311, - .flags = SPEC_DEV_ID_DISABLE_HT}, - {.idVendor = 0x13d3, .idProduct = 0x3335, - .flags = SPEC_DEV_ID_DISABLE_HT}, - {.idVendor = 0x13d3, .idProduct = 0x3336, - .flags = SPEC_DEV_ID_DISABLE_HT}, - {.idVendor = 0x13d3, .idProduct = 0x3340, - .flags = SPEC_DEV_ID_DISABLE_HT}, - {.idVendor = 0x13d3, .idProduct = 0x3341, - .flags = SPEC_DEV_ID_DISABLE_HT}, - {} -}; - -struct drv_priv { - struct usb_driver r871xu_drv; - int drv_registered; -}; - -#ifdef CONFIG_PM -static int r871x_suspend(struct usb_interface *pusb_intf, pm_message_t state) -{ - struct net_device *pnetdev = usb_get_intfdata(pusb_intf); - struct _adapter *padapter = netdev_priv(pnetdev); - - netdev_info(pnetdev, "Suspending...\n"); - padapter->suspended = true; - rtl871x_intf_stop(padapter); - if (pnetdev->netdev_ops->ndo_stop) - pnetdev->netdev_ops->ndo_stop(pnetdev); - mdelay(10); - netif_device_detach(pnetdev); - return 0; -} - -static void rtl871x_intf_resume(struct _adapter *padapter) -{ - if (padapter->dvobjpriv.inirp_init) - padapter->dvobjpriv.inirp_init(padapter); -} - -static int r871x_resume(struct usb_interface *pusb_intf) -{ - struct net_device *pnetdev = usb_get_intfdata(pusb_intf); - struct _adapter *padapter = netdev_priv(pnetdev); - - netdev_info(pnetdev, "Resuming...\n"); - netif_device_attach(pnetdev); - if (pnetdev->netdev_ops->ndo_open) - pnetdev->netdev_ops->ndo_open(pnetdev); - padapter->suspended = false; - rtl871x_intf_resume(padapter); - return 0; -} -#endif - -static struct drv_priv drvpriv = { - .r871xu_drv.name = "r8712u", - .r871xu_drv.id_table = rtl871x_usb_id_tbl, - .r871xu_drv.probe = r871xu_drv_init, - .r871xu_drv.disconnect = r871xu_dev_remove, -#ifdef CONFIG_PM - .r871xu_drv.suspend = r871x_suspend, - .r871xu_drv.resume = r871x_resume, -#endif -}; - -static uint r8712_usb_dvobj_init(struct _adapter *padapter) -{ - uint status = _SUCCESS; - struct usb_host_interface *phost_iface; - struct usb_interface_descriptor *piface_desc; - struct dvobj_priv *pdvobjpriv = &padapter->dvobjpriv; - struct usb_device *pusbd = pdvobjpriv->pusbdev; - - pdvobjpriv->padapter = padapter; - padapter->eeprom_address_size = 6; - phost_iface = pintf->cur_altsetting; - piface_desc = &phost_iface->desc; - pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; - if (pusbd->speed == USB_SPEED_HIGH) { - pdvobjpriv->ishighspeed = true; - dev_info(&pusbd->dev, "r8712u: USB_SPEED_HIGH with %d endpoints\n", - pdvobjpriv->nr_endpoint); - } else { - pdvobjpriv->ishighspeed = false; - dev_info(&pusbd->dev, "r8712u: USB_SPEED_LOW with %d endpoints\n", - pdvobjpriv->nr_endpoint); - } - if ((r8712_alloc_io_queue(padapter)) == _FAIL) - status = _FAIL; - return status; -} - -static void r8712_usb_dvobj_deinit(struct _adapter *padapter) -{ - r8712_free_io_queue(padapter); -} - -void rtl871x_intf_stop(struct _adapter *padapter) -{ - /*disable_hw_interrupt*/ - if (!padapter->surprise_removed) { - /*device still exists, so driver can do i/o operation - * TODO: - */ - } - - /* cancel in irp */ - if (padapter->dvobjpriv.inirp_deinit) - padapter->dvobjpriv.inirp_deinit(padapter); - /* cancel out irp */ - r8712_usb_write_port_cancel(padapter); - /* TODO:cancel other irps */ -} - -void r871x_dev_unload(struct _adapter *padapter) -{ - if (padapter->bup) { - /*s1.*/ - padapter->driver_stopped = true; - - /*s3.*/ - rtl871x_intf_stop(padapter); - - /*s4.*/ - r8712_stop_drv_threads(padapter); - - /*s5.*/ - if (!padapter->surprise_removed) { - padapter->hw_init_completed = false; - rtl8712_hal_deinit(padapter); - } - - padapter->bup = false; - } -} - -static void disable_ht_for_spec_devid(const struct usb_device_id *pdid, - struct _adapter *padapter) -{ - u16 vid, pid; - u32 flags; - int i; - int num = ARRAY_SIZE(specific_device_id_tbl); - - for (i = 0; i < num; i++) { - vid = specific_device_id_tbl[i].idVendor; - pid = specific_device_id_tbl[i].idProduct; - flags = specific_device_id_tbl[i].flags; - - if ((pdid->idVendor == vid) && (pdid->idProduct == pid) && - (flags & SPEC_DEV_ID_DISABLE_HT)) { - padapter->registrypriv.ht_enable = 0; - padapter->registrypriv.cbw40_enable = 0; - padapter->registrypriv.ampdu_enable = 0; - } - } -} - -static const struct device_type wlan_type = { - .name = "wlan", -}; - -/* - * drv_init() - a device potentially for us - * - * notes: drv_init() is called when the bus driver has located a card for us - * to support. We accept the new device by returning 0. - */ -static int r871xu_drv_init(struct usb_interface *pusb_intf, - const struct usb_device_id *pdid) -{ - uint status; - struct _adapter *padapter = NULL; - struct dvobj_priv *pdvobjpriv; - struct net_device *pnetdev; - struct usb_device *udev; - - /* In this probe function, O.S. will provide the usb interface pointer - * to driver. We have to increase the reference count of the usb device - * structure by using the usb_get_dev function. - */ - udev = interface_to_usbdev(pusb_intf); - usb_get_dev(udev); - pintf = pusb_intf; - /* step 1. */ - pnetdev = r8712_init_netdev(); - if (!pnetdev) - goto put_dev; - padapter = netdev_priv(pnetdev); - disable_ht_for_spec_devid(pdid, padapter); - pdvobjpriv = &padapter->dvobjpriv; - pdvobjpriv->padapter = padapter; - padapter->dvobjpriv.pusbdev = udev; - padapter->pusb_intf = pusb_intf; - usb_set_intfdata(pusb_intf, pnetdev); - SET_NETDEV_DEV(pnetdev, &pusb_intf->dev); - pnetdev->dev.type = &wlan_type; - /* step 2. */ - padapter->dvobj_init = r8712_usb_dvobj_init; - padapter->dvobj_deinit = r8712_usb_dvobj_deinit; - padapter->halpriv.hal_bus_init = r8712_usb_hal_bus_init; - padapter->dvobjpriv.inirp_init = r8712_usb_inirp_init; - padapter->dvobjpriv.inirp_deinit = r8712_usb_inirp_deinit; - /* step 3. - * initialize the dvobj_priv - */ - - status = padapter->dvobj_init(padapter); - if (status != _SUCCESS) - goto free_netdev; - - /* step 4. */ - status = r8712_init_drv_sw(padapter); - if (status) - goto dvobj_deinit; - /* step 5. read efuse/eeprom data and get mac_addr */ - { - int i, offset; - u8 mac[6]; - u8 tmpU1b, AutoloadFail, eeprom_CustomerID; - u8 *pdata = padapter->eeprompriv.efuse_eeprom_data; - - tmpU1b = r8712_read8(padapter, EE_9346CR);/*CR9346*/ - - /* To check system boot selection.*/ - dev_info(&udev->dev, "r8712u: Boot from %s: Autoload %s\n", - (tmpU1b & _9356SEL) ? "EEPROM" : "EFUSE", - (tmpU1b & _EEPROM_EN) ? "OK" : "Failed"); - - /* To check autoload success or not.*/ - if (tmpU1b & _EEPROM_EN) { - AutoloadFail = true; - /* The following operations prevent Efuse leakage by - * turning on 2.5V. - */ - tmpU1b = r8712_read8(padapter, EFUSE_TEST + 3); - r8712_write8(padapter, EFUSE_TEST + 3, tmpU1b | 0x80); - msleep(20); - r8712_write8(padapter, EFUSE_TEST + 3, - (tmpU1b & (~BIT(7)))); - - /* Retrieve Chip version. - * Recognize IC version by Reg0x4 BIT15. - */ - tmpU1b = (u8)((r8712_read32(padapter, PMC_FSM) >> 15) & - 0x1F); - if (tmpU1b == 0x3) - padapter->registrypriv.chip_version = - RTL8712_3rdCUT; - else - padapter->registrypriv.chip_version = - (tmpU1b >> 1) + 1; - switch (padapter->registrypriv.chip_version) { - case RTL8712_1stCUT: - case RTL8712_2ndCUT: - case RTL8712_3rdCUT: - break; - default: - padapter->registrypriv.chip_version = - RTL8712_2ndCUT; - break; - } - - for (i = 0, offset = 0; i < 128; i += 8, offset++) - r8712_efuse_pg_packet_read(padapter, offset, - &pdata[i]); - - if (!r8712_initmac || !mac_pton(r8712_initmac, mac)) { - /* Use the mac address stored in the Efuse - * offset = 0x12 for usb in efuse - */ - ether_addr_copy(mac, &pdata[0x12]); - } - eeprom_CustomerID = pdata[0x52]; - switch (eeprom_CustomerID) { - case EEPROM_CID_ALPHA: - padapter->eeprompriv.CustomerID = - RT_CID_819x_ALPHA; - break; - case EEPROM_CID_CAMEO: - padapter->eeprompriv.CustomerID = - RT_CID_819x_CAMEO; - break; - case EEPROM_CID_SITECOM: - padapter->eeprompriv.CustomerID = - RT_CID_819x_Sitecom; - break; - case EEPROM_CID_COREGA: - padapter->eeprompriv.CustomerID = - RT_CID_COREGA; - break; - case EEPROM_CID_Senao: - padapter->eeprompriv.CustomerID = - RT_CID_819x_Senao; - break; - case EEPROM_CID_EDIMAX_BELKIN: - padapter->eeprompriv.CustomerID = - RT_CID_819x_Edimax_Belkin; - break; - case EEPROM_CID_SERCOMM_BELKIN: - padapter->eeprompriv.CustomerID = - RT_CID_819x_Sercomm_Belkin; - break; - case EEPROM_CID_WNC_COREGA: - padapter->eeprompriv.CustomerID = - RT_CID_819x_WNC_COREGA; - break; - case EEPROM_CID_WHQL: - break; - case EEPROM_CID_NetCore: - padapter->eeprompriv.CustomerID = - RT_CID_819x_Netcore; - break; - case EEPROM_CID_CAMEO1: - padapter->eeprompriv.CustomerID = - RT_CID_819x_CAMEO1; - break; - case EEPROM_CID_CLEVO: - padapter->eeprompriv.CustomerID = - RT_CID_819x_CLEVO; - break; - default: - padapter->eeprompriv.CustomerID = - RT_CID_DEFAULT; - break; - } - dev_info(&udev->dev, "r8712u: CustomerID = 0x%.4x\n", - padapter->eeprompriv.CustomerID); - /* Led mode */ - switch (padapter->eeprompriv.CustomerID) { - case RT_CID_DEFAULT: - case RT_CID_819x_ALPHA: - case RT_CID_819x_CAMEO: - padapter->ledpriv.LedStrategy = SW_LED_MODE1; - padapter->ledpriv.bRegUseLed = true; - break; - case RT_CID_819x_Sitecom: - padapter->ledpriv.LedStrategy = SW_LED_MODE2; - padapter->ledpriv.bRegUseLed = true; - break; - case RT_CID_COREGA: - case RT_CID_819x_Senao: - padapter->ledpriv.LedStrategy = SW_LED_MODE3; - padapter->ledpriv.bRegUseLed = true; - break; - case RT_CID_819x_Edimax_Belkin: - padapter->ledpriv.LedStrategy = SW_LED_MODE4; - padapter->ledpriv.bRegUseLed = true; - break; - case RT_CID_819x_Sercomm_Belkin: - padapter->ledpriv.LedStrategy = SW_LED_MODE5; - padapter->ledpriv.bRegUseLed = true; - break; - case RT_CID_819x_WNC_COREGA: - padapter->ledpriv.LedStrategy = SW_LED_MODE6; - padapter->ledpriv.bRegUseLed = true; - break; - default: - padapter->ledpriv.LedStrategy = SW_LED_MODE0; - padapter->ledpriv.bRegUseLed = false; - break; - } - } else { - AutoloadFail = false; - } - if ((!AutoloadFail) || - ((mac[0] == 0xff) && (mac[1] == 0xff) && - (mac[2] == 0xff) && (mac[3] == 0xff) && - (mac[4] == 0xff) && (mac[5] == 0xff)) || - ((mac[0] == 0x00) && (mac[1] == 0x00) && - (mac[2] == 0x00) && (mac[3] == 0x00) && - (mac[4] == 0x00) && (mac[5] == 0x00))) { - mac[0] = 0x00; - mac[1] = 0xe0; - mac[2] = 0x4c; - mac[3] = 0x87; - mac[4] = 0x00; - mac[5] = 0x00; - } - if (r8712_initmac) { - /* Make sure the user did not select a multicast - * address by setting bit 1 of first octet. - */ - mac[0] &= 0xFE; - dev_info(&udev->dev, - "r8712u: MAC Address from user = %pM\n", mac); - } else { - dev_info(&udev->dev, - "r8712u: MAC Address from efuse = %pM\n", mac); - } - eth_hw_addr_set(pnetdev, mac); - } - /* step 6. Load the firmware asynchronously */ - if (rtl871x_load_fw(padapter)) - goto deinit_drv_sw; - init_completion(&padapter->rx_filter_ready); - return 0; - -deinit_drv_sw: - r8712_free_drv_sw(padapter); -dvobj_deinit: - padapter->dvobj_deinit(padapter); -free_netdev: - free_netdev(pnetdev); -put_dev: - usb_put_dev(udev); - usb_set_intfdata(pusb_intf, NULL); - return -ENODEV; -} - -/* rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() - * => how to recognize both - */ -static void r871xu_dev_remove(struct usb_interface *pusb_intf) -{ - struct net_device *pnetdev = usb_get_intfdata(pusb_intf); - struct usb_device *udev = interface_to_usbdev(pusb_intf); - struct _adapter *padapter = netdev_priv(pnetdev); - - /* never exit with a firmware callback pending */ - wait_for_completion(&padapter->rtl8712_fw_ready); - if (pnetdev->reg_state != NETREG_UNINITIALIZED) - unregister_netdev(pnetdev); /* will call netdev_close() */ - usb_set_intfdata(pusb_intf, NULL); - release_firmware(padapter->fw); - if (drvpriv.drv_registered) - padapter->surprise_removed = true; - r8712_flush_rwctrl_works(padapter); - r8712_flush_led_works(padapter); - udelay(1); - /* Stop driver mlme relation timer */ - r8712_stop_drv_timers(padapter); - r871x_dev_unload(padapter); - if (padapter->dvobj_deinit) - padapter->dvobj_deinit(padapter); - r8712_free_drv_sw(padapter); - free_netdev(pnetdev); - - /* decrease the reference count of the usb device structure - * when disconnect - */ - usb_put_dev(udev); - - /* If we didn't unplug usb dongle and remove/insert module, driver - * fails on sitesurvey for the first time when device is up. - * Reset usb port for sitesurvey fail issue. - */ - if (udev->state != USB_STATE_NOTATTACHED) - usb_reset_device(udev); -} - -static int __init r8712u_drv_entry(void) -{ - drvpriv.drv_registered = true; - return usb_register(&drvpriv.r871xu_drv); -} - -static void __exit r8712u_drv_halt(void) -{ - drvpriv.drv_registered = false; - usb_deregister(&drvpriv.r871xu_drv); -} - -module_init(r8712u_drv_entry); -module_exit(r8712u_drv_halt); diff --git a/drivers/staging/rtl8712/usb_ops.c b/drivers/staging/rtl8712/usb_ops.c deleted file mode 100644 index af9966d03979c6..00000000000000 --- a/drivers/staging/rtl8712/usb_ops.c +++ /dev/null @@ -1,195 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * usb_ops.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _HCI_OPS_C_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "osdep_intf.h" -#include "usb_ops.h" -#include "recv_osdep.h" - -static u8 usb_read8(struct intf_hdl *intfhdl, u32 addr) -{ - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - int status; - __le32 data = 0; - struct intf_priv *intfpriv = intfhdl->pintfpriv; - - request = 0x05; - requesttype = 0x01; /* read_in */ - index = 0; - wvalue = (u16)(addr & 0x0000ffff); - len = 1; - status = r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, - &data, len, requesttype); - if (status < 0) - return 0; - return (u8)(le32_to_cpu(data) & 0x0ff); -} - -static u16 usb_read16(struct intf_hdl *intfhdl, u32 addr) -{ - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - int status; - __le32 data = 0; - struct intf_priv *intfpriv = intfhdl->pintfpriv; - - request = 0x05; - requesttype = 0x01; /* read_in */ - index = 0; - wvalue = (u16)(addr & 0x0000ffff); - len = 2; - status = r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, - &data, len, requesttype); - if (status < 0) - return 0; - return (u16)(le32_to_cpu(data) & 0xffff); -} - -static u32 usb_read32(struct intf_hdl *intfhdl, u32 addr) -{ - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - int status; - __le32 data = 0; - struct intf_priv *intfpriv = intfhdl->pintfpriv; - - request = 0x05; - requesttype = 0x01; /* read_in */ - index = 0; - wvalue = (u16)(addr & 0x0000ffff); - len = 4; - status = r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, - &data, len, requesttype); - if (status < 0) - return 0; - return le32_to_cpu(data); -} - -static void usb_write8(struct intf_hdl *intfhdl, u32 addr, u8 val) -{ - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - __le32 data; - struct intf_priv *intfpriv = intfhdl->pintfpriv; - - request = 0x05; - requesttype = 0x00; /* write_out */ - index = 0; - wvalue = (u16)(addr & 0x0000ffff); - len = 1; - data = cpu_to_le32((u32)val & 0x000000ff); - r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len, - requesttype); -} - -static void usb_write16(struct intf_hdl *intfhdl, u32 addr, u16 val) -{ - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - __le32 data; - struct intf_priv *intfpriv = intfhdl->pintfpriv; - - request = 0x05; - requesttype = 0x00; /* write_out */ - index = 0; - wvalue = (u16)(addr & 0x0000ffff); - len = 2; - data = cpu_to_le32((u32)val & 0x0000ffff); - r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len, - requesttype); -} - -static void usb_write32(struct intf_hdl *intfhdl, u32 addr, u32 val) -{ - u8 request; - u8 requesttype; - u16 wvalue; - u16 index; - u16 len; - __le32 data; - struct intf_priv *intfpriv = intfhdl->pintfpriv; - - request = 0x05; - requesttype = 0x00; /* write_out */ - index = 0; - wvalue = (u16)(addr & 0x0000ffff); - len = 4; - data = cpu_to_le32(val); - r8712_usbctrl_vendorreq(intfpriv, request, wvalue, index, &data, len, - requesttype); -} - -void r8712_usb_set_intf_option(u32 *option) -{ - *option = ((*option) | _INTF_ASYNC_); -} - -static void usb_intf_hdl_init(u8 *priv) -{ -} - -static void usb_intf_hdl_unload(u8 *priv) -{ -} - -static void usb_intf_hdl_open(u8 *priv) -{ -} - -static void usb_intf_hdl_close(u8 *priv) -{ -} - -void r8712_usb_set_intf_funs(struct intf_hdl *intfhdl) -{ - intfhdl->intf_hdl_init = usb_intf_hdl_init; - intfhdl->intf_hdl_unload = usb_intf_hdl_unload; - intfhdl->intf_hdl_open = usb_intf_hdl_open; - intfhdl->intf_hdl_close = usb_intf_hdl_close; -} - -void r8712_usb_set_intf_ops(struct _io_ops *ops) -{ - memset((u8 *)ops, 0, sizeof(struct _io_ops)); - ops->_read8 = usb_read8; - ops->_read16 = usb_read16; - ops->_read32 = usb_read32; - ops->_read_port = r8712_usb_read_port; - ops->_write8 = usb_write8; - ops->_write16 = usb_write16; - ops->_write32 = usb_write32; - ops->_write_mem = r8712_usb_write_mem; - ops->_write_port = r8712_usb_write_port; -} diff --git a/drivers/staging/rtl8712/usb_ops.h b/drivers/staging/rtl8712/usb_ops.h deleted file mode 100644 index 7a6b619b73fabe..00000000000000 --- a/drivers/staging/rtl8712/usb_ops.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __USB_OPS_H_ -#define __USB_OPS_H_ - -#include "osdep_service.h" -#include "drv_types.h" -#include "osdep_intf.h" - -void r8712_usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, - u32 cnt, u8 *wmem); -u32 r8712_usb_write_port(struct intf_hdl *pintfhdl, u32 addr, - u32 cnt, u8 *wmem); -u32 r8712_usb_read_port(struct intf_hdl *pintfhdl, u32 addr, - u32 cnt, u8 *rmem); -void r8712_usb_set_intf_option(u32 *poption); -void r8712_usb_set_intf_funs(struct intf_hdl *pintf_hdl); -uint r8712_usb_init_intf_priv(struct intf_priv *pintfpriv); -void r8712_usb_unload_intf_priv(struct intf_priv *pintfpriv); -void r8712_usb_set_intf_ops(struct _io_ops *pops); -void r8712_usb_read_port_cancel(struct _adapter *padapter); -void r8712_usb_write_port_cancel(struct _adapter *padapter); -int r8712_usbctrl_vendorreq(struct intf_priv *pintfpriv, u8 request, u16 value, - u16 index, void *pdata, u16 len, u8 requesttype); - -#endif - diff --git a/drivers/staging/rtl8712/usb_ops_linux.c b/drivers/staging/rtl8712/usb_ops_linux.c deleted file mode 100644 index 4a34824830e39d..00000000000000 --- a/drivers/staging/rtl8712/usb_ops_linux.c +++ /dev/null @@ -1,508 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * usb_ops_linux.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _HCI_OPS_OS_C_ - -#include - -#include "osdep_service.h" -#include "drv_types.h" -#include "osdep_intf.h" -#include "usb_ops.h" - -#define RTL871X_VENQT_READ 0xc0 -#define RTL871X_VENQT_WRITE 0x40 - -uint r8712_usb_init_intf_priv(struct intf_priv *pintfpriv) -{ - pintfpriv->piorw_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!pintfpriv->piorw_urb) - return _FAIL; - init_completion(&pintfpriv->io_retevt_comp); - return _SUCCESS; -} - -void r8712_usb_unload_intf_priv(struct intf_priv *pintfpriv) -{ - if (pintfpriv->piorw_urb) { - usb_kill_urb(pintfpriv->piorw_urb); - usb_free_urb(pintfpriv->piorw_urb); - } -} - -static unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) -{ - unsigned int pipe = 0; - struct usb_device *pusbd = pdvobj->pusbdev; - - if (pdvobj->nr_endpoint == 11) { - switch (addr) { - case RTL8712_DMA_BKQ: - pipe = usb_sndbulkpipe(pusbd, 0x07); - break; - case RTL8712_DMA_BEQ: - pipe = usb_sndbulkpipe(pusbd, 0x06); - break; - case RTL8712_DMA_VIQ: - pipe = usb_sndbulkpipe(pusbd, 0x05); - break; - case RTL8712_DMA_VOQ: - pipe = usb_sndbulkpipe(pusbd, 0x04); - break; - case RTL8712_DMA_BCNQ: - pipe = usb_sndbulkpipe(pusbd, 0x0a); - break; - case RTL8712_DMA_BMCQ: /* HI Queue */ - pipe = usb_sndbulkpipe(pusbd, 0x0b); - break; - case RTL8712_DMA_MGTQ: - pipe = usb_sndbulkpipe(pusbd, 0x0c); - break; - case RTL8712_DMA_RX0FF: - pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ - break; - case RTL8712_DMA_C2HCMD: - pipe = usb_rcvbulkpipe(pusbd, 0x09); /* in */ - break; - case RTL8712_DMA_H2CCMD: - pipe = usb_sndbulkpipe(pusbd, 0x0d); - break; - } - } else if (pdvobj->nr_endpoint == 6) { - switch (addr) { - case RTL8712_DMA_BKQ: - pipe = usb_sndbulkpipe(pusbd, 0x07); - break; - case RTL8712_DMA_BEQ: - pipe = usb_sndbulkpipe(pusbd, 0x06); - break; - case RTL8712_DMA_VIQ: - pipe = usb_sndbulkpipe(pusbd, 0x05); - break; - case RTL8712_DMA_VOQ: - pipe = usb_sndbulkpipe(pusbd, 0x04); - break; - case RTL8712_DMA_RX0FF: - case RTL8712_DMA_C2HCMD: - pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ - break; - case RTL8712_DMA_H2CCMD: - case RTL8712_DMA_BCNQ: - case RTL8712_DMA_BMCQ: - case RTL8712_DMA_MGTQ: - pipe = usb_sndbulkpipe(pusbd, 0x0d); - break; - } - } else if (pdvobj->nr_endpoint == 4) { - switch (addr) { - case RTL8712_DMA_BEQ: - pipe = usb_sndbulkpipe(pusbd, 0x06); - break; - case RTL8712_DMA_VOQ: - pipe = usb_sndbulkpipe(pusbd, 0x04); - break; - case RTL8712_DMA_RX0FF: - case RTL8712_DMA_C2HCMD: - pipe = usb_rcvbulkpipe(pusbd, 0x03); /* in */ - break; - case RTL8712_DMA_H2CCMD: - case RTL8712_DMA_BCNQ: - case RTL8712_DMA_BMCQ: - case RTL8712_DMA_MGTQ: - pipe = usb_sndbulkpipe(pusbd, 0x0d); - break; - } - } else { - pipe = 0; - } - return pipe; -} - -static void usb_write_mem_complete(struct urb *purb) -{ - struct io_queue *pio_q = (struct io_queue *)purb->context; - struct intf_hdl *pintf = &(pio_q->intf); - struct intf_priv *pintfpriv = pintf->pintfpriv; - struct _adapter *padapter = (struct _adapter *)pintf->adapter; - - if (purb->status != 0) { - if (purb->status == (-ESHUTDOWN)) - padapter->driver_stopped = true; - else - padapter->surprise_removed = true; - } - complete(&pintfpriv->io_retevt_comp); -} - -void r8712_usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) -{ - unsigned int pipe; - struct _adapter *padapter = (struct _adapter *)pintfhdl->adapter; - struct intf_priv *pintfpriv = pintfhdl->pintfpriv; - struct io_queue *pio_queue = padapter->pio_queue; - struct dvobj_priv *pdvobj = (struct dvobj_priv *)pintfpriv->intf_dev; - struct usb_device *pusbd = pdvobj->pusbdev; - struct urb *piorw_urb = pintfpriv->piorw_urb; - - if ((padapter->driver_stopped) || (padapter->surprise_removed) || - (padapter->pwrctrlpriv.pnp_bstop_trx)) - return; - /* translate DMA FIFO addr to pipehandle */ - pipe = ffaddr2pipehdl(pdvobj, addr); - if (pipe == 0) - return; - usb_fill_bulk_urb(piorw_urb, pusbd, pipe, - wmem, cnt, usb_write_mem_complete, - pio_queue); - usb_submit_urb(piorw_urb, GFP_ATOMIC); - wait_for_completion_interruptible(&pintfpriv->io_retevt_comp); -} - -static void r8712_usb_read_port_complete(struct urb *purb) -{ - uint isevt; - __le32 *pbuf; - struct recv_buf *precvbuf = (struct recv_buf *)purb->context; - struct _adapter *padapter = (struct _adapter *)precvbuf->adapter; - struct recv_priv *precvpriv = &padapter->recvpriv; - - if (padapter->surprise_removed || padapter->driver_stopped) - return; - if (purb->status == 0) { /* SUCCESS */ - if ((purb->actual_length > (MAX_RECVBUF_SZ)) || - (purb->actual_length < RXDESC_SIZE)) { - r8712_read_port(padapter, precvpriv->ff_hwaddr, 0, - (unsigned char *)precvbuf); - } else { - _pkt *pskb = precvbuf->pskb; - - precvbuf->transfer_len = purb->actual_length; - pbuf = (__le32 *)precvbuf->pbuf; - isevt = le32_to_cpu(*(pbuf + 1)) & 0x1ff; - if ((isevt & 0x1ff) == 0x1ff) { - r8712_rxcmd_event_hdl(padapter, pbuf); - skb_queue_tail(&precvpriv->rx_skb_queue, pskb); - r8712_read_port(padapter, precvpriv->ff_hwaddr, - 0, (unsigned char *)precvbuf); - } else { - skb_put(pskb, purb->actual_length); - skb_queue_tail(&precvpriv->rx_skb_queue, pskb); - tasklet_hi_schedule(&precvpriv->recv_tasklet); - r8712_read_port(padapter, precvpriv->ff_hwaddr, - 0, (unsigned char *)precvbuf); - } - } - } else { - switch (purb->status) { - case -EINVAL: - case -EPIPE: - case -ENODEV: - case -ESHUTDOWN: - padapter->driver_stopped = true; - break; - case -ENOENT: - if (!padapter->suspended) { - padapter->driver_stopped = true; - break; - } - fallthrough; - case -EPROTO: - r8712_read_port(padapter, precvpriv->ff_hwaddr, 0, - (unsigned char *)precvbuf); - break; - case -EINPROGRESS: - netdev_err(padapter->pnetdev, "ERROR: URB IS IN PROGRESS!\n"); - break; - default: - break; - } - } -} - -u32 r8712_usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) -{ - unsigned int pipe; - int err; - u32 tmpaddr = 0; - int alignment = 0; - u32 ret = _SUCCESS; - struct urb *purb = NULL; - struct recv_buf *precvbuf = (struct recv_buf *)rmem; - struct intf_priv *pintfpriv = pintfhdl->pintfpriv; - struct dvobj_priv *pdvobj = (struct dvobj_priv *)pintfpriv->intf_dev; - struct _adapter *adapter = pdvobj->padapter; - struct recv_priv *precvpriv = &adapter->recvpriv; - struct usb_device *pusbd = pdvobj->pusbdev; - - if (adapter->driver_stopped || adapter->surprise_removed || - adapter->pwrctrlpriv.pnp_bstop_trx || !precvbuf) - return _FAIL; - r8712_init_recvbuf(adapter, precvbuf); - /* Try to use skb from the free queue */ - precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); - - if (!precvbuf->pskb) { - precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, - MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); - if (!precvbuf->pskb) - return _FAIL; - tmpaddr = (addr_t)precvbuf->pskb->data; - alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1); - skb_reserve(precvbuf->pskb, - (RECVBUFF_ALIGN_SZ - alignment)); - precvbuf->phead = precvbuf->pskb->head; - precvbuf->pdata = precvbuf->pskb->data; - precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); - precvbuf->pend = skb_end_pointer(precvbuf->pskb); - precvbuf->pbuf = precvbuf->pskb->data; - } else { /* skb is reused */ - precvbuf->phead = precvbuf->pskb->head; - precvbuf->pdata = precvbuf->pskb->data; - precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); - precvbuf->pend = skb_end_pointer(precvbuf->pskb); - precvbuf->pbuf = precvbuf->pskb->data; - } - purb = precvbuf->purb; - /* translate DMA FIFO addr to pipehandle */ - pipe = ffaddr2pipehdl(pdvobj, addr); - usb_fill_bulk_urb(purb, pusbd, pipe, - precvbuf->pbuf, MAX_RECVBUF_SZ, - r8712_usb_read_port_complete, - precvbuf); - err = usb_submit_urb(purb, GFP_ATOMIC); - if ((err) && (err != (-EPERM))) - ret = _FAIL; - return ret; -} - -void r8712_usb_read_port_cancel(struct _adapter *padapter) -{ - int i; - struct recv_buf *precvbuf; - - precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; - for (i = 0; i < NR_RECVBUFF; i++) { - if (precvbuf->purb) - usb_kill_urb(precvbuf->purb); - precvbuf++; - } -} - -void r8712_xmit_bh(struct tasklet_struct *t) -{ - int ret = false; - struct _adapter *padapter = from_tasklet(padapter, t, - xmitpriv.xmit_tasklet); - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - - if (padapter->driver_stopped || - padapter->surprise_removed) { - netdev_err(padapter->pnetdev, "xmit_bh => driver_stopped or surprise_removed\n"); - return; - } - ret = r8712_xmitframe_complete(padapter, pxmitpriv, NULL); - if (!ret) - return; - tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); -} - -static void usb_write_port_complete(struct urb *purb) -{ - int i; - struct xmit_frame *pxmitframe = (struct xmit_frame *)purb->context; - struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; - struct _adapter *padapter = pxmitframe->padapter; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - - switch (pattrib->priority) { - case 1: - case 2: - pxmitpriv->bkq_cnt--; - break; - case 4: - case 5: - pxmitpriv->viq_cnt--; - break; - case 6: - case 7: - pxmitpriv->voq_cnt--; - break; - case 0: - case 3: - default: - pxmitpriv->beq_cnt--; - break; - } - pxmitpriv->txirp_cnt--; - for (i = 0; i < 8; i++) { - if (purb == pxmitframe->pxmit_urb[i]) { - pxmitframe->bpending[i] = false; - break; - } - } - if (padapter->surprise_removed) - return; - switch (purb->status) { - case 0: - break; - default: - netdev_warn(padapter->pnetdev, - "r8712u: pipe error: (%d)\n", purb->status); - break; - } - /* not to consider tx fragment */ - r8712_free_xmitframe_ex(pxmitpriv, pxmitframe); - r8712_free_xmitbuf(pxmitpriv, pxmitbuf); - tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); -} - -u32 r8712_usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) -{ - unsigned long irqL; - int i, status; - unsigned int pipe; - u32 ret, bwritezero; - struct urb *purb = NULL; - struct _adapter *padapter = (struct _adapter *)pintfhdl->adapter; - struct dvobj_priv *pdvobj = &padapter->dvobjpriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - struct xmit_frame *pxmitframe = (struct xmit_frame *)wmem; - struct usb_device *pusbd = pdvobj->pusbdev; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - - if ((padapter->driver_stopped) || (padapter->surprise_removed) || - (padapter->pwrctrlpriv.pnp_bstop_trx)) - return _FAIL; - for (i = 0; i < 8; i++) { - if (!pxmitframe->bpending[i]) { - spin_lock_irqsave(&pxmitpriv->lock, irqL); - pxmitpriv->txirp_cnt++; - pxmitframe->bpending[i] = true; - switch (pattrib->priority) { - case 1: - case 2: - pxmitpriv->bkq_cnt++; - break; - case 4: - case 5: - pxmitpriv->viq_cnt++; - break; - case 6: - case 7: - pxmitpriv->voq_cnt++; - break; - case 0: - case 3: - default: - pxmitpriv->beq_cnt++; - break; - } - spin_unlock_irqrestore(&pxmitpriv->lock, irqL); - pxmitframe->sz[i] = (u16)cnt; - purb = pxmitframe->pxmit_urb[i]; - break; - } - } - bwritezero = false; - if (pdvobj->ishighspeed) { - if (cnt > 0 && cnt % 512 == 0) - bwritezero = true; - } else { - if (cnt > 0 && cnt % 64 == 0) - bwritezero = true; - } - /* translate DMA FIFO addr to pipehandle */ - pipe = ffaddr2pipehdl(pdvobj, addr); - if (pxmitpriv->free_xmitbuf_cnt % NR_XMITBUFF == 0) - purb->transfer_flags &= (~URB_NO_INTERRUPT); - else - purb->transfer_flags |= URB_NO_INTERRUPT; - if (bwritezero) - cnt += 8; - usb_fill_bulk_urb(purb, pusbd, pipe, - pxmitframe->mem_addr, - cnt, usb_write_port_complete, - pxmitframe); /* context is xmit_frame */ - status = usb_submit_urb(purb, GFP_ATOMIC); - if (!status) - ret = _SUCCESS; - else - ret = _FAIL; - return ret; -} - -void r8712_usb_write_port_cancel(struct _adapter *padapter) -{ - int i, j; - struct xmit_buf *pxmitbuf = (struct xmit_buf *) - padapter->xmitpriv.pxmitbuf; - - for (i = 0; i < NR_XMITBUFF; i++) { - for (j = 0; j < 8; j++) { - if (pxmitbuf->pxmit_urb[j]) - usb_kill_urb(pxmitbuf->pxmit_urb[j]); - } - pxmitbuf++; - } -} - -int r8712_usbctrl_vendorreq(struct intf_priv *pintfpriv, u8 request, u16 value, - u16 index, void *pdata, u16 len, u8 requesttype) -{ - unsigned int pipe; - int status; - u8 reqtype; - struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *) - pintfpriv->intf_dev; - struct usb_device *udev = pdvobjpriv->pusbdev; - /* For mstar platform, mstar suggests the address for USB IO - * should be 16 bytes alignment. Trying to fix it here. - */ - u8 *palloc_buf, *pIo_buf; - - palloc_buf = kmalloc((u32)len + 16, GFP_ATOMIC); - if (!palloc_buf) - return -ENOMEM; - pIo_buf = palloc_buf + 16 - ((addr_t)(palloc_buf) & 0x0f); - if (requesttype == 0x01) { - pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ - reqtype = RTL871X_VENQT_READ; - } else { - pipe = usb_sndctrlpipe(udev, 0); /* write_out */ - reqtype = RTL871X_VENQT_WRITE; - memcpy(pIo_buf, pdata, len); - } - status = usb_control_msg(udev, pipe, request, reqtype, value, index, - pIo_buf, len, 500); - if (status < 0) - goto free; - if (status != len) { - status = -EREMOTEIO; - goto free; - } - /* Success this control transfer. */ - if (requesttype == 0x01) { - /* For Control read transfer, we have to copy the read - * data from pIo_buf to pdata. - */ - memcpy(pdata, pIo_buf, status); - } - -free: - kfree(palloc_buf); - return status; -} diff --git a/drivers/staging/rtl8712/usb_osintf.h b/drivers/staging/rtl8712/usb_osintf.h deleted file mode 100644 index 2e512b4a564c21..00000000000000 --- a/drivers/staging/rtl8712/usb_osintf.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __USB_OSINTF_H -#define __USB_OSINTF_H - -#include "osdep_service.h" -#include "drv_types.h" - -extern char *r8712_initmac; - -unsigned int r8712_usb_inirp_init(struct _adapter *padapter); -unsigned int r8712_usb_inirp_deinit(struct _adapter *padapter); -uint rtl871x_hal_init(struct _adapter *padapter); -uint rtl8712_hal_deinit(struct _adapter *padapter); - -void rtl871x_intf_stop(struct _adapter *padapter); -void r871x_dev_unload(struct _adapter *padapter); -void r8712_stop_drv_threads(struct _adapter *padapter); -void r8712_stop_drv_timers(struct _adapter *padapter); -int r8712_init_drv_sw(struct _adapter *padapter); -void r8712_free_drv_sw(struct _adapter *padapter); -struct net_device *r8712_init_netdev(void); - -#endif diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h deleted file mode 100644 index 498e6dec7e67f6..00000000000000 --- a/drivers/staging/rtl8712/wifi.h +++ /dev/null @@ -1,196 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef _WIFI_H_ -#define _WIFI_H_ - -#include -#include - -#define WLAN_HDR_A3_LEN 24 -#define WLAN_HDR_A3_QOS_LEN 26 - -enum WIFI_FRAME_TYPE { - WIFI_QOS_DATA_TYPE = (BIT(7) | BIT(3)), /*!< QoS Data */ -}; - -#define SetToDs(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_TODS); \ -}) - -#define GetToDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(IEEE80211_FCTL_TODS)) != 0) - -#define ClearToDs(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_TODS)); \ -}) - -#define SetFrDs(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_FROMDS); \ -}) - -#define GetFrDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(IEEE80211_FCTL_FROMDS)) != 0) - -#define ClearFrDs(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_FROMDS)); \ -}) - -static inline unsigned char get_tofr_ds(unsigned char *pframe) -{ - return ((GetToDs(pframe) << 1) | GetFrDs(pframe)); -} - -#define SetMFrag(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); \ -}) - -#define GetMFrag(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) != 0) - -#define ClearMFrag(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)); \ -}) - -#define SetRetry(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_RETRY); \ -}) - -#define GetRetry(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(IEEE80211_FCTL_RETRY)) != 0) - -#define ClearRetry(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_RETRY)); \ -}) - -#define SetPwrMgt(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PM); \ -}) - -#define GetPwrMgt(pbuf) (((*(__le16 *)(pbuf)) & \ - cpu_to_le16(IEEE80211_FCTL_PM)) != 0) - -#define ClearPwrMgt(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_PM)); \ -}) - -#define SetMData(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); \ -}) - -#define GetMData(pbuf) (((*(__le16 *)(pbuf)) & \ - cpu_to_le16(IEEE80211_FCTL_MOREDATA)) != 0) - -#define ClearMData(pbuf) ({ \ - *(__le16 *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_MOREDATA)); \ -}) - -#define SetPrivacy(pbuf) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); \ -}) - -#define GetPrivacy(pbuf) (((*(__le16 *)(pbuf)) & \ - cpu_to_le16(IEEE80211_FCTL_PROTECTED)) != 0) - -#define GetOrder(pbuf) (((*(__le16 *)(pbuf)) & \ - cpu_to_le16(IEEE80211_FCTL_ORDER)) != 0) - -#define GetFrameType(pbuf) (le16_to_cpu(*(__le16 *)(pbuf)) & \ - (BIT(3) | BIT(2))) - -#define SetFrameType(pbuf, type) \ - do { \ - *(__le16 *)(pbuf) &= cpu_to_le16(~(BIT(3) | \ - BIT(2))); \ - *(__le16 *)(pbuf) |= cpu_to_le16(type); \ - } while (0) - -#define GetFrameSubType(pbuf) (le16_to_cpu(*(__le16 *)(pbuf)) & \ - (BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | \ - BIT(2))) - -#define SetFrameSubType(pbuf, type) \ - do { \ - *(__le16 *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | \ - BIT(5) | BIT(4) | BIT(3) | BIT(2))); \ - *(__le16 *)(pbuf) |= cpu_to_le16(type); \ - } while (0) - -#define GetSequence(pbuf) (le16_to_cpu(*(__le16 *)\ - ((addr_t)(pbuf) + 22)) >> 4) - -#define GetFragNum(pbuf) (le16_to_cpu(*(__le16 *)((addr_t)\ - (pbuf) + 22)) & 0x0f) - -#define SetSeqNum(pbuf, num) ({ \ - *(__le16 *)((addr_t)(pbuf) + 22) = \ - cpu_to_le16((le16_to_cpu(*(__le16 *)((addr_t)(pbuf) + 22)) & \ - 0x000f) | (0xfff0 & (num << 4))); \ -}) - -#define SetPriority(pbuf, tid) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf); \ -}) - -#define GetPriority(pbuf) ((le16_to_cpu(*(__le16 *)(pbuf))) & 0xf) - -#define SetAckpolicy(pbuf, ack) ({ \ - *(__le16 *)(pbuf) |= cpu_to_le16((ack & 3) << 5); \ -}) - -#define GetAckpolicy(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 5) & 0x3) - -#define GetAMsdu(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 7) & 0x1) - -#define GetAddr1Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 4)) - -#define GetAddr2Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 10)) - -#define GetAddr3Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 16)) - -#define GetAddr4Ptr(pbuf) ((unsigned char *)((addr_t)(pbuf) + 24)) - -static inline unsigned char *get_hdr_bssid(unsigned char *pframe) -{ - unsigned char *sa; - unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); - - switch (to_fr_ds) { - case 0x00: /* ToDs=0, FromDs=0 */ - sa = GetAddr3Ptr(pframe); - break; - case 0x01: /* ToDs=0, FromDs=1 */ - sa = GetAddr2Ptr(pframe); - break; - case 0x02: /* ToDs=1, FromDs=0 */ - sa = GetAddr1Ptr(pframe); - break; - default: /* ToDs=1, FromDs=1 */ - sa = NULL; - break; - } - return sa; -} - -/* --------------------------------------------------------------------------- - * Below is the fixed elements... - * --------------------------------------------------------------------------- - */ -#define _BEACON_ITERVAL_ 2 -#define _CAPABILITY_ 2 -#define _TIMESTAMP_ 8 - -/*----------------------------------------------------------------------------- - * Below is the definition for WMM - *------------------------------------------------------------------------------ - */ -#define _WMM_IE_Length_ 7 /* for WMM STA */ - -#endif /* _WIFI_H_ */ - diff --git a/drivers/staging/rtl8712/wlan_bssdef.h b/drivers/staging/rtl8712/wlan_bssdef.h deleted file mode 100644 index ec3749813728d9..00000000000000 --- a/drivers/staging/rtl8712/wlan_bssdef.h +++ /dev/null @@ -1,223 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __WLAN_BSSDEF_H__ -#define __WLAN_BSSDEF_H__ - -#define MAX_IE_SZ 768 - -#define NDIS_802_11_LENGTH_SSID 32 -#define NDIS_802_11_LENGTH_RATES 8 -#define NDIS_802_11_LENGTH_RATES_EX 16 - -struct ndis_802_11_ssid { - u32 SsidLength; - u8 Ssid[32]; -}; - -enum NDIS_802_11_NETWORK_TYPE { - Ndis802_11FH, - Ndis802_11DS, - Ndis802_11OFDM5, - Ndis802_11OFDM24, - Ndis802_11NetworkTypeMax /* not a real type, defined as an upper bound*/ -}; - -struct NDIS_802_11_CONFIGURATION_FH { - u32 Length; /* Length of structure */ - u32 HopPattern; /* As defined by 802.11, MSB set */ - u32 HopSet; /* to one if non-802.11 */ - u32 DwellTime; /* units are Kusec */ -}; - -/* - * FW will only save the channel number in DSConfig. - * ODI Handler will convert the channel number to freq. number. - */ -struct NDIS_802_11_CONFIGURATION { - u32 Length; /* Length of structure */ - u32 BeaconPeriod; /* units are Kusec */ - u32 ATIMWindow; /* units are Kusec */ - u32 DSConfig; /* Frequency, units are kHz */ - struct NDIS_802_11_CONFIGURATION_FH FHConfig; -}; - -enum NDIS_802_11_NETWORK_INFRASTRUCTURE { - Ndis802_11IBSS, - Ndis802_11Infrastructure, - Ndis802_11AutoUnknown, - Ndis802_11InfrastructureMax, /*Not a real value,defined as upper bound*/ - Ndis802_11APMode -}; - -struct NDIS_802_11_FIXED_IEs { - u8 Timestamp[8]; - u16 BeaconInterval; - u16 Capabilities; -}; - -struct wlan_bssid_ex { - u32 Length; - unsigned char MacAddress[6]; - u8 Reserved[2]; - struct ndis_802_11_ssid Ssid; - __le32 Privacy; - s32 Rssi; - enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; - struct NDIS_802_11_CONFIGURATION Configuration; - enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - u8 rates[NDIS_802_11_LENGTH_RATES_EX]; - /* number of content bytes in EIs, which varies */ - u32 IELength; - /*(timestamp, beacon interval, and capability information) */ - u8 IEs[MAX_IE_SZ]; -}; - -enum NDIS_802_11_AUTHENTICATION_MODE { - Ndis802_11AuthModeOpen, - Ndis802_11AuthModeShared, - Ndis802_11AuthModeAutoSwitch, - Ndis802_11AuthModeWPA, - Ndis802_11AuthModeWPAPSK, - Ndis802_11AuthModeWPANone, - Ndis802_11AuthModeMax /* Not a real mode, defined as upper bound */ -}; - -enum { - Ndis802_11WEPEnabled, - Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, - Ndis802_11WEPDisabled, - Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, - Ndis802_11WEPKeyAbsent, - Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, - Ndis802_11WEPNotSupported, - Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, - Ndis802_11Encryption2Enabled, - Ndis802_11Encryption2KeyAbsent, - Ndis802_11Encryption3Enabled, - Ndis802_11Encryption3KeyAbsent -}; - -#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 -#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 -#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 - -#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 -#define NDIS_802_11_AI_RESFI_STATUSCODE 2 -#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 - -struct NDIS_802_11_AI_REQFI { - u16 Capabilities; - u16 ListenInterval; - unsigned char CurrentAPAddress[6]; -}; - -struct NDIS_802_11_AI_RESFI { - u16 Capabilities; - u16 StatusCode; - u16 AssociationId; -}; - -struct NDIS_802_11_ASSOCIATION_INFORMATION { - u32 Length; - u16 AvailableRequestFixedIEs; - struct NDIS_802_11_AI_REQFI RequestFixedIEs; - u32 RequestIELength; - u32 OffsetRequestIEs; - u16 AvailableResponseFixedIEs; - struct NDIS_802_11_AI_RESFI ResponseFixedIEs; - u32 ResponseIELength; - u32 OffsetResponseIEs; -}; - -/* Key mapping keys require a BSSID*/ -struct NDIS_802_11_KEY { - u32 Length; /* Length of this structure */ - u32 KeyIndex; - u32 KeyLength; /* length of key in bytes */ - unsigned char BSSID[6]; - unsigned long long KeyRSC; - u8 KeyMaterial[32]; /* variable length */ -}; - -struct NDIS_802_11_REMOVE_KEY { - u32 Length; /* Length of this structure */ - u32 KeyIndex; - unsigned char BSSID[6]; -}; - -struct NDIS_802_11_WEP { - u32 Length; /* Length of this structure */ - u32 KeyIndex; /* 0 is the per-client key, - * 1-N are the global keys - */ - u32 KeyLength; /* length of key in bytes */ - u8 KeyMaterial[16]; /* variable length depending on above field */ -}; - -/* mask for authentication/integrity fields */ -#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f -#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 -#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 -#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 -#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E - -/* MIC check time, 60 seconds. */ -#define MIC_CHECK_TIME 60000000 - -#ifndef Ndis802_11APMode -#define Ndis802_11APMode (Ndis802_11InfrastructureMax + 1) -#endif - -struct wlan_network { - struct list_head list; - int network_type; /*refer to ieee80211.h for WIRELESS_11A/B/G */ - int fixed; /* set to fixed when not to be removed asi - * site-surveying - */ - unsigned int last_scanned; /*timestamp for the network */ - int aid; /*will only be valid when a BSS is joined. */ - int join_res; - struct wlan_bssid_ex network; /*must be the last item */ -}; - -enum VRTL_CARRIER_SENSE { - DISABLE_VCS, - ENABLE_VCS, - AUTO_VCS -}; - -enum VCS_TYPE { - NONE_VCS, - RTS_CTS, - CTS_TO_SELF -}; - -#define PWR_CAM 0 -#define PWR_MINPS 1 -#define PWR_MAXPS 2 -#define PWR_UAPSD 3 -#define PWR_VOIP 4 - -enum UAPSD_MAX_SP { - NO_LIMIT, - TWO_MSDU, - FOUR_MSDU, - SIX_MSDU -}; - -#define NUM_PRE_AUTH_KEY 16 -#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY - -#endif /* #ifndef WLAN_BSSDEF_H_ */ - diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c deleted file mode 100644 index ceb6b590b310fd..00000000000000 --- a/drivers/staging/rtl8712/xmit_linux.c +++ /dev/null @@ -1,181 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/****************************************************************************** - * xmit_linux.c - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * Linux device driver for RTL8192SU - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ - -#define _XMIT_OSDEP_C_ - -#include -#include -#include -#include - -#include "osdep_service.h" -#include "drv_types.h" - -#include "wifi.h" -#include "mlme_osdep.h" -#include "xmit_osdep.h" -#include "osdep_intf.h" - -static uint remainder_len(struct pkt_file *pfile) -{ - return (uint)(pfile->buf_len - ((addr_t)(pfile->cur_addr) - - (addr_t)(pfile->buf_start))); -} - -void _r8712_open_pktfile(_pkt *pktptr, struct pkt_file *pfile) -{ - pfile->pkt = pktptr; - pfile->cur_addr = pfile->buf_start = pktptr->data; - pfile->pkt_len = pfile->buf_len = pktptr->len; - pfile->cur_buffer = pfile->buf_start; -} - -uint _r8712_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) -{ - uint len; - - len = remainder_len(pfile); - len = (rlen > len) ? len : rlen; - if (rmem) - skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, - rmem, len); - pfile->cur_addr += len; - pfile->pkt_len -= len; - return len; -} - -sint r8712_endofpktfile(struct pkt_file *pfile) -{ - return (pfile->pkt_len == 0); -} - -void r8712_set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) -{ - struct ethhdr etherhdr; - struct iphdr ip_hdr; - u16 user_priority = 0; - - _r8712_open_pktfile(ppktfile->pkt, ppktfile); - _r8712_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); - - /* get user_priority from IP hdr*/ - if (pattrib->ether_type == 0x0800) { - _r8712_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); - /*user_priority = (ntohs(ip_hdr.tos) >> 5) & 0x3 ;*/ - user_priority = ip_hdr.tos >> 5; - } else { - /* "When priority processing of data frames is supported, - * a STA's SME should send EAPOL-Key frames at the highest - * priority." - */ - - if (pattrib->ether_type == 0x888e) - user_priority = 7; - } - pattrib->priority = user_priority; - pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; - pattrib->subtype = WIFI_QOS_DATA_TYPE; -} - -void r8712_SetFilter(struct work_struct *work) -{ - struct _adapter *adapter = container_of(work, struct _adapter, - wk_filter_rx_ff0); - u8 oldvalue = 0x00, newvalue = 0x00; - - oldvalue = r8712_read8(adapter, 0x117); - newvalue = oldvalue & 0xfe; - r8712_write8(adapter, 0x117, newvalue); - - wait_for_completion(&adapter->rx_filter_ready); - r8712_write8(adapter, 0x117, oldvalue); -} - -int r8712_xmit_resource_alloc(struct _adapter *padapter, - struct xmit_buf *pxmitbuf) -{ - int i; - - for (i = 0; i < 8; i++) { - pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!pxmitbuf->pxmit_urb[i]) { - int k; - - for (k = i - 1; k >= 0; k--) { - /* handle allocation errors part way through loop */ - usb_free_urb(pxmitbuf->pxmit_urb[k]); - } - netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n"); - return -ENOMEM; - } - kmemleak_not_leak(pxmitbuf->pxmit_urb[i]); - } - return 0; -} - -void r8712_xmit_resource_free(struct _adapter *padapter, - struct xmit_buf *pxmitbuf) -{ - int i; - - for (i = 0; i < 8; i++) { - if (pxmitbuf->pxmit_urb[i]) { - usb_kill_urb(pxmitbuf->pxmit_urb[i]); - usb_free_urb(pxmitbuf->pxmit_urb[i]); - } - } -} - -void r8712_xmit_complete(struct _adapter *padapter, struct xmit_frame *pxframe) -{ - if (pxframe->pkt) - dev_kfree_skb_any(pxframe->pkt); - pxframe->pkt = NULL; -} - -netdev_tx_t r8712_xmit_entry(_pkt *pkt, struct net_device *netdev) -{ - struct xmit_frame *xmitframe = NULL; - struct _adapter *adapter = netdev_priv(netdev); - struct xmit_priv *xmitpriv = &(adapter->xmitpriv); - - if (!r8712_if_up(adapter)) - goto _xmit_entry_drop; - - xmitframe = r8712_alloc_xmitframe(xmitpriv); - if (!xmitframe) - goto _xmit_entry_drop; - - if (r8712_update_attrib(adapter, pkt, &xmitframe->attrib)) - goto _xmit_entry_drop; - - adapter->ledpriv.LedControlHandler(adapter, LED_CTL_TX); - xmitframe->pkt = pkt; - if (r8712_pre_xmit(adapter, xmitframe)) { - /*dump xmitframe directly or drop xframe*/ - dev_kfree_skb_any(pkt); - xmitframe->pkt = NULL; - } - xmitpriv->tx_pkts++; - xmitpriv->tx_bytes += xmitframe->attrib.last_txcmdsz; - return NETDEV_TX_OK; -_xmit_entry_drop: - if (xmitframe) - r8712_free_xmitframe(xmitpriv, xmitframe); - xmitpriv->tx_drop++; - dev_kfree_skb_any(pkt); - return NETDEV_TX_OK; -} diff --git a/drivers/staging/rtl8712/xmit_osdep.h b/drivers/staging/rtl8712/xmit_osdep.h deleted file mode 100644 index 1ad42658c8831c..00000000000000 --- a/drivers/staging/rtl8712/xmit_osdep.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE - * Larry Finger - * - ******************************************************************************/ -#ifndef __XMIT_OSDEP_H_ -#define __XMIT_OSDEP_H_ - -#include "osdep_service.h" -#include "drv_types.h" - -struct pkt_file { - _pkt *pkt; - u32 pkt_len; /*the remainder length of the open_file*/ - _buffer *cur_buffer; - u8 *buf_start; - u8 *cur_addr; - u32 buf_len; -}; - -#define NR_XMITFRAME 256 - -struct xmit_priv; -struct pkt_attrib; -struct sta_xmit_priv; -struct xmit_frame; -struct xmit_buf; - -netdev_tx_t r8712_xmit_entry(_pkt *pkt, struct net_device *pnetdev); -void r8712_SetFilter(struct work_struct *work); -int r8712_xmit_resource_alloc(struct _adapter *padapter, - struct xmit_buf *pxmitbuf); -void r8712_xmit_resource_free(struct _adapter *padapter, - struct xmit_buf *pxmitbuf); - -void r8712_set_qos(struct pkt_file *ppktfile, - struct pkt_attrib *pattrib); -void _r8712_open_pktfile(_pkt *pktptr, struct pkt_file *pfile); -uint _r8712_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen); -sint r8712_endofpktfile(struct pkt_file *pfile); -void r8712_xmit_complete(struct _adapter *padapter, - struct xmit_frame *pxframe); - -#endif diff --git a/drivers/staging/rtl8723bs/TODO b/drivers/staging/rtl8723bs/TODO index 3d8f5a634a10b1..050dcd0bffab59 100644 --- a/drivers/staging/rtl8723bs/TODO +++ b/drivers/staging/rtl8723bs/TODO @@ -5,8 +5,4 @@ TODO: - checkpatch.pl fixes - most of the remaining ones are lines too long. Many of them will require refactoring - merge Realtek's bugfixes and new features into the driver -- switch to use LIB80211 - switch to use MAC80211 - -Please send any patches to Greg Kroah-Hartman , -Hans de Goede and Larry Finger . diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 84ce7307d8f3df..64ce33c6fba172 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -382,7 +382,7 @@ int rtw_cmd_thread(void *context) struct cmd_priv *pcmdpriv = &padapter->cmdpriv; struct drvextra_cmd_parm *extra_parm = NULL; - thread_enter("RTW_CMD_THREAD"); + allow_signal(SIGTERM); pcmdbuf = pcmdpriv->cmd_buf; @@ -1258,8 +1258,7 @@ static void dynamic_chk_wk_hdl(struct adapter *padapter) /* always call rtw_ps_processor() at last one. */ - if (is_primary_adapter(padapter)) - rtw_ps_processor(padapter); + rtw_ps_processor(padapter); } void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type); @@ -1465,6 +1464,7 @@ u8 rtw_ps_cmd(struct adapter *padapter) struct drvextra_cmd_parm *pdrvextra_cmd_parm; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; u8 res = _SUCCESS; + ppscmd = rtw_zmalloc(sizeof(struct cmd_obj)); if (!ppscmd) { res = _FAIL; diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 8b671f8a79659f..7a74b011dedc2a 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -77,33 +77,7 @@ struct adapter *padapter, u8 bWrite, u8 PwrState) { - padapter->HalFunc.EfusePowerSwitch(padapter, bWrite, PwrState); -} - -/*----------------------------------------------------------------------------- - * Function: Efuse_GetCurrentSize - * - * Overview: Get current efuse size!!! - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 11/16/2008 MHC Create Version 0. - * - *---------------------------------------------------------------------------*/ -u16 -Efuse_GetCurrentSize( - struct adapter *padapter, - u8 efuseType, - bool bPseudoTest) -{ - return padapter->HalFunc.EfuseGetCurrentSize(padapter, efuseType, - bPseudoTest); + Hal_EfusePowerSwitch(padapter, bWrite, PwrState); } /* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ @@ -159,7 +133,7 @@ efuse_ReadEFuse( bool bPseudoTest ) { - Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); + Hal_ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); } void @@ -171,7 +145,7 @@ EFUSE_GetEfuseDefinition( bool bPseudoTest ) { - padapter->HalFunc.EFUSEGetEfuseDefinition(padapter, efuseType, type, pOut, bPseudoTest); + Hal_GetEfuseDefinition(padapter, efuseType, type, pOut, bPseudoTest); } /*----------------------------------------------------------------------------- @@ -312,68 +286,6 @@ u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoT return bResult; } -int -Efuse_PgPacketRead(struct adapter *padapter, - u8 offset, - u8 *data, - bool bPseudoTest) -{ - return padapter->HalFunc.Efuse_PgPacketRead(padapter, offset, data, - bPseudoTest); -} - -int -Efuse_PgPacketWrite(struct adapter *padapter, - u8 offset, - u8 word_en, - u8 *data, - bool bPseudoTest) -{ - return padapter->HalFunc.Efuse_PgPacketWrite(padapter, offset, word_en, - data, bPseudoTest); -} - -/*----------------------------------------------------------------------------- - * Function: efuse_WordEnableDataRead - * - * Overview: Read allowed word in current efuse section data. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 11/16/2008 MHC Create Version 0. - * 11/21/2008 MHC Fix Write bug when we only enable late word. - * - *---------------------------------------------------------------------------*/ -void -efuse_WordEnableDataRead(u8 word_en, - u8 *sourdata, - u8 *targetdata) -{ - if (!(word_en & BIT(0))) { - targetdata[0] = sourdata[0]; - targetdata[1] = sourdata[1]; - } - if (!(word_en & BIT(1))) { - targetdata[2] = sourdata[2]; - targetdata[3] = sourdata[3]; - } - if (!(word_en & BIT(2))) { - targetdata[4] = sourdata[4]; - targetdata[5] = sourdata[5]; - } - if (!(word_en & BIT(3))) { - targetdata[6] = sourdata[6]; - targetdata[7] = sourdata[7]; - } -} - - u8 Efuse_WordEnableDataWrite(struct adapter *padapter, u16 efuse_addr, diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index cbdb134278d37b..5ded183aa08c49 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -911,8 +911,7 @@ inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted) { rtw_os_indicate_scan_done(padapter, aborted); - if (is_primary_adapter(padapter) && - (!adapter_to_pwrctl(padapter)->bInSuspend) && + if ((!adapter_to_pwrctl(padapter)->bInSuspend) && (!check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE|WIFI_UNDER_LINKING))) { rtw_set_ips_deny(padapter, 0); @@ -1589,8 +1588,7 @@ void rtw_dynamic_check_timer_handler(struct adapter *adapter) } } else { - if (is_primary_adapter(adapter)) - rtw_dynamic_chk_wk_cmd(adapter); + rtw_dynamic_chk_wk_cmd(adapter); } /* auto site survey */ diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 4d4bec47d1874c..317f3db193971c 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -1870,10 +1870,10 @@ unsigned int OnAction_sa_query(struct adapter *padapter, union recv_frame *precv if (0) { int pp; - printk("pattrib->pktlen = %d =>", pattrib->pkt_len); + netdev_dbg(padapter->pnetdev, "pattrib->pktlen = %d =>", pattrib->pkt_len); for (pp = 0; pp < pattrib->pkt_len; pp++) - printk(" %02x ", pframe[pp]); - printk("\n"); + pr_cont(" %02x ", pframe[pp]); + pr_cont("\n"); } return _SUCCESS; @@ -4872,8 +4872,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) /* set_link_timer(pmlmeext, DISCONNECT_TO); */ } - if (get_iface_type(padapter) == IFACE_PORT0) - rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); + rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); } /* currently only adhoc mode will go here */ @@ -5638,7 +5637,7 @@ u8 setkey_hdl(struct adapter *padapter, u8 *pbuf) rtw_hal_set_hwreg(padapter, HW_VAR_SEC_DK_CFG, (u8 *)true); /* allow multicast packets to driver */ - padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_ON_RCR_AM, null_addr); + SetHwReg8723BS(padapter, HW_VAR_ON_RCR_AM, null_addr); return H2C_SUCCESS; } diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index dbfcbac3d85554..c60e179bb2e196 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -73,9 +73,6 @@ int ips_leave(struct adapter *padapter) struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); int ret; - if (!is_primary_adapter(padapter)) - return _SUCCESS; - mutex_lock(&pwrpriv->lock); ret = _ips_leave(padapter); mutex_unlock(&pwrpriv->lock); @@ -455,10 +452,6 @@ void LPS_Enter(struct adapter *padapter, const char *msg) if (n_assoc_iface != 1) return; - /* Skip lps enter request for adapter not port0 */ - if (get_iface_type(padapter) != IFACE_PORT0) - return; - if (!PS_RDY_CHECK(dvobj->padapters)) return; diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index f37fec1efaf91c..73c70b016f0097 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -290,21 +290,11 @@ inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch) dvobj->oper_channel = ch; } -inline u8 rtw_get_oper_bw(struct adapter *adapter) -{ - return adapter_to_dvobj(adapter)->oper_bwmode; -} - inline void rtw_set_oper_bw(struct adapter *adapter, u8 bw) { adapter_to_dvobj(adapter)->oper_bwmode = bw; } -inline u8 rtw_get_oper_choffset(struct adapter *adapter) -{ - return adapter_to_dvobj(adapter)->oper_ch_offset; -} - inline void rtw_set_oper_choffset(struct adapter *adapter, u8 offset) { adapter_to_dvobj(adapter)->oper_ch_offset = offset; @@ -445,34 +435,6 @@ void invalidate_cam_all(struct adapter *padapter) spin_unlock_bh(&cam_ctl->lock); } -static u32 _ReadCAM(struct adapter *padapter, u32 addr) -{ - u32 count = 0, cmd; - - cmd = CAM_POLLINIG | addr; - rtw_write32(padapter, RWCAM, cmd); - - do { - if (0 == (rtw_read32(padapter, REG_CAMCMD) & CAM_POLLINIG)) - break; - } while (count++ < 100); - - return rtw_read32(padapter, REG_CAMREAD); -} - -void read_cam(struct adapter *padapter, u8 entry, u8 *get_key) -{ - u32 j, addr, cmd; - - addr = entry << 3; - - for (j = 0; j < 6; j++) { - cmd = _ReadCAM(padapter, addr+j); - if (j > 1) /* get key from cam */ - memcpy(get_key+(j-2)*4, &cmd, 4); - } -} - void _write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) { unsigned int i, val, addr; @@ -1613,9 +1575,9 @@ void update_wireless_mode(struct adapter *padapter) SIFS_Timer = 0x0a0a0808; /* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ /* change this value if having IOT issues. */ - padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); + SetHwReg8723BS(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); - padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_WIRELESS_MODE, (u8 *)&(pmlmeext->cur_wireless_mode)); + SetHwReg8723BS(padapter, HW_VAR_WIRELESS_MODE, (u8 *)&(pmlmeext->cur_wireless_mode)); if (pmlmeext->cur_wireless_mode & WIRELESS_11B) update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); @@ -1822,29 +1784,3 @@ void rtw_release_macid(struct adapter *padapter, struct sta_info *psta) } spin_unlock_bh(&pdvobj->lock); } - -/* For 8188E RA */ -u8 rtw_search_max_mac_id(struct adapter *padapter) -{ - u8 max_mac_id = 0; - struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); - int i; - - spin_lock_bh(&pdvobj->lock); - for (i = (NUM_STA-1); i >= 0 ; i--) { - if (pdvobj->macid[i] == true) - break; - } - max_mac_id = i; - spin_unlock_bh(&pdvobj->lock); - - return max_mac_id; -} - -struct adapter *dvobj_get_port0_adapter(struct dvobj_priv *dvobj) -{ - if (get_iface_type(dvobj->padapters[i]) != IFACE_PORT0) - return NULL; - - return dvobj->padapters; -} diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 3e88f14e3bf78a..699cff7b0ac955 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -2489,7 +2489,7 @@ int rtw_xmit_thread(void *context) err = _SUCCESS; padapter = context; - thread_enter("RTW_XMIT_THREAD"); + allow_signal(SIGTERM); do { err = rtw_hal_xmit_thread_handler(padapter); diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index 719dd116d8076a..95fb38283c582a 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -13,23 +13,20 @@ u8 rtw_hal_data_init(struct adapter *padapter) { - if (is_primary_adapter(padapter)) { /* if (padapter->isprimary) */ - padapter->hal_data_sz = sizeof(struct hal_com_data); - padapter->HalData = vzalloc(padapter->hal_data_sz); - if (!padapter->HalData) - return _FAIL; - } + padapter->hal_data_sz = sizeof(struct hal_com_data); + padapter->HalData = vzalloc(padapter->hal_data_sz); + if (!padapter->HalData) + return _FAIL; + return _SUCCESS; } void rtw_hal_data_deinit(struct adapter *padapter) { - if (is_primary_adapter(padapter)) { /* if (padapter->isprimary) */ - if (padapter->HalData) { - vfree(padapter->HalData); - padapter->HalData = NULL; - padapter->hal_data_sz = 0; - } + if (padapter->HalData) { + vfree(padapter->HalData); + padapter->HalData = NULL; + padapter->hal_data_sz = 0; } } @@ -796,19 +793,6 @@ u8 GetHalDefVar( return bResult; } -void GetHalODMVar( - struct adapter *Adapter, - enum hal_odm_variable eVariable, - void *pValue1, - void *pValue2 -) -{ - switch (eVariable) { - default: - break; - } -} - void SetHalODMVar( struct adapter *Adapter, enum hal_odm_variable eVariable, @@ -883,7 +867,6 @@ void rtw_hal_check_rxfifo_full(struct adapter *adapter) int save_cnt = false; /* switch counter to RX fifo */ - /* printk("8723b or 8192e , MAC_667 set 0xf0\n"); */ rtw_write8(adapter, REG_RXERR_RPT+3, rtw_read8(adapter, REG_RXERR_RPT+3)|0xf0); save_cnt = true; /* todo: other chips */ @@ -910,10 +893,9 @@ void rtw_dump_raw_rssi_info(struct adapter *padapter) for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { if (!isCCKrate) { - printk(", rx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n", - psample_pkt_rssi->ofdm_pwr[rf_path], psample_pkt_rssi->ofdm_snr[rf_path]); - } else { - printk("\n"); + netdev_dbg(padapter->pnetdev, ", rx_ofdm_pwr:%d(dBm), rx_ofdm_snr:%d(dB)\n", + psample_pkt_rssi->ofdm_pwr[rf_path], + psample_pkt_rssi->ofdm_snr[rf_path]); } } } diff --git a/drivers/staging/rtl8723bs/hal/hal_intf.c b/drivers/staging/rtl8723bs/hal/hal_intf.c index 0a3900548fd2ca..0db8f623b8059a 100644 --- a/drivers/staging/rtl8723bs/hal/hal_intf.c +++ b/drivers/staging/rtl8723bs/hal/hal_intf.c @@ -9,52 +9,37 @@ void rtw_hal_chip_configure(struct adapter *padapter) { - if (padapter->HalFunc.intf_chip_configure) - padapter->HalFunc.intf_chip_configure(padapter); + rtl8723bs_interface_configure(padapter); } void rtw_hal_read_chip_info(struct adapter *padapter) { - if (padapter->HalFunc.read_adapter_info) - padapter->HalFunc.read_adapter_info(padapter); + ReadAdapterInfo8723BS(padapter); } void rtw_hal_read_chip_version(struct adapter *padapter) { - if (padapter->HalFunc.read_chip_version) - padapter->HalFunc.read_chip_version(padapter); + rtl8723b_read_chip_version(padapter); } void rtw_hal_def_value_init(struct adapter *padapter) { - if (is_primary_adapter(padapter)) - if (padapter->HalFunc.init_default_value) - padapter->HalFunc.init_default_value(padapter); + rtl8723bs_init_default_value(padapter); } void rtw_hal_free_data(struct adapter *padapter) { /* free HAL Data */ rtw_hal_data_deinit(padapter); - - if (is_primary_adapter(padapter)) - if (padapter->HalFunc.free_hal_data) - padapter->HalFunc.free_hal_data(padapter); } void rtw_hal_dm_init(struct adapter *padapter) { - if (is_primary_adapter(padapter)) - if (padapter->HalFunc.dm_init) - padapter->HalFunc.dm_init(padapter); + rtl8723b_init_dm_priv(padapter); } void rtw_hal_dm_deinit(struct adapter *padapter) { - /* cancel dm timer */ - if (is_primary_adapter(padapter)) - if (padapter->HalFunc.dm_deinit) - padapter->HalFunc.dm_deinit(padapter); } static void rtw_hal_init_opmode(struct adapter *padapter) @@ -82,7 +67,7 @@ uint rtw_hal_init(struct adapter *padapter) uint status; struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); - status = padapter->HalFunc.hal_init(padapter); + status = rtl8723bs_hal_init(padapter); if (status == _SUCCESS) { rtw_hal_init_opmode(padapter); @@ -111,7 +96,7 @@ uint rtw_hal_deinit(struct adapter *padapter) uint status = _SUCCESS; struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); - status = padapter->HalFunc.hal_deinit(padapter); + status = rtl8723bs_hal_deinit(padapter); if (status == _SUCCESS) { padapter = dvobj->padapters; @@ -123,34 +108,27 @@ uint rtw_hal_deinit(struct adapter *padapter) void rtw_hal_set_hwreg(struct adapter *padapter, u8 variable, u8 *val) { - if (padapter->HalFunc.SetHwRegHandler) - padapter->HalFunc.SetHwRegHandler(padapter, variable, val); + SetHwReg8723BS(padapter, variable, val); } void rtw_hal_get_hwreg(struct adapter *padapter, u8 variable, u8 *val) { - if (padapter->HalFunc.GetHwRegHandler) - padapter->HalFunc.GetHwRegHandler(padapter, variable, val); + GetHwReg8723BS(padapter, variable, val); } void rtw_hal_set_hwreg_with_buf(struct adapter *padapter, u8 variable, u8 *pbuf, int len) { - if (padapter->HalFunc.SetHwRegHandlerWithBuf) - padapter->HalFunc.SetHwRegHandlerWithBuf(padapter, variable, pbuf, len); + SetHwRegWithBuf8723B(padapter, variable, pbuf, len); } u8 rtw_hal_set_def_var(struct adapter *padapter, enum hal_def_variable eVariable, void *pValue) { - if (padapter->HalFunc.SetHalDefVarHandler) - return padapter->HalFunc.SetHalDefVarHandler(padapter, eVariable, pValue); - return _FAIL; + return SetHalDefVar8723BSDIO(padapter, eVariable, pValue); } u8 rtw_hal_get_def_var(struct adapter *padapter, enum hal_def_variable eVariable, void *pValue) { - if (padapter->HalFunc.GetHalDefVarHandler) - return padapter->HalFunc.GetHalDefVarHandler(padapter, eVariable, pValue); - return _FAIL; + return GetHalDefVar8723BSDIO(padapter, eVariable, pValue); } void rtw_hal_set_odm_var(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) @@ -161,40 +139,27 @@ void rtw_hal_set_odm_var(struct adapter *padapter, enum hal_odm_variable eVariab void rtw_hal_enable_interrupt(struct adapter *padapter) { - if (padapter->HalFunc.enable_interrupt) - padapter->HalFunc.enable_interrupt(padapter); + EnableInterrupt8723BSdio(padapter); } void rtw_hal_disable_interrupt(struct adapter *padapter) { - if (padapter->HalFunc.disable_interrupt) - padapter->HalFunc.disable_interrupt(padapter); + DisableInterrupt8723BSdio(padapter); } u8 rtw_hal_check_ips_status(struct adapter *padapter) { - u8 val = false; - - if (padapter->HalFunc.check_ips_status) - val = padapter->HalFunc.check_ips_status(padapter); - - return val; + return CheckIPSStatus(padapter); } s32 rtw_hal_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) { - if (padapter->HalFunc.hal_xmitframe_enqueue) - return padapter->HalFunc.hal_xmitframe_enqueue(padapter, pxmitframe); - - return false; + return rtl8723bs_hal_xmitframe_enqueue(padapter, pxmitframe); } s32 rtw_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe) { - if (padapter->HalFunc.hal_xmit) - return padapter->HalFunc.hal_xmit(padapter, pxmitframe); - - return false; + return rtl8723bs_hal_xmit(padapter, pxmitframe); } /* @@ -202,8 +167,6 @@ s32 rtw_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe) */ s32 rtw_hal_mgnt_xmit(struct adapter *padapter, struct xmit_frame *pmgntframe) { - s32 ret = _FAIL; - update_mgntframe_attrib_addr(padapter, pmgntframe); /* pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; */ /* pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; */ @@ -220,36 +183,27 @@ s32 rtw_hal_mgnt_xmit(struct adapter *padapter, struct xmit_frame *pmgntframe) rtw_mgmt_xmitframe_coalesce(padapter, pmgntframe->pkt, pmgntframe); } - if (padapter->HalFunc.mgnt_xmit) - ret = padapter->HalFunc.mgnt_xmit(padapter, pmgntframe); - return ret; + return rtl8723bs_mgnt_xmit(padapter, pmgntframe); } s32 rtw_hal_init_xmit_priv(struct adapter *padapter) { - if (padapter->HalFunc.init_xmit_priv) - return padapter->HalFunc.init_xmit_priv(padapter); - return _FAIL; + return rtl8723bs_init_xmit_priv(padapter); } void rtw_hal_free_xmit_priv(struct adapter *padapter) { - if (padapter->HalFunc.free_xmit_priv) - padapter->HalFunc.free_xmit_priv(padapter); + rtl8723bs_free_xmit_priv(padapter); } s32 rtw_hal_init_recv_priv(struct adapter *padapter) { - if (padapter->HalFunc.init_recv_priv) - return padapter->HalFunc.init_recv_priv(padapter); - - return _FAIL; + return rtl8723bs_init_recv_priv(padapter); } void rtw_hal_free_recv_priv(struct adapter *padapter) { - if (padapter->HalFunc.free_recv_priv) - padapter->HalFunc.free_recv_priv(padapter); + rtl8723bs_free_recv_priv(padapter); } void rtw_hal_update_ra_mask(struct sta_info *psta, u8 rssi_level) @@ -267,91 +221,70 @@ void rtw_hal_update_ra_mask(struct sta_info *psta, u8 rssi_level) if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) add_RATid(padapter, psta, rssi_level); else { - if (padapter->HalFunc.UpdateRAMaskHandler) - padapter->HalFunc.UpdateRAMaskHandler(padapter, psta->mac_id, rssi_level); + UpdateHalRAMask8723B(padapter, psta->mac_id, rssi_level); } } void rtw_hal_add_ra_tid(struct adapter *padapter, u32 bitmap, u8 *arg, u8 rssi_level) { - if (padapter->HalFunc.Add_RateATid) - padapter->HalFunc.Add_RateATid(padapter, bitmap, arg, rssi_level); + rtl8723b_Add_RateATid(padapter, bitmap, arg, rssi_level); } /*Start specifical interface thread */ void rtw_hal_start_thread(struct adapter *padapter) { - if (padapter->HalFunc.run_thread) - padapter->HalFunc.run_thread(padapter); + rtl8723b_start_thread(padapter); } /*Start specifical interface thread */ void rtw_hal_stop_thread(struct adapter *padapter) { - if (padapter->HalFunc.cancel_thread) - padapter->HalFunc.cancel_thread(padapter); + rtl8723b_stop_thread(padapter); } u32 rtw_hal_read_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask) { - u32 data = 0; - - if (padapter->HalFunc.read_bbreg) - data = padapter->HalFunc.read_bbreg(padapter, RegAddr, BitMask); - return data; + return PHY_QueryBBReg_8723B(padapter, RegAddr, BitMask); } void rtw_hal_write_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data) { - if (padapter->HalFunc.write_bbreg) - padapter->HalFunc.write_bbreg(padapter, RegAddr, BitMask, Data); + PHY_SetBBReg_8723B(padapter, RegAddr, BitMask, Data); } u32 rtw_hal_read_rfreg(struct adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask) { - u32 data = 0; - - if (padapter->HalFunc.read_rfreg) - data = padapter->HalFunc.read_rfreg(padapter, eRFPath, RegAddr, BitMask); - return data; + return PHY_QueryRFReg_8723B(padapter, eRFPath, RegAddr, BitMask); } void rtw_hal_write_rfreg(struct adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) { - if (padapter->HalFunc.write_rfreg) - padapter->HalFunc.write_rfreg(padapter, eRFPath, RegAddr, BitMask, Data); + PHY_SetRFReg_8723B(padapter, eRFPath, RegAddr, BitMask, Data); } void rtw_hal_set_chan(struct adapter *padapter, u8 channel) { - if (padapter->HalFunc.set_channel_handler) - padapter->HalFunc.set_channel_handler(padapter, channel); + PHY_SwChnl8723B(padapter, channel); } void rtw_hal_set_chnl_bw(struct adapter *padapter, u8 channel, enum channel_width Bandwidth, u8 Offset40, u8 Offset80) { - if (padapter->HalFunc.set_chnl_bw_handler) - padapter->HalFunc.set_chnl_bw_handler(padapter, channel, - Bandwidth, Offset40, - Offset80); + PHY_SetSwChnlBWMode8723B(padapter, channel, Bandwidth, Offset40, Offset80); } void rtw_hal_dm_watchdog(struct adapter *padapter) { - if (padapter->HalFunc.hal_dm_watchdog) - padapter->HalFunc.hal_dm_watchdog(padapter); + rtl8723b_HalDmWatchDog(padapter); } void rtw_hal_dm_watchdog_in_lps(struct adapter *padapter) { if (adapter_to_pwrctl(padapter)->fw_current_in_ps_mode) { - if (padapter->HalFunc.hal_dm_watchdog_in_lps) - padapter->HalFunc.hal_dm_watchdog_in_lps(padapter); /* this function caller is in interrupt context */ + rtl8723b_HalDmWatchDog_in_LPS(padapter); /* this function caller is in interrupt context */ } } void beacon_timing_control(struct adapter *padapter) { - if (padapter->HalFunc.SetBeaconRelatedRegistersHandler) - padapter->HalFunc.SetBeaconRelatedRegistersHandler(padapter); + rtl8723b_SetBeaconRelatedRegisters(padapter); } diff --git a/drivers/staging/rtl8723bs/hal/odm.c b/drivers/staging/rtl8723bs/hal/odm.c index ea3b4cd3236035..8d6131f0ad47d9 100644 --- a/drivers/staging/rtl8723bs/hal/odm.c +++ b/drivers/staging/rtl8723bs/hal/odm.c @@ -417,13 +417,11 @@ static void odm_RefreshRateAdaptiveMaskCE(struct dm_odm_t *pDM_Odm) u8 i; struct adapter *padapter = pDM_Odm->Adapter; - if (padapter->bDriverStopped) { + if (padapter->bDriverStopped) return; - } - if (!pDM_Odm->bUseRAMask) { + if (!pDM_Odm->bUseRAMask) return; - } for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { PSTA_INFO_T pstat = pDM_Odm->pODM_StaInfo[i]; @@ -433,7 +431,6 @@ static void odm_RefreshRateAdaptiveMaskCE(struct dm_odm_t *pDM_Odm) continue; if (true == ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level)) { - /* printk("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level); */ rtw_hal_update_ra_mask(pstat, pstat->rssi_level); } @@ -461,9 +458,9 @@ static void odm_RefreshRateAdaptiveMaskCE(struct dm_odm_t *pDM_Odm) static void odm_RefreshRateAdaptiveMask(struct dm_odm_t *pDM_Odm) { - if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) { + if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) return; - } + odm_RefreshRateAdaptiveMaskCE(pDM_Odm); } @@ -512,7 +509,6 @@ bool ODM_RAStateCheck( RATRState = DM_RATR_STA_MIDDLE; else RATRState = DM_RATR_STA_LOW; - /* printk("==>%s, RATRState:0x%02x , RSSI:%d\n", __func__, RATRState, RSSI); */ if (*pRATRState != RATRState || bForceUpdate) { *pRATRState = RATRState; @@ -593,8 +589,6 @@ static void odm_RSSIMonitorCheckCE(struct dm_odm_t *pDM_Odm) } } - /* printk("%s ==> sta_cnt(%d)\n", __func__, sta_cnt); */ - for (i = 0; i < sta_cnt; i++) { if (PWDB_rssi[i] != (0)) { if (pHalData->fw_ractrl == true)/* Report every sta's RSSI to FW */ diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index 37ebbbf408ecfd..e15ec6452fd061 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -53,8 +53,6 @@ static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) u8 *bufferPtr = buffer; u32 i = 0, offset = 0; -/* printk("====>%s %d\n", __func__, __LINE__); */ - /* 3 Phase #1 */ blockCount_p1 = buffSize / blockSize_p1; remainSize_p1 = buffSize % blockSize_p1; @@ -62,7 +60,8 @@ static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) for (i = 0; i < blockCount_p1; i++) { ret = rtw_write32(padapter, (FW_8723B_START_ADDRESS + i * blockSize_p1), *((u32 *)(bufferPtr + i * blockSize_p1))); if (ret == _FAIL) { - printk("====>%s %d i:%d\n", __func__, __LINE__, i); + netdev_dbg(padapter->pnetdev, "write failed at %s %d, block:%d\n", + __func__, __LINE__, i); goto exit; } } @@ -85,7 +84,8 @@ static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) ret = rtw_write8(padapter, (FW_8723B_START_ADDRESS + offset + i), *(bufferPtr + offset + i)); if (ret == _FAIL) { - printk("====>%s %d i:%d\n", __func__, __LINE__, i); + netdev_dbg(padapter->pnetdev, "write failed at %s %d, block:%d\n", + __func__, __LINE__, i); goto exit; } } @@ -127,7 +127,8 @@ static int _WriteFW(struct adapter *padapter, void *buffer, u32 size) ret = _PageWrite(padapter, page, bufferPtr+offset, MAX_DLFW_PAGE_SIZE); if (ret == _FAIL) { - printk("====>%s %d\n", __func__, __LINE__); + netdev_dbg(padapter->pnetdev, "page write failed at %s %d\n", + __func__, __LINE__); goto exit; } } @@ -138,7 +139,8 @@ static int _WriteFW(struct adapter *padapter, void *buffer, u32 size) ret = _PageWrite(padapter, page, bufferPtr+offset, remainSize); if (ret == _FAIL) { - printk("====>%s %d\n", __func__, __LINE__); + netdev_dbg(padapter->pnetdev, "remaining page write failed at %s %d\n", + __func__, __LINE__); goto exit; } } @@ -439,10 +441,6 @@ void rtl8723b_InitializeFirmwareVars(struct adapter *padapter) /* pHalData->H2CStopInsertQueue = false; */ } -static void rtl8723b_free_hal_data(struct adapter *padapter) -{ -} - /* */ /* Efuse related code */ /* */ @@ -492,7 +490,7 @@ static u8 hal_EfuseSwitchToBank( return bRet; } -static void Hal_GetEfuseDefinition( +void Hal_GetEfuseDefinition( struct adapter *padapter, u8 efuseType, u8 type, @@ -604,46 +602,7 @@ static void Hal_GetEfuseDefinition( #define EFUSE_ACCESS_ON_8723 0x69 /* For RTL8723 only. */ #define REG_EFUSE_ACCESS_8723 0x00CF /* Efuse access protection for RTL8723 */ -/* */ -static void Hal_BT_EfusePowerSwitch( - struct adapter *padapter, u8 bWrite, u8 PwrState -) -{ - u8 tempval; - if (PwrState) { - /* enable BT power cut */ - /* 0x6A[14] = 1 */ - tempval = rtw_read8(padapter, 0x6B); - tempval |= BIT(6); - rtw_write8(padapter, 0x6B, tempval); - - /* Attention!! Between 0x6A[14] and 0x6A[15] setting need 100us delay */ - /* So don't write 0x6A[14]= 1 and 0x6A[15]= 0 together! */ - msleep(1); - /* disable BT output isolation */ - /* 0x6A[15] = 0 */ - tempval = rtw_read8(padapter, 0x6B); - tempval &= ~BIT(7); - rtw_write8(padapter, 0x6B, tempval); - } else { - /* enable BT output isolation */ - /* 0x6A[15] = 1 */ - tempval = rtw_read8(padapter, 0x6B); - tempval |= BIT(7); - rtw_write8(padapter, 0x6B, tempval); - - /* Attention!! Between 0x6A[14] and 0x6A[15] setting need 100us delay */ - /* So don't write 0x6A[14]= 1 and 0x6A[15]= 0 together! */ - - /* disable BT power cut */ - /* 0x6A[14] = 1 */ - tempval = rtw_read8(padapter, 0x6B); - tempval &= ~BIT(6); - rtw_write8(padapter, 0x6B, tempval); - } - -} -static void Hal_EfusePowerSwitch( +void Hal_EfusePowerSwitch( struct adapter *padapter, u8 bWrite, u8 PwrState ) { @@ -928,7 +887,7 @@ static void hal_ReadEFuse_BT( kfree(efuseTbl); } -static void Hal_ReadEFuse( +void Hal_ReadEFuse( struct adapter *padapter, u8 efuseType, u16 _offset, @@ -1069,7 +1028,6 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) /* only when bank is switched we have to reset the efuse_addr. */ if (bank != startBank) efuse_addr = 0; -#if 1 while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { if (efuse_OneByteRead(padapter, efuse_addr, @@ -1098,33 +1056,6 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) /* read next header */ efuse_addr += (word_cnts*2)+1; } -#else - while ( - bContinual && - efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest) && - AVAILABLE_EFUSE_ADDR(efuse_addr) - ) { - if (efuse_data != 0xFF) { - if ((efuse_data&0x1F) == 0x0F) { /* extended header */ - efuse_addr++; - efuse_OneByteRead(padapter, efuse_addr, &efuse_data, bPseudoTest); - if ((efuse_data & 0x0F) == 0x0F) { - efuse_addr++; - continue; - } else { - hworden = efuse_data & 0x0F; - } - } else { - hworden = efuse_data & 0x0F; - } - word_cnts = Efuse_CalculateWordCnts(hworden); - /* read next header */ - efuse_addr = efuse_addr + (word_cnts*2)+1; - } else - bContinual = false; - } -#endif - /* Check if we need to check next bank efuse */ if (efuse_addr < retU2) @@ -1141,7 +1072,7 @@ static u16 hal_EfuseGetCurrentSize_BT(struct adapter *padapter, u8 bPseudoTest) return retU2; } -static u16 Hal_EfuseGetCurrentSize( +u16 Hal_EfuseGetCurrentSize( struct adapter *padapter, u8 efuseType, bool bPseudoTest ) { @@ -1220,403 +1151,6 @@ static u8 Hal_EfuseWordEnableDataWrite( return badworden; } -static s32 Hal_EfusePgPacketRead( - struct adapter *padapter, - u8 offset, - u8 *data, - bool bPseudoTest -) -{ - u8 efuse_data, word_cnts = 0; - u16 efuse_addr = 0; - u8 hoffset = 0, hworden = 0; - u8 i; - u8 max_section = 0; - s32 ret; - - - if (!data) - return false; - - EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, &max_section, bPseudoTest); - if (offset > max_section) - return false; - - memset(data, 0xFF, PGPKT_DATA_SIZE); - ret = true; - - /* */ - /* Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */ - /* Skip dummy parts to prevent unexpected data read from Efuse. */ - /* By pass right now. 2009.02.19. */ - /* */ - while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { - if (efuse_OneByteRead(padapter, efuse_addr++, &efuse_data, bPseudoTest) == false) { - ret = false; - break; - } - - if (efuse_data == 0xFF) - break; - - if (EXT_HEADER(efuse_data)) { - hoffset = GET_HDR_OFFSET_2_0(efuse_data); - efuse_OneByteRead(padapter, efuse_addr++, &efuse_data, bPseudoTest); - if (ALL_WORDS_DISABLED(efuse_data)) - continue; - - hoffset |= ((efuse_data & 0xF0) >> 1); - hworden = efuse_data & 0x0F; - } else { - hoffset = (efuse_data>>4) & 0x0F; - hworden = efuse_data & 0x0F; - } - - if (hoffset == offset) { - for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { - /* Check word enable condition in the section */ - if (!(hworden & (0x01<= max_available) - return false; - - return true; -} - -static void hal_EfuseConstructPGPkt( - u8 offset, - u8 word_en, - u8 *pData, - struct pgpkt_struct *pTargetPkt -) -{ - memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE); - pTargetPkt->offset = offset; - pTargetPkt->word_en = word_en; - efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); - pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); -} - -static u8 hal_EfusePartialWriteCheck( - struct adapter *padapter, - u8 efuseType, - u16 *pAddr, - struct pgpkt_struct *pTargetPkt, - u8 bPseudoTest -) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - struct efuse_hal *pEfuseHal = &pHalData->EfuseHal; - u8 bRet = false; - u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; - u8 efuse_data = 0; - - EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_max_available_len, bPseudoTest); - EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_EFUSE_CONTENT_LEN_BANK, &efuse_max, bPseudoTest); - - if (efuseType == EFUSE_WIFI) { - if (bPseudoTest) { -#ifdef HAL_EFUSE_MEMORY - startAddr = (u16)pEfuseHal->fakeEfuseUsedBytes; -#else - startAddr = (u16)fakeEfuseUsedBytes; -#endif - } else - rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); - } else { - if (bPseudoTest) { -#ifdef HAL_EFUSE_MEMORY - startAddr = (u16)pEfuseHal->fakeBTEfuseUsedBytes; -#else - startAddr = (u16)fakeBTEfuseUsedBytes; -#endif - } else - rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&startAddr); - } - startAddr %= efuse_max; - - while (1) { - if (startAddr >= efuse_max_available_len) { - bRet = false; - break; - } - - if (efuse_OneByteRead(padapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) { -#if 1 - bRet = false; - break; -#else - if (EXT_HEADER(efuse_data)) { - cur_header = efuse_data; - startAddr++; - efuse_OneByteRead(padapter, startAddr, &efuse_data, bPseudoTest); - if (ALL_WORDS_DISABLED(efuse_data)) { - bRet = false; - break; - } else { - curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); - curPkt.word_en = efuse_data & 0x0F; - } - } else { - cur_header = efuse_data; - curPkt.offset = (cur_header>>4) & 0x0F; - curPkt.word_en = cur_header & 0x0F; - } - - curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en); - /* if same header is found but no data followed */ - /* write some part of data followed by the header. */ - if ( - (curPkt.offset == pTargetPkt->offset) && - (hal_EfuseCheckIfDatafollowed(padapter, curPkt.word_cnts, startAddr+1, bPseudoTest) == false) && - wordEnMatched(pTargetPkt, &curPkt, &matched_wden) == true - ) { - /* Here to write partial data */ - badworden = Efuse_WordEnableDataWrite(padapter, startAddr+1, matched_wden, pTargetPkt->data, bPseudoTest); - if (badworden != 0x0F) { - u32 PgWriteSuccess = 0; - /* if write fail on some words, write these bad words again */ - if (efuseType == EFUSE_WIFI) - PgWriteSuccess = Efuse_PgPacketWrite(padapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); - else - PgWriteSuccess = Efuse_PgPacketWrite_BT(padapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); - - if (!PgWriteSuccess) { - bRet = false; /* write fail, return */ - break; - } - } - /* partial write ok, update the target packet for later use */ - for (i = 0; i < 4; i++) { - if ((matched_wden & (0x1<word_en |= (0x1<word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); - } - /* read from next header */ - startAddr = startAddr + (curPkt.word_cnts*2) + 1; -#endif - } else { - /* not used header, 0xff */ - *pAddr = startAddr; - bRet = true; - break; - } - } - - return bRet; -} - -static u8 hal_EfusePgPacketWrite1ByteHeader( - struct adapter *padapter, - u8 efuseType, - u16 *pAddr, - struct pgpkt_struct *pTargetPkt, - u8 bPseudoTest -) -{ - u8 pg_header = 0, tmp_header = 0; - u16 efuse_addr = *pAddr; - u8 repeatcnt = 0; - - pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; - - do { - efuse_OneByteWrite(padapter, efuse_addr, pg_header, bPseudoTest); - efuse_OneByteRead(padapter, efuse_addr, &tmp_header, bPseudoTest); - if (tmp_header != 0xFF) - break; - if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) - return false; - - } while (1); - - if (tmp_header != pg_header) - return false; - - *pAddr = efuse_addr; - - return true; -} - -static u8 hal_EfusePgPacketWrite2ByteHeader( - struct adapter *padapter, - u8 efuseType, - u16 *pAddr, - struct pgpkt_struct *pTargetPkt, - u8 bPseudoTest -) -{ - u16 efuse_addr, efuse_max_available_len = 0; - u8 pg_header = 0, tmp_header = 0; - u8 repeatcnt = 0; - - EFUSE_GetEfuseDefinition(padapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, &efuse_max_available_len, bPseudoTest); - - efuse_addr = *pAddr; - if (efuse_addr >= efuse_max_available_len) - return false; - - pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; - - do { - efuse_OneByteWrite(padapter, efuse_addr, pg_header, bPseudoTest); - efuse_OneByteRead(padapter, efuse_addr, &tmp_header, bPseudoTest); - if (tmp_header != 0xFF) - break; - if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) - return false; - - } while (1); - - if (tmp_header != pg_header) - return false; - - /* to write ext_header */ - efuse_addr++; - pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; - - do { - efuse_OneByteWrite(padapter, efuse_addr, pg_header, bPseudoTest); - efuse_OneByteRead(padapter, efuse_addr, &tmp_header, bPseudoTest); - if (tmp_header != 0xFF) - break; - if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) - return false; - - } while (1); - - if (tmp_header != pg_header) /* offset PG fail */ - return false; - - *pAddr = efuse_addr; - - return true; -} - -static u8 hal_EfusePgPacketWriteHeader( - struct adapter *padapter, - u8 efuseType, - u16 *pAddr, - struct pgpkt_struct *pTargetPkt, - u8 bPseudoTest -) -{ - u8 bRet = false; - - if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) - bRet = hal_EfusePgPacketWrite2ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); - else - bRet = hal_EfusePgPacketWrite1ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); - - return bRet; -} - -static u8 hal_EfusePgPacketWriteData( - struct adapter *padapter, - u8 efuseType, - u16 *pAddr, - struct pgpkt_struct *pTargetPkt, - u8 bPseudoTest -) -{ - u16 efuse_addr; - u8 badworden; - - - efuse_addr = *pAddr; - badworden = Efuse_WordEnableDataWrite(padapter, efuse_addr+1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest); - if (badworden != 0x0F) - return false; - - return true; -} - -static s32 Hal_EfusePgPacketWrite( - struct adapter *padapter, - u8 offset, - u8 word_en, - u8 *pData, - bool bPseudoTest -) -{ - struct pgpkt_struct targetPkt; - u16 startAddr = 0; - u8 efuseType = EFUSE_WIFI; - - if (!hal_EfusePgCheckAvailableAddr(padapter, efuseType, bPseudoTest)) - return false; - - hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); - - if (!hal_EfusePartialWriteCheck(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) - return false; - - if (!hal_EfusePgPacketWriteHeader(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) - return false; - - if (!hal_EfusePgPacketWriteData(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) - return false; - - return true; -} - -static bool Hal_EfusePgPacketWrite_BT( - struct adapter *padapter, - u8 offset, - u8 word_en, - u8 *pData, - bool bPseudoTest -) -{ - struct pgpkt_struct targetPkt; - u16 startAddr = 0; - u8 efuseType = EFUSE_BT; - - if (!hal_EfusePgCheckAvailableAddr(padapter, efuseType, bPseudoTest)) - return false; - - hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); - - if (!hal_EfusePartialWriteCheck(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) - return false; - - if (!hal_EfusePgPacketWriteHeader(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) - return false; - - if (!hal_EfusePgPacketWriteData(padapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) - return false; - - return true; -} - static struct hal_version ReadChipVersion8723B(struct adapter *padapter) { u32 value32; @@ -1645,15 +1179,15 @@ static struct hal_version ReadChipVersion8723B(struct adapter *padapter) pHalData->MultiFunc |= ((value32 & BT_FUNC_EN) ? RT_MULTI_FUNC_BT : 0); pHalData->MultiFunc |= ((value32 & GPS_FUNC_EN) ? RT_MULTI_FUNC_GPS : 0); pHalData->PolarityCtl = ((value32 & WL_HWPDN_SL) ? RT_POLARITY_HIGH_ACT : RT_POLARITY_LOW_ACT); -#if 1 + dump_chip_info(ChipVersion); -#endif + pHalData->VersionID = ChipVersion; return ChipVersion; } -static void rtl8723b_read_chip_version(struct adapter *padapter) +void rtl8723b_read_chip_version(struct adapter *padapter) { ReadChipVersion8723B(padapter); } @@ -1747,7 +1281,7 @@ static void _BeaconFunctionEnable(struct adapter *padapter, u8 Enable, u8 Linked rtw_write8(padapter, REG_RD_CTRL+1, 0x6F); } -static void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter) +void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter) { u8 val8; u32 value32; @@ -1808,16 +1342,6 @@ static void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter) rtw_write8(padapter, bcn_ctrl_reg, val8); } -static void rtl8723b_GetHalODMVar( - struct adapter *Adapter, - enum hal_odm_variable eVariable, - void *pValue1, - void *pValue2 -) -{ - GetHalODMVar(Adapter, eVariable, pValue1, pValue2); -} - static void rtl8723b_SetHalODMVar( struct adapter *Adapter, enum hal_odm_variable eVariable, @@ -1836,7 +1360,7 @@ static void hal_notch_filter_8723b(struct adapter *adapter, bool enable) rtw_write8(adapter, rOFDM0_RxDSP+1, rtw_read8(adapter, rOFDM0_RxDSP+1) & ~BIT1); } -static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_level) +void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_level) { u32 mask, rate_bitmap; u8 shortGIrate = false; @@ -1876,49 +1400,9 @@ static void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_l void rtl8723b_set_hal_ops(struct hal_ops *pHalFunc) { - pHalFunc->free_hal_data = &rtl8723b_free_hal_data; - - pHalFunc->dm_init = &rtl8723b_init_dm_priv; - - pHalFunc->read_chip_version = &rtl8723b_read_chip_version; - - pHalFunc->UpdateRAMaskHandler = &UpdateHalRAMask8723B; - - pHalFunc->set_bwmode_handler = &PHY_SetBWMode8723B; - pHalFunc->set_channel_handler = &PHY_SwChnl8723B; - pHalFunc->set_chnl_bw_handler = &PHY_SetSwChnlBWMode8723B; - - pHalFunc->set_tx_power_level_handler = &PHY_SetTxPowerLevel8723B; - pHalFunc->get_tx_power_level_handler = &PHY_GetTxPowerLevel8723B; - - pHalFunc->hal_dm_watchdog = &rtl8723b_HalDmWatchDog; - pHalFunc->hal_dm_watchdog_in_lps = &rtl8723b_HalDmWatchDog_in_LPS; - - - pHalFunc->SetBeaconRelatedRegistersHandler = &rtl8723b_SetBeaconRelatedRegisters; - - pHalFunc->Add_RateATid = &rtl8723b_Add_RateATid; - - pHalFunc->run_thread = &rtl8723b_start_thread; - pHalFunc->cancel_thread = &rtl8723b_stop_thread; - - pHalFunc->read_bbreg = &PHY_QueryBBReg_8723B; - pHalFunc->write_bbreg = &PHY_SetBBReg_8723B; - pHalFunc->read_rfreg = &PHY_QueryRFReg_8723B; - pHalFunc->write_rfreg = &PHY_SetRFReg_8723B; - /* Efuse related function */ - pHalFunc->BTEfusePowerSwitch = &Hal_BT_EfusePowerSwitch; - pHalFunc->EfusePowerSwitch = &Hal_EfusePowerSwitch; - pHalFunc->ReadEFuse = &Hal_ReadEFuse; - pHalFunc->EFUSEGetEfuseDefinition = &Hal_GetEfuseDefinition; - pHalFunc->EfuseGetCurrentSize = &Hal_EfuseGetCurrentSize; - pHalFunc->Efuse_PgPacketRead = &Hal_EfusePgPacketRead; - pHalFunc->Efuse_PgPacketWrite = &Hal_EfusePgPacketWrite; pHalFunc->Efuse_WordEnableDataWrite = &Hal_EfuseWordEnableDataWrite; - pHalFunc->Efuse_PgPacketWrite_BT = &Hal_EfusePgPacketWrite_BT; - pHalFunc->GetHalODMVarHandler = &rtl8723b_GetHalODMVar; pHalFunc->SetHalODMVarHandler = &rtl8723b_SetHalODMVar; pHalFunc->xmit_thread_handler = &hal_xmit_handler; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c index 4ff092b7c9c99a..d8709d40cb33fe 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c @@ -575,10 +575,6 @@ void PHY_SetTxPowerLevel8723B(struct adapter *Adapter, u8 Channel) PHY_SetTxPowerLevelByPath(Adapter, Channel, RFPath); } -void PHY_GetTxPowerLevel8723B(struct adapter *Adapter, s32 *powerlevel) -{ -} - static void phy_SetRegBW_8723B( struct adapter *Adapter, enum channel_width CurrentBW ) @@ -764,17 +760,6 @@ static void PHY_HandleSwChnlAndSetBW8723B( } } -void PHY_SetBWMode8723B( - struct adapter *Adapter, - enum channel_width Bandwidth, /* 20M or 40M */ - unsigned char Offset /* Upper, Lower, or Don't care */ -) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - - PHY_HandleSwChnlAndSetBW8723B(Adapter, false, true, pHalData->CurrentChannel, Bandwidth, Offset, Offset, pHalData->CurrentChannel); -} - /* Call after initialization */ void PHY_SwChnl8723B(struct adapter *Adapter, u8 channel) { diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c index 78298e63edce6e..5dc1c12fe03e57 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c @@ -411,14 +411,12 @@ int rtl8723bs_xmit_thread(void *context) s32 ret; struct adapter *padapter; struct xmit_priv *pxmitpriv; - u8 thread_name[20]; ret = _SUCCESS; padapter = context; pxmitpriv = &padapter->xmitpriv; - rtw_sprintf(thread_name, 20, "RTWHALXT-%s", ADPT_ARG(padapter)); - thread_enter(thread_name); + allow_signal(SIGTERM); do { ret = rtl8723bs_xmit_handler(padapter); diff --git a/drivers/staging/rtl8723bs/hal/sdio_halinit.c b/drivers/staging/rtl8723bs/hal/sdio_halinit.c index d3aae413fc0f92..af9a2b068796a7 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_halinit.c +++ b/drivers/staging/rtl8723bs/hal/sdio_halinit.c @@ -583,7 +583,7 @@ static bool HalDetectPwrDownMode(struct adapter *Adapter) return pHalData->pwrdown; } /* HalDetectPwrDownMode */ -static u32 rtl8723bs_hal_init(struct adapter *padapter) +u32 rtl8723bs_hal_init(struct adapter *padapter) { s32 ret; struct hal_com_data *pHalData; @@ -884,7 +884,7 @@ static void CardDisableRTL8723BSdio(struct adapter *padapter) HalPwrSeqCmdParsing(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, rtl8723B_card_disable_flow); } -static u32 rtl8723bs_hal_deinit(struct adapter *padapter) +u32 rtl8723bs_hal_deinit(struct adapter *padapter) { struct dvobj_priv *psdpriv = padapter->dvobj; struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; @@ -937,17 +937,7 @@ static u32 rtl8723bs_hal_deinit(struct adapter *padapter) return _SUCCESS; } -static u32 rtl8723bs_inirp_init(struct adapter *padapter) -{ - return _SUCCESS; -} - -static u32 rtl8723bs_inirp_deinit(struct adapter *padapter) -{ - return _SUCCESS; -} - -static void rtl8723bs_init_default_value(struct adapter *padapter) +void rtl8723bs_init_default_value(struct adapter *padapter) { struct hal_com_data *pHalData; @@ -960,7 +950,7 @@ static void rtl8723bs_init_default_value(struct adapter *padapter) pHalData->SdioRxFIFOCnt = 0; } -static void rtl8723bs_interface_configure(struct adapter *padapter) +void rtl8723bs_interface_configure(struct adapter *padapter) { struct hal_com_data *pHalData = GET_HAL_DATA(padapter); struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); @@ -1142,7 +1132,7 @@ static s32 _ReadAdapterInfo8723BS(struct adapter *padapter) return _SUCCESS; } -static void ReadAdapterInfo8723BS(struct adapter *padapter) +void ReadAdapterInfo8723BS(struct adapter *padapter) { /* Read EEPROM size before call any EEPROM function */ padapter->EepromAddressSize = GetEEPROMSize8723B(padapter); @@ -1154,7 +1144,7 @@ static void ReadAdapterInfo8723BS(struct adapter *padapter) * If variable not handled here, * some variables will be processed in SetHwReg8723B() */ -static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) +void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) { u8 val8; @@ -1195,7 +1185,7 @@ static void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) * If variable not handled here, * some variables will be processed in GetHwReg8723B() */ -static void GetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) +void GetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) { switch (variable) { case HW_VAR_CPWM: @@ -1214,7 +1204,7 @@ static void GetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val) } } -static void SetHwRegWithBuf8723B(struct adapter *padapter, u8 variable, u8 *pbuf, int len) +void SetHwRegWithBuf8723B(struct adapter *padapter, u8 variable, u8 *pbuf, int len) { switch (variable) { case HW_VAR_C2H_HANDLE: @@ -1229,7 +1219,7 @@ static void SetHwRegWithBuf8723B(struct adapter *padapter, u8 variable, u8 *pbuf /* Description: */ /* Query setting of specified variable. */ /* */ -static u8 GetHalDefVar8723BSDIO( +u8 GetHalDefVar8723BSDIO( struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue ) { @@ -1257,8 +1247,7 @@ static u8 GetHalDefVar8723BSDIO( /* Description: */ /* Change default setting of specified variable. */ /* */ -static u8 SetHalDefVar8723BSDIO(struct adapter *Adapter, - enum hal_def_variable eVariable, void *pValue) +u8 SetHalDefVar8723BSDIO(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue) { return SetHalDefVar8723B(Adapter, eVariable, pValue); } @@ -1269,32 +1258,4 @@ void rtl8723bs_set_hal_ops(struct adapter *padapter) rtl8723b_set_hal_ops(pHalFunc); - pHalFunc->hal_init = &rtl8723bs_hal_init; - pHalFunc->hal_deinit = &rtl8723bs_hal_deinit; - - pHalFunc->inirp_init = &rtl8723bs_inirp_init; - pHalFunc->inirp_deinit = &rtl8723bs_inirp_deinit; - - pHalFunc->init_xmit_priv = &rtl8723bs_init_xmit_priv; - pHalFunc->free_xmit_priv = &rtl8723bs_free_xmit_priv; - - pHalFunc->init_recv_priv = &rtl8723bs_init_recv_priv; - pHalFunc->free_recv_priv = &rtl8723bs_free_recv_priv; - - pHalFunc->init_default_value = &rtl8723bs_init_default_value; - pHalFunc->intf_chip_configure = &rtl8723bs_interface_configure; - pHalFunc->read_adapter_info = &ReadAdapterInfo8723BS; - - pHalFunc->enable_interrupt = &EnableInterrupt8723BSdio; - pHalFunc->disable_interrupt = &DisableInterrupt8723BSdio; - pHalFunc->check_ips_status = &CheckIPSStatus; - pHalFunc->SetHwRegHandler = &SetHwReg8723BS; - pHalFunc->GetHwRegHandler = &GetHwReg8723BS; - pHalFunc->SetHwRegHandlerWithBuf = &SetHwRegWithBuf8723B; - pHalFunc->GetHalDefVarHandler = &GetHalDefVar8723BSDIO; - pHalFunc->SetHalDefVarHandler = &SetHalDefVar8723BSDIO; - - pHalFunc->hal_xmit = &rtl8723bs_hal_xmit; - pHalFunc->mgnt_xmit = &rtl8723bs_mgnt_xmit; - pHalFunc->hal_xmitframe_enqueue = &rtl8723bs_hal_xmitframe_enqueue; } diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index 0b35c97843cc7b..7b0e824e05a9a1 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -182,8 +182,6 @@ struct registry_priv { #include -#define is_primary_adapter(adapter) (1) -#define get_iface_type(adapter) (IFACE_PORT0) #define GET_PRIMARY_ADAPTER(padapter) (((struct adapter *)padapter)->dvobj->if1) #define GET_IFACE_NUMS(padapter) (((struct adapter *)padapter)->dvobj->iface_nums) #define GET_ADAPTER(padapter, iface_id) (((struct adapter *)padapter)->dvobj->padapters[iface_id]) @@ -320,14 +318,6 @@ static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj) return &dvobj->intf_data.func->dev; } -struct adapter *dvobj_get_port0_adapter(struct dvobj_priv *dvobj); - -enum { - IFACE_PORT0, /* mapping to port0 for C/D series chips */ - IFACE_PORT1, /* mapping to port1 for C/D series chip */ - MAX_IFACE_PORT, -}; - enum { DRIVER_NORMAL = 0, DRIVER_DISAPPEAR = 1, diff --git a/drivers/staging/rtl8723bs/include/hal_com.h b/drivers/staging/rtl8723bs/include/hal_com.h index 17d5cfb66a365f..4db93484725f09 100644 --- a/drivers/staging/rtl8723bs/include/hal_com.h +++ b/drivers/staging/rtl8723bs/include/hal_com.h @@ -158,10 +158,6 @@ void rtw_dump_raw_rssi_info(struct adapter *padapter); void rtw_bb_rf_gain_offset(struct adapter *padapter); -void GetHalODMVar(struct adapter *Adapter, - enum hal_odm_variable eVariable, - void *pValue1, - void *pValue2); void SetHalODMVar( struct adapter *Adapter, enum hal_odm_variable eVariable, diff --git a/drivers/staging/rtl8723bs/include/hal_intf.h b/drivers/staging/rtl8723bs/include/hal_intf.h index efdd1f912b5d9e..282e141616b0a2 100644 --- a/drivers/staging/rtl8723bs/include/hal_intf.h +++ b/drivers/staging/rtl8723bs/include/hal_intf.h @@ -162,91 +162,9 @@ enum hal_intf_ps_func { typedef s32 (*c2h_id_filter)(u8 *c2h_evt); struct hal_ops { - u32 (*hal_power_on)(struct adapter *padapter); - void (*hal_power_off)(struct adapter *padapter); - u32 (*hal_init)(struct adapter *padapter); - u32 (*hal_deinit)(struct adapter *padapter); - - void (*free_hal_data)(struct adapter *padapter); - - u32 (*inirp_init)(struct adapter *padapter); - u32 (*inirp_deinit)(struct adapter *padapter); - void (*irp_reset)(struct adapter *padapter); - - s32 (*init_xmit_priv)(struct adapter *padapter); - void (*free_xmit_priv)(struct adapter *padapter); - - s32 (*init_recv_priv)(struct adapter *padapter); - void (*free_recv_priv)(struct adapter *padapter); - - void (*dm_init)(struct adapter *padapter); - void (*dm_deinit)(struct adapter *padapter); - void (*read_chip_version)(struct adapter *padapter); - - void (*init_default_value)(struct adapter *padapter); - - void (*intf_chip_configure)(struct adapter *padapter); - - void (*read_adapter_info)(struct adapter *padapter); - - void (*enable_interrupt)(struct adapter *padapter); - void (*disable_interrupt)(struct adapter *padapter); - u8 (*check_ips_status)(struct adapter *padapter); - s32 (*interrupt_handler)(struct adapter *padapter); - void (*clear_interrupt)(struct adapter *padapter); - void (*set_bwmode_handler)(struct adapter *padapter, enum channel_width Bandwidth, u8 Offset); - void (*set_channel_handler)(struct adapter *padapter, u8 channel); - void (*set_chnl_bw_handler)(struct adapter *padapter, u8 channel, enum channel_width Bandwidth, u8 Offset40, u8 Offset80); - - void (*set_tx_power_level_handler)(struct adapter *padapter, u8 channel); - void (*get_tx_power_level_handler)(struct adapter *padapter, s32 *powerlevel); - - void (*hal_dm_watchdog)(struct adapter *padapter); - void (*hal_dm_watchdog_in_lps)(struct adapter *padapter); - - - void (*SetHwRegHandler)(struct adapter *padapter, u8 variable, u8 *val); - void (*GetHwRegHandler)(struct adapter *padapter, u8 variable, u8 *val); - - void (*SetHwRegHandlerWithBuf)(struct adapter *padapter, u8 variable, u8 *pbuf, int len); - - u8 (*GetHalDefVarHandler)(struct adapter *padapter, enum hal_def_variable eVariable, void *pValue); - u8 (*SetHalDefVarHandler)(struct adapter *padapter, enum hal_def_variable eVariable, void *pValue); - - void (*GetHalODMVarHandler)(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, void *pValue2); void (*SetHalODMVarHandler)(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet); - void (*UpdateRAMaskHandler)(struct adapter *padapter, u32 mac_id, u8 rssi_level); - void (*SetBeaconRelatedRegistersHandler)(struct adapter *padapter); - - void (*Add_RateATid)(struct adapter *padapter, u32 bitmap, u8 *arg, u8 rssi_level); - - void (*run_thread)(struct adapter *padapter); - void (*cancel_thread)(struct adapter *padapter); - - u8 (*interface_ps_func)(struct adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val); - - s32 (*hal_xmit)(struct adapter *padapter, struct xmit_frame *pxmitframe); - /* - * mgnt_xmit should be implemented to run in interrupt context - */ - s32 (*mgnt_xmit)(struct adapter *padapter, struct xmit_frame *pmgntframe); - s32 (*hal_xmitframe_enqueue)(struct adapter *padapter, struct xmit_frame *pxmitframe); - - u32 (*read_bbreg)(struct adapter *padapter, u32 RegAddr, u32 BitMask); - void (*write_bbreg)(struct adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data); - u32 (*read_rfreg)(struct adapter *padapter, u8 eRFPath, u32 RegAddr, u32 BitMask); - void (*write_rfreg)(struct adapter *padapter, u8 eRFPath, u32 RegAddr, u32 BitMask, u32 Data); - - void (*EfusePowerSwitch)(struct adapter *padapter, u8 bWrite, u8 PwrState); - void (*BTEfusePowerSwitch)(struct adapter *padapter, u8 bWrite, u8 PwrState); - void (*ReadEFuse)(struct adapter *padapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest); - void (*EFUSEGetEfuseDefinition)(struct adapter *padapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest); - u16 (*EfuseGetCurrentSize)(struct adapter *padapter, u8 efuseType, bool bPseudoTest); - int (*Efuse_PgPacketRead)(struct adapter *padapter, u8 offset, u8 *data, bool bPseudoTest); - int (*Efuse_PgPacketWrite)(struct adapter *padapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest); u8 (*Efuse_WordEnableDataWrite)(struct adapter *padapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest); - bool (*Efuse_PgPacketWrite_BT)(struct adapter *padapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest); s32 (*xmit_thread_handler)(struct adapter *padapter); void (*hal_notch_filter)(struct adapter *adapter, bool enable); @@ -357,4 +275,17 @@ s32 rtw_hal_macid_wakeup(struct adapter *padapter, u32 macid); s32 rtw_hal_fill_h2c_cmd(struct adapter *, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer); +void SetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val); +void GetHwReg8723BS(struct adapter *padapter, u8 variable, u8 *val); +void SetHwRegWithBuf8723B(struct adapter *padapter, u8 variable, u8 *pbuf, int len); +u8 GetHalDefVar8723BSDIO(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue); +u8 SetHalDefVar8723BSDIO(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue); +void UpdateHalRAMask8723B(struct adapter *padapter, u32 mac_id, u8 rssi_level); +void rtl8723b_SetBeaconRelatedRegisters(struct adapter *padapter); +void Hal_EfusePowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); +void Hal_ReadEFuse(struct adapter *padapter, u8 efuseType, u16 _offset, + u16 _size_byte, u8 *pbuf, bool bPseudoTest); +void Hal_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, + void *pOut, bool bPseudoTest); +u16 Hal_EfuseGetCurrentSize(struct adapter *padapter, u8 efuseType, bool bPseudoTest); #endif /* __HAL_INTF_H__ */ diff --git a/drivers/staging/rtl8723bs/include/hal_phy_cfg.h b/drivers/staging/rtl8723bs/include/hal_phy_cfg.h index ea494bcf830b81..07bf0a8d019aa9 100644 --- a/drivers/staging/rtl8723bs/include/hal_phy_cfg.h +++ b/drivers/staging/rtl8723bs/include/hal_phy_cfg.h @@ -49,13 +49,8 @@ void PHY_SetTxPowerIndex(struct adapter *Adapter, u32 PowerIndex, u8 PHY_GetTxPowerIndex(struct adapter *padapter, u8 RFPath, u8 Rate, enum channel_width BandWidth, u8 Channel); -void PHY_GetTxPowerLevel8723B(struct adapter *Adapter, s32 *powerlevel); - void PHY_SetTxPowerLevel8723B(struct adapter *Adapter, u8 channel); -void PHY_SetBWMode8723B(struct adapter *Adapter, enum channel_width Bandwidth, - unsigned char Offset); - /* Call after initialization */ void PHY_SwChnl8723B(struct adapter *Adapter, u8 channel); diff --git a/drivers/staging/rtl8723bs/include/osdep_intf.h b/drivers/staging/rtl8723bs/include/osdep_intf.h index 111e0179712ac6..215ece612f7157 100644 --- a/drivers/staging/rtl8723bs/include/osdep_intf.h +++ b/drivers/staging/rtl8723bs/include/osdep_intf.h @@ -55,9 +55,6 @@ void rtw_unregister_netdevs(struct dvobj_priv *dvobj); u16 rtw_recv_select_queue(struct sk_buff *skb); -int rtw_ndev_notifier_register(void); -void rtw_ndev_notifier_unregister(void); - void rtw_ips_dev_unload(struct adapter *padapter); int rtw_ips_pwr_up(struct adapter *padapter); diff --git a/drivers/staging/rtl8723bs/include/osdep_service.h b/drivers/staging/rtl8723bs/include/osdep_service.h index b21267d7ef7209..8b1634f4091ec1 100644 --- a/drivers/staging/rtl8723bs/include/osdep_service.h +++ b/drivers/staging/rtl8723bs/include/osdep_service.h @@ -73,11 +73,6 @@ int _rtw_netif_rx(struct net_device *ndev, struct sk_buff *skb); extern void _rtw_init_queue(struct __queue *pqueue); -static inline void thread_enter(char *name) -{ - allow_signal(SIGTERM); -} - static inline void flush_signals_thread(void) { if (signal_pending(current)) diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_recv.h b/drivers/staging/rtl8723bs/include/rtl8723b_recv.h index a108ce89bce432..783f64de0aec23 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_recv.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_recv.h @@ -87,4 +87,9 @@ void rtl8723bs_free_recv_priv(struct adapter *padapter); void rtl8723b_query_rx_phy_status(union recv_frame *prframe, struct phy_stat *pphy_stat); void rtl8723b_process_phy_info(struct adapter *padapter, void *prframe); +void rtl8723b_read_chip_version(struct adapter *padapter); +void rtl8723bs_init_default_value(struct adapter *padapter); +void rtl8723bs_interface_configure(struct adapter *padapter); +void ReadAdapterInfo8723BS(struct adapter *padapter); + #endif diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h b/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h index ad2542d0cabe26..ac4ca7e05b9bf5 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_xmit.h @@ -405,6 +405,8 @@ struct txdesc_8723b { void rtl8723b_update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem); void rtl8723b_fill_fake_txdesc(struct adapter *padapter, u8 *pDesc, u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull, u8 bDataFrame); +u32 rtl8723bs_hal_init(struct adapter *padapter); +u32 rtl8723bs_hal_deinit(struct adapter *padapter); s32 rtl8723bs_init_xmit_priv(struct adapter *padapter); void rtl8723bs_free_xmit_priv(struct adapter *padapter); s32 rtl8723bs_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe); diff --git a/drivers/staging/rtl8723bs/include/rtw_efuse.h b/drivers/staging/rtl8723bs/include/rtw_efuse.h index 0cb8c6f6d34dba..d6ea8a4a856f13 100644 --- a/drivers/staging/rtl8723bs/include/rtw_efuse.h +++ b/drivers/staging/rtl8723bs/include/rtw_efuse.h @@ -90,16 +90,12 @@ extern u8 fakeBTEfuseInitMap[]; extern u8 fakeBTEfuseModifiedMap[]; /*------------------------Export global variable----------------------------*/ -u16 Efuse_GetCurrentSize(struct adapter *padapter, u8 efuseType, bool bPseudoTest); u8 Efuse_CalculateWordCnts(u8 word_en); void EFUSE_GetEfuseDefinition(struct adapter *padapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest); u8 efuse_OneByteRead(struct adapter *padapter, u16 addr, u8 *data, bool bPseudoTest); u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest); void Efuse_PowerSwitch(struct adapter *padapter, u8 bWrite, u8 PwrState); -int Efuse_PgPacketRead(struct adapter *padapter, u8 offset, u8 *data, bool bPseudoTest); -int Efuse_PgPacketWrite(struct adapter *padapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest); -void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata); u8 Efuse_WordEnableDataWrite(struct adapter *padapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest); u8 EFUSE_Read1Byte(struct adapter *padapter, u16 Address); diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h index 8315399b64fdb5..2080408743ef72 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h @@ -447,9 +447,7 @@ void Set_MSR(struct adapter *padapter, u8 type); u8 rtw_get_oper_ch(struct adapter *adapter); void rtw_set_oper_ch(struct adapter *adapter, u8 ch); -u8 rtw_get_oper_bw(struct adapter *adapter); void rtw_set_oper_bw(struct adapter *adapter, u8 bw); -u8 rtw_get_oper_choffset(struct adapter *adapter); void rtw_set_oper_choffset(struct adapter *adapter, u8 offset); u8 rtw_get_center_ch(u8 channel, u8 chnl_bw, u8 chnl_offset); unsigned long rtw_get_on_cur_ch_time(struct adapter *adapter); @@ -459,8 +457,6 @@ void r8723bs_select_channel(struct adapter *padapter, unsigned char channel); unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval); -void read_cam(struct adapter *padapter, u8 entry, u8 *get_key); - /* modify HW only */ void _write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key); void _clear_cam_entry(struct adapter *padapter, u8 entry); @@ -528,7 +524,6 @@ void rtw_camid_free(struct adapter *adapter, u8 cam_id); extern void rtw_alloc_macid(struct adapter *padapter, struct sta_info *psta); extern void rtw_release_macid(struct adapter *padapter, struct sta_info *psta); -extern u8 rtw_search_max_mac_id(struct adapter *padapter); void report_join_res(struct adapter *padapter, int res); void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame); diff --git a/drivers/staging/rtl8723bs/include/rtw_mp.h b/drivers/staging/rtl8723bs/include/rtw_mp.h index f94bb18479da5d..5a1cbd2ed8515d 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mp.h +++ b/drivers/staging/rtl8723bs/include/rtw_mp.h @@ -276,10 +276,6 @@ void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u3 u32 read_macreg(struct adapter *padapter, u32 addr, u32 sz); void write_macreg(struct adapter *padapter, u32 addr, u32 val, u32 sz); -u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask); -void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val); -u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr); -void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val); void SetChannel(struct adapter *padapter); void SetBandwidth(struct adapter *padapter); diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index b63a74e669bcf2..c053ee9c1361c4 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -581,7 +581,6 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ /* set mic key */ memcpy(txkey, &(param->u.crypt.key[16]), 8); memcpy(rxkey, &(param->u.crypt.key[24]), 8); @@ -626,7 +625,6 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { psta->dot118021XPrivacy = _TKIP_; - /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ /* set mic key */ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); @@ -657,7 +655,6 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ /* set mic key */ memcpy(txkey, &(param->u.crypt.key[16]), 8); memcpy(rxkey, &(param->u.crypt.key[24]), 8); @@ -785,7 +782,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */ - /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); @@ -806,10 +802,6 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param } else if (strcmp(param->u.crypt.alg, "BIP") == 0) { /* save the IGTK key, length 16 bytes */ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - /* - for (no = 0;no<16;no++) - printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]); - */ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; padapter->securitypriv.binstallBIPkey = true; } @@ -817,9 +809,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param } pbcmc_sta = rtw_get_bcmc_stainfo(padapter); - if (!pbcmc_sta) { - /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */ - } else { + if (pbcmc_sta) { /* Jeff: don't disable ieee8021x_blocked while clearing key */ if (strcmp(param->u.crypt.alg, "none") != 0) pbcmc_sta->ieee8021x_blocked = false; diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index a9e481e182ad6c..793b051536f324 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -138,9 +138,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) { /* sta mode */ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); - if (!psta) { - /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */ - } else { + if (psta) { /* Jeff: don't disable ieee8021x_blocked while clearing key */ if (strcmp(param->u.crypt.alg, "none") != 0) psta->ieee8021x_blocked = false; @@ -154,7 +152,6 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */ - /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ memcpy(psta->dot11tkiptxmickey.skey, ¶m->u.crypt.key[16], 8); memcpy(psta->dot11tkiprxmickey.skey, ¶m->u.crypt.key[24], 8); @@ -177,13 +174,8 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, true); } else if (strcmp(param->u.crypt.alg, "BIP") == 0) { - /* printk("BIP key_len =%d , index =%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */ /* save the IGTK key, length 16 bytes */ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - /*printk("IGTK key below:\n"); - for (no = 0;no<16;no++) - printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]); - printk("\n");*/ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx; padapter->securitypriv.binstallBIPkey = true; } @@ -191,9 +183,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, } pbcmc_sta = rtw_get_bcmc_stainfo(padapter); - if (!pbcmc_sta) { - /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */ - } else { + if (pbcmc_sta) { /* Jeff: don't disable ieee8021x_blocked while clearing key */ if (strcmp(param->u.crypt.alg, "none") != 0) pbcmc_sta->ieee8021x_blocked = false; @@ -629,7 +619,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ /* set mic key */ memcpy(txkey, ¶m->u.crypt.key[16], 8); memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[24], 8); @@ -674,7 +663,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { psta->dot118021XPrivacy = _TKIP_; - /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ /* set mic key */ memcpy(psta->dot11tkiptxmickey.skey, ¶m->u.crypt.key[16], 8); memcpy(psta->dot11tkiprxmickey.skey, ¶m->u.crypt.key[24], 8); @@ -703,7 +691,6 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ /* set mic key */ memcpy(txkey, ¶m->u.crypt.key[16], 8); memcpy(rxkey, ¶m->u.crypt.key[24], 8); diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c index fc9b9c5efb50e1..4e1917c0540291 100644 --- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c @@ -381,34 +381,6 @@ u16 rtw_recv_select_queue(struct sk_buff *skb) return rtw_1d_to_queue[priority]; } -static int rtw_ndev_notifier_call(struct notifier_block *nb, unsigned long state, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - - if (dev->netdev_ops->ndo_do_ioctl != rtw_ioctl) - return NOTIFY_DONE; - - netdev_dbg(dev, FUNC_NDEV_FMT " state:%lu\n", FUNC_NDEV_ARG(dev), - state); - - return NOTIFY_DONE; -} - -static struct notifier_block rtw_ndev_notifier = { - .notifier_call = rtw_ndev_notifier_call, -}; - -int rtw_ndev_notifier_register(void) -{ - return register_netdevice_notifier(&rtw_ndev_notifier); -} - -void rtw_ndev_notifier_unregister(void) -{ - unregister_netdevice_notifier(&rtw_ndev_notifier); -} - - static int rtw_ndev_init(struct net_device *dev) { struct adapter *adapter = rtw_netdev_priv(dev); @@ -633,8 +605,7 @@ void rtw_reset_drv_sw(struct adapter *padapter) struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); /* hal_priv */ - if (is_primary_adapter(padapter)) - rtw_hal_def_value_init(padapter); + rtw_hal_def_value_init(padapter); RTW_ENABLE_FUNC(padapter, DF_RX_BIT); RTW_ENABLE_FUNC(padapter, DF_TX_BIT); diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index d18fde4e5d6cea..5a7238e661ffbe 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -72,7 +72,7 @@ static int sdio_alloc_irq(struct dvobj_priv *dvobj) err = sdio_claim_irq(func, &sd_sync_int_hdl); if (err) { dvobj->drv_dbg.dbg_sdio_alloc_irq_error_cnt++; - printk(KERN_CRIT "%s: sdio_claim_irq FAIL(%d)!\n", __func__, err); + netdev_crit(dvobj->if1->pnetdev, "%s: sdio_claim_irq FAIL(%d)!\n", __func__, err); } else { dvobj->drv_dbg.dbg_sdio_alloc_irq_cnt++; dvobj->irq_alloc = 1; @@ -382,7 +382,6 @@ static int rtw_drv_init( if (sdio_alloc_irq(dvobj) != _SUCCESS) goto free_if1; - rtw_ndev_notifier_register(); status = _SUCCESS; free_if1: @@ -484,22 +483,12 @@ static int rtw_sdio_resume(struct device *dev) static int __init rtw_drv_entry(void) { - int ret; - - ret = sdio_register_driver(&rtl8723bs_sdio_driver); - if (ret != 0) - rtw_ndev_notifier_unregister(); - - return ret; + return sdio_register_driver(&rtl8723bs_sdio_driver); } +module_init(rtw_drv_entry); static void __exit rtw_drv_halt(void) { sdio_unregister_driver(&rtl8723bs_sdio_driver); - - rtw_ndev_notifier_unregister(); } - - -module_init(rtw_drv_entry); module_exit(rtw_drv_halt); diff --git a/drivers/staging/rts5208/Kconfig b/drivers/staging/rts5208/Kconfig deleted file mode 100644 index b864023d3ccb58..00000000000000 --- a/drivers/staging/rts5208/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config RTS5208 - tristate "Realtek PCI-E Card Reader RTS5208/5288 support" - depends on PCI && SCSI - help - Say Y here to include driver code to support the Realtek - PCI-E card reader rts5208/rts5288. - - If this driver is compiled as a module, it will be named rts5208. diff --git a/drivers/staging/rts5208/Makefile b/drivers/staging/rts5208/Makefile deleted file mode 100644 index 3c9e9797d3d936..00000000000000 --- a/drivers/staging/rts5208/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_RTS5208) := rts5208.o - -rts5208-y := rtsx.o rtsx_chip.o rtsx_transport.o rtsx_scsi.o \ - rtsx_card.o general.o sd.o xd.o ms.o spi.o diff --git a/drivers/staging/rts5208/TODO b/drivers/staging/rts5208/TODO deleted file mode 100644 index 9cec0d8dd0b6ca..00000000000000 --- a/drivers/staging/rts5208/TODO +++ /dev/null @@ -1,7 +0,0 @@ -TODO: -- use kernel coding style -- checkpatch.pl fixes -- We will use the stack in drivers/mmc to implement - rts5208/5288 in the future - -Micky Ching diff --git a/drivers/staging/rts5208/general.c b/drivers/staging/rts5208/general.c deleted file mode 100644 index 0f912b011064f1..00000000000000 --- a/drivers/staging/rts5208/general.c +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include "general.h" - -int bit1cnt_long(u32 data) -{ - int i, cnt = 0; - - for (i = 0; i < 32; i++) { - if (data & 0x01) - cnt++; - data >>= 1; - } - return cnt; -} - diff --git a/drivers/staging/rts5208/general.h b/drivers/staging/rts5208/general.h deleted file mode 100644 index 53e2dbabf04b7b..00000000000000 --- a/drivers/staging/rts5208/general.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __RTSX_GENERAL_H -#define __RTSX_GENERAL_H - -#include "rtsx.h" - -int bit1cnt_long(u32 data); - -#endif /* __RTSX_GENERAL_H */ diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c deleted file mode 100644 index bfeb5873bf3baa..00000000000000 --- a/drivers/staging/rts5208/ms.c +++ /dev/null @@ -1,4311 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include -#include - -#include "rtsx.h" -#include "ms.h" - -static inline void ms_set_err_code(struct rtsx_chip *chip, u8 err_code) -{ - struct ms_info *ms_card = &chip->ms_card; - - ms_card->err_code = err_code; -} - -static inline int ms_check_err_code(struct rtsx_chip *chip, u8 err_code) -{ - struct ms_info *ms_card = &chip->ms_card; - - return (ms_card->err_code == err_code); -} - -static int ms_parse_err_code(struct rtsx_chip *chip) -{ - return STATUS_FAIL; -} - -static int ms_transfer_tpc(struct rtsx_chip *chip, u8 trans_mode, - u8 tpc, u8 cnt, u8 cfg) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - u8 *ptr; - - dev_dbg(rtsx_dev(chip), "%s: tpc = 0x%x\n", __func__, tpc); - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, - 0xFF, MS_TRANSFER_START | trans_mode); - rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, - MS_TRANSFER_END, MS_TRANSFER_END); - - rtsx_add_cmd(chip, READ_REG_CMD, MS_TRANS_CFG, 0, 0); - - retval = rtsx_send_cmd(chip, MS_CARD, 5000); - if (retval < 0) { - rtsx_clear_ms_error(chip); - ms_set_err_code(chip, MS_TO_ERROR); - return ms_parse_err_code(chip); - } - - ptr = rtsx_get_cmd_data(chip) + 1; - - if (!(tpc & 0x08)) { /* Read Packet */ - if (*ptr & MS_CRC16_ERR) { - ms_set_err_code(chip, MS_CRC16_ERROR); - return ms_parse_err_code(chip); - } - } else { /* Write Packet */ - if (CHK_MSPRO(ms_card) && !(*ptr & 0x80)) { - if (*ptr & (MS_INT_ERR | MS_INT_CMDNK)) { - ms_set_err_code(chip, MS_CMD_NK); - return ms_parse_err_code(chip); - } - } - } - - if (*ptr & MS_RDY_TIMEOUT) { - rtsx_clear_ms_error(chip); - ms_set_err_code(chip, MS_TO_ERROR); - return ms_parse_err_code(chip); - } - - return STATUS_SUCCESS; -} - -static int ms_transfer_data(struct rtsx_chip *chip, u8 trans_mode, - u8 tpc, u16 sec_cnt, u8 cfg, bool mode_2k, - int use_sg, void *buf, int buf_len) -{ - int retval; - u8 val, err_code = 0; - enum dma_data_direction dir; - - if (!buf || !buf_len) - return STATUS_FAIL; - - if (trans_mode == MS_TM_AUTO_READ) { - dir = DMA_FROM_DEVICE; - err_code = MS_FLASH_READ_ERROR; - } else if (trans_mode == MS_TM_AUTO_WRITE) { - dir = DMA_TO_DEVICE; - err_code = MS_FLASH_WRITE_ERROR; - } else { - return STATUS_FAIL; - } - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); - rtsx_add_cmd(chip, WRITE_REG_CMD, - MS_SECTOR_CNT_H, 0xFF, (u8)(sec_cnt >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_SECTOR_CNT_L, 0xFF, (u8)sec_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); - - if (mode_2k) { - rtsx_add_cmd(chip, WRITE_REG_CMD, - MS_CFG, MS_2K_SECTOR_MODE, MS_2K_SECTOR_MODE); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_CFG, MS_2K_SECTOR_MODE, 0); - } - - trans_dma_enable(dir, chip, sec_cnt * 512, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, - MS_TRANSFER, 0xFF, MS_TRANSFER_START | trans_mode); - rtsx_add_cmd(chip, CHECK_REG_CMD, - MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data(chip, MS_CARD, buf, buf_len, - use_sg, dir, chip->mspro_timeout); - if (retval < 0) { - ms_set_err_code(chip, err_code); - if (retval == -ETIMEDOUT) - retval = STATUS_TIMEDOUT; - else - retval = STATUS_FAIL; - - return retval; - } - - retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); - if (retval) - return retval; - - if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int ms_write_bytes(struct rtsx_chip *chip, - u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - - if (!data || data_len < cnt) - return STATUS_ERROR; - - rtsx_init_cmd(chip); - - for (i = 0; i < cnt; i++) { - rtsx_add_cmd(chip, WRITE_REG_CMD, - PPBUF_BASE2 + i, 0xFF, data[i]); - } - if (cnt % 2) - rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF, 0xFF); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - - rtsx_add_cmd(chip, WRITE_REG_CMD, - MS_TRANSFER, 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES); - rtsx_add_cmd(chip, CHECK_REG_CMD, - MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END); - - retval = rtsx_send_cmd(chip, MS_CARD, 5000); - if (retval < 0) { - u8 val = 0; - - rtsx_read_register(chip, MS_TRANS_CFG, &val); - dev_dbg(rtsx_dev(chip), "MS_TRANS_CFG: 0x%02x\n", val); - - rtsx_clear_ms_error(chip); - - if (!(tpc & 0x08)) { - if (val & MS_CRC16_ERR) { - ms_set_err_code(chip, MS_CRC16_ERROR); - return ms_parse_err_code(chip); - } - } else { - if (CHK_MSPRO(ms_card) && !(val & 0x80)) { - if (val & (MS_INT_ERR | MS_INT_CMDNK)) { - ms_set_err_code(chip, MS_CMD_NK); - return ms_parse_err_code(chip); - } - } - } - - if (val & MS_RDY_TIMEOUT) { - ms_set_err_code(chip, MS_TO_ERROR); - return ms_parse_err_code(chip); - } - - ms_set_err_code(chip, MS_TO_ERROR); - return ms_parse_err_code(chip); - } - - return STATUS_SUCCESS; -} - -static int ms_read_bytes(struct rtsx_chip *chip, - u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 *ptr; - - if (!data) - return STATUS_ERROR; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, - MS_TRANSFER_START | MS_TM_READ_BYTES); - rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, - MS_TRANSFER_END, MS_TRANSFER_END); - - for (i = 0; i < data_len - 1; i++) - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); - - if (data_len % 2) - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0, 0); - else - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len - 1, - 0, 0); - - retval = rtsx_send_cmd(chip, MS_CARD, 5000); - if (retval < 0) { - u8 val = 0; - - rtsx_read_register(chip, MS_TRANS_CFG, &val); - rtsx_clear_ms_error(chip); - - if (!(tpc & 0x08)) { - if (val & MS_CRC16_ERR) { - ms_set_err_code(chip, MS_CRC16_ERROR); - return ms_parse_err_code(chip); - } - } else { - if (CHK_MSPRO(ms_card) && !(val & 0x80)) { - if (val & (MS_INT_ERR | MS_INT_CMDNK)) { - ms_set_err_code(chip, MS_CMD_NK); - return ms_parse_err_code(chip); - } - } - } - - if (val & MS_RDY_TIMEOUT) { - ms_set_err_code(chip, MS_TO_ERROR); - return ms_parse_err_code(chip); - } - - ms_set_err_code(chip, MS_TO_ERROR); - return ms_parse_err_code(chip); - } - - ptr = rtsx_get_cmd_data(chip) + 1; - - for (i = 0; i < data_len; i++) - data[i] = ptr[i]; - - if (tpc == PRO_READ_SHORT_DATA && data_len == 8) { - dev_dbg(rtsx_dev(chip), "Read format progress:\n"); - print_hex_dump_bytes(KBUILD_MODNAME ": ", DUMP_PREFIX_NONE, ptr, - cnt); - } - - return STATUS_SUCCESS; -} - -static int ms_set_rw_reg_addr(struct rtsx_chip *chip, u8 read_start, - u8 read_cnt, u8 write_start, u8 write_cnt) -{ - int retval, i; - u8 data[4]; - - data[0] = read_start; - data[1] = read_cnt; - data[2] = write_start; - data[3] = write_cnt; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, SET_RW_REG_ADRS, 4, - NO_WAIT_INT, data, 4); - if (retval == STATUS_SUCCESS) - return STATUS_SUCCESS; - rtsx_clear_ms_error(chip); - } - - return STATUS_FAIL; -} - -static int ms_send_cmd(struct rtsx_chip *chip, u8 cmd, u8 cfg) -{ - u8 data[2]; - - data[0] = cmd; - data[1] = 0; - - return ms_write_bytes(chip, PRO_SET_CMD, 1, cfg, data, 1); -} - -static int ms_set_init_para(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - - if (CHK_HG8BIT(ms_card)) { - if (chip->asic_code) - ms_card->ms_clock = chip->asic_ms_hg_clk; - else - ms_card->ms_clock = chip->fpga_ms_hg_clk; - - } else if (CHK_MSPRO(ms_card) || CHK_MS4BIT(ms_card)) { - if (chip->asic_code) - ms_card->ms_clock = chip->asic_ms_4bit_clk; - else - ms_card->ms_clock = chip->fpga_ms_4bit_clk; - - } else { - if (chip->asic_code) - ms_card->ms_clock = chip->asic_ms_1bit_clk; - else - ms_card->ms_clock = chip->fpga_ms_1bit_clk; - } - - retval = switch_clock(chip, ms_card->ms_clock); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = select_card(chip, MS_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int ms_switch_clock(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - - retval = select_card(chip, MS_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = switch_clock(chip, ms_card->ms_clock); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int ms_pull_ctl_disable(struct rtsx_chip *chip) -{ - int retval; - - if (CHECK_PID(chip, 0x5208)) { - retval = rtsx_write_register(chip, CARD_PULL_CTL1, 0xFF, - MS_D1_PD | MS_D2_PD | MS_CLK_PD | - MS_D6_PD); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF, - MS_D3_PD | MS_D0_PD | MS_BS_PD | - XD_D4_PD); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF, - MS_D7_PD | XD_CE_PD | XD_CLE_PD | - XD_CD_PU); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF, - XD_RDY_PD | SD_D3_PD | SD_D2_PD | - XD_ALE_PD); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF, - MS_INS_PU | SD_WP_PD | SD_CD_PU | - SD_CMD_PD); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF, - MS_D5_PD | MS_D4_PD); - if (retval) - return retval; - - } else if (CHECK_PID(chip, 0x5288)) { - if (CHECK_BARO_PKG(chip, QFN)) { - retval = rtsx_write_register(chip, CARD_PULL_CTL1, - 0xFF, 0x55); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_PULL_CTL2, - 0xFF, 0x55); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_PULL_CTL3, - 0xFF, 0x4B); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_PULL_CTL4, - 0xFF, 0x69); - if (retval) - return retval; - } - } - - return STATUS_SUCCESS; -} - -static int ms_pull_ctl_enable(struct rtsx_chip *chip) -{ - int retval; - - rtsx_init_cmd(chip); - - if (CHECK_PID(chip, 0x5208)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, - MS_D1_PD | MS_D2_PD | MS_CLK_NP | MS_D6_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, - MS_D3_PD | MS_D0_PD | MS_BS_NP | XD_D4_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, - MS_D7_PD | XD_CE_PD | XD_CLE_PD | XD_CD_PU); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, - XD_RDY_PD | SD_D3_PD | SD_D2_PD | XD_ALE_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, - MS_INS_PU | SD_WP_PD | SD_CD_PU | SD_CMD_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, - MS_D5_PD | MS_D4_PD); - } else if (CHECK_PID(chip, 0x5288)) { - if (CHECK_BARO_PKG(chip, QFN)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, - CARD_PULL_CTL1, 0xFF, 0x55); - rtsx_add_cmd(chip, WRITE_REG_CMD, - CARD_PULL_CTL2, 0xFF, 0x45); - rtsx_add_cmd(chip, WRITE_REG_CMD, - CARD_PULL_CTL3, 0xFF, 0x4B); - rtsx_add_cmd(chip, WRITE_REG_CMD, - CARD_PULL_CTL4, 0xFF, 0x29); - } - } - - retval = rtsx_send_cmd(chip, MS_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int ms_prepare_reset(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - u8 oc_mask = 0; - - ms_card->ms_type = 0; - ms_card->check_ms_flow = 0; - ms_card->switch_8bit_fail = 0; - ms_card->delay_write.delay_write_flag = 0; - - ms_card->pro_under_formatting = 0; - - retval = ms_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (!chip->ft2_fast_mode) - wait_timeout(250); - - retval = enable_card_clock(chip, MS_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (chip->asic_code) { - retval = ms_pull_ctl_enable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register(chip, FPGA_PULL_CTL, - FPGA_MS_PULL_CTL_BIT | 0x20, 0); - if (retval) - return retval; - } - - if (!chip->ft2_fast_mode) { - retval = card_power_on(chip, MS_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - wait_timeout(150); - -#ifdef SUPPORT_OCP - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) - oc_mask = MS_OC_NOW | MS_OC_EVER; - else - oc_mask = SD_OC_NOW | SD_OC_EVER; - - if (chip->ocp_stat & oc_mask) { - dev_dbg(rtsx_dev(chip), "Over current, OCPSTAT is 0x%x\n", - chip->ocp_stat); - return STATUS_FAIL; - } -#endif - } - - retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, - MS_OUTPUT_EN); - if (retval) - return retval; - - if (chip->asic_code) { - retval = rtsx_write_register(chip, MS_CFG, 0xFF, - SAMPLE_TIME_RISING | - PUSH_TIME_DEFAULT | - NO_EXTEND_TOGGLE | - MS_BUS_WIDTH_1); - if (retval) - return retval; - - } else { - retval = rtsx_write_register(chip, MS_CFG, 0xFF, - SAMPLE_TIME_FALLING | - PUSH_TIME_DEFAULT | - NO_EXTEND_TOGGLE | - MS_BUS_WIDTH_1); - if (retval) - return retval; - } - retval = rtsx_write_register(chip, MS_TRANS_CFG, 0xFF, - NO_WAIT_INT | NO_AUTO_READ_INT_REG); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_STOP, MS_STOP | MS_CLR_ERR, - MS_STOP | MS_CLR_ERR); - if (retval) - return retval; - - retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 val; - - retval = ms_set_rw_reg_addr(chip, PRO_STATUS_REG, 6, SYSTEM_PARAM, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, READ_REG, - 6, NO_WAIT_INT); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - retval = rtsx_read_register(chip, PPBUF_BASE2 + 2, &val); - if (retval) - return retval; - - dev_dbg(rtsx_dev(chip), "Type register: 0x%x\n", val); - if (val != 0x01) { - if (val != 0x02) - ms_card->check_ms_flow = 1; - - return STATUS_FAIL; - } - - retval = rtsx_read_register(chip, PPBUF_BASE2 + 4, &val); - if (retval) - return retval; - - dev_dbg(rtsx_dev(chip), "Category register: 0x%x\n", val); - if (val != 0) { - ms_card->check_ms_flow = 1; - return STATUS_FAIL; - } - - retval = rtsx_read_register(chip, PPBUF_BASE2 + 5, &val); - if (retval) - return retval; - - dev_dbg(rtsx_dev(chip), "Class register: 0x%x\n", val); - if (val == 0) { - retval = rtsx_read_register(chip, PPBUF_BASE2, &val); - if (retval) - return retval; - - if (val & WRT_PRTCT) - chip->card_wp |= MS_CARD; - else - chip->card_wp &= ~MS_CARD; - - } else if ((val == 0x01) || (val == 0x02) || (val == 0x03)) { - chip->card_wp |= MS_CARD; - } else { - ms_card->check_ms_flow = 1; - return STATUS_FAIL; - } - - ms_card->ms_type |= TYPE_MSPRO; - - retval = rtsx_read_register(chip, PPBUF_BASE2 + 3, &val); - if (retval) - return retval; - - dev_dbg(rtsx_dev(chip), "IF Mode register: 0x%x\n", val); - if (val == 0) { - ms_card->ms_type &= 0x0F; - } else if (val == 7) { - if (switch_8bit_bus) - ms_card->ms_type |= MS_HG; - else - ms_card->ms_type &= 0x0F; - - } else { - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int ms_confirm_cpu_startup(struct rtsx_chip *chip) -{ - int retval, i, k; - u8 val; - - /* Confirm CPU StartUp */ - k = 0; - do { - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - ms_set_err_code(chip, MS_NO_CARD); - return STATUS_FAIL; - } - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_read_bytes(chip, GET_INT, 1, - NO_WAIT_INT, &val, 1); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - if (k > 100) - return STATUS_FAIL; - - k++; - wait_timeout(100); - } while (!(val & INT_REG_CED)); - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - if (val & INT_REG_ERR) { - if (val & INT_REG_CMDNK) - chip->card_wp |= (MS_CARD); - else - return STATUS_FAIL; - } - /* -- end confirm CPU startup */ - - return STATUS_SUCCESS; -} - -static int ms_switch_parallel_bus(struct rtsx_chip *chip) -{ - int retval, i; - u8 data[2]; - - data[0] = PARALLEL_4BIT_IF; - data[1] = 0; - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, WRITE_REG, 1, NO_WAIT_INT, - data, 2); - if (retval == STATUS_SUCCESS) - break; - } - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int ms_switch_8bit_bus(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 data[2]; - - data[0] = PARALLEL_8BIT_IF; - data[1] = 0; - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, WRITE_REG, 1, - NO_WAIT_INT, data, 2); - if (retval == STATUS_SUCCESS) - break; - } - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, MS_CFG, 0x98, - MS_BUS_WIDTH_8 | SAMPLE_TIME_FALLING); - if (retval) - return retval; - - ms_card->ms_type |= MS_8BIT; - retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, - 1, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int ms_pro_reset_flow(struct rtsx_chip *chip, int switch_8bit_bus) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - - for (i = 0; i < 3; i++) { - retval = ms_prepare_reset(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_identify_media_type(chip, switch_8bit_bus); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_confirm_cpu_startup(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_switch_parallel_bus(chip); - if (retval != STATUS_SUCCESS) { - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - ms_set_err_code(chip, MS_NO_CARD); - return STATUS_FAIL; - } - continue; - } else { - break; - } - } - - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - /* Switch MS-PRO into Parallel mode */ - retval = rtsx_write_register(chip, MS_CFG, 0x18, MS_BUS_WIDTH_4); - if (retval) - return retval; - - retval = rtsx_write_register(chip, MS_CFG, PUSH_TIME_ODD, - PUSH_TIME_ODD); - if (retval) - return retval; - - retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - /* If MSPro HG Card, We shall try to switch to 8-bit bus */ - if (CHK_MSHG(ms_card) && chip->support_ms_8bit && switch_8bit_bus) { - retval = ms_switch_8bit_bus(chip); - if (retval != STATUS_SUCCESS) { - ms_card->switch_8bit_fail = 1; - return STATUS_FAIL; - } - } - - return STATUS_SUCCESS; -} - -#ifdef XC_POWERCLASS -static int msxc_change_power(struct rtsx_chip *chip, u8 mode) -{ - int retval; - u8 buf[6]; - - ms_cleanup_work(chip); - - retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_DATA_COUNT1, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - buf[0] = 0; - buf[1] = mode; - buf[2] = 0; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - - retval = ms_write_bytes(chip, PRO_WRITE_REG, 6, NO_WAIT_INT, buf, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_send_cmd(chip, XC_CHG_POWER, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_read_register(chip, MS_TRANS_CFG, buf); - if (retval) - return retval; - - if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR)) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} -#endif - -static int ms_read_attribute_info(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 val, *buf, class_code, device_type, sub_class, data[16]; - u16 total_blk = 0, blk_size = 0; -#ifdef SUPPORT_MSXC - u32 xc_total_blk = 0, xc_blk_size = 0; -#endif - u32 sys_info_addr = 0, sys_info_size; -#ifdef SUPPORT_PCGL_1P18 - u32 model_name_addr = 0, model_name_size; - int found_sys_info = 0, found_model_name = 0; -#endif - - retval = ms_set_rw_reg_addr(chip, PRO_INT_REG, 2, PRO_SYSTEM_PARAM, 7); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHK_MS8BIT(ms_card)) - data[0] = PARALLEL_8BIT_IF; - else - data[0] = PARALLEL_4BIT_IF; - - data[1] = 0; - - data[2] = 0x40; - data[3] = 0; - data[4] = 0; - data[5] = 0; - data[6] = 0; - data[7] = 0; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, PRO_WRITE_REG, 7, NO_WAIT_INT, - data, 8); - if (retval == STATUS_SUCCESS) - break; - } - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - buf = kmalloc(64 * 512, GFP_KERNEL); - if (!buf) - return STATUS_ERROR; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_send_cmd(chip, PRO_READ_ATRB, WAIT_INT); - if (retval != STATUS_SUCCESS) - continue; - - retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - if (!(val & MS_INT_BREQ)) { - kfree(buf); - return STATUS_FAIL; - } - retval = ms_transfer_data(chip, MS_TM_AUTO_READ, - PRO_READ_LONG_DATA, 0x40, WAIT_INT, - 0, 0, buf, 64 * 512); - if (retval == STATUS_SUCCESS) - break; - - rtsx_clear_ms_error(chip); - } - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - - i = 0; - do { - retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - - if ((val & MS_INT_CED) || !(val & MS_INT_BREQ)) - break; - - retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, - PRO_READ_LONG_DATA, 0, WAIT_INT); - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - - i++; - } while (i < 1024); - - if (buf[0] != 0xa5 && buf[1] != 0xc3) { - /* Signature code is wrong */ - kfree(buf); - return STATUS_FAIL; - } - - if (buf[4] < 1 || buf[4] > 12) { - kfree(buf); - return STATUS_FAIL; - } - - for (i = 0; i < buf[4]; i++) { - int cur_addr_off = 16 + i * 12; - -#ifdef SUPPORT_MSXC - if (buf[cur_addr_off + 8] == 0x10 || - buf[cur_addr_off + 8] == 0x13) { -#else - if (buf[cur_addr_off + 8] == 0x10) { -#endif - sys_info_addr = ((u32)buf[cur_addr_off + 0] << 24) | - ((u32)buf[cur_addr_off + 1] << 16) | - ((u32)buf[cur_addr_off + 2] << 8) | - buf[cur_addr_off + 3]; - sys_info_size = ((u32)buf[cur_addr_off + 4] << 24) | - ((u32)buf[cur_addr_off + 5] << 16) | - ((u32)buf[cur_addr_off + 6] << 8) | - buf[cur_addr_off + 7]; - dev_dbg(rtsx_dev(chip), "sys_info_addr = 0x%x, sys_info_size = 0x%x\n", - sys_info_addr, sys_info_size); - if (sys_info_size != 96) { - kfree(buf); - return STATUS_FAIL; - } - if (sys_info_addr < 0x1A0) { - kfree(buf); - return STATUS_FAIL; - } - if ((sys_info_size + sys_info_addr) > 0x8000) { - kfree(buf); - return STATUS_FAIL; - } - -#ifdef SUPPORT_MSXC - if (buf[cur_addr_off + 8] == 0x13) - ms_card->ms_type |= MS_XC; -#endif -#ifdef SUPPORT_PCGL_1P18 - found_sys_info = 1; -#else - break; -#endif - } -#ifdef SUPPORT_PCGL_1P18 - if (buf[cur_addr_off + 8] == 0x15) { - model_name_addr = ((u32)buf[cur_addr_off + 0] << 24) | - ((u32)buf[cur_addr_off + 1] << 16) | - ((u32)buf[cur_addr_off + 2] << 8) | - buf[cur_addr_off + 3]; - model_name_size = ((u32)buf[cur_addr_off + 4] << 24) | - ((u32)buf[cur_addr_off + 5] << 16) | - ((u32)buf[cur_addr_off + 6] << 8) | - buf[cur_addr_off + 7]; - dev_dbg(rtsx_dev(chip), "model_name_addr = 0x%x, model_name_size = 0x%x\n", - model_name_addr, model_name_size); - if (model_name_size != 48) { - kfree(buf); - return STATUS_FAIL; - } - if (model_name_addr < 0x1A0) { - kfree(buf); - return STATUS_FAIL; - } - if ((model_name_size + model_name_addr) > 0x8000) { - kfree(buf); - return STATUS_FAIL; - } - - found_model_name = 1; - } - - if (found_sys_info && found_model_name) - break; -#endif - } - - if (i == buf[4]) { - kfree(buf); - return STATUS_FAIL; - } - - class_code = buf[sys_info_addr + 0]; - device_type = buf[sys_info_addr + 56]; - sub_class = buf[sys_info_addr + 46]; -#ifdef SUPPORT_MSXC - if (CHK_MSXC(ms_card)) { - xc_total_blk = ((u32)buf[sys_info_addr + 6] << 24) | - ((u32)buf[sys_info_addr + 7] << 16) | - ((u32)buf[sys_info_addr + 8] << 8) | - buf[sys_info_addr + 9]; - xc_blk_size = ((u32)buf[sys_info_addr + 32] << 24) | - ((u32)buf[sys_info_addr + 33] << 16) | - ((u32)buf[sys_info_addr + 34] << 8) | - buf[sys_info_addr + 35]; - dev_dbg(rtsx_dev(chip), "xc_total_blk = 0x%x, xc_blk_size = 0x%x\n", - xc_total_blk, xc_blk_size); - } else { - total_blk = ((u16)buf[sys_info_addr + 6] << 8) | - buf[sys_info_addr + 7]; - blk_size = ((u16)buf[sys_info_addr + 2] << 8) | - buf[sys_info_addr + 3]; - dev_dbg(rtsx_dev(chip), "total_blk = 0x%x, blk_size = 0x%x\n", - total_blk, blk_size); - } -#else - total_blk = ((u16)buf[sys_info_addr + 6] << 8) | buf[sys_info_addr + 7]; - blk_size = ((u16)buf[sys_info_addr + 2] << 8) | buf[sys_info_addr + 3]; - dev_dbg(rtsx_dev(chip), "total_blk = 0x%x, blk_size = 0x%x\n", - total_blk, blk_size); -#endif - - dev_dbg(rtsx_dev(chip), "class_code = 0x%x, device_type = 0x%x, sub_class = 0x%x\n", - class_code, device_type, sub_class); - - memcpy(ms_card->raw_sys_info, buf + sys_info_addr, 96); -#ifdef SUPPORT_PCGL_1P18 - memcpy(ms_card->raw_model_name, buf + model_name_addr, 48); -#endif - - kfree(buf); - -#ifdef SUPPORT_MSXC - if (CHK_MSXC(ms_card)) { - if (class_code != 0x03) - return STATUS_FAIL; - } else { - if (class_code != 0x02) - return STATUS_FAIL; - } -#else - if (class_code != 0x02) - return STATUS_FAIL; -#endif - - if (device_type != 0x00) { - if (device_type == 0x01 || device_type == 0x02 || - device_type == 0x03) { - chip->card_wp |= MS_CARD; - } else { - return STATUS_FAIL; - } - } - - if (sub_class & 0xC0) - return STATUS_FAIL; - - dev_dbg(rtsx_dev(chip), "class_code: 0x%x, device_type: 0x%x, sub_class: 0x%x\n", - class_code, device_type, sub_class); - -#ifdef SUPPORT_MSXC - if (CHK_MSXC(ms_card)) { - chip->capacity[chip->card2lun[MS_CARD]] = - ms_card->capacity = xc_total_blk * xc_blk_size; - } else { - chip->capacity[chip->card2lun[MS_CARD]] = - ms_card->capacity = total_blk * blk_size; - } -#else - ms_card->capacity = total_blk * blk_size; - chip->capacity[chip->card2lun[MS_CARD]] = ms_card->capacity; -#endif - - return STATUS_SUCCESS; -} - -#ifdef SUPPORT_MAGIC_GATE -static int mg_set_tpc_para_sub(struct rtsx_chip *chip, - int type, u8 mg_entry_num); -#endif - -static int reset_ms_pro(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; -#ifdef XC_POWERCLASS - u8 change_power_class; - - if (chip->ms_power_class_en & 0x02) - change_power_class = 2; - else if (chip->ms_power_class_en & 0x01) - change_power_class = 1; - else - change_power_class = 0; -#endif - -#ifdef XC_POWERCLASS -retry: -#endif - retval = ms_pro_reset_flow(chip, 1); - if (retval != STATUS_SUCCESS) { - if (ms_card->switch_8bit_fail) { - retval = ms_pro_reset_flow(chip, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - return STATUS_FAIL; - } - } - - retval = ms_read_attribute_info(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - -#ifdef XC_POWERCLASS - if (CHK_HG8BIT(ms_card)) - change_power_class = 0; - - if (change_power_class && CHK_MSXC(ms_card)) { - u8 power_class_en = chip->ms_power_class_en; - - dev_dbg(rtsx_dev(chip), "power_class_en = 0x%x\n", - power_class_en); - dev_dbg(rtsx_dev(chip), "change_power_class = %d\n", - change_power_class); - - if (change_power_class) - power_class_en &= (1 << (change_power_class - 1)); - else - power_class_en = 0; - - if (power_class_en) { - u8 power_class_mode = - (ms_card->raw_sys_info[46] & 0x18) >> 3; - dev_dbg(rtsx_dev(chip), "power_class_mode = 0x%x", - power_class_mode); - if (change_power_class > power_class_mode) - change_power_class = power_class_mode; - if (change_power_class) { - retval = msxc_change_power(chip, - change_power_class); - if (retval != STATUS_SUCCESS) { - change_power_class--; - goto retry; - } - } - } - } -#endif - -#ifdef SUPPORT_MAGIC_GATE - retval = mg_set_tpc_para_sub(chip, 0, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; -#endif - - if (CHK_HG8BIT(ms_card)) - chip->card_bus_width[chip->card2lun[MS_CARD]] = 8; - else - chip->card_bus_width[chip->card2lun[MS_CARD]] = 4; - - return STATUS_SUCCESS; -} - -static int ms_read_status_reg(struct rtsx_chip *chip) -{ - int retval; - u8 val[2]; - - retval = ms_set_rw_reg_addr(chip, STATUS_REG0, 2, 0, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_read_bytes(chip, READ_REG, 2, NO_WAIT_INT, val, 2); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val[1] & (STS_UCDT | STS_UCEX | STS_UCFG)) { - ms_set_err_code(chip, MS_FLASH_READ_ERROR); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int ms_read_extra_data(struct rtsx_chip *chip, - u16 block_addr, u8 page_num, u8 *buf, int buf_len) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 val, data[10]; - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHK_MS4BIT(ms_card)) { - /* Parallel interface */ - data[0] = 0x88; - } else { - /* Serial interface */ - data[0] = 0x80; - } - data[1] = 0; - data[2] = (u8)(block_addr >> 8); - data[3] = (u8)block_addr; - data[4] = 0x40; - data[5] = page_num; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, - data, 6); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - if (val & INT_REG_CED) { - if (val & INT_REG_ERR) { - retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, - MS_EXTRA_SIZE, SYSTEM_PARAM, - 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - } - - retval = ms_read_bytes(chip, READ_REG, MS_EXTRA_SIZE, NO_WAIT_INT, - data, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (buf && buf_len) { - if (buf_len > MS_EXTRA_SIZE) - buf_len = MS_EXTRA_SIZE; - memcpy(buf, data, buf_len); - } - - return STATUS_SUCCESS; -} - -static int ms_write_extra_data(struct rtsx_chip *chip, u16 block_addr, - u8 page_num, u8 *buf, int buf_len) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 val, data[16]; - - if (!buf || buf_len < MS_EXTRA_SIZE) - return STATUS_FAIL; - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, 6 + MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(block_addr >> 8); - data[3] = (u8)block_addr; - data[4] = 0x40; - data[5] = page_num; - - for (i = 6; i < MS_EXTRA_SIZE + 6; i++) - data[i] = buf[i - 6]; - - retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE), - NO_WAIT_INT, data, 16); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - if (val & INT_REG_CED) { - if (val & INT_REG_ERR) { - ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - } - - return STATUS_SUCCESS; -} - -static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - u8 val, data[6]; - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(block_addr >> 8); - data[3] = (u8)block_addr; - data[4] = 0x20; - data[5] = page_num; - - retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - - if (val & INT_REG_CED) { - if (val & INT_REG_ERR) { - if (!(val & INT_REG_BREQ)) { - ms_set_err_code(chip, MS_FLASH_READ_ERROR); - return STATUS_FAIL; - } - retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) - ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - - } else { - if (!(val & INT_REG_BREQ)) { - ms_set_err_code(chip, MS_BREQ_ERROR); - return STATUS_FAIL; - } - } - } - - retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA, - 0, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - u8 val, data[8], extra[MS_EXTRA_SIZE]; - - retval = ms_read_extra_data(chip, phy_blk, 0, extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, 7); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(phy_blk >> 8); - data[3] = (u8)phy_blk; - data[4] = 0x80; - data[5] = 0; - data[6] = extra[0] & 0x7F; - data[7] = 0xFF; - - retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 7); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - - if (val & INT_REG_CED) { - if (val & INT_REG_ERR) { - ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - } - - return STATUS_SUCCESS; -} - -static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i = 0; - u8 val, data[6]; - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(phy_blk >> 8); - data[3] = (u8)phy_blk; - data[4] = 0; - data[5] = 0; - - retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - -ERASE_RTY: - retval = ms_send_cmd(chip, BLOCK_ERASE, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - if (i < 3) { - i++; - goto ERASE_RTY; - } - - ms_set_err_code(chip, MS_CMD_NK); - ms_set_bad_block(chip, phy_blk); - return STATUS_FAIL; - } - - if (val & INT_REG_CED) { - if (val & INT_REG_ERR) { - ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - } - - return STATUS_SUCCESS; -} - -static void ms_set_page_status(u16 log_blk, u8 type, u8 *extra, int extra_len) -{ - if (!extra || extra_len < MS_EXTRA_SIZE) - return; - - memset(extra, 0xFF, MS_EXTRA_SIZE); - - if (type == set_PS_NG) { - /* set page status as 1:NG,and block status keep 1:OK */ - extra[0] = 0xB8; - } else { - /* set page status as 0:Data Error,and block status keep 1:OK */ - extra[0] = 0x98; - } - - extra[2] = (u8)(log_blk >> 8); - extra[3] = (u8)log_blk; -} - -static int ms_init_page(struct rtsx_chip *chip, u16 phy_blk, u16 log_blk, - u8 start_page, u8 end_page) -{ - int retval; - u8 extra[MS_EXTRA_SIZE], i; - - memset(extra, 0xff, MS_EXTRA_SIZE); - - extra[0] = 0xf8; /* Block, page OK, data erased */ - extra[1] = 0xff; - extra[2] = (u8)(log_blk >> 8); - extra[3] = (u8)log_blk; - - for (i = start_page; i < end_page; i++) { - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - ms_set_err_code(chip, MS_NO_CARD); - return STATUS_FAIL; - } - - retval = ms_write_extra_data(chip, phy_blk, i, - extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, - u16 log_blk, u8 start_page, u8 end_page) -{ - struct ms_info *ms_card = &chip->ms_card; - bool uncorrect_flag = false; - int retval, rty_cnt; - u8 extra[MS_EXTRA_SIZE], val, i, j, data[16]; - - dev_dbg(rtsx_dev(chip), "Copy page from 0x%x to 0x%x, logical block is 0x%x\n", - old_blk, new_blk, log_blk); - dev_dbg(rtsx_dev(chip), "start_page = %d, end_page = %d\n", - start_page, end_page); - - retval = ms_read_extra_data(chip, new_blk, 0, extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_read_register(chip, PPBUF_BASE2, &val); - if (retval) - return retval; - - if (val & BUF_FULL) { - retval = ms_send_cmd(chip, CLEAR_BUF, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (!(val & INT_REG_CED)) { - ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - } - - for (i = start_page; i < end_page; i++) { - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - ms_set_err_code(chip, MS_NO_CARD); - return STATUS_FAIL; - } - - retval = ms_read_extra_data(chip, old_blk, i, extra, - MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, - MS_EXTRA_SIZE, SYSTEM_PARAM, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(old_blk >> 8); - data[3] = (u8)old_blk; - data[4] = 0x20; - data[5] = i; - - retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, - data, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - - if (val & INT_REG_CED) { - if (val & INT_REG_ERR) { - retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) { - uncorrect_flag = true; - dev_dbg(rtsx_dev(chip), "Uncorrectable error\n"); - } else { - uncorrect_flag = false; - } - - retval = ms_transfer_tpc(chip, - MS_TM_NORMAL_READ, - READ_PAGE_DATA, - 0, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (uncorrect_flag) { - ms_set_page_status(log_blk, set_PS_NG, - extra, - MS_EXTRA_SIZE); - if (i == 0) - extra[0] &= 0xEF; - - ms_write_extra_data(chip, old_blk, i, - extra, - MS_EXTRA_SIZE); - dev_dbg(rtsx_dev(chip), "page %d : extra[0] = 0x%x\n", - i, extra[0]); - MS_SET_BAD_BLOCK_FLG(ms_card); - - ms_set_page_status(log_blk, - set_PS_error, extra, - MS_EXTRA_SIZE); - ms_write_extra_data(chip, new_blk, i, - extra, - MS_EXTRA_SIZE); - continue; - } - - for (rty_cnt = 0; rty_cnt < MS_MAX_RETRY_COUNT; - rty_cnt++) { - retval = ms_transfer_tpc(chip, - MS_TM_NORMAL_WRITE, - WRITE_PAGE_DATA, - 0, NO_WAIT_INT); - if (retval == STATUS_SUCCESS) - break; - } - if (rty_cnt == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - } - - if (!(val & INT_REG_BREQ)) { - ms_set_err_code(chip, MS_BREQ_ERROR); - return STATUS_FAIL; - } - } - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, (6 + MS_EXTRA_SIZE)); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(new_blk >> 8); - data[3] = (u8)new_blk; - data[4] = 0x20; - data[5] = i; - - if ((extra[0] & 0x60) != 0x60) - data[6] = extra[0]; - else - data[6] = 0xF8; - - data[6 + 1] = 0xFF; - data[6 + 2] = (u8)(log_blk >> 8); - data[6 + 3] = (u8)log_blk; - - for (j = 4; j <= MS_EXTRA_SIZE; j++) - data[6 + j] = 0xFF; - - retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE), - NO_WAIT_INT, data, 16); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - - if (val & INT_REG_CED) { - if (val & INT_REG_ERR) { - ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - } - - if (i == 0) { - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, - MS_EXTRA_SIZE, SYSTEM_PARAM, - 7); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(old_blk >> 8); - data[3] = (u8)old_blk; - data[4] = 0x80; - data[5] = 0; - data[6] = 0xEF; - data[7] = 0xFF; - - retval = ms_write_bytes(chip, WRITE_REG, 7, - NO_WAIT_INT, data, 8); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_read_bytes(chip, GET_INT, 1, - NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - - if (val & INT_REG_CED) { - if (val & INT_REG_ERR) { - ms_set_err_code(chip, - MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - } - } - } - - return STATUS_SUCCESS; -} - -static int reset_ms(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - u16 i, reg_addr, block_size; - u8 val, extra[MS_EXTRA_SIZE], j, *ptr; -#ifndef SUPPORT_MAGIC_GATE - u16 eblock_cnt; -#endif - - retval = ms_prepare_reset(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_card->ms_type |= TYPE_MS; - - retval = ms_send_cmd(chip, MS_RESET, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_read_register(chip, PPBUF_BASE2, &val); - if (retval) - return retval; - - if (val & WRT_PRTCT) - chip->card_wp |= MS_CARD; - else - chip->card_wp &= ~MS_CARD; - - i = 0; - -RE_SEARCH: - /* Search Boot Block */ - while (i < (MAX_DEFECTIVE_BLOCK + 2)) { - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - ms_set_err_code(chip, MS_NO_CARD); - return STATUS_FAIL; - } - - retval = ms_read_extra_data(chip, i, 0, extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) { - i++; - continue; - } - - if (extra[0] & BLOCK_OK) { - if (!(extra[1] & NOT_BOOT_BLOCK)) { - ms_card->boot_block = i; - break; - } - } - i++; - } - - if (i == (MAX_DEFECTIVE_BLOCK + 2)) { - dev_dbg(rtsx_dev(chip), "No boot block found!"); - return STATUS_FAIL; - } - - for (j = 0; j < 3; j++) { - retval = ms_read_page(chip, ms_card->boot_block, j); - if (retval != STATUS_SUCCESS) { - if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) { - i = ms_card->boot_block + 1; - ms_set_err_code(chip, MS_NO_ERROR); - goto RE_SEARCH; - } - } - } - - retval = ms_read_page(chip, ms_card->boot_block, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - /* Read MS system information as sys_info */ - rtsx_init_cmd(chip); - - for (i = 0; i < 96; i++) - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 0x1A0 + i, 0, 0); - - retval = rtsx_send_cmd(chip, MS_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - ptr = rtsx_get_cmd_data(chip); - memcpy(ms_card->raw_sys_info, ptr, 96); - - /* Read useful block contents */ - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID0, 0, 0); - rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID1, 0, 0); - - for (reg_addr = DISABLED_BLOCK0; reg_addr <= DISABLED_BLOCK3; - reg_addr++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - - for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - - rtsx_add_cmd(chip, READ_REG_CMD, MS_device_type, 0, 0); - rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_support, 0, 0); - - retval = rtsx_send_cmd(chip, MS_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - ptr = rtsx_get_cmd_data(chip); - - dev_dbg(rtsx_dev(chip), "Boot block data:\n"); - dev_dbg(rtsx_dev(chip), "%*ph\n", 16, ptr); - - /* Block ID error - * HEADER_ID0, HEADER_ID1 - */ - if (ptr[0] != 0x00 || ptr[1] != 0x01) { - i = ms_card->boot_block + 1; - goto RE_SEARCH; - } - - /* Page size error - * PAGE_SIZE_0, PAGE_SIZE_1 - */ - if (ptr[12] != 0x02 || ptr[13] != 0x00) { - i = ms_card->boot_block + 1; - goto RE_SEARCH; - } - - if (ptr[14] == 1 || ptr[14] == 3) - chip->card_wp |= MS_CARD; - - /* BLOCK_SIZE_0, BLOCK_SIZE_1 */ - block_size = ((u16)ptr[6] << 8) | ptr[7]; - if (block_size == 0x0010) { - /* Block size 16KB */ - ms_card->block_shift = 5; - ms_card->page_off = 0x1F; - } else if (block_size == 0x0008) { - /* Block size 8KB */ - ms_card->block_shift = 4; - ms_card->page_off = 0x0F; - } - - /* BLOCK_COUNT_0, BLOCK_COUNT_1 */ - ms_card->total_block = ((u16)ptr[8] << 8) | ptr[9]; - -#ifdef SUPPORT_MAGIC_GATE - j = ptr[10]; - - if (ms_card->block_shift == 4) { /* 4MB or 8MB */ - if (j < 2) { /* Effective block for 4MB: 0x1F0 */ - ms_card->capacity = 0x1EE0; - } else { /* Effective block for 8MB: 0x3E0 */ - ms_card->capacity = 0x3DE0; - } - } else { /* 16MB, 32MB, 64MB or 128MB */ - if (j < 5) { /* Effective block for 16MB: 0x3E0 */ - ms_card->capacity = 0x7BC0; - } else if (j < 0xA) { /* Effective block for 32MB: 0x7C0 */ - ms_card->capacity = 0xF7C0; - } else if (j < 0x11) { /* Effective block for 64MB: 0xF80 */ - ms_card->capacity = 0x1EF80; - } else { /* Effective block for 128MB: 0x1F00 */ - ms_card->capacity = 0x3DF00; - } - } -#else - /* EBLOCK_COUNT_0, EBLOCK_COUNT_1 */ - eblock_cnt = ((u16)ptr[10] << 8) | ptr[11]; - - ms_card->capacity = ((u32)eblock_cnt - 2) << ms_card->block_shift; -#endif - - chip->capacity[chip->card2lun[MS_CARD]] = ms_card->capacity; - - /* Switch I/F Mode */ - if (ptr[15]) { - retval = ms_set_rw_reg_addr(chip, 0, 0, SYSTEM_PARAM, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, PPBUF_BASE2, 0xFF, 0x88); - if (retval) - return retval; - - retval = rtsx_write_register(chip, PPBUF_BASE2 + 1, 0xFF, 0); - if (retval) - return retval; - - retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG, 1, - NO_WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, MS_CFG, - 0x58 | MS_NO_CHECK_INT, - MS_BUS_WIDTH_4 | - PUSH_TIME_ODD | - MS_NO_CHECK_INT); - if (retval) - return retval; - - ms_card->ms_type |= MS_4BIT; - } - - if (CHK_MS4BIT(ms_card)) - chip->card_bus_width[chip->card2lun[MS_CARD]] = 4; - else - chip->card_bus_width[chip->card2lun[MS_CARD]] = 1; - - return STATUS_SUCCESS; -} - -static int ms_init_l2p_tbl(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int size, i, seg_no, retval; - u16 defect_block, reg_addr; - u8 val1, val2; - - ms_card->segment_cnt = ms_card->total_block >> 9; - dev_dbg(rtsx_dev(chip), "ms_card->segment_cnt = %d\n", - ms_card->segment_cnt); - - size = ms_card->segment_cnt * sizeof(struct zone_entry); - ms_card->segment = vzalloc(size); - if (!ms_card->segment) - return STATUS_FAIL; - - retval = ms_read_page(chip, ms_card->boot_block, 1); - if (retval != STATUS_SUCCESS) - goto INIT_FAIL; - - reg_addr = PPBUF_BASE2; - for (i = 0; i < (((ms_card->total_block >> 9) * 10) + 1); i++) { - int block_no; - - retval = rtsx_read_register(chip, reg_addr++, &val1); - if (retval != STATUS_SUCCESS) - goto INIT_FAIL; - - retval = rtsx_read_register(chip, reg_addr++, &val2); - if (retval != STATUS_SUCCESS) - goto INIT_FAIL; - - defect_block = ((u16)val1 << 8) | val2; - if (defect_block == 0xFFFF) - break; - - seg_no = defect_block / 512; - - block_no = ms_card->segment[seg_no].disable_count++; - ms_card->segment[seg_no].defect_list[block_no] = defect_block; - } - - for (i = 0; i < ms_card->segment_cnt; i++) { - ms_card->segment[i].build_flag = 0; - ms_card->segment[i].l2p_table = NULL; - ms_card->segment[i].free_table = NULL; - ms_card->segment[i].get_index = 0; - ms_card->segment[i].set_index = 0; - ms_card->segment[i].unused_blk_cnt = 0; - - dev_dbg(rtsx_dev(chip), "defective block count of segment %d is %d\n", - i, ms_card->segment[i].disable_count); - } - - return STATUS_SUCCESS; - -INIT_FAIL: - vfree(ms_card->segment); - ms_card->segment = NULL; - - return STATUS_FAIL; -} - -static u16 ms_get_l2p_tbl(struct rtsx_chip *chip, int seg_no, u16 log_off) -{ - struct ms_info *ms_card = &chip->ms_card; - struct zone_entry *segment; - - if (!ms_card->segment) - return 0xFFFF; - - segment = &ms_card->segment[seg_no]; - - if (segment->l2p_table) - return segment->l2p_table[log_off]; - - return 0xFFFF; -} - -static void ms_set_l2p_tbl(struct rtsx_chip *chip, - int seg_no, u16 log_off, u16 phy_blk) -{ - struct ms_info *ms_card = &chip->ms_card; - struct zone_entry *segment; - - if (!ms_card->segment) - return; - - segment = &ms_card->segment[seg_no]; - if (segment->l2p_table) - segment->l2p_table[log_off] = phy_blk; -} - -static void ms_set_unused_block(struct rtsx_chip *chip, u16 phy_blk) -{ - struct ms_info *ms_card = &chip->ms_card; - struct zone_entry *segment; - int seg_no; - - seg_no = (int)phy_blk >> 9; - segment = &ms_card->segment[seg_no]; - - segment->free_table[segment->set_index++] = phy_blk; - if (segment->set_index >= MS_FREE_TABLE_CNT) - segment->set_index = 0; - - segment->unused_blk_cnt++; -} - -static u16 ms_get_unused_block(struct rtsx_chip *chip, int seg_no) -{ - struct ms_info *ms_card = &chip->ms_card; - struct zone_entry *segment; - u16 phy_blk; - - segment = &ms_card->segment[seg_no]; - - if (segment->unused_blk_cnt <= 0) - return 0xFFFF; - - phy_blk = segment->free_table[segment->get_index]; - segment->free_table[segment->get_index++] = 0xFFFF; - if (segment->get_index >= MS_FREE_TABLE_CNT) - segment->get_index = 0; - - segment->unused_blk_cnt--; - - return phy_blk; -} - -static const unsigned short ms_start_idx[] = {0, 494, 990, 1486, 1982, 2478, - 2974, 3470, 3966, 4462, 4958, - 5454, 5950, 6446, 6942, 7438, - 7934}; - -static int ms_arbitrate_l2p(struct rtsx_chip *chip, u16 phy_blk, - u16 log_off, u8 us1, u8 us2) -{ - struct ms_info *ms_card = &chip->ms_card; - struct zone_entry *segment; - int seg_no; - u16 tmp_blk; - - seg_no = (int)phy_blk >> 9; - segment = &ms_card->segment[seg_no]; - tmp_blk = segment->l2p_table[log_off]; - - if (us1 != us2) { - if (us1 == 0) { - if (!(chip->card_wp & MS_CARD)) - ms_erase_block(chip, tmp_blk); - - ms_set_unused_block(chip, tmp_blk); - segment->l2p_table[log_off] = phy_blk; - } else { - if (!(chip->card_wp & MS_CARD)) - ms_erase_block(chip, phy_blk); - - ms_set_unused_block(chip, phy_blk); - } - } else { - if (phy_blk < tmp_blk) { - if (!(chip->card_wp & MS_CARD)) - ms_erase_block(chip, phy_blk); - - ms_set_unused_block(chip, phy_blk); - } else { - if (!(chip->card_wp & MS_CARD)) - ms_erase_block(chip, tmp_blk); - - ms_set_unused_block(chip, tmp_blk); - segment->l2p_table[log_off] = phy_blk; - } - } - - return STATUS_SUCCESS; -} - -static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no) -{ - struct ms_info *ms_card = &chip->ms_card; - struct zone_entry *segment; - bool defect_flag; - int retval, table_size, disable_cnt, i; - u16 start, end, phy_blk, log_blk, tmp_blk, idx; - u8 extra[MS_EXTRA_SIZE], us1, us2; - - dev_dbg(rtsx_dev(chip), "%s: %d\n", __func__, seg_no); - - if (!ms_card->segment) { - retval = ms_init_l2p_tbl(chip); - if (retval != STATUS_SUCCESS) - return retval; - } - - if (ms_card->segment[seg_no].build_flag) { - dev_dbg(rtsx_dev(chip), "l2p table of segment %d has been built\n", - seg_no); - return STATUS_SUCCESS; - } - - if (seg_no == 0) - table_size = 494; - else - table_size = 496; - - segment = &ms_card->segment[seg_no]; - - if (!segment->l2p_table) { - segment->l2p_table = vmalloc(array_size(table_size, 2)); - if (!segment->l2p_table) - goto BUILD_FAIL; - } - memset((u8 *)(segment->l2p_table), 0xff, array_size(table_size, 2)); - - if (!segment->free_table) { - segment->free_table = vmalloc(array_size(MS_FREE_TABLE_CNT, 2)); - if (!segment->free_table) - goto BUILD_FAIL; - } - memset((u8 *)(segment->free_table), 0xff, array_size(MS_FREE_TABLE_CNT, 2)); - - start = (u16)seg_no << 9; - end = (u16)(seg_no + 1) << 9; - - disable_cnt = segment->disable_count; - - segment->get_index = 0; - segment->set_index = 0; - segment->unused_blk_cnt = 0; - - for (phy_blk = start; phy_blk < end; phy_blk++) { - if (disable_cnt) { - defect_flag = false; - for (i = 0; i < segment->disable_count; i++) { - if (phy_blk == segment->defect_list[i]) { - defect_flag = true; - break; - } - } - if (defect_flag) { - disable_cnt--; - continue; - } - } - - retval = ms_read_extra_data(chip, phy_blk, 0, - extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) { - dev_dbg(rtsx_dev(chip), "read extra data fail\n"); - ms_set_bad_block(chip, phy_blk); - continue; - } - - if (seg_no == ms_card->segment_cnt - 1) { - if (!(extra[1] & NOT_TRANSLATION_TABLE)) { - if (!(chip->card_wp & MS_CARD)) { - retval = ms_erase_block(chip, phy_blk); - if (retval != STATUS_SUCCESS) - continue; - extra[2] = 0xff; - extra[3] = 0xff; - } - } - } - - if (!(extra[0] & BLOCK_OK)) - continue; - if (!(extra[1] & NOT_BOOT_BLOCK)) - continue; - if ((extra[0] & PAGE_OK) != PAGE_OK) - continue; - - log_blk = ((u16)extra[2] << 8) | extra[3]; - - if (log_blk == 0xFFFF) { - if (!(chip->card_wp & MS_CARD)) { - retval = ms_erase_block(chip, phy_blk); - if (retval != STATUS_SUCCESS) - continue; - } - ms_set_unused_block(chip, phy_blk); - continue; - } - - if (log_blk < ms_start_idx[seg_no] || - log_blk >= ms_start_idx[seg_no + 1]) { - if (!(chip->card_wp & MS_CARD)) { - retval = ms_erase_block(chip, phy_blk); - if (retval != STATUS_SUCCESS) - continue; - } - ms_set_unused_block(chip, phy_blk); - continue; - } - - idx = log_blk - ms_start_idx[seg_no]; - - if (segment->l2p_table[idx] == 0xFFFF) { - segment->l2p_table[idx] = phy_blk; - continue; - } - - us1 = extra[0] & 0x10; - tmp_blk = segment->l2p_table[idx]; - retval = ms_read_extra_data(chip, tmp_blk, 0, - extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) - continue; - us2 = extra[0] & 0x10; - - (void)ms_arbitrate_l2p(chip, phy_blk, - log_blk - ms_start_idx[seg_no], us1, us2); - } - - segment->build_flag = 1; - - dev_dbg(rtsx_dev(chip), "unused block count: %d\n", - segment->unused_blk_cnt); - - /* Logical Address Confirmation Process */ - if (seg_no == ms_card->segment_cnt - 1) { - if (segment->unused_blk_cnt < 2) - chip->card_wp |= MS_CARD; - } else { - if (segment->unused_blk_cnt < 1) - chip->card_wp |= MS_CARD; - } - - if (chip->card_wp & MS_CARD) - return STATUS_SUCCESS; - - for (log_blk = ms_start_idx[seg_no]; - log_blk < ms_start_idx[seg_no + 1]; log_blk++) { - idx = log_blk - ms_start_idx[seg_no]; - if (segment->l2p_table[idx] == 0xFFFF) { - phy_blk = ms_get_unused_block(chip, seg_no); - if (phy_blk == 0xFFFF) { - chip->card_wp |= MS_CARD; - return STATUS_SUCCESS; - } - retval = ms_init_page(chip, phy_blk, log_blk, 0, 1); - if (retval != STATUS_SUCCESS) - goto BUILD_FAIL; - - segment->l2p_table[idx] = phy_blk; - if (seg_no == ms_card->segment_cnt - 1) { - if (segment->unused_blk_cnt < 2) { - chip->card_wp |= MS_CARD; - return STATUS_SUCCESS; - } - } else { - if (segment->unused_blk_cnt < 1) { - chip->card_wp |= MS_CARD; - return STATUS_SUCCESS; - } - } - } - } - - /* Make boot block be the first normal block */ - if (seg_no == 0) { - for (log_blk = 0; log_blk < 494; log_blk++) { - tmp_blk = segment->l2p_table[log_blk]; - if (tmp_blk < ms_card->boot_block) { - dev_dbg(rtsx_dev(chip), "Boot block is not the first normal block.\n"); - - if (chip->card_wp & MS_CARD) - break; - - phy_blk = ms_get_unused_block(chip, 0); - retval = ms_copy_page(chip, tmp_blk, phy_blk, - log_blk, 0, - ms_card->page_off + 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - segment->l2p_table[log_blk] = phy_blk; - - retval = ms_set_bad_block(chip, tmp_blk); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - } - } - - return STATUS_SUCCESS; - -BUILD_FAIL: - segment->build_flag = 0; - vfree(segment->l2p_table); - segment->l2p_table = NULL; - vfree(segment->free_table); - segment->free_table = NULL; - - return STATUS_FAIL; -} - -int reset_ms_card(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int seg_no = ms_card->total_block / 512 - 1; - int retval; - - memset(ms_card, 0, sizeof(struct ms_info)); - - retval = enable_card_clock(chip, MS_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = select_card(chip, MS_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_card->ms_type = 0; - - retval = reset_ms_pro(chip); - if (retval != STATUS_SUCCESS) { - if (ms_card->check_ms_flow) { - retval = reset_ms(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - return STATUS_FAIL; - } - } - - retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (!CHK_MSPRO(ms_card)) { - /* Build table for the last segment, - * to check if L2P table block exists, erasing it - */ - retval = ms_build_l2p_tbl(chip, seg_no); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - dev_dbg(rtsx_dev(chip), "ms_card->ms_type = 0x%x\n", ms_card->ms_type); - - return STATUS_SUCCESS; -} - -static int mspro_set_rw_cmd(struct rtsx_chip *chip, - u32 start_sec, u16 sec_cnt, u8 cmd) -{ - int retval, i; - u8 data[8]; - - data[0] = cmd; - data[1] = (u8)(sec_cnt >> 8); - data[2] = (u8)sec_cnt; - data[3] = (u8)(start_sec >> 24); - data[4] = (u8)(start_sec >> 16); - data[5] = (u8)(start_sec >> 8); - data[6] = (u8)start_sec; - data[7] = 0; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7, - WAIT_INT, data, 8); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -void mspro_stop_seq_mode(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - - if (ms_card->seq_mode) { - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return; - - ms_card->seq_mode = 0; - ms_card->total_sec_cnt = 0; - ms_send_cmd(chip, PRO_STOP, WAIT_INT); - - rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); - } -} - -static inline int ms_auto_tune_clock(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - - if (chip->asic_code) { - if (ms_card->ms_clock > 30) - ms_card->ms_clock -= 20; - } else { - if (ms_card->ms_clock == CLK_80) - ms_card->ms_clock = CLK_60; - else if (ms_card->ms_clock == CLK_60) - ms_card->ms_clock = CLK_40; - } - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int mspro_rw_multi_sector(struct scsi_cmnd *srb, - struct rtsx_chip *chip, u32 start_sector, - u16 sector_cnt) -{ - struct ms_info *ms_card = &chip->ms_card; - bool mode_2k = false; - int retval; - u16 count; - u8 val, trans_mode, rw_tpc, rw_cmd; - - ms_set_err_code(chip, MS_NO_ERROR); - - ms_card->cleanup_counter = 0; - - if (CHK_MSHG(ms_card)) { - if ((start_sector % 4) || (sector_cnt % 4)) { - if (srb->sc_data_direction == DMA_FROM_DEVICE) { - rw_tpc = PRO_READ_LONG_DATA; - rw_cmd = PRO_READ_DATA; - } else { - rw_tpc = PRO_WRITE_LONG_DATA; - rw_cmd = PRO_WRITE_DATA; - } - } else { - if (srb->sc_data_direction == DMA_FROM_DEVICE) { - rw_tpc = PRO_READ_QUAD_DATA; - rw_cmd = PRO_READ_2K_DATA; - } else { - rw_tpc = PRO_WRITE_QUAD_DATA; - rw_cmd = PRO_WRITE_2K_DATA; - } - mode_2k = true; - } - } else { - if (srb->sc_data_direction == DMA_FROM_DEVICE) { - rw_tpc = PRO_READ_LONG_DATA; - rw_cmd = PRO_READ_DATA; - } else { - rw_tpc = PRO_WRITE_LONG_DATA; - rw_cmd = PRO_WRITE_DATA; - } - } - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (srb->sc_data_direction == DMA_FROM_DEVICE) - trans_mode = MS_TM_AUTO_READ; - else - trans_mode = MS_TM_AUTO_WRITE; - - retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); - if (retval) - return retval; - - if (ms_card->seq_mode) { - if (ms_card->pre_dir != srb->sc_data_direction || - ((ms_card->pre_sec_addr + ms_card->pre_sec_cnt) != - start_sector) || - (mode_2k && (ms_card->seq_mode & MODE_512_SEQ)) || - (!mode_2k && (ms_card->seq_mode & MODE_2K_SEQ)) || - !(val & MS_INT_BREQ) || - ((ms_card->total_sec_cnt + sector_cnt) > 0xFE00)) { - ms_card->seq_mode = 0; - ms_card->total_sec_cnt = 0; - if (val & MS_INT_BREQ) { - retval = ms_send_cmd(chip, PRO_STOP, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - rtsx_write_register(chip, RBCTL, RB_FLUSH, - RB_FLUSH); - } - } - } - - if (!ms_card->seq_mode) { - ms_card->total_sec_cnt = 0; - if (sector_cnt >= SEQ_START_CRITERIA) { - if ((ms_card->capacity - start_sector) > 0xFE00) - count = 0xFE00; - else - count = (u16)(ms_card->capacity - start_sector); - - if (count > sector_cnt) { - if (mode_2k) - ms_card->seq_mode = MODE_2K_SEQ; - else - ms_card->seq_mode = MODE_512_SEQ; - } - } else { - count = sector_cnt; - } - retval = mspro_set_rw_cmd(chip, start_sector, count, rw_cmd); - if (retval != STATUS_SUCCESS) { - ms_card->seq_mode = 0; - return STATUS_FAIL; - } - } - - retval = ms_transfer_data(chip, trans_mode, rw_tpc, sector_cnt, - WAIT_INT, mode_2k, scsi_sg_count(srb), - scsi_sglist(srb), scsi_bufflen(srb)); - if (retval != STATUS_SUCCESS) { - ms_card->seq_mode = 0; - rtsx_read_register(chip, MS_TRANS_CFG, &val); - rtsx_clear_ms_error(chip); - - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - chip->rw_need_retry = 0; - dev_dbg(rtsx_dev(chip), "No card exist, exit %s\n", - __func__); - return STATUS_FAIL; - } - - if (val & MS_INT_BREQ) - ms_send_cmd(chip, PRO_STOP, WAIT_INT); - - if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) { - dev_dbg(rtsx_dev(chip), "MSPro CRC error, tune clock!\n"); - chip->rw_need_retry = 1; - ms_auto_tune_clock(chip); - } - - return retval; - } - - if (ms_card->seq_mode) { - ms_card->pre_sec_addr = start_sector; - ms_card->pre_sec_cnt = sector_cnt; - ms_card->pre_dir = srb->sc_data_direction; - ms_card->total_sec_cnt += sector_cnt; - } - - return STATUS_SUCCESS; -} - -static int mspro_read_format_progress(struct rtsx_chip *chip, - const int short_data_len) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u32 total_progress, cur_progress; - u8 cnt, tmp; - u8 data[8]; - - dev_dbg(rtsx_dev(chip), "%s, short_data_len = %d\n", __func__, - short_data_len); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - - retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp); - if (retval != STATUS_SUCCESS) { - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - - if (!(tmp & MS_INT_BREQ)) { - if ((tmp & (MS_INT_CED | MS_INT_BREQ | MS_INT_CMDNK | - MS_INT_ERR)) == MS_INT_CED) { - ms_card->format_status = FORMAT_SUCCESS; - return STATUS_SUCCESS; - } - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - - if (short_data_len >= 256) - cnt = 0; - else - cnt = (u8)short_data_len; - - retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT, - MS_NO_CHECK_INT); - if (retval != STATUS_SUCCESS) { - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - - retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, cnt, WAIT_INT, - data, 8); - if (retval != STATUS_SUCCESS) { - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - - total_progress = (data[0] << 24) | (data[1] << 16) | - (data[2] << 8) | data[3]; - cur_progress = (data[4] << 24) | (data[5] << 16) | - (data[6] << 8) | data[7]; - - dev_dbg(rtsx_dev(chip), "total_progress = %d, cur_progress = %d\n", - total_progress, cur_progress); - - if (total_progress == 0) { - ms_card->progress = 0; - } else { - u64 ulltmp = (u64)cur_progress * (u64)65535; - - do_div(ulltmp, total_progress); - ms_card->progress = (u16)ulltmp; - } - dev_dbg(rtsx_dev(chip), "progress = %d\n", ms_card->progress); - - for (i = 0; i < 5000; i++) { - retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp); - if (retval != STATUS_SUCCESS) { - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - if (tmp & (MS_INT_CED | MS_INT_CMDNK | - MS_INT_BREQ | MS_INT_ERR)) - break; - - wait_timeout(1); - } - - retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT, 0); - if (retval != STATUS_SUCCESS) { - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - - if (i == 5000) { - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - - if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) { - ms_card->format_status = FORMAT_FAIL; - return STATUS_FAIL; - } - - if (tmp & MS_INT_CED) { - ms_card->format_status = FORMAT_SUCCESS; - ms_card->pro_under_formatting = 0; - } else if (tmp & MS_INT_BREQ) { - ms_card->format_status = FORMAT_IN_PROGRESS; - } else { - ms_card->format_status = FORMAT_FAIL; - ms_card->pro_under_formatting = 0; - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -void mspro_polling_format_status(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int i; - - if (ms_card->pro_under_formatting && - (rtsx_get_stat(chip) != RTSX_STAT_SS)) { - rtsx_set_stat(chip, RTSX_STAT_RUN); - - for (i = 0; i < 65535; i++) { - mspro_read_format_progress(chip, MS_SHORT_DATA_LEN); - if (ms_card->format_status != FORMAT_IN_PROGRESS) - break; - } - } -} - -int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip, - int short_data_len, bool quick_format) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 buf[8], tmp; - u16 para; - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, PRO_TPC_PARM, 0x01); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - memset(buf, 0, 2); - switch (short_data_len) { - case 32: - buf[0] = 0; - break; - case 64: - buf[0] = 1; - break; - case 128: - buf[0] = 2; - break; - case 256: - default: - buf[0] = 3; - break; - } - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, PRO_WRITE_REG, 1, - NO_WAIT_INT, buf, 2); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - if (quick_format) - para = 0x0000; - else - para = 0x0001; - - retval = mspro_set_rw_cmd(chip, 0, para, PRO_FORMAT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp); - if (retval) - return retval; - - if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) - return STATUS_FAIL; - - if ((tmp & (MS_INT_BREQ | MS_INT_CED)) == MS_INT_BREQ) { - ms_card->pro_under_formatting = 1; - ms_card->progress = 0; - ms_card->format_status = FORMAT_IN_PROGRESS; - return STATUS_SUCCESS; - } - - if (tmp & MS_INT_CED) { - ms_card->pro_under_formatting = 0; - ms_card->progress = 0; - ms_card->format_status = FORMAT_SUCCESS; - set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_NO_SENSE); - return STATUS_SUCCESS; - } - - return STATUS_FAIL; -} - -static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk, - u16 log_blk, u8 start_page, u8 end_page, - u8 *buf, unsigned int *index, - unsigned int *offset) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 extra[MS_EXTRA_SIZE], page_addr, val, trans_cfg, data[6]; - u8 *ptr; - - retval = ms_read_extra_data(chip, phy_blk, start_page, - extra, MS_EXTRA_SIZE); - if (retval == STATUS_SUCCESS) { - if ((extra[1] & 0x30) != 0x30) { - ms_set_err_code(chip, MS_FLASH_READ_ERROR); - return STATUS_FAIL; - } - } - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(phy_blk >> 8); - data[3] = (u8)phy_blk; - data[4] = 0; - data[5] = start_page; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, - data, 6); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - - retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ptr = buf; - - for (page_addr = start_page; page_addr < end_page; page_addr++) { - ms_set_err_code(chip, MS_NO_ERROR); - - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - ms_set_err_code(chip, MS_NO_CARD); - return STATUS_FAIL; - } - - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - if (val & INT_REG_ERR) { - if (val & INT_REG_BREQ) { - retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) { - if (!(chip->card_wp & MS_CARD)) { - reset_ms(chip); - ms_set_page_status - (log_blk, set_PS_NG, - extra, - MS_EXTRA_SIZE); - ms_write_extra_data - (chip, phy_blk, - page_addr, extra, - MS_EXTRA_SIZE); - } - ms_set_err_code(chip, - MS_FLASH_READ_ERROR); - return STATUS_FAIL; - } - } else { - ms_set_err_code(chip, MS_FLASH_READ_ERROR); - return STATUS_FAIL; - } - } else { - if (!(val & INT_REG_BREQ)) { - ms_set_err_code(chip, MS_BREQ_ERROR); - return STATUS_FAIL; - } - } - - if (page_addr == (end_page - 1)) { - if (!(val & INT_REG_CED)) { - retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, - &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (!(val & INT_REG_CED)) { - ms_set_err_code(chip, MS_FLASH_READ_ERROR); - return STATUS_FAIL; - } - - trans_cfg = NO_WAIT_INT; - } else { - trans_cfg = WAIT_INT; - } - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, READ_PAGE_DATA); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, - 0xFF, trans_cfg); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, RING_BUFFER); - - trans_dma_enable(DMA_FROM_DEVICE, chip, 512, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, - MS_TRANSFER_START | MS_TM_NORMAL_READ); - rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, - MS_TRANSFER_END, MS_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data_partial(chip, MS_CARD, ptr, 512, - scsi_sg_count(chip->srb), - index, offset, - DMA_FROM_DEVICE, - chip->ms_timeout); - if (retval < 0) { - if (retval == -ETIMEDOUT) { - ms_set_err_code(chip, MS_TO_ERROR); - rtsx_clear_ms_error(chip); - return STATUS_TIMEDOUT; - } - - retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); - if (retval != STATUS_SUCCESS) { - ms_set_err_code(chip, MS_TO_ERROR); - rtsx_clear_ms_error(chip); - return STATUS_TIMEDOUT; - } - if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) { - ms_set_err_code(chip, MS_CRC16_ERROR); - rtsx_clear_ms_error(chip); - return STATUS_FAIL; - } - } - - if (scsi_sg_count(chip->srb) == 0) - ptr += 512; - } - - return STATUS_SUCCESS; -} - -static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk, - u16 new_blk, u16 log_blk, u8 start_page, - u8 end_page, u8 *buf, unsigned int *index, - unsigned int *offset) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, i; - u8 page_addr, val, data[16]; - u8 *ptr; - - if (!start_page) { - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, 7); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(old_blk >> 8); - data[3] = (u8)old_blk; - data[4] = 0x80; - data[5] = 0; - data[6] = 0xEF; - data[7] = 0xFF; - - retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, - data, 8); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1, - NO_WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, - SYSTEM_PARAM, (6 + MS_EXTRA_SIZE)); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ms_set_err_code(chip, MS_NO_ERROR); - - if (CHK_MS4BIT(ms_card)) - data[0] = 0x88; - else - data[0] = 0x80; - - data[1] = 0; - data[2] = (u8)(new_blk >> 8); - data[3] = (u8)new_blk; - if ((end_page - start_page) == 1) - data[4] = 0x20; - else - data[4] = 0; - - data[5] = start_page; - data[6] = 0xF8; - data[7] = 0xFF; - data[8] = (u8)(log_blk >> 8); - data[9] = (u8)log_blk; - - for (i = 0x0A; i < 0x10; i++) - data[i] = 0xFF; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, WRITE_REG, 6 + MS_EXTRA_SIZE, - NO_WAIT_INT, data, 16); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - ptr = buf; - for (page_addr = start_page; page_addr < end_page; page_addr++) { - ms_set_err_code(chip, MS_NO_ERROR); - - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - ms_set_err_code(chip, MS_NO_CARD); - return STATUS_FAIL; - } - - if (val & INT_REG_CMDNK) { - ms_set_err_code(chip, MS_CMD_NK); - return STATUS_FAIL; - } - if (val & INT_REG_ERR) { - ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - if (!(val & INT_REG_BREQ)) { - ms_set_err_code(chip, MS_BREQ_ERROR); - return STATUS_FAIL; - } - - udelay(30); - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, - 0xFF, WRITE_PAGE_DATA); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, - 0xFF, WAIT_INT); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, RING_BUFFER); - - trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, - MS_TRANSFER_START | MS_TM_NORMAL_WRITE); - rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, - MS_TRANSFER_END, MS_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data_partial(chip, MS_CARD, ptr, 512, - scsi_sg_count(chip->srb), - index, offset, - DMA_TO_DEVICE, - chip->ms_timeout); - if (retval < 0) { - ms_set_err_code(chip, MS_TO_ERROR); - rtsx_clear_ms_error(chip); - - if (retval == -ETIMEDOUT) - return STATUS_TIMEDOUT; - return STATUS_FAIL; - } - - retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if ((end_page - start_page) == 1) { - if (!(val & INT_REG_CED)) { - ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - } else { - if (page_addr == (end_page - 1)) { - if (!(val & INT_REG_CED)) { - retval = ms_send_cmd(chip, BLOCK_END, - WAIT_INT); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - retval = ms_read_bytes(chip, GET_INT, 1, - NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - if (page_addr == (end_page - 1) || - page_addr == ms_card->page_off) { - if (!(val & INT_REG_CED)) { - ms_set_err_code(chip, - MS_FLASH_WRITE_ERROR); - return STATUS_FAIL; - } - } - } - - if (scsi_sg_count(chip->srb) == 0) - ptr += 512; - } - - return STATUS_SUCCESS; -} - -static int ms_finish_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, - u16 log_blk, u8 page_off) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval, seg_no; - - retval = ms_copy_page(chip, old_blk, new_blk, log_blk, - page_off, ms_card->page_off + 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - seg_no = old_blk >> 9; - - if (MS_TST_BAD_BLOCK_FLG(ms_card)) { - MS_CLR_BAD_BLOCK_FLG(ms_card); - ms_set_bad_block(chip, old_blk); - } else { - retval = ms_erase_block(chip, old_blk); - if (retval == STATUS_SUCCESS) - ms_set_unused_block(chip, old_blk); - } - - ms_set_l2p_tbl(chip, seg_no, log_blk - ms_start_idx[seg_no], new_blk); - - return STATUS_SUCCESS; -} - -static int ms_prepare_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, - u16 log_blk, u8 start_page) -{ - int retval; - - if (start_page) { - retval = ms_copy_page(chip, old_blk, new_blk, log_blk, - 0, start_page); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -#ifdef MS_DELAY_WRITE -int ms_delay_write(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - struct ms_delay_write_tag *delay_write = &ms_card->delay_write; - int retval; - - if (delay_write->delay_write_flag) { - retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - delay_write->delay_write_flag = 0; - retval = ms_finish_write(chip, - delay_write->old_phyblock, - delay_write->new_phyblock, - delay_write->logblock, - delay_write->pageoff); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} -#endif - -static inline void ms_rw_fail(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - if (srb->sc_data_direction == DMA_FROM_DEVICE) - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - else - set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); -} - -static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 start_sector, u16 sector_cnt) -{ - struct ms_info *ms_card = &chip->ms_card; - unsigned int lun = SCSI_LUN(srb); - int retval, seg_no; - unsigned int index = 0, offset = 0; - u16 old_blk = 0, new_blk = 0, log_blk, total_sec_cnt = sector_cnt; - u8 start_page, end_page = 0, page_cnt; - u8 *ptr; -#ifdef MS_DELAY_WRITE - struct ms_delay_write_tag *delay_write = &ms_card->delay_write; -#endif - - ms_set_err_code(chip, MS_NO_ERROR); - - ms_card->cleanup_counter = 0; - - ptr = (u8 *)scsi_sglist(srb); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { - ms_rw_fail(srb, chip); - return STATUS_FAIL; - } - - log_blk = (u16)(start_sector >> ms_card->block_shift); - start_page = (u8)(start_sector & ms_card->page_off); - - for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; seg_no++) { - if (log_blk < ms_start_idx[seg_no + 1]) - break; - } - - if (ms_card->segment[seg_no].build_flag == 0) { - retval = ms_build_l2p_tbl(chip, seg_no); - if (retval != STATUS_SUCCESS) { - chip->card_fail |= MS_CARD; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - } - - if (srb->sc_data_direction == DMA_TO_DEVICE) { -#ifdef MS_DELAY_WRITE - if (delay_write->delay_write_flag && - delay_write->logblock == log_blk && - start_page > delay_write->pageoff) { - delay_write->delay_write_flag = 0; - retval = ms_copy_page(chip, - delay_write->old_phyblock, - delay_write->new_phyblock, - log_blk, - delay_write->pageoff, start_page); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } - old_blk = delay_write->old_phyblock; - new_blk = delay_write->new_phyblock; - } else if (delay_write->delay_write_flag && - (delay_write->logblock == log_blk) && - (start_page == delay_write->pageoff)) { - delay_write->delay_write_flag = 0; - old_blk = delay_write->old_phyblock; - new_blk = delay_write->new_phyblock; - } else { - retval = ms_delay_write(chip); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } -#endif - old_blk = ms_get_l2p_tbl - (chip, seg_no, - log_blk - ms_start_idx[seg_no]); - new_blk = ms_get_unused_block(chip, seg_no); - if (old_blk == 0xFFFF || new_blk == 0xFFFF) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } - - retval = ms_prepare_write(chip, old_blk, new_blk, - log_blk, start_page); - if (retval != STATUS_SUCCESS) { - if (detect_card_cd(chip, MS_CARD) != - STATUS_SUCCESS) { - set_sense_type - (chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } -#ifdef MS_DELAY_WRITE - } -#endif - } else { -#ifdef MS_DELAY_WRITE - retval = ms_delay_write(chip); - if (retval != STATUS_SUCCESS) { - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return STATUS_FAIL; - } -#endif - old_blk = ms_get_l2p_tbl(chip, seg_no, - log_blk - ms_start_idx[seg_no]); - if (old_blk == 0xFFFF) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return STATUS_FAIL; - } - } - - dev_dbg(rtsx_dev(chip), "seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n", - seg_no, old_blk, new_blk); - - while (total_sec_cnt) { - if ((start_page + total_sec_cnt) > (ms_card->page_off + 1)) - end_page = ms_card->page_off + 1; - else - end_page = start_page + (u8)total_sec_cnt; - - page_cnt = end_page - start_page; - - dev_dbg(rtsx_dev(chip), "start_page = %d, end_page = %d, page_cnt = %d\n", - start_page, end_page, page_cnt); - - if (srb->sc_data_direction == DMA_FROM_DEVICE) { - retval = ms_read_multiple_pages(chip, - old_blk, log_blk, - start_page, end_page, - ptr, &index, &offset); - } else { - retval = ms_write_multiple_pages(chip, old_blk, new_blk, - log_blk, start_page, - end_page, ptr, &index, - &offset); - } - - if (retval != STATUS_SUCCESS) { - toggle_gpio(chip, 1); - if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - ms_rw_fail(srb, chip); - return STATUS_FAIL; - } - - if (srb->sc_data_direction == DMA_TO_DEVICE) { - if (end_page == (ms_card->page_off + 1)) { - retval = ms_erase_block(chip, old_blk); - if (retval == STATUS_SUCCESS) - ms_set_unused_block(chip, old_blk); - - ms_set_l2p_tbl(chip, seg_no, - log_blk - ms_start_idx[seg_no], - new_blk); - } - } - - total_sec_cnt -= page_cnt; - if (scsi_sg_count(srb) == 0) - ptr += page_cnt * 512; - - if (total_sec_cnt == 0) - break; - - log_blk++; - - for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; - seg_no++) { - if (log_blk < ms_start_idx[seg_no + 1]) - break; - } - - if (ms_card->segment[seg_no].build_flag == 0) { - retval = ms_build_l2p_tbl(chip, seg_no); - if (retval != STATUS_SUCCESS) { - chip->card_fail |= MS_CARD; - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - } - - old_blk = ms_get_l2p_tbl(chip, seg_no, - log_blk - ms_start_idx[seg_no]); - if (old_blk == 0xFFFF) { - ms_rw_fail(srb, chip); - return STATUS_FAIL; - } - - if (srb->sc_data_direction == DMA_TO_DEVICE) { - new_blk = ms_get_unused_block(chip, seg_no); - if (new_blk == 0xFFFF) { - ms_rw_fail(srb, chip); - return STATUS_FAIL; - } - } - - dev_dbg(rtsx_dev(chip), "seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n", - seg_no, old_blk, new_blk); - - start_page = 0; - } - - if (srb->sc_data_direction == DMA_TO_DEVICE) { - if (end_page < (ms_card->page_off + 1)) { -#ifdef MS_DELAY_WRITE - delay_write->delay_write_flag = 1; - delay_write->old_phyblock = old_blk; - delay_write->new_phyblock = new_blk; - delay_write->logblock = log_blk; - delay_write->pageoff = end_page; -#else - retval = ms_finish_write(chip, old_blk, new_blk, - log_blk, end_page); - if (retval != STATUS_SUCCESS) { - if (detect_card_cd(chip, MS_CARD) != - STATUS_SUCCESS) { - set_sense_type - (chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - - ms_rw_fail(srb, chip); - return STATUS_FAIL; - } -#endif - } - } - - scsi_set_resid(srb, 0); - - return STATUS_SUCCESS; -} - -int ms_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 start_sector, u16 sector_cnt) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - - if (CHK_MSPRO(ms_card)) - retval = mspro_rw_multi_sector(srb, chip, start_sector, - sector_cnt); - else - retval = ms_rw_multi_sector(srb, chip, start_sector, - sector_cnt); - - return retval; -} - -void ms_free_l2p_tbl(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int i = 0; - - if (ms_card->segment) { - for (i = 0; i < ms_card->segment_cnt; i++) { - vfree(ms_card->segment[i].l2p_table); - ms_card->segment[i].l2p_table = NULL; - vfree(ms_card->segment[i].free_table); - ms_card->segment[i].free_table = NULL; - } - vfree(ms_card->segment); - ms_card->segment = NULL; - } -} - -#ifdef SUPPORT_MAGIC_GATE - -#ifdef READ_BYTES_WAIT_INT -static int ms_poll_int(struct rtsx_chip *chip) -{ - int retval; - u8 val; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANS_CFG, MS_INT_CED, MS_INT_CED); - - retval = rtsx_send_cmd(chip, MS_CARD, 5000); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - val = *rtsx_get_cmd_data(chip); - if (val & MS_INT_ERR) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} -#endif - -#ifdef MS_SAMPLE_INT_ERR -static int check_ms_err(struct rtsx_chip *chip) -{ - int retval; - u8 val; - - retval = rtsx_read_register(chip, MS_TRANSFER, &val); - if (retval != STATUS_SUCCESS) - return 1; - if (val & MS_TRANSFER_ERR) - return 1; - - retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); - if (retval != STATUS_SUCCESS) - return 1; - - if (val & (MS_INT_ERR | MS_INT_CMDNK)) - return 1; - - return 0; -} -#else -static int check_ms_err(struct rtsx_chip *chip) -{ - int retval; - u8 val; - - retval = rtsx_read_register(chip, MS_TRANSFER, &val); - if (retval != STATUS_SUCCESS) - return 1; - if (val & MS_TRANSFER_ERR) - return 1; - - return 0; -} -#endif - -static int mg_send_ex_cmd(struct rtsx_chip *chip, u8 cmd, u8 entry_num) -{ - int retval, i; - u8 data[8]; - - data[0] = cmd; - data[1] = 0; - data[2] = 0; - data[3] = 0; - data[4] = 0; - data[5] = 0; - data[6] = entry_num; - data[7] = 0; - - for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { - retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7, WAIT_INT, - data, 8); - if (retval == STATUS_SUCCESS) - break; - } - if (i == MS_MAX_RETRY_COUNT) - return STATUS_FAIL; - - if (check_ms_err(chip)) { - rtsx_clear_ms_error(chip); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type, - u8 mg_entry_num) -{ - int retval; - u8 buf[6]; - - if (type == 0) - retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_TPC_PARM, 1); - else - retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_DATA_COUNT1, 6); - - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - buf[0] = 0; - buf[1] = 0; - if (type == 1) { - buf[2] = 0; - buf[3] = 0; - buf[4] = 0; - buf[5] = mg_entry_num; - } - retval = ms_write_bytes(chip, PRO_WRITE_REG, (type == 0) ? 1 : 6, - NO_WAIT_INT, buf, 6); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - int i; - unsigned int lun = SCSI_LUN(srb); - u8 buf1[32], buf2[12]; - - if (scsi_bufflen(srb) < 12) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return STATUS_FAIL; - } - - ms_cleanup_work(chip); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = mg_send_ex_cmd(chip, MG_SET_LID, 0); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - return STATUS_FAIL; - } - - memset(buf1, 0, 32); - rtsx_stor_get_xfer_buf(buf2, min_t(int, 12, scsi_bufflen(srb)), srb); - for (i = 0; i < 8; i++) - buf1[8 + i] = buf2[4 + i]; - - retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, - buf1, 32); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - return STATUS_FAIL; - } - if (check_ms_err(chip)) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - rtsx_clear_ms_error(chip); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - int bufflen; - unsigned int lun = SCSI_LUN(srb); - u8 *buf = NULL; - - ms_cleanup_work(chip); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - buf = kmalloc(1540, GFP_KERNEL); - if (!buf) - return STATUS_ERROR; - - buf[0] = 0x04; - buf[1] = 0x1A; - buf[2] = 0x00; - buf[3] = 0x00; - - retval = mg_send_ex_cmd(chip, MG_GET_LEKB, 0); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - goto free_buffer; - } - - retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA, - 3, WAIT_INT, 0, 0, buf + 4, 1536); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - rtsx_clear_ms_error(chip); - goto free_buffer; - } - if (check_ms_err(chip)) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - rtsx_clear_ms_error(chip); - retval = STATUS_FAIL; - goto free_buffer; - } - - bufflen = min_t(int, 1052, scsi_bufflen(srb)); - rtsx_stor_set_xfer_buf(buf, bufflen, srb); - -free_buffer: - kfree(buf); - return retval; -} - -int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - int bufflen; - int i; - unsigned int lun = SCSI_LUN(srb); - u8 buf[32]; - - ms_cleanup_work(chip); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = mg_send_ex_cmd(chip, MG_GET_ID, 0); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - return STATUS_FAIL; - } - - retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT, - buf, 32); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - return STATUS_FAIL; - } - if (check_ms_err(chip)) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - rtsx_clear_ms_error(chip); - return STATUS_FAIL; - } - - memcpy(ms_card->magic_gate_id, buf, 16); - -#ifdef READ_BYTES_WAIT_INT - retval = ms_poll_int(chip); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - return STATUS_FAIL; - } -#endif - - retval = mg_send_ex_cmd(chip, MG_SET_RD, 0); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - return STATUS_FAIL; - } - - bufflen = min_t(int, 12, scsi_bufflen(srb)); - rtsx_stor_get_xfer_buf(buf, bufflen, srb); - - for (i = 0; i < 8; i++) - buf[i] = buf[4 + i]; - - for (i = 0; i < 24; i++) - buf[8 + i] = 0; - - retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, - 32, WAIT_INT, buf, 32); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - return STATUS_FAIL; - } - if (check_ms_err(chip)) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - rtsx_clear_ms_error(chip); - return STATUS_FAIL; - } - - ms_card->mg_auth = 0; - - return STATUS_SUCCESS; -} - -int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - int bufflen; - unsigned int lun = SCSI_LUN(srb); - u8 buf1[32], buf2[36]; - - ms_cleanup_work(chip); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = mg_send_ex_cmd(chip, MG_MAKE_RMS, 0); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - return STATUS_FAIL; - } - - retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT, - buf1, 32); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - return STATUS_FAIL; - } - if (check_ms_err(chip)) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - rtsx_clear_ms_error(chip); - return STATUS_FAIL; - } - - buf2[0] = 0x00; - buf2[1] = 0x22; - buf2[2] = 0x00; - buf2[3] = 0x00; - - memcpy(buf2 + 4, ms_card->magic_gate_id, 16); - memcpy(buf2 + 20, buf1, 16); - - bufflen = min_t(int, 36, scsi_bufflen(srb)); - rtsx_stor_set_xfer_buf(buf2, bufflen, srb); - -#ifdef READ_BYTES_WAIT_INT - retval = ms_poll_int(chip); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - return STATUS_FAIL; - } -#endif - - return STATUS_SUCCESS; -} - -int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - int i; - int bufflen; - unsigned int lun = SCSI_LUN(srb); - u8 buf[32]; - - ms_cleanup_work(chip); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = mg_send_ex_cmd(chip, MG_MAKE_KSE, 0); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - return STATUS_FAIL; - } - - bufflen = min_t(int, 12, scsi_bufflen(srb)); - rtsx_stor_get_xfer_buf(buf, bufflen, srb); - - for (i = 0; i < 8; i++) - buf[i] = buf[4 + i]; - - for (i = 0; i < 24; i++) - buf[8 + i] = 0; - - retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, - buf, 32); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - return STATUS_FAIL; - } - if (check_ms_err(chip)) { - set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); - rtsx_clear_ms_error(chip); - return STATUS_FAIL; - } - - ms_card->mg_auth = 1; - - return STATUS_SUCCESS; -} - -int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - int bufflen; - unsigned int lun = SCSI_LUN(srb); - u8 *buf = NULL; - - ms_cleanup_work(chip); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - buf = kmalloc(1028, GFP_KERNEL); - if (!buf) - return STATUS_ERROR; - - buf[0] = 0x04; - buf[1] = 0x02; - buf[2] = 0x00; - buf[3] = 0x00; - - retval = mg_send_ex_cmd(chip, MG_GET_IBD, ms_card->mg_entry_num); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - goto free_buffer; - } - - retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA, - 2, WAIT_INT, 0, 0, buf + 4, 1024); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - rtsx_clear_ms_error(chip); - goto free_buffer; - } - if (check_ms_err(chip)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - rtsx_clear_ms_error(chip); - retval = STATUS_FAIL; - goto free_buffer; - } - - bufflen = min_t(int, 1028, scsi_bufflen(srb)); - rtsx_stor_set_xfer_buf(buf, bufflen, srb); - -free_buffer: - kfree(buf); - return retval; -} - -int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - int bufflen; -#ifdef MG_SET_ICV_SLOW - int i; -#endif - unsigned int lun = SCSI_LUN(srb); - u8 *buf = NULL; - - ms_cleanup_work(chip); - - retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - buf = kmalloc(1028, GFP_KERNEL); - if (!buf) - return STATUS_ERROR; - - bufflen = min_t(int, 1028, scsi_bufflen(srb)); - rtsx_stor_get_xfer_buf(buf, bufflen, srb); - - retval = mg_send_ex_cmd(chip, MG_SET_IBD, ms_card->mg_entry_num); - if (retval != STATUS_SUCCESS) { - if (ms_card->mg_auth == 0) { - if ((buf[5] & 0xC0) != 0) - set_sense_type - (chip, lun, - SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - else - set_sense_type(chip, lun, - SENSE_TYPE_MG_WRITE_ERR); - } else { - set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); - } - goto set_ICV_finish; - } - -#ifdef MG_SET_ICV_SLOW - for (i = 0; i < 2; i++) { - udelay(50); - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, - 0xFF, PRO_WRITE_LONG_DATA); - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, WAIT_INT); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, RING_BUFFER); - - trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, - MS_TRANSFER_START | MS_TM_NORMAL_WRITE); - rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, - MS_TRANSFER_END, MS_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data(chip, MS_CARD, buf + 4 + i * 512, - 512, 0, DMA_TO_DEVICE, 3000); - if (retval < 0 || check_ms_err(chip)) { - rtsx_clear_ms_error(chip); - if (ms_card->mg_auth == 0) { - if ((buf[5] & 0xC0) != 0) - set_sense_type - (chip, lun, - SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - else - set_sense_type(chip, lun, - SENSE_TYPE_MG_WRITE_ERR); - } else { - set_sense_type(chip, lun, - SENSE_TYPE_MG_WRITE_ERR); - } - retval = STATUS_FAIL; - goto set_ICV_finish; - } - } -#else - retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA, - 2, WAIT_INT, 0, 0, buf + 4, 1024); - if (retval != STATUS_SUCCESS || check_ms_err(chip)) { - rtsx_clear_ms_error(chip); - if (ms_card->mg_auth == 0) { - if ((buf[5] & 0xC0) != 0) - set_sense_type - (chip, lun, - SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - else - set_sense_type(chip, lun, - SENSE_TYPE_MG_WRITE_ERR); - } else { - set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); - } - goto set_ICV_finish; - } -#endif - -set_ICV_finish: - kfree(buf); - return retval; -} - -#endif /* SUPPORT_MAGIC_GATE */ - -void ms_cleanup_work(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - - if (CHK_MSPRO(ms_card)) { - if (ms_card->seq_mode) { - dev_dbg(rtsx_dev(chip), "MS Pro: stop transmission\n"); - mspro_stop_seq_mode(chip); - ms_card->cleanup_counter = 0; - } - if (CHK_MSHG(ms_card)) { - rtsx_write_register(chip, MS_CFG, - MS_2K_SECTOR_MODE, 0x00); - } - } -#ifdef MS_DELAY_WRITE - else if ((!CHK_MSPRO(ms_card)) && - ms_card->delay_write.delay_write_flag) { - dev_dbg(rtsx_dev(chip), "MS: delay write\n"); - ms_delay_write(chip); - ms_card->cleanup_counter = 0; - } -#endif -} - -int ms_power_off_card3v3(struct rtsx_chip *chip) -{ - int retval; - - retval = disable_card_clock(chip, MS_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (chip->asic_code) { - retval = ms_pull_ctl_disable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register(chip, FPGA_PULL_CTL, - FPGA_MS_PULL_CTL_BIT | 0x20, - FPGA_MS_PULL_CTL_BIT); - if (retval) - return retval; - } - retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0); - if (retval) - return retval; - - if (!chip->ft2_fast_mode) { - retval = card_power_off(chip, MS_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -int release_ms_card(struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - int retval; - -#ifdef MS_DELAY_WRITE - ms_card->delay_write.delay_write_flag = 0; -#endif - ms_card->pro_under_formatting = 0; - - chip->card_ready &= ~MS_CARD; - chip->card_fail &= ~MS_CARD; - chip->card_wp &= ~MS_CARD; - - ms_free_l2p_tbl(chip); - - memset(ms_card->raw_sys_info, 0, 96); -#ifdef SUPPORT_PCGL_1P18 - memset(ms_card->raw_model_name, 0, 48); -#endif - - retval = ms_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} diff --git a/drivers/staging/rts5208/ms.h b/drivers/staging/rts5208/ms.h deleted file mode 100644 index 33bda9ce36b67c..00000000000000 --- a/drivers/staging/rts5208/ms.h +++ /dev/null @@ -1,214 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_MS_H -#define __REALTEK_RTSX_MS_H - -#define MS_DELAY_WRITE - -#define MS_MAX_RETRY_COUNT 3 - -#define MS_EXTRA_SIZE 0x9 - -#define WRT_PRTCT 0x01 - -/* Error Code */ -#define MS_NO_ERROR 0x00 -#define MS_CRC16_ERROR 0x80 -#define MS_TO_ERROR 0x40 -#define MS_NO_CARD 0x20 -#define MS_NO_MEMORY 0x10 -#define MS_CMD_NK 0x08 -#define MS_FLASH_READ_ERROR 0x04 -#define MS_FLASH_WRITE_ERROR 0x02 -#define MS_BREQ_ERROR 0x01 -#define MS_NOT_FOUND 0x03 - -/* Transfer Protocol Command */ -#define READ_PAGE_DATA 0x02 -#define READ_REG 0x04 -#define GET_INT 0x07 -#define WRITE_PAGE_DATA 0x0D -#define WRITE_REG 0x0B -#define SET_RW_REG_ADRS 0x08 -#define SET_CMD 0x0E - -#define PRO_READ_LONG_DATA 0x02 -#define PRO_READ_SHORT_DATA 0x03 -#define PRO_READ_REG 0x04 -#define PRO_READ_QUAD_DATA 0x05 -#define PRO_GET_INT 0x07 -#define PRO_WRITE_LONG_DATA 0x0D -#define PRO_WRITE_SHORT_DATA 0x0C -#define PRO_WRITE_QUAD_DATA 0x0A -#define PRO_WRITE_REG 0x0B -#define PRO_SET_RW_REG_ADRS 0x08 -#define PRO_SET_CMD 0x0E -#define PRO_EX_SET_CMD 0x09 - -#ifdef SUPPORT_MAGIC_GATE - -#define MG_GET_ID 0x40 -#define MG_SET_LID 0x41 -#define MG_GET_LEKB 0x42 -#define MG_SET_RD 0x43 -#define MG_MAKE_RMS 0x44 -#define MG_MAKE_KSE 0x45 -#define MG_SET_IBD 0x46 -#define MG_GET_IBD 0x47 - -#endif - -#ifdef XC_POWERCLASS -#define XC_CHG_POWER 0x16 -#endif - -#define BLOCK_READ 0xAA -#define BLOCK_WRITE 0x55 -#define BLOCK_END 0x33 -#define BLOCK_ERASE 0x99 -#define FLASH_STOP 0xCC - -#define SLEEP 0x5A -#define CLEAR_BUF 0xC3 -#define MS_RESET 0x3C - -#define PRO_READ_DATA 0x20 -#define PRO_WRITE_DATA 0x21 -#define PRO_READ_ATRB 0x24 -#define PRO_STOP 0x25 -#define PRO_ERASE 0x26 -#define PRO_READ_2K_DATA 0x27 -#define PRO_WRITE_2K_DATA 0x28 - -#define PRO_FORMAT 0x10 -#define PRO_SLEEP 0x11 - -#define INT_REG 0x01 -#define STATUS_REG0 0x02 -#define STATUS_REG1 0x03 - -#define SYSTEM_PARAM 0x10 -#define BLOCK_ADRS 0x11 -#define CMD_PARM 0x14 -#define PAGE_ADRS 0x15 - -#define OVERWRITE_FLAG 0x16 -#define MANAGEMEN_FLAG 0x17 -#define LOGICAL_ADRS 0x18 -#define RESERVE_AREA 0x1A - -#define PRO_INT_REG 0x01 -#define PRO_STATUS_REG 0x02 -#define PRO_TYPE_REG 0x04 -#define PRO_IF_mode_REG 0x05 -#define PRO_CATEGORY_REG 0x06 -#define PRO_CLASS_REG 0x07 - -#define PRO_SYSTEM_PARAM 0x10 -#define PRO_DATA_COUNT1 0x11 -#define PRO_DATA_COUNT0 0x12 -#define PRO_DATA_ADDR3 0x13 -#define PRO_DATA_ADDR2 0x14 -#define PRO_DATA_ADDR1 0x15 -#define PRO_DATA_ADDR0 0x16 - -#define PRO_TPC_PARM 0x17 -#define PRO_CMD_PARM 0x18 - -#define INT_REG_CED 0x80 -#define INT_REG_ERR 0x40 -#define INT_REG_BREQ 0x20 -#define INT_REG_CMDNK 0x01 - -#define BLOCK_BOOT 0xC0 -#define BLOCK_OK 0x80 -#define PAGE_OK 0x60 -#define DATA_COMPL 0x10 - -#define NOT_BOOT_BLOCK 0x4 -#define NOT_TRANSLATION_TABLE 0x8 - -#define HEADER_ID0 PPBUF_BASE2 -#define HEADER_ID1 (PPBUF_BASE2 + 1) -#define DISABLED_BLOCK0 (PPBUF_BASE2 + 0x170 + 4) -#define DISABLED_BLOCK1 (PPBUF_BASE2 + 0x170 + 5) -#define DISABLED_BLOCK2 (PPBUF_BASE2 + 0x170 + 6) -#define DISABLED_BLOCK3 (PPBUF_BASE2 + 0x170 + 7) -#define BLOCK_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 2) -#define BLOCK_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 3) -#define BLOCK_COUNT_0 (PPBUF_BASE2 + 0x1a0 + 4) -#define BLOCK_COUNT_1 (PPBUF_BASE2 + 0x1a0 + 5) -#define EBLOCK_COUNT_0 (PPBUF_BASE2 + 0x1a0 + 6) -#define EBLOCK_COUNT_1 (PPBUF_BASE2 + 0x1a0 + 7) -#define PAGE_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 8) -#define PAGE_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 9) - -#define MS_device_type (PPBUF_BASE2 + 0x1D8) - -#define MS_4bit_support (PPBUF_BASE2 + 0x1D3) - -#define set_PS_NG 1 -#define set_PS_error 0 - -#define PARALLEL_8BIT_IF 0x40 -#define PARALLEL_4BIT_IF 0x00 -#define SERIAL_IF 0x80 - -#define BUF_FULL 0x10 -#define BUF_EMPTY 0x20 - -#define MEDIA_BUSY 0x80 -#define FLASH_BUSY 0x40 -#define DATA_ERROR 0x20 -#define STS_UCDT 0x10 -#define EXTRA_ERROR 0x08 -#define STS_UCEX 0x04 -#define FLAG_ERROR 0x02 -#define STS_UCFG 0x01 - -#define MS_SHORT_DATA_LEN 32 - -#define FORMAT_SUCCESS 0 -#define FORMAT_FAIL 1 -#define FORMAT_IN_PROGRESS 2 - -#define MS_SET_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag |= 0x80) -#define MS_CLR_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag &= 0x7F) -#define MS_TST_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag & 0x80) - -void mspro_polling_format_status(struct rtsx_chip *chip); - -void mspro_stop_seq_mode(struct rtsx_chip *chip); -int reset_ms_card(struct rtsx_chip *chip); -int ms_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 start_sector, u16 sector_cnt); -int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip, - int short_data_len, bool quick_format); -void ms_free_l2p_tbl(struct rtsx_chip *chip); -void ms_cleanup_work(struct rtsx_chip *chip); -int ms_power_off_card3v3(struct rtsx_chip *chip); -int release_ms_card(struct rtsx_chip *chip); -#ifdef MS_DELAY_WRITE -int ms_delay_write(struct rtsx_chip *chip); -#endif - -#ifdef SUPPORT_MAGIC_GATE -int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip); -#endif - -#endif /* __REALTEK_RTSX_MS_H */ diff --git a/drivers/staging/rts5208/rtsx.c b/drivers/staging/rts5208/rtsx.c deleted file mode 100644 index c4f54c311d0549..00000000000000 --- a/drivers/staging/rts5208/rtsx.c +++ /dev/null @@ -1,987 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include -#include - -#include "rtsx.h" -#include "ms.h" -#include "sd.h" -#include "xd.h" - -MODULE_DESCRIPTION("Realtek PCI-Express card reader rts5208/rts5288 driver"); -MODULE_LICENSE("GPL"); - -static unsigned int delay_use = 1; -module_param(delay_use, uint, 0644); -MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); - -static int ss_en; -module_param(ss_en, int, 0644); -MODULE_PARM_DESC(ss_en, "enable selective suspend"); - -static int ss_interval = 50; -module_param(ss_interval, int, 0644); -MODULE_PARM_DESC(ss_interval, "Interval to enter ss state in seconds"); - -static int auto_delink_en; -module_param(auto_delink_en, int, 0644); -MODULE_PARM_DESC(auto_delink_en, "enable auto delink"); - -static unsigned char aspm_l0s_l1_en; -module_param(aspm_l0s_l1_en, byte, 0644); -MODULE_PARM_DESC(aspm_l0s_l1_en, "enable device aspm"); - -static int msi_en; -module_param(msi_en, int, 0644); -MODULE_PARM_DESC(msi_en, "enable msi"); - -static irqreturn_t rtsx_interrupt(int irq, void *dev_id); - -/*********************************************************************** - * Host functions - ***********************************************************************/ - -static const char *host_info(struct Scsi_Host *host) -{ - return "SCSI emulation for PCI-Express Mass Storage devices"; -} - -static int slave_alloc(struct scsi_device *sdev) -{ - /* - * Set the INQUIRY transfer length to 36. We don't use any of - * the extra data and many devices choke if asked for more or - * less than 36 bytes. - */ - sdev->inquiry_len = 36; - return 0; -} - -static int slave_configure(struct scsi_device *sdev) -{ - /* Set the SCSI level to at least 2. We'll leave it at 3 if that's - * what is originally reported. We need this to avoid confusing - * the SCSI layer with devices that report 0 or 1, but need 10-byte - * commands (ala ATAPI devices behind certain bridges, or devices - * which simply have broken INQUIRY data). - * - * NOTE: This means /dev/sg programs (ala cdrecord) will get the - * actual information. This seems to be the preference for - * programs like that. - * - * NOTE: This also means that /proc/scsi/scsi and sysfs may report - * the actual value or the modified one, depending on where the - * data comes from. - */ - if (sdev->scsi_level < SCSI_2) { - sdev->scsi_level = SCSI_2; - sdev->sdev_target->scsi_level = SCSI_2; - } - - return 0; -} - -/*********************************************************************** - * /proc/scsi/ functions - ***********************************************************************/ - -/* we use this macro to help us write into the buffer */ -#undef SPRINTF -#define SPRINTF(args...) \ - do { \ - if (pos < buffer + length) \ - pos += sprintf(pos, ## args); \ - } while (0) - -/* queue a command */ -/* This is always called with spin_lock_irq(host->host_lock) held */ -static int queuecommand_lck(struct scsi_cmnd *srb) -{ - void (*done)(struct scsi_cmnd *) = scsi_done; - struct rtsx_dev *dev = host_to_rtsx(srb->device->host); - struct rtsx_chip *chip = dev->chip; - - /* check for state-transition errors */ - if (chip->srb) { - dev_err(&dev->pci->dev, "Error: chip->srb = %p\n", - chip->srb); - return SCSI_MLQUEUE_HOST_BUSY; - } - - /* fail the command if we are disconnecting */ - if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { - dev_info(&dev->pci->dev, "Fail command during disconnect\n"); - srb->result = DID_NO_CONNECT << 16; - done(srb); - return 0; - } - - /* enqueue the command and wake up the control thread */ - chip->srb = srb; - complete(&dev->cmnd_ready); - - return 0; -} - -static DEF_SCSI_QCMD(queuecommand) - -/*********************************************************************** - * Error handling functions - ***********************************************************************/ - -/* Command timeout and abort */ -static int command_abort(struct scsi_cmnd *srb) -{ - struct Scsi_Host *host = srb->device->host; - struct rtsx_dev *dev = host_to_rtsx(host); - struct rtsx_chip *chip = dev->chip; - - spin_lock_irq(host->host_lock); - - /* Is this command still active? */ - if (chip->srb != srb) { - spin_unlock_irq(host->host_lock); - dev_info(&dev->pci->dev, "-- nothing to abort\n"); - return FAILED; - } - - rtsx_set_stat(chip, RTSX_STAT_ABORT); - - spin_unlock_irq(host->host_lock); - - /* Wait for the aborted command to finish */ - wait_for_completion(&dev->notify); - - return SUCCESS; -} - -/* - * This invokes the transport reset mechanism to reset the state of the - * device - */ -static int device_reset(struct scsi_cmnd *srb) -{ - return SUCCESS; -} - -/* - * this defines our host template, with which we'll allocate hosts - */ - -static const struct scsi_host_template rtsx_host_template = { - /* basic userland interface stuff */ - .name = CR_DRIVER_NAME, - .proc_name = CR_DRIVER_NAME, - .info = host_info, - - /* command interface -- queued only */ - .queuecommand = queuecommand, - - /* error and abort handlers */ - .eh_abort_handler = command_abort, - .eh_device_reset_handler = device_reset, - - /* queue commands only, only one command per LUN */ - .can_queue = 1, - - /* unknown initiator id */ - .this_id = -1, - - .slave_alloc = slave_alloc, - .slave_configure = slave_configure, - - /* lots of sg segments can be handled */ - .sg_tablesize = SG_ALL, - - /* limit the total size of a transfer to 120 KB */ - .max_sectors = 240, - - /* - * Scatter-gather buffers (all but the last) must have a length - * divisible by the bulk maxpacket size. Otherwise a data packet - * would end up being short, causing a premature end to the data - * transfer. Since high-speed bulk pipes have a maxpacket size - * of 512, we'll use that as the scsi device queue's DMA alignment - * mask. Guaranteeing proper alignment of the first buffer will - * have the desired effect because, except at the beginning and - * the end, scatter-gather buffers follow page boundaries. - */ - .dma_alignment = 511, - - /* emulated HBA */ - .emulated = 1, - - /* we do our own delay after a device or bus reset */ - .skip_settle_delay = 1, - - /* module management */ - .module = THIS_MODULE -}; - -static int rtsx_acquire_irq(struct rtsx_dev *dev) -{ - struct rtsx_chip *chip = dev->chip; - - dev_info(&dev->pci->dev, "%s: chip->msi_en = %d, pci->irq = %d\n", - __func__, chip->msi_en, dev->pci->irq); - - if (request_irq(dev->pci->irq, rtsx_interrupt, - chip->msi_en ? 0 : IRQF_SHARED, - CR_DRIVER_NAME, dev)) { - dev_err(&dev->pci->dev, - "rtsx: unable to grab IRQ %d, disabling device\n", - dev->pci->irq); - return -1; - } - - dev->irq = dev->pci->irq; - pci_intx(dev->pci, !chip->msi_en); - - return 0; -} - -/* - * power management - */ -static int __maybe_unused rtsx_suspend(struct device *dev_d) -{ - struct pci_dev *pci = to_pci_dev(dev_d); - struct rtsx_dev *dev = pci_get_drvdata(pci); - struct rtsx_chip *chip; - - if (!dev) - return 0; - - /* lock the device pointers */ - mutex_lock(&dev->dev_mutex); - - chip = dev->chip; - - rtsx_do_before_power_down(chip, PM_S3); - - if (dev->irq >= 0) { - free_irq(dev->irq, (void *)dev); - dev->irq = -1; - } - - if (chip->msi_en) - pci_free_irq_vectors(pci); - - device_wakeup_enable(dev_d); - - /* unlock the device pointers */ - mutex_unlock(&dev->dev_mutex); - - return 0; -} - -static int __maybe_unused rtsx_resume(struct device *dev_d) -{ - struct pci_dev *pci = to_pci_dev(dev_d); - struct rtsx_dev *dev = pci_get_drvdata(pci); - struct rtsx_chip *chip; - - if (!dev) - return 0; - - chip = dev->chip; - - /* lock the device pointers */ - mutex_lock(&dev->dev_mutex); - - pci_set_master(pci); - - if (chip->msi_en) { - if (pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) < 0) - chip->msi_en = 0; - } - - if (rtsx_acquire_irq(dev) < 0) { - /* unlock the device pointers */ - mutex_unlock(&dev->dev_mutex); - return -EIO; - } - - rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 0x00); - rtsx_init_chip(chip); - - /* unlock the device pointers */ - mutex_unlock(&dev->dev_mutex); - - return 0; -} - -static void rtsx_shutdown(struct pci_dev *pci) -{ - struct rtsx_dev *dev = pci_get_drvdata(pci); - struct rtsx_chip *chip; - - if (!dev) - return; - - chip = dev->chip; - - rtsx_do_before_power_down(chip, PM_S1); - - if (dev->irq >= 0) { - free_irq(dev->irq, (void *)dev); - dev->irq = -1; - } - - if (chip->msi_en) - pci_free_irq_vectors(pci); - - pci_disable_device(pci); -} - -static int rtsx_control_thread(void *__dev) -{ - struct rtsx_dev *dev = __dev; - struct rtsx_chip *chip = dev->chip; - struct Scsi_Host *host = rtsx_to_host(dev); - - for (;;) { - if (wait_for_completion_interruptible(&dev->cmnd_ready)) - break; - - /* lock the device pointers */ - mutex_lock(&dev->dev_mutex); - - /* if the device has disconnected, we are free to exit */ - if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { - dev_info(&dev->pci->dev, "-- rtsx-control exiting\n"); - mutex_unlock(&dev->dev_mutex); - break; - } - - /* lock access to the state */ - spin_lock_irq(host->host_lock); - - /* has the command aborted ? */ - if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) { - chip->srb->result = DID_ABORT << 16; - goto skip_for_abort; - } - - spin_unlock_irq(host->host_lock); - - /* reject the command if the direction indicator - * is UNKNOWN - */ - if (chip->srb->sc_data_direction == DMA_BIDIRECTIONAL) { - dev_err(&dev->pci->dev, "UNKNOWN data direction\n"); - chip->srb->result = DID_ERROR << 16; - } else if (chip->srb->device->id) { - /* reject if target != 0 or if LUN is higher than - * the maximum known LUN - */ - dev_err(&dev->pci->dev, "Bad target number (%d:%d)\n", - chip->srb->device->id, - (u8)chip->srb->device->lun); - chip->srb->result = DID_BAD_TARGET << 16; - } else if (chip->srb->device->lun > chip->max_lun) { - dev_err(&dev->pci->dev, "Bad LUN (%d:%d)\n", - chip->srb->device->id, - (u8)chip->srb->device->lun); - chip->srb->result = DID_BAD_TARGET << 16; - } else { - /* we've got a command, let's do it! */ - scsi_show_command(chip); - rtsx_invoke_transport(chip->srb, chip); - } - - /* lock access to the state */ - spin_lock_irq(host->host_lock); - - /* did the command already complete because of a disconnect? */ - if (!chip->srb) - ; /* nothing to do */ - - /* indicate that the command is done */ - else if (chip->srb->result != DID_ABORT << 16) { - scsi_done(chip->srb); - } else { -skip_for_abort: - dev_err(&dev->pci->dev, "scsi command aborted\n"); - } - - if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) { - complete(&dev->notify); - - rtsx_set_stat(chip, RTSX_STAT_IDLE); - } - - /* finished working on this command */ - chip->srb = NULL; - spin_unlock_irq(host->host_lock); - - /* unlock the device pointers */ - mutex_unlock(&dev->dev_mutex); - } /* for (;;) */ - - /* notify the exit routine that we're actually exiting now - * - * complete()/wait_for_completion() is similar to up()/down(), - * except that complete() is safe in the case where the structure - * is getting deleted in a parallel mode of execution (i.e. just - * after the down() -- that's necessary for the thread-shutdown - * case. - * - * kthread_complete_and_exit() goes even further than this -- - * it is safe in the case that the thread of the caller is going away - * (not just the structure) -- this is necessary for the module-remove - * case. This is important in preemption kernels, which transfer the - * flow of execution immediately upon a complete(). - */ - kthread_complete_and_exit(&dev->control_exit, 0); -} - -static int rtsx_polling_thread(void *__dev) -{ - struct rtsx_dev *dev = __dev; - struct rtsx_chip *chip = dev->chip; - struct sd_info *sd_card = &chip->sd_card; - struct xd_info *xd_card = &chip->xd_card; - struct ms_info *ms_card = &chip->ms_card; - - sd_card->cleanup_counter = 0; - xd_card->cleanup_counter = 0; - ms_card->cleanup_counter = 0; - - /* Wait until SCSI scan finished */ - wait_timeout((delay_use + 5) * 1000); - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(POLLING_INTERVAL)); - - /* lock the device pointers */ - mutex_lock(&dev->dev_mutex); - - /* if the device has disconnected, we are free to exit */ - if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { - dev_info(&dev->pci->dev, "-- rtsx-polling exiting\n"); - mutex_unlock(&dev->dev_mutex); - break; - } - - mutex_unlock(&dev->dev_mutex); - - mspro_polling_format_status(chip); - - /* lock the device pointers */ - mutex_lock(&dev->dev_mutex); - - rtsx_polling_func(chip); - - /* unlock the device pointers */ - mutex_unlock(&dev->dev_mutex); - } - - kthread_complete_and_exit(&dev->polling_exit, 0); -} - -/* - * interrupt handler - */ -static irqreturn_t rtsx_interrupt(int irq, void *dev_id) -{ - struct rtsx_dev *dev = dev_id; - struct rtsx_chip *chip; - int retval; - u32 status; - - if (dev) - chip = dev->chip; - else - return IRQ_NONE; - - if (!chip) - return IRQ_NONE; - - spin_lock(&dev->reg_lock); - - retval = rtsx_pre_handle_interrupt(chip); - if (retval == STATUS_FAIL) { - spin_unlock(&dev->reg_lock); - if (chip->int_reg == 0xFFFFFFFF) - return IRQ_HANDLED; - return IRQ_NONE; - } - - status = chip->int_reg; - - if (dev->check_card_cd) { - if (!(dev->check_card_cd & status)) { - /* card not exist, return TRANS_RESULT_FAIL */ - dev->trans_result = TRANS_RESULT_FAIL; - if (dev->done) - complete(dev->done); - goto exit; - } - } - - if (status & (NEED_COMPLETE_INT | DELINK_INT)) { - if (status & (TRANS_FAIL_INT | DELINK_INT)) { - if (status & DELINK_INT) - RTSX_SET_DELINK(chip); - dev->trans_result = TRANS_RESULT_FAIL; - if (dev->done) - complete(dev->done); - } else if (status & TRANS_OK_INT) { - dev->trans_result = TRANS_RESULT_OK; - if (dev->done) - complete(dev->done); - } else if (status & DATA_DONE_INT) { - dev->trans_result = TRANS_NOT_READY; - if (dev->done && dev->trans_state == STATE_TRANS_SG) - complete(dev->done); - } - } - -exit: - spin_unlock(&dev->reg_lock); - return IRQ_HANDLED; -} - -/* Release all our dynamic resources */ -static void rtsx_release_resources(struct rtsx_dev *dev) -{ - dev_info(&dev->pci->dev, "-- %s\n", __func__); - - /* Tell the control thread to exit. The SCSI host must - * already have been removed so it won't try to queue - * any more commands. - */ - dev_info(&dev->pci->dev, "-- sending exit command to thread\n"); - complete(&dev->cmnd_ready); - if (dev->ctl_thread) - wait_for_completion(&dev->control_exit); - if (dev->polling_thread) - wait_for_completion(&dev->polling_exit); - - wait_timeout(200); - - if (dev->rtsx_resv_buf) { - dev->chip->host_cmds_ptr = NULL; - dev->chip->host_sg_tbl_ptr = NULL; - } - - if (dev->irq > 0) - free_irq(dev->irq, (void *)dev); - if (dev->chip->msi_en) - pci_free_irq_vectors(dev->pci); - if (dev->remap_addr) - iounmap(dev->remap_addr); - - rtsx_release_chip(dev->chip); - kfree(dev->chip); -} - -/* - * First stage of disconnect processing: stop all commands and remove - * the host - */ -static void quiesce_and_remove_host(struct rtsx_dev *dev) -{ - struct Scsi_Host *host = rtsx_to_host(dev); - struct rtsx_chip *chip = dev->chip; - - /* - * Prevent new transfers, stop the current command, and - * interrupt a SCSI-scan or device-reset delay - */ - mutex_lock(&dev->dev_mutex); - spin_lock_irq(host->host_lock); - rtsx_set_stat(chip, RTSX_STAT_DISCONNECT); - spin_unlock_irq(host->host_lock); - mutex_unlock(&dev->dev_mutex); - wake_up(&dev->delay_wait); - wait_for_completion(&dev->scanning_done); - - /* Wait some time to let other threads exist */ - wait_timeout(100); - - /* - * queuecommand won't accept any new commands and the control - * thread won't execute a previously-queued command. If there - * is such a command pending, complete it with an error. - */ - mutex_lock(&dev->dev_mutex); - if (chip->srb) { - chip->srb->result = DID_NO_CONNECT << 16; - spin_lock_irq(host->host_lock); - scsi_done(dev->chip->srb); - chip->srb = NULL; - spin_unlock_irq(host->host_lock); - } - mutex_unlock(&dev->dev_mutex); - - /* Now we own no commands so it's safe to remove the SCSI host */ - scsi_remove_host(host); -} - -/* Second stage of disconnect processing: deallocate all resources */ -static void release_everything(struct rtsx_dev *dev) -{ - rtsx_release_resources(dev); - - /* - * Drop our reference to the host; the SCSI core will free it - * when the refcount becomes 0. - */ - scsi_host_put(rtsx_to_host(dev)); -} - -/* Thread to carry out delayed SCSI-device scanning */ -static int rtsx_scan_thread(void *__dev) -{ - struct rtsx_dev *dev = __dev; - struct rtsx_chip *chip = dev->chip; - - /* Wait for the timeout to expire or for a disconnect */ - if (delay_use > 0) { - dev_info(&dev->pci->dev, - "%s: waiting for device to settle before scanning\n", - CR_DRIVER_NAME); - wait_event_interruptible_timeout - (dev->delay_wait, - rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT), - delay_use * HZ); - } - - /* If the device is still connected, perform the scanning */ - if (!rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { - scsi_scan_host(rtsx_to_host(dev)); - dev_info(&dev->pci->dev, "%s: device scan complete\n", - CR_DRIVER_NAME); - - /* Should we unbind if no devices were detected? */ - } - - kthread_complete_and_exit(&dev->scanning_done, 0); -} - -static void rtsx_init_options(struct rtsx_chip *chip) -{ - chip->vendor_id = chip->rtsx->pci->vendor; - chip->product_id = chip->rtsx->pci->device; - chip->adma_mode = 1; - chip->lun_mc = 0; - chip->driver_first_load = 1; -#ifdef HW_AUTO_SWITCH_SD_BUS - chip->sdio_in_charge = 0; -#endif - - chip->mspro_formatter_enable = 1; - chip->ignore_sd = 0; - chip->use_hw_setting = 0; - chip->lun_mode = DEFAULT_SINGLE; - chip->auto_delink_en = auto_delink_en; - chip->ss_en = ss_en; - chip->ss_idle_period = ss_interval * 1000; - chip->remote_wakeup_en = 0; - chip->aspm_l0s_l1_en = aspm_l0s_l1_en; - chip->dynamic_aspm = 1; - chip->fpga_sd_sdr104_clk = CLK_200; - chip->fpga_sd_ddr50_clk = CLK_100; - chip->fpga_sd_sdr50_clk = CLK_100; - chip->fpga_sd_hs_clk = CLK_100; - chip->fpga_mmc_52m_clk = CLK_80; - chip->fpga_ms_hg_clk = CLK_80; - chip->fpga_ms_4bit_clk = CLK_80; - chip->fpga_ms_1bit_clk = CLK_40; - chip->asic_sd_sdr104_clk = 203; - chip->asic_sd_sdr50_clk = 98; - chip->asic_sd_ddr50_clk = 98; - chip->asic_sd_hs_clk = 98; - chip->asic_mmc_52m_clk = 98; - chip->asic_ms_hg_clk = 117; - chip->asic_ms_4bit_clk = 78; - chip->asic_ms_1bit_clk = 39; - chip->ssc_depth_sd_sdr104 = SSC_DEPTH_2M; - chip->ssc_depth_sd_sdr50 = SSC_DEPTH_2M; - chip->ssc_depth_sd_ddr50 = SSC_DEPTH_1M; - chip->ssc_depth_sd_hs = SSC_DEPTH_1M; - chip->ssc_depth_mmc_52m = SSC_DEPTH_1M; - chip->ssc_depth_ms_hg = SSC_DEPTH_1M; - chip->ssc_depth_ms_4bit = SSC_DEPTH_512K; - chip->ssc_depth_low_speed = SSC_DEPTH_512K; - chip->ssc_en = 1; - chip->sd_speed_prior = 0x01040203; - chip->sd_current_prior = 0x00010203; - chip->sd_ctl = SD_PUSH_POINT_AUTO | - SD_SAMPLE_POINT_AUTO | - SUPPORT_MMC_DDR_MODE; - chip->sd_ddr_tx_phase = 0; - chip->mmc_ddr_tx_phase = 1; - chip->sd_default_tx_phase = 15; - chip->sd_default_rx_phase = 15; - chip->pmos_pwr_on_interval = 200; - chip->sd_voltage_switch_delay = 1000; - chip->ms_power_class_en = 3; - - chip->sd_400mA_ocp_thd = 1; - chip->sd_800mA_ocp_thd = 5; - chip->ms_ocp_thd = 2; - - chip->card_drive_sel = 0x55; - chip->sd30_drive_sel_1v8 = 0x03; - chip->sd30_drive_sel_3v3 = 0x01; - - chip->do_delink_before_power_down = 1; - chip->auto_power_down = 1; - chip->polling_config = 0; - - chip->force_clkreq_0 = 1; - chip->ft2_fast_mode = 0; - - chip->sdio_retry_cnt = 1; - - chip->xd_timeout = 2000; - chip->sd_timeout = 10000; - chip->ms_timeout = 2000; - chip->mspro_timeout = 15000; - - chip->power_down_in_ss = 1; - - chip->sdr104_en = 1; - chip->sdr50_en = 1; - chip->ddr50_en = 1; - - chip->delink_stage1_step = 100; - chip->delink_stage2_step = 40; - chip->delink_stage3_step = 20; - - chip->auto_delink_in_L1 = 1; - chip->blink_led = 1; - chip->msi_en = msi_en; - chip->hp_watch_bios_hotplug = 0; - chip->max_payload = 0; - chip->phy_voltage = 0; - - chip->support_ms_8bit = 1; - chip->s3_pwr_off_delay = 1000; -} - -static int rtsx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) -{ - struct Scsi_Host *host; - struct rtsx_dev *dev; - int err = 0; - struct task_struct *th; - - dev_dbg(&pci->dev, "Realtek PCI-E card reader detected\n"); - - err = pcim_enable_device(pci); - if (err < 0) { - dev_err(&pci->dev, "PCI enable device failed!\n"); - return err; - } - - err = pci_request_regions(pci, CR_DRIVER_NAME); - if (err < 0) { - dev_err(&pci->dev, "PCI request regions for %s failed!\n", - CR_DRIVER_NAME); - return err; - } - - /* - * Ask the SCSI layer to allocate a host structure, with extra - * space at the end for our private rtsx_dev structure. - */ - host = scsi_host_alloc(&rtsx_host_template, sizeof(*dev)); - if (!host) { - dev_err(&pci->dev, "Unable to allocate the scsi host\n"); - err = -ENOMEM; - goto scsi_host_alloc_fail; - } - - dev = host_to_rtsx(host); - memset(dev, 0, sizeof(struct rtsx_dev)); - - dev->chip = kzalloc(sizeof(*dev->chip), GFP_KERNEL); - if (!dev->chip) { - err = -ENOMEM; - goto chip_alloc_fail; - } - - spin_lock_init(&dev->reg_lock); - mutex_init(&dev->dev_mutex); - init_completion(&dev->cmnd_ready); - init_completion(&dev->control_exit); - init_completion(&dev->polling_exit); - init_completion(&dev->notify); - init_completion(&dev->scanning_done); - init_waitqueue_head(&dev->delay_wait); - - dev->pci = pci; - dev->irq = -1; - - dev_info(&pci->dev, "Resource length: 0x%x\n", - (unsigned int)pci_resource_len(pci, 0)); - dev->addr = pci_resource_start(pci, 0); - dev->remap_addr = ioremap(dev->addr, pci_resource_len(pci, 0)); - if (!dev->remap_addr) { - dev_err(&pci->dev, "ioremap error\n"); - err = -ENXIO; - goto ioremap_fail; - } - - /* - * Using "unsigned long" cast here to eliminate gcc warning in - * 64-bit system - */ - dev_info(&pci->dev, "Original address: 0x%lx, remapped address: 0x%lx\n", - (unsigned long)(dev->addr), (unsigned long)(dev->remap_addr)); - - dev->rtsx_resv_buf = dmam_alloc_coherent(&pci->dev, RTSX_RESV_BUF_LEN, - &dev->rtsx_resv_buf_addr, - GFP_KERNEL); - if (!dev->rtsx_resv_buf) { - dev_err(&pci->dev, "alloc dma buffer fail\n"); - err = -ENXIO; - goto dma_alloc_fail; - } - dev->chip->host_cmds_ptr = dev->rtsx_resv_buf; - dev->chip->host_cmds_addr = dev->rtsx_resv_buf_addr; - dev->chip->host_sg_tbl_ptr = dev->rtsx_resv_buf + HOST_CMDS_BUF_LEN; - dev->chip->host_sg_tbl_addr = dev->rtsx_resv_buf_addr + - HOST_CMDS_BUF_LEN; - - dev->chip->rtsx = dev; - - rtsx_init_options(dev->chip); - - dev_info(&pci->dev, "pci->irq = %d\n", pci->irq); - - if (dev->chip->msi_en) { - if (pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) < 0) - dev->chip->msi_en = 0; - } - - if (rtsx_acquire_irq(dev) < 0) { - err = -EBUSY; - goto irq_acquire_fail; - } - - pci_set_master(pci); - synchronize_irq(dev->irq); - - rtsx_init_chip(dev->chip); - - /* - * set the supported max_lun and max_id for the scsi host - * NOTE: the minimal value of max_id is 1 - */ - host->max_id = 1; - host->max_lun = dev->chip->max_lun; - - /* Start up our control thread */ - th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME); - if (IS_ERR(th)) { - dev_err(&pci->dev, "Unable to start control thread\n"); - err = PTR_ERR(th); - goto control_thread_fail; - } - dev->ctl_thread = th; - - err = scsi_add_host(host, &pci->dev); - if (err) { - dev_err(&pci->dev, "Unable to add the scsi host\n"); - goto scsi_add_host_fail; - } - - /* Start up the thread for delayed SCSI-device scanning */ - th = kthread_run(rtsx_scan_thread, dev, "rtsx-scan"); - if (IS_ERR(th)) { - dev_err(&pci->dev, "Unable to start the device-scanning thread\n"); - complete(&dev->scanning_done); - err = PTR_ERR(th); - goto scan_thread_fail; - } - - /* Start up the thread for polling thread */ - th = kthread_run(rtsx_polling_thread, dev, "rtsx-polling"); - if (IS_ERR(th)) { - dev_err(&pci->dev, "Unable to start the device-polling thread\n"); - err = PTR_ERR(th); - goto scan_thread_fail; - } - dev->polling_thread = th; - - pci_set_drvdata(pci, dev); - - return 0; - - /* We come here if there are any problems */ -scan_thread_fail: - quiesce_and_remove_host(dev); -scsi_add_host_fail: - complete(&dev->cmnd_ready); - wait_for_completion(&dev->control_exit); -control_thread_fail: - free_irq(dev->irq, (void *)dev); - rtsx_release_chip(dev->chip); -irq_acquire_fail: - dev->chip->host_cmds_ptr = NULL; - dev->chip->host_sg_tbl_ptr = NULL; - if (dev->chip->msi_en) - pci_free_irq_vectors(dev->pci); -dma_alloc_fail: - iounmap(dev->remap_addr); -ioremap_fail: - kfree(dev->chip); -chip_alloc_fail: - dev_err(&pci->dev, "%s failed\n", __func__); - scsi_host_put(host); -scsi_host_alloc_fail: - pci_release_regions(pci); - return err; -} - -static void rtsx_remove(struct pci_dev *pci) -{ - struct rtsx_dev *dev = pci_get_drvdata(pci); - - quiesce_and_remove_host(dev); - release_everything(dev); - pci_release_regions(pci); -} - -/* PCI IDs */ -static const struct pci_device_id rtsx_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x5208), - PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x5288), - PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, rtsx_ids); - -static SIMPLE_DEV_PM_OPS(rtsx_pm_ops, rtsx_suspend, rtsx_resume); - -/* pci_driver definition */ -static struct pci_driver rtsx_driver = { - .name = CR_DRIVER_NAME, - .id_table = rtsx_ids, - .probe = rtsx_probe, - .remove = rtsx_remove, - .driver.pm = &rtsx_pm_ops, - .shutdown = rtsx_shutdown, -}; - -module_pci_driver(rtsx_driver); diff --git a/drivers/staging/rts5208/rtsx.h b/drivers/staging/rts5208/rtsx.h deleted file mode 100644 index ec6f5b07390b2c..00000000000000 --- a/drivers/staging/rts5208/rtsx.h +++ /dev/null @@ -1,164 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_H -#define __REALTEK_RTSX_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define CR_DRIVER_NAME "rts5208" - -/* - * macros for easy use - */ -#define wait_timeout_x(task_state, msecs) \ -do { \ - set_current_state((task_state)); \ - schedule_timeout((msecs) * HZ / 1000); \ -} while (0) -#define wait_timeout(msecs) wait_timeout_x(TASK_INTERRUPTIBLE, (msecs)) - -#define STATE_TRANS_NONE 0 -#define STATE_TRANS_CMD 1 -#define STATE_TRANS_BUF 2 -#define STATE_TRANS_SG 3 - -#define TRANS_NOT_READY 0 -#define TRANS_RESULT_OK 1 -#define TRANS_RESULT_FAIL 2 - -#define SCSI_LUN(srb) ((srb)->device->lun) - -struct rtsx_chip; - -struct rtsx_dev { - struct pci_dev *pci; - - /* pci resources */ - unsigned long addr; - void __iomem *remap_addr; - int irq; - - /* locks */ - spinlock_t reg_lock; - - struct task_struct *ctl_thread; /* the control thread */ - struct task_struct *polling_thread; /* the polling thread */ - - /* mutual exclusion and synchronization structures */ - struct completion cmnd_ready; /* to sleep thread on */ - struct completion control_exit; /* control thread exit */ - struct completion polling_exit; /* polling thread exit */ - struct completion notify; /* thread begin/end */ - struct completion scanning_done; /* wait for scan thread */ - - wait_queue_head_t delay_wait; /* wait during scan, reset */ - struct mutex dev_mutex; - - /* host reserved buffer */ - void *rtsx_resv_buf; - dma_addr_t rtsx_resv_buf_addr; - - char trans_result; - char trans_state; - - struct completion *done; - /* Whether interrupt handler should care card cd info */ - u32 check_card_cd; - - struct rtsx_chip *chip; -}; - -/* Convert between rtsx_dev and the corresponding Scsi_Host */ -static inline struct Scsi_Host *rtsx_to_host(struct rtsx_dev *dev) -{ - return container_of((void *)dev, struct Scsi_Host, hostdata); -} - -static inline struct rtsx_dev *host_to_rtsx(struct Scsi_Host *host) -{ - return (struct rtsx_dev *)host->hostdata; -} - -#define lock_state(chip) spin_lock_irq(&((chip)->rtsx->reg_lock)) -#define unlock_state(chip) spin_unlock_irq(&((chip)->rtsx->reg_lock)) - -/* struct scsi_cmnd transfer buffer access utilities */ -enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF}; - -#include "rtsx_chip.h" -#include "rtsx_transport.h" -#include "rtsx_scsi.h" -#include "rtsx_card.h" -#include "rtsx_sys.h" -#include "general.h" - -static inline void rtsx_writel(struct rtsx_chip *chip, u32 reg, u32 value) -{ - iowrite32(value, chip->rtsx->remap_addr + reg); -} - -static inline u32 rtsx_readl(struct rtsx_chip *chip, u32 reg) -{ - return ioread32(chip->rtsx->remap_addr + reg); -} - -static inline void rtsx_writew(struct rtsx_chip *chip, u32 reg, u16 value) -{ - iowrite16(value, chip->rtsx->remap_addr + reg); -} - -static inline u16 rtsx_readw(struct rtsx_chip *chip, u32 reg) -{ - return ioread16(chip->rtsx->remap_addr + reg); -} - -static inline void rtsx_writeb(struct rtsx_chip *chip, u32 reg, u8 value) -{ - iowrite8(value, chip->rtsx->remap_addr + reg); -} - -static inline u8 rtsx_readb(struct rtsx_chip *chip, u32 reg) -{ - return ioread8((chip)->rtsx->remap_addr + reg); -} - -static inline int rtsx_read_config_byte(struct rtsx_chip *chip, int where, u8 *val) -{ - return pci_read_config_byte(chip->rtsx->pci, where, val); -} - -static inline int rtsx_write_config_byte(struct rtsx_chip *chip, int where, u8 val) -{ - return pci_write_config_byte(chip->rtsx->pci, where, val); -} - -#endif /* __REALTEK_RTSX_H */ diff --git a/drivers/staging/rts5208/rtsx_card.c b/drivers/staging/rts5208/rtsx_card.c deleted file mode 100644 index 326b04756f62c7..00000000000000 --- a/drivers/staging/rts5208/rtsx_card.c +++ /dev/null @@ -1,1151 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include -#include -#include - -#include "rtsx.h" -#include "sd.h" -#include "xd.h" -#include "ms.h" - -void do_remaining_work(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; -#ifdef XD_DELAY_WRITE - struct xd_info *xd_card = &chip->xd_card; -#endif - struct ms_info *ms_card = &chip->ms_card; - - if (chip->card_ready & SD_CARD) { - if (sd_card->seq_mode) { - rtsx_set_stat(chip, RTSX_STAT_RUN); - sd_card->cleanup_counter++; - } else { - sd_card->cleanup_counter = 0; - } - } - -#ifdef XD_DELAY_WRITE - if (chip->card_ready & XD_CARD) { - if (xd_card->delay_write.delay_write_flag) { - rtsx_set_stat(chip, RTSX_STAT_RUN); - xd_card->cleanup_counter++; - } else { - xd_card->cleanup_counter = 0; - } - } -#endif - - if (chip->card_ready & MS_CARD) { - if (CHK_MSPRO(ms_card)) { - if (ms_card->seq_mode) { - rtsx_set_stat(chip, RTSX_STAT_RUN); - ms_card->cleanup_counter++; - } else { - ms_card->cleanup_counter = 0; - } - } else { -#ifdef MS_DELAY_WRITE - if (ms_card->delay_write.delay_write_flag) { - rtsx_set_stat(chip, RTSX_STAT_RUN); - ms_card->cleanup_counter++; - } else { - ms_card->cleanup_counter = 0; - } -#endif - } - } - - if (sd_card->cleanup_counter > POLLING_WAIT_CNT) - sd_cleanup_work(chip); - - if (xd_card->cleanup_counter > POLLING_WAIT_CNT) - xd_cleanup_work(chip); - - if (ms_card->cleanup_counter > POLLING_WAIT_CNT) - ms_cleanup_work(chip); -} - -void try_to_switch_sdio_ctrl(struct rtsx_chip *chip) -{ - u8 reg1 = 0, reg2 = 0; - - rtsx_read_register(chip, 0xFF34, ®1); - rtsx_read_register(chip, 0xFF38, ®2); - dev_dbg(rtsx_dev(chip), "reg 0xFF34: 0x%x, reg 0xFF38: 0x%x\n", - reg1, reg2); - if ((reg1 & 0xC0) && (reg2 & 0xC0)) { - chip->sd_int = 1; - rtsx_write_register(chip, SDIO_CTRL, 0xFF, - SDIO_BUS_CTRL | SDIO_CD_CTRL); - rtsx_write_register(chip, PWR_GATE_CTRL, - LDO3318_PWR_MASK, LDO_ON); - } -} - -#ifdef SUPPORT_SDIO_ASPM -void dynamic_configure_sdio_aspm(struct rtsx_chip *chip) -{ - u8 buf[12], reg; - int i; - - for (i = 0; i < 12; i++) - rtsx_read_register(chip, 0xFF08 + i, &buf[i]); - rtsx_read_register(chip, 0xFF25, ®); - if ((memcmp(buf, chip->sdio_raw_data, 12) != 0) || (reg & 0x03)) { - chip->sdio_counter = 0; - chip->sdio_idle = 0; - } else { - if (!chip->sdio_idle) { - chip->sdio_counter++; - if (chip->sdio_counter >= SDIO_IDLE_COUNT) { - chip->sdio_counter = 0; - chip->sdio_idle = 1; - } - } - } - memcpy(chip->sdio_raw_data, buf, 12); - - if (chip->sdio_idle) { - if (!chip->sdio_aspm) { - dev_dbg(rtsx_dev(chip), "SDIO enter ASPM!\n"); - rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFC, - 0x30 | (chip->aspm_level[1] << 2)); - chip->sdio_aspm = 1; - } - } else { - if (chip->sdio_aspm) { - dev_dbg(rtsx_dev(chip), "SDIO exit ASPM!\n"); - rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFC, 0x30); - chip->sdio_aspm = 0; - } - } -} -#endif - -void do_reset_sd_card(struct rtsx_chip *chip) -{ - int retval; - - dev_dbg(rtsx_dev(chip), "%s: %d, card2lun = 0x%x\n", __func__, - chip->sd_reset_counter, chip->card2lun[SD_CARD]); - - if (chip->card2lun[SD_CARD] >= MAX_ALLOWED_LUN_CNT) { - clear_bit(SD_NR, &chip->need_reset); - chip->sd_reset_counter = 0; - chip->sd_show_cnt = 0; - return; - } - - chip->rw_fail_cnt[chip->card2lun[SD_CARD]] = 0; - - rtsx_set_stat(chip, RTSX_STAT_RUN); - rtsx_write_register(chip, SDIO_CTRL, 0xFF, 0); - - retval = reset_sd_card(chip); - if (chip->need_release & SD_CARD) - return; - if (retval == STATUS_SUCCESS) { - clear_bit(SD_NR, &chip->need_reset); - chip->sd_reset_counter = 0; - chip->sd_show_cnt = 0; - chip->card_ready |= SD_CARD; - chip->card_fail &= ~SD_CARD; - chip->rw_card[chip->card2lun[SD_CARD]] = sd_rw; - } else { - if (chip->sd_io || chip->sd_reset_counter >= MAX_RESET_CNT) { - clear_bit(SD_NR, &chip->need_reset); - chip->sd_reset_counter = 0; - chip->sd_show_cnt = 0; - } else { - chip->sd_reset_counter++; - } - chip->card_ready &= ~SD_CARD; - chip->card_fail |= SD_CARD; - chip->capacity[chip->card2lun[SD_CARD]] = 0; - chip->rw_card[chip->card2lun[SD_CARD]] = NULL; - - rtsx_write_register(chip, CARD_OE, SD_OUTPUT_EN, 0); - if (!chip->ft2_fast_mode) - card_power_off(chip, SD_CARD); - if (chip->sd_io) { - chip->sd_int = 0; - try_to_switch_sdio_ctrl(chip); - } else { - disable_card_clock(chip, SD_CARD); - } - } -} - -void do_reset_xd_card(struct rtsx_chip *chip) -{ - int retval; - - dev_dbg(rtsx_dev(chip), "%s: %d, card2lun = 0x%x\n", __func__, - chip->xd_reset_counter, chip->card2lun[XD_CARD]); - - if (chip->card2lun[XD_CARD] >= MAX_ALLOWED_LUN_CNT) { - clear_bit(XD_NR, &chip->need_reset); - chip->xd_reset_counter = 0; - chip->xd_show_cnt = 0; - return; - } - - chip->rw_fail_cnt[chip->card2lun[XD_CARD]] = 0; - - rtsx_set_stat(chip, RTSX_STAT_RUN); - rtsx_write_register(chip, SDIO_CTRL, 0xFF, 0); - - retval = reset_xd_card(chip); - if (chip->need_release & XD_CARD) - return; - if (retval == STATUS_SUCCESS) { - clear_bit(XD_NR, &chip->need_reset); - chip->xd_reset_counter = 0; - chip->card_ready |= XD_CARD; - chip->card_fail &= ~XD_CARD; - chip->rw_card[chip->card2lun[XD_CARD]] = xd_rw; - } else { - if (chip->xd_reset_counter >= MAX_RESET_CNT) { - clear_bit(XD_NR, &chip->need_reset); - chip->xd_reset_counter = 0; - chip->xd_show_cnt = 0; - } else { - chip->xd_reset_counter++; - } - chip->card_ready &= ~XD_CARD; - chip->card_fail |= XD_CARD; - chip->capacity[chip->card2lun[XD_CARD]] = 0; - chip->rw_card[chip->card2lun[XD_CARD]] = NULL; - - rtsx_write_register(chip, CARD_OE, XD_OUTPUT_EN, 0); - if (!chip->ft2_fast_mode) - card_power_off(chip, XD_CARD); - disable_card_clock(chip, XD_CARD); - } -} - -void do_reset_ms_card(struct rtsx_chip *chip) -{ - int retval; - - dev_dbg(rtsx_dev(chip), "%s: %d, card2lun = 0x%x\n", __func__, - chip->ms_reset_counter, chip->card2lun[MS_CARD]); - - if (chip->card2lun[MS_CARD] >= MAX_ALLOWED_LUN_CNT) { - clear_bit(MS_NR, &chip->need_reset); - chip->ms_reset_counter = 0; - chip->ms_show_cnt = 0; - return; - } - - chip->rw_fail_cnt[chip->card2lun[MS_CARD]] = 0; - - rtsx_set_stat(chip, RTSX_STAT_RUN); - rtsx_write_register(chip, SDIO_CTRL, 0xFF, 0); - - retval = reset_ms_card(chip); - if (chip->need_release & MS_CARD) - return; - if (retval == STATUS_SUCCESS) { - clear_bit(MS_NR, &chip->need_reset); - chip->ms_reset_counter = 0; - chip->card_ready |= MS_CARD; - chip->card_fail &= ~MS_CARD; - chip->rw_card[chip->card2lun[MS_CARD]] = ms_rw; - } else { - if (chip->ms_reset_counter >= MAX_RESET_CNT) { - clear_bit(MS_NR, &chip->need_reset); - chip->ms_reset_counter = 0; - chip->ms_show_cnt = 0; - } else { - chip->ms_reset_counter++; - } - chip->card_ready &= ~MS_CARD; - chip->card_fail |= MS_CARD; - chip->capacity[chip->card2lun[MS_CARD]] = 0; - chip->rw_card[chip->card2lun[MS_CARD]] = NULL; - - rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0); - if (!chip->ft2_fast_mode) - card_power_off(chip, MS_CARD); - disable_card_clock(chip, MS_CARD); - } -} - -static void release_sdio(struct rtsx_chip *chip) -{ - if (chip->sd_io) { - rtsx_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, - SD_STOP | SD_CLR_ERR); - - if (chip->chip_insert_with_sdio) { - chip->chip_insert_with_sdio = 0; - - if (CHECK_PID(chip, 0x5288)) - rtsx_write_register(chip, 0xFE5A, 0x08, 0x00); - else - rtsx_write_register(chip, 0xFE70, 0x80, 0x00); - } - - rtsx_write_register(chip, SDIO_CTRL, SDIO_CD_CTRL, 0); - chip->sd_io = 0; - } -} - -void rtsx_power_off_card(struct rtsx_chip *chip) -{ - if ((chip->card_ready & SD_CARD) || chip->sd_io) { - sd_cleanup_work(chip); - sd_power_off_card3v3(chip); - } - - if (chip->card_ready & XD_CARD) { - xd_cleanup_work(chip); - xd_power_off_card3v3(chip); - } - - if (chip->card_ready & MS_CARD) { - ms_cleanup_work(chip); - ms_power_off_card3v3(chip); - } -} - -void rtsx_release_cards(struct rtsx_chip *chip) -{ - chip->int_reg = rtsx_readl(chip, RTSX_BIPR); - - if ((chip->card_ready & SD_CARD) || chip->sd_io) { - if (chip->int_reg & SD_EXIST) - sd_cleanup_work(chip); - release_sd_card(chip); - } - - if (chip->card_ready & XD_CARD) { - if (chip->int_reg & XD_EXIST) - xd_cleanup_work(chip); - release_xd_card(chip); - } - - if (chip->card_ready & MS_CARD) { - if (chip->int_reg & MS_EXIST) - ms_cleanup_work(chip); - release_ms_card(chip); - } -} - -void rtsx_reset_cards(struct rtsx_chip *chip) -{ - if (!chip->need_reset) - return; - - rtsx_set_stat(chip, RTSX_STAT_RUN); - - rtsx_force_power_on(chip, SSC_PDCTL | OC_PDCTL); - - rtsx_disable_aspm(chip); - - if ((chip->need_reset & SD_CARD) && chip->chip_insert_with_sdio) - clear_bit(SD_NR, &chip->need_reset); - - if (chip->need_reset & XD_CARD) { - chip->card_exist |= XD_CARD; - - if (chip->xd_show_cnt >= MAX_SHOW_CNT) - do_reset_xd_card(chip); - else - chip->xd_show_cnt++; - } - if (CHECK_PID(chip, 0x5288) && CHECK_BARO_PKG(chip, QFN)) { - if (chip->card_exist & XD_CARD) { - clear_bit(SD_NR, &chip->need_reset); - clear_bit(MS_NR, &chip->need_reset); - } - } - if (chip->need_reset & SD_CARD) { - chip->card_exist |= SD_CARD; - - if (chip->sd_show_cnt >= MAX_SHOW_CNT) { - rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); - do_reset_sd_card(chip); - } else { - chip->sd_show_cnt++; - } - } - if (chip->need_reset & MS_CARD) { - chip->card_exist |= MS_CARD; - - if (chip->ms_show_cnt >= MAX_SHOW_CNT) - do_reset_ms_card(chip); - else - chip->ms_show_cnt++; - } -} - -void rtsx_reinit_cards(struct rtsx_chip *chip, int reset_chip) -{ - rtsx_set_stat(chip, RTSX_STAT_RUN); - - rtsx_force_power_on(chip, SSC_PDCTL | OC_PDCTL); - - if (reset_chip) - rtsx_reset_chip(chip); - - chip->int_reg = rtsx_readl(chip, RTSX_BIPR); - - if ((chip->int_reg & SD_EXIST) && (chip->need_reinit & SD_CARD)) { - release_sdio(chip); - release_sd_card(chip); - - wait_timeout(100); - - chip->card_exist |= SD_CARD; - do_reset_sd_card(chip); - } - - if ((chip->int_reg & XD_EXIST) && (chip->need_reinit & XD_CARD)) { - release_xd_card(chip); - - wait_timeout(100); - - chip->card_exist |= XD_CARD; - do_reset_xd_card(chip); - } - - if ((chip->int_reg & MS_EXIST) && (chip->need_reinit & MS_CARD)) { - release_ms_card(chip); - - wait_timeout(100); - - chip->card_exist |= MS_CARD; - do_reset_ms_card(chip); - } - - chip->need_reinit = 0; -} - -#ifdef DISABLE_CARD_INT -void card_cd_debounce(struct rtsx_chip *chip, unsigned long *need_reset, - unsigned long *need_release) -{ - u8 release_map = 0, reset_map = 0; - - chip->int_reg = rtsx_readl(chip, RTSX_BIPR); - - if (chip->card_exist) { - if (chip->card_exist & XD_CARD) { - if (!(chip->int_reg & XD_EXIST)) - release_map |= XD_CARD; - } else if (chip->card_exist & SD_CARD) { - if (!(chip->int_reg & SD_EXIST)) - release_map |= SD_CARD; - } else if (chip->card_exist & MS_CARD) { - if (!(chip->int_reg & MS_EXIST)) - release_map |= MS_CARD; - } - } else { - if (chip->int_reg & XD_EXIST) - reset_map |= XD_CARD; - else if (chip->int_reg & SD_EXIST) - reset_map |= SD_CARD; - else if (chip->int_reg & MS_EXIST) - reset_map |= MS_CARD; - } - - if (reset_map) { - int xd_cnt = 0, sd_cnt = 0, ms_cnt = 0; - int i; - - for (i = 0; i < (DEBOUNCE_CNT); i++) { - chip->int_reg = rtsx_readl(chip, RTSX_BIPR); - - if (chip->int_reg & XD_EXIST) - xd_cnt++; - else - xd_cnt = 0; - - if (chip->int_reg & SD_EXIST) - sd_cnt++; - else - sd_cnt = 0; - - if (chip->int_reg & MS_EXIST) - ms_cnt++; - else - ms_cnt = 0; - - wait_timeout(30); - } - - reset_map = 0; - if (!(chip->card_exist & XD_CARD) && - (xd_cnt > (DEBOUNCE_CNT - 1))) - reset_map |= XD_CARD; - if (!(chip->card_exist & SD_CARD) && - (sd_cnt > (DEBOUNCE_CNT - 1))) - reset_map |= SD_CARD; - if (!(chip->card_exist & MS_CARD) && - (ms_cnt > (DEBOUNCE_CNT - 1))) - reset_map |= MS_CARD; - } - - if (CHECK_PID(chip, 0x5288) && CHECK_BARO_PKG(chip, QFN)) - rtsx_write_register(chip, HOST_SLEEP_STATE, 0xC0, 0x00); - - if (need_reset) - *need_reset = reset_map; - if (need_release) - *need_release = release_map; -} -#endif - -void rtsx_init_cards(struct rtsx_chip *chip) -{ - if (RTSX_TST_DELINK(chip) && (rtsx_get_stat(chip) != RTSX_STAT_SS)) { - dev_dbg(rtsx_dev(chip), "Reset chip in polling thread!\n"); - rtsx_reset_chip(chip); - RTSX_CLR_DELINK(chip); - } - -#ifdef DISABLE_CARD_INT - card_cd_debounce(chip, &chip->need_reset, &chip->need_release); -#endif - - if (chip->need_release) { - if (CHECK_PID(chip, 0x5288) && CHECK_BARO_PKG(chip, QFN)) { - if (chip->int_reg & XD_EXIST) { - clear_bit(SD_NR, &chip->need_release); - clear_bit(MS_NR, &chip->need_release); - } - } - - if (!(chip->card_exist & SD_CARD) && !chip->sd_io) - clear_bit(SD_NR, &chip->need_release); - if (!(chip->card_exist & XD_CARD)) - clear_bit(XD_NR, &chip->need_release); - if (!(chip->card_exist & MS_CARD)) - clear_bit(MS_NR, &chip->need_release); - - dev_dbg(rtsx_dev(chip), "chip->need_release = 0x%x\n", - (unsigned int)(chip->need_release)); - -#ifdef SUPPORT_OCP - if (chip->need_release) { - if (chip->ocp_stat & (CARD_OC_NOW | CARD_OC_EVER)) - rtsx_write_register(chip, OCPCLR, - CARD_OC_INT_CLR | - CARD_OC_CLR, - CARD_OC_INT_CLR | - CARD_OC_CLR); - chip->ocp_stat = 0; - } -#endif - if (chip->need_release) { - rtsx_set_stat(chip, RTSX_STAT_RUN); - rtsx_force_power_on(chip, SSC_PDCTL | OC_PDCTL); - } - - if (chip->need_release & SD_CARD) { - clear_bit(SD_NR, &chip->need_release); - chip->card_exist &= ~SD_CARD; - chip->card_ejected &= ~SD_CARD; - chip->card_fail &= ~SD_CARD; - CLR_BIT(chip->lun_mc, chip->card2lun[SD_CARD]); - chip->rw_fail_cnt[chip->card2lun[SD_CARD]] = 0; - rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); - - release_sdio(chip); - release_sd_card(chip); - } - - if (chip->need_release & XD_CARD) { - clear_bit(XD_NR, &chip->need_release); - chip->card_exist &= ~XD_CARD; - chip->card_ejected &= ~XD_CARD; - chip->card_fail &= ~XD_CARD; - CLR_BIT(chip->lun_mc, chip->card2lun[XD_CARD]); - chip->rw_fail_cnt[chip->card2lun[XD_CARD]] = 0; - - release_xd_card(chip); - - if (CHECK_PID(chip, 0x5288) && - CHECK_BARO_PKG(chip, QFN)) - rtsx_write_register(chip, HOST_SLEEP_STATE, - 0xC0, 0xC0); - } - - if (chip->need_release & MS_CARD) { - clear_bit(MS_NR, &chip->need_release); - chip->card_exist &= ~MS_CARD; - chip->card_ejected &= ~MS_CARD; - chip->card_fail &= ~MS_CARD; - CLR_BIT(chip->lun_mc, chip->card2lun[MS_CARD]); - chip->rw_fail_cnt[chip->card2lun[MS_CARD]] = 0; - - release_ms_card(chip); - } - - dev_dbg(rtsx_dev(chip), "chip->card_exist = 0x%x\n", - chip->card_exist); - - if (!chip->card_exist) - turn_off_led(chip, LED_GPIO); - } - - if (chip->need_reset) { - dev_dbg(rtsx_dev(chip), "chip->need_reset = 0x%x\n", - (unsigned int)(chip->need_reset)); - - rtsx_reset_cards(chip); - } - - if (chip->need_reinit) { - dev_dbg(rtsx_dev(chip), "chip->need_reinit = 0x%x\n", - (unsigned int)(chip->need_reinit)); - - rtsx_reinit_cards(chip, 0); - } -} - -int switch_ssc_clock(struct rtsx_chip *chip, int clk) -{ - int retval; - u8 n = (u8)(clk - 2), min_n, max_n; - u8 mcu_cnt, div, max_div, ssc_depth, ssc_depth_mask; - int sd_vpclk_phase_reset = 0; - - if (chip->cur_clk == clk) - return STATUS_SUCCESS; - - min_n = 60; - max_n = 120; - max_div = CLK_DIV_4; - - dev_dbg(rtsx_dev(chip), "Switch SSC clock to %dMHz (cur_clk = %d)\n", - clk, chip->cur_clk); - - if (clk <= 2 || n > max_n) - return STATUS_FAIL; - - mcu_cnt = (u8)(125 / clk + 3); - if (mcu_cnt > 7) - mcu_cnt = 7; - - div = CLK_DIV_1; - while ((n < min_n) && (div < max_div)) { - n = (n + 2) * 2 - 2; - div++; - } - dev_dbg(rtsx_dev(chip), "n = %d, div = %d\n", n, div); - - if (chip->ssc_en) { - ssc_depth = 0x01; - n -= 2; - } else { - ssc_depth = 0; - } - - ssc_depth_mask = 0x03; - - dev_dbg(rtsx_dev(chip), "ssc_depth = %d\n", ssc_depth); - - rtsx_init_cmd(chip); - rtsx_add_cmd(chip, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, CLK_LOW_FREQ); - rtsx_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0xFF, (div << 4) | mcu_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL2, ssc_depth_mask, ssc_depth); - rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n); - rtsx_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB); - if (sd_vpclk_phase_reset) { - rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, - PHASE_NOT_RESET, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL, - PHASE_NOT_RESET, PHASE_NOT_RESET); - } - - retval = rtsx_send_cmd(chip, 0, WAIT_TIME); - if (retval < 0) - return STATUS_ERROR; - - udelay(10); - retval = rtsx_write_register(chip, CLK_CTL, CLK_LOW_FREQ, 0); - if (retval) - return retval; - - chip->cur_clk = clk; - - return STATUS_SUCCESS; -} - -int switch_normal_clock(struct rtsx_chip *chip, int clk) -{ - int retval; - u8 sel, div, mcu_cnt; - int sd_vpclk_phase_reset = 0; - - if (chip->cur_clk == clk) - return STATUS_SUCCESS; - - switch (clk) { - case CLK_20: - dev_dbg(rtsx_dev(chip), "Switch clock to 20MHz\n"); - sel = SSC_80; - div = CLK_DIV_4; - mcu_cnt = 7; - break; - - case CLK_30: - dev_dbg(rtsx_dev(chip), "Switch clock to 30MHz\n"); - sel = SSC_120; - div = CLK_DIV_4; - mcu_cnt = 7; - break; - - case CLK_40: - dev_dbg(rtsx_dev(chip), "Switch clock to 40MHz\n"); - sel = SSC_80; - div = CLK_DIV_2; - mcu_cnt = 7; - break; - - case CLK_50: - dev_dbg(rtsx_dev(chip), "Switch clock to 50MHz\n"); - sel = SSC_100; - div = CLK_DIV_2; - mcu_cnt = 6; - break; - - case CLK_60: - dev_dbg(rtsx_dev(chip), "Switch clock to 60MHz\n"); - sel = SSC_120; - div = CLK_DIV_2; - mcu_cnt = 6; - break; - - case CLK_80: - dev_dbg(rtsx_dev(chip), "Switch clock to 80MHz\n"); - sel = SSC_80; - div = CLK_DIV_1; - mcu_cnt = 5; - break; - - case CLK_100: - dev_dbg(rtsx_dev(chip), "Switch clock to 100MHz\n"); - sel = SSC_100; - div = CLK_DIV_1; - mcu_cnt = 5; - break; - - case CLK_120: - dev_dbg(rtsx_dev(chip), "Switch clock to 120MHz\n"); - sel = SSC_120; - div = CLK_DIV_1; - mcu_cnt = 5; - break; - - case CLK_150: - dev_dbg(rtsx_dev(chip), "Switch clock to 150MHz\n"); - sel = SSC_150; - div = CLK_DIV_1; - mcu_cnt = 4; - break; - - case CLK_200: - dev_dbg(rtsx_dev(chip), "Switch clock to 200MHz\n"); - sel = SSC_200; - div = CLK_DIV_1; - mcu_cnt = 4; - break; - - default: - dev_dbg(rtsx_dev(chip), "Try to switch to an illegal clock (%d)\n", - clk); - return STATUS_FAIL; - } - - retval = rtsx_write_register(chip, CLK_CTL, 0xFF, CLK_LOW_FREQ); - if (retval) - return retval; - if (sd_vpclk_phase_reset) { - retval = rtsx_write_register(chip, SD_VPCLK0_CTL, - PHASE_NOT_RESET, 0); - if (retval) - return retval; - retval = rtsx_write_register(chip, SD_VPCLK1_CTL, - PHASE_NOT_RESET, 0); - if (retval) - return retval; - } - retval = rtsx_write_register(chip, CLK_DIV, 0xFF, - (div << 4) | mcu_cnt); - if (retval) - return retval; - retval = rtsx_write_register(chip, CLK_SEL, 0xFF, sel); - if (retval) - return retval; - - if (sd_vpclk_phase_reset) { - udelay(200); - retval = rtsx_write_register(chip, SD_VPCLK0_CTL, - PHASE_NOT_RESET, PHASE_NOT_RESET); - if (retval) - return retval; - retval = rtsx_write_register(chip, SD_VPCLK1_CTL, - PHASE_NOT_RESET, PHASE_NOT_RESET); - if (retval) - return retval; - udelay(200); - } - retval = rtsx_write_register(chip, CLK_CTL, 0xFF, 0); - if (retval) - return retval; - - chip->cur_clk = clk; - - return STATUS_SUCCESS; -} - -void trans_dma_enable(enum dma_data_direction dir, struct rtsx_chip *chip, - u32 byte_cnt, u8 pack_size) -{ - if (pack_size > DMA_1024) - pack_size = DMA_512; - - rtsx_add_cmd(chip, WRITE_REG_CMD, IRQSTAT0, DMA_DONE_INT, DMA_DONE_INT); - - rtsx_add_cmd(chip, WRITE_REG_CMD, DMATC3, 0xFF, (u8)(byte_cnt >> 24)); - rtsx_add_cmd(chip, WRITE_REG_CMD, DMATC2, 0xFF, (u8)(byte_cnt >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, DMATC1, 0xFF, (u8)(byte_cnt >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, DMATC0, 0xFF, (u8)byte_cnt); - - if (dir == DMA_FROM_DEVICE) { - rtsx_add_cmd(chip, WRITE_REG_CMD, DMACTL, - 0x03 | DMA_PACK_SIZE_MASK, - DMA_DIR_FROM_CARD | DMA_EN | pack_size); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, DMACTL, - 0x03 | DMA_PACK_SIZE_MASK, - DMA_DIR_TO_CARD | DMA_EN | pack_size); - } - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); -} - -int enable_card_clock(struct rtsx_chip *chip, u8 card) -{ - int retval; - u8 clk_en = 0; - - if (card & XD_CARD) - clk_en |= XD_CLK_EN; - if (card & SD_CARD) - clk_en |= SD_CLK_EN; - if (card & MS_CARD) - clk_en |= MS_CLK_EN; - - retval = rtsx_write_register(chip, CARD_CLK_EN, clk_en, clk_en); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -int disable_card_clock(struct rtsx_chip *chip, u8 card) -{ - int retval; - u8 clk_en = 0; - - if (card & XD_CARD) - clk_en |= XD_CLK_EN; - if (card & SD_CARD) - clk_en |= SD_CLK_EN; - if (card & MS_CARD) - clk_en |= MS_CLK_EN; - - retval = rtsx_write_register(chip, CARD_CLK_EN, clk_en, 0); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -int card_power_on(struct rtsx_chip *chip, u8 card) -{ - int retval; - u8 mask, val1, val2; - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN) && card == MS_CARD) { - mask = MS_POWER_MASK; - val1 = MS_PARTIAL_POWER_ON; - val2 = MS_POWER_ON; - } else { - mask = SD_POWER_MASK; - val1 = SD_PARTIAL_POWER_ON; - val2 = SD_POWER_ON; - } - - rtsx_init_cmd(chip); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, mask, val1); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - udelay(chip->pmos_pwr_on_interval); - - rtsx_init_cmd(chip); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, mask, val2); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -int card_power_off(struct rtsx_chip *chip, u8 card) -{ - int retval; - u8 mask, val; - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN) && card == MS_CARD) { - mask = MS_POWER_MASK; - val = MS_POWER_OFF; - } else { - mask = SD_POWER_MASK; - val = SD_POWER_OFF; - } - - retval = rtsx_write_register(chip, CARD_PWR_CTL, mask, val); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 sec_addr, u16 sec_cnt) -{ - int retval; - unsigned int lun = SCSI_LUN(srb); - int i; - - if (!chip->rw_card[lun]) - return STATUS_FAIL; - - for (i = 0; i < 3; i++) { - chip->rw_need_retry = 0; - - retval = chip->rw_card[lun](srb, chip, sec_addr, sec_cnt); - if (retval != STATUS_SUCCESS) { - if (rtsx_check_chip_exist(chip) != STATUS_SUCCESS) { - rtsx_release_chip(chip); - return STATUS_FAIL; - } - if (detect_card_cd(chip, chip->cur_card) != - STATUS_SUCCESS) { - return STATUS_FAIL; - } - - if (!chip->rw_need_retry) { - dev_dbg(rtsx_dev(chip), "RW fail, but no need to retry\n"); - break; - } - } else { - chip->rw_need_retry = 0; - break; - } - - dev_dbg(rtsx_dev(chip), "Retry RW, (i = %d)\n", i); - } - - return retval; -} - -int card_share_mode(struct rtsx_chip *chip, int card) -{ - int retval; - u8 mask, value; - - if (CHECK_PID(chip, 0x5208)) { - mask = CARD_SHARE_MASK; - if (card == SD_CARD) - value = CARD_SHARE_48_SD; - else if (card == MS_CARD) - value = CARD_SHARE_48_MS; - else if (card == XD_CARD) - value = CARD_SHARE_48_XD; - else - return STATUS_FAIL; - - } else if (CHECK_PID(chip, 0x5288)) { - mask = 0x03; - if (card == SD_CARD) - value = CARD_SHARE_BAROSSA_SD; - else if (card == MS_CARD) - value = CARD_SHARE_BAROSSA_MS; - else if (card == XD_CARD) - value = CARD_SHARE_BAROSSA_XD; - else - return STATUS_FAIL; - - } else { - return STATUS_FAIL; - } - - retval = rtsx_write_register(chip, CARD_SHARE_MODE, mask, value); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -int select_card(struct rtsx_chip *chip, int card) -{ - int retval; - - if (chip->cur_card != card) { - u8 mod; - - if (card == SD_CARD) - mod = SD_MOD_SEL; - else if (card == MS_CARD) - mod = MS_MOD_SEL; - else if (card == XD_CARD) - mod = XD_MOD_SEL; - else if (card == SPI_CARD) - mod = SPI_MOD_SEL; - else - return STATUS_FAIL; - - retval = rtsx_write_register(chip, CARD_SELECT, 0x07, mod); - if (retval) - return retval; - chip->cur_card = card; - - retval = card_share_mode(chip, card); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -void toggle_gpio(struct rtsx_chip *chip, u8 gpio) -{ - u8 temp_reg; - - rtsx_read_register(chip, CARD_GPIO, &temp_reg); - temp_reg ^= (0x01 << gpio); - rtsx_write_register(chip, CARD_GPIO, 0xFF, temp_reg); -} - -void turn_on_led(struct rtsx_chip *chip, u8 gpio) -{ - if (CHECK_PID(chip, 0x5288)) - rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), - (u8)(1 << gpio)); - else - rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), 0); -} - -void turn_off_led(struct rtsx_chip *chip, u8 gpio) -{ - if (CHECK_PID(chip, 0x5288)) - rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), 0); - else - rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), - (u8)(1 << gpio)); -} - -int detect_card_cd(struct rtsx_chip *chip, int card) -{ - u32 card_cd, status; - - if (card == SD_CARD) { - card_cd = SD_EXIST; - } else if (card == MS_CARD) { - card_cd = MS_EXIST; - } else if (card == XD_CARD) { - card_cd = XD_EXIST; - } else { - dev_dbg(rtsx_dev(chip), "Wrong card type: 0x%x\n", card); - return STATUS_FAIL; - } - - status = rtsx_readl(chip, RTSX_BIPR); - if (!(status & card_cd)) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -int check_card_exist(struct rtsx_chip *chip, unsigned int lun) -{ - if (chip->card_exist & chip->lun2card[lun]) - return 1; - - return 0; -} - -int check_card_ready(struct rtsx_chip *chip, unsigned int lun) -{ - if (chip->card_ready & chip->lun2card[lun]) - return 1; - - return 0; -} - -int check_card_wp(struct rtsx_chip *chip, unsigned int lun) -{ - if (chip->card_wp & chip->lun2card[lun]) - return 1; - - return 0; -} - -u8 get_lun_card(struct rtsx_chip *chip, unsigned int lun) -{ - if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD) - return (u8)XD_CARD; - else if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD) - return (u8)SD_CARD; - else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD) - return (u8)MS_CARD; - - return 0; -} - -void eject_card(struct rtsx_chip *chip, unsigned int lun) -{ - do_remaining_work(chip); - - if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD) { - release_sd_card(chip); - chip->card_ejected |= SD_CARD; - chip->card_ready &= ~SD_CARD; - chip->capacity[lun] = 0; - } else if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD) { - release_xd_card(chip); - chip->card_ejected |= XD_CARD; - chip->card_ready &= ~XD_CARD; - chip->capacity[lun] = 0; - } else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD) { - release_ms_card(chip); - chip->card_ejected |= MS_CARD; - chip->card_ready &= ~MS_CARD; - chip->capacity[lun] = 0; - } -} diff --git a/drivers/staging/rts5208/rtsx_card.h b/drivers/staging/rts5208/rtsx_card.h deleted file mode 100644 index 39727371cd7adf..00000000000000 --- a/drivers/staging/rts5208/rtsx_card.h +++ /dev/null @@ -1,1087 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_CARD_H -#define __REALTEK_RTSX_CARD_H - -#include "rtsx.h" -#include "rtsx_chip.h" -#include "rtsx_transport.h" -#include "sd.h" - -#define SSC_POWER_DOWN 0x01 -#define SD_OC_POWER_DOWN 0x02 -#define MS_OC_POWER_DOWN 0x04 -#define ALL_POWER_DOWN 0x07 -#define OC_POWER_DOWN 0x06 - -#define PMOS_STRG_MASK 0x10 -#define PMOS_STRG_800mA 0x10 -#define PMOS_STRG_400mA 0x00 - -#define POWER_OFF 0x03 -#define PARTIAL_POWER_ON 0x01 -#define POWER_ON 0x00 - -#define MS_POWER_OFF 0x0C -#define MS_PARTIAL_POWER_ON 0x04 -#define MS_POWER_ON 0x00 -#define MS_POWER_MASK 0x0C - -#define SD_POWER_OFF 0x03 -#define SD_PARTIAL_POWER_ON 0x01 -#define SD_POWER_ON 0x00 -#define SD_POWER_MASK 0x03 - -#define XD_OUTPUT_EN 0x02 -#define SD_OUTPUT_EN 0x04 -#define MS_OUTPUT_EN 0x08 -#define SPI_OUTPUT_EN 0x10 - -#define CLK_LOW_FREQ 0x01 - -#define CLK_DIV_1 0x01 -#define CLK_DIV_2 0x02 -#define CLK_DIV_4 0x03 -#define CLK_DIV_8 0x04 - -#define SSC_80 0 -#define SSC_100 1 -#define SSC_120 2 -#define SSC_150 3 -#define SSC_200 4 - -#define XD_CLK_EN 0x02 -#define SD_CLK_EN 0x04 -#define MS_CLK_EN 0x08 -#define SPI_CLK_EN 0x10 - -#define XD_MOD_SEL 1 -#define SD_MOD_SEL 2 -#define MS_MOD_SEL 3 -#define SPI_MOD_SEL 4 - -#define CHANGE_CLK 0x01 - -#define SD_CRC7_ERR 0x80 -#define SD_CRC16_ERR 0x40 -#define SD_CRC_WRITE_ERR 0x20 -#define SD_CRC_WRITE_ERR_MASK 0x1C -#define GET_CRC_TIME_OUT 0x02 -#define SD_TUNING_COMPARE_ERR 0x01 - -#define SD_RSP_80CLK_TIMEOUT 0x01 - -#define SD_CLK_TOGGLE_EN 0x80 -#define SD_CLK_FORCE_STOP 0x40 -#define SD_DAT3_STATUS 0x10 -#define SD_DAT2_STATUS 0x08 -#define SD_DAT1_STATUS 0x04 -#define SD_DAT0_STATUS 0x02 -#define SD_CMD_STATUS 0x01 - -#define SD_IO_USING_1V8 0x80 -#define SD_IO_USING_3V3 0x7F -#define TYPE_A_DRIVING 0x00 -#define TYPE_B_DRIVING 0x01 -#define TYPE_C_DRIVING 0x02 -#define TYPE_D_DRIVING 0x03 - -#define DDR_FIX_RX_DAT 0x00 -#define DDR_VAR_RX_DAT 0x80 -#define DDR_FIX_RX_DAT_EDGE 0x00 -#define DDR_FIX_RX_DAT_14_DELAY 0x40 -#define DDR_FIX_RX_CMD 0x00 -#define DDR_VAR_RX_CMD 0x20 -#define DDR_FIX_RX_CMD_POS_EDGE 0x00 -#define DDR_FIX_RX_CMD_14_DELAY 0x10 -#define SD20_RX_POS_EDGE 0x00 -#define SD20_RX_14_DELAY 0x08 -#define SD20_RX_SEL_MASK 0x08 - -#define DDR_FIX_TX_CMD_DAT 0x00 -#define DDR_VAR_TX_CMD_DAT 0x80 -#define DDR_FIX_TX_DAT_14_TSU 0x00 -#define DDR_FIX_TX_DAT_12_TSU 0x40 -#define DDR_FIX_TX_CMD_NEG_EDGE 0x00 -#define DDR_FIX_TX_CMD_14_AHEAD 0x20 -#define SD20_TX_NEG_EDGE 0x00 -#define SD20_TX_14_AHEAD 0x10 -#define SD20_TX_SEL_MASK 0x10 -#define DDR_VAR_SDCLK_POL_SWAP 0x01 - -#define SD_TRANSFER_START 0x80 -#define SD_TRANSFER_END 0x40 -#define SD_STAT_IDLE 0x20 -#define SD_TRANSFER_ERR 0x10 -#define SD_TM_NORMAL_WRITE 0x00 -#define SD_TM_AUTO_WRITE_3 0x01 -#define SD_TM_AUTO_WRITE_4 0x02 -#define SD_TM_AUTO_READ_3 0x05 -#define SD_TM_AUTO_READ_4 0x06 -#define SD_TM_CMD_RSP 0x08 -#define SD_TM_AUTO_WRITE_1 0x09 -#define SD_TM_AUTO_WRITE_2 0x0A -#define SD_TM_NORMAL_READ 0x0C -#define SD_TM_AUTO_READ_1 0x0D -#define SD_TM_AUTO_READ_2 0x0E -#define SD_TM_AUTO_TUNING 0x0F - -#define PHASE_CHANGE 0x80 -#define PHASE_NOT_RESET 0x40 - -#define DCMPS_CHANGE 0x80 -#define DCMPS_CHANGE_DONE 0x40 -#define DCMPS_ERROR 0x20 -#define DCMPS_CURRENT_PHASE 0x1F - -#define SD_CLK_DIVIDE_0 0x00 -#define SD_CLK_DIVIDE_256 0xC0 -#define SD_CLK_DIVIDE_128 0x80 -#define SD_BUS_WIDTH_1 0x00 -#define SD_BUS_WIDTH_4 0x01 -#define SD_BUS_WIDTH_8 0x02 -#define SD_ASYNC_FIFO_NOT_RST 0x10 -#define SD_20_MODE 0x00 -#define SD_DDR_MODE 0x04 -#define SD_30_MODE 0x08 - -#define SD_CLK_DIVIDE_MASK 0xC0 - -#define SD_CMD_IDLE 0x80 - -#define SD_DATA_IDLE 0x80 - -#define DCM_RESET 0x08 -#define DCM_LOCKED 0x04 -#define DCM_208M 0x00 -#define DCM_TX 0x01 -#define DCM_RX 0x02 - -#define DRP_START 0x80 -#define DRP_DONE 0x40 - -#define DRP_WRITE 0x80 -#define DRP_READ 0x00 -#define DCM_WRITE_ADDRESS_50 0x50 -#define DCM_WRITE_ADDRESS_51 0x51 -#define DCM_READ_ADDRESS_00 0x00 -#define DCM_READ_ADDRESS_51 0x51 - -#define SD_CALCULATE_CRC7 0x00 -#define SD_NO_CALCULATE_CRC7 0x80 -#define SD_CHECK_CRC16 0x00 -#define SD_NO_CHECK_CRC16 0x40 -#define SD_NO_CHECK_WAIT_CRC_TO 0x20 -#define SD_WAIT_BUSY_END 0x08 -#define SD_NO_WAIT_BUSY_END 0x00 -#define SD_CHECK_CRC7 0x00 -#define SD_NO_CHECK_CRC7 0x04 -#define SD_RSP_LEN_0 0x00 -#define SD_RSP_LEN_6 0x01 -#define SD_RSP_LEN_17 0x02 -#define SD_RSP_TYPE_R0 0x04 -#define SD_RSP_TYPE_R1 0x01 -#define SD_RSP_TYPE_R1b 0x09 -#define SD_RSP_TYPE_R2 0x02 -#define SD_RSP_TYPE_R3 0x05 -#define SD_RSP_TYPE_R4 0x05 -#define SD_RSP_TYPE_R5 0x01 -#define SD_RSP_TYPE_R6 0x01 -#define SD_RSP_TYPE_R7 0x01 - -#define SD_RSP_80CLK_TIMEOUT_EN 0x01 - -#define SAMPLE_TIME_RISING 0x00 -#define SAMPLE_TIME_FALLING 0x80 -#define PUSH_TIME_DEFAULT 0x00 -#define PUSH_TIME_ODD 0x40 -#define NO_EXTEND_TOGGLE 0x00 -#define EXTEND_TOGGLE_CHK 0x20 -#define MS_BUS_WIDTH_1 0x00 -#define MS_BUS_WIDTH_4 0x10 -#define MS_BUS_WIDTH_8 0x18 -#define MS_2K_SECTOR_MODE 0x04 -#define MS_512_SECTOR_MODE 0x00 -#define MS_TOGGLE_TIMEOUT_EN 0x00 -#define MS_TOGGLE_TIMEOUT_DISEN 0x01 -#define MS_NO_CHECK_INT 0x02 - -#define WAIT_INT 0x80 -#define NO_WAIT_INT 0x00 -#define NO_AUTO_READ_INT_REG 0x00 -#define AUTO_READ_INT_REG 0x40 -#define MS_CRC16_ERR 0x20 -#define MS_RDY_TIMEOUT 0x10 -#define MS_INT_CMDNK 0x08 -#define MS_INT_BREQ 0x04 -#define MS_INT_ERR 0x02 -#define MS_INT_CED 0x01 - -#define MS_TRANSFER_START 0x80 -#define MS_TRANSFER_END 0x40 -#define MS_TRANSFER_ERR 0x20 -#define MS_BS_STATE 0x10 -#define MS_TM_READ_BYTES 0x00 -#define MS_TM_NORMAL_READ 0x01 -#define MS_TM_WRITE_BYTES 0x04 -#define MS_TM_NORMAL_WRITE 0x05 -#define MS_TM_AUTO_READ 0x08 -#define MS_TM_AUTO_WRITE 0x0C - -#define CARD_SHARE_MASK 0x0F -#define CARD_SHARE_MULTI_LUN 0x00 -#define CARD_SHARE_NORMAL 0x00 -#define CARD_SHARE_48_XD 0x02 -#define CARD_SHARE_48_SD 0x04 -#define CARD_SHARE_48_MS 0x08 -#define CARD_SHARE_BAROSSA_XD 0x00 -#define CARD_SHARE_BAROSSA_SD 0x01 -#define CARD_SHARE_BAROSSA_MS 0x02 - -#define MS_DRIVE_8 0x00 -#define MS_DRIVE_4 0x40 -#define MS_DRIVE_12 0x80 -#define SD_DRIVE_8 0x00 -#define SD_DRIVE_4 0x10 -#define SD_DRIVE_12 0x20 -#define XD_DRIVE_8 0x00 -#define XD_DRIVE_4 0x04 -#define XD_DRIVE_12 0x08 - -#define SPI_STOP 0x01 -#define XD_STOP 0x02 -#define SD_STOP 0x04 -#define MS_STOP 0x08 -#define SPI_CLR_ERR 0x10 -#define XD_CLR_ERR 0x20 -#define SD_CLR_ERR 0x40 -#define MS_CLR_ERR 0x80 - -#define CRC_FIX_CLK (0x00 << 0) -#define CRC_VAR_CLK0 (0x01 << 0) -#define CRC_VAR_CLK1 (0x02 << 0) -#define SD30_FIX_CLK (0x00 << 2) -#define SD30_VAR_CLK0 (0x01 << 2) -#define SD30_VAR_CLK1 (0x02 << 2) -#define SAMPLE_FIX_CLK (0x00 << 4) -#define SAMPLE_VAR_CLK0 (0x01 << 4) -#define SAMPLE_VAR_CLK1 (0x02 << 4) - -#define SDIO_VER_20 0x80 -#define SDIO_VER_10 0x00 -#define SDIO_VER_CHG 0x40 -#define SDIO_BUS_AUTO_SWITCH 0x10 - -#define PINGPONG_BUFFER 0x01 -#define RING_BUFFER 0x00 - -#define RB_FLUSH 0x80 - -#define DMA_DONE_INT_EN 0x80 -#define SUSPEND_INT_EN 0x40 -#define LINK_RDY_INT_EN 0x20 -#define LINK_DOWN_INT_EN 0x10 - -#define DMA_DONE_INT 0x80 -#define SUSPEND_INT 0x40 -#define LINK_RDY_INT 0x20 -#define LINK_DOWN_INT 0x10 - -#define MRD_ERR_INT_EN 0x40 -#define MWR_ERR_INT_EN 0x20 -#define SCSI_CMD_INT_EN 0x10 -#define TLP_RCV_INT_EN 0x08 -#define TLP_TRSMT_INT_EN 0x04 -#define MRD_COMPLETE_INT_EN 0x02 -#define MWR_COMPLETE_INT_EN 0x01 - -#define MRD_ERR_INT 0x40 -#define MWR_ERR_INT 0x20 -#define SCSI_CMD_INT 0x10 -#define TLP_RX_INT 0x08 -#define TLP_TX_INT 0x04 -#define MRD_COMPLETE_INT 0x02 -#define MWR_COMPLETE_INT 0x01 - -#define MSG_RX_INT_EN 0x08 -#define MRD_RX_INT_EN 0x04 -#define MWR_RX_INT_EN 0x02 -#define CPLD_RX_INT_EN 0x01 - -#define MSG_RX_INT 0x08 -#define MRD_RX_INT 0x04 -#define MWR_RX_INT 0x02 -#define CPLD_RX_INT 0x01 - -#define MSG_TX_INT_EN 0x08 -#define MRD_TX_INT_EN 0x04 -#define MWR_TX_INT_EN 0x02 -#define CPLD_TX_INT_EN 0x01 - -#define MSG_TX_INT 0x08 -#define MRD_TX_INT 0x04 -#define MWR_TX_INT 0x02 -#define CPLD_TX_INT 0x01 - -#define DMA_RST 0x80 -#define DMA_BUSY 0x04 -#define DMA_DIR_TO_CARD 0x00 -#define DMA_DIR_FROM_CARD 0x02 -#define DMA_EN 0x01 -#define DMA_128 (0 << 4) -#define DMA_256 (1 << 4) -#define DMA_512 (2 << 4) -#define DMA_1024 (3 << 4) -#define DMA_PACK_SIZE_MASK 0x30 - -#define XD_PWR_OFF_DELAY0 0x00 -#define XD_PWR_OFF_DELAY1 0x02 -#define XD_PWR_OFF_DELAY2 0x04 -#define XD_PWR_OFF_DELAY3 0x06 -#define XD_AUTO_PWR_OFF_EN 0xF7 -#define XD_NO_AUTO_PWR_OFF 0x08 - -#define XD_TIME_RWN_1 0x00 -#define XD_TIME_RWN_STEP 0x20 -#define XD_TIME_RW_1 0x00 -#define XD_TIME_RW_STEP 0x04 -#define XD_TIME_SETUP_1 0x00 -#define XD_TIME_SETUP_STEP 0x01 - -#define XD_ECC2_UNCORRECTABLE 0x80 -#define XD_ECC2_ERROR 0x40 -#define XD_ECC1_UNCORRECTABLE 0x20 -#define XD_ECC1_ERROR 0x10 -#define XD_RDY 0x04 -#define XD_CE_EN 0xFD -#define XD_CE_DISEN 0x02 -#define XD_WP_EN 0xFE -#define XD_WP_DISEN 0x01 - -#define XD_TRANSFER_START 0x80 -#define XD_TRANSFER_END 0x40 -#define XD_PPB_EMPTY 0x20 -#define XD_RESET 0x00 -#define XD_ERASE 0x01 -#define XD_READ_STATUS 0x02 -#define XD_READ_ID 0x03 -#define XD_READ_REDUNDANT 0x04 -#define XD_READ_PAGES 0x05 -#define XD_SET_CMD 0x06 -#define XD_NORMAL_READ 0x07 -#define XD_WRITE_PAGES 0x08 -#define XD_NORMAL_WRITE 0x09 -#define XD_WRITE_REDUNDANT 0x0A -#define XD_SET_ADDR 0x0B - -#define XD_PPB_TO_SIE 0x80 -#define XD_TO_PPB_ONLY 0x00 -#define XD_BA_TRANSFORM 0x40 -#define XD_BA_NO_TRANSFORM 0x00 -#define XD_NO_CALC_ECC 0x20 -#define XD_CALC_ECC 0x00 -#define XD_IGNORE_ECC 0x10 -#define XD_CHECK_ECC 0x00 -#define XD_DIRECT_TO_RB 0x08 -#define XD_ADDR_LENGTH_0 0x00 -#define XD_ADDR_LENGTH_1 0x01 -#define XD_ADDR_LENGTH_2 0x02 -#define XD_ADDR_LENGTH_3 0x03 -#define XD_ADDR_LENGTH_4 0x04 - -#define XD_GPG 0xFF -#define XD_BPG 0x00 - -#define XD_GBLK 0xFF -#define XD_LATER_BBLK 0xF0 - -#define XD_ECC2_ALL1 0x80 -#define XD_ECC1_ALL1 0x40 -#define XD_BA2_ALL0 0x20 -#define XD_BA1_ALL0 0x10 -#define XD_BA1_BA2_EQL 0x04 -#define XD_BA2_VALID 0x02 -#define XD_BA1_VALID 0x01 - -#define XD_PGSTS_ZEROBIT_OVER4 0x00 -#define XD_PGSTS_NOT_FF 0x02 -#define XD_AUTO_CHK_DATA_STATUS 0x01 - -#define RSTB_MODE_DETECT 0x80 -#define MODE_OUT_VLD 0x40 -#define MODE_OUT_0_NONE 0x00 -#define MODE_OUT_10_NONE 0x04 -#define MODE_OUT_10_47 0x05 -#define MODE_OUT_10_180 0x06 -#define MODE_OUT_10_680 0x07 -#define MODE_OUT_16_NONE 0x08 -#define MODE_OUT_16_47 0x09 -#define MODE_OUT_16_180 0x0A -#define MODE_OUT_16_680 0x0B -#define MODE_OUT_NONE_NONE 0x0C -#define MODE_OUT_NONE_47 0x0D -#define MODE_OUT_NONE_180 0x0E -#define MODE_OUT_NONE_680 0x0F - -#define CARD_OC_INT_EN 0x20 -#define CARD_DETECT_EN 0x08 - -#define MS_DETECT_EN 0x80 -#define MS_OCP_INT_EN 0x40 -#define MS_OCP_INT_CLR 0x20 -#define MS_OC_CLR 0x10 -#define SD_DETECT_EN 0x08 -#define SD_OCP_INT_EN 0x04 -#define SD_OCP_INT_CLR 0x02 -#define SD_OC_CLR 0x01 - -#define CARD_OCP_DETECT 0x80 -#define CARD_OC_NOW 0x08 -#define CARD_OC_EVER 0x04 - -#define MS_OCP_DETECT 0x80 -#define MS_OC_NOW 0x40 -#define MS_OC_EVER 0x20 -#define SD_OCP_DETECT 0x08 -#define SD_OC_NOW 0x04 -#define SD_OC_EVER 0x02 - -#define CARD_OC_INT_CLR 0x08 -#define CARD_OC_CLR 0x02 - -#define SD_OCP_GLITCH_MASK 0x07 -#define SD_OCP_GLITCH_6_4 0x00 -#define SD_OCP_GLITCH_64 0x01 -#define SD_OCP_GLITCH_640 0x02 -#define SD_OCP_GLITCH_1000 0x03 -#define SD_OCP_GLITCH_2000 0x04 -#define SD_OCP_GLITCH_4000 0x05 -#define SD_OCP_GLITCH_8000 0x06 -#define SD_OCP_GLITCH_10000 0x07 - -#define MS_OCP_GLITCH_MASK 0x70 -#define MS_OCP_GLITCH_6_4 (0x00 << 4) -#define MS_OCP_GLITCH_64 (0x01 << 4) -#define MS_OCP_GLITCH_640 (0x02 << 4) -#define MS_OCP_GLITCH_1000 (0x03 << 4) -#define MS_OCP_GLITCH_2000 (0x04 << 4) -#define MS_OCP_GLITCH_4000 (0x05 << 4) -#define MS_OCP_GLITCH_8000 (0x06 << 4) -#define MS_OCP_GLITCH_10000 (0x07 << 4) - -#define OCP_TIME_60 0x00 -#define OCP_TIME_100 (0x01 << 3) -#define OCP_TIME_200 (0x02 << 3) -#define OCP_TIME_400 (0x03 << 3) -#define OCP_TIME_600 (0x04 << 3) -#define OCP_TIME_800 (0x05 << 3) -#define OCP_TIME_1100 (0x06 << 3) -#define OCP_TIME_MASK 0x38 - -#define MS_OCP_TIME_60 0x00 -#define MS_OCP_TIME_100 (0x01 << 4) -#define MS_OCP_TIME_200 (0x02 << 4) -#define MS_OCP_TIME_400 (0x03 << 4) -#define MS_OCP_TIME_600 (0x04 << 4) -#define MS_OCP_TIME_800 (0x05 << 4) -#define MS_OCP_TIME_1100 (0x06 << 4) -#define MS_OCP_TIME_MASK 0x70 - -#define SD_OCP_TIME_60 0x00 -#define SD_OCP_TIME_100 0x01 -#define SD_OCP_TIME_200 0x02 -#define SD_OCP_TIME_400 0x03 -#define SD_OCP_TIME_600 0x04 -#define SD_OCP_TIME_800 0x05 -#define SD_OCP_TIME_1100 0x06 -#define SD_OCP_TIME_MASK 0x07 - -#define OCP_THD_315_417 0x00 -#define OCP_THD_283_783 (0x01 << 6) -#define OCP_THD_244_946 (0x02 << 6) -#define OCP_THD_191_1080 (0x03 << 6) -#define OCP_THD_MASK 0xC0 - -#define MS_OCP_THD_450 0x00 -#define MS_OCP_THD_550 (0x01 << 4) -#define MS_OCP_THD_650 (0x02 << 4) -#define MS_OCP_THD_750 (0x03 << 4) -#define MS_OCP_THD_850 (0x04 << 4) -#define MS_OCP_THD_950 (0x05 << 4) -#define MS_OCP_THD_1050 (0x06 << 4) -#define MS_OCP_THD_1150 (0x07 << 4) -#define MS_OCP_THD_MASK 0x70 - -#define SD_OCP_THD_450 0x00 -#define SD_OCP_THD_550 0x01 -#define SD_OCP_THD_650 0x02 -#define SD_OCP_THD_750 0x03 -#define SD_OCP_THD_850 0x04 -#define SD_OCP_THD_950 0x05 -#define SD_OCP_THD_1050 0x06 -#define SD_OCP_THD_1150 0x07 -#define SD_OCP_THD_MASK 0x07 - -#define FPGA_MS_PULL_CTL_EN 0xEF -#define FPGA_SD_PULL_CTL_EN 0xF7 -#define FPGA_XD_PULL_CTL_EN1 0xFE -#define FPGA_XD_PULL_CTL_EN2 0xFD -#define FPGA_XD_PULL_CTL_EN3 0xFB - -#define FPGA_MS_PULL_CTL_BIT 0x10 -#define FPGA_SD_PULL_CTL_BIT 0x08 - -#define BLINK_EN 0x08 -#define LED_GPIO0 (0 << 4) -#define LED_GPIO1 (1 << 4) -#define LED_GPIO2 (2 << 4) - -#define SDIO_BUS_CTRL 0x01 -#define SDIO_CD_CTRL 0x02 - -#define SSC_RSTB 0x80 -#define SSC_8X_EN 0x40 -#define SSC_FIX_FRAC 0x20 -#define SSC_SEL_1M 0x00 -#define SSC_SEL_2M 0x08 -#define SSC_SEL_4M 0x10 -#define SSC_SEL_8M 0x18 - -#define SSC_DEPTH_MASK 0x07 -#define SSC_DEPTH_DISALBE 0x00 -#define SSC_DEPTH_4M 0x01 -#define SSC_DEPTH_2M 0x02 -#define SSC_DEPTH_1M 0x03 -#define SSC_DEPTH_512K 0x04 -#define SSC_DEPTH_256K 0x05 -#define SSC_DEPTH_128K 0x06 -#define SSC_DEPTH_64K 0x07 - -#define XD_D3_NP 0x00 -#define XD_D3_PD (0x01 << 6) -#define XD_D3_PU (0x02 << 6) -#define XD_D2_NP 0x00 -#define XD_D2_PD (0x01 << 4) -#define XD_D2_PU (0x02 << 4) -#define XD_D1_NP 0x00 -#define XD_D1_PD (0x01 << 2) -#define XD_D1_PU (0x02 << 2) -#define XD_D0_NP 0x00 -#define XD_D0_PD 0x01 -#define XD_D0_PU 0x02 - -#define SD_D7_NP 0x00 -#define SD_D7_PD (0x01 << 4) -#define SD_DAT7_PU (0x02 << 4) -#define SD_CLK_NP 0x00 -#define SD_CLK_PD (0x01 << 2) -#define SD_CLK_PU (0x02 << 2) -#define SD_D5_NP 0x00 -#define SD_D5_PD 0x01 -#define SD_D5_PU 0x02 - -#define MS_D1_NP 0x00 -#define MS_D1_PD (0x01 << 6) -#define MS_D1_PU (0x02 << 6) -#define MS_D2_NP 0x00 -#define MS_D2_PD (0x01 << 4) -#define MS_D2_PU (0x02 << 4) -#define MS_CLK_NP 0x00 -#define MS_CLK_PD (0x01 << 2) -#define MS_CLK_PU (0x02 << 2) -#define MS_D6_NP 0x00 -#define MS_D6_PD 0x01 -#define MS_D6_PU 0x02 - -#define XD_D7_NP 0x00 -#define XD_D7_PD (0x01 << 6) -#define XD_D7_PU (0x02 << 6) -#define XD_D6_NP 0x00 -#define XD_D6_PD (0x01 << 4) -#define XD_D6_PU (0x02 << 4) -#define XD_D5_NP 0x00 -#define XD_D5_PD (0x01 << 2) -#define XD_D5_PU (0x02 << 2) -#define XD_D4_NP 0x00 -#define XD_D4_PD 0x01 -#define XD_D4_PU 0x02 - -#define SD_D6_NP 0x00 -#define SD_D6_PD (0x01 << 6) -#define SD_D6_PU (0x02 << 6) -#define SD_D0_NP 0x00 -#define SD_D0_PD (0x01 << 4) -#define SD_D0_PU (0x02 << 4) -#define SD_D1_NP 0x00 -#define SD_D1_PD 0x01 -#define SD_D1_PU 0x02 - -#define MS_D3_NP 0x00 -#define MS_D3_PD (0x01 << 6) -#define MS_D3_PU (0x02 << 6) -#define MS_D0_NP 0x00 -#define MS_D0_PD (0x01 << 4) -#define MS_D0_PU (0x02 << 4) -#define MS_BS_NP 0x00 -#define MS_BS_PD (0x01 << 2) -#define MS_BS_PU (0x02 << 2) - -#define XD_WP_NP 0x00 -#define XD_WP_PD (0x01 << 6) -#define XD_WP_PU (0x02 << 6) -#define XD_CE_NP 0x00 -#define XD_CE_PD (0x01 << 3) -#define XD_CE_PU (0x02 << 3) -#define XD_CLE_NP 0x00 -#define XD_CLE_PD (0x01 << 1) -#define XD_CLE_PU (0x02 << 1) -#define XD_CD_PD 0x00 -#define XD_CD_PU 0x01 - -#define SD_D4_NP 0x00 -#define SD_D4_PD (0x01 << 6) -#define SD_D4_PU (0x02 << 6) - -#define MS_D7_NP 0x00 -#define MS_D7_PD (0x01 << 6) -#define MS_D7_PU (0x02 << 6) - -#define XD_RDY_NP 0x00 -#define XD_RDY_PD (0x01 << 6) -#define XD_RDY_PU (0x02 << 6) -#define XD_WE_NP 0x00 -#define XD_WE_PD (0x01 << 4) -#define XD_WE_PU (0x02 << 4) -#define XD_RE_NP 0x00 -#define XD_RE_PD (0x01 << 2) -#define XD_RE_PU (0x02 << 2) -#define XD_ALE_NP 0x00 -#define XD_ALE_PD 0x01 -#define XD_ALE_PU 0x02 - -#define SD_D3_NP 0x00 -#define SD_D3_PD (0x01 << 4) -#define SD_D3_PU (0x02 << 4) -#define SD_D2_NP 0x00 -#define SD_D2_PD (0x01 << 2) -#define SD_D2_PU (0x02 << 2) - -#define MS_INS_PD 0x00 -#define MS_INS_PU (0x01 << 7) -#define SD_WP_NP 0x00 -#define SD_WP_PD (0x01 << 5) -#define SD_WP_PU (0x02 << 5) -#define SD_CD_PD 0x00 -#define SD_CD_PU (0x01 << 4) -#define SD_CMD_NP 0x00 -#define SD_CMD_PD (0x01 << 2) -#define SD_CMD_PU (0x02 << 2) - -#define MS_D5_NP 0x00 -#define MS_D5_PD (0x01 << 2) -#define MS_D5_PU (0x02 << 2) -#define MS_D4_NP 0x00 -#define MS_D4_PD 0x01 -#define MS_D4_PU 0x02 - -#define FORCE_PM_CLOCK 0x10 -#define EN_CLOCK_PM 0x01 - -#define HOST_ENTER_S3 0x02 -#define HOST_ENTER_S1 0x01 - -#define AUX_PWR_DETECTED 0x01 - -#define PHY_DEBUG_MODE 0x01 - -#define SPI_COMMAND_BIT_8 0xE0 -#define SPI_ADDRESS_BIT_24 0x17 -#define SPI_ADDRESS_BIT_32 0x1F - -#define SPI_TRANSFER0_START 0x80 -#define SPI_TRANSFER0_END 0x40 -#define SPI_C_MODE0 0x00 -#define SPI_CA_MODE0 0x01 -#define SPI_CDO_MODE0 0x02 -#define SPI_CDI_MODE0 0x03 -#define SPI_CADO_MODE0 0x04 -#define SPI_CADI_MODE0 0x05 -#define SPI_POLLING_MODE0 0x06 - -#define SPI_TRANSFER1_START 0x80 -#define SPI_TRANSFER1_END 0x40 -#define SPI_DO_MODE1 0x00 -#define SPI_DI_MODE1 0x01 - -#define CS_POLARITY_HIGH 0x40 -#define CS_POLARITY_LOW 0x00 -#define DTO_MSB_FIRST 0x00 -#define DTO_LSB_FIRST 0x20 -#define SPI_MASTER 0x00 -#define SPI_SLAVE 0x10 -#define SPI_MODE0 0x00 -#define SPI_MODE1 0x04 -#define SPI_MODE2 0x08 -#define SPI_MODE3 0x0C -#define SPI_MANUAL 0x00 -#define SPI_HALF_AUTO 0x01 -#define SPI_AUTO 0x02 -#define SPI_EEPROM_AUTO 0x03 - -#define EDO_TIMING_MASK 0x03 -#define SAMPLE_RISING 0x00 -#define SAMPLE_DELAY_HALF 0x01 -#define SAMPLE_DELAY_ONE 0x02 -#define SAPMLE_DELAY_ONE_HALF 0x03 -#define TCS_MASK 0x0C - -#define NOT_BYPASS_SD 0x02 -#define DISABLE_SDIO_FUNC 0x04 -#define SELECT_1LUN 0x08 - -#define PWR_GATE_EN 0x01 -#define LDO3318_PWR_MASK 0x06 -#define LDO_ON 0x00 -#define LDO_SUSPEND 0x04 -#define LDO_OFF 0x06 - -#define SD_CFG1 0xFDA0 -#define SD_CFG2 0xFDA1 -#define SD_CFG3 0xFDA2 -#define SD_STAT1 0xFDA3 -#define SD_STAT2 0xFDA4 -#define SD_BUS_STAT 0xFDA5 -#define SD_PAD_CTL 0xFDA6 -#define SD_SAMPLE_POINT_CTL 0xFDA7 -#define SD_PUSH_POINT_CTL 0xFDA8 -#define SD_CMD0 0xFDA9 -#define SD_CMD1 0xFDAA -#define SD_CMD2 0xFDAB -#define SD_CMD3 0xFDAC -#define SD_CMD4 0xFDAD -#define SD_CMD5 0xFDAE -#define SD_BYTE_CNT_L 0xFDAF -#define SD_BYTE_CNT_H 0xFDB0 -#define SD_BLOCK_CNT_L 0xFDB1 -#define SD_BLOCK_CNT_H 0xFDB2 -#define SD_TRANSFER 0xFDB3 -#define SD_CMD_STATE 0xFDB5 -#define SD_DATA_STATE 0xFDB6 - -#define DCM_DRP_CTL 0xFC23 -#define DCM_DRP_TRIG 0xFC24 -#define DCM_DRP_CFG 0xFC25 -#define DCM_DRP_WR_DATA_L 0xFC26 -#define DCM_DRP_WR_DATA_H 0xFC27 -#define DCM_DRP_RD_DATA_L 0xFC28 -#define DCM_DRP_RD_DATA_H 0xFC29 -#define SD_VPCLK0_CTL 0xFC2A -#define SD_VPCLK1_CTL 0xFC2B -#define SD_DCMPS0_CTL 0xFC2C -#define SD_DCMPS1_CTL 0xFC2D -#define SD_VPTX_CTL SD_VPCLK0_CTL -#define SD_VPRX_CTL SD_VPCLK1_CTL -#define SD_DCMPS_TX_CTL SD_DCMPS0_CTL -#define SD_DCMPS_RX_CTL SD_DCMPS1_CTL - -#define CARD_CLK_SOURCE 0xFC2E - -#define CARD_PWR_CTL 0xFD50 -#define CARD_CLK_SWITCH 0xFD51 -#define CARD_SHARE_MODE 0xFD52 -#define CARD_DRIVE_SEL 0xFD53 -#define CARD_STOP 0xFD54 -#define CARD_OE 0xFD55 -#define CARD_AUTO_BLINK 0xFD56 -#define CARD_GPIO_DIR 0xFD57 -#define CARD_GPIO 0xFD58 - -#define CARD_DATA_SOURCE 0xFD5B -#define CARD_SELECT 0xFD5C -#define SD30_DRIVE_SEL 0xFD5E - -#define CARD_CLK_EN 0xFD69 - -#define SDIO_CTRL 0xFD6B - -#define FPDCTL 0xFC00 -#define PDINFO 0xFC01 - -#define CLK_CTL 0xFC02 -#define CLK_DIV 0xFC03 -#define CLK_SEL 0xFC04 - -#define SSC_DIV_N_0 0xFC0F -#define SSC_DIV_N_1 0xFC10 - -#define RCCTL 0xFC14 - -#define FPGA_PULL_CTL 0xFC1D - -#define CARD_PULL_CTL1 0xFD60 -#define CARD_PULL_CTL2 0xFD61 -#define CARD_PULL_CTL3 0xFD62 -#define CARD_PULL_CTL4 0xFD63 -#define CARD_PULL_CTL5 0xFD64 -#define CARD_PULL_CTL6 0xFD65 - -#define IRQEN0 0xFE20 -#define IRQSTAT0 0xFE21 -#define IRQEN1 0xFE22 -#define IRQSTAT1 0xFE23 -#define TLPRIEN 0xFE24 -#define TLPRISTAT 0xFE25 -#define TLPTIEN 0xFE26 -#define TLPTISTAT 0xFE27 -#define DMATC0 0xFE28 -#define DMATC1 0xFE29 -#define DMATC2 0xFE2A -#define DMATC3 0xFE2B -#define DMACTL 0xFE2C -#define BCTL 0xFE2D -#define RBBC0 0xFE2E -#define RBBC1 0xFE2F -#define RBDAT 0xFE30 -#define RBCTL 0xFE34 -#define CFGADDR0 0xFE35 -#define CFGADDR1 0xFE36 -#define CFGDATA0 0xFE37 -#define CFGDATA1 0xFE38 -#define CFGDATA2 0xFE39 -#define CFGDATA3 0xFE3A -#define CFGRWCTL 0xFE3B -#define PHYRWCTL 0xFE3C -#define PHYDATA0 0xFE3D -#define PHYDATA1 0xFE3E -#define PHYADDR 0xFE3F -#define MSGRXDATA0 0xFE40 -#define MSGRXDATA1 0xFE41 -#define MSGRXDATA2 0xFE42 -#define MSGRXDATA3 0xFE43 -#define MSGTXDATA0 0xFE44 -#define MSGTXDATA1 0xFE45 -#define MSGTXDATA2 0xFE46 -#define MSGTXDATA3 0xFE47 -#define MSGTXCTL 0xFE48 -#define PETXCFG 0xFE49 - -#define CDRESUMECTL 0xFE52 -#define WAKE_SEL_CTL 0xFE54 -#define PME_FORCE_CTL 0xFE56 -#define ASPM_FORCE_CTL 0xFE57 -#define PM_CLK_FORCE_CTL 0xFE58 -#define PERST_GLITCH_WIDTH 0xFE5C -#define CHANGE_LINK_STATE 0xFE5B -#define RESET_LOAD_REG 0xFE5E -#define HOST_SLEEP_STATE 0xFE60 -#define MAIN_PWR_OFF_CTL 0xFE70 /* RTS5208 */ - -#define NFTS_TX_CTRL 0xFE72 - -#define PWR_GATE_CTRL 0xFE75 -#define PWD_SUSPEND_EN 0xFE76 - -#define EFUSE_CONTENT 0xFE5F - -#define XD_INIT 0xFD10 -#define XD_DTCTL 0xFD11 -#define XD_CTL 0xFD12 -#define XD_TRANSFER 0xFD13 -#define XD_CFG 0xFD14 -#define XD_ADDRESS0 0xFD15 -#define XD_ADDRESS1 0xFD16 -#define XD_ADDRESS2 0xFD17 -#define XD_ADDRESS3 0xFD18 -#define XD_ADDRESS4 0xFD19 -#define XD_DAT 0xFD1A -#define XD_PAGE_CNT 0xFD1B -#define XD_PAGE_STATUS 0xFD1C -#define XD_BLOCK_STATUS 0xFD1D -#define XD_BLOCK_ADDR1_L 0xFD1E -#define XD_BLOCK_ADDR1_H 0xFD1F -#define XD_BLOCK_ADDR2_L 0xFD20 -#define XD_BLOCK_ADDR2_H 0xFD21 -#define XD_BYTE_CNT_L 0xFD22 -#define XD_BYTE_CNT_H 0xFD23 -#define XD_PARITY 0xFD24 -#define XD_ECC_BIT1 0xFD25 -#define XD_ECC_BYTE1 0xFD26 -#define XD_ECC_BIT2 0xFD27 -#define XD_ECC_BYTE2 0xFD28 -#define XD_RESERVED0 0xFD29 -#define XD_RESERVED1 0xFD2A -#define XD_RESERVED2 0xFD2B -#define XD_RESERVED3 0xFD2C -#define XD_CHK_DATA_STATUS 0xFD2D -#define XD_CATCTL 0xFD2E - -#define MS_CFG 0xFD40 -#define MS_TPC 0xFD41 -#define MS_TRANS_CFG 0xFD42 -#define MS_TRANSFER 0xFD43 -#define MS_INT_REG 0xFD44 -#define MS_BYTE_CNT 0xFD45 -#define MS_SECTOR_CNT_L 0xFD46 -#define MS_SECTOR_CNT_H 0xFD47 -#define MS_DBUS_H 0xFD48 - -#define SSC_CTL1 0xFC11 -#define SSC_CTL2 0xFC12 - -#define OCPCTL 0xFC15 -#define OCPSTAT 0xFC16 -#define OCPCLR 0xFC17 /* 5208 */ -#define OCPPARA1 0xFC18 -#define OCPPARA2 0xFC19 - -#define EFUSE_OP 0xFC20 -#define EFUSE_CTRL 0xFC21 -#define EFUSE_DATA 0xFC22 - -#define SPI_COMMAND 0xFD80 -#define SPI_ADDR0 0xFD81 -#define SPI_ADDR1 0xFD82 -#define SPI_ADDR2 0xFD83 -#define SPI_ADDR3 0xFD84 -#define SPI_CA_NUMBER 0xFD85 -#define SPI_LENGTH0 0xFD86 -#define SPI_LENGTH1 0xFD87 -#define SPI_DATA 0xFD88 -#define SPI_DATA_NUMBER 0xFD89 -#define SPI_TRANSFER0 0xFD90 -#define SPI_TRANSFER1 0xFD91 -#define SPI_CONTROL 0xFD92 -#define SPI_SIG 0xFD93 -#define SPI_TCTL 0xFD94 -#define SPI_SLAVE_NUM 0xFD95 -#define SPI_CLK_DIVIDER0 0xFD96 -#define SPI_CLK_DIVIDER1 0xFD97 - -#define SRAM_BASE 0xE600 -#define RBUF_BASE 0xF400 -#define PPBUF_BASE1 0xF800 -#define PPBUF_BASE2 0xFA00 -#define IMAGE_FLAG_ADDR0 0xCE80 -#define IMAGE_FLAG_ADDR1 0xCE81 - -#define READ_OP 1 -#define WRITE_OP 2 - -#define LCTLR 0x80 - -#define POLLING_WAIT_CNT 1 -#define IDLE_MAX_COUNT 10 -#define SDIO_IDLE_COUNT 10 - -#define DEBOUNCE_CNT 5 - -void do_remaining_work(struct rtsx_chip *chip); -void try_to_switch_sdio_ctrl(struct rtsx_chip *chip); -void do_reset_sd_card(struct rtsx_chip *chip); -void do_reset_xd_card(struct rtsx_chip *chip); -void do_reset_ms_card(struct rtsx_chip *chip); -void rtsx_power_off_card(struct rtsx_chip *chip); -void rtsx_release_cards(struct rtsx_chip *chip); -void rtsx_reset_cards(struct rtsx_chip *chip); -void rtsx_reinit_cards(struct rtsx_chip *chip, int reset_chip); -void rtsx_init_cards(struct rtsx_chip *chip); -int switch_ssc_clock(struct rtsx_chip *chip, int clk); -int switch_normal_clock(struct rtsx_chip *chip, int clk); -int enable_card_clock(struct rtsx_chip *chip, u8 card); -int disable_card_clock(struct rtsx_chip *chip, u8 card); -int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 sec_addr, u16 sec_cnt); -void trans_dma_enable(enum dma_data_direction dir, - struct rtsx_chip *chip, u32 byte_cnt, u8 pack_size); -void toggle_gpio(struct rtsx_chip *chip, u8 gpio); -void turn_on_led(struct rtsx_chip *chip, u8 gpio); -void turn_off_led(struct rtsx_chip *chip, u8 gpio); - -int card_share_mode(struct rtsx_chip *chip, int card); -int select_card(struct rtsx_chip *chip, int card); -int detect_card_cd(struct rtsx_chip *chip, int card); -int check_card_exist(struct rtsx_chip *chip, unsigned int lun); -int check_card_ready(struct rtsx_chip *chip, unsigned int lun); -int check_card_wp(struct rtsx_chip *chip, unsigned int lun); -void eject_card(struct rtsx_chip *chip, unsigned int lun); -u8 get_lun_card(struct rtsx_chip *chip, unsigned int lun); - -static inline u32 get_card_size(struct rtsx_chip *chip, unsigned int lun) -{ -#ifdef SUPPORT_SD_LOCK - struct sd_info *sd_card = &chip->sd_card; - - if ((get_lun_card(chip, lun) == SD_CARD) && - (sd_card->sd_lock_status & SD_LOCKED)) - return 0; - - return chip->capacity[lun]; -#else - return chip->capacity[lun]; -#endif -} - -static inline int switch_clock(struct rtsx_chip *chip, int clk) -{ - int retval = 0; - - if (chip->asic_code) - retval = switch_ssc_clock(chip, clk); - else - retval = switch_normal_clock(chip, clk); - - return retval; -} - -int card_power_on(struct rtsx_chip *chip, u8 card); -int card_power_off(struct rtsx_chip *chip, u8 card); - -static inline int card_power_off_all(struct rtsx_chip *chip) -{ - int retval; - - retval = rtsx_write_register(chip, CARD_PWR_CTL, 0x0F, 0x0F); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static inline void rtsx_clear_xd_error(struct rtsx_chip *chip) -{ - rtsx_write_register(chip, CARD_STOP, XD_STOP | XD_CLR_ERR, - XD_STOP | XD_CLR_ERR); -} - -static inline void rtsx_clear_sd_error(struct rtsx_chip *chip) -{ - rtsx_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, - SD_STOP | SD_CLR_ERR); -} - -static inline void rtsx_clear_ms_error(struct rtsx_chip *chip) -{ - rtsx_write_register(chip, CARD_STOP, MS_STOP | MS_CLR_ERR, - MS_STOP | MS_CLR_ERR); -} - -static inline void rtsx_clear_spi_error(struct rtsx_chip *chip) -{ - rtsx_write_register(chip, CARD_STOP, SPI_STOP | SPI_CLR_ERR, - SPI_STOP | SPI_CLR_ERR); -} - -#ifdef SUPPORT_SDIO_ASPM -void dynamic_configure_sdio_aspm(struct rtsx_chip *chip); -#endif - -#endif /* __REALTEK_RTSX_CARD_H */ diff --git a/drivers/staging/rts5208/rtsx_chip.c b/drivers/staging/rts5208/rtsx_chip.c deleted file mode 100644 index 6375032918d4cf..00000000000000 --- a/drivers/staging/rts5208/rtsx_chip.c +++ /dev/null @@ -1,2161 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include -#include -#include - -#include "rtsx.h" -#include "sd.h" -#include "xd.h" -#include "ms.h" - -static void rtsx_calibration(struct rtsx_chip *chip) -{ - rtsx_write_phy_register(chip, 0x1B, 0x135E); - wait_timeout(10); - rtsx_write_phy_register(chip, 0x00, 0x0280); - rtsx_write_phy_register(chip, 0x01, 0x7112); - rtsx_write_phy_register(chip, 0x01, 0x7110); - rtsx_write_phy_register(chip, 0x01, 0x7112); - rtsx_write_phy_register(chip, 0x01, 0x7113); - rtsx_write_phy_register(chip, 0x00, 0x0288); -} - -void rtsx_enable_card_int(struct rtsx_chip *chip) -{ - u32 reg = rtsx_readl(chip, RTSX_BIER); - int i; - - for (i = 0; i <= chip->max_lun; i++) { - if (chip->lun2card[i] & XD_CARD) - reg |= XD_INT_EN; - if (chip->lun2card[i] & SD_CARD) - reg |= SD_INT_EN; - if (chip->lun2card[i] & MS_CARD) - reg |= MS_INT_EN; - } - if (chip->hw_bypass_sd) - reg &= ~((u32)SD_INT_EN); - - rtsx_writel(chip, RTSX_BIER, reg); -} - -void rtsx_enable_bus_int(struct rtsx_chip *chip) -{ - u32 reg = 0; -#ifndef DISABLE_CARD_INT - int i; -#endif - - reg = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN; - -#ifndef DISABLE_CARD_INT - for (i = 0; i <= chip->max_lun; i++) { - dev_dbg(rtsx_dev(chip), "lun2card[%d] = 0x%02x\n", - i, chip->lun2card[i]); - - if (chip->lun2card[i] & XD_CARD) - reg |= XD_INT_EN; - if (chip->lun2card[i] & SD_CARD) - reg |= SD_INT_EN; - if (chip->lun2card[i] & MS_CARD) - reg |= MS_INT_EN; - } - if (chip->hw_bypass_sd) - reg &= ~((u32)SD_INT_EN); -#endif - - if (chip->ic_version >= IC_VER_C) - reg |= DELINK_INT_EN; -#ifdef SUPPORT_OCP - reg |= OC_INT_EN; -#endif - if (!chip->adma_mode) - reg |= DATA_DONE_INT_EN; - - /* Enable Bus Interrupt */ - rtsx_writel(chip, RTSX_BIER, reg); - - dev_dbg(rtsx_dev(chip), "RTSX_BIER: 0x%08x\n", reg); -} - -void rtsx_disable_bus_int(struct rtsx_chip *chip) -{ - rtsx_writel(chip, RTSX_BIER, 0); -} - -static int rtsx_pre_handle_sdio_old(struct rtsx_chip *chip) -{ - int retval; - - if (chip->ignore_sd && CHK_SDIO_EXIST(chip)) { - if (chip->asic_code) { - retval = rtsx_write_register(chip, CARD_PULL_CTL5, - 0xFF, - MS_INS_PU | SD_WP_PU | - SD_CD_PU | SD_CMD_PU); - if (retval) - return retval; - } else { - retval = rtsx_write_register(chip, FPGA_PULL_CTL, - 0xFF, - FPGA_SD_PULL_CTL_EN); - if (retval) - return retval; - } - retval = rtsx_write_register(chip, CARD_SHARE_MODE, 0xFF, - CARD_SHARE_48_SD); - if (retval) - return retval; - - /* Enable SDIO internal clock */ - retval = rtsx_write_register(chip, 0xFF2C, 0x01, 0x01); - if (retval) - return retval; - - retval = rtsx_write_register(chip, SDIO_CTRL, 0xFF, - SDIO_BUS_CTRL | SDIO_CD_CTRL); - if (retval) - return retval; - - chip->sd_int = 1; - chip->sd_io = 1; - } else { - chip->need_reset |= SD_CARD; - } - - return STATUS_SUCCESS; -} - -#ifdef HW_AUTO_SWITCH_SD_BUS -static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip) -{ - u8 tmp; - bool sw_bypass_sd = false; - int retval; - - if (chip->driver_first_load) { - if (CHECK_PID(chip, 0x5288)) { - retval = rtsx_read_register(chip, 0xFE5A, &tmp); - if (retval) - return retval; - if (tmp & 0x08) - sw_bypass_sd = true; - } else if (CHECK_PID(chip, 0x5208)) { - retval = rtsx_read_register(chip, 0xFE70, &tmp); - if (retval) - return retval; - if (tmp & 0x80) - sw_bypass_sd = true; - } - } else { - if (chip->sdio_in_charge) - sw_bypass_sd = true; - } - dev_dbg(rtsx_dev(chip), "chip->sdio_in_charge = %d\n", - chip->sdio_in_charge); - dev_dbg(rtsx_dev(chip), "chip->driver_first_load = %d\n", - chip->driver_first_load); - dev_dbg(rtsx_dev(chip), "sw_bypass_sd = %d\n", - sw_bypass_sd); - - if (sw_bypass_sd) { - u8 cd_toggle_mask = 0; - - retval = rtsx_read_register(chip, TLPTISTAT, &tmp); - if (retval) - return retval; - cd_toggle_mask = 0x08; - - if (tmp & cd_toggle_mask) { - /* Disable sdio_bus_auto_switch */ - if (CHECK_PID(chip, 0x5288)) { - retval = rtsx_write_register(chip, 0xFE5A, - 0x08, 0x00); - if (retval) - return retval; - } else if (CHECK_PID(chip, 0x5208)) { - retval = rtsx_write_register(chip, 0xFE70, - 0x80, 0x00); - if (retval) - return retval; - } - - retval = rtsx_write_register(chip, TLPTISTAT, 0xFF, - tmp); - if (retval) - return retval; - - chip->need_reset |= SD_CARD; - } else { - dev_dbg(rtsx_dev(chip), "Chip inserted with SDIO!\n"); - - if (chip->asic_code) { - retval = sd_pull_ctl_enable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register - (chip, FPGA_PULL_CTL, - FPGA_SD_PULL_CTL_BIT | 0x20, - 0); - if (retval) - return retval; - } - retval = card_share_mode(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - /* Enable sdio_bus_auto_switch */ - if (CHECK_PID(chip, 0x5288)) { - retval = rtsx_write_register(chip, 0xFE5A, - 0x08, 0x08); - if (retval) - return retval; - } else if (CHECK_PID(chip, 0x5208)) { - retval = rtsx_write_register(chip, 0xFE70, - 0x80, 0x80); - if (retval) - return retval; - } - - chip->chip_insert_with_sdio = 1; - chip->sd_io = 1; - } - } else { - retval = rtsx_write_register(chip, TLPTISTAT, 0x08, 0x08); - if (retval) - return retval; - - chip->need_reset |= SD_CARD; - } - - return STATUS_SUCCESS; -} -#endif - -static int rtsx_reset_aspm(struct rtsx_chip *chip) -{ - int ret; - - if (chip->dynamic_aspm) { - if (!CHK_SDIO_EXIST(chip) || !CHECK_PID(chip, 0x5288)) - return STATUS_SUCCESS; - - ret = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF, - chip->aspm_l0s_l1_en); - if (ret != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; - } - - if (CHECK_PID(chip, 0x5208)) { - ret = rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFF, 0x3F); - if (ret) - return ret; - } - ret = rtsx_write_config_byte(chip, LCTLR, chip->aspm_l0s_l1_en); - if (ret != STATUS_SUCCESS) - return STATUS_FAIL; - - chip->aspm_level[0] = chip->aspm_l0s_l1_en; - if (CHK_SDIO_EXIST(chip)) { - chip->aspm_level[1] = chip->aspm_l0s_l1_en; - ret = rtsx_write_cfg_dw(chip, CHECK_PID(chip, 0x5288) ? 2 : 1, - 0xC0, 0xFF, chip->aspm_l0s_l1_en); - if (ret != STATUS_SUCCESS) - return STATUS_FAIL; - } - - chip->aspm_enabled = 1; - - return STATUS_SUCCESS; -} - -static int rtsx_enable_pcie_intr(struct rtsx_chip *chip) -{ - int ret; - - if (!chip->asic_code || !CHECK_PID(chip, 0x5208)) { - rtsx_enable_bus_int(chip); - return STATUS_SUCCESS; - } - - if (chip->phy_debug_mode) { - ret = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0); - if (ret) - return ret; - rtsx_disable_bus_int(chip); - } else { - rtsx_enable_bus_int(chip); - } - - if (chip->ic_version >= IC_VER_D) { - u16 reg; - - ret = rtsx_read_phy_register(chip, 0x00, ®); - if (ret != STATUS_SUCCESS) - return STATUS_FAIL; - - reg &= 0xFE7F; - reg |= 0x80; - ret = rtsx_write_phy_register(chip, 0x00, reg); - if (ret != STATUS_SUCCESS) - return STATUS_FAIL; - - ret = rtsx_read_phy_register(chip, 0x1C, ®); - if (ret != STATUS_SUCCESS) - return STATUS_FAIL; - - reg &= 0xFFF7; - ret = rtsx_write_phy_register(chip, 0x1C, reg); - if (ret != STATUS_SUCCESS) - return STATUS_FAIL; - } - - if (chip->driver_first_load && chip->ic_version < IC_VER_C) - rtsx_calibration(chip); - - return STATUS_SUCCESS; -} - -int rtsx_reset_chip(struct rtsx_chip *chip) -{ - int retval; - - rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr); - - rtsx_disable_aspm(chip); - - retval = rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 0x00); - if (retval) - return retval; - - /* Disable card clock */ - retval = rtsx_write_register(chip, CARD_CLK_EN, 0x1E, 0); - if (retval) - return retval; - -#ifdef SUPPORT_OCP - /* SSC power on, OCD power on */ - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - retval = rtsx_write_register(chip, FPDCTL, OC_POWER_DOWN, 0); - if (retval) - return retval; - } else { - retval = rtsx_write_register(chip, FPDCTL, OC_POWER_DOWN, - MS_OC_POWER_DOWN); - if (retval) - return retval; - } - - retval = rtsx_write_register(chip, OCPPARA1, OCP_TIME_MASK, - OCP_TIME_800); - if (retval) - return retval; - retval = rtsx_write_register(chip, OCPPARA2, OCP_THD_MASK, - OCP_THD_244_946); - if (retval) - return retval; - retval = rtsx_write_register(chip, OCPCTL, 0xFF, - CARD_OC_INT_EN | CARD_DETECT_EN); - if (retval) - return retval; -#else - /* OC power down */ - retval = rtsx_write_register(chip, FPDCTL, OC_POWER_DOWN, - OC_POWER_DOWN); - if (retval) - return retval; -#endif - - if (!CHECK_PID(chip, 0x5288)) { - retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0xFF, 0x03); - if (retval) - return retval; - } - - /* Turn off LED */ - retval = rtsx_write_register(chip, CARD_GPIO, 0xFF, 0x03); - if (retval) - return retval; - - /* Reset delink mode */ - retval = rtsx_write_register(chip, CHANGE_LINK_STATE, 0x0A, 0); - if (retval) - return retval; - - /* Card driving select */ - retval = rtsx_write_register(chip, CARD_DRIVE_SEL, 0xFF, - chip->card_drive_sel); - if (retval) - return retval; - -#ifdef LED_AUTO_BLINK - retval = rtsx_write_register(chip, CARD_AUTO_BLINK, 0xFF, - LED_BLINK_SPEED | BLINK_EN | LED_GPIO0); - if (retval) - return retval; -#endif - - if (chip->asic_code) { - /* Enable SSC Clock */ - retval = rtsx_write_register(chip, SSC_CTL1, 0xFF, - SSC_8X_EN | SSC_SEL_4M); - if (retval) - return retval; - retval = rtsx_write_register(chip, SSC_CTL2, 0xFF, 0x12); - if (retval) - return retval; - } - - /* - * Disable cd_pwr_save (u_force_rst_core_en=0, u_cd_rst_core_en=0) - * 0xFE5B - * bit[1] u_cd_rst_core_en rst_value = 0 - * bit[2] u_force_rst_core_en rst_value = 0 - * bit[5] u_mac_phy_rst_n_dbg rst_value = 1 - * bit[4] u_non_sticky_rst_n_dbg rst_value = 0 - */ - retval = rtsx_write_register(chip, CHANGE_LINK_STATE, 0x16, 0x10); - if (retval) - return retval; - - /* Enable ASPM */ - if (chip->aspm_l0s_l1_en) { - retval = rtsx_reset_aspm(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - if (chip->asic_code && CHECK_PID(chip, 0x5208)) { - retval = rtsx_write_phy_register(chip, 0x07, 0x0129); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - retval = rtsx_write_config_byte(chip, LCTLR, - chip->aspm_l0s_l1_en); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - retval = rtsx_write_config_byte(chip, 0x81, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHK_SDIO_EXIST(chip)) { - retval = rtsx_write_cfg_dw(chip, - CHECK_PID(chip, 0x5288) ? 2 : 1, - 0xC0, 0xFF00, 0x0100); - - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - if (CHECK_PID(chip, 0x5288) && !CHK_SDIO_EXIST(chip)) { - retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFFFF, 0x0103); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_cfg_dw(chip, 2, 0x84, 0xFF, 0x03); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - retval = rtsx_write_register(chip, IRQSTAT0, LINK_RDY_INT, - LINK_RDY_INT); - if (retval) - return retval; - - retval = rtsx_write_register(chip, PERST_GLITCH_WIDTH, 0xFF, 0x80); - if (retval) - return retval; - - retval = rtsx_enable_pcie_intr(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - chip->need_reset = 0; - - chip->int_reg = rtsx_readl(chip, RTSX_BIPR); - - if (chip->hw_bypass_sd) - goto nextcard; - dev_dbg(rtsx_dev(chip), "In %s, chip->int_reg = 0x%x\n", __func__, - chip->int_reg); - if (chip->int_reg & SD_EXIST) { -#ifdef HW_AUTO_SWITCH_SD_BUS - if (CHECK_PID(chip, 0x5208) && chip->ic_version < IC_VER_C) - retval = rtsx_pre_handle_sdio_old(chip); - else - retval = rtsx_pre_handle_sdio_new(chip); - - dev_dbg(rtsx_dev(chip), "chip->need_reset = 0x%x (%s)\n", - (unsigned int)(chip->need_reset), __func__); -#else /* HW_AUTO_SWITCH_SD_BUS */ - retval = rtsx_pre_handle_sdio_old(chip); -#endif /* HW_AUTO_SWITCH_SD_BUS */ - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - } else { - chip->sd_io = 0; - retval = rtsx_write_register(chip, SDIO_CTRL, - SDIO_BUS_CTRL | SDIO_CD_CTRL, 0); - if (retval) - return retval; - } - -nextcard: - if (chip->int_reg & XD_EXIST) - chip->need_reset |= XD_CARD; - if (chip->int_reg & MS_EXIST) - chip->need_reset |= MS_CARD; - if (chip->int_reg & CARD_EXIST) { - retval = rtsx_write_register(chip, SSC_CTL1, SSC_RSTB, - SSC_RSTB); - if (retval) - return retval; - } - - dev_dbg(rtsx_dev(chip), "In %s, chip->need_reset = 0x%x\n", __func__, - (unsigned int)(chip->need_reset)); - - retval = rtsx_write_register(chip, RCCTL, 0x01, 0x00); - if (retval) - return retval; - - if (CHECK_PID(chip, 0x5208) || CHECK_PID(chip, 0x5288)) { - /* Turn off main power when entering S3/S4 state */ - retval = rtsx_write_register(chip, MAIN_PWR_OFF_CTL, 0x03, - 0x03); - if (retval) - return retval; - } - - if (chip->remote_wakeup_en && !chip->auto_delink_en) { - retval = rtsx_write_register(chip, WAKE_SEL_CTL, 0x07, 0x07); - if (retval) - return retval; - if (chip->aux_pwr_exist) { - retval = rtsx_write_register(chip, PME_FORCE_CTL, - 0xFF, 0x33); - if (retval) - return retval; - } - } else { - retval = rtsx_write_register(chip, WAKE_SEL_CTL, 0x07, 0x04); - if (retval) - return retval; - retval = rtsx_write_register(chip, PME_FORCE_CTL, 0xFF, 0x30); - if (retval) - return retval; - } - - if (CHECK_PID(chip, 0x5208) && chip->ic_version >= IC_VER_D) { - retval = rtsx_write_register(chip, PETXCFG, 0x1C, 0x14); - if (retval) - return retval; - } - - if (chip->asic_code && CHECK_PID(chip, 0x5208)) { - retval = rtsx_clr_phy_reg_bit(chip, 0x1C, 2); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - if (chip->ft2_fast_mode) { - retval = rtsx_write_register(chip, CARD_PWR_CTL, 0xFF, - MS_PARTIAL_POWER_ON | - SD_PARTIAL_POWER_ON); - if (retval) - return retval; - udelay(chip->pmos_pwr_on_interval); - retval = rtsx_write_register(chip, CARD_PWR_CTL, 0xFF, - MS_POWER_ON | SD_POWER_ON); - if (retval) - return retval; - - wait_timeout(200); - } - - /* Reset card */ - rtsx_reset_detected_cards(chip, 0); - - chip->driver_first_load = 0; - - return STATUS_SUCCESS; -} - -static inline int valid_sd_speed_prior(u32 sd_speed_prior) -{ - bool valid_para = true; - int i; - - for (i = 0; i < 4; i++) { - u8 tmp = (u8)(sd_speed_prior >> (i * 8)); - - if (tmp < 0x01 || tmp > 0x04) { - valid_para = false; - break; - } - } - - return valid_para; -} - -static inline int valid_sd_current_prior(u32 sd_current_prior) -{ - bool valid_para = true; - int i; - - for (i = 0; i < 4; i++) { - u8 tmp = (u8)(sd_current_prior >> (i * 8)); - - if (tmp > 0x03) { - valid_para = false; - break; - } - } - - return valid_para; -} - -static int rts5208_init(struct rtsx_chip *chip) -{ - int retval; - u16 reg = 0; - u8 val = 0; - - retval = rtsx_write_register(chip, CLK_SEL, 0x03, 0x03); - if (retval) - return retval; - retval = rtsx_read_register(chip, CLK_SEL, &val); - if (retval) - return retval; - chip->asic_code = val == 0 ? 1 : 0; - - if (chip->asic_code) { - retval = rtsx_read_phy_register(chip, 0x1C, ®); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - dev_dbg(rtsx_dev(chip), "Value of phy register 0x1C is 0x%x\n", - reg); - chip->ic_version = (reg >> 4) & 0x07; - chip->phy_debug_mode = reg & PHY_DEBUG_MODE ? 1 : 0; - - } else { - retval = rtsx_read_register(chip, 0xFE80, &val); - if (retval) - return retval; - chip->ic_version = val; - chip->phy_debug_mode = 0; - } - - retval = rtsx_read_register(chip, PDINFO, &val); - if (retval) - return retval; - dev_dbg(rtsx_dev(chip), "PDINFO: 0x%x\n", val); - chip->aux_pwr_exist = val & AUX_PWR_DETECTED ? 1 : 0; - - retval = rtsx_read_register(chip, 0xFE50, &val); - if (retval) - return retval; - chip->hw_bypass_sd = val & 0x01 ? 1 : 0; - - rtsx_read_config_byte(chip, 0x0E, &val); - if (val & 0x80) - SET_SDIO_EXIST(chip); - else - CLR_SDIO_EXIST(chip); - - if (chip->use_hw_setting) { - retval = rtsx_read_register(chip, CHANGE_LINK_STATE, &val); - if (retval) - return retval; - chip->auto_delink_en = val & 0x80 ? 1 : 0; - } - - return STATUS_SUCCESS; -} - -static int rts5288_init(struct rtsx_chip *chip) -{ - int retval; - u8 val = 0, max_func; - u32 lval = 0; - - retval = rtsx_write_register(chip, CLK_SEL, 0x03, 0x03); - if (retval) - return retval; - retval = rtsx_read_register(chip, CLK_SEL, &val); - if (retval) - return retval; - chip->asic_code = val == 0 ? 1 : 0; - - chip->ic_version = 0; - chip->phy_debug_mode = 0; - - retval = rtsx_read_register(chip, PDINFO, &val); - if (retval) - return retval; - dev_dbg(rtsx_dev(chip), "PDINFO: 0x%x\n", val); - chip->aux_pwr_exist = val & AUX_PWR_DETECTED ? 1 : 0; - - retval = rtsx_read_register(chip, CARD_SHARE_MODE, &val); - if (retval) - return retval; - dev_dbg(rtsx_dev(chip), "CARD_SHARE_MODE: 0x%x\n", val); - chip->baro_pkg = val & 0x04 ? QFN : LQFP; - - retval = rtsx_read_register(chip, 0xFE5A, &val); - if (retval) - return retval; - chip->hw_bypass_sd = val & 0x10 ? 1 : 0; - - retval = rtsx_read_cfg_dw(chip, 0, 0x718, &lval); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - max_func = (u8)((lval >> 29) & 0x07); - dev_dbg(rtsx_dev(chip), "Max function number: %d\n", max_func); - if (max_func == 0x02) - SET_SDIO_EXIST(chip); - else - CLR_SDIO_EXIST(chip); - - if (chip->use_hw_setting) { - retval = rtsx_read_register(chip, CHANGE_LINK_STATE, &val); - if (retval) - return retval; - chip->auto_delink_en = val & 0x80 ? 1 : 0; - - if (CHECK_BARO_PKG(chip, LQFP)) - chip->lun_mode = SD_MS_1LUN; - else - chip->lun_mode = DEFAULT_SINGLE; - } - - return STATUS_SUCCESS; -} - -int rtsx_init_chip(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - struct xd_info *xd_card = &chip->xd_card; - struct ms_info *ms_card = &chip->ms_card; - int retval; - unsigned int i; - - dev_dbg(rtsx_dev(chip), "Vendor ID: 0x%04x, Product ID: 0x%04x\n", - chip->vendor_id, chip->product_id); - - chip->ic_version = 0; - - memset(xd_card, 0, sizeof(struct xd_info)); - memset(sd_card, 0, sizeof(struct sd_info)); - memset(ms_card, 0, sizeof(struct ms_info)); - - chip->xd_reset_counter = 0; - chip->sd_reset_counter = 0; - chip->ms_reset_counter = 0; - - chip->xd_show_cnt = MAX_SHOW_CNT; - chip->sd_show_cnt = MAX_SHOW_CNT; - chip->ms_show_cnt = MAX_SHOW_CNT; - - chip->sd_io = 0; - chip->auto_delink_cnt = 0; - chip->auto_delink_allowed = 1; - rtsx_set_stat(chip, RTSX_STAT_INIT); - - chip->aspm_enabled = 0; - chip->chip_insert_with_sdio = 0; - chip->sdio_aspm = 0; - chip->sdio_idle = 0; - chip->sdio_counter = 0; - chip->cur_card = 0; - chip->phy_debug_mode = 0; - chip->sdio_func_exist = 0; - memset(chip->sdio_raw_data, 0, 12); - - for (i = 0; i < MAX_ALLOWED_LUN_CNT; i++) { - set_sense_type(chip, i, SENSE_TYPE_NO_SENSE); - chip->rw_fail_cnt[i] = 0; - } - - if (!valid_sd_speed_prior(chip->sd_speed_prior)) - chip->sd_speed_prior = 0x01040203; - - dev_dbg(rtsx_dev(chip), "sd_speed_prior = 0x%08x\n", - chip->sd_speed_prior); - - if (!valid_sd_current_prior(chip->sd_current_prior)) - chip->sd_current_prior = 0x00010203; - - dev_dbg(rtsx_dev(chip), "sd_current_prior = 0x%08x\n", - chip->sd_current_prior); - - if (chip->sd_ddr_tx_phase > 31 || chip->sd_ddr_tx_phase < 0) - chip->sd_ddr_tx_phase = 0; - - if (chip->mmc_ddr_tx_phase > 31 || chip->mmc_ddr_tx_phase < 0) - chip->mmc_ddr_tx_phase = 0; - - retval = rtsx_write_register(chip, FPDCTL, SSC_POWER_DOWN, 0); - if (retval) - return retval; - wait_timeout(200); - retval = rtsx_write_register(chip, CLK_DIV, 0x07, 0x07); - if (retval) - return retval; - dev_dbg(rtsx_dev(chip), "chip->use_hw_setting = %d\n", - chip->use_hw_setting); - - if (CHECK_PID(chip, 0x5208)) { - retval = rts5208_init(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - } else if (CHECK_PID(chip, 0x5288)) { - retval = rts5288_init(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - if (chip->ss_en == 2) - chip->ss_en = 0; - - dev_dbg(rtsx_dev(chip), "chip->asic_code = %d\n", chip->asic_code); - dev_dbg(rtsx_dev(chip), "chip->ic_version = 0x%x\n", chip->ic_version); - dev_dbg(rtsx_dev(chip), "chip->phy_debug_mode = %d\n", - chip->phy_debug_mode); - dev_dbg(rtsx_dev(chip), "chip->aux_pwr_exist = %d\n", - chip->aux_pwr_exist); - dev_dbg(rtsx_dev(chip), "chip->sdio_func_exist = %d\n", - chip->sdio_func_exist); - dev_dbg(rtsx_dev(chip), "chip->hw_bypass_sd = %d\n", - chip->hw_bypass_sd); - dev_dbg(rtsx_dev(chip), "chip->aspm_l0s_l1_en = %d\n", - chip->aspm_l0s_l1_en); - dev_dbg(rtsx_dev(chip), "chip->lun_mode = %d\n", chip->lun_mode); - dev_dbg(rtsx_dev(chip), "chip->auto_delink_en = %d\n", - chip->auto_delink_en); - dev_dbg(rtsx_dev(chip), "chip->ss_en = %d\n", chip->ss_en); - dev_dbg(rtsx_dev(chip), "chip->baro_pkg = %d\n", chip->baro_pkg); - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - chip->card2lun[SD_CARD] = 0; - chip->card2lun[MS_CARD] = 1; - chip->card2lun[XD_CARD] = 0xFF; - chip->lun2card[0] = SD_CARD; - chip->lun2card[1] = MS_CARD; - chip->max_lun = 1; - SET_SDIO_IGNORED(chip); - } else if (CHECK_LUN_MODE(chip, SD_MS_1LUN)) { - chip->card2lun[SD_CARD] = 0; - chip->card2lun[MS_CARD] = 0; - chip->card2lun[XD_CARD] = 0xFF; - chip->lun2card[0] = SD_CARD | MS_CARD; - chip->max_lun = 0; - } else { - chip->card2lun[XD_CARD] = 0; - chip->card2lun[SD_CARD] = 0; - chip->card2lun[MS_CARD] = 0; - chip->lun2card[0] = XD_CARD | SD_CARD | MS_CARD; - chip->max_lun = 0; - } - - retval = rtsx_reset_chip(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -void rtsx_release_chip(struct rtsx_chip *chip) -{ - xd_free_l2p_tbl(chip); - ms_free_l2p_tbl(chip); - chip->card_exist = 0; - chip->card_ready = 0; -} - -#if !defined(LED_AUTO_BLINK) && defined(REGULAR_BLINK) -static inline void rtsx_blink_led(struct rtsx_chip *chip) -{ - if (chip->card_exist && chip->blink_led) { - if (chip->led_toggle_counter < LED_TOGGLE_INTERVAL) { - chip->led_toggle_counter++; - } else { - chip->led_toggle_counter = 0; - toggle_gpio(chip, LED_GPIO); - } - } -} -#endif - -static void rtsx_monitor_aspm_config(struct rtsx_chip *chip) -{ - bool reg_changed, maybe_support_aspm; - u32 tmp = 0; - u8 reg0 = 0, reg1 = 0; - - maybe_support_aspm = false; - reg_changed = false; - rtsx_read_config_byte(chip, LCTLR, ®0); - if (chip->aspm_level[0] != reg0) { - reg_changed = true; - chip->aspm_level[0] = reg0; - } - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) { - rtsx_read_cfg_dw(chip, 1, 0xC0, &tmp); - reg1 = (u8)tmp; - if (chip->aspm_level[1] != reg1) { - reg_changed = true; - chip->aspm_level[1] = reg1; - } - - if ((reg0 & 0x03) && (reg1 & 0x03)) - maybe_support_aspm = true; - - } else { - if (reg0 & 0x03) - maybe_support_aspm = true; - } - - if (reg_changed) { - if (maybe_support_aspm) - chip->aspm_l0s_l1_en = 0x03; - - dev_dbg(rtsx_dev(chip), - "aspm_level[0] = 0x%02x, aspm_level[1] = 0x%02x\n", - chip->aspm_level[0], chip->aspm_level[1]); - - if (chip->aspm_l0s_l1_en) { - chip->aspm_enabled = 1; - } else { - chip->aspm_enabled = 0; - chip->sdio_aspm = 0; - } - rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFF, - 0x30 | chip->aspm_level[0] | - (chip->aspm_level[1] << 2)); - } -} - -static void rtsx_manage_ocp(struct rtsx_chip *chip) -{ -#ifdef SUPPORT_OCP - if (!chip->ocp_int) - return; - - rtsx_read_register(chip, OCPSTAT, &chip->ocp_stat); - - if (chip->card_exist & SD_CARD) - sd_power_off_card3v3(chip); - else if (chip->card_exist & MS_CARD) - ms_power_off_card3v3(chip); - else if (chip->card_exist & XD_CARD) - xd_power_off_card3v3(chip); - - chip->ocp_int = 0; -#endif -} - -static void rtsx_manage_sd_lock(struct rtsx_chip *chip) -{ -#ifdef SUPPORT_SD_LOCK - struct sd_info *sd_card = &chip->sd_card; - u8 val; - - if (!sd_card->sd_erase_status) - return; - - if (chip->card_exist & SD_CARD) { - rtsx_read_register(chip, 0xFD30, &val); - if (val & 0x02) { - sd_card->sd_erase_status = SD_NOT_ERASE; - sd_card->sd_lock_notify = 1; - chip->need_reinit |= SD_CARD; - } - } else { - sd_card->sd_erase_status = SD_NOT_ERASE; - } -#endif -} - -static bool rtsx_is_ss_allowed(struct rtsx_chip *chip) -{ - u32 val; - - if (!chip->ss_en || CHECK_PID(chip, 0x5288)) - return false; - - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) { - rtsx_read_cfg_dw(chip, 1, 0x04, &val); - if (val & 0x07) - return false; - } - - return true; -} - -static void rtsx_manage_ss(struct rtsx_chip *chip) -{ - if (!rtsx_is_ss_allowed(chip) || chip->sd_io) - return; - - if (rtsx_get_stat(chip) != RTSX_STAT_IDLE) { - chip->ss_counter = 0; - return; - } - - if (chip->ss_counter < (chip->ss_idle_period / POLLING_INTERVAL)) - chip->ss_counter++; - else - rtsx_exclusive_enter_ss(chip); -} - -static void rtsx_manage_aspm(struct rtsx_chip *chip) -{ - u8 data; - - if (!CHECK_PID(chip, 0x5208)) - return; - - rtsx_monitor_aspm_config(chip); - -#ifdef SUPPORT_SDIO_ASPM - if (!CHK_SDIO_EXIST(chip) || CHK_SDIO_IGNORED(chip) || - !chip->aspm_l0s_l1_en || !chip->dynamic_aspm) - return; - - if (chip->sd_io) { - dynamic_configure_sdio_aspm(chip); - return; - } - - if (chip->sdio_aspm) - return; - - dev_dbg(rtsx_dev(chip), "SDIO enter ASPM!\n"); - data = 0x30 | (chip->aspm_level[1] << 2); - rtsx_write_register(chip, ASPM_FORCE_CTL, 0xFC, data); - chip->sdio_aspm = 1; -#endif -} - -static void rtsx_manage_idle(struct rtsx_chip *chip) -{ - if (chip->idle_counter < IDLE_MAX_COUNT) { - chip->idle_counter++; - return; - } - - if (rtsx_get_stat(chip) == RTSX_STAT_IDLE) - return; - - dev_dbg(rtsx_dev(chip), "Idle state!\n"); - rtsx_set_stat(chip, RTSX_STAT_IDLE); - -#if !defined(LED_AUTO_BLINK) && defined(REGULAR_BLINK) - chip->led_toggle_counter = 0; -#endif - rtsx_force_power_on(chip, SSC_PDCTL); - - turn_off_led(chip, LED_GPIO); - - if (chip->auto_power_down && !chip->card_ready && !chip->sd_io) - rtsx_force_power_down(chip, SSC_PDCTL | OC_PDCTL); -} - -static void rtsx_manage_2lun_mode(struct rtsx_chip *chip) -{ -#ifdef SUPPORT_OCP - u8 sd_oc, ms_oc; - - sd_oc = chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER); - ms_oc = chip->ocp_stat & (MS_OC_NOW | MS_OC_EVER); - - if (sd_oc || ms_oc) - dev_dbg(rtsx_dev(chip), "Over current, OCPSTAT is 0x%x\n", - chip->ocp_stat); - - if (sd_oc && (chip->card_exist & SD_CARD)) { - rtsx_write_register(chip, CARD_OE, SD_OUTPUT_EN, 0); - card_power_off(chip, SD_CARD); - chip->card_fail |= SD_CARD; - } - - if (ms_oc && (chip->card_exist & MS_CARD)) { - rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0); - card_power_off(chip, MS_CARD); - chip->card_fail |= MS_CARD; - } -#endif -} - -static void rtsx_manage_1lun_mode(struct rtsx_chip *chip) -{ -#ifdef SUPPORT_OCP - if (!(chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER))) - return; - - dev_dbg(rtsx_dev(chip), "Over current, OCPSTAT is 0x%x\n", - chip->ocp_stat); - - if (chip->card_exist & SD_CARD) { - rtsx_write_register(chip, CARD_OE, SD_OUTPUT_EN, 0); - chip->card_fail |= SD_CARD; - } else if (chip->card_exist & MS_CARD) { - rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0); - chip->card_fail |= MS_CARD; - } else if (chip->card_exist & XD_CARD) { - rtsx_write_register(chip, CARD_OE, XD_OUTPUT_EN, 0); - chip->card_fail |= XD_CARD; - } - card_power_off(chip, SD_CARD); -#endif -} - -static void rtsx_delink_stage1(struct rtsx_chip *chip, int enter_L1, - int stage3_cnt) -{ - u8 val; - - rtsx_set_stat(chip, RTSX_STAT_DELINK); - - if (chip->asic_code && CHECK_PID(chip, 0x5208)) - rtsx_set_phy_reg_bit(chip, 0x1C, 2); - - if (chip->card_exist) - dev_dbg(rtsx_dev(chip), "False card inserted, do force delink\n"); - else - dev_dbg(rtsx_dev(chip), "No card inserted, do delink\n"); - - if (enter_L1) - rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 1); - - if (chip->card_exist) - val = 0x02; - else - val = 0x0A; - - rtsx_write_register(chip, CHANGE_LINK_STATE, val, val); - - if (enter_L1) - rtsx_enter_L1(chip); - - if (chip->card_exist) - chip->auto_delink_cnt = stage3_cnt + 1; -} - -static void rtsx_delink_stage(struct rtsx_chip *chip) -{ - int delink_stage1_cnt, delink_stage2_cnt, delink_stage3_cnt; - int enter_L1; - - if (!chip->auto_delink_en || !chip->auto_delink_allowed || - chip->card_ready || chip->card_ejected || chip->sd_io) { - chip->auto_delink_cnt = 0; - return; - } - - enter_L1 = chip->auto_delink_in_L1 && - (chip->aspm_l0s_l1_en || chip->ss_en); - - delink_stage1_cnt = chip->delink_stage1_step; - delink_stage2_cnt = delink_stage1_cnt + chip->delink_stage2_step; - delink_stage3_cnt = delink_stage2_cnt + chip->delink_stage3_step; - - if (chip->auto_delink_cnt > delink_stage3_cnt) - return; - - if (chip->auto_delink_cnt == delink_stage1_cnt) - rtsx_delink_stage1(chip, enter_L1, delink_stage3_cnt); - - if (chip->auto_delink_cnt == delink_stage2_cnt) { - dev_dbg(rtsx_dev(chip), "Try to do force delink\n"); - - if (enter_L1) - rtsx_exit_L1(chip); - - if (chip->asic_code && CHECK_PID(chip, 0x5208)) - rtsx_set_phy_reg_bit(chip, 0x1C, 2); - - rtsx_write_register(chip, CHANGE_LINK_STATE, 0x0A, 0x0A); - } - - chip->auto_delink_cnt++; -} - -void rtsx_polling_func(struct rtsx_chip *chip) -{ - if (rtsx_chk_stat(chip, RTSX_STAT_SUSPEND)) - return; - - if (rtsx_chk_stat(chip, RTSX_STAT_DELINK)) - goto delink_stage; - - if (chip->polling_config) { - u8 val; - - rtsx_read_config_byte(chip, 0, &val); - } - - if (rtsx_chk_stat(chip, RTSX_STAT_SS)) - return; - - rtsx_manage_ocp(chip); - - rtsx_manage_sd_lock(chip); - - rtsx_init_cards(chip); - - rtsx_manage_ss(chip); - - rtsx_manage_aspm(chip); - - rtsx_manage_idle(chip); - - switch (rtsx_get_stat(chip)) { - case RTSX_STAT_RUN: -#if !defined(LED_AUTO_BLINK) && defined(REGULAR_BLINK) - rtsx_blink_led(chip); -#endif - do_remaining_work(chip); - break; - - case RTSX_STAT_IDLE: - if (chip->sd_io && !chip->sd_int) - try_to_switch_sdio_ctrl(chip); - - rtsx_enable_aspm(chip); - break; - - default: - break; - } - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) - rtsx_manage_2lun_mode(chip); - else - rtsx_manage_1lun_mode(chip); - -delink_stage: - rtsx_delink_stage(chip); -} - -/** - * rtsx_stop_cmd - stop command transfer and DMA transfer - * @chip: Realtek's card reader chip - * @card: flash card type - * - * Stop command transfer and DMA transfer. - * This function is called in error handler. - */ -void rtsx_stop_cmd(struct rtsx_chip *chip, int card) -{ - int i; - - for (i = 0; i <= 8; i++) { - int addr = RTSX_HCBAR + i * 4; - u32 reg; - - reg = rtsx_readl(chip, addr); - dev_dbg(rtsx_dev(chip), "BAR (0x%02x): 0x%08x\n", addr, reg); - } - rtsx_writel(chip, RTSX_HCBCTLR, STOP_CMD); - rtsx_writel(chip, RTSX_HDBCTLR, STOP_DMA); - - for (i = 0; i < 16; i++) { - u16 addr = 0xFE20 + (u16)i; - u8 val; - - rtsx_read_register(chip, addr, &val); - dev_dbg(rtsx_dev(chip), "0x%04X: 0x%02x\n", addr, val); - } - - rtsx_write_register(chip, DMACTL, 0x80, 0x80); - rtsx_write_register(chip, RBCTL, 0x80, 0x80); -} - -#define MAX_RW_REG_CNT 1024 - -int rtsx_write_register(struct rtsx_chip *chip, u16 addr, u8 mask, u8 data) -{ - int i; - u32 val = 3 << 30; - - val |= (u32)(addr & 0x3FFF) << 16; - val |= (u32)mask << 8; - val |= (u32)data; - - rtsx_writel(chip, RTSX_HAIMR, val); - - for (i = 0; i < MAX_RW_REG_CNT; i++) { - val = rtsx_readl(chip, RTSX_HAIMR); - if ((val & BIT(31)) == 0) { - if (data != (u8)val) - return STATUS_FAIL; - - return STATUS_SUCCESS; - } - } - - return STATUS_TIMEDOUT; -} - -int rtsx_read_register(struct rtsx_chip *chip, u16 addr, u8 *data) -{ - u32 val = 2 << 30; - int i; - - if (data) - *data = 0; - - val |= (u32)(addr & 0x3FFF) << 16; - - rtsx_writel(chip, RTSX_HAIMR, val); - - for (i = 0; i < MAX_RW_REG_CNT; i++) { - val = rtsx_readl(chip, RTSX_HAIMR); - if ((val & BIT(31)) == 0) - break; - } - - if (i >= MAX_RW_REG_CNT) - return STATUS_TIMEDOUT; - - if (data) - *data = (u8)(val & 0xFF); - - return STATUS_SUCCESS; -} - -int rtsx_write_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 mask, - u32 val) -{ - int retval; - u8 mode = 0, tmp; - int i; - - for (i = 0; i < 4; i++) { - if (mask & 0xFF) { - retval = rtsx_write_register(chip, CFGDATA0 + i, - 0xFF, - (u8)(val & mask & 0xFF)); - if (retval) - return retval; - mode |= (1 << i); - } - mask >>= 8; - val >>= 8; - } - - if (mode) { - retval = rtsx_write_register(chip, CFGADDR0, 0xFF, (u8)addr); - if (retval) - return retval; - retval = rtsx_write_register(chip, CFGADDR1, 0xFF, - (u8)(addr >> 8)); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CFGRWCTL, 0xFF, - 0x80 | mode | - ((func_no & 0x03) << 4)); - if (retval) - return retval; - - for (i = 0; i < MAX_RW_REG_CNT; i++) { - retval = rtsx_read_register(chip, CFGRWCTL, &tmp); - if (retval) - return retval; - if ((tmp & 0x80) == 0) - break; - } - } - - return STATUS_SUCCESS; -} - -int rtsx_read_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 *val) -{ - int retval; - int i; - u8 tmp; - u32 data = 0; - - retval = rtsx_write_register(chip, CFGADDR0, 0xFF, (u8)addr); - if (retval) - return retval; - retval = rtsx_write_register(chip, CFGADDR1, 0xFF, (u8)(addr >> 8)); - if (retval) - return retval; - retval = rtsx_write_register(chip, CFGRWCTL, 0xFF, - 0x80 | ((func_no & 0x03) << 4)); - if (retval) - return retval; - - for (i = 0; i < MAX_RW_REG_CNT; i++) { - retval = rtsx_read_register(chip, CFGRWCTL, &tmp); - if (retval) - return retval; - if ((tmp & 0x80) == 0) - break; - } - - for (i = 0; i < 4; i++) { - retval = rtsx_read_register(chip, CFGDATA0 + i, &tmp); - if (retval) - return retval; - data |= (u32)tmp << (i * 8); - } - - if (val) - *val = data; - - return STATUS_SUCCESS; -} - -int rtsx_write_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf, - int len) -{ - u32 *data, *mask; - u16 offset = addr % 4; - u16 aligned_addr = addr - offset; - int dw_len, i, j; - int retval; - size_t size; - - if (!buf) - return STATUS_NOMEM; - - if ((len + offset) % 4) - dw_len = (len + offset) / 4 + 1; - else - dw_len = (len + offset) / 4; - - dev_dbg(rtsx_dev(chip), "dw_len = %d\n", dw_len); - - size = array_size(dw_len, 4); - data = vzalloc(size); - if (!data) - return STATUS_NOMEM; - - mask = vzalloc(size); - if (!mask) { - vfree(data); - return STATUS_NOMEM; - } - - j = 0; - for (i = 0; i < len; i++) { - mask[j] |= 0xFF << (offset * 8); - data[j] |= buf[i] << (offset * 8); - if (++offset == 4) { - j++; - offset = 0; - } - } - - print_hex_dump_bytes(KBUILD_MODNAME ": ", DUMP_PREFIX_NONE, mask, size); - print_hex_dump_bytes(KBUILD_MODNAME ": ", DUMP_PREFIX_NONE, data, size); - - for (i = 0; i < dw_len; i++) { - retval = rtsx_write_cfg_dw(chip, func, aligned_addr + i * 4, - mask[i], data[i]); - if (retval != STATUS_SUCCESS) { - vfree(data); - vfree(mask); - return STATUS_FAIL; - } - } - - vfree(data); - vfree(mask); - - return STATUS_SUCCESS; -} - -int rtsx_read_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf, - int len) -{ - u32 *data; - u16 offset = addr % 4; - u16 aligned_addr = addr - offset; - int dw_len, i, j; - int retval; - - if ((len + offset) % 4) - dw_len = (len + offset) / 4 + 1; - else - dw_len = (len + offset) / 4; - - dev_dbg(rtsx_dev(chip), "dw_len = %d\n", dw_len); - - data = vmalloc(array_size(dw_len, 4)); - if (!data) - return STATUS_NOMEM; - - for (i = 0; i < dw_len; i++) { - retval = rtsx_read_cfg_dw(chip, func, aligned_addr + i * 4, - data + i); - if (retval != STATUS_SUCCESS) { - vfree(data); - return STATUS_FAIL; - } - } - - if (buf) { - j = 0; - - for (i = 0; i < len; i++) { - buf[i] = (u8)(data[j] >> (offset * 8)); - if (++offset == 4) { - j++; - offset = 0; - } - } - } - - vfree(data); - - return STATUS_SUCCESS; -} - -int rtsx_write_phy_register(struct rtsx_chip *chip, u8 addr, u16 val) -{ - int retval; - bool finished = false; - int i; - u8 tmp; - - retval = rtsx_write_register(chip, PHYDATA0, 0xFF, (u8)val); - if (retval) - return retval; - retval = rtsx_write_register(chip, PHYDATA1, 0xFF, (u8)(val >> 8)); - if (retval) - return retval; - retval = rtsx_write_register(chip, PHYADDR, 0xFF, addr); - if (retval) - return retval; - retval = rtsx_write_register(chip, PHYRWCTL, 0xFF, 0x81); - if (retval) - return retval; - - for (i = 0; i < 100000; i++) { - retval = rtsx_read_register(chip, PHYRWCTL, &tmp); - if (retval) - return retval; - if (!(tmp & 0x80)) { - finished = true; - break; - } - } - - if (!finished) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -int rtsx_read_phy_register(struct rtsx_chip *chip, u8 addr, u16 *val) -{ - int retval; - bool finished = false; - int i; - u16 data = 0; - u8 tmp; - - retval = rtsx_write_register(chip, PHYADDR, 0xFF, addr); - if (retval) - return retval; - retval = rtsx_write_register(chip, PHYRWCTL, 0xFF, 0x80); - if (retval) - return retval; - - for (i = 0; i < 100000; i++) { - retval = rtsx_read_register(chip, PHYRWCTL, &tmp); - if (retval) - return retval; - if (!(tmp & 0x80)) { - finished = true; - break; - } - } - - if (!finished) - return STATUS_FAIL; - - retval = rtsx_read_register(chip, PHYDATA0, &tmp); - if (retval) - return retval; - data = tmp; - retval = rtsx_read_register(chip, PHYDATA1, &tmp); - if (retval) - return retval; - data |= (u16)tmp << 8; - - if (val) - *val = data; - - return STATUS_SUCCESS; -} - -int rtsx_read_efuse(struct rtsx_chip *chip, u8 addr, u8 *val) -{ - int retval; - int i; - u8 data = 0; - - retval = rtsx_write_register(chip, EFUSE_CTRL, 0xFF, 0x80 | addr); - if (retval) - return retval; - - for (i = 0; i < 100; i++) { - retval = rtsx_read_register(chip, EFUSE_CTRL, &data); - if (retval) - return retval; - if (!(data & 0x80)) - break; - udelay(1); - } - - if (data & 0x80) - return STATUS_TIMEDOUT; - - retval = rtsx_read_register(chip, EFUSE_DATA, &data); - if (retval) - return retval; - if (val) - *val = data; - - return STATUS_SUCCESS; -} - -int rtsx_write_efuse(struct rtsx_chip *chip, u8 addr, u8 val) -{ - int retval; - int i, j; - u8 data = 0, tmp = 0xFF; - - for (i = 0; i < 8; i++) { - if (val & (u8)(1 << i)) - continue; - - tmp &= (~(u8)(1 << i)); - dev_dbg(rtsx_dev(chip), "Write 0x%x to 0x%x\n", tmp, addr); - - retval = rtsx_write_register(chip, EFUSE_DATA, 0xFF, tmp); - if (retval) - return retval; - retval = rtsx_write_register(chip, EFUSE_CTRL, 0xFF, - 0xA0 | addr); - if (retval) - return retval; - - for (j = 0; j < 100; j++) { - retval = rtsx_read_register(chip, EFUSE_CTRL, &data); - if (retval) - return retval; - if (!(data & 0x80)) - break; - wait_timeout(3); - } - - if (data & 0x80) - return STATUS_TIMEDOUT; - - wait_timeout(5); - } - - return STATUS_SUCCESS; -} - -int rtsx_clr_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit) -{ - int retval; - u16 value; - - retval = rtsx_read_phy_register(chip, reg, &value); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (value & (1 << bit)) { - value &= ~(1 << bit); - retval = rtsx_write_phy_register(chip, reg, value); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -int rtsx_set_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit) -{ - int retval; - u16 value; - - retval = rtsx_read_phy_register(chip, reg, &value); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if ((value & (1 << bit)) == 0) { - value |= (1 << bit); - retval = rtsx_write_phy_register(chip, reg, value); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static void rtsx_handle_pm_dstate(struct rtsx_chip *chip, u8 dstate) -{ - u32 ultmp; - - dev_dbg(rtsx_dev(chip), "%04x set pm_dstate to %d\n", - chip->product_id, dstate); - - if (CHK_SDIO_EXIST(chip)) { - u8 func_no; - - if (CHECK_PID(chip, 0x5288)) - func_no = 2; - else - func_no = 1; - - rtsx_read_cfg_dw(chip, func_no, 0x84, &ultmp); - dev_dbg(rtsx_dev(chip), "pm_dstate of function %d: 0x%x\n", - (int)func_no, ultmp); - rtsx_write_cfg_dw(chip, func_no, 0x84, 0xFF, dstate); - } - - rtsx_write_config_byte(chip, 0x44, dstate); - rtsx_write_config_byte(chip, 0x45, 0); -} - -void rtsx_enter_L1(struct rtsx_chip *chip) -{ - rtsx_handle_pm_dstate(chip, 2); -} - -void rtsx_exit_L1(struct rtsx_chip *chip) -{ - rtsx_write_config_byte(chip, 0x44, 0); - rtsx_write_config_byte(chip, 0x45, 0); -} - -void rtsx_enter_ss(struct rtsx_chip *chip) -{ - dev_dbg(rtsx_dev(chip), "Enter Selective Suspend State!\n"); - - rtsx_write_register(chip, IRQSTAT0, LINK_RDY_INT, LINK_RDY_INT); - - if (chip->power_down_in_ss) { - rtsx_power_off_card(chip); - rtsx_force_power_down(chip, SSC_PDCTL | OC_PDCTL); - } - - if (CHK_SDIO_EXIST(chip)) - rtsx_write_cfg_dw(chip, CHECK_PID(chip, 0x5288) ? 2 : 1, - 0xC0, 0xFF00, 0x0100); - - if (chip->auto_delink_en) { - rtsx_write_register(chip, HOST_SLEEP_STATE, 0x01, 0x01); - } else { - if (!chip->phy_debug_mode) { - u32 tmp; - - tmp = rtsx_readl(chip, RTSX_BIER); - tmp |= CARD_INT; - rtsx_writel(chip, RTSX_BIER, tmp); - } - - rtsx_write_register(chip, CHANGE_LINK_STATE, 0x02, 0); - } - - rtsx_enter_L1(chip); - - RTSX_CLR_DELINK(chip); - rtsx_set_stat(chip, RTSX_STAT_SS); -} - -void rtsx_exit_ss(struct rtsx_chip *chip) -{ - dev_dbg(rtsx_dev(chip), "Exit Selective Suspend State!\n"); - - rtsx_exit_L1(chip); - - if (chip->power_down_in_ss) { - rtsx_force_power_on(chip, SSC_PDCTL | OC_PDCTL); - udelay(1000); - } - - if (RTSX_TST_DELINK(chip)) { - chip->need_reinit = SD_CARD | MS_CARD | XD_CARD; - rtsx_reinit_cards(chip, 1); - RTSX_CLR_DELINK(chip); - } else if (chip->power_down_in_ss) { - chip->need_reinit = SD_CARD | MS_CARD | XD_CARD; - rtsx_reinit_cards(chip, 0); - } -} - -int rtsx_pre_handle_interrupt(struct rtsx_chip *chip) -{ - u32 status, int_enable; - bool exit_ss = false; -#ifdef SUPPORT_OCP - u32 ocp_int = 0; - - ocp_int = OC_INT; -#endif - - if (chip->ss_en) { - chip->ss_counter = 0; - if (rtsx_get_stat(chip) == RTSX_STAT_SS) { - exit_ss = true; - rtsx_exit_L1(chip); - rtsx_set_stat(chip, RTSX_STAT_RUN); - } - } - - int_enable = rtsx_readl(chip, RTSX_BIER); - chip->int_reg = rtsx_readl(chip, RTSX_BIPR); - - if (((chip->int_reg & int_enable) == 0) || - chip->int_reg == 0xFFFFFFFF) - return STATUS_FAIL; - - status = chip->int_reg &= (int_enable | 0x7FFFFF); - - if (status & CARD_INT) { - chip->auto_delink_cnt = 0; - - if (status & SD_INT) { - if (status & SD_EXIST) { - set_bit(SD_NR, &chip->need_reset); - } else { - set_bit(SD_NR, &chip->need_release); - chip->sd_reset_counter = 0; - chip->sd_show_cnt = 0; - clear_bit(SD_NR, &chip->need_reset); - } - } else { - /* - * If multi-luns, it's possible that - * when plugging/unplugging one card - * there is another card which still - * exists in the slot. In this case, - * all existed cards should be reset. - */ - if (exit_ss && (status & SD_EXIST)) - set_bit(SD_NR, &chip->need_reinit); - } - if (!CHECK_PID(chip, 0x5288) || CHECK_BARO_PKG(chip, QFN)) { - if (status & XD_INT) { - if (status & XD_EXIST) { - set_bit(XD_NR, &chip->need_reset); - } else { - set_bit(XD_NR, &chip->need_release); - chip->xd_reset_counter = 0; - chip->xd_show_cnt = 0; - clear_bit(XD_NR, &chip->need_reset); - } - } else { - if (exit_ss && (status & XD_EXIST)) - set_bit(XD_NR, &chip->need_reinit); - } - } - if (status & MS_INT) { - if (status & MS_EXIST) { - set_bit(MS_NR, &chip->need_reset); - } else { - set_bit(MS_NR, &chip->need_release); - chip->ms_reset_counter = 0; - chip->ms_show_cnt = 0; - clear_bit(MS_NR, &chip->need_reset); - } - } else { - if (exit_ss && (status & MS_EXIST)) - set_bit(MS_NR, &chip->need_reinit); - } - } - -#ifdef SUPPORT_OCP - chip->ocp_int = ocp_int & status; -#endif - - if (chip->sd_io && (chip->int_reg & DATA_DONE_INT)) - chip->int_reg &= ~(u32)DATA_DONE_INT; - - return STATUS_SUCCESS; -} - -void rtsx_do_before_power_down(struct rtsx_chip *chip, int pm_stat) -{ - int retval; - - dev_dbg(rtsx_dev(chip), "%s, pm_stat = %d\n", __func__, pm_stat); - - rtsx_set_stat(chip, RTSX_STAT_SUSPEND); - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) - return; - - rtsx_release_cards(chip); - rtsx_disable_bus_int(chip); - turn_off_led(chip, LED_GPIO); - -#ifdef HW_AUTO_SWITCH_SD_BUS - if (chip->sd_io) { - chip->sdio_in_charge = 1; - if (CHECK_PID(chip, 0x5208)) { - rtsx_write_register(chip, TLPTISTAT, 0x08, 0x08); - /* Enable sdio_bus_auto_switch */ - rtsx_write_register(chip, 0xFE70, 0x80, 0x80); - } else if (CHECK_PID(chip, 0x5288)) { - rtsx_write_register(chip, TLPTISTAT, 0x08, 0x08); - /* Enable sdio_bus_auto_switch */ - rtsx_write_register(chip, 0xFE5A, 0x08, 0x08); - } - } -#endif - - if (CHECK_PID(chip, 0x5208) && chip->ic_version >= IC_VER_D) { - /* u_force_clkreq_0 */ - rtsx_write_register(chip, PETXCFG, 0x08, 0x08); - } - - if (pm_stat == PM_S1) { - dev_dbg(rtsx_dev(chip), "Host enter S1\n"); - rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, - HOST_ENTER_S1); - } else if (pm_stat == PM_S3) { - if (chip->s3_pwr_off_delay > 0) - wait_timeout(chip->s3_pwr_off_delay); - - dev_dbg(rtsx_dev(chip), "Host enter S3\n"); - rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, - HOST_ENTER_S3); - } - - if (chip->do_delink_before_power_down && chip->auto_delink_en) - rtsx_write_register(chip, CHANGE_LINK_STATE, 0x02, 2); - - rtsx_force_power_down(chip, SSC_PDCTL | OC_PDCTL); - - chip->cur_clk = 0; - chip->cur_card = 0; - chip->card_exist = 0; -} - -void rtsx_enable_aspm(struct rtsx_chip *chip) -{ - if (chip->aspm_l0s_l1_en && chip->dynamic_aspm && !chip->aspm_enabled) { - dev_dbg(rtsx_dev(chip), "Try to enable ASPM\n"); - chip->aspm_enabled = 1; - - if (chip->asic_code && CHECK_PID(chip, 0x5208)) - rtsx_write_phy_register(chip, 0x07, 0); - if (CHECK_PID(chip, 0x5208)) { - rtsx_write_register(chip, ASPM_FORCE_CTL, 0xF3, - 0x30 | chip->aspm_level[0]); - } else { - rtsx_write_config_byte(chip, LCTLR, - chip->aspm_l0s_l1_en); - } - - if (CHK_SDIO_EXIST(chip)) { - u16 val = chip->aspm_l0s_l1_en | 0x0100; - - rtsx_write_cfg_dw(chip, CHECK_PID(chip, 0x5288) ? 2 : 1, - 0xC0, 0xFFF, val); - } - } -} - -void rtsx_disable_aspm(struct rtsx_chip *chip) -{ - if (CHECK_PID(chip, 0x5208)) - rtsx_monitor_aspm_config(chip); - - if (chip->aspm_l0s_l1_en && chip->dynamic_aspm && chip->aspm_enabled) { - dev_dbg(rtsx_dev(chip), "Try to disable ASPM\n"); - chip->aspm_enabled = 0; - - if (chip->asic_code && CHECK_PID(chip, 0x5208)) - rtsx_write_phy_register(chip, 0x07, 0x0129); - if (CHECK_PID(chip, 0x5208)) - rtsx_write_register(chip, ASPM_FORCE_CTL, - 0xF3, 0x30); - else - rtsx_write_config_byte(chip, LCTLR, 0x00); - - wait_timeout(1); - } -} - -int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) -{ - int retval; - int i, j; - u16 reg_addr; - u8 *ptr; - - if (!buf) - return STATUS_ERROR; - - ptr = buf; - reg_addr = PPBUF_BASE2; - for (i = 0; i < buf_len / 256; i++) { - rtsx_init_cmd(chip); - - for (j = 0; j < 256; j++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr++, 0, 0); - - retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) - return STATUS_FAIL; - - memcpy(ptr, rtsx_get_cmd_data(chip), 256); - ptr += 256; - } - - if (buf_len % 256) { - rtsx_init_cmd(chip); - - for (j = 0; j < buf_len % 256; j++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr++, 0, 0); - - retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) - return STATUS_FAIL; - } - - memcpy(ptr, rtsx_get_cmd_data(chip), buf_len % 256); - - return STATUS_SUCCESS; -} - -int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) -{ - int retval; - int i, j; - u16 reg_addr; - u8 *ptr; - - if (!buf) - return STATUS_ERROR; - - ptr = buf; - reg_addr = PPBUF_BASE2; - for (i = 0; i < buf_len / 256; i++) { - rtsx_init_cmd(chip); - - for (j = 0; j < 256; j++) { - rtsx_add_cmd(chip, WRITE_REG_CMD, reg_addr++, 0xFF, - *ptr); - ptr++; - } - - retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) - return STATUS_FAIL; - } - - if (buf_len % 256) { - rtsx_init_cmd(chip); - - for (j = 0; j < buf_len % 256; j++) { - rtsx_add_cmd(chip, WRITE_REG_CMD, reg_addr++, 0xFF, - *ptr); - ptr++; - } - - retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -int rtsx_check_chip_exist(struct rtsx_chip *chip) -{ - if (rtsx_readl(chip, 0) == 0xFFFFFFFF) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -int rtsx_force_power_on(struct rtsx_chip *chip, u8 ctl) -{ - int retval; - u8 mask = 0; - - if (ctl & SSC_PDCTL) - mask |= SSC_POWER_DOWN; - -#ifdef SUPPORT_OCP - if (ctl & OC_PDCTL) { - mask |= SD_OC_POWER_DOWN; - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) - mask |= MS_OC_POWER_DOWN; - } -#endif - - if (mask) { - retval = rtsx_write_register(chip, FPDCTL, mask, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHECK_PID(chip, 0x5288)) - wait_timeout(200); - } - - return STATUS_SUCCESS; -} - -int rtsx_force_power_down(struct rtsx_chip *chip, u8 ctl) -{ - int retval; - u8 mask = 0, val = 0; - - if (ctl & SSC_PDCTL) - mask |= SSC_POWER_DOWN; - -#ifdef SUPPORT_OCP - if (ctl & OC_PDCTL) { - mask |= SD_OC_POWER_DOWN; - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) - mask |= MS_OC_POWER_DOWN; - } -#endif - - if (mask) { - val = mask; - retval = rtsx_write_register(chip, FPDCTL, mask, val); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} diff --git a/drivers/staging/rts5208/rtsx_chip.h b/drivers/staging/rts5208/rtsx_chip.h deleted file mode 100644 index bac65784d4a198..00000000000000 --- a/drivers/staging/rts5208/rtsx_chip.h +++ /dev/null @@ -1,987 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_CHIP_H -#define __REALTEK_RTSX_CHIP_H - -#include "rtsx.h" - -#define SUPPORT_CPRM -#define SUPPORT_OCP -#define SUPPORT_SDIO_ASPM -#define SUPPORT_MAGIC_GATE -#define SUPPORT_MSXC -#define SUPPORT_SD_LOCK -/* Hardware switch bus_ctl and cd_ctl automatically */ -#define HW_AUTO_SWITCH_SD_BUS -/* Enable hardware interrupt write clear */ -#define HW_INT_WRITE_CLR -/* #define LED_AUTO_BLINK */ -/* #define DISABLE_CARD_INT */ - -#ifdef SUPPORT_MAGIC_GATE - /* Using NORMAL_WRITE instead of AUTO_WRITE to set ICV */ - #define MG_SET_ICV_SLOW - /* HW may miss ERR/CMDNK signal when sampling INT status. */ - #define MS_SAMPLE_INT_ERR - /* - * HW DO NOT support Wait_INT function - * during READ_BYTES transfer mode - */ - #define READ_BYTES_WAIT_INT -#endif - -#ifdef SUPPORT_MSXC -#define XC_POWERCLASS -#define SUPPORT_PCGL_1P18 -#endif - -#ifndef LED_AUTO_BLINK -#define REGULAR_BLINK -#endif - -#define LED_BLINK_SPEED 5 -#define LED_TOGGLE_INTERVAL 6 -#define GPIO_TOGGLE_THRESHOLD 1024 -#define LED_GPIO 0 - -#define POLLING_INTERVAL 30 - -#define TRACE_ITEM_CNT 64 - -#ifndef STATUS_SUCCESS -#define STATUS_SUCCESS 0 -#endif -#ifndef STATUS_FAIL -#define STATUS_FAIL 1 -#endif -#ifndef STATUS_TIMEDOUT -#define STATUS_TIMEDOUT 2 -#endif -#ifndef STATUS_NOMEM -#define STATUS_NOMEM 3 -#endif -#ifndef STATUS_READ_FAIL -#define STATUS_READ_FAIL 4 -#endif -#ifndef STATUS_WRITE_FAIL -#define STATUS_WRITE_FAIL 5 -#endif -#ifndef STATUS_ERROR -#define STATUS_ERROR 10 -#endif - -#define PM_S1 1 -#define PM_S3 3 - -/* - * Transport return codes - */ - -#define TRANSPORT_GOOD 0 /* Transport good, command good */ -#define TRANSPORT_FAILED 1 /* Transport good, command failed */ -#define TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */ -#define TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */ - -/* - * Start-Stop-Unit - */ -#define STOP_MEDIUM 0x00 /* access disable */ -#define MAKE_MEDIUM_READY 0x01 /* access enable */ -#define UNLOAD_MEDIUM 0x02 /* unload */ -#define LOAD_MEDIUM 0x03 /* load */ - -/* - * STANDARD_INQUIRY - */ -#define QULIFIRE 0x00 -#define AENC_FNC 0x00 -#define TRML_IOP 0x00 -#define REL_ADR 0x00 -#define WBUS_32 0x00 -#define WBUS_16 0x00 -#define SYNC 0x00 -#define LINKED 0x00 -#define CMD_QUE 0x00 -#define SFT_RE 0x00 - -#define VEN_ID_LEN 8 /* Vendor ID Length */ -#define PRDCT_ID_LEN 16 /* Product ID Length */ -#define PRDCT_REV_LEN 4 /* Product LOT Length */ - -/* Dynamic flag definitions: used in set_bit() etc. */ -/* 0x00040000 transfer is active */ -#define RTSX_FLIDX_TRANS_ACTIVE 18 -/* 0x00100000 abort is in progress */ -#define RTSX_FLIDX_ABORTING 20 -/* 0x00200000 disconnect in progress */ -#define RTSX_FLIDX_DISCONNECTING 21 - -#define ABORTING_OR_DISCONNECTING ((1UL << US_FLIDX_ABORTING) | \ - (1UL << US_FLIDX_DISCONNECTING)) - -/* 0x00400000 device reset in progress */ -#define RTSX_FLIDX_RESETTING 22 -/* 0x00800000 SCSI midlayer timed out */ -#define RTSX_FLIDX_TIMED_OUT 23 -#define DRCT_ACCESS_DEV 0x00 /* Direct Access Device */ -#define RMB_DISC 0x80 /* The Device is Removable */ -#define ANSI_SCSI2 0x02 /* Based on ANSI-SCSI2 */ - -#define SCSI 0x00 /* Interface ID */ - -#define WRITE_PROTECTED_MEDIA 0x07 - -/*---- sense key ----*/ -#define ILI 0x20 /* ILI bit is on */ - -#define NO_SENSE 0x00 /* not exist sense key */ -#define RECOVER_ERR 0x01 /* Target/Logical unit is recoverd */ -#define NOT_READY 0x02 /* Logical unit is not ready */ -#define MEDIA_ERR 0x03 /* medium/data error */ -#define HARDWARE_ERR 0x04 /* hardware error */ -#define ILGAL_REQ 0x05 /* CDB/parameter/identify msg error */ -#define UNIT_ATTENTION 0x06 /* unit attention condition occur */ -#define DAT_PRTCT 0x07 /* read/write is desable */ -#define BLNC_CHK 0x08 /* find blank/DOF in read */ - /* write to unblank area */ -#define CPY_ABRT 0x0a /* Copy/Compare/Copy&Verify illegal */ -#define ABRT_CMD 0x0b /* Target make the command in error */ -#define EQUAL 0x0c /* Search Data end with Equal */ -#define VLM_OVRFLW 0x0d /* Some data are left in buffer */ -#define MISCMP 0x0e /* find inequality */ - -#define READ_ERR -1 -#define WRITE_ERR -2 - -#define FIRST_RESET 0x01 -#define USED_EXIST 0x02 - -/* - * SENSE_DATA - */ -/*---- valid ----*/ -#define SENSE_VALID 0x80 /* Sense data is valid as SCSI2 */ -#define SENSE_INVALID 0x00 /* Sense data is invalid as SCSI2 */ - -/*---- error code ----*/ -#define CUR_ERR 0x70 /* current error */ -#define DEF_ERR 0x71 /* specific command error */ - -/*---- sense key Information ----*/ -#define SNSKEYINFO_LEN 3 /* length of sense key information */ - -#define SKSV 0x80 -#define CDB_ILLEGAL 0x40 -#define DAT_ILLEGAL 0x00 -#define BPV 0x08 -#define BIT_ILLEGAL0 0 /* bit0 is illegal */ -#define BIT_ILLEGAL1 1 /* bit1 is illegal */ -#define BIT_ILLEGAL2 2 /* bit2 is illegal */ -#define BIT_ILLEGAL3 3 /* bit3 is illegal */ -#define BIT_ILLEGAL4 4 /* bit4 is illegal */ -#define BIT_ILLEGAL5 5 /* bit5 is illegal */ -#define BIT_ILLEGAL6 6 /* bit6 is illegal */ -#define BIT_ILLEGAL7 7 /* bit7 is illegal */ - -/*---- ASC ----*/ -#define ASC_NO_INFO 0x00 -#define ASC_MISCMP 0x1d -#define ASC_INVLD_CDB 0x24 -#define ASC_INVLD_PARA 0x26 -#define ASC_LU_NOT_READY 0x04 -#define ASC_WRITE_ERR 0x0c -#define ASC_READ_ERR 0x11 -#define ASC_LOAD_EJCT_ERR 0x53 -#define ASC_MEDIA_NOT_PRESENT 0x3A -#define ASC_MEDIA_CHANGED 0x28 -#define ASC_MEDIA_IN_PROCESS 0x04 -#define ASC_WRITE_PROTECT 0x27 -#define ASC_LUN_NOT_SUPPORTED 0x25 - -/*---- ASQC ----*/ -#define ASCQ_NO_INFO 0x00 -#define ASCQ_MEDIA_IN_PROCESS 0x01 -#define ASCQ_MISCMP 0x00 -#define ASCQ_INVLD_CDB 0x00 -#define ASCQ_INVLD_PARA 0x02 -#define ASCQ_LU_NOT_READY 0x02 -#define ASCQ_WRITE_ERR 0x02 -#define ASCQ_READ_ERR 0x00 -#define ASCQ_LOAD_EJCT_ERR 0x00 -#define ASCQ_WRITE_PROTECT 0x00 - -struct sense_data_t { - unsigned char err_code; /* error code */ - /* bit7 : valid */ - /* (1 : SCSI2) */ - /* (0 : Vendor * specific) */ - /* bit6-0 : error * code */ - /* (0x70 : current * error) */ - /* (0x71 : specific command error) */ - unsigned char seg_no; /* segment No. */ - unsigned char sense_key; /* byte5 : ILI */ - /* bit3-0 : sense key */ - unsigned char info[4]; /* information */ - unsigned char ad_sense_len; /* additional sense data length */ - unsigned char cmd_info[4]; /* command specific information */ - unsigned char asc; /* ASC */ - unsigned char ascq; /* ASCQ */ - unsigned char rfu; /* FRU */ - unsigned char sns_key_info[3];/* sense key specific information */ -}; - -/* PCI Operation Register Address */ -#define RTSX_HCBAR 0x00 -#define RTSX_HCBCTLR 0x04 -#define RTSX_HDBAR 0x08 -#define RTSX_HDBCTLR 0x0C -#define RTSX_HAIMR 0x10 -#define RTSX_BIPR 0x14 -#define RTSX_BIER 0x18 - -/* Host command buffer control register */ -#define STOP_CMD (0x01 << 28) - -/* Host data buffer control register */ -#define SDMA_MODE 0x00 -#define ADMA_MODE (0x02 << 26) -#define STOP_DMA (0x01 << 28) -#define TRIG_DMA (0x01 << 31) - -/* Bus interrupt pending register */ -#define CMD_DONE_INT BIT(31) -#define DATA_DONE_INT BIT(30) -#define TRANS_OK_INT BIT(29) -#define TRANS_FAIL_INT BIT(28) -#define XD_INT BIT(27) -#define MS_INT BIT(26) -#define SD_INT BIT(25) -#define GPIO0_INT BIT(24) -#define OC_INT BIT(23) -#define SD_WRITE_PROTECT BIT(19) -#define XD_EXIST BIT(18) -#define MS_EXIST BIT(17) -#define SD_EXIST BIT(16) -#define DELINK_INT GPIO0_INT -#define MS_OC_INT BIT(23) -#define SD_OC_INT BIT(22) - -#define CARD_INT (XD_INT | MS_INT | SD_INT) -#define NEED_COMPLETE_INT (DATA_DONE_INT | TRANS_OK_INT | TRANS_FAIL_INT) -#define RTSX_INT (CMD_DONE_INT | NEED_COMPLETE_INT | CARD_INT | \ - GPIO0_INT | OC_INT) - -#define CARD_EXIST (XD_EXIST | MS_EXIST | SD_EXIST) - -/* Bus interrupt enable register */ -#define CMD_DONE_INT_EN BIT(31) -#define DATA_DONE_INT_EN BIT(30) -#define TRANS_OK_INT_EN BIT(29) -#define TRANS_FAIL_INT_EN BIT(28) -#define XD_INT_EN BIT(27) -#define MS_INT_EN BIT(26) -#define SD_INT_EN BIT(25) -#define GPIO0_INT_EN BIT(24) -#define OC_INT_EN BIT(23) -#define DELINK_INT_EN GPIO0_INT_EN -#define MS_OC_INT_EN BIT(23) -#define SD_OC_INT_EN BIT(22) - -#define READ_REG_CMD 0 -#define WRITE_REG_CMD 1 -#define CHECK_REG_CMD 2 - -#define HOST_TO_DEVICE 0 -#define DEVICE_TO_HOST 1 - -#define RTSX_RESV_BUF_LEN 4096 -#define HOST_CMDS_BUF_LEN 1024 -#define HOST_SG_TBL_BUF_LEN (RTSX_RESV_BUF_LEN - HOST_CMDS_BUF_LEN) - -#define SD_NR 2 -#define MS_NR 3 -#define XD_NR 4 -#define SPI_NR 7 -#define SD_CARD BIT(SD_NR) -#define MS_CARD BIT(MS_NR) -#define XD_CARD BIT(XD_NR) -#define SPI_CARD BIT(SPI_NR) - -#define MAX_ALLOWED_LUN_CNT 8 - -#define XD_FREE_TABLE_CNT 1200 -#define MS_FREE_TABLE_CNT 512 - -/* Bit Operation */ -#define SET_BIT(data, idx) ((data) |= 1 << (idx)) -#define CLR_BIT(data, idx) ((data) &= ~(1 << (idx))) -#define CHK_BIT(data, idx) ((data) & (1 << (idx))) - -/* SG descriptor */ -#define RTSX_SG_INT 0x04 -#define RTSX_SG_END 0x02 -#define RTSX_SG_VALID 0x01 - -#define RTSX_SG_NO_OP 0x00 -#define RTSX_SG_TRANS_DATA (0x02 << 4) -#define RTSX_SG_LINK_DESC (0x03 << 4) - -struct rtsx_chip; - -typedef int (*card_rw_func)(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 sec_addr, u16 sec_cnt); - -/* Supported Clock */ -enum card_clock {CLK_20 = 1, CLK_30, CLK_40, CLK_50, CLK_60, - CLK_80, CLK_100, CLK_120, CLK_150, CLK_200}; - -enum RTSX_STAT {RTSX_STAT_INIT, RTSX_STAT_IDLE, RTSX_STAT_RUN, RTSX_STAT_SS, - RTSX_STAT_DELINK, RTSX_STAT_SUSPEND, - RTSX_STAT_ABORT, RTSX_STAT_DISCONNECT}; -enum IC_VER {IC_VER_AB, IC_VER_C = 2, IC_VER_D = 3}; - -#define MAX_RESET_CNT 3 - -/* For MS Card */ -#define MAX_DEFECTIVE_BLOCK 10 - -struct zone_entry { - u16 *l2p_table; - u16 *free_table; - u16 defect_list[MAX_DEFECTIVE_BLOCK]; /* For MS card only */ - int set_index; - int get_index; - int unused_blk_cnt; - int disable_count; - /* To indicate whether the L2P table of this zone has been built. */ - int build_flag; -}; - -#define TYPE_SD 0x0000 -#define TYPE_MMC 0x0001 - -/* TYPE_SD */ -#define SD_HS 0x0100 -#define SD_SDR50 0x0200 -#define SD_DDR50 0x0400 -#define SD_SDR104 0x0800 -#define SD_HCXC 0x1000 - -/* TYPE_MMC */ -#define MMC_26M 0x0100 -#define MMC_52M 0x0200 -#define MMC_4BIT 0x0400 -#define MMC_8BIT 0x0800 -#define MMC_SECTOR_MODE 0x1000 -#define MMC_DDR52 0x2000 - -/* SD card */ -#define CHK_SD(sd_card) (((sd_card)->sd_type & 0xFF) == TYPE_SD) -#define CHK_SD_HS(sd_card) (CHK_SD(sd_card) && \ - ((sd_card)->sd_type & SD_HS)) -#define CHK_SD_SDR50(sd_card) (CHK_SD(sd_card) && \ - ((sd_card)->sd_type & SD_SDR50)) -#define CHK_SD_DDR50(sd_card) (CHK_SD(sd_card) && \ - ((sd_card)->sd_type & SD_DDR50)) -#define CHK_SD_SDR104(sd_card) (CHK_SD(sd_card) && \ - ((sd_card)->sd_type & SD_SDR104)) -#define CHK_SD_HCXC(sd_card) (CHK_SD(sd_card) && \ - ((sd_card)->sd_type & SD_HCXC)) -#define CHK_SD_HC(sd_card) (CHK_SD_HCXC(sd_card) && \ - ((sd_card)->capacity <= 0x4000000)) -#define CHK_SD_XC(sd_card) (CHK_SD_HCXC(sd_card) && \ - ((sd_card)->capacity > 0x4000000)) -#define CHK_SD30_SPEED(sd_card) (CHK_SD_SDR50(sd_card) || \ - CHK_SD_DDR50(sd_card) || \ - CHK_SD_SDR104(sd_card)) - -#define SET_SD(sd_card) ((sd_card)->sd_type = TYPE_SD) -#define SET_SD_HS(sd_card) ((sd_card)->sd_type |= SD_HS) -#define SET_SD_SDR50(sd_card) ((sd_card)->sd_type |= SD_SDR50) -#define SET_SD_DDR50(sd_card) ((sd_card)->sd_type |= SD_DDR50) -#define SET_SD_SDR104(sd_card) ((sd_card)->sd_type |= SD_SDR104) -#define SET_SD_HCXC(sd_card) ((sd_card)->sd_type |= SD_HCXC) - -#define CLR_SD_HS(sd_card) ((sd_card)->sd_type &= ~SD_HS) -#define CLR_SD_SDR50(sd_card) ((sd_card)->sd_type &= ~SD_SDR50) -#define CLR_SD_DDR50(sd_card) ((sd_card)->sd_type &= ~SD_DDR50) -#define CLR_SD_SDR104(sd_card) ((sd_card)->sd_type &= ~SD_SDR104) -#define CLR_SD_HCXC(sd_card) ((sd_card)->sd_type &= ~SD_HCXC) - -/* MMC card */ -#define CHK_MMC(sd_card) (((sd_card)->sd_type & 0xFF) == \ - TYPE_MMC) -#define CHK_MMC_26M(sd_card) (CHK_MMC(sd_card) && \ - ((sd_card)->sd_type & MMC_26M)) -#define CHK_MMC_52M(sd_card) (CHK_MMC(sd_card) && \ - ((sd_card)->sd_type & MMC_52M)) -#define CHK_MMC_4BIT(sd_card) (CHK_MMC(sd_card) && \ - ((sd_card)->sd_type & MMC_4BIT)) -#define CHK_MMC_8BIT(sd_card) (CHK_MMC(sd_card) && \ - ((sd_card)->sd_type & MMC_8BIT)) -#define CHK_MMC_SECTOR_MODE(sd_card) (CHK_MMC(sd_card) && \ - ((sd_card)->sd_type & MMC_SECTOR_MODE)) -#define CHK_MMC_DDR52(sd_card) (CHK_MMC(sd_card) && \ - ((sd_card)->sd_type & MMC_DDR52)) - -#define SET_MMC(sd_card) ((sd_card)->sd_type = TYPE_MMC) -#define SET_MMC_26M(sd_card) ((sd_card)->sd_type |= MMC_26M) -#define SET_MMC_52M(sd_card) ((sd_card)->sd_type |= MMC_52M) -#define SET_MMC_4BIT(sd_card) ((sd_card)->sd_type |= MMC_4BIT) -#define SET_MMC_8BIT(sd_card) ((sd_card)->sd_type |= MMC_8BIT) -#define SET_MMC_SECTOR_MODE(sd_card) ((sd_card)->sd_type |= MMC_SECTOR_MODE) -#define SET_MMC_DDR52(sd_card) ((sd_card)->sd_type |= MMC_DDR52) - -#define CLR_MMC_26M(sd_card) ((sd_card)->sd_type &= ~MMC_26M) -#define CLR_MMC_52M(sd_card) ((sd_card)->sd_type &= ~MMC_52M) -#define CLR_MMC_4BIT(sd_card) ((sd_card)->sd_type &= ~MMC_4BIT) -#define CLR_MMC_8BIT(sd_card) ((sd_card)->sd_type &= ~MMC_8BIT) -#define CLR_MMC_SECTOR_MODE(sd_card) ((sd_card)->sd_type &= ~MMC_SECTOR_MODE) -#define CLR_MMC_DDR52(sd_card) ((sd_card)->sd_type &= ~MMC_DDR52) - -#define CHK_MMC_HS(sd_card) (CHK_MMC_52M(sd_card) && \ - CHK_MMC_26M(sd_card)) -#define CLR_MMC_HS(sd_card) \ -do { \ - CLR_MMC_DDR52(sd_card); \ - CLR_MMC_52M(sd_card); \ - CLR_MMC_26M(sd_card); \ -} while (0) - -#define SD_SUPPORT_CLASS_TEN 0x01 -#define SD_SUPPORT_1V8 0x02 - -#define SD_SET_CLASS_TEN(sd_card) ((sd_card)->sd_setting |= \ - SD_SUPPORT_CLASS_TEN) -#define SD_CHK_CLASS_TEN(sd_card) ((sd_card)->sd_setting & \ - SD_SUPPORT_CLASS_TEN) -#define SD_CLR_CLASS_TEN(sd_card) ((sd_card)->sd_setting &= \ - ~SD_SUPPORT_CLASS_TEN) -#define SD_SET_1V8(sd_card) ((sd_card)->sd_setting |= \ - SD_SUPPORT_1V8) -#define SD_CHK_1V8(sd_card) ((sd_card)->sd_setting & \ - SD_SUPPORT_1V8) -#define SD_CLR_1V8(sd_card) ((sd_card)->sd_setting &= \ - ~SD_SUPPORT_1V8) - -struct sd_info { - u16 sd_type; - u8 err_code; - u8 sd_data_buf_ready; - u32 sd_addr; - u32 capacity; - - u8 raw_csd[16]; - u8 raw_scr[8]; - - /* Sequential RW */ - int seq_mode; - enum dma_data_direction pre_dir; - u32 pre_sec_addr; - u16 pre_sec_cnt; - - int cleanup_counter; - - int sd_clock; - - int mmc_dont_switch_bus; - -#ifdef SUPPORT_CPRM - int sd_pass_thru_en; - int pre_cmd_err; - u8 last_rsp_type; - u8 rsp[17]; -#endif - - u8 func_group1_mask; - u8 func_group2_mask; - u8 func_group3_mask; - u8 func_group4_mask; - - u8 sd_switch_fail; - u8 sd_read_phase; - -#ifdef SUPPORT_SD_LOCK - u8 sd_lock_status; - u8 sd_erase_status; - u8 sd_lock_notify; -#endif - int need_retune; -}; - -struct xd_delay_write_tag { - u32 old_phyblock; - u32 new_phyblock; - u32 logblock; - u8 pageoff; - u8 delay_write_flag; -}; - -struct xd_info { - u8 maker_code; - u8 device_code; - u8 block_shift; - u8 page_off; - u8 addr_cycle; - u16 cis_block; - u8 multi_flag; - u8 err_code; - u32 capacity; - - struct zone_entry *zone; - int zone_cnt; - - struct xd_delay_write_tag delay_write; - int cleanup_counter; - - int xd_clock; -}; - -#define MODE_512_SEQ 0x01 -#define MODE_2K_SEQ 0x02 - -#define TYPE_MS 0x0000 -#define TYPE_MSPRO 0x0001 - -#define MS_4BIT 0x0100 -#define MS_8BIT 0x0200 -#define MS_HG 0x0400 -#define MS_XC 0x0800 - -#define HG8BIT (MS_HG | MS_8BIT) - -#define CHK_MSPRO(ms_card) (((ms_card)->ms_type & 0xFF) == TYPE_MSPRO) -#define CHK_HG8BIT(ms_card) (CHK_MSPRO(ms_card) && \ - (((ms_card)->ms_type & HG8BIT) == HG8BIT)) -#define CHK_MSXC(ms_card) (CHK_MSPRO(ms_card) && \ - ((ms_card)->ms_type & MS_XC)) -#define CHK_MSHG(ms_card) (CHK_MSPRO(ms_card) && \ - ((ms_card)->ms_type & MS_HG)) - -#define CHK_MS8BIT(ms_card) (((ms_card)->ms_type & MS_8BIT)) -#define CHK_MS4BIT(ms_card) (((ms_card)->ms_type & MS_4BIT)) - -struct ms_delay_write_tag { - u16 old_phyblock; - u16 new_phyblock; - u16 logblock; - u8 pageoff; - u8 delay_write_flag; -}; - -struct ms_info { - u16 ms_type; - u8 block_shift; - u8 page_off; - u16 total_block; - u16 boot_block; - u32 capacity; - - u8 check_ms_flow; - u8 switch_8bit_fail; - u8 err_code; - - struct zone_entry *segment; - int segment_cnt; - - int pro_under_formatting; - int format_status; - u16 progress; - u8 raw_sys_info[96]; -#ifdef SUPPORT_PCGL_1P18 - u8 raw_model_name[48]; -#endif - - u8 multi_flag; - - /* Sequential RW */ - u8 seq_mode; - enum dma_data_direction pre_dir; - u32 pre_sec_addr; - u16 pre_sec_cnt; - u32 total_sec_cnt; - - struct ms_delay_write_tag delay_write; - - int cleanup_counter; - - int ms_clock; - -#ifdef SUPPORT_MAGIC_GATE - u8 magic_gate_id[16]; - u8 mg_entry_num; - int mg_auth; /* flag to indicate authentication process */ -#endif -}; - -struct spi_info { - u8 use_clk; - u8 write_en; - u16 clk_div; - u8 err_code; - - int spi_clock; -}; - -/************/ -/* LUN mode */ -/************/ -/* Single LUN, support xD/SD/MS */ -#define DEFAULT_SINGLE 0 -/* 2 LUN mode, support SD/MS */ -#define SD_MS_2LUN 1 -/* Single LUN, but only support SD/MS, for Barossa LQFP */ -#define SD_MS_1LUN 2 - -#define LAST_LUN_MODE 2 - -/* Barossa package */ -#define QFN 0 -#define LQFP 1 - -/******************/ -/* sd_ctl bit map */ -/******************/ -/* SD push point control, bit 0, 1 */ -#define SD_PUSH_POINT_CTL_MASK 0x03 -#define SD_PUSH_POINT_DELAY 0x01 -#define SD_PUSH_POINT_AUTO 0x02 -/* SD sample point control, bit 2, 3 */ -#define SD_SAMPLE_POINT_CTL_MASK 0x0C -#define SD_SAMPLE_POINT_DELAY 0x04 -#define SD_SAMPLE_POINT_AUTO 0x08 -/* SD DDR Tx phase set by user, bit 4 */ -#define SD_DDR_TX_PHASE_SET_BY_USER 0x10 -/* MMC DDR Tx phase set by user, bit 5 */ -#define MMC_DDR_TX_PHASE_SET_BY_USER 0x20 -/* Support MMC DDR mode, bit 6 */ -#define SUPPORT_MMC_DDR_MODE 0x40 -/* Reset MMC at first */ -#define RESET_MMC_FIRST 0x80 - -#define SEQ_START_CRITERIA 0x20 - -/* MS Power Class En */ -#define POWER_CLASS_2_EN 0x02 -#define POWER_CLASS_1_EN 0x01 - -#define MAX_SHOW_CNT 10 -#define MAX_RESET_CNT 3 - -#define SDIO_EXIST 0x01 -#define SDIO_IGNORED 0x02 - -#define CHK_SDIO_EXIST(chip) ((chip)->sdio_func_exist & SDIO_EXIST) -#define SET_SDIO_EXIST(chip) ((chip)->sdio_func_exist |= SDIO_EXIST) -#define CLR_SDIO_EXIST(chip) ((chip)->sdio_func_exist &= ~SDIO_EXIST) - -#define CHK_SDIO_IGNORED(chip) ((chip)->sdio_func_exist & SDIO_IGNORED) -#define SET_SDIO_IGNORED(chip) ((chip)->sdio_func_exist |= \ - SDIO_IGNORED) -#define CLR_SDIO_IGNORED(chip) ((chip)->sdio_func_exist &= \ - ~SDIO_IGNORED) - -struct rtsx_chip { - struct rtsx_dev *rtsx; - - u32 int_reg; /* Bus interrupt pending register */ - char max_lun; - void *context; - - void *host_cmds_ptr; /* host commands buffer pointer */ - dma_addr_t host_cmds_addr; - int ci; /* Command Index */ - - void *host_sg_tbl_ptr; /* SG descriptor table */ - dma_addr_t host_sg_tbl_addr; - int sgi; /* SG entry index */ - - struct scsi_cmnd *srb; /* current srb */ - struct sense_data_t sense_buffer[MAX_ALLOWED_LUN_CNT]; - - int cur_clk; /* current card clock */ - - /* Current accessed card */ - int cur_card; - - unsigned long need_release; /* need release bit map */ - unsigned long need_reset; /* need reset bit map */ - /* - * Flag to indicate that this card is just resumed from SS state, - * and need released before being resetted - */ - unsigned long need_reinit; - - int rw_need_retry; - -#ifdef SUPPORT_OCP - u32 ocp_int; - u8 ocp_stat; -#endif - - u8 card_exist; /* card exist bit map (physical exist) */ - u8 card_ready; /* card ready bit map (reset successfully) */ - u8 card_fail; /* card reset fail bit map */ - u8 card_ejected; /* card ejected bit map */ - u8 card_wp; /* card write protected bit map */ - - u8 lun_mc; /* - * flag to indicate whether to answer - * MediaChange - */ - -#ifndef LED_AUTO_BLINK - int led_toggle_counter; -#endif - - int sd_reset_counter; - int xd_reset_counter; - int ms_reset_counter; - - /* card bus width */ - u8 card_bus_width[MAX_ALLOWED_LUN_CNT]; - /* card capacity */ - u32 capacity[MAX_ALLOWED_LUN_CNT]; - /* read/write card function pointer */ - card_rw_func rw_card[MAX_ALLOWED_LUN_CNT]; - /* read/write capacity, used for GPIO Toggle */ - u32 rw_cap[MAX_ALLOWED_LUN_CNT]; - /* card to lun mapping table */ - u8 card2lun[32]; - /* lun to card mapping table */ - u8 lun2card[MAX_ALLOWED_LUN_CNT]; - - int rw_fail_cnt[MAX_ALLOWED_LUN_CNT]; - - int sd_show_cnt; - int xd_show_cnt; - int ms_show_cnt; - - /* card information */ - struct sd_info sd_card; - struct xd_info xd_card; - struct ms_info ms_card; - - struct spi_info spi; - - int auto_delink_cnt; - int auto_delink_allowed; - - int aspm_enabled; - - int sdio_aspm; - int sdio_idle; - int sdio_counter; - u8 sdio_raw_data[12]; - - u8 sd_io; - u8 sd_int; - - u8 rtsx_flag; - - int ss_counter; - int idle_counter; - enum RTSX_STAT rtsx_stat; - - u16 vendor_id; - u16 product_id; - u8 ic_version; - - int driver_first_load; - -#ifdef HW_AUTO_SWITCH_SD_BUS - int sdio_in_charge; -#endif - - u8 aspm_level[2]; - - int chip_insert_with_sdio; - - /* Options */ - - int adma_mode; - - int auto_delink_en; - int ss_en; - u8 lun_mode; - u8 aspm_l0s_l1_en; - - int power_down_in_ss; - - int sdr104_en; - int ddr50_en; - int sdr50_en; - - int baro_pkg; - - int asic_code; - int phy_debug_mode; - int hw_bypass_sd; - int sdio_func_exist; - int aux_pwr_exist; - u8 ms_power_class_en; - - int mspro_formatter_enable; - - int remote_wakeup_en; - - int ignore_sd; - int use_hw_setting; - - int ss_idle_period; - - int dynamic_aspm; - - int fpga_sd_sdr104_clk; - int fpga_sd_ddr50_clk; - int fpga_sd_sdr50_clk; - int fpga_sd_hs_clk; - int fpga_mmc_52m_clk; - int fpga_ms_hg_clk; - int fpga_ms_4bit_clk; - int fpga_ms_1bit_clk; - - int asic_sd_sdr104_clk; - int asic_sd_ddr50_clk; - int asic_sd_sdr50_clk; - int asic_sd_hs_clk; - int asic_mmc_52m_clk; - int asic_ms_hg_clk; - int asic_ms_4bit_clk; - int asic_ms_1bit_clk; - - u8 ssc_depth_sd_sdr104; - u8 ssc_depth_sd_ddr50; - u8 ssc_depth_sd_sdr50; - u8 ssc_depth_sd_hs; - u8 ssc_depth_mmc_52m; - u8 ssc_depth_ms_hg; - u8 ssc_depth_ms_4bit; - u8 ssc_depth_low_speed; - - u8 card_drive_sel; - u8 sd30_drive_sel_1v8; - u8 sd30_drive_sel_3v3; - - u8 sd_400mA_ocp_thd; - u8 sd_800mA_ocp_thd; - u8 ms_ocp_thd; - - int ssc_en; - int msi_en; - - int xd_timeout; - int sd_timeout; - int ms_timeout; - int mspro_timeout; - - int auto_power_down; - - int sd_ddr_tx_phase; - int mmc_ddr_tx_phase; - int sd_default_tx_phase; - int sd_default_rx_phase; - - int pmos_pwr_on_interval; - int sd_voltage_switch_delay; - int s3_pwr_off_delay; - - int force_clkreq_0; - int ft2_fast_mode; - - int do_delink_before_power_down; - int polling_config; - int sdio_retry_cnt; - - int delink_stage1_step; - int delink_stage2_step; - int delink_stage3_step; - - int auto_delink_in_L1; - int hp_watch_bios_hotplug; - int support_ms_8bit; - - u8 blink_led; - u8 phy_voltage; - u8 max_payload; - - u32 sd_speed_prior; - u32 sd_current_prior; - u32 sd_ctl; -}; - -static inline struct device *rtsx_dev(const struct rtsx_chip *chip) -{ - return &chip->rtsx->pci->dev; -} - -#define rtsx_set_stat(chip, stat) \ -do { \ - if ((stat) != RTSX_STAT_IDLE) { \ - (chip)->idle_counter = 0; \ - } \ - (chip)->rtsx_stat = (enum RTSX_STAT)(stat); \ -} while (0) -#define rtsx_get_stat(chip) ((chip)->rtsx_stat) -#define rtsx_chk_stat(chip, stat) ((chip)->rtsx_stat == (stat)) - -#define RTSX_SET_DELINK(chip) ((chip)->rtsx_flag |= 0x01) -#define RTSX_CLR_DELINK(chip) ((chip)->rtsx_flag &= 0xFE) -#define RTSX_TST_DELINK(chip) ((chip)->rtsx_flag & 0x01) - -#define CHECK_PID(chip, pid) ((chip)->product_id == (pid)) -#define CHECK_BARO_PKG(chip, pkg) ((chip)->baro_pkg == (pkg)) -#define CHECK_LUN_MODE(chip, mode) ((chip)->lun_mode == (mode)) - -/* Power down control */ -#define SSC_PDCTL 0x01 -#define OC_PDCTL 0x02 - -int rtsx_force_power_on(struct rtsx_chip *chip, u8 ctl); -int rtsx_force_power_down(struct rtsx_chip *chip, u8 ctl); - -void rtsx_enable_card_int(struct rtsx_chip *chip); -void rtsx_enable_bus_int(struct rtsx_chip *chip); -void rtsx_disable_bus_int(struct rtsx_chip *chip); -int rtsx_reset_chip(struct rtsx_chip *chip); -int rtsx_init_chip(struct rtsx_chip *chip); -void rtsx_release_chip(struct rtsx_chip *chip); -void rtsx_polling_func(struct rtsx_chip *chip); -void rtsx_stop_cmd(struct rtsx_chip *chip, int card); -int rtsx_write_register(struct rtsx_chip *chip, u16 addr, u8 mask, u8 data); -int rtsx_read_register(struct rtsx_chip *chip, u16 addr, u8 *data); -int rtsx_write_cfg_dw(struct rtsx_chip *chip, - u8 func_no, u16 addr, u32 mask, u32 val); -int rtsx_read_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 *val); -int rtsx_write_cfg_seq(struct rtsx_chip *chip, - u8 func, u16 addr, u8 *buf, int len); -int rtsx_read_cfg_seq(struct rtsx_chip *chip, - u8 func, u16 addr, u8 *buf, int len); -int rtsx_write_phy_register(struct rtsx_chip *chip, u8 addr, u16 val); -int rtsx_read_phy_register(struct rtsx_chip *chip, u8 addr, u16 *val); -int rtsx_read_efuse(struct rtsx_chip *chip, u8 addr, u8 *val); -int rtsx_write_efuse(struct rtsx_chip *chip, u8 addr, u8 val); -int rtsx_clr_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit); -int rtsx_set_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit); -void rtsx_enter_ss(struct rtsx_chip *chip); -void rtsx_exit_ss(struct rtsx_chip *chip); -int rtsx_pre_handle_interrupt(struct rtsx_chip *chip); -void rtsx_enter_L1(struct rtsx_chip *chip); -void rtsx_exit_L1(struct rtsx_chip *chip); -void rtsx_do_before_power_down(struct rtsx_chip *chip, int pm_stat); -void rtsx_enable_aspm(struct rtsx_chip *chip); -void rtsx_disable_aspm(struct rtsx_chip *chip); -int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len); -int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len); -int rtsx_check_chip_exist(struct rtsx_chip *chip); - -#endif /* __REALTEK_RTSX_CHIP_H */ diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c deleted file mode 100644 index c27cffb9ad8f13..00000000000000 --- a/drivers/staging/rts5208/rtsx_scsi.c +++ /dev/null @@ -1,3279 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include -#include - -#include "rtsx.h" -#include "sd.h" -#include "ms.h" -#include "spi.h" - -void scsi_show_command(struct rtsx_chip *chip) -{ - struct scsi_cmnd *srb = chip->srb; - char *what = NULL; - bool unknown_cmd = false; - int len; - - switch (srb->cmnd[0]) { - case TEST_UNIT_READY: - what = "TEST_UNIT_READY"; - break; - case REZERO_UNIT: - what = "REZERO_UNIT"; - break; - case REQUEST_SENSE: - what = "REQUEST_SENSE"; - break; - case FORMAT_UNIT: - what = "FORMAT_UNIT"; - break; - case READ_BLOCK_LIMITS: - what = "READ_BLOCK_LIMITS"; - break; - case REASSIGN_BLOCKS: - what = "REASSIGN_BLOCKS"; - break; - case READ_6: - what = "READ_6"; - break; - case WRITE_6: - what = "WRITE_6"; - break; - case SEEK_6: - what = "SEEK_6"; - break; - case READ_REVERSE: - what = "READ_REVERSE"; - break; - case WRITE_FILEMARKS: - what = "WRITE_FILEMARKS"; - break; - case SPACE: - what = "SPACE"; - break; - case INQUIRY: - what = "INQUIRY"; - break; - case RECOVER_BUFFERED_DATA: - what = "RECOVER_BUFFERED_DATA"; - break; - case MODE_SELECT: - what = "MODE_SELECT"; - break; - case RESERVE: - what = "RESERVE"; - break; - case RELEASE: - what = "RELEASE"; - break; - case COPY: - what = "COPY"; - break; - case ERASE: - what = "ERASE"; - break; - case MODE_SENSE: - what = "MODE_SENSE"; - break; - case START_STOP: - what = "START_STOP"; - break; - case RECEIVE_DIAGNOSTIC: - what = "RECEIVE_DIAGNOSTIC"; - break; - case SEND_DIAGNOSTIC: - what = "SEND_DIAGNOSTIC"; - break; - case ALLOW_MEDIUM_REMOVAL: - what = "ALLOW_MEDIUM_REMOVAL"; - break; - case SET_WINDOW: - what = "SET_WINDOW"; - break; - case READ_CAPACITY: - what = "READ_CAPACITY"; - break; - case READ_10: - what = "READ_10"; - break; - case WRITE_10: - what = "WRITE_10"; - break; - case SEEK_10: - what = "SEEK_10"; - break; - case WRITE_VERIFY: - what = "WRITE_VERIFY"; - break; - case VERIFY: - what = "VERIFY"; - break; - case SEARCH_HIGH: - what = "SEARCH_HIGH"; - break; - case SEARCH_EQUAL: - what = "SEARCH_EQUAL"; - break; - case SEARCH_LOW: - what = "SEARCH_LOW"; - break; - case SET_LIMITS: - what = "SET_LIMITS"; - break; - case READ_POSITION: - what = "READ_POSITION"; - break; - case SYNCHRONIZE_CACHE: - what = "SYNCHRONIZE_CACHE"; - break; - case LOCK_UNLOCK_CACHE: - what = "LOCK_UNLOCK_CACHE"; - break; - case READ_DEFECT_DATA: - what = "READ_DEFECT_DATA"; - break; - case MEDIUM_SCAN: - what = "MEDIUM_SCAN"; - break; - case COMPARE: - what = "COMPARE"; - break; - case COPY_VERIFY: - what = "COPY_VERIFY"; - break; - case WRITE_BUFFER: - what = "WRITE_BUFFER"; - break; - case READ_BUFFER: - what = "READ_BUFFER"; - break; - case UPDATE_BLOCK: - what = "UPDATE_BLOCK"; - break; - case READ_LONG: - what = "READ_LONG"; - break; - case WRITE_LONG: - what = "WRITE_LONG"; - break; - case CHANGE_DEFINITION: - what = "CHANGE_DEFINITION"; - break; - case WRITE_SAME: - what = "WRITE_SAME"; - break; - case GPCMD_READ_SUBCHANNEL: - what = "READ SUBCHANNEL"; - break; - case READ_TOC: - what = "READ_TOC"; - break; - case GPCMD_READ_HEADER: - what = "READ HEADER"; - break; - case GPCMD_PLAY_AUDIO_10: - what = "PLAY AUDIO (10)"; - break; - case GPCMD_PLAY_AUDIO_MSF: - what = "PLAY AUDIO MSF"; - break; - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - what = "GET EVENT/STATUS NOTIFICATION"; - break; - case GPCMD_PAUSE_RESUME: - what = "PAUSE/RESUME"; - break; - case LOG_SELECT: - what = "LOG_SELECT"; - break; - case LOG_SENSE: - what = "LOG_SENSE"; - break; - case GPCMD_STOP_PLAY_SCAN: - what = "STOP PLAY/SCAN"; - break; - case GPCMD_READ_DISC_INFO: - what = "READ DISC INFORMATION"; - break; - case GPCMD_READ_TRACK_RZONE_INFO: - what = "READ TRACK INFORMATION"; - break; - case GPCMD_RESERVE_RZONE_TRACK: - what = "RESERVE TRACK"; - break; - case GPCMD_SEND_OPC: - what = "SEND OPC"; - break; - case MODE_SELECT_10: - what = "MODE_SELECT_10"; - break; - case GPCMD_REPAIR_RZONE_TRACK: - what = "REPAIR TRACK"; - break; - case 0x59: - what = "READ MASTER CUE"; - break; - case MODE_SENSE_10: - what = "MODE_SENSE_10"; - break; - case GPCMD_CLOSE_TRACK: - what = "CLOSE TRACK/SESSION"; - break; - case 0x5C: - what = "READ BUFFER CAPACITY"; - break; - case 0x5D: - what = "SEND CUE SHEET"; - break; - case GPCMD_BLANK: - what = "BLANK"; - break; - case REPORT_LUNS: - what = "REPORT LUNS"; - break; - case MOVE_MEDIUM: - what = "MOVE_MEDIUM or PLAY AUDIO (12)"; - break; - case READ_12: - what = "READ_12"; - break; - case WRITE_12: - what = "WRITE_12"; - break; - case WRITE_VERIFY_12: - what = "WRITE_VERIFY_12"; - break; - case SEARCH_HIGH_12: - what = "SEARCH_HIGH_12"; - break; - case SEARCH_EQUAL_12: - what = "SEARCH_EQUAL_12"; - break; - case SEARCH_LOW_12: - what = "SEARCH_LOW_12"; - break; - case SEND_VOLUME_TAG: - what = "SEND_VOLUME_TAG"; - break; - case READ_ELEMENT_STATUS: - what = "READ_ELEMENT_STATUS"; - break; - case GPCMD_READ_CD_MSF: - what = "READ CD MSF"; - break; - case GPCMD_SCAN: - what = "SCAN"; - break; - case GPCMD_SET_SPEED: - what = "SET CD SPEED"; - break; - case GPCMD_MECHANISM_STATUS: - what = "MECHANISM STATUS"; - break; - case GPCMD_READ_CD: - what = "READ CD"; - break; - case 0xE1: - what = "WRITE CONTINUE"; - break; - case WRITE_LONG_2: - what = "WRITE_LONG_2"; - break; - case VENDOR_CMND: - what = "Realtek's vendor command"; - break; - default: - what = "(unknown command)"; - unknown_cmd = true; - break; - } - - if (srb->cmnd[0] != TEST_UNIT_READY) - dev_dbg(rtsx_dev(chip), "Command %s (%d bytes)\n", - what, srb->cmd_len); - - if (unknown_cmd) { - len = min_t(unsigned short, srb->cmd_len, 16); - dev_dbg(rtsx_dev(chip), "%*ph\n", len, srb->cmnd); - } -} - -void set_sense_type(struct rtsx_chip *chip, unsigned int lun, int sense_type) -{ - switch (sense_type) { - case SENSE_TYPE_MEDIA_CHANGE: - set_sense_data(chip, lun, CUR_ERR, 0x06, 0, 0x28, 0, 0, 0); - break; - - case SENSE_TYPE_MEDIA_NOT_PRESENT: - set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x3A, 0, 0, 0); - break; - - case SENSE_TYPE_MEDIA_LBA_OVER_RANGE: - set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x21, 0, 0, 0); - break; - - case SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT: - set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x25, 0, 0, 0); - break; - - case SENSE_TYPE_MEDIA_WRITE_PROTECT: - set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x27, 0, 0, 0); - break; - - case SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR: - set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x11, 0, 0, 0); - break; - - case SENSE_TYPE_MEDIA_WRITE_ERR: - set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x0C, 0x02, 0, 0); - break; - - case SENSE_TYPE_MEDIA_INVALID_CMD_FIELD: - set_sense_data(chip, lun, CUR_ERR, ILGAL_REQ, 0, - ASC_INVLD_CDB, ASCQ_INVLD_CDB, CDB_ILLEGAL, 1); - break; - - case SENSE_TYPE_FORMAT_IN_PROGRESS: - set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, 0, 0); - break; - - case SENSE_TYPE_FORMAT_CMD_FAILED: - set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x31, 0x01, 0, 0); - break; - -#ifdef SUPPORT_MAGIC_GATE - case SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB: - set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x6F, 0x02, 0, 0); - break; - - case SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN: - set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x6F, 0x00, 0, 0); - break; - - case SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM: - set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x30, 0x00, 0, 0); - break; - - case SENSE_TYPE_MG_WRITE_ERR: - set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x0C, 0x00, 0, 0); - break; -#endif - -#ifdef SUPPORT_SD_LOCK - case SENSE_TYPE_MEDIA_READ_FORBIDDEN: - set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x11, 0x13, 0, 0); - break; -#endif - - case SENSE_TYPE_NO_SENSE: - default: - set_sense_data(chip, lun, CUR_ERR, 0, 0, 0, 0, 0, 0); - break; - } -} - -void set_sense_data(struct rtsx_chip *chip, unsigned int lun, u8 err_code, - u8 sense_key, u32 info, u8 asc, u8 ascq, u8 sns_key_info0, - u16 sns_key_info1) -{ - struct sense_data_t *sense = &chip->sense_buffer[lun]; - - sense->err_code = err_code; - sense->sense_key = sense_key; - sense->info[0] = (u8)(info >> 24); - sense->info[1] = (u8)(info >> 16); - sense->info[2] = (u8)(info >> 8); - sense->info[3] = (u8)info; - - sense->ad_sense_len = sizeof(struct sense_data_t) - 8; - sense->asc = asc; - sense->ascq = ascq; - if (sns_key_info0 != 0) { - sense->sns_key_info[0] = SKSV | sns_key_info0; - sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 4; - sense->sns_key_info[2] = sns_key_info1 & 0x0f; - } -} - -static int test_unit_ready(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - - if (!(CHK_BIT(chip->lun_mc, lun))) { - SET_BIT(chip->lun_mc, lun); - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - -#ifdef SUPPORT_SD_LOCK - if (get_lun_card(chip, SCSI_LUN(srb)) == SD_CARD) { - struct sd_info *sd_card = &chip->sd_card; - - if (sd_card->sd_lock_notify) { - sd_card->sd_lock_notify = 0; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } else if (sd_card->sd_lock_status & SD_LOCKED) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_READ_FORBIDDEN); - return TRANSPORT_FAILED; - } - } -#endif - - return TRANSPORT_GOOD; -} - -static unsigned char formatter_inquiry_str[20] = { - 'M', 'E', 'M', 'O', 'R', 'Y', 'S', 'T', 'I', 'C', 'K', -#ifdef SUPPORT_MAGIC_GATE - '-', 'M', 'G', /* Byte[47:49] */ -#else - 0x20, 0x20, 0x20, /* Byte[47:49] */ -#endif - -#ifdef SUPPORT_MAGIC_GATE - 0x0B, /* Byte[50]: MG, MS, MSPro, MSXC */ -#else - 0x09, /* Byte[50]: MS, MSPro, MSXC */ -#endif - 0x00, /* Byte[51]: Category Specific Commands */ - 0x00, /* Byte[52]: Access Control and feature */ - 0x20, 0x20, 0x20, /* Byte[53:55] */ -}; - -static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - char *inquiry_default = (char *)"Generic-xD/SD/M.S. 1.00"; - char *inquiry_sdms = (char *)"Generic-SD/MemoryStick 1.00"; - char *inquiry_sd = (char *)"Generic-SD/MMC 1.00"; - char *inquiry_ms = (char *)"Generic-MemoryStick 1.00"; - char *inquiry_string; - unsigned char sendbytes; - unsigned char *buf; - u8 card = get_lun_card(chip, lun); - bool pro_formatter_flag = false; - unsigned char inquiry_buf[] = { - QULIFIRE | DRCT_ACCESS_DEV, - RMB_DISC | 0x0D, - 0x00, - 0x01, - 0x1f, - 0x02, - 0, - REL_ADR | WBUS_32 | WBUS_16 | SYNC | LINKED | CMD_QUE | SFT_RE, - }; - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - if (chip->lun2card[lun] == SD_CARD) - inquiry_string = inquiry_sd; - else - inquiry_string = inquiry_ms; - - } else if (CHECK_LUN_MODE(chip, SD_MS_1LUN)) { - inquiry_string = inquiry_sdms; - } else { - inquiry_string = inquiry_default; - } - - buf = vmalloc(scsi_bufflen(srb)); - if (!buf) - return TRANSPORT_ERROR; - -#ifdef SUPPORT_MAGIC_GATE - if (chip->mspro_formatter_enable && - (chip->lun2card[lun] & MS_CARD)) -#else - if (chip->mspro_formatter_enable) -#endif - if (!card || card == MS_CARD) - pro_formatter_flag = true; - - if (pro_formatter_flag) { - if (scsi_bufflen(srb) < 56) - sendbytes = (unsigned char)(scsi_bufflen(srb)); - else - sendbytes = 56; - - } else { - if (scsi_bufflen(srb) < 36) - sendbytes = (unsigned char)(scsi_bufflen(srb)); - else - sendbytes = 36; - } - - if (sendbytes > 8) { - memcpy(buf, inquiry_buf, 8); - memcpy(buf + 8, inquiry_string, min(sendbytes, 36) - 8); - if (pro_formatter_flag) { - /* Additional Length */ - buf[4] = 0x33; - } - } else { - memcpy(buf, inquiry_buf, sendbytes); - } - - if (pro_formatter_flag) { - if (sendbytes > 36) - memcpy(buf + 36, formatter_inquiry_str, sendbytes - 36); - } - - scsi_set_resid(srb, 0); - - rtsx_stor_set_xfer_buf(buf, scsi_bufflen(srb), srb); - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int start_stop_unit(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - - scsi_set_resid(srb, scsi_bufflen(srb)); - - if (srb->cmnd[1] == 1) - return TRANSPORT_GOOD; - - switch (srb->cmnd[0x4]) { - case STOP_MEDIUM: - /* Media disabled */ - return TRANSPORT_GOOD; - - case UNLOAD_MEDIUM: - /* Media shall be unload */ - if (check_card_ready(chip, lun)) - eject_card(chip, lun); - return TRANSPORT_GOOD; - - case MAKE_MEDIUM_READY: - case LOAD_MEDIUM: - if (check_card_ready(chip, lun)) - return TRANSPORT_GOOD; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - - break; - } - - return TRANSPORT_ERROR; -} - -static int allow_medium_removal(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int prevent; - - prevent = srb->cmnd[4] & 0x1; - - scsi_set_resid(srb, 0); - - if (prevent) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - return TRANSPORT_GOOD; -} - -static int request_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sense_data_t *sense; - unsigned int lun = SCSI_LUN(srb); - struct ms_info *ms_card = &chip->ms_card; - unsigned char *tmp, *buf; - - sense = &chip->sense_buffer[lun]; - - if ((get_lun_card(chip, lun) == MS_CARD) && - ms_card->pro_under_formatting) { - if (ms_card->format_status == FORMAT_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - ms_card->pro_under_formatting = 0; - ms_card->progress = 0; - } else if (ms_card->format_status == FORMAT_IN_PROGRESS) { - /* Logical Unit Not Ready Format in Progress */ - set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, - 0, (u16)(ms_card->progress)); - } else { - /* Format Command Failed */ - set_sense_type(chip, lun, SENSE_TYPE_FORMAT_CMD_FAILED); - ms_card->pro_under_formatting = 0; - ms_card->progress = 0; - } - - rtsx_set_stat(chip, RTSX_STAT_RUN); - } - - buf = vmalloc(scsi_bufflen(srb)); - if (!buf) - return TRANSPORT_ERROR; - - tmp = (unsigned char *)sense; - memcpy(buf, tmp, scsi_bufflen(srb)); - - rtsx_stor_set_xfer_buf(buf, scsi_bufflen(srb), srb); - vfree(buf); - - scsi_set_resid(srb, 0); - /* Reset Sense Data */ - set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - return TRANSPORT_GOOD; -} - -static void ms_mode_sense(struct rtsx_chip *chip, u8 cmd, - int lun, u8 *buf, int buf_len) -{ - struct ms_info *ms_card = &chip->ms_card; - int sys_info_offset; - int data_size = buf_len; - bool support_format = false; - int i = 0; - - if (cmd == MODE_SENSE) { - sys_info_offset = 8; - if (data_size > 0x68) - data_size = 0x68; - - buf[i++] = 0x67; /* Mode Data Length */ - } else { - sys_info_offset = 12; - if (data_size > 0x6C) - data_size = 0x6C; - - buf[i++] = 0x00; /* Mode Data Length (MSB) */ - buf[i++] = 0x6A; /* Mode Data Length (LSB) */ - } - - /* Medium Type Code */ - if (check_card_ready(chip, lun)) { - if (CHK_MSXC(ms_card)) { - support_format = true; - buf[i++] = 0x40; - } else if (CHK_MSPRO(ms_card)) { - support_format = true; - buf[i++] = 0x20; - } else { - buf[i++] = 0x10; - } - - /* WP */ - if (check_card_wp(chip, lun)) - buf[i++] = 0x80; - else - buf[i++] = 0x00; - - } else { - buf[i++] = 0x00; /* MediaType */ - buf[i++] = 0x00; /* WP */ - } - - buf[i++] = 0x00; /* Reserved */ - - if (cmd == MODE_SENSE_10) { - buf[i++] = 0x00; /* Reserved */ - buf[i++] = 0x00; /* Block descriptor length(MSB) */ - buf[i++] = 0x00; /* Block descriptor length(LSB) */ - - /* The Following Data is the content of "Page 0x20" */ - if (data_size >= 9) - buf[i++] = 0x20; /* Page Code */ - if (data_size >= 10) - buf[i++] = 0x62; /* Page Length */ - if (data_size >= 11) - buf[i++] = 0x00; /* No Access Control */ - if (data_size >= 12) { - if (support_format) - buf[i++] = 0xC0; /* SF, SGM */ - else - buf[i++] = 0x00; - } - } else { - /* The Following Data is the content of "Page 0x20" */ - if (data_size >= 5) - buf[i++] = 0x20; /* Page Code */ - if (data_size >= 6) - buf[i++] = 0x62; /* Page Length */ - if (data_size >= 7) - buf[i++] = 0x00; /* No Access Control */ - if (data_size >= 8) { - if (support_format) - buf[i++] = 0xC0; /* SF, SGM */ - else - buf[i++] = 0x00; - } - } - - if (data_size > sys_info_offset) { - /* 96 Bytes Attribute Data */ - int len = data_size - sys_info_offset; - - len = (len < 96) ? len : 96; - - memcpy(buf + sys_info_offset, ms_card->raw_sys_info, len); - } -} - -static int mode_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - unsigned int data_size; - int status; - bool pro_formatter_flag; - unsigned char page_code, *buf; - u8 card = get_lun_card(chip, lun); - -#ifndef SUPPORT_MAGIC_GATE - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - scsi_set_resid(srb, scsi_bufflen(srb)); - return TRANSPORT_FAILED; - } -#endif - - pro_formatter_flag = false; - data_size = 8; -#ifdef SUPPORT_MAGIC_GATE - if ((chip->lun2card[lun] & MS_CARD)) { - if (!card || card == MS_CARD) { - data_size = 108; - if (chip->mspro_formatter_enable) - pro_formatter_flag = true; - } - } -#else - if (card == MS_CARD) { - if (chip->mspro_formatter_enable) { - pro_formatter_flag = true; - data_size = 108; - } - } -#endif - - buf = kmalloc(data_size, GFP_KERNEL); - if (!buf) - return TRANSPORT_ERROR; - - page_code = srb->cmnd[2] & 0x3f; - - if (page_code == 0x3F || page_code == 0x1C || - page_code == 0x00 || - (pro_formatter_flag && page_code == 0x20)) { - if (srb->cmnd[0] == MODE_SENSE) { - if (page_code == 0x3F || page_code == 0x20) { - ms_mode_sense(chip, srb->cmnd[0], - lun, buf, data_size); - } else { - data_size = 4; - buf[0] = 0x03; - buf[1] = 0x00; - if (check_card_wp(chip, lun)) - buf[2] = 0x80; - else - buf[2] = 0x00; - - buf[3] = 0x00; - } - } else { - if (page_code == 0x3F || page_code == 0x20) { - ms_mode_sense(chip, srb->cmnd[0], - lun, buf, data_size); - } else { - data_size = 8; - buf[0] = 0x00; - buf[1] = 0x06; - buf[2] = 0x00; - if (check_card_wp(chip, lun)) - buf[3] = 0x80; - else - buf[3] = 0x00; - buf[4] = 0x00; - buf[5] = 0x00; - buf[6] = 0x00; - buf[7] = 0x00; - } - } - status = TRANSPORT_GOOD; - } else { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - scsi_set_resid(srb, scsi_bufflen(srb)); - status = TRANSPORT_FAILED; - } - - if (status == TRANSPORT_GOOD) { - unsigned int len = min_t(unsigned int, scsi_bufflen(srb), - data_size); - rtsx_stor_set_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - } - kfree(buf); - - return status; -} - -static int read_write(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ -#ifdef SUPPORT_SD_LOCK - struct sd_info *sd_card = &chip->sd_card; -#endif - unsigned int lun = SCSI_LUN(srb); - int retval; - u32 start_sec; - u16 sec_cnt; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - if (!check_card_ready(chip, lun) || (get_card_size(chip, lun) == 0)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - - if (!(CHK_BIT(chip->lun_mc, lun))) { - SET_BIT(chip->lun_mc, lun); - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_erase_status) { - /* Accessing to any card is forbidden - * until the erase procedure of SD is completed - */ - dev_dbg(rtsx_dev(chip), "SD card being erased!\n"); - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN); - return TRANSPORT_FAILED; - } - - if (get_lun_card(chip, lun) == SD_CARD) { - if (sd_card->sd_lock_status & SD_LOCKED) { - dev_dbg(rtsx_dev(chip), "SD card locked!\n"); - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_READ_FORBIDDEN); - return TRANSPORT_FAILED; - } - } -#endif - - if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) { - start_sec = ((u32)srb->cmnd[2] << 24) | - ((u32)srb->cmnd[3] << 16) | - ((u32)srb->cmnd[4] << 8) | ((u32)srb->cmnd[5]); - sec_cnt = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8]; - } else if ((srb->cmnd[0] == READ_6) || (srb->cmnd[0] == WRITE_6)) { - start_sec = ((u32)(srb->cmnd[1] & 0x1F) << 16) | - ((u32)srb->cmnd[2] << 8) | ((u32)srb->cmnd[3]); - sec_cnt = srb->cmnd[4]; - if (sec_cnt == 0) - sec_cnt = 256; - } else if ((srb->cmnd[0] == VENDOR_CMND) && - (srb->cmnd[1] == SCSI_APP_CMD) && - ((srb->cmnd[2] == PP_READ10) || (srb->cmnd[2] == PP_WRITE10))) { - start_sec = ((u32)srb->cmnd[4] << 24) | - ((u32)srb->cmnd[5] << 16) | - ((u32)srb->cmnd[6] << 8) | ((u32)srb->cmnd[7]); - sec_cnt = ((u16)(srb->cmnd[9]) << 8) | srb->cmnd[10]; - } else { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - /* In some test, we will receive a start_sec like 0xFFFFFFFF. - * In this situation, start_sec + sec_cnt will overflow, so we - * need to judge start_sec at first - */ - if (start_sec > get_card_size(chip, lun) || - ((start_sec + sec_cnt) > get_card_size(chip, lun))) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LBA_OVER_RANGE); - return TRANSPORT_FAILED; - } - - if (sec_cnt == 0) { - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; - } - - if (chip->rw_fail_cnt[lun] == 3) { - dev_dbg(rtsx_dev(chip), "read/write fail three times in succession\n"); - if (srb->sc_data_direction == DMA_FROM_DEVICE) - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - else - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); - - return TRANSPORT_FAILED; - } - - if (srb->sc_data_direction == DMA_TO_DEVICE) { - if (check_card_wp(chip, lun)) { - dev_dbg(rtsx_dev(chip), "Write protected card!\n"); - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_PROTECT); - return TRANSPORT_FAILED; - } - } - - retval = card_rw(srb, chip, start_sec, sec_cnt); - if (retval != STATUS_SUCCESS) { - if (chip->need_release & chip->lun2card[lun]) { - chip->rw_fail_cnt[lun] = 0; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - } else { - chip->rw_fail_cnt[lun]++; - if (srb->sc_data_direction == DMA_FROM_DEVICE) - set_sense_type - (chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - else - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - } - retval = TRANSPORT_FAILED; - goto exit; - } else { - chip->rw_fail_cnt[lun] = 0; - retval = TRANSPORT_GOOD; - } - - scsi_set_resid(srb, 0); - -exit: - return retval; -} - -static int read_format_capacity(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned char *buf; - unsigned int lun = SCSI_LUN(srb); - unsigned int buf_len; - u8 card = get_lun_card(chip, lun); - u32 card_size; - int desc_cnt; - int i = 0; - - if (!check_card_ready(chip, lun)) { - if (!chip->mspro_formatter_enable) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - } - - buf_len = (scsi_bufflen(srb) > 12) ? 0x14 : 12; - - buf = kmalloc(buf_len, GFP_KERNEL); - if (!buf) - return TRANSPORT_ERROR; - - buf[i++] = 0; - buf[i++] = 0; - buf[i++] = 0; - - /* Capacity List Length */ - if (buf_len > 12 && chip->mspro_formatter_enable && - (chip->lun2card[lun] & MS_CARD) && - (!card || card == MS_CARD)) { - buf[i++] = 0x10; - desc_cnt = 2; - } else { - buf[i++] = 0x08; - desc_cnt = 1; - } - - while (desc_cnt) { - if (check_card_ready(chip, lun)) { - card_size = get_card_size(chip, lun); - buf[i++] = (unsigned char)(card_size >> 24); - buf[i++] = (unsigned char)(card_size >> 16); - buf[i++] = (unsigned char)(card_size >> 8); - buf[i++] = (unsigned char)card_size; - - if (desc_cnt == 2) - buf[i++] = 2; - else - buf[i++] = 0; - } else { - buf[i++] = 0xFF; - buf[i++] = 0xFF; - buf[i++] = 0xFF; - buf[i++] = 0xFF; - - if (desc_cnt == 2) - buf[i++] = 3; - else - buf[i++] = 0; - } - - buf[i++] = 0x00; - buf[i++] = 0x02; - buf[i++] = 0x00; - - desc_cnt--; - } - - buf_len = min_t(unsigned int, scsi_bufflen(srb), buf_len); - rtsx_stor_set_xfer_buf(buf, buf_len, srb); - kfree(buf); - - scsi_set_resid(srb, scsi_bufflen(srb) - buf_len); - - return TRANSPORT_GOOD; -} - -static int read_capacity(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned char *buf; - unsigned int lun = SCSI_LUN(srb); - u32 card_size; - - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - - if (!(CHK_BIT(chip->lun_mc, lun))) { - SET_BIT(chip->lun_mc, lun); - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - - buf = kmalloc(8, GFP_KERNEL); - if (!buf) - return TRANSPORT_ERROR; - - card_size = get_card_size(chip, lun); - buf[0] = (unsigned char)((card_size - 1) >> 24); - buf[1] = (unsigned char)((card_size - 1) >> 16); - buf[2] = (unsigned char)((card_size - 1) >> 8); - buf[3] = (unsigned char)(card_size - 1); - - buf[4] = 0x00; - buf[5] = 0x00; - buf[6] = 0x02; - buf[7] = 0x00; - - rtsx_stor_set_xfer_buf(buf, scsi_bufflen(srb), srb); - kfree(buf); - - scsi_set_resid(srb, 0); - - return TRANSPORT_GOOD; -} - -static int read_eeprom(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short len, i; - int retval; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - - for (i = 0; i < len; i++) { - retval = spi_read_eeprom(chip, i, buf + i); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - } - - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len); - rtsx_stor_set_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int write_eeprom(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short len, i; - int retval; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - - if (len == 511) { - retval = spi_erase_eeprom_chip(chip); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - } else { - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), - len); - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - rtsx_stor_get_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - for (i = 0; i < len; i++) { - retval = spi_write_eeprom(chip, i, buf[i]); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - } - - vfree(buf); - } - - return TRANSPORT_GOOD; -} - -static int read_mem(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short addr, len, i; - int retval; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = ((u16)srb->cmnd[2] << 8) | srb->cmnd[3]; - len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - - if (addr < 0xFC00) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - - for (i = 0; i < len; i++) { - retval = rtsx_read_register(chip, addr + i, buf + i); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - } - - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len); - rtsx_stor_set_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int write_mem(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short addr, len, i; - int retval; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = ((u16)srb->cmnd[2] << 8) | srb->cmnd[3]; - len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - - if (addr < 0xFC00) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len); - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - rtsx_stor_get_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - - for (i = 0; i < len; i++) { - retval = rtsx_write_register(chip, addr + i, 0xFF, buf[i]); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - } - - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int get_sd_csd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - unsigned int lun = SCSI_LUN(srb); - - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - - if (get_lun_card(chip, lun) != SD_CARD) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - - scsi_set_resid(srb, 0); - rtsx_stor_set_xfer_buf(sd_card->raw_csd, scsi_bufflen(srb), srb); - - return TRANSPORT_GOOD; -} - -static int toggle_gpio_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - u8 gpio = srb->cmnd[2]; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - if (gpio > 3) - gpio = 1; - toggle_gpio(chip, gpio); - - return TRANSPORT_GOOD; -} - -static int read_host_reg(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - u8 addr, buf[4]; - u32 val; - unsigned int len; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = srb->cmnd[4]; - - val = rtsx_readl(chip, addr); - dev_dbg(rtsx_dev(chip), "Host register (0x%x): 0x%x\n", addr, val); - - buf[0] = (u8)(val >> 24); - buf[1] = (u8)(val >> 16); - buf[2] = (u8)(val >> 8); - buf[3] = (u8)val; - - len = min_t(unsigned int, scsi_bufflen(srb), 4); - rtsx_stor_set_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - return TRANSPORT_GOOD; -} - -static int write_host_reg(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - u8 addr, buf[4]; - u32 val; - unsigned int len; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = srb->cmnd[4]; - - len = min_t(unsigned int, scsi_bufflen(srb), 4); - rtsx_stor_get_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - val = ((u32)buf[0] << 24) | ((u32)buf[1] << 16) | ((u32)buf[2] - << 8) | buf[3]; - - rtsx_writel(chip, addr, val); - - return TRANSPORT_GOOD; -} - -static int set_variable(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - - if (srb->cmnd[3] == 1) { - /* Variable Clock */ - struct xd_info *xd_card = &chip->xd_card; - struct sd_info *sd_card = &chip->sd_card; - struct ms_info *ms_card = &chip->ms_card; - - switch (srb->cmnd[4]) { - case XD_CARD: - xd_card->xd_clock = srb->cmnd[5]; - break; - - case SD_CARD: - sd_card->sd_clock = srb->cmnd[5]; - break; - - case MS_CARD: - ms_card->ms_clock = srb->cmnd[5]; - break; - - default: - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - } else if (srb->cmnd[3] == 2) { - if (srb->cmnd[4]) { - chip->blink_led = 1; - } else { - int retval; - - chip->blink_led = 0; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && - (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - - turn_off_led(chip, LED_GPIO); - } - } else { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - return TRANSPORT_GOOD; -} - -static int get_variable(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - - if (srb->cmnd[3] == 1) { - struct xd_info *xd_card = &chip->xd_card; - struct sd_info *sd_card = &chip->sd_card; - struct ms_info *ms_card = &chip->ms_card; - u8 tmp; - - switch (srb->cmnd[4]) { - case XD_CARD: - tmp = (u8)(xd_card->xd_clock); - break; - - case SD_CARD: - tmp = (u8)(sd_card->sd_clock); - break; - - case MS_CARD: - tmp = (u8)(ms_card->ms_clock); - break; - - default: - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - rtsx_stor_set_xfer_buf(&tmp, 1, srb); - } else if (srb->cmnd[3] == 2) { - u8 tmp = chip->blink_led; - - rtsx_stor_set_xfer_buf(&tmp, 1, srb); - } else { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - return TRANSPORT_GOOD; -} - -static int dma_access_ring_buffer(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - unsigned int lun = SCSI_LUN(srb); - u16 len; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - len = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5]; - len = min_t(u16, len, scsi_bufflen(srb)); - - if (srb->sc_data_direction == DMA_FROM_DEVICE) - dev_dbg(rtsx_dev(chip), "Read from device\n"); - else - dev_dbg(rtsx_dev(chip), "Write to device\n"); - - retval = rtsx_transfer_data(chip, 0, scsi_sglist(srb), len, - scsi_sg_count(srb), srb->sc_data_direction, - 1000); - if (retval < 0) { - if (srb->sc_data_direction == DMA_FROM_DEVICE) - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - else - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - - return TRANSPORT_FAILED; - } - scsi_set_resid(srb, 0); - - return TRANSPORT_GOOD; -} - -static int get_dev_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - struct ms_info *ms_card = &chip->ms_card; - int buf_len; - unsigned int lun = SCSI_LUN(srb); - u8 card = get_lun_card(chip, lun); - u8 status[32]; -#ifdef SUPPORT_OCP - u8 oc_now_mask = 0, oc_ever_mask = 0; -#endif - - memset(status, 0, 32); - - status[0] = (u8)(chip->product_id); - status[1] = chip->ic_version; - - if (chip->auto_delink_en) - status[2] = 0x10; - else - status[2] = 0x00; - - status[3] = 20; - status[4] = 10; - status[5] = 05; - status[6] = 21; - - if (chip->card_wp) - status[7] = 0x20; - else - status[7] = 0x00; - -#ifdef SUPPORT_OCP - status[8] = 0; - if (CHECK_LUN_MODE(chip, SD_MS_2LUN) && - chip->lun2card[lun] == MS_CARD) { - oc_now_mask = MS_OC_NOW; - oc_ever_mask = MS_OC_EVER; - } else { - oc_now_mask = SD_OC_NOW; - oc_ever_mask = SD_OC_EVER; - } - - if (chip->ocp_stat & oc_now_mask) - status[8] |= 0x02; - - if (chip->ocp_stat & oc_ever_mask) - status[8] |= 0x01; -#endif - - if (card == SD_CARD) { - if (CHK_SD(sd_card)) { - if (CHK_SD_HCXC(sd_card)) { - if (sd_card->capacity > 0x4000000) - status[0x0E] = 0x02; - else - status[0x0E] = 0x01; - } else { - status[0x0E] = 0x00; - } - - if (CHK_SD_SDR104(sd_card)) - status[0x0F] = 0x03; - else if (CHK_SD_DDR50(sd_card)) - status[0x0F] = 0x04; - else if (CHK_SD_SDR50(sd_card)) - status[0x0F] = 0x02; - else if (CHK_SD_HS(sd_card)) - status[0x0F] = 0x01; - else - status[0x0F] = 0x00; - } else { - if (CHK_MMC_SECTOR_MODE(sd_card)) - status[0x0E] = 0x01; - else - status[0x0E] = 0x00; - - if (CHK_MMC_DDR52(sd_card)) - status[0x0F] = 0x03; - else if (CHK_MMC_52M(sd_card)) - status[0x0F] = 0x02; - else if (CHK_MMC_26M(sd_card)) - status[0x0F] = 0x01; - else - status[0x0F] = 0x00; - } - } else if (card == MS_CARD) { - if (CHK_MSPRO(ms_card)) { - if (CHK_MSXC(ms_card)) - status[0x0E] = 0x01; - else - status[0x0E] = 0x00; - - if (CHK_HG8BIT(ms_card)) - status[0x0F] = 0x01; - else - status[0x0F] = 0x00; - } - } - -#ifdef SUPPORT_SD_LOCK - if (card == SD_CARD) { - status[0x17] = 0x80; - if (sd_card->sd_erase_status) - status[0x17] |= 0x01; - if (sd_card->sd_lock_status & SD_LOCKED) { - status[0x17] |= 0x02; - status[0x07] |= 0x40; - } - if (sd_card->sd_lock_status & SD_PWD_EXIST) - status[0x17] |= 0x04; - } else { - status[0x17] = 0x00; - } - - dev_dbg(rtsx_dev(chip), "status[0x17] = 0x%x\n", status[0x17]); -#endif - - status[0x18] = 0x8A; - status[0x1A] = 0x28; -#ifdef SUPPORT_SD_LOCK - status[0x1F] = 0x01; -#endif - - buf_len = min_t(unsigned int, scsi_bufflen(srb), sizeof(status)); - rtsx_stor_set_xfer_buf(status, buf_len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - buf_len); - - return TRANSPORT_GOOD; -} - -static int set_chip_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int phy_debug_mode; - int retval; - u16 reg; - - if (!CHECK_PID(chip, 0x5208)) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - phy_debug_mode = (int)(srb->cmnd[3]); - - if (phy_debug_mode) { - chip->phy_debug_mode = 1; - retval = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - rtsx_disable_bus_int(chip); - - retval = rtsx_read_phy_register(chip, 0x1C, ®); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - reg |= 0x0001; - retval = rtsx_write_phy_register(chip, 0x1C, reg); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - } else { - chip->phy_debug_mode = 0; - retval = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0x77); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - rtsx_enable_bus_int(chip); - - retval = rtsx_read_phy_register(chip, 0x1C, ®); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - reg &= 0xFFFE; - retval = rtsx_write_phy_register(chip, 0x1C, reg); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - } - - return TRANSPORT_GOOD; -} - -static int rw_mem_cmd_buf(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval = STATUS_SUCCESS; - unsigned int lun = SCSI_LUN(srb); - u8 cmd_type, mask, value, idx; - u16 addr; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - switch (srb->cmnd[3]) { - case INIT_BATCHCMD: - rtsx_init_cmd(chip); - break; - - case ADD_BATCHCMD: - cmd_type = srb->cmnd[4]; - if (cmd_type > 2) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - addr = (srb->cmnd[5] << 8) | srb->cmnd[6]; - mask = srb->cmnd[7]; - value = srb->cmnd[8]; - rtsx_add_cmd(chip, cmd_type, addr, mask, value); - break; - - case SEND_BATCHCMD: - retval = rtsx_send_cmd(chip, 0, 1000); - break; - - case GET_BATCHRSP: - idx = srb->cmnd[4]; - value = *(rtsx_get_cmd_data(chip) + idx); - if (scsi_bufflen(srb) < 1) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - rtsx_stor_set_xfer_buf(&value, 1, srb); - scsi_set_resid(srb, 0); - break; - - default: - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - - return TRANSPORT_GOOD; -} - -static int suit_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - switch (srb->cmnd[3]) { - case INIT_BATCHCMD: - case ADD_BATCHCMD: - case SEND_BATCHCMD: - case GET_BATCHRSP: - return rw_mem_cmd_buf(srb, chip); - default: - return TRANSPORT_ERROR; - } -} - -static int read_phy_register(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short addr, len, i; - int retval; - u8 *buf; - u16 val; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - len = ((u16)srb->cmnd[6] << 8) | srb->cmnd[7]; - - if (len % 2) - len -= len % 2; - - if (len) { - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - - for (i = 0; i < len / 2; i++) { - retval = rtsx_read_phy_register(chip, addr + i, &val); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type - (chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - - buf[2 * i] = (u8)(val >> 8); - buf[2 * i + 1] = (u8)val; - } - - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), - len); - rtsx_stor_set_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - vfree(buf); - } - - return TRANSPORT_GOOD; -} - -static int write_phy_register(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short addr, len, i; - int retval; - u8 *buf; - u16 val; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - len = ((u16)srb->cmnd[6] << 8) | srb->cmnd[7]; - - if (len % 2) - len -= len % 2; - - if (len) { - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), - len); - - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - rtsx_stor_get_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - - for (i = 0; i < len / 2; i++) { - val = ((u16)buf[2 * i] << 8) | buf[2 * i + 1]; - retval = rtsx_write_phy_register(chip, addr + i, val); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - } - - vfree(buf); - } - - return TRANSPORT_GOOD; -} - -static int erase_eeprom2(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short addr; - int retval; - u8 mode; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - - mode = srb->cmnd[3]; - addr = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - - if (mode == 0) { - retval = spi_erase_eeprom_chip(chip); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - } else if (mode == 1) { - retval = spi_erase_eeprom_byte(chip, addr); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - } else { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - return TRANSPORT_GOOD; -} - -static int read_eeprom2(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short addr, len, i; - int retval; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - len = ((u16)srb->cmnd[6] << 8) | srb->cmnd[7]; - - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - - for (i = 0; i < len; i++) { - retval = spi_read_eeprom(chip, addr + i, buf + i); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - } - - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len); - rtsx_stor_set_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int write_eeprom2(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned short addr, len, i; - int retval; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; - len = ((u16)srb->cmnd[6] << 8) | srb->cmnd[7]; - - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len); - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - rtsx_stor_get_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - - for (i = 0; i < len; i++) { - retval = spi_write_eeprom(chip, addr + i, buf[i]); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - return TRANSPORT_FAILED; - } - } - - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int read_efuse(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - u8 addr, len, i; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = srb->cmnd[4]; - len = srb->cmnd[5]; - - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - - for (i = 0; i < len; i++) { - retval = rtsx_read_efuse(chip, addr + i, buf + i); - if (retval != STATUS_SUCCESS) { - vfree(buf); - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - } - - len = (u8)min_t(unsigned int, scsi_bufflen(srb), len); - rtsx_stor_set_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int write_efuse(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval, result = TRANSPORT_GOOD; - u16 val; - u8 addr, len, i; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - addr = srb->cmnd[4]; - len = srb->cmnd[5]; - - len = (u8)min_t(unsigned int, scsi_bufflen(srb), len); - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - rtsx_stor_get_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - retval = rtsx_force_power_on(chip, SSC_PDCTL); - if (retval != STATUS_SUCCESS) { - vfree(buf); - return TRANSPORT_ERROR; - } - - if (chip->asic_code) { - retval = rtsx_read_phy_register(chip, 0x08, &val); - if (retval != STATUS_SUCCESS) { - vfree(buf); - return TRANSPORT_ERROR; - } - - retval = rtsx_write_register(chip, PWR_GATE_CTRL, - LDO3318_PWR_MASK, LDO_OFF); - if (retval != STATUS_SUCCESS) { - vfree(buf); - return TRANSPORT_ERROR; - } - - wait_timeout(600); - - retval = rtsx_write_phy_register(chip, 0x08, - 0x4C00 | chip->phy_voltage); - if (retval != STATUS_SUCCESS) { - vfree(buf); - return TRANSPORT_ERROR; - } - - retval = rtsx_write_register(chip, PWR_GATE_CTRL, - LDO3318_PWR_MASK, LDO_ON); - if (retval != STATUS_SUCCESS) { - vfree(buf); - return TRANSPORT_ERROR; - } - - wait_timeout(600); - } - - retval = card_power_on(chip, SPI_CARD); - if (retval != STATUS_SUCCESS) { - vfree(buf); - return TRANSPORT_ERROR; - } - - wait_timeout(50); - - for (i = 0; i < len; i++) { - retval = rtsx_write_efuse(chip, addr + i, buf[i]); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_WRITE_ERR); - result = TRANSPORT_FAILED; - goto exit; - } - } - -exit: - vfree(buf); - - retval = card_power_off(chip, SPI_CARD); - if (retval != STATUS_SUCCESS) - return TRANSPORT_ERROR; - - if (chip->asic_code) { - retval = rtsx_write_register(chip, PWR_GATE_CTRL, - LDO3318_PWR_MASK, LDO_OFF); - if (retval != STATUS_SUCCESS) - return TRANSPORT_ERROR; - - wait_timeout(600); - - retval = rtsx_write_phy_register(chip, 0x08, val); - if (retval != STATUS_SUCCESS) - return TRANSPORT_ERROR; - - retval = rtsx_write_register(chip, PWR_GATE_CTRL, - LDO3318_PWR_MASK, LDO_ON); - if (retval != STATUS_SUCCESS) - return TRANSPORT_ERROR; - } - - return result; -} - -static int read_cfg_byte(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - bool func_max; - u8 func; - u16 addr, len; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - func = srb->cmnd[3]; - addr = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5]; - len = ((u16)(srb->cmnd[6]) << 8) | srb->cmnd[7]; - - dev_dbg(rtsx_dev(chip), "%s: func = %d, addr = 0x%x, len = %d\n", - __func__, func, addr, len); - - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) - func_max = true; - else - func_max = false; - - if (func > func_max) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - retval = rtsx_read_cfg_seq(chip, func, addr, buf, len); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - vfree(buf); - return TRANSPORT_FAILED; - } - - len = (u16)min_t(unsigned int, scsi_bufflen(srb), len); - rtsx_stor_set_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int write_cfg_byte(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - bool func_max; - u8 func; - u16 addr, len; - u8 *buf; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - func = srb->cmnd[3]; - addr = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5]; - len = ((u16)(srb->cmnd[6]) << 8) | srb->cmnd[7]; - - dev_dbg(rtsx_dev(chip), "%s: func = %d, addr = 0x%x\n", - __func__, func, addr); - - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) - func_max = true; - else - func_max = false; - - if (func > func_max) { - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - len = (unsigned short)min_t(unsigned int, scsi_bufflen(srb), len); - buf = vmalloc(len); - if (!buf) - return TRANSPORT_ERROR; - - rtsx_stor_get_xfer_buf(buf, len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - len); - - retval = rtsx_write_cfg_seq(chip, func, addr, buf, len); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); - vfree(buf); - return TRANSPORT_FAILED; - } - - vfree(buf); - - return TRANSPORT_GOOD; -} - -static int app_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int result; - - switch (srb->cmnd[2]) { - case PP_READ10: - case PP_WRITE10: - result = read_write(srb, chip); - break; - - case READ_HOST_REG: - result = read_host_reg(srb, chip); - break; - - case WRITE_HOST_REG: - result = write_host_reg(srb, chip); - break; - - case GET_VAR: - result = get_variable(srb, chip); - break; - - case SET_VAR: - result = set_variable(srb, chip); - break; - - case DMA_READ: - case DMA_WRITE: - result = dma_access_ring_buffer(srb, chip); - break; - - case READ_PHY: - result = read_phy_register(srb, chip); - break; - - case WRITE_PHY: - result = write_phy_register(srb, chip); - break; - - case ERASE_EEPROM2: - result = erase_eeprom2(srb, chip); - break; - - case READ_EEPROM2: - result = read_eeprom2(srb, chip); - break; - - case WRITE_EEPROM2: - result = write_eeprom2(srb, chip); - break; - - case READ_EFUSE: - result = read_efuse(srb, chip); - break; - - case WRITE_EFUSE: - result = write_efuse(srb, chip); - break; - - case READ_CFG: - result = read_cfg_byte(srb, chip); - break; - - case WRITE_CFG: - result = write_cfg_byte(srb, chip); - break; - - case SET_CHIP_MODE: - result = set_chip_mode(srb, chip); - break; - - case SUIT_CMD: - result = suit_cmd(srb, chip); - break; - - case GET_DEV_STATUS: - result = get_dev_status(srb, chip); - break; - - default: - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - return result; -} - -static int read_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - u8 rtsx_status[16]; - int buf_len; - unsigned int lun = SCSI_LUN(srb); - - rtsx_status[0] = (u8)(chip->vendor_id >> 8); - rtsx_status[1] = (u8)(chip->vendor_id); - - rtsx_status[2] = (u8)(chip->product_id >> 8); - rtsx_status[3] = (u8)(chip->product_id); - - rtsx_status[4] = (u8)lun; - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - if (chip->lun2card[lun] == SD_CARD) - rtsx_status[5] = 2; - else - rtsx_status[5] = 3; - } else { - if (chip->card_exist) { - if (chip->card_exist & XD_CARD) - rtsx_status[5] = 4; - else if (chip->card_exist & SD_CARD) - rtsx_status[5] = 2; - else if (chip->card_exist & MS_CARD) - rtsx_status[5] = 3; - else - rtsx_status[5] = 7; - } else { - rtsx_status[5] = 7; - } - } - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) - rtsx_status[6] = 2; - else - rtsx_status[6] = 1; - - rtsx_status[7] = (u8)(chip->product_id); - rtsx_status[8] = chip->ic_version; - - if (check_card_exist(chip, lun)) - rtsx_status[9] = 1; - else - rtsx_status[9] = 0; - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) - rtsx_status[10] = 0; - else - rtsx_status[10] = 1; - - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - if (chip->lun2card[lun] == SD_CARD) - rtsx_status[11] = SD_CARD; - else - rtsx_status[11] = MS_CARD; - } else { - rtsx_status[11] = XD_CARD | SD_CARD | MS_CARD; - } - - if (check_card_ready(chip, lun)) - rtsx_status[12] = 1; - else - rtsx_status[12] = 0; - - if (get_lun_card(chip, lun) == XD_CARD) { - rtsx_status[13] = 0x40; - } else if (get_lun_card(chip, lun) == SD_CARD) { - struct sd_info *sd_card = &chip->sd_card; - - rtsx_status[13] = 0x20; - if (CHK_SD(sd_card)) { - if (CHK_SD_HCXC(sd_card)) - rtsx_status[13] |= 0x04; - if (CHK_SD_HS(sd_card)) - rtsx_status[13] |= 0x02; - } else { - rtsx_status[13] |= 0x08; - if (CHK_MMC_52M(sd_card)) - rtsx_status[13] |= 0x02; - if (CHK_MMC_SECTOR_MODE(sd_card)) - rtsx_status[13] |= 0x04; - } - } else if (get_lun_card(chip, lun) == MS_CARD) { - struct ms_info *ms_card = &chip->ms_card; - - if (CHK_MSPRO(ms_card)) { - rtsx_status[13] = 0x38; - if (CHK_HG8BIT(ms_card)) - rtsx_status[13] |= 0x04; -#ifdef SUPPORT_MSXC - if (CHK_MSXC(ms_card)) - rtsx_status[13] |= 0x01; -#endif - } else { - rtsx_status[13] = 0x30; - } - } else { - if (CHECK_LUN_MODE(chip, DEFAULT_SINGLE)) { -#ifdef SUPPORT_SDIO - if (chip->sd_io && chip->sd_int) - rtsx_status[13] = 0x60; - else - rtsx_status[13] = 0x70; -#else - rtsx_status[13] = 0x70; -#endif - } else { - if (chip->lun2card[lun] == SD_CARD) - rtsx_status[13] = 0x20; - else - rtsx_status[13] = 0x30; - } - } - - rtsx_status[14] = 0x78; - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) - rtsx_status[15] = 0x83; - else - rtsx_status[15] = 0x82; - - buf_len = min_t(unsigned int, scsi_bufflen(srb), sizeof(rtsx_status)); - rtsx_stor_set_xfer_buf(rtsx_status, buf_len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - buf_len); - - return TRANSPORT_GOOD; -} - -static int get_card_bus_width(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - u8 card, bus_width; - - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - - card = get_lun_card(chip, lun); - if (card == SD_CARD || card == MS_CARD) { - bus_width = chip->card_bus_width[lun]; - } else { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return TRANSPORT_FAILED; - } - - scsi_set_resid(srb, 0); - rtsx_stor_set_xfer_buf(&bus_width, scsi_bufflen(srb), srb); - - return TRANSPORT_GOOD; -} - -static int spi_vendor_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int result; - unsigned int lun = SCSI_LUN(srb); - u8 gpio_dir; - - if (CHECK_PID(chip, 0x5208) || CHECK_PID(chip, 0x5288)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - rtsx_force_power_on(chip, SSC_PDCTL); - - rtsx_read_register(chip, CARD_GPIO_DIR, &gpio_dir); - rtsx_write_register(chip, CARD_GPIO_DIR, 0x07, gpio_dir & 0x06); - - switch (srb->cmnd[2]) { - case SCSI_SPI_GETSTATUS: - result = spi_get_status(srb, chip); - break; - - case SCSI_SPI_SETPARAMETER: - result = spi_set_parameter(srb, chip); - break; - - case SCSI_SPI_READFALSHID: - result = spi_read_flash_id(srb, chip); - break; - - case SCSI_SPI_READFLASH: - result = spi_read_flash(srb, chip); - break; - - case SCSI_SPI_WRITEFLASH: - result = spi_write_flash(srb, chip); - break; - - case SCSI_SPI_WRITEFLASHSTATUS: - result = spi_write_flash_status(srb, chip); - break; - - case SCSI_SPI_ERASEFLASH: - result = spi_erase_flash(srb, chip); - break; - - default: - rtsx_write_register(chip, CARD_GPIO_DIR, 0x07, gpio_dir); - - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - rtsx_write_register(chip, CARD_GPIO_DIR, 0x07, gpio_dir); - - if (result != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - return TRANSPORT_GOOD; -} - -static int vendor_cmnd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int result; - - switch (srb->cmnd[1]) { - case READ_STATUS: - result = read_status(srb, chip); - break; - - case READ_MEM: - result = read_mem(srb, chip); - break; - - case WRITE_MEM: - result = write_mem(srb, chip); - break; - - case READ_EEPROM: - result = read_eeprom(srb, chip); - break; - - case WRITE_EEPROM: - result = write_eeprom(srb, chip); - break; - - case TOGGLE_GPIO: - result = toggle_gpio_cmd(srb, chip); - break; - - case GET_SD_CSD: - result = get_sd_csd(srb, chip); - break; - - case GET_BUS_WIDTH: - result = get_card_bus_width(srb, chip); - break; - - case SCSI_APP_CMD: - result = app_cmd(srb, chip); - break; - - case SPI_VENDOR_COMMAND: - result = spi_vendor_cmd(srb, chip); - break; - - default: - set_sense_type(chip, SCSI_LUN(srb), - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - return result; -} - -#if !defined(LED_AUTO_BLINK) && !defined(REGULAR_BLINK) -void led_shine(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - u16 sec_cnt; - - if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) { - sec_cnt = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8]; - } else if ((srb->cmnd[0] == READ_6) || (srb->cmnd[0] == WRITE_6)) { - sec_cnt = srb->cmnd[4]; - if (sec_cnt == 0) - sec_cnt = 256; - } else { - return; - } - - if (chip->rw_cap[lun] >= GPIO_TOGGLE_THRESHOLD) { - toggle_gpio(chip, LED_GPIO); - chip->rw_cap[lun] = 0; - } else { - chip->rw_cap[lun] += sec_cnt; - } -} -#endif - -static int ms_format_cmnd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - unsigned int lun = SCSI_LUN(srb); - bool quick_format; - int retval; - - if (get_lun_card(chip, lun) != MS_CARD) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT); - return TRANSPORT_FAILED; - } - - if (srb->cmnd[3] != 0x4D || srb->cmnd[4] != 0x47 || - srb->cmnd[5] != 0x66 || srb->cmnd[6] != 0x6D || - srb->cmnd[7] != 0x74) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - - if (!check_card_ready(chip, lun) || - (get_card_size(chip, lun) == 0)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - if (srb->cmnd[8] & 0x01) - quick_format = false; - else - quick_format = true; - - if (!(chip->card_ready & MS_CARD)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - - if (chip->card_wp & MS_CARD) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT); - return TRANSPORT_FAILED; - } - - if (!CHK_MSPRO(ms_card)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT); - return TRANSPORT_FAILED; - } - - retval = mspro_format(srb, chip, MS_SHORT_DATA_LEN, quick_format); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_FORMAT_CMD_FAILED); - return TRANSPORT_FAILED; - } - - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; -} - -#ifdef SUPPORT_PCGL_1P18 -static int get_ms_information(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - unsigned int lun = SCSI_LUN(srb); - u8 dev_info_id, data_len; - u8 *buf; - unsigned int buf_len; - int i; - - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - if (get_lun_card(chip, lun) != MS_CARD) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT); - return TRANSPORT_FAILED; - } - - if (srb->cmnd[2] != 0xB0 || srb->cmnd[4] != 0x4D || - srb->cmnd[5] != 0x53 || srb->cmnd[6] != 0x49 || - srb->cmnd[7] != 0x44) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - dev_info_id = srb->cmnd[3]; - if ((CHK_MSXC(ms_card) && dev_info_id == 0x10) || - (!CHK_MSXC(ms_card) && dev_info_id == 0x13) || - !CHK_MSPRO(ms_card)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - if (dev_info_id == 0x15) { - buf_len = 0x3C; - data_len = 0x3A; - } else { - buf_len = 0x6C; - data_len = 0x6A; - } - - buf = kmalloc(buf_len, GFP_KERNEL); - if (!buf) - return TRANSPORT_ERROR; - - i = 0; - /* GET Memory Stick Media Information Response Header */ - buf[i++] = 0x00; /* Data length MSB */ - buf[i++] = data_len; /* Data length LSB */ - /* Device Information Type Code */ - if (CHK_MSXC(ms_card)) - buf[i++] = 0x03; - else - buf[i++] = 0x02; - - /* SGM bit */ - buf[i++] = 0x01; - /* Reserved */ - buf[i++] = 0x00; - buf[i++] = 0x00; - buf[i++] = 0x00; - /* Number of Device Information */ - buf[i++] = 0x01; - - /* Device Information Body */ - - /* Device Information ID Number */ - buf[i++] = dev_info_id; - /* Device Information Length */ - if (dev_info_id == 0x15) - data_len = 0x31; - else - data_len = 0x61; - - buf[i++] = 0x00; /* Data length MSB */ - buf[i++] = data_len; /* Data length LSB */ - /* Valid Bit */ - buf[i++] = 0x80; - if (dev_info_id == 0x10 || dev_info_id == 0x13) { - /* System Information */ - memcpy(buf + i, ms_card->raw_sys_info, 96); - } else { - /* Model Name */ - memcpy(buf + i, ms_card->raw_model_name, 48); - } - - rtsx_stor_set_xfer_buf(buf, buf_len, srb); - scsi_set_resid(srb, scsi_bufflen(srb) - buf_len); - - kfree(buf); - return STATUS_SUCCESS; -} -#endif - -static int ms_sp_cmnd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval = TRANSPORT_ERROR; - - if (srb->cmnd[2] == MS_FORMAT) - retval = ms_format_cmnd(srb, chip); -#ifdef SUPPORT_PCGL_1P18 - else if (srb->cmnd[2] == GET_MS_INFORMATION) - retval = get_ms_information(srb, chip); -#endif - - return retval; -} - -#ifdef SUPPORT_CPRM -static int sd_extension_cmnd(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - unsigned int lun = SCSI_LUN(srb); - int result; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - sd_cleanup_work(chip); - - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - if (get_lun_card(chip, lun) != SD_CARD) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT); - return TRANSPORT_FAILED; - } - - switch (srb->cmnd[0]) { - case SD_PASS_THRU_MODE: - result = sd_pass_thru_mode(srb, chip); - break; - - case SD_EXECUTE_NO_DATA: - result = sd_execute_no_data(srb, chip); - break; - - case SD_EXECUTE_READ: - result = sd_execute_read_data(srb, chip); - break; - - case SD_EXECUTE_WRITE: - result = sd_execute_write_data(srb, chip); - break; - - case SD_GET_RSP: - result = sd_get_cmd_rsp(srb, chip); - break; - - case SD_HW_RST: - result = sd_hw_rst(srb, chip); - break; - - default: - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - return result; -} -#endif - -#ifdef SUPPORT_MAGIC_GATE -static int mg_report_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - unsigned int lun = SCSI_LUN(srb); - int retval; - u8 key_format; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - ms_cleanup_work(chip); - - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - if (get_lun_card(chip, lun) != MS_CARD) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT); - return TRANSPORT_FAILED; - } - - if (srb->cmnd[7] != KC_MG_R_PRO) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - if (!CHK_MSPRO(ms_card)) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - return TRANSPORT_FAILED; - } - - key_format = srb->cmnd[10] & 0x3F; - dev_dbg(rtsx_dev(chip), "key_format = 0x%x\n", key_format); - - switch (key_format) { - case KF_GET_LOC_EKB: - if ((scsi_bufflen(srb) == 0x41C) && - srb->cmnd[8] == 0x04 && - srb->cmnd[9] == 0x1C) { - retval = mg_get_local_EKB(srb, chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - break; - - case KF_RSP_CHG: - if ((scsi_bufflen(srb) == 0x24) && - srb->cmnd[8] == 0x00 && - srb->cmnd[9] == 0x24) { - retval = mg_get_rsp_chg(srb, chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - break; - - case KF_GET_ICV: - ms_card->mg_entry_num = srb->cmnd[5]; - if ((scsi_bufflen(srb) == 0x404) && - srb->cmnd[8] == 0x04 && - srb->cmnd[9] == 0x04 && - srb->cmnd[2] == 0x00 && - srb->cmnd[3] == 0x00 && - srb->cmnd[4] == 0x00 && - srb->cmnd[5] < 32) { - retval = mg_get_ICV(srb, chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - break; - - default: - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; -} - -static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct ms_info *ms_card = &chip->ms_card; - unsigned int lun = SCSI_LUN(srb); - int retval; - u8 key_format; - - rtsx_disable_aspm(chip); - - if (chip->ss_en && (rtsx_get_stat(chip) == RTSX_STAT_SS)) { - rtsx_exit_ss(chip); - wait_timeout(100); - } - rtsx_set_stat(chip, RTSX_STAT_RUN); - - ms_cleanup_work(chip); - - if (!check_card_ready(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return TRANSPORT_FAILED; - } - if (check_card_wp(chip, lun)) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT); - return TRANSPORT_FAILED; - } - if (get_lun_card(chip, lun) != MS_CARD) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT); - return TRANSPORT_FAILED; - } - - if (srb->cmnd[7] != KC_MG_R_PRO) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - if (!CHK_MSPRO(ms_card)) { - set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); - return TRANSPORT_FAILED; - } - - key_format = srb->cmnd[10] & 0x3F; - dev_dbg(rtsx_dev(chip), "key_format = 0x%x\n", key_format); - - switch (key_format) { - case KF_SET_LEAF_ID: - if ((scsi_bufflen(srb) == 0x0C) && - srb->cmnd[8] == 0x00 && - srb->cmnd[9] == 0x0C) { - retval = mg_set_leaf_id(srb, chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - break; - - case KF_CHG_HOST: - if ((scsi_bufflen(srb) == 0x0C) && - srb->cmnd[8] == 0x00 && - srb->cmnd[9] == 0x0C) { - retval = mg_chg(srb, chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - break; - - case KF_RSP_HOST: - if ((scsi_bufflen(srb) == 0x0C) && - srb->cmnd[8] == 0x00 && - srb->cmnd[9] == 0x0C) { - retval = mg_rsp(srb, chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - break; - - case KF_SET_ICV: - ms_card->mg_entry_num = srb->cmnd[5]; - if ((scsi_bufflen(srb) == 0x404) && - srb->cmnd[8] == 0x04 && - srb->cmnd[9] == 0x04 && - srb->cmnd[2] == 0x00 && - srb->cmnd[3] == 0x00 && - srb->cmnd[4] == 0x00 && - srb->cmnd[5] < 32) { - retval = mg_set_ICV(srb, chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - break; - - default: - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; -} -#endif - -int rtsx_scsi_handler(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ -#ifdef SUPPORT_SD_LOCK - struct sd_info *sd_card = &chip->sd_card; -#endif - struct ms_info *ms_card = &chip->ms_card; - unsigned int lun = SCSI_LUN(srb); - int result; - -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_erase_status) { - /* Block all SCSI command except for - * REQUEST_SENSE and rs_ppstatus - */ - if (!(srb->cmnd[0] == VENDOR_CMND && - srb->cmnd[1] == SCSI_APP_CMD && - srb->cmnd[2] == GET_DEV_STATUS) && - srb->cmnd[0] != REQUEST_SENSE) { - /* Logical Unit Not Ready Format in Progress */ - set_sense_data(chip, lun, CUR_ERR, - 0x02, 0, 0x04, 0x04, 0, 0); - return TRANSPORT_FAILED; - } - } -#endif - - if ((get_lun_card(chip, lun) == MS_CARD) && - ms_card->format_status == FORMAT_IN_PROGRESS) { - if (srb->cmnd[0] != REQUEST_SENSE && - srb->cmnd[0] != INQUIRY) { - /* Logical Unit Not Ready Format in Progress */ - set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, - 0, (u16)(ms_card->progress)); - return TRANSPORT_FAILED; - } - } - - switch (srb->cmnd[0]) { - case READ_10: - case WRITE_10: - case READ_6: - case WRITE_6: - result = read_write(srb, chip); -#if !defined(LED_AUTO_BLINK) && !defined(REGULAR_BLINK) - led_shine(srb, chip); -#endif - break; - - case TEST_UNIT_READY: - result = test_unit_ready(srb, chip); - break; - - case INQUIRY: - result = inquiry(srb, chip); - break; - - case READ_CAPACITY: - result = read_capacity(srb, chip); - break; - - case START_STOP: - result = start_stop_unit(srb, chip); - break; - - case ALLOW_MEDIUM_REMOVAL: - result = allow_medium_removal(srb, chip); - break; - - case REQUEST_SENSE: - result = request_sense(srb, chip); - break; - - case MODE_SENSE: - case MODE_SENSE_10: - result = mode_sense(srb, chip); - break; - - case 0x23: - result = read_format_capacity(srb, chip); - break; - - case VENDOR_CMND: - result = vendor_cmnd(srb, chip); - break; - - case MS_SP_CMND: - result = ms_sp_cmnd(srb, chip); - break; - -#ifdef SUPPORT_CPRM - case SD_PASS_THRU_MODE: - case SD_EXECUTE_NO_DATA: - case SD_EXECUTE_READ: - case SD_EXECUTE_WRITE: - case SD_GET_RSP: - case SD_HW_RST: - result = sd_extension_cmnd(srb, chip); - break; -#endif - -#ifdef SUPPORT_MAGIC_GATE - case CMD_MSPRO_MG_RKEY: - result = mg_report_key(srb, chip); - break; - - case CMD_MSPRO_MG_SKEY: - result = mg_send_key(srb, chip); - break; -#endif - - case FORMAT_UNIT: - case MODE_SELECT: - case VERIFY: - result = TRANSPORT_GOOD; - break; - - default: - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - result = TRANSPORT_FAILED; - } - - return result; -} diff --git a/drivers/staging/rts5208/rtsx_scsi.h b/drivers/staging/rts5208/rtsx_scsi.h deleted file mode 100644 index df6138c97aaad5..00000000000000 --- a/drivers/staging/rts5208/rtsx_scsi.h +++ /dev/null @@ -1,131 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_SCSI_H -#define __REALTEK_RTSX_SCSI_H - -#include "rtsx.h" -#include "rtsx_chip.h" - -#define MS_SP_CMND 0xFA -#define MS_FORMAT 0xA0 -#define GET_MS_INFORMATION 0xB0 - -#define VENDOR_CMND 0xF0 - -#define READ_STATUS 0x09 - -#define READ_EEPROM 0x04 -#define WRITE_EEPROM 0x05 -#define READ_MEM 0x0D -#define WRITE_MEM 0x0E -#define GET_BUS_WIDTH 0x13 -#define GET_SD_CSD 0x14 -#define TOGGLE_GPIO 0x15 -#define TRACE_MSG 0x18 - -#define SCSI_APP_CMD 0x10 - -#define PP_READ10 0x1A -#define PP_WRITE10 0x0A -#define READ_HOST_REG 0x1D -#define WRITE_HOST_REG 0x0D -#define SET_VAR 0x05 -#define GET_VAR 0x15 -#define DMA_READ 0x16 -#define DMA_WRITE 0x06 -#define GET_DEV_STATUS 0x10 -#define SET_CHIP_MODE 0x27 -#define SUIT_CMD 0xE0 -#define WRITE_PHY 0x07 -#define READ_PHY 0x17 -#define WRITE_EEPROM2 0x03 -#define READ_EEPROM2 0x13 -#define ERASE_EEPROM2 0x23 -#define WRITE_EFUSE 0x04 -#define READ_EFUSE 0x14 -#define WRITE_CFG 0x0E -#define READ_CFG 0x1E - -#define SPI_VENDOR_COMMAND 0x1C - -#define SCSI_SPI_GETSTATUS 0x00 -#define SCSI_SPI_SETPARAMETER 0x01 -#define SCSI_SPI_READFALSHID 0x02 -#define SCSI_SPI_READFLASH 0x03 -#define SCSI_SPI_WRITEFLASH 0x04 -#define SCSI_SPI_WRITEFLASHSTATUS 0x05 -#define SCSI_SPI_ERASEFLASH 0x06 - -#define INIT_BATCHCMD 0x41 -#define ADD_BATCHCMD 0x42 -#define SEND_BATCHCMD 0x43 -#define GET_BATCHRSP 0x44 - -#define CHIP_NORMALMODE 0x00 -#define CHIP_DEBUGMODE 0x01 - -/* SD Pass Through Command Extension */ -#define SD_PASS_THRU_MODE 0xD0 -#define SD_EXECUTE_NO_DATA 0xD1 -#define SD_EXECUTE_READ 0xD2 -#define SD_EXECUTE_WRITE 0xD3 -#define SD_GET_RSP 0xD4 -#define SD_HW_RST 0xD6 - -#ifdef SUPPORT_MAGIC_GATE -#define CMD_MSPRO_MG_RKEY 0xA4 /* Report Key Command */ -#define CMD_MSPRO_MG_SKEY 0xA3 /* Send Key Command */ - -/* CBWCB field: key class */ -#define KC_MG_R_PRO 0xBE /* MG-R PRO*/ - -/* CBWCB field: key format */ -#define KF_SET_LEAF_ID 0x31 /* Set Leaf ID */ -#define KF_GET_LOC_EKB 0x32 /* Get Local EKB */ -#define KF_CHG_HOST 0x33 /* Challenge (host) */ -#define KF_RSP_CHG 0x34 /* Response and Challenge (device) */ -#define KF_RSP_HOST 0x35 /* Response (host) */ -#define KF_GET_ICV 0x36 /* Get ICV */ -#define KF_SET_ICV 0x37 /* SSet ICV */ -#endif - -/* Sense type */ -#define SENSE_TYPE_NO_SENSE 0 -#define SENSE_TYPE_MEDIA_CHANGE 1 -#define SENSE_TYPE_MEDIA_NOT_PRESENT 2 -#define SENSE_TYPE_MEDIA_LBA_OVER_RANGE 3 -#define SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT 4 -#define SENSE_TYPE_MEDIA_WRITE_PROTECT 5 -#define SENSE_TYPE_MEDIA_INVALID_CMD_FIELD 6 -#define SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR 7 -#define SENSE_TYPE_MEDIA_WRITE_ERR 8 -#define SENSE_TYPE_FORMAT_IN_PROGRESS 9 -#define SENSE_TYPE_FORMAT_CMD_FAILED 10 -#ifdef SUPPORT_MAGIC_GATE -#define SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB 0x0b -#define SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN 0x0c -#define SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM 0x0d -#define SENSE_TYPE_MG_WRITE_ERR 0x0e -#endif -#ifdef SUPPORT_SD_LOCK -/* FOR Locked SD card*/ -#define SENSE_TYPE_MEDIA_READ_FORBIDDEN 0x10 -#endif - -void scsi_show_command(struct rtsx_chip *chip); -void set_sense_type(struct rtsx_chip *chip, unsigned int lun, int sense_type); -void set_sense_data(struct rtsx_chip *chip, unsigned int lun, u8 err_code, - u8 sense_key, u32 info, u8 asc, u8 ascq, - u8 sns_key_info0, u16 sns_key_info1); -int rtsx_scsi_handler(struct scsi_cmnd *srb, struct rtsx_chip *chip); - -#endif /* __REALTEK_RTSX_SCSI_H */ diff --git a/drivers/staging/rts5208/rtsx_sys.h b/drivers/staging/rts5208/rtsx_sys.h deleted file mode 100644 index 77094809c81456..00000000000000 --- a/drivers/staging/rts5208/rtsx_sys.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __RTSX_SYS_H -#define __RTSX_SYS_H - -#include "rtsx.h" -#include "rtsx_chip.h" -#include "rtsx_card.h" - -static inline void rtsx_exclusive_enter_ss(struct rtsx_chip *chip) -{ - struct rtsx_dev *dev = chip->rtsx; - - spin_lock(&dev->reg_lock); - rtsx_enter_ss(chip); - spin_unlock(&dev->reg_lock); -} - -static inline void rtsx_reset_detected_cards(struct rtsx_chip *chip, int flag) -{ - rtsx_reset_cards(chip); -} - -#define RTSX_MSG_IN_INT(x) - -#endif /* __RTSX_SYS_H */ - diff --git a/drivers/staging/rts5208/rtsx_transport.c b/drivers/staging/rts5208/rtsx_transport.c deleted file mode 100644 index d5ad49de4c5685..00000000000000 --- a/drivers/staging/rts5208/rtsx_transport.c +++ /dev/null @@ -1,768 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include - -#include "rtsx.h" - -/*********************************************************************** - * Scatter-gather transfer buffer access routines - ***********************************************************************/ - -/* - * Copy a buffer of length buflen to/from the srb's transfer buffer. - * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer - * points to a list of s-g entries and we ignore srb->request_bufflen. - * For non-scatter-gather transfers, srb->request_buffer points to the - * transfer buffer itself and srb->request_bufflen is the buffer's length.) - * Update the *index and *offset variables so that the next copy will - * pick up from where this one left off. - */ - -unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, - struct scsi_cmnd *srb, - unsigned int *index, - unsigned int *offset, - enum xfer_buf_dir dir) -{ - unsigned int cnt; - - /* If not using scatter-gather, just transfer the data directly. */ - if (scsi_sg_count(srb) == 0) { - unsigned char *sgbuffer; - - if (*offset >= scsi_bufflen(srb)) - return 0; - cnt = min(buflen, scsi_bufflen(srb) - *offset); - - sgbuffer = (unsigned char *)scsi_sglist(srb) + *offset; - - if (dir == TO_XFER_BUF) - memcpy(sgbuffer, buffer, cnt); - else - memcpy(buffer, sgbuffer, cnt); - *offset += cnt; - - /* - * Using scatter-gather. We have to go through the list one entry - * at a time. Each s-g entry contains some number of pages which - * have to be copied one at a time. - */ - } else { - struct scatterlist *sg = - (struct scatterlist *)scsi_sglist(srb) - + *index; - - /* - * This loop handles a single s-g list entry, which may - * include multiple pages. Find the initial page structure - * and the starting offset within the page, and update - * the *offset and *index values for the next loop. - */ - cnt = 0; - while (cnt < buflen && *index < scsi_sg_count(srb)) { - struct page *page = sg_page(sg) + - ((sg->offset + *offset) >> PAGE_SHIFT); - unsigned int poff = (sg->offset + *offset) & - (PAGE_SIZE - 1); - unsigned int sglen = sg->length - *offset; - - if (sglen > buflen - cnt) { - /* Transfer ends within this s-g entry */ - sglen = buflen - cnt; - *offset += sglen; - } else { - /* Transfer continues to next s-g entry */ - *offset = 0; - ++*index; - ++sg; - } - - while (sglen > 0) { - unsigned int plen = min(sglen, (unsigned int) - PAGE_SIZE - poff); - - if (dir == TO_XFER_BUF) - memcpy_to_page(page, poff, buffer + cnt, plen); - else - memcpy_from_page(buffer + cnt, page, poff, plen); - - /* Start at the beginning of the next page */ - poff = 0; - ++page; - cnt += plen; - sglen -= plen; - } - } - } - - /* Return the amount actually transferred */ - return cnt; -} - -/* - * Store the contents of buffer into srb's transfer buffer and set the - * SCSI residue. - */ -void rtsx_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb) -{ - unsigned int index = 0, offset = 0; - - rtsx_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset, - TO_XFER_BUF); - if (buflen < scsi_bufflen(srb)) - scsi_set_resid(srb, scsi_bufflen(srb) - buflen); -} - -void rtsx_stor_get_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb) -{ - unsigned int index = 0, offset = 0; - - rtsx_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset, - FROM_XFER_BUF); - if (buflen < scsi_bufflen(srb)) - scsi_set_resid(srb, scsi_bufflen(srb) - buflen); -} - -/*********************************************************************** - * Transport routines - ***********************************************************************/ - -/* - * Invoke the transport and basic error-handling/recovery methods - * - * This is used to send the message to the device and receive the response. - */ -void rtsx_invoke_transport(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int result; - - result = rtsx_scsi_handler(srb, chip); - - /* - * if the command gets aborted by the higher layers, we need to - * short-circuit all other processing. - */ - if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) { - dev_dbg(rtsx_dev(chip), "-- command was aborted\n"); - srb->result = DID_ABORT << 16; - goto handle_errors; - } - - /* if there is a transport error, reset and don't auto-sense */ - if (result == TRANSPORT_ERROR) { - dev_dbg(rtsx_dev(chip), "-- transport indicates error, resetting\n"); - srb->result = DID_ERROR << 16; - goto handle_errors; - } - - srb->result = SAM_STAT_GOOD; - - /* - * If we have a failure, we're going to do a REQUEST_SENSE - * automatically. Note that we differentiate between a command - * "failure" and an "error" in the transport mechanism. - */ - if (result == TRANSPORT_FAILED) { - /* set the result so the higher layers expect this data */ - srb->result = SAM_STAT_CHECK_CONDITION; - memcpy(srb->sense_buffer, - (unsigned char *)&chip->sense_buffer[SCSI_LUN(srb)], - sizeof(struct sense_data_t)); - } - - return; - -handle_errors: - return; -} - -void rtsx_add_cmd(struct rtsx_chip *chip, - u8 cmd_type, u16 reg_addr, u8 mask, u8 data) -{ - __le32 *cb = (__le32 *)(chip->host_cmds_ptr); - u32 val = 0; - - val |= (u32)(cmd_type & 0x03) << 30; - val |= (u32)(reg_addr & 0x3FFF) << 16; - val |= (u32)mask << 8; - val |= (u32)data; - - spin_lock_irq(&chip->rtsx->reg_lock); - if (chip->ci < (HOST_CMDS_BUF_LEN / 4)) - cb[(chip->ci)++] = cpu_to_le32(val); - - spin_unlock_irq(&chip->rtsx->reg_lock); -} - -void rtsx_send_cmd_no_wait(struct rtsx_chip *chip) -{ - u32 val = BIT(31); - - rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr); - - val |= (u32)(chip->ci * 4) & 0x00FFFFFF; - /* Hardware Auto Response */ - val |= 0x40000000; - rtsx_writel(chip, RTSX_HCBCTLR, val); -} - -int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout) -{ - struct rtsx_dev *rtsx = chip->rtsx; - struct completion trans_done; - u32 val = BIT(31); - long timeleft; - int err = 0; - - if (card == SD_CARD) - rtsx->check_card_cd = SD_EXIST; - else if (card == MS_CARD) - rtsx->check_card_cd = MS_EXIST; - else if (card == XD_CARD) - rtsx->check_card_cd = XD_EXIST; - else - rtsx->check_card_cd = 0; - - spin_lock_irq(&rtsx->reg_lock); - - /* set up data structures for the wakeup system */ - rtsx->done = &trans_done; - rtsx->trans_result = TRANS_NOT_READY; - init_completion(&trans_done); - rtsx->trans_state = STATE_TRANS_CMD; - - rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr); - - val |= (u32)(chip->ci * 4) & 0x00FFFFFF; - /* Hardware Auto Response */ - val |= 0x40000000; - rtsx_writel(chip, RTSX_HCBCTLR, val); - - spin_unlock_irq(&rtsx->reg_lock); - - /* Wait for TRANS_OK_INT */ - timeleft = wait_for_completion_interruptible_timeout(&trans_done, - msecs_to_jiffies(timeout)); - if (timeleft <= 0) { - dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n", - chip->int_reg); - err = -ETIMEDOUT; - goto finish_send_cmd; - } - - spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) - err = -EIO; - else if (rtsx->trans_result == TRANS_RESULT_OK) - err = 0; - - spin_unlock_irq(&rtsx->reg_lock); - -finish_send_cmd: - rtsx->done = NULL; - rtsx->trans_state = STATE_TRANS_NONE; - - if (err < 0) - rtsx_stop_cmd(chip, card); - - return err; -} - -static inline void rtsx_add_sg_tbl(struct rtsx_chip *chip, - u32 addr, u32 len, u8 option) -{ - __le64 *sgb = (__le64 *)(chip->host_sg_tbl_ptr); - u64 val = 0; - u32 temp_len = 0; - u8 temp_opt = 0; - - do { - if (len > 0x80000) { - temp_len = 0x80000; - temp_opt = option & (~RTSX_SG_END); - } else { - temp_len = len; - temp_opt = option; - } - val = ((u64)addr << 32) | ((u64)temp_len << 12) | temp_opt; - - if (chip->sgi < (HOST_SG_TBL_BUF_LEN / 8)) - sgb[(chip->sgi)++] = cpu_to_le64(val); - - len -= temp_len; - addr += temp_len; - } while (len); -} - -static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card, - struct scatterlist *sg, int num_sg, - unsigned int *index, - unsigned int *offset, int size, - enum dma_data_direction dma_dir, - int timeout) -{ - struct rtsx_dev *rtsx = chip->rtsx; - struct completion trans_done; - u8 dir; - int sg_cnt, i, resid; - int err = 0; - long timeleft; - struct scatterlist *sg_ptr; - u32 val = TRIG_DMA; - - if (!sg || num_sg <= 0 || !offset || !index) - return -EIO; - - if (dma_dir == DMA_TO_DEVICE) - dir = HOST_TO_DEVICE; - else if (dma_dir == DMA_FROM_DEVICE) - dir = DEVICE_TO_HOST; - else - return -ENXIO; - - if (card == SD_CARD) - rtsx->check_card_cd = SD_EXIST; - else if (card == MS_CARD) - rtsx->check_card_cd = MS_EXIST; - else if (card == XD_CARD) - rtsx->check_card_cd = XD_EXIST; - else - rtsx->check_card_cd = 0; - - spin_lock_irq(&rtsx->reg_lock); - - /* set up data structures for the wakeup system */ - rtsx->done = &trans_done; - - rtsx->trans_state = STATE_TRANS_SG; - rtsx->trans_result = TRANS_NOT_READY; - - spin_unlock_irq(&rtsx->reg_lock); - - sg_cnt = dma_map_sg(&rtsx->pci->dev, sg, num_sg, dma_dir); - - resid = size; - sg_ptr = sg; - chip->sgi = 0; - /* - * Usually the next entry will be @sg@ + 1, but if this sg element - * is part of a chained scatterlist, it could jump to the start of - * a new scatterlist array. So here we use sg_next to move to - * the proper sg. - */ - for (i = 0; i < *index; i++) - sg_ptr = sg_next(sg_ptr); - for (i = *index; i < sg_cnt; i++) { - dma_addr_t addr; - unsigned int len; - u8 option; - - addr = sg_dma_address(sg_ptr); - len = sg_dma_len(sg_ptr); - - dev_dbg(rtsx_dev(chip), "DMA addr: 0x%x, Len: 0x%x\n", - (unsigned int)addr, len); - dev_dbg(rtsx_dev(chip), "*index = %d, *offset = %d\n", - *index, *offset); - - addr += *offset; - - if ((len - *offset) > resid) { - *offset += resid; - len = resid; - resid = 0; - } else { - resid -= (len - *offset); - len -= *offset; - *offset = 0; - *index = *index + 1; - } - option = RTSX_SG_VALID | RTSX_SG_TRANS_DATA; - if ((i == sg_cnt - 1) || !resid) - option |= RTSX_SG_END; - - rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option); - - if (!resid) - break; - - sg_ptr = sg_next(sg_ptr); - } - - dev_dbg(rtsx_dev(chip), "SG table count = %d\n", chip->sgi); - - val |= (u32)(dir & 0x01) << 29; - val |= ADMA_MODE; - - spin_lock_irq(&rtsx->reg_lock); - - init_completion(&trans_done); - - rtsx_writel(chip, RTSX_HDBAR, chip->host_sg_tbl_addr); - rtsx_writel(chip, RTSX_HDBCTLR, val); - - spin_unlock_irq(&rtsx->reg_lock); - - timeleft = wait_for_completion_interruptible_timeout(&trans_done, - msecs_to_jiffies(timeout)); - if (timeleft <= 0) { - dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n", - __func__, __LINE__); - dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n", - chip->int_reg); - err = -ETIMEDOUT; - goto out; - } - - spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) { - err = -EIO; - spin_unlock_irq(&rtsx->reg_lock); - goto out; - } - spin_unlock_irq(&rtsx->reg_lock); - - /* Wait for TRANS_OK_INT */ - spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_NOT_READY) { - init_completion(&trans_done); - spin_unlock_irq(&rtsx->reg_lock); - timeleft = wait_for_completion_interruptible_timeout(&trans_done, - msecs_to_jiffies(timeout)); - if (timeleft <= 0) { - dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n", - __func__, __LINE__); - dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n", - chip->int_reg); - err = -ETIMEDOUT; - goto out; - } - } else { - spin_unlock_irq(&rtsx->reg_lock); - } - - spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) - err = -EIO; - else if (rtsx->trans_result == TRANS_RESULT_OK) - err = 0; - - spin_unlock_irq(&rtsx->reg_lock); - -out: - rtsx->done = NULL; - rtsx->trans_state = STATE_TRANS_NONE; - dma_unmap_sg(&rtsx->pci->dev, sg, num_sg, dma_dir); - - if (err < 0) - rtsx_stop_cmd(chip, card); - - return err; -} - -static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card, - struct scatterlist *sg, int num_sg, - enum dma_data_direction dma_dir, - int timeout) -{ - struct rtsx_dev *rtsx = chip->rtsx; - struct completion trans_done; - u8 dir; - int buf_cnt, i; - int err = 0; - long timeleft; - struct scatterlist *sg_ptr; - - if (!sg || num_sg <= 0) - return -EIO; - - if (dma_dir == DMA_TO_DEVICE) - dir = HOST_TO_DEVICE; - else if (dma_dir == DMA_FROM_DEVICE) - dir = DEVICE_TO_HOST; - else - return -ENXIO; - - if (card == SD_CARD) - rtsx->check_card_cd = SD_EXIST; - else if (card == MS_CARD) - rtsx->check_card_cd = MS_EXIST; - else if (card == XD_CARD) - rtsx->check_card_cd = XD_EXIST; - else - rtsx->check_card_cd = 0; - - spin_lock_irq(&rtsx->reg_lock); - - /* set up data structures for the wakeup system */ - rtsx->done = &trans_done; - - rtsx->trans_state = STATE_TRANS_SG; - rtsx->trans_result = TRANS_NOT_READY; - - spin_unlock_irq(&rtsx->reg_lock); - - buf_cnt = dma_map_sg(&rtsx->pci->dev, sg, num_sg, dma_dir); - - sg_ptr = sg; - - for (i = 0; i <= buf_cnt / (HOST_SG_TBL_BUF_LEN / 8); i++) { - u32 val = TRIG_DMA; - int sg_cnt, j; - - if (i == buf_cnt / (HOST_SG_TBL_BUF_LEN / 8)) - sg_cnt = buf_cnt % (HOST_SG_TBL_BUF_LEN / 8); - else - sg_cnt = HOST_SG_TBL_BUF_LEN / 8; - - chip->sgi = 0; - for (j = 0; j < sg_cnt; j++) { - dma_addr_t addr = sg_dma_address(sg_ptr); - unsigned int len = sg_dma_len(sg_ptr); - u8 option; - - dev_dbg(rtsx_dev(chip), "DMA addr: 0x%x, Len: 0x%x\n", - (unsigned int)addr, len); - - option = RTSX_SG_VALID | RTSX_SG_TRANS_DATA; - if (j == (sg_cnt - 1)) - option |= RTSX_SG_END; - - rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option); - - sg_ptr = sg_next(sg_ptr); - } - - dev_dbg(rtsx_dev(chip), "SG table count = %d\n", chip->sgi); - - val |= (u32)(dir & 0x01) << 29; - val |= ADMA_MODE; - - spin_lock_irq(&rtsx->reg_lock); - - init_completion(&trans_done); - - rtsx_writel(chip, RTSX_HDBAR, chip->host_sg_tbl_addr); - rtsx_writel(chip, RTSX_HDBCTLR, val); - - spin_unlock_irq(&rtsx->reg_lock); - - timeleft = wait_for_completion_interruptible_timeout(&trans_done, - msecs_to_jiffies(timeout)); - if (timeleft <= 0) { - dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n", - __func__, __LINE__); - dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n", - chip->int_reg); - err = -ETIMEDOUT; - goto out; - } - - spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) { - err = -EIO; - spin_unlock_irq(&rtsx->reg_lock); - goto out; - } - spin_unlock_irq(&rtsx->reg_lock); - - sg_ptr += sg_cnt; - } - - /* Wait for TRANS_OK_INT */ - spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_NOT_READY) { - init_completion(&trans_done); - spin_unlock_irq(&rtsx->reg_lock); - timeleft = wait_for_completion_interruptible_timeout(&trans_done, - msecs_to_jiffies(timeout)); - if (timeleft <= 0) { - dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n", - __func__, __LINE__); - dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n", - chip->int_reg); - err = -ETIMEDOUT; - goto out; - } - } else { - spin_unlock_irq(&rtsx->reg_lock); - } - - spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) - err = -EIO; - else if (rtsx->trans_result == TRANS_RESULT_OK) - err = 0; - - spin_unlock_irq(&rtsx->reg_lock); - -out: - rtsx->done = NULL; - rtsx->trans_state = STATE_TRANS_NONE; - dma_unmap_sg(&rtsx->pci->dev, sg, num_sg, dma_dir); - - if (err < 0) - rtsx_stop_cmd(chip, card); - - return err; -} - -static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf, - size_t len, enum dma_data_direction dma_dir, - int timeout) -{ - struct rtsx_dev *rtsx = chip->rtsx; - struct completion trans_done; - dma_addr_t addr; - u8 dir; - int err = 0; - u32 val = BIT(31); - long timeleft; - - if (!buf || len <= 0) - return -EIO; - - if (dma_dir == DMA_TO_DEVICE) - dir = HOST_TO_DEVICE; - else if (dma_dir == DMA_FROM_DEVICE) - dir = DEVICE_TO_HOST; - else - return -ENXIO; - - addr = dma_map_single(&rtsx->pci->dev, buf, len, dma_dir); - if (dma_mapping_error(&rtsx->pci->dev, addr)) - return -ENOMEM; - - if (card == SD_CARD) - rtsx->check_card_cd = SD_EXIST; - else if (card == MS_CARD) - rtsx->check_card_cd = MS_EXIST; - else if (card == XD_CARD) - rtsx->check_card_cd = XD_EXIST; - else - rtsx->check_card_cd = 0; - - val |= (u32)(dir & 0x01) << 29; - val |= (u32)(len & 0x00FFFFFF); - - spin_lock_irq(&rtsx->reg_lock); - - /* set up data structures for the wakeup system */ - rtsx->done = &trans_done; - - init_completion(&trans_done); - - rtsx->trans_state = STATE_TRANS_BUF; - rtsx->trans_result = TRANS_NOT_READY; - - rtsx_writel(chip, RTSX_HDBAR, addr); - rtsx_writel(chip, RTSX_HDBCTLR, val); - - spin_unlock_irq(&rtsx->reg_lock); - - /* Wait for TRANS_OK_INT */ - timeleft = wait_for_completion_interruptible_timeout(&trans_done, - msecs_to_jiffies(timeout)); - if (timeleft <= 0) { - dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n", - __func__, __LINE__); - dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n", - chip->int_reg); - err = -ETIMEDOUT; - goto out; - } - - spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) - err = -EIO; - else if (rtsx->trans_result == TRANS_RESULT_OK) - err = 0; - - spin_unlock_irq(&rtsx->reg_lock); - -out: - rtsx->done = NULL; - rtsx->trans_state = STATE_TRANS_NONE; - dma_unmap_single(&rtsx->pci->dev, addr, len, dma_dir); - - if (err < 0) - rtsx_stop_cmd(chip, card); - - return err; -} - -int rtsx_transfer_data_partial(struct rtsx_chip *chip, u8 card, - void *buf, size_t len, int use_sg, - unsigned int *index, unsigned int *offset, - enum dma_data_direction dma_dir, int timeout) -{ - int err = 0; - - /* don't transfer data during abort processing */ - if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) - return -EIO; - - if (use_sg) { - struct scatterlist *sg = buf; - - err = rtsx_transfer_sglist_adma_partial(chip, card, sg, use_sg, - index, offset, (int)len, - dma_dir, timeout); - } else { - err = rtsx_transfer_buf(chip, card, - buf, len, dma_dir, timeout); - } - if (err < 0) { - if (RTSX_TST_DELINK(chip)) { - RTSX_CLR_DELINK(chip); - chip->need_reinit = SD_CARD | MS_CARD | XD_CARD; - rtsx_reinit_cards(chip, 1); - } - } - - return err; -} - -int rtsx_transfer_data(struct rtsx_chip *chip, u8 card, void *buf, size_t len, - int use_sg, enum dma_data_direction dma_dir, int timeout) -{ - int err = 0; - - dev_dbg(rtsx_dev(chip), "use_sg = %d\n", use_sg); - - /* don't transfer data during abort processing */ - if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) - return -EIO; - - if (use_sg) { - err = rtsx_transfer_sglist_adma(chip, card, buf, - use_sg, dma_dir, timeout); - } else { - err = rtsx_transfer_buf(chip, card, buf, len, dma_dir, timeout); - } - - if (err < 0) { - if (RTSX_TST_DELINK(chip)) { - RTSX_CLR_DELINK(chip); - chip->need_reinit = SD_CARD | MS_CARD | XD_CARD; - rtsx_reinit_cards(chip, 1); - } - } - - return err; -} - diff --git a/drivers/staging/rts5208/rtsx_transport.h b/drivers/staging/rts5208/rtsx_transport.h deleted file mode 100644 index 097efed24b7985..00000000000000 --- a/drivers/staging/rts5208/rtsx_transport.h +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_TRANSPORT_H -#define __REALTEK_RTSX_TRANSPORT_H - -#include "rtsx.h" -#include "rtsx_chip.h" - -#define WAIT_TIME 2000 - -unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, - struct scsi_cmnd *srb, - unsigned int *index, - unsigned int *offset, - enum xfer_buf_dir dir); -void rtsx_stor_set_xfer_buf(unsigned char *buffer, unsigned int buflen, - struct scsi_cmnd *srb); -void rtsx_stor_get_xfer_buf(unsigned char *buffer, unsigned int buflen, - struct scsi_cmnd *srb); -void rtsx_invoke_transport(struct scsi_cmnd *srb, struct rtsx_chip *chip); - -#define rtsx_init_cmd(chip) ((chip)->ci = 0) - -void rtsx_add_cmd(struct rtsx_chip *chip, u8 cmd_type, u16 reg_addr, u8 mask, - u8 data); -void rtsx_send_cmd_no_wait(struct rtsx_chip *chip); -int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout); - -static inline u8 *rtsx_get_cmd_data(struct rtsx_chip *chip) -{ -#ifdef CMD_USING_SG - return (u8 *)(chip->host_sg_tbl_ptr); -#else - return (u8 *)(chip->host_cmds_ptr); -#endif -} - -int rtsx_transfer_data(struct rtsx_chip *chip, u8 card, void *buf, size_t len, - int use_sg, enum dma_data_direction dma_dir, - int timeout); - -int rtsx_transfer_data_partial(struct rtsx_chip *chip, u8 card, void *buf, - size_t len, int use_sg, unsigned int *index, - unsigned int *offset, - enum dma_data_direction dma_dir, int timeout); - -#endif /* __REALTEK_RTSX_TRANSPORT_H */ diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c deleted file mode 100644 index 74c4f476b3a4a1..00000000000000 --- a/drivers/staging/rts5208/sd.c +++ /dev/null @@ -1,4717 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include - -#include "rtsx.h" -#include "sd.h" - -#define SD_MAX_RETRY_COUNT 3 - -static u16 REG_SD_CFG1; -static u16 REG_SD_CFG2; -static u16 REG_SD_CFG3; -static u16 REG_SD_STAT1; -static u16 REG_SD_STAT2; -static u16 REG_SD_BUS_STAT; -static u16 REG_SD_PAD_CTL; -static u16 REG_SD_SAMPLE_POINT_CTL; -static u16 REG_SD_PUSH_POINT_CTL; -static u16 REG_SD_CMD0; -static u16 REG_SD_CMD1; -static u16 REG_SD_CMD2; -static u16 REG_SD_CMD3; -static u16 REG_SD_CMD4; -static u16 REG_SD_CMD5; -static u16 REG_SD_BYTE_CNT_L; -static u16 REG_SD_BYTE_CNT_H; -static u16 REG_SD_BLOCK_CNT_L; -static u16 REG_SD_BLOCK_CNT_H; -static u16 REG_SD_TRANSFER; -static u16 REG_SD_VPCLK0_CTL; -static u16 REG_SD_VPCLK1_CTL; -static u16 REG_SD_DCMPS0_CTL; -static u16 REG_SD_DCMPS1_CTL; - -static inline void sd_set_err_code(struct rtsx_chip *chip, u8 err_code) -{ - struct sd_info *sd_card = &chip->sd_card; - - sd_card->err_code |= err_code; -} - -static inline void sd_clr_err_code(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - - sd_card->err_code = 0; -} - -static inline int sd_check_err_code(struct rtsx_chip *chip, u8 err_code) -{ - struct sd_info *sd_card = &chip->sd_card; - - return sd_card->err_code & err_code; -} - -static void sd_init_reg_addr(struct rtsx_chip *chip) -{ - REG_SD_CFG1 = 0xFD31; - REG_SD_CFG2 = 0xFD33; - REG_SD_CFG3 = 0xFD3E; - REG_SD_STAT1 = 0xFD30; - REG_SD_STAT2 = 0; - REG_SD_BUS_STAT = 0; - REG_SD_PAD_CTL = 0; - REG_SD_SAMPLE_POINT_CTL = 0; - REG_SD_PUSH_POINT_CTL = 0; - REG_SD_CMD0 = 0xFD34; - REG_SD_CMD1 = 0xFD35; - REG_SD_CMD2 = 0xFD36; - REG_SD_CMD3 = 0xFD37; - REG_SD_CMD4 = 0xFD38; - REG_SD_CMD5 = 0xFD5A; - REG_SD_BYTE_CNT_L = 0xFD39; - REG_SD_BYTE_CNT_H = 0xFD3A; - REG_SD_BLOCK_CNT_L = 0xFD3B; - REG_SD_BLOCK_CNT_H = 0xFD3C; - REG_SD_TRANSFER = 0xFD32; - REG_SD_VPCLK0_CTL = 0; - REG_SD_VPCLK1_CTL = 0; - REG_SD_DCMPS0_CTL = 0; - REG_SD_DCMPS1_CTL = 0; -} - -static int sd_check_data0_status(struct rtsx_chip *chip) -{ - int retval; - u8 stat; - - retval = rtsx_read_register(chip, REG_SD_STAT1, &stat); - if (retval) - return retval; - - if (!(stat & SD_DAT0_STATUS)) { - sd_set_err_code(chip, SD_BUSY); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx, - u32 arg, u8 rsp_type, u8 *rsp, int rsp_len) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int timeout = 100; - u16 reg_addr; - u8 *ptr; - int stat_idx = 0; - int rty_cnt = 0; - - sd_clr_err_code(chip); - - dev_dbg(rtsx_dev(chip), "SD/MMC CMD %d, arg = 0x%08x\n", cmd_idx, arg); - - if (rsp_type == SD_RSP_TYPE_R1b) - timeout = 3000; - -RTY_SEND_CMD: - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0, 0xFF, 0x40 | cmd_idx); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD1, 0xFF, (u8)(arg >> 24)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD2, 0xFF, (u8)(arg >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD3, 0xFF, (u8)(arg >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD4, 0xFF, (u8)arg); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, rsp_type); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, - 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, - SD_TRANSFER_END | SD_STAT_IDLE, SD_TRANSFER_END | - SD_STAT_IDLE); - - if (rsp_type == SD_RSP_TYPE_R2) { - for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; - reg_addr++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - - stat_idx = 16; - } else if (rsp_type != SD_RSP_TYPE_R0) { - for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; - reg_addr++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - - stat_idx = 5; - } - - rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_STAT1, 0, 0); - - retval = rtsx_send_cmd(chip, SD_CARD, timeout); - if (retval < 0) { - u8 val; - - rtsx_read_register(chip, REG_SD_STAT1, &val); - dev_dbg(rtsx_dev(chip), "SD_STAT1: 0x%x\n", val); - - rtsx_read_register(chip, REG_SD_CFG3, &val); - dev_dbg(rtsx_dev(chip), "SD_CFG3: 0x%x\n", val); - - if (retval == -ETIMEDOUT) { - if (rsp_type & SD_WAIT_BUSY_END) { - retval = sd_check_data0_status(chip); - if (retval != STATUS_SUCCESS) { - rtsx_clear_sd_error(chip); - return retval; - } - } else { - sd_set_err_code(chip, SD_TO_ERR); - } - retval = STATUS_TIMEDOUT; - } else { - retval = STATUS_FAIL; - } - rtsx_clear_sd_error(chip); - - return retval; - } - - if (rsp_type == SD_RSP_TYPE_R0) - return STATUS_SUCCESS; - - ptr = rtsx_get_cmd_data(chip) + 1; - - if ((ptr[0] & 0xC0) != 0) { - sd_set_err_code(chip, SD_STS_ERR); - return STATUS_FAIL; - } - - if (!(rsp_type & SD_NO_CHECK_CRC7)) { - if (ptr[stat_idx] & SD_CRC7_ERR) { - if (cmd_idx == WRITE_MULTIPLE_BLOCK) { - sd_set_err_code(chip, SD_CRC_ERR); - return STATUS_FAIL; - } - if (rty_cnt < SD_MAX_RETRY_COUNT) { - wait_timeout(20); - rty_cnt++; - goto RTY_SEND_CMD; - } else { - sd_set_err_code(chip, SD_CRC_ERR); - return STATUS_FAIL; - } - } - } - - if (rsp_type == SD_RSP_TYPE_R1 || rsp_type == SD_RSP_TYPE_R1b) { - if (cmd_idx != SEND_RELATIVE_ADDR && - cmd_idx != SEND_IF_COND) { - if (cmd_idx != STOP_TRANSMISSION) { - if (ptr[1] & 0x80) - return STATUS_FAIL; - } -#ifdef SUPPORT_SD_LOCK - if (ptr[1] & 0x7D) { -#else - if (ptr[1] & 0x7F) { -#endif - dev_dbg(rtsx_dev(chip), "ptr[1]: 0x%02x\n", - ptr[1]); - return STATUS_FAIL; - } - if (ptr[2] & 0xFF) { - dev_dbg(rtsx_dev(chip), "ptr[2]: 0x%02x\n", - ptr[2]); - return STATUS_FAIL; - } - if (ptr[3] & 0x80) { - dev_dbg(rtsx_dev(chip), "ptr[3]: 0x%02x\n", - ptr[3]); - return STATUS_FAIL; - } - if (ptr[3] & 0x01) - sd_card->sd_data_buf_ready = 1; - else - sd_card->sd_data_buf_ready = 0; - } - } - - if (rsp && rsp_len) - memcpy(rsp, ptr, rsp_len); - - return STATUS_SUCCESS; -} - -static int sd_read_data(struct rtsx_chip *chip, - u8 trans_mode, u8 *cmd, int cmd_len, u16 byte_cnt, - u16 blk_cnt, u8 bus_width, u8 *buf, int buf_len, - int timeout) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int i; - - sd_clr_err_code(chip); - - if (!buf) - buf_len = 0; - - if (buf_len > 512) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - if (cmd_len) { - dev_dbg(rtsx_dev(chip), "SD/MMC CMD %d\n", cmd[0] - 0x40); - for (i = 0; i < (min(cmd_len, 6)); i++) - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0 + i, - 0xFF, cmd[i]); - } - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, - (u8)byte_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, - (u8)(byte_cnt >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, 0xFF, - (u8)blk_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, 0xFF, - (u8)(blk_cnt >> 8)); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, bus_width); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, - SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END | - SD_CHECK_CRC7 | SD_RSP_LEN_6); - if (trans_mode != SD_TM_AUTO_TUNING) - rtsx_add_cmd(chip, WRITE_REG_CMD, - CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - trans_mode | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, - SD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, SD_CARD, timeout); - if (retval < 0) { - if (retval == -ETIMEDOUT) { - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - } - - return STATUS_FAIL; - } - - if (buf && buf_len) { - retval = rtsx_read_ppbuf(chip, buf, buf_len); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_write_data(struct rtsx_chip *chip, u8 trans_mode, - u8 *cmd, int cmd_len, u16 byte_cnt, u16 blk_cnt, - u8 bus_width, u8 *buf, int buf_len, int timeout) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int i; - - sd_clr_err_code(chip); - - if (!buf) - buf_len = 0; - - if (buf_len > 512) { - /* This function can't write data more than one page */ - return STATUS_FAIL; - } - - if (buf && buf_len) { - retval = rtsx_write_ppbuf(chip, buf, buf_len); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - rtsx_init_cmd(chip); - - if (cmd_len) { - dev_dbg(rtsx_dev(chip), "SD/MMC CMD %d\n", cmd[0] - 0x40); - for (i = 0; i < (min(cmd_len, 6)); i++) { - rtsx_add_cmd(chip, WRITE_REG_CMD, - REG_SD_CMD0 + i, 0xFF, cmd[i]); - } - } - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, - (u8)byte_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, - (u8)(byte_cnt >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, 0xFF, - (u8)blk_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, 0xFF, - (u8)(blk_cnt >> 8)); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, bus_width); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, - SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END | - SD_CHECK_CRC7 | SD_RSP_LEN_6); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - trans_mode | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, - SD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, SD_CARD, timeout); - if (retval < 0) { - if (retval == -ETIMEDOUT) { - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - } - - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_check_csd(struct rtsx_chip *chip, char check_wp) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int i; - u8 csd_ver, trans_speed; - u8 rsp[16]; - - for (i = 0; i < 6; i++) { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - return STATUS_FAIL; - } - - retval = sd_send_cmd_get_rsp(chip, SEND_CSD, sd_card->sd_addr, - SD_RSP_TYPE_R2, rsp, 16); - if (retval == STATUS_SUCCESS) - break; - } - - if (i == 6) - return STATUS_FAIL; - - memcpy(sd_card->raw_csd, rsp + 1, 15); - - dev_dbg(rtsx_dev(chip), "CSD Response:\n"); - dev_dbg(rtsx_dev(chip), "%*ph\n", 16, sd_card->raw_csd); - - csd_ver = (rsp[1] & 0xc0) >> 6; - dev_dbg(rtsx_dev(chip), "csd_ver = %d\n", csd_ver); - - trans_speed = rsp[4]; - if ((trans_speed & 0x07) == 0x02) { - if ((trans_speed & 0xf8) >= 0x30) { - if (chip->asic_code) - sd_card->sd_clock = 47; - else - sd_card->sd_clock = CLK_50; - - } else if ((trans_speed & 0xf8) == 0x28) { - if (chip->asic_code) - sd_card->sd_clock = 39; - else - sd_card->sd_clock = CLK_40; - - } else if ((trans_speed & 0xf8) == 0x20) { - if (chip->asic_code) - sd_card->sd_clock = 29; - else - sd_card->sd_clock = CLK_30; - - } else if ((trans_speed & 0xf8) >= 0x10) { - if (chip->asic_code) - sd_card->sd_clock = 23; - else - sd_card->sd_clock = CLK_20; - - } else if ((trans_speed & 0x08) >= 0x08) { - if (chip->asic_code) - sd_card->sd_clock = 19; - else - sd_card->sd_clock = CLK_20; - } else { - return STATUS_FAIL; - } - } else { - return STATUS_FAIL; - } - - if (CHK_MMC_SECTOR_MODE(sd_card)) { - sd_card->capacity = 0; - } else { - if ((!CHK_SD_HCXC(sd_card)) || csd_ver == 0) { - u8 blk_size, c_size_mult; - u16 c_size; - - blk_size = rsp[6] & 0x0F; - c_size = ((u16)(rsp[7] & 0x03) << 10) - + ((u16)rsp[8] << 2) - + ((u16)(rsp[9] & 0xC0) >> 6); - c_size_mult = (u8)((rsp[10] & 0x03) << 1); - c_size_mult += (rsp[11] & 0x80) >> 7; - sd_card->capacity = (((u32)(c_size + 1)) * - (1 << (c_size_mult + 2))) - << (blk_size - 9); - } else { - u32 total_sector = 0; - - total_sector = (((u32)rsp[8] & 0x3f) << 16) | - ((u32)rsp[9] << 8) | (u32)rsp[10]; - sd_card->capacity = (total_sector + 1) << 10; - } - } - - if (check_wp) { - if (rsp[15] & 0x30) - chip->card_wp |= SD_CARD; - - dev_dbg(rtsx_dev(chip), "CSD WP Status: 0x%x\n", rsp[15]); - } - - return STATUS_SUCCESS; -} - -static int sd_set_sample_push_timing(struct rtsx_chip *chip) -{ - int retval; - struct sd_info *sd_card = &chip->sd_card; - u8 val = 0; - - if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY) - val |= 0x10; - - if ((chip->sd_ctl & SD_SAMPLE_POINT_CTL_MASK) == SD_SAMPLE_POINT_AUTO) { - if (chip->asic_code) { - if (CHK_SD_HS(sd_card) || CHK_MMC_52M(sd_card)) { - if (val & 0x10) - val |= 0x04; - else - val |= 0x08; - } - } else { - if (val & 0x10) - val |= 0x04; - else - val |= 0x08; - } - } else if ((chip->sd_ctl & SD_SAMPLE_POINT_CTL_MASK) == - SD_SAMPLE_POINT_DELAY) { - if (val & 0x10) - val |= 0x04; - else - val |= 0x08; - } - - retval = rtsx_write_register(chip, REG_SD_CFG1, 0x1C, val); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static void sd_choose_proper_clock(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - - if (CHK_SD_SDR104(sd_card)) { - if (chip->asic_code) - sd_card->sd_clock = chip->asic_sd_sdr104_clk; - else - sd_card->sd_clock = chip->fpga_sd_sdr104_clk; - - } else if (CHK_SD_DDR50(sd_card)) { - if (chip->asic_code) - sd_card->sd_clock = chip->asic_sd_ddr50_clk; - else - sd_card->sd_clock = chip->fpga_sd_ddr50_clk; - - } else if (CHK_SD_SDR50(sd_card)) { - if (chip->asic_code) - sd_card->sd_clock = chip->asic_sd_sdr50_clk; - else - sd_card->sd_clock = chip->fpga_sd_sdr50_clk; - - } else if (CHK_SD_HS(sd_card)) { - if (chip->asic_code) - sd_card->sd_clock = chip->asic_sd_hs_clk; - else - sd_card->sd_clock = chip->fpga_sd_hs_clk; - - } else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) { - if (chip->asic_code) - sd_card->sd_clock = chip->asic_mmc_52m_clk; - else - sd_card->sd_clock = chip->fpga_mmc_52m_clk; - - } else if (CHK_MMC_26M(sd_card)) { - if (chip->asic_code) - sd_card->sd_clock = 48; - else - sd_card->sd_clock = CLK_50; - } -} - -static int sd_set_clock_divider(struct rtsx_chip *chip, u8 clk_div) -{ - int retval; - u8 mask = 0, val = 0; - - mask = 0x60; - if (clk_div == SD_CLK_DIVIDE_0) - val = 0x00; - else if (clk_div == SD_CLK_DIVIDE_128) - val = 0x40; - else if (clk_div == SD_CLK_DIVIDE_256) - val = 0x20; - - retval = rtsx_write_register(chip, REG_SD_CFG1, mask, val); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static int sd_set_init_para(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - - retval = sd_set_sample_push_timing(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - sd_choose_proper_clock(chip); - - retval = switch_clock(chip, sd_card->sd_clock); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -int sd_select_card(struct rtsx_chip *chip, int select) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 cmd_idx, cmd_type; - u32 addr; - - if (select) { - cmd_idx = SELECT_CARD; - cmd_type = SD_RSP_TYPE_R1; - addr = sd_card->sd_addr; - } else { - cmd_idx = DESELECT_CARD; - cmd_type = SD_RSP_TYPE_R0; - addr = 0; - } - - retval = sd_send_cmd_get_rsp(chip, cmd_idx, addr, cmd_type, NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -#ifdef SUPPORT_SD_LOCK -static int sd_update_lock_status(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 rsp[5]; - - retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, rsp, 5); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (rsp[1] & 0x02) - sd_card->sd_lock_status |= SD_LOCKED; - else - sd_card->sd_lock_status &= ~SD_LOCKED; - - dev_dbg(rtsx_dev(chip), "sd_card->sd_lock_status = 0x%x\n", - sd_card->sd_lock_status); - - if (rsp[1] & 0x01) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} -#endif - -static int sd_wait_state_data_ready(struct rtsx_chip *chip, u8 state, - u8 data_ready, int polling_cnt) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval, i; - u8 rsp[5]; - - for (i = 0; i < polling_cnt; i++) { - retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, - sd_card->sd_addr, SD_RSP_TYPE_R1, - rsp, 5); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (((rsp[3] & 0x1E) == state) && - ((rsp[3] & 0x01) == data_ready)) - return STATUS_SUCCESS; - } - - return STATUS_FAIL; -} - -static int sd_change_bank_voltage(struct rtsx_chip *chip, u8 voltage) -{ - int retval; - - if (voltage == SD_IO_3V3) { - if (chip->asic_code) { - retval = rtsx_write_phy_register(chip, 0x08, - 0x4FC0 | - chip->phy_voltage); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register(chip, SD_PAD_CTL, - SD_IO_USING_1V8, 0); - if (retval) - return retval; - } - } else if (voltage == SD_IO_1V8) { - if (chip->asic_code) { - retval = rtsx_write_phy_register(chip, 0x08, - 0x4C40 | - chip->phy_voltage); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register(chip, SD_PAD_CTL, - SD_IO_USING_1V8, - SD_IO_USING_1V8); - if (retval) - return retval; - } - } else { - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_voltage_switch(struct rtsx_chip *chip) -{ - int retval; - u8 stat; - - retval = rtsx_write_register(chip, SD_BUS_STAT, - SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, - SD_CLK_TOGGLE_EN); - if (retval) - return retval; - - retval = sd_send_cmd_get_rsp(chip, VOLTAGE_SWITCH, 0, SD_RSP_TYPE_R1, - NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - udelay(chip->sd_voltage_switch_delay); - - retval = rtsx_read_register(chip, SD_BUS_STAT, &stat); - if (retval) - return retval; - if (stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | - SD_DAT1_STATUS | SD_DAT0_STATUS)) { - return STATUS_FAIL; - } - - retval = rtsx_write_register(chip, SD_BUS_STAT, 0xFF, - SD_CLK_FORCE_STOP); - if (retval) - return retval; - retval = sd_change_bank_voltage(chip, SD_IO_1V8); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - wait_timeout(50); - - retval = rtsx_write_register(chip, SD_BUS_STAT, 0xFF, - SD_CLK_TOGGLE_EN); - if (retval) - return retval; - wait_timeout(10); - - retval = rtsx_read_register(chip, SD_BUS_STAT, &stat); - if (retval) - return retval; - if ((stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | - SD_DAT1_STATUS | SD_DAT0_STATUS)) != - (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | - SD_DAT1_STATUS | SD_DAT0_STATUS)) { - dev_dbg(rtsx_dev(chip), "SD_BUS_STAT: 0x%x\n", stat); - rtsx_write_register(chip, SD_BUS_STAT, SD_CLK_TOGGLE_EN | - SD_CLK_FORCE_STOP, 0); - rtsx_write_register(chip, CARD_CLK_EN, 0xFF, 0); - return STATUS_FAIL; - } - - retval = rtsx_write_register(chip, SD_BUS_STAT, - SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static int sd_reset_dcm(struct rtsx_chip *chip, u8 tune_dir) -{ - int retval; - - if (tune_dir == TUNE_RX) { - retval = rtsx_write_register(chip, DCM_DRP_CTL, 0xFF, - DCM_RESET | DCM_RX); - if (retval) - return retval; - retval = rtsx_write_register(chip, DCM_DRP_CTL, 0xFF, DCM_RX); - if (retval) - return retval; - } else { - retval = rtsx_write_register(chip, DCM_DRP_CTL, 0xFF, - DCM_RESET | DCM_TX); - if (retval) - return retval; - retval = rtsx_write_register(chip, DCM_DRP_CTL, 0xFF, DCM_TX); - if (retval) - return retval; - } - - return STATUS_SUCCESS; -} - -static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) -{ - struct sd_info *sd_card = &chip->sd_card; - u16 SD_VP_CTL, SD_DCMPS_CTL; - u8 val; - int retval; - bool ddr_rx = false; - - dev_dbg(rtsx_dev(chip), "%s (sample_point = %d, tune_dir = %d)\n", - __func__, sample_point, tune_dir); - - if (tune_dir == TUNE_RX) { - SD_VP_CTL = SD_VPRX_CTL; - SD_DCMPS_CTL = SD_DCMPS_RX_CTL; - if (CHK_SD_DDR50(sd_card)) - ddr_rx = true; - } else { - SD_VP_CTL = SD_VPTX_CTL; - SD_DCMPS_CTL = SD_DCMPS_TX_CTL; - } - - if (chip->asic_code) { - retval = rtsx_write_register(chip, CLK_CTL, CHANGE_CLK, - CHANGE_CLK); - if (retval) - return retval; - retval = rtsx_write_register(chip, SD_VP_CTL, 0x1F, - sample_point); - if (retval) - return retval; - retval = rtsx_write_register(chip, SD_VPCLK0_CTL, - PHASE_NOT_RESET, 0); - if (retval) - return retval; - retval = rtsx_write_register(chip, SD_VPCLK0_CTL, - PHASE_NOT_RESET, PHASE_NOT_RESET); - if (retval) - return retval; - retval = rtsx_write_register(chip, CLK_CTL, CHANGE_CLK, 0); - if (retval) - return retval; - } else { - rtsx_read_register(chip, SD_VP_CTL, &val); - dev_dbg(rtsx_dev(chip), "SD_VP_CTL: 0x%x\n", val); - rtsx_read_register(chip, SD_DCMPS_CTL, &val); - dev_dbg(rtsx_dev(chip), "SD_DCMPS_CTL: 0x%x\n", val); - - if (ddr_rx) { - retval = rtsx_write_register(chip, SD_VP_CTL, - PHASE_CHANGE, - PHASE_CHANGE); - if (retval) - return retval; - udelay(50); - retval = rtsx_write_register(chip, SD_VP_CTL, 0xFF, - PHASE_CHANGE | - PHASE_NOT_RESET | - sample_point); - if (retval) - return retval; - } else { - retval = rtsx_write_register(chip, CLK_CTL, - CHANGE_CLK, CHANGE_CLK); - if (retval) - return retval; - udelay(50); - retval = rtsx_write_register(chip, SD_VP_CTL, 0xFF, - PHASE_NOT_RESET | - sample_point); - if (retval) - return retval; - } - udelay(100); - - rtsx_init_cmd(chip); - rtsx_add_cmd(chip, WRITE_REG_CMD, SD_DCMPS_CTL, DCMPS_CHANGE, - DCMPS_CHANGE); - rtsx_add_cmd(chip, CHECK_REG_CMD, SD_DCMPS_CTL, - DCMPS_CHANGE_DONE, DCMPS_CHANGE_DONE); - retval = rtsx_send_cmd(chip, SD_CARD, 100); - if (retval != STATUS_SUCCESS) - goto fail; - - val = *rtsx_get_cmd_data(chip); - if (val & DCMPS_ERROR) - goto fail; - - if ((val & DCMPS_CURRENT_PHASE) != sample_point) - goto fail; - - retval = rtsx_write_register(chip, SD_DCMPS_CTL, - DCMPS_CHANGE, 0); - if (retval) - return retval; - if (ddr_rx) { - retval = rtsx_write_register(chip, SD_VP_CTL, - PHASE_CHANGE, 0); - if (retval) - return retval; - } else { - retval = rtsx_write_register(chip, CLK_CTL, - CHANGE_CLK, 0); - if (retval) - return retval; - } - - udelay(50); - } - - retval = rtsx_write_register(chip, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0); - if (retval) - return retval; - - return STATUS_SUCCESS; - -fail: - rtsx_read_register(chip, SD_VP_CTL, &val); - dev_dbg(rtsx_dev(chip), "SD_VP_CTL: 0x%x\n", val); - rtsx_read_register(chip, SD_DCMPS_CTL, &val); - dev_dbg(rtsx_dev(chip), "SD_DCMPS_CTL: 0x%x\n", val); - - rtsx_write_register(chip, SD_DCMPS_CTL, DCMPS_CHANGE, 0); - rtsx_write_register(chip, SD_VP_CTL, PHASE_CHANGE, 0); - mdelay(10); - sd_reset_dcm(chip, tune_dir); - return STATUS_FAIL; -} - -static int sd_check_spec(struct rtsx_chip *chip, u8 bus_width) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 cmd[5], buf[8]; - - retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - cmd[0] = 0x40 | SEND_SCR; - cmd[1] = 0; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = 0; - - retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 8, 1, bus_width, - buf, 8, 250); - if (retval != STATUS_SUCCESS) { - rtsx_clear_sd_error(chip); - return STATUS_FAIL; - } - - memcpy(sd_card->raw_scr, buf, 8); - - if ((buf[0] & 0x0F) == 0) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int sd_query_switch_result(struct rtsx_chip *chip, u8 func_group, - u8 func_to_switch, u8 *buf, int buf_len) -{ - u8 support_mask = 0, query_switch = 0, switch_busy = 0; - int support_offset = 0, query_switch_offset = 0, check_busy_offset = 0; - - if (func_group == SD_FUNC_GROUP_1) { - support_offset = FUNCTION_GROUP1_SUPPORT_OFFSET; - query_switch_offset = FUNCTION_GROUP1_QUERY_SWITCH_OFFSET; - check_busy_offset = FUNCTION_GROUP1_CHECK_BUSY_OFFSET; - - switch (func_to_switch) { - case HS_SUPPORT: - support_mask = HS_SUPPORT_MASK; - query_switch = HS_QUERY_SWITCH_OK; - switch_busy = HS_SWITCH_BUSY; - break; - - case SDR50_SUPPORT: - support_mask = SDR50_SUPPORT_MASK; - query_switch = SDR50_QUERY_SWITCH_OK; - switch_busy = SDR50_SWITCH_BUSY; - break; - - case SDR104_SUPPORT: - support_mask = SDR104_SUPPORT_MASK; - query_switch = SDR104_QUERY_SWITCH_OK; - switch_busy = SDR104_SWITCH_BUSY; - break; - - case DDR50_SUPPORT: - support_mask = DDR50_SUPPORT_MASK; - query_switch = DDR50_QUERY_SWITCH_OK; - switch_busy = DDR50_SWITCH_BUSY; - break; - - default: - return STATUS_FAIL; - } - } else if (func_group == SD_FUNC_GROUP_3) { - support_offset = FUNCTION_GROUP3_SUPPORT_OFFSET; - query_switch_offset = FUNCTION_GROUP3_QUERY_SWITCH_OFFSET; - check_busy_offset = FUNCTION_GROUP3_CHECK_BUSY_OFFSET; - - switch (func_to_switch) { - case DRIVING_TYPE_A: - support_mask = DRIVING_TYPE_A_MASK; - query_switch = TYPE_A_QUERY_SWITCH_OK; - switch_busy = TYPE_A_SWITCH_BUSY; - break; - - case DRIVING_TYPE_C: - support_mask = DRIVING_TYPE_C_MASK; - query_switch = TYPE_C_QUERY_SWITCH_OK; - switch_busy = TYPE_C_SWITCH_BUSY; - break; - - case DRIVING_TYPE_D: - support_mask = DRIVING_TYPE_D_MASK; - query_switch = TYPE_D_QUERY_SWITCH_OK; - switch_busy = TYPE_D_SWITCH_BUSY; - break; - - default: - return STATUS_FAIL; - } - } else if (func_group == SD_FUNC_GROUP_4) { - support_offset = FUNCTION_GROUP4_SUPPORT_OFFSET; - query_switch_offset = FUNCTION_GROUP4_QUERY_SWITCH_OFFSET; - check_busy_offset = FUNCTION_GROUP4_CHECK_BUSY_OFFSET; - - switch (func_to_switch) { - case CURRENT_LIMIT_400: - support_mask = CURRENT_LIMIT_400_MASK; - query_switch = CURRENT_LIMIT_400_QUERY_SWITCH_OK; - switch_busy = CURRENT_LIMIT_400_SWITCH_BUSY; - break; - - case CURRENT_LIMIT_600: - support_mask = CURRENT_LIMIT_600_MASK; - query_switch = CURRENT_LIMIT_600_QUERY_SWITCH_OK; - switch_busy = CURRENT_LIMIT_600_SWITCH_BUSY; - break; - - case CURRENT_LIMIT_800: - support_mask = CURRENT_LIMIT_800_MASK; - query_switch = CURRENT_LIMIT_800_QUERY_SWITCH_OK; - switch_busy = CURRENT_LIMIT_800_SWITCH_BUSY; - break; - - default: - return STATUS_FAIL; - } - } else { - return STATUS_FAIL; - } - - if (func_group == SD_FUNC_GROUP_1) { - if (!(buf[support_offset] & support_mask) || - ((buf[query_switch_offset] & 0x0F) != query_switch)) { - return STATUS_FAIL; - } - } - - /* Check 'Busy Status' */ - if (buf[DATA_STRUCTURE_VER_OFFSET] == 0x01 && - ((buf[check_busy_offset] & switch_busy) == switch_busy)) { - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_check_switch_mode(struct rtsx_chip *chip, u8 mode, u8 func_group, - u8 func_to_switch, u8 bus_width) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 cmd[5], buf[64]; - - dev_dbg(rtsx_dev(chip), "%s (mode = %d, func_group = %d, func_to_switch = %d)\n", - __func__, mode, func_group, func_to_switch); - - cmd[0] = 0x40 | SWITCH; - cmd[1] = mode; - - if (func_group == SD_FUNC_GROUP_1) { - cmd[2] = 0xFF; - cmd[3] = 0xFF; - cmd[4] = 0xF0 + func_to_switch; - } else if (func_group == SD_FUNC_GROUP_3) { - cmd[2] = 0xFF; - cmd[3] = 0xF0 + func_to_switch; - cmd[4] = 0xFF; - } else if (func_group == SD_FUNC_GROUP_4) { - cmd[2] = 0xFF; - cmd[3] = 0x0F + (func_to_switch << 4); - cmd[4] = 0xFF; - } else { - cmd[1] = SD_CHECK_MODE; - cmd[2] = 0xFF; - cmd[3] = 0xFF; - cmd[4] = 0xFF; - } - - retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 64, 1, bus_width, - buf, 64, 250); - if (retval != STATUS_SUCCESS) { - rtsx_clear_sd_error(chip); - return STATUS_FAIL; - } - - dev_dbg(rtsx_dev(chip), "%*ph\n", 64, buf); - - if (func_group == NO_ARGUMENT) { - sd_card->func_group1_mask = buf[0x0D]; - sd_card->func_group2_mask = buf[0x0B]; - sd_card->func_group3_mask = buf[0x09]; - sd_card->func_group4_mask = buf[0x07]; - - dev_dbg(rtsx_dev(chip), "func_group1_mask = 0x%02x\n", - buf[0x0D]); - dev_dbg(rtsx_dev(chip), "func_group2_mask = 0x%02x\n", - buf[0x0B]); - dev_dbg(rtsx_dev(chip), "func_group3_mask = 0x%02x\n", - buf[0x09]); - dev_dbg(rtsx_dev(chip), "func_group4_mask = 0x%02x\n", - buf[0x07]); - } else { - /* Maximum current consumption, check whether current is - * acceptable; bit[511:496] = 0x0000 means some error happened. - */ - u16 cc = ((u16)buf[0] << 8) | buf[1]; - - dev_dbg(rtsx_dev(chip), "Maximum current consumption: %dmA\n", - cc); - if (cc == 0 || cc > 800) - return STATUS_FAIL; - - retval = sd_query_switch_result(chip, func_group, - func_to_switch, buf, 64); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (cc > 400 || func_to_switch > CURRENT_LIMIT_400) { - retval = rtsx_write_register(chip, OCPPARA2, - SD_OCP_THD_MASK, - chip->sd_800mA_ocp_thd); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PWR_CTL, - PMOS_STRG_MASK, - PMOS_STRG_800mA); - if (retval) - return retval; - } - } - - return STATUS_SUCCESS; -} - -static u8 downgrade_switch_mode(u8 func_group, u8 func_to_switch) -{ - if (func_group == SD_FUNC_GROUP_1) { - if (func_to_switch > HS_SUPPORT) - func_to_switch--; - - } else if (func_group == SD_FUNC_GROUP_4) { - if (func_to_switch > CURRENT_LIMIT_200) - func_to_switch--; - } - - return func_to_switch; -} - -static int sd_check_switch(struct rtsx_chip *chip, - u8 func_group, u8 func_to_switch, u8 bus_width) -{ - int retval; - int i; - bool switch_good = false; - - for (i = 0; i < 3; i++) { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - return STATUS_FAIL; - } - - retval = sd_check_switch_mode(chip, SD_CHECK_MODE, func_group, - func_to_switch, bus_width); - if (retval == STATUS_SUCCESS) { - u8 stat; - - retval = sd_check_switch_mode(chip, SD_SWITCH_MODE, - func_group, - func_to_switch, - bus_width); - if (retval == STATUS_SUCCESS) { - switch_good = true; - break; - } - - retval = rtsx_read_register(chip, SD_STAT1, &stat); - if (retval) - return retval; - if (stat & SD_CRC16_ERR) { - dev_dbg(rtsx_dev(chip), "SD CRC16 error when switching mode\n"); - return STATUS_FAIL; - } - } - - func_to_switch = downgrade_switch_mode(func_group, - func_to_switch); - - wait_timeout(20); - } - - if (!switch_good) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int i; - u8 func_to_switch = 0; - - /* Get supported functions */ - retval = sd_check_switch_mode(chip, SD_CHECK_MODE, NO_ARGUMENT, - NO_ARGUMENT, bus_width); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - sd_card->func_group1_mask &= ~(sd_card->sd_switch_fail); - - /* Function Group 1: Access Mode */ - for (i = 0; i < 4; i++) { - switch ((u8)(chip->sd_speed_prior >> (i * 8))) { - case SDR104_SUPPORT: - if ((sd_card->func_group1_mask & SDR104_SUPPORT_MASK) && - chip->sdr104_en) { - func_to_switch = SDR104_SUPPORT; - } - break; - - case DDR50_SUPPORT: - if ((sd_card->func_group1_mask & DDR50_SUPPORT_MASK) && - chip->ddr50_en) { - func_to_switch = DDR50_SUPPORT; - } - break; - - case SDR50_SUPPORT: - if ((sd_card->func_group1_mask & SDR50_SUPPORT_MASK) && - chip->sdr50_en) { - func_to_switch = SDR50_SUPPORT; - } - break; - - case HS_SUPPORT: - if (sd_card->func_group1_mask & HS_SUPPORT_MASK) - func_to_switch = HS_SUPPORT; - - break; - - default: - continue; - } - - if (func_to_switch) - break; - } - dev_dbg(rtsx_dev(chip), "SD_FUNC_GROUP_1: func_to_switch = 0x%02x", - func_to_switch); - -#ifdef SUPPORT_SD_LOCK - if ((sd_card->sd_lock_status & SD_SDR_RST) && - func_to_switch == DDR50_SUPPORT && - (sd_card->func_group1_mask & SDR50_SUPPORT_MASK)) { - func_to_switch = SDR50_SUPPORT; - dev_dbg(rtsx_dev(chip), "Using SDR50 instead of DDR50 for SD Lock\n"); - } -#endif - - if (func_to_switch) { - retval = sd_check_switch(chip, SD_FUNC_GROUP_1, func_to_switch, - bus_width); - if (retval != STATUS_SUCCESS) { - if (func_to_switch == SDR104_SUPPORT) { - sd_card->sd_switch_fail = SDR104_SUPPORT_MASK; - } else if (func_to_switch == DDR50_SUPPORT) { - sd_card->sd_switch_fail = SDR104_SUPPORT_MASK | - DDR50_SUPPORT_MASK; - } else if (func_to_switch == SDR50_SUPPORT) { - sd_card->sd_switch_fail = SDR104_SUPPORT_MASK | - DDR50_SUPPORT_MASK | SDR50_SUPPORT_MASK; - } - return STATUS_FAIL; - } - - if (func_to_switch == SDR104_SUPPORT) - SET_SD_SDR104(sd_card); - else if (func_to_switch == DDR50_SUPPORT) - SET_SD_DDR50(sd_card); - else if (func_to_switch == SDR50_SUPPORT) - SET_SD_SDR50(sd_card); - else - SET_SD_HS(sd_card); - } - - if (CHK_SD_DDR50(sd_card)) { - retval = rtsx_write_register(chip, SD_PUSH_POINT_CTL, 0x06, - 0x04); - if (retval) - return retval; - retval = sd_set_sample_push_timing(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - if (!func_to_switch || func_to_switch == HS_SUPPORT) { - /* Do not try to switch current limit if the card doesn't - * support UHS mode or we don't want it to support UHS mode - */ - return STATUS_SUCCESS; - } - - /* Function Group 4: Current Limit */ - func_to_switch = 0xFF; - - for (i = 0; i < 4; i++) { - switch ((u8)(chip->sd_current_prior >> (i * 8))) { - case CURRENT_LIMIT_800: - if (sd_card->func_group4_mask & CURRENT_LIMIT_800_MASK) - func_to_switch = CURRENT_LIMIT_800; - - break; - - case CURRENT_LIMIT_600: - if (sd_card->func_group4_mask & CURRENT_LIMIT_600_MASK) - func_to_switch = CURRENT_LIMIT_600; - - break; - - case CURRENT_LIMIT_400: - if (sd_card->func_group4_mask & CURRENT_LIMIT_400_MASK) - func_to_switch = CURRENT_LIMIT_400; - - break; - - case CURRENT_LIMIT_200: - if (sd_card->func_group4_mask & CURRENT_LIMIT_200_MASK) - func_to_switch = CURRENT_LIMIT_200; - - break; - - default: - continue; - } - - if (func_to_switch != 0xFF) - break; - } - - dev_dbg(rtsx_dev(chip), "SD_FUNC_GROUP_4: func_to_switch = 0x%02x", - func_to_switch); - - if (func_to_switch <= CURRENT_LIMIT_800) { - retval = sd_check_switch(chip, SD_FUNC_GROUP_4, func_to_switch, - bus_width); - if (retval != STATUS_SUCCESS) { - if (sd_check_err_code(chip, SD_NO_CARD)) - return STATUS_FAIL; - } - dev_dbg(rtsx_dev(chip), "Switch current limit finished! (%d)\n", - retval); - } - - if (CHK_SD_DDR50(sd_card)) { - retval = rtsx_write_register(chip, SD_PUSH_POINT_CTL, 0x06, 0); - if (retval) - return retval; - } - - return STATUS_SUCCESS; -} - -static int sd_wait_data_idle(struct rtsx_chip *chip) -{ - int retval = STATUS_TIMEDOUT; - int i; - u8 val = 0; - - for (i = 0; i < 100; i++) { - retval = rtsx_read_register(chip, SD_DATA_STATE, &val); - if (retval) - return retval; - if (val & SD_DATA_IDLE) { - retval = STATUS_SUCCESS; - break; - } - udelay(100); - } - dev_dbg(rtsx_dev(chip), "SD_DATA_STATE: 0x%02x\n", val); - - return retval; -} - -static int sd_sdr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) -{ - int retval; - u8 cmd[5]; - - retval = sd_change_phase(chip, sample_point, TUNE_RX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - cmd[0] = 0x40 | SEND_TUNING_PATTERN; - cmd[1] = 0; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = 0; - - retval = sd_read_data(chip, SD_TM_AUTO_TUNING, cmd, 5, 0x40, 1, - SD_BUS_WIDTH_4, NULL, 0, 100); - if (retval != STATUS_SUCCESS) { - (void)sd_wait_data_idle(chip); - - rtsx_clear_sd_error(chip); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_ddr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 cmd[5]; - - retval = sd_change_phase(chip, sample_point, TUNE_RX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - dev_dbg(rtsx_dev(chip), "sd ddr tuning rx\n"); - - retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - cmd[0] = 0x40 | SD_STATUS; - cmd[1] = 0; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = 0; - - retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 64, 1, - SD_BUS_WIDTH_4, NULL, 0, 100); - if (retval != STATUS_SUCCESS) { - (void)sd_wait_data_idle(chip); - - rtsx_clear_sd_error(chip); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int mmc_ddr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 cmd[5], bus_width; - - if (CHK_MMC_8BIT(sd_card)) - bus_width = SD_BUS_WIDTH_8; - else if (CHK_MMC_4BIT(sd_card)) - bus_width = SD_BUS_WIDTH_4; - else - bus_width = SD_BUS_WIDTH_1; - - retval = sd_change_phase(chip, sample_point, TUNE_RX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - dev_dbg(rtsx_dev(chip), "mmc ddr tuning rx\n"); - - cmd[0] = 0x40 | SEND_EXT_CSD; - cmd[1] = 0; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = 0; - - retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 0x200, 1, - bus_width, NULL, 0, 100); - if (retval != STATUS_SUCCESS) { - (void)sd_wait_data_idle(chip); - - rtsx_clear_sd_error(chip); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_sdr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - - retval = sd_change_phase(chip, sample_point, TUNE_TX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, - SD_RSP_80CLK_TIMEOUT_EN); - if (retval) - return retval; - - retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { - if (sd_check_err_code(chip, SD_RSP_TIMEOUT)) { - rtsx_write_register(chip, SD_CFG3, - SD_RSP_80CLK_TIMEOUT_EN, 0); - return STATUS_FAIL; - } - } - - retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, - 0); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static int sd_ddr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 cmd[5], bus_width; - - retval = sd_change_phase(chip, sample_point, TUNE_TX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (CHK_SD(sd_card)) { - bus_width = SD_BUS_WIDTH_4; - } else { - if (CHK_MMC_8BIT(sd_card)) - bus_width = SD_BUS_WIDTH_8; - else if (CHK_MMC_4BIT(sd_card)) - bus_width = SD_BUS_WIDTH_4; - else - bus_width = SD_BUS_WIDTH_1; - } - - retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, - SD_RSP_80CLK_TIMEOUT_EN); - if (retval) - return retval; - - cmd[0] = 0x40 | PROGRAM_CSD; - cmd[1] = 0; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = 0; - - retval = sd_write_data(chip, SD_TM_AUTO_WRITE_2, cmd, 5, 16, 1, - bus_width, sd_card->raw_csd, 16, 100); - if (retval != STATUS_SUCCESS) { - rtsx_clear_sd_error(chip); - rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, 0); - return STATUS_FAIL; - } - - retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, - 0); - if (retval) - return retval; - - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, - NULL, 0); - - return STATUS_SUCCESS; -} - -static u8 sd_search_final_phase(struct rtsx_chip *chip, u32 phase_map, - u8 tune_dir) -{ - struct sd_info *sd_card = &chip->sd_card; - struct timing_phase_path path[MAX_PHASE + 1]; - int i, j, cont_path_cnt; - bool new_block; - int max_len, final_path_idx; - u8 final_phase = 0xFF; - - if (phase_map == 0xFFFFFFFF) { - if (tune_dir == TUNE_RX) - final_phase = (u8)chip->sd_default_rx_phase; - else - final_phase = (u8)chip->sd_default_tx_phase; - - goto search_finish; - } - - cont_path_cnt = 0; - new_block = true; - j = 0; - for (i = 0; i < MAX_PHASE + 1; i++) { - if (phase_map & (1 << i)) { - if (new_block) { - new_block = false; - j = cont_path_cnt++; - path[j].start = i; - path[j].end = i; - } else { - path[j].end = i; - } - } else { - new_block = true; - if (cont_path_cnt) { - int idx = cont_path_cnt - 1; - - path[idx].len = path[idx].end - - path[idx].start + 1; - path[idx].mid = path[idx].start + - path[idx].len / 2; - } - } - } - - if (cont_path_cnt == 0) { - dev_dbg(rtsx_dev(chip), "No continuous phase path\n"); - goto search_finish; - } else { - int idx = cont_path_cnt - 1; - - path[idx].len = path[idx].end - path[idx].start + 1; - path[idx].mid = path[idx].start + path[idx].len / 2; - } - - if (path[0].start == 0 && - path[cont_path_cnt - 1].end == MAX_PHASE) { - path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; - path[0].len += path[cont_path_cnt - 1].len; - path[0].mid = path[0].start + path[0].len / 2; - if (path[0].mid < 0) - path[0].mid += MAX_PHASE + 1; - - cont_path_cnt--; - } - - max_len = 0; - final_phase = 0; - final_path_idx = 0; - for (i = 0; i < cont_path_cnt; i++) { - if (path[i].len > max_len) { - max_len = path[i].len; - final_phase = (u8)path[i].mid; - final_path_idx = i; - } - - dev_dbg(rtsx_dev(chip), "path[%d].start = %d\n", - i, path[i].start); - dev_dbg(rtsx_dev(chip), "path[%d].end = %d\n", i, path[i].end); - dev_dbg(rtsx_dev(chip), "path[%d].len = %d\n", i, path[i].len); - dev_dbg(rtsx_dev(chip), "path[%d].mid = %d\n", i, path[i].mid); - dev_dbg(rtsx_dev(chip), "\n"); - } - - if (tune_dir == TUNE_TX) { - if (CHK_SD_SDR104(sd_card)) { - if (max_len > 15) { - int temp_mid = (max_len - 16) / 2; - int temp_final_phase = - path[final_path_idx].end - - (max_len - (6 + temp_mid)); - - if (temp_final_phase < 0) - final_phase = (u8)(temp_final_phase + - MAX_PHASE + 1); - else - final_phase = (u8)temp_final_phase; - } - } else if (CHK_SD_SDR50(sd_card)) { - if (max_len > 12) { - int temp_mid = (max_len - 13) / 2; - int temp_final_phase = - path[final_path_idx].end - - (max_len - (3 + temp_mid)); - - if (temp_final_phase < 0) - final_phase = (u8)(temp_final_phase + - MAX_PHASE + 1); - else - final_phase = (u8)temp_final_phase; - } - } - } - -search_finish: - dev_dbg(rtsx_dev(chip), "Final chosen phase: %d\n", final_phase); - return final_phase; -} - -static int sd_tuning_rx(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int i, j; - u32 raw_phase_map[3], phase_map; - u8 final_phase; - int (*tuning_cmd)(struct rtsx_chip *chip, u8 sample_point); - - if (CHK_SD(sd_card)) { - if (CHK_SD_DDR50(sd_card)) - tuning_cmd = sd_ddr_tuning_rx_cmd; - else - tuning_cmd = sd_sdr_tuning_rx_cmd; - - } else { - if (CHK_MMC_DDR52(sd_card)) - tuning_cmd = mmc_ddr_tuning_rx_cmd; - else - return STATUS_FAIL; - } - - for (i = 0; i < 3; i++) { - raw_phase_map[i] = 0; - for (j = MAX_PHASE; j >= 0; j--) { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - return STATUS_FAIL; - } - - retval = tuning_cmd(chip, (u8)j); - if (retval == STATUS_SUCCESS) - raw_phase_map[i] |= 1 << j; - } - } - - phase_map = raw_phase_map[0] & raw_phase_map[1] & raw_phase_map[2]; - for (i = 0; i < 3; i++) - dev_dbg(rtsx_dev(chip), "RX raw_phase_map[%d] = 0x%08x\n", - i, raw_phase_map[i]); - - dev_dbg(rtsx_dev(chip), "RX phase_map = 0x%08x\n", phase_map); - - final_phase = sd_search_final_phase(chip, phase_map, TUNE_RX); - if (final_phase == 0xFF) - return STATUS_FAIL; - - retval = sd_change_phase(chip, final_phase, TUNE_RX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int sd_ddr_pre_tuning_tx(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int i; - u32 phase_map; - u8 final_phase; - - retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, - SD_RSP_80CLK_TIMEOUT_EN); - if (retval) - return retval; - - phase_map = 0; - for (i = MAX_PHASE; i >= 0; i--) { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - rtsx_write_register(chip, SD_CFG3, - SD_RSP_80CLK_TIMEOUT_EN, 0); - return STATUS_FAIL; - } - - retval = sd_change_phase(chip, (u8)i, TUNE_TX); - if (retval != STATUS_SUCCESS) - continue; - - retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, - sd_card->sd_addr, SD_RSP_TYPE_R1, - NULL, 0); - if (retval == STATUS_SUCCESS || - !sd_check_err_code(chip, SD_RSP_TIMEOUT)) - phase_map |= 1 << i; - } - - retval = rtsx_write_register(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, - 0); - if (retval) - return retval; - - dev_dbg(rtsx_dev(chip), "DDR TX pre tune phase_map = 0x%08x\n", - phase_map); - - final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX); - if (final_phase == 0xFF) - return STATUS_FAIL; - - retval = sd_change_phase(chip, final_phase, TUNE_TX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - dev_dbg(rtsx_dev(chip), "DDR TX pre tune phase: %d\n", - (int)final_phase); - - return STATUS_SUCCESS; -} - -static int sd_tuning_tx(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int i, j; - u32 raw_phase_map[3], phase_map; - u8 final_phase; - int (*tuning_cmd)(struct rtsx_chip *chip, u8 sample_point); - - if (CHK_SD(sd_card)) { - if (CHK_SD_DDR50(sd_card)) - tuning_cmd = sd_ddr_tuning_tx_cmd; - else - tuning_cmd = sd_sdr_tuning_tx_cmd; - - } else { - if (CHK_MMC_DDR52(sd_card)) - tuning_cmd = sd_ddr_tuning_tx_cmd; - else - return STATUS_FAIL; - } - - for (i = 0; i < 3; i++) { - raw_phase_map[i] = 0; - for (j = MAX_PHASE; j >= 0; j--) { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - rtsx_write_register(chip, SD_CFG3, - SD_RSP_80CLK_TIMEOUT_EN, 0); - return STATUS_FAIL; - } - - retval = tuning_cmd(chip, (u8)j); - if (retval == STATUS_SUCCESS) - raw_phase_map[i] |= 1 << j; - } - } - - phase_map = raw_phase_map[0] & raw_phase_map[1] & raw_phase_map[2]; - for (i = 0; i < 3; i++) - dev_dbg(rtsx_dev(chip), "TX raw_phase_map[%d] = 0x%08x\n", - i, raw_phase_map[i]); - - dev_dbg(rtsx_dev(chip), "TX phase_map = 0x%08x\n", phase_map); - - final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX); - if (final_phase == 0xFF) - return STATUS_FAIL; - - retval = sd_change_phase(chip, final_phase, TUNE_TX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int sd_sdr_tuning(struct rtsx_chip *chip) -{ - int retval; - - retval = sd_tuning_tx(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = sd_tuning_rx(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int sd_ddr_tuning(struct rtsx_chip *chip) -{ - int retval; - - if (!(chip->sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) { - retval = sd_ddr_pre_tuning_tx(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = sd_change_phase(chip, (u8)chip->sd_ddr_tx_phase, - TUNE_TX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - retval = sd_tuning_rx(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (!(chip->sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) { - retval = sd_tuning_tx(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int mmc_ddr_tuning(struct rtsx_chip *chip) -{ - int retval; - - if (!(chip->sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) { - retval = sd_ddr_pre_tuning_tx(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = sd_change_phase(chip, (u8)chip->mmc_ddr_tx_phase, - TUNE_TX); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - retval = sd_tuning_rx(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (!(chip->sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) { - retval = sd_tuning_tx(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -int sd_switch_clock(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - int re_tuning = 0; - - retval = select_card(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = switch_clock(chip, sd_card->sd_clock); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (re_tuning) { - if (CHK_SD(sd_card)) { - if (CHK_SD_DDR50(sd_card)) - retval = sd_ddr_tuning(chip); - else - retval = sd_sdr_tuning(chip); - } else { - if (CHK_MMC_DDR52(sd_card)) - retval = mmc_ddr_tuning(chip); - } - - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_prepare_reset(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - - if (chip->asic_code) - sd_card->sd_clock = 29; - else - sd_card->sd_clock = CLK_30; - - sd_card->sd_type = 0; - sd_card->seq_mode = 0; - sd_card->sd_data_buf_ready = 0; - sd_card->capacity = 0; - -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status = 0; - sd_card->sd_erase_status = 0; -#endif - - chip->capacity[chip->card2lun[SD_CARD]] = 0; - chip->sd_io = 0; - - retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return retval; - - retval = rtsx_write_register(chip, REG_SD_CFG1, 0xFF, 0x40); - if (retval) - return retval; - - retval = rtsx_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, - SD_STOP | SD_CLR_ERR); - if (retval) - return retval; - - retval = select_card(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int sd_pull_ctl_disable(struct rtsx_chip *chip) -{ - int retval; - - if (CHECK_PID(chip, 0x5208)) { - retval = rtsx_write_register(chip, CARD_PULL_CTL1, 0xFF, - XD_D3_PD | SD_D7_PD | SD_CLK_PD | - SD_D5_PD); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF, - SD_D6_PD | SD_D0_PD | SD_D1_PD | - XD_D5_PD); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF, - SD_D4_PD | XD_CE_PD | XD_CLE_PD | - XD_CD_PU); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF, - XD_RDY_PD | SD_D3_PD | SD_D2_PD | - XD_ALE_PD); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF, - MS_INS_PU | SD_WP_PD | SD_CD_PU | - SD_CMD_PD); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF, - MS_D5_PD | MS_D4_PD); - if (retval) - return retval; - } else if (CHECK_PID(chip, 0x5288)) { - if (CHECK_BARO_PKG(chip, QFN)) { - retval = rtsx_write_register(chip, CARD_PULL_CTL1, - 0xFF, 0x55); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL2, - 0xFF, 0x55); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL3, - 0xFF, 0x4B); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL4, - 0xFF, 0x69); - if (retval) - return retval; - } - } - - return STATUS_SUCCESS; -} - -int sd_pull_ctl_enable(struct rtsx_chip *chip) -{ - int retval; - - rtsx_init_cmd(chip); - - if (CHECK_PID(chip, 0x5208)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, - XD_D3_PD | SD_DAT7_PU | SD_CLK_NP | SD_D5_PU); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, - SD_D6_PU | SD_D0_PU | SD_D1_PU | XD_D5_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, - SD_D4_PU | XD_CE_PD | XD_CLE_PD | XD_CD_PU); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, - XD_RDY_PD | SD_D3_PU | SD_D2_PU | XD_ALE_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, - MS_INS_PU | SD_WP_PU | SD_CD_PU | SD_CMD_PU); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, - MS_D5_PD | MS_D4_PD); - } else if (CHECK_PID(chip, 0x5288)) { - if (CHECK_BARO_PKG(chip, QFN)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, - 0xA8); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, - 0x5A); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, - 0x95); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, - 0xAA); - } - } - - retval = rtsx_send_cmd(chip, SD_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int sd_init_power(struct rtsx_chip *chip) -{ - int retval; - - retval = sd_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (!chip->ft2_fast_mode) - wait_timeout(250); - - retval = enable_card_clock(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (chip->asic_code) { - retval = sd_pull_ctl_enable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register(chip, FPGA_PULL_CTL, - FPGA_SD_PULL_CTL_BIT | 0x20, 0); - if (retval) - return retval; - } - - if (!chip->ft2_fast_mode) { - retval = card_power_on(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - wait_timeout(260); - -#ifdef SUPPORT_OCP - if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) { - dev_dbg(rtsx_dev(chip), "Over current, OCPSTAT is 0x%x\n", - chip->ocp_stat); - return STATUS_FAIL; - } -#endif - } - - retval = rtsx_write_register(chip, CARD_OE, SD_OUTPUT_EN, - SD_OUTPUT_EN); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static int sd_dummy_clock(struct rtsx_chip *chip) -{ - int retval; - - retval = rtsx_write_register(chip, REG_SD_CFG3, 0x01, 0x01); - if (retval) - return retval; - wait_timeout(5); - retval = rtsx_write_register(chip, REG_SD_CFG3, 0x01, 0); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static int sd_read_lba0(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 cmd[5], bus_width; - - cmd[0] = 0x40 | READ_SINGLE_BLOCK; - cmd[1] = 0; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = 0; - - if (CHK_SD(sd_card)) { - bus_width = SD_BUS_WIDTH_4; - } else { - if (CHK_MMC_8BIT(sd_card)) - bus_width = SD_BUS_WIDTH_8; - else if (CHK_MMC_4BIT(sd_card)) - bus_width = SD_BUS_WIDTH_4; - else - bus_width = SD_BUS_WIDTH_1; - } - - retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 512, 1, - bus_width, NULL, 0, 100); - if (retval != STATUS_SUCCESS) { - rtsx_clear_sd_error(chip); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sd_check_wp_state(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u32 val; - u16 sd_card_type; - u8 cmd[5], buf[64]; - - retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - cmd[0] = 0x40 | SD_STATUS; - cmd[1] = 0; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = 0; - - retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 64, 1, - SD_BUS_WIDTH_4, buf, 64, 250); - if (retval != STATUS_SUCCESS) { - rtsx_clear_sd_error(chip); - - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - return STATUS_FAIL; - } - - dev_dbg(rtsx_dev(chip), "ACMD13:\n"); - dev_dbg(rtsx_dev(chip), "%*ph\n", 64, buf); - - sd_card_type = ((u16)buf[2] << 8) | buf[3]; - dev_dbg(rtsx_dev(chip), "sd_card_type = 0x%04x\n", sd_card_type); - if (sd_card_type == 0x0001 || sd_card_type == 0x0002) { - /* ROM card or OTP */ - chip->card_wp |= SD_CARD; - } - - /* Check SD Machanical Write-Protect Switch */ - val = rtsx_readl(chip, RTSX_BIPR); - if (val & SD_WRITE_PROTECT) - chip->card_wp |= SD_CARD; - - return STATUS_SUCCESS; -} - -static int reset_sd(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - bool hi_cap_flow = false; - int retval, i = 0, j = 0, k = 0; - bool sd_dont_switch = false; - bool support_1v8 = false; - bool try_sdio = true; - u8 rsp[16]; - u8 switch_bus_width; - u32 voltage = 0; - bool sd20_mode = false; - - SET_SD(sd_card); - -switch_fail: - - i = 0; - j = 0; - k = 0; - hi_cap_flow = false; - -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) - goto SD_UNLOCK_ENTRY; -#endif - - retval = sd_prepare_reset(chip); - if (retval != STATUS_SUCCESS) - goto status_fail; - - retval = sd_dummy_clock(chip); - if (retval != STATUS_SUCCESS) - goto status_fail; - - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip) && try_sdio) { - int rty_cnt = 0; - - for (; rty_cnt < chip->sdio_retry_cnt; rty_cnt++) { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - goto status_fail; - } - - retval = sd_send_cmd_get_rsp(chip, IO_SEND_OP_COND, 0, - SD_RSP_TYPE_R4, rsp, 5); - if (retval == STATUS_SUCCESS) { - int func_num = (rsp[1] >> 4) & 0x07; - - if (func_num) { - dev_dbg(rtsx_dev(chip), "SD_IO card (Function number: %d)!\n", - func_num); - chip->sd_io = 1; - goto status_fail; - } - - break; - } - - sd_init_power(chip); - - sd_dummy_clock(chip); - } - - dev_dbg(rtsx_dev(chip), "Normal card!\n"); - } - - /* Start Initialization Process of SD Card */ -RTY_SD_RST: - retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, - NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - wait_timeout(20); - - retval = sd_send_cmd_get_rsp(chip, SEND_IF_COND, 0x000001AA, - SD_RSP_TYPE_R7, rsp, 5); - if (retval == STATUS_SUCCESS) { - if (rsp[4] == 0xAA && ((rsp[3] & 0x0f) == 0x01)) { - hi_cap_flow = true; - voltage = SUPPORT_VOLTAGE | 0x40000000; - } - } - - if (!hi_cap_flow) { - voltage = SUPPORT_VOLTAGE; - - retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, - SD_RSP_TYPE_R0, NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - wait_timeout(20); - } - - do { - retval = sd_send_cmd_get_rsp(chip, APP_CMD, 0, SD_RSP_TYPE_R1, - NULL, 0); - if (retval != STATUS_SUCCESS) { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - goto status_fail; - } - - j++; - if (j < 3) - goto RTY_SD_RST; - else - goto status_fail; - } - - retval = sd_send_cmd_get_rsp(chip, SD_APP_OP_COND, voltage, - SD_RSP_TYPE_R3, rsp, 5); - if (retval != STATUS_SUCCESS) { - k++; - if (k < 3) - goto RTY_SD_RST; - else - goto status_fail; - } - - i++; - wait_timeout(20); - } while (!(rsp[1] & 0x80) && (i < 255)); - - if (i == 255) - goto status_fail; - - if (hi_cap_flow) { - if (rsp[1] & 0x40) - SET_SD_HCXC(sd_card); - else - CLR_SD_HCXC(sd_card); - - support_1v8 = false; - } else { - CLR_SD_HCXC(sd_card); - support_1v8 = false; - } - dev_dbg(rtsx_dev(chip), "support_1v8 = %d\n", support_1v8); - - if (support_1v8) { - retval = sd_voltage_switch(chip); - if (retval != STATUS_SUCCESS) - goto status_fail; - } - - retval = sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2, - NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - for (i = 0; i < 3; i++) { - retval = sd_send_cmd_get_rsp(chip, SEND_RELATIVE_ADDR, 0, - SD_RSP_TYPE_R6, rsp, 5); - if (retval != STATUS_SUCCESS) - goto status_fail; - - sd_card->sd_addr = (u32)rsp[1] << 24; - sd_card->sd_addr += (u32)rsp[2] << 16; - - if (sd_card->sd_addr) - break; - } - - retval = sd_check_csd(chip, 1); - if (retval != STATUS_SUCCESS) - goto status_fail; - - retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) - goto status_fail; - -#ifdef SUPPORT_SD_LOCK -SD_UNLOCK_ENTRY: - retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) - goto status_fail; - - if (sd_card->sd_lock_status & SD_LOCKED) { - sd_card->sd_lock_status |= (SD_LOCK_1BIT_MODE | SD_PWD_EXIST); - return STATUS_SUCCESS; - } else if (!(sd_card->sd_lock_status & SD_UNLOCK_POW_ON)) { - sd_card->sd_lock_status &= ~SD_PWD_EXIST; - } -#endif - - retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - retval = sd_send_cmd_get_rsp(chip, SET_CLR_CARD_DETECT, 0, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - if (support_1v8) { - retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - retval = sd_send_cmd_get_rsp(chip, SET_BUS_WIDTH, 2, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - switch_bus_width = SD_BUS_WIDTH_4; - } else { - switch_bus_width = SD_BUS_WIDTH_1; - } - - retval = sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, - NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - if (!(sd_card->raw_csd[4] & 0x40)) - sd_dont_switch = true; - - if (!sd_dont_switch) { - if (sd20_mode) { - /* Set sd_switch_fail here, because we needn't - * switch to UHS mode - */ - sd_card->sd_switch_fail = SDR104_SUPPORT_MASK | - DDR50_SUPPORT_MASK | SDR50_SUPPORT_MASK; - } - - /* Check the card whether follow SD1.1 spec or higher */ - retval = sd_check_spec(chip, switch_bus_width); - if (retval == STATUS_SUCCESS) { - retval = sd_switch_function(chip, switch_bus_width); - if (retval != STATUS_SUCCESS) { - sd_init_power(chip); - sd_dont_switch = true; - try_sdio = false; - - goto switch_fail; - } - } else { - if (support_1v8) { - sd_init_power(chip); - sd_dont_switch = true; - try_sdio = false; - - goto switch_fail; - } - } - } - - if (!support_1v8) { - retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - - retval = sd_send_cmd_get_rsp(chip, SET_BUS_WIDTH, 2, - SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) - goto status_fail; - } - -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE; -#endif - - if (!sd20_mode && CHK_SD30_SPEED(sd_card)) { - int read_lba0 = 1; - - retval = rtsx_write_register(chip, SD30_DRIVE_SEL, 0x07, - chip->sd30_drive_sel_1v8); - if (retval) - return retval; - - retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) - goto status_fail; - - if (CHK_SD_DDR50(sd_card)) - retval = sd_ddr_tuning(chip); - else - retval = sd_sdr_tuning(chip); - - if (retval != STATUS_SUCCESS) { - retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) - goto status_fail; - - try_sdio = false; - sd20_mode = true; - goto switch_fail; - } - - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - - if (CHK_SD_DDR50(sd_card)) { - retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000); - if (retval != STATUS_SUCCESS) - read_lba0 = 0; - } - - if (read_lba0) { - retval = sd_read_lba0(chip); - if (retval != STATUS_SUCCESS) { - retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) - goto status_fail; - - try_sdio = false; - sd20_mode = true; - goto switch_fail; - } - } - } - - retval = sd_check_wp_state(chip); - if (retval != STATUS_SUCCESS) - goto status_fail; - - chip->card_bus_width[chip->card2lun[SD_CARD]] = 4; - -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) { - retval = rtsx_write_register(chip, REG_SD_BLOCK_CNT_H, 0xFF, - 0x02); - if (retval) - return retval; - retval = rtsx_write_register(chip, REG_SD_BLOCK_CNT_L, 0xFF, - 0x00); - if (retval) - return retval; - } -#endif - - return STATUS_SUCCESS; - -status_fail: - return STATUS_FAIL; -} - -static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 buf[8] = {0}, bus_width, *ptr; - u16 byte_cnt; - int len; - - retval = sd_send_cmd_get_rsp(chip, BUSTEST_W, 0, SD_RSP_TYPE_R1, NULL, - 0); - if (retval != STATUS_SUCCESS) - return SWITCH_FAIL; - - if (width == MMC_8BIT_BUS) { - buf[0] = 0x55; - buf[1] = 0xAA; - len = 8; - byte_cnt = 8; - bus_width = SD_BUS_WIDTH_8; - } else { - buf[0] = 0x5A; - len = 4; - byte_cnt = 4; - bus_width = SD_BUS_WIDTH_4; - } - - retval = rtsx_write_register(chip, REG_SD_CFG3, 0x02, 0x02); - if (retval != STATUS_SUCCESS) - return SWITCH_ERR; - - retval = sd_write_data(chip, SD_TM_AUTO_WRITE_3, NULL, 0, byte_cnt, 1, - bus_width, buf, len, 100); - if (retval != STATUS_SUCCESS) { - rtsx_clear_sd_error(chip); - rtsx_write_register(chip, REG_SD_CFG3, 0x02, 0); - return SWITCH_ERR; - } - - retval = rtsx_write_register(chip, REG_SD_CFG3, 0x02, 0); - if (retval != STATUS_SUCCESS) - return SWITCH_ERR; - - dev_dbg(rtsx_dev(chip), "SD/MMC CMD %d\n", BUSTEST_R); - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0, 0xFF, 0x40 | BUSTEST_R); - - if (width == MMC_8BIT_BUS) - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, - 0xFF, 0x08); - else - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, - 0xFF, 0x04); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, 0xFF, 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, 0xFF, 0); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, SD_CALCULATE_CRC7 | - SD_NO_CHECK_CRC16 | SD_NO_WAIT_BUSY_END | - SD_CHECK_CRC7 | SD_RSP_LEN_6); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, - PINGPONG_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - SD_TM_NORMAL_READ | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, - SD_TRANSFER_END); - - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2, 0, 0); - if (width == MMC_8BIT_BUS) - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 1, 0, 0); - - retval = rtsx_send_cmd(chip, SD_CARD, 100); - if (retval < 0) { - rtsx_clear_sd_error(chip); - return SWITCH_ERR; - } - - ptr = rtsx_get_cmd_data(chip) + 1; - - if (width == MMC_8BIT_BUS) { - dev_dbg(rtsx_dev(chip), "BUSTEST_R [8bits]: 0x%02x 0x%02x\n", - ptr[0], ptr[1]); - if (ptr[0] == 0xAA && ptr[1] == 0x55) { - u8 rsp[5]; - u32 arg; - - if (CHK_MMC_DDR52(sd_card)) - arg = 0x03B70600; - else - arg = 0x03B70200; - - retval = sd_send_cmd_get_rsp(chip, SWITCH, arg, - SD_RSP_TYPE_R1b, rsp, 5); - if (retval == STATUS_SUCCESS && - !(rsp[4] & MMC_SWITCH_ERR)) - return SWITCH_SUCCESS; - } - } else { - dev_dbg(rtsx_dev(chip), "BUSTEST_R [4bits]: 0x%02x\n", ptr[0]); - if (ptr[0] == 0xA5) { - u8 rsp[5]; - u32 arg; - - if (CHK_MMC_DDR52(sd_card)) - arg = 0x03B70500; - else - arg = 0x03B70100; - - retval = sd_send_cmd_get_rsp(chip, SWITCH, arg, - SD_RSP_TYPE_R1b, rsp, 5); - if (retval == STATUS_SUCCESS && - !(rsp[4] & MMC_SWITCH_ERR)) - return SWITCH_SUCCESS; - } - } - - return SWITCH_FAIL; -} - -static int mmc_switch_timing_bus(struct rtsx_chip *chip, bool switch_ddr) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - u8 *ptr, card_type, card_type_mask = 0; - - CLR_MMC_HS(sd_card); - - dev_dbg(rtsx_dev(chip), "SD/MMC CMD %d\n", SEND_EXT_CSD); - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0, 0xFF, - 0x40 | SEND_EXT_CSD); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD1, 0xFF, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD2, 0xFF, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD3, 0xFF, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD4, 0xFF, 0); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, 2); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, 0xFF, 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, 0xFF, 0); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, - SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END | - SD_CHECK_CRC7 | SD_RSP_LEN_6); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, - PINGPONG_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - SD_TM_NORMAL_READ | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, - SD_TRANSFER_END); - - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 196, 0xFF, 0); - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 212, 0xFF, 0); - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 213, 0xFF, 0); - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 214, 0xFF, 0); - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 215, 0xFF, 0); - - retval = rtsx_send_cmd(chip, SD_CARD, 1000); - if (retval < 0) { - if (retval == -ETIMEDOUT) { - rtsx_clear_sd_error(chip); - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - } - return STATUS_FAIL; - } - - ptr = rtsx_get_cmd_data(chip); - if (ptr[0] & SD_TRANSFER_ERR) { - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - return STATUS_FAIL; - } - - if (CHK_MMC_SECTOR_MODE(sd_card)) { - sd_card->capacity = ((u32)ptr[5] << 24) | ((u32)ptr[4] << 16) | - ((u32)ptr[3] << 8) | ((u32)ptr[2]); - } - - card_type_mask = 0x03; - card_type = ptr[1] & card_type_mask; - if (card_type) { - u8 rsp[5]; - - if (card_type & 0x04) { - if (switch_ddr) - SET_MMC_DDR52(sd_card); - else - SET_MMC_52M(sd_card); - } else if (card_type & 0x02) { - SET_MMC_52M(sd_card); - } else { - SET_MMC_26M(sd_card); - } - - retval = sd_send_cmd_get_rsp(chip, SWITCH, 0x03B90100, - SD_RSP_TYPE_R1b, rsp, 5); - if (retval != STATUS_SUCCESS || (rsp[4] & MMC_SWITCH_ERR)) - CLR_MMC_HS(sd_card); - } - - sd_choose_proper_clock(chip); - retval = switch_clock(chip, sd_card->sd_clock); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - /* Test Bus Procedure */ - retval = mmc_test_switch_bus(chip, MMC_8BIT_BUS); - if (retval == SWITCH_SUCCESS) { - SET_MMC_8BIT(sd_card); - chip->card_bus_width[chip->card2lun[SD_CARD]] = 8; -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE; -#endif - } else if (retval == SWITCH_FAIL) { - retval = mmc_test_switch_bus(chip, MMC_4BIT_BUS); - if (retval == SWITCH_SUCCESS) { - SET_MMC_4BIT(sd_card); - chip->card_bus_width[chip->card2lun[SD_CARD]] = 4; -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE; -#endif - } else if (retval == SWITCH_FAIL) { - CLR_MMC_8BIT(sd_card); - CLR_MMC_4BIT(sd_card); - } else { - return STATUS_FAIL; - } - } else { - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int reset_mmc(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval, i = 0, j = 0, k = 0; - bool switch_ddr = true; - u8 rsp[16]; - u8 spec_ver = 0; - u32 temp; - -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) - goto MMC_UNLOCK_ENTRY; -#endif - -switch_fail: - retval = sd_prepare_reset(chip); - if (retval != STATUS_SUCCESS) - return retval; - - SET_MMC(sd_card); - -RTY_MMC_RST: - retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, - NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - do { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - return STATUS_FAIL; - } - - retval = sd_send_cmd_get_rsp(chip, SEND_OP_COND, - (SUPPORT_VOLTAGE | 0x40000000), - SD_RSP_TYPE_R3, rsp, 5); - if (retval != STATUS_SUCCESS) { - if (sd_check_err_code(chip, SD_BUSY) || - sd_check_err_code(chip, SD_TO_ERR)) { - k++; - if (k < 20) { - sd_clr_err_code(chip); - goto RTY_MMC_RST; - } else { - return STATUS_FAIL; - } - } else { - j++; - if (j < 100) { - sd_clr_err_code(chip); - goto RTY_MMC_RST; - } else { - return STATUS_FAIL; - } - } - } - - wait_timeout(20); - i++; - } while (!(rsp[1] & 0x80) && (i < 255)); - - if (i == 255) - return STATUS_FAIL; - - if ((rsp[1] & 0x60) == 0x40) - SET_MMC_SECTOR_MODE(sd_card); - else - CLR_MMC_SECTOR_MODE(sd_card); - - retval = sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2, - NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - sd_card->sd_addr = 0x00100000; - retval = sd_send_cmd_get_rsp(chip, SET_RELATIVE_ADDR, sd_card->sd_addr, - SD_RSP_TYPE_R6, rsp, 5); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = sd_check_csd(chip, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - spec_ver = (sd_card->raw_csd[0] & 0x3C) >> 2; - - retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, - NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - -#ifdef SUPPORT_SD_LOCK -MMC_UNLOCK_ENTRY: - retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; -#endif - - retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - chip->card_bus_width[chip->card2lun[SD_CARD]] = 1; - - if (!sd_card->mmc_dont_switch_bus) { - if (spec_ver == 4) { - /* MMC 4.x Cards */ - retval = mmc_switch_timing_bus(chip, switch_ddr); - if (retval != STATUS_SUCCESS) { - retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - sd_card->mmc_dont_switch_bus = 1; - goto switch_fail; - } - } - - if (CHK_MMC_SECTOR_MODE(sd_card) && sd_card->capacity == 0) - return STATUS_FAIL; - - if (switch_ddr && CHK_MMC_DDR52(sd_card)) { - retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = mmc_ddr_tuning(chip); - if (retval != STATUS_SUCCESS) { - retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - switch_ddr = false; - goto switch_fail; - } - - retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000); - if (retval == STATUS_SUCCESS) { - retval = sd_read_lba0(chip); - if (retval != STATUS_SUCCESS) { - retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - switch_ddr = false; - goto switch_fail; - } - } - } - } - -#ifdef SUPPORT_SD_LOCK - if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) { - retval = rtsx_write_register(chip, REG_SD_BLOCK_CNT_H, 0xFF, - 0x02); - if (retval) - return retval; - retval = rtsx_write_register(chip, REG_SD_BLOCK_CNT_L, 0xFF, - 0x00); - if (retval) - return retval; - } -#endif - - temp = rtsx_readl(chip, RTSX_BIPR); - if (temp & SD_WRITE_PROTECT) - chip->card_wp |= SD_CARD; - - return STATUS_SUCCESS; -} - -int reset_sd_card(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - - sd_init_reg_addr(chip); - - memset(sd_card, 0, sizeof(struct sd_info)); - chip->capacity[chip->card2lun[SD_CARD]] = 0; - - retval = enable_card_clock(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (chip->ignore_sd && CHK_SDIO_EXIST(chip) && - !CHK_SDIO_IGNORED(chip)) { - if (chip->asic_code) { - retval = sd_pull_ctl_enable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register(chip, FPGA_PULL_CTL, - FPGA_SD_PULL_CTL_BIT | - 0x20, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - retval = card_share_mode(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - chip->sd_io = 1; - return STATUS_FAIL; - } - - retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (chip->sd_ctl & RESET_MMC_FIRST) { - retval = reset_mmc(chip); - if (retval != STATUS_SUCCESS) { - if (sd_check_err_code(chip, SD_NO_CARD)) - return STATUS_FAIL; - - retval = reset_sd(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - } else { - retval = reset_sd(chip); - if (retval != STATUS_SUCCESS) { - if (sd_check_err_code(chip, SD_NO_CARD)) - return STATUS_FAIL; - - if (chip->sd_io) - return STATUS_FAIL; - retval = reset_mmc(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - } - - retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, REG_SD_BYTE_CNT_L, 0xFF, 0); - if (retval) - return retval; - retval = rtsx_write_register(chip, REG_SD_BYTE_CNT_H, 0xFF, 2); - if (retval) - return retval; - - chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity; - - retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - dev_dbg(rtsx_dev(chip), "sd_card->sd_type = 0x%x\n", sd_card->sd_type); - - return STATUS_SUCCESS; -} - -static int reset_mmc_only(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - - sd_card->sd_type = 0; - sd_card->seq_mode = 0; - sd_card->sd_data_buf_ready = 0; - sd_card->capacity = 0; - sd_card->sd_switch_fail = 0; - -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status = 0; - sd_card->sd_erase_status = 0; -#endif - - chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity = 0; - - retval = enable_card_clock(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = reset_mmc(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, REG_SD_BYTE_CNT_L, 0xFF, 0); - if (retval) - return retval; - retval = rtsx_write_register(chip, REG_SD_BYTE_CNT_H, 0xFF, 2); - if (retval) - return retval; - - chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity; - - retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - dev_dbg(rtsx_dev(chip), "In %s, sd_card->sd_type = 0x%x\n", - __func__, sd_card->sd_type); - - return STATUS_SUCCESS; -} - -#define WAIT_DATA_READY_RTY_CNT 255 - -static int wait_data_buf_ready(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int i, retval; - - for (i = 0; i < WAIT_DATA_READY_RTY_CNT; i++) { - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_NO_CARD); - return STATUS_FAIL; - } - - sd_card->sd_data_buf_ready = 0; - - retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, - sd_card->sd_addr, SD_RSP_TYPE_R1, - NULL, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (sd_card->sd_data_buf_ready) { - return sd_send_cmd_get_rsp(chip, SEND_STATUS, - sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - } - } - - sd_set_err_code(chip, SD_TO_ERR); - - return STATUS_FAIL; -} - -void sd_stop_seq_mode(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - - if (sd_card->seq_mode) { - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return; - - retval = sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, - SD_RSP_TYPE_R1b, NULL, 0); - if (retval != STATUS_SUCCESS) - sd_set_err_code(chip, SD_STS_ERR); - - retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000); - if (retval != STATUS_SUCCESS) - sd_set_err_code(chip, SD_STS_ERR); - - sd_card->seq_mode = 0; - - rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); - } -} - -static inline int sd_auto_tune_clock(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - - if (chip->asic_code) { - if (sd_card->sd_clock > 30) - sd_card->sd_clock -= 20; - } else { - switch (sd_card->sd_clock) { - case CLK_200: - sd_card->sd_clock = CLK_150; - break; - - case CLK_150: - sd_card->sd_clock = CLK_120; - break; - - case CLK_120: - sd_card->sd_clock = CLK_100; - break; - - case CLK_100: - sd_card->sd_clock = CLK_80; - break; - - case CLK_80: - sd_card->sd_clock = CLK_60; - break; - - case CLK_60: - sd_card->sd_clock = CLK_50; - break; - - default: - break; - } - } - - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, - u16 sector_cnt) -{ - struct sd_info *sd_card = &chip->sd_card; - u32 data_addr; - u8 cfg2; - int retval; - - if (srb->sc_data_direction == DMA_FROM_DEVICE) { - dev_dbg(rtsx_dev(chip), "%s: Read %d %s from 0x%x\n", __func__, - sector_cnt, (sector_cnt > 1) ? "sectors" : "sector", - start_sector); - } else { - dev_dbg(rtsx_dev(chip), "%s: Write %d %s to 0x%x\n", __func__, - sector_cnt, (sector_cnt > 1) ? "sectors" : "sector", - start_sector); - } - - sd_card->cleanup_counter = 0; - - if (!(chip->card_ready & SD_CARD)) { - sd_card->seq_mode = 0; - - retval = reset_sd_card(chip); - if (retval == STATUS_SUCCESS) { - chip->card_ready |= SD_CARD; - chip->card_fail &= ~SD_CARD; - } else { - chip->card_ready &= ~SD_CARD; - chip->card_fail |= SD_CARD; - chip->capacity[chip->card2lun[SD_CARD]] = 0; - chip->rw_need_retry = 1; - return STATUS_FAIL; - } - } - - if (!CHK_SD_HCXC(sd_card) && !CHK_MMC_SECTOR_MODE(sd_card)) - data_addr = start_sector << 9; - else - data_addr = start_sector; - - sd_clr_err_code(chip); - - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_IO_ERR); - goto RW_FAIL; - } - - if (sd_card->seq_mode && - (sd_card->pre_dir != srb->sc_data_direction || - ((sd_card->pre_sec_addr + sd_card->pre_sec_cnt) != - start_sector))) { - if (sd_card->pre_sec_cnt < 0x80 && - sd_card->pre_dir == DMA_FROM_DEVICE && - !CHK_SD30_SPEED(sd_card) && - !CHK_SD_HS(sd_card) && - !CHK_MMC_HS(sd_card)) { - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - } - - retval = sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, - SD_RSP_TYPE_R1b, NULL, 0); - if (retval != STATUS_SUCCESS) { - chip->rw_need_retry = 1; - sd_set_err_code(chip, SD_STS_ERR); - goto RW_FAIL; - } - - sd_card->seq_mode = 0; - - retval = rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); - if (retval != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_IO_ERR); - goto RW_FAIL; - } - - if (sd_card->pre_sec_cnt < 0x80 && - !CHK_SD30_SPEED(sd_card) && - !CHK_SD_HS(sd_card) && - !CHK_MMC_HS(sd_card)) { - sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0); - } - } - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, 0x00); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, 0x02); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, 0xFF, - (u8)sector_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, 0xFF, - (u8)(sector_cnt >> 8)); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - - if (CHK_MMC_8BIT(sd_card)) - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, - 0x03, SD_BUS_WIDTH_8); - else if (CHK_MMC_4BIT(sd_card) || CHK_SD(sd_card)) - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, - 0x03, SD_BUS_WIDTH_4); - else - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, - 0x03, SD_BUS_WIDTH_1); - - if (sd_card->seq_mode) { - cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | - SD_RSP_LEN_0; - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, cfg2); - - trans_dma_enable(srb->sc_data_direction, chip, sector_cnt * 512, - DMA_512); - - if (srb->sc_data_direction == DMA_FROM_DEVICE) { - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - SD_TM_AUTO_READ_3 | SD_TRANSFER_START); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START); - } - - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - } else { - if (srb->sc_data_direction == DMA_FROM_DEVICE) { - dev_dbg(rtsx_dev(chip), "SD/MMC CMD %d\n", - READ_MULTIPLE_BLOCK); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0, 0xFF, - 0x40 | READ_MULTIPLE_BLOCK); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD1, 0xFF, - (u8)(data_addr >> 24)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD2, 0xFF, - (u8)(data_addr >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD3, 0xFF, - (u8)(data_addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD4, 0xFF, - (u8)data_addr); - - cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | - SD_RSP_LEN_6; - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, - cfg2); - - trans_dma_enable(srb->sc_data_direction, chip, - sector_cnt * 512, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - SD_TM_AUTO_READ_2 | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - } else { - retval = rtsx_send_cmd(chip, SD_CARD, 50); - if (retval < 0) { - rtsx_clear_sd_error(chip); - - chip->rw_need_retry = 1; - sd_set_err_code(chip, SD_TO_ERR); - goto RW_FAIL; - } - - retval = wait_data_buf_ready(chip); - if (retval != STATUS_SUCCESS) { - chip->rw_need_retry = 1; - sd_set_err_code(chip, SD_TO_ERR); - goto RW_FAIL; - } - - retval = sd_send_cmd_get_rsp(chip, WRITE_MULTIPLE_BLOCK, - data_addr, SD_RSP_TYPE_R1, - NULL, 0); - if (retval != STATUS_SUCCESS) { - chip->rw_need_retry = 1; - goto RW_FAIL; - } - - rtsx_init_cmd(chip); - - cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | - SD_NO_WAIT_BUSY_END | - SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, - cfg2); - - trans_dma_enable(srb->sc_data_direction, chip, - sector_cnt * 512, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - } - - sd_card->seq_mode = 1; - } - - retval = rtsx_transfer_data(chip, SD_CARD, scsi_sglist(srb), - scsi_bufflen(srb), scsi_sg_count(srb), - srb->sc_data_direction, chip->sd_timeout); - if (retval < 0) { - u8 stat = 0; - int err; - - sd_card->seq_mode = 0; - - if (retval == -ETIMEDOUT) - err = STATUS_TIMEDOUT; - else - err = STATUS_FAIL; - - rtsx_read_register(chip, REG_SD_STAT1, &stat); - rtsx_clear_sd_error(chip); - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - chip->rw_need_retry = 0; - dev_dbg(rtsx_dev(chip), "No card exist, exit %s\n", - __func__); - return STATUS_FAIL; - } - - chip->rw_need_retry = 1; - - retval = sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, - SD_RSP_TYPE_R1b, NULL, 0); - if (retval != STATUS_SUCCESS) { - sd_set_err_code(chip, SD_STS_ERR); - goto RW_FAIL; - } - - if (stat & (SD_CRC7_ERR | SD_CRC16_ERR | SD_CRC_WRITE_ERR)) { - dev_dbg(rtsx_dev(chip), "SD CRC error, tune clock!\n"); - sd_set_err_code(chip, SD_CRC_ERR); - goto RW_FAIL; - } - - if (err == STATUS_TIMEDOUT) { - sd_set_err_code(chip, SD_TO_ERR); - goto RW_FAIL; - } - - return err; - } - - sd_card->pre_sec_addr = start_sector; - sd_card->pre_sec_cnt = sector_cnt; - sd_card->pre_dir = srb->sc_data_direction; - - return STATUS_SUCCESS; - -RW_FAIL: - sd_card->seq_mode = 0; - - if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { - chip->rw_need_retry = 0; - dev_dbg(rtsx_dev(chip), "No card exist, exit %s\n", __func__); - return STATUS_FAIL; - } - - if (sd_check_err_code(chip, SD_CRC_ERR)) { - if (CHK_MMC_4BIT(sd_card) || CHK_MMC_8BIT(sd_card)) { - sd_card->mmc_dont_switch_bus = 1; - reset_mmc_only(chip); - sd_card->mmc_dont_switch_bus = 0; - } else { - sd_card->need_retune = 1; - sd_auto_tune_clock(chip); - } - } else if (sd_check_err_code(chip, SD_TO_ERR | SD_STS_ERR)) { - retval = reset_sd_card(chip); - if (retval != STATUS_SUCCESS) { - chip->card_ready &= ~SD_CARD; - chip->card_fail |= SD_CARD; - chip->capacity[chip->card2lun[SD_CARD]] = 0; - } - } - - return STATUS_FAIL; -} - -#ifdef SUPPORT_CPRM -int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx, u32 arg, - u8 rsp_type, u8 *rsp, int rsp_len, - bool special_check) -{ - int retval; - int timeout = 100; - u16 reg_addr; - u8 *ptr; - int stat_idx = 0; - int rty_cnt = 0; - - dev_dbg(rtsx_dev(chip), "EXT SD/MMC CMD %d\n", cmd_idx); - - if (rsp_type == SD_RSP_TYPE_R1b) - timeout = 3000; - -RTY_SEND_CMD: - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0, 0xFF, 0x40 | cmd_idx); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD1, 0xFF, (u8)(arg >> 24)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD2, 0xFF, (u8)(arg >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD3, 0xFF, (u8)(arg >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD4, 0xFF, (u8)arg); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, rsp_type); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, - 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, - SD_TRANSFER_END); - - if (rsp_type == SD_RSP_TYPE_R2) { - for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; - reg_addr++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - - stat_idx = 17; - } else if (rsp_type != SD_RSP_TYPE_R0) { - for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; - reg_addr++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - - stat_idx = 6; - } - rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_CMD5, 0, 0); - - rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_STAT1, 0, 0); - - retval = rtsx_send_cmd(chip, SD_CARD, timeout); - if (retval < 0) { - if (retval == -ETIMEDOUT) { - rtsx_clear_sd_error(chip); - - if (rsp_type & SD_WAIT_BUSY_END) { - retval = sd_check_data0_status(chip); - if (retval != STATUS_SUCCESS) - return retval; - } else { - sd_set_err_code(chip, SD_TO_ERR); - } - } - return STATUS_FAIL; - } - - if (rsp_type == SD_RSP_TYPE_R0) - return STATUS_SUCCESS; - - ptr = rtsx_get_cmd_data(chip) + 1; - - if ((ptr[0] & 0xC0) != 0) { - sd_set_err_code(chip, SD_STS_ERR); - return STATUS_FAIL; - } - - if (!(rsp_type & SD_NO_CHECK_CRC7)) { - if (ptr[stat_idx] & SD_CRC7_ERR) { - if (cmd_idx == WRITE_MULTIPLE_BLOCK) { - sd_set_err_code(chip, SD_CRC_ERR); - return STATUS_FAIL; - } - if (rty_cnt < SD_MAX_RETRY_COUNT) { - wait_timeout(20); - rty_cnt++; - goto RTY_SEND_CMD; - } else { - sd_set_err_code(chip, SD_CRC_ERR); - return STATUS_FAIL; - } - } - } - - if (cmd_idx == SELECT_CARD || cmd_idx == APP_CMD || - cmd_idx == SEND_STATUS || cmd_idx == STOP_TRANSMISSION) { - if (cmd_idx != STOP_TRANSMISSION && !special_check) { - if (ptr[1] & 0x80) - return STATUS_FAIL; - } -#ifdef SUPPORT_SD_LOCK - if (ptr[1] & 0x7D) { -#else - if (ptr[1] & 0x7F) { -#endif - return STATUS_FAIL; - } - if (ptr[2] & 0xF8) - return STATUS_FAIL; - - if (cmd_idx == SELECT_CARD) { - if (rsp_type == SD_RSP_TYPE_R2) { - if ((ptr[3] & 0x1E) != 0x04) - return STATUS_FAIL; - } - } - } - - if (rsp && rsp_len) - memcpy(rsp, ptr, rsp_len); - - return STATUS_SUCCESS; -} - -int ext_sd_get_rsp(struct rtsx_chip *chip, int len, u8 *rsp, u8 rsp_type) -{ - int retval, rsp_len; - u16 reg_addr; - - if (rsp_type == SD_RSP_TYPE_R0) - return STATUS_SUCCESS; - - rtsx_init_cmd(chip); - - if (rsp_type == SD_RSP_TYPE_R2) { - for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; - reg_addr++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0); - - rsp_len = 17; - } else if (rsp_type != SD_RSP_TYPE_R0) { - for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; - reg_addr++) - rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0); - - rsp_len = 6; - } - rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_CMD5, 0xFF, 0); - - retval = rtsx_send_cmd(chip, SD_CARD, 100); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (rsp) { - int min_len = (rsp_len < len) ? rsp_len : len; - - memcpy(rsp, rtsx_get_cmd_data(chip), min_len); - - dev_dbg(rtsx_dev(chip), "min_len = %d\n", min_len); - dev_dbg(rtsx_dev(chip), "Response in cmd buf: 0x%x 0x%x 0x%x 0x%x\n", - rsp[0], rsp[1], rsp[2], rsp[3]); - } - - return STATUS_SUCCESS; -} - -int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - unsigned int lun = SCSI_LUN(srb); - int len; - u8 buf[18] = { - 0x00, - 0x00, - 0x00, - 0x0E, - 0x00, - 0x00, - 0x00, - 0x00, - 0x53, - 0x44, - 0x20, - 0x43, - 0x61, - 0x72, - 0x64, - 0x00, - 0x00, - 0x00, - }; - - sd_card->pre_cmd_err = 0; - - if (!(CHK_BIT(chip->lun_mc, lun))) { - SET_BIT(chip->lun_mc, lun); - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - - if (srb->cmnd[2] != 0x53 || srb->cmnd[3] != 0x44 || - srb->cmnd[4] != 0x20 || srb->cmnd[5] != 0x43 || - srb->cmnd[6] != 0x61 || srb->cmnd[7] != 0x72 || - srb->cmnd[8] != 0x64) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - switch (srb->cmnd[1] & 0x0F) { - case 0: - sd_card->sd_pass_thru_en = 0; - break; - - case 1: - sd_card->sd_pass_thru_en = 1; - break; - - default: - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - buf[5] = (CHK_SD(sd_card) == 1) ? 0x01 : 0x02; - if (chip->card_wp & SD_CARD) - buf[5] |= 0x80; - - buf[6] = (u8)(sd_card->sd_addr >> 16); - buf[7] = (u8)(sd_card->sd_addr >> 24); - - buf[15] = chip->max_lun; - - len = min_t(int, 18, scsi_bufflen(srb)); - rtsx_stor_set_xfer_buf(buf, len, srb); - - return TRANSPORT_GOOD; -} - -static inline int get_rsp_type(struct scsi_cmnd *srb, u8 *rsp_type, - int *rsp_len) -{ - if (!rsp_type || !rsp_len) - return STATUS_FAIL; - - switch (srb->cmnd[10]) { - case 0x03: - *rsp_type = SD_RSP_TYPE_R0; - *rsp_len = 0; - break; - - case 0x04: - *rsp_type = SD_RSP_TYPE_R1; - *rsp_len = 6; - break; - - case 0x05: - *rsp_type = SD_RSP_TYPE_R1b; - *rsp_len = 6; - break; - - case 0x06: - *rsp_type = SD_RSP_TYPE_R2; - *rsp_len = 17; - break; - - case 0x07: - *rsp_type = SD_RSP_TYPE_R3; - *rsp_len = 6; - break; - - default: - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - unsigned int lun = SCSI_LUN(srb); - int retval, rsp_len; - u8 cmd_idx, rsp_type; - bool standby = false, acmd = false; - u32 arg; - - if (!sd_card->sd_pass_thru_en) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - if (sd_card->pre_cmd_err) { - sd_card->pre_cmd_err = 0; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - - cmd_idx = srb->cmnd[2] & 0x3F; - if (srb->cmnd[1] & 0x02) - standby = true; - - if (srb->cmnd[1] & 0x01) - acmd = true; - - arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) | - ((u32)srb->cmnd[5] << 8) | srb->cmnd[6]; - - retval = get_rsp_type(srb, &rsp_type, &rsp_len); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - sd_card->last_rsp_type = rsp_type; - - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - -#ifdef SUPPORT_SD_LOCK - if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { - if (CHK_MMC_8BIT(sd_card)) { - retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, - SD_BUS_WIDTH_8); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { - retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, - SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - } - } -#else - retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; -#endif - - if (standby) { - retval = sd_select_card(chip, 0); - if (retval != STATUS_SUCCESS) - goto sd_execute_cmd_failed; - } - - if (acmd) { - retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, - sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_cmd_failed; - } - - retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type, - sd_card->rsp, rsp_len, false); - if (retval != STATUS_SUCCESS) - goto sd_execute_cmd_failed; - - if (standby) { - retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) - goto sd_execute_cmd_failed; - } - -#ifdef SUPPORT_SD_LOCK - retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) - goto sd_execute_cmd_failed; -#endif - - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; - -sd_execute_cmd_failed: - sd_card->pre_cmd_err = 1; - set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - release_sd_card(chip); - do_reset_sd_card(chip); - if (!(chip->card_ready & SD_CARD)) - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - - return TRANSPORT_FAILED; -} - -int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - unsigned int lun = SCSI_LUN(srb); - int retval, rsp_len, i; - bool read_err = false, cmd13_checkbit = false; - u8 cmd_idx, rsp_type, bus_width; - bool standby = false, send_cmd12 = false, acmd = false; - u32 data_len; - - if (!sd_card->sd_pass_thru_en) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - if (sd_card->pre_cmd_err) { - sd_card->pre_cmd_err = 0; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - cmd_idx = srb->cmnd[2] & 0x3F; - if (srb->cmnd[1] & 0x04) - send_cmd12 = true; - - if (srb->cmnd[1] & 0x02) - standby = true; - - if (srb->cmnd[1] & 0x01) - acmd = true; - - data_len = ((u32)srb->cmnd[7] << 16) | ((u32)srb->cmnd[8] - << 8) | srb->cmnd[9]; - - retval = get_rsp_type(srb, &rsp_type, &rsp_len); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - sd_card->last_rsp_type = rsp_type; - - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - -#ifdef SUPPORT_SD_LOCK - if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { - if (CHK_MMC_8BIT(sd_card)) - bus_width = SD_BUS_WIDTH_8; - else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) - bus_width = SD_BUS_WIDTH_4; - else - bus_width = SD_BUS_WIDTH_1; - } else { - bus_width = SD_BUS_WIDTH_4; - } - dev_dbg(rtsx_dev(chip), "bus_width = %d\n", bus_width); -#else - bus_width = SD_BUS_WIDTH_4; -#endif - - if (data_len < 512) { - retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len, - SD_RSP_TYPE_R1, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - } - - if (standby) { - retval = sd_select_card(chip, 0); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - } - - if (acmd) { - retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, - sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - } - - if (data_len <= 512) { - int min_len; - u8 *buf; - u16 byte_cnt, blk_cnt; - u8 cmd[5]; - - byte_cnt = ((u16)(srb->cmnd[8] & 0x03) << 8) | srb->cmnd[9]; - blk_cnt = 1; - - cmd[0] = 0x40 | cmd_idx; - cmd[1] = srb->cmnd[3]; - cmd[2] = srb->cmnd[4]; - cmd[3] = srb->cmnd[5]; - cmd[4] = srb->cmnd[6]; - - buf = kmalloc(data_len, GFP_KERNEL); - if (!buf) - return TRANSPORT_ERROR; - - retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, byte_cnt, - blk_cnt, bus_width, buf, data_len, 2000); - if (retval != STATUS_SUCCESS) { - read_err = true; - kfree(buf); - rtsx_clear_sd_error(chip); - goto sd_execute_read_cmd_failed; - } - - min_len = min(data_len, scsi_bufflen(srb)); - rtsx_stor_set_xfer_buf(buf, min_len, srb); - - kfree(buf); - } else if (!(data_len & 0x1FF)) { - rtsx_init_cmd(chip); - - trans_dma_enable(DMA_FROM_DEVICE, chip, data_len, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, - 0x02); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, - 0x00); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, - 0xFF, (srb->cmnd[7] & 0xFE) >> 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, - 0xFF, (u8)((data_len & 0x0001FE00) >> 9)); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0, 0xFF, - 0x40 | cmd_idx); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD1, 0xFF, - srb->cmnd[3]); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD2, 0xFF, - srb->cmnd[4]); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD3, 0xFF, - srb->cmnd[5]); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD4, 0xFF, - srb->cmnd[6]); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, bus_width); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, rsp_type); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, - 0xFF, SD_TM_AUTO_READ_2 | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data(chip, SD_CARD, scsi_sglist(srb), - scsi_bufflen(srb), - scsi_sg_count(srb), - DMA_FROM_DEVICE, 10000); - if (retval < 0) { - read_err = true; - rtsx_clear_sd_error(chip); - goto sd_execute_read_cmd_failed; - } - - } else { - goto sd_execute_read_cmd_failed; - } - - retval = ext_sd_get_rsp(chip, rsp_len, sd_card->rsp, rsp_type); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - - if (standby) { - retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - } - - if (send_cmd12) { - retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, - SD_RSP_TYPE_R1b, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - } - - if (data_len < 512) { - retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, - SD_RSP_TYPE_R1, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - - retval = rtsx_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - - retval = rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00); - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - } - - if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04)) - cmd13_checkbit = true; - - for (i = 0; i < 3; i++) { - retval = ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, - sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0, - cmd13_checkbit); - if (retval == STATUS_SUCCESS) - break; - } - if (retval != STATUS_SUCCESS) - goto sd_execute_read_cmd_failed; - - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; - -sd_execute_read_cmd_failed: - sd_card->pre_cmd_err = 1; - set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - if (read_err) - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - - release_sd_card(chip); - do_reset_sd_card(chip); - if (!(chip->card_ready & SD_CARD)) - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - - return TRANSPORT_FAILED; -} - -int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - unsigned int lun = SCSI_LUN(srb); - int retval, rsp_len, i; - bool write_err = false, cmd13_checkbit = false; - u8 cmd_idx, rsp_type; - bool standby = false, send_cmd12 = false, acmd = false; - u32 data_len, arg; -#ifdef SUPPORT_SD_LOCK - int lock_cmd_fail = 0; - u8 sd_lock_state = 0; - u8 lock_cmd_type = 0; -#endif - - if (!sd_card->sd_pass_thru_en) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - if (sd_card->pre_cmd_err) { - sd_card->pre_cmd_err = 0; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - cmd_idx = srb->cmnd[2] & 0x3F; - if (srb->cmnd[1] & 0x04) - send_cmd12 = true; - - if (srb->cmnd[1] & 0x02) - standby = true; - - if (srb->cmnd[1] & 0x01) - acmd = true; - - data_len = ((u32)srb->cmnd[7] << 16) | ((u32)srb->cmnd[8] - << 8) | srb->cmnd[9]; - arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) | - ((u32)srb->cmnd[5] << 8) | srb->cmnd[6]; - -#ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) { - sd_lock_state = sd_card->sd_lock_status; - sd_lock_state &= SD_LOCKED; - } -#endif - - retval = get_rsp_type(srb, &rsp_type, &rsp_len); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - sd_card->last_rsp_type = rsp_type; - - retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - -#ifdef SUPPORT_SD_LOCK - if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { - if (CHK_MMC_8BIT(sd_card)) { - retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, - SD_BUS_WIDTH_8); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - - } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { - retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, - SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; - } - } -#else - retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) - return TRANSPORT_FAILED; -#endif - - if (data_len < 512) { - retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len, - SD_RSP_TYPE_R1, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - } - - if (standby) { - retval = sd_select_card(chip, 0); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - } - - if (acmd) { - retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, - sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - } - - retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type, - sd_card->rsp, rsp_len, false); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - - if (data_len <= 512) { - u16 i; - u8 *buf; - - buf = kmalloc(data_len, GFP_KERNEL); - if (!buf) - return TRANSPORT_ERROR; - - rtsx_stor_get_xfer_buf(buf, data_len, srb); - -#ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) - lock_cmd_type = buf[0] & 0x0F; -#endif - - if (data_len > 256) { - rtsx_init_cmd(chip); - for (i = 0; i < 256; i++) { - rtsx_add_cmd(chip, WRITE_REG_CMD, - PPBUF_BASE2 + i, 0xFF, buf[i]); - } - retval = rtsx_send_cmd(chip, 0, 250); - if (retval != STATUS_SUCCESS) { - kfree(buf); - goto sd_execute_write_cmd_failed; - } - - rtsx_init_cmd(chip); - for (i = 256; i < data_len; i++) { - rtsx_add_cmd(chip, WRITE_REG_CMD, - PPBUF_BASE2 + i, 0xFF, buf[i]); - } - retval = rtsx_send_cmd(chip, 0, 250); - if (retval != STATUS_SUCCESS) { - kfree(buf); - goto sd_execute_write_cmd_failed; - } - } else { - rtsx_init_cmd(chip); - for (i = 0; i < data_len; i++) { - rtsx_add_cmd(chip, WRITE_REG_CMD, - PPBUF_BASE2 + i, 0xFF, buf[i]); - } - retval = rtsx_send_cmd(chip, 0, 250); - if (retval != STATUS_SUCCESS) { - kfree(buf); - goto sd_execute_write_cmd_failed; - } - } - - kfree(buf); - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, - srb->cmnd[8] & 0x03); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, - srb->cmnd[9]); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, 0xFF, - 0x00); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, 0xFF, - 0x01); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, - PINGPONG_BUFFER); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, SD_CARD, 250); - } else if (!(data_len & 0x1FF)) { - rtsx_init_cmd(chip); - - trans_dma_enable(DMA_TO_DEVICE, chip, data_len, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, - 0x02); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, - 0x00); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, - 0xFF, (srb->cmnd[7] & 0xFE) >> 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, - 0xFF, (u8)((data_len & 0x0001FE00) >> 9)); - - rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, - SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START); - rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, - SD_TRANSFER_END, SD_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data(chip, SD_CARD, scsi_sglist(srb), - scsi_bufflen(srb), - scsi_sg_count(srb), - DMA_TO_DEVICE, 10000); - - } else { - goto sd_execute_write_cmd_failed; - } - - if (retval < 0) { - write_err = true; - rtsx_clear_sd_error(chip); - goto sd_execute_write_cmd_failed; - } - -#ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) { - if (lock_cmd_type == SD_ERASE) { - sd_card->sd_erase_status = SD_UNDER_ERASING; - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; - } - - rtsx_init_cmd(chip); - rtsx_add_cmd(chip, CHECK_REG_CMD, 0xFD30, 0x02, 0x02); - - retval = rtsx_send_cmd(chip, SD_CARD, 250); - if (retval < 0) { - write_err = true; - rtsx_clear_sd_error(chip); - goto sd_execute_write_cmd_failed; - } - - retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) { - dev_dbg(rtsx_dev(chip), "Lock command fail!\n"); - lock_cmd_fail = 1; - } - } -#endif /* SUPPORT_SD_LOCK */ - - if (standby) { - retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - } - - if (send_cmd12) { - retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, - SD_RSP_TYPE_R1b, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - } - - if (data_len < 512) { - retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, - SD_RSP_TYPE_R1, NULL, 0, - false); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - - retval = rtsx_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - - retval = rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00); - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - } - - if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04)) - cmd13_checkbit = true; - - for (i = 0; i < 3; i++) { - retval = ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, - sd_card->sd_addr, - SD_RSP_TYPE_R1, NULL, 0, - cmd13_checkbit); - if (retval == STATUS_SUCCESS) - break; - } - if (retval != STATUS_SUCCESS) - goto sd_execute_write_cmd_failed; - -#ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) { - if (!lock_cmd_fail) { - dev_dbg(rtsx_dev(chip), "lock_cmd_type = 0x%x\n", - lock_cmd_type); - if (lock_cmd_type & SD_CLR_PWD) - sd_card->sd_lock_status &= ~SD_PWD_EXIST; - - if (lock_cmd_type & SD_SET_PWD) - sd_card->sd_lock_status |= SD_PWD_EXIST; - } - - dev_dbg(rtsx_dev(chip), "sd_lock_state = 0x%x, sd_card->sd_lock_status = 0x%x\n", - sd_lock_state, sd_card->sd_lock_status); - if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) { - sd_card->sd_lock_notify = 1; - if (sd_lock_state && - (sd_card->sd_lock_status & SD_LOCK_1BIT_MODE)) { - sd_card->sd_lock_status |= (SD_UNLOCK_POW_ON | SD_SDR_RST); - if (CHK_SD(sd_card)) { - retval = reset_sd(chip); - if (retval != STATUS_SUCCESS) { - sd_card->sd_lock_status &= - ~(SD_UNLOCK_POW_ON | SD_SDR_RST); - goto sd_execute_write_cmd_failed; - } - } - - sd_card->sd_lock_status &= ~(SD_UNLOCK_POW_ON | SD_SDR_RST); - } - } - } - - if (lock_cmd_fail) { - scsi_set_resid(srb, 0); - set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - return TRANSPORT_FAILED; - } -#endif /* SUPPORT_SD_LOCK */ - - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; - -sd_execute_write_cmd_failed: - sd_card->pre_cmd_err = 1; - set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - if (write_err) - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); - - release_sd_card(chip); - do_reset_sd_card(chip); - if (!(chip->card_ready & SD_CARD)) - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - - return TRANSPORT_FAILED; -} - -int sd_get_cmd_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - unsigned int lun = SCSI_LUN(srb); - int count; - u16 data_len; - - if (!sd_card->sd_pass_thru_en) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - if (sd_card->pre_cmd_err) { - sd_card->pre_cmd_err = 0; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - - data_len = ((u16)srb->cmnd[7] << 8) | srb->cmnd[8]; - - if (sd_card->last_rsp_type == SD_RSP_TYPE_R0) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } else if (sd_card->last_rsp_type == SD_RSP_TYPE_R2) { - count = (data_len < 17) ? data_len : 17; - } else { - count = (data_len < 6) ? data_len : 6; - } - rtsx_stor_set_xfer_buf(sd_card->rsp, count, srb); - - dev_dbg(rtsx_dev(chip), "Response length: %d\n", data_len); - dev_dbg(rtsx_dev(chip), "Response: 0x%x 0x%x 0x%x 0x%x\n", - sd_card->rsp[0], sd_card->rsp[1], - sd_card->rsp[2], sd_card->rsp[3]); - - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; -} - -int sd_hw_rst(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - unsigned int lun = SCSI_LUN(srb); - int retval; - - if (!sd_card->sd_pass_thru_en) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - if (sd_card->pre_cmd_err) { - sd_card->pre_cmd_err = 0; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE); - return TRANSPORT_FAILED; - } - - if (srb->cmnd[2] != 0x53 || srb->cmnd[3] != 0x44 || - srb->cmnd[4] != 0x20 || srb->cmnd[5] != 0x43 || - srb->cmnd[6] != 0x61 || srb->cmnd[7] != 0x72 || - srb->cmnd[8] != 0x64) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - switch (srb->cmnd[1] & 0x0F) { - case 0: -#ifdef SUPPORT_SD_LOCK - if (srb->cmnd[9] == 0x64) - sd_card->sd_lock_status |= SD_SDR_RST; -#endif - retval = reset_sd_card(chip); - if (retval != STATUS_SUCCESS) { -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_SDR_RST; -#endif - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - sd_card->pre_cmd_err = 1; - return TRANSPORT_FAILED; - } -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status &= ~SD_SDR_RST; -#endif - break; - - case 1: - retval = reset_sd(chip); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - sd_card->pre_cmd_err = 1; - return TRANSPORT_FAILED; - } - break; - - default: - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); - return TRANSPORT_FAILED; - } - - scsi_set_resid(srb, 0); - return TRANSPORT_GOOD; -} -#endif - -void sd_cleanup_work(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - - if (sd_card->seq_mode) { - dev_dbg(rtsx_dev(chip), "SD: stop transmission\n"); - sd_stop_seq_mode(chip); - sd_card->cleanup_counter = 0; - } -} - -int sd_power_off_card3v3(struct rtsx_chip *chip) -{ - int retval; - - retval = disable_card_clock(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, CARD_OE, SD_OUTPUT_EN, 0); - if (retval) - return retval; - - if (!chip->ft2_fast_mode) { - retval = card_power_off(chip, SD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - mdelay(50); - } - - if (chip->asic_code) { - retval = sd_pull_ctl_disable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register(chip, FPGA_PULL_CTL, - FPGA_SD_PULL_CTL_BIT | 0x20, - FPGA_SD_PULL_CTL_BIT); - if (retval) - return retval; - } - - return STATUS_SUCCESS; -} - -int release_sd_card(struct rtsx_chip *chip) -{ - struct sd_info *sd_card = &chip->sd_card; - int retval; - - chip->card_ready &= ~SD_CARD; - chip->card_fail &= ~SD_CARD; - chip->card_wp &= ~SD_CARD; - - chip->sd_io = 0; - chip->sd_int = 0; - -#ifdef SUPPORT_SD_LOCK - sd_card->sd_lock_status = 0; - sd_card->sd_erase_status = 0; -#endif - - memset(sd_card->raw_csd, 0, 16); - memset(sd_card->raw_scr, 0, 8); - - retval = sd_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} diff --git a/drivers/staging/rts5208/sd.h b/drivers/staging/rts5208/sd.h deleted file mode 100644 index f4ff62653b56c3..00000000000000 --- a/drivers/staging/rts5208/sd.h +++ /dev/null @@ -1,289 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_SD_H -#define __REALTEK_RTSX_SD_H - -#include "rtsx_chip.h" - -#define SUPPORT_VOLTAGE 0x003C0000 - -/* Error Code */ -#define SD_NO_ERROR 0x0 -#define SD_CRC_ERR 0x80 -#define SD_TO_ERR 0x40 -#define SD_NO_CARD 0x20 -#define SD_BUSY 0x10 -#define SD_STS_ERR 0x08 -#define SD_RSP_TIMEOUT 0x04 -#define SD_IO_ERR 0x02 - -/* Return code for MMC switch bus */ -#define SWITCH_SUCCESS 0 -#define SWITCH_ERR 1 -#define SWITCH_FAIL 2 - -/* MMC/SD Command Index */ -/* Basic command (class 0) */ -#define GO_IDLE_STATE 0 -#define SEND_OP_COND 1 -#define ALL_SEND_CID 2 -#define SET_RELATIVE_ADDR 3 -#define SEND_RELATIVE_ADDR 3 -#define SET_DSR 4 -#define IO_SEND_OP_COND 5 -#define SWITCH 6 -#define SELECT_CARD 7 -#define DESELECT_CARD 7 -/* CMD8 is "SEND_EXT_CSD" for MMC4.x Spec - * while is "SEND_IF_COND" for SD 2.0 - */ -#define SEND_EXT_CSD 8 -#define SEND_IF_COND 8 - -#define SEND_CSD 9 -#define SEND_CID 10 -#define VOLTAGE_SWITCH 11 -#define READ_DAT_UTIL_STOP 11 -#define STOP_TRANSMISSION 12 -#define SEND_STATUS 13 -#define GO_INACTIVE_STATE 15 - -#define SET_BLOCKLEN 16 -#define READ_SINGLE_BLOCK 17 -#define READ_MULTIPLE_BLOCK 18 -#define SEND_TUNING_PATTERN 19 - -#define BUSTEST_R 14 -#define BUSTEST_W 19 - -#define WRITE_BLOCK 24 -#define WRITE_MULTIPLE_BLOCK 25 -#define PROGRAM_CSD 27 - -#define ERASE_WR_BLK_START 32 -#define ERASE_WR_BLK_END 33 -#define ERASE_CMD 38 - -#define LOCK_UNLOCK 42 -#define IO_RW_DIRECT 52 - -#define APP_CMD 55 -#define GEN_CMD 56 - -#define SET_BUS_WIDTH 6 -#define SD_STATUS 13 -#define SEND_NUM_WR_BLOCKS 22 -#define SET_WR_BLK_ERASE_COUNT 23 -#define SD_APP_OP_COND 41 -#define SET_CLR_CARD_DETECT 42 -#define SEND_SCR 51 - -#define SD_READ_COMPLETE 0x00 -#define SD_READ_TO 0x01 -#define SD_READ_ADVENCE 0x02 - -#define SD_CHECK_MODE 0x00 -#define SD_SWITCH_MODE 0x80 -#define SD_FUNC_GROUP_1 0x01 -#define SD_FUNC_GROUP_2 0x02 -#define SD_FUNC_GROUP_3 0x03 -#define SD_FUNC_GROUP_4 0x04 -#define SD_CHECK_SPEC_V1_1 0xFF - -#define NO_ARGUMENT 0x00 -#define CHECK_PATTERN 0x000000AA -#define VOLTAGE_SUPPLY_RANGE 0x00000100 -#define SUPPORT_HIGH_AND_EXTENDED_CAPACITY 0x40000000 -#define SUPPORT_MAX_POWER_PERMANCE 0x10000000 -#define SUPPORT_1V8 0x01000000 - -#define SWITCH_NO_ERR 0x00 -#define CARD_NOT_EXIST 0x01 -#define SPEC_NOT_SUPPORT 0x02 -#define CHECK_MODE_ERR 0x03 -#define CHECK_NOT_READY 0x04 -#define SWITCH_CRC_ERR 0x05 -#define SWITCH_MODE_ERR 0x06 -#define SWITCH_PASS 0x07 - -#ifdef SUPPORT_SD_LOCK -#define SD_ERASE 0x08 -#define SD_LOCK 0x04 -#define SD_UNLOCK 0x00 -#define SD_CLR_PWD 0x02 -#define SD_SET_PWD 0x01 - -#define SD_PWD_LEN 0x10 - -#define SD_LOCKED 0x80 -#define SD_LOCK_1BIT_MODE 0x40 -#define SD_PWD_EXIST 0x20 -#define SD_UNLOCK_POW_ON 0x01 -#define SD_SDR_RST 0x02 - -#define SD_NOT_ERASE 0x00 -#define SD_UNDER_ERASING 0x01 -#define SD_COMPLETE_ERASE 0x02 - -#define SD_RW_FORBIDDEN 0x0F - -#endif - -#define HS_SUPPORT 0x01 -#define SDR50_SUPPORT 0x02 -#define SDR104_SUPPORT 0x03 -#define DDR50_SUPPORT 0x04 - -#define HS_SUPPORT_MASK 0x02 -#define SDR50_SUPPORT_MASK 0x04 -#define SDR104_SUPPORT_MASK 0x08 -#define DDR50_SUPPORT_MASK 0x10 - -#define HS_QUERY_SWITCH_OK 0x01 -#define SDR50_QUERY_SWITCH_OK 0x02 -#define SDR104_QUERY_SWITCH_OK 0x03 -#define DDR50_QUERY_SWITCH_OK 0x04 - -#define HS_SWITCH_BUSY 0x02 -#define SDR50_SWITCH_BUSY 0x04 -#define SDR104_SWITCH_BUSY 0x08 -#define DDR50_SWITCH_BUSY 0x10 - -#define FUNCTION_GROUP1_SUPPORT_OFFSET 0x0D -#define FUNCTION_GROUP1_QUERY_SWITCH_OFFSET 0x10 -#define FUNCTION_GROUP1_CHECK_BUSY_OFFSET 0x1D - -#define DRIVING_TYPE_A 0x01 -#define DRIVING_TYPE_B 0x00 -#define DRIVING_TYPE_C 0x02 -#define DRIVING_TYPE_D 0x03 - -#define DRIVING_TYPE_A_MASK 0x02 -#define DRIVING_TYPE_B_MASK 0x01 -#define DRIVING_TYPE_C_MASK 0x04 -#define DRIVING_TYPE_D_MASK 0x08 - -#define TYPE_A_QUERY_SWITCH_OK 0x01 -#define TYPE_B_QUERY_SWITCH_OK 0x00 -#define TYPE_C_QUERY_SWITCH_OK 0x02 -#define TYPE_D_QUERY_SWITCH_OK 0x03 - -#define TYPE_A_SWITCH_BUSY 0x02 -#define TYPE_B_SWITCH_BUSY 0x01 -#define TYPE_C_SWITCH_BUSY 0x04 -#define TYPE_D_SWITCH_BUSY 0x08 - -#define FUNCTION_GROUP3_SUPPORT_OFFSET 0x09 -#define FUNCTION_GROUP3_QUERY_SWITCH_OFFSET 0x0F -#define FUNCTION_GROUP3_CHECK_BUSY_OFFSET 0x19 - -#define CURRENT_LIMIT_200 0x00 -#define CURRENT_LIMIT_400 0x01 -#define CURRENT_LIMIT_600 0x02 -#define CURRENT_LIMIT_800 0x03 - -#define CURRENT_LIMIT_200_MASK 0x01 -#define CURRENT_LIMIT_400_MASK 0x02 -#define CURRENT_LIMIT_600_MASK 0x04 -#define CURRENT_LIMIT_800_MASK 0x08 - -#define CURRENT_LIMIT_200_QUERY_SWITCH_OK 0x00 -#define CURRENT_LIMIT_400_QUERY_SWITCH_OK 0x01 -#define CURRENT_LIMIT_600_QUERY_SWITCH_OK 0x02 -#define CURRENT_LIMIT_800_QUERY_SWITCH_OK 0x03 - -#define CURRENT_LIMIT_200_SWITCH_BUSY 0x01 -#define CURRENT_LIMIT_400_SWITCH_BUSY 0x02 -#define CURRENT_LIMIT_600_SWITCH_BUSY 0x04 -#define CURRENT_LIMIT_800_SWITCH_BUSY 0x08 - -#define FUNCTION_GROUP4_SUPPORT_OFFSET 0x07 -#define FUNCTION_GROUP4_QUERY_SWITCH_OFFSET 0x0F -#define FUNCTION_GROUP4_CHECK_BUSY_OFFSET 0x17 - -#define DATA_STRUCTURE_VER_OFFSET 0x11 - -#define MAX_PHASE 31 - -#define MMC_8BIT_BUS 0x0010 -#define MMC_4BIT_BUS 0x0020 - -#define MMC_SWITCH_ERR 0x80 - -#define SD_IO_3V3 0 -#define SD_IO_1V8 1 - -#define TUNE_TX 0x00 -#define TUNE_RX 0x01 - -#define CHANGE_TX 0x00 -#define CHANGE_RX 0x01 - -#define DCM_HIGH_FREQUENCY_MODE 0x00 -#define DCM_LOW_FREQUENCY_MODE 0x01 - -#define DCM_HIGH_FREQUENCY_MODE_SET 0x0C -#define DCM_LOW_FREQUENCY_MODE_SET 0x00 - -#define MULTIPLY_BY_1 0x00 -#define MULTIPLY_BY_2 0x01 -#define MULTIPLY_BY_3 0x02 -#define MULTIPLY_BY_4 0x03 -#define MULTIPLY_BY_5 0x04 -#define MULTIPLY_BY_6 0x05 -#define MULTIPLY_BY_7 0x06 -#define MULTIPLY_BY_8 0x07 -#define MULTIPLY_BY_9 0x08 -#define MULTIPLY_BY_10 0x09 - -#define DIVIDE_BY_2 0x01 -#define DIVIDE_BY_3 0x02 -#define DIVIDE_BY_4 0x03 -#define DIVIDE_BY_5 0x04 -#define DIVIDE_BY_6 0x05 -#define DIVIDE_BY_7 0x06 -#define DIVIDE_BY_8 0x07 -#define DIVIDE_BY_9 0x08 -#define DIVIDE_BY_10 0x09 - -struct timing_phase_path { - int start; - int end; - int mid; - int len; -}; - -int sd_select_card(struct rtsx_chip *chip, int select); -int sd_pull_ctl_enable(struct rtsx_chip *chip); -int reset_sd_card(struct rtsx_chip *chip); -int sd_switch_clock(struct rtsx_chip *chip); -void sd_stop_seq_mode(struct rtsx_chip *chip); -int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 start_sector, u16 sector_cnt); -void sd_cleanup_work(struct rtsx_chip *chip); -int sd_power_off_card3v3(struct rtsx_chip *chip); -int release_sd_card(struct rtsx_chip *chip); -#ifdef SUPPORT_CPRM -int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx, - u32 arg, u8 rsp_type, u8 *rsp, int rsp_len, - bool special_check); -int ext_sd_get_rsp(struct rtsx_chip *chip, int len, u8 *rsp, u8 rsp_type); - -int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int sd_get_cmd_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int sd_hw_rst(struct scsi_cmnd *srb, struct rtsx_chip *chip); -#endif - -#endif /* __REALTEK_RTSX_SD_H */ diff --git a/drivers/staging/rts5208/spi.c b/drivers/staging/rts5208/spi.c deleted file mode 100644 index e88fe1a998f812..00000000000000 --- a/drivers/staging/rts5208/spi.c +++ /dev/null @@ -1,906 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include - -#include "rtsx.h" -#include "spi.h" - -static inline void spi_set_err_code(struct rtsx_chip *chip, u8 err_code) -{ - struct spi_info *spi = &chip->spi; - - spi->err_code = err_code; -} - -static int spi_init(struct rtsx_chip *chip) -{ - int retval; - - retval = rtsx_write_register(chip, SPI_CONTROL, 0xFF, - CS_POLARITY_LOW | DTO_MSB_FIRST - | SPI_MASTER | SPI_MODE0 | SPI_AUTO); - if (retval) - return retval; - retval = rtsx_write_register(chip, SPI_TCTL, EDO_TIMING_MASK, - SAMPLE_DELAY_HALF); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static int spi_set_init_para(struct rtsx_chip *chip) -{ - struct spi_info *spi = &chip->spi; - int retval; - - retval = rtsx_write_register(chip, SPI_CLK_DIVIDER1, 0xFF, - (u8)(spi->clk_div >> 8)); - if (retval) - return retval; - retval = rtsx_write_register(chip, SPI_CLK_DIVIDER0, 0xFF, - (u8)(spi->clk_div)); - if (retval) - return retval; - - retval = switch_clock(chip, spi->spi_clock); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = select_card(chip, SPI_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, CARD_CLK_EN, SPI_CLK_EN, - SPI_CLK_EN); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_OE, SPI_OUTPUT_EN, - SPI_OUTPUT_EN); - if (retval) - return retval; - - wait_timeout(10); - - retval = spi_init(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int sf_polling_status(struct rtsx_chip *chip, int msec) -{ - int retval; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, SPI_RDSR); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_POLLING_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, msec); - if (retval < 0) { - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_BUSY_ERR); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sf_enable_write(struct rtsx_chip *chip, u8 ins) -{ - struct spi_info *spi = &chip->spi; - int retval; - - if (!spi->write_en) - return STATUS_SUCCESS; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, - SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_C_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) { - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int sf_disable_write(struct rtsx_chip *chip, u8 ins) -{ - struct spi_info *spi = &chip->spi; - int retval; - - if (!spi->write_en) - return STATUS_SUCCESS; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, - SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_C_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) { - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static void sf_program(struct rtsx_chip *chip, u8 ins, u8 addr_mode, u32 addr, - u16 len) -{ - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, - SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, (u8)len); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, (u8)(len >> 8)); - if (addr_mode) { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, - (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, - (u8)(addr >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CADO_MODE0); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CDO_MODE0); - } - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); -} - -static int sf_erase(struct rtsx_chip *chip, u8 ins, u8 addr_mode, u32 addr) -{ - int retval; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, - SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24); - if (addr_mode) { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, - (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, - (u8)(addr >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CA_MODE0); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_C_MODE0); - } - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) { - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int spi_init_eeprom(struct rtsx_chip *chip) -{ - int retval; - int clk; - - if (chip->asic_code) - clk = 30; - else - clk = CLK_30; - - retval = rtsx_write_register(chip, SPI_CLK_DIVIDER1, 0xFF, 0x00); - if (retval) - return retval; - retval = rtsx_write_register(chip, SPI_CLK_DIVIDER0, 0xFF, 0x27); - if (retval) - return retval; - - retval = switch_clock(chip, clk); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = select_card(chip, SPI_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, CARD_CLK_EN, SPI_CLK_EN, - SPI_CLK_EN); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_OE, SPI_OUTPUT_EN, - SPI_OUTPUT_EN); - if (retval) - return retval; - - wait_timeout(10); - - retval = rtsx_write_register(chip, SPI_CONTROL, 0xFF, - CS_POLARITY_HIGH | SPI_EEPROM_AUTO); - if (retval) - return retval; - retval = rtsx_write_register(chip, SPI_TCTL, EDO_TIMING_MASK, - SAMPLE_DELAY_HALF); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -static int spi_eeprom_program_enable(struct rtsx_chip *chip) -{ - int retval; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x86); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x13); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CA_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -int spi_erase_eeprom_chip(struct rtsx_chip *chip) -{ - int retval; - - retval = spi_init_eeprom(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = spi_eeprom_program_enable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x12); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x84); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CA_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -int spi_erase_eeprom_byte(struct rtsx_chip *chip, u16 addr) -{ - int retval; - - retval = spi_init_eeprom(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = spi_eeprom_program_enable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x07); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x46); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CA_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -int spi_read_eeprom(struct rtsx_chip *chip, u16 addr, u8 *val) -{ - int retval; - u8 data; - - retval = spi_init_eeprom(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x06); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x46); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CADI_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) - return STATUS_FAIL; - - wait_timeout(5); - retval = rtsx_read_register(chip, SPI_DATA, &data); - if (retval) - return retval; - - if (val) - *val = data; - - retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -int spi_write_eeprom(struct rtsx_chip *chip, u16 addr, u8 val) -{ - int retval; - - retval = spi_init_eeprom(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = spi_eeprom_program_enable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x05); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, val); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x4E); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CA_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, CARD_GPIO_DIR, 0x01, 0x01); - if (retval) - return retval; - - return STATUS_SUCCESS; -} - -int spi_get_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct spi_info *spi = &chip->spi; - - dev_dbg(rtsx_dev(chip), "%s: err_code = 0x%x\n", __func__, - spi->err_code); - rtsx_stor_set_xfer_buf(&spi->err_code, - min_t(int, scsi_bufflen(srb), 1), srb); - scsi_set_resid(srb, scsi_bufflen(srb) - 1); - - return STATUS_SUCCESS; -} - -int spi_set_parameter(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - struct spi_info *spi = &chip->spi; - - spi_set_err_code(chip, SPI_NO_ERR); - - if (chip->asic_code) - spi->spi_clock = ((u16)(srb->cmnd[8]) << 8) | srb->cmnd[9]; - else - spi->spi_clock = srb->cmnd[3]; - - spi->clk_div = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5]; - spi->write_en = srb->cmnd[6]; - - dev_dbg(rtsx_dev(chip), "spi_clock = %d, clk_div = %d, write_en = %d\n", - spi->spi_clock, spi->clk_div, spi->write_en); - - return STATUS_SUCCESS; -} - -int spi_read_flash_id(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - u16 len; - u8 *buf; - - spi_set_err_code(chip, SPI_NO_ERR); - - len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8]; - if (len > 512) { - spi_set_err_code(chip, SPI_INVALID_COMMAND); - return STATUS_FAIL; - } - - retval = spi_set_init_para(chip); - if (retval != STATUS_SUCCESS) { - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, - PINGPONG_BUFFER); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, srb->cmnd[3]); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, srb->cmnd[4]); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, srb->cmnd[5]); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, srb->cmnd[6]); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, - SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, srb->cmnd[7]); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, srb->cmnd[8]); - - if (len == 0) { - if (srb->cmnd[9]) { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, - 0xFF, SPI_TRANSFER0_START | SPI_CA_MODE0); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, - 0xFF, SPI_TRANSFER0_START | SPI_C_MODE0); - } - } else { - if (srb->cmnd[9]) { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CADI_MODE0); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CDI_MODE0); - } - } - - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) { - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - if (len) { - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return STATUS_ERROR; - - retval = rtsx_read_ppbuf(chip, buf, len); - if (retval != STATUS_SUCCESS) { - spi_set_err_code(chip, SPI_READ_ERR); - kfree(buf); - return STATUS_FAIL; - } - - rtsx_stor_set_xfer_buf(buf, scsi_bufflen(srb), srb); - scsi_set_resid(srb, 0); - - kfree(buf); - } - - return STATUS_SUCCESS; -} - -int spi_read_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - unsigned int index = 0, offset = 0; - u8 ins, slow_read; - u32 addr; - u16 len; - u8 *buf; - - spi_set_err_code(chip, SPI_NO_ERR); - - ins = srb->cmnd[3]; - addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5]) - << 8) | srb->cmnd[6]; - len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8]; - slow_read = srb->cmnd[9]; - - retval = spi_set_init_para(chip); - if (retval != STATUS_SUCCESS) { - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - buf = kmalloc(SF_PAGE_LEN, GFP_KERNEL); - if (!buf) - return STATUS_ERROR; - - while (len) { - u16 pagelen = SF_PAGE_LEN - (u8)addr; - - if (pagelen > len) - pagelen = len; - - rtsx_init_cmd(chip); - - trans_dma_enable(DMA_FROM_DEVICE, chip, 256, DMA_256); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins); - - if (slow_read) { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, - (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, - (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, - (u8)(addr >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, - SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, - (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, - (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR3, 0xFF, - (u8)(addr >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, - SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_32); - } - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, - (u8)(pagelen >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, - (u8)pagelen); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CADI_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, - SPI_TRANSFER0_END, SPI_TRANSFER0_END); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data(chip, 0, buf, pagelen, 0, - DMA_FROM_DEVICE, 10000); - if (retval < 0) { - kfree(buf); - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - rtsx_stor_access_xfer_buf(buf, pagelen, srb, &index, &offset, - TO_XFER_BUF); - - addr += pagelen; - len -= pagelen; - } - - scsi_set_resid(srb, 0); - kfree(buf); - - return STATUS_SUCCESS; -} - -int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - u8 ins, program_mode; - u32 addr; - u16 len; - u8 *buf; - unsigned int index = 0, offset = 0; - - spi_set_err_code(chip, SPI_NO_ERR); - - ins = srb->cmnd[3]; - addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5]) - << 8) | srb->cmnd[6]; - len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8]; - program_mode = srb->cmnd[9]; - - retval = spi_set_init_para(chip); - if (retval != STATUS_SUCCESS) { - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - if (program_mode == BYTE_PROGRAM) { - buf = kmalloc(4, GFP_KERNEL); - if (!buf) - return STATUS_ERROR; - - while (len) { - retval = sf_enable_write(chip, SPI_WREN); - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - - rtsx_stor_access_xfer_buf(buf, 1, srb, &index, &offset, - FROM_XFER_BUF); - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF, - buf[0]); - sf_program(chip, ins, 1, addr, 1); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) { - kfree(buf); - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - retval = sf_polling_status(chip, 100); - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - - addr++; - len--; - } - - kfree(buf); - - } else if (program_mode == AAI_PROGRAM) { - int first_byte = 1; - - retval = sf_enable_write(chip, SPI_WREN); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - buf = kmalloc(4, GFP_KERNEL); - if (!buf) - return STATUS_ERROR; - - while (len) { - rtsx_stor_access_xfer_buf(buf, 1, srb, &index, &offset, - FROM_XFER_BUF); - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF, - buf[0]); - if (first_byte) { - sf_program(chip, ins, 1, addr, 1); - first_byte = 0; - } else { - sf_program(chip, ins, 0, 0, 1); - } - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval < 0) { - kfree(buf); - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - retval = sf_polling_status(chip, 100); - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - - len--; - } - - kfree(buf); - - retval = sf_disable_write(chip, SPI_WRDI); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = sf_polling_status(chip, 100); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else if (program_mode == PAGE_PROGRAM) { - buf = kmalloc(SF_PAGE_LEN, GFP_KERNEL); - if (!buf) - return STATUS_NOMEM; - - while (len) { - u16 pagelen = SF_PAGE_LEN - (u8)addr; - - if (pagelen > len) - pagelen = len; - - retval = sf_enable_write(chip, SPI_WREN); - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - - rtsx_init_cmd(chip); - - trans_dma_enable(DMA_TO_DEVICE, chip, 256, DMA_256); - sf_program(chip, ins, 1, addr, pagelen); - - rtsx_send_cmd_no_wait(chip); - - rtsx_stor_access_xfer_buf(buf, pagelen, srb, &index, - &offset, FROM_XFER_BUF); - - retval = rtsx_transfer_data(chip, 0, buf, pagelen, 0, - DMA_TO_DEVICE, 100); - if (retval < 0) { - kfree(buf); - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - retval = sf_polling_status(chip, 100); - if (retval != STATUS_SUCCESS) { - kfree(buf); - return STATUS_FAIL; - } - - addr += pagelen; - len -= pagelen; - } - - kfree(buf); - } else { - spi_set_err_code(chip, SPI_INVALID_COMMAND); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -int spi_erase_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - u8 ins, erase_mode; - u32 addr; - - spi_set_err_code(chip, SPI_NO_ERR); - - ins = srb->cmnd[3]; - addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5]) - << 8) | srb->cmnd[6]; - erase_mode = srb->cmnd[9]; - - retval = spi_set_init_para(chip); - if (retval != STATUS_SUCCESS) { - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - if (erase_mode == PAGE_ERASE) { - retval = sf_enable_write(chip, SPI_WREN); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = sf_erase(chip, ins, 1, addr); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else if (erase_mode == CHIP_ERASE) { - retval = sf_enable_write(chip, SPI_WREN); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = sf_erase(chip, ins, 0, 0); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - spi_set_err_code(chip, SPI_INVALID_COMMAND); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -int spi_write_flash_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) -{ - int retval; - u8 ins, status, ewsr; - - ins = srb->cmnd[3]; - status = srb->cmnd[4]; - ewsr = srb->cmnd[5]; - - retval = spi_set_init_para(chip); - if (retval != STATUS_SUCCESS) { - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - retval = sf_enable_write(chip, ewsr); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, - PINGPONG_BUFFER); - - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, - SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF, status); - rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF, - SPI_TRANSFER0_START | SPI_CDO_MODE0); - rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END, - SPI_TRANSFER0_END); - - retval = rtsx_send_cmd(chip, 0, 100); - if (retval != STATUS_SUCCESS) { - rtsx_clear_spi_error(chip); - spi_set_err_code(chip, SPI_HW_ERR); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} diff --git a/drivers/staging/rts5208/spi.h b/drivers/staging/rts5208/spi.h deleted file mode 100644 index dcf93c80b2d50a..00000000000000 --- a/drivers/staging/rts5208/spi.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_SPI_H -#define __REALTEK_RTSX_SPI_H - -/* SPI operation error */ -#define SPI_NO_ERR 0x00 -#define SPI_HW_ERR 0x01 -#define SPI_INVALID_COMMAND 0x02 -#define SPI_READ_ERR 0x03 -#define SPI_WRITE_ERR 0x04 -#define SPI_ERASE_ERR 0x05 -#define SPI_BUSY_ERR 0x06 - -/* Serial flash instruction */ -#define SPI_READ 0x03 -#define SPI_FAST_READ 0x0B -#define SPI_WREN 0x06 -#define SPI_WRDI 0x04 -#define SPI_RDSR 0x05 - -#define SF_PAGE_LEN 256 - -#define BYTE_PROGRAM 0 -#define AAI_PROGRAM 1 -#define PAGE_PROGRAM 2 - -#define PAGE_ERASE 0 -#define CHIP_ERASE 1 - -int spi_erase_eeprom_chip(struct rtsx_chip *chip); -int spi_erase_eeprom_byte(struct rtsx_chip *chip, u16 addr); -int spi_read_eeprom(struct rtsx_chip *chip, u16 addr, u8 *val); -int spi_write_eeprom(struct rtsx_chip *chip, u16 addr, u8 val); -int spi_get_status(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int spi_set_parameter(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int spi_read_flash_id(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int spi_read_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int spi_erase_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip); -int spi_write_flash_status(struct scsi_cmnd *srb, struct rtsx_chip *chip); - -#endif /* __REALTEK_RTSX_SPI_H */ diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c deleted file mode 100644 index c0af378ada7162..00000000000000 --- a/drivers/staging/rts5208/xd.c +++ /dev/null @@ -1,2145 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#include -#include -#include -#include - -#include "rtsx.h" -#include "rtsx_transport.h" -#include "rtsx_scsi.h" -#include "rtsx_card.h" -#include "xd.h" - -static int xd_build_l2p_tbl(struct rtsx_chip *chip, int zone_no); -static int xd_init_page(struct rtsx_chip *chip, u32 phy_blk, u16 logoff, - u8 start_page, u8 end_page); - -static inline void xd_set_err_code(struct rtsx_chip *chip, u8 err_code) -{ - struct xd_info *xd_card = &chip->xd_card; - - xd_card->err_code = err_code; -} - -static int xd_set_init_para(struct rtsx_chip *chip) -{ - struct xd_info *xd_card = &chip->xd_card; - int retval; - - if (chip->asic_code) - xd_card->xd_clock = 47; - else - xd_card->xd_clock = CLK_50; - - retval = switch_clock(chip, xd_card->xd_clock); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int xd_switch_clock(struct rtsx_chip *chip) -{ - struct xd_info *xd_card = &chip->xd_card; - int retval; - - retval = select_card(chip, XD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = switch_clock(chip, xd_card->xd_clock); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int xd_read_id(struct rtsx_chip *chip, u8 id_cmd, u8 *id_buf, u8 buf_len) -{ - int retval, i; - u8 *ptr; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_DAT, 0xFF, id_cmd); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_READ_ID); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END, - XD_TRANSFER_END); - - for (i = 0; i < 4; i++) - rtsx_add_cmd(chip, READ_REG_CMD, (u16)(XD_ADDRESS1 + i), 0, 0); - - retval = rtsx_send_cmd(chip, XD_CARD, 20); - if (retval < 0) - return STATUS_FAIL; - - ptr = rtsx_get_cmd_data(chip) + 1; - if (id_buf && buf_len) { - if (buf_len > 4) - buf_len = 4; - memcpy(id_buf, ptr, buf_len); - } - - return STATUS_SUCCESS; -} - -static void xd_assign_phy_addr(struct rtsx_chip *chip, u32 addr, u8 mode) -{ - struct xd_info *xd_card = &chip->xd_card; - - switch (mode) { - case XD_RW_ADDR: - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS0, 0xFF, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS1, 0xFF, (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS2, - 0xFF, (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS3, - 0xFF, (u8)(addr >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CFG, 0xFF, - xd_card->addr_cycle | - XD_CALC_ECC | - XD_BA_NO_TRANSFORM); - break; - - case XD_ERASE_ADDR: - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS0, 0xFF, (u8)addr); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS1, - 0xFF, (u8)(addr >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS2, - 0xFF, (u8)(addr >> 16)); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CFG, 0xFF, - (xd_card->addr_cycle - 1) | XD_CALC_ECC | - XD_BA_NO_TRANSFORM); - break; - - default: - break; - } -} - -static int xd_read_redundant(struct rtsx_chip *chip, u32 page_addr, - u8 *buf, int buf_len) -{ - int retval, i; - - rtsx_init_cmd(chip); - - xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, - 0xFF, XD_TRANSFER_START | XD_READ_REDUNDANT); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - - for (i = 0; i < 6; i++) - rtsx_add_cmd(chip, READ_REG_CMD, (u16)(XD_PAGE_STATUS + i), - 0, 0); - for (i = 0; i < 4; i++) - rtsx_add_cmd(chip, READ_REG_CMD, (u16)(XD_RESERVED0 + i), - 0, 0); - rtsx_add_cmd(chip, READ_REG_CMD, XD_PARITY, 0, 0); - - retval = rtsx_send_cmd(chip, XD_CARD, 500); - if (retval < 0) - return STATUS_FAIL; - - if (buf && buf_len) { - u8 *ptr = rtsx_get_cmd_data(chip) + 1; - - if (buf_len > 11) - buf_len = 11; - memcpy(buf, ptr, buf_len); - } - - return STATUS_SUCCESS; -} - -static int xd_read_data_from_ppb(struct rtsx_chip *chip, int offset, - u8 *buf, int buf_len) -{ - int retval, i; - - if (!buf || buf_len < 0) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - for (i = 0; i < buf_len; i++) - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + offset + i, - 0, 0); - - retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) { - rtsx_clear_xd_error(chip); - return STATUS_FAIL; - } - - memcpy(buf, rtsx_get_cmd_data(chip), buf_len); - - return STATUS_SUCCESS; -} - -static int xd_read_cis(struct rtsx_chip *chip, u32 page_addr, u8 *buf, - int buf_len) -{ - int retval; - u8 reg; - - if (!buf || buf_len < 10) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, - 0x01, PINGPONG_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS, - XD_AUTO_CHK_DATA_STATUS, XD_AUTO_CHK_DATA_STATUS); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_READ_PAGES); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END, - XD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, XD_CARD, 250); - if (retval == -ETIMEDOUT) { - rtsx_clear_xd_error(chip); - return STATUS_FAIL; - } - - retval = rtsx_read_register(chip, XD_PAGE_STATUS, ®); - if (retval) - return retval; - if (reg != XD_GPG) { - rtsx_clear_xd_error(chip); - return STATUS_FAIL; - } - - retval = rtsx_read_register(chip, XD_CTL, ®); - if (retval) - return retval; - if (!(reg & XD_ECC1_ERROR) || !(reg & XD_ECC1_UNCORRECTABLE)) { - retval = xd_read_data_from_ppb(chip, 0, buf, buf_len); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - if (reg & XD_ECC1_ERROR) { - u8 ecc_bit, ecc_byte; - - retval = rtsx_read_register(chip, XD_ECC_BIT1, - &ecc_bit); - if (retval) - return retval; - retval = rtsx_read_register(chip, XD_ECC_BYTE1, - &ecc_byte); - if (retval) - return retval; - - dev_dbg(rtsx_dev(chip), "ECC_BIT1 = 0x%x, ECC_BYTE1 = 0x%x\n", - ecc_bit, ecc_byte); - if (ecc_byte < buf_len) { - dev_dbg(rtsx_dev(chip), "Before correct: 0x%x\n", - buf[ecc_byte]); - buf[ecc_byte] ^= (1 << ecc_bit); - dev_dbg(rtsx_dev(chip), "After correct: 0x%x\n", - buf[ecc_byte]); - } - } - } else if (!(reg & XD_ECC2_ERROR) || !(reg & XD_ECC2_UNCORRECTABLE)) { - rtsx_clear_xd_error(chip); - - retval = xd_read_data_from_ppb(chip, 256, buf, buf_len); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - if (reg & XD_ECC2_ERROR) { - u8 ecc_bit, ecc_byte; - - retval = rtsx_read_register(chip, XD_ECC_BIT2, - &ecc_bit); - if (retval) - return retval; - retval = rtsx_read_register(chip, XD_ECC_BYTE2, - &ecc_byte); - if (retval) - return retval; - - dev_dbg(rtsx_dev(chip), "ECC_BIT2 = 0x%x, ECC_BYTE2 = 0x%x\n", - ecc_bit, ecc_byte); - if (ecc_byte < buf_len) { - dev_dbg(rtsx_dev(chip), "Before correct: 0x%x\n", - buf[ecc_byte]); - buf[ecc_byte] ^= (1 << ecc_bit); - dev_dbg(rtsx_dev(chip), "After correct: 0x%x\n", - buf[ecc_byte]); - } - } - } else { - rtsx_clear_xd_error(chip); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static void xd_fill_pull_ctl_disable(struct rtsx_chip *chip) -{ - if (CHECK_PID(chip, 0x5208)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, - XD_D3_PD | XD_D2_PD | XD_D1_PD | XD_D0_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, - XD_D7_PD | XD_D6_PD | XD_D5_PD | XD_D4_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, - XD_WP_PD | XD_CE_PD | XD_CLE_PD | XD_CD_PU); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, - XD_RDY_PD | XD_WE_PD | XD_RE_PD | XD_ALE_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, - MS_INS_PU | SD_WP_PD | SD_CD_PU | SD_CMD_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, - MS_D5_PD | MS_D4_PD); - } else if (CHECK_PID(chip, 0x5288)) { - if (CHECK_BARO_PKG(chip, QFN)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, - 0xFF, 0x55); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, - 0xFF, 0x55); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, - 0xFF, 0x4B); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, - 0xFF, 0x69); - } - } -} - -static void xd_fill_pull_ctl_stage1_barossa(struct rtsx_chip *chip) -{ - if (CHECK_BARO_PKG(chip, QFN)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x4B); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); - } -} - -static void xd_fill_pull_ctl_enable(struct rtsx_chip *chip) -{ - if (CHECK_PID(chip, 0x5208)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, - XD_D3_PD | XD_D2_PD | XD_D1_PD | XD_D0_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, - XD_D7_PD | XD_D6_PD | XD_D5_PD | XD_D4_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, - XD_WP_PD | XD_CE_PU | XD_CLE_PD | XD_CD_PU); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, - XD_RDY_PU | XD_WE_PU | XD_RE_PU | XD_ALE_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, - MS_INS_PU | SD_WP_PD | SD_CD_PU | SD_CMD_PD); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, - MS_D5_PD | MS_D4_PD); - } else if (CHECK_PID(chip, 0x5288)) { - if (CHECK_BARO_PKG(chip, QFN)) { - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, - 0xFF, 0x55); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, - 0xFF, 0x55); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, - 0xFF, 0x53); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, - 0xFF, 0xA9); - } - } -} - -static int xd_pull_ctl_disable(struct rtsx_chip *chip) -{ - int retval; - - if (CHECK_PID(chip, 0x5208)) { - retval = rtsx_write_register(chip, CARD_PULL_CTL1, 0xFF, - XD_D3_PD | - XD_D2_PD | - XD_D1_PD | - XD_D0_PD); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF, - XD_D7_PD | - XD_D6_PD | - XD_D5_PD | - XD_D4_PD); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF, - XD_WP_PD | - XD_CE_PD | - XD_CLE_PD | - XD_CD_PU); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF, - XD_RDY_PD | - XD_WE_PD | - XD_RE_PD | - XD_ALE_PD); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF, - MS_INS_PU | - SD_WP_PD | - SD_CD_PU | - SD_CMD_PD); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF, - MS_D5_PD | MS_D4_PD); - if (retval) - return retval; - } else if (CHECK_PID(chip, 0x5288)) { - if (CHECK_BARO_PKG(chip, QFN)) { - retval = rtsx_write_register(chip, CARD_PULL_CTL1, - 0xFF, 0x55); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL2, - 0xFF, 0x55); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL3, - 0xFF, 0x4B); - if (retval) - return retval; - retval = rtsx_write_register(chip, CARD_PULL_CTL4, - 0xFF, 0x69); - if (retval) - return retval; - } - } - - return STATUS_SUCCESS; -} - -static int reset_xd(struct rtsx_chip *chip) -{ - struct xd_info *xd_card = &chip->xd_card; - int retval, i, j; - u8 *ptr, id_buf[4], redunt[11]; - - retval = select_card(chip, XD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS, 0xFF, - XD_PGSTS_NOT_FF); - if (chip->asic_code) { - if (!CHECK_PID(chip, 0x5288)) - xd_fill_pull_ctl_disable(chip); - else - xd_fill_pull_ctl_stage1_barossa(chip); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL, 0xFF, - (FPGA_XD_PULL_CTL_EN1 & FPGA_XD_PULL_CTL_EN3) | - 0x20); - } - - if (!chip->ft2_fast_mode) - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_INIT, - XD_NO_AUTO_PWR_OFF, 0); - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_OE, XD_OUTPUT_EN, 0); - - retval = rtsx_send_cmd(chip, XD_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - if (!chip->ft2_fast_mode) { - retval = card_power_off(chip, XD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - wait_timeout(250); - - rtsx_init_cmd(chip); - - if (chip->asic_code) { - xd_fill_pull_ctl_enable(chip); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL, 0xFF, - (FPGA_XD_PULL_CTL_EN1 & - FPGA_XD_PULL_CTL_EN2) | - 0x20); - } - - retval = rtsx_send_cmd(chip, XD_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - retval = card_power_on(chip, XD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - -#ifdef SUPPORT_OCP - wait_timeout(50); - if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) { - dev_dbg(rtsx_dev(chip), "Over current, OCPSTAT is 0x%x\n", - chip->ocp_stat); - return STATUS_FAIL; - } -#endif - } - - rtsx_init_cmd(chip); - - if (chip->ft2_fast_mode) { - if (chip->asic_code) { - xd_fill_pull_ctl_enable(chip); - } else { - rtsx_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL, 0xFF, - (FPGA_XD_PULL_CTL_EN1 & - FPGA_XD_PULL_CTL_EN2) | - 0x20); - } - } - - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_OE, XD_OUTPUT_EN, XD_OUTPUT_EN); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CTL, XD_CE_DISEN, XD_CE_DISEN); - - retval = rtsx_send_cmd(chip, XD_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - if (!chip->ft2_fast_mode) - wait_timeout(200); - - retval = xd_set_init_para(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - /* Read ID to check if the timing setting is right */ - for (i = 0; i < 4; i++) { - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_DTCTL, 0xFF, - XD_TIME_SETUP_STEP * 3 + - XD_TIME_RW_STEP * (2 + i) + XD_TIME_RWN_STEP * i); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CATCTL, 0xFF, - XD_TIME_SETUP_STEP * 3 + - XD_TIME_RW_STEP * (4 + i) + - XD_TIME_RWN_STEP * (3 + i)); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_RESET); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - - rtsx_add_cmd(chip, READ_REG_CMD, XD_DAT, 0, 0); - rtsx_add_cmd(chip, READ_REG_CMD, XD_CTL, 0, 0); - - retval = rtsx_send_cmd(chip, XD_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - ptr = rtsx_get_cmd_data(chip) + 1; - - dev_dbg(rtsx_dev(chip), "XD_DAT: 0x%x, XD_CTL: 0x%x\n", - ptr[0], ptr[1]); - - if (((ptr[0] & READY_FLAG) != READY_STATE) || - !(ptr[1] & XD_RDY)) - continue; - - retval = xd_read_id(chip, READ_ID, id_buf, 4); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - dev_dbg(rtsx_dev(chip), "READ_ID: 0x%x 0x%x 0x%x 0x%x\n", - id_buf[0], id_buf[1], id_buf[2], id_buf[3]); - - xd_card->device_code = id_buf[1]; - - /* Check if the xD card is supported */ - switch (xd_card->device_code) { - case XD_4M_X8_512_1: - case XD_4M_X8_512_2: - xd_card->block_shift = 4; - xd_card->page_off = 0x0F; - xd_card->addr_cycle = 3; - xd_card->zone_cnt = 1; - xd_card->capacity = 8000; - XD_SET_4MB(xd_card); - break; - case XD_8M_X8_512: - xd_card->block_shift = 4; - xd_card->page_off = 0x0F; - xd_card->addr_cycle = 3; - xd_card->zone_cnt = 1; - xd_card->capacity = 16000; - break; - case XD_16M_X8_512: - XD_PAGE_512(xd_card); - xd_card->addr_cycle = 3; - xd_card->zone_cnt = 1; - xd_card->capacity = 32000; - break; - case XD_32M_X8_512: - XD_PAGE_512(xd_card); - xd_card->addr_cycle = 3; - xd_card->zone_cnt = 2; - xd_card->capacity = 64000; - break; - case XD_64M_X8_512: - XD_PAGE_512(xd_card); - xd_card->addr_cycle = 4; - xd_card->zone_cnt = 4; - xd_card->capacity = 128000; - break; - case XD_128M_X8_512: - XD_PAGE_512(xd_card); - xd_card->addr_cycle = 4; - xd_card->zone_cnt = 8; - xd_card->capacity = 256000; - break; - case XD_256M_X8_512: - XD_PAGE_512(xd_card); - xd_card->addr_cycle = 4; - xd_card->zone_cnt = 16; - xd_card->capacity = 512000; - break; - case XD_512M_X8: - XD_PAGE_512(xd_card); - xd_card->addr_cycle = 4; - xd_card->zone_cnt = 32; - xd_card->capacity = 1024000; - break; - case XD_1G_X8_512: - XD_PAGE_512(xd_card); - xd_card->addr_cycle = 4; - xd_card->zone_cnt = 64; - xd_card->capacity = 2048000; - break; - case XD_2G_X8_512: - XD_PAGE_512(xd_card); - xd_card->addr_cycle = 4; - xd_card->zone_cnt = 128; - xd_card->capacity = 4096000; - break; - default: - continue; - } - - /* Confirm timing setting */ - for (j = 0; j < 10; j++) { - retval = xd_read_id(chip, READ_ID, id_buf, 4); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (id_buf[1] != xd_card->device_code) - break; - } - - if (j == 10) - break; - } - - if (i == 4) { - xd_card->block_shift = 0; - xd_card->page_off = 0; - xd_card->addr_cycle = 0; - xd_card->capacity = 0; - - return STATUS_FAIL; - } - - retval = xd_read_id(chip, READ_XD_ID, id_buf, 4); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - dev_dbg(rtsx_dev(chip), "READ_XD_ID: 0x%x 0x%x 0x%x 0x%x\n", - id_buf[0], id_buf[1], id_buf[2], id_buf[3]); - if (id_buf[2] != XD_ID_CODE) - return STATUS_FAIL; - - /* Search CIS block */ - for (i = 0; i < 24; i++) { - u32 page_addr; - - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) - return STATUS_FAIL; - - page_addr = (u32)i << xd_card->block_shift; - - for (j = 0; j < 3; j++) { - retval = xd_read_redundant(chip, page_addr, redunt, 11); - if (retval == STATUS_SUCCESS) - break; - } - if (j == 3) - continue; - - if (redunt[BLOCK_STATUS] != XD_GBLK) - continue; - - j = 0; - if (redunt[PAGE_STATUS] != XD_GPG) { - for (j = 1; j <= 8; j++) { - retval = xd_read_redundant(chip, page_addr + j, - redunt, 11); - if (retval == STATUS_SUCCESS) { - if (redunt[PAGE_STATUS] == XD_GPG) - break; - } - } - - if (j == 9) - break; - } - - /* Check CIS data */ - if (redunt[BLOCK_STATUS] == XD_GBLK && - (redunt[PARITY] & XD_BA1_ALL0)) { - u8 buf[10]; - - page_addr += j; - - retval = xd_read_cis(chip, page_addr, buf, 10); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (buf[0] == 0x01 && buf[1] == 0x03 && - buf[2] == 0xD9 && - buf[3] == 0x01 && buf[4] == 0xFF && - buf[5] == 0x18 && buf[6] == 0x02 && - buf[7] == 0xDF && buf[8] == 0x01 && - buf[9] == 0x20) { - xd_card->cis_block = (u16)i; - } - } - - break; - } - - dev_dbg(rtsx_dev(chip), "CIS block: 0x%x\n", xd_card->cis_block); - if (xd_card->cis_block == 0xFFFF) - return STATUS_FAIL; - - chip->capacity[chip->card2lun[XD_CARD]] = xd_card->capacity; - - return STATUS_SUCCESS; -} - -static int xd_check_data_blank(u8 *redunt) -{ - int i; - - for (i = 0; i < 6; i++) { - if (redunt[PAGE_STATUS + i] != 0xFF) - return 0; - } - - if ((redunt[PARITY] & (XD_ECC1_ALL1 | XD_ECC2_ALL1)) - != (XD_ECC1_ALL1 | XD_ECC2_ALL1)) - return 0; - - for (i = 0; i < 4; i++) { - if (redunt[RESERVED0 + i] != 0xFF) - return 0; - } - - return 1; -} - -static u16 xd_load_log_block_addr(u8 *redunt) -{ - u16 addr = 0xFFFF; - - if (redunt[PARITY] & XD_BA1_BA2_EQL) - addr = ((u16)redunt[BLOCK_ADDR1_H] << 8) | - redunt[BLOCK_ADDR1_L]; - else if (redunt[PARITY] & XD_BA1_VALID) - addr = ((u16)redunt[BLOCK_ADDR1_H] << 8) | - redunt[BLOCK_ADDR1_L]; - else if (redunt[PARITY] & XD_BA2_VALID) - addr = ((u16)redunt[BLOCK_ADDR2_H] << 8) | - redunt[BLOCK_ADDR2_L]; - - return addr; -} - -static int xd_init_l2p_tbl(struct rtsx_chip *chip) -{ - struct xd_info *xd_card = &chip->xd_card; - int size, i; - - dev_dbg(rtsx_dev(chip), "%s: zone_cnt = %d\n", __func__, - xd_card->zone_cnt); - - if (xd_card->zone_cnt < 1) - return STATUS_FAIL; - - size = xd_card->zone_cnt * sizeof(struct zone_entry); - dev_dbg(rtsx_dev(chip), "Buffer size for l2p table is %d\n", size); - - xd_card->zone = vmalloc(size); - if (!xd_card->zone) - return STATUS_ERROR; - - for (i = 0; i < xd_card->zone_cnt; i++) { - xd_card->zone[i].build_flag = 0; - xd_card->zone[i].l2p_table = NULL; - xd_card->zone[i].free_table = NULL; - xd_card->zone[i].get_index = 0; - xd_card->zone[i].set_index = 0; - xd_card->zone[i].unused_blk_cnt = 0; - } - - return STATUS_SUCCESS; -} - -static inline void free_zone(struct zone_entry *zone) -{ - if (!zone) - return; - - zone->build_flag = 0; - zone->set_index = 0; - zone->get_index = 0; - zone->unused_blk_cnt = 0; - vfree(zone->l2p_table); - zone->l2p_table = NULL; - vfree(zone->free_table); - zone->free_table = NULL; -} - -static void xd_set_unused_block(struct rtsx_chip *chip, u32 phy_blk) -{ - struct xd_info *xd_card = &chip->xd_card; - struct zone_entry *zone; - int zone_no; - - zone_no = (int)phy_blk >> 10; - if (zone_no >= xd_card->zone_cnt) { - dev_dbg(rtsx_dev(chip), "Set unused block to invalid zone (zone_no = %d, zone_cnt = %d)\n", - zone_no, xd_card->zone_cnt); - return; - } - zone = &xd_card->zone[zone_no]; - - if (!zone->free_table) { - if (xd_build_l2p_tbl(chip, zone_no) != STATUS_SUCCESS) - return; - } - - if (zone->set_index >= XD_FREE_TABLE_CNT || - zone->set_index < 0) { - free_zone(zone); - dev_dbg(rtsx_dev(chip), "Set unused block fail, invalid set_index\n"); - return; - } - - dev_dbg(rtsx_dev(chip), "Set unused block to index %d\n", - zone->set_index); - - zone->free_table[zone->set_index++] = (u16)(phy_blk & 0x3ff); - if (zone->set_index >= XD_FREE_TABLE_CNT) - zone->set_index = 0; - zone->unused_blk_cnt++; -} - -static u32 xd_get_unused_block(struct rtsx_chip *chip, int zone_no) -{ - struct xd_info *xd_card = &chip->xd_card; - struct zone_entry *zone; - u32 phy_blk; - - if (zone_no >= xd_card->zone_cnt) { - dev_dbg(rtsx_dev(chip), "Get unused block from invalid zone (zone_no = %d, zone_cnt = %d)\n", - zone_no, xd_card->zone_cnt); - return BLK_NOT_FOUND; - } - zone = &xd_card->zone[zone_no]; - - if (zone->unused_blk_cnt == 0 || - zone->set_index == zone->get_index) { - free_zone(zone); - dev_dbg(rtsx_dev(chip), "Get unused block fail, no unused block available\n"); - return BLK_NOT_FOUND; - } - if (zone->get_index >= XD_FREE_TABLE_CNT || zone->get_index < 0) { - free_zone(zone); - dev_dbg(rtsx_dev(chip), "Get unused block fail, invalid get_index\n"); - return BLK_NOT_FOUND; - } - - dev_dbg(rtsx_dev(chip), "Get unused block from index %d\n", - zone->get_index); - - phy_blk = zone->free_table[zone->get_index]; - zone->free_table[zone->get_index++] = 0xFFFF; - if (zone->get_index >= XD_FREE_TABLE_CNT) - zone->get_index = 0; - zone->unused_blk_cnt--; - - phy_blk += ((u32)(zone_no) << 10); - return phy_blk; -} - -static void xd_set_l2p_tbl(struct rtsx_chip *chip, - int zone_no, u16 log_off, u16 phy_off) -{ - struct xd_info *xd_card = &chip->xd_card; - struct zone_entry *zone; - - zone = &xd_card->zone[zone_no]; - zone->l2p_table[log_off] = phy_off; -} - -static u32 xd_get_l2p_tbl(struct rtsx_chip *chip, int zone_no, u16 log_off) -{ - struct xd_info *xd_card = &chip->xd_card; - struct zone_entry *zone; - int retval; - - zone = &xd_card->zone[zone_no]; - if (zone->l2p_table[log_off] == 0xFFFF) { - u32 phy_blk = 0; - int i; - -#ifdef XD_DELAY_WRITE - retval = xd_delay_write(chip); - if (retval != STATUS_SUCCESS) { - dev_dbg(rtsx_dev(chip), "In %s, delay write fail!\n", - __func__); - return BLK_NOT_FOUND; - } -#endif - - if (zone->unused_blk_cnt <= 0) { - dev_dbg(rtsx_dev(chip), "No unused block!\n"); - return BLK_NOT_FOUND; - } - - for (i = 0; i < zone->unused_blk_cnt; i++) { - phy_blk = xd_get_unused_block(chip, zone_no); - if (phy_blk == BLK_NOT_FOUND) { - dev_dbg(rtsx_dev(chip), "No unused block available!\n"); - return BLK_NOT_FOUND; - } - - retval = xd_init_page(chip, phy_blk, log_off, - 0, xd_card->page_off + 1); - if (retval == STATUS_SUCCESS) - break; - } - if (i >= zone->unused_blk_cnt) { - dev_dbg(rtsx_dev(chip), "No good unused block available!\n"); - return BLK_NOT_FOUND; - } - - xd_set_l2p_tbl(chip, zone_no, log_off, (u16)(phy_blk & 0x3FF)); - return phy_blk; - } - - return (u32)zone->l2p_table[log_off] + ((u32)(zone_no) << 10); -} - -int reset_xd_card(struct rtsx_chip *chip) -{ - struct xd_info *xd_card = &chip->xd_card; - int retval; - - memset(xd_card, 0, sizeof(struct xd_info)); - - xd_card->block_shift = 0; - xd_card->page_off = 0; - xd_card->addr_cycle = 0; - xd_card->capacity = 0; - xd_card->zone_cnt = 0; - xd_card->cis_block = 0xFFFF; - xd_card->delay_write.delay_write_flag = 0; - - retval = enable_card_clock(chip, XD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = reset_xd(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = xd_init_l2p_tbl(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int xd_mark_bad_block(struct rtsx_chip *chip, u32 phy_blk) -{ - struct xd_info *xd_card = &chip->xd_card; - int retval; - u32 page_addr; - u8 reg = 0; - - dev_dbg(rtsx_dev(chip), "mark block 0x%x as bad block\n", phy_blk); - - if (phy_blk == BLK_NOT_FOUND) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_STATUS, 0xFF, XD_GPG); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_STATUS, 0xFF, XD_LATER_BBLK); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_H, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_L, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR2_H, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR2_L, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_RESERVED0, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_RESERVED1, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_RESERVED2, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_RESERVED3, 0xFF, 0xFF); - - page_addr = phy_blk << xd_card->block_shift; - - xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, - xd_card->page_off + 1); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_WRITE_REDUNDANT); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, XD_CARD, 500); - if (retval < 0) { - rtsx_clear_xd_error(chip); - rtsx_read_register(chip, XD_DAT, ®); - if (reg & PROGRAM_ERROR) - xd_set_err_code(chip, XD_PRG_ERROR); - else - xd_set_err_code(chip, XD_TO_ERROR); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int xd_init_page(struct rtsx_chip *chip, u32 phy_blk, - u16 logoff, u8 start_page, u8 end_page) -{ - struct xd_info *xd_card = &chip->xd_card; - int retval; - u32 page_addr; - u8 reg = 0; - - dev_dbg(rtsx_dev(chip), "Init block 0x%x\n", phy_blk); - - if (start_page > end_page) - return STATUS_FAIL; - if (phy_blk == BLK_NOT_FOUND) - return STATUS_FAIL; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_STATUS, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_STATUS, 0xFF, 0xFF); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_H, - 0xFF, (u8)(logoff >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_L, 0xFF, (u8)logoff); - - page_addr = (phy_blk << xd_card->block_shift) + start_page; - - xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CFG, - XD_BA_TRANSFORM, XD_BA_TRANSFORM); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, - 0xFF, (end_page - start_page)); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, - 0xFF, XD_TRANSFER_START | XD_WRITE_REDUNDANT); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, XD_CARD, 500); - if (retval < 0) { - rtsx_clear_xd_error(chip); - rtsx_read_register(chip, XD_DAT, ®); - if (reg & PROGRAM_ERROR) { - xd_mark_bad_block(chip, phy_blk); - xd_set_err_code(chip, XD_PRG_ERROR); - } else { - xd_set_err_code(chip, XD_TO_ERROR); - } - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int xd_copy_page(struct rtsx_chip *chip, u32 old_blk, u32 new_blk, - u8 start_page, u8 end_page) -{ - struct xd_info *xd_card = &chip->xd_card; - u32 old_page, new_page; - u8 i, reg = 0; - int retval; - - dev_dbg(rtsx_dev(chip), "Copy page from block 0x%x to block 0x%x\n", - old_blk, new_blk); - - if (start_page > end_page) - return STATUS_FAIL; - - if (old_blk == BLK_NOT_FOUND || new_blk == BLK_NOT_FOUND) - return STATUS_FAIL; - - old_page = (old_blk << xd_card->block_shift) + start_page; - new_page = (new_blk << xd_card->block_shift) + start_page; - - XD_CLR_BAD_NEWBLK(xd_card); - - retval = rtsx_write_register(chip, CARD_DATA_SOURCE, 0x01, - PINGPONG_BUFFER); - if (retval) - return retval; - - for (i = start_page; i < end_page; i++) { - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { - rtsx_clear_xd_error(chip); - xd_set_err_code(chip, XD_NO_CARD); - return STATUS_FAIL; - } - - rtsx_init_cmd(chip); - - xd_assign_phy_addr(chip, old_page, XD_RW_ADDR); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS, - XD_AUTO_CHK_DATA_STATUS, 0); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_READ_PAGES); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, XD_CARD, 500); - if (retval < 0) { - rtsx_clear_xd_error(chip); - reg = 0; - rtsx_read_register(chip, XD_CTL, ®); - if (reg & (XD_ECC1_ERROR | XD_ECC2_ERROR)) { - mdelay(100); - - if (detect_card_cd(chip, - XD_CARD) != STATUS_SUCCESS) { - xd_set_err_code(chip, XD_NO_CARD); - return STATUS_FAIL; - } - - if (((reg & XD_ECC1_ERROR) && - (reg & XD_ECC1_UNCORRECTABLE)) || - ((reg & XD_ECC2_ERROR) && - (reg & XD_ECC2_UNCORRECTABLE))) { - rtsx_write_register(chip, - XD_PAGE_STATUS, - 0xFF, - XD_BPG); - rtsx_write_register(chip, - XD_BLOCK_STATUS, - 0xFF, - XD_GBLK); - XD_SET_BAD_OLDBLK(xd_card); - dev_dbg(rtsx_dev(chip), "old block 0x%x ecc error\n", - old_blk); - } - } else { - xd_set_err_code(chip, XD_TO_ERROR); - return STATUS_FAIL; - } - } - - if (XD_CHK_BAD_OLDBLK(xd_card)) - rtsx_clear_xd_error(chip); - - rtsx_init_cmd(chip); - - xd_assign_phy_addr(chip, new_page, XD_RW_ADDR); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, 1); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_WRITE_PAGES); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, XD_CARD, 300); - if (retval < 0) { - rtsx_clear_xd_error(chip); - reg = 0; - rtsx_read_register(chip, XD_DAT, ®); - if (reg & PROGRAM_ERROR) { - xd_mark_bad_block(chip, new_blk); - xd_set_err_code(chip, XD_PRG_ERROR); - XD_SET_BAD_NEWBLK(xd_card); - } else { - xd_set_err_code(chip, XD_TO_ERROR); - } - return STATUS_FAIL; - } - - old_page++; - new_page++; - } - - return STATUS_SUCCESS; -} - -static int xd_reset_cmd(struct rtsx_chip *chip) -{ - int retval; - u8 *ptr; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, - 0xFF, XD_TRANSFER_START | XD_RESET); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - rtsx_add_cmd(chip, READ_REG_CMD, XD_DAT, 0, 0); - rtsx_add_cmd(chip, READ_REG_CMD, XD_CTL, 0, 0); - - retval = rtsx_send_cmd(chip, XD_CARD, 100); - if (retval < 0) - return STATUS_FAIL; - - ptr = rtsx_get_cmd_data(chip) + 1; - if (((ptr[0] & READY_FLAG) == READY_STATE) && (ptr[1] & XD_RDY)) - return STATUS_SUCCESS; - - return STATUS_FAIL; -} - -static int xd_erase_block(struct rtsx_chip *chip, u32 phy_blk) -{ - struct xd_info *xd_card = &chip->xd_card; - u32 page_addr; - u8 reg = 0, *ptr; - int i, retval; - - if (phy_blk == BLK_NOT_FOUND) - return STATUS_FAIL; - - page_addr = phy_blk << xd_card->block_shift; - - for (i = 0; i < 3; i++) { - rtsx_init_cmd(chip); - - xd_assign_phy_addr(chip, page_addr, XD_ERASE_ADDR); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_ERASE); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - rtsx_add_cmd(chip, READ_REG_CMD, XD_DAT, 0, 0); - - retval = rtsx_send_cmd(chip, XD_CARD, 250); - if (retval < 0) { - rtsx_clear_xd_error(chip); - rtsx_read_register(chip, XD_DAT, ®); - if (reg & PROGRAM_ERROR) { - xd_mark_bad_block(chip, phy_blk); - xd_set_err_code(chip, XD_PRG_ERROR); - return STATUS_FAIL; - } - xd_set_err_code(chip, XD_ERASE_FAIL); - retval = xd_reset_cmd(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - continue; - } - - ptr = rtsx_get_cmd_data(chip) + 1; - if (*ptr & PROGRAM_ERROR) { - xd_mark_bad_block(chip, phy_blk); - xd_set_err_code(chip, XD_PRG_ERROR); - return STATUS_FAIL; - } - - return STATUS_SUCCESS; - } - - xd_mark_bad_block(chip, phy_blk); - xd_set_err_code(chip, XD_ERASE_FAIL); - return STATUS_FAIL; -} - -static int xd_build_l2p_tbl(struct rtsx_chip *chip, int zone_no) -{ - struct xd_info *xd_card = &chip->xd_card; - struct zone_entry *zone; - int retval; - u32 start, end, i; - u16 max_logoff, cur_fst_page_logoff; - u16 cur_lst_page_logoff, ent_lst_page_logoff; - u8 redunt[11]; - - dev_dbg(rtsx_dev(chip), "%s: %d\n", __func__, zone_no); - - if (!xd_card->zone) { - retval = xd_init_l2p_tbl(chip); - if (retval != STATUS_SUCCESS) - return retval; - } - - if (xd_card->zone[zone_no].build_flag) { - dev_dbg(rtsx_dev(chip), "l2p table of zone %d has been built\n", - zone_no); - return STATUS_SUCCESS; - } - - zone = &xd_card->zone[zone_no]; - - if (!zone->l2p_table) { - zone->l2p_table = vmalloc(2000); - if (!zone->l2p_table) - goto build_fail; - } - memset((u8 *)(zone->l2p_table), 0xff, 2000); - - if (!zone->free_table) { - zone->free_table = vmalloc(XD_FREE_TABLE_CNT * 2); - if (!zone->free_table) - goto build_fail; - } - memset((u8 *)(zone->free_table), 0xff, XD_FREE_TABLE_CNT * 2); - - if (zone_no == 0) { - if (xd_card->cis_block == 0xFFFF) - start = 0; - else - start = xd_card->cis_block + 1; - if (XD_CHK_4MB(xd_card)) { - end = 0x200; - max_logoff = 499; - } else { - end = 0x400; - max_logoff = 999; - } - } else { - start = (u32)(zone_no) << 10; - end = (u32)(zone_no + 1) << 10; - max_logoff = 999; - } - - dev_dbg(rtsx_dev(chip), "start block 0x%x, end block 0x%x\n", - start, end); - - zone->set_index = 0; - zone->get_index = 0; - zone->unused_blk_cnt = 0; - - for (i = start; i < end; i++) { - u32 page_addr = i << xd_card->block_shift; - u32 phy_block; - - retval = xd_read_redundant(chip, page_addr, redunt, 11); - if (retval != STATUS_SUCCESS) - continue; - - if (redunt[BLOCK_STATUS] != 0xFF) { - dev_dbg(rtsx_dev(chip), "bad block\n"); - continue; - } - - if (xd_check_data_blank(redunt)) { - dev_dbg(rtsx_dev(chip), "blank block\n"); - xd_set_unused_block(chip, i); - continue; - } - - cur_fst_page_logoff = xd_load_log_block_addr(redunt); - if (cur_fst_page_logoff == 0xFFFF || - cur_fst_page_logoff > max_logoff) { - retval = xd_erase_block(chip, i); - if (retval == STATUS_SUCCESS) - xd_set_unused_block(chip, i); - continue; - } - - if (zone_no == 0 && cur_fst_page_logoff == 0 && - redunt[PAGE_STATUS] != XD_GPG) - XD_SET_MBR_FAIL(xd_card); - - if (zone->l2p_table[cur_fst_page_logoff] == 0xFFFF) { - zone->l2p_table[cur_fst_page_logoff] = (u16)(i & 0x3FF); - continue; - } - - phy_block = zone->l2p_table[cur_fst_page_logoff] + - ((u32)((zone_no) << 10)); - - page_addr = ((i + 1) << xd_card->block_shift) - 1; - - retval = xd_read_redundant(chip, page_addr, redunt, 11); - if (retval != STATUS_SUCCESS) - continue; - - cur_lst_page_logoff = xd_load_log_block_addr(redunt); - if (cur_lst_page_logoff == cur_fst_page_logoff) { - int m; - - page_addr = ((phy_block + 1) << - xd_card->block_shift) - 1; - - for (m = 0; m < 3; m++) { - retval = xd_read_redundant(chip, page_addr, - redunt, 11); - if (retval == STATUS_SUCCESS) - break; - } - - if (m == 3) { - zone->l2p_table[cur_fst_page_logoff] = - (u16)(i & 0x3FF); - retval = xd_erase_block(chip, phy_block); - if (retval == STATUS_SUCCESS) - xd_set_unused_block(chip, phy_block); - continue; - } - - ent_lst_page_logoff = xd_load_log_block_addr(redunt); - if (ent_lst_page_logoff != cur_fst_page_logoff) { - zone->l2p_table[cur_fst_page_logoff] = - (u16)(i & 0x3FF); - retval = xd_erase_block(chip, phy_block); - if (retval == STATUS_SUCCESS) - xd_set_unused_block(chip, phy_block); - continue; - } else { - retval = xd_erase_block(chip, i); - if (retval == STATUS_SUCCESS) - xd_set_unused_block(chip, i); - } - } else { - retval = xd_erase_block(chip, i); - if (retval == STATUS_SUCCESS) - xd_set_unused_block(chip, i); - } - } - - if (XD_CHK_4MB(xd_card)) - end = 500; - else - end = 1000; - - i = 0; - for (start = 0; start < end; start++) { - if (zone->l2p_table[start] == 0xFFFF) - i++; - } - - dev_dbg(rtsx_dev(chip), "Block count %d, invalid L2P entry %d\n", - end, i); - dev_dbg(rtsx_dev(chip), "Total unused block: %d\n", - zone->unused_blk_cnt); - - if ((zone->unused_blk_cnt - i) < 1) - chip->card_wp |= XD_CARD; - - zone->build_flag = 1; - - return STATUS_SUCCESS; - -build_fail: - vfree(zone->l2p_table); - zone->l2p_table = NULL; - vfree(zone->free_table); - zone->free_table = NULL; - - return STATUS_FAIL; -} - -static int xd_send_cmd(struct rtsx_chip *chip, u8 cmd) -{ - int retval; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_DAT, 0xFF, cmd); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_SET_CMD); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - - retval = rtsx_send_cmd(chip, XD_CARD, 200); - if (retval < 0) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} - -static int xd_read_multiple_pages(struct rtsx_chip *chip, u32 phy_blk, - u32 log_blk, u8 start_page, u8 end_page, - u8 *buf, unsigned int *index, - unsigned int *offset) -{ - struct xd_info *xd_card = &chip->xd_card; - u32 page_addr, new_blk; - u16 log_off; - u8 reg_val, page_cnt; - int zone_no, retval, i; - - if (start_page > end_page) - goto status_fail; - - page_cnt = end_page - start_page; - zone_no = (int)(log_blk / 1000); - log_off = (u16)(log_blk % 1000); - - if ((phy_blk & 0x3FF) == 0x3FF) { - for (i = 0; i < 256; i++) { - page_addr = ((u32)i) << xd_card->block_shift; - - retval = xd_read_redundant(chip, page_addr, NULL, 0); - if (retval == STATUS_SUCCESS) - break; - - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { - xd_set_err_code(chip, XD_NO_CARD); - goto status_fail; - } - } - } - - page_addr = (phy_blk << xd_card->block_shift) + start_page; - - rtsx_init_cmd(chip); - - xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CFG, XD_PPB_TO_SIE, XD_PPB_TO_SIE); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, page_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS, - XD_AUTO_CHK_DATA_STATUS, XD_AUTO_CHK_DATA_STATUS); - - trans_dma_enable(chip->srb->sc_data_direction, chip, - page_cnt * 512, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF, - XD_TRANSFER_START | XD_READ_PAGES); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END | XD_PPB_EMPTY, - XD_TRANSFER_END | XD_PPB_EMPTY); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data_partial(chip, XD_CARD, buf, page_cnt * 512, - scsi_sg_count(chip->srb), - index, offset, DMA_FROM_DEVICE, - chip->xd_timeout); - if (retval < 0) { - rtsx_clear_xd_error(chip); - - if (retval == -ETIMEDOUT) { - xd_set_err_code(chip, XD_TO_ERROR); - goto status_fail; - } else { - goto fail; - } - } - - return STATUS_SUCCESS; - -fail: - retval = rtsx_read_register(chip, XD_PAGE_STATUS, ®_val); - if (retval) - return retval; - - if (reg_val != XD_GPG) - xd_set_err_code(chip, XD_PRG_ERROR); - - retval = rtsx_read_register(chip, XD_CTL, ®_val); - if (retval) - return retval; - - if (((reg_val & (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE)) == - (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE)) || - ((reg_val & (XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE)) == - (XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE))) { - wait_timeout(100); - - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { - xd_set_err_code(chip, XD_NO_CARD); - goto status_fail; - } - - xd_set_err_code(chip, XD_ECC_ERROR); - - new_blk = xd_get_unused_block(chip, zone_no); - if (new_blk == NO_NEW_BLK) { - XD_CLR_BAD_OLDBLK(xd_card); - goto status_fail; - } - - retval = xd_copy_page(chip, phy_blk, new_blk, 0, - xd_card->page_off + 1); - if (retval != STATUS_SUCCESS) { - if (!XD_CHK_BAD_NEWBLK(xd_card)) { - retval = xd_erase_block(chip, new_blk); - if (retval == STATUS_SUCCESS) - xd_set_unused_block(chip, new_blk); - } else { - XD_CLR_BAD_NEWBLK(xd_card); - } - XD_CLR_BAD_OLDBLK(xd_card); - goto status_fail; - } - xd_set_l2p_tbl(chip, zone_no, log_off, (u16)(new_blk & 0x3FF)); - xd_erase_block(chip, phy_blk); - xd_mark_bad_block(chip, phy_blk); - XD_CLR_BAD_OLDBLK(xd_card); - } - -status_fail: - return STATUS_FAIL; -} - -static int xd_finish_write(struct rtsx_chip *chip, - u32 old_blk, u32 new_blk, u32 log_blk, u8 page_off) -{ - struct xd_info *xd_card = &chip->xd_card; - int retval, zone_no; - u16 log_off; - - dev_dbg(rtsx_dev(chip), "old_blk = 0x%x, ", old_blk); - dev_dbg(rtsx_dev(chip), "new_blk = 0x%x, ", new_blk); - dev_dbg(rtsx_dev(chip), "log_blk = 0x%x\n", log_blk); - - if (page_off > xd_card->page_off) - return STATUS_FAIL; - - zone_no = (int)(log_blk / 1000); - log_off = (u16)(log_blk % 1000); - - if (old_blk == BLK_NOT_FOUND) { - retval = xd_init_page(chip, new_blk, log_off, - page_off, xd_card->page_off + 1); - if (retval != STATUS_SUCCESS) { - retval = xd_erase_block(chip, new_blk); - if (retval == STATUS_SUCCESS) - xd_set_unused_block(chip, new_blk); - return STATUS_FAIL; - } - } else { - retval = xd_copy_page(chip, old_blk, new_blk, - page_off, xd_card->page_off + 1); - if (retval != STATUS_SUCCESS) { - if (!XD_CHK_BAD_NEWBLK(xd_card)) { - retval = xd_erase_block(chip, new_blk); - if (retval == STATUS_SUCCESS) - xd_set_unused_block(chip, new_blk); - } - XD_CLR_BAD_NEWBLK(xd_card); - return STATUS_FAIL; - } - - retval = xd_erase_block(chip, old_blk); - if (retval == STATUS_SUCCESS) { - if (XD_CHK_BAD_OLDBLK(xd_card)) { - xd_mark_bad_block(chip, old_blk); - XD_CLR_BAD_OLDBLK(xd_card); - } else { - xd_set_unused_block(chip, old_blk); - } - } else { - xd_set_err_code(chip, XD_NO_ERROR); - XD_CLR_BAD_OLDBLK(xd_card); - } - } - - xd_set_l2p_tbl(chip, zone_no, log_off, (u16)(new_blk & 0x3FF)); - - return STATUS_SUCCESS; -} - -static int xd_prepare_write(struct rtsx_chip *chip, - u32 old_blk, u32 new_blk, u32 log_blk, u8 page_off) -{ - int retval; - - dev_dbg(rtsx_dev(chip), "%s, old_blk = 0x%x, new_blk = 0x%x, log_blk = 0x%x, page_off = %d\n", - __func__, old_blk, new_blk, log_blk, (int)page_off); - - if (page_off) { - retval = xd_copy_page(chip, old_blk, new_blk, 0, page_off); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} - -static int xd_write_multiple_pages(struct rtsx_chip *chip, u32 old_blk, - u32 new_blk, u32 log_blk, u8 start_page, - u8 end_page, u8 *buf, unsigned int *index, - unsigned int *offset) -{ - struct xd_info *xd_card = &chip->xd_card; - u32 page_addr; - int zone_no, retval; - u16 log_off; - u8 page_cnt, reg_val; - - dev_dbg(rtsx_dev(chip), "%s, old_blk = 0x%x, new_blk = 0x%x, log_blk = 0x%x\n", - __func__, old_blk, new_blk, log_blk); - - if (start_page > end_page) - goto status_fail; - - page_cnt = end_page - start_page; - zone_no = (int)(log_blk / 1000); - log_off = (u16)(log_blk % 1000); - - page_addr = (new_blk << xd_card->block_shift) + start_page; - - retval = xd_send_cmd(chip, READ1_1); - if (retval != STATUS_SUCCESS) - goto status_fail; - - rtsx_init_cmd(chip); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_H, - 0xFF, (u8)(log_off >> 8)); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_L, 0xFF, (u8)log_off); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_STATUS, 0xFF, XD_GBLK); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_STATUS, 0xFF, XD_GPG); - - xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_CFG, XD_BA_TRANSFORM, - XD_BA_TRANSFORM); - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, page_cnt); - rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - - trans_dma_enable(chip->srb->sc_data_direction, chip, - page_cnt * 512, DMA_512); - - rtsx_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, - 0xFF, XD_TRANSFER_START | XD_WRITE_PAGES); - rtsx_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, - XD_TRANSFER_END, XD_TRANSFER_END); - - rtsx_send_cmd_no_wait(chip); - - retval = rtsx_transfer_data_partial(chip, XD_CARD, buf, page_cnt * 512, - scsi_sg_count(chip->srb), - index, offset, DMA_TO_DEVICE, chip->xd_timeout); - if (retval < 0) { - rtsx_clear_xd_error(chip); - - if (retval == -ETIMEDOUT) { - xd_set_err_code(chip, XD_TO_ERROR); - goto status_fail; - } else { - goto fail; - } - } - - if (end_page == (xd_card->page_off + 1)) { - xd_card->delay_write.delay_write_flag = 0; - - if (old_blk != BLK_NOT_FOUND) { - retval = xd_erase_block(chip, old_blk); - if (retval == STATUS_SUCCESS) { - if (XD_CHK_BAD_OLDBLK(xd_card)) { - xd_mark_bad_block(chip, old_blk); - XD_CLR_BAD_OLDBLK(xd_card); - } else { - xd_set_unused_block(chip, old_blk); - } - } else { - xd_set_err_code(chip, XD_NO_ERROR); - XD_CLR_BAD_OLDBLK(xd_card); - } - } - xd_set_l2p_tbl(chip, zone_no, log_off, (u16)(new_blk & 0x3FF)); - } - - return STATUS_SUCCESS; - -fail: - retval = rtsx_read_register(chip, XD_DAT, ®_val); - if (retval) - return retval; - if (reg_val & PROGRAM_ERROR) { - xd_set_err_code(chip, XD_PRG_ERROR); - xd_mark_bad_block(chip, new_blk); - } - -status_fail: - return STATUS_FAIL; -} - -#ifdef XD_DELAY_WRITE -int xd_delay_write(struct rtsx_chip *chip) -{ - struct xd_info *xd_card = &chip->xd_card; - struct xd_delay_write_tag *delay_write = &xd_card->delay_write; - int retval; - - if (delay_write->delay_write_flag) { - retval = xd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - delay_write->delay_write_flag = 0; - retval = xd_finish_write(chip, - delay_write->old_phyblock, - delay_write->new_phyblock, - delay_write->logblock, - delay_write->pageoff); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } - - return STATUS_SUCCESS; -} -#endif - -int xd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 start_sector, u16 sector_cnt) -{ - struct xd_info *xd_card = &chip->xd_card; - unsigned int lun = SCSI_LUN(srb); -#ifdef XD_DELAY_WRITE - struct xd_delay_write_tag *delay_write = &xd_card->delay_write; -#endif - int retval, zone_no; - unsigned int index = 0, offset = 0; - u32 log_blk, old_blk = 0, new_blk = 0; - u16 log_off, total_sec_cnt = sector_cnt; - u8 start_page, end_page = 0, page_cnt; - u8 *ptr; - - xd_set_err_code(chip, XD_NO_ERROR); - - xd_card->cleanup_counter = 0; - - dev_dbg(rtsx_dev(chip), "%s: scsi_sg_count = %d\n", __func__, - scsi_sg_count(srb)); - - ptr = (u8 *)scsi_sglist(srb); - - retval = xd_switch_clock(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { - chip->card_fail |= XD_CARD; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - - log_blk = start_sector >> xd_card->block_shift; - start_page = (u8)start_sector & xd_card->page_off; - zone_no = (int)(log_blk / 1000); - log_off = (u16)(log_blk % 1000); - - if (xd_card->zone[zone_no].build_flag == 0) { - retval = xd_build_l2p_tbl(chip, zone_no); - if (retval != STATUS_SUCCESS) { - chip->card_fail |= XD_CARD; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - } - - if (srb->sc_data_direction == DMA_TO_DEVICE) { -#ifdef XD_DELAY_WRITE - if (delay_write->delay_write_flag && - delay_write->logblock == log_blk && - start_page > delay_write->pageoff) { - delay_write->delay_write_flag = 0; - if (delay_write->old_phyblock != BLK_NOT_FOUND) { - retval = xd_copy_page(chip, - delay_write->old_phyblock, - delay_write->new_phyblock, - delay_write->pageoff, - start_page); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } - } - old_blk = delay_write->old_phyblock; - new_blk = delay_write->new_phyblock; - } else if (delay_write->delay_write_flag && - (delay_write->logblock == log_blk) && - (start_page == delay_write->pageoff)) { - delay_write->delay_write_flag = 0; - old_blk = delay_write->old_phyblock; - new_blk = delay_write->new_phyblock; - } else { - retval = xd_delay_write(chip); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } -#endif - old_blk = xd_get_l2p_tbl(chip, zone_no, log_off); - new_blk = xd_get_unused_block(chip, zone_no); - if (old_blk == BLK_NOT_FOUND || - new_blk == BLK_NOT_FOUND) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } - - retval = xd_prepare_write(chip, old_blk, new_blk, - log_blk, start_page); - if (retval != STATUS_SUCCESS) { - if (detect_card_cd(chip, XD_CARD) != - STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } -#ifdef XD_DELAY_WRITE - } -#endif - } else { -#ifdef XD_DELAY_WRITE - retval = xd_delay_write(chip); - if (retval != STATUS_SUCCESS) { - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return STATUS_FAIL; - } -#endif - - old_blk = xd_get_l2p_tbl(chip, zone_no, log_off); - if (old_blk == BLK_NOT_FOUND) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return STATUS_FAIL; - } - } - - dev_dbg(rtsx_dev(chip), "old_blk = 0x%x\n", old_blk); - - while (total_sec_cnt) { - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { - chip->card_fail |= XD_CARD; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - - if ((start_page + total_sec_cnt) > (xd_card->page_off + 1)) - end_page = xd_card->page_off + 1; - else - end_page = start_page + (u8)total_sec_cnt; - - page_cnt = end_page - start_page; - if (srb->sc_data_direction == DMA_FROM_DEVICE) { - retval = xd_read_multiple_pages(chip, old_blk, log_blk, - start_page, end_page, - ptr, &index, &offset); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - return STATUS_FAIL; - } - } else { - retval = xd_write_multiple_pages(chip, old_blk, - new_blk, log_blk, - start_page, end_page, - ptr, &index, &offset); - if (retval != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } - } - - total_sec_cnt -= page_cnt; - if (scsi_sg_count(srb) == 0) - ptr += page_cnt * 512; - - if (total_sec_cnt == 0) - break; - - log_blk++; - zone_no = (int)(log_blk / 1000); - log_off = (u16)(log_blk % 1000); - - if (xd_card->zone[zone_no].build_flag == 0) { - retval = xd_build_l2p_tbl(chip, zone_no); - if (retval != STATUS_SUCCESS) { - chip->card_fail |= XD_CARD; - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - } - - old_blk = xd_get_l2p_tbl(chip, zone_no, log_off); - if (old_blk == BLK_NOT_FOUND) { - if (srb->sc_data_direction == DMA_FROM_DEVICE) - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - else - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - - return STATUS_FAIL; - } - - if (srb->sc_data_direction == DMA_TO_DEVICE) { - new_blk = xd_get_unused_block(chip, zone_no); - if (new_blk == BLK_NOT_FOUND) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } - } - - start_page = 0; - } - - if (srb->sc_data_direction == DMA_TO_DEVICE && - (end_page != (xd_card->page_off + 1))) { -#ifdef XD_DELAY_WRITE - delay_write->delay_write_flag = 1; - delay_write->old_phyblock = old_blk; - delay_write->new_phyblock = new_blk; - delay_write->logblock = log_blk; - delay_write->pageoff = end_page; -#else - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { - chip->card_fail |= XD_CARD; - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - - retval = xd_finish_write(chip, old_blk, new_blk, - log_blk, end_page); - if (retval != STATUS_SUCCESS) { - if (detect_card_cd(chip, XD_CARD) != STATUS_SUCCESS) { - set_sense_type(chip, lun, - SENSE_TYPE_MEDIA_NOT_PRESENT); - return STATUS_FAIL; - } - set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); - return STATUS_FAIL; - } -#endif - } - - scsi_set_resid(srb, 0); - - return STATUS_SUCCESS; -} - -void xd_free_l2p_tbl(struct rtsx_chip *chip) -{ - struct xd_info *xd_card = &chip->xd_card; - int i = 0; - - if (xd_card->zone) { - for (i = 0; i < xd_card->zone_cnt; i++) { - vfree(xd_card->zone[i].l2p_table); - xd_card->zone[i].l2p_table = NULL; - vfree(xd_card->zone[i].free_table); - xd_card->zone[i].free_table = NULL; - } - vfree(xd_card->zone); - xd_card->zone = NULL; - } -} - -void xd_cleanup_work(struct rtsx_chip *chip) -{ -#ifdef XD_DELAY_WRITE - struct xd_info *xd_card = &chip->xd_card; - - if (xd_card->delay_write.delay_write_flag) { - dev_dbg(rtsx_dev(chip), "xD: delay write\n"); - xd_delay_write(chip); - xd_card->cleanup_counter = 0; - } -#endif -} - -int xd_power_off_card3v3(struct rtsx_chip *chip) -{ - int retval; - - retval = disable_card_clock(chip, XD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - retval = rtsx_write_register(chip, CARD_OE, XD_OUTPUT_EN, 0); - if (retval) - return retval; - - if (!chip->ft2_fast_mode) { - retval = card_power_off(chip, XD_CARD); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - wait_timeout(50); - } - - if (chip->asic_code) { - retval = xd_pull_ctl_disable(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - } else { - retval = rtsx_write_register(chip, FPGA_PULL_CTL, 0xFF, 0xDF); - if (retval) - return retval; - } - - return STATUS_SUCCESS; -} - -int release_xd_card(struct rtsx_chip *chip) -{ - struct xd_info *xd_card = &chip->xd_card; - int retval; - - chip->card_ready &= ~XD_CARD; - chip->card_fail &= ~XD_CARD; - chip->card_wp &= ~XD_CARD; - - xd_card->delay_write.delay_write_flag = 0; - - xd_free_l2p_tbl(chip); - - retval = xd_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) - return STATUS_FAIL; - - return STATUS_SUCCESS; -} diff --git a/drivers/staging/rts5208/xd.h b/drivers/staging/rts5208/xd.h deleted file mode 100644 index 98c00f268e5612..00000000000000 --- a/drivers/staging/rts5208/xd.h +++ /dev/null @@ -1,176 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * Author: - * Wei WANG (wei_wang@realsil.com.cn) - * Micky Ching (micky_ching@realsil.com.cn) - */ - -#ifndef __REALTEK_RTSX_XD_H -#define __REALTEK_RTSX_XD_H - -#define XD_DELAY_WRITE - -/* Error Codes */ -#define XD_NO_ERROR 0x00 -#define XD_NO_MEMORY 0x80 -#define XD_PRG_ERROR 0x40 -#define XD_NO_CARD 0x20 -#define XD_READ_FAIL 0x10 -#define XD_ERASE_FAIL 0x08 -#define XD_WRITE_FAIL 0x04 -#define XD_ECC_ERROR 0x02 -#define XD_TO_ERROR 0x01 - -/* XD Commands */ -#define READ1_1 0x00 -#define READ1_2 0x01 -#define READ2 0x50 -#define READ_ID 0x90 -#define RESET 0xff -#define PAGE_PRG_1 0x80 -#define PAGE_PRG_2 0x10 -#define BLK_ERASE_1 0x60 -#define BLK_ERASE_2 0xD0 -#define READ_STS 0x70 -#define READ_XD_ID 0x9A -#define COPY_BACK_512 0x8A -#define COPY_BACK_2K 0x85 -#define READ1_1_2 0x30 -#define READ1_1_3 0x35 -#define CHG_DAT_OUT_1 0x05 -#define RDM_DAT_OUT_1 0x05 -#define CHG_DAT_OUT_2 0xE0 -#define RDM_DAT_OUT_2 0xE0 -#define CHG_DAT_OUT_2 0xE0 -#define CHG_DAT_IN_1 0x85 -#define CACHE_PRG 0x15 - -/* Redundant Area Related */ -#define XD_EXTRA_SIZE 0x10 -#define XD_2K_EXTRA_SIZE 0x40 - -#define NOT_WRITE_PROTECTED 0x80 -#define READY_STATE 0x40 -#define PROGRAM_ERROR 0x01 -#define PROGRAM_ERROR_N_1 0x02 -#define INTERNAL_READY 0x20 -#define READY_FLAG 0x5F - -#define XD_8M_X8_512 0xE6 -#define XD_16M_X8_512 0x73 -#define XD_32M_X8_512 0x75 -#define XD_64M_X8_512 0x76 -#define XD_128M_X8_512 0x79 -#define XD_256M_X8_512 0x71 -#define XD_128M_X8_2048 0xF1 -#define XD_256M_X8_2048 0xDA -#define XD_512M_X8 0xDC -#define XD_128M_X16_2048 0xC1 -#define XD_4M_X8_512_1 0xE3 -#define XD_4M_X8_512_2 0xE5 -#define XD_1G_X8_512 0xD3 -#define XD_2G_X8_512 0xD5 - -#define XD_ID_CODE 0xB5 - -#define VENDOR_BLOCK 0xEFFF -#define CIS_BLOCK 0xDFFF - -#define BLK_NOT_FOUND 0xFFFFFFFF - -#define NO_NEW_BLK 0xFFFFFFFF - -#define PAGE_CORRECTABLE 0x0 -#define PAGE_NOTCORRECTABLE 0x1 - -#define NO_OFFSET 0x0 -#define WITH_OFFSET 0x1 - -#define SECT_PER_PAGE 4 -#define XD_ADDR_MODE_2C XD_ADDR_MODE_2A - -#define ZONE0_BAD_BLOCK 23 -#define NOT_ZONE0_BAD_BLOCK 24 - -#define XD_RW_ADDR 0x01 -#define XD_ERASE_ADDR 0x02 - -#define XD_PAGE_512(xd_card) \ -do { \ - (xd_card)->block_shift = 5; \ - (xd_card)->page_off = 0x1F; \ -} while (0) - -#define XD_SET_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag |= 0x01) -#define XD_CLR_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag &= ~0x01) -#define XD_CHK_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag & 0x01) - -#define XD_SET_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag |= 0x02) -#define XD_CLR_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag &= ~0x02) -#define XD_CHK_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag & 0x02) - -#define XD_SET_MBR_FAIL(xd_card) ((xd_card)->multi_flag |= 0x04) -#define XD_CLR_MBR_FAIL(xd_card) ((xd_card)->multi_flag &= ~0x04) -#define XD_CHK_MBR_FAIL(xd_card) ((xd_card)->multi_flag & 0x04) - -#define XD_SET_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag |= 0x08) -#define XD_CLR_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag &= ~0x08) -#define XD_CHK_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag & 0x08) - -#define XD_SET_4MB(xd_card) ((xd_card)->multi_flag |= 0x10) -#define XD_CLR_4MB(xd_card) ((xd_card)->multi_flag &= ~0x10) -#define XD_CHK_4MB(xd_card) ((xd_card)->multi_flag & 0x10) - -#define XD_SET_ECC_ERR(xd_card) ((xd_card)->multi_flag |= 0x40) -#define XD_CLR_ECC_ERR(xd_card) ((xd_card)->multi_flag &= ~0x40) -#define XD_CHK_ECC_ERR(xd_card) ((xd_card)->multi_flag & 0x40) - -#define PAGE_STATUS 0 -#define BLOCK_STATUS 1 -#define BLOCK_ADDR1_L 2 -#define BLOCK_ADDR1_H 3 -#define BLOCK_ADDR2_L 4 -#define BLOCK_ADDR2_H 5 -#define RESERVED0 6 -#define RESERVED1 7 -#define RESERVED2 8 -#define RESERVED3 9 -#define PARITY 10 - -#define CIS0_0 0 -#define CIS0_1 1 -#define CIS0_2 2 -#define CIS0_3 3 -#define CIS0_4 4 -#define CIS0_5 5 -#define CIS0_6 6 -#define CIS0_7 7 -#define CIS0_8 8 -#define CIS0_9 9 -#define CIS1_0 256 -#define CIS1_1 (256 + 1) -#define CIS1_2 (256 + 2) -#define CIS1_3 (256 + 3) -#define CIS1_4 (256 + 4) -#define CIS1_5 (256 + 5) -#define CIS1_6 (256 + 6) -#define CIS1_7 (256 + 7) -#define CIS1_8 (256 + 8) -#define CIS1_9 (256 + 9) - -int reset_xd_card(struct rtsx_chip *chip); -#ifdef XD_DELAY_WRITE -int xd_delay_write(struct rtsx_chip *chip); -#endif -int xd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, - u32 start_sector, u16 sector_cnt); -void xd_free_l2p_tbl(struct rtsx_chip *chip); -void xd_cleanup_work(struct rtsx_chip *chip); -int xd_power_off_card3v3(struct rtsx_chip *chip); -int release_xd_card(struct rtsx_chip *chip); - -#endif /* __REALTEK_RTSX_XD_H */ diff --git a/drivers/staging/sm750fb/TODO b/drivers/staging/sm750fb/TODO index 481409eb3fb384..9dd57c56625704 100644 --- a/drivers/staging/sm750fb/TODO +++ b/drivers/staging/sm750fb/TODO @@ -12,8 +12,3 @@ TODO: Note: - This driver will be removed from staging after the drm driver is ready - The drm driver is getting ready at https://gitlab.com/sudipm/sm750/tree/sm750 - -Please send any patches to - Greg Kroah-Hartman - Sudip Mukherjee - Teddy Wang diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c index 133ed15f3dbcc0..dc0d715ed97078 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c @@ -96,7 +96,8 @@ static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance, static int audio_vchi_callback(struct vchiq_instance *vchiq_instance, enum vchiq_reason reason, struct vchiq_header *header, - unsigned int handle, void *userdata) + unsigned int handle, + void *cb_data, void __user *cb_userdata) { struct bcm2835_audio_instance *instance = vchiq_get_service_userdata(vchiq_instance, handle); diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h index 6c40d8c1dde607..ee4469f4fc510e 100644 --- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h +++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h @@ -56,7 +56,7 @@ struct vchiq_service_base { enum vchiq_reason reason, struct vchiq_header *header, unsigned int handle, - void *bulk_userdata); + void *cb_data, void __user *cb_userdata); void *userdata; }; @@ -64,7 +64,8 @@ struct vchiq_completion_data_kernel { enum vchiq_reason reason; struct vchiq_header *header; void *service_userdata; - void *bulk_userdata; + void *cb_data; + void __user *cb_userdata; }; struct vchiq_service_params_kernel { @@ -73,7 +74,7 @@ struct vchiq_service_params_kernel { enum vchiq_reason reason, struct vchiq_header *header, unsigned int handle, - void *bulk_userdata); + void *cb_data, void __user *cb_userdata); void *userdata; short version; /* Increment for non-trivial changes */ short version_min; /* Update for incompatible changes */ diff --git a/drivers/staging/vc04_services/interface/TESTING b/drivers/staging/vc04_services/interface/TESTING index 273952dc9d8596..c98f688b07e0fe 100644 --- a/drivers/staging/vc04_services/interface/TESTING +++ b/drivers/staging/vc04_services/interface/TESTING @@ -52,10 +52,10 @@ Here are the most common kernel configurations: * Ping test - Command: vchiq_test -p 1 + Command: vchiq_test -p Expected output: - Ping test - service:echo, iters:1, version 3 + Ping test - service:echo, iters:1000, version 3 vchi ping (size 0) -> 57.000000us vchi ping (size 0, 0 async, 0 oneway) -> 122.000000us vchi bulk (size 0, 0 async, 0 oneway) -> 546.000000us diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO index dfb1ee49633fe2..f6f24600aa8624 100644 --- a/drivers/staging/vc04_services/interface/TODO +++ b/drivers/staging/vc04_services/interface/TODO @@ -26,16 +26,3 @@ kthreads, userspace, limitations) could be very helpful for reviewers. The code follows the 80 characters limitation yet tends to go 3 or 4 levels of indentation deep making it very unpleasant to read. This is specially relevant in the character driver ioctl code and in the core thread functions. - -* Clean up Sparse warnings from __user annotations. See -vchiq_irq_queue_bulk_tx_rx(). Ensure that the address of "&waiter->bulk_waiter" -is never disclosed to userspace. - -* Fix behavior of message handling - -The polling behavior of vchiq_bulk_transmit(), vchiq_bulk_receive() and -vchiq_queue_kernel_message() looks broken. A possible signal should be -propagated back to user space to let the calling task handle it before -retrying. Hopefully these msleep(1) shouldn't be necessary anymore. - -https://lore.kernel.org/linux-staging/CAK8P3a3HGm1cPo4sW9fOY4E8AN8yAq3tevXxU5m8bmtmsU8WKw@mail.gmail.com/ 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 6c488b1e262485..a4e83e5d619bc9 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -36,7 +35,6 @@ #include "vchiq_arm.h" #include "vchiq_bus.h" #include "vchiq_debugfs.h" -#include "vchiq_pagelist.h" #define DEVICE_NAME "vchiq" @@ -48,7 +46,6 @@ #define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1 #define BELL0 0x00 -#define BELL2 0x08 #define ARM_DS_ACTIVE BIT(2) @@ -109,21 +106,9 @@ struct vchiq_arm_state { int first_connect; }; -struct vchiq_pagelist_info { - struct pagelist *pagelist; - size_t pagelist_buffer_size; - dma_addr_t dma_addr; - enum dma_data_direction dma_dir; - unsigned int num_pages; - unsigned int pages_need_release; - struct page **pages; - struct scatterlist *scatterlist; - unsigned int scatterlist_mapped; -}; - static int -vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data, - unsigned int size, enum vchiq_bulk_dir dir); +vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_bulk *bulk_params); static irqreturn_t vchiq_doorbell_irq(int irq, void *dev_id) @@ -146,35 +131,6 @@ vchiq_doorbell_irq(int irq, void *dev_id) return ret; } -static void -cleanup_pagelistinfo(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo) -{ - if (pagelistinfo->scatterlist_mapped) { - dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist, - pagelistinfo->num_pages, pagelistinfo->dma_dir); - } - - if (pagelistinfo->pages_need_release) - unpin_user_pages(pagelistinfo->pages, pagelistinfo->num_pages); - - dma_free_coherent(instance->state->dev, pagelistinfo->pagelist_buffer_size, - pagelistinfo->pagelist, pagelistinfo->dma_addr); -} - -static inline bool -is_adjacent_block(u32 *addrs, dma_addr_t addr, unsigned int k) -{ - u32 tmp; - - if (!k) - return false; - - tmp = (addrs[k - 1] & PAGE_MASK) + - (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT); - - return tmp == (addr & PAGE_MASK); -} - /* * This function is called by the vchiq stack once it has been connected to * the videocore and clients can start to use the stack. @@ -225,270 +181,6 @@ void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)( } EXPORT_SYMBOL(vchiq_add_connected_callback); -/* There is a potential problem with partial cache lines (pages?) - * at the ends of the block when reading. If the CPU accessed anything in - * the same line (page?) then it may have pulled old data into the cache, - * obscuring the new data underneath. We can solve this by transferring the - * partial cache lines separately, and allowing the ARM to copy into the - * cached area. - */ - -static struct vchiq_pagelist_info * -create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, - size_t count, unsigned short type) -{ - struct vchiq_drv_mgmt *drv_mgmt; - struct pagelist *pagelist; - struct vchiq_pagelist_info *pagelistinfo; - struct page **pages; - u32 *addrs; - unsigned int num_pages, offset, i, k; - int actual_pages; - size_t pagelist_size; - struct scatterlist *scatterlist, *sg; - int dma_buffers; - dma_addr_t dma_addr; - - if (count >= INT_MAX - PAGE_SIZE) - return NULL; - - drv_mgmt = dev_get_drvdata(instance->state->dev); - - if (buf) - offset = (uintptr_t)buf & (PAGE_SIZE - 1); - else - offset = (uintptr_t)ubuf & (PAGE_SIZE - 1); - num_pages = DIV_ROUND_UP(count + offset, PAGE_SIZE); - - if ((size_t)num_pages > (SIZE_MAX - sizeof(struct pagelist) - - sizeof(struct vchiq_pagelist_info)) / - (sizeof(u32) + sizeof(pages[0]) + - sizeof(struct scatterlist))) - return NULL; - - pagelist_size = sizeof(struct pagelist) + - (num_pages * sizeof(u32)) + - (num_pages * sizeof(pages[0]) + - (num_pages * sizeof(struct scatterlist))) + - sizeof(struct vchiq_pagelist_info); - - /* Allocate enough storage to hold the page pointers and the page - * list - */ - pagelist = dma_alloc_coherent(instance->state->dev, pagelist_size, &dma_addr, - GFP_KERNEL); - - dev_dbg(instance->state->dev, "arm: %pK\n", pagelist); - - if (!pagelist) - return NULL; - - addrs = pagelist->addrs; - pages = (struct page **)(addrs + num_pages); - scatterlist = (struct scatterlist *)(pages + num_pages); - pagelistinfo = (struct vchiq_pagelist_info *) - (scatterlist + num_pages); - - pagelist->length = count; - pagelist->type = type; - pagelist->offset = offset; - - /* Populate the fields of the pagelistinfo structure */ - pagelistinfo->pagelist = pagelist; - pagelistinfo->pagelist_buffer_size = pagelist_size; - pagelistinfo->dma_addr = dma_addr; - pagelistinfo->dma_dir = (type == PAGELIST_WRITE) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE; - pagelistinfo->num_pages = num_pages; - pagelistinfo->pages_need_release = 0; - pagelistinfo->pages = pages; - pagelistinfo->scatterlist = scatterlist; - pagelistinfo->scatterlist_mapped = 0; - - if (buf) { - unsigned long length = count; - unsigned int off = offset; - - for (actual_pages = 0; actual_pages < num_pages; - actual_pages++) { - struct page *pg = - vmalloc_to_page((buf + - (actual_pages * PAGE_SIZE))); - size_t bytes = PAGE_SIZE - off; - - if (!pg) { - cleanup_pagelistinfo(instance, pagelistinfo); - return NULL; - } - - if (bytes > length) - bytes = length; - pages[actual_pages] = pg; - length -= bytes; - off = 0; - } - /* do not try and release vmalloc pages */ - } else { - actual_pages = pin_user_pages_fast((unsigned long)ubuf & PAGE_MASK, num_pages, - type == PAGELIST_READ, pages); - - if (actual_pages != num_pages) { - dev_dbg(instance->state->dev, "arm: Only %d/%d pages locked\n", - actual_pages, num_pages); - - /* This is probably due to the process being killed */ - if (actual_pages > 0) - unpin_user_pages(pages, actual_pages); - cleanup_pagelistinfo(instance, pagelistinfo); - return NULL; - } - /* release user pages */ - pagelistinfo->pages_need_release = 1; - } - - /* - * Initialize the scatterlist so that the magic cookie - * is filled if debugging is enabled - */ - sg_init_table(scatterlist, num_pages); - /* Now set the pages for each scatterlist */ - for (i = 0; i < num_pages; i++) { - unsigned int len = PAGE_SIZE - offset; - - if (len > count) - len = count; - sg_set_page(scatterlist + i, pages[i], len, offset); - offset = 0; - count -= len; - } - - dma_buffers = dma_map_sg(instance->state->dev, - scatterlist, - num_pages, - pagelistinfo->dma_dir); - - if (dma_buffers == 0) { - cleanup_pagelistinfo(instance, pagelistinfo); - return NULL; - } - - pagelistinfo->scatterlist_mapped = 1; - - /* Combine adjacent blocks for performance */ - k = 0; - for_each_sg(scatterlist, sg, dma_buffers, i) { - unsigned int len = sg_dma_len(sg); - dma_addr_t addr = sg_dma_address(sg); - - /* Note: addrs is the address + page_count - 1 - * The firmware expects blocks after the first to be page- - * aligned and a multiple of the page size - */ - WARN_ON(len == 0); - WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); - WARN_ON(i && (addr & ~PAGE_MASK)); - if (is_adjacent_block(addrs, addr, k)) - addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT); - else - addrs[k++] = (addr & PAGE_MASK) | - (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1); - } - - /* Partial cache lines (fragments) require special measures */ - if ((type == PAGELIST_READ) && - ((pagelist->offset & (drv_mgmt->info->cache_line_size - 1)) || - ((pagelist->offset + pagelist->length) & - (drv_mgmt->info->cache_line_size - 1)))) { - char *fragments; - - if (down_interruptible(&drv_mgmt->free_fragments_sema)) { - cleanup_pagelistinfo(instance, pagelistinfo); - return NULL; - } - - WARN_ON(!drv_mgmt->free_fragments); - - down(&drv_mgmt->free_fragments_mutex); - fragments = drv_mgmt->free_fragments; - WARN_ON(!fragments); - drv_mgmt->free_fragments = *(char **)drv_mgmt->free_fragments; - up(&drv_mgmt->free_fragments_mutex); - pagelist->type = PAGELIST_READ_WITH_FRAGMENTS + - (fragments - drv_mgmt->fragments_base) / drv_mgmt->fragments_size; - } - - return pagelistinfo; -} - -static void -free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo, - int actual) -{ - struct vchiq_drv_mgmt *drv_mgmt; - struct pagelist *pagelist = pagelistinfo->pagelist; - struct page **pages = pagelistinfo->pages; - unsigned int num_pages = pagelistinfo->num_pages; - - dev_dbg(instance->state->dev, "arm: %pK, %d\n", pagelistinfo->pagelist, actual); - - drv_mgmt = dev_get_drvdata(instance->state->dev); - - /* - * NOTE: dma_unmap_sg must be called before the - * cpu can touch any of the data/pages. - */ - dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist, - pagelistinfo->num_pages, pagelistinfo->dma_dir); - pagelistinfo->scatterlist_mapped = 0; - - /* Deal with any partial cache lines (fragments) */ - if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS && drv_mgmt->fragments_base) { - char *fragments = drv_mgmt->fragments_base + - (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) * - drv_mgmt->fragments_size; - int head_bytes, tail_bytes; - - head_bytes = (drv_mgmt->info->cache_line_size - pagelist->offset) & - (drv_mgmt->info->cache_line_size - 1); - tail_bytes = (pagelist->offset + actual) & - (drv_mgmt->info->cache_line_size - 1); - - if ((actual >= 0) && (head_bytes != 0)) { - if (head_bytes > actual) - head_bytes = actual; - - memcpy_to_page(pages[0], - pagelist->offset, - fragments, - head_bytes); - } - if ((actual >= 0) && (head_bytes < actual) && - (tail_bytes != 0)) - memcpy_to_page(pages[num_pages - 1], - (pagelist->offset + actual) & - (PAGE_SIZE - 1) & ~(drv_mgmt->info->cache_line_size - 1), - fragments + drv_mgmt->info->cache_line_size, - tail_bytes); - - down(&drv_mgmt->free_fragments_mutex); - *(char **)fragments = drv_mgmt->free_fragments; - drv_mgmt->free_fragments = fragments; - up(&drv_mgmt->free_fragments_mutex); - up(&drv_mgmt->free_fragments_sema); - } - - /* Need to mark all the pages dirty. */ - if (pagelist->type != PAGELIST_WRITE && - pagelistinfo->pages_need_release) { - unsigned int i; - - for (i = 0; i < num_pages; i++) - set_page_dirty(pages[i]); - } - - cleanup_pagelistinfo(instance, pagelistinfo); -} - static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) { struct device *dev = &pdev->dev; @@ -616,58 +308,6 @@ static struct vchiq_arm_state *vchiq_platform_get_arm_state(struct vchiq_state * return (struct vchiq_arm_state *)state->platform_state; } -void -remote_event_signal(struct vchiq_state *state, struct remote_event *event) -{ - struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(state->dev); - - /* - * Ensure that all writes to shared data structures have completed - * before signalling the peer. - */ - wmb(); - - event->fired = 1; - - dsb(sy); /* data barrier operation */ - - if (event->armed) - writel(0, mgmt->regs + BELL2); /* trigger vc interrupt */ -} - -int -vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk *bulk, void *offset, - void __user *uoffset, int size, int dir) -{ - struct vchiq_pagelist_info *pagelistinfo; - - pagelistinfo = create_pagelist(instance, offset, uoffset, size, - (dir == VCHIQ_BULK_RECEIVE) - ? PAGELIST_READ - : PAGELIST_WRITE); - - if (!pagelistinfo) - return -ENOMEM; - - bulk->data = pagelistinfo->dma_addr; - - /* - * Store the pagelistinfo address in remote_data, - * which isn't used by the slave. - */ - bulk->remote_data = pagelistinfo; - - return 0; -} - -void -vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk) -{ - if (bulk && bulk->remote_data && bulk->actual) - free_pagelist(instance, (struct vchiq_pagelist_info *)bulk->remote_data, - bulk->actual); -} - void vchiq_dump_platform_state(struct seq_file *f) { seq_puts(f, " Platform: 2835 (VC master)\n"); @@ -851,34 +491,31 @@ int vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int handle, const void *data, unsigned int size, void *userdata, enum vchiq_bulk_mode mode) { + struct vchiq_bulk bulk_params = {}; int ret; - while (1) { - switch (mode) { - case VCHIQ_BULK_MODE_NOCALLBACK: - case VCHIQ_BULK_MODE_CALLBACK: - ret = vchiq_bulk_xfer_callback_interruptible(instance, handle, - (void *)data, NULL, - size, mode, userdata, - VCHIQ_BULK_TRANSMIT); - break; - case VCHIQ_BULK_MODE_BLOCKING: - ret = vchiq_blocking_bulk_transfer(instance, handle, (void *)data, size, - VCHIQ_BULK_TRANSMIT); - break; - default: - return -EINVAL; - } - - /* - * vchiq_*_bulk_transfer() may return -EAGAIN, so we need - * to implement a retry mechanism since this function is - * supposed to block until queued - */ - if (ret != -EAGAIN) - break; - - msleep(1); + switch (mode) { + case VCHIQ_BULK_MODE_NOCALLBACK: + case VCHIQ_BULK_MODE_CALLBACK: + + bulk_params.offset = (void *)data; + bulk_params.mode = mode; + bulk_params.size = size; + bulk_params.cb_data = userdata; + bulk_params.dir = VCHIQ_BULK_TRANSMIT; + + ret = vchiq_bulk_xfer_callback(instance, handle, &bulk_params); + break; + case VCHIQ_BULK_MODE_BLOCKING: + bulk_params.offset = (void *)data; + bulk_params.mode = mode; + bulk_params.size = size; + bulk_params.dir = VCHIQ_BULK_TRANSMIT; + + ret = vchiq_blocking_bulk_transfer(instance, handle, &bulk_params); + break; + default: + return -EINVAL; } return ret; @@ -889,34 +526,31 @@ int vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int handle, void *data, unsigned int size, void *userdata, enum vchiq_bulk_mode mode) { + struct vchiq_bulk bulk_params = {}; int ret; - while (1) { - switch (mode) { - case VCHIQ_BULK_MODE_NOCALLBACK: - case VCHIQ_BULK_MODE_CALLBACK: - ret = vchiq_bulk_xfer_callback_interruptible(instance, handle, - (void *)data, NULL, - size, mode, userdata, - VCHIQ_BULK_RECEIVE); - break; - case VCHIQ_BULK_MODE_BLOCKING: - ret = vchiq_blocking_bulk_transfer(instance, handle, (void *)data, size, - VCHIQ_BULK_RECEIVE); - break; - default: - return -EINVAL; - } - - /* - * vchiq_*_bulk_transfer() may return -EAGAIN, so we need - * to implement a retry mechanism since this function is - * supposed to block until queued - */ - if (ret != -EAGAIN) - break; - - msleep(1); + switch (mode) { + case VCHIQ_BULK_MODE_NOCALLBACK: + case VCHIQ_BULK_MODE_CALLBACK: + + bulk_params.offset = (void *)data; + bulk_params.mode = mode; + bulk_params.size = size; + bulk_params.cb_data = userdata; + bulk_params.dir = VCHIQ_BULK_RECEIVE; + + ret = vchiq_bulk_xfer_callback(instance, handle, &bulk_params); + break; + case VCHIQ_BULK_MODE_BLOCKING: + bulk_params.offset = (void *)data; + bulk_params.mode = mode; + bulk_params.size = size; + bulk_params.dir = VCHIQ_BULK_RECEIVE; + + ret = vchiq_blocking_bulk_transfer(instance, handle, &bulk_params); + break; + default: + return -EINVAL; } return ret; @@ -924,8 +558,8 @@ int vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int handle, EXPORT_SYMBOL(vchiq_bulk_receive); static int -vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data, - unsigned int size, enum vchiq_bulk_dir dir) +vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_bulk *bulk_params) { struct vchiq_service *service; struct bulk_waiter_node *waiter = NULL, *iter; @@ -953,13 +587,14 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl if (bulk) { /* This thread has an outstanding bulk transfer. */ /* FIXME: why compare a dma address to a pointer? */ - if ((bulk->data != (dma_addr_t)(uintptr_t)data) || (bulk->size != size)) { + if ((bulk->dma_addr != (dma_addr_t)(uintptr_t)bulk_params->dma_addr) || + (bulk->size != bulk_params->size)) { /* * This is not a retry of the previous one. * Cancel the signal when the transfer completes. */ spin_lock(&service->state->bulk_waiter_spinlock); - bulk->userdata = NULL; + bulk->waiter = NULL; spin_unlock(&service->state->bulk_waiter_spinlock); } } @@ -969,15 +604,16 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl return -ENOMEM; } - ret = vchiq_bulk_xfer_blocking_interruptible(instance, handle, data, NULL, size, - &waiter->bulk_waiter, dir); + bulk_params->waiter = &waiter->bulk_waiter; + + ret = vchiq_bulk_xfer_blocking(instance, handle, bulk_params); if ((ret != -EAGAIN) || fatal_signal_pending(current) || !waiter->bulk_waiter.bulk) { struct vchiq_bulk *bulk = waiter->bulk_waiter.bulk; if (bulk) { /* Cancel the signal when the transfer completes. */ spin_lock(&service->state->bulk_waiter_spinlock); - bulk->userdata = NULL; + bulk->waiter = NULL; spin_unlock(&service->state->bulk_waiter_spinlock); } kfree(waiter); @@ -996,7 +632,7 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl static int add_completion(struct vchiq_instance *instance, enum vchiq_reason reason, struct vchiq_header *header, struct user_service *user_service, - void *bulk_userdata) + void *cb_data, void __user *cb_userdata) { struct vchiq_completion_data_kernel *completion; struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(instance->state->dev); @@ -1026,7 +662,8 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason, completion->reason = reason; /* N.B. service_userdata is updated while processing AWAIT_COMPLETION */ completion->service_userdata = user_service->service; - completion->bulk_userdata = bulk_userdata; + completion->cb_data = cb_data; + completion->cb_userdata = cb_userdata; if (reason == VCHIQ_SERVICE_CLOSED) { /* @@ -1057,8 +694,8 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason, static int service_single_message(struct vchiq_instance *instance, - enum vchiq_reason reason, - struct vchiq_service *service, void *bulk_userdata) + enum vchiq_reason reason, struct vchiq_service *service, + void *cb_data, void __user *cb_userdata) { struct user_service *user_service; @@ -1076,7 +713,7 @@ service_single_message(struct vchiq_instance *instance, dev_dbg(instance->state->dev, "arm: Inserting extra MESSAGE_AVAILABLE\n"); ret = add_completion(instance, reason, NULL, user_service, - bulk_userdata); + cb_data, cb_userdata); if (ret) return ret; } @@ -1094,7 +731,8 @@ service_single_message(struct vchiq_instance *instance, int service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, - struct vchiq_header *header, unsigned int handle, void *bulk_userdata) + struct vchiq_header *header, unsigned int handle, + void *cb_data, void __user *cb_userdata) { /* * How do we ensure the callback goes to the right client? @@ -1133,9 +771,9 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, rcu_read_unlock(); dev_dbg(service->state->dev, - "arm: service %p(%d,%p), reason %d, header %p, instance %p, bulk_userdata %p\n", + "arm: service %p(%d,%p), reason %d, header %p, instance %p, cb_data %p, cb_userdata %p\n", user_service, service->localport, user_service->userdata, - reason, header, instance, bulk_userdata); + reason, header, instance, cb_data, cb_userdata); if (header && user_service->is_vchi) { spin_lock(&service->state->msg_queue_spinlock); @@ -1147,8 +785,8 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, DEBUG_TRACE(SERVICE_CALLBACK_LINE); DEBUG_COUNT(MSG_QUEUE_FULL_COUNT); - ret = service_single_message(instance, reason, - service, bulk_userdata); + ret = service_single_message(instance, reason, service, + cb_data, cb_userdata); if (ret) { DEBUG_TRACE(SERVICE_CALLBACK_LINE); vchiq_service_put(service); @@ -1186,7 +824,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, return 0; return add_completion(instance, reason, header, user_service, - bulk_userdata); + cb_data, cb_userdata); } void vchiq_dump_platform_instances(struct vchiq_state *state, struct seq_file *f) @@ -1273,7 +911,8 @@ static int vchiq_keepalive_vchiq_callback(struct vchiq_instance *instance, enum vchiq_reason reason, struct vchiq_header *header, - unsigned int service_user, void *bulk_user) + unsigned int service_user, + void *cb_data, void __user *cb_userdata) { dev_err(instance->state->dev, "suspend: %s: callback reason %d\n", __func__, reason); @@ -1715,7 +1354,6 @@ MODULE_DEVICE_TABLE(of, vchiq_of_match); static int vchiq_probe(struct platform_device *pdev) { - struct device_node *fw_node; const struct vchiq_platform_info *info; struct vchiq_drv_mgmt *mgmt; int ret; @@ -1724,8 +1362,8 @@ static int vchiq_probe(struct platform_device *pdev) if (!info) return -EINVAL; - fw_node = of_find_compatible_node(NULL, NULL, - "raspberrypi,bcm2835-firmware"); + struct device_node *fw_node __free(device_node) = + of_find_compatible_node(NULL, NULL, "raspberrypi,bcm2835-firmware"); if (!fw_node) { dev_err(&pdev->dev, "Missing firmware node\n"); return -ENOENT; @@ -1736,7 +1374,6 @@ static int vchiq_probe(struct platform_device *pdev) return -ENOMEM; mgmt->fw = devm_rpi_firmware_get(&pdev->dev, fw_node); - of_node_put(fw_node); if (!mgmt->fw) return -EPROBE_DEFER; @@ -1744,8 +1381,10 @@ static int vchiq_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mgmt); ret = vchiq_platform_init(pdev, &mgmt->state); - if (ret) - goto failed_platform_init; + if (ret) { + dev_err(&pdev->dev, "arm: Could not initialize vchiq platform\n"); + return ret; + } vchiq_debugfs_init(&mgmt->state); @@ -1759,18 +1398,13 @@ static int vchiq_probe(struct platform_device *pdev) ret = vchiq_register_chrdev(&pdev->dev); if (ret) { dev_err(&pdev->dev, "arm: Failed to initialize vchiq cdev\n"); - goto error_exit; + return ret; } bcm2835_audio = vchiq_device_register(&pdev->dev, "bcm2835-audio"); bcm2835_camera = vchiq_device_register(&pdev->dev, "bcm2835-camera"); return 0; - -failed_platform_init: - dev_err(&pdev->dev, "arm: Could not initialize vchiq platform\n"); -error_exit: - return ret; } static void vchiq_remove(struct platform_device *pdev) @@ -1797,7 +1431,7 @@ static struct platform_driver vchiq_driver = { .of_match_table = vchiq_of_match, }, .probe = vchiq_probe, - .remove_new = vchiq_remove, + .remove = vchiq_remove, }; static int __init vchiq_driver_init(void) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index b402aac333d9b9..e32b02f990244b 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -155,7 +155,8 @@ static inline int vchiq_register_chrdev(struct device *parent) { return 0; } extern int service_callback(struct vchiq_instance *vchiq_instance, enum vchiq_reason reason, - struct vchiq_header *header, unsigned int handle, void *bulk_userdata); + struct vchiq_header *header, unsigned int handle, + void *cb_data, void __user *cb_userdata); extern void free_bulk_waiter(struct vchiq_instance *instance); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 1f94db6e0cd984..8d5795db4f39f8 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include #include @@ -61,12 +63,16 @@ #define MAKE_REMOTE_USE (VCHIQ_MSG_REMOTE_USE << TYPE_SHIFT) #define MAKE_REMOTE_USE_ACTIVE (VCHIQ_MSG_REMOTE_USE_ACTIVE << TYPE_SHIFT) +#define PAGELIST_WRITE 0 +#define PAGELIST_READ 1 +#define PAGELIST_READ_WITH_FRAGMENTS 2 + +#define BELL2 0x08 + /* Ensure the fields are wide enough */ -static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0, 0, VCHIQ_PORT_MAX)) - == 0); +static_assert(VCHIQ_MSG_SRCPORT(VCHIQ_MAKE_MSG(0, 0, VCHIQ_PORT_MAX)) == 0); static_assert(VCHIQ_MSG_TYPE(VCHIQ_MAKE_MSG(0, VCHIQ_PORT_MAX, 0)) == 0); -static_assert((unsigned int)VCHIQ_PORT_MAX < - (unsigned int)VCHIQ_PORT_FREE); +static_assert((unsigned int)VCHIQ_PORT_MAX < (unsigned int)VCHIQ_PORT_FREE); #define VCHIQ_MSGID_PADDING VCHIQ_MAKE_MSG(VCHIQ_MSG_PADDING, 0, 0) #define VCHIQ_MSGID_CLAIMED 0x40000000 @@ -449,15 +455,26 @@ mark_service_closing(struct vchiq_service *service) static inline int make_service_callback(struct vchiq_service *service, enum vchiq_reason reason, - struct vchiq_header *header, void *bulk_userdata) + struct vchiq_header *header, struct vchiq_bulk *bulk) { + void *cb_data = NULL; + void __user *cb_userdata = NULL; int status; - dev_dbg(service->state->dev, "core: %d: callback:%d (%s, %pK, %pK)\n", + /* + * If a bulk transfer is in progress, pass bulk->cb_*data to the + * callback function. + */ + if (bulk) { + cb_data = bulk->cb_data; + cb_userdata = bulk->cb_userdata; + } + + dev_dbg(service->state->dev, "core: %d: callback:%d (%s, %pK, %pK %pK)\n", service->state->id, service->localport, reason_names[reason], - header, bulk_userdata); + header, cb_data, cb_userdata); status = service->base.callback(service->instance, reason, header, service->handle, - bulk_userdata); + cb_data, cb_userdata); if (status && (status != -EAGAIN)) { dev_warn(service->state->dev, "core: %d: ignoring ERROR from callback to service %x\n", @@ -526,6 +543,25 @@ remote_event_wait(wait_queue_head_t *wq, struct remote_event *event) return ret; } +static void +remote_event_signal(struct vchiq_state *state, struct remote_event *event) +{ + struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(state->dev); + + /* + * Ensure that all writes to shared data structures have completed + * before signalling the peer. + */ + wmb(); + + event->fired = 1; + + dsb(sy); /* data barrier operation */ + + if (event->armed) + writel(0, mgmt->regs + BELL2); /* trigger vc interrupt */ +} + /* * Acknowledge that the event has been signalled, and wake any waiters. Usually * called as a result of the doorbell being rung. @@ -911,6 +947,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, struct vchiq_service_quota *quota = NULL; struct vchiq_header *header; int type = VCHIQ_MSG_TYPE(msgid); + int svc_fourcc; size_t stride; @@ -922,7 +959,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, if (!(flags & QMFLAGS_NO_MUTEX_LOCK) && mutex_lock_killable(&state->slot_mutex)) - return -EAGAIN; + return -EINTR; if (type == VCHIQ_MSG_DATA) { int tx_end_index; @@ -962,8 +999,8 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, spin_unlock(&state->quota_spinlock); mutex_unlock(&state->slot_mutex); - if (wait_for_completion_interruptible(&state->data_quota_event)) - return -EAGAIN; + if (wait_for_completion_killable(&state->data_quota_event)) + return -EINTR; mutex_lock(&state->slot_mutex); spin_lock(&state->quota_spinlock); @@ -986,12 +1023,12 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, quota->message_use_count, quota->slot_use_count); VCHIQ_SERVICE_STATS_INC(service, quota_stalls); mutex_unlock(&state->slot_mutex); - if (wait_for_completion_interruptible("a->quota_event)) - return -EAGAIN; + if (wait_for_completion_killable("a->quota_event)) + return -EINTR; if (service->closing) return -EHOSTDOWN; if (mutex_lock_killable(&state->slot_mutex)) - return -EAGAIN; + return -EINTR; if (service->srvstate != VCHIQ_SRVSTATE_OPEN) { /* The service has been closed */ mutex_unlock(&state->slot_mutex); @@ -1103,17 +1140,13 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, header->msgid = msgid; header->size = size; - { - int svc_fourcc; - - svc_fourcc = service - ? service->base.fourcc - : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); + svc_fourcc = service ? service->base.fourcc + : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); - dev_dbg(state->dev, "core_msg: Sent Msg %s(%u) to %p4cc s:%u d:%d len:%zu\n", - msg_type_str(VCHIQ_MSG_TYPE(msgid)), VCHIQ_MSG_TYPE(msgid), - &svc_fourcc, VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid), size); - } + dev_dbg(state->dev, "core_msg: Sent Msg %s(%u) to %p4cc s:%u d:%d len:%zu\n", + msg_type_str(VCHIQ_MSG_TYPE(msgid)), + VCHIQ_MSG_TYPE(msgid), &svc_fourcc, + VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid), size); /* Make sure the new header is visible to the peer. */ wmb(); @@ -1175,9 +1208,8 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service, state->id, msg_type_str(VCHIQ_MSG_TYPE(msgid)), header, size, VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid)); - callback_result = - copy_message_data(copy_callback, context, - header->data, size); + callback_result = copy_message_data(copy_callback, context, + header->data, size); if (callback_result < 0) { mutex_unlock(&state->slot_mutex); @@ -1288,6 +1320,42 @@ get_bulk_reason(struct vchiq_bulk *bulk) return VCHIQ_BULK_RECEIVE_DONE; } +static int service_notify_bulk(struct vchiq_service *service, + struct vchiq_bulk *bulk) +{ + if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) { + if (bulk->dir == VCHIQ_BULK_TRANSMIT) { + VCHIQ_SERVICE_STATS_INC(service, bulk_tx_count); + VCHIQ_SERVICE_STATS_ADD(service, bulk_tx_bytes, + bulk->actual); + } else { + VCHIQ_SERVICE_STATS_INC(service, bulk_rx_count); + VCHIQ_SERVICE_STATS_ADD(service, bulk_rx_bytes, + bulk->actual); + } + } else { + VCHIQ_SERVICE_STATS_INC(service, bulk_aborted_count); + } + + if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) { + struct bulk_waiter *waiter; + + spin_lock(&service->state->bulk_waiter_spinlock); + waiter = bulk->waiter; + if (waiter) { + waiter->actual = bulk->actual; + complete(&waiter->event); + } + spin_unlock(&service->state->bulk_waiter_spinlock); + } else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK) { + enum vchiq_reason reason = get_bulk_reason(bulk); + + return make_service_callback(service, reason, NULL, bulk); + } + + return 0; +} + /* Called by the slot handler - don't hold the bulk mutex */ static int notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue, @@ -1311,38 +1379,10 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue, * Only generate callbacks for non-dummy bulk * requests, and non-terminated services */ - if (bulk->data && service->instance) { - if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) { - if (bulk->dir == VCHIQ_BULK_TRANSMIT) { - VCHIQ_SERVICE_STATS_INC(service, bulk_tx_count); - VCHIQ_SERVICE_STATS_ADD(service, bulk_tx_bytes, - bulk->actual); - } else { - VCHIQ_SERVICE_STATS_INC(service, bulk_rx_count); - VCHIQ_SERVICE_STATS_ADD(service, bulk_rx_bytes, - bulk->actual); - } - } else { - VCHIQ_SERVICE_STATS_INC(service, bulk_aborted_count); - } - if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) { - struct bulk_waiter *waiter; - - spin_lock(&service->state->bulk_waiter_spinlock); - waiter = bulk->userdata; - if (waiter) { - waiter->actual = bulk->actual; - complete(&waiter->event); - } - spin_unlock(&service->state->bulk_waiter_spinlock); - } else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK) { - enum vchiq_reason reason = - get_bulk_reason(bulk); - status = make_service_callback(service, reason, NULL, - bulk->userdata); - if (status == -EAGAIN) - break; - } + if (bulk->dma_addr && service->instance) { + status = service_notify_bulk(service, bulk); + if (status == -EAGAIN) + break; } queue->remove++; @@ -1415,6 +1455,331 @@ poll_services(struct vchiq_state *state) poll_services_of_group(state, group); } +static void +cleanup_pagelistinfo(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo) +{ + if (pagelistinfo->scatterlist_mapped) { + dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist, + pagelistinfo->num_pages, pagelistinfo->dma_dir); + } + + if (pagelistinfo->pages_need_release) + unpin_user_pages(pagelistinfo->pages, pagelistinfo->num_pages); + + dma_free_coherent(instance->state->dev, pagelistinfo->pagelist_buffer_size, + pagelistinfo->pagelist, pagelistinfo->dma_addr); +} + +static inline bool +is_adjacent_block(u32 *addrs, dma_addr_t addr, unsigned int k) +{ + u32 tmp; + + if (!k) + return false; + + tmp = (addrs[k - 1] & PAGE_MASK) + + (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT); + + return tmp == (addr & PAGE_MASK); +} + +/* There is a potential problem with partial cache lines (pages?) + * at the ends of the block when reading. If the CPU accessed anything in + * the same line (page?) then it may have pulled old data into the cache, + * obscuring the new data underneath. We can solve this by transferring the + * partial cache lines separately, and allowing the ARM to copy into the + * cached area. + */ +static struct vchiq_pagelist_info * +create_pagelist(struct vchiq_instance *instance, struct vchiq_bulk *bulk) +{ + struct vchiq_drv_mgmt *drv_mgmt; + struct pagelist *pagelist; + struct vchiq_pagelist_info *pagelistinfo; + struct page **pages; + u32 *addrs; + unsigned int num_pages, offset, i, k; + int actual_pages; + size_t pagelist_size; + struct scatterlist *scatterlist, *sg; + int dma_buffers; + unsigned int cache_line_size; + dma_addr_t dma_addr; + size_t count = bulk->size; + unsigned short type = (bulk->dir == VCHIQ_BULK_RECEIVE) + ? PAGELIST_READ : PAGELIST_WRITE; + + if (count >= INT_MAX - PAGE_SIZE) + return NULL; + + drv_mgmt = dev_get_drvdata(instance->state->dev); + + if (bulk->offset) + offset = (uintptr_t)bulk->offset & (PAGE_SIZE - 1); + else + offset = (uintptr_t)bulk->uoffset & (PAGE_SIZE - 1); + num_pages = DIV_ROUND_UP(count + offset, PAGE_SIZE); + + if ((size_t)num_pages > (SIZE_MAX - sizeof(struct pagelist) - + sizeof(struct vchiq_pagelist_info)) / + (sizeof(u32) + sizeof(pages[0]) + + sizeof(struct scatterlist))) + return NULL; + + pagelist_size = sizeof(struct pagelist) + + (num_pages * sizeof(u32)) + + (num_pages * sizeof(pages[0]) + + (num_pages * sizeof(struct scatterlist))) + + sizeof(struct vchiq_pagelist_info); + + /* Allocate enough storage to hold the page pointers and the page + * list + */ + pagelist = dma_alloc_coherent(instance->state->dev, pagelist_size, &dma_addr, + GFP_KERNEL); + + dev_dbg(instance->state->dev, "arm: %pK\n", pagelist); + + if (!pagelist) + return NULL; + + addrs = pagelist->addrs; + pages = (struct page **)(addrs + num_pages); + scatterlist = (struct scatterlist *)(pages + num_pages); + pagelistinfo = (struct vchiq_pagelist_info *) + (scatterlist + num_pages); + + pagelist->length = count; + pagelist->type = type; + pagelist->offset = offset; + + /* Populate the fields of the pagelistinfo structure */ + pagelistinfo->pagelist = pagelist; + pagelistinfo->pagelist_buffer_size = pagelist_size; + pagelistinfo->dma_addr = dma_addr; + pagelistinfo->dma_dir = (type == PAGELIST_WRITE) ? + DMA_TO_DEVICE : DMA_FROM_DEVICE; + pagelistinfo->num_pages = num_pages; + pagelistinfo->pages_need_release = 0; + pagelistinfo->pages = pages; + pagelistinfo->scatterlist = scatterlist; + pagelistinfo->scatterlist_mapped = 0; + + if (bulk->offset) { + unsigned long length = count; + unsigned int off = offset; + + for (actual_pages = 0; actual_pages < num_pages; + actual_pages++) { + struct page *pg = + vmalloc_to_page(((unsigned int *)bulk->offset + + (actual_pages * PAGE_SIZE))); + size_t bytes = PAGE_SIZE - off; + + if (!pg) { + cleanup_pagelistinfo(instance, pagelistinfo); + return NULL; + } + + if (bytes > length) + bytes = length; + pages[actual_pages] = pg; + length -= bytes; + off = 0; + } + /* do not try and release vmalloc pages */ + } else { + actual_pages = + pin_user_pages_fast((unsigned long)bulk->uoffset & PAGE_MASK, num_pages, + type == PAGELIST_READ, pages); + + if (actual_pages != num_pages) { + dev_dbg(instance->state->dev, "arm: Only %d/%d pages locked\n", + actual_pages, num_pages); + + /* This is probably due to the process being killed */ + if (actual_pages > 0) + unpin_user_pages(pages, actual_pages); + cleanup_pagelistinfo(instance, pagelistinfo); + return NULL; + } + /* release user pages */ + pagelistinfo->pages_need_release = 1; + } + + /* + * Initialize the scatterlist so that the magic cookie + * is filled if debugging is enabled + */ + sg_init_table(scatterlist, num_pages); + /* Now set the pages for each scatterlist */ + for (i = 0; i < num_pages; i++) { + unsigned int len = PAGE_SIZE - offset; + + if (len > count) + len = count; + sg_set_page(scatterlist + i, pages[i], len, offset); + offset = 0; + count -= len; + } + + dma_buffers = dma_map_sg(instance->state->dev, + scatterlist, + num_pages, + pagelistinfo->dma_dir); + + if (dma_buffers == 0) { + cleanup_pagelistinfo(instance, pagelistinfo); + return NULL; + } + + pagelistinfo->scatterlist_mapped = 1; + + /* Combine adjacent blocks for performance */ + k = 0; + for_each_sg(scatterlist, sg, dma_buffers, i) { + unsigned int len = sg_dma_len(sg); + dma_addr_t addr = sg_dma_address(sg); + + /* Note: addrs is the address + page_count - 1 + * The firmware expects blocks after the first to be page- + * aligned and a multiple of the page size + */ + WARN_ON(len == 0); + WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK)); + WARN_ON(i && (addr & ~PAGE_MASK)); + if (is_adjacent_block(addrs, addr, k)) + addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT); + else + addrs[k++] = (addr & PAGE_MASK) | + (((len + PAGE_SIZE - 1) >> PAGE_SHIFT) - 1); + } + + /* Partial cache lines (fragments) require special measures */ + cache_line_size = drv_mgmt->info->cache_line_size; + if ((type == PAGELIST_READ) && + ((pagelist->offset & (cache_line_size - 1)) || + ((pagelist->offset + pagelist->length) & (cache_line_size - 1)))) { + char *fragments; + + if (down_interruptible(&drv_mgmt->free_fragments_sema)) { + cleanup_pagelistinfo(instance, pagelistinfo); + return NULL; + } + + WARN_ON(!drv_mgmt->free_fragments); + + down(&drv_mgmt->free_fragments_mutex); + fragments = drv_mgmt->free_fragments; + WARN_ON(!fragments); + drv_mgmt->free_fragments = *(char **)drv_mgmt->free_fragments; + up(&drv_mgmt->free_fragments_mutex); + pagelist->type = PAGELIST_READ_WITH_FRAGMENTS + + (fragments - drv_mgmt->fragments_base) / drv_mgmt->fragments_size; + } + + return pagelistinfo; +} + +static void +free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo, + int actual) +{ + struct vchiq_drv_mgmt *drv_mgmt; + struct pagelist *pagelist = pagelistinfo->pagelist; + struct page **pages = pagelistinfo->pages; + unsigned int num_pages = pagelistinfo->num_pages; + unsigned int cache_line_size; + + dev_dbg(instance->state->dev, "arm: %pK, %d\n", pagelistinfo->pagelist, actual); + + drv_mgmt = dev_get_drvdata(instance->state->dev); + + /* + * NOTE: dma_unmap_sg must be called before the + * cpu can touch any of the data/pages. + */ + dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist, + pagelistinfo->num_pages, pagelistinfo->dma_dir); + pagelistinfo->scatterlist_mapped = 0; + + /* Deal with any partial cache lines (fragments) */ + cache_line_size = drv_mgmt->info->cache_line_size; + if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS && drv_mgmt->fragments_base) { + char *fragments = drv_mgmt->fragments_base + + (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) * + drv_mgmt->fragments_size; + int head_bytes, tail_bytes; + + head_bytes = (cache_line_size - pagelist->offset) & + (cache_line_size - 1); + tail_bytes = (pagelist->offset + actual) & + (cache_line_size - 1); + + if ((actual >= 0) && (head_bytes != 0)) { + if (head_bytes > actual) + head_bytes = actual; + + memcpy_to_page(pages[0], pagelist->offset, + fragments, head_bytes); + } + if ((actual >= 0) && (head_bytes < actual) && + (tail_bytes != 0)) + memcpy_to_page(pages[num_pages - 1], + (pagelist->offset + actual) & + (PAGE_SIZE - 1) & ~(cache_line_size - 1), + fragments + cache_line_size, + tail_bytes); + + down(&drv_mgmt->free_fragments_mutex); + *(char **)fragments = drv_mgmt->free_fragments; + drv_mgmt->free_fragments = fragments; + up(&drv_mgmt->free_fragments_mutex); + up(&drv_mgmt->free_fragments_sema); + } + + /* Need to mark all the pages dirty. */ + if (pagelist->type != PAGELIST_WRITE && + pagelistinfo->pages_need_release) { + unsigned int i; + + for (i = 0; i < num_pages; i++) + set_page_dirty(pages[i]); + } + + cleanup_pagelistinfo(instance, pagelistinfo); +} + +static int +vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk *bulk) +{ + struct vchiq_pagelist_info *pagelistinfo; + + pagelistinfo = create_pagelist(instance, bulk); + + if (!pagelistinfo) + return -ENOMEM; + + bulk->dma_addr = pagelistinfo->dma_addr; + + /* + * Store the pagelistinfo address in remote_data, + * which isn't used by the slave. + */ + bulk->remote_data = pagelistinfo; + + return 0; +} + +static void +vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk) +{ + if (bulk && bulk->remote_data && bulk->actual) + free_pagelist(instance, (struct vchiq_pagelist_info *)bulk->remote_data, + bulk->actual); +} + /* Called with the bulk_mutex held */ static void abort_outstanding_bulks(struct vchiq_service *service, @@ -1452,7 +1817,7 @@ abort_outstanding_bulks(struct vchiq_service *service, service->remoteport, bulk->size, bulk->remote_size); } else { /* fabricate a matching dummy bulk */ - bulk->data = 0; + bulk->dma_addr = 0; bulk->size = 0; bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED; bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT : @@ -1468,8 +1833,10 @@ static int parse_open(struct vchiq_state *state, struct vchiq_header *header) { const struct vchiq_open_payload *payload; + struct vchiq_openack_payload ack_payload; struct vchiq_service *service = NULL; int msgid, size; + int openack_id; unsigned int localport, remoteport, fourcc; short version, version_min; @@ -1504,34 +1871,36 @@ parse_open(struct vchiq_state *state, struct vchiq_header *header) } service->peer_version = version; - if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) { - struct vchiq_openack_payload ack_payload = { - service->version - }; - int openack_id = MAKE_OPENACK(service->localport, remoteport); + if (service->srvstate != VCHIQ_SRVSTATE_LISTENING) + goto done; - if (state->version_common < - VCHIQ_VERSION_SYNCHRONOUS_MODE) - service->sync = 0; + ack_payload.version = service->version; + openack_id = MAKE_OPENACK(service->localport, remoteport); - /* Acknowledge the OPEN */ - if (service->sync) { - if (queue_message_sync(state, NULL, openack_id, memcpy_copy_callback, - &ack_payload, sizeof(ack_payload)) == -EAGAIN) - goto bail_not_ready; + if (state->version_common < VCHIQ_VERSION_SYNCHRONOUS_MODE) + service->sync = 0; - /* The service is now open */ - set_service_state(service, VCHIQ_SRVSTATE_OPENSYNC); - } else { - if (queue_message(state, NULL, openack_id, memcpy_copy_callback, - &ack_payload, sizeof(ack_payload), 0) == -EAGAIN) - goto bail_not_ready; + /* Acknowledge the OPEN */ + if (service->sync) { + if (queue_message_sync(state, NULL, openack_id, + memcpy_copy_callback, + &ack_payload, + sizeof(ack_payload)) == -EAGAIN) + goto bail_not_ready; - /* The service is now open */ - set_service_state(service, VCHIQ_SRVSTATE_OPEN); - } + /* The service is now open */ + set_service_state(service, VCHIQ_SRVSTATE_OPENSYNC); + } else { + if (queue_message(state, NULL, openack_id, + memcpy_copy_callback, &ack_payload, + sizeof(ack_payload), 0) == -EINTR) + goto bail_not_ready; + + /* The service is now open */ + set_service_state(service, VCHIQ_SRVSTATE_OPEN); } +done: /* Success - the message has been dealt with */ vchiq_service_put(service); return 1; @@ -1539,7 +1908,7 @@ parse_open(struct vchiq_state *state, struct vchiq_header *header) fail_open: /* No available service, or an invalid request - send a CLOSE */ if (queue_message(state, NULL, MAKE_CLOSE(0, VCHIQ_MSG_SRCPORT(msgid)), - NULL, NULL, 0, 0) == -EAGAIN) + NULL, NULL, 0, 0) == -EINTR) goto bail_not_ready; return 1; @@ -1753,7 +2122,7 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header) dev_dbg(state->dev, "core: %d: prs %s@%pK (%d->%d) %x@%pad\n", state->id, msg_type_str(type), header, remoteport, - localport, bulk->actual, &bulk->data); + localport, bulk->actual, &bulk->dma_addr); dev_dbg(state->dev, "core: %d: prs:%d %cx li=%x ri=%x p=%x\n", state->id, localport, @@ -1786,7 +2155,7 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header) if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) { /* Send a PAUSE in response */ if (queue_message(state, NULL, MAKE_PAUSE, NULL, NULL, 0, - QMFLAGS_NO_MUTEX_UNLOCK) == -EAGAIN) + QMFLAGS_NO_MUTEX_UNLOCK) == -EINTR) goto bail_not_ready; } /* At this point slot_mutex is held */ @@ -1903,7 +2272,7 @@ handle_poll(struct vchiq_state *state) case VCHIQ_CONNSTATE_PAUSING: if (queue_message(state, NULL, MAKE_PAUSE, NULL, NULL, 0, - QMFLAGS_NO_MUTEX_UNLOCK) != -EAGAIN) { + QMFLAGS_NO_MUTEX_UNLOCK) != -EINTR) { vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSE_SENT); } else { /* Retry later */ @@ -1913,7 +2282,7 @@ handle_poll(struct vchiq_state *state) case VCHIQ_CONNSTATE_RESUMING: if (queue_message(state, NULL, MAKE_RESUME, NULL, NULL, 0, - QMFLAGS_NO_MUTEX_LOCK) != -EAGAIN) { + QMFLAGS_NO_MUTEX_LOCK) != -EINTR) { vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED); } else { /* @@ -2662,56 +3031,58 @@ close_service_complete(struct vchiq_service *service, int failstate) * returned to user context. */ static int -vchiq_bulk_xfer_queue_msg_interruptible(struct vchiq_service *service, - void *offset, void __user *uoffset, - int size, void *userdata, - enum vchiq_bulk_mode mode, - enum vchiq_bulk_dir dir) +vchiq_bulk_xfer_queue_msg_killable(struct vchiq_service *service, + struct vchiq_bulk *bulk_params) { struct vchiq_bulk_queue *queue; struct bulk_waiter *bulk_waiter = NULL; struct vchiq_bulk *bulk; struct vchiq_state *state = service->state; - const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r'; - const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ? + const char dir_char = (bulk_params->dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r'; + const int dir_msgtype = (bulk_params->dir == VCHIQ_BULK_TRANSMIT) ? VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX; int status = -EINVAL; int payload[2]; - if (mode == VCHIQ_BULK_MODE_BLOCKING) { - bulk_waiter = userdata; + if (bulk_params->mode == VCHIQ_BULK_MODE_BLOCKING) { + bulk_waiter = bulk_params->waiter; init_completion(&bulk_waiter->event); bulk_waiter->actual = 0; bulk_waiter->bulk = NULL; } - queue = (dir == VCHIQ_BULK_TRANSMIT) ? + queue = (bulk_params->dir == VCHIQ_BULK_TRANSMIT) ? &service->bulk_tx : &service->bulk_rx; if (mutex_lock_killable(&service->bulk_mutex)) - return -EAGAIN; + return -EINTR; if (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS) { VCHIQ_SERVICE_STATS_INC(service, bulk_stalls); do { mutex_unlock(&service->bulk_mutex); - if (wait_for_completion_interruptible(&service->bulk_remove_event)) - return -EAGAIN; + if (wait_for_completion_killable(&service->bulk_remove_event)) + return -EINTR; if (mutex_lock_killable(&service->bulk_mutex)) - return -EAGAIN; + return -EINTR; } while (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS); } bulk = &queue->bulks[BULK_INDEX(queue->local_insert)]; - bulk->mode = mode; - bulk->dir = dir; - bulk->userdata = userdata; - bulk->size = size; + /* Initiliaze the 'bulk' slot with bulk parameters passed in. */ + bulk->mode = bulk_params->mode; + bulk->dir = bulk_params->dir; + bulk->waiter = bulk_params->waiter; + bulk->cb_data = bulk_params->cb_data; + bulk->cb_userdata = bulk_params->cb_userdata; + bulk->size = bulk_params->size; + bulk->offset = bulk_params->offset; + bulk->uoffset = bulk_params->uoffset; bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED; - if (vchiq_prepare_bulk_data(service->instance, bulk, offset, uoffset, size, dir)) + if (vchiq_prepare_bulk_data(service->instance, bulk)) goto unlock_error_exit; /* @@ -2722,21 +3093,21 @@ vchiq_bulk_xfer_queue_msg_interruptible(struct vchiq_service *service, dev_dbg(state->dev, "core: %d: bt (%d->%d) %cx %x@%pad %pK\n", state->id, service->localport, service->remoteport, - dir_char, size, &bulk->data, userdata); + dir_char, bulk->size, &bulk->dma_addr, bulk->cb_data); /* * The slot mutex must be held when the service is being closed, so * claim it here to ensure that isn't happening */ if (mutex_lock_killable(&state->slot_mutex)) { - status = -EAGAIN; + status = -EINTR; goto cancel_bulk_error_exit; } if (service->srvstate != VCHIQ_SRVSTATE_OPEN) goto unlock_both_error_exit; - payload[0] = lower_32_bits(bulk->data); + payload[0] = lower_32_bits(bulk->dma_addr); payload[1] = bulk->size; status = queue_message(state, NULL, @@ -2761,13 +3132,13 @@ vchiq_bulk_xfer_queue_msg_interruptible(struct vchiq_service *service, state->id, service->localport, dir_char, queue->local_insert, queue->remote_insert, queue->process); - if (bulk_waiter) { - bulk_waiter->bulk = bulk; - if (wait_for_completion_interruptible(&bulk_waiter->event)) - status = -EAGAIN; - else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED) - status = -EINVAL; - } + if (bulk_waiter) { + bulk_waiter->bulk = bulk; + if (wait_for_completion_killable(&bulk_waiter->event)) + status = -EINTR; + else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED) + status = -EINVAL; + } return status; @@ -2803,19 +3174,21 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd) if (close_recvd) { dev_err(state->dev, "core: (1) called in state %s\n", srvstate_names[service->srvstate]); - } else if (is_server) { - if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) { - status = -EINVAL; - } else { - service->client_id = 0; - service->remoteport = VCHIQ_PORT_FREE; - if (service->srvstate == VCHIQ_SRVSTATE_CLOSEWAIT) - set_service_state(service, VCHIQ_SRVSTATE_LISTENING); - } - complete(&service->remove_event); - } else { + break; + } else if (!is_server) { vchiq_free_service_internal(service); + break; + } + + if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) { + status = -EINVAL; + } else { + service->client_id = 0; + service->remoteport = VCHIQ_PORT_FREE; + if (service->srvstate == VCHIQ_SRVSTATE_CLOSEWAIT) + set_service_state(service, VCHIQ_SRVSTATE_LISTENING); } + complete(&service->remove_event); break; case VCHIQ_SRVSTATE_OPENING: if (close_recvd) { @@ -2945,6 +3318,7 @@ int vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instance) { struct vchiq_service *service; + int status = 0; int i; /* Find all services registered to this client and enable them. */ @@ -2956,9 +3330,10 @@ vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instanc } if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) { - if (queue_message(state, NULL, MAKE_CONNECT, NULL, NULL, 0, - QMFLAGS_IS_BLOCKING) == -EAGAIN) - return -EAGAIN; + status = queue_message(state, NULL, MAKE_CONNECT, NULL, NULL, 0, + QMFLAGS_IS_BLOCKING); + if (status) + return status; vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING); } @@ -2971,7 +3346,7 @@ vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instanc complete(&state->connect); } - return 0; + return status; } void @@ -3105,12 +3480,10 @@ vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle) } int -vchiq_bulk_xfer_blocking_interruptible(struct vchiq_instance *instance, unsigned int handle, - void *offset, void __user *uoffset, int size, - void __user *userdata, enum vchiq_bulk_dir dir) +vchiq_bulk_xfer_blocking(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_bulk *bulk_params) { struct vchiq_service *service = find_service_by_handle(instance, handle); - enum vchiq_bulk_mode mode = VCHIQ_BULK_MODE_BLOCKING; int status = -EINVAL; if (!service) @@ -3119,15 +3492,13 @@ vchiq_bulk_xfer_blocking_interruptible(struct vchiq_instance *instance, unsigned if (service->srvstate != VCHIQ_SRVSTATE_OPEN) goto error_exit; - if (!offset && !uoffset) + if (!bulk_params->offset && !bulk_params->uoffset) goto error_exit; if (vchiq_check_service(service)) goto error_exit; - - status = vchiq_bulk_xfer_queue_msg_interruptible(service, offset, uoffset, size, - userdata, mode, dir); + status = vchiq_bulk_xfer_queue_msg_killable(service, bulk_params); error_exit: vchiq_service_put(service); @@ -3136,10 +3507,8 @@ vchiq_bulk_xfer_blocking_interruptible(struct vchiq_instance *instance, unsigned } int -vchiq_bulk_xfer_callback_interruptible(struct vchiq_instance *instance, unsigned int handle, - void *offset, void __user *uoffset, int size, - enum vchiq_bulk_mode mode, void *userdata, - enum vchiq_bulk_dir dir) +vchiq_bulk_xfer_callback(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_bulk *bulk_params) { struct vchiq_service *service = find_service_by_handle(instance, handle); int status = -EINVAL; @@ -3147,21 +3516,20 @@ vchiq_bulk_xfer_callback_interruptible(struct vchiq_instance *instance, unsigned if (!service) return -EINVAL; - if (mode != VCHIQ_BULK_MODE_CALLBACK && - mode != VCHIQ_BULK_MODE_NOCALLBACK) + if (bulk_params->mode != VCHIQ_BULK_MODE_CALLBACK && + bulk_params->mode != VCHIQ_BULK_MODE_NOCALLBACK) goto error_exit; if (service->srvstate != VCHIQ_SRVSTATE_OPEN) goto error_exit; - if (!offset && !uoffset) + if (!bulk_params->offset && !bulk_params->uoffset) goto error_exit; if (vchiq_check_service(service)) goto error_exit; - status = vchiq_bulk_xfer_queue_msg_interruptible(service, offset, uoffset, - size, userdata, mode, dir); + status = vchiq_bulk_xfer_queue_msg_killable(service, bulk_params); error_exit: vchiq_service_put(service); @@ -3175,8 +3543,8 @@ vchiq_bulk_xfer_callback_interruptible(struct vchiq_instance *instance, unsigned * and the call should be retried after being returned to user context. */ int -vchiq_bulk_xfer_waiting_interruptible(struct vchiq_instance *instance, - unsigned int handle, struct bulk_waiter *userdata) +vchiq_bulk_xfer_waiting(struct vchiq_instance *instance, + unsigned int handle, struct bulk_waiter *waiter) { struct vchiq_service *service = find_service_by_handle(instance, handle); struct bulk_waiter *bulk_waiter; @@ -3185,7 +3553,7 @@ vchiq_bulk_xfer_waiting_interruptible(struct vchiq_instance *instance, if (!service) return -EINVAL; - if (!userdata) + if (!waiter) goto error_exit; if (service->srvstate != VCHIQ_SRVSTATE_OPEN) @@ -3194,14 +3562,14 @@ vchiq_bulk_xfer_waiting_interruptible(struct vchiq_instance *instance, if (vchiq_check_service(service)) goto error_exit; - bulk_waiter = userdata; + bulk_waiter = waiter; vchiq_service_put(service); status = 0; - if (wait_for_completion_interruptible(&bulk_waiter->event)) - return -EAGAIN; + if (wait_for_completion_killable(&bulk_waiter->event)) + return -EINTR; else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED) return -EINVAL; @@ -3267,24 +3635,8 @@ vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle, int vchiq_queue_kernel_message(struct vchiq_instance *instance, unsigned int handle, void *data, unsigned int size) { - int status; - - while (1) { - status = vchiq_queue_message(instance, handle, memcpy_copy_callback, - data, size); - - /* - * vchiq_queue_message() may return -EAGAIN, so we need to - * implement a retry mechanism since this function is supposed - * to block until queued - */ - if (status != -EAGAIN) - break; - - msleep(1); - } - - return status; + return vchiq_queue_message(instance, handle, memcpy_copy_callback, + data, size); } EXPORT_SYMBOL(vchiq_queue_kernel_message); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 468463f318018c..9b4e766990a493 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -6,11 +6,12 @@ #include #include -#include +#include #include #include #include #include +#include #include #include @@ -113,12 +114,16 @@ enum vchiq_bulk_dir { struct vchiq_bulk { short mode; short dir; - void *userdata; - dma_addr_t data; + void *cb_data; + void __user *cb_userdata; + struct bulk_waiter *waiter; + dma_addr_t dma_addr; int size; void *remote_data; int remote_size; int actual; + void *offset; + void __user *uoffset; }; struct vchiq_bulk_queue { @@ -409,6 +414,28 @@ struct vchiq_state { struct opaque_platform_state *platform_state; }; +struct pagelist { + u32 length; + u16 type; + u16 offset; + u32 addrs[1]; /* N.B. 12 LSBs hold the number + * of following pages at consecutive + * addresses. + */ +}; + +struct vchiq_pagelist_info { + struct pagelist *pagelist; + size_t pagelist_buffer_size; + dma_addr_t dma_addr; + enum dma_data_direction dma_dir; + unsigned int num_pages; + unsigned int pages_need_release; + struct page **pages; + struct scatterlist *scatterlist; + unsigned int scatterlist_mapped; +}; + static inline bool vchiq_remote_initialised(const struct vchiq_state *state) { return state->remote && state->remote->initialised; @@ -471,19 +498,16 @@ extern void remote_event_pollall(struct vchiq_state *state); extern int -vchiq_bulk_xfer_waiting_interruptible(struct vchiq_instance *instance, - unsigned int handle, struct bulk_waiter *userdata); +vchiq_bulk_xfer_waiting(struct vchiq_instance *instance, unsigned int handle, + struct bulk_waiter *userdata); extern int -vchiq_bulk_xfer_blocking_interruptible(struct vchiq_instance *instance, unsigned int handle, - void *offset, void __user *uoffset, int size, - void __user *userdata, enum vchiq_bulk_dir dir); +vchiq_bulk_xfer_blocking(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_bulk *bulk); extern int -vchiq_bulk_xfer_callback_interruptible(struct vchiq_instance *instance, unsigned int handle, - void *offset, void __user *uoffset, int size, - enum vchiq_bulk_mode mode, void *userdata, - enum vchiq_bulk_dir dir); +vchiq_bulk_xfer_callback(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_bulk *bulk); extern void vchiq_dump_state(struct seq_file *f, struct vchiq_state *state); @@ -529,13 +553,6 @@ vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle, void *context, size_t size); -int vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk *bulk, void *offset, - void __user *uoffset, int size, int dir); - -void vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk); - -void remote_event_signal(struct vchiq_state *state, struct remote_event *event); - void vchiq_dump_platform_state(struct seq_file *f); void vchiq_dump_platform_instances(struct vchiq_state *state, struct seq_file *f); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h index fabffd81b1ec9a..b29e6693c94993 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h @@ -4,7 +4,8 @@ #ifndef VCHIQ_DEBUGFS_H #define VCHIQ_DEBUGFS_H -#include "vchiq_core.h" +struct vchiq_state; +struct vchiq_instance; struct vchiq_debugfs_node { struct dentry *dentry; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c index d41a4624cc92c3..454f4341650306 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c @@ -288,7 +288,7 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance, { struct vchiq_service *service; struct bulk_waiter_node *waiter = NULL, *iter; - void *userdata; + struct vchiq_bulk bulk_params = {}; int status = 0; int ret; @@ -303,12 +303,14 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance, goto out; } - userdata = &waiter->bulk_waiter; - - status = vchiq_bulk_xfer_blocking_interruptible(instance, args->handle, - NULL, args->data, args->size, - userdata, dir); + bulk_params.uoffset = args->data; + bulk_params.mode = args->mode; + bulk_params.size = args->size; + bulk_params.dir = dir; + bulk_params.waiter = &waiter->bulk_waiter; + status = vchiq_bulk_xfer_blocking(instance, args->handle, + &bulk_params); } else if (args->mode == VCHIQ_BULK_MODE_WAITING) { mutex_lock(&instance->bulk_waiter_list_mutex); list_for_each_entry(iter, &instance->bulk_waiter_list, @@ -328,16 +330,18 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance, } dev_dbg(service->state->dev, "arm: found bulk_waiter %pK for pid %d\n", waiter, current->pid); - userdata = &waiter->bulk_waiter; - status = vchiq_bulk_xfer_waiting_interruptible(instance, args->handle, userdata); + status = vchiq_bulk_xfer_waiting(instance, args->handle, + &waiter->bulk_waiter); } else { - userdata = args->userdata; - - status = vchiq_bulk_xfer_callback_interruptible(instance, args->handle, NULL, - args->data, args->size, - args->mode, userdata, dir); - + bulk_params.uoffset = args->data; + bulk_params.mode = args->mode; + bulk_params.size = args->size; + bulk_params.dir = dir; + bulk_params.cb_userdata = args->userdata; + + status = vchiq_bulk_xfer_callback(instance, args->handle, + &bulk_params); } if (!waiter) { @@ -350,7 +354,7 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance, if (waiter->bulk_waiter.bulk) { /* Cancel the signal when the transfer completes. */ spin_lock(&service->state->bulk_waiter_spinlock); - waiter->bulk_waiter.bulk->userdata = NULL; + waiter->bulk_waiter.bulk->waiter = NULL; spin_unlock(&service->state->bulk_waiter_spinlock); } kfree(waiter); @@ -410,7 +414,7 @@ struct vchiq_completion_data32 { enum vchiq_reason reason; compat_uptr_t header; compat_uptr_t service_userdata; - compat_uptr_t bulk_userdata; + compat_uptr_t cb_data; }; static int vchiq_put_completion(struct vchiq_completion_data __user *buf, @@ -424,7 +428,7 @@ static int vchiq_put_completion(struct vchiq_completion_data __user *buf, .reason = completion->reason, .header = ptr_to_compat(completion->header), .service_userdata = ptr_to_compat(completion->service_userdata), - .bulk_userdata = ptr_to_compat(completion->bulk_userdata), + .cb_data = ptr_to_compat(completion->cb_userdata), }; if (copy_to_user(&buf32[index], &tmp, sizeof(tmp))) return -EFAULT; @@ -545,11 +549,7 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance, !instance->use_close_delivered) vchiq_service_put(service); - /* - * FIXME: address space mismatch, does bulk_userdata - * actually point to user or kernel memory? - */ - user_completion.bulk_userdata = completion->bulk_userdata; + user_completion.cb_userdata = completion->cb_userdata; if (vchiq_put_completion(args->buf, &user_completion, ret)) { if (ret == 0) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h index 17550831f86cb9..afb71a83cfe703 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h @@ -47,7 +47,7 @@ struct vchiq_completion_data { enum vchiq_reason reason; struct vchiq_header __user *header; void __user *service_userdata; - void __user *bulk_userdata; + void __user *cb_userdata; }; struct vchiq_await_completion { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h deleted file mode 100644 index ebd12bfabb6375..00000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#ifndef VCHIQ_PAGELIST_H -#define VCHIQ_PAGELIST_H - -#define PAGELIST_WRITE 0 -#define PAGELIST_READ 1 -#define PAGELIST_READ_WITH_FRAGMENTS 2 - -struct pagelist { - u32 length; - u16 type; - u16 offset; - u32 addrs[1]; /* N.B. 12 LSBs hold the number - * of following pages at consecutive - * addresses. - */ -}; - -#endif /* VCHIQ_PAGELIST_H */ diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 67489c334f7b2d..3fe482bd279390 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -551,7 +551,8 @@ static void bulk_abort_cb(struct vchiq_mmal_instance *instance, /* incoming event service callback */ static int mmal_service_callback(struct vchiq_instance *vchiq_instance, enum vchiq_reason reason, struct vchiq_header *header, - unsigned int handle, void *bulk_ctx) + unsigned int handle, void *cb_data, + void __user *cb_userdata) { struct vchiq_mmal_instance *instance = vchiq_get_service_userdata(vchiq_instance, handle); u32 msg_len; @@ -626,11 +627,11 @@ static int mmal_service_callback(struct vchiq_instance *vchiq_instance, break; case VCHIQ_BULK_RECEIVE_DONE: - bulk_receive_cb(instance, bulk_ctx); + bulk_receive_cb(instance, cb_data); break; case VCHIQ_BULK_RECEIVE_ABORTED: - bulk_abort_cb(instance, bulk_ctx); + bulk_abort_cb(instance, cb_data); break; case VCHIQ_SERVICE_CLOSED: diff --git a/drivers/staging/vme_user/vme_bridge.h b/drivers/staging/vme_user/vme_bridge.h index 9bdc41bb660210..abf880d68b124c 100644 --- a/drivers/staging/vme_user/vme_bridge.h +++ b/drivers/staging/vme_user/vme_bridge.h @@ -128,39 +128,49 @@ struct vme_bridge { struct mutex irq_mtx; /* Slave Functions */ - int (*slave_get)(struct vme_slave_resource *, int *, unsigned long long *, - unsigned long long *, dma_addr_t *, u32 *, u32 *); - int (*slave_set)(struct vme_slave_resource *, int, unsigned long long, - unsigned long long, dma_addr_t, u32, u32); + int (*slave_get)(struct vme_slave_resource *image, int *enabled, + unsigned long long *vme_base, unsigned long long *size, + dma_addr_t *buf_base, u32 *aspace, u32 *cycle); + int (*slave_set)(struct vme_slave_resource *image, int enabled, + unsigned long long vme_base, unsigned long long size, + dma_addr_t buf_base, u32 aspace, u32 cycle); /* Master Functions */ - int (*master_get)(struct vme_master_resource *, int *, unsigned long long *, - unsigned long long *, u32 *, u32 *, u32 *); - int (*master_set)(struct vme_master_resource *, int, unsigned long long, - unsigned long long, u32, u32, u32); - ssize_t (*master_read)(struct vme_master_resource *, void *, size_t, loff_t); - ssize_t (*master_write)(struct vme_master_resource *, void *, size_t, loff_t); - unsigned int (*master_rmw)(struct vme_master_resource *, unsigned int, - unsigned int, unsigned int, loff_t); + int (*master_get)(struct vme_master_resource *image, int *enabled, + unsigned long long *vme_base, unsigned long long *size, + u32 *aspace, u32 *cycle, u32 *dwidth); + int (*master_set)(struct vme_master_resource *image, int enabled, + unsigned long long vme_base, unsigned long long size, + u32 aspace, u32 cycle, u32 dwidth); + ssize_t (*master_read)(struct vme_master_resource *image, void *buf, + size_t count, loff_t offset); + ssize_t (*master_write)(struct vme_master_resource *image, void *buf, + size_t count, loff_t offset); + unsigned int (*master_rmw)(struct vme_master_resource *image, + unsigned int mask, unsigned int compare, + unsigned int swap, loff_t offset); /* DMA Functions */ - int (*dma_list_add)(struct vme_dma_list *, struct vme_dma_attr *, - struct vme_dma_attr *, size_t); - int (*dma_list_exec)(struct vme_dma_list *); - int (*dma_list_empty)(struct vme_dma_list *); + int (*dma_list_add)(struct vme_dma_list *list, struct vme_dma_attr *src, + struct vme_dma_attr *dest, size_t count); + int (*dma_list_exec)(struct vme_dma_list *list); + int (*dma_list_empty)(struct vme_dma_list *list); /* Interrupt Functions */ - void (*irq_set)(struct vme_bridge *, int, int, int); - int (*irq_generate)(struct vme_bridge *, int, int); + void (*irq_set)(struct vme_bridge *bridge, int level, int state, int sync); + int (*irq_generate)(struct vme_bridge *bridge, int level, int statid); /* Location monitor functions */ - int (*lm_set)(struct vme_lm_resource *, unsigned long long, u32, u32); - int (*lm_get)(struct vme_lm_resource *, unsigned long long *, u32 *, u32 *); - int (*lm_attach)(struct vme_lm_resource *, int, void (*callback)(void *), void *); - int (*lm_detach)(struct vme_lm_resource *, int); + int (*lm_set)(struct vme_lm_resource *lm, unsigned long long lm_base, + u32 aspace, u32 cycle); + int (*lm_get)(struct vme_lm_resource *lm, unsigned long long *lm_base, + u32 *aspace, u32 *cycle); + int (*lm_attach)(struct vme_lm_resource *lm, int monitor, + void (*callback)(void *), void *data); + int (*lm_detach)(struct vme_lm_resource *lm, int monitor); /* CR/CSR space functions */ - int (*slot_get)(struct vme_bridge *); + int (*slot_get)(struct vme_bridge *bridge); /* Bridge parent interface */ void *(*alloc_consistent)(struct device *dev, size_t size, dma_addr_t *dma); diff --git a/drivers/staging/vt6655/Kconfig b/drivers/staging/vt6655/Kconfig deleted file mode 100644 index 077f62ebe80cdd..00000000000000 --- a/drivers/staging/vt6655/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config VT6655 - tristate "VIA Technologies VT6655 support" - depends on PCI && HAS_IOPORT && MAC80211 && m - help - This is a vendor-written driver for VIA VT6655. diff --git a/drivers/staging/vt6655/Makefile b/drivers/staging/vt6655/Makefile deleted file mode 100644 index e70357ec0af8a1..00000000000000 --- a/drivers/staging/vt6655/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -vt6655_stage-y += device_main.o \ - card.o \ - channel.o \ - mac.o \ - baseband.o \ - rxtx.o \ - dpc.o \ - power.o \ - srom.o \ - key.o \ - rf.o - -obj-$(CONFIG_VT6655) += vt6655_stage.o diff --git a/drivers/staging/vt6655/TODO b/drivers/staging/vt6655/TODO deleted file mode 100644 index 529bc22cd6081e..00000000000000 --- a/drivers/staging/vt6655/TODO +++ /dev/null @@ -1,21 +0,0 @@ -TODO: -- remove __cplusplus ifdefs -- done -- prepare for merge with vt6656 driver: - - rename DEVICE_PRT() to DBG_PRT() -- done - - share 80211*.h includes - - split rf.c - - remove dead code - - abstract VT3253 chipset specific code -- add common vt665x infrastructure -- kill ttype.h -- switch to use LIB80211 -- switch to use MAC80211 -- verify unsigned long usage for x86-64 arch -- reduce .data footprint -- use kernel coding style -- checkpatch.pl fixes -- sparse fixes -- integrate with drivers/net/wireless - -Please send any patches to Greg Kroah-Hartman -and Philipp Hortmann . diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c deleted file mode 100644 index f7824396c5ff70..00000000000000 --- a/drivers/staging/vt6655/baseband.c +++ /dev/null @@ -1,2257 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions to access baseband - * - * Author: Kyle Hsu - * - * Date: Aug.22, 2002 - * - * Functions: - * bb_get_frame_time - Calculate data frame transmitting time - * bb_read_embedded - Embedded read baseband register via MAC - * bb_write_embedded - Embedded write baseband register via MAC - * bb_vt3253_init - VIA VT3253 baseband chip init code - * - * Revision History: - * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. - * 08-07-2003 Bryan YC Fan: Add MAXIM2827/2825 and RFMD2959 support. - * 08-26-2003 Kyle Hsu : Modify BBuGetFrameTime() and - * BBvCalculateParameter(). - * cancel the setting of MAC_REG_SOFTPWRCTL on - * BBbVT3253Init(). - * Add the comments. - * 09-01-2003 Bryan YC Fan: RF & BB tables updated. - * Modified BBvLoopbackOn & BBvLoopbackOff(). - * - * - */ - -#include "mac.h" -#include "baseband.h" -#include "srom.h" -#include "rf.h" - -/*--------------------- Static Classes ----------------------------*/ - -/*--------------------- Static Variables --------------------------*/ - -/*--------------------- Static Functions --------------------------*/ - -/*--------------------- Export Variables --------------------------*/ - -/*--------------------- Static Definitions -------------------------*/ - -/*--------------------- Static Classes ----------------------------*/ - -/*--------------------- Static Variables --------------------------*/ - -#define CB_VT3253_INIT_FOR_RFMD 446 -static const unsigned char by_vt3253_init_tab_rfmd[CB_VT3253_INIT_FOR_RFMD][2] = { - {0x00, 0x30}, - {0x01, 0x00}, - {0x02, 0x00}, - {0x03, 0x00}, - {0x04, 0x00}, - {0x05, 0x00}, - {0x06, 0x00}, - {0x07, 0x00}, - {0x08, 0x70}, - {0x09, 0x45}, - {0x0a, 0x2a}, - {0x0b, 0x76}, - {0x0c, 0x00}, - {0x0d, 0x01}, - {0x0e, 0x80}, - {0x0f, 0x00}, - {0x10, 0x00}, - {0x11, 0x00}, - {0x12, 0x00}, - {0x13, 0x00}, - {0x14, 0x00}, - {0x15, 0x00}, - {0x16, 0x00}, - {0x17, 0x00}, - {0x18, 0x00}, - {0x19, 0x00}, - {0x1a, 0x00}, - {0x1b, 0x9d}, - {0x1c, 0x05}, - {0x1d, 0x00}, - {0x1e, 0x00}, - {0x1f, 0x00}, - {0x20, 0x00}, - {0x21, 0x00}, - {0x22, 0x00}, - {0x23, 0x00}, - {0x24, 0x00}, - {0x25, 0x4a}, - {0x26, 0x00}, - {0x27, 0x00}, - {0x28, 0x00}, - {0x29, 0x00}, - {0x2a, 0x00}, - {0x2b, 0x00}, - {0x2c, 0x00}, - {0x2d, 0xa8}, - {0x2e, 0x1a}, - {0x2f, 0x0c}, - {0x30, 0x26}, - {0x31, 0x5b}, - {0x32, 0x00}, - {0x33, 0x00}, - {0x34, 0x00}, - {0x35, 0x00}, - {0x36, 0xaa}, - {0x37, 0xaa}, - {0x38, 0xff}, - {0x39, 0xff}, - {0x3a, 0x00}, - {0x3b, 0x00}, - {0x3c, 0x00}, - {0x3d, 0x0d}, - {0x3e, 0x51}, - {0x3f, 0x04}, - {0x40, 0x00}, - {0x41, 0x08}, - {0x42, 0x00}, - {0x43, 0x08}, - {0x44, 0x06}, - {0x45, 0x14}, - {0x46, 0x05}, - {0x47, 0x08}, - {0x48, 0x00}, - {0x49, 0x00}, - {0x4a, 0x00}, - {0x4b, 0x00}, - {0x4c, 0x09}, - {0x4d, 0x80}, - {0x4e, 0x00}, - {0x4f, 0xc5}, - {0x50, 0x14}, - {0x51, 0x19}, - {0x52, 0x00}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x00}, - {0x56, 0x00}, - {0x57, 0x00}, - {0x58, 0x00}, - {0x59, 0xb0}, - {0x5a, 0x00}, - {0x5b, 0x00}, - {0x5c, 0x00}, - {0x5d, 0x00}, - {0x5e, 0x00}, - {0x5f, 0x00}, - {0x60, 0x44}, - {0x61, 0x04}, - {0x62, 0x00}, - {0x63, 0x00}, - {0x64, 0x00}, - {0x65, 0x00}, - {0x66, 0x04}, - {0x67, 0xb7}, - {0x68, 0x00}, - {0x69, 0x00}, - {0x6a, 0x00}, - {0x6b, 0x00}, - {0x6c, 0x00}, - {0x6d, 0x03}, - {0x6e, 0x01}, - {0x6f, 0x00}, - {0x70, 0x00}, - {0x71, 0x00}, - {0x72, 0x00}, - {0x73, 0x00}, - {0x74, 0x00}, - {0x75, 0x00}, - {0x76, 0x00}, - {0x77, 0x00}, - {0x78, 0x00}, - {0x79, 0x00}, - {0x7a, 0x00}, - {0x7b, 0x00}, - {0x7c, 0x00}, - {0x7d, 0x00}, - {0x7e, 0x00}, - {0x7f, 0x00}, - {0x80, 0x0b}, - {0x81, 0x00}, - {0x82, 0x3c}, - {0x83, 0x00}, - {0x84, 0x00}, - {0x85, 0x00}, - {0x86, 0x00}, - {0x87, 0x00}, - {0x88, 0x08}, - {0x89, 0x00}, - {0x8a, 0x08}, - {0x8b, 0xa6}, - {0x8c, 0x84}, - {0x8d, 0x47}, - {0x8e, 0xbb}, - {0x8f, 0x02}, - {0x90, 0x21}, - {0x91, 0x0c}, - {0x92, 0x04}, - {0x93, 0x22}, - {0x94, 0x00}, - {0x95, 0x00}, - {0x96, 0x00}, - {0x97, 0xeb}, - {0x98, 0x00}, - {0x99, 0x00}, - {0x9a, 0x00}, - {0x9b, 0x00}, - {0x9c, 0x00}, - {0x9d, 0x00}, - {0x9e, 0x00}, - {0x9f, 0x00}, - {0xa0, 0x00}, - {0xa1, 0x00}, - {0xa2, 0x00}, - {0xa3, 0x00}, - {0xa4, 0x00}, - {0xa5, 0x00}, - {0xa6, 0x10}, - {0xa7, 0x04}, - {0xa8, 0x10}, - {0xa9, 0x00}, - {0xaa, 0x8f}, - {0xab, 0x00}, - {0xac, 0x00}, - {0xad, 0x00}, - {0xae, 0x00}, - {0xaf, 0x80}, - {0xb0, 0x38}, - {0xb1, 0x00}, - {0xb2, 0x00}, - {0xb3, 0x00}, - {0xb4, 0xee}, - {0xb5, 0xff}, - {0xb6, 0x10}, - {0xb7, 0x00}, - {0xb8, 0x00}, - {0xb9, 0x00}, - {0xba, 0x00}, - {0xbb, 0x03}, - {0xbc, 0x00}, - {0xbd, 0x00}, - {0xbe, 0x00}, - {0xbf, 0x00}, - {0xc0, 0x10}, - {0xc1, 0x10}, - {0xc2, 0x18}, - {0xc3, 0x20}, - {0xc4, 0x10}, - {0xc5, 0x00}, - {0xc6, 0x22}, - {0xc7, 0x14}, - {0xc8, 0x0f}, - {0xc9, 0x08}, - {0xca, 0xa4}, - {0xcb, 0xa7}, - {0xcc, 0x3c}, - {0xcd, 0x10}, - {0xce, 0x20}, - {0xcf, 0x00}, - {0xd0, 0x00}, - {0xd1, 0x10}, - {0xd2, 0x00}, - {0xd3, 0x00}, - {0xd4, 0x10}, - {0xd5, 0x33}, - {0xd6, 0x70}, - {0xd7, 0x01}, - {0xd8, 0x00}, - {0xd9, 0x00}, - {0xda, 0x00}, - {0xdb, 0x00}, - {0xdc, 0x00}, - {0xdd, 0x00}, - {0xde, 0x00}, - {0xdf, 0x00}, - {0xe0, 0x00}, - {0xe1, 0x00}, - {0xe2, 0xcc}, - {0xe3, 0x04}, - {0xe4, 0x08}, - {0xe5, 0x10}, - {0xe6, 0x00}, - {0xe7, 0x0e}, - {0xe8, 0x88}, - {0xe9, 0xd4}, - {0xea, 0x05}, - {0xeb, 0xf0}, - {0xec, 0x79}, - {0xed, 0x0f}, - {0xee, 0x04}, - {0xef, 0x04}, - {0xf0, 0x00}, - {0xf1, 0x00}, - {0xf2, 0x00}, - {0xf3, 0x00}, - {0xf4, 0x00}, - {0xf5, 0x00}, - {0xf6, 0x00}, - {0xf7, 0x00}, - {0xf8, 0x00}, - {0xf9, 0x00}, - {0xF0, 0x00}, - {0xF1, 0xF8}, - {0xF0, 0x80}, - {0xF0, 0x00}, - {0xF1, 0xF4}, - {0xF0, 0x81}, - {0xF0, 0x01}, - {0xF1, 0xF0}, - {0xF0, 0x82}, - {0xF0, 0x02}, - {0xF1, 0xEC}, - {0xF0, 0x83}, - {0xF0, 0x03}, - {0xF1, 0xE8}, - {0xF0, 0x84}, - {0xF0, 0x04}, - {0xF1, 0xE4}, - {0xF0, 0x85}, - {0xF0, 0x05}, - {0xF1, 0xE0}, - {0xF0, 0x86}, - {0xF0, 0x06}, - {0xF1, 0xDC}, - {0xF0, 0x87}, - {0xF0, 0x07}, - {0xF1, 0xD8}, - {0xF0, 0x88}, - {0xF0, 0x08}, - {0xF1, 0xD4}, - {0xF0, 0x89}, - {0xF0, 0x09}, - {0xF1, 0xD0}, - {0xF0, 0x8A}, - {0xF0, 0x0A}, - {0xF1, 0xCC}, - {0xF0, 0x8B}, - {0xF0, 0x0B}, - {0xF1, 0xC8}, - {0xF0, 0x8C}, - {0xF0, 0x0C}, - {0xF1, 0xC4}, - {0xF0, 0x8D}, - {0xF0, 0x0D}, - {0xF1, 0xC0}, - {0xF0, 0x8E}, - {0xF0, 0x0E}, - {0xF1, 0xBC}, - {0xF0, 0x8F}, - {0xF0, 0x0F}, - {0xF1, 0xB8}, - {0xF0, 0x90}, - {0xF0, 0x10}, - {0xF1, 0xB4}, - {0xF0, 0x91}, - {0xF0, 0x11}, - {0xF1, 0xB0}, - {0xF0, 0x92}, - {0xF0, 0x12}, - {0xF1, 0xAC}, - {0xF0, 0x93}, - {0xF0, 0x13}, - {0xF1, 0xA8}, - {0xF0, 0x94}, - {0xF0, 0x14}, - {0xF1, 0xA4}, - {0xF0, 0x95}, - {0xF0, 0x15}, - {0xF1, 0xA0}, - {0xF0, 0x96}, - {0xF0, 0x16}, - {0xF1, 0x9C}, - {0xF0, 0x97}, - {0xF0, 0x17}, - {0xF1, 0x98}, - {0xF0, 0x98}, - {0xF0, 0x18}, - {0xF1, 0x94}, - {0xF0, 0x99}, - {0xF0, 0x19}, - {0xF1, 0x90}, - {0xF0, 0x9A}, - {0xF0, 0x1A}, - {0xF1, 0x8C}, - {0xF0, 0x9B}, - {0xF0, 0x1B}, - {0xF1, 0x88}, - {0xF0, 0x9C}, - {0xF0, 0x1C}, - {0xF1, 0x84}, - {0xF0, 0x9D}, - {0xF0, 0x1D}, - {0xF1, 0x80}, - {0xF0, 0x9E}, - {0xF0, 0x1E}, - {0xF1, 0x7C}, - {0xF0, 0x9F}, - {0xF0, 0x1F}, - {0xF1, 0x78}, - {0xF0, 0xA0}, - {0xF0, 0x20}, - {0xF1, 0x74}, - {0xF0, 0xA1}, - {0xF0, 0x21}, - {0xF1, 0x70}, - {0xF0, 0xA2}, - {0xF0, 0x22}, - {0xF1, 0x6C}, - {0xF0, 0xA3}, - {0xF0, 0x23}, - {0xF1, 0x68}, - {0xF0, 0xA4}, - {0xF0, 0x24}, - {0xF1, 0x64}, - {0xF0, 0xA5}, - {0xF0, 0x25}, - {0xF1, 0x60}, - {0xF0, 0xA6}, - {0xF0, 0x26}, - {0xF1, 0x5C}, - {0xF0, 0xA7}, - {0xF0, 0x27}, - {0xF1, 0x58}, - {0xF0, 0xA8}, - {0xF0, 0x28}, - {0xF1, 0x54}, - {0xF0, 0xA9}, - {0xF0, 0x29}, - {0xF1, 0x50}, - {0xF0, 0xAA}, - {0xF0, 0x2A}, - {0xF1, 0x4C}, - {0xF0, 0xAB}, - {0xF0, 0x2B}, - {0xF1, 0x48}, - {0xF0, 0xAC}, - {0xF0, 0x2C}, - {0xF1, 0x44}, - {0xF0, 0xAD}, - {0xF0, 0x2D}, - {0xF1, 0x40}, - {0xF0, 0xAE}, - {0xF0, 0x2E}, - {0xF1, 0x3C}, - {0xF0, 0xAF}, - {0xF0, 0x2F}, - {0xF1, 0x38}, - {0xF0, 0xB0}, - {0xF0, 0x30}, - {0xF1, 0x34}, - {0xF0, 0xB1}, - {0xF0, 0x31}, - {0xF1, 0x30}, - {0xF0, 0xB2}, - {0xF0, 0x32}, - {0xF1, 0x2C}, - {0xF0, 0xB3}, - {0xF0, 0x33}, - {0xF1, 0x28}, - {0xF0, 0xB4}, - {0xF0, 0x34}, - {0xF1, 0x24}, - {0xF0, 0xB5}, - {0xF0, 0x35}, - {0xF1, 0x20}, - {0xF0, 0xB6}, - {0xF0, 0x36}, - {0xF1, 0x1C}, - {0xF0, 0xB7}, - {0xF0, 0x37}, - {0xF1, 0x18}, - {0xF0, 0xB8}, - {0xF0, 0x38}, - {0xF1, 0x14}, - {0xF0, 0xB9}, - {0xF0, 0x39}, - {0xF1, 0x10}, - {0xF0, 0xBA}, - {0xF0, 0x3A}, - {0xF1, 0x0C}, - {0xF0, 0xBB}, - {0xF0, 0x3B}, - {0xF1, 0x08}, - {0xF0, 0x00}, - {0xF0, 0x3C}, - {0xF1, 0x04}, - {0xF0, 0xBD}, - {0xF0, 0x3D}, - {0xF1, 0x00}, - {0xF0, 0xBE}, - {0xF0, 0x3E}, - {0xF1, 0x00}, - {0xF0, 0xBF}, - {0xF0, 0x3F}, - {0xF1, 0x00}, - {0xF0, 0xC0}, - {0xF0, 0x00}, -}; - -#define CB_VT3253B0_INIT_FOR_RFMD 256 -static const unsigned char vt3253b0_rfmd[CB_VT3253B0_INIT_FOR_RFMD][2] = { - {0x00, 0x31}, - {0x01, 0x00}, - {0x02, 0x00}, - {0x03, 0x00}, - {0x04, 0x00}, - {0x05, 0x81}, - {0x06, 0x00}, - {0x07, 0x00}, - {0x08, 0x38}, - {0x09, 0x45}, - {0x0a, 0x2a}, - {0x0b, 0x76}, - {0x0c, 0x00}, - {0x0d, 0x00}, - {0x0e, 0x80}, - {0x0f, 0x00}, - {0x10, 0x00}, - {0x11, 0x00}, - {0x12, 0x00}, - {0x13, 0x00}, - {0x14, 0x00}, - {0x15, 0x00}, - {0x16, 0x00}, - {0x17, 0x00}, - {0x18, 0x00}, - {0x19, 0x00}, - {0x1a, 0x00}, - {0x1b, 0x8e}, - {0x1c, 0x06}, - {0x1d, 0x00}, - {0x1e, 0x00}, - {0x1f, 0x00}, - {0x20, 0x00}, - {0x21, 0x00}, - {0x22, 0x00}, - {0x23, 0x00}, - {0x24, 0x00}, - {0x25, 0x4a}, - {0x26, 0x00}, - {0x27, 0x00}, - {0x28, 0x00}, - {0x29, 0x00}, - {0x2a, 0x00}, - {0x2b, 0x00}, - {0x2c, 0x00}, - {0x2d, 0x34}, - {0x2e, 0x18}, - {0x2f, 0x0c}, - {0x30, 0x26}, - {0x31, 0x5b}, - {0x32, 0x00}, - {0x33, 0x00}, - {0x34, 0x00}, - {0x35, 0x00}, - {0x36, 0xaa}, - {0x37, 0xaa}, - {0x38, 0xff}, - {0x39, 0xff}, - {0x3a, 0xf8}, - {0x3b, 0x00}, - {0x3c, 0x00}, - {0x3d, 0x09}, - {0x3e, 0x0d}, - {0x3f, 0x04}, - {0x40, 0x00}, - {0x41, 0x08}, - {0x42, 0x00}, - {0x43, 0x08}, - {0x44, 0x08}, - {0x45, 0x14}, - {0x46, 0x05}, - {0x47, 0x08}, - {0x48, 0x00}, - {0x49, 0x00}, - {0x4a, 0x00}, - {0x4b, 0x00}, - {0x4c, 0x09}, - {0x4d, 0x80}, - {0x4e, 0x00}, - {0x4f, 0xc5}, - {0x50, 0x14}, - {0x51, 0x19}, - {0x52, 0x00}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x00}, - {0x56, 0x00}, - {0x57, 0x00}, - {0x58, 0x00}, - {0x59, 0xb0}, - {0x5a, 0x00}, - {0x5b, 0x00}, - {0x5c, 0x00}, - {0x5d, 0x00}, - {0x5e, 0x00}, - {0x5f, 0x00}, - {0x60, 0x39}, - {0x61, 0x83}, - {0x62, 0x00}, - {0x63, 0x00}, - {0x64, 0x00}, - {0x65, 0x00}, - {0x66, 0xc0}, - {0x67, 0x49}, - {0x68, 0x00}, - {0x69, 0x00}, - {0x6a, 0x00}, - {0x6b, 0x00}, - {0x6c, 0x00}, - {0x6d, 0x03}, - {0x6e, 0x01}, - {0x6f, 0x00}, - {0x70, 0x00}, - {0x71, 0x00}, - {0x72, 0x00}, - {0x73, 0x00}, - {0x74, 0x00}, - {0x75, 0x00}, - {0x76, 0x00}, - {0x77, 0x00}, - {0x78, 0x00}, - {0x79, 0x00}, - {0x7a, 0x00}, - {0x7b, 0x00}, - {0x7c, 0x00}, - {0x7d, 0x00}, - {0x7e, 0x00}, - {0x7f, 0x00}, - {0x80, 0x89}, - {0x81, 0x00}, - {0x82, 0x0e}, - {0x83, 0x00}, - {0x84, 0x00}, - {0x85, 0x00}, - {0x86, 0x00}, - {0x87, 0x00}, - {0x88, 0x08}, - {0x89, 0x00}, - {0x8a, 0x0e}, - {0x8b, 0xa7}, - {0x8c, 0x88}, - {0x8d, 0x47}, - {0x8e, 0xaa}, - {0x8f, 0x02}, - {0x90, 0x23}, - {0x91, 0x0c}, - {0x92, 0x06}, - {0x93, 0x08}, - {0x94, 0x00}, - {0x95, 0x00}, - {0x96, 0x00}, - {0x97, 0xeb}, - {0x98, 0x00}, - {0x99, 0x00}, - {0x9a, 0x00}, - {0x9b, 0x00}, - {0x9c, 0x00}, - {0x9d, 0x00}, - {0x9e, 0x00}, - {0x9f, 0x00}, - {0xa0, 0x00}, - {0xa1, 0x00}, - {0xa2, 0x00}, - {0xa3, 0xcd}, - {0xa4, 0x07}, - {0xa5, 0x33}, - {0xa6, 0x18}, - {0xa7, 0x00}, - {0xa8, 0x18}, - {0xa9, 0x00}, - {0xaa, 0x28}, - {0xab, 0x00}, - {0xac, 0x00}, - {0xad, 0x00}, - {0xae, 0x00}, - {0xaf, 0x18}, - {0xb0, 0x38}, - {0xb1, 0x30}, - {0xb2, 0x00}, - {0xb3, 0x00}, - {0xb4, 0x00}, - {0xb5, 0x00}, - {0xb6, 0x84}, - {0xb7, 0xfd}, - {0xb8, 0x00}, - {0xb9, 0x00}, - {0xba, 0x00}, - {0xbb, 0x03}, - {0xbc, 0x00}, - {0xbd, 0x00}, - {0xbe, 0x00}, - {0xbf, 0x00}, - {0xc0, 0x10}, - {0xc1, 0x20}, - {0xc2, 0x18}, - {0xc3, 0x20}, - {0xc4, 0x10}, - {0xc5, 0x2c}, - {0xc6, 0x1e}, - {0xc7, 0x10}, - {0xc8, 0x12}, - {0xc9, 0x01}, - {0xca, 0x6f}, - {0xcb, 0xa7}, - {0xcc, 0x3c}, - {0xcd, 0x10}, - {0xce, 0x00}, - {0xcf, 0x22}, - {0xd0, 0x00}, - {0xd1, 0x10}, - {0xd2, 0x00}, - {0xd3, 0x00}, - {0xd4, 0x10}, - {0xd5, 0x33}, - {0xd6, 0x80}, - {0xd7, 0x21}, - {0xd8, 0x00}, - {0xd9, 0x00}, - {0xda, 0x00}, - {0xdb, 0x00}, - {0xdc, 0x00}, - {0xdd, 0x00}, - {0xde, 0x00}, - {0xdf, 0x00}, - {0xe0, 0x00}, - {0xe1, 0xB3}, - {0xe2, 0x00}, - {0xe3, 0x00}, - {0xe4, 0x00}, - {0xe5, 0x10}, - {0xe6, 0x00}, - {0xe7, 0x18}, - {0xe8, 0x08}, - {0xe9, 0xd4}, - {0xea, 0x00}, - {0xeb, 0xff}, - {0xec, 0x79}, - {0xed, 0x10}, - {0xee, 0x30}, - {0xef, 0x02}, - {0xf0, 0x00}, - {0xf1, 0x09}, - {0xf2, 0x00}, - {0xf3, 0x00}, - {0xf4, 0x00}, - {0xf5, 0x00}, - {0xf6, 0x00}, - {0xf7, 0x00}, - {0xf8, 0x00}, - {0xf9, 0x00}, - {0xfa, 0x00}, - {0xfb, 0x00}, - {0xfc, 0x00}, - {0xfd, 0x00}, - {0xfe, 0x00}, - {0xff, 0x00}, -}; - -#define CB_VT3253B0_AGC_FOR_RFMD2959 195 -/* For RFMD2959 */ -static -unsigned char vt3253b0_agc4_rfmd2959[CB_VT3253B0_AGC_FOR_RFMD2959][2] = { - {0xF0, 0x00}, - {0xF1, 0x3E}, - {0xF0, 0x80}, - {0xF0, 0x00}, - {0xF1, 0x3E}, - {0xF0, 0x81}, - {0xF0, 0x01}, - {0xF1, 0x3E}, - {0xF0, 0x82}, - {0xF0, 0x02}, - {0xF1, 0x3E}, - {0xF0, 0x83}, - {0xF0, 0x03}, - {0xF1, 0x3B}, - {0xF0, 0x84}, - {0xF0, 0x04}, - {0xF1, 0x39}, - {0xF0, 0x85}, - {0xF0, 0x05}, - {0xF1, 0x38}, - {0xF0, 0x86}, - {0xF0, 0x06}, - {0xF1, 0x37}, - {0xF0, 0x87}, - {0xF0, 0x07}, - {0xF1, 0x36}, - {0xF0, 0x88}, - {0xF0, 0x08}, - {0xF1, 0x35}, - {0xF0, 0x89}, - {0xF0, 0x09}, - {0xF1, 0x35}, - {0xF0, 0x8A}, - {0xF0, 0x0A}, - {0xF1, 0x34}, - {0xF0, 0x8B}, - {0xF0, 0x0B}, - {0xF1, 0x34}, - {0xF0, 0x8C}, - {0xF0, 0x0C}, - {0xF1, 0x33}, - {0xF0, 0x8D}, - {0xF0, 0x0D}, - {0xF1, 0x32}, - {0xF0, 0x8E}, - {0xF0, 0x0E}, - {0xF1, 0x31}, - {0xF0, 0x8F}, - {0xF0, 0x0F}, - {0xF1, 0x30}, - {0xF0, 0x90}, - {0xF0, 0x10}, - {0xF1, 0x2F}, - {0xF0, 0x91}, - {0xF0, 0x11}, - {0xF1, 0x2F}, - {0xF0, 0x92}, - {0xF0, 0x12}, - {0xF1, 0x2E}, - {0xF0, 0x93}, - {0xF0, 0x13}, - {0xF1, 0x2D}, - {0xF0, 0x94}, - {0xF0, 0x14}, - {0xF1, 0x2C}, - {0xF0, 0x95}, - {0xF0, 0x15}, - {0xF1, 0x2B}, - {0xF0, 0x96}, - {0xF0, 0x16}, - {0xF1, 0x2B}, - {0xF0, 0x97}, - {0xF0, 0x17}, - {0xF1, 0x2A}, - {0xF0, 0x98}, - {0xF0, 0x18}, - {0xF1, 0x29}, - {0xF0, 0x99}, - {0xF0, 0x19}, - {0xF1, 0x28}, - {0xF0, 0x9A}, - {0xF0, 0x1A}, - {0xF1, 0x27}, - {0xF0, 0x9B}, - {0xF0, 0x1B}, - {0xF1, 0x26}, - {0xF0, 0x9C}, - {0xF0, 0x1C}, - {0xF1, 0x25}, - {0xF0, 0x9D}, - {0xF0, 0x1D}, - {0xF1, 0x24}, - {0xF0, 0x9E}, - {0xF0, 0x1E}, - {0xF1, 0x24}, - {0xF0, 0x9F}, - {0xF0, 0x1F}, - {0xF1, 0x23}, - {0xF0, 0xA0}, - {0xF0, 0x20}, - {0xF1, 0x22}, - {0xF0, 0xA1}, - {0xF0, 0x21}, - {0xF1, 0x21}, - {0xF0, 0xA2}, - {0xF0, 0x22}, - {0xF1, 0x20}, - {0xF0, 0xA3}, - {0xF0, 0x23}, - {0xF1, 0x20}, - {0xF0, 0xA4}, - {0xF0, 0x24}, - {0xF1, 0x1F}, - {0xF0, 0xA5}, - {0xF0, 0x25}, - {0xF1, 0x1E}, - {0xF0, 0xA6}, - {0xF0, 0x26}, - {0xF1, 0x1D}, - {0xF0, 0xA7}, - {0xF0, 0x27}, - {0xF1, 0x1C}, - {0xF0, 0xA8}, - {0xF0, 0x28}, - {0xF1, 0x1B}, - {0xF0, 0xA9}, - {0xF0, 0x29}, - {0xF1, 0x1B}, - {0xF0, 0xAA}, - {0xF0, 0x2A}, - {0xF1, 0x1A}, - {0xF0, 0xAB}, - {0xF0, 0x2B}, - {0xF1, 0x1A}, - {0xF0, 0xAC}, - {0xF0, 0x2C}, - {0xF1, 0x19}, - {0xF0, 0xAD}, - {0xF0, 0x2D}, - {0xF1, 0x18}, - {0xF0, 0xAE}, - {0xF0, 0x2E}, - {0xF1, 0x17}, - {0xF0, 0xAF}, - {0xF0, 0x2F}, - {0xF1, 0x16}, - {0xF0, 0xB0}, - {0xF0, 0x30}, - {0xF1, 0x15}, - {0xF0, 0xB1}, - {0xF0, 0x31}, - {0xF1, 0x15}, - {0xF0, 0xB2}, - {0xF0, 0x32}, - {0xF1, 0x15}, - {0xF0, 0xB3}, - {0xF0, 0x33}, - {0xF1, 0x14}, - {0xF0, 0xB4}, - {0xF0, 0x34}, - {0xF1, 0x13}, - {0xF0, 0xB5}, - {0xF0, 0x35}, - {0xF1, 0x12}, - {0xF0, 0xB6}, - {0xF0, 0x36}, - {0xF1, 0x11}, - {0xF0, 0xB7}, - {0xF0, 0x37}, - {0xF1, 0x10}, - {0xF0, 0xB8}, - {0xF0, 0x38}, - {0xF1, 0x0F}, - {0xF0, 0xB9}, - {0xF0, 0x39}, - {0xF1, 0x0E}, - {0xF0, 0xBA}, - {0xF0, 0x3A}, - {0xF1, 0x0D}, - {0xF0, 0xBB}, - {0xF0, 0x3B}, - {0xF1, 0x0C}, - {0xF0, 0xBC}, - {0xF0, 0x3C}, - {0xF1, 0x0B}, - {0xF0, 0xBD}, - {0xF0, 0x3D}, - {0xF1, 0x0B}, - {0xF0, 0xBE}, - {0xF0, 0x3E}, - {0xF1, 0x0A}, - {0xF0, 0xBF}, - {0xF0, 0x3F}, - {0xF1, 0x09}, - {0xF0, 0x00}, -}; - -#define CB_VT3253B0_INIT_FOR_AIROHA2230 256 -/* For AIROHA */ -static -unsigned char vt3253b0_airoha2230[CB_VT3253B0_INIT_FOR_AIROHA2230][2] = { - {0x00, 0x31}, - {0x01, 0x00}, - {0x02, 0x00}, - {0x03, 0x00}, - {0x04, 0x00}, - {0x05, 0x80}, - {0x06, 0x00}, - {0x07, 0x00}, - {0x08, 0x70}, - {0x09, 0x41}, - {0x0a, 0x2A}, - {0x0b, 0x76}, - {0x0c, 0x00}, - {0x0d, 0x00}, - {0x0e, 0x80}, - {0x0f, 0x00}, - {0x10, 0x00}, - {0x11, 0x00}, - {0x12, 0x00}, - {0x13, 0x00}, - {0x14, 0x00}, - {0x15, 0x00}, - {0x16, 0x00}, - {0x17, 0x00}, - {0x18, 0x00}, - {0x19, 0x00}, - {0x1a, 0x00}, - {0x1b, 0x8f}, - {0x1c, 0x09}, - {0x1d, 0x00}, - {0x1e, 0x00}, - {0x1f, 0x00}, - {0x20, 0x00}, - {0x21, 0x00}, - {0x22, 0x00}, - {0x23, 0x00}, - {0x24, 0x00}, - {0x25, 0x4a}, - {0x26, 0x00}, - {0x27, 0x00}, - {0x28, 0x00}, - {0x29, 0x00}, - {0x2a, 0x00}, - {0x2b, 0x00}, - {0x2c, 0x00}, - {0x2d, 0x4a}, - {0x2e, 0x00}, - {0x2f, 0x0a}, - {0x30, 0x26}, - {0x31, 0x5b}, - {0x32, 0x00}, - {0x33, 0x00}, - {0x34, 0x00}, - {0x35, 0x00}, - {0x36, 0xaa}, - {0x37, 0xaa}, - {0x38, 0xff}, - {0x39, 0xff}, - {0x3a, 0x79}, - {0x3b, 0x00}, - {0x3c, 0x00}, - {0x3d, 0x0b}, - {0x3e, 0x48}, - {0x3f, 0x04}, - {0x40, 0x00}, - {0x41, 0x08}, - {0x42, 0x00}, - {0x43, 0x08}, - {0x44, 0x08}, - {0x45, 0x14}, - {0x46, 0x05}, - {0x47, 0x09}, - {0x48, 0x00}, - {0x49, 0x00}, - {0x4a, 0x00}, - {0x4b, 0x00}, - {0x4c, 0x09}, - {0x4d, 0x73}, - {0x4e, 0x00}, - {0x4f, 0xc5}, - {0x50, 0x15}, - {0x51, 0x19}, - {0x52, 0x00}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x00}, - {0x56, 0x00}, - {0x57, 0x00}, - {0x58, 0x00}, - {0x59, 0xb0}, - {0x5a, 0x00}, - {0x5b, 0x00}, - {0x5c, 0x00}, - {0x5d, 0x00}, - {0x5e, 0x00}, - {0x5f, 0x00}, - {0x60, 0xe4}, - {0x61, 0x80}, - {0x62, 0x00}, - {0x63, 0x00}, - {0x64, 0x00}, - {0x65, 0x00}, - {0x66, 0x98}, - {0x67, 0x0a}, - {0x68, 0x00}, - {0x69, 0x00}, - {0x6a, 0x00}, - {0x6b, 0x00}, - {0x6c, 0x00}, /* RobertYu:20050125, request by JJSue */ - {0x6d, 0x03}, - {0x6e, 0x01}, - {0x6f, 0x00}, - {0x70, 0x00}, - {0x71, 0x00}, - {0x72, 0x00}, - {0x73, 0x00}, - {0x74, 0x00}, - {0x75, 0x00}, - {0x76, 0x00}, - {0x77, 0x00}, - {0x78, 0x00}, - {0x79, 0x00}, - {0x7a, 0x00}, - {0x7b, 0x00}, - {0x7c, 0x00}, - {0x7d, 0x00}, - {0x7e, 0x00}, - {0x7f, 0x00}, - {0x80, 0x8c}, - {0x81, 0x01}, - {0x82, 0x09}, - {0x83, 0x00}, - {0x84, 0x00}, - {0x85, 0x00}, - {0x86, 0x00}, - {0x87, 0x00}, - {0x88, 0x08}, - {0x89, 0x00}, - {0x8a, 0x0f}, - {0x8b, 0xb7}, - {0x8c, 0x88}, - {0x8d, 0x47}, - {0x8e, 0xaa}, - {0x8f, 0x02}, - {0x90, 0x22}, - {0x91, 0x00}, - {0x92, 0x00}, - {0x93, 0x00}, - {0x94, 0x00}, - {0x95, 0x00}, - {0x96, 0x00}, - {0x97, 0xeb}, - {0x98, 0x00}, - {0x99, 0x00}, - {0x9a, 0x00}, - {0x9b, 0x00}, - {0x9c, 0x00}, - {0x9d, 0x00}, - {0x9e, 0x00}, - {0x9f, 0x01}, - {0xa0, 0x00}, - {0xa1, 0x00}, - {0xa2, 0x00}, - {0xa3, 0x00}, - {0xa4, 0x00}, - {0xa5, 0x00}, - {0xa6, 0x10}, - {0xa7, 0x00}, - {0xa8, 0x18}, - {0xa9, 0x00}, - {0xaa, 0x00}, - {0xab, 0x00}, - {0xac, 0x00}, - {0xad, 0x00}, - {0xae, 0x00}, - {0xaf, 0x18}, - {0xb0, 0x38}, - {0xb1, 0x30}, - {0xb2, 0x00}, - {0xb3, 0x00}, - {0xb4, 0xff}, - {0xb5, 0x0f}, - {0xb6, 0xe4}, - {0xb7, 0xe2}, - {0xb8, 0x00}, - {0xb9, 0x00}, - {0xba, 0x00}, - {0xbb, 0x03}, - {0xbc, 0x01}, - {0xbd, 0x00}, - {0xbe, 0x00}, - {0xbf, 0x00}, - {0xc0, 0x18}, - {0xc1, 0x20}, - {0xc2, 0x07}, - {0xc3, 0x18}, - {0xc4, 0xff}, - {0xc5, 0x2c}, - {0xc6, 0x0c}, - {0xc7, 0x0a}, - {0xc8, 0x0e}, - {0xc9, 0x01}, - {0xca, 0x68}, - {0xcb, 0xa7}, - {0xcc, 0x3c}, - {0xcd, 0x10}, - {0xce, 0x00}, - {0xcf, 0x25}, - {0xd0, 0x40}, - {0xd1, 0x12}, - {0xd2, 0x00}, - {0xd3, 0x00}, - {0xd4, 0x10}, - {0xd5, 0x28}, - {0xd6, 0x80}, - {0xd7, 0x2A}, - {0xd8, 0x00}, - {0xd9, 0x00}, - {0xda, 0x00}, - {0xdb, 0x00}, - {0xdc, 0x00}, - {0xdd, 0x00}, - {0xde, 0x00}, - {0xdf, 0x00}, - {0xe0, 0x00}, - {0xe1, 0xB3}, - {0xe2, 0x00}, - {0xe3, 0x00}, - {0xe4, 0x00}, - {0xe5, 0x10}, - {0xe6, 0x00}, - {0xe7, 0x1C}, - {0xe8, 0x00}, - {0xe9, 0xf4}, - {0xea, 0x00}, - {0xeb, 0xff}, - {0xec, 0x79}, - {0xed, 0x20}, - {0xee, 0x30}, - {0xef, 0x01}, - {0xf0, 0x00}, - {0xf1, 0x3e}, - {0xf2, 0x00}, - {0xf3, 0x00}, - {0xf4, 0x00}, - {0xf5, 0x00}, - {0xf6, 0x00}, - {0xf7, 0x00}, - {0xf8, 0x00}, - {0xf9, 0x00}, - {0xfa, 0x00}, - {0xfb, 0x00}, - {0xfc, 0x00}, - {0xfd, 0x00}, - {0xfe, 0x00}, - {0xff, 0x00}, -}; - -#define CB_VT3253B0_INIT_FOR_UW2451 256 -/* For UW2451 */ -static unsigned char vt3253b0_uw2451[CB_VT3253B0_INIT_FOR_UW2451][2] = { - {0x00, 0x31}, - {0x01, 0x00}, - {0x02, 0x00}, - {0x03, 0x00}, - {0x04, 0x00}, - {0x05, 0x81}, - {0x06, 0x00}, - {0x07, 0x00}, - {0x08, 0x38}, - {0x09, 0x45}, - {0x0a, 0x28}, - {0x0b, 0x76}, - {0x0c, 0x00}, - {0x0d, 0x00}, - {0x0e, 0x80}, - {0x0f, 0x00}, - {0x10, 0x00}, - {0x11, 0x00}, - {0x12, 0x00}, - {0x13, 0x00}, - {0x14, 0x00}, - {0x15, 0x00}, - {0x16, 0x00}, - {0x17, 0x00}, - {0x18, 0x00}, - {0x19, 0x00}, - {0x1a, 0x00}, - {0x1b, 0x8f}, - {0x1c, 0x0f}, - {0x1d, 0x00}, - {0x1e, 0x00}, - {0x1f, 0x00}, - {0x20, 0x00}, - {0x21, 0x00}, - {0x22, 0x00}, - {0x23, 0x00}, - {0x24, 0x00}, - {0x25, 0x4a}, - {0x26, 0x00}, - {0x27, 0x00}, - {0x28, 0x00}, - {0x29, 0x00}, - {0x2a, 0x00}, - {0x2b, 0x00}, - {0x2c, 0x00}, - {0x2d, 0x18}, - {0x2e, 0x00}, - {0x2f, 0x0a}, - {0x30, 0x26}, - {0x31, 0x5b}, - {0x32, 0x00}, - {0x33, 0x00}, - {0x34, 0x00}, - {0x35, 0x00}, - {0x36, 0xaa}, - {0x37, 0xaa}, - {0x38, 0xff}, - {0x39, 0xff}, - {0x3a, 0x00}, - {0x3b, 0x00}, - {0x3c, 0x00}, - {0x3d, 0x03}, - {0x3e, 0x1d}, - {0x3f, 0x04}, - {0x40, 0x00}, - {0x41, 0x08}, - {0x42, 0x00}, - {0x43, 0x08}, - {0x44, 0x08}, - {0x45, 0x14}, - {0x46, 0x05}, - {0x47, 0x09}, - {0x48, 0x00}, - {0x49, 0x00}, - {0x4a, 0x00}, - {0x4b, 0x00}, - {0x4c, 0x09}, - {0x4d, 0x90}, - {0x4e, 0x00}, - {0x4f, 0xc5}, - {0x50, 0x15}, - {0x51, 0x19}, - {0x52, 0x00}, - {0x53, 0x00}, - {0x54, 0x00}, - {0x55, 0x00}, - {0x56, 0x00}, - {0x57, 0x00}, - {0x58, 0x00}, - {0x59, 0xb0}, - {0x5a, 0x00}, - {0x5b, 0x00}, - {0x5c, 0x00}, - {0x5d, 0x00}, - {0x5e, 0x00}, - {0x5f, 0x00}, - {0x60, 0xb3}, - {0x61, 0x81}, - {0x62, 0x00}, - {0x63, 0x00}, - {0x64, 0x00}, - {0x65, 0x00}, - {0x66, 0x57}, - {0x67, 0x6c}, - {0x68, 0x00}, - {0x69, 0x00}, - {0x6a, 0x00}, - {0x6b, 0x00}, - {0x6c, 0x00}, /* RobertYu:20050125, request by JJSue */ - {0x6d, 0x03}, - {0x6e, 0x01}, - {0x6f, 0x00}, - {0x70, 0x00}, - {0x71, 0x00}, - {0x72, 0x00}, - {0x73, 0x00}, - {0x74, 0x00}, - {0x75, 0x00}, - {0x76, 0x00}, - {0x77, 0x00}, - {0x78, 0x00}, - {0x79, 0x00}, - {0x7a, 0x00}, - {0x7b, 0x00}, - {0x7c, 0x00}, - {0x7d, 0x00}, - {0x7e, 0x00}, - {0x7f, 0x00}, - {0x80, 0x8c}, - {0x81, 0x00}, - {0x82, 0x0e}, - {0x83, 0x00}, - {0x84, 0x00}, - {0x85, 0x00}, - {0x86, 0x00}, - {0x87, 0x00}, - {0x88, 0x08}, - {0x89, 0x00}, - {0x8a, 0x0e}, - {0x8b, 0xa7}, - {0x8c, 0x88}, - {0x8d, 0x47}, - {0x8e, 0xaa}, - {0x8f, 0x02}, - {0x90, 0x00}, - {0x91, 0x00}, - {0x92, 0x00}, - {0x93, 0x00}, - {0x94, 0x00}, - {0x95, 0x00}, - {0x96, 0x00}, - {0x97, 0xe3}, - {0x98, 0x00}, - {0x99, 0x00}, - {0x9a, 0x00}, - {0x9b, 0x00}, - {0x9c, 0x00}, - {0x9d, 0x00}, - {0x9e, 0x00}, - {0x9f, 0x00}, - {0xa0, 0x00}, - {0xa1, 0x00}, - {0xa2, 0x00}, - {0xa3, 0x00}, - {0xa4, 0x00}, - {0xa5, 0x00}, - {0xa6, 0x10}, - {0xa7, 0x00}, - {0xa8, 0x18}, - {0xa9, 0x00}, - {0xaa, 0x00}, - {0xab, 0x00}, - {0xac, 0x00}, - {0xad, 0x00}, - {0xae, 0x00}, - {0xaf, 0x18}, - {0xb0, 0x18}, - {0xb1, 0x30}, - {0xb2, 0x00}, - {0xb3, 0x00}, - {0xb4, 0x00}, - {0xb5, 0x00}, - {0xb6, 0x00}, - {0xb7, 0x00}, - {0xb8, 0x00}, - {0xb9, 0x00}, - {0xba, 0x00}, - {0xbb, 0x03}, - {0xbc, 0x01}, - {0xbd, 0x00}, - {0xbe, 0x00}, - {0xbf, 0x00}, - {0xc0, 0x10}, - {0xc1, 0x20}, - {0xc2, 0x00}, - {0xc3, 0x20}, - {0xc4, 0x00}, - {0xc5, 0x2c}, - {0xc6, 0x1c}, - {0xc7, 0x10}, - {0xc8, 0x10}, - {0xc9, 0x01}, - {0xca, 0x68}, - {0xcb, 0xa7}, - {0xcc, 0x3c}, - {0xcd, 0x09}, - {0xce, 0x00}, - {0xcf, 0x20}, - {0xd0, 0x40}, - {0xd1, 0x10}, - {0xd2, 0x00}, - {0xd3, 0x00}, - {0xd4, 0x20}, - {0xd5, 0x28}, - {0xd6, 0xa0}, - {0xd7, 0x2a}, - {0xd8, 0x00}, - {0xd9, 0x00}, - {0xda, 0x00}, - {0xdb, 0x00}, - {0xdc, 0x00}, - {0xdd, 0x00}, - {0xde, 0x00}, - {0xdf, 0x00}, - {0xe0, 0x00}, - {0xe1, 0xd3}, - {0xe2, 0xc0}, - {0xe3, 0x00}, - {0xe4, 0x00}, - {0xe5, 0x10}, - {0xe6, 0x00}, - {0xe7, 0x12}, - {0xe8, 0x12}, - {0xe9, 0x34}, - {0xea, 0x00}, - {0xeb, 0xff}, - {0xec, 0x79}, - {0xed, 0x20}, - {0xee, 0x30}, - {0xef, 0x01}, - {0xf0, 0x00}, - {0xf1, 0x3e}, - {0xf2, 0x00}, - {0xf3, 0x00}, - {0xf4, 0x00}, - {0xf5, 0x00}, - {0xf6, 0x00}, - {0xf7, 0x00}, - {0xf8, 0x00}, - {0xf9, 0x00}, - {0xfa, 0x00}, - {0xfb, 0x00}, - {0xfc, 0x00}, - {0xfd, 0x00}, - {0xfe, 0x00}, - {0xff, 0x00}, -}; - -#define CB_VT3253B0_AGC 193 -/* For AIROHA */ -static unsigned char vt3253b0_agc[CB_VT3253B0_AGC][2] = { - {0xF0, 0x00}, - {0xF1, 0x00}, - {0xF0, 0x80}, - {0xF0, 0x01}, - {0xF1, 0x00}, - {0xF0, 0x81}, - {0xF0, 0x02}, - {0xF1, 0x02}, - {0xF0, 0x82}, - {0xF0, 0x03}, - {0xF1, 0x04}, - {0xF0, 0x83}, - {0xF0, 0x03}, - {0xF1, 0x04}, - {0xF0, 0x84}, - {0xF0, 0x04}, - {0xF1, 0x06}, - {0xF0, 0x85}, - {0xF0, 0x05}, - {0xF1, 0x06}, - {0xF0, 0x86}, - {0xF0, 0x06}, - {0xF1, 0x06}, - {0xF0, 0x87}, - {0xF0, 0x07}, - {0xF1, 0x08}, - {0xF0, 0x88}, - {0xF0, 0x08}, - {0xF1, 0x08}, - {0xF0, 0x89}, - {0xF0, 0x09}, - {0xF1, 0x0A}, - {0xF0, 0x8A}, - {0xF0, 0x0A}, - {0xF1, 0x0A}, - {0xF0, 0x8B}, - {0xF0, 0x0B}, - {0xF1, 0x0C}, - {0xF0, 0x8C}, - {0xF0, 0x0C}, - {0xF1, 0x0C}, - {0xF0, 0x8D}, - {0xF0, 0x0D}, - {0xF1, 0x0E}, - {0xF0, 0x8E}, - {0xF0, 0x0E}, - {0xF1, 0x0E}, - {0xF0, 0x8F}, - {0xF0, 0x0F}, - {0xF1, 0x10}, - {0xF0, 0x90}, - {0xF0, 0x10}, - {0xF1, 0x10}, - {0xF0, 0x91}, - {0xF0, 0x11}, - {0xF1, 0x12}, - {0xF0, 0x92}, - {0xF0, 0x12}, - {0xF1, 0x12}, - {0xF0, 0x93}, - {0xF0, 0x13}, - {0xF1, 0x14}, - {0xF0, 0x94}, - {0xF0, 0x14}, - {0xF1, 0x14}, - {0xF0, 0x95}, - {0xF0, 0x15}, - {0xF1, 0x16}, - {0xF0, 0x96}, - {0xF0, 0x16}, - {0xF1, 0x16}, - {0xF0, 0x97}, - {0xF0, 0x17}, - {0xF1, 0x18}, - {0xF0, 0x98}, - {0xF0, 0x18}, - {0xF1, 0x18}, - {0xF0, 0x99}, - {0xF0, 0x19}, - {0xF1, 0x1A}, - {0xF0, 0x9A}, - {0xF0, 0x1A}, - {0xF1, 0x1A}, - {0xF0, 0x9B}, - {0xF0, 0x1B}, - {0xF1, 0x1C}, - {0xF0, 0x9C}, - {0xF0, 0x1C}, - {0xF1, 0x1C}, - {0xF0, 0x9D}, - {0xF0, 0x1D}, - {0xF1, 0x1E}, - {0xF0, 0x9E}, - {0xF0, 0x1E}, - {0xF1, 0x1E}, - {0xF0, 0x9F}, - {0xF0, 0x1F}, - {0xF1, 0x20}, - {0xF0, 0xA0}, - {0xF0, 0x20}, - {0xF1, 0x20}, - {0xF0, 0xA1}, - {0xF0, 0x21}, - {0xF1, 0x22}, - {0xF0, 0xA2}, - {0xF0, 0x22}, - {0xF1, 0x22}, - {0xF0, 0xA3}, - {0xF0, 0x23}, - {0xF1, 0x24}, - {0xF0, 0xA4}, - {0xF0, 0x24}, - {0xF1, 0x24}, - {0xF0, 0xA5}, - {0xF0, 0x25}, - {0xF1, 0x26}, - {0xF0, 0xA6}, - {0xF0, 0x26}, - {0xF1, 0x26}, - {0xF0, 0xA7}, - {0xF0, 0x27}, - {0xF1, 0x28}, - {0xF0, 0xA8}, - {0xF0, 0x28}, - {0xF1, 0x28}, - {0xF0, 0xA9}, - {0xF0, 0x29}, - {0xF1, 0x2A}, - {0xF0, 0xAA}, - {0xF0, 0x2A}, - {0xF1, 0x2A}, - {0xF0, 0xAB}, - {0xF0, 0x2B}, - {0xF1, 0x2C}, - {0xF0, 0xAC}, - {0xF0, 0x2C}, - {0xF1, 0x2C}, - {0xF0, 0xAD}, - {0xF0, 0x2D}, - {0xF1, 0x2E}, - {0xF0, 0xAE}, - {0xF0, 0x2E}, - {0xF1, 0x2E}, - {0xF0, 0xAF}, - {0xF0, 0x2F}, - {0xF1, 0x30}, - {0xF0, 0xB0}, - {0xF0, 0x30}, - {0xF1, 0x30}, - {0xF0, 0xB1}, - {0xF0, 0x31}, - {0xF1, 0x32}, - {0xF0, 0xB2}, - {0xF0, 0x32}, - {0xF1, 0x32}, - {0xF0, 0xB3}, - {0xF0, 0x33}, - {0xF1, 0x34}, - {0xF0, 0xB4}, - {0xF0, 0x34}, - {0xF1, 0x34}, - {0xF0, 0xB5}, - {0xF0, 0x35}, - {0xF1, 0x36}, - {0xF0, 0xB6}, - {0xF0, 0x36}, - {0xF1, 0x36}, - {0xF0, 0xB7}, - {0xF0, 0x37}, - {0xF1, 0x38}, - {0xF0, 0xB8}, - {0xF0, 0x38}, - {0xF1, 0x38}, - {0xF0, 0xB9}, - {0xF0, 0x39}, - {0xF1, 0x3A}, - {0xF0, 0xBA}, - {0xF0, 0x3A}, - {0xF1, 0x3A}, - {0xF0, 0xBB}, - {0xF0, 0x3B}, - {0xF1, 0x3C}, - {0xF0, 0xBC}, - {0xF0, 0x3C}, - {0xF1, 0x3C}, - {0xF0, 0xBD}, - {0xF0, 0x3D}, - {0xF1, 0x3E}, - {0xF0, 0xBE}, - {0xF0, 0x3E}, - {0xF1, 0x3E}, - {0xF0, 0xBF}, - {0xF0, 0x00}, -}; - -static const unsigned short awc_frame_time[MAX_RATE] = { - 10, 20, 55, 110, 24, 36, 48, 72, 96, 144, 192, 216 -}; - -/*--------------------- Export Variables --------------------------*/ -/* - * Description: Calculate data frame transmitting time - * - * Parameters: - * In: - * preamble_type - Preamble Type - * by_pkt_type - PK_TYPE_11A, PK_TYPE_11B, PK_TYPE_11GB, PK_TYPE_11GA - * cb_frame_length - Baseband Type - * tx_rate - Tx Rate - * Out: - * - * Return Value: FrameTime - * - */ -unsigned int bb_get_frame_time(unsigned char preamble_type, - unsigned char by_pkt_type, - unsigned int cb_frame_length, - unsigned short tx_rate) -{ - unsigned int frame_time; - unsigned int preamble; - unsigned int tmp; - unsigned int rate_idx = (unsigned int)tx_rate; - unsigned int rate = 0; - - if (rate_idx > RATE_54M) - return 0; - - rate = (unsigned int)awc_frame_time[rate_idx]; - - if (rate_idx <= 3) { /* CCK mode */ - if (preamble_type == PREAMBLE_SHORT) - preamble = 96; - else - preamble = 192; - frame_time = (cb_frame_length * 80) / rate; /* ????? */ - tmp = (frame_time * rate) / 80; - if (cb_frame_length != tmp) - frame_time++; - - return preamble + frame_time; - } - frame_time = (cb_frame_length * 8 + 22) / rate; /* ???????? */ - tmp = ((frame_time * rate) - 22) / 8; - if (cb_frame_length != tmp) - frame_time++; - - frame_time = frame_time * 4; /* ??????? */ - if (by_pkt_type != PK_TYPE_11A) - frame_time += 6; /* ?????? */ - - return 20 + frame_time; /* ?????? */ -} - -/* - * Description: Calculate Length, Service, and Signal fields of Phy for Tx - * - * Parameters: - * In: - * priv - Device Structure - * frame_length - Tx Frame Length - * tx_rate - Tx Rate - * Out: - * struct vnt_phy_field *phy - * - pointer to Phy Length field - * - pointer to Phy Service field - * - pointer to Phy Signal field - * - * Return Value: none - * - */ -void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length, - u16 tx_rate, u8 pkt_type, struct vnt_phy_field *phy) -{ - u32 bit_count; - u32 count = 0; - u32 tmp; - int ext_bit; - u8 preamble_type = priv->preamble_type; - - bit_count = frame_length * 8; - ext_bit = false; - - switch (tx_rate) { - case RATE_1M: - count = bit_count; - - phy->signal = 0x00; - - break; - case RATE_2M: - count = bit_count / 2; - - if (preamble_type == PREAMBLE_SHORT) - phy->signal = 0x09; - else - phy->signal = 0x01; - - break; - case RATE_5M: - count = (bit_count * 10) / 55; - tmp = (count * 55) / 10; - - if (tmp != bit_count) - count++; - - if (preamble_type == PREAMBLE_SHORT) - phy->signal = 0x0a; - else - phy->signal = 0x02; - - break; - case RATE_11M: - count = bit_count / 11; - tmp = count * 11; - - if (tmp != bit_count) { - count++; - - if ((bit_count - tmp) <= 3) - ext_bit = true; - } - - if (preamble_type == PREAMBLE_SHORT) - phy->signal = 0x0b; - else - phy->signal = 0x03; - - break; - case RATE_6M: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x9b; - else - phy->signal = 0x8b; - - break; - case RATE_9M: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x9f; - else - phy->signal = 0x8f; - - break; - case RATE_12M: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x9a; - else - phy->signal = 0x8a; - - break; - case RATE_18M: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x9e; - else - phy->signal = 0x8e; - - break; - case RATE_24M: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x99; - else - phy->signal = 0x89; - - break; - case RATE_36M: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x9d; - else - phy->signal = 0x8d; - - break; - case RATE_48M: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x98; - else - phy->signal = 0x88; - - break; - case RATE_54M: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x9c; - else - phy->signal = 0x8c; - break; - default: - if (pkt_type == PK_TYPE_11A) - phy->signal = 0x9c; - else - phy->signal = 0x8c; - break; - } - - if (pkt_type == PK_TYPE_11B) { - phy->service = 0x00; - if (ext_bit) - phy->service |= 0x80; - phy->len = cpu_to_le16((u16)count); - } else { - phy->service = 0x00; - phy->len = cpu_to_le16((u16)frame_length); - } -} - -/* - * Description: Read a byte from BASEBAND, by embedded programming - * - * Parameters: - * In: - * iobase - I/O base address - * by_bb_addr - address of register in Baseband - * Out: - * pby_data - data read - * - * Return Value: true if succeeded; false if failed. - * - */ -bool bb_read_embedded(struct vnt_private *priv, unsigned char by_bb_addr, - unsigned char *pby_data) -{ - void __iomem *iobase = priv->port_offset; - unsigned short ww; - unsigned char by_value; - - /* BB reg offset */ - iowrite8(by_bb_addr, iobase + MAC_REG_BBREGADR); - - /* turn on REGR */ - vt6655_mac_reg_bits_on(iobase, MAC_REG_BBREGCTL, BBREGCTL_REGR); - /* W_MAX_TIMEOUT is the timeout period */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - by_value = ioread8(iobase + MAC_REG_BBREGCTL); - if (by_value & BBREGCTL_DONE) - break; - } - - /* get BB data */ - *pby_data = ioread8(iobase + MAC_REG_BBREGDATA); - - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x30)\n"); - return false; - } - return true; -} - -/* - * Description: Write a Byte to BASEBAND, by embedded programming - * - * Parameters: - * In: - * iobase - I/O base address - * by_bb_addr - address of register in Baseband - * by_data - data to write - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ -bool bb_write_embedded(struct vnt_private *priv, unsigned char by_bb_addr, - unsigned char by_data) -{ - void __iomem *iobase = priv->port_offset; - unsigned short ww; - unsigned char by_value; - - /* BB reg offset */ - iowrite8(by_bb_addr, iobase + MAC_REG_BBREGADR); - /* set BB data */ - iowrite8(by_data, iobase + MAC_REG_BBREGDATA); - - /* turn on BBREGCTL_REGW */ - vt6655_mac_reg_bits_on(iobase, MAC_REG_BBREGCTL, BBREGCTL_REGW); - /* W_MAX_TIMEOUT is the timeout period */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - by_value = ioread8(iobase + MAC_REG_BBREGCTL); - if (by_value & BBREGCTL_DONE) - break; - } - - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x31)\n"); - return false; - } - return true; -} - -/* - * Description: VIA VT3253 Baseband chip init function - * - * Parameters: - * In: - * iobase - I/O base address - * byRevId - Revision ID - * rf_type - RF type - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ - -bool bb_vt3253_init(struct vnt_private *priv) -{ - bool result = true; - int ii; - void __iomem *iobase = priv->port_offset; - unsigned char rf_type = priv->rf_type; - unsigned char by_local_id = priv->local_id; - - if (rf_type == RF_RFMD2959) { - if (by_local_id <= REV_ID_VT3253_A1) { - for (ii = 0; ii < CB_VT3253_INIT_FOR_RFMD; ii++) - result &= bb_write_embedded(priv, - by_vt3253_init_tab_rfmd[ii][0], - by_vt3253_init_tab_rfmd[ii][1]); - - } else { - for (ii = 0; ii < CB_VT3253B0_INIT_FOR_RFMD; ii++) - result &= bb_write_embedded(priv, - vt3253b0_rfmd[ii][0], - vt3253b0_rfmd[ii][1]); - - for (ii = 0; ii < CB_VT3253B0_AGC_FOR_RFMD2959; ii++) - result &= bb_write_embedded(priv, - vt3253b0_agc4_rfmd2959[ii][0], - vt3253b0_agc4_rfmd2959[ii][1]); - - iowrite32(0x23, iobase + MAC_REG_ITRTMSET); - vt6655_mac_reg_bits_on(iobase, MAC_REG_PAPEDELAY, BIT(0)); - } - priv->bbvga[0] = 0x18; - priv->bbvga[1] = 0x0A; - priv->bbvga[2] = 0x0; - priv->bbvga[3] = 0x0; - priv->dbm_threshold[0] = -70; - priv->dbm_threshold[1] = -50; - priv->dbm_threshold[2] = 0; - priv->dbm_threshold[3] = 0; - } else if ((rf_type == RF_AIROHA) || (rf_type == RF_AL2230S)) { - for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) - result &= bb_write_embedded(priv, - vt3253b0_airoha2230[ii][0], - vt3253b0_airoha2230[ii][1]); - - for (ii = 0; ii < CB_VT3253B0_AGC; ii++) - result &= bb_write_embedded(priv, - vt3253b0_agc[ii][0], vt3253b0_agc[ii][1]); - - priv->bbvga[0] = 0x1C; - priv->bbvga[1] = 0x10; - priv->bbvga[2] = 0x0; - priv->bbvga[3] = 0x0; - priv->dbm_threshold[0] = -70; - priv->dbm_threshold[1] = -48; - priv->dbm_threshold[2] = 0; - priv->dbm_threshold[3] = 0; - } else if (rf_type == RF_UW2451) { - for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) - result &= bb_write_embedded(priv, - vt3253b0_uw2451[ii][0], - vt3253b0_uw2451[ii][1]); - - for (ii = 0; ii < CB_VT3253B0_AGC; ii++) - result &= bb_write_embedded(priv, - vt3253b0_agc[ii][0], - vt3253b0_agc[ii][1]); - - iowrite8(0x23, iobase + MAC_REG_ITRTMSET); - vt6655_mac_reg_bits_on(iobase, MAC_REG_PAPEDELAY, BIT(0)); - - priv->bbvga[0] = 0x14; - priv->bbvga[1] = 0x0A; - priv->bbvga[2] = 0x0; - priv->bbvga[3] = 0x0; - priv->dbm_threshold[0] = -60; - priv->dbm_threshold[1] = -50; - priv->dbm_threshold[2] = 0; - priv->dbm_threshold[3] = 0; - } else if (rf_type == RF_VT3226) { - for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) - result &= bb_write_embedded(priv, - vt3253b0_airoha2230[ii][0], - vt3253b0_airoha2230[ii][1]); - - for (ii = 0; ii < CB_VT3253B0_AGC; ii++) - result &= bb_write_embedded(priv, - vt3253b0_agc[ii][0], vt3253b0_agc[ii][1]); - - priv->bbvga[0] = 0x1C; - priv->bbvga[1] = 0x10; - priv->bbvga[2] = 0x0; - priv->bbvga[3] = 0x0; - priv->dbm_threshold[0] = -70; - priv->dbm_threshold[1] = -48; - priv->dbm_threshold[2] = 0; - priv->dbm_threshold[3] = 0; - /* Fix VT3226 DFC system timing issue */ - vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_RFLEOPT); - /* {{ RobertYu: 20050104 */ - } else { - /* No VGA Table now */ - priv->update_bbvga = false; - priv->bbvga[0] = 0x1C; - } - - if (by_local_id > REV_ID_VT3253_A1) { - bb_write_embedded(priv, 0x04, 0x7F); - bb_write_embedded(priv, 0x0D, 0x01); - } - - return result; -} - -/* - * Description: Set ShortSlotTime mode - * - * Parameters: - * In: - * priv - Device Structure - * Out: - * none - * - * Return Value: none - * - */ -void -bb_set_short_slot_time(struct vnt_private *priv) -{ - unsigned char by_bb_rx_conf = 0; - unsigned char by_bb_vga = 0; - - bb_read_embedded(priv, 0x0A, &by_bb_rx_conf); /* CR10 */ - - if (priv->short_slot_time) - by_bb_rx_conf &= 0xDF; /* 1101 1111 */ - else - by_bb_rx_conf |= 0x20; /* 0010 0000 */ - - /* patch for 3253B0 Baseband with Cardbus module */ - bb_read_embedded(priv, 0xE7, &by_bb_vga); - if (by_bb_vga == priv->bbvga[0]) - by_bb_rx_conf |= 0x20; /* 0010 0000 */ - - bb_write_embedded(priv, 0x0A, by_bb_rx_conf); /* CR10 */ -} - -void bb_set_vga_gain_offset(struct vnt_private *priv, unsigned char by_data) -{ - unsigned char by_bb_rx_conf = 0; - - bb_write_embedded(priv, 0xE7, by_data); - - bb_read_embedded(priv, 0x0A, &by_bb_rx_conf); /* CR10 */ - /* patch for 3253B0 Baseband with Cardbus module */ - if (by_data == priv->bbvga[0]) - by_bb_rx_conf |= 0x20; /* 0010 0000 */ - else if (priv->short_slot_time) - by_bb_rx_conf &= 0xDF; /* 1101 1111 */ - else - by_bb_rx_conf |= 0x20; /* 0010 0000 */ - priv->bbvga_current = by_data; - bb_write_embedded(priv, 0x0A, by_bb_rx_conf); /* CR10 */ -} - -/* - * Description: Baseband SoftwareReset - * - * Parameters: - * In: - * iobase - I/O base address - * Out: - * none - * - * Return Value: none - * - */ -void -bb_software_reset(struct vnt_private *priv) -{ - bb_write_embedded(priv, 0x50, 0x40); - bb_write_embedded(priv, 0x50, 0); - bb_write_embedded(priv, 0x9C, 0x01); - bb_write_embedded(priv, 0x9C, 0); -} - -/* - * Description: Set Tx Antenna mode - * - * Parameters: - * In: - * priv - Device Structure - * by_antenna_mode - Antenna Mode - * Out: - * none - * - * Return Value: none - * - */ - -void -bb_set_tx_antenna_mode(struct vnt_private *priv, unsigned char by_antenna_mode) -{ - unsigned char by_bb_tx_conf; - - bb_read_embedded(priv, 0x09, &by_bb_tx_conf); /* CR09 */ - if (by_antenna_mode == ANT_DIVERSITY) { - /* bit 1 is diversity */ - by_bb_tx_conf |= 0x02; - } else if (by_antenna_mode == ANT_A) { - /* bit 2 is ANTSEL */ - by_bb_tx_conf &= 0xF9; /* 1111 1001 */ - } else if (by_antenna_mode == ANT_B) { - by_bb_tx_conf &= 0xFD; /* 1111 1101 */ - by_bb_tx_conf |= 0x04; - } - bb_write_embedded(priv, 0x09, by_bb_tx_conf); /* CR09 */ -} - -/* - * Description: Set Rx Antenna mode - * - * Parameters: - * In: - * priv - Device Structure - * by_antenna_mode - Antenna Mode - * Out: - * none - * - * Return Value: none - * - */ - -void -bb_set_rx_antenna_mode(struct vnt_private *priv, unsigned char by_antenna_mode) -{ - unsigned char by_bb_rx_conf; - - bb_read_embedded(priv, 0x0A, &by_bb_rx_conf); /* CR10 */ - if (by_antenna_mode == ANT_DIVERSITY) { - by_bb_rx_conf |= 0x01; - - } else if (by_antenna_mode == ANT_A) { - by_bb_rx_conf &= 0xFC; /* 1111 1100 */ - } else if (by_antenna_mode == ANT_B) { - by_bb_rx_conf &= 0xFE; /* 1111 1110 */ - by_bb_rx_conf |= 0x02; - } - bb_write_embedded(priv, 0x0A, by_bb_rx_conf); /* CR10 */ -} - -/* - * Description: bb_set_deep_sleep - * - * Parameters: - * In: - * priv - Device Structure - * Out: - * none - * - * Return Value: none - * - */ -void -bb_set_deep_sleep(struct vnt_private *priv, unsigned char by_local_id) -{ - bb_write_embedded(priv, 0x0C, 0x17); /* CR12 */ - bb_write_embedded(priv, 0x0D, 0xB9); /* CR13 */ -} - diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h deleted file mode 100644 index e4a02c240a1c1c..00000000000000 --- a/drivers/staging/vt6655/baseband.h +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions to access baseband - * - * Author: Jerry Chen - * - * Date: Jun. 5, 2002 - * - */ - -#ifndef __BASEBAND_H__ -#define __BASEBAND_H__ - -#include "device.h" - -/* - * Registers in the BASEBAND - */ -#define BB_MAX_CONTEXT_SIZE 256 - -/* - * Baseband RF pair definition in eeprom (Bits 6..0) - */ - -#define PREAMBLE_LONG 0 -#define PREAMBLE_SHORT 1 - -#define F5G 0 -#define F2_4G 1 - -#define TOP_RATE_54M 0x80000000 -#define TOP_RATE_48M 0x40000000 -#define TOP_RATE_36M 0x20000000 -#define TOP_RATE_24M 0x10000000 -#define TOP_RATE_18M 0x08000000 -#define TOP_RATE_12M 0x04000000 -#define TOP_RATE_11M 0x02000000 -#define TOP_RATE_9M 0x01000000 -#define TOP_RATE_6M 0x00800000 -#define TOP_RATE_55M 0x00400000 -#define TOP_RATE_2M 0x00200000 -#define TOP_RATE_1M 0x00100000 - -unsigned int bb_get_frame_time(unsigned char preamble_type, - unsigned char by_pkt_type, - unsigned int cb_frame_length, - unsigned short w_rate); - -void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length, - u16 tx_rate, u8 pkt_type, struct vnt_phy_field *phy); - -bool bb_read_embedded(struct vnt_private *priv, unsigned char by_bb_addr, - unsigned char *pby_data); -bool bb_write_embedded(struct vnt_private *priv, unsigned char by_bb_addr, - unsigned char by_data); - -void bb_set_short_slot_time(struct vnt_private *priv); -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_set_tx_antenna_mode(struct vnt_private *priv, - unsigned char by_antenna_mode); -void bb_set_rx_antenna_mode(struct vnt_private *priv, - unsigned char by_antenna_mode); -void bb_set_deep_sleep(struct vnt_private *priv, unsigned char by_local_id); - -#endif /* __BASEBAND_H__ */ diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c deleted file mode 100644 index 6a2e390e94939a..00000000000000 --- a/drivers/staging/vt6655/card.c +++ /dev/null @@ -1,836 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Provide functions to setup NIC operation mode - * Functions: - * s_vSafeResetTx - Rest Tx - * card_set_rspinf - Set RSPINF - * CARDvUpdateBasicTopRate - Update BasicTopRate - * CARDbAddBasicRate - Add to BasicRateSet - * CARDbIsOFDMinBasicRate - Check if any OFDM rate is in BasicRateSet - * card_get_tsf_offset - Calculate TSFOffset - * vt6655_get_current_tsf - Read Current NIC TSF counter - * card_get_next_tbtt - Calculate Next Beacon TSF counter - * CARDvSetFirstNextTBTT - Set NIC Beacon time - * CARDvUpdateNextTBTT - Sync. NIC Beacon time - * card_radio_power_off - Turn Off NIC Radio Power - * - * Revision History: - * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. - * 08-26-2003 Kyle Hsu: Modify the definition type of iobase. - * 09-01-2003 Bryan YC Fan: Add vUpdateIFS(). - * - */ - -#include "card.h" -#include "baseband.h" -#include "mac.h" -#include "desc.h" -#include "rf.h" -#include "power.h" - -/*--------------------- Static Definitions -------------------------*/ - -#define C_SIFS_A 16 /* micro sec. */ -#define C_SIFS_BG 10 - -#define C_EIFS 80 /* micro sec. */ - -#define C_SLOT_SHORT 9 /* micro sec. */ -#define C_SLOT_LONG 20 - -#define C_CWMIN_A 15 /* slot time */ -#define C_CWMIN_B 31 - -#define C_CWMAX 1023 /* slot time */ - -#define WAIT_BEACON_TX_DOWN_TMO 3 /* Times */ - -/*--------------------- Static Variables --------------------------*/ - -static const unsigned short rx_bcn_tsf_off[MAX_RATE] = { - 17, 17, 17, 17, 34, 23, 17, 11, 8, 5, 4, 3}; - -/*--------------------- Static Functions --------------------------*/ - -static void vt6655_mac_set_bb_type(void __iomem *iobase, u32 mask) -{ - u32 reg_value; - - reg_value = ioread32(iobase + MAC_REG_ENCFG); - reg_value = reg_value & ~ENCFG_BBTYPE_MASK; - reg_value = reg_value | mask; - iowrite32(reg_value, iobase + MAC_REG_ENCFG); -} - -/*--------------------- Export Functions --------------------------*/ - -/* - * Description: Calculate TxRate and RsvTime fields for RSPINF in OFDM mode. - * - * Parameters: - * In: - * wRate - Tx Rate - * byPktType - Tx Packet type - * Out: - * tx_rate - pointer to RSPINF TxRate field - * rsv_time - pointer to RSPINF RsvTime field - * - * Return Value: none - */ -static void calculate_ofdmr_parameter(unsigned char rate, - u8 bb_type, - unsigned char *tx_rate, - unsigned char *rsv_time) -{ - switch (rate) { - case RATE_6M: - if (bb_type == BB_TYPE_11A) { /* 5GHZ */ - *tx_rate = 0x9B; - *rsv_time = 44; - } else { - *tx_rate = 0x8B; - *rsv_time = 50; - } - break; - - case RATE_9M: - if (bb_type == BB_TYPE_11A) { /* 5GHZ */ - *tx_rate = 0x9F; - *rsv_time = 36; - } else { - *tx_rate = 0x8F; - *rsv_time = 42; - } - break; - - case RATE_12M: - if (bb_type == BB_TYPE_11A) { /* 5GHZ */ - *tx_rate = 0x9A; - *rsv_time = 32; - } else { - *tx_rate = 0x8A; - *rsv_time = 38; - } - break; - - case RATE_18M: - if (bb_type == BB_TYPE_11A) { /* 5GHZ */ - *tx_rate = 0x9E; - *rsv_time = 28; - } else { - *tx_rate = 0x8E; - *rsv_time = 34; - } - break; - - case RATE_36M: - if (bb_type == BB_TYPE_11A) { /* 5GHZ */ - *tx_rate = 0x9D; - *rsv_time = 24; - } else { - *tx_rate = 0x8D; - *rsv_time = 30; - } - break; - - case RATE_48M: - if (bb_type == BB_TYPE_11A) { /* 5GHZ */ - *tx_rate = 0x98; - *rsv_time = 24; - } else { - *tx_rate = 0x88; - *rsv_time = 30; - } - break; - - case RATE_54M: - if (bb_type == BB_TYPE_11A) { /* 5GHZ */ - *tx_rate = 0x9C; - *rsv_time = 24; - } else { - *tx_rate = 0x8C; - *rsv_time = 30; - } - break; - - case RATE_24M: - default: - if (bb_type == BB_TYPE_11A) { /* 5GHZ */ - *tx_rate = 0x99; - *rsv_time = 28; - } else { - *tx_rate = 0x89; - *rsv_time = 34; - } - break; - } -} - -/*--------------------- Export Functions --------------------------*/ - -/* - * Description: Update IFS - * - * Parameters: - * In: - * priv - The adapter to be set - * Out: - * none - * - * Return Value: None. - */ -bool card_set_phy_parameter(struct vnt_private *priv, u8 bb_type) -{ - unsigned char cw_max_min = 0; - unsigned char slot = 0; - unsigned char sifs = 0; - unsigned char difs = 0; - int i; - - /* Set SIFS, DIFS, EIFS, SlotTime, CwMin */ - if (bb_type == BB_TYPE_11A) { - vt6655_mac_set_bb_type(priv->port_offset, BB_TYPE_11A); - bb_write_embedded(priv, 0x88, 0x03); - slot = C_SLOT_SHORT; - sifs = C_SIFS_A; - difs = C_SIFS_A + 2 * C_SLOT_SHORT; - cw_max_min = 0xA4; - } else if (bb_type == BB_TYPE_11B) { - vt6655_mac_set_bb_type(priv->port_offset, BB_TYPE_11B); - bb_write_embedded(priv, 0x88, 0x02); - slot = C_SLOT_LONG; - sifs = C_SIFS_BG; - difs = C_SIFS_BG + 2 * C_SLOT_LONG; - cw_max_min = 0xA5; - } else { /* PK_TYPE_11GA & PK_TYPE_11GB */ - vt6655_mac_set_bb_type(priv->port_offset, BB_TYPE_11G); - bb_write_embedded(priv, 0x88, 0x08); - sifs = C_SIFS_BG; - - if (priv->short_slot_time) { - slot = C_SLOT_SHORT; - difs = C_SIFS_BG + 2 * C_SLOT_SHORT; - } else { - slot = C_SLOT_LONG; - difs = C_SIFS_BG + 2 * C_SLOT_LONG; - } - - cw_max_min = 0xa4; - - for (i = RATE_54M; i >= RATE_6M; i--) { - if (priv->basic_rates & ((u32)(0x1 << i))) { - cw_max_min |= 0x1; - break; - } - } - } - - if (priv->rf_type == RF_RFMD2959) { - /* - * bcs TX_PE will reserve 3 us hardware's processing - * time here is 2 us. - */ - sifs -= 3; - difs -= 3; - /* - * TX_PE will reserve 3 us for MAX2829 A mode only, it is for - * better TX throughput; MAC will need 2 us to process, so the - * SIFS, DIFS can be shorter by 2 us. - */ - } - - if (priv->sifs != sifs) { - priv->sifs = sifs; - iowrite8(priv->sifs, priv->port_offset + MAC_REG_SIFS); - } - if (priv->difs != difs) { - priv->difs = difs; - iowrite8(priv->difs, priv->port_offset + MAC_REG_DIFS); - } - if (priv->eifs != C_EIFS) { - priv->eifs = C_EIFS; - iowrite8(priv->eifs, priv->port_offset + MAC_REG_EIFS); - } - if (priv->slot != slot) { - priv->slot = slot; - iowrite8(priv->slot, priv->port_offset + MAC_REG_SLOT); - - bb_set_short_slot_time(priv); - } - if (priv->cw_max_min != cw_max_min) { - priv->cw_max_min = cw_max_min; - iowrite8(priv->cw_max_min, priv->port_offset + MAC_REG_CWMAXMIN0); - } - - priv->packet_type = card_get_pkt_type(priv); - - card_set_rspinf(priv, bb_type); - - return true; -} - -/* - * Description: Sync. TSF counter to BSS - * Get TSF offset and write to HW - * - * Parameters: - * In: - * priv - The adapter to be sync. - * rx_rate - data rate of receive beacon - * bss_timestamp - Rx BCN's TSF - * qwLocalTSF - Local TSF - * Out: - * none - * - * Return Value: none - */ -bool card_update_tsf(struct vnt_private *priv, unsigned char rx_rate, - u64 bss_timestamp) -{ - u64 local_tsf; - u64 tsf_offset = 0; - - local_tsf = vt6655_get_current_tsf(priv); - - if (bss_timestamp != local_tsf) { - tsf_offset = card_get_tsf_offset(rx_rate, bss_timestamp, - local_tsf); - /* adjust TSF, HW's TSF add TSF Offset reg */ - tsf_offset = le64_to_cpu(tsf_offset); - iowrite32((u32)tsf_offset, priv->port_offset + MAC_REG_TSFOFST); - iowrite32((u32)(tsf_offset >> 32), priv->port_offset + MAC_REG_TSFOFST + 4); - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TSFSYNCEN); - } - return true; -} - -/* - * Description: Set NIC TSF counter for first Beacon time - * Get NEXTTBTT from adjusted TSF and Beacon Interval - * - * Parameters: - * In: - * priv - The adapter to be set. - * beacon_interval - Beacon Interval - * Out: - * none - * - * Return Value: true if succeed; otherwise false - */ -bool card_set_beacon_period(struct vnt_private *priv, - unsigned short beacon_interval) -{ - u64 next_tbtt; - - next_tbtt = vt6655_get_current_tsf(priv); /* Get Local TSF counter */ - - next_tbtt = card_get_next_tbtt(next_tbtt, beacon_interval); - - /* set HW beacon interval */ - iowrite16(beacon_interval, priv->port_offset + MAC_REG_BI); - priv->beacon_interval = beacon_interval; - /* Set NextTBTT */ - next_tbtt = le64_to_cpu(next_tbtt); - iowrite32((u32)next_tbtt, priv->port_offset + MAC_REG_NEXTTBTT); - iowrite32((u32)(next_tbtt >> 32), priv->port_offset + MAC_REG_NEXTTBTT + 4); - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); - - return true; -} - -/* - * Description: Turn off Radio power - * - * Parameters: - * In: - * priv - The adapter to be turned off - * Out: - * none - * - */ -void card_radio_power_off(struct vnt_private *priv) -{ - if (priv->radio_off) - return; - - switch (priv->rf_type) { - case RF_RFMD2959: - vt6655_mac_word_reg_bits_off(priv->port_offset, MAC_REG_SOFTPWRCTL, - SOFTPWRCTL_TXPEINV); - vt6655_mac_word_reg_bits_on(priv->port_offset, MAC_REG_SOFTPWRCTL, - SOFTPWRCTL_SWPE1); - break; - - case RF_AIROHA: - case RF_AL2230S: - vt6655_mac_word_reg_bits_off(priv->port_offset, MAC_REG_SOFTPWRCTL, - SOFTPWRCTL_SWPE2); - vt6655_mac_word_reg_bits_off(priv->port_offset, MAC_REG_SOFTPWRCTL, - SOFTPWRCTL_SWPE3); - break; - } - - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_RXON); - - bb_set_deep_sleep(priv, priv->local_id); - - priv->radio_off = true; - pr_debug("chester power off\n"); - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_GPIOCTL0, LED_ACTSET); /* LED issue */ -} - -void card_safe_reset_tx(struct vnt_private *priv) -{ - unsigned int uu; - struct vnt_tx_desc *curr_td; - - /* initialize TD index */ - priv->tail_td[0] = &priv->ap_td0_rings[0]; - priv->apCurrTD[0] = &priv->ap_td0_rings[0]; - - priv->tail_td[1] = &priv->ap_td1_rings[0]; - priv->apCurrTD[1] = &priv->ap_td1_rings[0]; - - for (uu = 0; uu < TYPE_MAXTD; uu++) - priv->iTDUsed[uu] = 0; - - for (uu = 0; uu < priv->opts.tx_descs[0]; uu++) { - curr_td = &priv->ap_td0_rings[uu]; - curr_td->td0.owner = OWNED_BY_HOST; - /* init all Tx Packet pointer to NULL */ - } - for (uu = 0; uu < priv->opts.tx_descs[1]; uu++) { - curr_td = &priv->ap_td1_rings[uu]; - curr_td->td0.owner = OWNED_BY_HOST; - /* init all Tx Packet pointer to NULL */ - } - - /* set MAC TD pointer */ - vt6655_mac_set_curr_tx_desc_addr(TYPE_TXDMA0, priv, priv->td0_pool_dma); - - vt6655_mac_set_curr_tx_desc_addr(TYPE_AC0DMA, priv, priv->td1_pool_dma); - - /* set MAC Beacon TX pointer */ - iowrite32((u32)priv->tx_beacon_dma, priv->port_offset + MAC_REG_BCNDMAPTR); -} - -/* - * Description: - * Reset Rx - * - * Parameters: - * In: - * priv - Pointer to the adapter - * Out: - * none - * - * Return Value: none - */ -void CARDvSafeResetRx(struct vnt_private *priv) -{ - unsigned int uu; - struct vnt_rx_desc *pDesc; - - /* initialize RD index */ - priv->pCurrRD[0] = &priv->aRD0Ring[0]; - priv->pCurrRD[1] = &priv->aRD1Ring[0]; - - /* init state, all RD is chip's */ - for (uu = 0; uu < priv->opts.rx_descs0; uu++) { - pDesc = &priv->aRD0Ring[uu]; - pDesc->rd0.res_count = cpu_to_le16(priv->rx_buf_sz); - pDesc->rd0.owner = OWNED_BY_NIC; - pDesc->rd1.req_count = cpu_to_le16(priv->rx_buf_sz); - } - - /* init state, all RD is chip's */ - for (uu = 0; uu < priv->opts.rx_descs1; uu++) { - pDesc = &priv->aRD1Ring[uu]; - pDesc->rd0.res_count = cpu_to_le16(priv->rx_buf_sz); - pDesc->rd0.owner = OWNED_BY_NIC; - pDesc->rd1.req_count = cpu_to_le16(priv->rx_buf_sz); - } - - /* set perPkt mode */ - iowrite32(RX_PERPKT, priv->port_offset + MAC_REG_RXDMACTL0); - iowrite32(RX_PERPKT, priv->port_offset + MAC_REG_RXDMACTL1); - /* set MAC RD pointer */ - vt6655_mac_set_curr_rx_0_desc_addr(priv, priv->rd0_pool_dma); - - vt6655_mac_set_curr_rx_1_desc_addr(priv, priv->rd1_pool_dma); -} - -/* - * Description: Get response Control frame rate in CCK mode - * - * Parameters: - * In: - * priv - The adapter to be set - * wRateIdx - Receiving data rate - * Out: - * none - * - * Return Value: response Control frame rate - */ -static unsigned short CARDwGetCCKControlRate(struct vnt_private *priv, - unsigned short wRateIdx) -{ - unsigned int ui = (unsigned int)wRateIdx; - - while (ui > RATE_1M) { - if (priv->basic_rates & ((u32)0x1 << ui)) - return (unsigned short)ui; - - ui--; - } - return (unsigned short)RATE_1M; -} - -/* - * Description: Get response Control frame rate in OFDM mode - * - * Parameters: - * In: - * priv - The adapter to be set - * wRateIdx - Receiving data rate - * Out: - * none - * - * Return Value: response Control frame rate - */ -static unsigned short CARDwGetOFDMControlRate(struct vnt_private *priv, - unsigned short wRateIdx) -{ - unsigned int ui = (unsigned int)wRateIdx; - - pr_debug("BASIC RATE: %X\n", priv->basic_rates); - - if (!CARDbIsOFDMinBasicRate((void *)priv)) { - pr_debug("%s:(NO OFDM) %d\n", __func__, wRateIdx); - if (wRateIdx > RATE_24M) - wRateIdx = RATE_24M; - return wRateIdx; - } - while (ui > RATE_11M) { - if (priv->basic_rates & ((u32)0x1 << ui)) { - pr_debug("%s : %d\n", __func__, ui); - return (unsigned short)ui; - } - ui--; - } - pr_debug("%s: 6M\n", __func__); - return (unsigned short)RATE_24M; -} - -/* - * Description: Set RSPINF - * - * Parameters: - * In: - * priv - The adapter to be set - * Out: - * none - * - * Return Value: None. - */ -void card_set_rspinf(struct vnt_private *priv, u8 bb_type) -{ - union vnt_phy_field_swap phy; - unsigned char byTxRate, byRsvTime; /* For OFDM */ - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* Set to Page1 */ - VT6655_MAC_SELECT_PAGE1(priv->port_offset); - - /* RSPINF_b_1 */ - vnt_get_phy_field(priv, 14, - CARDwGetCCKControlRate(priv, RATE_1M), - PK_TYPE_11B, &phy.field_read); - - /* swap over to get correct write order */ - swap(phy.swap[0], phy.swap[1]); - - iowrite32(phy.field_write, priv->port_offset + MAC_REG_RSPINF_B_1); - - /* RSPINF_b_2 */ - vnt_get_phy_field(priv, 14, - CARDwGetCCKControlRate(priv, RATE_2M), - PK_TYPE_11B, &phy.field_read); - - swap(phy.swap[0], phy.swap[1]); - - iowrite32(phy.field_write, priv->port_offset + MAC_REG_RSPINF_B_2); - - /* RSPINF_b_5 */ - vnt_get_phy_field(priv, 14, - CARDwGetCCKControlRate(priv, RATE_5M), - PK_TYPE_11B, &phy.field_read); - - swap(phy.swap[0], phy.swap[1]); - - iowrite32(phy.field_write, priv->port_offset + MAC_REG_RSPINF_B_5); - - /* RSPINF_b_11 */ - vnt_get_phy_field(priv, 14, - CARDwGetCCKControlRate(priv, RATE_11M), - PK_TYPE_11B, &phy.field_read); - - swap(phy.swap[0], phy.swap[1]); - - iowrite32(phy.field_write, priv->port_offset + MAC_REG_RSPINF_B_11); - - /* RSPINF_a_6 */ - calculate_ofdmr_parameter(RATE_6M, - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_6); - /* RSPINF_a_9 */ - calculate_ofdmr_parameter(RATE_9M, - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_9); - /* RSPINF_a_12 */ - calculate_ofdmr_parameter(RATE_12M, - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_12); - /* RSPINF_a_18 */ - calculate_ofdmr_parameter(RATE_18M, - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_18); - /* RSPINF_a_24 */ - calculate_ofdmr_parameter(RATE_24M, - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_24); - /* RSPINF_a_36 */ - calculate_ofdmr_parameter(CARDwGetOFDMControlRate((void *)priv, - RATE_36M), - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_36); - /* RSPINF_a_48 */ - calculate_ofdmr_parameter(CARDwGetOFDMControlRate((void *)priv, - RATE_48M), - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_48); - /* RSPINF_a_54 */ - calculate_ofdmr_parameter(CARDwGetOFDMControlRate((void *)priv, - RATE_54M), - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_54); - /* RSPINF_a_72 */ - calculate_ofdmr_parameter(CARDwGetOFDMControlRate((void *)priv, - RATE_54M), - bb_type, - &byTxRate, - &byRsvTime); - iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_72); - /* Set to Page0 */ - VT6655_MAC_SELECT_PAGE0(priv->port_offset); - - spin_unlock_irqrestore(&priv->lock, flags); -} - -void CARDvUpdateBasicTopRate(struct vnt_private *priv) -{ - unsigned char byTopOFDM = RATE_24M, byTopCCK = RATE_1M; - unsigned char ii; - - /* Determines the highest basic rate. */ - for (ii = RATE_54M; ii >= RATE_6M; ii--) { - if ((priv->basic_rates) & ((u32)(1 << ii))) { - byTopOFDM = ii; - break; - } - } - priv->byTopOFDMBasicRate = byTopOFDM; - - for (ii = RATE_11M;; ii--) { - if ((priv->basic_rates) & ((u32)(1 << ii))) { - byTopCCK = ii; - break; - } - if (ii == RATE_1M) - break; - } - priv->byTopCCKBasicRate = byTopCCK; -} - -bool CARDbIsOFDMinBasicRate(struct vnt_private *priv) -{ - int ii; - - for (ii = RATE_54M; ii >= RATE_6M; ii--) { - if ((priv->basic_rates) & ((u32)BIT(ii))) - return true; - } - return false; -} - -unsigned char card_get_pkt_type(struct vnt_private *priv) -{ - if (priv->byBBType == BB_TYPE_11A || priv->byBBType == BB_TYPE_11B) - return (unsigned char)priv->byBBType; - else if (CARDbIsOFDMinBasicRate((void *)priv)) - return PK_TYPE_11GA; - else - return PK_TYPE_11GB; -} - -/* - * Description: Calculate TSF offset of two TSF input - * Get TSF Offset from RxBCN's TSF and local TSF - * - * Parameters: - * In: - * priv - The adapter to be sync. - * qwTSF1 - Rx BCN's TSF - * qwTSF2 - Local TSF - * Out: - * none - * - * Return Value: TSF Offset value - */ -u64 card_get_tsf_offset(unsigned char rx_rate, u64 qwTSF1, u64 qwTSF2) -{ - unsigned short wRxBcnTSFOffst; - - wRxBcnTSFOffst = rx_bcn_tsf_off[rx_rate % MAX_RATE]; - - qwTSF2 += (u64)wRxBcnTSFOffst; - - return qwTSF1 - qwTSF2; -} - -/* - * Description: Read NIC TSF counter - * Get local TSF counter - * - * Parameters: - * In: - * priv - The adapter to be read - * Out: - * none - * - * Return Value: Current TSF counter - */ -u64 vt6655_get_current_tsf(struct vnt_private *priv) -{ - void __iomem *iobase = priv->port_offset; - unsigned short ww; - unsigned char data; - u32 low, high; - - vt6655_mac_reg_bits_on(iobase, MAC_REG_TFTCTL, TFTCTL_TSFCNTRRD); - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - data = ioread8(iobase + MAC_REG_TFTCTL); - if (!(data & TFTCTL_TSFCNTRRD)) - break; - } - if (ww == W_MAX_TIMEOUT) - return 0; - low = ioread32(iobase + MAC_REG_TSFCNTR); - high = ioread32(iobase + MAC_REG_TSFCNTR + 4); - return le64_to_cpu(low + ((u64)high << 32)); -} - -/* - * Description: Read NIC TSF counter - * Get NEXTTBTT from adjusted TSF and Beacon Interval - * - * Parameters: - * In: - * qwTSF - Current TSF counter - * wbeaconInterval - Beacon Interval - * Out: - * qwCurrTSF - Current TSF counter - * - * Return Value: TSF value of next Beacon - */ -u64 card_get_next_tbtt(u64 qwTSF, unsigned short beacon_interval) -{ - u32 beacon_int; - - beacon_int = beacon_interval * 1024; - if (beacon_int) { - do_div(qwTSF, beacon_int); - qwTSF += 1; - qwTSF *= beacon_int; - } - - return qwTSF; -} - -/* - * Description: Set NIC TSF counter for first Beacon time - * Get NEXTTBTT from adjusted TSF and Beacon Interval - * - * Parameters: - * In: - * iobase - IO Base - * beacon_interval - Beacon Interval - * Out: - * none - * - * Return Value: none - */ -void CARDvSetFirstNextTBTT(struct vnt_private *priv, - unsigned short beacon_interval) -{ - void __iomem *iobase = priv->port_offset; - u64 next_tbtt; - - next_tbtt = vt6655_get_current_tsf(priv); /* Get Local TSF counter */ - - next_tbtt = card_get_next_tbtt(next_tbtt, beacon_interval); - /* Set NextTBTT */ - next_tbtt = le64_to_cpu(next_tbtt); - iowrite32((u32)next_tbtt, iobase + MAC_REG_NEXTTBTT); - iowrite32((u32)(next_tbtt >> 32), iobase + MAC_REG_NEXTTBTT + 4); - vt6655_mac_reg_bits_on(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); -} - -/* - * Description: Sync NIC TSF counter for Beacon time - * Get NEXTTBTT and write to HW - * - * Parameters: - * In: - * priv - The adapter to be set - * qwTSF - Current TSF counter - * beacon_interval - Beacon Interval - * Out: - * none - * - * Return Value: none - */ -void CARDvUpdateNextTBTT(struct vnt_private *priv, u64 qwTSF, - unsigned short beacon_interval) -{ - void __iomem *iobase = priv->port_offset; - - qwTSF = card_get_next_tbtt(qwTSF, beacon_interval); - /* Set NextTBTT */ - qwTSF = le64_to_cpu(qwTSF); - iowrite32((u32)qwTSF, iobase + MAC_REG_NEXTTBTT); - iowrite32((u32)(qwTSF >> 32), iobase + MAC_REG_NEXTTBTT + 4); - vt6655_mac_reg_bits_on(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); - pr_debug("Card:Update Next TBTT[%8llx]\n", qwTSF); -} diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h deleted file mode 100644 index f6b462ebca51cd..00000000000000 --- a/drivers/staging/vt6655/card.h +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Provide functions to setup NIC operation mode - * - * Author: Tevin Chen - * - * Date: May 21, 1996 - * - */ - -#ifndef __CARD_H__ -#define __CARD_H__ - -#include -#include - -/* - * Loopback mode - * - * LOBYTE is MAC LB mode, HIBYTE is MII LB mode - */ -#define CARD_LB_NONE MAKEWORD(MAC_LB_NONE, 0) -/* PHY must ISO, avoid MAC loopback packet go out */ -#define CARD_LB_MAC MAKEWORD(MAC_LB_INTERNAL, 0) -#define CARD_LB_PHY MAKEWORD(MAC_LB_EXT, 0) - -#define DEFAULT_MSDU_LIFETIME 512 /* ms */ -#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 /* 64us */ - -#define DEFAULT_MGN_LIFETIME 8 /* ms */ -#define DEFAULT_MGN_LIFETIME_RES_64us 125 /* 64us */ - -#define CB_MAX_CHANNEL_24G 14 -#define CB_MAX_CHANNEL_5G 42 -#define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G + CB_MAX_CHANNEL_5G) - -struct vnt_private; - -void card_set_rspinf(struct vnt_private *priv, u8 bb_type); -void CARDvUpdateBasicTopRate(struct vnt_private *priv); -bool CARDbIsOFDMinBasicRate(struct vnt_private *priv); -void CARDvSetFirstNextTBTT(struct vnt_private *priv, - unsigned short beacon_interval); -void CARDvUpdateNextTBTT(struct vnt_private *priv, u64 qwTSF, - unsigned short beacon_interval); -u64 vt6655_get_current_tsf(struct vnt_private *priv); -u64 card_get_next_tbtt(u64 qwTSF, unsigned short beacon_interval); -u64 card_get_tsf_offset(unsigned char rx_rate, u64 qwTSF1, u64 qwTSF2); -unsigned char card_get_pkt_type(struct vnt_private *priv); -void card_safe_reset_tx(struct vnt_private *priv); -void CARDvSafeResetRx(struct vnt_private *priv); -void card_radio_power_off(struct vnt_private *priv); -bool card_set_phy_parameter(struct vnt_private *priv, u8 bb_type); -bool card_update_tsf(struct vnt_private *priv, unsigned char rx_rate, - u64 bss_timestamp); -bool card_set_beacon_period(struct vnt_private *priv, - unsigned short beacon_interval); - -#endif /* __CARD_H__ */ diff --git a/drivers/staging/vt6655/channel.c b/drivers/staging/vt6655/channel.c deleted file mode 100644 index 771c1364b0f08e..00000000000000 --- a/drivers/staging/vt6655/channel.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - */ - -#include "baseband.h" -#include "channel.h" -#include "device.h" -#include "rf.h" - -static struct ieee80211_rate vnt_rates_bg[] = { - { .bitrate = 10, .hw_value = RATE_1M }, - { .bitrate = 20, .hw_value = RATE_2M }, - { .bitrate = 55, .hw_value = RATE_5M }, - { .bitrate = 110, .hw_value = RATE_11M }, - { .bitrate = 60, .hw_value = RATE_6M }, - { .bitrate = 90, .hw_value = RATE_9M }, - { .bitrate = 120, .hw_value = RATE_12M }, - { .bitrate = 180, .hw_value = RATE_18M }, - { .bitrate = 240, .hw_value = RATE_24M }, - { .bitrate = 360, .hw_value = RATE_36M }, - { .bitrate = 480, .hw_value = RATE_48M }, - { .bitrate = 540, .hw_value = RATE_54M }, -}; - -static struct ieee80211_channel vnt_channels_2ghz[] = { - { .center_freq = 2412, .hw_value = 1 }, - { .center_freq = 2417, .hw_value = 2 }, - { .center_freq = 2422, .hw_value = 3 }, - { .center_freq = 2427, .hw_value = 4 }, - { .center_freq = 2432, .hw_value = 5 }, - { .center_freq = 2437, .hw_value = 6 }, - { .center_freq = 2442, .hw_value = 7 }, - { .center_freq = 2447, .hw_value = 8 }, - { .center_freq = 2452, .hw_value = 9 }, - { .center_freq = 2457, .hw_value = 10 }, - { .center_freq = 2462, .hw_value = 11 }, - { .center_freq = 2467, .hw_value = 12 }, - { .center_freq = 2472, .hw_value = 13 }, - { .center_freq = 2484, .hw_value = 14 } -}; - -static struct ieee80211_supported_band vnt_supported_2ghz_band = { - .channels = vnt_channels_2ghz, - .n_channels = ARRAY_SIZE(vnt_channels_2ghz), - .bitrates = vnt_rates_bg, - .n_bitrates = ARRAY_SIZE(vnt_rates_bg), -}; - -static void vnt_init_band(struct vnt_private *priv, - struct ieee80211_supported_band *supported_band, - enum nl80211_band band) -{ - int i; - - for (i = 0; i < supported_band->n_channels; i++) { - supported_band->channels[i].max_power = 0x3f; - supported_band->channels[i].flags = - IEEE80211_CHAN_NO_HT40; - } - - priv->hw->wiphy->bands[band] = supported_band; -} - -void vnt_init_bands(struct vnt_private *priv) -{ - vnt_init_band(priv, &vnt_supported_2ghz_band, NL80211_BAND_2GHZ); -} - -/** - * set_channel() - Set NIC media channel - * - * @priv: The adapter to be set - * @ch: Channel to be set - * - * Return Value: true if succeeded; false if failed. - * - */ -bool set_channel(struct vnt_private *priv, struct ieee80211_channel *ch) -{ - bool ret = true; - - if (priv->current_ch == ch->hw_value) - return ret; - - /* Set VGA to max sensitivity */ - if (priv->update_bbvga && - priv->bbvga_current != priv->bbvga[0]) { - priv->bbvga_current = priv->bbvga[0]; - - bb_set_vga_gain_offset(priv, priv->bbvga_current); - } - - /* clear NAV */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_MACCR, MACCR_CLRNAV); - - /* TX_PE will reserve 3 us for MAX2829 A mode only, - * it is for better TX throughput - */ - - priv->current_ch = ch->hw_value; - ret &= RFbSelectChannel(priv, priv->rf_type, - ch->hw_value); - - /* Init Synthesizer Table */ - if (priv->bEnablePSMode) - rf_write_wake_prog_syn(priv, priv->rf_type, ch->hw_value); - - bb_software_reset(priv); - - if (priv->local_id > REV_ID_VT3253_B1) { - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - /* set HW default power register */ - VT6655_MAC_SELECT_PAGE1(priv->port_offset); - RFbSetPower(priv, RATE_1M, priv->current_ch); - iowrite8(priv->cur_pwr, priv->port_offset + MAC_REG_PWRCCK); - RFbSetPower(priv, RATE_6M, priv->current_ch); - iowrite8(priv->cur_pwr, priv->port_offset + MAC_REG_PWROFDM); - VT6655_MAC_SELECT_PAGE0(priv->port_offset); - - spin_unlock_irqrestore(&priv->lock, flags); - } - - if (priv->byBBType == BB_TYPE_11B) - RFbSetPower(priv, RATE_1M, priv->current_ch); - else - RFbSetPower(priv, RATE_6M, priv->current_ch); - - return ret; -} diff --git a/drivers/staging/vt6655/channel.h b/drivers/staging/vt6655/channel.h deleted file mode 100644 index 78b2d82317e52d..00000000000000 --- a/drivers/staging/vt6655/channel.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - */ - -#ifndef _CHANNEL_H_ -#define _CHANNEL_H_ - -#include "card.h" - -void vnt_init_bands(struct vnt_private *priv); - -bool set_channel(struct vnt_private *priv, struct ieee80211_channel *ch); - -#endif /* _CHANNEL_H_ */ diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h deleted file mode 100644 index 17a40c53b8ffd0..00000000000000 --- a/drivers/staging/vt6655/desc.h +++ /dev/null @@ -1,249 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose:The header file of descriptor - * - * Revision History: - * - * Author: Tevin Chen - * - * Date: May 21, 1996 - * - */ - -#ifndef __DESC_H__ -#define __DESC_H__ - -#include -#include -#include "linux/ieee80211.h" - -#define B_OWNED_BY_CHIP 1 -#define B_OWNED_BY_HOST 0 - -/* Bits in the RSR register */ -#define RSR_ADDRBROAD 0x80 -#define RSR_ADDRMULTI 0x40 -#define RSR_ADDRUNI 0x00 -#define RSR_IVLDTYP 0x20 -#define RSR_IVLDLEN 0x10 /* invalid len (> 2312 byte) */ -#define RSR_BSSIDOK 0x08 -#define RSR_CRCOK 0x04 -#define RSR_BCNSSIDOK 0x02 -#define RSR_ADDROK 0x01 - -/* Bits in the new RSR register */ -#define NEWRSR_DECRYPTOK 0x10 -#define NEWRSR_CFPIND 0x08 -#define NEWRSR_HWUTSF 0x04 -#define NEWRSR_BCNHITAID 0x02 -#define NEWRSR_BCNHITAID0 0x01 - -/* Bits in the TSR0 register */ -#define TSR0_PWRSTS1_2 0xC0 -#define TSR0_PWRSTS7 0x20 -#define TSR0_NCR 0x1F - -/* Bits in the TSR1 register */ -#define TSR1_TERR 0x80 -#define TSR1_PWRSTS4_6 0x70 -#define TSR1_RETRYTMO 0x08 -#define TSR1_TMO 0x04 -#define TSR1_PWRSTS3 0x02 -#define ACK_DATA 0x01 - -/* Bits in the TCR register */ -#define EDMSDU 0x04 /* end of sdu */ -#define TCR_EDP 0x02 /* end of packet */ -#define TCR_STP 0x01 /* start of packet */ - -/* max transmit or receive buffer size */ -#define CB_MAX_BUF_SIZE 2900U - /* NOTE: must be multiple of 4 */ -#define CB_MAX_TX_BUF_SIZE CB_MAX_BUF_SIZE -#define CB_MAX_RX_BUF_SIZE_NORMAL CB_MAX_BUF_SIZE - -#define CB_BEACON_BUF_SIZE 512U - -#define CB_MAX_RX_DESC 128 -#define CB_MIN_RX_DESC 16 -#define CB_MAX_TX_DESC 64 -#define CB_MIN_TX_DESC 16 - -#define CB_MAX_RECEIVED_PACKETS 16 - /* - * limit our receive routine to indicating - * this many at a time for 2 reasons: - * 1. driver flow control to protocol layer - * 2. limit the time used in ISR routine - */ - -#define CB_EXTRA_RD_NUM 32 -#define CB_RD_NUM 32 -#define CB_TD_NUM 32 - -/* - * max number of physical segments in a single NDIS packet. Above this - * threshold, the packet is copied into a single physically contiguous buffer - */ -#define CB_MAX_SEGMENT 4 - -#define CB_MIN_MAP_REG_NUM 4 -#define CB_MAX_MAP_REG_NUM CB_MAX_TX_DESC - -#define CB_PROTOCOL_RESERVED_SECTION 16 - -/* - * if retrys excess 15 times , tx will abort, and if tx fifo underflow, - * tx will fail, we should try to resend it - */ -#define CB_MAX_TX_ABORT_RETRY 3 - -/* WMAC definition FIFO Control */ -#define FIFOCTL_AUTO_FB_1 0x1000 -#define FIFOCTL_AUTO_FB_0 0x0800 -#define FIFOCTL_GRPACK 0x0400 -#define FIFOCTL_11GA 0x0300 -#define FIFOCTL_11GB 0x0200 -#define FIFOCTL_11B 0x0100 -#define FIFOCTL_11A 0x0000 -#define FIFOCTL_RTS 0x0080 -#define FIFOCTL_ISDMA0 0x0040 -#define FIFOCTL_GENINT 0x0020 -#define FIFOCTL_TMOEN 0x0010 -#define FIFOCTL_LRETRY 0x0008 -#define FIFOCTL_CRCDIS 0x0004 -#define FIFOCTL_NEEDACK 0x0002 -#define FIFOCTL_LHEAD 0x0001 - -/* WMAC definition Frag Control */ -#define FRAGCTL_AES 0x0300 -#define FRAGCTL_TKIP 0x0200 -#define FRAGCTL_LEGACY 0x0100 -#define FRAGCTL_NONENCRYPT 0x0000 -#define FRAGCTL_ENDFRAG 0x0003 -#define FRAGCTL_MIDFRAG 0x0002 -#define FRAGCTL_STAFRAG 0x0001 -#define FRAGCTL_NONFRAG 0x0000 - -#define TYPE_TXDMA0 0 -#define TYPE_AC0DMA 1 -#define TYPE_ATIMDMA 2 -#define TYPE_SYNCDMA 3 -#define TYPE_MAXTD 2 - -#define TYPE_BEACONDMA 4 - -#define TYPE_RXDMA0 0 -#define TYPE_RXDMA1 1 -#define TYPE_MAXRD 2 - -/* TD_INFO flags control bit */ -#define TD_FLAGS_NETIF_SKB 0x01 /* check if need release skb */ -/* check if called from private skb (hostap) */ -#define TD_FLAGS_PRIV_SKB 0x02 -#define TD_FLAGS_PS_RETRY 0x04 /* check if PS STA frame re-transmit */ - -/* - * ref_sk_buff is used for mapping the skb structure between pre-built - * driver-obj & running kernel. Since different kernel version (2.4x) may - * change skb structure, i.e. pre-built driver-obj may link to older skb that - * leads error. - */ - -struct vnt_rd_info { - struct sk_buff *skb; - dma_addr_t skb_dma; -}; - -struct vnt_rdes0 { - volatile __le16 res_count; -#ifdef __BIG_ENDIAN - union { - volatile u16 f15_reserved; - struct { - volatile u8 f8_reserved1; - volatile u8 owner:1; - volatile u8 f7_reserved:7; - } __packed; - } __packed; -#else - u16 f15_reserved:15; - u16 owner:1; -#endif -} __packed; - -struct vnt_rdes1 { - __le16 req_count; - u16 reserved; -} __packed; - -/* Rx descriptor*/ -struct vnt_rx_desc { - volatile struct vnt_rdes0 rd0; - volatile struct vnt_rdes1 rd1; - volatile __le32 buff_addr; - volatile __le32 next_desc; - struct vnt_rx_desc *next __aligned(8); - struct vnt_rd_info *rd_info __aligned(8); -} __packed; - -struct vnt_tdes0 { - volatile u8 tsr0; - volatile u8 tsr1; -#ifdef __BIG_ENDIAN - union { - volatile u16 f15_txtime; - struct { - volatile u8 f8_reserved; - volatile u8 owner:1; - volatile u8 f7_reserved:7; - } __packed; - } __packed; -#else - volatile u16 f15_txtime:15; - volatile u16 owner:1; -#endif -} __packed; - -struct vnt_tdes1 { - volatile __le16 req_count; - volatile u8 tcr; - volatile u8 reserved; -} __packed; - -struct vnt_td_info { - void *mic_hdr; - struct sk_buff *skb; - unsigned char *buf; - dma_addr_t buf_dma; - u16 req_count; - u8 flags; -}; - -/* transmit descriptor */ -struct vnt_tx_desc { - volatile struct vnt_tdes0 td0; - volatile struct vnt_tdes1 td1; - volatile __le32 buff_addr; - volatile __le32 next_desc; - struct vnt_tx_desc *next __aligned(8); - struct vnt_td_info *td_info __aligned(8); -} __packed; - -/* Length, Service, and Signal fields of Phy for Tx */ -struct vnt_phy_field { - u8 signal; - u8 service; - __le16 len; -} __packed; - -union vnt_phy_field_swap { - struct vnt_phy_field field_read; - u16 swap[2]; - u32 field_write; -}; - -#endif /* __DESC_H__ */ diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h deleted file mode 100644 index 5eaab6b172d370..00000000000000 --- a/drivers/staging/vt6655/device.h +++ /dev/null @@ -1,292 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: MAC Data structure - * - * Author: Tevin Chen - * - * Date: Mar 17, 1997 - * - */ - -#ifndef __DEVICE_H__ -#define __DEVICE_H__ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* device specific */ - -#include "device_cfg.h" -#include "card.h" -#include "srom.h" -#include "desc.h" -#include "key.h" -#include "mac.h" - -/*--------------------- Export Definitions -------------------------*/ - -#define RATE_1M 0 -#define RATE_2M 1 -#define RATE_5M 2 -#define RATE_11M 3 -#define RATE_6M 4 -#define RATE_9M 5 -#define RATE_12M 6 -#define RATE_18M 7 -#define RATE_24M 8 -#define RATE_36M 9 -#define RATE_48M 10 -#define RATE_54M 11 -#define MAX_RATE 12 - -#define AUTO_FB_NONE 0 -#define AUTO_FB_0 1 -#define AUTO_FB_1 2 - -#define FB_RATE0 0 -#define FB_RATE1 1 - -/* Antenna Mode */ -#define ANT_A 0 -#define ANT_B 1 -#define ANT_DIVERSITY 2 -#define ANT_RXD_TXA 3 -#define ANT_RXD_TXB 4 -#define ANT_UNKNOWN 0xFF - -#define BB_VGA_LEVEL 4 -#define BB_VGA_CHANGE_THRESHOLD 16 - -#define MAKE_BEACON_RESERVED 10 /* (us) */ - -/* BUILD OBJ mode */ - -#define AVAIL_TD(p, q) ((p)->opts.tx_descs[(q)] - ((p)->iTDUsed[(q)])) - -/* 0:11A 1:11B 2:11G */ -#define BB_TYPE_11A 0 -#define BB_TYPE_11B 1 -#define BB_TYPE_11G 2 - -/* 0:11a, 1:11b, 2:11gb (only CCK in BasicRate), 3:11ga (OFDM in BasicRate) */ -#define PK_TYPE_11A 0 -#define PK_TYPE_11B 1 -#define PK_TYPE_11GB 2 -#define PK_TYPE_11GA 3 - -#define OWNED_BY_HOST 0 -#define OWNED_BY_NIC 1 - -struct vnt_options { - int rx_descs0; /* Number of RX descriptors0 */ - int rx_descs1; /* Number of RX descriptors1 */ - int tx_descs[2]; /* Number of TX descriptors 0, 1 */ - int int_works; /* interrupt limits */ - int short_retry; - int long_retry; - int bbp_type; - u32 flags; -}; - -struct vnt_private { - struct pci_dev *pcid; - /* mac80211 */ - struct ieee80211_hw *hw; - struct ieee80211_vif *vif; - unsigned long key_entry_inuse; - u32 basic_rates; - u16 current_aid; - int mc_list_count; - u8 mac_hw; - -/* dma addr, rx/tx pool */ - dma_addr_t pool_dma; - dma_addr_t rd0_pool_dma; - dma_addr_t rd1_pool_dma; - - dma_addr_t td0_pool_dma; - dma_addr_t td1_pool_dma; - - dma_addr_t tx_bufs_dma0; - dma_addr_t tx_bufs_dma1; - dma_addr_t tx_beacon_dma; - - unsigned char *tx0_bufs; - unsigned char *tx1_bufs; - unsigned char *tx_beacon_bufs; - - void __iomem *port_offset; - u32 memaddr; - u32 ioaddr; - - spinlock_t lock; - - volatile int iTDUsed[TYPE_MAXTD]; - - struct vnt_tx_desc *apCurrTD[TYPE_MAXTD]; - struct vnt_tx_desc *tail_td[TYPE_MAXTD]; - - struct vnt_tx_desc *ap_td0_rings; - struct vnt_tx_desc *ap_td1_rings; - - struct vnt_rx_desc *aRD0Ring; - struct vnt_rx_desc *aRD1Ring; - struct vnt_rx_desc *pCurrRD[TYPE_MAXRD]; - - struct vnt_options opts; - - u32 flags; - - u32 rx_buf_sz; - u8 rx_rate; - - u32 rx_bytes; - - /* Version control */ - unsigned char local_id; - unsigned char rf_type; - - unsigned char max_pwr_level; - unsigned char byZoneType; - bool bZoneRegExist; - unsigned char byOriginalZonetype; - - unsigned char abyCurrentNetAddr[ETH_ALEN]; __aligned(2) - bool bLinkPass; /* link status: OK or fail */ - - unsigned int current_rssi; - unsigned char byCurrSQ; - - unsigned long dwTxAntennaSel; - unsigned long dwRxAntennaSel; - unsigned char byAntennaCount; - unsigned char byRxAntennaMode; - unsigned char byTxAntennaMode; - bool bTxRxAntInv; - - unsigned char *pbyTmpBuff; - unsigned int uSIFS; /* Current SIFS */ - unsigned int uDIFS; /* Current DIFS */ - unsigned int uEIFS; /* Current EIFS */ - unsigned int uSlot; /* Current SlotTime */ - unsigned int uCwMin; /* Current CwMin */ - unsigned int uCwMax; /* CwMax is fixed on 1023. */ - /* PHY parameter */ - unsigned char sifs; - unsigned char difs; - unsigned char eifs; - unsigned char slot; - unsigned char cw_max_min; - - u8 byBBType; /* 0:11A, 1:11B, 2:11G */ - u8 packet_type; /* - * 0:11a,1:11b,2:11gb (only CCK - * in BasicRate), 3:11ga (OFDM in - * Basic Rate) - */ - unsigned short wBasicRate; - unsigned char byACKRate; - unsigned char byTopOFDMBasicRate; - unsigned char byTopCCKBasicRate; - - unsigned char byMinChannel; - unsigned char byMaxChannel; - - unsigned char preamble_type; - unsigned char byShortPreamble; - - unsigned short wCurrentRate; - unsigned char byShortRetryLimit; - unsigned char byLongRetryLimit; - enum nl80211_iftype op_mode; - bool bBSSIDFilter; - unsigned short wMaxTransmitMSDULifetime; - - bool bEncryptionEnable; - bool bLongHeader; - bool short_slot_time; - bool bProtectMode; - bool bNonERPPresent; - bool bBarkerPreambleMd; - - bool bRadioControlOff; - bool radio_off; - bool bEnablePSMode; - unsigned short wListenInterval; - bool bPWBitOn; - - /* GPIO Radio Control */ - unsigned char byRadioCtl; - unsigned char byGPIO; - bool hw_radio_off; - bool bPrvActive4RadioOFF; - bool bGPIOBlockRead; - - /* Beacon related */ - unsigned short wSeqCounter; - unsigned short wBCNBufLen; - bool bBeaconBufReady; - bool bBeaconSent; - bool bIsBeaconBufReadySet; - unsigned int cbBeaconBufReadySetCnt; - bool bFixRate; - u16 current_ch; - - bool bAES; - - unsigned char byAutoFBCtrl; - - /* For Update BaseBand VGA Gain Offset */ - bool update_bbvga; - unsigned int uBBVGADiffCount; - unsigned char bbvga_new; - unsigned char bbvga_current; - unsigned char bbvga[BB_VGA_LEVEL]; - long dbm_threshold[BB_VGA_LEVEL]; - - unsigned char bb_pre_edrssi; - unsigned char byBBPreEDIndex; - - unsigned long dwDiagRefCount; - - /* For FOE Tuning */ - unsigned char byFOETuning; - - /* For RF Power table */ - unsigned char byCCKPwr; - unsigned char byOFDMPwrG; - unsigned char cur_pwr; - char byCurPwrdBm; - unsigned char abyCCKPwrTbl[CB_MAX_CHANNEL_24G + 1]; - unsigned char abyOFDMPwrTbl[CB_MAX_CHANNEL + 1]; - char abyCCKDefaultPwr[CB_MAX_CHANNEL_24G + 1]; - char abyOFDMDefaultPwr[CB_MAX_CHANNEL + 1]; - char abyRegPwr[CB_MAX_CHANNEL + 1]; - char abyLocalPwr[CB_MAX_CHANNEL + 1]; - - /* BaseBand Loopback Use */ - unsigned char byBBCR4d; - unsigned char byBBCRc9; - unsigned char byBBCR88; - unsigned char byBBCR09; - - unsigned char abyEEPROM[EEP_MAX_CONTEXT_SIZE]; /* unsigned long alignment */ - - unsigned short beacon_interval; - u16 wake_up_count; - - struct work_struct interrupt_work; - - struct ieee80211_low_level_stats low_stats; -}; - -#endif diff --git a/drivers/staging/vt6655/device_cfg.h b/drivers/staging/vt6655/device_cfg.h deleted file mode 100644 index 2d647a3619bad1..00000000000000 --- a/drivers/staging/vt6655/device_cfg.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Driver configuration header - * Author: Lyndon Chen - * - * Date: Dec 17, 2002 - * - */ - -#ifndef __DEVICE_CONFIG_H -#define __DEVICE_CONFIG_H - -#include - -#define VID_TABLE_SIZE 64 -#define MCAST_TABLE_SIZE 64 -#define MCAM_SIZE 32 -#define VCAM_SIZE 32 -#define TX_QUEUE_NO 8 - -#define DEVICE_NAME "vt6655" -#define DEVICE_FULL_DRV_NAM "VIA Networking Solomon-A/B/G Wireless LAN Adapter Driver" - -#ifndef MAJOR_VERSION -#define MAJOR_VERSION 1 -#endif - -#ifndef MINOR_VERSION -#define MINOR_VERSION 17 -#endif - -#ifndef DEVICE_VERSION -#define DEVICE_VERSION "1.19.12" -#endif - -#include -#include - -#define PKT_BUF_SZ 2390 - -#endif diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c deleted file mode 100644 index bf3ecf72020666..00000000000000 --- a/drivers/staging/vt6655/device_main.c +++ /dev/null @@ -1,1868 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: driver entry for initial, open, close, tx and rx. - * - * Author: Lyndon Chen - * - * Date: Jan 8, 2003 - * - * Functions: - * - * vt6655_probe - module initial (insmod) driver entry - * vt6655_remove - module remove entry - * device_free_info - device structure resource free function - * device_print_info - print out resource - * device_rx_srv - rx service function - * device_alloc_rx_buf - rx buffer pre-allocated function - * device_free_rx_buf - free rx buffer function - * device_free_tx_buf - free tx buffer function - * device_init_rd0_ring - initial rd dma0 ring - * device_init_rd1_ring - initial rd dma1 ring - * device_init_td0_ring - initial tx dma0 ring buffer - * device_init_td1_ring - initial tx dma1 ring buffer - * device_init_registers - initial MAC & BBP & RF internal registers. - * device_init_rings - initial tx/rx ring buffer - * device_free_rings - free all allocated ring buffer - * device_tx_srv - tx interrupt service function - * - * Revision History: - */ - -#include -#include "device.h" -#include "card.h" -#include "channel.h" -#include "baseband.h" -#include "mac.h" -#include "power.h" -#include "rxtx.h" -#include "dpc.h" -#include "rf.h" -#include -#include -#include - -/*--------------------- Static Definitions -------------------------*/ -/* - * Define module options - */ -MODULE_AUTHOR("VIA Networking Technologies, Inc., "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VIA Networking Solomon-A/B/G Wireless LAN Adapter Driver"); - -#define DEVICE_PARAM(N, D) - -#define RX_DESC_MIN0 16 -#define RX_DESC_MAX0 128 -#define RX_DESC_DEF0 32 -DEVICE_PARAM(RxDescriptors0, "Number of receive descriptors0"); - -#define RX_DESC_MIN1 16 -#define RX_DESC_MAX1 128 -#define RX_DESC_DEF1 32 -DEVICE_PARAM(RxDescriptors1, "Number of receive descriptors1"); - -#define TX_DESC_MIN0 16 -#define TX_DESC_MAX0 128 -#define TX_DESC_DEF0 32 -DEVICE_PARAM(TxDescriptors0, "Number of transmit descriptors0"); - -#define TX_DESC_MIN1 16 -#define TX_DESC_MAX1 128 -#define TX_DESC_DEF1 64 -DEVICE_PARAM(TxDescriptors1, "Number of transmit descriptors1"); - -#define INT_WORKS_DEF 20 -#define INT_WORKS_MIN 10 -#define INT_WORKS_MAX 64 - -DEVICE_PARAM(int_works, "Number of packets per interrupt services"); - -#define RTS_THRESH_DEF 2347 - -#define FRAG_THRESH_DEF 2346 - -#define SHORT_RETRY_MIN 0 -#define SHORT_RETRY_MAX 31 -#define SHORT_RETRY_DEF 8 - -DEVICE_PARAM(ShortRetryLimit, "Short frame retry limits"); - -#define LONG_RETRY_MIN 0 -#define LONG_RETRY_MAX 15 -#define LONG_RETRY_DEF 4 - -DEVICE_PARAM(LongRetryLimit, "long frame retry limits"); - -/* BasebandType[] baseband type selected - * 0: indicate 802.11a type - * 1: indicate 802.11b type - * 2: indicate 802.11g type - */ -#define BBP_TYPE_MIN 0 -#define BBP_TYPE_MAX 2 -#define BBP_TYPE_DEF 2 - -DEVICE_PARAM(BasebandType, "baseband type"); - -/* - * Static vars definitions - */ -static const struct pci_device_id vt6655_pci_id_table[] = { - { PCI_VDEVICE(VIA, 0x3253) }, - { 0, } -}; - -/*--------------------- Static Functions --------------------------*/ - -static int vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent); -static void device_free_info(struct vnt_private *priv); -static void device_print_info(struct vnt_private *priv); - -static void vt6655_mac_write_bssid_addr(void __iomem *iobase, const u8 *mac_addr); -static void vt6655_mac_read_ether_addr(void __iomem *iobase, u8 *mac_addr); - -static int device_init_rd0_ring(struct vnt_private *priv); -static int device_init_rd1_ring(struct vnt_private *priv); -static int device_init_td0_ring(struct vnt_private *priv); -static int device_init_td1_ring(struct vnt_private *priv); - -static int device_rx_srv(struct vnt_private *priv, unsigned int idx); -static int device_tx_srv(struct vnt_private *priv, unsigned int idx); -static bool device_alloc_rx_buf(struct vnt_private *, struct vnt_rx_desc *); -static void device_free_rx_buf(struct vnt_private *priv, - struct vnt_rx_desc *rd); -static void device_init_registers(struct vnt_private *priv); -static void device_free_tx_buf(struct vnt_private *, struct vnt_tx_desc *); -static void device_free_td0_ring(struct vnt_private *priv); -static void device_free_td1_ring(struct vnt_private *priv); -static void device_free_rd0_ring(struct vnt_private *priv); -static void device_free_rd1_ring(struct vnt_private *priv); -static void device_free_rings(struct vnt_private *priv); - -/*--------------------- Export Variables --------------------------*/ - -/*--------------------- Export Functions --------------------------*/ - -static void vt6655_remove(struct pci_dev *pcid) -{ - struct vnt_private *priv = pci_get_drvdata(pcid); - - if (!priv) - return; - device_free_info(priv); -} - -static void device_get_options(struct vnt_private *priv) -{ - struct vnt_options *opts = &priv->opts; - - opts->rx_descs0 = RX_DESC_DEF0; - opts->rx_descs1 = RX_DESC_DEF1; - opts->tx_descs[0] = TX_DESC_DEF0; - opts->tx_descs[1] = TX_DESC_DEF1; - opts->int_works = INT_WORKS_DEF; - - opts->short_retry = SHORT_RETRY_DEF; - opts->long_retry = LONG_RETRY_DEF; - opts->bbp_type = BBP_TYPE_DEF; -} - -static void -device_set_options(struct vnt_private *priv) -{ - priv->byShortRetryLimit = priv->opts.short_retry; - priv->byLongRetryLimit = priv->opts.long_retry; - priv->byBBType = priv->opts.bbp_type; - priv->packet_type = priv->byBBType; - priv->byAutoFBCtrl = AUTO_FB_0; - priv->update_bbvga = true; - priv->preamble_type = 0; - - pr_debug(" byShortRetryLimit= %d\n", (int)priv->byShortRetryLimit); - pr_debug(" byLongRetryLimit= %d\n", (int)priv->byLongRetryLimit); - pr_debug(" preamble_type= %d\n", (int)priv->preamble_type); - pr_debug(" byShortPreamble= %d\n", (int)priv->byShortPreamble); - pr_debug(" byBBType= %d\n", (int)priv->byBBType); -} - -static void vt6655_mac_write_bssid_addr(void __iomem *iobase, const u8 *mac_addr) -{ - iowrite8(1, iobase + MAC_REG_PAGE1SEL); - for (int i = 0; i < 6; i++) - iowrite8(mac_addr[i], iobase + MAC_REG_BSSID0 + i); - iowrite8(0, iobase + MAC_REG_PAGE1SEL); -} - -static void vt6655_mac_read_ether_addr(void __iomem *iobase, u8 *mac_addr) -{ - iowrite8(1, iobase + MAC_REG_PAGE1SEL); - for (int i = 0; i < 6; i++) - mac_addr[i] = ioread8(iobase + MAC_REG_PAR0 + i); - iowrite8(0, iobase + MAC_REG_PAGE1SEL); -} - -static void vt6655_mac_dma_ctl(void __iomem *iobase, u8 reg_index) -{ - u32 reg_value; - - reg_value = ioread32(iobase + reg_index); - if (reg_value & DMACTL_RUN) - iowrite32(DMACTL_WAKE, iobase + reg_index); - else - iowrite32(DMACTL_RUN, iobase + reg_index); -} - -static void vt6655_mac_set_bits(void __iomem *iobase, u32 mask) -{ - u32 reg_value; - - reg_value = ioread32(iobase + MAC_REG_ENCFG); - reg_value = reg_value | mask; - iowrite32(reg_value, iobase + MAC_REG_ENCFG); -} - -static void vt6655_mac_clear_bits(void __iomem *iobase, u32 mask) -{ - u32 reg_value; - - reg_value = ioread32(iobase + MAC_REG_ENCFG); - reg_value = reg_value & ~mask; - iowrite32(reg_value, iobase + MAC_REG_ENCFG); -} - -static void vt6655_mac_en_protect_md(void __iomem *iobase) -{ - vt6655_mac_set_bits(iobase, ENCFG_PROTECTMD); -} - -static void vt6655_mac_dis_protect_md(void __iomem *iobase) -{ - vt6655_mac_clear_bits(iobase, ENCFG_PROTECTMD); -} - -static void vt6655_mac_en_barker_preamble_md(void __iomem *iobase) -{ - vt6655_mac_set_bits(iobase, ENCFG_BARKERPREAM); -} - -static void vt6655_mac_dis_barker_preamble_md(void __iomem *iobase) -{ - vt6655_mac_clear_bits(iobase, ENCFG_BARKERPREAM); -} - -/* - * Initialisation of MAC & BBP registers - */ - -static void device_init_registers(struct vnt_private *priv) -{ - unsigned long flags; - unsigned int ii; - unsigned char byValue; - unsigned char byCCKPwrdBm = 0; - unsigned char byOFDMPwrdBm = 0; - - MACbShutdown(priv); - bb_software_reset(priv); - - /* Do MACbSoftwareReset in MACvInitialize */ - MACbSoftwareReset(priv); - - priv->bAES = false; - - /* Only used in 11g type, sync with ERP IE */ - priv->bProtectMode = false; - - priv->bNonERPPresent = false; - priv->bBarkerPreambleMd = false; - priv->wCurrentRate = RATE_1M; - priv->byTopOFDMBasicRate = RATE_24M; - priv->byTopCCKBasicRate = RATE_1M; - - /* init MAC */ - MACvInitialize(priv); - - /* Get Local ID */ - priv->local_id = ioread8(priv->port_offset + MAC_REG_LOCALID); - - spin_lock_irqsave(&priv->lock, flags); - - SROMvReadAllContents(priv->port_offset, priv->abyEEPROM); - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Get Channel range */ - priv->byMinChannel = 1; - priv->byMaxChannel = CB_MAX_CHANNEL; - - /* Get Antena */ - byValue = SROMbyReadEmbedded(priv->port_offset, EEP_OFS_ANTENNA); - if (byValue & EEP_ANTINV) - priv->bTxRxAntInv = true; - else - priv->bTxRxAntInv = false; - - byValue &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); - /* if not set default is All */ - if (byValue == 0) - byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); - - if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) { - priv->byAntennaCount = 2; - priv->byTxAntennaMode = ANT_B; - priv->dwTxAntennaSel = 1; - priv->dwRxAntennaSel = 1; - - if (priv->bTxRxAntInv) - priv->byRxAntennaMode = ANT_A; - else - priv->byRxAntennaMode = ANT_B; - } else { - priv->byAntennaCount = 1; - priv->dwTxAntennaSel = 0; - priv->dwRxAntennaSel = 0; - - if (byValue & EEP_ANTENNA_AUX) { - priv->byTxAntennaMode = ANT_A; - - if (priv->bTxRxAntInv) - priv->byRxAntennaMode = ANT_B; - else - priv->byRxAntennaMode = ANT_A; - } else { - priv->byTxAntennaMode = ANT_B; - - if (priv->bTxRxAntInv) - priv->byRxAntennaMode = ANT_A; - else - priv->byRxAntennaMode = ANT_B; - } - } - - /* Set initial antenna mode */ - bb_set_tx_antenna_mode(priv, priv->byTxAntennaMode); - bb_set_rx_antenna_mode(priv, priv->byRxAntennaMode); - - /* zonetype initial */ - priv->byOriginalZonetype = priv->abyEEPROM[EEP_OFS_ZONETYPE]; - - if (!priv->bZoneRegExist) - priv->byZoneType = priv->abyEEPROM[EEP_OFS_ZONETYPE]; - - pr_debug("priv->byZoneType = %x\n", priv->byZoneType); - - /* Init RF module */ - RFbInit(priv); - - /* Get Desire Power Value */ - priv->cur_pwr = 0xFF; - priv->byCCKPwr = SROMbyReadEmbedded(priv->port_offset, EEP_OFS_PWR_CCK); - priv->byOFDMPwrG = SROMbyReadEmbedded(priv->port_offset, - EEP_OFS_PWR_OFDMG); - - /* Load power Table */ - for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) { - priv->abyCCKPwrTbl[ii + 1] = - SROMbyReadEmbedded(priv->port_offset, - (unsigned char)(ii + EEP_OFS_CCK_PWR_TBL)); - if (priv->abyCCKPwrTbl[ii + 1] == 0) - priv->abyCCKPwrTbl[ii + 1] = priv->byCCKPwr; - - priv->abyOFDMPwrTbl[ii + 1] = - SROMbyReadEmbedded(priv->port_offset, - (unsigned char)(ii + EEP_OFS_OFDM_PWR_TBL)); - if (priv->abyOFDMPwrTbl[ii + 1] == 0) - priv->abyOFDMPwrTbl[ii + 1] = priv->byOFDMPwrG; - - priv->abyCCKDefaultPwr[ii + 1] = byCCKPwrdBm; - priv->abyOFDMDefaultPwr[ii + 1] = byOFDMPwrdBm; - } - - /* recover 12,13 ,14channel for EUROPE by 11 channel */ - for (ii = 11; ii < 14; ii++) { - priv->abyCCKPwrTbl[ii] = priv->abyCCKPwrTbl[10]; - priv->abyOFDMPwrTbl[ii] = priv->abyOFDMPwrTbl[10]; - } - - /* Load OFDM A Power Table */ - for (ii = 0; ii < CB_MAX_CHANNEL_5G; ii++) { - priv->abyOFDMPwrTbl[ii + CB_MAX_CHANNEL_24G + 1] = - SROMbyReadEmbedded(priv->port_offset, - (unsigned char)(ii + EEP_OFS_OFDMA_PWR_TBL)); - - priv->abyOFDMDefaultPwr[ii + CB_MAX_CHANNEL_24G + 1] = - SROMbyReadEmbedded(priv->port_offset, - (unsigned char)(ii + EEP_OFS_OFDMA_PWR_dBm)); - } - - if (priv->local_id > REV_ID_VT3253_B1) { - VT6655_MAC_SELECT_PAGE1(priv->port_offset); - - iowrite8(MSRCTL1_TXPWR | MSRCTL1_CSAPAREN, priv->port_offset + MAC_REG_MSRCTL + 1); - - VT6655_MAC_SELECT_PAGE0(priv->port_offset); - } - - /* use relative tx timeout and 802.11i D4 */ - vt6655_mac_word_reg_bits_on(priv->port_offset, MAC_REG_CFG, - (CFG_TKIPOPT | CFG_NOTXTIMEOUT)); - - /* set performance parameter by registry */ - vt6655_mac_set_short_retry_limit(priv, priv->byShortRetryLimit); - MACvSetLongRetryLimit(priv, priv->byLongRetryLimit); - - /* reset TSF counter */ - iowrite8(TFTCTL_TSFCNTRST, priv->port_offset + MAC_REG_TFTCTL); - /* enable TSF counter */ - iowrite8(TFTCTL_TSFCNTREN, priv->port_offset + MAC_REG_TFTCTL); - - /* initialize BBP registers */ - bb_vt3253_init(priv); - - if (priv->update_bbvga) { - priv->bbvga_current = priv->bbvga[0]; - priv->bbvga_new = priv->bbvga_current; - bb_set_vga_gain_offset(priv, priv->bbvga[0]); - } - - bb_set_rx_antenna_mode(priv, priv->byRxAntennaMode); - bb_set_tx_antenna_mode(priv, priv->byTxAntennaMode); - - /* Set BB and packet type at the same time. */ - /* Set Short Slot Time, xIFS, and RSPINF. */ - priv->wCurrentRate = RATE_54M; - - priv->radio_off = false; - - priv->byRadioCtl = SROMbyReadEmbedded(priv->port_offset, - EEP_OFS_RADIOCTL); - priv->hw_radio_off = false; - - if (priv->byRadioCtl & EEP_RADIOCTL_ENABLE) { - /* Get GPIO */ - priv->byGPIO = ioread8(priv->port_offset + MAC_REG_GPIOCTL1); - - if (((priv->byGPIO & GPIO0_DATA) && - !(priv->byRadioCtl & EEP_RADIOCTL_INV)) || - (!(priv->byGPIO & GPIO0_DATA) && - (priv->byRadioCtl & EEP_RADIOCTL_INV))) - priv->hw_radio_off = true; - } - - if (priv->hw_radio_off || priv->bRadioControlOff) - card_radio_power_off(priv); - - /* get Permanent network address */ - SROMvReadEtherAddress(priv->port_offset, priv->abyCurrentNetAddr); - pr_debug("Network address = %pM\n", priv->abyCurrentNetAddr); - - /* reset Tx pointer */ - CARDvSafeResetRx(priv); - /* reset Rx pointer */ - card_safe_reset_tx(priv); - - if (priv->local_id <= REV_ID_VT3253_A1) - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_RCR, RCR_WPAERR); - - /* Turn On Rx DMA */ - vt6655_mac_dma_ctl(priv->port_offset, MAC_REG_RXDMACTL0); - vt6655_mac_dma_ctl(priv->port_offset, MAC_REG_RXDMACTL1); - - /* start the adapter */ - iowrite8(HOSTCR_MACEN | HOSTCR_RXON | HOSTCR_TXON, priv->port_offset + MAC_REG_HOSTCR); -} - -static void device_print_info(struct vnt_private *priv) -{ - dev_info(&priv->pcid->dev, "MAC=%pM IO=0x%lx Mem=0x%lx IRQ=%d\n", - priv->abyCurrentNetAddr, (unsigned long)priv->ioaddr, - (unsigned long)priv->port_offset, priv->pcid->irq); -} - -static void device_free_info(struct vnt_private *priv) -{ - if (!priv) - return; - - if (priv->mac_hw) - ieee80211_unregister_hw(priv->hw); - - if (priv->port_offset) - iounmap(priv->port_offset); - - if (priv->pcid) - pci_release_regions(priv->pcid); - - if (priv->hw) - ieee80211_free_hw(priv->hw); -} - -static bool device_init_rings(struct vnt_private *priv) -{ - void *vir_pool; - - /*allocate all RD/TD rings a single pool*/ - vir_pool = dma_alloc_coherent(&priv->pcid->dev, - priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + - priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + - priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + - priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc), - &priv->pool_dma, GFP_ATOMIC); - if (!vir_pool) { - dev_err(&priv->pcid->dev, "allocate desc dma memory failed\n"); - return false; - } - - priv->aRD0Ring = vir_pool; - priv->aRD1Ring = vir_pool + - priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc); - - priv->rd0_pool_dma = priv->pool_dma; - priv->rd1_pool_dma = priv->rd0_pool_dma + - priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc); - - priv->tx0_bufs = dma_alloc_coherent(&priv->pcid->dev, - priv->opts.tx_descs[0] * PKT_BUF_SZ + - priv->opts.tx_descs[1] * PKT_BUF_SZ + - CB_BEACON_BUF_SIZE + - CB_MAX_BUF_SIZE, - &priv->tx_bufs_dma0, GFP_ATOMIC); - if (!priv->tx0_bufs) { - dev_err(&priv->pcid->dev, "allocate buf dma memory failed\n"); - - dma_free_coherent(&priv->pcid->dev, - priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + - priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + - priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + - priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc), - vir_pool, priv->pool_dma); - return false; - } - - priv->td0_pool_dma = priv->rd1_pool_dma + - priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc); - - priv->td1_pool_dma = priv->td0_pool_dma + - priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc); - - /* vir_pool: pvoid type */ - priv->ap_td0_rings = vir_pool - + priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) - + priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc); - - priv->ap_td1_rings = vir_pool - + priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) - + priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) - + priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc); - - priv->tx1_bufs = priv->tx0_bufs + - priv->opts.tx_descs[0] * PKT_BUF_SZ; - - priv->tx_beacon_bufs = priv->tx1_bufs + - priv->opts.tx_descs[1] * PKT_BUF_SZ; - - priv->pbyTmpBuff = priv->tx_beacon_bufs + - CB_BEACON_BUF_SIZE; - - priv->tx_bufs_dma1 = priv->tx_bufs_dma0 + - priv->opts.tx_descs[0] * PKT_BUF_SZ; - - priv->tx_beacon_dma = priv->tx_bufs_dma1 + - priv->opts.tx_descs[1] * PKT_BUF_SZ; - - return true; -} - -static void device_free_rings(struct vnt_private *priv) -{ - dma_free_coherent(&priv->pcid->dev, - priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + - priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + - priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + - priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc), - priv->aRD0Ring, priv->pool_dma); - - dma_free_coherent(&priv->pcid->dev, - priv->opts.tx_descs[0] * PKT_BUF_SZ + - priv->opts.tx_descs[1] * PKT_BUF_SZ + - CB_BEACON_BUF_SIZE + - CB_MAX_BUF_SIZE, - priv->tx0_bufs, priv->tx_bufs_dma0); -} - -static int device_init_rd0_ring(struct vnt_private *priv) -{ - int i; - dma_addr_t curr = priv->rd0_pool_dma; - struct vnt_rx_desc *desc; - int ret; - - /* Init the RD0 ring entries */ - for (i = 0; i < priv->opts.rx_descs0; - i ++, curr += sizeof(struct vnt_rx_desc)) { - desc = &priv->aRD0Ring[i]; - desc->rd_info = kzalloc(sizeof(*desc->rd_info), GFP_KERNEL); - if (!desc->rd_info) { - ret = -ENOMEM; - goto err_free_desc; - } - - if (!device_alloc_rx_buf(priv, desc)) { - dev_err(&priv->pcid->dev, "can not alloc rx bufs\n"); - ret = -ENOMEM; - goto err_free_rd; - } - - desc->next = &priv->aRD0Ring[(i + 1) % priv->opts.rx_descs0]; - desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_rx_desc)); - } - - if (i > 0) - priv->aRD0Ring[i - 1].next_desc = cpu_to_le32(priv->rd0_pool_dma); - priv->pCurrRD[0] = &priv->aRD0Ring[0]; - - return 0; - -err_free_rd: - kfree(desc->rd_info); - -err_free_desc: - while (i--) { - desc = &priv->aRD0Ring[i]; - device_free_rx_buf(priv, desc); - kfree(desc->rd_info); - } - - return ret; -} - -static int device_init_rd1_ring(struct vnt_private *priv) -{ - int i; - dma_addr_t curr = priv->rd1_pool_dma; - struct vnt_rx_desc *desc; - int ret; - - /* Init the RD1 ring entries */ - for (i = 0; i < priv->opts.rx_descs1; - i ++, curr += sizeof(struct vnt_rx_desc)) { - desc = &priv->aRD1Ring[i]; - desc->rd_info = kzalloc(sizeof(*desc->rd_info), GFP_KERNEL); - if (!desc->rd_info) { - ret = -ENOMEM; - goto err_free_desc; - } - - if (!device_alloc_rx_buf(priv, desc)) { - dev_err(&priv->pcid->dev, "can not alloc rx bufs\n"); - ret = -ENOMEM; - goto err_free_rd; - } - - desc->next = &priv->aRD1Ring[(i + 1) % priv->opts.rx_descs1]; - desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_rx_desc)); - } - - if (i > 0) - priv->aRD1Ring[i - 1].next_desc = cpu_to_le32(priv->rd1_pool_dma); - priv->pCurrRD[1] = &priv->aRD1Ring[0]; - - return 0; - -err_free_rd: - kfree(desc->rd_info); - -err_free_desc: - while (i--) { - desc = &priv->aRD1Ring[i]; - device_free_rx_buf(priv, desc); - kfree(desc->rd_info); - } - - return ret; -} - -static void device_free_rd0_ring(struct vnt_private *priv) -{ - int i; - - for (i = 0; i < priv->opts.rx_descs0; i++) { - struct vnt_rx_desc *desc = &priv->aRD0Ring[i]; - - device_free_rx_buf(priv, desc); - kfree(desc->rd_info); - } -} - -static void device_free_rd1_ring(struct vnt_private *priv) -{ - int i; - - for (i = 0; i < priv->opts.rx_descs1; i++) { - struct vnt_rx_desc *desc = &priv->aRD1Ring[i]; - - device_free_rx_buf(priv, desc); - kfree(desc->rd_info); - } -} - -static int device_init_td0_ring(struct vnt_private *priv) -{ - int i; - dma_addr_t curr; - struct vnt_tx_desc *desc; - int ret; - - curr = priv->td0_pool_dma; - for (i = 0; i < priv->opts.tx_descs[0]; - i++, curr += sizeof(struct vnt_tx_desc)) { - desc = &priv->ap_td0_rings[i]; - desc->td_info = kzalloc(sizeof(*desc->td_info), GFP_KERNEL); - if (!desc->td_info) { - ret = -ENOMEM; - goto err_free_desc; - } - - desc->td_info->buf = priv->tx0_bufs + i * PKT_BUF_SZ; - desc->td_info->buf_dma = priv->tx_bufs_dma0 + i * PKT_BUF_SZ; - - desc->next = &(priv->ap_td0_rings[(i + 1) % priv->opts.tx_descs[0]]); - desc->next_desc = cpu_to_le32(curr + - sizeof(struct vnt_tx_desc)); - } - - if (i > 0) - priv->ap_td0_rings[i - 1].next_desc = cpu_to_le32(priv->td0_pool_dma); - priv->tail_td[0] = priv->apCurrTD[0] = &priv->ap_td0_rings[0]; - - return 0; - -err_free_desc: - while (i--) { - desc = &priv->ap_td0_rings[i]; - kfree(desc->td_info); - } - - return ret; -} - -static int device_init_td1_ring(struct vnt_private *priv) -{ - int i; - dma_addr_t curr; - struct vnt_tx_desc *desc; - int ret; - - /* Init the TD ring entries */ - curr = priv->td1_pool_dma; - for (i = 0; i < priv->opts.tx_descs[1]; - i++, curr += sizeof(struct vnt_tx_desc)) { - desc = &priv->ap_td1_rings[i]; - desc->td_info = kzalloc(sizeof(*desc->td_info), GFP_KERNEL); - if (!desc->td_info) { - ret = -ENOMEM; - goto err_free_desc; - } - - desc->td_info->buf = priv->tx1_bufs + i * PKT_BUF_SZ; - desc->td_info->buf_dma = priv->tx_bufs_dma1 + i * PKT_BUF_SZ; - - desc->next = &(priv->ap_td1_rings[(i + 1) % priv->opts.tx_descs[1]]); - desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_tx_desc)); - } - - if (i > 0) - priv->ap_td1_rings[i - 1].next_desc = cpu_to_le32(priv->td1_pool_dma); - priv->tail_td[1] = priv->apCurrTD[1] = &priv->ap_td1_rings[0]; - - return 0; - -err_free_desc: - while (i--) { - desc = &priv->ap_td1_rings[i]; - kfree(desc->td_info); - } - - return ret; -} - -static void device_free_td0_ring(struct vnt_private *priv) -{ - int i; - - for (i = 0; i < priv->opts.tx_descs[0]; i++) { - struct vnt_tx_desc *desc = &priv->ap_td0_rings[i]; - struct vnt_td_info *td_info = desc->td_info; - - dev_kfree_skb(td_info->skb); - kfree(desc->td_info); - } -} - -static void device_free_td1_ring(struct vnt_private *priv) -{ - int i; - - for (i = 0; i < priv->opts.tx_descs[1]; i++) { - struct vnt_tx_desc *desc = &priv->ap_td1_rings[i]; - struct vnt_td_info *td_info = desc->td_info; - - dev_kfree_skb(td_info->skb); - kfree(desc->td_info); - } -} - -/*-----------------------------------------------------------------*/ - -static int device_rx_srv(struct vnt_private *priv, unsigned int idx) -{ - struct vnt_rx_desc *rd; - int works = 0; - - for (rd = priv->pCurrRD[idx]; - rd->rd0.owner == OWNED_BY_HOST; - rd = rd->next) { - if (works++ > 15) - break; - - if (!rd->rd_info->skb) - break; - - if (vnt_receive_frame(priv, rd)) { - if (!device_alloc_rx_buf(priv, rd)) { - dev_err(&priv->pcid->dev, - "can not allocate rx buf\n"); - break; - } - } - rd->rd0.owner = OWNED_BY_NIC; - } - - priv->pCurrRD[idx] = rd; - - return works; -} - -static bool device_alloc_rx_buf(struct vnt_private *priv, - struct vnt_rx_desc *rd) -{ - struct vnt_rd_info *rd_info = rd->rd_info; - - rd_info->skb = dev_alloc_skb((int)priv->rx_buf_sz); - if (!rd_info->skb) - return false; - - rd_info->skb_dma = - dma_map_single(&priv->pcid->dev, - skb_put(rd_info->skb, skb_tailroom(rd_info->skb)), - priv->rx_buf_sz, DMA_FROM_DEVICE); - if (dma_mapping_error(&priv->pcid->dev, rd_info->skb_dma)) { - dev_kfree_skb(rd_info->skb); - rd_info->skb = NULL; - return false; - } - - *((unsigned int *)&rd->rd0) = 0; /* FIX cast */ - - rd->rd0.res_count = cpu_to_le16(priv->rx_buf_sz); - rd->rd0.owner = OWNED_BY_NIC; - rd->rd1.req_count = cpu_to_le16(priv->rx_buf_sz); - rd->buff_addr = cpu_to_le32(rd_info->skb_dma); - - return true; -} - -static void device_free_rx_buf(struct vnt_private *priv, - struct vnt_rx_desc *rd) -{ - struct vnt_rd_info *rd_info = rd->rd_info; - - dma_unmap_single(&priv->pcid->dev, rd_info->skb_dma, - priv->rx_buf_sz, DMA_FROM_DEVICE); - dev_kfree_skb(rd_info->skb); -} - -static const u8 fallback_rate0[5][5] = { - {RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M}, - {RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M}, - {RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M}, - {RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M}, - {RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M} -}; - -static const u8 fallback_rate1[5][5] = { - {RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M}, - {RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M}, - {RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M}, - {RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M}, - {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M} -}; - -static int vnt_int_report_rate(struct vnt_private *priv, - struct vnt_td_info *context, u8 tsr0, u8 tsr1) -{ - struct vnt_tx_fifo_head *fifo_head; - struct ieee80211_tx_info *info; - struct ieee80211_rate *rate; - u16 fb_option; - u8 tx_retry = (tsr0 & TSR0_NCR); - s8 idx; - - if (!context) - return -ENOMEM; - - if (!context->skb) - return -EINVAL; - - fifo_head = (struct vnt_tx_fifo_head *)context->buf; - fb_option = (le16_to_cpu(fifo_head->fifo_ctl) & - (FIFOCTL_AUTO_FB_0 | FIFOCTL_AUTO_FB_1)); - - info = IEEE80211_SKB_CB(context->skb); - idx = info->control.rates[0].idx; - - if (fb_option && !(tsr1 & TSR1_TERR)) { - u8 tx_rate; - u8 retry = tx_retry; - - rate = ieee80211_get_tx_rate(priv->hw, info); - tx_rate = rate->hw_value - RATE_18M; - - if (retry > 4) - retry = 4; - - if (fb_option & FIFOCTL_AUTO_FB_0) - tx_rate = fallback_rate0[tx_rate][retry]; - else if (fb_option & FIFOCTL_AUTO_FB_1) - tx_rate = fallback_rate1[tx_rate][retry]; - - if (info->band == NL80211_BAND_5GHZ) - idx = tx_rate - RATE_6M; - else - idx = tx_rate; - } - - ieee80211_tx_info_clear_status(info); - - info->status.rates[0].count = tx_retry; - - if (!(tsr1 & TSR1_TERR)) { - info->status.rates[0].idx = idx; - - if (info->flags & IEEE80211_TX_CTL_NO_ACK) - info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - else - info->flags |= IEEE80211_TX_STAT_ACK; - } - - return 0; -} - -static int device_tx_srv(struct vnt_private *priv, unsigned int idx) -{ - struct vnt_tx_desc *desc; - int works = 0; - unsigned char byTsr0; - unsigned char byTsr1; - - for (desc = priv->tail_td[idx]; priv->iTDUsed[idx] > 0; desc = desc->next) { - if (desc->td0.owner == OWNED_BY_NIC) - break; - if (works++ > 15) - break; - - byTsr0 = desc->td0.tsr0; - byTsr1 = desc->td0.tsr1; - - /* Only the status of first TD in the chain is correct */ - if (desc->td1.tcr & TCR_STP) { - if ((desc->td_info->flags & TD_FLAGS_NETIF_SKB) != 0) { - if (!(byTsr1 & TSR1_TERR)) { - if (byTsr0 != 0) { - pr_debug(" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X]\n", - (int)idx, byTsr1, - byTsr0); - } - } else { - pr_debug(" Tx[%d] dropped & tsr1[%02X] tsr0[%02X]\n", - (int)idx, byTsr1, byTsr0); - } - } - - if (byTsr1 & TSR1_TERR) { - if ((desc->td_info->flags & TD_FLAGS_PRIV_SKB) != 0) { - pr_debug(" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X]\n", - (int)idx, byTsr1, byTsr0); - } - } - - vnt_int_report_rate(priv, desc->td_info, byTsr0, byTsr1); - - device_free_tx_buf(priv, desc); - priv->iTDUsed[idx]--; - } - } - - priv->tail_td[idx] = desc; - - return works; -} - -static void device_error(struct vnt_private *priv, unsigned short status) -{ - if (status & ISR_FETALERR) { - dev_err(&priv->pcid->dev, "Hardware fatal error\n"); - - MACbShutdown(priv); - return; - } -} - -static void device_free_tx_buf(struct vnt_private *priv, - struct vnt_tx_desc *desc) -{ - struct vnt_td_info *td_info = desc->td_info; - struct sk_buff *skb = td_info->skb; - - if (skb) - ieee80211_tx_status_irqsafe(priv->hw, skb); - - td_info->skb = NULL; - td_info->flags = 0; -} - -static void vnt_check_bb_vga(struct vnt_private *priv) -{ - long dbm; - int i; - - if (!priv->update_bbvga) - return; - - if (priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) - return; - - if (!(priv->vif->cfg.assoc && priv->current_rssi)) - return; - - RFvRSSITodBm(priv, (u8)priv->current_rssi, &dbm); - - for (i = 0; i < BB_VGA_LEVEL; i++) { - if (dbm < priv->dbm_threshold[i]) { - priv->bbvga_new = priv->bbvga[i]; - break; - } - } - - if (priv->bbvga_new == priv->bbvga_current) { - priv->uBBVGADiffCount = 1; - return; - } - - priv->uBBVGADiffCount++; - - if (priv->uBBVGADiffCount == 1) { - /* first VGA diff gain */ - bb_set_vga_gain_offset(priv, priv->bbvga_new); - - dev_dbg(&priv->pcid->dev, - "First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n", - (int)dbm, priv->bbvga_new, - priv->bbvga_current, - (int)priv->uBBVGADiffCount); - } - - if (priv->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) { - dev_dbg(&priv->pcid->dev, - "RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n", - (int)dbm, priv->bbvga_new, - priv->bbvga_current, - (int)priv->uBBVGADiffCount); - - bb_set_vga_gain_offset(priv, priv->bbvga_new); - } -} - -static void vnt_interrupt_process(struct vnt_private *priv) -{ - struct ieee80211_low_level_stats *low_stats = &priv->low_stats; - int max_count = 0; - u32 mib_counter; - u32 isr; - unsigned long flags; - - isr = ioread32(priv->port_offset + MAC_REG_ISR); - - if (isr == 0) - return; - - if (isr == 0xffffffff) { - pr_debug("isr = 0xffff\n"); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - - /* Read low level stats */ - mib_counter = ioread32(priv->port_offset + MAC_REG_MIBCNTR); - - low_stats->dot11RTSSuccessCount += mib_counter & 0xff; - low_stats->dot11RTSFailureCount += (mib_counter >> 8) & 0xff; - low_stats->dot11ACKFailureCount += (mib_counter >> 16) & 0xff; - low_stats->dot11FCSErrorCount += (mib_counter >> 24) & 0xff; - - /* - * TBD.... - * Must do this after doing rx/tx, cause ISR bit is slow - * than RD/TD write back - * update ISR counter - */ - while (isr && priv->vif) { - iowrite32(isr, priv->port_offset + MAC_REG_ISR); - - if (isr & ISR_FETALERR) { - pr_debug(" ISR_FETALERR\n"); - iowrite8(0, priv->port_offset + MAC_REG_SOFTPWRCTL); - iowrite16(SOFTPWRCTL_SWPECTI, priv->port_offset + MAC_REG_SOFTPWRCTL); - device_error(priv, isr); - } - - if (isr & ISR_TBTT) { - if (priv->op_mode != NL80211_IFTYPE_ADHOC) - vnt_check_bb_vga(priv); - - priv->bBeaconSent = false; - if (priv->bEnablePSMode) - PSbIsNextTBTTWakeUp((void *)priv); - - if ((priv->op_mode == NL80211_IFTYPE_AP || - priv->op_mode == NL80211_IFTYPE_ADHOC) && - priv->vif->bss_conf.enable_beacon) - MACvOneShotTimer1MicroSec(priv, - (priv->vif->bss_conf.beacon_int - - MAKE_BEACON_RESERVED) << 10); - - /* TODO: adhoc PS mode */ - } - - if (isr & ISR_BNTX) { - if (priv->op_mode == NL80211_IFTYPE_ADHOC) { - priv->bIsBeaconBufReadySet = false; - priv->cbBeaconBufReadySetCnt = 0; - } - - priv->bBeaconSent = true; - } - - if (isr & ISR_RXDMA0) - max_count += device_rx_srv(priv, TYPE_RXDMA0); - - if (isr & ISR_RXDMA1) - max_count += device_rx_srv(priv, TYPE_RXDMA1); - - if (isr & ISR_TXDMA0) - max_count += device_tx_srv(priv, TYPE_TXDMA0); - - if (isr & ISR_AC0DMA) - max_count += device_tx_srv(priv, TYPE_AC0DMA); - - if (isr & ISR_SOFTTIMER1) { - if (priv->vif->bss_conf.enable_beacon) - vnt_beacon_make(priv, priv->vif); - } - - /* If both buffers available wake the queue */ - if (AVAIL_TD(priv, TYPE_TXDMA0) && - AVAIL_TD(priv, TYPE_AC0DMA) && - ieee80211_queue_stopped(priv->hw, 0)) - ieee80211_wake_queues(priv->hw); - - isr = ioread32(priv->port_offset + MAC_REG_ISR); - - vt6655_mac_dma_ctl(priv->port_offset, MAC_REG_RXDMACTL0); - vt6655_mac_dma_ctl(priv->port_offset, MAC_REG_RXDMACTL1); - - if (max_count > priv->opts.int_works) - break; - } - - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void vnt_interrupt_work(struct work_struct *work) -{ - struct vnt_private *priv = - container_of(work, struct vnt_private, interrupt_work); - - if (priv->vif) - vnt_interrupt_process(priv); - - iowrite32(IMR_MASK_VALUE, priv->port_offset + MAC_REG_IMR); -} - -static irqreturn_t vnt_interrupt(int irq, void *arg) -{ - struct vnt_private *priv = arg; - - schedule_work(&priv->interrupt_work); - - iowrite32(0, priv->port_offset + MAC_REG_IMR); - - return IRQ_HANDLED; -} - -static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct vnt_tx_desc *head_td; - u32 dma_idx; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - if (ieee80211_is_data(hdr->frame_control)) - dma_idx = TYPE_AC0DMA; - else - dma_idx = TYPE_TXDMA0; - - if (AVAIL_TD(priv, dma_idx) < 1) { - spin_unlock_irqrestore(&priv->lock, flags); - ieee80211_stop_queues(priv->hw); - return -ENOMEM; - } - - head_td = priv->apCurrTD[dma_idx]; - - head_td->td1.tcr = 0; - - head_td->td_info->skb = skb; - - if (dma_idx == TYPE_AC0DMA) - head_td->td_info->flags = TD_FLAGS_NETIF_SKB; - - priv->apCurrTD[dma_idx] = head_td->next; - - spin_unlock_irqrestore(&priv->lock, flags); - - vnt_generate_fifo_header(priv, dma_idx, head_td, skb); - - spin_lock_irqsave(&priv->lock, flags); - - priv->bPWBitOn = false; - - /* Set TSR1 & ReqCount in TxDescHead */ - head_td->td1.tcr |= (TCR_STP | TCR_EDP | EDMSDU); - head_td->td1.req_count = cpu_to_le16(head_td->td_info->req_count); - - head_td->buff_addr = cpu_to_le32(head_td->td_info->buf_dma); - - /* Poll Transmit the adapter */ - wmb(); - head_td->td0.owner = OWNED_BY_NIC; - wmb(); /* second memory barrier */ - - if (head_td->td_info->flags & TD_FLAGS_NETIF_SKB) - vt6655_mac_dma_ctl(priv->port_offset, MAC_REG_AC0DMACTL); - else - vt6655_mac_dma_ctl(priv->port_offset, MAC_REG_TXDMACTL0); - - priv->iTDUsed[dma_idx]++; - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static void vnt_tx_80211(struct ieee80211_hw *hw, - struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct vnt_private *priv = hw->priv; - - if (vnt_tx_packet(priv, skb)) - ieee80211_free_txskb(hw, skb); -} - -static int vnt_start(struct ieee80211_hw *hw) -{ - struct vnt_private *priv = hw->priv; - int ret; - - priv->rx_buf_sz = PKT_BUF_SZ; - if (!device_init_rings(priv)) - return -ENOMEM; - - ret = request_irq(priv->pcid->irq, vnt_interrupt, - IRQF_SHARED, "vt6655", priv); - if (ret) { - dev_dbg(&priv->pcid->dev, "failed to start irq\n"); - goto err_free_rings; - } - - dev_dbg(&priv->pcid->dev, "call device init rd0 ring\n"); - ret = device_init_rd0_ring(priv); - if (ret) - goto err_free_irq; - ret = device_init_rd1_ring(priv); - if (ret) - goto err_free_rd0_ring; - ret = device_init_td0_ring(priv); - if (ret) - goto err_free_rd1_ring; - ret = device_init_td1_ring(priv); - if (ret) - goto err_free_td0_ring; - - device_init_registers(priv); - - dev_dbg(&priv->pcid->dev, "enable MAC interrupt\n"); - iowrite32(IMR_MASK_VALUE, priv->port_offset + MAC_REG_IMR); - - ieee80211_wake_queues(hw); - - return 0; - -err_free_td0_ring: - device_free_td0_ring(priv); -err_free_rd1_ring: - device_free_rd1_ring(priv); -err_free_rd0_ring: - device_free_rd0_ring(priv); -err_free_irq: - free_irq(priv->pcid->irq, priv); -err_free_rings: - device_free_rings(priv); - return ret; -} - -static void vnt_stop(struct ieee80211_hw *hw, bool suspend) -{ - struct vnt_private *priv = hw->priv; - - ieee80211_stop_queues(hw); - - cancel_work_sync(&priv->interrupt_work); - - MACbShutdown(priv); - MACbSoftwareReset(priv); - card_radio_power_off(priv); - - device_free_td0_ring(priv); - device_free_td1_ring(priv); - device_free_rd0_ring(priv); - device_free_rd1_ring(priv); - device_free_rings(priv); - - free_irq(priv->pcid->irq, priv); -} - -static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct vnt_private *priv = hw->priv; - - priv->vif = vif; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_ADHOC: - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_RCR, RCR_UNICAST); - - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_ADHOC); - - break; - case NL80211_IFTYPE_AP: - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_RCR, RCR_UNICAST); - - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_AP); - - break; - default: - return -EOPNOTSUPP; - } - - priv->op_mode = vif->type; - - return 0; -} - -static void vnt_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct vnt_private *priv = hw->priv; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_ADHOC: - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); - vt6655_mac_reg_bits_off(priv->port_offset, - MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_ADHOC); - break; - case NL80211_IFTYPE_AP: - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); - vt6655_mac_reg_bits_off(priv->port_offset, - MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_AP); - break; - default: - break; - } - - priv->op_mode = NL80211_IFTYPE_UNSPECIFIED; -} - -static int vnt_config(struct ieee80211_hw *hw, u32 changed) -{ - struct vnt_private *priv = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - u8 bb_type; - - if (changed & IEEE80211_CONF_CHANGE_PS) { - if (conf->flags & IEEE80211_CONF_PS) - PSvEnablePowerSaving(priv, conf->listen_interval); - else - PSvDisablePowerSaving(priv); - } - - if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || - (conf->flags & IEEE80211_CONF_OFFCHANNEL)) { - set_channel(priv, conf->chandef.chan); - - if (conf->chandef.chan->band == NL80211_BAND_5GHZ) - bb_type = BB_TYPE_11A; - else - bb_type = BB_TYPE_11G; - - if (priv->byBBType != bb_type) { - priv->byBBType = bb_type; - - card_set_phy_parameter(priv, priv->byBBType); - } - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - if (priv->byBBType == BB_TYPE_11B) - priv->wCurrentRate = RATE_1M; - else - priv->wCurrentRate = RATE_54M; - - RFbSetPower(priv, priv->wCurrentRate, - conf->chandef.chan->hw_value); - } - - return 0; -} - -static void vnt_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf, u64 changed) -{ - struct vnt_private *priv = hw->priv; - - priv->current_aid = vif->cfg.aid; - - if (changed & BSS_CHANGED_BSSID && conf->bssid) { - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - vt6655_mac_write_bssid_addr(priv->port_offset, conf->bssid); - - spin_unlock_irqrestore(&priv->lock, flags); - } - - if (changed & BSS_CHANGED_BASIC_RATES) { - priv->basic_rates = conf->basic_rates; - - CARDvUpdateBasicTopRate(priv); - - dev_dbg(&priv->pcid->dev, - "basic rates %x\n", conf->basic_rates); - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (conf->use_short_preamble) { - vt6655_mac_en_barker_preamble_md(priv->port_offset); - priv->preamble_type = true; - } else { - vt6655_mac_dis_barker_preamble_md(priv->port_offset); - priv->preamble_type = false; - } - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (conf->use_cts_prot) - vt6655_mac_en_protect_md(priv->port_offset); - else - vt6655_mac_dis_protect_md(priv->port_offset); - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - if (conf->use_short_slot) - priv->short_slot_time = true; - else - priv->short_slot_time = false; - - card_set_phy_parameter(priv, priv->byBBType); - bb_set_vga_gain_offset(priv, priv->bbvga[0]); - } - - if (changed & BSS_CHANGED_TXPOWER) - RFbSetPower(priv, priv->wCurrentRate, - conf->chanreq.oper.chan->hw_value); - - if (changed & BSS_CHANGED_BEACON_ENABLED) { - dev_dbg(&priv->pcid->dev, - "Beacon enable %d\n", conf->enable_beacon); - - if (conf->enable_beacon) { - vnt_beacon_enable(priv, vif, conf); - - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); - } else { - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_TCR, - TCR_AUTOBCNTX); - } - } - - if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) && - priv->op_mode != NL80211_IFTYPE_AP) { - if (vif->cfg.assoc && conf->beacon_rate) { - card_update_tsf(priv, conf->beacon_rate->hw_value, - conf->sync_tsf); - - card_set_beacon_period(priv, conf->beacon_int); - - CARDvSetFirstNextTBTT(priv, conf->beacon_int); - } else { - iowrite8(TFTCTL_TSFCNTRST, priv->port_offset + MAC_REG_TFTCTL); - iowrite8(TFTCTL_TSFCNTREN, priv->port_offset + MAC_REG_TFTCTL); - } - } -} - -static u64 vnt_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) -{ - struct vnt_private *priv = hw->priv; - struct netdev_hw_addr *ha; - u64 mc_filter = 0; - u32 bit_nr = 0; - - netdev_hw_addr_list_for_each(ha, mc_list) { - bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; - - mc_filter |= 1ULL << (bit_nr & 0x3f); - } - - priv->mc_list_count = mc_list->count; - - return mc_filter; -} - -static void vnt_configure(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, u64 multicast) -{ - struct vnt_private *priv = hw->priv; - u8 rx_mode = 0; - - *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC; - - rx_mode = ioread8(priv->port_offset + MAC_REG_RCR); - - dev_dbg(&priv->pcid->dev, "rx mode in = %x\n", rx_mode); - - if (changed_flags & FIF_ALLMULTI) { - if (*total_flags & FIF_ALLMULTI) { - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->mc_list_count > 2) { - VT6655_MAC_SELECT_PAGE1(priv->port_offset); - - iowrite32(0xffffffff, priv->port_offset + MAC_REG_MAR0); - iowrite32(0xffffffff, priv->port_offset + MAC_REG_MAR0 + 4); - - VT6655_MAC_SELECT_PAGE0(priv->port_offset); - } else { - VT6655_MAC_SELECT_PAGE1(priv->port_offset); - - multicast = le64_to_cpu(multicast); - iowrite32((u32)multicast, priv->port_offset + MAC_REG_MAR0); - iowrite32((u32)(multicast >> 32), - priv->port_offset + MAC_REG_MAR0 + 4); - - VT6655_MAC_SELECT_PAGE0(priv->port_offset); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - rx_mode |= RCR_MULTICAST | RCR_BROADCAST; - } else { - rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST); - } - } - - if (changed_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) { - rx_mode |= RCR_MULTICAST | RCR_BROADCAST; - - if (*total_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) - rx_mode &= ~RCR_BSSID; - else - rx_mode |= RCR_BSSID; - } - - iowrite8(rx_mode, priv->port_offset + MAC_REG_RCR); - - dev_dbg(&priv->pcid->dev, "rx mode out= %x\n", rx_mode); -} - -static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct vnt_private *priv = hw->priv; - - switch (cmd) { - case SET_KEY: - if (vnt_set_keys(hw, sta, vif, key)) - return -EOPNOTSUPP; - break; - case DISABLE_KEY: - if (test_bit(key->hw_key_idx, &priv->key_entry_inuse)) - clear_bit(key->hw_key_idx, &priv->key_entry_inuse); - break; - default: - break; - } - - return 0; -} - -static int vnt_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct vnt_private *priv = hw->priv; - - memcpy(stats, &priv->low_stats, sizeof(*stats)); - - return 0; -} - -static u64 vnt_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct vnt_private *priv = hw->priv; - u64 tsf; - - tsf = vt6655_get_current_tsf(priv); - - return tsf; -} - -static void vnt_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u64 tsf) -{ - struct vnt_private *priv = hw->priv; - - CARDvUpdateNextTBTT(priv, tsf, vif->bss_conf.beacon_int); -} - -static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct vnt_private *priv = hw->priv; - - /* reset TSF counter */ - iowrite8(TFTCTL_TSFCNTRST, priv->port_offset + MAC_REG_TFTCTL); -} - -static const struct ieee80211_ops vnt_mac_ops = { - .add_chanctx = ieee80211_emulate_add_chanctx, - .remove_chanctx = ieee80211_emulate_remove_chanctx, - .change_chanctx = ieee80211_emulate_change_chanctx, - .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, - .tx = vnt_tx_80211, - .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = vnt_start, - .stop = vnt_stop, - .add_interface = vnt_add_interface, - .remove_interface = vnt_remove_interface, - .config = vnt_config, - .bss_info_changed = vnt_bss_info_changed, - .prepare_multicast = vnt_prepare_multicast, - .configure_filter = vnt_configure, - .set_key = vnt_set_key, - .get_stats = vnt_get_stats, - .get_tsf = vnt_get_tsf, - .set_tsf = vnt_set_tsf, - .reset_tsf = vnt_reset_tsf, -}; - -static int vnt_init(struct vnt_private *priv) -{ - SET_IEEE80211_PERM_ADDR(priv->hw, priv->abyCurrentNetAddr); - - vnt_init_bands(priv); - - if (ieee80211_register_hw(priv->hw)) - return -ENODEV; - - priv->mac_hw = true; - - card_radio_power_off(priv); - - return 0; -} - -static int -vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) -{ - struct vnt_private *priv; - struct ieee80211_hw *hw; - struct wiphy *wiphy; - int rc; - - dev_notice(&pcid->dev, - "%s Ver. %s\n", DEVICE_FULL_DRV_NAM, DEVICE_VERSION); - - dev_notice(&pcid->dev, - "Copyright (c) 2003 VIA Networking Technologies, Inc.\n"); - - hw = ieee80211_alloc_hw(sizeof(*priv), &vnt_mac_ops); - if (!hw) { - dev_err(&pcid->dev, "could not register ieee80211_hw\n"); - return -ENOMEM; - } - - priv = hw->priv; - priv->pcid = pcid; - - spin_lock_init(&priv->lock); - - priv->hw = hw; - - SET_IEEE80211_DEV(priv->hw, &pcid->dev); - - if (pci_enable_device(pcid)) { - device_free_info(priv); - return -ENODEV; - } - - dev_dbg(&pcid->dev, - "Before get pci_info memaddr is %x\n", priv->memaddr); - - pci_set_master(pcid); - - priv->memaddr = pci_resource_start(pcid, 0); - priv->ioaddr = pci_resource_start(pcid, 1); - priv->port_offset = ioremap(priv->memaddr & PCI_BASE_ADDRESS_MEM_MASK, - 256); - if (!priv->port_offset) { - dev_err(&pcid->dev, ": Failed to IO remapping ..\n"); - device_free_info(priv); - return -ENODEV; - } - - rc = pci_request_regions(pcid, DEVICE_NAME); - if (rc) { - dev_err(&pcid->dev, ": Failed to find PCI device\n"); - device_free_info(priv); - return -ENODEV; - } - - if (dma_set_mask(&pcid->dev, DMA_BIT_MASK(32))) { - dev_err(&pcid->dev, ": Failed to set dma 32 bit mask\n"); - device_free_info(priv); - return -ENODEV; - } - - INIT_WORK(&priv->interrupt_work, vnt_interrupt_work); - - /* do reset */ - if (!MACbSoftwareReset(priv)) { - dev_err(&pcid->dev, ": Failed to access MAC hardware..\n"); - device_free_info(priv); - return -ENODEV; - } - /* initial to reload eeprom */ - MACvInitialize(priv); - vt6655_mac_read_ether_addr(priv->port_offset, priv->abyCurrentNetAddr); - - /* Get RFType */ - priv->rf_type = SROMbyReadEmbedded(priv->port_offset, EEP_OFS_RFTYPE); - priv->rf_type &= RF_MASK; - - dev_dbg(&pcid->dev, "RF Type = %x\n", priv->rf_type); - - device_get_options(priv); - device_set_options(priv); - - wiphy = priv->hw->wiphy; - - wiphy->frag_threshold = FRAG_THRESH_DEF; - wiphy->rts_threshold = RTS_THRESH_DEF; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); - - ieee80211_hw_set(priv->hw, TIMING_BEACON_ONLY); - ieee80211_hw_set(priv->hw, SIGNAL_DBM); - ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS); - ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS); - ieee80211_hw_set(priv->hw, SUPPORTS_PS); - - priv->hw->max_signal = 100; - - if (vnt_init(priv)) { - device_free_info(priv); - return -ENODEV; - } - - device_print_info(priv); - pci_set_drvdata(pcid, priv); - - return 0; -} - -/*------------------------------------------------------------------*/ - -static int __maybe_unused vt6655_suspend(struct device *dev_d) -{ - struct vnt_private *priv = dev_get_drvdata(dev_d); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - MACbShutdown(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static int __maybe_unused vt6655_resume(struct device *dev_d) -{ - device_wakeup_disable(dev_d); - - return 0; -} - -MODULE_DEVICE_TABLE(pci, vt6655_pci_id_table); - -static SIMPLE_DEV_PM_OPS(vt6655_pm_ops, vt6655_suspend, vt6655_resume); - -static struct pci_driver device_driver = { - .name = DEVICE_NAME, - .id_table = vt6655_pci_id_table, - .probe = vt6655_probe, - .remove = vt6655_remove, - .driver.pm = &vt6655_pm_ops, -}; - -module_pci_driver(device_driver); diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c deleted file mode 100644 index 7ada188e204894..00000000000000 --- a/drivers/staging/vt6655/dpc.c +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: handle dpc rx functions - * - * Author: Lyndon Chen - * - * Date: May 20, 2003 - * - * Functions: - * - * Revision History: - * - */ - -#include "device.h" -#include "baseband.h" -#include "rf.h" -#include "dpc.h" - -static bool vnt_rx_data(struct vnt_private *priv, struct sk_buff *skb, - u16 bytes_received) -{ - struct ieee80211_hw *hw = priv->hw; - struct ieee80211_supported_band *sband; - struct ieee80211_rx_status rx_status = { 0 }; - struct ieee80211_hdr *hdr; - __le16 fc; - u8 *rsr, *new_rsr, *rssi; - __le64 *tsf_time; - u16 frame_size; - int ii, r; - u8 *rx_rate; - u8 *skb_data; - u8 rate_idx = 0; - u8 rate[MAX_RATE] = {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108}; - long rx_dbm; - - /* [31:16]RcvByteCount ( not include 4-byte Status ) */ - frame_size = le16_to_cpu(*((__le16 *)(skb->data + 2))); - if (frame_size > 2346 || frame_size < 14) { - dev_dbg(&priv->pcid->dev, "------- WRONG Length 1\n"); - return false; - } - - skb_data = (u8 *)skb->data; - - rx_rate = skb_data + 1; - - sband = hw->wiphy->bands[hw->conf.chandef.chan->band]; - - for (r = RATE_1M; r < MAX_RATE; r++) { - if (*rx_rate == rate[r]) - break; - } - - priv->rx_rate = r; - - for (ii = 0; ii < sband->n_bitrates; ii++) { - if (sband->bitrates[ii].hw_value == r) { - rate_idx = ii; - break; - } - } - - if (ii == sband->n_bitrates) { - dev_dbg(&priv->pcid->dev, "Wrong RxRate %x\n", *rx_rate); - return false; - } - - tsf_time = (__le64 *)(skb_data + bytes_received - 12); - new_rsr = skb_data + bytes_received - 3; - rssi = skb_data + bytes_received - 2; - rsr = skb_data + bytes_received - 1; - if (*rsr & (RSR_IVLDTYP | RSR_IVLDLEN)) - return false; - - RFvRSSITodBm(priv, *rssi, &rx_dbm); - - priv->bb_pre_edrssi = (u8)rx_dbm + 1; - priv->current_rssi = *rssi; - - skb_pull(skb, 4); - skb_trim(skb, frame_size); - - rx_status.mactime = le64_to_cpu(*tsf_time); - rx_status.band = hw->conf.chandef.chan->band; - rx_status.signal = rx_dbm; - rx_status.flag = 0; - rx_status.freq = hw->conf.chandef.chan->center_freq; - - if (!(*rsr & RSR_CRCOK)) - rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; - - hdr = (struct ieee80211_hdr *)(skb->data); - fc = hdr->frame_control; - - rx_status.rate_idx = rate_idx; - - if (ieee80211_has_protected(fc)) { - if (priv->local_id > REV_ID_VT3253_A1) - rx_status.flag |= RX_FLAG_DECRYPTED; - - /* Drop packet */ - if (!(*new_rsr & NEWRSR_DECRYPTOK)) - return false; - } - - memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); - - ieee80211_rx_irqsafe(priv->hw, skb); - - return true; -} - -bool vnt_receive_frame(struct vnt_private *priv, struct vnt_rx_desc *curr_rd) -{ - struct vnt_rd_info *rd_info = curr_rd->rd_info; - struct sk_buff *skb; - u16 frame_size; - - skb = rd_info->skb; - - dma_unmap_single(&priv->pcid->dev, rd_info->skb_dma, - priv->rx_buf_sz, DMA_FROM_DEVICE); - - frame_size = le16_to_cpu(curr_rd->rd1.req_count) - - le16_to_cpu(curr_rd->rd0.res_count); - - if ((frame_size > 2364) || (frame_size < 33)) { - /* Frame Size error drop this packet.*/ - dev_dbg(&priv->pcid->dev, "Wrong frame size %d\n", frame_size); - dev_kfree_skb_irq(skb); - return true; - } - - if (vnt_rx_data(priv, skb, frame_size)) - return true; - - dev_kfree_skb_irq(skb); - - return true; -} diff --git a/drivers/staging/vt6655/dpc.h b/drivers/staging/vt6655/dpc.h deleted file mode 100644 index 40364c0ab7f64f..00000000000000 --- a/drivers/staging/vt6655/dpc.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: - * - * Author: Jerry Chen - * - * Date: Jun. 27, 2002 - * - */ - -#ifndef __DPC_H__ -#define __DPC_H__ - -#include "device.h" - -bool vnt_receive_frame(struct vnt_private *priv, struct vnt_rx_desc *curr_rd); - -#endif /* __RXTX_H__ */ diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c deleted file mode 100644 index 1469015eb5b4a6..00000000000000 --- a/drivers/staging/vt6655/key.c +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions for 802.11i Key management - * - * Author: Jerry Chen - * - * Date: May 29, 2003 - * - */ - -#include "key.h" -#include "mac.h" - -static int vnt_set_keymode(struct ieee80211_hw *hw, u8 *mac_addr, - struct ieee80211_key_conf *key, u32 key_type, - u32 mode, bool onfly_latch) -{ - struct vnt_private *priv = hw->priv; - u8 broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - u16 key_mode = 0; - u32 entry = 0; - u8 *bssid; - u8 key_inx = key->keyidx; - u8 i; - - if (mac_addr) - bssid = mac_addr; - else - bssid = &broadcast[0]; - - if (key_type != VNT_KEY_DEFAULTKEY) { - for (i = 0; i < (MAX_KEY_TABLE - 1); i++) { - if (!test_bit(i, &priv->key_entry_inuse)) { - set_bit(i, &priv->key_entry_inuse); - - key->hw_key_idx = i; - entry = key->hw_key_idx; - break; - } - } - } - - switch (key_type) { - case VNT_KEY_DEFAULTKEY: - /* default key last entry */ - entry = MAX_KEY_TABLE - 1; - key->hw_key_idx = entry; - fallthrough; - case VNT_KEY_ALLGROUP: - key_mode |= VNT_KEY_ALLGROUP; - if (onfly_latch) - key_mode |= VNT_KEY_ONFLY_ALL; - fallthrough; - case VNT_KEY_GROUP_ADDRESS: - key_mode |= mode; - fallthrough; - case VNT_KEY_GROUP: - key_mode |= (mode << 4); - key_mode |= VNT_KEY_GROUP; - break; - case VNT_KEY_PAIRWISE: - key_mode |= mode; - key_inx = 4; - break; - default: - return -EINVAL; - } - - if (onfly_latch) - key_mode |= VNT_KEY_ONFLY; - - if (mode == KEY_CTL_WEP) { - if (key->keylen == WLAN_KEY_LEN_WEP40) - key->key[15] &= 0x7f; - if (key->keylen == WLAN_KEY_LEN_WEP104) - key->key[15] |= 0x80; - } - - MACvSetKeyEntry(priv, key_mode, entry, key_inx, - bssid, (u32 *)key->key, priv->local_id); - - return 0; -} - -int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, struct ieee80211_key_conf *key) -{ - struct ieee80211_bss_conf *conf = &vif->bss_conf; - struct vnt_private *priv = hw->priv; - u8 *mac_addr = NULL; - u8 key_dec_mode = 0; - int ret = 0; - u32 u; - - if (sta) - mac_addr = &sta->addr[0]; - - switch (key->cipher) { - case 0: - for (u = 0 ; u < MAX_KEY_TABLE; u++) - MACvDisableKeyEntry(priv, u); - return ret; - - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - for (u = 0; u < MAX_KEY_TABLE; u++) - MACvDisableKeyEntry(priv, u); - - vnt_set_keymode(hw, mac_addr, - key, VNT_KEY_DEFAULTKEY, KEY_CTL_WEP, true); - - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - - return ret; - case WLAN_CIPHER_SUITE_TKIP: - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - - key_dec_mode = KEY_CTL_TKIP; - - break; - case WLAN_CIPHER_SUITE_CCMP: - key_dec_mode = KEY_CTL_CCMP; - - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - } - - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { - vnt_set_keymode(hw, mac_addr, - key, VNT_KEY_PAIRWISE, key_dec_mode, true); - } else { - vnt_set_keymode(hw, mac_addr, - key, VNT_KEY_DEFAULTKEY, key_dec_mode, true); - - vnt_set_keymode(hw, (u8 *)conf->bssid, - key, VNT_KEY_GROUP_ADDRESS, key_dec_mode, true); - } - - return 0; -} diff --git a/drivers/staging/vt6655/key.h b/drivers/staging/vt6655/key.h deleted file mode 100644 index d88da9dfb5c3be..00000000000000 --- a/drivers/staging/vt6655/key.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions for 802.11i Key management - * - * Author: Jerry Chen - * - * Date: May 29, 2003 - * - */ - -#ifndef __KEY_H__ -#define __KEY_H__ - -#include - -/*--------------------- Export Definitions -------------------------*/ -#define MAX_GROUP_KEY 4 -#define MAX_KEY_TABLE 11 -#define MAX_KEY_LEN 32 -#define AES_KEY_LEN 16 - -#define AUTHENTICATOR_KEY 0x10000000 -#define USE_KEYRSC 0x20000000 -#define PAIRWISE_KEY 0x40000000 -#define TRANSMIT_KEY 0x80000000 - -#define GROUP_KEY 0x00000000 - -#define KEY_CTL_WEP 0x00 -#define KEY_CTL_NONE 0x01 -#define KEY_CTL_TKIP 0x02 -#define KEY_CTL_CCMP 0x03 -#define KEY_CTL_INVALID 0xFF - -#define VNT_KEY_DEFAULTKEY 0x1 -#define VNT_KEY_GROUP_ADDRESS 0x2 -#define VNT_KEY_ALLGROUP 0x4 -#define VNT_KEY_GROUP 0x40 -#define VNT_KEY_PAIRWISE 0x00 -#define VNT_KEY_ONFLY 0x8000 -#define VNT_KEY_ONFLY_ALL 0x4000 - -struct vnt_private; - -int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, struct ieee80211_key_conf *key); - -#endif /* __KEY_H__ */ diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c deleted file mode 100644 index b4ebc7d3196190..00000000000000 --- a/drivers/staging/vt6655/mac.c +++ /dev/null @@ -1,851 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: MAC routines - * - * Author: Tevin Chen - * - * Date: May 21, 1996 - * - * Functions: - * vt6655_mac_is_reg_bits_off - Test if All test Bits Off - * vt6655_mac_set_short_retry_limit - Set 802.11 Short Retry limit - * MACvSetLongRetryLimit - Set 802.11 Long Retry limit - * vt6655_mac_set_loopback_mode - Set MAC Loopback Mode - * vt6655_mac_save_context - Save Context of MAC Registers - * vt6655_mac_restore_context - Restore Context of MAC Registers - * MACbSoftwareReset - Software Reset MAC - * vt6655_mac_safe_rx_off - Turn Off MAC Rx - * vt6655_mac_safe_tx_off - Turn Off MAC Tx - * vt6655_mac_safe_stop - Stop MAC function - * MACbShutdown - Shut down MAC - * MACvInitialize - Initialize MAC - * MACvSetCurrRxDescAddr - Set Rx Descriptors Address - * MACvSetCurrTx0DescAddr - Set Tx0 Descriptors Address - * MACvSetCurrTx1DescAddr - Set Tx1 Descriptors Address - * MACvTimer0MicroSDelay - Micro Second Delay Loop by MAC - * - * Revision History: - * 08-22-2003 Kyle Hsu : Porting MAC functions from sim53 - * 09-03-2003 Bryan YC Fan : Add MACvClearBusSusInd()& - * MACvEnableBusSusEn() - * 09-18-2003 Jerry Chen : Add MACvSetKeyEntry & MACvDisableKeyEntry - * - */ - -#include "mac.h" - -void vt6655_mac_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask) -{ - unsigned char reg_value; - - reg_value = ioread8(iobase + reg_offset); - iowrite8(reg_value | bit_mask, iobase + reg_offset); -} - -void vt6655_mac_word_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask) -{ - unsigned short reg_value; - - reg_value = ioread16(iobase + reg_offset); - iowrite16(reg_value | (bit_mask), iobase + reg_offset); -} - -void vt6655_mac_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask) -{ - unsigned char reg_value; - - reg_value = ioread8(iobase + reg_offset); - iowrite8(reg_value & ~(bit_mask), iobase + reg_offset); -} - -void vt6655_mac_word_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask) -{ - unsigned short reg_value; - - reg_value = ioread16(iobase + reg_offset); - iowrite16(reg_value & ~(bit_mask), iobase + reg_offset); -} - -static void vt6655_mac_clear_stck_ds(void __iomem *iobase) -{ - u8 reg_value; - - reg_value = ioread8(iobase + MAC_REG_STICKHW); - reg_value = reg_value & 0xFC; - iowrite8(reg_value, iobase + MAC_REG_STICKHW); -} - -/* - * Description: - * Test if all test bits off - * - * Parameters: - * In: - * io_base - Base Address for MAC - * reg_offset - Offset of MAC Register - * mask - Test bits - * Out: - * none - * - * Return Value: true if all test bits Off; otherwise false - * - */ -static bool vt6655_mac_is_reg_bits_off(struct vnt_private *priv, - unsigned char reg_offset, - unsigned char mask) -{ - void __iomem *io_base = priv->port_offset; - - return !(ioread8(io_base + reg_offset) & mask); -} - -/* - * Description: - * Set 802.11 Short Retry Limit - * - * Parameters: - * In: - * io_base - Base Address for MAC - * retry_limit - Retry Limit - * Out: - * none - * - * Return Value: none - * - */ -void vt6655_mac_set_short_retry_limit(struct vnt_private *priv, unsigned char retry_limit) -{ - void __iomem *io_base = priv->port_offset; - /* set SRT */ - iowrite8(retry_limit, io_base + MAC_REG_SRT); -} - -/* - * Description: - * Set 802.11 Long Retry Limit - * - * Parameters: - * In: - * io_base - Base Address for MAC - * byRetryLimit- Retry Limit - * Out: - * none - * - * Return Value: none - * - */ -void MACvSetLongRetryLimit(struct vnt_private *priv, - unsigned char byRetryLimit) -{ - void __iomem *io_base = priv->port_offset; - /* set LRT */ - iowrite8(byRetryLimit, io_base + MAC_REG_LRT); -} - -/* - * Description: - * Set MAC Loopback mode - * - * Parameters: - * In: - * io_base - Base Address for MAC - * loopback_mode - Loopback Mode - * Out: - * none - * - * Return Value: none - * - */ -static void vt6655_mac_set_loopback_mode(struct vnt_private *priv, u8 loopback_mode) -{ - void __iomem *io_base = priv->port_offset; - - loopback_mode <<= 6; - /* set TCR */ - iowrite8((ioread8(io_base + MAC_REG_TEST) & 0x3f) | loopback_mode, io_base + MAC_REG_TEST); -} - -/* - * Description: - * Save MAC registers to context buffer - * - * Parameters: - * In: - * io_base - Base Address for MAC - * Out: - * cxt_buf - Context buffer - * - * Return Value: none - * - */ -static void vt6655_mac_save_context(struct vnt_private *priv, u8 *cxt_buf) -{ - void __iomem *io_base = priv->port_offset; - - /* read page0 register */ - memcpy_fromio(cxt_buf, io_base, MAC_MAX_CONTEXT_SIZE_PAGE0); - - VT6655_MAC_SELECT_PAGE1(io_base); - - /* read page1 register */ - memcpy_fromio(cxt_buf + MAC_MAX_CONTEXT_SIZE_PAGE0, io_base, - MAC_MAX_CONTEXT_SIZE_PAGE1); - - VT6655_MAC_SELECT_PAGE0(io_base); -} - -/* - * Description: - * Restore MAC registers from context buffer - * - * Parameters: - * In: - * io_base - Base Address for MAC - * cxt_buf - Context buffer - * Out: - * none - * - * Return Value: none - * - */ -static void vt6655_mac_restore_context(struct vnt_private *priv, u8 *cxt_buf) -{ - void __iomem *io_base = priv->port_offset; - - VT6655_MAC_SELECT_PAGE1(io_base); - /* restore page1 */ - memcpy_toio(io_base, cxt_buf + MAC_MAX_CONTEXT_SIZE_PAGE0, - MAC_MAX_CONTEXT_SIZE_PAGE1); - - VT6655_MAC_SELECT_PAGE0(io_base); - - /* restore RCR,TCR,IMR... */ - memcpy_toio(io_base + MAC_REG_RCR, cxt_buf + MAC_REG_RCR, - MAC_REG_ISR - MAC_REG_RCR); - - /* restore MAC Config. */ - memcpy_toio(io_base + MAC_REG_LRT, cxt_buf + MAC_REG_LRT, - MAC_REG_PAGE1SEL - MAC_REG_LRT); - - iowrite8(*(cxt_buf + MAC_REG_CFG), io_base + MAC_REG_CFG); - - /* restore PS Config. */ - memcpy_toio(io_base + MAC_REG_PSCFG, cxt_buf + MAC_REG_PSCFG, - MAC_REG_BBREGCTL - MAC_REG_PSCFG); - - /* restore CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR */ - iowrite32(*(u32 *)(cxt_buf + MAC_REG_TXDMAPTR0), - io_base + MAC_REG_TXDMAPTR0); - iowrite32(*(u32 *)(cxt_buf + MAC_REG_AC0DMAPTR), - io_base + MAC_REG_AC0DMAPTR); - iowrite32(*(u32 *)(cxt_buf + MAC_REG_BCNDMAPTR), - io_base + MAC_REG_BCNDMAPTR); - iowrite32(*(u32 *)(cxt_buf + MAC_REG_RXDMAPTR0), - io_base + MAC_REG_RXDMAPTR0); - iowrite32(*(u32 *)(cxt_buf + MAC_REG_RXDMAPTR1), - io_base + MAC_REG_RXDMAPTR1); -} - -/* - * Description: - * Software Reset MAC - * - * Parameters: - * In: - * io_base - Base Address for MAC - * Out: - * none - * - * Return Value: true if Reset Success; otherwise false - * - */ -bool MACbSoftwareReset(struct vnt_private *priv) -{ - void __iomem *io_base = priv->port_offset; - unsigned short ww; - - /* turn on HOSTCR_SOFTRST, just write 0x01 to reset */ - iowrite8(0x01, io_base + MAC_REG_HOSTCR); - - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread8(io_base + MAC_REG_HOSTCR) & HOSTCR_SOFTRST)) - break; - } - if (ww == W_MAX_TIMEOUT) - return false; - return true; -} - -/* - * Description: - * save some important register's value, then do reset, then restore - * register's value - * - * Parameters: - * In: - * io_base - Base Address for MAC - * Out: - * none - * - * Return Value: true if success; otherwise false - * - */ -static void vt6655_mac_save_soft_reset(struct vnt_private *priv) -{ - u8 tmp_reg_data[MAC_MAX_CONTEXT_SIZE_PAGE0 + MAC_MAX_CONTEXT_SIZE_PAGE1]; - - /* PATCH.... - * save some important register's value, then do - * reset, then restore register's value - */ - /* save MAC context */ - vt6655_mac_save_context(priv, tmp_reg_data); - /* do reset */ - MACbSoftwareReset(priv); - /* restore MAC context, except CR0 */ - vt6655_mac_restore_context(priv, tmp_reg_data); -} - -/* - * Description: - * Turn Off MAC Rx - * - * Parameters: - * In: - * io_base - Base Address for MAC - * Out: - * none - * - * Return Value: true if success; otherwise false - * - */ -static bool vt6655_mac_safe_rx_off(struct vnt_private *priv) -{ - void __iomem *io_base = priv->port_offset; - unsigned short ww; - - /* turn off wow temp for turn off Rx safely */ - - /* Clear RX DMA0,1 */ - iowrite32(DMACTL_CLRRUN, io_base + MAC_REG_RXDMACTL0); - iowrite32(DMACTL_CLRRUN, io_base + MAC_REG_RXDMACTL1); - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread32(io_base + MAC_REG_RXDMACTL0) & DMACTL_RUN)) - break; - } - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x10)\n"); - return false; - } - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread32(io_base + MAC_REG_RXDMACTL1) & DMACTL_RUN)) - break; - } - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x11)\n"); - return false; - } - - /* try to safe shutdown RX */ - vt6655_mac_reg_bits_off(io_base, MAC_REG_HOSTCR, HOSTCR_RXON); - /* W_MAX_TIMEOUT is the timeout period */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread8(io_base + MAC_REG_HOSTCR) & HOSTCR_RXONST)) - break; - } - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x12)\n"); - return false; - } - return true; -} - -/* - * Description: - * Turn Off MAC Tx - * - * Parameters: - * In: - * io_base - Base Address for MAC - * Out: - * none - * - * Return Value: true if success; otherwise false - * - */ -static bool vt6655_mac_safe_tx_off(struct vnt_private *priv) -{ - void __iomem *io_base = priv->port_offset; - unsigned short ww; - - /* Clear TX DMA */ - /* Tx0 */ - iowrite32(DMACTL_CLRRUN, io_base + MAC_REG_TXDMACTL0); - /* AC0 */ - iowrite32(DMACTL_CLRRUN, io_base + MAC_REG_AC0DMACTL); - - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread32(io_base + MAC_REG_TXDMACTL0) & DMACTL_RUN)) - break; - } - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x20)\n"); - return false; - } - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread32(io_base + MAC_REG_AC0DMACTL) & DMACTL_RUN)) - break; - } - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x21)\n"); - return false; - } - - /* try to safe shutdown TX */ - vt6655_mac_reg_bits_off(io_base, MAC_REG_HOSTCR, HOSTCR_TXON); - - /* W_MAX_TIMEOUT is the timeout period */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread8(io_base + MAC_REG_HOSTCR) & HOSTCR_TXONST)) - break; - } - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x24)\n"); - return false; - } - return true; -} - -/* - * Description: - * Stop MAC function - * - * Parameters: - * In: - * io_base - Base Address for MAC - * Out: - * none - * - * Return Value: true if success; otherwise false - * - */ -static bool vt6655_mac_safe_stop(struct vnt_private *priv) -{ - void __iomem *io_base = priv->port_offset; - - vt6655_mac_reg_bits_off(io_base, MAC_REG_TCR, TCR_AUTOBCNTX); - - if (!vt6655_mac_safe_rx_off(priv)) { - pr_debug(" vt6655_mac_safe_rx_off == false)\n"); - vt6655_mac_save_soft_reset(priv); - return false; - } - if (!vt6655_mac_safe_tx_off(priv)) { - pr_debug(" vt6655_mac_safe_tx_off == false)\n"); - vt6655_mac_save_soft_reset(priv); - return false; - } - - vt6655_mac_reg_bits_off(io_base, MAC_REG_HOSTCR, HOSTCR_MACEN); - - return true; -} - -/* - * Description: - * Shut Down MAC - * - * Parameters: - * In: - * io_base - Base Address for MAC - * Out: - * none - * - * Return Value: true if success; otherwise false - * - */ -bool MACbShutdown(struct vnt_private *priv) -{ - void __iomem *io_base = priv->port_offset; - /* disable MAC IMR */ - iowrite32(0, io_base + MAC_REG_IMR); - vt6655_mac_set_loopback_mode(priv, MAC_LB_INTERNAL); - /* stop the adapter */ - if (!vt6655_mac_safe_stop(priv)) { - vt6655_mac_set_loopback_mode(priv, MAC_LB_NONE); - return false; - } - vt6655_mac_set_loopback_mode(priv, MAC_LB_NONE); - return true; -} - -/* - * Description: - * Initialize MAC - * - * Parameters: - * In: - * io_base - Base Address for MAC - * Out: - * none - * - * Return Value: none - * - */ -void MACvInitialize(struct vnt_private *priv) -{ - void __iomem *io_base = priv->port_offset; - /* clear sticky bits */ - vt6655_mac_clear_stck_ds(io_base); - /* disable force PME-enable */ - iowrite8(PME_OVR, io_base + MAC_REG_PMC1); - /* only 3253 A */ - - /* do reset */ - MACbSoftwareReset(priv); - - /* reset TSF counter */ - iowrite8(TFTCTL_TSFCNTRST, io_base + MAC_REG_TFTCTL); - /* enable TSF counter */ - iowrite8(TFTCTL_TSFCNTREN, io_base + MAC_REG_TFTCTL); -} - -/* - * Description: - * Set the chip with current rx descriptor address - * - * Parameters: - * In: - * io_base - Base Address for MAC - * curr_desc_addr - Descriptor Address - * Out: - * none - * - * Return Value: none - * - */ -void vt6655_mac_set_curr_rx_0_desc_addr(struct vnt_private *priv, u32 curr_desc_addr) -{ - void __iomem *io_base = priv->port_offset; - unsigned short ww; - unsigned char org_dma_ctl; - - org_dma_ctl = ioread8(io_base + MAC_REG_RXDMACTL0); - if (org_dma_ctl & DMACTL_RUN) - iowrite8(DMACTL_RUN, io_base + MAC_REG_RXDMACTL0 + 2); - - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread8(io_base + MAC_REG_RXDMACTL0) & DMACTL_RUN)) - break; - } - - iowrite32(curr_desc_addr, io_base + MAC_REG_RXDMAPTR0); - if (org_dma_ctl & DMACTL_RUN) - iowrite8(DMACTL_RUN, io_base + MAC_REG_RXDMACTL0); -} - -/* - * Description: - * Set the chip with current rx descriptor address - * - * Parameters: - * In: - * io_base - Base Address for MAC - * curr_desc_addr - Descriptor Address - * Out: - * none - * - * Return Value: none - * - */ -void vt6655_mac_set_curr_rx_1_desc_addr(struct vnt_private *priv, u32 curr_desc_addr) -{ - void __iomem *io_base = priv->port_offset; - unsigned short ww; - unsigned char org_dma_ctl; - - org_dma_ctl = ioread8(io_base + MAC_REG_RXDMACTL1); - if (org_dma_ctl & DMACTL_RUN) - iowrite8(DMACTL_RUN, io_base + MAC_REG_RXDMACTL1 + 2); - - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread8(io_base + MAC_REG_RXDMACTL1) & DMACTL_RUN)) - break; - } - - iowrite32(curr_desc_addr, io_base + MAC_REG_RXDMAPTR1); - if (org_dma_ctl & DMACTL_RUN) - iowrite8(DMACTL_RUN, io_base + MAC_REG_RXDMACTL1); -} - -/* - * Description: - * Set the chip with current tx0 descriptor address - * - * Parameters: - * In: - * io_base - Base Address for MAC - * curr_desc_addr - Descriptor Address - * Out: - * none - * - * Return Value: none - * - */ -static void vt6655_mac_set_curr_tx_0_desc_addr_ex(struct vnt_private *priv, u32 curr_desc_addr) -{ - void __iomem *io_base = priv->port_offset; - unsigned short ww; - unsigned char org_dma_ctl; - - org_dma_ctl = ioread8(io_base + MAC_REG_TXDMACTL0); - if (org_dma_ctl & DMACTL_RUN) - iowrite8(DMACTL_RUN, io_base + MAC_REG_TXDMACTL0 + 2); - - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread8(io_base + MAC_REG_TXDMACTL0) & DMACTL_RUN)) - break; - } - - iowrite32(curr_desc_addr, io_base + MAC_REG_TXDMAPTR0); - if (org_dma_ctl & DMACTL_RUN) - iowrite8(DMACTL_RUN, io_base + MAC_REG_TXDMACTL0); -} - -/* - * Description: - * Set the chip with current AC0 descriptor address - * - * Parameters: - * In: - * io_base - Base Address for MAC - * curr_desc_addr - Descriptor Address - * Out: - * none - * - * Return Value: none - * - */ -/* TxDMA1 = AC0DMA */ -static void vt6655_mac_set_curr_ac_0_desc_addr_ex(struct vnt_private *priv, u32 curr_desc_addr) -{ - void __iomem *io_base = priv->port_offset; - unsigned short ww; - unsigned char org_dma_ctl; - - org_dma_ctl = ioread8(io_base + MAC_REG_AC0DMACTL); - if (org_dma_ctl & DMACTL_RUN) - iowrite8(DMACTL_RUN, io_base + MAC_REG_AC0DMACTL + 2); - - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (!(ioread8(io_base + MAC_REG_AC0DMACTL) & DMACTL_RUN)) - break; - } - if (ww == W_MAX_TIMEOUT) - pr_debug(" DBG_PORT80(0x26)\n"); - iowrite32(curr_desc_addr, io_base + MAC_REG_AC0DMAPTR); - if (org_dma_ctl & DMACTL_RUN) - iowrite8(DMACTL_RUN, io_base + MAC_REG_AC0DMACTL); -} - -void vt6655_mac_set_curr_tx_desc_addr(int tx_type, struct vnt_private *priv, u32 curr_desc_addr) -{ - if (tx_type == TYPE_AC0DMA) - vt6655_mac_set_curr_ac_0_desc_addr_ex(priv, curr_desc_addr); - else if (tx_type == TYPE_TXDMA0) - vt6655_mac_set_curr_tx_0_desc_addr_ex(priv, curr_desc_addr); -} - -/* - * Description: - * Micro Second Delay via MAC - * - * Parameters: - * In: - * io_base - Base Address for MAC - * uDelay - Delay time (timer resolution is 4 us) - * Out: - * none - * - * Return Value: none - * - */ -void MACvTimer0MicroSDelay(struct vnt_private *priv, unsigned int uDelay) -{ - void __iomem *io_base = priv->port_offset; - unsigned char byValue; - unsigned int uu, ii; - - iowrite8(0, io_base + MAC_REG_TMCTL0); - iowrite32(uDelay, io_base + MAC_REG_TMDATA0); - iowrite8((TMCTL_TMD | TMCTL_TE), io_base + MAC_REG_TMCTL0); - for (ii = 0; ii < 66; ii++) { /* assume max PCI clock is 66Mhz */ - for (uu = 0; uu < uDelay; uu++) { - byValue = ioread8(io_base + MAC_REG_TMCTL0); - if ((byValue == 0) || - (byValue & TMCTL_TSUSP)) { - iowrite8(0, io_base + MAC_REG_TMCTL0); - return; - } - } - } - iowrite8(0, io_base + MAC_REG_TMCTL0); -} - -/* - * Description: - * Micro Second One shot timer via MAC - * - * Parameters: - * In: - * io_base - Base Address for MAC - * uDelay - Delay time - * Out: - * none - * - * Return Value: none - * - */ -void MACvOneShotTimer1MicroSec(struct vnt_private *priv, - unsigned int uDelayTime) -{ - void __iomem *io_base = priv->port_offset; - - iowrite8(0, io_base + MAC_REG_TMCTL1); - iowrite32(uDelayTime, io_base + MAC_REG_TMDATA1); - iowrite8((TMCTL_TMD | TMCTL_TE), io_base + MAC_REG_TMCTL1); -} - -void MACvSetMISCFifo(struct vnt_private *priv, unsigned short offset, - u32 data) -{ - void __iomem *io_base = priv->port_offset; - - if (offset > 273) - return; - iowrite16(offset, io_base + MAC_REG_MISCFFNDEX); - iowrite32(data, io_base + MAC_REG_MISCFFDATA); - iowrite16(MISCFFCTL_WRITE, io_base + MAC_REG_MISCFFCTL); -} - -bool MACbPSWakeup(struct vnt_private *priv) -{ - void __iomem *io_base = priv->port_offset; - unsigned int ww; - /* Read PSCTL */ - if (vt6655_mac_is_reg_bits_off(priv, MAC_REG_PSCTL, PSCTL_PS)) - return true; - - /* Disable PS */ - vt6655_mac_reg_bits_off(io_base, MAC_REG_PSCTL, PSCTL_PSEN); - - /* Check if SyncFlushOK */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - if (ioread8(io_base + MAC_REG_PSCTL) & PSCTL_WAKEDONE) - break; - } - if (ww == W_MAX_TIMEOUT) { - pr_debug(" DBG_PORT80(0x33)\n"); - return false; - } - return true; -} - -/* - * Description: - * Set the Key by MISCFIFO - * - * Parameters: - * In: - * io_base - Base Address for MAC - * - * Out: - * none - * - * Return Value: none - * - */ - -void MACvSetKeyEntry(struct vnt_private *priv, unsigned short wKeyCtl, - unsigned int uEntryIdx, unsigned int uKeyIdx, - unsigned char *pbyAddr, u32 *pdwKey, - unsigned char local_id) -{ - void __iomem *io_base = priv->port_offset; - unsigned short offset; - u32 data; - int ii; - - if (local_id <= 1) - return; - - offset = MISCFIFO_KEYETRY0; - offset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE); - - data = 0; - data |= wKeyCtl; - data <<= 16; - data |= MAKEWORD(*(pbyAddr + 4), *(pbyAddr + 5)); - pr_debug("1. offset: %d, Data: %X, KeyCtl:%X\n", - offset, data, wKeyCtl); - - iowrite16(offset, io_base + MAC_REG_MISCFFNDEX); - iowrite32(data, io_base + MAC_REG_MISCFFDATA); - iowrite16(MISCFFCTL_WRITE, io_base + MAC_REG_MISCFFCTL); - offset++; - - data = 0; - data |= *(pbyAddr + 3); - data <<= 8; - data |= *(pbyAddr + 2); - data <<= 8; - data |= *(pbyAddr + 1); - data <<= 8; - data |= *pbyAddr; - pr_debug("2. offset: %d, Data: %X\n", offset, data); - - iowrite16(offset, io_base + MAC_REG_MISCFFNDEX); - iowrite32(data, io_base + MAC_REG_MISCFFDATA); - iowrite16(MISCFFCTL_WRITE, io_base + MAC_REG_MISCFFCTL); - offset++; - - offset += (uKeyIdx * 4); - for (ii = 0; ii < 4; ii++) { - /* always push 128 bits */ - pr_debug("3.(%d) offset: %d, Data: %X\n", - ii, offset + ii, *pdwKey); - iowrite16(offset + ii, io_base + MAC_REG_MISCFFNDEX); - iowrite32(*pdwKey++, io_base + MAC_REG_MISCFFDATA); - iowrite16(MISCFFCTL_WRITE, io_base + MAC_REG_MISCFFCTL); - } -} - -/* - * Description: - * Disable the Key Entry by MISCFIFO - * - * Parameters: - * In: - * io_base - Base Address for MAC - * - * Out: - * none - * - * Return Value: none - * - */ -void MACvDisableKeyEntry(struct vnt_private *priv, unsigned int uEntryIdx) -{ - void __iomem *io_base = priv->port_offset; - unsigned short offset; - - offset = MISCFIFO_KEYETRY0; - offset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE); - - iowrite16(offset, io_base + MAC_REG_MISCFFNDEX); - iowrite32(0, io_base + MAC_REG_MISCFFDATA); - iowrite16(MISCFFCTL_WRITE, io_base + MAC_REG_MISCFFCTL); -} diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h deleted file mode 100644 index a33af285222763..00000000000000 --- a/drivers/staging/vt6655/mac.h +++ /dev/null @@ -1,580 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: MAC routines - * - * Author: Tevin Chen - * - * Date: May 21, 1996 - * - * Revision History: - * 07-01-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. - * 08-25-2003 Kyle Hsu: Porting MAC functions from sim53. - * 09-03-2003 Bryan YC Fan: Add vt6655_mac_dis_protect_md & vt6655_mac_en_protect_md - */ - -#ifndef __MAC_H__ -#define __MAC_H__ - -#include "device.h" - -/*--------------------- Export Definitions -------------------------*/ -/* Registers in the MAC */ -#define MAC_MAX_CONTEXT_SIZE_PAGE0 256 -#define MAC_MAX_CONTEXT_SIZE_PAGE1 128 - -/* Registers not related to 802.11b */ -#define MAC_REG_BCFG0 0x00 -#define MAC_REG_BCFG1 0x01 -#define MAC_REG_FCR0 0x02 -#define MAC_REG_FCR1 0x03 -#define MAC_REG_BISTCMD 0x04 -#define MAC_REG_BISTSR0 0x05 -#define MAC_REG_BISTSR1 0x06 -#define MAC_REG_BISTSR2 0x07 -#define MAC_REG_I2MCSR 0x08 -#define MAC_REG_I2MTGID 0x09 -#define MAC_REG_I2MTGAD 0x0A -#define MAC_REG_I2MCFG 0x0B -#define MAC_REG_I2MDIPT 0x0C -#define MAC_REG_I2MDOPT 0x0E -#define MAC_REG_PMC0 0x10 -#define MAC_REG_PMC1 0x11 -#define MAC_REG_STICKHW 0x12 -#define MAC_REG_LOCALID 0x14 -#define MAC_REG_TESTCFG 0x15 -#define MAC_REG_JUMPER0 0x16 -#define MAC_REG_JUMPER1 0x17 -#define MAC_REG_TMCTL0 0x18 -#define MAC_REG_TMCTL1 0x19 -#define MAC_REG_TMDATA0 0x1C - -/* MAC Parameter related */ -#define MAC_REG_LRT 0x20 -#define MAC_REG_SRT 0x21 -#define MAC_REG_SIFS 0x22 -#define MAC_REG_DIFS 0x23 -#define MAC_REG_EIFS 0x24 -#define MAC_REG_SLOT 0x25 -#define MAC_REG_BI 0x26 -#define MAC_REG_CWMAXMIN0 0x28 -#define MAC_REG_LINKOFFTOTM 0x2A -#define MAC_REG_SWTMOT 0x2B -#define MAC_REG_MIBCNTR 0x2C -#define MAC_REG_RTSOKCNT 0x2C -#define MAC_REG_RTSFAILCNT 0x2D -#define MAC_REG_ACKFAILCNT 0x2E -#define MAC_REG_FCSERRCNT 0x2F - -/* TSF Related */ -#define MAC_REG_TSFCNTR 0x30 -#define MAC_REG_NEXTTBTT 0x38 -#define MAC_REG_TSFOFST 0x40 -#define MAC_REG_TFTCTL 0x48 - -/* WMAC Control/Status Related */ -#define MAC_REG_ENCFG 0x4C -#define MAC_REG_PAGE1SEL 0x4F -#define MAC_REG_CFG 0x50 -#define MAC_REG_TEST 0x52 -#define MAC_REG_HOSTCR 0x54 -#define MAC_REG_MACCR 0x55 -#define MAC_REG_RCR 0x56 -#define MAC_REG_TCR 0x57 -#define MAC_REG_IMR 0x58 -#define MAC_REG_ISR 0x5C - -/* Power Saving Related */ -#define MAC_REG_PSCFG 0x60 -#define MAC_REG_PSCTL 0x61 -#define MAC_REG_PSPWRSIG 0x62 -#define MAC_REG_BBCR13 0x63 -#define MAC_REG_AIDATIM 0x64 -#define MAC_REG_PWBT 0x66 -#define MAC_REG_WAKEOKTMR 0x68 -#define MAC_REG_CALTMR 0x69 -#define MAC_REG_SYNSPACCNT 0x6A -#define MAC_REG_WAKSYNOPT 0x6B - -/* Baseband/IF Control Group */ -#define MAC_REG_BBREGCTL 0x6C -#define MAC_REG_CHANNEL 0x6D -#define MAC_REG_BBREGADR 0x6E -#define MAC_REG_BBREGDATA 0x6F -#define MAC_REG_IFREGCTL 0x70 -#define MAC_REG_IFDATA 0x71 -#define MAC_REG_ITRTMSET 0x74 -#define MAC_REG_PAPEDELAY 0x77 -#define MAC_REG_SOFTPWRCTL 0x78 -#define MAC_REG_GPIOCTL0 0x7A -#define MAC_REG_GPIOCTL1 0x7B - -/* MAC DMA Related Group */ -#define MAC_REG_TXDMACTL0 0x7C -#define MAC_REG_TXDMAPTR0 0x80 -#define MAC_REG_AC0DMACTL 0x84 -#define MAC_REG_AC0DMAPTR 0x88 -#define MAC_REG_BCNDMACTL 0x8C -#define MAC_REG_BCNDMAPTR 0x90 -#define MAC_REG_RXDMACTL0 0x94 -#define MAC_REG_RXDMAPTR0 0x98 -#define MAC_REG_RXDMACTL1 0x9C -#define MAC_REG_RXDMAPTR1 0xA0 -#define MAC_REG_SYNCDMACTL 0xA4 -#define MAC_REG_SYNCDMAPTR 0xA8 -#define MAC_REG_ATIMDMACTL 0xAC -#define MAC_REG_ATIMDMAPTR 0xB0 - -/* MiscFF PIO related */ -#define MAC_REG_MISCFFNDEX 0xB4 -#define MAC_REG_MISCFFCTL 0xB6 -#define MAC_REG_MISCFFDATA 0xB8 - -/* Extend SW Timer */ -#define MAC_REG_TMDATA1 0xBC - -/* WOW Related Group */ -#define MAC_REG_WAKEUPEN0 0xC0 -#define MAC_REG_WAKEUPEN1 0xC1 -#define MAC_REG_WAKEUPSR0 0xC2 -#define MAC_REG_WAKEUPSR1 0xC3 -#define MAC_REG_WAKE128_0 0xC4 -#define MAC_REG_WAKE128_1 0xD4 -#define MAC_REG_WAKE128_2 0xE4 -#define MAC_REG_WAKE128_3 0xF4 - -/************** Page 1 ******************/ -#define MAC_REG_CRC_128_0 0x04 -#define MAC_REG_CRC_128_1 0x06 -#define MAC_REG_CRC_128_2 0x08 -#define MAC_REG_CRC_128_3 0x0A - -/* MAC Configuration Group */ -#define MAC_REG_PAR0 0x0C -#define MAC_REG_PAR4 0x10 -#define MAC_REG_BSSID0 0x14 -#define MAC_REG_BSSID4 0x18 -#define MAC_REG_MAR0 0x1C -#define MAC_REG_MAR4 0x20 - -/* MAC RSPPKT INFO Group */ -#define MAC_REG_RSPINF_B_1 0x24 -#define MAC_REG_RSPINF_B_2 0x28 -#define MAC_REG_RSPINF_B_5 0x2C -#define MAC_REG_RSPINF_B_11 0x30 -#define MAC_REG_RSPINF_A_6 0x34 -#define MAC_REG_RSPINF_A_9 0x36 -#define MAC_REG_RSPINF_A_12 0x38 -#define MAC_REG_RSPINF_A_18 0x3A -#define MAC_REG_RSPINF_A_24 0x3C -#define MAC_REG_RSPINF_A_36 0x3E -#define MAC_REG_RSPINF_A_48 0x40 -#define MAC_REG_RSPINF_A_54 0x42 -#define MAC_REG_RSPINF_A_72 0x44 - -/* 802.11h relative */ -#define MAC_REG_QUIETINIT 0x60 -#define MAC_REG_QUIETGAP 0x62 -#define MAC_REG_QUIETDUR 0x64 -#define MAC_REG_MSRCTL 0x66 -#define MAC_REG_MSRBBSTS 0x67 -#define MAC_REG_MSRSTART 0x68 -#define MAC_REG_MSRDURATION 0x70 -#define MAC_REG_CCAFRACTION 0x72 -#define MAC_REG_PWRCCK 0x73 -#define MAC_REG_PWROFDM 0x7C - -/* Bits in the BCFG0 register */ -#define BCFG0_PERROFF 0x40 -#define BCFG0_MRDMDIS 0x20 -#define BCFG0_MRDLDIS 0x10 -#define BCFG0_MWMEN 0x08 -#define BCFG0_VSERREN 0x02 -#define BCFG0_LATMEN 0x01 - -/* Bits in the BCFG1 register */ -#define BCFG1_CFUNOPT 0x80 -#define BCFG1_CREQOPT 0x40 -#define BCFG1_DMA8 0x10 -#define BCFG1_ARBITOPT 0x08 -#define BCFG1_PCIMEN 0x04 -#define BCFG1_MIOEN 0x02 -#define BCFG1_CISDLYEN 0x01 - -/* Bits in RAMBIST registers */ -#define BISTCMD_TSTPAT5 0x00 -#define BISTCMD_TSTPATA 0x80 -#define BISTCMD_TSTERR 0x20 -#define BISTCMD_TSTPATF 0x18 -#define BISTCMD_TSTPAT0 0x10 -#define BISTCMD_TSTMODE 0x04 -#define BISTCMD_TSTITTX 0x03 -#define BISTCMD_TSTATRX 0x02 -#define BISTCMD_TSTATTX 0x01 -#define BISTCMD_TSTRX 0x00 -#define BISTSR0_BISTGO 0x01 -#define BISTSR1_TSTSR 0x01 -#define BISTSR2_CMDPRTEN 0x02 -#define BISTSR2_RAMTSTEN 0x01 - -/* Bits in the I2MCFG EEPROM register */ -#define I2MCFG_BOUNDCTL 0x80 -#define I2MCFG_WAITCTL 0x20 -#define I2MCFG_SCLOECTL 0x10 -#define I2MCFG_WBUSYCTL 0x08 -#define I2MCFG_NORETRY 0x04 -#define I2MCFG_I2MLDSEQ 0x02 -#define I2MCFG_I2CMFAST 0x01 - -/* Bits in the I2MCSR EEPROM register */ -#define I2MCSR_EEMW 0x80 -#define I2MCSR_EEMR 0x40 -#define I2MCSR_AUTOLD 0x08 -#define I2MCSR_NACK 0x02 -#define I2MCSR_DONE 0x01 - -/* Bits in the PMC1 register */ -#define SPS_RST 0x80 -#define PCISTIKY 0x40 -#define PME_OVR 0x02 - -/* Bits in the STICKYHW register */ -#define STICKHW_DS1_SHADOW 0x02 -#define STICKHW_DS0_SHADOW 0x01 - -/* Bits in the TMCTL register */ -#define TMCTL_TSUSP 0x04 -#define TMCTL_TMD 0x02 -#define TMCTL_TE 0x01 - -/* Bits in the TFTCTL register */ -#define TFTCTL_HWUTSF 0x80 -#define TFTCTL_TBTTSYNC 0x40 -#define TFTCTL_HWUTSFEN 0x20 -#define TFTCTL_TSFCNTRRD 0x10 -#define TFTCTL_TBTTSYNCEN 0x08 -#define TFTCTL_TSFSYNCEN 0x04 -#define TFTCTL_TSFCNTRST 0x02 -#define TFTCTL_TSFCNTREN 0x01 - -/* Bits in the EnhanceCFG register */ -#define ENCFG_BARKERPREAM 0x00020000 -#define ENCFG_NXTBTTCFPSTR 0x00010000 -#define ENCFG_BCNSUSCLR 0x00000200 -#define ENCFG_BCNSUSIND 0x00000100 -#define ENCFG_CFP_PROTECTEN 0x00000040 -#define ENCFG_PROTECTMD 0x00000020 -#define ENCFG_HWPARCFP 0x00000010 -#define ENCFG_CFNULRSP 0x00000004 -#define ENCFG_BBTYPE_MASK 0x00000003 -#define ENCFG_BBTYPE_G 0x00000002 -#define ENCFG_BBTYPE_B 0x00000001 -#define ENCFG_BBTYPE_A 0x00000000 - -/* Bits in the Page1Sel register */ -#define PAGE1_SEL 0x01 - -/* Bits in the CFG register */ -#define CFG_TKIPOPT 0x80 -#define CFG_RXDMAOPT 0x40 -#define CFG_TMOT_SW 0x20 -#define CFG_TMOT_HWLONG 0x10 -#define CFG_TMOT_HW 0x00 -#define CFG_CFPENDOPT 0x08 -#define CFG_BCNSUSEN 0x04 -#define CFG_NOTXTIMEOUT 0x02 -#define CFG_NOBUFOPT 0x01 - -/* Bits in the TEST register */ -#define TEST_LBEXT 0x80 -#define TEST_LBINT 0x40 -#define TEST_LBNONE 0x00 -#define TEST_SOFTINT 0x20 -#define TEST_CONTTX 0x10 -#define TEST_TXPE 0x08 -#define TEST_NAVDIS 0x04 -#define TEST_NOCTS 0x02 -#define TEST_NOACK 0x01 - -/* Bits in the HOSTCR register */ -#define HOSTCR_TXONST 0x80 -#define HOSTCR_RXONST 0x40 -#define HOSTCR_ADHOC 0x20 /* Network Type 1 = Ad-hoc */ -#define HOSTCR_AP 0x10 /* Port Type 1 = AP */ -#define HOSTCR_TXON 0x08 /* 0000 1000 */ -#define HOSTCR_RXON 0x04 /* 0000 0100 */ -#define HOSTCR_MACEN 0x02 /* 0000 0010 */ -#define HOSTCR_SOFTRST 0x01 /* 0000 0001 */ - -/* Bits in the MACCR register */ -#define MACCR_SYNCFLUSHOK 0x04 -#define MACCR_SYNCFLUSH 0x02 -#define MACCR_CLRNAV 0x01 - -/* Bits in the MAC_REG_GPIOCTL0 register */ -#define LED_ACTSET 0x01 -#define LED_RFOFF 0x02 -#define LED_NOCONNECT 0x04 - -/* Bits in the RCR register */ -#define RCR_SSID 0x80 -#define RCR_RXALLTYPE 0x40 -#define RCR_UNICAST 0x20 -#define RCR_BROADCAST 0x10 -#define RCR_MULTICAST 0x08 -#define RCR_WPAERR 0x04 -#define RCR_ERRCRC 0x02 -#define RCR_BSSID 0x01 - -/* Bits in the TCR register */ -#define TCR_SYNCDCFOPT 0x02 -#define TCR_AUTOBCNTX 0x01 /* Beacon automatically transmit enable */ - -/* Bits in the IMR register */ -#define IMR_MEASURESTART 0x80000000 -#define IMR_QUIETSTART 0x20000000 -#define IMR_RADARDETECT 0x10000000 -#define IMR_MEASUREEND 0x08000000 -#define IMR_SOFTTIMER1 0x00200000 -#define IMR_RXDMA1 0x00001000 /* 0000 0000 0001 0000 0000 0000 */ -#define IMR_RXNOBUF 0x00000800 -#define IMR_MIBNEARFULL 0x00000400 -#define IMR_SOFTINT 0x00000200 -#define IMR_FETALERR 0x00000100 -#define IMR_WATCHDOG 0x00000080 -#define IMR_SOFTTIMER 0x00000040 -#define IMR_GPIO 0x00000020 -#define IMR_TBTT 0x00000010 -#define IMR_RXDMA0 0x00000008 -#define IMR_BNTX 0x00000004 -#define IMR_AC0DMA 0x00000002 -#define IMR_TXDMA0 0x00000001 - -/* Bits in the ISR register */ -#define ISR_MEASURESTART 0x80000000 -#define ISR_QUIETSTART 0x20000000 -#define ISR_RADARDETECT 0x10000000 -#define ISR_MEASUREEND 0x08000000 -#define ISR_SOFTTIMER1 0x00200000 -#define ISR_RXDMA1 0x00001000 /* 0000 0000 0001 0000 0000 0000 */ -#define ISR_RXNOBUF 0x00000800 /* 0000 0000 0000 1000 0000 0000 */ -#define ISR_MIBNEARFULL 0x00000400 /* 0000 0000 0000 0100 0000 0000 */ -#define ISR_SOFTINT 0x00000200 -#define ISR_FETALERR 0x00000100 -#define ISR_WATCHDOG 0x00000080 -#define ISR_SOFTTIMER 0x00000040 -#define ISR_GPIO 0x00000020 -#define ISR_TBTT 0x00000010 -#define ISR_RXDMA0 0x00000008 -#define ISR_BNTX 0x00000004 -#define ISR_AC0DMA 0x00000002 -#define ISR_TXDMA0 0x00000001 - -/* Bits in the PSCFG register */ -#define PSCFG_PHILIPMD 0x40 -#define PSCFG_WAKECALEN 0x20 -#define PSCFG_WAKETMREN 0x10 -#define PSCFG_BBPSPROG 0x08 -#define PSCFG_WAKESYN 0x04 -#define PSCFG_SLEEPSYN 0x02 -#define PSCFG_AUTOSLEEP 0x01 - -/* Bits in the PSCTL register */ -#define PSCTL_WAKEDONE 0x20 -#define PSCTL_PS 0x10 -#define PSCTL_GO2DOZE 0x08 -#define PSCTL_LNBCN 0x04 -#define PSCTL_ALBCN 0x02 -#define PSCTL_PSEN 0x01 - -/* Bits in the PSPWSIG register */ -#define PSSIG_WPE3 0x80 -#define PSSIG_WPE2 0x40 -#define PSSIG_WPE1 0x20 -#define PSSIG_WRADIOPE 0x10 -#define PSSIG_SPE3 0x08 -#define PSSIG_SPE2 0x04 -#define PSSIG_SPE1 0x02 -#define PSSIG_SRADIOPE 0x01 - -/* Bits in the BBREGCTL register */ -#define BBREGCTL_DONE 0x04 -#define BBREGCTL_REGR 0x02 -#define BBREGCTL_REGW 0x01 - -/* Bits in the IFREGCTL register */ -#define IFREGCTL_DONE 0x04 -#define IFREGCTL_IFRF 0x02 -#define IFREGCTL_REGW 0x01 - -/* Bits in the SOFTPWRCTL register */ -#define SOFTPWRCTL_RFLEOPT 0x0800 -#define SOFTPWRCTL_TXPEINV 0x0200 -#define SOFTPWRCTL_SWPECTI 0x0100 -#define SOFTPWRCTL_SWPAPE 0x0020 -#define SOFTPWRCTL_SWCALEN 0x0010 -#define SOFTPWRCTL_SWRADIO_PE 0x0008 -#define SOFTPWRCTL_SWPE2 0x0004 -#define SOFTPWRCTL_SWPE1 0x0002 -#define SOFTPWRCTL_SWPE3 0x0001 - -/* Bits in the GPIOCTL1 register */ -#define GPIO1_DATA1 0x20 -#define GPIO1_MD1 0x10 -#define GPIO1_DATA0 0x02 -#define GPIO1_MD0 0x01 - -/* Bits in the DMACTL register */ -#define DMACTL_CLRRUN 0x00080000 -#define DMACTL_RUN 0x00000008 -#define DMACTL_WAKE 0x00000004 -#define DMACTL_DEAD 0x00000002 -#define DMACTL_ACTIVE 0x00000001 - -/* Bits in the RXDMACTL0 register */ -#define RX_PERPKT 0x00000100 -#define RX_PERPKTCLR 0x01000000 - -/* Bits in the BCNDMACTL register */ -#define BEACON_READY 0x01 - -/* Bits in the MISCFFCTL register */ -#define MISCFFCTL_WRITE 0x0001 - -/* Bits in WAKEUPEN0 */ -#define WAKEUPEN0_DIRPKT 0x10 -#define WAKEUPEN0_LINKOFF 0x08 -#define WAKEUPEN0_ATIMEN 0x04 -#define WAKEUPEN0_TIMEN 0x02 -#define WAKEUPEN0_MAGICEN 0x01 - -/* Bits in WAKEUPEN1 */ -#define WAKEUPEN1_128_3 0x08 -#define WAKEUPEN1_128_2 0x04 -#define WAKEUPEN1_128_1 0x02 -#define WAKEUPEN1_128_0 0x01 - -/* Bits in WAKEUPSR0 */ -#define WAKEUPSR0_DIRPKT 0x10 -#define WAKEUPSR0_LINKOFF 0x08 -#define WAKEUPSR0_ATIMEN 0x04 -#define WAKEUPSR0_TIMEN 0x02 -#define WAKEUPSR0_MAGICEN 0x01 - -/* Bits in WAKEUPSR1 */ -#define WAKEUPSR1_128_3 0x08 -#define WAKEUPSR1_128_2 0x04 -#define WAKEUPSR1_128_1 0x02 -#define WAKEUPSR1_128_0 0x01 - -/* Bits in the MAC_REG_GPIOCTL register */ -#define GPIO0_MD 0x01 -#define GPIO0_DATA 0x02 -#define GPIO0_INTMD 0x04 -#define GPIO1_MD 0x10 -#define GPIO1_DATA 0x20 - -/* Bits in the MSRCTL register */ -#define MSRCTL_FINISH 0x80 -#define MSRCTL_READY 0x40 -#define MSRCTL_RADARDETECT 0x20 -#define MSRCTL_EN 0x10 -#define MSRCTL_QUIETTXCHK 0x08 -#define MSRCTL_QUIETRPT 0x04 -#define MSRCTL_QUIETINT 0x02 -#define MSRCTL_QUIETEN 0x01 - -/* Bits in the MSRCTL1 register */ -#define MSRCTL1_TXPWR 0x08 -#define MSRCTL1_CSAPAREN 0x04 -#define MSRCTL1_TXPAUSE 0x01 - -/* Loopback mode */ -#define MAC_LB_EXT 0x02 -#define MAC_LB_INTERNAL 0x01 -#define MAC_LB_NONE 0x00 - -#define DEFAULT_BI 0x200 - -/* MiscFIFO Offset */ -#define MISCFIFO_KEYETRY0 32 -#define MISCFIFO_KEYENTRYSIZE 22 -#define MISCFIFO_SYNINFO_IDX 10 -#define MISCFIFO_SYNDATA_IDX 11 -#define MISCFIFO_SYNDATASIZE 21 - -/* enabled mask value of irq */ -#define IMR_MASK_VALUE (IMR_SOFTTIMER1 | \ - IMR_RXDMA1 | \ - IMR_RXNOBUF | \ - IMR_MIBNEARFULL | \ - IMR_SOFTINT | \ - IMR_FETALERR | \ - IMR_WATCHDOG | \ - IMR_SOFTTIMER | \ - IMR_GPIO | \ - IMR_TBTT | \ - IMR_RXDMA0 | \ - IMR_BNTX | \ - IMR_AC0DMA | \ - IMR_TXDMA0) - -/* max time out delay time */ -#define W_MAX_TIMEOUT 0xFFF0U - -/* wait time within loop */ -#define CB_DELAY_LOOP_WAIT 10 /* 10ms */ - -/* revision id */ -#define REV_ID_VT3253_A0 0x00 -#define REV_ID_VT3253_A1 0x01 -#define REV_ID_VT3253_B0 0x08 -#define REV_ID_VT3253_B1 0x09 - -/*--------------------- Export Types ------------------------------*/ - -/*--------------------- Export Macros ------------------------------*/ - -#define VT6655_MAC_SELECT_PAGE0(iobase) iowrite8(0, (iobase) + MAC_REG_PAGE1SEL) - -#define VT6655_MAC_SELECT_PAGE1(iobase) iowrite8(1, (iobase) + MAC_REG_PAGE1SEL) - -#define MAKEWORD(lb, hb) \ - ((unsigned short)(((unsigned char)(lb)) | (((unsigned short)((unsigned char)(hb))) << 8))) - -void vt6655_mac_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask); -void vt6655_mac_word_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask); -void vt6655_mac_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask); -void vt6655_mac_word_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask); - -void vt6655_mac_set_short_retry_limit(struct vnt_private *priv, unsigned char retry_limit); - -void MACvSetLongRetryLimit(struct vnt_private *priv, unsigned char byRetryLimit); - -bool MACbSoftwareReset(struct vnt_private *priv); -bool MACbShutdown(struct vnt_private *priv); -void MACvInitialize(struct vnt_private *priv); -void vt6655_mac_set_curr_rx_0_desc_addr(struct vnt_private *priv, u32 curr_desc_addr); -void vt6655_mac_set_curr_rx_1_desc_addr(struct vnt_private *priv, u32 curr_desc_addr); -void vt6655_mac_set_curr_tx_desc_addr(int tx_type, struct vnt_private *priv, u32 curr_desc_addr); -void MACvSetCurrSyncDescAddrEx(struct vnt_private *priv, - u32 curr_desc_addr); -void MACvSetCurrATIMDescAddrEx(struct vnt_private *priv, - u32 curr_desc_addr); -void MACvTimer0MicroSDelay(struct vnt_private *priv, unsigned int uDelay); -void MACvOneShotTimer1MicroSec(struct vnt_private *priv, unsigned int uDelayTime); - -void MACvSetMISCFifo(struct vnt_private *priv, unsigned short wOffset, - u32 dwData); - -bool MACbPSWakeup(struct vnt_private *priv); - -void MACvSetKeyEntry(struct vnt_private *priv, unsigned short wKeyCtl, - unsigned int uEntryIdx, unsigned int uKeyIdx, - unsigned char *pbyAddr, u32 *pdwKey, - unsigned char local_id); -void MACvDisableKeyEntry(struct vnt_private *priv, unsigned int uEntryIdx); - -#endif /* __MAC_H__ */ diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c deleted file mode 100644 index 8527ad3eff4862..00000000000000 --- a/drivers/staging/vt6655/power.c +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Handles 802.11 power management functions - * - * Author: Lyndon Chen - * - * Date: July 17, 2002 - * - * Functions: - * PSvEnablePowerSaving - Enable Power Saving Mode - * PSvDiasblePowerSaving - Disable Power Saving Mode - * PSbConsiderPowerDown - Decide if we can Power Down - * PSvSendPSPOLL - Send PS-POLL packet - * PSbSendNullPacket - Send Null packet - * PSbIsNextTBTTWakeUp - Decide if we need to wake up at next Beacon - * - * Revision History: - * - */ - -#include "mac.h" -#include "device.h" -#include "power.h" -#include "card.h" - -/*--------------------- Static Definitions -------------------------*/ - -/*--------------------- Static Classes ----------------------------*/ - -/*--------------------- Static Functions --------------------------*/ - -/*--------------------- Export Variables --------------------------*/ - -/*--------------------- Export Functions --------------------------*/ - -/* - * - * Routine Description: - * Enable hw power saving functions - * - * Return Value: - * None. - * - */ - -void PSvEnablePowerSaving(struct vnt_private *priv, - unsigned short wListenInterval) -{ - u16 wAID = priv->current_aid | BIT(14) | BIT(15); - - /* set period of power up before TBTT */ - iowrite16(C_PWBT, priv->port_offset + MAC_REG_PWBT); - if (priv->op_mode != NL80211_IFTYPE_ADHOC) { - /* set AID */ - iowrite16(wAID, priv->port_offset + MAC_REG_AIDATIM); - } - - /* Set AutoSleep */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); - - /* Set HWUTSF */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); - - if (wListenInterval >= 2) { - /* clear always listen beacon */ - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); - /* first time set listen next beacon */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_LNBCN); - } else { - /* always listen beacon */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); - } - - /* enable power saving hw function */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_PSEN); - priv->bEnablePSMode = true; - - priv->bPWBitOn = true; - pr_debug("PS:Power Saving Mode Enable...\n"); -} - -/* - * - * Routine Description: - * Disable hw power saving functions - * - * Return Value: - * None. - * - */ - -void PSvDisablePowerSaving(struct vnt_private *priv) -{ - /* disable power saving hw function */ - MACbPSWakeup(priv); - - /* clear AutoSleep */ - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); - - /* clear HWUTSF */ - vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); - - /* set always listen beacon */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); - - priv->bEnablePSMode = false; - - priv->bPWBitOn = false; -} - -/* - * - * Routine Description: - * Check if Next TBTT must wake up - * - * Return Value: - * None. - * - */ - -bool PSbIsNextTBTTWakeUp(struct vnt_private *priv) -{ - struct ieee80211_hw *hw = priv->hw; - struct ieee80211_conf *conf = &hw->conf; - bool wake_up = false; - - if (conf->listen_interval > 1) { - if (!priv->wake_up_count) - priv->wake_up_count = conf->listen_interval; - - --priv->wake_up_count; - - if (priv->wake_up_count == 1) { - /* Turn on wake up to listen next beacon */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_LNBCN); - wake_up = true; - } - } - - return wake_up; -} diff --git a/drivers/staging/vt6655/power.h b/drivers/staging/vt6655/power.h deleted file mode 100644 index 060516f81f5bbd..00000000000000 --- a/drivers/staging/vt6655/power.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Handles 802.11 power management functions - * - * Author: Lyndon Chen - * - * Date: July 17, 2002 - * - */ - -#ifndef __POWER_H__ -#define __POWER_H__ - -#include "device.h" - -#define C_PWBT 1000 /* micro sec. power up before TBTT */ -#define PS_FAST_INTERVAL 1 /* Fast power saving listen interval */ -#define PS_MAX_INTERVAL 4 /* MAX power saving listen interval */ - -void PSvDisablePowerSaving(struct vnt_private *priv); - -void PSvEnablePowerSaving(struct vnt_private *priv, unsigned short wListenInterval); - -bool PSbIsNextTBTTWakeUp(struct vnt_private *priv); - -#endif /* __POWER_H__ */ diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c deleted file mode 100644 index d319ec21c97b89..00000000000000 --- a/drivers/staging/vt6655/rf.c +++ /dev/null @@ -1,535 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: rf function code - * - * Author: Jerry Chen - * - * Date: Feb. 19, 2004 - * - * Functions: - * IFRFbWriteEmbedded - Embedded write RF register via MAC - * - * Revision History: - * RobertYu 2005 - * chester 2008 - * - */ - -#include "mac.h" -#include "srom.h" -#include "rf.h" -#include "baseband.h" - -#define BY_AL2230_REG_LEN 23 /* 24bit */ -#define CB_AL2230_INIT_SEQ 15 -#define SWITCH_CHANNEL_DELAY_AL2230 200 /* us */ -#define AL2230_PWR_IDX_LEN 64 - -#define BY_AL7230_REG_LEN 23 /* 24bit */ -#define CB_AL7230_INIT_SEQ 16 -#define SWITCH_CHANNEL_DELAY_AL7230 200 /* us */ -#define AL7230_PWR_IDX_LEN 64 - -static const unsigned long al2230_init_table[CB_AL2230_INIT_SEQ] = { - 0x03F79000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x03333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x01A00200 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x00FFF300 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0005A400 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0F4DC500 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0805B600 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0146C700 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x00068800 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0403B900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x00DBBA00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x00099B00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0BDFFC00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x00000D00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x00580F00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW -}; - -static const unsigned long al2230_channel_table0[CB_MAX_CHANNEL] = { - 0x03F79000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 1, Tf = 2412MHz */ - 0x03F79000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 2, Tf = 2417MHz */ - 0x03E79000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 3, Tf = 2422MHz */ - 0x03E79000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 4, Tf = 2427MHz */ - 0x03F7A000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 5, Tf = 2432MHz */ - 0x03F7A000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 6, Tf = 2437MHz */ - 0x03E7A000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 7, Tf = 2442MHz */ - 0x03E7A000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 8, Tf = 2447MHz */ - 0x03F7B000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 9, Tf = 2452MHz */ - 0x03F7B000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 10, Tf = 2457MHz */ - 0x03E7B000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 11, Tf = 2462MHz */ - 0x03E7B000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 12, Tf = 2467MHz */ - 0x03F7C000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 13, Tf = 2472MHz */ - 0x03E7C000 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW /* channel = 14, Tf = 2412M */ -}; - -static const unsigned long al2230_channel_table1[CB_MAX_CHANNEL] = { - 0x03333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 1, Tf = 2412MHz */ - 0x0B333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 2, Tf = 2417MHz */ - 0x03333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 3, Tf = 2422MHz */ - 0x0B333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 4, Tf = 2427MHz */ - 0x03333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 5, Tf = 2432MHz */ - 0x0B333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 6, Tf = 2437MHz */ - 0x03333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 7, Tf = 2442MHz */ - 0x0B333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 8, Tf = 2447MHz */ - 0x03333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 9, Tf = 2452MHz */ - 0x0B333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 10, Tf = 2457MHz */ - 0x03333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 11, Tf = 2462MHz */ - 0x0B333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 12, Tf = 2467MHz */ - 0x03333100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, /* channel = 13, Tf = 2472MHz */ - 0x06666100 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW /* channel = 14, Tf = 2412M */ -}; - -static unsigned long al2230_power_table[AL2230_PWR_IDX_LEN] = { - 0x04040900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04041900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04042900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04043900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04044900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04045900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04046900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04047900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04048900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04049900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0404A900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0404B900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0404C900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0404D900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0404E900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0404F900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04050900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04051900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04052900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04053900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04054900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04055900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04056900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04057900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04058900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04059900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0405A900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0405B900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0405C900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0405D900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0405E900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0405F900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04060900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04061900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04062900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04063900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04064900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04065900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04066900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04067900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04068900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04069900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0406A900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0406B900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0406C900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0406D900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0406E900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0406F900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04070900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04071900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04072900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04073900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04074900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04075900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04076900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04077900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04078900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x04079900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0407A900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0407B900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0407C900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0407D900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0407E900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW, - 0x0407F900 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW -}; - -/* - * Description: Write to IF/RF, by embedded programming - * - * Parameters: - * In: - * iobase - I/O base address - * dwData - data to write - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ -bool IFRFbWriteEmbedded(struct vnt_private *priv, unsigned long dwData) -{ - void __iomem *iobase = priv->port_offset; - unsigned short ww; - unsigned long dwValue; - - iowrite32((u32)dwData, iobase + MAC_REG_IFREGCTL); - - /* W_MAX_TIMEOUT is the timeout period */ - for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { - dwValue = ioread32(iobase + MAC_REG_IFREGCTL); - if (dwValue & IFREGCTL_DONE) - break; - } - - if (ww == W_MAX_TIMEOUT) - return false; - - return true; -} - -/* - * Description: AIROHA IFRF chip init function - * - * Parameters: - * In: - * iobase - I/O base address - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ -static bool RFbAL2230Init(struct vnt_private *priv) -{ - void __iomem *iobase = priv->port_offset; - int ii; - bool ret; - - ret = true; - - /* 3-wire control for normal mode */ - iowrite8(0, iobase + MAC_REG_SOFTPWRCTL); - - vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, - (SOFTPWRCTL_SWPECTI | SOFTPWRCTL_TXPEINV)); - /* PLL Off */ - vt6655_mac_word_reg_bits_off(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); - - /* patch abnormal AL2230 frequency output */ - IFRFbWriteEmbedded(priv, (0x07168700 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW)); - - for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++) - ret &= IFRFbWriteEmbedded(priv, al2230_init_table[ii]); - MACvTimer0MicroSDelay(priv, 30); /* delay 30 us */ - - /* PLL On */ - vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); - - MACvTimer0MicroSDelay(priv, 150);/* 150us */ - ret &= IFRFbWriteEmbedded(priv, (0x00d80f00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW)); - MACvTimer0MicroSDelay(priv, 30);/* 30us */ - ret &= IFRFbWriteEmbedded(priv, (0x00780f00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW)); - MACvTimer0MicroSDelay(priv, 30);/* 30us */ - ret &= IFRFbWriteEmbedded(priv, - al2230_init_table[CB_AL2230_INIT_SEQ - 1]); - - vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | - SOFTPWRCTL_SWPE2 | - SOFTPWRCTL_SWPECTI | - SOFTPWRCTL_TXPEINV)); - - /* 3-wire control for power saving mode */ - iowrite8(PSSIG_WPE3 | PSSIG_WPE2, iobase + MAC_REG_PSPWRSIG); - - return ret; -} - -static bool RFbAL2230SelectChannel(struct vnt_private *priv, unsigned char byChannel) -{ - void __iomem *iobase = priv->port_offset; - bool ret; - - ret = true; - - ret &= IFRFbWriteEmbedded(priv, al2230_channel_table0[byChannel - 1]); - ret &= IFRFbWriteEmbedded(priv, al2230_channel_table1[byChannel - 1]); - - /* Set Channel[7] = 0 to tell H/W channel is changing now. */ - iowrite8(byChannel & 0x7F, iobase + MAC_REG_CHANNEL); - MACvTimer0MicroSDelay(priv, SWITCH_CHANNEL_DELAY_AL2230); - /* Set Channel[7] = 1 to tell H/W channel change is done. */ - iowrite8(byChannel | 0x80, iobase + MAC_REG_CHANNEL); - - return ret; -} - -/* - * Description: RF init function - * - * Parameters: - * In: - * byBBType - * rf_type - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ -bool RFbInit(struct vnt_private *priv) -{ - bool ret = true; - - switch (priv->rf_type) { - case RF_AIROHA: - case RF_AL2230S: - priv->max_pwr_level = AL2230_PWR_IDX_LEN; - ret = RFbAL2230Init(priv); - break; - case RF_NOTHING: - ret = true; - break; - default: - ret = false; - break; - } - return ret; -} - -/* - * Description: Select channel - * - * Parameters: - * In: - * rf_type - * byChannel - Channel number - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ -bool RFbSelectChannel(struct vnt_private *priv, unsigned char rf_type, - u16 byChannel) -{ - bool ret = true; - - switch (rf_type) { - case RF_AIROHA: - case RF_AL2230S: - ret = RFbAL2230SelectChannel(priv, byChannel); - break; - /*{{ RobertYu: 20050104 */ - case RF_NOTHING: - ret = true; - break; - default: - ret = false; - break; - } - return ret; -} - -/* - * Description: Write WakeProgSyn - * - * Parameters: - * In: - * priv - Device Structure - * rf_type - RF type - * channel - Channel number - * - * Return Value: true if succeeded; false if failed. - * - */ -bool rf_write_wake_prog_syn(struct vnt_private *priv, unsigned char rf_type, - u16 channel) -{ - void __iomem *iobase = priv->port_offset; - int i; - unsigned char init_count = 0; - unsigned char sleep_count = 0; - unsigned short idx = MISCFIFO_SYNDATA_IDX; - - iowrite16(0, iobase + MAC_REG_MISCFFNDEX); - switch (rf_type) { - case RF_AIROHA: - case RF_AL2230S: - - if (channel > CB_MAX_CHANNEL_24G) - return false; - - /* Init Reg + Channel Reg (2) */ - init_count = CB_AL2230_INIT_SEQ + 2; - sleep_count = 0; - - for (i = 0; i < CB_AL2230_INIT_SEQ; i++) - MACvSetMISCFifo(priv, idx++, al2230_init_table[i]); - - MACvSetMISCFifo(priv, idx++, al2230_channel_table0[channel - 1]); - MACvSetMISCFifo(priv, idx++, al2230_channel_table1[channel - 1]); - break; - - /* Need to check, PLLON need to be low for channel setting */ - - case RF_NOTHING: - return true; - - default: - return false; - } - - MACvSetMISCFifo(priv, MISCFIFO_SYNINFO_IDX, (unsigned long)MAKEWORD(sleep_count, init_count)); - - return true; -} - -/* - * Description: Set Tx power - * - * Parameters: - * In: - * iobase - I/O base address - * dwRFPowerTable - RF Tx Power Setting - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ -bool RFbSetPower(struct vnt_private *priv, unsigned int rate, u16 uCH) -{ - bool ret; - unsigned char byPwr = 0; - unsigned char byDec = 0; - - if (priv->dwDiagRefCount != 0) - return true; - - if ((uCH < 1) || (uCH > CB_MAX_CHANNEL)) - return false; - - switch (rate) { - case RATE_1M: - case RATE_2M: - case RATE_5M: - case RATE_11M: - if (uCH > CB_MAX_CHANNEL_24G) - return false; - - byPwr = priv->abyCCKPwrTbl[uCH]; - break; - case RATE_6M: - case RATE_9M: - case RATE_12M: - case RATE_18M: - byPwr = priv->abyOFDMPwrTbl[uCH]; - byDec = byPwr + 10; - - if (byDec >= priv->max_pwr_level) - byDec = priv->max_pwr_level - 1; - - byPwr = byDec; - break; - case RATE_24M: - case RATE_36M: - case RATE_48M: - case RATE_54M: - byPwr = priv->abyOFDMPwrTbl[uCH]; - break; - } - - if (priv->cur_pwr == byPwr) - return true; - - ret = RFbRawSetPower(priv, byPwr, rate); - if (ret) - priv->cur_pwr = byPwr; - - return ret; -} - -/* - * Description: Set Tx power - * - * Parameters: - * In: - * iobase - I/O base address - * dwRFPowerTable - RF Tx Power Setting - * Out: - * none - * - * Return Value: true if succeeded; false if failed. - * - */ - -bool RFbRawSetPower(struct vnt_private *priv, unsigned char byPwr, - unsigned int rate) -{ - bool ret = true; - - if (byPwr >= priv->max_pwr_level) - return false; - - switch (priv->rf_type) { - case RF_AIROHA: - ret &= IFRFbWriteEmbedded(priv, al2230_power_table[byPwr]); - if (rate <= RATE_11M) - ret &= IFRFbWriteEmbedded(priv, 0x0001B400 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW); - else - ret &= IFRFbWriteEmbedded(priv, 0x0005A400 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW); - - break; - - case RF_AL2230S: - ret &= IFRFbWriteEmbedded(priv, al2230_power_table[byPwr]); - if (rate <= RATE_11M) { - ret &= IFRFbWriteEmbedded(priv, 0x040C1400 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW); - ret &= IFRFbWriteEmbedded(priv, 0x00299B00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW); - } else { - ret &= IFRFbWriteEmbedded(priv, 0x0005A400 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW); - ret &= IFRFbWriteEmbedded(priv, 0x00099B00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW); - } - - break; - - default: - break; - } - return ret; -} - -/* - * - * Routine Description: - * Translate RSSI to dBm - * - * Parameters: - * In: - * priv - The adapter to be translated - * byCurrRSSI - RSSI to be translated - * Out: - * pdwdbm - Translated dbm number - * - * Return Value: none - * - */ -void -RFvRSSITodBm(struct vnt_private *priv, unsigned char byCurrRSSI, long *pldBm) -{ - unsigned char byIdx = (((byCurrRSSI & 0xC0) >> 6) & 0x03); - long b = (byCurrRSSI & 0x3F); - long a = 0; - unsigned char abyAIROHARF[4] = {0, 18, 0, 40}; - - switch (priv->rf_type) { - case RF_AIROHA: - case RF_AL2230S: - a = abyAIROHARF[byIdx]; - break; - default: - break; - } - - *pldBm = -1 * (a + b * 2); -} - diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h deleted file mode 100644 index 8eef100c7ef29e..00000000000000 --- a/drivers/staging/vt6655/rf.h +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: - * - * Author: Jerry Chen - * - * Date: Feb. 19, 2004 - * - */ - -#ifndef __RF_H__ -#define __RF_H__ - -#include "device.h" - -/*--------------------- Export Definitions -------------------------*/ -/* - * Baseband RF pair definition in eeprom (Bits 6..0) - */ -#define RF_RFMD2959 0x01 -#define RF_MAXIMAG 0x02 -#define RF_AIROHA 0x03 - -#define RF_UW2451 0x05 -#define RF_MAXIMG 0x06 -#define RF_MAXIM2829 0x07 /* RobertYu: 20041118 */ -#define RF_UW2452 0x08 /* RobertYu: 20041210 */ -#define RF_AIROHA7230 0x0a /* RobertYu: 20050104 */ -#define RF_UW2453 0x0b - -#define RF_VT3226 0x09 -#define RF_AL2230S 0x0e - -#define RF_NOTHING 0x7E -#define RF_EMU 0x80 -#define RF_MASK 0x7F - -#define ZONE_FCC 0 -#define ZONE_MKK1 1 -#define ZONE_ETSI 2 -#define ZONE_IC 3 -#define ZONE_SPAIN 4 -#define ZONE_FRANCE 5 -#define ZONE_MKK 6 -#define ZONE_ISRAEL 7 - -/* [20050104] CB_MAXIM2829_CHANNEL_5G_HIGH, CB_UW2452_CHANNEL_5G_HIGH: 40==>41 */ -#define CB_MAXIM2829_CHANNEL_5G_HIGH 41 /* Index41: channel = 100, Tf = 5500MHz, set the (A3:A0=0101) D6=1 */ -#define CB_UW2452_CHANNEL_5G_HIGH 41 /* [20041210] Index41: channel = 100, Tf = 5500MHz, change VCO2->VCO3 */ - -/*--------------------- Export Classes ----------------------------*/ - -/*--------------------- Export Variables --------------------------*/ - -/*--------------------- Export Functions --------------------------*/ - -bool IFRFbWriteEmbedded(struct vnt_private *priv, unsigned long dwData); -bool RFbSelectChannel(struct vnt_private *priv, unsigned char rf_type, u16 byChannel); -bool RFbInit(struct vnt_private *priv); -bool rf_write_wake_prog_syn(struct vnt_private *priv, unsigned char rf_type, u16 channel); -bool RFbSetPower(struct vnt_private *priv, unsigned int rate, u16 uCH); -bool RFbRawSetPower(struct vnt_private *priv, unsigned char byPwr, - unsigned int rate); - -void RFvRSSITodBm(struct vnt_private *priv, unsigned char byCurrRSSI, - long *pldBm); - -#endif /* __RF_H__ */ diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c deleted file mode 100644 index 3705cb1e87b635..00000000000000 --- a/drivers/staging/vt6655/rxtx.c +++ /dev/null @@ -1,1462 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: handle WMAC/802.3/802.11 rx & tx functions - * - * Author: Lyndon Chen - * - * Date: May 20, 2003 - * - * Functions: - * s_vGenerateTxParameter - Generate tx dma required parameter. - * vGenerateMACHeader - Translate 802.3 to 802.11 header - * cbGetFragCount - Calculate fragment number count - * csBeacon_xmit - beacon tx function - * csMgmt_xmit - management tx function - * s_cbFillTxBufHead - fulfill tx dma buffer header - * s_uGetDataDuration - get tx data required duration - * s_uFillDataHead- fulfill tx data duration header - * s_uGetRTSCTSDuration- get rtx/cts required duration - * get_rtscts_time- get rts/cts reserved time - * s_uGetTxRsvTime- get frame reserved time - * s_vFillCTSHead- fulfill CTS ctl header - * s_vFillFragParameter- Set fragment ctl parameter. - * s_vFillRTSHead- fulfill RTS ctl header - * s_vFillTxKey- fulfill tx encrypt key - * s_vSWencryption- Software encrypt header - * vDMA0_tx_80211- tx 802.11 frame via dma0 - * vGenerateFIFOHeader- Generate tx FIFO ctl header - * - * Revision History: - * - */ - -#include "device.h" -#include "rxtx.h" -#include "card.h" -#include "mac.h" -#include "baseband.h" -#include "rf.h" - -/*--------------------- Static Definitions -------------------------*/ - -/*--------------------- Static Classes ----------------------------*/ - -/*--------------------- Static Variables --------------------------*/ - -/*--------------------- Static Functions --------------------------*/ - -/*--------------------- Static Definitions -------------------------*/ -/* if packet size < 256 -> in-direct send - * vpacket size >= 256 -> direct send - */ -#define CRITICAL_PACKET_LEN 256 - -static const unsigned short time_stamp_off[2][MAX_RATE] = { - {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23}, /* Long Preamble */ - {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23}, /* Short Preamble */ -}; - -static const unsigned short fb_opt0[2][5] = { - {RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, /* fallback_rate0 */ - {RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, /* fallback_rate1 */ -}; - -static const unsigned short fb_opt1[2][5] = { - {RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, /* fallback_rate0 */ - {RATE_6M, RATE_6M, RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */ -}; - -#define RTSDUR_BB 0 -#define RTSDUR_BA 1 -#define RTSDUR_AA 2 -#define CTSDUR_BA 3 -#define RTSDUR_BA_F0 4 -#define RTSDUR_AA_F0 5 -#define RTSDUR_BA_F1 6 -#define RTSDUR_AA_F1 7 -#define CTSDUR_BA_F0 8 -#define CTSDUR_BA_F1 9 -#define DATADUR_B 10 -#define DATADUR_A 11 -#define DATADUR_A_F0 12 -#define DATADUR_A_F1 13 - -/*--------------------- Static Functions --------------------------*/ -static -void -s_vFillRTSHead( - struct vnt_private *pDevice, - unsigned char byPktType, - void *pvRTS, - unsigned int cbFrameLength, - bool bNeedAck, - bool bDisCRC, - struct ieee80211_hdr *hdr, - unsigned short wCurrentRate, - unsigned char byFBOption -); - -static -void -s_vGenerateTxParameter( - struct vnt_private *pDevice, - unsigned char byPktType, - struct vnt_tx_fifo_head *, - void *pvRrvTime, - void *pvRTS, - void *pvCTS, - unsigned int cbFrameSize, - bool bNeedACK, - unsigned int uDMAIdx, - void *psEthHeader, - unsigned short wCurrentRate -); - -static unsigned int -s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType, - unsigned char *pbyTxBufferAddr, - unsigned int uDMAIdx, struct vnt_tx_desc *pHeadTD, - unsigned int uNodeIndex); - -static -__le16 -s_uFillDataHead( - struct vnt_private *pDevice, - unsigned char byPktType, - void *pTxDataHead, - unsigned int cbFrameLength, - unsigned int uDMAIdx, - bool bNeedAck, - unsigned int uFragIdx, - unsigned int cbLastFragmentSize, - unsigned int uMACfragNum, - unsigned char byFBOption, - unsigned short wCurrentRate, - bool is_pspoll -); - -/*--------------------- Export Variables --------------------------*/ - -static __le16 vnt_time_stamp_off(struct vnt_private *priv, u16 rate) -{ - return cpu_to_le16(time_stamp_off[priv->preamble_type % 2] - [rate % MAX_RATE]); -} - -/* byPktType : PK_TYPE_11A 0 - * PK_TYPE_11B 1 - * PK_TYPE_11GB 2 - * PK_TYPE_11GA 3 - */ -static -unsigned int -s_uGetTxRsvTime( - struct vnt_private *pDevice, - unsigned char byPktType, - unsigned int cbFrameLength, - unsigned short wRate, - bool bNeedAck -) -{ - unsigned int uDataTime, uAckTime; - - uDataTime = bb_get_frame_time(pDevice->preamble_type, byPktType, cbFrameLength, wRate); - - if (!bNeedAck) - return uDataTime; - - /* - * CCK mode - 11b - * OFDM mode - 11g 2.4G & 11a 5G - */ - uAckTime = bb_get_frame_time(pDevice->preamble_type, byPktType, 14, - byPktType == PK_TYPE_11B ? - pDevice->byTopCCKBasicRate : - pDevice->byTopOFDMBasicRate); - - return uDataTime + pDevice->uSIFS + uAckTime; -} - -static __le16 vnt_rxtx_rsvtime_le16(struct vnt_private *priv, u8 pkt_type, - u32 frame_length, u16 rate, bool need_ack) -{ - return cpu_to_le16((u16)s_uGetTxRsvTime(priv, pkt_type, - frame_length, rate, need_ack)); -} - -/* byFreqType: 0=>5GHZ 1=>2.4GHZ */ -static __le16 get_rtscts_time(struct vnt_private *priv, - unsigned char rts_rsvtype, - unsigned char pkt_type, - unsigned int frame_length, - unsigned short current_rate) -{ - unsigned int rrv_time = 0; - unsigned int rts_time = 0; - unsigned int cts_time = 0; - unsigned int ack_time = 0; - unsigned int data_time = 0; - - data_time = bb_get_frame_time(priv->preamble_type, pkt_type, frame_length, current_rate); - if (rts_rsvtype == 0) { /* RTSTxRrvTime_bb */ - rts_time = bb_get_frame_time(priv->preamble_type, pkt_type, 20, priv->byTopCCKBasicRate); - ack_time = bb_get_frame_time(priv->preamble_type, pkt_type, 14, priv->byTopCCKBasicRate); - cts_time = ack_time; - } else if (rts_rsvtype == 1) { /* RTSTxRrvTime_ba, only in 2.4GHZ */ - rts_time = bb_get_frame_time(priv->preamble_type, pkt_type, 20, priv->byTopCCKBasicRate); - cts_time = bb_get_frame_time(priv->preamble_type, pkt_type, 14, priv->byTopCCKBasicRate); - ack_time = bb_get_frame_time(priv->preamble_type, pkt_type, 14, priv->byTopOFDMBasicRate); - } else if (rts_rsvtype == 2) { /* RTSTxRrvTime_aa */ - rts_time = bb_get_frame_time(priv->preamble_type, pkt_type, 20, priv->byTopOFDMBasicRate); - ack_time = bb_get_frame_time(priv->preamble_type, pkt_type, 14, priv->byTopOFDMBasicRate); - cts_time = ack_time; - } else if (rts_rsvtype == 3) { /* CTSTxRrvTime_ba, only in 2.4GHZ */ - cts_time = bb_get_frame_time(priv->preamble_type, pkt_type, 14, priv->byTopCCKBasicRate); - ack_time = bb_get_frame_time(priv->preamble_type, pkt_type, 14, priv->byTopOFDMBasicRate); - rrv_time = cts_time + ack_time + data_time + 2 * priv->uSIFS; - return cpu_to_le16((u16)rrv_time); - } - - /* RTSRrvTime */ - rrv_time = rts_time + cts_time + ack_time + data_time + 3 * priv->uSIFS; - return cpu_to_le16((u16)rrv_time); -} - -/* byFreqType 0: 5GHz, 1:2.4Ghz */ -static -unsigned int -s_uGetDataDuration( - struct vnt_private *pDevice, - unsigned char byDurType, - unsigned int cbFrameLength, - unsigned char byPktType, - unsigned short wRate, - bool bNeedAck, - unsigned int uFragIdx, - unsigned int cbLastFragmentSize, - unsigned int uMACfragNum, - unsigned char byFBOption -) -{ - bool bLastFrag = false; - unsigned int uAckTime = 0, uNextPktTime = 0, len; - - if (uFragIdx == (uMACfragNum - 1)) - bLastFrag = true; - - if (uFragIdx == (uMACfragNum - 2)) - len = cbLastFragmentSize; - else - len = cbFrameLength; - - switch (byDurType) { - case DATADUR_B: /* DATADUR_B */ - if (bNeedAck) { - uAckTime = bb_get_frame_time(pDevice->preamble_type, - byPktType, 14, - pDevice->byTopCCKBasicRate); - } - /* Non Frag or Last Frag */ - if ((uMACfragNum == 1) || bLastFrag) { - if (!bNeedAck) - return 0; - } else { - /* First Frag or Mid Frag */ - uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, - len, wRate, bNeedAck); - } - - return pDevice->uSIFS + uAckTime + uNextPktTime; - - case DATADUR_A: /* DATADUR_A */ - if (bNeedAck) { - uAckTime = bb_get_frame_time(pDevice->preamble_type, - byPktType, 14, - pDevice->byTopOFDMBasicRate); - } - /* Non Frag or Last Frag */ - if ((uMACfragNum == 1) || bLastFrag) { - if (!bNeedAck) - return 0; - } else { - /* First Frag or Mid Frag */ - uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, - len, wRate, bNeedAck); - } - - return pDevice->uSIFS + uAckTime + uNextPktTime; - - case DATADUR_A_F0: /* DATADUR_A_F0 */ - case DATADUR_A_F1: /* DATADUR_A_F1 */ - if (bNeedAck) { - uAckTime = bb_get_frame_time(pDevice->preamble_type, - byPktType, 14, - pDevice->byTopOFDMBasicRate); - } - /* Non Frag or Last Frag */ - if ((uMACfragNum == 1) || bLastFrag) { - if (!bNeedAck) - return 0; - } else { - /* First Frag or Mid Frag */ - if (wRate < RATE_18M) - wRate = RATE_18M; - else if (wRate > RATE_54M) - wRate = RATE_54M; - - wRate -= RATE_18M; - - if (byFBOption == AUTO_FB_0) - wRate = fb_opt0[FB_RATE0][wRate]; - else - wRate = fb_opt1[FB_RATE0][wRate]; - - uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, - len, wRate, bNeedAck); - } - - return pDevice->uSIFS + uAckTime + uNextPktTime; - - default: - break; - } - - return 0; -} - -/* byFreqType: 0=>5GHZ 1=>2.4GHZ */ -static -__le16 -s_uGetRTSCTSDuration( - struct vnt_private *pDevice, - unsigned char byDurType, - unsigned int cbFrameLength, - unsigned char byPktType, - unsigned short wRate, - bool bNeedAck, - unsigned char byFBOption -) -{ - unsigned int uCTSTime = 0, uDurTime = 0; - - switch (byDurType) { - case RTSDUR_BB: /* RTSDuration_bb */ - uCTSTime = bb_get_frame_time(pDevice->preamble_type, byPktType, 14, pDevice->byTopCCKBasicRate); - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); - break; - - case RTSDUR_BA: /* RTSDuration_ba */ - uCTSTime = bb_get_frame_time(pDevice->preamble_type, byPktType, 14, pDevice->byTopCCKBasicRate); - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); - break; - - case RTSDUR_AA: /* RTSDuration_aa */ - uCTSTime = bb_get_frame_time(pDevice->preamble_type, byPktType, 14, pDevice->byTopOFDMBasicRate); - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); - break; - - case CTSDUR_BA: /* CTSDuration_ba */ - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck); - break; - - case RTSDUR_BA_F0: /* RTSDuration_ba_f0 */ - uCTSTime = bb_get_frame_time(pDevice->preamble_type, byPktType, 14, pDevice->byTopCCKBasicRate); - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt0[FB_RATE0][wRate - RATE_18M], bNeedAck); - else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt1[FB_RATE0][wRate - RATE_18M], bNeedAck); - - break; - - case RTSDUR_AA_F0: /* RTSDuration_aa_f0 */ - uCTSTime = bb_get_frame_time(pDevice->preamble_type, byPktType, 14, pDevice->byTopOFDMBasicRate); - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt0[FB_RATE0][wRate - RATE_18M], bNeedAck); - else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt1[FB_RATE0][wRate - RATE_18M], bNeedAck); - - break; - - case RTSDUR_BA_F1: /* RTSDuration_ba_f1 */ - uCTSTime = bb_get_frame_time(pDevice->preamble_type, byPktType, 14, pDevice->byTopCCKBasicRate); - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt0[FB_RATE1][wRate - RATE_18M], bNeedAck); - else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt1[FB_RATE1][wRate - RATE_18M], bNeedAck); - - break; - - case RTSDUR_AA_F1: /* RTSDuration_aa_f1 */ - uCTSTime = bb_get_frame_time(pDevice->preamble_type, byPktType, 14, pDevice->byTopOFDMBasicRate); - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt0[FB_RATE1][wRate - RATE_18M], bNeedAck); - else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt1[FB_RATE1][wRate - RATE_18M], bNeedAck); - - break; - - case CTSDUR_BA_F0: /* CTSDuration_ba_f0 */ - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt0[FB_RATE0][wRate - RATE_18M], bNeedAck); - else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt1[FB_RATE0][wRate - RATE_18M], bNeedAck); - - break; - - case CTSDUR_BA_F1: /* CTSDuration_ba_f1 */ - if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt0[FB_RATE1][wRate - RATE_18M], bNeedAck); - else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) - uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, fb_opt1[FB_RATE1][wRate - RATE_18M], bNeedAck); - - break; - - default: - break; - } - - return cpu_to_le16((u16)uDurTime); -} - -static -__le16 -s_uFillDataHead( - struct vnt_private *pDevice, - unsigned char byPktType, - void *pTxDataHead, - unsigned int cbFrameLength, - unsigned int uDMAIdx, - bool bNeedAck, - unsigned int uFragIdx, - unsigned int cbLastFragmentSize, - unsigned int uMACfragNum, - unsigned char byFBOption, - unsigned short wCurrentRate, - bool is_pspoll -) -{ - struct vnt_tx_datahead_ab *buf = pTxDataHead; - - if (!pTxDataHead) - return 0; - - if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - /* Auto Fallback */ - struct vnt_tx_datahead_g_fb *buf = pTxDataHead; - - if (byFBOption == AUTO_FB_NONE) { - struct vnt_tx_datahead_g *buf = pTxDataHead; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, cbFrameLength, wCurrentRate, - byPktType, &buf->a); - - vnt_get_phy_field(pDevice, cbFrameLength, - pDevice->byTopCCKBasicRate, - PK_TYPE_11B, &buf->b); - - if (is_pspoll) { - __le16 dur = cpu_to_le16(pDevice->current_aid | BIT(14) | BIT(15)); - - buf->duration_a = dur; - buf->duration_b = dur; - } else { - /* Get Duration and TimeStamp */ - buf->duration_a = - cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, - byPktType, wCurrentRate, bNeedAck, uFragIdx, - cbLastFragmentSize, uMACfragNum, - byFBOption)); - buf->duration_b = - cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, - PK_TYPE_11B, pDevice->byTopCCKBasicRate, - bNeedAck, uFragIdx, cbLastFragmentSize, - uMACfragNum, byFBOption)); - } - - buf->time_stamp_off_a = vnt_time_stamp_off(pDevice, wCurrentRate); - buf->time_stamp_off_b = vnt_time_stamp_off(pDevice, pDevice->byTopCCKBasicRate); - - return buf->duration_a; - } - - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, cbFrameLength, wCurrentRate, - byPktType, &buf->a); - - vnt_get_phy_field(pDevice, cbFrameLength, - pDevice->byTopCCKBasicRate, - PK_TYPE_11B, &buf->b); - /* Get Duration and TimeStamp */ - buf->duration_a = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType, - wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); - buf->duration_b = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B, - pDevice->byTopCCKBasicRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); - buf->duration_a_f0 = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType, - wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); - buf->duration_a_f1 = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType, - wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); - - buf->time_stamp_off_a = vnt_time_stamp_off(pDevice, wCurrentRate); - buf->time_stamp_off_b = vnt_time_stamp_off(pDevice, pDevice->byTopCCKBasicRate); - - return buf->duration_a; - /* if (byFBOption == AUTO_FB_NONE) */ - } else if (byPktType == PK_TYPE_11A) { - struct vnt_tx_datahead_ab *buf = pTxDataHead; - - if (byFBOption != AUTO_FB_NONE) { - /* Auto Fallback */ - struct vnt_tx_datahead_a_fb *buf = pTxDataHead; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, cbFrameLength, wCurrentRate, - byPktType, &buf->a); - - /* Get Duration and TimeStampOff */ - buf->duration = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType, - wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); - buf->duration_f0 = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType, - wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); - buf->duration_f1 = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType, - wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); - buf->time_stamp_off = vnt_time_stamp_off(pDevice, wCurrentRate); - return buf->duration; - } - - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, cbFrameLength, wCurrentRate, - byPktType, &buf->ab); - - if (is_pspoll) { - __le16 dur = cpu_to_le16(pDevice->current_aid | BIT(14) | BIT(15)); - - buf->duration = dur; - } else { - /* Get Duration and TimeStampOff */ - buf->duration = - cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType, - wCurrentRate, bNeedAck, uFragIdx, - cbLastFragmentSize, uMACfragNum, - byFBOption)); - } - - buf->time_stamp_off = vnt_time_stamp_off(pDevice, wCurrentRate); - return buf->duration; - } - - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, cbFrameLength, wCurrentRate, - byPktType, &buf->ab); - - if (is_pspoll) { - __le16 dur = cpu_to_le16(pDevice->current_aid | BIT(14) | BIT(15)); - - buf->duration = dur; - } else { - /* Get Duration and TimeStampOff */ - buf->duration = - cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType, - wCurrentRate, bNeedAck, uFragIdx, - cbLastFragmentSize, uMACfragNum, - byFBOption)); - } - - buf->time_stamp_off = vnt_time_stamp_off(pDevice, wCurrentRate); - return buf->duration; -} - -static -void -s_vFillRTSHead( - struct vnt_private *pDevice, - unsigned char byPktType, - void *pvRTS, - unsigned int cbFrameLength, - bool bNeedAck, - bool bDisCRC, - struct ieee80211_hdr *hdr, - unsigned short wCurrentRate, - unsigned char byFBOption -) -{ - unsigned int uRTSFrameLen = 20; - - if (!pvRTS) - return; - - if (bDisCRC) { - /* When CRCDIS bit is on, H/W forgot to generate FCS for - * RTS frame, in this case we need to decrease its length by 4. - */ - uRTSFrameLen -= 4; - } - - /* Note: So far RTSHead doesn't appear in ATIM & Beacom DMA, - * so we don't need to take them into account. - * Otherwise, we need to modify codes for them. - */ - if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - if (byFBOption == AUTO_FB_NONE) { - struct vnt_rts_g *buf = pvRTS; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, uRTSFrameLen, - pDevice->byTopCCKBasicRate, - PK_TYPE_11B, &buf->b); - - vnt_get_phy_field(pDevice, uRTSFrameLen, - pDevice->byTopOFDMBasicRate, - byPktType, &buf->a); - /* Get Duration */ - buf->duration_bb = - s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, - cbFrameLength, PK_TYPE_11B, - pDevice->byTopCCKBasicRate, - bNeedAck, byFBOption); - buf->duration_aa = - s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->duration_ba = - s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - - buf->data.duration = buf->duration_aa; - /* Get RTS Frame body */ - buf->data.frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | - IEEE80211_STYPE_RTS); - - ether_addr_copy(buf->data.ra, hdr->addr1); - ether_addr_copy(buf->data.ta, hdr->addr2); - } else { - struct vnt_rts_g_fb *buf = pvRTS; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, uRTSFrameLen, - pDevice->byTopCCKBasicRate, - PK_TYPE_11B, &buf->b); - - vnt_get_phy_field(pDevice, uRTSFrameLen, - pDevice->byTopOFDMBasicRate, - byPktType, &buf->a); - /* Get Duration */ - buf->duration_bb = - s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, - cbFrameLength, PK_TYPE_11B, - pDevice->byTopCCKBasicRate, - bNeedAck, byFBOption); - buf->duration_aa = - s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->duration_ba = - s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->rts_duration_ba_f0 = - s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->rts_duration_aa_f0 = - s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->rts_duration_ba_f1 = - s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->rts_duration_aa_f1 = - s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->data.duration = buf->duration_aa; - /* Get RTS Frame body */ - buf->data.frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | - IEEE80211_STYPE_RTS); - - ether_addr_copy(buf->data.ra, hdr->addr1); - ether_addr_copy(buf->data.ta, hdr->addr2); - } /* if (byFBOption == AUTO_FB_NONE) */ - } else if (byPktType == PK_TYPE_11A) { - if (byFBOption == AUTO_FB_NONE) { - struct vnt_rts_ab *buf = pvRTS; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, uRTSFrameLen, - pDevice->byTopOFDMBasicRate, - byPktType, &buf->ab); - /* Get Duration */ - buf->duration = - s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->data.duration = buf->duration; - /* Get RTS Frame body */ - buf->data.frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | - IEEE80211_STYPE_RTS); - - ether_addr_copy(buf->data.ra, hdr->addr1); - ether_addr_copy(buf->data.ta, hdr->addr2); - } else { - struct vnt_rts_a_fb *buf = pvRTS; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, uRTSFrameLen, - pDevice->byTopOFDMBasicRate, - byPktType, &buf->a); - /* Get Duration */ - buf->duration = - s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->rts_duration_f0 = - s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->rts_duration_f1 = - s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - buf->data.duration = buf->duration; - /* Get RTS Frame body */ - buf->data.frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | - IEEE80211_STYPE_RTS); - - ether_addr_copy(buf->data.ra, hdr->addr1); - ether_addr_copy(buf->data.ta, hdr->addr2); - } - } else if (byPktType == PK_TYPE_11B) { - struct vnt_rts_ab *buf = pvRTS; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, uRTSFrameLen, - pDevice->byTopCCKBasicRate, - PK_TYPE_11B, &buf->ab); - /* Get Duration */ - buf->duration = - s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, - byPktType, wCurrentRate, bNeedAck, - byFBOption); - - buf->data.duration = buf->duration; - /* Get RTS Frame body */ - buf->data.frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); - - ether_addr_copy(buf->data.ra, hdr->addr1); - ether_addr_copy(buf->data.ta, hdr->addr2); - } -} - -static -void -s_vFillCTSHead( - struct vnt_private *pDevice, - unsigned int uDMAIdx, - unsigned char byPktType, - void *pvCTS, - unsigned int cbFrameLength, - bool bNeedAck, - bool bDisCRC, - unsigned short wCurrentRate, - unsigned char byFBOption -) -{ - unsigned int uCTSFrameLen = 14; - - if (!pvCTS) - return; - - if (bDisCRC) { - /* When CRCDIS bit is on, H/W forgot to generate FCS for - * CTS frame, in this case we need to decrease its length by 4. - */ - uCTSFrameLen -= 4; - } - - if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) { - /* Auto Fall back */ - struct vnt_cts_fb *buf = pvCTS; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, uCTSFrameLen, - pDevice->byTopCCKBasicRate, - PK_TYPE_11B, &buf->b); - - buf->duration_ba = - s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - - /* Get CTSDuration_ba_f0 */ - buf->cts_duration_ba_f0 = - s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - - /* Get CTSDuration_ba_f1 */ - buf->cts_duration_ba_f1 = - s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - - /* Get CTS Frame body */ - buf->data.duration = buf->duration_ba; - - buf->data.frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | - IEEE80211_STYPE_CTS); - - buf->reserved2 = 0x0; - - ether_addr_copy(buf->data.ra, - pDevice->abyCurrentNetAddr); - } else { /* if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) */ - struct vnt_cts *buf = pvCTS; - /* Get SignalField, ServiceField & Length */ - vnt_get_phy_field(pDevice, uCTSFrameLen, - pDevice->byTopCCKBasicRate, - PK_TYPE_11B, &buf->b); - - /* Get CTSDuration_ba */ - buf->duration_ba = - s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, - cbFrameLength, byPktType, - wCurrentRate, bNeedAck, - byFBOption); - - /* Get CTS Frame body */ - buf->data.duration = buf->duration_ba; - - buf->data.frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | - IEEE80211_STYPE_CTS); - - buf->reserved2 = 0x0; - ether_addr_copy(buf->data.ra, - pDevice->abyCurrentNetAddr); - } - } -} - -/* - * - * Description: - * Generate FIFO control for MAC & Baseband controller - * - * Parameters: - * In: - * pDevice - Pointer to adapter - * pTxDataHead - Transmit Data Buffer - * pTxBufHead - pTxBufHead - * pvRrvTime - pvRrvTime - * pvRTS - RTS Buffer - * pCTS - CTS Buffer - * cbFrameSize - Transmit Data Length (Hdr+Payload+FCS) - * bNeedACK - If need ACK - * uDescIdx - Desc Index - * Out: - * none - * - * Return Value: none - * - - - * unsigned int cbFrameSize, Hdr+Payload+FCS - */ -static -void -s_vGenerateTxParameter( - struct vnt_private *pDevice, - unsigned char byPktType, - struct vnt_tx_fifo_head *tx_buffer_head, - void *pvRrvTime, - void *pvRTS, - void *pvCTS, - unsigned int cbFrameSize, - bool bNeedACK, - unsigned int uDMAIdx, - void *psEthHeader, - unsigned short wCurrentRate -) -{ - u16 fifo_ctl = le16_to_cpu(tx_buffer_head->fifo_ctl); - bool bDisCRC = false; - unsigned char byFBOption = AUTO_FB_NONE; - - tx_buffer_head->current_rate = cpu_to_le16(wCurrentRate); - - if (fifo_ctl & FIFOCTL_CRCDIS) - bDisCRC = true; - - if (fifo_ctl & FIFOCTL_AUTO_FB_0) - byFBOption = AUTO_FB_0; - else if (fifo_ctl & FIFOCTL_AUTO_FB_1) - byFBOption = AUTO_FB_1; - - if (!pvRrvTime) - return; - - if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - if (pvRTS) { /* RTS_need */ - /* Fill RsvTime */ - struct vnt_rrv_time_rts *buf = pvRrvTime; - - buf->rts_rrv_time_aa = get_rtscts_time(pDevice, 2, byPktType, cbFrameSize, wCurrentRate); - buf->rts_rrv_time_ba = get_rtscts_time(pDevice, 1, byPktType, cbFrameSize, wCurrentRate); - buf->rts_rrv_time_bb = get_rtscts_time(pDevice, 0, byPktType, cbFrameSize, wCurrentRate); - buf->rrv_time_a = vnt_rxtx_rsvtime_le16(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK); - buf->rrv_time_b = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK); - - s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption); - } else {/* RTS_needless, PCF mode */ - struct vnt_rrv_time_cts *buf = pvRrvTime; - - buf->rrv_time_a = vnt_rxtx_rsvtime_le16(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK); - buf->rrv_time_b = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK); - buf->cts_rrv_time_ba = get_rtscts_time(pDevice, 3, byPktType, cbFrameSize, wCurrentRate); - - /* Fill CTS */ - s_vFillCTSHead(pDevice, uDMAIdx, byPktType, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption); - } - } else if (byPktType == PK_TYPE_11A) { - if (pvRTS) {/* RTS_need, non PCF mode */ - struct vnt_rrv_time_ab *buf = pvRrvTime; - - buf->rts_rrv_time = get_rtscts_time(pDevice, 2, byPktType, cbFrameSize, wCurrentRate); - buf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK); - - /* Fill RTS */ - s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption); - } else if (!pvRTS) {/* RTS_needless, non PCF mode */ - struct vnt_rrv_time_ab *buf = pvRrvTime; - - buf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK); - } - } else if (byPktType == PK_TYPE_11B) { - if (pvRTS) {/* RTS_need, non PCF mode */ - struct vnt_rrv_time_ab *buf = pvRrvTime; - - buf->rts_rrv_time = get_rtscts_time(pDevice, 0, byPktType, cbFrameSize, wCurrentRate); - buf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK); - - /* Fill RTS */ - s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption); - } else { /* RTS_needless, non PCF mode */ - struct vnt_rrv_time_ab *buf = pvRrvTime; - - buf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK); - } - } -} - -static unsigned int -s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType, - unsigned char *pbyTxBufferAddr, - unsigned int uDMAIdx, struct vnt_tx_desc *pHeadTD, - unsigned int is_pspoll) -{ - struct vnt_td_info *td_info = pHeadTD->td_info; - struct sk_buff *skb = td_info->skb; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct vnt_tx_fifo_head *tx_buffer_head = - (struct vnt_tx_fifo_head *)td_info->buf; - u16 fifo_ctl = le16_to_cpu(tx_buffer_head->fifo_ctl); - unsigned int cbFrameSize; - __le16 uDuration; - unsigned char *pbyBuffer; - unsigned int uLength = 0; - unsigned int cbMICHDR = 0; - unsigned int uMACfragNum = 1; - unsigned int uPadding = 0; - unsigned int cbReqCount = 0; - bool bNeedACK = (bool)(fifo_ctl & FIFOCTL_NEEDACK); - bool bRTS = (bool)(fifo_ctl & FIFOCTL_RTS); - struct vnt_tx_desc *ptdCurr; - unsigned int cbHeaderLength = 0; - void *pvRrvTime = NULL; - struct vnt_mic_hdr *pMICHDR = NULL; - void *pvRTS = NULL; - void *pvCTS = NULL; - void *pvTxDataHd = NULL; - unsigned short wTxBufSize; /* FFinfo size */ - unsigned char byFBOption = AUTO_FB_NONE; - - cbFrameSize = skb->len + 4; - - if (info->control.hw_key) { - switch (info->control.hw_key->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - cbMICHDR = sizeof(struct vnt_mic_hdr); - break; - default: - break; - } - - cbFrameSize += info->control.hw_key->icv_len; - - if (pDevice->local_id > REV_ID_VT3253_A1) { - /* MAC Header should be padding 0 to DW alignment. */ - uPadding = 4 - (ieee80211_get_hdrlen_from_skb(skb) % 4); - uPadding %= 4; - } - } - - /* - * Use for AUTO FALL BACK - */ - if (fifo_ctl & FIFOCTL_AUTO_FB_0) - byFBOption = AUTO_FB_0; - else if (fifo_ctl & FIFOCTL_AUTO_FB_1) - byFBOption = AUTO_FB_1; - - /* Set RrvTime/RTS/CTS Buffer */ - wTxBufSize = sizeof(struct vnt_tx_fifo_head); - if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {/* 802.11g packet */ - - if (byFBOption == AUTO_FB_NONE) { - if (bRTS) {/* RTS_need */ - pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts)); - pvRTS = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts) + cbMICHDR); - pvCTS = NULL; - pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts) + - cbMICHDR + sizeof(struct vnt_rts_g)); - cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_rts) + - cbMICHDR + sizeof(struct vnt_rts_g) + - sizeof(struct vnt_tx_datahead_g); - } else { /* RTS_needless */ - pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts)); - pvRTS = NULL; - pvCTS = (void *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR); - pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_cts) + cbMICHDR + sizeof(struct vnt_cts)); - cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_cts) + - cbMICHDR + sizeof(struct vnt_cts) + sizeof(struct vnt_tx_datahead_g); - } - } else { - /* Auto Fall Back */ - if (bRTS) {/* RTS_need */ - pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts)); - pvRTS = (void *) (pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts) + cbMICHDR); - pvCTS = NULL; - pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_rts) + - cbMICHDR + sizeof(struct vnt_rts_g_fb)); - cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_rts) + - cbMICHDR + sizeof(struct vnt_rts_g_fb) + sizeof(struct vnt_tx_datahead_g_fb); - } else { /* RTS_needless */ - pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts)); - pvRTS = NULL; - pvCTS = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts) + cbMICHDR); - pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_cts) + - cbMICHDR + sizeof(struct vnt_cts_fb)); - cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_cts) + - cbMICHDR + sizeof(struct vnt_cts_fb) + sizeof(struct vnt_tx_datahead_g_fb); - } - } /* Auto Fall Back */ - } else {/* 802.11a/b packet */ - - if (byFBOption == AUTO_FB_NONE) { - if (bRTS) { - pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab)); - pvRTS = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR); - pvCTS = NULL; - pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab) + cbMICHDR + sizeof(struct vnt_rts_ab)); - cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + - cbMICHDR + sizeof(struct vnt_rts_ab) + sizeof(struct vnt_tx_datahead_ab); - } else { /* RTS_needless, need MICHDR */ - pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab)); - pvRTS = NULL; - pvCTS = NULL; - pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR); - cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + - cbMICHDR + sizeof(struct vnt_tx_datahead_ab); - } - } else { - /* Auto Fall Back */ - if (bRTS) { /* RTS_need */ - pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab)); - pvRTS = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR); - pvCTS = NULL; - pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + - sizeof(struct vnt_rrv_time_ab) + cbMICHDR + sizeof(struct vnt_rts_a_fb)); - cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + - cbMICHDR + sizeof(struct vnt_rts_a_fb) + sizeof(struct vnt_tx_datahead_a_fb); - } else { /* RTS_needless */ - pvRrvTime = (void *)(pbyTxBufferAddr + wTxBufSize); - pMICHDR = (struct vnt_mic_hdr *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab)); - pvRTS = NULL; - pvCTS = NULL; - pvTxDataHd = (void *)(pbyTxBufferAddr + wTxBufSize + sizeof(struct vnt_rrv_time_ab) + cbMICHDR); - cbHeaderLength = wTxBufSize + sizeof(struct vnt_rrv_time_ab) + - cbMICHDR + sizeof(struct vnt_tx_datahead_a_fb); - } - } /* Auto Fall Back */ - } - - td_info->mic_hdr = pMICHDR; - - memset((void *)(pbyTxBufferAddr + wTxBufSize), 0, (cbHeaderLength - wTxBufSize)); - - /* Fill FIFO,RrvTime,RTS,and CTS */ - s_vGenerateTxParameter(pDevice, byPktType, tx_buffer_head, pvRrvTime, pvRTS, pvCTS, - cbFrameSize, bNeedACK, uDMAIdx, hdr, pDevice->wCurrentRate); - /* Fill DataHead */ - uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFrameSize, uDMAIdx, bNeedACK, - 0, 0, uMACfragNum, byFBOption, pDevice->wCurrentRate, is_pspoll); - - hdr->duration_id = uDuration; - - cbReqCount = cbHeaderLength + uPadding + skb->len; - pbyBuffer = (unsigned char *)pHeadTD->td_info->buf; - uLength = cbHeaderLength + uPadding; - - /* Copy the Packet into a tx Buffer */ - memcpy((pbyBuffer + uLength), skb->data, skb->len); - - ptdCurr = pHeadTD; - - ptdCurr->td_info->req_count = (u16)cbReqCount; - - return cbHeaderLength; -} - -static void vnt_fill_txkey(struct ieee80211_hdr *hdr, u8 *key_buffer, - struct ieee80211_key_conf *tx_key, - struct sk_buff *skb, u16 payload_len, - struct vnt_mic_hdr *mic_hdr) -{ - u64 pn64; - u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb)); - - /* strip header and icv len from payload */ - payload_len -= ieee80211_get_hdrlen_from_skb(skb); - payload_len -= tx_key->icv_len; - - switch (tx_key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - memcpy(key_buffer, iv, 3); - memcpy(key_buffer + 3, tx_key->key, tx_key->keylen); - - if (tx_key->keylen == WLAN_KEY_LEN_WEP40) { - memcpy(key_buffer + 8, iv, 3); - memcpy(key_buffer + 11, - tx_key->key, WLAN_KEY_LEN_WEP40); - } - - break; - case WLAN_CIPHER_SUITE_TKIP: - ieee80211_get_tkip_p2k(tx_key, skb, key_buffer); - - break; - case WLAN_CIPHER_SUITE_CCMP: - - if (!mic_hdr) - return; - - mic_hdr->id = 0x59; - mic_hdr->payload_len = cpu_to_be16(payload_len); - ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2); - - pn64 = atomic64_read(&tx_key->tx_pn); - mic_hdr->ccmp_pn[5] = pn64; - mic_hdr->ccmp_pn[4] = pn64 >> 8; - mic_hdr->ccmp_pn[3] = pn64 >> 16; - mic_hdr->ccmp_pn[2] = pn64 >> 24; - mic_hdr->ccmp_pn[1] = pn64 >> 32; - mic_hdr->ccmp_pn[0] = pn64 >> 40; - - if (ieee80211_has_a4(hdr->frame_control)) - mic_hdr->hlen = cpu_to_be16(28); - else - mic_hdr->hlen = cpu_to_be16(22); - - ether_addr_copy(mic_hdr->addr1, hdr->addr1); - ether_addr_copy(mic_hdr->addr2, hdr->addr2); - ether_addr_copy(mic_hdr->addr3, hdr->addr3); - - mic_hdr->frame_control = cpu_to_le16( - le16_to_cpu(hdr->frame_control) & 0xc78f); - mic_hdr->seq_ctrl = cpu_to_le16( - le16_to_cpu(hdr->seq_ctrl) & 0xf); - - if (ieee80211_has_a4(hdr->frame_control)) - ether_addr_copy(mic_hdr->addr4, hdr->addr4); - - memcpy(key_buffer, tx_key->key, WLAN_KEY_LEN_CCMP); - - break; - default: - break; - } -} - -int vnt_generate_fifo_header(struct vnt_private *priv, u32 dma_idx, - struct vnt_tx_desc *head_td, struct sk_buff *skb) -{ - struct vnt_td_info *td_info = head_td->td_info; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *tx_rate = &info->control.rates[0]; - struct ieee80211_rate *rate; - struct ieee80211_key_conf *tx_key; - struct ieee80211_hdr *hdr; - struct vnt_tx_fifo_head *tx_buffer_head = - (struct vnt_tx_fifo_head *)td_info->buf; - u16 tx_body_size = skb->len, current_rate; - u8 pkt_type; - bool is_pspoll = false; - - memset(tx_buffer_head, 0, sizeof(*tx_buffer_head)); - - hdr = (struct ieee80211_hdr *)(skb->data); - - rate = ieee80211_get_tx_rate(priv->hw, info); - - current_rate = rate->hw_value; - if (priv->wCurrentRate != current_rate && - !(priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { - priv->wCurrentRate = current_rate; - - RFbSetPower(priv, priv->wCurrentRate, - priv->hw->conf.chandef.chan->hw_value); - } - - if (current_rate > RATE_11M) { - if (info->band == NL80211_BAND_5GHZ) { - pkt_type = PK_TYPE_11A; - } else { - if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - pkt_type = PK_TYPE_11GB; - else - pkt_type = PK_TYPE_11GA; - } - } else { - pkt_type = PK_TYPE_11B; - } - - /*Set fifo controls */ - if (pkt_type == PK_TYPE_11A) - tx_buffer_head->fifo_ctl = 0; - else if (pkt_type == PK_TYPE_11B) - tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11B); - else if (pkt_type == PK_TYPE_11GB) - tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11GB); - else if (pkt_type == PK_TYPE_11GA) - tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11GA); - - /* generate interrupt */ - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_GENINT); - - if (!ieee80211_is_data(hdr->frame_control)) { - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_TMOEN); - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_ISDMA0); - tx_buffer_head->time_stamp = - cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); - } else { - tx_buffer_head->time_stamp = - cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us); - } - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_NEEDACK); - - if (ieee80211_has_retry(hdr->frame_control)) - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_LRETRY); - - if (tx_rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - priv->preamble_type = PREAMBLE_SHORT; - else - priv->preamble_type = PREAMBLE_LONG; - - if (tx_rate->flags & IEEE80211_TX_RC_USE_RTS_CTS) - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_RTS); - - if (ieee80211_has_a4(hdr->frame_control)) { - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_LHEAD); - priv->bLongHeader = true; - } - - if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) - is_pspoll = true; - - tx_buffer_head->frag_ctl = - cpu_to_le16(ieee80211_get_hdrlen_from_skb(skb) << 10); - - if (info->control.hw_key) { - switch (info->control.hw_key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_LEGACY); - break; - case WLAN_CIPHER_SUITE_TKIP: - tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_TKIP); - break; - case WLAN_CIPHER_SUITE_CCMP: - tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_AES); - break; - default: - break; - } - } - - tx_buffer_head->current_rate = cpu_to_le16(current_rate); - - /* legacy rates TODO use ieee80211_tx_rate */ - if (current_rate >= RATE_18M && ieee80211_is_data(hdr->frame_control)) { - if (priv->byAutoFBCtrl == AUTO_FB_0) - tx_buffer_head->fifo_ctl |= - cpu_to_le16(FIFOCTL_AUTO_FB_0); - else if (priv->byAutoFBCtrl == AUTO_FB_1) - tx_buffer_head->fifo_ctl |= - cpu_to_le16(FIFOCTL_AUTO_FB_1); - } - - tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_NONFRAG); - - s_cbFillTxBufHead(priv, pkt_type, (u8 *)tx_buffer_head, - dma_idx, head_td, is_pspoll); - - if (info->control.hw_key) { - tx_key = info->control.hw_key; - if (tx_key->keylen > 0) - vnt_fill_txkey(hdr, tx_buffer_head->tx_key, - tx_key, skb, tx_body_size, - td_info->mic_hdr); - } - - return 0; -} - -static int vnt_beacon_xmit(struct vnt_private *priv, - struct sk_buff *skb) -{ - struct vnt_tx_short_buf_head *short_head = - (struct vnt_tx_short_buf_head *)priv->tx_beacon_bufs; - struct ieee80211_mgmt *mgmt_hdr = (struct ieee80211_mgmt *) - (priv->tx_beacon_bufs + sizeof(*short_head)); - struct ieee80211_tx_info *info; - u32 frame_size = skb->len + 4; - u16 current_rate; - - memset(priv->tx_beacon_bufs, 0, sizeof(*short_head)); - - if (priv->byBBType == BB_TYPE_11A) { - current_rate = RATE_6M; - - /* Get SignalField,ServiceField,Length */ - vnt_get_phy_field(priv, frame_size, current_rate, - PK_TYPE_11A, &short_head->ab); - - /* Get Duration and TimeStampOff */ - short_head->duration = - cpu_to_le16((u16)s_uGetDataDuration(priv, DATADUR_B, - frame_size, PK_TYPE_11A, current_rate, - false, 0, 0, 1, AUTO_FB_NONE)); - - short_head->time_stamp_off = - vnt_time_stamp_off(priv, current_rate); - } else { - current_rate = RATE_1M; - short_head->fifo_ctl |= cpu_to_le16(FIFOCTL_11B); - - /* Get SignalField,ServiceField,Length */ - vnt_get_phy_field(priv, frame_size, current_rate, - PK_TYPE_11B, &short_head->ab); - - /* Get Duration and TimeStampOff */ - short_head->duration = - cpu_to_le16((u16)s_uGetDataDuration(priv, DATADUR_B, - frame_size, PK_TYPE_11B, current_rate, - false, 0, 0, 1, AUTO_FB_NONE)); - - short_head->time_stamp_off = - vnt_time_stamp_off(priv, current_rate); - } - - short_head->fifo_ctl |= cpu_to_le16(FIFOCTL_GENINT); - - /* Copy Beacon */ - memcpy(mgmt_hdr, skb->data, skb->len); - - /* time stamp always 0 */ - mgmt_hdr->u.beacon.timestamp = 0; - - info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)mgmt_hdr; - - hdr->duration_id = 0; - hdr->seq_ctrl = cpu_to_le16(priv->wSeqCounter << 4); - } - - priv->wSeqCounter++; - if (priv->wSeqCounter > 0x0fff) - priv->wSeqCounter = 0; - - priv->wBCNBufLen = sizeof(*short_head) + skb->len; - - iowrite32((u32)priv->tx_beacon_dma, priv->port_offset + MAC_REG_BCNDMAPTR); - - iowrite16(priv->wBCNBufLen, priv->port_offset + MAC_REG_BCNDMACTL + 2); - /* Set auto Transmit on */ - vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); - /* Poll Transmit the adapter */ - iowrite8(BEACON_READY, priv->port_offset + MAC_REG_BCNDMACTL); - - return 0; -} - -int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif) -{ - struct sk_buff *beacon; - - beacon = ieee80211_beacon_get(priv->hw, vif, 0); - if (!beacon) - return -ENOMEM; - - if (vnt_beacon_xmit(priv, beacon)) { - ieee80211_free_txskb(priv->hw, beacon); - return -ENODEV; - } - - return 0; -} - -int vnt_beacon_enable(struct vnt_private *priv, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf) -{ - iowrite8(TFTCTL_TSFCNTRST, priv->port_offset + MAC_REG_TFTCTL); - - iowrite8(TFTCTL_TSFCNTREN, priv->port_offset + MAC_REG_TFTCTL); - - CARDvSetFirstNextTBTT(priv, conf->beacon_int); - - card_set_beacon_period(priv, conf->beacon_int); - - return vnt_beacon_make(priv, vif); -} diff --git a/drivers/staging/vt6655/rxtx.h b/drivers/staging/vt6655/rxtx.h deleted file mode 100644 index be1e5180d57b8c..00000000000000 --- a/drivers/staging/vt6655/rxtx.h +++ /dev/null @@ -1,184 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: - * - * Author: Jerry Chen - * - * Date: Jun. 27, 2002 - * - */ - -#ifndef __RXTX_H__ -#define __RXTX_H__ - -#include "device.h" - -#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 /* 64us */ -#define DEFAULT_MGN_LIFETIME_RES_64us 125 /* 64us */ - -/*--------------------- Export Definitions -------------------------*/ - -/*--------------------- Export Variables --------------------------*/ - -/*--------------------- Export Functions --------------------------*/ - -/* MIC HDR data header */ -struct vnt_mic_hdr { - u8 id; - u8 tx_priority; - u8 mic_addr2[ETH_ALEN]; - u8 ccmp_pn[IEEE80211_CCMP_PN_LEN]; - __be16 payload_len; - __be16 hlen; - __le16 frame_control; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctrl; - u8 addr4[ETH_ALEN]; - u16 packing; /* packing to 48 bytes */ -} __packed; - -/* RsvTime buffer header */ -struct vnt_rrv_time_rts { - __le16 rts_rrv_time_ba; - __le16 rts_rrv_time_aa; - __le16 rts_rrv_time_bb; - u16 reserved; - __le16 rrv_time_b; - __le16 rrv_time_a; -} __packed; - -struct vnt_rrv_time_cts { - __le16 cts_rrv_time_ba; - u16 reserved; - __le16 rrv_time_b; - __le16 rrv_time_a; -} __packed; - -struct vnt_rrv_time_ab { - __le16 rts_rrv_time; - __le16 rrv_time; -} __packed; - -/* TX data header */ -struct vnt_tx_datahead_g { - struct vnt_phy_field b; - struct vnt_phy_field a; - __le16 duration_b; - __le16 duration_a; - __le16 time_stamp_off_b; - __le16 time_stamp_off_a; -} __packed; - -struct vnt_tx_datahead_g_fb { - struct vnt_phy_field b; - struct vnt_phy_field a; - __le16 duration_b; - __le16 duration_a; - __le16 duration_a_f0; - __le16 duration_a_f1; - __le16 time_stamp_off_b; - __le16 time_stamp_off_a; -} __packed; - -struct vnt_tx_datahead_ab { - struct vnt_phy_field ab; - __le16 duration; - __le16 time_stamp_off; -} __packed; - -struct vnt_tx_datahead_a_fb { - struct vnt_phy_field a; - __le16 duration; - __le16 time_stamp_off; - __le16 duration_f0; - __le16 duration_f1; -} __packed; - -/* RTS buffer header */ -struct vnt_rts_g { - struct vnt_phy_field b; - struct vnt_phy_field a; - __le16 duration_ba; - __le16 duration_aa; - __le16 duration_bb; - u16 reserved; - struct ieee80211_rts data; -} __packed __aligned(2); - -struct vnt_rts_g_fb { - struct vnt_phy_field b; - struct vnt_phy_field a; - __le16 duration_ba; - __le16 duration_aa; - __le16 duration_bb; - u16 wReserved; - __le16 rts_duration_ba_f0; - __le16 rts_duration_aa_f0; - __le16 rts_duration_ba_f1; - __le16 rts_duration_aa_f1; - struct ieee80211_rts data; -} __packed __aligned(2); - -struct vnt_rts_ab { - struct vnt_phy_field ab; - __le16 duration; - u16 reserved; - struct ieee80211_rts data; -} __packed __aligned(2); - -struct vnt_rts_a_fb { - struct vnt_phy_field a; - __le16 duration; - u16 reserved; - __le16 rts_duration_f0; - __le16 rts_duration_f1; - struct ieee80211_rts data; -} __packed __aligned(2); - -/* CTS buffer header */ -struct vnt_cts { - struct vnt_phy_field b; - __le16 duration_ba; - u16 reserved; - struct ieee80211_cts data; - u16 reserved2; -} __packed __aligned(2); - -struct vnt_cts_fb { - struct vnt_phy_field b; - __le16 duration_ba; - u16 reserved; - __le16 cts_duration_ba_f0; - __le16 cts_duration_ba_f1; - struct ieee80211_cts data; - u16 reserved2; -} __packed __aligned(2); - -struct vnt_tx_fifo_head { - u8 tx_key[WLAN_KEY_LEN_CCMP]; - __le16 fifo_ctl; - __le16 time_stamp; - __le16 frag_ctl; - __le16 current_rate; -} __packed; - -struct vnt_tx_short_buf_head { - __le16 fifo_ctl; - u16 time_stamp; - struct vnt_phy_field ab; - __le16 duration; - __le16 time_stamp_off; -} __packed; - -int vnt_generate_fifo_header(struct vnt_private *priv, u32 dma_idx, - struct vnt_tx_desc *head_td, struct sk_buff *skb); -int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif); -int vnt_beacon_enable(struct vnt_private *priv, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf); - -#endif /* __RXTX_H__ */ diff --git a/drivers/staging/vt6655/srom.c b/drivers/staging/vt6655/srom.c deleted file mode 100644 index e80556509c58dd..00000000000000 --- a/drivers/staging/vt6655/srom.c +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose:Implement functions to access eeprom - * - * Author: Jerry Chen - * - * Date: Jan 29, 2003 - * - * Functions: - * SROMbyReadEmbedded - Embedded read eeprom via MAC - * SROMbWriteEmbedded - Embedded write eeprom via MAC - * SROMvRegBitsOn - Set Bits On in eeprom - * SROMvRegBitsOff - Clear Bits Off in eeprom - * SROMbIsRegBitsOn - Test if Bits On in eeprom - * SROMbIsRegBitsOff - Test if Bits Off in eeprom - * SROMvReadAllContents - Read all contents in eeprom - * SROMvWriteAllContents - Write all contents in eeprom - * SROMvReadEtherAddress - Read Ethernet Address in eeprom - * SROMvWriteEtherAddress - Write Ethernet Address in eeprom - * SROMvReadSubSysVenId - Read Sub_VID and Sub_SysId in eeprom - * SROMbAutoLoad - Auto Load eeprom to MAC register - * - * Revision History: - * - */ - -#include "device.h" -#include "mac.h" -#include "srom.h" - -/*--------------------- Static Definitions -------------------------*/ - -/*--------------------- Static Classes ----------------------------*/ - -/*--------------------- Static Variables --------------------------*/ - -/*--------------------- Static Functions --------------------------*/ - -/*--------------------- Export Variables --------------------------*/ - -/*--------------------- Export Functions --------------------------*/ - -/* - * Description: Read a byte from EEPROM, by MAC I2C - * - * Parameters: - * In: - * iobase - I/O base address - * contnt_offset - address of EEPROM - * Out: - * none - * - * Return Value: data read - * - */ -unsigned char SROMbyReadEmbedded(void __iomem *iobase, - unsigned char contnt_offset) -{ - unsigned short wDelay, wNoACK; - unsigned char byWait; - unsigned char byData; - unsigned char byOrg; - - byOrg = ioread8(iobase + MAC_REG_I2MCFG); - /* turn off hardware retry for getting NACK */ - iowrite8(byOrg & (~I2MCFG_NORETRY), iobase + MAC_REG_I2MCFG); - for (wNoACK = 0; wNoACK < W_MAX_I2CRETRY; wNoACK++) { - iowrite8(EEP_I2C_DEV_ID, iobase + MAC_REG_I2MTGID); - iowrite8(contnt_offset, iobase + MAC_REG_I2MTGAD); - - /* issue read command */ - iowrite8(I2MCSR_EEMR, iobase + MAC_REG_I2MCSR); - /* wait DONE be set */ - for (wDelay = 0; wDelay < W_MAX_TIMEOUT; wDelay++) { - byWait = ioread8(iobase + MAC_REG_I2MCSR); - if (byWait & (I2MCSR_DONE | I2MCSR_NACK)) - break; - udelay(CB_DELAY_LOOP_WAIT); - } - if ((wDelay < W_MAX_TIMEOUT) && - (!(byWait & I2MCSR_NACK))) { - break; - } - } - byData = ioread8(iobase + MAC_REG_I2MDIPT); - iowrite8(byOrg, iobase + MAC_REG_I2MCFG); - return byData; -} - -/* - * Description: Read all contents of eeprom to buffer - * - * Parameters: - * In: - * iobase - I/O base address - * Out: - * pbyEepromRegs - EEPROM content Buffer - * - * Return Value: none - * - */ -void SROMvReadAllContents(void __iomem *iobase, unsigned char *pbyEepromRegs) -{ - int ii; - - /* ii = Rom Address */ - for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) { - *pbyEepromRegs = SROMbyReadEmbedded(iobase, - (unsigned char)ii); - pbyEepromRegs++; - } -} - -/* - * Description: Read Ethernet Address from eeprom to buffer - * - * Parameters: - * In: - * iobase - I/O base address - * Out: - * pbyEtherAddress - Ethernet Address buffer - * - * Return Value: none - * - */ -void SROMvReadEtherAddress(void __iomem *iobase, - unsigned char *pbyEtherAddress) -{ - unsigned char ii; - - /* ii = Rom Address */ - for (ii = 0; ii < ETH_ALEN; ii++) { - *pbyEtherAddress = SROMbyReadEmbedded(iobase, ii); - pbyEtherAddress++; - } -} diff --git a/drivers/staging/vt6655/srom.h b/drivers/staging/vt6655/srom.h deleted file mode 100644 index b03073ffa18a2e..00000000000000 --- a/drivers/staging/vt6655/srom.h +++ /dev/null @@ -1,85 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions to access eeprom - * - * Author: Jerry Chen - * - * Date: Jan 29, 2003 - */ - -#ifndef __SROM_H__ -#define __SROM_H__ - -/*--------------------- Export Definitions -------------------------*/ - -#define EEP_MAX_CONTEXT_SIZE 256 - -#define CB_EEPROM_READBYTE_WAIT 900 /* us */ - -#define W_MAX_I2CRETRY 0x0fff - -/* Contents in the EEPROM */ -#define EEP_OFS_PAR 0x00 /* physical address */ -#define EEP_OFS_ANTENNA 0x16 -#define EEP_OFS_RADIOCTL 0x17 -#define EEP_OFS_RFTYPE 0x1B /* for select RF */ -#define EEP_OFS_MINCHANNEL 0x1C /* Min Channel # */ -#define EEP_OFS_MAXCHANNEL 0x1D /* Max Channel # */ -#define EEP_OFS_SIGNATURE 0x1E -#define EEP_OFS_ZONETYPE 0x1F -#define EEP_OFS_RFTABLE 0x20 /* RF POWER TABLE */ -#define EEP_OFS_PWR_CCK 0x20 -#define EEP_OFS_SETPT_CCK 0x21 -#define EEP_OFS_PWR_OFDMG 0x23 -#define EEP_OFS_SETPT_OFDMG 0x24 -#define EEP_OFS_PWR_FORMULA_OST 0x26 -#define EEP_OFS_MAJOR_VER 0x2E -#define EEP_OFS_MINOR_VER 0x2F -#define EEP_OFS_CCK_PWR_TBL 0x30 -#define EEP_OFS_CCK_PWR_dBm 0x3F -#define EEP_OFS_OFDM_PWR_TBL 0x40 -#define EEP_OFS_OFDM_PWR_dBm 0x4F -/*{{ RobertYu: 20041124 */ -#define EEP_OFS_SETPT_OFDMA 0x4E -#define EEP_OFS_OFDMA_PWR_TBL 0x50 -/*}}*/ -#define EEP_OFS_OFDMA_PWR_dBm 0xD2 - -/*----------need to remove --------------------*/ -#define EEP_OFS_BBTAB_LEN 0x70 /* BB Table Length */ -#define EEP_OFS_BBTAB_ADR 0x71 /* BB Table Offset */ -#define EEP_OFS_CHECKSUM 0xFF /* reserved area for baseband 28h~78h */ - -#define EEP_I2C_DEV_ID 0x50 /* EEPROM device address on I2C bus */ - -/* Bits in EEP_OFS_ANTENNA */ -#define EEP_ANTENNA_MAIN 0x01 -#define EEP_ANTENNA_AUX 0x02 -#define EEP_ANTINV 0x04 - -/* Bits in EEP_OFS_RADIOCTL */ -#define EEP_RADIOCTL_ENABLE 0x80 -#define EEP_RADIOCTL_INV 0x01 - -/*--------------------- Export Types ------------------------------*/ - -/*--------------------- Export Macros ------------------------------*/ - -/*--------------------- Export Classes ----------------------------*/ - -/*--------------------- Export Variables --------------------------*/ - -/*--------------------- Export Functions --------------------------*/ - -unsigned char SROMbyReadEmbedded(void __iomem *iobase, - unsigned char byContntOffset); - -void SROMvReadAllContents(void __iomem *iobase, unsigned char *pbyEepromRegs); - -void SROMvReadEtherAddress(void __iomem *iobase, - unsigned char *pbyEtherAddress); - -#endif /* __EEPROM_H__*/ diff --git a/drivers/staging/vt6655/test b/drivers/staging/vt6655/test deleted file mode 100644 index ba6dec774478e9..00000000000000 --- a/drivers/staging/vt6655/test +++ /dev/null @@ -1,9 +0,0 @@ -KSP := /lib/modules/$(shell uname -r)/build \ - /usr/src/linux-$(shell uname -r) \ - /usr/src/linux-$(shell uname -r | sed 's/-.*//') \ -# /usr/src/kernel-headers-$(shell uname -r) \ -# /usr/src/kernel-source-$(shell uname -r) \ -# /usr/src/linux-$(shell uname -r | sed 's/\([0-9]*\.[0-9]*\)\..*/\1/') \ -# /usr/src/linux /home/plice -test_dir = $(shell [ -e $(dir)/include/linux ] && echo $(dir)) -KSP := $(foreach dir, $(KSP), $(test_dir)) diff --git a/drivers/staging/vt6656/Kconfig b/drivers/staging/vt6656/Kconfig deleted file mode 100644 index f52a3f1d9a2ee2..00000000000000 --- a/drivers/staging/vt6656/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config VT6656 - tristate "VIA Technologies VT6656 support" - depends on MAC80211 && USB && WLAN && m - select FW_LOADER - help - This is a vendor-written driver for VIA VT6656. diff --git a/drivers/staging/vt6656/Makefile b/drivers/staging/vt6656/Makefile deleted file mode 100644 index f696a9d7a143d4..00000000000000 --- a/drivers/staging/vt6656/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -vt6656_stage-y += main_usb.o \ - card.o \ - mac.o \ - baseband.o \ - wcmd.o\ - rxtx.o \ - power.o \ - key.o \ - rf.o \ - usbpipe.o \ - channel.o - -obj-$(CONFIG_VT6656) += vt6656_stage.o diff --git a/drivers/staging/vt6656/TODO b/drivers/staging/vt6656/TODO deleted file mode 100644 index 876cdccb6948c3..00000000000000 --- a/drivers/staging/vt6656/TODO +++ /dev/null @@ -1,18 +0,0 @@ -TODO: -- remove __cplusplus ifdefs -- done -- remove kernel version compatibility wrappers -- remove support for older wireless extensions -- prepare for merge with vt6655 driver: - - remove PRINT_K() macro - - split rf.c - - abstract VT3184 chipset specific code -- add common vt665x infrastructure -- kill ttype.h -- done -- switch to use LIB80211 -- switch to use MAC80211 -- use kernel coding style -- sparse fixes -- integrate with drivers/net/wireless - -Please send any patches to Greg Kroah-Hartman -and Forest Bond . diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c deleted file mode 100644 index ad7b963f0d981a..00000000000000 --- a/drivers/staging/vt6656/baseband.c +++ /dev/null @@ -1,455 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions to access baseband - * - * Author: Jerry Chen - * - * Date: Jun. 5, 2002 - * - * Functions: - * vnt_get_frame_time - Calculate data frame transmitting time - * vnt_get_phy_field - Calculate PhyLength, PhyService and Phy - * Signal parameter for baseband Tx - * vnt_vt3184_init - VIA VT3184 baseband chip init code - * - * Revision History: - * - * - */ - -#include -#include -#include -#include "device.h" -#include "mac.h" -#include "baseband.h" -#include "rf.h" -#include "usbpipe.h" - -static const u8 vnt_vt3184_agc[] = { - 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x06, 0x06, - 0x08, 0x08, 0x0a, 0x0a, 0x0c, 0x0c, 0x0e, 0x0e, /* 0x0f */ - 0x10, 0x10, 0x12, 0x12, 0x14, 0x14, 0x16, 0x16, - 0x18, 0x18, 0x1a, 0x1a, 0x1c, 0x1c, 0x1e, 0x1e, /* 0x1f */ - 0x20, 0x20, 0x22, 0x22, 0x24, 0x24, 0x26, 0x26, - 0x28, 0x28, 0x2a, 0x2a, 0x2c, 0x2c, 0x2e, 0x2e, /* 0x2f */ - 0x30, 0x30, 0x32, 0x32, 0x34, 0x34, 0x36, 0x36, - 0x38, 0x38, 0x3a, 0x3a, 0x3c, 0x3c, 0x3e, 0x3e /* 0x3f */ -}; - -static u8 vnt_vt3184_al2230[] = { - 0x31, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, - 0x70, 0x45, 0x2a, 0x76, 0x00, 0x00, 0x80, 0x00, /* 0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x8e, 0x0a, 0x00, 0x00, 0x00, /* 0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x0c, /* 0x2f */ - 0x26, 0x5b, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, - 0xff, 0xff, 0x79, 0x00, 0x00, 0x0b, 0x48, 0x04, /* 0x3f */ - 0x00, 0x08, 0x00, 0x08, 0x08, 0x14, 0x05, 0x09, - 0x00, 0x00, 0x00, 0x00, 0x09, 0x73, 0x00, 0xc5, /* 0x4f */ - 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5f */ - 0xe4, 0x80, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* 0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7f */ - 0x8c, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x1f, 0xb7, 0x88, 0x47, 0xaa, 0x00, /* 0x8f */ - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x18, /* 0xaf */ - 0x38, 0x30, 0x00, 0x00, 0xff, 0x0f, 0xe4, 0xe2, - 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, /* 0xbf */ - 0x18, 0x20, 0x07, 0x18, 0xff, 0xff, 0x0e, 0x0a, - 0x0e, 0x00, 0x82, 0xa7, 0x3c, 0x10, 0x30, 0x05, /* 0xcf */ - 0x40, 0x12, 0x00, 0x00, 0x10, 0x28, 0x80, 0x2a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xdf */ - 0x00, 0xf3, 0x00, 0x00, 0x00, 0x10, 0x00, 0x12, - 0x00, 0xf4, 0x00, 0xff, 0x79, 0x20, 0x30, 0x05, /* 0xef */ - 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xff */ -}; - -/* {{RobertYu:20060515, new BB setting for VT3226D0 */ -static const u8 vnt_vt3184_vt3226d0[] = { - 0x31, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, - 0x70, 0x45, 0x2a, 0x76, 0x00, 0x00, 0x80, 0x00, /* 0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x8e, 0x0a, 0x00, 0x00, 0x00, /* 0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x0c, /* 0x2f */ - 0x26, 0x5b, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, - 0xff, 0xff, 0x79, 0x00, 0x00, 0x0b, 0x48, 0x04, /* 0x3f */ - 0x00, 0x08, 0x00, 0x08, 0x08, 0x14, 0x05, 0x09, - 0x00, 0x00, 0x00, 0x00, 0x09, 0x73, 0x00, 0xc5, /* 0x4f */ - 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5f */ - 0xe4, 0x80, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* 0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7f */ - 0x8c, 0x01, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x1f, 0xb7, 0x88, 0x47, 0xaa, 0x00, /* 0x8f */ - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* 0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, /* 0xaf */ - 0x38, 0x30, 0x00, 0x00, 0xff, 0x0f, 0xe4, 0xe2, - 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, /* 0xbf */ - 0x18, 0x20, 0x07, 0x18, 0xff, 0xff, 0x10, 0x0a, - 0x0e, 0x00, 0x84, 0xa7, 0x3c, 0x10, 0x24, 0x05, /* 0xcf */ - 0x40, 0x12, 0x00, 0x00, 0x10, 0x28, 0x80, 0x2a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xdf */ - 0x00, 0xf3, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, - 0x00, 0xf4, 0x00, 0xff, 0x79, 0x20, 0x30, 0x08, /* 0xef */ - 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xff */ -}; - -struct vnt_threshold { - u8 bb_pre_ed_rssi; - u8 cr_201; - u8 cr_206; -}; - -static const struct vnt_threshold al2230_vnt_threshold[] = { - {0, 0x00, 0x30}, /* Max sensitivity */ - {68, 0x00, 0x36}, - {67, 0x00, 0x43}, - {66, 0x00, 0x51}, - {65, 0x00, 0x62}, - {64, 0x00, 0x79}, - {63, 0x00, 0x93}, - {62, 0x00, 0xb9}, - {61, 0x00, 0xe3}, - {60, 0x01, 0x18}, - {59, 0x01, 0x54}, - {58, 0x01, 0xa0}, - {57, 0x02, 0x20}, - {56, 0x02, 0xa0}, - {55, 0x03, 0x00}, - {53, 0x06, 0x00}, - {51, 0x09, 0x00}, - {49, 0x0e, 0x00}, - {47, 0x15, 0x00}, - {46, 0x1a, 0x00}, - {45, 0xff, 0x00} -}; - -static const struct vnt_threshold vt3226_vnt_threshold[] = { - {0, 0x00, 0x24}, /* Max sensitivity */ - {68, 0x00, 0x2d}, - {67, 0x00, 0x36}, - {66, 0x00, 0x43}, - {65, 0x00, 0x52}, - {64, 0x00, 0x68}, - {63, 0x00, 0x80}, - {62, 0x00, 0x9c}, - {61, 0x00, 0xc0}, - {60, 0x00, 0xea}, - {59, 0x01, 0x30}, - {58, 0x01, 0x70}, - {57, 0x01, 0xb0}, - {56, 0x02, 0x30}, - {55, 0x02, 0xc0}, - {53, 0x04, 0x00}, - {51, 0x07, 0x00}, - {49, 0x0a, 0x00}, - {47, 0x11, 0x00}, - {45, 0x18, 0x00}, - {43, 0x26, 0x00}, - {42, 0x36, 0x00}, - {41, 0xff, 0x00} -}; - -/* - * Description: Set Antenna mode - * - * Parameters: - * In: - * priv - Device Structure - * antenna_mode - Antenna Mode - * Out: - * none - * - * Return Value: none - * - */ -int vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode) -{ - switch (antenna_mode) { - case ANT_TXA: - case ANT_TXB: - break; - case ANT_RXA: - priv->bb_rx_conf &= 0xFC; - break; - case ANT_RXB: - priv->bb_rx_conf &= 0xFE; - priv->bb_rx_conf |= 0x02; - break; - } - - return vnt_control_out(priv, MESSAGE_TYPE_SET_ANTMD, - (u16)antenna_mode, 0, 0, NULL); -} - -/* - * Description: Set Antenna mode - * - * Parameters: - * In: - * pDevice - Device Structure - * byAntennaMode - Antenna Mode - * Out: - * none - * - * Return Value: none - * - */ - -int vnt_vt3184_init(struct vnt_private *priv) -{ - int ret; - u16 length; - u8 *addr = NULL; - const u8 *c_addr; - u8 data; - - ret = vnt_control_in(priv, MESSAGE_TYPE_READ, 0, MESSAGE_REQUEST_EEPROM, - EEP_MAX_CONTEXT_SIZE, priv->eeprom); - if (ret) - goto end; - - priv->rf_type = priv->eeprom[EEP_OFS_RFTYPE]; - - dev_dbg(&priv->usb->dev, "RF Type %d\n", priv->rf_type); - - if ((priv->rf_type == RF_AL2230) || - (priv->rf_type == RF_AL2230S)) { - priv->bb_rx_conf = vnt_vt3184_al2230[10]; - length = sizeof(vnt_vt3184_al2230); - addr = vnt_vt3184_al2230; - - priv->bb_vga[0] = 0x1c; - priv->bb_vga[1] = 0x10; - priv->bb_vga[2] = 0x0; - priv->bb_vga[3] = 0x0; - - } else if ((priv->rf_type == RF_VT3226) || - (priv->rf_type == RF_VT3226D0)) { - priv->bb_rx_conf = vnt_vt3184_vt3226d0[10]; - length = sizeof(vnt_vt3184_vt3226d0); - c_addr = vnt_vt3184_vt3226d0; - - priv->bb_vga[0] = 0x20; - priv->bb_vga[1] = 0x10; - priv->bb_vga[2] = 0x0; - priv->bb_vga[3] = 0x0; - - /* Fix VT3226 DFC system timing issue */ - ret = vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL2, - SOFTPWRCTL_RFLEOPT); - if (ret) - goto end; - } else { - goto end; - } - - if (addr) - c_addr = addr; - - ret = vnt_control_out_blocks(priv, VNT_REG_BLOCK_SIZE, - MESSAGE_REQUEST_BBREG, length, c_addr); - if (ret) - goto end; - - ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0, - MESSAGE_REQUEST_BBAGC, - sizeof(vnt_vt3184_agc), vnt_vt3184_agc); - if (ret) - goto end; - - if ((priv->rf_type == RF_VT3226) || - (priv->rf_type == RF_VT3226D0)) { - data = (priv->rf_type == RF_VT3226D0) ? 0x11 : 0x23; - - ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, - MAC_REG_ITRTMSET, data); - if (ret) - goto end; - - ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, BIT(0)); - if (ret) - goto end; - } - - ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x04, 0x7f); - if (ret) - goto end; - - ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01); - if (ret) - goto end; - - ret = vnt_rf_table_download(priv); - if (ret) - goto end; - - /* Fix for TX USB resets from vendors driver */ - ret = vnt_control_in(priv, MESSAGE_TYPE_READ, USB_REG4, - MESSAGE_REQUEST_MEM, sizeof(data), &data); - if (ret) - goto end; - - data |= 0x2; - - ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, USB_REG4, - MESSAGE_REQUEST_MEM, sizeof(data), &data); - -end: - return ret; -} - -/* - * Description: Set ShortSlotTime mode - * - * Parameters: - * In: - * priv - Device Structure - * Out: - * none - * - * Return Value: none - * - */ -int vnt_set_short_slot_time(struct vnt_private *priv) -{ - int ret = 0; - u8 bb_vga = 0; - - if (priv->short_slot_time) - priv->bb_rx_conf &= 0xdf; - else - priv->bb_rx_conf |= 0x20; - - ret = vnt_control_in_u8(priv, MESSAGE_REQUEST_BBREG, 0xe7, &bb_vga); - if (ret) - return ret; - - if (bb_vga == priv->bb_vga[0]) - priv->bb_rx_conf |= 0x20; - - return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0a, - priv->bb_rx_conf); -} - -int vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data) -{ - int ret; - - ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0xE7, data); - if (ret) - return ret; - - /* patch for 3253B0 Baseband with Cardbus module */ - if (priv->short_slot_time) - priv->bb_rx_conf &= 0xdf; /* 1101 1111 */ - else - priv->bb_rx_conf |= 0x20; /* 0010 0000 */ - - return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0a, - priv->bb_rx_conf); -} - -/* - * Description: vnt_set_deep_sleep - * - * Parameters: - * In: - * priv - Device Structure - * Out: - * none - * - * Return Value: none - * - */ -int vnt_set_deep_sleep(struct vnt_private *priv) -{ - int ret = 0; - - /* CR12 */ - ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x17); - if (ret) - return ret; - - /* CR13 */ - return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0xB9); -} - -int vnt_exit_deep_sleep(struct vnt_private *priv) -{ - int ret = 0; - - /* CR12 */ - ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0c, 0x00); - if (ret) - return ret; - - /* CR13 */ - return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0x0d, 0x01); -} - -int vnt_update_pre_ed_threshold(struct vnt_private *priv, int scanning) -{ - const struct vnt_threshold *threshold = NULL; - u8 length; - u8 cr_201, cr_206; - u8 ed_inx; - int ret; - - switch (priv->rf_type) { - case RF_AL2230: - case RF_AL2230S: - threshold = al2230_vnt_threshold; - length = ARRAY_SIZE(al2230_vnt_threshold); - break; - - case RF_VT3226: - case RF_VT3226D0: - threshold = vt3226_vnt_threshold; - length = ARRAY_SIZE(vt3226_vnt_threshold); - break; - } - - if (!threshold) - return -EINVAL; - - for (ed_inx = scanning ? 0 : length - 1; ed_inx > 0; ed_inx--) { - if (priv->bb_pre_ed_rssi <= threshold[ed_inx].bb_pre_ed_rssi) - break; - } - - cr_201 = threshold[ed_inx].cr_201; - cr_206 = threshold[ed_inx].cr_206; - - if (ed_inx == priv->bb_pre_ed_index && !scanning) - return 0; - - priv->bb_pre_ed_index = ed_inx; - - dev_dbg(&priv->usb->dev, "%s bb_pre_ed_rssi %d\n", - __func__, priv->bb_pre_ed_rssi); - - ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0xc9, cr_201); - if (ret) - return ret; - - return vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, 0xce, cr_206); -} - diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h deleted file mode 100644 index dce50a311f2438..00000000000000 --- a/drivers/staging/vt6656/baseband.h +++ /dev/null @@ -1,75 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions to access baseband - * - * Author: Jerry Chen - * - * Date: Jun. 5, 2002 - * - * Revision History: - * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. - * 08-26-2003 Kyle Hsu : Add defines of packet type and TX rate. - */ - -#ifndef __BASEBAND_H__ -#define __BASEBAND_H__ - -#include "device.h" - -#define PREAMBLE_LONG 0 -#define PREAMBLE_SHORT 1 - -/* - * Registers in the BASEBAND - */ -#define BB_MAX_CONTEXT_SIZE 256 - -#define C_SIFS_A 16 /* usec */ -#define C_SIFS_BG 10 - -#define C_EIFS 80 /* usec */ - -#define C_SLOT_SHORT 9 /* usec */ -#define C_SLOT_LONG 20 - -#define C_CWMIN_A 15 /* slot time */ -#define C_CWMIN_B 31 - -#define C_CWMAX 1023 /* slot time */ - -/* 0:11A 1:11B 2:11G */ -#define BB_TYPE_11A 0 -#define BB_TYPE_11B 1 -#define BB_TYPE_11G 2 - -/* 0:11a, 1:11b, 2:11gb (only CCK in BasicRate), 3:11ga (OFDM in BasicRate) */ -#define PK_TYPE_11A 0 -#define PK_TYPE_11B 1 -#define PK_TYPE_11GB 2 -#define PK_TYPE_11GA 3 - -#define TOP_RATE_54M 0x80000000 -#define TOP_RATE_48M 0x40000000 -#define TOP_RATE_36M 0x20000000 -#define TOP_RATE_24M 0x10000000 -#define TOP_RATE_18M 0x08000000 -#define TOP_RATE_12M 0x04000000 -#define TOP_RATE_11M 0x02000000 -#define TOP_RATE_9M 0x01000000 -#define TOP_RATE_6M 0x00800000 -#define TOP_RATE_55M 0x00400000 -#define TOP_RATE_2M 0x00200000 -#define TOP_RATE_1M 0x00100000 - -int vnt_set_short_slot_time(struct vnt_private *priv); -int vnt_set_vga_gain_offset(struct vnt_private *priv, u8 data); -int vnt_set_antenna_mode(struct vnt_private *priv, u8 antenna_mode); -int vnt_vt3184_init(struct vnt_private *priv); -int vnt_set_deep_sleep(struct vnt_private *priv); -int vnt_exit_deep_sleep(struct vnt_private *priv); -int vnt_update_pre_ed_threshold(struct vnt_private *priv, int scanning); - -#endif /* __BASEBAND_H__ */ diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c deleted file mode 100644 index b9dc0d13c00c85..00000000000000 --- a/drivers/staging/vt6656/card.c +++ /dev/null @@ -1,456 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Provide functions to setup NIC operation mode - * Functions: - * vnt_set_rspinf - Set RSPINF - * vnt_update_ifs - Update slotTime,SIFS,DIFS, and EIFS - * vnt_update_top_rates - Update BasicTopRate - * 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_next_tbtt - Calculate Next Beacon TSF counter - * vnt_reset_next_tbtt - Set NIC Beacon time - * vnt_update_next_tbtt - Sync. NIC Beacon time - * vnt_radio_power_off - Turn Off NIC Radio Power - * vnt_radio_power_on - Turn On NIC Radio Power - * - * Revision History: - * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. - * 08-26-2003 Kyle Hsu: Modify the definition type of dwIoBase. - * 09-01-2003 Bryan YC Fan: Add vnt_update_ifs(). - * - */ - -#include -#include -#include "device.h" -#include "card.h" -#include "baseband.h" -#include "mac.h" -#include "desc.h" -#include "rf.h" -#include "power.h" -#include "key.h" -#include "usbpipe.h" - -/* const u16 cw_rxbcntsf_off[MAX_RATE] = - * {17, 34, 96, 192, 34, 23, 17, 11, 8, 5, 4, 3}; - */ - -static const u16 cw_rxbcntsf_off[MAX_RATE] = { - 192, 96, 34, 17, 34, 23, 17, 11, 8, 5, 4, 3 -}; - -int vnt_set_channel(struct vnt_private *priv, u32 connection_channel) -{ - int ret; - - if (connection_channel > CB_MAX_CHANNEL || !connection_channel) - return -EINVAL; - - /* clear NAV */ - vnt_mac_reg_bits_on(priv, MAC_REG_MACCR, MACCR_CLRNAV); - - /* Set Channel[7] = 0 to tell H/W channel is changing now. */ - vnt_mac_reg_bits_off(priv, MAC_REG_CHANNEL, - (BIT(7) | BIT(5) | BIT(4))); - - ret = vnt_control_out(priv, MESSAGE_TYPE_SELECT_CHANNEL, - connection_channel, 0, 0, NULL); - if (ret) - return ret; - - return vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, MAC_REG_CHANNEL, - (u8)(connection_channel | 0x80)); -} - -static const u8 vnt_rspinf_b_short_table[] = { - 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x09, 0x00, - 0x15, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0b, 0x80 -}; - -static const u8 vnt_rspinf_b_long_table[] = { - 0x70, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0x00, - 0x15, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x03, 0x80 -}; - -static const u8 vnt_rspinf_a_table[] = { - 0x9b, 0x18, 0x9f, 0x10, 0x9a, 0x0a, 0x9e, 0x08, 0x99, - 0x08, 0x9d, 0x04, 0x98, 0x04, 0x9c, 0x04, 0x9c, 0x04 -}; - -static const u8 vnt_rspinf_gb_table[] = { - 0x8b, 0x1e, 0x8f, 0x16, 0x8a, 0x12, 0x8e, 0x0e, 0x89, - 0x0e, 0x8d, 0x0a, 0x88, 0x0a, 0x8c, 0x0a, 0x8c, 0x0a -}; - -int vnt_set_rspinf(struct vnt_private *priv, u8 bb_type) -{ - const u8 *data; - u16 len; - int ret; - - if (priv->preamble_type) { - data = vnt_rspinf_b_short_table; - len = ARRAY_SIZE(vnt_rspinf_b_short_table); - } else { - data = vnt_rspinf_b_long_table; - len = ARRAY_SIZE(vnt_rspinf_b_long_table); - } - - /* RSPINF_b_1 to RSPINF_b_11 */ - ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_RSPINF_B_1, - MESSAGE_REQUEST_MACREG, len, data); - if (ret) - return ret; - - if (bb_type == BB_TYPE_11A) { - data = vnt_rspinf_a_table; - len = ARRAY_SIZE(vnt_rspinf_a_table); - } else { - data = vnt_rspinf_gb_table; - len = ARRAY_SIZE(vnt_rspinf_gb_table); - } - - /* RSPINF_a_6 to RSPINF_a_72 */ - return vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_RSPINF_A_6, - MESSAGE_REQUEST_MACREG, len, data); -} - -int vnt_update_ifs(struct vnt_private *priv) -{ - u8 max_min = 0; - u8 data[4]; - int ret; - - if (priv->packet_type == PK_TYPE_11A) { - priv->slot = C_SLOT_SHORT; - priv->sifs = C_SIFS_A; - priv->difs = C_SIFS_A + 2 * C_SLOT_SHORT; - max_min = 4; - } else { - priv->sifs = C_SIFS_BG; - - if (priv->short_slot_time) { - priv->slot = C_SLOT_SHORT; - max_min = 4; - } else { - priv->slot = C_SLOT_LONG; - max_min = 5; - } - - priv->difs = C_SIFS_BG + 2 * priv->slot; - } - - priv->eifs = C_EIFS; - - data[0] = (u8)priv->sifs; - data[1] = (u8)priv->difs; - data[2] = (u8)priv->eifs; - data[3] = (u8)priv->slot; - - ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_SIFS, - MESSAGE_REQUEST_MACREG, 4, &data[0]); - if (ret) - return ret; - - max_min |= 0xa0; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_CWMAXMIN0, - MESSAGE_REQUEST_MACREG, 1, &max_min); -} - -void vnt_update_top_rates(struct vnt_private *priv) -{ - int pos; - - pos = fls(priv->basic_rates & GENMASK(RATE_54M, RATE_6M)); - priv->top_ofdm_basic_rate = pos ? (pos - 1) : RATE_24M; - - pos = fls(priv->basic_rates & GENMASK(RATE_11M, RATE_1M)); - priv->top_cck_basic_rate = pos ? (pos - 1) : RATE_1M; -} - -bool vnt_ofdm_min_rate(struct vnt_private *priv) -{ - return priv->basic_rates & GENMASK(RATE_54M, RATE_6M) ? true : false; -} - -u8 vnt_get_pkt_type(struct vnt_private *priv) -{ - if (priv->bb_type == BB_TYPE_11A || priv->bb_type == BB_TYPE_11B) - return (u8)priv->bb_type; - else if (vnt_ofdm_min_rate(priv)) - return PK_TYPE_11GA; - return PK_TYPE_11GB; -} - -/* - * Description: Calculate TSF offset of two TSF input - * Get TSF Offset from RxBCN's TSF and local TSF - * - * Parameters: - * In: - * rx_rate - rx rate. - * tsf1 - Rx BCN's TSF - * tsf2 - Local TSF - * Out: - * none - * - * Return Value: TSF Offset value - * - */ -u64 vnt_get_tsf_offset(u8 rx_rate, u64 tsf1, u64 tsf2) -{ - return tsf1 - tsf2 - (u64)cw_rxbcntsf_off[rx_rate % MAX_RATE]; -} - -int vnt_adjust_tsf(struct vnt_private *priv, u8 rx_rate, - u64 time_stamp, u64 local_tsf) -{ - u64 tsf_offset = 0; - u8 data[8]; - - tsf_offset = vnt_get_tsf_offset(rx_rate, time_stamp, local_tsf); - - data[0] = (u8)tsf_offset; - data[1] = (u8)(tsf_offset >> 8); - data[2] = (u8)(tsf_offset >> 16); - data[3] = (u8)(tsf_offset >> 24); - data[4] = (u8)(tsf_offset >> 32); - data[5] = (u8)(tsf_offset >> 40); - data[6] = (u8)(tsf_offset >> 48); - data[7] = (u8)(tsf_offset >> 56); - - return vnt_control_out(priv, MESSAGE_TYPE_SET_TSFTBTT, - MESSAGE_REQUEST_TSF, 0, 8, data); -} - -/* - * Description: Clear NIC TSF counter - * Clear local TSF counter - * - * Parameters: - * In: - * priv - The adapter to be read - * - * Return Value: true if success; otherwise false - * - */ -bool vnt_clear_current_tsf(struct vnt_private *priv) -{ - vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTRST); - - priv->current_tsf = 0; - - return true; -} - -/* - * Description: Read NIC TSF counter - * Get NEXTTBTT from adjusted TSF and Beacon Interval - * - * Parameters: - * In: - * tsf - Current TSF counter - * beacon_interval - Beacon Interval - * Out: - * tsf - Current TSF counter - * - * Return Value: TSF value of next Beacon - * - */ -u64 vnt_get_next_tbtt(u64 tsf, u16 beacon_interval) -{ - u32 beacon_int; - - beacon_int = beacon_interval * 1024; - - /* Next TBTT = - * ((local_current_TSF / beacon_interval) + 1) * beacon_interval - */ - if (beacon_int) { - do_div(tsf, beacon_int); - tsf += 1; - tsf *= beacon_int; - } - - return tsf; -} - -int vnt_reset_next_tbtt(struct vnt_private *priv, u16 beacon_interval) -{ - u64 next_tbtt = 0; - u8 data[8]; - - vnt_clear_current_tsf(priv); - - next_tbtt = vnt_get_next_tbtt(next_tbtt, beacon_interval); - - data[0] = (u8)next_tbtt; - data[1] = (u8)(next_tbtt >> 8); - data[2] = (u8)(next_tbtt >> 16); - data[3] = (u8)(next_tbtt >> 24); - data[4] = (u8)(next_tbtt >> 32); - data[5] = (u8)(next_tbtt >> 40); - data[6] = (u8)(next_tbtt >> 48); - data[7] = (u8)(next_tbtt >> 56); - - return vnt_control_out(priv, MESSAGE_TYPE_SET_TSFTBTT, - MESSAGE_REQUEST_TBTT, 0, 8, data); -} - -int vnt_update_next_tbtt(struct vnt_private *priv, u64 tsf, - u16 beacon_interval) -{ - u8 data[8]; - int ret; - - tsf = vnt_get_next_tbtt(tsf, beacon_interval); - - data[0] = (u8)tsf; - data[1] = (u8)(tsf >> 8); - data[2] = (u8)(tsf >> 16); - data[3] = (u8)(tsf >> 24); - data[4] = (u8)(tsf >> 32); - data[5] = (u8)(tsf >> 40); - data[6] = (u8)(tsf >> 48); - data[7] = (u8)(tsf >> 56); - - ret = vnt_control_out(priv, MESSAGE_TYPE_SET_TSFTBTT, - MESSAGE_REQUEST_TBTT, 0, 8, data); - if (ret) - return ret; - - dev_dbg(&priv->usb->dev, "%s TBTT: %8llx\n", __func__, tsf); - return 0; -} - -/* - * Description: Turn off Radio power - * - * Parameters: - * In: - * priv - The adapter to be turned off - * Out: - * none - * - * Return Value: true if success; otherwise false - * - */ -int vnt_radio_power_off(struct vnt_private *priv) -{ - int ret = 0; - - switch (priv->rf_type) { - case RF_AL2230: - case RF_AL2230S: - case RF_VT3226: - case RF_VT3226D0: - ret = vnt_mac_reg_bits_off(priv, MAC_REG_SOFTPWRCTL, - (SOFTPWRCTL_SWPE2 | - SOFTPWRCTL_SWPE3)); - break; - } - - if (ret) - goto end; - - ret = vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_RXON); - if (ret) - goto end; - - ret = vnt_set_deep_sleep(priv); - if (ret) - goto end; - - ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1, GPIO3_INTMD); - -end: - return ret; -} - -/* - * Description: Turn on Radio power - * - * Parameters: - * In: - * priv - The adapter to be turned on - * Out: - * none - * - * Return Value: true if success; otherwise false - * - */ -int vnt_radio_power_on(struct vnt_private *priv) -{ - int ret = 0; - - ret = vnt_exit_deep_sleep(priv); - if (ret) - return ret; - - ret = vnt_mac_reg_bits_on(priv, MAC_REG_HOSTCR, HOSTCR_RXON); - if (ret) - return ret; - - switch (priv->rf_type) { - case RF_AL2230: - case RF_AL2230S: - case RF_VT3226: - case RF_VT3226D0: - ret = vnt_mac_reg_bits_on(priv, MAC_REG_SOFTPWRCTL, - (SOFTPWRCTL_SWPE2 | - SOFTPWRCTL_SWPE3)); - if (ret) - return ret; - } - - return vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1, GPIO3_INTMD); -} - -int vnt_set_bss_mode(struct vnt_private *priv) -{ - int ret; - unsigned char type = priv->bb_type; - unsigned char data = 0; - unsigned char bb_vga_2_3 = 0x00; - - ret = vnt_mac_set_bb_type(priv, type); - if (ret) - return ret; - - priv->packet_type = vnt_get_pkt_type(priv); - - if (priv->bb_type == BB_TYPE_11A) { - data = 0x03; - bb_vga_2_3 = 0x10; - } else if (priv->bb_type == BB_TYPE_11B) { - data = 0x02; - } else if (priv->bb_type == BB_TYPE_11G) { - data = 0x08; - } - - if (data) { - ret = vnt_control_out_u8(priv, MESSAGE_REQUEST_BBREG, - 0x88, data); - if (ret) - return ret; - } - - ret = vnt_update_ifs(priv); - if (ret) - return ret; - - ret = vnt_set_rspinf(priv, priv->bb_type); - if (ret) - return ret; - - priv->bb_vga[2] = bb_vga_2_3; - priv->bb_vga[3] = bb_vga_2_3; - - return vnt_set_vga_gain_offset(priv, priv->bb_vga[0]); -} diff --git a/drivers/staging/vt6656/card.h b/drivers/staging/vt6656/card.h deleted file mode 100644 index eb01f7cc871f40..00000000000000 --- a/drivers/staging/vt6656/card.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Provide functions to setup NIC operation mode - * - * Author: Tevin Chen - * - * Date: May 21, 1996 - * - */ - -#ifndef __CARD_H__ -#define __CARD_H__ -#include "device.h" - -/* init card type */ - -#define CB_MAX_CHANNEL_24G 14 -#define CB_MAX_CHANNEL_5G 42 /* add channel9(5045MHz), 41==>42 */ -#define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G + CB_MAX_CHANNEL_5G) - -struct vnt_private; - -int vnt_set_channel(struct vnt_private *priv, u32 connection_channel); -int vnt_set_rspinf(struct vnt_private *priv, u8 bb_type); -int vnt_update_ifs(struct vnt_private *priv); -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_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, - u16 beacon_interval); -u64 vnt_get_next_tbtt(u64 tsf, u16 beacon_interval); -u64 vnt_get_tsf_offset(u8 rx_rate, u64 tsf1, u64 tsf2); -int vnt_radio_power_off(struct vnt_private *priv); -int vnt_radio_power_on(struct vnt_private *priv); -u8 vnt_get_pkt_type(struct vnt_private *priv); -int vnt_set_bss_mode(struct vnt_private *priv); - -#endif /* __CARD_H__ */ diff --git a/drivers/staging/vt6656/channel.c b/drivers/staging/vt6656/channel.c deleted file mode 100644 index 413e2fc4a50dca..00000000000000 --- a/drivers/staging/vt6656/channel.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Channel number mapping - * - * Author: Lucas Lin - * - * Date: Dec 24, 2004 - * - * - * - * Revision History: - * 01-18-2005 RobertYu: remove the for loop searching in - * ChannelValid, change ChannelRuleTab - * to lookup-type, reorder table items. - * - * - */ - -#include "device.h" -#include "channel.h" -#include "rf.h" - -static struct ieee80211_rate vnt_rates_bg[] = { - { .bitrate = 10, .hw_value = RATE_1M }, - { .bitrate = 20, .hw_value = RATE_2M }, - { .bitrate = 55, .hw_value = RATE_5M }, - { .bitrate = 110, .hw_value = RATE_11M }, - { .bitrate = 60, .hw_value = RATE_6M }, - { .bitrate = 90, .hw_value = RATE_9M }, - { .bitrate = 120, .hw_value = RATE_12M }, - { .bitrate = 180, .hw_value = RATE_18M }, - { .bitrate = 240, .hw_value = RATE_24M }, - { .bitrate = 360, .hw_value = RATE_36M }, - { .bitrate = 480, .hw_value = RATE_48M }, - { .bitrate = 540, .hw_value = RATE_54M }, -}; - -static struct ieee80211_channel vnt_channels_2ghz[] = { - { .center_freq = 2412, .hw_value = 1 }, - { .center_freq = 2417, .hw_value = 2 }, - { .center_freq = 2422, .hw_value = 3 }, - { .center_freq = 2427, .hw_value = 4 }, - { .center_freq = 2432, .hw_value = 5 }, - { .center_freq = 2437, .hw_value = 6 }, - { .center_freq = 2442, .hw_value = 7 }, - { .center_freq = 2447, .hw_value = 8 }, - { .center_freq = 2452, .hw_value = 9 }, - { .center_freq = 2457, .hw_value = 10 }, - { .center_freq = 2462, .hw_value = 11 }, - { .center_freq = 2467, .hw_value = 12 }, - { .center_freq = 2472, .hw_value = 13 }, - { .center_freq = 2484, .hw_value = 14 } -}; - -static struct ieee80211_supported_band vnt_supported_2ghz_band = { - .channels = vnt_channels_2ghz, - .n_channels = ARRAY_SIZE(vnt_channels_2ghz), - .bitrates = vnt_rates_bg, - .n_bitrates = ARRAY_SIZE(vnt_rates_bg), -}; - -void vnt_init_bands(struct vnt_private *priv) -{ - struct ieee80211_channel *ch; - int i; - - ch = vnt_channels_2ghz; - for (i = 0; i < ARRAY_SIZE(vnt_channels_2ghz); i++) { - ch[i].max_power = VNT_RF_MAX_POWER; - ch[i].flags = IEEE80211_CHAN_NO_HT40; - } - priv->hw->wiphy->bands[NL80211_BAND_2GHZ] = - &vnt_supported_2ghz_band; -} diff --git a/drivers/staging/vt6656/channel.h b/drivers/staging/vt6656/channel.h deleted file mode 100644 index 723660e40310a6..00000000000000 --- a/drivers/staging/vt6656/channel.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Country Regulation Rules header file - * - * Author: Lucas Lin - * - * Date: Dec 23, 2004 - * - */ - -#ifndef _CHANNEL_H_ -#define _CHANNEL_H_ - -#include "device.h" - -void vnt_init_bands(struct vnt_private *priv); - -#endif /* _CHANNEL_H_ */ diff --git a/drivers/staging/vt6656/desc.h b/drivers/staging/vt6656/desc.h deleted file mode 100644 index c13561e528db37..00000000000000 --- a/drivers/staging/vt6656/desc.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose:The header file of descriptor - * - * Revision History: - * - * Author: Tevin Chen - * - * Date: May 21, 1996 - * - */ - -#ifndef __DESC_H__ -#define __DESC_H__ - -#include -#include -#include - -/* max transmit or receive buffer size */ -#define CB_MAX_BUF_SIZE 2900U /* NOTE: must be multiple of 4 */ - -#define MAX_TOTAL_SIZE_WITH_ALL_HEADERS CB_MAX_BUF_SIZE - -#define MAX_INTERRUPT_SIZE 32 - -#define CB_MAX_RX_DESC 128 /* max # of descriptors */ -#define CB_MIN_RX_DESC 16 /* min # of RX descriptors */ -#define CB_MAX_TX_DESC 128 /* max # of descriptors */ -#define CB_MIN_TX_DESC 16 /* min # of TX descriptors */ - -/* - * bits in the RSR register - */ -#define RSR_ADDRBROAD BIT(7) -#define RSR_ADDRMULTI BIT(6) -#define RSR_ADDRUNI 0x00 -#define RSR_IVLDTYP BIT(5) /* invalid packet type */ -#define RSR_IVLDLEN BIT(4) /* invalid len (> 2312 byte) */ -#define RSR_BSSIDOK BIT(3) -#define RSR_CRCOK BIT(2) -#define RSR_BCNSSIDOK BIT(1) -#define RSR_ADDROK BIT(0) - -/* - * bits in the new RSR register - */ -#define NEWRSR_DECRYPTOK BIT(4) -#define NEWRSR_CFPIND BIT(3) -#define NEWRSR_HWUTSF BIT(2) -#define NEWRSR_BCNHITAID BIT(1) -#define NEWRSR_BCNHITAID0 BIT(0) - -/* - * bits in the TSR register - */ -#define TSR_RETRYTMO BIT(3) -#define TSR_TMO BIT(2) -#define TSR_ACKDATA BIT(1) -#define TSR_VALID BIT(0) - -#define FIFOCTL_AUTO_FB_1 0x1000 -#define FIFOCTL_AUTO_FB_0 0x0800 -#define FIFOCTL_GRPACK 0x0400 -#define FIFOCTL_11GA 0x0300 -#define FIFOCTL_11GB 0x0200 -#define FIFOCTL_11B 0x0100 -#define FIFOCTL_11A 0x0000 -#define FIFOCTL_RTS 0x0080 -#define FIFOCTL_ISDMA0 0x0040 -#define FIFOCTL_GENINT 0x0020 -#define FIFOCTL_TMOEN 0x0010 -#define FIFOCTL_LRETRY 0x0008 -#define FIFOCTL_CRCDIS 0x0004 -#define FIFOCTL_NEEDACK 0x0002 -#define FIFOCTL_LHEAD 0x0001 - -/* WMAC definition Frag Control */ -#define FRAGCTL_AES 0x0300 -#define FRAGCTL_TKIP 0x0200 -#define FRAGCTL_LEGACY 0x0100 -#define FRAGCTL_NONENCRYPT 0x0000 -#define FRAGCTL_ENDFRAG 0x0003 -#define FRAGCTL_MIDFRAG 0x0002 -#define FRAGCTL_STAFRAG 0x0001 -#define FRAGCTL_NONFRAG 0x0000 - -#endif /* __DESC_H__ */ diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h deleted file mode 100644 index ca974d61d3f443..00000000000000 --- a/drivers/staging/vt6656/device.h +++ /dev/null @@ -1,386 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: MAC Data structure - * - * Author: Tevin Chen - * - * Date: Mar 17, 1997 - * - */ - -#ifndef __DEVICE_H__ -#define __DEVICE_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef SIOCETHTOOL -#define DEVICE_ETHTOOL_IOCTL_SUPPORT -#include -#else -#undef DEVICE_ETHTOOL_IOCTL_SUPPORT -#endif - -#define RATE_1M 0 -#define RATE_2M 1 -#define RATE_5M 2 -#define RATE_11M 3 -#define RATE_6M 4 -#define RATE_9M 5 -#define RATE_12M 6 -#define RATE_18M 7 -#define RATE_24M 8 -#define RATE_36M 9 -#define RATE_48M 10 -#define RATE_54M 11 -#define RATE_AUTO 12 - -#define MAX_RATE 12 -#define VNT_B_RATES (BIT(RATE_1M) | BIT(RATE_2M) |\ - BIT(RATE_5M) | BIT(RATE_11M)) - -/* - * device specific - */ - -#include "wcmd.h" -#include "desc.h" -#include "key.h" -#include "card.h" - -#define VNT_USB_VENDOR_ID 0x160a -#define VNT_USB_PRODUCT_ID 0x3184 - -#define DEVICE_NAME "vt6656" -#define DEVICE_FULL_DRV_NAM "VIA Networking Wireless LAN USB Driver" - -#define DEVICE_VERSION "mac80211" - -#define FIRMWARE_VERSION 0x133 /* version 1.51 */ -#define FIRMWARE_NAME "vntwusb.fw" -#define FIRMWARE_CHUNK_SIZE 0x400 - -#define MAX_UINTS 8 -#define OPTION_DEFAULT { [0 ... MAX_UINTS - 1] = -1} - -#define DUPLICATE_RX_CACHE_LENGTH 5 - -#define AUTO_FB_NONE 0 -#define AUTO_FB_0 1 -#define AUTO_FB_1 2 - -#define FB_RATE0 0 -#define FB_RATE1 1 - -/* Antenna Mode */ -#define ANT_A 0 -#define ANT_B 1 -#define ANT_DIVERSITY 2 -#define ANT_RXD_TXA 3 -#define ANT_RXD_TXB 4 -#define ANT_UNKNOWN 0xFF -#define ANT_TXA 0 -#define ANT_TXB 1 -#define ANT_RXA 2 -#define ANT_RXB 3 - -#define BB_VGA_LEVEL 4 -#define BB_VGA_CHANGE_THRESHOLD 3 - -#define EEP_MAX_CONTEXT_SIZE 256 - -/* Contents in the EEPROM */ -#define EEP_OFS_PAR 0x0 -#define EEP_OFS_ANTENNA 0x17 -#define EEP_OFS_RADIOCTL 0x18 -#define EEP_OFS_RFTYPE 0x1b -#define EEP_OFS_MINCHANNEL 0x1c -#define EEP_OFS_MAXCHANNEL 0x1d -#define EEP_OFS_SIGNATURE 0x1e -#define EEP_OFS_ZONETYPE 0x1f -#define EEP_OFS_RFTABLE 0x20 -#define EEP_OFS_PWR_CCK 0x20 -#define EEP_OFS_SETPT_CCK 0x21 -#define EEP_OFS_PWR_OFDMG 0x23 - -#define EEP_OFS_CALIB_TX_IQ 0x24 -#define EEP_OFS_CALIB_TX_DC 0x25 -#define EEP_OFS_CALIB_RX_IQ 0x26 - -#define EEP_OFS_MAJOR_VER 0x2e -#define EEP_OFS_MINOR_VER 0x2f - -#define EEP_OFS_CCK_PWR_TBL 0x30 -#define EEP_OFS_OFDM_PWR_TBL 0x40 -#define EEP_OFS_OFDMA_PWR_TBL 0x50 - -/* Bits in EEP_OFS_ANTENNA */ -#define EEP_ANTENNA_MAIN BIT(0) -#define EEP_ANTENNA_AUX BIT(1) -#define EEP_ANTINV BIT(2) - -/* Bits in EEP_OFS_RADIOCTL */ -#define EEP_RADIOCTL_ENABLE BIT(7) - -/* control commands */ -#define MESSAGE_TYPE_READ 0x1 -#define MESSAGE_TYPE_WRITE 0x0 -#define MESSAGE_TYPE_LOCK_OR 0x2 -#define MESSAGE_TYPE_LOCK_AND 0x3 -#define MESSAGE_TYPE_WRITE_MASK 0x4 -#define MESSAGE_TYPE_CARDINIT 0x5 -#define MESSAGE_TYPE_INIT_RSP 0x6 -#define MESSAGE_TYPE_MACSHUTDOWN 0x7 -#define MESSAGE_TYPE_SETKEY 0x8 -#define MESSAGE_TYPE_CLRKEYENTRY 0x9 -#define MESSAGE_TYPE_WRITE_MISCFF 0xa -#define MESSAGE_TYPE_SET_ANTMD 0xb -#define MESSAGE_TYPE_SELECT_CHANNEL 0xc -#define MESSAGE_TYPE_SET_TSFTBTT 0xd -#define MESSAGE_TYPE_SET_SSTIFS 0xe -#define MESSAGE_TYPE_CHANGE_BBTYPE 0xf -#define MESSAGE_TYPE_DISABLE_PS 0x10 -#define MESSAGE_TYPE_WRITE_IFRF 0x11 - -/* command read/write(index) */ -#define MESSAGE_REQUEST_MEM 0x1 -#define MESSAGE_REQUEST_BBREG 0x2 -#define MESSAGE_REQUEST_MACREG 0x3 -#define MESSAGE_REQUEST_EEPROM 0x4 -#define MESSAGE_REQUEST_TSF 0x5 -#define MESSAGE_REQUEST_TBTT 0x6 -#define MESSAGE_REQUEST_BBAGC 0x7 -#define MESSAGE_REQUEST_VERSION 0x8 -#define MESSAGE_REQUEST_RF_INIT 0x9 -#define MESSAGE_REQUEST_RF_INIT2 0xa -#define MESSAGE_REQUEST_RF_CH0 0xb -#define MESSAGE_REQUEST_RF_CH1 0xc -#define MESSAGE_REQUEST_RF_CH2 0xd - -/* USB registers */ -#define USB_REG4 0x604 - -#define DEVICE_INIT_COLD 0x0 /* cold init */ -#define DEVICE_INIT_RESET 0x1 /* reset init or Dx to D0 power remain */ -#define DEVICE_INIT_DXPL 0x2 /* Dx to D0 power lost init */ - -/* Device init */ -struct vnt_cmd_card_init { - u8 init_class; - u8 exist_sw_net_addr; - u8 sw_net_addr[6]; - u8 short_retry_limit; - u8 long_retry_limit; -}; - -struct vnt_rsp_card_init { - u8 status; - u8 net_addr[6]; - u8 rf_type; - u8 min_channel; - u8 max_channel; -}; - -/* USB */ - -/* - * Enum of context types for SendPacket - */ -enum { - CONTEXT_DATA_PACKET = 0, - CONTEXT_BEACON_PACKET -}; - -struct vnt_rx_header { - u32 wbk_status; - u8 rx_sts; - u8 rx_rate; - u16 pay_load_len; -} __packed; - -struct vnt_rx_tail { - __le64 tsf_time; - u8 sq; - u8 new_rsr; - u8 rssi; - u8 rsr; - u8 sq_3; -} __packed; - -/* RCB (Receive Control Block) */ -struct vnt_rcb { - void *priv; - struct urb *urb; - struct sk_buff *skb; -}; - -/* used to track bulk out irps */ -struct vnt_usb_send_context { - void *priv; - struct sk_buff *skb; - void *tx_buffer; - u32 frame_len; - u16 tx_hdr_size; - u16 tx_rate; - u8 type; - u8 pkt_no; - u8 pkt_type; - bool in_use; -}; - -/* - * Structure to keep track of USB interrupt packets - */ -struct vnt_interrupt_buffer { - u8 *data_buf; -}; - -/* flags for options */ -#define DEVICE_FLAGS_UNPLUG 0 -#define DEVICE_FLAGS_DISCONNECTED 1 - -struct vnt_private { - /* mac80211 */ - struct ieee80211_hw *hw; - struct ieee80211_vif *vif; - u8 mac_hw; - /* netdev */ - struct usb_device *usb; - struct usb_interface *intf; - - u64 tsf_time; - - u32 rx_buf_sz; - int mc_list_count; - - spinlock_t lock; /* prepare tx USB URB */ - struct mutex usb_lock; /* USB control messages */ - - unsigned long flags; - - /* USB */ - struct urb *interrupt_urb; - u32 int_interval; - - /* Variables to track resources for the BULK In Pipe */ - struct vnt_rcb *rcb[CB_MAX_RX_DESC]; - u32 num_rcb; - - /* Variables to track resources for the BULK Out Pipe */ - struct vnt_usb_send_context *tx_context[CB_MAX_TX_DESC]; - struct usb_anchor tx_submitted; - u32 num_tx_context; - - /* Variables to track resources for the Interrupt In Pipe */ - struct vnt_interrupt_buffer int_buf; - - /* Version control */ - u16 firmware_version; - u8 local_id; - u8 rf_type; - u8 bb_rx_conf; - - struct vnt_cmd_card_init init_command; - struct vnt_rsp_card_init init_response; - u8 current_net_addr[ETH_ALEN] __aligned(2); - u8 permanent_net_addr[ETH_ALEN] __aligned(2); - - u8 exist_sw_net_addr; - - u64 current_tsf; - - /* 802.11 MAC specific */ - u32 current_rssi; - - /* Antenna Diversity */ - int tx_rx_ant_inv; - u32 rx_antenna_sel; - u8 rx_antenna_mode; - u8 tx_antenna_mode; - u8 radio_ctl; - - /* IFS & Cw */ - u32 sifs; /* Current SIFS */ - u32 difs; /* Current DIFS */ - u32 eifs; /* Current EIFS */ - u32 slot; /* Current SlotTime */ - - /* Rate */ - u8 bb_type; /* 0: 11A, 1:11B, 2:11G */ - u8 packet_type; /* 0:11a 1:11b 2:11gb 3:11ga */ - u32 basic_rates; - u8 top_ofdm_basic_rate; - u8 top_cck_basic_rate; - - u8 eeprom[EEP_MAX_CONTEXT_SIZE]; /*u32 alignment */ - - u8 preamble_type; - - /* For RF Power table */ - u8 cck_pwr; - u8 ofdm_pwr_g; - u8 ofdm_pwr_a; - u8 power; - u8 cck_pwr_tbl[14]; - u8 ofdm_pwr_tbl[14]; - u8 ofdm_a_pwr_tbl[42]; - - u16 tx_rate_fb0; - u16 tx_rate_fb1; - - enum nl80211_iftype op_mode; - - int short_slot_time; - - /* Power save */ - u16 current_aid; - - /* Beacon related */ - u16 seq_counter; - - enum vnt_cmd_state command_state; - - enum vnt_cmd command; - - /* 802.11 counter */ - - enum vnt_cmd cmd_queue[CMD_Q_SIZE]; - u32 cmd_dequeue_idx; - u32 cmd_enqueue_idx; - u32 free_cmd_queue; - int cmd_running; - - unsigned long key_entry_inuse; - - u8 auto_fb_ctrl; - - /* For Update BaseBand VGA Gain Offset */ - u8 bb_vga[BB_VGA_LEVEL]; - - u8 bb_pre_ed_rssi; - u8 bb_pre_ed_index; - - /* command timer */ - struct delayed_work run_command_work; - - struct ieee80211_low_level_stats low_stats; -}; - -int vnt_init(struct vnt_private *priv); - -#endif diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c deleted file mode 100644 index bdc5f30c4f9d29..00000000000000 --- a/drivers/staging/vt6656/key.c +++ /dev/null @@ -1,142 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions for 802.11i Key management - * - * Author: Jerry Chen - * - * Date: May 29, 2003 - * - * Functions: - * - * Revision History: - * - */ - -#include "mac.h" -#include "key.h" -#include "usbpipe.h" - -int vnt_key_init_table(struct vnt_private *priv) -{ - u8 i; - u8 data[MAX_KEY_TABLE]; - - for (i = 0; i < MAX_KEY_TABLE; i++) - data[i] = i; - - return vnt_control_out(priv, MESSAGE_TYPE_CLRKEYENTRY, - 0, 0, ARRAY_SIZE(data), data); -} - -static int vnt_set_keymode(struct ieee80211_hw *hw, u8 *mac_addr, - struct ieee80211_key_conf *key, u32 key_type, - u32 mode) -{ - struct vnt_private *priv = hw->priv; - u8 broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - u16 key_mode = 0; - u32 entry = 0; - u8 *bssid; - u8 key_inx = key->keyidx; - u8 i; - - if (mac_addr) - bssid = mac_addr; - else - bssid = &broadcast[0]; - - if (key_type != VNT_KEY_DEFAULTKEY) { - for (i = 0; i < (MAX_KEY_TABLE - 1); i++) { - if (!test_bit(i, &priv->key_entry_inuse)) { - set_bit(i, &priv->key_entry_inuse); - - key->hw_key_idx = i; - entry = key->hw_key_idx; - break; - } - } - } - - switch (key_type) { - case VNT_KEY_DEFAULTKEY: - /* default key last entry */ - entry = MAX_KEY_TABLE - 1; - key->hw_key_idx = entry; - fallthrough; - case VNT_KEY_GROUP_ADDRESS: - key_mode = mode | (mode << 4); - break; - case VNT_KEY_GROUP: - key_mode = mode << 4; - break; - case VNT_KEY_PAIRWISE: - key_mode |= mode; - key_inx = 4; - break; - default: - return -EINVAL; - } - - key_mode |= key_type; - - if (mode == KEY_CTL_WEP) { - if (key->keylen == WLAN_KEY_LEN_WEP40) - key->key[15] &= 0x7f; - if (key->keylen == WLAN_KEY_LEN_WEP104) - key->key[15] |= 0x80; - } - - return vnt_mac_set_keyentry(priv, key_mode, entry, - key_inx, bssid, key->key); -} - -int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, struct ieee80211_key_conf *key) -{ - struct vnt_private *priv = hw->priv; - u8 *mac_addr = NULL; - u8 key_dec_mode = 0; - - if (sta) - mac_addr = &sta->addr[0]; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY, - KEY_CTL_WEP); - - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - - return vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY, - KEY_CTL_WEP); - - case WLAN_CIPHER_SUITE_TKIP: - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - - key_dec_mode = KEY_CTL_TKIP; - - break; - case WLAN_CIPHER_SUITE_CCMP: - if (priv->local_id <= MAC_REVISION_A1) - return -EOPNOTSUPP; - - key_dec_mode = KEY_CTL_CCMP; - - key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - break; - default: - return -EOPNOTSUPP; - } - - if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) - return vnt_set_keymode(hw, mac_addr, key, VNT_KEY_PAIRWISE, - key_dec_mode); - - return vnt_set_keymode(hw, mac_addr, key, - VNT_KEY_GROUP_ADDRESS, key_dec_mode); -} diff --git a/drivers/staging/vt6656/key.h b/drivers/staging/vt6656/key.h deleted file mode 100644 index 6f1d5b4f6da789..00000000000000 --- a/drivers/staging/vt6656/key.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Implement functions for 802.11i Key management - * - * Author: Jerry Chen - * - * Date: May 29, 2003 - * - */ - -#ifndef __KEY_H__ -#define __KEY_H__ - -#include "device.h" - -#define MAX_KEY_TABLE 11 - -#define KEY_CTL_WEP 0x00 -#define KEY_CTL_NONE 0x01 -#define KEY_CTL_TKIP 0x02 -#define KEY_CTL_CCMP 0x03 - -#define VNT_KEY_ONFLY_ALL 0x4000 -#define VNT_KEY_ONFLY 0x8000 -#define VNT_KEY_ALLGROUP 0x04 -#define VNT_KEY_GROUP 0x40 -#define VNT_KEY_PAIRWISE VNT_KEY_ONFLY -#define VNT_KEY_GROUP_ADDRESS (VNT_KEY_ALLGROUP | VNT_KEY_GROUP) -#define VNT_KEY_DEFAULTKEY (VNT_KEY_GROUP_ADDRESS | VNT_KEY_ONFLY |\ - VNT_KEY_ONFLY_ALL) - -int vnt_key_init_table(struct vnt_private *priv); - -int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta, - struct ieee80211_vif *vif, struct ieee80211_key_conf *key); - -#endif /* __KEY_H__ */ diff --git a/drivers/staging/vt6656/mac.c b/drivers/staging/vt6656/mac.c deleted file mode 100644 index 49430c0a99b8dd..00000000000000 --- a/drivers/staging/vt6656/mac.c +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: MAC routines - * - * Author: Tevin Chen - * - * Date: May 21, 1996 - * - * Functions: - * - * Revision History: - */ - -#include - -#include "desc.h" -#include "mac.h" -#include "usbpipe.h" - -int vnt_mac_set_filter(struct vnt_private *priv, u64 mc_filter) -{ - __le64 le_mc = cpu_to_le64(mc_filter); - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_MAR0, - MESSAGE_REQUEST_MACREG, sizeof(le_mc), - (u8 *)&le_mc); -} - -int vnt_mac_shutdown(struct vnt_private *priv) -{ - return vnt_control_out(priv, MESSAGE_TYPE_MACSHUTDOWN, 0, 0, 0, NULL); -} - -int vnt_mac_set_bb_type(struct vnt_private *priv, u8 type) -{ - u8 data[2]; - - data[0] = type; - data[1] = EN_CFG_BB_TYPE_MASK; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG0, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), - data); -} - -int vnt_mac_disable_keyentry(struct vnt_private *priv, u8 entry_idx) -{ - return vnt_control_out(priv, MESSAGE_TYPE_CLRKEYENTRY, 0, 0, - sizeof(entry_idx), &entry_idx); -} - -int vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx, - u32 key_idx, u8 *addr, u8 *key) -{ - struct vnt_mac_set_key set_key; - u16 offset; - - offset = MISCFIFO_KEYETRY0; - offset += entry_idx * MISCFIFO_KEYENTRYSIZE; - - set_key.u.write.key_ctl = cpu_to_le16(key_ctl); - ether_addr_copy(set_key.u.write.addr, addr); - - /* swap over swap[0] and swap[1] to get correct write order */ - swap(set_key.u.swap[0], set_key.u.swap[1]); - - memcpy(set_key.key, key, WLAN_KEY_LEN_CCMP); - - dev_dbg(&priv->usb->dev, "offset %d key ctl %d set key %24ph\n", - offset, key_ctl, (u8 *)&set_key); - - return vnt_control_out(priv, MESSAGE_TYPE_SETKEY, offset, - (u16)key_idx, sizeof(struct vnt_mac_set_key), - (u8 *)&set_key); -} - -int vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits) -{ - u8 data[2]; - - data[0] = 0; - data[1] = bits; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} - -int vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits) -{ - u8 data[2]; - - data[0] = bits; - data[1] = bits; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} - -int vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word) -{ - u8 data[2]; - - data[0] = (u8)(word & 0xff); - data[1] = (u8)(word >> 8); - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE, reg_ofs, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} - -int vnt_mac_set_bssid_addr(struct vnt_private *priv, u8 *addr) -{ - return vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_BSSID0, - MESSAGE_REQUEST_MACREG, ETH_ALEN, addr); -} - -int vnt_mac_enable_protect_mode(struct vnt_private *priv) -{ - u8 data[2]; - - data[0] = EN_CFG_PROTECT_MD; - data[1] = EN_CFG_PROTECT_MD; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG0, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} - -int vnt_mac_disable_protect_mode(struct vnt_private *priv) -{ - u8 data[2]; - - data[0] = 0; - data[1] = EN_CFG_PROTECT_MD; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG0, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} - -int vnt_mac_enable_barker_preamble_mode(struct vnt_private *priv) -{ - u8 data[2]; - - data[0] = EN_CFG_BARKER_PREAM; - data[1] = EN_CFG_BARKER_PREAM; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG2, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} - -int vnt_mac_disable_barker_preamble_mode(struct vnt_private *priv) -{ - u8 data[2]; - - data[0] = 0; - data[1] = EN_CFG_BARKER_PREAM; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG2, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} - -int vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval) -{ - u8 data[2]; - - data[0] = (u8)(interval & 0xff); - data[1] = (u8)(interval >> 8); - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_BI, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} - -int vnt_mac_set_led(struct vnt_private *priv, u8 state, u8 led) -{ - u8 data[2]; - - data[0] = led; - data[1] = state; - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_PAPEDELAY, - MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data); -} diff --git a/drivers/staging/vt6656/mac.h b/drivers/staging/vt6656/mac.h deleted file mode 100644 index 0ac845bd3c5ad8..00000000000000 --- a/drivers/staging/vt6656/mac.h +++ /dev/null @@ -1,373 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: MAC routines - * - * Author: Tevin Chen - * - * Date: May 21, 1996 - * - * Revision History: - * 07-01-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. - * 08-25-2003 Kyle Hsu: Porting MAC functions from sim53. - * 09-03-2003 Bryan YC Fan: Add MACvDisableProtectMD & MACvEnableProtectMD - */ - -#ifndef __MAC_H__ -#define __MAC_H__ - -#include -#include "device.h" - -#define REV_ID_VT3253_A0 0x00 -#define REV_ID_VT3253_A1 0x01 -#define REV_ID_VT3253_B0 0x08 -#define REV_ID_VT3253_B1 0x09 - -/* Registers in the MAC */ -#define MAC_REG_BISTCMD 0x04 -#define MAC_REG_BISTSR0 0x05 -#define MAC_REG_BISTSR1 0x06 -#define MAC_REG_BISTSR2 0x07 -#define MAC_REG_I2MCSR 0x08 -#define MAC_REG_I2MTGID 0x09 -#define MAC_REG_I2MTGAD 0x0a -#define MAC_REG_I2MCFG 0x0b -#define MAC_REG_I2MDIPT 0x0c -#define MAC_REG_I2MDOPT 0x0e -#define MAC_REG_USBSUS 0x0f - -#define MAC_REG_LOCALID 0x14 -#define MAC_REG_TESTCFG 0x15 -#define MAC_REG_JUMPER0 0x16 -#define MAC_REG_JUMPER1 0x17 -#define MAC_REG_TMCTL 0x18 -#define MAC_REG_TMDATA0 0x1c -#define MAC_REG_TMDATA1 0x1d -#define MAC_REG_TMDATA2 0x1e -#define MAC_REG_TMDATA3 0x1f - -/* MAC Parameter related */ -#define MAC_REG_LRT 0x20 -#define MAC_REG_SRT 0x21 -#define MAC_REG_SIFS 0x22 -#define MAC_REG_DIFS 0x23 -#define MAC_REG_EIFS 0x24 -#define MAC_REG_SLOT 0x25 -#define MAC_REG_BI 0x26 -#define MAC_REG_CWMAXMIN0 0x28 -#define MAC_REG_LINKOFFTOTM 0x2a -#define MAC_REG_SWTMOT 0x2b -#define MAC_REG_RTSOKCNT 0x2c -#define MAC_REG_RTSFAILCNT 0x2d -#define MAC_REG_ACKFAILCNT 0x2e -#define MAC_REG_FCSERRCNT 0x2f - -/* TSF Related */ -#define MAC_REG_TSFCNTR 0x30 -#define MAC_REG_NEXTTBTT 0x38 -#define MAC_REG_TSFOFST 0x40 -#define MAC_REG_TFTCTL 0x48 - -/* WMAC Control/Status Related */ -#define MAC_REG_ENCFG0 0x4c -#define MAC_REG_ENCFG1 0x4d -#define MAC_REG_ENCFG2 0x4e - -#define MAC_REG_CFG 0x50 -#define MAC_REG_TEST 0x52 -#define MAC_REG_HOSTCR 0x54 -#define MAC_REG_MACCR 0x55 -#define MAC_REG_RCR 0x56 -#define MAC_REG_TCR 0x57 -#define MAC_REG_IMR 0x58 -#define MAC_REG_ISR 0x5c -#define MAC_REG_ISR1 0x5d - -/* Power Saving Related */ -#define MAC_REG_PSCFG 0x60 -#define MAC_REG_PSCTL 0x61 -#define MAC_REG_PSPWRSIG 0x62 -#define MAC_REG_BBCR13 0x63 -#define MAC_REG_AIDATIM 0x64 -#define MAC_REG_PWBT 0x66 -#define MAC_REG_WAKEOKTMR 0x68 -#define MAC_REG_CALTMR 0x69 -#define MAC_REG_SYNSPACCNT 0x6a -#define MAC_REG_WAKSYNOPT 0x6b - -/* Baseband/IF Control Group */ -#define MAC_REG_BBREGCTL 0x6c -#define MAC_REG_CHANNEL 0x6d -#define MAC_REG_BBREGADR 0x6e -#define MAC_REG_BBREGDATA 0x6f -#define MAC_REG_IFREGCTL 0x70 -#define MAC_REG_IFDATA 0x71 -#define MAC_REG_ITRTMSET 0x74 -#define MAC_REG_PAPEDELAY 0x77 -#define MAC_REG_SOFTPWRCTL 0x78 -#define MAC_REG_SOFTPWRCTL2 0x79 -#define MAC_REG_GPIOCTL0 0x7a -#define MAC_REG_GPIOCTL1 0x7b - -/* MiscFF PIO related */ -#define MAC_REG_MISCFFNDEX 0xbc -#define MAC_REG_MISCFFCTL 0xbe -#define MAC_REG_MISCFFDATA 0xc0 - -/* MAC Configuration Group */ -#define MAC_REG_PAR0 0xc4 -#define MAC_REG_PAR4 0xc8 -#define MAC_REG_BSSID0 0xcc -#define MAC_REG_BSSID4 0xd0 -#define MAC_REG_MAR0 0xd4 -#define MAC_REG_MAR4 0xd8 - -/* MAC RSPPKT INFO Group */ -#define MAC_REG_RSPINF_B_1 0xdC -#define MAC_REG_RSPINF_B_2 0xe0 -#define MAC_REG_RSPINF_B_5 0xe4 -#define MAC_REG_RSPINF_B_11 0xe8 -#define MAC_REG_RSPINF_A_6 0xec -#define MAC_REG_RSPINF_A_9 0xee -#define MAC_REG_RSPINF_A_12 0xf0 -#define MAC_REG_RSPINF_A_18 0xf2 -#define MAC_REG_RSPINF_A_24 0xf4 -#define MAC_REG_RSPINF_A_36 0xf6 -#define MAC_REG_RSPINF_A_48 0xf8 -#define MAC_REG_RSPINF_A_54 0xfa -#define MAC_REG_RSPINF_A_72 0xfc - -/* Bits in the I2MCFG EEPROM register */ -#define I2MCFG_BOUNDCTL BIT(7) -#define I2MCFG_WAITCTL BIT(5) -#define I2MCFG_SCLOECTL BIT(4) -#define I2MCFG_WBUSYCTL BIT(3) -#define I2MCFG_NORETRY BIT(2) -#define I2MCFG_I2MLDSEQ BIT(1) -#define I2MCFG_I2CMFAST BIT(0) - -/* Bits in the I2MCSR EEPROM register */ -#define I2MCSR_EEMW BIT(7) -#define I2MCSR_EEMR BIT(6) -#define I2MCSR_AUTOLD BIT(3) -#define I2MCSR_NACK BIT(1) -#define I2MCSR_DONE BIT(0) - -/* Bits in the TMCTL register */ -#define TMCTL_TSUSP BIT(2) -#define TMCTL_TMD BIT(1) -#define TMCTL_TE BIT(0) - -/* Bits in the TFTCTL register */ -#define TFTCTL_HWUTSF BIT(7) -#define TFTCTL_TBTTSYNC BIT(6) -#define TFTCTL_HWUTSFEN BIT(5) -#define TFTCTL_TSFCNTRRD BIT(4) -#define TFTCTL_TBTTSYNCEN BIT(3) -#define TFTCTL_TSFSYNCEN BIT(2) -#define TFTCTL_TSFCNTRST BIT(1) -#define TFTCTL_TSFCNTREN BIT(0) - -/* Bits in the EnhanceCFG_0 register */ -#define EN_CFG_BB_TYPE_A 0x00 -#define EN_CFG_BB_TYPE_B BIT(0) -#define EN_CFG_BB_TYPE_G BIT(1) -#define EN_CFG_BB_TYPE_MASK (EN_CFG_BB_TYPE_B | EN_CFG_BB_TYPE_G) -#define EN_CFG_PROTECT_MD BIT(5) - -/* Bits in the EnhanceCFG_1 register */ -#define EN_CFG_BCN_SUS_IND BIT(0) -#define EN_CFG_BCN_SUS_CLR BIT(1) - -/* Bits in the EnhanceCFG_2 register */ -#define EN_CFG_NXTBTTCFPSTR BIT(0) -#define EN_CFG_BARKER_PREAM BIT(1) -#define EN_CFG_PKT_BURST_MD BIT(2) - -/* Bits in the CFG register */ -#define CFG_TKIPOPT BIT(7) -#define CFG_RXDMAOPT BIT(6) -#define CFG_TMOT_SW BIT(5) -#define CFG_TMOT_HWLONG BIT(4) -#define CFG_TMOT_HW 0x00 -#define CFG_CFPENDOPT BIT(3) -#define CFG_BCNSUSEN BIT(2) -#define CFG_NOTXTIMEOUT BIT(1) -#define CFG_NOBUFOPT BIT(0) - -/* Bits in the TEST register */ -#define TEST_LBEXT BIT(7) -#define TEST_LBINT BIT(6) -#define TEST_LBNONE 0x00 -#define TEST_SOFTINT BIT(5) -#define TEST_CONTTX BIT(4) -#define TEST_TXPE BIT(3) -#define TEST_NAVDIS BIT(2) -#define TEST_NOCTS BIT(1) -#define TEST_NOACK BIT(0) - -/* Bits in the HOSTCR register */ -#define HOSTCR_TXONST BIT(7) -#define HOSTCR_RXONST BIT(6) -#define HOSTCR_ADHOC BIT(5) -#define HOSTCR_AP BIT(4) -#define HOSTCR_TXON BIT(3) -#define HOSTCR_RXON BIT(2) -#define HOSTCR_MACEN BIT(1) -#define HOSTCR_SOFTRST BIT(0) - -/* Bits in the MACCR register */ -#define MACCR_SYNCFLUSHOK BIT(2) -#define MACCR_SYNCFLUSH BIT(1) -#define MACCR_CLRNAV BIT(0) - -/* Bits in the RCR register */ -#define RCR_SSID BIT(7) -#define RCR_RXALLTYPE BIT(6) -#define RCR_UNICAST BIT(5) -#define RCR_BROADCAST BIT(4) -#define RCR_MULTICAST BIT(3) -#define RCR_WPAERR BIT(2) -#define RCR_ERRCRC BIT(1) -#define RCR_BSSID BIT(0) - -/* Bits in the TCR register */ -#define TCR_SYNCDCFOPT BIT(1) -#define TCR_AUTOBCNTX BIT(0) - -/* ISR1 */ -#define ISR_GPIO3 BIT(6) -#define ISR_RXNOBUF BIT(3) -#define ISR_MIBNEARFULL BIT(2) -#define ISR_SOFTINT BIT(1) -#define ISR_FETALERR BIT(0) - -#define LEDSTS_STS 0x06 -#define LEDSTS_TMLEN 0x78 -#define LEDSTS_OFF 0x00 -#define LEDSTS_ON 0x02 -#define LEDSTS_SLOW 0x04 -#define LEDSTS_INTER 0x06 - -/* ISR0 */ -#define ISR_WATCHDOG BIT(7) -#define ISR_SOFTTIMER BIT(6) -#define ISR_GPIO0 BIT(5) -#define ISR_TBTT BIT(4) -#define ISR_RXDMA0 BIT(3) -#define ISR_BNTX BIT(2) -#define ISR_ACTX BIT(0) - -/* Bits in the PSCFG register */ -#define PSCFG_PHILIPMD BIT(6) -#define PSCFG_WAKECALEN BIT(5) -#define PSCFG_WAKETMREN BIT(4) -#define PSCFG_BBPSPROG BIT(3) -#define PSCFG_WAKESYN BIT(2) -#define PSCFG_SLEEPSYN BIT(1) -#define PSCFG_AUTOSLEEP BIT(0) - -/* Bits in the PSCTL register */ -#define PSCTL_WAKEDONE BIT(5) -#define PSCTL_PS BIT(4) -#define PSCTL_GO2DOZE BIT(3) -#define PSCTL_LNBCN BIT(2) -#define PSCTL_ALBCN BIT(1) -#define PSCTL_PSEN BIT(0) - -/* Bits in the PSPWSIG register */ -#define PSSIG_WPE3 BIT(7) -#define PSSIG_WPE2 BIT(6) -#define PSSIG_WPE1 BIT(5) -#define PSSIG_WRADIOPE BIT(4) -#define PSSIG_SPE3 BIT(3) -#define PSSIG_SPE2 BIT(2) -#define PSSIG_SPE1 BIT(1) -#define PSSIG_SRADIOPE BIT(0) - -/* Bits in the BBREGCTL register */ -#define BBREGCTL_DONE BIT(2) -#define BBREGCTL_REGR BIT(1) -#define BBREGCTL_REGW BIT(0) - -/* Bits in the IFREGCTL register */ -#define IFREGCTL_DONE BIT(2) -#define IFREGCTL_IFRF BIT(1) -#define IFREGCTL_REGW BIT(0) - -/* Bits in the SOFTPWRCTL register */ -#define SOFTPWRCTL_RFLEOPT BIT(3) -#define SOFTPWRCTL_TXPEINV BIT(1) -#define SOFTPWRCTL_SWPECTI BIT(0) -#define SOFTPWRCTL_SWPAPE BIT(5) -#define SOFTPWRCTL_SWCALEN BIT(4) -#define SOFTPWRCTL_SWRADIO_PE BIT(3) -#define SOFTPWRCTL_SWPE2 BIT(2) -#define SOFTPWRCTL_SWPE1 BIT(1) -#define SOFTPWRCTL_SWPE3 BIT(0) - -/* Bits in the GPIOCTL1 register */ -#define GPIO3_MD BIT(5) -#define GPIO3_DATA BIT(6) -#define GPIO3_INTMD BIT(7) - -/* Bits in the MISCFFCTL register */ -#define MISCFFCTL_WRITE BIT(0) - -/* Loopback mode */ -#define MAC_LB_EXT BIT(1) -#define MAC_LB_INTERNAL BIT(0) -#define MAC_LB_NONE 0x00 - -/* Ethernet address filter type */ -#define PKT_TYPE_NONE 0x00 /* turn off receiver */ -#define PKT_TYPE_ALL_MULTICAST BIT(7) -#define PKT_TYPE_PROMISCUOUS BIT(6) -#define PKT_TYPE_DIRECTED BIT(5) /* obselete */ -#define PKT_TYPE_BROADCAST BIT(4) -#define PKT_TYPE_MULTICAST BIT(3) -#define PKT_TYPE_ERROR_WPA BIT(2) -#define PKT_TYPE_ERROR_CRC BIT(1) -#define PKT_TYPE_BSSID BIT(0) - -#define DEFAULT_BI 0x200 - -/* MiscFIFO Offset */ -#define MISCFIFO_KEYETRY0 32 -#define MISCFIFO_KEYENTRYSIZE 22 - -#define MAC_REVISION_A0 0x00 -#define MAC_REVISION_A1 0x01 - -struct vnt_mac_set_key { - union { - struct { - u8 addr[ETH_ALEN]; - __le16 key_ctl; - } write __packed; - u32 swap[2]; - } u; - u8 key[WLAN_KEY_LEN_CCMP]; -} __packed; - -int vnt_mac_set_filter(struct vnt_private *priv, u64 mc_filter); -int vnt_mac_shutdown(struct vnt_private *priv); -int vnt_mac_set_bb_type(struct vnt_private *priv, u8 type); -int vnt_mac_disable_keyentry(struct vnt_private *priv, u8 entry_idx); -int vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx, - u32 key_idx, u8 *addr, u8 *key); -int vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits); -int vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits); -int vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word); -int vnt_mac_set_bssid_addr(struct vnt_private *priv, u8 *addr); -int vnt_mac_enable_protect_mode(struct vnt_private *priv); -int vnt_mac_disable_protect_mode(struct vnt_private *priv); -int vnt_mac_enable_barker_preamble_mode(struct vnt_private *priv); -int vnt_mac_disable_barker_preamble_mode(struct vnt_private *priv); -int vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval); -int vnt_mac_set_led(struct vnt_private *privpriv, u8 state, u8 led); - -#endif /* __MAC_H__ */ diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c deleted file mode 100644 index 4f09e733e7a81e..00000000000000 --- a/drivers/staging/vt6656/main_usb.c +++ /dev/null @@ -1,1121 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: driver entry for initial, open, close, tx and rx. - * - * Author: Lyndon Chen - * - * Date: Dec 8, 2005 - * - * Functions: - * - * vt6656_probe - module initial (insmod) driver entry - * vnt_free_tx_bufs - free tx buffer function - * vnt_init_registers- initial MAC & BBP & RF internal registers. - * - * Revision History: - */ -#undef __NO_VERSION__ - -#include -#include -#include -#include -#include "device.h" -#include "card.h" -#include "baseband.h" -#include "mac.h" -#include "power.h" -#include "wcmd.h" -#include "rxtx.h" -#include "rf.h" -#include "usbpipe.h" -#include "channel.h" - -/* - * define module options - */ - -/* version information */ -#define DRIVER_AUTHOR \ - "VIA Networking Technologies, Inc., " -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(DEVICE_FULL_DRV_NAM); - -#define RX_DESC_DEF0 64 -static int vnt_rx_buffers = RX_DESC_DEF0; -module_param_named(rx_buffers, vnt_rx_buffers, int, 0644); -MODULE_PARM_DESC(rx_buffers, "Number of receive usb rx buffers"); - -#define TX_DESC_DEF0 64 -static int vnt_tx_buffers = TX_DESC_DEF0; -module_param_named(tx_buffers, vnt_tx_buffers, int, 0644); -MODULE_PARM_DESC(tx_buffers, "Number of receive usb tx buffers"); - -#define RTS_THRESH_DEF 2347 -#define FRAG_THRESH_DEF 2346 - -/* BasebandType[] baseband type selected - * 0: indicate 802.11a type - * 1: indicate 802.11b type - * 2: indicate 802.11g type - */ - -#define BBP_TYPE_DEF 2 - -/* - * Static vars definitions - */ - -static const struct usb_device_id vt6656_table[] = { - {USB_DEVICE(VNT_USB_VENDOR_ID, VNT_USB_PRODUCT_ID)}, - {} -}; - -static void vnt_set_options(struct vnt_private *priv) -{ - /* Set number of TX buffers */ - if (vnt_tx_buffers < CB_MIN_TX_DESC || vnt_tx_buffers > CB_MAX_TX_DESC) - priv->num_tx_context = TX_DESC_DEF0; - else - priv->num_tx_context = vnt_tx_buffers; - - /* Set number of RX buffers */ - if (vnt_rx_buffers < CB_MIN_RX_DESC || vnt_rx_buffers > CB_MAX_RX_DESC) - priv->num_rcb = RX_DESC_DEF0; - else - priv->num_rcb = vnt_rx_buffers; - - priv->op_mode = NL80211_IFTYPE_UNSPECIFIED; - priv->bb_type = BBP_TYPE_DEF; - priv->packet_type = priv->bb_type; - priv->preamble_type = PREAMBLE_LONG; - priv->exist_sw_net_addr = false; -} - -static int vnt_download_firmware(struct vnt_private *priv) -{ - struct device *dev = &priv->usb->dev; - const struct firmware *fw; - u16 length; - int ii; - int ret = 0; - - dev_dbg(dev, "---->Download firmware\n"); - - ret = request_firmware(&fw, FIRMWARE_NAME, dev); - if (ret) { - dev_err(dev, "firmware file %s request failed (%d)\n", - FIRMWARE_NAME, ret); - goto end; - } - - for (ii = 0; ii < fw->size; ii += FIRMWARE_CHUNK_SIZE) { - length = min_t(int, fw->size - ii, FIRMWARE_CHUNK_SIZE); - - ret = vnt_control_out(priv, 0, 0x1200 + ii, 0x0000, length, - fw->data + ii); - if (ret) - goto free_fw; - - dev_dbg(dev, "Download firmware...%d %zu\n", ii, fw->size); - } - -free_fw: - release_firmware(fw); -end: - return ret; -} - -static int vnt_firmware_branch_to_sram(struct vnt_private *priv) -{ - dev_dbg(&priv->usb->dev, "---->Branch to Sram\n"); - - return vnt_control_out(priv, 1, 0x1200, 0x0000, 0, NULL); -} - -static int vnt_check_firmware_version(struct vnt_private *priv) -{ - int ret = 0; - - ret = vnt_control_in(priv, MESSAGE_TYPE_READ, 0, - MESSAGE_REQUEST_VERSION, 2, - (u8 *)&priv->firmware_version); - if (ret) { - dev_dbg(&priv->usb->dev, - "Could not get firmware version: %d.\n", ret); - goto end; - } - - dev_dbg(&priv->usb->dev, "Firmware Version [%04x]\n", - priv->firmware_version); - - if (priv->firmware_version == 0xFFFF) { - dev_dbg(&priv->usb->dev, "In Loader.\n"); - ret = -EINVAL; - goto end; - } - - if (priv->firmware_version < FIRMWARE_VERSION) { - /* branch to loader for download new firmware */ - ret = vnt_firmware_branch_to_sram(priv); - if (ret) { - dev_dbg(&priv->usb->dev, - "Could not branch to SRAM: %d.\n", ret); - } else { - ret = -EINVAL; - } - } - -end: - return ret; -} - -/* - * initialization of MAC & BBP registers - */ -static int vnt_init_registers(struct vnt_private *priv) -{ - int ret; - struct vnt_cmd_card_init *init_cmd = &priv->init_command; - struct vnt_rsp_card_init *init_rsp = &priv->init_response; - u8 antenna; - int ii; - u8 tmp; - u8 calib_tx_iq = 0, calib_tx_dc = 0, calib_rx_iq = 0; - - dev_dbg(&priv->usb->dev, "---->INIbInitAdapter. [%d][%d]\n", - DEVICE_INIT_COLD, priv->packet_type); - - ret = vnt_check_firmware_version(priv); - if (ret) { - ret = vnt_download_firmware(priv); - if (ret) { - dev_dbg(&priv->usb->dev, - "Could not download firmware: %d.\n", ret); - goto end; - } - - ret = vnt_firmware_branch_to_sram(priv); - if (ret) { - dev_dbg(&priv->usb->dev, - "Could not branch to SRAM: %d.\n", ret); - goto end; - } - } - - ret = vnt_vt3184_init(priv); - if (ret) { - dev_dbg(&priv->usb->dev, "vnt_vt3184_init fail\n"); - goto end; - } - - init_cmd->init_class = DEVICE_INIT_COLD; - init_cmd->exist_sw_net_addr = priv->exist_sw_net_addr; - for (ii = 0; ii < ARRAY_SIZE(init_cmd->sw_net_addr); ii++) - init_cmd->sw_net_addr[ii] = priv->current_net_addr[ii]; - init_cmd->short_retry_limit = priv->hw->wiphy->retry_short; - init_cmd->long_retry_limit = priv->hw->wiphy->retry_long; - - /* issue card_init command to device */ - ret = vnt_control_out(priv, MESSAGE_TYPE_CARDINIT, 0, 0, - sizeof(struct vnt_cmd_card_init), - (u8 *)init_cmd); - if (ret) { - dev_dbg(&priv->usb->dev, "Issue Card init fail\n"); - goto end; - } - - ret = vnt_control_in(priv, MESSAGE_TYPE_INIT_RSP, 0, 0, - sizeof(struct vnt_rsp_card_init), - (u8 *)init_rsp); - if (ret) { - dev_dbg(&priv->usb->dev, "Cardinit request in status fail!\n"); - goto end; - } - - /* local ID for AES functions */ - ret = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_LOCALID, - MESSAGE_REQUEST_MACREG, 1, &priv->local_id); - if (ret) - goto end; - - /* do MACbSoftwareReset in MACvInitialize */ - - priv->top_ofdm_basic_rate = RATE_24M; - priv->top_cck_basic_rate = RATE_1M; - - /* target to IF pin while programming to RF chip */ - priv->power = 0xFF; - - priv->cck_pwr = priv->eeprom[EEP_OFS_PWR_CCK]; - priv->ofdm_pwr_g = priv->eeprom[EEP_OFS_PWR_OFDMG]; - /* load power table */ - for (ii = 0; ii < ARRAY_SIZE(priv->cck_pwr_tbl); ii++) { - priv->cck_pwr_tbl[ii] = - priv->eeprom[ii + EEP_OFS_CCK_PWR_TBL]; - if (priv->cck_pwr_tbl[ii] == 0) - priv->cck_pwr_tbl[ii] = priv->cck_pwr; - - priv->ofdm_pwr_tbl[ii] = - priv->eeprom[ii + EEP_OFS_OFDM_PWR_TBL]; - if (priv->ofdm_pwr_tbl[ii] == 0) - priv->ofdm_pwr_tbl[ii] = priv->ofdm_pwr_g; - } - - /* - * original zonetype is USA, but custom zonetype is Europe, - * then need to recover 12, 13, 14 channels with 11 channel - */ - for (ii = 11; ii < ARRAY_SIZE(priv->cck_pwr_tbl); ii++) { - priv->cck_pwr_tbl[ii] = priv->cck_pwr_tbl[10]; - priv->ofdm_pwr_tbl[ii] = priv->ofdm_pwr_tbl[10]; - } - - priv->ofdm_pwr_a = 0x34; /* same as RFbMA2829SelectChannel */ - - /* load OFDM A power table */ - for (ii = 0; ii < CB_MAX_CHANNEL_5G; ii++) { - priv->ofdm_a_pwr_tbl[ii] = - priv->eeprom[ii + EEP_OFS_OFDMA_PWR_TBL]; - - if (priv->ofdm_a_pwr_tbl[ii] == 0) - priv->ofdm_a_pwr_tbl[ii] = priv->ofdm_pwr_a; - } - - antenna = priv->eeprom[EEP_OFS_ANTENNA]; - - if (antenna & EEP_ANTINV) - priv->tx_rx_ant_inv = true; - else - priv->tx_rx_ant_inv = false; - - antenna &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); - - if (antenna == 0) /* if not set default is both */ - antenna = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN); - - if (antenna == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) { - priv->tx_antenna_mode = ANT_B; - priv->rx_antenna_sel = 1; - - if (priv->tx_rx_ant_inv) - priv->rx_antenna_mode = ANT_A; - else - priv->rx_antenna_mode = ANT_B; - } else { - priv->rx_antenna_sel = 0; - - if (antenna & EEP_ANTENNA_AUX) { - priv->tx_antenna_mode = ANT_A; - - if (priv->tx_rx_ant_inv) - priv->rx_antenna_mode = ANT_B; - else - priv->rx_antenna_mode = ANT_A; - } else { - priv->tx_antenna_mode = ANT_B; - - if (priv->tx_rx_ant_inv) - priv->rx_antenna_mode = ANT_A; - else - priv->rx_antenna_mode = ANT_B; - } - } - - /* Set initial antenna mode */ - ret = vnt_set_antenna_mode(priv, priv->rx_antenna_mode); - if (ret) - goto end; - - /* default Auto Mode */ - priv->bb_type = BB_TYPE_11G; - - /* get RFType */ - priv->rf_type = init_rsp->rf_type; - - /* load vt3266 calibration parameters in EEPROM */ - if (priv->rf_type == RF_VT3226D0) { - if ((priv->eeprom[EEP_OFS_MAJOR_VER] == 0x1) && - (priv->eeprom[EEP_OFS_MINOR_VER] >= 0x4)) { - calib_tx_iq = priv->eeprom[EEP_OFS_CALIB_TX_IQ]; - calib_tx_dc = priv->eeprom[EEP_OFS_CALIB_TX_DC]; - calib_rx_iq = priv->eeprom[EEP_OFS_CALIB_RX_IQ]; - if (calib_tx_iq || calib_tx_dc || calib_rx_iq) { - /* CR255, enable TX/RX IQ and - * DC compensation mode - */ - ret = vnt_control_out_u8(priv, - MESSAGE_REQUEST_BBREG, - 0xff, 0x03); - if (ret) - goto end; - - /* CR251, TX I/Q Imbalance Calibration */ - ret = vnt_control_out_u8(priv, - MESSAGE_REQUEST_BBREG, - 0xfb, calib_tx_iq); - if (ret) - goto end; - - /* CR252, TX DC-Offset Calibration */ - ret = vnt_control_out_u8(priv, - MESSAGE_REQUEST_BBREG, - 0xfC, calib_tx_dc); - if (ret) - goto end; - - /* CR253, RX I/Q Imbalance Calibration */ - ret = vnt_control_out_u8(priv, - MESSAGE_REQUEST_BBREG, - 0xfd, calib_rx_iq); - if (ret) - goto end; - } else { - /* CR255, turn off - * BB Calibration compensation - */ - ret = vnt_control_out_u8(priv, - MESSAGE_REQUEST_BBREG, - 0xff, 0x0); - if (ret) - goto end; - } - } - } - - /* get permanent network address */ - memcpy(priv->permanent_net_addr, init_rsp->net_addr, 6); - ether_addr_copy(priv->current_net_addr, priv->permanent_net_addr); - - /* if exist SW network address, use it */ - dev_dbg(&priv->usb->dev, "Network address = %pM\n", - priv->current_net_addr); - - priv->radio_ctl = priv->eeprom[EEP_OFS_RADIOCTL]; - - if ((priv->radio_ctl & EEP_RADIOCTL_ENABLE) != 0) { - ret = vnt_control_in(priv, MESSAGE_TYPE_READ, - MAC_REG_GPIOCTL1, MESSAGE_REQUEST_MACREG, - 1, &tmp); - if (ret) - goto end; - - if ((tmp & GPIO3_DATA) == 0) { - ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1, - GPIO3_INTMD); - } else { - ret = vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1, - GPIO3_INTMD); - } - - if (ret) - goto end; - } - - ret = vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38); - if (ret) - goto end; - - ret = vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW); - if (ret) - goto end; - - ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, BIT(0)); - if (ret) - goto end; - - ret = vnt_radio_power_on(priv); - if (ret) - goto end; - - dev_dbg(&priv->usb->dev, "<----INIbInitAdapter Exit\n"); - -end: - return ret; -} - -static void vnt_free_tx_bufs(struct vnt_private *priv) -{ - struct vnt_usb_send_context *tx_context; - int ii; - - usb_kill_anchored_urbs(&priv->tx_submitted); - - for (ii = 0; ii < priv->num_tx_context; ii++) { - tx_context = priv->tx_context[ii]; - if (!tx_context) - continue; - - kfree(tx_context); - } -} - -static void vnt_free_rx_bufs(struct vnt_private *priv) -{ - struct vnt_rcb *rcb; - int ii; - - for (ii = 0; ii < priv->num_rcb; ii++) { - rcb = priv->rcb[ii]; - if (!rcb) - continue; - - /* deallocate URBs */ - if (rcb->urb) { - usb_kill_urb(rcb->urb); - usb_free_urb(rcb->urb); - } - - /* deallocate skb */ - if (rcb->skb) - dev_kfree_skb(rcb->skb); - - kfree(rcb); - } -} - -static void vnt_free_int_bufs(struct vnt_private *priv) -{ - kfree(priv->int_buf.data_buf); -} - -static int vnt_alloc_bufs(struct vnt_private *priv) -{ - int ret; - struct vnt_usb_send_context *tx_context; - struct vnt_rcb *rcb; - int ii; - - init_usb_anchor(&priv->tx_submitted); - - for (ii = 0; ii < priv->num_tx_context; ii++) { - tx_context = kmalloc(sizeof(*tx_context), GFP_KERNEL); - if (!tx_context) { - ret = -ENOMEM; - goto free_tx; - } - - priv->tx_context[ii] = tx_context; - tx_context->priv = priv; - tx_context->pkt_no = ii; - tx_context->in_use = false; - } - - for (ii = 0; ii < priv->num_rcb; ii++) { - priv->rcb[ii] = kzalloc(sizeof(*priv->rcb[ii]), GFP_KERNEL); - if (!priv->rcb[ii]) { - ret = -ENOMEM; - goto free_rx_tx; - } - - rcb = priv->rcb[ii]; - - rcb->priv = priv; - - /* allocate URBs */ - rcb->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rcb->urb) { - ret = -ENOMEM; - goto free_rx_tx; - } - - rcb->skb = dev_alloc_skb(priv->rx_buf_sz); - if (!rcb->skb) { - ret = -ENOMEM; - goto free_rx_tx; - } - /* submit rx urb */ - ret = vnt_submit_rx_urb(priv, rcb); - if (ret) - goto free_rx_tx; - } - - priv->interrupt_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!priv->interrupt_urb) { - ret = -ENOMEM; - goto free_rx_tx; - } - - priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL); - if (!priv->int_buf.data_buf) { - ret = -ENOMEM; - goto free_rx_tx_urb; - } - - return 0; - -free_rx_tx_urb: - usb_free_urb(priv->interrupt_urb); -free_rx_tx: - vnt_free_rx_bufs(priv); -free_tx: - vnt_free_tx_bufs(priv); - return ret; -} - -static void vnt_tx_80211(struct ieee80211_hw *hw, - struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct vnt_private *priv = hw->priv; - - if (vnt_tx_packet(priv, skb)) - ieee80211_free_txskb(hw, skb); -} - -static int vnt_start(struct ieee80211_hw *hw) -{ - int ret; - struct vnt_private *priv = hw->priv; - - priv->rx_buf_sz = MAX_TOTAL_SIZE_WITH_ALL_HEADERS; - - ret = vnt_alloc_bufs(priv); - if (ret) { - dev_dbg(&priv->usb->dev, "vnt_alloc_bufs fail...\n"); - goto err; - } - - clear_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags); - - ret = vnt_init_registers(priv); - if (ret) { - dev_dbg(&priv->usb->dev, " init register fail\n"); - goto free_all; - } - - ret = vnt_key_init_table(priv); - if (ret) - goto free_all; - - priv->int_interval = 1; /* bInterval is set to 1 */ - - ret = vnt_start_interrupt_urb(priv); - if (ret) - goto free_all; - - ieee80211_wake_queues(hw); - - return 0; - -free_all: - vnt_free_rx_bufs(priv); - vnt_free_tx_bufs(priv); - vnt_free_int_bufs(priv); - - usb_kill_urb(priv->interrupt_urb); - usb_free_urb(priv->interrupt_urb); -err: - return ret; -} - -static void vnt_stop(struct ieee80211_hw *hw, bool suspend) -{ - struct vnt_private *priv = hw->priv; - int i; - - if (!priv) - return; - - for (i = 0; i < MAX_KEY_TABLE; i++) - vnt_mac_disable_keyentry(priv, i); - - /* clear all keys */ - priv->key_entry_inuse = 0; - - if (!test_bit(DEVICE_FLAGS_UNPLUG, &priv->flags)) - vnt_mac_shutdown(priv); - - ieee80211_stop_queues(hw); - - set_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags); - - cancel_delayed_work_sync(&priv->run_command_work); - - priv->cmd_running = false; - - vnt_free_tx_bufs(priv); - vnt_free_rx_bufs(priv); - vnt_free_int_bufs(priv); - - usb_kill_urb(priv->interrupt_urb); - usb_free_urb(priv->interrupt_urb); -} - -static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct vnt_private *priv = hw->priv; - - priv->vif = vif; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_ADHOC: - vnt_mac_reg_bits_off(priv, MAC_REG_RCR, RCR_UNICAST); - - vnt_mac_reg_bits_on(priv, MAC_REG_HOSTCR, HOSTCR_ADHOC); - - break; - case NL80211_IFTYPE_AP: - vnt_mac_reg_bits_off(priv, MAC_REG_RCR, RCR_UNICAST); - - vnt_mac_reg_bits_on(priv, MAC_REG_HOSTCR, HOSTCR_AP); - - break; - default: - return -EOPNOTSUPP; - } - - priv->op_mode = vif->type; - - /* LED blink on TX */ - vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_INTER); - - return 0; -} - -static void vnt_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct vnt_private *priv = hw->priv; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_ADHOC: - vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); - vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_ADHOC); - break; - case NL80211_IFTYPE_AP: - vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); - vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - vnt_mac_reg_bits_off(priv, MAC_REG_HOSTCR, HOSTCR_AP); - break; - default: - break; - } - - vnt_radio_power_off(priv); - - priv->op_mode = NL80211_IFTYPE_UNSPECIFIED; - - /* LED slow blink */ - vnt_mac_set_led(priv, LEDSTS_STS, LEDSTS_SLOW); -} - -static int vnt_config(struct ieee80211_hw *hw, u32 changed) -{ - struct vnt_private *priv = hw->priv; - struct ieee80211_conf *conf = &hw->conf; - - if (changed & IEEE80211_CONF_CHANGE_PS) { - if (conf->flags & IEEE80211_CONF_PS) - vnt_enable_power_saving(priv, conf->listen_interval); - else - vnt_disable_power_saving(priv); - } - - if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || - (conf->flags & IEEE80211_CONF_OFFCHANNEL)) { - vnt_set_channel(priv, conf->chandef.chan->hw_value); - - if (conf->chandef.chan->band == NL80211_BAND_5GHZ) - priv->bb_type = BB_TYPE_11A; - else - priv->bb_type = BB_TYPE_11G; - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) - vnt_rf_setpower(priv, conf->chandef.chan); - - if (conf->flags & (IEEE80211_CONF_OFFCHANNEL | IEEE80211_CONF_IDLE)) - /* Set max sensitivity*/ - vnt_update_pre_ed_threshold(priv, true); - else - vnt_update_pre_ed_threshold(priv, false); - - return 0; -} - -static void vnt_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf, u64 changed) -{ - struct vnt_private *priv = hw->priv; - - priv->current_aid = vif->cfg.aid; - - if (changed & BSS_CHANGED_BSSID && conf->bssid) - vnt_mac_set_bssid_addr(priv, (u8 *)conf->bssid); - - if (changed & BSS_CHANGED_BASIC_RATES) { - priv->basic_rates = conf->basic_rates; - - vnt_update_top_rates(priv); - - dev_dbg(&priv->usb->dev, "basic rates %x\n", conf->basic_rates); - } - - if (changed & BSS_CHANGED_ERP_PREAMBLE) { - if (conf->use_short_preamble) { - vnt_mac_enable_barker_preamble_mode(priv); - priv->preamble_type = PREAMBLE_SHORT; - } else { - vnt_mac_disable_barker_preamble_mode(priv); - priv->preamble_type = PREAMBLE_LONG; - } - } - - if (changed & BSS_CHANGED_ERP_CTS_PROT) { - if (conf->use_cts_prot) - vnt_mac_enable_protect_mode(priv); - else - vnt_mac_disable_protect_mode(priv); - } - - if (changed & BSS_CHANGED_ERP_SLOT) { - if (conf->use_short_slot) - priv->short_slot_time = true; - else - priv->short_slot_time = false; - - vnt_set_short_slot_time(priv); - vnt_set_vga_gain_offset(priv, priv->bb_vga[0]); - } - - if (changed & (BSS_CHANGED_BASIC_RATES | BSS_CHANGED_ERP_PREAMBLE | - BSS_CHANGED_ERP_SLOT)) - vnt_set_bss_mode(priv); - - if (changed & (BSS_CHANGED_TXPOWER | BSS_CHANGED_BANDWIDTH)) - vnt_rf_setpower(priv, conf->chanreq.oper.chan); - - if (changed & BSS_CHANGED_BEACON_ENABLED) { - dev_dbg(&priv->usb->dev, - "Beacon enable %d\n", conf->enable_beacon); - - if (conf->enable_beacon) { - vnt_beacon_enable(priv, vif, conf); - - vnt_mac_reg_bits_on(priv, MAC_REG_TCR, TCR_AUTOBCNTX); - } else { - vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); - } - } - - if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_BEACON_INFO) && - priv->op_mode != NL80211_IFTYPE_AP) { - if (vif->cfg.assoc && conf->beacon_rate) { - u16 ps_beacon_int = conf->beacon_int; - - if (conf->dtim_period) - ps_beacon_int *= conf->dtim_period; - else if (hw->conf.listen_interval) - ps_beacon_int *= hw->conf.listen_interval; - - vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL, - TFTCTL_TSFCNTREN); - - vnt_mac_set_beacon_interval(priv, ps_beacon_int); - - vnt_reset_next_tbtt(priv, conf->beacon_int); - - vnt_adjust_tsf(priv, conf->beacon_rate->hw_value, - conf->sync_tsf, priv->current_tsf); - - vnt_update_next_tbtt(priv, - conf->sync_tsf, ps_beacon_int); - } else { - vnt_clear_current_tsf(priv); - - vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, - TFTCTL_TSFCNTREN); - } - } -} - -static u64 vnt_prepare_multicast(struct ieee80211_hw *hw, - struct netdev_hw_addr_list *mc_list) -{ - struct vnt_private *priv = hw->priv; - struct netdev_hw_addr *ha; - u64 mc_filter = 0; - u32 bit_nr; - - netdev_hw_addr_list_for_each(ha, mc_list) { - bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; - mc_filter |= BIT_ULL(bit_nr); - } - - priv->mc_list_count = mc_list->count; - - return mc_filter; -} - -static void vnt_configure(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, u64 multicast) -{ - struct vnt_private *priv = hw->priv; - u8 rx_mode = 0; - - *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC; - - vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR, - MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode); - - dev_dbg(&priv->usb->dev, "rx mode in = %x\n", rx_mode); - - if (changed_flags & FIF_ALLMULTI) { - if (*total_flags & FIF_ALLMULTI) { - if (priv->mc_list_count > 2) - vnt_mac_set_filter(priv, ~0); - else - vnt_mac_set_filter(priv, multicast); - - rx_mode |= RCR_MULTICAST | RCR_BROADCAST; - } else { - rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST); - } - } - - if (changed_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) { - if (*total_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) - rx_mode &= ~RCR_BSSID; - else - rx_mode |= RCR_BSSID; - } - - vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, MAC_REG_RCR, rx_mode); - - dev_dbg(&priv->usb->dev, "rx mode out= %x\n", rx_mode); -} - -static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct vnt_private *priv = hw->priv; - - switch (cmd) { - case SET_KEY: - return vnt_set_keys(hw, sta, vif, key); - case DISABLE_KEY: - if (test_bit(key->hw_key_idx, &priv->key_entry_inuse)) { - clear_bit(key->hw_key_idx, &priv->key_entry_inuse); - - vnt_mac_disable_keyentry(priv, key->hw_key_idx); - } - break; - - default: - break; - } - - return 0; -} - -static int vnt_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) -{ - struct vnt_private *priv = hw->priv; - - memcpy(stats, &priv->low_stats, sizeof(*stats)); - - return 0; -} - -static u64 vnt_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct vnt_private *priv = hw->priv; - - return priv->current_tsf; -} - -static void vnt_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u64 tsf) -{ - struct vnt_private *priv = hw->priv; - - vnt_update_next_tbtt(priv, tsf, vif->bss_conf.beacon_int); -} - -static void vnt_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct vnt_private *priv = hw->priv; - - vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - - vnt_clear_current_tsf(priv); -} - -static const struct ieee80211_ops vnt_mac_ops = { - .add_chanctx = ieee80211_emulate_add_chanctx, - .remove_chanctx = ieee80211_emulate_remove_chanctx, - .change_chanctx = ieee80211_emulate_change_chanctx, - .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, - .tx = vnt_tx_80211, - .wake_tx_queue = ieee80211_handle_wake_tx_queue, - .start = vnt_start, - .stop = vnt_stop, - .add_interface = vnt_add_interface, - .remove_interface = vnt_remove_interface, - .config = vnt_config, - .bss_info_changed = vnt_bss_info_changed, - .prepare_multicast = vnt_prepare_multicast, - .configure_filter = vnt_configure, - .set_key = vnt_set_key, - .get_stats = vnt_get_stats, - .get_tsf = vnt_get_tsf, - .set_tsf = vnt_set_tsf, - .reset_tsf = vnt_reset_tsf, -}; - -int vnt_init(struct vnt_private *priv) -{ - if (vnt_init_registers(priv)) - return -EAGAIN; - - SET_IEEE80211_PERM_ADDR(priv->hw, priv->permanent_net_addr); - - vnt_init_bands(priv); - - if (ieee80211_register_hw(priv->hw)) - return -ENODEV; - - priv->mac_hw = true; - - vnt_radio_power_off(priv); - - return 0; -} - -static int -vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev; - struct vnt_private *priv; - struct ieee80211_hw *hw; - struct wiphy *wiphy; - int rc; - - udev = usb_get_dev(interface_to_usbdev(intf)); - - dev_notice(&udev->dev, "%s Ver. %s\n", - DEVICE_FULL_DRV_NAM, DEVICE_VERSION); - dev_notice(&udev->dev, - "Copyright (c) 2004 VIA Networking Technologies, Inc.\n"); - - hw = ieee80211_alloc_hw(sizeof(struct vnt_private), &vnt_mac_ops); - if (!hw) { - dev_err(&udev->dev, "could not register ieee80211_hw\n"); - rc = -ENOMEM; - goto err_nomem; - } - - priv = hw->priv; - priv->hw = hw; - priv->usb = udev; - priv->intf = intf; - - vnt_set_options(priv); - - spin_lock_init(&priv->lock); - mutex_init(&priv->usb_lock); - - INIT_DELAYED_WORK(&priv->run_command_work, vnt_run_command); - - usb_set_intfdata(intf, priv); - - wiphy = priv->hw->wiphy; - - wiphy->frag_threshold = FRAG_THRESH_DEF; - wiphy->rts_threshold = RTS_THRESH_DEF; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); - - ieee80211_hw_set(priv->hw, TIMING_BEACON_ONLY); - ieee80211_hw_set(priv->hw, SIGNAL_DBM); - ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS); - ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS); - ieee80211_hw_set(priv->hw, SUPPORTS_PS); - ieee80211_hw_set(priv->hw, PS_NULLFUNC_STACK); - - priv->hw->extra_tx_headroom = - sizeof(struct vnt_tx_buffer) + sizeof(struct vnt_tx_usb_header); - priv->hw->max_signal = 100; - - SET_IEEE80211_DEV(priv->hw, &intf->dev); - - rc = usb_reset_device(priv->usb); - if (rc) - dev_warn(&priv->usb->dev, - "%s reset fail status=%d\n", __func__, rc); - - clear_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags); - vnt_reset_command_timer(priv); - - vnt_schedule_command(priv, WLAN_CMD_INIT_MAC80211); - - return 0; - -err_nomem: - usb_put_dev(udev); - - return rc; -} - -static void vt6656_disconnect(struct usb_interface *intf) -{ - struct vnt_private *priv = usb_get_intfdata(intf); - - if (!priv) - return; - - if (priv->mac_hw) - ieee80211_unregister_hw(priv->hw); - - usb_set_intfdata(intf, NULL); - usb_put_dev(interface_to_usbdev(intf)); - - set_bit(DEVICE_FLAGS_UNPLUG, &priv->flags); - - ieee80211_free_hw(priv->hw); -} - -#ifdef CONFIG_PM - -static int vt6656_suspend(struct usb_interface *intf, pm_message_t message) -{ - return 0; -} - -static int vt6656_resume(struct usb_interface *intf) -{ - return 0; -} - -#endif /* CONFIG_PM */ - -MODULE_DEVICE_TABLE(usb, vt6656_table); - -static struct usb_driver vt6656_driver = { - .name = DEVICE_NAME, - .probe = vt6656_probe, - .disconnect = vt6656_disconnect, - .id_table = vt6656_table, -#ifdef CONFIG_PM - .suspend = vt6656_suspend, - .resume = vt6656_resume, -#endif /* CONFIG_PM */ -}; - -module_usb_driver(vt6656_driver); - -MODULE_FIRMWARE(FIRMWARE_NAME); diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c deleted file mode 100644 index e5411f6284c765..00000000000000 --- a/drivers/staging/vt6656/power.c +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Handles 802.11 power management functions - * - * Author: Lyndon Chen - * - * Date: July 17, 2002 - * - * Functions: - * vnt_enable_power_saving - Enable Power Saving Mode - * PSvDiasblePowerSaving - Disable Power Saving Mode - * vnt_next_tbtt_wakeup - Decide if we need to wake up at next Beacon - * - * Revision History: - * - */ - -#include "mac.h" -#include "device.h" -#include "power.h" -#include "wcmd.h" -#include "rxtx.h" -#include "card.h" -#include "usbpipe.h" - -/* - * - * Routine Description: - * Enable hw power saving functions - * - * Return Value: - * None. - * - */ - -void vnt_enable_power_saving(struct vnt_private *priv, u16 listen_interval) -{ - u16 aid = priv->current_aid | BIT(14) | BIT(15); - - /* set period of power up before TBTT */ - vnt_mac_write_word(priv, MAC_REG_PWBT, C_PWBT); - - if (priv->op_mode != NL80211_IFTYPE_ADHOC) - /* set AID */ - vnt_mac_write_word(priv, MAC_REG_AIDATIM, aid); - - /* Warren:06-18-2004,the sequence must follow - * PSEN->AUTOSLEEP->GO2DOZE - */ - /* enable power saving hw function */ - vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_PSEN); - - /* Set AutoSleep */ - vnt_mac_reg_bits_on(priv, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); - - /* Warren:MUST turn on this once before turn on AUTOSLEEP ,or the - * AUTOSLEEP doesn't work - */ - vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_GO2DOZE); - - /* always listen beacon */ - vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_ALBCN); - - dev_dbg(&priv->usb->dev, "PS:Power Saving Mode Enable...\n"); -} - -int vnt_disable_power_saving(struct vnt_private *priv) -{ - int ret; - - /* disable power saving hw function */ - ret = vnt_control_out(priv, MESSAGE_TYPE_DISABLE_PS, 0, - 0, 0, NULL); - if (ret) - return ret; - - /* clear AutoSleep */ - vnt_mac_reg_bits_off(priv, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); - - /* set always listen beacon */ - vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_ALBCN); - - return 0; -} - -/* - * - * Routine Description: - * Check if Next TBTT must wake up - * - * Return Value: - * None. - * - */ - -int vnt_next_tbtt_wakeup(struct vnt_private *priv) -{ - struct ieee80211_hw *hw = priv->hw; - struct ieee80211_conf *conf = &hw->conf; - int wake_up = false; - - if (conf->listen_interval > 1) { - /* Turn on wake up to listen next beacon */ - vnt_mac_reg_bits_on(priv, MAC_REG_PSCTL, PSCTL_LNBCN); - wake_up = true; - } - - return wake_up; -} diff --git a/drivers/staging/vt6656/power.h b/drivers/staging/vt6656/power.h deleted file mode 100644 index 9f9c7007293345..00000000000000 --- a/drivers/staging/vt6656/power.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Handles 802.11 power management functions - * - * Author: Lyndon Chen - * - * Date: July 17, 2002 - * - */ - -#ifndef __POWER_H__ -#define __POWER_H__ - -#define C_PWBT 1000 /* micro sec. power up before TBTT */ - -int vnt_disable_power_saving(struct vnt_private *priv); -void vnt_enable_power_saving(struct vnt_private *priv, u16 listen_interval); -int vnt_next_tbtt_wakeup(struct vnt_private *priv); - -#endif /* __POWER_H__ */ diff --git a/drivers/staging/vt6656/rf.c b/drivers/staging/vt6656/rf.c deleted file mode 100644 index 464602c747270d..00000000000000 --- a/drivers/staging/vt6656/rf.c +++ /dev/null @@ -1,443 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: rf function code - * - * Author: Jerry Chen - * - * Date: Feb. 19, 2004 - * - * Functions: - * vnt_rf_write_embedded - Embedded write RF register via MAC - * - * Revision History: - * RF_VT3226: RobertYu:20051111, VT3226C0 and before - * RF_VT3226D0: RobertYu:20051228 - * RF_VT3342A0: RobertYu:20060609 - * - */ - -#include -#include "mac.h" -#include "rf.h" -#include "baseband.h" -#include "usbpipe.h" - -#define CB_AL2230_INIT_SEQ 15 -#define CB_AL7230_INIT_SEQ 16 -#define CB_VT3226_INIT_SEQ 11 -#define CB_VT3342_INIT_SEQ 13 - -static u8 al2230_init_table[CB_AL2230_INIT_SEQ][3] = { - {0x03, 0xf7, 0x90}, - {0x03, 0x33, 0x31}, - {0x01, 0xb8, 0x02}, - {0x00, 0xff, 0xf3}, - {0x00, 0x05, 0xa4}, - {0x0f, 0x4d, 0xc5}, - {0x08, 0x05, 0xb6}, - {0x01, 0x47, 0xc7}, - {0x00, 0x06, 0x88}, - {0x04, 0x03, 0xb9}, - {0x00, 0xdb, 0xba}, - {0x00, 0x09, 0x9b}, - {0x0b, 0xdf, 0xfc}, - {0x00, 0x00, 0x0d}, - {0x00, 0x58, 0x0f} -}; - -static u8 al2230_channel_table0[CB_MAX_CHANNEL_24G][3] = { - {0x03, 0xf7, 0x90}, - {0x03, 0xf7, 0x90}, - {0x03, 0xe7, 0x90}, - {0x03, 0xe7, 0x90}, - {0x03, 0xf7, 0xa0}, - {0x03, 0xf7, 0xa0}, - {0x03, 0xe7, 0xa0}, - {0x03, 0xe7, 0xa0}, - {0x03, 0xf7, 0xb0}, - {0x03, 0xf7, 0xb0}, - {0x03, 0xe7, 0xb0}, - {0x03, 0xe7, 0xb0}, - {0x03, 0xf7, 0xc0}, - {0x03, 0xe7, 0xc0} -}; - -static u8 al2230_channel_table1[CB_MAX_CHANNEL_24G][3] = { - {0x03, 0x33, 0x31}, - {0x0b, 0x33, 0x31}, - {0x03, 0x33, 0x31}, - {0x0b, 0x33, 0x31}, - {0x03, 0x33, 0x31}, - {0x0b, 0x33, 0x31}, - {0x03, 0x33, 0x31}, - {0x0b, 0x33, 0x31}, - {0x03, 0x33, 0x31}, - {0x0b, 0x33, 0x31}, - {0x03, 0x33, 0x31}, - {0x0b, 0x33, 0x31}, - {0x03, 0x33, 0x31}, - {0x06, 0x66, 0x61} -}; - -static u8 vt3226_init_table[CB_VT3226_INIT_SEQ][3] = { - {0x03, 0xff, 0x80}, - {0x02, 0x82, 0xa1}, - {0x03, 0xc6, 0xa2}, - {0x01, 0x97, 0x93}, - {0x03, 0x66, 0x64}, - {0x00, 0x61, 0xa5}, - {0x01, 0x7b, 0xd6}, - {0x00, 0x80, 0x17}, - {0x03, 0xf8, 0x08}, - {0x00, 0x02, 0x39}, - {0x02, 0x00, 0x2a} -}; - -static u8 vt3226d0_init_table[CB_VT3226_INIT_SEQ][3] = { - {0x03, 0xff, 0x80}, - {0x03, 0x02, 0x21}, - {0x03, 0xc6, 0xa2}, - {0x01, 0x97, 0x93}, - {0x03, 0x66, 0x64}, - {0x00, 0x71, 0xa5}, - {0x01, 0x15, 0xc6}, - {0x01, 0x2e, 0x07}, - {0x00, 0x58, 0x08}, - {0x00, 0x02, 0x79}, - {0x02, 0x01, 0xaa} -}; - -static u8 vt3226_channel_table0[CB_MAX_CHANNEL_24G][3] = { - {0x01, 0x97, 0x83}, - {0x01, 0x97, 0x83}, - {0x01, 0x97, 0x93}, - {0x01, 0x97, 0x93}, - {0x01, 0x97, 0x93}, - {0x01, 0x97, 0x93}, - {0x01, 0x97, 0xa3}, - {0x01, 0x97, 0xa3}, - {0x01, 0x97, 0xa3}, - {0x01, 0x97, 0xa3}, - {0x01, 0x97, 0xb3}, - {0x01, 0x97, 0xb3}, - {0x01, 0x97, 0xb3}, - {0x03, 0x37, 0xc3} -}; - -static u8 vt3226_channel_table1[CB_MAX_CHANNEL_24G][3] = { - {0x02, 0x66, 0x64}, - {0x03, 0x66, 0x64}, - {0x00, 0x66, 0x64}, - {0x01, 0x66, 0x64}, - {0x02, 0x66, 0x64}, - {0x03, 0x66, 0x64}, - {0x00, 0x66, 0x64}, - {0x01, 0x66, 0x64}, - {0x02, 0x66, 0x64}, - {0x03, 0x66, 0x64}, - {0x00, 0x66, 0x64}, - {0x01, 0x66, 0x64}, - {0x02, 0x66, 0x64}, - {0x00, 0xcc, 0xc4} -}; - -static const u32 vt3226d0_lo_current_table[CB_MAX_CHANNEL_24G] = { - 0x0135c600, - 0x0135c600, - 0x0235c600, - 0x0235c600, - 0x0235c600, - 0x0335c600, - 0x0335c600, - 0x0335c600, - 0x0335c600, - 0x0335c600, - 0x0335c600, - 0x0335c600, - 0x0335c600, - 0x0135c600 -}; - -enum { - VNT_TABLE_INIT = 0, - VNT_TABLE_INIT_2 = 0, - VNT_TABLE_0 = 1, - VNT_TABLE_1 = 2, - VNT_TABLE_2 = 1 -}; - -struct vnt_table_info { - u8 *addr; - int length; -}; - -static const struct vnt_table_info vnt_table_seq[][3] = { - { /* RF_AL2230, RF_AL2230S init table, channel table 0 and 1 */ - {&al2230_init_table[0][0], CB_AL2230_INIT_SEQ * 3}, - {&al2230_channel_table0[0][0], CB_MAX_CHANNEL_24G * 3}, - {&al2230_channel_table1[0][0], CB_MAX_CHANNEL_24G * 3} - }, { /* RF_VT3226 init table, channel table 0 and 1 */ - {&vt3226_init_table[0][0], CB_VT3226_INIT_SEQ * 3}, - {&vt3226_channel_table0[0][0], CB_MAX_CHANNEL_24G * 3}, - {&vt3226_channel_table1[0][0], CB_MAX_CHANNEL_24G * 3} - }, { /* RF_VT3226D0 init table, channel table 0 and 1 */ - {&vt3226d0_init_table[0][0], CB_VT3226_INIT_SEQ * 3}, - {&vt3226_channel_table0[0][0], CB_MAX_CHANNEL_24G * 3}, - {&vt3226_channel_table1[0][0], CB_MAX_CHANNEL_24G * 3} - } -}; - -/* - * Description: Write to IF/RF, by embedded programming - */ -int vnt_rf_write_embedded(struct vnt_private *priv, u32 data) -{ - u8 reg_data[4]; - - data |= (VNT_RF_REG_LEN << 3) | IFREGCTL_REGW; - - reg_data[0] = (u8)data; - reg_data[1] = (u8)(data >> 8); - reg_data[2] = (u8)(data >> 16); - reg_data[3] = (u8)(data >> 24); - - return vnt_control_out(priv, MESSAGE_TYPE_WRITE_IFRF, 0, 0, - ARRAY_SIZE(reg_data), reg_data); -} - -static u8 vnt_rf_addpower(struct vnt_private *priv) -{ - int base; - s32 rssi = -priv->current_rssi; - - if (!rssi) - return 7; - - if (priv->rf_type == RF_VT3226D0) - base = -60; - else - base = -70; - - if (rssi < base) - return ((rssi - base + 1) / -5) * 2 + 5; - - return 0; -} - -/* Set Tx power by power level and rate */ -static int vnt_rf_set_txpower(struct vnt_private *priv, u8 power, - struct ieee80211_channel *ch) -{ - u32 power_setting = 0; - int ret = 0; - - power += vnt_rf_addpower(priv); - if (power > VNT_RF_MAX_POWER) - power = VNT_RF_MAX_POWER; - - if (priv->power == power) - return 0; - - priv->power = power; - - switch (priv->rf_type) { - case RF_AL2230: - power_setting = 0x0404090 | (power << 12); - - ret = vnt_rf_write_embedded(priv, power_setting); - if (ret) - return ret; - - if (ch->flags & IEEE80211_CHAN_NO_OFDM) - ret = vnt_rf_write_embedded(priv, 0x0001b400); - else - ret = vnt_rf_write_embedded(priv, 0x0005a400); - - break; - case RF_AL2230S: - power_setting = 0x0404090 | (power << 12); - - ret = vnt_rf_write_embedded(priv, power_setting); - if (ret) - return ret; - - if (ch->flags & IEEE80211_CHAN_NO_OFDM) { - ret = vnt_rf_write_embedded(priv, 0x040c1400); - if (ret) - return ret; - - ret = vnt_rf_write_embedded(priv, 0x00299b00); - } else { - ret = vnt_rf_write_embedded(priv, 0x0005a400); - if (ret) - return ret; - - ret = vnt_rf_write_embedded(priv, 0x00099b00); - } - - break; - - case RF_VT3226: - power_setting = ((0x3f - power) << 20) | (0x17 << 8); - - ret = vnt_rf_write_embedded(priv, power_setting); - break; - case RF_VT3226D0: - if (ch->flags & IEEE80211_CHAN_NO_OFDM) { - u16 hw_value = ch->hw_value; - - power_setting = ((0x3f - power) << 20) | (0xe07 << 8); - - ret = vnt_rf_write_embedded(priv, power_setting); - if (ret) - return ret; - - ret = vnt_rf_write_embedded(priv, 0x03c6a200); - if (ret) - return ret; - - dev_dbg(&priv->usb->dev, - "%s 11b channel [%d]\n", __func__, hw_value); - - hw_value--; - - if (hw_value < ARRAY_SIZE(vt3226d0_lo_current_table)) { - ret = vnt_rf_write_embedded(priv, - vt3226d0_lo_current_table[hw_value]); - if (ret) - return ret; - } - - ret = vnt_rf_write_embedded(priv, 0x015C0800); - } else { - dev_dbg(&priv->usb->dev, - "@@@@ %s> 11G mode\n", __func__); - - power_setting = ((0x3f - power) << 20) | (0x7 << 8); - - ret = vnt_rf_write_embedded(priv, power_setting); - if (ret) - return ret; - - ret = vnt_rf_write_embedded(priv, 0x00C6A200); - if (ret) - return ret; - - ret = vnt_rf_write_embedded(priv, 0x016BC600); - if (ret) - return ret; - - ret = vnt_rf_write_embedded(priv, 0x00900800); - } - - break; - - default: - break; - } - return ret; -} - -/* Set Tx power by channel number type */ -int vnt_rf_setpower(struct vnt_private *priv, - struct ieee80211_channel *ch) -{ - u16 channel; - u8 power = priv->cck_pwr; - - if (!ch) - return -EINVAL; - - /* set channel number to array number */ - channel = ch->hw_value - 1; - - if (ch->flags & IEEE80211_CHAN_NO_OFDM) { - if (channel < ARRAY_SIZE(priv->cck_pwr_tbl)) - power = priv->cck_pwr_tbl[channel]; - } else if (ch->band == NL80211_BAND_5GHZ) { - /* remove 14 channels to array size */ - channel -= 14; - - if (channel < ARRAY_SIZE(priv->ofdm_a_pwr_tbl)) - power = priv->ofdm_a_pwr_tbl[channel]; - } else { - if (channel < ARRAY_SIZE(priv->ofdm_pwr_tbl)) - power = priv->ofdm_pwr_tbl[channel]; - } - - return vnt_rf_set_txpower(priv, power, ch); -} - -/* Convert rssi to dbm */ -void vnt_rf_rssi_to_dbm(struct vnt_private *priv, u8 rssi, long *dbm) -{ - u8 idx = ((rssi & 0xc0) >> 6) & 0x03; - long b = rssi & 0x3f; - long a = 0; - u8 airoharf[4] = {0, 18, 0, 40}; - - switch (priv->rf_type) { - case RF_AL2230: - case RF_AL2230S: - case RF_VT3226: - case RF_VT3226D0: - a = airoharf[idx]; - break; - default: - break; - } - - *dbm = -1 * (a + b * 2); -} - -int vnt_rf_table_download(struct vnt_private *priv) -{ - int ret; - int idx = -1; - const struct vnt_table_info *table_seq; - - switch (priv->rf_type) { - case RF_AL2230: - case RF_AL2230S: - idx = 0; - break; - case RF_VT3226: - idx = 1; - break; - case RF_VT3226D0: - idx = 2; - break; - } - - if (idx < 0) - return 0; - - table_seq = &vnt_table_seq[idx][0]; - - /* Init Table */ - ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0, - MESSAGE_REQUEST_RF_INIT, - table_seq[VNT_TABLE_INIT].length, - table_seq[VNT_TABLE_INIT].addr); - if (ret) - return ret; - - /* Channel Table 0 */ - ret = vnt_control_out_blocks(priv, VNT_REG_BLOCK_SIZE, - MESSAGE_REQUEST_RF_CH0, - table_seq[VNT_TABLE_0].length, - table_seq[VNT_TABLE_0].addr); - if (ret) - return ret; - - /* Channel Table 1 */ - ret = vnt_control_out_blocks(priv, VNT_REG_BLOCK_SIZE, - MESSAGE_REQUEST_RF_CH1, - table_seq[VNT_TABLE_1].length, - table_seq[VNT_TABLE_1].addr); - - return ret; -} diff --git a/drivers/staging/vt6656/rf.h b/drivers/staging/vt6656/rf.h deleted file mode 100644 index b47e149875d1db..00000000000000 --- a/drivers/staging/vt6656/rf.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: - * - * Author: Jerry Chen - * - * Date: Feb. 19, 2004 - * - */ - -#ifndef __RF_H__ -#define __RF_H__ - -#include "device.h" - -/* Baseband RF pair definition in eeprom (Bits 6..0) */ -#define RF_RFMD2959 0x01 -#define RF_MAXIMAG 0x02 -#define RF_AL2230 0x03 -#define RF_GCT5103 0x04 -#define RF_UW2451 0x05 -#define RF_MAXIMG 0x06 -#define RF_MAXIM2829 0x07 -#define RF_UW2452 0x08 -#define RF_VT3226 0x09 -#define RF_AIROHA7230 0x0a -#define RF_UW2453 0x0b -#define RF_VT3226D0 0x0c /* RobertYu:20051114 */ -#define RF_VT3342A0 0x0d /* RobertYu:20060609 */ -#define RF_AL2230S 0x0e - -#define RF_EMU 0x80 -#define RF_MASK 0x7F - -#define VNT_RF_MAX_POWER 0x3f -#define VNT_RF_REG_LEN 0x17 /* 24 bit length */ - -int vnt_rf_write_embedded(struct vnt_private *priv, u32 data); -int vnt_rf_setpower(struct vnt_private *priv, struct ieee80211_channel *ch); -void vnt_rf_rssi_to_dbm(struct vnt_private *priv, u8 rssi, long *dbm); -int vnt_rf_table_download(struct vnt_private *priv); - -#endif /* __RF_H__ */ diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c deleted file mode 100644 index cd99091c6c28fc..00000000000000 --- a/drivers/staging/vt6656/rxtx.c +++ /dev/null @@ -1,730 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: handle WMAC/802.3/802.11 rx & tx functions - * - * Author: Lyndon Chen - * - * Date: May 20, 2003 - * - * Functions: - * vnt_generate_tx_parameter - Generate tx dma required parameter. - * vnt_get_rsvtime- get frame reserved time - * vnt_fill_cts_head- fulfill CTS ctl header - * - * Revision History: - * - */ - -#include -#include "device.h" -#include "rxtx.h" -#include "card.h" -#include "mac.h" -#include "rf.h" -#include "usbpipe.h" - -static const u16 vnt_time_stampoff[2][MAX_RATE] = { - /* Long Preamble */ - {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23}, - - /* Short Preamble */ - {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23}, -}; - -#define DATADUR_B 10 -#define DATADUR_A 11 - -static const u8 vnt_phy_signal[] = { - 0x00, /* RATE_1M */ - 0x01, /* RATE_2M */ - 0x02, /* RATE_5M */ - 0x03, /* RATE_11M */ - 0x8b, /* RATE_6M */ - 0x8f, /* RATE_9M */ - 0x8a, /* RATE_12M */ - 0x8e, /* RATE_18M */ - 0x89, /* RATE_24M */ - 0x8d, /* RATE_36M */ - 0x88, /* RATE_48M */ - 0x8c /* RATE_54M */ -}; - -static struct vnt_usb_send_context - *vnt_get_free_context(struct vnt_private *priv) -{ - struct vnt_usb_send_context *context = NULL; - int ii; - - for (ii = 0; ii < priv->num_tx_context; ii++) { - if (!priv->tx_context[ii]) - return NULL; - - context = priv->tx_context[ii]; - if (!context->in_use) { - context->in_use = true; - return context; - } - } - - if (ii == priv->num_tx_context) { - dev_dbg(&priv->usb->dev, "%s No Free Tx Context\n", __func__); - - ieee80211_stop_queues(priv->hw); - } - - return NULL; -} - -/* Get Length, Service, and Signal fields of Phy for Tx */ -static void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length, - u16 tx_rate, u8 pkt_type, - struct vnt_phy_field *phy) -{ - u32 bit_count; - u32 count = 0; - u32 tmp; - int ext_bit; - int i; - u8 mask = 0; - u8 preamble_type = priv->preamble_type; - - bit_count = frame_length * 8; - ext_bit = false; - - switch (tx_rate) { - case RATE_1M: - count = bit_count; - break; - case RATE_2M: - count = bit_count / 2; - break; - case RATE_5M: - count = DIV_ROUND_UP(bit_count * 10, 55); - break; - case RATE_11M: - count = bit_count / 11; - tmp = count * 11; - - if (tmp != bit_count) { - count++; - - if ((bit_count - tmp) <= 3) - ext_bit = true; - } - - break; - } - - if (tx_rate > RATE_11M) { - if (pkt_type == PK_TYPE_11A) - mask = BIT(4); - } else if (tx_rate > RATE_1M) { - if (preamble_type == PREAMBLE_SHORT) - mask = BIT(3); - } - - i = tx_rate > RATE_54M ? RATE_54M : tx_rate; - phy->signal = vnt_phy_signal[i] | mask; - phy->service = 0x00; - - if (pkt_type == PK_TYPE_11B) { - if (ext_bit) - phy->service |= 0x80; - phy->len = cpu_to_le16((u16)count); - } else { - phy->len = cpu_to_le16((u16)frame_length); - } -} - -static __le16 vnt_time_stamp_off(struct vnt_private *priv, u16 rate) -{ - return cpu_to_le16(vnt_time_stampoff[priv->preamble_type % 2] - [rate % MAX_RATE]); -} - -static __le16 vnt_rxtx_rsvtime_le16(struct vnt_usb_send_context *context) -{ - struct vnt_private *priv = context->priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(context->skb); - struct ieee80211_rate *rate = ieee80211_get_tx_rate(priv->hw, info); - - return ieee80211_generic_frame_duration(priv->hw, - info->control.vif, info->band, - context->frame_len, - rate); -} - -static __le16 vnt_get_rts_duration(struct vnt_usb_send_context *context) -{ - struct vnt_private *priv = context->priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(context->skb); - - return ieee80211_rts_duration(priv->hw, priv->vif, - context->frame_len, info); -} - -static __le16 vnt_get_cts_duration(struct vnt_usb_send_context *context) -{ - struct vnt_private *priv = context->priv; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(context->skb); - - return ieee80211_ctstoself_duration(priv->hw, priv->vif, - context->frame_len, info); -} - -static void vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context, - struct vnt_tx_datahead_g *buf) -{ - struct vnt_private *priv = tx_context->priv; - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *)tx_context->skb->data; - u32 frame_len = tx_context->frame_len; - u16 rate = tx_context->tx_rate; - - /* Get SignalField,ServiceField,Length */ - vnt_get_phy_field(priv, frame_len, rate, tx_context->pkt_type, &buf->a); - vnt_get_phy_field(priv, frame_len, priv->top_cck_basic_rate, - PK_TYPE_11B, &buf->b); - - /* Get Duration and TimeStamp */ - buf->duration_a = hdr->duration_id; - buf->duration_b = hdr->duration_id; - buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate); - buf->time_stamp_off_b = vnt_time_stamp_off(priv, - priv->top_cck_basic_rate); -} - -static void vnt_rxtx_datahead_ab(struct vnt_usb_send_context *tx_context, - struct vnt_tx_datahead_ab *buf) -{ - struct vnt_private *priv = tx_context->priv; - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *)tx_context->skb->data; - u32 frame_len = tx_context->frame_len; - u16 rate = tx_context->tx_rate; - - /* Get SignalField,ServiceField,Length */ - vnt_get_phy_field(priv, frame_len, rate, - tx_context->pkt_type, &buf->ab); - - /* Get Duration and TimeStampOff */ - buf->duration = hdr->duration_id; - buf->time_stamp_off = vnt_time_stamp_off(priv, rate); -} - -static void vnt_fill_ieee80211_rts(struct vnt_usb_send_context *tx_context, - struct ieee80211_rts *rts, __le16 duration) -{ - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *)tx_context->skb->data; - - rts->duration = duration; - rts->frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS); - - ether_addr_copy(rts->ra, hdr->addr1); - ether_addr_copy(rts->ta, hdr->addr2); -} - -static void vnt_rxtx_rts_g_head(struct vnt_usb_send_context *tx_context, - struct vnt_rts_g *buf) -{ - struct vnt_private *priv = tx_context->priv; - u16 rts_frame_len = 20; - - vnt_get_phy_field(priv, rts_frame_len, priv->top_cck_basic_rate, - PK_TYPE_11B, &buf->b); - vnt_get_phy_field(priv, rts_frame_len, priv->top_ofdm_basic_rate, - tx_context->pkt_type, &buf->a); - - buf->duration_bb = vnt_get_rts_duration(tx_context); - buf->duration_aa = buf->duration_bb; - buf->duration_ba = buf->duration_bb; - - vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration_aa); - - vnt_rxtx_datahead_g(tx_context, &buf->data_head); -} - -static void vnt_rxtx_rts_ab_head(struct vnt_usb_send_context *tx_context, - struct vnt_rts_ab *buf) -{ - struct vnt_private *priv = tx_context->priv; - u16 rts_frame_len = 20; - - vnt_get_phy_field(priv, rts_frame_len, priv->top_ofdm_basic_rate, - tx_context->pkt_type, &buf->ab); - - buf->duration = vnt_get_rts_duration(tx_context); - - vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration); - - vnt_rxtx_datahead_ab(tx_context, &buf->data_head); -} - -static void vnt_fill_cts_head(struct vnt_usb_send_context *tx_context, - union vnt_tx_data_head *head) -{ - struct vnt_private *priv = tx_context->priv; - struct vnt_cts *buf = &head->cts_g; - u32 cts_frame_len = 14; - - /* Get SignalField,ServiceField,Length */ - vnt_get_phy_field(priv, cts_frame_len, priv->top_cck_basic_rate, - PK_TYPE_11B, &buf->b); - /* Get CTSDuration_ba */ - buf->duration_ba = vnt_get_cts_duration(tx_context); - /*Get CTS Frame body*/ - buf->data.duration = buf->duration_ba; - buf->data.frame_control = - cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS); - - ether_addr_copy(buf->data.ra, priv->current_net_addr); - - vnt_rxtx_datahead_g(tx_context, &buf->data_head); -} - -/* returns true if mic_hdr is needed */ -static bool vnt_fill_txkey(struct vnt_tx_buffer *tx_buffer, struct sk_buff *skb) -{ - struct vnt_tx_fifo_head *fifo = &tx_buffer->fifo_head; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_key_conf *tx_key = info->control.hw_key; - struct vnt_mic_hdr *mic_hdr; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u64 pn64; - u16 payload_len = skb->len; - u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb)); - - /* strip header and icv len from payload */ - payload_len -= ieee80211_get_hdrlen_from_skb(skb); - payload_len -= tx_key->icv_len; - - switch (tx_key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - memcpy(fifo->tx_key, iv, 3); - memcpy(fifo->tx_key + 3, tx_key->key, tx_key->keylen); - - if (tx_key->keylen == WLAN_KEY_LEN_WEP40) { - memcpy(fifo->tx_key + 8, iv, 3); - memcpy(fifo->tx_key + 11, - tx_key->key, WLAN_KEY_LEN_WEP40); - } - - fifo->frag_ctl |= cpu_to_le16(FRAGCTL_LEGACY); - break; - case WLAN_CIPHER_SUITE_TKIP: - ieee80211_get_tkip_p2k(tx_key, skb, fifo->tx_key); - - fifo->frag_ctl |= cpu_to_le16(FRAGCTL_TKIP); - break; - case WLAN_CIPHER_SUITE_CCMP: - if (info->control.use_cts_prot) { - if (info->control.use_rts) - mic_hdr = &tx_buffer->tx_head.tx_rts.tx.mic.hdr; - else - mic_hdr = &tx_buffer->tx_head.tx_cts.tx.mic.hdr; - } else { - mic_hdr = &tx_buffer->tx_head.tx_ab.tx.mic.hdr; - } - - mic_hdr->id = 0x59; - mic_hdr->payload_len = cpu_to_be16(payload_len); - ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2); - - pn64 = atomic64_read(&tx_key->tx_pn); - mic_hdr->ccmp_pn[5] = pn64; - mic_hdr->ccmp_pn[4] = pn64 >> 8; - mic_hdr->ccmp_pn[3] = pn64 >> 16; - mic_hdr->ccmp_pn[2] = pn64 >> 24; - mic_hdr->ccmp_pn[1] = pn64 >> 32; - mic_hdr->ccmp_pn[0] = pn64 >> 40; - - if (ieee80211_has_a4(hdr->frame_control)) - mic_hdr->hlen = cpu_to_be16(28); - else - mic_hdr->hlen = cpu_to_be16(22); - - ether_addr_copy(mic_hdr->addr1, hdr->addr1); - ether_addr_copy(mic_hdr->addr2, hdr->addr2); - ether_addr_copy(mic_hdr->addr3, hdr->addr3); - - mic_hdr->frame_control = cpu_to_le16(le16_to_cpu(hdr->frame_control) & 0xc78f); - mic_hdr->seq_ctrl = cpu_to_le16(le16_to_cpu(hdr->seq_ctrl) & 0xf); - - if (ieee80211_has_a4(hdr->frame_control)) - ether_addr_copy(mic_hdr->addr4, hdr->addr4); - - memcpy(fifo->tx_key, tx_key->key, WLAN_KEY_LEN_CCMP); - - fifo->frag_ctl |= cpu_to_le16(FRAGCTL_AES); - return true; - default: - break; - } - - return false; -} - -static void vnt_rxtx_rts(struct vnt_usb_send_context *tx_context) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_context->skb); - struct vnt_tx_buffer *tx_buffer = tx_context->tx_buffer; - union vnt_tx_head *tx_head = &tx_buffer->tx_head; - struct vnt_rrv_time_rts *buf = &tx_head->tx_rts.rts; - union vnt_tx_data_head *head = &tx_head->tx_rts.tx.head; - - buf->rts_rrv_time_aa = vnt_get_rts_duration(tx_context); - buf->rts_rrv_time_ba = buf->rts_rrv_time_aa; - buf->rts_rrv_time_bb = buf->rts_rrv_time_aa; - - buf->rrv_time_a = vnt_rxtx_rsvtime_le16(tx_context); - buf->rrv_time_b = buf->rrv_time_a; - - if (info->control.hw_key) { - if (vnt_fill_txkey(tx_buffer, tx_context->skb)) - head = &tx_head->tx_rts.tx.mic.head; - } - - vnt_rxtx_rts_g_head(tx_context, &head->rts_g); -} - -static void vnt_rxtx_cts(struct vnt_usb_send_context *tx_context) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_context->skb); - struct vnt_tx_buffer *tx_buffer = tx_context->tx_buffer; - union vnt_tx_head *tx_head = &tx_buffer->tx_head; - struct vnt_rrv_time_cts *buf = &tx_head->tx_cts.cts; - union vnt_tx_data_head *head = &tx_head->tx_cts.tx.head; - - buf->rrv_time_a = vnt_rxtx_rsvtime_le16(tx_context); - buf->rrv_time_b = buf->rrv_time_a; - - buf->cts_rrv_time_ba = vnt_get_cts_duration(tx_context); - - if (info->control.hw_key) { - if (vnt_fill_txkey(tx_buffer, tx_context->skb)) - head = &tx_head->tx_cts.tx.mic.head; - } - - vnt_fill_cts_head(tx_context, head); -} - -static void vnt_rxtx_ab(struct vnt_usb_send_context *tx_context) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_context->skb); - struct vnt_tx_buffer *tx_buffer = tx_context->tx_buffer; - union vnt_tx_head *tx_head = &tx_buffer->tx_head; - struct vnt_rrv_time_ab *buf = &tx_head->tx_ab.ab; - union vnt_tx_data_head *head = &tx_head->tx_ab.tx.head; - - buf->rrv_time = vnt_rxtx_rsvtime_le16(tx_context); - - if (info->control.hw_key) { - if (vnt_fill_txkey(tx_buffer, tx_context->skb)) - head = &tx_head->tx_ab.tx.mic.head; - } - - if (info->control.use_rts) { - buf->rts_rrv_time = vnt_get_rts_duration(tx_context); - - vnt_rxtx_rts_ab_head(tx_context, &head->rts_ab); - - return; - } - - vnt_rxtx_datahead_ab(tx_context, &head->data_head_ab); -} - -static void vnt_generate_tx_parameter(struct vnt_usb_send_context *tx_context) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_context->skb); - - if (info->control.use_cts_prot) { - if (info->control.use_rts) { - vnt_rxtx_rts(tx_context); - - return; - } - - vnt_rxtx_cts(tx_context); - - return; - } - - vnt_rxtx_ab(tx_context); -} - -static u16 vnt_get_hdr_size(struct ieee80211_tx_info *info) -{ - u16 size = sizeof(struct vnt_tx_datahead_ab); - - if (info->control.use_cts_prot) { - if (info->control.use_rts) - size = sizeof(struct vnt_rts_g); - else - size = sizeof(struct vnt_cts); - } else if (info->control.use_rts) { - size = sizeof(struct vnt_rts_ab); - } - - if (info->control.hw_key) { - if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP) - size += sizeof(struct vnt_mic_hdr); - } - - /* Get rrv_time header */ - if (info->control.use_cts_prot) { - if (info->control.use_rts) - size += sizeof(struct vnt_rrv_time_rts); - else - size += sizeof(struct vnt_rrv_time_cts); - } else { - size += sizeof(struct vnt_rrv_time_ab); - } - - size += sizeof(struct vnt_tx_fifo_head); - - return size; -} - -int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_rate *tx_rate = &info->control.rates[0]; - struct ieee80211_rate *rate; - struct ieee80211_hdr *hdr; - struct vnt_tx_buffer *tx_buffer; - struct vnt_tx_fifo_head *tx_buffer_head; - struct vnt_usb_send_context *tx_context; - unsigned long flags; - u8 pkt_type; - - hdr = (struct ieee80211_hdr *)(skb->data); - - rate = ieee80211_get_tx_rate(priv->hw, info); - - if (rate->hw_value > RATE_11M) { - if (info->band == NL80211_BAND_5GHZ) { - pkt_type = PK_TYPE_11A; - } else { - if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - if (priv->basic_rates & VNT_B_RATES) - pkt_type = PK_TYPE_11GB; - else - pkt_type = PK_TYPE_11GA; - } else { - pkt_type = PK_TYPE_11A; - } - } - } else { - pkt_type = PK_TYPE_11B; - } - - spin_lock_irqsave(&priv->lock, flags); - - tx_context = vnt_get_free_context(priv); - if (!tx_context) { - dev_dbg(&priv->usb->dev, "%s No free context\n", __func__); - spin_unlock_irqrestore(&priv->lock, flags); - return -ENOMEM; - } - - tx_context->pkt_type = pkt_type; - tx_context->frame_len = skb->len + 4; - tx_context->tx_rate = rate->hw_value; - - spin_unlock_irqrestore(&priv->lock, flags); - - tx_context->skb = skb_clone(skb, GFP_ATOMIC); - if (!tx_context->skb) { - tx_context->in_use = false; - return -ENOMEM; - } - - tx_buffer = skb_push(skb, vnt_get_hdr_size(info)); - tx_context->tx_buffer = tx_buffer; - tx_buffer_head = &tx_buffer->fifo_head; - - tx_context->type = CONTEXT_DATA_PACKET; - - /*Set fifo controls */ - if (pkt_type == PK_TYPE_11A) - tx_buffer_head->fifo_ctl = 0; - else if (pkt_type == PK_TYPE_11B) - tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11B); - else if (pkt_type == PK_TYPE_11GB) - tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11GB); - else if (pkt_type == PK_TYPE_11GA) - tx_buffer_head->fifo_ctl = cpu_to_le16(FIFOCTL_11GA); - - if (!ieee80211_is_data(hdr->frame_control)) { - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_GENINT | - FIFOCTL_ISDMA0); - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_TMOEN); - - tx_buffer_head->time_stamp = - cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us); - } else { - tx_buffer_head->time_stamp = - cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us); - } - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_NEEDACK); - - if (ieee80211_has_retry(hdr->frame_control)) - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_LRETRY); - - if (info->control.use_rts) - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_RTS); - - if (ieee80211_has_a4(hdr->frame_control)) - tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_LHEAD); - - tx_buffer_head->frag_ctl = - cpu_to_le16(ieee80211_hdrlen(hdr->frame_control) << 10); - - if (info->control.hw_key) - tx_context->frame_len += info->control.hw_key->icv_len; - - tx_buffer_head->current_rate = cpu_to_le16(rate->hw_value); - - vnt_generate_tx_parameter(tx_context); - - tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_NONFRAG); - - priv->seq_counter = (le16_to_cpu(hdr->seq_ctrl) & - IEEE80211_SCTL_SEQ) >> 4; - - spin_lock_irqsave(&priv->lock, flags); - - if (vnt_tx_context(priv, tx_context, skb)) { - dev_kfree_skb(tx_context->skb); - spin_unlock_irqrestore(&priv->lock, flags); - return -EIO; - } - - dev_kfree_skb(skb); - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static int vnt_beacon_xmit(struct vnt_private *priv, struct sk_buff *skb) -{ - struct vnt_tx_short_buf_head *short_head; - struct ieee80211_tx_info *info; - struct vnt_usb_send_context *context; - struct ieee80211_mgmt *mgmt_hdr; - unsigned long flags; - u32 frame_size = skb->len + 4; - u16 current_rate; - - spin_lock_irqsave(&priv->lock, flags); - - context = vnt_get_free_context(priv); - if (!context) { - dev_dbg(&priv->usb->dev, "%s No free context!\n", __func__); - spin_unlock_irqrestore(&priv->lock, flags); - return -ENOMEM; - } - - context->skb = skb; - - spin_unlock_irqrestore(&priv->lock, flags); - - mgmt_hdr = (struct ieee80211_mgmt *)skb->data; - short_head = skb_push(skb, sizeof(*short_head)); - - if (priv->bb_type == BB_TYPE_11A) { - current_rate = RATE_6M; - - /* Get SignalField,ServiceField,Length */ - vnt_get_phy_field(priv, frame_size, current_rate, - PK_TYPE_11A, &short_head->ab); - - /* Get TimeStampOff */ - short_head->time_stamp_off = - vnt_time_stamp_off(priv, current_rate); - } else { - current_rate = RATE_1M; - short_head->fifo_ctl |= cpu_to_le16(FIFOCTL_11B); - - /* Get SignalField,ServiceField,Length */ - vnt_get_phy_field(priv, frame_size, current_rate, - PK_TYPE_11B, &short_head->ab); - - /* Get TimeStampOff */ - short_head->time_stamp_off = - vnt_time_stamp_off(priv, current_rate); - } - - /* Get Duration */ - short_head->duration = mgmt_hdr->duration; - - /* time stamp always 0 */ - mgmt_hdr->u.beacon.timestamp = 0; - - info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)mgmt_hdr; - - hdr->duration_id = 0; - hdr->seq_ctrl = cpu_to_le16(priv->seq_counter << 4); - } - - priv->seq_counter++; - if (priv->seq_counter > 0x0fff) - priv->seq_counter = 0; - - context->type = CONTEXT_BEACON_PACKET; - - spin_lock_irqsave(&priv->lock, flags); - - if (vnt_tx_context(priv, context, skb)) - ieee80211_free_txskb(priv->hw, context->skb); - - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif) -{ - struct sk_buff *beacon; - - beacon = ieee80211_beacon_get(priv->hw, vif, 0); - if (!beacon) - return -ENOMEM; - - if (vnt_beacon_xmit(priv, beacon)) { - ieee80211_free_txskb(priv->hw, beacon); - return -ENODEV; - } - - return 0; -} - -int vnt_beacon_enable(struct vnt_private *priv, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf) -{ - vnt_mac_reg_bits_off(priv, MAC_REG_TCR, TCR_AUTOBCNTX); - - vnt_mac_reg_bits_off(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - - vnt_mac_set_beacon_interval(priv, conf->beacon_int); - - vnt_clear_current_tsf(priv); - - vnt_mac_reg_bits_on(priv, MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - - vnt_reset_next_tbtt(priv, conf->beacon_int); - - return vnt_beacon_make(priv, vif); -} diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h deleted file mode 100644 index b9df0854b4b011..00000000000000 --- a/drivers/staging/vt6656/rxtx.h +++ /dev/null @@ -1,178 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: - * - * Author: Jerry Chen - * - * Date: Jun. 27, 2002 - * - */ - -#ifndef __RXTX_H__ -#define __RXTX_H__ - -#include "device.h" -#include "wcmd.h" -#include "baseband.h" - -#define DEFAULT_MGN_LIFETIME_RES_64us 125 /* 64us */ -#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 - -/* Length, Service, and Signal fields of Phy for Tx */ -struct vnt_phy_field { - u8 signal; - u8 service; - __le16 len; -} __packed; - -/* MIC HDR data header */ -struct vnt_mic_hdr { - u8 id; - u8 tx_priority; - u8 mic_addr2[6]; - u8 ccmp_pn[IEEE80211_CCMP_PN_LEN]; - __be16 payload_len; - __be16 hlen; - __le16 frame_control; - u8 addr1[6]; - u8 addr2[6]; - u8 addr3[6]; - __le16 seq_ctrl; - u8 addr4[6]; - u16 packing; /* packing to 48 bytes */ -} __packed; - -/* RsvTime buffer header */ -struct vnt_rrv_time_rts { - __le16 rts_rrv_time_ba; - __le16 rts_rrv_time_aa; - __le16 rts_rrv_time_bb; - u16 wReserved; - __le16 rrv_time_b; - __le16 rrv_time_a; -} __packed; - -struct vnt_rrv_time_cts { - __le16 cts_rrv_time_ba; - u16 wReserved; - __le16 rrv_time_b; - __le16 rrv_time_a; -} __packed; - -struct vnt_rrv_time_ab { - __le16 rts_rrv_time; - __le16 rrv_time; -} __packed; - -/* TX data header */ -struct vnt_tx_datahead_g { - struct vnt_phy_field b; - struct vnt_phy_field a; - __le16 duration_b; - __le16 duration_a; - __le16 time_stamp_off_b; - __le16 time_stamp_off_a; -} __packed; - -struct vnt_tx_datahead_ab { - struct vnt_phy_field ab; - __le16 duration; - __le16 time_stamp_off; -} __packed; - -/* RTS buffer header */ -struct vnt_rts_g { - struct vnt_phy_field b; - struct vnt_phy_field a; - __le16 duration_ba; - __le16 duration_aa; - __le16 duration_bb; - u16 wReserved; - struct ieee80211_rts data; - struct vnt_tx_datahead_g data_head; -} __packed __aligned(2); - -struct vnt_rts_ab { - struct vnt_phy_field ab; - __le16 duration; - u16 wReserved; - struct ieee80211_rts data; - struct vnt_tx_datahead_ab data_head; -} __packed __aligned(2); - -/* CTS buffer header */ -struct vnt_cts { - struct vnt_phy_field b; - __le16 duration_ba; - u16 wReserved; - struct ieee80211_cts data; - u16 reserved2; - struct vnt_tx_datahead_g data_head; -} __packed __aligned(2); - -union vnt_tx_data_head { - /* rts g */ - struct vnt_rts_g rts_g; - /* rts a/b */ - struct vnt_rts_ab rts_ab; - /* cts g */ - struct vnt_cts cts_g; - /* no rts/cts */ - struct vnt_tx_datahead_ab data_head_ab; -}; - -struct vnt_tx_mic_hdr { - struct vnt_mic_hdr hdr; - union vnt_tx_data_head head; -} __packed; - -union vnt_tx { - struct vnt_tx_mic_hdr mic; - union vnt_tx_data_head head; -}; - -union vnt_tx_head { - struct { - struct vnt_rrv_time_rts rts; - union vnt_tx tx; - } __packed tx_rts; - struct { - struct vnt_rrv_time_cts cts; - union vnt_tx tx; - } __packed tx_cts; - struct { - struct vnt_rrv_time_ab ab; - union vnt_tx tx; - } __packed tx_ab; -}; - -struct vnt_tx_fifo_head { - u8 tx_key[WLAN_KEY_LEN_CCMP]; - __le16 fifo_ctl; - __le16 time_stamp; - __le16 frag_ctl; - __le16 current_rate; -} __packed; - -struct vnt_tx_buffer { - struct vnt_tx_fifo_head fifo_head; - union vnt_tx_head tx_head; -} __packed; - -struct vnt_tx_short_buf_head { - __le16 fifo_ctl; - u16 time_stamp; - struct vnt_phy_field ab; - __le16 duration; - __le16 time_stamp_off; -} __packed; - -int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb); -int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif); -int vnt_beacon_enable(struct vnt_private *priv, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *conf); - -#endif /* __RXTX_H__ */ diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c deleted file mode 100644 index d505b4b69ba493..00000000000000 --- a/drivers/staging/vt6656/usbpipe.c +++ /dev/null @@ -1,506 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Handle USB control endpoint - * - * Author: Warren Hsu - * - * Date: Mar. 29, 2005 - * - * Functions: - * vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM - * vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM - * vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM - * vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM - * - * Revision History: - * 04-05-2004 Jerry Chen: Initial release - * 11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte, - * ControlvMaskByte - * - */ - -#include "rxtx.h" -#include "desc.h" -#include "device.h" -#include "usbpipe.h" -#include "mac.h" -#include "rf.h" - -#define USB_CTL_WAIT 500 /* ms */ - -int vnt_control_out(struct vnt_private *priv, u8 request, u16 value, - u16 index, u16 length, const u8 *buffer) -{ - int ret = 0; - u8 *usb_buffer; - - if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) { - ret = -EINVAL; - goto end; - } - - mutex_lock(&priv->usb_lock); - - usb_buffer = kmemdup(buffer, length, GFP_KERNEL); - if (!usb_buffer) { - ret = -ENOMEM; - goto end_unlock; - } - - ret = usb_control_msg(priv->usb, - usb_sndctrlpipe(priv->usb, 0), - request, 0x40, value, - index, usb_buffer, length, USB_CTL_WAIT); - - kfree(usb_buffer); - - if (ret == (int)length) - ret = 0; - else - ret = -EIO; - -end_unlock: - mutex_unlock(&priv->usb_lock); -end: - return ret; -} - -int vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data) -{ - return vnt_control_out(priv, MESSAGE_TYPE_WRITE, - reg_off, reg, sizeof(u8), &data); -} - -int vnt_control_out_blocks(struct vnt_private *priv, - u16 block, u8 reg, u16 length, const u8 *data) -{ - int ret = 0, i; - - for (i = 0; i < length; i += block) { - u16 len = min_t(int, length - i, block); - - ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, - i, reg, len, data + i); - if (ret) - goto end; - } -end: - return ret; -} - -int vnt_control_in(struct vnt_private *priv, u8 request, u16 value, - u16 index, u16 length, u8 *buffer) -{ - int ret = 0; - u8 *usb_buffer; - - if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) { - ret = -EINVAL; - goto end; - } - - mutex_lock(&priv->usb_lock); - - usb_buffer = kmalloc(length, GFP_KERNEL); - if (!usb_buffer) { - ret = -ENOMEM; - goto end_unlock; - } - - ret = usb_control_msg(priv->usb, - usb_rcvctrlpipe(priv->usb, 0), - request, 0xc0, value, - index, usb_buffer, length, USB_CTL_WAIT); - - if (ret == length) - memcpy(buffer, usb_buffer, length); - - kfree(usb_buffer); - - if (ret == (int)length) - ret = 0; - else - ret = -EIO; - -end_unlock: - mutex_unlock(&priv->usb_lock); -end: - return ret; -} - -int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data) -{ - return vnt_control_in(priv, MESSAGE_TYPE_READ, - reg_off, reg, sizeof(u8), data); -} - -static int vnt_int_report_rate(struct vnt_private *priv, u8 pkt_no, u8 tsr) -{ - struct vnt_usb_send_context *context; - struct ieee80211_tx_info *info; - u8 tx_retry = (tsr & 0xf0) >> 4; - s8 idx; - - if (pkt_no >= priv->num_tx_context) - return -EINVAL; - - context = priv->tx_context[pkt_no]; - - if (!context->skb) - return -EINVAL; - - info = IEEE80211_SKB_CB(context->skb); - idx = info->control.rates[0].idx; - - ieee80211_tx_info_clear_status(info); - - info->status.rates[0].count = tx_retry; - - if (!(tsr & TSR_TMO)) { - info->status.rates[0].idx = idx; - - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_ACK; - } - - ieee80211_tx_status_irqsafe(priv->hw, context->skb); - - context->in_use = false; - - return 0; -} - -static void vnt_int_process_data(struct vnt_private *priv) -{ - struct vnt_interrupt_data *int_data; - struct ieee80211_low_level_stats *low_stats = &priv->low_stats; - - dev_dbg(&priv->usb->dev, "---->s_nsInterruptProcessData\n"); - - int_data = (struct vnt_interrupt_data *)priv->int_buf.data_buf; - - if (int_data->tsr0 & TSR_VALID) - vnt_int_report_rate(priv, int_data->pkt0, int_data->tsr0); - - if (int_data->tsr1 & TSR_VALID) - vnt_int_report_rate(priv, int_data->pkt1, int_data->tsr1); - - if (int_data->tsr2 & TSR_VALID) - vnt_int_report_rate(priv, int_data->pkt2, int_data->tsr2); - - if (int_data->tsr3 & TSR_VALID) - vnt_int_report_rate(priv, int_data->pkt3, int_data->tsr3); - - if (!int_data->isr0) - return; - - if (int_data->isr0 & ISR_BNTX && priv->op_mode == NL80211_IFTYPE_AP) - vnt_schedule_command(priv, WLAN_CMD_BECON_SEND); - - priv->current_tsf = le64_to_cpu(int_data->tsf); - - low_stats->dot11RTSSuccessCount += int_data->rts_success; - low_stats->dot11RTSFailureCount += int_data->rts_fail; - low_stats->dot11ACKFailureCount += int_data->ack_fail; - low_stats->dot11FCSErrorCount += int_data->fcs_err; -} - -static void vnt_start_interrupt_urb_complete(struct urb *urb) -{ - struct vnt_private *priv = urb->context; - int status = urb->status; - - switch (status) { - case 0: - case -ETIMEDOUT: - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - return; - default: - break; - } - - if (status) - dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status); - else - vnt_int_process_data(priv); - - if (!test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) - status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); - - if (status) - dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status); -} - -int vnt_start_interrupt_urb(struct vnt_private *priv) -{ - int ret = 0; - - dev_dbg(&priv->usb->dev, "---->Interrupt Polling Thread\n"); - - usb_fill_int_urb(priv->interrupt_urb, - priv->usb, - usb_rcvintpipe(priv->usb, 1), - priv->int_buf.data_buf, - MAX_INTERRUPT_SIZE, - vnt_start_interrupt_urb_complete, - priv, - priv->int_interval); - - ret = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC); - if (ret) - dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", ret); - - return ret; -} - -static int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb, - unsigned long bytes_received) -{ - struct ieee80211_hw *hw = priv->hw; - struct ieee80211_supported_band *sband; - struct sk_buff *skb; - struct ieee80211_rx_status *rx_status; - struct vnt_rx_header *head; - struct vnt_rx_tail *tail; - u32 frame_size; - int ii; - u16 rx_bitrate, pay_load_with_padding; - u8 rate_idx = 0; - long rx_dbm; - - skb = ptr_rcb->skb; - rx_status = IEEE80211_SKB_RXCB(skb); - - /* [31:16]RcvByteCount ( not include 4-byte Status ) */ - head = (struct vnt_rx_header *)skb->data; - frame_size = head->wbk_status >> 16; - frame_size += 4; - - if (bytes_received != frame_size) { - dev_dbg(&priv->usb->dev, "------- WRONG Length 1\n"); - return false; - } - - if ((bytes_received > 2372) || (bytes_received <= 40)) { - /* Frame Size error drop this packet.*/ - dev_dbg(&priv->usb->dev, "------ WRONG Length 2\n"); - return false; - } - - /* real Frame Size = USBframe_size -4WbkStatus - 4RxStatus */ - /* -8TSF - 4RSR - 4SQ3 - ?Padding */ - - /* if SQ3 the range is 24~27, if no SQ3 the range is 20~23 */ - - /*Fix hardware bug => PLCP_Length error */ - if (((bytes_received - head->pay_load_len) > 27) || - ((bytes_received - head->pay_load_len) < 24) || - (bytes_received < head->pay_load_len)) { - dev_dbg(&priv->usb->dev, "Wrong PLCP Length %x\n", - head->pay_load_len); - return false; - } - - sband = hw->wiphy->bands[hw->conf.chandef.chan->band]; - rx_bitrate = head->rx_rate * 5; /* rx_rate * 5 */ - - for (ii = 0; ii < sband->n_bitrates; ii++) { - if (sband->bitrates[ii].bitrate == rx_bitrate) { - rate_idx = ii; - break; - } - } - - if (ii == sband->n_bitrates) { - dev_dbg(&priv->usb->dev, "Wrong Rx Bit Rate %d\n", rx_bitrate); - return false; - } - - pay_load_with_padding = ((head->pay_load_len / 4) + - ((head->pay_load_len % 4) ? 1 : 0)) * 4; - - tail = (struct vnt_rx_tail *)(skb->data + - sizeof(*head) + pay_load_with_padding); - priv->tsf_time = le64_to_cpu(tail->tsf_time); - - if (tail->rsr & (RSR_IVLDTYP | RSR_IVLDLEN)) - return false; - - vnt_rf_rssi_to_dbm(priv, tail->rssi, &rx_dbm); - - priv->bb_pre_ed_rssi = (u8)-rx_dbm + 1; - priv->current_rssi = priv->bb_pre_ed_rssi; - - skb_pull(skb, sizeof(*head)); - skb_trim(skb, head->pay_load_len); - - rx_status->mactime = priv->tsf_time; - rx_status->band = hw->conf.chandef.chan->band; - rx_status->signal = rx_dbm; - rx_status->flag = 0; - rx_status->freq = hw->conf.chandef.chan->center_freq; - - if (!(tail->rsr & RSR_CRCOK)) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - - rx_status->rate_idx = rate_idx; - - if (tail->new_rsr & NEWRSR_DECRYPTOK) - rx_status->flag |= RX_FLAG_DECRYPTED; - - ieee80211_rx_irqsafe(priv->hw, skb); - - return true; -} - -static void vnt_submit_rx_urb_complete(struct urb *urb) -{ - struct vnt_rcb *rcb = urb->context; - struct vnt_private *priv = rcb->priv; - - switch (urb->status) { - case 0: - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - return; - case -ETIMEDOUT: - default: - dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status); - break; - } - - if (urb->actual_length) { - if (vnt_rx_data(priv, rcb, urb->actual_length)) { - rcb->skb = dev_alloc_skb(priv->rx_buf_sz); - if (!rcb->skb) - return; - } else { - skb_push(rcb->skb, skb_headroom(rcb->skb)); - skb_trim(rcb->skb, 0); - } - - urb->transfer_buffer = skb_put(rcb->skb, - skb_tailroom(rcb->skb)); - } - - if (usb_submit_urb(urb, GFP_ATOMIC)) - dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n"); -} - -int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb) -{ - int ret = 0; - struct urb *urb = rcb->urb; - - if (!rcb->skb) { - dev_dbg(&priv->usb->dev, "rcb->skb is null\n"); - ret = -EINVAL; - goto end; - } - - usb_fill_bulk_urb(urb, - priv->usb, - usb_rcvbulkpipe(priv->usb, 2), - skb_put(rcb->skb, skb_tailroom(rcb->skb)), - MAX_TOTAL_SIZE_WITH_ALL_HEADERS, - vnt_submit_rx_urb_complete, - rcb); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", ret); -end: - return ret; -} - -static void vnt_tx_context_complete(struct urb *urb) -{ - struct vnt_usb_send_context *context = urb->context; - struct vnt_private *priv = context->priv; - - switch (urb->status) { - case 0: - dev_dbg(&priv->usb->dev, - "Write %d bytes\n", urb->actual_length); - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - context->in_use = false; - return; - case -ETIMEDOUT: - default: - dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status); - break; - } - - if (context->type == CONTEXT_DATA_PACKET) - ieee80211_wake_queues(priv->hw); - - if (urb->status || context->type == CONTEXT_BEACON_PACKET) { - if (context->skb) - ieee80211_free_txskb(priv->hw, context->skb); - - context->in_use = false; - } -} - -int vnt_tx_context(struct vnt_private *priv, - struct vnt_usb_send_context *context, - struct sk_buff *skb) -{ - struct vnt_tx_usb_header *usb; - struct urb *urb; - int status; - u16 count = skb->len; - - usb = skb_push(skb, sizeof(*usb)); - usb->tx_byte_count = cpu_to_le16(count); - usb->pkt_no = context->pkt_no; - usb->type = context->type; - - if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) { - context->in_use = false; - return -ENODEV; - } - - if (skb->len > MAX_TOTAL_SIZE_WITH_ALL_HEADERS) { - context->in_use = false; - return -E2BIG; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - context->in_use = false; - return -ENOMEM; - } - - usb_fill_bulk_urb(urb, - priv->usb, - usb_sndbulkpipe(priv->usb, 3), - skb->data, - skb->len, - vnt_tx_context_complete, - context); - - usb_anchor_urb(urb, &priv->tx_submitted); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status); - usb_unanchor_urb(urb); - context->in_use = false; - } - - usb_free_urb(urb); - - return status; -} diff --git a/drivers/staging/vt6656/usbpipe.h b/drivers/staging/vt6656/usbpipe.h deleted file mode 100644 index 922312e299bf64..00000000000000 --- a/drivers/staging/vt6656/usbpipe.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: - * - * Author: Warren Hsu - * - * Date: Mar. 30, 2005 - * - */ - -#ifndef __USBPIPE_H__ -#define __USBPIPE_H__ - -#include "device.h" - -struct vnt_interrupt_data { - u8 tsr0; - u8 pkt0; - u16 time0; - u8 tsr1; - u8 pkt1; - u16 time1; - u8 tsr2; - u8 pkt2; - u16 time2; - u8 tsr3; - u8 pkt3; - u16 time3; - __le64 tsf; - u8 isr0; - u8 isr1; - u8 rts_success; - u8 rts_fail; - u8 ack_fail; - u8 fcs_err; - u8 sw[2]; -} __packed; - -struct vnt_tx_usb_header { - u8 type; - u8 pkt_no; - __le16 tx_byte_count; -} __packed; - -#define VNT_REG_BLOCK_SIZE 64 - -int vnt_control_out(struct vnt_private *priv, u8 request, u16 value, - u16 index, u16 length, const u8 *buffer); -int vnt_control_in(struct vnt_private *priv, u8 request, u16 value, - u16 index, u16 length, u8 *buffer); - -int vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 ref_off, u8 data); -int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data); - -int vnt_control_out_blocks(struct vnt_private *priv, - u16 block, u8 reg, u16 len, const u8 *data); - -int vnt_start_interrupt_urb(struct vnt_private *priv); -int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb); -int vnt_tx_context(struct vnt_private *priv, - struct vnt_usb_send_context *context, - struct sk_buff *skb); - -#endif /* __USBPIPE_H__ */ diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c deleted file mode 100644 index 14b8aa58711906..00000000000000 --- a/drivers/staging/vt6656/wcmd.c +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Handles the management command interface functions - * - * Author: Lyndon Chen - * - * Date: May 8, 2003 - * - * Functions: - * vnt_cmd_complete - Command Complete function - * vnt_schedule_command - Push Command and wait Command Scheduler to do - * vnt_cmd_timer_wait- Call back timer - * - * Revision History: - * - */ - -#include "device.h" -#include "mac.h" -#include "wcmd.h" -#include "power.h" -#include "usbpipe.h" -#include "rxtx.h" -#include "rf.h" - -static void vnt_cmd_timer_wait(struct vnt_private *priv, unsigned long msecs) -{ - schedule_delayed_work(&priv->run_command_work, msecs_to_jiffies(msecs)); -} - -static u32 add_one_with_wrap_around(u32 var, u8 modulo) -{ - if (var >= (modulo - 1)) - var = 0; - else - var++; - return var; -} - -static int vnt_cmd_complete(struct vnt_private *priv) -{ - priv->command_state = WLAN_CMD_IDLE; - if (priv->free_cmd_queue == CMD_Q_SIZE) { - /* Command Queue Empty */ - priv->cmd_running = false; - return true; - } - - priv->command = priv->cmd_queue[priv->cmd_dequeue_idx]; - - priv->cmd_dequeue_idx = add_one_with_wrap_around(priv->cmd_dequeue_idx, CMD_Q_SIZE); - priv->free_cmd_queue++; - priv->cmd_running = true; - - switch (priv->command) { - case WLAN_CMD_INIT_MAC80211: - priv->command_state = WLAN_CMD_INIT_MAC80211_START; - break; - - case WLAN_CMD_TBTT_WAKEUP: - priv->command_state = WLAN_CMD_TBTT_WAKEUP_START; - break; - - case WLAN_CMD_BECON_SEND: - priv->command_state = WLAN_CMD_BECON_SEND_START; - break; - - case WLAN_CMD_SETPOWER: - priv->command_state = WLAN_CMD_SETPOWER_START; - break; - - case WLAN_CMD_CHANGE_ANTENNA: - priv->command_state = WLAN_CMD_CHANGE_ANTENNA_START; - break; - - default: - break; - } - - vnt_cmd_timer_wait(priv, 0); - - return true; -} - -void vnt_run_command(struct work_struct *work) -{ - struct vnt_private *priv = - container_of(work, struct vnt_private, run_command_work.work); - - if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) - return; - - if (!priv->cmd_running) - return; - - switch (priv->command_state) { - case WLAN_CMD_INIT_MAC80211_START: - if (priv->mac_hw) - break; - - dev_info(&priv->usb->dev, "Starting mac80211\n"); - - if (vnt_init(priv)) { - /* If fail all ends TODO retry */ - dev_err(&priv->usb->dev, "failed to start\n"); - usb_set_intfdata(priv->intf, NULL); - ieee80211_free_hw(priv->hw); - return; - } - - break; - - case WLAN_CMD_TBTT_WAKEUP_START: - vnt_next_tbtt_wakeup(priv); - break; - - case WLAN_CMD_BECON_SEND_START: - if (!priv->vif) - break; - - vnt_beacon_make(priv, priv->vif); - - vnt_mac_reg_bits_on(priv, MAC_REG_TCR, TCR_AUTOBCNTX); - - break; - - case WLAN_CMD_SETPOWER_START: - - vnt_rf_setpower(priv, priv->hw->conf.chandef.chan); - - break; - - case WLAN_CMD_CHANGE_ANTENNA_START: - dev_dbg(&priv->usb->dev, "Change from Antenna%d to", - priv->rx_antenna_sel); - - if (priv->rx_antenna_sel == 0) { - priv->rx_antenna_sel = 1; - if (priv->tx_rx_ant_inv) - vnt_set_antenna_mode(priv, ANT_RXA); - else - vnt_set_antenna_mode(priv, ANT_RXB); - } else { - priv->rx_antenna_sel = 0; - if (priv->tx_rx_ant_inv) - vnt_set_antenna_mode(priv, ANT_RXB); - else - vnt_set_antenna_mode(priv, ANT_RXA); - } - break; - - default: - break; - } - - vnt_cmd_complete(priv); -} - -int vnt_schedule_command(struct vnt_private *priv, enum vnt_cmd command) -{ - if (priv->free_cmd_queue == 0) - return false; - - priv->cmd_queue[priv->cmd_enqueue_idx] = command; - - priv->cmd_enqueue_idx = add_one_with_wrap_around(priv->cmd_enqueue_idx, CMD_Q_SIZE); - priv->free_cmd_queue--; - - if (!priv->cmd_running) - vnt_cmd_complete(priv); - - return true; -} - -void vnt_reset_command_timer(struct vnt_private *priv) -{ - priv->free_cmd_queue = CMD_Q_SIZE; - priv->cmd_dequeue_idx = 0; - priv->cmd_enqueue_idx = 0; - priv->command_state = WLAN_CMD_IDLE; - priv->cmd_running = false; -} diff --git a/drivers/staging/vt6656/wcmd.h b/drivers/staging/vt6656/wcmd.h deleted file mode 100644 index a62924671b17e6..00000000000000 --- a/drivers/staging/vt6656/wcmd.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Handles the management command interface functions - * - * Author: Lyndon Chen - * - * Date: May 8, 2002 - * - */ - -#ifndef __WCMD_H__ -#define __WCMD_H__ - -#include "device.h" - -/* Command code */ -enum vnt_cmd { - WLAN_CMD_INIT_MAC80211, - WLAN_CMD_SETPOWER, - WLAN_CMD_TBTT_WAKEUP, - WLAN_CMD_BECON_SEND, - WLAN_CMD_CHANGE_ANTENNA -}; - -#define CMD_Q_SIZE 32 - -/* Command state */ -enum vnt_cmd_state { - WLAN_CMD_INIT_MAC80211_START, - WLAN_CMD_SETPOWER_START, - WLAN_CMD_TBTT_WAKEUP_START, - WLAN_CMD_BECON_SEND_START, - WLAN_CMD_CHANGE_ANTENNA_START, - WLAN_CMD_IDLE -}; - -struct vnt_private; - -void vnt_reset_command_timer(struct vnt_private *priv); - -int vnt_schedule_command(struct vnt_private *priv, enum vnt_cmd); - -void vnt_run_command(struct work_struct *work); - -#endif /* __WCMD_H__ */ diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 440e07b1d5cdb1..287ac5b0495f9a 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -369,7 +369,7 @@ static int pscsi_create_type_disk(struct se_device *dev, struct scsi_device *sd) bdev_file = bdev_file_open_by_path(dev->udev_path, BLK_OPEN_WRITE | BLK_OPEN_READ, pdv, NULL); if (IS_ERR(bdev_file)) { - pr_err("pSCSI: bdev_open_by_path() failed\n"); + pr_err("pSCSI: bdev_file_open_by_path() failed\n"); scsi_device_put(sd); return PTR_ERR(bdev_file); } diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 717931267bda0c..0f5d820af1194d 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -361,7 +361,7 @@ static const struct genl_multicast_group tcmu_mcgrps[] = { [TCMU_MCGRP_CONFIG] = { .name = "config", }, }; -static struct nla_policy tcmu_attr_policy[TCMU_ATTR_MAX+1] = { +static const struct nla_policy tcmu_attr_policy[TCMU_ATTR_MAX + 1] = { [TCMU_ATTR_DEVICE] = { .type = NLA_STRING }, [TCMU_ATTR_MINOR] = { .type = NLA_U32 }, [TCMU_ATTR_CMD_STATUS] = { .type = NLA_S32 }, @@ -2430,7 +2430,7 @@ enum { Opt_cmd_ring_size_mb, Opt_err, }; -static match_table_t tokens = { +static const match_table_t tokens = { {Opt_dev_config, "dev_config=%s"}, {Opt_dev_size, "dev_size=%s"}, {Opt_hw_block_size, "hw_block_size=%d"}, diff --git a/drivers/tc/tc.c b/drivers/tc/tc.c index c5b17dd8f587a9..0629f277f7b43b 100644 --- a/drivers/tc/tc.c +++ b/drivers/tc/tc.c @@ -162,7 +162,7 @@ static int __init tc_init(void) if (tc_bus.info.slot_size) { unsigned int tc_clock = tc_get_speed(&tc_bus) / 100000; - pr_info("tc: TURBOchannel rev. %d at %d.%d MHz " + pr_info("tc: TURBOchannel rev. %d at %u.%u MHz " "(with%s parity)\n", tc_bus.info.revision, tc_clock / 10, tc_clock % 10, tc_bus.info.parity ? "" : "out"); diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c index e9456e3e74ccaa..3e33cf2af73bbf 100644 --- a/drivers/tee/optee/smc_abi.c +++ b/drivers/tee/optee/smc_abi.c @@ -1817,7 +1817,7 @@ MODULE_DEVICE_TABLE(of, optee_dt_match); static struct platform_driver optee_driver = { .probe = optee_probe, - .remove_new = optee_smc_remove, + .remove = optee_smc_remove, .shutdown = optee_shutdown, .driver = { .name = "optee", diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 61e7ae524b1f85..d3f9686e26e710 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -220,6 +220,15 @@ config DEVFREQ_THERMAL If you want this support, you should say Y here. +config PCIE_THERMAL + bool "PCIe cooling support" + depends on PCIEPORTBUS + help + This implements PCIe cooling mechanism through bandwidth reduction + for PCIe devices. + + If you want this support, you should say Y here. + config THERMAL_EMULATION bool "Thermal emulation mode support" help diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 41c4d56beb40d0..9abf43a74f2bbd 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -6,6 +6,7 @@ CFLAGS_thermal_core.o := -I$(src) obj-$(CONFIG_THERMAL) += thermal_sys.o thermal_sys-y += thermal_core.o thermal_sysfs.o thermal_sys-y += thermal_trip.o thermal_helpers.o +thermal_sys-y += thermal_thresholds.o # netlink interface to manage the thermal framework thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o @@ -31,6 +32,8 @@ thermal_sys-$(CONFIG_CPU_IDLE_THERMAL) += cpuidle_cooling.o # devfreq cooling thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o +thermal_sys-$(CONFIG_PCIE_THERMAL) += pcie_cooling.o + obj-$(CONFIG_K3_THERMAL) += k3_bandgap.o k3_j72xx_bandgap.o # platform thermal drivers obj-y += broadcom/ diff --git a/drivers/thermal/amlogic_thermal.c b/drivers/thermal/amlogic_thermal.c index cd4776aa805e05..3c5f7dbddf2c1f 100644 --- a/drivers/thermal/amlogic_thermal.c +++ b/drivers/thermal/amlogic_thermal.c @@ -333,7 +333,7 @@ static struct platform_driver amlogic_thermal_driver = { .of_match_table = of_amlogic_thermal_match, }, .probe = amlogic_thermal_probe, - .remove_new = amlogic_thermal_remove, + .remove = amlogic_thermal_remove, }; module_platform_driver(amlogic_thermal_driver); diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index fdcb077cfd54e7..9bff21068721cb 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c @@ -970,7 +970,7 @@ static void armada_thermal_exit(struct platform_device *pdev) static struct platform_driver armada_thermal_driver = { .probe = armada_thermal_probe, - .remove_new = armada_thermal_exit, + .remove = armada_thermal_exit, .driver = { .name = "armada_thermal", .of_match_table = armada_thermal_id_table, diff --git a/drivers/thermal/broadcom/bcm2835_thermal.c b/drivers/thermal/broadcom/bcm2835_thermal.c index 7d61493082b5a0..7fbba2233c4c12 100644 --- a/drivers/thermal/broadcom/bcm2835_thermal.c +++ b/drivers/thermal/broadcom/bcm2835_thermal.c @@ -268,7 +268,7 @@ static void bcm2835_thermal_remove(struct platform_device *pdev) static struct platform_driver bcm2835_thermal_driver = { .probe = bcm2835_thermal_probe, - .remove_new = bcm2835_thermal_remove, + .remove = bcm2835_thermal_remove, .driver = { .name = "bcm2835_thermal", .of_match_table = bcm2835_thermal_of_match_table, diff --git a/drivers/thermal/broadcom/ns-thermal.c b/drivers/thermal/broadcom/ns-thermal.c index 5eaf79c490f0f6..8b5b32f749ee89 100644 --- a/drivers/thermal/broadcom/ns-thermal.c +++ b/drivers/thermal/broadcom/ns-thermal.c @@ -80,7 +80,7 @@ MODULE_DEVICE_TABLE(of, ns_thermal_of_match); static struct platform_driver ns_thermal_driver = { .probe = ns_thermal_probe, - .remove_new = ns_thermal_remove, + .remove = ns_thermal_remove, .driver = { .name = "ns-thermal", .of_match_table = ns_thermal_of_match, diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c index a27aff88cd96cb..2077e85ef5caec 100644 --- a/drivers/thermal/da9062-thermal.c +++ b/drivers/thermal/da9062-thermal.c @@ -250,10 +250,10 @@ static void da9062_thermal_remove(struct platform_device *pdev) static struct platform_driver da9062_thermal_driver = { .probe = da9062_thermal_probe, - .remove_new = da9062_thermal_remove, + .remove = da9062_thermal_remove, .driver = { - .name = "da9062-thermal", - .of_match_table = da9062_compatible_reg_id_table, + .name = "da9062-thermal", + .of_match_table = da9062_compatible_reg_id_table, }, }; diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c index ac30de3c0a5fb9..f9157a47156b08 100644 --- a/drivers/thermal/dove_thermal.c +++ b/drivers/thermal/dove_thermal.c @@ -170,7 +170,7 @@ MODULE_DEVICE_TABLE(of, dove_thermal_id_table); static struct platform_driver dove_thermal_driver = { .probe = dove_thermal_probe, - .remove_new = dove_thermal_exit, + .remove = dove_thermal_exit, .driver = { .name = "dove_thermal", .of_match_table = dove_thermal_id_table, diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index 863e7a4272e66f..97f3d819852b2f 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c @@ -30,9 +30,7 @@ static void bang_bang_set_instance_target(struct thermal_instance *instance, dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target); - mutex_lock(&instance->cdev->lock); - __thermal_cdev_update(instance->cdev); - mutex_unlock(&instance->cdev->lock); + thermal_cdev_update_nocheck(instance->cdev); } /** @@ -67,6 +65,7 @@ static void bang_bang_control(struct thermal_zone_device *tz, const struct thermal_trip *trip, bool crossed_up) { + const struct thermal_trip_desc *td = trip_to_trip_desc(trip); struct thermal_instance *instance; lockdep_assert_held(&tz->lock); @@ -75,10 +74,8 @@ static void bang_bang_control(struct thermal_zone_device *tz, thermal_zone_trip_id(tz, trip), trip->temperature, tz->temperature, trip->hysteresis); - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - if (instance->trip == trip) - bang_bang_set_instance_target(instance, crossed_up); - } + list_for_each_entry(instance, &td->thermal_instances, trip_node) + bang_bang_set_instance_target(instance, crossed_up); } static void bang_bang_manage(struct thermal_zone_device *tz) @@ -104,8 +101,8 @@ static void bang_bang_manage(struct thermal_zone_device *tz) * to the thermal zone temperature and the trip point threshold. */ turn_on = tz->temperature >= td->threshold; - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - if (!instance->initialized && instance->trip == trip) + list_for_each_entry(instance, &td->thermal_instances, trip_node) { + if (!instance->initialized) bang_bang_set_instance_target(instance, turn_on); } } diff --git a/drivers/thermal/gov_fair_share.c b/drivers/thermal/gov_fair_share.c index ce0ea571ed67ab..4643be4f941db8 100644 --- a/drivers/thermal/gov_fair_share.c +++ b/drivers/thermal/gov_fair_share.c @@ -44,7 +44,7 @@ static int get_trip_level(struct thermal_zone_device *tz) /** * fair_share_throttle - throttles devices associated with the given zone * @tz: thermal_zone_device - * @trip: trip point + * @td: trip point descriptor * @trip_level: number of trips crossed by the zone temperature * * Throttling Logic: This uses three parameters to calculate the new @@ -61,29 +61,23 @@ static int get_trip_level(struct thermal_zone_device *tz) * new_state of cooling device = P3 * P2 * P1 */ static void fair_share_throttle(struct thermal_zone_device *tz, - const struct thermal_trip *trip, + const struct thermal_trip_desc *td, int trip_level) { struct thermal_instance *instance; int total_weight = 0; int nr_instances = 0; - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - if (instance->trip != trip) - continue; - + list_for_each_entry(instance, &td->thermal_instances, trip_node) { total_weight += instance->weight; nr_instances++; } - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { + list_for_each_entry(instance, &td->thermal_instances, trip_node) { struct thermal_cooling_device *cdev = instance->cdev; u64 dividend; u32 divisor; - if (instance->trip != trip) - continue; - dividend = trip_level; dividend *= cdev->max_state; divisor = tz->num_trips; @@ -95,9 +89,7 @@ static void fair_share_throttle(struct thermal_zone_device *tz, } instance->target = div_u64(dividend, divisor); - mutex_lock(&cdev->lock); - __thermal_cdev_update(cdev); - mutex_unlock(&cdev->lock); + thermal_cdev_update_nocheck(cdev); } } @@ -116,7 +108,7 @@ static void fair_share_manage(struct thermal_zone_device *tz) trip->type == THERMAL_TRIP_HOT) continue; - fair_share_throttle(tz, trip, trip_level); + fair_share_throttle(tz, td, trip_level); } } diff --git a/drivers/thermal/gov_power_allocator.c b/drivers/thermal/gov_power_allocator.c index 1b2345a697c5a0..3b644de3292e2e 100644 --- a/drivers/thermal/gov_power_allocator.c +++ b/drivers/thermal/gov_power_allocator.c @@ -97,11 +97,9 @@ struct power_allocator_params { struct power_actor *power; }; -static bool power_actor_is_valid(struct power_allocator_params *params, - struct thermal_instance *instance) +static bool power_actor_is_valid(struct thermal_instance *instance) { - return (instance->trip == params->trip_max && - cdev_is_power_actor(instance->cdev)); + return cdev_is_power_actor(instance->cdev); } /** @@ -118,13 +116,14 @@ static bool power_actor_is_valid(struct power_allocator_params *params, static u32 estimate_sustainable_power(struct thermal_zone_device *tz) { struct power_allocator_params *params = tz->governor_data; + const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max); struct thermal_cooling_device *cdev; struct thermal_instance *instance; u32 sustainable_power = 0; u32 min_power; - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - if (!power_actor_is_valid(params, instance)) + list_for_each_entry(instance, &td->thermal_instances, trip_node) { + if (!power_actor_is_valid(instance)) continue; cdev = instance->cdev; @@ -323,9 +322,8 @@ power_actor_set_power(struct thermal_cooling_device *cdev, return ret; instance->target = clamp_val(state, instance->lower, instance->upper); - mutex_lock(&cdev->lock); - __thermal_cdev_update(cdev); - mutex_unlock(&cdev->lock); + + thermal_cdev_update_nocheck(cdev); return 0; } @@ -356,11 +354,19 @@ static void divvy_up_power(struct power_actor *power, int num_actors, u32 extra_power = 0; int i; - /* - * Prevent division by 0 if none of the actors request power. - */ - if (!total_req_power) - total_req_power = 1; + if (!total_req_power) { + /* + * Nobody requested anything, just give everybody + * the maximum power + */ + for (i = 0; i < num_actors; i++) { + struct power_actor *pa = &power[i]; + + pa->granted_power = pa->max_power; + } + + return; + } for (i = 0; i < num_actors; i++) { struct power_actor *pa = &power[i]; @@ -400,6 +406,7 @@ static void divvy_up_power(struct power_actor *power, int num_actors, static void allocate_power(struct thermal_zone_device *tz, int control_temp) { struct power_allocator_params *params = tz->governor_data; + const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max); unsigned int num_actors = params->num_actors; struct power_actor *power = params->power; struct thermal_cooling_device *cdev; @@ -417,10 +424,10 @@ static void allocate_power(struct thermal_zone_device *tz, int control_temp) /* Clean all buffers for new power estimations */ memset(power, 0, params->buffer_size); - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { + list_for_each_entry(instance, &td->thermal_instances, trip_node) { struct power_actor *pa = &power[i]; - if (!power_actor_is_valid(params, instance)) + if (!power_actor_is_valid(instance)) continue; cdev = instance->cdev; @@ -454,10 +461,10 @@ static void allocate_power(struct thermal_zone_device *tz, int control_temp) power_range); i = 0; - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { + list_for_each_entry(instance, &td->thermal_instances, trip_node) { struct power_actor *pa = &power[i]; - if (!power_actor_is_valid(params, instance)) + if (!power_actor_is_valid(instance)) continue; power_actor_set_power(instance->cdev, instance, @@ -538,29 +545,29 @@ static void reset_pid_controller(struct power_allocator_params *params) static void allow_maximum_power(struct thermal_zone_device *tz) { struct power_allocator_params *params = tz->governor_data; + const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max); struct thermal_cooling_device *cdev; struct thermal_instance *instance; u32 req_power; - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - if (!power_actor_is_valid(params, instance)) + list_for_each_entry(instance, &td->thermal_instances, trip_node) { + if (!power_actor_is_valid(instance)) continue; cdev = instance->cdev; instance->target = 0; - mutex_lock(&cdev->lock); - /* - * Call for updating the cooling devices local stats and avoid - * periods of dozen of seconds when those have not been - * maintained. - */ - cdev->ops->get_requested_power(cdev, &req_power); - - if (params->update_cdevs) - __thermal_cdev_update(cdev); - - mutex_unlock(&cdev->lock); + scoped_guard(cooling_dev, cdev) { + /* + * Call for updating the cooling devices local stats and + * avoid periods of dozen of seconds when those have not + * been maintained. + */ + cdev->ops->get_requested_power(cdev, &req_power); + + if (params->update_cdevs) + __thermal_cdev_update(cdev); + } } } @@ -581,13 +588,16 @@ static void allow_maximum_power(struct thermal_zone_device *tz) static int check_power_actors(struct thermal_zone_device *tz, struct power_allocator_params *params) { + const struct thermal_trip_desc *td; struct thermal_instance *instance; int ret = 0; - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - if (instance->trip != params->trip_max) - continue; + if (!params->trip_max) + return 0; + + td = trip_to_trip_desc(params->trip_max); + list_for_each_entry(instance, &td->thermal_instances, trip_node) { if (!cdev_is_power_actor(instance->cdev)) { dev_warn(&tz->device, "power_allocator: %s is not a power actor\n", instance->cdev->type); @@ -635,14 +645,15 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz, enum thermal_notify_event reason) { struct power_allocator_params *params = tz->governor_data; + const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max); struct thermal_instance *instance; int num_actors = 0; switch (reason) { case THERMAL_TZ_BIND_CDEV: case THERMAL_TZ_UNBIND_CDEV: - list_for_each_entry(instance, &tz->thermal_instances, tz_node) - if (power_actor_is_valid(params, instance)) + list_for_each_entry(instance, &td->thermal_instances, trip_node) + if (power_actor_is_valid(instance)) num_actors++; if (num_actors == params->num_actors) @@ -652,8 +663,8 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz, break; case THERMAL_INSTANCE_WEIGHT_CHANGED: params->total_weight = 0; - list_for_each_entry(instance, &tz->thermal_instances, tz_node) - if (power_actor_is_valid(params, instance)) + list_for_each_entry(instance, &td->thermal_instances, trip_node) + if (power_actor_is_valid(instance)) params->total_weight += instance->weight; break; default: diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c index fd5527188cf91a..d1bb59f1dfbd39 100644 --- a/drivers/thermal/gov_step_wise.c +++ b/drivers/thermal/gov_step_wise.c @@ -66,9 +66,10 @@ static unsigned long get_target_state(struct thermal_instance *instance, } static void thermal_zone_trip_update(struct thermal_zone_device *tz, - const struct thermal_trip *trip, + const struct thermal_trip_desc *td, int trip_threshold) { + const struct thermal_trip *trip = &td->trip; enum thermal_trend trend = get_tz_trend(tz, trip); int trip_id = thermal_zone_trip_id(tz, trip); struct thermal_instance *instance; @@ -82,12 +83,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", trip_id, trip->type, trip_threshold, trend, throttle); - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { + list_for_each_entry(instance, &td->thermal_instances, trip_node) { int old_target; - if (instance->trip != trip) - continue; - old_target = instance->target; instance->target = get_target_state(instance, trend, throttle); @@ -99,9 +97,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, instance->initialized = true; - mutex_lock(&instance->cdev->lock); - instance->cdev->updated = false; /* cdev needs update */ - mutex_unlock(&instance->cdev->lock); + scoped_guard(cooling_dev, instance->cdev) { + instance->cdev->updated = false; /* cdev needs update */ + } } } @@ -127,11 +125,13 @@ static void step_wise_manage(struct thermal_zone_device *tz) trip->type == THERMAL_TRIP_HOT) continue; - thermal_zone_trip_update(tz, trip, td->threshold); + thermal_zone_trip_update(tz, td, td->threshold); } - list_for_each_entry(instance, &tz->thermal_instances, tz_node) - thermal_cdev_update(instance->cdev); + for_each_trip_desc(tz, td) { + list_for_each_entry(instance, &td->thermal_instances, trip_node) + thermal_cdev_update(instance->cdev); + } } static struct thermal_governor thermal_gov_step_wise = { diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index f1fe0f8ab04f17..7e918bd3f10024 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -637,10 +637,10 @@ static struct platform_driver hisi_thermal_driver = { .driver = { .name = "hisi_thermal", .pm = pm_sleep_ptr(&hisi_thermal_pm_ops), - .of_match_table = of_hisi_thermal_match, + .of_match_table = of_hisi_thermal_match, }, .probe = hisi_thermal_probe, - .remove_new = hisi_thermal_remove, + .remove = hisi_thermal_remove, }; module_platform_driver(hisi_thermal_driver); diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c index d74ed6ce2974c4..719d71f5b23565 100644 --- a/drivers/thermal/imx8mm_thermal.c +++ b/drivers/thermal/imx8mm_thermal.c @@ -399,7 +399,7 @@ static struct platform_driver imx8mm_tmu = { .of_match_table = imx8mm_tmu_table, }, .probe = imx8mm_tmu_probe, - .remove_new = imx8mm_tmu_remove, + .remove = imx8mm_tmu_remove, }; module_platform_driver(imx8mm_tmu); diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index b8e85a405351ba..bab52e6b3b1558 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -861,7 +861,7 @@ static struct platform_driver imx_thermal = { .of_match_table = of_imx_thermal_match, }, .probe = imx_thermal_probe, - .remove_new = imx_thermal_remove, + .remove = imx_thermal_remove, }; module_platform_driver(imx_thermal); diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c index b0c0f0ffdcb046..8660ef2175be8e 100644 --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c @@ -75,11 +75,6 @@ struct odvp_attr { static BIN_ATTR_SIMPLE_RO(data_vault); -static struct bin_attribute *data_attributes[] = { - &bin_attr_data_vault, - NULL, -}; - static ssize_t imok_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -108,10 +103,6 @@ static const struct attribute_group imok_attribute_group = { .attrs = imok_attr, }; -static const struct attribute_group data_attribute_group = { - .bin_attrs = data_attributes, -}; - static ssize_t available_uuids_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -137,7 +128,7 @@ static ssize_t current_uuid_show(struct device *dev, struct int3400_thermal_priv *priv = dev_get_drvdata(dev); int i, length = 0; - if (priv->current_uuid_index > 0) + if (priv->current_uuid_index >= 0) return sprintf(buf, "%s\n", int3400_thermal_uuids[priv->current_uuid_index]); @@ -624,8 +615,7 @@ static int int3400_thermal_probe(struct platform_device *pdev) } if (!ZERO_OR_NULL_PTR(priv->data_vault)) { - result = sysfs_create_group(&pdev->dev.kobj, - &data_attribute_group); + result = device_create_bin_file(&pdev->dev, &bin_attr_data_vault); if (result) goto free_uuid; } @@ -648,7 +638,7 @@ static int int3400_thermal_probe(struct platform_device *pdev) free_sysfs: cleanup_odvp(priv); if (!ZERO_OR_NULL_PTR(priv->data_vault)) { - sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group); + device_remove_bin_file(&pdev->dev, &bin_attr_data_vault); kfree(priv->data_vault); } free_uuid: @@ -683,7 +673,7 @@ static void int3400_thermal_remove(struct platform_device *pdev) acpi_thermal_rel_misc_device_remove(priv->adev->handle); if (!ZERO_OR_NULL_PTR(priv->data_vault)) - sysfs_remove_group(&pdev->dev.kobj, &data_attribute_group); + device_remove_bin_file(&pdev->dev, &bin_attr_data_vault); sysfs_remove_group(&pdev->dev.kobj, &uuid_attribute_group); sysfs_remove_group(&pdev->dev.kobj, &imok_attribute_group); thermal_zone_device_unregister(priv->thermal); @@ -707,7 +697,7 @@ MODULE_DEVICE_TABLE(acpi, int3400_thermal_match); static struct platform_driver int3400_thermal_driver = { .probe = int3400_thermal_probe, - .remove_new = int3400_thermal_remove, + .remove = int3400_thermal_remove, .driver = { .name = "int3400 thermal", .acpi_match_table = ACPI_PTR(int3400_thermal_match), diff --git a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c index 193645a73861be..96d6277a5a8c47 100644 --- a/drivers/thermal/intel/int340x_thermal/int3401_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3401_thermal.c @@ -60,7 +60,7 @@ static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, int3401_thermal_suspend, static struct platform_driver int3401_driver = { .probe = int3401_add, - .remove_new = int3401_remove, + .remove = int3401_remove, .driver = { .name = "int3401 thermal", .acpi_match_table = int3401_device_ids, diff --git a/drivers/thermal/intel/int340x_thermal/int3402_thermal.c b/drivers/thermal/intel/int340x_thermal/int3402_thermal.c index ab8bfb5a3946bc..543b03960e9923 100644 --- a/drivers/thermal/intel/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3402_thermal.c @@ -89,7 +89,7 @@ MODULE_DEVICE_TABLE(acpi, int3402_thermal_match); static struct platform_driver int3402_thermal_driver = { .probe = int3402_thermal_probe, - .remove_new = int3402_thermal_remove, + .remove = int3402_thermal_remove, .driver = { .name = "int3402 thermal", .acpi_match_table = int3402_thermal_match, diff --git a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c index c094a422ded3d9..04aa0afb3b1d54 100644 --- a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c @@ -281,7 +281,7 @@ MODULE_DEVICE_TABLE(acpi, int3403_device_ids); static struct platform_driver int3403_driver = { .probe = int3403_add, - .remove_new = int3403_remove, + .remove = int3403_remove, .driver = { .name = "int3403 thermal", .acpi_match_table = int3403_device_ids, diff --git a/drivers/thermal/intel/int340x_thermal/int3406_thermal.c b/drivers/thermal/intel/int340x_thermal/int3406_thermal.c index 1c266493c1aade..e21fcbccf4ba63 100644 --- a/drivers/thermal/intel/int340x_thermal/int3406_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3406_thermal.c @@ -195,7 +195,7 @@ MODULE_DEVICE_TABLE(acpi, int3406_thermal_match); static struct platform_driver int3406_thermal_driver = { .probe = int3406_thermal_probe, - .remove_new = int3406_thermal_remove, + .remove = int3406_thermal_remove, .driver = { .name = "int3406 thermal", .acpi_match_table = int3406_thermal_match, diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 7c46dd6bee731e..c868d8b7bd1cbf 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -454,8 +454,8 @@ void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device * } EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove); -MODULE_IMPORT_NS(INTEL_TCC); -MODULE_IMPORT_NS(INT340X_THERMAL); +MODULE_IMPORT_NS("INTEL_TCC"); +MODULE_IMPORT_NS("INT340X_THERMAL"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c index ba5d36d36fc404..145d471546d50c 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device_pci.c @@ -510,7 +510,7 @@ static struct pci_driver proc_thermal_pci_driver = { module_pci_driver(proc_thermal_pci_driver); -MODULE_IMPORT_NS(INT340X_THERMAL); +MODULE_IMPORT_NS("INT340X_THERMAL"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c index af2ec0beb7a110..b1d531ef440f1d 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c @@ -94,7 +94,7 @@ int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp return ret; } -EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, "INT340X_THERMAL"); int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data) { @@ -106,7 +106,7 @@ int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data return ret; } -EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, "INT340X_THERMAL"); #define MBOX_CAMARILLO_RD_INTR_CONFIG 0x1E #define MBOX_CAMARILLO_WR_INTR_CONFIG 0x1F @@ -153,7 +153,7 @@ int processor_thermal_mbox_interrupt_config(struct pci_dev *pdev, bool enable, return ret; } -EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, "INT340X_THERMAL"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Processor Thermal Mail Box Interface"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c index d6b787ca2741ee..25cdbb6d91a6a7 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_power_floor.c @@ -42,7 +42,7 @@ int proc_thermal_read_power_floor_status(struct proc_thermal_device *proc_priv) status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET); return (status & SOC_POWER_FLOOR_STATUS) >> SOC_POWER_FLOOR_SHIFT; } -EXPORT_SYMBOL_NS_GPL(proc_thermal_read_power_floor_status, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_read_power_floor_status, "INT340X_THERMAL"); static bool enable_state; static DEFINE_MUTEX(pf_lock); @@ -69,13 +69,13 @@ int proc_thermal_power_floor_set_state(struct proc_thermal_device *proc_priv, bo return ret; } -EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_set_state, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_set_state, "INT340X_THERMAL"); bool proc_thermal_power_floor_get_state(struct proc_thermal_device *proc_priv) { return enable_state; } -EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_get_state, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_get_state, "INT340X_THERMAL"); /** * proc_thermal_check_power_floor_intr() - Check power floor interrupt. @@ -94,7 +94,7 @@ bool proc_thermal_check_power_floor_intr(struct proc_thermal_device *proc_priv) int_status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET); return !!(int_status & SOC_POWER_FLOOR_INT_ACTIVE); } -EXPORT_SYMBOL_NS_GPL(proc_thermal_check_power_floor_intr, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_check_power_floor_intr, "INT340X_THERMAL"); /** * proc_thermal_power_floor_intr_callback() - Process power floor notification @@ -120,8 +120,8 @@ void proc_thermal_power_floor_intr_callback(struct pci_dev *pdev, sysfs_notify(&pdev->dev.kobj, "power_limits", "power_floor_status"); } -EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_intr_callback, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_intr_callback, "INT340X_THERMAL"); -MODULE_IMPORT_NS(INT340X_THERMAL); +MODULE_IMPORT_NS("INT340X_THERMAL"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Processor Thermal power floor notification Interface"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c index 0e2dc1426282da..dad63f2d5f90fc 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_rfim.c @@ -9,7 +9,7 @@ #include #include "processor_thermal_device.h" -MODULE_IMPORT_NS(INT340X_THERMAL); +MODULE_IMPORT_NS("INT340X_THERMAL"); struct mmio_reg { int read_only; diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c index e947d84f4977fc..68e8391af8f4e1 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_hint.c @@ -204,7 +204,7 @@ bool proc_thermal_check_wt_intr(struct proc_thermal_device *proc_priv) return false; } -EXPORT_SYMBOL_NS_GPL(proc_thermal_check_wt_intr, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_check_wt_intr, "INT340X_THERMAL"); /* Callback to notify user space */ void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_device *proc_priv) @@ -217,7 +217,7 @@ void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_dev sysfs_notify(&pdev->dev.kobj, "workload_hint", "workload_type_index"); } -EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_intr_callback, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_intr_callback, "INT340X_THERMAL"); static bool workload_hint_created; @@ -233,7 +233,7 @@ int proc_thermal_wt_hint_add(struct pci_dev *pdev, struct proc_thermal_device *p return 0; } -EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_add, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_add, "INT340X_THERMAL"); void proc_thermal_wt_hint_remove(struct pci_dev *pdev) { @@ -249,8 +249,8 @@ void proc_thermal_wt_hint_remove(struct pci_dev *pdev) workload_hint_created = false; } -EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_remove, INT340X_THERMAL); +EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_remove, "INT340X_THERMAL"); -MODULE_IMPORT_NS(INT340X_THERMAL); +MODULE_IMPORT_NS("INT340X_THERMAL"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Processor Thermal Work Load type hint Interface"); diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c index f298e7442662a1..b95810f4a0118a 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_wt_req.c @@ -132,6 +132,6 @@ void proc_thermal_wt_req_remove(struct pci_dev *pdev) } EXPORT_SYMBOL_GPL(proc_thermal_wt_req_remove); -MODULE_IMPORT_NS(INT340X_THERMAL); +MODULE_IMPORT_NS("INT340X_THERMAL"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Processor Thermal Work Load type request Interface"); diff --git a/drivers/thermal/intel/intel_powerclamp.c b/drivers/thermal/intel/intel_powerclamp.c index 4ba649370aa1a7..96a24df79686ca 100644 --- a/drivers/thermal/intel/intel_powerclamp.c +++ b/drivers/thermal/intel/intel_powerclamp.c @@ -809,7 +809,7 @@ static void __exit powerclamp_exit(void) } module_exit(powerclamp_exit); -MODULE_IMPORT_NS(IDLE_INJECT); +MODULE_IMPORT_NS("IDLE_INJECT"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arjan van de Ven "); diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c index 47296a14db3c15..89498eb29a89da 100644 --- a/drivers/thermal/intel/intel_quark_dts_thermal.c +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c @@ -401,7 +401,7 @@ static struct soc_sensor_entry *alloc_soc_dts(void) } static const struct x86_cpu_id qrk_thermal_ids[] __initconst = { - X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL), + X86_MATCH_VFM(INTEL_QUARK_X1000, NULL), {} }; MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids); diff --git a/drivers/thermal/intel/intel_soc_dts_iosf.c b/drivers/thermal/intel/intel_soc_dts_iosf.c index 43a29551ba17eb..ea87439fe7a99b 100644 --- a/drivers/thermal/intel/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel/intel_soc_dts_iosf.c @@ -388,6 +388,6 @@ void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors) } EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit); -MODULE_IMPORT_NS(INTEL_TCC); +MODULE_IMPORT_NS("INTEL_TCC"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("SoC DTS driver using side band interface"); diff --git a/drivers/thermal/intel/intel_tcc.c b/drivers/thermal/intel/intel_tcc.c index c86654f28aa5b2..817421508d5c92 100644 --- a/drivers/thermal/intel/intel_tcc.c +++ b/drivers/thermal/intel/intel_tcc.c @@ -150,7 +150,7 @@ u32 intel_tcc_get_offset_mask(void) { return intel_tcc_temp_masks.tcc_offset; } -EXPORT_SYMBOL_NS(intel_tcc_get_offset_mask, INTEL_TCC); +EXPORT_SYMBOL_NS(intel_tcc_get_offset_mask, "INTEL_TCC"); /** * get_temp_mask() - Returns the model-specific bitmask for temperature @@ -195,7 +195,7 @@ int intel_tcc_get_tjmax(int cpu) return val ? val : -ENODATA; } -EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, INTEL_TCC); +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_tjmax, "INTEL_TCC"); /** * intel_tcc_get_offset() - returns the TCC Offset value to Tjmax @@ -220,7 +220,7 @@ int intel_tcc_get_offset(int cpu) return (low >> 24) & intel_tcc_temp_masks.tcc_offset; } -EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, INTEL_TCC); +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_offset, "INTEL_TCC"); /** * intel_tcc_set_offset() - set the TCC offset value to Tjmax @@ -263,7 +263,7 @@ int intel_tcc_set_offset(int cpu, int offset) else return wrmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, low, high); } -EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, INTEL_TCC); +EXPORT_SYMBOL_NS_GPL(intel_tcc_set_offset, "INTEL_TCC"); /** * intel_tcc_get_temp() - returns the current temperature @@ -303,4 +303,4 @@ int intel_tcc_get_temp(int cpu, int *temp, bool pkg) return 0; } -EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, INTEL_TCC); +EXPORT_SYMBOL_NS_GPL(intel_tcc_get_temp, "INTEL_TCC"); diff --git a/drivers/thermal/intel/intel_tcc_cooling.c b/drivers/thermal/intel/intel_tcc_cooling.c index 17110ffa80bb05..9ff0ebdde0ef2c 100644 --- a/drivers/thermal/intel/intel_tcc_cooling.c +++ b/drivers/thermal/intel/intel_tcc_cooling.c @@ -118,7 +118,7 @@ static void __exit tcc_cooling_exit(void) module_exit(tcc_cooling_exit) -MODULE_IMPORT_NS(INTEL_TCC); +MODULE_IMPORT_NS("INTEL_TCC"); MODULE_DESCRIPTION("TCC offset cooling device Driver"); MODULE_AUTHOR("Zhang Rui "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c index 65b33b56a9be5e..496abf8e55e0d5 100644 --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c @@ -524,7 +524,7 @@ static void __exit pkg_temp_thermal_exit(void) } module_exit(pkg_temp_thermal_exit) -MODULE_IMPORT_NS(INTEL_TCC); +MODULE_IMPORT_NS("INTEL_TCC"); MODULE_DESCRIPTION("X86 PKG TEMP Thermal Driver"); MODULE_AUTHOR("Srinivas Pandruvada "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/thermal/k3_bandgap.c b/drivers/thermal/k3_bandgap.c index 2a703770fc917e..678d6ed711b5ef 100644 --- a/drivers/thermal/k3_bandgap.c +++ b/drivers/thermal/k3_bandgap.c @@ -250,7 +250,7 @@ MODULE_DEVICE_TABLE(of, of_k3_bandgap_match); static struct platform_driver k3_bandgap_sensor_driver = { .probe = k3_bandgap_probe, - .remove_new = k3_bandgap_remove, + .remove = k3_bandgap_remove, .driver = { .name = "k3-soc-thermal", .of_match_table = of_k3_bandgap_match, diff --git a/drivers/thermal/k3_j72xx_bandgap.c b/drivers/thermal/k3_j72xx_bandgap.c index 9bc279ac131a4e..70de6dbf99c5a4 100644 --- a/drivers/thermal/k3_j72xx_bandgap.c +++ b/drivers/thermal/k3_j72xx_bandgap.c @@ -238,7 +238,7 @@ static inline int k3_bgp_read_temp(struct k3_thermal_data *devdata, K3_VTM_TS_STAT_DTEMP_MASK; dtemp = vtm_get_best_value(s0, s1, s2); - if (dtemp < 0 || dtemp >= TABLE_SIZE) + if (dtemp >= TABLE_SIZE) return -EINVAL; *temp = derived_table[dtemp]; @@ -594,7 +594,7 @@ MODULE_DEVICE_TABLE(of, of_k3_j72xx_bandgap_match); static struct platform_driver k3_j72xx_bandgap_sensor_driver = { .probe = k3_j72xx_bandgap_probe, - .remove_new = k3_j72xx_bandgap_remove, + .remove = k3_j72xx_bandgap_remove, .driver = { .name = "k3-j72xx-soc-thermal", .of_match_table = of_k3_j72xx_bandgap_match, diff --git a/drivers/thermal/kirkwood_thermal.c b/drivers/thermal/kirkwood_thermal.c index a18158ebe65f63..7c22652316688b 100644 --- a/drivers/thermal/kirkwood_thermal.c +++ b/drivers/thermal/kirkwood_thermal.c @@ -102,7 +102,7 @@ MODULE_DEVICE_TABLE(of, kirkwood_thermal_id_table); static struct platform_driver kirkwood_thermal_driver = { .probe = kirkwood_thermal_probe, - .remove_new = kirkwood_thermal_exit, + .remove = kirkwood_thermal_exit, .driver = { .name = "kirkwood_thermal", .of_match_table = kirkwood_thermal_id_table, diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 1997e91bb3be94..07f7f3b7a2fb56 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -329,7 +329,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) static void lvts_update_irq_mask(struct lvts_ctrl *lvts_ctrl) { - u32 masks[] = { + static const u32 masks[] = { LVTS_MONINT_OFFSET_SENSOR0, LVTS_MONINT_OFFSET_SENSOR1, LVTS_MONINT_OFFSET_SENSOR2, @@ -424,7 +424,7 @@ static irqreturn_t lvts_ctrl_irq_handler(struct lvts_ctrl *lvts_ctrl) { irqreturn_t iret = IRQ_NONE; u32 value; - u32 masks[] = { + static const u32 masks[] = { LVTS_INT_SENSOR0, LVTS_INT_SENSOR1, LVTS_INT_SENSOR2, @@ -1788,7 +1788,7 @@ static const struct dev_pm_ops lvts_pm_ops = { static struct platform_driver lvts_driver = { .probe = lvts_probe, - .remove_new = lvts_remove, + .remove = lvts_remove, .driver = { .name = "mtk-lvts-thermal", .of_match_table = lvts_of_match, diff --git a/drivers/thermal/pcie_cooling.c b/drivers/thermal/pcie_cooling.c new file mode 100644 index 00000000000000..a876d64f15827a --- /dev/null +++ b/drivers/thermal/pcie_cooling.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PCIe cooling device + * + * Copyright (C) 2023-2024 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define COOLING_DEV_TYPE_PREFIX "PCIe_Port_Link_Speed_" + +static int pcie_cooling_get_max_level(struct thermal_cooling_device *cdev, unsigned long *state) +{ + struct pci_dev *port = cdev->devdata; + + /* cooling state 0 is same as the maximum PCIe speed */ + *state = port->subordinate->max_bus_speed - PCIE_SPEED_2_5GT; + + return 0; +} + +static int pcie_cooling_get_cur_level(struct thermal_cooling_device *cdev, unsigned long *state) +{ + struct pci_dev *port = cdev->devdata; + + /* cooling state 0 is same as the maximum PCIe speed */ + *state = cdev->max_state - (port->subordinate->cur_bus_speed - PCIE_SPEED_2_5GT); + + return 0; +} + +static int pcie_cooling_set_cur_level(struct thermal_cooling_device *cdev, unsigned long state) +{ + struct pci_dev *port = cdev->devdata; + enum pci_bus_speed speed; + + /* cooling state 0 is same as the maximum PCIe speed */ + speed = (cdev->max_state - state) + PCIE_SPEED_2_5GT; + + return pcie_set_target_speed(port, speed, true); +} + +static struct thermal_cooling_device_ops pcie_cooling_ops = { + .get_max_state = pcie_cooling_get_max_level, + .get_cur_state = pcie_cooling_get_cur_level, + .set_cur_state = pcie_cooling_set_cur_level, +}; + +struct thermal_cooling_device *pcie_cooling_device_register(struct pci_dev *port) +{ + char *name __free(kfree) = + kasprintf(GFP_KERNEL, COOLING_DEV_TYPE_PREFIX "%s", pci_name(port)); + if (!name) + return ERR_PTR(-ENOMEM); + + return thermal_cooling_device_register(name, port, &pcie_cooling_ops); +} + +void pcie_cooling_device_unregister(struct thermal_cooling_device *cdev) +{ + thermal_cooling_device_unregister(cdev); +} + +/* For bus_speed <-> state arithmetic */ +static_assert(PCIE_SPEED_2_5GT + 1 == PCIE_SPEED_5_0GT); +static_assert(PCIE_SPEED_5_0GT + 1 == PCIE_SPEED_8_0GT); +static_assert(PCIE_SPEED_8_0GT + 1 == PCIE_SPEED_16_0GT); +static_assert(PCIE_SPEED_16_0GT + 1 == PCIE_SPEED_32_0GT); +static_assert(PCIE_SPEED_32_0GT + 1 == PCIE_SPEED_64_0GT); + +MODULE_AUTHOR("Ilpo Järvinen "); +MODULE_DESCRIPTION("PCIe cooling driver"); diff --git a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c index 5e94a45eba3eef..d7f2e6ca92c2c9 100644 --- a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c +++ b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c @@ -938,7 +938,6 @@ static const struct adc_tm5_data adc_tm5_gen2_data_pmic = { static int adc_tm5_get_dt_data(struct adc_tm5_chip *adc_tm, struct device_node *node) { struct adc_tm5_channel *channels; - struct device_node *child; u32 value; int ret; struct device *dev = adc_tm->dev; @@ -982,12 +981,10 @@ static int adc_tm5_get_dt_data(struct adc_tm5_chip *adc_tm, struct device_node * adc_tm->avg_samples = VADC_DEF_AVG_SAMPLES; } - for_each_available_child_of_node(node, child) { + for_each_available_child_of_node_scoped(node, child) { ret = adc_tm5_get_dt_channel_data(adc_tm, channels, child); - if (ret) { - of_node_put(child); + if (ret) return ret; - } channels++; } diff --git a/drivers/thermal/qcom/tsens-v1.c b/drivers/thermal/qcom/tsens-v1.c index dc1c4ae2d8b01b..1a7874676f68e4 100644 --- a/drivers/thermal/qcom/tsens-v1.c +++ b/drivers/thermal/qcom/tsens-v1.c @@ -162,28 +162,35 @@ struct tsens_plat_data data_tsens_v1 = { .fields = tsens_v1_regfields, }; -static const struct tsens_ops ops_8956 = { - .init = init_8956, +static const struct tsens_ops ops_common = { + .init = init_common, .calibrate = tsens_calibrate_common, .get_temp = get_temp_tsens_valid, }; -struct tsens_plat_data data_8956 = { +struct tsens_plat_data data_8937 = { .num_sensors = 11, - .ops = &ops_8956, + .ops = &ops_common, .feat = &tsens_v1_feat, .fields = tsens_v1_regfields, }; -static const struct tsens_ops ops_8976 = { - .init = init_common, +static const struct tsens_ops ops_8956 = { + .init = init_8956, .calibrate = tsens_calibrate_common, .get_temp = get_temp_tsens_valid, }; +struct tsens_plat_data data_8956 = { + .num_sensors = 11, + .ops = &ops_8956, + .feat = &tsens_v1_feat, + .fields = tsens_v1_regfields, +}; + struct tsens_plat_data data_8976 = { .num_sensors = 11, - .ops = &ops_8976, + .ops = &ops_common, .feat = &tsens_v1_feat, .fields = tsens_v1_regfields, }; diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 0b4421bf478544..3aa3736181aa7b 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -1119,6 +1119,9 @@ static const struct of_device_id tsens_table[] = { }, { .compatible = "qcom,msm8916-tsens", .data = &data_8916, + }, { + .compatible = "qcom,msm8937-tsens", + .data = &data_8937, }, { .compatible = "qcom,msm8939-tsens", .data = &data_8939, @@ -1360,7 +1363,7 @@ static void tsens_remove(struct platform_device *pdev) static struct platform_driver tsens_driver = { .probe = tsens_probe, - .remove_new = tsens_remove, + .remove = tsens_remove, .driver = { .name = "qcom-tsens", .pm = &tsens_pm_ops, diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index cab39de045b100..7b36a0318fa6a0 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -647,7 +647,7 @@ extern struct tsens_plat_data data_8960; extern struct tsens_plat_data data_8226, data_8909, data_8916, data_8939, data_8974, data_9607; /* TSENS v1 targets */ -extern struct tsens_plat_data data_tsens_v1, data_8976, data_8956; +extern struct tsens_plat_data data_tsens_v1, data_8937, data_8976, data_8956; /* TSENS v2 targets */ extern struct tsens_plat_data data_8996, data_ipq8074, data_tsens_v2; diff --git a/drivers/thermal/renesas/rcar_gen3_thermal.c b/drivers/thermal/renesas/rcar_gen3_thermal.c index 810f866774612b..1ec169aeacfc30 100644 --- a/drivers/thermal/renesas/rcar_gen3_thermal.c +++ b/drivers/thermal/renesas/rcar_gen3_thermal.c @@ -603,7 +603,7 @@ static struct platform_driver rcar_gen3_thermal_driver = { .of_match_table = rcar_gen3_thermal_dt_ids, }, .probe = rcar_gen3_thermal_probe, - .remove_new = rcar_gen3_thermal_remove, + .remove = rcar_gen3_thermal_remove, }; module_platform_driver(rcar_gen3_thermal_driver); diff --git a/drivers/thermal/renesas/rcar_thermal.c b/drivers/thermal/renesas/rcar_thermal.c index ddc8341e5c3fa0..00a66ee0a5b00c 100644 --- a/drivers/thermal/renesas/rcar_thermal.c +++ b/drivers/thermal/renesas/rcar_thermal.c @@ -579,7 +579,7 @@ static struct platform_driver rcar_thermal_driver = { .of_match_table = rcar_thermal_dt_ids, }, .probe = rcar_thermal_probe, - .remove_new = rcar_thermal_remove, + .remove = rcar_thermal_remove, }; module_platform_driver(rcar_thermal_driver); diff --git a/drivers/thermal/renesas/rzg2l_thermal.c b/drivers/thermal/renesas/rzg2l_thermal.c index 0e1cb9045ee6ff..b588be628640a3 100644 --- a/drivers/thermal/renesas/rzg2l_thermal.c +++ b/drivers/thermal/renesas/rzg2l_thermal.c @@ -240,7 +240,7 @@ static struct platform_driver rzg2l_thermal_driver = { .of_match_table = rzg2l_thermal_dt_ids, }, .probe = rzg2l_thermal_probe, - .remove_new = rzg2l_thermal_remove, + .remove = rzg2l_thermal_remove, }; module_platform_driver(rzg2l_thermal_driver); diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 086ed42dd16cd4..f551df48eef935 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -1689,7 +1689,7 @@ static struct platform_driver rockchip_thermal_driver = { .of_match_table = of_rockchip_thermal_match, }, .probe = rockchip_thermal_probe, - .remove_new = rockchip_thermal_remove, + .remove = rockchip_thermal_remove, }; module_platform_driver(rockchip_thermal_driver); diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 96cffb2c44ba35..47a99b3c539582 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -1164,7 +1164,7 @@ static struct platform_driver exynos_tmu_driver = { .of_match_table = exynos_tmu_match, }, .probe = exynos_tmu_probe, - .remove_new = exynos_tmu_remove, + .remove = exynos_tmu_remove, }; module_platform_driver(exynos_tmu_driver); diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c index 60a871998b07e3..bb96be94752138 100644 --- a/drivers/thermal/spear_thermal.c +++ b/drivers/thermal/spear_thermal.c @@ -173,7 +173,7 @@ MODULE_DEVICE_TABLE(of, spear_thermal_id_table); static struct platform_driver spear_thermal_driver = { .probe = spear_thermal_probe, - .remove_new = spear_thermal_exit, + .remove = spear_thermal_exit, .driver = { .name = "spear_thermal", .pm = &spear_thermal_pm_ops, diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c index dfd1d529c4101d..e546067c962187 100644 --- a/drivers/thermal/sprd_thermal.c +++ b/drivers/thermal/sprd_thermal.c @@ -534,7 +534,7 @@ static const struct dev_pm_ops sprd_thermal_pm_ops = { static struct platform_driver sprd_thermal_driver = { .probe = sprd_thm_probe, - .remove_new = sprd_thm_remove, + .remove = sprd_thm_remove, .driver = { .name = "sprd-thermal", .pm = &sprd_thermal_pm_ops, diff --git a/drivers/thermal/st/st_thermal_memmap.c b/drivers/thermal/st/st_thermal_memmap.c index 97493d2b2f4999..8f76e50ea5677f 100644 --- a/drivers/thermal/st/st_thermal_memmap.c +++ b/drivers/thermal/st/st_thermal_memmap.c @@ -174,7 +174,7 @@ static struct platform_driver st_mmap_thermal_driver = { .of_match_table = st_mmap_thermal_of_match, }, .probe = st_mmap_probe, - .remove_new = st_mmap_remove, + .remove = st_mmap_remove, }; module_platform_driver(st_mmap_thermal_driver); diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c index ffd988600ed6a2..6e90eb9f414dfc 100644 --- a/drivers/thermal/st/stm_thermal.c +++ b/drivers/thermal/st/stm_thermal.c @@ -582,7 +582,7 @@ static struct platform_driver stm_thermal_driver = { .of_match_table = stm_thermal_of_match, }, .probe = stm_thermal_probe, - .remove_new = stm_thermal_remove, + .remove = stm_thermal_remove, }; module_platform_driver(stm_thermal_driver); diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c index 3203d8bd13a8fc..22674790629a7b 100644 --- a/drivers/thermal/sun8i_thermal.c +++ b/drivers/thermal/sun8i_thermal.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -348,19 +349,18 @@ static void sun8i_ths_reset_control_assert(void *data) static struct regmap *sun8i_ths_get_sram_regmap(struct device_node *node) { - struct device_node *sram_node; struct platform_device *sram_pdev; struct regmap *regmap = NULL; - sram_node = of_parse_phandle(node, "allwinner,sram", 0); + struct device_node *sram_node __free(device_node) = + of_parse_phandle(node, "allwinner,sram", 0); if (!sram_node) return ERR_PTR(-ENODEV); sram_pdev = of_find_device_by_node(sram_node); if (!sram_pdev) { /* platform device might not be probed yet */ - regmap = ERR_PTR(-EPROBE_DEFER); - goto out_put_node; + return ERR_PTR(-EPROBE_DEFER); } /* If no regmap is found then the other device driver is at fault */ @@ -369,8 +369,7 @@ static struct regmap *sun8i_ths_get_sram_regmap(struct device_node *node) regmap = ERR_PTR(-EINVAL); platform_device_put(sram_pdev); -out_put_node: - of_node_put(sram_node); + return regmap; } diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index a023c948afbddd..2c5ddf0db40c6e 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -1651,7 +1651,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct tegra_soctherm *ts = dev_get_drvdata(dev); - struct device_node *np_stc, *np_stcc; + struct device_node *np_stc; const char *name; int i; @@ -1668,7 +1668,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) return; } - for_each_child_of_node(np_stc, np_stcc) { + for_each_child_of_node_scoped(np_stc, np_stcc) { struct soctherm_throt_cfg *stc; struct thermal_cooling_device *tcd; int err; @@ -1683,7 +1683,6 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) if (stc->init) { dev_err(dev, "throttle-cfg: %s: redefined!\n", name); - of_node_put(np_stcc); break; } @@ -2269,7 +2268,7 @@ static SIMPLE_DEV_PM_OPS(tegra_soctherm_pm, soctherm_suspend, soctherm_resume); static struct platform_driver tegra_soctherm_driver = { .probe = tegra_soctherm_probe, - .remove_new = tegra_soctherm_remove, + .remove = tegra_soctherm_remove, .driver = { .name = "tegra_soctherm", .pm = &tegra_soctherm_pm, diff --git a/drivers/thermal/tegra/tegra-bpmp-thermal.c b/drivers/thermal/tegra/tegra-bpmp-thermal.c index 72ce14c980cdb4..997d77ce30d94c 100644 --- a/drivers/thermal/tegra/tegra-bpmp-thermal.c +++ b/drivers/thermal/tegra/tegra-bpmp-thermal.c @@ -315,7 +315,7 @@ MODULE_DEVICE_TABLE(of, tegra_bpmp_thermal_of_match); static struct platform_driver tegra_bpmp_thermal_driver = { .probe = tegra_bpmp_thermal_probe, - .remove_new = tegra_bpmp_thermal_remove, + .remove = tegra_bpmp_thermal_remove, .driver = { .name = "tegra-bpmp-thermal", .of_match_table = tegra_bpmp_thermal_of_match, diff --git a/drivers/thermal/testing/zone.c b/drivers/thermal/testing/zone.c index c6d8c66f40f980..1f4e450100e2f1 100644 --- a/drivers/thermal/testing/zone.c +++ b/drivers/thermal/testing/zone.c @@ -185,7 +185,7 @@ static void tt_add_tz_work_fn(struct work_struct *work) int tt_add_tz(void) { struct tt_thermal_zone *tt_zone __free(kfree); - struct tt_work *tt_work __free(kfree); + struct tt_work *tt_work __free(kfree) = NULL; int ret; tt_zone = kzalloc(sizeof(*tt_zone), GFP_KERNEL); @@ -237,7 +237,7 @@ static void tt_zone_unregister_tz(struct tt_thermal_zone *tt_zone) int tt_del_tz(const char *arg) { - struct tt_work *tt_work __free(kfree); + struct tt_work *tt_work __free(kfree) = NULL; struct tt_thermal_zone *tt_zone, *aux; int ret; int id; @@ -288,19 +288,14 @@ static struct tt_thermal_zone *tt_get_tt_zone(const char *arg) guard(mutex)(&tt_thermal_zones_lock); - ret = -EINVAL; list_for_each_entry(tt_zone, &tt_thermal_zones, list_node) { if (tt_zone->id == id) { tt_zone->refcount++; - ret = 0; - break; + return tt_zone; } } - if (ret) - return ERR_PTR(ret); - - return tt_zone; + return ERR_PTR(-EINVAL); } static void tt_put_tt_zone(struct tt_thermal_zone *tt_zone) @@ -310,6 +305,9 @@ static void tt_put_tt_zone(struct tt_thermal_zone *tt_zone) tt_zone->refcount--; } +DEFINE_FREE(put_tt_zone, struct tt_thermal_zone *, + if (!IS_ERR_OR_NULL(_T)) tt_put_tt_zone(_T)) + static void tt_zone_add_trip_work_fn(struct work_struct *work) { struct tt_work *tt_work = tt_work_of_work(work); @@ -332,9 +330,9 @@ static void tt_zone_add_trip_work_fn(struct work_struct *work) int tt_zone_add_trip(const char *arg) { + struct tt_thermal_zone *tt_zone __free(put_tt_zone) = NULL; + struct tt_trip *tt_trip __free(kfree) = NULL; struct tt_work *tt_work __free(kfree); - struct tt_trip *tt_trip __free(kfree); - struct tt_thermal_zone *tt_zone; int id; tt_work = kzalloc(sizeof(*tt_work), GFP_KERNEL); @@ -350,10 +348,8 @@ int tt_zone_add_trip(const char *arg) return PTR_ERR(tt_zone); id = ida_alloc(&tt_zone->ida, GFP_KERNEL); - if (id < 0) { - tt_put_tt_zone(tt_zone); + if (id < 0) return id; - } tt_trip->trip.type = THERMAL_TRIP_ACTIVE; tt_trip->trip.temperature = THERMAL_TEMP_INVALID; @@ -366,7 +362,7 @@ int tt_zone_add_trip(const char *arg) tt_zone->num_trips++; INIT_WORK(&tt_work->work, tt_zone_add_trip_work_fn); - tt_work->tt_zone = tt_zone; + tt_work->tt_zone = no_free_ptr(tt_zone); tt_work->tt_trip = no_free_ptr(tt_trip); schedule_work(&(no_free_ptr(tt_work)->work)); @@ -391,7 +387,7 @@ static struct thermal_zone_device_ops tt_zone_ops = { static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone) { - struct thermal_trip *trips __free(kfree); + struct thermal_trip *trips __free(kfree) = NULL; struct thermal_zone_device *tz; struct tt_trip *tt_trip; int i; @@ -425,23 +421,18 @@ static int tt_zone_register_tz(struct tt_thermal_zone *tt_zone) int tt_zone_reg(const char *arg) { - struct tt_thermal_zone *tt_zone; - int ret; + struct tt_thermal_zone *tt_zone __free(put_tt_zone); tt_zone = tt_get_tt_zone(arg); if (IS_ERR(tt_zone)) return PTR_ERR(tt_zone); - ret = tt_zone_register_tz(tt_zone); - - tt_put_tt_zone(tt_zone); - - return ret; + return tt_zone_register_tz(tt_zone); } int tt_zone_unreg(const char *arg) { - struct tt_thermal_zone *tt_zone; + struct tt_thermal_zone *tt_zone __free(put_tt_zone); tt_zone = tt_get_tt_zone(arg); if (IS_ERR(tt_zone)) @@ -449,8 +440,6 @@ int tt_zone_unreg(const char *arg) tt_zone_unregister_tz(tt_zone); - tt_put_tt_zone(tt_zone); - return 0; } diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 8f03985f971c30..19a3894ad752a9 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -40,6 +39,8 @@ static DEFINE_MUTEX(thermal_governor_lock); static struct thermal_governor *def_governor; +static bool thermal_pm_suspended; + /* * Governor section: set of functions to handle thermal governors * @@ -122,7 +123,7 @@ int thermal_register_governor(struct thermal_governor *governor) if (!governor) return -EINVAL; - mutex_lock(&thermal_governor_lock); + guard(mutex)(&thermal_governor_lock); err = -EBUSY; if (!__find_governor(governor->name)) { @@ -138,7 +139,7 @@ int thermal_register_governor(struct thermal_governor *governor) def_governor = governor; } - mutex_lock(&thermal_list_lock); + guard(mutex)(&thermal_list_lock); list_for_each_entry(pos, &thermal_tz_list, node) { /* @@ -161,9 +162,6 @@ int thermal_register_governor(struct thermal_governor *governor) } } - mutex_unlock(&thermal_list_lock); - mutex_unlock(&thermal_governor_lock); - return err; } @@ -174,23 +172,20 @@ void thermal_unregister_governor(struct thermal_governor *governor) if (!governor) return; - mutex_lock(&thermal_governor_lock); + guard(mutex)(&thermal_governor_lock); if (!__find_governor(governor->name)) - goto exit; + return; - mutex_lock(&thermal_list_lock); + list_del(&governor->governor_list); + + guard(mutex)(&thermal_list_lock); list_for_each_entry(pos, &thermal_tz_list, node) { if (!strncasecmp(pos->governor->name, governor->name, THERMAL_NAME_LENGTH)) thermal_set_governor(pos, NULL); } - - mutex_unlock(&thermal_list_lock); - list_del(&governor->governor_list); -exit: - mutex_unlock(&thermal_governor_lock); } int thermal_zone_device_set_policy(struct thermal_zone_device *tz, @@ -199,18 +194,12 @@ int thermal_zone_device_set_policy(struct thermal_zone_device *tz, struct thermal_governor *gov; int ret = -EINVAL; - mutex_lock(&thermal_governor_lock); - mutex_lock(&tz->lock); + guard(mutex)(&thermal_governor_lock); + guard(thermal_zone)(tz); gov = __find_governor(strim(policy)); - if (!gov) - goto exit; - - ret = thermal_set_governor(tz, gov); - -exit: - mutex_unlock(&tz->lock); - mutex_unlock(&thermal_governor_lock); + if (gov) + ret = thermal_set_governor(tz, gov); thermal_notify_tz_gov_change(tz, policy); @@ -222,15 +211,13 @@ int thermal_build_list_of_policies(char *buf) struct thermal_governor *pos; ssize_t count = 0; - mutex_lock(&thermal_governor_lock); + guard(mutex)(&thermal_governor_lock); list_for_each_entry(pos, &thermal_governor_list, governor_list) { count += sysfs_emit_at(buf, count, "%s ", pos->name); } count += sysfs_emit_at(buf, count, "\n"); - mutex_unlock(&thermal_governor_lock); - return count; } @@ -421,83 +408,46 @@ static void handle_critical_trips(struct thermal_zone_device *tz, tz->ops.hot(tz); } -static void handle_thermal_trip(struct thermal_zone_device *tz, - struct thermal_trip_desc *td, - struct list_head *way_up_list, - struct list_head *way_down_list) +static void move_trip_to_sorted_list(struct thermal_trip_desc *td, + struct list_head *list) { - const struct thermal_trip *trip = &td->trip; - int old_threshold; - - if (trip->temperature == THERMAL_TEMP_INVALID) - return; + struct thermal_trip_desc *entry; /* - * If the trip temperature or hysteresis has been updated recently, - * the threshold needs to be computed again using the new values. - * However, its initial value still reflects the old ones and that - * is what needs to be compared with the previous zone temperature - * to decide which action to take. + * Delete upfront and then add to make relocation within the same list + * work. */ - old_threshold = td->threshold; - td->threshold = trip->temperature; + list_del(&td->list_node); - if (tz->last_temperature >= old_threshold && - tz->last_temperature != THERMAL_TEMP_INIT) { - /* - * Mitigation is under way, so it needs to stop if the zone - * temperature falls below the low temperature of the trip. - * In that case, the trip temperature becomes the new threshold. - */ - if (tz->temperature < trip->temperature - trip->hysteresis) { - list_add(&td->notify_list_node, way_down_list); - td->notify_temp = trip->temperature - trip->hysteresis; - - if (trip->type == THERMAL_TRIP_PASSIVE) { - tz->passive--; - WARN_ON(tz->passive < 0); - } - } else { - td->threshold -= trip->hysteresis; + /* Assume that the new entry is likely to be the last one. */ + list_for_each_entry_reverse(entry, list, list_node) { + if (entry->threshold <= td->threshold) { + list_add(&td->list_node, &entry->list_node); + return; } - } else if (tz->temperature >= trip->temperature) { - /* - * There is no mitigation under way, so it needs to be started - * if the zone temperature exceeds the trip one. The new - * threshold is then set to the low temperature of the trip. - */ - list_add_tail(&td->notify_list_node, way_up_list); - td->notify_temp = trip->temperature; - td->threshold -= trip->hysteresis; - - if (trip->type == THERMAL_TRIP_PASSIVE) - tz->passive++; - else if (trip->type == THERMAL_TRIP_CRITICAL || - trip->type == THERMAL_TRIP_HOT) - handle_critical_trips(tz, trip); } + list_add(&td->list_node, list); } -static void thermal_zone_device_check(struct work_struct *work) +static void move_to_trips_high(struct thermal_zone_device *tz, + struct thermal_trip_desc *td) { - struct thermal_zone_device *tz = container_of(work, struct - thermal_zone_device, - poll_queue.work); - thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + td->threshold = td->trip.temperature; + move_trip_to_sorted_list(td, &tz->trips_high); } -static void thermal_zone_device_init(struct thermal_zone_device *tz) +static void move_to_trips_reached(struct thermal_zone_device *tz, + struct thermal_trip_desc *td) { - struct thermal_instance *pos; - - INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check); + td->threshold = td->trip.temperature - td->trip.hysteresis; + move_trip_to_sorted_list(td, &tz->trips_reached); +} - tz->temperature = THERMAL_TEMP_INIT; - tz->passive = 0; - tz->prev_low_trip = -INT_MAX; - tz->prev_high_trip = INT_MAX; - list_for_each_entry(pos, &tz->thermal_instances, tz_node) - pos->initialized = false; +static void move_to_trips_invalid(struct thermal_zone_device *tz, + struct thermal_trip_desc *td) +{ + td->threshold = INT_MAX; + list_move(&td->list_node, &tz->trips_invalid); } static void thermal_governor_trip_crossed(struct thermal_governor *governor, @@ -513,41 +463,154 @@ static void thermal_governor_trip_crossed(struct thermal_governor *governor, } static void thermal_trip_crossed(struct thermal_zone_device *tz, - const struct thermal_trip *trip, + struct thermal_trip_desc *td, struct thermal_governor *governor, bool crossed_up) { + const struct thermal_trip *trip = &td->trip; + if (crossed_up) { + if (trip->type == THERMAL_TRIP_PASSIVE) + tz->passive++; + else if (trip->type == THERMAL_TRIP_CRITICAL || + trip->type == THERMAL_TRIP_HOT) + handle_critical_trips(tz, trip); + thermal_notify_tz_trip_up(tz, trip); thermal_debug_tz_trip_up(tz, trip); } else { + if (trip->type == THERMAL_TRIP_PASSIVE) { + tz->passive--; + WARN_ON(tz->passive < 0); + } thermal_notify_tz_trip_down(tz, trip); thermal_debug_tz_trip_down(tz, trip); } thermal_governor_trip_crossed(governor, tz, trip, crossed_up); } -static int thermal_trip_notify_cmp(void *not_used, const struct list_head *a, - const struct list_head *b) +void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz, + struct thermal_trip *trip, int hyst) { - struct thermal_trip_desc *tda = container_of(a, struct thermal_trip_desc, - notify_list_node); - struct thermal_trip_desc *tdb = container_of(b, struct thermal_trip_desc, - notify_list_node); - return tda->notify_temp - tdb->notify_temp; + struct thermal_trip_desc *td = trip_to_trip_desc(trip); + + WRITE_ONCE(trip->hysteresis, hyst); + thermal_notify_tz_trip_change(tz, trip); + /* + * If the zone temperature is above or at the trip tmperature, the trip + * is in the trips_reached list and its threshold is equal to its low + * temperature. It needs to stay in that list, but its threshold needs + * to be updated and the list ordering may need to be restored. + */ + if (tz->temperature >= td->threshold) + move_to_trips_reached(tz, td); +} + +void thermal_zone_set_trip_temp(struct thermal_zone_device *tz, + struct thermal_trip *trip, int temp) +{ + struct thermal_trip_desc *td = trip_to_trip_desc(trip); + int old_temp = trip->temperature; + + if (old_temp == temp) + return; + + WRITE_ONCE(trip->temperature, temp); + thermal_notify_tz_trip_change(tz, trip); + + if (old_temp == THERMAL_TEMP_INVALID) { + /* + * The trip was invalid before the change, so move it to the + * trips_high list regardless of the new temperature value + * because there is no mitigation under way for it. If a + * mitigation needs to be started, the trip will be moved to the + * trips_reached list later. + */ + move_to_trips_high(tz, td); + return; + } + + if (temp == THERMAL_TEMP_INVALID) { + /* + * If the trip is in the trips_reached list, mitigation is under + * way for it and it needs to be stopped because the trip is + * effectively going away. + */ + if (tz->temperature >= td->threshold) + thermal_trip_crossed(tz, td, thermal_get_tz_governor(tz), false); + + move_to_trips_invalid(tz, td); + return; + } + + /* + * The trip stays on its current list, but its threshold needs to be + * updated due to the temperature change and the list ordering may need + * to be restored. + */ + if (tz->temperature >= td->threshold) + move_to_trips_reached(tz, td); + else + move_to_trips_high(tz, td); +} +EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp); + +static void thermal_zone_handle_trips(struct thermal_zone_device *tz, + struct thermal_governor *governor, + int *low, int *high) +{ + struct thermal_trip_desc *td, *next; + LIST_HEAD(way_down_list); + + /* Check the trips that were below or at the zone temperature. */ + list_for_each_entry_safe_reverse(td, next, &tz->trips_reached, list_node) { + if (td->threshold <= tz->temperature) + break; + + thermal_trip_crossed(tz, td, governor, false); + /* + * The current trips_high list needs to be processed before + * adding new entries to it, so put them on a temporary list. + */ + list_move(&td->list_node, &way_down_list); + } + /* Check the trips that were previously above the zone temperature. */ + list_for_each_entry_safe(td, next, &tz->trips_high, list_node) { + if (td->threshold > tz->temperature) + break; + + thermal_trip_crossed(tz, td, governor, true); + move_to_trips_reached(tz, td); + } + /* Move all of the trips from the temporary list to trips_high. */ + list_for_each_entry_safe(td, next, &way_down_list, list_node) + move_to_trips_high(tz, td); + + if (!list_empty(&tz->trips_reached)) { + td = list_last_entry(&tz->trips_reached, + struct thermal_trip_desc, list_node); + /* + * Set the "low" value below the current trip threshold in case + * the zone temperature is at that threshold and stays there, + * which would trigger a new interrupt immediately in vain. + */ + *low = td->threshold - 1; + } + if (!list_empty(&tz->trips_high)) { + td = list_first_entry(&tz->trips_high, + struct thermal_trip_desc, list_node); + *high = td->threshold; + } } void __thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { struct thermal_governor *governor = thermal_get_tz_governor(tz); - struct thermal_trip_desc *td; - LIST_HEAD(way_down_list); - LIST_HEAD(way_up_list); int low = -INT_MAX, high = INT_MAX; int temp, ret; - if (tz->suspended || tz->mode != THERMAL_DEVICE_ENABLED) + if (tz->state != TZ_STATE_READY || tz->mode != THERMAL_DEVICE_ENABLED) return; ret = __thermal_zone_get_temp(tz, &temp); @@ -575,26 +638,12 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz, tz->notify_event = event; - for_each_trip_desc(tz, td) { - handle_thermal_trip(tz, td, &way_up_list, &way_down_list); + thermal_zone_handle_trips(tz, governor, &low, &high); - if (td->threshold <= tz->temperature && td->threshold > low) - low = td->threshold; - - if (td->threshold >= tz->temperature && td->threshold < high) - high = td->threshold; - } + thermal_thresholds_handle(tz, &low, &high); thermal_zone_set_trips(tz, low, high); - list_sort(NULL, &way_up_list, thermal_trip_notify_cmp); - list_for_each_entry(td, &way_up_list, notify_list_node) - thermal_trip_crossed(tz, &td->trip, governor, true); - - list_sort(NULL, &way_down_list, thermal_trip_notify_cmp); - list_for_each_entry_reverse(td, &way_down_list, notify_list_node) - thermal_trip_crossed(tz, &td->trip, governor, false); - if (governor->manage) governor->manage(tz); @@ -609,26 +658,18 @@ static int thermal_zone_device_set_mode(struct thermal_zone_device *tz, { int ret; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); /* do nothing if mode isn't changing */ - if (mode == tz->mode) { - mutex_unlock(&tz->lock); - + if (mode == tz->mode) return 0; - } ret = __thermal_zone_device_set_mode(tz, mode); - if (ret) { - mutex_unlock(&tz->lock); - + if (ret) return ret; - } __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); - mutex_unlock(&tz->lock); - if (mode == THERMAL_DEVICE_ENABLED) thermal_notify_tz_enable(tz); else @@ -657,85 +698,81 @@ static bool thermal_zone_is_present(struct thermal_zone_device *tz) void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); + if (thermal_zone_is_present(tz)) __thermal_zone_device_update(tz, event); - mutex_unlock(&tz->lock); } EXPORT_SYMBOL_GPL(thermal_zone_device_update); -void thermal_zone_trip_down(struct thermal_zone_device *tz, - const struct thermal_trip *trip) -{ - thermal_trip_crossed(tz, trip, thermal_get_tz_governor(tz), false); -} - int for_each_thermal_governor(int (*cb)(struct thermal_governor *, void *), void *data) { struct thermal_governor *gov; - int ret = 0; - mutex_lock(&thermal_governor_lock); + guard(mutex)(&thermal_governor_lock); + list_for_each_entry(gov, &thermal_governor_list, governor_list) { + int ret; + ret = cb(gov, data); if (ret) - break; + return ret; } - mutex_unlock(&thermal_governor_lock); - return ret; + return 0; } int for_each_thermal_cooling_device(int (*cb)(struct thermal_cooling_device *, void *), void *data) { struct thermal_cooling_device *cdev; - int ret = 0; - mutex_lock(&thermal_list_lock); + guard(mutex)(&thermal_list_lock); + list_for_each_entry(cdev, &thermal_cdev_list, node) { + int ret; + ret = cb(cdev, data); if (ret) - break; + return ret; } - mutex_unlock(&thermal_list_lock); - return ret; + return 0; } int for_each_thermal_zone(int (*cb)(struct thermal_zone_device *, void *), void *data) { struct thermal_zone_device *tz; - int ret = 0; - mutex_lock(&thermal_list_lock); + guard(mutex)(&thermal_list_lock); + list_for_each_entry(tz, &thermal_tz_list, node) { + int ret; + ret = cb(tz, data); if (ret) - break; + return ret; } - mutex_unlock(&thermal_list_lock); - return ret; + return 0; } struct thermal_zone_device *thermal_zone_get_by_id(int id) { - struct thermal_zone_device *tz, *match = NULL; + struct thermal_zone_device *tz; + + guard(mutex)(&thermal_list_lock); - mutex_lock(&thermal_list_lock); list_for_each_entry(tz, &thermal_tz_list, node) { if (tz->id == id) { get_device(&tz->device); - match = tz; - break; + return tz; } } - mutex_unlock(&thermal_list_lock); - return match; + return NULL; } /* @@ -748,12 +785,32 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id) * binding, and unbinding. */ +static int thermal_instance_add(struct thermal_instance *new_instance, + struct thermal_cooling_device *cdev, + struct thermal_trip_desc *td) +{ + struct thermal_instance *instance; + + list_for_each_entry(instance, &td->thermal_instances, trip_node) { + if (instance->cdev == cdev) + return -EEXIST; + } + + list_add_tail(&new_instance->trip_node, &td->thermal_instances); + + guard(cooling_dev)(cdev); + + list_add_tail(&new_instance->cdev_node, &cdev->thermal_instances); + + return 0; +} + /** * thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone * @tz: pointer to struct thermal_zone_device - * @trip: trip point the cooling devices is associated with in this zone. + * @td: descriptor of the trip point to bind @cdev to * @cdev: pointer to struct thermal_cooling_device - * @cool_spec: cooling specification for @trip and @cdev + * @cool_spec: cooling specification for the trip point and @cdev * * This interface function bind a thermal cooling device to the certain trip * point of a thermal zone device. @@ -762,12 +819,11 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id) * Return: 0 on success, the proper error value otherwise. */ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, - const struct thermal_trip *trip, + struct thermal_trip_desc *td, struct thermal_cooling_device *cdev, struct cooling_spec *cool_spec) { struct thermal_instance *dev; - struct thermal_instance *pos; bool upper_no_limit; int result; @@ -790,7 +846,7 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, return -ENOMEM; dev->cdev = cdev; - dev->trip = trip; + dev->trip = &td->trip; dev->upper = cool_spec->upper; dev->upper_no_limit = upper_no_limit; dev->lower = cool_spec->lower; @@ -829,24 +885,15 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, if (result) goto remove_trip_file; - mutex_lock(&cdev->lock); - list_for_each_entry(pos, &tz->thermal_instances, tz_node) - if (pos->trip == trip && pos->cdev == cdev) { - result = -EEXIST; - break; - } - if (!result) { - list_add_tail(&dev->tz_node, &tz->thermal_instances); - list_add_tail(&dev->cdev_node, &cdev->thermal_instances); - atomic_set(&tz->need_update, 1); + result = thermal_instance_add(dev, cdev, td); + if (result) + goto remove_weight_file; - thermal_governor_update_tz(tz, THERMAL_TZ_BIND_CDEV); - } - mutex_unlock(&cdev->lock); + thermal_governor_update_tz(tz, THERMAL_TZ_BIND_CDEV); - if (!result) - return 0; + return 0; +remove_weight_file: device_remove_file(&tz->device, &dev->weight_attr); remove_trip_file: device_remove_file(&tz->device, &dev->attr); @@ -859,10 +906,19 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, return result; } +static void thermal_instance_delete(struct thermal_instance *instance) +{ + list_del(&instance->trip_node); + + guard(cooling_dev)(instance->cdev); + + list_del(&instance->cdev_node); +} + /** * thermal_unbind_cdev_from_trip - unbind a cooling device from a thermal zone. * @tz: pointer to a struct thermal_zone_device. - * @trip: trip point the cooling devices is associated with in this zone. + * @td: descriptor of the trip point to unbind @cdev from * @cdev: pointer to a struct thermal_cooling_device. * * This interface function unbind a thermal cooling device from the certain @@ -870,28 +926,23 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz, * This function is usually called in the thermal zone device .unbind callback. */ static void thermal_unbind_cdev_from_trip(struct thermal_zone_device *tz, - const struct thermal_trip *trip, + struct thermal_trip_desc *td, struct thermal_cooling_device *cdev) { struct thermal_instance *pos, *next; - mutex_lock(&cdev->lock); - list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) { - if (pos->trip == trip && pos->cdev == cdev) { - list_del(&pos->tz_node); - list_del(&pos->cdev_node); - - thermal_governor_update_tz(tz, THERMAL_TZ_UNBIND_CDEV); - - mutex_unlock(&cdev->lock); + list_for_each_entry_safe(pos, next, &td->thermal_instances, trip_node) { + if (pos->cdev == cdev) { + thermal_instance_delete(pos); goto unbind; } } - mutex_unlock(&cdev->lock); return; unbind: + thermal_governor_update_tz(tz, THERMAL_TZ_UNBIND_CDEV); + device_remove_file(&tz->device, &pos->weight_attr); device_remove_file(&tz->device, &pos->attr); sysfs_remove_link(&tz->device.kobj, pos->name); @@ -924,25 +975,23 @@ static struct class *thermal_class; static inline void print_bind_err_msg(struct thermal_zone_device *tz, - const struct thermal_trip *trip, + const struct thermal_trip_desc *td, struct thermal_cooling_device *cdev, int ret) { dev_err(&tz->device, "binding cdev %s to trip %d failed: %d\n", - cdev->type, thermal_zone_trip_id(tz, trip), ret); + cdev->type, thermal_zone_trip_id(tz, &td->trip), ret); } -static void thermal_zone_cdev_bind(struct thermal_zone_device *tz, - struct thermal_cooling_device *cdev) +static bool __thermal_zone_cdev_bind(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev) { struct thermal_trip_desc *td; + bool update_tz = false; if (!tz->ops.should_bind) - return; - - mutex_lock(&tz->lock); + return false; for_each_trip_desc(tz, td) { - struct thermal_trip *trip = &td->trip; struct cooling_spec c = { .upper = THERMAL_NO_LIMIT, .lower = THERMAL_NO_LIMIT, @@ -950,15 +999,40 @@ static void thermal_zone_cdev_bind(struct thermal_zone_device *tz, }; int ret; - if (!tz->ops.should_bind(tz, trip, cdev, &c)) + if (!tz->ops.should_bind(tz, &td->trip, cdev, &c)) continue; - ret = thermal_bind_cdev_to_trip(tz, trip, cdev, &c); - if (ret) - print_bind_err_msg(tz, trip, cdev, ret); + ret = thermal_bind_cdev_to_trip(tz, td, cdev, &c); + if (ret) { + print_bind_err_msg(tz, td, cdev, ret); + continue; + } + + update_tz = true; } - mutex_unlock(&tz->lock); + return update_tz; +} + +static void thermal_zone_cdev_bind(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev) +{ + guard(thermal_zone)(tz); + + if (__thermal_zone_cdev_bind(tz, cdev)) + __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); +} + +static void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev) +{ + struct thermal_zone_device *tz; + + guard(mutex)(&thermal_list_lock); + + list_add(&cdev->node, &thermal_cdev_list); + + list_for_each_entry(tz, &thermal_tz_list, node) + thermal_zone_cdev_bind(tz, cdev); } /** @@ -983,7 +1057,6 @@ __thermal_cooling_device_register(struct device_node *np, const struct thermal_cooling_device_ops *ops) { struct thermal_cooling_device *cdev; - struct thermal_zone_device *pos = NULL; unsigned long current_state; int id, ret; @@ -1050,21 +1123,7 @@ __thermal_cooling_device_register(struct device_node *np, if (current_state <= cdev->max_state) thermal_debug_cdev_add(cdev, current_state); - /* Add 'this' new cdev to the global cdev list */ - mutex_lock(&thermal_list_lock); - - list_add(&cdev->node, &thermal_cdev_list); - - /* Update binding information for 'this' new cdev */ - list_for_each_entry(pos, &thermal_tz_list, node) - thermal_zone_cdev_bind(pos, cdev); - - list_for_each_entry(pos, &thermal_tz_list, node) - if (atomic_cmpxchg(&pos->need_update, 1, 0)) - thermal_zone_device_update(pos, - THERMAL_EVENT_UNSPECIFIED); - - mutex_unlock(&thermal_list_lock); + thermal_cooling_device_init_complete(cdev); return cdev; @@ -1207,19 +1266,19 @@ void thermal_cooling_device_update(struct thermal_cooling_device *cdev) * Hold thermal_list_lock throughout the update to prevent the device * from going away while being updated. */ - mutex_lock(&thermal_list_lock); + guard(mutex)(&thermal_list_lock); if (!thermal_cooling_device_present(cdev)) - goto unlock_list; + return; /* * Update under the cdev lock to prevent the state from being set beyond * the new limit concurrently. */ - mutex_lock(&cdev->lock); + guard(cooling_dev)(cdev); if (cdev->ops->get_max_state(cdev, &cdev->max_state)) - goto unlock; + return; thermal_cooling_device_stats_reinit(cdev); @@ -1246,63 +1305,59 @@ void thermal_cooling_device_update(struct thermal_cooling_device *cdev) } if (cdev->ops->get_cur_state(cdev, &state) || state > cdev->max_state) - goto unlock; + return; thermal_cooling_device_stats_update(cdev, state); - -unlock: - mutex_unlock(&cdev->lock); - -unlock_list: - mutex_unlock(&thermal_list_lock); } EXPORT_SYMBOL_GPL(thermal_cooling_device_update); -static void thermal_zone_cdev_unbind(struct thermal_zone_device *tz, - struct thermal_cooling_device *cdev) +static void __thermal_zone_cdev_unbind(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev) { struct thermal_trip_desc *td; - mutex_lock(&tz->lock); - for_each_trip_desc(tz, td) - thermal_unbind_cdev_from_trip(tz, &td->trip, cdev); - - mutex_unlock(&tz->lock); + thermal_unbind_cdev_from_trip(tz, td, cdev); } -/** - * thermal_cooling_device_unregister - removes a thermal cooling device - * @cdev: the thermal cooling device to remove. - * - * thermal_cooling_device_unregister() must be called when a registered - * thermal cooling device is no longer needed. - */ -void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) +static void thermal_zone_cdev_unbind(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev) { - struct thermal_zone_device *tz; + guard(thermal_zone)(tz); - if (!cdev) - return; + __thermal_zone_cdev_unbind(tz, cdev); +} - thermal_debug_cdev_remove(cdev); +static bool thermal_cooling_device_exit(struct thermal_cooling_device *cdev) +{ + struct thermal_zone_device *tz; - mutex_lock(&thermal_list_lock); + guard(mutex)(&thermal_list_lock); - if (!thermal_cooling_device_present(cdev)) { - mutex_unlock(&thermal_list_lock); - return; - } + if (!thermal_cooling_device_present(cdev)) + return false; list_del(&cdev->node); - /* Unbind all thermal zones associated with 'this' cdev */ list_for_each_entry(tz, &thermal_tz_list, node) thermal_zone_cdev_unbind(tz, cdev); - mutex_unlock(&thermal_list_lock); + return true; +} - device_unregister(&cdev->device); +/** + * thermal_cooling_device_unregister() - removes a thermal cooling device + * @cdev: Thermal cooling device to remove. + */ +void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) +{ + if (!cdev) + return; + + thermal_debug_cdev_remove(cdev); + + if (thermal_cooling_device_exit(cdev)) + device_unregister(&cdev->device); } EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister); @@ -1314,7 +1369,7 @@ int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp) if (tz->ops.get_crit_temp) return tz->ops.get_crit_temp(tz, temp); - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); for_each_trip_desc(tz, td) { const struct thermal_trip *trip = &td->trip; @@ -1326,12 +1381,91 @@ int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp) } } - mutex_unlock(&tz->lock); - return ret; } EXPORT_SYMBOL_GPL(thermal_zone_get_crit_temp); +static void thermal_zone_device_check(struct work_struct *work) +{ + struct thermal_zone_device *tz = container_of(work, struct + thermal_zone_device, + poll_queue.work); + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); +} + +static void thermal_zone_device_init(struct thermal_zone_device *tz) +{ + struct thermal_trip_desc *td, *next; + + INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check); + + tz->temperature = THERMAL_TEMP_INIT; + tz->passive = 0; + tz->prev_low_trip = -INT_MAX; + tz->prev_high_trip = INT_MAX; + for_each_trip_desc(tz, td) { + struct thermal_instance *instance; + + list_for_each_entry(instance, &td->thermal_instances, trip_node) + instance->initialized = false; + } + /* + * At this point, all valid trips need to be moved to trips_high so that + * mitigation can be started if the zone temperature is above them. + */ + list_for_each_entry_safe(td, next, &tz->trips_invalid, list_node) { + if (td->trip.temperature != THERMAL_TEMP_INVALID) + move_to_trips_high(tz, td); + } + /* The trips_reached list may not be empty during system resume. */ + list_for_each_entry_safe(td, next, &tz->trips_reached, list_node) { + if (td->trip.temperature == THERMAL_TEMP_INVALID) + move_to_trips_invalid(tz, td); + else + move_to_trips_high(tz, td); + } +} + +static int thermal_zone_init_governor(struct thermal_zone_device *tz) +{ + struct thermal_governor *governor; + + guard(mutex)(&thermal_governor_lock); + + if (tz->tzp) + governor = __find_governor(tz->tzp->governor_name); + else + governor = def_governor; + + return thermal_set_governor(tz, governor); +} + +static void thermal_zone_init_complete(struct thermal_zone_device *tz) +{ + struct thermal_cooling_device *cdev; + + guard(mutex)(&thermal_list_lock); + + list_add_tail(&tz->node, &thermal_tz_list); + + guard(thermal_zone)(tz); + + /* Bind cooling devices for this zone. */ + list_for_each_entry(cdev, &thermal_cdev_list, node) + __thermal_zone_cdev_bind(tz, cdev); + + tz->state &= ~TZ_STATE_FLAG_INIT; + /* + * If system suspend or resume is in progress at this point, the + * new thermal zone needs to be marked as suspended because + * thermal_pm_notify() has run already. + */ + if (thermal_pm_suspended) + tz->state |= TZ_STATE_FLAG_SUSPENDED; + + __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); +} + /** * thermal_zone_device_register_with_trips() - register a new thermal zone device * @type: the thermal zone device type @@ -1366,12 +1500,10 @@ thermal_zone_device_register_with_trips(const char *type, unsigned int polling_delay) { const struct thermal_trip *trip = trips; - struct thermal_cooling_device *cdev; struct thermal_zone_device *tz; struct thermal_trip_desc *td; int id; int result; - struct thermal_governor *governor; if (!type || strlen(type) == 0) { pr_err("No thermal zone type defined\n"); @@ -1415,8 +1547,10 @@ thermal_zone_device_register_with_trips(const char *type, } } - INIT_LIST_HEAD(&tz->thermal_instances); INIT_LIST_HEAD(&tz->node); + INIT_LIST_HEAD(&tz->trips_high); + INIT_LIST_HEAD(&tz->trips_reached); + INIT_LIST_HEAD(&tz->trips_invalid); ida_init(&tz->ida); mutex_init(&tz->lock); init_completion(&tz->removal); @@ -1439,51 +1573,41 @@ thermal_zone_device_register_with_trips(const char *type, tz->num_trips = num_trips; for_each_trip_desc(tz, td) { td->trip = *trip++; + INIT_LIST_HEAD(&td->thermal_instances); + INIT_LIST_HEAD(&td->list_node); /* * Mark all thresholds as invalid to start with even though * this only matters for the trips that start as invalid and * become valid later. */ - td->threshold = INT_MAX; + move_to_trips_invalid(tz, td); } tz->polling_delay_jiffies = msecs_to_jiffies(polling_delay); tz->passive_delay_jiffies = msecs_to_jiffies(passive_delay); tz->recheck_delay_jiffies = THERMAL_RECHECK_DELAY; + tz->state = TZ_STATE_FLAG_INIT; + /* sys I/F */ /* Add nodes that are always present via .groups */ result = thermal_zone_create_device_groups(tz); if (result) goto remove_id; - /* A new thermal zone needs to be updated anyway. */ - atomic_set(&tz->need_update, 1); - result = dev_set_name(&tz->device, "thermal_zone%d", tz->id); if (result) { thermal_zone_destroy_device_groups(tz); goto remove_id; } + thermal_zone_device_init(tz); result = device_register(&tz->device); if (result) goto release_device; - /* Update 'this' zone's governor information */ - mutex_lock(&thermal_governor_lock); - - if (tz->tzp) - governor = __find_governor(tz->tzp->governor_name); - else - governor = def_governor; - - result = thermal_set_governor(tz, governor); - if (result) { - mutex_unlock(&thermal_governor_lock); + result = thermal_zone_init_governor(tz); + if (result) goto unregister; - } - - mutex_unlock(&thermal_governor_lock); if (!tz->tzp || !tz->tzp->no_hwmon) { result = thermal_add_hwmon_sysfs(tz); @@ -1491,22 +1615,11 @@ thermal_zone_device_register_with_trips(const char *type, goto unregister; } - mutex_lock(&thermal_list_lock); - - mutex_lock(&tz->lock); - list_add_tail(&tz->node, &thermal_tz_list); - mutex_unlock(&tz->lock); - - /* Bind cooling devices for this zone */ - list_for_each_entry(cdev, &thermal_cdev_list, node) - thermal_zone_cdev_bind(tz, cdev); - - mutex_unlock(&thermal_list_lock); + result = thermal_thresholds_init(tz); + if (result) + goto remove_hwmon; - thermal_zone_device_init(tz); - /* Update the new thermal zone and mark it as already updated. */ - if (atomic_cmpxchg(&tz->need_update, 1, 0)) - thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + thermal_zone_init_complete(tz); thermal_notify_tz_create(tz); @@ -1514,6 +1627,8 @@ thermal_zone_device_register_with_trips(const char *type, return tz; +remove_hwmon: + thermal_remove_hwmon_sysfs(tz); unregister: device_del(&tz->device); release_device: @@ -1563,44 +1678,46 @@ struct device *thermal_zone_device(struct thermal_zone_device *tzd) } EXPORT_SYMBOL_GPL(thermal_zone_device); +static bool thermal_zone_exit(struct thermal_zone_device *tz) +{ + struct thermal_cooling_device *cdev; + + guard(mutex)(&thermal_list_lock); + + if (list_empty(&tz->node)) + return false; + + guard(thermal_zone)(tz); + + tz->state |= TZ_STATE_FLAG_EXIT; + list_del_init(&tz->node); + + /* Unbind all cdevs associated with this thermal zone. */ + list_for_each_entry(cdev, &thermal_cdev_list, node) + __thermal_zone_cdev_unbind(tz, cdev); + + return true; +} + /** * thermal_zone_device_unregister - removes the registered thermal zone device * @tz: the thermal zone device to remove */ void thermal_zone_device_unregister(struct thermal_zone_device *tz) { - struct thermal_cooling_device *cdev; - struct thermal_zone_device *pos = NULL; - if (!tz) return; thermal_debug_tz_remove(tz); - mutex_lock(&thermal_list_lock); - list_for_each_entry(pos, &thermal_tz_list, node) - if (pos == tz) - break; - if (pos != tz) { - /* thermal zone device not found */ - mutex_unlock(&thermal_list_lock); + if (!thermal_zone_exit(tz)) return; - } - - mutex_lock(&tz->lock); - list_del(&tz->node); - mutex_unlock(&tz->lock); - - /* Unbind all cdevs associated with 'this' thermal zone */ - list_for_each_entry(cdev, &thermal_cdev_list, node) - thermal_zone_cdev_unbind(tz, cdev); - - mutex_unlock(&thermal_list_lock); cancel_delayed_work_sync(&tz->poll_queue); thermal_set_governor(tz, NULL); + thermal_thresholds_exit(tz); thermal_remove_hwmon_sysfs(tz); ida_free(&thermal_tz_ida, tz->id); ida_destroy(&tz->ida); @@ -1632,24 +1749,23 @@ struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name) unsigned int found = 0; if (!name) - goto exit; + return ERR_PTR(-EINVAL); + + guard(mutex)(&thermal_list_lock); - mutex_lock(&thermal_list_lock); list_for_each_entry(pos, &thermal_tz_list, node) if (!strncasecmp(name, pos->type, THERMAL_NAME_LENGTH)) { found++; ref = pos; } - mutex_unlock(&thermal_list_lock); - /* nothing has been found, thus an error code for it */ - if (found == 0) - ref = ERR_PTR(-ENODEV); - else if (found > 1) - /* Success only when an unique zone is found */ - ref = ERR_PTR(-EEXIST); + if (!found) + return ERR_PTR(-ENODEV); + + /* Success only when one zone is found. */ + if (found > 1) + return ERR_PTR(-EEXIST); -exit: return ref; } EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name); @@ -1660,9 +1776,9 @@ static void thermal_zone_device_resume(struct work_struct *work) tz = container_of(work, struct thermal_zone_device, poll_queue.work); - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); - tz->suspended = false; + tz->state &= ~(TZ_STATE_FLAG_SUSPENDED | TZ_STATE_FLAG_RESUMING); thermal_debug_tz_resume(tz); thermal_zone_device_init(tz); @@ -1670,74 +1786,81 @@ static void thermal_zone_device_resume(struct work_struct *work) __thermal_zone_device_update(tz, THERMAL_TZ_RESUME); complete(&tz->resume); - tz->resuming = false; - - mutex_unlock(&tz->lock); } -static int thermal_pm_notify(struct notifier_block *nb, - unsigned long mode, void *_unused) +static void thermal_zone_pm_prepare(struct thermal_zone_device *tz) { - struct thermal_zone_device *tz; + guard(thermal_zone)(tz); - switch (mode) { - case PM_HIBERNATION_PREPARE: - case PM_RESTORE_PREPARE: - case PM_SUSPEND_PREPARE: - mutex_lock(&thermal_list_lock); + if (tz->state & TZ_STATE_FLAG_RESUMING) { + /* + * thermal_zone_device_resume() queued up for this zone has not + * acquired the lock yet, so release it to let the function run + * and wait util it has done the work. + */ + scoped_guard(thermal_zone_reverse, tz) { + wait_for_completion(&tz->resume); + } + } - list_for_each_entry(tz, &thermal_tz_list, node) { - mutex_lock(&tz->lock); + tz->state |= TZ_STATE_FLAG_SUSPENDED; +} - if (tz->resuming) { - /* - * thermal_zone_device_resume() queued up for - * this zone has not acquired the lock yet, so - * release it to let the function run and wait - * util it has done the work. - */ - mutex_unlock(&tz->lock); +static void thermal_pm_notify_prepare(void) +{ + struct thermal_zone_device *tz; - wait_for_completion(&tz->resume); + guard(mutex)(&thermal_list_lock); - mutex_lock(&tz->lock); - } + thermal_pm_suspended = true; - tz->suspended = true; + list_for_each_entry(tz, &thermal_tz_list, node) + thermal_zone_pm_prepare(tz); +} - mutex_unlock(&tz->lock); - } +static void thermal_zone_pm_complete(struct thermal_zone_device *tz) +{ + guard(thermal_zone)(tz); - mutex_unlock(&thermal_list_lock); - break; - case PM_POST_HIBERNATION: - case PM_POST_RESTORE: - case PM_POST_SUSPEND: - mutex_lock(&thermal_list_lock); + cancel_delayed_work(&tz->poll_queue); - list_for_each_entry(tz, &thermal_tz_list, node) { - mutex_lock(&tz->lock); + reinit_completion(&tz->resume); + tz->state |= TZ_STATE_FLAG_RESUMING; + + /* + * Replace the work function with the resume one, which will restore the + * original work function and schedule the polling work if needed. + */ + INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_resume); + /* Queue up the work without a delay. */ + mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, 0); +} - cancel_delayed_work(&tz->poll_queue); +static void thermal_pm_notify_complete(void) +{ + struct thermal_zone_device *tz; - reinit_completion(&tz->resume); - tz->resuming = true; + guard(mutex)(&thermal_list_lock); - /* - * Replace the work function with the resume one, which - * will restore the original work function and schedule - * the polling work if needed. - */ - INIT_DELAYED_WORK(&tz->poll_queue, - thermal_zone_device_resume); - /* Queue up the work without a delay. */ - mod_delayed_work(system_freezable_power_efficient_wq, - &tz->poll_queue, 0); + thermal_pm_suspended = false; - mutex_unlock(&tz->lock); - } + list_for_each_entry(tz, &thermal_tz_list, node) + thermal_zone_pm_complete(tz); +} - mutex_unlock(&thermal_list_lock); +static int thermal_pm_notify(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + thermal_pm_notify_prepare(); + break; + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + thermal_pm_notify_complete(); break; default: break; diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index a64d39b1c86b23..be271e7c8f4141 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -9,10 +9,12 @@ #ifndef __THERMAL_CORE_H__ #define __THERMAL_CORE_H__ +#include #include #include #include "thermal_netlink.h" +#include "thermal_thresholds.h" #include "thermal_debugfs.h" struct thermal_attr { @@ -29,8 +31,8 @@ struct thermal_trip_attrs { struct thermal_trip_desc { struct thermal_trip trip; struct thermal_trip_attrs trip_attrs; - struct list_head notify_list_node; - int notify_temp; + struct list_head list_node; + struct list_head thermal_instances; int threshold; }; @@ -61,6 +63,13 @@ struct thermal_governor { struct list_head governor_list; }; +#define TZ_STATE_FLAG_SUSPENDED BIT(0) +#define TZ_STATE_FLAG_RESUMING BIT(1) +#define TZ_STATE_FLAG_INIT BIT(2) +#define TZ_STATE_FLAG_EXIT BIT(3) + +#define TZ_STATE_READY 0 + /** * struct thermal_zone_device - structure for a thermal zone * @id: unique id number for each thermal zone @@ -68,6 +77,9 @@ struct thermal_governor { * @device: &struct device for this thermal zone * @removal: removal completion * @resume: resume completion + * @trips_high: trips above the current zone temperature + * @trips_reached: trips below or at the current zone temperature + * @trips_invalid: trips with invalid temperature * @mode: current mode of this thermal zone * @devdata: private pointer for device private data * @num_trips: number of trip points the thermal zone supports @@ -88,20 +100,17 @@ struct thermal_governor { trip point. * @prev_high_trip: the above current temperature if you've crossed a passive trip point. - * @need_update: if equals 1, thermal_zone_device_update needs to be invoked. * @ops: operations this &thermal_zone_device supports * @tzp: thermal zone parameters * @governor: pointer to the governor for this thermal zone * @governor_data: private pointer for governor data - * @thermal_instances: list of &struct thermal_instance of this thermal zone * @ida: &struct ida to generate unique id for this zone's cooling * devices * @lock: lock to protect thermal_instances list * @node: node in thermal_tz_list (in thermal_core.c) * @poll_queue: delayed work for polling * @notify_event: Last notification event - * @suspended: thermal zone suspend indicator - * @resuming: indicates whether or not thermal zone resume is in progress + * @state: current state of the thermal zone * @trips: array of struct thermal_trip objects */ struct thermal_zone_device { @@ -111,6 +120,9 @@ struct thermal_zone_device { struct completion removal; struct completion resume; struct attribute_group trips_attribute_group; + struct list_head trips_high; + struct list_head trips_reached; + struct list_head trips_invalid; enum thermal_device_mode mode; void *devdata; int num_trips; @@ -123,25 +135,29 @@ struct thermal_zone_device { int passive; int prev_low_trip; int prev_high_trip; - atomic_t need_update; struct thermal_zone_device_ops ops; struct thermal_zone_params *tzp; struct thermal_governor *governor; void *governor_data; - struct list_head thermal_instances; struct ida ida; struct mutex lock; struct list_head node; struct delayed_work poll_queue; enum thermal_notify_event notify_event; - bool suspended; - bool resuming; + u8 state; #ifdef CONFIG_THERMAL_DEBUGFS struct thermal_debugfs *debugfs; #endif + struct list_head user_thresholds; struct thermal_trip_desc trips[] __counted_by(num_trips); }; +DEFINE_GUARD(thermal_zone, struct thermal_zone_device *, mutex_lock(&_T->lock), + mutex_unlock(&_T->lock)) + +DEFINE_GUARD(thermal_zone_reverse, struct thermal_zone_device *, + mutex_unlock(&_T->lock), mutex_lock(&_T->lock)) + /* Initial thermal zone temperature. */ #define THERMAL_TEMP_INIT INT_MIN @@ -204,6 +220,7 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) } void thermal_cdev_update(struct thermal_cooling_device *); +void thermal_cdev_update_nocheck(struct thermal_cooling_device *cdev); void __thermal_cdev_update(struct thermal_cooling_device *cdev); int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip); @@ -226,7 +243,7 @@ struct thermal_instance { struct device_attribute attr; char weight_attr_name[THERMAL_NAME_LENGTH]; struct device_attribute weight_attr; - struct list_head tz_node; /* node in tz->thermal_instances */ + struct list_head trip_node; /* node in trip->thermal_instances */ struct list_head cdev_node; /* node in cdev->thermal_instances */ unsigned int weight; /* The weight of the cooling device */ bool upper_no_limit; @@ -261,8 +278,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz, int low, int high); int thermal_zone_trip_id(const struct thermal_zone_device *tz, const struct thermal_trip *trip); int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); -void thermal_zone_trip_down(struct thermal_zone_device *tz, - const struct thermal_trip *trip); void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz, struct thermal_trip *trip, int hyst); diff --git a/drivers/thermal/thermal_debugfs.c b/drivers/thermal/thermal_debugfs.c index 939d3e5f181771..c800504c3cfe0e 100644 --- a/drivers/thermal/thermal_debugfs.c +++ b/drivers/thermal/thermal_debugfs.c @@ -516,6 +516,19 @@ void thermal_debug_cdev_add(struct thermal_cooling_device *cdev, int state) cdev->debugfs = thermal_dbg; } +static struct thermal_debugfs *thermal_debug_cdev_clear(struct thermal_cooling_device *cdev) +{ + struct thermal_debugfs *thermal_dbg; + + guard(cooling_dev)(cdev); + + thermal_dbg = cdev->debugfs; + if (thermal_dbg) + cdev->debugfs = NULL; + + return thermal_dbg; +} + /** * thermal_debug_cdev_remove - Remove a cooling device debugfs entry * @@ -527,17 +540,9 @@ void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev) { struct thermal_debugfs *thermal_dbg; - mutex_lock(&cdev->lock); - - thermal_dbg = cdev->debugfs; - if (!thermal_dbg) { - mutex_unlock(&cdev->lock); + thermal_dbg = thermal_debug_cdev_clear(cdev); + if (!thermal_dbg) return; - } - - cdev->debugfs = NULL; - - mutex_unlock(&cdev->lock); mutex_lock(&thermal_dbg->lock); @@ -885,6 +890,19 @@ void thermal_debug_tz_add(struct thermal_zone_device *tz) tz->debugfs = thermal_dbg; } +static struct thermal_debugfs *thermal_debug_tz_clear(struct thermal_zone_device *tz) +{ + struct thermal_debugfs *thermal_dbg; + + guard(thermal_zone)(tz); + + thermal_dbg = tz->debugfs; + if (thermal_dbg) + tz->debugfs = NULL; + + return thermal_dbg; +} + void thermal_debug_tz_remove(struct thermal_zone_device *tz) { struct thermal_debugfs *thermal_dbg; @@ -892,17 +910,9 @@ void thermal_debug_tz_remove(struct thermal_zone_device *tz) struct tz_debugfs *tz_dbg; int *trips_crossed; - mutex_lock(&tz->lock); - - thermal_dbg = tz->debugfs; - if (!thermal_dbg) { - mutex_unlock(&tz->lock); + thermal_dbg = thermal_debug_tz_clear(tz); + if (!thermal_dbg) return; - } - - tz->debugfs = NULL; - - mutex_unlock(&tz->lock); tz_dbg = &thermal_dbg->tz_dbg; diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c index dc374a7a1a659f..b1152ad7acc900 100644 --- a/drivers/thermal/thermal_helpers.c +++ b/drivers/thermal/thermal_helpers.c @@ -43,10 +43,11 @@ static bool thermal_instance_present(struct thermal_zone_device *tz, struct thermal_cooling_device *cdev, const struct thermal_trip *trip) { + const struct thermal_trip_desc *td = trip_to_trip_desc(trip); struct thermal_instance *ti; - list_for_each_entry(ti, &tz->thermal_instances, tz_node) { - if (ti->trip == trip && ti->cdev == cdev) + list_for_each_entry(ti, &td->thermal_instances, trip_node) { + if (ti->cdev == cdev) return true; } @@ -57,17 +58,10 @@ bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz, const struct thermal_trip *trip, struct thermal_cooling_device *cdev) { - bool ret; + guard(thermal_zone)(tz); + guard(cooling_dev)(cdev); - mutex_lock(&tz->lock); - mutex_lock(&cdev->lock); - - ret = thermal_instance_present(tz, cdev, trip); - - mutex_unlock(&cdev->lock); - mutex_unlock(&tz->lock); - - return ret; + return thermal_instance_present(tz, cdev, trip); } EXPORT_SYMBOL_GPL(thermal_trip_is_bound_to_cdev); @@ -137,19 +131,14 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) if (IS_ERR_OR_NULL(tz)) return -EINVAL; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); - if (!tz->ops.get_temp) { - ret = -EINVAL; - goto unlock; - } + if (!tz->ops.get_temp) + return -EINVAL; ret = __thermal_zone_get_temp(tz, temp); if (!ret && *temp <= THERMAL_TEMP_INVALID) - ret = -ENODATA; - -unlock: - mutex_unlock(&tz->lock); + return -ENODATA; return ret; } @@ -201,12 +190,23 @@ void __thermal_cdev_update(struct thermal_cooling_device *cdev) */ void thermal_cdev_update(struct thermal_cooling_device *cdev) { - mutex_lock(&cdev->lock); + guard(cooling_dev)(cdev); + if (!cdev->updated) { __thermal_cdev_update(cdev); cdev->updated = true; } - mutex_unlock(&cdev->lock); +} + +/** + * thermal_cdev_update_nocheck() - Unconditionally update cooling device state + * @cdev: Target cooling device. + */ +void thermal_cdev_update_nocheck(struct thermal_cooling_device *cdev) +{ + guard(cooling_dev)(cdev); + + __thermal_cdev_update(cdev); } /** diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c index f0e504fd866aeb..0ecccd4d8556c4 100644 --- a/drivers/thermal/thermal_hwmon.c +++ b/drivers/thermal/thermal_hwmon.c @@ -78,12 +78,9 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf) int temperature; int ret; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); ret = tz->ops.get_crit_temp(tz, &temperature); - - mutex_unlock(&tz->lock); - if (ret) return ret; @@ -287,4 +284,4 @@ int devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device } EXPORT_SYMBOL_GPL(devm_thermal_add_hwmon_sysfs); -MODULE_IMPORT_NS(HWMON_THERMAL); +MODULE_IMPORT_NS("HWMON_THERMAL"); diff --git a/drivers/thermal/thermal_netlink.c b/drivers/thermal/thermal_netlink.c index f3c58c708969c2..315a76b01f6a19 100644 --- a/drivers/thermal/thermal_netlink.c +++ b/drivers/thermal/thermal_netlink.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,11 @@ static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID] = { .type = NLA_U32 }, [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE] = { .type = NLA_U32 }, [THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY] = { .type = NLA_U32 }, + + /* Thresholds */ + [THERMAL_GENL_ATTR_THRESHOLD] = { .type = NLA_NESTED }, + [THERMAL_GENL_ATTR_THRESHOLD_TEMP] = { .type = NLA_U32 }, + [THERMAL_GENL_ATTR_THRESHOLD_DIRECTION] = { .type = NLA_U32 }, }; struct param { @@ -62,6 +68,8 @@ struct param { int trip_type; int trip_hyst; int temp; + int prev_temp; + int direction; int cdev_state; int cdev_max_state; struct thermal_genl_cpu_caps *cpu_capabilities; @@ -234,6 +242,34 @@ static int thermal_genl_event_cpu_capability_change(struct param *p) return -EMSGSIZE; } +static int thermal_genl_event_threshold_add(struct param *p) +{ + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, p->temp) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, p->direction)) + return -EMSGSIZE; + + return 0; +} + +static int thermal_genl_event_threshold_flush(struct param *p) +{ + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) + return -EMSGSIZE; + + return 0; +} + +static int thermal_genl_event_threshold_up(struct param *p) +{ + if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_PREV_TEMP, p->prev_temp) || + nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TEMP, p->temp)) + return -EMSGSIZE; + + return 0; +} + int thermal_genl_event_tz_delete(struct param *p) __attribute__((alias("thermal_genl_event_tz"))); @@ -246,6 +282,12 @@ int thermal_genl_event_tz_disable(struct param *p) int thermal_genl_event_tz_trip_down(struct param *p) __attribute__((alias("thermal_genl_event_tz_trip_up"))); +int thermal_genl_event_threshold_delete(struct param *p) + __attribute__((alias("thermal_genl_event_threshold_add"))); + +int thermal_genl_event_threshold_down(struct param *p) + __attribute__((alias("thermal_genl_event_threshold_up"))); + static cb_t event_cb[] = { [THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create, [THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete, @@ -259,6 +301,11 @@ static cb_t event_cb[] = { [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update, [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change, [THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change, + [THERMAL_GENL_EVENT_THRESHOLD_ADD] = thermal_genl_event_threshold_add, + [THERMAL_GENL_EVENT_THRESHOLD_DELETE] = thermal_genl_event_threshold_delete, + [THERMAL_GENL_EVENT_THRESHOLD_FLUSH] = thermal_genl_event_threshold_flush, + [THERMAL_GENL_EVENT_THRESHOLD_DOWN] = thermal_genl_event_threshold_down, + [THERMAL_GENL_EVENT_THRESHOLD_UP] = thermal_genl_event_threshold_up, }; /* @@ -401,6 +448,43 @@ int thermal_genl_cpu_capability_event(int count, } EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event); +int thermal_notify_threshold_add(const struct thermal_zone_device *tz, + int temperature, int direction) +{ + struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_ADD, &p); +} + +int thermal_notify_threshold_delete(const struct thermal_zone_device *tz, + int temperature, int direction) +{ + struct param p = { .tz_id = tz->id, .temp = temperature, .direction = direction }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DELETE, &p); +} + +int thermal_notify_threshold_flush(const struct thermal_zone_device *tz) +{ + struct param p = { .tz_id = tz->id }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_FLUSH, &p); +} + +int thermal_notify_threshold_down(const struct thermal_zone_device *tz) +{ + struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_DOWN, &p); +} + +int thermal_notify_threshold_up(const struct thermal_zone_device *tz) +{ + struct param p = { .tz_id = tz->id, .temp = tz->temperature, .prev_temp = tz->last_temperature }; + + return thermal_genl_send_event(THERMAL_GENL_EVENT_THRESHOLD_UP, &p); +} + /*************************** Command encoding ********************************/ static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz, @@ -459,7 +543,7 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p) if (!start_trip) return -EMSGSIZE; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); for_each_trip_desc(tz, td) { const struct thermal_trip *trip = &td->trip; @@ -469,19 +553,12 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p) nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, trip->type) || nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TEMP, trip->temperature) || nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_HYST, trip->hysteresis)) - goto out_cancel_nest; + return -EMSGSIZE; } - mutex_unlock(&tz->lock); - nla_nest_end(msg, start_trip); return 0; - -out_cancel_nest: - mutex_unlock(&tz->lock); - - return -EMSGSIZE; } static int thermal_genl_cmd_tz_get_temp(struct param *p) @@ -512,7 +589,7 @@ static int thermal_genl_cmd_tz_get_temp(struct param *p) static int thermal_genl_cmd_tz_get_gov(struct param *p) { struct sk_buff *msg = p->msg; - int id, ret = 0; + int id; if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) return -EINVAL; @@ -523,16 +600,14 @@ static int thermal_genl_cmd_tz_get_gov(struct param *p) if (!tz) return -EINVAL; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id) || nla_put_string(msg, THERMAL_GENL_ATTR_TZ_GOV_NAME, tz->governor->name)) - ret = -EMSGSIZE; - - mutex_unlock(&tz->lock); + return -EMSGSIZE; - return ret; + return 0; } static int __thermal_genl_cmd_cdev_get(struct thermal_cooling_device *cdev, @@ -572,12 +647,128 @@ static int thermal_genl_cmd_cdev_get(struct param *p) return ret; } +static int __thermal_genl_cmd_threshold_get(struct user_threshold *threshold, void *arg) +{ + struct sk_buff *msg = arg; + + if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, threshold->temperature) || + nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, threshold->direction)) + return -1; + + return 0; +} + +static int thermal_genl_cmd_threshold_get(struct param *p) +{ + struct sk_buff *msg = p->msg; + struct nlattr *start_trip; + int id, ret; + + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) + return -EINVAL; + + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); + + CLASS(thermal_zone_get_by_id, tz)(id); + if (!tz) + return -EINVAL; + + start_trip = nla_nest_start(msg, THERMAL_GENL_ATTR_THRESHOLD); + if (!start_trip) + return -EMSGSIZE; + + ret = thermal_thresholds_for_each(tz, __thermal_genl_cmd_threshold_get, msg); + if (ret) + return -EMSGSIZE; + + nla_nest_end(msg, start_trip); + + return 0; +} + +static int thermal_genl_cmd_threshold_add(struct param *p) +{ + int id, temp, direction; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] || + !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] || + !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]) + return -EINVAL; + + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); + temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]); + direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]); + + CLASS(thermal_zone_get_by_id, tz)(id); + if (!tz) + return -EINVAL; + + guard(thermal_zone)(tz); + + return thermal_thresholds_add(tz, temp, direction); +} + +static int thermal_genl_cmd_threshold_delete(struct param *p) +{ + int id, temp, direction; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID] || + !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP] || + !p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]) + return -EINVAL; + + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); + temp = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]); + direction = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]); + + CLASS(thermal_zone_get_by_id, tz)(id); + if (!tz) + return -EINVAL; + + guard(thermal_zone)(tz); + + return thermal_thresholds_delete(tz, temp, direction); +} + +static int thermal_genl_cmd_threshold_flush(struct param *p) +{ + int id; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!p->attrs[THERMAL_GENL_ATTR_TZ_ID]) + return -EINVAL; + + id = nla_get_u32(p->attrs[THERMAL_GENL_ATTR_TZ_ID]); + + CLASS(thermal_zone_get_by_id, tz)(id); + if (!tz) + return -EINVAL; + + guard(thermal_zone)(tz); + + thermal_thresholds_flush(tz); + + return 0; +} + static cb_t cmd_cb[] = { - [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id, - [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip, - [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp, - [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov, - [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get, + [THERMAL_GENL_CMD_TZ_GET_ID] = thermal_genl_cmd_tz_get_id, + [THERMAL_GENL_CMD_TZ_GET_TRIP] = thermal_genl_cmd_tz_get_trip, + [THERMAL_GENL_CMD_TZ_GET_TEMP] = thermal_genl_cmd_tz_get_temp, + [THERMAL_GENL_CMD_TZ_GET_GOV] = thermal_genl_cmd_tz_get_gov, + [THERMAL_GENL_CMD_CDEV_GET] = thermal_genl_cmd_cdev_get, + [THERMAL_GENL_CMD_THRESHOLD_GET] = thermal_genl_cmd_threshold_get, + [THERMAL_GENL_CMD_THRESHOLD_ADD] = thermal_genl_cmd_threshold_add, + [THERMAL_GENL_CMD_THRESHOLD_DELETE] = thermal_genl_cmd_threshold_delete, + [THERMAL_GENL_CMD_THRESHOLD_FLUSH] = thermal_genl_cmd_threshold_flush, }; static int thermal_genl_cmd_dumpit(struct sk_buff *skb, @@ -688,6 +879,26 @@ static const struct genl_small_ops thermal_genl_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .dumpit = thermal_genl_cmd_dumpit, }, + { + .cmd = THERMAL_GENL_CMD_THRESHOLD_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = thermal_genl_cmd_doit, + }, + { + .cmd = THERMAL_GENL_CMD_THRESHOLD_ADD, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = thermal_genl_cmd_doit, + }, + { + .cmd = THERMAL_GENL_CMD_THRESHOLD_DELETE, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = thermal_genl_cmd_doit, + }, + { + .cmd = THERMAL_GENL_CMD_THRESHOLD_FLUSH, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = thermal_genl_cmd_doit, + }, }; static struct genl_family thermal_genl_family __ro_after_init = { @@ -700,7 +911,7 @@ static struct genl_family thermal_genl_family __ro_after_init = { .unbind = thermal_genl_unbind, .small_ops = thermal_genl_ops, .n_small_ops = ARRAY_SIZE(thermal_genl_ops), - .resv_start_op = THERMAL_GENL_CMD_CDEV_GET + 1, + .resv_start_op = __THERMAL_GENL_CMD_MAX, .mcgrps = thermal_genl_mcgrps, .n_mcgrps = ARRAY_SIZE(thermal_genl_mcgrps), }; diff --git a/drivers/thermal/thermal_netlink.h b/drivers/thermal/thermal_netlink.h index e01221e8816b42..075e9ae85f3d08 100644 --- a/drivers/thermal/thermal_netlink.h +++ b/drivers/thermal/thermal_netlink.h @@ -53,6 +53,13 @@ int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz, int thermal_genl_sampling_temp(int id, int temp); int thermal_genl_cpu_capability_event(int count, struct thermal_genl_cpu_caps *caps); +int thermal_notify_threshold_add(const struct thermal_zone_device *tz, + int temperature, int direction); +int thermal_notify_threshold_delete(const struct thermal_zone_device *tz, + int temperature, int direction); +int thermal_notify_threshold_flush(const struct thermal_zone_device *tz); +int thermal_notify_threshold_down(const struct thermal_zone_device *tz); +int thermal_notify_threshold_up(const struct thermal_zone_device *tz); #else static inline int thermal_netlink_init(void) { @@ -139,6 +146,33 @@ static inline int thermal_genl_cpu_capability_event(int count, struct thermal_ge return 0; } +static inline int thermal_notify_threshold_add(const struct thermal_zone_device *tz, + int temperature, int direction) +{ + return 0; +} + +static inline int thermal_notify_threshold_delete(const struct thermal_zone_device *tz, + int temperature, int direction) +{ + return 0; +} + +static inline int thermal_notify_threshold_flush(const struct thermal_zone_device *tz) +{ + return 0; +} + +static inline int thermal_notify_threshold_down(const struct thermal_zone_device *tz) +{ + return 0; +} + +static inline int thermal_notify_threshold_up(const struct thermal_zone_device *tz) +{ + return 0; +} + static inline void __init thermal_netlink_exit(void) {} #endif /* CONFIG_THERMAL_NETLINK */ diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index 07e09897165f34..fab11b98ca4952 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c @@ -95,13 +95,11 @@ static int thermal_of_populate_trip(struct device_node *np, static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips) { - struct thermal_trip *tt; - struct device_node *trips; int ret, count; *ntrips = 0; - trips = of_get_child_by_name(np, "trips"); + struct device_node *trips __free(device_node) = of_get_child_by_name(np, "trips"); if (!trips) return NULL; @@ -109,39 +107,27 @@ static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *n if (!count) return NULL; - tt = kzalloc(sizeof(*tt) * count, GFP_KERNEL); - if (!tt) { - ret = -ENOMEM; - goto out_of_node_put; - } - - *ntrips = count; + struct thermal_trip *tt __free(kfree) = kzalloc(sizeof(*tt) * count, GFP_KERNEL); + if (!tt) + return ERR_PTR(-ENOMEM); count = 0; for_each_child_of_node_scoped(trips, trip) { ret = thermal_of_populate_trip(trip, &tt[count++]); if (ret) - goto out_kfree; + return ERR_PTR(ret); } - of_node_put(trips); - - return tt; - -out_kfree: - kfree(tt); -out_of_node_put: - of_node_put(trips); + *ntrips = count; - return ERR_PTR(ret); + return no_free_ptr(tt); } static struct device_node *of_thermal_zone_find(struct device_node *sensor, int id) { - struct device_node *np, *tz; struct of_phandle_args sensor_specs; - np = of_find_node_by_name(NULL, "thermal-zones"); + struct device_node *np __free(device_node) = of_find_node_by_name(NULL, "thermal-zones"); if (!np) { pr_debug("No thermal zones description\n"); return ERR_PTR(-ENODEV); @@ -159,8 +145,7 @@ static struct device_node *of_thermal_zone_find(struct device_node *sensor, int "#thermal-sensor-cells"); if (count <= 0) { pr_err("%pOFn: missing thermal sensor\n", child); - tz = ERR_PTR(-EINVAL); - goto out; + return ERR_PTR(-EINVAL); } for (i = 0; i < count; i++) { @@ -172,22 +157,18 @@ static struct device_node *of_thermal_zone_find(struct device_node *sensor, int i, &sensor_specs); if (ret < 0) { pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", child, ret); - tz = ERR_PTR(ret); - goto out; + return ERR_PTR(ret); } if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ? sensor_specs.args[0] : 0)) { pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, child); - tz = no_free_ptr(child); - goto out; + return no_free_ptr(child); } } } - tz = ERR_PTR(-ENODEV); -out: - of_node_put(np); - return tz; + + return ERR_PTR(-ENODEV); } static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdelay) @@ -297,7 +278,7 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz, struct thermal_cooling_device *cdev, struct cooling_spec *c) { - struct device_node *tz_np, *cm_np, *child; + struct device_node *tz_np, *cm_np; bool result = false; tz_np = thermal_of_zone_get_by_name(tz); @@ -311,7 +292,7 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz, goto out; /* Look up the trip and the cdev in the cooling maps. */ - for_each_child_of_node(cm_np, child) { + for_each_child_of_node_scoped(cm_np, child) { struct device_node *tr_np; int count, i; @@ -330,7 +311,6 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz, break; } - of_node_put(child); break; } diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 1838aa729bb50a..24b9055a0b6c51 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -50,13 +50,13 @@ static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); - int enabled; - mutex_lock(&tz->lock); - enabled = tz->mode == THERMAL_DEVICE_ENABLED; - mutex_unlock(&tz->lock); + guard(thermal_zone)(tz); - return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled"); + if (tz->mode == THERMAL_DEVICE_ENABLED) + return sprintf(buf, "enabled\n"); + + return sprintf(buf, "disabled\n"); } static ssize_t @@ -103,38 +103,34 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr, { struct thermal_trip *trip = thermal_trip_of_attr(attr, temp); struct thermal_zone_device *tz = to_thermal_zone(dev); - int ret, temp; + int temp; - ret = kstrtoint(buf, 10, &temp); - if (ret) + if (kstrtoint(buf, 10, &temp)) return -EINVAL; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); if (temp == trip->temperature) - goto unlock; + return count; /* Arrange the condition to avoid integer overflows. */ if (temp != THERMAL_TEMP_INVALID && - temp <= trip->hysteresis + THERMAL_TEMP_INVALID) { - ret = -EINVAL; - goto unlock; - } + temp <= trip->hysteresis + THERMAL_TEMP_INVALID) + return -EINVAL; if (tz->ops.set_trip_temp) { + int ret; + ret = tz->ops.set_trip_temp(tz, trip, temp); if (ret) - goto unlock; + return ret; } thermal_zone_set_trip_temp(tz, trip, temp); __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); -unlock: - mutex_unlock(&tz->lock); - - return ret ? ret : count; + return count; } static ssize_t @@ -152,16 +148,15 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, { struct thermal_trip *trip = thermal_trip_of_attr(attr, hyst); struct thermal_zone_device *tz = to_thermal_zone(dev); - int ret, hyst; + int hyst; - ret = kstrtoint(buf, 10, &hyst); - if (ret || hyst < 0) + if (kstrtoint(buf, 10, &hyst) || hyst < 0) return -EINVAL; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); if (hyst == trip->hysteresis) - goto unlock; + return count; /* * Allow the hysteresis to be updated when the temperature is invalid @@ -171,22 +166,17 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, */ if (trip->temperature == THERMAL_TEMP_INVALID) { WRITE_ONCE(trip->hysteresis, hyst); - goto unlock; + return count; } - if (trip->temperature - hyst <= THERMAL_TEMP_INVALID) { - ret = -EINVAL; - goto unlock; - } + if (trip->temperature - hyst <= THERMAL_TEMP_INVALID) + return -EINVAL; thermal_zone_set_trip_hyst(tz, trip, hyst); __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); -unlock: - mutex_unlock(&tz->lock); - - return ret ? ret : count; + return count; } static ssize_t @@ -236,25 +226,26 @@ emul_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct thermal_zone_device *tz = to_thermal_zone(dev); - int ret = 0; int temperature; if (kstrtoint(buf, 10, &temperature)) return -EINVAL; - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); - if (!tz->ops.set_emul_temp) - tz->emul_temperature = temperature; - else - ret = tz->ops.set_emul_temp(tz, temperature); + if (tz->ops.set_emul_temp) { + int ret; - if (!ret) - __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + ret = tz->ops.set_emul_temp(tz, temperature); + if (ret) + return ret; + } else { + tz->emul_temperature = temperature; + } - mutex_unlock(&tz->lock); + __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); - return ret ? ret : count; + return count; } static DEVICE_ATTR_WO(emul_temp); #endif @@ -553,14 +544,15 @@ cur_state_store(struct device *dev, struct device_attribute *attr, if (state > cdev->max_state) return -EINVAL; - mutex_lock(&cdev->lock); + guard(cooling_dev)(cdev); result = cdev->ops->set_cur_state(cdev, state); - if (!result) - thermal_cooling_device_stats_update(cdev, state); + if (result) + return result; - mutex_unlock(&cdev->lock); - return result ? result : count; + thermal_cooling_device_stats_update(cdev, state); + + return count; } static struct device_attribute @@ -634,21 +626,18 @@ static ssize_t total_trans_show(struct device *dev, { struct thermal_cooling_device *cdev = to_cooling_device(dev); struct cooling_dev_stats *stats; - int ret = 0; + int ret; - mutex_lock(&cdev->lock); + guard(cooling_dev)(cdev); stats = cdev->stats; if (!stats) - goto unlock; + return 0; spin_lock(&stats->lock); ret = sprintf(buf, "%u\n", stats->total_trans); spin_unlock(&stats->lock); -unlock: - mutex_unlock(&cdev->lock); - return ret; } @@ -661,11 +650,11 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, ssize_t len = 0; int i; - mutex_lock(&cdev->lock); + guard(cooling_dev)(cdev); stats = cdev->stats; if (!stats) - goto unlock; + return 0; spin_lock(&stats->lock); @@ -677,9 +666,6 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr, } spin_unlock(&stats->lock); -unlock: - mutex_unlock(&cdev->lock); - return len; } @@ -691,11 +677,11 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, struct cooling_dev_stats *stats; int i, states; - mutex_lock(&cdev->lock); + guard(cooling_dev)(cdev); stats = cdev->stats; if (!stats) - goto unlock; + return count; states = cdev->max_state + 1; @@ -711,9 +697,6 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf, spin_unlock(&stats->lock); -unlock: - mutex_unlock(&cdev->lock); - return count; } @@ -725,13 +708,11 @@ static ssize_t trans_table_show(struct device *dev, ssize_t len = 0; int i, j; - mutex_lock(&cdev->lock); + guard(cooling_dev)(cdev); stats = cdev->stats; - if (!stats) { - len = -ENODATA; - goto unlock; - } + if (!stats) + return -ENODATA; len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); @@ -740,10 +721,8 @@ static ssize_t trans_table_show(struct device *dev, break; len += snprintf(buf + len, PAGE_SIZE - len, "state%2u ", i); } - if (len >= PAGE_SIZE) { - len = PAGE_SIZE; - goto unlock; - } + if (len >= PAGE_SIZE) + return PAGE_SIZE; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); @@ -769,9 +748,6 @@ static ssize_t trans_table_show(struct device *dev, len = -EFBIG; } -unlock: - mutex_unlock(&cdev->lock); - return len; } @@ -894,13 +870,11 @@ ssize_t weight_store(struct device *dev, struct device_attribute *attr, instance = container_of(attr, struct thermal_instance, weight_attr); /* Don't race with governors using the 'weight' value */ - mutex_lock(&tz->lock); + guard(thermal_zone)(tz); instance->weight = weight; thermal_governor_update_tz(tz, THERMAL_INSTANCE_WEIGHT_CHANGED); - mutex_unlock(&tz->lock); - return count; } diff --git a/drivers/thermal/thermal_thresholds.c b/drivers/thermal/thermal_thresholds.c new file mode 100644 index 00000000000000..38f5fd0e89303a --- /dev/null +++ b/drivers/thermal/thermal_thresholds.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 Linaro Limited + * + * Author: Daniel Lezcano + * + * Thermal thresholds + */ +#include +#include +#include + +#include "thermal_core.h" +#include "thermal_thresholds.h" + +int thermal_thresholds_init(struct thermal_zone_device *tz) +{ + INIT_LIST_HEAD(&tz->user_thresholds); + + return 0; +} + +static void __thermal_thresholds_flush(struct thermal_zone_device *tz) +{ + struct list_head *thresholds = &tz->user_thresholds; + struct user_threshold *entry, *tmp; + + list_for_each_entry_safe(entry, tmp, thresholds, list_node) { + list_del(&entry->list_node); + kfree(entry); + } +} + +void thermal_thresholds_flush(struct thermal_zone_device *tz) +{ + lockdep_assert_held(&tz->lock); + + __thermal_thresholds_flush(tz); + + thermal_notify_threshold_flush(tz); + + __thermal_zone_device_update(tz, THERMAL_TZ_FLUSH_THRESHOLDS); +} + +void thermal_thresholds_exit(struct thermal_zone_device *tz) +{ + __thermal_thresholds_flush(tz); +} + +static int __thermal_thresholds_cmp(void *data, + const struct list_head *l1, + const struct list_head *l2) +{ + struct user_threshold *t1 = container_of(l1, struct user_threshold, list_node); + struct user_threshold *t2 = container_of(l2, struct user_threshold, list_node); + + return t1->temperature - t2->temperature; +} + +static struct user_threshold *__thermal_thresholds_find(const struct list_head *thresholds, + int temperature) +{ + struct user_threshold *t; + + list_for_each_entry(t, thresholds, list_node) + if (t->temperature == temperature) + return t; + + return NULL; +} + +static bool thermal_thresholds_handle_raising(struct list_head *thresholds, int temperature, + int last_temperature) +{ + struct user_threshold *t; + + list_for_each_entry(t, thresholds, list_node) { + + if (!(t->direction & THERMAL_THRESHOLD_WAY_UP)) + continue; + + if (temperature >= t->temperature && + last_temperature < t->temperature) + return true; + } + + return false; +} + +static bool thermal_thresholds_handle_dropping(struct list_head *thresholds, int temperature, + int last_temperature) +{ + struct user_threshold *t; + + list_for_each_entry_reverse(t, thresholds, list_node) { + + if (!(t->direction & THERMAL_THRESHOLD_WAY_DOWN)) + continue; + + if (temperature <= t->temperature && + last_temperature > t->temperature) + return true; + } + + return false; +} + +static void thermal_threshold_find_boundaries(struct list_head *thresholds, int temperature, + int *low, int *high) +{ + struct user_threshold *t; + + list_for_each_entry(t, thresholds, list_node) { + if (temperature < t->temperature && + (t->direction & THERMAL_THRESHOLD_WAY_UP) && + *high > t->temperature) + *high = t->temperature; + } + + list_for_each_entry_reverse(t, thresholds, list_node) { + if (temperature > t->temperature && + (t->direction & THERMAL_THRESHOLD_WAY_DOWN) && + *low < t->temperature) + *low = t->temperature; + } +} + +void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *high) +{ + struct list_head *thresholds = &tz->user_thresholds; + + int temperature = tz->temperature; + int last_temperature = tz->last_temperature; + + lockdep_assert_held(&tz->lock); + + thermal_threshold_find_boundaries(thresholds, temperature, low, high); + + /* + * We need a second update in order to detect a threshold being crossed + */ + if (last_temperature == THERMAL_TEMP_INVALID) + return; + + /* + * The temperature is stable, so obviously we can not have + * crossed a threshold. + */ + if (last_temperature == temperature) + return; + + /* + * Since last update the temperature: + * - increased : thresholds are crossed the way up + * - decreased : thresholds are crossed the way down + */ + if (temperature > last_temperature) { + if (thermal_thresholds_handle_raising(thresholds, + temperature, last_temperature)) + thermal_notify_threshold_up(tz); + } else { + if (thermal_thresholds_handle_dropping(thresholds, + temperature, last_temperature)) + thermal_notify_threshold_down(tz); + } +} + +int thermal_thresholds_add(struct thermal_zone_device *tz, + int temperature, int direction) +{ + struct list_head *thresholds = &tz->user_thresholds; + struct user_threshold *t; + + lockdep_assert_held(&tz->lock); + + t = __thermal_thresholds_find(thresholds, temperature); + if (t) { + if (t->direction == direction) + return -EEXIST; + + t->direction |= direction; + } else { + + t = kmalloc(sizeof(*t), GFP_KERNEL); + if (!t) + return -ENOMEM; + + INIT_LIST_HEAD(&t->list_node); + t->temperature = temperature; + t->direction = direction; + list_add(&t->list_node, thresholds); + list_sort(NULL, thresholds, __thermal_thresholds_cmp); + } + + thermal_notify_threshold_add(tz, temperature, direction); + + __thermal_zone_device_update(tz, THERMAL_TZ_ADD_THRESHOLD); + + return 0; +} + +int thermal_thresholds_delete(struct thermal_zone_device *tz, + int temperature, int direction) +{ + struct list_head *thresholds = &tz->user_thresholds; + struct user_threshold *t; + + lockdep_assert_held(&tz->lock); + + t = __thermal_thresholds_find(thresholds, temperature); + if (!t) + return -ENOENT; + + if (t->direction == direction) { + list_del(&t->list_node); + kfree(t); + } else { + t->direction &= ~direction; + } + + thermal_notify_threshold_delete(tz, temperature, direction); + + __thermal_zone_device_update(tz, THERMAL_TZ_DEL_THRESHOLD); + + return 0; +} + +int thermal_thresholds_for_each(struct thermal_zone_device *tz, + int (*cb)(struct user_threshold *, void *arg), void *arg) +{ + struct list_head *thresholds = &tz->user_thresholds; + struct user_threshold *entry; + int ret; + + guard(thermal_zone)(tz); + + list_for_each_entry(entry, thresholds, list_node) { + ret = cb(entry, arg); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/thermal/thermal_thresholds.h b/drivers/thermal/thermal_thresholds.h new file mode 100644 index 00000000000000..cb372659a20d64 --- /dev/null +++ b/drivers/thermal/thermal_thresholds.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __THERMAL_THRESHOLDS_H__ +#define __THERMAL_THRESHOLDS_H__ + +struct user_threshold { + struct list_head list_node; + int temperature; + int direction; +}; + +int thermal_thresholds_init(struct thermal_zone_device *tz); +void thermal_thresholds_exit(struct thermal_zone_device *tz); +void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *high); +void thermal_thresholds_flush(struct thermal_zone_device *tz); +int thermal_thresholds_add(struct thermal_zone_device *tz, int temperature, int direction); +int thermal_thresholds_delete(struct thermal_zone_device *tz, int temperature, int direction); +int thermal_thresholds_for_each(struct thermal_zone_device *tz, + int (*cb)(struct user_threshold *, void *arg), void *arg); +#endif diff --git a/drivers/thermal/thermal_trip.c b/drivers/thermal/thermal_trip.c index b53fac333ec5de..4b8238468b5343 100644 --- a/drivers/thermal/thermal_trip.c +++ b/drivers/thermal/thermal_trip.c @@ -45,13 +45,9 @@ int thermal_zone_for_each_trip(struct thermal_zone_device *tz, int (*cb)(struct thermal_trip *, void *), void *data) { - int ret; - - mutex_lock(&tz->lock); - ret = for_each_thermal_trip(tz, cb, data); - mutex_unlock(&tz->lock); + guard(thermal_zone)(tz); - return ret; + return for_each_thermal_trip(tz, cb, data); } EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip); @@ -92,43 +88,3 @@ int thermal_zone_trip_id(const struct thermal_zone_device *tz, */ return trip_to_trip_desc(trip) - tz->trips; } - -void thermal_zone_set_trip_hyst(struct thermal_zone_device *tz, - struct thermal_trip *trip, int hyst) -{ - WRITE_ONCE(trip->hysteresis, hyst); - thermal_notify_tz_trip_change(tz, trip); -} - -void thermal_zone_set_trip_temp(struct thermal_zone_device *tz, - struct thermal_trip *trip, int temp) -{ - if (trip->temperature == temp) - return; - - WRITE_ONCE(trip->temperature, temp); - thermal_notify_tz_trip_change(tz, trip); - - if (temp == THERMAL_TEMP_INVALID) { - struct thermal_trip_desc *td = trip_to_trip_desc(trip); - - if (tz->temperature >= td->threshold) { - /* - * The trip has been crossed on the way up, so some - * adjustments are needed to compensate for the lack - * of it going forward. - */ - if (trip->type == THERMAL_TRIP_PASSIVE) { - tz->passive--; - WARN_ON_ONCE(tz->passive < 0); - } - thermal_zone_trip_down(tz, trip); - } - /* - * Invalidate the threshold to avoid triggering a spurious - * trip crossing notification when the trip becomes valid. - */ - td->threshold = INT_MAX; - } -} -EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp); diff --git a/drivers/thermal/ti-soc-thermal/dra752-bandgap.h b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h index d1b5b699cf23c1..1402b8c44c6ba5 100644 --- a/drivers/thermal/ti-soc-thermal/dra752-bandgap.h +++ b/drivers/thermal/ti-soc-thermal/dra752-bandgap.h @@ -74,7 +74,7 @@ /** * Register bitfields for DRA752 * - * All the macros bellow define the required bits for + * All the macros below define the required bits for * controlling temperature on DRA752. Bit defines are * grouped by register. */ @@ -125,7 +125,7 @@ /** * Temperature limits and thresholds for DRA752 * - * All the macros bellow are definitions for handling the + * All the macros below are definitions for handling the * ADC conversions and representation of temperature limits * and thresholds for DRA752. Definitions are grouped * by temperature domain. diff --git a/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h index c63f439e01d6ce..3963f1badfc99e 100644 --- a/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h +++ b/drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h @@ -32,7 +32,7 @@ /** * Register and bit definitions for OMAP4430 * - * All the macros bellow define the required bits for + * All the macros below define the required bits for * controlling temperature on OMAP4430. Bit defines are * grouped by register. */ @@ -48,7 +48,7 @@ /** * Temperature limits and thresholds for OMAP4430 * - * All the macros bellow are definitions for handling the + * All the macros below are definitions for handling the * ADC conversions and representation of temperature limits * and thresholds for OMAP4430. */ @@ -102,7 +102,7 @@ /** * Register bitfields for OMAP4460 * - * All the macros bellow define the required bits for + * All the macros below define the required bits for * controlling temperature on OMAP4460. Bit defines are * grouped by register. */ @@ -135,7 +135,7 @@ /** * Temperature limits and thresholds for OMAP4460 * - * All the macros bellow are definitions for handling the + * All the macros below are definitions for handling the * ADC conversions and representation of temperature limits * and thresholds for OMAP4460. */ diff --git a/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h index 3880e667ea9641..b70084b8013a54 100644 --- a/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h +++ b/drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h @@ -56,7 +56,7 @@ /** * Register bitfields for OMAP5430 * - * All the macros bellow define the required bits for + * All the macros below define the required bits for * controlling temperature on OMAP5430. Bit defines are * grouped by register. */ @@ -101,7 +101,7 @@ /** * Temperature limits and thresholds for OMAP5430 * - * All the macros bellow are definitions for handling the + * All the macros below are definitions for handling the * ADC conversions and representation of temperature limits * and thresholds for OMAP5430. Definitions are grouped * by temperature domain. diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c index caadfc61be93ab..ba43399d0b384c 100644 --- a/drivers/thermal/ti-soc-thermal/ti-bandgap.c +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c @@ -1281,7 +1281,7 @@ MODULE_DEVICE_TABLE(of, of_ti_bandgap_match); static struct platform_driver ti_bandgap_sensor_driver = { .probe = ti_bandgap_probe, - .remove_new = ti_bandgap_remove, + .remove = ti_bandgap_remove, .driver = { .name = "ti-soc-thermal", .pm = DEV_PM_OPS, diff --git a/drivers/thermal/uniphier_thermal.c b/drivers/thermal/uniphier_thermal.c index 0325b719513633..1a04294effea29 100644 --- a/drivers/thermal/uniphier_thermal.c +++ b/drivers/thermal/uniphier_thermal.c @@ -371,7 +371,7 @@ MODULE_DEVICE_TABLE(of, uniphier_tm_dt_ids); static struct platform_driver uniphier_tm_driver = { .probe = uniphier_tm_probe, - .remove_new = uniphier_tm_remove, + .remove = uniphier_tm_remove, .driver = { .name = "uniphier-thermal", .of_match_table = uniphier_tm_dt_ids, diff --git a/drivers/thunderbolt/debugfs.c b/drivers/thunderbolt/debugfs.c index 350310bd0feea7..a1d0d8a33f208a 100644 --- a/drivers/thunderbolt/debugfs.c +++ b/drivers/thunderbolt/debugfs.c @@ -7,6 +7,7 @@ * Mika Westerberg */ +#include #include #include #include @@ -43,6 +44,24 @@ #define MAX_DWELL_TIME 500 /* ms */ #define DWELL_SAMPLE_INTERVAL 10 +enum usb4_margin_cap_voltage_indp { + USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_MIN, + USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_HL, + USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_BOTH, + USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_MIN, + USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_BOTH, + USB4_MARGIN_CAP_VOLTAGE_INDP_UNKNOWN, +}; + +enum usb4_margin_cap_time_indp { + USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_MIN, + USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_LR, + USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_BOTH, + USB4_MARGIN_CAP_TIME_INDP_GEN_4_MIN, + USB4_MARGIN_CAP_TIME_INDP_GEN_4_BOTH, + USB4_MARGIN_CAP_TIME_INDP_UNKNOWN, +}; + /* Sideband registers and their sizes as defined in the USB4 spec */ struct sb_reg { unsigned int reg; @@ -395,6 +414,8 @@ static ssize_t retimer_sb_regs_write(struct file *file, * @target: Sideband target * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER * @dev: Pointer to the device that is the target (USB4 port or retimer) + * @gen: Link generation + * @asym_rx: %true% if @port supports asymmetric link with 3 Rx * @caps: Port lane margining capabilities * @results: Last lane margining results * @lanes: %0, %1 or %7 (all) @@ -416,15 +437,19 @@ static ssize_t retimer_sb_regs_write(struct file *file, * @time: %true if time margining is used instead of voltage * @right_high: %false if left/low margin test is performed, %true if * right/high + * @upper_eye: %false if the lower PAM3 eye is used, %true if the upper + * eye is used */ struct tb_margining { struct tb_port *port; enum usb4_sb_target target; u8 index; struct device *dev; - u32 caps[2]; - u32 results[2]; - unsigned int lanes; + unsigned int gen; + bool asym_rx; + u32 caps[3]; + u32 results[3]; + enum usb4_margining_lane lanes; unsigned int min_ber_level; unsigned int max_ber_level; unsigned int ber_level; @@ -441,6 +466,7 @@ struct tb_margining { bool software; bool time; bool right_high; + bool upper_eye; }; static int margining_modify_error_counter(struct tb_margining *margining, @@ -463,35 +489,75 @@ static int margining_modify_error_counter(struct tb_margining *margining, static bool supports_software(const struct tb_margining *margining) { - return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW; + if (margining->gen < 4) + return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW; + return margining->caps[2] & USB4_MARGIN_CAP_2_MODES_SW; } static bool supports_hardware(const struct tb_margining *margining) { - return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW; + if (margining->gen < 4) + return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW; + return margining->caps[2] & USB4_MARGIN_CAP_2_MODES_HW; } -static bool both_lanes(const struct tb_margining *margining) +static bool all_lanes(const struct tb_margining *margining) { - return margining->caps[0] & USB4_MARGIN_CAP_0_2_LANES; + return margining->caps[0] & USB4_MARGIN_CAP_0_ALL_LANES; } -static unsigned int +static enum usb4_margin_cap_voltage_indp independent_voltage_margins(const struct tb_margining *margining) { - return FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK, margining->caps[0]); + if (margining->gen < 4) { + switch (FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK, margining->caps[0])) { + case USB4_MARGIN_CAP_0_VOLTAGE_MIN: + return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_MIN; + case USB4_MARGIN_CAP_0_VOLTAGE_HL: + return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_HL; + case USB4_MARGIN_CAP_1_TIME_BOTH: + return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_BOTH; + } + } else { + switch (FIELD_GET(USB4_MARGIN_CAP_2_VOLTAGE_INDP_MASK, margining->caps[2])) { + case USB4_MARGIN_CAP_2_VOLTAGE_MIN: + return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_MIN; + case USB4_MARGIN_CAP_2_VOLTAGE_BOTH: + return USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_BOTH; + } + } + return USB4_MARGIN_CAP_VOLTAGE_INDP_UNKNOWN; } static bool supports_time(const struct tb_margining *margining) { - return margining->caps[0] & USB4_MARGIN_CAP_0_TIME; + if (margining->gen < 4) + return margining->caps[0] & USB4_MARGIN_CAP_0_TIME; + return margining->caps[2] & USB4_MARGIN_CAP_2_TIME; } /* Only applicable if supports_time() returns true */ -static unsigned int +static enum usb4_margin_cap_time_indp independent_time_margins(const struct tb_margining *margining) { - return FIELD_GET(USB4_MARGIN_CAP_1_TIME_INDP_MASK, margining->caps[1]); + if (margining->gen < 4) { + switch (FIELD_GET(USB4_MARGIN_CAP_1_TIME_INDP_MASK, margining->caps[1])) { + case USB4_MARGIN_CAP_1_TIME_MIN: + return USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_MIN; + case USB4_MARGIN_CAP_1_TIME_LR: + return USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_LR; + case USB4_MARGIN_CAP_1_TIME_BOTH: + return USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_BOTH; + } + } else { + switch (FIELD_GET(USB4_MARGIN_CAP_2_TIME_INDP_MASK, margining->caps[2])) { + case USB4_MARGIN_CAP_2_TIME_MIN: + return USB4_MARGIN_CAP_TIME_INDP_GEN_4_MIN; + case USB4_MARGIN_CAP_2_TIME_BOTH: + return USB4_MARGIN_CAP_TIME_INDP_GEN_4_BOTH; + } + } + return USB4_MARGIN_CAP_TIME_INDP_UNKNOWN; } static bool @@ -570,16 +636,14 @@ static int margining_caps_show(struct seq_file *s, void *not_used) { struct tb_margining *margining = s->private; struct tb *tb = margining->port->sw->tb; - u32 cap0, cap1; + int ret = 0; if (mutex_lock_interruptible(&tb->lock)) return -ERESTARTSYS; /* Dump the raw caps first */ - cap0 = margining->caps[0]; - seq_printf(s, "0x%08x\n", cap0); - cap1 = margining->caps[1]; - seq_printf(s, "0x%08x\n", cap1); + for (int i = 0; i < ARRAY_SIZE(margining->caps); i++) + seq_printf(s, "0x%08x\n", margining->caps[i]); seq_printf(s, "# software margining: %s\n", supports_software(margining) ? "yes" : "no"); @@ -593,8 +657,8 @@ static int margining_caps_show(struct seq_file *s, void *not_used) seq_puts(s, "# hardware margining: no\n"); } - seq_printf(s, "# both lanes simultaneously: %s\n", - both_lanes(margining) ? "yes" : "no"); + seq_printf(s, "# all lanes simultaneously: %s\n", + str_yes_no(all_lanes(margining))); seq_printf(s, "# voltage margin steps: %u\n", margining->voltage_steps); seq_printf(s, "# maximum voltage offset: %u mV\n", @@ -609,32 +673,54 @@ static int margining_caps_show(struct seq_file *s, void *not_used) } switch (independent_voltage_margins(margining)) { - case USB4_MARGIN_CAP_0_VOLTAGE_MIN: + case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_MIN: seq_puts(s, "# returns minimum between high and low voltage margins\n"); break; - case USB4_MARGIN_CAP_0_VOLTAGE_HL: + case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_HL: seq_puts(s, "# returns high or low voltage margin\n"); break; - case USB4_MARGIN_CAP_0_VOLTAGE_BOTH: + case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_BOTH: seq_puts(s, "# returns both high and low margins\n"); break; + case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_MIN: + seq_puts(s, "# returns minimum between high and low voltage margins in both lower and upper eye\n"); + break; + case USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_4_BOTH: + seq_puts(s, "# returns both high and low margins of both upper and lower eye\n"); + break; + case USB4_MARGIN_CAP_VOLTAGE_INDP_UNKNOWN: + tb_port_warn(margining->port, + "failed to parse independent voltage margining capabilities\n"); + ret = -EIO; + goto out; } if (supports_time(margining)) { seq_puts(s, "# time margining: yes\n"); seq_printf(s, "# time margining is destructive: %s\n", - cap1 & USB4_MARGIN_CAP_1_TIME_DESTR ? "yes" : "no"); + str_yes_no(margining->caps[1] & USB4_MARGIN_CAP_1_TIME_DESTR)); switch (independent_time_margins(margining)) { - case USB4_MARGIN_CAP_1_TIME_MIN: + case USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_MIN: seq_puts(s, "# returns minimum between left and right time margins\n"); break; - case USB4_MARGIN_CAP_1_TIME_LR: + case USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_LR: seq_puts(s, "# returns left or right margin\n"); break; - case USB4_MARGIN_CAP_1_TIME_BOTH: + case USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_BOTH: seq_puts(s, "# returns both left and right margins\n"); break; + case USB4_MARGIN_CAP_TIME_INDP_GEN_4_MIN: + seq_puts(s, "# returns minimum between left and right time margins in both lower and upper eye\n"); + break; + case USB4_MARGIN_CAP_TIME_INDP_GEN_4_BOTH: + seq_puts(s, "# returns both left and right margins of both upper and lower eye\n"); + break; + case USB4_MARGIN_CAP_TIME_INDP_UNKNOWN: + tb_port_warn(margining->port, + "failed to parse independent time margining capabilities\n"); + ret = -EIO; + goto out; } seq_printf(s, "# time margin steps: %u\n", @@ -645,19 +731,43 @@ static int margining_caps_show(struct seq_file *s, void *not_used) seq_puts(s, "# time margining: no\n"); } +out: mutex_unlock(&tb->lock); - return 0; + return ret; } DEBUGFS_ATTR_RO(margining_caps); +static const struct { + enum usb4_margining_lane lane; + const char *name; +} lane_names[] = { + { + .lane = USB4_MARGINING_LANE_RX0, + .name = "0", + }, + { + .lane = USB4_MARGINING_LANE_RX1, + .name = "1", + }, + { + .lane = USB4_MARGINING_LANE_RX2, + .name = "2", + }, + { + .lane = USB4_MARGINING_LANE_ALL, + .name = "all", + }, +}; + static ssize_t margining_lanes_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct seq_file *s = file->private_data; struct tb_margining *margining = s->private; - struct tb *tb = margining->port->sw->tb; - int ret = 0; + struct tb_port *port = margining->port; + struct tb *tb = port->sw->tb; + int lane = -1; char *buf; buf = validate_and_copy_from_user(user_buf, &count); @@ -666,57 +776,60 @@ margining_lanes_write(struct file *file, const char __user *user_buf, buf[count - 1] = '\0'; - if (mutex_lock_interruptible(&tb->lock)) { - ret = -ERESTARTSYS; - goto out_free; + for (int i = 0; i < ARRAY_SIZE(lane_names); i++) { + if (!strcmp(buf, lane_names[i].name)) { + lane = lane_names[i].lane; + break; + } } - if (!strcmp(buf, "0")) { - margining->lanes = 0; - } else if (!strcmp(buf, "1")) { - margining->lanes = 1; - } else if (!strcmp(buf, "all")) { - /* Needs to be supported */ - if (both_lanes(margining)) - margining->lanes = 7; - else - ret = -EINVAL; - } else { - ret = -EINVAL; - } + free_page((unsigned long)buf); - mutex_unlock(&tb->lock); + if (lane == -1) + return -EINVAL; -out_free: - free_page((unsigned long)buf); - return ret < 0 ? ret : count; + scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) { + if (lane == USB4_MARGINING_LANE_ALL && !all_lanes(margining)) + return -EINVAL; + /* + * Enabling on RX2 requires that it is supported by the + * USB4 port. + */ + if (lane == USB4_MARGINING_LANE_RX2 && !margining->asym_rx) + return -EINVAL; + + margining->lanes = lane; + } + + return count; } static int margining_lanes_show(struct seq_file *s, void *not_used) { struct tb_margining *margining = s->private; - struct tb *tb = margining->port->sw->tb; - unsigned int lanes; - - if (mutex_lock_interruptible(&tb->lock)) - return -ERESTARTSYS; + struct tb_port *port = margining->port; + struct tb *tb = port->sw->tb; - lanes = margining->lanes; - if (both_lanes(margining)) { - if (!lanes) - seq_puts(s, "[0] 1 all\n"); - else if (lanes == 1) - seq_puts(s, "0 [1] all\n"); - else - seq_puts(s, "0 1 [all]\n"); - } else { - if (!lanes) - seq_puts(s, "[0] 1\n"); - else - seq_puts(s, "0 [1]\n"); + scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) { + for (int i = 0; i < ARRAY_SIZE(lane_names); i++) { + if (lane_names[i].lane == USB4_MARGINING_LANE_ALL && + !all_lanes(margining)) + continue; + if (lane_names[i].lane == USB4_MARGINING_LANE_RX2 && + !margining->asym_rx) + continue; + + if (i != 0) + seq_putc(s, ' '); + + if (lane_names[i].lane == margining->lanes) + seq_printf(s, "[%s]", lane_names[i].name); + else + seq_printf(s, "%s", lane_names[i].name); + } + seq_puts(s, "\n"); } - mutex_unlock(&tb->lock); return 0; } DEBUGFS_ATTR_RW(margining_lanes); @@ -1004,13 +1117,16 @@ static int margining_run_sw(struct tb_margining *margining, if (ret) break; - if (margining->lanes == USB4_MARGIN_SW_LANE_0) + if (margining->lanes == USB4_MARGINING_LANE_RX0) errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK, margining->results[1]); - else if (margining->lanes == USB4_MARGIN_SW_LANE_1) + else if (margining->lanes == USB4_MARGINING_LANE_RX1) errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK, margining->results[1]); - else if (margining->lanes == USB4_MARGIN_SW_ALL_LANES) + else if (margining->lanes == USB4_MARGINING_LANE_RX2) + errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK, + margining->results[1]); + else if (margining->lanes == USB4_MARGINING_LANE_ALL) errors = margining->results[1]; /* Any errors stop the test */ @@ -1030,6 +1146,31 @@ static int margining_run_sw(struct tb_margining *margining, return ret; } +static int validate_margining(struct tb_margining *margining) +{ + /* + * For running on RX2 the link must be asymmetric with 3 + * receivers. Because this is can change dynamically, check it + * here before we start the margining and report back error if + * expectations are not met. + */ + if (margining->lanes == USB4_MARGINING_LANE_RX2) { + int ret; + + ret = tb_port_get_link_width(margining->port); + if (ret < 0) + return ret; + if (ret != TB_LINK_WIDTH_ASYM_RX) { + tb_port_warn(margining->port, "link is %s expected %s", + tb_width_name(ret), + tb_width_name(TB_LINK_WIDTH_ASYM_RX)); + return -EINVAL; + } + } + + return 0; +} + static int margining_run_write(void *data, u64 val) { struct tb_margining *margining = data; @@ -1050,6 +1191,10 @@ static int margining_run_write(void *data, u64 val) goto out_rpm_put; } + ret = validate_margining(margining); + if (ret) + goto out_unlock; + if (tb_is_upstream_port(port)) down_sw = sw; else if (port->remote) @@ -1080,6 +1225,7 @@ static int margining_run_write(void *data, u64 val) .time = margining->time, .voltage_time_offset = margining->voltage_time_offset, .right_high = margining->right_high, + .upper_eye = margining->upper_eye, .optional_voltage_offset_range = margining->optional_voltage_offset_range, }; @@ -1095,6 +1241,7 @@ static int margining_run_write(void *data, u64 val) .lanes = margining->lanes, .time = margining->time, .right_high = margining->right_high, + .upper_eye = margining->upper_eye, .optional_voltage_offset_range = margining->optional_voltage_offset_range, }; @@ -1104,7 +1251,7 @@ static int margining_run_write(void *data, u64 val) margining->lanes); ret = usb4_port_hw_margin(port, margining->target, margining->index, ¶ms, - margining->results); + margining->results, ARRAY_SIZE(margining->results)); } if (down_sw) @@ -1132,13 +1279,12 @@ static ssize_t margining_results_write(struct file *file, return -ERESTARTSYS; /* Just clear the results */ - margining->results[0] = 0; - margining->results[1] = 0; + memset(margining->results, 0, sizeof(margining->results)); if (margining->software) { /* Clear the error counters */ margining_modify_error_counter(margining, - USB4_MARGIN_SW_ALL_LANES, + USB4_MARGINING_LANE_ALL, USB4_MARGIN_SW_ERROR_COUNTER_CLEAR); } @@ -1151,10 +1297,10 @@ static void voltage_margin_show(struct seq_file *s, { unsigned int tmp, voltage; - tmp = FIELD_GET(USB4_MARGIN_HW_RES_1_MARGIN_MASK, val); + tmp = FIELD_GET(USB4_MARGIN_HW_RES_MARGIN_MASK, val); voltage = tmp * margining->max_voltage_offset / margining->voltage_steps; seq_printf(s, "%u mV (%u)", voltage, tmp); - if (val & USB4_MARGIN_HW_RES_1_EXCEEDS) + if (val & USB4_MARGIN_HW_RES_EXCEEDS) seq_puts(s, " exceeds maximum"); seq_puts(s, "\n"); if (margining->optional_voltage_offset_range) @@ -1166,14 +1312,55 @@ static void time_margin_show(struct seq_file *s, { unsigned int tmp, interval; - tmp = FIELD_GET(USB4_MARGIN_HW_RES_1_MARGIN_MASK, val); + tmp = FIELD_GET(USB4_MARGIN_HW_RES_MARGIN_MASK, val); interval = tmp * margining->max_time_offset / margining->time_steps; seq_printf(s, "%u mUI (%u)", interval, tmp); - if (val & USB4_MARGIN_HW_RES_1_EXCEEDS) + if (val & USB4_MARGIN_HW_RES_EXCEEDS) seq_puts(s, " exceeds maximum"); seq_puts(s, "\n"); } +static u8 margining_hw_result_val(const u32 *results, + enum usb4_margining_lane lane, + bool right_high) +{ + u32 val; + + if (lane == USB4_MARGINING_LANE_RX0) + val = results[1]; + else if (lane == USB4_MARGINING_LANE_RX1) + val = results[1] >> USB4_MARGIN_HW_RES_LANE_SHIFT; + else if (lane == USB4_MARGINING_LANE_RX2) + val = results[2]; + else + val = 0; + + return right_high ? val : val >> USB4_MARGIN_HW_RES_LL_SHIFT; +} + +static void margining_hw_result_format(struct seq_file *s, + const struct tb_margining *margining, + enum usb4_margining_lane lane) +{ + u8 val; + + if (margining->time) { + val = margining_hw_result_val(margining->results, lane, true); + seq_printf(s, "# lane %u right time margin: ", lane); + time_margin_show(s, margining, val); + val = margining_hw_result_val(margining->results, lane, false); + seq_printf(s, "# lane %u left time margin: ", lane); + time_margin_show(s, margining, val); + } else { + val = margining_hw_result_val(margining->results, lane, true); + seq_printf(s, "# lane %u high voltage margin: ", lane); + voltage_margin_show(s, margining, val); + val = margining_hw_result_val(margining->results, lane, false); + seq_printf(s, "# lane %u low voltage margin: ", lane); + voltage_margin_show(s, margining, val); + } +} + static int margining_results_show(struct seq_file *s, void *not_used) { struct tb_margining *margining = s->private; @@ -1186,69 +1373,46 @@ static int margining_results_show(struct seq_file *s, void *not_used) seq_printf(s, "0x%08x\n", margining->results[0]); /* Only the hardware margining has two result dwords */ if (!margining->software) { - unsigned int val; - - seq_printf(s, "0x%08x\n", margining->results[1]); - - if (margining->time) { - if (!margining->lanes || margining->lanes == 7) { - val = margining->results[1]; - seq_puts(s, "# lane 0 right time margin: "); - time_margin_show(s, margining, val); - val = margining->results[1] >> - USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT; - seq_puts(s, "# lane 0 left time margin: "); - time_margin_show(s, margining, val); - } - if (margining->lanes == 1 || margining->lanes == 7) { - val = margining->results[1] >> - USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT; - seq_puts(s, "# lane 1 right time margin: "); - time_margin_show(s, margining, val); - val = margining->results[1] >> - USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT; - seq_puts(s, "# lane 1 left time margin: "); - time_margin_show(s, margining, val); - } + for (int i = 1; i < ARRAY_SIZE(margining->results); i++) + seq_printf(s, "0x%08x\n", margining->results[i]); + + if (margining->lanes == USB4_MARGINING_LANE_ALL) { + margining_hw_result_format(s, margining, + USB4_MARGINING_LANE_RX0); + margining_hw_result_format(s, margining, + USB4_MARGINING_LANE_RX1); + if (margining->asym_rx) + margining_hw_result_format(s, margining, + USB4_MARGINING_LANE_RX2); } else { - if (!margining->lanes || margining->lanes == 7) { - val = margining->results[1]; - seq_puts(s, "# lane 0 high voltage margin: "); - voltage_margin_show(s, margining, val); - val = margining->results[1] >> - USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT; - seq_puts(s, "# lane 0 low voltage margin: "); - voltage_margin_show(s, margining, val); - } - if (margining->lanes == 1 || margining->lanes == 7) { - val = margining->results[1] >> - USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT; - seq_puts(s, "# lane 1 high voltage margin: "); - voltage_margin_show(s, margining, val); - val = margining->results[1] >> - USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT; - seq_puts(s, "# lane 1 low voltage margin: "); - voltage_margin_show(s, margining, val); - } + margining_hw_result_format(s, margining, + margining->lanes); } } else { u32 lane_errors, result; seq_printf(s, "0x%08x\n", margining->results[1]); - result = FIELD_GET(USB4_MARGIN_SW_LANES_MASK, margining->results[0]); - if (result == USB4_MARGIN_SW_LANE_0 || - result == USB4_MARGIN_SW_ALL_LANES) { + result = FIELD_GET(USB4_MARGIN_SW_LANES_MASK, margining->results[0]); + if (result == USB4_MARGINING_LANE_RX0 || + result == USB4_MARGINING_LANE_ALL) { lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK, margining->results[1]); seq_printf(s, "# lane 0 errors: %u\n", lane_errors); } - if (result == USB4_MARGIN_SW_LANE_1 || - result == USB4_MARGIN_SW_ALL_LANES) { + if (result == USB4_MARGINING_LANE_RX1 || + result == USB4_MARGINING_LANE_ALL) { lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK, margining->results[1]); seq_printf(s, "# lane 1 errors: %u\n", lane_errors); } + if (margining->asym_rx && + (result == USB4_MARGINING_LANE_RX2 || + result == USB4_MARGINING_LANE_ALL)) { + lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK, + margining->results[1]); + seq_printf(s, "# lane 2 errors: %u\n", lane_errors); + } } mutex_unlock(&tb->lock); @@ -1382,6 +1546,55 @@ static int margining_margin_show(struct seq_file *s, void *not_used) } DEBUGFS_ATTR_RW(margining_margin); +static ssize_t margining_eye_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = file->private_data; + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + int ret = 0; + char *buf; + + buf = validate_and_copy_from_user(user_buf, &count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + buf[count - 1] = '\0'; + + scoped_cond_guard(mutex_intr, ret = -ERESTARTSYS, &tb->lock) { + if (!strcmp(buf, "lower")) + usb4->margining->upper_eye = false; + else if (!strcmp(buf, "upper")) + usb4->margining->upper_eye = true; + else + ret = -EINVAL; + } + + free_page((unsigned long)buf); + return ret ? ret : count; +} + +static int margining_eye_show(struct seq_file *s, void *not_used) +{ + struct tb_port *port = s->private; + struct usb4_port *usb4 = port->usb4; + struct tb *tb = port->sw->tb; + + scoped_guard(mutex_intr, &tb->lock) { + if (usb4->margining->upper_eye) + seq_puts(s, "lower [upper]\n"); + else + seq_puts(s, "[lower] upper\n"); + + return 0; + } + + return -ERESTARTSYS; +} +DEBUGFS_ATTR_RW(margining_eye); + static struct tb_margining *margining_alloc(struct tb_port *port, struct device *dev, enum usb4_sb_target target, @@ -1392,6 +1605,12 @@ static struct tb_margining *margining_alloc(struct tb_port *port, unsigned int val; int ret; + ret = tb_port_get_link_generation(port); + if (ret < 0) { + tb_port_warn(port, "failed to read link generation\n"); + return NULL; + } + margining = kzalloc(sizeof(*margining), GFP_KERNEL); if (!margining) return NULL; @@ -1400,8 +1619,11 @@ static struct tb_margining *margining_alloc(struct tb_port *port, margining->target = target; margining->index = index; margining->dev = dev; + margining->gen = ret; + margining->asym_rx = tb_port_width_supported(port, TB_LINK_WIDTH_ASYM_RX); - ret = usb4_port_margining_caps(port, target, index, margining->caps); + ret = usb4_port_margining_caps(port, target, index, margining->caps, + ARRAY_SIZE(margining->caps)); if (ret) { kfree(margining); return NULL; @@ -1411,10 +1633,17 @@ static struct tb_margining *margining_alloc(struct tb_port *port, if (supports_software(margining)) margining->software = true; - val = FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK, margining->caps[0]); - margining->voltage_steps = val; - val = FIELD_GET(USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK, margining->caps[0]); - margining->max_voltage_offset = 74 + val * 2; + if (margining->gen < 4) { + val = FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK, margining->caps[0]); + margining->voltage_steps = val; + val = FIELD_GET(USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK, margining->caps[0]); + margining->max_voltage_offset = 74 + val * 2; + } else { + val = FIELD_GET(USB4_MARGIN_CAP_2_VOLTAGE_STEPS_MASK, margining->caps[2]); + margining->voltage_steps = val; + val = FIELD_GET(USB4_MARGIN_CAP_2_MAX_VOLTAGE_OFFSET_MASK, margining->caps[2]); + margining->max_voltage_offset = 74 + val * 2; + } if (supports_optional_voltage_offset_range(margining)) { val = FIELD_GET(USB4_MARGIN_CAP_0_VOLT_STEPS_OPT_MASK, @@ -1456,11 +1685,10 @@ static struct tb_margining *margining_alloc(struct tb_port *port, debugfs_create_file("results", 0600, dir, margining, &margining_results_fops); debugfs_create_file("test", 0600, dir, margining, &margining_test_fops); - if (independent_voltage_margins(margining) == USB4_MARGIN_CAP_0_VOLTAGE_HL || + if (independent_voltage_margins(margining) == USB4_MARGIN_CAP_VOLTAGE_INDP_GEN_2_3_HL || (supports_time(margining) && - independent_time_margins(margining) == USB4_MARGIN_CAP_1_TIME_LR)) - debugfs_create_file("margin", 0600, dir, margining, - &margining_margin_fops); + independent_time_margins(margining) == USB4_MARGIN_CAP_TIME_INDP_GEN_2_3_LR)) + debugfs_create_file("margin", 0600, dir, margining, &margining_margin_fops); margining->error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR; margining->dwell_time = MIN_DWELL_TIME; @@ -1477,6 +1705,10 @@ static struct tb_margining *margining_alloc(struct tb_port *port, debugfs_create_file("dwell_time", DEBUGFS_MODE, dir, margining, &margining_dwell_time_fops); } + + if (margining->gen >= 4) + debugfs_create_file("eye", 0600, dir, port, &margining_eye_fops); + return margining; } diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 7af2642b97cb81..f3a2264e012bcd 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -1340,18 +1340,18 @@ static int nhi_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (res) return dev_err_probe(dev, res, "cannot enable PCI device, aborting\n"); - res = pcim_iomap_regions(pdev, 1 << 0, "thunderbolt"); - if (res) - return dev_err_probe(dev, res, "cannot obtain PCI resources, aborting\n"); - nhi = devm_kzalloc(&pdev->dev, sizeof(*nhi), GFP_KERNEL); if (!nhi) return -ENOMEM; nhi->pdev = pdev; nhi->ops = (const struct tb_nhi_ops *)id->driver_data; - /* cannot fail - table is allocated in pcim_iomap_regions */ - nhi->iobase = pcim_iomap_table(pdev)[0]; + + nhi->iobase = pcim_iomap_region(pdev, 0, "thunderbolt"); + res = PTR_ERR_OR_ZERO(nhi->iobase); + if (res) + return dev_err_probe(dev, res, "cannot obtain PCI resources, aborting\n"); + nhi->hop_count = ioread32(nhi->iobase + REG_CAPS) & 0x3ff; dev_dbg(dev, "total paths: %d\n", nhi->hop_count); @@ -1520,6 +1520,14 @@ static struct pci_device_id nhi_ids[] = { .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_LNL_NHI1), .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_PTL_M_NHI0), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_PTL_M_NHI1), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_PTL_P_NHI0), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_PTL_P_NHI1), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_80G_NHI) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_40G_NHI) }, diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h index 7a07c7c1a9c2c6..16744f25a9a069 100644 --- a/drivers/thunderbolt/nhi.h +++ b/drivers/thunderbolt/nhi.h @@ -92,6 +92,10 @@ extern const struct tb_nhi_ops icl_nhi_ops; #define PCI_DEVICE_ID_INTEL_RPL_NHI1 0xa76d #define PCI_DEVICE_ID_INTEL_LNL_NHI0 0xa833 #define PCI_DEVICE_ID_INTEL_LNL_NHI1 0xa834 +#define PCI_DEVICE_ID_INTEL_PTL_M_NHI0 0xe333 +#define PCI_DEVICE_ID_INTEL_PTL_M_NHI1 0xe334 +#define PCI_DEVICE_ID_INTEL_PTL_P_NHI0 0xe433 +#define PCI_DEVICE_ID_INTEL_PTL_P_NHI1 0xe434 #define PCI_CLASS_SERIAL_USB_USB4 0x0c0340 diff --git a/drivers/thunderbolt/retimer.c b/drivers/thunderbolt/retimer.c index 89d2919d0193e8..eeb64433ebbca0 100644 --- a/drivers/thunderbolt/retimer.c +++ b/drivers/thunderbolt/retimer.c @@ -103,6 +103,7 @@ static int tb_retimer_nvm_add(struct tb_retimer *rt) err_nvm: dev_dbg(&rt->dev, "NVM upgrade disabled\n"); + rt->no_nvm_upgrade = true; if (!IS_ERR(nvm)) tb_nvm_free(nvm); @@ -182,8 +183,6 @@ static ssize_t nvm_authenticate_show(struct device *dev, if (!rt->nvm) ret = -EAGAIN; - else if (rt->no_nvm_upgrade) - ret = -EOPNOTSUPP; else ret = sysfs_emit(buf, "%#x\n", rt->auth_status); @@ -323,8 +322,6 @@ static ssize_t nvm_version_show(struct device *dev, if (!rt->nvm) ret = -EAGAIN; - else if (rt->no_nvm_upgrade) - ret = -EOPNOTSUPP; else ret = sysfs_emit(buf, "%x.%x\n", rt->nvm->major, rt->nvm->minor); @@ -342,6 +339,19 @@ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(vendor); +static umode_t retimer_is_visible(struct kobject *kobj, struct attribute *attr, + int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct tb_retimer *rt = tb_to_retimer(dev); + + if (attr == &dev_attr_nvm_authenticate.attr || + attr == &dev_attr_nvm_version.attr) + return rt->no_nvm_upgrade ? 0 : attr->mode; + + return attr->mode; +} + static struct attribute *retimer_attrs[] = { &dev_attr_device.attr, &dev_attr_nvm_authenticate.attr, @@ -351,6 +361,7 @@ static struct attribute *retimer_attrs[] = { }; static const struct attribute_group retimer_group = { + .is_visible = retimer_is_visible, .attrs = retimer_attrs, }; diff --git a/drivers/thunderbolt/sb_regs.h b/drivers/thunderbolt/sb_regs.h index dbcad25ead50f1..5391502a4b8736 100644 --- a/drivers/thunderbolt/sb_regs.h +++ b/drivers/thunderbolt/sb_regs.h @@ -49,7 +49,7 @@ enum usb4_sb_opcode { /* USB4_SB_OPCODE_READ_LANE_MARGINING_CAP */ #define USB4_MARGIN_CAP_0_MODES_HW BIT(0) #define USB4_MARGIN_CAP_0_MODES_SW BIT(1) -#define USB4_MARGIN_CAP_0_2_LANES BIT(2) +#define USB4_MARGIN_CAP_0_ALL_LANES BIT(2) #define USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK GENMASK(4, 3) #define USB4_MARGIN_CAP_0_VOLTAGE_MIN 0x0 #define USB4_MARGIN_CAP_0_VOLTAGE_HL 0x1 @@ -69,34 +69,44 @@ enum usb4_sb_opcode { #define USB4_MARGIN_CAP_1_TIME_OFFSET_MASK GENMASK(20, 16) #define USB4_MARGIN_CAP_1_MIN_BER_MASK GENMASK(25, 21) #define USB4_MARGIN_CAP_1_MAX_BER_MASK GENMASK(30, 26) +#define USB4_MARGIN_CAP_2_MODES_HW BIT(0) +#define USB4_MARGIN_CAP_2_MODES_SW BIT(1) +#define USB4_MARGIN_CAP_2_TIME BIT(2) +#define USB4_MARGIN_CAP_2_MAX_VOLTAGE_OFFSET_MASK GENMASK(8, 3) +#define USB4_MARGIN_CAP_2_VOLTAGE_STEPS_MASK GENMASK(15, 9) +#define USB4_MARGIN_CAP_2_VOLTAGE_INDP_MASK GENMASK(17, 16) +#define USB4_MARGIN_CAP_2_VOLTAGE_MIN 0x0 +#define USB4_MARGIN_CAP_2_VOLTAGE_BOTH 0x1 +#define USB4_MARGIN_CAP_2_TIME_INDP_MASK GENMASK(19, 18) +#define USB4_MARGIN_CAP_2_TIME_MIN 0x0 +#define USB4_MARGIN_CAP_2_TIME_BOTH 0x1 /* USB4_SB_OPCODE_RUN_HW_LANE_MARGINING */ #define USB4_MARGIN_HW_TIME BIT(3) -#define USB4_MARGIN_HW_RH BIT(4) +#define USB4_MARGIN_HW_RHU BIT(4) #define USB4_MARGIN_HW_BER_MASK GENMASK(9, 5) #define USB4_MARGIN_HW_BER_SHIFT 5 #define USB4_MARGIN_HW_OPT_VOLTAGE BIT(10) /* Applicable to all margin values */ -#define USB4_MARGIN_HW_RES_1_MARGIN_MASK GENMASK(6, 0) -#define USB4_MARGIN_HW_RES_1_EXCEEDS BIT(7) -/* Different lane margin shifts */ -#define USB4_MARGIN_HW_RES_1_L0_LL_MARGIN_SHIFT 8 -#define USB4_MARGIN_HW_RES_1_L1_RH_MARGIN_SHIFT 16 -#define USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT 24 +#define USB4_MARGIN_HW_RES_MARGIN_MASK GENMASK(6, 0) +#define USB4_MARGIN_HW_RES_EXCEEDS BIT(7) + +/* Shifts for parsing the lane results */ +#define USB4_MARGIN_HW_RES_LANE_SHIFT 16 +#define USB4_MARGIN_HW_RES_LL_SHIFT 8 /* USB4_SB_OPCODE_RUN_SW_LANE_MARGINING */ #define USB4_MARGIN_SW_LANES_MASK GENMASK(2, 0) -#define USB4_MARGIN_SW_LANE_0 0x0 -#define USB4_MARGIN_SW_LANE_1 0x1 -#define USB4_MARGIN_SW_ALL_LANES 0x7 #define USB4_MARGIN_SW_TIME BIT(3) #define USB4_MARGIN_SW_RH BIT(4) #define USB4_MARGIN_SW_OPT_VOLTAGE BIT(5) #define USB4_MARGIN_SW_VT_MASK GENMASK(12, 6) #define USB4_MARGIN_SW_COUNTER_MASK GENMASK(14, 13) +#define USB4_MARGIN_SW_UPPER_EYE BIT(15) #define USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK GENMASK(3, 0) #define USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK GENMASK(7, 4) +#define USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK GENMASK(11, 8) #endif diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 4f777788e9179c..a7c6919fbf9788 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -2059,6 +2059,37 @@ static void tb_exit_redrive(struct tb_port *port) } } +static void tb_switch_enter_redrive(struct tb_switch *sw) +{ + struct tb_port *port; + + tb_switch_for_each_port(sw, port) + tb_enter_redrive(port); +} + +/* + * Called during system and runtime suspend to forcefully exit redrive + * mode without querying whether the resource is available. + */ +static void tb_switch_exit_redrive(struct tb_switch *sw) +{ + struct tb_port *port; + + if (!(sw->quirks & QUIRK_KEEP_POWER_IN_DP_REDRIVE)) + return; + + tb_switch_for_each_port(sw, port) { + if (!tb_port_is_dpin(port)) + continue; + + if (port->redrive) { + port->redrive = false; + pm_runtime_put(&sw->dev); + tb_port_dbg(port, "exit redrive mode\n"); + } + } +} + static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port) { struct tb_port *in, *out; @@ -2909,6 +2940,7 @@ static int tb_start(struct tb *tb, bool reset) tb_create_usb3_tunnels(tb->root_switch); /* Add DP IN resources for the root switch */ tb_add_dp_resources(tb->root_switch); + tb_switch_enter_redrive(tb->root_switch); /* Make the discovered switches available to the userspace */ device_for_each_child(&tb->root_switch->dev, NULL, tb_scan_finalize_switch); @@ -2924,6 +2956,7 @@ static int tb_suspend_noirq(struct tb *tb) tb_dbg(tb, "suspending...\n"); tb_disconnect_and_release_dp(tb); + tb_switch_exit_redrive(tb->root_switch); tb_switch_suspend(tb->root_switch, false); tcm->hotplug_active = false; /* signal tb_handle_hotplug to quit */ tb_dbg(tb, "suspend finished\n"); @@ -3016,6 +3049,7 @@ static int tb_resume_noirq(struct tb *tb) tb_dbg(tb, "tunnels restarted, sleeping for 100ms\n"); msleep(100); } + tb_switch_enter_redrive(tb->root_switch); /* Allow tb_handle_hotplug to progress events */ tcm->hotplug_active = true; tb_dbg(tb, "resume finished\n"); @@ -3079,6 +3113,12 @@ static int tb_runtime_suspend(struct tb *tb) struct tb_cm *tcm = tb_priv(tb); mutex_lock(&tb->lock); + /* + * The below call only releases DP resources to allow exiting and + * re-entering redrive mode. + */ + tb_disconnect_and_release_dp(tb); + tb_switch_exit_redrive(tb->root_switch); tb_switch_suspend(tb->root_switch, true); tcm->hotplug_active = false; mutex_unlock(&tb->lock); @@ -3110,6 +3150,7 @@ static int tb_runtime_resume(struct tb *tb) tb_restore_children(tb->root_switch); list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) tb_tunnel_restart(tunnel); + tb_switch_enter_redrive(tb->root_switch); tcm->hotplug_active = true; mutex_unlock(&tb->lock); diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 6737188f258157..ddbf0cd7837763 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -1367,11 +1367,18 @@ enum usb4_margin_sw_error_counter { USB4_MARGIN_SW_ERROR_COUNTER_STOP, }; +enum usb4_margining_lane { + USB4_MARGINING_LANE_RX0 = 0, + USB4_MARGINING_LANE_RX1 = 1, + USB4_MARGINING_LANE_RX2 = 2, + USB4_MARGINING_LANE_ALL = 7, +}; + /** * struct usb4_port_margining_params - USB4 margining parameters * @error_counter: Error counter operation for software margining * @ber_level: Current BER level contour value - * @lanes: %0, %1 or %7 (all) + * @lanes: Lanes to enable for the margining operation * @voltage_time_offset: Offset for voltage / time for software margining * @optional_voltage_offset_range: Enable optional extended voltage range * @right_high: %false if left/low margin test is performed, %true if right/high @@ -1380,18 +1387,19 @@ enum usb4_margin_sw_error_counter { struct usb4_port_margining_params { enum usb4_margin_sw_error_counter error_counter; u32 ber_level; - u32 lanes; + enum usb4_margining_lane lanes; u32 voltage_time_offset; bool optional_voltage_offset_range; bool right_high; + bool upper_eye; bool time; }; int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target, - u8 index, u32 *caps); + u8 index, u32 *caps, size_t ncaps); int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, u8 index, const struct usb4_port_margining_params *params, - u32 *results); + u32 *results, size_t nresults); int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target, u8 index, const struct usb4_port_margining_params *params, u32 *results); diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index 402fdf8b1cdeca..e51d01671d8e7c 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -1631,11 +1631,12 @@ int usb4_port_asym_start(struct tb_port *port) * @target: Sideband target * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER * @caps: Array with at least two elements to hold the results + * @ncaps: Number of elements in the caps array * * Reads the USB4 port lane margining capabilities into @caps. */ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target, - u8 index, u32 *caps) + u8 index, u32 *caps, size_t ncaps) { int ret; @@ -1645,7 +1646,7 @@ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target, return ret; return usb4_port_sb_read(port, target, index, USB4_SB_DATA, caps, - sizeof(*caps) * 2); + sizeof(*caps) * ncaps); } /** @@ -1654,14 +1655,15 @@ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target, * @target: Sideband target * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER * @params: Parameters for USB4 hardware margining - * @results: Array with at least two elements to hold the results + * @results: Array to hold the results + * @nresults: Number of elements in the results array * * Runs hardware lane margining on USB4 port and returns the result in * @results. */ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, u8 index, const struct usb4_port_margining_params *params, - u32 *results) + u32 *results, size_t nresults) { u32 val; int ret; @@ -1672,8 +1674,8 @@ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, val = params->lanes; if (params->time) val |= USB4_MARGIN_HW_TIME; - if (params->right_high) - val |= USB4_MARGIN_HW_RH; + if (params->right_high || params->upper_eye) + val |= USB4_MARGIN_HW_RHU; if (params->ber_level) val |= FIELD_PREP(USB4_MARGIN_HW_BER_MASK, params->ber_level); if (params->optional_voltage_offset_range) @@ -1690,7 +1692,7 @@ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, return ret; return usb4_port_sb_read(port, target, index, USB4_SB_DATA, results, - sizeof(*results) * 2); + sizeof(*results) * nresults); } /** @@ -1722,6 +1724,8 @@ int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target, val |= USB4_MARGIN_SW_OPT_VOLTAGE; if (params->right_high) val |= USB4_MARGIN_SW_RH; + if (params->upper_eye) + val |= USB4_MARGIN_SW_UPPER_EYE; val |= FIELD_PREP(USB4_MARGIN_SW_COUNTER_MASK, params->error_counter); val |= FIELD_PREP(USB4_MARGIN_SW_VT_MASK, params->voltage_time_offset); diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index a45d423ad10f02..63a494d36a1fdc 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -220,7 +220,7 @@ config MOXA_INTELLIO config MOXA_SMARTIO tristate "Moxa SmartIO support v. 2.0" - depends on SERIAL_NONSTANDARD && PCI + depends on SERIAL_NONSTANDARD && PCI && HAS_IOPORT help Say Y here if you have a Moxa SmartIO multiport serial card and/or want to help develop a new version of this driver. @@ -302,7 +302,7 @@ config GOLDFISH_TTY_EARLY_CONSOLE config IPWIRELESS tristate "IPWireless 3G UMTS PCMCIA card support" - depends on PCMCIA && NETDEVICES + depends on PCMCIA && NETDEVICES && HAS_IOPORT select PPP help This is a driver for 3G UMTS PCMCIA card from IPWireless company. In diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 37164289277bf8..5af46442a792d4 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1585,7 +1585,7 @@ static void __exit amiga_serial_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver amiga_serial_driver __refdata = { - .remove_new = __exit_p(amiga_serial_remove), + .remove = __exit_p(amiga_serial_remove), .driver = { .name = "amiga-serial", }, diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index c60745f8e62162..3a958202900531 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -461,7 +461,7 @@ MODULE_DEVICE_TABLE(of, goldfish_tty_of_match); static struct platform_driver goldfish_tty_platform_driver = { .probe = goldfish_tty_probe, - .remove_new = goldfish_tty_remove, + .remove = goldfish_tty_remove, .driver = { .name = "goldfish_tty", .of_match_table = goldfish_tty_of_match, diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 095c33ad10f83c..b2ec1f6efa0a8a 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -247,7 +247,7 @@ static void hvc_opal_remove(struct platform_device *dev) static struct platform_driver hvc_opal_driver = { .probe = hvc_opal_probe, - .remove_new = hvc_opal_remove, + .remove = hvc_opal_remove, .driver = { .name = hvc_opal_name, .of_match_table = hvc_opal_match, diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 25c201cfb91e17..e5da9ce26006db 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -569,7 +569,7 @@ static struct platform_driver aspeed_vuart_driver = { .of_match_table = aspeed_vuart_table, }, .probe = aspeed_vuart_probe, - .remove_new = aspeed_vuart_remove, + .remove = aspeed_vuart_remove, }; module_platform_driver(aspeed_vuart_driver); diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index d7a0f271263a93..fdb53b54e99e60 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -267,7 +267,7 @@ static struct platform_driver bcm2835aux_serial_driver = { .pm = pm_ptr(&bcm2835aux_dev_pm_ops), }, .probe = bcm2835aux_serial_probe, - .remove_new = bcm2835aux_serial_remove, + .remove = bcm2835aux_serial_remove, }; module_platform_driver(bcm2835aux_serial_driver); diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 2569ca69223f3c..d0b18358859e11 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -812,7 +812,7 @@ static int brcmuart_handle_irq(struct uart_port *p) /* * if Receive Data Interrupt is enabled and * we're uing hardware flow control, deassert - * RTS and wait for any chars in the pipline to + * RTS and wait for any chars in the pipeline to * arrive and then check for DR again. */ if ((ier & UART_IER_RDI) && (up->mcr & UART_MCR_AFE)) { @@ -1204,7 +1204,7 @@ static struct platform_driver brcmuart_platform_driver = { .of_match_table = brcmuart_dt_ids, }, .probe = brcmuart_probe, - .remove_new = brcmuart_remove, + .remove = brcmuart_remove, }; static int __init brcmuart_init(void) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index ab9e7f20426025..6afcf27db3b888 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -750,7 +750,7 @@ static const struct dw8250_platform_data dw8250_renesas_rzn1_data = { .quirks = DW_UART_QUIRK_CPR_VALUE | DW_UART_QUIRK_IS_DMA_FC, }; -static const struct dw8250_platform_data dw8250_starfive_jh7100_data = { +static const struct dw8250_platform_data dw8250_skip_set_rate_data = { .usr_reg = DW_UART_USR, .quirks = DW_UART_QUIRK_SKIP_SET_RATE, }; @@ -760,7 +760,8 @@ static const struct of_device_id dw8250_of_match[] = { { .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data }, { .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data }, { .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data }, - { .compatible = "starfive,jh7100-uart", .data = &dw8250_starfive_jh7100_data }, + { .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data }, + { .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dw8250_of_match); @@ -796,7 +797,7 @@ static struct platform_driver dw8250_platform_driver = { .acpi_match_table = dw8250_acpi_match, }, .probe = dw8250_probe, - .remove_new = dw8250_remove, + .remove = dw8250_remove, }; module_platform_driver(dw8250_platform_driver); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 6176083d0341ca..84242292176570 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -46,8 +46,10 @@ static unsigned int serial8250_early_in(struct uart_port *port, int offset) return readl(port->membase + offset); case UPIO_MEM32BE: return ioread32be(port->membase + offset); +#ifdef CONFIG_HAS_IOPORT case UPIO_PORT: return inb(port->iobase + offset); +#endif default: return 0; } @@ -70,9 +72,11 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value) case UPIO_MEM32BE: iowrite32be(value, port->membase + offset); break; +#ifdef CONFIG_HAS_IOPORT case UPIO_PORT: outb(value, port->iobase + offset); break; +#endif } } diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index a754755100ffe1..35094f884492c7 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -219,7 +219,7 @@ static struct platform_driver serial8250_em_platform_driver = { .of_match_table = serial8250_em_dt_ids, }, .probe = serial8250_em_probe, - .remove_new = serial8250_em_remove, + .remove = serial8250_em_remove, }; module_platform_driver(serial8250_em_platform_driver); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index b7a75db15249a7..04a0cbab02c253 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -135,8 +136,6 @@ #define UART_EXAR_REGB_EECS BIT(5) #define UART_EXAR_REGB_EEDI BIT(6) #define UART_EXAR_REGB_EEDO BIT(7) -#define UART_EXAR_REGB_EE_ADDR_SIZE 6 -#define UART_EXAR_REGB_EE_DATA_SIZE 16 #define UART_EXAR_XR17C15X_PORT_OFFSET 0x200 #define UART_EXAR_XR17V25X_PORT_OFFSET 0x200 @@ -179,18 +178,19 @@ /* CTI EEPROM offsets */ #define CTI_EE_OFF_XR17C15X_OSC_FREQ 0x04 /* 2 words */ -#define CTI_EE_OFF_XR17V25X_OSC_FREQ 0x08 /* 2 words */ #define CTI_EE_OFF_XR17C15X_PART_NUM 0x0A /* 4 words */ -#define CTI_EE_OFF_XR17V25X_PART_NUM 0x0E /* 4 words */ #define CTI_EE_OFF_XR17C15X_SERIAL_NUM 0x0E /* 1 word */ + +#define CTI_EE_OFF_XR17V25X_OSC_FREQ 0x08 /* 2 words */ +#define CTI_EE_OFF_XR17V25X_PART_NUM 0x0E /* 4 words */ #define CTI_EE_OFF_XR17V25X_SERIAL_NUM 0x12 /* 1 word */ + #define CTI_EE_OFF_XR17V35X_SERIAL_NUM 0x11 /* 2 word */ #define CTI_EE_OFF_XR17V35X_BRD_FLAGS 0x13 /* 1 word */ #define CTI_EE_OFF_XR17V35X_PORT_FLAGS 0x14 /* 1 word */ #define CTI_EE_MASK_PORT_FLAGS_TYPE GENMASK(7, 0) -#define CTI_EE_MASK_OSC_FREQ_LOWER GENMASK(15, 0) -#define CTI_EE_MASK_OSC_FREQ_UPPER GENMASK(31, 16) +#define CTI_EE_MASK_OSC_FREQ GENMASK(31, 0) #define CTI_FPGA_RS485_IO_REG 0x2008 #define CTI_FPGA_CFG_INT_EN_REG 0x48 @@ -252,6 +252,7 @@ struct exar8250 { unsigned int nr; unsigned int osc_freq; struct exar8250_board *board; + struct eeprom_93cx6 eeprom; void __iomem *virt; int line[]; }; @@ -267,92 +268,37 @@ static inline u8 exar_read_reg(struct exar8250 *priv, unsigned int reg) return readb(priv->virt + reg); } -static inline void exar_ee_select(struct exar8250 *priv) -{ - // Set chip select pin high to enable EEPROM reads/writes - exar_write_reg(priv, UART_EXAR_REGB, UART_EXAR_REGB_EECS); - // Min ~500ns delay needed between CS assert and EEPROM access - udelay(1); -} - -static inline void exar_ee_deselect(struct exar8250 *priv) -{ - exar_write_reg(priv, UART_EXAR_REGB, 0x00); -} - -static inline void exar_ee_write_bit(struct exar8250 *priv, u8 bit) +static void exar_eeprom_93cx6_reg_read(struct eeprom_93cx6 *eeprom) { - u8 value = UART_EXAR_REGB_EECS; + struct exar8250 *priv = eeprom->data; + u8 regb = exar_read_reg(priv, UART_EXAR_REGB); - if (bit) - value |= UART_EXAR_REGB_EEDI; - - // Clock out the bit on the EEPROM interface - exar_write_reg(priv, UART_EXAR_REGB, value); - // 2us delay = ~500khz clock speed - udelay(2); - - value |= UART_EXAR_REGB_EECK; - - exar_write_reg(priv, UART_EXAR_REGB, value); - udelay(2); + /* EECK and EECS always read 0 from REGB so only set EEDO */ + eeprom->reg_data_out = regb & UART_EXAR_REGB_EEDO; } -static inline u8 exar_ee_read_bit(struct exar8250 *priv) +static void exar_eeprom_93cx6_reg_write(struct eeprom_93cx6 *eeprom) { - u8 regb; - u8 value = UART_EXAR_REGB_EECS; - - // Clock in the bit on the EEPROM interface - exar_write_reg(priv, UART_EXAR_REGB, value); - // 2us delay = ~500khz clock speed - udelay(2); + struct exar8250 *priv = eeprom->data; + u8 regb = 0; - value |= UART_EXAR_REGB_EECK; + if (eeprom->reg_data_in) + regb |= UART_EXAR_REGB_EEDI; + if (eeprom->reg_data_clock) + regb |= UART_EXAR_REGB_EECK; + if (eeprom->reg_chip_select) + regb |= UART_EXAR_REGB_EECS; - exar_write_reg(priv, UART_EXAR_REGB, value); - udelay(2); - - regb = exar_read_reg(priv, UART_EXAR_REGB); - - return (regb & UART_EXAR_REGB_EEDO ? 1 : 0); + exar_write_reg(priv, UART_EXAR_REGB, regb); } -/** - * exar_ee_read() - Read a word from the EEPROM - * @priv: Device's private structure - * @ee_addr: Offset of EEPROM to read word from - * - * Read a single 16bit word from an Exar UART's EEPROM. - * The type of the EEPROM is AT93C46D. - * - * Return: EEPROM word - */ -static u16 exar_ee_read(struct exar8250 *priv, u8 ee_addr) +static void exar_eeprom_init(struct exar8250 *priv) { - int i; - u16 data = 0; - - exar_ee_select(priv); - - // Send read command (opcode 110) - exar_ee_write_bit(priv, 1); - exar_ee_write_bit(priv, 1); - exar_ee_write_bit(priv, 0); - - // Send address to read from - for (i = UART_EXAR_REGB_EE_ADDR_SIZE - 1; i >= 0; i--) - exar_ee_write_bit(priv, ee_addr & BIT(i)); - - // Read data 1 bit at a time starting with a dummy bit - for (i = UART_EXAR_REGB_EE_DATA_SIZE; i >= 0; i--) { - if (exar_ee_read_bit(priv)) - data |= BIT(i); - } - - exar_ee_deselect(priv); - - return data; + priv->eeprom.data = priv; + priv->eeprom.register_read = exar_eeprom_93cx6_reg_read; + priv->eeprom.register_write = exar_eeprom_93cx6_reg_write; + priv->eeprom.width = PCI_EEPROM_WIDTH_93C46; + priv->eeprom.quirks |= PCI_EEPROM_QUIRK_EXTRA_READ_CYCLE; } /** @@ -360,7 +306,7 @@ static u16 exar_ee_read(struct exar8250 *priv, u8 ee_addr) * @priv: Device's private structure * @mpio_num: MPIO number/offset to configure * - * Configure a single MPIO as an output and disable tristate. It is reccomended + * Configure a single MPIO as an output and disable tristate. It is recommended * to set the level with exar_mpio_set_high()/exar_mpio_set_low() prior to * calling this function to ensure default MPIO pin state. * @@ -516,7 +462,7 @@ static int xr17v35x_startup(struct uart_port *port) serial_port_out(port, UART_XR_EFR, UART_EFR_ECB); /* - * Make sure all interrups are masked until initialization is + * Make sure all interrupts are masked until initialization is * complete and the FIFOs are cleared * * Synchronize UART_IER access against the console. @@ -696,20 +642,16 @@ static int cti_plx_int_enable(struct exar8250 *priv) */ static int cti_read_osc_freq(struct exar8250 *priv, u8 eeprom_offset) { - u16 lower_word; - u16 upper_word; + __le16 ee_words[2]; + u32 osc_freq; - lower_word = exar_ee_read(priv, eeprom_offset); - // Check if EEPROM word was blank - if (lower_word == 0xFFFF) - return -EIO; + eeprom_93cx6_multiread(&priv->eeprom, eeprom_offset, ee_words, ARRAY_SIZE(ee_words)); - upper_word = exar_ee_read(priv, (eeprom_offset + 1)); - if (upper_word == 0xFFFF) + osc_freq = le16_to_cpu(ee_words[0]) | (le16_to_cpu(ee_words[1]) << 16); + if (osc_freq == CTI_EE_MASK_OSC_FREQ) return -EIO; - return FIELD_PREP(CTI_EE_MASK_OSC_FREQ_LOWER, lower_word) | - FIELD_PREP(CTI_EE_MASK_OSC_FREQ_UPPER, upper_word); + return osc_freq; } /** @@ -833,7 +775,7 @@ static enum cti_port_type cti_get_port_type_xr17v35x(struct exar8250 *priv, u8 offset; offset = CTI_EE_OFF_XR17V35X_PORT_FLAGS + port_num; - port_flags = exar_ee_read(priv, offset); + eeprom_93cx6_read(&priv->eeprom, offset, &port_flags); port_type = FIELD_GET(CTI_EE_MASK_PORT_FLAGS_TYPE, port_flags); if (CTI_PORT_TYPE_VALID(port_type)) @@ -1551,6 +1493,8 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) if (rc) return rc; + exar_eeprom_init(priv); + for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { @@ -1786,7 +1730,7 @@ static struct pci_driver exar_pci_driver = { }; module_pci_driver(exar_pci_driver); -MODULE_IMPORT_NS(SERIAL_8250_PCI); +MODULE_IMPORT_NS("SERIAL_8250_PCI"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Exar Serial Driver"); MODULE_AUTHOR("Sudip Mukherjee "); diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index e2aa2a1a02ddf5..b4461a89b8d0ca 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -21,6 +21,7 @@ #define CHIP_ID_F81866 0x1010 #define CHIP_ID_F81966 0x0215 #define CHIP_ID_F81216AD 0x1602 +#define CHIP_ID_F81216E 0x1617 #define CHIP_ID_F81216H 0x0501 #define CHIP_ID_F81216 0x0802 #define VENDOR_ID1 0x23 @@ -125,7 +126,7 @@ static int fintek_8250_enter_key(u16 base_port, u8 key) if (!request_muxed_region(base_port, 2, "8250_fintek")) return -EBUSY; - /* Force to deactive all SuperIO in this base_port */ + /* Force to deactivate all SuperIO in this base_port */ outb(EXIT_KEY, base_port + ADDR_PORT); outb(key, base_port + ADDR_PORT); @@ -158,6 +159,7 @@ static int fintek_8250_check_id(struct fintek_8250 *pdata) case CHIP_ID_F81866: case CHIP_ID_F81966: case CHIP_ID_F81216AD: + case CHIP_ID_F81216E: case CHIP_ID_F81216H: case CHIP_ID_F81216: break; @@ -181,6 +183,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min, return 0; case CHIP_ID_F81216AD: + case CHIP_ID_F81216E: case CHIP_ID_F81216H: case CHIP_ID_F81216: *min = F81216_LDN_LOW; @@ -250,6 +253,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) break; case CHIP_ID_F81216AD: + case CHIP_ID_F81216E: case CHIP_ID_F81216H: case CHIP_ID_F81216: sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE, @@ -263,7 +267,8 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata) { switch (pdata->pid) { - case CHIP_ID_F81216H: /* 128Bytes FIFO */ + case CHIP_ID_F81216E: /* 128Bytes FIFO */ + case CHIP_ID_F81216H: case CHIP_ID_F81966: case CHIP_ID_F81866: sio_write_mask_reg(pdata, FIFO_CTRL, @@ -297,6 +302,7 @@ static void fintek_8250_set_termios(struct uart_port *port, goto exit; switch (pdata->pid) { + case CHIP_ID_F81216E: case CHIP_ID_F81216H: reg = RS485; break; @@ -346,6 +352,7 @@ static void fintek_8250_set_termios_handler(struct uart_8250_port *uart) struct fintek_8250 *pdata = uart->port.private_data; switch (pdata->pid) { + case CHIP_ID_F81216E: case CHIP_ID_F81216H: case CHIP_ID_F81966: case CHIP_ID_F81866: @@ -438,6 +445,11 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) uart->port.rs485_supported = fintek_8250_rs485_supported; break; + case CHIP_ID_F81216E: /* F81216E does not support RS485 delays */ + uart->port.rs485_config = fintek_8250_rs485_config; + uart->port.rs485_supported = fintek_8250_rs485_supported; + break; + default: /* No RS485 Auto direction functional */ break; } diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index b4ed442082a852..1b7bd55619c660 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -179,7 +179,7 @@ static struct platform_driver fsl8250_platform_driver = { .acpi_match_table = ACPI_PTR(fsl_8250_acpi_id), }, .probe = fsl8250_acpi_probe, - .remove_new = fsl8250_acpi_remove, + .remove = fsl8250_acpi_remove, }; module_platform_driver(fsl8250_platform_driver); diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index a2783e38a2e316..a73dd377364048 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -361,7 +361,7 @@ static struct platform_driver ingenic_uart_platform_driver = { .of_match_table = of_match, }, .probe = ingenic_uart_probe, - .remove_new = ingenic_uart_remove, + .remove = ingenic_uart_remove, }; module_platform_driver(ingenic_uart_platform_driver); diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c index 50c77c3dacf2c8..499e80aa4cf96b 100644 --- a/drivers/tty/serial/8250/8250_ioc3.c +++ b/drivers/tty/serial/8250/8250_ioc3.c @@ -84,7 +84,7 @@ static void serial8250_ioc3_remove(struct platform_device *pdev) static struct platform_driver serial8250_ioc3_driver = { .probe = serial8250_ioc3_probe, - .remove_new = serial8250_ioc3_remove, + .remove = serial8250_ioc3_remove, .driver = { .name = "ioc3-serial8250", } diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c index 47e1a056a60c34..d52445948da0b8 100644 --- a/drivers/tty/serial/8250/8250_lpc18xx.c +++ b/drivers/tty/serial/8250/8250_lpc18xx.c @@ -195,7 +195,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_serial_match); static struct platform_driver lpc18xx_serial_driver = { .probe = lpc18xx_serial_probe, - .remove_new = lpc18xx_serial_remove, + .remove = lpc18xx_serial_remove, .driver = { .name = "lpc18xx-uart", .of_match_table = lpc18xx_serial_match, diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index dc9e093b1cb311..a78ef35c81877e 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -271,4 +271,4 @@ MODULE_AUTHOR("Michael Moese private_data; + pm_runtime_get_sync(port->dev); + flush_work(&priv->qos_work); if (up->dma) omap_8250_rx_dma_flush(up); - pm_runtime_get_sync(port->dev); - serial_out(up, UART_OMAP_WER, 0); if (priv->habit & UART_HAS_EFR2) serial_out(up, UART_OMAP_EFR2, 0x0); @@ -1304,7 +1304,7 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, /* * This is mostly serial8250_handle_irq(). We have a slightly different DMA - * hoook for RX/TX and need different logic for them in the ISR. Therefore we + * hook for RX/TX and need different logic for them in the ISR. Therefore we * use the default routine in the non-DMA case and this one for with DMA. */ static int omap_8250_dma_handle_irq(struct uart_port *port) @@ -1338,7 +1338,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) serial8250_tx_chars(up); } else { /* - * try again due to an earlier failer which + * try again due to an earlier failure which * might have been resolved by now. */ if (omap_8250_tx_dma(up)) @@ -1867,7 +1867,7 @@ static struct platform_driver omap8250_platform_driver = { .of_match_table = omap8250_dt_ids, }, .probe = omap8250_probe, - .remove_new = omap8250_remove, + .remove = omap8250_remove, }; module_platform_driver(omap8250_platform_driver); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 6709b6a5f3011d..3c3f7c926afb87 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -964,6 +964,9 @@ static int pci_ite887x_init(struct pci_dev *dev) struct resource *iobase = NULL; u32 miscr, uartbar, ioport; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + /* search for the base-ioport */ for (i = 0; i < ARRAY_SIZE(inta_addr); i++) { iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, @@ -1514,6 +1517,9 @@ static int pci_quatech_init(struct pci_dev *dev) const struct pci_device_id *match; bool amcc = false; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + match = pci_match_id(quatech_cards, dev); if (match) amcc = match->driver_data; @@ -1538,6 +1544,9 @@ static int pci_quatech_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + /* Needed by pci_quatech calls below */ port->port.iobase = pci_resource_start(priv->dev, FL_GET_BASE(board->flags)); /* Set up the clocking */ @@ -1655,6 +1664,9 @@ static int pci_fintek_setup(struct serial_private *priv, u8 config_base; u16 iobase; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(pdev); + config_base = 0x40 + 0x08 * idx; /* Get the io address from configuration space */ @@ -1686,6 +1698,9 @@ static int pci_fintek_init(struct pci_dev *dev) u8 config_base; struct serial_private *priv = pci_get_drvdata(dev); + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + if (!(pci_resource_flags(dev, 5) & IORESOURCE_IO) || !(pci_resource_flags(dev, 4) & IORESOURCE_IO) || !(pci_resource_flags(dev, 3) & IORESOURCE_IO)) @@ -1864,6 +1879,9 @@ static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_BUG_THRE; port->port.serial_in = kt_serial_in; port->port.handle_break = kt_handle_break; @@ -1884,6 +1902,9 @@ pci_wch_ch353_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16550A; return pci_default_setup(priv, board, port, idx); @@ -1894,6 +1915,9 @@ pci_wch_ch355_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16550A; return pci_default_setup(priv, board, port, idx); @@ -1904,6 +1928,9 @@ pci_wch_ch38x_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + port->port.flags |= UPF_FIXED_TYPE; port->port.type = PORT_16850; return pci_default_setup(priv, board, port, idx); @@ -1918,6 +1945,8 @@ static int pci_wch_ch38x_init(struct pci_dev *dev) int max_port; unsigned long iobase; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); switch (dev->device) { case 0x3853: /* 8 ports */ @@ -1937,6 +1966,11 @@ static void pci_wch_ch38x_exit(struct pci_dev *dev) { unsigned long iobase; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) { + serial_8250_warn_need_ioport(dev); + return; + } + iobase = pci_resource_start(dev, 0); outb(0x0, iobase + CH384_XINT_ENABLE_REG); } @@ -2052,6 +2086,9 @@ static int pci_moxa_init(struct pci_dev *dev) unsigned int i, num_ports = moxa_get_nports(device); u8 val, init_mode = MOXA_RS232; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(dev); + if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) { init_mode = MOXA_RS422; } @@ -2084,6 +2121,9 @@ pci_moxa_setup(struct serial_private *priv, unsigned int bar = FL_GET_BASE(board->flags); int offset; + if (!IS_ENABLED(CONFIG_HAS_IOPORT)) + return serial_8250_warn_need_ioport(priv->dev); + if (board->num_ports == 4 && idx == 3) offset = 7 * board->uart_offset; else @@ -6140,4 +6180,4 @@ module_pci_driver(serial_pci_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module"); MODULE_DEVICE_TABLE(pci, serial_pci_tbl); -MODULE_IMPORT_NS(SERIAL_8250_PCI); +MODULE_IMPORT_NS("SERIAL_8250_PCI"); diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c index d3930bf32fe4c4..838f181f929bf0 100644 --- a/drivers/tty/serial/8250/8250_pci1xxxx.c +++ b/drivers/tty/serial/8250/8250_pci1xxxx.c @@ -812,7 +812,7 @@ module_pci_driver(pci1xxxx_pci_driver); static_assert((ARRAY_SIZE(logical_to_physical_port_idx) == PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 + 1)); -MODULE_IMPORT_NS(SERIAL_8250_PCI); +MODULE_IMPORT_NS("SERIAL_8250_PCI"); MODULE_DESCRIPTION("Microchip Technology Inc. PCIe to UART module"); MODULE_AUTHOR("Kumaravel Thiagarajan "); MODULE_AUTHOR("Tharun Kumar P "); diff --git a/drivers/tty/serial/8250/8250_pcilib.c b/drivers/tty/serial/8250/8250_pcilib.c index ea906d721b2c3e..d8d0ae0d72387c 100644 --- a/drivers/tty/serial/8250/8250_pcilib.c +++ b/drivers/tty/serial/8250/8250_pcilib.c @@ -12,6 +12,15 @@ #include "8250.h" #include "8250_pcilib.h" +int serial_8250_warn_need_ioport(struct pci_dev *dev) +{ + dev_warn(&dev->dev, + "Serial port not supported because of missing I/O resource\n"); + + return -ENXIO; +} +EXPORT_SYMBOL_NS_GPL(serial_8250_warn_need_ioport, "SERIAL_8250_PCI"); + int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar, unsigned int offset, int regshift) { @@ -27,15 +36,17 @@ int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, port->port.mapbase = pci_resource_start(dev, bar) + offset; port->port.membase = pcim_iomap_table(dev)[bar] + offset; port->port.regshift = regshift; - } else { + } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) { port->port.iotype = UPIO_PORT; port->port.iobase = pci_resource_start(dev, bar) + offset; port->port.mapbase = 0; port->port.membase = NULL; port->port.regshift = 0; + } else { + return serial_8250_warn_need_ioport(dev); } return 0; } -EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, SERIAL_8250_PCI); +EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, "SERIAL_8250_PCI"); MODULE_DESCRIPTION("8250 PCI library"); MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/8250_pcilib.h b/drivers/tty/serial/8250/8250_pcilib.h index 1aaf1b50ce9cc9..16a274574cdef9 100644 --- a/drivers/tty/serial/8250/8250_pcilib.h +++ b/drivers/tty/serial/8250/8250_pcilib.h @@ -13,3 +13,5 @@ struct uart_8250_port; int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar, unsigned int offset, int regshift); + +int serial_8250_warn_need_ioport(struct pci_dev *dev); diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c index be7ff07cbdd009..8bdc1879d952be 100644 --- a/drivers/tty/serial/8250/8250_platform.c +++ b/drivers/tty/serial/8250/8250_platform.c @@ -285,7 +285,7 @@ MODULE_DEVICE_TABLE(acpi, acpi_platform_serial_table); static struct platform_driver serial8250_isa_driver = { .probe = serial8250_probe, - .remove_new = serial8250_remove, + .remove = serial8250_remove, .suspend = serial8250_suspend, .resume = serial8250_resume, .driver = { diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3509af7dc52b88..649e74e9b52f6a 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -338,6 +338,7 @@ static void default_serial_dl_write(struct uart_8250_port *up, u32 value) serial_out(up, UART_DLM, value >> 8 & 0xff); } +#ifdef CONFIG_HAS_IOPORT static unsigned int hub6_serial_in(struct uart_port *p, int offset) { offset = offset << p->regshift; @@ -351,6 +352,7 @@ static void hub6_serial_out(struct uart_port *p, int offset, int value) outb(p->hub6 - 1 + offset, p->iobase); outb(value, p->iobase + 1); } +#endif /* CONFIG_HAS_IOPORT */ static unsigned int mem_serial_in(struct uart_port *p, int offset) { @@ -400,6 +402,7 @@ static unsigned int mem32be_serial_in(struct uart_port *p, int offset) return ioread32be(p->membase + offset); } +#ifdef CONFIG_HAS_IOPORT static unsigned int io_serial_in(struct uart_port *p, int offset) { offset = offset << p->regshift; @@ -411,6 +414,15 @@ static void io_serial_out(struct uart_port *p, int offset, int value) offset = offset << p->regshift; outb(value, p->iobase + offset); } +#endif +static unsigned int no_serial_in(struct uart_port *p, int offset) +{ + return (unsigned int)-1; +} + +static void no_serial_out(struct uart_port *p, int offset, int value) +{ +} static int serial8250_default_handle_irq(struct uart_port *port); @@ -422,10 +434,12 @@ static void set_io_from_upio(struct uart_port *p) up->dl_write = default_serial_dl_write; switch (p->iotype) { +#ifdef CONFIG_HAS_IOPORT case UPIO_HUB6: p->serial_in = hub6_serial_in; p->serial_out = hub6_serial_out; break; +#endif case UPIO_MEM: p->serial_in = mem_serial_in; @@ -446,11 +460,17 @@ static void set_io_from_upio(struct uart_port *p) p->serial_in = mem32be_serial_in; p->serial_out = mem32be_serial_out; break; - - default: +#ifdef CONFIG_HAS_IOPORT + case UPIO_PORT: p->serial_in = io_serial_in; p->serial_out = io_serial_out; break; +#endif + default: + WARN(p->iotype != UPIO_PORT || p->iobase, + "Unsupported UART type %x\n", p->iotype); + p->serial_in = no_serial_in; + p->serial_out = no_serial_out; } /* Remember loaded iotype */ up->cur_iotype = p->iotype; @@ -1174,7 +1194,7 @@ static void autoconfig(struct uart_8250_port *up) */ scratch = serial_in(up, UART_IER); serial_out(up, UART_IER, 0); -#ifdef __i386__ +#if defined(__i386__) && defined(CONFIG_HAS_IOPORT) outb(0xff, 0x080); #endif /* @@ -1183,7 +1203,7 @@ static void autoconfig(struct uart_8250_port *up) */ scratch2 = serial_in(up, UART_IER) & UART_IER_ALL_INTR; serial_out(up, UART_IER, UART_IER_ALL_INTR); -#ifdef __i386__ +#if defined(__i386__) && defined(CONFIG_HAS_IOPORT) outb(0, 0x080); #endif scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR; @@ -3176,7 +3196,7 @@ static void serial8250_config_port(struct uart_port *port, int flags) static int serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) { - if (ser->irq >= nr_irqs || ser->irq < 0 || + if (ser->irq >= irq_get_nr_irqs() || ser->irq < 0 || ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS || ser->type == PORT_STARTECH) diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c index 96dd6126296c6d..6dd0190b4843b4 100644 --- a/drivers/tty/serial/8250/8250_pxa.c +++ b/drivers/tty/serial/8250/8250_pxa.c @@ -154,7 +154,7 @@ static void serial_pxa_remove(struct platform_device *pdev) static struct platform_driver serial_pxa_driver = { .probe = serial_pxa_probe, - .remove_new = serial_pxa_remove, + .remove = serial_pxa_remove, .driver = { .name = "pxa2xx-uart", diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c index 60a80d00d2519b..2f3b0075763f28 100644 --- a/drivers/tty/serial/8250/8250_tegra.c +++ b/drivers/tty/serial/8250/8250_tegra.c @@ -182,7 +182,7 @@ static struct platform_driver tegra_uart_driver = { .acpi_match_table = ACPI_PTR(tegra_uart_acpi_match), }, .probe = tegra_uart_probe, - .remove_new = tegra_uart_remove, + .remove = tegra_uart_remove, }; module_platform_driver(tegra_uart_driver); diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 670d2ca0f75729..4874a9632db391 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -282,7 +282,7 @@ MODULE_DEVICE_TABLE(of, uniphier_uart_match); static struct platform_driver uniphier_uart_platform_driver = { .probe = uniphier_uart_probe, - .remove_new = uniphier_uart_remove, + .remove = uniphier_uart_remove, .driver = { .name = "uniphier-uart", .of_match_table = uniphier_uart_match, diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 47ff50763c048c..55d26d16df9b94 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -72,7 +72,7 @@ config SERIAL_8250_16550A_VARIANTS config SERIAL_8250_FINTEK bool "Support for Fintek variants" - depends on SERIAL_8250 + depends on SERIAL_8250 && HAS_IOPORT help Selecting this option will add support for the RS232 and RS485 capabilities of the Fintek F81216A LPC to 4 UART as well similar @@ -150,6 +150,7 @@ config SERIAL_8250_EXAR tristate "8250/16550 Exar/Commtech PCI/PCIe device support" depends on SERIAL_8250 && PCI select SERIAL_8250_PCILIB + select EEPROM_93CX6 default SERIAL_8250 help This builds support for XR17C1xx, XR17V3xx and some Commtech @@ -163,7 +164,7 @@ config SERIAL_8250_HP300 config SERIAL_8250_CS tristate "8250/16550 PCMCIA device support" - depends on PCMCIA && SERIAL_8250 + depends on PCMCIA && SERIAL_8250 && HAS_IOPORT help Say Y here to enable support for 16-bit PCMCIA serial devices, including serial port cards, modems, and the modem functions of diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 28e4beeabf8f37..45f0f779fbf960 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -877,7 +877,7 @@ config SERIAL_TXX9_STDSERIAL config SERIAL_JSM tristate "Digi International NEO and Classic PCI Support" - depends on PCI + depends on PCI && HAS_IOPORT select SERIAL_CORE help This is a driver for Digi International's Neo and Classic series diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index effcba71ea775a..b9c3c3bed0c170 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -175,8 +175,8 @@ static int altera_jtaguart_startup(struct uart_port *port) ret = request_irq(port->irq, altera_jtaguart_interrupt, 0, DRV_NAME, port); if (ret) { - pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d " - "interrupt vector=%d\n", port->line, port->irq); + dev_err(port->dev, "unable to attach Altera JTAG UART %d interrupt vector=%d\n", + port->line, port->irq); return ret; } @@ -449,7 +449,7 @@ MODULE_DEVICE_TABLE(of, altera_jtaguart_match); static struct platform_driver altera_jtaguart_platform_driver = { .probe = altera_jtaguart_probe, - .remove_new = altera_jtaguart_remove, + .remove = altera_jtaguart_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(altera_jtaguart_match), diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 897f0995b2fe77..c94655453c3353 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -307,8 +307,8 @@ static int altera_uart_startup(struct uart_port *port) ret = request_irq(port->irq, altera_uart_interrupt, 0, dev_name(port->dev), port); if (ret) { - pr_err(DRV_NAME ": unable to attach Altera UART %d " - "interrupt vector=%d\n", port->line, port->irq); + dev_err(port->dev, "unable to attach Altera UART %d interrupt vector=%d\n", + port->line, port->irq); return ret; } } @@ -617,7 +617,7 @@ MODULE_DEVICE_TABLE(of, altera_uart_match); static struct platform_driver altera_uart_platform_driver = { .probe = altera_uart_probe, - .remove_new = altera_uart_remove, + .remove = altera_uart_remove, .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(altera_uart_match), diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index eabbf8afc9b5f8..c3a7fad02ac9b3 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -499,7 +499,7 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) + if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs()) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 7d0134ecd82fa5..69b7a3e1e418e2 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1819,6 +1819,13 @@ static void pl011_unthrottle_rx(struct uart_port *port) pl011_write(uap->im, uap, REG_IMSC); +#ifdef CONFIG_DMA_ENGINE + if (uap->using_rx_dma) { + uap->dmacr |= UART011_RXDMAE; + pl011_write(uap->dmacr, uap, REG_DMACR); + } +#endif + uart_port_unlock_irqrestore(&uap->port, flags); } @@ -2202,7 +2209,7 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser) if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) + if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs()) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; @@ -2937,7 +2944,7 @@ MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match); static struct platform_driver arm_sbsa_uart_platform_driver = { .probe = sbsa_uart_probe, - .remove_new = sbsa_uart_remove, + .remove = sbsa_uart_remove, .driver = { .name = "sbsa-uart", .pm = &pl011_dev_pm_ops, diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 47889a55711988..8bb33556b31208 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -832,7 +832,7 @@ MODULE_DEVICE_TABLE(of, ar933x_uart_of_ids); static struct platform_driver ar933x_uart_platform_driver = { .probe = ar933x_uart_probe, - .remove_new = ar933x_uart_remove, + .remove = ar933x_uart_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(ar933x_uart_of_ids), diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 09b246c9e389ec..0cf05ac1899383 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1166,7 +1166,7 @@ static void atmel_rx_from_dma(struct uart_port *port) port->icount.rx += count; } - /* USART retreives ownership of RX DMA buffer */ + /* USART retrieves ownership of RX DMA buffer */ dma_sync_single_for_device(port->dev, atmel_port->rx_phys, ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE); @@ -2419,17 +2419,11 @@ static void atmel_release_port(struct uart_port *port) static int atmel_request_port(struct uart_port *port) { struct platform_device *mpdev = to_platform_device(port->dev->parent); - int size = resource_size(mpdev->resource); - - if (!request_mem_region(port->mapbase, size, "atmel_serial")) - return -EBUSY; if (port->flags & UPF_IOREMAP) { - port->membase = ioremap(port->mapbase, size); - if (port->membase == NULL) { - release_mem_region(port->mapbase, size); - return -ENOMEM; - } + port->membase = devm_platform_ioremap_resource(mpdev, 0); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); } return 0; @@ -3017,7 +3011,7 @@ static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend, static struct platform_driver atmel_serial_driver = { .probe = atmel_serial_probe, - .remove_new = atmel_serial_remove, + .remove = atmel_serial_remove, .driver = { .name = "atmel_usart_serial", .of_match_table = of_match_ptr(atmel_serial_dt_ids), diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index b88cc28c94e337..51df9d2d8bfc54 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -884,7 +884,7 @@ MODULE_DEVICE_TABLE(of, bcm63xx_of_match); */ static struct platform_driver bcm_uart_platform_driver = { .probe = bcm_uart_probe, - .remove_new = bcm_uart_remove, + .remove = bcm_uart_remove, .driver = { .name = "bcm63xx_uart", .of_match_table = bcm63xx_of_match, diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 30425a3d19fbe0..83186bf5000272 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -529,7 +529,7 @@ static struct platform_driver clps711x_uart_platform = { .of_match_table = of_match_ptr(clps711x_uart_dt_ids), }, .probe = uart_clps711x_probe, - .remove_new = uart_clps711x_remove, + .remove = uart_clps711x_remove, }; static int __init uart_clps711x_init(void) diff --git a/drivers/tty/serial/cpm_uart.c b/drivers/tty/serial/cpm_uart.c index a927478f581d71..b778a20ec9b13d 100644 --- a/drivers/tty/serial/cpm_uart.c +++ b/drivers/tty/serial/cpm_uart.c @@ -631,7 +631,7 @@ static int cpm_uart_verify_port(struct uart_port *port, if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) + if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs()) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; @@ -1573,7 +1573,7 @@ static struct platform_driver cpm_uart_driver = { .of_match_table = cpm_uart_match, }, .probe = cpm_uart_probe, - .remove_new = cpm_uart_remove, + .remove = cpm_uart_remove, }; static int __init cpm_uart_init(void) diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c index 2ccd13cc0a899f..d2482df5cb9b46 100644 --- a/drivers/tty/serial/digicolor-usart.c +++ b/drivers/tty/serial/digicolor-usart.c @@ -522,7 +522,7 @@ static struct platform_driver digicolor_uart_platform = { .of_match_table = of_match_ptr(digicolor_uart_dt_ids), }, .probe = digicolor_uart_probe, - .remove_new = digicolor_uart_remove, + .remove = digicolor_uart_remove, }; static int __init digicolor_uart_init(void) diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index a5fbb6ed38aed6..ab9af37f6cda35 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -248,6 +248,29 @@ static int __init param_setup_earlycon(char *buf) } early_param("earlycon", param_setup_earlycon); +/* + * The `console` parameter is overloaded. It's handled here as an early param + * and in `printk.c` as a late param. It's possible to specify an early + * `bootconsole` using `earlycon=uartXXXX` (handled above), or via + * the `console=uartXXX` alias. See the comment in `8250_early.c`. + */ +static int __init param_setup_earlycon_console_alias(char *buf) +{ + /* + * A plain `console` parameter must not enable the SPCR `bootconsole` + * like a plain `earlycon` does. + * + * A `console=` parameter that specifies an empty value is used to + * disable the `console`, not the `earlycon` `bootconsole`. The + * disabling of the `console` is handled by `printk.c`. + */ + if (!buf || !buf[0]) + return 0; + + return param_setup_earlycon(buf); +} +early_param("console", param_setup_earlycon_console_alias); + #ifdef CONFIG_OF_EARLY_FLATTREE int __init of_setup_earlycon(const struct earlycon_id *match, diff --git a/drivers/tty/serial/esp32_acm.c b/drivers/tty/serial/esp32_acm.c index 85eb0392e37935..bb7cc65427f0b7 100644 --- a/drivers/tty/serial/esp32_acm.c +++ b/drivers/tty/serial/esp32_acm.c @@ -423,7 +423,7 @@ static void esp32s3_acm_remove(struct platform_device *pdev) static struct platform_driver esp32s3_acm_driver = { .probe = esp32s3_acm_probe, - .remove_new = esp32s3_acm_remove, + .remove = esp32s3_acm_remove, .driver = { .name = DRIVER_NAME, .of_match_table = esp32s3_acm_dt_ids, diff --git a/drivers/tty/serial/esp32_uart.c b/drivers/tty/serial/esp32_uart.c index 8c86cf9cb7630c..667c2198a03a51 100644 --- a/drivers/tty/serial/esp32_uart.c +++ b/drivers/tty/serial/esp32_uart.c @@ -743,7 +743,7 @@ static void esp32_uart_remove(struct platform_device *pdev) static struct platform_driver esp32_uart_driver = { .probe = esp32_uart_probe, - .remove_new = esp32_uart_remove, + .remove = esp32_uart_remove, .driver = { .name = DRIVER_NAME, .of_match_table = esp32_uart_dt_ids, diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index e972df4b188d3b..e70a56de1fcedb 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -882,7 +882,7 @@ static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume); static struct platform_driver linflex_driver = { .probe = linflex_probe, - .remove_new = linflex_remove, + .remove = linflex_remove, .driver = { .name = DRIVER_NAME, .of_match_table = linflex_dt_ids, diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 77efa7ee6eda29..57b0632a3db6fb 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -184,6 +184,7 @@ #define UARTCTRL_SBK 0x00010000 #define UARTCTRL_MA1IE 0x00008000 #define UARTCTRL_MA2IE 0x00004000 +#define UARTCTRL_M7 0x00000800 #define UARTCTRL_IDLECFG GENMASK(10, 8) #define UARTCTRL_LOOPS 0x00000080 #define UARTCTRL_DOZEEN 0x00000040 @@ -2222,8 +2223,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, modem = lpuart32_read(&sport->port, UARTMODIR); sport->is_cs7 = false; /* - * only support CS8 and CS7, and for CS7 must enable PE. + * only support CS8 and CS7 * supported mode: + * - (7,n,1) (imx only) * - (7,e/o,1) * - (8,n,1) * - (8,m/s,1) @@ -2238,7 +2240,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, if ((termios->c_cflag & CSIZE) == CS8 || (termios->c_cflag & CSIZE) == CS7) - ctrl = old_ctrl & ~UARTCTRL_M; + ctrl = old_ctrl & ~(UARTCTRL_M | UARTCTRL_M7); if (termios->c_cflag & CMSPAR) { if ((termios->c_cflag & CSIZE) != CS8) { @@ -2265,9 +2267,18 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, else bd &= ~UARTBAUD_SBNS; - /* parity must be enabled when CS7 to match 8-bits format */ - if ((termios->c_cflag & CSIZE) == CS7) - termios->c_cflag |= PARENB; + /* + * imx support 7-bits format, no limitation on parity when CS7 + * for layerscape, parity must be enabled when CS7 to match 8-bits format + */ + if ((termios->c_cflag & CSIZE) == CS7 && !(termios->c_cflag & PARENB)) { + if (is_imx7ulp_lpuart(sport) || + is_imx8ulp_lpuart(sport) || + is_imx8qxp_lpuart(sport)) + ctrl |= UARTCTRL_M7; + else + termios->c_cflag |= PARENB; + } if ((termios->c_cflag & PARENB)) { if (termios->c_cflag & CMSPAR) { @@ -3206,7 +3217,7 @@ static const struct dev_pm_ops lpuart_pm_ops = { static struct platform_driver lpuart_driver = { .probe = lpuart_probe, - .remove_new = lpuart_remove, + .remove = lpuart_remove, .driver = { .name = "fsl-lpuart", .of_match_table = lpuart_dt_ids, diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 90974d338f3c0b..17f70e4bee4358 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -230,6 +230,8 @@ struct imx_port { unsigned int saved_reg[10]; bool context_saved; + bool last_putchar_was_newline; + enum imx_tx_state tx_state; struct hrtimer trigger_start_tx; struct hrtimer trigger_stop_tx; @@ -370,6 +372,7 @@ static void imx_uart_soft_reset(struct imx_port *sport) sport->idle_counter = 0; } +/* called with port.lock taken and irqs off */ static void imx_uart_disable_loopback_rs485(struct imx_port *sport) { unsigned int uts; @@ -470,6 +473,7 @@ static void imx_uart_stop_tx(struct uart_port *port) } } +/* called with port.lock taken and irqs off */ static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback) { struct imx_port *sport = to_imx_port(port); @@ -818,6 +822,8 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id) * issuing soft reset to the UART (just stop/start of RX does not help). Note * that what we do here is sending isolated start bit about 2.4 times shorter * than it is to be on UART configured baud rate. + * + * Called with port.lock taken and irqs off. */ static void imx_uart_check_flood(struct imx_port *sport, u32 usr2) { @@ -853,6 +859,7 @@ static void imx_uart_check_flood(struct imx_port *sport, u32 usr2) } } +/* called with port.lock taken and irqs off */ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; @@ -931,6 +938,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport); /* * We have a modem side uart, so the meanings of RTS and CTS are inverted. */ +/* called with port.lock taken and irqs off */ static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport) { unsigned int tmp = TIOCM_DSR; @@ -953,6 +961,8 @@ static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport) /* * Handle any change of modem status signal since we were last called. + * + * Called with port.lock taken and irqs off. */ static void imx_uart_mctrl_check(struct imx_port *sport) { @@ -1292,6 +1302,7 @@ static int imx_uart_start_rx_dma(struct imx_port *sport) return 0; } +/* called with port.lock taken and irqs off */ static void imx_uart_clear_rx_errors(struct imx_port *sport) { struct tty_port *port = &sport->port.state->port; @@ -1422,6 +1433,7 @@ static int imx_uart_dma_init(struct imx_port *sport) return ret; } +/* called with port.lock taken and irqs off */ static void imx_uart_enable_dma(struct imx_port *sport) { u32 ucr1; @@ -2069,26 +2081,34 @@ static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch) barrier(); imx_uart_writel(sport, ch, URTX0); + + sport->last_putchar_was_newline = (ch == '\n'); } -/* - * Interrupts are disabled on entering - */ -static void -imx_uart_console_write(struct console *co, const char *s, unsigned int count) +static void imx_uart_console_device_lock(struct console *co, unsigned long *flags) +{ + struct uart_port *up = &imx_uart_ports[co->index]->port; + + return __uart_port_lock_irqsave(up, flags); +} + +static void imx_uart_console_device_unlock(struct console *co, unsigned long flags) +{ + struct uart_port *up = &imx_uart_ports[co->index]->port; + + return __uart_port_unlock_irqrestore(up, flags); +} + +static void imx_uart_console_write_atomic(struct console *co, + struct nbcon_write_context *wctxt) { struct imx_port *sport = imx_uart_ports[co->index]; + struct uart_port *port = &sport->port; struct imx_port_ucrs old_ucr; - unsigned long flags; unsigned int ucr1, usr2; - int locked = 1; - if (sport->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock_irqsave(&sport->port, &flags); - else - uart_port_lock_irqsave(&sport->port, &flags); + if (!nbcon_enter_unsafe(wctxt)) + return; /* * First, save UCR1/2/3 and then disable interrupts @@ -2102,10 +2122,12 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); - imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); - uart_console_write(&sport->port, s, count, imx_uart_console_putchar); + if (!sport->last_putchar_was_newline) + uart_console_write(port, "\n", 1, imx_uart_console_putchar); + uart_console_write(port, wctxt->outbuf, wctxt->len, + imx_uart_console_putchar); /* * Finally, wait for transmitter to become empty @@ -2115,8 +2137,73 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) 0, USEC_PER_SEC, false, sport, USR2); imx_uart_ucrs_restore(sport, &old_ucr); - if (locked) - uart_port_unlock_irqrestore(&sport->port, flags); + nbcon_exit_unsafe(wctxt); +} + +static void imx_uart_console_write_thread(struct console *co, + struct nbcon_write_context *wctxt) +{ + struct imx_port *sport = imx_uart_ports[co->index]; + struct uart_port *port = &sport->port; + struct imx_port_ucrs old_ucr; + unsigned int ucr1, usr2; + + if (!nbcon_enter_unsafe(wctxt)) + return; + + /* + * First, save UCR1/2/3 and then disable interrupts + */ + imx_uart_ucrs_save(sport, &old_ucr); + ucr1 = old_ucr.ucr1; + + if (imx_uart_is_imx1(sport)) + ucr1 |= IMX1_UCR1_UARTCLKEN; + ucr1 |= UCR1_UARTEN; + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); + + imx_uart_writel(sport, ucr1, UCR1); + imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); + + if (nbcon_exit_unsafe(wctxt)) { + int len = READ_ONCE(wctxt->len); + int i; + + /* + * Write out the message. Toggle unsafe for each byte in order + * to give another (higher priority) context the opportunity + * for a friendly takeover. If such a takeover occurs, this + * context must reacquire ownership in order to perform final + * actions (such as re-enabling the interrupts). + * + * IMPORTANT: wctxt->outbuf and wctxt->len are no longer valid + * after a reacquire so writing the message must be + * aborted. + */ + for (i = 0; i < len; i++) { + if (!nbcon_enter_unsafe(wctxt)) + break; + + uart_console_write(port, wctxt->outbuf + i, 1, + imx_uart_console_putchar); + + if (!nbcon_exit_unsafe(wctxt)) + break; + } + } + + while (!nbcon_enter_unsafe(wctxt)) + nbcon_reacquire_nobuf(wctxt); + + /* + * Finally, wait for transmitter to become empty + * and restore UCR1/2/3 + */ + read_poll_timeout(imx_uart_readl, usr2, usr2 & USR2_TXDC, + 0, USEC_PER_SEC, false, sport, USR2); + imx_uart_ucrs_restore(sport, &old_ucr); + + nbcon_exit_unsafe(wctxt); } /* @@ -2208,6 +2295,8 @@ imx_uart_console_setup(struct console *co, char *options) if (retval) goto error_console; + sport->last_putchar_was_newline = true; + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else @@ -2244,11 +2333,14 @@ imx_uart_console_exit(struct console *co) static struct uart_driver imx_uart_uart_driver; static struct console imx_uart_console = { .name = DEV_NAME, - .write = imx_uart_console_write, + .write_atomic = imx_uart_console_write_atomic, + .write_thread = imx_uart_console_write_thread, + .device_lock = imx_uart_console_device_lock, + .device_unlock = imx_uart_console_device_unlock, + .flags = CON_PRINTBUFFER | CON_NBCON, .device = uart_console_device, .setup = imx_uart_console_setup, .exit = imx_uart_console_exit, - .flags = CON_PRINTBUFFER, .index = -1, .data = &imx_uart_uart_driver, }; @@ -2595,10 +2687,13 @@ static void imx_uart_save_context(struct imx_port *sport) uart_port_unlock_irqrestore(&sport->port, flags); } +/* called with irq off */ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) { u32 ucr3; + uart_port_lock(&sport->port); + ucr3 = imx_uart_readl(sport, UCR3); if (on) { imx_uart_writel(sport, USR1_AWAKE, USR1); @@ -2618,6 +2713,8 @@ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) } imx_uart_writel(sport, ucr1, UCR1); } + + uart_port_unlock(&sport->port); } static int imx_uart_suspend_noirq(struct device *dev) @@ -2717,7 +2814,7 @@ static const struct dev_pm_ops imx_uart_pm_ops = { static struct platform_driver imx_uart_platform_driver = { .probe = imx_uart_probe, - .remove_new = imx_uart_remove, + .remove = imx_uart_remove, .driver = { .name = "imx-uart", diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index a0731773ce75c5..58a3ab030d6706 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -915,7 +915,7 @@ MODULE_DEVICE_TABLE(of, ltq_asc_match); static struct platform_driver lqasc_driver = { .probe = lqasc_probe, - .remove_new = lqasc_remove, + .remove = lqasc_remove, .driver = { .name = DRVNAME, .of_match_table = ltq_asc_match, diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index 3ce369f7634983..6c13cf1ab646fb 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -353,7 +353,7 @@ MODULE_DEVICE_TABLE(of, liteuart_of_match); static struct platform_driver liteuart_platform_driver = { .probe = liteuart_probe, - .remove_new = liteuart_remove, + .remove = liteuart_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = liteuart_of_match, diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 3e4ac46de1bc37..42c5f9bc18b7c3 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -695,7 +695,7 @@ MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids); static struct platform_driver serial_hs_lpc32xx_driver = { .probe = serial_hs_lpc32xx_probe, - .remove_new = serial_hs_lpc32xx_remove, + .remove = serial_hs_lpc32xx_remove, .suspend = serial_hs_lpc32xx_suspend, .resume = serial_hs_lpc32xx_resume, .driver = { diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c index 3b4206e815fe9d..8dcad52eedfd1c 100644 --- a/drivers/tty/serial/ma35d1_serial.c +++ b/drivers/tty/serial/ma35d1_serial.c @@ -794,7 +794,7 @@ static int ma35d1serial_resume(struct platform_device *dev) static struct platform_driver ma35d1serial_driver = { .probe = ma35d1serial_probe, - .remove_new = ma35d1serial_remove, + .remove = ma35d1serial_remove, .suspend = ma35d1serial_suspend, .resume = ma35d1serial_resume, .driver = { diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c index 58858dd352c59b..93e7dda4d39acd 100644 --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -616,7 +616,7 @@ static void mcf_remove(struct platform_device *pdev) static struct platform_driver mcf_platform_driver = { .probe = mcf_probe, - .remove_new = mcf_remove, + .remove = mcf_remove, .driver = { .name = "mcfuart", }, diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 4bff422bb1bc36..9cc15449b673c4 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -920,4 +920,4 @@ MODULE_AUTHOR("Johannes Thumshirn "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MEN 16z135 High Speed UART"); MODULE_ALIAS("mcb:16z135"); -MODULE_IMPORT_NS(MCB); +MODULE_IMPORT_NS("MCB"); diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 8eb586ac3b0da0..a6cb2a535f9dcc 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -842,7 +842,7 @@ MODULE_DEVICE_TABLE(of, meson_uart_dt_match); static struct platform_driver meson_uart_platform_driver = { .probe = meson_uart_probe, - .remove_new = meson_uart_remove, + .remove = meson_uart_remove, .driver = { .name = "meson_uart", .of_match_table = meson_uart_dt_match, diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c index fb082ee73d5b25..059bea18dbab56 100644 --- a/drivers/tty/serial/milbeaut_usio.c +++ b/drivers/tty/serial/milbeaut_usio.c @@ -570,7 +570,7 @@ MODULE_DEVICE_TABLE(of, mlb_usio_dt_ids); static struct platform_driver mlb_usio_driver = { .probe = mlb_usio_probe, - .remove_new = mlb_usio_remove, + .remove = mlb_usio_remove, .driver = { .name = USIO_NAME, .of_match_table = mlb_usio_dt_ids, diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 95dae5e27b2868..f55aa353aed9ee 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -1843,7 +1843,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); static struct platform_driver mpc52xx_uart_of_driver = { .probe = mpc52xx_uart_of_probe, - .remove_new = mpc52xx_uart_of_remove, + .remove = mpc52xx_uart_of_remove, #ifdef CONFIG_PM .suspend = mpc52xx_uart_of_suspend, .resume = mpc52xx_uart_of_resume, diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 0a9c5219df88bf..1b137e06844425 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1894,7 +1894,7 @@ static const struct dev_pm_ops msm_serial_dev_pm_ops = { }; static struct platform_driver msm_platform_driver = { - .remove_new = msm_serial_remove, + .remove = msm_serial_remove, .probe = msm_serial_probe, .driver = { .name = "msm_serial", diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index a1c76565c3991f..cc65c9fb6446c2 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1704,7 +1704,7 @@ static void mxs_auart_remove(struct platform_device *pdev) static struct platform_driver mxs_auart_driver = { .probe = mxs_auart_probe, - .remove_new = mxs_auart_remove, + .remove = mxs_auart_remove, .driver = { .name = "mxs-auart", .of_match_table = mxs_auart_dt_ids, diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d7e172eeaab153..0b85f47ff19e04 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1802,7 +1802,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match); static struct platform_driver serial_omap_driver = { .probe = serial_omap_probe, - .remove_new = serial_omap_remove, + .remove = serial_omap_remove, .driver = { .name = OMAP_SERIAL_DRIVER_NAME, .pm = &serial_omap_dev_pm_ops, diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index ecec483d4d59df..0542882cfbbe45 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -730,7 +730,7 @@ static void owl_uart_remove(struct platform_device *pdev) static struct platform_driver owl_uart_platform_driver = { .probe = owl_uart_probe, - .remove_new = owl_uart_remove, + .remove = owl_uart_remove, .driver = { .name = "owl-uart", .of_match_table = owl_uart_dt_matches, diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index 261c8115a700cc..14d50bd7f1bd35 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -956,7 +956,7 @@ MODULE_DEVICE_TABLE(of, pic32_serial_dt_ids); static struct platform_driver pic32_uart_platform_driver = { .probe = pic32_uart_probe, - .remove_new = pic32_uart_remove, + .remove = pic32_uart_remove, .driver = { .name = PIC32_DEV_NAME, .of_match_table = of_match_ptr(pic32_serial_dt_ids), diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 8969b11cc0a9a9..e3a91932869545 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1776,7 +1776,7 @@ static struct macio_driver pmz_driver = { static struct platform_driver pmz_driver = { .probe = pmz_attach, - .remove_new = pmz_detach, + .remove = pmz_detach, .driver = { .name = "scc", }, diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 5dfe4e599ad68d..a80ce7aaf309d1 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1839,7 +1839,7 @@ static const struct of_device_id qcom_geni_serial_match_table[] = { MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table); static struct platform_driver qcom_geni_serial_platform_driver = { - .remove_new = qcom_geni_serial_remove, + .remove = qcom_geni_serial_remove, .probe = qcom_geni_serial_probe, .driver = { .name = "qcom_geni_serial", diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c index 663e35e424bdb0..87fa30d6868784 100644 --- a/drivers/tty/serial/rda-uart.c +++ b/drivers/tty/serial/rda-uart.c @@ -777,7 +777,7 @@ static void rda_uart_remove(struct platform_device *pdev) static struct platform_driver rda_uart_platform_driver = { .probe = rda_uart_probe, - .remove_new = rda_uart_remove, + .remove = rda_uart_remove, .driver = { .name = "rda-uart", .of_match_table = rda_uart_dt_matches, diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 8bab2aedc4991f..6d99a02dd439d0 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -698,7 +698,6 @@ static int rp2_probe(struct pci_dev *pdev, const struct firmware *fw; struct rp2_card *card; struct rp2_uart_port *ports; - void __iomem * const *bars; int rc; card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL); @@ -711,13 +710,16 @@ static int rp2_probe(struct pci_dev *pdev, if (rc) return rc; - rc = pcim_iomap_regions_request_all(pdev, 0x03, DRV_NAME); + rc = pcim_request_all_regions(pdev, DRV_NAME); if (rc) return rc; - bars = pcim_iomap_table(pdev); - card->bar0 = bars[0]; - card->bar1 = bars[1]; + card->bar0 = pcim_iomap(pdev, 0, 0); + if (!card->bar0) + return -ENOMEM; + card->bar1 = pcim_iomap(pdev, 1, 0); + if (!card->bar1) + return -ENOMEM; card->pdev = pdev; rp2_decode_cap(id, &card->n_ports, &card->smpte); diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index 79c794fa654512..3c34027687d21c 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -880,7 +880,7 @@ static void sa1100_serial_remove(struct platform_device *pdev) static struct platform_driver sa11x0_serial_driver = { .probe = sa1100_serial_probe, - .remove_new = sa1100_serial_remove, + .remove = sa1100_serial_remove, .suspend = sa1100_serial_suspend, .resume = sa1100_serial_resume, .driver = { diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 0d184ee2f9cec0..210fff7164c138 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2498,6 +2498,12 @@ static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { .fifosize = { 256, 64, 64, 64 }, }; +static const struct s3c24xx_serial_drv_data exynos8895_serial_drv_data = { + EXYNOS_COMMON_SERIAL_DRV_DATA, + /* samsung,uart-fifosize must be specified in the device tree. */ + .fifosize = { 0 }, +}; + static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = { .info = { .name = "Google GS101 UART", @@ -2528,12 +2534,14 @@ static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = { #define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data) #define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_serial_drv_data) #define EXYNOS850_SERIAL_DRV_DATA (&exynos850_serial_drv_data) +#define EXYNOS8895_SERIAL_DRV_DATA (&exynos8895_serial_drv_data) #define GS101_SERIAL_DRV_DATA (&gs101_serial_drv_data) #else #define EXYNOS4210_SERIAL_DRV_DATA NULL #define EXYNOS5433_SERIAL_DRV_DATA NULL #define EXYNOS850_SERIAL_DRV_DATA NULL +#define EXYNOS8895_SERIAL_DRV_DATA NULL #define GS101_SERIAL_DRV_DATA NULL #endif @@ -2623,6 +2631,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = { }, { .name = "gs101-uart", .driver_data = (kernel_ulong_t)GS101_SERIAL_DRV_DATA, + }, { + .name = "exynos8895-uart", + .driver_data = (kernel_ulong_t)EXYNOS8895_SERIAL_DRV_DATA, }, { }, }; @@ -2646,6 +2657,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = { .data = ARTPEC8_SERIAL_DRV_DATA }, { .compatible = "google,gs101-uart", .data = GS101_SERIAL_DRV_DATA }, + { .compatible = "samsung,exynos8895-uart", + .data = EXYNOS8895_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); @@ -2653,7 +2666,7 @@ MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); static struct platform_driver samsung_serial_driver = { .probe = s3c24xx_serial_probe, - .remove_new = s3c24xx_serial_remove, + .remove = s3c24xx_serial_remove, .id_table = s3c24xx_serial_driver_ids, .driver = { .name = "samsung-uart", diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index ad88a33a504f53..a3093e09309ffe 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -8,7 +8,7 @@ */ #undef DEFAULT_SYMBOL_NAMESPACE -#define DEFAULT_SYMBOL_NAMESPACE SERIAL_NXP_SC16IS7XX +#define DEFAULT_SYMBOL_NAMESPACE "SERIAL_NXP_SC16IS7XX" #include #include @@ -1473,7 +1473,7 @@ static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s, } static const struct serial_rs485 sc16is7xx_rs485_supported = { - .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND, + .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, .delay_rts_before_send = 1, .delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */ }; diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c index 3ed47c306d8557..cd7de9e057b851 100644 --- a/drivers/tty/serial/sc16is7xx_i2c.c +++ b/drivers/tty/serial/sc16is7xx_i2c.c @@ -64,4 +64,4 @@ module_i2c_driver(sc16is7xx_i2c_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SC16IS7xx I2C interface driver"); -MODULE_IMPORT_NS(SERIAL_NXP_SC16IS7XX); +MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX"); diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c index 73df36f8a7fd86..20d736b657b17a 100644 --- a/drivers/tty/serial/sc16is7xx_spi.c +++ b/drivers/tty/serial/sc16is7xx_spi.c @@ -87,4 +87,4 @@ module_spi_driver(sc16is7xx_spi_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SC16IS7xx SPI interface driver"); -MODULE_IMPORT_NS(SERIAL_NXP_SC16IS7XX); +MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX"); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 6d1d142fd2161f..4c851dae6624f8 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -1052,7 +1052,7 @@ static struct platform_driver sccnxp_uart_driver = { .name = SCCNXP_NAME, }, .probe = sccnxp_probe, - .remove_new = sccnxp_remove, + .remove = sccnxp_remove, .id_table = sccnxp_id_table, }; module_platform_driver(sccnxp_uart_driver); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 1183ca54ab9217..8004fc00fb9cd5 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1648,7 +1648,7 @@ static const struct dev_pm_ops tegra_uart_pm_ops = { static struct platform_driver tegra_uart_platform_driver = { .probe = tegra_uart_probe, - .remove_new = tegra_uart_remove, + .remove = tegra_uart_remove, .driver = { .name = "serial-tegra", .of_match_table = tegra_uart_of_match, diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index d94d73e45fb6de..74fa02b2377299 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -919,7 +919,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, if (uport->ops->verify_port) retval = uport->ops->verify_port(uport, new_info); - if ((new_info->irq >= nr_irqs) || (new_info->irq < 0) || + if ((new_info->irq >= irq_get_nr_irqs()) || (new_info->irq < 0) || (new_info->baud_base < 9600)) retval = -EINVAL; diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index abba3972295818..436a559234dfe7 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -1097,7 +1097,7 @@ static int serial_txx9_resume(struct platform_device *dev) static struct platform_driver serial_txx9_plat_driver = { .probe = serial_txx9_probe, - .remove_new = serial_txx9_remove, + .remove = serial_txx9_remove, #ifdef CONFIG_PM .suspend = serial_txx9_suspend, .resume = serial_txx9_resume, diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index b80e9a528e17ff..924b803af44003 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -157,6 +157,7 @@ struct sci_port { bool has_rtscts; bool autorts; + bool tx_occurred; }; #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS @@ -850,6 +851,7 @@ static void sci_transmit_chars(struct uart_port *port) { struct tty_port *tport = &port->state->port; unsigned int stopped = uart_tx_stopped(port); + struct sci_port *s = to_sci_port(port); unsigned short status; unsigned short ctrl; int count; @@ -885,6 +887,7 @@ static void sci_transmit_chars(struct uart_port *port) } sci_serial_out(port, SCxTDR, c); + s->tx_occurred = true; port->icount.tx++; } while (--count > 0); @@ -1241,6 +1244,8 @@ static void sci_dma_tx_complete(void *arg) if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); + s->tx_occurred = true; + if (!kfifo_is_empty(&tport->xmit_fifo)) { s->cookie_tx = 0; schedule_work(&s->work_tx); @@ -1731,6 +1736,19 @@ static void sci_flush_buffer(struct uart_port *port) s->cookie_tx = -EINVAL; } } + +static void sci_dma_check_tx_occurred(struct sci_port *s) +{ + struct dma_tx_state state; + enum dma_status status; + + if (!s->chan_tx) + return; + + status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state); + if (status == DMA_COMPLETE || status == DMA_IN_PROGRESS) + s->tx_occurred = true; +} #else /* !CONFIG_SERIAL_SH_SCI_DMA */ static inline void sci_request_dma(struct uart_port *port) { @@ -1740,6 +1758,10 @@ static inline void sci_free_dma(struct uart_port *port) { } +static void sci_dma_check_tx_occurred(struct sci_port *s) +{ +} + #define sci_flush_buffer NULL #endif /* !CONFIG_SERIAL_SH_SCI_DMA */ @@ -2076,6 +2098,12 @@ static unsigned int sci_tx_empty(struct uart_port *port) { unsigned short status = sci_serial_in(port, SCxSR); unsigned short in_tx_fifo = sci_txfill(port); + struct sci_port *s = to_sci_port(port); + + sci_dma_check_tx_occurred(s); + + if (!s->tx_occurred) + return TIOCSER_TEMT; return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; } @@ -2247,6 +2275,7 @@ static int sci_startup(struct uart_port *port) dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + s->tx_occurred = false; sci_request_dma(port); ret = sci_request_irq(s); @@ -3505,7 +3534,7 @@ static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume); static struct platform_driver sci_driver = { .probe = sci_probe, - .remove_new = sci_remove, + .remove = sci_remove, .driver = { .name = "sh-sci", .pm = &sci_dev_pm_ops, diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c index cbfce65c9d221a..5904a2d4cefa71 100644 --- a/drivers/tty/serial/sifive.c +++ b/drivers/tty/serial/sifive.c @@ -1040,7 +1040,7 @@ MODULE_DEVICE_TABLE(of, sifive_serial_of_match); static struct platform_driver sifive_serial_platform_driver = { .probe = sifive_serial_probe, - .remove_new = sifive_serial_remove, + .remove = sifive_serial_remove, .driver = { .name = SIFIVE_SERIAL_NAME, .pm = pm_sleep_ptr(&sifive_uart_pm_ops), diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 3fc54cc02a1fc5..8c9366321f8e73 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -53,10 +53,12 @@ #define SPRD_IEN_TX_EMPTY BIT(1) #define SPRD_IEN_BREAK_DETECT BIT(7) #define SPRD_IEN_TIMEOUT BIT(13) +#define SPRD_IEN_DATA_TIMEOUT BIT(17) /* interrupt clear register */ #define SPRD_ICLR 0x0014 #define SPRD_ICLR_TIMEOUT BIT(13) +#define SPRD_ICLR_DATA_TIMEOUT BIT(17) /* line control register */ #define SPRD_LCR 0x0018 @@ -102,6 +104,7 @@ #define SPRD_IMSR_TX_FIFO_EMPTY BIT(1) #define SPRD_IMSR_BREAK_DETECT BIT(7) #define SPRD_IMSR_TIMEOUT BIT(13) +#define SPRD_IMSR_DATA_TIMEOUT BIT(17) #define SPRD_DEFAULT_SOURCE_CLK 26000000 #define SPRD_RX_DMA_STEP 1 @@ -118,6 +121,12 @@ struct sprd_uart_dma { bool enable; }; +struct sprd_uart_data { + unsigned int timeout_ien; + unsigned int timeout_iclr; + unsigned int timeout_imsr; +}; + struct sprd_uart_port { struct uart_port port; char name[16]; @@ -126,6 +135,7 @@ struct sprd_uart_port { struct sprd_uart_dma rx_dma; dma_addr_t pos; unsigned char *rx_buf_tail; + const struct sprd_uart_data *pdata; }; static struct sprd_uart_port *sprd_port[UART_NR_MAX]; @@ -134,6 +144,18 @@ static int sprd_ports_num; static int sprd_start_dma_rx(struct uart_port *port); static int sprd_tx_dma_config(struct uart_port *port); +static const struct sprd_uart_data sc9836_data = { + .timeout_ien = SPRD_IEN_TIMEOUT, + .timeout_iclr = SPRD_ICLR_TIMEOUT, + .timeout_imsr = SPRD_IMSR_TIMEOUT, +}; + +static const struct sprd_uart_data sc9632_data = { + .timeout_ien = SPRD_IEN_DATA_TIMEOUT, + .timeout_iclr = SPRD_ICLR_DATA_TIMEOUT, + .timeout_imsr = SPRD_IMSR_DATA_TIMEOUT, +}; + static inline unsigned int serial_in(struct uart_port *port, unsigned int offset) { @@ -637,6 +659,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; unsigned int ims; + struct sprd_uart_port *sp = + container_of(port, struct sprd_uart_port, port); uart_port_lock(port); @@ -647,14 +671,14 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) return IRQ_NONE; } - if (ims & SPRD_IMSR_TIMEOUT) - serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT); + if (ims & sp->pdata->timeout_imsr) + serial_out(port, SPRD_ICLR, sp->pdata->timeout_iclr); if (ims & SPRD_IMSR_BREAK_DETECT) serial_out(port, SPRD_ICLR, SPRD_IMSR_BREAK_DETECT); if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT | - SPRD_IMSR_TIMEOUT)) + sp->pdata->timeout_imsr)) sprd_rx(port); if (ims & SPRD_IMSR_TX_FIFO_EMPTY) @@ -729,7 +753,7 @@ static int sprd_startup(struct uart_port *port) /* enable interrupt */ uart_port_lock_irqsave(port, &flags); ien = serial_in(port, SPRD_IEN); - ien |= SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT; + ien |= SPRD_IEN_BREAK_DETECT | sp->pdata->timeout_ien; if (!sp->rx_dma.enable) ien |= SPRD_IEN_RX_FULL; serial_out(port, SPRD_IEN, ien); @@ -1184,6 +1208,12 @@ static int sprd_probe(struct platform_device *pdev) up->mapbase = res->start; + sport->pdata = of_device_get_match_data(&pdev->dev); + if (!sport->pdata) { + dev_err(&pdev->dev, "get match data failed!\n"); + return -EINVAL; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -1248,14 +1278,15 @@ static int sprd_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume); static const struct of_device_id serial_ids[] = { - {.compatible = "sprd,sc9836-uart",}, + {.compatible = "sprd,sc9836-uart", .data = &sc9836_data}, + {.compatible = "sprd,sc9632-uart", .data = &sc9632_data}, {} }; MODULE_DEVICE_TABLE(of, serial_ids); static struct platform_driver sprd_platform_driver = { .probe = sprd_probe, - .remove_new = sprd_remove, + .remove = sprd_remove, .driver = { .name = "sprd_serial", .of_match_table = serial_ids, diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 8aea59f8ca13da..6ed9a327702bb5 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -934,7 +934,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(asc_serial_pm_ops, asc_serial_suspend, static struct platform_driver asc_serial_driver = { .probe = asc_serial_probe, - .remove_new = asc_serial_remove, + .remove = asc_serial_remove, .driver = { .name = DRIVER_NAME, .pm = pm_sleep_ptr(&asc_serial_pm_ops), diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index e1e7bc04c57920..7dc25454607512 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -2188,7 +2188,7 @@ static const struct dev_pm_ops stm32_serial_pm_ops = { static struct platform_driver stm32_serial_driver = { .probe = stm32_usart_serial_probe, - .remove_new = stm32_usart_serial_remove, + .remove = stm32_usart_serial_remove, .driver = { .name = DRIVER_NAME, .pm = &stm32_serial_pm_ops, diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index 7f60679fdde197..2b3ec65d595d8f 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -633,7 +633,7 @@ static struct platform_driver hv_driver = { .of_match_table = hv_match, }, .probe = hv_probe, - .remove_new = hv_remove, + .remove = hv_remove, }; static int __init sunhv_init(void) diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c index abf7c449308d9f..38deee571b0d08 100644 --- a/drivers/tty/serial/sunplus-uart.c +++ b/drivers/tty/serial/sunplus-uart.c @@ -697,7 +697,7 @@ MODULE_DEVICE_TABLE(of, sp_uart_of_match); static struct platform_driver sunplus_uart_platform_driver = { .probe = sunplus_uart_probe, - .remove_new = sunplus_uart_remove, + .remove = sunplus_uart_remove, .driver = { .name = "sunplus_uart", .of_match_table = sp_uart_of_match, diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 1acbe2fba746f9..df906ccf2e8a4f 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -1100,7 +1100,7 @@ static struct platform_driver sab_driver = { .of_match_table = sab_match, }, .probe = sab_probe, - .remove_new = sab_remove, + .remove = sab_remove, }; static int __init sunsab_init(void) diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 0f463da5e7ce68..7f0fef07e141d0 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1549,7 +1549,7 @@ static struct platform_driver su_driver = { .of_match_table = su_match, }, .probe = su_probe, - .remove_new = su_remove, + .remove = su_remove, }; static int __init sunsu_init(void) diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 71758ad4241c17..0551c24c06f5fa 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1538,7 +1538,7 @@ static struct platform_driver zs_driver = { .of_match_table = zs_match, }, .probe = zs_probe, - .remove_new = zs_remove, + .remove = zs_remove, }; static int __init sunzilog_init(void) diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c index 21ca5fcadf4997..7033dbfe8ba1ec 100644 --- a/drivers/tty/serial/tegra-tcu.c +++ b/drivers/tty/serial/tegra-tcu.c @@ -293,7 +293,7 @@ static struct platform_driver tegra_tcu_driver = { .of_match_table = tegra_tcu_match, }, .probe = tegra_tcu_probe, - .remove_new = tegra_tcu_remove, + .remove = tegra_tcu_remove, }; module_platform_driver(tegra_tcu_driver); diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c index 43fa0938b5e33e..6fa93c3872a727 100644 --- a/drivers/tty/serial/timbuart.c +++ b/drivers/tty/serial/timbuart.c @@ -485,7 +485,7 @@ static struct platform_driver timbuart_platform_driver = { .name = "timb-uart", }, .probe = timbuart_probe, - .remove_new = timbuart_remove, + .remove = timbuart_remove, }; module_platform_driver(timbuart_platform_driver); diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index 68357ac8ffe3ca..a41e7fc373b7c6 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -915,7 +915,7 @@ MODULE_ALIAS("platform:uartlite"); static struct platform_driver ulite_platform_driver = { .probe = ulite_probe, - .remove_new = ulite_remove, + .remove = ulite_remove, .driver = { .name = "uartlite", .of_match_table = of_match_ptr(ulite_of_match), diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 53bb8c5ef499ec..0613f8c11ab111 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1045,7 +1045,7 @@ static int qe_uart_verify_port(struct uart_port *port, if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM) return -EINVAL; - if (ser->irq < 0 || ser->irq >= nr_irqs) + if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs()) return -EINVAL; if (ser->baud_base < 9600) @@ -1484,7 +1484,7 @@ static struct platform_driver ucc_uart_of_driver = { .of_match_table = ucc_uart_match, }, .probe = ucc_uart_probe, - .remove_new = ucc_uart_remove, + .remove = ucc_uart_remove, }; static int __init ucc_uart_init(void) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 777392914819d7..beb151be4d3287 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1903,7 +1903,7 @@ static void cdns_uart_remove(struct platform_device *pdev) static struct platform_driver cdns_uart_platform_driver = { .probe = cdns_uart_probe, - .remove_new = cdns_uart_remove, + .remove = cdns_uart_remove, .driver = { .name = CDNS_UART_NAME, .of_match_table = cdns_uart_of_match, diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 930b04e3d148f5..f85ce02e4725bb 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -583,7 +583,6 @@ static void __sysrq_put_key_op(u8 key, const struct sysrq_key_op *op_p) void __handle_sysrq(u8 key, bool check_mask) { const struct sysrq_key_op *op_p; - int orig_log_level; int orig_suppress_printk; int i; @@ -593,13 +592,12 @@ void __handle_sysrq(u8 key, bool check_mask) rcu_sysrq_start(); rcu_read_lock(); /* - * Raise the apparent loglevel to maximum so that the sysrq header - * is shown to provide the user with positive feedback. We do not - * simply emit this at KERN_EMERG as that would change message - * routing in the consumers of /proc/kmsg. + * Enter in the force_console context so that sysrq header is shown to + * provide the user with positive feedback. We do not simply emit this + * at KERN_EMERG as that would change message routing in the consumers + * of /proc/kmsg. */ - orig_log_level = console_loglevel; - console_loglevel = CONSOLE_LOGLEVEL_DEFAULT; + printk_force_console_enter(); op_p = __sysrq_get_key_op(key); if (op_p) { @@ -609,11 +607,11 @@ void __handle_sysrq(u8 key, bool check_mask) */ if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { pr_info("%s\n", op_p->action_msg); - console_loglevel = orig_log_level; + printk_force_console_exit(); op_p->handler(key); } else { pr_info("This sysrq operation is disabled.\n"); - console_loglevel = orig_log_level; + printk_force_console_exit(); } } else { pr_info("HELP : "); @@ -631,7 +629,7 @@ void __handle_sysrq(u8 key, bool check_mask) } } pr_cont("\n"); - console_loglevel = orig_log_level; + printk_force_console_exit(); } rcu_read_unlock(); rcu_sysrq_end(); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 9771072da177cb..dcb1769c3625cd 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3631,7 +3631,7 @@ static struct ctl_table tty_table[] = { .data = &tty_ldisc_autoload, .maxlen = sizeof(tty_ldisc_autoload), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index dba935c712d64b..240ce135bbfbc3 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -417,13 +417,6 @@ void ufshcd_mcq_make_queues_operational(struct ufs_hba *hba) } EXPORT_SYMBOL_GPL(ufshcd_mcq_make_queues_operational); -void ufshcd_mcq_enable_esi(struct ufs_hba *hba) -{ - ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, - REG_UFS_MEM_CFG); -} -EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); - void ufshcd_mcq_enable(struct ufs_hba *hba) { ufshcd_rmwl(hba, MCQ_MODE_SELECT, MCQ_MODE_SELECT, REG_UFS_MEM_CFG); @@ -437,6 +430,13 @@ void ufshcd_mcq_disable(struct ufs_hba *hba) hba->mcq_enabled = false; } +void ufshcd_mcq_enable_esi(struct ufs_hba *hba) +{ + ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, + REG_UFS_MEM_CFG); +} +EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); + void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg) { ufshcd_writel(hba, msg->address_lo, REG_UFS_ESILBA); @@ -539,7 +539,7 @@ int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag) struct scsi_cmnd *cmd = lrbp->cmd; struct ufs_hw_queue *hwq; void __iomem *reg, *opr_sqd_base; - u32 nexus, id, val, rtc; + u32 nexus, id, val; int err; if (hba->quirks & UFSHCD_QUIRK_MCQ_BROKEN_RTC) @@ -573,14 +573,18 @@ int ufshcd_mcq_sq_cleanup(struct ufs_hba *hba, int task_tag) writel(readl(opr_sqd_base + REG_SQRTC) | SQ_ICU, opr_sqd_base + REG_SQRTC); - /* Poll SQRTSy.CUS = 1. Return result from SQRTSy.RTC */ + /* Wait until SQRTSy.CUS = 1. Report SQRTSy.RTC. */ reg = opr_sqd_base + REG_SQRTS; err = read_poll_timeout(readl, val, val & SQ_CUS, 20, MCQ_POLL_US, false, reg); - rtc = FIELD_GET(SQ_ICU_ERR_CODE_MASK, readl(reg)); - if (err || rtc) - dev_err(hba->dev, "%s: failed. hwq=%d, tag=%d err=%d RTC=%d\n", - __func__, id, task_tag, err, rtc); + if (err) + dev_err(hba->dev, "%s: failed. hwq=%d, tag=%d err=%d\n", + __func__, id, task_tag, err); + else + dev_info(hba->dev, + "%s, hwq %d: cleanup return code (RTC) %ld\n", + __func__, id, + FIELD_GET(SQ_ICU_ERR_CODE_MASK, readl(reg))); if (ufshcd_mcq_sq_start(hba, hwq)) err = -ETIMEDOUT; diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index 265f21133b633e..796e37a1d859f2 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -670,6 +670,9 @@ static ssize_t read_req_latency_avg_show(struct device *dev, struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_hba_monitor *m = &hba->monitor; + if (!m->nr_req[READ]) + return sysfs_emit(buf, "0\n"); + return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[READ]), m->nr_req[READ])); } @@ -737,6 +740,9 @@ static ssize_t write_req_latency_avg_show(struct device *dev, struct ufs_hba *hba = dev_get_drvdata(dev); struct ufs_hba_monitor *m = &hba->monitor; + if (!m->nr_req[WRITE]) + return sysfs_emit(buf, "0\n"); + return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[WRITE]), m->nr_req[WRITE])); } diff --git a/drivers/ufs/core/ufs_bsg.c b/drivers/ufs/core/ufs_bsg.c index 433d0480391ea6..6c09d97ae00658 100644 --- a/drivers/ufs/core/ufs_bsg.c +++ b/drivers/ufs/core/ufs_bsg.c @@ -170,7 +170,7 @@ static int ufs_bsg_request(struct bsg_job *job) break; case UPIU_TRANSACTION_UIC_CMD: memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE); - ret = ufshcd_send_uic_cmd(hba, &uc); + ret = ufshcd_send_bsg_uic_cmd(hba, &uc); if (ret) dev_err(hba->dev, "send uic cmd: error code %d\n", ret); diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 7aea8fbaeee882..9ffd94ddf8c7ce 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -84,6 +84,7 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, u8 **buf, bool ascii); int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd); +int ufshcd_send_bsg_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd); int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index abbe7135a97787..8a01e4393159d5 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -298,6 +298,7 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba); static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); static void ufshcd_hba_exit(struct ufs_hba *hba); +static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params); static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params); static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); @@ -349,18 +350,6 @@ static void ufshcd_configure_wb(struct ufs_hba *hba) ufshcd_wb_toggle_buf_flush(hba, true); } -static void ufshcd_scsi_unblock_requests(struct ufs_hba *hba) -{ - if (atomic_dec_and_test(&hba->scsi_block_reqs_cnt)) - scsi_unblock_requests(hba->host); -} - -static void ufshcd_scsi_block_requests(struct ufs_hba *hba) -{ - if (atomic_inc_return(&hba->scsi_block_reqs_cnt) == 1) - scsi_block_requests(hba->host); -} - static void ufshcd_add_cmd_upiu_trace(struct ufs_hba *hba, unsigned int tag, enum ufs_trace_str_t str_t) { @@ -739,25 +728,15 @@ EXPORT_SYMBOL_GPL(ufshcd_delay_us); * Return: -ETIMEDOUT on error, zero on success. */ static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, - u32 val, unsigned long interval_us, - unsigned long timeout_ms) + u32 val, unsigned long interval_us, + unsigned long timeout_ms) { - int err = 0; - unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); - - /* ignore bits that we don't intend to wait on */ - val = val & mask; + u32 v; - while ((ufshcd_readl(hba, reg) & mask) != val) { - usleep_range(interval_us, interval_us + 50); - if (time_after(jiffies, timeout)) { - if ((ufshcd_readl(hba, reg) & mask) != val) - err = -ETIMEDOUT; - break; - } - } + val &= mask; /* ignore bits that we don't intend to wait on */ - return err; + return read_poll_timeout(ufshcd_readl, v, (v & mask) == val, + interval_us, timeout_ms * 1000, false, hba, reg); } /** @@ -1255,11 +1234,13 @@ static bool ufshcd_is_devfreq_scaling_required(struct ufs_hba *hba, static u32 ufshcd_pending_cmds(struct ufs_hba *hba) { const struct scsi_device *sdev; + unsigned long flags; u32 pending = 0; - lockdep_assert_held(hba->host->host_lock); + spin_lock_irqsave(hba->host->host_lock, flags); __shost_for_each_device(sdev, hba->host) pending += sbitmap_weight(&sdev->budget_map); + spin_unlock_irqrestore(hba->host->host_lock, flags); return pending; } @@ -1273,7 +1254,6 @@ static u32 ufshcd_pending_cmds(struct ufs_hba *hba) static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us) { - unsigned long flags; int ret = 0; u32 tm_doorbell; u32 tr_pending; @@ -1281,7 +1261,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, ktime_t start; ufshcd_hold(hba); - spin_lock_irqsave(hba->host->host_lock, flags); /* * Wait for all the outstanding tasks/transfer requests. * Verify by checking the doorbell registers are clear. @@ -1302,7 +1281,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, break; } - spin_unlock_irqrestore(hba->host->host_lock, flags); io_schedule_timeout(msecs_to_jiffies(20)); if (ktime_to_us(ktime_sub(ktime_get(), start)) > wait_timeout_us) { @@ -1314,7 +1292,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, */ do_last_check = true; } - spin_lock_irqsave(hba->host->host_lock, flags); } while (tm_doorbell || tr_pending); if (timeout) { @@ -1324,7 +1301,6 @@ static int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, ret = -EBUSY; } out: - spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_release(hba); return ret; } @@ -2411,8 +2387,6 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) int err; hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES); - if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) - hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT; /* nutrs and nutmrs are 0 based values */ hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS_SDB) + 1; @@ -2551,13 +2525,11 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) * __ufshcd_send_uic_cmd - Send UIC commands and retrieve the result * @hba: per adapter instance * @uic_cmd: UIC command - * @completion: initialize the completion only if this is set to true * * Return: 0 only if success. */ static int -__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, - bool completion) +__ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) { lockdep_assert_held(&hba->uic_cmd_mutex); @@ -2567,8 +2539,7 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, return -EIO; } - if (completion) - init_completion(&uic_cmd->done); + init_completion(&uic_cmd->done); uic_cmd->cmd_active = 1; ufshcd_dispatch_uic_cmd(hba, uic_cmd); @@ -2594,7 +2565,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) mutex_lock(&hba->uic_cmd_mutex); ufshcd_add_delay_before_dme_cmd(hba); - ret = __ufshcd_send_uic_cmd(hba, uic_cmd, true); + ret = __ufshcd_send_uic_cmd(hba, uic_cmd); if (!ret) ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd); @@ -2775,7 +2746,6 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags) ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(cmd->sdb.length); cdb_len = min_t(unsigned short, cmd->cmd_len, UFS_CDB_SIZE); - memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE); memcpy(ucd_req_ptr->sc.cdb, cmd->cmnd, cdb_len); memset(lrbp->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); @@ -2878,6 +2848,26 @@ static void ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags); } +static void __ufshcd_setup_cmd(struct ufshcd_lrb *lrbp, struct scsi_cmnd *cmd, u8 lun, int tag) +{ + memset(lrbp->ucd_req_ptr, 0, sizeof(*lrbp->ucd_req_ptr)); + + lrbp->cmd = cmd; + lrbp->task_tag = tag; + lrbp->lun = lun; + ufshcd_prepare_lrbp_crypto(cmd ? scsi_cmd_to_rq(cmd) : NULL, lrbp); +} + +static void ufshcd_setup_scsi_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, + struct scsi_cmnd *cmd, u8 lun, int tag) +{ + __ufshcd_setup_cmd(lrbp, cmd, lun, tag); + lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba); + lrbp->req_abort_skip = false; + + ufshcd_comp_scsi_upiu(hba, lrbp); +} + /** * ufshcd_upiu_wlun_to_scsi_wlun - maps UPIU W-LUN id to SCSI W-LUN ID * @upiu_wlun_id: UPIU W-LUN id @@ -3010,16 +3000,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) ufshcd_hold(hba); lrbp = &hba->lrb[tag]; - lrbp->cmd = cmd; - lrbp->task_tag = tag; - lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun); - lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba); - ufshcd_prepare_lrbp_crypto(scsi_cmd_to_rq(cmd), lrbp); - - lrbp->req_abort_skip = false; - - ufshcd_comp_scsi_upiu(hba, lrbp); + ufshcd_setup_scsi_cmd(hba, lrbp, cmd, ufshcd_scsi_to_upiu_lun(cmd->device->lun), tag); err = ufshcd_map_sg(hba, lrbp); if (err) { @@ -3047,11 +3029,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) static void ufshcd_setup_dev_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, enum dev_cmd_type cmd_type, u8 lun, int tag) { - lrbp->cmd = NULL; - lrbp->task_tag = tag; - lrbp->lun = lun; + __ufshcd_setup_cmd(lrbp, NULL, lun, tag); lrbp->intr_cmd = true; /* No interrupt aggregation */ - ufshcd_prepare_lrbp_crypto(NULL, lrbp); hba->dev_cmd.type = cmd_type; } @@ -3083,7 +3062,6 @@ bool ufshcd_cmd_inflight(struct scsi_cmnd *cmd) static int ufshcd_clear_cmd(struct ufs_hba *hba, u32 task_tag) { u32 mask; - unsigned long flags; int err; if (hba->mcq_enabled) { @@ -3103,9 +3081,7 @@ static int ufshcd_clear_cmd(struct ufs_hba *hba, u32 task_tag) mask = 1U << task_tag; /* clear outstanding transaction before retry */ - spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_utrl_clear(hba, mask); - spin_unlock_irqrestore(hba->host->host_lock, flags); /* * wait for h/w to clear corresponding bit in door-bell. @@ -4288,7 +4264,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) reenable_intr = true; } spin_unlock_irqrestore(hba->host->host_lock, flags); - ret = __ufshcd_send_uic_cmd(hba, cmd, false); + ret = __ufshcd_send_uic_cmd(hba, cmd); if (ret) { dev_err(hba->dev, "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", @@ -4343,6 +4319,42 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) return ret; } +/** + * ufshcd_send_bsg_uic_cmd - Send UIC commands requested via BSG layer and retrieve the result + * @hba: per adapter instance + * @uic_cmd: UIC command + * + * Return: 0 only if success. + */ +int ufshcd_send_bsg_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +{ + int ret; + + if (hba->quirks & UFSHCD_QUIRK_BROKEN_UIC_CMD) + return 0; + + ufshcd_hold(hba); + + if (uic_cmd->argument1 == UIC_ARG_MIB(PA_PWRMODE) && + uic_cmd->command == UIC_CMD_DME_SET) { + ret = ufshcd_uic_pwr_ctrl(hba, uic_cmd); + goto out; + } + + mutex_lock(&hba->uic_cmd_mutex); + ufshcd_add_delay_before_dme_cmd(hba); + + ret = __ufshcd_send_uic_cmd(hba, uic_cmd); + if (!ret) + ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd); + + mutex_unlock(&hba->uic_cmd_mutex); + +out: + ufshcd_release(hba); + return ret; +} + /** * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage * using DME_SET primitives. @@ -4539,6 +4551,14 @@ static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) return -EINVAL; } + if (pwr_info->lane_rx != pwr_info->lane_tx) { + dev_err(hba->dev, "%s: asymmetric connected lanes. rx=%d, tx=%d\n", + __func__, + pwr_info->lane_rx, + pwr_info->lane_tx); + return -EINVAL; + } + /* * First, get the maximum gears of HS speed. * If a zero value, it means there is no HSGEAR capability. @@ -4651,9 +4671,6 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, dev_err(hba->dev, "%s: power mode change failed %d\n", __func__, ret); } else { - ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL, - pwr_mode); - memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr)); } @@ -4682,6 +4699,10 @@ int ufshcd_config_pwr_mode(struct ufs_hba *hba, ret = ufshcd_change_power_mode(hba, &final_params); + if (!ret) + ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL, + &final_params); + return ret; } EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode); @@ -4822,51 +4843,44 @@ EXPORT_SYMBOL_GPL(ufshcd_hba_stop); */ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) { - int retry_outer = 3; - int retry_inner; + int retry; -start: - if (ufshcd_is_hba_active(hba)) - /* change controller state to "reset state" */ - ufshcd_hba_stop(hba); + for (retry = 3; retry > 0; retry--) { + if (ufshcd_is_hba_active(hba)) + /* change controller state to "reset state" */ + ufshcd_hba_stop(hba); - /* UniPro link is disabled at this point */ - ufshcd_set_link_off(hba); + /* UniPro link is disabled at this point */ + ufshcd_set_link_off(hba); - ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE); + ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE); - /* start controller initialization sequence */ - ufshcd_hba_start(hba); + /* start controller initialization sequence */ + ufshcd_hba_start(hba); - /* - * To initialize a UFS host controller HCE bit must be set to 1. - * During initialization the HCE bit value changes from 1->0->1. - * When the host controller completes initialization sequence - * it sets the value of HCE bit to 1. The same HCE bit is read back - * to check if the controller has completed initialization sequence. - * So without this delay the value HCE = 1, set in the previous - * instruction might be read back. - * This delay can be changed based on the controller. - */ - ufshcd_delay_us(hba->vps->hba_enable_delay_us, 100); + /* + * To initialize a UFS host controller HCE bit must be set to 1. + * During initialization the HCE bit value changes from 1->0->1. + * When the host controller completes initialization sequence + * it sets the value of HCE bit to 1. The same HCE bit is read back + * to check if the controller has completed initialization sequence. + * So without this delay the value HCE = 1, set in the previous + * instruction might be read back. + * This delay can be changed based on the controller. + */ + ufshcd_delay_us(hba->vps->hba_enable_delay_us, 100); - /* wait for the host controller to complete initialization */ - retry_inner = 50; - while (!ufshcd_is_hba_active(hba)) { - if (retry_inner) { - retry_inner--; - } else { - dev_err(hba->dev, - "Controller enable failed\n"); - if (retry_outer) { - retry_outer--; - goto start; - } - return -EIO; - } - usleep_range(1000, 1100); + /* wait for the host controller to complete initialization */ + if (!ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE, CONTROLLER_ENABLE, + CONTROLLER_ENABLE, 1000, 50)) + break; + + dev_err(hba->dev, "Enabling the controller failed\n"); } + if (!retry) + return -EIO; + /* enable UIC related interrupts */ ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); @@ -5258,6 +5272,9 @@ static int ufshcd_device_configure(struct scsi_device *sdev, */ sdev->silence_suspend = 1; + if (hba->vops && hba->vops->config_scsi_dev) + hba->vops->config_scsi_dev(sdev); + ufshcd_crypto_register(hba, q); return 0; @@ -5478,32 +5495,37 @@ static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba, static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) { irqreturn_t retval = IRQ_NONE; + struct uic_command *cmd; spin_lock(hba->host->host_lock); + cmd = hba->active_uic_cmd; + if (WARN_ON_ONCE(!cmd)) + goto unlock; + if (ufshcd_is_auto_hibern8_error(hba, intr_status)) hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); - if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) { - hba->active_uic_cmd->argument2 |= - ufshcd_get_uic_cmd_result(hba); - hba->active_uic_cmd->argument3 = - ufshcd_get_dme_attr_val(hba); + if (intr_status & UIC_COMMAND_COMPL) { + cmd->argument2 |= ufshcd_get_uic_cmd_result(hba); + cmd->argument3 = ufshcd_get_dme_attr_val(hba); if (!hba->uic_async_done) - hba->active_uic_cmd->cmd_active = 0; - complete(&hba->active_uic_cmd->done); + cmd->cmd_active = 0; + complete(&cmd->done); retval = IRQ_HANDLED; } - if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) { - hba->active_uic_cmd->cmd_active = 0; + if (intr_status & UFSHCD_UIC_PWR_MASK && hba->uic_async_done) { + cmd->cmd_active = 0; complete(hba->uic_async_done); retval = IRQ_HANDLED; } if (retval == IRQ_HANDLED) - ufshcd_add_uic_command_trace(hba, hba->active_uic_cmd, - UFS_CMD_COMP); + ufshcd_add_uic_command_trace(hba, cmd, UFS_CMD_COMP); + +unlock: spin_unlock(hba->host->host_lock); + return retval; } @@ -5534,6 +5556,7 @@ void ufshcd_compl_one_cqe(struct ufs_hba *hba, int task_tag, lrbp = &hba->lrb[task_tag]; lrbp->compl_time_stamp = ktime_get(); + lrbp->compl_time_stamp_local_clock = local_clock(); cmd = lrbp->cmd; if (cmd) { if (unlikely(ufshcd_should_inform_monitor(hba, lrbp))) @@ -6196,12 +6219,11 @@ static void ufshcd_exception_event_handler(struct work_struct *work) u32 status = 0; hba = container_of(work, struct ufs_hba, eeh_work); - ufshcd_scsi_block_requests(hba); err = ufshcd_get_ee_status(hba, &status); if (err) { dev_err(hba->dev, "%s: failed to get exception status %d\n", __func__, err); - goto out; + return; } trace_ufshcd_exception_event(dev_name(hba->dev), status); @@ -6213,8 +6235,6 @@ static void ufshcd_exception_event_handler(struct work_struct *work) ufshcd_temp_exception_event_handler(hba, status); ufs_debugfs_exception_event(hba, status); -out: - ufshcd_scsi_unblock_requests(hba); } /* Complete requests that have door-bell cleared */ @@ -6380,15 +6400,14 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba) ufshcd_suspend_clkscaling(hba); ufshcd_clk_scaling_allow(hba, false); } - ufshcd_scsi_block_requests(hba); /* Wait for ongoing ufshcd_queuecommand() calls to finish. */ - blk_mq_wait_quiesce_done(&hba->host->tag_set); + blk_mq_quiesce_tagset(&hba->host->tag_set); cancel_work_sync(&hba->eeh_work); } static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) { - ufshcd_scsi_unblock_requests(hba); + blk_mq_unquiesce_tagset(&hba->host->tag_set); ufshcd_release(hba); if (ufshcd_is_clkscaling_supported(hba)) ufshcd_clk_scaling_suspend(hba, false); @@ -7002,14 +7021,11 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag) { int err = 0; u32 mask = 1 << tag; - unsigned long flags; if (!test_bit(tag, &hba->outstanding_tasks)) goto out; - spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_utmrl_clear(hba, tag); - spin_unlock_irqrestore(hba->host->host_lock, flags); /* poll for max. 1 sec to clear door bell register by h/w */ err = ufshcd_wait_for_register(hba, @@ -7052,12 +7068,13 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, memcpy(hba->utmrdl_base_addr + task_tag, treq, sizeof(*treq)); ufshcd_vops_setup_task_mgmt(hba, task_tag, tm_function); - /* send command to the controller */ __set_bit(task_tag, &hba->outstanding_tasks); - ufshcd_writel(hba, 1 << task_tag, REG_UTP_TASK_REQ_DOOR_BELL); spin_unlock_irqrestore(host->host_lock, flags); + /* send command to the controller */ + ufshcd_writel(hba, 1 << task_tag, REG_UTP_TASK_REQ_DOOR_BELL); + ufshcd_add_tm_upiu_trace(hba, task_tag, UFS_TM_SEND); /* wait until the task management command is completed */ @@ -7473,10 +7490,9 @@ static void ufshcd_set_req_abort_skip(struct ufs_hba *hba, unsigned long bitmap) int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) { struct ufshcd_lrb *lrbp = &hba->lrb[tag]; - int err = 0; + int err; int poll_cnt; u8 resp = 0xF; - u32 reg; for (poll_cnt = 100; poll_cnt; poll_cnt--) { err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, @@ -7491,46 +7507,27 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) * cmd not pending in the device, check if it is * in transition. */ - dev_err(hba->dev, "%s: cmd at tag %d not pending in the device.\n", + dev_info( + hba->dev, + "%s: cmd with tag %d not pending in the device.\n", __func__, tag); - if (hba->mcq_enabled) { - /* MCQ mode */ - if (ufshcd_cmd_inflight(lrbp->cmd)) { - /* sleep for max. 200us same delay as in SDB mode */ - usleep_range(100, 200); - continue; - } - /* command completed already */ - dev_err(hba->dev, "%s: cmd at tag=%d is cleared.\n", - __func__, tag); - goto out; + if (!ufshcd_cmd_inflight(lrbp->cmd)) { + dev_info(hba->dev, + "%s: cmd with tag=%d completed.\n", + __func__, tag); + return 0; } - - /* Single Doorbell Mode */ - reg = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); - if (reg & (1 << tag)) { - /* sleep for max. 200us to stabilize */ - usleep_range(100, 200); - continue; - } - /* command completed already */ - dev_err(hba->dev, "%s: cmd at tag %d successfully cleared from DB.\n", - __func__, tag); - goto out; + usleep_range(100, 200); } else { dev_err(hba->dev, "%s: no response from device. tag = %d, err %d\n", __func__, tag, err); - if (!err) - err = resp; /* service response error */ - goto out; + return err ? : resp; } } - if (!poll_cnt) { - err = -EBUSY; - goto out; - } + if (!poll_cnt) + return -EBUSY; err = ufshcd_issue_tm_cmd(hba, lrbp->lun, lrbp->task_tag, UFS_ABORT_TASK, &resp); @@ -7540,7 +7537,7 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) dev_err(hba->dev, "%s: issued. tag = %d, err %d\n", __func__, tag, err); } - goto out; + return err; } err = ufshcd_clear_cmd(hba, tag); @@ -7548,7 +7545,6 @@ int ufshcd_try_to_abort_task(struct ufs_hba *hba, int tag) dev_err(hba->dev, "%s: Failed clearing cmd at tag %d, err %d\n", __func__, tag, err); -out: return err; } @@ -7671,6 +7667,29 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) return err; } +/** + * ufshcd_process_probe_result - Process the ufshcd_probe_hba() result. + * @hba: UFS host controller instance. + * @probe_start: time when the ufshcd_probe_hba() call started. + * @ret: ufshcd_probe_hba() return value. + */ +static void ufshcd_process_probe_result(struct ufs_hba *hba, + ktime_t probe_start, int ret) +{ + unsigned long flags; + + spin_lock_irqsave(hba->host->host_lock, flags); + if (ret) + hba->ufshcd_state = UFSHCD_STATE_ERROR; + else if (hba->ufshcd_state == UFSHCD_STATE_RESET) + hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; + spin_unlock_irqrestore(hba->host->host_lock, flags); + + trace_ufshcd_init(dev_name(hba->dev), ret, + ktime_to_us(ktime_sub(ktime_get(), probe_start)), + hba->curr_dev_pwr_mode, hba->uic_link_state); +} + /** * ufshcd_host_reset_and_restore - reset and restore host controller * @hba: per-adapter instance @@ -7700,8 +7719,14 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) err = ufshcd_hba_enable(hba); /* Establish the link again and restore the device */ - if (!err) - err = ufshcd_probe_hba(hba, false); + if (!err) { + ktime_t probe_start = ktime_get(); + + err = ufshcd_device_init(hba, /*init_dev_params=*/false); + if (!err) + err = ufshcd_probe_hba(hba, false); + ufshcd_process_probe_result(hba, probe_start, err); + } if (err) dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err); @@ -8727,10 +8752,43 @@ static void ufshcd_config_mcq(struct ufs_hba *hba) hba->nutrs); } +static int ufshcd_post_device_init(struct ufs_hba *hba) +{ + int ret; + + ufshcd_tune_unipro_params(hba); + + /* UFS device is also active now */ + ufshcd_set_ufs_dev_active(hba); + ufshcd_force_reset_auto_bkops(hba); + + ufshcd_set_timestamp_attr(hba); + + if (!hba->max_pwr_info.is_valid) + return 0; + + /* + * Set the right value to bRefClkFreq before attempting to + * switch to HS gears. + */ + if (hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL) + ufshcd_set_dev_ref_clk(hba); + /* Gear up to HS gear. */ + ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info); + if (ret) { + dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", + __func__, ret); + return ret; + } + + return 0; +} + static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) { int ret; - struct Scsi_Host *host = hba->host; + + WARN_ON_ONCE(!hba->scsi_host_added); hba->ufshcd_state = UFSHCD_STATE_RESET; @@ -8771,56 +8829,14 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) ret = ufshcd_device_params_init(hba); if (ret) return ret; - if (is_mcq_supported(hba) && !hba->scsi_host_added) { - ufshcd_mcq_enable(hba); - ret = ufshcd_alloc_mcq(hba); - if (!ret) { - ufshcd_config_mcq(hba); - } else { - /* Continue with SDB mode */ - ufshcd_mcq_disable(hba); - use_mcq_mode = false; - dev_err(hba->dev, "MCQ mode is disabled, err=%d\n", - ret); - } - ret = scsi_add_host(host, hba->dev); - if (ret) { - dev_err(hba->dev, "scsi_add_host failed\n"); - return ret; - } - hba->scsi_host_added = true; - } else if (is_mcq_supported(hba)) { - /* UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is set */ + if (is_mcq_supported(hba) && + hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) { ufshcd_config_mcq(hba); ufshcd_mcq_enable(hba); } } - ufshcd_tune_unipro_params(hba); - - /* UFS device is also active now */ - ufshcd_set_ufs_dev_active(hba); - ufshcd_force_reset_auto_bkops(hba); - - ufshcd_set_timestamp_attr(hba); - - /* Gear up to HS gear if supported */ - if (hba->max_pwr_info.is_valid) { - /* - * Set the right value to bRefClkFreq before attempting to - * switch to HS gears. - */ - if (hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL) - ufshcd_set_dev_ref_clk(hba); - ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info); - if (ret) { - dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", - __func__, ret); - return ret; - } - } - - return 0; + return ufshcd_post_device_init(hba); } /** @@ -8834,14 +8850,8 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) */ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) { - ktime_t start = ktime_get(); - unsigned long flags; int ret; - ret = ufshcd_device_init(hba, init_dev_params); - if (ret) - goto out; - if (!hba->pm_op_in_progress && (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH)) { /* Reset the device and controller before doing reinit */ @@ -8854,13 +8864,13 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) dev_err(hba->dev, "Host controller enable failed\n"); ufshcd_print_evt_hist(hba); ufshcd_print_host_state(hba); - goto out; + return ret; } /* Reinit the device */ ret = ufshcd_device_init(hba, init_dev_params); if (ret) - goto out; + return ret; } ufshcd_print_pwr_info(hba); @@ -8880,18 +8890,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) ufshcd_write_ee_control(hba); ufshcd_configure_auto_hibern8(hba); -out: - spin_lock_irqsave(hba->host->host_lock, flags); - if (ret) - hba->ufshcd_state = UFSHCD_STATE_ERROR; - else if (hba->ufshcd_state == UFSHCD_STATE_RESET) - hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; - spin_unlock_irqrestore(hba->host->host_lock, flags); - - trace_ufshcd_init(dev_name(hba->dev), ret, - ktime_to_us(ktime_sub(ktime_get(), start)), - hba->curr_dev_pwr_mode, hba->uic_link_state); - return ret; + return 0; } /** @@ -8902,11 +8901,14 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) static void ufshcd_async_scan(void *data, async_cookie_t cookie) { struct ufs_hba *hba = (struct ufs_hba *)data; + ktime_t probe_start; int ret; down(&hba->host_sem); /* Initialize hba, detect and initialize UFS device */ + probe_start = ktime_get(); ret = ufshcd_probe_hba(hba, true); + ufshcd_process_probe_result(hba, probe_start, ret); up(&hba->host_sem); if (ret) goto out; @@ -10231,6 +10233,7 @@ void ufshcd_remove(struct ufs_hba *hba) ufs_hwmon_remove(hba); ufs_bsg_remove(hba); ufs_sysfs_remove_nodes(hba->dev); + cancel_delayed_work_sync(&hba->ufs_rtc_update_work); blk_mq_destroy_queue(hba->tmf_queue); blk_put_queue(hba->tmf_queue); blk_mq_free_tag_set(&hba->tmf_tag_set); @@ -10309,6 +10312,8 @@ EXPORT_SYMBOL_GPL(ufshcd_dealloc_host); */ static int ufshcd_set_dma_mask(struct ufs_hba *hba) { + if (hba->vops && hba->vops->set_dma_mask) + return hba->vops->set_dma_mask(hba); if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT) { if (!dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(64))) return 0; @@ -10372,6 +10377,74 @@ static const struct blk_mq_ops ufshcd_tmf_ops = { .queue_rq = ufshcd_queue_tmf, }; +static int ufshcd_add_scsi_host(struct ufs_hba *hba) +{ + int err; + + if (is_mcq_supported(hba)) { + ufshcd_mcq_enable(hba); + err = ufshcd_alloc_mcq(hba); + if (!err) { + ufshcd_config_mcq(hba); + } else { + /* Continue with SDB mode */ + ufshcd_mcq_disable(hba); + use_mcq_mode = false; + dev_err(hba->dev, "MCQ mode is disabled, err=%d\n", + err); + } + } + if (!is_mcq_supported(hba) && !hba->lsdb_sup) { + dev_err(hba->dev, + "%s: failed to initialize (legacy doorbell mode not supported)\n", + __func__); + return -EINVAL; + } + + err = scsi_add_host(hba->host, hba->dev); + if (err) { + dev_err(hba->dev, "scsi_add_host failed\n"); + return err; + } + hba->scsi_host_added = true; + + hba->tmf_tag_set = (struct blk_mq_tag_set) { + .nr_hw_queues = 1, + .queue_depth = hba->nutmrs, + .ops = &ufshcd_tmf_ops, + .flags = BLK_MQ_F_NO_SCHED, + }; + err = blk_mq_alloc_tag_set(&hba->tmf_tag_set); + if (err < 0) + goto remove_scsi_host; + hba->tmf_queue = blk_mq_alloc_queue(&hba->tmf_tag_set, NULL, NULL); + if (IS_ERR(hba->tmf_queue)) { + err = PTR_ERR(hba->tmf_queue); + goto free_tmf_tag_set; + } + hba->tmf_rqs = devm_kcalloc(hba->dev, hba->nutmrs, + sizeof(*hba->tmf_rqs), GFP_KERNEL); + if (!hba->tmf_rqs) { + err = -ENOMEM; + goto free_tmf_queue; + } + + return 0; + +free_tmf_queue: + blk_mq_destroy_queue(hba->tmf_queue); + blk_put_queue(hba->tmf_queue); + +free_tmf_tag_set: + blk_mq_free_tag_set(&hba->tmf_tag_set); + +remove_scsi_host: + if (hba->scsi_host_added) + scsi_remove_host(hba->host); + + return err; +} + /** * ufshcd_init - Driver initialization routine * @hba: per-adapter instance @@ -10503,42 +10576,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->is_irq_enabled = true; } - if (!is_mcq_supported(hba)) { - if (!hba->lsdb_sup) { - dev_err(hba->dev, "%s: failed to initialize (legacy doorbell mode not supported)\n", - __func__); - err = -EINVAL; - goto out_disable; - } - err = scsi_add_host(host, hba->dev); - if (err) { - dev_err(hba->dev, "scsi_add_host failed\n"); - goto out_disable; - } - hba->scsi_host_added = true; - } - - hba->tmf_tag_set = (struct blk_mq_tag_set) { - .nr_hw_queues = 1, - .queue_depth = hba->nutmrs, - .ops = &ufshcd_tmf_ops, - .flags = BLK_MQ_F_NO_SCHED, - }; - err = blk_mq_alloc_tag_set(&hba->tmf_tag_set); - if (err < 0) - goto out_remove_scsi_host; - hba->tmf_queue = blk_mq_alloc_queue(&hba->tmf_tag_set, NULL, NULL); - if (IS_ERR(hba->tmf_queue)) { - err = PTR_ERR(hba->tmf_queue); - goto free_tmf_tag_set; - } - hba->tmf_rqs = devm_kcalloc(hba->dev, hba->nutmrs, - sizeof(*hba->tmf_rqs), GFP_KERNEL); - if (!hba->tmf_rqs) { - err = -ENOMEM; - goto free_tmf_queue; - } - /* Reset the attached device */ ufshcd_device_reset(hba); @@ -10550,7 +10587,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) dev_err(hba->dev, "Host controller enable failed\n"); ufshcd_print_evt_hist(hba); ufshcd_print_host_state(hba); - goto free_tmf_queue; + goto out_disable; } /* @@ -10576,7 +10613,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) /* Hold auto suspend until async scan completes */ pm_runtime_get_sync(dev); - atomic_set(&hba->scsi_block_reqs_cnt, 0); + /* * We are assuming that device wasn't put in sleep/power-down * state exclusively during the boot stage before kernel. @@ -10585,6 +10622,49 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) */ ufshcd_set_ufs_dev_active(hba); + /* Initialize hba, detect and initialize UFS device */ + ktime_t probe_start = ktime_get(); + + hba->ufshcd_state = UFSHCD_STATE_RESET; + + err = ufshcd_link_startup(hba); + if (err) + goto out_disable; + + if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION) + goto initialized; + + /* Debug counters initialization */ + ufshcd_clear_dbg_ufs_stats(hba); + + /* UniPro link is active now */ + ufshcd_set_link_active(hba); + + /* Verify device initialization by sending NOP OUT UPIU */ + err = ufshcd_verify_dev_init(hba); + if (err) + goto out_disable; + + /* Initiate UFS initialization, and waiting until completion */ + err = ufshcd_complete_dev_init(hba); + if (err) + goto out_disable; + + err = ufshcd_device_params_init(hba); + if (err) + goto out_disable; + + err = ufshcd_post_device_init(hba); + +initialized: + ufshcd_process_probe_result(hba, probe_start, err); + if (err) + goto out_disable; + + err = ufshcd_add_scsi_host(hba); + if (err) + goto out_disable; + async_schedule(ufshcd_async_scan, hba); ufs_sysfs_add_nodes(hba->dev); @@ -10592,14 +10672,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_pm_qos_init(hba); return 0; -free_tmf_queue: - blk_mq_destroy_queue(hba->tmf_queue); - blk_put_queue(hba->tmf_queue); -free_tmf_tag_set: - blk_mq_free_tag_set(&hba->tmf_tag_set); -out_remove_scsi_host: - if (hba->scsi_host_added) - scsi_remove_host(hba->host); out_disable: hba->is_irq_enabled = false; ufshcd_hba_exit(hba); diff --git a/drivers/ufs/host/cdns-pltfrm.c b/drivers/ufs/host/cdns-pltfrm.c index 66811d8d1929c1..e793e3538c48f8 100644 --- a/drivers/ufs/host/cdns-pltfrm.c +++ b/drivers/ufs/host/cdns-pltfrm.c @@ -307,9 +307,7 @@ static int cdns_ufs_pltfrm_probe(struct platform_device *pdev) */ static void cdns_ufs_pltfrm_remove(struct platform_device *pdev) { - struct ufs_hba *hba = platform_get_drvdata(pdev); - - ufshcd_remove(hba); + ufshcd_pltfrm_remove(pdev); } static const struct dev_pm_ops cdns_ufs_dev_pm_ops = { @@ -321,7 +319,7 @@ static const struct dev_pm_ops cdns_ufs_dev_pm_ops = { static struct platform_driver cdns_ufs_pltfrm_driver = { .probe = cdns_ufs_pltfrm_probe, - .remove_new = cdns_ufs_pltfrm_remove, + .remove = cdns_ufs_pltfrm_remove, .driver = { .name = "cdns-ufshcd", .pm = &cdns_ufs_dev_pm_ops, diff --git a/drivers/ufs/host/tc-dwc-g210-pci.c b/drivers/ufs/host/tc-dwc-g210-pci.c index 876781fd6861ee..0167d8bef71a13 100644 --- a/drivers/ufs/host/tc-dwc-g210-pci.c +++ b/drivers/ufs/host/tc-dwc-g210-pci.c @@ -80,14 +80,12 @@ tc_dwc_g210_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); - err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD); - if (err < 0) { + mmio_base = pcim_iomap_region(pdev, 0, UFSHCD); + if (IS_ERR(mmio_base)) { dev_err(&pdev->dev, "request and iomap failed\n"); - return err; + return PTR_ERR(mmio_base); } - mmio_base = pcim_iomap_table(pdev)[0]; - err = ufshcd_alloc_host(&pdev->dev, &hba); if (err) { dev_err(&pdev->dev, "Allocation failed\n"); diff --git a/drivers/ufs/host/tc-dwc-g210-pltfrm.c b/drivers/ufs/host/tc-dwc-g210-pltfrm.c index a3877592604d5d..454ac88c357da2 100644 --- a/drivers/ufs/host/tc-dwc-g210-pltfrm.c +++ b/drivers/ufs/host/tc-dwc-g210-pltfrm.c @@ -76,10 +76,7 @@ static int tc_dwc_g210_pltfm_probe(struct platform_device *pdev) */ static void tc_dwc_g210_pltfm_remove(struct platform_device *pdev) { - struct ufs_hba *hba = platform_get_drvdata(pdev); - - pm_runtime_get_sync(&(pdev)->dev); - ufshcd_remove(hba); + ufshcd_pltfrm_remove(pdev); } static const struct dev_pm_ops tc_dwc_g210_pltfm_pm_ops = { @@ -89,7 +86,7 @@ static const struct dev_pm_ops tc_dwc_g210_pltfm_pm_ops = { static struct platform_driver tc_dwc_g210_pltfm_driver = { .probe = tc_dwc_g210_pltfm_probe, - .remove_new = tc_dwc_g210_pltfm_remove, + .remove = tc_dwc_g210_pltfm_remove, .driver = { .name = "tc-dwc-g210-pltfm", .pm = &tc_dwc_g210_pltfm_pm_ops, diff --git a/drivers/ufs/host/ti-j721e-ufs.c b/drivers/ufs/host/ti-j721e-ufs.c index 250c22df000d53..21214e5d589644 100644 --- a/drivers/ufs/host/ti-j721e-ufs.c +++ b/drivers/ufs/host/ti-j721e-ufs.c @@ -83,7 +83,7 @@ MODULE_DEVICE_TABLE(of, ti_j721e_ufs_of_match); static struct platform_driver ti_j721e_ufs_driver = { .probe = ti_j721e_ufs_probe, - .remove_new = ti_j721e_ufs_remove, + .remove = ti_j721e_ufs_remove, .driver = { .name = "ti-j721e-ufs", .of_match_table = ti_j721e_ufs_of_match, diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index 5867e633856233..13dd5dfc03eb38 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -48,6 +48,8 @@ #define HCI_UNIPRO_APB_CLK_CTRL 0x68 #define UNIPRO_APB_CLK(v, x) (((v) & ~0xF) | ((x) & 0xF)) #define HCI_AXIDMA_RWDATA_BURST_LEN 0x6C +#define WLU_EN BIT(31) +#define WLU_BURST_LEN(x) ((x) << 27 | ((x) & 0xF)) #define HCI_GPIO_OUT 0x70 #define HCI_ERR_EN_PA_LAYER 0x78 #define HCI_ERR_EN_DL_LAYER 0x7C @@ -74,6 +76,10 @@ #define CLK_CTRL_EN_MASK (REFCLK_CTRL_EN |\ UNIPRO_PCLK_CTRL_EN |\ UNIPRO_MCLK_CTRL_EN) + +#define HCI_IOP_ACG_DISABLE 0x100 +#define HCI_IOP_ACG_DISABLE_EN BIT(0) + /* Device fatal error */ #define DFES_ERR_EN BIT(31) #define DFES_DEF_L2_ERRS (UIC_DATA_LINK_LAYER_ERROR_RX_BUF_OF |\ @@ -198,15 +204,8 @@ static inline void exynos_ufs_ungate_clks(struct exynos_ufs *ufs) exynos_ufs_ctrl_clkstop(ufs, false); } -static int exynos7_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs) -{ - return 0; -} - -static int exynosauto_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs) +static int exynos_ufs_shareability(struct exynos_ufs *ufs) { - struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr; - /* IO Coherency setting */ if (ufs->sysreg) { return regmap_update_bits(ufs->sysreg, @@ -214,11 +213,32 @@ static int exynosauto_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs) UFS_SHARABLE, UFS_SHARABLE); } - attr->tx_dif_p_nsec = 3200000; - return 0; } +static int gs101_ufs_drv_init(struct exynos_ufs *ufs) +{ + struct ufs_hba *hba = ufs->hba; + u32 reg; + + /* Enable WriteBooster */ + hba->caps |= UFSHCD_CAP_WB_EN; + + /* Enable clock gating and hibern8 */ + hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; + + /* set ACG to be controlled by UFS_ACG_DISABLE */ + reg = hci_readl(ufs, HCI_IOP_ACG_DISABLE); + hci_writel(ufs, reg & (~HCI_IOP_ACG_DISABLE_EN), HCI_IOP_ACG_DISABLE); + + return exynos_ufs_shareability(ufs); +} + +static int exynosauto_ufs_drv_init(struct exynos_ufs *ufs) +{ + return exynos_ufs_shareability(ufs); +} + static int exynosauto_ufs_post_hce_enable(struct exynos_ufs *ufs) { struct ufs_hba *hba = ufs->hba; @@ -546,6 +566,9 @@ static void exynos_ufs_specify_phy_time_attr(struct exynos_ufs *ufs) struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr; struct ufs_phy_time_cfg *t_cfg = &ufs->t_cfg; + if (ufs->opts & EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR) + return; + t_cfg->tx_linereset_p = exynos_ufs_calc_time_cntr(ufs, attr->tx_dif_p_nsec); t_cfg->tx_linereset_n = @@ -724,6 +747,9 @@ static void exynos_ufs_config_smu(struct exynos_ufs *ufs) { u32 reg, val; + if (ufs->opts & EXYNOS_UFS_OPT_UFSPR_SECURE) + return; + exynos_ufs_disable_auto_ctrl_hcc_save(ufs, &val); /* make encryption disabled by default */ @@ -771,6 +797,21 @@ static void exynos_ufs_config_sync_pattern_mask(struct exynos_ufs *ufs, exynos_ufs_disable_ov_tm(hba); } +#define UFS_HW_VER_MAJOR_MASK GENMASK(15, 8) + +static u32 exynos_ufs_get_hs_gear(struct ufs_hba *hba) +{ + u8 major; + + major = FIELD_GET(UFS_HW_VER_MAJOR_MASK, hba->ufs_version); + + if (major >= 3) + return UFS_HS_G4; + + /* Default is HS-G3 */ + return UFS_HS_G3; +} + static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) @@ -788,6 +829,10 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, ufshcd_init_host_params(&host_params); + /* This driver only support symmetric gear setting e.g. hs_tx_gear == hs_rx_gear */ + host_params.hs_tx_gear = exynos_ufs_get_hs_gear(hba); + host_params.hs_rx_gear = exynos_ufs_get_hs_gear(hba); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { pr_err("%s: failed to determine capabilities\n", __func__); @@ -1429,7 +1474,7 @@ static int exynos_ufs_init(struct ufs_hba *hba) exynos_ufs_fmp_init(hba, ufs); if (ufs->drv_data->drv_init) { - ret = ufs->drv_data->drv_init(dev, ufs); + ret = ufs->drv_data->drv_init(ufs); if (ret) { dev_err(dev, "failed to init drv-data\n"); goto out; @@ -1440,8 +1485,8 @@ static int exynos_ufs_init(struct ufs_hba *hba) if (ret) goto out; exynos_ufs_specify_phy_time_attr(ufs); - if (!(ufs->opts & EXYNOS_UFS_OPT_UFSPR_SECURE)) - exynos_ufs_config_smu(ufs); + + exynos_ufs_config_smu(ufs); hba->host->dma_alignment = DATA_UNIT_SIZE - 1; return 0; @@ -1484,12 +1529,12 @@ static void exynos_ufs_dev_hw_reset(struct ufs_hba *hba) hci_writel(ufs, 1 << 0, HCI_GPIO_OUT); } -static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, u8 enter) +static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd) { struct exynos_ufs *ufs = ufshcd_get_variant(hba); struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr; - if (!enter) { + if (cmd == UIC_CMD_DME_HIBER_EXIT) { if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL) exynos_ufs_disable_auto_ctrl_hcc(ufs); exynos_ufs_ungate_clks(ufs); @@ -1517,30 +1562,11 @@ static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, u8 enter) } } -static void exynos_ufs_post_hibern8(struct ufs_hba *hba, u8 enter) +static void exynos_ufs_post_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd) { struct exynos_ufs *ufs = ufshcd_get_variant(hba); - if (!enter) { - u32 cur_mode = 0; - u32 pwrmode; - - if (ufshcd_is_hs_mode(&ufs->dev_req_params)) - pwrmode = FAST_MODE; - else - pwrmode = SLOW_MODE; - - ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &cur_mode); - if (cur_mode != (pwrmode << 4 | pwrmode)) { - dev_warn(hba->dev, "%s: power mode change\n", __func__); - hba->pwr_info.pwr_rx = (cur_mode >> 4) & 0xf; - hba->pwr_info.pwr_tx = cur_mode & 0xf; - ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info); - } - - if (!(ufs->opts & EXYNOS_UFS_OPT_SKIP_CONNECTION_ESTAB)) - exynos_ufs_establish_connt(ufs); - } else { + if (cmd == UIC_CMD_DME_HIBER_ENTER) { ufs->entry_hibern8_t = ktime_get(); exynos_ufs_gate_clks(ufs); if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL) @@ -1627,15 +1653,15 @@ static int exynos_ufs_pwr_change_notify(struct ufs_hba *hba, } static void exynos_ufs_hibern8_notify(struct ufs_hba *hba, - enum uic_cmd_dme enter, + enum uic_cmd_dme cmd, enum ufs_notify_change_status notify) { switch ((u8)notify) { case PRE_CHANGE: - exynos_ufs_pre_hibern8(hba, enter); + exynos_ufs_pre_hibern8(hba, cmd); break; case POST_CHANGE: - exynos_ufs_post_hibern8(hba, enter); + exynos_ufs_post_hibern8(hba, cmd); break; } } @@ -1891,6 +1917,12 @@ static int gs101_ufs_post_link(struct exynos_ufs *ufs) { struct ufs_hba *hba = ufs->hba; + /* + * Enable Write Line Unique. This field has to be 0x3 + * to support Write Line Unique transaction on gs101. + */ + hci_writel(ufs, WLU_EN | WLU_BURST_LEN(3), HCI_AXIDMA_RWDATA_BURST_LEN); + exynos_ufs_enable_dbg_mode(hba); ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SAVECONFIGTIME), 0x3e8); exynos_ufs_disable_dbg_mode(hba); @@ -1960,8 +1992,7 @@ static void exynos_ufs_remove(struct platform_device *pdev) struct ufs_hba *hba = platform_get_drvdata(pdev); struct exynos_ufs *ufs = ufshcd_get_variant(hba); - pm_runtime_get_sync(&(pdev)->dev); - ufshcd_remove(hba); + ufshcd_pltfrm_remove(pdev); phy_power_off(ufs->phy); phy_exit(ufs->phy); @@ -2036,7 +2067,6 @@ static const struct exynos_ufs_drv_data exynos_ufs_drvs = { EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX | EXYNOS_UFS_OPT_SKIP_CONNECTION_ESTAB | EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER, - .drv_init = exynos7_ufs_drv_init, .pre_link = exynos7_ufs_pre_link, .post_link = exynos7_ufs_post_link, .pre_pwr_change = exynos7_ufs_pre_pwr_change, @@ -2045,26 +2075,6 @@ static const struct exynos_ufs_drv_data exynos_ufs_drvs = { static struct exynos_ufs_uic_attr gs101_uic_attr = { .tx_trailingclks = 0xff, - .tx_dif_p_nsec = 3000000, /* unit: ns */ - .tx_dif_n_nsec = 1000000, /* unit: ns */ - .tx_high_z_cnt_nsec = 20000, /* unit: ns */ - .tx_base_unit_nsec = 100000, /* unit: ns */ - .tx_gran_unit_nsec = 4000, /* unit: ns */ - .tx_sleep_cnt = 1000, /* unit: ns */ - .tx_min_activatetime = 0xa, - .rx_filler_enable = 0x2, - .rx_dif_p_nsec = 1000000, /* unit: ns */ - .rx_hibern8_wait_nsec = 4000000, /* unit: ns */ - .rx_base_unit_nsec = 100000, /* unit: ns */ - .rx_gran_unit_nsec = 4000, /* unit: ns */ - .rx_sleep_cnt = 1280, /* unit: ns */ - .rx_stall_cnt = 320, /* unit: ns */ - .rx_hs_g1_sync_len_cap = SYNC_LEN_COARSE(0xf), - .rx_hs_g2_sync_len_cap = SYNC_LEN_COARSE(0xf), - .rx_hs_g3_sync_len_cap = SYNC_LEN_COARSE(0xf), - .rx_hs_g1_prep_sync_len_cap = PREP_LEN(0xf), - .rx_hs_g2_prep_sync_len_cap = PREP_LEN(0xf), - .rx_hs_g3_prep_sync_len_cap = PREP_LEN(0xf), .pa_dbg_opt_suite1_val = 0x90913C1C, .pa_dbg_opt_suite1_off = PA_GS101_DBG_OPTION_SUITE1, .pa_dbg_opt_suite2_val = 0xE01C115F, @@ -2122,11 +2132,10 @@ static const struct exynos_ufs_drv_data gs101_ufs_drvs = { UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR | UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL | UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING, - .opts = EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL | - EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR | + .opts = EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR | EXYNOS_UFS_OPT_UFSPR_SECURE | EXYNOS_UFS_OPT_TIMER_TICK_SELECT, - .drv_init = exynosauto_ufs_drv_init, + .drv_init = gs101_ufs_drv_init, .pre_link = gs101_ufs_pre_link, .post_link = gs101_ufs_post_link, .pre_pwr_change = gs101_ufs_pre_pwr_change, @@ -2156,7 +2165,7 @@ static const struct dev_pm_ops exynos_ufs_pm_ops = { static struct platform_driver exynos_ufs_pltform = { .probe = exynos_ufs_probe, - .remove_new = exynos_ufs_remove, + .remove = exynos_ufs_remove, .driver = { .name = "exynos-ufshc", .pm = &exynos_ufs_pm_ops, diff --git a/drivers/ufs/host/ufs-exynos.h b/drivers/ufs/host/ufs-exynos.h index 1646c4a9bb088d..9670dc138d1e49 100644 --- a/drivers/ufs/host/ufs-exynos.h +++ b/drivers/ufs/host/ufs-exynos.h @@ -182,7 +182,7 @@ struct exynos_ufs_drv_data { unsigned int quirks; unsigned int opts; /* SoC's specific operations */ - int (*drv_init)(struct device *dev, struct exynos_ufs *ufs); + int (*drv_init)(struct exynos_ufs *ufs); int (*pre_link)(struct exynos_ufs *ufs); int (*post_link)(struct exynos_ufs *ufs); int (*pre_pwr_change)(struct exynos_ufs *ufs, diff --git a/drivers/ufs/host/ufs-hisi.c b/drivers/ufs/host/ufs-hisi.c index 5ee73ff052512b..6e6569de74d830 100644 --- a/drivers/ufs/host/ufs-hisi.c +++ b/drivers/ufs/host/ufs-hisi.c @@ -576,9 +576,7 @@ static int ufs_hisi_probe(struct platform_device *pdev) static void ufs_hisi_remove(struct platform_device *pdev) { - struct ufs_hba *hba = platform_get_drvdata(pdev); - - ufshcd_remove(hba); + ufshcd_pltfrm_remove(pdev); } static const struct dev_pm_ops ufs_hisi_pm_ops = { @@ -590,7 +588,7 @@ static const struct dev_pm_ops ufs_hisi_pm_ops = { static struct platform_driver ufs_hisi_pltform = { .probe = ufs_hisi_probe, - .remove_new = ufs_hisi_remove, + .remove = ufs_hisi_remove, .driver = { .name = "ufshcd-hisi", .pm = &ufs_hisi_pm_ops, diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index 9a5919434c4e0d..135cd78109e24e 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -1780,6 +1780,15 @@ static int ufs_mtk_config_esi(struct ufs_hba *hba) return ufs_mtk_config_mcq(hba, true); } +static void ufs_mtk_config_scsi_dev(struct scsi_device *sdev) +{ + struct ufs_hba *hba = shost_priv(sdev->host); + + dev_dbg(hba->dev, "lu %llu scsi device configured", sdev->lun); + if (sdev->lun == 2) + blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, sdev->request_queue); +} + /* * struct ufs_hba_mtk_vops - UFS MTK specific variant operations * @@ -1809,6 +1818,7 @@ static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = { .op_runtime_config = ufs_mtk_op_runtime_config, .mcq_config_resource = ufs_mtk_mcq_config_resource, .config_esi = ufs_mtk_config_esi, + .config_scsi_dev = ufs_mtk_config_scsi_dev, }; /** @@ -1869,10 +1879,7 @@ static int ufs_mtk_probe(struct platform_device *pdev) */ static void ufs_mtk_remove(struct platform_device *pdev) { - struct ufs_hba *hba = platform_get_drvdata(pdev); - - pm_runtime_get_sync(&(pdev)->dev); - ufshcd_remove(hba); + ufshcd_pltfrm_remove(pdev); } #ifdef CONFIG_PM_SLEEP @@ -1952,7 +1959,7 @@ static const struct dev_pm_ops ufs_mtk_pm_ops = { static struct platform_driver ufs_mtk_pltform = { .probe = ufs_mtk_probe, - .remove_new = ufs_mtk_remove, + .remove = ufs_mtk_remove, .driver = { .name = "ufshcd-mtk", .pm = &ufs_mtk_pm_ops, diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index ecdfff2456e31d..68040b2ab5f827 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -828,12 +828,28 @@ static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME) err = ufs_qcom_quirk_host_pa_saveconfigtime(hba); - if (hba->dev_info.wmanufacturerid == UFS_VENDOR_WDC) - hba->dev_quirks |= UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE; - return err; } +/* UFS device-specific quirks */ +static struct ufs_dev_quirk ufs_qcom_dev_fixups[] = { + { .wmanufacturerid = UFS_VENDOR_SKHYNIX, + .model = UFS_ANY_MODEL, + .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM }, + { .wmanufacturerid = UFS_VENDOR_TOSHIBA, + .model = UFS_ANY_MODEL, + .quirk = UFS_DEVICE_QUIRK_DELAY_AFTER_LPM }, + { .wmanufacturerid = UFS_VENDOR_WDC, + .model = UFS_ANY_MODEL, + .quirk = UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE }, + {} +}; + +static void ufs_qcom_fixup_dev_quirks(struct ufs_hba *hba) +{ + ufshcd_fixup_dev_quirks(hba, ufs_qcom_dev_fixups); +} + static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) { return ufshci_version(2, 0); @@ -858,7 +874,8 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) if (host->hw_ver.major > 0x3) hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; - if (of_device_is_compatible(hba->dev->of_node, "qcom,sm8550-ufshc")) + if (of_device_is_compatible(hba->dev->of_node, "qcom,sm8550-ufshc") || + of_device_is_compatible(hba->dev->of_node, "qcom,sm8650-ufshc")) hba->quirks |= UFSHCD_QUIRK_BROKEN_LSDBS_CAP; } @@ -1801,6 +1818,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .link_startup_notify = ufs_qcom_link_startup_notify, .pwr_change_notify = ufs_qcom_pwr_change_notify, .apply_dev_quirks = ufs_qcom_apply_dev_quirks, + .fixup_dev_quirks = ufs_qcom_fixup_dev_quirks, .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, .dbg_register_dump = ufs_qcom_dump_dbg_regs, @@ -1843,10 +1861,11 @@ static int ufs_qcom_probe(struct platform_device *pdev) static void ufs_qcom_remove(struct platform_device *pdev) { struct ufs_hba *hba = platform_get_drvdata(pdev); + struct ufs_qcom_host *host = ufshcd_get_variant(hba); - pm_runtime_get_sync(&(pdev)->dev); - ufshcd_remove(hba); - platform_device_msi_free_irqs_all(hba->dev); + ufshcd_pltfrm_remove(pdev); + if (host->esi_enabled) + platform_device_msi_free_irqs_all(hba->dev); } static const struct of_device_id ufs_qcom_of_match[] __maybe_unused = { @@ -1879,7 +1898,7 @@ static const struct dev_pm_ops ufs_qcom_pm_ops = { static struct platform_driver ufs_qcom_pltform = { .probe = ufs_qcom_probe, - .remove_new = ufs_qcom_remove, + .remove = ufs_qcom_remove, .driver = { .name = "ufshcd-qcom", .pm = &ufs_qcom_pm_ops, diff --git a/drivers/ufs/host/ufs-renesas.c b/drivers/ufs/host/ufs-renesas.c index 8711e5cbc9680a..03cd82db751b01 100644 --- a/drivers/ufs/host/ufs-renesas.c +++ b/drivers/ufs/host/ufs-renesas.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -364,14 +365,20 @@ static int ufs_renesas_init(struct ufs_hba *hba) return -ENOMEM; ufshcd_set_variant(hba, priv); - hba->quirks |= UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS | UFSHCD_QUIRK_HIBERN_FASTAUTO; + hba->quirks |= UFSHCD_QUIRK_HIBERN_FASTAUTO; return 0; } +static int ufs_renesas_set_dma_mask(struct ufs_hba *hba) +{ + return dma_set_mask_and_coherent(hba->dev, DMA_BIT_MASK(32)); +} + static const struct ufs_hba_variant_ops ufs_renesas_vops = { .name = "renesas", .init = ufs_renesas_init, + .set_dma_mask = ufs_renesas_set_dma_mask, .setup_clocks = ufs_renesas_setup_clocks, .hce_enable_notify = ufs_renesas_hce_enable_notify, .dbg_register_dump = ufs_renesas_dbg_register_dump, @@ -390,14 +397,12 @@ static int ufs_renesas_probe(struct platform_device *pdev) static void ufs_renesas_remove(struct platform_device *pdev) { - struct ufs_hba *hba = platform_get_drvdata(pdev); - - ufshcd_remove(hba); + ufshcd_pltfrm_remove(pdev); } static struct platform_driver ufs_renesas_platform = { .probe = ufs_renesas_probe, - .remove_new = ufs_renesas_remove, + .remove = ufs_renesas_remove, .driver = { .name = "ufshcd-renesas", .of_match_table = of_match_ptr(ufs_renesas_of_match), diff --git a/drivers/ufs/host/ufs-sprd.c b/drivers/ufs/host/ufs-sprd.c index d8b165908809d6..b1d532363f9d49 100644 --- a/drivers/ufs/host/ufs-sprd.c +++ b/drivers/ufs/host/ufs-sprd.c @@ -427,10 +427,7 @@ static int ufs_sprd_probe(struct platform_device *pdev) static void ufs_sprd_remove(struct platform_device *pdev) { - struct ufs_hba *hba = platform_get_drvdata(pdev); - - pm_runtime_get_sync(&(pdev)->dev); - ufshcd_remove(hba); + ufshcd_pltfrm_remove(pdev); } static const struct dev_pm_ops ufs_sprd_pm_ops = { @@ -442,7 +439,7 @@ static const struct dev_pm_ops ufs_sprd_pm_ops = { static struct platform_driver ufs_sprd_pltform = { .probe = ufs_sprd_probe, - .remove_new = ufs_sprd_remove, + .remove = ufs_sprd_remove, .driver = { .name = "ufshcd-sprd", .pm = &ufs_sprd_pm_ops, diff --git a/drivers/ufs/host/ufshcd-pci.c b/drivers/ufs/host/ufshcd-pci.c index 54e0cc0653a247..ea39c5d5b8cf15 100644 --- a/drivers/ufs/host/ufshcd-pci.c +++ b/drivers/ufs/host/ufshcd-pci.c @@ -588,14 +588,12 @@ ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); - err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD); - if (err < 0) { + mmio_base = pcim_iomap_region(pdev, 0, UFSHCD); + if (IS_ERR(mmio_base)) { dev_err(&pdev->dev, "request and iomap failed\n"); - return err; + return PTR_ERR(mmio_base); } - mmio_base = pcim_iomap_table(pdev)[0]; - err = ufshcd_alloc_host(&pdev->dev, &hba); if (err) { dev_err(&pdev->dev, "Allocation failed\n"); diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index 1f4f30d6cb4234..505572d4fa878c 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -524,6 +524,22 @@ int ufshcd_pltfrm_init(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init); +/** + * ufshcd_pltfrm_remove - Remove ufshcd platform + * @pdev: pointer to Platform device handle + */ +void ufshcd_pltfrm_remove(struct platform_device *pdev) +{ + struct ufs_hba *hba = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + ufshcd_remove(hba); + ufshcd_dealloc_host(hba); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); +} +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_remove); + MODULE_AUTHOR("Santosh Yaragnavi "); MODULE_AUTHOR("Vinayak Holikatti "); MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver"); diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h index df387be5216bd4..3017f8e8f93c67 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.h +++ b/drivers/ufs/host/ufshcd-pltfrm.h @@ -31,6 +31,7 @@ int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params, void ufshcd_init_host_params(struct ufs_host_params *host_params); int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops); +void ufshcd_pltfrm_remove(struct platform_device *pdev); int ufshcd_populate_vreg(struct device *dev, const char *name, struct ufs_vreg **out_vreg, bool skip_current); diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c index 13cc35ab5d29a7..c70dd81bfc61fd 100644 --- a/drivers/uio/uio_dmem_genirq.c +++ b/drivers/uio/uio_dmem_genirq.c @@ -210,8 +210,6 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev) } if (uioinfo->irq) { - struct irq_data *irq_data = irq_get_irq_data(uioinfo->irq); - /* * If a level interrupt, dont do lazy disable. Otherwise the * irq will fire again since clearing of the actual cause, on @@ -219,8 +217,7 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev) * irqd_is_level_type() isn't used since isn't valid until * irq is configured. */ - if (irq_data && - irqd_get_trigger_type(irq_data) & IRQ_TYPE_LEVEL_MASK) { + if (irq_get_trigger_type(uioinfo->irq) & IRQ_TYPE_LEVEL_MASK) { dev_dbg(&pdev->dev, "disable lazy unmask\n"); irq_set_status_flags(uioinfo->irq, IRQ_DISABLE_UNLAZY); } diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c index 496caff66e7ea1..81454c3e2484c8 100644 --- a/drivers/uio/uio_fsl_elbc_gpcm.c +++ b/drivers/uio/uio_fsl_elbc_gpcm.c @@ -453,7 +453,7 @@ static struct platform_driver uio_fsl_elbc_gpcm_driver = { .dev_groups = uio_fsl_elbc_gpcm_groups, }, .probe = uio_fsl_elbc_gpcm_probe, - .remove_new = uio_fsl_elbc_gpcm_remove, + .remove = uio_fsl_elbc_gpcm_remove, }; module_platform_driver(uio_fsl_elbc_gpcm_driver); diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 8704095994118c..3976360d0096d6 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -135,7 +135,7 @@ static void hv_uio_rescind(struct vmbus_channel *channel) * The ring buffer is allocated as contiguous memory by vmbus_open */ static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, + const struct bin_attribute *attr, struct vm_area_struct *vma) { struct vmbus_channel *channel diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 796f5be0a086a5..2ec7d25e826490 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -173,8 +173,6 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) } if (uioinfo->irq) { - struct irq_data *irq_data = irq_get_irq_data(uioinfo->irq); - /* * If a level interrupt, dont do lazy disable. Otherwise the * irq will fire again since clearing of the actual cause, on @@ -182,8 +180,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) * irqd_is_level_type() isn't used since isn't valid until * irq is configured. */ - if (irq_data && - irqd_get_trigger_type(irq_data) & IRQ_TYPE_LEVEL_MASK) { + if (irq_get_trigger_type(uioinfo->irq) & IRQ_TYPE_LEVEL_MASK) { dev_dbg(&pdev->dev, "disable lazy unmask\n"); irq_set_status_flags(uioinfo->irq, IRQ_DISABLE_UNLAZY); } diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index e8e43c38aa1b43..cd0f7b4bd82ab1 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -808,7 +808,7 @@ static int check_dsp_e4(const u8 *dsp, int len) if (l > len) return 1; - /* zero is zero regardless endianes */ + /* zero is zero regardless endianness */ } while (blockidx->NotLastBlock); } @@ -1276,7 +1276,7 @@ static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) sc->stats.phy.dsrate == dsrate) return; - /* Original timming (1Mbit/s) from ADI (used in windows driver) */ + /* Original timing (1Mbit/s) from ADI (used in windows driver) */ timeout = (dsrate <= 1024*1024) ? 0 : 1; ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n", @@ -1972,7 +1972,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) if (cmv->bDirection != E1_MODEMTOHOST) goto bad1; - /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to + /* FIXME : ADI930 reply wrong preamble (func = 2, sub = 2) to * the first MEMACCESS cmv. Ignore it... */ if (cmv->bFunction != dsc->function) { diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 2da6615fbb6f4e..d1e622bb140622 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1158,7 +1158,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, if (i >= num_rcv_urbs) list_add_tail(&urb->urb_list, &channel->list); - vdbg(&intf->dev, "%s: alloced buffer 0x%p buf size %u urb 0x%p", + vdbg(&intf->dev, "%s: allocated buffer 0x%p buf size %u urb 0x%p", __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb); } diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c index bb9d5d7ffefc54..8f38e2c5369a1f 100644 --- a/drivers/usb/c67x00/c67x00-drv.c +++ b/drivers/usb/c67x00/c67x00-drv.c @@ -201,7 +201,7 @@ static void c67x00_drv_remove(struct platform_device *pdev) static struct platform_driver c67x00_driver = { .probe = c67x00_drv_probe, - .remove_new = c67x00_drv_remove, + .remove = c67x00_drv_remove, .driver = { .name = "c67x00", }, diff --git a/drivers/usb/cdns3/cdns3-imx.c b/drivers/usb/cdns3/cdns3-imx.c index 281de47e2a3b12..a2f041e1707c0d 100644 --- a/drivers/usb/cdns3/cdns3-imx.c +++ b/drivers/usb/cdns3/cdns3-imx.c @@ -422,7 +422,7 @@ MODULE_DEVICE_TABLE(of, cdns_imx_of_match); static struct platform_driver cdns_imx_driver = { .probe = cdns_imx_probe, - .remove_new = cdns_imx_remove, + .remove = cdns_imx_remove, .driver = { .name = "cdns3-imx", .of_match_table = cdns_imx_of_match, diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c index 591d149de8f3d9..3b3b3dc75f3590 100644 --- a/drivers/usb/cdns3/cdns3-pci-wrap.c +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c @@ -37,8 +37,6 @@ struct cdns3_wrap { #define PCI_DRIVER_NAME "cdns3-pci-usbss" #define PLAT_DRIVER_NAME "cdns-usb3" -#define PCI_DEVICE_ID_CDNS_USB3 0x0100 - static struct pci_dev *cdns3_get_second_fun(struct pci_dev *pdev) { struct pci_dev *func; @@ -189,7 +187,7 @@ static void cdns3_pci_remove(struct pci_dev *pdev) } static const struct pci_device_id cdns3_pci_ids[] = { - { PCI_VDEVICE(CDNS, PCI_DEVICE_ID_CDNS_USB3) }, + { PCI_VDEVICE(CDNS, PCI_DEVICE_ID_CDNS_USBSS) }, { 0, } }; diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c index 3ef8e3c872a37e..59ec505e198a4b 100644 --- a/drivers/usb/cdns3/cdns3-plat.c +++ b/drivers/usb/cdns3/cdns3-plat.c @@ -327,7 +327,7 @@ MODULE_DEVICE_TABLE(of, of_cdns3_match); static struct platform_driver cdns3_driver = { .probe = cdns3_plat_probe, - .remove_new = cdns3_plat_remove, + .remove = cdns3_plat_remove, .driver = { .name = "cdns-usb3", .of_match_table = of_match_ptr(of_cdns3_match), diff --git a/drivers/usb/cdns3/cdns3-starfive.c b/drivers/usb/cdns3/cdns3-starfive.c index c04d196abd8782..2ff7f2b48cc2b7 100644 --- a/drivers/usb/cdns3/cdns3-starfive.c +++ b/drivers/usb/cdns3/cdns3-starfive.c @@ -230,7 +230,7 @@ MODULE_DEVICE_TABLE(of, cdns_starfive_of_match); static struct platform_driver cdns_starfive_driver = { .probe = cdns_starfive_probe, - .remove_new = cdns_starfive_remove, + .remove = cdns_starfive_remove, .driver = { .name = "cdns3-starfive", .of_match_table = cdns_starfive_of_match, diff --git a/drivers/usb/cdns3/cdns3-ti.c b/drivers/usb/cdns3/cdns3-ti.c index cfabc12ee0e3c0..040bb91e9c017d 100644 --- a/drivers/usb/cdns3/cdns3-ti.c +++ b/drivers/usb/cdns3/cdns3-ti.c @@ -233,7 +233,7 @@ MODULE_DEVICE_TABLE(of, cdns_ti_of_match); static struct platform_driver cdns_ti_driver = { .probe = cdns_ti_probe, - .remove_new = cdns_ti_remove, + .remove = cdns_ti_remove, .driver = { .name = "cdns3-ti", .of_match_table = cdns_ti_of_match, diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c index 2d05368a6745a1..a51144504ff337 100644 --- a/drivers/usb/cdns3/cdnsp-pci.c +++ b/drivers/usb/cdns3/cdnsp-pci.c @@ -28,12 +28,6 @@ #define PCI_DRIVER_NAME "cdns-pci-usbssp" #define PLAT_DRIVER_NAME "cdns-usbssp" -#define PCI_DEVICE_ID_CDNS_USB3 0x0100 -#define PCI_DEVICE_ID_CDNS_UDC 0x0200 - -#define PCI_CLASS_SERIAL_USB_CDNS_USB3 (PCI_CLASS_SERIAL_USB << 8 | 0x80) -#define PCI_CLASS_SERIAL_USB_CDNS_UDC PCI_CLASS_SERIAL_USB_DEVICE - static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev) { /* @@ -41,10 +35,10 @@ static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev) * Platform has two function. The fist keeps resources for * Host/Device while the secon keeps resources for DRD/OTG. */ - if (pdev->device == PCI_DEVICE_ID_CDNS_UDC) - return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USB3, NULL); - if (pdev->device == PCI_DEVICE_ID_CDNS_USB3) - return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_UDC, NULL); + if (pdev->device == PCI_DEVICE_ID_CDNS_USBSSP) + return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USBSS, NULL); + if (pdev->device == PCI_DEVICE_ID_CDNS_USBSS) + return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USBSSP, NULL); return NULL; } @@ -221,12 +215,12 @@ static const struct dev_pm_ops cdnsp_pci_pm_ops = { }; static const struct pci_device_id cdnsp_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_UDC), - .class = PCI_CLASS_SERIAL_USB_CDNS_UDC }, - { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_UDC), - .class = PCI_CLASS_SERIAL_USB_CDNS_USB3 }, - { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB3), - .class = PCI_CLASS_SERIAL_USB_CDNS_USB3 }, + { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSSP), + .class = PCI_CLASS_SERIAL_USB_DEVICE }, + { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSSP), + .class = PCI_CLASS_SERIAL_USB_CDNS }, + { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USBSS), + .class = PCI_CLASS_SERIAL_USB_CDNS }, { 0, } }; diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 2a38e1eb65466c..97437de52ef681 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -25,6 +25,7 @@ #define TD_PAGE_COUNT 5 #define CI_HDRC_PAGE_SIZE 4096ul /* page size for TD's */ #define ENDPT_MAX 32 +#define CI_MAX_REQ_SIZE (4 * CI_HDRC_PAGE_SIZE) #define CI_MAX_BUF_SIZE (TD_PAGE_COUNT * CI_HDRC_PAGE_SIZE) /****************************************************************************** @@ -260,6 +261,7 @@ struct ci_hdrc { bool b_sess_valid_event; bool imx28_write_fix; bool has_portsc_pec_bug; + bool has_short_pkt_limit; bool supports_runtime_pm; bool in_lpm; bool wakeup_int; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index c64ab0e07ea030..f2801700be8ec1 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -342,6 +342,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) struct ci_hdrc_platform_data pdata = { .name = dev_name(&pdev->dev), .capoffset = DEF_CAPOFFSET, + .flags = CI_HDRC_HAS_SHORT_PKT_LIMIT, .notify_event = ci_hdrc_imx_notify_event, }; int ret; @@ -675,7 +676,7 @@ static const struct dev_pm_ops ci_hdrc_imx_pm_ops = { }; static struct platform_driver ci_hdrc_imx_driver = { .probe = ci_hdrc_imx_probe, - .remove_new = ci_hdrc_imx_remove, + .remove = ci_hdrc_imx_remove, .shutdown = ci_hdrc_imx_shutdown, .driver = { .name = "imx_usb", diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 1661639cd2ebb7..3ab3daa78e3401 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -292,7 +292,7 @@ MODULE_DEVICE_TABLE(of, msm_ci_dt_match); static struct platform_driver ci_hdrc_msm_driver = { .probe = ci_hdrc_msm_probe, - .remove_new = ci_hdrc_msm_remove, + .remove = ci_hdrc_msm_remove, .driver = { .name = "msm_hsusb", .of_match_table = msm_ci_dt_match, diff --git a/drivers/usb/chipidea/ci_hdrc_npcm.c b/drivers/usb/chipidea/ci_hdrc_npcm.c index 3e5e05dbda8904..e52a2b05cbe2ae 100644 --- a/drivers/usb/chipidea/ci_hdrc_npcm.c +++ b/drivers/usb/chipidea/ci_hdrc_npcm.c @@ -98,7 +98,7 @@ MODULE_DEVICE_TABLE(of, npcm_udc_dt_match); static struct platform_driver npcm_udc_driver = { .probe = npcm_udc_probe, - .remove_new = npcm_udc_remove, + .remove = npcm_udc_remove, .driver = { .name = "npcm_udc", .of_match_table = npcm_udc_dt_match, diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 9538d425f0a02a..372788f0f97014 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -406,7 +406,7 @@ static struct platform_driver tegra_usb_driver = { .pm = pm_ptr(&tegra_usb_pm), }, .probe = tegra_usb_probe, - .remove_new = tegra_usb_remove, + .remove = tegra_usb_remove, }; module_platform_driver(tegra_usb_driver); diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index 97379f653b0629..8ffa1e95d8e860 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -116,7 +116,7 @@ static void ci_hdrc_usb2_remove(struct platform_device *pdev) static struct platform_driver ci_hdrc_usb2_driver = { .probe = ci_hdrc_usb2_probe, - .remove_new = ci_hdrc_usb2_remove, + .remove = ci_hdrc_usb2_remove, .driver = { .name = "chipidea-usb2", .of_match_table = ci_hdrc_usb2_of_match, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 835bf2428dc6ec..694b4a8e4e1d85 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -765,7 +765,7 @@ static int ci_get_platdata(struct device *dev, ext_id = ERR_PTR(-ENODEV); ext_vbus = ERR_PTR(-ENODEV); - if (of_property_read_bool(dev->of_node, "extcon")) { + if (of_property_present(dev->of_node, "extcon")) { /* Each one of them is not mandatory */ ext_vbus = extcon_get_edev_by_phandle(dev, 0); if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV) @@ -1076,6 +1076,8 @@ static int ci_hdrc_probe(struct platform_device *pdev) CI_HDRC_SUPPORTS_RUNTIME_PM); ci->has_portsc_pec_bug = !!(ci->platdata->flags & CI_HDRC_HAS_PORTSC_PEC_MISSED); + ci->has_short_pkt_limit = !!(ci->platdata->flags & + CI_HDRC_HAS_SHORT_PKT_LIMIT); platform_set_drvdata(pdev, ci); ret = hw_device_init(ci, base); @@ -1495,7 +1497,7 @@ static const struct dev_pm_ops ci_pm_ops = { static struct platform_driver ci_hdrc_driver = { .probe = ci_hdrc_probe, - .remove_new = ci_hdrc_remove, + .remove = ci_hdrc_remove, .driver = { .name = "ci_hdrc", .pm = &ci_pm_ops, diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 69ef3cd8d4f836..8a9b31fd5c89d8 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -540,6 +541,126 @@ static int prepare_td_for_sg(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) return ret; } +/* + * Verify if the scatterlist is valid by iterating each sg entry. + * Return invalid sg entry index which is less than num_sgs. + */ +static int sglist_get_invalid_entry(struct device *dma_dev, u8 dir, + struct usb_request *req) +{ + int i; + struct scatterlist *s = req->sg; + + if (req->num_sgs == 1) + return 1; + + dir = dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + for (i = 0; i < req->num_sgs; i++, s = sg_next(s)) { + /* Only small sg (generally last sg) may be bounced. If + * that happens. we can't ensure the addr is page-aligned + * after dma map. + */ + if (dma_kmalloc_needs_bounce(dma_dev, s->length, dir)) + break; + + /* Make sure each sg start address (except first sg) is + * page-aligned and end address (except last sg) is also + * page-aligned. + */ + if (i == 0) { + if (!IS_ALIGNED(s->offset + s->length, + CI_HDRC_PAGE_SIZE)) + break; + } else { + if (s->offset) + break; + if (!sg_is_last(s) && !IS_ALIGNED(s->length, + CI_HDRC_PAGE_SIZE)) + break; + } + } + + return i; +} + +static int sglist_do_bounce(struct ci_hw_req *hwreq, int index, + bool copy, unsigned int *bounced) +{ + void *buf; + int i, ret, nents, num_sgs; + unsigned int rest, rounded; + struct scatterlist *sg, *src, *dst; + + nents = index + 1; + ret = sg_alloc_table(&hwreq->sgt, nents, GFP_KERNEL); + if (ret) + return ret; + + sg = src = hwreq->req.sg; + num_sgs = hwreq->req.num_sgs; + rest = hwreq->req.length; + dst = hwreq->sgt.sgl; + + for (i = 0; i < index; i++) { + memcpy(dst, src, sizeof(*src)); + rest -= src->length; + src = sg_next(src); + dst = sg_next(dst); + } + + /* create one bounce buffer */ + rounded = round_up(rest, CI_HDRC_PAGE_SIZE); + buf = kmalloc(rounded, GFP_KERNEL); + if (!buf) { + sg_free_table(&hwreq->sgt); + return -ENOMEM; + } + + sg_set_buf(dst, buf, rounded); + + hwreq->req.sg = hwreq->sgt.sgl; + hwreq->req.num_sgs = nents; + hwreq->sgt.sgl = sg; + hwreq->sgt.nents = num_sgs; + + if (copy) + sg_copy_to_buffer(src, num_sgs - index, buf, rest); + + *bounced = rest; + + return 0; +} + +static void sglist_do_debounce(struct ci_hw_req *hwreq, bool copy) +{ + void *buf; + int i, nents, num_sgs; + struct scatterlist *sg, *src, *dst; + + sg = hwreq->req.sg; + num_sgs = hwreq->req.num_sgs; + src = sg_last(sg, num_sgs); + buf = sg_virt(src); + + if (copy) { + dst = hwreq->sgt.sgl; + for (i = 0; i < num_sgs - 1; i++) + dst = sg_next(dst); + + nents = hwreq->sgt.nents - num_sgs + 1; + sg_copy_from_buffer(dst, nents, buf, sg_dma_len(src)); + } + + hwreq->req.sg = hwreq->sgt.sgl; + hwreq->req.num_sgs = hwreq->sgt.nents; + hwreq->sgt.sgl = sg; + hwreq->sgt.nents = num_sgs; + + kfree(buf); + sg_free_table(&hwreq->sgt); +} + /** * _hardware_enqueue: configures a request at hardware level * @hwep: endpoint @@ -552,6 +673,8 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) struct ci_hdrc *ci = hwep->ci; int ret = 0; struct td_node *firstnode, *lastnode; + unsigned int bounced_size; + struct scatterlist *sg; /* don't queue twice */ if (hwreq->req.status == -EALREADY) @@ -559,11 +682,29 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) hwreq->req.status = -EALREADY; + if (hwreq->req.num_sgs && hwreq->req.length && + ci->has_short_pkt_limit) { + ret = sglist_get_invalid_entry(ci->dev->parent, hwep->dir, + &hwreq->req); + if (ret < hwreq->req.num_sgs) { + ret = sglist_do_bounce(hwreq, ret, hwep->dir == TX, + &bounced_size); + if (ret) + return ret; + } + } + ret = usb_gadget_map_request_by_dev(ci->dev->parent, &hwreq->req, hwep->dir); if (ret) return ret; + if (hwreq->sgt.sgl) { + /* We've mapped a bigger buffer, now recover the actual size */ + sg = sg_last(hwreq->req.sg, hwreq->req.num_sgs); + sg_dma_len(sg) = min(sg_dma_len(sg), bounced_size); + } + if (hwreq->req.num_mapped_sgs) ret = prepare_td_for_sg(hwep, hwreq); else @@ -612,10 +753,17 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) do { hw_write(ci, OP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW); tmp_stat = hw_read(ci, OP_ENDPTSTAT, BIT(n)); - } while (!hw_read(ci, OP_USBCMD, USBCMD_ATDTW)); + } while (!hw_read(ci, OP_USBCMD, USBCMD_ATDTW) && tmp_stat); hw_write(ci, OP_USBCMD, USBCMD_ATDTW, 0); if (tmp_stat) goto done; + + /* OP_ENDPTSTAT will be clear by HW when the endpoint met + * err. This dTD don't push to dQH if current dTD point is + * not the last one in previous request. + */ + if (hwep->qh.ptr->curr != cpu_to_le32(prevlastnode->dma)) + goto done; } /* QH configuration */ @@ -676,6 +824,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) unsigned remaining_length; unsigned actual = hwreq->req.length; struct ci_hdrc *ci = hwep->ci; + bool is_isoc = hwep->type == USB_ENDPOINT_XFER_ISOC; if (hwreq->req.status != -EALREADY) return -EINVAL; @@ -689,7 +838,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) int n = hw_ep_bit(hwep->num, hwep->dir); if (ci->rev == CI_REVISION_24 || - ci->rev == CI_REVISION_22) + ci->rev == CI_REVISION_22 || is_isoc) if (!hw_read(ci, OP_ENDPTSTAT, BIT(n))) reprime_dtd(ci, hwep, node); hwreq->req.status = -EALREADY; @@ -708,11 +857,15 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) hwreq->req.status = -EPROTO; break; } else if ((TD_STATUS_TR_ERR & hwreq->req.status)) { - hwreq->req.status = -EILSEQ; - break; + if (is_isoc) { + hwreq->req.status = 0; + } else { + hwreq->req.status = -EILSEQ; + break; + } } - if (remaining_length) { + if (remaining_length && !is_isoc) { if (hwep->dir == TX) { hwreq->req.status = -EPROTO; break; @@ -733,6 +886,10 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) usb_gadget_unmap_request_by_dev(hwep->ci->dev->parent, &hwreq->req, hwep->dir); + /* sglist bounced */ + if (hwreq->sgt.sgl) + sglist_do_debounce(hwreq, hwep->dir == RX); + hwreq->req.actual += actual; if (hwreq->req.status) @@ -960,6 +1117,12 @@ static int _ep_queue(struct usb_ep *ep, struct usb_request *req, return -EMSGSIZE; } + if (ci->has_short_pkt_limit && + hwreq->req.length > CI_MAX_REQ_SIZE) { + dev_err(hwep->ci->dev, "request length too big (max 16KB)\n"); + return -EMSGSIZE; + } + /* first nuke then test link, e.g. previous status has not sent */ if (!list_empty(&hwreq->queue)) { dev_err(hwep->ci->dev, "request already in queue\n"); @@ -1574,6 +1737,9 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) usb_gadget_unmap_request(&hwep->ci->gadget, req, hwep->dir); + if (hwreq->sgt.sgl) + sglist_do_debounce(hwreq, false); + req->status = -ECONNRESET; if (hwreq->req.complete != NULL) { @@ -2063,7 +2229,7 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci) } } - if (USBi_UI & intr) + if ((USBi_UI | USBi_UEI) & intr) isr_tr_complete_handler(ci); if ((USBi_SLI & intr) && !(ci->suspended)) { diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h index 5193df1e18c75b..c8a47389a46bbb 100644 --- a/drivers/usb/chipidea/udc.h +++ b/drivers/usb/chipidea/udc.h @@ -69,11 +69,13 @@ struct td_node { * @req: request structure for gadget drivers * @queue: link to QH list * @tds: link to TD list + * @sgt: hold original sglist when bounce sglist */ struct ci_hw_req { struct usb_request req; struct list_head queue; struct list_head tds; + struct sg_table sgt; }; #ifdef CONFIG_USB_CHIPIDEA_UDC diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 173c78afd50227..1394881fde5f5b 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -1285,6 +1285,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = { .compatible = "fsl,imx7ulp-usbmisc", .data = &imx7ulp_usbmisc_ops, }, + { + .compatible = "fsl,imx8ulp-usbmisc", + .data = &imx7ulp_usbmisc_ops, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index b7bea1015d7c1d..871cf199b6bf17 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -415,6 +415,9 @@ EXPORT_SYMBOL_GPL(usb_of_get_companion_dev); struct dentry *usb_debug_root; EXPORT_SYMBOL_GPL(usb_debug_root); +DEFINE_MUTEX(usb_dynids_lock); +EXPORT_SYMBOL_GPL(usb_dynids_lock); + static int __init usb_common_init(void) { usb_debug_root = debugfs_create_dir("usb", NULL); diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index 501e8bc9738eba..c84b4a70008460 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -340,7 +340,7 @@ MODULE_DEVICE_TABLE(of, usb_conn_dt_match); static struct platform_driver usb_conn_driver = { .probe = usb_conn_probe, - .remove_new = usb_conn_remove, + .remove = usb_conn_remove, .driver = { .name = "usb-conn-gpio", .pm = &usb_conn_pm_ops, diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 880d52c0949d47..25a00f974934fb 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -924,7 +924,7 @@ int usb_get_configuration(struct usb_device *dev) result = -EINVAL; goto err; } - length = max((int) le16_to_cpu(desc->wTotalLength), + length = max_t(int, le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE); /* Now that we know the length, get the whole thing */ diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3beb6a862e8084..f6ce6e26e0d45f 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -238,6 +238,9 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma) dma_addr_t dma_handle = DMA_MAPPING_ERROR; int ret; + if (!(file->f_mode & FMODE_WRITE)) + return -EPERM; + ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory)); if (ret) goto error; @@ -1295,7 +1298,7 @@ static int do_proc_bulk(struct usb_dev_state *ps, return ret; len1 = bulk->len; - if (len1 < 0 || len1 >= (INT_MAX - sizeof(struct urb))) + if (len1 >= (INT_MAX - sizeof(struct urb))) return -EINVAL; if (bulk->ep & USB_DIR_IN) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 0c3f12daac79e0..f203fdbfb6f68e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -95,9 +95,9 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, } } - spin_lock(&dynids->lock); + mutex_lock(&usb_dynids_lock); list_add_tail(&dynid->node, &dynids->list); - spin_unlock(&dynids->lock); + mutex_unlock(&usb_dynids_lock); retval = driver_attach(driver); @@ -116,6 +116,7 @@ ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf) struct usb_dynid *dynid; size_t count = 0; + guard(mutex)(&usb_dynids_lock); list_for_each_entry(dynid, &dynids->list, node) if (dynid->id.bInterfaceClass != 0) count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n", @@ -160,7 +161,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf, if (fields < 2) return -EINVAL; - spin_lock(&usb_driver->dynids.lock); + guard(mutex)(&usb_dynids_lock); list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) { struct usb_device_id *id = &dynid->id; @@ -171,7 +172,6 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf, break; } } - spin_unlock(&usb_driver->dynids.lock); return count; } @@ -220,27 +220,24 @@ static void usb_free_dynids(struct usb_driver *usb_drv) { struct usb_dynid *dynid, *n; - spin_lock(&usb_drv->dynids.lock); + guard(mutex)(&usb_dynids_lock); list_for_each_entry_safe(dynid, n, &usb_drv->dynids.list, node) { list_del(&dynid->node); kfree(dynid); } - spin_unlock(&usb_drv->dynids.lock); } static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf, - struct usb_driver *drv) + const struct usb_driver *drv) { struct usb_dynid *dynid; - spin_lock(&drv->dynids.lock); + guard(mutex)(&usb_dynids_lock); list_for_each_entry(dynid, &drv->dynids.list, node) { if (usb_match_one_id(intf, &dynid->id)) { - spin_unlock(&drv->dynids.lock); return &dynid->id; } } - spin_unlock(&drv->dynids.lock); return NULL; } @@ -853,7 +850,7 @@ const struct usb_device_id *usb_device_match_id(struct usb_device *udev, EXPORT_SYMBOL_GPL(usb_device_match_id); bool usb_driver_applicable(struct usb_device *udev, - struct usb_device_driver *udrv) + const struct usb_device_driver *udrv) { if (udrv->id_table && udrv->match) return usb_device_match_id(udev, udrv->id_table) != NULL && @@ -873,7 +870,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv) /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { struct usb_device *udev; - struct usb_device_driver *udrv; + const struct usb_device_driver *udrv; /* interface drivers never match devices */ if (!is_usb_device_driver(drv)) @@ -893,7 +890,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv) } else if (is_usb_interface(dev)) { struct usb_interface *intf; - struct usb_driver *usb_drv; + const struct usb_driver *usb_drv; const struct usb_device_id *id; /* device drivers never match interfaces */ @@ -1076,7 +1073,6 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, new_driver->driver.owner = owner; new_driver->driver.mod_name = mod_name; new_driver->driver.dev_groups = new_driver->dev_groups; - spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); retval = driver_register(&new_driver->driver); diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 4b38b87a13438d..e4839940160877 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "usb.h" @@ -39,7 +40,7 @@ static ssize_t field##_show(struct device *dev, \ char *buf) \ { \ struct ep_device *ep = to_ep_device(dev); \ - return sprintf(buf, format_string, ep->desc->field); \ + return sysfs_emit(buf, format_string, ep->desc->field); \ } \ static DEVICE_ATTR_RO(field) @@ -52,7 +53,7 @@ static ssize_t wMaxPacketSize_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ep_device *ep = to_ep_device(dev); - return sprintf(buf, "%04x\n", usb_endpoint_maxp(ep->desc)); + return sysfs_emit(buf, "%04x\n", usb_endpoint_maxp(ep->desc)); } static DEVICE_ATTR_RO(wMaxPacketSize); @@ -76,7 +77,7 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr, type = "Interrupt"; break; } - return sprintf(buf, "%s\n", type); + return sysfs_emit(buf, "%s\n", type); } static DEVICE_ATTR_RO(type); @@ -95,7 +96,7 @@ static ssize_t interval_show(struct device *dev, struct device_attribute *attr, interval /= 1000; } - return sprintf(buf, "%d%cs\n", interval, unit); + return sysfs_emit(buf, "%d%cs\n", interval, unit); } static DEVICE_ATTR_RO(interval); @@ -111,7 +112,7 @@ static ssize_t direction_show(struct device *dev, struct device_attribute *attr, direction = "in"; else direction = "out"; - return sprintf(buf, "%s\n", direction); + return sysfs_emit(buf, "%s\n", direction); } static DEVICE_ATTR_RO(direction); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 500dc35e64774d..0b2490347b9fe7 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2794,8 +2794,14 @@ int usb_add_hcd(struct usb_hcd *hcd, int retval; struct usb_device *rhdev; struct usb_hcd *shared_hcd; + int skip_phy_initialization; - if (!hcd->skip_phy_initialization) { + if (usb_hcd_is_primary_hcd(hcd)) + skip_phy_initialization = hcd->skip_phy_initialization; + else + skip_phy_initialization = hcd->primary_hcd->skip_phy_initialization; + + if (!skip_phy_initialization) { if (usb_hcd_is_primary_hcd(hcd)) { hcd->phy_roothub = usb_phy_roothub_alloc(hcd->self.sysdev); if (IS_ERR(hcd->phy_roothub)) diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index 85c999f71ad7c2..5e3c515991f3f1 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -87,7 +88,7 @@ static ssize_t usbport_trig_port_show(struct device *dev, struct usbport_trig_port, attr); - return sprintf(buf, "%d\n", port->observed) + 1; + return sysfs_emit(buf, "%d\n", port->observed) + 1; } static ssize_t usbport_trig_port_store(struct device *dev, diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index e7da2fca11a48c..45d7af00f8d17e 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -166,7 +167,7 @@ static ssize_t location_show(struct device *dev, { struct usb_port *port_dev = to_usb_port(dev); - return sprintf(buf, "0x%08x\n", port_dev->location); + return sysfs_emit(buf, "0x%08x\n", port_dev->location); } static DEVICE_ATTR_RO(location); @@ -191,7 +192,7 @@ static ssize_t connect_type_show(struct device *dev, break; } - return sprintf(buf, "%s\n", result); + return sysfs_emit(buf, "%s\n", result); } static DEVICE_ATTR_RO(connect_type); @@ -210,7 +211,7 @@ static ssize_t over_current_count_show(struct device *dev, { struct usb_port *port_dev = to_usb_port(dev); - return sprintf(buf, "%u\n", port_dev->over_current_count); + return sysfs_emit(buf, "%u\n", port_dev->over_current_count); } static DEVICE_ATTR_RO(over_current_count); @@ -219,7 +220,7 @@ static ssize_t quirks_show(struct device *dev, { struct usb_port *port_dev = to_usb_port(dev); - return sprintf(buf, "%08x\n", port_dev->quirks); + return sysfs_emit(buf, "%08x\n", port_dev->quirks); } static ssize_t quirks_store(struct device *dev, struct device_attribute *attr, @@ -254,7 +255,7 @@ static ssize_t usb3_lpm_permit_show(struct device *dev, p = "0"; } - return sprintf(buf, "%s\n", p); + return sysfs_emit(buf, "%s\n", p); } static ssize_t usb3_lpm_permit_store(struct device *dev, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 61b6d978892c79..b4cba23831acd2 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -925,7 +925,7 @@ static struct bin_attribute *dev_bin_attrs[] = { }; static umode_t dev_bin_attrs_are_visible(struct kobject *kobj, - struct bin_attribute *a, int n) + const struct bin_attribute *a, int n) { struct device *dev = kobj_to_dev(kobj); struct usb_device *udev = to_usb_device(dev); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index b8324ea05b20fb..a9b37aeb515bef 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -75,7 +75,7 @@ extern int usb_match_device(struct usb_device *dev, extern const struct usb_device_id *usb_device_match_id(struct usb_device *udev, const struct usb_device_id *id); extern bool usb_driver_applicable(struct usb_device *udev, - struct usb_device_driver *udrv); + const struct usb_device_driver *udrv); extern void usb_forced_unbind_intf(struct usb_interface *intf); extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev); diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig index c131719367ecab..d7af55a8eced73 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig @@ -21,7 +21,7 @@ config USB_DWC2 if USB_DWC2 choice - bool "DWC2 Mode Selection" + prompt "DWC2 Mode Selection" default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET) default USB_DWC2_HOST if (USB && !USB_GADGET) default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index cb54390e7de488..8c3941ecaaf5d4 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3546,11 +3546,9 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, port_status |= USB_PORT_STAT_C_OVERCURRENT << 16; } - if (!hsotg->flags.b.port_connect_status) { + if (dwc2_is_device_mode(hsotg)) { /* - * The port is disconnected, which means the core is - * either in device mode or it soon will be. Just - * return 0's for the remainder of the port status + * Just return 0's for the remainder of the port status * since the port register can't be read if the core * is in device mode. */ @@ -3620,13 +3618,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) goto error; - if (!hsotg->flags.b.port_connect_status) { + if (dwc2_is_device_mode(hsotg)) { /* - * The port is disconnected, which means the core is - * either in device mode or it soon will be. Just - * return without doing anything since the port - * register can't be written if the core is in device - * mode. + * Just return 0's for the remainder of the port status + * since the port register can't be read if the core + * is in device mode. */ break; } @@ -4349,7 +4345,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) if (hsotg->bus_suspended) goto skip_power_saving; - if (hsotg->flags.b.port_connect_status == 0) + if (!(dwc2_read_hprt0(hsotg) & HPRT0_CONNSTS)) goto skip_power_saving; switch (hsotg->params.power_down) { @@ -4431,6 +4427,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) * Power Down mode. */ if (hprt0 & HPRT0_CONNSTS) { + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); hsotg->lx_state = DWC2_L0; goto unlock; } diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index c1b7209b94836c..91c80a92d9b8be 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -756,7 +756,7 @@ static struct platform_driver dwc2_platform_driver = { .pm = &dwc2_dev_pm_ops, }, .probe = dwc2_driver_probe, - .remove_new = dwc2_driver_remove, + .remove = dwc2_driver_remove, .shutdown = dwc2_driver_shutdown, }; diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 31078f3d41b88d..310d182e10b50b 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -23,7 +23,7 @@ config USB_DWC3_ULPI controller. choice - bool "DWC3 Mode Selection" + prompt "DWC3 Mode Selection" default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET) default USB_DWC3_HOST if (USB && !USB_GADGET) default USB_DWC3_GADGET if (!USB && USB_GADGET) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 98114c2827c098..f219c82e9619d9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1409,7 +1409,7 @@ static int dwc3_core_init(struct dwc3 *dwc) /* * When configured in HOST mode, after issuing U3/L2 exit controller - * fails to send proper CRC checksum in CRC5 feild. Because of this + * fails to send proper CRC checksum in CRC5 field. Because of this * behaviour Transaction Error is generated, resulting in reset and * re-enumeration of usb device attached. All the termsel, xcvrsel, * opmode becomes 0 during end of resume. Enabling bit 10 of GUCTL1 @@ -1470,9 +1470,13 @@ static int dwc3_core_init(struct dwc3 *dwc) if (hw_mode != DWC3_GHWPARAMS0_MODE_GADGET && (DWC3_IP_IS(DWC31)) && dwc->maximum_speed == USB_SPEED_SUPER) { - reg = dwc3_readl(dwc->regs, DWC3_LLUCTL); - reg |= DWC3_LLUCTL_FORCE_GEN1; - dwc3_writel(dwc->regs, DWC3_LLUCTL, reg); + int i; + + for (i = 0; i < dwc->num_usb3_ports; i++) { + reg = dwc3_readl(dwc->regs, DWC3_LLUCTL(i)); + reg |= DWC3_LLUCTL_FORCE_GEN1; + dwc3_writel(dwc->regs, DWC3_LLUCTL(i), reg); + } } return 0; @@ -1941,7 +1945,7 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) struct extcon_dev *edev = NULL; const char *name; - if (device_property_read_bool(dev, "extcon")) + if (device_property_present(dev, "extcon")) return extcon_get_edev_by_phandle(dev, 0); /* @@ -2651,7 +2655,7 @@ MODULE_DEVICE_TABLE(acpi, dwc3_acpi_match); static struct platform_driver dwc3_driver = { .probe = dwc3_probe, - .remove_new = dwc3_remove, + .remove = dwc3_remove, .driver = { .name = "dwc3", .of_match_table = of_match_ptr(of_dwc3_match), diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index eab81dfdcc3502..ee73789326bc61 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -81,7 +81,7 @@ #define DWC3_GSNPSREV_MASK 0xffff #define DWC3_GSNPS_ID(p) (((p) & DWC3_GSNPSID_MASK) >> 16) -/* DWC3 registers memory space boundries */ +/* DWC3 registers memory space boundaries */ #define DWC3_XHCI_REGS_START 0x0 #define DWC3_XHCI_REGS_END 0x7fff #define DWC3_GLOBALS_REGS_START 0xc100 @@ -179,7 +179,7 @@ #define DWC3_OEVTEN 0xcc0C #define DWC3_OSTS 0xcc10 -#define DWC3_LLUCTL 0xd024 +#define DWC3_LLUCTL(n) (0xd024 + ((n) * 0x80)) /* Bit fields */ @@ -915,6 +915,7 @@ struct dwc3_hwparams { #define DWC3_MODE(n) ((n) & 0x7) /* HWPARAMS1 */ +#define DWC3_SPRAM_TYPE(n) (((n) >> 23) & 1) #define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) /* HWPARAMS3 */ @@ -925,6 +926,9 @@ struct dwc3_hwparams { #define DWC3_NUM_IN_EPS(p) (((p)->hwparams3 & \ (DWC3_NUM_IN_EPS_MASK)) >> 18) +/* HWPARAMS6 */ +#define DWC3_RAM0_DEPTH(n) (((n) & (0xffff0000)) >> 16) + /* HWPARAMS7 */ #define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) @@ -937,18 +941,14 @@ struct dwc3_hwparams { * @request: struct usb_request to be transferred * @list: a list_head used for request queueing * @dep: struct dwc3_ep owning this request - * @sg: pointer to first incomplete sg * @start_sg: pointer to the sg which should be queued next * @num_pending_sgs: counter to pending sgs - * @num_queued_sgs: counter to the number of sgs which already got queued * @remaining: amount of data remaining * @status: internal dwc3 request status tracking * @epnum: endpoint number to which this request refers * @trb: pointer to struct dwc3_trb * @trb_dma: DMA address of @trb * @num_trbs: number of TRBs used by this request - * @needs_extra_trb: true when request needs one extra TRB (either due to ZLP - * or unaligned OUT) * @direction: IN or OUT direction flag * @mapped: true when request has been dma-mapped */ @@ -960,7 +960,6 @@ struct dwc3_request { struct scatterlist *start_sg; unsigned int num_pending_sgs; - unsigned int num_queued_sgs; unsigned int remaining; unsigned int status; @@ -978,7 +977,6 @@ struct dwc3_request { unsigned int num_trbs; - unsigned int needs_extra_trb:1; unsigned int direction:1; unsigned int mapped:1; }; diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index fad151e78fd669..5e3d1741701f7e 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -377,7 +377,7 @@ MODULE_DEVICE_TABLE(of, dwc3_ti_of_match); static struct platform_driver dwc3_ti_driver = { .probe = dwc3_ti_probe, - .remove_new = dwc3_ti_remove, + .remove = dwc3_ti_remove, .driver = { .name = "dwc3-am62", .pm = DEV_PM_OPS, diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 9a6e988d165a67..f5d963fae9e069 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -243,7 +243,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(dwc3_exynos_dev_pm_ops, static struct platform_driver dwc3_exynos_driver = { .probe = dwc3_exynos_probe, - .remove_new = dwc3_exynos_remove, + .remove = dwc3_exynos_remove, .driver = { .name = "exynos-dwc3", .of_match_table = exynos_dwc3_match, diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c index 64c0cd1995aa06..3edc5aca76f97b 100644 --- a/drivers/usb/dwc3/dwc3-imx8mp.c +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -129,6 +129,16 @@ static void dwc3_imx8mp_wakeup_disable(struct dwc3_imx8mp *dwc3_imx) writel(val, dwc3_imx->hsio_blk_base + USB_WAKEUP_CTRL); } +static const struct property_entry dwc3_imx8mp_properties[] = { + PROPERTY_ENTRY_BOOL("xhci-missing-cas-quirk"), + PROPERTY_ENTRY_BOOL("xhci-skip-phy-init-quirk"), + {}, +}; + +static const struct software_node dwc3_imx8mp_swnode = { + .properties = dwc3_imx8mp_properties, +}; + static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx) { struct dwc3_imx8mp *dwc3_imx = _dwc3_imx; @@ -148,17 +158,6 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx) return IRQ_HANDLED; } -static int dwc3_imx8mp_set_software_node(struct device *dev) -{ - struct property_entry props[3] = { 0 }; - int prop_idx = 0; - - props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-missing-cas-quirk"); - props[prop_idx++] = PROPERTY_ENTRY_BOOL("xhci-skip-phy-init-quirk"); - - return device_create_managed_software_node(dev, props, NULL); -} - static int dwc3_imx8mp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -221,17 +220,17 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) if (err < 0) goto disable_rpm; - err = dwc3_imx8mp_set_software_node(dev); + err = device_add_software_node(dev, &dwc3_imx8mp_swnode); if (err) { err = -ENODEV; - dev_err(dev, "failed to create software node\n"); + dev_err(dev, "failed to add software node\n"); goto disable_rpm; } err = of_platform_populate(node, NULL, NULL, dev); if (err) { dev_err(&pdev->dev, "failed to create dwc3 core\n"); - goto disable_rpm; + goto remove_swnode; } dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np); @@ -255,6 +254,8 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) depopulate: of_platform_depopulate(dev); +remove_swnode: + device_remove_software_node(dev); disable_rpm: pm_runtime_disable(dev); pm_runtime_put_noidle(dev); @@ -268,6 +269,7 @@ static void dwc3_imx8mp_remove(struct platform_device *pdev) pm_runtime_get_sync(dev); of_platform_depopulate(dev); + device_remove_software_node(dev); pm_runtime_disable(dev); pm_runtime_put_noidle(dev); @@ -400,7 +402,7 @@ MODULE_DEVICE_TABLE(of, dwc3_imx8mp_of_match); static struct platform_driver dwc3_imx8mp_driver = { .probe = dwc3_imx8mp_probe, - .remove_new = dwc3_imx8mp_remove, + .remove = dwc3_imx8mp_remove, .driver = { .name = "imx8mp-dwc3", .pm = pm_ptr(&dwc3_imx8mp_dev_pm_ops), diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 8899348b627632..7ee1610162b94f 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -208,7 +208,7 @@ MODULE_DEVICE_TABLE(of, kdwc3_of_match); static struct platform_driver kdwc3_driver = { .probe = kdwc3_probe, - .remove_new = kdwc3_remove, + .remove = kdwc3_remove, .driver = { .name = "keystone-dwc3", .of_match_table = kdwc3_of_match, diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 2c07c038b584dc..7d80bf7b18b0d2 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -968,7 +968,7 @@ MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match); static struct platform_driver dwc3_meson_g12a_driver = { .probe = dwc3_meson_g12a_probe, - .remove_new = dwc3_meson_g12a_remove, + .remove = dwc3_meson_g12a_remove, .driver = { .name = "dwc3-meson-g12a", .of_match_table = dwc3_meson_g12a_match, diff --git a/drivers/usb/dwc3/dwc3-octeon.c b/drivers/usb/dwc3/dwc3-octeon.c index 1a3b205367fd55..42bfc14ae0c464 100644 --- a/drivers/usb/dwc3/dwc3-octeon.c +++ b/drivers/usb/dwc3/dwc3-octeon.c @@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, dwc3_octeon_of_match); static struct platform_driver dwc3_octeon_driver = { .probe = dwc3_octeon_probe, - .remove_new = dwc3_octeon_remove, + .remove = dwc3_octeon_remove, .driver = { .name = "dwc3-octeon", .of_match_table = dwc3_octeon_of_match, diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index be7be00ecb3491..a4954a21be9301 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -180,7 +180,7 @@ MODULE_DEVICE_TABLE(of, of_dwc3_simple_match); static struct platform_driver dwc3_of_simple_driver = { .probe = dwc3_of_simple_probe, - .remove_new = dwc3_of_simple_remove, + .remove = dwc3_of_simple_remove, .shutdown = dwc3_of_simple_shutdown, .driver = { .name = "dwc3-of-simple", diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 2a11fc0ee84f1e..b261c46124c612 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -416,7 +416,7 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap) struct device_node *node = omap->dev->of_node; struct extcon_dev *edev; - if (of_property_read_bool(node, "extcon")) { + if (of_property_present(node, "extcon")) { edev = extcon_get_edev_by_phandle(omap->dev, 0); if (IS_ERR(edev)) { dev_vdbg(omap->dev, "couldn't get extcon device\n"); @@ -611,7 +611,7 @@ static const struct dev_pm_ops dwc3_omap_dev_pm_ops = { static struct platform_driver dwc3_omap_driver = { .probe = dwc3_omap_probe, - .remove_new = dwc3_omap_remove, + .remove = dwc3_omap_remove, .driver = { .name = "omap-dwc3", .of_match_table = of_dwc3_match, diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index c1d4b52f25b063..58683bb672e952 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -161,7 +161,7 @@ static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom) struct extcon_dev *host_edev; int ret; - if (!of_property_read_bool(dev->of_node, "extcon")) + if (!of_property_present(dev->of_node, "extcon")) return 0; qcom->edev = extcon_get_edev_by_phandle(dev, 0); @@ -921,7 +921,7 @@ MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match); static struct platform_driver dwc3_qcom_driver = { .probe = dwc3_qcom_probe, - .remove_new = dwc3_qcom_remove, + .remove = dwc3_qcom_remove, .driver = { .name = "dwc3-qcom", .pm = &dwc3_qcom_dev_pm_ops, diff --git a/drivers/usb/dwc3/dwc3-rtk.c b/drivers/usb/dwc3/dwc3-rtk.c index e9c8b032c72cb6..56c53e0c025748 100644 --- a/drivers/usb/dwc3/dwc3-rtk.c +++ b/drivers/usb/dwc3/dwc3-rtk.c @@ -441,7 +441,7 @@ static const struct dev_pm_ops dwc3_rtk_dev_pm_ops = { static struct platform_driver dwc3_rtk_driver = { .probe = dwc3_rtk_probe, - .remove_new = dwc3_rtk_remove, + .remove = dwc3_rtk_remove, .driver = { .name = "rtk-dwc3", .of_match_table = rtk_dwc3_match, diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index 2841021f3557f8..e16c3237180e97 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -356,7 +356,7 @@ MODULE_DEVICE_TABLE(of, st_dwc3_match); static struct platform_driver st_dwc3_driver = { .probe = st_dwc3_probe, - .remove_new = st_dwc3_remove, + .remove = st_dwc3_remove, .driver = { .name = "usb-st-dwc3", .of_match_table = st_dwc3_match, diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c index b5e5be424ce997..a33a42ba0249ab 100644 --- a/drivers/usb/dwc3/dwc3-xilinx.c +++ b/drivers/usb/dwc3/dwc3-xilinx.c @@ -121,8 +121,11 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data) * in use but the usb3-phy entry is missing from the device tree. * Therefore, skip these operations in this case. */ - if (!priv_data->usb3_phy) + if (!priv_data->usb3_phy) { + /* Deselect the PIPE Clock Select bit in FPD PIPE Clock register */ + writel(PIPE_CLK_DESELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK); goto skip_usb3_phy; + } crst = devm_reset_control_get_exclusive(dev, "usb_crst"); if (IS_ERR(crst)) { @@ -420,7 +423,7 @@ static const struct dev_pm_ops dwc3_xlnx_dev_pm_ops = { static struct platform_driver dwc3_xlnx_driver = { .probe = dwc3_xlnx_probe, - .remove_new = dwc3_xlnx_remove, + .remove = dwc3_xlnx_remove, .driver = { .name = "dwc3-xilinx", .of_match_table = dwc3_xlnx_of_match, diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c9533a99e47c89..666ac432f52d67 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -145,7 +145,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, * Unfortunately we have uncovered a limitation wrt the Data Phase. * * Section 9.4 says we can wait for the XferNotReady(DATA) event to - * come before issueing Start Transfer command, but if we do, we will + * come before issuing Start Transfer command, but if we do, we will * miss situations where the host starts another SETUP phase instead of * the DATA phase. Such cases happen at least on TD.7.6 of the Link * Layer Compliance Suite. @@ -232,7 +232,7 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) /* stall is always issued on EP0 */ dep = dwc->eps[0]; __dwc3_gadget_ep_set_halt(dep, 1, false); - dep->flags &= DWC3_EP_RESOURCE_ALLOCATED; + dep->flags &= DWC3_EP_RESOURCE_ALLOCATED | DWC3_EP_TRANSFER_STARTED; dep->flags |= DWC3_EP_ENABLED; dwc->delayed_status = false; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4959c26d3b71b8..83dc7304d70109 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -197,7 +197,6 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, list_del(&req->list); req->remaining = 0; - req->needs_extra_trb = false; req->num_trbs = 0; if (req->request.status == -EINPROGRESS) @@ -687,6 +686,44 @@ static int dwc3_gadget_calc_tx_fifo_size(struct dwc3 *dwc, int mult) return fifo_size; } +/** + * dwc3_gadget_calc_ram_depth - calculates the ram depth for txfifo + * @dwc: pointer to the DWC3 context + */ +static int dwc3_gadget_calc_ram_depth(struct dwc3 *dwc) +{ + int ram_depth; + int fifo_0_start; + bool is_single_port_ram; + + /* Check supporting RAM type by HW */ + is_single_port_ram = DWC3_SPRAM_TYPE(dwc->hwparams.hwparams1); + + /* + * If a single port RAM is utilized, then allocate TxFIFOs from + * RAM0. otherwise, allocate them from RAM1. + */ + ram_depth = is_single_port_ram ? DWC3_RAM0_DEPTH(dwc->hwparams.hwparams6) : + DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); + + /* + * In a single port RAM configuration, the available RAM is shared + * between the RX and TX FIFOs. This means that the txfifo can begin + * at a non-zero address. + */ + if (is_single_port_ram) { + u32 reg; + + /* Check if TXFIFOs start at non-zero addr */ + reg = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); + fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(reg); + + ram_depth -= (fifo_0_start >> 16); + } + + return ram_depth; +} + /** * dwc3_gadget_clear_tx_fifos - Clears txfifo allocation * @dwc: pointer to the DWC3 context @@ -753,7 +790,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; int fifo_0_start; - int ram1_depth; + int ram_depth; int fifo_size; int min_depth; int num_in_ep; @@ -773,17 +810,32 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) if (dep->flags & DWC3_EP_TXFIFO_RESIZED) return 0; - ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); + ram_depth = dwc3_gadget_calc_ram_depth(dwc); - if ((dep->endpoint.maxburst > 1 && - usb_endpoint_xfer_bulk(dep->endpoint.desc)) || - usb_endpoint_xfer_isoc(dep->endpoint.desc)) - num_fifos = 3; - - if (dep->endpoint.maxburst > 6 && - (usb_endpoint_xfer_bulk(dep->endpoint.desc) || - usb_endpoint_xfer_isoc(dep->endpoint.desc)) && DWC3_IP_IS(DWC31)) - num_fifos = dwc->tx_fifo_resize_max_num; + switch (dwc->gadget->speed) { + case USB_SPEED_SUPER_PLUS: + case USB_SPEED_SUPER: + if (usb_endpoint_xfer_bulk(dep->endpoint.desc) || + usb_endpoint_xfer_isoc(dep->endpoint.desc)) + num_fifos = min_t(unsigned int, + dep->endpoint.maxburst, + dwc->tx_fifo_resize_max_num); + break; + case USB_SPEED_HIGH: + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { + num_fifos = min_t(unsigned int, + usb_endpoint_maxp_mult(dep->endpoint.desc) + 1, + dwc->tx_fifo_resize_max_num); + break; + } + fallthrough; + case USB_SPEED_FULL: + if (usb_endpoint_xfer_bulk(dep->endpoint.desc)) + num_fifos = 2; + break; + default: + break; + } /* FIFO size for a single buffer */ fifo = dwc3_gadget_calc_tx_fifo_size(dwc, 1); @@ -794,7 +846,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) /* Reserve at least one FIFO for the number of IN EPs */ min_depth = num_in_ep * (fifo + 1); - remaining = ram1_depth - min_depth - dwc->last_fifo_depth; + remaining = ram_depth - min_depth - dwc->last_fifo_depth; remaining = max_t(int, 0, remaining); /* * We've already reserved 1 FIFO per EP, so check what we can fit in @@ -820,9 +872,9 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep) dwc->last_fifo_depth += DWC31_GTXFIFOSIZ_TXFDEP(fifo_size); /* Check fifo size allocation doesn't exceed available RAM size. */ - if (dwc->last_fifo_depth >= ram1_depth) { + if (dwc->last_fifo_depth >= ram_depth) { dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n", - dwc->last_fifo_depth, ram1_depth, + dwc->last_fifo_depth, ram_depth, dep->endpoint.name, fifo_size); if (DWC3_IP_IS(DWC3)) fifo_size = DWC3_GTXFIFOSIZ_TXFDEP(fifo_size); @@ -1177,11 +1229,14 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) * pending to be processed by the driver. */ if (dep->trb_enqueue == dep->trb_dequeue) { + struct dwc3_request *req; + /* - * If there is any request remained in the started_list at - * this point, that means there is no TRB available. + * If there is any request remained in the started_list with + * active TRBs at this point, then there is no TRB available. */ - if (!list_empty(&dep->started_list)) + req = next_request(&dep->started_list); + if (req && req->num_trbs) return 0; return DWC3_TRB_NUM - 1; @@ -1384,6 +1439,7 @@ static int dwc3_prepare_last_sg(struct dwc3_ep *dep, unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); unsigned int rem = req->request.length % maxp; unsigned int num_trbs = 1; + bool needs_extra_trb; if (dwc3_needs_extra_trb(dep, req)) num_trbs++; @@ -1391,15 +1447,15 @@ static int dwc3_prepare_last_sg(struct dwc3_ep *dep, if (dwc3_calc_trbs_left(dep) < num_trbs) return 0; - req->needs_extra_trb = num_trbs > 1; + needs_extra_trb = num_trbs > 1; /* Prepare a normal TRB */ if (req->direction || req->request.length) dwc3_prepare_one_trb(dep, req, entry_length, - req->needs_extra_trb, node, false, false); + needs_extra_trb, node, false, false); /* Prepare extra TRBs for ZLP and MPS OUT transfer alignment */ - if ((!req->direction && !req->request.length) || req->needs_extra_trb) + if ((!req->direction && !req->request.length) || needs_extra_trb) dwc3_prepare_one_trb(dep, req, req->direction ? 0 : maxp - rem, false, 1, true, false); @@ -1414,8 +1470,8 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep, struct scatterlist *s; int i; unsigned int length = req->request.length; - unsigned int remaining = req->request.num_mapped_sgs - - req->num_queued_sgs; + unsigned int remaining = req->num_pending_sgs; + unsigned int num_queued_sgs = req->request.num_mapped_sgs - remaining; unsigned int num_trbs = req->num_trbs; bool needs_extra_trb = dwc3_needs_extra_trb(dep, req); @@ -1423,7 +1479,7 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep, * If we resume preparing the request, then get the remaining length of * the request and resume where we left off. */ - for_each_sg(req->request.sg, s, req->num_queued_sgs, i) + for_each_sg(req->request.sg, s, num_queued_sgs, i) length -= sg_dma_len(s); for_each_sg(sg, s, remaining, i) { @@ -1488,7 +1544,6 @@ static int dwc3_prepare_trbs_sg(struct dwc3_ep *dep, if (!last_sg) req->start_sg = sg_next(s); - req->num_queued_sgs++; req->num_pending_sgs--; /* @@ -1569,9 +1624,7 @@ static int dwc3_prepare_trbs(struct dwc3_ep *dep) if (ret) return ret; - req->sg = req->request.sg; - req->start_sg = req->sg; - req->num_queued_sgs = 0; + req->start_sg = req->request.sg; req->num_pending_sgs = req->request.num_mapped_sgs; if (req->num_pending_sgs > 0) { @@ -3075,7 +3128,7 @@ static int dwc3_gadget_check_config(struct usb_gadget *g) struct dwc3 *dwc = gadget_to_dwc(g); struct usb_ep *ep; int fifo_size = 0; - int ram1_depth; + int ram_depth; int ep_num = 0; if (!dwc->do_fifo_resize) @@ -3098,8 +3151,8 @@ static int dwc3_gadget_check_config(struct usb_gadget *g) fifo_size += dwc->max_cfg_eps; /* Check if we can fit a single fifo per endpoint */ - ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); - if (fifo_size > ram1_depth) + ram_depth = dwc3_gadget_calc_ram_depth(dwc); + if (fifo_size > ram_depth) return -ENOMEM; return 0; @@ -3416,20 +3469,16 @@ static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep, int status) { struct dwc3_trb *trb; - struct scatterlist *sg = req->sg; - struct scatterlist *s; - unsigned int num_queued = req->num_queued_sgs; + unsigned int num_completed_trbs = req->num_trbs; unsigned int i; int ret = 0; - for_each_sg(sg, s, num_queued, i) { + for (i = 0; i < num_completed_trbs; i++) { trb = &dep->trb_pool[dep->trb_dequeue]; - req->sg = sg_next(s); - req->num_queued_sgs--; - ret = dwc3_gadget_ep_reclaim_completed_trb(dep, req, - trb, event, status, true); + trb, event, status, + !!(trb->ctrl & DWC3_TRB_CTRL_CHN)); if (ret) break; } @@ -3437,19 +3486,9 @@ static int dwc3_gadget_ep_reclaim_trb_sg(struct dwc3_ep *dep, return ret; } -static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req, const struct dwc3_event_depevt *event, - int status) -{ - struct dwc3_trb *trb = &dep->trb_pool[dep->trb_dequeue]; - - return dwc3_gadget_ep_reclaim_completed_trb(dep, req, trb, - event, status, false); -} - static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req) { - return req->num_pending_sgs == 0 && req->num_queued_sgs == 0; + return req->num_pending_sgs == 0 && req->num_trbs == 0; } static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, @@ -3459,24 +3498,13 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, int request_status; int ret; - if (req->request.num_mapped_sgs) - ret = dwc3_gadget_ep_reclaim_trb_sg(dep, req, event, - status); - else - ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, - status); + ret = dwc3_gadget_ep_reclaim_trb_sg(dep, req, event, status); req->request.actual = req->request.length - req->remaining; if (!dwc3_gadget_ep_request_completed(req)) goto out; - if (req->needs_extra_trb) { - ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, - status); - req->needs_extra_trb = false; - } - /* * The event status only reflects the status of the TRB with IOC set. * For the requests that don't set interrupt on completion, the driver diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index e0533cee6870ba..b48e108fc8fe73 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -35,7 +35,7 @@ static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc) u32 reg; int i; - /* xhci regs is not mapped yet, do it temperary here */ + /* xhci regs are not mapped yet, do it temporarily here */ if (dwc->xhci_resources[0].start) { xhci_regs = ioremap(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END); if (!xhci_regs) { diff --git a/drivers/usb/fotg210/fotg210-core.c b/drivers/usb/fotg210/fotg210-core.c index 0655afe7f9779f..49f25a70b32ebd 100644 --- a/drivers/usb/fotg210/fotg210-core.c +++ b/drivers/usb/fotg210/fotg210-core.c @@ -195,7 +195,7 @@ static struct platform_driver fotg210_driver = { .of_match_table = of_match_ptr(fotg210_of_match), }, .probe = fotg210_probe, - .remove_new = fotg210_remove, + .remove = fotg210_remove, }; static int __init fotg210_init(void) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index f25dd2cb5d03b1..bdda8c74602dea 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1844,7 +1844,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) cdev->desc.bcdUSB = cpu_to_le16(0x0200); } - value = min(w_length, (u16) sizeof cdev->desc); + value = min_t(u16, w_length, sizeof(cdev->desc)); memcpy(req->buf, &cdev->desc, value); break; case USB_DT_DEVICE_QUALIFIER: @@ -1863,19 +1863,19 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_DT_CONFIG: value = config_desc(cdev, w_value); if (value >= 0) - value = min(w_length, (u16) value); + value = min_t(u16, w_length, value); break; case USB_DT_STRING: value = get_string(cdev, req->buf, w_index, w_value & 0xff); if (value >= 0) - value = min(w_length, (u16) value); + value = min_t(u16, w_length, value); break; case USB_DT_BOS: if (gadget_is_superspeed(gadget) || gadget->lpm_capable || cdev->use_webusb) { value = bos_desc(cdev); - value = min(w_length, (u16) value); + value = min_t(u16, w_length, value); } break; case USB_DT_OTG: @@ -1930,7 +1930,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) *(u8 *)req->buf = cdev->config->bConfigurationValue; else *(u8 *)req->buf = 0; - value = min(w_length, (u16) 1); + value = min_t(u16, w_length, 1); break; /* function drivers must handle get/set altsetting */ @@ -1976,7 +1976,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (value < 0) break; *((u8 *)req->buf) = value; - value = min(w_length, (u16) 1); + value = min_t(u16, w_length, 1); break; case USB_REQ_GET_STATUS: if (gadget_is_otg(gadget) && gadget->hnp_polling_support && @@ -2111,8 +2111,20 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) memset(buf, 0, w_length); buf[5] = 0x01; switch (ctrl->bRequestType & USB_RECIP_MASK) { + /* + * The Microsoft CompatID OS Descriptor Spec(w_index = 0x4) and + * Extended Prop OS Desc Spec(w_index = 0x5) state that the + * HighByte of wValue is the InterfaceNumber and the LowByte is + * the PageNumber. This high/low byte ordering is incorrectly + * documented in the Spec. USB analyzer output on the below + * request packets show the high/low byte inverted i.e LowByte + * is the InterfaceNumber and the HighByte is the PageNumber. + * Since we dont support >64KB CompatID/ExtendedProp descriptors, + * PageNumber is set to 0. Hence verify that the HighByte is 0 + * for below two cases. + */ case USB_RECIP_DEVICE: - if (w_index != 0x4 || (w_value & 0xff)) + if (w_index != 0x4 || (w_value >> 8)) break; buf[6] = w_index; /* Number of ext compat interfaces */ @@ -2128,9 +2140,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) } break; case USB_RECIP_INTERFACE: - if (w_index != 0x5 || (w_value & 0xff)) + if (w_index != 0x5 || (w_value >> 8)) break; - interface = w_value >> 8; + interface = w_value & 0xFF; if (interface >= MAX_CONFIG_INTERFACES || !os_desc_cfg->interface[interface]) break; diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index b1f625245713a4..95f144a54ed96f 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -57,11 +57,11 @@ EXPORT_SYMBOL_GPL(usb_descriptor_fillbuf); * usb_gadget_config_buf - builts a complete configuration descriptor * @config: Header for the descriptor, including characteristics such * as power requirements and number of interfaces. - * @desc: Null-terminated vector of pointers to the descriptors (interface, - * endpoint, etc) defining all functions in this device configuration. * @buf: Buffer for the resulting configuration descriptor. * @length: Length of buffer. If this is not big enough to hold the * entire configuration descriptor, an error code will be returned. + * @desc: Null-terminated vector of pointers to the descriptors (interface, + * endpoint, etc) defining all functions in this device configuration. * * This copies descriptors into the response buffer, building a descriptor * for that configuration. It returns the buffer length or a negative diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index c82a6a0fba93dd..6499a88d346cd3 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1184,7 +1184,7 @@ static ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page, struct gadget_info *gi = os_desc_item_to_gadget_info(item); int res, l; - l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1); + l = min_t(int, len, OS_STRING_QW_SIGN_LEN >> 1); if (page[l - 1] == '\n') --l; diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 87917a7d4a9be8..7ce1637276f099 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -41,6 +41,10 @@ obj-$(CONFIG_USB_F_UAC1_LEGACY) += usb_f_uac1_legacy.o usb_f_uac2-y := f_uac2.o obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o +ifneq ($(CONFIG_TRACING),) + CFLAGS_uvc_trace.o := -I$(src) + usb_f_uvc-y += uvc_trace.o +endif obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o usb_f_midi-y := f_midi.o obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 2920f8000bbd83..ad79eb0f729b34 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -49,7 +49,7 @@ #define DMABUF_ENQUEUE_TIMEOUT_MS 5000 -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); /* Reference counter handling */ static void ffs_data_get(struct ffs_data *ffs); @@ -456,7 +456,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, } /* FFS_SETUP_PENDING and not stall */ - len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); + len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength)); spin_unlock_irq(&ffs->ev.waitq.lock); @@ -590,7 +590,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, /* unlocks spinlock */ return __ffs_ep0_read_events(ffs, buf, - min(n, (size_t)ffs->ev.count)); + min_t(size_t, n, ffs->ev.count)); case FFS_SETUP_PENDING: if (ffs->ev.setup.bRequestType & USB_DIR_IN) { @@ -599,7 +599,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, goto done_mutex; } - len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); + len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength)); spin_unlock_irq(&ffs->ev.waitq.lock); diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 08e0d1c511e8d9..2eae8fc2e0db78 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -500,7 +500,7 @@ static int fsg_setup(struct usb_function *f, *(u8 *)req->buf = _fsg_common_get_max_lun(fsg->common); /* Respond with data/status */ - req->length = min((u16)1, w_length); + req->length = min_t(u16, 1, w_length); return ep0_queue(fsg->common); } @@ -655,7 +655,7 @@ static int do_read(struct fsg_common *common) * And don't try to read past the end of the file. */ amount = min(amount_left, FSG_BUFLEN); - amount = min((loff_t)amount, + amount = min_t(loff_t, amount, curlun->file_length - file_offset); /* Wait for the next buffer to become available */ @@ -1005,7 +1005,7 @@ static int do_verify(struct fsg_common *common) * And don't try to read past the end of the file. */ amount = min(amount_left, FSG_BUFLEN); - amount = min((loff_t)amount, + amount = min_t(loff_t, amount, curlun->file_length - file_offset); if (amount == 0) { curlun->sense_data = @@ -2167,7 +2167,7 @@ static int do_scsi_command(struct fsg_common *common) if (reply == -EINVAL) reply = 0; /* Error reply length */ if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) { - reply = min((u32)reply, common->data_size_from_cmnd); + reply = min_t(u32, reply, common->data_size_from_cmnd); bh->inreq->length = reply; bh->state = BUF_STATE_FULL; common->residue -= reply; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 1067847cc07995..837fcdfa3840ff 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -819,9 +819,9 @@ static int f_midi_register_card(struct f_midi *midi) goto fail; } - strcpy(card->driver, f_midi_longname); - strcpy(card->longname, f_midi_longname); - strcpy(card->shortname, f_midi_shortname); + strscpy(card->driver, f_midi_longname); + strscpy(card->longname, f_midi_longname); + strscpy(card->shortname, f_midi_shortname); /* Set up rawmidi */ snd_component_add(card, "MIDI"); @@ -833,7 +833,7 @@ static int f_midi_register_card(struct f_midi *midi) } midi->rmidi = rmidi; midi->in_last_port = 0; - strcpy(rmidi->name, card->shortname); + strscpy(rmidi->name, card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c index 8285df9ed6fd78..12e866fb311d63 100644 --- a/drivers/usb/gadget/function/f_midi2.c +++ b/drivers/usb/gadget/function/f_midi2.c @@ -1285,10 +1285,8 @@ static int f_midi2_set_alt(struct usb_function *fn, unsigned int intf, if (alt == 0) op_mode = MIDI_OP_MODE_MIDI1; - else if (alt == 1) - op_mode = MIDI_OP_MODE_MIDI2; else - op_mode = MIDI_OP_MODE_UNSET; + op_mode = MIDI_OP_MODE_MIDI2; if (midi2->operation_mode == op_mode) return 0; @@ -1593,7 +1591,11 @@ static int f_midi2_create_card(struct f_midi2 *midi2) fb->info.midi_ci_version = b->midi_ci_version; fb->info.ui_hint = reverse_dir(b->ui_hint); fb->info.sysex8_streams = b->sysex8_streams; - fb->info.flags |= b->is_midi1; + if (b->is_midi1 < 2) + fb->info.flags |= b->is_midi1; + else + fb->info.flags |= SNDRV_UMP_BLOCK_IS_MIDI1 | + SNDRV_UMP_BLOCK_IS_LOWSPEED; strscpy(fb->info.name, ump_fb_name(b), sizeof(fb->info.name)); } diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 40187b7112e79c..aa6ab666741a95 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -465,7 +465,7 @@ uvc_register_video(struct uvc_device *uvc) memcpy(mem, desc, (desc)->bLength); \ *(dst)++ = mem; \ mem += (desc)->bLength; \ - } while (0); + } while (0) #define UVC_COPY_DESCRIPTORS(mem, dst, src) \ do { \ @@ -991,6 +991,8 @@ static void uvc_function_unbind(struct usb_configuration *c, uvcg_info(f, "%s()\n", __func__); + kthread_cancel_work_sync(&video->hw_submit); + if (video->async_wq) destroy_workqueue(video->async_wq); diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 0a8c05b2746b4e..53d9fc41acc522 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -579,9 +579,12 @@ static int gs_start_io(struct gs_port *port) * we didn't in gs_start_tx() */ tty_wakeup(port->port.tty); } else { - gs_free_requests(ep, head, &port->read_allocated); - gs_free_requests(port->port_usb->in, &port->write_pool, - &port->write_allocated); + /* Free reqs only if we are still connected */ + if (port->port_usb) { + gs_free_requests(ep, head, &port->read_allocated); + gs_free_requests(port->port_usb->in, &port->write_pool, + &port->write_allocated); + } status = -EIO; } diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index cb35687b11e7e9..6f44dd73231507 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -71,6 +71,11 @@ extern unsigned int uvc_gadget_trace_param; #define UVCG_REQUEST_HEADER_LEN 12 +#define UVCG_REQ_MAX_INT_COUNT 16 +#define UVCG_REQ_MAX_ZERO_COUNT (2 * UVCG_REQ_MAX_INT_COUNT) + +#define UVCG_STREAMING_MIN_BUFFERS 2 + /* ------------------------------------------------------------------------ * Structures */ @@ -91,16 +96,24 @@ struct uvc_video { struct work_struct pump; struct workqueue_struct *async_wq; + struct kthread_worker *kworker; + struct kthread_work hw_submit; + + atomic_t queued; + /* Frame parameters */ u8 bpp; u32 fcc; unsigned int width; unsigned int height; unsigned int imagesize; + unsigned int interval; struct mutex mutex; /* protects frame parameters */ unsigned int uvc_num_requests; + unsigned int reqs_per_frame; + /* Requests */ bool is_enabled; /* tracks whether video stream is enabled */ unsigned int req_size; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 6fac696ea84637..f131943254a4c4 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -1566,11 +1566,13 @@ static const struct uvcg_config_group_type uvcg_control_grp_type = { /* ----------------------------------------------------------------------------- * streaming/uncompressed * streaming/mjpeg + * streaming/framebased */ static const char * const uvcg_format_names[] = { "uncompressed", "mjpeg", + "framebased", }; static struct uvcg_color_matching * @@ -1777,6 +1779,9 @@ static int uvcg_streaming_header_allow_link(struct config_item *src, target_fmt = container_of(to_config_group(target), struct uvcg_format, group); + if (!target_fmt) + goto out; + uvcg_format_set_indices(to_config_group(target)); format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL); @@ -1816,6 +1821,9 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, target_fmt = container_of(to_config_group(target), struct uvcg_format, group); + if (!target_fmt) + goto out; + list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry) if (format_ptr->fmt == target_fmt) { list_del(&format_ptr->entry); @@ -1826,6 +1834,7 @@ static void uvcg_streaming_header_drop_link(struct config_item *src, --target_fmt->linked; +out: mutex_unlock(&opts->lock); mutex_unlock(su_mutex); } @@ -2022,6 +2031,7 @@ UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, 32); UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32); UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32); UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32); +UVCG_FRAME_ATTR(dw_bytes_perline, dwBytesPerLine, 32); #undef UVCG_FRAME_ATTR @@ -2035,7 +2045,7 @@ static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item, int result, i; char *pg = page; - mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ opts_item = frm->item.ci_parent->ci_parent->ci_parent->ci_parent; opts = to_f_uvc_opts(opts_item); @@ -2105,7 +2115,7 @@ static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item, UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); -static struct configfs_attribute *uvcg_frame_attrs[] = { +static struct configfs_attribute *uvcg_frame_attrs1[] = { &uvcg_frame_attr_b_frame_index, &uvcg_frame_attr_bm_capabilities, &uvcg_frame_attr_w_width, @@ -2118,12 +2128,31 @@ static struct configfs_attribute *uvcg_frame_attrs[] = { NULL, }; -static const struct config_item_type uvcg_frame_type = { +static struct configfs_attribute *uvcg_frame_attrs2[] = { + &uvcg_frame_attr_b_frame_index, + &uvcg_frame_attr_bm_capabilities, + &uvcg_frame_attr_w_width, + &uvcg_frame_attr_w_height, + &uvcg_frame_attr_dw_min_bit_rate, + &uvcg_frame_attr_dw_max_bit_rate, + &uvcg_frame_attr_dw_default_frame_interval, + &uvcg_frame_attr_dw_frame_interval, + &uvcg_frame_attr_dw_bytes_perline, + NULL, +}; + +static const struct config_item_type uvcg_frame_type1 = { .ct_item_ops = &uvcg_config_item_ops, - .ct_attrs = uvcg_frame_attrs, + .ct_attrs = uvcg_frame_attrs1, .ct_owner = THIS_MODULE, }; +static const struct config_item_type uvcg_frame_type2 = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_frame_attrs2, + .ct_owner = THIS_MODULE, +}; + static struct config_item *uvcg_frame_make(struct config_group *group, const char *name) { @@ -2145,6 +2174,7 @@ static struct config_item *uvcg_frame_make(struct config_group *group, h->frame.dw_max_bit_rate = 55296000; h->frame.dw_max_video_frame_buffer_size = 460800; h->frame.dw_default_frame_interval = 666666; + h->frame.dw_bytes_perline = 0; opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; opts = to_f_uvc_opts(opts_item); @@ -2157,6 +2187,9 @@ static struct config_item *uvcg_frame_make(struct config_group *group, } else if (fmt->type == UVCG_MJPEG) { h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG; h->fmt_type = UVCG_MJPEG; + } else if (fmt->type == UVCG_FRAMEBASED) { + h->frame.b_descriptor_subtype = UVC_VS_FRAME_FRAME_BASED; + h->fmt_type = UVCG_FRAMEBASED; } else { mutex_unlock(&opts->lock); kfree(h); @@ -2175,7 +2208,10 @@ static struct config_item *uvcg_frame_make(struct config_group *group, ++fmt->num_frames; mutex_unlock(&opts->lock); - config_item_init_type_name(&h->item, name, &uvcg_frame_type); + if (fmt->type == UVCG_FRAMEBASED) + config_item_init_type_name(&h->item, name, &uvcg_frame_type2); + else + config_item_init_type_name(&h->item, name, &uvcg_frame_type1); return &h->item; } @@ -2215,9 +2251,6 @@ static void uvcg_format_set_indices(struct config_group *fmt) list_for_each_entry(ci, &fmt->cg_children, ci_entry) { struct uvcg_frame *frm; - if (ci->ci_type != &uvcg_frame_type) - continue; - frm = to_uvcg_frame(ci); frm->frame.b_frame_index = i++; } @@ -2677,6 +2710,251 @@ static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = { .name = "mjpeg", }; +/* ----------------------------------------------------------------------------- + * streaming/framebased/ + */ + +static struct configfs_group_operations uvcg_framebased_group_ops = { + .make_item = uvcg_frame_make, + .drop_item = uvcg_frame_drop, +}; + +#define UVCG_FRAMEBASED_ATTR_RO(cname, aname, bits) \ +static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \ + char *page) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int result; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ + mutex_unlock(&opts->lock); \ + \ + mutex_unlock(su_mutex); \ + return result; \ +} \ + \ +UVC_ATTR_RO(uvcg_framebased_, cname, aname) + +#define UVCG_FRAMEBASED_ATTR(cname, aname, bits) \ +static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \ + char *page) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int result; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + result = sprintf(page, "%u\n", le##bits##_to_cpu(u->desc.aname));\ + mutex_unlock(&opts->lock); \ + \ + mutex_unlock(su_mutex); \ + return result; \ +} \ + \ +static ssize_t \ +uvcg_framebased_##cname##_store(struct config_item *item, \ + const char *page, size_t len) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int ret; \ + u8 num; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + if (u->fmt.linked || opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = kstrtou8(page, 0, &num); \ + if (ret) \ + goto end; \ + \ + if (num > 255) { \ + ret = -EINVAL; \ + goto end; \ + } \ + u->desc.aname = num; \ + ret = len; \ +end: \ + mutex_unlock(&opts->lock); \ + mutex_unlock(su_mutex); \ + return ret; \ +} \ + \ +UVC_ATTR(uvcg_framebased_, cname, aname) + +UVCG_FRAMEBASED_ATTR_RO(b_format_index, bFormatIndex, 8); +UVCG_FRAMEBASED_ATTR_RO(b_bits_per_pixel, bBitsPerPixel, 8); +UVCG_FRAMEBASED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8); +UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8); +UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8); +UVCG_FRAMEBASED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8); + +#undef UVCG_FRAMEBASED_ATTR +#undef UVCG_FRAMEBASED_ATTR_RO + +static ssize_t uvcg_framebased_guid_format_show(struct config_item *item, + char *page) +{ + struct uvcg_framebased *ch = to_uvcg_framebased(item); + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat)); + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return sizeof(ch->desc.guidFormat); +} + +static ssize_t uvcg_framebased_guid_format_store(struct config_item *item, + const char *page, size_t len) +{ + struct uvcg_framebased *ch = to_uvcg_framebased(item); + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; + int ret; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + if (ch->fmt.linked || opts->refcnt) { + ret = -EBUSY; + goto end; + } + + memcpy(ch->desc.guidFormat, page, + min(sizeof(ch->desc.guidFormat), len)); + ret = sizeof(ch->desc.guidFormat); + +end: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + +UVC_ATTR(uvcg_framebased_, guid_format, guidFormat); + +static inline ssize_t +uvcg_framebased_bma_controls_show(struct config_item *item, char *page) +{ + struct uvcg_framebased *u = to_uvcg_framebased(item); + + return uvcg_format_bma_controls_show(&u->fmt, page); +} + +static inline ssize_t +uvcg_framebased_bma_controls_store(struct config_item *item, + const char *page, size_t len) +{ + struct uvcg_framebased *u = to_uvcg_framebased(item); + + return uvcg_format_bma_controls_store(&u->fmt, page, len); +} + +UVC_ATTR(uvcg_framebased_, bma_controls, bmaControls); + +static struct configfs_attribute *uvcg_framebased_attrs[] = { + &uvcg_framebased_attr_b_format_index, + &uvcg_framebased_attr_b_default_frame_index, + &uvcg_framebased_attr_b_bits_per_pixel, + &uvcg_framebased_attr_b_aspect_ratio_x, + &uvcg_framebased_attr_b_aspect_ratio_y, + &uvcg_framebased_attr_bm_interface_flags, + &uvcg_framebased_attr_bma_controls, + &uvcg_framebased_attr_guid_format, + NULL, +}; + +static const struct config_item_type uvcg_framebased_type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_framebased_group_ops, + .ct_attrs = uvcg_framebased_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *uvcg_framebased_make(struct config_group *group, + const char *name) +{ + static char guid[] = { /*Declear frame based as H264 format*/ + 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + }; + struct uvcg_framebased *h; + + h = kzalloc(sizeof(*h), GFP_KERNEL); + if (!h) + return ERR_PTR(-ENOMEM); + + h->desc.bLength = UVC_DT_FORMAT_FRAMEBASED_SIZE; + h->desc.bDescriptorType = USB_DT_CS_INTERFACE; + h->desc.bDescriptorSubType = UVC_VS_FORMAT_FRAME_BASED; + memcpy(h->desc.guidFormat, guid, sizeof(guid)); + h->desc.bBitsPerPixel = 0; + h->desc.bDefaultFrameIndex = 1; + h->desc.bAspectRatioX = 0; + h->desc.bAspectRatioY = 0; + h->desc.bmInterfaceFlags = 0; + h->desc.bCopyProtect = 0; + h->desc.bVariableSize = 1; + + INIT_LIST_HEAD(&h->fmt.frames); + h->fmt.type = UVCG_FRAMEBASED; + config_group_init_type_name(&h->fmt.group, name, + &uvcg_framebased_type); + + return &h->fmt.group; +} + +static struct configfs_group_operations uvcg_framebased_grp_ops = { + .make_group = uvcg_framebased_make, +}; + +static const struct uvcg_config_group_type uvcg_framebased_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_framebased_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "framebased", +}; + /* ----------------------------------------------------------------------------- * streaming/color_matching/default */ @@ -2912,6 +3190,7 @@ static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h, if (ret) return ret; grp = &f->fmt->group; + j = 0; list_for_each_entry(item, &grp->cg_children, ci_entry) { frm = to_uvcg_frame(item); ret = fun(frm, priv2, priv3, j++, UVCG_FRAME); @@ -2965,6 +3244,11 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, container_of(fmt, struct uvcg_mjpeg, fmt); *size += sizeof(m->desc); + } else if (fmt->type == UVCG_FRAMEBASED) { + struct uvcg_framebased *f = + container_of(fmt, struct uvcg_framebased, fmt); + + *size += sizeof(f->desc); } else { return -EINVAL; } @@ -2975,6 +3259,11 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, int sz = sizeof(frm->dw_frame_interval); *size += sizeof(frm->frame); + /* + * framebased has duplicate member with uncompressed and + * mjpeg, so minus it + */ + *size -= sizeof(u32); *size += frm->frame.b_frame_interval_type * sz; } break; @@ -2991,6 +3280,27 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, return 0; } +static int __uvcg_copy_framebased_desc(void *dest, struct uvcg_frame *frm, + int sz) +{ + struct uvc_frame_framebased *desc = dest; + + desc->bLength = frm->frame.b_length; + desc->bDescriptorType = frm->frame.b_descriptor_type; + desc->bDescriptorSubType = frm->frame.b_descriptor_subtype; + desc->bFrameIndex = frm->frame.b_frame_index; + desc->bmCapabilities = frm->frame.bm_capabilities; + desc->wWidth = frm->frame.w_width; + desc->wHeight = frm->frame.w_height; + desc->dwMinBitRate = frm->frame.dw_min_bit_rate; + desc->dwMaxBitRate = frm->frame.dw_max_bit_rate; + desc->dwDefaultFrameInterval = frm->frame.dw_default_frame_interval; + desc->bFrameIntervalType = frm->frame.b_frame_interval_type; + desc->dwBytesPerLine = frm->frame.dw_bytes_perline; + + return 0; +} + /* * Fill an array of streaming descriptors. * @@ -3045,6 +3355,15 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, m->desc.bNumFrameDescriptors = fmt->num_frames; memcpy(*dest, &m->desc, sizeof(m->desc)); *dest += sizeof(m->desc); + } else if (fmt->type == UVCG_FRAMEBASED) { + struct uvcg_framebased *f = + container_of(fmt, struct uvcg_framebased, + fmt); + + f->desc.bFormatIndex = n + 1; + f->desc.bNumFrameDescriptors = fmt->num_frames; + memcpy(*dest, &f->desc, sizeof(f->desc)); + *dest += sizeof(f->desc); } else { return -EINVAL; } @@ -3054,8 +3373,11 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, struct uvcg_frame *frm = priv1; struct uvc_descriptor_header *h = *dest; - sz = sizeof(frm->frame); - memcpy(*dest, &frm->frame, sz); + sz = sizeof(frm->frame) - 4; + if (frm->fmt_type != UVCG_FRAMEBASED) + memcpy(*dest, &frm->frame, sz); + else + __uvcg_copy_framebased_desc(*dest, frm, sz); *dest += sz; sz = frm->frame.b_frame_interval_type * sizeof(*frm->dw_frame_interval); @@ -3066,7 +3388,10 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, frm->frame.b_frame_interval_type); else if (frm->fmt_type == UVCG_MJPEG) h->bLength = UVC_DT_FRAME_MJPEG_SIZE( - frm->frame.b_frame_interval_type); + frm->frame.b_frame_interval_type); + else if (frm->fmt_type == UVCG_FRAMEBASED) + h->bLength = UVC_DT_FRAME_FRAMEBASED_SIZE( + frm->frame.b_frame_interval_type); } break; case UVCG_COLOR_MATCHING: { @@ -3285,6 +3610,7 @@ static const struct uvcg_config_group_type uvcg_streaming_grp_type = { &uvcg_streaming_header_grp_type, &uvcg_uncompressed_grp_type, &uvcg_mjpeg_grp_type, + &uvcg_framebased_grp_type, &uvcg_color_matching_grp_type, &uvcg_streaming_class_grp_type, NULL, diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h index c6a690158138fe..2f78cd4f396f24 100644 --- a/drivers/usb/gadget/function/uvc_configfs.h +++ b/drivers/usb/gadget/function/uvc_configfs.h @@ -49,6 +49,7 @@ container_of(group_ptr, struct uvcg_color_matching, group) enum uvcg_format_type { UVCG_UNCOMPRESSED = 0, UVCG_MJPEG, + UVCG_FRAMEBASED, }; struct uvcg_format { @@ -105,6 +106,7 @@ struct uvcg_frame { u32 dw_max_video_frame_buffer_size; u32 dw_default_frame_interval; u8 b_frame_interval_type; + u32 dw_bytes_perline; } __attribute__((packed)) frame; u32 *dw_frame_interval; }; @@ -142,6 +144,20 @@ static inline struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item) return container_of(to_uvcg_format(item), struct uvcg_mjpeg, fmt); } +/* ----------------------------------------------------------------------------- + * streaming/framebased/ + */ + +struct uvcg_framebased { + struct uvcg_format fmt; + struct uvc_format_framebased desc; +}; + +static inline struct uvcg_framebased *to_uvcg_framebased(struct config_item *item) +{ + return container_of(to_uvcg_format(item), struct uvcg_framebased, fmt); +} + /* ----------------------------------------------------------------------------- * control/extensions/ */ diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 0aa3d7e1f3cc32..5eaeae3e2441c5 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -21,6 +21,7 @@ #include #include "uvc.h" +#include "uvc_video.h" /* ------------------------------------------------------------------------ * Video buffers queue management. @@ -44,33 +45,23 @@ static int uvc_queue_setup(struct vb2_queue *vq, { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_video *video = container_of(queue, struct uvc_video, queue); - unsigned int req_size; - unsigned int nreq; if (*nbuffers > UVC_MAX_VIDEO_BUFFERS) *nbuffers = UVC_MAX_VIDEO_BUFFERS; + if (*nbuffers < UVCG_STREAMING_MIN_BUFFERS) + *nbuffers = UVCG_STREAMING_MIN_BUFFERS; *nplanes = 1; sizes[0] = video->imagesize; - req_size = video->ep->maxpacket - * max_t(unsigned int, video->ep->maxburst, 1) - * (video->ep->mult); - - /* We divide by two, to increase the chance to run - * into fewer requests for smaller framesizes. - */ - nreq = DIV_ROUND_UP(DIV_ROUND_UP(sizes[0], 2), req_size); - nreq = clamp(nreq, 4U, 64U); - video->uvc_num_requests = nreq; - return 0; } static int uvc_buffer_prepare(struct vb2_buffer *vb) { struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_video *video = container_of(queue, struct uvc_video, queue); struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct uvc_buffer *buf = container_of(vbuf, struct uvc_buffer, buf); @@ -91,10 +82,15 @@ static int uvc_buffer_prepare(struct vb2_buffer *vb) buf->mem = vb2_plane_vaddr(vb, 0); } buf->length = vb2_plane_size(vb, 0); - if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { buf->bytesused = 0; - else + } else { buf->bytesused = vb2_get_plane_payload(vb, 0); + buf->req_payload_size = + DIV_ROUND_UP(buf->bytesused + + (video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN), + video->reqs_per_frame); + } return 0; } diff --git a/drivers/usb/gadget/function/uvc_queue.h b/drivers/usb/gadget/function/uvc_queue.h index 41f87b917f6bc1..b54becc570a38e 100644 --- a/drivers/usb/gadget/function/uvc_queue.h +++ b/drivers/usb/gadget/function/uvc_queue.h @@ -39,6 +39,8 @@ struct uvc_buffer { unsigned int offset; unsigned int length; unsigned int bytesused; + /* req_payload_size: only used with isoc */ + unsigned int req_payload_size; }; #define UVC_QUEUE_DISCONNECTED (1 << 0) diff --git a/drivers/usb/gadget/function/uvc_trace.c b/drivers/usb/gadget/function/uvc_trace.c new file mode 100644 index 00000000000000..d384f6d8221a54 --- /dev/null +++ b/drivers/usb/gadget/function/uvc_trace.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * trace.c - USB UVC Gadget Trace Support + * + * Copyright (C) 2024 Pengutronix e.K. + * + * Author: Michael Grzeschik + */ + +#define CREATE_TRACE_POINTS +#include "uvc_trace.h" diff --git a/drivers/usb/gadget/function/uvc_trace.h b/drivers/usb/gadget/function/uvc_trace.h new file mode 100644 index 00000000000000..04c33cf43cc2d4 --- /dev/null +++ b/drivers/usb/gadget/function/uvc_trace.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * trace.h - USB UVC Gadget Trace Support + * + * Copyright (C) 2024 Pengutronix e.K. + * + * Author: Michael Grzeschik + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM uvcg + +#if !defined(__UVCG_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __UVCG_TRACE_H + +#include +#include +#include +#include + +DECLARE_EVENT_CLASS(uvcg_video_req, + TP_PROTO(struct usb_request *req, u32 queued), + TP_ARGS(req, queued), + TP_STRUCT__entry( + __field(struct usb_request *, req) + __field(u32, length) + __field(u32, queued) + ), + TP_fast_assign( + __entry->req = req; + __entry->length = req->length; + __entry->queued = queued; + ), + TP_printk("req %p length %u queued %u", + __entry->req, + __entry->length, + __entry->queued) +); + +DEFINE_EVENT(uvcg_video_req, uvcg_video_complete, + TP_PROTO(struct usb_request *req, u32 queued), + TP_ARGS(req, queued) +); + +DEFINE_EVENT(uvcg_video_req, uvcg_video_queue, + TP_PROTO(struct usb_request *req, u32 queued), + TP_ARGS(req, queued) +); + +#endif /* __UVCG_TRACE_H */ + +/* this part has to be here */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE uvc_trace + +#include diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index de1736f834e6b8..fc9a8d31a1e983 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -31,13 +31,22 @@ static const struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat) { char guid[16] = UVC_GUID_FORMAT_MJPEG; const struct uvc_format_desc *format; - struct uvcg_uncompressed *unc; if (uformat->type == UVCG_UNCOMPRESSED) { + struct uvcg_uncompressed *unc; + unc = to_uvcg_uncompressed(&uformat->group.cg_item); if (!unc) return ERR_PTR(-EINVAL); + memcpy(guid, unc->desc.guidFormat, sizeof(guid)); + } else if (uformat->type == UVCG_FRAMEBASED) { + struct uvcg_framebased *unc; + + unc = to_uvcg_framebased(&uformat->group.cg_item); + if (!unc) + return ERR_PTR(-EINVAL); + memcpy(guid, unc->desc.guidFormat, sizeof(guid)); } @@ -314,6 +323,56 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt) return ret; } +static int uvc_v4l2_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvc_video *video = &uvc->video; + struct v4l2_fract timeperframe; + + if (!V4L2_TYPE_IS_OUTPUT(parm->type)) + return -EINVAL; + + /* Return the actual frame period. */ + timeperframe.numerator = video->interval; + timeperframe.denominator = 10000000; + v4l2_simplify_fraction(&timeperframe.numerator, + &timeperframe.denominator, 8, 333); + + uvcg_dbg(&uvc->func, "Getting frame interval of %u/%u (%u)\n", + timeperframe.numerator, timeperframe.denominator, + video->interval); + + parm->parm.output.timeperframe = timeperframe; + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + + return 0; +} + +static int uvc_v4l2_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvc_video *video = &uvc->video; + struct v4l2_fract timeperframe; + + if (!V4L2_TYPE_IS_OUTPUT(parm->type)) + return -EINVAL; + + timeperframe = parm->parm.output.timeperframe; + + video->interval = v4l2_fraction_to_interval(timeperframe.numerator, + timeperframe.denominator); + + uvcg_dbg(&uvc->func, "Setting frame interval to %u/%u (%u)\n", + timeperframe.numerator, timeperframe.denominator, + video->interval); + + return 0; +} + static int uvc_v4l2_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) @@ -496,6 +555,9 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) if (ret < 0) return ret; + if (uvc->state != UVC_STATE_STREAMING) + return 0; + uvc->state = UVC_STATE_CONNECTED; uvc_function_setup_continue(uvc, 1); return 0; @@ -587,6 +649,8 @@ const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = { .vidioc_dqbuf = uvc_v4l2_dqbuf, .vidioc_streamon = uvc_v4l2_streamon, .vidioc_streamoff = uvc_v4l2_streamoff, + .vidioc_s_parm = uvc_v4l2_s_parm, + .vidioc_g_parm = uvc_v4l2_g_parm, .vidioc_subscribe_event = uvc_v4l2_subscribe_event, .vidioc_unsubscribe_event = uvc_v4l2_unsubscribe_event, .vidioc_default = uvc_v4l2_ioctl_default, diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 57a851151225de..79e223713d8b93 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -19,6 +19,7 @@ #include "uvc.h" #include "uvc_queue.h" #include "uvc_video.h" +#include "uvc_trace.h" /* -------------------------------------------------------------------------- * Video codecs @@ -78,7 +79,7 @@ uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf, /* Copy video data to the USB buffer. */ mem = buf->mem + queue->buf_used; - nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used); + nbytes = min_t(unsigned int, len, buf->bytesused - queue->buf_used); memcpy(data, mem, nbytes); queue->buf_used += nbytes; @@ -104,7 +105,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video, } /* Process video data. */ - len = min((int)(video->max_payload_size - video->payload_size), len); + len = min_t(int, video->max_payload_size - video->payload_size, len); ret = uvc_video_encode_data(video, buf, mem, len); video->payload_size += ret; @@ -136,7 +137,7 @@ uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video, unsigned int pending = buf->bytesused - video->queue.buf_used; struct uvc_request *ureq = req->context; struct scatterlist *sg, *iter; - unsigned int len = video->req_size; + unsigned int len = buf->req_payload_size; unsigned int sg_left, part = 0; unsigned int i; int header_len; @@ -146,15 +147,15 @@ uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video, /* Init the header. */ header_len = uvc_video_encode_header(video, buf, ureq->header, - video->req_size); + buf->req_payload_size); sg_set_buf(sg, ureq->header, header_len); len -= header_len; if (pending <= len) len = pending; - req->length = (len == pending) ? - len + header_len : video->req_size; + req->length = (len == pending) ? len + header_len : + buf->req_payload_size; /* Init the pending sgs with payload */ sg = sg_next(sg); @@ -202,7 +203,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, { void *mem = req->buf; struct uvc_request *ureq = req->context; - int len = video->req_size; + int len = buf->req_payload_size; int ret; /* Add the header. */ @@ -214,7 +215,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, ret = uvc_video_encode_data(video, buf, mem, len); len -= ret; - req->length = video->req_size - len; + req->length = buf->req_payload_size - len; if (buf->bytesused == video->queue.buf_used || video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE) { @@ -269,6 +270,10 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req) } } + atomic_inc(&video->queued); + + trace_uvcg_video_queue(req, atomic_read(&video->queued)); + return ret; } @@ -304,7 +309,7 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video, */ if (list_empty(&video->req_free) || ureq->last_buf || !(video->req_int_count % - DIV_ROUND_UP(video->uvc_num_requests, 4))) { + min(DIV_ROUND_UP(video->uvc_num_requests, 4), UVCG_REQ_MAX_INT_COUNT))) { video->req_int_count = 0; req->no_interrupt = 0; } else { @@ -322,50 +327,6 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video, return 0; } -/* - * Must only be called from uvcg_video_enable - since after that we only want to - * queue requests to the endpoint from the uvc_video_complete complete handler. - * This function is needed in order to 'kick start' the flow of requests from - * gadget driver to the usb controller. - */ -static void uvc_video_ep_queue_initial_requests(struct uvc_video *video) -{ - struct usb_request *req = NULL; - unsigned long flags = 0; - unsigned int count = 0; - int ret = 0; - - /* - * We only queue half of the free list since we still want to have - * some free usb_requests in the free list for the video_pump async_wq - * thread to encode uvc buffers into. Otherwise we could get into a - * situation where the free list does not have any usb requests to - * encode into - we always end up queueing 0 length requests to the - * end point. - */ - unsigned int half_list_size = video->uvc_num_requests / 2; - - spin_lock_irqsave(&video->req_lock, flags); - /* - * Take these requests off the free list and queue them all to the - * endpoint. Since we queue 0 length requests with the req_lock held, - * there isn't any 'data' race involved here with the complete handler. - */ - while (count < half_list_size) { - req = list_first_entry(&video->req_free, struct usb_request, - list); - list_del(&req->list); - req->length = 0; - ret = uvcg_video_ep_queue(video, req); - if (ret < 0) { - uvcg_queue_cancel(&video->queue, 0); - break; - } - count++; - } - spin_unlock_irqrestore(&video->req_lock, flags); -} - static void uvc_video_complete(struct usb_ep *ep, struct usb_request *req) { @@ -373,12 +334,10 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) struct uvc_video *video = ureq->video; struct uvc_video_queue *queue = &video->queue; struct uvc_buffer *last_buf; - struct usb_request *to_queue = req; unsigned long flags; - bool is_bulk = video->max_payload_size; - int ret = 0; spin_lock_irqsave(&video->req_lock, flags); + atomic_dec(&video->queued); if (!video->is_enabled) { /* * When is_enabled is false, uvcg_video_disable() ensures @@ -438,51 +397,87 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) return; } + list_add_tail(&req->list, &video->req_free); /* - * Here we check whether any request is available in the ready - * list. If it is, queue it to the ep and add the current - * usb_request to the req_free list - for video_pump to fill in. - * Otherwise, just use the current usb_request to queue a 0 - * length request to the ep. Since we always add to the req_free - * list if we dequeue from the ready list, there will never - * be a situation where the req_free list is completely out of - * requests and cannot recover. + * Queue work to the wq as well since it is possible that a + * buffer may not have been completely encoded with the set of + * in-flight usb requests for whih the complete callbacks are + * firing. + * In that case, if we do not queue work to the worker thread, + * the buffer will never be marked as complete - and therefore + * not be returned to userpsace. As a result, + * dequeue -> queue -> dequeue flow of uvc buffers will not + * happen. Since there are is a new free request wake up the pump. */ - to_queue->length = 0; - if (!list_empty(&video->req_ready)) { - to_queue = list_first_entry(&video->req_ready, - struct usb_request, list); - list_del(&to_queue->list); - list_add_tail(&req->list, &video->req_free); + queue_work(video->async_wq, &video->pump); + + trace_uvcg_video_complete(req, atomic_read(&video->queued)); + + spin_unlock_irqrestore(&video->req_lock, flags); + + kthread_queue_work(video->kworker, &video->hw_submit); +} + +static void uvcg_video_hw_submit(struct kthread_work *work) +{ + struct uvc_video *video = container_of(work, struct uvc_video, hw_submit); + bool is_bulk = video->max_payload_size; + unsigned long flags; + struct usb_request *req; + int ret = 0; + + while (true) { + if (!video->ep->enabled) + return; + spin_lock_irqsave(&video->req_lock, flags); /* - * Queue work to the wq as well since it is possible that a - * buffer may not have been completely encoded with the set of - * in-flight usb requests for whih the complete callbacks are - * firing. - * In that case, if we do not queue work to the worker thread, - * the buffer will never be marked as complete - and therefore - * not be returned to userpsace. As a result, - * dequeue -> queue -> dequeue flow of uvc buffers will not - * happen. + * Here we check whether any request is available in the ready + * list. If it is, queue it to the ep and add the current + * usb_request to the req_free list - for video_pump to fill in. + * Otherwise, just use the current usb_request to queue a 0 + * length request to the ep. Since we always add to the req_free + * list if we dequeue from the ready list, there will never + * be a situation where the req_free list is completely out of + * requests and cannot recover. */ - queue_work(video->async_wq, &video->pump); - } - /* - * Queue to the endpoint. The actual queueing to ep will - * only happen on one thread - the async_wq for bulk endpoints - * and this thread for isoc endpoints. - */ - ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk); - if (ret < 0) { + if (!list_empty(&video->req_ready)) { + req = list_first_entry(&video->req_ready, + struct usb_request, list); + } else { + if (list_empty(&video->req_free) || + (atomic_read(&video->queued) > UVCG_REQ_MAX_ZERO_COUNT)) { + spin_unlock_irqrestore(&video->req_lock, flags); + + return; + } + req = list_first_entry(&video->req_free, struct usb_request, + list); + req->length = 0; + } + list_del(&req->list); + /* - * Endpoint error, but the stream is still enabled. - * Put request back in req_free for it to be cleaned - * up later. + * Queue to the endpoint. The actual queueing to ep will + * only happen on one thread - the async_wq for bulk endpoints + * and this thread for isoc endpoints. */ - list_add_tail(&to_queue->list, &video->req_free); - } + ret = uvcg_video_usb_req_queue(video, req, !is_bulk); + if (ret < 0) { + /* + * Endpoint error, but the stream is still enabled. + * Put request back in req_free for it to be cleaned + * up later. + */ + list_add_tail(&req->list, &video->req_free); + /* + * There is a new free request - wake up the pump. + */ + queue_work(video->async_wq, &video->pump); - spin_unlock_irqrestore(&video->req_lock, flags); + } + + spin_unlock_irqrestore(&video->req_lock, flags); + } } static int @@ -496,23 +491,71 @@ uvc_video_free_requests(struct uvc_video *video) INIT_LIST_HEAD(&video->ureqs); INIT_LIST_HEAD(&video->req_free); INIT_LIST_HEAD(&video->req_ready); - video->req_size = 0; return 0; } +static void +uvc_video_prep_requests(struct uvc_video *video) +{ + struct uvc_device *uvc = container_of(video, struct uvc_device, video); + struct usb_composite_dev *cdev = uvc->func.config->cdev; + unsigned int interval_duration = video->ep->desc->bInterval * 1250; + unsigned int max_req_size, req_size, header_size; + unsigned int nreq; + + max_req_size = video->ep->maxpacket + * max_t(unsigned int, video->ep->maxburst, 1) + * (video->ep->mult); + + if (!usb_endpoint_xfer_isoc(video->ep->desc)) { + video->req_size = max_req_size; + video->reqs_per_frame = video->uvc_num_requests = + DIV_ROUND_UP(video->imagesize, max_req_size); + + return; + } + + if (cdev->gadget->speed < USB_SPEED_HIGH) + interval_duration = video->ep->desc->bInterval * 10000; + + nreq = DIV_ROUND_UP(video->interval, interval_duration); + + header_size = nreq * UVCG_REQUEST_HEADER_LEN; + + req_size = DIV_ROUND_UP(video->imagesize + header_size, nreq); + + if (req_size > max_req_size) { + /* The prepared interval length and expected buffer size + * is not possible to stream with the currently configured + * isoc bandwidth. Fallback to the maximum. + */ + req_size = max_req_size; + } + video->req_size = req_size; + + /* We need to compensate the amount of requests to be + * allocated with the maximum amount of zero length requests. + * Since it is possible that hw_submit will initially + * enqueue some zero length requests and we then will not be + * able to fully encode one frame. + */ + video->uvc_num_requests = nreq + UVCG_REQ_MAX_ZERO_COUNT; + video->reqs_per_frame = nreq; +} + static int uvc_video_alloc_requests(struct uvc_video *video) { struct uvc_request *ureq; - unsigned int req_size; unsigned int i; int ret = -ENOMEM; - BUG_ON(video->req_size); - - req_size = video->ep->maxpacket - * max_t(unsigned int, video->ep->maxburst, 1) - * (video->ep->mult); + /* + * calculate in uvc_video_prep_requests + * - video->uvc_num_requests + * - video->req_size + */ + uvc_video_prep_requests(video); for (i = 0; i < video->uvc_num_requests; i++) { ureq = kzalloc(sizeof(struct uvc_request), GFP_KERNEL); @@ -523,7 +566,7 @@ uvc_video_alloc_requests(struct uvc_video *video) list_add_tail(&ureq->list, &video->ureqs); - ureq->req_buffer = kmalloc(req_size, GFP_KERNEL); + ureq->req_buffer = kmalloc(video->req_size, GFP_KERNEL); if (ureq->req_buffer == NULL) goto error; @@ -541,12 +584,10 @@ uvc_video_alloc_requests(struct uvc_video *video) list_add_tail(&ureq->req->list, &video->req_free); /* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */ sg_alloc_table(&ureq->sgt, - DIV_ROUND_UP(req_size - UVCG_REQUEST_HEADER_LEN, + DIV_ROUND_UP(video->req_size - UVCG_REQUEST_HEADER_LEN, PAGE_SIZE) + 2, GFP_KERNEL); } - video->req_size = req_size; - return 0; error: @@ -699,7 +740,6 @@ uvcg_video_disable(struct uvc_video *video) INIT_LIST_HEAD(&video->ureqs); INIT_LIST_HEAD(&video->req_free); INIT_LIST_HEAD(&video->req_ready); - video->req_size = 0; spin_unlock_irqrestore(&video->req_lock, flags); /* @@ -752,7 +792,9 @@ int uvcg_video_enable(struct uvc_video *video) video->req_int_count = 0; - uvc_video_ep_queue_initial_requests(video); + atomic_set(&video->queued, 0); + + kthread_queue_work(video->kworker, &video->hw_submit); queue_work(video->async_wq, &video->pump); return ret; @@ -775,12 +817,24 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) if (!video->async_wq) return -EINVAL; + /* Allocate a kthread for asynchronous hw submit handler. */ + video->kworker = kthread_create_worker(0, "UVCG"); + if (IS_ERR(video->kworker)) { + uvcg_err(&video->uvc->func, "failed to create UVCG kworker\n"); + return PTR_ERR(video->kworker); + } + + kthread_init_work(&video->hw_submit, uvcg_video_hw_submit); + + sched_set_fifo(video->kworker->task); + video->uvc = uvc; video->fcc = V4L2_PIX_FMT_YUYV; video->bpp = 16; video->width = 320; video->height = 240; video->imagesize = 320 * 240 * 2; + video->interval = 666666; /* Initialize the video buffers queue. */ uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent, diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index 4ca67b2f8f2437..3684546e8801d4 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -261,7 +261,7 @@ static struct usb_composite_driver hidg_driver = { }; static struct platform_driver hidg_plat_driver = { - .remove_new = hidg_plat_driver_remove, + .remove = hidg_plat_driver_remove, .driver = { .name = "hidg", }, diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c index 112fd18d8c99dc..20165e1582d9ba 100644 --- a/drivers/usb/gadget/legacy/raw_gadget.c +++ b/drivers/usb/gadget/legacy/raw_gadget.c @@ -782,7 +782,7 @@ static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value) if (ret < 0) goto free; - length = min(io.length, (unsigned int)ret); + length = min_t(unsigned int, io.length, ret); if (copy_to_user((void __user *)(value + sizeof(io)), data, length)) ret = -EFAULT; else @@ -1168,7 +1168,7 @@ static int raw_ioctl_ep_read(struct raw_dev *dev, unsigned long value) if (ret < 0) goto free; - length = min(io.length, (unsigned int)ret); + length = min_t(unsigned int, io.length, ret); if (copy_to_user((void __user *)(value + sizeof(io)), data, length)) ret = -EFAULT; else diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c index f60a019bb17301..f2685f89b3e50a 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/core.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c @@ -428,7 +428,7 @@ MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids); static struct platform_driver ast_vhub_driver = { .probe = ast_vhub_probe, - .remove_new = ast_vhub_remove, + .remove = ast_vhub_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = ast_vhub_dt_ids, diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c index f4781e611aaa29..353bfb1ff0a12b 100644 --- a/drivers/usb/gadget/udc/aspeed_udc.c +++ b/drivers/usb/gadget/udc/aspeed_udc.c @@ -156,7 +156,7 @@ #define AST_EP_DMA_DESC_PID_DATA1 (2 << 14) #define AST_EP_DMA_DESC_PID_MDATA (3 << 14) #define EP_DESC1_IN_LEN(x) ((x) & 0x1fff) -#define AST_EP_DMA_DESC_MAX_LEN (7680) /* Max packet length for trasmit in 1 desc */ +#define AST_EP_DMA_DESC_MAX_LEN (7680) /* Max packet length for transmit in 1 desc */ struct ast_udc_request { struct usb_request req; @@ -1590,7 +1590,7 @@ MODULE_DEVICE_TABLE(of, ast_udc_of_dt_ids); static struct platform_driver ast_udc_driver = { .probe = ast_udc_probe, - .remove_new = ast_udc_remove, + .remove = ast_udc_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = ast_udc_of_dt_ids, diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index e3bf17a98b3806..e3af4ec3794e2e 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -2002,7 +2002,7 @@ static int at91udc_resume(struct platform_device *pdev) static struct platform_driver at91_udc_driver = { .probe = at91udc_probe, - .remove_new = at91udc_remove, + .remove = at91udc_remove, .shutdown = at91udc_shutdown, .suspend = at91udc_suspend, .resume = at91udc_resume, diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 4928eba1932721..0c6f2ad81d37f5 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2444,7 +2444,7 @@ static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume); static struct platform_driver udc_driver = { .probe = usba_udc_probe, - .remove_new = usba_udc_remove, + .remove = usba_udc_remove, .driver = { .name = "atmel_usba_udc", .pm = &usba_udc_pm_ops, diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index da7011d906e01d..502612a5650e72 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -2367,7 +2367,7 @@ static void bcm63xx_udc_remove(struct platform_device *pdev) static struct platform_driver bcm63xx_udc_driver = { .probe = bcm63xx_udc_probe, - .remove_new = bcm63xx_udc_remove, + .remove = bcm63xx_udc_remove, .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index 5149e2b7f05087..5c3d8b64c0e76e 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -648,7 +648,7 @@ static struct platform_driver bdc_driver = { .of_match_table = bdc_of_match, }, .probe = bdc_probe, - .remove_new = bdc_remove, + .remove = bdc_remove, }; module_platform_driver(bdc_driver); diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-pci.c b/drivers/usb/gadget/udc/cdns2/cdns2-pci.c index b1a8f772467c0d..e589593b4cbf89 100644 --- a/drivers/usb/gadget/udc/cdns2/cdns2-pci.c +++ b/drivers/usb/gadget/udc/cdns2/cdns2-pci.c @@ -15,7 +15,6 @@ #include "cdns2-gadget.h" #define PCI_DRIVER_NAME "cdns-pci-usbhs" -#define PCI_DEVICE_ID_CDNS_USB2 0x0120 #define PCI_BAR_DEV 0 #define PCI_DEV_FN_DEVICE 0 @@ -113,7 +112,7 @@ static const struct dev_pm_ops cdns2_pci_pm_ops = { }; static const struct pci_device_id cdns2_pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB2), + { PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB), .class = PCI_CLASS_SERIAL_USB_DEVICE }, { 0, } }; diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 081ac7683c0b35..a7e8fa45776b5c 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -80,7 +80,7 @@ module_param_named(num, mod_data.num, uint, S_IRUGO); MODULE_PARM_DESC(num, "number of emulated controllers"); /*-------------------------------------------------------------------------*/ -/* gadget side driver data structres */ +/* gadget side driver data structures */ struct dummy_ep { struct list_head queue; unsigned long last_io; /* jiffies timestamp */ @@ -1152,7 +1152,7 @@ static int dummy_udc_resume(struct platform_device *pdev) static struct platform_driver dummy_udc_driver = { .probe = dummy_udc_probe, - .remove_new = dummy_udc_remove, + .remove = dummy_udc_remove, .suspend = dummy_udc_suspend, .resume = dummy_udc_resume, .driver = { @@ -2769,7 +2769,7 @@ static int dummy_hcd_resume(struct platform_device *pdev) static struct platform_driver dummy_hcd_driver = { .probe = dummy_hcd_probe, - .remove_new = dummy_hcd_remove, + .remove = dummy_hcd_remove, .suspend = dummy_hcd_suspend, .resume = dummy_hcd_resume, .driver = { diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 4e88681a79b633..aacfde06387c0b 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -511,7 +511,7 @@ static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num) out_8(&epparam->tbmr, rtfcr); tmp = (u16)(ep->ep.maxpacket + USB_CRC_SIZE); - /* MRBLR must be divisble by 4 */ + /* MRBLR must be divisible by 4 */ tmp = (u16)(((tmp >> 2) << 2) + 4); out_be16(&epparam->mrblr, tmp); @@ -1413,7 +1413,7 @@ static int ep_txframe_handle(struct qe_ep *ep) return 0; } -/* confirm the already trainsmited bd */ +/* confirm the already transmitted bd */ static int qe_ep_txconf(struct qe_ep *ep) { struct qe_bd __iomem *bd; @@ -2196,7 +2196,7 @@ static int tx_irq(struct qe_udc *udc) } -/* setup packect's rx is handle in the function too */ +/* setup packet's rx is handle in the function too */ static void rx_irq(struct qe_udc *udc) { struct qe_ep *ep; @@ -2704,7 +2704,7 @@ static struct platform_driver udc_driver = { .of_match_table = qe_udc_match, }, .probe = qe_udc_probe, - .remove_new = qe_udc_remove, + .remove = qe_udc_remove, #ifdef CONFIG_PM .suspend = qe_udc_suspend, .resume = qe_udc_resume, diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 0cabd4eee6acb5..8b7f7f96177459 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2685,7 +2685,7 @@ MODULE_DEVICE_TABLE(of, fsl_udc_dt_ids); static struct platform_driver udc_driver = { .probe = fsl_udc_probe, - .remove_new = fsl_udc_remove, + .remove = fsl_udc_remove, .id_table = fsl_udc_devtype, /* these suspend and resume are not usb suspend and resume */ .suspend = fsl_udc_suspend, diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c index 873265634cccb7..5e94a99b3e5393 100644 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ b/drivers/usb/gadget/udc/fusb300_udc.c @@ -1297,7 +1297,7 @@ static void init_controller(struct fusb300 *fusb300) reg |= val; iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR); - /*set u1 u2 timmer*/ + /*set u1 u2 timer*/ fusb300_set_u2_timeout(fusb300, 0xff); fusb300_set_u1_timeout(fusb300, 0xff); @@ -1507,7 +1507,7 @@ static int fusb300_probe(struct platform_device *pdev) static struct platform_driver fusb300_driver = { .probe = fusb300_probe, - .remove_new = fusb300_remove, + .remove = fusb300_remove, .driver = { .name = udc_name, }, diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index fb901be5dac1b7..bf5b3c964c1870 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -2249,7 +2249,7 @@ static struct platform_driver gr_driver = { .of_match_table = gr_match, }, .probe = gr_probe, - .remove_new = gr_remove, + .remove = gr_remove, }; module_platform_driver(gr_driver); diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 3bfd889ed56a47..89d6daf2bda7a3 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -3249,7 +3249,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match); static struct platform_driver lpc32xx_udc_driver = { .probe = lpc32xx_udc_probe, - .remove_new = lpc32xx_udc_remove, + .remove = lpc32xx_udc_remove, .shutdown = lpc32xx_udc_shutdown, .suspend = lpc32xx_udc_suspend, .resume = lpc32xx_udc_resume, diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index bfaa5291e6c83b..a938b2af0944bc 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1688,7 +1688,7 @@ static int m66592_probe(struct platform_device *pdev) /*-------------------------------------------------------------------------*/ static struct platform_driver m66592_driver = { .probe = m66592_probe, - .remove_new = m66592_remove, + .remove = m66592_remove, .driver = { .name = udc_name, }, diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index e1dd5cf25d08a0..062f43e146aaac 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -2047,7 +2047,7 @@ static void mv_u3d_shutdown(struct platform_device *dev) static struct platform_driver mv_u3d_driver = { .probe = mv_u3d_probe, - .remove_new = mv_u3d_remove, + .remove = mv_u3d_remove, .shutdown = mv_u3d_shutdown, .driver = { .name = "mv-u3d", diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 71012b28289105..ff103e6b3048f5 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -2409,7 +2409,7 @@ static void mv_udc_shutdown(struct platform_device *pdev) static struct platform_driver udc_driver = { .probe = mv_udc_probe, - .remove_new = mv_udc_remove, + .remove = mv_udc_remove, .shutdown = mv_udc_shutdown, .driver = { .name = "mv-udc", diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 9230db57dab7a6..7ecddbf5c90db5 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -2097,7 +2097,7 @@ static irqreturn_t net2272_irq(int irq, void *_dev) } /* check dma interrupts */ #endif - /* Platform/devcice interrupt handler */ + /* Platform/device interrupt handler */ #if !defined(PLX_PCI_RDK) net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); @@ -2685,7 +2685,7 @@ net2272_plat_remove(struct platform_device *pdev) static struct platform_driver net2272_plat_driver = { .probe = net2272_plat_probe, - .remove_new = net2272_plat_remove, + .remove = net2272_plat_remove, .driver = { .name = driver_name, }, diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index 61a45e4657d5d4..698463bf697b29 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -576,13 +576,13 @@ static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status) static void next_out_dma(struct omap_ep *ep, struct omap_req *req) { - unsigned packets = req->req.length - req->req.actual; + unsigned int packets = req->req.length - req->req.actual; int dma_trigger = 0; u16 w; /* set up this DMA transfer, enable the fifo, start */ packets /= ep->ep.maxpacket; - packets = min(packets, (unsigned)UDC_RXN_TC + 1); + packets = min_t(unsigned int, packets, UDC_RXN_TC + 1); req->dma_bytes = packets * ep->ep.maxpacket; omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, ep->ep.maxpacket >> 1, packets, @@ -2980,7 +2980,7 @@ static int omap_udc_resume(struct platform_device *dev) static struct platform_driver udc_driver = { .probe = omap_udc_probe, - .remove_new = omap_udc_remove, + .remove = omap_udc_remove, .suspend = omap_udc_suspend, .resume = omap_udc_resume, .driver = { diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 7c96fc9f680f1b..1e9998024aaa3c 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -2474,7 +2474,7 @@ static int pxa25x_udc_resume(struct platform_device *dev) static struct platform_driver udc_driver = { .shutdown = pxa25x_udc_shutdown, .probe = pxa25x_udc_probe, - .remove_new = pxa25x_udc_remove, + .remove = pxa25x_udc_remove, .suspend = pxa25x_udc_suspend, .resume = pxa25x_udc_resume, .driver = { diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 1a6317e4b2a323..f9a55d4f189f43 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2355,18 +2355,19 @@ static int pxa_udc_probe(struct platform_device *pdev) struct pxa_udc *udc = &memory; int retval = 0, gpio; struct pxa2xx_udc_mach_info *mach = dev_get_platdata(&pdev->dev); - unsigned long gpio_flags; if (mach) { - gpio_flags = mach->gpio_pullup_inverted ? GPIOF_ACTIVE_LOW : 0; gpio = mach->gpio_pullup; if (gpio_is_valid(gpio)) { retval = devm_gpio_request_one(&pdev->dev, gpio, - gpio_flags, + GPIOF_OUT_INIT_LOW, "USB D+ pullup"); if (retval) return retval; udc->gpiod = gpio_to_desc(mach->gpio_pullup); + + if (mach->gpio_pullup_inverted ^ gpiod_is_active_low(udc->gpiod)) + gpiod_toggle_active_low(udc->gpiod); } udc->udc_command = mach->udc_command; } else { @@ -2538,7 +2539,7 @@ static struct platform_driver udc_driver = { .of_match_table = of_match_ptr(udc_pxa_dt_ids), }, .probe = pxa_udc_probe, - .remove_new = pxa_udc_remove, + .remove = pxa_udc_remove, .shutdown = pxa_udc_shutdown, #ifdef CONFIG_PM .suspend = pxa_udc_suspend, diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index db4a10a979f9db..ff6f846b1d411c 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1965,7 +1965,7 @@ static int r8a66597_probe(struct platform_device *pdev) /*-------------------------------------------------------------------------*/ static struct platform_driver r8a66597_driver = { .probe = r8a66597_probe, - .remove_new = r8a66597_remove, + .remove = r8a66597_remove, .driver = { .name = udc_name, }, diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 3b01734ce1b7e5..fce5c41d9f298b 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -3013,7 +3013,7 @@ static SIMPLE_DEV_PM_OPS(renesas_usb3_pm_ops, renesas_usb3_suspend, static struct platform_driver renesas_usb3_driver = { .probe = renesas_usb3_probe, - .remove_new = renesas_usb3_remove, + .remove = renesas_usb3_remove, .driver = { .name = udc_name, .pm = &renesas_usb3_pm_ops, diff --git a/drivers/usb/gadget/udc/renesas_usbf.c b/drivers/usb/gadget/udc/renesas_usbf.c index 657f265ac7cc57..14f4b2cf05a485 100644 --- a/drivers/usb/gadget/udc/renesas_usbf.c +++ b/drivers/usb/gadget/udc/renesas_usbf.c @@ -2482,7 +2482,7 @@ static int usbf_handle_ep0_setup(struct usbf_ep *ep0) ep0->delayed_status = 0; if ((crq.ctrlreq.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) { - /* This is not a USB standard request -> delelate */ + /* This is not a USB standard request -> delegate */ goto delegate; } @@ -3381,7 +3381,7 @@ static struct platform_driver udc_driver = { .of_match_table = usbf_match, }, .probe = usbf_probe, - .remove_new = usbf_remove, + .remove = usbf_remove, }; module_platform_driver(udc_driver); diff --git a/drivers/usb/gadget/udc/rzv2m_usb3drd.c b/drivers/usb/gadget/udc/rzv2m_usb3drd.c index 36f4ff00d22fdb..4692eae89f4435 100644 --- a/drivers/usb/gadget/udc/rzv2m_usb3drd.c +++ b/drivers/usb/gadget/udc/rzv2m_usb3drd.c @@ -127,7 +127,7 @@ static struct platform_driver rzv2m_usb3drd_driver = { .of_match_table = rzv2m_usb3drd_of_match, }, .probe = rzv2m_usb3drd_probe, - .remove_new = rzv2m_usb3drd_remove, + .remove = rzv2m_usb3drd_remove, }; module_platform_driver(rzv2m_usb3drd_driver); diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index cd89532adec262..1f8a99d2a64363 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -2707,7 +2707,7 @@ static irqreturn_t udc_control_in_isr(struct udc *dev) /* write fifo */ udc_txfifo_write(ep, &req->req); - /* lengh bytes transferred */ + /* length bytes transferred */ len = req->req.length - req->req.actual; if (len > ep->ep.maxpacket) len = ep->ep.maxpacket; diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c index ba5a0669050779..db842a6de643de 100644 --- a/drivers/usb/gadget/udc/snps_udc_plat.c +++ b/drivers/usb/gadget/udc/snps_udc_plat.c @@ -309,7 +309,7 @@ MODULE_DEVICE_TABLE(of, of_udc_match); static struct platform_driver udc_plat_driver = { .probe = udc_plat_probe, - .remove_new = udc_plat_remove, + .remove = udc_plat_remove, .driver = { .name = "snps-udc-plat", .of_match_table = of_udc_match, diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 7aa46d426f31b2..c7fdbc55fb0b97 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -4071,7 +4071,7 @@ static const struct dev_pm_ops tegra_xudc_pm_ops = { static struct platform_driver tegra_xudc_driver = { .probe = tegra_xudc_probe, - .remove_new = tegra_xudc_remove, + .remove = tegra_xudc_remove, .driver = { .name = "tegra-xudc", .pm = &tegra_xudc_pm_ops, diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index ebc45565c33e54..ae2aeb2718977d 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -2258,7 +2258,7 @@ static struct platform_driver xudc_driver = { .pm = &xudc_pm_ops, }, .probe = xudc_probe, - .remove_new = xudc_remove, + .remove = xudc_remove, }; module_platform_driver(xudc_driver); diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 75f6f99f8173ed..37a2f1b61cbab3 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -55,7 +55,7 @@ usb_gadget_get_string (const struct usb_gadget_strings *table, int id, u8 *buf) return -EINVAL; /* string descriptors have length, tag, then UTF16-LE text */ - len = min((size_t)USB_MAX_STRING_LEN, strlen(s->s)); + len = min_t(size_t, USB_MAX_STRING_LEN, strlen(s->s)); len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN, (wchar_t *) &buf[2], USB_MAX_STRING_LEN); if (len < 0) diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 7558cc4d90cc66..519386255886c5 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 6a6e1c510b2838..65747270fd88d0 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -220,7 +220,7 @@ static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend, static struct platform_driver ehci_atmel_driver = { .probe = ehci_atmel_drv_probe, - .remove_new = ehci_atmel_drv_remove, + .remove = ehci_atmel_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "atmel-ehci", diff --git a/drivers/usb/host/ehci-brcm.c b/drivers/usb/host/ehci-brcm.c index 68cad0620f1a93..888e8f6670d2a1 100644 --- a/drivers/usb/host/ehci-brcm.c +++ b/drivers/usb/host/ehci-brcm.c @@ -250,7 +250,7 @@ MODULE_DEVICE_TABLE(of, brcm_ehci_of_match); static struct platform_driver ehci_brcm_driver = { .probe = ehci_brcm_probe, - .remove_new = ehci_brcm_remove, + .remove = ehci_brcm_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ehci-brcm", diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index e3a961d3f5fc96..d2a5bedf736a2f 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE(of, exynos_ehci_match); static struct platform_driver exynos_ehci_driver = { .probe = exynos_ehci_probe, - .remove_new = exynos_ehci_remove, + .remove = exynos_ehci_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "exynos-ehci", diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 5b1ce394a4174d..26f13278d4d698 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -706,7 +706,7 @@ static void fsl_ehci_drv_remove(struct platform_device *pdev) static struct platform_driver ehci_fsl_driver = { .probe = fsl_ehci_drv_probe, - .remove_new = fsl_ehci_drv_remove, + .remove = fsl_ehci_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = DRV_NAME, diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index 14150e4d338265..bd9762eaa13529 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -168,7 +168,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match); static struct platform_driver ehci_grlib_driver = { .probe = ehci_hcd_grlib_probe, - .remove_new = ehci_hcd_grlib_remove, + .remove = ehci_hcd_grlib_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "grlib-ehci", diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index cbc0b86fcc365e..6de79ac5e6a442 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -547,7 +547,7 @@ static int ehci_init(struct usb_hcd *hcd) * make problems: throughput reduction (!), data errors... */ if (park) { - park = min(park, (unsigned) 3); + park = min_t(unsigned int, park, 3); temp |= CMD_PARK; temp |= park << 8; } diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 2f1fc7eb8b727f..cbabbe10717210 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -279,7 +279,7 @@ static const struct of_device_id ehci_mv_dt_ids[] = { static struct platform_driver ehci_mv_driver = { .probe = mv_ehci_probe, - .remove_new = mv_ehci_remove, + .remove = mv_ehci_remove, .shutdown = mv_ehci_shutdown, .driver = { .name = "mv-ehci", diff --git a/drivers/usb/host/ehci-npcm7xx.c b/drivers/usb/host/ehci-npcm7xx.c index 3d3317a1a0b3fd..f1c7034c1e80d7 100644 --- a/drivers/usb/host/ehci-npcm7xx.c +++ b/drivers/usb/host/ehci-npcm7xx.c @@ -122,7 +122,7 @@ MODULE_DEVICE_TABLE(of, npcm7xx_ehci_id_table); static struct platform_driver npcm7xx_ehci_hcd_driver = { .probe = npcm7xx_ehci_hcd_drv_probe, - .remove_new = npcm7xx_ehci_hcd_drv_remove, + .remove = npcm7xx_ehci_hcd_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "npcm7xx-ehci", diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index b24f371a46f3ec..db4a1acb27dae7 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids); static struct platform_driver ehci_hcd_omap_driver = { .probe = ehci_hcd_omap_probe, - .remove_new = ehci_hcd_omap_remove, + .remove = ehci_hcd_omap_remove, .shutdown = usb_hcd_platform_shutdown, /*.suspend = ehci_hcd_omap_suspend, */ /*.resume = ehci_hcd_omap_resume, */ diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index ad145a54ca74e4..34abff8669f8bf 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -352,7 +352,7 @@ MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids); static struct platform_driver ehci_orion_driver = { .probe = ehci_orion_drv_probe, - .remove_new = ehci_orion_drv_remove, + .remove = ehci_orion_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "orion-ehci", diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 98b073185e1c73..cdf41886e8cafa 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -508,7 +508,7 @@ static SIMPLE_DEV_PM_OPS(ehci_platform_pm_ops, ehci_platform_suspend, static struct platform_driver ehci_platform_driver = { .id_table = ehci_platform_table, .probe = ehci_platform_probe, - .remove_new = ehci_platform_remove, + .remove = ehci_platform_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ehci-platform", diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 7fd83e806ae466..8063b9d3aebd08 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -230,7 +230,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match); static struct platform_driver ehci_hcd_ppc_of_driver = { .probe = ehci_hcd_ppc_of_probe, - .remove_new = ehci_hcd_ppc_of_remove, + .remove = ehci_hcd_ppc_of_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ppc-of-ehci", diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index d31d9506e41ab0..2d23690d72c507 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -119,8 +119,12 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) if (IS_ERR(priv->iclk)) priv->iclk = NULL; - clk_enable(priv->fclk); - clk_enable(priv->iclk); + ret = clk_enable(priv->fclk); + if (ret) + goto fail_request_resource; + ret = clk_enable(priv->iclk); + if (ret) + goto fail_iclk; ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret != 0) { @@ -136,6 +140,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) fail_add_hcd: clk_disable(priv->iclk); +fail_iclk: clk_disable(priv->fclk); fail_request_resource: @@ -169,7 +174,7 @@ static void ehci_hcd_sh_shutdown(struct platform_device *pdev) static struct platform_driver ehci_hcd_sh_driver = { .probe = ehci_hcd_sh_probe, - .remove_new = ehci_hcd_sh_remove, + .remove = ehci_hcd_sh_remove, .shutdown = ehci_hcd_sh_shutdown, .driver = { .name = "sh_ehci", diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index d0e94e4c9fe274..e96710192d6b02 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -105,7 +105,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) /* registers start at offset 0x0 */ hcd_to_ehci(hcd)->caps = hcd->regs; - clk_prepare_enable(sehci->clk); + retval = clk_prepare_enable(sehci->clk); + if (retval) + goto err_put_hcd; retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) goto err_stop_ehci; @@ -130,8 +132,7 @@ static void spear_ehci_hcd_drv_remove(struct platform_device *pdev) usb_remove_hcd(hcd); - if (sehci->clk) - clk_disable_unprepare(sehci->clk); + clk_disable_unprepare(sehci->clk); usb_put_hcd(hcd); } @@ -143,7 +144,7 @@ MODULE_DEVICE_TABLE(of, spear_ehci_id_table); static struct platform_driver spear_ehci_hcd_driver = { .probe = spear_ehci_hcd_drv_probe, - .remove_new = spear_ehci_hcd_drv_remove, + .remove = spear_ehci_hcd_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "spear-ehci", diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c index 2dbb0d86daaaa9..58867d816af756 100644 --- a/drivers/usb/host/ehci-st.c +++ b/drivers/usb/host/ehci-st.c @@ -320,7 +320,7 @@ MODULE_DEVICE_TABLE(of, st_ehci_ids); static struct platform_driver ehci_platform_driver = { .probe = st_ehci_platform_probe, - .remove_new = st_ehci_platform_remove, + .remove = st_ehci_platform_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "st-ehci", diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index a2112c28f63146..1d16cfefabd716 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -220,7 +220,7 @@ MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match); static struct platform_driver ehci_hcd_xilinx_of_driver = { .probe = ehci_hcd_xilinx_of_probe, - .remove_new = ehci_hcd_xilinx_of_remove, + .remove = ehci_hcd_xilinx_of_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xilinx-of-ehci", diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 9a1b5224f2396e..22a0942f0bcee6 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -791,7 +791,7 @@ static struct platform_driver of_fhci_driver = { .of_match_table = of_fhci_match, }, .probe = of_fhci_probe, - .remove_new = of_fhci_remove, + .remove = of_fhci_remove, }; module_platform_driver(of_fhci_driver); diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index a45ede80edfcd1..c3acd410ce948c 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -158,7 +158,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td) struct packet *pkt; u8 *data = NULL; - /* calcalate data address,len and toggle and then add the transaction */ + /* calculate data address,len and toggle and then add the transaction */ if (td->toggle == USB_TD_TOGGLE_CARRY) td->toggle = ed->toggle_carry; @@ -679,7 +679,7 @@ static void process_done_list(unsigned long data) DECLARE_TASKLET_OLD(fhci_tasklet, process_done_list); -/* transfer complted callback */ +/* transfer completed callback */ u32 fhci_transfer_confirm_callback(struct fhci_hcd *fhci) { if (!fhci->process_done_task->state) diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 6cdc3d805c32a5..4e67b947198604 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -362,7 +362,7 @@ static struct platform_driver fsl_usb2_mph_dr_driver = { .of_match_table = fsl_usb2_mph_dr_of_match, }, .probe = fsl_usb2_mph_dr_of_probe, - .remove_new = fsl_usb2_mph_dr_of_remove, + .remove = fsl_usb2_mph_dr_of_remove, }; module_platform_driver(fsl_usb2_mph_dr_driver); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index a82d8926e922c4..71c22c4bd16353 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1684,7 +1684,7 @@ MODULE_ALIAS("platform:isp116x-hcd"); static struct platform_driver isp116x_driver = { .probe = isp116x_probe, - .remove_new = isp116x_remove, + .remove = isp116x_remove, .suspend = isp116x_suspend, .resume = isp116x_resume, .driver = { diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 31059c8f94e63f..2d3a082cb52f82 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2757,7 +2757,7 @@ static int isp1362_resume(struct platform_device *pdev) static struct platform_driver isp1362_driver = { .probe = isp1362_probe, - .remove_new = isp1362_remove, + .remove = isp1362_remove, .suspend = isp1362_suspend, .resume = isp1362_resume, diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 9fe4f48b18980c..0881fdd1823e0b 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -779,11 +779,17 @@ max3421_check_unlink(struct usb_hcd *hcd) retval = 1; dev_dbg(&spi->dev, "%s: URB %p unlinked=%d", __func__, urb, urb->unlinked); - usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock_irqrestore(&max3421_hcd->lock, - flags); - usb_hcd_giveback_urb(hcd, urb, 0); - spin_lock_irqsave(&max3421_hcd->lock, flags); + if (urb == max3421_hcd->curr_urb) { + max3421_hcd->urb_done = 1; + max3421_hcd->hien &= ~(BIT(MAX3421_HI_HXFRDN_BIT) | + BIT(MAX3421_HI_RCVDAV_BIT)); + } else { + usb_hcd_unlink_urb_from_ep(hcd, urb); + spin_unlock_irqrestore(&max3421_hcd->lock, + flags); + usb_hcd_giveback_urb(hcd, urb, 0); + spin_lock_irqsave(&max3421_hcd->lock, flags); + } } } } diff --git a/drivers/usb/host/octeon-hcd.c b/drivers/usb/host/octeon-hcd.c index 19d5777f5db25c..361d33b0c4d29a 100644 --- a/drivers/usb/host/octeon-hcd.c +++ b/drivers/usb/host/octeon-hcd.c @@ -3346,7 +3346,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case USB_PORT_FEAT_INDICATOR: dev_dbg(dev, " INDICATOR\n"); - /* Port inidicator not supported */ + /* Port indicator not supported */ break; case USB_PORT_FEAT_C_CONNECTION: dev_dbg(dev, " C_CONNECTION\n"); @@ -3711,8 +3711,8 @@ static struct platform_driver octeon_usb_driver = { .name = "octeon-hcd", .of_match_table = octeon_usb_match, }, - .probe = octeon_usb_probe, - .remove_new = octeon_usb_remove, + .probe = octeon_usb_probe, + .remove = octeon_usb_remove, }; static int __init octeon_usb_driver_init(void) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index f691cd98a57466..5df793dcb25dac 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -685,7 +685,7 @@ static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend, static struct platform_driver ohci_hcd_at91_driver = { .probe = ohci_hcd_at91_drv_probe, - .remove_new = ohci_hcd_at91_drv_remove, + .remove = ohci_hcd_at91_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "at91_ohci", diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index d2b67da76762c6..3c5ca2d7c92ed7 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -531,7 +531,7 @@ static const struct ohci_driver_overrides da8xx_overrides __initconst = { */ static struct platform_driver ohci_hcd_da8xx_driver = { .probe = ohci_da8xx_probe, - .remove_new = ohci_da8xx_remove, + .remove = ohci_da8xx_remove, .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_da8xx_suspend, diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 1379e03644b2a3..cc5cb09009880a 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -262,7 +262,7 @@ MODULE_DEVICE_TABLE(of, exynos_ohci_match); static struct platform_driver exynos_ohci_driver = { .probe = exynos_ohci_probe, - .remove_new = exynos_ohci_remove, + .remove = exynos_ohci_remove, .shutdown = exynos_ohci_shutdown, .driver = { .name = "exynos-ohci", diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 5b775e1ea52707..24d5a1dc505604 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -254,7 +254,7 @@ static struct platform_driver ohci_hcd_nxp_driver = { .of_match_table = of_match_ptr(ohci_hcd_nxp_match), }, .probe = ohci_hcd_nxp_probe, - .remove_new = ohci_hcd_nxp_remove, + .remove = ohci_hcd_nxp_remove, }; static int __init ohci_nxp_init(void) diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 21a6f6c55e079e..f6e56c4b991485 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -152,7 +152,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) rh &= ~RH_A_NOCP; - /* gpio9 for overcurrent detction */ + /* gpio9 for overcurrent detection */ omap_cfg_reg(W8_1610_GPIO9); /* for paranoia's sake: disable USB.PUEN */ @@ -390,7 +390,7 @@ static int ohci_omap_resume(struct platform_device *dev) */ static struct platform_driver ohci_hcd_omap_driver = { .probe = ohci_hcd_omap_probe, - .remove_new = ohci_hcd_omap_remove, + .remove = ohci_hcd_omap_remove, .shutdown = usb_hcd_platform_shutdown, #ifdef CONFIG_PM .suspend = ohci_omap_suspend, diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 4a75507325ddcd..f47ae12cde6a26 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -344,7 +344,7 @@ static const struct dev_pm_ops ohci_platform_pm_ops = { static struct platform_driver ohci_platform_driver = { .id_table = ohci_platform_table, .probe = ohci_platform_probe, - .remove_new = ohci_platform_remove, + .remove = ohci_platform_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ohci-platform", diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index a6be061f86532b..acd0a0e398a430 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -219,7 +219,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); static struct platform_driver ohci_hcd_ppc_of_driver = { .probe = ohci_hcd_ppc_of_probe, - .remove_new = ohci_hcd_ppc_of_remove, + .remove = ohci_hcd_ppc_of_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ppc-of-ohci", diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 3348c25ddb18d2..45d026e85168b4 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -569,7 +569,7 @@ static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = { static struct platform_driver ohci_hcd_pxa27x_driver = { .probe = ohci_hcd_pxa27x_probe, - .remove_new = ohci_hcd_pxa27x_remove, + .remove = ohci_hcd_pxa27x_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "pxa27x-ohci", diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index c5c9b4cbcb9a3c..66d970854357d3 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -457,7 +457,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_s3c2410_dt_ids); static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_probe, - .remove_new = ohci_hcd_s3c2410_remove, + .remove = ohci_hcd_s3c2410_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "s3c2410-ohci", diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index 4b39e9d6f33a98..843a5378764e6b 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -252,7 +252,7 @@ static int ohci_sm501_resume(struct platform_device *pdev) */ static struct platform_driver ohci_hcd_sm501_driver = { .probe = ohci_hcd_sm501_drv_probe, - .remove_new = ohci_hcd_sm501_drv_remove, + .remove = ohci_hcd_sm501_drv_remove, .shutdown = usb_hcd_platform_shutdown, .suspend = ohci_sm501_suspend, .resume = ohci_sm501_resume, diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 993f347c5c2884..d7131e5a4477c4 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -157,7 +157,7 @@ MODULE_DEVICE_TABLE(of, spear_ohci_id_table); /* Driver definition to register with the platform bus */ static struct platform_driver spear_ohci_hcd_driver = { .probe = spear_ohci_hcd_drv_probe, - .remove_new = spear_ohci_hcd_drv_remove, + .remove = spear_ohci_hcd_drv_remove, #ifdef CONFIG_PM .suspend = spear_ohci_hcd_drv_suspend, .resume = spear_ohci_hcd_drv_resume, diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c index 214342013f7ec4..d1656fce540047 100644 --- a/drivers/usb/host/ohci-st.c +++ b/drivers/usb/host/ohci-st.c @@ -298,7 +298,7 @@ MODULE_DEVICE_TABLE(of, st_ohci_platform_ids); static struct platform_driver ohci_platform_driver = { .probe = st_ohci_platform_probe, - .remove_new = st_ohci_platform_remove, + .remove = st_ohci_platform_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "st-ohci", diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index ca3859463ba141..a6c20facf94501 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -885,7 +885,7 @@ static int oxu_buf_alloc(struct oxu_hcd *oxu, struct ehci_qtd *qtd, int len) int a_blocks; /* blocks allocated */ int i, j; - /* Don't allocte bigger than supported */ + /* Don't allocate bigger than supported */ if (len > BUFFER_SIZE * BUFFER_NUM) { oxu_err(oxu, "buffer too big (%d)\n", len); return -ENOMEM; @@ -902,7 +902,7 @@ static int oxu_buf_alloc(struct oxu_hcd *oxu, struct ehci_qtd *qtd, int len) /* Find a suitable available data buffer */ for (i = 0; i < BUFFER_NUM; - i += max(a_blocks, (int)oxu->db_used[i])) { + i += max_t(int, a_blocks, oxu->db_used[i])) { /* Check all the required blocks are available */ for (j = 0; j < a_blocks; j++) @@ -3040,7 +3040,7 @@ static int oxu_hcd_init(struct usb_hcd *hcd) * make problems: throughput reduction (!), data errors... */ if (park) { - park = min(park, (unsigned) 3); + park = min_t(unsigned int, park, 3); temp |= CMD_PARK; temp |= park << 8; } @@ -4289,7 +4289,7 @@ static int oxu_drv_resume(struct device *dev) static struct platform_driver oxu_driver = { .probe = oxu_drv_probe, - .remove_new = oxu_drv_remove, + .remove = oxu_drv_remove, .shutdown = oxu_drv_shutdown, .suspend = oxu_drv_suspend, .resume = oxu_drv_resume, diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 6576515a29cd37..a44992e2561b06 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -759,7 +759,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597, struct r8a66597_pipe_info *info = &pipe->info; unsigned short mbw = mbw_value(r8a66597); - /* pipe dma is only for external controlles */ + /* pipe dma is only for external controllers */ if (r8a66597->pdata->on_chip) return; @@ -1336,7 +1336,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) buf = (void *)urb->transfer_buffer + urb->actual_length; urb_len = urb->transfer_buffer_length - urb->actual_length; } - bufsize = min(urb_len, (int) td->maxpacket); + bufsize = min_t(int, urb_len, td->maxpacket); if (rcv_len <= bufsize) { size = rcv_len; } else { @@ -2510,7 +2510,7 @@ static int r8a66597_probe(struct platform_device *pdev) static struct platform_driver r8a66597_driver = { .probe = r8a66597_probe, - .remove_new = r8a66597_remove, + .remove = r8a66597_remove, .driver = { .name = hcd_name, .pm = R8A66597_DEV_PM_OPS, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 92f2d12384488f..036f5fd6d159fe 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1784,7 +1784,7 @@ sl811h_resume(struct platform_device *dev) /* this driver is exported so sl811_cs can depend on it */ struct platform_driver sl811h_driver = { .probe = sl811h_probe, - .remove_new = sl811h_remove, + .remove = sl811h_remove, .suspend = sl811h_suspend, .resume = sl811h_resume, diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c index cfebb833668e4b..8a1f6d1b5b5608 100644 --- a/drivers/usb/host/uhci-grlib.c +++ b/drivers/usb/host/uhci-grlib.c @@ -184,7 +184,7 @@ MODULE_DEVICE_TABLE(of, uhci_hcd_grlib_of_match); static struct platform_driver uhci_grlib_driver = { .probe = uhci_hcd_grlib_probe, - .remove_new = uhci_hcd_grlib_remove, + .remove = uhci_hcd_grlib_remove, .shutdown = uhci_hcd_grlib_shutdown, .driver = { .name = "grlib-uhci", diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 3dec5dd3a0d5ca..a7c934404ebc7e 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -184,7 +184,7 @@ MODULE_DEVICE_TABLE(of, platform_uhci_ids); static struct platform_driver uhci_platform_driver = { .probe = uhci_hcd_platform_probe, - .remove_new = uhci_hcd_platform_remove, + .remove = uhci_hcd_platform_remove, .shutdown = uhci_hcd_platform_shutdown, .driver = { .name = "platform-uhci", diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 241d7aa1fbc20f..227e513867dd27 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -248,8 +248,9 @@ xhci_dbc_queue_trb(struct xhci_ring *ring, u32 field1, trb->generic.field[2] = cpu_to_le32(field3); trb->generic.field[3] = cpu_to_le32(field4); - trace_xhci_dbc_gadget_ep_queue(ring, &trb->generic); - + trace_xhci_dbc_gadget_ep_queue(ring, &trb->generic, + xhci_trb_virt_to_dma(ring->enq_seg, + ring->enqueue)); ring->num_trbs_free--; next = ++(ring->enqueue); if (TRB_TYPE_LINK_LE32(next->link.control)) { @@ -471,7 +472,7 @@ xhci_dbc_ring_alloc(struct device *dev, enum xhci_ring_type type, gfp_t flags) trb->link.control = cpu_to_le32(LINK_TOGGLE | TRB_TYPE(TRB_LINK)); } INIT_LIST_HEAD(&ring->td_list); - xhci_initialize_ring_info(ring, 1); + xhci_initialize_ring_info(ring); return ring; dma_fail: kfree(seg); @@ -747,7 +748,7 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event) return; } - trace_xhci_dbc_handle_transfer(ring, &req->trb->generic); + trace_xhci_dbc_handle_transfer(ring, &req->trb->generic, req->trb_dma); switch (comp_code) { case COMP_SUCCESS: @@ -898,7 +899,9 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) */ rmb(); - trace_xhci_dbc_handle_event(dbc->ring_evt, &evt->generic); + trace_xhci_dbc_handle_event(dbc->ring_evt, &evt->generic, + xhci_trb_virt_to_dma(dbc->ring_evt->deq_seg, + dbc->ring_evt->dequeue)); switch (le32_to_cpu(evt->event_cmd.flags) & TRB_TYPE_BITMASK) { case TRB_TYPE(TRB_PORT_STATUS): diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index f8ba15e7c225c2..4f0c1b96e208f2 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -214,14 +214,11 @@ static void xhci_ring_dump_segment(struct seq_file *s, static int xhci_ring_trb_show(struct seq_file *s, void *unused) { - int i; struct xhci_ring *ring = *(struct xhci_ring **)s->private; struct xhci_segment *seg = ring->first_seg; - for (i = 0; i < ring->num_segs; i++) { + xhci_for_each_ring_seg(ring->first_seg, seg) xhci_ring_dump_segment(s, seg); - seg = seg->next; - } return 0; } @@ -291,12 +288,13 @@ static int xhci_endpoint_context_show(struct seq_file *s, void *unused) for (ep_index = 0; ep_index < 31; ep_index++) { ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); dma = dev->out_ctx->dma + (ep_index + 1) * CTX_SIZE(xhci->hcc_params); - seq_printf(s, "%pad: %s\n", &dma, + seq_printf(s, "%pad: %s, virt_state:%#x\n", &dma, xhci_decode_ep_context(str, le32_to_cpu(ep_ctx->ep_info), le32_to_cpu(ep_ctx->ep_info2), le64_to_cpu(ep_ctx->deq), - le32_to_cpu(ep_ctx->tx_info))); + le32_to_cpu(ep_ctx->tx_info)), + dev->eps[ep_index].ep_state); } return 0; diff --git a/drivers/usb/host/xhci-histb.c b/drivers/usb/host/xhci-histb.c index f9a4a4b0eb5749..8a7d46dae62c8c 100644 --- a/drivers/usb/host/xhci-histb.c +++ b/drivers/usb/host/xhci-histb.c @@ -373,7 +373,7 @@ MODULE_DEVICE_TABLE(of, histb_xhci_of_match); static struct platform_driver histb_xhci_driver = { .probe = xhci_histb_probe, - .remove_new = xhci_histb_remove, + .remove = xhci_histb_remove, .driver = { .name = "xhci-histb", .pm = DEV_PM_OPS, diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 8d774f19271e6a..9693464c052049 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -946,9 +946,9 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, } /* did port event handler already start resume timing? */ if (!port->resume_timestamp) { - /* If not, maybe we are in a host initated resume? */ + /* If not, maybe we are in a host initiated resume? */ if (test_bit(wIndex, &bus_state->resuming_ports)) { - /* Host initated resume doesn't time the resume + /* Host initiated resume doesn't time the resume * signalling using resume_done[]. * It manually sets RESUME state, sleeps 20ms * and sets U0 state. This should probably be @@ -1924,7 +1924,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) /* resume already initiated */ break; default: - /* not in a resumeable state, ignore it */ + /* not in a resumable state, ignore it */ clear_bit(port_index, &bus_state->bus_suspended); break; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d2900197a49e74..92703efda1f7b3 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -27,14 +27,12 @@ * "All components of all Command and Transfer TRBs shall be initialized to '0'" */ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, - unsigned int cycle_state, unsigned int max_packet, unsigned int num, gfp_t flags) { struct xhci_segment *seg; dma_addr_t dma; - int i; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; seg = kzalloc_node(sizeof(*seg), flags, dev_to_node(dev)); @@ -56,11 +54,6 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, return NULL; } } - /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */ - if (cycle_state == 0) { - for (i = 0; i < TRBS_PER_SEGMENT; i++) - seg->trbs[i].link.control = cpu_to_le32(TRB_CYCLE); - } seg->num = num; seg->dma = dma; seg->next = NULL; @@ -78,82 +71,104 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) kfree(seg); } -static void xhci_free_segments_for_ring(struct xhci_hcd *xhci, - struct xhci_segment *first) +static void xhci_ring_segments_free(struct xhci_hcd *xhci, struct xhci_ring *ring) { - struct xhci_segment *seg; + struct xhci_segment *seg, *next; + + ring->last_seg->next = NULL; + seg = ring->first_seg; - seg = first->next; - while (seg && seg != first) { - struct xhci_segment *next = seg->next; + while (seg) { + next = seg->next; xhci_segment_free(xhci, seg); seg = next; } - xhci_segment_free(xhci, first); } /* - * Make the prev segment point to the next segment. + * Only for transfer and command rings where driver is the producer, not for + * event rings. * - * Change the last TRB in the prev segment to be a Link TRB which points to the + * Change the last TRB in the segment to be a Link TRB which points to the * DMA address of the next segment. The caller needs to set any Link TRB * related flags, such as End TRB, Toggle Cycle, and no snoop. */ -static void xhci_link_segments(struct xhci_segment *prev, - struct xhci_segment *next, - enum xhci_ring_type type, bool chain_links) +static void xhci_set_link_trb(struct xhci_segment *seg, bool chain_links) { + union xhci_trb *trb; u32 val; - if (!prev || !next) + if (!seg || !seg->next) return; - prev->next = next; - if (type != TYPE_EVENT) { - prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = - cpu_to_le64(next->dma); - /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ - val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control); - val &= ~TRB_TYPE_BITMASK; - val |= TRB_TYPE(TRB_LINK); - if (chain_links) - val |= TRB_CHAIN; - prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); - } + trb = &seg->trbs[TRBS_PER_SEGMENT - 1]; + + /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ + val = le32_to_cpu(trb->link.control); + val &= ~TRB_TYPE_BITMASK; + val |= TRB_TYPE(TRB_LINK); + if (chain_links) + val |= TRB_CHAIN; + trb->link.control = cpu_to_le32(val); + trb->link.segment_ptr = cpu_to_le64(seg->next->dma); +} + +static void xhci_initialize_ring_segments(struct xhci_hcd *xhci, struct xhci_ring *ring) +{ + struct xhci_segment *seg; + bool chain_links; + + if (ring->type == TYPE_EVENT) + return; + + chain_links = xhci_link_chain_quirk(xhci, ring->type); + xhci_for_each_ring_seg(ring->first_seg, seg) + xhci_set_link_trb(seg, chain_links); + + /* See section 4.9.2.1 and 6.4.4.1 */ + ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= cpu_to_le32(LINK_TOGGLE); } /* - * Link the ring to the new segments. + * Link the src ring segments to the dst ring. * Set Toggle Cycle for the new ring if needed. */ -static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring, - struct xhci_segment *first, struct xhci_segment *last, - unsigned int num_segs) +static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *src, struct xhci_ring *dst) { - struct xhci_segment *next, *seg; + struct xhci_segment *seg; bool chain_links; - if (!ring || !first || !last) + if (!src || !dst) return; - chain_links = xhci_link_chain_quirk(xhci, ring->type); + /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */ + if (dst->cycle_state == 0) { + xhci_for_each_ring_seg(src->first_seg, seg) { + for (int i = 0; i < TRBS_PER_SEGMENT; i++) + seg->trbs[i].link.control |= cpu_to_le32(TRB_CYCLE); + } + } - next = ring->enq_seg->next; - xhci_link_segments(ring->enq_seg, first, ring->type, chain_links); - xhci_link_segments(last, next, ring->type, chain_links); - ring->num_segs += num_segs; + src->last_seg->next = dst->enq_seg->next; + dst->enq_seg->next = src->first_seg; + if (dst->type != TYPE_EVENT) { + chain_links = xhci_link_chain_quirk(xhci, dst->type); + xhci_set_link_trb(dst->enq_seg, chain_links); + xhci_set_link_trb(src->last_seg, chain_links); + } + dst->num_segs += src->num_segs; - if (ring->enq_seg == ring->last_seg) { - if (ring->type != TYPE_EVENT) { - ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control + if (dst->enq_seg == dst->last_seg) { + if (dst->type != TYPE_EVENT) + dst->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control &= ~cpu_to_le32(LINK_TOGGLE); - last->trbs[TRBS_PER_SEGMENT-1].link.control - |= cpu_to_le32(LINK_TOGGLE); - } - ring->last_seg = last; + + dst->last_seg = src->last_seg; + } else if (dst->type != TYPE_EVENT) { + src->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control &= ~cpu_to_le32(LINK_TOGGLE); } - for (seg = ring->enq_seg; seg != ring->last_seg; seg = seg->next) + for (seg = dst->enq_seg; seg != dst->last_seg; seg = seg->next) seg->next->num = seg->num + 1; } @@ -224,7 +239,6 @@ static int xhci_update_stream_segment_mapping( struct radix_tree_root *trb_address_map, struct xhci_ring *ring, struct xhci_segment *first_seg, - struct xhci_segment *last_seg, gfp_t mem_flags) { struct xhci_segment *seg; @@ -234,28 +248,22 @@ static int xhci_update_stream_segment_mapping( if (WARN_ON_ONCE(trb_address_map == NULL)) return 0; - seg = first_seg; - do { + xhci_for_each_ring_seg(first_seg, seg) { ret = xhci_insert_segment_mapping(trb_address_map, ring, seg, mem_flags); if (ret) goto remove_streams; - if (seg == last_seg) - return 0; - seg = seg->next; - } while (seg != first_seg); + } return 0; remove_streams: failed_seg = seg; - seg = first_seg; - do { + xhci_for_each_ring_seg(first_seg, seg) { xhci_remove_segment_mapping(trb_address_map, seg); if (seg == failed_seg) return ret; - seg = seg->next; - } while (seg != first_seg); + } return ret; } @@ -267,17 +275,14 @@ static void xhci_remove_stream_mapping(struct xhci_ring *ring) if (WARN_ON_ONCE(ring->trb_address_map == NULL)) return; - seg = ring->first_seg; - do { + xhci_for_each_ring_seg(ring->first_seg, seg) xhci_remove_segment_mapping(ring->trb_address_map, seg); - seg = seg->next; - } while (seg != ring->first_seg); } static int xhci_update_stream_mapping(struct xhci_ring *ring, gfp_t mem_flags) { return xhci_update_stream_segment_mapping(ring->trb_address_map, ring, - ring->first_seg, ring->last_seg, mem_flags); + ring->first_seg, mem_flags); } /* XXX: Do we need the hcd structure in all these functions? */ @@ -291,14 +296,13 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) if (ring->first_seg) { if (ring->type == TYPE_STREAM) xhci_remove_stream_mapping(ring); - xhci_free_segments_for_ring(xhci, ring->first_seg); + xhci_ring_segments_free(xhci, ring); } kfree(ring); } -void xhci_initialize_ring_info(struct xhci_ring *ring, - unsigned int cycle_state) +void xhci_initialize_ring_info(struct xhci_ring *ring) { /* The ring is empty, so the enqueue pointer == dequeue pointer */ ring->enqueue = ring->first_seg->trbs; @@ -312,7 +316,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring, * New rings are initialized with cycle state equal to 1; if we are * handling ring expansion, set the cycle state equal to the old ring. */ - ring->cycle_state = cycle_state; + ring->cycle_state = 1; /* * Each segment has a link TRB, and leave an extra TRB for SW @@ -323,46 +327,36 @@ void xhci_initialize_ring_info(struct xhci_ring *ring, EXPORT_SYMBOL_GPL(xhci_initialize_ring_info); /* Allocate segments and link them for a ring */ -static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, - struct xhci_segment **first, - struct xhci_segment **last, - unsigned int num_segs, - unsigned int cycle_state, - enum xhci_ring_type type, - unsigned int max_packet, - gfp_t flags) +static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, gfp_t flags) { struct xhci_segment *prev; unsigned int num = 0; - bool chain_links; - - chain_links = xhci_link_chain_quirk(xhci, type); - prev = xhci_segment_alloc(xhci, cycle_state, max_packet, num, flags); + prev = xhci_segment_alloc(xhci, ring->bounce_buf_len, num, flags); if (!prev) return -ENOMEM; num++; - *first = prev; - while (num < num_segs) { + ring->first_seg = prev; + while (num < ring->num_segs) { struct xhci_segment *next; - next = xhci_segment_alloc(xhci, cycle_state, max_packet, num, - flags); + next = xhci_segment_alloc(xhci, ring->bounce_buf_len, num, flags); if (!next) goto free_segments; - xhci_link_segments(prev, next, type, chain_links); + prev->next = next; prev = next; num++; } - xhci_link_segments(prev, *first, type, chain_links); - *last = prev; + ring->last_seg = prev; + ring->last_seg->next = ring->first_seg; return 0; free_segments: - xhci_free_segments_for_ring(xhci, *first); + ring->last_seg = prev; + xhci_ring_segments_free(xhci, ring); return -ENOMEM; } @@ -373,9 +367,8 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, * Set the end flag and the cycle toggle bit on the last segment. * See section 4.9.1 and figures 15 and 16. */ -struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, - unsigned int num_segs, unsigned int cycle_state, - enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) +struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, unsigned int num_segs, + enum xhci_ring_type type, unsigned int max_packet, gfp_t flags) { struct xhci_ring *ring; int ret; @@ -392,18 +385,12 @@ struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, if (num_segs == 0) return ring; - ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, &ring->last_seg, num_segs, - cycle_state, type, max_packet, flags); + ret = xhci_alloc_segments_for_ring(xhci, ring, flags); if (ret) goto fail; - /* Only event ring does not use link TRB */ - if (type != TYPE_EVENT) { - /* See section 4.9.2.1 and 6.4.4.1 */ - ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= - cpu_to_le32(LINK_TOGGLE); - } - xhci_initialize_ring_info(ring, cycle_state); + xhci_initialize_ring_segments(xhci, ring); + xhci_initialize_ring_info(ring); trace_xhci_ring_alloc(ring); return ring; @@ -427,23 +414,29 @@ void xhci_free_endpoint_ring(struct xhci_hcd *xhci, int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned int num_new_segs, gfp_t flags) { - struct xhci_segment *first; - struct xhci_segment *last; - int ret; + struct xhci_ring new_ring; + int ret; + + if (num_new_segs == 0) + return 0; - ret = xhci_alloc_segments_for_ring(xhci, &first, &last, num_new_segs, ring->cycle_state, - ring->type, ring->bounce_buf_len, flags); + new_ring.num_segs = num_new_segs; + new_ring.bounce_buf_len = ring->bounce_buf_len; + new_ring.type = ring->type; + ret = xhci_alloc_segments_for_ring(xhci, &new_ring, flags); if (ret) return -ENOMEM; + xhci_initialize_ring_segments(xhci, &new_ring); + if (ring->type == TYPE_STREAM) { - ret = xhci_update_stream_segment_mapping(ring->trb_address_map, - ring, first, last, flags); + ret = xhci_update_stream_segment_mapping(ring->trb_address_map, ring, + new_ring.first_seg, flags); if (ret) goto free_segments; } - xhci_link_rings(xhci, ring, first, last, num_new_segs); + xhci_link_rings(xhci, &new_ring, ring); trace_xhci_ring_expansion(ring); xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion, "ring expansion succeed, now has %d segments", @@ -452,7 +445,7 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, return 0; free_segments: - xhci_free_segments_for_ring(xhci, first); + xhci_ring_segments_free(xhci, &new_ring); return ret; } @@ -642,8 +635,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { stream_info->stream_rings[cur_stream] = - xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, max_packet, - mem_flags); + xhci_ring_alloc(xhci, 2, TYPE_STREAM, max_packet, mem_flags); cur_ring = stream_info->stream_rings[cur_stream]; if (!cur_ring) goto cleanup_rings; @@ -658,6 +650,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, addr); ret = xhci_update_stream_mapping(cur_ring, mem_flags); + + trace_xhci_alloc_stream_info_ctx(stream_info, cur_stream); if (ret) { xhci_ring_free(xhci, cur_ring); stream_info->stream_rings[cur_stream] = NULL; @@ -984,7 +978,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, } /* Allocate endpoint 0 ring */ - dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, 0, flags); + dev->eps[0].ring = xhci_ring_alloc(xhci, 2, TYPE_CTRL, 0, flags); if (!dev->eps[0].ring) goto fail; @@ -1461,7 +1455,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, /* Set up the endpoint ring */ virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags); + xhci_ring_alloc(xhci, 2, ring_type, max_packet, mem_flags); if (!virt_dev->eps[ep_index].new_ring) return -ENOMEM; @@ -2271,7 +2265,7 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, unsigned int segs, gfp_t flags) if (!ir) return NULL; - ir->event_ring = xhci_ring_alloc(xhci, segs, 1, TYPE_EVENT, 0, flags); + ir->event_ring = xhci_ring_alloc(xhci, segs, TYPE_EVENT, 0, flags); if (!ir->event_ring) { xhci_warn(xhci, "Failed to allocate interrupter event ring\n"); kfree(ir); @@ -2473,7 +2467,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; /* Set up the command ring to have one segments for now. */ - xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, 0, flags); + xhci->cmd_ring = xhci_ring_alloc(xhci, 1, TYPE_COMMAND, 0, flags); if (!xhci->cmd_ring) goto fail; xhci_dbg_trace(xhci, trace_xhci_dbg_init, @@ -2518,11 +2512,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) ir->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX; - /* - * XXX: Might need to set the Interrupter Moderation Register to - * something other than the default (~1ms minimum between interrupts). - * See section 5.5.1.2. - */ for (i = 0; i < MAX_HC_SLOTS; i++) xhci->devs[i] = NULL; diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 3252e3d2d79cd6..9048313444409e 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -853,7 +853,7 @@ MODULE_DEVICE_TABLE(of, mtk_xhci_of_match); static struct platform_driver mtk_xhci_driver = { .probe = xhci_mtk_probe, - .remove_new = xhci_mtk_remove, + .remove = xhci_mtk_remove, .driver = { .name = "xhci-mtk", .pm = DEV_PM_OPS, diff --git a/drivers/usb/host/xhci-pci-renesas.c b/drivers/usb/host/xhci-pci-renesas.c index 65fc9319d5e70f..620f8f0febb84b 100644 --- a/drivers/usb/host/xhci-pci-renesas.c +++ b/drivers/usb/host/xhci-pci-renesas.c @@ -661,5 +661,5 @@ module_pci_driver(xhci_renesas_pci_driver); MODULE_DESCRIPTION("Renesas xHCI PCI Host Controller Driver"); MODULE_FIRMWARE(RENESAS_FW_NAME); -MODULE_IMPORT_NS(xhci); +MODULE_IMPORT_NS("xhci"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index cb07cee9ed0c75..2d1e205c14c609 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -28,18 +28,18 @@ #define SPARSE_CNTL_ENABLE 0xC12C /* Device for a quirk */ -#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 -#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 +#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1009 0x1009 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1100 0x1100 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400 -#define PCI_VENDOR_ID_ETRON 0x1b6f -#define PCI_DEVICE_ID_EJ168 0x7023 -#define PCI_DEVICE_ID_EJ188 0x7052 +#define PCI_VENDOR_ID_ETRON 0x1b6f +#define PCI_DEVICE_ID_ETRON_EJ168 0x7023 +#define PCI_DEVICE_ID_ETRON_EJ188 0x7052 -#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 -#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1 #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f @@ -82,9 +82,6 @@ #define PCI_DEVICE_ID_ASMEDIA_3042_XHCI 0x3042 #define PCI_DEVICE_ID_ASMEDIA_3242_XHCI 0x3242 -#define PCI_DEVICE_ID_CADENCE 0x17CD -#define PCI_DEVICE_ID_CADENCE_SSP 0x0200 - static const char hcd_name[] = "xhci_hcd"; static struct hc_driver __read_mostly xhci_pci_hc_driver; @@ -150,14 +147,11 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd) hcd->irq = 0; /* - * 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. + * Calculate number of MSI/MSI-X vectors supported. + * - max_interrupters: the max number of interrupts requested, capped to xhci HCSPARAMS1. + * - num_online_cpus: one vector per CPUs core, with at least one overall. */ - xhci->nvecs = min(num_online_cpus() + 1, - HCS_MAX_INTRS(xhci->hcs_params1)); + xhci->nvecs = min(num_online_cpus() + 1, xhci->max_interrupters); /* TODO: Check with MSI Soc for sysdev */ xhci->nvecs = pci_alloc_irq_vectors(pdev, 1, xhci->nvecs, @@ -395,14 +389,12 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; if (pdev->vendor == PCI_VENDOR_ID_ETRON && - pdev->device == PCI_DEVICE_ID_EJ168) { - xhci->quirks |= XHCI_RESET_ON_RESUME; - xhci->quirks |= XHCI_BROKEN_STREAMS; - } - if (pdev->vendor == PCI_VENDOR_ID_ETRON && - pdev->device == PCI_DEVICE_ID_EJ188) { + (pdev->device == PCI_DEVICE_ID_ETRON_EJ168 || + pdev->device == PCI_DEVICE_ID_ETRON_EJ188)) { + xhci->quirks |= XHCI_ETRON_HOST; xhci->quirks |= XHCI_RESET_ON_RESUME; xhci->quirks |= XHCI_BROKEN_STREAMS; + xhci->quirks |= XHCI_NO_SOFT_RETRY; } if (pdev->vendor == PCI_VENDOR_ID_RENESAS && @@ -482,8 +474,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH; } - if (pdev->vendor == PCI_DEVICE_ID_CADENCE && - pdev->device == PCI_DEVICE_ID_CADENCE_SSP) + if (pdev->vendor == PCI_VENDOR_ID_CDNS && + pdev->device == PCI_DEVICE_ID_CDNS_USBSSP) xhci->quirks |= XHCI_CDNS_SCTX_QUIRK; /* xHC spec requires PCI devices to support D3hot and D3cold */ @@ -646,6 +638,9 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id) dma_set_max_seg_size(&dev->dev, UINT_MAX); + if (device_property_read_bool(&dev->dev, "ti,pwron-active-high")) + pci_clear_and_set_config_dword(dev, 0xE0, 0, 1 << 22); + return 0; put_usb3_hcd: @@ -656,7 +651,7 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id) pm_runtime_put_noidle(&dev->dev); return retval; } -EXPORT_SYMBOL_NS_GPL(xhci_pci_common_probe, xhci); +EXPORT_SYMBOL_NS_GPL(xhci_pci_common_probe, "xhci"); static const struct pci_device_id pci_ids_reject[] = { /* handled by xhci-pci-renesas */ @@ -700,7 +695,7 @@ void xhci_pci_remove(struct pci_dev *dev) if (set_power_d3) pci_set_power_state(dev, PCI_D3hot); } -EXPORT_SYMBOL_NS_GPL(xhci_pci_remove, xhci); +EXPORT_SYMBOL_NS_GPL(xhci_pci_remove, "xhci"); /* * In some Intel xHCI controllers, in order to get D3 working, diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index ecaa75718e5926..e6c9006bd5685f 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -573,7 +573,7 @@ MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); static struct platform_driver usb_generic_xhci_driver = { .probe = xhci_generic_plat_probe, - .remove_new = xhci_plat_remove, + .remove = xhci_plat_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xhci-hcd", diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 8b357647728c2b..1cc082a3b7939b 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -274,7 +274,7 @@ static int xhci_renesas_probe(struct platform_device *pdev) static struct platform_driver usb_xhci_renesas_driver = { .probe = xhci_renesas_probe, - .remove_new = xhci_plat_remove, + .remove = xhci_plat_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xhci-renesas-hcd", diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 928b93ad1ee866..09b05a62375e01 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -52,6 +52,7 @@ * endpoint rings; it generates events on the event ring for these. */ +#include #include #include #include @@ -145,10 +146,8 @@ static void trb_to_noop(union xhci_trb *trb, u32 noop_type) * TRB is in a new segment. This does not skip over link TRBs, and it does not * effect the ring dequeue or enqueue pointers. */ -static void next_trb(struct xhci_hcd *xhci, - struct xhci_ring *ring, - struct xhci_segment **seg, - union xhci_trb **trb) +static void next_trb(struct xhci_segment **seg, + union xhci_trb **trb) { if (trb_is_link(*trb) || last_trb_on_seg(*seg, *trb)) { *seg = (*seg)->next; @@ -169,13 +168,16 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) if (ring->type == TYPE_EVENT) { if (!last_trb_on_seg(ring->deq_seg, ring->dequeue)) { ring->dequeue++; - goto out; + return; } if (last_trb_on_ring(ring, ring->deq_seg, ring->dequeue)) ring->cycle_state ^= 1; ring->deq_seg = ring->deq_seg->next; ring->dequeue = ring->deq_seg->trbs; - goto out; + + trace_xhci_inc_deq(ring); + + return; } /* All other rings have link trbs */ @@ -190,14 +192,13 @@ void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) ring->deq_seg = ring->deq_seg->next; ring->dequeue = ring->deq_seg->trbs; + trace_xhci_inc_deq(ring); + if (link_trb_count++ > ring->num_segs) { xhci_warn(xhci, "Ring is an endless link TRB loop\n"); break; } } -out: - trace_xhci_inc_deq(ring); - return; } @@ -266,13 +267,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, ring->enqueue = ring->enq_seg->trbs; next = ring->enqueue; + trace_xhci_inc_enq(ring); + if (link_trb_count++ > ring->num_segs) { xhci_warn(xhci, "%s: Ring link TRB loop\n", __func__); break; } } - - trace_xhci_inc_enq(ring); } /* @@ -426,7 +427,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, } } -/* Must be called with xhci->lock held, releases and aquires lock back */ +/* Must be called with xhci->lock held, releases and acquires lock back */ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags) { struct xhci_segment *new_seg = xhci->cmd_ring->deq_seg; @@ -446,9 +447,9 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags) * avoiding corrupting the command ring pointer in case the command ring * is stopped by the time the upper dword is written. */ - next_trb(xhci, NULL, &new_seg, &new_deq); + next_trb(&new_seg, &new_deq); if (trb_is_link(new_deq)) - next_trb(xhci, NULL, &new_seg, &new_deq); + next_trb(&new_seg, &new_deq); crcr = xhci_trb_virt_to_dma(new_seg, new_deq); xhci_write_64(xhci, crcr | CMD_RING_ABORT, &xhci->op_regs->cmd_ring); @@ -660,8 +661,8 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, /* * We want to find the pointer, segment and cycle state of the new trb - * (the one after current TD's last_trb). We know the cycle state at - * hw_dequeue, so walk the ring until both hw_dequeue and last_trb are + * (the one after current TD's end_trb). We know the cycle state at + * hw_dequeue, so walk the ring until both hw_dequeue and end_trb are * found. */ do { @@ -671,14 +672,14 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, if (td_last_trb_found) break; } - if (new_deq == td->last_trb) + if (new_deq == td->end_trb) td_last_trb_found = true; if (cycle_found && trb_is_link(new_deq) && link_trb_toggles_cycle(new_deq)) new_cycle ^= 0x1; - next_trb(xhci, ep_ring, &new_seg, &new_deq); + next_trb(&new_seg, &new_deq); /* Search wrapped around, bail out */ if (new_deq == ep->ring->dequeue) { @@ -740,23 +741,22 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci, * (The last TRB actually points to the ring enqueue pointer, which is not part * of this TD.) This is used to remove partially enqueued isoc TDs from a ring. */ -static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, - struct xhci_td *td, bool flip_cycle) +static void td_to_noop(struct xhci_td *td, bool flip_cycle) { struct xhci_segment *seg = td->start_seg; - union xhci_trb *trb = td->first_trb; + union xhci_trb *trb = td->start_trb; while (1) { trb_to_noop(trb, TRB_TR_NOOP); /* flip cycle if asked to */ - if (flip_cycle && trb != td->first_trb && trb != td->last_trb) + if (flip_cycle && trb != td->start_trb && trb != td->end_trb) trb->generic.field[3] ^= cpu_to_le32(TRB_CYCLE); - if (trb == td->last_trb) + if (trb == td->end_trb) break; - next_trb(xhci, ep_ring, &seg, &trb); + next_trb(&seg, &trb); } } @@ -799,7 +799,7 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len, DMA_FROM_DEVICE); - /* for in tranfers we need to copy the data from bounce to sg */ + /* for in transfers we need to copy the data from bounce to sg */ if (urb->num_sgs) { len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf, seg->bounce_len, seg->bounce_offs); @@ -814,8 +814,8 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, seg->bounce_offs = 0; } -static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, - struct xhci_ring *ep_ring, int status) +static void xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_ring *ep_ring, int status) { struct urb *urb = NULL; @@ -858,10 +858,18 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, status = 0; xhci_giveback_urb_in_irq(xhci, td, status); } - - return 0; } +/* Give back previous TD and move on to the next TD. */ +static void xhci_dequeue_td(struct xhci_hcd *xhci, struct xhci_td *td, struct xhci_ring *ring, + u32 status) +{ + ring->dequeue = td->end_trb; + ring->deq_seg = td->end_seg; + inc_deq(xhci, ring); + + xhci_td_cleanup(xhci, td, ring, status); +} /* Complete the cancelled URBs we unlinked from td_list. */ static void xhci_giveback_invalidated_tds(struct xhci_virt_ep *ep) @@ -972,13 +980,20 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) unsigned int slot_id = ep->vdev->slot_id; int err; + /* + * This is not going to work if the hardware is changing its dequeue + * pointers as we look at them. Completion handler will call us later. + */ + if (ep->ep_state & SET_DEQ_PENDING) + return 0; + xhci = ep->xhci; list_for_each_entry_safe(td, tmp_td, &ep->cancelled_td_list, cancelled_td_list) { xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Removing canceled TD starting at 0x%llx (dma) in stream %u URB %p", (unsigned long long)xhci_trb_virt_to_dma( - td->start_seg, td->first_trb), + td->start_seg, td->start_trb), td->urb->stream_id, td->urb); list_del_init(&td->td_list); ring = xhci_urb_to_transfer_ring(xhci, td->urb); @@ -1020,16 +1035,16 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) "Found multiple active URBs %p and %p in stream %u?\n", td->urb, cached_td->urb, td->urb->stream_id); - td_to_noop(xhci, ring, cached_td, false); + td_to_noop(cached_td, false); cached_td->cancel_status = TD_CLEARED; } - td_to_noop(xhci, ring, td, false); + td_to_noop(td, false); td->cancel_status = TD_CLEARING_CACHE; cached_td = td; break; } } else { - td_to_noop(xhci, ring, td, false); + td_to_noop(td, false); td->cancel_status = TD_CLEARED; } } @@ -1054,13 +1069,26 @@ static int xhci_invalidate_cancelled_tds(struct xhci_virt_ep *ep) continue; xhci_warn(xhci, "Failed to clear cancelled cached URB %p, mark clear anyway\n", td->urb); - td_to_noop(xhci, ring, td, false); + td_to_noop(td, false); td->cancel_status = TD_CLEARED; } } return 0; } +/* + * Erase queued TDs from transfer ring(s) and give back those the xHC didn't + * stop on. If necessary, queue commands to move the xHC off cancelled TDs it + * stopped on. Those will be given back later when the commands complete. + * + * Call under xhci->lock on a stopped endpoint. + */ +void xhci_process_cancelled_tds(struct xhci_virt_ep *ep) +{ + xhci_invalidate_cancelled_tds(ep); + xhci_giveback_invalidated_tds(ep); +} + /* * Returns the TD the endpoint ring halted on. * Only call for non-running rings without streams. @@ -1151,16 +1179,33 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, return; case EP_STATE_STOPPED: /* - * NEC uPD720200 sometimes sets this state and fails with - * Context Error while continuing to process TRBs. - * Be conservative and trust EP_CTX_STATE on other chips. + * Per xHCI 4.6.9, Stop Endpoint command on a Stopped + * EP is a Context State Error, and EP stays Stopped. + * + * But maybe it failed on Halted, and somebody ran Reset + * Endpoint later. EP state is now Stopped and EP_HALTED + * still set because Reset EP handler will run after us. */ - if (!(xhci->quirks & XHCI_NEC_HOST)) + if (ep->ep_state & EP_HALTED) + break; + /* + * On some HCs EP state remains Stopped for some tens of + * us to a few ms or more after a doorbell ring, and any + * new Stop Endpoint fails without aborting the restart. + * This handler may run quickly enough to still see this + * Stopped state, but it will soon change to Running. + * + * Assume this bug on unexpected Stop Endpoint failures. + * Keep retrying until the EP starts and stops again, on + * chips where this is known to help. Wait for 100ms. + */ + if (time_is_before_jiffies(ep->stop_time + msecs_to_jiffies(100))) break; fallthrough; case EP_STATE_RUNNING: /* Race, HW handled stop ep cmd before ep was running */ - xhci_dbg(xhci, "Stop ep completion ctx error, ep is running\n"); + xhci_dbg(xhci, "Stop ep completion ctx error, ctx_state %d\n", + GET_EP_CTX_STATE(ep_ctx)); command = xhci_alloc_command(xhci, false, GFP_ATOMIC); if (!command) { @@ -1338,8 +1383,8 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, struct xhci_virt_ep *ep; struct xhci_ep_ctx *ep_ctx; struct xhci_slot_ctx *slot_ctx; + struct xhci_stream_ctx *stream_ctx; struct xhci_td *td, *tmp_td; - bool deferred = false; ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2])); @@ -1360,6 +1405,11 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, trace_xhci_handle_cmd_set_deq(slot_ctx); trace_xhci_handle_cmd_set_deq_ep(ep_ctx); + if (ep->ep_state & EP_HAS_STREAMS) { + stream_ctx = &ep->stream_info->stream_ctx_array[stream_id]; + trace_xhci_handle_cmd_set_deq_stream(ep->stream_info, stream_id); + } + if (cmd_comp_code != COMP_SUCCESS) { unsigned int ep_state; unsigned int slot_state; @@ -1396,9 +1446,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, u64 deq; /* 4.6.10 deq ptr is written to the stream ctx for streams */ if (ep->ep_state & EP_HAS_STREAMS) { - struct xhci_stream_ctx *ctx = - &ep->stream_info->stream_ctx_array[stream_id]; - deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK; + deq = le64_to_cpu(stream_ctx->stream_ring) & SCTX_DEQ_MASK; /* * Cadence xHCI controllers store some endpoint state @@ -1410,8 +1458,8 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, * To fix this issue driver must clear Rsvd0 field. */ if (xhci->quirks & XHCI_CDNS_SCTX_QUIRK) { - ctx->reserved[0] = 0; - ctx->reserved[1] = 0; + stream_ctx->reserved[0] = 0; + stream_ctx->reserved[1] = 0; } } else { deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; @@ -1440,8 +1488,6 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, xhci_dbg(ep->xhci, "%s: Giveback cancelled URB %p TD\n", __func__, td->urb); xhci_td_cleanup(ep->xhci, td, ep_ring, td->status); - } else if (td->cancel_status == TD_CLEARING_CACHE_DEFERRED) { - deferred = true; } else { xhci_dbg(ep->xhci, "%s: Keep cancelled URB %p TD as cancel_status is %d\n", __func__, td->urb, td->cancel_status); @@ -1452,11 +1498,15 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, ep->queued_deq_seg = NULL; ep->queued_deq_ptr = NULL; - if (deferred) { - /* We have more streams to clear */ + /* Check for deferred or newly cancelled TDs */ + if (!list_empty(&ep->cancelled_td_list)) { xhci_dbg(ep->xhci, "%s: Pending TDs to clear, continuing with invalidation\n", __func__); xhci_invalidate_cancelled_tds(ep); + /* Try to restart the endpoint if all is done */ + ring_doorbell_for_active_rings(xhci, slot_id, ep_index); + /* Start giving back any TDs invalidated above */ + xhci_giveback_invalidated_tds(ep); } else { /* Restart any rings with pending URBs */ xhci_dbg(ep->xhci, "%s: All TDs cleared, ring doorbell\n", __func__); @@ -1716,7 +1766,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, cmd_dma = le64_to_cpu(event->cmd_trb); cmd_trb = xhci->cmd_ring->dequeue; - trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic); + trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic, cmd_dma); cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status)); @@ -2074,7 +2124,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, dma_ad dma_addr_t end_trb_dma; struct xhci_segment *cur_seg; - start_dma = xhci_trb_virt_to_dma(td->start_seg, td->first_trb); + start_dma = xhci_trb_virt_to_dma(td->start_seg, td->start_trb); cur_seg = td->start_seg; do { @@ -2084,7 +2134,7 @@ struct xhci_segment *trb_in_td(struct xhci_hcd *xhci, struct xhci_td *td, dma_ad end_seg_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[TRBS_PER_SEGMENT - 1]); /* If the end TRB isn't in this segment, this is set to 0 */ - end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->last_trb); + end_trb_dma = xhci_trb_virt_to_dma(cur_seg, td->end_trb); if (debug) xhci_warn(xhci, @@ -2184,9 +2234,9 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code) return 0; } -static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, - struct xhci_ring *ep_ring, struct xhci_td *td, - u32 trb_comp_code) +static void finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, + struct xhci_ring *ep_ring, struct xhci_td *td, + u32 trb_comp_code) { struct xhci_ep_ctx *ep_ctx; @@ -2201,7 +2251,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, * stopped TDs. A stopped TD may be restarted, so don't update * the ring dequeue pointer or take this TD off any lists yet. */ - return 0; + return; case COMP_USB_TRANSACTION_ERROR: case COMP_BABBLE_DETECTED_ERROR: case COMP_SPLIT_TRANSACTION_ERROR: @@ -2226,8 +2276,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, !list_empty(&td->cancelled_td_list)) { xhci_dbg(xhci, "Already resolving halted ep for 0x%llx\n", (unsigned long long)xhci_trb_virt_to_dma( - td->start_seg, td->first_trb)); - return 0; + td->start_seg, td->start_trb)); + return; } /* endpoint not halted, don't reset it */ break; @@ -2235,7 +2285,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, /* Almost same procedure as for STALL_ERROR below */ xhci_clear_hub_tt_buffer(xhci, td, ep); xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET); - return 0; + return; case COMP_STALL_ERROR: /* * xhci internal endpoint state will go to a "halt" state for @@ -2252,28 +2302,22 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, xhci_handle_halted_endpoint(xhci, ep, td, EP_HARD_RESET); - return 0; /* xhci_handle_halted_endpoint marked td cancelled */ + return; /* xhci_handle_halted_endpoint marked td cancelled */ default: break; } - /* Update ring dequeue pointer */ - ep_ring->dequeue = td->last_trb; - ep_ring->deq_seg = td->last_trb_seg; - inc_deq(xhci, ep_ring); - - return xhci_td_cleanup(xhci, td, ep_ring, td->status); + xhci_dequeue_td(xhci, td, ep_ring, td->status); } -/* sum trb lengths from ring dequeue up to stop_trb, _excluding_ stop_trb */ -static int sum_trb_lengths(struct xhci_hcd *xhci, struct xhci_ring *ring, - union xhci_trb *stop_trb) +/* sum trb lengths from the first trb up to stop_trb, _excluding_ stop_trb */ +static u32 sum_trb_lengths(struct xhci_td *td, union xhci_trb *stop_trb) { u32 sum; - union xhci_trb *trb = ring->dequeue; - struct xhci_segment *seg = ring->deq_seg; + union xhci_trb *trb = td->start_trb; + struct xhci_segment *seg = td->start_seg; - for (sum = 0; trb != stop_trb; next_trb(xhci, ring, &seg, &trb)) { + for (sum = 0; trb != stop_trb; next_trb(&seg, &trb)) { if (!trb_is_noop(trb) && !trb_is_link(trb)) sum += TRB_LEN(le32_to_cpu(trb->generic.field[2])); } @@ -2283,9 +2327,9 @@ static int sum_trb_lengths(struct xhci_hcd *xhci, struct xhci_ring *ring, /* * Process control tds, update urb status and actual_length. */ -static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, - struct xhci_ring *ep_ring, struct xhci_td *td, - union xhci_trb *ep_trb, struct xhci_transfer_event *event) +static void process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, + struct xhci_ring *ep_ring, struct xhci_td *td, + union xhci_trb *ep_trb, struct xhci_transfer_event *event) { struct xhci_ep_ctx *ep_ctx; u32 trb_comp_code; @@ -2364,7 +2408,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, td->urb_length_set = true; td->urb->actual_length = requested - remaining; xhci_dbg(xhci, "Waiting for status stage event\n"); - return 0; + return; } /* at status stage */ @@ -2372,15 +2416,15 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, td->urb->actual_length = requested; finish_td: - return finish_td(xhci, ep, ep_ring, td, trb_comp_code); + finish_td(xhci, ep, ep_ring, td, trb_comp_code); } /* * Process isochronous tds, update urb packet status and actual_length. */ -static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, - struct xhci_ring *ep_ring, struct xhci_td *td, - union xhci_trb *ep_trb, struct xhci_transfer_event *event) +static void process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, + struct xhci_ring *ep_ring, struct xhci_td *td, + union xhci_trb *ep_trb, struct xhci_transfer_event *event) { struct urb_priv *urb_priv; int idx; @@ -2425,7 +2469,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, fallthrough; case COMP_ISOCH_BUFFER_OVERRUN: frame->status = -EOVERFLOW; - if (ep_trb != td->last_trb) + if (ep_trb != td->end_trb) td->error_mid_td = true; break; case COMP_INCOMPATIBLE_DEVICE_ERROR: @@ -2435,14 +2479,14 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, case COMP_USB_TRANSACTION_ERROR: frame->status = -EPROTO; sum_trbs_for_length = true; - if (ep_trb != td->last_trb) + if (ep_trb != td->end_trb) td->error_mid_td = true; break; case COMP_STOPPED: sum_trbs_for_length = true; break; case COMP_STOPPED_SHORT_PACKET: - /* field normally containing residue now contains tranferred */ + /* field normally containing residue now contains transferred */ frame->status = short_framestatus; requested = remaining; break; @@ -2462,7 +2506,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, goto finish_td; if (sum_trbs_for_length) - frame->actual_length = sum_trb_lengths(xhci, ep->ring, ep_trb) + + frame->actual_length = sum_trb_lengths(td, ep_trb) + ep_trb_len - remaining; else frame->actual_length = requested; @@ -2471,17 +2515,16 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, finish_td: /* Don't give back TD yet if we encountered an error mid TD */ - if (td->error_mid_td && ep_trb != td->last_trb) { + if (td->error_mid_td && ep_trb != td->end_trb) { xhci_dbg(xhci, "Error mid isoc TD, wait for final completion event\n"); td->urb_length_set = true; - return 0; + return; } - - return finish_td(xhci, ep, ep_ring, td, trb_comp_code); + finish_td(xhci, ep, ep_ring, td, trb_comp_code); } -static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, - struct xhci_virt_ep *ep, int status) +static void skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_virt_ep *ep, int status) { struct urb_priv *urb_priv; struct usb_iso_packet_descriptor *frame; @@ -2497,20 +2540,15 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* calc actual length */ frame->actual_length = 0; - /* Update ring dequeue pointer */ - ep->ring->dequeue = td->last_trb; - ep->ring->deq_seg = td->last_trb_seg; - inc_deq(xhci, ep->ring); - - return xhci_td_cleanup(xhci, td, ep->ring, status); + xhci_dequeue_td(xhci, td, ep->ring, status); } /* * Process bulk and interrupt tds, update urb status and actual_length. */ -static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, - struct xhci_ring *ep_ring, struct xhci_td *td, - union xhci_trb *ep_trb, struct xhci_transfer_event *event) +static void process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, + struct xhci_ring *ep_ring, struct xhci_td *td, + union xhci_trb *ep_trb, struct xhci_transfer_event *event) { struct xhci_slot_ctx *slot_ctx; u32 trb_comp_code; @@ -2526,7 +2564,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, case COMP_SUCCESS: ep->err_count = 0; /* handle success with untransferred data as short packet */ - if (ep_trb != td->last_trb || remaining) { + if (ep_trb != td->end_trb || remaining) { xhci_warn(xhci, "WARN Successful completion on short TX\n"); xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n", td->urb->ep->desc.bEndpointAddress, @@ -2542,7 +2580,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, goto finish_td; case COMP_STOPPED_LENGTH_INVALID: /* stopped on ep trb with invalid length, exclude it */ - td->urb->actual_length = sum_trb_lengths(xhci, ep_ring, ep_trb); + td->urb->actual_length = sum_trb_lengths(td, ep_trb); goto finish_td; case COMP_USB_TRANSACTION_ERROR: if (xhci->quirks & XHCI_NO_SOFT_RETRY || @@ -2553,17 +2591,17 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, td->status = 0; xhci_handle_halted_endpoint(xhci, ep, td, EP_SOFT_RESET); - return 0; + return; default: /* do nothing */ break; } - if (ep_trb == td->last_trb) + if (ep_trb == td->end_trb) td->urb->actual_length = requested - remaining; else td->urb->actual_length = - sum_trb_lengths(xhci, ep_ring, ep_trb) + + sum_trb_lengths(td, ep_trb) + ep_trb_len - remaining; finish_td: if (remaining > requested) { @@ -2572,7 +2610,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, td->urb->actual_length = 0; } - return finish_td(xhci, ep, ep_ring, td, trb_comp_code); + finish_td(xhci, ep, ep_ring, td, trb_comp_code); } /* Transfer events which don't point to a transfer TRB, see xhci 4.17.4 */ @@ -2792,10 +2830,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, if (td && td->error_mid_td && !trb_in_td(xhci, td, ep_trb_dma, false)) { xhci_dbg(xhci, "Missing TD completion event after mid TD error\n"); - ep_ring->dequeue = td->last_trb; - ep_ring->deq_seg = td->last_trb_seg; - inc_deq(xhci, ep_ring); - xhci_td_cleanup(xhci, td, ep_ring, td->status); + xhci_dequeue_td(xhci, td, ep_ring, td->status); } if (list_empty(&ep_ring->td_list)) { @@ -2889,7 +2924,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep_ring->last_td_was_short = false; ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)]; - trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb); + trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb, ep_trb_dma); /* * No-op TRB could trigger interrupts in a case where a URB was killed @@ -2939,7 +2974,9 @@ static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter { u32 trb_type; - trace_xhci_handle_event(ir->event_ring, &event->generic); + trace_xhci_handle_event(ir->event_ring, &event->generic, + xhci_trb_virt_to_dma(ir->event_ring->deq_seg, + ir->event_ring->dequeue)); /* * Barrier between reading the TRB_CYCLE (valid) flag before, and any @@ -3162,7 +3199,8 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, wmb(); trb->field[3] = cpu_to_le32(field4); - trace_xhci_queue_trb(ring, trb); + trace_xhci_queue_trb(ring, trb, + xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue)); inc_enq(xhci, ring, more_trbs_coming); } @@ -3302,7 +3340,7 @@ static int prepare_transfer(struct xhci_hcd *xhci, /* Add this TD to the tail of the endpoint ring's TD list */ list_add_tail(&td->td_list, &ep_ring->td_list); td->start_seg = ep_ring->enq_seg; - td->first_trb = ep_ring->enqueue; + td->start_trb = ep_ring->enqueue; return 0; } @@ -3641,8 +3679,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field &= ~TRB_CHAIN; field |= TRB_IOC; more_trbs_coming = false; - td->last_trb = ring->enqueue; - td->last_trb_seg = ring->enq_seg; + td->end_trb = ring->enqueue; + td->end_seg = ring->enq_seg; if (xhci_urb_suitable_for_idt(urb)) { memcpy(&send_addr, urb->transfer_buffer, trb_buff_len); @@ -3690,8 +3728,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, 1, urb, 1, mem_flags); - urb_priv->td[1].last_trb = ring->enqueue; - urb_priv->td[1].last_trb_seg = ring->enq_seg; + urb_priv->td[1].end_trb = ring->enqueue; + urb_priv->td[1].end_seg = ring->enq_seg; field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC; queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field); } @@ -3727,6 +3765,20 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (!urb->setup_packet) return -EINVAL; + if ((xhci->quirks & XHCI_ETRON_HOST) && + urb->dev->speed >= USB_SPEED_SUPER) { + /* + * If next available TRB is the Link TRB in the ring segment then + * enqueue a No Op TRB, this can prevent the Setup and Data Stage + * TRB to be breaked by the Link TRB. + */ + if (trb_is_link(ep_ring->enqueue + 1)) { + field = TRB_TYPE(TRB_TR_NOOP) | ep_ring->cycle_state; + queue_trb(xhci, ep_ring, false, 0, 0, + TRB_INTR_TARGET(0), field); + } + } + /* 1 TRB for setup, 1 for status */ num_trbs = 2; /* @@ -3815,8 +3867,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } /* Save the DMA address of the last TRB in the TD */ - td->last_trb = ep_ring->enqueue; - td->last_trb_seg = ep_ring->enq_seg; + td->end_trb = ep_ring->enqueue; + td->end_seg = ep_ring->enq_seg; /* Queue status TRB - see Table 7 and sections 4.11.2.2 and 6.4.1.2.3 */ /* If the device sent data, the status stage is an OUT transfer */ @@ -4101,8 +4153,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field |= TRB_CHAIN; } else { more_trbs_coming = false; - td->last_trb = ep_ring->enqueue; - td->last_trb_seg = ep_ring->enq_seg; + td->end_trb = ep_ring->enqueue; + td->end_seg = ep_ring->enq_seg; field |= TRB_IOC; if (trb_block_event_intr(xhci, num_tds, i, ir)) field |= TRB_BEI; @@ -4168,14 +4220,14 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Use the first TD as a temporary variable to turn the TDs we've queued * into No-ops with a software-owned cycle bit. That way the hardware * won't accidentally start executing bogus TDs when we partially - * overwrite them. td->first_trb and td->start_seg are already set. + * overwrite them. td->start_trb and td->start_seg are already set. */ - urb_priv->td[0].last_trb = ep_ring->enqueue; + urb_priv->td[0].end_trb = ep_ring->enqueue; /* Every TRB except the first & last will have its cycle bit flipped. */ - td_to_noop(xhci, ep_ring, &urb_priv->td[0], true); + td_to_noop(&urb_priv->td[0], true); /* Reset the ring enqueue back to the first TRB and its cycle bit. */ - ep_ring->enqueue = urb_priv->td[0].first_trb; + ep_ring->enqueue = urb_priv->td[0].start_trb; ep_ring->enq_seg = urb_priv->td[0].start_seg; ep_ring->cycle_state = start_cycle; usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 76f228e7443cb6..06ae193ec87407 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -2664,7 +2664,7 @@ MODULE_DEVICE_TABLE(of, tegra_xusb_of_match); static struct platform_driver tegra_xusb_driver = { .probe = tegra_xusb_probe, - .remove_new = tegra_xusb_remove, + .remove = tegra_xusb_remove, .shutdown = tegra_xusb_shutdown, .driver = { .name = "tegra-xusb", diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 24405315ffe6d9..bfb5c5c170127a 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -108,9 +108,10 @@ DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx, ); DECLARE_EVENT_CLASS(xhci_log_trb, - TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), - TP_ARGS(ring, trb), + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma), + TP_ARGS(ring, trb, dma), TP_STRUCT__entry( + __field(dma_addr_t, dma) __field(u32, type) __field(u32, field0) __field(u32, field1) @@ -118,51 +119,54 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __field(u32, field3) ), TP_fast_assign( + __entry->dma = dma; __entry->type = ring->type; __entry->field0 = le32_to_cpu(trb->field[0]); __entry->field1 = le32_to_cpu(trb->field[1]); __entry->field2 = le32_to_cpu(trb->field[2]); __entry->field3 = le32_to_cpu(trb->field[3]); ), - TP_printk("%s: %s", xhci_ring_type_string(__entry->type), + TP_printk("%s: @%pad %s", + xhci_ring_type_string(__entry->type), &__entry->dma, xhci_decode_trb(__get_buf(XHCI_MSG_MAX), XHCI_MSG_MAX, __entry->field0, __entry->field1, __entry->field2, __entry->field3) ) ); DEFINE_EVENT(xhci_log_trb, xhci_handle_event, - TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), - TP_ARGS(ring, trb) + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma), + TP_ARGS(ring, trb, dma) ); DEFINE_EVENT(xhci_log_trb, xhci_handle_command, - TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), - TP_ARGS(ring, trb) + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma), + TP_ARGS(ring, trb, dma) ); DEFINE_EVENT(xhci_log_trb, xhci_handle_transfer, - TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), - TP_ARGS(ring, trb) + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma), + TP_ARGS(ring, trb, dma) ); DEFINE_EVENT(xhci_log_trb, xhci_queue_trb, - TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), - TP_ARGS(ring, trb) + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma), + TP_ARGS(ring, trb, dma) + ); DEFINE_EVENT(xhci_log_trb, xhci_dbc_handle_event, - TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), - TP_ARGS(ring, trb) + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma), + TP_ARGS(ring, trb, dma) ); DEFINE_EVENT(xhci_log_trb, xhci_dbc_handle_transfer, - TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), - TP_ARGS(ring, trb) + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma), + TP_ARGS(ring, trb, dma) ); DEFINE_EVENT(xhci_log_trb, xhci_dbc_gadget_ep_queue, - TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), - TP_ARGS(ring, trb) + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb, dma_addr_t dma), + TP_ARGS(ring, trb, dma) ); DECLARE_EVENT_CLASS(xhci_log_free_virt_dev, @@ -310,6 +314,37 @@ DEFINE_EVENT(xhci_log_urb, xhci_urb_dequeue, TP_ARGS(urb) ); +DECLARE_EVENT_CLASS(xhci_log_stream_ctx, + TP_PROTO(struct xhci_stream_info *info, unsigned int stream_id), + TP_ARGS(info, stream_id), + TP_STRUCT__entry( + __field(unsigned int, stream_id) + __field(u64, stream_ring) + __field(dma_addr_t, ctx_array_dma) + + ), + TP_fast_assign( + __entry->stream_id = stream_id; + __entry->stream_ring = le64_to_cpu(info->stream_ctx_array[stream_id].stream_ring); + __entry->ctx_array_dma = info->ctx_array_dma + stream_id * 16; + + ), + TP_printk("stream %u ctx @%pad: SCT %llu deq %llx", __entry->stream_id, + &__entry->ctx_array_dma, CTX_TO_SCT(__entry->stream_ring), + __entry->stream_ring + ) +); + +DEFINE_EVENT(xhci_log_stream_ctx, xhci_alloc_stream_info_ctx, + TP_PROTO(struct xhci_stream_info *info, unsigned int stream_id), + TP_ARGS(info, stream_id) +); + +DEFINE_EVENT(xhci_log_stream_ctx, xhci_handle_cmd_set_deq_stream, + TP_PROTO(struct xhci_stream_info *info, unsigned int stream_id), + TP_ARGS(info, stream_id) +); + DECLARE_EVENT_CLASS(xhci_log_ep_ctx, TP_PROTO(struct xhci_ep_ctx *ctx), TP_ARGS(ctx), @@ -454,8 +489,6 @@ DECLARE_EVENT_CLASS(xhci_log_ring, __field(void *, ring) __field(dma_addr_t, enq) __field(dma_addr_t, deq) - __field(dma_addr_t, enq_seg) - __field(dma_addr_t, deq_seg) __field(unsigned int, num_segs) __field(unsigned int, stream_id) __field(unsigned int, cycle_state) @@ -466,17 +499,15 @@ DECLARE_EVENT_CLASS(xhci_log_ring, __entry->type = ring->type; __entry->num_segs = ring->num_segs; __entry->stream_id = ring->stream_id; - __entry->enq_seg = ring->enq_seg->dma; - __entry->deq_seg = ring->deq_seg->dma; __entry->cycle_state = ring->cycle_state; __entry->bounce_buf_len = ring->bounce_buf_len; __entry->enq = xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue); __entry->deq = xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue); ), - TP_printk("%s %p: enq %pad(%pad) deq %pad(%pad) segs %d stream %d bounce %d cycle %d", + TP_printk("%s %p: enq %pad deq %pad segs %d stream %d bounce %d cycle %d", xhci_ring_type_string(__entry->type), __entry->ring, - &__entry->enq, &__entry->enq_seg, - &__entry->deq, &__entry->deq_seg, + &__entry->enq, + &__entry->deq, __entry->num_segs, __entry->stream_id, __entry->bounce_buf_len, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 899c0effb5d3c1..5ebde8cae4fc44 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -8,6 +8,7 @@ * Some code borrowed from the Linux EHCI driver. */ +#include #include #include #include @@ -40,15 +41,15 @@ MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default"); static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring) { - struct xhci_segment *seg = ring->first_seg; + struct xhci_segment *seg; if (!td || !td->start_seg) return false; - do { + + xhci_for_each_ring_seg(ring->first_seg, seg) { if (seg == td->start_seg) return true; - seg = seg->next; - } while (seg && seg != ring->first_seg); + } return false; } @@ -473,14 +474,7 @@ static int xhci_init(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_init"); spin_lock_init(&xhci->lock); - if (xhci->hci_version == 0x95 && link_quirk) { - xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, - "QUIRK: Not clearing Link TRB chain bits."); - xhci->quirks |= XHCI_LINK_TRB_QUIRK; - } else { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "xHCI doesn't need link TRB QUIRK"); - } + retval = xhci_mem_init(xhci, GFP_KERNEL); xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Finished xhci_init"); @@ -785,16 +779,10 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) struct xhci_segment *seg; ring = xhci->cmd_ring; - seg = ring->deq_seg; - do { - memset(seg->trbs, 0, - sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); - seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= - cpu_to_le32(~TRB_CYCLE); - seg = seg->next; - } while (seg != ring->deq_seg); - - xhci_initialize_ring_info(ring, 1); + xhci_for_each_ring_seg(ring->first_seg, seg) + memset(seg->trbs, 0, sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); + + xhci_initialize_ring_info(ring); /* * Reset the hardware dequeue pointer. * Yes, this will need to be re-written after resume, but we're paranoid @@ -1756,7 +1744,7 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) urb->ep->desc.bEndpointAddress, (unsigned long long) xhci_trb_virt_to_dma( urb_priv->td[i].start_seg, - urb_priv->td[i].first_trb)); + urb_priv->td[i].start_trb)); for (; i < urb_priv->num_tds; i++) { td = &urb_priv->td[i]; @@ -1768,15 +1756,27 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) } } - /* Queue a stop endpoint command, but only if this is - * the first cancellation to be handled. - */ - if (!(ep->ep_state & EP_STOP_CMD_PENDING)) { + /* These completion handlers will sort out cancelled TDs for us */ + if (ep->ep_state & (EP_STOP_CMD_PENDING | EP_HALTED | SET_DEQ_PENDING)) { + xhci_dbg(xhci, "Not queuing Stop Endpoint on slot %d ep %d in state 0x%x\n", + urb->dev->slot_id, ep_index, ep->ep_state); + goto done; + } + + /* In this case no commands are pending but the endpoint is stopped */ + if (ep->ep_state & EP_CLEARING_TT) { + /* and cancelled TDs can be given back right away */ + xhci_dbg(xhci, "Invalidating TDs instantly on slot %d ep %d in state 0x%x\n", + urb->dev->slot_id, ep_index, ep->ep_state); + xhci_process_cancelled_tds(ep); + } else { + /* Otherwise, queue a new Stop Endpoint command */ command = xhci_alloc_command(xhci, false, GFP_ATOMIC); if (!command) { ret = -ENOMEM; goto done; } + ep->stop_time = jiffies; ep->ep_state |= EP_STOP_CMD_PENDING; xhci_queue_stop_endpoint(xhci, command, urb->dev->slot_id, ep_index, 0); @@ -2794,6 +2794,51 @@ static int xhci_reserve_bandwidth(struct xhci_hcd *xhci, return -ENOMEM; } +/* + * Synchronous XHCI stop endpoint helper. Issues the stop endpoint command and + * waits for the command completion before returning. This does not call + * xhci_handle_cmd_stop_ep(), which has additional handling for 'context error' + * cases, along with transfer ring cleanup. + * + * xhci_stop_endpoint_sync() is intended to be utilized by clients that manage + * their own transfer ring, such as offload situations. + */ +int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, int suspend, + gfp_t gfp_flags) +{ + struct xhci_command *command; + unsigned long flags; + int ret; + + command = xhci_alloc_command(xhci, true, gfp_flags); + if (!command) + return -ENOMEM; + + spin_lock_irqsave(&xhci->lock, flags); + ret = xhci_queue_stop_endpoint(xhci, command, ep->vdev->slot_id, + ep->ep_index, suspend); + if (ret < 0) { + spin_unlock_irqrestore(&xhci->lock, flags); + goto out; + } + + xhci_ring_cmd_db(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); + + wait_for_completion(command->completion); + + /* No handling for COMP_CONTEXT_STATE_ERROR done at command completion*/ + if (command->status == COMP_COMMAND_ABORTED || + command->status == COMP_COMMAND_RING_STOPPED) { + xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n"); + ret = -ETIME; + } +out: + xhci_free_command(xhci, command); + + return ret; +} +EXPORT_SYMBOL_GPL(xhci_stop_endpoint_sync); /* Issue a configure endpoint command or evaluate context command * and wait for it to finish. @@ -3692,6 +3737,8 @@ void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci, xhci->num_active_eps); } +static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); + /* * This submits a Reset Device Command, which will set the device state to 0, * set the device address to 0, and disable all the endpoints except the default @@ -3762,6 +3809,23 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd, SLOT_STATE_DISABLED) return 0; + if (xhci->quirks & XHCI_ETRON_HOST) { + /* + * Obtaining a new device slot to inform the xHCI host that + * the USB device has been reset. + */ + ret = xhci_disable_slot(xhci, udev->slot_id); + xhci_free_virt_device(xhci, udev->slot_id); + if (!ret) { + ret = xhci_alloc_dev(hcd, udev); + if (ret == 1) + ret = 0; + else + ret = -EINVAL; + } + return ret; + } + trace_xhci_discover_or_reset_device(slot_ctx); xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id); @@ -5251,6 +5315,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) if (xhci->hci_version > 0x96) xhci->quirks |= XHCI_SPURIOUS_SUCCESS; + if (xhci->hci_version == 0x95 && link_quirk) { + xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits"); + xhci->quirks |= XHCI_LINK_TRB_QUIRK; + } + /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f0fb696d561986..4914f0a10cff42 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -554,6 +554,7 @@ struct xhci_stream_ctx { /* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */ #define SCT_FOR_CTX(p) (((p) & 0x7) << 1) +#define CTX_TO_SCT(p) (((p) >> 1) & 0x7) /* Secondary stream array type, dequeue pointer is to a transfer ring */ #define SCT_SEC_TR 0 /* Primary stream array type, dequeue pointer is to a transfer ring */ @@ -690,6 +691,7 @@ struct xhci_virt_ep { /* Bandwidth checking storage */ struct xhci_bw_info bw_info; struct list_head bw_endpoint_list; + unsigned long stop_time; /* Isoch Frame ID checking storage */ int next_frame_id; /* Use new Isoch TRB layout needed for extended TBC support */ @@ -1023,9 +1025,6 @@ enum xhci_setup_dev { /* Interrupter Target - which MSI-X vector to target the completion event at */ #define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) #define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) -/* Total burst count field, Rsvdz on xhci 1.1 with Extended TBC enabled (ETE) */ -#define TRB_TBC(p) (((p) & 0x3) << 7) -#define TRB_TLBPC(p) (((p) & 0xf) << 16) /* Cycle bit - indicates TRB ownership by HC or HCD */ #define TRB_CYCLE (1<<0) @@ -1059,6 +1058,12 @@ enum xhci_setup_dev { /* Isochronous TRB specific fields */ #define TRB_SIA (1<<31) #define TRB_FRAME_ID(p) (((p) & 0x7ff) << 20) +#define GET_FRAME_ID(p) (((p) >> 20) & 0x7ff) +/* Total burst count field, Rsvdz on xhci 1.1 with Extended TBC enabled (ETE) */ +#define TRB_TBC(p) (((p) & 0x3) << 7) +#define GET_TBC(p) (((p) >> 7) & 0x3) +#define TRB_TLBPC(p) (((p) & 0xf) << 16) +#define GET_TLBPC(p) (((p) >> 16) & 0xf) /* TRB cache size for xHC with TRB cache */ #define TRB_CACHE_SIZE_HS 8 @@ -1259,6 +1264,9 @@ static inline const char *xhci_trb_type_string(u8 type) #define AVOID_BEI_INTERVAL_MIN 8 #define AVOID_BEI_INTERVAL_MAX 32 +#define xhci_for_each_ring_seg(head, seg) \ + for (seg = head; seg != NULL; seg = (seg->next != head ? seg->next : NULL)) + struct xhci_segment { union xhci_trb *trbs; /* private to HCD */ @@ -1287,9 +1295,9 @@ struct xhci_td { enum xhci_cancelled_td_status cancel_status; struct urb *urb; struct xhci_segment *start_seg; - union xhci_trb *first_trb; - union xhci_trb *last_trb; - struct xhci_segment *last_trb_seg; + union xhci_trb *start_trb; + struct xhci_segment *end_seg; + union xhci_trb *end_trb; struct xhci_segment *bounce_seg; /* actual_length of the URB has already been set */ bool urb_length_set; @@ -1624,6 +1632,7 @@ struct xhci_hcd { #define XHCI_ZHAOXIN_HOST BIT_ULL(46) #define XHCI_WRITE_64_HI_LO BIT_ULL(47) #define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48) +#define XHCI_ETRON_HOST BIT_ULL(49) unsigned int num_active_eps; unsigned int limit_active_eps; @@ -1788,14 +1797,12 @@ void xhci_slot_copy(struct xhci_hcd *xhci, int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_device *udev, struct usb_host_endpoint *ep, gfp_t mem_flags); -struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, - unsigned int num_segs, unsigned int cycle_state, +struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, unsigned int num_segs, enum xhci_ring_type type, unsigned int max_packet, gfp_t flags); void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, unsigned int num_trbs, gfp_t flags); -void xhci_initialize_ring_info(struct xhci_ring *ring, - unsigned int cycle_state); +void xhci_initialize_ring_info(struct xhci_ring *ring); void xhci_free_endpoint_ring(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, unsigned int ep_index); @@ -1913,6 +1920,9 @@ void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci, void xhci_cleanup_command_queue(struct xhci_hcd *xhci); void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring); unsigned int count_trbs(u64 addr, u64 len); +int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, + int suspend, gfp_t gfp_flags); +void xhci_process_cancelled_tds(struct xhci_virt_ep *ep); /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, @@ -2070,7 +2080,6 @@ static inline const char *xhci_decode_trb(char *str, size_t size, field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_NORMAL: - case TRB_ISOC: case TRB_EVENT_DATA: case TRB_TR_NOOP: snprintf(str, size, @@ -2087,7 +2096,25 @@ static inline const char *xhci_decode_trb(char *str, size_t size, field3 & TRB_ENT ? 'E' : 'e', field3 & TRB_CYCLE ? 'C' : 'c'); break; - + case TRB_ISOC: + snprintf(str, size, + "Buffer %08x%08x length %d TD size/TBC %d intr %d type '%s' TBC %u TLBPC %u frame_id %u flags %c:%c:%c:%c:%c:%c:%c:%c:%c", + field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + xhci_trb_type_string(type), + GET_TBC(field3), + GET_TLBPC(field3), + GET_FRAME_ID(field3), + field3 & TRB_SIA ? 'S' : 's', + field3 & TRB_BEI ? 'B' : 'b', + field3 & TRB_IDT ? 'I' : 'i', + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_NO_SNOOP ? 'S' : 's', + field3 & TRB_ISP ? 'I' : 'i', + field3 & TRB_ENT ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; case TRB_CMD_NOOP: case TRB_ENABLE_SLOT: snprintf(str, size, diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig index 2ed2b73291d181..e19178f3cdd39c 100644 --- a/drivers/usb/isp1760/Kconfig +++ b/drivers/usb/isp1760/Kconfig @@ -26,7 +26,7 @@ config USB_ISP1761_UDC if USB_ISP1760 choice - bool "ISP1760 Mode Selection" + prompt "ISP1760 Mode Selection" default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET) default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET) default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET) diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c index fe1e3985419a28..a64190addba6f9 100644 --- a/drivers/usb/isp1760/isp1760-if.c +++ b/drivers/usb/isp1760/isp1760-if.c @@ -263,7 +263,7 @@ MODULE_DEVICE_TABLE(of, isp1760_of_match); static struct platform_driver isp1760_plat_driver = { .probe = isp1760_plat_probe, - .remove_new = isp1760_plat_remove, + .remove = isp1760_plat_remove, .driver = { .name = "isp1760", .of_match_table = of_match_ptr(isp1760_of_match), diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c index 6fb5140e29b9dd..225863321dc479 100644 --- a/drivers/usb/misc/chaoskey.c +++ b/drivers/usb/misc/chaoskey.c @@ -27,6 +27,8 @@ static struct usb_class_driver chaoskey_class; static int chaoskey_rng_read(struct hwrng *rng, void *data, size_t max, bool wait); +static DEFINE_MUTEX(chaoskey_list_lock); + #define usb_dbg(usb_if, format, arg...) \ dev_dbg(&(usb_if)->dev, format, ## arg) @@ -233,6 +235,7 @@ static void chaoskey_disconnect(struct usb_interface *interface) usb_deregister_dev(interface, &chaoskey_class); usb_set_intfdata(interface, NULL); + mutex_lock(&chaoskey_list_lock); mutex_lock(&dev->lock); dev->present = false; @@ -244,6 +247,7 @@ static void chaoskey_disconnect(struct usb_interface *interface) } else mutex_unlock(&dev->lock); + mutex_unlock(&chaoskey_list_lock); usb_dbg(interface, "disconnect done"); } @@ -251,6 +255,7 @@ static int chaoskey_open(struct inode *inode, struct file *file) { struct chaoskey *dev; struct usb_interface *interface; + int rv = 0; /* get the interface from minor number and driver information */ interface = usb_find_interface(&chaoskey_driver, iminor(inode)); @@ -266,18 +271,23 @@ static int chaoskey_open(struct inode *inode, struct file *file) } file->private_data = dev; + mutex_lock(&chaoskey_list_lock); mutex_lock(&dev->lock); - ++dev->open; + if (dev->present) + ++dev->open; + else + rv = -ENODEV; mutex_unlock(&dev->lock); + mutex_unlock(&chaoskey_list_lock); - usb_dbg(interface, "open success"); - return 0; + return rv; } static int chaoskey_release(struct inode *inode, struct file *file) { struct chaoskey *dev = file->private_data; struct usb_interface *interface; + int rv = 0; if (dev == NULL) return -ENODEV; @@ -286,14 +296,15 @@ static int chaoskey_release(struct inode *inode, struct file *file) usb_dbg(interface, "release"); + mutex_lock(&chaoskey_list_lock); mutex_lock(&dev->lock); usb_dbg(interface, "open count at release is %d", dev->open); if (dev->open <= 0) { usb_dbg(interface, "invalid open count (%d)", dev->open); - mutex_unlock(&dev->lock); - return -ENODEV; + rv = -ENODEV; + goto bail; } --dev->open; @@ -302,13 +313,15 @@ static int chaoskey_release(struct inode *inode, struct file *file) if (dev->open == 0) { mutex_unlock(&dev->lock); chaoskey_free(dev); - } else - mutex_unlock(&dev->lock); - } else - mutex_unlock(&dev->lock); - + goto destruction; + } + } +bail: + mutex_unlock(&dev->lock); +destruction: + mutex_unlock(&chaoskey_list_lock); usb_dbg(interface, "release success"); - return 0; + return rv; } static void chaos_read_callback(struct urb *urb) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 6d28467ce35227..365c1006934583 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -277,28 +277,45 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer, struct iowarrior *dev; int read_idx; int offset; + int retval; dev = file->private_data; + if (file->f_flags & O_NONBLOCK) { + retval = mutex_trylock(&dev->mutex); + if (!retval) + return -EAGAIN; + } else { + retval = mutex_lock_interruptible(&dev->mutex); + if (retval) + return -ERESTARTSYS; + } + /* verify that the device wasn't unplugged */ - if (!dev || !dev->present) - return -ENODEV; + if (!dev->present) { + retval = -ENODEV; + goto exit; + } dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", dev->minor, count); /* read count must be packet size (+ time stamp) */ if ((count != dev->report_size) - && (count != (dev->report_size + 1))) - return -EINVAL; + && (count != (dev->report_size + 1))) { + retval = -EINVAL; + goto exit; + } /* repeat until no buffer overrun in callback handler occur */ do { atomic_set(&dev->overflow_flag, 0); if ((read_idx = read_index(dev)) == -1) { /* queue empty */ - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto exit; + } else { //next line will return when there is either new data, or the device is unplugged int r = wait_event_interruptible(dev->read_wait, @@ -309,28 +326,37 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer, -1)); if (r) { //we were interrupted by a signal - return -ERESTART; + retval = -ERESTART; + goto exit; } if (!dev->present) { //The device was unplugged - return -ENODEV; + retval = -ENODEV; + goto exit; } if (read_idx == -1) { // Can this happen ??? - return 0; + retval = 0; + goto exit; } } } offset = read_idx * (dev->report_size + 1); if (copy_to_user(buffer, dev->read_queue + offset, count)) { - return -EFAULT; + retval = -EFAULT; + goto exit; } } while (atomic_read(&dev->overflow_flag)); read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx; atomic_set(&dev->read_idx, read_idx); + mutex_unlock(&dev->mutex); return count; + +exit: + mutex_unlock(&dev->mutex); + return retval; } /* @@ -885,7 +911,6 @@ static int iowarrior_probe(struct usb_interface *interface, static void iowarrior_disconnect(struct usb_interface *interface) { struct iowarrior *dev = usb_get_intfdata(interface); - int minor = dev->minor; usb_deregister_dev(interface, &iowarrior_class); @@ -909,9 +934,6 @@ static void iowarrior_disconnect(struct usb_interface *interface) mutex_unlock(&dev->mutex); iowarrior_delete(dev); } - - dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", - minor - IOWARRIOR_MINOR_BASE); } /* usb specific object needed to register this driver with the usb subsystem */ diff --git a/drivers/usb/misc/onboard_usb_dev.c b/drivers/usb/misc/onboard_usb_dev.c index 75dfdca04ff1c2..75ac3c6aa92d0d 100644 --- a/drivers/usb/misc/onboard_usb_dev.c +++ b/drivers/usb/misc/onboard_usb_dev.c @@ -407,8 +407,10 @@ static int onboard_dev_probe(struct platform_device *pdev) } if (of_device_is_compatible(pdev->dev.of_node, "usb424,2744") || - of_device_is_compatible(pdev->dev.of_node, "usb424,5744")) + of_device_is_compatible(pdev->dev.of_node, "usb424,5744")) { err = onboard_dev_5744_i2c_init(client); + onboard_dev->always_powered_in_suspend = true; + } put_device(&client->dev); if (err < 0) @@ -473,7 +475,7 @@ static const struct dev_pm_ops __maybe_unused onboard_dev_pm_ops = { static struct platform_driver onboard_dev_driver = { .probe = onboard_dev_probe, - .remove_new = onboard_dev_remove, + .remove = onboard_dev_remove, .driver = { .name = "onboard-usb-dev", diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c index 19906301a4eb8a..83079c414b4f28 100644 --- a/drivers/usb/misc/qcom_eud.c +++ b/drivers/usb/misc/qcom_eud.c @@ -239,7 +239,7 @@ MODULE_DEVICE_TABLE(of, eud_dt_match); static struct platform_driver eud_driver = { .probe = eud_probe, - .remove_new = eud_remove, + .remove = eud_remove, .driver = { .name = "qcom_eud", .dev_groups = eud_groups, diff --git a/drivers/usb/misc/usb-ljca.c b/drivers/usb/misc/usb-ljca.c index 01ceafc4ab78ce..c562630d862c74 100644 --- a/drivers/usb/misc/usb-ljca.c +++ b/drivers/usb/misc/usb-ljca.c @@ -332,14 +332,11 @@ static int ljca_send(struct ljca_adapter *adap, u8 type, u8 cmd, ret = usb_bulk_msg(adap->usb_dev, adap->tx_pipe, header, msg_len, &transferred, LJCA_WRITE_TIMEOUT_MS); - - usb_autopm_put_interface(adap->intf); - if (ret < 0) - goto out; + goto out_put; if (transferred != msg_len) { ret = -EIO; - goto out; + goto out_put; } if (ack) { @@ -347,11 +344,14 @@ static int ljca_send(struct ljca_adapter *adap, u8 type, u8 cmd, timeout); if (!ret) { ret = -ETIMEDOUT; - goto out; + goto out_put; } } ret = adap->actual_length; +out_put: + usb_autopm_put_interface(adap->intf); + out: spin_lock_irqsave(&adap->lock, flags); adap->ex_buf = NULL; @@ -372,7 +372,7 @@ int ljca_transfer(struct ljca_client *client, u8 cmd, const u8 *obuf, obuf, obuf_len, ibuf, ibuf_len, true, LJCA_WRITE_ACK_TIMEOUT_MS); } -EXPORT_SYMBOL_NS_GPL(ljca_transfer, LJCA); +EXPORT_SYMBOL_NS_GPL(ljca_transfer, "LJCA"); int ljca_transfer_noack(struct ljca_client *client, u8 cmd, const u8 *obuf, u8 obuf_len) @@ -380,7 +380,7 @@ int ljca_transfer_noack(struct ljca_client *client, u8 cmd, const u8 *obuf, return ljca_send(client->adapter, client->type, cmd, obuf, obuf_len, NULL, 0, false, LJCA_WRITE_ACK_TIMEOUT_MS); } -EXPORT_SYMBOL_NS_GPL(ljca_transfer_noack, LJCA); +EXPORT_SYMBOL_NS_GPL(ljca_transfer_noack, "LJCA"); int ljca_register_event_cb(struct ljca_client *client, ljca_event_cb_t event_cb, void *context) @@ -404,7 +404,7 @@ int ljca_register_event_cb(struct ljca_client *client, ljca_event_cb_t event_cb, return 0; } -EXPORT_SYMBOL_NS_GPL(ljca_register_event_cb, LJCA); +EXPORT_SYMBOL_NS_GPL(ljca_register_event_cb, "LJCA"); void ljca_unregister_event_cb(struct ljca_client *client) { @@ -417,7 +417,7 @@ void ljca_unregister_event_cb(struct ljca_client *client) spin_unlock_irqrestore(&client->event_cb_lock, flags); } -EXPORT_SYMBOL_NS_GPL(ljca_unregister_event_cb, LJCA); +EXPORT_SYMBOL_NS_GPL(ljca_unregister_event_cb, "LJCA"); static int ljca_match_device_ids(struct acpi_device *adev, void *data) { @@ -811,6 +811,14 @@ static int ljca_probe(struct usb_interface *interface, if (ret) goto err_free; + /* + * This works around problems with ov2740 initialization on some + * Lenovo platforms. The autosuspend delay, has to be smaller than + * the delay after setting the reset_gpio line in ov2740_resume(). + * Otherwise the sensor randomly fails to initialize. + */ + pm_runtime_set_autosuspend_delay(&usb_dev->dev, 10); + usb_enable_autosuspend(usb_dev); return 0; diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index 3b33e4878c608e..322e59381b7830 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -423,7 +423,7 @@ static struct platform_driver usb3503_platform_driver = { .pm = pm_ptr(&usb3503_platform_pm_ops), }, .probe = usb3503_platform_probe, - .remove_new = usb3503_platform_remove, + .remove = usb3503_platform_remove, }; static int __init usb3503_init(void) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index caf65f8294db22..8d379ae835bc45 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -2021,7 +2021,8 @@ static struct urb *iso_alloc_urb( for (i = 0; i < packets; i++) { /* here, only the last packet will be short */ - urb->iso_frame_desc[i].length = min((unsigned) bytes, maxp); + urb->iso_frame_desc[i].length = min_t(unsigned int, + bytes, maxp); bytes -= urb->iso_frame_desc[i].length; urb->iso_frame_desc[i].offset = maxp * i; diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 6aebc736a80c66..70dff0db5354ff 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -441,7 +441,10 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, if (count == 0) goto error; - mutex_lock(&dev->io_mutex); + retval = mutex_lock_interruptible(&dev->io_mutex); + if (retval < 0) + return -EINTR; + if (dev->disconnected) { /* already disconnected */ mutex_unlock(&dev->io_mutex); retval = -ENODEV; diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index afb71c18415dd1..c93b43f5bc4614 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -823,7 +823,7 @@ static ssize_t mon_bin_read(struct file *file, char __user *buf, ep = MON_OFF2HDR(rp, rp->b_out); if (rp->b_read < hdrbytes) { - step_len = min(nbytes, (size_t)(hdrbytes - rp->b_read)); + step_len = min_t(size_t, nbytes, hdrbytes - rp->b_read); ptr = ((char *)ep) + rp->b_read; if (step_len && copy_to_user(buf, ptr, step_len)) { mutex_unlock(&rp->fetch_lock); diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig index bf98fd36341dab..d281da1cdbccf2 100644 --- a/drivers/usb/mtu3/Kconfig +++ b/drivers/usb/mtu3/Kconfig @@ -21,7 +21,7 @@ config USB_MTU3 if USB_MTU3 choice - bool "MTU3 Mode Selection" + prompt "MTU3 Mode Selection" default USB_MTU3_DUAL_ROLE if (USB && USB_GADGET) default USB_MTU3_HOST if (USB && !USB_GADGET) default USB_MTU3_GADGET if (!USB && USB_GADGET) diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 6858ed9fc3b2f1..7b5a431acb5657 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -307,7 +307,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) if (otg_sx->role_sw_used || otg_sx->manual_drd_enabled) goto out; - if (of_property_read_bool(node, "extcon")) { + if (of_property_present(node, "extcon")) { otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0); if (IS_ERR(otg_sx->edev)) { return dev_err_probe(dev, PTR_ERR(otg_sx->edev), @@ -621,7 +621,7 @@ MODULE_DEVICE_TABLE(of, mtu3_of_match); static struct platform_driver mtu3_driver = { .probe = mtu3_probe, - .remove_new = mtu3_remove, + .remove = mtu3_remove, .driver = { .name = MTU3_DRIVER_NAME, .pm = DEV_PM_OPS, diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 9a8cf3de061700..9e45d12b81d38d 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -29,7 +29,7 @@ config USB_MUSB_HDRC if USB_MUSB_HDRC choice - bool "MUSB Mode Selection" + prompt "MUSB Mode Selection" default USB_MUSB_DUAL_ROLE if (USB && USB_GADGET) default USB_MUSB_HOST if (USB && !USB_GADGET) default USB_MUSB_GADGET if (!USB && USB_GADGET) diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 953094c1930c8f..f772aa272bea65 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -633,7 +633,7 @@ MODULE_DEVICE_TABLE(of, da8xx_id_table); static struct platform_driver da8xx_driver = { .probe = da8xx_probe, - .remove_new = da8xx_remove, + .remove = 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 b38df9226278b0..acdeb1117cd3f6 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -325,7 +325,7 @@ MODULE_DEVICE_TABLE(of, jz4740_musb_of_match); static struct platform_driver jz4740_driver = { .probe = jz4740_probe, - .remove_new = jz4740_remove, + .remove = 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 63c86c046b9865..aa988d74b58d0f 100644 --- a/drivers/usb/musb/mediatek.c +++ b/drivers/usb/musb/mediatek.c @@ -523,7 +523,7 @@ MODULE_DEVICE_TABLE(of, mtk_musb_match); static struct platform_driver mtk_musb_driver = { .probe = mtk_musb_probe, - .remove_new = mtk_musb_remove, + .remove = 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 00e13214aa766c..7edc8429b27490 100644 --- a/drivers/usb/musb/mpfs.c +++ b/drivers/usb/musb/mpfs.c @@ -369,7 +369,7 @@ MODULE_DEVICE_TABLE(of, mpfs_id_table); static struct platform_driver mpfs_musb_driver = { .probe = mpfs_probe, - .remove_new = mpfs_remove, + .remove = 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 b24adb5b399fc7..03b1154a6014ab 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1387,7 +1387,7 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, /* expect hw_ep has already been zero-initialized */ - size = ffs(max(maxpacket, (u16) 8)) - 1; + size = ffs(max_t(u16, maxpacket, 8)) - 1; maxpacket = 1 << size; c_size = size - 3; @@ -2953,7 +2953,7 @@ static struct platform_driver musb_driver = { .dev_groups = musb_groups, }, .probe = musb_probe, - .remove_new = musb_remove, + .remove = musb_remove, }; module_platform_driver(musb_driver); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 9c7a8bbc0542ce..2542239ec64eaf 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -1032,7 +1032,7 @@ static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, - .remove_new = dsps_remove, + .remove = dsps_remove, .driver = { .name = "musb-dsps", .pm = &dsps_pm_ops, diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index bdf13911a1e590..c6076df0d50cc7 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1161,12 +1161,19 @@ void musb_free_request(struct usb_ep *ep, struct usb_request *req) */ void musb_ep_restart(struct musb *musb, struct musb_request *req) { + u16 csr; + void __iomem *epio = req->ep->hw_ep->regs; + trace_musb_req_start(req); musb_ep_select(musb->mregs, req->epnum); - if (req->tx) + if (req->tx) { txstate(musb, req); - else - rxstate(musb, req); + } else { + csr = musb_readw(epio, MUSB_RXCSR); + csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_P_WZC_BITS; + musb_writew(epio, MUSB_RXCSR, csr); + musb_writew(epio, MUSB_RXCSR, csr); + } } static int musb_ep_restart_resume_work(struct musb *musb, void *data) diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 6d7336727388b6..f0786f8fbb25c2 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -533,7 +533,7 @@ static void ep0_txstate(struct musb *musb) /* load the data */ fifo_src = (u8 *) request->buf + request->actual; - fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE, + fifo_count = min_t(unsigned, MUSB_EP0_FIFOSIZE, request->length - request->actual); musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src); request->actual += fifo_count; diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index bc450778116796..732ba981e607e7 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -798,10 +798,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum, } if (can_bulk_split(musb, qh->type)) - load_count = min((u32) hw_ep->max_packet_sz_tx, - len); + load_count = min_t(u32, hw_ep->max_packet_sz_tx, len); else - load_count = min((u32) packet_sz, len); + load_count = min_t(u32, packet_sz, len); if (dma_channel && musb_tx_dma_program(dma_controller, hw_ep, qh, urb, offset, len)) diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index b4a4c1df4e0d96..2970967a4fd28b 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -608,7 +608,7 @@ MODULE_DEVICE_TABLE(of, omap2430_id_table); static struct platform_driver omap2430_driver = { .probe = omap2430_probe, - .remove_new = omap2430_remove, + .remove = 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 05b6e7e52e0275..eac1cde86be3fd 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -857,7 +857,7 @@ MODULE_DEVICE_TABLE(of, sunxi_musb_match); static struct platform_driver sunxi_musb_driver = { .probe = sunxi_musb_probe, - .remove_new = sunxi_musb_remove, + .remove = 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 461587629bf261..90b760a95e4e34 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1290,7 +1290,7 @@ static void tusb_remove(struct platform_device *pdev) static struct platform_driver tusb_driver = { .probe = tusb_probe, - .remove_new = tusb_remove, + .remove = tusb_remove, .driver = { .name = "musb-tusb", }, diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index c8d9d2a1d2f036..8c2a43d992f5c9 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -355,7 +355,7 @@ MODULE_DEVICE_TABLE(of, ux500_match); static struct platform_driver ux500_driver = { .probe = ux500_probe, - .remove_new = ux500_remove, + .remove = 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 408f47e390259f..6a98aeeeae319c 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -987,7 +987,7 @@ MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype); static struct platform_driver ab8500_usb_driver = { .probe = ab8500_usb_probe, - .remove_new = ab8500_usb_remove, + .remove = 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 6db88e00f127c1..ca9353dad71aa2 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -133,7 +133,7 @@ MODULE_DEVICE_TABLE(of, am335x_phy_ids); static struct platform_driver am335x_phy_driver = { .probe = am335x_phy_probe, - .remove_new = am335x_phy_remove, + .remove = 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 c5c6b818998eea..42c42e1932326c 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -1002,7 +1002,7 @@ static void fsl_otg_remove(struct platform_device *pdev) struct platform_driver fsl_otg_driver = { .probe = fsl_otg_probe, - .remove_new = fsl_otg_remove, + .remove = fsl_otg_remove, .driver = { .name = driver_name, }, diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index e7d50e0a161238..6c3ececf913752 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -345,7 +345,7 @@ MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); static struct platform_driver usb_phy_generic_driver = { .probe = usb_phy_generic_probe, - .remove_new = usb_phy_generic_remove, + .remove = 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 5428b2b67de1fc..ce09e789afd882 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -385,7 +385,7 @@ static struct platform_driver gpio_vbus_driver = { .of_match_table = gpio_vbus_of_match, }, .probe = gpio_vbus_probe, - .remove_new = gpio_vbus_remove, + .remove = gpio_vbus_remove, }; module_platform_driver(gpio_vbus_driver); diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index 993d7525a10211..f9b5c411aee4e5 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -25,7 +25,7 @@ struct isp1301 { #define phy_to_isp(p) (container_of((p), struct isp1301, phy)) static const struct i2c_device_id isp1301_id[] = { - { "isp1301", 0 }, + { "isp1301" }, { } }; MODULE_DEVICE_TABLE(i2c, isp1301_id); diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index bd9a98ad1b3093..51155c5513d3c6 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -103,7 +103,7 @@ MODULE_DEVICE_TABLE(of, keystone_usbphy_ids); static struct platform_driver keystone_usbphy_driver = { .probe = keystone_usbphy_probe, - .remove_new = keystone_usbphy_remove, + .remove = 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 df7c27474a75a6..a7a102f2e163fa 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -867,7 +867,7 @@ static int mv_otg_resume(struct platform_device *pdev) static struct platform_driver mv_otg_driver = { .probe = mv_otg_probe, - .remove_new = mv_otg_remove, + .remove = 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 cc4156c1b148ee..7490f1798b461c 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -952,7 +952,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_new = mxs_phy_remove, + .remove = 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 5cac31c6029b38..ae7bf3ff89ee17 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -424,7 +424,7 @@ static void tahvo_usb_remove(struct platform_device *pdev) static struct platform_driver tahvo_usb_driver = { .probe = tahvo_usb_probe, - .remove_new = tahvo_usb_remove, + .remove = 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 4ea47e6f835bfb..bee222967f6b19 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -1495,7 +1495,7 @@ static void tegra_usb_phy_remove(struct platform_device *pdev) static struct platform_driver tegra_usb_phy_driver = { .probe = tegra_usb_phy_probe, - .remove_new = tegra_usb_phy_remove, + .remove = 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 da09cff55abcec..49d79c1257f3a4 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -432,7 +432,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table); static struct platform_driver twl6030_usb_driver = { .probe = twl6030_usb_probe, - .remove_new = twl6030_usb_remove, + .remove = twl6030_usb_remove, .driver = { .name = "twl6030_usb", .of_match_table = of_match_ptr(twl6030_usb_id_table), diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 06f789097989f1..1ce134505cee86 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -365,7 +365,7 @@ static int usb_add_extcon(struct usb_phy *x) { int ret; - if (of_property_read_bool(x->dev->of_node, "extcon")) { + if (of_property_present(x->dev->of_node, "extcon")) { x->edev = extcon_get_edev_by_phandle(x->dev, 0); if (IS_ERR(x->edev)) return PTR_ERR(x->edev); diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index edc43f169d493c..935fc496fe94b6 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -632,7 +632,7 @@ static int usbhs_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - if (of_property_read_bool(dev_of_node(dev), "extcon")) { + if (of_property_present(dev_of_node(dev), "extcon")) { priv->edev = extcon_get_edev_by_phandle(dev, 0); if (IS_ERR(priv->edev)) return PTR_ERR(priv->edev); @@ -835,7 +835,7 @@ static struct platform_driver renesas_usbhs_driver = { .of_match_table = usbhs_of_match, }, .probe = usbhs_probe, - .remove_new = usbhs_remove, + .remove = usbhs_remove, }; module_platform_driver(renesas_usbhs_driver); diff --git a/drivers/usb/roles/intel-xhci-usb-role-switch.c b/drivers/usb/roles/intel-xhci-usb-role-switch.c index e5c6c413a075b6..cd2e026dcb22f1 100644 --- a/drivers/usb/roles/intel-xhci-usb-role-switch.c +++ b/drivers/usb/roles/intel-xhci-usb-role-switch.c @@ -217,7 +217,7 @@ static struct platform_driver intel_xhci_usb_driver = { }, .id_table = intel_xhci_usb_table, .probe = intel_xhci_usb_probe, - .remove_new = intel_xhci_usb_remove, + .remove = intel_xhci_usb_remove, }; module_platform_driver(intel_xhci_usb_driver); diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index d200e2c29a8ffe..2fea1b1db4a269 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -136,12 +136,11 @@ static void free_dynids(struct usb_serial_driver *drv) { struct usb_dynid *dynid, *n; - spin_lock(&drv->dynids.lock); + guard(mutex)(&usb_dynids_lock); list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { list_del(&dynid->node); kfree(dynid); } - spin_unlock(&drv->dynids.lock); } const struct bus_type usb_serial_bus_type = { @@ -157,7 +156,6 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) int retval; driver->driver.bus = &usb_serial_bus_type; - spin_lock_init(&driver->dynids.lock); INIT_LIST_HEAD(&driver->dynids.list); retval = driver_register(&driver->driver); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c6f17d732b9581..e07c5e3eb18c0d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1443,9 +1443,11 @@ static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss) struct usb_serial_port *port = tty->driver_data; struct ftdi_private *priv = usb_get_serial_port_data(port); + mutex_lock(&priv->cfg_lock); ss->flags = priv->flags; ss->baud_base = priv->baud_base; ss->custom_divisor = priv->custom_divisor; + mutex_unlock(&priv->cfg_lock); } static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 28c71d99e85726..1fffda7647f989 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1129,7 +1129,7 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, spin_lock_irqsave(&edge_port->ep_lock, flags); /* calculate number of bytes to put in fifo */ - copySize = min((unsigned int)count, + copySize = min_t(unsigned int, count, (edge_port->txCredits - fifo->count)); dev_dbg(&port->dev, "%s of %d byte(s) Fifo room %d -- will copy %d bytes\n", diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 9ba5584061c8c4..64317b390d2285 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -625,6 +625,8 @@ static void option_instat_callback(struct urb *urb); #define MEIGSMART_PRODUCT_SRM825L 0x4d22 /* MeiG Smart SLM320 based on UNISOC UIS8910 */ #define MEIGSMART_PRODUCT_SLM320 0x4d41 +/* MeiG Smart SLM770A based on ASR1803 */ +#define MEIGSMART_PRODUCT_SLM770A 0x4d57 /* Device flags */ @@ -1395,6 +1397,12 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10aa, 0xff), /* Telit FN920C04 (MBIM) */ .driver_info = NCTRL(3) | RSVD(4) | RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c0, 0xff), /* Telit FE910C04 (rmnet) */ + .driver_info = RSVD(0) | NCTRL(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c4, 0xff), /* Telit FE910C04 (rmnet) */ + .driver_info = RSVD(0) | NCTRL(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c8, 0xff), /* Telit FE910C04 (rmnet) */ + .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), @@ -2247,6 +2255,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(2) }, { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x7127, 0xff, 0x00, 0x00), .driver_info = NCTRL(2) | NCTRL(3) | NCTRL(4) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x7129, 0xff, 0x00, 0x00), /* MediaTek T7XX */ + .driver_info = NCTRL(2) | NCTRL(3) | NCTRL(4) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MPL200), .driver_info = RSVD(1) | RSVD(4) }, @@ -2375,6 +2385,18 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0116, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Golbal EDU */ { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0116, 0xff, 0x00, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0116, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010a, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WRD for WWAN Ready */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010a, 0xff, 0x00, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010a, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010b, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for WWAN Ready */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010b, 0xff, 0x00, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010b, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010c, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WRD for WWAN Ready */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010c, 0xff, 0x00, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010c, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010d, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for WWAN Ready */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010d, 0xff, 0x00, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x010d, 0xff, 0xff, 0x40) }, { 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, 0xff, 0x40) }, @@ -2382,9 +2404,14 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM320, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM770A, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x60) }, + { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0530, 0xff), /* TCL IK512 MBIM */ + .driver_info = NCTRL(1) }, + { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0640, 0xff), /* TCL IK512 ECM */ + .driver_info = NCTRL(3) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ad41363e3cea5a..010688dd9e49ce 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -31,6 +31,7 @@ #define PL2303_QUIRK_UART_STATE_IDX0 BIT(0) #define PL2303_QUIRK_LEGACY BIT(1) #define PL2303_QUIRK_ENDPOINT_HACK BIT(2) +#define PL2303_QUIRK_NO_BREAK_GETLINE BIT(3) static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID), @@ -467,6 +468,25 @@ static int pl2303_detect_type(struct usb_serial *serial) return -ENODEV; } +static bool pl2303_is_hxd_clone(struct usb_serial *serial) +{ + struct usb_device *udev = serial->dev; + unsigned char *buf; + int ret; + + buf = kmalloc(7, GFP_KERNEL); + if (!buf) + return false; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, + 0, 0, buf, 7, 100); + + kfree(buf); + + return ret == -EPIPE; +} + static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; @@ -489,6 +509,9 @@ static int pl2303_startup(struct usb_serial *serial) spriv->quirks = (unsigned long)usb_get_serial_data(serial); spriv->quirks |= spriv->type->quirks; + if (type == TYPE_HXD && pl2303_is_hxd_clone(serial)) + spriv->quirks |= PL2303_QUIRK_NO_BREAK_GETLINE; + usb_set_serial_data(serial, spriv); if (type != TYPE_HXN) { @@ -725,9 +748,18 @@ static void pl2303_encode_baud_rate(struct tty_struct *tty, static int pl2303_get_line_request(struct usb_serial_port *port, unsigned char buf[7]) { - struct usb_device *udev = port->serial->dev; + struct usb_serial *serial = port->serial; + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); + struct usb_device *udev = serial->dev; int ret; + if (spriv->quirks & PL2303_QUIRK_NO_BREAK_GETLINE) { + struct pl2303_private *priv = usb_get_serial_port_data(port); + + memcpy(buf, priv->line_settings, 7); + return 0; + } + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); @@ -1064,9 +1096,13 @@ static int pl2303_carrier_raised(struct usb_serial_port *port) static int pl2303_set_break(struct usb_serial_port *port, bool enable) { struct usb_serial *serial = port->serial; + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); u16 state; int result; + if (spriv->quirks & PL2303_QUIRK_NO_BREAK_GETLINE) + return -ENOTTY; + if (enable) state = BREAK_ON; else diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 64a2e0bb5723ed..741e68e4613960 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -421,7 +421,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, unsigned long flags; unsigned char *buffer; struct urb *urb; - size_t writesize = min((size_t)count, (size_t)MAX_TRANSFER); + size_t writesize = min_t(size_t, count, MAX_TRANSFER); int retval = 0; /* verify that we actually have some data to write */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index df6a2ae0bf4246..7266558d823ac2 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -706,14 +706,12 @@ static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, { struct usb_dynid *dynid; - spin_lock(&drv->dynids.lock); + guard(mutex)(&usb_dynids_lock); list_for_each_entry(dynid, &drv->dynids.list, node) { if (usb_match_one_id(intf, &dynid->id)) { - spin_unlock(&drv->dynids.lock); return &dynid->id; } } - spin_unlock(&drv->dynids.lock); return NULL; } diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile index 46635fa4a3405d..28db337f190bf5 100644 --- a/drivers/usb/storage/Makefile +++ b/drivers/usb/storage/Makefile @@ -8,7 +8,7 @@ ccflags-y := -I $(srctree)/drivers/scsi -ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=USB_STORAGE +ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE='"USB_STORAGE"' obj-$(CONFIG_USB_UAS) += uas.o obj-$(CONFIG_USB_STORAGE) += usb-storage.o diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index a9d3c58ce7d935..6263c4e61678e8 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -36,7 +36,7 @@ MODULE_DESCRIPTION("Driver for Alauda-based card readers"); MODULE_AUTHOR("Daniel Drake "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); /* * Status bytes diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c index 30dfd0082474c3..2fce5f95be515d 100644 --- a/drivers/usb/storage/cypress_atacb.c +++ b/drivers/usb/storage/cypress_atacb.c @@ -22,7 +22,7 @@ MODULE_DESCRIPTION("SAT support for Cypress USB/ATA bridges with ATACB"); MODULE_AUTHOR("Matthieu Castet "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); /* * The table of devices diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 3ea5601d16b8b7..bbfa2398b17036 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -54,7 +54,7 @@ MODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader"); MODULE_AUTHOR("Jimmie Mayfield "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); struct datafab_info { unsigned long sectors; /* total sector count */ diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index a4bfbecbf16c33..ce91fb1059754d 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -26,7 +26,7 @@ MODULE_DESCRIPTION("Driver for ENE UB6250 reader"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); MODULE_FIRMWARE(SD_INIT1_FIRMWARE); MODULE_FIRMWARE(SD_INIT2_FIRMWARE); MODULE_FIRMWARE(SD_RW_FIRMWARE); @@ -737,7 +737,7 @@ static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb) memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = blenByte; - bcb->Flags = 0x00; + bcb->Flags = US_BULK_FLAG_OUT; bcb->CDB[0] = 0xF0; bcb->CDB[5] = (unsigned char)(bnByte); bcb->CDB[4] = (unsigned char)(bnByte>>8); @@ -1163,7 +1163,7 @@ static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy, memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = 0x200*len; - bcb->Flags = 0x00; + bcb->Flags = US_BULK_FLAG_OUT; bcb->CDB[0] = 0xF0; bcb->CDB[1] = 0x08; bcb->CDB[4] = (unsigned char)(oldphy); @@ -1759,7 +1759,7 @@ static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb) memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = blenByte; - bcb->Flags = 0x00; + bcb->Flags = US_BULK_FLAG_OUT; bcb->CDB[0] = 0xF0; bcb->CDB[1] = 0x04; bcb->CDB[5] = (unsigned char)(bn); @@ -1931,7 +1931,7 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag) memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = sd_fw->size; - bcb->Flags = 0x00; + bcb->Flags = US_BULK_FLAG_OUT; bcb->CDB[0] = 0xEF; result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0); diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index cab27ba7a32a65..a075620907b49e 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -29,7 +29,7 @@ MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor"); MODULE_AUTHOR("David Brown "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); #ifdef CONFIG_USB_STORAGE_DEBUG static void pdump(struct us_data *us, void *ibuffer, int length); diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index f2254eb3c0d73f..a1669c35bad5e8 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -53,7 +53,7 @@ MODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC"); MODULE_AUTHOR("Björn Stenberg "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); static int isd200_Initialization(struct us_data *us); diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index 0e71a8f33c2b63..39ca84d6859122 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -51,7 +51,7 @@ MODULE_DESCRIPTION("Driver for Lexar \"Jumpshot\" Compact Flash reader"); MODULE_AUTHOR("Jimmie Mayfield "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); /* * The table of devices diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index d6a5e54f2ca823..341d6839548a02 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -23,7 +23,7 @@ MODULE_DESCRIPTION("Driver for Rio Karma"); MODULE_AUTHOR("Bob Copeland , Keith Bennett "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); #define RIO_PREFIX "RIOP\x00" #define RIO_PREFIX_LEN 5 diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index f97cf6cadb8eb7..5a8a1ffda0ec94 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -25,7 +25,7 @@ MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver"); MODULE_AUTHOR("Nick Sillik "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); #define ONETOUCH_PKT_LEN 0x02 #define ONETOUCH_BUTTON KEY_PROG1 diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 0c423916d7bfa4..2a82ed7b68eaa7 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -35,7 +35,7 @@ MODULE_DESCRIPTION("Driver for Realtek USB Card Reader"); MODULE_AUTHOR("wwang "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); static int auto_delink_en = 1; module_param(auto_delink_en, int, S_IRUGO | S_IWUSR); @@ -212,7 +212,7 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun, /* set up the command wrapper */ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = cpu_to_le32(buf_len); - bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0; + bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : US_BULK_FLAG_OUT; bcb->Tag = ++us->tag; bcb->Lun = lun; bcb->Length = cmd_len; @@ -301,7 +301,7 @@ static int rts51x_bulk_transport_special(struct us_data *us, u8 lun, /* set up the command wrapper */ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = cpu_to_le32(buf_len); - bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0; + bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : US_BULK_FLAG_OUT; bcb->Tag = ++us->tag; bcb->Lun = lun; bcb->Length = cmd_len; diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 03d1b9c69ea18f..d21ce3466e2584 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -47,7 +47,7 @@ MODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader"); MODULE_AUTHOR("Andries Brouwer , Robert Baruch "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); static int usb_stor_sddr09_dpcm_init(struct us_data *us); static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us); @@ -752,7 +752,7 @@ sddr09_read_data(struct us_data *us, // a bounce buffer and move the data a piece at a time between the // bounce buffer and the actual transfer buffer. - len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; + len = min_t(unsigned int, sectors, info->blocksize) * info->pagesize; buffer = kmalloc(len, GFP_NOIO); if (!buffer) return -ENOMEM; @@ -997,7 +997,7 @@ sddr09_write_data(struct us_data *us, * at a time between the bounce buffer and the actual transfer buffer. */ - len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; + len = min_t(unsigned int, sectors, info->blocksize) * info->pagesize; buffer = kmalloc(len, GFP_NOIO); if (!buffer) { kfree(blockbuffer); diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index b8227478a7add2..d5cdff30f6f31f 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -29,7 +29,7 @@ MODULE_DESCRIPTION("Driver for SanDisk SDDR-55 SmartMedia reader"); MODULE_AUTHOR("Simon Munton"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); /* * The table of devices @@ -206,7 +206,7 @@ static int sddr55_read_data(struct us_data *us, // a bounce buffer and move the data a piece at a time between the // bounce buffer and the actual transfer buffer. - len = min((unsigned int) sectors, (unsigned int) info->blocksize >> + len = min_t(unsigned int, sectors, info->blocksize >> info->smallpageshift) * PAGESIZE; buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) @@ -224,7 +224,7 @@ static int sddr55_read_data(struct us_data *us, // Read as many sectors as possible in this block - pages = min((unsigned int) sectors << info->smallpageshift, + pages = min_t(unsigned int, sectors << info->smallpageshift, info->blocksize - page); len = pages << info->pageshift; @@ -333,7 +333,7 @@ static int sddr55_write_data(struct us_data *us, // a bounce buffer and move the data a piece at a time between the // bounce buffer and the actual transfer buffer. - len = min((unsigned int) sectors, (unsigned int) info->blocksize >> + len = min_t(unsigned int, sectors, info->blocksize >> info->smallpageshift) * PAGESIZE; buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) @@ -351,7 +351,7 @@ static int sddr55_write_data(struct us_data *us, // Write as many sectors as possible in this block - pages = min((unsigned int) sectors << info->smallpageshift, + pages = min_t(unsigned int, sectors << info->smallpageshift, info->blocksize - page); len = pages << info->pageshift; diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index e7c224b7c46463..087c706bb315f9 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -48,7 +48,7 @@ MODULE_DESCRIPTION("Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable"); MODULE_AUTHOR("Daniel Drake , Robert Baruch "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); /* Supported device types */ #define USBAT_DEV_HP8200 0x01 diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 7449e379077a58..9d767f6bf7225f 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1133,7 +1133,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->DataTransferLength = cpu_to_le32(transfer_length); bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? - US_BULK_FLAG_IN : 0; + US_BULK_FLAG_IN : US_BULK_FLAG_OUT; bcb->Tag = ++us->tag; bcb->Lun = srb->device->lun; if (us->fflags & US_FL_SCM_MULT_TARG) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 03043d567fa1be..f9ad90ce7af4bf 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -1289,6 +1289,6 @@ module_exit(uas_exit); MODULE_DESCRIPTION("USB Attached SCSI driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(USB_STORAGE); +MODULE_IMPORT_NS("USB_STORAGE"); MODULE_AUTHOR( "Hans de Goede , Matthew Wilcox and Sarah Sharp"); diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 92cc1b13612084..2f03190a9873ac 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -729,7 +729,7 @@ int dp_altmode_probe(struct typec_altmode *alt) /* FIXME: Port can only be DFP_U. */ - /* Make sure we have compatiple pin configurations */ + /* Make sure we have compatible pin configurations */ if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index d1e7c487ddfbb5..0ae0a5ee3fae07 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -290,6 +290,8 @@ struct anx7411_data { struct power_supply *psy; struct power_supply_desc psy_desc; struct device *dev; + struct fwnode_handle *switch_node; + struct fwnode_handle *mux_node; }; static u8 snk_identity[] = { @@ -1021,6 +1023,16 @@ static void anx7411_port_unregister_altmodes(struct typec_altmode **adev) } } +static void anx7411_port_unregister(struct typec_params *typecp) +{ + fwnode_handle_put(typecp->caps.fwnode); + anx7411_port_unregister_altmodes(typecp->port_amode); + if (typecp->port) + typec_unregister_port(typecp->port); + if (typecp->role_sw) + usb_role_switch_put(typecp->role_sw); +} + static int anx7411_usb_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state) { @@ -1089,6 +1101,7 @@ static void anx7411_unregister_mux(struct anx7411_data *ctx) if (ctx->typec.typec_mux) { typec_mux_unregister(ctx->typec.typec_mux); ctx->typec.typec_mux = NULL; + fwnode_handle_put(ctx->mux_node); } } @@ -1097,6 +1110,7 @@ static void anx7411_unregister_switch(struct anx7411_data *ctx) if (ctx->typec.typec_switch) { typec_switch_unregister(ctx->typec.typec_switch); ctx->typec.typec_switch = NULL; + fwnode_handle_put(ctx->switch_node); } } @@ -1104,28 +1118,29 @@ static int anx7411_typec_switch_probe(struct anx7411_data *ctx, struct device *dev) { int ret; - struct device_node *node; - node = of_get_child_by_name(dev->of_node, "orientation_switch"); - if (!node) + ctx->switch_node = device_get_named_child_node(dev, "orientation_switch"); + if (!ctx->switch_node) return 0; - ret = anx7411_register_switch(ctx, dev, &node->fwnode); + ret = anx7411_register_switch(ctx, dev, ctx->switch_node); if (ret) { dev_err(dev, "failed register switch"); + fwnode_handle_put(ctx->switch_node); return ret; } - node = of_get_child_by_name(dev->of_node, "mode_switch"); - if (!node) { + ctx->mux_node = device_get_named_child_node(dev, "mode_switch"); + if (!ctx->mux_node) { dev_err(dev, "no typec mux exist"); ret = -ENODEV; goto unregister_switch; } - ret = anx7411_register_mux(ctx, dev, &node->fwnode); + ret = anx7411_register_mux(ctx, dev, ctx->mux_node); if (ret) { dev_err(dev, "failed register mode switch"); + fwnode_handle_put(ctx->mux_node); ret = -ENODEV; goto unregister_switch; } @@ -1154,34 +1169,34 @@ static int anx7411_typec_port_probe(struct anx7411_data *ctx, ret = fwnode_property_read_string(fwnode, "power-role", &buf); if (ret) { dev_err(dev, "power-role not found: %d\n", ret); - return ret; + goto put_fwnode; } ret = typec_find_port_power_role(buf); if (ret < 0) - return ret; + goto put_fwnode; cap->type = ret; ret = fwnode_property_read_string(fwnode, "data-role", &buf); if (ret) { dev_err(dev, "data-role not found: %d\n", ret); - return ret; + goto put_fwnode; } ret = typec_find_port_data_role(buf); if (ret < 0) - return ret; + goto put_fwnode; cap->data = ret; ret = fwnode_property_read_string(fwnode, "try-power-role", &buf); if (ret) { dev_err(dev, "try-power-role not found: %d\n", ret); - return ret; + goto put_fwnode; } ret = typec_find_power_role(buf); if (ret < 0) - return ret; + goto put_fwnode; cap->prefer_role = ret; /* Get source pdos */ @@ -1193,7 +1208,7 @@ static int anx7411_typec_port_probe(struct anx7411_data *ctx, typecp->src_pdo_nr); if (ret < 0) { dev_err(dev, "source cap validate failed: %d\n", ret); - return -EINVAL; + goto put_fwnode; } typecp->caps_flags |= HAS_SOURCE_CAP; @@ -1207,7 +1222,7 @@ static int anx7411_typec_port_probe(struct anx7411_data *ctx, typecp->sink_pdo_nr); if (ret < 0) { dev_err(dev, "sink cap validate failed: %d\n", ret); - return -EINVAL; + goto put_fwnode; } for (i = 0; i < typecp->sink_pdo_nr; i++) { @@ -1251,13 +1266,21 @@ static int anx7411_typec_port_probe(struct anx7411_data *ctx, ret = PTR_ERR(ctx->typec.port); ctx->typec.port = NULL; dev_err(dev, "Failed to register type c port %d\n", ret); - return ret; + goto put_usb_role_switch; } typec_port_register_altmodes(ctx->typec.port, NULL, ctx, ctx->typec.port_amode, MAX_ALTMODE); return 0; + +put_usb_role_switch: + if (ctx->typec.role_sw) + usb_role_switch_put(ctx->typec.role_sw); +put_fwnode: + fwnode_handle_put(fwnode); + + return ret; } static int anx7411_typec_check_connection(struct anx7411_data *ctx) @@ -1523,8 +1546,7 @@ static int anx7411_i2c_probe(struct i2c_client *client) destroy_workqueue(plat->workqueue); free_typec_port: - typec_unregister_port(plat->typec.port); - anx7411_port_unregister_altmodes(plat->typec.port_amode); + anx7411_port_unregister(&plat->typec); free_typec_switch: anx7411_unregister_switch(plat); @@ -1548,17 +1570,11 @@ static void anx7411_i2c_remove(struct i2c_client *client) i2c_unregister_device(plat->spi_client); - if (plat->typec.role_sw) - usb_role_switch_put(plat->typec.role_sw); - anx7411_unregister_mux(plat); anx7411_unregister_switch(plat); - if (plat->typec.port) - typec_unregister_port(plat->typec.port); - - anx7411_port_unregister_altmodes(plat->typec.port_amode); + anx7411_port_unregister(&plat->typec); } static const struct i2c_device_id anx7411_id[] = { diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 58f40156de5622..4b3047e055a373 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -219,6 +219,13 @@ static ssize_t usb_power_delivery_revision_show(struct device *dev, char *buf); static DEVICE_ATTR_RO(usb_power_delivery_revision); +static const char * const usb_modes[] = { + [USB_MODE_NONE] = "none", + [USB_MODE_USB2] = "usb2", + [USB_MODE_USB3] = "usb3", + [USB_MODE_USB4] = "usb4" +}; + /* ------------------------------------------------------------------------- */ /* Alternate Modes */ @@ -614,6 +621,75 @@ EXPORT_SYMBOL_GPL(typec_unregister_altmode); /* ------------------------------------------------------------------------- */ /* Type-C Partners */ +/** + * typec_partner_set_usb_mode - Assign active USB Mode for the partner + * @partner: USB Type-C partner + * @mode: USB Mode (USB2, USB3 or USB4) + * + * The port drivers can use this function to assign the active USB Mode to + * @partner. The USB Mode can change for example due to Data Reset. + */ +void typec_partner_set_usb_mode(struct typec_partner *partner, enum usb_mode mode) +{ + if (!partner || partner->usb_mode == mode) + return; + + partner->usb_capability |= BIT(mode - 1); + partner->usb_mode = mode; + sysfs_notify(&partner->dev.kobj, NULL, "usb_mode"); +} +EXPORT_SYMBOL_GPL(typec_partner_set_usb_mode); + +static ssize_t +usb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct typec_partner *partner = to_typec_partner(dev); + int len = 0; + int i; + + for (i = USB_MODE_USB2; i < USB_MODE_USB4 + 1; i++) { + if (!(BIT(i - 1) & partner->usb_capability)) + continue; + + if (i == partner->usb_mode) + len += sysfs_emit_at(buf, len, "[%s] ", usb_modes[i]); + else + len += sysfs_emit_at(buf, len, "%s ", usb_modes[i]); + } + + sysfs_emit_at(buf, len - 1, "\n"); + + return len; +} + +static ssize_t usb_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct typec_partner *partner = to_typec_partner(dev); + struct typec_port *port = to_typec_port(dev->parent); + int mode; + int ret; + + if (!port->ops || !port->ops->enter_usb_mode) + return -EOPNOTSUPP; + + mode = sysfs_match_string(usb_modes, buf); + if (mode < 0) + return mode; + + if (mode == partner->usb_mode) + return size; + + ret = port->ops->enter_usb_mode(port, mode); + if (ret) + return ret; + + typec_partner_set_usb_mode(partner, mode); + + return size; +} +static DEVICE_ATTR_RW(usb_mode); + static ssize_t accessory_mode_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -660,6 +736,7 @@ static struct attribute *typec_partner_attrs[] = { &dev_attr_supports_usb_power_delivery.attr, &dev_attr_number_of_alternate_modes.attr, &dev_attr_type.attr, + &dev_attr_usb_mode.attr, &dev_attr_usb_power_delivery_revision.attr, NULL }; @@ -667,6 +744,14 @@ static struct attribute *typec_partner_attrs[] = { static umode_t typec_partner_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { struct typec_partner *partner = to_typec_partner(kobj_to_dev(kobj)); + struct typec_port *port = to_typec_port(partner->dev.parent); + + if (attr == &dev_attr_usb_mode.attr) { + if (!partner->usb_capability) + return 0; + if (!port->ops || !port->ops->enter_usb_mode) + return 0444; + } if (attr == &dev_attr_number_of_alternate_modes.attr) { if (partner->num_altmodes < 0) @@ -740,10 +825,33 @@ static void typec_partner_unlink_device(struct typec_partner *partner, struct de */ int typec_partner_set_identity(struct typec_partner *partner) { - if (!partner->identity) + u8 usb_capability = partner->usb_capability; + struct device *dev = &partner->dev; + struct usb_pd_identity *id; + + id = get_pd_identity(dev); + if (!id) return -EINVAL; - typec_report_identity(&partner->dev); + if (to_typec_port(dev->parent)->data_role == TYPEC_HOST) { + u32 devcap = PD_VDO_UFP_DEVCAP(id->vdo[0]); + + if (devcap & (DEV_USB2_CAPABLE | DEV_USB2_BILLBOARD)) + usb_capability |= USB_CAPABILITY_USB2; + if (devcap & DEV_USB3_CAPABLE) + usb_capability |= USB_CAPABILITY_USB3; + if (devcap & DEV_USB4_CAPABLE) + usb_capability |= USB_CAPABILITY_USB4; + } else { + usb_capability = PD_VDO_DFP_HOSTCAP(id->vdo[0]); + } + + if (partner->usb_capability != usb_capability) { + partner->usb_capability = usb_capability; + sysfs_notify(&dev->kobj, NULL, "usb_mode"); + } + + typec_report_identity(dev); return 0; } EXPORT_SYMBOL_GPL(typec_partner_set_identity); @@ -913,6 +1021,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port, partner->usb_pd = desc->usb_pd; partner->accessory = desc->accessory; partner->num_altmodes = -1; + partner->usb_capability = desc->usb_capability; partner->pd_revision = desc->pd_revision; partner->svdm_version = port->cap->svdm_version; partner->attach = desc->attach; @@ -932,6 +1041,15 @@ struct typec_partner *typec_register_partner(struct typec_port *port, partner->dev.type = &typec_partner_dev_type; dev_set_name(&partner->dev, "%s-partner", dev_name(&port->dev)); + if (port->usb2_dev) { + partner->usb_capability |= USB_CAPABILITY_USB2; + partner->usb_mode = USB_MODE_USB2; + } + if (port->usb3_dev) { + partner->usb_capability |= USB_CAPABILITY_USB2 | USB_CAPABILITY_USB3; + partner->usb_mode = USB_MODE_USB3; + } + ret = device_register(&partner->dev); if (ret) { dev_err(&port->dev, "failed to register partner (%d)\n", ret); @@ -1292,6 +1410,67 @@ EXPORT_SYMBOL_GPL(typec_unregister_cable); /* ------------------------------------------------------------------------- */ /* USB Type-C ports */ +/** + * typec_port_set_usb_mode - Set the operational USB mode for the port + * @port: USB Type-C port + * @mode: USB Mode (USB2, USB3 or USB4) + * + * @mode will be used with the next Enter_USB message. Existing connections are + * not affected. + */ +void typec_port_set_usb_mode(struct typec_port *port, enum usb_mode mode) +{ + port->usb_mode = mode; +} +EXPORT_SYMBOL_GPL(typec_port_set_usb_mode); + +static ssize_t +usb_capability_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct typec_port *port = to_typec_port(dev); + int len = 0; + int i; + + for (i = USB_MODE_USB2; i < USB_MODE_USB4 + 1; i++) { + if (!(BIT(i - 1) & port->cap->usb_capability)) + continue; + + if (i == port->usb_mode) + len += sysfs_emit_at(buf, len, "[%s] ", usb_modes[i]); + else + len += sysfs_emit_at(buf, len, "%s ", usb_modes[i]); + } + + sysfs_emit_at(buf, len - 1, "\n"); + + return len; +} + +static ssize_t +usb_capability_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct typec_port *port = to_typec_port(dev); + int ret = 0; + int mode; + + if (!port->ops || !port->ops->default_usb_mode_set) + return -EOPNOTSUPP; + + mode = sysfs_match_string(usb_modes, buf); + if (mode < 0) + return mode; + + ret = port->ops->default_usb_mode_set(port, mode); + if (ret) + return ret; + + port->usb_mode = mode; + + return size; +} +static DEVICE_ATTR_RW(usb_capability); + /** * typec_port_set_usb_power_delivery - Assign USB PD for port. * @port: USB Type-C port. @@ -1760,6 +1939,7 @@ static struct attribute *typec_attrs[] = { &dev_attr_vconn_source.attr, &dev_attr_port_type.attr, &dev_attr_orientation.attr, + &dev_attr_usb_capability.attr, NULL, }; @@ -1793,6 +1973,11 @@ static umode_t typec_attr_is_visible(struct kobject *kobj, if (port->cap->orientation_aware) return 0444; return 0; + } else if (attr == &dev_attr_usb_capability.attr) { + if (!port->cap->usb_capability) + return 0; + if (!port->ops || !port->ops->default_usb_mode_set) + return 0444; } return attr->mode; @@ -1864,13 +2049,18 @@ static void typec_partner_attach(struct typec_connector *con, struct device *dev struct typec_port *port = container_of(con, struct typec_port, con); struct typec_partner *partner = typec_get_partner(port); struct usb_device *udev = to_usb_device(dev); + enum usb_mode usb_mode; - if (udev->speed < USB_SPEED_SUPER) + if (udev->speed < USB_SPEED_SUPER) { + usb_mode = USB_MODE_USB2; port->usb2_dev = dev; - else + } else { + usb_mode = USB_MODE_USB3; port->usb3_dev = dev; + } if (partner) { + typec_partner_set_usb_mode(partner, usb_mode); typec_partner_link_device(partner, dev); put_device(&partner->dev); } @@ -2433,6 +2623,13 @@ struct typec_port *typec_register_port(struct device *parent, port->con.attach = typec_partner_attach; port->con.deattach = typec_partner_deattach; + if (cap->usb_capability & USB_CAPABILITY_USB4) + port->usb_mode = USB_MODE_USB4; + else if (cap->usb_capability & USB_CAPABILITY_USB3) + port->usb_mode = USB_MODE_USB3; + else if (cap->usb_capability & USB_CAPABILITY_USB2) + port->usb_mode = USB_MODE_USB2; + device_initialize(&port->dev); port->dev.class = &typec_class; port->dev.parent = parent; diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index 7485cdb9dd2017..b3076a24ad2eee 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -35,6 +35,8 @@ struct typec_partner { int num_altmodes; u16 pd_revision; /* 0300H = "3.0" */ enum usb_pd_svdm_ver svdm_version; + enum usb_mode usb_mode; + u8 usb_capability; struct usb_power_delivery *pd; @@ -55,6 +57,7 @@ struct typec_port { enum typec_role vconn_role; enum typec_pwr_opmode pwr_opmode; enum typec_port_type port_type; + enum usb_mode usb_mode; struct mutex port_type_lock; enum typec_orientation orientation; diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index ce7db6ad30572a..67381b4ef4f68f 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -66,6 +66,15 @@ config TYPEC_MUX_PTN36502 Say Y or M if your system has a NXP PTN36502 Type-C redriver chip found on some devices with a Type-C port. +config TYPEC_MUX_TUSB1046 + tristate "TI TUSB1046 Type-C crosspoint switch driver" + depends on I2C + help + Driver for the Texas Instruments TUSB1046-DCI crosspoint switch. + Supports flipping USB-C SuperSpeed lanes to adapt to orientation + changes, as well as muxing DisplayPort and sideband signals to a + common Type-C connector. + config TYPEC_MUX_WCD939X_USBSS tristate "Qualcomm WCD939x USBSS Analog Audio Switch driver" depends on I2C diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile index bb96f30267af05..60879446da9365 100644 --- a/drivers/usb/typec/mux/Makefile +++ b/drivers/usb/typec/mux/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o obj-$(CONFIG_TYPEC_MUX_IT5205) += it5205.o obj-$(CONFIG_TYPEC_MUX_NB7VPQ904M) += nb7vpq904m.o obj-$(CONFIG_TYPEC_MUX_PTN36502) += ptn36502.o +obj-$(CONFIG_TYPEC_MUX_TUSB1046) += tusb1046.o obj-$(CONFIG_TYPEC_MUX_WCD939X_USBSS) += wcd939x-usbss.o diff --git a/drivers/usb/typec/mux/gpio-sbu-mux.c b/drivers/usb/typec/mux/gpio-sbu-mux.c index 8902102c05a8ec..1834f1a2dd9dd0 100644 --- a/drivers/usb/typec/mux/gpio-sbu-mux.c +++ b/drivers/usb/typec/mux/gpio-sbu-mux.c @@ -159,7 +159,7 @@ MODULE_DEVICE_TABLE(of, gpio_sbu_mux_match); static struct platform_driver gpio_sbu_mux_driver = { .probe = gpio_sbu_mux_probe, - .remove_new = gpio_sbu_mux_remove, + .remove = gpio_sbu_mux_remove, .driver = { .name = "gpio_sbu_mux", .of_match_table = gpio_sbu_mux_match, diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c index 46b4c5c3a6beb3..5dfe9575439461 100644 --- a/drivers/usb/typec/mux/intel_pmc_mux.c +++ b/drivers/usb/typec/mux/intel_pmc_mux.c @@ -828,7 +828,7 @@ static struct platform_driver pmc_usb_driver = { .acpi_match_table = ACPI_PTR(pmc_usb_acpi_ids), }, .probe = pmc_usb_probe, - .remove_new = pmc_usb_remove, + .remove = pmc_usb_remove, }; static int __init pmc_usb_init(void) diff --git a/drivers/usb/typec/mux/tusb1046.c b/drivers/usb/typec/mux/tusb1046.c new file mode 100644 index 00000000000000..b4f45c217b59fe --- /dev/null +++ b/drivers/usb/typec/mux/tusb1046.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the TUSB1046-DCI USB Type-C crosspoint switch + * + * Copyright (C) 2024 Bootlin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TUSB1046_REG_GENERAL 0xa + +/* General register bits */ +#define TUSB1046_GENERAL_FLIPSEL BIT(2) +#define TUSB1046_GENERAL_CTLSEL GENMASK(1, 0) + +/* Mux modes */ +#define TUSB1046_CTLSEL_DISABLED 0x0 +#define TUSB1046_CTLSEL_USB3 0x1 +#define TUSB1046_CTLSEL_4LANE_DP 0x2 +#define TUSB1046_CTLSEL_USB3_AND_2LANE_DP 0x3 + +struct tusb1046_priv { + struct i2c_client *client; + struct typec_switch_dev *sw; + struct typec_mux_dev *mux; + + /* Lock General register during accesses */ + struct mutex general_reg_lock; +}; + +static int tusb1046_mux_set(struct typec_mux_dev *mux, + struct typec_mux_state *state) +{ + struct tusb1046_priv *priv = typec_mux_get_drvdata(mux); + struct i2c_client *client = priv->client; + struct device *dev = &client->dev; + int mode, val, ret = 0; + + if (state->mode >= TYPEC_STATE_MODAL && + state->alt->svid != USB_TYPEC_DP_SID) + return -EINVAL; + + dev_dbg(dev, "mux mode requested: %lu\n", state->mode); + + mutex_lock(&priv->general_reg_lock); + + val = i2c_smbus_read_byte_data(client, TUSB1046_REG_GENERAL); + if (val < 0) { + dev_err(dev, "failed to read ctlsel status, err %d\n", val); + ret = val; + goto out_unlock; + } + + switch (state->mode) { + case TYPEC_STATE_USB: + mode = TUSB1046_CTLSEL_USB3; + break; + case TYPEC_DP_STATE_C: + case TYPEC_DP_STATE_E: + mode = TUSB1046_CTLSEL_4LANE_DP; + break; + case TYPEC_DP_STATE_D: + mode = TUSB1046_CTLSEL_USB3_AND_2LANE_DP; + break; + case TYPEC_STATE_SAFE: + default: + mode = TUSB1046_CTLSEL_DISABLED; + break; + } + + val &= ~TUSB1046_GENERAL_CTLSEL; + val |= mode; + + ret = i2c_smbus_write_byte_data(client, TUSB1046_REG_GENERAL, val); + +out_unlock: + mutex_unlock(&priv->general_reg_lock); + return ret; +} + +static int tusb1046_switch_set(struct typec_switch_dev *sw, + enum typec_orientation orientation) +{ + struct tusb1046_priv *priv = typec_switch_get_drvdata(sw); + struct i2c_client *client = priv->client; + struct device *dev = &client->dev; + int val, ret = 0; + + dev_dbg(dev, "setting USB3.0 lane flip for orientation %d\n", orientation); + + mutex_lock(&priv->general_reg_lock); + + val = i2c_smbus_read_byte_data(client, TUSB1046_REG_GENERAL); + if (val < 0) { + dev_err(dev, "failed to read flipsel status, err %d\n", val); + ret = val; + goto out_unlock; + } + + if (orientation == TYPEC_ORIENTATION_REVERSE) + val |= TUSB1046_GENERAL_FLIPSEL; + else + val &= ~TUSB1046_GENERAL_FLIPSEL; + + ret = i2c_smbus_write_byte_data(client, TUSB1046_REG_GENERAL, val); + +out_unlock: + mutex_unlock(&priv->general_reg_lock); + return ret; +} + +static int tusb1046_i2c_probe(struct i2c_client *client) +{ + struct typec_switch_desc sw_desc = { }; + struct typec_mux_desc mux_desc = { }; + struct device *dev = &client->dev; + struct tusb1046_priv *priv; + int ret = 0; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return dev_err_probe(dev, -ENOMEM, "failed to allocate driver data\n"); + + priv->client = client; + + mutex_init(&priv->general_reg_lock); + + sw_desc.drvdata = priv; + sw_desc.fwnode = dev_fwnode(dev); + sw_desc.set = tusb1046_switch_set; + + priv->sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(priv->sw)) { + ret = dev_err_probe(dev, PTR_ERR(priv->sw), "failed to register type-c switch\n"); + goto err_destroy_mutex; + } + + mux_desc.drvdata = priv; + mux_desc.fwnode = dev_fwnode(dev); + mux_desc.set = tusb1046_mux_set; + + priv->mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(priv->mux)) { + ret = dev_err_probe(dev, PTR_ERR(priv->mux), "failed to register type-c mux\n"); + goto err_unregister_switch; + } + + i2c_set_clientdata(client, priv); + + return 0; + +err_unregister_switch: + typec_switch_unregister(priv->sw); +err_destroy_mutex: + mutex_destroy(&priv->general_reg_lock); + return ret; +} + +static void tusb1046_i2c_remove(struct i2c_client *client) +{ + struct tusb1046_priv *priv = i2c_get_clientdata(client); + + typec_switch_unregister(priv->sw); + typec_mux_unregister(priv->mux); + mutex_destroy(&priv->general_reg_lock); +} + +static const struct of_device_id tusb1046_match_table[] = { + {.compatible = "ti,tusb1046"}, + {}, +}; + +static struct i2c_driver tusb1046_driver = { + .driver = { + .name = "tusb1046", + .of_match_table = tusb1046_match_table, + }, + .probe = tusb1046_i2c_probe, + .remove = tusb1046_i2c_remove, +}; + +module_i2c_driver(tusb1046_driver); + +MODULE_DESCRIPTION("TUSB1046 USB Type-C switch driver"); +MODULE_AUTHOR("Romain Gantois "); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c index f3140fc04c12e1..6d85b25b40bc0c 100644 --- a/drivers/usb/typec/stusb160x.c +++ b/drivers/usb/typec/stusb160x.c @@ -633,9 +633,8 @@ MODULE_DEVICE_TABLE(of, stusb160x_of_match); static int stusb160x_probe(struct i2c_client *client) { + const struct regmap_config *regmap_config; struct stusb160x *chip; - const struct of_device_id *match; - struct regmap_config *regmap_config; struct fwnode_handle *fwnode; int ret; @@ -645,8 +644,8 @@ static int stusb160x_probe(struct i2c_client *client) i2c_set_clientdata(client, chip); - match = i2c_of_match_device(stusb160x_of_match, client); - regmap_config = (struct regmap_config *)match->data; + regmap_config = i2c_get_match_data(client); + chip->regmap = devm_regmap_init_i2c(client, regmap_config); if (IS_ERR(chip->regmap)) { ret = PTR_ERR(chip->regmap); diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c index b80eb2d78d88b4..3766790c1548c7 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c @@ -163,7 +163,7 @@ static struct platform_driver qcom_pmic_typec_driver = { .of_match_table = qcom_pmic_typec_table, }, .probe = qcom_pmic_typec_probe, - .remove_new = qcom_pmic_typec_remove, + .remove = qcom_pmic_typec_remove, }; module_platform_driver(qcom_pmic_typec_driver); diff --git a/drivers/usb/typec/tcpm/tcpci_mt6360.c b/drivers/usb/typec/tcpm/tcpci_mt6360.c index 02b7fd30226508..881ffacbfd7737 100644 --- a/drivers/usb/typec/tcpm/tcpci_mt6360.c +++ b/drivers/usb/typec/tcpm/tcpci_mt6360.c @@ -221,7 +221,7 @@ static struct platform_driver mt6360_tcpc_driver = { .of_match_table = mt6360_tcpc_of_id, }, .probe = mt6360_tcpc_probe, - .remove_new = mt6360_tcpc_remove, + .remove = mt6360_tcpc_remove, }; module_platform_driver(mt6360_tcpc_driver); diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c index 9cda1005ef01a5..1479f961772d0d 100644 --- a/drivers/usb/typec/tcpm/tcpci_mt6370.c +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c @@ -196,7 +196,7 @@ static struct platform_driver mt6370_tcpc_driver = { .of_match_table = mt6370_tcpc_devid_table, }, .probe = mt6370_tcpc_probe, - .remove_new = mt6370_tcpc_remove, + .remove = mt6370_tcpc_remove, }; module_platform_driver(mt6370_tcpc_driver); diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 7ae341a403424c..6021eeb903fec5 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -310,6 +310,18 @@ struct pd_data { unsigned int operating_snk_mw; }; +/* + * @sink_wait_cap_time: Deadline (in ms) for tTypeCSinkWaitCap timer + * @ps_src_wait_off_time: Deadline (in ms) for tPSSourceOff timer + * @cc_debounce_time: Deadline (in ms) for tCCDebounce timer + */ +struct pd_timings { + u32 sink_wait_cap_time; + u32 ps_src_off_time; + u32 cc_debounce_time; + u32 snk_bc12_cmpletion_time; +}; + struct tcpm_port { struct device *dev; @@ -552,6 +564,9 @@ struct tcpm_port { */ unsigned int message_id_prime; unsigned int rx_msgid_prime; + + /* Timer deadline values configured at runtime */ + struct pd_timings timings; #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct mutex logbuffer_lock; /* log buffer access lock */ @@ -4640,15 +4655,15 @@ static void run_state_machine(struct tcpm_port *port) case SRC_ATTACH_WAIT: if (tcpm_port_is_debug(port)) tcpm_set_state(port, DEBUG_ACC_ATTACHED, - PD_T_CC_DEBOUNCE); + port->timings.cc_debounce_time); else if (tcpm_port_is_audio(port)) tcpm_set_state(port, AUDIO_ACC_ATTACHED, - PD_T_CC_DEBOUNCE); + port->timings.cc_debounce_time); else if (tcpm_port_is_source(port) && port->vbus_vsafe0v) tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED, - PD_T_CC_DEBOUNCE); + port->timings.cc_debounce_time); break; case SNK_TRY: @@ -4699,7 +4714,7 @@ static void run_state_machine(struct tcpm_port *port) } break; case SRC_TRYWAIT_DEBOUNCE: - tcpm_set_state(port, SRC_ATTACHED, PD_T_CC_DEBOUNCE); + tcpm_set_state(port, SRC_ATTACHED, port->timings.cc_debounce_time); break; case SRC_TRYWAIT_UNATTACHED: tcpm_set_state(port, SNK_UNATTACHED, 0); @@ -4902,7 +4917,7 @@ static void run_state_machine(struct tcpm_port *port) (port->cc1 != TYPEC_CC_OPEN && port->cc2 == TYPEC_CC_OPEN)) tcpm_set_state(port, SNK_DEBOUNCED, - PD_T_CC_DEBOUNCE); + port->timings.cc_debounce_time); else if (tcpm_port_is_disconnected(port)) tcpm_set_state(port, SNK_UNATTACHED, PD_T_PD_DEBOUNCE); @@ -4942,7 +4957,7 @@ static void run_state_machine(struct tcpm_port *port) break; case SNK_TRYWAIT: tcpm_set_cc(port, TYPEC_CC_RD); - tcpm_set_state(port, SNK_TRYWAIT_VBUS, PD_T_CC_DEBOUNCE); + tcpm_set_state(port, SNK_TRYWAIT_VBUS, port->timings.cc_debounce_time); break; case SNK_TRYWAIT_VBUS: /* @@ -4965,7 +4980,16 @@ static void run_state_machine(struct tcpm_port *port) if (ret < 0) tcpm_set_state(port, SNK_UNATTACHED, 0); else - tcpm_set_state(port, SNK_STARTUP, 0); + /* + * For Type C port controllers that use Battery Charging + * Detection (based on BCv1.2 spec) to detect USB + * charger type, add a delay of "snk_bc12_cmpletion_time" + * before transitioning to SNK_STARTUP to allow BC1.2 + * detection to complete before PD is eventually enabled + * in later states. + */ + tcpm_set_state(port, SNK_STARTUP, + port->timings.snk_bc12_cmpletion_time); break; case SNK_STARTUP: opmode = tcpm_get_pwr_opmode(port->polarity ? @@ -5015,7 +5039,7 @@ static void run_state_machine(struct tcpm_port *port) break; case SNK_DISCOVERY_DEBOUNCE: tcpm_set_state(port, SNK_DISCOVERY_DEBOUNCE_DONE, - PD_T_CC_DEBOUNCE); + port->timings.cc_debounce_time); break; case SNK_DISCOVERY_DEBOUNCE_DONE: if (!tcpm_port_is_disconnected(port) && @@ -5042,13 +5066,14 @@ static void run_state_machine(struct tcpm_port *port) if (port->vbus_never_low) { port->vbus_never_low = false; tcpm_set_state(port, SNK_SOFT_RESET, - PD_T_SINK_WAIT_CAP); + port->timings.sink_wait_cap_time); } else { if (!port->self_powered) upcoming_state = SNK_WAIT_CAPABILITIES_TIMEOUT; else upcoming_state = hard_reset_state(port); - tcpm_set_state(port, upcoming_state, PD_T_SINK_WAIT_CAP); + tcpm_set_state(port, SNK_WAIT_CAPABILITIES_TIMEOUT, + port->timings.sink_wait_cap_time); } break; case SNK_WAIT_CAPABILITIES_TIMEOUT: @@ -5070,7 +5095,8 @@ static void run_state_machine(struct tcpm_port *port) if (tcpm_pd_send_control(port, PD_CTRL_GET_SOURCE_CAP, TCPC_TX_SOP)) tcpm_set_state_cond(port, hard_reset_state(port), 0); else - tcpm_set_state(port, hard_reset_state(port), PD_T_SINK_WAIT_CAP); + tcpm_set_state(port, hard_reset_state(port), + port->timings.sink_wait_cap_time); break; case SNK_NEGOTIATE_CAPABILITIES: port->pd_capable = true; @@ -5207,7 +5233,7 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, ACC_UNATTACHED, 0); break; case AUDIO_ACC_DEBOUNCE: - tcpm_set_state(port, ACC_UNATTACHED, PD_T_CC_DEBOUNCE); + tcpm_set_state(port, ACC_UNATTACHED, port->timings.cc_debounce_time); break; /* Hard_Reset states */ @@ -5274,7 +5300,7 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, SRC_UNATTACHED, PD_T_PS_SOURCE_ON); break; case SNK_HARD_RESET_SINK_OFF: - /* Do not discharge/disconnect during hard reseet */ + /* Do not discharge/disconnect during hard reset */ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_USB, false, 0); memset(&port->pps_data, 0, sizeof(port->pps_data)); tcpm_set_vconn(port, false); @@ -5424,7 +5450,7 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_state(port, ERROR_RECOVERY, 0); break; case FR_SWAP_SNK_SRC_TRANSITION_TO_OFF: - tcpm_set_state(port, ERROR_RECOVERY, PD_T_PS_SOURCE_OFF); + tcpm_set_state(port, ERROR_RECOVERY, port->timings.ps_src_off_time); break; case FR_SWAP_SNK_SRC_NEW_SINK_READY: if (port->vbus_source) @@ -5479,7 +5505,7 @@ static void run_state_machine(struct tcpm_port *port) tcpm_set_cc(port, TYPEC_CC_RD); /* allow CC debounce */ tcpm_set_state(port, PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED, - PD_T_CC_DEBOUNCE); + port->timings.cc_debounce_time); break; case PR_SWAP_SRC_SNK_SOURCE_OFF_CC_DEBOUNCED: /* @@ -5514,7 +5540,7 @@ static void run_state_machine(struct tcpm_port *port) port->pps_data.active, 0); tcpm_set_charge(port, false); tcpm_set_state(port, hard_reset_state(port), - PD_T_PS_SOURCE_OFF); + port->timings.ps_src_off_time); break; case PR_SWAP_SNK_SRC_SOURCE_ON: tcpm_enable_auto_vbus_discharge(port, true); @@ -5670,7 +5696,7 @@ static void run_state_machine(struct tcpm_port *port) case PORT_RESET_WAIT_OFF: tcpm_set_state(port, tcpm_default_state(port), - port->vbus_present ? PD_T_PS_SOURCE_OFF : 0); + port->vbus_present ? port->timings.ps_src_off_time : 0); break; /* AMS intermediate state */ @@ -6070,7 +6096,7 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) break; case SNK_ATTACH_WAIT: case SNK_DEBOUNCED: - /* Do nothing, as TCPM is still waiting for vbus to reaach VSAFE5V to connect */ + /* Do nothing, as TCPM is still waiting for vbus to reach VSAFE5V to connect */ break; case SNK_NEGOTIATE_CAPABILITIES: @@ -6161,7 +6187,7 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port) case SRC_ATTACH_WAIT: if (tcpm_port_is_source(port)) tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED, - PD_T_CC_DEBOUNCE); + port->timings.cc_debounce_time); break; case SRC_STARTUP: case SRC_SEND_CAPABILITIES: @@ -7057,6 +7083,34 @@ static int tcpm_port_register_pd(struct tcpm_port *port) return ret; } +static void tcpm_fw_get_timings(struct tcpm_port *port, struct fwnode_handle *fwnode) +{ + int ret; + u32 val; + + ret = fwnode_property_read_u32(fwnode, "sink-wait-cap-time-ms", &val); + if (!ret) + port->timings.sink_wait_cap_time = val; + else + port->timings.sink_wait_cap_time = PD_T_SINK_WAIT_CAP; + + ret = fwnode_property_read_u32(fwnode, "ps-source-off-time-ms", &val); + if (!ret) + port->timings.ps_src_off_time = val; + else + port->timings.ps_src_off_time = PD_T_PS_SOURCE_OFF; + + ret = fwnode_property_read_u32(fwnode, "cc-debounce-time-ms", &val); + if (!ret) + port->timings.cc_debounce_time = val; + else + port->timings.cc_debounce_time = PD_T_CC_DEBOUNCE; + + ret = fwnode_property_read_u32(fwnode, "sink-bc12-completion-time-ms", &val); + if (!ret) + port->timings.snk_bc12_cmpletion_time = val; +} + static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode) { struct fwnode_handle *capabilities, *child, *caps = NULL; @@ -7371,7 +7425,7 @@ static int tcpm_psy_get_input_power_limit(struct tcpm_port *port, src_mv = pdo_fixed_voltage(pdo); src_ma = pdo_max_current(pdo); tmp = src_mv * src_ma; - max_src_uw = tmp > max_src_uw ? tmp : max_src_uw; + max_src_uw = max(tmp, max_src_uw); } } @@ -7614,6 +7668,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) if (err < 0) goto out_destroy_wq; + tcpm_fw_get_timings(port, tcpc->fwnode); + port->try_role = port->typec_caps.prefer_role; port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */ diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c index cf719307b3f6b9..759c982bb16a9a 100644 --- a/drivers/usb/typec/tcpm/wcove.c +++ b/drivers/usb/typec/tcpm/wcove.c @@ -621,10 +621,6 @@ static int wcove_typec_probe(struct platform_device *pdev) if (irq < 0) return irq; - irq = regmap_irq_get_virq(pmic->irq_chip_data_chgr, irq); - if (irq < 0) - return irq; - ret = guid_parse(WCOVE_DSM_UUID, &wcove->guid); if (ret) return ret; @@ -691,7 +687,7 @@ static struct platform_driver wcove_typec_driver = { .name = "bxt_wcove_usbc", }, .probe = wcove_typec_probe, - .remove_new = wcove_typec_remove, + .remove = wcove_typec_remove, }; module_platform_driver(wcove_typec_driver); diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c index f67733cecfdf5d..83ff23086d7948 100644 --- a/drivers/usb/typec/ucsi/debugfs.c +++ b/drivers/usb/typec/ucsi/debugfs.c @@ -32,6 +32,7 @@ static int ucsi_cmd(void *data, u64 val) case UCSI_SET_UOR: case UCSI_SET_PDR: case UCSI_CONNECTOR_RESET: + case UCSI_SET_SINK_PATH: ret = ucsi_send_command(ucsi, val, NULL, 0); break; case UCSI_GET_CAPABILITY: diff --git a/drivers/usb/typec/ucsi/psy.c b/drivers/usb/typec/ucsi/psy.c index 1c631c7855a960..62ac6973040502 100644 --- a/drivers/usb/typec/ucsi/psy.c +++ b/drivers/usb/typec/ucsi/psy.c @@ -55,8 +55,8 @@ static int ucsi_psy_get_online(struct ucsi_connector *con, union power_supply_propval *val) { val->intval = UCSI_PSY_OFFLINE; - if (con->status.flags & UCSI_CONSTAT_CONNECTED && - (con->status.flags & UCSI_CONSTAT_PWR_DIR) == TYPEC_SINK) + if (UCSI_CONSTAT(con, CONNECTED) && + (UCSI_CONSTAT(con, PWR_DIR) == TYPEC_SINK)) val->intval = UCSI_PSY_FIXED_ONLINE; return 0; } @@ -66,7 +66,7 @@ static int ucsi_psy_get_voltage_min(struct ucsi_connector *con, { u32 pdo; - switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + switch (UCSI_CONSTAT(con, PWR_OPMODE)) { case UCSI_CONSTAT_PWR_OPMODE_PD: pdo = con->src_pdos[0]; val->intval = pdo_fixed_voltage(pdo) * 1000; @@ -89,7 +89,7 @@ static int ucsi_psy_get_voltage_max(struct ucsi_connector *con, { u32 pdo; - switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + switch (UCSI_CONSTAT(con, PWR_OPMODE)) { case UCSI_CONSTAT_PWR_OPMODE_PD: if (con->num_pdos > 0) { pdo = con->src_pdos[con->num_pdos - 1]; @@ -117,7 +117,7 @@ static int ucsi_psy_get_voltage_now(struct ucsi_connector *con, int index; u32 pdo; - switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + switch (UCSI_CONSTAT(con, PWR_OPMODE)) { case UCSI_CONSTAT_PWR_OPMODE_PD: index = rdo_index(con->rdo); if (index > 0) { @@ -145,7 +145,7 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con, { u32 pdo; - switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + switch (UCSI_CONSTAT(con, PWR_OPMODE)) { case UCSI_CONSTAT_PWR_OPMODE_PD: if (con->num_pdos > 0) { pdo = con->src_pdos[con->num_pdos - 1]; @@ -173,9 +173,7 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con, static int ucsi_psy_get_current_now(struct ucsi_connector *con, union power_supply_propval *val) { - u16 flags = con->status.flags; - - if (UCSI_CONSTAT_PWR_OPMODE(flags) == UCSI_CONSTAT_PWR_OPMODE_PD) + if (UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) val->intval = rdo_op_current(con->rdo) * 1000; else val->intval = 0; @@ -185,11 +183,9 @@ static int ucsi_psy_get_current_now(struct ucsi_connector *con, static int ucsi_psy_get_usb_type(struct ucsi_connector *con, union power_supply_propval *val) { - u16 flags = con->status.flags; - val->intval = POWER_SUPPLY_USB_TYPE_C; - if (flags & UCSI_CONSTAT_CONNECTED && - UCSI_CONSTAT_PWR_OPMODE(flags) == UCSI_CONSTAT_PWR_OPMODE_PD) + if (UCSI_CONSTAT(con, CONNECTED) && + UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) val->intval = POWER_SUPPLY_USB_TYPE_PD; return 0; @@ -197,18 +193,18 @@ static int ucsi_psy_get_usb_type(struct ucsi_connector *con, static int ucsi_psy_get_charge_type(struct ucsi_connector *con, union power_supply_propval *val) { - if (!(con->status.flags & UCSI_CONSTAT_CONNECTED)) { + if (!(UCSI_CONSTAT(con, CONNECTED))) { val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; return 0; } /* The Battery Charging Cabability Status field is only valid in sink role. */ - if ((con->status.flags & UCSI_CONSTAT_PWR_DIR) != TYPEC_SINK) { + if (UCSI_CONSTAT(con, PWR_DIR) != TYPEC_SINK) { val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; return 0; } - switch (UCSI_CONSTAT_BC_STATUS(con->status.pwr_status)) { + switch (UCSI_CONSTAT(con, BC_STATUS)) { case UCSI_CONSTAT_BC_NOMINAL_CHARGING: val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD; break; diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h index a0d3a934d3d924..41701dee70564b 100644 --- a/drivers/usb/typec/ucsi/trace.h +++ b/drivers/usb/typec/ucsi/trace.h @@ -40,8 +40,8 @@ DEFINE_EVENT(ucsi_log_command, ucsi_reset_ppm, ); DECLARE_EVENT_CLASS(ucsi_log_connector_status, - TP_PROTO(int port, struct ucsi_connector_status *status), - TP_ARGS(port, status), + TP_PROTO(int port, struct ucsi_connector *con), + TP_ARGS(port, con), TP_STRUCT__entry( __field(int, port) __field(u16, change) @@ -55,14 +55,14 @@ DECLARE_EVENT_CLASS(ucsi_log_connector_status, ), TP_fast_assign( __entry->port = port - 1; - __entry->change = status->change; - __entry->opmode = UCSI_CONSTAT_PWR_OPMODE(status->flags); - __entry->connected = !!(status->flags & UCSI_CONSTAT_CONNECTED); - __entry->pwr_dir = !!(status->flags & UCSI_CONSTAT_PWR_DIR); - __entry->partner_flags = UCSI_CONSTAT_PARTNER_FLAGS(status->flags); - __entry->partner_type = UCSI_CONSTAT_PARTNER_TYPE(status->flags); - __entry->request_data_obj = status->request_data_obj; - __entry->bc_status = UCSI_CONSTAT_BC_STATUS(status->pwr_status); + __entry->change = UCSI_CONSTAT(con, CHANGE); + __entry->opmode = UCSI_CONSTAT(con, PWR_OPMODE); + __entry->connected = UCSI_CONSTAT(con, CONNECTED); + __entry->pwr_dir = UCSI_CONSTAT(con, PWR_DIR); + __entry->partner_flags = UCSI_CONSTAT(con, PARTNER_FLAGS); + __entry->partner_type = UCSI_CONSTAT(con, PARTNER_TYPE); + __entry->request_data_obj = UCSI_CONSTAT(con, RDO); + __entry->bc_status = UCSI_CONSTAT(con, BC_STATUS); ), TP_printk("port%d status: change=%04x, opmode=%x, connected=%d, " "sourcing=%d, partner_flags=%x, partner_type=%x, " @@ -73,13 +73,13 @@ DECLARE_EVENT_CLASS(ucsi_log_connector_status, ); DEFINE_EVENT(ucsi_log_connector_status, ucsi_connector_change, - TP_PROTO(int port, struct ucsi_connector_status *status), - TP_ARGS(port, status) + TP_PROTO(int port, struct ucsi_connector *con), + TP_ARGS(port, con) ); DEFINE_EVENT(ucsi_log_connector_status, ucsi_register_port, - TP_PROTO(int port, struct ucsi_connector_status *status), - TP_ARGS(port, status) + TP_PROTO(int port, struct ucsi_connector *con), + TP_ARGS(port, con) ); DECLARE_EVENT_CLASS(ucsi_log_register_altmode, diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index e0f3925e401b3d..fcf499cc9458c0 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -46,11 +46,11 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci) ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci)); if (cci & UCSI_CCI_ACK_COMPLETE && - test_bit(ACK_PENDING, &ucsi->flags)) + test_and_clear_bit(ACK_PENDING, &ucsi->flags)) complete(&ucsi->complete); if (cci & UCSI_CCI_COMMAND_COMPLETE && - test_bit(COMMAND_PENDING, &ucsi->flags)) + test_and_clear_bit(COMMAND_PENDING, &ucsi->flags)) complete(&ucsi->complete); } EXPORT_SYMBOL_GPL(ucsi_notify_common); @@ -65,6 +65,8 @@ int ucsi_sync_control_common(struct ucsi *ucsi, u64 command) else set_bit(COMMAND_PENDING, &ucsi->flags); + reinit_completion(&ucsi->complete); + ret = ucsi->ops->async_control(ucsi, command); if (ret) goto out_clear_bit; @@ -648,6 +650,18 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient) } } +static int ucsi_get_connector_status(struct ucsi_connector *con, bool conn_ack) +{ + u64 command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); + size_t size = min(sizeof(con->status), + UCSI_MAX_DATA_LENGTH(con->ucsi)); + int ret; + + ret = ucsi_send_command_common(con->ucsi, command, &con->status, size, conn_ack); + + return ret < 0 ? ret : 0; +} + static int ucsi_read_pdos(struct ucsi_connector *con, enum typec_role role, int is_partner, u32 *pdos, int offset, int num_pdos) @@ -658,8 +672,7 @@ static int ucsi_read_pdos(struct ucsi_connector *con, if (is_partner && ucsi->quirks & UCSI_NO_PARTNER_PDOS && - ((con->status.flags & UCSI_CONSTAT_PWR_DIR) || - !is_source(role))) + (UCSI_CONSTAT(con, PWR_DIR) || !is_source(role))) return 0; command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num); @@ -973,6 +986,7 @@ static void ucsi_unregister_cable(struct ucsi_connector *con) static int ucsi_check_connector_capability(struct ucsi_connector *con) { + u64 pd_revision; u64 command; int ret; @@ -986,17 +1000,17 @@ static int ucsi_check_connector_capability(struct ucsi_connector *con) return ret; } - typec_partner_set_pd_revision(con->partner, - UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags)); + pd_revision = UCSI_CONCAP(con, PARTNER_PD_REVISION_V2_1); + typec_partner_set_pd_revision(con->partner, UCSI_SPEC_REVISION_TO_BCD(pd_revision)); return ret; } static void ucsi_pwr_opmode_change(struct ucsi_connector *con) { - switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { + switch (UCSI_CONSTAT(con, PWR_OPMODE)) { case UCSI_CONSTAT_PWR_OPMODE_PD: - con->rdo = con->status.request_data_obj; + con->rdo = UCSI_CONSTAT(con, RDO); typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_PD); ucsi_partner_task(con, ucsi_get_src_pdos, 30, 0); ucsi_partner_task(con, ucsi_check_altmodes, 30, HZ); @@ -1020,7 +1034,7 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con) static int ucsi_register_partner(struct ucsi_connector *con) { - u8 pwr_opmode = UCSI_CONSTAT_PWR_OPMODE(con->status.flags); + u8 pwr_opmode = UCSI_CONSTAT(con, PWR_OPMODE); struct typec_partner_desc desc; struct typec_partner *partner; @@ -1029,7 +1043,7 @@ static int ucsi_register_partner(struct ucsi_connector *con) memset(&desc, 0, sizeof(desc)); - switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { + switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { case UCSI_CONSTAT_PARTNER_TYPE_DEBUG: desc.accessory = TYPEC_ACCESSORY_DEBUG; break; @@ -1047,6 +1061,11 @@ static int ucsi_register_partner(struct ucsi_connector *con) desc.identity = &con->partner_identity; desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD; + if (con->ucsi->version >= UCSI_VERSION_2_1) { + u64 pd_revision = UCSI_CONCAP(con, PARTNER_PD_REVISION_V2_1); + desc.pd_revision = UCSI_SPEC_REVISION_TO_BCD(pd_revision); + } + partner = typec_register_partner(con->port, &desc); if (IS_ERR(partner)) { dev_err(con->ucsi->dev, @@ -1057,6 +1076,13 @@ static int ucsi_register_partner(struct ucsi_connector *con) con->partner = partner; + if (con->ucsi->version >= UCSI_VERSION_3_0 && + UCSI_CONSTAT(con, PARTNER_FLAG_USB4_GEN4)) + typec_partner_set_usb_mode(partner, USB_MODE_USB4); + else if (con->ucsi->version >= UCSI_VERSION_2_0 && + UCSI_CONSTAT(con, PARTNER_FLAG_USB4_GEN3)) + typec_partner_set_usb_mode(partner, USB_MODE_USB4); + return 0; } @@ -1081,7 +1107,7 @@ static void ucsi_partner_change(struct ucsi_connector *con) enum usb_role u_role = USB_ROLE_NONE; int ret; - switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { + switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: u_role = USB_ROLE_HOST; @@ -1097,8 +1123,8 @@ static void ucsi_partner_change(struct ucsi_connector *con) break; } - if (con->status.flags & UCSI_CONSTAT_CONNECTED) { - switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { + if (UCSI_CONSTAT(con, CONNECTED)) { + switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { case UCSI_CONSTAT_PARTNER_TYPE_DEBUG: typec_set_mode(con->port, TYPEC_MODE_DEBUG); break; @@ -1106,14 +1132,13 @@ static void ucsi_partner_change(struct ucsi_connector *con) typec_set_mode(con->port, TYPEC_MODE_AUDIO); break; default: - if (UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) == - UCSI_CONSTAT_PARTNER_FLAG_USB) + if (UCSI_CONSTAT(con, PARTNER_FLAG_USB)) typec_set_mode(con->port, TYPEC_STATE_USB); } } /* Only notify USB controller if partner supports USB data */ - if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB)) + if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB))) u_role = USB_ROLE_NONE; ret = usb_role_switch_set_role(con->usb_role_sw, u_role); @@ -1124,21 +1149,18 @@ static void ucsi_partner_change(struct ucsi_connector *con) static int ucsi_check_connection(struct ucsi_connector *con) { - u8 prev_flags = con->status.flags; - u64 command; + u8 prev_state = UCSI_CONSTAT(con, CONNECTED); int ret; - command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); - ret = ucsi_send_command(con->ucsi, command, &con->status, sizeof(con->status)); - if (ret < 0) { + ret = ucsi_get_connector_status(con, false); + if (ret) { dev_err(con->ucsi->dev, "GET_CONNECTOR_STATUS failed (%d)\n", ret); return ret; } - if (con->status.flags == prev_flags) - return 0; - - if (con->status.flags & UCSI_CONSTAT_CONNECTED) { + if (UCSI_CONSTAT(con, CONNECTED)) { + if (prev_state) + return 0; ucsi_register_partner(con); ucsi_pwr_opmode_change(con); ucsi_partner_change(con); @@ -1194,7 +1216,7 @@ static void ucsi_handle_connector_change(struct work_struct *work) work); struct ucsi *ucsi = con->ucsi; enum typec_role role; - u64 command; + u16 change; int ret; mutex_lock(&con->lock); @@ -1203,25 +1225,23 @@ static void ucsi_handle_connector_change(struct work_struct *work) dev_err_once(ucsi->dev, "%s entered without EVENT_PENDING\n", __func__); - command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); - - ret = ucsi_send_command_common(ucsi, command, &con->status, - sizeof(con->status), true); - if (ret < 0) { + ret = ucsi_get_connector_status(con, true); + if (ret) { dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n", __func__, ret); clear_bit(EVENT_PENDING, &con->ucsi->flags); goto out_unlock; } - trace_ucsi_connector_change(con->num, &con->status); + trace_ucsi_connector_change(con->num, con); if (ucsi->ops->connector_status) ucsi->ops->connector_status(con); - role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); + change = UCSI_CONSTAT(con, CHANGE); + role = UCSI_CONSTAT(con, PWR_DIR); - if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) { + if (change & UCSI_CONSTAT_POWER_DIR_CHANGE) { typec_set_pwr_role(con->port, role); /* Complete pending power role swap */ @@ -1229,12 +1249,12 @@ static void ucsi_handle_connector_change(struct work_struct *work) complete(&con->complete); } - if (con->status.change & UCSI_CONSTAT_CONNECT_CHANGE) { + if (change & UCSI_CONSTAT_CONNECT_CHANGE) { typec_set_pwr_role(con->port, role); ucsi_port_psy_changed(con); ucsi_partner_change(con); - if (con->status.flags & UCSI_CONSTAT_CONNECTED) { + if (UCSI_CONSTAT(con, CONNECTED)) { ucsi_register_partner(con); ucsi_partner_task(con, ucsi_check_connection, 1, HZ); if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE) @@ -1242,8 +1262,7 @@ static void ucsi_handle_connector_change(struct work_struct *work) if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS) ucsi_partner_task(con, ucsi_check_cable, 1, HZ); - if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) == - UCSI_CONSTAT_PWR_OPMODE_PD) { + if (UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) { ucsi_partner_task(con, ucsi_register_partner_pdos, 1, HZ); ucsi_partner_task(con, ucsi_check_connector_capability, 1, HZ); } @@ -1252,11 +1271,10 @@ static void ucsi_handle_connector_change(struct work_struct *work) } } - if (con->status.change & UCSI_CONSTAT_POWER_OPMODE_CHANGE || - con->status.change & UCSI_CONSTAT_POWER_LEVEL_CHANGE) + if (change & (UCSI_CONSTAT_POWER_OPMODE_CHANGE | UCSI_CONSTAT_POWER_LEVEL_CHANGE)) ucsi_pwr_opmode_change(con); - if (con->partner && con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) { + if (con->partner && (change & UCSI_CONSTAT_PARTNER_CHANGE)) { ucsi_partner_change(con); /* Complete pending data role swap */ @@ -1264,10 +1282,10 @@ static void ucsi_handle_connector_change(struct work_struct *work) complete(&con->complete); } - if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) + if (change & UCSI_CONSTAT_CAM_CHANGE) ucsi_partner_task(con, ucsi_check_altmodes, 1, HZ); - if (con->status.change & UCSI_CONSTAT_BC_CHANGE) + if (change & UCSI_CONSTAT_BC_CHANGE) ucsi_port_psy_changed(con); out_unlock: @@ -1427,7 +1445,7 @@ static int ucsi_dr_swap(struct typec_port *port, enum typec_data_role role) goto out_unlock; } - partner_type = UCSI_CONSTAT_PARTNER_TYPE(con->status.flags); + partner_type = UCSI_CONSTAT(con, PARTNER_TYPE); if ((partner_type == UCSI_CONSTAT_PARTNER_TYPE_DFP && role == TYPEC_DEVICE) || (partner_type == UCSI_CONSTAT_PARTNER_TYPE_UFP && @@ -1471,7 +1489,7 @@ static int ucsi_pr_swap(struct typec_port *port, enum typec_role role) goto out_unlock; } - cur_role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); + cur_role = UCSI_CONSTAT(con, PWR_DIR); if (cur_role == role) goto out_unlock; @@ -1494,8 +1512,7 @@ static int ucsi_pr_swap(struct typec_port *port, enum typec_role role) mutex_lock(&con->lock); /* Something has gone wrong while swapping the role */ - if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) != - UCSI_CONSTAT_PWR_OPMODE_PD) { + if (UCSI_CONSTAT(con, PWR_OPMODE) != UCSI_CONSTAT_PWR_OPMODE_PD) { ucsi_reset_connector(con, true); ret = -EPROTO; } @@ -1563,19 +1580,18 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) if (ret < 0) goto out_unlock; - if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP) + if (UCSI_CONCAP(con, OPMODE_DRP)) cap->data = TYPEC_PORT_DRD; - else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DFP) + else if (UCSI_CONCAP(con, OPMODE_DFP)) cap->data = TYPEC_PORT_DFP; - else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_UFP) + else if (UCSI_CONCAP(con, OPMODE_UFP)) cap->data = TYPEC_PORT_UFP; - if ((con->cap.flags & UCSI_CONCAP_FLAG_PROVIDER) && - (con->cap.flags & UCSI_CONCAP_FLAG_CONSUMER)) + if (UCSI_CONCAP(con, PROVIDER) && UCSI_CONCAP(con, CONSUMER)) cap->type = TYPEC_PORT_DRP; - else if (con->cap.flags & UCSI_CONCAP_FLAG_PROVIDER) + else if (UCSI_CONCAP(con, PROVIDER)) cap->type = TYPEC_PORT_SRC; - else if (con->cap.flags & UCSI_CONCAP_FLAG_CONSUMER) + else if (UCSI_CONCAP(con, CONSUMER)) cap->type = TYPEC_PORT_SNK; cap->revision = ucsi->cap.typec_version; @@ -1583,11 +1599,18 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) cap->svdm_version = SVDM_VER_2_0; cap->prefer_role = TYPEC_NO_PREFERRED_ROLE; - if (con->cap.op_mode & UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY) + if (UCSI_CONCAP(con, OPMODE_AUDIO_ACCESSORY)) *accessory++ = TYPEC_ACCESSORY_AUDIO; - if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY) + if (UCSI_CONCAP(con, OPMODE_DEBUG_ACCESSORY)) *accessory = TYPEC_ACCESSORY_DEBUG; + if (UCSI_CONCAP_USB2_SUPPORT(con)) + cap->usb_capability |= USB_CAPABILITY_USB2; + if (UCSI_CONCAP_USB3_SUPPORT(con)) + cap->usb_capability |= USB_CAPABILITY_USB3; + if (UCSI_CONCAP_USB4_SUPPORT(con)) + cap->usb_capability |= USB_CAPABILITY_USB4; + cap->driver_data = con; cap->ops = &ucsi_ops; @@ -1617,19 +1640,16 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) } /* Get the status */ - command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); - ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status)); - if (ret < 0) { + ret = ucsi_get_connector_status(con, false); + if (ret) { dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); - ret = 0; goto out; } - ret = 0; /* ucsi_send_command() returns length on success */ if (ucsi->ops->connector_status) ucsi->ops->connector_status(con); - switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { + switch (UCSI_CONSTAT(con, PARTNER_TYPE)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: u_role = USB_ROLE_HOST; @@ -1646,9 +1666,8 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) } /* Check if there is already something connected */ - if (con->status.flags & UCSI_CONSTAT_CONNECTED) { - typec_set_pwr_role(con->port, - !!(con->status.flags & UCSI_CONSTAT_PWR_DIR)); + if (UCSI_CONSTAT(con, CONNECTED)) { + typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR)); ucsi_register_partner(con); ucsi_pwr_opmode_change(con); ucsi_port_psy_changed(con); @@ -1659,7 +1678,7 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) } /* Only notify USB controller if partner supports USB data */ - if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB)) + if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB))) u_role = USB_ROLE_NONE; ret = usb_role_switch_set_role(con->usb_role_sw, u_role); @@ -1669,16 +1688,14 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) ret = 0; } - if (con->partner && - UCSI_CONSTAT_PWR_OPMODE(con->status.flags) == - UCSI_CONSTAT_PWR_OPMODE_PD) { + if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) { ucsi_register_device_pdos(con); ucsi_get_src_pdos(con); ucsi_check_altmodes(con); ucsi_check_connector_capability(con); } - trace_ucsi_register_port(con->num, &con->status); + trace_ucsi_register_port(con->num, con); out: fwnode_handle_put(cap->fwnode); @@ -1761,7 +1778,8 @@ static int ucsi_init(struct ucsi *ucsi) /* Get PPM capabilities */ command = UCSI_GET_CAPABILITY; - ret = ucsi_send_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap)); + ret = ucsi_send_command(ucsi, command, &ucsi->cap, + BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE)); if (ret < 0) goto err_reset; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 1cf5aad4c23a9e..5ff369c24a2fc4 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -4,6 +4,7 @@ #define __DRIVER_USB_TYPEC_UCSI_H #include +#include #include #include #include @@ -95,26 +96,31 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); /* -------------------------------------------------------------------------- */ /* Commands */ -#define UCSI_PPM_RESET 0x01 -#define UCSI_CANCEL 0x02 -#define UCSI_CONNECTOR_RESET 0x03 -#define UCSI_ACK_CC_CI 0x04 -#define UCSI_SET_NOTIFICATION_ENABLE 0x05 -#define UCSI_GET_CAPABILITY 0x06 -#define UCSI_GET_CONNECTOR_CAPABILITY 0x07 -#define UCSI_SET_UOM 0x08 -#define UCSI_SET_UOR 0x09 -#define UCSI_SET_PDM 0x0a -#define UCSI_SET_PDR 0x0b -#define UCSI_GET_ALTERNATE_MODES 0x0c -#define UCSI_GET_CAM_SUPPORTED 0x0d -#define UCSI_GET_CURRENT_CAM 0x0e -#define UCSI_SET_NEW_CAM 0x0f -#define UCSI_GET_PDOS 0x10 -#define UCSI_GET_CABLE_PROPERTY 0x11 -#define UCSI_GET_CONNECTOR_STATUS 0x12 -#define UCSI_GET_ERROR_STATUS 0x13 -#define UCSI_GET_PD_MESSAGE 0x15 +#define UCSI_PPM_RESET 0x01 +#define UCSI_CANCEL 0x02 +#define UCSI_CONNECTOR_RESET 0x03 +#define UCSI_ACK_CC_CI 0x04 +#define UCSI_SET_NOTIFICATION_ENABLE 0x05 +#define UCSI_GET_CAPABILITY 0x06 +#define UCSI_GET_CAPABILITY_SIZE 128 +#define UCSI_GET_CONNECTOR_CAPABILITY 0x07 +#define UCSI_GET_CONNECTOR_CAPABILITY_SIZE 32 +#define UCSI_SET_UOM 0x08 +#define UCSI_SET_UOR 0x09 +#define UCSI_SET_PDM 0x0a +#define UCSI_SET_PDR 0x0b +#define UCSI_GET_ALTERNATE_MODES 0x0c +#define UCSI_GET_CAM_SUPPORTED 0x0d +#define UCSI_GET_CURRENT_CAM 0x0e +#define UCSI_SET_NEW_CAM 0x0f +#define UCSI_GET_PDOS 0x10 +#define UCSI_GET_CABLE_PROPERTY 0x11 +#define UCSI_GET_CABLE_PROPERTY_SIZE 64 +#define UCSI_GET_CONNECTOR_STATUS 0x12 +#define UCSI_GET_CONNECTOR_STATUS_SIZE 152 +#define UCSI_GET_ERROR_STATUS 0x13 +#define UCSI_GET_PD_MESSAGE 0x15 +#define UCSI_SET_SINK_PATH 0x1c #define UCSI_CONNECTOR_NUMBER(_num_) ((u64)(_num_) << 16) #define UCSI_COMMAND(_cmd_) ((_cmd_) & 0xff) @@ -126,7 +132,6 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_CONNECTOR_RESET_HARD_VER_1_0 BIT(23) /* Deprecated in v1.1 */ #define UCSI_CONNECTOR_RESET_DATA_VER_2_0 BIT(23) /* Redefined in v2.0 */ - /* ACK_CC_CI bits */ #define UCSI_ACK_CONNECTOR_CHANGE BIT(16) #define UCSI_ACK_COMMAND_COMPLETE BIT(17) @@ -250,42 +255,6 @@ struct ucsi_capability { u16 typec_version; } __packed; -/* Data structure filled by PPM in response to GET_CONNECTOR_CAPABILITY cmd. */ -struct ucsi_connector_capability { - u8 op_mode; -#define UCSI_CONCAP_OPMODE_DFP BIT(0) -#define UCSI_CONCAP_OPMODE_UFP BIT(1) -#define UCSI_CONCAP_OPMODE_DRP BIT(2) -#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY BIT(3) -#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY BIT(4) -#define UCSI_CONCAP_OPMODE_USB2 BIT(5) -#define UCSI_CONCAP_OPMODE_USB3 BIT(6) -#define UCSI_CONCAP_OPMODE_ALT_MODE BIT(7) - u32 flags; -#define UCSI_CONCAP_FLAG_PROVIDER BIT(0) -#define UCSI_CONCAP_FLAG_CONSUMER BIT(1) -#define UCSI_CONCAP_FLAG_SWAP_TO_DFP BIT(2) -#define UCSI_CONCAP_FLAG_SWAP_TO_UFP BIT(3) -#define UCSI_CONCAP_FLAG_SWAP_TO_SRC BIT(4) -#define UCSI_CONCAP_FLAG_SWAP_TO_SINK BIT(5) -#define UCSI_CONCAP_FLAG_EX_OP_MODE(_f_) \ - (((_f_) & GENMASK(13, 6)) >> 6) -#define UCSI_CONCAP_EX_OP_MODE_USB4_GEN2 BIT(0) -#define UCSI_CONCAP_EX_OP_MODE_EPR_SRC BIT(1) -#define UCSI_CONCAP_EX_OP_MODE_EPR_SINK BIT(2) -#define UCSI_CONCAP_EX_OP_MODE_USB4_GEN3 BIT(3) -#define UCSI_CONCAP_EX_OP_MODE_USB4_GEN4 BIT(4) -#define UCSI_CONCAP_FLAG_MISC_CAPS(_f_) \ - (((_f_) & GENMASK(17, 14)) >> 14) -#define UCSI_CONCAP_MISC_CAP_FW_UPDATE BIT(0) -#define UCSI_CONCAP_MISC_CAP_SECURITY BIT(1) -#define UCSI_CONCAP_FLAG_REV_CURR_PROT_SUPPORT BIT(18) -#define UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV(_f_) \ - (((_f_) & GENMASK(20, 19)) >> 19) -#define UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(_f_) \ - UCSI_SPEC_REVISION_TO_BCD(UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV(_f_)) -} __packed; - struct ucsi_altmode { u16 svid; u32 mid; @@ -311,49 +280,143 @@ struct ucsi_cable_property { u8 latency; } __packed; -/* Data structure filled by PPM in response to GET_CONNECTOR_STATUS command. */ -struct ucsi_connector_status { - u16 change; -#define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1) -#define UCSI_CONSTAT_POWER_OPMODE_CHANGE BIT(2) -#define UCSI_CONSTAT_PDOS_CHANGE BIT(5) -#define UCSI_CONSTAT_POWER_LEVEL_CHANGE BIT(6) -#define UCSI_CONSTAT_PD_RESET_COMPLETE BIT(7) -#define UCSI_CONSTAT_CAM_CHANGE BIT(8) -#define UCSI_CONSTAT_BC_CHANGE BIT(9) -#define UCSI_CONSTAT_PARTNER_CHANGE BIT(11) -#define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12) -#define UCSI_CONSTAT_CONNECT_CHANGE BIT(14) -#define UCSI_CONSTAT_ERROR BIT(15) - u16 flags; -#define UCSI_CONSTAT_PWR_OPMODE(_f_) ((_f_) & GENMASK(2, 0)) +/* Get Connector Capability Fields. */ +#define UCSI_CONCAP_OPMODE UCSI_DECLARE_BITFIELD(0, 0, 8) +#define UCSI_CONCAP_OPMODE_DFP UCSI_DECLARE_BITFIELD(0, 0, 1) +#define UCSI_CONCAP_OPMODE_UFP UCSI_DECLARE_BITFIELD(0, 1, 1) +#define UCSI_CONCAP_OPMODE_DRP UCSI_DECLARE_BITFIELD(0, 2, 1) +#define UCSI_CONCAP_OPMODE_AUDIO_ACCESSORY UCSI_DECLARE_BITFIELD(0, 3, 1) +#define UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY UCSI_DECLARE_BITFIELD(0, 4, 1) +#define UCSI_CONCAP_OPMODE_USB2 UCSI_DECLARE_BITFIELD(0, 5, 1) +#define UCSI_CONCAP_OPMODE_USB3 UCSI_DECLARE_BITFIELD(0, 6, 1) +#define UCSI_CONCAP_OPMODE_ALT_MODE UCSI_DECLARE_BITFIELD(0, 7, 1) +#define UCSI_CONCAP_PROVIDER UCSI_DECLARE_BITFIELD(0, 8, 1) +#define UCSI_CONCAP_CONSUMER UCSI_DECLARE_BITFIELD(0, 9, 1) +#define UCSI_CONCAP_SWAP_TO_DFP_V1_1 UCSI_DECLARE_BITFIELD_V1_1(10, 1) +#define UCSI_CONCAP_SWAP_TO_UFP_V1_1 UCSI_DECLARE_BITFIELD_V1_1(11, 1) +#define UCSI_CONCAP_SWAP_TO_SRC_V1_1 UCSI_DECLARE_BITFIELD_V1_1(12, 1) +#define UCSI_CONCAP_SWAP_TO_SNK_V1_1 UCSI_DECLARE_BITFIELD_V1_1(13, 1) +#define UCSI_CONCAP_EXT_OPMODE_V2_0 UCSI_DECLARE_BITFIELD_V2_0(14, 8) +#define UCSI_CONCAP_EXT_OPMODE_USB4_GEN2_V2_0 UCSI_DECLARE_BITFIELD_V2_0(14, 1) +#define UCSI_CONCAP_EXT_OPMODE_EPR_SRC_V2_0 UCSI_DECLARE_BITFIELD_V2_0(15, 1) +#define UCSI_CONCAP_EXT_OPMODE_EPR_SINK_V2_0 UCSI_DECLARE_BITFIELD_V2_0(16, 1) +#define UCSI_CONCAP_EXT_OPMODE_USB4_GEN3_V2_0 UCSI_DECLARE_BITFIELD_V2_0(17, 1) +#define UCSI_CONCAP_EXT_OPMODE_USB4_GEN4_V2_0 UCSI_DECLARE_BITFIELD_V2_0(18, 1) +#define UCSI_CONCAP_MISC_V2_0 UCSI_DECLARE_BITFIELD_V2_0(22, 4) +#define UCSI_CONCAP_MISC_FW_UPDATE_V2_0 UCSI_DECLARE_BITFIELD_V2_0(22, 1) +#define UCSI_CONCAP_MISC_SECURITY_V2_0 UCSI_DECLARE_BITFIELD_V2_0(23, 1) +#define UCSI_CONCAP_REV_CURR_PROT_SUPPORT_V2_0 UCSI_DECLARE_BITFIELD_V2_0(26, 1) +#define UCSI_CONCAP_PARTNER_PD_REVISION_V2_1 UCSI_DECLARE_BITFIELD_V2_1(27, 2) + +/* Helpers for USB capability checks. */ +#define UCSI_CONCAP_USB2_SUPPORT(_con_) UCSI_CONCAP((_con_), OPMODE_USB2) +#define UCSI_CONCAP_USB3_SUPPORT(_con_) UCSI_CONCAP((_con_), OPMODE_USB3) +#define UCSI_CONCAP_USB4_SUPPORT(_con_) \ + ((_con_)->ucsi->version >= UCSI_VERSION_2_0 && \ + (UCSI_CONCAP((_con_), EXT_OPMODE_USB4_GEN2_V2_0) | \ + UCSI_CONCAP((_con_), EXT_OPMODE_USB4_GEN3_V2_0) | \ + UCSI_CONCAP((_con_), EXT_OPMODE_USB4_GEN4_V2_0))) + +/* Get Connector Status Fields. */ +#define UCSI_CONSTAT_CHANGE UCSI_DECLARE_BITFIELD(0, 0, 16) +#define UCSI_CONSTAT_PWR_OPMODE UCSI_DECLARE_BITFIELD(0, 16, 3) #define UCSI_CONSTAT_PWR_OPMODE_NONE 0 #define UCSI_CONSTAT_PWR_OPMODE_DEFAULT 1 #define UCSI_CONSTAT_PWR_OPMODE_BC 2 #define UCSI_CONSTAT_PWR_OPMODE_PD 3 #define UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5 4 #define UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0 5 -#define UCSI_CONSTAT_CONNECTED BIT(3) -#define UCSI_CONSTAT_PWR_DIR BIT(4) -#define UCSI_CONSTAT_PARTNER_FLAGS(_f_) (((_f_) & GENMASK(12, 5)) >> 5) -#define UCSI_CONSTAT_PARTNER_FLAG_USB 1 -#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE 2 -#define UCSI_CONSTAT_PARTNER_TYPE(_f_) (((_f_) & GENMASK(15, 13)) >> 13) +#define UCSI_CONSTAT_CONNECTED UCSI_DECLARE_BITFIELD(0, 19, 1) +#define UCSI_CONSTAT_PWR_DIR UCSI_DECLARE_BITFIELD(0, 20, 1) +#define UCSI_CONSTAT_PARTNER_FLAGS UCSI_DECLARE_BITFIELD(0, 21, 8) +#define UCSI_CONSTAT_PARTNER_FLAG_USB UCSI_DECLARE_BITFIELD(0, 21, 1) +#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE UCSI_DECLARE_BITFIELD(0, 22, 1) +#define UCSI_CONSTAT_PARTNER_FLAG_USB4_GEN3 UCSI_DECLARE_BITFIELD(0, 23, 1) +#define UCSI_CONSTAT_PARTNER_FLAG_USB4_GEN4 UCSI_DECLARE_BITFIELD(0, 24, 1) +#define UCSI_CONSTAT_PARTNER_TYPE UCSI_DECLARE_BITFIELD(0, 29, 3) #define UCSI_CONSTAT_PARTNER_TYPE_DFP 1 #define UCSI_CONSTAT_PARTNER_TYPE_UFP 2 -#define UCSI_CONSTAT_PARTNER_TYPE_CABLE 3 /* Powered Cable */ -#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */ +#define UCSI_CONSTAT_PARTNER_TYPE_CABLE 3 /* Powered Cable */ +#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */ #define UCSI_CONSTAT_PARTNER_TYPE_DEBUG 5 #define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6 - u32 request_data_obj; - - u8 pwr_status; -#define UCSI_CONSTAT_BC_STATUS(_p_) ((_p_) & GENMASK(1, 0)) +#define UCSI_CONSTAT_RDO UCSI_DECLARE_BITFIELD(0, 32, 32) +#define UCSI_CONSTAT_BC_STATUS UCSI_DECLARE_BITFIELD(0, 64, 2) #define UCSI_CONSTAT_BC_NOT_CHARGING 0 #define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1 #define UCSI_CONSTAT_BC_SLOW_CHARGING 2 #define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3 -} __packed; +#define UCSI_CONSTAT_PD_VERSION_V1_2 UCSI_DECLARE_BITFIELD_V1_2(70, 16) + +/* Connector Status Change Bits. */ +#define UCSI_CONSTAT_EXT_SUPPLY_CHANGE BIT(1) +#define UCSI_CONSTAT_POWER_OPMODE_CHANGE BIT(2) +#define UCSI_CONSTAT_PDOS_CHANGE BIT(5) +#define UCSI_CONSTAT_POWER_LEVEL_CHANGE BIT(6) +#define UCSI_CONSTAT_PD_RESET_COMPLETE BIT(7) +#define UCSI_CONSTAT_CAM_CHANGE BIT(8) +#define UCSI_CONSTAT_BC_CHANGE BIT(9) +#define UCSI_CONSTAT_PARTNER_CHANGE BIT(11) +#define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12) +#define UCSI_CONSTAT_CONNECT_CHANGE BIT(14) +#define UCSI_CONSTAT_ERROR BIT(15) + +#define UCSI_DECLARE_BITFIELD_V1_1(_offset_, _size_) \ + UCSI_DECLARE_BITFIELD(UCSI_VERSION_1_1, (_offset_), (_size_)) +#define UCSI_DECLARE_BITFIELD_V1_2(_offset_, _size_) \ + UCSI_DECLARE_BITFIELD(UCSI_VERSION_1_2, (_offset_), (_size_)) +#define UCSI_DECLARE_BITFIELD_V2_0(_offset_, _size_) \ + UCSI_DECLARE_BITFIELD(UCSI_VERSION_2_0, (_offset_), (_size_)) +#define UCSI_DECLARE_BITFIELD_V2_1(_offset_, _size_) \ + UCSI_DECLARE_BITFIELD(UCSI_VERSION_2_1, (_offset_), (_size_)) +#define UCSI_DECLARE_BITFIELD_V3_0(_offset_, _size_) \ + UCSI_DECLARE_BITFIELD(UCSI_VERSION_3_0, (_offset_), (_size_)) + +#define UCSI_DECLARE_BITFIELD(_ver_, _offset_, _size_) \ +(struct ucsi_bitfield) { \ + .version = _ver_, \ + .offset = _offset_, \ + .size = _size_, \ +} + +struct ucsi_bitfield { + const u16 version; + const u8 offset; + const u8 size; +}; + +/** + * ucsi_bitfield_read - Read a field from UCSI command response + * @_map_: UCSI command response + * @_field_: The field offset in the response data structure + * @_ver_: UCSI version where the field was introduced + * + * Reads the fields in the command responses by first checking that the field is + * valid with the UCSI interface version that is used in the system. + * @_ver_ is the minimum UCSI version for the @_field_. If the UCSI interface is + * older than @_ver_, a warning is generated. + * + * Caveats: + * - Removed fields are not checked - @_ver_ is just the minimum UCSI version. + * + * Returns the value of @_field_, or 0 when the UCSI interface is older than + * @_ver_. + */ +#define ucsi_bitfield_read(_map_, _field_, _ver_) \ +({ \ + struct ucsi_bitfield f = (_field_); \ + WARN((_ver_) < f.version, \ + "Access to unsupported field at offset 0x%x (need version %04x)", \ + f.offset, f.version) ? 0 : \ + bitmap_read((_map_), f.offset, f.size); \ +}) + +/* Helpers to access cached command responses. */ +#define UCSI_CONCAP(_con_, _field_) \ + ucsi_bitfield_read((_con_)->cap, UCSI_CONCAP_##_field_, (_con_)->ucsi->version) + +#define UCSI_CONSTAT(_con_, _field_) \ + ucsi_bitfield_read((_con_)->status, UCSI_CONSTAT_##_field_, (_con_)->ucsi->version) /* -------------------------------------------------------------------------- */ @@ -433,8 +496,10 @@ struct ucsi_connector { struct typec_capability typec_cap; - struct ucsi_connector_status status; - struct ucsi_connector_capability cap; + /* Cached command responses. */ + DECLARE_BITMAP(cap, UCSI_GET_CONNECTOR_CAPABILITY_SIZE); + DECLARE_BITMAP(status, UCSI_GET_CONNECTOR_STATUS_SIZE); + struct power_supply *psy; struct power_supply_desc psy_desc; u32 rdo; diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 7a5dff8d9cc6c3..5c55155519634d 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -61,9 +61,11 @@ static int ucsi_acpi_read_cci(struct ucsi *ucsi, u32 *cci) struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); int ret; - ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); - if (ret) - return ret; + if (UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) { + ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); + if (ret) + return ret; + } memcpy(cci, ua->base + UCSI_CCI, sizeof(*cci)); @@ -73,11 +75,6 @@ static int ucsi_acpi_read_cci(struct ucsi *ucsi, u32 *cci) static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_len) { struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - int ret; - - ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); - if (ret) - return ret; memcpy(val, ua->base + UCSI_MESSAGE_IN, val_len); @@ -102,48 +99,11 @@ static const struct ucsi_operations ucsi_acpi_ops = { .async_control = ucsi_acpi_async_control }; -static int -ucsi_zenbook_read_cci(struct ucsi *ucsi, u32 *cci) -{ - struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - int ret; - - if (UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) { - ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); - if (ret) - return ret; - } - - memcpy(cci, ua->base + UCSI_CCI, sizeof(*cci)); - - return 0; -} - -static int -ucsi_zenbook_read_message_in(struct ucsi *ucsi, void *val, size_t val_len) -{ - struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - - /* UCSI_MESSAGE_IN is never read for PPM_RESET, return stored data */ - memcpy(val, ua->base + UCSI_MESSAGE_IN, val_len); - - return 0; -} - -static const struct ucsi_operations ucsi_zenbook_ops = { - .read_version = ucsi_acpi_read_version, - .read_cci = ucsi_zenbook_read_cci, - .read_message_in = ucsi_zenbook_read_message_in, - .sync_control = ucsi_sync_control_common, - .async_control = ucsi_acpi_async_control -}; - static int ucsi_gram_read_message_in(struct ucsi *ucsi, void *val, size_t val_len) { u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE | UCSI_CONSTAT_PDOS_CHANGE; struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - struct ucsi_connector_status *status; int ret; ret = ucsi_acpi_read_message_in(ucsi, val, val_len); @@ -152,11 +112,9 @@ static int ucsi_gram_read_message_in(struct ucsi *ucsi, void *val, size_t val_le if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS && ua->check_bogus_event) { - status = (struct ucsi_connector_status *)val; - /* Clear the bogus change */ - if (status->change == bogus_change) - status->change = 0; + if (*(u16 *)val == bogus_change) + *(u16 *)val = 0; ua->check_bogus_event = false; } @@ -190,13 +148,6 @@ static const struct ucsi_operations ucsi_gram_ops = { }; static const struct dmi_system_id ucsi_acpi_quirks[] = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"), - }, - .driver_data = (void *)&ucsi_zenbook_ops, - }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), @@ -320,7 +271,7 @@ static struct platform_driver ucsi_acpi_platform_driver = { .acpi_match_table = ACPI_PTR(ucsi_acpi_match), }, .probe = ucsi_acpi_probe, - .remove_new = ucsi_acpi_remove, + .remove = ucsi_acpi_remove, }; module_platform_driver(ucsi_acpi_platform_driver); diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index bccfc03b5986d7..fcb8e61136cfd7 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -644,6 +644,10 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command) uc->has_multiple_dp) { con_index = (uc->last_cmd_sent >> 16) & UCSI_CMD_CONNECTOR_MASK; + if (con_index == 0) { + ret = -EINVAL; + goto unlock; + } con = &uc->ucsi->connector[con_index - 1]; ucsi_ccg_update_set_new_cam_cmd(uc, con, &command); } @@ -651,6 +655,7 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command) ret = ucsi_sync_control_common(ucsi, command); pm_runtime_put_sync(uc->dev); +unlock: mutex_unlock(&uc->lock); return ret; diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 03c0fa8edc8db5..90948cd6d29724 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -172,12 +172,12 @@ static int pmic_glink_ucsi_async_control(struct ucsi *__ucsi, u64 command) static void pmic_glink_ucsi_update_connector(struct ucsi_connector *con) { struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); - int i; - for (i = 0; i < PMIC_GLINK_MAX_PORTS; i++) { - if (ucsi->port_orientation[i]) - con->typec_cap.orientation_aware = true; - } + if (con->num > PMIC_GLINK_MAX_PORTS || + !ucsi->port_orientation[con->num - 1]) + return; + + con->typec_cap.orientation_aware = true; } static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con) @@ -185,7 +185,7 @@ static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con) struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); int orientation; - if (con->num >= PMIC_GLINK_MAX_PORTS || + if (con->num > PMIC_GLINK_MAX_PORTS || !ucsi->port_orientation[con->num - 1]) return; @@ -322,7 +322,6 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, struct pmic_glink_ucsi *ucsi; struct device *dev = &adev->dev; const struct of_device_id *match; - struct fwnode_handle *fwnode; int ret; ucsi = devm_kzalloc(dev, sizeof(*ucsi), GFP_KERNEL); @@ -354,14 +353,13 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, ucsi_set_drvdata(ucsi->ucsi, ucsi); - device_for_each_child_node(dev, fwnode) { + device_for_each_child_node_scoped(dev, fwnode) { struct gpio_desc *desc; u32 port; ret = fwnode_property_read_u32(fwnode, "reg", &port); if (ret < 0) { dev_err(dev, "missing reg property of %pOFn\n", fwnode); - fwnode_handle_put(fwnode); return ret; } @@ -376,11 +374,10 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, if (!desc) continue; - if (IS_ERR(desc)) { - fwnode_handle_put(fwnode); + if (IS_ERR(desc)) return dev_err_probe(dev, PTR_ERR(desc), "unable to acquire orientation gpio\n"); - } + ucsi->port_orientation[port] = desc; } diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 8dac1edc74d4ee..b03e5021c25bd5 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1487,7 +1487,7 @@ static int vhci_hcd_resume(struct platform_device *pdev) static struct platform_driver vhci_driver = { .probe = vhci_hcd_probe, - .remove_new = vhci_hcd_remove, + .remove = vhci_hcd_remove, .suspend = vhci_hcd_suspend, .resume = vhci_hcd_resume, .driver = { diff --git a/drivers/usb/usbip/vudc_main.c b/drivers/usb/usbip/vudc_main.c index 8bee553e48945f..993e721cb840df 100644 --- a/drivers/usb/usbip/vudc_main.c +++ b/drivers/usb/usbip/vudc_main.c @@ -19,7 +19,7 @@ MODULE_PARM_DESC(num, "number of emulated controllers"); static struct platform_driver vudc_driver = { .probe = vudc_probe, - .remove_new = vudc_remove, + .remove = vudc_remove, .driver = { .name = GADGET_NAME, .dev_groups = vudc_groups, diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c index 7d0c83b5b07158..8455f08f5d4060 100644 --- a/drivers/vdpa/mlx5/core/mr.c +++ b/drivers/vdpa/mlx5/core/mr.c @@ -368,7 +368,6 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr unsigned long lgcd = 0; int log_entity_size; unsigned long size; - u64 start = 0; int err; struct page *pg; unsigned int nsg; @@ -379,10 +378,9 @@ static int map_direct_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_direct_mr struct device *dma = mvdev->vdev.dma_dev; for (map = vhost_iotlb_itree_first(iotlb, mr->start, mr->end - 1); - map; map = vhost_iotlb_itree_next(map, start, mr->end - 1)) { + map; map = vhost_iotlb_itree_next(map, mr->start, mr->end - 1)) { size = maplen(map, mr); lgcd = gcd(lgcd, size); - start += size; } log_entity_size = ilog2(lgcd); diff --git a/drivers/vfio/cdx/main.c b/drivers/vfio/cdx/main.c index 67465fad5b4bf3..5dd5f5ad768653 100644 --- a/drivers/vfio/cdx/main.c +++ b/drivers/vfio/cdx/main.c @@ -347,4 +347,4 @@ module_driver(vfio_cdx_driver, cdx_driver_register, cdx_driver_unregister); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("VFIO for CDX devices - User Level meta-driver"); -MODULE_IMPORT_NS(CDX_BUS); +MODULE_IMPORT_NS("CDX_BUS"); diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c index 95b336de8a1732..49559605177efc 100644 --- a/drivers/vfio/group.c +++ b/drivers/vfio/group.c @@ -104,15 +104,14 @@ static int vfio_group_ioctl_set_container(struct vfio_group *group, { struct vfio_container *container; struct iommufd_ctx *iommufd; - struct fd f; int ret; int fd; if (get_user(fd, arg)) return -EFAULT; - f = fdget(fd); - if (!fd_file(f)) + CLASS(fd, f)(fd); + if (fd_empty(f)) return -EBADF; mutex_lock(&group->group_lock); @@ -153,7 +152,6 @@ static int vfio_group_ioctl_set_container(struct vfio_group *group, out_unlock: mutex_unlock(&group->group_lock); - fdput(f); return ret; } diff --git a/drivers/vfio/iommufd.c b/drivers/vfio/iommufd.c index 82eba6966fa508..516294fd901be4 100644 --- a/drivers/vfio/iommufd.c +++ b/drivers/vfio/iommufd.c @@ -7,8 +7,8 @@ #include "vfio.h" -MODULE_IMPORT_NS(IOMMUFD); -MODULE_IMPORT_NS(IOMMUFD_VFIO); +MODULE_IMPORT_NS("IOMMUFD"); +MODULE_IMPORT_NS("IOMMUFD_VFIO"); bool vfio_iommufd_device_has_compat_ioas(struct vfio_device *vdev, struct iommufd_ctx *ictx) diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c index 0d632ba5d2a3c9..451c639299eb3b 100644 --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c @@ -486,31 +486,11 @@ static int vf_qm_load_data(struct hisi_acc_vf_core_device *hisi_acc_vdev, return 0; } -static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev, - struct hisi_acc_vf_migration_file *migf) +static int vf_qm_read_data(struct hisi_qm *vf_qm, struct acc_vf_data *vf_data) { - struct acc_vf_data *vf_data = &migf->vf_data; - struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm; struct device *dev = &vf_qm->pdev->dev; int ret; - if (unlikely(qm_wait_dev_not_ready(vf_qm))) { - /* Update state and return with match data */ - vf_data->vf_qm_state = QM_NOT_READY; - hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state; - migf->total_length = QM_MATCH_SIZE; - return 0; - } - - vf_data->vf_qm_state = QM_READY; - hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state; - - ret = vf_qm_cache_wb(vf_qm); - if (ret) { - dev_err(dev, "failed to writeback QM Cache!\n"); - return ret; - } - ret = qm_get_regs(vf_qm, vf_data); if (ret) return -EINVAL; @@ -536,6 +516,38 @@ static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev, return -EINVAL; } + return 0; +} + +static int vf_qm_state_save(struct hisi_acc_vf_core_device *hisi_acc_vdev, + struct hisi_acc_vf_migration_file *migf) +{ + struct acc_vf_data *vf_data = &migf->vf_data; + struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm; + struct device *dev = &vf_qm->pdev->dev; + int ret; + + if (unlikely(qm_wait_dev_not_ready(vf_qm))) { + /* Update state and return with match data */ + vf_data->vf_qm_state = QM_NOT_READY; + hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state; + migf->total_length = QM_MATCH_SIZE; + return 0; + } + + vf_data->vf_qm_state = QM_READY; + hisi_acc_vdev->vf_qm_state = vf_data->vf_qm_state; + + ret = vf_qm_cache_wb(vf_qm); + if (ret) { + dev_err(dev, "failed to writeback QM Cache!\n"); + return ret; + } + + ret = vf_qm_read_data(vf_qm, vf_data); + if (ret) + return -EINVAL; + migf->total_length = sizeof(struct acc_vf_data); return 0; } @@ -615,21 +627,43 @@ static void hisi_acc_vf_disable_fd(struct hisi_acc_vf_migration_file *migf) mutex_unlock(&migf->lock); } +static void +hisi_acc_debug_migf_copy(struct hisi_acc_vf_core_device *hisi_acc_vdev, + struct hisi_acc_vf_migration_file *src_migf) +{ + struct hisi_acc_vf_migration_file *dst_migf = hisi_acc_vdev->debug_migf; + + if (!dst_migf) + return; + + dst_migf->total_length = src_migf->total_length; + memcpy(&dst_migf->vf_data, &src_migf->vf_data, + sizeof(struct acc_vf_data)); +} + static void hisi_acc_vf_disable_fds(struct hisi_acc_vf_core_device *hisi_acc_vdev) { if (hisi_acc_vdev->resuming_migf) { + hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->resuming_migf); hisi_acc_vf_disable_fd(hisi_acc_vdev->resuming_migf); fput(hisi_acc_vdev->resuming_migf->filp); hisi_acc_vdev->resuming_migf = NULL; } if (hisi_acc_vdev->saving_migf) { + hisi_acc_debug_migf_copy(hisi_acc_vdev, hisi_acc_vdev->saving_migf); hisi_acc_vf_disable_fd(hisi_acc_vdev->saving_migf); fput(hisi_acc_vdev->saving_migf->filp); hisi_acc_vdev->saving_migf = NULL; } } +static struct hisi_acc_vf_core_device *hisi_acc_get_vf_dev(struct vfio_device *vdev) +{ + return container_of(vdev, struct hisi_acc_vf_core_device, + core_device.vdev); +} + static void hisi_acc_vf_reset(struct hisi_acc_vf_core_device *hisi_acc_vdev) { hisi_acc_vdev->vf_qm_state = QM_NOT_READY; @@ -1031,8 +1065,7 @@ static struct file * hisi_acc_vfio_pci_set_device_state(struct vfio_device *vdev, enum vfio_device_mig_state new_state) { - struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(vdev, - struct hisi_acc_vf_core_device, core_device.vdev); + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev); enum vfio_device_mig_state next_state; struct file *res = NULL; int ret; @@ -1073,8 +1106,7 @@ static int hisi_acc_vfio_pci_get_device_state(struct vfio_device *vdev, enum vfio_device_mig_state *curr_state) { - struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(vdev, - struct hisi_acc_vf_core_device, core_device.vdev); + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev); mutex_lock(&hisi_acc_vdev->state_mutex); *curr_state = hisi_acc_vdev->mig_state; @@ -1276,10 +1308,132 @@ static long hisi_acc_vfio_pci_ioctl(struct vfio_device *core_vdev, unsigned int return vfio_pci_core_ioctl(core_vdev, cmd, arg); } +static int hisi_acc_vf_debug_check(struct seq_file *seq, struct vfio_device *vdev) +{ + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev); + struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm; + int ret; + + lockdep_assert_held(&hisi_acc_vdev->open_mutex); + /* + * When the device is not opened, the io_base is not mapped. + * The driver cannot perform device read and write operations. + */ + if (!hisi_acc_vdev->dev_opened) { + seq_puts(seq, "device not opened!\n"); + return -EINVAL; + } + + ret = qm_wait_dev_not_ready(vf_qm); + if (ret) { + seq_puts(seq, "VF device not ready!\n"); + return -EBUSY; + } + + return 0; +} + +static int hisi_acc_vf_debug_cmd(struct seq_file *seq, void *data) +{ + struct device *vf_dev = seq->private; + struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev); + struct vfio_device *vdev = &core_device->vdev; + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev); + struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm; + u64 value; + int ret; + + mutex_lock(&hisi_acc_vdev->open_mutex); + ret = hisi_acc_vf_debug_check(seq, vdev); + if (ret) { + mutex_unlock(&hisi_acc_vdev->open_mutex); + return ret; + } + + value = readl(vf_qm->io_base + QM_MB_CMD_SEND_BASE); + if (value == QM_MB_CMD_NOT_READY) { + mutex_unlock(&hisi_acc_vdev->open_mutex); + seq_puts(seq, "mailbox cmd channel not ready!\n"); + return -EINVAL; + } + mutex_unlock(&hisi_acc_vdev->open_mutex); + seq_puts(seq, "mailbox cmd channel ready!\n"); + + return 0; +} + +static int hisi_acc_vf_dev_read(struct seq_file *seq, void *data) +{ + struct device *vf_dev = seq->private; + struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev); + struct vfio_device *vdev = &core_device->vdev; + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev); + size_t vf_data_sz = offsetofend(struct acc_vf_data, padding); + struct acc_vf_data *vf_data; + int ret; + + mutex_lock(&hisi_acc_vdev->open_mutex); + ret = hisi_acc_vf_debug_check(seq, vdev); + if (ret) { + mutex_unlock(&hisi_acc_vdev->open_mutex); + return ret; + } + + mutex_lock(&hisi_acc_vdev->state_mutex); + vf_data = kzalloc(sizeof(*vf_data), GFP_KERNEL); + if (!vf_data) { + ret = -ENOMEM; + goto mutex_release; + } + + vf_data->vf_qm_state = hisi_acc_vdev->vf_qm_state; + ret = vf_qm_read_data(&hisi_acc_vdev->vf_qm, vf_data); + if (ret) + goto migf_err; + + seq_hex_dump(seq, "Dev Data:", DUMP_PREFIX_OFFSET, 16, 1, + (const void *)vf_data, vf_data_sz, false); + + seq_printf(seq, + "guest driver load: %u\n" + "data size: %lu\n", + hisi_acc_vdev->vf_qm_state, + sizeof(struct acc_vf_data)); + +migf_err: + kfree(vf_data); +mutex_release: + mutex_unlock(&hisi_acc_vdev->state_mutex); + mutex_unlock(&hisi_acc_vdev->open_mutex); + + return ret; +} + +static int hisi_acc_vf_migf_read(struct seq_file *seq, void *data) +{ + struct device *vf_dev = seq->private; + struct vfio_pci_core_device *core_device = dev_get_drvdata(vf_dev); + struct vfio_device *vdev = &core_device->vdev; + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(vdev); + size_t vf_data_sz = offsetofend(struct acc_vf_data, padding); + struct hisi_acc_vf_migration_file *debug_migf = hisi_acc_vdev->debug_migf; + + /* Check whether the live migration operation has been performed */ + if (debug_migf->total_length < QM_MATCH_SIZE) { + seq_puts(seq, "device not migrated!\n"); + return -EAGAIN; + } + + seq_hex_dump(seq, "Mig Data:", DUMP_PREFIX_OFFSET, 16, 1, + (const void *)&debug_migf->vf_data, vf_data_sz, false); + seq_printf(seq, "migrate data length: %lu\n", debug_migf->total_length); + + return 0; +} + static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev) { - struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev, - struct hisi_acc_vf_core_device, core_device.vdev); + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev); struct vfio_pci_core_device *vdev = &hisi_acc_vdev->core_device; int ret; @@ -1288,12 +1442,16 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev) return ret; if (core_vdev->mig_ops) { + mutex_lock(&hisi_acc_vdev->open_mutex); ret = hisi_acc_vf_qm_init(hisi_acc_vdev); if (ret) { + mutex_unlock(&hisi_acc_vdev->open_mutex); vfio_pci_core_disable(vdev); return ret; } hisi_acc_vdev->mig_state = VFIO_DEVICE_STATE_RUNNING; + hisi_acc_vdev->dev_opened = true; + mutex_unlock(&hisi_acc_vdev->open_mutex); } vfio_pci_core_finish_enable(vdev); @@ -1302,11 +1460,13 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev) static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev) { - struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev, - struct hisi_acc_vf_core_device, core_device.vdev); + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev); struct hisi_qm *vf_qm = &hisi_acc_vdev->vf_qm; + mutex_lock(&hisi_acc_vdev->open_mutex); + hisi_acc_vdev->dev_opened = false; iounmap(vf_qm->io_base); + mutex_unlock(&hisi_acc_vdev->open_mutex); vfio_pci_core_close_device(core_vdev); } @@ -1318,8 +1478,7 @@ static const struct vfio_migration_ops hisi_acc_vfio_pci_migrn_state_ops = { static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev) { - struct hisi_acc_vf_core_device *hisi_acc_vdev = container_of(core_vdev, - struct hisi_acc_vf_core_device, core_device.vdev); + struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev); struct pci_dev *pdev = to_pci_dev(core_vdev->dev); struct hisi_qm *pf_qm = hisi_acc_get_pf_qm(pdev); @@ -1327,6 +1486,7 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev) hisi_acc_vdev->pf_qm = pf_qm; hisi_acc_vdev->vf_dev = pdev; mutex_init(&hisi_acc_vdev->state_mutex); + mutex_init(&hisi_acc_vdev->open_mutex); core_vdev->migration_flags = VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_PRE_COPY; core_vdev->mig_ops = &hisi_acc_vfio_pci_migrn_state_ops; @@ -1372,6 +1532,47 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_ops = { .detach_ioas = vfio_iommufd_physical_detach_ioas, }; +static void hisi_acc_vfio_debug_init(struct hisi_acc_vf_core_device *hisi_acc_vdev) +{ + struct vfio_device *vdev = &hisi_acc_vdev->core_device.vdev; + struct hisi_acc_vf_migration_file *migf; + struct dentry *vfio_dev_migration; + struct dentry *vfio_hisi_acc; + struct device *dev = vdev->dev; + + if (!debugfs_initialized() || + !IS_ENABLED(CONFIG_VFIO_DEBUGFS)) + return; + + if (vdev->ops != &hisi_acc_vfio_pci_migrn_ops) + return; + + vfio_dev_migration = debugfs_lookup("migration", vdev->debug_root); + if (!vfio_dev_migration) { + dev_err(dev, "failed to lookup migration debugfs file!\n"); + return; + } + + migf = kzalloc(sizeof(*migf), GFP_KERNEL); + if (!migf) + return; + hisi_acc_vdev->debug_migf = migf; + + vfio_hisi_acc = debugfs_create_dir("hisi_acc", vfio_dev_migration); + debugfs_create_devm_seqfile(dev, "dev_data", vfio_hisi_acc, + hisi_acc_vf_dev_read); + debugfs_create_devm_seqfile(dev, "migf_data", vfio_hisi_acc, + hisi_acc_vf_migf_read); + debugfs_create_devm_seqfile(dev, "cmd_state", vfio_hisi_acc, + hisi_acc_vf_debug_cmd); +} + +static void hisi_acc_vf_debugfs_exit(struct hisi_acc_vf_core_device *hisi_acc_vdev) +{ + kfree(hisi_acc_vdev->debug_migf); + hisi_acc_vdev->debug_migf = NULL; +} + static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct hisi_acc_vf_core_device *hisi_acc_vdev; @@ -1398,6 +1599,8 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device ret = vfio_pci_core_register_device(&hisi_acc_vdev->core_device); if (ret) goto out_put_vdev; + + hisi_acc_vfio_debug_init(hisi_acc_vdev); return 0; out_put_vdev: @@ -1410,6 +1613,7 @@ static void hisi_acc_vfio_pci_remove(struct pci_dev *pdev) struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_drvdata(pdev); vfio_pci_core_unregister_device(&hisi_acc_vdev->core_device); + hisi_acc_vf_debugfs_exit(hisi_acc_vdev); vfio_put_device(&hisi_acc_vdev->core_device.vdev); } diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h index 5bab46602fad26..245d7537b2bcd4 100644 --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h @@ -32,6 +32,7 @@ #define QM_SQC_VFT_BASE_MASK_V2 GENMASK(15, 0) #define QM_SQC_VFT_NUM_SHIFT_V2 45 #define QM_SQC_VFT_NUM_MASK_V2 GENMASK(9, 0) +#define QM_MB_CMD_NOT_READY 0xffffffff /* RW regs */ #define QM_REGS_MAX_LEN 7 @@ -99,6 +100,13 @@ struct hisi_acc_vf_migration_file { struct hisi_acc_vf_core_device { struct vfio_pci_core_device core_device; u8 match_done; + /* + * io_base is only valid when dev_opened is true, + * which is protected by open_mutex. + */ + bool dev_opened; + /* Ensure the accuracy of dev_opened operation */ + struct mutex open_mutex; /* For migration state */ struct mutex state_mutex; @@ -107,9 +115,20 @@ struct hisi_acc_vf_core_device { struct pci_dev *vf_dev; struct hisi_qm *pf_qm; struct hisi_qm vf_qm; + /* + * vf_qm_state represents the QM_VF_STATE register value. + * It is set by Guest driver for the ACC VF dev indicating + * the driver has loaded and configured the dev correctly. + */ u32 vf_qm_state; int vf_id; struct hisi_acc_vf_migration_file *resuming_migf; struct hisi_acc_vf_migration_file *saving_migf; + + /* + * It holds migration data corresponding to the last migration + * and is used by the debugfs interface to report it. + */ + struct hisi_acc_vf_migration_file *debug_migf; }; #endif /* HISI_ACC_VFIO_PCI_H */ diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c index 41a4b0cf429756..eb7387ee6ebd10 100644 --- a/drivers/vfio/pci/mlx5/cmd.c +++ b/drivers/vfio/pci/mlx5/cmd.c @@ -423,6 +423,7 @@ static int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf, unsigned long filled; unsigned int to_fill; int ret; + int i; to_fill = min_t(unsigned int, npages, PAGE_SIZE / sizeof(*page_list)); page_list = kvzalloc(to_fill * sizeof(*page_list), GFP_KERNEL_ACCOUNT); @@ -443,7 +444,7 @@ static int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf, GFP_KERNEL_ACCOUNT); if (ret) - goto err; + goto err_append; buf->allocated_length += filled * PAGE_SIZE; /* clean input for another bulk allocation */ memset(page_list, 0, filled * sizeof(*page_list)); @@ -454,6 +455,9 @@ static int mlx5vf_add_migration_pages(struct mlx5_vhca_data_buffer *buf, kvfree(page_list); return 0; +err_append: + for (i = filled - 1; i >= 0; i--) + __free_page(page_list[i]); err: kvfree(page_list); return ret; @@ -1513,7 +1517,8 @@ int mlx5vf_start_page_tracker(struct vfio_device *vdev, struct mlx5_vhca_qp *host_qp; struct mlx5_vhca_qp *fw_qp; struct mlx5_core_dev *mdev; - u32 max_msg_size = PAGE_SIZE; + u32 log_max_msg_size; + u32 max_msg_size; u64 rq_size = SZ_2M; u32 max_recv_wr; int err; @@ -1530,6 +1535,12 @@ int mlx5vf_start_page_tracker(struct vfio_device *vdev, } mdev = mvdev->mdev; + log_max_msg_size = MLX5_CAP_ADV_VIRTUALIZATION(mdev, pg_track_log_max_msg_size); + max_msg_size = (1ULL << log_max_msg_size); + /* The RQ must hold at least 4 WQEs/messages for successful QP creation */ + if (rq_size < 4 * max_msg_size) + rq_size = 4 * max_msg_size; + memset(tracker, 0, sizeof(*tracker)); tracker->uar = mlx5_get_uars_page(mdev); if (IS_ERR(tracker->uar)) { @@ -1619,25 +1630,41 @@ set_report_output(u32 size, int index, struct mlx5_vhca_qp *qp, { u32 entry_size = MLX5_ST_SZ_BYTES(page_track_report_entry); u32 nent = size / entry_size; + u32 nent_in_page; + u32 nent_to_set; struct page *page; + u32 page_offset; + u32 page_index; + u32 buf_offset; + void *kaddr; u64 addr; u64 *buf; int i; - if (WARN_ON(index >= qp->recv_buf.npages || + buf_offset = index * qp->max_msg_size; + if (WARN_ON(buf_offset + size >= qp->recv_buf.npages * PAGE_SIZE || (nent > qp->max_msg_size / entry_size))) return; - page = qp->recv_buf.page_list[index]; - buf = kmap_local_page(page); - for (i = 0; i < nent; i++) { - addr = MLX5_GET(page_track_report_entry, buf + i, - dirty_address_low); - addr |= (u64)MLX5_GET(page_track_report_entry, buf + i, - dirty_address_high) << 32; - iova_bitmap_set(dirty, addr, qp->tracked_page_size); - } - kunmap_local(buf); + do { + page_index = buf_offset / PAGE_SIZE; + page_offset = buf_offset % PAGE_SIZE; + nent_in_page = (PAGE_SIZE - page_offset) / entry_size; + page = qp->recv_buf.page_list[page_index]; + kaddr = kmap_local_page(page); + buf = kaddr + page_offset; + nent_to_set = min(nent, nent_in_page); + for (i = 0; i < nent_to_set; i++) { + addr = MLX5_GET(page_track_report_entry, buf + i, + dirty_address_low); + addr |= (u64)MLX5_GET(page_track_report_entry, buf + i, + dirty_address_high) << 32; + iova_bitmap_set(dirty, addr, qp->tracked_page_size); + } + kunmap_local(kaddr); + buf_offset += (nent_to_set * entry_size); + nent -= nent_to_set; + } while (nent); } static void diff --git a/drivers/vfio/pci/mlx5/main.c b/drivers/vfio/pci/mlx5/main.c index 242c23eef452e8..709543e7eb0428 100644 --- a/drivers/vfio/pci/mlx5/main.c +++ b/drivers/vfio/pci/mlx5/main.c @@ -640,14 +640,11 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track) O_RDONLY); if (IS_ERR(migf->filp)) { ret = PTR_ERR(migf->filp); - goto end; + kfree(migf); + return ERR_PTR(ret); } migf->mvdev = mvdev; - ret = mlx5vf_cmd_alloc_pd(migf); - if (ret) - goto out_free; - stream_open(migf->filp->f_inode, migf->filp); mutex_init(&migf->lock); init_waitqueue_head(&migf->poll_wait); @@ -663,6 +660,11 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track) INIT_LIST_HEAD(&migf->buf_list); INIT_LIST_HEAD(&migf->avail_list); spin_lock_init(&migf->list_lock); + + ret = mlx5vf_cmd_alloc_pd(migf); + if (ret) + goto out; + ret = mlx5vf_cmd_query_vhca_migration_state(mvdev, &length, &full_size, 0); if (ret) goto out_pd; @@ -692,10 +694,8 @@ mlx5vf_pci_save_device_data(struct mlx5vf_pci_core_device *mvdev, bool track) mlx5vf_free_data_buffer(buf); out_pd: mlx5fv_cmd_clean_migf_resources(migf); -out_free: +out: fput(migf->filp); -end: - kfree(migf); return ERR_PTR(ret); } @@ -1016,13 +1016,19 @@ mlx5vf_pci_resume_device_data(struct mlx5vf_pci_core_device *mvdev) O_WRONLY); if (IS_ERR(migf->filp)) { ret = PTR_ERR(migf->filp); - goto end; + kfree(migf); + return ERR_PTR(ret); } + stream_open(migf->filp->f_inode, migf->filp); + mutex_init(&migf->lock); + INIT_LIST_HEAD(&migf->buf_list); + INIT_LIST_HEAD(&migf->avail_list); + spin_lock_init(&migf->list_lock); migf->mvdev = mvdev; ret = mlx5vf_cmd_alloc_pd(migf); if (ret) - goto out_free; + goto out; buf = mlx5vf_alloc_data_buffer(migf, 0, DMA_TO_DEVICE); if (IS_ERR(buf)) { @@ -1041,20 +1047,13 @@ mlx5vf_pci_resume_device_data(struct mlx5vf_pci_core_device *mvdev) migf->buf_header[0] = buf; migf->load_state = MLX5_VF_LOAD_STATE_READ_HEADER; - stream_open(migf->filp->f_inode, migf->filp); - mutex_init(&migf->lock); - INIT_LIST_HEAD(&migf->buf_list); - INIT_LIST_HEAD(&migf->avail_list); - spin_lock_init(&migf->list_lock); return migf; out_buf: mlx5vf_free_data_buffer(migf->buf[0]); out_pd: mlx5vf_cmd_dealloc_pd(migf); -out_free: +out: fput(migf->filp); -end: - kfree(migf); return ERR_PTR(ret); } @@ -1447,7 +1446,7 @@ static struct pci_driver mlx5vf_pci_driver = { module_pci_driver(mlx5vf_pci_driver); -MODULE_IMPORT_NS(IOMMUFD); +MODULE_IMPORT_NS("IOMMUFD"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Max Gurtovoy "); MODULE_AUTHOR("Yishai Hadas "); diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c index a7fd018aa54836..a467085038f0c5 100644 --- a/drivers/vfio/pci/nvgrace-gpu/main.c +++ b/drivers/vfio/pci/nvgrace-gpu/main.c @@ -866,6 +866,8 @@ static const struct pci_device_id nvgrace_gpu_vfio_pci_table[] = { { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_NVIDIA, 0x2342) }, /* GH200 480GB */ { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_NVIDIA, 0x2345) }, + /* GH200 SKU */ + { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_NVIDIA, 0x2348) }, {} }; diff --git a/drivers/vfio/pci/pds/pci_drv.c b/drivers/vfio/pci/pds/pci_drv.c index 16e93b11ab1b0e..4923f182312637 100644 --- a/drivers/vfio/pci/pds/pci_drv.c +++ b/drivers/vfio/pci/pds/pci_drv.c @@ -187,7 +187,7 @@ static struct pci_driver pds_vfio_pci_driver = { module_pci_driver(pds_vfio_pci_driver); -MODULE_IMPORT_NS(IOMMUFD); +MODULE_IMPORT_NS("IOMMUFD"); MODULE_DESCRIPTION(PDS_VFIO_DRV_DESCRIPTION); MODULE_AUTHOR("Brett Creeley "); MODULE_LICENSE("GPL"); diff --git a/drivers/vfio/pci/qat/main.c b/drivers/vfio/pci/qat/main.c index be3644ced17be4..845ed15b67718c 100644 --- a/drivers/vfio/pci/qat/main.c +++ b/drivers/vfio/pci/qat/main.c @@ -304,7 +304,7 @@ static ssize_t qat_vf_resume_write(struct file *filp, const char __user *buf, offs = &filp->f_pos; if (*offs < 0 || - check_add_overflow((loff_t)len, *offs, &end)) + check_add_overflow(len, *offs, &end)) return -EOVERFLOW; if (end > mig_dev->state_size) @@ -697,4 +697,4 @@ module_pci_driver(qat_vf_vfio_pci_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Xin Zeng "); MODULE_DESCRIPTION("QAT VFIO PCI - VFIO PCI driver with live migration support for Intel(R) QAT GEN4 device family"); -MODULE_IMPORT_NS(CRYPTO_QAT); +MODULE_IMPORT_NS("CRYPTO_QAT"); diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 97422aafaa7b5d..ea2745c1ac5e68 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -313,6 +313,10 @@ static int vfio_virt_config_read(struct vfio_pci_core_device *vdev, int pos, return count; } +static struct perm_bits direct_ro_perms = { + .readfn = vfio_direct_config_read, +}; + /* Default capability regions to read-only, no-virtualization */ static struct perm_bits cap_perms[PCI_CAP_ID_MAX + 1] = { [0 ... PCI_CAP_ID_MAX] = { .readfn = vfio_direct_config_read } @@ -1897,9 +1901,17 @@ static ssize_t vfio_config_do_rw(struct vfio_pci_core_device *vdev, char __user cap_start = *ppos; } else { if (*ppos >= PCI_CFG_SPACE_SIZE) { - WARN_ON(cap_id > PCI_EXT_CAP_ID_MAX); + /* + * We can get a cap_id that exceeds PCI_EXT_CAP_ID_MAX + * if we're hiding an unknown capability at the start + * of the extended capability list. Use default, ro + * access, which will virtualize the id and next values. + */ + if (cap_id > PCI_EXT_CAP_ID_MAX) + perm = &direct_ro_perms; + else + perm = &ecap_perms[cap_id]; - perm = &ecap_perms[cap_id]; cap_start = vfio_find_cap_start(vdev, *ppos); } else { WARN_ON(cap_id > PCI_CAP_ID_MAX); diff --git a/drivers/vfio/pci/virtio/Kconfig b/drivers/vfio/pci/virtio/Kconfig index bd80eca4a196c2..2770f7eb702cc2 100644 --- a/drivers/vfio/pci/virtio/Kconfig +++ b/drivers/vfio/pci/virtio/Kconfig @@ -1,15 +1,31 @@ # SPDX-License-Identifier: GPL-2.0-only config VIRTIO_VFIO_PCI - tristate "VFIO support for VIRTIO NET PCI devices" - depends on VIRTIO_PCI && VIRTIO_PCI_ADMIN_LEGACY - select VFIO_PCI_CORE - help - This provides support for exposing VIRTIO NET VF devices which support - legacy IO access, using the VFIO framework that can work with a legacy - virtio driver in the guest. - Based on PCIe spec, VFs do not support I/O Space. - As of that this driver emulates I/O BAR in software to let a VF be - seen as a transitional device by its users and let it work with - a legacy driver. - - If you don't know what to do here, say N. + tristate "VFIO support for VIRTIO NET PCI VF devices" + depends on VIRTIO_PCI + select VFIO_PCI_CORE + help + This provides migration support for VIRTIO NET PCI VF devices + using the VFIO framework. Migration support requires the + SR-IOV PF device to support specific VIRTIO extensions, + otherwise this driver provides no additional functionality + beyond vfio-pci. + + Migration support in this driver relies on dirty page tracking + provided by the IOMMU hardware and exposed through IOMMUFD, any + other use cases are dis-recommended. + + If you don't know what to do here, say N. + +config VIRTIO_VFIO_PCI_ADMIN_LEGACY + bool "Legacy I/O support for VIRTIO NET PCI VF devices" + depends on VIRTIO_VFIO_PCI && VIRTIO_PCI_ADMIN_LEGACY + default y + help + This extends the virtio-vfio-pci driver to support legacy I/O + access, allowing use of legacy virtio drivers with VIRTIO NET + PCI VF devices. Legacy I/O support requires the SR-IOV PF + device to support and enable specific VIRTIO extensions, + otherwise this driver provides no additional functionality + beyond vfio-pci. + + If you don't know what to do here, say N. diff --git a/drivers/vfio/pci/virtio/Makefile b/drivers/vfio/pci/virtio/Makefile index 7171105baf3300..d9b0bb40d6b34c 100644 --- a/drivers/vfio/pci/virtio/Makefile +++ b/drivers/vfio/pci/virtio/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_VIRTIO_VFIO_PCI) += virtio-vfio-pci.o -virtio-vfio-pci-y := main.o +virtio-vfio-pci-y := main.o migrate.o +virtio-vfio-pci-$(CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY) += legacy_io.o diff --git a/drivers/vfio/pci/virtio/common.h b/drivers/vfio/pci/virtio/common.h new file mode 100644 index 00000000000000..c7d7e27af386e9 --- /dev/null +++ b/drivers/vfio/pci/virtio/common.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef VIRTIO_VFIO_COMMON_H +#define VIRTIO_VFIO_COMMON_H + +#include +#include +#include +#include + +enum virtiovf_migf_state { + VIRTIOVF_MIGF_STATE_ERROR = 1, + VIRTIOVF_MIGF_STATE_PRECOPY = 2, + VIRTIOVF_MIGF_STATE_COMPLETE = 3, +}; + +enum virtiovf_load_state { + VIRTIOVF_LOAD_STATE_READ_HEADER, + VIRTIOVF_LOAD_STATE_PREP_HEADER_DATA, + VIRTIOVF_LOAD_STATE_READ_HEADER_DATA, + VIRTIOVF_LOAD_STATE_PREP_CHUNK, + VIRTIOVF_LOAD_STATE_READ_CHUNK, + VIRTIOVF_LOAD_STATE_LOAD_CHUNK, +}; + +struct virtiovf_data_buffer { + struct sg_append_table table; + loff_t start_pos; + u64 length; + u64 allocated_length; + struct list_head buf_elm; + u8 include_header_object:1; + struct virtiovf_migration_file *migf; + /* Optimize virtiovf_get_migration_page() for sequential access */ + struct scatterlist *last_offset_sg; + unsigned int sg_last_entry; + unsigned long last_offset; +}; + +enum virtiovf_migf_header_flags { + VIRTIOVF_MIGF_HEADER_FLAGS_TAG_MANDATORY = 0, + VIRTIOVF_MIGF_HEADER_FLAGS_TAG_OPTIONAL = 1 << 0, +}; + +enum virtiovf_migf_header_tag { + VIRTIOVF_MIGF_HEADER_TAG_DEVICE_DATA = 0, +}; + +struct virtiovf_migration_header { + __le64 record_size; + /* For future use in case we may need to change the kernel protocol */ + __le32 flags; /* Use virtiovf_migf_header_flags */ + __le32 tag; /* Use virtiovf_migf_header_tag */ + __u8 data[]; /* Its size is given in the record_size */ +}; + +struct virtiovf_migration_file { + struct file *filp; + /* synchronize access to the file state */ + struct mutex lock; + loff_t max_pos; + u64 pre_copy_initial_bytes; + struct ratelimit_state pre_copy_rl_state; + u64 record_size; + u32 record_tag; + u8 has_obj_id:1; + u32 obj_id; + enum virtiovf_migf_state state; + enum virtiovf_load_state load_state; + /* synchronize access to the lists */ + spinlock_t list_lock; + struct list_head buf_list; + struct list_head avail_list; + struct virtiovf_data_buffer *buf; + struct virtiovf_data_buffer *buf_header; + struct virtiovf_pci_core_device *virtvdev; +}; + +struct virtiovf_pci_core_device { + struct vfio_pci_core_device core_device; +#ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY + u8 *bar0_virtual_buf; + /* synchronize access to the virtual buf */ + struct mutex bar_mutex; + void __iomem *notify_addr; + u64 notify_offset; + __le32 pci_base_addr_0; + __le16 pci_cmd; + u8 bar0_virtual_buf_size; + u8 notify_bar; +#endif + + /* LM related */ + u8 migrate_cap:1; + u8 deferred_reset:1; + /* protect migration state */ + struct mutex state_mutex; + enum vfio_device_mig_state mig_state; + /* protect the reset_done flow */ + spinlock_t reset_lock; + struct virtiovf_migration_file *resuming_migf; + struct virtiovf_migration_file *saving_migf; +}; + +void virtiovf_set_migratable(struct virtiovf_pci_core_device *virtvdev); +void virtiovf_open_migration(struct virtiovf_pci_core_device *virtvdev); +void virtiovf_close_migration(struct virtiovf_pci_core_device *virtvdev); +void virtiovf_migration_reset_done(struct pci_dev *pdev); + +#ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY +int virtiovf_open_legacy_io(struct virtiovf_pci_core_device *virtvdev); +long virtiovf_vfio_pci_core_ioctl(struct vfio_device *core_vdev, + unsigned int cmd, unsigned long arg); +int virtiovf_pci_ioctl_get_region_info(struct vfio_device *core_vdev, + unsigned int cmd, unsigned long arg); +ssize_t virtiovf_pci_core_write(struct vfio_device *core_vdev, + const char __user *buf, size_t count, + loff_t *ppos); +ssize_t virtiovf_pci_core_read(struct vfio_device *core_vdev, char __user *buf, + size_t count, loff_t *ppos); +bool virtiovf_support_legacy_io(struct pci_dev *pdev); +int virtiovf_init_legacy_io(struct virtiovf_pci_core_device *virtvdev); +void virtiovf_release_legacy_io(struct virtiovf_pci_core_device *virtvdev); +void virtiovf_legacy_io_reset_done(struct pci_dev *pdev); +#endif + +#endif /* VIRTIO_VFIO_COMMON_H */ diff --git a/drivers/vfio/pci/virtio/legacy_io.c b/drivers/vfio/pci/virtio/legacy_io.c new file mode 100644 index 00000000000000..20382ee15faca9 --- /dev/null +++ b/drivers/vfio/pci/virtio/legacy_io.c @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static int +virtiovf_issue_legacy_rw_cmd(struct virtiovf_pci_core_device *virtvdev, + loff_t pos, char __user *buf, + size_t count, bool read) +{ + bool msix_enabled = + (virtvdev->core_device.irq_type == VFIO_PCI_MSIX_IRQ_INDEX); + struct pci_dev *pdev = virtvdev->core_device.pdev; + u8 *bar0_buf = virtvdev->bar0_virtual_buf; + bool common; + u8 offset; + int ret; + + common = pos < VIRTIO_PCI_CONFIG_OFF(msix_enabled); + /* offset within the relevant configuration area */ + offset = common ? pos : pos - VIRTIO_PCI_CONFIG_OFF(msix_enabled); + mutex_lock(&virtvdev->bar_mutex); + if (read) { + if (common) + ret = virtio_pci_admin_legacy_common_io_read(pdev, offset, + count, bar0_buf + pos); + else + ret = virtio_pci_admin_legacy_device_io_read(pdev, offset, + count, bar0_buf + pos); + if (ret) + goto out; + if (copy_to_user(buf, bar0_buf + pos, count)) + ret = -EFAULT; + } else { + if (copy_from_user(bar0_buf + pos, buf, count)) { + ret = -EFAULT; + goto out; + } + + if (common) + ret = virtio_pci_admin_legacy_common_io_write(pdev, offset, + count, bar0_buf + pos); + else + ret = virtio_pci_admin_legacy_device_io_write(pdev, offset, + count, bar0_buf + pos); + } +out: + mutex_unlock(&virtvdev->bar_mutex); + return ret; +} + +static int +virtiovf_pci_bar0_rw(struct virtiovf_pci_core_device *virtvdev, + loff_t pos, char __user *buf, + size_t count, bool read) +{ + struct vfio_pci_core_device *core_device = &virtvdev->core_device; + struct pci_dev *pdev = core_device->pdev; + u16 queue_notify; + int ret; + + if (!(le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO)) + return -EIO; + + if (pos + count > virtvdev->bar0_virtual_buf_size) + return -EINVAL; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) { + pci_info_ratelimited(pdev, "runtime resume failed %d\n", ret); + return -EIO; + } + + switch (pos) { + case VIRTIO_PCI_QUEUE_NOTIFY: + if (count != sizeof(queue_notify)) { + ret = -EINVAL; + goto end; + } + if (read) { + ret = vfio_pci_core_ioread16(core_device, true, &queue_notify, + virtvdev->notify_addr); + if (ret) + goto end; + if (copy_to_user(buf, &queue_notify, + sizeof(queue_notify))) { + ret = -EFAULT; + goto end; + } + } else { + if (copy_from_user(&queue_notify, buf, count)) { + ret = -EFAULT; + goto end; + } + ret = vfio_pci_core_iowrite16(core_device, true, queue_notify, + virtvdev->notify_addr); + } + break; + default: + ret = virtiovf_issue_legacy_rw_cmd(virtvdev, pos, buf, count, + read); + } + +end: + pm_runtime_put(&pdev->dev); + return ret ? ret : count; +} + +static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, + char __user *buf, size_t count, + loff_t *ppos) +{ + struct virtiovf_pci_core_device *virtvdev = container_of( + core_vdev, struct virtiovf_pci_core_device, core_device.vdev); + loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; + size_t register_offset; + loff_t copy_offset; + size_t copy_count; + __le32 val32; + __le16 val16; + u8 val8; + int ret; + + ret = vfio_pci_core_read(core_vdev, buf, count, ppos); + if (ret < 0) + return ret; + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_DEVICE_ID, + sizeof(val16), ©_offset, + ©_count, ®ister_offset)) { + val16 = cpu_to_le16(VIRTIO_TRANS_ID_NET); + if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count)) + return -EFAULT; + } + + if ((le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO) && + vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND, + sizeof(val16), ©_offset, + ©_count, ®ister_offset)) { + if (copy_from_user((void *)&val16 + register_offset, buf + copy_offset, + copy_count)) + return -EFAULT; + val16 |= cpu_to_le16(PCI_COMMAND_IO); + if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, + copy_count)) + return -EFAULT; + } + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_REVISION_ID, + sizeof(val8), ©_offset, + ©_count, ®ister_offset)) { + /* Transional needs to have revision 0 */ + val8 = 0; + if (copy_to_user(buf + copy_offset, &val8, copy_count)) + return -EFAULT; + } + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, + sizeof(val32), ©_offset, + ©_count, ®ister_offset)) { + u32 bar_mask = ~(virtvdev->bar0_virtual_buf_size - 1); + u32 pci_base_addr_0 = le32_to_cpu(virtvdev->pci_base_addr_0); + + val32 = cpu_to_le32((pci_base_addr_0 & bar_mask) | PCI_BASE_ADDRESS_SPACE_IO); + if (copy_to_user(buf + copy_offset, (void *)&val32 + register_offset, copy_count)) + return -EFAULT; + } + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_ID, + sizeof(val16), ©_offset, + ©_count, ®ister_offset)) { + /* + * Transitional devices use the PCI subsystem device id as + * virtio device id, same as legacy driver always did. + */ + val16 = cpu_to_le16(VIRTIO_ID_NET); + if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, + copy_count)) + return -EFAULT; + } + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID, + sizeof(val16), ©_offset, + ©_count, ®ister_offset)) { + val16 = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET); + if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, + copy_count)) + return -EFAULT; + } + + return count; +} + +ssize_t virtiovf_pci_core_read(struct vfio_device *core_vdev, char __user *buf, + size_t count, loff_t *ppos) +{ + struct virtiovf_pci_core_device *virtvdev = container_of( + core_vdev, struct virtiovf_pci_core_device, core_device.vdev); + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; + + if (!count) + return 0; + + if (index == VFIO_PCI_CONFIG_REGION_INDEX) + return virtiovf_pci_read_config(core_vdev, buf, count, ppos); + + if (index == VFIO_PCI_BAR0_REGION_INDEX) + return virtiovf_pci_bar0_rw(virtvdev, pos, buf, count, true); + + return vfio_pci_core_read(core_vdev, buf, count, ppos); +} + +static ssize_t virtiovf_pci_write_config(struct vfio_device *core_vdev, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct virtiovf_pci_core_device *virtvdev = container_of( + core_vdev, struct virtiovf_pci_core_device, core_device.vdev); + loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; + size_t register_offset; + loff_t copy_offset; + size_t copy_count; + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND, + sizeof(virtvdev->pci_cmd), + ©_offset, ©_count, + ®ister_offset)) { + if (copy_from_user((void *)&virtvdev->pci_cmd + register_offset, + buf + copy_offset, + copy_count)) + return -EFAULT; + } + + if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, + sizeof(virtvdev->pci_base_addr_0), + ©_offset, ©_count, + ®ister_offset)) { + if (copy_from_user((void *)&virtvdev->pci_base_addr_0 + register_offset, + buf + copy_offset, + copy_count)) + return -EFAULT; + } + + return vfio_pci_core_write(core_vdev, buf, count, ppos); +} + +ssize_t virtiovf_pci_core_write(struct vfio_device *core_vdev, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct virtiovf_pci_core_device *virtvdev = container_of( + core_vdev, struct virtiovf_pci_core_device, core_device.vdev); + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; + + if (!count) + return 0; + + if (index == VFIO_PCI_CONFIG_REGION_INDEX) + return virtiovf_pci_write_config(core_vdev, buf, count, ppos); + + if (index == VFIO_PCI_BAR0_REGION_INDEX) + return virtiovf_pci_bar0_rw(virtvdev, pos, (char __user *)buf, count, false); + + return vfio_pci_core_write(core_vdev, buf, count, ppos); +} + +int virtiovf_pci_ioctl_get_region_info(struct vfio_device *core_vdev, + unsigned int cmd, unsigned long arg) +{ + struct virtiovf_pci_core_device *virtvdev = container_of( + core_vdev, struct virtiovf_pci_core_device, core_device.vdev); + unsigned long minsz = offsetofend(struct vfio_region_info, offset); + void __user *uarg = (void __user *)arg; + struct vfio_region_info info = {}; + + if (copy_from_user(&info, uarg, minsz)) + return -EFAULT; + + if (info.argsz < minsz) + return -EINVAL; + + switch (info.index) { + case VFIO_PCI_BAR0_REGION_INDEX: + info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); + info.size = virtvdev->bar0_virtual_buf_size; + info.flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE; + return copy_to_user(uarg, &info, minsz) ? -EFAULT : 0; + default: + return vfio_pci_core_ioctl(core_vdev, cmd, arg); + } +} + +long virtiovf_vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case VFIO_DEVICE_GET_REGION_INFO: + return virtiovf_pci_ioctl_get_region_info(core_vdev, cmd, arg); + default: + return vfio_pci_core_ioctl(core_vdev, cmd, arg); + } +} + +static int virtiovf_set_notify_addr(struct virtiovf_pci_core_device *virtvdev) +{ + struct vfio_pci_core_device *core_device = &virtvdev->core_device; + int ret; + + /* + * Setup the BAR where the 'notify' exists to be used by vfio as well + * This will let us mmap it only once and use it when needed. + */ + ret = vfio_pci_core_setup_barmap(core_device, + virtvdev->notify_bar); + if (ret) + return ret; + + virtvdev->notify_addr = core_device->barmap[virtvdev->notify_bar] + + virtvdev->notify_offset; + return 0; +} + +int virtiovf_open_legacy_io(struct virtiovf_pci_core_device *virtvdev) +{ + if (!virtvdev->bar0_virtual_buf) + return 0; + + /* + * Upon close_device() the vfio_pci_core_disable() is called + * and will close all the previous mmaps, so it seems that the + * valid life cycle for the 'notify' addr is per open/close. + */ + return virtiovf_set_notify_addr(virtvdev); +} + +static int virtiovf_get_device_config_size(unsigned short device) +{ + /* Network card */ + return offsetofend(struct virtio_net_config, status); +} + +static int virtiovf_read_notify_info(struct virtiovf_pci_core_device *virtvdev) +{ + u64 offset; + int ret; + u8 bar; + + ret = virtio_pci_admin_legacy_io_notify_info(virtvdev->core_device.pdev, + VIRTIO_ADMIN_CMD_NOTIFY_INFO_FLAGS_OWNER_MEM, + &bar, &offset); + if (ret) + return ret; + + virtvdev->notify_bar = bar; + virtvdev->notify_offset = offset; + return 0; +} + +static bool virtiovf_bar0_exists(struct pci_dev *pdev) +{ + struct resource *res = pdev->resource; + + return res->flags; +} + +bool virtiovf_support_legacy_io(struct pci_dev *pdev) +{ + return virtio_pci_admin_has_legacy_io(pdev) && !virtiovf_bar0_exists(pdev); +} + +int virtiovf_init_legacy_io(struct virtiovf_pci_core_device *virtvdev) +{ + struct pci_dev *pdev = virtvdev->core_device.pdev; + int ret; + + ret = virtiovf_read_notify_info(virtvdev); + if (ret) + return ret; + + virtvdev->bar0_virtual_buf_size = VIRTIO_PCI_CONFIG_OFF(true) + + virtiovf_get_device_config_size(pdev->device); + BUILD_BUG_ON(!is_power_of_2(virtvdev->bar0_virtual_buf_size)); + virtvdev->bar0_virtual_buf = kzalloc(virtvdev->bar0_virtual_buf_size, + GFP_KERNEL); + if (!virtvdev->bar0_virtual_buf) + return -ENOMEM; + mutex_init(&virtvdev->bar_mutex); + return 0; +} + +void virtiovf_release_legacy_io(struct virtiovf_pci_core_device *virtvdev) +{ + kfree(virtvdev->bar0_virtual_buf); +} + +void virtiovf_legacy_io_reset_done(struct pci_dev *pdev) +{ + struct virtiovf_pci_core_device *virtvdev = dev_get_drvdata(&pdev->dev); + + virtvdev->pci_cmd = 0; +} diff --git a/drivers/vfio/pci/virtio/main.c b/drivers/vfio/pci/virtio/main.c index b5d3a8c5bbc9aa..d534d48c416337 100644 --- a/drivers/vfio/pci/virtio/main.c +++ b/drivers/vfio/pci/virtio/main.c @@ -16,347 +16,12 @@ #include #include -struct virtiovf_pci_core_device { - struct vfio_pci_core_device core_device; - u8 *bar0_virtual_buf; - /* synchronize access to the virtual buf */ - struct mutex bar_mutex; - void __iomem *notify_addr; - u64 notify_offset; - __le32 pci_base_addr_0; - __le16 pci_cmd; - u8 bar0_virtual_buf_size; - u8 notify_bar; -}; - -static int -virtiovf_issue_legacy_rw_cmd(struct virtiovf_pci_core_device *virtvdev, - loff_t pos, char __user *buf, - size_t count, bool read) -{ - bool msix_enabled = - (virtvdev->core_device.irq_type == VFIO_PCI_MSIX_IRQ_INDEX); - struct pci_dev *pdev = virtvdev->core_device.pdev; - u8 *bar0_buf = virtvdev->bar0_virtual_buf; - bool common; - u8 offset; - int ret; - - common = pos < VIRTIO_PCI_CONFIG_OFF(msix_enabled); - /* offset within the relevant configuration area */ - offset = common ? pos : pos - VIRTIO_PCI_CONFIG_OFF(msix_enabled); - mutex_lock(&virtvdev->bar_mutex); - if (read) { - if (common) - ret = virtio_pci_admin_legacy_common_io_read(pdev, offset, - count, bar0_buf + pos); - else - ret = virtio_pci_admin_legacy_device_io_read(pdev, offset, - count, bar0_buf + pos); - if (ret) - goto out; - if (copy_to_user(buf, bar0_buf + pos, count)) - ret = -EFAULT; - } else { - if (copy_from_user(bar0_buf + pos, buf, count)) { - ret = -EFAULT; - goto out; - } - - if (common) - ret = virtio_pci_admin_legacy_common_io_write(pdev, offset, - count, bar0_buf + pos); - else - ret = virtio_pci_admin_legacy_device_io_write(pdev, offset, - count, bar0_buf + pos); - } -out: - mutex_unlock(&virtvdev->bar_mutex); - return ret; -} - -static int -virtiovf_pci_bar0_rw(struct virtiovf_pci_core_device *virtvdev, - loff_t pos, char __user *buf, - size_t count, bool read) -{ - struct vfio_pci_core_device *core_device = &virtvdev->core_device; - struct pci_dev *pdev = core_device->pdev; - u16 queue_notify; - int ret; - - if (!(le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO)) - return -EIO; - - if (pos + count > virtvdev->bar0_virtual_buf_size) - return -EINVAL; - - ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret) { - pci_info_ratelimited(pdev, "runtime resume failed %d\n", ret); - return -EIO; - } - - switch (pos) { - case VIRTIO_PCI_QUEUE_NOTIFY: - if (count != sizeof(queue_notify)) { - ret = -EINVAL; - goto end; - } - if (read) { - ret = vfio_pci_core_ioread16(core_device, true, &queue_notify, - virtvdev->notify_addr); - if (ret) - goto end; - if (copy_to_user(buf, &queue_notify, - sizeof(queue_notify))) { - ret = -EFAULT; - goto end; - } - } else { - if (copy_from_user(&queue_notify, buf, count)) { - ret = -EFAULT; - goto end; - } - ret = vfio_pci_core_iowrite16(core_device, true, queue_notify, - virtvdev->notify_addr); - } - break; - default: - ret = virtiovf_issue_legacy_rw_cmd(virtvdev, pos, buf, count, - read); - } - -end: - pm_runtime_put(&pdev->dev); - return ret ? ret : count; -} - -static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev, - char __user *buf, size_t count, - loff_t *ppos) -{ - struct virtiovf_pci_core_device *virtvdev = container_of( - core_vdev, struct virtiovf_pci_core_device, core_device.vdev); - loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; - size_t register_offset; - loff_t copy_offset; - size_t copy_count; - __le32 val32; - __le16 val16; - u8 val8; - int ret; - - ret = vfio_pci_core_read(core_vdev, buf, count, ppos); - if (ret < 0) - return ret; - - if (vfio_pci_core_range_intersect_range(pos, count, PCI_DEVICE_ID, - sizeof(val16), ©_offset, - ©_count, ®ister_offset)) { - val16 = cpu_to_le16(VIRTIO_TRANS_ID_NET); - if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count)) - return -EFAULT; - } - - if ((le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO) && - vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND, - sizeof(val16), ©_offset, - ©_count, ®ister_offset)) { - if (copy_from_user((void *)&val16 + register_offset, buf + copy_offset, - copy_count)) - return -EFAULT; - val16 |= cpu_to_le16(PCI_COMMAND_IO); - if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, - copy_count)) - return -EFAULT; - } - - if (vfio_pci_core_range_intersect_range(pos, count, PCI_REVISION_ID, - sizeof(val8), ©_offset, - ©_count, ®ister_offset)) { - /* Transional needs to have revision 0 */ - val8 = 0; - if (copy_to_user(buf + copy_offset, &val8, copy_count)) - return -EFAULT; - } - - if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, - sizeof(val32), ©_offset, - ©_count, ®ister_offset)) { - u32 bar_mask = ~(virtvdev->bar0_virtual_buf_size - 1); - u32 pci_base_addr_0 = le32_to_cpu(virtvdev->pci_base_addr_0); - - val32 = cpu_to_le32((pci_base_addr_0 & bar_mask) | PCI_BASE_ADDRESS_SPACE_IO); - if (copy_to_user(buf + copy_offset, (void *)&val32 + register_offset, copy_count)) - return -EFAULT; - } - - if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_ID, - sizeof(val16), ©_offset, - ©_count, ®ister_offset)) { - /* - * Transitional devices use the PCI subsystem device id as - * virtio device id, same as legacy driver always did. - */ - val16 = cpu_to_le16(VIRTIO_ID_NET); - if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, - copy_count)) - return -EFAULT; - } - - if (vfio_pci_core_range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID, - sizeof(val16), ©_offset, - ©_count, ®ister_offset)) { - val16 = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET); - if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, - copy_count)) - return -EFAULT; - } - - return count; -} - -static ssize_t -virtiovf_pci_core_read(struct vfio_device *core_vdev, char __user *buf, - size_t count, loff_t *ppos) -{ - struct virtiovf_pci_core_device *virtvdev = container_of( - core_vdev, struct virtiovf_pci_core_device, core_device.vdev); - unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); - loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; - - if (!count) - return 0; - - if (index == VFIO_PCI_CONFIG_REGION_INDEX) - return virtiovf_pci_read_config(core_vdev, buf, count, ppos); - - if (index == VFIO_PCI_BAR0_REGION_INDEX) - return virtiovf_pci_bar0_rw(virtvdev, pos, buf, count, true); - - return vfio_pci_core_read(core_vdev, buf, count, ppos); -} - -static ssize_t virtiovf_pci_write_config(struct vfio_device *core_vdev, - const char __user *buf, size_t count, - loff_t *ppos) -{ - struct virtiovf_pci_core_device *virtvdev = container_of( - core_vdev, struct virtiovf_pci_core_device, core_device.vdev); - loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; - size_t register_offset; - loff_t copy_offset; - size_t copy_count; - - if (vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND, - sizeof(virtvdev->pci_cmd), - ©_offset, ©_count, - ®ister_offset)) { - if (copy_from_user((void *)&virtvdev->pci_cmd + register_offset, - buf + copy_offset, - copy_count)) - return -EFAULT; - } - - if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, - sizeof(virtvdev->pci_base_addr_0), - ©_offset, ©_count, - ®ister_offset)) { - if (copy_from_user((void *)&virtvdev->pci_base_addr_0 + register_offset, - buf + copy_offset, - copy_count)) - return -EFAULT; - } - - return vfio_pci_core_write(core_vdev, buf, count, ppos); -} - -static ssize_t -virtiovf_pci_core_write(struct vfio_device *core_vdev, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct virtiovf_pci_core_device *virtvdev = container_of( - core_vdev, struct virtiovf_pci_core_device, core_device.vdev); - unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); - loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; - - if (!count) - return 0; - - if (index == VFIO_PCI_CONFIG_REGION_INDEX) - return virtiovf_pci_write_config(core_vdev, buf, count, ppos); - - if (index == VFIO_PCI_BAR0_REGION_INDEX) - return virtiovf_pci_bar0_rw(virtvdev, pos, (char __user *)buf, count, false); - - return vfio_pci_core_write(core_vdev, buf, count, ppos); -} - -static int -virtiovf_pci_ioctl_get_region_info(struct vfio_device *core_vdev, - unsigned int cmd, unsigned long arg) -{ - struct virtiovf_pci_core_device *virtvdev = container_of( - core_vdev, struct virtiovf_pci_core_device, core_device.vdev); - unsigned long minsz = offsetofend(struct vfio_region_info, offset); - void __user *uarg = (void __user *)arg; - struct vfio_region_info info = {}; - - if (copy_from_user(&info, uarg, minsz)) - return -EFAULT; - - if (info.argsz < minsz) - return -EINVAL; - - switch (info.index) { - case VFIO_PCI_BAR0_REGION_INDEX: - info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); - info.size = virtvdev->bar0_virtual_buf_size; - info.flags = VFIO_REGION_INFO_FLAG_READ | - VFIO_REGION_INFO_FLAG_WRITE; - return copy_to_user(uarg, &info, minsz) ? -EFAULT : 0; - default: - return vfio_pci_core_ioctl(core_vdev, cmd, arg); - } -} - -static long -virtiovf_vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd, - unsigned long arg) -{ - switch (cmd) { - case VFIO_DEVICE_GET_REGION_INFO: - return virtiovf_pci_ioctl_get_region_info(core_vdev, cmd, arg); - default: - return vfio_pci_core_ioctl(core_vdev, cmd, arg); - } -} - -static int -virtiovf_set_notify_addr(struct virtiovf_pci_core_device *virtvdev) -{ - struct vfio_pci_core_device *core_device = &virtvdev->core_device; - int ret; - - /* - * Setup the BAR where the 'notify' exists to be used by vfio as well - * This will let us mmap it only once and use it when needed. - */ - ret = vfio_pci_core_setup_barmap(core_device, - virtvdev->notify_bar); - if (ret) - return ret; - - virtvdev->notify_addr = core_device->barmap[virtvdev->notify_bar] + - virtvdev->notify_offset; - return 0; -} +#include "common.h" static int virtiovf_pci_open_device(struct vfio_device *core_vdev) { - struct virtiovf_pci_core_device *virtvdev = container_of( - core_vdev, struct virtiovf_pci_core_device, core_device.vdev); + struct virtiovf_pci_core_device *virtvdev = container_of(core_vdev, + struct virtiovf_pci_core_device, core_device.vdev); struct vfio_pci_core_device *vdev = &virtvdev->core_device; int ret; @@ -364,88 +29,84 @@ static int virtiovf_pci_open_device(struct vfio_device *core_vdev) if (ret) return ret; - if (virtvdev->bar0_virtual_buf) { - /* - * Upon close_device() the vfio_pci_core_disable() is called - * and will close all the previous mmaps, so it seems that the - * valid life cycle for the 'notify' addr is per open/close. - */ - ret = virtiovf_set_notify_addr(virtvdev); - if (ret) { - vfio_pci_core_disable(vdev); - return ret; - } +#ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY + ret = virtiovf_open_legacy_io(virtvdev); + if (ret) { + vfio_pci_core_disable(vdev); + return ret; } +#endif + virtiovf_open_migration(virtvdev); vfio_pci_core_finish_enable(vdev); return 0; } -static int virtiovf_get_device_config_size(unsigned short device) +static void virtiovf_pci_close_device(struct vfio_device *core_vdev) { - /* Network card */ - return offsetofend(struct virtio_net_config, status); -} - -static int virtiovf_read_notify_info(struct virtiovf_pci_core_device *virtvdev) -{ - u64 offset; - int ret; - u8 bar; + struct virtiovf_pci_core_device *virtvdev = container_of(core_vdev, + struct virtiovf_pci_core_device, core_device.vdev); - ret = virtio_pci_admin_legacy_io_notify_info(virtvdev->core_device.pdev, - VIRTIO_ADMIN_CMD_NOTIFY_INFO_FLAGS_OWNER_MEM, - &bar, &offset); - if (ret) - return ret; - - virtvdev->notify_bar = bar; - virtvdev->notify_offset = offset; - return 0; + virtiovf_close_migration(virtvdev); + vfio_pci_core_close_device(core_vdev); } +#ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY static int virtiovf_pci_init_device(struct vfio_device *core_vdev) { - struct virtiovf_pci_core_device *virtvdev = container_of( - core_vdev, struct virtiovf_pci_core_device, core_device.vdev); - struct pci_dev *pdev; + struct virtiovf_pci_core_device *virtvdev = container_of(core_vdev, + struct virtiovf_pci_core_device, core_device.vdev); int ret; ret = vfio_pci_core_init_dev(core_vdev); if (ret) return ret; - pdev = virtvdev->core_device.pdev; - ret = virtiovf_read_notify_info(virtvdev); - if (ret) - return ret; - - virtvdev->bar0_virtual_buf_size = VIRTIO_PCI_CONFIG_OFF(true) + - virtiovf_get_device_config_size(pdev->device); - BUILD_BUG_ON(!is_power_of_2(virtvdev->bar0_virtual_buf_size)); - virtvdev->bar0_virtual_buf = kzalloc(virtvdev->bar0_virtual_buf_size, - GFP_KERNEL); - if (!virtvdev->bar0_virtual_buf) - return -ENOMEM; - mutex_init(&virtvdev->bar_mutex); - return 0; + /* + * The vfio_device_ops.init() callback is set to virtiovf_pci_init_device() + * only when legacy I/O is supported. Now, let's initialize it. + */ + return virtiovf_init_legacy_io(virtvdev); } +#endif static void virtiovf_pci_core_release_dev(struct vfio_device *core_vdev) { - struct virtiovf_pci_core_device *virtvdev = container_of( - core_vdev, struct virtiovf_pci_core_device, core_device.vdev); +#ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY + struct virtiovf_pci_core_device *virtvdev = container_of(core_vdev, + struct virtiovf_pci_core_device, core_device.vdev); - kfree(virtvdev->bar0_virtual_buf); + virtiovf_release_legacy_io(virtvdev); +#endif vfio_pci_core_release_dev(core_vdev); } -static const struct vfio_device_ops virtiovf_vfio_pci_tran_ops = { - .name = "virtio-vfio-pci-trans", +static const struct vfio_device_ops virtiovf_vfio_pci_lm_ops = { + .name = "virtio-vfio-pci-lm", + .init = vfio_pci_core_init_dev, + .release = virtiovf_pci_core_release_dev, + .open_device = virtiovf_pci_open_device, + .close_device = virtiovf_pci_close_device, + .ioctl = vfio_pci_core_ioctl, + .device_feature = vfio_pci_core_ioctl_feature, + .read = vfio_pci_core_read, + .write = vfio_pci_core_write, + .mmap = vfio_pci_core_mmap, + .request = vfio_pci_core_request, + .match = vfio_pci_core_match, + .bind_iommufd = vfio_iommufd_physical_bind, + .unbind_iommufd = vfio_iommufd_physical_unbind, + .attach_ioas = vfio_iommufd_physical_attach_ioas, + .detach_ioas = vfio_iommufd_physical_detach_ioas, +}; + +#ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY +static const struct vfio_device_ops virtiovf_vfio_pci_tran_lm_ops = { + .name = "virtio-vfio-pci-trans-lm", .init = virtiovf_pci_init_device, .release = virtiovf_pci_core_release_dev, .open_device = virtiovf_pci_open_device, - .close_device = vfio_pci_core_close_device, + .close_device = virtiovf_pci_close_device, .ioctl = virtiovf_vfio_pci_core_ioctl, .device_feature = vfio_pci_core_ioctl_feature, .read = virtiovf_pci_core_read, @@ -458,6 +119,7 @@ static const struct vfio_device_ops virtiovf_vfio_pci_tran_ops = { .attach_ioas = vfio_iommufd_physical_attach_ioas, .detach_ioas = vfio_iommufd_physical_detach_ioas, }; +#endif static const struct vfio_device_ops virtiovf_vfio_pci_ops = { .name = "virtio-vfio-pci", @@ -478,29 +140,34 @@ static const struct vfio_device_ops virtiovf_vfio_pci_ops = { .detach_ioas = vfio_iommufd_physical_detach_ioas, }; -static bool virtiovf_bar0_exists(struct pci_dev *pdev) -{ - struct resource *res = pdev->resource; - - return res->flags; -} - static int virtiovf_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { const struct vfio_device_ops *ops = &virtiovf_vfio_pci_ops; struct virtiovf_pci_core_device *virtvdev; + bool sup_legacy_io = false; + bool sup_lm = false; int ret; - if (pdev->is_virtfn && virtio_pci_admin_has_legacy_io(pdev) && - !virtiovf_bar0_exists(pdev)) - ops = &virtiovf_vfio_pci_tran_ops; + if (pdev->is_virtfn) { +#ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY + sup_legacy_io = virtiovf_support_legacy_io(pdev); + if (sup_legacy_io) + ops = &virtiovf_vfio_pci_tran_lm_ops; +#endif + sup_lm = virtio_pci_admin_has_dev_parts(pdev); + if (sup_lm && !sup_legacy_io) + ops = &virtiovf_vfio_pci_lm_ops; + } virtvdev = vfio_alloc_device(virtiovf_pci_core_device, core_device.vdev, &pdev->dev, ops); if (IS_ERR(virtvdev)) return PTR_ERR(virtvdev); + if (sup_lm) + virtiovf_set_migratable(virtvdev); + dev_set_drvdata(&pdev->dev, &virtvdev->core_device); ret = vfio_pci_core_register_device(&virtvdev->core_device); if (ret) @@ -529,9 +196,10 @@ MODULE_DEVICE_TABLE(pci, virtiovf_pci_table); static void virtiovf_pci_aer_reset_done(struct pci_dev *pdev) { - struct virtiovf_pci_core_device *virtvdev = dev_get_drvdata(&pdev->dev); - - virtvdev->pci_cmd = 0; +#ifdef CONFIG_VIRTIO_VFIO_PCI_ADMIN_LEGACY + virtiovf_legacy_io_reset_done(pdev); +#endif + virtiovf_migration_reset_done(pdev); } static const struct pci_error_handlers virtiovf_err_handlers = { diff --git a/drivers/vfio/pci/virtio/migrate.c b/drivers/vfio/pci/virtio/migrate.c new file mode 100644 index 00000000000000..ee54f4c1785771 --- /dev/null +++ b/drivers/vfio/pci/virtio/migrate.c @@ -0,0 +1,1337 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* Device specification max parts size */ +#define MAX_LOAD_SIZE (BIT_ULL(BITS_PER_TYPE \ + (((struct virtio_admin_cmd_dev_parts_metadata_result *)0)->parts_size.size)) - 1) + +/* Initial target buffer size */ +#define VIRTIOVF_TARGET_INITIAL_BUF_SIZE SZ_1M + +static int +virtiovf_read_device_context_chunk(struct virtiovf_migration_file *migf, + u32 ctx_size); + +static struct page * +virtiovf_get_migration_page(struct virtiovf_data_buffer *buf, + unsigned long offset) +{ + unsigned long cur_offset = 0; + struct scatterlist *sg; + unsigned int i; + + /* All accesses are sequential */ + if (offset < buf->last_offset || !buf->last_offset_sg) { + buf->last_offset = 0; + buf->last_offset_sg = buf->table.sgt.sgl; + buf->sg_last_entry = 0; + } + + cur_offset = buf->last_offset; + + for_each_sg(buf->last_offset_sg, sg, + buf->table.sgt.orig_nents - buf->sg_last_entry, i) { + if (offset < sg->length + cur_offset) { + buf->last_offset_sg = sg; + buf->sg_last_entry += i; + buf->last_offset = cur_offset; + return nth_page(sg_page(sg), + (offset - cur_offset) / PAGE_SIZE); + } + cur_offset += sg->length; + } + return NULL; +} + +static int virtiovf_add_migration_pages(struct virtiovf_data_buffer *buf, + unsigned int npages) +{ + unsigned int to_alloc = npages; + struct page **page_list; + unsigned long filled; + unsigned int to_fill; + int ret; + int i; + + to_fill = min_t(unsigned int, npages, PAGE_SIZE / sizeof(*page_list)); + page_list = kvcalloc(to_fill, sizeof(*page_list), GFP_KERNEL_ACCOUNT); + if (!page_list) + return -ENOMEM; + + do { + filled = alloc_pages_bulk_array(GFP_KERNEL_ACCOUNT, to_fill, + page_list); + if (!filled) { + ret = -ENOMEM; + goto err; + } + to_alloc -= filled; + ret = sg_alloc_append_table_from_pages(&buf->table, page_list, + filled, 0, filled << PAGE_SHIFT, UINT_MAX, + SG_MAX_SINGLE_ALLOC, GFP_KERNEL_ACCOUNT); + + if (ret) + goto err_append; + buf->allocated_length += filled * PAGE_SIZE; + /* clean input for another bulk allocation */ + memset(page_list, 0, filled * sizeof(*page_list)); + to_fill = min_t(unsigned int, to_alloc, + PAGE_SIZE / sizeof(*page_list)); + } while (to_alloc > 0); + + kvfree(page_list); + return 0; + +err_append: + for (i = filled - 1; i >= 0; i--) + __free_page(page_list[i]); +err: + kvfree(page_list); + return ret; +} + +static void virtiovf_free_data_buffer(struct virtiovf_data_buffer *buf) +{ + struct sg_page_iter sg_iter; + + /* Undo alloc_pages_bulk_array() */ + for_each_sgtable_page(&buf->table.sgt, &sg_iter, 0) + __free_page(sg_page_iter_page(&sg_iter)); + sg_free_append_table(&buf->table); + kfree(buf); +} + +static struct virtiovf_data_buffer * +virtiovf_alloc_data_buffer(struct virtiovf_migration_file *migf, size_t length) +{ + struct virtiovf_data_buffer *buf; + int ret; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL_ACCOUNT); + if (!buf) + return ERR_PTR(-ENOMEM); + + ret = virtiovf_add_migration_pages(buf, + DIV_ROUND_UP_ULL(length, PAGE_SIZE)); + if (ret) + goto end; + + buf->migf = migf; + return buf; +end: + virtiovf_free_data_buffer(buf); + return ERR_PTR(ret); +} + +static void virtiovf_put_data_buffer(struct virtiovf_data_buffer *buf) +{ + spin_lock_irq(&buf->migf->list_lock); + list_add_tail(&buf->buf_elm, &buf->migf->avail_list); + spin_unlock_irq(&buf->migf->list_lock); +} + +static int +virtiovf_pci_alloc_obj_id(struct virtiovf_pci_core_device *virtvdev, u8 type, + u32 *obj_id) +{ + return virtio_pci_admin_obj_create(virtvdev->core_device.pdev, + VIRTIO_RESOURCE_OBJ_DEV_PARTS, type, obj_id); +} + +static void +virtiovf_pci_free_obj_id(struct virtiovf_pci_core_device *virtvdev, u32 obj_id) +{ + virtio_pci_admin_obj_destroy(virtvdev->core_device.pdev, + VIRTIO_RESOURCE_OBJ_DEV_PARTS, obj_id); +} + +static struct virtiovf_data_buffer * +virtiovf_get_data_buffer(struct virtiovf_migration_file *migf, size_t length) +{ + struct virtiovf_data_buffer *buf, *temp_buf; + struct list_head free_list; + + INIT_LIST_HEAD(&free_list); + + spin_lock_irq(&migf->list_lock); + list_for_each_entry_safe(buf, temp_buf, &migf->avail_list, buf_elm) { + list_del_init(&buf->buf_elm); + if (buf->allocated_length >= length) { + spin_unlock_irq(&migf->list_lock); + goto found; + } + /* + * Prevent holding redundant buffers. Put in a free + * list and call at the end not under the spin lock + * (&migf->list_lock) to minimize its scope usage. + */ + list_add(&buf->buf_elm, &free_list); + } + spin_unlock_irq(&migf->list_lock); + buf = virtiovf_alloc_data_buffer(migf, length); + +found: + while ((temp_buf = list_first_entry_or_null(&free_list, + struct virtiovf_data_buffer, buf_elm))) { + list_del(&temp_buf->buf_elm); + virtiovf_free_data_buffer(temp_buf); + } + + return buf; +} + +static void virtiovf_clean_migf_resources(struct virtiovf_migration_file *migf) +{ + struct virtiovf_data_buffer *entry; + + if (migf->buf) { + virtiovf_free_data_buffer(migf->buf); + migf->buf = NULL; + } + + if (migf->buf_header) { + virtiovf_free_data_buffer(migf->buf_header); + migf->buf_header = NULL; + } + + list_splice(&migf->avail_list, &migf->buf_list); + + while ((entry = list_first_entry_or_null(&migf->buf_list, + struct virtiovf_data_buffer, buf_elm))) { + list_del(&entry->buf_elm); + virtiovf_free_data_buffer(entry); + } + + if (migf->has_obj_id) + virtiovf_pci_free_obj_id(migf->virtvdev, migf->obj_id); +} + +static void virtiovf_disable_fd(struct virtiovf_migration_file *migf) +{ + mutex_lock(&migf->lock); + migf->state = VIRTIOVF_MIGF_STATE_ERROR; + migf->filp->f_pos = 0; + mutex_unlock(&migf->lock); +} + +static void virtiovf_disable_fds(struct virtiovf_pci_core_device *virtvdev) +{ + if (virtvdev->resuming_migf) { + virtiovf_disable_fd(virtvdev->resuming_migf); + virtiovf_clean_migf_resources(virtvdev->resuming_migf); + fput(virtvdev->resuming_migf->filp); + virtvdev->resuming_migf = NULL; + } + if (virtvdev->saving_migf) { + virtiovf_disable_fd(virtvdev->saving_migf); + virtiovf_clean_migf_resources(virtvdev->saving_migf); + fput(virtvdev->saving_migf->filp); + virtvdev->saving_migf = NULL; + } +} + +/* + * This function is called in all state_mutex unlock cases to + * handle a 'deferred_reset' if exists. + */ +static void virtiovf_state_mutex_unlock(struct virtiovf_pci_core_device *virtvdev) +{ +again: + spin_lock(&virtvdev->reset_lock); + if (virtvdev->deferred_reset) { + virtvdev->deferred_reset = false; + spin_unlock(&virtvdev->reset_lock); + virtvdev->mig_state = VFIO_DEVICE_STATE_RUNNING; + virtiovf_disable_fds(virtvdev); + goto again; + } + mutex_unlock(&virtvdev->state_mutex); + spin_unlock(&virtvdev->reset_lock); +} + +void virtiovf_migration_reset_done(struct pci_dev *pdev) +{ + struct virtiovf_pci_core_device *virtvdev = dev_get_drvdata(&pdev->dev); + + if (!virtvdev->migrate_cap) + return; + + /* + * As the higher VFIO layers are holding locks across reset and using + * those same locks with the mm_lock we need to prevent ABBA deadlock + * with the state_mutex and mm_lock. + * In case the state_mutex was taken already we defer the cleanup work + * to the unlock flow of the other running context. + */ + spin_lock(&virtvdev->reset_lock); + virtvdev->deferred_reset = true; + if (!mutex_trylock(&virtvdev->state_mutex)) { + spin_unlock(&virtvdev->reset_lock); + return; + } + spin_unlock(&virtvdev->reset_lock); + virtiovf_state_mutex_unlock(virtvdev); +} + +static int virtiovf_release_file(struct inode *inode, struct file *filp) +{ + struct virtiovf_migration_file *migf = filp->private_data; + + virtiovf_disable_fd(migf); + mutex_destroy(&migf->lock); + kfree(migf); + return 0; +} + +static struct virtiovf_data_buffer * +virtiovf_get_data_buff_from_pos(struct virtiovf_migration_file *migf, + loff_t pos, bool *end_of_data) +{ + struct virtiovf_data_buffer *buf; + bool found = false; + + *end_of_data = false; + spin_lock_irq(&migf->list_lock); + if (list_empty(&migf->buf_list)) { + *end_of_data = true; + goto end; + } + + buf = list_first_entry(&migf->buf_list, struct virtiovf_data_buffer, + buf_elm); + if (pos >= buf->start_pos && + pos < buf->start_pos + buf->length) { + found = true; + goto end; + } + + /* + * As we use a stream based FD we may expect having the data always + * on first chunk + */ + migf->state = VIRTIOVF_MIGF_STATE_ERROR; + +end: + spin_unlock_irq(&migf->list_lock); + return found ? buf : NULL; +} + +static ssize_t virtiovf_buf_read(struct virtiovf_data_buffer *vhca_buf, + char __user **buf, size_t *len, loff_t *pos) +{ + unsigned long offset; + ssize_t done = 0; + size_t copy_len; + + copy_len = min_t(size_t, + vhca_buf->start_pos + vhca_buf->length - *pos, *len); + while (copy_len) { + size_t page_offset; + struct page *page; + size_t page_len; + u8 *from_buff; + int ret; + + offset = *pos - vhca_buf->start_pos; + page_offset = offset % PAGE_SIZE; + offset -= page_offset; + page = virtiovf_get_migration_page(vhca_buf, offset); + if (!page) + return -EINVAL; + page_len = min_t(size_t, copy_len, PAGE_SIZE - page_offset); + from_buff = kmap_local_page(page); + ret = copy_to_user(*buf, from_buff + page_offset, page_len); + kunmap_local(from_buff); + if (ret) + return -EFAULT; + *pos += page_len; + *len -= page_len; + *buf += page_len; + done += page_len; + copy_len -= page_len; + } + + if (*pos >= vhca_buf->start_pos + vhca_buf->length) { + spin_lock_irq(&vhca_buf->migf->list_lock); + list_del_init(&vhca_buf->buf_elm); + list_add_tail(&vhca_buf->buf_elm, &vhca_buf->migf->avail_list); + spin_unlock_irq(&vhca_buf->migf->list_lock); + } + + return done; +} + +static ssize_t virtiovf_save_read(struct file *filp, char __user *buf, size_t len, + loff_t *pos) +{ + struct virtiovf_migration_file *migf = filp->private_data; + struct virtiovf_data_buffer *vhca_buf; + bool first_loop_call = true; + bool end_of_data; + ssize_t done = 0; + + if (pos) + return -ESPIPE; + pos = &filp->f_pos; + + mutex_lock(&migf->lock); + if (migf->state == VIRTIOVF_MIGF_STATE_ERROR) { + done = -ENODEV; + goto out_unlock; + } + + while (len) { + ssize_t count; + + vhca_buf = virtiovf_get_data_buff_from_pos(migf, *pos, &end_of_data); + if (first_loop_call) { + first_loop_call = false; + /* Temporary end of file as part of PRE_COPY */ + if (end_of_data && migf->state == VIRTIOVF_MIGF_STATE_PRECOPY) { + done = -ENOMSG; + goto out_unlock; + } + if (end_of_data && migf->state != VIRTIOVF_MIGF_STATE_COMPLETE) { + done = -EINVAL; + goto out_unlock; + } + } + + if (end_of_data) + goto out_unlock; + + if (!vhca_buf) { + done = -EINVAL; + goto out_unlock; + } + + count = virtiovf_buf_read(vhca_buf, &buf, &len, pos); + if (count < 0) { + done = count; + goto out_unlock; + } + done += count; + } + +out_unlock: + mutex_unlock(&migf->lock); + return done; +} + +static long virtiovf_precopy_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct virtiovf_migration_file *migf = filp->private_data; + struct virtiovf_pci_core_device *virtvdev = migf->virtvdev; + struct vfio_precopy_info info = {}; + loff_t *pos = &filp->f_pos; + bool end_of_data = false; + unsigned long minsz; + u32 ctx_size = 0; + int ret; + + if (cmd != VFIO_MIG_GET_PRECOPY_INFO) + return -ENOTTY; + + minsz = offsetofend(struct vfio_precopy_info, dirty_bytes); + if (copy_from_user(&info, (void __user *)arg, minsz)) + return -EFAULT; + + if (info.argsz < minsz) + return -EINVAL; + + mutex_lock(&virtvdev->state_mutex); + if (virtvdev->mig_state != VFIO_DEVICE_STATE_PRE_COPY && + virtvdev->mig_state != VFIO_DEVICE_STATE_PRE_COPY_P2P) { + ret = -EINVAL; + goto err_state_unlock; + } + + /* + * The virtio specification does not include a PRE_COPY concept. + * Since we can expect the data to remain the same for a certain period, + * we use a rate limiter mechanism before making a call to the device. + */ + if (__ratelimit(&migf->pre_copy_rl_state)) { + + ret = virtio_pci_admin_dev_parts_metadata_get(virtvdev->core_device.pdev, + VIRTIO_RESOURCE_OBJ_DEV_PARTS, migf->obj_id, + VIRTIO_ADMIN_CMD_DEV_PARTS_METADATA_TYPE_SIZE, + &ctx_size); + if (ret) + goto err_state_unlock; + } + + mutex_lock(&migf->lock); + if (migf->state == VIRTIOVF_MIGF_STATE_ERROR) { + ret = -ENODEV; + goto err_migf_unlock; + } + + if (migf->pre_copy_initial_bytes > *pos) { + info.initial_bytes = migf->pre_copy_initial_bytes - *pos; + } else { + info.dirty_bytes = migf->max_pos - *pos; + if (!info.dirty_bytes) + end_of_data = true; + info.dirty_bytes += ctx_size; + } + + if (!end_of_data || !ctx_size) { + mutex_unlock(&migf->lock); + goto done; + } + + mutex_unlock(&migf->lock); + /* + * We finished transferring the current state and the device has a + * dirty state, read a new state. + */ + ret = virtiovf_read_device_context_chunk(migf, ctx_size); + if (ret) + /* + * The machine is running, and context size could be grow, so no reason to mark + * the device state as VIRTIOVF_MIGF_STATE_ERROR. + */ + goto err_state_unlock; + +done: + virtiovf_state_mutex_unlock(virtvdev); + if (copy_to_user((void __user *)arg, &info, minsz)) + return -EFAULT; + return 0; + +err_migf_unlock: + mutex_unlock(&migf->lock); +err_state_unlock: + virtiovf_state_mutex_unlock(virtvdev); + return ret; +} + +static const struct file_operations virtiovf_save_fops = { + .owner = THIS_MODULE, + .read = virtiovf_save_read, + .unlocked_ioctl = virtiovf_precopy_ioctl, + .compat_ioctl = compat_ptr_ioctl, + .release = virtiovf_release_file, +}; + +static int +virtiovf_add_buf_header(struct virtiovf_data_buffer *header_buf, + u32 data_size) +{ + struct virtiovf_migration_file *migf = header_buf->migf; + struct virtiovf_migration_header header = {}; + struct page *page; + u8 *to_buff; + + header.record_size = cpu_to_le64(data_size); + header.flags = cpu_to_le32(VIRTIOVF_MIGF_HEADER_FLAGS_TAG_MANDATORY); + header.tag = cpu_to_le32(VIRTIOVF_MIGF_HEADER_TAG_DEVICE_DATA); + page = virtiovf_get_migration_page(header_buf, 0); + if (!page) + return -EINVAL; + to_buff = kmap_local_page(page); + memcpy(to_buff, &header, sizeof(header)); + kunmap_local(to_buff); + header_buf->length = sizeof(header); + header_buf->start_pos = header_buf->migf->max_pos; + migf->max_pos += header_buf->length; + spin_lock_irq(&migf->list_lock); + list_add_tail(&header_buf->buf_elm, &migf->buf_list); + spin_unlock_irq(&migf->list_lock); + return 0; +} + +static int +virtiovf_read_device_context_chunk(struct virtiovf_migration_file *migf, + u32 ctx_size) +{ + struct virtiovf_data_buffer *header_buf; + struct virtiovf_data_buffer *buf; + bool unmark_end = false; + struct scatterlist *sg; + unsigned int i; + u32 res_size; + int nent; + int ret; + + buf = virtiovf_get_data_buffer(migf, ctx_size); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* Find the total count of SG entries which satisfies the size */ + nent = sg_nents_for_len(buf->table.sgt.sgl, ctx_size); + if (nent <= 0) { + ret = -EINVAL; + goto out; + } + + /* + * Iterate to that SG entry and mark it as last (if it's not already) + * to let underlay layers iterate only till that entry. + */ + for_each_sg(buf->table.sgt.sgl, sg, nent - 1, i) + ; + + if (!sg_is_last(sg)) { + unmark_end = true; + sg_mark_end(sg); + } + + ret = virtio_pci_admin_dev_parts_get(migf->virtvdev->core_device.pdev, + VIRTIO_RESOURCE_OBJ_DEV_PARTS, + migf->obj_id, + VIRTIO_ADMIN_CMD_DEV_PARTS_GET_TYPE_ALL, + buf->table.sgt.sgl, &res_size); + /* Restore the original SG mark end */ + if (unmark_end) + sg_unmark_end(sg); + if (ret) + goto out; + + buf->length = res_size; + header_buf = virtiovf_get_data_buffer(migf, + sizeof(struct virtiovf_migration_header)); + if (IS_ERR(header_buf)) { + ret = PTR_ERR(header_buf); + goto out; + } + + ret = virtiovf_add_buf_header(header_buf, res_size); + if (ret) + goto out_header; + + buf->start_pos = buf->migf->max_pos; + migf->max_pos += buf->length; + spin_lock(&migf->list_lock); + list_add_tail(&buf->buf_elm, &migf->buf_list); + spin_unlock_irq(&migf->list_lock); + return 0; + +out_header: + virtiovf_put_data_buffer(header_buf); +out: + virtiovf_put_data_buffer(buf); + return ret; +} + +static int +virtiovf_pci_save_device_final_data(struct virtiovf_pci_core_device *virtvdev) +{ + struct virtiovf_migration_file *migf = virtvdev->saving_migf; + u32 ctx_size; + int ret; + + if (migf->state == VIRTIOVF_MIGF_STATE_ERROR) + return -ENODEV; + + ret = virtio_pci_admin_dev_parts_metadata_get(virtvdev->core_device.pdev, + VIRTIO_RESOURCE_OBJ_DEV_PARTS, migf->obj_id, + VIRTIO_ADMIN_CMD_DEV_PARTS_METADATA_TYPE_SIZE, + &ctx_size); + if (ret) + goto err; + + if (!ctx_size) { + ret = -EINVAL; + goto err; + } + + ret = virtiovf_read_device_context_chunk(migf, ctx_size); + if (ret) + goto err; + + migf->state = VIRTIOVF_MIGF_STATE_COMPLETE; + return 0; + +err: + migf->state = VIRTIOVF_MIGF_STATE_ERROR; + return ret; +} + +static struct virtiovf_migration_file * +virtiovf_pci_save_device_data(struct virtiovf_pci_core_device *virtvdev, + bool pre_copy) +{ + struct virtiovf_migration_file *migf; + u32 ctx_size; + u32 obj_id; + int ret; + + migf = kzalloc(sizeof(*migf), GFP_KERNEL_ACCOUNT); + if (!migf) + return ERR_PTR(-ENOMEM); + + migf->filp = anon_inode_getfile("virtiovf_mig", &virtiovf_save_fops, migf, + O_RDONLY); + if (IS_ERR(migf->filp)) { + ret = PTR_ERR(migf->filp); + kfree(migf); + return ERR_PTR(ret); + } + + stream_open(migf->filp->f_inode, migf->filp); + mutex_init(&migf->lock); + INIT_LIST_HEAD(&migf->buf_list); + INIT_LIST_HEAD(&migf->avail_list); + spin_lock_init(&migf->list_lock); + migf->virtvdev = virtvdev; + + lockdep_assert_held(&virtvdev->state_mutex); + ret = virtiovf_pci_alloc_obj_id(virtvdev, VIRTIO_RESOURCE_OBJ_DEV_PARTS_TYPE_GET, + &obj_id); + if (ret) + goto out; + + migf->obj_id = obj_id; + /* Mark as having a valid obj id which can be even 0 */ + migf->has_obj_id = true; + ret = virtio_pci_admin_dev_parts_metadata_get(virtvdev->core_device.pdev, + VIRTIO_RESOURCE_OBJ_DEV_PARTS, obj_id, + VIRTIO_ADMIN_CMD_DEV_PARTS_METADATA_TYPE_SIZE, + &ctx_size); + if (ret) + goto out_clean; + + if (!ctx_size) { + ret = -EINVAL; + goto out_clean; + } + + ret = virtiovf_read_device_context_chunk(migf, ctx_size); + if (ret) + goto out_clean; + + if (pre_copy) { + migf->pre_copy_initial_bytes = migf->max_pos; + /* Arbitrarily set the pre-copy rate limit to 1-second intervals */ + ratelimit_state_init(&migf->pre_copy_rl_state, 1 * HZ, 1); + /* Prevent any rate messages upon its usage */ + ratelimit_set_flags(&migf->pre_copy_rl_state, + RATELIMIT_MSG_ON_RELEASE); + migf->state = VIRTIOVF_MIGF_STATE_PRECOPY; + } else { + migf->state = VIRTIOVF_MIGF_STATE_COMPLETE; + } + + return migf; + +out_clean: + virtiovf_clean_migf_resources(migf); +out: + fput(migf->filp); + return ERR_PTR(ret); +} + +/* + * Set the required object header at the beginning of the buffer. + * The actual device parts data will be written post of the header offset. + */ +static int virtiovf_set_obj_cmd_header(struct virtiovf_data_buffer *vhca_buf) +{ + struct virtio_admin_cmd_resource_obj_cmd_hdr obj_hdr = {}; + struct page *page; + u8 *to_buff; + + obj_hdr.type = cpu_to_le16(VIRTIO_RESOURCE_OBJ_DEV_PARTS); + obj_hdr.id = cpu_to_le32(vhca_buf->migf->obj_id); + page = virtiovf_get_migration_page(vhca_buf, 0); + if (!page) + return -EINVAL; + to_buff = kmap_local_page(page); + memcpy(to_buff, &obj_hdr, sizeof(obj_hdr)); + kunmap_local(to_buff); + + /* Mark the buffer as including the header object data */ + vhca_buf->include_header_object = 1; + return 0; +} + +static int +virtiovf_append_page_to_mig_buf(struct virtiovf_data_buffer *vhca_buf, + const char __user **buf, size_t *len, + loff_t *pos, ssize_t *done) +{ + unsigned long offset; + size_t page_offset; + struct page *page; + size_t page_len; + u8 *to_buff; + int ret; + + offset = *pos - vhca_buf->start_pos; + + if (vhca_buf->include_header_object) + /* The buffer holds the object header, update the offset accordingly */ + offset += sizeof(struct virtio_admin_cmd_resource_obj_cmd_hdr); + + page_offset = offset % PAGE_SIZE; + + page = virtiovf_get_migration_page(vhca_buf, offset - page_offset); + if (!page) + return -EINVAL; + + page_len = min_t(size_t, *len, PAGE_SIZE - page_offset); + to_buff = kmap_local_page(page); + ret = copy_from_user(to_buff + page_offset, *buf, page_len); + kunmap_local(to_buff); + if (ret) + return -EFAULT; + + *pos += page_len; + *done += page_len; + *buf += page_len; + *len -= page_len; + vhca_buf->length += page_len; + return 0; +} + +static ssize_t +virtiovf_resume_read_chunk(struct virtiovf_migration_file *migf, + struct virtiovf_data_buffer *vhca_buf, + size_t chunk_size, const char __user **buf, + size_t *len, loff_t *pos, ssize_t *done, + bool *has_work) +{ + size_t copy_len, to_copy; + int ret; + + to_copy = min_t(size_t, *len, chunk_size - vhca_buf->length); + copy_len = to_copy; + while (to_copy) { + ret = virtiovf_append_page_to_mig_buf(vhca_buf, buf, &to_copy, + pos, done); + if (ret) + return ret; + } + + *len -= copy_len; + if (vhca_buf->length == chunk_size) { + migf->load_state = VIRTIOVF_LOAD_STATE_LOAD_CHUNK; + migf->max_pos += chunk_size; + *has_work = true; + } + + return 0; +} + +static int +virtiovf_resume_read_header_data(struct virtiovf_migration_file *migf, + struct virtiovf_data_buffer *vhca_buf, + const char __user **buf, size_t *len, + loff_t *pos, ssize_t *done) +{ + size_t copy_len, to_copy; + size_t required_data; + int ret; + + required_data = migf->record_size - vhca_buf->length; + to_copy = min_t(size_t, *len, required_data); + copy_len = to_copy; + while (to_copy) { + ret = virtiovf_append_page_to_mig_buf(vhca_buf, buf, &to_copy, + pos, done); + if (ret) + return ret; + } + + *len -= copy_len; + if (vhca_buf->length == migf->record_size) { + switch (migf->record_tag) { + default: + /* Optional tag */ + break; + } + + migf->load_state = VIRTIOVF_LOAD_STATE_READ_HEADER; + migf->max_pos += migf->record_size; + vhca_buf->length = 0; + } + + return 0; +} + +static int +virtiovf_resume_read_header(struct virtiovf_migration_file *migf, + struct virtiovf_data_buffer *vhca_buf, + const char __user **buf, + size_t *len, loff_t *pos, + ssize_t *done, bool *has_work) +{ + struct page *page; + size_t copy_len; + u8 *to_buff; + int ret; + + copy_len = min_t(size_t, *len, + sizeof(struct virtiovf_migration_header) - vhca_buf->length); + page = virtiovf_get_migration_page(vhca_buf, 0); + if (!page) + return -EINVAL; + to_buff = kmap_local_page(page); + ret = copy_from_user(to_buff + vhca_buf->length, *buf, copy_len); + if (ret) { + ret = -EFAULT; + goto end; + } + + *buf += copy_len; + *pos += copy_len; + *done += copy_len; + *len -= copy_len; + vhca_buf->length += copy_len; + if (vhca_buf->length == sizeof(struct virtiovf_migration_header)) { + u64 record_size; + u32 flags; + + record_size = le64_to_cpup((__le64 *)to_buff); + if (record_size > MAX_LOAD_SIZE) { + ret = -ENOMEM; + goto end; + } + + migf->record_size = record_size; + flags = le32_to_cpup((__le32 *)(to_buff + + offsetof(struct virtiovf_migration_header, flags))); + migf->record_tag = le32_to_cpup((__le32 *)(to_buff + + offsetof(struct virtiovf_migration_header, tag))); + switch (migf->record_tag) { + case VIRTIOVF_MIGF_HEADER_TAG_DEVICE_DATA: + migf->load_state = VIRTIOVF_LOAD_STATE_PREP_CHUNK; + break; + default: + if (!(flags & VIRTIOVF_MIGF_HEADER_FLAGS_TAG_OPTIONAL)) { + ret = -EOPNOTSUPP; + goto end; + } + /* We may read and skip this optional record data */ + migf->load_state = VIRTIOVF_LOAD_STATE_PREP_HEADER_DATA; + } + + migf->max_pos += vhca_buf->length; + vhca_buf->length = 0; + *has_work = true; + } +end: + kunmap_local(to_buff); + return ret; +} + +static ssize_t virtiovf_resume_write(struct file *filp, const char __user *buf, + size_t len, loff_t *pos) +{ + struct virtiovf_migration_file *migf = filp->private_data; + struct virtiovf_data_buffer *vhca_buf = migf->buf; + struct virtiovf_data_buffer *vhca_buf_header = migf->buf_header; + unsigned int orig_length; + bool has_work = false; + ssize_t done = 0; + int ret = 0; + + if (pos) + return -ESPIPE; + + pos = &filp->f_pos; + if (*pos < vhca_buf->start_pos) + return -EINVAL; + + mutex_lock(&migf->virtvdev->state_mutex); + mutex_lock(&migf->lock); + if (migf->state == VIRTIOVF_MIGF_STATE_ERROR) { + done = -ENODEV; + goto out_unlock; + } + + while (len || has_work) { + has_work = false; + switch (migf->load_state) { + case VIRTIOVF_LOAD_STATE_READ_HEADER: + ret = virtiovf_resume_read_header(migf, vhca_buf_header, &buf, + &len, pos, &done, &has_work); + if (ret) + goto out_unlock; + break; + case VIRTIOVF_LOAD_STATE_PREP_HEADER_DATA: + if (vhca_buf_header->allocated_length < migf->record_size) { + virtiovf_free_data_buffer(vhca_buf_header); + + migf->buf_header = virtiovf_alloc_data_buffer(migf, + migf->record_size); + if (IS_ERR(migf->buf_header)) { + ret = PTR_ERR(migf->buf_header); + migf->buf_header = NULL; + goto out_unlock; + } + + vhca_buf_header = migf->buf_header; + } + + vhca_buf_header->start_pos = migf->max_pos; + migf->load_state = VIRTIOVF_LOAD_STATE_READ_HEADER_DATA; + break; + case VIRTIOVF_LOAD_STATE_READ_HEADER_DATA: + ret = virtiovf_resume_read_header_data(migf, vhca_buf_header, + &buf, &len, pos, &done); + if (ret) + goto out_unlock; + break; + case VIRTIOVF_LOAD_STATE_PREP_CHUNK: + { + u32 cmd_size = migf->record_size + + sizeof(struct virtio_admin_cmd_resource_obj_cmd_hdr); + + /* + * The DMA map/unmap is managed in virtio layer, we just need to extend + * the SG pages to hold the extra required chunk data. + */ + if (vhca_buf->allocated_length < cmd_size) { + ret = virtiovf_add_migration_pages(vhca_buf, + DIV_ROUND_UP_ULL(cmd_size - vhca_buf->allocated_length, + PAGE_SIZE)); + if (ret) + goto out_unlock; + } + + vhca_buf->start_pos = migf->max_pos; + migf->load_state = VIRTIOVF_LOAD_STATE_READ_CHUNK; + break; + } + case VIRTIOVF_LOAD_STATE_READ_CHUNK: + ret = virtiovf_resume_read_chunk(migf, vhca_buf, migf->record_size, + &buf, &len, pos, &done, &has_work); + if (ret) + goto out_unlock; + break; + case VIRTIOVF_LOAD_STATE_LOAD_CHUNK: + /* Mark the last SG entry and set its length */ + sg_mark_end(vhca_buf->last_offset_sg); + orig_length = vhca_buf->last_offset_sg->length; + /* Length should include the resource object command header */ + vhca_buf->last_offset_sg->length = vhca_buf->length + + sizeof(struct virtio_admin_cmd_resource_obj_cmd_hdr) - + vhca_buf->last_offset; + ret = virtio_pci_admin_dev_parts_set(migf->virtvdev->core_device.pdev, + vhca_buf->table.sgt.sgl); + /* Restore the original SG data */ + vhca_buf->last_offset_sg->length = orig_length; + sg_unmark_end(vhca_buf->last_offset_sg); + if (ret) + goto out_unlock; + migf->load_state = VIRTIOVF_LOAD_STATE_READ_HEADER; + /* be ready for reading the next chunk */ + vhca_buf->length = 0; + break; + default: + break; + } + } + +out_unlock: + if (ret) + migf->state = VIRTIOVF_MIGF_STATE_ERROR; + mutex_unlock(&migf->lock); + virtiovf_state_mutex_unlock(migf->virtvdev); + return ret ? ret : done; +} + +static const struct file_operations virtiovf_resume_fops = { + .owner = THIS_MODULE, + .write = virtiovf_resume_write, + .release = virtiovf_release_file, +}; + +static struct virtiovf_migration_file * +virtiovf_pci_resume_device_data(struct virtiovf_pci_core_device *virtvdev) +{ + struct virtiovf_migration_file *migf; + struct virtiovf_data_buffer *buf; + u32 obj_id; + int ret; + + migf = kzalloc(sizeof(*migf), GFP_KERNEL_ACCOUNT); + if (!migf) + return ERR_PTR(-ENOMEM); + + migf->filp = anon_inode_getfile("virtiovf_mig", &virtiovf_resume_fops, migf, + O_WRONLY); + if (IS_ERR(migf->filp)) { + ret = PTR_ERR(migf->filp); + kfree(migf); + return ERR_PTR(ret); + } + + stream_open(migf->filp->f_inode, migf->filp); + mutex_init(&migf->lock); + INIT_LIST_HEAD(&migf->buf_list); + INIT_LIST_HEAD(&migf->avail_list); + spin_lock_init(&migf->list_lock); + + buf = virtiovf_alloc_data_buffer(migf, VIRTIOVF_TARGET_INITIAL_BUF_SIZE); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto out; + } + + migf->buf = buf; + + buf = virtiovf_alloc_data_buffer(migf, + sizeof(struct virtiovf_migration_header)); + if (IS_ERR(buf)) { + ret = PTR_ERR(buf); + goto out_clean; + } + + migf->buf_header = buf; + migf->load_state = VIRTIOVF_LOAD_STATE_READ_HEADER; + + migf->virtvdev = virtvdev; + ret = virtiovf_pci_alloc_obj_id(virtvdev, VIRTIO_RESOURCE_OBJ_DEV_PARTS_TYPE_SET, + &obj_id); + if (ret) + goto out_clean; + + migf->obj_id = obj_id; + /* Mark as having a valid obj id which can be even 0 */ + migf->has_obj_id = true; + ret = virtiovf_set_obj_cmd_header(migf->buf); + if (ret) + goto out_clean; + + return migf; + +out_clean: + virtiovf_clean_migf_resources(migf); +out: + fput(migf->filp); + return ERR_PTR(ret); +} + +static struct file * +virtiovf_pci_step_device_state_locked(struct virtiovf_pci_core_device *virtvdev, + u32 new) +{ + u32 cur = virtvdev->mig_state; + int ret; + + if (cur == VFIO_DEVICE_STATE_RUNNING_P2P && new == VFIO_DEVICE_STATE_STOP) { + /* NOP */ + return NULL; + } + + if (cur == VFIO_DEVICE_STATE_STOP && new == VFIO_DEVICE_STATE_RUNNING_P2P) { + /* NOP */ + return NULL; + } + + if ((cur == VFIO_DEVICE_STATE_RUNNING && new == VFIO_DEVICE_STATE_RUNNING_P2P) || + (cur == VFIO_DEVICE_STATE_PRE_COPY && new == VFIO_DEVICE_STATE_PRE_COPY_P2P)) { + ret = virtio_pci_admin_mode_set(virtvdev->core_device.pdev, + BIT(VIRTIO_ADMIN_CMD_DEV_MODE_F_STOPPED)); + if (ret) + return ERR_PTR(ret); + return NULL; + } + + if ((cur == VFIO_DEVICE_STATE_RUNNING_P2P && new == VFIO_DEVICE_STATE_RUNNING) || + (cur == VFIO_DEVICE_STATE_PRE_COPY_P2P && new == VFIO_DEVICE_STATE_PRE_COPY)) { + ret = virtio_pci_admin_mode_set(virtvdev->core_device.pdev, 0); + if (ret) + return ERR_PTR(ret); + return NULL; + } + + if (cur == VFIO_DEVICE_STATE_STOP && new == VFIO_DEVICE_STATE_STOP_COPY) { + struct virtiovf_migration_file *migf; + + migf = virtiovf_pci_save_device_data(virtvdev, false); + if (IS_ERR(migf)) + return ERR_CAST(migf); + get_file(migf->filp); + virtvdev->saving_migf = migf; + return migf->filp; + } + + if ((cur == VFIO_DEVICE_STATE_STOP_COPY && new == VFIO_DEVICE_STATE_STOP) || + (cur == VFIO_DEVICE_STATE_PRE_COPY && new == VFIO_DEVICE_STATE_RUNNING) || + (cur == VFIO_DEVICE_STATE_PRE_COPY_P2P && new == VFIO_DEVICE_STATE_RUNNING_P2P)) { + virtiovf_disable_fds(virtvdev); + return NULL; + } + + if (cur == VFIO_DEVICE_STATE_STOP && new == VFIO_DEVICE_STATE_RESUMING) { + struct virtiovf_migration_file *migf; + + migf = virtiovf_pci_resume_device_data(virtvdev); + if (IS_ERR(migf)) + return ERR_CAST(migf); + get_file(migf->filp); + virtvdev->resuming_migf = migf; + return migf->filp; + } + + if (cur == VFIO_DEVICE_STATE_RESUMING && new == VFIO_DEVICE_STATE_STOP) { + virtiovf_disable_fds(virtvdev); + return NULL; + } + + if ((cur == VFIO_DEVICE_STATE_RUNNING && new == VFIO_DEVICE_STATE_PRE_COPY) || + (cur == VFIO_DEVICE_STATE_RUNNING_P2P && + new == VFIO_DEVICE_STATE_PRE_COPY_P2P)) { + struct virtiovf_migration_file *migf; + + migf = virtiovf_pci_save_device_data(virtvdev, true); + if (IS_ERR(migf)) + return ERR_CAST(migf); + get_file(migf->filp); + virtvdev->saving_migf = migf; + return migf->filp; + } + + if (cur == VFIO_DEVICE_STATE_PRE_COPY_P2P && new == VFIO_DEVICE_STATE_STOP_COPY) { + ret = virtiovf_pci_save_device_final_data(virtvdev); + return ret ? ERR_PTR(ret) : NULL; + } + + /* + * vfio_mig_get_next_state() does not use arcs other than the above + */ + WARN_ON(true); + return ERR_PTR(-EINVAL); +} + +static struct file * +virtiovf_pci_set_device_state(struct vfio_device *vdev, + enum vfio_device_mig_state new_state) +{ + struct virtiovf_pci_core_device *virtvdev = container_of( + vdev, struct virtiovf_pci_core_device, core_device.vdev); + enum vfio_device_mig_state next_state; + struct file *res = NULL; + int ret; + + mutex_lock(&virtvdev->state_mutex); + while (new_state != virtvdev->mig_state) { + ret = vfio_mig_get_next_state(vdev, virtvdev->mig_state, + new_state, &next_state); + if (ret) { + res = ERR_PTR(ret); + break; + } + res = virtiovf_pci_step_device_state_locked(virtvdev, next_state); + if (IS_ERR(res)) + break; + virtvdev->mig_state = next_state; + if (WARN_ON(res && new_state != virtvdev->mig_state)) { + fput(res); + res = ERR_PTR(-EINVAL); + break; + } + } + virtiovf_state_mutex_unlock(virtvdev); + return res; +} + +static int virtiovf_pci_get_device_state(struct vfio_device *vdev, + enum vfio_device_mig_state *curr_state) +{ + struct virtiovf_pci_core_device *virtvdev = container_of( + vdev, struct virtiovf_pci_core_device, core_device.vdev); + + mutex_lock(&virtvdev->state_mutex); + *curr_state = virtvdev->mig_state; + virtiovf_state_mutex_unlock(virtvdev); + return 0; +} + +static int virtiovf_pci_get_data_size(struct vfio_device *vdev, + unsigned long *stop_copy_length) +{ + struct virtiovf_pci_core_device *virtvdev = container_of( + vdev, struct virtiovf_pci_core_device, core_device.vdev); + bool obj_id_exists; + u32 res_size; + u32 obj_id; + int ret; + + mutex_lock(&virtvdev->state_mutex); + obj_id_exists = virtvdev->saving_migf && virtvdev->saving_migf->has_obj_id; + if (!obj_id_exists) { + ret = virtiovf_pci_alloc_obj_id(virtvdev, + VIRTIO_RESOURCE_OBJ_DEV_PARTS_TYPE_GET, + &obj_id); + if (ret) + goto end; + } else { + obj_id = virtvdev->saving_migf->obj_id; + } + + ret = virtio_pci_admin_dev_parts_metadata_get(virtvdev->core_device.pdev, + VIRTIO_RESOURCE_OBJ_DEV_PARTS, obj_id, + VIRTIO_ADMIN_CMD_DEV_PARTS_METADATA_TYPE_SIZE, + &res_size); + if (!ret) + *stop_copy_length = res_size; + + /* + * We can't leave this obj_id alive if didn't exist before, otherwise, it might + * stay alive, even without an active migration flow (e.g. migration was cancelled) + */ + if (!obj_id_exists) + virtiovf_pci_free_obj_id(virtvdev, obj_id); +end: + virtiovf_state_mutex_unlock(virtvdev); + return ret; +} + +static const struct vfio_migration_ops virtvdev_pci_mig_ops = { + .migration_set_state = virtiovf_pci_set_device_state, + .migration_get_state = virtiovf_pci_get_device_state, + .migration_get_data_size = virtiovf_pci_get_data_size, +}; + +void virtiovf_set_migratable(struct virtiovf_pci_core_device *virtvdev) +{ + virtvdev->migrate_cap = 1; + mutex_init(&virtvdev->state_mutex); + spin_lock_init(&virtvdev->reset_lock); + virtvdev->core_device.vdev.migration_flags = + VFIO_MIGRATION_STOP_COPY | + VFIO_MIGRATION_P2P | + VFIO_MIGRATION_PRE_COPY; + virtvdev->core_device.vdev.mig_ops = &virtvdev_pci_mig_ops; +} + +void virtiovf_open_migration(struct virtiovf_pci_core_device *virtvdev) +{ + if (!virtvdev->migrate_cap) + return; + + virtvdev->mig_state = VFIO_DEVICE_STATE_RUNNING; +} + +void virtiovf_close_migration(struct virtiovf_pci_core_device *virtvdev) +{ + if (!virtvdev->migrate_cap) + return; + + virtiovf_disable_fds(virtvdev); +} diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c index 42d1462c5e19da..512533501eb7f3 100644 --- a/drivers/vfio/platform/vfio_platform.c +++ b/drivers/vfio/platform/vfio_platform.c @@ -112,7 +112,7 @@ static const struct vfio_device_ops vfio_platform_ops = { static struct platform_driver vfio_platform_driver = { .probe = vfio_platform_probe, - .remove_new = vfio_platform_remove, + .remove = vfio_platform_remove, .driver = { .name = "vfio-platform", }, diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index bf391b40e576fc..50ebc9593c9d70 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -72,7 +72,6 @@ struct vfio_iommu { uint64_t pgsize_bitmap; uint64_t num_non_pinned_groups; bool v2; - bool nesting; bool dirty_page_tracking; struct list_head emulated_iommu_groups; }; @@ -2195,12 +2194,6 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, goto out_free_domain; } - if (iommu->nesting) { - ret = iommu_enable_nesting(domain->domain); - if (ret) - goto out_domain; - } - ret = iommu_attach_group(domain->domain, group->iommu_group); if (ret) goto out_domain; @@ -2541,9 +2534,7 @@ static void *vfio_iommu_type1_open(unsigned long arg) switch (arg) { case VFIO_TYPE1_IOMMU: break; - case VFIO_TYPE1_NESTING_IOMMU: - iommu->nesting = true; - fallthrough; + case __VFIO_RESERVED_TYPE1_NESTING_IOMMU: case VFIO_TYPE1v2_IOMMU: iommu->v2 = true; break; @@ -2638,7 +2629,6 @@ static int vfio_iommu_type1_check_extension(struct vfio_iommu *iommu, switch (arg) { case VFIO_TYPE1_IOMMU: case VFIO_TYPE1v2_IOMMU: - case VFIO_TYPE1_NESTING_IOMMU: case VFIO_UNMAP_ALL: return 1; case VFIO_UPDATE_VADDR: diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index a5a62d9d963f72..1fd261efc582d0 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -1751,7 +1751,7 @@ static void __exit vfio_cleanup(void) module_init(vfio_init); module_exit(vfio_cleanup); -MODULE_IMPORT_NS(IOMMUFD); +MODULE_IMPORT_NS("IOMMUFD"); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c index d22881245e8914..aa2891f975087e 100644 --- a/drivers/vfio/virqfd.c +++ b/drivers/vfio/virqfd.c @@ -113,7 +113,6 @@ int vfio_virqfd_enable(void *opaque, void (*thread)(void *, void *), void *data, struct virqfd **pvirqfd, int fd) { - struct fd irqfd; struct eventfd_ctx *ctx; struct virqfd *virqfd; int ret = 0; @@ -133,8 +132,8 @@ int vfio_virqfd_enable(void *opaque, INIT_WORK(&virqfd->inject, virqfd_inject); INIT_WORK(&virqfd->flush_inject, virqfd_flush_inject); - irqfd = fdget(fd); - if (!fd_file(irqfd)) { + CLASS(fd, irqfd)(fd); + if (fd_empty(irqfd)) { ret = -EBADF; goto err_fd; } @@ -142,7 +141,7 @@ int vfio_virqfd_enable(void *opaque, ctx = eventfd_ctx_fileget(fd_file(irqfd)); if (IS_ERR(ctx)) { ret = PTR_ERR(ctx); - goto err_ctx; + goto err_fd; } virqfd->eventfd = ctx; @@ -181,18 +180,9 @@ int vfio_virqfd_enable(void *opaque, if ((!handler || handler(opaque, data)) && thread) schedule_work(&virqfd->inject); } - - /* - * Do not drop the file until the irqfd is fully initialized, - * otherwise we might race against the EPOLLHUP. - */ - fdput(irqfd); - return 0; err_busy: eventfd_ctx_put(ctx); -err_ctx: - fdput(irqfd); err_fd: kfree(virqfd); diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index f16279351db56e..9ad37c0121890e 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1325,7 +1325,7 @@ static int vhost_net_open(struct inode *inode, struct file *f) vqs[VHOST_NET_VQ_RX]); f->private_data = n; - n->pf_cache.va = NULL; + page_frag_cache_init(&n->pf_cache); return 0; } diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 25e409bbb1a2e3..720b5ada7fe850 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -151,7 +151,7 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev, struct pm860x_backlight_data *data, char *name) { - struct device_node *nproot, *np; + struct device_node *nproot; int iset = 0; nproot = of_get_child_by_name(pdev->dev.parent->of_node, "backlights"); @@ -159,14 +159,13 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev, dev_err(&pdev->dev, "failed to find backlights node\n"); return -ENODEV; } - for_each_child_of_node(nproot, np) { + for_each_child_of_node_scoped(nproot, np) { if (of_node_name_eq(np, name)) { of_property_read_u32(np, "marvell,88pm860x-iset", &iset); data->iset = PM8606_WLED_CURRENT(iset); of_property_read_u32(np, "marvell,88pm860x-pwm", &data->pwm); - of_node_put(np); break; } } diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index 68d327ee4b2ed7..8b790df1e842b3 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -186,7 +186,7 @@ static struct platform_driver aat2870_bl_driver = { .name = "aat2870-backlight", }, .probe = aat2870_bl_probe, - .remove_new = aat2870_bl_remove, + .remove = 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 8e0e9cfe5fe938..aa5c15e8db86ed 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -375,7 +375,7 @@ static struct platform_driver adp5520_bl_driver = { .pm = &adp5520_bl_pm_ops, }, .probe = adp5520_bl_probe, - .remove_new = adp5520_bl_remove, + .remove = adp5520_bl_remove, }; module_platform_driver(adp5520_bl_driver); diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index a82934694d05c3..f699e5827ccb3a 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -65,7 +65,6 @@ static struct list_head backlight_dev_list; static struct mutex backlight_dev_list_mutex; -static struct blocking_notifier_head backlight_notifier; static const char *const backlight_types[] = { [BACKLIGHT_RAW] = "raw", @@ -467,9 +466,6 @@ struct backlight_device *backlight_device_register(const char *name, list_add(&new_bd->entry, &backlight_dev_list); mutex_unlock(&backlight_dev_list_mutex); - blocking_notifier_call_chain(&backlight_notifier, - BACKLIGHT_REGISTERED, new_bd); - return new_bd; } EXPORT_SYMBOL(backlight_device_register); @@ -539,9 +535,6 @@ void backlight_device_unregister(struct backlight_device *bd) mutex_unlock(&pmac_backlight_mutex); #endif - blocking_notifier_call_chain(&backlight_notifier, - BACKLIGHT_UNREGISTERED, bd); - mutex_lock(&bd->ops_lock); bd->ops = NULL; mutex_unlock(&bd->ops_lock); @@ -566,40 +559,6 @@ static int devm_backlight_device_match(struct device *dev, void *res, return *r == data; } -/** - * backlight_register_notifier - get notified of backlight (un)registration - * @nb: notifier block with the notifier to call on backlight (un)registration - * - * Register a notifier to get notified when backlight devices get registered - * or unregistered. - * - * RETURNS: - * - * 0 on success, otherwise a negative error code - */ -int backlight_register_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&backlight_notifier, nb); -} -EXPORT_SYMBOL(backlight_register_notifier); - -/** - * backlight_unregister_notifier - unregister a backlight notifier - * @nb: notifier block to unregister - * - * Register a notifier to get notified when backlight devices get registered - * or unregistered. - * - * RETURNS: - * - * 0 on success, otherwise a negative error code - */ -int backlight_unregister_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&backlight_notifier, nb); -} -EXPORT_SYMBOL(backlight_unregister_notifier); - /** * devm_backlight_device_register - register a new backlight device * @dev: the device to register @@ -767,7 +726,6 @@ static int __init backlight_class_init(void) INIT_LIST_HEAD(&backlight_dev_list); mutex_init(&backlight_dev_list_mutex); - BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier); return 0; } diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index e4fcfbe38dc659..69f49371ea3533 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -17,14 +17,13 @@ #include #include #include -#include #include #include #include #include #include -#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) +#define POWER_IS_ON(pwr) ((pwr) <= LCD_POWER_REDUCED) /* Register Addresses */ #define RESCTL_ADRS 0x00 @@ -332,12 +331,12 @@ static void corgi_lcd_power_off(struct corgi_lcd *lcd) POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF); } -static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m) +static int corgi_lcd_set_mode(struct lcd_device *ld, u32 xres, u32 yres) { struct corgi_lcd *lcd = lcd_get_data(ld); int mode = CORGI_LCD_MODE_QVGA; - if (m->xres == 640 || m->xres == 480) + if (xres == 640 || xres == 480) mode = CORGI_LCD_MODE_VGA; if (lcd->mode == mode) @@ -455,7 +454,7 @@ static int corgi_lcd_suspend(struct device *dev) corgibl_flags |= CORGIBL_SUSPENDED; corgi_bl_set_intensity(lcd, 0); - corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN); + corgi_lcd_set_power(lcd->lcd_dev, LCD_POWER_OFF); return 0; } @@ -464,7 +463,7 @@ static int corgi_lcd_resume(struct device *dev) struct corgi_lcd *lcd = dev_get_drvdata(dev); corgibl_flags &= ~CORGIBL_SUSPENDED; - corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK); + corgi_lcd_set_power(lcd->lcd_dev, LCD_POWER_ON); backlight_update_status(lcd->bl_dev); return 0; } @@ -513,7 +512,7 @@ static int corgi_lcd_probe(struct spi_device *spi) if (IS_ERR(lcd->lcd_dev)) return PTR_ERR(lcd->lcd_dev); - lcd->power = FB_BLANK_POWERDOWN; + lcd->power = LCD_POWER_OFF; lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA; memset(&props, 0, sizeof(struct backlight_properties)); @@ -535,7 +534,7 @@ static int corgi_lcd_probe(struct spi_device *spi) lcd->kick_battery = pdata->kick_battery; spi_set_drvdata(spi, lcd); - corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK); + corgi_lcd_set_power(lcd->lcd_dev, LCD_POWER_ON); backlight_update_status(lcd->bl_dev); lcd->limit_mask = pdata->limit_mask; @@ -550,7 +549,7 @@ static void corgi_lcd_remove(struct spi_device *spi) lcd->bl_dev->props.power = BACKLIGHT_POWER_ON; lcd->bl_dev->props.brightness = 0; backlight_update_status(lcd->bl_dev); - corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN); + corgi_lcd_set_power(lcd->lcd_dev, LCD_POWER_OFF); } static struct spi_driver corgi_lcd_driver = { diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c index b8ff7046510eb9..5e13ef96b717cc 100644 --- a/drivers/video/backlight/da9052_bl.c +++ b/drivers/video/backlight/da9052_bl.c @@ -165,7 +165,7 @@ MODULE_DEVICE_TABLE(platform, da9052_wled_ids); static struct platform_driver da9052_wled_driver = { .probe = da9052_backlight_probe, - .remove_new = da9052_backlight_remove, + .remove = 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 ddb7ab4df77e9c..fa9a983533b2de 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -130,7 +130,7 @@ static void hp680bl_remove(struct platform_device *pdev) static struct platform_driver hp680bl_driver = { .probe = hp680bl_probe, - .remove_new = hp680bl_remove, + .remove = 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 cdd7b76867235c..61a57d38700fe6 100644 --- a/drivers/video/backlight/hx8357.c +++ b/drivers/video/backlight/hx8357.c @@ -532,7 +532,7 @@ static int hx8369_lcd_init(struct lcd_device *lcdev) return 0; } -#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) +#define POWER_IS_ON(pwr) ((pwr) <= LCD_POWER_REDUCED) static int hx8357_set_power(struct lcd_device *lcdev, int power) { diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c index 7683e209ad6bca..5e1bf0c5831ff8 100644 --- a/drivers/video/backlight/ili922x.c +++ b/drivers/video/backlight/ili922x.c @@ -8,7 +8,6 @@ * memory is cyclically updated over the RGB interface. */ -#include #include #include #include @@ -119,7 +118,7 @@ #define CMD_BUFSIZE 16 -#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) +#define POWER_IS_ON(pwr) ((pwr) <= LCD_POWER_REDUCED) #define set_tx_byte(b) (tx_invert ? ~(b) : b) @@ -513,7 +512,7 @@ static int ili922x_probe(struct spi_device *spi) ili922x_display_init(spi); - ili->power = FB_BLANK_POWERDOWN; + ili->power = LCD_POWER_OFF; lcd = devm_lcd_device_register(&spi->dev, "ili922xlcd", &spi->dev, ili, &ili922x_ops); @@ -525,7 +524,7 @@ static int ili922x_probe(struct spi_device *spi) ili->ld = lcd; spi_set_drvdata(spi, ili); - ili922x_lcd_power(ili, FB_BLANK_UNBLANK); + ili922x_lcd_power(ili, LCD_POWER_ON); return 0; } diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c index 3e318d1891b630..2df96a882119fd 100644 --- a/drivers/video/backlight/ili9320.c +++ b/drivers/video/backlight/ili9320.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include @@ -121,7 +120,7 @@ static inline int ili9320_power_off(struct ili9320 *lcd) return 0; } -#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) +#define POWER_IS_ON(pwr) ((pwr) <= LCD_POWER_REDUCED) static int ili9320_power(struct ili9320 *lcd, int power) { @@ -223,7 +222,7 @@ int ili9320_probe_spi(struct spi_device *spi, ili->dev = dev; ili->client = client; - ili->power = FB_BLANK_POWERDOWN; + ili->power = LCD_POWER_OFF; ili->platdata = cfg; spi_set_drvdata(spi, ili); @@ -241,7 +240,7 @@ int ili9320_probe_spi(struct spi_device *spi, dev_info(dev, "initialising %s\n", client->name); - ret = ili9320_power(ili, FB_BLANK_UNBLANK); + ret = ili9320_power(ili, LCD_POWER_ON); if (ret != 0) { dev_err(dev, "failed to set lcd power state\n"); return ret; @@ -253,7 +252,7 @@ EXPORT_SYMBOL_GPL(ili9320_probe_spi); void ili9320_remove(struct ili9320 *ili) { - ili9320_power(ili, FB_BLANK_POWERDOWN); + ili9320_power(ili, LCD_POWER_OFF); } EXPORT_SYMBOL_GPL(ili9320_remove); @@ -262,7 +261,7 @@ int ili9320_suspend(struct ili9320 *lcd) { int ret; - ret = ili9320_power(lcd, FB_BLANK_POWERDOWN); + ret = ili9320_power(lcd, LCD_POWER_OFF); if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) { ili9320_write(lcd, ILI9320_POWER1, lcd->power1 | @@ -282,7 +281,7 @@ int ili9320_resume(struct ili9320 *lcd) if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) ili9320_write(lcd, ILI9320_POWER1, 0x00); - return ili9320_power(lcd, FB_BLANK_UNBLANK); + return ili9320_power(lcd, LCD_POWER_ON); } EXPORT_SYMBOL_GPL(ili9320_resume); #endif @@ -290,7 +289,7 @@ EXPORT_SYMBOL_GPL(ili9320_resume); /* Power down all displays on reboot, poweroff or halt */ void ili9320_shutdown(struct ili9320 *lcd) { - ili9320_power(lcd, FB_BLANK_POWERDOWN); + ili9320_power(lcd, LCD_POWER_OFF); } EXPORT_SYMBOL_GPL(ili9320_shutdown); diff --git a/drivers/video/backlight/jornada720_lcd.c b/drivers/video/backlight/jornada720_lcd.c index 5c64fa61e81065..31a52dee906002 100644 --- a/drivers/video/backlight/jornada720_lcd.c +++ b/drivers/video/backlight/jornada720_lcd.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include #include @@ -23,14 +23,14 @@ static int jornada_lcd_get_power(struct lcd_device *ld) { - return PPSR & PPC_LDD2 ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; + return PPSR & PPC_LDD2 ? LCD_POWER_ON : LCD_POWER_OFF; } static int jornada_lcd_get_contrast(struct lcd_device *ld) { int ret; - if (jornada_lcd_get_power(ld) != FB_BLANK_UNBLANK) + if (jornada_lcd_get_power(ld) != LCD_POWER_ON) return 0; jornada_ssp_start(); @@ -71,7 +71,7 @@ static int jornada_lcd_set_contrast(struct lcd_device *ld, int value) static int jornada_lcd_set_power(struct lcd_device *ld, int power) { - if (power != FB_BLANK_UNBLANK) { + if (power != LCD_POWER_ON) { PPSR &= ~PPC_LDD2; PPDR |= PPC_LDD2; } else { @@ -106,7 +106,7 @@ static int jornada_lcd_probe(struct platform_device *pdev) /* lets set our default values */ jornada_lcd_set_contrast(lcd_device, LCD_DEF_CONTRAST); - jornada_lcd_set_power(lcd_device, FB_BLANK_UNBLANK); + jornada_lcd_set_power(lcd_device, LCD_POWER_ON); /* give it some time to startup */ msleep(100); diff --git a/drivers/video/backlight/ktd2801-backlight.c b/drivers/video/backlight/ktd2801-backlight.c index d295c27660251f..0489b0615cebc9 100644 --- a/drivers/video/backlight/ktd2801-backlight.c +++ b/drivers/video/backlight/ktd2801-backlight.c @@ -122,7 +122,7 @@ static struct platform_driver ktd2801_backlight_driver = { }; module_platform_driver(ktd2801_backlight_driver); -MODULE_IMPORT_NS(EXPRESSWIRE); +MODULE_IMPORT_NS("EXPRESSWIRE"); MODULE_AUTHOR("Duje Mihanović "); MODULE_DESCRIPTION("Kinetic KTD2801 Backlight Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/ktz8866.c b/drivers/video/backlight/ktz8866.c index 2e508741c0af64..351c2b4d63ed72 100644 --- a/drivers/video/backlight/ktz8866.c +++ b/drivers/video/backlight/ktz8866.c @@ -190,6 +190,7 @@ static const struct of_device_id ktz8866_match_table[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, ktz8866_match_table); static struct i2c_driver ktz8866_driver = { .driver = { diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 4175a460307112..d04d2256306e8a 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -112,40 +112,40 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) const u16 slpin = 0x10; const u16 disoff = 0x28; - if (power <= FB_BLANK_NORMAL) { - if (priv->lcd_state <= FB_BLANK_NORMAL) { + if (power <= LCD_POWER_REDUCED) { + if (priv->lcd_state <= LCD_POWER_REDUCED) { /* Do nothing, the LCD is running */ - } else if (priv->lcd_state < FB_BLANK_POWERDOWN) { + } else if (priv->lcd_state < LCD_POWER_OFF) { dev_dbg(&spi->dev, "Resuming LCD\n"); spi_write(spi, (const u8 *)&slpout, sizeof(u16)); msleep(60); spi_write(spi, (const u8 *)&dison, sizeof(u16)); } else { - /* priv->lcd_state == FB_BLANK_POWERDOWN */ + /* priv->lcd_state == LCD_POWER_OFF */ l4f00242t03_lcd_init(spi); - priv->lcd_state = FB_BLANK_VSYNC_SUSPEND; + priv->lcd_state = LCD_POWER_REDUCED_VSYNC_SUSPEND; l4f00242t03_lcd_power_set(priv->ld, power); } - } else if (power < FB_BLANK_POWERDOWN) { - if (priv->lcd_state <= FB_BLANK_NORMAL) { + } else if (power < LCD_POWER_OFF) { + if (priv->lcd_state <= LCD_POWER_REDUCED) { /* Send the display in standby */ dev_dbg(&spi->dev, "Standby the LCD\n"); spi_write(spi, (const u8 *)&disoff, sizeof(u16)); msleep(60); spi_write(spi, (const u8 *)&slpin, sizeof(u16)); - } else if (priv->lcd_state < FB_BLANK_POWERDOWN) { + } else if (priv->lcd_state < LCD_POWER_OFF) { /* Do nothing, the LCD is already in standby */ } else { - /* priv->lcd_state == FB_BLANK_POWERDOWN */ + /* priv->lcd_state == LCD_POWER_OFF */ l4f00242t03_lcd_init(spi); - priv->lcd_state = FB_BLANK_UNBLANK; + priv->lcd_state = LCD_POWER_ON; l4f00242t03_lcd_power_set(ld, power); } } else { - /* power == FB_BLANK_POWERDOWN */ - if (priv->lcd_state != FB_BLANK_POWERDOWN) { + /* power == LCD_POWER_OFF */ + if (priv->lcd_state != LCD_POWER_OFF) { /* Clear the screen before shutting down */ spi_write(spi, (const u8 *)&disoff, sizeof(u16)); msleep(60); @@ -212,8 +212,8 @@ static int l4f00242t03_probe(struct spi_device *spi) /* Init the LCD */ l4f00242t03_lcd_init(spi); - priv->lcd_state = FB_BLANK_VSYNC_SUSPEND; - l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_UNBLANK); + priv->lcd_state = LCD_POWER_REDUCED_VSYNC_SUSPEND; + l4f00242t03_lcd_power_set(priv->ld, LCD_POWER_ON); dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n"); @@ -224,7 +224,7 @@ static void l4f00242t03_remove(struct spi_device *spi) { struct l4f00242t03_priv *priv = spi_get_drvdata(spi); - l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); + l4f00242t03_lcd_power_set(priv->ld, LCD_POWER_OFF); } static void l4f00242t03_shutdown(struct spi_device *spi) @@ -232,7 +232,7 @@ static void l4f00242t03_shutdown(struct spi_device *spi) struct l4f00242t03_priv *priv = spi_get_drvdata(spi); if (priv) - l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN); + l4f00242t03_lcd_power_set(priv->ld, LCD_POWER_OFF); } diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index ceec90ca758b83..3267acf8dc5b12 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -20,6 +20,24 @@ #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ defined(CONFIG_LCD_CLASS_DEVICE_MODULE)) +static int to_lcd_power(int fb_blank) +{ + switch (fb_blank) { + case FB_BLANK_UNBLANK: + return LCD_POWER_ON; + /* deprecated; TODO: should become 'off' */ + case FB_BLANK_NORMAL: + return LCD_POWER_REDUCED; + case FB_BLANK_VSYNC_SUSPEND: + return LCD_POWER_REDUCED_VSYNC_SUSPEND; + /* 'off' */ + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + default: + return LCD_POWER_OFF; + } +} + /* This callback gets called when something important happens inside a * framebuffer driver. We're looking if that important event is blanking, * and if it is, we're switching lcd power as well ... @@ -27,24 +45,32 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { - struct lcd_device *ld; + struct lcd_device *ld = container_of(self, struct lcd_device, fb_notif); struct fb_event *evdata = data; + struct fb_info *info = evdata->info; + struct lcd_device *fb_lcd = fb_lcd_device(info); + + guard(mutex)(&ld->ops_lock); - ld = container_of(self, struct lcd_device, fb_notif); if (!ld->ops) return 0; + if (ld->ops->controls_device && !ld->ops->controls_device(ld, info->device)) + return 0; + if (fb_lcd && fb_lcd != ld) + return 0; - mutex_lock(&ld->ops_lock); - if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) { - if (event == FB_EVENT_BLANK) { - if (ld->ops->set_power) - ld->ops->set_power(ld, *(int *)evdata->data); - } else { - if (ld->ops->set_mode) - ld->ops->set_mode(ld, evdata->data); - } + if (event == FB_EVENT_BLANK) { + int power = to_lcd_power(*(int *)evdata->data); + + if (ld->ops->set_power) + ld->ops->set_power(ld, power); + } else { + const struct fb_videomode *videomode = evdata->data; + + if (ld->ops->set_mode) + ld->ops->set_mode(ld, videomode->xres, videomode->yres); } - mutex_unlock(&ld->ops_lock); + return 0; } diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c index c7aefcd6e4e3e3..ae34d1ecbfbef7 100644 --- a/drivers/video/backlight/led_bl.c +++ b/drivers/video/backlight/led_bl.c @@ -246,7 +246,7 @@ static struct platform_driver led_bl_driver = { .of_match_table = led_bl_of_match, }, .probe = led_bl_probe, - .remove_new = led_bl_remove, + .remove = 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 5d06f8ca976cd4..babfd3ceec8663 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -387,7 +387,7 @@ static struct platform_driver lm3533_bl_driver = { .pm = &lm3533_bl_pm_ops, }, .probe = lm3533_bl_probe, - .remove_new = lm3533_bl_remove, + .remove = lm3533_bl_remove, .shutdown = lm3533_bl_shutdown, }; module_platform_driver(lm3533_bl_driver); diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index a65490e83d3de4..c8b7eeeb333e0b 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -126,7 +126,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power) struct lms283gf05_state *st = lcd_get_data(ld); struct spi_device *spi = st->spi; - if (power <= FB_BLANK_NORMAL) { + if (power <= LCD_POWER_REDUCED) { if (st->reset) lms283gf05_reset(st->reset); lms283gf05_toggle(spi, disp_initseq, ARRAY_SIZE(disp_initseq)); diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c index 8aebe0af3391ac..28721b48b4c784 100644 --- a/drivers/video/backlight/lms501kf03.c +++ b/drivers/video/backlight/lms501kf03.c @@ -6,9 +6,7 @@ * Author: Jingoo Han */ -#include #include -#include #include #include #include @@ -206,7 +204,7 @@ static int lms501kf03_ldi_disable(struct lms501kf03 *lcd) static int lms501kf03_power_is_on(int power) { - return (power) <= FB_BLANK_NORMAL; + return (power) <= LCD_POWER_REDUCED; } static int lms501kf03_power_on(struct lms501kf03 *lcd) @@ -295,8 +293,8 @@ static int lms501kf03_set_power(struct lcd_device *ld, int power) { struct lms501kf03 *lcd = lcd_get_data(ld); - if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && - power != FB_BLANK_NORMAL) { + if (power != LCD_POWER_ON && power != LCD_POWER_OFF && + power != LCD_POWER_REDUCED) { dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); return -EINVAL; } @@ -350,11 +348,11 @@ static int lms501kf03_probe(struct spi_device *spi) * current lcd status is powerdown and then * it enables lcd panel. */ - lcd->power = FB_BLANK_POWERDOWN; + lcd->power = LCD_POWER_OFF; - lms501kf03_power(lcd, FB_BLANK_UNBLANK); + lms501kf03_power(lcd, LCD_POWER_ON); } else { - lcd->power = FB_BLANK_UNBLANK; + lcd->power = LCD_POWER_ON; } spi_set_drvdata(spi, lcd); @@ -368,7 +366,7 @@ static void lms501kf03_remove(struct spi_device *spi) { struct lms501kf03 *lcd = spi_get_drvdata(spi); - lms501kf03_power(lcd, FB_BLANK_POWERDOWN); + lms501kf03_power(lcd, LCD_POWER_OFF); } #ifdef CONFIG_PM_SLEEP @@ -382,16 +380,16 @@ static int lms501kf03_suspend(struct device *dev) * when lcd panel is suspend, lcd panel becomes off * regardless of status. */ - return lms501kf03_power(lcd, FB_BLANK_POWERDOWN); + return lms501kf03_power(lcd, LCD_POWER_OFF); } static int lms501kf03_resume(struct device *dev) { struct lms501kf03 *lcd = dev_get_drvdata(dev); - lcd->power = FB_BLANK_POWERDOWN; + lcd->power = LCD_POWER_OFF; - return lms501kf03_power(lcd, FB_BLANK_UNBLANK); + return lms501kf03_power(lcd, LCD_POWER_ON); } #endif @@ -402,7 +400,7 @@ static void lms501kf03_shutdown(struct spi_device *spi) { struct lms501kf03 *lcd = spi_get_drvdata(spi); - lms501kf03_power(lcd, FB_BLANK_POWERDOWN); + lms501kf03_power(lcd, LCD_POWER_OFF); } static struct spi_driver lms501kf03_driver = { diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c index 0b7663519fa5f4..f61a64905a02dc 100644 --- a/drivers/video/backlight/lp8788_bl.c +++ b/drivers/video/backlight/lp8788_bl.c @@ -177,7 +177,7 @@ static void lp8788_backlight_remove(struct platform_device *pdev) static struct platform_driver lp8788_bl_driver = { .probe = lp8788_backlight_probe, - .remove_new = lp8788_backlight_remove, + .remove = lp8788_backlight_remove, .driver = { .name = LP8788_DEV_BACKLIGHT, }, diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index cdc4c087f23019..c919b0fe4cd9bc 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include @@ -15,7 +14,7 @@ #include "ltv350qv.h" -#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) +#define POWER_IS_ON(pwr) ((pwr) <= LCD_POWER_REDUCED) struct ltv350qv { struct spi_device *spi; @@ -233,7 +232,7 @@ static int ltv350qv_probe(struct spi_device *spi) return -ENOMEM; lcd->spi = spi; - lcd->power = FB_BLANK_POWERDOWN; + lcd->power = LCD_POWER_OFF; lcd->buffer = devm_kzalloc(&spi->dev, 8, GFP_KERNEL); if (!lcd->buffer) return -ENOMEM; @@ -245,7 +244,7 @@ static int ltv350qv_probe(struct spi_device *spi) lcd->ld = ld; - ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK); + ret = ltv350qv_power(lcd, LCD_POWER_ON); if (ret) return ret; @@ -258,7 +257,7 @@ static void ltv350qv_remove(struct spi_device *spi) { struct ltv350qv *lcd = spi_get_drvdata(spi); - ltv350qv_power(lcd, FB_BLANK_POWERDOWN); + ltv350qv_power(lcd, LCD_POWER_OFF); } #ifdef CONFIG_PM_SLEEP @@ -266,14 +265,14 @@ static int ltv350qv_suspend(struct device *dev) { struct ltv350qv *lcd = dev_get_drvdata(dev); - return ltv350qv_power(lcd, FB_BLANK_POWERDOWN); + return ltv350qv_power(lcd, LCD_POWER_OFF); } static int ltv350qv_resume(struct device *dev) { struct ltv350qv *lcd = dev_get_drvdata(dev); - return ltv350qv_power(lcd, FB_BLANK_UNBLANK); + return ltv350qv_power(lcd, LCD_POWER_ON); } #endif @@ -284,7 +283,7 @@ static void ltv350qv_shutdown(struct spi_device *spi) { struct ltv350qv *lcd = spi_get_drvdata(spi); - ltv350qv_power(lcd, FB_BLANK_POWERDOWN); + ltv350qv_power(lcd, LCD_POWER_OFF); } static struct spi_driver ltv350qv_driver = { diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c index 94422c956453d8..e55f26888d0fb9 100644 --- a/drivers/video/backlight/mt6370-backlight.c +++ b/drivers/video/backlight/mt6370-backlight.c @@ -340,7 +340,7 @@ static struct platform_driver mt6370_bl_driver = { .of_match_table = mt6370_bl_of_match, }, .probe = mt6370_bl_probe, - .remove_new = mt6370_bl_remove, + .remove = mt6370_bl_remove, }; module_platform_driver(mt6370_bl_driver); diff --git a/drivers/video/backlight/otm3225a.c b/drivers/video/backlight/otm3225a.c index efe52fa08b07bb..5c6575f23ea889 100644 --- a/drivers/video/backlight/otm3225a.c +++ b/drivers/video/backlight/otm3225a.c @@ -189,7 +189,7 @@ static int otm3225a_set_power(struct lcd_device *ld, int power) if (power == dd->power) return 0; - if (power > FB_BLANK_UNBLANK) + if (power > LCD_POWER_ON) otm3225a_write(dd->spi, display_off, ARRAY_SIZE(display_off)); else otm3225a_write(dd->spi, display_on, ARRAY_SIZE(display_on)); diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index b0af612834a740..c9fe50f4d8ed20 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -9,8 +9,6 @@ #include #include -#include -#include #include #include @@ -42,7 +40,7 @@ static int platform_lcd_set_power(struct lcd_device *lcd, int power) struct platform_lcd *plcd = to_our_lcd(lcd); int lcd_power = 1; - if (power == FB_BLANK_POWERDOWN || plcd->suspended) + if (power == LCD_POWER_OFF || plcd->suspended) lcd_power = 0; plcd->pdata->set_power(plcd->pdata, lcd_power); @@ -51,21 +49,17 @@ static int platform_lcd_set_power(struct lcd_device *lcd, int power) return 0; } -static int platform_lcd_match(struct lcd_device *lcd, struct fb_info *info) +static bool platform_lcd_controls_device(struct lcd_device *lcd, struct device *display_device) { struct platform_lcd *plcd = to_our_lcd(lcd); - struct plat_lcd_data *pdata = plcd->pdata; - if (pdata->match_fb) - return pdata->match_fb(pdata, info); - - return plcd->us->parent == info->device; + return plcd->us->parent == display_device; } static const struct lcd_ops platform_lcd_ops = { - .get_power = platform_lcd_get_power, - .set_power = platform_lcd_set_power, - .check_fb = platform_lcd_match, + .get_power = platform_lcd_get_power, + .set_power = platform_lcd_set_power, + .controls_device = platform_lcd_controls_device, }; static int platform_lcd_probe(struct platform_device *pdev) @@ -102,7 +96,7 @@ static int platform_lcd_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, plcd); - platform_lcd_set_power(plcd->lcd, FB_BLANK_NORMAL); + platform_lcd_set_power(plcd->lcd, LCD_POWER_REDUCED); return 0; } diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index e942908d1275fe..237d3d3f3bb1a6 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -697,7 +697,7 @@ static struct platform_driver pwm_backlight_driver = { .of_match_table = of_match_ptr(pwm_backlight_of_match), }, .probe = pwm_backlight_probe, - .remove_new = pwm_backlight_remove, + .remove = pwm_backlight_remove, .shutdown = pwm_backlight_shutdown, }; diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index 10129095a4c178..9afe701b2a1b64 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -1741,7 +1741,7 @@ MODULE_DEVICE_TABLE(of, wled_match_table); static struct platform_driver wled_driver = { .probe = wled_probe, - .remove_new = wled_remove, + .remove = 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 c2f6fb29e1d04b..7ead75929a437a 100644 --- a/drivers/video/backlight/rt4831-backlight.c +++ b/drivers/video/backlight/rt4831-backlight.c @@ -224,7 +224,7 @@ static struct platform_driver rt4831_bl_driver = { .of_match_table = rt4831_bl_of_match, }, .probe = rt4831_bl_probe, - .remove_new = rt4831_bl_remove, + .remove = 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 935043b6778698..2749231f038544 100644 --- a/drivers/video/backlight/sky81452-backlight.c +++ b/drivers/video/backlight/sky81452-backlight.c @@ -337,7 +337,7 @@ static struct platform_driver sky81452_bl_driver = { .of_match_table = of_match_ptr(sky81452_bl_of_match), }, .probe = sky81452_bl_probe, - .remove_new = sky81452_bl_remove, + .remove = sky81452_bl_remove, }; module_platform_driver(sky81452_bl_driver); diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index c413b3c68e954e..c04ee3d04d8793 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -12,11 +12,10 @@ #include #include #include -#include #include #include -#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) +#define POWER_IS_ON(pwr) ((pwr) <= LCD_POWER_REDUCED) #define TDO24M_SPI_BUFF_SIZE (4) #define MODE_QVGA 0 @@ -308,12 +307,12 @@ static int tdo24m_get_power(struct lcd_device *ld) return lcd->power; } -static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m) +static int tdo24m_set_mode(struct lcd_device *ld, u32 xres, u32 yres) { struct tdo24m *lcd = lcd_get_data(ld); int mode = MODE_QVGA; - if (m->xres == 640 || m->xres == 480) + if (xres == 640 || xres == 480) mode = MODE_VGA; if (lcd->mode == mode) @@ -354,7 +353,7 @@ static int tdo24m_probe(struct spi_device *spi) return -ENOMEM; lcd->spi_dev = spi; - lcd->power = FB_BLANK_POWERDOWN; + lcd->power = LCD_POWER_OFF; lcd->mode = MODE_VGA; /* default to VGA */ lcd->buf = devm_kzalloc(&spi->dev, TDO24M_SPI_BUFF_SIZE, GFP_KERNEL); @@ -390,7 +389,7 @@ static int tdo24m_probe(struct spi_device *spi) return PTR_ERR(lcd->lcd_dev); spi_set_drvdata(spi, lcd); - err = tdo24m_power(lcd, FB_BLANK_UNBLANK); + err = tdo24m_power(lcd, LCD_POWER_ON); if (err) return err; @@ -401,7 +400,7 @@ static void tdo24m_remove(struct spi_device *spi) { struct tdo24m *lcd = spi_get_drvdata(spi); - tdo24m_power(lcd, FB_BLANK_POWERDOWN); + tdo24m_power(lcd, LCD_POWER_OFF); } #ifdef CONFIG_PM_SLEEP @@ -409,14 +408,14 @@ static int tdo24m_suspend(struct device *dev) { struct tdo24m *lcd = dev_get_drvdata(dev); - return tdo24m_power(lcd, FB_BLANK_POWERDOWN); + return tdo24m_power(lcd, LCD_POWER_OFF); } static int tdo24m_resume(struct device *dev) { struct tdo24m *lcd = dev_get_drvdata(dev); - return tdo24m_power(lcd, FB_BLANK_UNBLANK); + return tdo24m_power(lcd, LCD_POWER_ON); } #endif @@ -427,7 +426,7 @@ static void tdo24m_shutdown(struct spi_device *spi) { struct tdo24m *lcd = spi_get_drvdata(spi); - tdo24m_power(lcd, FB_BLANK_POWERDOWN); + tdo24m_power(lcd, LCD_POWER_OFF); } static struct spi_driver tdo24m_driver = { diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index de035071fedb1b..55c6686f091e79 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -649,6 +649,7 @@ config FB_S1D13XXX config FB_ATMEL tristate "AT91 LCD Controller support" depends on FB && OF && HAVE_CLK && HAS_IOMEM + depends on BACKLIGHT_CLASS_DEVICE depends on HAVE_FB_ATMEL || COMPILE_TEST select FB_BACKLIGHT select FB_IOMEM_HELPERS @@ -660,7 +661,6 @@ config FB_ATMEL config FB_NVIDIA tristate "nVidia Framebuffer Support" depends on FB && PCI - select FB_BACKLIGHT if FB_NVIDIA_BACKLIGHT select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -700,6 +700,8 @@ config FB_NVIDIA_DEBUG config FB_NVIDIA_BACKLIGHT bool "Support for backlight control" depends on FB_NVIDIA + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_NVIDIA + select FB_BACKLIGHT default y help Say Y here if you want to control the backlight of your display. @@ -707,7 +709,6 @@ config FB_NVIDIA_BACKLIGHT config FB_RIVA tristate "nVidia Riva support" depends on FB && PCI - select FB_BACKLIGHT if FB_RIVA_BACKLIGHT select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -747,6 +748,8 @@ config FB_RIVA_DEBUG config FB_RIVA_BACKLIGHT bool "Support for backlight control" depends on FB_RIVA + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_RIVA + select FB_BACKLIGHT default y help Say Y here if you want to control the backlight of your display. @@ -934,7 +937,6 @@ config FB_MATROX_MAVEN config FB_RADEON tristate "ATI Radeon display support" depends on FB && PCI - select FB_BACKLIGHT if FB_RADEON_BACKLIGHT select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -960,6 +962,8 @@ config FB_RADEON_I2C config FB_RADEON_BACKLIGHT bool "Support for backlight control" depends on FB_RADEON + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_RADEON + select FB_BACKLIGHT default y help Say Y here if you want to control the backlight of your display. @@ -975,7 +979,6 @@ config FB_RADEON_DEBUG config FB_ATY128 tristate "ATI Rage128 display support" depends on FB && PCI - select FB_BACKLIGHT if FB_ATY128_BACKLIGHT select FB_IOMEM_HELPERS select FB_MACMODES if PPC_PMAC help @@ -989,6 +992,8 @@ config FB_ATY128 config FB_ATY128_BACKLIGHT bool "Support for backlight control" depends on FB_ATY128 + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_ATY128 + select FB_BACKLIGHT default y help Say Y here if you want to control the backlight of your display. @@ -999,7 +1004,6 @@ config FB_ATY select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_BACKLIGHT if FB_ATY_BACKLIGHT select FB_IOMEM_FOPS select FB_MACMODES if PPC select FB_ATY_CT if SPARC64 && PCI @@ -1040,6 +1044,8 @@ config FB_ATY_GX config FB_ATY_BACKLIGHT bool "Support for backlight control" depends on FB_ATY + depends on BACKLIGHT_CLASS_DEVICE=y || BACKLIGHT_CLASS_DEVICE=FB_ATY + select FB_BACKLIGHT default y help Say Y here if you want to control the backlight of your display. @@ -1528,6 +1534,7 @@ config FB_SH_MOBILE_LCDC depends on FB && HAVE_CLK && HAS_IOMEM depends on SUPERH || COMPILE_TEST depends on FB_DEVICE + depends on BACKLIGHT_CLASS_DEVICE select FB_BACKLIGHT select FB_DEFERRED_IO select FB_DMAMEM_HELPERS @@ -1793,6 +1800,7 @@ config FB_SSD1307 tristate "Solomon SSD1307 framebuffer support" depends on FB && I2C depends on GPIOLIB || COMPILE_TEST + depends on BACKLIGHT_CLASS_DEVICE select FB_BACKLIGHT select FB_SYSMEM_HELPERS_DEFERRED help diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index e13f53965a0d4e..9dfbc531021073 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -152,7 +152,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo) } sinfo->backlight = bl; - bl->props.power = FB_BLANK_UNBLANK; + bl->props.power = BACKLIGHT_POWER_ON; bl->props.brightness = atmel_bl_get_brightness(bl); } @@ -162,7 +162,7 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo) return; if (sinfo->backlight->ops) { - sinfo->backlight->props.power = FB_BLANK_POWERDOWN; + sinfo->backlight->props.power = BACKLIGHT_POWER_OFF; sinfo->backlight->ops->update_status(sinfo->backlight); } backlight_device_unregister(sinfo->backlight); diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index f4de11f1923577..f55b4c7609a8c9 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -1299,11 +1299,11 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on) reg &= ~LVDS_DISPLAY_DIS; aty_st_le32(LVDS_GEN_CNTL, reg); #ifdef CONFIG_FB_ATY128_BACKLIGHT - aty128_bl_set_power(info, FB_BLANK_UNBLANK); + aty128_bl_set_power(info, BACKLIGHT_POWER_ON); #endif } else { #ifdef CONFIG_FB_ATY128_BACKLIGHT - aty128_bl_set_power(info, FB_BLANK_POWERDOWN); + aty128_bl_set_power(info, BACKLIGHT_POWER_OFF); #endif reg = aty_ld_le32(LVDS_GEN_CNTL); reg |= LVDS_DISPLAY_DIS; @@ -1858,7 +1858,7 @@ static void aty128_bl_init(struct aty128fb_par *par) 219 * FB_BACKLIGHT_MAX / MAX_LEVEL); bd->props.brightness = bd->props.max_brightness; - bd->props.power = FB_BLANK_UNBLANK; + bd->props.power = BACKLIGHT_POWER_ON; backlight_update_status(bd); printk("aty128: Backlight initialized (%s)\n", name); diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index a6dd1cd2712535..210fd3ac18a480 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -2272,7 +2272,7 @@ static void aty_bl_init(struct atyfb_par *par) 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL); bd->props.brightness = bd->props.max_brightness; - bd->props.power = FB_BLANK_UNBLANK; + bd->props.power = BACKLIGHT_POWER_ON; backlight_update_status(bd); printk("aty: Backlight initialized (%s)\n", name); diff --git a/drivers/video/fbdev/aty/radeon_backlight.c b/drivers/video/fbdev/aty/radeon_backlight.c index 23a38c3f3977e6..9e41d2a18649e4 100644 --- a/drivers/video/fbdev/aty/radeon_backlight.c +++ b/drivers/video/fbdev/aty/radeon_backlight.c @@ -179,7 +179,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL); bd->props.brightness = bd->props.max_brightness; - bd->props.power = FB_BLANK_UNBLANK; + bd->props.power = BACKLIGHT_POWER_ON; backlight_update_status(bd); printk("radeonfb: Backlight initialized (%s)\n", name); diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c index b16a905588fed4..33caf0b99a452a 100644 --- a/drivers/video/fbdev/chipsfb.c +++ b/drivers/video/fbdev/chipsfb.c @@ -399,7 +399,7 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) /* turn on the backlight */ mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { - pmac_backlight->props.power = FB_BLANK_UNBLANK; + pmac_backlight->props.power = BACKLIGHT_POWER_ON; backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex); diff --git a/drivers/video/fbdev/clps711x-fb.c b/drivers/video/fbdev/clps711x-fb.c index 0d0ba617b4aa87..5e61a349a4ab61 100644 --- a/drivers/video/fbdev/clps711x-fb.c +++ b/drivers/video/fbdev/clps711x-fb.c @@ -162,22 +162,15 @@ static const struct fb_ops clps711x_fb_ops = { .fb_blank = clps711x_fb_blank, }; -static int clps711x_lcd_check_fb(struct lcd_device *lcddev, struct fb_info *fi) -{ - struct clps711x_fb_info *cfb = dev_get_drvdata(&lcddev->dev); - - return (!fi || fi->par == cfb) ? 1 : 0; -} - static int clps711x_lcd_get_power(struct lcd_device *lcddev) { struct clps711x_fb_info *cfb = dev_get_drvdata(&lcddev->dev); if (!IS_ERR_OR_NULL(cfb->lcd_pwr)) if (!regulator_is_enabled(cfb->lcd_pwr)) - return FB_BLANK_NORMAL; + return LCD_POWER_REDUCED; - return FB_BLANK_UNBLANK; + return LCD_POWER_ON; } static int clps711x_lcd_set_power(struct lcd_device *lcddev, int blank) @@ -185,7 +178,7 @@ static int clps711x_lcd_set_power(struct lcd_device *lcddev, int blank) struct clps711x_fb_info *cfb = dev_get_drvdata(&lcddev->dev); if (!IS_ERR_OR_NULL(cfb->lcd_pwr)) { - if (blank == FB_BLANK_UNBLANK) { + if (blank == LCD_POWER_ON) { if (!regulator_is_enabled(cfb->lcd_pwr)) return regulator_enable(cfb->lcd_pwr); } else { @@ -198,7 +191,6 @@ static int clps711x_lcd_set_power(struct lcd_device *lcddev, int blank) } static const struct lcd_ops clps711x_lcd_ops = { - .check_fb = clps711x_lcd_check_fb, .get_power = clps711x_lcd_get_power, .set_power = clps711x_lcd_set_power, }; @@ -325,16 +317,21 @@ static int clps711x_fb_probe(struct platform_device *pdev) if (ret) goto out_fb_dealloc_cmap; + lcd = devm_lcd_device_register(dev, "clps711x-lcd", dev, cfb, + &clps711x_lcd_ops); + if (IS_ERR(lcd)) { + ret = PTR_ERR(lcd); + goto out_fb_dealloc_cmap; + } + + info->lcd_dev = lcd; + ret = register_framebuffer(info); if (ret) goto out_fb_dealloc_cmap; - lcd = devm_lcd_device_register(dev, "clps711x-lcd", dev, cfb, - &clps711x_lcd_ops); - if (!IS_ERR(lcd)) - return 0; + return 0; - ret = PTR_ERR(lcd); unregister_framebuffer(info); out_fb_dealloc_cmap: diff --git a/drivers/video/fbdev/core/Kconfig b/drivers/video/fbdev/core/Kconfig index 0ab8848ba2f10f..d554d8c543d492 100644 --- a/drivers/video/fbdev/core/Kconfig +++ b/drivers/video/fbdev/core/Kconfig @@ -183,9 +183,8 @@ config FB_SYSMEM_HELPERS_DEFERRED select FB_SYSMEM_HELPERS config FB_BACKLIGHT - tristate + bool depends on FB - select BACKLIGHT_CLASS_DEVICE config FB_MODE_HELPERS bool "Enable Video Mode Handling Helpers" diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c index ff343e4ed35ba5..f30da32cdaed4d 100644 --- a/drivers/video/fbdev/imxfb.c +++ b/drivers/video/fbdev/imxfb.c @@ -782,16 +782,6 @@ static int imxfb_of_read_mode(struct device *dev, struct device_node *np, return 0; } -static int imxfb_lcd_check_fb(struct lcd_device *lcddev, struct fb_info *fi) -{ - struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev); - - if (!fi || fi->par == fbi) - return 1; - - return 0; -} - static int imxfb_lcd_get_contrast(struct lcd_device *lcddev) { struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev); @@ -824,9 +814,9 @@ static int imxfb_lcd_get_power(struct lcd_device *lcddev) if (!IS_ERR(fbi->lcd_pwr) && !regulator_is_enabled(fbi->lcd_pwr)) - return FB_BLANK_POWERDOWN; + return LCD_POWER_OFF; - return FB_BLANK_UNBLANK; + return LCD_POWER_ON; } static int imxfb_regulator_set(struct imxfb_info *fbi, int enable) @@ -852,13 +842,12 @@ static int imxfb_lcd_set_power(struct lcd_device *lcddev, int power) struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev); if (!IS_ERR(fbi->lcd_pwr)) - return imxfb_regulator_set(fbi, power == FB_BLANK_UNBLANK); + return imxfb_regulator_set(fbi, power == LCD_POWER_ON); return 0; } static const struct lcd_ops imxfb_lcd_ops = { - .check_fb = imxfb_lcd_check_fb, .get_contrast = imxfb_lcd_get_contrast, .set_contrast = imxfb_lcd_set_contrast, .get_power = imxfb_lcd_get_power, @@ -1025,11 +1014,6 @@ static int imxfb_probe(struct platform_device *pdev) goto failed_cmap; imxfb_set_par(info); - ret = register_framebuffer(info); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register framebuffer\n"); - goto failed_register; - } fbi->lcd_pwr = devm_regulator_get(&pdev->dev, "lcd"); if (PTR_ERR(fbi->lcd_pwr) == -EPROBE_DEFER) { @@ -1046,13 +1030,19 @@ static int imxfb_probe(struct platform_device *pdev) lcd->props.max_contrast = 0xff; + info->lcd_dev = lcd; + + ret = register_framebuffer(info); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register framebuffer\n"); + goto failed_lcd; + } + imxfb_enable_controller(fbi); return 0; failed_lcd: - unregister_framebuffer(info); -failed_register: fb_dealloc_cmap(&info->cmap); failed_cmap: dma_free_wc(&pdev->dev, fbi->map_size, info->screen_buffer, diff --git a/drivers/video/fbdev/mmp/hw/mmp_spi.c b/drivers/video/fbdev/mmp/hw/mmp_spi.c index cf23650d7f0b71..3f253f4271ac9c 100644 --- a/drivers/video/fbdev/mmp/hw/mmp_spi.c +++ b/drivers/video/fbdev/mmp/hw/mmp_spi.c @@ -140,9 +140,9 @@ int lcd_spi_register(struct mmphw_ctrl *ctrl) void **p_regbase; int err; - ctlr = spi_alloc_master(ctrl->dev, sizeof(void *)); + ctlr = spi_alloc_host(ctrl->dev, sizeof(void *)); if (!ctlr) { - dev_err(ctrl->dev, "unable to allocate SPI master\n"); + dev_err(ctrl->dev, "unable to allocate SPI host\n"); return -ENOMEM; } p_regbase = spi_controller_get_devdata(ctlr); @@ -156,7 +156,7 @@ int lcd_spi_register(struct mmphw_ctrl *ctrl) err = spi_register_controller(ctlr); if (err < 0) { - dev_err(ctrl->dev, "unable to register SPI master\n"); + dev_err(ctrl->dev, "unable to register SPI host\n"); spi_controller_put(ctlr); return err; } diff --git a/drivers/video/fbdev/nvidia/nv_backlight.c b/drivers/video/fbdev/nvidia/nv_backlight.c index 160da9c50a52c9..7edd47ab16e9f1 100644 --- a/drivers/video/fbdev/nvidia/nv_backlight.c +++ b/drivers/video/fbdev/nvidia/nv_backlight.c @@ -112,7 +112,7 @@ void nvidia_bl_init(struct nvidia_par *par) 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL); bd->props.brightness = bd->props.max_brightness; - bd->props.power = FB_BLANK_UNBLANK; + bd->props.power = BACKLIGHT_POWER_ON; backlight_update_status(bd); printk("nvidia: Backlight initialized (%s)\n", name); diff --git a/drivers/video/fbdev/omap/lcd_ams_delta.c b/drivers/video/fbdev/omap/lcd_ams_delta.c index 97e2b71b64d7f8..456e6e9e11a9be 100644 --- a/drivers/video/fbdev/omap/lcd_ams_delta.c +++ b/drivers/video/fbdev/omap/lcd_ams_delta.c @@ -32,7 +32,7 @@ static struct gpio_desc *gpiod_ndisp; static int ams_delta_lcd_set_power(struct lcd_device *dev, int power) { - if (power == FB_BLANK_UNBLANK) { + if (power == LCD_POWER_ON) { if (!(ams_delta_lcd & AMS_DELTA_LCD_POWER)) { omap_writeb(ams_delta_lcd & AMS_DELTA_MAX_CONTRAST, OMAP_PWL_ENABLE); @@ -63,9 +63,9 @@ static int ams_delta_lcd_set_contrast(struct lcd_device *dev, int value) static int ams_delta_lcd_get_power(struct lcd_device *dev) { if (ams_delta_lcd & AMS_DELTA_LCD_POWER) - return FB_BLANK_UNBLANK; + return LCD_POWER_ON; else - return FB_BLANK_POWERDOWN; + return LCD_POWER_OFF; } static int ams_delta_lcd_get_contrast(struct lcd_device *dev) @@ -155,7 +155,7 @@ static int ams_delta_panel_probe(struct platform_device *pdev) #endif ams_delta_lcd_set_contrast(lcd_device, AMS_DELTA_DEFAULT_CONTRAST); - ams_delta_lcd_set_power(lcd_device, FB_BLANK_UNBLANK); + ams_delta_lcd_set_power(lcd_device, LCD_POWER_ON); omapfb_register_panel(&ams_delta_panel); return 0; diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index 4a0df640ab6484..1d75f27c6b80f0 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -1215,7 +1215,7 @@ static int dsicm_probe(struct platform_device *pdev) ddata->bldev = bldev; - bldev->props.power = FB_BLANK_UNBLANK; + bldev->props.power = BACKLIGHT_POWER_ON; bldev->props.brightness = 255; dsicm_bl_update_status(bldev); @@ -1253,7 +1253,7 @@ static void dsicm_remove(struct platform_device *pdev) bldev = ddata->bldev; if (bldev != NULL) { - bldev->props.power = FB_BLANK_POWERDOWN; + bldev->props.power = BACKLIGHT_POWER_OFF; dsicm_bl_update_status(bldev); backlight_device_unregister(bldev); } diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index fc975615d5c9e4..8f430d9e805496 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -754,7 +754,7 @@ static int acx565akm_probe(struct spi_device *spi) } memset(&props, 0, sizeof(props)); - props.power = FB_BLANK_UNBLANK; + props.power = BACKLIGHT_POWER_ON; props.type = BACKLIGHT_RAW; bldev = backlight_device_register("acx565akm", &ddata->spi->dev, diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c index 5832485ab998c4..c3329c8b4c169b 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c @@ -1230,17 +1230,6 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu)); } -void dispc_enable_fifomerge(bool enable) -{ - if (!dss_has_feature(FEAT_FIFO_MERGE)) { - WARN_ON(enable); - return; - } - - DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); - REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); -} - void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, bool manual_update) @@ -3656,22 +3645,6 @@ void dispc_mgr_set_clock_div(enum omap_channel channel, dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); } -int dispc_mgr_get_clock_div(enum omap_channel channel, - struct dispc_clock_info *cinfo) -{ - unsigned long fck; - - fck = dispc_fclk_rate(); - - cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16); - cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0); - - cinfo->lck = fck / cinfo->lck_div; - cinfo->pck = cinfo->lck / cinfo->pck_div; - - return 0; -} - u32 dispc_read_irqstatus(void) { return dispc_read_reg(DISPC_IRQSTATUS); diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dpi.c b/drivers/video/fbdev/omap2/omapfb/dss/dpi.c index c40b87ffe8fcbf..86ed4c077c30a2 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dpi.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dpi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -845,7 +846,7 @@ int dpi_init_port(struct platform_device *pdev, struct device_node *port) if (!dpi) return -ENOMEM; - ep = omapdss_of_get_next_endpoint(port, NULL); + ep = of_graph_get_next_port_endpoint(port, NULL); if (!ep) return 0; diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss-of.c b/drivers/video/fbdev/omap2/omapfb/dss/dss-of.c index d5a43b3bf45ec9..c04cbe0ef173d6 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dss-of.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dss-of.c @@ -15,72 +15,6 @@ #include "dss.h" -struct device_node * -omapdss_of_get_next_port(const struct device_node *parent, - struct device_node *prev) -{ - struct device_node *port = NULL; - - if (!parent) - return NULL; - - if (!prev) { - struct device_node *ports; - /* - * It's the first call, we have to find a port subnode - * within this node or within an optional 'ports' node. - */ - ports = of_get_child_by_name(parent, "ports"); - if (ports) - parent = ports; - - port = of_get_child_by_name(parent, "port"); - - /* release the 'ports' node */ - of_node_put(ports); - } else { - struct device_node *ports; - - ports = of_get_parent(prev); - if (!ports) - return NULL; - - do { - port = of_get_next_child(ports, prev); - if (!port) { - of_node_put(ports); - return NULL; - } - prev = port; - } while (!of_node_name_eq(port, "port")); - - of_node_put(ports); - } - - return port; -} -EXPORT_SYMBOL_GPL(omapdss_of_get_next_port); - -struct device_node * -omapdss_of_get_next_endpoint(const struct device_node *parent, - struct device_node *prev) -{ - struct device_node *ep = NULL; - - if (!parent) - return NULL; - - do { - ep = of_get_next_child(parent, prev); - if (!ep) - return NULL; - prev = ep; - } while (!of_node_name_eq(ep, "endpoint")); - - return ep; -} -EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint); - struct device_node *dss_of_port_get_parent_device(struct device_node *port) { struct device_node *np; diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.c b/drivers/video/fbdev/omap2/omapfb/dss/dss.c index f06debee02c5c5..3624a7fbdca82c 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dss.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -919,10 +920,7 @@ static int dss_init_ports(struct platform_device *pdev) struct device_node *port; int r, ret = 0; - if (parent == NULL) - return 0; - - port = omapdss_of_get_next_port(parent, NULL); + port = of_graph_get_next_port(parent, NULL); if (!port) return 0; @@ -952,8 +950,9 @@ static int dss_init_ports(struct platform_device *pdev) default: break; } - } while (!ret && - (port = omapdss_of_get_next_port(parent, port)) != NULL); + + port = of_graph_get_next_port(parent, port); + } while (!ret && port); if (ret) dss_uninit_ports(pdev); @@ -966,10 +965,7 @@ static void dss_uninit_ports(struct platform_device *pdev) struct device_node *parent = pdev->dev.of_node; struct device_node *port; - if (parent == NULL) - return; - - port = omapdss_of_get_next_port(parent, NULL); + port = of_graph_get_next_port(parent, NULL); if (!port) return; @@ -1000,7 +996,9 @@ static void dss_uninit_ports(struct platform_device *pdev) default: break; } - } while ((port = omapdss_of_get_next_port(parent, port)) != NULL); + + port = of_graph_get_next_port(parent, port); + } while (port); } static int dss_video_pll_probe(struct platform_device *pdev) diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.h b/drivers/video/fbdev/omap2/omapfb/dss/dss.h index 21cfcbf74a6d9d..a33a43f26829fb 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dss.h +++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.h @@ -366,7 +366,6 @@ void dispc_disable_sidle(void); void dispc_lcd_enable_signal(bool enable); void dispc_pck_free_enable(bool enable); -void dispc_enable_fifomerge(bool enable); void dispc_enable_gamma_table(bool enable); typedef bool (*dispc_div_calc_func)(int lckd, int pckd, unsigned long lck, @@ -388,8 +387,6 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, void dispc_mgr_set_clock_div(enum omap_channel channel, const struct dispc_clock_info *cinfo); -int dispc_mgr_get_clock_div(enum omap_channel channel, - struct dispc_clock_info *cinfo); void dispc_set_tv_pclk(unsigned long pclk); u32 dispc_read_irqstatus(void); diff --git a/drivers/video/fbdev/omap2/omapfb/dss/sdi.c b/drivers/video/fbdev/omap2/omapfb/dss/sdi.c index 2a45f019ef4574..2d3e5d4467c571 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/sdi.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/sdi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include ); + +/// Type alias for [`Box`] with a [`Kmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let b = KBox::new(24_u64, GFP_KERNEL)?; +/// +/// assert_eq!(*b, 24_u64); +/// # Ok::<(), Error>(()) +/// ``` +pub type KBox = Box; + +/// Type alias for [`Box`] with a [`Vmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let b = VBox::new(24_u64, GFP_KERNEL)?; +/// +/// assert_eq!(*b, 24_u64); +/// # Ok::<(), Error>(()) +/// ``` +pub type VBox = Box; + +/// Type alias for [`Box`] with a [`KVmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let b = KVBox::new(24_u64, GFP_KERNEL)?; +/// +/// assert_eq!(*b, 24_u64); +/// # Ok::<(), Error>(()) +/// ``` +pub type KVBox = Box; + +// SAFETY: `Box` is `Send` if `T` is `Send` because the `Box` owns a `T`. +unsafe impl Send for Box +where + T: Send + ?Sized, + A: Allocator, +{ +} + +// SAFETY: `Box` is `Sync` if `T` is `Sync` because the `Box` owns a `T`. +unsafe impl Sync for Box +where + T: Sync + ?Sized, + A: Allocator, +{ +} + +impl Box +where + T: ?Sized, + A: Allocator, +{ + /// Creates a new `Box` from a raw pointer. + /// + /// # Safety + /// + /// For non-ZSTs, `raw` must point at an allocation allocated with `A` that is sufficiently + /// aligned for and holds a valid `T`. The caller passes ownership of the allocation to the + /// `Box`. + /// + /// For ZSTs, `raw` must be a dangling, well aligned pointer. + #[inline] + pub const unsafe fn from_raw(raw: *mut T) -> Self { + // INVARIANT: Validity of `raw` is guaranteed by the safety preconditions of this function. + // SAFETY: By the safety preconditions of this function, `raw` is not a NULL pointer. + Self(unsafe { NonNull::new_unchecked(raw) }, PhantomData) + } + + /// Consumes the `Box` and returns a raw pointer. + /// + /// This will not run the destructor of `T` and for non-ZSTs the allocation will stay alive + /// indefinitely. Use [`Box::from_raw`] to recover the [`Box`], drop the value and free the + /// allocation, if any. + /// + /// # Examples + /// + /// ``` + /// let x = KBox::new(24, GFP_KERNEL)?; + /// let ptr = KBox::into_raw(x); + /// // SAFETY: `ptr` comes from a previous call to `KBox::into_raw`. + /// let x = unsafe { KBox::from_raw(ptr) }; + /// + /// assert_eq!(*x, 24); + /// # Ok::<(), Error>(()) + /// ``` + #[inline] + pub fn into_raw(b: Self) -> *mut T { + ManuallyDrop::new(b).0.as_ptr() + } + + /// Consumes and leaks the `Box` and returns a mutable reference. + /// + /// See [`Box::into_raw`] for more details. + #[inline] + pub fn leak<'a>(b: Self) -> &'a mut T { + // SAFETY: `Box::into_raw` always returns a properly aligned and dereferenceable pointer + // which points to an initialized instance of `T`. + unsafe { &mut *Box::into_raw(b) } + } +} + +impl Box, A> +where + A: Allocator, +{ + /// Converts a `Box, A>` to a `Box`. + /// + /// It is undefined behavior to call this function while the value inside of `b` is not yet + /// fully initialized. + /// + /// # Safety + /// + /// Callers must ensure that the value inside of `b` is in an initialized state. + pub unsafe fn assume_init(self) -> Box { + let raw = Self::into_raw(self); + + // SAFETY: `raw` comes from a previous call to `Box::into_raw`. By the safety requirements + // of this function, the value inside the `Box` is in an initialized state. Hence, it is + // safe to reconstruct the `Box` as `Box`. + unsafe { Box::from_raw(raw.cast()) } + } + + /// Writes the value and converts to `Box`. + pub fn write(mut self, value: T) -> Box { + (*self).write(value); + + // SAFETY: We've just initialized `b`'s value. + unsafe { self.assume_init() } + } +} + +impl Box +where + A: Allocator, +{ + /// Creates a new `Box` and initializes its contents with `x`. + /// + /// New memory is allocated with `A`. The allocation may fail, in which case an error is + /// returned. For ZSTs no memory is allocated. + pub fn new(x: T, flags: Flags) -> Result { + let b = Self::new_uninit(flags)?; + Ok(Box::write(b, x)) + } + + /// Creates a new `Box` with uninitialized contents. + /// + /// New memory is allocated with `A`. The allocation may fail, in which case an error is + /// returned. For ZSTs no memory is allocated. + /// + /// # Examples + /// + /// ``` + /// let b = KBox::::new_uninit(GFP_KERNEL)?; + /// let b = KBox::write(b, 24); + /// + /// assert_eq!(*b, 24_u64); + /// # Ok::<(), Error>(()) + /// ``` + pub fn new_uninit(flags: Flags) -> Result, A>, AllocError> { + let layout = Layout::new::>(); + let ptr = A::alloc(layout, flags)?; + + // INVARIANT: `ptr` is either a dangling pointer or points to memory allocated with `A`, + // which is sufficient in size and alignment for storing a `T`. + Ok(Box(ptr.cast(), PhantomData)) + } + + /// Constructs a new `Pin>`. If `T` does not implement [`Unpin`], then `x` will be + /// pinned in memory and can't be moved. + #[inline] + pub fn pin(x: T, flags: Flags) -> Result>, AllocError> + where + A: 'static, + { + Ok(Self::new(x, flags)?.into()) + } + + /// Forgets the contents (does not run the destructor), but keeps the allocation. + fn forget_contents(this: Self) -> Box, A> { + let ptr = Self::into_raw(this); + + // SAFETY: `ptr` is valid, because it came from `Box::into_raw`. + unsafe { Box::from_raw(ptr.cast()) } + } + + /// Drops the contents, but keeps the allocation. + /// + /// # Examples + /// + /// ``` + /// let value = KBox::new([0; 32], GFP_KERNEL)?; + /// assert_eq!(*value, [0; 32]); + /// let value = KBox::drop_contents(value); + /// // Now we can re-use `value`: + /// let value = KBox::write(value, [1; 32]); + /// assert_eq!(*value, [1; 32]); + /// # Ok::<(), Error>(()) + /// ``` + pub fn drop_contents(this: Self) -> Box, A> { + let ptr = this.0.as_ptr(); + + // SAFETY: `ptr` is valid, because it came from `this`. After this call we never access the + // value stored in `this` again. + unsafe { core::ptr::drop_in_place(ptr) }; + + Self::forget_contents(this) + } + + /// Moves the `Box`'s value out of the `Box` and consumes the `Box`. + pub fn into_inner(b: Self) -> T { + // SAFETY: By the type invariant `&*b` is valid for `read`. + let value = unsafe { core::ptr::read(&*b) }; + let _ = Self::forget_contents(b); + value + } +} + +impl From> for Pin> +where + T: ?Sized, + A: Allocator, +{ + /// Converts a `Box` into a `Pin>`. If `T` does not implement [`Unpin`], then + /// `*b` will be pinned in memory and can't be moved. + /// + /// This moves `b` into `Pin` without moving `*b` or allocating and copying any memory. + fn from(b: Box) -> Self { + // SAFETY: The value wrapped inside a `Pin>` cannot be moved or replaced as long + // as `T` does not implement `Unpin`. + unsafe { Pin::new_unchecked(b) } + } +} + +impl InPlaceWrite for Box, A> +where + A: Allocator + 'static, +{ + type Initialized = Box; + + fn write_init(mut self, init: impl Init) -> Result { + let slot = self.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid. + unsafe { init.__init(slot)? }; + // SAFETY: All fields have been initialized. + Ok(unsafe { Box::assume_init(self) }) + } + + fn write_pin_init(mut self, init: impl PinInit) -> Result, E> { + let slot = self.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid and will not be moved, because we pin it later. + unsafe { init.__pinned_init(slot)? }; + // SAFETY: All fields have been initialized. + Ok(unsafe { Box::assume_init(self) }.into()) + } +} + +impl InPlaceInit for Box +where + A: Allocator + 'static, +{ + type PinnedSelf = Pin; + + #[inline] + fn try_pin_init(init: impl PinInit, flags: Flags) -> Result, E> + where + E: From, + { + Box::<_, A>::new_uninit(flags)?.write_pin_init(init) + } + + #[inline] + fn try_init(init: impl Init, flags: Flags) -> Result + where + E: From, + { + Box::<_, A>::new_uninit(flags)?.write_init(init) + } +} + +impl ForeignOwnable for Box +where + A: Allocator, +{ + type Borrowed<'a> = &'a T; + + fn into_foreign(self) -> *const crate::ffi::c_void { + Box::into_raw(self) as _ + } + + unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous + // call to `Self::into_foreign`. + unsafe { Box::from_raw(ptr as _) } + } + + unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> &'a T { + // SAFETY: The safety requirements of this method ensure that the object remains alive and + // immutable for the duration of 'a. + unsafe { &*ptr.cast() } + } +} + +impl ForeignOwnable for Pin> +where + A: Allocator, +{ + type Borrowed<'a> = Pin<&'a T>; + + fn into_foreign(self) -> *const crate::ffi::c_void { + // SAFETY: We are still treating the box as pinned. + Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _ + } + + unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { + // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous + // call to `Self::into_foreign`. + unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) } + } + + unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Pin<&'a T> { + // SAFETY: The safety requirements for this function ensure that the object is still alive, + // so it is safe to dereference the raw pointer. + // The safety requirements of `from_foreign` also ensure that the object remains alive for + // the lifetime of the returned value. + let r = unsafe { &*ptr.cast() }; + + // SAFETY: This pointer originates from a `Pin>`. + unsafe { Pin::new_unchecked(r) } + } +} + +impl Deref for Box +where + T: ?Sized, + A: Allocator, +{ + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: `self.0` is always properly aligned, dereferenceable and points to an initialized + // instance of `T`. + unsafe { self.0.as_ref() } + } +} + +impl DerefMut for Box +where + T: ?Sized, + A: Allocator, +{ + fn deref_mut(&mut self) -> &mut T { + // SAFETY: `self.0` is always properly aligned, dereferenceable and points to an initialized + // instance of `T`. + unsafe { self.0.as_mut() } + } +} + +impl fmt::Debug for Box +where + T: ?Sized + fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl Drop for Box +where + T: ?Sized, + A: Allocator, +{ + fn drop(&mut self) { + let layout = Layout::for_value::(self); + + // SAFETY: The pointer in `self.0` is guaranteed to be valid by the type invariant. + unsafe { core::ptr::drop_in_place::(self.deref_mut()) }; + + // SAFETY: + // - `self.0` was previously allocated with `A`. + // - `layout` is equal to the `Layout´ `self.0` was allocated with. + unsafe { A::free(self.0.cast(), layout) }; + } +} diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs new file mode 100644 index 00000000000000..ae9d072741cedb --- /dev/null +++ b/rust/kernel/alloc/kvec.rs @@ -0,0 +1,913 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Implementation of [`Vec`]. + +use super::{ + allocator::{KVmalloc, Kmalloc, Vmalloc}, + layout::ArrayLayout, + AllocError, Allocator, Box, Flags, +}; +use core::{ + fmt, + marker::PhantomData, + mem::{ManuallyDrop, MaybeUninit}, + ops::Deref, + ops::DerefMut, + ops::Index, + ops::IndexMut, + ptr, + ptr::NonNull, + slice, + slice::SliceIndex, +}; + +/// Create a [`KVec`] containing the arguments. +/// +/// New memory is allocated with `GFP_KERNEL`. +/// +/// # Examples +/// +/// ``` +/// let mut v = kernel::kvec![]; +/// v.push(1, GFP_KERNEL)?; +/// assert_eq!(v, [1]); +/// +/// let mut v = kernel::kvec![1; 3]?; +/// v.push(4, GFP_KERNEL)?; +/// assert_eq!(v, [1, 1, 1, 4]); +/// +/// let mut v = kernel::kvec![1, 2, 3]?; +/// v.push(4, GFP_KERNEL)?; +/// assert_eq!(v, [1, 2, 3, 4]); +/// +/// # Ok::<(), Error>(()) +/// ``` +#[macro_export] +macro_rules! kvec { + () => ( + $crate::alloc::KVec::new() + ); + ($elem:expr; $n:expr) => ( + $crate::alloc::KVec::from_elem($elem, $n, GFP_KERNEL) + ); + ($($x:expr),+ $(,)?) => ( + match $crate::alloc::KBox::new_uninit(GFP_KERNEL) { + Ok(b) => Ok($crate::alloc::KVec::from($crate::alloc::KBox::write(b, [$($x),+]))), + Err(e) => Err(e), + } + ); +} + +/// The kernel's [`Vec`] type. +/// +/// A contiguous growable array type with contents allocated with the kernel's allocators (e.g. +/// [`Kmalloc`], [`Vmalloc`] or [`KVmalloc`]), written `Vec`. +/// +/// For non-zero-sized values, a [`Vec`] will use the given allocator `A` for its allocation. For +/// the most common allocators the type aliases [`KVec`], [`VVec`] and [`KVVec`] exist. +/// +/// For zero-sized types the [`Vec`]'s pointer must be `dangling_mut::`; no memory is allocated. +/// +/// Generally, [`Vec`] consists of a pointer that represents the vector's backing buffer, the +/// capacity of the vector (the number of elements that currently fit into the vector), its length +/// (the number of elements that are currently stored in the vector) and the `Allocator` type used +/// to allocate (and free) the backing buffer. +/// +/// A [`Vec`] can be deconstructed into and (re-)constructed from its previously named raw parts +/// and manually modified. +/// +/// [`Vec`]'s backing buffer gets, if required, automatically increased (re-allocated) when elements +/// are added to the vector. +/// +/// # Invariants +/// +/// - `self.ptr` is always properly aligned and either points to memory allocated with `A` or, for +/// zero-sized types, is a dangling, well aligned pointer. +/// +/// - `self.len` always represents the exact number of elements stored in the vector. +/// +/// - `self.layout` represents the absolute number of elements that can be stored within the vector +/// without re-allocation. For ZSTs `self.layout`'s capacity is zero. However, it is legal for the +/// backing buffer to be larger than `layout`. +/// +/// - The `Allocator` type `A` of the vector is the exact same `Allocator` type the backing buffer +/// was allocated with (and must be freed with). +pub struct Vec { + ptr: NonNull, + /// Represents the actual buffer size as `cap` times `size_of::` bytes. + /// + /// Note: This isn't quite the same as `Self::capacity`, which in contrast returns the number of + /// elements we can still store without reallocating. + layout: ArrayLayout, + len: usize, + _p: PhantomData, +} + +/// Type alias for [`Vec`] with a [`Kmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let mut v = KVec::new(); +/// v.push(1, GFP_KERNEL)?; +/// assert_eq!(&v, &[1]); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub type KVec = Vec; + +/// Type alias for [`Vec`] with a [`Vmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let mut v = VVec::new(); +/// v.push(1, GFP_KERNEL)?; +/// assert_eq!(&v, &[1]); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub type VVec = Vec; + +/// Type alias for [`Vec`] with a [`KVmalloc`] allocator. +/// +/// # Examples +/// +/// ``` +/// let mut v = KVVec::new(); +/// v.push(1, GFP_KERNEL)?; +/// assert_eq!(&v, &[1]); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub type KVVec = Vec; + +// SAFETY: `Vec` is `Send` if `T` is `Send` because `Vec` owns its elements. +unsafe impl Send for Vec +where + T: Send, + A: Allocator, +{ +} + +// SAFETY: `Vec` is `Sync` if `T` is `Sync` because `Vec` owns its elements. +unsafe impl Sync for Vec +where + T: Sync, + A: Allocator, +{ +} + +impl Vec +where + A: Allocator, +{ + #[inline] + const fn is_zst() -> bool { + core::mem::size_of::() == 0 + } + + /// Returns the number of elements that can be stored within the vector without allocating + /// additional memory. + pub fn capacity(&self) -> usize { + if const { Self::is_zst() } { + usize::MAX + } else { + self.layout.len() + } + } + + /// Returns the number of elements stored within the vector. + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Forcefully sets `self.len` to `new_len`. + /// + /// # Safety + /// + /// - `new_len` must be less than or equal to [`Self::capacity`]. + /// - If `new_len` is greater than `self.len`, all elements within the interval + /// [`self.len`,`new_len`) must be initialized. + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) { + debug_assert!(new_len <= self.capacity()); + self.len = new_len; + } + + /// Returns a slice of the entire vector. + #[inline] + pub fn as_slice(&self) -> &[T] { + self + } + + /// Returns a mutable slice of the entire vector. + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [T] { + self + } + + /// Returns a mutable raw pointer to the vector's backing buffer, or, if `T` is a ZST, a + /// dangling raw pointer. + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + self.ptr.as_ptr() + } + + /// Returns a raw pointer to the vector's backing buffer, or, if `T` is a ZST, a dangling raw + /// pointer. + #[inline] + pub fn as_ptr(&self) -> *const T { + self.ptr.as_ptr() + } + + /// Returns `true` if the vector contains no elements, `false` otherwise. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// assert!(v.is_empty()); + /// + /// v.push(1, GFP_KERNEL); + /// assert!(!v.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Creates a new, empty `Vec`. + /// + /// This method does not allocate by itself. + #[inline] + pub const fn new() -> Self { + // INVARIANT: Since this is a new, empty `Vec` with no backing memory yet, + // - `ptr` is a properly aligned dangling pointer for type `T`, + // - `layout` is an empty `ArrayLayout` (zero capacity) + // - `len` is zero, since no elements can be or have been stored, + // - `A` is always valid. + Self { + ptr: NonNull::dangling(), + layout: ArrayLayout::empty(), + len: 0, + _p: PhantomData::, + } + } + + /// Returns a slice of `MaybeUninit` for the remaining spare capacity of the vector. + pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit] { + // SAFETY: + // - `self.len` is smaller than `self.capacity` and hence, the resulting pointer is + // guaranteed to be part of the same allocated object. + // - `self.len` can not overflow `isize`. + let ptr = unsafe { self.as_mut_ptr().add(self.len) } as *mut MaybeUninit; + + // SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated + // and valid, but uninitialized. + unsafe { slice::from_raw_parts_mut(ptr, self.capacity() - self.len) } + } + + /// Appends an element to the back of the [`Vec`] instance. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// v.push(1, GFP_KERNEL)?; + /// assert_eq!(&v, &[1]); + /// + /// v.push(2, GFP_KERNEL)?; + /// assert_eq!(&v, &[1, 2]); + /// # Ok::<(), Error>(()) + /// ``` + pub fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> { + self.reserve(1, flags)?; + + // SAFETY: + // - `self.len` is smaller than `self.capacity` and hence, the resulting pointer is + // guaranteed to be part of the same allocated object. + // - `self.len` can not overflow `isize`. + let ptr = unsafe { self.as_mut_ptr().add(self.len) }; + + // SAFETY: + // - `ptr` is properly aligned and valid for writes. + unsafe { core::ptr::write(ptr, v) }; + + // SAFETY: We just initialised the first spare entry, so it is safe to increase the length + // by 1. We also know that the new length is <= capacity because of the previous call to + // `reserve` above. + unsafe { self.set_len(self.len() + 1) }; + Ok(()) + } + + /// Creates a new [`Vec`] instance with at least the given capacity. + /// + /// # Examples + /// + /// ``` + /// let v = KVec::::with_capacity(20, GFP_KERNEL)?; + /// + /// assert!(v.capacity() >= 20); + /// # Ok::<(), Error>(()) + /// ``` + pub fn with_capacity(capacity: usize, flags: Flags) -> Result { + let mut v = Vec::new(); + + v.reserve(capacity, flags)?; + + Ok(v) + } + + /// Creates a `Vec` from a pointer, a length and a capacity using the allocator `A`. + /// + /// # Examples + /// + /// ``` + /// let mut v = kernel::kvec![1, 2, 3]?; + /// v.reserve(1, GFP_KERNEL)?; + /// + /// let (mut ptr, mut len, cap) = v.into_raw_parts(); + /// + /// // SAFETY: We've just reserved memory for another element. + /// unsafe { ptr.add(len).write(4) }; + /// len += 1; + /// + /// // SAFETY: We only wrote an additional element at the end of the `KVec`'s buffer and + /// // correspondingly increased the length of the `KVec` by one. Otherwise, we construct it + /// // from the exact same raw parts. + /// let v = unsafe { KVec::from_raw_parts(ptr, len, cap) }; + /// + /// assert_eq!(v, [1, 2, 3, 4]); + /// + /// # Ok::<(), Error>(()) + /// ``` + /// + /// # Safety + /// + /// If `T` is a ZST: + /// + /// - `ptr` must be a dangling, well aligned pointer. + /// + /// Otherwise: + /// + /// - `ptr` must have been allocated with the allocator `A`. + /// - `ptr` must satisfy or exceed the alignment requirements of `T`. + /// - `ptr` must point to memory with a size of at least `size_of::() * capacity` bytes. + /// - The allocated size in bytes must not be larger than `isize::MAX`. + /// - `length` must be less than or equal to `capacity`. + /// - The first `length` elements must be initialized values of type `T`. + /// + /// It is also valid to create an empty `Vec` passing a dangling pointer for `ptr` and zero for + /// `cap` and `len`. + pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self { + let layout = if Self::is_zst() { + ArrayLayout::empty() + } else { + // SAFETY: By the safety requirements of this function, `capacity * size_of::()` is + // smaller than `isize::MAX`. + unsafe { ArrayLayout::new_unchecked(capacity) } + }; + + // INVARIANT: For ZSTs, we store an empty `ArrayLayout`, all other type invariants are + // covered by the safety requirements of this function. + Self { + // SAFETY: By the safety requirements, `ptr` is either dangling or pointing to a valid + // memory allocation, allocated with `A`. + ptr: unsafe { NonNull::new_unchecked(ptr) }, + layout, + len: length, + _p: PhantomData::, + } + } + + /// Consumes the `Vec` and returns its raw components `pointer`, `length` and `capacity`. + /// + /// This will not run the destructor of the contained elements and for non-ZSTs the allocation + /// will stay alive indefinitely. Use [`Vec::from_raw_parts`] to recover the [`Vec`], drop the + /// elements and free the allocation, if any. + pub fn into_raw_parts(self) -> (*mut T, usize, usize) { + let mut me = ManuallyDrop::new(self); + let len = me.len(); + let capacity = me.capacity(); + let ptr = me.as_mut_ptr(); + (ptr, len, capacity) + } + + /// Ensures that the capacity exceeds the length by at least `additional` elements. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// v.push(1, GFP_KERNEL)?; + /// + /// v.reserve(10, GFP_KERNEL)?; + /// let cap = v.capacity(); + /// assert!(cap >= 10); + /// + /// v.reserve(10, GFP_KERNEL)?; + /// let new_cap = v.capacity(); + /// assert_eq!(new_cap, cap); + /// + /// # Ok::<(), Error>(()) + /// ``` + pub fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> { + let len = self.len(); + let cap = self.capacity(); + + if cap - len >= additional { + return Ok(()); + } + + if Self::is_zst() { + // The capacity is already `usize::MAX` for ZSTs, we can't go higher. + return Err(AllocError); + } + + // We know that `cap <= isize::MAX` because of the type invariants of `Self`. So the + // multiplication by two won't overflow. + let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?); + let layout = ArrayLayout::new(new_cap).map_err(|_| AllocError)?; + + // SAFETY: + // - `ptr` is valid because it's either `None` or comes from a previous call to + // `A::realloc`. + // - `self.layout` matches the `ArrayLayout` of the preceding allocation. + let ptr = unsafe { + A::realloc( + Some(self.ptr.cast()), + layout.into(), + self.layout.into(), + flags, + )? + }; + + // INVARIANT: + // - `layout` is some `ArrayLayout::`, + // - `ptr` has been created by `A::realloc` from `layout`. + self.ptr = ptr.cast(); + self.layout = layout; + + Ok(()) + } +} + +impl Vec { + /// Extend the vector by `n` clones of `value`. + pub fn extend_with(&mut self, n: usize, value: T, flags: Flags) -> Result<(), AllocError> { + if n == 0 { + return Ok(()); + } + + self.reserve(n, flags)?; + + let spare = self.spare_capacity_mut(); + + for item in spare.iter_mut().take(n - 1) { + item.write(value.clone()); + } + + // We can write the last element directly without cloning needlessly. + spare[n - 1].write(value); + + // SAFETY: + // - `self.len() + n < self.capacity()` due to the call to reserve above, + // - the loop and the line above initialized the next `n` elements. + unsafe { self.set_len(self.len() + n) }; + + Ok(()) + } + + /// Pushes clones of the elements of slice into the [`Vec`] instance. + /// + /// # Examples + /// + /// ``` + /// let mut v = KVec::new(); + /// v.push(1, GFP_KERNEL)?; + /// + /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?; + /// assert_eq!(&v, &[1, 20, 30, 40]); + /// + /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?; + /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]); + /// # Ok::<(), Error>(()) + /// ``` + pub fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> { + self.reserve(other.len(), flags)?; + for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) { + slot.write(item.clone()); + } + + // SAFETY: + // - `other.len()` spare entries have just been initialized, so it is safe to increase + // the length by the same number. + // - `self.len() + other.len() <= self.capacity()` is guaranteed by the preceding `reserve` + // call. + unsafe { self.set_len(self.len() + other.len()) }; + Ok(()) + } + + /// Create a new `Vec` and extend it by `n` clones of `value`. + pub fn from_elem(value: T, n: usize, flags: Flags) -> Result { + let mut v = Self::with_capacity(n, flags)?; + + v.extend_with(n, value, flags)?; + + Ok(v) + } +} + +impl Drop for Vec +where + A: Allocator, +{ + fn drop(&mut self) { + // SAFETY: `self.as_mut_ptr` is guaranteed to be valid by the type invariant. + unsafe { + ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut( + self.as_mut_ptr(), + self.len, + )) + }; + + // SAFETY: + // - `self.ptr` was previously allocated with `A`. + // - `self.layout` matches the `ArrayLayout` of the preceding allocation. + unsafe { A::free(self.ptr.cast(), self.layout.into()) }; + } +} + +impl From> for Vec +where + A: Allocator, +{ + fn from(b: Box<[T; N], A>) -> Vec { + let len = b.len(); + let ptr = Box::into_raw(b); + + // SAFETY: + // - `b` has been allocated with `A`, + // - `ptr` fulfills the alignment requirements for `T`, + // - `ptr` points to memory with at least a size of `size_of::() * len`, + // - all elements within `b` are initialized values of `T`, + // - `len` does not exceed `isize::MAX`. + unsafe { Vec::from_raw_parts(ptr as _, len, len) } + } +} + +impl Default for KVec { + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl fmt::Debug for Vec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl Deref for Vec +where + A: Allocator, +{ + type Target = [T]; + + #[inline] + fn deref(&self) -> &[T] { + // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len` + // initialized elements of type `T`. + unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } + } +} + +impl DerefMut for Vec +where + A: Allocator, +{ + #[inline] + fn deref_mut(&mut self) -> &mut [T] { + // SAFETY: The memory behind `self.as_ptr()` is guaranteed to contain `self.len` + // initialized elements of type `T`. + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } + } +} + +impl Eq for Vec where A: Allocator {} + +impl, A> Index for Vec +where + A: Allocator, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + Index::index(&**self, index) + } +} + +impl, A> IndexMut for Vec +where + A: Allocator, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + IndexMut::index_mut(&mut **self, index) + } +} + +macro_rules! impl_slice_eq { + ($([$($vars:tt)*] $lhs:ty, $rhs:ty,)*) => { + $( + impl PartialEq<$rhs> for $lhs + where + T: PartialEq, + { + #[inline] + fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] } + } + )* + } +} + +impl_slice_eq! { + [A1: Allocator, A2: Allocator] Vec, Vec, + [A: Allocator] Vec, &[U], + [A: Allocator] Vec, &mut [U], + [A: Allocator] &[T], Vec, + [A: Allocator] &mut [T], Vec, + [A: Allocator] Vec, [U], + [A: Allocator] [T], Vec, + [A: Allocator, const N: usize] Vec, [U; N], + [A: Allocator, const N: usize] Vec, &[U; N], +} + +impl<'a, T, A> IntoIterator for &'a Vec +where + A: Allocator, +{ + type Item = &'a T; + type IntoIter = slice::Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec +where + A: Allocator, +{ + type Item = &'a mut T; + type IntoIter = slice::IterMut<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + +/// An [`Iterator`] implementation for [`Vec`] that moves elements out of a vector. +/// +/// This structure is created by the [`Vec::into_iter`] method on [`Vec`] (provided by the +/// [`IntoIterator`] trait). +/// +/// # Examples +/// +/// ``` +/// let v = kernel::kvec![0, 1, 2]?; +/// let iter = v.into_iter(); +/// +/// # Ok::<(), Error>(()) +/// ``` +pub struct IntoIter { + ptr: *mut T, + buf: NonNull, + len: usize, + layout: ArrayLayout, + _p: PhantomData, +} + +impl IntoIter +where + A: Allocator, +{ + fn into_raw_parts(self) -> (*mut T, NonNull, usize, usize) { + let me = ManuallyDrop::new(self); + let ptr = me.ptr; + let buf = me.buf; + let len = me.len; + let cap = me.layout.len(); + (ptr, buf, len, cap) + } + + /// Same as `Iterator::collect` but specialized for `Vec`'s `IntoIter`. + /// + /// # Examples + /// + /// ``` + /// let v = kernel::kvec![1, 2, 3]?; + /// let mut it = v.into_iter(); + /// + /// assert_eq!(it.next(), Some(1)); + /// + /// let v = it.collect(GFP_KERNEL); + /// assert_eq!(v, [2, 3]); + /// + /// # Ok::<(), Error>(()) + /// ``` + /// + /// # Implementation details + /// + /// Currently, we can't implement `FromIterator`. There are a couple of issues with this trait + /// in the kernel, namely: + /// + /// - Rust's specialization feature is unstable. This prevents us to optimize for the special + /// case where `I::IntoIter` equals `Vec`'s `IntoIter` type. + /// - We also can't use `I::IntoIter`'s type ID either to work around this, since `FromIterator` + /// doesn't require this type to be `'static`. + /// - `FromIterator::from_iter` does return `Self` instead of `Result`, hence + /// we can't properly handle allocation failures. + /// - Neither `Iterator::collect` nor `FromIterator::from_iter` can handle additional allocation + /// flags. + /// + /// Instead, provide `IntoIter::collect`, such that we can at least convert a `IntoIter` into a + /// `Vec` again. + /// + /// Note that `IntoIter::collect` doesn't require `Flags`, since it re-uses the existing backing + /// buffer. However, this backing buffer may be shrunk to the actual count of elements. + pub fn collect(self, flags: Flags) -> Vec { + let old_layout = self.layout; + let (mut ptr, buf, len, mut cap) = self.into_raw_parts(); + let has_advanced = ptr != buf.as_ptr(); + + if has_advanced { + // Copy the contents we have advanced to at the beginning of the buffer. + // + // SAFETY: + // - `ptr` is valid for reads of `len * size_of::()` bytes, + // - `buf.as_ptr()` is valid for writes of `len * size_of::()` bytes, + // - `ptr` and `buf.as_ptr()` are not be subject to aliasing restrictions relative to + // each other, + // - both `ptr` and `buf.ptr()` are properly aligned. + unsafe { ptr::copy(ptr, buf.as_ptr(), len) }; + ptr = buf.as_ptr(); + + // SAFETY: `len` is guaranteed to be smaller than `self.layout.len()`. + let layout = unsafe { ArrayLayout::::new_unchecked(len) }; + + // SAFETY: `buf` points to the start of the backing buffer and `len` is guaranteed to be + // smaller than `cap`. Depending on `alloc` this operation may shrink the buffer or leaves + // it as it is. + ptr = match unsafe { + A::realloc(Some(buf.cast()), layout.into(), old_layout.into(), flags) + } { + // If we fail to shrink, which likely can't even happen, continue with the existing + // buffer. + Err(_) => ptr, + Ok(ptr) => { + cap = len; + ptr.as_ptr().cast() + } + }; + } + + // SAFETY: If the iterator has been advanced, the advanced elements have been copied to + // the beginning of the buffer and `len` has been adjusted accordingly. + // + // - `ptr` is guaranteed to point to the start of the backing buffer. + // - `cap` is either the original capacity or, after shrinking the buffer, equal to `len`. + // - `alloc` is guaranteed to be unchanged since `into_iter` has been called on the original + // `Vec`. + unsafe { Vec::from_raw_parts(ptr, len, cap) } + } +} + +impl Iterator for IntoIter +where + A: Allocator, +{ + type Item = T; + + /// # Examples + /// + /// ``` + /// let v = kernel::kvec![1, 2, 3]?; + /// let mut it = v.into_iter(); + /// + /// assert_eq!(it.next(), Some(1)); + /// assert_eq!(it.next(), Some(2)); + /// assert_eq!(it.next(), Some(3)); + /// assert_eq!(it.next(), None); + /// + /// # Ok::<(), Error>(()) + /// ``` + fn next(&mut self) -> Option { + if self.len == 0 { + return None; + } + + let current = self.ptr; + + // SAFETY: We can't overflow; decreasing `self.len` by one every time we advance `self.ptr` + // by one guarantees that. + unsafe { self.ptr = self.ptr.add(1) }; + + self.len -= 1; + + // SAFETY: `current` is guaranteed to point at a valid element within the buffer. + Some(unsafe { current.read() }) + } + + /// # Examples + /// + /// ``` + /// let v: KVec = kernel::kvec![1, 2, 3]?; + /// let mut iter = v.into_iter(); + /// let size = iter.size_hint().0; + /// + /// iter.next(); + /// assert_eq!(iter.size_hint().0, size - 1); + /// + /// iter.next(); + /// assert_eq!(iter.size_hint().0, size - 2); + /// + /// iter.next(); + /// assert_eq!(iter.size_hint().0, size - 3); + /// + /// # Ok::<(), Error>(()) + /// ``` + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } +} + +impl Drop for IntoIter +where + A: Allocator, +{ + fn drop(&mut self) { + // SAFETY: `self.ptr` is guaranteed to be valid by the type invariant. + unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.ptr, self.len)) }; + + // SAFETY: + // - `self.buf` was previously allocated with `A`. + // - `self.layout` matches the `ArrayLayout` of the preceding allocation. + unsafe { A::free(self.buf.cast(), self.layout.into()) }; + } +} + +impl IntoIterator for Vec +where + A: Allocator, +{ + type Item = T; + type IntoIter = IntoIter; + + /// Consumes the `Vec` and creates an `Iterator`, which moves each value out of the + /// vector (from start to end). + /// + /// # Examples + /// + /// ``` + /// let v = kernel::kvec![1, 2]?; + /// let mut v_iter = v.into_iter(); + /// + /// let first_element: Option = v_iter.next(); + /// + /// assert_eq!(first_element, Some(1)); + /// assert_eq!(v_iter.next(), Some(2)); + /// assert_eq!(v_iter.next(), None); + /// + /// # Ok::<(), Error>(()) + /// ``` + /// + /// ``` + /// let v = kernel::kvec![]; + /// let mut v_iter = v.into_iter(); + /// + /// let first_element: Option = v_iter.next(); + /// + /// assert_eq!(first_element, None); + /// + /// # Ok::<(), Error>(()) + /// ``` + #[inline] + fn into_iter(self) -> Self::IntoIter { + let buf = self.ptr; + let layout = self.layout; + let (ptr, len, _) = self.into_raw_parts(); + + IntoIter { + ptr, + buf, + len, + layout, + _p: PhantomData::, + } + } +} diff --git a/rust/kernel/alloc/layout.rs b/rust/kernel/alloc/layout.rs new file mode 100644 index 00000000000000..4b3cd7fdc816c1 --- /dev/null +++ b/rust/kernel/alloc/layout.rs @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Memory layout. +//! +//! Custom layout types extending or improving [`Layout`]. + +use core::{alloc::Layout, marker::PhantomData}; + +/// Error when constructing an [`ArrayLayout`]. +pub struct LayoutError; + +/// A layout for an array `[T; n]`. +/// +/// # Invariants +/// +/// - `len * size_of::() <= isize::MAX`. +pub struct ArrayLayout { + len: usize, + _phantom: PhantomData T>, +} + +impl Clone for ArrayLayout { + fn clone(&self) -> Self { + *self + } +} +impl Copy for ArrayLayout {} + +const ISIZE_MAX: usize = isize::MAX as usize; + +impl ArrayLayout { + /// Creates a new layout for `[T; 0]`. + pub const fn empty() -> Self { + // INVARIANT: `0 * size_of::() <= isize::MAX`. + Self { + len: 0, + _phantom: PhantomData, + } + } + + /// Creates a new layout for `[T; len]`. + /// + /// # Errors + /// + /// When `len * size_of::()` overflows or when `len * size_of::() > isize::MAX`. + pub const fn new(len: usize) -> Result { + match len.checked_mul(core::mem::size_of::()) { + Some(size) if size <= ISIZE_MAX => { + // INVARIANT: We checked above that `len * size_of::() <= isize::MAX`. + Ok(Self { + len, + _phantom: PhantomData, + }) + } + _ => Err(LayoutError), + } + } + + /// Creates a new layout for `[T; len]`. + /// + /// # Safety + /// + /// `len` must be a value, for which `len * size_of::() <= isize::MAX` is true. + pub unsafe fn new_unchecked(len: usize) -> Self { + // INVARIANT: By the safety requirements of this function + // `len * size_of::() <= isize::MAX`. + Self { + len, + _phantom: PhantomData, + } + } + + /// Returns the number of array elements represented by this layout. + pub const fn len(&self) -> usize { + self.len + } + + /// Returns `true` when no array elements are represented by this layout. + pub const fn is_empty(&self) -> bool { + self.len == 0 + } +} + +impl From> for Layout { + fn from(value: ArrayLayout) -> Self { + let res = Layout::array::(value.len); + // SAFETY: By the type invariant of `ArrayLayout` we have + // `len * size_of::() <= isize::MAX` and thus the result must be `Ok`. + unsafe { res.unwrap_unchecked() } + } +} diff --git a/rust/kernel/alloc/vec_ext.rs b/rust/kernel/alloc/vec_ext.rs deleted file mode 100644 index 1297a4be32e8c4..00000000000000 --- a/rust/kernel/alloc/vec_ext.rs +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Extensions to [`Vec`] for fallible allocations. - -use super::{AllocError, Flags}; -use alloc::vec::Vec; - -/// Extensions to [`Vec`]. -pub trait VecExt: Sized { - /// Creates a new [`Vec`] instance with at least the given capacity. - /// - /// # Examples - /// - /// ``` - /// let v = Vec::::with_capacity(20, GFP_KERNEL)?; - /// - /// assert!(v.capacity() >= 20); - /// # Ok::<(), Error>(()) - /// ``` - fn with_capacity(capacity: usize, flags: Flags) -> Result; - - /// Appends an element to the back of the [`Vec`] instance. - /// - /// # Examples - /// - /// ``` - /// let mut v = Vec::new(); - /// v.push(1, GFP_KERNEL)?; - /// assert_eq!(&v, &[1]); - /// - /// v.push(2, GFP_KERNEL)?; - /// assert_eq!(&v, &[1, 2]); - /// # Ok::<(), Error>(()) - /// ``` - fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError>; - - /// Pushes clones of the elements of slice into the [`Vec`] instance. - /// - /// # Examples - /// - /// ``` - /// let mut v = Vec::new(); - /// v.push(1, GFP_KERNEL)?; - /// - /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?; - /// assert_eq!(&v, &[1, 20, 30, 40]); - /// - /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?; - /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]); - /// # Ok::<(), Error>(()) - /// ``` - fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> - where - T: Clone; - - /// Ensures that the capacity exceeds the length by at least `additional` elements. - /// - /// # Examples - /// - /// ``` - /// let mut v = Vec::new(); - /// v.push(1, GFP_KERNEL)?; - /// - /// v.reserve(10, GFP_KERNEL)?; - /// let cap = v.capacity(); - /// assert!(cap >= 10); - /// - /// v.reserve(10, GFP_KERNEL)?; - /// let new_cap = v.capacity(); - /// assert_eq!(new_cap, cap); - /// - /// # Ok::<(), Error>(()) - /// ``` - fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError>; -} - -impl VecExt for Vec { - fn with_capacity(capacity: usize, flags: Flags) -> Result { - let mut v = Vec::new(); - >::reserve(&mut v, capacity, flags)?; - Ok(v) - } - - fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> { - >::reserve(self, 1, flags)?; - let s = self.spare_capacity_mut(); - s[0].write(v); - - // SAFETY: We just initialised the first spare entry, so it is safe to increase the length - // by 1. We also know that the new length is <= capacity because of the previous call to - // `reserve` above. - unsafe { self.set_len(self.len() + 1) }; - Ok(()) - } - - fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> - where - T: Clone, - { - >::reserve(self, other.len(), flags)?; - for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) { - slot.write(item.clone()); - } - - // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase - // the length by the same amount. We also know that the new length is <= capacity because - // of the previous call to `reserve` above. - unsafe { self.set_len(self.len() + other.len()) }; - Ok(()) - } - - #[cfg(any(test, testlib))] - fn reserve(&mut self, additional: usize, _flags: Flags) -> Result<(), AllocError> { - Vec::reserve(self, additional); - Ok(()) - } - - #[cfg(not(any(test, testlib)))] - fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> { - let len = self.len(); - let cap = self.capacity(); - - if cap - len >= additional { - return Ok(()); - } - - if core::mem::size_of::() == 0 { - // The capacity is already `usize::MAX` for SZTs, we can't go higher. - return Err(AllocError); - } - - // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size - // is greater than `isize::MAX`. So the multiplication by two won't overflow. - let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?); - let layout = core::alloc::Layout::array::(new_cap).map_err(|_| AllocError)?; - - let (old_ptr, len, cap) = destructure(self); - - // We need to make sure that `ptr` is either NULL or comes from a previous call to - // `krealloc_aligned`. A `Vec`'s `ptr` value is not guaranteed to be NULL and might be - // dangling after being created with `Vec::new`. Instead, we can rely on `Vec`'s capacity - // to be zero if no memory has been allocated yet. - let ptr = if cap == 0 { - core::ptr::null_mut() - } else { - old_ptr - }; - - // SAFETY: `ptr` is valid because it's either NULL or comes from a previous call to - // `krealloc_aligned`. We also verified that the type is not a ZST. - let new_ptr = unsafe { super::allocator::krealloc_aligned(ptr.cast(), layout, flags) }; - if new_ptr.is_null() { - // SAFETY: We are just rebuilding the existing `Vec` with no changes. - unsafe { rebuild(self, old_ptr, len, cap) }; - Err(AllocError) - } else { - // SAFETY: `ptr` has been reallocated with the layout for `new_cap` elements. New cap - // is greater than `cap`, so it continues to be >= `len`. - unsafe { rebuild(self, new_ptr.cast::(), len, new_cap) }; - Ok(()) - } - } -} - -#[cfg(not(any(test, testlib)))] -fn destructure(v: &mut Vec) -> (*mut T, usize, usize) { - let mut tmp = Vec::new(); - core::mem::swap(&mut tmp, v); - let mut tmp = core::mem::ManuallyDrop::new(tmp); - let len = tmp.len(); - let cap = tmp.capacity(); - (tmp.as_mut_ptr(), len, cap) -} - -/// Rebuilds a `Vec` from a pointer, length, and capacity. -/// -/// # Safety -/// -/// The same as [`Vec::from_raw_parts`]. -#[cfg(not(any(test, testlib)))] -unsafe fn rebuild(v: &mut Vec, ptr: *mut T, len: usize, cap: usize) { - // SAFETY: The safety requirements from this function satisfy those of `from_raw_parts`. - let mut tmp = unsafe { Vec::from_raw_parts(ptr, len, cap) }; - core::mem::swap(&mut tmp, v); -} diff --git a/rust/kernel/block/mq/gen_disk.rs b/rust/kernel/block/mq/gen_disk.rs index 708125dce96a93..798c4ae0bdedd5 100644 --- a/rust/kernel/block/mq/gen_disk.rs +++ b/rust/kernel/block/mq/gen_disk.rs @@ -45,7 +45,7 @@ pub fn rotational(mut self, rotational: bool) -> Self { /// Validate block size by verifying that it is between 512 and `PAGE_SIZE`, /// and that it is a power of two. - fn validate_block_size(size: u32) -> Result<()> { + fn validate_block_size(size: u32) -> Result { if !(512..=bindings::PAGE_SIZE as u32).contains(&size) || !size.is_power_of_two() { Err(error::code::EINVAL) } else { diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs index 9ba7fdfeb4b22c..c8646d0d98669f 100644 --- a/rust/kernel/block/mq/operations.rs +++ b/rust/kernel/block/mq/operations.rs @@ -131,7 +131,7 @@ impl OperationsVTable { unsafe extern "C" fn poll_callback( _hctx: *mut bindings::blk_mq_hw_ctx, _iob: *mut bindings::io_comp_batch, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { T::poll().into() } @@ -145,9 +145,9 @@ impl OperationsVTable { /// for the same context. unsafe extern "C" fn init_hctx_callback( _hctx: *mut bindings::blk_mq_hw_ctx, - _tagset_data: *mut core::ffi::c_void, - _hctx_idx: core::ffi::c_uint, - ) -> core::ffi::c_int { + _tagset_data: *mut crate::ffi::c_void, + _hctx_idx: crate::ffi::c_uint, + ) -> crate::ffi::c_int { from_result(|| Ok(0)) } @@ -159,7 +159,7 @@ impl OperationsVTable { /// This function may only be called by blk-mq C infrastructure. unsafe extern "C" fn exit_hctx_callback( _hctx: *mut bindings::blk_mq_hw_ctx, - _hctx_idx: core::ffi::c_uint, + _hctx_idx: crate::ffi::c_uint, ) { } @@ -176,9 +176,9 @@ impl OperationsVTable { unsafe extern "C" fn init_request_callback( _set: *mut bindings::blk_mq_tag_set, rq: *mut bindings::request, - _hctx_idx: core::ffi::c_uint, - _numa_node: core::ffi::c_uint, - ) -> core::ffi::c_int { + _hctx_idx: crate::ffi::c_uint, + _numa_node: crate::ffi::c_uint, + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: By the safety requirements of this function, `rq` points // to a valid allocation. @@ -203,7 +203,7 @@ impl OperationsVTable { unsafe extern "C" fn exit_request_callback( _set: *mut bindings::blk_mq_tag_set, rq: *mut bindings::request, - _hctx_idx: core::ffi::c_uint, + _hctx_idx: crate::ffi::c_uint, ) { // SAFETY: The tagset invariants guarantee that all requests are allocated with extra memory // for the request data. diff --git a/rust/kernel/block/mq/raw_writer.rs b/rust/kernel/block/mq/raw_writer.rs index 9222465d670bfe..7e2159e4f6a6f7 100644 --- a/rust/kernel/block/mq/raw_writer.rs +++ b/rust/kernel/block/mq/raw_writer.rs @@ -25,7 +25,7 @@ fn new(buffer: &'a mut [u8]) -> Result> { } pub(crate) fn from_array( - a: &'a mut [core::ffi::c_char; N], + a: &'a mut [crate::ffi::c_char; N], ) -> Result> { Self::new( // SAFETY: the buffer of `a` is valid for read and write as `u8` for diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request.rs index a0e22827f3f4ec..7943f43b957532 100644 --- a/rust/kernel/block/mq/request.rs +++ b/rust/kernel/block/mq/request.rs @@ -16,50 +16,55 @@ sync::atomic::{AtomicU64, Ordering}, }; -/// A wrapper around a blk-mq `struct request`. This represents an IO request. +/// A wrapper around a blk-mq [`struct request`]. This represents an IO request. /// /// # Implementation details /// /// There are four states for a request that the Rust bindings care about: /// -/// A) Request is owned by block layer (refcount 0) -/// B) Request is owned by driver but with zero `ARef`s in existence -/// (refcount 1) -/// C) Request is owned by driver with exactly one `ARef` in existence -/// (refcount 2) -/// D) Request is owned by driver with more than one `ARef` in existence -/// (refcount > 2) +/// 1. Request is owned by block layer (refcount 0). +/// 2. Request is owned by driver but with zero [`ARef`]s in existence +/// (refcount 1). +/// 3. Request is owned by driver with exactly one [`ARef`] in existence +/// (refcount 2). +/// 4. Request is owned by driver with more than one [`ARef`] in existence +/// (refcount > 2). /// /// -/// We need to track A and B to ensure we fail tag to request conversions for +/// We need to track 1 and 2 to ensure we fail tag to request conversions for /// requests that are not owned by the driver. /// -/// We need to track C and D to ensure that it is safe to end the request and hand +/// We need to track 3 and 4 to ensure that it is safe to end the request and hand /// back ownership to the block layer. /// /// The states are tracked through the private `refcount` field of /// `RequestDataWrapper`. This structure lives in the private data area of the C -/// `struct request`. +/// [`struct request`]. /// /// # Invariants /// -/// * `self.0` is a valid `struct request` created by the C portion of the kernel. +/// * `self.0` is a valid [`struct request`] created by the C portion of the +/// kernel. /// * The private data area associated with this request must be an initialized /// and valid `RequestDataWrapper`. /// * `self` is reference counted by atomic modification of -/// self.wrapper_ref().refcount(). +/// `self.wrapper_ref().refcount()`. +/// +/// [`struct request`]: srctree/include/linux/blk-mq.h /// #[repr(transparent)] pub struct Request(Opaque, PhantomData); impl Request { - /// Create an `ARef` from a `struct request` pointer. + /// Create an [`ARef`] from a [`struct request`] pointer. /// /// # Safety /// /// * The caller must own a refcount on `ptr` that is transferred to the - /// returned `ARef`. - /// * The type invariants for `Request` must hold for the pointee of `ptr`. + /// returned [`ARef`]. + /// * The type invariants for [`Request`] must hold for the pointee of `ptr`. + /// + /// [`struct request`]: srctree/include/linux/blk-mq.h pub(crate) unsafe fn aref_from_raw(ptr: *mut bindings::request) -> ARef { // INVARIANT: By the safety requirements of this function, invariants are upheld. // SAFETY: By the safety requirement of this function, we own a @@ -84,12 +89,14 @@ pub(crate) unsafe fn start_unchecked(this: &ARef) { } /// Try to take exclusive ownership of `this` by dropping the refcount to 0. - /// This fails if `this` is not the only `ARef` pointing to the underlying - /// `Request`. + /// This fails if `this` is not the only [`ARef`] pointing to the underlying + /// [`Request`]. /// - /// If the operation is successful, `Ok` is returned with a pointer to the - /// C `struct request`. If the operation fails, `this` is returned in the - /// `Err` variant. + /// If the operation is successful, [`Ok`] is returned with a pointer to the + /// C [`struct request`]. If the operation fails, `this` is returned in the + /// [`Err`] variant. + /// + /// [`struct request`]: srctree/include/linux/blk-mq.h fn try_set_end(this: ARef) -> Result<*mut bindings::request, ARef> { // We can race with `TagSet::tag_to_rq` if let Err(_old) = this.wrapper_ref().refcount().compare_exchange( @@ -109,7 +116,7 @@ fn try_set_end(this: ARef) -> Result<*mut bindings::request, ARef> { /// Notify the block layer that the request has been completed without errors. /// - /// This function will return `Err` if `this` is not the only `ARef` + /// This function will return [`Err`] if `this` is not the only [`ARef`] /// referencing the request. pub fn end_ok(this: ARef) -> Result<(), ARef> { let request_ptr = Self::try_set_end(this)?; @@ -123,13 +130,13 @@ pub fn end_ok(this: ARef) -> Result<(), ARef> { Ok(()) } - /// Return a pointer to the `RequestDataWrapper` stored in the private area + /// Return a pointer to the [`RequestDataWrapper`] stored in the private area /// of the request structure. /// /// # Safety /// /// - `this` must point to a valid allocation of size at least size of - /// `Self` plus size of `RequestDataWrapper`. + /// [`Self`] plus size of [`RequestDataWrapper`]. pub(crate) unsafe fn wrapper_ptr(this: *mut Self) -> NonNull { let request_ptr = this.cast::(); // SAFETY: By safety requirements for this function, `this` is a @@ -141,7 +148,7 @@ pub(crate) unsafe fn wrapper_ptr(this: *mut Self) -> NonNull unsafe { NonNull::new_unchecked(wrapper_ptr) } } - /// Return a reference to the `RequestDataWrapper` stored in the private + /// Return a reference to the [`RequestDataWrapper`] stored in the private /// area of the request structure. pub(crate) fn wrapper_ref(&self) -> &RequestDataWrapper { // SAFETY: By type invariant, `self.0` is a valid allocation. Further, @@ -152,13 +159,15 @@ pub(crate) fn wrapper_ref(&self) -> &RequestDataWrapper { } } -/// A wrapper around data stored in the private area of the C `struct request`. +/// A wrapper around data stored in the private area of the C [`struct request`]. +/// +/// [`struct request`]: srctree/include/linux/blk-mq.h pub(crate) struct RequestDataWrapper { /// The Rust request refcount has the following states: /// /// - 0: The request is owned by C block layer. - /// - 1: The request is owned by Rust abstractions but there are no ARef references to it. - /// - 2+: There are `ARef` references to the request. + /// - 1: The request is owned by Rust abstractions but there are no [`ARef`] references to it. + /// - 2+: There are [`ARef`] references to the request. refcount: AtomicU64, } @@ -204,7 +213,7 @@ fn atomic_relaxed_op_return(target: &AtomicU64, op: impl Fn(u64) -> u64) -> u64 } /// Store the result of `op(target.load)` in `target` if `target.load() != -/// pred`, returning true if the target was updated. +/// pred`, returning [`true`] if the target was updated. fn atomic_relaxed_op_unless(target: &AtomicU64, op: impl Fn(u64) -> u64, pred: u64) -> bool { target .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |x| { diff --git a/rust/kernel/block/mq/tag_set.rs b/rust/kernel/block/mq/tag_set.rs index f9a1ca655a35be..d7f175a05d992b 100644 --- a/rust/kernel/block/mq/tag_set.rs +++ b/rust/kernel/block/mq/tag_set.rs @@ -53,7 +53,7 @@ pub fn new( queue_depth: num_tags, cmd_size, flags: bindings::BLK_MQ_F_SHOULD_MERGE, - driver_data: core::ptr::null_mut::(), + driver_data: core::ptr::null_mut::(), nr_maps: num_maps, ..tag_set } diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs new file mode 100644 index 00000000000000..81d67789b16f24 --- /dev/null +++ b/rust/kernel/cred.rs @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Credentials management. +//! +//! C header: [`include/linux/cred.h`](srctree/include/linux/cred.h). +//! +//! Reference: + +use crate::{ + bindings, + task::Kuid, + types::{AlwaysRefCounted, Opaque}, +}; + +/// Wraps the kernel's `struct cred`. +/// +/// Credentials are used for various security checks in the kernel. +/// +/// Most fields of credentials are immutable. When things have their credentials changed, that +/// happens by replacing the credential instead of changing an existing credential. See the [kernel +/// documentation][ref] for more info on this. +/// +/// # Invariants +/// +/// Instances of this type are always ref-counted, that is, a call to `get_cred` ensures that the +/// allocation remains valid at least until the matching call to `put_cred`. +/// +/// [ref]: https://www.kernel.org/doc/html/latest/security/credentials.html +#[repr(transparent)] +pub struct Credential(Opaque); + +// SAFETY: +// - `Credential::dec_ref` can be called from any thread. +// - It is okay to send ownership of `Credential` across thread boundaries. +unsafe impl Send for Credential {} + +// SAFETY: It's OK to access `Credential` through shared references from other threads because +// we're either accessing properties that don't change or that are properly synchronised by C code. +unsafe impl Sync for Credential {} + +impl Credential { + /// Creates a reference to a [`Credential`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the + /// returned [`Credential`] reference. + pub unsafe fn from_ptr<'a>(ptr: *const bindings::cred) -> &'a Credential { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `Credential` type being transparent makes the cast ok. + unsafe { &*ptr.cast() } + } + + /// Get the id for this security context. + pub fn get_secid(&self) -> u32 { + let mut secid = 0; + // SAFETY: The invariants of this type ensures that the pointer is valid. + unsafe { bindings::security_cred_getsecid(self.0.get(), &mut secid) }; + secid + } + + /// Returns the effective UID of the given credential. + pub fn euid(&self) -> Kuid { + // SAFETY: By the type invariant, we know that `self.0` is valid. Furthermore, the `euid` + // field of a credential is never changed after initialization, so there is no potential + // for data races. + Kuid::from_raw(unsafe { (*self.0.get()).euid }) + } +} + +// SAFETY: The type invariants guarantee that `Credential` is always ref-counted. +unsafe impl AlwaysRefCounted for Credential { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::get_cred(self.0.get()) }; + } + + unsafe fn dec_ref(obj: core::ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is nonzero. The cast is okay + // because `Credential` has the same representation as `struct cred`. + unsafe { bindings::put_cred(obj.cast().as_ptr()) }; + } +} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index c8199ee079eff1..c926e0c2b8528c 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -8,7 +8,10 @@ bindings, types::{ARef, Opaque}, }; -use core::ptr; +use core::{fmt, ptr}; + +#[cfg(CONFIG_PRINTK)] +use crate::c_str; /// A reference-counted device. /// @@ -73,6 +76,110 @@ pub unsafe fn as_ref<'a>(ptr: *mut bindings::device) -> &'a Self { // SAFETY: Guaranteed by the safety requirements of the function. unsafe { &*ptr.cast() } } + + /// Prints an emergency-level message (level 0) prefixed with device information. + /// + /// More details are available from [`dev_emerg`]. + /// + /// [`dev_emerg`]: crate::dev_emerg + pub fn pr_emerg(&self, args: fmt::Arguments<'_>) { + // SAFETY: `klevel` is null-terminated, uses one of the kernel constants. + unsafe { self.printk(bindings::KERN_EMERG, args) }; + } + + /// Prints an alert-level message (level 1) prefixed with device information. + /// + /// More details are available from [`dev_alert`]. + /// + /// [`dev_alert`]: crate::dev_alert + pub fn pr_alert(&self, args: fmt::Arguments<'_>) { + // SAFETY: `klevel` is null-terminated, uses one of the kernel constants. + unsafe { self.printk(bindings::KERN_ALERT, args) }; + } + + /// Prints a critical-level message (level 2) prefixed with device information. + /// + /// More details are available from [`dev_crit`]. + /// + /// [`dev_crit`]: crate::dev_crit + pub fn pr_crit(&self, args: fmt::Arguments<'_>) { + // SAFETY: `klevel` is null-terminated, uses one of the kernel constants. + unsafe { self.printk(bindings::KERN_CRIT, args) }; + } + + /// Prints an error-level message (level 3) prefixed with device information. + /// + /// More details are available from [`dev_err`]. + /// + /// [`dev_err`]: crate::dev_err + pub fn pr_err(&self, args: fmt::Arguments<'_>) { + // SAFETY: `klevel` is null-terminated, uses one of the kernel constants. + unsafe { self.printk(bindings::KERN_ERR, args) }; + } + + /// Prints a warning-level message (level 4) prefixed with device information. + /// + /// More details are available from [`dev_warn`]. + /// + /// [`dev_warn`]: crate::dev_warn + pub fn pr_warn(&self, args: fmt::Arguments<'_>) { + // SAFETY: `klevel` is null-terminated, uses one of the kernel constants. + unsafe { self.printk(bindings::KERN_WARNING, args) }; + } + + /// Prints a notice-level message (level 5) prefixed with device information. + /// + /// More details are available from [`dev_notice`]. + /// + /// [`dev_notice`]: crate::dev_notice + pub fn pr_notice(&self, args: fmt::Arguments<'_>) { + // SAFETY: `klevel` is null-terminated, uses one of the kernel constants. + unsafe { self.printk(bindings::KERN_NOTICE, args) }; + } + + /// Prints an info-level message (level 6) prefixed with device information. + /// + /// More details are available from [`dev_info`]. + /// + /// [`dev_info`]: crate::dev_info + pub fn pr_info(&self, args: fmt::Arguments<'_>) { + // SAFETY: `klevel` is null-terminated, uses one of the kernel constants. + unsafe { self.printk(bindings::KERN_INFO, args) }; + } + + /// Prints a debug-level message (level 7) prefixed with device information. + /// + /// More details are available from [`dev_dbg`]. + /// + /// [`dev_dbg`]: crate::dev_dbg + pub fn pr_dbg(&self, args: fmt::Arguments<'_>) { + if cfg!(debug_assertions) { + // SAFETY: `klevel` is null-terminated, uses one of the kernel constants. + unsafe { self.printk(bindings::KERN_DEBUG, args) }; + } + } + + /// Prints the provided message to the console. + /// + /// # Safety + /// + /// Callers must ensure that `klevel` is null-terminated; in particular, one of the + /// `KERN_*`constants, for example, `KERN_CRIT`, `KERN_ALERT`, etc. + #[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))] + unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) { + // SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.as_raw` + // is valid because `self` is valid. The "%pA" format string expects a pointer to + // `fmt::Arguments`, which is what we're passing as the last argument. + #[cfg(CONFIG_PRINTK)] + unsafe { + bindings::_dev_printk( + klevel as *const _ as *const core::ffi::c_char, + self.as_raw(), + c_str!("%pA").as_char_ptr(), + &msg as *const _ as *const core::ffi::c_void, + ) + }; + } } // SAFETY: Instances of `Device` are always reference-counted. @@ -94,3 +201,213 @@ unsafe impl Send for Device {} // SAFETY: `Device` can be shared among threads because all immutable methods are protected by the // synchronization in `struct device`. unsafe impl Sync for Device {} + +#[doc(hidden)] +#[macro_export] +macro_rules! dev_printk { + ($method:ident, $dev:expr, $($f:tt)*) => { + { + ($dev).$method(core::format_args!($($f)*)); + } + } +} + +/// Prints an emergency-level message (level 0) prefixed with device information. +/// +/// This level should be used if the system is unusable. +/// +/// Equivalent to the kernel's `dev_emerg` macro. +/// +/// Mimics the interface of [`std::print!`]. More information about the syntax is available from +/// [`core::fmt`] and `alloc::format!`. +/// +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// # use kernel::device::Device; +/// +/// fn example(dev: &Device) { +/// dev_emerg!(dev, "hello {}\n", "there"); +/// } +/// ``` +#[macro_export] +macro_rules! dev_emerg { + ($($f:tt)*) => { $crate::dev_printk!(pr_emerg, $($f)*); } +} + +/// Prints an alert-level message (level 1) prefixed with device information. +/// +/// This level should be used if action must be taken immediately. +/// +/// Equivalent to the kernel's `dev_alert` macro. +/// +/// Mimics the interface of [`std::print!`]. More information about the syntax is available from +/// [`core::fmt`] and `alloc::format!`. +/// +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// # use kernel::device::Device; +/// +/// fn example(dev: &Device) { +/// dev_alert!(dev, "hello {}\n", "there"); +/// } +/// ``` +#[macro_export] +macro_rules! dev_alert { + ($($f:tt)*) => { $crate::dev_printk!(pr_alert, $($f)*); } +} + +/// Prints a critical-level message (level 2) prefixed with device information. +/// +/// This level should be used in critical conditions. +/// +/// Equivalent to the kernel's `dev_crit` macro. +/// +/// Mimics the interface of [`std::print!`]. More information about the syntax is available from +/// [`core::fmt`] and `alloc::format!`. +/// +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// # use kernel::device::Device; +/// +/// fn example(dev: &Device) { +/// dev_crit!(dev, "hello {}\n", "there"); +/// } +/// ``` +#[macro_export] +macro_rules! dev_crit { + ($($f:tt)*) => { $crate::dev_printk!(pr_crit, $($f)*); } +} + +/// Prints an error-level message (level 3) prefixed with device information. +/// +/// This level should be used in error conditions. +/// +/// Equivalent to the kernel's `dev_err` macro. +/// +/// Mimics the interface of [`std::print!`]. More information about the syntax is available from +/// [`core::fmt`] and `alloc::format!`. +/// +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// # use kernel::device::Device; +/// +/// fn example(dev: &Device) { +/// dev_err!(dev, "hello {}\n", "there"); +/// } +/// ``` +#[macro_export] +macro_rules! dev_err { + ($($f:tt)*) => { $crate::dev_printk!(pr_err, $($f)*); } +} + +/// Prints a warning-level message (level 4) prefixed with device information. +/// +/// This level should be used in warning conditions. +/// +/// Equivalent to the kernel's `dev_warn` macro. +/// +/// Mimics the interface of [`std::print!`]. More information about the syntax is available from +/// [`core::fmt`] and `alloc::format!`. +/// +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// # use kernel::device::Device; +/// +/// fn example(dev: &Device) { +/// dev_warn!(dev, "hello {}\n", "there"); +/// } +/// ``` +#[macro_export] +macro_rules! dev_warn { + ($($f:tt)*) => { $crate::dev_printk!(pr_warn, $($f)*); } +} + +/// Prints a notice-level message (level 5) prefixed with device information. +/// +/// This level should be used in normal but significant conditions. +/// +/// Equivalent to the kernel's `dev_notice` macro. +/// +/// Mimics the interface of [`std::print!`]. More information about the syntax is available from +/// [`core::fmt`] and `alloc::format!`. +/// +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// # use kernel::device::Device; +/// +/// fn example(dev: &Device) { +/// dev_notice!(dev, "hello {}\n", "there"); +/// } +/// ``` +#[macro_export] +macro_rules! dev_notice { + ($($f:tt)*) => { $crate::dev_printk!(pr_notice, $($f)*); } +} + +/// Prints an info-level message (level 6) prefixed with device information. +/// +/// This level should be used for informational messages. +/// +/// Equivalent to the kernel's `dev_info` macro. +/// +/// Mimics the interface of [`std::print!`]. More information about the syntax is available from +/// [`core::fmt`] and `alloc::format!`. +/// +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// # use kernel::device::Device; +/// +/// fn example(dev: &Device) { +/// dev_info!(dev, "hello {}\n", "there"); +/// } +/// ``` +#[macro_export] +macro_rules! dev_info { + ($($f:tt)*) => { $crate::dev_printk!(pr_info, $($f)*); } +} + +/// Prints a debug-level message (level 7) prefixed with device information. +/// +/// This level should be used for debug messages. +/// +/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet. +/// +/// Mimics the interface of [`std::print!`]. More information about the syntax is available from +/// [`core::fmt`] and `alloc::format!`. +/// +/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html +/// +/// # Examples +/// +/// ``` +/// # use kernel::device::Device; +/// +/// fn example(dev: &Device) { +/// dev_dbg!(dev, "hello {}\n", "there"); +/// } +/// ``` +#[macro_export] +macro_rules! dev_dbg { + ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*); } +} diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 6f1587a2524e8b..52c5024324474f 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -6,9 +6,10 @@ use crate::{alloc::AllocError, str::CStr}; -use alloc::alloc::LayoutError; +use core::alloc::LayoutError; use core::fmt; +use core::num::NonZeroI32; use core::num::TryFromIntError; use core::str::Utf8Error; @@ -20,7 +21,11 @@ macro_rules! declare_err { $( #[doc = $doc] )* - pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32)); + pub const $err: super::Error = + match super::Error::try_from_errno(-(crate::bindings::$err as i32)) { + Some(err) => err, + None => panic!("Invalid errno in `declare_err!`"), + }; }; } @@ -88,14 +93,14 @@ macro_rules! declare_err { /// /// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`). #[derive(Clone, Copy, PartialEq, Eq)] -pub struct Error(core::ffi::c_int); +pub struct Error(NonZeroI32); impl Error { /// Creates an [`Error`] from a kernel error code. /// /// It is a bug to pass an out-of-range `errno`. `EINVAL` would /// be returned in such a case. - pub(crate) fn from_errno(errno: core::ffi::c_int) -> Error { + pub fn from_errno(errno: crate::ffi::c_int) -> Error { if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { // TODO: Make it a `WARN_ONCE` once available. crate::pr_warn!( @@ -107,7 +112,20 @@ pub(crate) fn from_errno(errno: core::ffi::c_int) -> Error { // INVARIANT: The check above ensures the type invariant // will hold. - Error(errno) + // SAFETY: `errno` is checked above to be in a valid range. + unsafe { Error::from_errno_unchecked(errno) } + } + + /// Creates an [`Error`] from a kernel error code. + /// + /// Returns [`None`] if `errno` is out-of-range. + const fn try_from_errno(errno: crate::ffi::c_int) -> Option { + if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 { + return None; + } + + // SAFETY: `errno` is checked above to be in a valid range. + Some(unsafe { Error::from_errno_unchecked(errno) }) } /// Creates an [`Error`] from a kernel error code. @@ -115,38 +133,38 @@ pub(crate) fn from_errno(errno: core::ffi::c_int) -> Error { /// # Safety /// /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`). - unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error { + const unsafe fn from_errno_unchecked(errno: crate::ffi::c_int) -> Error { // INVARIANT: The contract ensures the type invariant // will hold. - Error(errno) + // SAFETY: The caller guarantees `errno` is non-zero. + Error(unsafe { NonZeroI32::new_unchecked(errno) }) } /// Returns the kernel error code. - pub fn to_errno(self) -> core::ffi::c_int { - self.0 + pub fn to_errno(self) -> crate::ffi::c_int { + self.0.get() } #[cfg(CONFIG_BLOCK)] pub(crate) fn to_blk_status(self) -> bindings::blk_status_t { // SAFETY: `self.0` is a valid error due to its invariant. - unsafe { bindings::errno_to_blk_status(self.0) } + unsafe { bindings::errno_to_blk_status(self.0.get()) } } /// Returns the error encoded as a pointer. - #[allow(dead_code)] - pub(crate) fn to_ptr(self) -> *mut T { + pub fn to_ptr(self) -> *mut T { #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))] // SAFETY: `self.0` is a valid error due to its invariant. unsafe { - bindings::ERR_PTR(self.0.into()) as *mut _ + bindings::ERR_PTR(self.0.get().into()) as *mut _ } } /// Returns a string representing the error, if one exists. - #[cfg(not(testlib))] + #[cfg(not(any(test, testlib)))] pub fn name(&self) -> Option<&'static CStr> { // SAFETY: Just an FFI call, there are no extra safety requirements. - let ptr = unsafe { bindings::errname(-self.0) }; + let ptr = unsafe { bindings::errname(-self.0.get()) }; if ptr.is_null() { None } else { @@ -160,7 +178,7 @@ pub fn name(&self) -> Option<&'static CStr> { /// When `testlib` is configured, this always returns `None` to avoid the dependency on a /// kernel function so that tests that use this (e.g., by calling [`Result::unwrap`]) can still /// run in userspace. - #[cfg(testlib)] + #[cfg(any(test, testlib))] pub fn name(&self) -> Option<&'static CStr> { None } @@ -171,9 +189,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.name() { // Print out number if no name can be found. None => f.debug_tuple("Error").field(&-self.0).finish(), - // SAFETY: These strings are ASCII-only. Some(name) => f - .debug_tuple(unsafe { core::str::from_utf8_unchecked(name) }) + .debug_tuple( + // SAFETY: These strings are ASCII-only. + unsafe { core::str::from_utf8_unchecked(name) }, + ) .finish(), } } @@ -239,7 +259,7 @@ fn from(e: core::convert::Infallible) -> Error { /// Converts an integer as returned by a C kernel function to an error if it's negative, and /// `Ok(())` otherwise. -pub fn to_result(err: core::ffi::c_int) -> Result { +pub fn to_result(err: crate::ffi::c_int) -> Result { if err < 0 { Err(Error::from_errno(err)) } else { @@ -262,21 +282,21 @@ pub fn to_result(err: core::ffi::c_int) -> Result { /// fn devm_platform_ioremap_resource( /// pdev: &mut PlatformDevice, /// index: u32, -/// ) -> Result<*mut core::ffi::c_void> { +/// ) -> Result<*mut kernel::ffi::c_void> { /// // SAFETY: `pdev` points to a valid platform device. There are no safety requirements /// // on `index`. /// from_err_ptr(unsafe { bindings::devm_platform_ioremap_resource(pdev.to_ptr(), index) }) /// } /// ``` -// TODO: Remove `dead_code` marker once an in-kernel client is available. -#[allow(dead_code)] -pub(crate) fn from_err_ptr(ptr: *mut T) -> Result<*mut T> { - // CAST: Casting a pointer to `*const core::ffi::c_void` is always valid. - let const_ptr: *const core::ffi::c_void = ptr.cast(); +pub fn from_err_ptr(ptr: *mut T) -> Result<*mut T> { + // CAST: Casting a pointer to `*const crate::ffi::c_void` is always valid. + let const_ptr: *const crate::ffi::c_void = ptr.cast(); // SAFETY: The FFI function does not deref the pointer. if unsafe { bindings::IS_ERR(const_ptr) } { // SAFETY: The FFI function does not deref the pointer. let err = unsafe { bindings::PTR_ERR(const_ptr) }; + + #[allow(clippy::unnecessary_cast)] // CAST: If `IS_ERR()` returns `true`, // then `PTR_ERR()` is guaranteed to return a // negative value greater-or-equal to `-bindings::MAX_ERRNO`, @@ -286,8 +306,7 @@ pub(crate) fn from_err_ptr(ptr: *mut T) -> Result<*mut T> { // // SAFETY: `IS_ERR()` ensures `err` is a // negative value greater-or-equal to `-bindings::MAX_ERRNO`. - #[allow(clippy::unnecessary_cast)] - return Err(unsafe { Error::from_errno_unchecked(err as core::ffi::c_int) }); + return Err(unsafe { Error::from_errno_unchecked(err as crate::ffi::c_int) }); } Ok(ptr) } @@ -307,7 +326,7 @@ pub(crate) fn from_err_ptr(ptr: *mut T) -> Result<*mut T> { /// # use kernel::bindings; /// unsafe extern "C" fn probe_callback( /// pdev: *mut bindings::platform_device, -/// ) -> core::ffi::c_int { +/// ) -> kernel::ffi::c_int { /// from_result(|| { /// let ptr = devm_alloc(pdev)?; /// bindings::platform_set_drvdata(pdev, ptr); @@ -315,9 +334,7 @@ pub(crate) fn from_err_ptr(ptr: *mut T) -> Result<*mut T> { /// }) /// } /// ``` -// TODO: Remove `dead_code` marker once an in-kernel client is available. -#[allow(dead_code)] -pub(crate) fn from_result(f: F) -> T +pub fn from_result(f: F) -> T where T: From, F: FnOnce() -> Result, diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs new file mode 100644 index 00000000000000..0121b38c59e63d --- /dev/null +++ b/rust/kernel/fs.rs @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Kernel file systems. +//! +//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h) + +pub mod file; +pub use self::file::{File, LocalFile}; diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs new file mode 100644 index 00000000000000..e03dbe14d62a56 --- /dev/null +++ b/rust/kernel/fs/file.rs @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Files and file descriptors. +//! +//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h) and +//! [`include/linux/file.h`](srctree/include/linux/file.h) + +use crate::{ + bindings, + cred::Credential, + error::{code::*, Error, Result}, + types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque}, +}; +use core::ptr; + +/// Flags associated with a [`File`]. +pub mod flags { + /// File is opened in append mode. + pub const O_APPEND: u32 = bindings::O_APPEND; + + /// Signal-driven I/O is enabled. + pub const O_ASYNC: u32 = bindings::FASYNC; + + /// Close-on-exec flag is set. + pub const O_CLOEXEC: u32 = bindings::O_CLOEXEC; + + /// File was created if it didn't already exist. + pub const O_CREAT: u32 = bindings::O_CREAT; + + /// Direct I/O is enabled for this file. + pub const O_DIRECT: u32 = bindings::O_DIRECT; + + /// File must be a directory. + pub const O_DIRECTORY: u32 = bindings::O_DIRECTORY; + + /// Like [`O_SYNC`] except metadata is not synced. + pub const O_DSYNC: u32 = bindings::O_DSYNC; + + /// Ensure that this file is created with the `open(2)` call. + pub const O_EXCL: u32 = bindings::O_EXCL; + + /// Large file size enabled (`off64_t` over `off_t`). + pub const O_LARGEFILE: u32 = bindings::O_LARGEFILE; + + /// Do not update the file last access time. + pub const O_NOATIME: u32 = bindings::O_NOATIME; + + /// File should not be used as process's controlling terminal. + pub const O_NOCTTY: u32 = bindings::O_NOCTTY; + + /// If basename of path is a symbolic link, fail open. + pub const O_NOFOLLOW: u32 = bindings::O_NOFOLLOW; + + /// File is using nonblocking I/O. + pub const O_NONBLOCK: u32 = bindings::O_NONBLOCK; + + /// File is using nonblocking I/O. + /// + /// This is effectively the same flag as [`O_NONBLOCK`] on all architectures + /// except SPARC64. + pub const O_NDELAY: u32 = bindings::O_NDELAY; + + /// Used to obtain a path file descriptor. + pub const O_PATH: u32 = bindings::O_PATH; + + /// Write operations on this file will flush data and metadata. + pub const O_SYNC: u32 = bindings::O_SYNC; + + /// This file is an unnamed temporary regular file. + pub const O_TMPFILE: u32 = bindings::O_TMPFILE; + + /// File should be truncated to length 0. + pub const O_TRUNC: u32 = bindings::O_TRUNC; + + /// Bitmask for access mode flags. + /// + /// # Examples + /// + /// ``` + /// use kernel::fs::file; + /// # fn do_something() {} + /// # let flags = 0; + /// if (flags & file::flags::O_ACCMODE) == file::flags::O_RDONLY { + /// do_something(); + /// } + /// ``` + pub const O_ACCMODE: u32 = bindings::O_ACCMODE; + + /// File is read only. + pub const O_RDONLY: u32 = bindings::O_RDONLY; + + /// File is write only. + pub const O_WRONLY: u32 = bindings::O_WRONLY; + + /// File can be both read and written. + pub const O_RDWR: u32 = bindings::O_RDWR; +} + +/// Wraps the kernel's `struct file`. Thread safe. +/// +/// This represents an open file rather than a file on a filesystem. Processes generally reference +/// open files using file descriptors. However, file descriptors are not the same as files. A file +/// descriptor is just an integer that corresponds to a file, and a single file may be referenced +/// by multiple file descriptors. +/// +/// # Refcounting +/// +/// Instances of this type are reference-counted. The reference count is incremented by the +/// `fget`/`get_file` functions and decremented by `fput`. The Rust type `ARef` represents a +/// pointer that owns a reference count on the file. +/// +/// Whenever a process opens a file descriptor (fd), it stores a pointer to the file in its fd +/// table (`struct files_struct`). This pointer owns a reference count to the file, ensuring the +/// file isn't prematurely deleted while the file descriptor is open. In Rust terminology, the +/// pointers in `struct files_struct` are `ARef` pointers. +/// +/// ## Light refcounts +/// +/// Whenever a process has an fd to a file, it may use something called a "light refcount" as a +/// performance optimization. Light refcounts are acquired by calling `fdget` and released with +/// `fdput`. The idea behind light refcounts is that if the fd is not closed between the calls to +/// `fdget` and `fdput`, then the refcount cannot hit zero during that time, as the `struct +/// files_struct` holds a reference until the fd is closed. This means that it's safe to access the +/// file even if `fdget` does not increment the refcount. +/// +/// The requirement that the fd is not closed during a light refcount applies globally across all +/// threads - not just on the thread using the light refcount. For this reason, light refcounts are +/// only used when the `struct files_struct` is not shared with other threads, since this ensures +/// that other unrelated threads cannot suddenly start using the fd and close it. Therefore, +/// calling `fdget` on a shared `struct files_struct` creates a normal refcount instead of a light +/// refcount. +/// +/// Light reference counts must be released with `fdput` before the system call returns to +/// userspace. This means that if you wait until the current system call returns to userspace, then +/// all light refcounts that existed at the time have gone away. +/// +/// ### The file position +/// +/// Each `struct file` has a position integer, which is protected by the `f_pos_lock` mutex. +/// However, if the `struct file` is not shared, then the kernel may avoid taking the lock as a +/// performance optimization. +/// +/// The condition for avoiding the `f_pos_lock` mutex is different from the condition for using +/// `fdget`. With `fdget`, you may avoid incrementing the refcount as long as the current fd table +/// is not shared; it is okay if there are other fd tables that also reference the same `struct +/// file`. However, `fdget_pos` can only avoid taking the `f_pos_lock` if the entire `struct file` +/// is not shared, as different processes with an fd to the same `struct file` share the same +/// position. +/// +/// To represent files that are not thread safe due to this optimization, the [`LocalFile`] type is +/// used. +/// +/// ## Rust references +/// +/// The reference type `&File` is similar to light refcounts: +/// +/// * `&File` references don't own a reference count. They can only exist as long as the reference +/// count stays positive, and can only be created when there is some mechanism in place to ensure +/// this. +/// +/// * The Rust borrow-checker normally ensures this by enforcing that the `ARef` from which +/// a `&File` is created outlives the `&File`. +/// +/// * Using the unsafe [`File::from_raw_file`] means that it is up to the caller to ensure that the +/// `&File` only exists while the reference count is positive. +/// +/// * You can think of `fdget` as using an fd to look up an `ARef` in the `struct +/// files_struct` and create an `&File` from it. The "fd cannot be closed" rule is like the Rust +/// rule "the `ARef` must outlive the `&File`". +/// +/// # Invariants +/// +/// * All instances of this type are refcounted using the `f_count` field. +/// * There must not be any active calls to `fdget_pos` on this file that did not take the +/// `f_pos_lock` mutex. +#[repr(transparent)] +pub struct File { + inner: Opaque, +} + +// SAFETY: This file is known to not have any active `fdget_pos` calls that did not take the +// `f_pos_lock` mutex, so it is safe to transfer it between threads. +unsafe impl Send for File {} + +// SAFETY: This file is known to not have any active `fdget_pos` calls that did not take the +// `f_pos_lock` mutex, so it is safe to access its methods from several threads in parallel. +unsafe impl Sync for File {} + +// SAFETY: The type invariants guarantee that `File` is always ref-counted. This implementation +// makes `ARef` own a normal refcount. +unsafe impl AlwaysRefCounted for File { + #[inline] + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::get_file(self.as_ptr()) }; + } + + #[inline] + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: To call this method, the caller passes us ownership of a normal refcount, so we + // may drop it. The cast is okay since `File` has the same representation as `struct file`. + unsafe { bindings::fput(obj.cast().as_ptr()) } + } +} + +/// Wraps the kernel's `struct file`. Not thread safe. +/// +/// This type represents a file that is not known to be safe to transfer across thread boundaries. +/// To obtain a thread-safe [`File`], use the [`assume_no_fdget_pos`] conversion. +/// +/// See the documentation for [`File`] for more information. +/// +/// # Invariants +/// +/// * All instances of this type are refcounted using the `f_count` field. +/// * If there is an active call to `fdget_pos` that did not take the `f_pos_lock` mutex, then it +/// must be on the same thread as this file. +/// +/// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos +pub struct LocalFile { + inner: Opaque, +} + +// SAFETY: The type invariants guarantee that `LocalFile` is always ref-counted. This implementation +// makes `ARef` own a normal refcount. +unsafe impl AlwaysRefCounted for LocalFile { + #[inline] + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::get_file(self.as_ptr()) }; + } + + #[inline] + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: To call this method, the caller passes us ownership of a normal refcount, so we + // may drop it. The cast is okay since `File` has the same representation as `struct file`. + unsafe { bindings::fput(obj.cast().as_ptr()) } + } +} + +impl LocalFile { + /// Constructs a new `struct file` wrapper from a file descriptor. + /// + /// The file descriptor belongs to the current process, and there might be active local calls + /// to `fdget_pos` on the same file. + /// + /// To obtain an `ARef`, use the [`assume_no_fdget_pos`] function to convert. + /// + /// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos + #[inline] + pub fn fget(fd: u32) -> Result, BadFdError> { + // SAFETY: FFI call, there are no requirements on `fd`. + let ptr = ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or(BadFdError)?; + + // SAFETY: `bindings::fget` created a refcount, and we pass ownership of it to the `ARef`. + // + // INVARIANT: This file is in the fd table on this thread, so either all `fdget_pos` calls + // are on this thread, or the file is shared, in which case `fdget_pos` calls took the + // `f_pos_lock` mutex. + Ok(unsafe { ARef::from_raw(ptr.cast()) }) + } + + /// Creates a reference to a [`LocalFile`] from a valid pointer. + /// + /// # Safety + /// + /// * The caller must ensure that `ptr` points at a valid file and that the file's refcount is + /// positive for the duration of 'a. + /// * The caller must ensure that if there is an active call to `fdget_pos` that did not take + /// the `f_pos_lock` mutex, then that call is on the current thread. + #[inline] + pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a LocalFile { + // SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the + // duration of 'a. The cast is okay because `File` is `repr(transparent)`. + // + // INVARIANT: The caller guarantees that there are no problematic `fdget_pos` calls. + unsafe { &*ptr.cast() } + } + + /// Assume that there are no active `fdget_pos` calls that prevent us from sharing this file. + /// + /// This makes it safe to transfer this file to other threads. No checks are performed, and + /// using it incorrectly may lead to a data race on the file position if the file is shared + /// with another thread. + /// + /// This method is intended to be used together with [`LocalFile::fget`] when the caller knows + /// statically that there are no `fdget_pos` calls on the current thread. For example, you + /// might use it when calling `fget` from an ioctl, since ioctls usually do not touch the file + /// position. + /// + /// # Safety + /// + /// There must not be any active `fdget_pos` calls on the current thread. + #[inline] + pub unsafe fn assume_no_fdget_pos(me: ARef) -> ARef { + // INVARIANT: There are no `fdget_pos` calls on the current thread, and by the type + // invariants, if there is a `fdget_pos` call on another thread, then it took the + // `f_pos_lock` mutex. + // + // SAFETY: `LocalFile` and `File` have the same layout. + unsafe { ARef::from_raw(ARef::into_raw(me).cast()) } + } + + /// Returns a raw pointer to the inner C struct. + #[inline] + pub fn as_ptr(&self) -> *mut bindings::file { + self.inner.get() + } + + /// Returns the credentials of the task that originally opened the file. + pub fn cred(&self) -> &Credential { + // SAFETY: It's okay to read the `f_cred` field without synchronization because `f_cred` is + // never changed after initialization of the file. + let ptr = unsafe { (*self.as_ptr()).f_cred }; + + // SAFETY: The signature of this function ensures that the caller will only access the + // returned credential while the file is still valid, and the C side ensures that the + // credential stays valid at least as long as the file. + unsafe { Credential::from_ptr(ptr) } + } + + /// Returns the flags associated with the file. + /// + /// The flags are a combination of the constants in [`flags`]. + #[inline] + pub fn flags(&self) -> u32 { + // This `read_volatile` is intended to correspond to a READ_ONCE call. + // + // SAFETY: The file is valid because the shared reference guarantees a nonzero refcount. + // + // FIXME(read_once): Replace with `read_once` when available on the Rust side. + unsafe { core::ptr::addr_of!((*self.as_ptr()).f_flags).read_volatile() } + } +} + +impl File { + /// Creates a reference to a [`File`] from a valid pointer. + /// + /// # Safety + /// + /// * The caller must ensure that `ptr` points at a valid file and that the file's refcount is + /// positive for the duration of 'a. + /// * The caller must ensure that if there are active `fdget_pos` calls on this file, then they + /// took the `f_pos_lock` mutex. + #[inline] + pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a File { + // SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the + // duration of 'a. The cast is okay because `File` is `repr(transparent)`. + // + // INVARIANT: The caller guarantees that there are no problematic `fdget_pos` calls. + unsafe { &*ptr.cast() } + } +} + +// Make LocalFile methods available on File. +impl core::ops::Deref for File { + type Target = LocalFile; + #[inline] + fn deref(&self) -> &LocalFile { + // SAFETY: The caller provides a `&File`, and since it is a reference, it must point at a + // valid file for the desired duration. + // + // By the type invariants, there are no `fdget_pos` calls that did not take the + // `f_pos_lock` mutex. + unsafe { LocalFile::from_raw_file(self as *const File as *const bindings::file) } + } +} + +/// A file descriptor reservation. +/// +/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it, +/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran +/// out of available slots), but commit and drop never fail (and are mutually exclusive). +/// +/// Dropping the reservation happens in the destructor of this type. +/// +/// # Invariants +/// +/// The fd stored in this struct must correspond to a reserved file descriptor of the current task. +pub struct FileDescriptorReservation { + fd: u32, + /// Prevent values of this type from being moved to a different task. + /// + /// The `fd_install` and `put_unused_fd` functions assume that the value of `current` is + /// unchanged since the call to `get_unused_fd_flags`. By adding this marker to this type, we + /// prevent it from being moved across task boundaries, which ensures that `current` does not + /// change while this value exists. + _not_send: NotThreadSafe, +} + +impl FileDescriptorReservation { + /// Creates a new file descriptor reservation. + pub fn get_unused_fd_flags(flags: u32) -> Result { + // SAFETY: FFI call, there are no safety requirements on `flags`. + let fd: i32 = unsafe { bindings::get_unused_fd_flags(flags) }; + if fd < 0 { + return Err(Error::from_errno(fd)); + } + Ok(Self { + fd: fd as u32, + _not_send: NotThreadSafe, + }) + } + + /// Returns the file descriptor number that was reserved. + pub fn reserved_fd(&self) -> u32 { + self.fd + } + + /// Commits the reservation. + /// + /// The previously reserved file descriptor is bound to `file`. This method consumes the + /// [`FileDescriptorReservation`], so it will not be usable after this call. + pub fn fd_install(self, file: ARef) { + // SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`. We have not yet used + // the fd, so it is still valid, and `current` still refers to the same task, as this type + // cannot be moved across task boundaries. + // + // Furthermore, the file pointer is guaranteed to own a refcount by its type invariants, + // and we take ownership of that refcount by not running the destructor below. + // Additionally, the file is known to not have any non-shared `fdget_pos` calls, so even if + // this process starts using the file position, this will not result in a data race on the + // file position. + unsafe { bindings::fd_install(self.fd, file.as_ptr()) }; + + // `fd_install` consumes both the file descriptor and the file reference, so we cannot run + // the destructors. + core::mem::forget(self); + core::mem::forget(file); + } +} + +impl Drop for FileDescriptorReservation { + fn drop(&mut self) { + // SAFETY: By the type invariants of this type, `self.fd` was previously returned by + // `get_unused_fd_flags`. We have not yet used the fd, so it is still valid, and `current` + // still refers to the same task, as this type cannot be moved across task boundaries. + unsafe { bindings::put_unused_fd(self.fd) }; + } +} + +/// Represents the `EBADF` error code. +/// +/// Used for methods that can only fail with `EBADF`. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct BadFdError; + +impl From for Error { + #[inline] + fn from(_: BadFdError) -> Error { + EBADF + } +} + +impl core::fmt::Debug for BadFdError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.pad("EBADF") + } +} diff --git a/rust/kernel/generated_arch_static_branch_asm.rs.S b/rust/kernel/generated_arch_static_branch_asm.rs.S new file mode 100644 index 00000000000000..2afb638708db36 --- /dev/null +++ b/rust/kernel/generated_arch_static_branch_asm.rs.S @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include + +// Cut here. + +::kernel::concat_literals!(ARCH_STATIC_BRANCH_ASM("{symb} + {off} + {branch}", "{l_yes}")) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index a17ac8762d8f9f..347049df556b14 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -13,7 +13,7 @@ //! To initialize a `struct` with an in-place constructor you will need two things: //! - an in-place constructor, //! - a memory location that can hold your `struct` (this can be the [stack], an [`Arc`], -//! [`UniqueArc`], [`Box`] or any other smart pointer that implements [`InPlaceInit`]). +//! [`UniqueArc`], [`KBox`] or any other smart pointer that implements [`InPlaceInit`]). //! //! To get an in-place constructor there are generally three options: //! - directly creating an in-place constructor using the [`pin_init!`] macro, @@ -35,7 +35,7 @@ //! that you need to write `<-` instead of `:` for fields that you want to initialize in-place. //! //! ```rust -//! # #![allow(clippy::disallowed_names)] +//! # #![expect(clippy::disallowed_names)] //! use kernel::sync::{new_mutex, Mutex}; //! # use core::pin::Pin; //! #[pin_data] @@ -55,7 +55,7 @@ //! (or just the stack) to actually initialize a `Foo`: //! //! ```rust -//! # #![allow(clippy::disallowed_names)] +//! # #![expect(clippy::disallowed_names)] //! # use kernel::sync::{new_mutex, Mutex}; //! # use core::pin::Pin; //! # #[pin_data] @@ -68,7 +68,7 @@ //! # a <- new_mutex!(42, "Foo::a"), //! # b: 24, //! # }); -//! let foo: Result>> = Box::pin_init(foo, GFP_KERNEL); +//! let foo: Result>> = KBox::pin_init(foo, GFP_KERNEL); //! ``` //! //! For more information see the [`pin_init!`] macro. @@ -87,20 +87,19 @@ //! To declare an init macro/function you just return an [`impl PinInit`]: //! //! ```rust -//! # #![allow(clippy::disallowed_names)] //! # use kernel::{sync::Mutex, new_mutex, init::PinInit, try_pin_init}; //! #[pin_data] //! struct DriverData { //! #[pin] //! status: Mutex, -//! buffer: Box<[u8; 1_000_000]>, +//! buffer: KBox<[u8; 1_000_000]>, //! } //! //! impl DriverData { //! fn new() -> impl PinInit { //! try_pin_init!(Self { //! status <- new_mutex!(0, "DriverData::status"), -//! buffer: Box::init(kernel::init::zeroed(), GFP_KERNEL)?, +//! buffer: KBox::init(kernel::init::zeroed(), GFP_KERNEL)?, //! }) //! } //! } @@ -121,11 +120,12 @@ //! `slot` gets called. //! //! ```rust -//! # #![allow(unreachable_pub, clippy::disallowed_names)] +//! # #![expect(unreachable_pub, clippy::disallowed_names)] //! use kernel::{init, types::Opaque}; //! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; //! # mod bindings { -//! # #![allow(non_camel_case_types)] +//! # #![expect(non_camel_case_types)] +//! # #![expect(clippy::missing_safety_doc)] //! # pub struct foo; //! # pub unsafe fn init_foo(_ptr: *mut foo) {} //! # pub unsafe fn destroy_foo(_ptr: *mut foo) {} @@ -133,7 +133,7 @@ //! # } //! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround. //! # trait FromErrno { -//! # fn from_errno(errno: core::ffi::c_int) -> Error { +//! # fn from_errno(errno: kernel::ffi::c_int) -> Error { //! # // Dummy error that can be constructed outside the `kernel` crate. //! # Error::from(core::fmt::Error) //! # } @@ -211,13 +211,12 @@ //! [`pin_init!`]: crate::pin_init! use crate::{ - alloc::{box_ext::BoxExt, AllocError, Flags}, + alloc::{AllocError, Flags, KBox}, error::{self, Error}, sync::Arc, sync::UniqueArc, types::{Opaque, ScopeGuard}, }; -use alloc::boxed::Box; use core::{ cell::UnsafeCell, convert::Infallible, @@ -238,7 +237,7 @@ /// # Examples /// /// ```rust -/// # #![allow(clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex}; /// # use core::pin::Pin; /// #[pin_data] @@ -290,7 +289,7 @@ macro_rules! stack_pin_init { /// # Examples /// /// ```rust,ignore -/// # #![allow(clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; /// # use macros::pin_data; /// # use core::{alloc::AllocError, pin::Pin}; @@ -298,7 +297,7 @@ macro_rules! stack_pin_init { /// struct Foo { /// #[pin] /// a: Mutex, -/// b: Box, +/// b: KBox, /// } /// /// struct Bar { @@ -307,7 +306,7 @@ macro_rules! stack_pin_init { /// /// stack_try_pin_init!(let foo: Result, AllocError> = pin_init!(Foo { /// a <- new_mutex!(42), -/// b: Box::new(Bar { +/// b: KBox::new(Bar { /// x: 64, /// }, GFP_KERNEL)?, /// })); @@ -316,7 +315,7 @@ macro_rules! stack_pin_init { /// ``` /// /// ```rust,ignore -/// # #![allow(clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; /// # use macros::pin_data; /// # use core::{alloc::AllocError, pin::Pin}; @@ -324,7 +323,7 @@ macro_rules! stack_pin_init { /// struct Foo { /// #[pin] /// a: Mutex, -/// b: Box, +/// b: KBox, /// } /// /// struct Bar { @@ -333,7 +332,7 @@ macro_rules! stack_pin_init { /// /// stack_try_pin_init!(let foo: Pin<&mut Foo> =? pin_init!(Foo { /// a <- new_mutex!(42), -/// b: Box::new(Bar { +/// b: KBox::new(Bar { /// x: 64, /// }, GFP_KERNEL)?, /// })); @@ -368,7 +367,6 @@ macro_rules! stack_try_pin_init { /// The syntax is almost identical to that of a normal `struct` initializer: /// /// ```rust -/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// #[pin_data] @@ -392,7 +390,7 @@ macro_rules! stack_try_pin_init { /// }, /// }); /// # initializer } -/// # Box::pin_init(demo(), GFP_KERNEL).unwrap(); +/// # KBox::pin_init(demo(), GFP_KERNEL).unwrap(); /// ``` /// /// Arbitrary Rust expressions can be used to set the value of a variable. @@ -413,7 +411,6 @@ macro_rules! stack_try_pin_init { /// To create an initializer function, simply declare it like this: /// /// ```rust -/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, init::*}; /// # use core::pin::Pin; /// # #[pin_data] @@ -440,7 +437,7 @@ macro_rules! stack_try_pin_init { /// Users of `Foo` can now create it like this: /// /// ```rust -/// # #![allow(clippy::disallowed_names)] +/// # #![expect(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// # #[pin_data] @@ -462,13 +459,12 @@ macro_rules! stack_try_pin_init { /// # }) /// # } /// # } -/// let foo = Box::pin_init(Foo::new(), GFP_KERNEL); +/// let foo = KBox::pin_init(Foo::new(), GFP_KERNEL); /// ``` /// /// They can also easily embed it into their own `struct`s: /// /// ```rust -/// # #![allow(clippy::disallowed_names)] /// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; /// # #[pin_data] @@ -541,6 +537,7 @@ macro_rules! stack_try_pin_init { /// } /// pin_init!(&this in Buf { /// buf: [0; 64], +/// // SAFETY: TODO. /// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() }, /// pin: PhantomPinned, /// }); @@ -590,11 +587,10 @@ macro_rules! pin_init { /// # Examples /// /// ```rust -/// # #![feature(new_uninit)] /// use kernel::{init::{self, PinInit}, error::Error}; /// #[pin_data] /// struct BigBuf { -/// big: Box<[u8; 1024 * 1024 * 1024]>, +/// big: KBox<[u8; 1024 * 1024 * 1024]>, /// small: [u8; 1024 * 1024], /// ptr: *mut u8, /// } @@ -602,7 +598,7 @@ macro_rules! pin_init { /// impl BigBuf { /// fn new() -> impl PinInit { /// try_pin_init!(Self { -/// big: Box::init(init::zeroed(), GFP_KERNEL)?, +/// big: KBox::init(init::zeroed(), GFP_KERNEL)?, /// small: [0; 1024 * 1024], /// ptr: core::ptr::null_mut(), /// }? Error) @@ -694,16 +690,16 @@ macro_rules! init { /// # Examples /// /// ```rust -/// use kernel::{init::{PinInit, zeroed}, error::Error}; +/// use kernel::{alloc::KBox, init::{PinInit, zeroed}, error::Error}; /// struct BigBuf { -/// big: Box<[u8; 1024 * 1024 * 1024]>, +/// big: KBox<[u8; 1024 * 1024 * 1024]>, /// small: [u8; 1024 * 1024], /// } /// /// impl BigBuf { /// fn new() -> impl Init { /// try_init!(Self { -/// big: Box::init(zeroed(), GFP_KERNEL)?, +/// big: KBox::init(zeroed(), GFP_KERNEL)?, /// small: [0; 1024 * 1024], /// }? Error) /// } @@ -814,8 +810,8 @@ macro_rules! assert_pinned { /// A pin-initializer for the type `T`. /// /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can -/// be [`Box`], [`Arc`], [`UniqueArc`] or even the stack (see [`stack_pin_init!`]). Use the -/// [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc`] on this. +/// be [`KBox`], [`Arc`], [`UniqueArc`] or even the stack (see [`stack_pin_init!`]). Use +/// the [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc`] on this. /// /// Also see the [module description](self). /// @@ -854,7 +850,7 @@ pub unsafe trait PinInit: Sized { /// # Examples /// /// ```rust - /// # #![allow(clippy::disallowed_names)] + /// # #![expect(clippy::disallowed_names)] /// use kernel::{types::Opaque, init::pin_init_from_closure}; /// #[repr(C)] /// struct RawFoo([u8; 16]); @@ -875,6 +871,7 @@ pub unsafe trait PinInit: Sized { /// } /// /// let foo = pin_init!(Foo { + /// // SAFETY: TODO. /// raw <- unsafe { /// Opaque::ffi_init(|s| { /// init_foo(s); @@ -894,7 +891,7 @@ fn pin_chain(self, f: F) -> ChainPinInit } /// An initializer returned by [`PinInit::pin_chain`]. -pub struct ChainPinInit(I, F, __internal::Invariant<(E, Box)>); +pub struct ChainPinInit(I, F, __internal::Invariant<(E, KBox)>); // SAFETY: The `__pinned_init` function is implemented such that it // - returns `Ok(())` on successful initialization, @@ -920,8 +917,8 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { /// An initializer for `T`. /// /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can -/// be [`Box`], [`Arc`], [`UniqueArc`] or even the stack (see [`stack_pin_init!`]). Use the -/// [`InPlaceInit::init`] function of a smart pointer like [`Arc`] on this. Because +/// be [`KBox`], [`Arc`], [`UniqueArc`] or even the stack (see [`stack_pin_init!`]). Use +/// the [`InPlaceInit::init`] function of a smart pointer like [`Arc`] on this. Because /// [`PinInit`] is a super trait, you can use every function that takes it as well. /// /// Also see the [module description](self). @@ -965,7 +962,7 @@ pub unsafe trait Init: PinInit { /// # Examples /// /// ```rust - /// # #![allow(clippy::disallowed_names)] + /// # #![expect(clippy::disallowed_names)] /// use kernel::{types::Opaque, init::{self, init_from_closure}}; /// struct Foo { /// buf: [u8; 1_000_000], @@ -993,7 +990,7 @@ fn chain(self, f: F) -> ChainInit } /// An initializer returned by [`Init::chain`]. -pub struct ChainInit(I, F, __internal::Invariant<(E, Box)>); +pub struct ChainInit(I, F, __internal::Invariant<(E, KBox)>); // SAFETY: The `__init` function is implemented such that it // - returns `Ok(())` on successful initialization, @@ -1077,8 +1074,9 @@ pub fn uninit() -> impl Init, E> { /// # Examples /// /// ```rust -/// use kernel::{error::Error, init::init_array_from_fn}; -/// let array: Box<[usize; 1_000]> = Box::init::(init_array_from_fn(|i| i), GFP_KERNEL).unwrap(); +/// use kernel::{alloc::KBox, error::Error, init::init_array_from_fn}; +/// let array: KBox<[usize; 1_000]> = +/// KBox::init::(init_array_from_fn(|i| i), GFP_KERNEL).unwrap(); /// assert_eq!(array.len(), 1_000); /// ``` pub fn init_array_from_fn( @@ -1162,6 +1160,7 @@ pub fn pin_init_array_from_fn( // SAFETY: Every type can be initialized by-value. unsafe impl Init for T { unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: TODO. unsafe { slot.write(self) }; Ok(()) } @@ -1170,6 +1169,7 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> { // SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`. unsafe impl PinInit for T { unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: TODO. unsafe { self.__init(slot) } } } @@ -1243,26 +1243,6 @@ fn try_init(init: impl Init, flags: Flags) -> Result } } -impl InPlaceInit for Box { - type PinnedSelf = Pin; - - #[inline] - fn try_pin_init(init: impl PinInit, flags: Flags) -> Result - where - E: From, - { - as BoxExt<_>>::new_uninit(flags)?.write_pin_init(init) - } - - #[inline] - fn try_init(init: impl Init, flags: Flags) -> Result - where - E: From, - { - as BoxExt<_>>::new_uninit(flags)?.write_init(init) - } -} - impl InPlaceInit for UniqueArc { type PinnedSelf = Pin; @@ -1299,28 +1279,6 @@ pub trait InPlaceWrite { fn write_pin_init(self, init: impl PinInit) -> Result, E>; } -impl InPlaceWrite for Box> { - type Initialized = Box; - - fn write_init(mut self, init: impl Init) -> Result { - let slot = self.as_mut_ptr(); - // SAFETY: When init errors/panics, slot will get deallocated but not dropped, - // slot is valid. - unsafe { init.__init(slot)? }; - // SAFETY: All fields have been initialized. - Ok(unsafe { self.assume_init() }) - } - - fn write_pin_init(mut self, init: impl PinInit) -> Result, E> { - let slot = self.as_mut_ptr(); - // SAFETY: When init errors/panics, slot will get deallocated but not dropped, - // slot is valid and will not be moved, because we pin it later. - unsafe { init.__pinned_init(slot)? }; - // SAFETY: All fields have been initialized. - Ok(unsafe { self.assume_init() }.into()) - } -} - impl InPlaceWrite for UniqueArc> { type Initialized = UniqueArc; @@ -1411,6 +1369,7 @@ pub fn zeroed() -> impl Init { macro_rules! impl_zeroable { ($($({$($generics:tt)*})? $t:ty, )*) => { + // SAFETY: Safety comments written in the macro invocation. $(unsafe impl$($($generics)*)? Zeroable for $t {})* }; } @@ -1451,7 +1410,7 @@ macro_rules! impl_zeroable { // // In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant. {} Option>, - {} Option>, + {} Option>, // SAFETY: `null` pointer is valid. // diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 13cefd37512f8d..74329cc3262c05 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -15,9 +15,10 @@ /// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns pub(super) type Invariant = PhantomData *mut T>; -/// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this -/// type, since the closure needs to fulfill the same safety requirement as the -/// `__pinned_init`/`__init` functions. +/// Module-internal type implementing `PinInit` and `Init`. +/// +/// It is unsafe to create this type, since the closure needs to fulfill the same safety +/// requirement as the `__pinned_init`/`__init` functions. pub(crate) struct InitClosure(pub(crate) F, pub(crate) Invariant<(E, T)>); // SAFETY: While constructing the `InitClosure`, the user promised that it upholds the @@ -53,6 +54,7 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { pub unsafe trait HasPinData { type PinData: PinData; + #[expect(clippy::missing_safety_doc)] unsafe fn __pin_data() -> Self::PinData; } @@ -82,6 +84,7 @@ fn make_closure(self, f: F) -> F pub unsafe trait HasInitData { type InitData: InitData; + #[expect(clippy::missing_safety_doc)] unsafe fn __init_data() -> Self::InitData; } @@ -102,7 +105,7 @@ fn make_closure(self, f: F) -> F } } -pub struct AllData(PhantomData) -> Box>); +pub struct AllData(PhantomData) -> KBox>); impl Clone for AllData { fn clone(&self) -> Self { @@ -112,10 +115,12 @@ fn clone(&self) -> Self { impl Copy for AllData {} +// SAFETY: TODO. unsafe impl InitData for AllData { type Datee = T; } +// SAFETY: TODO. unsafe impl HasInitData for T { type InitData = AllData; diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 9a0c4650ef676d..1fd146a8324165 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -182,13 +182,13 @@ //! // Normally `Drop` bounds do not have the correct semantics, but for this purpose they do //! // (normally people want to know if a type has any kind of drop glue at all, here we want //! // to know if it has any kind of custom drop glue, which is exactly what this bound does). -//! #[allow(drop_bounds)] +//! #[expect(drop_bounds)] //! impl MustNotImplDrop for T {} //! impl MustNotImplDrop for Bar {} //! // Here comes a convenience check, if one implemented `PinnedDrop`, but forgot to add it to //! // `#[pin_data]`, then this will error with the same mechanic as above, this is not needed //! // for safety, but a good sanity check, since no normal code calls `PinnedDrop::drop`. -//! #[allow(non_camel_case_types)] +//! #[expect(non_camel_case_types)] //! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} //! impl< //! T: ::kernel::init::PinnedDrop, @@ -513,6 +513,7 @@ fn drop($($sig:tt)*) { } ), ) => { + // SAFETY: TODO. unsafe $($impl_sig)* { // Inherit all attributes and the type/ident tokens for the signature. $(#[$($attr)*])* @@ -872,6 +873,7 @@ unsafe fn __pin_data() -> Self::PinData { } } + // SAFETY: TODO. unsafe impl<$($impl_generics)*> $crate::init::__internal::PinData for __ThePinData<$($ty_generics)*> where $($whr)* @@ -923,14 +925,14 @@ impl<'__pin, $($impl_generics)*> ::core::marker::Unpin for $name<$($ty_generics) // `Drop`. Additionally we will implement this trait for the struct leading to a conflict, // if it also implements `Drop` trait MustNotImplDrop {} - #[allow(drop_bounds)] + #[expect(drop_bounds)] impl MustNotImplDrop for T {} impl<$($impl_generics)*> MustNotImplDrop for $name<$($ty_generics)*> where $($whr)* {} // We also take care to prevent users from writing a useless `PinnedDrop` implementation. // They might implement `PinnedDrop` correctly for the struct, but forget to give // `PinnedDrop` as the parameter to `#[pin_data]`. - #[allow(non_camel_case_types)] + #[expect(non_camel_case_types)] trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} @@ -987,6 +989,7 @@ fn drop(&mut self) { // // The functions are `unsafe` to prevent accidentally calling them. #[allow(dead_code)] + #[expect(clippy::missing_safety_doc)] impl<$($impl_generics)*> $pin_data<$($ty_generics)*> where $($whr)* { @@ -997,6 +1000,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> slot: *mut $p_type, init: impl $crate::init::PinInit<$p_type, E>, ) -> ::core::result::Result<(), E> { + // SAFETY: TODO. unsafe { $crate::init::PinInit::__pinned_init(init, slot) } } )* @@ -1007,6 +1011,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> slot: *mut $type, init: impl $crate::init::Init<$type, E>, ) -> ::core::result::Result<(), E> { + // SAFETY: TODO. unsafe { $crate::init::Init::__init(init, slot) } } )* @@ -1121,6 +1126,8 @@ macro_rules! __init_internal { // no possibility of returning without `unsafe`. struct __InitOk; // Get the data about fields from the supplied type. + // + // SAFETY: TODO. let data = unsafe { use $crate::init::__internal::$has_data; // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal @@ -1176,6 +1183,7 @@ fn assert_zeroable(_: *mut T) {} let init = move |slot| -> ::core::result::Result<(), $err> { init(slot).map(|__InitOk| ()) }; + // SAFETY: TODO. let init = unsafe { $crate::init::$construct_closure::<_, $err>(init) }; init }}; @@ -1324,6 +1332,8 @@ fn assert_zeroable(_: *mut T) {} // Endpoint, nothing more to munch, create the initializer. // Since we are in the closure that is never called, this will never get executed. // We abuse `slot` to get the correct type inference here: + // + // SAFETY: TODO. unsafe { // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal // information that is associated to already parsed fragments, so a path fragment diff --git a/rust/kernel/ioctl.rs b/rust/kernel/ioctl.rs index cfa7d080b53193..2fc7662339e54b 100644 --- a/rust/kernel/ioctl.rs +++ b/rust/kernel/ioctl.rs @@ -4,7 +4,7 @@ //! //! C header: [`include/asm-generic/ioctl.h`](srctree/include/asm-generic/ioctl.h) -#![allow(non_snake_case)] +#![expect(non_snake_case)] use crate::build_assert; diff --git a/rust/kernel/jump_label.rs b/rust/kernel/jump_label.rs new file mode 100644 index 00000000000000..4e974c768dbd51 --- /dev/null +++ b/rust/kernel/jump_label.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Logic for static keys. +//! +//! C header: [`include/linux/jump_label.h`](srctree/include/linux/jump_label.h). + +/// Branch based on a static key. +/// +/// Takes three arguments: +/// +/// * `key` - the path to the static variable containing the `static_key`. +/// * `keytyp` - the type of `key`. +/// * `field` - the name of the field of `key` that contains the `static_key`. +/// +/// # Safety +/// +/// The macro must be used with a real static key defined by C. +#[macro_export] +macro_rules! static_branch_unlikely { + ($key:path, $keytyp:ty, $field:ident) => {{ + let _key: *const $keytyp = ::core::ptr::addr_of!($key); + let _key: *const $crate::bindings::static_key_false = ::core::ptr::addr_of!((*_key).$field); + let _key: *const $crate::bindings::static_key = _key.cast(); + + #[cfg(not(CONFIG_JUMP_LABEL))] + { + $crate::bindings::static_key_count(_key.cast_mut()) > 0 + } + + #[cfg(CONFIG_JUMP_LABEL)] + $crate::jump_label::arch_static_branch! { $key, $keytyp, $field, false } + }}; +} +pub use static_branch_unlikely; + +/// Assert that the assembly block evaluates to a string literal. +#[cfg(CONFIG_JUMP_LABEL)] +const _: &str = include!(concat!( + env!("OBJTREE"), + "/rust/kernel/generated_arch_static_branch_asm.rs" +)); + +#[macro_export] +#[doc(hidden)] +#[cfg(CONFIG_JUMP_LABEL)] +macro_rules! arch_static_branch { + ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: { + $crate::asm!( + include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_static_branch_asm.rs")); + l_yes = label { + break 'my_label true; + }, + symb = sym $key, + off = const ::core::mem::offset_of!($keytyp, $field), + branch = const $crate::jump_label::bool_to_int($branch), + ); + + break 'my_label false; + }}; +} + +#[cfg(CONFIG_JUMP_LABEL)] +pub use arch_static_branch; + +/// A helper used by inline assembly to pass a boolean to as a `const` parameter. +/// +/// Using this function instead of a cast lets you assert that the input is a boolean, and not some +/// other type that can also be cast to an integer. +#[doc(hidden)] +pub const fn bool_to_int(b: bool) -> i32 { + b as i32 +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index b5f4b3ce6b4820..e1065a7551a39e 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -12,10 +12,11 @@ //! do so first instead of bypassing this crate. #![no_std] +#![feature(arbitrary_self_types)] #![feature(coerce_unsized)] #![feature(dispatch_from_dyn)] -#![feature(new_uninit)] -#![feature(receiver_trait)] +#![feature(inline_const)] +#![feature(lint_reasons)] #![feature(unsize)] // Ensure conditional compilation based on the kernel configuration works; @@ -26,25 +27,34 @@ // Allow proc-macros to refer to `::kernel` inside the `kernel` crate (this crate). extern crate self as kernel; +pub use ffi; + pub mod alloc; #[cfg(CONFIG_BLOCK)] pub mod block; mod build_assert; +pub mod cred; pub mod device; pub mod error; #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] pub mod firmware; +pub mod fs; pub mod init; pub mod ioctl; +pub mod jump_label; #[cfg(CONFIG_KUNIT)] pub mod kunit; pub mod list; +pub mod miscdevice; #[cfg(CONFIG_NET)] pub mod net; pub mod page; +pub mod pid_namespace; pub mod prelude; pub mod print; pub mod rbtree; +pub mod security; +pub mod seq_file; pub mod sizes; mod static_assert; #[doc(hidden)] @@ -53,6 +63,8 @@ pub mod sync; pub mod task; pub mod time; +pub mod tracepoint; +pub mod transmute; pub mod types; pub mod uaccess; pub mod workqueue; @@ -81,9 +93,32 @@ pub trait Module: Sized + Sync + Send { fn init(module: &'static ThisModule) -> error::Result; } +/// A module that is pinned and initialised in-place. +pub trait InPlaceModule: Sync + Send { + /// Creates an initialiser for the module. + /// + /// It is called when the module is loaded. + fn init(module: &'static ThisModule) -> impl init::PinInit; +} + +impl InPlaceModule for T { + fn init(module: &'static ThisModule) -> impl init::PinInit { + let initer = move |slot: *mut Self| { + let m = ::init(module)?; + + // SAFETY: `slot` is valid for write per the contract with `pin_init_from_closure`. + unsafe { slot.write(m) }; + Ok(()) + }; + + // SAFETY: On success, `initer` always fully initialises an instance of `Self`. + unsafe { init::pin_init_from_closure(initer) } + } +} + /// Equivalent to `THIS_MODULE` in the C API. /// -/// C header: [`include/linux/export.h`](srctree/include/linux/export.h) +/// C header: [`include/linux/init.h`](srctree/include/linux/init.h) pub struct ThisModule(*mut bindings::module); // SAFETY: `THIS_MODULE` may be used from all threads within a module. @@ -146,3 +181,38 @@ macro_rules! container_of { ptr.sub(offset) as *const $type }} } + +/// Helper for `.rs.S` files. +#[doc(hidden)] +#[macro_export] +macro_rules! concat_literals { + ($( $asm:literal )* ) => { + ::core::concat!($($asm),*) + }; +} + +/// Wrapper around `asm!` configured for use in the kernel. +/// +/// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!` +/// syntax. +// For x86, `asm!` uses intel syntax by default, but we want to use at&t syntax in the kernel. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[macro_export] +macro_rules! asm { + ($($asm:expr),* ; $($rest:tt)*) => { + ::core::arch::asm!( $($asm)*, options(att_syntax), $($rest)* ) + }; +} + +/// Wrapper around `asm!` configured for use in the kernel. +/// +/// Uses a semicolon to avoid parsing ambiguities, even though this does not match native `asm!` +/// syntax. +// For non-x86 arches we just pass through to `asm!`. +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +#[macro_export] +macro_rules! asm { + ($($asm:expr),* ; $($rest:tt)*) => { + ::core::arch::asm!( $($asm)*, $($rest)* ) + }; +} diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs index 5b4aec29eb6753..fb93330f4af48c 100644 --- a/rust/kernel/list.rs +++ b/rust/kernel/list.rs @@ -354,6 +354,7 @@ pub fn pop_front(&mut self) -> Option> { /// /// `item` must not be in a different linked list (with the same id). pub unsafe fn remove(&mut self, item: &T) -> Option> { + // SAFETY: TODO. let mut item = unsafe { ListLinks::fields(T::view_links(item)) }; // SAFETY: The user provided a reference, and reference are never dangling. // diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs index d801b9dc6291db..3483d8c232c4f1 100644 --- a/rust/kernel/list/arc.rs +++ b/rust/kernel/list/arc.rs @@ -441,9 +441,6 @@ fn as_ref(&self) -> &Arc { } } -// This is to allow [`ListArc`] (and variants) to be used as the type of `self`. -impl core::ops::Receiver for ListArc where T: ListArcSafe + ?Sized {} - // This is to allow coercion from `ListArc` to `ListArc` if `T` can be converted to the // dynamically-sized type (DST) `U`. impl core::ops::CoerceUnsized> for ListArc diff --git a/rust/kernel/list/arc_field.rs b/rust/kernel/list/arc_field.rs index 2330f673427ab0..c4b9dd50398264 100644 --- a/rust/kernel/list/arc_field.rs +++ b/rust/kernel/list/arc_field.rs @@ -56,7 +56,7 @@ pub unsafe fn assert_ref(&self) -> &T { /// /// The caller must have mutable access to the `ListArc` containing the struct with this /// field for the duration of the returned reference. - #[allow(clippy::mut_from_ref)] + #[expect(clippy::mut_from_ref)] pub unsafe fn assert_mut(&self) -> &mut T { // SAFETY: The caller has exclusive access to the `ListArc`, so they also have exclusive // access to this field. diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs new file mode 100644 index 00000000000000..7e2a79b3ae2636 --- /dev/null +++ b/rust/kernel/miscdevice.rs @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Miscdevice support. +//! +//! C headers: [`include/linux/miscdevice.h`](srctree/include/linux/miscdevice.h). +//! +//! Reference: + +use crate::{ + bindings, + error::{to_result, Error, Result, VTABLE_DEFAULT_ERROR}, + prelude::*, + str::CStr, + types::{ForeignOwnable, Opaque}, +}; +use core::{ + ffi::{c_int, c_long, c_uint, c_ulong}, + marker::PhantomData, + mem::MaybeUninit, + pin::Pin, +}; + +/// Options for creating a misc device. +#[derive(Copy, Clone)] +pub struct MiscDeviceOptions { + /// The name of the miscdevice. + pub name: &'static CStr, +} + +impl MiscDeviceOptions { + /// Create a raw `struct miscdev` ready for registration. + pub const fn into_raw(self) -> bindings::miscdevice { + // SAFETY: All zeros is valid for this C type. + let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() }; + result.minor = bindings::MISC_DYNAMIC_MINOR as _; + result.name = self.name.as_char_ptr(); + result.fops = create_vtable::(); + result + } +} + +/// A registration of a miscdevice. +/// +/// # Invariants +/// +/// `inner` is a registered misc device. +#[repr(transparent)] +#[pin_data(PinnedDrop)] +pub struct MiscDeviceRegistration { + #[pin] + inner: Opaque, + _t: PhantomData, +} + +// SAFETY: It is allowed to call `misc_deregister` on a different thread from where you called +// `misc_register`. +unsafe impl Send for MiscDeviceRegistration {} +// SAFETY: All `&self` methods on this type are written to ensure that it is safe to call them in +// parallel. +unsafe impl Sync for MiscDeviceRegistration {} + +impl MiscDeviceRegistration { + /// Register a misc device. + pub fn register(opts: MiscDeviceOptions) -> impl PinInit { + try_pin_init!(Self { + inner <- Opaque::try_ffi_init(move |slot: *mut bindings::miscdevice| { + // SAFETY: The initializer can write to the provided `slot`. + unsafe { slot.write(opts.into_raw::()) }; + + // SAFETY: We just wrote the misc device options to the slot. The miscdevice will + // get unregistered before `slot` is deallocated because the memory is pinned and + // the destructor of this type deallocates the memory. + // INVARIANT: If this returns `Ok(())`, then the `slot` will contain a registered + // misc device. + to_result(unsafe { bindings::misc_register(slot) }) + }), + _t: PhantomData, + }) + } + + /// Returns a raw pointer to the misc device. + pub fn as_raw(&self) -> *mut bindings::miscdevice { + self.inner.get() + } +} + +#[pinned_drop] +impl PinnedDrop for MiscDeviceRegistration { + fn drop(self: Pin<&mut Self>) { + // SAFETY: We know that the device is registered by the type invariants. + unsafe { bindings::misc_deregister(self.inner.get()) }; + } +} + +/// Trait implemented by the private data of an open misc device. +#[vtable] +pub trait MiscDevice { + /// What kind of pointer should `Self` be wrapped in. + type Ptr: ForeignOwnable + Send + Sync; + + /// Called when the misc device is opened. + /// + /// The returned pointer will be stored as the private data for the file. + fn open() -> Result; + + /// Called when the misc device is released. + fn release(device: Self::Ptr) { + drop(device); + } + + /// Handler for ioctls. + /// + /// The `cmd` argument is usually manipulated using the utilties in [`kernel::ioctl`]. + /// + /// [`kernel::ioctl`]: mod@crate::ioctl + fn ioctl( + _device: ::Borrowed<'_>, + _cmd: u32, + _arg: usize, + ) -> Result { + kernel::build_error(VTABLE_DEFAULT_ERROR) + } + + /// Handler for ioctls. + /// + /// Used for 32-bit userspace on 64-bit platforms. + /// + /// This method is optional and only needs to be provided if the ioctl relies on structures + /// that have different layout on 32-bit and 64-bit userspace. If no implementation is + /// provided, then `compat_ptr_ioctl` will be used instead. + #[cfg(CONFIG_COMPAT)] + fn compat_ioctl( + _device: ::Borrowed<'_>, + _cmd: u32, + _arg: usize, + ) -> Result { + kernel::build_error(VTABLE_DEFAULT_ERROR) + } +} + +const fn create_vtable() -> &'static bindings::file_operations { + const fn maybe_fn(check: bool, func: T) -> Option { + if check { + Some(func) + } else { + None + } + } + + struct VtableHelper { + _t: PhantomData, + } + impl VtableHelper { + const VTABLE: bindings::file_operations = bindings::file_operations { + open: Some(fops_open::), + release: Some(fops_release::), + unlocked_ioctl: maybe_fn(T::HAS_IOCTL, fops_ioctl::), + #[cfg(CONFIG_COMPAT)] + compat_ioctl: if T::HAS_COMPAT_IOCTL { + Some(fops_compat_ioctl::) + } else if T::HAS_IOCTL { + Some(bindings::compat_ptr_ioctl) + } else { + None + }, + // SAFETY: All zeros is a valid value for `bindings::file_operations`. + ..unsafe { MaybeUninit::zeroed().assume_init() } + }; + } + + &VtableHelper::::VTABLE +} + +/// # Safety +/// +/// `file` and `inode` must be the file and inode for a file that is undergoing initialization. +/// The file must be associated with a `MiscDeviceRegistration`. +unsafe extern "C" fn fops_open( + inode: *mut bindings::inode, + file: *mut bindings::file, +) -> c_int { + // SAFETY: The pointers are valid and for a file being opened. + let ret = unsafe { bindings::generic_file_open(inode, file) }; + if ret != 0 { + return ret; + } + + let ptr = match T::open() { + Ok(ptr) => ptr, + Err(err) => return err.to_errno(), + }; + + // SAFETY: The open call of a file owns the private data. + unsafe { (*file).private_data = ptr.into_foreign().cast_mut() }; + + 0 +} + +/// # Safety +/// +/// `file` and `inode` must be the file and inode for a file that is being released. The file must +/// be associated with a `MiscDeviceRegistration`. +unsafe extern "C" fn fops_release( + _inode: *mut bindings::inode, + file: *mut bindings::file, +) -> c_int { + // SAFETY: The release call of a file owns the private data. + let private = unsafe { (*file).private_data }; + // SAFETY: The release call of a file owns the private data. + let ptr = unsafe { ::from_foreign(private) }; + + T::release(ptr); + + 0 +} + +/// # Safety +/// +/// `file` must be a valid file that is associated with a `MiscDeviceRegistration`. +unsafe extern "C" fn fops_ioctl( + file: *mut bindings::file, + cmd: c_uint, + arg: c_ulong, +) -> c_long { + // SAFETY: The ioctl call of a file can access the private data. + let private = unsafe { (*file).private_data }; + // SAFETY: Ioctl calls can borrow the private data of the file. + let device = unsafe { ::borrow(private) }; + + match T::ioctl(device, cmd, arg as usize) { + Ok(ret) => ret as c_long, + Err(err) => err.to_errno() as c_long, + } +} + +/// # Safety +/// +/// `file` must be a valid file that is associated with a `MiscDeviceRegistration`. +#[cfg(CONFIG_COMPAT)] +unsafe extern "C" fn fops_compat_ioctl( + file: *mut bindings::file, + cmd: c_uint, + arg: c_ulong, +) -> c_long { + // SAFETY: The compat ioctl call of a file can access the private data. + let private = unsafe { (*file).private_data }; + // SAFETY: Ioctl calls can borrow the private data of the file. + let device = unsafe { ::borrow(private) }; + + match T::compat_ioctl(device, cmd, arg as usize) { + Ok(ret) => ret as c_long, + Err(err) => err.to_errno() as c_long, + } +} diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index 910ce867480a8a..2fbfb6a94c11e6 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -314,7 +314,7 @@ impl Adapter { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn soft_reset_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on @@ -328,7 +328,7 @@ impl Adapter { /// # Safety /// /// `phydev` must be passed by the corresponding callback in `phy_driver`. - unsafe extern "C" fn probe_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int { + unsafe extern "C" fn probe_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we can exclusively access `phy_device` because @@ -345,7 +345,7 @@ impl Adapter { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn get_features_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on @@ -359,7 +359,7 @@ impl Adapter { /// # Safety /// /// `phydev` must be passed by the corresponding callback in `phy_driver`. - unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int { + unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int { from_result(|| { // SAFETY: The C core code ensures that the accessors on // `Device` are okay to call even though `phy_device->lock` @@ -373,7 +373,7 @@ impl Adapter { /// # Safety /// /// `phydev` must be passed by the corresponding callback in `phy_driver`. - unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int { + unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int { from_result(|| { // SAFETY: The C core code ensures that the accessors on // `Device` are okay to call even though `phy_device->lock` @@ -389,7 +389,7 @@ impl Adapter { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn config_aneg_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on @@ -405,7 +405,7 @@ impl Adapter { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn read_status_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { from_result(|| { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on @@ -421,7 +421,7 @@ impl Adapter { /// `phydev` must be passed by the corresponding callback in `phy_driver`. unsafe extern "C" fn match_phy_device_callback( phydev: *mut bindings::phy_device, - ) -> core::ffi::c_int { + ) -> crate::ffi::c_int { // SAFETY: This callback is called only in contexts // where we hold `phy_device->lock`, so the accessors on // `Device` are okay to call. @@ -848,9 +848,7 @@ const fn as_int(&self) -> u32 { /// } /// }; /// -/// #[cfg(MODULE)] -/// #[no_mangle] -/// static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id; 2] = [ +/// const _DEVICE_TABLE: [::kernel::bindings::mdio_device_id; 2] = [ /// ::kernel::bindings::mdio_device_id { /// phy_id: 0x00000001, /// phy_id_mask: 0xffffffff, @@ -860,6 +858,9 @@ const fn as_int(&self) -> u32 { /// phy_id_mask: 0, /// }, /// ]; +/// #[cfg(MODULE)] +/// #[no_mangle] +/// static __mod_device_table__mdio__phydev: [::kernel::bindings::mdio_device_id; 2] = _DEVICE_TABLE; /// ``` #[macro_export] macro_rules! module_phy_driver { @@ -871,9 +872,7 @@ macro_rules! module_phy_driver { (@device_table [$($dev:expr),+]) => { // SAFETY: C will not read off the end of this constant since the last element is zero. - #[cfg(MODULE)] - #[no_mangle] - static __mod_mdio__phydev_device_table: [$crate::bindings::mdio_device_id; + const _DEVICE_TABLE: [$crate::bindings::mdio_device_id; $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = [ $($dev.mdio_device_id()),+, $crate::bindings::mdio_device_id { @@ -881,6 +880,11 @@ macro_rules! module_phy_driver { phy_id_mask: 0 } ]; + + #[cfg(MODULE)] + #[no_mangle] + static __mod_device_table__mdio__phydev: [$crate::bindings::mdio_device_id; + $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = _DEVICE_TABLE; }; (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => { diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs index 208a006d587c15..fdac6c375fe46e 100644 --- a/rust/kernel/page.rs +++ b/rust/kernel/page.rs @@ -20,6 +20,16 @@ /// A bitmask that gives the page containing a given address. pub const PAGE_MASK: usize = !(PAGE_SIZE - 1); +/// Round up the given number to the next multiple of [`PAGE_SIZE`]. +/// +/// It is incorrect to pass an address where the next multiple of [`PAGE_SIZE`] doesn't fit in a +/// [`usize`]. +pub const fn page_align(addr: usize) -> usize { + // Parentheses around `PAGE_SIZE - 1` to avoid triggering overflow sanitizers in the wrong + // cases. + (addr + (PAGE_SIZE - 1)) & PAGE_MASK +} + /// A pointer to a page that owns the page allocation. /// /// # Invariants diff --git a/rust/kernel/pid_namespace.rs b/rust/kernel/pid_namespace.rs new file mode 100644 index 00000000000000..0e93808e4639b3 --- /dev/null +++ b/rust/kernel/pid_namespace.rs @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (c) 2024 Christian Brauner + +//! Pid namespaces. +//! +//! C header: [`include/linux/pid_namespace.h`](srctree/include/linux/pid_namespace.h) and +//! [`include/linux/pid.h`](srctree/include/linux/pid.h) + +use crate::{ + bindings, + types::{AlwaysRefCounted, Opaque}, +}; +use core::ptr; + +/// Wraps the kernel's `struct pid_namespace`. Thread safe. +/// +/// This structure represents the Rust abstraction for a C `struct pid_namespace`. This +/// implementation abstracts the usage of an already existing C `struct pid_namespace` within Rust +/// code that we get passed from the C side. +#[repr(transparent)] +pub struct PidNamespace { + inner: Opaque, +} + +impl PidNamespace { + /// Returns a raw pointer to the inner C struct. + #[inline] + pub fn as_ptr(&self) -> *mut bindings::pid_namespace { + self.inner.get() + } + + /// Creates a reference to a [`PidNamespace`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the + /// returned [`PidNamespace`] reference. + pub unsafe fn from_ptr<'a>(ptr: *const bindings::pid_namespace) -> &'a Self { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `PidNamespace` type being transparent makes the cast ok. + unsafe { &*ptr.cast() } + } +} + +// SAFETY: Instances of `PidNamespace` are always reference-counted. +unsafe impl AlwaysRefCounted for PidNamespace { + #[inline] + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::get_pid_ns(self.as_ptr()) }; + } + + #[inline] + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is non-zero. + unsafe { bindings::put_pid_ns(obj.cast().as_ptr()) } + } +} + +// SAFETY: +// - `PidNamespace::dec_ref` can be called from any thread. +// - It is okay to send ownership of `PidNamespace` across thread boundaries. +unsafe impl Send for PidNamespace {} + +// SAFETY: It's OK to access `PidNamespace` through shared references from other threads because +// we're either accessing properties that don't change or that are properly synchronised by C code. +unsafe impl Sync for PidNamespace {} diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 4571daec0961bb..9ab4e0b6cbc912 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -14,10 +14,7 @@ #[doc(no_inline)] pub use core::pin::Pin; -pub use crate::alloc::{box_ext::BoxExt, flags::*, vec_ext::VecExt}; - -#[doc(no_inline)] -pub use alloc::{boxed::Box, vec::Vec}; +pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec}; #[doc(no_inline)] pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable}; @@ -27,6 +24,8 @@ // `super::std_vendor` is hidden, which makes the macro inline for some reason. #[doc(no_inline)] pub use super::dbg; +pub use super::fmt; +pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn}; pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; pub use super::{init, pin_init, try_init, try_pin_init}; diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs index 508b0221256c97..a28077a7cb3011 100644 --- a/rust/kernel/print.rs +++ b/rust/kernel/print.rs @@ -14,6 +14,7 @@ use crate::str::RawFormatter; // Called from `vsprintf` with format specifier `%pA`. +#[expect(clippy::missing_safety_doc)] #[no_mangle] unsafe extern "C" fn rust_fmt_argument( buf: *mut c_char, @@ -23,6 +24,7 @@ use fmt::Write; // SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`. let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) }; + // SAFETY: TODO. let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) }); w.pos().cast() } @@ -102,6 +104,7 @@ pub unsafe fn call_printk( ) { // `_printk` does not seem to fail in any path. #[cfg(CONFIG_PRINTK)] + // SAFETY: TODO. unsafe { bindings::_printk( format_string.as_ptr() as _, @@ -137,7 +140,7 @@ pub fn call_printk_cont(args: fmt::Arguments<'_>) { #[doc(hidden)] #[cfg(not(testlib))] #[macro_export] -#[allow(clippy::crate_in_macro_def)] +#[expect(clippy::crate_in_macro_def)] macro_rules! print_macro ( // The non-continuation cases (most of them, e.g. `INFO`). ($format_string:path, false, $($arg:tt)+) => ( diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs index 25eb36fd1cdceb..cb4415a1225825 100644 --- a/rust/kernel/rbtree.rs +++ b/rust/kernel/rbtree.rs @@ -7,7 +7,6 @@ //! Reference: use crate::{alloc::Flags, bindings, container_of, error::Result, prelude::*}; -use alloc::boxed::Box; use core::{ cmp::{Ord, Ordering}, marker::PhantomData, @@ -497,7 +496,7 @@ fn drop(&mut self) { // but it is not observable. The loop invariant is still maintained. // SAFETY: `this` is valid per the loop invariant. - unsafe { drop(Box::from_raw(this.cast_mut())) }; + unsafe { drop(KBox::from_raw(this.cast_mut())) }; } } } @@ -764,7 +763,7 @@ pub fn remove_current(self) -> (Option, RBTreeNode) { // point to the links field of `Node` objects. let this = unsafe { container_of!(self.current.as_ptr(), Node, links) }.cast_mut(); // SAFETY: `this` is valid by the type invariants as described above. - let node = unsafe { Box::from_raw(this) }; + let node = unsafe { KBox::from_raw(this) }; let node = RBTreeNode { node }; // SAFETY: The reference to the tree used to create the cursor outlives the cursor, so // the tree cannot change. By the tree invariant, all nodes are valid. @@ -809,7 +808,7 @@ fn remove_neighbor(&mut self, direction: Direction) -> Option> // point to the links field of `Node` objects. let this = unsafe { container_of!(neighbor, Node, links) }.cast_mut(); // SAFETY: `this` is valid by the type invariants as described above. - let node = unsafe { Box::from_raw(this) }; + let node = unsafe { KBox::from_raw(this) }; return Some(RBTreeNode { node }); } None @@ -884,7 +883,8 @@ fn get_neighbor_raw(&self, direction: Direction) -> Option(node: NonNull) -> (&'b K, &'b V) { @@ -894,7 +894,8 @@ unsafe fn to_key_value<'b>(node: NonNull) -> (&'b K, &'b V) { (k, unsafe { &*v }) } - /// SAFETY: + /// # Safety + /// /// - `node` must be a valid pointer to a node in an [`RBTree`]. /// - The caller has mutable access to `node` for the duration of 'b. unsafe fn to_key_value_mut<'b>(node: NonNull) -> (&'b K, &'b mut V) { @@ -904,7 +905,8 @@ unsafe fn to_key_value_mut<'b>(node: NonNull) -> (&'b K, &'b (k, unsafe { &mut *v }) } - /// SAFETY: + /// # Safety + /// /// - `node` must be a valid pointer to a node in an [`RBTree`]. /// - The caller has immutable access to the key for the duration of 'b. unsafe fn to_key_value_raw<'b>(node: NonNull) -> (&'b K, *mut V) { @@ -1035,7 +1037,7 @@ fn next(&mut self) -> Option { /// It contains the memory needed to hold a node that can be inserted into a red-black tree. One /// can be obtained by directly allocating it ([`RBTreeNodeReservation::new`]). pub struct RBTreeNodeReservation { - node: Box>>, + node: KBox>>, } impl RBTreeNodeReservation { @@ -1043,7 +1045,7 @@ impl RBTreeNodeReservation { /// call to [`RBTree::insert`]. pub fn new(flags: Flags) -> Result> { Ok(RBTreeNodeReservation { - node: as BoxExt<_>>::new_uninit(flags)?, + node: KBox::new_uninit(flags)?, }) } } @@ -1059,14 +1061,15 @@ impl RBTreeNodeReservation { /// Initialises a node reservation. /// /// It then becomes an [`RBTreeNode`] that can be inserted into a tree. - pub fn into_node(mut self, key: K, value: V) -> RBTreeNode { - self.node.write(Node { - key, - value, - links: bindings::rb_node::default(), - }); - // SAFETY: We just wrote to it. - let node = unsafe { self.node.assume_init() }; + pub fn into_node(self, key: K, value: V) -> RBTreeNode { + let node = KBox::write( + self.node, + Node { + key, + value, + links: bindings::rb_node::default(), + }, + ); RBTreeNode { node } } } @@ -1076,7 +1079,7 @@ pub fn into_node(mut self, key: K, value: V) -> RBTreeNode { /// The node is fully initialised (with key and value) and can be inserted into a tree without any /// extra allocations or failure paths. pub struct RBTreeNode { - node: Box>, + node: KBox>, } impl RBTreeNode { @@ -1088,7 +1091,9 @@ pub fn new(key: K, value: V, flags: Flags) -> Result> { /// Get the key and value from inside the node. pub fn to_key_value(self) -> (K, V) { - (self.node.key, self.node.value) + let node = KBox::into_inner(self.node); + + (node.key, node.value) } } @@ -1110,7 +1115,7 @@ impl RBTreeNode { /// may be freed (but only for the key/value; memory for the node itself is kept for reuse). pub fn into_reservation(self) -> RBTreeNodeReservation { RBTreeNodeReservation { - node: Box::drop_contents(self.node), + node: KBox::drop_contents(self.node), } } } @@ -1161,7 +1166,7 @@ impl<'a, K, V> RawVacantEntry<'a, K, V> { /// The `node` must have a key such that inserting it here does not break the ordering of this /// [`RBTree`]. fn insert(self, node: RBTreeNode) -> &'a mut V { - let node = Box::into_raw(node.node); + let node = KBox::into_raw(node.node); // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when // the node is removed or replaced. @@ -1235,21 +1240,24 @@ pub fn remove_node(self) -> RBTreeNode { // SAFETY: The node was a node in the tree, but we removed it, so we can convert it // back into a box. node: unsafe { - Box::from_raw(container_of!(self.node_links, Node, links).cast_mut()) + KBox::from_raw(container_of!(self.node_links, Node, links).cast_mut()) }, } } /// Takes the value of the entry out of the map, and returns it. pub fn remove(self) -> V { - self.remove_node().node.value + let rb_node = self.remove_node(); + let node = KBox::into_inner(rb_node.node); + + node.value } /// Swap the current node for the provided node. /// /// The key of both nodes must be equal. fn replace(self, node: RBTreeNode) -> RBTreeNode { - let node = Box::into_raw(node.node); + let node = KBox::into_raw(node.node); // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when // the node is removed or replaced. @@ -1265,7 +1273,7 @@ fn replace(self, node: RBTreeNode) -> RBTreeNode { // - `self.node_ptr` produces a valid pointer to a node in the tree. // - Now that we removed this entry from the tree, we can convert the node to a box. let old_node = - unsafe { Box::from_raw(container_of!(self.node_links, Node, links).cast_mut()) }; + unsafe { KBox::from_raw(container_of!(self.node_links, Node, links).cast_mut()) }; RBTreeNode { node: old_node } } diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs new file mode 100644 index 00000000000000..2522868862a1bf --- /dev/null +++ b/rust/kernel/security.rs @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Linux Security Modules (LSM). +//! +//! C header: [`include/linux/security.h`](srctree/include/linux/security.h). + +use crate::{ + bindings, + error::{to_result, Result}, +}; + +/// A security context string. +/// +/// # Invariants +/// +/// The `secdata` and `seclen` fields correspond to a valid security context as returned by a +/// successful call to `security_secid_to_secctx`, that has not yet been destroyed by calling +/// `security_release_secctx`. +pub struct SecurityCtx { + secdata: *mut core::ffi::c_char, + seclen: usize, +} + +impl SecurityCtx { + /// Get the security context given its id. + pub fn from_secid(secid: u32) -> Result { + let mut secdata = core::ptr::null_mut(); + let mut seclen = 0u32; + // SAFETY: Just a C FFI call. The pointers are valid for writes. + to_result(unsafe { bindings::security_secid_to_secctx(secid, &mut secdata, &mut seclen) })?; + + // INVARIANT: If the above call did not fail, then we have a valid security context. + Ok(Self { + secdata, + seclen: seclen as usize, + }) + } + + /// Returns whether the security context is empty. + pub fn is_empty(&self) -> bool { + self.seclen == 0 + } + + /// Returns the length of this security context. + pub fn len(&self) -> usize { + self.seclen + } + + /// Returns the bytes for this security context. + pub fn as_bytes(&self) -> &[u8] { + let ptr = self.secdata; + if ptr.is_null() { + debug_assert_eq!(self.seclen, 0); + // We can't pass a null pointer to `slice::from_raw_parts` even if the length is zero. + return &[]; + } + + // SAFETY: The call to `security_secid_to_secctx` guarantees that the pointer is valid for + // `seclen` bytes. Furthermore, if the length is zero, then we have ensured that the + // pointer is not null. + unsafe { core::slice::from_raw_parts(ptr.cast(), self.seclen) } + } +} + +impl Drop for SecurityCtx { + fn drop(&mut self) { + // SAFETY: By the invariant of `Self`, this frees a pointer that came from a successful + // call to `security_secid_to_secctx` and has not yet been destroyed by + // `security_release_secctx`. + unsafe { bindings::security_release_secctx(self.secdata, self.seclen as u32) }; + } +} diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs new file mode 100644 index 00000000000000..6ca29d576d029d --- /dev/null +++ b/rust/kernel/seq_file.rs @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Seq file bindings. +//! +//! C header: [`include/linux/seq_file.h`](srctree/include/linux/seq_file.h) + +use crate::{bindings, c_str, types::NotThreadSafe, types::Opaque}; + +/// A utility for generating the contents of a seq file. +#[repr(transparent)] +pub struct SeqFile { + inner: Opaque, + _not_send: NotThreadSafe, +} + +impl SeqFile { + /// Creates a new [`SeqFile`] from a raw pointer. + /// + /// # Safety + /// + /// The caller must ensure that for the duration of 'a the following is satisfied: + /// * The pointer points at a valid `struct seq_file`. + /// * The `struct seq_file` is not accessed from any other thread. + pub unsafe fn from_raw<'a>(ptr: *mut bindings::seq_file) -> &'a SeqFile { + // SAFETY: The caller ensures that the reference is valid for 'a. There's no way to trigger + // a data race by using the `&SeqFile` since this is the only thread accessing the seq_file. + // + // CAST: The layout of `struct seq_file` and `SeqFile` is compatible. + unsafe { &*ptr.cast() } + } + + /// Used by the [`seq_print`] macro. + pub fn call_printf(&self, args: core::fmt::Arguments<'_>) { + // SAFETY: Passing a void pointer to `Arguments` is valid for `%pA`. + unsafe { + bindings::seq_printf( + self.inner.get(), + c_str!("%pA").as_char_ptr(), + &args as *const _ as *const core::ffi::c_void, + ); + } + } +} + +/// Write to a [`SeqFile`] with the ordinary Rust formatting syntax. +#[macro_export] +macro_rules! seq_print { + ($m:expr, $($arg:tt)+) => ( + $m.call_printf(format_args!($($arg)+)) + ); +} +pub use seq_print; diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs index 67bf9d37ddb557..279bd353687a74 100644 --- a/rust/kernel/std_vendor.rs +++ b/rust/kernel/std_vendor.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +//! Rust standard library vendored code. +//! //! The contents of this file come from the Rust standard library, hosted in //! the repository, licensed under //! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details, @@ -14,9 +16,9 @@ /// /// ```rust /// let a = 2; -/// # #[allow(clippy::dbg_macro)] +/// # #[expect(clippy::disallowed_macros)] /// let b = dbg!(a * 2) + 1; -/// // ^-- prints: [src/main.rs:2] a * 2 = 4 +/// // ^-- prints: [src/main.rs:3:9] a * 2 = 4 /// assert_eq!(b, 5); /// ``` /// @@ -52,7 +54,7 @@ /// With a method call: /// /// ```rust -/// # #[allow(clippy::dbg_macro)] +/// # #[expect(clippy::disallowed_macros)] /// fn foo(n: usize) { /// if dbg!(n.checked_sub(4)).is_some() { /// // ... @@ -65,14 +67,13 @@ /// This prints to the kernel log: /// /// ```text,ignore -/// [src/main.rs:4] n.checked_sub(4) = None +/// [src/main.rs:3:8] n.checked_sub(4) = None /// ``` /// /// Naive factorial implementation: /// /// ```rust -/// # #[allow(clippy::dbg_macro)] -/// # { +/// # #![expect(clippy::disallowed_macros)] /// fn factorial(n: u32) -> u32 { /// if dbg!(n <= 1) { /// dbg!(1) @@ -82,21 +83,20 @@ /// } /// /// dbg!(factorial(4)); -/// # } /// ``` /// /// This prints to the kernel log: /// /// ```text,ignore -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = true -/// [src/main.rs:4] 1 = 1 -/// [src/main.rs:5] n * factorial(n - 1) = 2 -/// [src/main.rs:5] n * factorial(n - 1) = 6 -/// [src/main.rs:5] n * factorial(n - 1) = 24 -/// [src/main.rs:11] factorial(4) = 24 +/// [src/main.rs:3:8] n <= 1 = false +/// [src/main.rs:3:8] n <= 1 = false +/// [src/main.rs:3:8] n <= 1 = false +/// [src/main.rs:3:8] n <= 1 = true +/// [src/main.rs:4:9] 1 = 1 +/// [src/main.rs:5:9] n * factorial(n - 1) = 2 +/// [src/main.rs:5:9] n * factorial(n - 1) = 6 +/// [src/main.rs:5:9] n * factorial(n - 1) = 24 +/// [src/main.rs:11:1] factorial(4) = 24 /// ``` /// /// The `dbg!(..)` macro moves the input: @@ -118,7 +118,7 @@ /// a tuple (and return it, too): /// /// ``` -/// # #[allow(clippy::dbg_macro)] +/// # #![expect(clippy::disallowed_macros)] /// assert_eq!(dbg!(1usize, 2u32), (1, 2)); /// ``` /// @@ -127,11 +127,9 @@ /// invocations. You can use a 1-tuple directly if you need one: /// /// ``` -/// # #[allow(clippy::dbg_macro)] -/// # { +/// # #![expect(clippy::disallowed_macros)] /// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored /// assert_eq!((1,), dbg!((1u32,))); // 1-tuple -/// # } /// ``` /// /// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index bb8d4f41475b59..d04c12a1426d1c 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -2,8 +2,7 @@ //! String representations. -use crate::alloc::{flags::*, vec_ext::VecExt, AllocError}; -use alloc::vec::Vec; +use crate::alloc::{flags::*, AllocError, KVec}; use core::fmt::{self, Write}; use core::ops::{self, Deref, DerefMut, Index}; @@ -162,10 +161,10 @@ pub const fn len(&self) -> usize { /// Returns the length of this string with `NUL`. #[inline] pub const fn len_with_nul(&self) -> usize { - // SAFETY: This is one of the invariant of `CStr`. - // We add a `unreachable_unchecked` here to hint the optimizer that - // the value returned from this function is non-zero. if self.0.is_empty() { + // SAFETY: This is one of the invariant of `CStr`. + // We add a `unreachable_unchecked` here to hint the optimizer that + // the value returned from this function is non-zero. unsafe { core::hint::unreachable_unchecked() }; } self.0.len() @@ -185,7 +184,7 @@ pub const fn is_empty(&self) -> bool { /// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr` /// must not be mutated. #[inline] - pub unsafe fn from_char_ptr<'a>(ptr: *const core::ffi::c_char) -> &'a Self { + pub unsafe fn from_char_ptr<'a>(ptr: *const crate::ffi::c_char) -> &'a Self { // SAFETY: The safety precondition guarantees `ptr` is a valid pointer // to a `NUL`-terminated C string. let len = unsafe { bindings::strlen(ptr) } + 1; @@ -248,7 +247,7 @@ pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr { /// Returns a C pointer to the string. #[inline] - pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { + pub const fn as_char_ptr(&self) -> *const crate::ffi::c_char { self.0.as_ptr() as _ } @@ -301,6 +300,7 @@ pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { /// ``` #[inline] pub unsafe fn as_str_unchecked(&self) -> &str { + // SAFETY: TODO. unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } } @@ -524,7 +524,28 @@ macro_rules! c_str { #[cfg(test)] mod tests { use super::*; - use alloc::format; + + struct String(CString); + + impl String { + fn from_fmt(args: fmt::Arguments<'_>) -> Self { + String(CString::try_from_fmt(args).unwrap()) + } + } + + impl Deref for String { + type Target = str; + + fn deref(&self) -> &str { + self.0.to_str().unwrap() + } + } + + macro_rules! format { + ($($f:tt)*) => ({ + &*String::from_fmt(kernel::fmt!($($f)*)) + }) + } const ALL_ASCII_CHARS: &'static str = "\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\x09\\x0a\\x0b\\x0c\\x0d\\x0e\\x0f\ @@ -790,7 +811,7 @@ fn write_str(&mut self, s: &str) -> fmt::Result { /// assert_eq!(s.is_ok(), false); /// ``` pub struct CString { - buf: Vec, + buf: KVec, } impl CString { @@ -803,7 +824,7 @@ pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result { let size = f.bytes_written(); // Allocate a vector with the required number of bytes, and write to it. - let mut buf = as VecExt<_>>::with_capacity(size, GFP_KERNEL)?; + let mut buf = KVec::with_capacity(size, GFP_KERNEL)?; // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes. let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) }; f.write_fmt(args)?; @@ -850,10 +871,9 @@ impl<'a> TryFrom<&'a CStr> for CString { type Error = AllocError; fn try_from(cstr: &'a CStr) -> Result { - let mut buf = Vec::new(); + let mut buf = KVec::new(); - as VecExt<_>>::extend_from_slice(&mut buf, cstr.as_bytes_with_nul(), GFP_KERNEL) - .map_err(|_| AllocError)?; + buf.extend_from_slice(cstr.as_bytes_with_nul(), GFP_KERNEL)?; // INVARIANT: The `CStr` and `CString` types have the same invariants for // the string data, and we copied it over without changes. diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 0ab20975a3b5db..1eab7ebf25fd39 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -11,9 +11,11 @@ mod condvar; pub mod lock; mod locked_by; +pub mod poll; pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; +pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy}; pub use lock::mutex::{new_mutex, Mutex}; pub use lock::spinlock::{new_spinlock, SpinLock}; pub use locked_by::LockedBy; diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 3021f30fd822f6..fa4509406ee909 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -17,13 +17,12 @@ //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html use crate::{ - alloc::{box_ext::BoxExt, AllocError, Flags}, + alloc::{AllocError, Flags, KBox}, bindings, init::{self, InPlaceInit, Init, PinInit}, try_init, types::{ForeignOwnable, Opaque}, }; -use alloc::boxed::Box; use core::{ alloc::Layout, fmt, @@ -171,9 +170,6 @@ unsafe fn container_of(ptr: *const T) -> NonNull> { } } -// This is to allow [`Arc`] (and variants) to be used as the type of `self`. -impl core::ops::Receiver for Arc {} - // This is to allow coercion from `Arc` to `Arc` if `T` can be converted to the // dynamically-sized type (DST) `U`. impl, U: ?Sized> core::ops::CoerceUnsized> for Arc {} @@ -204,11 +200,11 @@ pub fn new(contents: T, flags: Flags) -> Result { data: contents, }; - let inner = as BoxExt<_>>::new(value, flags)?; + let inner = KBox::new(value, flags)?; // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new // `Arc` object. - Ok(unsafe { Self::from_inner(Box::leak(inner).into()) }) + Ok(unsafe { Self::from_inner(KBox::leak(inner).into()) }) } } @@ -336,12 +332,12 @@ pub fn into_unique_or_drop(self) -> Option>> { impl ForeignOwnable for Arc { type Borrowed<'a> = ArcBorrow<'a, T>; - fn into_foreign(self) -> *const core::ffi::c_void { + fn into_foreign(self) -> *const crate::ffi::c_void { ManuallyDrop::new(self).ptr.as_ptr() as _ } - unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> { - // SAFETY: By the safety requirement of this function, we know that `ptr` came from + unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> ArcBorrow<'a, T> { + // By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`. let inner = NonNull::new(ptr as *mut ArcInner).unwrap(); @@ -350,7 +346,7 @@ unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> { unsafe { ArcBorrow::new(inner) } } - unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self { // SAFETY: By the safety requirement of this function, we know that `ptr` came from // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and // holds a reference count increment that is transferrable to us. @@ -401,8 +397,8 @@ fn drop(&mut self) { if is_zero { // The count reached zero, we must free the memory. // - // SAFETY: The pointer was initialised from the result of `Box::leak`. - unsafe { drop(Box::from_raw(self.ptr.as_ptr())) }; + // SAFETY: The pointer was initialised from the result of `KBox::leak`. + unsafe { drop(KBox::from_raw(self.ptr.as_ptr())) }; } } } @@ -480,9 +476,6 @@ pub struct ArcBorrow<'a, T: ?Sized + 'a> { _p: PhantomData<&'a ()>, } -// This is to allow [`ArcBorrow`] (and variants) to be used as the type of `self`. -impl core::ops::Receiver for ArcBorrow<'_, T> {} - // This is to allow `ArcBorrow` to be dispatched on when `ArcBorrow` can be coerced into // `ArcBorrow`. impl, U: ?Sized> core::ops::DispatchFromDyn> @@ -647,7 +640,7 @@ pub fn new(value: T, flags: Flags) -> Result { /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet. pub fn new_uninit(flags: Flags) -> Result>, AllocError> { // INVARIANT: The refcount is initialised to a non-zero value. - let inner = Box::try_init::( + let inner = KBox::try_init::( try_init!(ArcInner { // SAFETY: There are no safety requirements for this FFI call. refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }), @@ -657,8 +650,8 @@ pub fn new_uninit(flags: Flags) -> Result>, AllocError> )?; Ok(UniqueArc { // INVARIANT: The newly-created object has a refcount of 1. - // SAFETY: The pointer from the `Box` is valid. - inner: unsafe { Arc::from_inner(Box::leak(inner).into()) }, + // SAFETY: The pointer from the `KBox` is valid. + inner: unsafe { Arc::from_inner(KBox::leak(inner).into()) }, }) } } diff --git a/rust/kernel/sync/arc/std_vendor.rs b/rust/kernel/sync/arc/std_vendor.rs index a66a0c2831b3ed..11b3f4ecca5f79 100644 --- a/rust/kernel/sync/arc/std_vendor.rs +++ b/rust/kernel/sync/arc/std_vendor.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT +//! Rust standard library vendored code. +//! //! The contents of this file come from the Rust standard library, hosted in //! the repository, licensed under //! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details, diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index 2b306afbe56d96..7df565038d7d0d 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -7,6 +7,7 @@ use super::{lock::Backend, lock::Guard, LockClassKey}; use crate::{ + ffi::{c_int, c_long}, init::PinInit, pin_init, str::CStr, @@ -14,7 +15,6 @@ time::Jiffies, types::Opaque, }; -use core::ffi::{c_int, c_long}; use core::marker::PhantomPinned; use core::ptr; use macros::pin_data; @@ -70,8 +70,8 @@ macro_rules! new_condvar { /// } /// /// /// Allocates a new boxed `Example`. -/// fn new_example() -> Result>> { -/// Box::pin_init(pin_init!(Example { +/// fn new_example() -> Result>> { +/// KBox::pin_init(pin_init!(Example { /// value <- new_mutex!(0), /// value_changed <- new_condvar!(), /// }), GFP_KERNEL) @@ -93,7 +93,6 @@ pub struct CondVar { } // SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on any thread. -#[allow(clippy::non_send_fields_in_send_ty)] unsafe impl Send for CondVar {} // SAFETY: `CondVar` only uses a `struct wait_queue_head`, which is safe to use on multiple threads diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs index f6c34ca4d819f8..41dcddac69e203 100644 --- a/rust/kernel/sync/lock.rs +++ b/rust/kernel/sync/lock.rs @@ -6,13 +6,21 @@ //! spinlocks, raw spinlocks) to be provided with minimal effort. use super::LockClassKey; -use crate::{init::PinInit, pin_init, str::CStr, types::Opaque, types::ScopeGuard}; -use core::{cell::UnsafeCell, marker::PhantomData, marker::PhantomPinned}; +use crate::{ + init::PinInit, + pin_init, + str::CStr, + types::{NotThreadSafe, Opaque, ScopeGuard}, +}; +use core::{cell::UnsafeCell, marker::PhantomPinned}; use macros::pin_data; pub mod mutex; pub mod spinlock; +pub(super) mod global; +pub use global::{GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy}; + /// The "backend" of a lock. /// /// It is the actual implementation of the lock, without the need to repeat patterns used in all @@ -46,7 +54,7 @@ pub unsafe trait Backend { /// remain valid for read indefinitely. unsafe fn init( ptr: *mut Self::State, - name: *const core::ffi::c_char, + name: *const crate::ffi::c_char, key: *mut bindings::lock_class_key, ); @@ -58,6 +66,13 @@ unsafe fn init( #[must_use] unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState; + /// Tries to acquire the lock. + /// + /// # Safety + /// + /// Callers must ensure that [`Backend::init`] has been previously called. + unsafe fn try_lock(ptr: *mut Self::State) -> Option; + /// Releases the lock, giving up its ownership. /// /// # Safety @@ -128,6 +143,15 @@ pub fn lock(&self) -> Guard<'_, T, B> { // SAFETY: The lock was just acquired. unsafe { Guard::new(self, state) } } + + /// Tries to acquire the lock. + /// + /// Returns a guard that can be used to access the data protected by the lock if successful. + pub fn try_lock(&self) -> Option> { + // SAFETY: The constructor of the type calls `init`, so the existence of the object proves + // that `init` was called. + unsafe { B::try_lock(self.state.get()).map(|state| Guard::new(self, state)) } + } } /// A lock guard. @@ -139,7 +163,7 @@ pub fn lock(&self) -> Guard<'_, T, B> { pub struct Guard<'a, T: ?Sized, B: Backend> { pub(crate) lock: &'a Lock, pub(crate) state: B::GuardState, - _not_send: PhantomData<*mut ()>, + _not_send: NotThreadSafe, } // SAFETY: `Guard` is sync when the data protected by the lock is also sync. @@ -150,9 +174,9 @@ pub(crate) fn do_unlocked(&mut self, cb: impl FnOnce() -> U) -> U { // SAFETY: The caller owns the lock, so it is safe to unlock it. unsafe { B::unlock(self.lock.state.get(), &self.state) }; - // SAFETY: The lock was just unlocked above and is being relocked now. - let _relock = - ScopeGuard::new(|| unsafe { B::relock(self.lock.state.get(), &mut self.state) }); + let _relock = ScopeGuard::new(|| + // SAFETY: The lock was just unlocked above and is being relocked now. + unsafe { B::relock(self.lock.state.get(), &mut self.state) }); cb() } @@ -191,7 +215,7 @@ pub(crate) unsafe fn new(lock: &'a Lock, state: B::GuardState) -> Self { Self { lock, state, - _not_send: PhantomData, + _not_send: NotThreadSafe, } } } diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global.rs new file mode 100644 index 00000000000000..480ee724e3cc4a --- /dev/null +++ b/rust/kernel/sync/lock/global.rs @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Support for defining statics containing locks. + +use crate::{ + str::CStr, + sync::lock::{Backend, Guard, Lock}, + sync::{LockClassKey, LockedBy}, + types::Opaque, +}; +use core::{ + cell::UnsafeCell, + marker::{PhantomData, PhantomPinned}, +}; + +/// Trait implemented for marker types for global locks. +/// +/// See [`global_lock!`] for examples. +pub trait GlobalLockBackend { + /// The name for this global lock. + const NAME: &'static CStr; + /// Item type stored in this global lock. + type Item: 'static; + /// The backend used for this global lock. + type Backend: Backend + 'static; + /// The class for this global lock. + fn get_lock_class() -> &'static LockClassKey; +} + +/// Type used for global locks. +/// +/// See [`global_lock!`] for examples. +pub struct GlobalLock { + inner: Lock, +} + +impl GlobalLock { + /// Creates a global lock. + /// + /// # Safety + /// + /// * Before any other method on this lock is called, [`Self::init`] must be called. + /// * The type `B` must not be used with any other lock. + pub const unsafe fn new(data: B::Item) -> Self { + Self { + inner: Lock { + state: Opaque::uninit(), + data: UnsafeCell::new(data), + _pin: PhantomPinned, + }, + } + } + + /// Initializes a global lock. + /// + /// # Safety + /// + /// Must not be called more than once on a given lock. + pub unsafe fn init(&'static self) { + // SAFETY: The pointer to `state` is valid for the duration of this call, and both `name` + // and `key` are valid indefinitely. The `state` is pinned since we have a `'static` + // reference to `self`. + // + // We have exclusive access to the `state` since the caller of `new` promised to call + // `init` before using any other methods. As `init` can only be called once, all other + // uses of this lock must happen after this call. + unsafe { + B::Backend::init( + self.inner.state.get(), + B::NAME.as_char_ptr(), + B::get_lock_class().as_ptr(), + ) + } + } + + /// Lock this global lock. + pub fn lock(&'static self) -> GlobalGuard { + GlobalGuard { + inner: self.inner.lock(), + } + } + + /// Try to lock this global lock. + pub fn try_lock(&'static self) -> Option> { + Some(GlobalGuard { + inner: self.inner.try_lock()?, + }) + } +} + +/// A guard for a [`GlobalLock`]. +/// +/// See [`global_lock!`] for examples. +pub struct GlobalGuard { + inner: Guard<'static, B::Item, B::Backend>, +} + +impl core::ops::Deref for GlobalGuard { + type Target = B::Item; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl core::ops::DerefMut for GlobalGuard { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +/// A version of [`LockedBy`] for a [`GlobalLock`]. +/// +/// See [`global_lock!`] for examples. +pub struct GlobalLockedBy { + _backend: PhantomData, + value: UnsafeCell, +} + +// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. +unsafe impl Send for GlobalLockedBy +where + T: ?Sized, + B: GlobalLockBackend, + LockedBy: Send, +{ +} + +// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. +unsafe impl Sync for GlobalLockedBy +where + T: ?Sized, + B: GlobalLockBackend, + LockedBy: Sync, +{ +} + +impl GlobalLockedBy { + /// Create a new [`GlobalLockedBy`]. + /// + /// The provided value will be protected by the global lock indicated by `B`. + pub fn new(val: T) -> Self { + Self { + value: UnsafeCell::new(val), + _backend: PhantomData, + } + } +} + +impl GlobalLockedBy { + /// Access the value immutably. + /// + /// The caller must prove shared access to the lock. + pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard) -> &'a T { + // SAFETY: The lock is globally unique, so there can only be one guard. + unsafe { &*self.value.get() } + } + + /// Access the value mutably. + /// + /// The caller must prove shared exclusive to the lock. + pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard) -> &'a mut T { + // SAFETY: The lock is globally unique, so there can only be one guard. + unsafe { &mut *self.value.get() } + } + + /// Access the value mutably directly. + /// + /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the + /// lock. + pub fn get_mut(&mut self) -> &mut T { + self.value.get_mut() + } +} + +/// Defines a global lock. +/// +/// The global mutex must be initialized before first use. Usually this is done by calling +/// [`GlobalLock::init`] in the module initializer. +/// +/// # Examples +/// +/// A global counter: +/// +/// ``` +/// # mod ex { +/// # use kernel::prelude::*; +/// kernel::sync::global_lock! { +/// // SAFETY: Initialized in module initializer before first use. +/// unsafe(uninit) static MY_COUNTER: Mutex = 0; +/// } +/// +/// fn increment_counter() -> u32 { +/// let mut guard = MY_COUNTER.lock(); +/// *guard += 1; +/// *guard +/// } +/// +/// impl kernel::Module for MyModule { +/// fn init(_module: &'static ThisModule) -> Result { +/// // SAFETY: Called exactly once. +/// unsafe { MY_COUNTER.init() }; +/// +/// Ok(MyModule {}) +/// } +/// } +/// # struct MyModule {} +/// # } +/// ``` +/// +/// A global mutex used to protect all instances of a given struct: +/// +/// ``` +/// # mod ex { +/// # use kernel::prelude::*; +/// use kernel::sync::{GlobalGuard, GlobalLockedBy}; +/// +/// kernel::sync::global_lock! { +/// // SAFETY: Initialized in module initializer before first use. +/// unsafe(uninit) static MY_MUTEX: Mutex<()> = (); +/// } +/// +/// /// All instances of this struct are protected by `MY_MUTEX`. +/// struct MyStruct { +/// my_counter: GlobalLockedBy, +/// } +/// +/// impl MyStruct { +/// /// Increment the counter in this instance. +/// /// +/// /// The caller must hold the `MY_MUTEX` mutex. +/// fn increment(&self, guard: &mut GlobalGuard) -> u32 { +/// let my_counter = self.my_counter.as_mut(guard); +/// *my_counter += 1; +/// *my_counter +/// } +/// } +/// +/// impl kernel::Module for MyModule { +/// fn init(_module: &'static ThisModule) -> Result { +/// // SAFETY: Called exactly once. +/// unsafe { MY_MUTEX.init() }; +/// +/// Ok(MyModule {}) +/// } +/// } +/// # struct MyModule {} +/// # } +/// ``` +#[macro_export] +macro_rules! global_lock { + { + $(#[$meta:meta])* $pub:vis + unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr; + } => { + #[doc = ::core::concat!( + "Backend type used by [`", + ::core::stringify!($name), + "`](static@", + ::core::stringify!($name), + ")." + )] + #[allow(non_camel_case_types, unreachable_pub)] + $pub enum $name {} + + impl $crate::sync::lock::GlobalLockBackend for $name { + const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name)); + type Item = $valuety; + type Backend = $crate::global_lock_inner!(backend $kind); + + fn get_lock_class() -> &'static $crate::sync::LockClassKey { + $crate::static_lock_class!() + } + } + + $(#[$meta])* + $pub static $name: $crate::sync::lock::GlobalLock<$name> = { + // Defined here to be outside the unsafe scope. + let init: $valuety = $value; + + // SAFETY: + // * The user of this macro promises to initialize the macro before use. + // * We are only generating one static with this backend type. + unsafe { $crate::sync::lock::GlobalLock::new(init) } + }; + }; +} +pub use global_lock; + +#[doc(hidden)] +#[macro_export] +macro_rules! global_lock_inner { + (backend Mutex) => { + $crate::sync::lock::mutex::MutexBackend + }; + (backend SpinLock) => { + $crate::sync::lock::spinlock::SpinLockBackend + }; +} diff --git a/rust/kernel/sync/lock/mutex.rs b/rust/kernel/sync/lock/mutex.rs index 30632070ee6709..0e946ebefce125 100644 --- a/rust/kernel/sync/lock/mutex.rs +++ b/rust/kernel/sync/lock/mutex.rs @@ -58,7 +58,7 @@ macro_rules! new_mutex { /// } /// /// // Allocate a boxed `Example`. -/// let e = Box::pin_init(Example::new(), GFP_KERNEL)?; +/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?; /// assert_eq!(e.c, 10); /// assert_eq!(e.d.lock().a, 20); /// assert_eq!(e.d.lock().b, 30); @@ -96,7 +96,7 @@ unsafe impl super::Backend for MutexBackend { unsafe fn init( ptr: *mut Self::State, - name: *const core::ffi::c_char, + name: *const crate::ffi::c_char, key: *mut bindings::lock_class_key, ) { // SAFETY: The safety requirements ensure that `ptr` is valid for writes, and `name` and @@ -115,4 +115,15 @@ unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardState) { // caller is the owner of the mutex. unsafe { bindings::mutex_unlock(ptr) }; } + + unsafe fn try_lock(ptr: *mut Self::State) -> Option { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + let result = unsafe { bindings::mutex_trylock(ptr) }; + + if result != 0 { + Some(()) + } else { + None + } + } } diff --git a/rust/kernel/sync/lock/spinlock.rs b/rust/kernel/sync/lock/spinlock.rs index ea5c5bc1ce12ed..9f4d128bed983e 100644 --- a/rust/kernel/sync/lock/spinlock.rs +++ b/rust/kernel/sync/lock/spinlock.rs @@ -56,7 +56,7 @@ macro_rules! new_spinlock { /// } /// /// // Allocate a boxed `Example`. -/// let e = Box::pin_init(Example::new(), GFP_KERNEL)?; +/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?; /// assert_eq!(e.c, 10); /// assert_eq!(e.d.lock().a, 20); /// assert_eq!(e.d.lock().b, 30); @@ -95,7 +95,7 @@ unsafe impl super::Backend for SpinLockBackend { unsafe fn init( ptr: *mut Self::State, - name: *const core::ffi::c_char, + name: *const crate::ffi::c_char, key: *mut bindings::lock_class_key, ) { // SAFETY: The safety requirements ensure that `ptr` is valid for writes, and `name` and @@ -114,4 +114,15 @@ unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardState) { // caller is the owner of the spinlock. unsafe { bindings::spin_unlock(ptr) } } + + unsafe fn try_lock(ptr: *mut Self::State) -> Option { + // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use. + let result = unsafe { bindings::spin_trylock(ptr) }; + + if result != 0 { + Some(()) + } else { + None + } + } } diff --git a/rust/kernel/sync/locked_by.rs b/rust/kernel/sync/locked_by.rs index ce2ee8d8786587..a7b244675c2b96 100644 --- a/rust/kernel/sync/locked_by.rs +++ b/rust/kernel/sync/locked_by.rs @@ -43,7 +43,7 @@ /// struct InnerDirectory { /// /// The sum of the bytes used by all files. /// bytes_used: u64, -/// _files: Vec, +/// _files: KVec, /// } /// /// struct Directory { diff --git a/rust/kernel/sync/poll.rs b/rust/kernel/sync/poll.rs new file mode 100644 index 00000000000000..d5f17153b42446 --- /dev/null +++ b/rust/kernel/sync/poll.rs @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Utilities for working with `struct poll_table`. + +use crate::{ + bindings, + fs::File, + prelude::*, + sync::{CondVar, LockClassKey}, + types::Opaque, +}; +use core::ops::Deref; + +/// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class. +#[macro_export] +macro_rules! new_poll_condvar { + ($($name:literal)?) => { + $crate::sync::poll::PollCondVar::new( + $crate::optional_name!($($name)?), $crate::static_lock_class!() + ) + }; +} + +/// Wraps the kernel's `struct poll_table`. +/// +/// # Invariants +/// +/// This struct contains a valid `struct poll_table`. +/// +/// For a `struct poll_table` to be valid, its `_qproc` function must follow the safety +/// requirements of `_qproc` functions: +/// +/// * The `_qproc` function is given permission to enqueue a waiter to the provided `poll_table` +/// during the call. Once the waiter is removed and an rcu grace period has passed, it must no +/// longer access the `wait_queue_head`. +#[repr(transparent)] +pub struct PollTable(Opaque); + +impl PollTable { + /// Creates a reference to a [`PollTable`] from a valid pointer. + /// + /// # Safety + /// + /// The caller must ensure that for the duration of 'a, the pointer will point at a valid poll + /// table (as defined in the type invariants). + /// + /// The caller must also ensure that the `poll_table` is only accessed via the returned + /// reference for the duration of 'a. + pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut PollTable { + // SAFETY: The safety requirements guarantee the validity of the dereference, while the + // `PollTable` type being transparent makes the cast ok. + unsafe { &mut *ptr.cast() } + } + + fn get_qproc(&self) -> bindings::poll_queue_proc { + let ptr = self.0.get(); + // SAFETY: The `ptr` is valid because it originates from a reference, and the `_qproc` + // field is not modified concurrently with this call since we have an immutable reference. + unsafe { (*ptr)._qproc } + } + + /// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified + /// using the condition variable. + pub fn register_wait(&mut self, file: &File, cv: &PollCondVar) { + if let Some(qproc) = self.get_qproc() { + // SAFETY: The pointers to `file` and `self` need to be valid for the duration of this + // call to `qproc`, which they are because they are references. + // + // The `cv.wait_queue_head` pointer must be valid until an rcu grace period after the + // waiter is removed. The `PollCondVar` is pinned, so before `cv.wait_queue_head` can + // be destroyed, the destructor must run. That destructor first removes all waiters, + // and then waits for an rcu grace period. Therefore, `cv.wait_queue_head` is valid for + // long enough. + unsafe { qproc(file.as_ptr() as _, cv.wait_queue_head.get(), self.0.get()) }; + } + } +} + +/// A wrapper around [`CondVar`] that makes it usable with [`PollTable`]. +/// +/// [`CondVar`]: crate::sync::CondVar +#[pin_data(PinnedDrop)] +pub struct PollCondVar { + #[pin] + inner: CondVar, +} + +impl PollCondVar { + /// Constructs a new condvar initialiser. + pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + pin_init!(Self { + inner <- CondVar::new(name, key), + }) + } +} + +// Make the `CondVar` methods callable on `PollCondVar`. +impl Deref for PollCondVar { + type Target = CondVar; + + fn deref(&self) -> &CondVar { + &self.inner + } +} + +#[pinned_drop] +impl PinnedDrop for PollCondVar { + fn drop(self: Pin<&mut Self>) { + // Clear anything registered using `register_wait`. + // + // SAFETY: The pointer points at a valid `wait_queue_head`. + unsafe { bindings::__wake_up_pollfree(self.inner.wait_queue_head.get()) }; + + // Wait for epoll items to be properly removed. + // + // SAFETY: Just an FFI call. + unsafe { bindings::synchronize_rcu() }; + } +} diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 55dff7e088bf5f..07bc22a7645c0c 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -4,10 +4,14 @@ //! //! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h). -use crate::types::Opaque; -use core::{ +use crate::{ + bindings, ffi::{c_int, c_long, c_uint}, - marker::PhantomData, + pid_namespace::PidNamespace, + types::{ARef, NotThreadSafe, Opaque}, +}; +use core::{ + cmp::{Eq, PartialEq}, ops::Deref, ptr, }; @@ -33,6 +37,16 @@ macro_rules! current { }; } +/// Returns the currently running task's pid namespace. +#[macro_export] +macro_rules! current_pid_ns { + () => { + // SAFETY: Deref + addr-of below create a temporary `PidNamespaceRef` that cannot outlive + // the caller. + unsafe { &*$crate::task::Task::current_pid_ns() } + }; +} + /// Wraps the kernel's `struct task_struct`. /// /// # Invariants @@ -94,7 +108,22 @@ unsafe impl Sync for Task {} /// The type of process identifiers (PIDs). type Pid = bindings::pid_t; +/// The type of user identifiers (UIDs). +#[derive(Copy, Clone)] +pub struct Kuid { + kuid: bindings::kuid_t, +} + impl Task { + /// Returns a raw pointer to the current task. + /// + /// It is up to the user to use the pointer correctly. + #[inline] + pub fn current_raw() -> *mut bindings::task_struct { + // SAFETY: Getting the current pointer is always safe. + unsafe { bindings::get_current() } + } + /// Returns a task reference for the currently executing task/thread. /// /// The recommended way to get the current task/thread is to use the @@ -106,7 +135,7 @@ impl Task { pub unsafe fn current() -> impl Deref { struct TaskRef<'a> { task: &'a Task, - _not_send: PhantomData<*mut ()>, + _not_send: NotThreadSafe, } impl Deref for TaskRef<'_> { @@ -117,23 +146,118 @@ fn deref(&self) -> &Self::Target { } } - // SAFETY: Just an FFI call with no additional safety requirements. - let ptr = unsafe { bindings::get_current() }; - + let current = Task::current_raw(); TaskRef { // SAFETY: If the current thread is still running, the current task is valid. Given // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread // (where it could potentially outlive the caller). - task: unsafe { &*ptr.cast() }, - _not_send: PhantomData, + task: unsafe { &*current.cast() }, + _not_send: NotThreadSafe, } } + /// Returns a PidNamespace reference for the currently executing task's/thread's pid namespace. + /// + /// This function can be used to create an unbounded lifetime by e.g., storing the returned + /// PidNamespace in a global variable which would be a bug. So the recommended way to get the + /// current task's/thread's pid namespace is to use the [`current_pid_ns`] macro because it is + /// safe. + /// + /// # Safety + /// + /// Callers must ensure that the returned object doesn't outlive the current task/thread. + pub unsafe fn current_pid_ns() -> impl Deref { + struct PidNamespaceRef<'a> { + task: &'a PidNamespace, + _not_send: NotThreadSafe, + } + + impl Deref for PidNamespaceRef<'_> { + type Target = PidNamespace; + + fn deref(&self) -> &Self::Target { + self.task + } + } + + // The lifetime of `PidNamespace` is bound to `Task` and `struct pid`. + // + // The `PidNamespace` of a `Task` doesn't ever change once the `Task` is alive. A + // `unshare(CLONE_NEWPID)` or `setns(fd_pidns/pidfd, CLONE_NEWPID)` will not have an effect + // on the calling `Task`'s pid namespace. It will only effect the pid namespace of children + // created by the calling `Task`. This invariant guarantees that after having acquired a + // reference to a `Task`'s pid namespace it will remain unchanged. + // + // When a task has exited and been reaped `release_task()` will be called. This will set + // the `PidNamespace` of the task to `NULL`. So retrieving the `PidNamespace` of a task + // that is dead will return `NULL`. Note, that neither holding the RCU lock nor holding a + // referencing count to + // the `Task` will prevent `release_task()` being called. + // + // In order to retrieve the `PidNamespace` of a `Task` the `task_active_pid_ns()` function + // can be used. There are two cases to consider: + // + // (1) retrieving the `PidNamespace` of the `current` task + // (2) retrieving the `PidNamespace` of a non-`current` task + // + // From system call context retrieving the `PidNamespace` for case (1) is always safe and + // requires neither RCU locking nor a reference count to be held. Retrieving the + // `PidNamespace` after `release_task()` for current will return `NULL` but no codepath + // like that is exposed to Rust. + // + // Retrieving the `PidNamespace` from system call context for (2) requires RCU protection. + // Accessing `PidNamespace` outside of RCU protection requires a reference count that + // must've been acquired while holding the RCU lock. Note that accessing a non-`current` + // task means `NULL` can be returned as the non-`current` task could have already passed + // through `release_task()`. + // + // To retrieve (1) the `current_pid_ns!()` macro should be used which ensure that the + // returned `PidNamespace` cannot outlive the calling scope. The associated + // `current_pid_ns()` function should not be called directly as it could be abused to + // created an unbounded lifetime for `PidNamespace`. The `current_pid_ns!()` macro allows + // Rust to handle the common case of accessing `current`'s `PidNamespace` without RCU + // protection and without having to acquire a reference count. + // + // For (2) the `task_get_pid_ns()` method must be used. This will always acquire a + // reference on `PidNamespace` and will return an `Option` to force the caller to + // explicitly handle the case where `PidNamespace` is `None`, something that tends to be + // forgotten when doing the equivalent operation in `C`. Missing RCU primitives make it + // difficult to perform operations that are otherwise safe without holding a reference + // count as long as RCU protection is guaranteed. But it is not important currently. But we + // do want it in the future. + // + // Note for (2) the required RCU protection around calling `task_active_pid_ns()` + // synchronizes against putting the last reference of the associated `struct pid` of + // `task->thread_pid`. The `struct pid` stored in that field is used to retrieve the + // `PidNamespace` of the caller. When `release_task()` is called `task->thread_pid` will be + // `NULL`ed and `put_pid()` on said `struct pid` will be delayed in `free_pid()` via + // `call_rcu()` allowing everyone with an RCU protected access to the `struct pid` acquired + // from `task->thread_pid` to finish. + // + // SAFETY: The current task's pid namespace is valid as long as the current task is running. + let pidns = unsafe { bindings::task_active_pid_ns(Task::current_raw()) }; + PidNamespaceRef { + // SAFETY: If the current thread is still running, the current task and its associated + // pid namespace are valid. `PidNamespaceRef` is not `Send`, so we know it cannot be + // transferred to another thread (where it could potentially outlive the current + // `Task`). The caller needs to ensure that the PidNamespaceRef doesn't outlive the + // current task/thread. + task: unsafe { PidNamespace::from_ptr(pidns) }, + _not_send: NotThreadSafe, + } + } + + /// Returns a raw pointer to the task. + #[inline] + pub fn as_ptr(&self) -> *mut bindings::task_struct { + self.0.get() + } + /// Returns the group leader of the given task. pub fn group_leader(&self) -> &Task { - // SAFETY: By the type invariant, we know that `self.0` is a valid task. Valid tasks always - // have a valid `group_leader`. - let ptr = unsafe { *ptr::addr_of!((*self.0.get()).group_leader) }; + // SAFETY: The group leader of a task never changes after initialization, so reading this + // field is not a data race. + let ptr = unsafe { *ptr::addr_of!((*self.as_ptr()).group_leader) }; // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`, // and given that a task has a reference to its group leader, we know it must be valid for @@ -143,23 +267,62 @@ pub fn group_leader(&self) -> &Task { /// Returns the PID of the given task. pub fn pid(&self) -> Pid { - // SAFETY: By the type invariant, we know that `self.0` is a valid task. Valid tasks always - // have a valid pid. - unsafe { *ptr::addr_of!((*self.0.get()).pid) } + // SAFETY: The pid of a task never changes after initialization, so reading this field is + // not a data race. + unsafe { *ptr::addr_of!((*self.as_ptr()).pid) } + } + + /// Returns the UID of the given task. + pub fn uid(&self) -> Kuid { + // SAFETY: It's always safe to call `task_uid` on a valid task. + Kuid::from_raw(unsafe { bindings::task_uid(self.as_ptr()) }) + } + + /// Returns the effective UID of the given task. + pub fn euid(&self) -> Kuid { + // SAFETY: It's always safe to call `task_euid` on a valid task. + Kuid::from_raw(unsafe { bindings::task_euid(self.as_ptr()) }) } /// Determines whether the given task has pending signals. pub fn signal_pending(&self) -> bool { + // SAFETY: It's always safe to call `signal_pending` on a valid task. + unsafe { bindings::signal_pending(self.as_ptr()) != 0 } + } + + /// Returns task's pid namespace with elevated reference count + pub fn get_pid_ns(&self) -> Option> { // SAFETY: By the type invariant, we know that `self.0` is valid. - unsafe { bindings::signal_pending(self.0.get()) != 0 } + let ptr = unsafe { bindings::task_get_pid_ns(self.as_ptr()) }; + if ptr.is_null() { + None + } else { + // SAFETY: `ptr` is valid by the safety requirements of this function. And we own a + // reference count via `task_get_pid_ns()`. + // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::pid_namespace`. + Some(unsafe { ARef::from_raw(ptr::NonNull::new_unchecked(ptr.cast::())) }) + } + } + + /// Returns the given task's pid in the provided pid namespace. + #[doc(alias = "task_tgid_nr_ns")] + pub fn tgid_nr_ns(&self, pidns: Option<&PidNamespace>) -> Pid { + let pidns = match pidns { + Some(pidns) => pidns.as_ptr(), + None => core::ptr::null_mut(), + }; + // SAFETY: By the type invariant, we know that `self.0` is valid. We received a valid + // PidNamespace that we can use as a pointer or we received an empty PidNamespace and + // thus pass a null pointer. The underlying C function is safe to be used with NULL + // pointers. + unsafe { bindings::task_tgid_nr_ns(self.as_ptr(), pidns) } } /// Wakes up the task. pub fn wake_up(&self) { - // SAFETY: By the type invariant, we know that `self.0.get()` is non-null and valid. - // And `wake_up_process` is safe to be called for any valid task, even if the task is + // SAFETY: It's always safe to call `signal_pending` on a valid task, even if the task // running. - unsafe { bindings::wake_up_process(self.0.get()) }; + unsafe { bindings::wake_up_process(self.as_ptr()) }; } } @@ -167,7 +330,7 @@ pub fn wake_up(&self) { unsafe impl crate::types::AlwaysRefCounted for Task { fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refcount is nonzero. - unsafe { bindings::get_task_struct(self.0.get()) }; + unsafe { bindings::get_task_struct(self.as_ptr()) }; } unsafe fn dec_ref(obj: ptr::NonNull) { @@ -175,3 +338,43 @@ unsafe fn dec_ref(obj: ptr::NonNull) { unsafe { bindings::put_task_struct(obj.cast().as_ptr()) } } } + +impl Kuid { + /// Get the current euid. + #[inline] + pub fn current_euid() -> Kuid { + // SAFETY: Just an FFI call. + Self::from_raw(unsafe { bindings::current_euid() }) + } + + /// Create a `Kuid` given the raw C type. + #[inline] + pub fn from_raw(kuid: bindings::kuid_t) -> Self { + Self { kuid } + } + + /// Turn this kuid into the raw C type. + #[inline] + pub fn into_raw(self) -> bindings::kuid_t { + self.kuid + } + + /// Converts this kernel UID into a userspace UID. + /// + /// Uses the namespace of the current task. + #[inline] + pub fn into_uid_in_current_ns(self) -> bindings::uid_t { + // SAFETY: Just an FFI call. + unsafe { bindings::from_kuid(bindings::current_user_ns(), self.kuid) } + } +} + +impl PartialEq for Kuid { + #[inline] + fn eq(&self, other: &Kuid) -> bool { + // SAFETY: Just an FFI call. + unsafe { bindings::uid_eq(self.kuid, other.kuid) } + } +} + +impl Eq for Kuid {} diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs index e3bb5e89f88dac..379c0f5772e575 100644 --- a/rust/kernel/time.rs +++ b/rust/kernel/time.rs @@ -12,10 +12,10 @@ pub const NSEC_PER_MSEC: i64 = bindings::NSEC_PER_MSEC as i64; /// The time unit of Linux kernel. One jiffy equals (1/HZ) second. -pub type Jiffies = core::ffi::c_ulong; +pub type Jiffies = crate::ffi::c_ulong; /// The millisecond time unit. -pub type Msecs = core::ffi::c_uint; +pub type Msecs = crate::ffi::c_uint; /// Converts milliseconds to jiffies. #[inline] diff --git a/rust/kernel/tracepoint.rs b/rust/kernel/tracepoint.rs new file mode 100644 index 00000000000000..c6e80aa99e8e14 --- /dev/null +++ b/rust/kernel/tracepoint.rs @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 Google LLC. + +//! Logic for tracepoints. + +/// Declare the Rust entry point for a tracepoint. +/// +/// This macro generates an unsafe function that calls into C, and its safety requirements will be +/// whatever the relevant C code requires. To document these safety requirements, you may add +/// doc-comments when invoking the macro. +#[macro_export] +macro_rules! declare_trace { + ($($(#[$attr:meta])* $pub:vis unsafe fn $name:ident($($argname:ident : $argtyp:ty),* $(,)?);)*) => {$( + $( #[$attr] )* + #[inline(always)] + $pub unsafe fn $name($($argname : $argtyp),*) { + #[cfg(CONFIG_TRACEPOINTS)] + { + // SAFETY: It's always okay to query the static key for a tracepoint. + let should_trace = unsafe { + $crate::macros::paste! { + $crate::jump_label::static_branch_unlikely!( + $crate::bindings::[< __tracepoint_ $name >], + $crate::bindings::tracepoint, + key + ) + } + }; + + if should_trace { + $crate::macros::paste! { + // SAFETY: The caller guarantees that it is okay to call this tracepoint. + unsafe { $crate::bindings::[< rust_do_trace_ $name >]($($argname),*) }; + } + } + } + + #[cfg(not(CONFIG_TRACEPOINTS))] + { + // If tracepoints are disabled, insert a trivial use of each argument + // to avoid unused argument warnings. + $( let _unused = $argname; )* + } + } + )*} +} + +pub use declare_trace; diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs new file mode 100644 index 00000000000000..1c7d43771a37b9 --- /dev/null +++ b/rust/kernel/transmute.rs @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Traits for transmuting types. + +/// Types for which any bit pattern is valid. +/// +/// Not all types are valid for all values. For example, a `bool` must be either zero or one, so +/// reading arbitrary bytes into something that contains a `bool` is not okay. +/// +/// It's okay for the type to have padding, as initializing those bytes has no effect. +/// +/// # Safety +/// +/// All bit-patterns must be valid for this type. This type must not have interior mutability. +pub unsafe trait FromBytes {} + +macro_rules! impl_frombytes { + ($($({$($generics:tt)*})? $t:ty, )*) => { + // SAFETY: Safety comments written in the macro invocation. + $(unsafe impl$($($generics)*)? FromBytes for $t {})* + }; +} + +impl_frombytes! { + // SAFETY: All bit patterns are acceptable values of the types below. + u8, u16, u32, u64, usize, + i8, i16, i32, i64, isize, + + // SAFETY: If all bit patterns are acceptable for individual values in an array, then all bit + // patterns are also acceptable for arrays of that type. + {} [T], + {} [T; N], +} + +/// Types that can be viewed as an immutable slice of initialized bytes. +/// +/// If a struct implements this trait, then it is okay to copy it byte-for-byte to userspace. This +/// means that it should not have any padding, as padding bytes are uninitialized. Reading +/// uninitialized memory is not just undefined behavior, it may even lead to leaking sensitive +/// information on the stack to userspace. +/// +/// The struct should also not hold kernel pointers, as kernel pointer addresses are also considered +/// sensitive. However, leaking kernel pointers is not considered undefined behavior by Rust, so +/// this is a correctness requirement, but not a safety requirement. +/// +/// # Safety +/// +/// Values of this type may not contain any uninitialized bytes. This type must not have interior +/// mutability. +pub unsafe trait AsBytes {} + +macro_rules! impl_asbytes { + ($($({$($generics:tt)*})? $t:ty, )*) => { + // SAFETY: Safety comments written in the macro invocation. + $(unsafe impl$($($generics)*)? AsBytes for $t {})* + }; +} + +impl_asbytes! { + // SAFETY: Instances of the following types have no uninitialized portions. + u8, u16, u32, u64, usize, + i8, i16, i32, i64, isize, + bool, + char, + str, + + // SAFETY: If individual values in an array have no uninitialized portions, then the array + // itself does not have any uninitialized portions either. + {} [T], + {} [T; N], +} diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9e7ca066355cd5..ec6457bb3084ae 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -3,13 +3,11 @@ //! Kernel types. use crate::init::{self, PinInit}; -use alloc::boxed::Box; use core::{ cell::UnsafeCell, marker::{PhantomData, PhantomPinned}, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, - pin::Pin, ptr::NonNull, }; @@ -31,7 +29,7 @@ pub trait ForeignOwnable: Sized { /// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in /// any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`], /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior. - fn into_foreign(self) -> *const core::ffi::c_void; + fn into_foreign(self) -> *const crate::ffi::c_void; /// Borrows a foreign-owned object. /// @@ -39,7 +37,7 @@ pub trait ForeignOwnable: Sized { /// /// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. - unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>; + unsafe fn borrow<'a>(ptr: *const crate::ffi::c_void) -> Self::Borrowed<'a>; /// Converts a foreign-owned object back to a Rust-owned one. /// @@ -49,7 +47,7 @@ pub trait ForeignOwnable: Sized { /// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet. /// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for /// this object must have been dropped. - unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self; + unsafe fn from_foreign(ptr: *const crate::ffi::c_void) -> Self; /// Tries to convert a foreign-owned object back to a Rust-owned one. /// @@ -60,7 +58,7 @@ pub trait ForeignOwnable: Sized { /// /// `ptr` must either be null or satisfy the safety requirements for /// [`ForeignOwnable::from_foreign`]. - unsafe fn try_from_foreign(ptr: *const core::ffi::c_void) -> Option { + unsafe fn try_from_foreign(ptr: *const crate::ffi::c_void) -> Option { if ptr.is_null() { None } else { @@ -71,64 +69,16 @@ unsafe fn try_from_foreign(ptr: *const core::ffi::c_void) -> Option { } } -impl ForeignOwnable for Box { - type Borrowed<'a> = &'a T; - - fn into_foreign(self) -> *const core::ffi::c_void { - Box::into_raw(self) as _ - } - - unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T { - // SAFETY: The safety requirements for this function ensure that the object is still alive, - // so it is safe to dereference the raw pointer. - // The safety requirements of `from_foreign` also ensure that the object remains alive for - // the lifetime of the returned value. - unsafe { &*ptr.cast() } - } - - unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { - // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous - // call to `Self::into_foreign`. - unsafe { Box::from_raw(ptr as _) } - } -} - -impl ForeignOwnable for Pin> { - type Borrowed<'a> = Pin<&'a T>; - - fn into_foreign(self) -> *const core::ffi::c_void { - // SAFETY: We are still treating the box as pinned. - Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) as _ - } - - unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Pin<&'a T> { - // SAFETY: The safety requirements for this function ensure that the object is still alive, - // so it is safe to dereference the raw pointer. - // The safety requirements of `from_foreign` also ensure that the object remains alive for - // the lifetime of the returned value. - let r = unsafe { &*ptr.cast() }; - - // SAFETY: This pointer originates from a `Pin>`. - unsafe { Pin::new_unchecked(r) } - } - - unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self { - // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous - // call to `Self::into_foreign`. - unsafe { Pin::new_unchecked(Box::from_raw(ptr as _)) } - } -} - impl ForeignOwnable for () { type Borrowed<'a> = (); - fn into_foreign(self) -> *const core::ffi::c_void { + fn into_foreign(self) -> *const crate::ffi::c_void { core::ptr::NonNull::dangling().as_ptr() } - unsafe fn borrow<'a>(_: *const core::ffi::c_void) -> Self::Borrowed<'a> {} + unsafe fn borrow<'a>(_: *const crate::ffi::c_void) -> Self::Borrowed<'a> {} - unsafe fn from_foreign(_: *const core::ffi::c_void) -> Self {} + unsafe fn from_foreign(_: *const crate::ffi::c_void) -> Self {} } /// Runs a cleanup function/closure when dropped. @@ -185,7 +135,7 @@ unsafe fn from_foreign(_: *const core::ffi::c_void) -> Self {} /// # use kernel::types::ScopeGuard; /// fn example3(arg: bool) -> Result { /// let mut vec = -/// ScopeGuard::new_with_data(Vec::new(), |v| pr_info!("vec had {} elements\n", v.len())); +/// ScopeGuard::new_with_data(KVec::new(), |v| pr_info!("vec had {} elements\n", v.len())); /// /// vec.push(10u8, GFP_KERNEL)?; /// if arg { @@ -225,7 +175,7 @@ pub fn dismiss(mut self) -> T { impl ScopeGuard<(), fn(())> { /// Creates a new guarded object with the given cleanup function. pub fn new(cleanup: impl FnOnce()) -> ScopeGuard<(), impl FnOnce(())> { - ScopeGuard::new_with_data((), move |_| cleanup()) + ScopeGuard::new_with_data((), move |()| cleanup()) } } @@ -256,7 +206,58 @@ fn drop(&mut self) { /// Stores an opaque value. /// -/// This is meant to be used with FFI objects that are never interpreted by Rust code. +/// `Opaque` is meant to be used with FFI objects that are never interpreted by Rust code. +/// +/// It is used to wrap structs from the C side, like for example `Opaque`. +/// It gets rid of all the usual assumptions that Rust has for a value: +/// +/// * The value is allowed to be uninitialized (for example have invalid bit patterns: `3` for a +/// [`bool`]). +/// * The value is allowed to be mutated, when a `&Opaque` exists on the Rust side. +/// * No uniqueness for mutable references: it is fine to have multiple `&mut Opaque` point to +/// the same value. +/// * The value is not allowed to be shared with other threads (i.e. it is `!Sync`). +/// +/// This has to be used for all values that the C side has access to, because it can't be ensured +/// that the C side is adhering to the usual constraints that Rust needs. +/// +/// Using `Opaque` allows to continue to use references on the Rust side even for values shared +/// with C. +/// +/// # Examples +/// +/// ``` +/// # #![expect(unreachable_pub, clippy::disallowed_names)] +/// use kernel::types::Opaque; +/// # // Emulate a C struct binding which is from C, maybe uninitialized or not, only the C side +/// # // knows. +/// # mod bindings { +/// # pub struct Foo { +/// # pub val: u8, +/// # } +/// # } +/// +/// // `foo.val` is assumed to be handled on the C side, so we use `Opaque` to wrap it. +/// pub struct Foo { +/// foo: Opaque, +/// } +/// +/// impl Foo { +/// pub fn get_val(&self) -> u8 { +/// let ptr = Opaque::get(&self.foo); +/// +/// // SAFETY: `Self` is valid from C side. +/// unsafe { (*ptr).val } +/// } +/// } +/// +/// // Create an instance of `Foo` with the `Opaque` wrapper. +/// let foo = Foo { +/// foo: Opaque::new(bindings::Foo { val: 0xdb }), +/// }; +/// +/// assert_eq!(foo.get_val(), 0xdb); +/// ``` #[repr(transparent)] pub struct Opaque { value: UnsafeCell>, @@ -299,6 +300,22 @@ pub fn ffi_init(init_func: impl FnOnce(*mut T)) -> impl PinInit { } } + /// Creates a fallible pin-initializer from the given initializer closure. + /// + /// The returned initializer calls the given closure with the pointer to the inner `T` of this + /// `Opaque`. Since this memory is uninitialized, the closure is not allowed to read from it. + /// + /// This function is safe, because the `T` inside of an `Opaque` is allowed to be + /// uninitialized. Additionally, access to the inner `T` requires `unsafe`, so the caller needs + /// to verify at that point that the inner value is valid. + pub fn try_ffi_init( + init_func: impl FnOnce(*mut T) -> Result<(), E>, + ) -> impl PinInit { + // SAFETY: We contain a `MaybeUninit`, so it is OK for the `init_func` to not fully + // initialize the `T`. + unsafe { init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::raw_get(slot))) } + } + /// Returns a raw pointer to the opaque data. pub const fn get(&self) -> *mut T { UnsafeCell::get(&self.value).cast::() @@ -410,6 +427,7 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// struct Empty {} /// + /// # // SAFETY: TODO. /// unsafe impl AlwaysRefCounted for Empty { /// fn inc_ref(&self) {} /// unsafe fn dec_ref(_obj: NonNull) {} @@ -417,6 +435,7 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// let mut data = Empty {}; /// let ptr = NonNull::::new(&mut data as *mut _).unwrap(); + /// # // SAFETY: TODO. /// let data_ref: ARef = unsafe { ARef::from_raw(ptr) }; /// let raw_ptr: NonNull = ARef::into_raw(data_ref); /// @@ -461,6 +480,15 @@ fn drop(&mut self) { } /// A sum type that always holds either a value of type `L` or `R`. +/// +/// # Examples +/// +/// ``` +/// use kernel::types::Either; +/// +/// let left_value: Either = Either::Left(7); +/// let right_value: Either = Either::Right("right value"); +/// ``` pub enum Either { /// Constructs an instance of [`Either`] containing a value of type `L`. Left(L), @@ -469,66 +497,23 @@ pub enum Either { Right(R), } -/// Types for which any bit pattern is valid. -/// -/// Not all types are valid for all values. For example, a `bool` must be either zero or one, so -/// reading arbitrary bytes into something that contains a `bool` is not okay. -/// -/// It's okay for the type to have padding, as initializing those bytes has no effect. +/// Zero-sized type to mark types not [`Send`]. /// -/// # Safety +/// Add this type as a field to your struct if your type should not be sent to a different task. +/// Since [`Send`] is an auto trait, adding a single field that is `!Send` will ensure that the +/// whole type is `!Send`. /// -/// All bit-patterns must be valid for this type. This type must not have interior mutability. -pub unsafe trait FromBytes {} - -// SAFETY: All bit patterns are acceptable values of the types below. -unsafe impl FromBytes for u8 {} -unsafe impl FromBytes for u16 {} -unsafe impl FromBytes for u32 {} -unsafe impl FromBytes for u64 {} -unsafe impl FromBytes for usize {} -unsafe impl FromBytes for i8 {} -unsafe impl FromBytes for i16 {} -unsafe impl FromBytes for i32 {} -unsafe impl FromBytes for i64 {} -unsafe impl FromBytes for isize {} -// SAFETY: If all bit patterns are acceptable for individual values in an array, then all bit -// patterns are also acceptable for arrays of that type. -unsafe impl FromBytes for [T] {} -unsafe impl FromBytes for [T; N] {} - -/// Types that can be viewed as an immutable slice of initialized bytes. -/// -/// If a struct implements this trait, then it is okay to copy it byte-for-byte to userspace. This -/// means that it should not have any padding, as padding bytes are uninitialized. Reading -/// uninitialized memory is not just undefined behavior, it may even lead to leaking sensitive -/// information on the stack to userspace. -/// -/// The struct should also not hold kernel pointers, as kernel pointer addresses are also considered -/// sensitive. However, leaking kernel pointers is not considered undefined behavior by Rust, so -/// this is a correctness requirement, but not a safety requirement. +/// If a type is `!Send` it is impossible to give control over an instance of the type to another +/// task. This is useful to include in types that store or reference task-local information. A file +/// descriptor is an example of such task-local information. /// -/// # Safety +/// This type also makes the type `!Sync`, which prevents immutable access to the value from +/// several threads in parallel. +pub type NotThreadSafe = PhantomData<*mut ()>; + +/// Used to construct instances of type [`NotThreadSafe`] similar to how `PhantomData` is +/// constructed. /// -/// Values of this type may not contain any uninitialized bytes. This type must not have interior -/// mutability. -pub unsafe trait AsBytes {} - -// SAFETY: Instances of the following types have no uninitialized portions. -unsafe impl AsBytes for u8 {} -unsafe impl AsBytes for u16 {} -unsafe impl AsBytes for u32 {} -unsafe impl AsBytes for u64 {} -unsafe impl AsBytes for usize {} -unsafe impl AsBytes for i8 {} -unsafe impl AsBytes for i16 {} -unsafe impl AsBytes for i32 {} -unsafe impl AsBytes for i64 {} -unsafe impl AsBytes for isize {} -unsafe impl AsBytes for bool {} -unsafe impl AsBytes for char {} -unsafe impl AsBytes for str {} -// SAFETY: If individual values in an array have no uninitialized portions, then the array itself -// does not have any uninitialized portions either. -unsafe impl AsBytes for [T] {} -unsafe impl AsBytes for [T; N] {} +/// [`NotThreadSafe`]: type@NotThreadSafe +#[allow(non_upper_case_globals)] +pub const NotThreadSafe: NotThreadSafe = PhantomData; diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs index e9347cff99ab20..05b0b8d13b10da 100644 --- a/rust/kernel/uaccess.rs +++ b/rust/kernel/uaccess.rs @@ -8,11 +8,10 @@ alloc::Flags, bindings, error::Result, + ffi::{c_ulong, c_void}, prelude::*, - types::{AsBytes, FromBytes}, + transmute::{AsBytes, FromBytes}, }; -use alloc::vec::Vec; -use core::ffi::{c_ulong, c_void}; use core::mem::{size_of, MaybeUninit}; /// The type used for userspace addresses. @@ -46,15 +45,14 @@ /// every byte in the region. /// /// ```no_run -/// use alloc::vec::Vec; -/// use core::ffi::c_void; +/// use kernel::ffi::c_void; /// use kernel::error::Result; /// use kernel::uaccess::{UserPtr, UserSlice}; /// /// fn bytes_add_one(uptr: UserPtr, len: usize) -> Result<()> { /// let (read, mut write) = UserSlice::new(uptr, len).reader_writer(); /// -/// let mut buf = Vec::new(); +/// let mut buf = KVec::new(); /// read.read_all(&mut buf, GFP_KERNEL)?; /// /// for b in &mut buf { @@ -69,8 +67,7 @@ /// Example illustrating a TOCTOU (time-of-check to time-of-use) bug. /// /// ```no_run -/// use alloc::vec::Vec; -/// use core::ffi::c_void; +/// use kernel::ffi::c_void; /// use kernel::error::{code::EINVAL, Result}; /// use kernel::uaccess::{UserPtr, UserSlice}; /// @@ -78,21 +75,21 @@ /// fn is_valid(uptr: UserPtr, len: usize) -> Result { /// let read = UserSlice::new(uptr, len).reader(); /// -/// let mut buf = Vec::new(); +/// let mut buf = KVec::new(); /// read.read_all(&mut buf, GFP_KERNEL)?; /// /// todo!() /// } /// /// /// Returns the bytes behind this user pointer if they are valid. -/// fn get_bytes_if_valid(uptr: UserPtr, len: usize) -> Result> { +/// fn get_bytes_if_valid(uptr: UserPtr, len: usize) -> Result> { /// if !is_valid(uptr, len)? { /// return Err(EINVAL); /// } /// /// let read = UserSlice::new(uptr, len).reader(); /// -/// let mut buf = Vec::new(); +/// let mut buf = KVec::new(); /// read.read_all(&mut buf, GFP_KERNEL)?; /// /// // THIS IS A BUG! The bytes could have changed since we checked them. @@ -130,7 +127,7 @@ pub fn new(ptr: UserPtr, length: usize) -> Self { /// Reads the entirety of the user slice, appending it to the end of the provided buffer. /// /// Fails with [`EFAULT`] if the read happens on a bad address. - pub fn read_all(self, buf: &mut Vec, flags: Flags) -> Result { + pub fn read_all(self, buf: &mut KVec, flags: Flags) -> Result { self.reader().read_all(buf, flags) } @@ -291,9 +288,9 @@ pub fn read(&mut self) -> Result { /// Reads the entirety of the user slice, appending it to the end of the provided buffer. /// /// Fails with [`EFAULT`] if the read happens on a bad address. - pub fn read_all(mut self, buf: &mut Vec, flags: Flags) -> Result { + pub fn read_all(mut self, buf: &mut KVec, flags: Flags) -> Result { let len = self.length; - VecExt::::reserve(buf, len, flags)?; + buf.reserve(len, flags)?; // The call to `try_reserve` was successful, so the spare capacity is at least `len` bytes // long. diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs index 553a5cba2adcb5..4d1d2062f6eba5 100644 --- a/rust/kernel/workqueue.rs +++ b/rust/kernel/workqueue.rs @@ -216,7 +216,7 @@ pub fn try_spawn( func: Some(func), }); - self.enqueue(Box::pin_init(init, flags).map_err(|_| AllocError)?); + self.enqueue(KBox::pin_init(init, flags).map_err(|_| AllocError)?); Ok(()) } } @@ -239,9 +239,9 @@ fn project(self: Pin<&mut Self>) -> &mut Option { } impl WorkItem for ClosureWork { - type Pointer = Pin>; + type Pointer = Pin>; - fn run(mut this: Pin>) { + fn run(mut this: Pin>) { if let Some(func) = this.as_mut().project().take() { (func)() } @@ -297,7 +297,7 @@ unsafe fn __enqueue(self, queue_work_on: F) -> Self::EnqueueOutput /// Defines the method that should be called directly when a work item is executed. /// -/// This trait is implemented by `Pin>` and [`Arc`], and is mainly intended to be +/// This trait is implemented by `Pin>` and [`Arc`], and is mainly intended to be /// implemented for smart pointer types. For your own structs, you would implement [`WorkItem`] /// instead. The [`run`] method on this trait will usually just perform the appropriate /// `container_of` translation and then call into the [`run`][WorkItem::run] method from the @@ -329,7 +329,7 @@ pub unsafe trait WorkItemPointer: RawWorkItem { /// This trait is used when the `work_struct` field is defined using the [`Work`] helper. pub trait WorkItem { /// The pointer type that this struct is wrapped in. This will typically be `Arc` or - /// `Pin>`. + /// `Pin>`. type Pointer: WorkItemPointer; /// The method that should be called when this work item is executed. @@ -366,7 +366,6 @@ unsafe impl Sync for Work {} impl Work { /// Creates a new instance of [`Work`]. #[inline] - #[allow(clippy::new_ret_no_self)] pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit where T: WorkItem, @@ -520,13 +519,14 @@ unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_typ impl{T} HasWork for ClosureWork { self.work } } +// SAFETY: TODO. unsafe impl WorkItemPointer for Arc where T: WorkItem, T: HasWork, { unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { - // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work`. + // The `__enqueue` method always uses a `work_struct` stored in a `Work`. let ptr = ptr as *mut Work; // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. let ptr = unsafe { T::work_container_of(ptr) }; @@ -537,6 +537,7 @@ unsafe impl WorkItemPointer for Arc } } +// SAFETY: TODO. unsafe impl RawWorkItem for Arc where T: WorkItem, @@ -565,18 +566,19 @@ unsafe fn __enqueue(self, queue_work_on: F) -> Self::EnqueueOutput } } -unsafe impl WorkItemPointer for Pin> +// SAFETY: TODO. +unsafe impl WorkItemPointer for Pin> where T: WorkItem, T: HasWork, { unsafe extern "C" fn run(ptr: *mut bindings::work_struct) { - // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work`. + // The `__enqueue` method always uses a `work_struct` stored in a `Work`. let ptr = ptr as *mut Work; // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`. let ptr = unsafe { T::work_container_of(ptr) }; // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership. - let boxed = unsafe { Box::from_raw(ptr) }; + let boxed = unsafe { KBox::from_raw(ptr) }; // SAFETY: The box was already pinned when it was enqueued. let pinned = unsafe { Pin::new_unchecked(boxed) }; @@ -584,7 +586,8 @@ unsafe impl WorkItemPointer for Pin> } } -unsafe impl RawWorkItem for Pin> +// SAFETY: TODO. +unsafe impl RawWorkItem for Pin> where T: WorkItem, T: HasWork, @@ -598,9 +601,9 @@ unsafe fn __enqueue(self, queue_work_on: F) -> Self::EnqueueOutput // SAFETY: We're not going to move `self` or any of its fields, so its okay to temporarily // remove the `Pin` wrapper. let boxed = unsafe { Pin::into_inner_unchecked(self) }; - let ptr = Box::into_raw(boxed); + let ptr = KBox::into_raw(boxed); - // SAFETY: Pointers into a `Box` point at a valid value. + // SAFETY: Pointers into a `KBox` point at a valid value. let work_ptr = unsafe { T::raw_get_work(ptr) }; // SAFETY: `raw_get_work` returns a pointer to a valid value. let work_ptr = unsafe { Work::raw_get(work_ptr) }; diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index a626b1145e5c4f..4ab94e44adfe32 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -30,7 +30,7 @@ /// /// # Examples /// -/// ```ignore +/// ``` /// use kernel::prelude::*; /// /// module!{ @@ -42,22 +42,16 @@ /// alias: ["alternate_module_name"], /// } /// -/// struct MyModule; +/// struct MyModule(i32); /// /// impl kernel::Module for MyModule { -/// fn init() -> Result { -/// // If the parameter is writeable, then the kparam lock must be -/// // taken to read the parameter: -/// { -/// let lock = THIS_MODULE.kernel_param_lock(); -/// pr_info!("i32 param is: {}\n", writeable_i32.read(&lock)); -/// } -/// // If the parameter is read only, it can be read without locking -/// // the kernel parameters: -/// pr_info!("i32 param is: {}\n", my_i32.read()); -/// Ok(Self) +/// fn init(_module: &'static ThisModule) -> Result { +/// let foo: i32 = 42; +/// pr_info!("I contain: {}\n", foo); +/// Ok(Self(foo)) /// } /// } +/// # fn main() {} /// ``` /// /// ## Firmware @@ -69,7 +63,7 @@ /// build an initramfs uses this information to put the firmware files into /// the initramfs image. /// -/// ```ignore +/// ``` /// use kernel::prelude::*; /// /// module!{ @@ -84,10 +78,11 @@ /// struct MyDeviceDriverModule; /// /// impl kernel::Module for MyDeviceDriverModule { -/// fn init() -> Result { +/// fn init(_module: &'static ThisModule) -> Result { /// Ok(Self) /// } /// } +/// # fn main() {} /// ``` /// /// # Supported argument types @@ -132,7 +127,7 @@ pub fn module(ts: TokenStream) -> TokenStream { /// calls to this function at compile time: /// /// ```compile_fail -/// # use kernel::error::VTABLE_DEFAULT_ERROR; +/// # // Intentionally missing `use`s to simplify `rusttest`. /// kernel::build_error(VTABLE_DEFAULT_ERROR) /// ``` /// @@ -142,7 +137,7 @@ pub fn module(ts: TokenStream) -> TokenStream { /// /// # Examples /// -/// ```ignore +/// ``` /// use kernel::error::VTABLE_DEFAULT_ERROR; /// use kernel::prelude::*; /// @@ -187,12 +182,27 @@ pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream { /// /// # Examples /// -/// ```ignore -/// use kernel::macro::concat_idents; +/// ``` +/// # const binder_driver_return_protocol_BR_OK: u32 = 0; +/// # const binder_driver_return_protocol_BR_ERROR: u32 = 1; +/// # const binder_driver_return_protocol_BR_TRANSACTION: u32 = 2; +/// # const binder_driver_return_protocol_BR_REPLY: u32 = 3; +/// # const binder_driver_return_protocol_BR_DEAD_REPLY: u32 = 4; +/// # const binder_driver_return_protocol_BR_TRANSACTION_COMPLETE: u32 = 5; +/// # const binder_driver_return_protocol_BR_INCREFS: u32 = 6; +/// # const binder_driver_return_protocol_BR_ACQUIRE: u32 = 7; +/// # const binder_driver_return_protocol_BR_RELEASE: u32 = 8; +/// # const binder_driver_return_protocol_BR_DECREFS: u32 = 9; +/// # const binder_driver_return_protocol_BR_NOOP: u32 = 10; +/// # const binder_driver_return_protocol_BR_SPAWN_LOOPER: u32 = 11; +/// # const binder_driver_return_protocol_BR_DEAD_BINDER: u32 = 12; +/// # const binder_driver_return_protocol_BR_CLEAR_DEATH_NOTIFICATION_DONE: u32 = 13; +/// # const binder_driver_return_protocol_BR_FAILED_REPLY: u32 = 14; +/// use kernel::macros::concat_idents; /// /// macro_rules! pub_no_prefix { /// ($prefix:ident, $($newname:ident),+) => { -/// $(pub(crate) const $newname: u32 = kernel::macros::concat_idents!($prefix, $newname);)+ +/// $(pub(crate) const $newname: u32 = concat_idents!($prefix, $newname);)+ /// }; /// } /// @@ -238,21 +248,35 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { /// /// # Examples /// -/// ```rust,ignore +/// ``` +/// # #![feature(lint_reasons)] +/// # use kernel::prelude::*; +/// # use std::{sync::Mutex, process::Command}; +/// # use kernel::macros::pin_data; /// #[pin_data] /// struct DriverData { /// #[pin] -/// queue: Mutex>, -/// buf: Box<[u8; 1024 * 1024]>, +/// queue: Mutex>, +/// buf: KBox<[u8; 1024 * 1024]>, /// } /// ``` /// -/// ```rust,ignore +/// ``` +/// # #![feature(lint_reasons)] +/// # use kernel::prelude::*; +/// # use std::{sync::Mutex, process::Command}; +/// # use core::pin::Pin; +/// # pub struct Info; +/// # mod bindings { +/// # pub unsafe fn destroy_info(_ptr: *mut super::Info) {} +/// # } +/// use kernel::macros::{pin_data, pinned_drop}; +/// /// #[pin_data(PinnedDrop)] /// struct DriverData { /// #[pin] -/// queue: Mutex>, -/// buf: Box<[u8; 1024 * 1024]>, +/// queue: Mutex>, +/// buf: KBox<[u8; 1024 * 1024]>, /// raw_info: *mut Info, /// } /// @@ -262,6 +286,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { /// unsafe { bindings::destroy_info(self.raw_info) }; /// } /// } +/// # fn main() {} /// ``` /// /// [`pin_init!`]: ../kernel/macro.pin_init.html @@ -277,13 +302,22 @@ pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream { /// /// # Examples /// -/// ```rust,ignore +/// ``` +/// # #![feature(lint_reasons)] +/// # use kernel::prelude::*; +/// # use macros::{pin_data, pinned_drop}; +/// # use std::{sync::Mutex, process::Command}; +/// # use core::pin::Pin; +/// # mod bindings { +/// # pub struct Info; +/// # pub unsafe fn destroy_info(_ptr: *mut Info) {} +/// # } /// #[pin_data(PinnedDrop)] /// struct DriverData { /// #[pin] -/// queue: Mutex>, -/// buf: Box<[u8; 1024 * 1024]>, -/// raw_info: *mut Info, +/// queue: Mutex>, +/// buf: KBox<[u8; 1024 * 1024]>, +/// raw_info: *mut bindings::Info, /// } /// /// #[pinned_drop] @@ -309,12 +343,25 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// /// # Example /// -/// ```ignore -/// use kernel::macro::paste; -/// +/// ``` +/// # const binder_driver_return_protocol_BR_OK: u32 = 0; +/// # const binder_driver_return_protocol_BR_ERROR: u32 = 1; +/// # const binder_driver_return_protocol_BR_TRANSACTION: u32 = 2; +/// # const binder_driver_return_protocol_BR_REPLY: u32 = 3; +/// # const binder_driver_return_protocol_BR_DEAD_REPLY: u32 = 4; +/// # const binder_driver_return_protocol_BR_TRANSACTION_COMPLETE: u32 = 5; +/// # const binder_driver_return_protocol_BR_INCREFS: u32 = 6; +/// # const binder_driver_return_protocol_BR_ACQUIRE: u32 = 7; +/// # const binder_driver_return_protocol_BR_RELEASE: u32 = 8; +/// # const binder_driver_return_protocol_BR_DECREFS: u32 = 9; +/// # const binder_driver_return_protocol_BR_NOOP: u32 = 10; +/// # const binder_driver_return_protocol_BR_SPAWN_LOOPER: u32 = 11; +/// # const binder_driver_return_protocol_BR_DEAD_BINDER: u32 = 12; +/// # const binder_driver_return_protocol_BR_CLEAR_DEATH_NOTIFICATION_DONE: u32 = 13; +/// # const binder_driver_return_protocol_BR_FAILED_REPLY: u32 = 14; /// macro_rules! pub_no_prefix { /// ($prefix:ident, $($newname:ident),+) => { -/// paste! { +/// kernel::macros::paste! { /// $(pub(crate) const $newname: u32 = [<$prefix $newname>];)+ /// } /// }; @@ -353,13 +400,26 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// * `lower`: change the identifier to lower case. /// * `upper`: change the identifier to upper case. /// -/// ```ignore -/// use kernel::macro::paste; -/// +/// ``` +/// # const binder_driver_return_protocol_BR_OK: u32 = 0; +/// # const binder_driver_return_protocol_BR_ERROR: u32 = 1; +/// # const binder_driver_return_protocol_BR_TRANSACTION: u32 = 2; +/// # const binder_driver_return_protocol_BR_REPLY: u32 = 3; +/// # const binder_driver_return_protocol_BR_DEAD_REPLY: u32 = 4; +/// # const binder_driver_return_protocol_BR_TRANSACTION_COMPLETE: u32 = 5; +/// # const binder_driver_return_protocol_BR_INCREFS: u32 = 6; +/// # const binder_driver_return_protocol_BR_ACQUIRE: u32 = 7; +/// # const binder_driver_return_protocol_BR_RELEASE: u32 = 8; +/// # const binder_driver_return_protocol_BR_DECREFS: u32 = 9; +/// # const binder_driver_return_protocol_BR_NOOP: u32 = 10; +/// # const binder_driver_return_protocol_BR_SPAWN_LOOPER: u32 = 11; +/// # const binder_driver_return_protocol_BR_DEAD_BINDER: u32 = 12; +/// # const binder_driver_return_protocol_BR_CLEAR_DEATH_NOTIFICATION_DONE: u32 = 13; +/// # const binder_driver_return_protocol_BR_FAILED_REPLY: u32 = 14; /// macro_rules! pub_no_prefix { /// ($prefix:ident, $($newname:ident),+) => { /// kernel::macros::paste! { -/// $(pub(crate) const fn [<$newname:lower:span>]: u32 = [<$prefix $newname:span>];)+ +/// $(pub(crate) const fn [<$newname:lower:span>]() -> u32 { [<$prefix $newname:span>] })+ /// } /// }; /// } @@ -390,7 +450,7 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// /// Literals can also be concatenated with other identifiers: /// -/// ```ignore +/// ``` /// macro_rules! create_numbered_fn { /// ($name:literal, $val:literal) => { /// kernel::macros::paste! { @@ -418,7 +478,9 @@ pub fn paste(input: TokenStream) -> TokenStream { /// /// # Examples /// -/// ```rust,ignore +/// ``` +/// use kernel::macros::Zeroable; +/// /// #[derive(Zeroable)] /// pub struct DriverData { /// id: i64, diff --git a/rust/macros/module.rs b/rust/macros/module.rs index aef3b132f32b33..2587f41b0d3929 100644 --- a/rust/macros/module.rs +++ b/rust/macros/module.rs @@ -232,6 +232,7 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream { mod __module_init {{ mod __module_init {{ use super::super::{type_}; + use kernel::init::PinInit; /// The \"Rust loadable module\" mark. // @@ -242,7 +243,8 @@ mod __module_init {{ #[used] static __IS_RUST_MODULE: () = (); - static mut __MOD: Option<{type_}> = None; + static mut __MOD: core::mem::MaybeUninit<{type_}> = + core::mem::MaybeUninit::uninit(); // Loadable modules need to export the `{{init,cleanup}}_module` identifiers. /// # Safety @@ -253,7 +255,7 @@ mod __module_init {{ #[doc(hidden)] #[no_mangle] #[link_section = \".init.text\"] - pub unsafe extern \"C\" fn init_module() -> core::ffi::c_int {{ + pub unsafe extern \"C\" fn init_module() -> kernel::ffi::c_int {{ // SAFETY: This function is inaccessible to the outside due to the double // module wrapping it. It is called exactly once by the C side via its // unique name. @@ -292,7 +294,7 @@ mod __module_init {{ #[doc(hidden)] #[link_section = \"{initcall_section}\"] #[used] - pub static __{name}_initcall: extern \"C\" fn() -> core::ffi::c_int = __{name}_init; + pub static __{name}_initcall: extern \"C\" fn() -> kernel::ffi::c_int = __{name}_init; #[cfg(not(MODULE))] #[cfg(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)] @@ -307,7 +309,7 @@ mod __module_init {{ #[cfg(not(MODULE))] #[doc(hidden)] #[no_mangle] - pub extern \"C\" fn __{name}_init() -> core::ffi::c_int {{ + pub extern \"C\" fn __{name}_init() -> kernel::ffi::c_int {{ // SAFETY: This function is inaccessible to the outside due to the double // module wrapping it. It is called exactly once by the C side via its // placement above in the initcall section. @@ -330,21 +332,15 @@ mod __module_init {{ /// # Safety /// /// This function must only be called once. - unsafe fn __init() -> core::ffi::c_int {{ - match <{type_} as kernel::Module>::init(&super::super::THIS_MODULE) {{ - Ok(m) => {{ - // SAFETY: No data race, since `__MOD` can only be accessed by this - // module and there only `__init` and `__exit` access it. These - // functions are only called once and `__exit` cannot be called - // before or during `__init`. - unsafe {{ - __MOD = Some(m); - }} - return 0; - }} - Err(e) => {{ - return e.to_errno(); - }} + unsafe fn __init() -> kernel::ffi::c_int {{ + let initer = + <{type_} as kernel::InPlaceModule>::init(&super::super::THIS_MODULE); + // SAFETY: No data race, since `__MOD` can only be accessed by this module + // and there only `__init` and `__exit` access it. These functions are only + // called once and `__exit` cannot be called before or during `__init`. + match unsafe {{ initer.__pinned_init(__MOD.as_mut_ptr()) }} {{ + Ok(m) => 0, + Err(e) => e.to_errno(), }} }} @@ -359,7 +355,7 @@ unsafe fn __exit() {{ // called once and `__init` was already called. unsafe {{ // Invokes `drop()` on `__MOD`, which should be used for cleanup. - __MOD = None; + __MOD.assume_init_drop(); }} }} diff --git a/rust/macros/paste.rs b/rust/macros/paste.rs index f40d42b35b5869..6529a387673fb5 100644 --- a/rust/macros/paste.rs +++ b/rust/macros/paste.rs @@ -2,7 +2,7 @@ use proc_macro::{Delimiter, Group, Ident, Spacing, Span, TokenTree}; -fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree { +fn concat_helper(tokens: &[TokenTree]) -> Vec<(String, Span)> { let mut tokens = tokens.iter(); let mut segments = Vec::new(); let mut span = None; @@ -46,12 +46,21 @@ fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree { }; segments.push((value, sp)); } - _ => panic!("unexpected token in paste segments"), + Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::None => { + let tokens = group.stream().into_iter().collect::>(); + segments.append(&mut concat_helper(tokens.as_slice())); + } + token => panic!("unexpected token in paste segments: {:?}", token), }; } + segments +} + +fn concat(tokens: &[TokenTree], group_span: Span) -> TokenTree { + let segments = concat_helper(tokens); let pasted: String = segments.into_iter().map(|x| x.0).collect(); - TokenTree::Ident(Ident::new(&pasted, span.unwrap_or(group_span))) + TokenTree::Ident(Ident::new(&pasted, group_span)) } pub(crate) fn expand(tokens: &mut Vec) { diff --git a/rust/uapi/lib.rs b/rust/uapi/lib.rs index 80a00260e3e7a1..13495910271faf 100644 --- a/rust/uapi/lib.rs +++ b/rust/uapi/lib.rs @@ -14,6 +14,7 @@ #![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))] #![allow( clippy::all, + clippy::undocumented_unsafe_blocks, dead_code, missing_docs, non_camel_case_types, @@ -24,4 +25,9 @@ unsafe_op_in_unsafe_fn )] +// Manual definition of blocklisted types. +type __kernel_size_t = usize; +type __kernel_ssize_t = isize; +type __kernel_ptrdiff_t = isize; + include!(concat!(env!("OBJTREE"), "/rust/uapi/uapi_generated.rs")); diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 7afe040cf43b3f..96a05e70ace30a 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -17,20 +17,12 @@ tprogs-y += tracex3 tprogs-y += tracex4 tprogs-y += tracex5 tprogs-y += tracex6 -tprogs-y += tracex7 -tprogs-y += test_probe_write_user tprogs-y += trace_output tprogs-y += lathist tprogs-y += offwaketime tprogs-y += spintest tprogs-y += map_perf_test -tprogs-y += test_overhead -tprogs-y += test_cgrp2_array_pin -tprogs-y += test_cgrp2_attach -tprogs-y += test_cgrp2_sock -tprogs-y += test_cgrp2_sock2 tprogs-y += xdp_router_ipv4 -tprogs-y += test_current_task_under_cgroup tprogs-y += trace_event tprogs-y += sampleip tprogs-y += tc_l2_redirect @@ -66,20 +58,12 @@ tracex3-objs := tracex3_user.o tracex4-objs := tracex4_user.o tracex5-objs := tracex5_user.o $(TRACE_HELPERS) tracex6-objs := tracex6_user.o -tracex7-objs := tracex7_user.o -test_probe_write_user-objs := test_probe_write_user_user.o trace_output-objs := trace_output_user.o lathist-objs := lathist_user.o offwaketime-objs := offwaketime_user.o $(TRACE_HELPERS) spintest-objs := spintest_user.o $(TRACE_HELPERS) map_perf_test-objs := map_perf_test_user.o test_overhead-objs := test_overhead_user.o -test_cgrp2_array_pin-objs := test_cgrp2_array_pin.o -test_cgrp2_attach-objs := test_cgrp2_attach.o -test_cgrp2_sock-objs := test_cgrp2_sock.o -test_cgrp2_sock2-objs := test_cgrp2_sock2.o -test_current_task_under_cgroup-objs := $(CGROUP_HELPERS) \ - test_current_task_under_cgroup_user.o trace_event-objs := trace_event_user.o $(TRACE_HELPERS) sampleip-objs := sampleip_user.o $(TRACE_HELPERS) tc_l2_redirect-objs := tc_l2_redirect_user.o @@ -107,9 +91,6 @@ always-y += tracex3.bpf.o always-y += tracex4.bpf.o always-y += tracex5.bpf.o always-y += tracex6.bpf.o -always-y += tracex7.bpf.o -always-y += sock_flags.bpf.o -always-y += test_probe_write_user.bpf.o always-y += trace_output.bpf.o always-y += tcbpf1_kern.o always-y += tc_l2_redirect_kern.o @@ -117,12 +98,7 @@ always-y += lathist_kern.o always-y += offwaketime.bpf.o always-y += spintest.bpf.o always-y += map_perf_test.bpf.o -always-y += test_overhead_tp.bpf.o -always-y += test_overhead_raw_tp.bpf.o -always-y += test_overhead_kprobe.bpf.o always-y += parse_varlen.o parse_simple.o parse_ldabs.o -always-y += test_cgrp2_tc.bpf.o -always-y += test_current_task_under_cgroup.bpf.o always-y += trace_event_kern.o always-y += sampleip_kern.o always-y += lwt_len_hist.bpf.o @@ -170,13 +146,14 @@ ifeq ($(ARCH), x86) BPF_EXTRA_CFLAGS += -fcf-protection endif -TPROGS_CFLAGS += -Wall -O2 -TPROGS_CFLAGS += -Wmissing-prototypes -TPROGS_CFLAGS += -Wstrict-prototypes -TPROGS_CFLAGS += $(call try-run,\ +COMMON_CFLAGS += -Wall -O2 +COMMON_CFLAGS += -Wmissing-prototypes +COMMON_CFLAGS += -Wstrict-prototypes +COMMON_CFLAGS += $(call try-run,\ printf "int main() { return 0; }" |\ $(CC) -Werror -fsanitize=bounds -x c - -o "$$TMP",-fsanitize=bounds,) +TPROGS_CFLAGS += $(COMMON_CFLAGS) TPROGS_CFLAGS += -I$(objtree)/usr/include TPROGS_CFLAGS += -I$(srctree)/tools/testing/selftests/bpf/ TPROGS_CFLAGS += -I$(LIBBPF_INCLUDE) @@ -186,7 +163,7 @@ TPROGS_CFLAGS += -I$(srctree)/tools/lib TPROGS_CFLAGS += -DHAVE_ATTR_TEST=0 ifdef SYSROOT -TPROGS_CFLAGS += --sysroot=$(SYSROOT) +COMMON_CFLAGS += --sysroot=$(SYSROOT) TPROGS_LDFLAGS := -L$(SYSROOT)/usr/lib endif @@ -195,7 +172,6 @@ TPROGLDLIBS_xdp_router_ipv4 += -lm -pthread TPROGLDLIBS_tracex4 += -lrt TPROGLDLIBS_trace_output += -lrt TPROGLDLIBS_map_perf_test += -lrt -TPROGLDLIBS_test_overhead += -lrt # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: # make M=samples/bpf LLC=~/git/llvm-project/llvm/build/bin/llc CLANG=~/git/llvm-project/llvm/build/bin/clang @@ -254,7 +230,7 @@ clean: $(LIBBPF): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT) # Fix up variables inherited from Kbuild that tools/ build system won't like - $(MAKE) -C $(LIBBPF_SRC) RM='rm -rf' EXTRA_CFLAGS="$(TPROGS_CFLAGS)" \ + $(MAKE) -C $(LIBBPF_SRC) RM='rm -rf' EXTRA_CFLAGS="$(COMMON_CFLAGS)" \ LDFLAGS="$(TPROGS_LDFLAGS)" srctree=$(BPF_SAMPLES_PATH)/../../ \ O= OUTPUT=$(LIBBPF_OUTPUT)/ DESTDIR=$(LIBBPF_DESTDIR) prefix= \ $@ install_headers diff --git a/samples/bpf/sock_flags.bpf.c b/samples/bpf/sock_flags.bpf.c deleted file mode 100644 index 0da749f6a9e10d..00000000000000 --- a/samples/bpf/sock_flags.bpf.c +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "vmlinux.h" -#include "net_shared.h" -#include - -SEC("cgroup/sock") -int bpf_prog1(struct bpf_sock *sk) -{ - char fmt[] = "socket: family %d type %d protocol %d\n"; - char fmt2[] = "socket: uid %u gid %u\n"; - __u64 gid_uid = bpf_get_current_uid_gid(); - __u32 uid = gid_uid & 0xffffffff; - __u32 gid = gid_uid >> 32; - - bpf_trace_printk(fmt, sizeof(fmt), sk->family, sk->type, sk->protocol); - bpf_trace_printk(fmt2, sizeof(fmt2), uid, gid); - - /* block AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6 sockets - * ie., make ping6 fail - */ - if (sk->family == AF_INET6 && - sk->type == SOCK_DGRAM && - sk->protocol == IPPROTO_ICMPV6) - return 0; - - return 1; -} - -SEC("cgroup/sock") -int bpf_prog2(struct bpf_sock *sk) -{ - char fmt[] = "socket: family %d type %d protocol %d\n"; - - bpf_trace_printk(fmt, sizeof(fmt), sk->family, sk->type, sk->protocol); - - /* block AF_INET, SOCK_DGRAM, IPPROTO_ICMP sockets - * ie., make ping fail - */ - if (sk->family == AF_INET && - sk->type == SOCK_DGRAM && - sk->protocol == IPPROTO_ICMP) - return 0; - - return 1; -} - -char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/syscall_nrs.c b/samples/bpf/syscall_nrs.c index 88f9400524509d..a6e600f3d47763 100644 --- a/samples/bpf/syscall_nrs.c +++ b/samples/bpf/syscall_nrs.c @@ -2,6 +2,9 @@ #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + #define SYSNR(_NR) DEFINE(SYS ## _NR, _NR) void syscall_defines(void) @@ -17,3 +20,5 @@ void syscall_defines(void) #endif } + +#pragma GCC diagnostic pop diff --git a/samples/bpf/tc_l2_redirect_kern.c b/samples/bpf/tc_l2_redirect_kern.c index fd2fa00043305a..b19fa9b88fe0a2 100644 --- a/samples/bpf/tc_l2_redirect_kern.c +++ b/samples/bpf/tc_l2_redirect_kern.c @@ -58,14 +58,11 @@ static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr) SEC("l2_to_iptun_ingress_forward") int _l2_to_iptun_ingress_forward(struct __sk_buff *skb) { - struct bpf_tunnel_key tkey = {}; void *data = (void *)(long)skb->data; struct eth_hdr *eth = data; void *data_end = (void *)(long)skb->data_end; int key = 0, *ifindex; - int ret; - if (data + sizeof(*eth) > data_end) return TC_ACT_OK; @@ -115,8 +112,6 @@ int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb) void *data_end = (void *)(long)skb->data_end; int key = 0, *ifindex; - int ret; - if (data + sizeof(*eth) > data_end) return TC_ACT_OK; @@ -205,7 +200,6 @@ int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb) SEC("drop_non_tun_vip") int _drop_non_tun_vip(struct __sk_buff *skb) { - struct bpf_tunnel_key tkey = {}; void *data = (void *)(long)skb->data; struct eth_hdr *eth = data; void *data_end = (void *)(long)skb->data_end; diff --git a/samples/bpf/test_cgrp2_array_pin.c b/samples/bpf/test_cgrp2_array_pin.c deleted file mode 100644 index 05e88aa63009c5..00000000000000 --- a/samples/bpf/test_cgrp2_array_pin.c +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2016 Facebook - */ -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -static void usage(void) -{ - printf("Usage: test_cgrp2_array_pin [...]\n"); - printf(" -F File to pin an BPF cgroup array\n"); - printf(" -U Update an already pinned BPF cgroup array\n"); - printf(" -v Full path of the cgroup2\n"); - printf(" -h Display this help\n"); -} - -int main(int argc, char **argv) -{ - const char *pinned_file = NULL, *cg2 = NULL; - int create_array = 1; - int array_key = 0; - int array_fd = -1; - int cg2_fd = -1; - int ret = -1; - int opt; - - while ((opt = getopt(argc, argv, "F:U:v:")) != -1) { - switch (opt) { - /* General args */ - case 'F': - pinned_file = optarg; - break; - case 'U': - pinned_file = optarg; - create_array = 0; - break; - case 'v': - cg2 = optarg; - break; - default: - usage(); - goto out; - } - } - - if (!cg2 || !pinned_file) { - usage(); - goto out; - } - - cg2_fd = open(cg2, O_RDONLY); - if (cg2_fd < 0) { - fprintf(stderr, "open(%s,...): %s(%d)\n", - cg2, strerror(errno), errno); - goto out; - } - - if (create_array) { - array_fd = bpf_map_create(BPF_MAP_TYPE_CGROUP_ARRAY, NULL, - sizeof(uint32_t), sizeof(uint32_t), - 1, NULL); - if (array_fd < 0) { - fprintf(stderr, - "bpf_create_map(BPF_MAP_TYPE_CGROUP_ARRAY,...): %s(%d)\n", - strerror(errno), errno); - goto out; - } - } else { - array_fd = bpf_obj_get(pinned_file); - if (array_fd < 0) { - fprintf(stderr, "bpf_obj_get(%s): %s(%d)\n", - pinned_file, strerror(errno), errno); - goto out; - } - } - - ret = bpf_map_update_elem(array_fd, &array_key, &cg2_fd, 0); - if (ret) { - perror("bpf_map_update_elem"); - goto out; - } - - if (create_array) { - ret = bpf_obj_pin(array_fd, pinned_file); - if (ret) { - fprintf(stderr, "bpf_obj_pin(..., %s): %s(%d)\n", - pinned_file, strerror(errno), errno); - goto out; - } - } - -out: - if (array_fd != -1) - close(array_fd); - if (cg2_fd != -1) - close(cg2_fd); - return ret; -} diff --git a/samples/bpf/test_cgrp2_attach.c b/samples/bpf/test_cgrp2_attach.c deleted file mode 100644 index 68ce69457afea8..00000000000000 --- a/samples/bpf/test_cgrp2_attach.c +++ /dev/null @@ -1,177 +0,0 @@ -/* eBPF example program: - * - * - Creates arraymap in kernel with 4 bytes keys and 8 byte values - * - * - Loads eBPF program - * - * The eBPF program accesses the map passed in to store two pieces of - * information. The number of invocations of the program, which maps - * to the number of packets received, is stored to key 0. Key 1 is - * incremented on each iteration by the number of bytes stored in - * the skb. - * - * - Attaches the new program to a cgroup using BPF_PROG_ATTACH - * - * - Every second, reads map[0] and map[1] to see how many bytes and - * packets were seen on any socket of tasks in the given cgroup. - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "bpf_insn.h" -#include "bpf_util.h" - -enum { - MAP_KEY_PACKETS, - MAP_KEY_BYTES, -}; - -char bpf_log_buf[BPF_LOG_BUF_SIZE]; - -static int prog_load(int map_fd, int verdict) -{ - struct bpf_insn prog[] = { - BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), /* save r6 so it's not clobbered by BPF_CALL */ - - /* Count packets */ - BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_PACKETS), /* r0 = 0 */ - BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ - BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), - BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */ - BPF_LD_MAP_FD(BPF_REG_1, map_fd), /* load map fd to r1 */ - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), - BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), - BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */ - BPF_ATOMIC_OP(BPF_DW, BPF_ADD, BPF_REG_0, BPF_REG_1, 0), - - /* Count bytes */ - BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_BYTES), /* r0 = 1 */ - BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ - BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), - BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */ - BPF_LD_MAP_FD(BPF_REG_1, map_fd), - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), - BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), - BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offsetof(struct __sk_buff, len)), /* r1 = skb->len */ - - BPF_ATOMIC_OP(BPF_DW, BPF_ADD, BPF_REG_0, BPF_REG_1, 0), - - BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ - BPF_EXIT_INSN(), - }; - size_t insns_cnt = ARRAY_SIZE(prog); - LIBBPF_OPTS(bpf_prog_load_opts, opts, - .log_buf = bpf_log_buf, - .log_size = BPF_LOG_BUF_SIZE, - ); - - return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SKB, NULL, "GPL", - prog, insns_cnt, &opts); -} - -static int usage(const char *argv0) -{ - printf("Usage: %s [-d] [-D] \n", argv0); - printf(" -d Drop Traffic\n"); - printf(" -D Detach filter, and exit\n"); - return EXIT_FAILURE; -} - -static int attach_filter(int cg_fd, int type, int verdict) -{ - int prog_fd, map_fd, ret, key; - long long pkt_cnt, byte_cnt; - - map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, - sizeof(key), sizeof(byte_cnt), - 256, NULL); - if (map_fd < 0) { - printf("Failed to create map: '%s'\n", strerror(errno)); - return EXIT_FAILURE; - } - - prog_fd = prog_load(map_fd, verdict); - printf("Output from kernel verifier:\n%s\n-------\n", bpf_log_buf); - - if (prog_fd < 0) { - printf("Failed to load prog: '%s'\n", strerror(errno)); - return EXIT_FAILURE; - } - - ret = bpf_prog_attach(prog_fd, cg_fd, type, 0); - if (ret < 0) { - printf("Failed to attach prog to cgroup: '%s'\n", - strerror(errno)); - return EXIT_FAILURE; - } - while (1) { - key = MAP_KEY_PACKETS; - assert(bpf_map_lookup_elem(map_fd, &key, &pkt_cnt) == 0); - - key = MAP_KEY_BYTES; - assert(bpf_map_lookup_elem(map_fd, &key, &byte_cnt) == 0); - - printf("cgroup received %lld packets, %lld bytes\n", - pkt_cnt, byte_cnt); - sleep(1); - } - - return EXIT_SUCCESS; -} - -int main(int argc, char **argv) -{ - int detach_only = 0, verdict = 1; - enum bpf_attach_type type; - int opt, cg_fd, ret; - - while ((opt = getopt(argc, argv, "Dd")) != -1) { - switch (opt) { - case 'd': - verdict = 0; - break; - case 'D': - detach_only = 1; - break; - default: - return usage(argv[0]); - } - } - - if (argc - optind < 2) - return usage(argv[0]); - - if (strcmp(argv[optind + 1], "ingress") == 0) - type = BPF_CGROUP_INET_INGRESS; - else if (strcmp(argv[optind + 1], "egress") == 0) - type = BPF_CGROUP_INET_EGRESS; - else - return usage(argv[0]); - - cg_fd = open(argv[optind], O_DIRECTORY | O_RDONLY); - if (cg_fd < 0) { - printf("Failed to open cgroup path: '%s'\n", strerror(errno)); - return EXIT_FAILURE; - } - - if (detach_only) { - ret = bpf_prog_detach(cg_fd, type); - printf("bpf_prog_detach() returned '%s' (%d)\n", - strerror(errno), errno); - } else - ret = attach_filter(cg_fd, type, verdict); - - return ret; -} diff --git a/samples/bpf/test_cgrp2_sock.c b/samples/bpf/test_cgrp2_sock.c deleted file mode 100644 index a0811df888f453..00000000000000 --- a/samples/bpf/test_cgrp2_sock.c +++ /dev/null @@ -1,294 +0,0 @@ -/* eBPF example program: - * - * - Loads eBPF program - * - * The eBPF program sets the sk_bound_dev_if index in new AF_INET{6} - * sockets opened by processes in the cgroup. - * - * - Attaches the new program to a cgroup using BPF_PROG_ATTACH - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bpf_insn.h" - -char bpf_log_buf[BPF_LOG_BUF_SIZE]; - -static int prog_load(__u32 idx, __u32 mark, __u32 prio) -{ - /* save pointer to context */ - struct bpf_insn prog_start[] = { - BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), - }; - struct bpf_insn prog_end[] = { - BPF_MOV64_IMM(BPF_REG_0, 1), /* r0 = verdict */ - BPF_EXIT_INSN(), - }; - - /* set sk_bound_dev_if on socket */ - struct bpf_insn prog_dev[] = { - BPF_MOV64_IMM(BPF_REG_3, idx), - BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, bound_dev_if)), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, bound_dev_if)), - }; - - /* set mark on socket */ - struct bpf_insn prog_mark[] = { - /* get uid of process */ - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, - BPF_FUNC_get_current_uid_gid), - BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffffffff), - - /* if uid is 0, use given mark, else use the uid as the mark */ - BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), - BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), - BPF_MOV64_IMM(BPF_REG_3, mark), - - /* set the mark on the new socket */ - BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), - BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, mark)), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, mark)), - }; - - /* set priority on socket */ - struct bpf_insn prog_prio[] = { - BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), - BPF_MOV64_IMM(BPF_REG_3, prio), - BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, priority)), - BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, priority)), - }; - LIBBPF_OPTS(bpf_prog_load_opts, opts, - .log_buf = bpf_log_buf, - .log_size = BPF_LOG_BUF_SIZE, - ); - - struct bpf_insn *prog; - size_t insns_cnt; - void *p; - int ret; - - insns_cnt = sizeof(prog_start) + sizeof(prog_end); - if (idx) - insns_cnt += sizeof(prog_dev); - - if (mark) - insns_cnt += sizeof(prog_mark); - - if (prio) - insns_cnt += sizeof(prog_prio); - - p = prog = malloc(insns_cnt); - if (!prog) { - fprintf(stderr, "Failed to allocate memory for instructions\n"); - return EXIT_FAILURE; - } - - memcpy(p, prog_start, sizeof(prog_start)); - p += sizeof(prog_start); - - if (idx) { - memcpy(p, prog_dev, sizeof(prog_dev)); - p += sizeof(prog_dev); - } - - if (mark) { - memcpy(p, prog_mark, sizeof(prog_mark)); - p += sizeof(prog_mark); - } - - if (prio) { - memcpy(p, prog_prio, sizeof(prog_prio)); - p += sizeof(prog_prio); - } - - memcpy(p, prog_end, sizeof(prog_end)); - p += sizeof(prog_end); - - insns_cnt /= sizeof(struct bpf_insn); - - ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", - prog, insns_cnt, &opts); - - free(prog); - - return ret; -} - -static int get_bind_to_device(int sd, char *name, size_t len) -{ - socklen_t optlen = len; - int rc; - - name[0] = '\0'; - rc = getsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, name, &optlen); - if (rc < 0) - perror("setsockopt(SO_BINDTODEVICE)"); - - return rc; -} - -static unsigned int get_somark(int sd) -{ - unsigned int mark = 0; - socklen_t optlen = sizeof(mark); - int rc; - - rc = getsockopt(sd, SOL_SOCKET, SO_MARK, &mark, &optlen); - if (rc < 0) - perror("getsockopt(SO_MARK)"); - - return mark; -} - -static unsigned int get_priority(int sd) -{ - unsigned int prio = 0; - socklen_t optlen = sizeof(prio); - int rc; - - rc = getsockopt(sd, SOL_SOCKET, SO_PRIORITY, &prio, &optlen); - if (rc < 0) - perror("getsockopt(SO_PRIORITY)"); - - return prio; -} - -static int show_sockopts(int family) -{ - unsigned int mark, prio; - char name[16]; - int sd; - - sd = socket(family, SOCK_DGRAM, 17); - if (sd < 0) { - perror("socket"); - return 1; - } - - if (get_bind_to_device(sd, name, sizeof(name)) < 0) - return 1; - - mark = get_somark(sd); - prio = get_priority(sd); - - close(sd); - - printf("sd %d: dev %s, mark %u, priority %u\n", sd, name, mark, prio); - - return 0; -} - -static int usage(const char *argv0) -{ - printf("Usage:\n"); - printf(" Attach a program\n"); - printf(" %s -b bind-to-dev -m mark -p prio cg-path\n", argv0); - printf("\n"); - printf(" Detach a program\n"); - printf(" %s -d cg-path\n", argv0); - printf("\n"); - printf(" Show inherited socket settings (mark, priority, and device)\n"); - printf(" %s [-6]\n", argv0); - return EXIT_FAILURE; -} - -int main(int argc, char **argv) -{ - __u32 idx = 0, mark = 0, prio = 0; - const char *cgrp_path = NULL; - int cg_fd, prog_fd, ret; - int family = PF_INET; - int do_attach = 1; - int rc; - - while ((rc = getopt(argc, argv, "db:m:p:6")) != -1) { - switch (rc) { - case 'd': - do_attach = 0; - break; - case 'b': - idx = if_nametoindex(optarg); - if (!idx) { - idx = strtoumax(optarg, NULL, 0); - if (!idx) { - printf("Invalid device name\n"); - return EXIT_FAILURE; - } - } - break; - case 'm': - mark = strtoumax(optarg, NULL, 0); - break; - case 'p': - prio = strtoumax(optarg, NULL, 0); - break; - case '6': - family = PF_INET6; - break; - default: - return usage(argv[0]); - } - } - - if (optind == argc) - return show_sockopts(family); - - cgrp_path = argv[optind]; - if (!cgrp_path) { - fprintf(stderr, "cgroup path not given\n"); - return EXIT_FAILURE; - } - - if (do_attach && !idx && !mark && !prio) { - fprintf(stderr, - "One of device, mark or priority must be given\n"); - return EXIT_FAILURE; - } - - cg_fd = open(cgrp_path, O_DIRECTORY | O_RDONLY); - if (cg_fd < 0) { - printf("Failed to open cgroup path: '%s'\n", strerror(errno)); - return EXIT_FAILURE; - } - - if (do_attach) { - prog_fd = prog_load(idx, mark, prio); - if (prog_fd < 0) { - printf("Failed to load prog: '%s'\n", strerror(errno)); - printf("Output from kernel verifier:\n%s\n-------\n", - bpf_log_buf); - return EXIT_FAILURE; - } - - ret = bpf_prog_attach(prog_fd, cg_fd, - BPF_CGROUP_INET_SOCK_CREATE, 0); - if (ret < 0) { - printf("Failed to attach prog to cgroup: '%s'\n", - strerror(errno)); - return EXIT_FAILURE; - } - } else { - ret = bpf_prog_detach(cg_fd, BPF_CGROUP_INET_SOCK_CREATE); - if (ret < 0) { - printf("Failed to detach prog from cgroup: '%s'\n", - strerror(errno)); - return EXIT_FAILURE; - } - } - - close(cg_fd); - return EXIT_SUCCESS; -} diff --git a/samples/bpf/test_cgrp2_sock.sh b/samples/bpf/test_cgrp2_sock.sh deleted file mode 100755 index 36bd7cb46f06d8..00000000000000 --- a/samples/bpf/test_cgrp2_sock.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 - -# Test various socket options that can be set by attaching programs to cgroups. - -MY_DIR=$(dirname $0) -TEST=$MY_DIR/test_cgrp2_sock -CGRP_MNT="/tmp/cgroupv2-test_cgrp2_sock" - -################################################################################ -# -print_result() -{ - local rc=$1 - local status=" OK " - - [ $rc -ne 0 ] && status="FAIL" - - printf "%-50s [%4s]\n" "$2" "$status" -} - -check_sock() -{ - out=$($TEST) - echo $out | grep -q "$1" - if [ $? -ne 0 ]; then - print_result 1 "IPv4: $2" - echo " expected: $1" - echo " have: $out" - rc=1 - else - print_result 0 "IPv4: $2" - fi -} - -check_sock6() -{ - out=$($TEST -6) - echo $out | grep -q "$1" - if [ $? -ne 0 ]; then - print_result 1 "IPv6: $2" - echo " expected: $1" - echo " have: $out" - rc=1 - else - print_result 0 "IPv6: $2" - fi -} - -################################################################################ -# - -cleanup() -{ - echo $$ >> ${CGRP_MNT}/cgroup.procs - rmdir ${CGRP_MNT}/sockopts -} - -cleanup_and_exit() -{ - local rc=$1 - local msg="$2" - - [ -n "$msg" ] && echo "ERROR: $msg" - - $TEST -d ${CGRP_MNT}/sockopts - ip li del cgrp2_sock - umount ${CGRP_MNT} - - exit $rc -} - - -################################################################################ -# main - -rc=0 - -ip li add cgrp2_sock type dummy 2>/dev/null - -set -e -mkdir -p ${CGRP_MNT} -mount -t cgroup2 none ${CGRP_MNT} -set +e - - -# make sure we have a known start point -cleanup 2>/dev/null - -mkdir -p ${CGRP_MNT}/sockopts -[ $? -ne 0 ] && cleanup_and_exit 1 "Failed to create cgroup hierarchy" - - -# set pid into cgroup -echo $$ > ${CGRP_MNT}/sockopts/cgroup.procs - -# no bpf program attached, so socket should show no settings -check_sock "dev , mark 0, priority 0" "No programs attached" -check_sock6 "dev , mark 0, priority 0" "No programs attached" - -# verify device is set -# -$TEST -b cgrp2_sock ${CGRP_MNT}/sockopts -if [ $? -ne 0 ]; then - cleanup_and_exit 1 "Failed to install program to set device" -fi -check_sock "dev cgrp2_sock, mark 0, priority 0" "Device set" -check_sock6 "dev cgrp2_sock, mark 0, priority 0" "Device set" - -# verify mark is set -# -$TEST -m 666 ${CGRP_MNT}/sockopts -if [ $? -ne 0 ]; then - cleanup_and_exit 1 "Failed to install program to set mark" -fi -check_sock "dev , mark 666, priority 0" "Mark set" -check_sock6 "dev , mark 666, priority 0" "Mark set" - -# verify priority is set -# -$TEST -p 123 ${CGRP_MNT}/sockopts -if [ $? -ne 0 ]; then - cleanup_and_exit 1 "Failed to install program to set priority" -fi -check_sock "dev , mark 0, priority 123" "Priority set" -check_sock6 "dev , mark 0, priority 123" "Priority set" - -# all 3 at once -# -$TEST -b cgrp2_sock -m 666 -p 123 ${CGRP_MNT}/sockopts -if [ $? -ne 0 ]; then - cleanup_and_exit 1 "Failed to install program to set device, mark and priority" -fi -check_sock "dev cgrp2_sock, mark 666, priority 123" "Priority set" -check_sock6 "dev cgrp2_sock, mark 666, priority 123" "Priority set" - -cleanup_and_exit $rc diff --git a/samples/bpf/test_cgrp2_sock2.c b/samples/bpf/test_cgrp2_sock2.c deleted file mode 100644 index e7060aaa2f5a3d..00000000000000 --- a/samples/bpf/test_cgrp2_sock2.c +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* eBPF example program: - * - * - Loads eBPF program - * - * The eBPF program loads a filter from file and attaches the - * program to a cgroup using BPF_PROG_ATTACH - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bpf_insn.h" - -static int usage(const char *argv0) -{ - printf("Usage: %s cg-path filter-path [filter-id]\n", argv0); - return EXIT_FAILURE; -} - -int main(int argc, char **argv) -{ - int cg_fd, err, ret = EXIT_FAILURE, filter_id = 0, prog_cnt = 0; - const char *link_pin_path = "/sys/fs/bpf/test_cgrp2_sock2"; - struct bpf_link *link = NULL; - struct bpf_program *progs[2]; - struct bpf_program *prog; - struct bpf_object *obj; - - if (argc < 3) - return usage(argv[0]); - - if (argc > 3) - filter_id = atoi(argv[3]); - - cg_fd = open(argv[1], O_DIRECTORY | O_RDONLY); - if (cg_fd < 0) { - printf("Failed to open cgroup path: '%s'\n", strerror(errno)); - return ret; - } - - obj = bpf_object__open_file(argv[2], NULL); - if (libbpf_get_error(obj)) { - printf("ERROR: opening BPF object file failed\n"); - return ret; - } - - bpf_object__for_each_program(prog, obj) { - progs[prog_cnt] = prog; - prog_cnt++; - } - - if (filter_id >= prog_cnt) { - printf("Invalid program id; program not found in file\n"); - goto cleanup; - } - - /* load BPF program */ - if (bpf_object__load(obj)) { - printf("ERROR: loading BPF object file failed\n"); - goto cleanup; - } - - link = bpf_program__attach_cgroup(progs[filter_id], cg_fd); - if (libbpf_get_error(link)) { - printf("ERROR: bpf_program__attach failed\n"); - link = NULL; - goto cleanup; - } - - err = bpf_link__pin(link, link_pin_path); - if (err < 0) { - printf("ERROR: bpf_link__pin failed: %d\n", err); - goto cleanup; - } - - ret = EXIT_SUCCESS; - -cleanup: - bpf_link__destroy(link); - bpf_object__close(obj); - return ret; -} diff --git a/samples/bpf/test_cgrp2_sock2.sh b/samples/bpf/test_cgrp2_sock2.sh deleted file mode 100755 index 82acff93d73975..00000000000000 --- a/samples/bpf/test_cgrp2_sock2.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0 - -BPFFS=/sys/fs/bpf -MY_DIR=$(dirname $0) -TEST=$MY_DIR/test_cgrp2_sock2 -LINK_PIN=$BPFFS/test_cgrp2_sock2 -BPF_PROG=$MY_DIR/sock_flags.bpf.o - -function config_device { - ip netns add at_ns0 - ip link add veth0 type veth peer name veth0b - ip link set veth0 netns at_ns0 - ip netns exec at_ns0 sysctl -q net.ipv6.conf.veth0.disable_ipv6=0 - ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0 - ip netns exec at_ns0 ip addr add 2401:db00::1/64 dev veth0 nodad - ip netns exec at_ns0 ip link set dev veth0 up - sysctl -q net.ipv6.conf.veth0b.disable_ipv6=0 - ip addr add 172.16.1.101/24 dev veth0b - ip addr add 2401:db00::2/64 dev veth0b nodad - ip link set veth0b up -} - -function config_cgroup { - rm -rf /tmp/cgroupv2 - mkdir -p /tmp/cgroupv2 - mount -t cgroup2 none /tmp/cgroupv2 - mkdir -p /tmp/cgroupv2/foo - echo $$ >> /tmp/cgroupv2/foo/cgroup.procs -} - -function config_bpffs { - if mount | grep $BPFFS > /dev/null; then - echo "bpffs already mounted" - else - echo "bpffs not mounted. Mounting..." - mount -t bpf none $BPFFS - fi -} - -function attach_bpf { - $TEST /tmp/cgroupv2/foo $BPF_PROG $1 - [ $? -ne 0 ] && exit 1 -} - -function cleanup { - rm -rf $LINK_PIN - ip link del veth0b - ip netns delete at_ns0 - umount /tmp/cgroupv2 - rm -rf /tmp/cgroupv2 -} - -cleanup 2>/dev/null - -set -e -config_device -config_cgroup -config_bpffs -set +e - -# -# Test 1 - fail ping6 -# -attach_bpf 0 -ping -c1 -w1 172.16.1.100 -if [ $? -ne 0 ]; then - echo "ping failed when it should succeed" - cleanup - exit 1 -fi - -ping6 -c1 -w1 2401:db00::1 -if [ $? -eq 0 ]; then - echo "ping6 succeeded when it should not" - cleanup - exit 1 -fi - -rm -rf $LINK_PIN -sleep 1 # Wait for link detach - -# -# Test 2 - fail ping -# -attach_bpf 1 -ping6 -c1 -w1 2401:db00::1 -if [ $? -ne 0 ]; then - echo "ping6 failed when it should succeed" - cleanup - exit 1 -fi - -ping -c1 -w1 172.16.1.100 -if [ $? -eq 0 ]; then - echo "ping succeeded when it should not" - cleanup - exit 1 -fi - -cleanup -echo -echo "*** PASS ***" diff --git a/samples/bpf/test_cgrp2_tc.bpf.c b/samples/bpf/test_cgrp2_tc.bpf.c deleted file mode 100644 index c7d2291d676f68..00000000000000 --- a/samples/bpf/test_cgrp2_tc.bpf.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2016 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#define KBUILD_MODNAME "foo" -#include "vmlinux.h" -#include "net_shared.h" -#include - -/* copy of 'struct ethhdr' without __packed */ -struct eth_hdr { - unsigned char h_dest[ETH_ALEN]; - unsigned char h_source[ETH_ALEN]; - unsigned short h_proto; -}; - -struct { - __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY); - __type(key, u32); - __type(value, u32); - __uint(pinning, LIBBPF_PIN_BY_NAME); - __uint(max_entries, 1); -} test_cgrp2_array_pin SEC(".maps"); - -SEC("filter") -int handle_egress(struct __sk_buff *skb) -{ - void *data = (void *)(long)skb->data; - struct eth_hdr *eth = data; - struct ipv6hdr *ip6h = data + sizeof(*eth); - void *data_end = (void *)(long)skb->data_end; - char dont_care_msg[] = "dont care %04x %d\n"; - char pass_msg[] = "pass\n"; - char reject_msg[] = "reject\n"; - - /* single length check */ - if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) - return TC_ACT_OK; - - if (eth->h_proto != bpf_htons(ETH_P_IPV6) || - ip6h->nexthdr != IPPROTO_ICMPV6) { - bpf_trace_printk(dont_care_msg, sizeof(dont_care_msg), - eth->h_proto, ip6h->nexthdr); - return TC_ACT_OK; - } else if (bpf_skb_under_cgroup(skb, &test_cgrp2_array_pin, 0) != 1) { - bpf_trace_printk(pass_msg, sizeof(pass_msg)); - return TC_ACT_OK; - } else { - bpf_trace_printk(reject_msg, sizeof(reject_msg)); - return TC_ACT_SHOT; - } -} - -char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/test_cgrp2_tc.sh b/samples/bpf/test_cgrp2_tc.sh deleted file mode 100755 index 38e8dbc9d16eeb..00000000000000 --- a/samples/bpf/test_cgrp2_tc.sh +++ /dev/null @@ -1,187 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0 - -MY_DIR=$(dirname $0) -# Details on the bpf prog -BPF_CGRP2_ARRAY_NAME='test_cgrp2_array_pin' -BPF_PROG="$MY_DIR/test_cgrp2_tc.bpf.o" -BPF_SECTION='filter' - -[ -z "$TC" ] && TC='tc' -[ -z "$IP" ] && IP='ip' - -# Names of the veth interface, net namespace...etc. -HOST_IFC='ve' -NS_IFC='vens' -NS='ns' - -find_mnt() { - cat /proc/mounts | \ - awk '{ if ($3 == "'$1'" && mnt == "") { mnt = $2 }} END { print mnt }' -} - -# Init cgroup2 vars -init_cgrp2_vars() { - CGRP2_ROOT=$(find_mnt cgroup2) - if [ -z "$CGRP2_ROOT" ] - then - CGRP2_ROOT='/mnt/cgroup2' - MOUNT_CGRP2="yes" - fi - CGRP2_TC="$CGRP2_ROOT/tc" - CGRP2_TC_LEAF="$CGRP2_TC/leaf" -} - -# Init bpf fs vars -init_bpf_fs_vars() { - local bpf_fs_root=$(find_mnt bpf) - [ -n "$bpf_fs_root" ] || return -1 - BPF_FS_TC_SHARE="$bpf_fs_root/tc/globals" -} - -setup_cgrp2() { - case $1 in - start) - if [ "$MOUNT_CGRP2" == 'yes' ] - then - [ -d $CGRP2_ROOT ] || mkdir -p $CGRP2_ROOT - mount -t cgroup2 none $CGRP2_ROOT || return $? - fi - mkdir -p $CGRP2_TC_LEAF - ;; - *) - rmdir $CGRP2_TC_LEAF && rmdir $CGRP2_TC - [ "$MOUNT_CGRP2" == 'yes' ] && umount $CGRP2_ROOT - ;; - esac -} - -setup_bpf_cgrp2_array() { - local bpf_cgrp2_array="$BPF_FS_TC_SHARE/$BPF_CGRP2_ARRAY_NAME" - case $1 in - start) - $MY_DIR/test_cgrp2_array_pin -U $bpf_cgrp2_array -v $CGRP2_TC - ;; - *) - [ -d "$BPF_FS_TC_SHARE" ] && rm -f $bpf_cgrp2_array - ;; - esac -} - -setup_net() { - case $1 in - start) - $IP link add $HOST_IFC type veth peer name $NS_IFC || return $? - $IP link set dev $HOST_IFC up || return $? - sysctl -q net.ipv6.conf.$HOST_IFC.disable_ipv6=0 - sysctl -q net.ipv6.conf.$HOST_IFC.accept_dad=0 - - $IP netns add $NS || return $? - $IP link set dev $NS_IFC netns $NS || return $? - $IP -n $NS link set dev $NS_IFC up || return $? - $IP netns exec $NS sysctl -q net.ipv6.conf.$NS_IFC.disable_ipv6=0 - $IP netns exec $NS sysctl -q net.ipv6.conf.$NS_IFC.accept_dad=0 - $TC qdisc add dev $HOST_IFC clsact || return $? - $TC filter add dev $HOST_IFC egress bpf da obj $BPF_PROG sec $BPF_SECTION || return $? - ;; - *) - $IP netns del $NS - $IP link del $HOST_IFC - ;; - esac -} - -run_in_cgrp() { - # Fork another bash and move it under the specified cgroup. - # It makes the cgroup cleanup easier at the end of the test. - cmd='echo $$ > ' - cmd="$cmd $1/cgroup.procs; exec $2" - bash -c "$cmd" -} - -do_test() { - run_in_cgrp $CGRP2_TC_LEAF "ping -6 -c3 ff02::1%$HOST_IFC >& /dev/null" - local dropped=$($TC -s qdisc show dev $HOST_IFC | tail -3 | \ - awk '/drop/{print substr($7, 0, index($7, ",")-1)}') - if [[ $dropped -eq 0 ]] - then - echo "FAIL" - return 1 - else - echo "Successfully filtered $dropped packets" - return 0 - fi -} - -do_exit() { - if [ "$DEBUG" == "yes" ] && [ "$MODE" != 'cleanuponly' ] - then - echo "------ DEBUG ------" - echo "mount: "; mount | grep -E '(cgroup2|bpf)'; echo - echo "$CGRP2_TC_LEAF: "; ls -l $CGRP2_TC_LEAF; echo - if [ -d "$BPF_FS_TC_SHARE" ] - then - echo "$BPF_FS_TC_SHARE: "; ls -l $BPF_FS_TC_SHARE; echo - fi - echo "Host net:" - $IP netns - $IP link show dev $HOST_IFC - $IP -6 a show dev $HOST_IFC - $TC -s qdisc show dev $HOST_IFC - echo - echo "$NS net:" - $IP -n $NS link show dev $NS_IFC - $IP -n $NS -6 link show dev $NS_IFC - echo "------ DEBUG ------" - echo - fi - - if [ "$MODE" != 'nocleanup' ] - then - setup_net stop - setup_bpf_cgrp2_array stop - setup_cgrp2 stop - fi -} - -init_cgrp2_vars -init_bpf_fs_vars - -while [[ $# -ge 1 ]] -do - a="$1" - case $a in - debug) - DEBUG='yes' - shift 1 - ;; - cleanup-only) - MODE='cleanuponly' - shift 1 - ;; - no-cleanup) - MODE='nocleanup' - shift 1 - ;; - *) - echo "test_cgrp2_tc [debug] [cleanup-only | no-cleanup]" - echo " debug: Print cgrp and network setup details at the end of the test" - echo " cleanup-only: Try to cleanup things from last test. No test will be run" - echo " no-cleanup: Run the test but don't do cleanup at the end" - echo "[Note: If no arg is given, it will run the test and do cleanup at the end]" - echo - exit -1 - ;; - esac -done - -trap do_exit 0 - -[ "$MODE" == 'cleanuponly' ] && exit - -setup_cgrp2 start || exit $? -setup_net start || exit $? -init_bpf_fs_vars || exit $? -setup_bpf_cgrp2_array start || exit $? -do_test -echo diff --git a/samples/bpf/test_current_task_under_cgroup.bpf.c b/samples/bpf/test_current_task_under_cgroup.bpf.c deleted file mode 100644 index 58b9cf7ed659ab..00000000000000 --- a/samples/bpf/test_current_task_under_cgroup.bpf.c +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2016 Sargun Dhillon - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ - -#include "vmlinux.h" -#include -#include -#include -#include - -struct { - __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY); - __uint(key_size, sizeof(u32)); - __uint(value_size, sizeof(u32)); - __uint(max_entries, 1); -} cgroup_map SEC(".maps"); - -struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, u32); - __type(value, u64); - __uint(max_entries, 1); -} perf_map SEC(".maps"); - -/* Writes the last PID that called sync to a map at index 0 */ -SEC("ksyscall/sync") -int BPF_KSYSCALL(bpf_prog1) -{ - u64 pid = bpf_get_current_pid_tgid(); - int idx = 0; - - if (!bpf_current_task_under_cgroup(&cgroup_map, 0)) - return 0; - - bpf_map_update_elem(&perf_map, &idx, &pid, BPF_ANY); - return 0; -} - -char _license[] SEC("license") = "GPL"; -u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/samples/bpf/test_current_task_under_cgroup_user.c b/samples/bpf/test_current_task_under_cgroup_user.c deleted file mode 100644 index 9726ed2a8a8bf5..00000000000000 --- a/samples/bpf/test_current_task_under_cgroup_user.c +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2016 Sargun Dhillon - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include "cgroup_helpers.h" - -#define CGROUP_PATH "/my-cgroup" - -int main(int argc, char **argv) -{ - pid_t remote_pid, local_pid = getpid(); - int cg2 = -1, idx = 0, rc = 1; - struct bpf_link *link = NULL; - struct bpf_program *prog; - struct bpf_object *obj; - char filename[256]; - int map_fd[2]; - - snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]); - obj = bpf_object__open_file(filename, NULL); - if (libbpf_get_error(obj)) { - fprintf(stderr, "ERROR: opening BPF object file failed\n"); - return 0; - } - - prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); - if (!prog) { - printf("finding a prog in obj file failed\n"); - goto cleanup; - } - - /* load BPF program */ - if (bpf_object__load(obj)) { - fprintf(stderr, "ERROR: loading BPF object file failed\n"); - goto cleanup; - } - - map_fd[0] = bpf_object__find_map_fd_by_name(obj, "cgroup_map"); - map_fd[1] = bpf_object__find_map_fd_by_name(obj, "perf_map"); - if (map_fd[0] < 0 || map_fd[1] < 0) { - fprintf(stderr, "ERROR: finding a map in obj file failed\n"); - goto cleanup; - } - - link = bpf_program__attach(prog); - if (libbpf_get_error(link)) { - fprintf(stderr, "ERROR: bpf_program__attach failed\n"); - link = NULL; - goto cleanup; - } - - if (setup_cgroup_environment()) - goto err; - - cg2 = create_and_get_cgroup(CGROUP_PATH); - - if (cg2 < 0) - goto err; - - if (bpf_map_update_elem(map_fd[0], &idx, &cg2, BPF_ANY)) { - log_err("Adding target cgroup to map"); - goto err; - } - - if (join_cgroup(CGROUP_PATH)) - goto err; - - /* - * The installed helper program catched the sync call, and should - * write it to the map. - */ - - sync(); - bpf_map_lookup_elem(map_fd[1], &idx, &remote_pid); - - if (local_pid != remote_pid) { - fprintf(stderr, - "BPF Helper didn't write correct PID to map, but: %d\n", - remote_pid); - goto err; - } - - /* Verify the negative scenario; leave the cgroup */ - if (join_cgroup("/")) - goto err; - - remote_pid = 0; - bpf_map_update_elem(map_fd[1], &idx, &remote_pid, BPF_ANY); - - sync(); - bpf_map_lookup_elem(map_fd[1], &idx, &remote_pid); - - if (local_pid == remote_pid) { - fprintf(stderr, "BPF cgroup negative test did not work\n"); - goto err; - } - - rc = 0; - -err: - if (cg2 != -1) - close(cg2); - - cleanup_cgroup_environment(); - -cleanup: - bpf_link__destroy(link); - bpf_object__close(obj); - return rc; -} diff --git a/samples/bpf/test_overhead_kprobe.bpf.c b/samples/bpf/test_overhead_kprobe.bpf.c deleted file mode 100644 index 668cf5259c605e..00000000000000 --- a/samples/bpf/test_overhead_kprobe.bpf.c +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (c) 2016 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include "vmlinux.h" -#include -#include -#include -#include - -SEC("kprobe/__set_task_comm") -int prog(struct pt_regs *ctx) -{ - struct signal_struct *signal; - struct task_struct *tsk; - char oldcomm[TASK_COMM_LEN] = {}; - char newcomm[TASK_COMM_LEN] = {}; - u16 oom_score_adj; - u32 pid; - - tsk = (void *)PT_REGS_PARM1_CORE(ctx); - - pid = BPF_CORE_READ(tsk, pid); - bpf_core_read_str(oldcomm, sizeof(oldcomm), &tsk->comm); - bpf_core_read_str(newcomm, sizeof(newcomm), - (void *)PT_REGS_PARM2(ctx)); - signal = BPF_CORE_READ(tsk, signal); - oom_score_adj = BPF_CORE_READ(signal, oom_score_adj); - return 0; -} - -SEC("kprobe/fib_table_lookup") -int prog2(struct pt_regs *ctx) -{ - return 0; -} - -char _license[] SEC("license") = "GPL"; -u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/samples/bpf/test_overhead_raw_tp.bpf.c b/samples/bpf/test_overhead_raw_tp.bpf.c deleted file mode 100644 index 6af39fe3f8dd03..00000000000000 --- a/samples/bpf/test_overhead_raw_tp.bpf.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (c) 2018 Facebook */ -#include "vmlinux.h" -#include - -SEC("raw_tracepoint/task_rename") -int prog(struct bpf_raw_tracepoint_args *ctx) -{ - return 0; -} - -SEC("raw_tracepoint/fib_table_lookup") -int prog2(struct bpf_raw_tracepoint_args *ctx) -{ - return 0; -} -char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/test_overhead_tp.bpf.c b/samples/bpf/test_overhead_tp.bpf.c deleted file mode 100644 index 5dc08b5879788f..00000000000000 --- a/samples/bpf/test_overhead_tp.bpf.c +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2016 Facebook - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include "vmlinux.h" -#include - -/* from /sys/kernel/tracing/events/task/task_rename/format */ -SEC("tracepoint/task/task_rename") -int prog(struct trace_event_raw_task_rename *ctx) -{ - return 0; -} - -/* from /sys/kernel/tracing/events/fib/fib_table_lookup/format */ -SEC("tracepoint/fib/fib_table_lookup") -int prog2(struct trace_event_raw_fib_table_lookup *ctx) -{ - return 0; -} -char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/test_overhead_user.c b/samples/bpf/test_overhead_user.c deleted file mode 100644 index dbd86f7b1473ac..00000000000000 --- a/samples/bpf/test_overhead_user.c +++ /dev/null @@ -1,225 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2016 Facebook - */ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_CNT 1000000 -#define DUMMY_IP "127.0.0.1" -#define DUMMY_PORT 80 - -static struct bpf_link *links[2]; -static struct bpf_object *obj; -static int cnt; - -static __u64 time_get_ns(void) -{ - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000ull + ts.tv_nsec; -} - -static void test_task_rename(int cpu) -{ - char buf[] = "test\n"; - __u64 start_time; - int i, fd; - - fd = open("/proc/self/comm", O_WRONLY|O_TRUNC); - if (fd < 0) { - printf("couldn't open /proc\n"); - exit(1); - } - start_time = time_get_ns(); - for (i = 0; i < MAX_CNT; i++) { - if (write(fd, buf, sizeof(buf)) < 0) { - printf("task rename failed: %s\n", strerror(errno)); - close(fd); - return; - } - } - printf("task_rename:%d: %lld events per sec\n", - cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); - close(fd); -} - -static void test_fib_table_lookup(int cpu) -{ - struct sockaddr_in addr; - char buf[] = "test\n"; - __u64 start_time; - int i, fd; - - fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (fd < 0) { - printf("couldn't open socket\n"); - exit(1); - } - memset((char *)&addr, 0, sizeof(addr)); - addr.sin_addr.s_addr = inet_addr(DUMMY_IP); - addr.sin_port = htons(DUMMY_PORT); - addr.sin_family = AF_INET; - start_time = time_get_ns(); - for (i = 0; i < MAX_CNT; i++) { - if (sendto(fd, buf, strlen(buf), 0, - (struct sockaddr *)&addr, sizeof(addr)) < 0) { - printf("failed to start ping: %s\n", strerror(errno)); - close(fd); - return; - } - } - printf("fib_table_lookup:%d: %lld events per sec\n", - cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); - close(fd); -} - -static void loop(int cpu, int flags) -{ - cpu_set_t cpuset; - - CPU_ZERO(&cpuset); - CPU_SET(cpu, &cpuset); - sched_setaffinity(0, sizeof(cpuset), &cpuset); - - if (flags & 1) - test_task_rename(cpu); - if (flags & 2) - test_fib_table_lookup(cpu); -} - -static void run_perf_test(int tasks, int flags) -{ - pid_t pid[tasks]; - int i; - - for (i = 0; i < tasks; i++) { - pid[i] = fork(); - if (pid[i] == 0) { - loop(i, flags); - exit(0); - } else if (pid[i] == -1) { - printf("couldn't spawn #%d process\n", i); - exit(1); - } - } - for (i = 0; i < tasks; i++) { - int status; - - assert(waitpid(pid[i], &status, 0) == pid[i]); - assert(status == 0); - } -} - -static int load_progs(char *filename) -{ - struct bpf_program *prog; - int err = 0; - - obj = bpf_object__open_file(filename, NULL); - err = libbpf_get_error(obj); - if (err < 0) { - fprintf(stderr, "ERROR: opening BPF object file failed\n"); - return err; - } - - /* load BPF program */ - err = bpf_object__load(obj); - if (err < 0) { - fprintf(stderr, "ERROR: loading BPF object file failed\n"); - return err; - } - - bpf_object__for_each_program(prog, obj) { - links[cnt] = bpf_program__attach(prog); - err = libbpf_get_error(links[cnt]); - if (err < 0) { - fprintf(stderr, "ERROR: bpf_program__attach failed\n"); - links[cnt] = NULL; - return err; - } - cnt++; - } - - return err; -} - -static void unload_progs(void) -{ - while (cnt) - bpf_link__destroy(links[--cnt]); - - bpf_object__close(obj); -} - -int main(int argc, char **argv) -{ - int num_cpu = sysconf(_SC_NPROCESSORS_ONLN); - int test_flags = ~0; - char filename[256]; - int err = 0; - - - if (argc > 1) - test_flags = atoi(argv[1]) ? : test_flags; - if (argc > 2) - num_cpu = atoi(argv[2]) ? : num_cpu; - - if (test_flags & 0x3) { - printf("BASE\n"); - run_perf_test(num_cpu, test_flags); - } - - if (test_flags & 0xC) { - snprintf(filename, sizeof(filename), - "%s_kprobe.bpf.o", argv[0]); - - printf("w/KPROBE\n"); - err = load_progs(filename); - if (!err) - run_perf_test(num_cpu, test_flags >> 2); - - unload_progs(); - } - - if (test_flags & 0x30) { - snprintf(filename, sizeof(filename), - "%s_tp.bpf.o", argv[0]); - printf("w/TRACEPOINT\n"); - err = load_progs(filename); - if (!err) - run_perf_test(num_cpu, test_flags >> 4); - - unload_progs(); - } - - if (test_flags & 0xC0) { - snprintf(filename, sizeof(filename), - "%s_raw_tp.bpf.o", argv[0]); - printf("w/RAW_TRACEPOINT\n"); - err = load_progs(filename); - if (!err) - run_perf_test(num_cpu, test_flags >> 6); - - unload_progs(); - } - - return err; -} diff --git a/samples/bpf/test_override_return.sh b/samples/bpf/test_override_return.sh deleted file mode 100755 index 35db26f736b9d9..00000000000000 --- a/samples/bpf/test_override_return.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -rm -r tmpmnt -rm -f testfile.img -dd if=/dev/zero of=testfile.img bs=1M seek=1000 count=1 -DEVICE=$(losetup --show -f testfile.img) -mkfs.btrfs -f $DEVICE -mkdir tmpmnt -./tracex7 $DEVICE -if [ $? -eq 0 ] -then - echo "SUCCESS!" -else - echo "FAILED!" -fi -losetup -d $DEVICE diff --git a/samples/bpf/test_probe_write_user.bpf.c b/samples/bpf/test_probe_write_user.bpf.c deleted file mode 100644 index a4f3798b7fb0c0..00000000000000 --- a/samples/bpf/test_probe_write_user.bpf.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (c) 2016 Sargun Dhillon - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#include "vmlinux.h" -#include -#include -#include -#include -#include - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, struct sockaddr_in); - __type(value, struct sockaddr_in); - __uint(max_entries, 256); -} dnat_map SEC(".maps"); - -/* kprobe is NOT a stable ABI - * kernel functions can be removed, renamed or completely change semantics. - * Number of arguments and their positions can change, etc. - * In such case this bpf+kprobe example will no longer be meaningful - * - * This example sits on a syscall, and the syscall ABI is relatively stable - * of course, across platforms, and over time, the ABI may change. - */ -SEC("ksyscall/connect") -int BPF_KSYSCALL(bpf_prog1, int fd, struct sockaddr_in *uservaddr, - int addrlen) -{ - struct sockaddr_in new_addr, orig_addr = {}; - struct sockaddr_in *mapped_addr; - - if (addrlen > sizeof(orig_addr)) - return 0; - - if (bpf_probe_read_user(&orig_addr, sizeof(orig_addr), uservaddr) != 0) - return 0; - - mapped_addr = bpf_map_lookup_elem(&dnat_map, &orig_addr); - if (mapped_addr != NULL) { - memcpy(&new_addr, mapped_addr, sizeof(new_addr)); - bpf_probe_write_user(uservaddr, &new_addr, - sizeof(new_addr)); - } - return 0; -} - -char _license[] SEC("license") = "GPL"; -u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/samples/bpf/test_probe_write_user_user.c b/samples/bpf/test_probe_write_user_user.c deleted file mode 100644 index 2a539aec411630..00000000000000 --- a/samples/bpf/test_probe_write_user_user.c +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int ac, char **argv) -{ - struct sockaddr_in *serv_addr_in, *mapped_addr_in, *tmp_addr_in; - struct sockaddr serv_addr, mapped_addr, tmp_addr; - int serverfd, serverconnfd, clientfd, map_fd; - struct bpf_link *link = NULL; - struct bpf_program *prog; - struct bpf_object *obj; - socklen_t sockaddr_len; - char filename[256]; - char *ip; - - serv_addr_in = (struct sockaddr_in *)&serv_addr; - mapped_addr_in = (struct sockaddr_in *)&mapped_addr; - tmp_addr_in = (struct sockaddr_in *)&tmp_addr; - - snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]); - obj = bpf_object__open_file(filename, NULL); - if (libbpf_get_error(obj)) { - fprintf(stderr, "ERROR: opening BPF object file failed\n"); - return 0; - } - - prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); - if (libbpf_get_error(prog)) { - fprintf(stderr, "ERROR: finding a prog in obj file failed\n"); - goto cleanup; - } - - /* load BPF program */ - if (bpf_object__load(obj)) { - fprintf(stderr, "ERROR: loading BPF object file failed\n"); - goto cleanup; - } - - map_fd = bpf_object__find_map_fd_by_name(obj, "dnat_map"); - if (map_fd < 0) { - fprintf(stderr, "ERROR: finding a map in obj file failed\n"); - goto cleanup; - } - - link = bpf_program__attach(prog); - if (libbpf_get_error(link)) { - fprintf(stderr, "ERROR: bpf_program__attach failed\n"); - link = NULL; - goto cleanup; - } - - assert((serverfd = socket(AF_INET, SOCK_STREAM, 0)) > 0); - assert((clientfd = socket(AF_INET, SOCK_STREAM, 0)) > 0); - - /* Bind server to ephemeral port on lo */ - memset(&serv_addr, 0, sizeof(serv_addr)); - serv_addr_in->sin_family = AF_INET; - serv_addr_in->sin_port = 0; - serv_addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - assert(bind(serverfd, &serv_addr, sizeof(serv_addr)) == 0); - - sockaddr_len = sizeof(serv_addr); - assert(getsockname(serverfd, &serv_addr, &sockaddr_len) == 0); - ip = inet_ntoa(serv_addr_in->sin_addr); - printf("Server bound to: %s:%d\n", ip, ntohs(serv_addr_in->sin_port)); - - memset(&mapped_addr, 0, sizeof(mapped_addr)); - mapped_addr_in->sin_family = AF_INET; - mapped_addr_in->sin_port = htons(5555); - mapped_addr_in->sin_addr.s_addr = inet_addr("255.255.255.255"); - - assert(!bpf_map_update_elem(map_fd, &mapped_addr, &serv_addr, BPF_ANY)); - - assert(listen(serverfd, 5) == 0); - - ip = inet_ntoa(mapped_addr_in->sin_addr); - printf("Client connecting to: %s:%d\n", - ip, ntohs(mapped_addr_in->sin_port)); - assert(connect(clientfd, &mapped_addr, sizeof(mapped_addr)) == 0); - - sockaddr_len = sizeof(tmp_addr); - ip = inet_ntoa(tmp_addr_in->sin_addr); - assert((serverconnfd = accept(serverfd, &tmp_addr, &sockaddr_len)) > 0); - printf("Server received connection from: %s:%d\n", - ip, ntohs(tmp_addr_in->sin_port)); - - sockaddr_len = sizeof(tmp_addr); - assert(getpeername(clientfd, &tmp_addr, &sockaddr_len) == 0); - ip = inet_ntoa(tmp_addr_in->sin_addr); - printf("Client's peer address: %s:%d\n", - ip, ntohs(tmp_addr_in->sin_port)); - - /* Is the server's getsockname = the socket getpeername */ - assert(memcmp(&serv_addr, &tmp_addr, sizeof(struct sockaddr_in)) == 0); - -cleanup: - bpf_link__destroy(link); - bpf_object__close(obj); - return 0; -} diff --git a/samples/bpf/tracex7.bpf.c b/samples/bpf/tracex7.bpf.c deleted file mode 100644 index ab8d6704a5a432..00000000000000 --- a/samples/bpf/tracex7.bpf.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "vmlinux.h" -#include -#include - -SEC("kprobe/open_ctree") -int bpf_prog1(struct pt_regs *ctx) -{ - unsigned long rc = -12; - - bpf_override_return(ctx, rc); - return 0; -} - -char _license[] SEC("license") = "GPL"; -u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/samples/bpf/tracex7_user.c b/samples/bpf/tracex7_user.c deleted file mode 100644 index b10b5e03a226ea..00000000000000 --- a/samples/bpf/tracex7_user.c +++ /dev/null @@ -1,56 +0,0 @@ -#define _GNU_SOURCE - -#include -#include -#include - -int main(int argc, char **argv) -{ - struct bpf_link *link = NULL; - struct bpf_program *prog; - struct bpf_object *obj; - char filename[256]; - char command[256]; - int ret = 0; - FILE *f; - - if (!argv[1]) { - fprintf(stderr, "ERROR: Run with the btrfs device argument!\n"); - return 0; - } - - snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]); - obj = bpf_object__open_file(filename, NULL); - if (libbpf_get_error(obj)) { - fprintf(stderr, "ERROR: opening BPF object file failed\n"); - return 0; - } - - prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); - if (!prog) { - fprintf(stderr, "ERROR: finding a prog in obj file failed\n"); - goto cleanup; - } - - /* load BPF program */ - if (bpf_object__load(obj)) { - fprintf(stderr, "ERROR: loading BPF object file failed\n"); - goto cleanup; - } - - link = bpf_program__attach(prog); - if (libbpf_get_error(link)) { - fprintf(stderr, "ERROR: bpf_program__attach failed\n"); - link = NULL; - goto cleanup; - } - - snprintf(command, 256, "mount %s tmpmnt/", argv[1]); - f = popen(command, "r"); - ret = pclose(f); - -cleanup: - bpf_link__destroy(link); - bpf_object__close(obj); - return ret ? 0 : 1; -} diff --git a/samples/bpf/xdp2skb_meta_kern.c b/samples/bpf/xdp2skb_meta_kern.c index d5631014a17643..af29a1bde4e44f 100644 --- a/samples/bpf/xdp2skb_meta_kern.c +++ b/samples/bpf/xdp2skb_meta_kern.c @@ -32,7 +32,7 @@ SEC("xdp_mark") int _xdp_mark(struct xdp_md *ctx) { struct meta_info *meta; - void *data, *data_end; + void *data; int ret; /* Reserve space in-front of data pointer for our meta info. diff --git a/samples/bpf/xdp_adjust_tail_kern.c b/samples/bpf/xdp_adjust_tail_kern.c index ffdd548627f0a4..da67bcad1c6381 100644 --- a/samples/bpf/xdp_adjust_tail_kern.c +++ b/samples/bpf/xdp_adjust_tail_kern.c @@ -57,6 +57,7 @@ static __always_inline void swap_mac(void *data, struct ethhdr *orig_eth) static __always_inline __u16 csum_fold_helper(__u32 csum) { + csum = (csum & 0xffff) + (csum >> 16); return ~((csum & 0xffff) + (csum >> 16)); } diff --git a/samples/ftrace/ftrace-direct-modify.c b/samples/ftrace/ftrace-direct-modify.c index 81220390851a39..cfea7a38befb05 100644 --- a/samples/ftrace/ftrace-direct-modify.c +++ b/samples/ftrace/ftrace-direct-modify.c @@ -2,7 +2,7 @@ #include #include #include -#ifndef CONFIG_ARM64 +#if !defined(CONFIG_ARM64) && !defined(CONFIG_PPC32) #include #endif @@ -199,6 +199,89 @@ asm ( #endif /* CONFIG_LOONGARCH */ +#ifdef CONFIG_PPC +#include + +#ifdef CONFIG_PPC64 +#define STACK_FRAME_SIZE 48 +#else +#define STACK_FRAME_SIZE 24 +#endif + +#if defined(CONFIG_PPC64_ELF_ABI_V2) && !defined(CONFIG_PPC_KERNEL_PCREL) +#define PPC64_TOC_SAVE_AND_UPDATE \ +" std 2, 24(1)\n" \ +" bcl 20, 31, 1f\n" \ +" 1: mflr 12\n" \ +" ld 2, (99f - 1b)(12)\n" +#define PPC64_TOC_RESTORE \ +" ld 2, 24(1)\n" +#define PPC64_TOC \ +" 99: .quad .TOC.@tocbase\n" +#else +#define PPC64_TOC_SAVE_AND_UPDATE "" +#define PPC64_TOC_RESTORE "" +#define PPC64_TOC "" +#endif + +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtlr 0\n" +#define PPC_FTRACE_RET \ +" blr\n" +#else +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtctr 0\n" +#define PPC_FTRACE_RET \ +" mtlr 0\n" \ +" bctr\n" +#endif + +asm ( +" .pushsection .text, \"ax\", @progbits\n" +" .type my_tramp1, @function\n" +" .globl my_tramp1\n" +" my_tramp1:\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mflr 0\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" + PPC64_TOC_SAVE_AND_UPDATE +" bl my_direct_func1\n" + PPC64_TOC_RESTORE +" addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" + PPC_FTRACE_RESTORE_LR +" addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_FTRACE_RET +" .size my_tramp1, .-my_tramp1\n" + +" .type my_tramp2, @function\n" +" .globl my_tramp2\n" +" my_tramp2:\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mflr 0\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" + PPC64_TOC_SAVE_AND_UPDATE +" bl my_direct_func2\n" + PPC64_TOC_RESTORE +" addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" + PPC_FTRACE_RESTORE_LR +" addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_FTRACE_RET + PPC64_TOC +" .size my_tramp2, .-my_tramp2\n" +" .popsection\n" +); + +#endif /* CONFIG_PPC */ + static struct ftrace_ops direct; static unsigned long my_tramp = (unsigned long)my_tramp1; diff --git a/samples/ftrace/ftrace-direct-multi-modify.c b/samples/ftrace/ftrace-direct-multi-modify.c index f943e40d57fd32..8f7986d698d874 100644 --- a/samples/ftrace/ftrace-direct-multi-modify.c +++ b/samples/ftrace/ftrace-direct-multi-modify.c @@ -2,7 +2,7 @@ #include #include #include -#ifndef CONFIG_ARM64 +#if !defined(CONFIG_ARM64) && !defined(CONFIG_PPC32) #include #endif @@ -225,6 +225,105 @@ asm ( #endif /* CONFIG_LOONGARCH */ +#ifdef CONFIG_PPC +#include + +#ifdef CONFIG_PPC64 +#define STACK_FRAME_SIZE 48 +#else +#define STACK_FRAME_SIZE 24 +#endif + +#if defined(CONFIG_PPC64_ELF_ABI_V2) && !defined(CONFIG_PPC_KERNEL_PCREL) +#define PPC64_TOC_SAVE_AND_UPDATE \ +" std 2, 24(1)\n" \ +" bcl 20, 31, 1f\n" \ +" 1: mflr 12\n" \ +" ld 2, (99f - 1b)(12)\n" +#define PPC64_TOC_RESTORE \ +" ld 2, 24(1)\n" +#define PPC64_TOC \ +" 99: .quad .TOC.@tocbase\n" +#else +#define PPC64_TOC_SAVE_AND_UPDATE "" +#define PPC64_TOC_RESTORE "" +#define PPC64_TOC "" +#endif + +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtlr 0\n" +#define PPC_FTRACE_RET \ +" blr\n" +#define PPC_FTRACE_RECOVER_IP \ +" lwz 8, 4(3)\n" \ +" li 9, 6\n" \ +" slw 8, 8, 9\n" \ +" sraw 8, 8, 9\n" \ +" add 3, 3, 8\n" \ +" addi 3, 3, 4\n" +#else +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtctr 0\n" +#define PPC_FTRACE_RET \ +" mtlr 0\n" \ +" bctr\n" +#define PPC_FTRACE_RECOVER_IP "" +#endif + +asm ( +" .pushsection .text, \"ax\", @progbits\n" +" .type my_tramp1, @function\n" +" .globl my_tramp1\n" +" my_tramp1:\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mflr 0\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" + PPC64_TOC_SAVE_AND_UPDATE + PPC_STL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mr 3, 0\n" + PPC_FTRACE_RECOVER_IP +" bl my_direct_func1\n" + PPC_LL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" + PPC64_TOC_RESTORE +" addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" + PPC_FTRACE_RESTORE_LR +" addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_FTRACE_RET +" .size my_tramp1, .-my_tramp1\n" + +" .type my_tramp2, @function\n" +" .globl my_tramp2\n" +" my_tramp2:\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mflr 0\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" + PPC64_TOC_SAVE_AND_UPDATE + PPC_STL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mr 3, 0\n" + PPC_FTRACE_RECOVER_IP +" bl my_direct_func2\n" + PPC_LL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" + PPC64_TOC_RESTORE +" addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" + PPC_FTRACE_RESTORE_LR +" addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_FTRACE_RET + PPC64_TOC + " .size my_tramp2, .-my_tramp2\n" +" .popsection\n" +); + +#endif /* CONFIG_PPC */ + static unsigned long my_tramp = (unsigned long)my_tramp1; static unsigned long tramps[2] = { (unsigned long)my_tramp1, diff --git a/samples/ftrace/ftrace-direct-multi.c b/samples/ftrace/ftrace-direct-multi.c index aed6df2927ce18..db326c81a27ddd 100644 --- a/samples/ftrace/ftrace-direct-multi.c +++ b/samples/ftrace/ftrace-direct-multi.c @@ -4,7 +4,7 @@ #include /* for handle_mm_fault() */ #include #include -#ifndef CONFIG_ARM64 +#if !defined(CONFIG_ARM64) && !defined(CONFIG_PPC32) #include #endif @@ -141,6 +141,83 @@ asm ( #endif /* CONFIG_LOONGARCH */ +#ifdef CONFIG_PPC +#include + +#ifdef CONFIG_PPC64 +#define STACK_FRAME_SIZE 48 +#else +#define STACK_FRAME_SIZE 24 +#endif + +#if defined(CONFIG_PPC64_ELF_ABI_V2) && !defined(CONFIG_PPC_KERNEL_PCREL) +#define PPC64_TOC_SAVE_AND_UPDATE \ +" std 2, 24(1)\n" \ +" bcl 20, 31, 1f\n" \ +" 1: mflr 12\n" \ +" ld 2, (99f - 1b)(12)\n" +#define PPC64_TOC_RESTORE \ +" ld 2, 24(1)\n" +#define PPC64_TOC \ +" 99: .quad .TOC.@tocbase\n" +#else +#define PPC64_TOC_SAVE_AND_UPDATE "" +#define PPC64_TOC_RESTORE "" +#define PPC64_TOC "" +#endif + +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtlr 0\n" +#define PPC_FTRACE_RET \ +" blr\n" +#define PPC_FTRACE_RECOVER_IP \ +" lwz 8, 4(3)\n" \ +" li 9, 6\n" \ +" slw 8, 8, 9\n" \ +" sraw 8, 8, 9\n" \ +" add 3, 3, 8\n" \ +" addi 3, 3, 4\n" +#else +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtctr 0\n" +#define PPC_FTRACE_RET \ +" mtlr 0\n" \ +" bctr\n" +#define PPC_FTRACE_RECOVER_IP "" +#endif + +asm ( +" .pushsection .text, \"ax\", @progbits\n" +" .type my_tramp, @function\n" +" .globl my_tramp\n" +" my_tramp:\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mflr 0\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" + PPC64_TOC_SAVE_AND_UPDATE + PPC_STL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mr 3, 0\n" + PPC_FTRACE_RECOVER_IP +" bl my_direct_func\n" + PPC_LL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" + PPC64_TOC_RESTORE +" addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" + PPC_FTRACE_RESTORE_LR +" addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_FTRACE_RET + PPC64_TOC +" .size my_tramp, .-my_tramp\n" +" .popsection\n" +); + +#endif /* CONFIG_PPC */ + static struct ftrace_ops direct; static int __init ftrace_direct_multi_init(void) diff --git a/samples/ftrace/ftrace-direct-too.c b/samples/ftrace/ftrace-direct-too.c index 6ff546a5d7eb05..3d0fa260332d47 100644 --- a/samples/ftrace/ftrace-direct-too.c +++ b/samples/ftrace/ftrace-direct-too.c @@ -3,7 +3,7 @@ #include /* for handle_mm_fault() */ #include -#ifndef CONFIG_ARM64 +#if !defined(CONFIG_ARM64) && !defined(CONFIG_PPC32) #include #endif @@ -153,6 +153,87 @@ asm ( #endif /* CONFIG_LOONGARCH */ +#ifdef CONFIG_PPC +#include + +#ifdef CONFIG_PPC64 +#define STACK_FRAME_SIZE 64 +#define STACK_FRAME_ARG1 32 +#define STACK_FRAME_ARG2 40 +#define STACK_FRAME_ARG3 48 +#define STACK_FRAME_ARG4 56 +#else +#define STACK_FRAME_SIZE 32 +#define STACK_FRAME_ARG1 16 +#define STACK_FRAME_ARG2 20 +#define STACK_FRAME_ARG3 24 +#define STACK_FRAME_ARG4 28 +#endif + +#if defined(CONFIG_PPC64_ELF_ABI_V2) && !defined(CONFIG_PPC_KERNEL_PCREL) +#define PPC64_TOC_SAVE_AND_UPDATE \ +" std 2, 24(1)\n" \ +" bcl 20, 31, 1f\n" \ +" 1: mflr 12\n" \ +" ld 2, (99f - 1b)(12)\n" +#define PPC64_TOC_RESTORE \ +" ld 2, 24(1)\n" +#define PPC64_TOC \ +" 99: .quad .TOC.@tocbase\n" +#else +#define PPC64_TOC_SAVE_AND_UPDATE "" +#define PPC64_TOC_RESTORE "" +#define PPC64_TOC "" +#endif + +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtlr 0\n" +#define PPC_FTRACE_RET \ +" blr\n" +#else +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtctr 0\n" +#define PPC_FTRACE_RET \ +" mtlr 0\n" \ +" bctr\n" +#endif + +asm ( +" .pushsection .text, \"ax\", @progbits\n" +" .type my_tramp, @function\n" +" .globl my_tramp\n" +" my_tramp:\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mflr 0\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" + PPC64_TOC_SAVE_AND_UPDATE + PPC_STL" 3, "__stringify(STACK_FRAME_ARG1)"(1)\n" + PPC_STL" 4, "__stringify(STACK_FRAME_ARG2)"(1)\n" + PPC_STL" 5, "__stringify(STACK_FRAME_ARG3)"(1)\n" + PPC_STL" 6, "__stringify(STACK_FRAME_ARG4)"(1)\n" +" bl my_direct_func\n" + PPC_LL" 6, "__stringify(STACK_FRAME_ARG4)"(1)\n" + PPC_LL" 5, "__stringify(STACK_FRAME_ARG3)"(1)\n" + PPC_LL" 4, "__stringify(STACK_FRAME_ARG2)"(1)\n" + PPC_LL" 3, "__stringify(STACK_FRAME_ARG1)"(1)\n" + PPC64_TOC_RESTORE +" addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" + PPC_FTRACE_RESTORE_LR +" addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_FTRACE_RET + PPC64_TOC +" .size my_tramp, .-my_tramp\n" +" .popsection\n" +); + +#endif /* CONFIG_PPC */ + static struct ftrace_ops direct; static int __init ftrace_direct_init(void) diff --git a/samples/ftrace/ftrace-direct.c b/samples/ftrace/ftrace-direct.c index ef0945670e1eb9..956834b0d19ac6 100644 --- a/samples/ftrace/ftrace-direct.c +++ b/samples/ftrace/ftrace-direct.c @@ -3,7 +3,7 @@ #include /* for wake_up_process() */ #include -#ifndef CONFIG_ARM64 +#if !defined(CONFIG_ARM64) && !defined(CONFIG_PPC32) #include #endif @@ -134,6 +134,73 @@ asm ( #endif /* CONFIG_LOONGARCH */ +#ifdef CONFIG_PPC +#include + +#ifdef CONFIG_PPC64 +#define STACK_FRAME_SIZE 48 +#else +#define STACK_FRAME_SIZE 24 +#endif + +#if defined(CONFIG_PPC64_ELF_ABI_V2) && !defined(CONFIG_PPC_KERNEL_PCREL) +#define PPC64_TOC_SAVE_AND_UPDATE \ +" std 2, 24(1)\n" \ +" bcl 20, 31, 1f\n" \ +" 1: mflr 12\n" \ +" ld 2, (99f - 1b)(12)\n" +#define PPC64_TOC_RESTORE \ +" ld 2, 24(1)\n" +#define PPC64_TOC \ +" 99: .quad .TOC.@tocbase\n" +#else +#define PPC64_TOC_SAVE_AND_UPDATE "" +#define PPC64_TOC_RESTORE "" +#define PPC64_TOC "" +#endif + +#ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtlr 0\n" +#define PPC_FTRACE_RET \ +" blr\n" +#else +#define PPC_FTRACE_RESTORE_LR \ + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" \ +" mtctr 0\n" +#define PPC_FTRACE_RET \ +" mtlr 0\n" \ +" bctr\n" +#endif + +asm ( +" .pushsection .text, \"ax\", @progbits\n" +" .type my_tramp, @function\n" +" .globl my_tramp\n" +" my_tramp:\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" mflr 0\n" + PPC_STL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_STLU" 1, -"__stringify(STACK_FRAME_SIZE)"(1)\n" + PPC64_TOC_SAVE_AND_UPDATE + PPC_STL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" +" bl my_direct_func\n" + PPC_LL" 3, "__stringify(STACK_FRAME_MIN_SIZE)"(1)\n" + PPC64_TOC_RESTORE +" addi 1, 1, "__stringify(STACK_FRAME_SIZE)"\n" + PPC_FTRACE_RESTORE_LR +" addi 1, 1, "__stringify(STACK_FRAME_MIN_SIZE)"\n" + PPC_LL" 0, "__stringify(PPC_LR_STKOFF)"(1)\n" + PPC_FTRACE_RET + PPC64_TOC +" .size my_tramp, .-my_tramp\n" +" .popsection\n" +); + +#endif /* CONFIG_PPC */ + static struct ftrace_ops direct; static int __init ftrace_direct_init(void) diff --git a/samples/hw_breakpoint/data_breakpoint.c b/samples/hw_breakpoint/data_breakpoint.c index a2c831e89ce0e9..fbb03b66dcbd13 100644 --- a/samples/hw_breakpoint/data_breakpoint.c +++ b/samples/hw_breakpoint/data_breakpoint.c @@ -52,8 +52,8 @@ static int __init hw_break_module_init(void) attr.bp_type = HW_BREAKPOINT_W; sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler, NULL); - if (IS_ERR((void __force *)sample_hbp)) { - ret = PTR_ERR((void __force *)sample_hbp); + if (IS_ERR_PCPU(sample_hbp)) { + ret = PTR_ERR_PCPU(sample_hbp); goto fail; } diff --git a/samples/kfifo/dma-example.c b/samples/kfifo/dma-example.c index 48df719dac8c6d..8076ac410161a3 100644 --- a/samples/kfifo/dma-example.c +++ b/samples/kfifo/dma-example.c @@ -9,6 +9,7 @@ #include #include #include +#include /* * This module shows how to handle fifo dma operations. diff --git a/samples/qmi/qmi_sample_client.c b/samples/qmi/qmi_sample_client.c index a42892523d3bfa..b27d861f354f5a 100644 --- a/samples/qmi/qmi_sample_client.c +++ b/samples/qmi/qmi_sample_client.c @@ -524,7 +524,7 @@ static void qmi_sample_remove(struct platform_device *pdev) static struct platform_driver qmi_sample_driver = { .probe = qmi_sample_probe, - .remove_new = qmi_sample_remove, + .remove = qmi_sample_remove, .driver = { .name = "qmi_sample_client", }, diff --git a/samples/rust/Makefile b/samples/rust/Makefile index 03086dabbea44f..c1a5c16553955b 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -1,6 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 +ccflags-y += -I$(src) # needed for trace events obj-$(CONFIG_SAMPLE_RUST_MINIMAL) += rust_minimal.o obj-$(CONFIG_SAMPLE_RUST_PRINT) += rust_print.o +rust_print-y := rust_print_main.o rust_print_events.o + subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) += hostprogs diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs index 2a9eaab62d1ca7..4aaf117bf8e3c0 100644 --- a/samples/rust/rust_minimal.rs +++ b/samples/rust/rust_minimal.rs @@ -13,7 +13,7 @@ } struct RustMinimal { - numbers: Vec, + numbers: KVec, } impl kernel::Module for RustMinimal { @@ -21,7 +21,7 @@ fn init(_module: &'static ThisModule) -> Result { pr_info!("Rust minimal sample (init)\n"); pr_info!("Am I built-in? {}\n", !cfg!(MODULE)); - let mut numbers = Vec::new(); + let mut numbers = KVec::new(); numbers.push(72, GFP_KERNEL)?; numbers.push(108, GFP_KERNEL)?; numbers.push(200, GFP_KERNEL)?; diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs deleted file mode 100644 index 6eabb0d79ea3a7..00000000000000 --- a/samples/rust/rust_print.rs +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -//! Rust printing macros sample. - -use kernel::pr_cont; -use kernel::prelude::*; - -module! { - type: RustPrint, - name: "rust_print", - author: "Rust for Linux Contributors", - description: "Rust printing macros sample", - license: "GPL", -} - -struct RustPrint; - -fn arc_print() -> Result { - use kernel::sync::*; - - let a = Arc::new(1, GFP_KERNEL)?; - let b = UniqueArc::new("hello, world", GFP_KERNEL)?; - - // Prints the value of data in `a`. - pr_info!("{}", a); - - // Uses ":?" to print debug fmt of `b`. - pr_info!("{:?}", b); - - let a: Arc<&str> = b.into(); - let c = a.clone(); - - // Uses `dbg` to print, will move `c` (for temporary debugging purposes). - dbg!(c); - - // Pretty-prints the debug formatting with lower-case hexadecimal integers. - pr_info!("{:#x?}", a); - - Ok(()) -} - -impl kernel::Module for RustPrint { - fn init(_module: &'static ThisModule) -> Result { - pr_info!("Rust printing macros sample (init)\n"); - - pr_emerg!("Emergency message (level 0) without args\n"); - pr_alert!("Alert message (level 1) without args\n"); - pr_crit!("Critical message (level 2) without args\n"); - pr_err!("Error message (level 3) without args\n"); - pr_warn!("Warning message (level 4) without args\n"); - pr_notice!("Notice message (level 5) without args\n"); - pr_info!("Info message (level 6) without args\n"); - - pr_info!("A line that"); - pr_cont!(" is continued"); - pr_cont!(" without args\n"); - - pr_emerg!("{} message (level {}) with args\n", "Emergency", 0); - pr_alert!("{} message (level {}) with args\n", "Alert", 1); - pr_crit!("{} message (level {}) with args\n", "Critical", 2); - pr_err!("{} message (level {}) with args\n", "Error", 3); - pr_warn!("{} message (level {}) with args\n", "Warning", 4); - pr_notice!("{} message (level {}) with args\n", "Notice", 5); - pr_info!("{} message (level {}) with args\n", "Info", 6); - - pr_info!("A {} that", "line"); - pr_cont!(" is {}", "continued"); - pr_cont!(" with {}\n", "args"); - - arc_print()?; - - Ok(RustPrint) - } -} - -impl Drop for RustPrint { - fn drop(&mut self) { - pr_info!("Rust printing macros sample (exit)\n"); - } -} diff --git a/samples/rust/rust_print_events.c b/samples/rust/rust_print_events.c new file mode 100644 index 00000000000000..a9169ff0edf181 --- /dev/null +++ b/samples/rust/rust_print_events.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2024 Google LLC + */ + +#define CREATE_TRACE_POINTS +#define CREATE_RUST_TRACE_POINTS +#include diff --git a/samples/rust/rust_print_main.rs b/samples/rust/rust_print_main.rs new file mode 100644 index 00000000000000..aed90a6feecfa7 --- /dev/null +++ b/samples/rust/rust_print_main.rs @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust printing macros sample. + +use kernel::pr_cont; +use kernel::prelude::*; + +module! { + type: RustPrint, + name: "rust_print", + author: "Rust for Linux Contributors", + description: "Rust printing macros sample", + license: "GPL", +} + +struct RustPrint; + +#[expect(clippy::disallowed_macros)] +fn arc_print() -> Result { + use kernel::sync::*; + + let a = Arc::new(1, GFP_KERNEL)?; + let b = UniqueArc::new("hello, world", GFP_KERNEL)?; + + // Prints the value of data in `a`. + pr_info!("{}", a); + + // Uses ":?" to print debug fmt of `b`. + pr_info!("{:?}", b); + + let a: Arc<&str> = b.into(); + let c = a.clone(); + + // Uses `dbg` to print, will move `c` (for temporary debugging purposes). + dbg!(c); + + // Pretty-prints the debug formatting with lower-case hexadecimal integers. + pr_info!("{:#x?}", a); + + Ok(()) +} + +impl kernel::Module for RustPrint { + fn init(_module: &'static ThisModule) -> Result { + pr_info!("Rust printing macros sample (init)\n"); + + pr_emerg!("Emergency message (level 0) without args\n"); + pr_alert!("Alert message (level 1) without args\n"); + pr_crit!("Critical message (level 2) without args\n"); + pr_err!("Error message (level 3) without args\n"); + pr_warn!("Warning message (level 4) without args\n"); + pr_notice!("Notice message (level 5) without args\n"); + pr_info!("Info message (level 6) without args\n"); + + pr_info!("A line that"); + pr_cont!(" is continued"); + pr_cont!(" without args\n"); + + pr_emerg!("{} message (level {}) with args\n", "Emergency", 0); + pr_alert!("{} message (level {}) with args\n", "Alert", 1); + pr_crit!("{} message (level {}) with args\n", "Critical", 2); + pr_err!("{} message (level {}) with args\n", "Error", 3); + pr_warn!("{} message (level {}) with args\n", "Warning", 4); + pr_notice!("{} message (level {}) with args\n", "Notice", 5); + pr_info!("{} message (level {}) with args\n", "Info", 6); + + pr_info!("A {} that", "line"); + pr_cont!(" is {}", "continued"); + pr_cont!(" with {}\n", "args"); + + arc_print()?; + + trace::trace_rust_sample_loaded(42); + + Ok(RustPrint) + } +} + +impl Drop for RustPrint { + fn drop(&mut self) { + pr_info!("Rust printing macros sample (exit)\n"); + } +} + +mod trace { + use core::ffi::c_int; + + kernel::declare_trace! { + /// # Safety + /// + /// Always safe to call. + unsafe fn rust_sample_loaded(magic: c_int); + } + + pub(crate) fn trace_rust_sample_loaded(magic: i32) { + // SAFETY: Always safe to call. + unsafe { rust_sample_loaded(magic as c_int) } + } +} diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h index 55f9a3da92d5f9..999f78d380aee4 100644 --- a/samples/trace_events/trace-events-sample.h +++ b/samples/trace_events/trace-events-sample.h @@ -319,7 +319,7 @@ TRACE_EVENT(foo_bar, __assign_cpumask(cpum, cpumask_bits(mask)); ), - TP_printk("foo %s %d %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, + TP_printk("foo %s %d %s %s %s %s %s %s (%s) (%s) %s", __entry->foo, __entry->bar, /* * Notice here the use of some helper functions. This includes: @@ -363,6 +363,11 @@ TRACE_EVENT(foo_bar, __print_array(__get_dynamic_array(list), __get_dynamic_array_len(list) / sizeof(int), sizeof(int)), + +/* A shortcut is to use __print_dynamic_array for dynamic arrays */ + + __print_dynamic_array(list, sizeof(int)), + __get_str(str), __get_str(lstr), __get_bitmask(cpus), __get_cpumask(cpum), __get_str(vstr)) diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index 4fc2063b9f595f..d709d82800cdb8 100644 --- a/samples/v4l/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c @@ -269,9 +269,7 @@ static void stop_streaming(struct vb2_queue *vq) } /* - * The vb2 queue ops. Note that since q->lock is set we can use the standard - * vb2_ops_wait_prepare/finish helper functions. If q->lock would be NULL, - * then this driver would have to provide these ops. + * The vb2 queue ops. */ static const struct vb2_ops skel_qops = { .queue_setup = queue_setup, @@ -279,8 +277,6 @@ static const struct vb2_ops skel_qops = { .buf_queue = buffer_queue, .start_streaming = start_streaming, .stop_streaming = stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; /* diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index 83645683799703..18623ba666e33f 100644 --- a/samples/vfio-mdev/mbochs.c +++ b/samples/vfio-mdev/mbochs.c @@ -1469,6 +1469,6 @@ static void __exit mbochs_dev_exit(void) class_unregister(&mbochs_class); } -MODULE_IMPORT_NS(DMA_BUF); +MODULE_IMPORT_NS("DMA_BUF"); module_init(mbochs_dev_init) module_exit(mbochs_dev_exit) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index ed8a7493524b29..8c311b997e2463 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -205,7 +205,7 @@ if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:) cmd_and_fixdep = \ $(cmd); \ - scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\ + $(objtree)/scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\ rm -f $(depfile) # Usage: $(call if_changed_rule,foo) diff --git a/scripts/Makefile.autofdo b/scripts/Makefile.autofdo new file mode 100644 index 00000000000000..1caf2457e585c0 --- /dev/null +++ b/scripts/Makefile.autofdo @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Enable available and selected Clang AutoFDO features. + +CFLAGS_AUTOFDO_CLANG := -fdebug-info-for-profiling -mllvm -enable-fs-discriminator=true -mllvm -improved-fs-discriminator=true + +ifndef CONFIG_DEBUG_INFO + CFLAGS_AUTOFDO_CLANG += -gmlt +endif + +ifdef CLANG_AUTOFDO_PROFILE + CFLAGS_AUTOFDO_CLANG += -fprofile-sample-use=$(CLANG_AUTOFDO_PROFILE) -ffunction-sections + CFLAGS_AUTOFDO_CLANG += -fsplit-machine-functions +endif + +ifdef CONFIG_LTO_CLANG_THIN + ifdef CLANG_AUTOFDO_PROFILE + KBUILD_LDFLAGS += --lto-sample-profile=$(CLANG_AUTOFDO_PROFILE) + endif + KBUILD_LDFLAGS += --mllvm=-enable-fs-discriminator=true --mllvm=-improved-fs-discriminator=true -plugin-opt=thinlto + KBUILD_LDFLAGS += -plugin-opt=-split-machine-functions +endif + +export CFLAGS_AUTOFDO_CLANG diff --git a/scripts/Makefile.btf b/scripts/Makefile.btf index b75f09f3f4248d..c3cbeb13de5035 100644 --- a/scripts/Makefile.btf +++ b/scripts/Makefile.btf @@ -3,6 +3,8 @@ pahole-ver := $(CONFIG_PAHOLE_VERSION) pahole-flags-y := +JOBS := $(patsubst -j%,%,$(filter -j%,$(MAKEFLAGS))) + ifeq ($(call test-le, $(pahole-ver), 125),y) # pahole 1.18 through 1.21 can't handle zero-sized per-CPU vars @@ -12,14 +14,14 @@ endif pahole-flags-$(call test-ge, $(pahole-ver), 121) += --btf_gen_floats -pahole-flags-$(call test-ge, $(pahole-ver), 122) += -j +pahole-flags-$(call test-ge, $(pahole-ver), 122) += -j$(JOBS) pahole-flags-$(call test-ge, $(pahole-ver), 125) += --skip_encoding_btf_inconsistent_proto --btf_gen_optimized else # Switch to using --btf_features for v1.26 and later. -pahole-flags-$(call test-ge, $(pahole-ver), 126) = -j --btf_features=encode_force,var,float,enum64,decl_tag,type_tag,optimized_func,consistent_func,decl_tag_kfuncs +pahole-flags-$(call test-ge, $(pahole-ver), 126) = -j$(JOBS) --btf_features=encode_force,var,float,enum64,decl_tag,type_tag,optimized_func,consistent_func,decl_tag_kfuncs ifneq ($(KBUILD_EXTMOD),) module-pahole-flags-$(call test-ge, $(pahole-ver), 126) += --btf_features=distilled_base diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 8f423a1faf5077..c16e4cf54d770f 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -3,7 +3,7 @@ # Building # ========================================================================== -src := $(if $(VPATH),$(VPATH)/)$(obj) +src := $(srcroot)/$(obj) PHONY := $(obj)/ $(obj)/: @@ -34,7 +34,7 @@ subdir-asflags-y := subdir-ccflags-y := # Read auto.conf if it exists, otherwise ignore --include include/config/auto.conf +-include $(objtree)/include/config/auto.conf include $(srctree)/scripts/Kbuild.include include $(srctree)/scripts/Makefile.compiler @@ -107,20 +107,14 @@ cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $< $(obj)/%.i: $(obj)/%.c FORCE $(call if_changed_dep,cpp_i_c) -genksyms = scripts/genksyms/genksyms \ - $(if $(1), -T $(2)) \ - $(if $(KBUILD_PRESERVE), -p) \ - -r $(or $(wildcard $(2:.symtypes=.symref)), /dev/null) +genksyms = $(objtree)/scripts/genksyms/genksyms \ + $(if $(KBUILD_SYMTYPES), -T $(@:.o=.symtypes)) \ + $(if $(KBUILD_PRESERVE), -p) \ + $(addprefix -r , $(wildcard $(@:.o=.symref))) # These mirror gensymtypes_S and co below, keep them in synch. cmd_gensymtypes_c = $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms) -quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ - cmd_cc_symtypes_c = $(call cmd_gensymtypes_c,true,$@) >/dev/null - -$(obj)/%.symtypes : $(obj)/%.c FORCE - $(call cmd,cc_symtypes_c) - # LLVM assembly # Generate .ll files from .c quiet_cmd_cc_ll_c = CC $(quiet_modtag) $@ @@ -135,17 +129,6 @@ $(obj)/%.ll: $(obj)/%.c FORCE is-single-obj-m = $(and $(part-of-module),$(filter $@, $(obj-m)),y) -# When a module consists of a single object, there is no reason to keep LLVM IR. -# Make $(LD) covert LLVM IR to ELF here. -ifdef CONFIG_LTO_CLANG -cmd_ld_single_m = $(if $(is-single-obj-m), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@) -endif - -quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ - cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \ - $(cmd_ld_single_m) \ - $(cmd_objtool) - ifdef CONFIG_MODVERSIONS # When module versioning is enabled the following steps are executed: # o compile a .o from .c @@ -158,8 +141,7 @@ ifdef CONFIG_MODVERSIONS gen_symversions = \ if $(NM) $@ 2>/dev/null | grep -q ' __export_symbol_'; then \ - $(call cmd_gensymtypes_$(1),$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - >> $(dot-target).cmd; \ + $(cmd_gensymtypes_$1) >> $(dot-target).cmd; \ fi cmd_gen_symversions_c = $(call gen_symversions,c) @@ -207,23 +189,6 @@ ifneq ($(findstring 1, $(KBUILD_EXTRA_WARN)),) cmd_warn_shared_object = $(if $(word 2, $(modname-multi)),$(warning $(kbuild-file): $*.o is added to multiple modules: $(modname-multi))) endif -define rule_cc_o_c - $(call cmd_and_fixdep,cc_o_c) - $(call cmd,checksrc) - $(call cmd,checkdoc) - $(call cmd,gen_objtooldep) - $(call cmd,gen_symversions_c) - $(call cmd,record_mcount) - $(call cmd,warn_shared_object) -endef - -define rule_as_o_S - $(call cmd_and_fixdep,as_o_S) - $(call cmd,gen_objtooldep) - $(call cmd,gen_symversions_S) - $(call cmd,warn_shared_object) -endef - # Built-in and composite module parts $(obj)/%.o: $(obj)/%.c $(recordmcount_source) FORCE $(call if_changed_rule,cc_o_c) @@ -248,17 +213,18 @@ $(obj)/%.lst: $(obj)/%.c FORCE # Compile Rust sources (.rs) # --------------------------------------------------------------------------- -rust_allowed_features := new_uninit +rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons # `--out-dir` is required to avoid temporaries being created by `rustc` in the # current working directory, which may be not accessible in the out-of-tree # modules case. rust_common_cmd = \ + OBJTREE=$(abspath $(objtree)) \ RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \ -Zallow-features=$(rust_allowed_features) \ -Zcrate-attr=no_std \ -Zcrate-attr='feature($(rust_allowed_features))' \ - -Zunstable-options --extern force:alloc --extern kernel \ + -Zunstable-options --extern kernel \ --crate-type rlib -L $(objtree)/rust/ \ --crate-name $(basename $(notdir $@)) \ --sysroot=/dev/null \ @@ -303,6 +269,12 @@ quiet_cmd_rustc_ll_rs = $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ $(obj)/%.ll: $(obj)/%.rs FORCE +$(call if_changed_dep,rustc_ll_rs) +quiet_cmd_rustc_rs_rs_S = RSCPP $(quiet_modtag) $@ + cmd_rustc_rs_rs_S = $(CPP) $(c_flags) -xc -C -P $< | sed '1,/^\/\/ Cut here.$$/d' >$@ + +$(obj)/%.rs: $(obj)/%.rs.S FORCE + +$(call if_changed_dep,rustc_rs_rs_S) + # Compile assembler sources (.S) # --------------------------------------------------------------------------- @@ -323,22 +295,12 @@ cmd_gensymtypes_S = \ $(NM) $@ | sed -n 's/.* __export_symbol_\(.*\)/EXPORT_SYMBOL(\1);/p' ; } | \ $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms) -quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@ - cmd_cc_symtypes_S = $(call cmd_gensymtypes_S,true,$@) >/dev/null - -$(obj)/%.symtypes : $(obj)/%.S FORCE - $(call cmd,cc_symtypes_S) - - quiet_cmd_cpp_s_S = CPP $(quiet_modtag) $@ cmd_cpp_s_S = $(CPP) $(a_flags) -o $@ $< $(obj)/%.s: $(obj)/%.S FORCE $(call if_changed_dep,cpp_s_S) -quiet_cmd_as_o_S = AS $(quiet_modtag) $@ - cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool) - ifdef CONFIG_ASM_MODVERSIONS # versioning matches the C process described above, with difference that diff --git a/scripts/Makefile.clang b/scripts/Makefile.clang index 6c23c6af797fb0..2435efae67f53a 100644 --- a/scripts/Makefile.clang +++ b/scripts/Makefile.clang @@ -10,6 +10,7 @@ CLANG_TARGET_FLAGS_mips := mipsel-linux-gnu CLANG_TARGET_FLAGS_powerpc := powerpc64le-linux-gnu CLANG_TARGET_FLAGS_riscv := riscv64-linux-gnu CLANG_TARGET_FLAGS_s390 := s390x-linux-gnu +CLANG_TARGET_FLAGS_sparc := sparc64-linux-gnu CLANG_TARGET_FLAGS_x86 := x86_64-linux-gnu CLANG_TARGET_FLAGS_um := $(CLANG_TARGET_FLAGS_$(SUBARCH)) CLANG_TARGET_FLAGS := $(CLANG_TARGET_FLAGS_$(SRCARCH)) diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean index 4fcfab40ed61a8..6ead00ec7313b3 100644 --- a/scripts/Makefile.clean +++ b/scripts/Makefile.clean @@ -3,7 +3,7 @@ # Cleaning up # ========================================================================== -src := $(if $(VPATH),$(VPATH)/)$(obj) +src := $(srcroot)/$(obj) PHONY := __clean __clean: diff --git a/scripts/Makefile.compiler b/scripts/Makefile.compiler index e0842496d26ed7..8c1029687e2e4f 100644 --- a/scripts/Makefile.compiler +++ b/scripts/Makefile.compiler @@ -13,7 +13,7 @@ cc-cross-prefix = $(firstword $(foreach c, $(1), \ $(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c)))) # output directory for tests below -TMPOUT = $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_$$$$ +TMPOUT = .tmp_$$$$ # try-run # Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise) diff --git a/scripts/Makefile.host b/scripts/Makefile.host index e01c13a588ddd9..c1dedf646a39f7 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -96,12 +96,10 @@ hostrust_flags = --out-dir $(dir $@) --emit=dep-info=$(depfile) \ $(KBUILD_HOSTRUSTFLAGS) $(HOST_EXTRARUSTFLAGS) \ $(HOSTRUSTFLAGS_$(target-stem)) -# $(objtree)/$(obj) for including generated headers from checkin source files -ifeq ($(KBUILD_EXTMOD),) +# $(obj) for including generated headers from checkin source files ifdef building_out_of_srctree -hostc_flags += -I $(objtree)/$(obj) -hostcxx_flags += -I $(objtree)/$(obj) -endif +hostc_flags += -I $(obj) +hostcxx_flags += -I $(obj) endif ##### diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 01a9f567d5af48..7395200538da89 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -191,15 +191,33 @@ _c_flags += $(if $(patsubst n%,, \ -D__KCSAN_INSTRUMENT_BARRIERS__) endif +# +# Enable AutoFDO build flags except some files or directories we don't want to +# enable (depends on variables AUTOFDO_PROFILE_obj.o and AUTOFDO_PROFILE). +# +ifeq ($(CONFIG_AUTOFDO_CLANG),y) +_c_flags += $(if $(patsubst n%,, \ + $(AUTOFDO_PROFILE_$(target-stem).o)$(AUTOFDO_PROFILE)$(is-kernel-object)), \ + $(CFLAGS_AUTOFDO_CLANG)) +endif + +# +# Enable Propeller build flags except some files or directories we don't want to +# enable (depends on variables AUTOFDO_PROPELLER_obj.o and PROPELLER_PROFILE). +# +ifdef CONFIG_PROPELLER_CLANG +_c_flags += $(if $(patsubst n%,, \ + $(AUTOFDO_PROFILE_$(target-stem).o)$(AUTOFDO_PROFILE)$(PROPELLER_PROFILE))$(is-kernel-object), \ + $(CFLAGS_PROPELLER_CLANG)) +endif + # $(src) for including checkin headers from generated source files # $(obj) for including generated headers from checkin source files -ifeq ($(KBUILD_EXTMOD),) ifdef building_out_of_srctree _c_flags += $(addprefix -I, $(src) $(obj)) _a_flags += $(addprefix -I, $(src) $(obj)) _cpp_flags += $(addprefix -I, $(src) $(obj)) endif -endif # If $(is-kernel-object) is 'y', this object will be linked to vmlinux or modules is-kernel-object = $(or $(part-of-builtin),$(part-of-module)) @@ -280,6 +298,42 @@ $(foreach m, $1, \ $(addprefix $(obj)/, $(call suffix-search, $(patsubst $(obj)/%,%,$m), $2, $3)))) endef +# Build commands +# =========================================================================== +# These are shared by some Makefile.* files. + +objtool-enabled := y + +ifdef CONFIG_LTO_CLANG +# objtool cannot process LLVM IR. Make $(LD) covert LLVM IR to ELF here. +cmd_ld_single = $(if $(objtool-enabled), ; $(LD) $(ld_flags) -r -o $(tmp-target) $@; mv $(tmp-target) $@) +endif + +quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ + cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< \ + $(cmd_ld_single) \ + $(cmd_objtool) + +define rule_cc_o_c + $(call cmd_and_fixdep,cc_o_c) + $(call cmd,checksrc) + $(call cmd,checkdoc) + $(call cmd,gen_objtooldep) + $(call cmd,gen_symversions_c) + $(call cmd,record_mcount) + $(call cmd,warn_shared_object) +endef + +quiet_cmd_as_o_S = AS $(quiet_modtag) $@ + cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< $(cmd_objtool) + +define rule_as_o_S + $(call cmd_and_fixdep,as_o_S) + $(call cmd,gen_objtooldep) + $(call cmd,gen_symversions_S) + $(call cmd,warn_shared_object) +endef + # Copy a file # =========================================================================== # 'cp' preserves permissions. If you use it to copy a file in read-only srctree, @@ -371,10 +425,10 @@ quiet_cmd_lzo_with_size = LZO $@ cmd_lzo_with_size = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@ quiet_cmd_lz4 = LZ4 $@ - cmd_lz4 = cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout > $@ + cmd_lz4 = cat $(real-prereqs) | $(LZ4) -l -9 - - > $@ quiet_cmd_lz4_with_size = LZ4 $@ - cmd_lz4_with_size = { cat $(real-prereqs) | $(LZ4) -l -c1 stdin stdout; \ + cmd_lz4_with_size = { cat $(real-prereqs) | $(LZ4) -l -9 - -; \ $(size_append); } > $@ # U-Boot mkimage diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 1482884ec3ca82..542ba462ed3ec9 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -6,14 +6,12 @@ PHONY := __modfinal __modfinal: -include include/config/auto.conf +include $(objtree)/include/config/auto.conf include $(srctree)/scripts/Kbuild.include - -# for c_flags include $(srctree)/scripts/Makefile.lib # find all modules listed in modules.order -modules := $(call read-file, $(MODORDER)) +modules := $(call read-file, modules.order) __modfinal: $(modules:%.o=%.ko) @: @@ -22,30 +20,27 @@ __modfinal: $(modules:%.o=%.ko) modname = $(notdir $(@:.mod.o=)) part-of-module = y GCOV_PROFILE := n -KCSAN_SANITIZE := n - -quiet_cmd_cc_o_c = CC [M] $@ - cmd_cc_o_c = $(CC) $(filter-out $(CC_FLAGS_CFI), $(c_flags)) -c -o $@ $< +ccflags-remove-y := $(CC_FLAGS_CFI) %.mod.o: %.mod.c FORCE - $(call if_changed_dep,cc_o_c) + $(call if_changed_rule,cc_o_c) -$(extmod_prefix).module-common.o: $(srctree)/scripts/module-common.c FORCE - $(call if_changed_dep,cc_o_c) +.module-common.o: $(srctree)/scripts/module-common.c FORCE + $(call if_changed_rule,cc_o_c) quiet_cmd_ld_ko_o = LD [M] $@ cmd_ld_ko_o = \ $(LD) -r $(KBUILD_LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ - -T scripts/module.lds -o $@ $(filter %.o, $^) + -T $(objtree)/scripts/module.lds -o $@ $(filter %.o, $^) quiet_cmd_btf_ko = BTF [M] $@ cmd_btf_ko = \ - if [ ! -f vmlinux ]; then \ + if [ ! -f $(objtree)/vmlinux ]; then \ printf "Skipping BTF generation for %s due to unavailability of vmlinux\n" $@ 1>&2; \ else \ - LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) $(MODULE_PAHOLE_FLAGS) --btf_base vmlinux $@; \ - $(RESOLVE_BTFIDS) -b vmlinux $@; \ + LLVM_OBJCOPY="$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) $(MODULE_PAHOLE_FLAGS) --btf_base $(objtree)/vmlinux $@; \ + $(RESOLVE_BTFIDS) -b $(objtree)/vmlinux $@; \ fi; # Same as newer-prereqs, but allows to exclude specified extra dependencies @@ -57,13 +52,13 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \ printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) # Re-generate module BTFs if either module's .ko or vmlinux changed -%.ko: %.o %.mod.o $(extmod_prefix).module-common.o scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),vmlinux) FORCE - +$(call if_changed_except,ld_ko_o,vmlinux) +%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE + +$(call if_changed_except,ld_ko_o,$(objtree)/vmlinux) ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) endif -targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) $(extmod_prefix).module-common.o +targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o) .module-common.o # Add FORCE to the prerequisites of a target to force it to be always rebuilt. # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index d977209431898b..f97c9926ed31b2 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst @@ -6,7 +6,7 @@ PHONY := __modinst __modinst: -include include/config/auto.conf +include $(objtree)/include/config/auto.conf include $(srctree)/scripts/Kbuild.include install-y := @@ -40,7 +40,7 @@ $(addprefix $(MODLIB)/, modules.builtin modules.builtin.modinfo modules.builtin. endif -modules := $(call read-file, $(MODORDER)) +modules := $(call read-file, modules.order) ifeq ($(KBUILD_EXTMOD),) dst := $(MODLIB)/kernel @@ -59,7 +59,7 @@ suffix-$(CONFIG_MODULE_COMPRESS_XZ) := .xz suffix-$(CONFIG_MODULE_COMPRESS_ZSTD) := .zst endif -modules := $(patsubst $(extmod_prefix)%.o, $(dst)/%.ko$(suffix-y), $(modules)) +modules := $(patsubst %.o, $(dst)/%.ko$(suffix-y), $(modules)) install-$(CONFIG_MODULES) += $(modules) __modinst: $(install-y) @@ -119,7 +119,7 @@ endif # Create necessary directories $(foreach dir, $(sort $(dir $(install-y))), $(shell mkdir -p $(dir))) -$(dst)/%.ko: $(extmod_prefix)%.ko FORCE +$(dst)/%.ko: %.ko FORCE $(call cmd,install) $(call cmd,strip) $(call cmd,sign) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 44936ebad161e9..ab0e94ea62496e 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -35,10 +35,10 @@ PHONY := __modpost __modpost: -include include/config/auto.conf +include $(objtree)/include/config/auto.conf include $(srctree)/scripts/Kbuild.include -MODPOST = scripts/mod/modpost +MODPOST = $(objtree)/scripts/mod/modpost modpost-args = \ $(if $(CONFIG_MODULES),-M) \ @@ -46,7 +46,7 @@ modpost-args = \ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ $(if $(KBUILD_MODPOST_WARN),-w) \ - $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) \ + $(if $(KBUILD_NSDEPS),-d modules.nsdeps) \ $(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N) \ $(if $(findstring 1, $(KBUILD_EXTRA_WARN)),-W) \ -o $@ @@ -61,8 +61,8 @@ endif # Read out modules.order to pass in modpost. # Otherwise, allmodconfig would fail with "Argument list too long". ifdef KBUILD_MODULES -modpost-args += -T $(MODORDER) -modpost-deps += $(MODORDER) +modpost-args += -T modules.order +modpost-deps += modules.order endif ifeq ($(KBUILD_EXTMOD),) @@ -111,19 +111,19 @@ endif else # set src + obj - they may be used in the modules's Makefile -obj := $(KBUILD_EXTMOD) -src := $(if $(VPATH),$(VPATH)/)$(obj) +obj := . +src := $(srcroot) # Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS include $(kbuild-file) -output-symdump := $(KBUILD_EXTMOD)/Module.symvers +output-symdump := Module.symvers -ifeq ($(wildcard Module.symvers),) -missing-input := Module.symvers +ifeq ($(wildcard $(objtree)/Module.symvers),) +missing-input := $(objtree)/Module.symvers else -modpost-args += -i Module.symvers -modpost-deps += Module.symvers +modpost-args += -i $(objtree)/Module.symvers +modpost-deps += $(objtree)/Module.symvers endif modpost-args += -e $(addprefix -i , $(KBUILD_EXTRA_SYMBOLS)) diff --git a/scripts/Makefile.propeller b/scripts/Makefile.propeller new file mode 100644 index 00000000000000..48a660128e256d --- /dev/null +++ b/scripts/Makefile.propeller @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Enable available and selected Clang Propeller features. +ifdef CLANG_PROPELLER_PROFILE_PREFIX + CFLAGS_PROPELLER_CLANG := -fbasic-block-sections=list=$(CLANG_PROPELLER_PROFILE_PREFIX)_cc_profile.txt -ffunction-sections + KBUILD_LDFLAGS += --symbol-ordering-file=$(CLANG_PROPELLER_PROFILE_PREFIX)_ld_profile.txt --no-warn-symbol-ordering +else + # Starting with Clang v20, the '-fbasic-block-sections=labels' option is + # deprecated. Use the recommended '-fbasic-block-address-map' option. + # Link: https://github.com/llvm/llvm-project/pull/110039 + ifeq ($(call clang-min-version, 200000),y) + CFLAGS_PROPELLER_CLANG := -fbasic-block-address-map + else + CFLAGS_PROPELLER_CLANG := -fbasic-block-sections=labels + endif +endif + +# Propeller requires debug information to embed module names in the profiles. +# If CONFIG_DEBUG_INFO is not enabled, set -gmlt option. Skip this for AutoFDO, +# as the option should already be set. +ifndef CONFIG_DEBUG_INFO + ifndef CONFIG_AUTOFDO_CLANG + CFLAGS_PROPELLER_CLANG += -gmlt + endif +endif + +ifdef CONFIG_LTO_CLANG_THIN + ifdef CLANG_PROPELLER_PROFILE_PREFIX + KBUILD_LDFLAGS += --lto-basic-block-sections=$(CLANG_PROPELLER_PROFILE_PREFIX)_cc_profile.txt + else + ifeq ($(call test-ge, $(CONFIG_LLD_VERSION), 200000),y) + KBUILD_LDFLAGS += --lto-basic-block-address-map + else + KBUILD_LDFLAGS += --lto-basic-block-sections=labels + endif + endif +endif + +export CFLAGS_PROPELLER_CLANG diff --git a/scripts/Makefile.vmlinux b/scripts/Makefile.vmlinux index 1284f05555b97f..873caaa553134e 100644 --- a/scripts/Makefile.vmlinux +++ b/scripts/Makefile.vmlinux @@ -5,23 +5,66 @@ __default: vmlinux include include/config/auto.conf include $(srctree)/scripts/Kbuild.include - -# for c_flags include $(srctree)/scripts/Makefile.lib targets := -quiet_cmd_cc_o_c = CC $@ - cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< - %.o: %.c FORCE - $(call if_changed_dep,cc_o_c) + $(call if_changed_rule,cc_o_c) + +%.o: %.S FORCE + $(call if_changed_rule,as_o_S) + +# Built-in dtb +# --------------------------------------------------------------------------- + +quiet_cmd_wrap_dtbs = WRAP $@ + cmd_wrap_dtbs = { \ + echo '\#include '; \ + echo '.section .dtb.init.rodata,"a"'; \ + while read dtb; do \ + symbase=__dtb_$$(basename -s .dtb "$${dtb}" | tr - _); \ + echo '.balign STRUCT_ALIGNMENT'; \ + echo ".global $${symbase}_begin"; \ + echo "$${symbase}_begin:"; \ + echo '.incbin "'$$dtb'" '; \ + echo ".global $${symbase}_end"; \ + echo "$${symbase}_end:"; \ + done < $<; \ + } > $@ + +.builtin-dtbs.S: .builtin-dtbs-list FORCE + $(call if_changed,wrap_dtbs) + +quiet_cmd_gen_dtbs_list = GEN $@ + cmd_gen_dtbs_list = \ + $(if $(CONFIG_BUILTIN_DTB_NAME), echo "arch/$(SRCARCH)/boot/dts/$(CONFIG_BUILTIN_DTB_NAME).dtb",:) > $@ + +.builtin-dtbs-list: arch/$(SRCARCH)/boot/dts/dtbs-list FORCE + $(call if_changed,$(if $(CONFIG_BUILTIN_DTB_ALL),copy,gen_dtbs_list)) + +targets += .builtin-dtbs-list + +ifdef CONFIG_GENERIC_BUILTIN_DTB +targets += .builtin-dtbs.S .builtin-dtbs.o +vmlinux: .builtin-dtbs.o +endif + +# vmlinux +# --------------------------------------------------------------------------- ifdef CONFIG_MODULES targets += .vmlinux.export.o vmlinux: .vmlinux.export.o endif +ifdef CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX +vmlinux: arch/$(SRCARCH)/tools/vmlinux.arch.o + +arch/$(SRCARCH)/tools/vmlinux.arch.o: vmlinux.o FORCE + $(Q)$(MAKE) $(build)=arch/$(SRCARCH)/tools $@ +endif + ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) # Final link of vmlinux with optional arch pass after final link @@ -32,6 +75,9 @@ cmd_link_vmlinux = \ targets += vmlinux vmlinux: scripts/link-vmlinux.sh vmlinux.o $(KBUILD_LDS) FORCE +$(call if_changed_dep,link_vmlinux) +ifdef CONFIG_DEBUG_INFO_BTF +vmlinux: $(RESOLVE_BTFIDS) +endif # module.builtin.ranges # --------------------------------------------------------------------------- diff --git a/scripts/bpf_doc.py b/scripts/bpf_doc.py index c55878bddfddc4..e74a01a850706d 100755 --- a/scripts/bpf_doc.py +++ b/scripts/bpf_doc.py @@ -37,10 +37,11 @@ class APIElement(object): @desc: textual description of the symbol @ret: (optional) description of any associated return value """ - def __init__(self, proto='', desc='', ret=''): + def __init__(self, proto='', desc='', ret='', attrs=[]): self.proto = proto self.desc = desc self.ret = ret + self.attrs = attrs class Helper(APIElement): @@ -81,6 +82,11 @@ class Helper(APIElement): return res +ATTRS = { + '__bpf_fastcall': 'bpf_fastcall' +} + + class HeaderParser(object): """ An object used to parse a file in order to extract the documentation of a @@ -111,7 +117,8 @@ class HeaderParser(object): proto = self.parse_proto() desc = self.parse_desc(proto) ret = self.parse_ret(proto) - return Helper(proto=proto, desc=desc, ret=ret) + attrs = self.parse_attrs(proto) + return Helper(proto=proto, desc=desc, ret=ret, attrs=attrs) def parse_symbol(self): p = re.compile(r' \* ?(BPF\w+)$') @@ -192,6 +199,28 @@ class HeaderParser(object): raise Exception("No return found for " + proto) return ret + def parse_attrs(self, proto): + p = re.compile(r' \* ?(?:\t| {5,8})Attributes$') + capture = p.match(self.line) + if not capture: + return [] + # Expect a single line with mnemonics for attributes separated by spaces + self.line = self.reader.readline() + p = re.compile(r' \* ?(?:\t| {5,8})(?:\t| {8})(.*)') + capture = p.match(self.line) + if not capture: + raise Exception("Incomplete 'Attributes' section for " + proto) + attrs = capture.group(1).split(' ') + for attr in attrs: + if attr not in ATTRS: + raise Exception("Unexpected attribute '" + attr + "' specified for " + proto) + self.line = self.reader.readline() + if self.line != ' *\n': + raise Exception("Expecting empty line after 'Attributes' section for " + proto) + # Prepare a line for next self.parse_* to consume + self.line = self.reader.readline() + return attrs + def seek_to(self, target, help_message, discard_lines = 1): self.reader.seek(0) offset = self.reader.read().find(target) @@ -789,6 +818,21 @@ class PrinterHelpers(Printer): print('%s;' % fwd) print('') + used_attrs = set() + for helper in self.elements: + for attr in helper.attrs: + used_attrs.add(attr) + for attr in sorted(used_attrs): + print('#ifndef %s' % attr) + print('#if __has_attribute(%s)' % ATTRS[attr]) + print('#define %s __attribute__((%s))' % (attr, ATTRS[attr])) + print('#else') + print('#define %s' % attr) + print('#endif') + print('#endif') + if used_attrs: + print('') + def print_footer(self): footer = '' print(footer) @@ -827,7 +871,10 @@ class PrinterHelpers(Printer): print(' *{}{}'.format(' \t' if line else '', line)) print(' */') - print('static %s %s(* const %s)(' % (self.map_type(proto['ret_type']), + print('static ', end='') + if helper.attrs: + print('%s ' % (" ".join(helper.attrs)), end='') + print('%s %s(* const %s)(' % (self.map_type(proto['ret_type']), proto['ret_star'], proto['name']), end='') comma = '' for i, a in enumerate(proto['args']): diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 4427572b24771d..9eed3683ad76ca 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3209,36 +3209,31 @@ sub process { # Check Fixes: styles is correct if (!$in_header_lines && - $line =~ /^\s*fixes:?\s*(?:commit\s*)?[0-9a-f]{5,}\b/i) { - my $orig_commit = ""; - my $id = "0123456789ab"; - my $title = "commit title"; - my $tag_case = 1; - my $tag_space = 1; - my $id_length = 1; - my $id_case = 1; + $line =~ /^\s*(fixes:?)\s*(?:commit\s*)?([0-9a-f]{5,40})(?:\s*($balanced_parens))?/i) { + my $tag = $1; + my $orig_commit = $2; + my $title; my $title_has_quotes = 0; $fixes_tag = 1; - - if ($line =~ /(\s*fixes:?)\s+([0-9a-f]{5,})\s+($balanced_parens)/i) { - my $tag = $1; - $orig_commit = $2; - $title = $3; - - $tag_case = 0 if $tag eq "Fixes:"; - $tag_space = 0 if ($line =~ /^fixes:? [0-9a-f]{5,} ($balanced_parens)/i); - - $id_length = 0 if ($orig_commit =~ /^[0-9a-f]{12}$/i); - $id_case = 0 if ($orig_commit !~ /[A-F]/); - + if (defined $3) { # Always strip leading/trailing parens then double quotes if existing - $title = substr($title, 1, -1); + $title = substr($3, 1, -1); if ($title =~ /^".*"$/) { $title = substr($title, 1, -1); $title_has_quotes = 1; } + } else { + $title = "commit title" } + + my $tag_case = not ($tag eq "Fixes:"); + my $tag_space = not ($line =~ /^fixes:? [0-9a-f]{5,40} ($balanced_parens)/i); + + my $id_length = not ($orig_commit =~ /^[0-9a-f]{12}$/i); + my $id_case = not ($orig_commit !~ /[A-F]/); + + my $id = "0123456789ab"; my ($cid, $ctitle) = git_commit_info($orig_commit, $id, $title); @@ -6597,11 +6592,11 @@ sub process { # ignore udelay's < 10, however if (! ($delay < 10) ) { CHK("USLEEP_RANGE", - "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst\n" . $herecurr); + "usleep_range is preferred over udelay; see function description of usleep_range() and udelay().\n" . $herecurr); } if ($delay > 2000) { WARN("LONG_UDELAY", - "long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $herecurr); + "long udelay - prefer mdelay; see function description of mdelay().\n" . $herecurr); } } @@ -6609,7 +6604,7 @@ sub process { if ($line =~ /\bmsleep\s*\((\d+)\);/) { if ($1 < 20) { WARN("MSLEEP", - "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.rst\n" . $herecurr); + "msleep < 20ms can sleep for up to 20ms; see function description of msleep().\n" . $herecurr); } } @@ -7077,11 +7072,11 @@ sub process { my $max = $7; if ($min eq $max) { WARN("USLEEP_RANGE", - "usleep_range should not use min == max args; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); + "usleep_range should not use min == max args; see function description of usleep_range().\n" . "$here\n$stat\n"); } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && $min > $max) { WARN("USLEEP_RANGE", - "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.rst\n" . "$here\n$stat\n"); + "usleep_range args reversed, use min then max; see function description of usleep_range().\n" . "$here\n$stat\n"); } } diff --git a/scripts/coccicheck b/scripts/coccicheck index e52cb43fede60f..0e6bc5a10320c9 100755 --- a/scripts/coccicheck +++ b/scripts/coccicheck @@ -80,11 +80,7 @@ command results in a shift count error.' NPROC=1 else ONLINE=0 - if [ "$KBUILD_EXTMOD" = "" ] ; then - OPTIONS="--dir $srctree $COCCIINCLUDE" - else - OPTIONS="--dir $KBUILD_EXTMOD $COCCIINCLUDE" - fi + OPTIONS="--dir $srcroot $COCCIINCLUDE" # Use only one thread per core by default if hyperthreading is enabled THREADS_PER_CORE=$(LANG=C lscpu | grep "Thread(s) per core: " | tr -cd "[:digit:]") diff --git a/scripts/const_structs.checkpatch b/scripts/const_structs.checkpatch index 014b3bfe323748..e8609a03c3d8b5 100644 --- a/scripts/const_structs.checkpatch +++ b/scripts/const_structs.checkpatch @@ -6,6 +6,7 @@ bus_type clk_ops comedi_lrange component_ops +ctl_table dentry_operations dev_pm_ops device_type diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 826836d264c6a5..46fa18b80fc1bc 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -311,7 +311,12 @@ handle_line() { parse_symbol # modifies $symbol # Add up the line number to the symbol - echo "${words[@]}" "$symbol $module" + if [[ -z ${module} ]] + then + echo "${words[@]}" "$symbol" + else + echo "${words[@]}" "$symbol $module" + fi } while read line; do diff --git a/scripts/depmod.sh b/scripts/depmod.sh index e22da27fe13eb3..3c34fecacbc82e 100755 --- a/scripts/depmod.sh +++ b/scripts/depmod.sh @@ -12,7 +12,7 @@ KERNELRELEASE=$1 : ${DEPMOD:=depmod} -if ! test -r System.map ; then +if ! test -r "${objtree}/System.map" ; then echo "Warning: modules_install: missing 'System.map' file. Skipping depmod." >&2 exit 0 fi @@ -25,7 +25,7 @@ if [ -z $(command -v $DEPMOD) ]; then exit 0 fi -set -- -ae -F System.map +set -- -ae -F "${objtree}/System.map" if test -n "$INSTALL_MOD_PATH"; then set -- "$@" -b "$INSTALL_MOD_PATH" fi diff --git a/scripts/export_report.pl b/scripts/export_report.pl deleted file mode 100755 index feb3d5542a62d9..00000000000000 --- a/scripts/export_report.pl +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env perl -# SPDX-License-Identifier: GPL-2.0-only -# -# (C) Copyright IBM Corporation 2006. -# Author : Ram Pai (linuxram@us.ibm.com) -# -# Usage: export_report.pl -k Module.symvers [-o report_file ] -f *.mod.c -# - -use warnings; -use Getopt::Std; -use strict; - -sub numerically { - my $no1 = (split /\s+/, $a)[1]; - my $no2 = (split /\s+/, $b)[1]; - return $no1 <=> $no2; -} - -sub alphabetically { - my ($module1, $value1) = @{$a}; - my ($module2, $value2) = @{$b}; - return $value1 <=> $value2 || $module2 cmp $module1; -} - -sub print_depends_on { - my ($href) = @_; - print "\n"; - for my $mod (sort keys %$href) { - my $list = $href->{$mod}; - print "\t$mod:\n"; - foreach my $sym (sort numerically @{$list}) { - my ($symbol, $no) = split /\s+/, $sym; - printf("\t\t%-25s\n", $symbol); - } - print "\n"; - } - print "\n"; - print "~"x80 , "\n"; -} - -sub usage { - print "Usage: @_ -h -k Module.symvers [ -o outputfile ] \n", - "\t-f: treat all the non-option argument as .mod.c files. ", - "Recommend using this as the last option\n", - "\t-h: print detailed help\n", - "\t-k: the path to Module.symvers file. By default uses ", - "the file from the current directory\n", - "\t-o outputfile: output the report to outputfile\n"; - exit 0; -} - -sub collectcfiles { - my @file; - open my $fh, '< modules.order' or die "cannot open modules.order: $!\n"; - while (<$fh>) { - s/\.ko$/.mod.c/; - push (@file, $_) - } - close($fh); - chomp @file; - return @file; -} - -my (%SYMBOL, %MODULE, %opt, @allcfiles); - -if (not getopts('hk:o:f',\%opt) or defined $opt{'h'}) { - usage($0); -} - -if (defined $opt{'f'}) { - @allcfiles = @ARGV; -} else { - @allcfiles = collectcfiles(); -} - -if (not defined $opt{'k'}) { - $opt{'k'} = "Module.symvers"; -} - -open (my $module_symvers, '<', $opt{'k'}) - or die "Sorry, cannot open $opt{'k'}: $!\n"; - -if (defined $opt{'o'}) { - open (my $out, '>', $opt{'o'}) - or die "Sorry, cannot open $opt{'o'} $!\n"; - - select $out; -} - -# -# collect all the symbols and their attributes from the -# Module.symvers file -# -while ( <$module_symvers> ) { - chomp; - my (undef, $symbol, $module, $gpl, $namespace) = split('\t'); - $SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl]; -} -close($module_symvers); - -# -# collect the usage count of each symbol. -# -my $modversion_warnings = 0; - -foreach my $thismod (@allcfiles) { - my $module; - - unless (open ($module, '<', $thismod)) { - warn "Sorry, cannot open $thismod: $!\n"; - next; - } - - my $state=0; - while ( <$module> ) { - chomp; - if ($state == 0) { - $state = 1 if ($_ =~ /static const struct modversion_info/); - next; - } - if ($state == 1) { - $state = 2 if ($_ =~ /__attribute__\(\(section\("__versions"\)\)\)/); - next; - } - if ($state == 2) { - if ( $_ !~ /0x[0-9a-f]+,/ ) { - next; - } - my $sym = (split /([,"])/,)[4]; - my ($module, $value, $symbol, $gpl) = @{$SYMBOL{$sym}}; - $SYMBOL{ $sym } = [ $module, $value+1, $symbol, $gpl]; - push(@{$MODULE{$thismod}} , $sym); - } - } - if ($state != 2) { - warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n"; - $modversion_warnings++; - } - close($module); -} - -print "\tThis file reports the exported symbols usage patterns by in-tree\n", - "\t\t\t\tmodules\n"; -printf("%s\n\n\n","x"x80); -printf("\t\t\t\tINDEX\n\n\n"); -printf("SECTION 1: Usage counts of all exported symbols\n"); -printf("SECTION 2: List of modules and the exported symbols they use\n"); -printf("%s\n\n\n","x"x80); -printf("SECTION 1:\tThe exported symbols and their usage count\n\n"); -printf("%-25s\t%-25s\t%-5s\t%-25s\n", "Symbol", "Module", "Usage count", - "export type"); - -# -# print the list of unused exported symbols -# -foreach my $list (sort alphabetically values(%SYMBOL)) { - my ($module, $value, $symbol, $gpl) = @{$list}; - printf("%-25s\t%-25s\t%-10s\t", $symbol, $module, $value); - if (defined $gpl) { - printf("%-25s\n",$gpl); - } else { - printf("\n"); - } -} -printf("%s\n\n\n","x"x80); - -printf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel -modules. Each module lists the modules, and the symbols from that module that -it uses. Each listed symbol reports the number of modules using it\n"); - -print "\nNOTE: Got $modversion_warnings CONFIG_MODVERSIONS warnings\n\n" - if $modversion_warnings; - -print "~"x80 , "\n"; -for my $thismod (sort keys %MODULE) { - my $list = $MODULE{$thismod}; - my %depends; - $thismod =~ s/\.mod\.c/.ko/; - print "\t\t\t$thismod\n"; - foreach my $symbol (@{$list}) { - my ($module, $value, undef, $gpl) = @{$SYMBOL{$symbol}}; - push (@{$depends{"$module"}}, "$symbol $value"); - } - print_depends_on(\%depends); -} diff --git a/scripts/faddr2line b/scripts/faddr2line index fe0cc45f03be11..1fa6beef9f978e 100755 --- a/scripts/faddr2line +++ b/scripts/faddr2line @@ -252,7 +252,7 @@ __faddr2line() { found=2 break fi - done < <(echo "${ELF_SYMS}" | sed 's/\[.*\]//' | ${AWK} -v sec=$sym_sec '$7 == sec' | sort --key=2 | ${GREP} -A1 --no-group-separator " ${sym_name}$") + done < <(echo "${ELF_SYMS}" | sed 's/\[.*\]//' | ${AWK} -v sec=$sym_sec '$7 == sec' | sort --key=2) if [[ $found = 0 ]]; then warn "can't find symbol: sym_name: $sym_name sym_sec: $sym_sec sym_addr: $sym_addr sym_elf_size: $sym_elf_size" diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py index 298dfcc25eaea1..fa15f872ddbe8f 100644 --- a/scripts/gdb/linux/modules.py +++ b/scripts/gdb/linux/modules.py @@ -19,6 +19,9 @@ from linux import cpus, utils, lists, constants module_type = utils.CachedType("struct module") +def has_modules(): + return utils.gdb_eval_or_none("modules") is not None + def module_list(): global module_type modules = utils.gdb_eval_or_none("modules") diff --git a/scripts/gdb/linux/symbols.py b/scripts/gdb/linux/symbols.py index e8316beb17a714..f6c1b063775a71 100644 --- a/scripts/gdb/linux/symbols.py +++ b/scripts/gdb/linux/symbols.py @@ -178,6 +178,9 @@ lx-symbols command.""" self.load_all_symbols() + if not modules.has_modules(): + return + if hasattr(gdb, 'Breakpoint'): if self.breakpoint is not None: self.breakpoint.delete() diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index d2bc63cde8c6a3..09e1d166d8d236 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -64,13 +64,6 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): [], ) - append_crate( - "alloc", - sysroot_src / "alloc" / "src" / "lib.rs", - ["core", "compiler_builtins"], - cfg=crates_cfgs.get("alloc", []), - ) - append_crate( "macros", srctree / "rust" / "macros" / "lib.rs", @@ -96,7 +89,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): append_crate( "kernel", srctree / "rust" / "kernel" / "lib.rs", - ["core", "alloc", "macros", "build_error", "bindings"], + ["core", "macros", "build_error", "bindings"], cfg=cfg, ) crates[-1]["source"] = { @@ -133,7 +126,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs): append_crate( name, path, - ["core", "alloc", "kernel"], + ["core", "kernel"], cfg=cfg, ) diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index f3901c55df239d..07f9b8cfb23370 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -632,54 +632,55 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc) void export_symbol(const char *name) { struct symbol *sym; + unsigned long crc; + int has_changed = 0; sym = find_symbol(name, SYM_NORMAL, 0); - if (!sym) + if (!sym) { error_with_pos("export undefined symbol %s", name); - else { - unsigned long crc; - int has_changed = 0; + return; + } - if (flag_dump_defs) - fprintf(debugfile, "Export %s == <", name); + if (flag_dump_defs) + fprintf(debugfile, "Export %s == <", name); - expansion_trail = (struct symbol *)-1L; + expansion_trail = (struct symbol *)-1L; - sym->expansion_trail = expansion_trail; - expansion_trail = sym; - crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff; + sym->expansion_trail = expansion_trail; + expansion_trail = sym; + crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff; - sym = expansion_trail; - while (sym != (struct symbol *)-1L) { - struct symbol *n = sym->expansion_trail; + sym = expansion_trail; + while (sym != (struct symbol *)-1L) { + struct symbol *n = sym->expansion_trail; - if (sym->status != STATUS_UNCHANGED) { - if (!has_changed) { - print_location(); - fprintf(stderr, "%s: %s: modversion " - "changed because of changes " - "in ", flag_preserve ? "error" : - "warning", name); - } else - fprintf(stderr, ", "); - print_type_name(sym->type, sym->name); - if (sym->status == STATUS_DEFINED) - fprintf(stderr, " (became defined)"); - has_changed = 1; - if (flag_preserve) - errors++; + if (sym->status != STATUS_UNCHANGED) { + if (!has_changed) { + print_location(); + fprintf(stderr, + "%s: %s: modversion changed because of changes in ", + flag_preserve ? "error" : "warning", + name); + } else { + fprintf(stderr, ", "); } - sym->expansion_trail = 0; - sym = n; + print_type_name(sym->type, sym->name); + if (sym->status == STATUS_DEFINED) + fprintf(stderr, " (became defined)"); + has_changed = 1; + if (flag_preserve) + errors++; } - if (has_changed) - fprintf(stderr, "\n"); + sym->expansion_trail = 0; + sym = n; + } + if (has_changed) + fprintf(stderr, "\n"); - if (flag_dump_defs) - fputs(">\n", debugfile); + if (flag_dump_defs) + fputs(">\n", debugfile); - printf("#SYMVER %s 0x%08lx\n", name, crc); - } + printf("#SYMVER %s 0x%08lx\n", name, crc); } /*----------------------------------------------------------------------*/ diff --git a/scripts/head-object-list.txt b/scripts/head-object-list.txt index fd5d00bac447da..7274dfc65af606 100644 --- a/scripts/head-object-list.txt +++ b/scripts/head-object-list.txt @@ -23,9 +23,7 @@ arch/m68k/coldfire/head.o arch/m68k/kernel/head.o arch/m68k/kernel/sun3-head.o arch/microblaze/kernel/head.o -arch/mips/kernel/head.o arch/nios2/kernel/head.o -arch/openrisc/kernel/head.o arch/parisc/kernel/head.o arch/powerpc/kernel/head_44x.o arch/powerpc/kernel/head_64.o diff --git a/scripts/ipe/polgen/polgen.c b/scripts/ipe/polgen/polgen.c index c6283b3ff00626..01134cf895d08e 100644 --- a/scripts/ipe/polgen/polgen.c +++ b/scripts/ipe/polgen/polgen.c @@ -61,15 +61,12 @@ static int policy_to_buffer(const char *pathname, char **buffer, size_t *size) static int write_boot_policy(const char *pathname, const char *buf, size_t size) { - int rc = 0; FILE *fd; size_t i; fd = fopen(pathname, "w"); - if (!fd) { - rc = errno; - goto err; - } + if (!fd) + return errno; fprintf(fd, "/* This file is automatically generated."); fprintf(fd, " Do not edit. */\n"); @@ -113,11 +110,6 @@ static int write_boot_policy(const char *pathname, const char *buf, size_t size) fclose(fd); return 0; - -err: - if (fd) - fclose(fd); - return rc; } int main(int argc, const char *const argv[]) diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 3d7d454c54da3c..8abe570419552f 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -628,7 +628,7 @@ static const struct option long_opts[] = { static void conf_usage(const char *progname) { - printf("Usage: %s [options] \n", progname); + printf("Usage: %s [options] kconfig_file\n", progname); printf("\n"); printf("Generic options:\n"); printf(" -h, --help Print this message and exit.\n"); @@ -653,6 +653,9 @@ static void conf_usage(const char *progname) printf(" --mod2yesconfig Change answers from mod to yes if possible\n"); printf(" --mod2noconfig Change answers from mod to no if possible\n"); printf(" (If none of the above is given, --oldaskconfig is the default)\n"); + printf("\n"); + printf("Arguments:\n"); + printf(" kconfig_file Top-level Kconfig file.\n"); } int main(int ac, char **av) diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 63519cd24bc7fa..8914b4e8f2a811 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -34,6 +34,7 @@ bool sym_string_valid(struct symbol *sym, const char *newval); bool sym_string_within_range(struct symbol *sym, const char *str); bool sym_set_string_value(struct symbol *sym, const char *newval); bool sym_is_changeable(const struct symbol *sym); +struct menu *sym_get_prompt_menu(const struct symbol *sym); struct menu *sym_get_choice_menu(const struct symbol *sym); const char * sym_get_string_value(struct symbol *sym); diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 063b4f7ccbdb36..c0b2dabf6c894f 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -467,7 +467,7 @@ static void handle_f9(int *key, struct menu *current_item) return; } -/* return != 0 to indicate the key was handles */ +/* return != 0 to indicate the key was handled */ static int process_special_keys(int *key, struct menu *menu) { int i; diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 72b605efe549d9..4bfdf8ac2a9a34 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -277,6 +277,15 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...) case KEY_RIGHT: menu_driver(menu, REQ_RIGHT_ITEM); break; + case 9: /* TAB */ + if (btn_num > 1) { + /* cycle through buttons */ + if (item_index(current_item(menu)) == btn_num - 1) + menu_driver(menu, REQ_FIRST_ITEM); + else + menu_driver(menu, REQ_NEXT_ITEM); + } + break; case 10: /* ENTER */ case 27: /* ESCAPE */ case ' ': diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index bc43fb67c7c41e..68372d3ff32539 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -24,7 +24,6 @@ int cdebug = PRINTD; static void yyerror(const char *err); -static void zconfprint(const char *err, ...); static void zconf_error(const char *err, ...); static bool zconf_endtoken(const char *tokenname, const char *expected_tokenname); @@ -183,7 +182,7 @@ menuconfig_stmt: menuconfig_entry_start config_option_list if (current_entry->prompt) current_entry->prompt->type = P_MENU; else - zconfprint("warning: menuconfig statement without prompt"); + zconf_error("menuconfig statement without prompt"); printd(DEBUG_PARSE, "%s:%d:endconfig\n", cur_filename, cur_lineno); }; @@ -293,12 +292,6 @@ choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL printd(DEBUG_PARSE, "%s:%d:prompt\n", cur_filename, cur_lineno); }; -choice_option: T_BOOL T_WORD_QUOTE if_expr T_EOL -{ - menu_add_prompt(P_PROMPT, $2, $3); - printd(DEBUG_PARSE, "%s:%d:bool\n", cur_filename, cur_lineno); -}; - choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL { menu_add_symbol(P_DEFAULT, $2, $3); @@ -408,14 +401,14 @@ help: help_start T_HELPTEXT { if (current_entry->help) { free(current_entry->help); - zconfprint("warning: '%s' defined with more than one help text -- only the last one will be used", - current_entry->sym->name ?: ""); + zconf_error("'%s' defined with more than one help text", + current_entry->sym->name ?: ""); } /* Is the help text empty or all whitespace? */ if ($2[strspn($2, " \f\n\r\t\v")] == '\0') - zconfprint("warning: '%s' defined with blank help text", - current_entry->sym->name ?: ""); + zconf_error("'%s' defined with blank help text", + current_entry->sym->name ?: ""); current_entry->help = $2; }; @@ -598,17 +591,6 @@ static bool zconf_endtoken(const char *tokenname, return true; } -static void zconfprint(const char *err, ...) -{ - va_list ap; - - fprintf(stderr, "%s:%d: ", cur_filename, cur_lineno); - va_start(ap, err); - vfprintf(stderr, err, ap); - va_end(ap); - fprintf(stderr, "\n"); -} - static void zconf_error(const char *err, ...) { va_list ap; diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index e260cab1c2afff..6c92ef1e16efb1 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -110,7 +110,7 @@ void ConfigItem::updateMenu(void) if (prop) switch (prop->type) { case P_MENU: - if (list->mode == singleMode || list->mode == symbolMode) { + if (list->mode == singleMode) { /* a menuconfig entry is displayed differently * depending whether it's at the view root or a child. */ @@ -159,7 +159,7 @@ void ConfigItem::updateMenu(void) ch = 'M'; break; default: - if (sym_is_choice_value(sym) && type == S_BOOLEAN) + if (sym_is_choice_value(sym)) setIcon(promptColIdx, choiceNoIcon); else setIcon(promptColIdx, symbolNoIcon); @@ -175,17 +175,16 @@ void ConfigItem::updateMenu(void) setText(dataColIdx, sym_get_string_value(sym)); break; } - if (!sym_has_value(sym) && visible) + if (!sym_has_value(sym)) prompt += " (NEW)"; set_prompt: setText(promptColIdx, prompt); } -void ConfigItem::testUpdateMenu(bool v) +void ConfigItem::testUpdateMenu(void) { ConfigItem* i; - visible = v; if (!menu) return; @@ -307,7 +306,6 @@ ConfigList::ConfigList(QWidget *parent, const char *name) { setObjectName(name); setSortingEnabled(false); - setRootIsDecorated(true); setVerticalScrollMode(ScrollPerPixel); setHorizontalScrollMode(ScrollPerPixel); @@ -430,27 +428,26 @@ void ConfigList::updateList() item = (ConfigItem*)(*it); if (!item->menu) continue; - item->testUpdateMenu(menu_is_visible(item->menu)); + item->testUpdateMenu(); ++it; } return; } - if (rootEntry != &rootmenu && (mode == singleMode || - (mode == symbolMode && rootEntry->parent != &rootmenu))) { + if (rootEntry != &rootmenu && mode == singleMode) { item = (ConfigItem *)topLevelItem(0); if (!item) - item = new ConfigItem(this, 0, true); + item = new ConfigItem(this, 0); last = item; } if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && rootEntry->sym && rootEntry->prompt) { item = last ? last->nextSibling() : nullptr; if (!item) - item = new ConfigItem(this, last, rootEntry, true); + item = new ConfigItem(this, last, rootEntry); else - item->testUpdateMenu(true); + item->testUpdateMenu(); updateMenuList(item, rootEntry); update(); @@ -599,7 +596,6 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu) struct menu* child; ConfigItem* item; ConfigItem* last; - bool visible; enum prop_type type; if (!menu) { @@ -631,14 +627,13 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu) break; } - visible = menu_is_visible(child); if (!menuSkip(child)) { if (!child->sym && !child->list && !child->prompt) continue; if (!item || item->menu != child) - item = new ConfigItem(parent, last, child, visible); + item = new ConfigItem(parent, last, child); else - item->testUpdateMenu(visible); + item->testUpdateMenu(); if (mode == fullMode || mode == menuMode || type != P_MENU) updateMenuList(item, child); @@ -664,7 +659,6 @@ void ConfigList::updateMenuList(struct menu *menu) struct menu* child; ConfigItem* item; ConfigItem* last; - bool visible; enum prop_type type; if (!menu) { @@ -696,14 +690,13 @@ void ConfigList::updateMenuList(struct menu *menu) break; } - visible = menu_is_visible(child); if (!menuSkip(child)) { if (!child->sym && !child->list && !child->prompt) continue; if (!item || item->menu != child) - item = new ConfigItem(this, last, child, visible); + item = new ConfigItem(this, last, child); else - item->testUpdateMenu(visible); + item->testUpdateMenu(); if (mode == fullMode || mode == menuMode || type != P_MENU) updateMenuList(item, child); @@ -731,7 +724,7 @@ void ConfigList::keyPressEvent(QKeyEvent* ev) struct menu *menu; enum prop_type type; - if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { + if (ev->key() == Qt::Key_Escape && mode == singleMode) { emit parentSelected(); ev->accept(); return; @@ -781,13 +774,6 @@ void ConfigList::keyPressEvent(QKeyEvent* ev) ev->accept(); } -void ConfigList::mousePressEvent(QMouseEvent* e) -{ - //QPoint p(contentsToViewport(e->pos())); - //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); - Parent::mousePressEvent(e); -} - void ConfigList::mouseReleaseEvent(QMouseEvent* e) { QPoint p = e->pos(); @@ -834,13 +820,6 @@ skip: Parent::mouseReleaseEvent(e); } -void ConfigList::mouseMoveEvent(QMouseEvent* e) -{ - //QPoint p(contentsToViewport(e->pos())); - //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); - Parent::mouseMoveEvent(e); -} - void ConfigList::mouseDoubleClickEvent(QMouseEvent* e) { QPoint p = e->pos(); @@ -1022,7 +1001,7 @@ void ConfigInfoView::menuInfo(void) if (sym->name) { stream << " ("; if (showDebug()) - stream << "name << "\">"; + stream << "name << "\">"; stream << print_filter(sym->name); if (showDebug()) stream << ""; @@ -1031,7 +1010,7 @@ void ConfigInfoView::menuInfo(void) } else if (sym->name) { stream << ""; if (showDebug()) - stream << "name << "\">"; + stream << "name << "\">"; stream << print_filter(sym->name); if (showDebug()) stream << ""; @@ -1086,9 +1065,9 @@ QString ConfigInfoView::debug_info(struct symbol *sym) switch (prop->type) { case P_PROMPT: case P_MENU: - stream << "prompt: name << "\">"; + stream << "prompt: "; stream << print_filter(prop->text); - stream << "
"; + stream << "
"; break; case P_DEFAULT: case P_SELECT: @@ -1122,28 +1101,19 @@ QString ConfigInfoView::print_filter(const QString &str) { QRegularExpression re("[<>&\"\\n]"); QString res = str; + + QHash patterns; + patterns['<'] = "<"; + patterns['>'] = ">"; + patterns['&'] = "&"; + patterns['"'] = """; + patterns['\n'] = "
"; + for (int i = 0; (i = res.indexOf(re, i)) >= 0;) { - switch (res[i].toLatin1()) { - case '<': - res.replace(i, 1, "<"); - i += 4; - break; - case '>': - res.replace(i, 1, ">"); - i += 4; - break; - case '&': - res.replace(i, 1, "&"); - i += 5; - break; - case '"': - res.replace(i, 1, """); - i += 6; - break; - case '\n': - res.replace(i, 1, "
"); - i += 4; - break; + const QString n = patterns.value(res[i], QString()); + if (!n.isEmpty()) { + res.replace(i, 1, n); + i += n.length(); } } return res; @@ -1154,7 +1124,7 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char QTextStream *stream = reinterpret_cast(data); if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { - *stream << "name << "\">"; + *stream << "name << "\">"; *stream << print_filter(str); *stream << ""; } else { @@ -1164,39 +1134,11 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char void ConfigInfoView::clicked(const QUrl &url) { - QByteArray str = url.toEncoded(); - const std::size_t count = str.size(); - char *data = new char[count + 2]; // '$' + '\0' - struct symbol **result; - struct menu *m = NULL; - - if (count < 1) { - delete[] data; - return; - } - - memcpy(data, str.constData(), count); - data[count] = '\0'; - - /* Seek for exact match */ - data[0] = '^'; - strcat(data, "$"); - result = sym_re_search(data); - if (!result) { - delete[] data; - return; - } + struct menu *m; - sym = *result; - - /* Seek for the menu which holds the symbol */ - for (struct property *prop = sym->prop; prop; prop = prop->next) { - if (prop->type != P_PROMPT && prop->type != P_MENU) - continue; - m = prop->menu; - break; - } + sym = sym_find(url.toEncoded().constData()); + m = sym_get_prompt_menu(sym); if (!m) { /* Symbol is not visible as a menu */ symbolInfo(); @@ -1204,9 +1146,6 @@ void ConfigInfoView::clicked(const QUrl &url) } else { emit menuSelected(m); } - - free(result); - delete[] data; } void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event) @@ -1240,8 +1179,7 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent) layout2->addWidget(searchButton); layout1->addLayout(layout2); - split = new QSplitter(this); - split->setOrientation(Qt::Vertical); + split = new QSplitter(Qt::Vertical, this); list = new ConfigList(split, "search"); list->mode = listMode; info = new ConfigInfoView(split, "search"); @@ -1300,8 +1238,7 @@ void ConfigSearchWindow::search(void) return; for (p = result; *p; p++) { for_all_prompts((*p), prop) - lastItem = new ConfigItem(list, lastItem, prop->menu, - menu_is_visible(prop->menu)); + lastItem = new ConfigItem(list, lastItem, prop->menu); } } @@ -1341,61 +1278,56 @@ ConfigMainWindow::ConfigMainWindow(void) ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback)); QWidget *widget = new QWidget(this); - QVBoxLayout *layout = new QVBoxLayout(widget); setCentralWidget(widget); - split1 = new QSplitter(widget); - split1->setOrientation(Qt::Horizontal); - split1->setChildrenCollapsible(false); - - menuList = new ConfigList(widget, "menu"); + QVBoxLayout *layout = new QVBoxLayout(widget); - split2 = new QSplitter(widget); + split2 = new QSplitter(Qt::Vertical, widget); + layout->addWidget(split2); split2->setChildrenCollapsible(false); - split2->setOrientation(Qt::Vertical); - // create config tree - configList = new ConfigList(widget, "config"); + split1 = new QSplitter(Qt::Horizontal, split2); + split1->setChildrenCollapsible(false); - helpText = new ConfigInfoView(widget, "help"); + configList = new ConfigList(split1, "config"); - layout->addWidget(split2); - split2->addWidget(split1); - split1->addWidget(configList); - split1->addWidget(menuList); - split2->addWidget(helpText); + menuList = new ConfigList(split1, "menu"); + helpText = new ConfigInfoView(split2, "help"); setTabOrder(configList, helpText); + configList->setFocus(); backAction = new QAction(QPixmap(xpm_back), "Back", this); + backAction->setShortcut(QKeySequence::Back); connect(backAction, &QAction::triggered, this, &ConfigMainWindow::goBack); QAction *quitAction = new QAction("&Quit", this); - quitAction->setShortcut(Qt::CTRL | Qt::Key_Q); + quitAction->setShortcut(QKeySequence::Quit); connect(quitAction, &QAction::triggered, this, &ConfigMainWindow::close); - QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this); - loadAction->setShortcut(Qt::CTRL | Qt::Key_L); + QAction *loadAction = new QAction(QPixmap(xpm_load), "&Open", this); + loadAction->setShortcut(QKeySequence::Open); connect(loadAction, &QAction::triggered, this, &ConfigMainWindow::loadConfig); saveAction = new QAction(QPixmap(xpm_save), "&Save", this); - saveAction->setShortcut(Qt::CTRL | Qt::Key_S); + saveAction->setShortcut(QKeySequence::Save); connect(saveAction, &QAction::triggered, this, &ConfigMainWindow::saveConfig); conf_set_changed_callback(conf_changed); - configname = xstrdup(conf_get_configname()); + configname = conf_get_configname(); QAction *saveAsAction = new QAction("Save &As...", this); + saveAsAction->setShortcut(QKeySequence::SaveAs); connect(saveAsAction, &QAction::triggered, this, &ConfigMainWindow::saveConfigAs); QAction *searchAction = new QAction("&Find", this); - searchAction->setShortcut(Qt::CTRL | Qt::Key_F); + searchAction->setShortcut(QKeySequence::Find); connect(searchAction, &QAction::triggered, this, &ConfigMainWindow::searchConfig); singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this); @@ -1505,6 +1437,9 @@ ConfigMainWindow::ConfigMainWindow(void) connect(helpText, &ConfigInfoView::menuSelected, this, &ConfigMainWindow::setMenuLink); + connect(configApp, &QApplication::aboutToQuit, + this, &ConfigMainWindow::saveSettings); + conf_read(NULL); QString listMode = configSettings->value("/listMode", "symbol").toString(); @@ -1528,28 +1463,22 @@ ConfigMainWindow::ConfigMainWindow(void) void ConfigMainWindow::loadConfig(void) { QString str; - QByteArray ba; - const char *name; str = QFileDialog::getOpenFileName(this, "", configname); if (str.isNull()) return; - ba = str.toLocal8Bit(); - name = ba.data(); - - if (conf_read(name)) + if (conf_read(str.toLocal8Bit().constData())) QMessageBox::information(this, "qconf", "Unable to load configuration!"); - free(configname); - configname = xstrdup(name); + configname = str; ConfigList::updateListAllForAll(); } bool ConfigMainWindow::saveConfig(void) { - if (conf_write(configname)) { + if (conf_write(configname.toLocal8Bit().constData())) { QMessageBox::information(this, "qconf", "Unable to save configuration!"); return false; } @@ -1561,23 +1490,17 @@ bool ConfigMainWindow::saveConfig(void) void ConfigMainWindow::saveConfigAs(void) { QString str; - QByteArray ba; - const char *name; str = QFileDialog::getSaveFileName(this, "", configname); if (str.isNull()) return; - ba = str.toLocal8Bit(); - name = ba.data(); - - if (conf_write(name)) { + if (conf_write(str.toLocal8Bit().constData())) { QMessageBox::information(this, "qconf", "Unable to save configuration!"); } conf_write_autoconf(0); - free(configname); - configname = xstrdup(name); + configname = str; } void ConfigMainWindow::searchConfig(void) @@ -1662,9 +1585,6 @@ void ConfigMainWindow::listFocusChanged(void) void ConfigMainWindow::goBack(void) { - if (configList->rootEntry == &rootmenu) - return; - configList->setParentMenu(); } @@ -1905,8 +1825,6 @@ int main(int ac, char** av) v = new ConfigMainWindow(); //zconfdump(stdout); - configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); - configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); v->show(); configApp->exec(); diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h index 53373064d90ace..62ab3286d04f75 100644 --- a/scripts/kconfig/qconf.h +++ b/scripts/kconfig/qconf.h @@ -55,9 +55,7 @@ class ConfigList : public QTreeWidget { protected: void keyPressEvent(QKeyEvent *e); - void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); - void mouseMoveEvent(QMouseEvent *e); void mouseDoubleClickEvent(QMouseEvent *e); void focusInEvent(QFocusEvent *e); void contextMenuEvent(QContextMenuEvent *e); @@ -116,25 +114,25 @@ public slots: class ConfigItem : public QTreeWidgetItem { typedef class QTreeWidgetItem Parent; public: - ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool v) - : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false) + ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m) + : Parent(parent, after), nextItem(0), menu(m), goParent(false) { init(); } - ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v) - : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false) + ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m) + : Parent(parent, after), nextItem(0), menu(m), goParent(false) { init(); } - ConfigItem(ConfigList *parent, ConfigItem *after, bool v) - : Parent(parent, after), nextItem(0), menu(0), visible(v), goParent(true) + ConfigItem(ConfigList *parent, ConfigItem *after) + : Parent(parent, after), nextItem(0), menu(0), goParent(true) { init(); } ~ConfigItem(void); void init(void); void updateMenu(void); - void testUpdateMenu(bool v); + void testUpdateMenu(void); ConfigList* listView() const { return (ConfigList*)Parent::treeWidget(); @@ -161,7 +159,6 @@ class ConfigItem : public QTreeWidgetItem { ConfigItem* nextItem; struct menu *menu; - bool visible; bool goParent; static QIcon symbolYesIcon, symbolModIcon, symbolNoIcon; @@ -237,7 +234,7 @@ public slots: class ConfigMainWindow : public QMainWindow { Q_OBJECT - char *configname; + QString configname; static QAction *saveAction; static void conf_changed(bool); public: diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index d51cd7ac15d2ce..8e23faab5d2277 100755 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -144,6 +144,7 @@ my %selects; my %prompts; my %objects; my %config2kfile; +my %defaults; my $var; my $iflevel = 0; my @ifdeps; @@ -220,8 +221,9 @@ sub read_kconfig { $depends{$config} = $1; } elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) { $depends{$config} .= " " . $1; - } elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) { + } elsif ($state ne "NONE" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) { my $dep = $3; + $defaults{$config} = 1; if ($dep !~ /^\s*(y|m|n)\s*$/) { $dep =~ s/.*\sif\s+//; $depends{$config} .= " " . $dep; @@ -503,7 +505,7 @@ sub parse_config_selects # Check if something other than a module selects this config if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") { - dprint "$conf (non module) selects config, we are good\n"; + dprint "$conf (non module) selects $config, we are good\n"; # we are good with this return; } @@ -523,8 +525,16 @@ sub parse_config_selects # If no possible config selected this, then something happened. if (!defined($next_config)) { - print STDERR "WARNING: $config is required, but nothing in the\n"; - print STDERR " current config selects it.\n"; + + # Some config options have no prompt, and nothing selects them, but + # they stay turned on once the final checks for the configs + # are done. These configs have a default option, so turn off the + # warnings for configs with default options. + if (!defined($defaults{$config})) { + print STDERR "WARNING: $config is required, but nothing in the\n"; + print STDERR " current config selects it.\n"; + } + return; } diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index a3af93aaaf32af..89b84bf8e21fa6 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -70,6 +70,24 @@ const char *sym_type_name(enum symbol_type type) return "???"; } +/** + * sym_get_prompt_menu - get the menu entry with a prompt + * + * @sym: a symbol pointer + * + * Return: the menu entry with a prompt. + */ +struct menu *sym_get_prompt_menu(const struct symbol *sym) +{ + struct menu *m; + + list_for_each_entry(m, &sym->menus, link) + if (m->prompt) + return m; + + return NULL; +} + /** * sym_get_choice_menu - get the parent choice menu if present * @@ -80,18 +98,12 @@ const char *sym_type_name(enum symbol_type type) struct menu *sym_get_choice_menu(const struct symbol *sym) { struct menu *menu = NULL; - struct menu *m; /* * Choice members must have a prompt. Find a menu entry with a prompt, * and assume it resides inside a choice block. */ - list_for_each_entry(m, &sym->menus, link) - if (m->prompt) { - menu = m; - break; - } - + menu = sym_get_prompt_menu(sym); if (!menu) return NULL; diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 2791f819520387..4ee843d3600e22 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -160,7 +160,7 @@ my @export_file_list; my @build_time; if (defined($ENV{'KBUILD_BUILD_TIMESTAMP'}) && - (my $seconds = `date -d"${ENV{'KBUILD_BUILD_TIMESTAMP'}}" +%s`) ne '') { + (my $seconds = `date -d "${ENV{'KBUILD_BUILD_TIMESTAMP'}}" +%s`) ne '') { @build_time = gmtime($seconds); } else { @build_time = localtime; @@ -267,7 +267,7 @@ my $doc_inline_sect = '\s*\*\s*(@\s*[\w][\w\.]*\s*):(.*)'; my $doc_inline_end = '^\s*\*/\s*$'; my $doc_inline_oneline = '^\s*/\*\*\s*(@[\w\s]+):\s*(.*)\s*\*/\s*$'; my $export_symbol = '^\s*EXPORT_SYMBOL(_GPL)?\s*\(\s*(\w+)\s*\)\s*;'; -my $export_symbol_ns = '^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*\w+\)\s*;'; +my $export_symbol_ns = '^\s*EXPORT_SYMBOL_NS(_GPL)?\s*\(\s*(\w+)\s*,\s*"\S+"\)\s*;'; my $function_pointer = qr{([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)}; my $attribute = qr{__attribute__\s*\(\([a-z0-9,_\*\s\(\)]*\)\)}i; @@ -569,6 +569,8 @@ sub output_function_man(%) { my %args = %{$_[0]}; my ($parameter, $section); my $count; + my $func_macro = $args{'func_macro'}; + my $paramcount = $#{$args{'parameterlist'}}; # -1 is empty print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Kernel Hacker's Manual\" LINUX\n"; @@ -600,7 +602,10 @@ sub output_function_man(%) { $parenth = ""; } - print ".SH ARGUMENTS\n"; + $paramcount = $#{$args{'parameterlist'}}; # -1 is empty + if ($paramcount >= 0) { + print ".SH ARGUMENTS\n"; + } foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; @@ -822,10 +827,16 @@ sub output_function_rst(%) { my $oldprefix = $lineprefix; my $signature = ""; - if ($args{'functiontype'} ne "") { - $signature = $args{'functiontype'} . " " . $args{'function'} . " ("; - } else { - $signature = $args{'function'} . " ("; + my $func_macro = $args{'func_macro'}; + my $paramcount = $#{$args{'parameterlist'}}; # -1 is empty + + if ($func_macro) { + $signature = $args{'function'}; + } else { + if ($args{'functiontype'}) { + $signature = $args{'functiontype'} . " "; + } + $signature .= $args{'function'} . " ("; } my $count = 0; @@ -844,7 +855,9 @@ sub output_function_rst(%) { } } - $signature .= ")"; + if (!$func_macro) { + $signature .= ")"; + } if ($sphinx_major < 3) { if ($args{'typedef'}) { @@ -888,9 +901,11 @@ sub output_function_rst(%) { # Put our descriptive text into a container (thus an HTML
) to help # set the function prototypes apart. # - print ".. container:: kernelindent\n\n"; $lineprefix = " "; - print $lineprefix . "**Parameters**\n\n"; + if ($paramcount >= 0) { + print ".. container:: kernelindent\n\n"; + print $lineprefix . "**Parameters**\n\n"; + } foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; @@ -1704,7 +1719,7 @@ sub check_return_section { sub dump_function($$) { my $prototype = shift; my $file = shift; - my $noret = 0; + my $func_macro = 0; print_lineno($new_start_line); @@ -1769,7 +1784,7 @@ sub dump_function($$) { # declaration_name and opening parenthesis (notice the \s+). $return_type = $1; $declaration_name = $2; - $noret = 1; + $func_macro = 1; } elsif ($prototype =~ m/^()($name)\s*$prototype_end/ || $prototype =~ m/^($type1)\s+($name)\s*$prototype_end/ || $prototype =~ m/^($type2+)\s*($name)\s*$prototype_end/) { @@ -1796,7 +1811,7 @@ sub dump_function($$) { # of warnings goes sufficiently down, the check is only performed in # -Wreturn mode. # TODO: always perform the check. - if ($Wreturn && !$noret) { + if ($Wreturn && !$func_macro) { check_return_section($file, $declaration_name, $return_type); } @@ -1814,7 +1829,8 @@ sub dump_function($$) { 'parametertypes' => \%parametertypes, 'sectionlist' => \@sectionlist, 'sections' => \%sections, - 'purpose' => $declaration_purpose + 'purpose' => $declaration_purpose, + 'func_macro' => $func_macro }); } else { output_declaration($declaration_name, @@ -1827,7 +1843,8 @@ sub dump_function($$) { 'parametertypes' => \%parametertypes, 'sectionlist' => \@sectionlist, 'sections' => \%sections, - 'purpose' => $declaration_purpose + 'purpose' => $declaration_purpose, + 'func_macro' => $func_macro }); } } @@ -2322,7 +2339,6 @@ sub process_inline($$) { sub process_file($) { my $file; - my $initial_section_counter = $section_counter; my ($orig_file) = @_; $file = map_filename($orig_file); @@ -2360,8 +2376,7 @@ sub process_file($) { } # Make sure we got something interesting. - if ($initial_section_counter == $section_counter && $ - output_mode ne "none") { + if (!$section_counter && $output_mode ne "none") { if ($output_selection == OUTPUT_INCLUDE) { emit_warning("${file}:1", "'$_' not found\n") for keys %function_table; diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index a9b3f34a78d2cd..d853ddb3b28c12 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -68,6 +68,10 @@ vmlinux_link() libs="${KBUILD_VMLINUX_LIBS}" fi + if is_enabled CONFIG_GENERIC_BUILTIN_DTB; then + objs="${objs} .builtin-dtbs.o" + fi + if is_enabled CONFIG_MODULES; then objs="${objs} .vmlinux.export.o" fi @@ -100,7 +104,7 @@ vmlinux_link() ${ld} ${ldflags} -o ${output} \ ${wl}--whole-archive ${objs} ${wl}--no-whole-archive \ ${wl}--start-group ${libs} ${wl}--end-group \ - ${kallsymso} ${btf_vmlinux_bin_o} ${ldlibs} + ${kallsymso} ${btf_vmlinux_bin_o} ${arch_vmlinux_o} ${ldlibs} } # generate .BTF typeinfo from DWARF debuginfo @@ -198,13 +202,18 @@ fi ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init init/version-timestamp.o +arch_vmlinux_o= +if is_enabled CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX; then + arch_vmlinux_o=arch/${SRCARCH}/tools/vmlinux.arch.o +fi + btf_vmlinux_bin_o= kallsymso= strip_debug= if is_enabled CONFIG_KALLSYMS; then - true > .tmp_vmlinux.kallsyms0.syms - kallsyms .tmp_vmlinux.kallsyms0.syms .tmp_vmlinux0.kallsyms + true > .tmp_vmlinux0.syms + kallsyms .tmp_vmlinux0.syms .tmp_vmlinux0.kallsyms fi if is_enabled CONFIG_KALLSYMS || is_enabled CONFIG_DEBUG_INFO_BTF; then @@ -231,14 +240,14 @@ if is_enabled CONFIG_KALLSYMS; then # Generate section listing all symbols and add it into vmlinux # It's a four step process: # 0) Generate a dummy __kallsyms with empty symbol list. - # 1) Link .tmp_vmlinux.kallsyms1 so it has all symbols and sections, + # 1) Link .tmp_vmlinux1.kallsyms so it has all symbols and sections, # with a dummy __kallsyms. - # Running kallsyms on that gives us .tmp_kallsyms1.o with + # Running kallsyms on that gives us .tmp_vmlinux1.kallsyms.o with # the right size - # 2) Link .tmp_vmlinux.kallsyms2 so it now has a __kallsyms section of + # 2) Link .tmp_vmlinux2.kallsyms so it now has a __kallsyms section of # the right size, but due to the added section, some # addresses have shifted. - # From here, we generate a correct .tmp_vmlinux.kallsyms2.o + # From here, we generate a correct .tmp_vmlinux2.kallsyms.o # 3) That link may have expanded the kernel image enough that # more linker branch stubs / trampolines had to be added, which # introduces new names, which further expands kallsyms. Do another diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index c4cc11aa558f5f..5b5745f00eb306 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -10,6 +10,12 @@ * of the GNU General Public License, incorporated herein by reference. */ +#include +#include + +#include "list.h" +#include "xalloc.h" + #include "modpost.h" #include "devicetable-offsets.h" @@ -31,6 +37,66 @@ typedef Elf64_Addr kernel_ulong_t; #include #include +/** + * module_alias_printf - add auto-generated MODULE_ALIAS() + * + * @mod: module + * @append_wildcard: append '*' for future extension if not exist yet + * @fmt: printf(3)-like format + */ +static void __attribute__((format (printf, 3, 4))) +module_alias_printf(struct module *mod, bool append_wildcard, + const char *fmt, ...) +{ + struct module_alias *new, *als; + size_t len; + int n; + va_list ap; + + /* Determine required size. */ + va_start(ap, fmt); + n = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + if (n < 0) { + error("vsnprintf failed\n"); + return; + } + + len = n + 1; /* extra byte for '\0' */ + + if (append_wildcard) + len++; /* extra byte for '*' */ + + new = xmalloc(sizeof(*new) + len); + + /* Now, really print it to the allocated buffer */ + va_start(ap, fmt); + n = vsnprintf(new->str, len, fmt, ap); + va_end(ap); + + if (n < 0) { + error("vsnprintf failed\n"); + free(new); + return; + } + + if (append_wildcard && (n == 0 || new->str[n - 1] != '*')) { + new->str[n] = '*'; + new->str[n + 1] = '\0'; + } + + /* avoid duplication */ + list_for_each_entry(als, &mod->aliases, node) { + if (!strcmp(als->str, new->str)) { + free(new); + return; + } + } + + list_add_tail(&new->node, &mod->aliases); +} + typedef uint32_t __u32; typedef uint16_t __u16; typedef unsigned char __u8; @@ -56,35 +122,24 @@ typedef struct { * we handle those differences explicitly below */ #include "../../include/linux/mod_devicetable.h" -/* This array collects all instances that use the generic do_table */ struct devtable { - const char *device_id; /* name of table, __mod___*_device_table. */ + const char *device_id; unsigned long id_size; - int (*do_entry)(const char *filename, void *symval, char *alias); + void (*do_entry)(struct module *mod, void *symval); }; -/* Size of alias provided to do_entry functions */ -#define ALIAS_SIZE 500 - /* Define a variable f that holds the value of field f of struct devid * based at address m. */ #define DEF_FIELD(m, devid, f) \ typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f)) -/* Define a variable v that holds the address of field f of struct devid - * based at address m. Due to the way typeof works, for a field of type - * T[N] the variable has type T(*)[N], _not_ T*. - */ -#define DEF_FIELD_ADDR_VAR(m, devid, f, v) \ - typeof(((struct devid *)0)->f) *v = ((m) + OFF_##devid##_##f) - /* Define a variable f that holds the address of field f of struct devid * based at address m. Due to the way typeof works, for a field of type * T[N] the variable has type T(*)[N], _not_ T*. */ #define DEF_FIELD_ADDR(m, devid, f) \ - DEF_FIELD_ADDR_VAR(m, devid, f, f) + typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) #define ADD(str, sep, cond, field) \ do { \ @@ -99,15 +154,6 @@ do { \ sprintf(str + strlen(str), "*"); \ } while(0) -/* End in a wildcard, for future extension */ -static inline void add_wildcard(char *str) -{ - int len = strlen(str); - - if (str[len - 1] != '*') - strcat(str + len, "*"); -} - static inline void add_uuid(char *str, uuid_le uuid) { int len = strlen(str); @@ -130,40 +176,6 @@ static inline void add_guid(char *str, guid_t guid) guid.b[12], guid.b[13], guid.b[14], guid.b[15]); } -/** - * Check that sizeof(device_id type) are consistent with size of section - * in .o file. If in-consistent then userspace and kernel does not agree - * on actual size which is a bug. - * Also verify that the final entry in the table is all zeros. - * Ignore both checks if build host differ from target host and size differs. - **/ -static void device_id_check(const char *modname, const char *device_id, - unsigned long size, unsigned long id_size, - void *symval) -{ - int i; - - if (size % id_size || size < id_size) { - fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo of the size of section __mod_%s___device_table=%lu.\n" - "Fix definition of struct %s_device_id in mod_devicetable.h\n", - modname, device_id, id_size, device_id, size, device_id); - } - /* Verify last one is a terminator */ - for (i = 0; i < id_size; i++ ) { - if (*(uint8_t*)(symval+size-id_size+i)) { - fprintf(stderr, - "%s: struct %s_device_id is %lu bytes. The last of %lu is:\n", - modname, device_id, id_size, size / id_size); - for (i = 0; i < id_size; i++ ) - fprintf(stderr,"0x%02x ", - *(uint8_t*)(symval+size-id_size+i) ); - fprintf(stderr,"\n"); - fatal("%s: struct %s_device_id is not terminated with a NULL entry!\n", - modname, device_id); - } - } -} - /* USB is special because the bcdDevice can be matched against a numeric range */ /* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ static void do_usb_entry(void *symval, @@ -229,9 +241,7 @@ static void do_usb_entry(void *symval, ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER, bInterfaceNumber); - add_wildcard(alias); - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"%s\");\n", alias); + module_alias_printf(mod, true, "%s", alias); } /* Handles increment/decrement of BCD formatted integers */ @@ -273,7 +283,7 @@ static unsigned int incbcd(unsigned int *bcd, return init; } -static void do_usb_entry_multi(void *symval, struct module *mod) +static void do_usb_entry_multi(struct module *mod, void *symval) { unsigned int devlo, devhi; unsigned char chi, clo, max; @@ -338,22 +348,7 @@ static void do_usb_entry_multi(void *symval, struct module *mod) } } -static void do_usb_table(void *symval, unsigned long size, - struct module *mod) -{ - unsigned int i; - const unsigned long id_size = SIZE_usb_device_id; - - device_id_check(mod->name, "usb", size, id_size, symval); - - /* Leave last one: it's the terminator. */ - size -= id_size; - - for (i = 0; i < size; i += id_size) - do_usb_entry_multi(symval + i, mod); -} - -static void do_of_entry_multi(void *symval, struct module *mod) +static void do_of_entry(struct module *mod, void *symval) { char alias[500]; int len; @@ -375,56 +370,39 @@ static void do_of_entry_multi(void *symval, struct module *mod) if (isspace(*tmp)) *tmp = '_'; - buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias); - strcat(alias, "C"); - add_wildcard(alias); - buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias); -} - -static void do_of_table(void *symval, unsigned long size, - struct module *mod) -{ - unsigned int i; - const unsigned long id_size = SIZE_of_device_id; - - device_id_check(mod->name, "of", size, id_size, symval); - - /* Leave last one: it's the terminator. */ - size -= id_size; - - for (i = 0; i < size; i += id_size) - do_of_entry_multi(symval + i, mod); + module_alias_printf(mod, false, "%s", alias); + module_alias_printf(mod, false, "%sC*", alias); } /* Looks like: hid:bNvNpN */ -static int do_hid_entry(const char *filename, - void *symval, char *alias) +static void do_hid_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, hid_device_id, bus); DEF_FIELD(symval, hid_device_id, group); DEF_FIELD(symval, hid_device_id, vendor); DEF_FIELD(symval, hid_device_id, product); - sprintf(alias, "hid:"); ADD(alias, "b", bus != HID_BUS_ANY, bus); ADD(alias, "g", group != HID_GROUP_ANY, group); ADD(alias, "v", vendor != HID_ANY_ID, vendor); ADD(alias, "p", product != HID_ANY_ID, product); - return 1; + module_alias_printf(mod, false, "hid:%s", alias); } /* Looks like: ieee1394:venNmoNspNverN */ -static int do_ieee1394_entry(const char *filename, - void *symval, char *alias) +static void do_ieee1394_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, ieee1394_device_id, match_flags); DEF_FIELD(symval, ieee1394_device_id, vendor_id); DEF_FIELD(symval, ieee1394_device_id, model_id); DEF_FIELD(symval, ieee1394_device_id, specifier_id); DEF_FIELD(symval, ieee1394_device_id, version); - strcpy(alias, "ieee1394:"); ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID, vendor_id); ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID, @@ -434,14 +412,13 @@ static int do_ieee1394_entry(const char *filename, ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION, version); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "ieee1394:%s", alias); } /* Looks like: pci:vNdNsvNsdNbcNscNiN or _pci:vNdNsvNsdNbcNscNiN. */ -static int do_pci_entry(const char *filename, - void *symval, char *alias) +static void do_pci_entry(struct module *mod, void *symval) { + char alias[256]; /* Class field can be divided into these three. */ unsigned char baseclass, subclass, interface, baseclass_mask, subclass_mask, interface_mask; @@ -464,7 +441,6 @@ static int do_pci_entry(const char *filename, default: warn("Unknown PCI driver_override alias %08X\n", override_only); - return 0; } ADD(alias, "v", vendor != PCI_ANY_ID, vendor); @@ -483,28 +459,28 @@ static int do_pci_entry(const char *filename, || (subclass_mask != 0 && subclass_mask != 0xFF) || (interface_mask != 0 && interface_mask != 0xFF)) { warn("Can't handle masks in %s:%04X\n", - filename, class_mask); - return 0; + mod->name, class_mask); + return; } ADD(alias, "bc", baseclass_mask == 0xFF, baseclass); ADD(alias, "sc", subclass_mask == 0xFF, subclass); ADD(alias, "i", interface_mask == 0xFF, interface); - add_wildcard(alias); - return 1; + + module_alias_printf(mod, true, "%s", alias); } /* looks like: "ccw:tNmNdtNdmN" */ -static int do_ccw_entry(const char *filename, - void *symval, char *alias) +static void do_ccw_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, ccw_device_id, match_flags); DEF_FIELD(symval, ccw_device_id, cu_type); DEF_FIELD(symval, ccw_device_id, cu_model); DEF_FIELD(symval, ccw_device_id, dev_type); DEF_FIELD(symval, ccw_device_id, dev_model); - strcpy(alias, "ccw:"); ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, cu_type); ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, @@ -513,47 +489,42 @@ static int do_ccw_entry(const char *filename, dev_type); ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, dev_model); - add_wildcard(alias); - return 1; + + module_alias_printf(mod, true, "ccw:%s", alias); } /* looks like: "ap:tN" */ -static int do_ap_entry(const char *filename, - void *symval, char *alias) +static void do_ap_entry(struct module *mod, void *symval) { DEF_FIELD(symval, ap_device_id, dev_type); - sprintf(alias, "ap:t%02X*", dev_type); - return 1; + module_alias_printf(mod, false, "ap:t%02X*", dev_type); } /* looks like: "css:tN" */ -static int do_css_entry(const char *filename, - void *symval, char *alias) +static void do_css_entry(struct module *mod, void *symval) { DEF_FIELD(symval, css_device_id, type); - sprintf(alias, "css:t%01X", type); - return 1; + module_alias_printf(mod, false, "css:t%01X", type); } /* Looks like: "serio:tyNprNidNexN" */ -static int do_serio_entry(const char *filename, - void *symval, char *alias) +static void do_serio_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, serio_device_id, type); DEF_FIELD(symval, serio_device_id, proto); DEF_FIELD(symval, serio_device_id, id); DEF_FIELD(symval, serio_device_id, extra); - strcpy(alias, "serio:"); ADD(alias, "ty", type != SERIO_ANY, type); ADD(alias, "pr", proto != SERIO_ANY, proto); ADD(alias, "id", id != SERIO_ANY, id); ADD(alias, "ex", extra != SERIO_ANY, extra); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "serio:%s", alias); } /* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or @@ -563,21 +534,19 @@ static int do_serio_entry(const char *filename, * or _CLS. Also, bb, ss, and pp can be substituted with ?? * as don't care byte. */ -static int do_acpi_entry(const char *filename, - void *symval, char *alias) +static void do_acpi_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, acpi_device_id, id); DEF_FIELD(symval, acpi_device_id, cls); DEF_FIELD(symval, acpi_device_id, cls_msk); - if (id && strlen((const char *)*id)) - sprintf(alias, "acpi*:%s:*", *id); + if ((*id)[0]) + module_alias_printf(mod, false, "acpi*:%s:*", *id); else { + char alias[256]; int i, byte_shift, cnt = 0; unsigned int msk; - sprintf(&alias[cnt], "acpi*:"); - cnt = 6; for (i = 1; i <= 3; i++) { byte_shift = 8 * (3-i); msk = (cls_msk >> byte_shift) & 0xFF; @@ -588,101 +557,49 @@ static int do_acpi_entry(const char *filename, sprintf(&alias[cnt], "??"); cnt += 2; } - sprintf(&alias[cnt], ":*"); + module_alias_printf(mod, false, "acpi*:%s:*", alias); } - return 1; } /* looks like: "pnp:dD" */ -static void do_pnp_device_entry(void *symval, unsigned long size, - struct module *mod) +static void do_pnp_device_entry(struct module *mod, void *symval) { - const unsigned long id_size = SIZE_pnp_device_id; - const unsigned int count = (size / id_size)-1; - unsigned int i; - - device_id_check(mod->name, "pnp", size, id_size, symval); + DEF_FIELD_ADDR(symval, pnp_device_id, id); + char acpi_id[sizeof(*id)]; - for (i = 0; i < count; i++) { - DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); - char acpi_id[sizeof(*id)]; - int j; - - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", *id); - - /* fix broken pnp bus lowercasing */ - for (j = 0; j < sizeof(acpi_id); j++) - acpi_id[j] = toupper((*id)[j]); - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); - } + /* fix broken pnp bus lowercasing */ + for (unsigned int i = 0; i < sizeof(acpi_id); i++) + acpi_id[i] = toupper((*id)[i]); + module_alias_printf(mod, false, "pnp:d%s*", *id); + module_alias_printf(mod, false, "acpi*:%s:*", acpi_id); } /* looks like: "pnp:dD" for every device of the card */ -static void do_pnp_card_entries(void *symval, unsigned long size, - struct module *mod) +static void do_pnp_card_entry(struct module *mod, void *symval) { - const unsigned long id_size = SIZE_pnp_card_device_id; - const unsigned int count = (size / id_size)-1; - unsigned int i; - - device_id_check(mod->name, "pnp", size, id_size, symval); - - for (i = 0; i < count; i++) { - unsigned int j; - DEF_FIELD_ADDR(symval + i * id_size, pnp_card_device_id, devs); - - for (j = 0; j < PNP_MAX_DEVICES; j++) { - const char *id = (char *)(*devs)[j].id; - int i2, j2; - int dup = 0; - - if (!id[0]) - break; + DEF_FIELD_ADDR(symval, pnp_card_device_id, devs); - /* find duplicate, already added value */ - for (i2 = 0; i2 < i && !dup; i2++) { - DEF_FIELD_ADDR_VAR(symval + i2 * id_size, - pnp_card_device_id, - devs, devs_dup); + for (unsigned int i = 0; i < PNP_MAX_DEVICES; i++) { + const char *id = (char *)(*devs)[i].id; + char acpi_id[PNP_ID_LEN]; - for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { - const char *id2 = - (char *)(*devs_dup)[j2].id; - - if (!id2[0]) - break; - - if (!strcmp(id, id2)) { - dup = 1; - break; - } - } - } - - /* add an individual alias for every device entry */ - if (!dup) { - char acpi_id[PNP_ID_LEN]; - int k; + if (!id[0]) + break; - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", id); + /* fix broken pnp bus lowercasing */ + for (unsigned int j = 0; j < sizeof(acpi_id); j++) + acpi_id[j] = toupper(id[j]); - /* fix broken pnp bus lowercasing */ - for (k = 0; k < sizeof(acpi_id); k++) - acpi_id[k] = toupper(id[k]); - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); - } - } + /* add an individual alias for every device entry */ + module_alias_printf(mod, false, "pnp:d%s*", id); + module_alias_printf(mod, false, "acpi*:%s:*", acpi_id); } } /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ -static int do_pcmcia_entry(const char *filename, - void *symval, char *alias) +static void do_pcmcia_entry(struct module *mod, void *symval) { + char alias[256] = {}; unsigned int i; DEF_FIELD(symval, pcmcia_device_id, match_flags); DEF_FIELD(symval, pcmcia_device_id, manf_id); @@ -696,7 +613,6 @@ static int do_pcmcia_entry(const char *filename, (*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]); } - strcpy(alias, "pcmcia:"); ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, manf_id); ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, @@ -712,13 +628,12 @@ static int do_pcmcia_entry(const char *filename, ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]); ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "pcmcia:%s", alias); } -static int do_vio_entry(const char *filename, void *symval, - char *alias) +static void do_vio_entry(struct module *mod, void *symval) { + char alias[256]; char *tmp; DEF_FIELD_ADDR(symval, vio_device_id, type); DEF_FIELD_ADDR(symval, vio_device_id, compat); @@ -731,8 +646,7 @@ static int do_vio_entry(const char *filename, void *symval, if (isspace (*tmp)) *tmp = '_'; - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "%s", alias); } static void do_input(char *alias, @@ -748,9 +662,10 @@ static void do_input(char *alias, } /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ -static int do_input_entry(const char *filename, void *symval, - char *alias) +static void do_input_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, input_device_id, flags); DEF_FIELD(symval, input_device_id, bustype); DEF_FIELD(symval, input_device_id, vendor); @@ -766,8 +681,6 @@ static int do_input_entry(const char *filename, void *symval, DEF_FIELD_ADDR(symval, input_device_id, ffbit); DEF_FIELD_ADDR(symval, input_device_id, swbit); - sprintf(alias, "input:"); - ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype); ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor); ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product); @@ -802,102 +715,96 @@ static int do_input_entry(const char *filename, void *symval, sprintf(alias + strlen(alias), "w*"); if (flags & INPUT_DEVICE_ID_MATCH_SWBIT) do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); - return 1; + + module_alias_printf(mod, false, "input:%s", alias); } -static int do_eisa_entry(const char *filename, void *symval, - char *alias) +static void do_eisa_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, eisa_device_id, sig); - if (sig[0]) - sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); - else - strcat(alias, "*"); - return 1; + module_alias_printf(mod, false, EISA_DEVICE_MODALIAS_FMT "*", *sig); } /* Looks like: parisc:tNhvNrevNsvN */ -static int do_parisc_entry(const char *filename, void *symval, - char *alias) +static void do_parisc_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, parisc_device_id, hw_type); DEF_FIELD(symval, parisc_device_id, hversion); DEF_FIELD(symval, parisc_device_id, hversion_rev); DEF_FIELD(symval, parisc_device_id, sversion); - strcpy(alias, "parisc:"); ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type); ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion); ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev); ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "parisc:%s", alias); } /* Looks like: sdio:cNvNdN. */ -static int do_sdio_entry(const char *filename, - void *symval, char *alias) +static void do_sdio_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, sdio_device_id, class); DEF_FIELD(symval, sdio_device_id, vendor); DEF_FIELD(symval, sdio_device_id, device); - strcpy(alias, "sdio:"); ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class); ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor); ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device); - add_wildcard(alias); - return 1; + + module_alias_printf(mod, true, "sdio:%s", alias); } /* Looks like: ssb:vNidNrevN. */ -static int do_ssb_entry(const char *filename, - void *symval, char *alias) +static void do_ssb_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, ssb_device_id, vendor); DEF_FIELD(symval, ssb_device_id, coreid); DEF_FIELD(symval, ssb_device_id, revision); - strcpy(alias, "ssb:"); ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor); ADD(alias, "id", coreid != SSB_ANY_ID, coreid); ADD(alias, "rev", revision != SSB_ANY_REV, revision); - add_wildcard(alias); - return 1; + + module_alias_printf(mod, true, "ssb:%s", alias); } /* Looks like: bcma:mNidNrevNclN. */ -static int do_bcma_entry(const char *filename, - void *symval, char *alias) +static void do_bcma_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, bcma_device_id, manuf); DEF_FIELD(symval, bcma_device_id, id); DEF_FIELD(symval, bcma_device_id, rev); DEF_FIELD(symval, bcma_device_id, class); - strcpy(alias, "bcma:"); ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf); ADD(alias, "id", id != BCMA_ANY_ID, id); ADD(alias, "rev", rev != BCMA_ANY_REV, rev); ADD(alias, "cl", class != BCMA_ANY_CLASS, class); - add_wildcard(alias); - return 1; + + module_alias_printf(mod, true, "bcma:%s", alias); } /* Looks like: virtio:dNvN */ -static int do_virtio_entry(const char *filename, void *symval, - char *alias) +static void do_virtio_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, virtio_device_id, device); DEF_FIELD(symval, virtio_device_id, vendor); - strcpy(alias, "virtio:"); ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device); ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "virtio:%s", alias); } /* @@ -906,8 +813,7 @@ static int do_virtio_entry(const char *filename, void *symval, * in the name. */ -static int do_vmbus_entry(const char *filename, void *symval, - char *alias) +static void do_vmbus_entry(struct module *mod, void *symval) { int i; DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid); @@ -916,68 +822,57 @@ static int do_vmbus_entry(const char *filename, void *symval, for (i = 0; i < (sizeof(*guid) * 2); i += 2) sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2])); - strcpy(alias, "vmbus:"); - strcat(alias, guid_name); - - return 1; + module_alias_printf(mod, false, "vmbus:%s", guid_name); } /* Looks like: rpmsg:S */ -static int do_rpmsg_entry(const char *filename, void *symval, - char *alias) +static void do_rpmsg_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, rpmsg_device_id, name); - sprintf(alias, RPMSG_DEVICE_MODALIAS_FMT, *name); - return 1; + module_alias_printf(mod, false, RPMSG_DEVICE_MODALIAS_FMT, *name); } /* Looks like: i2c:S */ -static int do_i2c_entry(const char *filename, void *symval, - char *alias) +static void do_i2c_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, i2c_device_id, name); - sprintf(alias, I2C_MODULE_PREFIX "%s", *name); - return 1; + module_alias_printf(mod, false, I2C_MODULE_PREFIX "%s", *name); } -static int do_i3c_entry(const char *filename, void *symval, - char *alias) +static void do_i3c_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, i3c_device_id, match_flags); DEF_FIELD(symval, i3c_device_id, dcr); DEF_FIELD(symval, i3c_device_id, manuf_id); DEF_FIELD(symval, i3c_device_id, part_id); DEF_FIELD(symval, i3c_device_id, extra_info); - strcpy(alias, "i3c:"); ADD(alias, "dcr", match_flags & I3C_MATCH_DCR, dcr); ADD(alias, "manuf", match_flags & I3C_MATCH_MANUF, manuf_id); ADD(alias, "part", match_flags & I3C_MATCH_PART, part_id); ADD(alias, "ext", match_flags & I3C_MATCH_EXTRA_INFO, extra_info); - return 1; + module_alias_printf(mod, false, "i3c:%s", alias); } -static int do_slim_entry(const char *filename, void *symval, char *alias) +static void do_slim_entry(struct module *mod, void *symval) { DEF_FIELD(symval, slim_device_id, manf_id); DEF_FIELD(symval, slim_device_id, prod_code); - sprintf(alias, "slim:%x:%x:*", manf_id, prod_code); - - return 1; + module_alias_printf(mod, false, "slim:%x:%x:*", manf_id, prod_code); } /* Looks like: spi:S */ -static int do_spi_entry(const char *filename, void *symval, - char *alias) +static void do_spi_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, spi_device_id, name); - sprintf(alias, SPI_MODULE_PREFIX "%s", *name); - return 1; + module_alias_printf(mod, false, SPI_MODULE_PREFIX "%s", *name); } static const struct dmifield { @@ -1012,12 +907,11 @@ static void dmi_ascii_filter(char *d, const char *s) } -static int do_dmi_entry(const char *filename, void *symval, - char *alias) +static void do_dmi_entry(struct module *mod, void *symval) { + char alias[256] = {}; int i, j; DEF_FIELD_ADDR(symval, dmi_system_id, matches); - sprintf(alias, "dmi*"); for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { for (j = 0; j < 4; j++) { @@ -1032,80 +926,75 @@ static int do_dmi_entry(const char *filename, void *symval, } } - strcat(alias, ":"); - return 1; + module_alias_printf(mod, false, "dmi*%s:", alias); } -static int do_platform_entry(const char *filename, - void *symval, char *alias) +static void do_platform_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, platform_device_id, name); - sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); - return 1; + + module_alias_printf(mod, false, PLATFORM_MODULE_PREFIX "%s", *name); } -static int do_mdio_entry(const char *filename, - void *symval, char *alias) +static void do_mdio_entry(struct module *mod, void *symval) { + char id[33]; int i; DEF_FIELD(symval, mdio_device_id, phy_id); DEF_FIELD(symval, mdio_device_id, phy_id_mask); - alias += sprintf(alias, MDIO_MODULE_PREFIX); - for (i = 0; i < 32; i++) { if (!((phy_id_mask >> (31-i)) & 1)) - *(alias++) = '?'; + id[i] = '?'; else if ((phy_id >> (31-i)) & 1) - *(alias++) = '1'; + id[i] = '1'; else - *(alias++) = '0'; + id[i] = '0'; } /* Terminate the string */ - *alias = 0; + id[32] = '\0'; - return 1; + module_alias_printf(mod, false, MDIO_MODULE_PREFIX "%s", id); } /* Looks like: zorro:iN. */ -static int do_zorro_entry(const char *filename, void *symval, - char *alias) +static void do_zorro_entry(struct module *mod, void *symval) { + char alias[256] = {}; DEF_FIELD(symval, zorro_device_id, id); - strcpy(alias, "zorro:"); + ADD(alias, "i", id != ZORRO_WILDCARD, id); - return 1; + + module_alias_printf(mod, false, "zorro:%s", alias); } /* looks like: "pnp:dD" */ -static int do_isapnp_entry(const char *filename, - void *symval, char *alias) +static void do_isapnp_entry(struct module *mod, void *symval) { DEF_FIELD(symval, isapnp_device_id, vendor); DEF_FIELD(symval, isapnp_device_id, function); - sprintf(alias, "pnp:d%c%c%c%x%x%x%x*", + module_alias_printf(mod, false, "pnp:d%c%c%c%x%x%x%x*", 'A' + ((vendor >> 2) & 0x3f) - 1, 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, 'A' + ((vendor >> 8) & 0x1f) - 1, (function >> 4) & 0x0f, function & 0x0f, (function >> 12) & 0x0f, (function >> 8) & 0x0f); - return 1; } /* Looks like: "ipack:fNvNdN". */ -static int do_ipack_entry(const char *filename, - void *symval, char *alias) +static void do_ipack_entry(struct module *mod, void *symval) { + char alias[256] = {}; DEF_FIELD(symval, ipack_device_id, format); DEF_FIELD(symval, ipack_device_id, vendor); DEF_FIELD(symval, ipack_device_id, device); - strcpy(alias, "ipack:"); + ADD(alias, "f", format != IPACK_ANY_FORMAT, format); ADD(alias, "v", vendor != IPACK_ANY_ID, vendor); ADD(alias, "d", device != IPACK_ANY_ID, device); - add_wildcard(alias); - return 1; + + module_alias_printf(mod, true, "ipack:%s", alias); } /* @@ -1156,9 +1045,9 @@ static void append_nibble_mask(char **outp, * N is exactly 8 digits, where each is an upper-case hex digit, or * a ? or [] pattern matching exactly one digit. */ -static int do_amba_entry(const char *filename, - void *symval, char *alias) +static void do_amba_entry(struct module *mod, void *symval) { + char alias[256]; unsigned int digit; char *p = alias; DEF_FIELD(symval, amba_id, id); @@ -1166,15 +1055,14 @@ static int do_amba_entry(const char *filename, if ((id & mask) != id) fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: id=0x%08X, mask=0x%08X. Please fix this driver.\n", - filename, id, mask); + mod->name, id, mask); - p += sprintf(alias, "amba:d"); for (digit = 0; digit < 8; digit++) append_nibble_mask(&p, (id >> (4 * (7 - digit))) & 0xf, (mask >> (4 * (7 - digit))) & 0xf); - return 1; + module_alias_printf(mod, false, "amba:d%s", alias); } /* @@ -1183,13 +1071,11 @@ static int do_amba_entry(const char *filename, * N is exactly 2 digits, where each is an upper-case hex digit, or * a ? or [] pattern matching exactly one digit. */ -static int do_mips_cdmm_entry(const char *filename, - void *symval, char *alias) +static void do_mips_cdmm_entry(struct module *mod, void *symval) { DEF_FIELD(symval, mips_cdmm_device_id, type); - sprintf(alias, "mipscdmm:t%02X*", type); - return 1; + module_alias_printf(mod, false, "mipscdmm:t%02X*", type); } /* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* @@ -1198,137 +1084,130 @@ static int do_mips_cdmm_entry(const char *filename, * complicated. */ -static int do_x86cpu_entry(const char *filename, void *symval, - char *alias) +static void do_x86cpu_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, x86_cpu_id, feature); DEF_FIELD(symval, x86_cpu_id, family); DEF_FIELD(symval, x86_cpu_id, model); DEF_FIELD(symval, x86_cpu_id, vendor); - strcpy(alias, "cpu:type:x86,"); ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor); ADD(alias, "fam", family != X86_FAMILY_ANY, family); ADD(alias, "mod", model != X86_MODEL_ANY, model); strcat(alias, ":feature:*"); if (feature != X86_FEATURE_ANY) sprintf(alias + strlen(alias), "%04X*", feature); - return 1; + + module_alias_printf(mod, false, "cpu:type:x86,%s", alias); } /* LOOKS like cpu:type:*:feature:*FEAT* */ -static int do_cpu_entry(const char *filename, void *symval, char *alias) +static void do_cpu_entry(struct module *mod, void *symval) { DEF_FIELD(symval, cpu_feature, feature); - sprintf(alias, "cpu:type:*:feature:*%04X*", feature); - return 1; + module_alias_printf(mod, false, "cpu:type:*:feature:*%04X*", feature); } /* Looks like: mei:S:uuid:N:* */ -static int do_mei_entry(const char *filename, void *symval, - char *alias) +static void do_mei_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD_ADDR(symval, mei_cl_device_id, name); DEF_FIELD_ADDR(symval, mei_cl_device_id, uuid); DEF_FIELD(symval, mei_cl_device_id, version); - sprintf(alias, MEI_CL_MODULE_PREFIX); - sprintf(alias + strlen(alias), "%s:", (*name)[0] ? *name : "*"); add_uuid(alias, *uuid); ADD(alias, ":", version != MEI_CL_VERSION_ANY, version); - strcat(alias, ":*"); - - return 1; + module_alias_printf(mod, false, MEI_CL_MODULE_PREFIX "%s:%s:*", + (*name)[0] ? *name : "*", alias); } /* Looks like: rapidio:vNdNavNadN */ -static int do_rio_entry(const char *filename, - void *symval, char *alias) +static void do_rio_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, rio_device_id, did); DEF_FIELD(symval, rio_device_id, vid); DEF_FIELD(symval, rio_device_id, asm_did); DEF_FIELD(symval, rio_device_id, asm_vid); - strcpy(alias, "rapidio:"); ADD(alias, "v", vid != RIO_ANY_ID, vid); ADD(alias, "d", did != RIO_ANY_ID, did); ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "rapidio:%s", alias); } /* Looks like: ulpi:vNpN */ -static int do_ulpi_entry(const char *filename, void *symval, - char *alias) +static void do_ulpi_entry(struct module *mod, void *symval) { DEF_FIELD(symval, ulpi_device_id, vendor); DEF_FIELD(symval, ulpi_device_id, product); - sprintf(alias, "ulpi:v%04xp%04x", vendor, product); - - return 1; + module_alias_printf(mod, false, "ulpi:v%04xp%04x", vendor, product); } /* Looks like: hdaudio:vNrNaN */ -static int do_hda_entry(const char *filename, void *symval, char *alias) +static void do_hda_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, hda_device_id, vendor_id); DEF_FIELD(symval, hda_device_id, rev_id); DEF_FIELD(symval, hda_device_id, api_version); - strcpy(alias, "hdaudio:"); ADD(alias, "v", vendor_id != 0, vendor_id); ADD(alias, "r", rev_id != 0, rev_id); ADD(alias, "a", api_version != 0, api_version); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "hdaudio:%s", alias); } /* Looks like: sdw:mNpNvNcN */ -static int do_sdw_entry(const char *filename, void *symval, char *alias) +static void do_sdw_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, sdw_device_id, mfg_id); DEF_FIELD(symval, sdw_device_id, part_id); DEF_FIELD(symval, sdw_device_id, sdw_version); DEF_FIELD(symval, sdw_device_id, class_id); - strcpy(alias, "sdw:"); ADD(alias, "m", mfg_id != 0, mfg_id); ADD(alias, "p", part_id != 0, part_id); ADD(alias, "v", sdw_version != 0, sdw_version); ADD(alias, "c", class_id != 0, class_id); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "sdw:%s", alias); } /* Looks like: fsl-mc:vNdN */ -static int do_fsl_mc_entry(const char *filename, void *symval, - char *alias) +static void do_fsl_mc_entry(struct module *mod, void *symval) { DEF_FIELD(symval, fsl_mc_device_id, vendor); DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type); - sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type); - return 1; + module_alias_printf(mod, false, "fsl-mc:v%08Xd%s", vendor, *obj_type); } /* Looks like: tbsvc:kSpNvNrN */ -static int do_tbsvc_entry(const char *filename, void *symval, char *alias) +static void do_tbsvc_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, tb_service_id, match_flags); DEF_FIELD_ADDR(symval, tb_service_id, protocol_key); DEF_FIELD(symval, tb_service_id, protocol_id); DEF_FIELD(symval, tb_service_id, protocol_version); DEF_FIELD(symval, tb_service_id, protocol_revision); - strcpy(alias, "tbsvc:"); if (match_flags & TBSVC_MATCH_PROTOCOL_KEY) sprintf(alias + strlen(alias), "k%s", *protocol_key); else @@ -1339,93 +1218,80 @@ static int do_tbsvc_entry(const char *filename, void *symval, char *alias) ADD(alias, "r", match_flags & TBSVC_MATCH_PROTOCOL_REVISION, protocol_revision); - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "tbsvc:%s", alias); } /* Looks like: typec:idNmN */ -static int do_typec_entry(const char *filename, void *symval, char *alias) +static void do_typec_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, typec_device_id, svid); DEF_FIELD(symval, typec_device_id, mode); - sprintf(alias, "typec:id%04X", svid); ADD(alias, "m", mode != TYPEC_ANY_MODE, mode); - return 1; + module_alias_printf(mod, false, "typec:id%04X%s", svid, alias); } /* Looks like: tee:uuid */ -static int do_tee_entry(const char *filename, void *symval, char *alias) +static void do_tee_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, tee_client_device_id, uuid); - sprintf(alias, "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + module_alias_printf(mod, true, + "tee:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid->b[0], uuid->b[1], uuid->b[2], uuid->b[3], uuid->b[4], uuid->b[5], uuid->b[6], uuid->b[7], uuid->b[8], uuid->b[9], uuid->b[10], uuid->b[11], uuid->b[12], uuid->b[13], uuid->b[14], uuid->b[15]); - - add_wildcard(alias); - return 1; } /* Looks like: wmi:guid */ -static int do_wmi_entry(const char *filename, void *symval, char *alias) +static void do_wmi_entry(struct module *mod, void *symval) { - int len; DEF_FIELD_ADDR(symval, wmi_device_id, guid_string); if (strlen(*guid_string) != UUID_STRING_LEN) { warn("Invalid WMI device id 'wmi:%s' in '%s'\n", - *guid_string, filename); - return 0; + *guid_string, mod->name); + return; } - len = snprintf(alias, ALIAS_SIZE, WMI_MODULE_PREFIX "%s", *guid_string); - if (len < 0 || len >= ALIAS_SIZE) { - warn("Could not generate all MODULE_ALIAS's in '%s'\n", - filename); - return 0; - } - return 1; + module_alias_printf(mod, false, WMI_MODULE_PREFIX "%s", *guid_string); } /* Looks like: mhi:S */ -static int do_mhi_entry(const char *filename, void *symval, char *alias) +static void do_mhi_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, mhi_device_id, chan); - sprintf(alias, MHI_DEVICE_MODALIAS_FMT, *chan); - return 1; + module_alias_printf(mod, false, MHI_DEVICE_MODALIAS_FMT, *chan); } /* Looks like: mhi_ep:S */ -static int do_mhi_ep_entry(const char *filename, void *symval, char *alias) +static void do_mhi_ep_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, mhi_device_id, chan); - sprintf(alias, MHI_EP_DEVICE_MODALIAS_FMT, *chan); - return 1; + module_alias_printf(mod, false, MHI_EP_DEVICE_MODALIAS_FMT, *chan); } /* Looks like: ishtp:{guid} */ -static int do_ishtp_entry(const char *filename, void *symval, char *alias) +static void do_ishtp_entry(struct module *mod, void *symval) { + char alias[256] = {}; DEF_FIELD_ADDR(symval, ishtp_device_id, guid); - strcpy(alias, ISHTP_MODULE_PREFIX "{"); add_guid(alias, *guid); - strcat(alias, "}"); - return 1; + module_alias_printf(mod, false, ISHTP_MODULE_PREFIX "{%s}", alias); } -static int do_auxiliary_entry(const char *filename, void *symval, char *alias) +static void do_auxiliary_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, auxiliary_device_id, name); - sprintf(alias, AUXILIARY_MODULE_PREFIX "%s", *name); - return 1; + module_alias_printf(mod, false, AUXILIARY_MODULE_PREFIX "%s", *name); } /* @@ -1433,8 +1299,10 @@ static int do_auxiliary_entry(const char *filename, void *symval, char *alias) * * N is exactly 2 digits, where each is an upper-case hex digit. */ -static int do_ssam_entry(const char *filename, void *symval, char *alias) +static void do_ssam_entry(struct module *mod, void *symval) { + char alias[256] = {}; + DEF_FIELD(symval, ssam_device_id, match_flags); DEF_FIELD(symval, ssam_device_id, domain); DEF_FIELD(symval, ssam_device_id, category); @@ -1442,30 +1310,28 @@ static int do_ssam_entry(const char *filename, void *symval, char *alias) DEF_FIELD(symval, ssam_device_id, instance); DEF_FIELD(symval, ssam_device_id, function); - sprintf(alias, "ssam:d%02Xc%02X", domain, category); ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target); ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance); ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function); - return 1; + module_alias_printf(mod, false, "ssam:d%02Xc%02X%s", + domain, category, alias); } /* Looks like: dfl:tNfN */ -static int do_dfl_entry(const char *filename, void *symval, char *alias) +static void do_dfl_entry(struct module *mod, void *symval) { DEF_FIELD(symval, dfl_device_id, type); DEF_FIELD(symval, dfl_device_id, feature_id); - sprintf(alias, "dfl:t%04Xf%04X", type, feature_id); - - add_wildcard(alias); - return 1; + module_alias_printf(mod, true, "dfl:t%04Xf%04X", type, feature_id); } /* Looks like: cdx:vNdN */ -static int do_cdx_entry(const char *filename, void *symval, - char *alias) +static void do_cdx_entry(struct module *mod, void *symval) { + char alias[256]; + DEF_FIELD(symval, cdx_device_id, vendor); DEF_FIELD(symval, cdx_device_id, device); DEF_FIELD(symval, cdx_device_id, subvendor); @@ -1484,7 +1350,7 @@ static int do_cdx_entry(const char *filename, void *symval, default: warn("Unknown CDX driver_override alias %08X\n", override_only); - return 0; + return; } ADD(alias, "v", vendor != CDX_ANY_ID, vendor); @@ -1493,24 +1359,22 @@ static int do_cdx_entry(const char *filename, void *symval, ADD(alias, "sd", subdevice != CDX_ANY_ID, subdevice); ADD(alias, "c", class_mask == 0xFFFFFF, class); - return 1; + module_alias_printf(mod, false, "%s", alias); } -static int do_vchiq_entry(const char *filename, void *symval, char *alias) +static void do_vchiq_entry(struct module *mod, void *symval) { DEF_FIELD_ADDR(symval, vchiq_device_id, name); - sprintf(alias, "vchiq:%s", *name); - return 1; + module_alias_printf(mod, false, "vchiq:%s", *name); } /* Looks like: coreboot:tN */ -static int do_coreboot_entry(const char *filename, void *symval, char *alias) +static void do_coreboot_entry(struct module *mod, void *symval) { DEF_FIELD(symval, coreboot_device_id, tag); - sprintf(alias, "coreboot:t%08X", tag); - return 1; + module_alias_printf(mod, false, "coreboot:t%08X", tag); } /* Does namelen bytes of name exactly match the symbol? */ @@ -1522,25 +1386,34 @@ static bool sym_is(const char *name, unsigned namelen, const char *symbol) return memcmp(name, symbol, namelen) == 0; } -static void do_table(void *symval, unsigned long size, +static void do_table(const char *name, void *symval, unsigned long size, unsigned long id_size, const char *device_id, - int (*do_entry)(const char *filename, void *symval, char *alias), + void (*do_entry)(struct module *mod, void *symval), struct module *mod) { unsigned int i; - char alias[ALIAS_SIZE]; - device_id_check(mod->name, device_id, size, id_size, symval); - /* Leave last one: it's the terminator. */ - size -= id_size; + if (size % id_size || size < id_size) { + error("%s: type mismatch between %s[] and MODULE_DEVICE_TABLE(%s, ...)\n", + mod->name, name, device_id); + return; + } - for (i = 0; i < size; i += id_size) { - if (do_entry(mod->name, symval+i, alias)) { - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"%s\");\n", alias); + /* Verify the last entry is a terminator */ + for (i = size - id_size; i < size; i++) { + if (*(uint8_t *)(symval + i)) { + error("%s: %s[] is not terminated with a NULL entry\n", + mod->name, name); + return; } } + + /* Leave last one: it's the terminator. */ + size -= id_size; + + for (i = 0; i < size; i += id_size) + do_entry(mod, symval + i); } static const struct devtable devtable[] = { @@ -1596,6 +1469,10 @@ static const struct devtable devtable[] = { {"cdx", SIZE_cdx_device_id, do_cdx_entry}, {"vchiq", SIZE_vchiq_device_id, do_vchiq_entry}, {"coreboot", SIZE_coreboot_device_id, do_coreboot_entry}, + {"of", SIZE_of_device_id, do_of_entry}, + {"usb", SIZE_usb_device_id, do_usb_entry_multi}, + {"pnp", SIZE_pnp_device_id, do_pnp_device_entry}, + {"pnp_card", SIZE_pnp_card_device_id, do_pnp_card_entry}, }; /* Create MODULE_ALIAS() statements. @@ -1606,8 +1483,9 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, { void *symval; char *zeros = NULL; - const char *name, *identifier; - unsigned int namelen; + const char *type, *name; + size_t typelen; + static const char *prefix = "__mod_device_table__"; /* We're looking for a section relative symbol */ if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) @@ -1617,19 +1495,16 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) return; - /* All our symbols are of form __mod____device_table. */ - if (strncmp(symname, "__mod_", strlen("__mod_"))) - return; - name = symname + strlen("__mod_"); - namelen = strlen(name); - if (namelen < strlen("_device_table")) - return; - if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) + /* All our symbols are of form __mod_device_table____. */ + if (!strstarts(symname, prefix)) return; - identifier = strstr(name, "__"); - if (!identifier) + type = symname + strlen(prefix); + + name = strstr(type, "__"); + if (!name) return; - namelen = identifier - name; + typelen = name - type; + name += strlen("__"); /* Handle all-NULL symbols allocated into .bss */ if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { @@ -1639,35 +1514,15 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, symval = sym_get_data(info, sym); } - /* First handle the "special" cases */ - if (sym_is(name, namelen, "usb")) - do_usb_table(symval, sym->st_size, mod); - else if (sym_is(name, namelen, "of")) - do_of_table(symval, sym->st_size, mod); - else if (sym_is(name, namelen, "pnp")) - do_pnp_device_entry(symval, sym->st_size, mod); - else if (sym_is(name, namelen, "pnp_card")) - do_pnp_card_entries(symval, sym->st_size, mod); - else { - int i; - - for (i = 0; i < ARRAY_SIZE(devtable); i++) { - const struct devtable *p = &devtable[i]; + for (int i = 0; i < ARRAY_SIZE(devtable); i++) { + const struct devtable *p = &devtable[i]; - if (sym_is(name, namelen, p->device_id)) { - do_table(symval, sym->st_size, p->id_size, - p->device_id, p->do_entry, mod); - break; - } + if (sym_is(type, typelen, p->device_id)) { + do_table(name, symval, sym->st_size, p->id_size, + p->device_id, p->do_entry, mod); + break; } } - free(zeros); -} -/* Now add out buffered information to the generated C source */ -void add_moddevtable(struct buffer *buf, struct module *mod) -{ - buf_printf(buf, "\n"); - buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos); - free(mod->dev_table_buf.p); + free(zeros); } diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 107393a8c48a59..94ee49207a45ae 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -154,12 +155,13 @@ char *get_line(char **stringp) /* A list of all modules we processed */ LIST_HEAD(modules); -static struct module *find_module(const char *modname) +static struct module *find_module(const char *filename, const char *modname) { struct module *mod; list_for_each_entry(mod, &modules, list) { - if (strcmp(mod->name, modname) == 0) + if (!strcmp(mod->dump_file, filename) && + !strcmp(mod->name, modname)) return mod; } return NULL; @@ -176,6 +178,7 @@ static struct module *new_module(const char *name, size_t namelen) INIT_LIST_HEAD(&mod->unresolved_symbols); INIT_LIST_HEAD(&mod->missing_namespaces); INIT_LIST_HEAD(&mod->imported_namespaces); + INIT_LIST_HEAD(&mod->aliases); memcpy(mod->name, name, namelen); mod->name[namelen] = '\0'; @@ -209,19 +212,6 @@ struct symbol { static HASHTABLE_DEFINE(symbol_hashtable, 1U << 10); -/* This is based on the hash algorithm from gdbm, via tdb */ -static inline unsigned int tdb_hash(const char *name) -{ - unsigned value; /* Used to compute the hash value. */ - unsigned i; /* Used to cycle through random values. */ - - /* Set the initial value from the key size. */ - for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) - value = (value + (((unsigned char *)name)[i] << (i*5 % 24))); - - return (1103515243 * value + 12345); -} - /** * Allocate a new symbols for use in the hash of exported symbols or * the list of unresolved symbols per module @@ -239,7 +229,7 @@ static struct symbol *alloc_symbol(const char *name) /* For the hash of exported symbols */ static void hash_add_symbol(struct symbol *sym) { - hash_add(symbol_hashtable, &sym->hnode, tdb_hash(sym->name)); + hash_add(symbol_hashtable, &sym->hnode, hash_str(sym->name)); } static void sym_add_unresolved(const char *name, struct module *mod, bool weak) @@ -260,7 +250,7 @@ static struct symbol *sym_find_with_module(const char *name, struct module *mod) if (name[0] == '.') name++; - hash_for_each_possible(symbol_hashtable, s, hnode, tdb_hash(name)) { + hash_for_each_possible(symbol_hashtable, s, hnode, hash_str(name)) { if (strcmp(s->name, name) == 0 && (!mod || s->module == mod)) return s; } @@ -340,8 +330,6 @@ static const char *sec_name(const struct elf_info *info, unsigned int secindex) return sech_name(info, &info->sechdrs[secindex]); } -#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) - static struct symbol *sym_add_exported(const char *name, struct module *mod, bool gpl_only, const char *namespace) { @@ -785,7 +773,7 @@ static void check_section(const char *modname, struct elf_info *elf, ".ltext", ".ltext.*" #define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ ".fixup", ".entry.text", ".exception.text", \ - ".coldtext", ".softirqentry.text" + ".coldtext", ".softirqentry.text", ".irqentry.text" #define ALL_TEXT_SECTIONS ".init.text", ".exit.text", \ TEXT_SECTIONS, OTHER_TEXT_SECTIONS @@ -1966,6 +1954,7 @@ static void write_vmlinux_export_c_file(struct module *mod) static void write_mod_c_file(struct module *mod) { struct buffer buf = { }; + struct module_alias *alias, *next; char fname[PATH_MAX]; int ret; @@ -1973,7 +1962,14 @@ static void write_mod_c_file(struct module *mod) add_exported_symbols(&buf, mod); add_versions(&buf, mod); add_depends(&buf, mod); - add_moddevtable(&buf, mod); + + buf_printf(&buf, "\n"); + list_for_each_entry_safe(alias, next, &mod->aliases, node) { + buf_printf(&buf, "MODULE_ALIAS(\"%s\");\n", alias->str); + list_del(&alias->node); + free(alias); + } + add_srcversion(&buf, mod); ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name); @@ -2035,10 +2031,10 @@ static void read_dump(const char *fname) continue; } - mod = find_module(modname); + mod = find_module(fname, modname); if (!mod) { mod = new_module(modname, strlen(modname)); - mod->from_dump = true; + mod->dump_file = fname; } s = sym_add_exported(symname, mod, gpl_only, namespace); sym_set_crc(s, crc); @@ -2057,7 +2053,7 @@ static void write_dump(const char *fname) struct symbol *sym; list_for_each_entry(mod, &modules, list) { - if (mod->from_dump) + if (mod->dump_file) continue; list_for_each_entry(sym, &mod->exported_symbols, list) { if (trim_unused_exports && !sym->used) @@ -2081,7 +2077,7 @@ static void write_namespace_deps_files(const char *fname) list_for_each_entry(mod, &modules, list) { - if (mod->from_dump || list_empty(&mod->missing_namespaces)) + if (mod->dump_file || list_empty(&mod->missing_namespaces)) continue; buf_printf(&ns_deps_buf, "%s.ko:", mod->name); @@ -2199,7 +2195,7 @@ int main(int argc, char **argv) read_symbols_from_files(files_source); list_for_each_entry(mod, &modules, list) { - if (mod->from_dump || mod->is_vmlinux) + if (mod->dump_file || mod->is_vmlinux) continue; check_modname_len(mod); @@ -2210,7 +2206,7 @@ int main(int argc, char **argv) handle_white_list_exports(unused_exports_white_list); list_for_each_entry(mod, &modules, list) { - if (mod->from_dump) + if (mod->dump_file) continue; if (mod->is_vmlinux) diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index ada3a36cc4bc93..8b72c227ebf47e 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -67,6 +67,8 @@ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) + struct buffer { char *p; int pos; @@ -79,22 +81,39 @@ buf_printf(struct buffer *buf, const char *fmt, ...); void buf_write(struct buffer *buf, const char *s, int len); +/** + * struct module_alias - auto-generated MODULE_ALIAS() + * + * @node: linked to module::aliases + * @str: a string for MODULE_ALIAS() + */ +struct module_alias { + struct list_head node; + char str[]; +}; + +/** + * struct module - represent a module (vmlinux or *.ko) + * + * @dump_file: path to the .symvers file if loaded from a file + * @aliases: list head for module_aliases + */ struct module { struct list_head list; struct list_head exported_symbols; struct list_head unresolved_symbols; + const char *dump_file; bool is_gpl_compatible; - bool from_dump; /* true if module was loaded from *.symvers */ bool is_vmlinux; bool seen; bool has_init; bool has_cleanup; - struct buffer dev_table_buf; char srcversion[25]; // Missing namespace dependencies struct list_head missing_namespaces; // Actual imported namespaces struct list_head imported_namespaces; + struct list_head aliases; char name[]; }; @@ -170,7 +189,6 @@ Elf_Sym *symsearch_find_nearest(struct elf_info *elf, Elf_Addr addr, /* file2alias.c */ void handle_moddevtable(struct module *mod, struct elf_info *info, Elf_Sym *sym, const char *symname); -void add_moddevtable(struct buffer *buf, struct module *mod); /* sumversion.c */ void get_src_version(const char *modname, char sum[], unsigned sumlen); diff --git a/scripts/module.lds.S b/scripts/module.lds.S index 3f43edef813cb9..c2f80f9141d407 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -18,10 +18,10 @@ SECTIONS { *(.export_symbol) } - __ksymtab 0 : { *(SORT(___ksymtab+*)) } - __ksymtab_gpl 0 : { *(SORT(___ksymtab_gpl+*)) } - __kcrctab 0 : { *(SORT(___kcrctab+*)) } - __kcrctab_gpl 0 : { *(SORT(___kcrctab_gpl+*)) } + __ksymtab 0 : ALIGN(8) { *(SORT(___ksymtab+*)) } + __ksymtab_gpl 0 : ALIGN(8) { *(SORT(___ksymtab_gpl+*)) } + __kcrctab 0 : ALIGN(4) { *(SORT(___kcrctab+*)) } + __kcrctab_gpl 0 : ALIGN(4) { *(SORT(___kcrctab_gpl+*)) } .ctors 0 : ALIGN(8) { *(SORT(.ctors.*)) *(.ctors) } .init_array 0 : ALIGN(8) { *(SORT(.init_array.*)) *(.init_array) } @@ -29,6 +29,7 @@ SECTIONS { .altinstructions 0 : ALIGN(8) { KEEP(*(.altinstructions)) } __bug_table 0 : ALIGN(8) { KEEP(*(__bug_table)) } __jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) } + __ex_table 0 : ALIGN(4) { KEEP(*(__ex_table)) } __patchable_function_entries : { *(__patchable_function_entries) } @@ -50,7 +51,7 @@ SECTIONS { .data : { *(.data .data.[0-9a-zA-Z_]*) *(.data..L*) - CODETAG_SECTIONS() + MOD_CODETAG_SECTIONS() } .rodata : { @@ -59,9 +60,10 @@ SECTIONS { } #else .data : { - CODETAG_SECTIONS() + MOD_CODETAG_SECTIONS() } #endif + MOD_SEPARATE_CODETAG_SECTIONS() } /* bring in arch-specific sections */ diff --git a/scripts/nsdeps b/scripts/nsdeps index f1718cc0d700bb..a3372166ac01b9 100644 --- a/scripts/nsdeps +++ b/scripts/nsdeps @@ -19,22 +19,16 @@ if ! { echo "$SPATCH_REQ_VERSION"; echo "$SPATCH_VERSION"; } | sort -CV ; then exit 1 fi -if [ "$KBUILD_EXTMOD" ]; then - src_prefix= -else - src_prefix=$srctree/ -fi - generate_deps_for_ns() { $SPATCH --very-quiet --in-place --sp-file \ - $srctree/scripts/coccinelle/misc/add_namespace.cocci -D nsdeps -D ns=$1 $2 + $srctree/scripts/coccinelle/misc/add_namespace.cocci -D nsdeps -D ns=\"$1\" $2 } generate_deps() { local mod=${1%.ko:} shift local namespaces="$*" - local mod_source_files=$(sed "s|^\(.*\)\.o$|${src_prefix}\1.c|" $mod.mod) + local mod_source_files=$(sed "s|^\(.*\)\.o$|${srcroot}/\1.c|" $mod.mod) for ns in $namespaces; do echo "Adding namespace $ns to module $mod.ko." @@ -57,4 +51,4 @@ generate_deps() { while read line do generate_deps $line -done < $MODULES_NSDEPS +done < modules.nsdeps diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 441b0bb66e0d0c..ad7aba0f268e1f 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -63,6 +63,12 @@ install_linux_image () { esac cp "$(${MAKE} -s -f ${srctree}/Makefile image_name)" "${pdir}/${installed_image_path}" + if [ "${ARCH}" != um ]; then + install_maint_scripts "${pdir}" + fi +} + +install_maint_scripts () { # Install the maintainer scripts # Note: hook scripts under /etc/kernel are also executed by official Debian # kernel packages, as well as kernel packages built using make-kpkg. @@ -96,16 +102,18 @@ install_linux_image_dbg () { # Parse modules.order directly because 'make modules_install' may sign, # compress modules, and then run unneeded depmod. - while read -r mod; do - mod="${mod%.o}.ko" - dbg="${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/kernel/${mod}" - buildid=$("${READELF}" -n "${mod}" | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p') - link="${pdir}/usr/lib/debug/.build-id/${buildid}.debug" - - mkdir -p "${dbg%/*}" "${link%/*}" - "${OBJCOPY}" --only-keep-debug "${mod}" "${dbg}" - ln -sf --relative "${dbg}" "${link}" - done < modules.order + if is_enabled CONFIG_MODULES; then + while read -r mod; do + mod="${mod%.o}.ko" + dbg="${pdir}/usr/lib/debug/lib/modules/${KERNELRELEASE}/kernel/${mod}" + buildid=$("${READELF}" -n "${mod}" | sed -n 's@^.*Build ID: \(..\)\(.*\)@\1/\2@p') + link="${pdir}/usr/lib/debug/.build-id/${buildid}.debug" + + mkdir -p "${dbg%/*}" "${link%/*}" + "${OBJCOPY}" --only-keep-debug "${mod}" "${dbg}" + ln -sf --relative "${dbg}" "${link}" + done < modules.order + fi # Build debug package # Different tools want the image in different locations diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build index 7ec1f061a519c7..d3c5b104c06316 100755 --- a/scripts/package/install-extmod-build +++ b/scripts/package/install-extmod-build @@ -51,6 +51,13 @@ mkdir -p "${destdir}" if [ "${CC}" != "${HOSTCC}" ]; then echo "Rebuilding host programs with ${CC}..." + # This leverages external module building. + # - Clear sub_make_done to allow the top-level Makefile to redo sub-make. + # - Filter out --no-print-directory to print "Entering directory" logs + # when Make changes the working directory. + unset sub_make_done + MAKEFLAGS=$(echo "${MAKEFLAGS}" | sed s/--no-print-directory//) + cat <<-'EOF' > "${destdir}/Kbuild" subdir-y := scripts EOF @@ -62,7 +69,7 @@ if [ "${CC}" != "${HOSTCC}" ]; then # # Use the single-target build to avoid the modpost invocation, which # would overwrite Module.symvers. - "${MAKE}" HOSTCC="${CC}" KBUILD_EXTMOD="${destdir}" scripts/ + "${MAKE}" HOSTCC="${CC}" KBUILD_OUTPUT=. KBUILD_EXTMOD="${destdir}" scripts/ cat <<-'EOF' > "${destdir}/scripts/Kbuild" subdir-y := basic @@ -71,7 +78,7 @@ if [ "${CC}" != "${HOSTCC}" ]; then EOF # Run once again to rebuild scripts/basic/ and scripts/mod/modpost. - "${MAKE}" HOSTCC="${CC}" KBUILD_EXTMOD="${destdir}" scripts/ + "${MAKE}" HOSTCC="${CC}" KBUILD_OUTPUT=. KBUILD_EXTMOD="${destdir}" scripts/ rm -f "${destdir}/Kbuild" "${destdir}/scripts/Kbuild" fi diff --git a/scripts/package/mkdebian b/scripts/package/mkdebian index fc3b7fa709fcf2..b038a1380b8af1 100755 --- a/scripts/package/mkdebian +++ b/scripts/package/mkdebian @@ -70,6 +70,13 @@ set_debarch() { debarch=sh4$(if_enabled_echo CONFIG_CPU_BIG_ENDIAN eb) fi ;; + um) + if is_enabled CONFIG_64BIT; then + debarch=amd64 + else + debarch=i386 + fi + ;; esac if [ -z "$debarch" ]; then debarch=$(dpkg-architecture -qDEB_HOST_ARCH) @@ -202,7 +209,7 @@ Build-Depends-Arch: bc, bison, cpio, flex, gcc-${host_gnu} , kmod, libelf-dev:native, libssl-dev:native, libssl-dev , - rsync + python3:native, rsync Homepage: https://www.kernel.org/ Package: $packagename-$version diff --git a/scripts/remove-stale-files b/scripts/remove-stale-files index 8fc55a749ccc30..6e39fa8540df2f 100755 --- a/scripts/remove-stale-files +++ b/scripts/remove-stale-files @@ -20,6 +20,9 @@ set -e # yard. Stale files stay in this file for a while (for some release cycles?), # then will be really dead and removed from the code base entirely. +# moved to security/selinux/genheaders +rm -f scripts/selinux/genheaders/genheaders + rm -f *.spec rm -f lib/test_fortify.log diff --git a/scripts/rust_is_available.sh b/scripts/rust_is_available.sh index 5262c56dd674e6..93c0ef7fb3fb22 100755 --- a/scripts/rust_is_available.sh +++ b/scripts/rust_is_available.sh @@ -225,6 +225,21 @@ if [ "$bindgen_libclang_cversion" -lt "$bindgen_libclang_min_cversion" ]; then exit 1 fi +if [ "$bindgen_libclang_cversion" -ge 1900100 ] && + [ "$rust_bindings_generator_cversion" -lt 6905 ]; then + # Distributions may have patched the issue (e.g. Debian did). + if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_libclang_concat.h | grep -q foofoo; then + echo >&2 "***" + echo >&2 "*** Rust bindings generator '$BINDGEN' < 0.69.5 together with libclang >= 19.1" + echo >&2 "*** may not work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2824)," + echo >&2 "*** unless patched (like Debian's)." + echo >&2 "*** Your bindgen version: $rust_bindings_generator_version" + echo >&2 "*** Your libclang version: $bindgen_libclang_version" + echo >&2 "***" + warning=1 + fi +fi + # If the C compiler is Clang, then we can also check whether its version # matches the `libclang` version used by the Rust bindings generator. # diff --git a/scripts/rust_is_available_bindgen_libclang_concat.h b/scripts/rust_is_available_bindgen_libclang_concat.h new file mode 100644 index 00000000000000..efc6e98d0f1d0c --- /dev/null +++ b/scripts/rust_is_available_bindgen_libclang_concat.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#define F(x) int x##x +F(foo); diff --git a/scripts/rust_is_available_test.py b/scripts/rust_is_available_test.py index 413741037fb307..4fcc319dea84e7 100755 --- a/scripts/rust_is_available_test.py +++ b/scripts/rust_is_available_test.py @@ -54,7 +54,7 @@ else: """) @classmethod - def generate_bindgen(cls, version_stdout, libclang_stderr, version_0_66_patched=False): + def generate_bindgen(cls, version_stdout, libclang_stderr, version_0_66_patched=False, libclang_concat_patched=False): if libclang_stderr is None: libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})" else: @@ -65,12 +65,19 @@ else: else: version_0_66_case = "raise SystemExit(1)" + if libclang_concat_patched: + libclang_concat_case = "print('pub static mut foofoo: ::std::os::raw::c_int;')" + else: + libclang_concat_case = "pass" + return cls.generate_executable(f"""#!/usr/bin/env python3 import sys if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv): {libclang_case} elif "rust_is_available_bindgen_0_66.h" in " ".join(sys.argv): {version_0_66_case} +elif "rust_is_available_bindgen_libclang_concat.h" in " ".join(sys.argv): + {libclang_concat_case} else: print({repr(version_stdout)}) """) @@ -268,6 +275,31 @@ else: result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen }) self.assertIn(f"libclang (used by the Rust bindings generator '{bindgen}') is too old.", result.stderr) + def test_bindgen_bad_libclang_concat(self): + for (bindgen_version, libclang_version, expected_not_patched) in ( + ("0.69.4", "18.0.0", self.Expected.SUCCESS), + ("0.69.4", "19.1.0", self.Expected.SUCCESS_WITH_WARNINGS), + ("0.69.4", "19.2.0", self.Expected.SUCCESS_WITH_WARNINGS), + + ("0.69.5", "18.0.0", self.Expected.SUCCESS), + ("0.69.5", "19.1.0", self.Expected.SUCCESS), + ("0.69.5", "19.2.0", self.Expected.SUCCESS), + + ("0.70.0", "18.0.0", self.Expected.SUCCESS), + ("0.70.0", "19.1.0", self.Expected.SUCCESS), + ("0.70.0", "19.2.0", self.Expected.SUCCESS), + ): + with self.subTest(bindgen_version=bindgen_version, libclang_version=libclang_version): + cc = self.generate_clang(f"clang version {libclang_version}") + libclang_stderr = f"scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version {libclang_version} [-W#pragma-messages], err: false" + bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr) + result = self.run_script(expected_not_patched, { "BINDGEN": bindgen, "CC": cc }) + if expected_not_patched == self.Expected.SUCCESS_WITH_WARNINGS: + self.assertIn(f"Rust bindings generator '{bindgen}' < 0.69.5 together with libclang >= 19.1", result.stderr) + + bindgen = self.generate_bindgen(f"bindgen {bindgen_version}", libclang_stderr, libclang_concat_patched=True) + result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen, "CC": cc }) + def test_clang_matches_bindgen_libclang_different_bindgen(self): bindgen = self.generate_bindgen_libclang("scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version 999.0.0 [-W#pragma-messages], err: false") result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen }) diff --git a/scripts/selinux/Makefile b/scripts/selinux/Makefile index 59494e14989b57..4b1308fa573235 100644 --- a/scripts/selinux/Makefile +++ b/scripts/selinux/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -subdir-y := mdp genheaders +subdir-y := mdp diff --git a/scripts/selinux/genheaders/.gitignore b/scripts/selinux/genheaders/.gitignore deleted file mode 100644 index 5fcadd307908c3..00000000000000 --- a/scripts/selinux/genheaders/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -genheaders diff --git a/scripts/selinux/genheaders/Makefile b/scripts/selinux/genheaders/Makefile deleted file mode 100644 index 1faf7f07e8db38..00000000000000 --- a/scripts/selinux/genheaders/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -hostprogs-always-y += genheaders -HOST_EXTRACFLAGS += \ - -I$(srctree)/include/uapi -I$(srctree)/include \ - -I$(srctree)/security/selinux/include diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c deleted file mode 100644 index 15520806889ee8..00000000000000 --- a/scripts/selinux/genheaders/genheaders.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -/* NOTE: we really do want to use the kernel headers here */ -#define __EXPORTED_HEADERS__ - -#include -#include -#include -#include -#include -#include - -struct security_class_mapping { - const char *name; - const char *perms[sizeof(unsigned) * 8 + 1]; -}; - -#include "classmap.h" -#include "initial_sid_to_string.h" - -const char *progname; - -static void usage(void) -{ - printf("usage: %s flask.h av_permissions.h\n", progname); - exit(1); -} - -static char *stoupperx(const char *s) -{ - char *s2 = strdup(s); - char *p; - - if (!s2) { - fprintf(stderr, "%s: out of memory\n", progname); - exit(3); - } - - for (p = s2; *p; p++) - *p = toupper(*p); - return s2; -} - -int main(int argc, char *argv[]) -{ - int i, j; - int isids_len; - FILE *fout; - - progname = argv[0]; - - if (argc < 3) - usage(); - - fout = fopen(argv[1], "w"); - if (!fout) { - fprintf(stderr, "Could not open %s for writing: %s\n", - argv[1], strerror(errno)); - exit(2); - } - - fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); - fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n"); - - for (i = 0; secclass_map[i].name; i++) { - char *name = stoupperx(secclass_map[i].name); - - fprintf(fout, "#define SECCLASS_%-39s %2d\n", name, i+1); - free(name); - } - - fprintf(fout, "\n"); - - isids_len = sizeof(initial_sid_to_string) / sizeof(char *); - for (i = 1; i < isids_len; i++) { - const char *s = initial_sid_to_string[i]; - if (s) { - char *sidname = stoupperx(s); - - fprintf(fout, "#define SECINITSID_%-39s %2d\n", sidname, i); - free(sidname); - } - } - fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1); - fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n"); - fprintf(fout, "{\n"); - fprintf(fout, "\tbool sock = false;\n\n"); - fprintf(fout, "\tswitch (kern_tclass) {\n"); - for (i = 0; secclass_map[i].name; i++) { - static char s[] = "SOCKET"; - int len, l; - char *name = stoupperx(secclass_map[i].name); - - len = strlen(name); - l = sizeof(s) - 1; - if (len >= l && memcmp(name + len - l, s, l) == 0) - fprintf(fout, "\tcase SECCLASS_%s:\n", name); - free(name); - } - fprintf(fout, "\t\tsock = true;\n"); - fprintf(fout, "\t\tbreak;\n"); - fprintf(fout, "\tdefault:\n"); - fprintf(fout, "\t\tbreak;\n"); - fprintf(fout, "\t}\n\n"); - fprintf(fout, "\treturn sock;\n"); - fprintf(fout, "}\n"); - - fprintf(fout, "\n#endif\n"); - - if (fclose(fout) != 0) { - fprintf(stderr, "Could not successfully close %s: %s\n", - argv[1], strerror(errno)); - exit(4); - } - - fout = fopen(argv[2], "w"); - if (!fout) { - fprintf(stderr, "Could not open %s for writing: %s\n", - argv[2], strerror(errno)); - exit(5); - } - - fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); - fprintf(fout, "#ifndef _SELINUX_AV_PERMISSIONS_H_\n#define _SELINUX_AV_PERMISSIONS_H_\n\n"); - - for (i = 0; secclass_map[i].name; i++) { - const struct security_class_mapping *map = &secclass_map[i]; - int len; - char *name = stoupperx(map->name); - - len = strlen(name); - for (j = 0; map->perms[j]; j++) { - char *permname; - - if (j >= 32) { - fprintf(stderr, "Too many permissions to fit into an access vector at (%s, %s).\n", - map->name, map->perms[j]); - exit(5); - } - permname = stoupperx(map->perms[j]); - fprintf(fout, "#define %s__%-*s 0x%08xU\n", name, - 39-len, permname, 1U< */ - -/* NOTE: we really do want to use the kernel headers here */ -#define __EXPORTED_HEADERS__ - #include #include #include @@ -171,9 +167,6 @@ int main(int argc, char *argv[]) #ifdef CONFIG_JFS_SECURITY FS_USE("xattr", "jfs"); #endif -#ifdef CONFIG_REISERFS_FS_SECURITY - FS_USE("xattr", "reiserfs"); -#endif #ifdef CONFIG_JFFS2_FS_SECURITY FS_USE("xattr", "jffs2"); #endif diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 38b96c6797f408..28169d7e143b69 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -10,6 +10,8 @@ # # +set -e + usage() { echo "Usage: $0 [--no-local] [srctree]" >&2 exit 1 @@ -30,6 +32,29 @@ if test $# -gt 0 -o ! -d "$srctree"; then usage fi +try_tag() { + tag="$1" + + # Is $tag an annotated tag? + if [ "$(git cat-file -t "$tag" 2> /dev/null)" != tag ]; then + return + fi + + # Is it an ancestor of HEAD, and if so, how many commits are in $tag..HEAD? + # shellcheck disable=SC2046 # word splitting is the point here + set -- $(git rev-list --count --left-right "$tag"...HEAD 2> /dev/null) + + # $1 is 0 if and only if $tag is an ancestor of HEAD. Use + # string comparison, because $1 is empty if the 'git rev-list' + # command somehow failed. + if [ "$1" != 0 ]; then + return + fi + + # $2 is the number of commits in the range $tag..HEAD, possibly 0. + count="$2" +} + scm_version() { local short=false @@ -61,33 +86,33 @@ scm_version() # stable kernel: 6.1.7 -> v6.1.7 version_tag=v$(echo "${KERNELVERSION}" | sed -E 's/^([0-9]+\.[0-9]+)\.0(.*)$/\1\2/') + # try_tag initializes count if the tag is usable. + count= + # If a localversion* file exists, and the corresponding # annotated tag exists and is an ancestor of HEAD, use # it. This is the case in linux-next. - tag=${file_localversion#-} - desc= - if [ -n "${tag}" ]; then - desc=$(git describe --match=$tag 2>/dev/null) + if [ -n "${file_localversion#-}" ] ; then + try_tag "${file_localversion#-}" fi # Otherwise, if a localversion* file exists, and the tag # obtained by appending it to the tag derived from # KERNELVERSION exists and is an ancestor of HEAD, use # it. This is e.g. the case in linux-rt. - if [ -z "${desc}" ] && [ -n "${file_localversion}" ]; then - tag="${version_tag}${file_localversion}" - desc=$(git describe --match=$tag 2>/dev/null) + if [ -z "${count}" ] && [ -n "${file_localversion}" ]; then + try_tag "${version_tag}${file_localversion}" fi # Otherwise, default to the annotated tag derived from KERNELVERSION. - if [ -z "${desc}" ]; then - tag="${version_tag}" - desc=$(git describe --match=$tag 2>/dev/null) + if [ -z "${count}" ]; then + try_tag "${version_tag}" fi - # If we are at the tagged commit, we ignore it because the version is - # well-defined. - if [ "${tag}" != "${desc}" ]; then + # If we are at the tagged commit, we ignore it because the + # version is well-defined. If none of the attempted tags exist + # or were usable, $count is still empty. + if [ -z "${count}" ] || [ "${count}" -gt 0 ]; then # If only the short version is requested, don't bother # running further git commands @@ -95,14 +120,15 @@ scm_version() echo "+" return fi + # If we are past the tagged commit, we pretty print it. # (like 6.1.0-14595-g292a089d78d3) - if [ -n "${desc}" ]; then - echo "${desc}" | awk -F- '{printf("-%05d", $(NF-1))}' + if [ -n "${count}" ]; then + printf "%s%05d" "-" "${count}" fi # Add -g and exactly 12 hex chars. - printf '%s%s' -g "$(echo $head | cut -c1-12)" + printf '%s%.12s' -g "$head" fi if ${no_dirty}; then diff --git a/scripts/spelling.txt b/scripts/spelling.txt index 554329a074ce9d..05bd9ca1fbfa11 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -141,6 +141,7 @@ anomoly||anomaly anonynous||anonymous anway||anyway aplication||application +apeared||appeared appearence||appearance applicaion||application appliction||application @@ -155,6 +156,7 @@ apropriate||appropriate aquainted||acquainted aquired||acquired aquisition||acquisition +aquires||acquires arbitary||arbitrary architechture||architecture archtecture||architecture @@ -185,10 +187,12 @@ assotiated||associated asssert||assert assum||assume assumtpion||assumption +asume||assume asuming||assuming asycronous||asynchronous asychronous||asynchronous asynchnous||asynchronous +asynchrnous||asynchronous asynchronus||asynchronous asynchromous||asynchronous asymetric||asymmetric @@ -269,6 +273,7 @@ caculate||calculate caculation||calculation cadidate||candidate cahces||caches +calcluate||calculate calender||calendar calescing||coalescing calibraiton||calibration @@ -331,6 +336,7 @@ chouse||chose circumvernt||circumvent claread||cleared clared||cleared +clearify||clarify closeing||closing clustred||clustered cnfiguration||configuration @@ -379,12 +385,14 @@ comsumed||consumed comunicate||communicate comunication||communication conbination||combination +concurent||concurrent conditionaly||conditionally conditon||condition condtion||condition condtional||conditional conected||connected conector||connector +configed||configured configration||configuration configred||configured configuartion||configuration @@ -394,6 +402,7 @@ configuratoin||configuration configuraton||configuration configuretion||configuration configutation||configuration +congiuration||configuration conider||consider conjuction||conjunction connecetd||connected @@ -403,6 +412,7 @@ connnection||connection connnections||connections consistancy||consistency consistant||consistent +consits||consists containes||contains containts||contains contaisn||contains @@ -452,6 +462,7 @@ decendants||descendants decompres||decompress decsribed||described decription||description +detault||default dectected||detected defailt||default deferal||deferral @@ -487,6 +498,7 @@ depreacte||deprecate desactivate||deactivate desciptor||descriptor desciptors||descriptors +descritpor||descriptor descripto||descriptor descripton||description descrition||description @@ -601,6 +613,7 @@ enchanced||enhanced encorporating||incorporating encrupted||encrypted encrypiton||encryption +encryped||encrypted encryptio||encryption endianess||endianness enpoint||endpoint @@ -630,6 +643,7 @@ etsbalishment||establishment evalute||evaluate evalutes||evaluates evalution||evaluation +evaulated||evaluated excecutable||executable excceed||exceed exceded||exceeded @@ -650,6 +664,7 @@ exlcude||exclude exlcuding||excluding exlcusive||exclusive exlusive||exclusive +exlicitly||explicitly exmaple||example expecially||especially experies||expires @@ -659,6 +674,7 @@ explict||explicit explictely||explicitly explictly||explicitly expresion||expression +exprienced||experienced exprimental||experimental extened||extended exteneded||extended @@ -834,6 +850,7 @@ informations||information informtion||information infromation||information ingore||ignore +inheritence||inheritance inital||initial initalized||initialized initalised||initialized @@ -878,6 +895,7 @@ interoprability||interoperability interuupt||interrupt interupt||interrupt interupts||interrupts +interurpt||interrupt interrface||interface interrrupt||interrupt interrup||interrupt @@ -925,6 +943,7 @@ jumpimng||jumping juse||just jus||just kown||known +lable||label langage||language langauage||language langauge||language @@ -995,6 +1014,7 @@ metdata||metadata micropone||microphone microprocesspr||microprocessor migrateable||migratable +miliseconds||milliseconds millenium||millennium milliseonds||milliseconds minimim||minimum @@ -1132,6 +1152,7 @@ palne||plane paramameters||parameters paramaters||parameters paramater||parameter +paramenters||parameters parametes||parameters parametised||parametrised paramter||parameter @@ -1177,9 +1198,11 @@ poiter||pointer posible||possible positon||position possibilites||possibilities +postion||position potocol||protocol powerfull||powerful pramater||parameter +preambule||preamble preamle||preamble preample||preamble preapre||prepare @@ -1269,6 +1292,7 @@ raoming||roaming reasearcher||researcher reasearchers||researchers reasearch||research +recalcualte||recalculate receieve||receive recepient||recipient recevied||received @@ -1291,6 +1315,7 @@ refcounf||refcount refence||reference refered||referred referenace||reference +refererence||reference refering||referring refernces||references refernnce||reference @@ -1315,12 +1340,14 @@ reloade||reload remoote||remote remore||remote removeable||removable +repective||respective repectively||respectively replacable||replaceable replacments||replacements replys||replies reponse||response representaion||representation +repsonse||response reqeust||request reqister||register requed||requeued @@ -1362,6 +1389,7 @@ reuest||request reuqest||request reutnred||returned revsion||revision +rewritting||rewriting rmeoved||removed rmeove||remove rmeoves||removes @@ -1444,6 +1472,7 @@ soluation||solution souce||source speach||speech specfic||specific +specfication||specification specfield||specified speciefied||specified specifc||specific @@ -1544,6 +1573,7 @@ syncronus||synchronous syste||system sytem||system sythesis||synthesis +tagert||target taht||that tained||tainted tarffic||traffic @@ -1574,6 +1604,7 @@ tiggers||triggers tiggered||triggered tipically||typically timeing||timing +timming||timing timout||timeout tmis||this toogle||toggle @@ -1597,8 +1628,10 @@ transision||transition transistioned||transitioned transmittd||transmitted transormed||transformed +trasaction||transaction trasfer||transfer trasmission||transmission +trasmitter||transmitter treshold||threshold triggerd||triggered trigerred||triggered diff --git a/scripts/syscall.tbl b/scripts/syscall.tbl index 845e24eb372e7f..ebbdb3c42e9f74 100644 --- a/scripts/syscall.tbl +++ b/scripts/syscall.tbl @@ -403,3 +403,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/scripts/tags.sh b/scripts/tags.sh index 191e0461d6d5bd..b2123637799802 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -152,9 +152,7 @@ regex_c=( '/^BPF_CALL_[0-9]([[:space:]]*\([[:alnum:]_]*\).*/\1/' '/^COMPAT_SYSCALL_DEFINE[0-9]([[:space:]]*\([[:alnum:]_]*\).*/compat_sys_\1/' '/^TRACE_EVENT([[:space:]]*\([[:alnum:]_]*\).*/trace_\1/' - '/^TRACE_EVENT([[:space:]]*\([[:alnum:]_]*\).*/trace_\1_rcuidle/' '/^DEFINE_EVENT([^,)]*,[[:space:]]*\([[:alnum:]_]*\).*/trace_\1/' - '/^DEFINE_EVENT([^,)]*,[[:space:]]*\([[:alnum:]_]*\).*/trace_\1_rcuidle/' '/^DEFINE_INSN_CACHE_OPS([[:space:]]*\([[:alnum:]_]*\).*/get_\1_slot/' '/^DEFINE_INSN_CACHE_OPS([[:space:]]*\([[:alnum:]_]*\).*/free_\1_slot/' '/^PAGEFLAG([[:space:]]*\([[:alnum:]_]*\).*/Page\1/' @@ -191,7 +189,7 @@ regex_c=( '/\apparmor.label; if (!label) return -ENOENT; diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 9934df16c8431d..7ca489ee1054f8 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "include/apparmor.h" #include "include/capability.h" @@ -30,8 +31,9 @@ struct aa_sfs_entry aa_sfs_entry_caps[] = { }; struct audit_cache { - struct aa_profile *profile; - kernel_cap_t caps; + const struct cred *ad_subj_cred; + /* Capabilities go from 0 to CAP_LAST_CAP */ + u64 ktime_ns_expiration[CAP_LAST_CAP+1]; }; static DEFINE_PER_CPU(struct audit_cache, audit_cache); @@ -64,6 +66,8 @@ static void audit_cb(struct audit_buffer *ab, void *va) static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile, int cap, int error) { + const u64 AUDIT_CACHE_TIMEOUT_NS = 1000*1000*1000; /* 1 second */ + struct aa_ruleset *rules = list_first_entry(&profile->rules, typeof(*rules), list); struct audit_cache *ent; @@ -89,15 +93,16 @@ static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile /* Do simple duplicate message elimination */ ent = &get_cpu_var(audit_cache); - if (profile == ent->profile && cap_raised(ent->caps, cap)) { + /* If the capability was never raised the timestamp check would also catch that */ + if (ad->subj_cred == ent->ad_subj_cred && ktime_get_ns() <= ent->ktime_ns_expiration[cap]) { put_cpu_var(audit_cache); if (COMPLAIN_MODE(profile)) return complain_error(error); return error; } else { - aa_put_profile(ent->profile); - ent->profile = aa_get_profile(profile); - cap_raise(ent->caps, cap); + put_cred(ent->ad_subj_cred); + ent->ad_subj_cred = get_cred(ad->subj_cred); + ent->ktime_ns_expiration[cap] = ktime_get_ns() + AUDIT_CACHE_TIMEOUT_NS; } put_cpu_var(audit_cache); @@ -109,7 +114,7 @@ static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile * @profile: profile being enforced (NOT NULL, NOT unconfined) * @cap: capability to test if allowed * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated - * @ad: audit data (MAY BE NULL indicating no auditing) + * @ad: audit data (NOT NULL) * * Returns: 0 if allowed else -EPERM */ diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 571158ec6188f9..5939bd9a9b9bb0 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -637,6 +636,7 @@ static struct aa_label *profile_transition(const struct cred *subj_cred, struct aa_ruleset *rules = list_first_entry(&profile->rules, typeof(*rules), list); struct aa_label *new = NULL; + struct aa_profile *new_profile = NULL; const char *info = NULL, *name = NULL, *target = NULL; aa_state_t state = rules->file->start[AA_CLASS_FILE]; struct aa_perms perms = {}; @@ -681,15 +681,18 @@ static struct aa_label *profile_transition(const struct cred *subj_cred, /* hack ix fallback - improve how this is detected */ goto audit; } else if (!new) { - error = -EACCES; info = "profile transition not found"; - /* remove MAY_EXEC to audit as failure */ + /* remove MAY_EXEC to audit as failure or complaint */ perms.allow &= ~MAY_EXEC; + if (COMPLAIN_MODE(profile)) { + /* create null profile instead of failing */ + goto create_learning_profile; + } + error = -EACCES; } } else if (COMPLAIN_MODE(profile)) { +create_learning_profile: /* no exec permission - learning mode */ - struct aa_profile *new_profile = NULL; - new_profile = aa_new_learning_profile(profile, false, name, GFP_KERNEL); if (!new_profile) { @@ -710,8 +713,8 @@ static struct aa_label *profile_transition(const struct cred *subj_cred, if (!(perms.xindex & AA_X_UNSAFE)) { if (DEBUG_ON) { - dbg_printk("apparmor: scrubbing environment variables" - " for %s profile=", name); + dbg_printk("apparmor: setting AT_SECURE for %s profile=", + name); aa_label_printk(new, GFP_KERNEL); dbg_printk("\n"); } @@ -790,8 +793,8 @@ static int profile_onexec(const struct cred *subj_cred, if (!(perms.xindex & AA_X_UNSAFE)) { if (DEBUG_ON) { - dbg_printk("apparmor: scrubbing environment " - "variables for %s label=", xname); + dbg_printk("apparmor: setting AT_SECURE for %s label=", + xname); aa_label_printk(onexec, GFP_KERNEL); dbg_printk("\n"); } @@ -822,33 +825,19 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred, AA_BUG(!bprm); AA_BUG(!buffer); - if (!stack) { - error = fn_for_each_in_ns(label, profile, - profile_onexec(subj_cred, profile, onexec, stack, - bprm, buffer, cond, unsafe)); - if (error) - return ERR_PTR(error); - new = fn_label_build_in_ns(label, profile, GFP_KERNEL, - aa_get_newest_label(onexec), - profile_transition(subj_cred, profile, bprm, - buffer, - cond, unsafe)); - - } else { - /* TODO: determine how much we want to loosen this */ - error = fn_for_each_in_ns(label, profile, - profile_onexec(subj_cred, profile, onexec, stack, bprm, - buffer, cond, unsafe)); - if (error) - return ERR_PTR(error); - new = fn_label_build_in_ns(label, profile, GFP_KERNEL, - aa_label_merge(&profile->label, onexec, - GFP_KERNEL), - profile_transition(subj_cred, profile, bprm, - buffer, - cond, unsafe)); - } + /* TODO: determine how much we want to loosen this */ + error = fn_for_each_in_ns(label, profile, + profile_onexec(subj_cred, profile, onexec, stack, + bprm, buffer, cond, unsafe)); + if (error) + return ERR_PTR(error); + new = fn_label_build_in_ns(label, profile, GFP_KERNEL, + stack ? aa_label_merge(&profile->label, onexec, + GFP_KERNEL) + : aa_get_newest_label(onexec), + profile_transition(subj_cred, profile, bprm, + buffer, cond, unsafe)); if (new) return new; @@ -961,8 +950,8 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) if (unsafe) { if (DEBUG_ON) { - dbg_printk("scrubbing environment variables for %s " - "label=", bprm->filename); + dbg_printk("setting AT_SECURE for %s label=", + bprm->filename); aa_label_printk(new, GFP_KERNEL); dbg_printk("\n"); } @@ -972,8 +961,8 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) if (label->proxy != new->proxy) { /* when transitioning clear unsafe personality bits */ if (DEBUG_ON) { - dbg_printk("apparmor: clearing unsafe personality " - "bits. %s label=", bprm->filename); + dbg_printk("apparmor: clearing unsafe personality bits. %s label=", + bprm->filename); aa_label_printk(new, GFP_KERNEL); dbg_printk("\n"); } diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 0c8cc86b417b56..e27229349abbe1 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -202,6 +202,6 @@ static inline int complain_error(int error) void aa_audit_rule_free(void *vrule); int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, gfp_t gfp); int aa_audit_rule_known(struct audit_krule *rule); -int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule); +int aa_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vrule); #endif /* __AA_AUDIT_H */ diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index 2a72e6b17d68bc..93290ae300bb2e 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -160,31 +160,7 @@ int aa_label_next_confined(struct aa_label *l, int i); #define label_for_each_cont(I, L, P) \ for (++((I).i); ((P) = (L)->vec[(I).i]); ++((I).i)) -#define next_comb(I, L1, L2) \ -do { \ - (I).j++; \ - if ((I).j >= (L2)->size) { \ - (I).i++; \ - (I).j = 0; \ - } \ -} while (0) - -/* for each combination of P1 in L1, and P2 in L2 */ -#define label_for_each_comb(I, L1, L2, P1, P2) \ -for ((I).i = (I).j = 0; \ - ((P1) = (L1)->vec[(I).i]) && ((P2) = (L2)->vec[(I).j]); \ - (I) = next_comb(I, L1, L2)) - -#define fn_for_each_comb(L1, L2, P1, P2, FN) \ -({ \ - struct label_it i; \ - int __E = 0; \ - label_for_each_comb(i, (L1), (L2), (P1), (P2)) { \ - last_error(__E, (FN)); \ - } \ - __E; \ -}) /* for each profile that is enforcing confinement in a label */ #define label_for_each_confined(I, L, P) \ @@ -291,8 +267,6 @@ bool aa_label_replace(struct aa_label *old, struct aa_label *new); bool aa_label_make_newest(struct aa_labelset *ls, struct aa_label *old, struct aa_label *new); -struct aa_label *aa_label_find(struct aa_label *l); - struct aa_profile *aa_label_next_in_merge(struct label_it *I, struct aa_label *a, struct aa_label *b); @@ -320,8 +294,6 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns, struct aa_label *label, int flags, gfp_t gfp); void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags, gfp_t gfp); -void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp); -void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp); void aa_label_printk(struct aa_label *label, gfp_t gfp); struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str, diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index d7a894b1031ffd..f11a0db7f51da4 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -59,7 +59,6 @@ extern int apparmor_initialized; /* fn's in lib */ const char *skipn_spaces(const char *str, size_t n); -char *aa_split_fqname(char *args, char **ns_name); const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, size_t *ns_len); void aa_info_message(const char *str); diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index 4bb0405c91908a..536ce3abd5986a 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -87,10 +87,12 @@ struct table_header { char td_data[]; }; -#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data)) +#define TABLE_DATAU16(TABLE) ((u16 *)((TABLE)->td_data)) +#define TABLE_DATAU32(TABLE) ((u32 *)((TABLE)->td_data)) +#define DEFAULT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_DEF]->td_data)) #define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data)) -#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data)) -#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data)) +#define NEXT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_NXT]->td_data)) +#define CHECK_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_CHK]->td_data)) #define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data)) #define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data)) #define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data)) diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index 0f7e913c3fc214..bbaa7d39a39ace 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -213,9 +213,6 @@ void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend); void aa_profile_match_label(struct aa_profile *profile, struct aa_ruleset *rules, struct aa_label *label, int type, u32 request, struct aa_perms *perms); -int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, - u32 request, int type, u32 *deny, - struct apparmor_audit_data *ad); int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, u32 request, struct apparmor_audit_data *ad, void (*cb)(struct audit_buffer *, void *)); diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 75088cc310b677..757e3c232c5716 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -264,7 +264,6 @@ void aa_free_profile(struct aa_profile *profile); struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, size_t n); -struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); struct aa_profile *aa_fqlookupn_profile(struct aa_label *base, const char *fqname, size_t n); diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h index a912a5d5d04f5e..f6a515640950ff 100644 --- a/security/apparmor/include/secid.h +++ b/security/apparmor/include/secid.h @@ -26,12 +26,13 @@ extern int apparmor_display_secid_mode; struct aa_label *aa_secid_to_label(u32 secid); int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); +int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, + u32 *seclen); int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); void apparmor_release_secctx(char *secdata, u32 seclen); int aa_alloc_secid(struct aa_label *label, gfp_t gfp); void aa_free_secid(u32 secid); -void aa_secid_update(u32 secid, struct aa_label *label); #endif /* __AA_SECID_H */ diff --git a/security/apparmor/label.c b/security/apparmor/label.c index c71e4615dd460b..91483ecacc16ac 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -899,23 +899,6 @@ struct aa_label *aa_vec_find_or_create_label(struct aa_profile **vec, int len, return vec_create_and_insert_label(vec, len, gfp); } -/** - * aa_label_find - find label @label in label set - * @label: label to find (NOT NULL) - * - * Requires: caller to hold a valid ref on l - * - * Returns: refcounted @label if @label is in tree - * refcounted label that is equiv to @label in tree - * else NULL if @label or equiv is not in tree - */ -struct aa_label *aa_label_find(struct aa_label *label) -{ - AA_BUG(!label); - - return vec_find(label->vec, label->size); -} - /** * aa_label_insert - insert label @label into @ls or return existing label @@ -1811,22 +1794,6 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags, pr_info("%s", label->hname); } -void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp) -{ - struct aa_ns *ns = aa_get_current_ns(); - - aa_label_xaudit(ab, ns, label, FLAG_VIEW_SUBNS, gfp); - aa_put_ns(ns); -} - -void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp) -{ - struct aa_ns *ns = aa_get_current_ns(); - - aa_label_seq_xprint(f, ns, label, FLAG_VIEW_SUBNS, gfp); - aa_put_ns(ns); -} - void aa_label_printk(struct aa_label *label, gfp_t gfp) { struct aa_ns *ns = aa_get_current_ns(); diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index cd569fbbfe36d2..7db62213e352e6 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -45,44 +45,6 @@ void aa_free_str_table(struct aa_str_table *t) } } -/** - * aa_split_fqname - split a fqname into a profile and namespace name - * @fqname: a full qualified name in namespace profile format (NOT NULL) - * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) - * - * Returns: profile name or NULL if one is not specified - * - * Split a namespace name from a profile name (see policy.c for naming - * description). If a portion of the name is missing it returns NULL for - * that portion. - * - * NOTE: may modify the @fqname string. The pointers returned point - * into the @fqname string. - */ -char *aa_split_fqname(char *fqname, char **ns_name) -{ - char *name = strim(fqname); - - *ns_name = NULL; - if (name[0] == ':') { - char *split = strchr(&name[1], ':'); - *ns_name = skip_spaces(&name[1]); - if (split) { - /* overwrite ':' with \0 */ - *split++ = 0; - if (strncmp(split, "//", 2) == 0) - split += 2; - name = skip_spaces(split); - } else - /* a ns name without a following profile is allowed */ - name = NULL; - } - if (name && *name == 0) - name = NULL; - - return name; -} - /** * skipn_spaces - Removes leading whitespace from @str. * @str: The string to be stripped. @@ -275,33 +237,6 @@ void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, audit_log_format(ab, "\""); } -/** - * aa_audit_perms_cb - generic callback fn for auditing perms - * @ab: audit buffer (NOT NULL) - * @va: audit struct to audit values of (NOT NULL) - */ -static void aa_audit_perms_cb(struct audit_buffer *ab, void *va) -{ - struct common_audit_data *sa = va; - struct apparmor_audit_data *ad = aad(sa); - - if (ad->request) { - audit_log_format(ab, " requested_mask="); - aa_audit_perm_mask(ab, ad->request, aa_file_perm_chrs, - PERMS_CHRS_MASK, aa_file_perm_names, - PERMS_NAMES_MASK); - } - if (ad->denied) { - audit_log_format(ab, "denied_mask="); - aa_audit_perm_mask(ab, ad->denied, aa_file_perm_chrs, - PERMS_CHRS_MASK, aa_file_perm_names, - PERMS_NAMES_MASK); - } - audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, - FLAGS_NONE, GFP_ATOMIC); -} - /** * aa_apply_modes_to_perms - apply namespace and profile flags to perms * @profile: that perms where computed from @@ -349,25 +284,6 @@ void aa_profile_match_label(struct aa_profile *profile, } -/* currently unused */ -int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, - u32 request, int type, u32 *deny, - struct apparmor_audit_data *ad) -{ - struct aa_ruleset *rules = list_first_entry(&profile->rules, - typeof(*rules), list); - struct aa_perms perms; - - ad->peer = &target->label; - ad->request = request; - - aa_profile_match_label(profile, rules, &target->label, type, request, - &perms); - aa_apply_modes_to_perms(profile, &perms); - *deny |= request & perms.deny; - return aa_check_perms(profile, &perms, request, ad, aa_audit_perms_cb); -} - /** * aa_check_perms - do audit mode selection based on perms set * @profile: profile being checked diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f5d05297d59ee4..1edc12862a7de2 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -982,17 +982,20 @@ static void apparmor_bprm_committed_creds(const struct linux_binprm *bprm) return; } -static void apparmor_current_getsecid_subj(u32 *secid) +static void apparmor_current_getlsmprop_subj(struct lsm_prop *prop) { struct aa_label *label = __begin_current_label_crit_section(); - *secid = label->secid; + + prop->apparmor.label = label; __end_current_label_crit_section(label); } -static void apparmor_task_getsecid_obj(struct task_struct *p, u32 *secid) +static void apparmor_task_getlsmprop_obj(struct task_struct *p, + struct lsm_prop *prop) { struct aa_label *label = aa_get_task_label(p); - *secid = label->secid; + + prop->apparmor.label = label; aa_put_label(label); } @@ -1503,8 +1506,9 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = { LSM_HOOK_INIT(task_free, apparmor_task_free), LSM_HOOK_INIT(task_alloc, apparmor_task_alloc), - LSM_HOOK_INIT(current_getsecid_subj, apparmor_current_getsecid_subj), - LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid_obj), + LSM_HOOK_INIT(current_getlsmprop_subj, + apparmor_current_getlsmprop_subj), + LSM_HOOK_INIT(task_getlsmprop_obj, apparmor_task_getlsmprop_obj), LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), LSM_HOOK_INIT(task_kill, apparmor_task_kill), LSM_HOOK_INIT(userns_create, apparmor_userns_create), @@ -1517,6 +1521,7 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = { #endif LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx), + LSM_HOOK_INIT(lsmprop_to_secctx, apparmor_lsmprop_to_secctx), LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid), LSM_HOOK_INIT(release_secctx, apparmor_release_secctx), diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 517d77d3c34cc9..f2d9c57f879439 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -247,6 +247,42 @@ void aa_dfa_free_kref(struct kref *kref) dfa_free(dfa); } + + +/** + * remap_data16_to_data32 - remap u16 @old table to a u32 based table + * @old: table to remap + * + * Returns: new table with u32 entries instead of u16. + * + * Note: will free @old so caller does not have to + */ +static struct table_header *remap_data16_to_data32(struct table_header *old) +{ + struct table_header *new; + size_t tsize; + u32 i; + + tsize = table_size(old->td_lolen, YYTD_DATA32); + new = kvzalloc(tsize, GFP_KERNEL); + if (!new) { + kvfree(old); + return NULL; + } + new->td_id = old->td_id; + new->td_flags = YYTD_DATA32; + new->td_lolen = old->td_lolen; + + for (i = 0; i < old->td_lolen; i++) + TABLE_DATAU32(new)[i] = (u32) TABLE_DATAU16(old)[i]; + + kvfree(old); + if (is_vmalloc_addr(new)) + vm_unmap_aliases(); + + return new; +} + /** * aa_dfa_unpack - unpack the binary tables of a serialized dfa * @blob: aligned serialized stream of data to unpack (NOT NULL) @@ -326,8 +362,10 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) case YYTD_ID_DEF: case YYTD_ID_NXT: case YYTD_ID_CHK: - if (table->td_flags != YYTD_DATA16) + if (!(table->td_flags == YYTD_DATA16 || + table->td_flags == YYTD_DATA32)) { goto fail; + } break; case YYTD_ID_EC: if (table->td_flags != YYTD_DATA8) @@ -342,6 +380,23 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags) dfa->tables[table->td_id] = table; data += table_size(table->td_lolen, table->td_flags); size -= table_size(table->td_lolen, table->td_flags); + + /* + * this remapping has to be done after incrementing data above + * for now straight remap, later have dfa support both + */ + switch (table->td_id) { + case YYTD_ID_DEF: + case YYTD_ID_NXT: + case YYTD_ID_CHK: + if (table->td_flags == YYTD_DATA16) { + table = remap_data16_to_data32(table); + if (!table) + goto fail; + } + dfa->tables[table->td_id] = table; + break; + } table = NULL; } error = verify_table_headers(dfa->tables, flags); @@ -395,10 +450,10 @@ do { \ aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start, const char *str, int len) { - u16 *def = DEFAULT_TABLE(dfa); + u32 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); + u32 *next = NEXT_TABLE(dfa); + u32 *check = CHECK_TABLE(dfa); aa_state_t state = start; if (state == DFA_NOMATCH) @@ -434,10 +489,10 @@ aa_state_t aa_dfa_match_len(struct aa_dfa *dfa, aa_state_t start, */ aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, const char *str) { - u16 *def = DEFAULT_TABLE(dfa); + u32 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); + u32 *next = NEXT_TABLE(dfa); + u32 *check = CHECK_TABLE(dfa); aa_state_t state = start; if (state == DFA_NOMATCH) @@ -472,10 +527,10 @@ aa_state_t aa_dfa_match(struct aa_dfa *dfa, aa_state_t start, const char *str) */ aa_state_t aa_dfa_next(struct aa_dfa *dfa, aa_state_t state, const char c) { - u16 *def = DEFAULT_TABLE(dfa); + u32 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); + u32 *next = NEXT_TABLE(dfa); + u32 *check = CHECK_TABLE(dfa); /* current state is , matching character *str */ if (dfa->tables[YYTD_ID_EC]) { @@ -490,10 +545,10 @@ aa_state_t aa_dfa_next(struct aa_dfa *dfa, aa_state_t state, const char c) aa_state_t aa_dfa_outofband_transition(struct aa_dfa *dfa, aa_state_t state) { - u16 *def = DEFAULT_TABLE(dfa); + u32 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); + u32 *next = NEXT_TABLE(dfa); + u32 *check = CHECK_TABLE(dfa); u32 b = (base)[(state)]; if (!(b & MATCH_FLAG_OOB_TRANSITION)) @@ -521,10 +576,10 @@ aa_state_t aa_dfa_outofband_transition(struct aa_dfa *dfa, aa_state_t state) aa_state_t aa_dfa_match_until(struct aa_dfa *dfa, aa_state_t start, const char *str, const char **retpos) { - u16 *def = DEFAULT_TABLE(dfa); + u32 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); + u32 *next = NEXT_TABLE(dfa); + u32 *check = CHECK_TABLE(dfa); u32 *accept = ACCEPT_TABLE(dfa); aa_state_t state = start, pos; @@ -582,10 +637,10 @@ aa_state_t aa_dfa_match_until(struct aa_dfa *dfa, aa_state_t start, aa_state_t aa_dfa_matchn_until(struct aa_dfa *dfa, aa_state_t start, const char *str, int n, const char **retpos) { - u16 *def = DEFAULT_TABLE(dfa); + u32 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); + u32 *next = NEXT_TABLE(dfa); + u32 *check = CHECK_TABLE(dfa); u32 *accept = ACCEPT_TABLE(dfa); aa_state_t state = start, pos; @@ -658,10 +713,10 @@ static aa_state_t leftmatch_fb(struct aa_dfa *dfa, aa_state_t start, const char *str, struct match_workbuf *wb, unsigned int *count) { - u16 *def = DEFAULT_TABLE(dfa); + u32 *def = DEFAULT_TABLE(dfa); u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); + u32 *next = NEXT_TABLE(dfa); + u32 *check = CHECK_TABLE(dfa); aa_state_t state = start, pos; AA_BUG(!dfa); diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 45ec994b558d7b..d6c74c357ffd59 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -130,7 +130,7 @@ static int d_namespace_path(const struct path *path, char *buf, char **name, /* handle error conditions - and still allow a partial path to * be returned. */ - if (!res || IS_ERR(res)) { + if (IS_ERR_OR_NULL(res)) { if (PTR_ERR(res) == -ENAMETOOLONG) { error = -ENAMETOOLONG; *name = buf; diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 14df15e3569525..d0244fab065308 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -103,8 +103,7 @@ static void aa_free_pdb(struct aa_policydb *pdb) { if (pdb) { aa_put_dfa(pdb->dfa); - if (pdb->perms) - kvfree(pdb->perms); + kvfree(pdb->perms); aa_free_str_table(&pdb->trans); kfree(pdb); } @@ -580,11 +579,6 @@ struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, return profile; } -struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) -{ - return aa_lookupn_profile(ns, hname, strlen(hname)); -} - struct aa_profile *aa_fqlookupn_profile(struct aa_label *base, const char *fqname, size_t n) { @@ -626,6 +620,7 @@ struct aa_profile *aa_alloc_null(struct aa_profile *parent, const char *name, /* TODO: ideally we should inherit abi from parent */ profile->label.flags |= FLAG_NULL; + profile->attach.xmatch = aa_get_pdb(nullpdb); rules = list_first_entry(&profile->rules, typeof(*rules), list); rules->file = aa_get_pdb(nullpdb); rules->policy = aa_get_pdb(nullpdb); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 3483c595f999fc..992b74c50d641e 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -645,10 +645,13 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_ruleset *rules) static bool unpack_perm(struct aa_ext *e, u32 version, struct aa_perms *perm) { + u32 reserved; + if (version != 1) return false; - return aa_unpack_u32(e, &perm->allow, NULL) && + /* reserved entry is for later expansion, discard for now */ + return aa_unpack_u32(e, &reserved, NULL) && aa_unpack_u32(e, &perm->allow, NULL) && aa_unpack_u32(e, &perm->deny, NULL) && aa_unpack_u32(e, &perm->subtree, NULL) && diff --git a/security/apparmor/policy_unpack_test.c b/security/apparmor/policy_unpack_test.c index c64733d6c98fbb..5b2ba88ae9e24b 100644 --- a/security/apparmor/policy_unpack_test.c +++ b/security/apparmor/policy_unpack_test.c @@ -44,7 +44,7 @@ #define TEST_ARRAY_BUF_OFFSET \ (TEST_NAMED_ARRAY_BUF_OFFSET + 3 + strlen(TEST_ARRAY_NAME) + 1) -MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); struct policy_unpack_fixture { struct aa_ext *e; @@ -281,6 +281,8 @@ static void policy_unpack_test_unpack_strdup_with_null_name(struct kunit *test) ((uintptr_t)puf->e->start <= (uintptr_t)string) && ((uintptr_t)string <= (uintptr_t)puf->e->end)); KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA); + + kfree(string); } static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test) @@ -296,6 +298,8 @@ static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test) ((uintptr_t)puf->e->start <= (uintptr_t)string) && ((uintptr_t)string <= (uintptr_t)puf->e->end)); KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA); + + kfree(string); } static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test) @@ -313,6 +317,8 @@ static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test) KUNIT_EXPECT_EQ(test, size, 0); KUNIT_EXPECT_NULL(test, string); KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start); + + kfree(string); } static void policy_unpack_test_unpack_nameX_with_null_name(struct kunit *test) diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c index 83d3d1e6d9dcb9..47dc08fc583e9a 100644 --- a/security/apparmor/secid.c +++ b/security/apparmor/secid.c @@ -39,20 +39,6 @@ int apparmor_display_secid_mode; * TODO: use secid_update in label replace */ -/** - * aa_secid_update - update a secid mapping to a new label - * @secid: secid to update - * @label: label the secid will now map to - */ -void aa_secid_update(u32 secid, struct aa_label *label) -{ - unsigned long flags; - - xa_lock_irqsave(&aa_secids, flags); - __xa_store(&aa_secids, secid, label, 0); - xa_unlock_irqrestore(&aa_secids, flags); -} - /* * see label for inverse aa_label_to_secid */ @@ -61,10 +47,10 @@ struct aa_label *aa_secid_to_label(u32 secid) return xa_load(&aa_secids, secid); } -int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +static int apparmor_label_to_secctx(struct aa_label *label, char **secdata, + u32 *seclen) { /* TODO: cache secctx and ref count so we don't have to recreate */ - struct aa_label *label = aa_secid_to_label(secid); int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT; int len; @@ -90,6 +76,23 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) return 0; } +int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) +{ + struct aa_label *label = aa_secid_to_label(secid); + + return apparmor_label_to_secctx(label, secdata, seclen); +} + +int apparmor_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, + u32 *seclen) +{ + struct aa_label *label; + + label = prop->apparmor.label; + + return apparmor_label_to_secctx(label, secdata, seclen); +} + int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) { struct aa_label *label; diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 3c323ca213d42c..c0d3b716d11fac 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -369,7 +369,7 @@ static inline void ima_process_queued_keys(void) {} /* LIM API function definitions */ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, - const struct cred *cred, u32 secid, int mask, + const struct cred *cred, struct lsm_prop *prop, int mask, enum ima_hooks func, int *pcr, struct ima_template_desc **template_desc, const char *func_data, unsigned int *allowed_algos); @@ -400,8 +400,8 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *filename); /* IMA policy related functions */ int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode, - const struct cred *cred, u32 secid, enum ima_hooks func, - int mask, int flags, int *pcr, + const struct cred *cred, struct lsm_prop *prop, + enum ima_hooks func, int mask, int flags, int *pcr, struct ima_template_desc **template_desc, const char *func_data, unsigned int *allowed_algos); void ima_init_policy(void); @@ -555,7 +555,7 @@ static inline void ima_filter_rule_free(void *lsmrule) { } -static inline int ima_filter_rule_match(u32 secid, u32 field, u32 op, +static inline int ima_filter_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *lsmrule) { return -EINVAL; diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 984e861f6e3328..c35ea613c9f8d4 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -165,7 +165,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * @idmap: idmap of the mount the inode was found from * @inode: pointer to the inode associated with the object being validated * @cred: pointer to credentials structure to validate - * @secid: secid of the task being validated + * @prop: properties of the task being validated * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXEC, * MAY_APPEND) * @func: caller identifier @@ -187,7 +187,7 @@ void ima_add_violation(struct file *file, const unsigned char *filename, * */ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, - const struct cred *cred, u32 secid, int mask, + const struct cred *cred, struct lsm_prop *prop, int mask, enum ima_hooks func, int *pcr, struct ima_template_desc **template_desc, const char *func_data, unsigned int *allowed_algos) @@ -196,7 +196,7 @@ int ima_get_action(struct mnt_idmap *idmap, struct inode *inode, flags &= ima_policy_flag; - return ima_match_policy(idmap, inode, cred, secid, func, mask, + return ima_match_policy(idmap, inode, cred, prop, func, mask, flags, pcr, template_desc, func_data, allowed_algos); } diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 656c709b974fdf..884a3533f7af21 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -73,13 +73,13 @@ bool is_ima_appraise_enabled(void) int ima_must_appraise(struct mnt_idmap *idmap, struct inode *inode, int mask, enum ima_hooks func) { - u32 secid; + struct lsm_prop prop; if (!ima_appraise) return 0; - security_current_getsecid_subj(&secid); - return ima_match_policy(idmap, inode, current_cred(), secid, + security_current_getlsmprop_subj(&prop); + return ima_match_policy(idmap, inode, current_cred(), &prop, func, mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL, NULL); } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 06132cf47016da..9b87556b03a7c0 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -206,8 +206,8 @@ static void ima_file_free(struct file *file) } static int process_measurement(struct file *file, const struct cred *cred, - u32 secid, char *buf, loff_t size, int mask, - enum ima_hooks func) + struct lsm_prop *prop, char *buf, loff_t size, + int mask, enum ima_hooks func) { struct inode *real_inode, *inode = file_inode(file); struct ima_iint_cache *iint = NULL; @@ -232,7 +232,7 @@ static int process_measurement(struct file *file, const struct cred *cred, * bitmask based on the appraise/audit/measurement policy. * Included is the appraise submask. */ - action = ima_get_action(file_mnt_idmap(file), inode, cred, secid, + action = ima_get_action(file_mnt_idmap(file), inode, cred, prop, mask, func, &pcr, &template_desc, NULL, &allowed_algos); violation_check = ((func == FILE_CHECK || func == MMAP_CHECK || @@ -443,23 +443,23 @@ static int process_measurement(struct file *file, const struct cred *cred, static int ima_file_mmap(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) { - u32 secid; + struct lsm_prop prop; int ret; if (!file) return 0; - security_current_getsecid_subj(&secid); + security_current_getlsmprop_subj(&prop); if (reqprot & PROT_EXEC) { - ret = process_measurement(file, current_cred(), secid, NULL, + ret = process_measurement(file, current_cred(), &prop, NULL, 0, MAY_EXEC, MMAP_CHECK_REQPROT); if (ret) return ret; } if (prot & PROT_EXEC) - return process_measurement(file, current_cred(), secid, NULL, + return process_measurement(file, current_cred(), &prop, NULL, 0, MAY_EXEC, MMAP_CHECK); return 0; @@ -488,9 +488,9 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, char *pathbuf = NULL; const char *pathname = NULL; struct inode *inode; + struct lsm_prop prop; int result = 0; int action; - u32 secid; int pcr; /* Is mprotect making an mmap'ed file executable? */ @@ -498,13 +498,13 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, !(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC)) return 0; - security_current_getsecid_subj(&secid); + security_current_getlsmprop_subj(&prop); inode = file_inode(vma->vm_file); action = ima_get_action(file_mnt_idmap(vma->vm_file), inode, - current_cred(), secid, MAY_EXEC, MMAP_CHECK, + current_cred(), &prop, MAY_EXEC, MMAP_CHECK, &pcr, &template, NULL, NULL); action |= ima_get_action(file_mnt_idmap(vma->vm_file), inode, - current_cred(), secid, MAY_EXEC, + current_cred(), &prop, MAY_EXEC, MMAP_CHECK_REQPROT, &pcr, &template, NULL, NULL); @@ -541,16 +541,16 @@ static int ima_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, static int ima_bprm_check(struct linux_binprm *bprm) { int ret; - u32 secid; + struct lsm_prop prop; - security_current_getsecid_subj(&secid); - ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0, - MAY_EXEC, BPRM_CHECK); + security_current_getlsmprop_subj(&prop); + ret = process_measurement(bprm->file, current_cred(), + &prop, NULL, 0, MAY_EXEC, BPRM_CHECK); if (ret) return ret; - security_cred_getsecid(bprm->cred, &secid); - return process_measurement(bprm->file, bprm->cred, secid, NULL, 0, + security_cred_getlsmprop(bprm->cred, &prop); + return process_measurement(bprm->file, bprm->cred, &prop, NULL, 0, MAY_EXEC, CREDS_CHECK); } @@ -566,10 +566,10 @@ static int ima_bprm_check(struct linux_binprm *bprm) */ static int ima_file_check(struct file *file, int mask) { - u32 secid; + struct lsm_prop prop; - security_current_getsecid_subj(&secid); - return process_measurement(file, current_cred(), secid, NULL, 0, + security_current_getlsmprop_subj(&prop); + return process_measurement(file, current_cred(), &prop, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK); } @@ -768,7 +768,7 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id, bool contents) { enum ima_hooks func; - u32 secid; + struct lsm_prop prop; /* * Do devices using pre-allocated memory run the risk of the @@ -788,9 +788,9 @@ static int ima_read_file(struct file *file, enum kernel_read_file_id read_id, /* Read entire file for all partial reads. */ func = read_idmap[read_id] ?: FILE_CHECK; - security_current_getsecid_subj(&secid); - return process_measurement(file, current_cred(), secid, NULL, - 0, MAY_READ, func); + security_current_getlsmprop_subj(&prop); + return process_measurement(file, current_cred(), &prop, NULL, 0, + MAY_READ, func); } const int read_idmap[READING_MAX_ID] = { @@ -818,7 +818,7 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id read_id) { enum ima_hooks func; - u32 secid; + struct lsm_prop prop; /* permit signed certs */ if (!file && read_id == READING_X509_CERTIFICATE) @@ -831,8 +831,8 @@ static int ima_post_read_file(struct file *file, char *buf, loff_t size, } func = read_idmap[read_id] ?: FILE_CHECK; - security_current_getsecid_subj(&secid); - return process_measurement(file, current_cred(), secid, buf, size, + security_current_getlsmprop_subj(&prop); + return process_measurement(file, current_cred(), &prop, buf, size, MAY_READ, func); } @@ -967,7 +967,7 @@ int process_buffer_measurement(struct mnt_idmap *idmap, int digest_hash_len = hash_digest_size[ima_hash_algo]; int violation = 0; int action = 0; - u32 secid; + struct lsm_prop prop; if (digest && digest_len < digest_hash_len) return -EINVAL; @@ -990,9 +990,9 @@ int process_buffer_measurement(struct mnt_idmap *idmap, * buffer measurements. */ if (func) { - security_current_getsecid_subj(&secid); + security_current_getlsmprop_subj(&prop); action = ima_get_action(idmap, inode, current_cred(), - secid, 0, func, &pcr, &template, + &prop, 0, func, &pcr, &template, func_data, NULL); if (!(action & IMA_MEASURE) && !digest) return -ENOENT; @@ -1062,19 +1062,16 @@ int process_buffer_measurement(struct mnt_idmap *idmap, */ void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) { - struct fd f; - if (!buf || !size) return; - f = fdget(kernel_fd); - if (!fd_file(f)) + CLASS(fd, f)(kernel_fd); + if (fd_empty(f)) return; process_buffer_measurement(file_mnt_idmap(fd_file(f)), file_inode(fd_file(f)), buf, size, "kexec-cmdline", KEXEC_CMDLINE, 0, NULL, false, NULL, 0); - fdput(f); } /** @@ -1114,7 +1111,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data); #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS /** - * ima_kernel_module_request - Prevent crypto-pkcs1pad(rsa,*) requests + * ima_kernel_module_request - Prevent crypto-pkcs1(rsa,*) requests * @kmod_name: kernel module name * * Avoid a verification loop where verifying the signature of the modprobe @@ -1128,7 +1125,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data); * algorithm on the fly, but crypto_larval_lookup() will try to use alg_name * in order to load a kernel module with same name. * - * Since we don't have any real "crypto-pkcs1pad(rsa,*)" kernel modules, + * Since we don't have any real "crypto-pkcs1(rsa,*)" kernel modules, * we are safe to fail such module request from crypto_larval_lookup(), and * avoid the verification loop. * @@ -1136,7 +1133,7 @@ EXPORT_SYMBOL_GPL(ima_measure_critical_data); */ static int ima_kernel_module_request(char *kmod_name) { - if (strncmp(kmod_name, "crypto-pkcs1pad(rsa,", 20) == 0) + if (strncmp(kmod_name, "crypto-pkcs1(rsa,", 17) == 0) return -EINVAL; return 0; diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 09da8e63923956..21a8e54c383f08 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -557,7 +557,7 @@ static bool ima_match_rule_data(struct ima_rule_entry *rule, * @idmap: idmap of the mount the inode was found from * @inode: a pointer to an inode * @cred: a pointer to a credentials structure for user validation - * @secid: the secid of the task to be validated + * @prop: LSM properties of the task to be validated * @func: LIM hook identifier * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) * @func_data: func specific data, may be NULL @@ -567,7 +567,7 @@ static bool ima_match_rule_data(struct ima_rule_entry *rule, static bool ima_match_rules(struct ima_rule_entry *rule, struct mnt_idmap *idmap, struct inode *inode, const struct cred *cred, - u32 secid, enum ima_hooks func, int mask, + struct lsm_prop *prop, enum ima_hooks func, int mask, const char *func_data) { int i; @@ -635,7 +635,7 @@ static bool ima_match_rules(struct ima_rule_entry *rule, return false; for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; - u32 osid; + struct lsm_prop inode_prop = { }; if (!lsm_rule->lsm[i].rule) { if (!lsm_rule->lsm[i].args_p) @@ -649,15 +649,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule, case LSM_OBJ_USER: case LSM_OBJ_ROLE: case LSM_OBJ_TYPE: - security_inode_getsecid(inode, &osid); - rc = ima_filter_rule_match(osid, lsm_rule->lsm[i].type, + security_inode_getlsmprop(inode, &inode_prop); + rc = ima_filter_rule_match(&inode_prop, + lsm_rule->lsm[i].type, Audit_equal, lsm_rule->lsm[i].rule); break; case LSM_SUBJ_USER: case LSM_SUBJ_ROLE: case LSM_SUBJ_TYPE: - rc = ima_filter_rule_match(secid, lsm_rule->lsm[i].type, + rc = ima_filter_rule_match(prop, lsm_rule->lsm[i].type, Audit_equal, lsm_rule->lsm[i].rule); break; @@ -720,7 +721,7 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * @inode: pointer to an inode for which the policy decision is being made * @cred: pointer to a credentials structure for which the policy decision is * being made - * @secid: LSM secid of the task to be validated + * @prop: LSM properties of the task to be validated * @func: IMA hook identifier * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) * @flags: IMA actions to consider (e.g. IMA_MEASURE | IMA_APPRAISE) @@ -737,8 +738,8 @@ static int get_subaction(struct ima_rule_entry *rule, enum ima_hooks func) * than writes so ima_match_policy() is classical RCU candidate. */ int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode, - const struct cred *cred, u32 secid, enum ima_hooks func, - int mask, int flags, int *pcr, + const struct cred *cred, struct lsm_prop *prop, + enum ima_hooks func, int mask, int flags, int *pcr, struct ima_template_desc **template_desc, const char *func_data, unsigned int *allowed_algos) { @@ -756,7 +757,7 @@ int ima_match_policy(struct mnt_idmap *idmap, struct inode *inode, if (!(entry->action & actmask)) continue; - if (!ima_match_rules(entry, idmap, inode, cred, secid, + if (!ima_match_rules(entry, idmap, inode, cred, prop, func, mask, func_data)) continue; diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index c097d356fa4535..4ed8e70c25ede6 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -241,31 +241,21 @@ SYSCALL_DEFINE3(landlock_create_ruleset, static struct landlock_ruleset *get_ruleset_from_fd(const int fd, const fmode_t mode) { - struct fd ruleset_f; + CLASS(fd, ruleset_f)(fd); struct landlock_ruleset *ruleset; - ruleset_f = fdget(fd); - if (!fd_file(ruleset_f)) + if (fd_empty(ruleset_f)) return ERR_PTR(-EBADF); /* Checks FD type and access right. */ - if (fd_file(ruleset_f)->f_op != &ruleset_fops) { - ruleset = ERR_PTR(-EBADFD); - goto out_fdput; - } - if (!(fd_file(ruleset_f)->f_mode & mode)) { - ruleset = ERR_PTR(-EPERM); - goto out_fdput; - } + if (fd_file(ruleset_f)->f_op != &ruleset_fops) + return ERR_PTR(-EBADFD); + if (!(fd_file(ruleset_f)->f_mode & mode)) + return ERR_PTR(-EPERM); ruleset = fd_file(ruleset_f)->private_data; - if (WARN_ON_ONCE(ruleset->num_layers != 1)) { - ruleset = ERR_PTR(-EINVAL); - goto out_fdput; - } + if (WARN_ON_ONCE(ruleset->num_layers != 1)) + return ERR_PTR(-EINVAL); landlock_get_ruleset(ruleset); - -out_fdput: - fdput(ruleset_f); return ruleset; } @@ -276,15 +266,12 @@ static struct landlock_ruleset *get_ruleset_from_fd(const int fd, */ static int get_path_from_fd(const s32 fd, struct path *const path) { - struct fd f; - int err = 0; + CLASS(fd_raw, f)(fd); BUILD_BUG_ON(!__same_type( fd, ((struct landlock_path_beneath_attr *)NULL)->parent_fd)); - /* Handles O_PATH. */ - f = fdget_raw(fd); - if (!fd_file(f)) + if (fd_empty(f)) return -EBADF; /* * Forbids ruleset FDs, internal filesystems (e.g. nsfs), including @@ -295,16 +282,12 @@ static int get_path_from_fd(const s32 fd, struct path *const path) (fd_file(f)->f_path.mnt->mnt_flags & MNT_INTERNAL) || (fd_file(f)->f_path.dentry->d_sb->s_flags & SB_NOUSER) || d_is_negative(fd_file(f)->f_path.dentry) || - IS_PRIVATE(d_backing_inode(fd_file(f)->f_path.dentry))) { - err = -EBADFD; - goto out_fdput; - } + IS_PRIVATE(d_backing_inode(fd_file(f)->f_path.dentry))) + return -EBADFD; + *path = fd_file(f)->f_path; path_get(path); - -out_fdput: - fdput(f); - return err; + return 0; } static int add_rule_path_beneath(struct landlock_ruleset *const ruleset, diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 02144ec39f4305..68252452b66cb9 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -283,7 +283,6 @@ enum loadpin_securityfs_interface_index { static int read_trusted_verity_root_digests(unsigned int fd) { - struct fd f; void *data; int rc; char *p, *d; @@ -295,8 +294,8 @@ static int read_trusted_verity_root_digests(unsigned int fd) if (!list_empty(&dm_verity_loadpin_trusted_root_digests)) return -EPERM; - f = fdget(fd); - if (!fd_file(f)) + CLASS(fd, f)(fd); + if (fd_empty(f)) return -EINVAL; data = kzalloc(SZ_4K, GFP_KERNEL); @@ -359,7 +358,6 @@ static int read_trusted_verity_root_digests(unsigned int fd) } kfree(data); - fdput(f); return 0; @@ -379,8 +377,6 @@ static int read_trusted_verity_root_digests(unsigned int fd) /* disallow further attempts after reading a corrupt/invalid file */ deny_reading_verity_digests = true; - fdput(f); - return rc; } diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 849e832719e215..9a8352972086cf 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -207,7 +207,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2); audit_log_format(ab, " pid=%d comm=", task_tgid_nr(current)); - audit_log_untrustedstring(ab, memcpy(comm, current->comm, sizeof(comm))); + audit_log_untrustedstring(ab, get_task_comm(comm, current)); switch (a->type) { case LSM_AUDIT_DATA_NONE: @@ -302,7 +302,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, char comm[sizeof(tsk->comm)]; audit_log_format(ab, " opid=%d ocomm=", pid); audit_log_untrustedstring(ab, - memcpy(comm, tsk->comm, sizeof(comm))); + get_task_comm(comm, tsk)); } } break; diff --git a/security/security.c b/security/security.c index c5981e558bc264..09664e09fec9a1 100644 --- a/security/security.c +++ b/security/security.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -2726,16 +2725,15 @@ int security_inode_listsecurity(struct inode *inode, EXPORT_SYMBOL(security_inode_listsecurity); /** - * security_inode_getsecid() - Get an inode's secid + * security_inode_getlsmprop() - Get an inode's LSM data * @inode: inode - * @secid: secid to return + * @prop: lsm specific information to return * - * Get the secid associated with the node. In case of failure, @secid will be - * set to zero. + * Get the lsm specific information associated with the node. */ -void security_inode_getsecid(struct inode *inode, u32 *secid) +void security_inode_getlsmprop(struct inode *inode, struct lsm_prop *prop) { - call_void_hook(inode_getsecid, inode, secid); + call_void_hook(inode_getlsmprop, inode, prop); } /** @@ -3104,13 +3102,7 @@ int security_file_receive(struct file *file) */ int security_file_open(struct file *file) { - int ret; - - ret = call_int_hook(file_open, file); - if (ret) - return ret; - - return fsnotify_open_perm(file); + return call_int_hook(file_open, file); } /** @@ -3275,6 +3267,21 @@ void security_cred_getsecid(const struct cred *c, u32 *secid) } EXPORT_SYMBOL(security_cred_getsecid); +/** + * security_cred_getlsmprop() - Get the LSM data from a set of credentials + * @c: credentials + * @prop: destination for the LSM data + * + * Retrieve the security data of the cred structure @c. In case of + * failure, @prop will be cleared. + */ +void security_cred_getlsmprop(const struct cred *c, struct lsm_prop *prop) +{ + lsmprop_init(prop); + call_void_hook(cred_getlsmprop, c, prop); +} +EXPORT_SYMBOL(security_cred_getlsmprop); + /** * security_kernel_act_as() - Set the kernel credentials to act as secid * @new: credentials @@ -3494,33 +3501,33 @@ int security_task_getsid(struct task_struct *p) } /** - * security_current_getsecid_subj() - Get the current task's subjective secid - * @secid: secid value + * security_current_getlsmprop_subj() - Current task's subjective LSM data + * @prop: lsm specific information * * Retrieve the subjective security identifier of the current task and return - * it in @secid. In case of failure, @secid will be set to zero. + * it in @prop. */ -void security_current_getsecid_subj(u32 *secid) +void security_current_getlsmprop_subj(struct lsm_prop *prop) { - *secid = 0; - call_void_hook(current_getsecid_subj, secid); + lsmprop_init(prop); + call_void_hook(current_getlsmprop_subj, prop); } -EXPORT_SYMBOL(security_current_getsecid_subj); +EXPORT_SYMBOL(security_current_getlsmprop_subj); /** - * security_task_getsecid_obj() - Get a task's objective secid + * security_task_getlsmprop_obj() - Get a task's objective LSM data * @p: target task - * @secid: secid value + * @prop: lsm specific information * * Retrieve the objective security identifier of the task_struct in @p and - * return it in @secid. In case of failure, @secid will be set to zero. + * return it in @prop. */ -void security_task_getsecid_obj(struct task_struct *p, u32 *secid) +void security_task_getlsmprop_obj(struct task_struct *p, struct lsm_prop *prop) { - *secid = 0; - call_void_hook(task_getsecid_obj, p, secid); + lsmprop_init(prop); + call_void_hook(task_getlsmprop_obj, p, prop); } -EXPORT_SYMBOL(security_task_getsecid_obj); +EXPORT_SYMBOL(security_task_getlsmprop_obj); /** * security_task_setnice() - Check if setting a task's nice value is allowed @@ -3732,17 +3739,17 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag) } /** - * security_ipc_getsecid() - Get the sysv ipc object's secid + * security_ipc_getlsmprop() - Get the sysv ipc object LSM data * @ipcp: ipc permission structure - * @secid: secid pointer + * @prop: pointer to lsm information * - * Get the secid associated with the ipc object. In case of failure, @secid - * will be set to zero. + * Get the lsm information associated with the ipc object. */ -void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) + +void security_ipc_getlsmprop(struct kern_ipc_perm *ipcp, struct lsm_prop *prop) { - *secid = 0; - call_void_hook(ipc_getsecid, ipcp, secid); + lsmprop_init(prop); + call_void_hook(ipc_getlsmprop, ipcp, prop); } /** @@ -4313,6 +4320,27 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) } EXPORT_SYMBOL(security_secid_to_secctx); +/** + * security_lsmprop_to_secctx() - Convert a lsm_prop to a secctx + * @prop: lsm specific information + * @secdata: secctx + * @seclen: secctx length + * + * Convert a @prop entry to security context. If @secdata is NULL the + * length of the result will be returned in @seclen, but no @secdata + * will be returned. This does mean that the length could change between + * calls to check the length and the next call which actually allocates + * and returns the @secdata. + * + * Return: Return 0 on success, error on failure. + */ +int security_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, + u32 *seclen) +{ + return call_int_hook(lsmprop_to_secctx, prop, secdata, seclen); +} +EXPORT_SYMBOL(security_lsmprop_to_secctx); + /** * security_secctx_to_secid() - Convert a secctx to a secid * @secdata: secctx @@ -5572,7 +5600,7 @@ void security_audit_rule_free(void *lsmrule) /** * security_audit_rule_match() - Check if a label matches an audit rule - * @secid: security label + * @prop: security label * @field: LSM audit field * @op: matching operator * @lsmrule: audit rule @@ -5583,9 +5611,10 @@ void security_audit_rule_free(void *lsmrule) * Return: Returns 1 if secid matches the rule, 0 if it does not, -ERRNO on * failure. */ -int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule) +int security_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, + void *lsmrule) { - return call_int_hook(audit_rule_match, secid, field, op, lsmrule); + return call_int_hook(audit_rule_match, prop, field, op, lsmrule); } #endif /* CONFIG_AUDIT */ diff --git a/security/selinux/.gitignore b/security/selinux/.gitignore index 168fae13ca5a9b..01c0df8ab009cf 100644 --- a/security/selinux/.gitignore +++ b/security/selinux/.gitignore @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only av_permissions.h flask.h +/genheaders diff --git a/security/selinux/Makefile b/security/selinux/Makefile index c47519ed81565e..86f0575f670da6 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -36,7 +36,10 @@ quiet_cmd_genhdrs = GEN $(addprefix $(obj)/,$(genhdrs)) # see the note above, replace the $targets and 'flask.h' rule with the lines # below: # targets += $(genhdrs) -# $(addprefix $(obj)/,$(genhdrs)) &: scripts/selinux/... +# $(addprefix $(obj)/,$(genhdrs)) &: $(obj)/genheaders FORCE targets += flask.h -$(obj)/flask.h: scripts/selinux/genheaders/genheaders FORCE +$(obj)/flask.h: $(obj)/genheaders FORCE $(call if_changed,genhdrs) + +hostprogs := genheaders +HOST_EXTRACFLAGS += -I$(srctree)/security/selinux/include diff --git a/security/selinux/genheaders.c b/security/selinux/genheaders.c new file mode 100644 index 00000000000000..3834d7eb0af666 --- /dev/null +++ b/security/selinux/genheaders.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include + +struct security_class_mapping { + const char *name; + const char *perms[sizeof(unsigned) * 8 + 1]; +}; + +#include "classmap.h" +#include "initial_sid_to_string.h" + +const char *progname; + +static void usage(void) +{ + printf("usage: %s flask.h av_permissions.h\n", progname); + exit(1); +} + +static char *stoupperx(const char *s) +{ + char *s2 = strdup(s); + char *p; + + if (!s2) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(3); + } + + for (p = s2; *p; p++) + *p = toupper(*p); + return s2; +} + +int main(int argc, char *argv[]) +{ + int i, j; + int isids_len; + FILE *fout; + + progname = argv[0]; + + if (argc < 3) + usage(); + + fout = fopen(argv[1], "w"); + if (!fout) { + fprintf(stderr, "Could not open %s for writing: %s\n", + argv[1], strerror(errno)); + exit(2); + } + + fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); + fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n"); + + for (i = 0; secclass_map[i].name; i++) { + char *name = stoupperx(secclass_map[i].name); + + fprintf(fout, "#define SECCLASS_%-39s %2d\n", name, i+1); + free(name); + } + + fprintf(fout, "\n"); + + isids_len = sizeof(initial_sid_to_string) / sizeof(char *); + for (i = 1; i < isids_len; i++) { + const char *s = initial_sid_to_string[i]; + if (s) { + char *sidname = stoupperx(s); + + fprintf(fout, "#define SECINITSID_%-39s %2d\n", sidname, i); + free(sidname); + } + } + fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1); + fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n"); + fprintf(fout, "{\n"); + fprintf(fout, "\tbool sock = false;\n\n"); + fprintf(fout, "\tswitch (kern_tclass) {\n"); + for (i = 0; secclass_map[i].name; i++) { + static char s[] = "SOCKET"; + int len, l; + char *name = stoupperx(secclass_map[i].name); + + len = strlen(name); + l = sizeof(s) - 1; + if (len >= l && memcmp(name + len - l, s, l) == 0) + fprintf(fout, "\tcase SECCLASS_%s:\n", name); + free(name); + } + fprintf(fout, "\t\tsock = true;\n"); + fprintf(fout, "\t\tbreak;\n"); + fprintf(fout, "\tdefault:\n"); + fprintf(fout, "\t\tbreak;\n"); + fprintf(fout, "\t}\n\n"); + fprintf(fout, "\treturn sock;\n"); + fprintf(fout, "}\n"); + + fprintf(fout, "\n#endif\n"); + + if (fclose(fout) != 0) { + fprintf(stderr, "Could not successfully close %s: %s\n", + argv[1], strerror(errno)); + exit(4); + } + + fout = fopen(argv[2], "w"); + if (!fout) { + fprintf(stderr, "Could not open %s for writing: %s\n", + argv[2], strerror(errno)); + exit(5); + } + + fprintf(fout, "/* This file is automatically generated. Do not edit. */\n"); + fprintf(fout, "#ifndef _SELINUX_AV_PERMISSIONS_H_\n#define _SELINUX_AV_PERMISSIONS_H_\n\n"); + + for (i = 0; secclass_map[i].name; i++) { + const struct security_class_mapping *map = &secclass_map[i]; + int len; + char *name = stoupperx(map->name); + + len = strlen(name); + for (j = 0; map->perms[j]; j++) { + char *permname; + + if (j >= 32) { + fprintf(stderr, "Too many permissions to fit into an access vector at (%s, %s).\n", + map->name, map->perms[j]); + exit(5); + } + permname = stoupperx(map->perms[j]); + fprintf(fout, "#define %s__%-*s 0x%08xU\n", name, + 39-len, permname, 1U<sid; + + prop->selinux.secid = isec->sid; } static int selinux_inode_copy_up(struct dentry *src, struct cred **new) { - u32 sid; + struct lsm_prop prop; struct task_security_struct *tsec; struct cred *new_creds = *new; @@ -3523,8 +3524,8 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new) tsec = selinux_cred(new_creds); /* Get label from overlay inode and set it in create_sid */ - selinux_inode_getsecid(d_inode(src), &sid); - tsec->create_sid = sid; + selinux_inode_getlsmprop(d_inode(src), &prop); + tsec->create_sid = prop.selinux.secid; *new = new_creds; return 0; } @@ -4034,6 +4035,11 @@ static void selinux_cred_getsecid(const struct cred *c, u32 *secid) *secid = cred_sid(c); } +static void selinux_cred_getlsmprop(const struct cred *c, struct lsm_prop *prop) +{ + prop->selinux.secid = cred_sid(c); +} + /* * set the security data for a kernel service * - all the creation contexts are set to unlabelled @@ -4169,14 +4175,15 @@ static int selinux_task_getsid(struct task_struct *p) PROCESS__GETSESSION, NULL); } -static void selinux_current_getsecid_subj(u32 *secid) +static void selinux_current_getlsmprop_subj(struct lsm_prop *prop) { - *secid = current_sid(); + prop->selinux.secid = current_sid(); } -static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid) +static void selinux_task_getlsmprop_obj(struct task_struct *p, + struct lsm_prop *prop) { - *secid = task_sid_obj(p); + prop->selinux.secid = task_sid_obj(p); } static int selinux_task_setnice(struct task_struct *p, int nice) @@ -4590,14 +4597,10 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec, secclass, NULL, socksid); } -static int sock_has_perm(struct sock *sk, u32 perms) +static bool sock_skip_has_perm(u32 sid) { - struct sk_security_struct *sksec = selinux_sock(sk); - struct common_audit_data ad; - struct lsm_network_audit net; - - if (sksec->sid == SECINITSID_KERNEL) - return 0; + if (sid == SECINITSID_KERNEL) + return true; /* * Before POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT, sockets that @@ -4611,7 +4614,19 @@ static int sock_has_perm(struct sock *sk, u32 perms) * setting. */ if (!selinux_policycap_userspace_initial_context() && - sksec->sid == SECINITSID_INIT) + sid == SECINITSID_INIT) + return true; + return false; +} + + +static int sock_has_perm(struct sock *sk, u32 perms) +{ + struct sk_security_struct *sksec = sk->sk_security; + struct common_audit_data ad; + struct lsm_network_audit net; + + if (sock_skip_has_perm(sksec->sid)) return 0; ad_net_init_from_sk(&ad, &net, sk); @@ -5723,7 +5738,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb, /* we do this in the LOCAL_OUT path and not the POST_ROUTING path * because we want to make sure we apply the necessary labeling * before IPsec is applied so we can leverage AH protection */ - sk = skb->sk; + sk = sk_to_full_sk(skb->sk); if (sk) { struct sk_security_struct *sksec; @@ -5920,6 +5935,26 @@ static unsigned int selinux_ip_postroute(void *priv, } #endif /* CONFIG_NETFILTER */ +static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_type) +{ + struct sk_security_struct *sksec = sk->sk_security; + struct common_audit_data ad; + struct lsm_network_audit net; + u8 driver; + u8 xperm; + + if (sock_skip_has_perm(sksec->sid)) + return 0; + + ad_net_init_from_sk(&ad, &net, sk); + + driver = nlmsg_type >> 8; + xperm = nlmsg_type & 0xff; + + return avc_has_extended_perms(current_sid(), sksec->sid, sksec->sclass, + perms, driver, xperm, &ad); +} + static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) { int rc = 0; @@ -5945,7 +5980,12 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm); if (rc == 0) { - rc = sock_has_perm(sk, perm); + if (selinux_policycap_netlink_xperm()) { + rc = nlmsg_sock_has_extended_perms( + sk, perm, nlh->nlmsg_type); + } else { + rc = sock_has_perm(sk, perm); + } if (rc) return rc; } else if (rc == -EINVAL) { @@ -6319,10 +6359,11 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) return ipc_has_perm(ipcp, av); } -static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) +static void selinux_ipc_getlsmprop(struct kern_ipc_perm *ipcp, + struct lsm_prop *prop) { struct ipc_security_struct *isec = selinux_ipc(ipcp); - *secid = isec->sid; + prop->selinux.secid = isec->sid; } static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode) @@ -6601,8 +6642,13 @@ static int selinux_ismaclabel(const char *name) static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { - return security_sid_to_context(secid, - secdata, seclen); + return security_sid_to_context(secid, secdata, seclen); +} + +static int selinux_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, + u32 *seclen) +{ + return selinux_secid_to_secctx(prop->selinux.secid, secdata, seclen); } static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) @@ -7155,7 +7201,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity), LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity), LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity), - LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid), + LSM_HOOK_INIT(inode_getlsmprop, selinux_inode_getlsmprop), LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), LSM_HOOK_INIT(path_notify, selinux_path_notify), @@ -7181,6 +7227,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer), LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid), + LSM_HOOK_INIT(cred_getlsmprop, selinux_cred_getlsmprop), LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as), LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as), LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request), @@ -7189,8 +7236,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid), LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid), LSM_HOOK_INIT(task_getsid, selinux_task_getsid), - LSM_HOOK_INIT(current_getsecid_subj, selinux_current_getsecid_subj), - LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_obj), + LSM_HOOK_INIT(current_getlsmprop_subj, selinux_current_getlsmprop_subj), + LSM_HOOK_INIT(task_getlsmprop_obj, selinux_task_getlsmprop_obj), LSM_HOOK_INIT(task_setnice, selinux_task_setnice), LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio), LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio), @@ -7204,7 +7251,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(userns_create, selinux_userns_create), LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission), - LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid), + LSM_HOOK_INIT(ipc_getlsmprop, selinux_ipc_getlsmprop), LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate), LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl), @@ -7347,6 +7394,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security), LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security), LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx), + LSM_HOOK_INIT(lsmprop_to_secctx, selinux_lsmprop_to_secctx), LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx), LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security), LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security), diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h index 168d17be7df3b9..d5b0425055e424 100644 --- a/security/selinux/include/audit.h +++ b/security/selinux/include/audit.h @@ -41,7 +41,7 @@ void selinux_audit_rule_free(void *rule); /** * selinux_audit_rule_match - determine if a context ID matches a rule. - * @sid: the context ID to check + * @prop: includes the context ID to check * @field: the field this rule refers to * @op: the operator the rule uses * @rule: pointer to the audit rule to check against @@ -49,7 +49,8 @@ void selinux_audit_rule_free(void *rule); * Returns 1 if the context id matches the rule, 0 if it does not, and * -errno on failure. */ -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule); +int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, + void *rule); /** * selinux_audit_rule_known - check to see if rule contains selinux fields. diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 7229c9bf6c2703..2bc20135324a08 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -1,8 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#include -#include - #define COMMON_FILE_SOCK_PERMS \ "ioctl", "read", "write", "create", "getattr", "setattr", "lock", \ "relabelfrom", "relabelto", "append", "map" @@ -36,9 +33,13 @@ "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", \ "audit_read", "perfmon", "bpf", "checkpoint_restore" +#ifdef __KERNEL__ /* avoid this check when building host programs */ +#include + #if CAP_LAST_CAP > CAP_CHECKPOINT_RESTORE #error New capability defined, please update COMMON_CAP2_PERMS. #endif +#endif /* * Note: The name for any socket class should be suffixed by "socket", @@ -96,17 +97,17 @@ const struct security_class_mapping secclass_map[] = { { "shm", { COMMON_IPC_PERMS, "lock", NULL } }, { "ipc", { COMMON_IPC_PERMS, NULL } }, { "netlink_route_socket", - { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } }, + { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", "nlmsg", NULL } }, { "netlink_tcpdiag_socket", - { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } }, + { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", "nlmsg", NULL } }, { "netlink_nflog_socket", { COMMON_SOCK_PERMS, NULL } }, { "netlink_xfrm_socket", - { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } }, + { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", "nlmsg", NULL } }, { "netlink_selinux_socket", { COMMON_SOCK_PERMS, NULL } }, { "netlink_iscsi_socket", { COMMON_SOCK_PERMS, NULL } }, { "netlink_audit_socket", { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", "nlmsg_relay", - "nlmsg_readpriv", "nlmsg_tty_audit", NULL } }, + "nlmsg_readpriv", "nlmsg_tty_audit", "nlmsg", NULL } }, { "netlink_fib_lookup_socket", { COMMON_SOCK_PERMS, NULL } }, { "netlink_connector_socket", { COMMON_SOCK_PERMS, NULL } }, { "netlink_netfilter_socket", { COMMON_SOCK_PERMS, NULL } }, @@ -181,6 +182,10 @@ const struct security_class_mapping secclass_map[] = { { NULL } }; +#ifdef __KERNEL__ /* avoid this check when building host programs */ +#include + #if PF_MAX > 46 #error New address family defined, please update secclass_map. #endif +#endif diff --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h index 99b353b2abb413..d7ba60b6249185 100644 --- a/security/selinux/include/initial_sid_to_string.h +++ b/security/selinux/include/initial_sid_to_string.h @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifdef __KERNEL__ #include +#else +#include +#endif static const char *const initial_sid_to_string[] = { NULL, /* zero placeholder, not used */ diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h index dc3674eb29c18c..079679fe7254b0 100644 --- a/security/selinux/include/policycap.h +++ b/security/selinux/include/policycap.h @@ -14,6 +14,7 @@ enum { POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS, POLICYDB_CAP_IOCTL_SKIP_CLOEXEC, POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT, + POLICYDB_CAP_NETLINK_XPERM, __POLICYDB_CAP_MAX }; #define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1) diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h index 2cffcc1ce85191..e080827408c4c8 100644 --- a/security/selinux/include/policycap_names.h +++ b/security/selinux/include/policycap_names.h @@ -17,6 +17,7 @@ const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = { "genfs_seclabel_symlinks", "ioctl_skip_cloexec", "userspace_initial_context", + "netlink_xperm", }; /* clang-format on */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 289bf9233f7147..c7f2731abd03e8 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -195,6 +195,12 @@ static inline bool selinux_policycap_userspace_initial_context(void) selinux_state.policycap[POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT]); } +static inline bool selinux_policycap_netlink_xperm(void) +{ + return READ_ONCE( + selinux_state.policycap[POLICYDB_CAP_NETLINK_XPERM]); +} + struct selinux_policy_convert_data; struct selinux_load_state { diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 8ff670cf1ee599..3a95986b134f28 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -21,142 +21,142 @@ #include "security.h" struct nlmsg_perm { - u16 nlmsg_type; - u32 perm; + u16 nlmsg_type; + u32 perm; }; static const struct nlmsg_perm nlmsg_route_perms[] = { - { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_SETLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_NEWADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETADDR, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETROUTE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETQDISC, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETACTION, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_SETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_NEWADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_GETDCB, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_NEWNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETMDB, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWNSID, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_GETNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_SETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_NEWCACHEREPORT, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_NEWVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETVLAN, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - { RTM_NEWTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_SETLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_NEWADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETADDR, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETROUTE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETQDISC, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETACTION, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_SETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_NEWADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_GETDCB, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_NEWNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETMDB, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWNSID, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_GETNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_SETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_NEWCACHEREPORT, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_NEWVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETVLAN, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ }, + { RTM_NEWTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_DELTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, + { RTM_GETTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_READ }, }; static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = { - { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, - { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, - { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, - { SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE }, + { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, + { SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE }, }; static const struct nlmsg_perm nlmsg_xfrm_perms[] = { - { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ }, - { XFRM_MSG_NEWPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ }, - { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_ACQUIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_EXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_POLEXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_FLUSHSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, - { XFRM_MSG_REPORT, NETLINK_XFRM_SOCKET__NLMSG_READ }, - { XFRM_MSG_MIGRATE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, - { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, - { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, - { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ }, - { XFRM_MSG_SETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, - { XFRM_MSG_GETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_NEWPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_ACQUIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_EXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_POLEXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_FLUSHSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_REPORT, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_MIGRATE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_SETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_READ }, }; static const struct nlmsg_perm nlmsg_audit_perms[] = { - { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, - { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV }, - { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV }, - { AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, - { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, - { AUDIT_TRIM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, - { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, - { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT }, - { AUDIT_GET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_READ }, - { AUDIT_SET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV }, + { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV }, + { AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY }, + { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_TRIM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, + { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT }, + { AUDIT_GET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_READ }, + { AUDIT_SET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE }, }; - -static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab, size_t tabsize) +static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab, + size_t tabsize) { unsigned int i; int err = -EINVAL; - for (i = 0; i < tabsize/sizeof(struct nlmsg_perm); i++) + for (i = 0; i < tabsize / sizeof(struct nlmsg_perm); i++) if (nlmsg_type == tab[i].nlmsg_type) { *perm = tab[i].perm; err = 0; @@ -168,7 +168,12 @@ static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab, s int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) { - int err = 0; + /* While it is possible to add a similar permission to other netlink + * classes, note that the extended permission value is matched against + * the nlmsg_type field. Notably, SECCLASS_NETLINK_GENERIC_SOCKET uses + * dynamic values for this field, which means that it cannot be added + * as-is. + */ switch (sclass) { case SECCLASS_NETLINK_ROUTE_SOCKET: @@ -178,42 +183,52 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) * before updating the BUILD_BUG_ON() macro! */ BUILD_BUG_ON(RTM_MAX != (RTM_NEWTUNNEL + 3)); - err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, - sizeof(nlmsg_route_perms)); - break; + if (selinux_policycap_netlink_xperm()) { + *perm = NETLINK_ROUTE_SOCKET__NLMSG; + return 0; + } + return nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, + sizeof(nlmsg_route_perms)); + break; case SECCLASS_NETLINK_TCPDIAG_SOCKET: - err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms, - sizeof(nlmsg_tcpdiag_perms)); + if (selinux_policycap_netlink_xperm()) { + *perm = NETLINK_TCPDIAG_SOCKET__NLMSG; + return 0; + } + return nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms, + sizeof(nlmsg_tcpdiag_perms)); break; - case SECCLASS_NETLINK_XFRM_SOCKET: /* If the BUILD_BUG_ON() below fails you must update the * structures at the top of this file with the new mappings * before updating the BUILD_BUG_ON() macro! */ BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_GETDEFAULT); - err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms, - sizeof(nlmsg_xfrm_perms)); - break; + if (selinux_policycap_netlink_xperm()) { + *perm = NETLINK_XFRM_SOCKET__NLMSG; + return 0; + } + return nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms, + sizeof(nlmsg_xfrm_perms)); + break; case SECCLASS_NETLINK_AUDIT_SOCKET: - if ((nlmsg_type >= AUDIT_FIRST_USER_MSG && - nlmsg_type <= AUDIT_LAST_USER_MSG) || - (nlmsg_type >= AUDIT_FIRST_USER_MSG2 && - nlmsg_type <= AUDIT_LAST_USER_MSG2)) { + if (selinux_policycap_netlink_xperm()) { + *perm = NETLINK_AUDIT_SOCKET__NLMSG; + return 0; + } else if ((nlmsg_type >= AUDIT_FIRST_USER_MSG && + nlmsg_type <= AUDIT_LAST_USER_MSG) || + (nlmsg_type >= AUDIT_FIRST_USER_MSG2 && + nlmsg_type <= AUDIT_LAST_USER_MSG2)) { *perm = NETLINK_AUDIT_SOCKET__NLMSG_RELAY; - } else { - err = nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms, - sizeof(nlmsg_audit_perms)); + return 0; } - break; - - /* No messaging from userspace, or class unknown/unhandled */ - default: - err = -ENOENT; + return nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms, + sizeof(nlmsg_audit_perms)); break; } - return err; + /* No messaging from userspace, or class unknown/unhandled */ + return -ENOENT; } diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index e172f182b65cc3..6cd5bb0ba380c8 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -708,7 +708,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, if (new_value) { char comm[sizeof(current->comm)]; - memcpy(comm, current->comm, sizeof(comm)); + strscpy(comm, current->comm); pr_err("SELinux: %s (%d) set checkreqprot to 1. This is no longer supported.\n", comm, current->pid); } @@ -1069,6 +1069,10 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) int rc; u32 i, len, nsids; + pr_warn_ratelimited("SELinux: %s (%d) wrote to /sys/fs/selinux/user!" + " This will not be supported in the future; please update your" + " userspace.\n", current->comm, current->pid); + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__COMPUTE_USER, NULL); diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index 8e8820484c55b3..f4407185401c39 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -53,8 +53,9 @@ struct avtab_key { */ struct avtab_extended_perms { /* These are not flags. All 256 values may be used */ -#define AVTAB_XPERMS_IOCTLFUNCTION 0x01 -#define AVTAB_XPERMS_IOCTLDRIVER 0x02 +#define AVTAB_XPERMS_IOCTLFUNCTION 0x01 +#define AVTAB_XPERMS_IOCTLDRIVER 0x02 +#define AVTAB_XPERMS_NLMSG 0x03 /* extension of the avtab_key specified */ u8 specified; /* ioctl, netfilter, ... */ /* diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index a9830fbfc5c66c..3d5c563cfc4c86 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -582,8 +582,7 @@ static void type_attribute_bounds_av(struct policydb *policydb, } /* - * flag which drivers have permissions - * only looking for ioctl based extended permissions + * Flag which drivers have permissions. */ void services_compute_xperms_drivers( struct extended_perms *xperms, @@ -591,14 +590,18 @@ void services_compute_xperms_drivers( { unsigned int i; - if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + switch (node->datum.u.xperms->specified) { + case AVTAB_XPERMS_IOCTLDRIVER: /* if one or more driver has all permissions allowed */ for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; - } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + break; + case AVTAB_XPERMS_IOCTLFUNCTION: + case AVTAB_XPERMS_NLMSG: /* if allowing permissions within a driver */ security_xperm_set(xperms->drivers.p, node->datum.u.xperms->driver); + break; } xperms->len = 1; @@ -942,57 +945,64 @@ static void avd_init(struct selinux_policy *policy, struct av_decision *avd) avd->flags = 0; } -void services_compute_xperms_decision(struct extended_perms_decision *xpermd, - struct avtab_node *node) +static void update_xperms_extended_data(u8 specified, + struct extended_perms_data *from, + struct extended_perms_data *xp_data) { unsigned int i; - if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + switch (specified) { + case AVTAB_XPERMS_IOCTLDRIVER: + memset(xp_data->p, 0xff, sizeof(xp_data->p)); + break; + case AVTAB_XPERMS_IOCTLFUNCTION: + case AVTAB_XPERMS_NLMSG: + for (i = 0; i < ARRAY_SIZE(xp_data->p); i++) + xp_data->p[i] |= from->p[i]; + break; + } + +} + +void services_compute_xperms_decision(struct extended_perms_decision *xpermd, + struct avtab_node *node) +{ + switch (node->datum.u.xperms->specified) { + case AVTAB_XPERMS_IOCTLFUNCTION: + case AVTAB_XPERMS_NLMSG: if (xpermd->driver != node->datum.u.xperms->driver) return; - } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + break; + case AVTAB_XPERMS_IOCTLDRIVER: if (!security_xperm_test(node->datum.u.xperms->perms.p, xpermd->driver)) return; - } else { - BUG(); + break; + default: + pr_warn_once( + "SELinux: unknown extended permission (%u) will be ignored\n", + node->datum.u.xperms->specified); + return; } if (node->key.specified == AVTAB_XPERMS_ALLOWED) { xpermd->used |= XPERMS_ALLOWED; - if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { - memset(xpermd->allowed->p, 0xff, - sizeof(xpermd->allowed->p)); - } - if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { - for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) - xpermd->allowed->p[i] |= - node->datum.u.xperms->perms.p[i]; - } + update_xperms_extended_data(node->datum.u.xperms->specified, + &node->datum.u.xperms->perms, + xpermd->allowed); } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { xpermd->used |= XPERMS_AUDITALLOW; - if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { - memset(xpermd->auditallow->p, 0xff, - sizeof(xpermd->auditallow->p)); - } - if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { - for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) - xpermd->auditallow->p[i] |= - node->datum.u.xperms->perms.p[i]; - } + update_xperms_extended_data(node->datum.u.xperms->specified, + &node->datum.u.xperms->perms, + xpermd->auditallow); } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { xpermd->used |= XPERMS_DONTAUDIT; - if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { - memset(xpermd->dontaudit->p, 0xff, - sizeof(xpermd->dontaudit->p)); - } - if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { - for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) - xpermd->dontaudit->p[i] |= - node->datum.u.xperms->perms.p[i]; - } + update_xperms_extended_data(node->datum.u.xperms->specified, + &node->datum.u.xperms->perms, + xpermd->dontaudit); } else { - BUG(); + pr_warn_once("SELinux: unknown specified key (%u)\n", + node->key.specified); } } @@ -3635,7 +3645,7 @@ int selinux_audit_rule_known(struct audit_krule *rule) return 0; } -int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) +int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vrule) { struct selinux_state *state = &selinux_state; struct selinux_policy *policy; @@ -3661,10 +3671,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) goto out; } - ctxt = sidtab_search(policy->sidtab, sid); + ctxt = sidtab_search(policy->sidtab, prop->selinux.secid); if (unlikely(!ctxt)) { WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", - sid); + prop->selinux.secid); match = -ENOENT; goto out; } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 370fd594da1252..0c476282e27945 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1649,15 +1649,13 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer, } /** - * smack_inode_getsecid - Extract inode's security id + * smack_inode_getlsmprop - Extract inode's security id * @inode: inode to extract the info from - * @secid: where result will be saved + * @prop: where result will be saved */ -static void smack_inode_getsecid(struct inode *inode, u32 *secid) +static void smack_inode_getlsmprop(struct inode *inode, struct lsm_prop *prop) { - struct smack_known *skp = smk_of_inode(inode); - - *secid = skp->smk_secid; + prop->smack.skp = smk_of_inode(inode); } /* @@ -2148,6 +2146,21 @@ static void smack_cred_getsecid(const struct cred *cred, u32 *secid) rcu_read_unlock(); } +/** + * smack_cred_getlsmprop - get the Smack label for a creds structure + * @cred: the object creds + * @prop: where to put the data + * + * Sets the Smack part of the ref + */ +static void smack_cred_getlsmprop(const struct cred *cred, + struct lsm_prop *prop) +{ + rcu_read_lock(); + prop->smack.skp = smk_of_task(smack_cred(cred)); + rcu_read_unlock(); +} + /** * smack_kernel_act_as - Set the subjective context in a set of credentials * @new: points to the set of credentials to be modified. @@ -2239,30 +2252,27 @@ static int smack_task_getsid(struct task_struct *p) } /** - * smack_current_getsecid_subj - get the subjective secid of the current task - * @secid: where to put the result + * smack_current_getlsmprop_subj - get the subjective secid of the current task + * @prop: where to put the result * * Sets the secid to contain a u32 version of the task's subjective smack label. */ -static void smack_current_getsecid_subj(u32 *secid) +static void smack_current_getlsmprop_subj(struct lsm_prop *prop) { - struct smack_known *skp = smk_of_current(); - - *secid = skp->smk_secid; + prop->smack.skp = smk_of_current(); } /** - * smack_task_getsecid_obj - get the objective secid of the task + * smack_task_getlsmprop_obj - get the objective data of the task * @p: the task - * @secid: where to put the result + * @prop: where to put the result * * Sets the secid to contain a u32 version of the task's objective smack label. */ -static void smack_task_getsecid_obj(struct task_struct *p, u32 *secid) +static void smack_task_getlsmprop_obj(struct task_struct *p, + struct lsm_prop *prop) { - struct smack_known *skp = smk_of_task_struct_obj(p); - - *secid = skp->smk_secid; + prop->smack.skp = smk_of_task_struct_obj(p); } /** @@ -3435,16 +3445,15 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) } /** - * smack_ipc_getsecid - Extract smack security id + * smack_ipc_getlsmprop - Extract smack security data * @ipp: the object permissions - * @secid: where result will be saved + * @prop: where result will be saved */ -static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) +static void smack_ipc_getlsmprop(struct kern_ipc_perm *ipp, struct lsm_prop *prop) { - struct smack_known **blob = smack_ipc(ipp); - struct smack_known *iskp = *blob; + struct smack_known **iskpp = smack_ipc(ipp); - *secid = iskp->smk_secid; + prop->smack.skp = *iskpp; } /** @@ -4757,7 +4766,7 @@ static int smack_audit_rule_known(struct audit_krule *krule) /** * smack_audit_rule_match - Audit given object ? - * @secid: security id for identifying the object to test + * @prop: security id for identifying the object to test * @field: audit rule flags given from user-space * @op: required testing operator * @vrule: smack internal rule presentation @@ -4765,9 +4774,10 @@ static int smack_audit_rule_known(struct audit_krule *krule) * The core Audit hook. It's used to take the decision of * whether to audit or not to audit a given object. */ -static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule) +static int smack_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, + void *vrule) { - struct smack_known *skp; + struct smack_known *skp = prop->smack.skp; char *rule = vrule; if (unlikely(!rule)) { @@ -4778,8 +4788,6 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule) if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) return 0; - skp = smack_from_secid(secid); - /* * No need to do string comparisons. If a match occurs, * both pointers will point to the same smack_known @@ -4809,7 +4817,6 @@ static int smack_ismaclabel(const char *name) return (strcmp(name, XATTR_SMACK_SUFFIX) == 0); } - /** * smack_secid_to_secctx - return the smack label for a secid * @secid: incoming integer @@ -4828,6 +4835,25 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) return 0; } +/** + * smack_lsmprop_to_secctx - return the smack label + * @prop: includes incoming Smack data + * @secdata: destination + * @seclen: how long it is + * + * Exists for audit code. + */ +static int smack_lsmprop_to_secctx(struct lsm_prop *prop, char **secdata, + u32 *seclen) +{ + struct smack_known *skp = prop->smack.skp; + + if (secdata) + *secdata = skp->smk_known; + *seclen = strlen(skp->smk_known); + return 0; +} + /** * smack_secctx_to_secid - return the secid for a smack label * @secdata: smack label @@ -5078,7 +5104,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = { LSM_HOOK_INIT(inode_getsecurity, smack_inode_getsecurity), LSM_HOOK_INIT(inode_setsecurity, smack_inode_setsecurity), LSM_HOOK_INIT(inode_listsecurity, smack_inode_listsecurity), - LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid), + LSM_HOOK_INIT(inode_getlsmprop, smack_inode_getlsmprop), LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security), LSM_HOOK_INIT(file_ioctl, smack_file_ioctl), @@ -5098,13 +5124,14 @@ static struct security_hook_list smack_hooks[] __ro_after_init = { LSM_HOOK_INIT(cred_prepare, smack_cred_prepare), LSM_HOOK_INIT(cred_transfer, smack_cred_transfer), LSM_HOOK_INIT(cred_getsecid, smack_cred_getsecid), + LSM_HOOK_INIT(cred_getlsmprop, smack_cred_getlsmprop), LSM_HOOK_INIT(kernel_act_as, smack_kernel_act_as), LSM_HOOK_INIT(kernel_create_files_as, smack_kernel_create_files_as), LSM_HOOK_INIT(task_setpgid, smack_task_setpgid), LSM_HOOK_INIT(task_getpgid, smack_task_getpgid), LSM_HOOK_INIT(task_getsid, smack_task_getsid), - LSM_HOOK_INIT(current_getsecid_subj, smack_current_getsecid_subj), - LSM_HOOK_INIT(task_getsecid_obj, smack_task_getsecid_obj), + LSM_HOOK_INIT(current_getlsmprop_subj, smack_current_getlsmprop_subj), + LSM_HOOK_INIT(task_getlsmprop_obj, smack_task_getlsmprop_obj), LSM_HOOK_INIT(task_setnice, smack_task_setnice), LSM_HOOK_INIT(task_setioprio, smack_task_setioprio), LSM_HOOK_INIT(task_getioprio, smack_task_getioprio), @@ -5115,7 +5142,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = { LSM_HOOK_INIT(task_to_inode, smack_task_to_inode), LSM_HOOK_INIT(ipc_permission, smack_ipc_permission), - LSM_HOOK_INIT(ipc_getsecid, smack_ipc_getsecid), + LSM_HOOK_INIT(ipc_getlsmprop, smack_ipc_getlsmprop), LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security), @@ -5187,6 +5214,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = { LSM_HOOK_INIT(ismaclabel, smack_ismaclabel), LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx), + LSM_HOOK_INIT(lsmprop_to_secctx, smack_lsmprop_to_secctx), LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid), LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx), LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx), diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 5dd1e164f9b13d..1401412fd79488 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -182,11 +182,9 @@ static inline void smack_catset_bit(unsigned int cat, char *catsetp) */ static void smk_netlabel_audit_set(struct netlbl_audit *nap) { - struct smack_known *skp = smk_of_current(); - nap->loginuid = audit_get_loginuid(current); nap->sessionid = audit_get_sessionid(current); - nap->secid = skp->smk_secid; + nap->prop.smack.skp = smk_of_current(); } /* diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index 96d4d7eb879f3a..8dfffdc101a256 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -180,7 +180,7 @@ static int ac97_bus_reset(struct ac97_controller *ac97_ctrl) /** * snd_ac97_codec_driver_register - register an AC97 codec driver - * @dev: AC97 driver codec to register + * @drv: AC97 driver codec to register * * Register an AC97 codec driver to the ac97 bus driver, aka. the AC97 digital * controller. @@ -196,7 +196,7 @@ EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_register); /** * snd_ac97_codec_driver_unregister - unregister an AC97 codec driver - * @dev: AC97 codec driver to unregister + * @drv: AC97 codec driver to unregister * * Unregister a previously registered ac97 codec driver. */ @@ -338,6 +338,7 @@ static int ac97_add_adapter(struct ac97_controller *ac97_ctrl) * @dev: the device providing the ac97 DC function * @slots_available: mask of the ac97 codecs that can be scanned and probed * bit0 => codec 0, bit1 => codec 1 ... bit 3 => codec 3 + * @codecs_pdata: codec platform data * * Register a digital controller which can control up to 4 ac97 codecs. This is * the controller side of the AC97 AC-link, while the slave side are the codecs. diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 4c367e73b2c9b3..77b11616a7ee05 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -271,7 +271,7 @@ static void pxa2xx_ac97_remove(struct platform_device *dev) static struct platform_driver pxa2xx_ac97_driver = { .probe = pxa2xx_ac97_probe, - .remove_new = pxa2xx_ac97_remove, + .remove = pxa2xx_ac97_remove, .driver = { .name = "pxa2xx-ac97", .pm = &pxa2xx_ac97_pm_ops, diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 402b5f66dcc302..d8f8e08f1bb7ef 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -861,7 +861,7 @@ static void atmel_ac97c_remove(struct platform_device *pdev) static struct platform_driver atmel_ac97c_driver = { .probe = atmel_ac97c_probe, - .remove_new = atmel_ac97c_remove, + .remove = atmel_ac97c_remove, .driver = { .name = "atmel_ac97c", .pm = ATMEL_AC97C_PM_OPS, diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 2c5b9f964703d0..48db44fa56feb1 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -59,6 +59,9 @@ config SND_CORE_TEST config SND_COMPRESS_OFFLOAD tristate +config SND_COMPRESS_ACCEL + bool + config SND_JACK bool diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index bdf1d78de8338a..86ed2fbee0c867 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,12 @@ struct snd_compr_file { static void error_delayed_work(struct work_struct *work); +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) +static void snd_compr_task_free_all(struct snd_compr_stream *stream); +#else +static inline void snd_compr_task_free_all(struct snd_compr_stream *stream) { } +#endif + /* * a note on stream states used: * we use following states in the compressed core @@ -85,6 +92,8 @@ static int snd_compr_open(struct inode *inode, struct file *f) dirn = SND_COMPRESS_PLAYBACK; else if ((f->f_flags & O_ACCMODE) == O_RDONLY) dirn = SND_COMPRESS_CAPTURE; + else if ((f->f_flags & O_ACCMODE) == O_RDWR) + dirn = SND_COMPRESS_ACCEL; else return -EINVAL; @@ -125,6 +134,9 @@ static int snd_compr_open(struct inode *inode, struct file *f) } runtime->state = SNDRV_PCM_STATE_OPEN; init_waitqueue_head(&runtime->sleep); +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + INIT_LIST_HEAD(&runtime->tasks); +#endif data->stream.runtime = runtime; f->private_data = (void *)data; scoped_guard(mutex, &compr->lock) @@ -154,6 +166,8 @@ static int snd_compr_free(struct inode *inode, struct file *f) break; } + snd_compr_task_free_all(&data->stream); + data->stream.ops->free(&data->stream); if (!data->stream.runtime->dma_buffer_p) kfree(data->stream.runtime->buffer); @@ -226,6 +240,9 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) struct snd_compr_avail ioctl_avail; size_t avail; + if (stream->direction == SND_COMPRESS_ACCEL) + return -EBADFD; + avail = snd_compr_calc_avail(stream, &ioctl_avail); ioctl_avail.avail = avail; @@ -287,6 +304,8 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf, return -EFAULT; stream = &data->stream; + if (stream->direction == SND_COMPRESS_ACCEL) + return -EBADFD; guard(mutex)(&stream->device->lock); /* write is allowed when stream is running or has been setup */ switch (stream->runtime->state) { @@ -336,6 +355,8 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, return -EFAULT; stream = &data->stream; + if (stream->direction == SND_COMPRESS_ACCEL) + return -EBADFD; guard(mutex)(&stream->device->lock); /* read is allowed when stream is running, paused, draining and setup @@ -385,6 +406,7 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) { struct snd_compr_file *data = f->private_data; struct snd_compr_stream *stream; + struct snd_compr_runtime *runtime; size_t avail; __poll_t retval = 0; @@ -392,10 +414,11 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) return EPOLLERR; stream = &data->stream; + runtime = stream->runtime; guard(mutex)(&stream->device->lock); - switch (stream->runtime->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_XRUN: return snd_compr_get_poll(stream) | EPOLLERR; @@ -403,23 +426,37 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) break; } - poll_wait(f, &stream->runtime->sleep, wait); + poll_wait(f, &runtime->sleep, wait); + +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + if (stream->direction == SND_COMPRESS_ACCEL) { + struct snd_compr_task_runtime *task; + if (runtime->fragments > runtime->active_tasks) + retval |= EPOLLOUT | EPOLLWRNORM; + task = list_first_entry_or_null(&runtime->tasks, + struct snd_compr_task_runtime, + list); + if (task && task->state == SND_COMPRESS_TASK_STATE_FINISHED) + retval |= EPOLLIN | EPOLLRDNORM; + return retval; + } +#endif avail = snd_compr_get_avail(stream); pr_debug("avail is %ld\n", (unsigned long)avail); /* check if we have at least one fragment to fill */ - switch (stream->runtime->state) { + switch (runtime->state) { case SNDRV_PCM_STATE_DRAINING: /* stream has been woken up after drain is complete * draining done so set stream state to stopped */ retval = snd_compr_get_poll(stream); - stream->runtime->state = SNDRV_PCM_STATE_SETUP; + runtime->state = SNDRV_PCM_STATE_SETUP; break; case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PAUSED: - if (avail >= stream->runtime->fragment_size) + if (avail >= runtime->fragment_size) retval = snd_compr_get_poll(stream); break; default: @@ -521,6 +558,9 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, unsigned int buffer_size; void *buffer = NULL; + if (stream->direction == SND_COMPRESS_ACCEL) + goto params; + buffer_size = params->buffer.fragment_size * params->buffer.fragments; if (stream->ops->copy) { buffer = NULL; @@ -543,18 +583,30 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, if (!buffer) return -ENOMEM; } - stream->runtime->fragment_size = params->buffer.fragment_size; - stream->runtime->fragments = params->buffer.fragments; + stream->runtime->buffer = buffer; stream->runtime->buffer_size = buffer_size; +params: + stream->runtime->fragment_size = params->buffer.fragment_size; + stream->runtime->fragments = params->buffer.fragments; return 0; } -static int snd_compress_check_input(struct snd_compr_params *params) +static int +snd_compress_check_input(struct snd_compr_stream *stream, struct snd_compr_params *params) { + u32 max_fragments; + /* first let's check the buffer parameter's */ - if (params->buffer.fragment_size == 0 || - params->buffer.fragments > U32_MAX / params->buffer.fragment_size || + if (params->buffer.fragment_size == 0) + return -EINVAL; + + if (stream->direction == SND_COMPRESS_ACCEL) + max_fragments = 64; /* safe value */ + else + max_fragments = U32_MAX / params->buffer.fragment_size; + + if (params->buffer.fragments > max_fragments || params->buffer.fragments == 0) return -EINVAL; @@ -583,7 +635,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) if (IS_ERR(params)) return PTR_ERR(params); - retval = snd_compress_check_input(params); + retval = snd_compress_check_input(stream, params); if (retval) return retval; @@ -939,6 +991,264 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream) return snd_compress_wait_for_drain(stream); } +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + +static struct snd_compr_task_runtime * +snd_compr_find_task(struct snd_compr_stream *stream, __u64 seqno) +{ + struct snd_compr_task_runtime *task; + + list_for_each_entry(task, &stream->runtime->tasks, list) { + if (task->seqno == seqno) + return task; + } + return NULL; +} + +static void snd_compr_task_free(struct snd_compr_task_runtime *task) +{ + if (task->output) + dma_buf_put(task->output); + if (task->input) + dma_buf_put(task->input); + kfree(task); +} + +static u64 snd_compr_seqno_next(struct snd_compr_stream *stream) +{ + u64 seqno = ++stream->runtime->task_seqno; + if (seqno == 0) + seqno = ++stream->runtime->task_seqno; + return seqno; +} + +static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_task *utask) +{ + struct snd_compr_task_runtime *task; + int retval; + + if (stream->runtime->total_tasks >= stream->runtime->fragments) + return -EBUSY; + if (utask->origin_seqno != 0 || utask->input_size != 0) + return -EINVAL; + task = kzalloc(sizeof(*task), GFP_KERNEL); + if (task == NULL) + return -ENOMEM; + task->seqno = utask->seqno = snd_compr_seqno_next(stream); + task->input_size = utask->input_size; + retval = stream->ops->task_create(stream, task); + if (retval < 0) + goto cleanup; + utask->input_fd = dma_buf_fd(task->input, O_WRONLY|O_CLOEXEC); + if (utask->input_fd < 0) { + retval = utask->input_fd; + goto cleanup; + } + utask->output_fd = dma_buf_fd(task->output, O_RDONLY|O_CLOEXEC); + if (utask->output_fd < 0) { + retval = utask->output_fd; + goto cleanup; + } + /* keep dmabuf reference until freed with task free ioctl */ + dma_buf_get(utask->input_fd); + dma_buf_get(utask->output_fd); + list_add_tail(&task->list, &stream->runtime->tasks); + stream->runtime->total_tasks++; + return 0; +cleanup: + snd_compr_task_free(task); + return retval; +} + +static int snd_compr_task_create(struct snd_compr_stream *stream, unsigned long arg) +{ + struct snd_compr_task *task __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; + task = memdup_user((void __user *)arg, sizeof(*task)); + if (IS_ERR(task)) + return PTR_ERR(no_free_ptr(task)); + retval = snd_compr_task_new(stream, task); + if (retval >= 0) + if (copy_to_user((void __user *)arg, task, sizeof(*task))) + retval = -EFAULT; + return retval; +} + +static int snd_compr_task_start_prepare(struct snd_compr_task_runtime *task, + struct snd_compr_task *utask) +{ + if (task == NULL) + return -EINVAL; + if (task->state >= SND_COMPRESS_TASK_STATE_FINISHED) + return -EBUSY; + if (utask->input_size > task->input->size) + return -EINVAL; + task->flags = utask->flags; + task->input_size = utask->input_size; + task->state = SND_COMPRESS_TASK_STATE_IDLE; + return 0; +} + +static int snd_compr_task_start(struct snd_compr_stream *stream, struct snd_compr_task *utask) +{ + struct snd_compr_task_runtime *task; + int retval; + + if (utask->origin_seqno > 0) { + task = snd_compr_find_task(stream, utask->origin_seqno); + retval = snd_compr_task_start_prepare(task, utask); + if (retval < 0) + return retval; + task->seqno = utask->seqno = snd_compr_seqno_next(stream); + utask->origin_seqno = 0; + list_move_tail(&task->list, &stream->runtime->tasks); + } else { + task = snd_compr_find_task(stream, utask->seqno); + if (task && task->state != SND_COMPRESS_TASK_STATE_IDLE) + return -EBUSY; + retval = snd_compr_task_start_prepare(task, utask); + if (retval < 0) + return retval; + } + retval = stream->ops->task_start(stream, task); + if (retval >= 0) { + task->state = SND_COMPRESS_TASK_STATE_ACTIVE; + stream->runtime->active_tasks++; + } + return retval; +} + +static int snd_compr_task_start_ioctl(struct snd_compr_stream *stream, unsigned long arg) +{ + struct snd_compr_task *task __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; + task = memdup_user((void __user *)arg, sizeof(*task)); + if (IS_ERR(task)) + return PTR_ERR(no_free_ptr(task)); + retval = snd_compr_task_start(stream, task); + if (retval >= 0) + if (copy_to_user((void __user *)arg, task, sizeof(*task))) + retval = -EFAULT; + return retval; +} + +static void snd_compr_task_stop_one(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task) +{ + if (task->state != SND_COMPRESS_TASK_STATE_ACTIVE) + return; + stream->ops->task_stop(stream, task); + if (!snd_BUG_ON(stream->runtime->active_tasks == 0)) + stream->runtime->active_tasks--; + list_move_tail(&task->list, &stream->runtime->tasks); + task->state = SND_COMPRESS_TASK_STATE_IDLE; +} + +static void snd_compr_task_free_one(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task) +{ + snd_compr_task_stop_one(stream, task); + stream->ops->task_free(stream, task); + list_del(&task->list); + snd_compr_task_free(task); + stream->runtime->total_tasks--; +} + +static void snd_compr_task_free_all(struct snd_compr_stream *stream) +{ + struct snd_compr_task_runtime *task, *temp; + + list_for_each_entry_safe_reverse(task, temp, &stream->runtime->tasks, list) + snd_compr_task_free_one(stream, task); +} + +typedef void (*snd_compr_seq_func_t)(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task); + +static int snd_compr_task_seq(struct snd_compr_stream *stream, unsigned long arg, + snd_compr_seq_func_t fcn) +{ + struct snd_compr_task_runtime *task; + __u64 seqno; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; + retval = get_user(seqno, (__u64 __user *)arg); + if (retval < 0) + return retval; + retval = 0; + if (seqno == 0) { + list_for_each_entry_reverse(task, &stream->runtime->tasks, list) + fcn(stream, task); + } else { + task = snd_compr_find_task(stream, seqno); + if (task == NULL) { + retval = -EINVAL; + } else { + fcn(stream, task); + } + } + return retval; +} + +static int snd_compr_task_status(struct snd_compr_stream *stream, + struct snd_compr_task_status *status) +{ + struct snd_compr_task_runtime *task; + + task = snd_compr_find_task(stream, status->seqno); + if (task == NULL) + return -EINVAL; + status->input_size = task->input_size; + status->output_size = task->output_size; + status->state = task->state; + return 0; +} + +static int snd_compr_task_status_ioctl(struct snd_compr_stream *stream, unsigned long arg) +{ + struct snd_compr_task_status *status __free(kfree) = NULL; + int retval; + + if (stream->runtime->state != SNDRV_PCM_STATE_SETUP) + return -EPERM; + status = memdup_user((void __user *)arg, sizeof(*status)); + if (IS_ERR(status)) + return PTR_ERR(no_free_ptr(status)); + retval = snd_compr_task_status(stream, status); + if (retval >= 0) + if (copy_to_user((void __user *)arg, status, sizeof(*status))) + retval = -EFAULT; + return retval; +} + +/** + * snd_compr_task_finished: Notify that the task was finished + * @stream: pointer to stream + * @task: runtime task structure + * + * Set the finished task state and notify waiters. + */ +void snd_compr_task_finished(struct snd_compr_stream *stream, + struct snd_compr_task_runtime *task) +{ + guard(mutex)(&stream->device->lock); + if (!snd_BUG_ON(stream->runtime->active_tasks == 0)) + stream->runtime->active_tasks--; + task->state = SND_COMPRESS_TASK_STATE_FINISHED; + wake_up(&stream->runtime->sleep); +} +EXPORT_SYMBOL_GPL(snd_compr_task_finished); + +#endif /* CONFIG_SND_COMPRESS_ACCEL */ + static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { struct snd_compr_file *data = f->private_data; @@ -968,6 +1278,27 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return snd_compr_set_metadata(stream, arg); case _IOC_NR(SNDRV_COMPRESS_GET_METADATA): return snd_compr_get_metadata(stream, arg); + } + + if (stream->direction == SND_COMPRESS_ACCEL) { +#if IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + switch (_IOC_NR(cmd)) { + case _IOC_NR(SNDRV_COMPRESS_TASK_CREATE): + return snd_compr_task_create(stream, arg); + case _IOC_NR(SNDRV_COMPRESS_TASK_FREE): + return snd_compr_task_seq(stream, arg, snd_compr_task_free_one); + case _IOC_NR(SNDRV_COMPRESS_TASK_START): + return snd_compr_task_start_ioctl(stream, arg); + case _IOC_NR(SNDRV_COMPRESS_TASK_STOP): + return snd_compr_task_seq(stream, arg, snd_compr_task_stop_one); + case _IOC_NR(SNDRV_COMPRESS_TASK_STATUS): + return snd_compr_task_status_ioctl(stream, arg); + } +#endif + return -ENOTTY; + } + + switch (_IOC_NR(cmd)) { case _IOC_NR(SNDRV_COMPRESS_TSTAMP): return snd_compr_tstamp(stream, arg); case _IOC_NR(SNDRV_COMPRESS_AVAIL): @@ -1140,6 +1471,11 @@ int snd_compress_new(struct snd_card *card, int device, }; int ret; +#if !IS_ENABLED(CONFIG_SND_COMPRESS_ACCEL) + if (snd_BUG_ON(dirn == SND_COMPRESS_ACCEL)) + return -EINVAL; +#endif + compr->card = card; compr->device = device; compr->direction = dirn; diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 65a1ebe877768f..e33dfcf863cf13 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -668,10 +668,16 @@ static void snd_ctl_led_sysfs_add(struct snd_card *card) goto cerr; led->cards[card->number] = led_card; snprintf(link_name, sizeof(link_name), "led-%s", led->name); - WARN(sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj, link_name), - "can't create symlink to controlC%i device\n", card->number); - WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"), - "can't create symlink to card%i\n", card->number); + if (sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj, + link_name)) + dev_err(card->dev, + "%s: can't create symlink to controlC%i device\n", + __func__, card->number); + if (sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, + "card")) + dev_err(card->dev, + "%s: can't create symlink to card%i\n", + __func__, card->number); continue; cerr: diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b465fb6e1f5f0d..8a3384342e8db0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2250,7 +2250,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) bool nonatomic = substream->pcm->nonatomic; CLASS(fd, f)(fd); - if (!fd_file(f)) + if (fd_empty(f)) return -EBADFD; if (!is_pcm_file(fd_file(f))) return -EBADFD; @@ -3773,6 +3773,26 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file } #endif /* coherent mmap */ +/* + * snd_pcm_mmap_data_open - increase the mmap counter + */ +static void snd_pcm_mmap_data_open(struct vm_area_struct *area) +{ + struct snd_pcm_substream *substream = area->vm_private_data; + + atomic_inc(&substream->mmap_count); +} + +/* + * snd_pcm_mmap_data_close - decrease the mmap counter + */ +static void snd_pcm_mmap_data_close(struct vm_area_struct *area) +{ + struct snd_pcm_substream *substream = area->vm_private_data; + + atomic_dec(&substream->mmap_count); +} + /* * fault callback for mmapping a RAM page */ @@ -3793,9 +3813,11 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; if (substream->ops->page) page = substream->ops->page(substream, offset); - else if (!snd_pcm_get_dma_buf(substream)) + else if (!snd_pcm_get_dma_buf(substream)) { + if (WARN_ON_ONCE(!runtime->dma_area)) + return VM_FAULT_SIGBUS; page = virt_to_page(runtime->dma_area + offset); - else + } else page = snd_sgbuf_get_page(snd_pcm_get_dma_buf(substream), offset); if (!page) return VM_FAULT_SIGBUS; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 03306be5fa0245..348ce1b7725ea2 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -724,8 +724,9 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream, newbuf = kvzalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; - guard(spinlock_irq)(&substream->lock); + spin_lock_irq(&substream->lock); if (runtime->buffer_ref) { + spin_unlock_irq(&substream->lock); kvfree(newbuf); return -EBUSY; } @@ -733,6 +734,7 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream, runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; __reset_runtime_ptrs(runtime, is_input); + spin_unlock_irq(&substream->lock); kvfree(oldbuf); } runtime->avail_min = params->avail_min; diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c index e5d3f4d206bf6a..e956f17f379282 100644 --- a/sound/core/seq/seq_ump_client.c +++ b/sound/core/seq/seq_ump_client.c @@ -257,12 +257,12 @@ static void update_port_infos(struct seq_ump_client *client) continue; old->addr.client = client->seq_client; - old->addr.port = i; + old->addr.port = ump_group_to_seq_port(i); err = snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, old); if (err < 0) - return; + continue; fill_port_info(new, client, &client->ump->groups[i]); if (old->capability == new->capability && !strcmp(old->name, new->name)) @@ -271,7 +271,7 @@ static void update_port_infos(struct seq_ump_client *client) SNDRV_SEQ_IOCTL_SET_PORT_INFO, new); if (err < 0) - return; + continue; /* notify to system port */ snd_seq_system_client_ev_port_change(client->seq_client, i); } diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c index bfed1a25fc8f74..84e337ecbddd0a 100644 --- a/sound/core/sound_kunit.c +++ b/sound/core/sound_kunit.c @@ -172,6 +172,7 @@ static void test_format_fill_silence(struct kunit *test) u32 i, j; buffer = kunit_kzalloc(test, SILENCE_BUFFER_SIZE, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer); for (i = 0; i < ARRAY_SIZE(buf_samples); i++) { for (j = 0; j < ARRAY_SIZE(valid_fmt); j++) @@ -208,8 +209,12 @@ static void test_playback_avail(struct kunit *test) struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL); u32 i; + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r); + r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL); r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r->status); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r->control); for (i = 0; i < ARRAY_SIZE(p_avail_data); i++) { r->buffer_size = p_avail_data[i].buffer_size; @@ -232,8 +237,12 @@ static void test_capture_avail(struct kunit *test) struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL); u32 i; + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r); + r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL); r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r->status); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, r->control); for (i = 0; i < ARRAY_SIZE(c_avail_data); i++) { r->buffer_size = c_avail_data[i].buffer_size; @@ -247,6 +256,7 @@ static void test_capture_avail(struct kunit *test) static void test_card_set_id(struct kunit *test) { struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, card); snd_card_set_id(card, VALID_NAME); KUNIT_EXPECT_STREQ(test, card->id, VALID_NAME); @@ -280,6 +290,7 @@ static void test_pcm_format_name(struct kunit *test) static void test_card_add_component(struct kunit *test) { struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, card); snd_component_add(card, TEST_FIRST_COMPONENT); KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT); diff --git a/sound/core/ump.c b/sound/core/ump.c index 7d59a0a9b037ad..fe4d39ae115930 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -37,6 +37,7 @@ static int process_legacy_output(struct snd_ump_endpoint *ump, u32 *buffer, int count); static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, int words); +static void update_legacy_names(struct snd_ump_endpoint *ump); #else static inline int process_legacy_output(struct snd_ump_endpoint *ump, u32 *buffer, int count) @@ -47,6 +48,9 @@ static inline void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, int words) { } +static inline void update_legacy_names(struct snd_ump_endpoint *ump) +{ +} #endif static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = { @@ -366,7 +370,7 @@ int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, { struct snd_ump_block *fb, *p; - if (blk < 0 || blk >= SNDRV_UMP_MAX_BLOCKS) + if (blk >= SNDRV_UMP_MAX_BLOCKS) return -EINVAL; if (snd_ump_get_block(ump, blk)) @@ -387,7 +391,7 @@ int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, fb->info.first_group = first_group; fb->info.num_groups = num_groups; /* fill the default name, may be overwritten to a better name */ - snprintf(fb->info.name, sizeof(fb->info.name), "Group %d-%d", + snprintf(fb->info.name, sizeof(fb->info.name), "Group %u-%u", first_group + 1, first_group + num_groups); /* put the entry in the ordered list */ @@ -788,7 +792,10 @@ static void fill_fb_info(struct snd_ump_endpoint *ump, info->ui_hint = buf->fb_info.ui_hint; info->first_group = buf->fb_info.first_group; info->num_groups = buf->fb_info.num_groups; - info->flags = buf->fb_info.midi_10; + if (buf->fb_info.midi_10 < 2) + info->flags = buf->fb_info.midi_10; + else + info->flags = SNDRV_UMP_BLOCK_IS_MIDI1 | SNDRV_UMP_BLOCK_IS_LOWSPEED; info->active = buf->fb_info.active; info->midi_ci_version = buf->fb_info.midi_ci_version; info->sysex8_streams = buf->fb_info.sysex8_streams; @@ -858,6 +865,7 @@ static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump, fill_fb_info(ump, &fb->info, buf); if (ump->parsed) { snd_ump_update_group_attrs(ump); + update_legacy_names(ump); seq_notify_fb_change(ump, fb); } } @@ -890,6 +898,7 @@ static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump, /* notify the FB name update to sequencer, too */ if (ret > 0 && ump->parsed) { snd_ump_update_group_attrs(ump); + update_legacy_names(ump); seq_notify_fb_change(ump, fb); } return ret; @@ -1084,6 +1093,8 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream) guard(mutex)(&ump->open_mutex); if (ump->legacy_substreams[dir][group]) return -EBUSY; + if (!ump->groups[group].active) + return -ENODEV; if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { if (!ump->legacy_out_opens) { err = snd_rawmidi_kernel_open(&ump->core, 0, @@ -1251,11 +1262,20 @@ static void fill_substream_names(struct snd_ump_endpoint *ump, name = ump->groups[idx].name; if (!*name) name = ump->info.name; - snprintf(s->name, sizeof(s->name), "Group %d (%.16s)", - idx + 1, name); + scnprintf(s->name, sizeof(s->name), "Group %d (%.16s)%s", + idx + 1, name, + ump->groups[idx].active ? "" : " [Inactive]"); } } +static void update_legacy_names(struct snd_ump_endpoint *ump) +{ + struct snd_rawmidi *rmidi = ump->legacy_rmidi; + + fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT); + fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT); +} + int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, char *id, int device) { @@ -1292,10 +1312,7 @@ int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, rmidi->ops = &snd_ump_legacy_ops; rmidi->private_data = ump; ump->legacy_rmidi = rmidi; - if (input) - fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT); - if (output) - fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT); + update_legacy_names(ump); ump_dbg(ump, "Created a legacy rawmidi #%d (%s)\n", device, id); return 0; diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 6fc255a6754d1f..17f215bad0ec77 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -1008,7 +1008,7 @@ static void snd_mts64_remove(struct platform_device *pdev) static struct platform_driver snd_mts64_driver = { .probe = snd_mts64_probe, - .remove_new = snd_mts64_remove, + .remove = snd_mts64_remove, .driver = { .name = PLATFORM_DRIVER, } diff --git a/sound/drivers/pcmtest.c b/sound/drivers/pcmtest.c index 21cefaf5419aad..72378f354fd01e 100644 --- a/sound/drivers/pcmtest.c +++ b/sound/drivers/pcmtest.c @@ -640,7 +640,7 @@ static struct platform_device pcmtst_pdev = { static struct platform_driver pcmtst_pdrv = { .probe = pcmtst_probe, - .remove_new = pdev_remove, + .remove = pdev_remove, .driver = { .name = "pcmtest", }, diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index 54d818d2f53dc4..5e4ef25a83a49f 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c @@ -794,7 +794,7 @@ static void snd_portman_remove(struct platform_device *pdev) static struct platform_driver snd_portman_driver = { .probe = snd_portman_probe, - .remove_new = snd_portman_remove, + .remove = snd_portman_remove, .driver = { .name = PLATFORM_DRIVER, } diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c index b596bec19774c8..f5028a061a91ff 100644 --- a/sound/firewire/cmp.c +++ b/sound/firewire/cmp.c @@ -333,53 +333,6 @@ int cmp_connection_establish(struct cmp_connection *c) } EXPORT_SYMBOL(cmp_connection_establish); -/** - * cmp_connection_update - update the connection after a bus reset - * @c: the connection manager - * - * This function must be called from the driver's .update handler to - * reestablish any connection that might have been active. - * - * Returns zero on success, or a negative error code. On an error, the - * connection is broken and the caller must stop transmitting iso packets. - */ -int cmp_connection_update(struct cmp_connection *c) -{ - int err; - - mutex_lock(&c->mutex); - - if (!c->connected) { - mutex_unlock(&c->mutex); - return 0; - } - - err = fw_iso_resources_update(&c->resources); - if (err < 0) - goto err_unconnect; - - if (c->direction == CMP_OUTPUT) - err = pcr_modify(c, opcr_set_modify, pcr_set_check, - SUCCEED_ON_BUS_RESET); - else - err = pcr_modify(c, ipcr_set_modify, pcr_set_check, - SUCCEED_ON_BUS_RESET); - - if (err < 0) - goto err_unconnect; - - mutex_unlock(&c->mutex); - - return 0; - -err_unconnect: - c->connected = false; - mutex_unlock(&c->mutex); - - return err; -} -EXPORT_SYMBOL(cmp_connection_update); - static __be32 pcr_break_modify(struct cmp_connection *c, __be32 pcr) { return pcr & ~cpu_to_be32(PCR_BCAST_CONN | PCR_P2P_CONN_MASK); diff --git a/sound/firewire/cmp.h b/sound/firewire/cmp.h index 26ab88000e34b5..66fc08b742d2e0 100644 --- a/sound/firewire/cmp.h +++ b/sound/firewire/cmp.h @@ -47,7 +47,6 @@ int cmp_connection_reserve(struct cmp_connection *connection, void cmp_connection_release(struct cmp_connection *connection); int cmp_connection_establish(struct cmp_connection *connection); -int cmp_connection_update(struct cmp_connection *connection); void cmp_connection_break(struct cmp_connection *connection); #endif diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 9f849e05ce79f8..f564ec7af19405 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -801,4 +801,4 @@ EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel DSP config driver"); -MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); +MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI"); diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index ed530e0dd4ddcc..49d3e0e3007350 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -198,7 +198,7 @@ int sdw_intel_acpi_scan(acpi_handle *parent_handle, return sdw_intel_scan_controller(info); } -EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SND_INTEL_SOUNDWIRE_ACPI); +EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, "SND_INTEL_SOUNDWIRE_ACPI"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Intel Soundwire ACPI helpers"); diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c index 3c26334227bb49..991793e6bda9b2 100644 --- a/sound/mips/hal2.c +++ b/sound/mips/hal2.c @@ -886,7 +886,7 @@ static void hal2_remove(struct platform_device *pdev) static struct platform_driver hal2_driver = { .probe = hal2_probe, - .remove_new = hal2_remove, + .remove = hal2_remove, .driver = { .name = "sgihal2", } diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index a8551ccdd1bf8a..4e2ff954ff5901 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -917,8 +917,8 @@ static void snd_sgio2audio_remove(struct platform_device *pdev) static struct platform_driver sgio2audio_driver = { .probe = snd_sgio2audio_probe, - .remove_new = snd_sgio2audio_remove, - .driver = { + .remove = snd_sgio2audio_remove, + .driver = { .name = "sgio2audio", } }; diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index b8fad12f9e5f58..8d443a3663d3e9 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c @@ -732,7 +732,7 @@ static void __exit amiga_audio_remove(struct platform_device *pdev) * triggering a section mismatch warning. */ static struct platform_driver amiga_audio_driver __refdata = { - .remove_new = __exit_p(amiga_audio_remove), + .remove = __exit_p(amiga_audio_remove), .driver = { .name = "amiga-audio", }, diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index fdd4fe16225fcb..5a84591b13fc2b 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -464,7 +464,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream, return -ENOMEM; } - err = hpi_stream_get_info_ex(dpcm->h_stream, NULL, + hpi_stream_get_info_ex(dpcm->h_stream, NULL, &dpcm->hpi_buffer_attached, NULL, NULL, NULL); } bytes_per_sec = params_rate(params) * params_channels(params); diff --git a/sound/pci/hda/cirrus_scodec.c b/sound/pci/hda/cirrus_scodec.c index 8de3bc7448fa52..3c670207ba30e0 100644 --- a/sound/pci/hda/cirrus_scodec.c +++ b/sound/pci/hda/cirrus_scodec.c @@ -66,7 +66,7 @@ int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index, return speaker_id; } -EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, SND_HDA_CIRRUS_SCODEC); +EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, "SND_HDA_CIRRUS_SCODEC"); MODULE_DESCRIPTION("HDA Cirrus side-codec library"); MODULE_AUTHOR("Richard Fitzgerald "); diff --git a/sound/pci/hda/cirrus_scodec_test.c b/sound/pci/hda/cirrus_scodec_test.c index e925ebe21ccbae..f5d6241daee47c 100644 --- a/sound/pci/hda/cirrus_scodec_test.c +++ b/sound/pci/hda/cirrus_scodec_test.c @@ -365,7 +365,7 @@ static struct kunit_suite cirrus_scodec_test_suite = { kunit_test_suite(cirrus_scodec_test_suite); -MODULE_IMPORT_NS(SND_HDA_CIRRUS_SCODEC); +MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC"); MODULE_DESCRIPTION("KUnit test for the Cirrus side-codec library"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index d68bf7591d90c1..5dc021976c7905 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -2019,7 +2019,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, SND_HDA_SCODEC_CS35L41); +EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, "SND_HDA_SCODEC_CS35L41"); void cs35l41_hda_remove(struct device *dev) { @@ -2044,7 +2044,7 @@ void cs35l41_hda_remove(struct device *dev) gpiod_put(cs35l41->cs_gpio); kfree(cs35l41->acpi_subsystem_id); } -EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41); +EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, "SND_HDA_SCODEC_CS35L41"); const struct dev_pm_ops cs35l41_hda_pm_ops = { RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, @@ -2052,11 +2052,11 @@ const struct dev_pm_ops cs35l41_hda_pm_ops = { .prepare = cs35l41_system_suspend_prep, SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume) }; -EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41); +EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, "SND_HDA_SCODEC_CS35L41"); MODULE_DESCRIPTION("CS35L41 HDA Driver"); -MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS); -MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB); +MODULE_IMPORT_NS("SND_HDA_CS_DSP_CONTROLS"); +MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(FW_CS_DSP); +MODULE_IMPORT_NS("FW_CS_DSP"); diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/pci/hda/cs35l41_hda_i2c.c index bb84740c852076..e77495413c214d 100644 --- a/sound/pci/hda/cs35l41_hda_i2c.c +++ b/sound/pci/hda/cs35l41_hda_i2c.c @@ -64,6 +64,6 @@ static struct i2c_driver cs35l41_i2c_driver = { module_i2c_driver(cs35l41_i2c_driver); MODULE_DESCRIPTION("HDA CS35L41 driver"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L41); +MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41"); MODULE_AUTHOR("Lucas Tanure "); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l41_hda_spi.c b/sound/pci/hda/cs35l41_hda_spi.c index f8c356ad0d340f..2acbaf8467a09f 100644 --- a/sound/pci/hda/cs35l41_hda_spi.c +++ b/sound/pci/hda/cs35l41_hda_spi.c @@ -59,6 +59,6 @@ static struct spi_driver cs35l41_spi_driver = { module_spi_driver(cs35l41_spi_driver); MODULE_DESCRIPTION("HDA CS35L41 driver"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L41); +MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41"); MODULE_AUTHOR("Lucas Tanure "); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index e3ac0e23ae3211..4ef7878e8fd4b4 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -151,10 +151,6 @@ static int cs35l56_hda_runtime_resume(struct device *dev) } } - ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); - if (ret) - goto err; - return 0; err: @@ -1059,9 +1055,6 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config, ARRAY_SIZE(cs35l56_hda_dai_config)); - ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); - if (ret) - goto dsp_err; /* * By default only enable one ASP1TXn, where n=amplifier index, @@ -1087,14 +1080,13 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) pm_err: pm_runtime_disable(cs35l56->base.dev); -dsp_err: cs_dsp_remove(&cs35l56->cs_dsp); err: gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, SND_HDA_SCODEC_CS35L56); +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, "SND_HDA_SCODEC_CS35L56"); void cs35l56_hda_remove(struct device *dev) { @@ -1113,7 +1105,7 @@ void cs35l56_hda_remove(struct device *dev) gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); } -EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, SND_HDA_SCODEC_CS35L56); +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, "SND_HDA_SCODEC_CS35L56"); const struct dev_pm_ops cs35l56_hda_pm_ops = { RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL) @@ -1123,14 +1115,14 @@ const struct dev_pm_ops cs35l56_hda_pm_ops = { NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq, cs35l56_hda_system_resume_no_irq) }; -EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, SND_HDA_SCODEC_CS35L56); +EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, "SND_HDA_SCODEC_CS35L56"); MODULE_DESCRIPTION("CS35L56 HDA Driver"); -MODULE_IMPORT_NS(FW_CS_DSP); -MODULE_IMPORT_NS(SND_HDA_CIRRUS_SCODEC); -MODULE_IMPORT_NS(SND_HDA_CS_DSP_CONTROLS); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); -MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB); +MODULE_IMPORT_NS("FW_CS_DSP"); +MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC"); +MODULE_IMPORT_NS("SND_HDA_CS_DSP_CONTROLS"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); +MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c index 40f2f97944d54c..c7b83661314984 100644 --- a/sound/pci/hda/cs35l56_hda_i2c.c +++ b/sound/pci/hda/cs35l56_hda_i2c.c @@ -77,8 +77,8 @@ static struct i2c_driver cs35l56_hda_i2c_driver = { module_i2c_driver(cs35l56_hda_i2c_driver); MODULE_DESCRIPTION("HDA CS35L56 I2C driver"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c index 7f02155fe61e3c..d4ee5bb7c48660 100644 --- a/sound/pci/hda/cs35l56_hda_spi.c +++ b/sound/pci/hda/cs35l56_hda_spi.c @@ -77,8 +77,8 @@ static struct spi_driver cs35l56_hda_spi_driver = { module_spi_driver(cs35l56_hda_spi_driver); MODULE_DESCRIPTION("HDA CS35L56 SPI driver"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_CS35L56); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 7c6b1fe8dfcce3..84393f4f429dff 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -933,6 +933,7 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, bool match_all_pins) { const struct snd_hda_pin_quirk *pq; + const char *name = NULL; if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) return; @@ -946,9 +947,10 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, codec->fixup_id = pq->value; #ifdef CONFIG_SND_DEBUG_VERBOSE codec->fixup_name = pq->name; - codec_dbg(codec, "%s: picked fixup %s (pin match)\n", - codec->core.chip_name, codec->fixup_name); + name = pq->name; #endif + codec_info(codec, "%s: picked fixup %s (pin match)\n", + codec->core.chip_name, name ? name : ""); codec->fixup_list = fixlist; return; } @@ -956,6 +958,28 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec, } EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); +/* check whether the given quirk entry matches with vendor/device pair */ +static bool hda_quirk_match(u16 vendor, u16 device, const struct hda_quirk *q) +{ + if (q->subvendor != vendor) + return false; + return !q->subdevice || + (device & q->subdevice_mask) == q->subdevice; +} + +/* look through the quirk list and return the matching entry */ +static const struct hda_quirk * +hda_quirk_lookup_id(u16 vendor, u16 device, const struct hda_quirk *list) +{ + const struct hda_quirk *q; + + for (q = list; q->subvendor || q->subdevice; q++) { + if (hda_quirk_match(vendor, device, q)) + return q; + } + return NULL; +} + /** * snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string * @codec: the HDA codec @@ -975,14 +999,16 @@ EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); */ void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, + const struct hda_quirk *quirk, const struct hda_fixup *fixlist) { - const struct snd_pci_quirk *q; + const struct hda_quirk *q; int id = HDA_FIXUP_ID_NOT_SET; const char *name = NULL; const char *type = NULL; unsigned int vendor, device; + u16 pci_vendor, pci_device; + u16 codec_vendor, codec_device; if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET) return; @@ -991,8 +1017,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { id = HDA_FIXUP_ID_NO_FIXUP; fixlist = NULL; - codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n", - codec->core.chip_name); + codec_info(codec, "%s: picked no fixup (nofixup specified)\n", + codec->core.chip_name); goto found; } @@ -1002,8 +1028,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec, if (!strcmp(codec->modelname, models->name)) { id = models->id; name = models->name; - codec_dbg(codec, "%s: picked fixup %s (model specified)\n", - codec->core.chip_name, codec->fixup_name); + codec_info(codec, "%s: picked fixup %s (model specified)\n", + codec->core.chip_name, name); goto found; } models++; @@ -1013,27 +1039,42 @@ void snd_hda_pick_fixup(struct hda_codec *codec, if (!quirk) return; + if (codec->bus->pci) { + pci_vendor = codec->bus->pci->subsystem_vendor; + pci_device = codec->bus->pci->subsystem_device; + } + + codec_vendor = codec->core.subsystem_id >> 16; + codec_device = codec->core.subsystem_id & 0xffff; + /* match with the SSID alias given by the model string "XXXX:YYYY" */ if (codec->modelname && sscanf(codec->modelname, "%04x:%04x", &vendor, &device) == 2) { - q = snd_pci_quirk_lookup_id(vendor, device, quirk); + q = hda_quirk_lookup_id(vendor, device, quirk); if (q) { type = "alias SSID"; goto found_device; } } - /* match with the PCI SSID */ - q = snd_pci_quirk_lookup(codec->bus->pci, quirk); - if (q) { - type = "PCI SSID"; - goto found_device; + /* match primarily with the PCI SSID */ + for (q = quirk; q->subvendor || q->subdevice; q++) { + /* if the entry is specific to codec SSID, check with it */ + if (!codec->bus->pci || q->match_codec_ssid) { + if (hda_quirk_match(codec_vendor, codec_device, q)) { + type = "codec SSID"; + goto found_device; + } + } else { + if (hda_quirk_match(pci_vendor, pci_device, q)) { + type = "PCI SSID"; + goto found_device; + } + } } /* match with the codec SSID */ - q = snd_pci_quirk_lookup_id(codec->core.subsystem_id >> 16, - codec->core.subsystem_id & 0xffff, - quirk); + q = hda_quirk_lookup_id(codec_vendor, codec_device, quirk); if (q) { type = "codec SSID"; goto found_device; @@ -1046,9 +1087,9 @@ void snd_hda_pick_fixup(struct hda_codec *codec, #ifdef CONFIG_SND_DEBUG_VERBOSE name = q->name; #endif - codec_dbg(codec, "%s: picked fixup %s for %s %04x:%04x\n", - codec->core.chip_name, name ? name : "", - type, q->subvendor, q->subdevice); + codec_info(codec, "%s: picked fixup %s for %s %04x:%04x\n", + codec->core.chip_name, name ? name : "", + type, q->subvendor, q->subdevice); found: codec->fixup_id = id; codec->fixup_list = fixlist; diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c index 2d6b7b0b355d2a..71860e2d637716 100644 --- a/sound/pci/hda/hda_component.c +++ b/sound/pci/hda/hda_component.c @@ -29,7 +29,7 @@ void hda_component_acpi_device_notify(struct hda_component_parent *parent, } mutex_unlock(&parent->mutex); } -EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, "SND_HDA_SCODEC_COMPONENT"); int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, struct hda_component_parent *parent, @@ -64,7 +64,7 @@ int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, return 0; } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT"); void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, struct hda_component_parent *parent, @@ -81,7 +81,7 @@ void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, if (ret < 0) codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret); } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT"); #endif /* ifdef CONFIG_ACPI */ void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action) @@ -107,7 +107,7 @@ void hda_component_manager_playback_hook(struct hda_component_parent *parent, in } mutex_unlock(&parent->mutex); } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, "SND_HDA_SCODEC_COMPONENT"); struct hda_scodec_match { const char *bus; @@ -149,7 +149,7 @@ int hda_component_manager_bind(struct hda_codec *cdc, return ret; } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, "SND_HDA_SCODEC_COMPONENT"); int hda_component_manager_init(struct hda_codec *cdc, struct hda_component_parent *parent, int count, @@ -189,7 +189,7 @@ int hda_component_manager_init(struct hda_codec *cdc, return ret; } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, "SND_HDA_SCODEC_COMPONENT"); void hda_component_manager_free(struct hda_component_parent *parent, const struct component_master_ops *ops) @@ -205,7 +205,7 @@ void hda_component_manager_free(struct hda_component_parent *parent, parent->codec = NULL; } -EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, SND_HDA_SCODEC_COMPONENT); +EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, "SND_HDA_SCODEC_COMPONENT"); MODULE_DESCRIPTION("HD Audio component binding library"); MODULE_AUTHOR("Richard Fitzgerald "); diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c index deb74c2470829f..18fa6e7edb497c 100644 --- a/sound/pci/hda/hda_cs_dsp_ctl.c +++ b/sound/pci/hda/hda_cs_dsp_ctl.c @@ -34,7 +34,7 @@ const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW] = { [HDA_CS_DSP_FW_SPK_DIAG] = "spk-diag", [HDA_CS_DSP_FW_MISC] = "misc", }; -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_fw_ids, SND_HDA_CS_DSP_CONTROLS); +EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_fw_ids, "SND_HDA_CS_DSP_CONTROLS"); static int hda_cs_dsp_coeff_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -200,7 +200,7 @@ void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_inf hda_cs_dsp_control_add(cs_ctl, info); } } -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_add_controls, SND_HDA_CS_DSP_CONTROLS); +EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_add_controls, "SND_HDA_CS_DSP_CONTROLS"); void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) { @@ -210,7 +210,7 @@ void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) if (ctl) snd_ctl_remove(ctl->card, ctl->kctl); } -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS); +EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, "SND_HDA_CS_DSP_CONTROLS"); int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type, unsigned int alg, const void *buf, size_t len) @@ -227,7 +227,7 @@ int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type, return 0; } -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_write_ctl, SND_HDA_CS_DSP_CONTROLS); +EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_write_ctl, "SND_HDA_CS_DSP_CONTROLS"); int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len) @@ -241,9 +241,9 @@ int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type, return ret; } -EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, SND_HDA_CS_DSP_CONTROLS); +EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, "SND_HDA_CS_DSP_CONTROLS"); MODULE_DESCRIPTION("CS_DSP ALSA Control HDA Library"); MODULE_AUTHOR("Stefan Binding, "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(FW_CS_DSP); +MODULE_IMPORT_NS("FW_CS_DSP"); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index b4540c5cd2a6f9..4a62440adfafdb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -773,6 +773,14 @@ static void azx_clear_irq_pending(struct azx *chip) static int azx_acquire_irq(struct azx *chip, int do_disconnect) { struct hdac_bus *bus = azx_bus(chip); + int ret; + + if (!chip->msi || pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_MSI) < 0) { + ret = pci_alloc_irq_vectors(chip->pci, 1, 1, PCI_IRQ_INTX); + if (ret < 0) + return ret; + chip->msi = 0; + } if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, @@ -786,7 +794,6 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) } bus->irq = chip->pci->irq; chip->card->sync_irq = bus->irq; - pci_intx(chip->pci, !chip->msi); return 0; } @@ -1032,22 +1039,12 @@ static int azx_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hdac_bus *bus; if (!azx_is_pm_ready(card)) return 0; chip = card->private_data; - bus = azx_bus(chip); azx_shutdown_chip(chip); - if (bus->irq >= 0) { - free_irq(bus->irq, chip); - bus->irq = -1; - chip->card->sync_irq = -1; - } - - if (chip->msi) - pci_disable_msi(chip->pci); trace_azx_suspend(chip); return 0; @@ -1062,11 +1059,6 @@ static int __maybe_unused azx_resume(struct device *dev) return 0; chip = card->private_data; - if (chip->msi) - if (pci_enable_msi(chip->pci) < 0) - chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) - return -EIO; __azx_runtime_resume(chip); @@ -1867,6 +1859,8 @@ static int azx_first_init(struct azx *chip) bus->polling_mode = 1; bus->not_use_interrupts = 1; bus->access_sdnctl_in_dword = 1; + if (!chip->jackpoll_interval) + chip->jackpoll_interval = msecs_to_jiffies(1500); } err = pcim_iomap_regions(pci, 1 << 0, "ICH HD audio"); @@ -1892,13 +1886,9 @@ static int azx_first_init(struct azx *chip) chip->gts_present = true; #endif - if (chip->msi) { - if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { - dev_dbg(card->dev, "Disabling 64bit MSI\n"); - pci->no_64bit_msi = true; - } - if (pci_enable_msi(pci) < 0) - chip->msi = 0; + if (chip->msi && chip->driver_caps & AZX_DCAPS_NO_MSI64) { + dev_dbg(card->dev, "Disabling 64bit MSI\n"); + pci->no_64bit_msi = true; } pci_set_master(pci); @@ -2050,7 +2040,7 @@ static int disable_msi_reset_irq(struct azx *chip) free_irq(bus->irq, chip); bus->irq = -1; chip->card->sync_irq = -1; - pci_disable_msi(chip->pci); + pci_free_irq_vectors(chip->pci); chip->msi = 0; err = azx_acquire_irq(chip, 1); if (err < 0) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 53a5a62b78fa98..763f79f6f32e70 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -292,6 +292,32 @@ struct hda_fixup { } v; }; +/* + * extended form of snd_pci_quirk: + * for PCI SSID matching, use SND_PCI_QUIRK() like before; + * for codec SSID matching, use the new HDA_CODEC_QUIRK() instead + */ +struct hda_quirk { + unsigned short subvendor; /* PCI subvendor ID */ + unsigned short subdevice; /* PCI subdevice ID */ + unsigned short subdevice_mask; /* bitmask to match */ + bool match_codec_ssid; /* match only with codec SSID */ + int value; /* value */ +#ifdef CONFIG_SND_DEBUG_VERBOSE + const char *name; /* name of the device (optional) */ +#endif +}; + +#ifdef CONFIG_SND_DEBUG_VERBOSE +#define HDA_CODEC_QUIRK(vend, dev, xname, val) \ + { _SND_PCI_QUIRK_ID(vend, dev), .value = (val), .name = (xname),\ + .match_codec_ssid = true } +#else +#define HDA_CODEC_QUIRK(vend, dev, xname, val) \ + { _SND_PCI_QUIRK_ID(vend, dev), .value = (val), \ + .match_codec_ssid = true } +#endif + struct snd_hda_pin_quirk { unsigned int codec; /* Codec vendor/device ID */ unsigned short subvendor; /* PCI subvendor ID */ @@ -351,7 +377,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action); void __snd_hda_apply_fixup(struct hda_codec *codec, int id, int action, int depth); void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, + const struct hda_quirk *quirk, const struct hda_fixup *fixlist); void snd_hda_pick_pin_fixup(struct hda_codec *codec, const struct snd_hda_pin_quirk *pin_quirk, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index d967e70a705859..b1e30a83dfb0ce 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -606,7 +606,7 @@ static struct platform_driver tegra_platform_hda = { .of_match_table = hda_tegra_match, }, .probe = hda_tegra_probe, - .remove_new = hda_tegra_remove, + .remove = hda_tegra_remove, .shutdown = hda_tegra_shutdown, }; module_platform_driver(tegra_platform_hda); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 1e9dadcdc51be2..56354fe060a1aa 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -345,7 +345,7 @@ static const struct hda_fixup ad1986a_fixups[] = { }, }; -static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { +static const struct hda_quirk ad1986a_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC), SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD), @@ -588,7 +588,7 @@ static const struct hda_fixup ad1981_fixups[] = { }, }; -static const struct snd_pci_quirk ad1981_fixup_tbl[] = { +static const struct hda_quirk ad1981_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), @@ -1061,7 +1061,7 @@ static const struct hda_fixup ad1884_fixups[] = { }, }; -static const struct snd_pci_quirk ad1884_fixup_tbl[] = { +static const struct hda_quirk ad1884_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART), SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD), diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index e4673a71551a3b..d40197fb5fbd58 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1134,7 +1134,6 @@ struct ca0132_spec { struct hda_codec *codec; struct delayed_work unsol_hp_work; - int quirk; #ifdef ENABLE_TUNING_CONTROLS long cur_ctl_vals[TUNING_CTLS_COUNT]; @@ -1166,7 +1165,6 @@ struct ca0132_spec { * CA0132 quirks table */ enum { - QUIRK_NONE, QUIRK_ALIENWARE, QUIRK_ALIENWARE_M17XR4, QUIRK_SBZ, @@ -1176,10 +1174,11 @@ enum { QUIRK_R3D, QUIRK_AE5, QUIRK_AE7, + QUIRK_NONE = HDA_FIXUP_ID_NOT_SET, }; #ifdef CONFIG_PCI -#define ca0132_quirk(spec) ((spec)->quirk) +#define ca0132_quirk(spec) ((spec)->codec->fixup_id) #define ca0132_use_pci_mmio(spec) ((spec)->use_pci_mmio) #define ca0132_use_alt_functions(spec) ((spec)->use_alt_functions) #define ca0132_use_alt_controls(spec) ((spec)->use_alt_controls) @@ -1293,7 +1292,7 @@ static const struct hda_pintbl ae7_pincfgs[] = { {} }; -static const struct snd_pci_quirk ca0132_quirks[] = { +static const struct hda_quirk ca0132_quirks[] = { SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4), SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE), @@ -1316,6 +1315,19 @@ static const struct snd_pci_quirk ca0132_quirks[] = { {} }; +static const struct hda_model_fixup ca0132_quirk_models[] = { + { .id = QUIRK_ALIENWARE, .name = "alienware" }, + { .id = QUIRK_ALIENWARE_M17XR4, .name = "alienware-m17xr4" }, + { .id = QUIRK_SBZ, .name = "sbz" }, + { .id = QUIRK_ZXR, .name = "zxr" }, + { .id = QUIRK_ZXR_DBPRO, .name = "zxr-dbpro" }, + { .id = QUIRK_R3DI, .name = "r3di" }, + { .id = QUIRK_R3D, .name = "r3d" }, + { .id = QUIRK_AE5, .name = "ae5" }, + { .id = QUIRK_AE7, .name = "ae7" }, + {} +}; + /* Output selection quirk info structures. */ #define MAX_QUIRK_MMIO_GPIO_SET_VALS 3 #define MAX_QUIRK_SCP_SET_VALS 2 @@ -9957,17 +9969,15 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) */ static void sbz_detect_quirk(struct hda_codec *codec) { - struct ca0132_spec *spec = codec->spec; - switch (codec->core.subsystem_id) { case 0x11020033: - spec->quirk = QUIRK_ZXR; + codec->fixup_id = QUIRK_ZXR; break; case 0x1102003f: - spec->quirk = QUIRK_ZXR_DBPRO; + codec->fixup_id = QUIRK_ZXR_DBPRO; break; default: - spec->quirk = QUIRK_SBZ; + codec->fixup_id = QUIRK_SBZ; break; } } @@ -9976,7 +9986,6 @@ static int patch_ca0132(struct hda_codec *codec) { struct ca0132_spec *spec; int err; - const struct snd_pci_quirk *quirk; codec_dbg(codec, "patch_ca0132\n"); @@ -9987,11 +9996,7 @@ static int patch_ca0132(struct hda_codec *codec) spec->codec = codec; /* Detect codec quirk */ - quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks); - if (quirk) - spec->quirk = quirk->value; - else - spec->quirk = QUIRK_NONE; + snd_hda_pick_fixup(codec, ca0132_quirk_models, ca0132_quirks, NULL); if (ca0132_quirk(spec) == QUIRK_SBZ) sbz_detect_quirk(codec); @@ -10068,7 +10073,7 @@ static int patch_ca0132(struct hda_codec *codec) spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20); if (spec->mem_base == NULL) { codec_warn(codec, "pci_iomap failed! Setting quirk to QUIRK_NONE."); - spec->quirk = QUIRK_NONE; + codec->fixup_id = QUIRK_NONE; } } #endif diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 654724559355ef..06e046214a4134 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -385,7 +385,7 @@ static const struct hda_model_fixup cs420x_models[] = { {} }; -static const struct snd_pci_quirk cs420x_fixup_tbl[] = { +static const struct hda_quirk cs420x_fixup_tbl[] = { SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), @@ -634,13 +634,13 @@ static const struct hda_model_fixup cs4208_models[] = { {} }; -static const struct snd_pci_quirk cs4208_fixup_tbl[] = { +static const struct hda_quirk cs4208_fixup_tbl[] = { SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO), {} /* terminator */ }; /* codec SSID matching */ -static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = { +static const struct hda_quirk cs4208_mac_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI), SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), @@ -818,7 +818,7 @@ static const struct hda_model_fixup cs421x_models[] = { {} }; -static const struct snd_pci_quirk cs421x_fixup_tbl[] = { +static const struct hda_quirk cs421x_fixup_tbl[] = { /* Test Intel board + CDB2410 */ SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), {} /* terminator */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index b2bcdf76da3058..538c37a78a56f7 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -307,6 +307,7 @@ enum { CXT_FIXUP_HP_MIC_NO_PRESENCE, CXT_PINCFG_SWS_JS201D, CXT_PINCFG_TOP_SPEAKER, + CXT_FIXUP_HP_A_U, }; /* for hda_fixup_thinkpad_acpi() */ @@ -774,6 +775,18 @@ static void cxt_setup_mute_led(struct hda_codec *codec, } } +static void cxt_setup_gpio_unmute(struct hda_codec *codec, + unsigned int gpio_mute_mask) +{ + if (gpio_mute_mask) { + // set gpio data to 0. + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, gpio_mute_mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, gpio_mute_mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_STICKY_MASK, 0); + } +} + static void cxt_fixup_mute_led_gpio(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -788,6 +801,15 @@ static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec, cxt_setup_mute_led(codec, 0x10, 0x20); } +static void cxt_fixup_hp_a_u(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + // Init vers in BIOS mute the spk/hp by set gpio high to avoid pop noise, + // so need to unmute once by clearing the gpio data when runs into the system. + if (action == HDA_FIXUP_ACT_INIT) + cxt_setup_gpio_unmute(codec, 0x2); +} + /* ThinkPad X200 & co with cxt5051 */ static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ @@ -828,23 +850,6 @@ static const struct hda_pintbl cxt_pincfg_sws_js201d[] = { {} }; -/* pincfg quirk for Tuxedo Sirius; - * unfortunately the (PCI) SSID conflicts with System76 Pangolin pang14, - * which has incompatible pin setup, so we check the codec SSID (luckily - * different one!) and conditionally apply the quirk here - */ -static void cxt_fixup_sirius_top_speaker(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - /* ignore for incorrectly picked-up pang14 */ - if (codec->core.subsystem_id == 0x278212b3) - return; - /* set up the top speaker pin */ - if (action == HDA_FIXUP_ACT_PRE_PROBE) - snd_hda_codec_set_pincfg(codec, 0x1d, 0x82170111); -} - static const struct hda_fixup cxt_fixups[] = { [CXT_PINCFG_LENOVO_X200] = { .type = HDA_FIXUP_PINS, @@ -1009,12 +1014,19 @@ static const struct hda_fixup cxt_fixups[] = { .v.pins = cxt_pincfg_sws_js201d, }, [CXT_PINCFG_TOP_SPEAKER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1d, 0x82170111 }, + { } + }, + }, + [CXT_FIXUP_HP_A_U] = { .type = HDA_FIXUP_FUNC, - .v.func = cxt_fixup_sirius_top_speaker, + .v.func = cxt_fixup_hp_a_u, }, }; -static const struct snd_pci_quirk cxt5045_fixups[] = { +static const struct hda_quirk cxt5045_fixups[] = { SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105), /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have @@ -1034,7 +1046,7 @@ static const struct hda_model_fixup cxt5045_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5047_fixups[] = { +static const struct hda_quirk cxt5047_fixups[] = { /* HP laptops have really bad sound over 0 dB on NID 0x10. */ SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047), @@ -1046,7 +1058,7 @@ static const struct hda_model_fixup cxt5047_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5051_fixups[] = { +static const struct hda_quirk cxt5051_fixups[] = { SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200), {} @@ -1057,7 +1069,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = { {} }; -static const struct snd_pci_quirk cxt5066_fixups[] = { +static const struct hda_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), @@ -1086,6 +1098,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), + SND_PCI_QUIRK(0x14f1, 0x0252, "MBX-Z60MR100", CXT_FIXUP_HP_A_U), SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), @@ -1109,8 +1122,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI), SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), - SND_PCI_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER), - SND_PCI_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER), + HDA_CODEC_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER), + HDA_CODEC_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER), {} }; @@ -1131,6 +1144,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" }, { .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" }, { .id = CXT_PINCFG_TOP_SPEAKER, .name = "sirius-top-speaker" }, + { .id = CXT_FIXUP_HP_A_U, .name = "HP-U-support" }, {} }; diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c index 36b411d1a9609a..759f48038273df 100644 --- a/sound/pci/hda/patch_cs8409-tables.c +++ b/sound/pci/hda/patch_cs8409-tables.c @@ -473,7 +473,7 @@ struct sub_codec dolphin_cs42l42_1 = { * Arrays Used for all projects using CS8409 ******************************************************************************/ -const struct snd_pci_quirk cs8409_fixup_tbl[] = { +const struct hda_quirk cs8409_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE), SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE), SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE), diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h index 937e9387abdc7a..5e48115caf096b 100644 --- a/sound/pci/hda/patch_cs8409.h +++ b/sound/pci/hda/patch_cs8409.h @@ -355,7 +355,7 @@ int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uc extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback; extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture; -extern const struct snd_pci_quirk cs8409_fixup_tbl[]; +extern const struct hda_quirk cs8409_fixup_tbl[]; extern const struct hda_model_fixup cs8409_models[]; extern const struct hda_fixup cs8409_fixups[]; extern const struct hda_verb cs8409_cs42l42_init_verbs[]; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 24b4fe99304a40..61ba5dc35b8b81 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -473,6 +473,8 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) break; case 0x10ec0234: case 0x10ec0274: + alc_write_coef_idx(codec, 0x6e, 0x0c25); + fallthrough; case 0x10ec0294: case 0x10ec0700: case 0x10ec0701: @@ -1565,7 +1567,7 @@ static const struct hda_fixup alc880_fixups[] = { }, }; -static const struct snd_pci_quirk alc880_fixup_tbl[] = { +static const struct hda_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A), SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), @@ -1874,7 +1876,7 @@ static const struct hda_fixup alc260_fixups[] = { }, }; -static const struct snd_pci_quirk alc260_fixup_tbl[] = { +static const struct hda_quirk alc260_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1), SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1), @@ -2566,7 +2568,7 @@ static const struct hda_fixup alc882_fixups[] = { }, }; -static const struct snd_pci_quirk alc882_fixup_tbl[] = { +static const struct hda_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD), @@ -2910,7 +2912,7 @@ static const struct hda_fixup alc262_fixups[] = { }, }; -static const struct snd_pci_quirk alc262_fixup_tbl[] = { +static const struct hda_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200), SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), @@ -3071,7 +3073,7 @@ static const struct hda_model_fixup alc268_fixup_models[] = { {} }; -static const struct snd_pci_quirk alc268_fixup_tbl[] = { +static const struct hda_quirk alc268_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF), SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC), /* below is codec SSID since multiple Toshiba laptops have the @@ -3613,25 +3615,22 @@ static void alc256_init(struct hda_codec *codec) hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); - if (hp_pin_sense) + if (hp_pin_sense) { msleep(2); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ - alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ - - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - if (hp_pin_sense || spec->ultra_low_power) - msleep(85); - - snd_hda_codec_write(codec, hp_pin, 0, + snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - if (hp_pin_sense || spec->ultra_low_power) - msleep(100); + msleep(75); + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + + msleep(75); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ + } alc_update_coef_idx(codec, 0x46, 3 << 12, 0); - alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */ alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15); /* @@ -3655,29 +3654,28 @@ static void alc256_shutup(struct hda_codec *codec) alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); - if (hp_pin_sense) + if (hp_pin_sense) { msleep(2); - snd_hda_codec_write(codec, hp_pin, 0, + snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp_pin_sense || spec->ultra_low_power) - msleep(85); + msleep(75); /* 3k pull low control for Headset jack. */ /* NOTE: call this before clearing the pin, otherwise codec stalls */ /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly * when booting with headset plugged. So skip setting it for the codec alc257 */ - if (spec->en_3kpull_low) - alc_update_coef_idx(codec, 0x46, 0, 3 << 12); + if (spec->en_3kpull_low) + alc_update_coef_idx(codec, 0x46, 0, 3 << 12); - if (!spec->no_shutup_pins) - snd_hda_codec_write(codec, hp_pin, 0, + if (!spec->no_shutup_pins) + snd_hda_codec_write(codec, hp_pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - if (hp_pin_sense || spec->ultra_low_power) - msleep(100); + msleep(75); + } alc_auto_setup_eapd(codec, false); alc_shutup_pins(codec); @@ -3772,33 +3770,28 @@ static void alc225_init(struct hda_codec *codec) hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); hp2_pin_sense = snd_hda_jack_detect(codec, 0x16); - if (hp1_pin_sense || hp2_pin_sense) + if (hp1_pin_sense || hp2_pin_sense) { msleep(2); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ - alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */ - - if (hp1_pin_sense || spec->ultra_low_power) - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp2_pin_sense) - snd_hda_codec_write(codec, 0x16, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power) - msleep(85); - - if (hp1_pin_sense || spec->ultra_low_power) - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - if (hp2_pin_sense) - snd_hda_codec_write(codec, 0x16, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + msleep(75); - if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power) - msleep(100); + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); - alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ + msleep(75); + alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */ + } } static void alc225_shutup(struct hda_codec *codec) @@ -3810,36 +3803,35 @@ static void alc225_shutup(struct hda_codec *codec) if (!hp_pin) hp_pin = 0x21; - alc_disable_headset_jack_key(codec); - /* 3k pull low control for Headset jack. */ - alc_update_coef_idx(codec, 0x4a, 0, 3 << 10); - hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin); hp2_pin_sense = snd_hda_jack_detect(codec, 0x16); - if (hp1_pin_sense || hp2_pin_sense) + if (hp1_pin_sense || hp2_pin_sense) { + alc_disable_headset_jack_key(codec); + /* 3k pull low control for Headset jack. */ + alc_update_coef_idx(codec, 0x4a, 0, 3 << 10); msleep(2); - if (hp1_pin_sense || spec->ultra_low_power) - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp2_pin_sense) - snd_hda_codec_write(codec, 0x16, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - - if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power) - msleep(85); + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (hp1_pin_sense || spec->ultra_low_power) - snd_hda_codec_write(codec, hp_pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); - if (hp2_pin_sense) - snd_hda_codec_write(codec, 0x16, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + msleep(75); - if (hp1_pin_sense || hp2_pin_sense || spec->ultra_low_power) - msleep(100); + if (hp1_pin_sense) + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + if (hp2_pin_sense) + snd_hda_codec_write(codec, 0x16, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + msleep(75); + alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); + alc_enable_headset_jack_key(codec); + } alc_auto_setup_eapd(codec, false); alc_shutup_pins(codec); if (spec->ultra_low_power) { @@ -3850,9 +3842,6 @@ static void alc225_shutup(struct hda_codec *codec) alc_update_coef_idx(codec, 0x4a, 3<<4, 2<<4); msleep(30); } - - alc_update_coef_idx(codec, 0x4a, 3 << 10, 0); - alc_enable_headset_jack_key(codec); } static void alc_default_init(struct hda_codec *codec) @@ -6502,6 +6491,16 @@ static void alc285_fixup_speaker2_to_dac1(struct hda_codec *codec, } } +/* disable DAC3 (0x06) selection on NID 0x15 - share Speaker/Bass Speaker DAC 0x03 */ +static void alc294_fixup_bass_speaker_15(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + static const hda_nid_t conn[] = { 0x02, 0x03 }; + snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn); + } +} + /* Hook to update amp GPIO4 for automute */ static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec, struct hda_jack_callback *jack) @@ -7559,6 +7558,7 @@ enum { ALC269_FIXUP_THINKPAD_ACPI, ALC269_FIXUP_DMIC_THINKPAD_ACPI, ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13, + ALC269VC_FIXUP_INFINIX_Y4_MAX, ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO, ALC255_FIXUP_ACER_MIC_NO_PRESENCE, ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, @@ -7714,6 +7714,7 @@ enum { ALC274_FIXUP_HP_MIC, ALC274_FIXUP_HP_HEADSET_MIC, ALC274_FIXUP_HP_ENVY_GPIO, + ALC274_FIXUP_ASUS_ZEN_AIO_27, ALC256_FIXUP_ASUS_HPE, ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, ALC287_FIXUP_HP_GPIO_LED, @@ -7736,8 +7737,6 @@ enum { ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE, ALC287_FIXUP_YOGA7_14ITL_SPEAKERS, ALC298_FIXUP_LENOVO_C940_DUET7, - ALC287_FIXUP_LENOVO_14IRP8_DUETITL, - ALC287_FIXUP_LENOVO_LEGION_7, ALC287_FIXUP_13S_GEN2_SPEAKERS, ALC256_FIXUP_SET_COEF_DEFAULTS, ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE, @@ -7782,10 +7781,10 @@ enum { ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1, ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318, ALC256_FIXUP_CHROME_BOOK, - ALC287_FIXUP_LENOVO_14ARP8_LEGION_IAH7, - ALC287_FIXUP_LENOVO_SSID_17AA3820, ALC245_FIXUP_CLEVO_NOISY_MIC, ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE, + ALC233_FIXUP_MEDION_MTL_SPK, + ALC294_FIXUP_BASS_SPEAKER_15, }; /* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -7805,72 +7804,6 @@ static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec, __snd_hda_apply_fixup(codec, id, action, 0); } -/* A special fixup for Lenovo Slim/Yoga Pro 9 14IRP8 and Yoga DuetITL 2021; - * 14IRP8 PCI SSID will mistakenly be matched with the DuetITL codec SSID, - * so we need to apply a different fixup in this case. The only DuetITL codec - * SSID reported so far is the 17aa:3802 while the 14IRP8 has the 17aa:38be - * and 17aa:38bf. If it weren't for the PCI SSID, the 14IRP8 models would - * have matched correctly by their codecs. - */ -static void alc287_fixup_lenovo_14irp8_duetitl(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa3802) - id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* DuetITL */ - else - id = ALC287_FIXUP_TAS2781_I2C; /* 14IRP8 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - -/* Similar to above the Lenovo Yoga Pro 7 14ARP8 PCI SSID matches the codec SSID of the - Legion Y9000X 2022 IAH7.*/ -static void alc287_fixup_lenovo_14arp8_legion_iah7(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa386e) - id = ALC287_FIXUP_CS35L41_I2C_2; /* Legion Y9000X 2022 IAH7 */ - else - id = ALC285_FIXUP_SPEAKER2_TO_DAC1; /* Yoga Pro 7 14ARP8 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - -/* Another hilarious PCI SSID conflict with Lenovo Legion Pro 7 16ARX8H (with - * TAS2781 codec) and Legion 7i 16IAX7 (with CS35L41 codec); - * we apply a corresponding fixup depending on the codec SSID instead - */ -static void alc287_fixup_lenovo_legion_7(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa38a8) - id = ALC287_FIXUP_TAS2781_I2C; /* Legion Pro 7 16ARX8H */ - else - id = ALC287_FIXUP_CS35L41_I2C_2; /* Legion 7i 16IAX7 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - -/* Yet more conflicting PCI SSID (17aa:3820) on two Lenovo models */ -static void alc287_fixup_lenovo_ssid_17aa3820(struct hda_codec *codec, - const struct hda_fixup *fix, - int action) -{ - int id; - - if (codec->core.subsystem_id == 0x17aa3820) - id = ALC269_FIXUP_ASPIRE_HEADSET_MIC; /* IdeaPad 330-17IKB 81DM */ - else /* 0x17aa3802 */ - id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* "Yoga Duet 7 13ITL6 */ - __snd_hda_apply_fixup(codec, id, action, 0); -} - static const struct hda_fixup alc269_fixups[] = { [ALC269_FIXUP_GPIO2] = { .type = HDA_FIXUP_FUNC, @@ -8015,6 +7948,15 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, + [ALC269VC_FIXUP_INFINIX_Y4_MAX] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170150 }, /* use as internal speaker */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + }, [ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -9575,6 +9517,26 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc274_fixup_hp_envy_gpio, }, + [ALC274_FIXUP_ASUS_ZEN_AIO_27] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x20, AC_VERB_SET_COEF_INDEX, 0x10 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xc420 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x40 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x8800 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x0249 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x202b }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x62 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0xa007 }, + { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x5060 }, + {} + }, + .chained = true, + .chain_id = ALC2XX_FIXUP_HEADSET_MIC, + }, [ALC256_FIXUP_ASUS_HPE] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -9810,14 +9772,6 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc298_fixup_lenovo_c940_duet7, }, - [ALC287_FIXUP_LENOVO_14IRP8_DUETITL] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_14irp8_duetitl, - }, - [ALC287_FIXUP_LENOVO_LEGION_7] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_legion_7, - }, [ALC287_FIXUP_13S_GEN2_SPEAKERS] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -10002,10 +9956,6 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK, }, - [ALC287_FIXUP_LENOVO_14ARP8_LEGION_IAH7] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_14arp8_legion_iah7, - }, [ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN] = { .type = HDA_FIXUP_FUNC, .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin, @@ -10140,10 +10090,6 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC225_FIXUP_HEADSET_JACK }, - [ALC287_FIXUP_LENOVO_SSID_17AA3820] = { - .type = HDA_FIXUP_FUNC, - .v.func = alc287_fixup_lenovo_ssid_17aa3820, - }, [ALC245_FIXUP_CLEVO_NOISY_MIC] = { .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_limit_int_mic_boost, @@ -10160,9 +10106,20 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, + [ALC233_FIXUP_MEDION_MTL_SPK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170110 }, + { } + }, + }, + [ALC294_FIXUP_BASS_SPEAKER_15] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc294_fixup_bass_speaker_15, + }, }; -static const struct snd_pci_quirk alc269_fixup_tbl[] = { +static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), @@ -10206,6 +10163,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC), SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED), SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X), @@ -10404,6 +10362,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87d3, "HP Laptop 15-gw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x87df, "HP ProBook 430 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x87f1, "HP ProBook 630 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), @@ -10585,6 +10544,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8cdf, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ce0, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -10668,6 +10634,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606WA", ALC294_FIXUP_BASS_SPEAKER_15), SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), @@ -10685,6 +10652,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), + SND_PCI_QUIRK(0x1043, 0x31d0, "ASUS Zen AIO 27 Z272SD_A272SD", ALC274_FIXUP_ASUS_ZEN_AIO_27), SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), @@ -10738,6 +10706,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP), + SND_PCI_QUIRK(0x144d, 0xca06, "Samsung Galaxy Book3 360 (NP730QFG)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc868, "Samsung Galaxy Book2 Pro (NP930XED)", ALC298_FIXUP_SAMSUNG_AMP), SND_PCI_QUIRK(0x144d, 0xc870, "Samsung Galaxy Book2 Pro (NP950XED)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS), SND_PCI_QUIRK(0x144d, 0xc872, "Samsung Galaxy Book2 Pro (NP950XEE)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS), @@ -10895,11 +10864,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340), SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8 / DuetITL 2021", ALC287_FIXUP_LENOVO_14IRP8_DUETITL), + HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), + SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C), SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7), SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS), - SND_PCI_QUIRK(0x17aa, 0x3820, "IdeaPad 330 / Yoga Duet 7", ALC287_FIXUP_LENOVO_SSID_17AA3820), + HDA_CODEC_QUIRK(0x17aa, 0x3820, "IdeaPad 330-17IKB 81DM", ALC269_FIXUP_ASPIRE_HEADSET_MIC), + SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF), SND_PCI_QUIRK(0x17aa, 0x3834, "Lenovo IdeaPad Slim 9i 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), @@ -10913,8 +10884,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN), - SND_PCI_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7 / Yoga Pro 7 14ARP8", ALC287_FIXUP_LENOVO_14ARP8_LEGION_IAH7), - SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7/7i", ALC287_FIXUP_LENOVO_LEGION_7), + HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1), + HDA_CODEC_QUIRK(0x17aa, 0x386f, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), + SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C), SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2), @@ -11025,7 +10998,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13), SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO), + SND_PCI_QUIRK(0x2782, 0x1701, "Infinix Y4 Max", ALC269VC_FIXUP_INFINIX_Y4_MAX), + SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX), SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME), + SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK), SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), @@ -11085,7 +11061,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { {} }; -static const struct snd_pci_quirk alc269_fixup_vendor_tbl[] = { +static const struct hda_quirk alc269_fixup_vendor_tbl[] = { SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), @@ -11224,6 +11200,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"}, {.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"}, {.id = ALC236_FIXUP_LENOVO_INV_DMIC, .name = "alc236-fixup-lenovo-inv-mic"}, + {.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"}, {} }; #define ALC225_STANDARD_PINS \ @@ -12021,7 +11998,7 @@ static const struct hda_fixup alc861_fixups[] = { } }; -static const struct snd_pci_quirk alc861_fixup_tbl[] = { +static const struct hda_quirk alc861_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J), SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J), SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), @@ -12125,7 +12102,7 @@ static const struct hda_fixup alc861vd_fixups[] = { }, }; -static const struct snd_pci_quirk alc861vd_fixup_tbl[] = { +static const struct hda_quirk alc861vd_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS), SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1), SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS), @@ -12926,7 +12903,7 @@ static const struct hda_fixup alc662_fixups[] = { }, }; -static const struct snd_pci_quirk alc662_fixup_tbl[] = { +static const struct hda_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3), SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), @@ -13348,7 +13325,7 @@ MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek HD-audio codec"); -MODULE_IMPORT_NS(SND_HDA_SCODEC_COMPONENT); +MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT"); static struct hda_codec_driver realtek_driver = { .id = snd_hda_id_realtek, diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ae1a34c68c6161..bde6b737385831 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1462,7 +1462,7 @@ static const struct hda_model_fixup stac9200_models[] = { {} }; -static const struct snd_pci_quirk stac9200_fixup_tbl[] = { +static const struct hda_quirk stac9200_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), @@ -1683,7 +1683,7 @@ static const struct hda_model_fixup stac925x_models[] = { {} }; -static const struct snd_pci_quirk stac925x_fixup_tbl[] = { +static const struct hda_quirk stac925x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), @@ -1957,7 +1957,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { +static const struct hda_quirk stac92hd73xx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), @@ -2753,7 +2753,7 @@ static const struct hda_model_fixup stac92hd83xxx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { +static const struct hda_quirk stac92hd83xxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD83XXX_REF), @@ -3236,7 +3236,7 @@ static const struct hda_model_fixup stac92hd71bxx_models[] = { {} }; -static const struct snd_pci_quirk stac92hd71bxx_fixup_tbl[] = { +static const struct hda_quirk stac92hd71bxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD71BXX_REF), @@ -3496,7 +3496,7 @@ static const struct hda_pintbl ecs202_pin_configs[] = { }; /* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */ -static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = { +static const struct hda_quirk stac922x_intel_mac_fixup_tbl[] = { SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3), SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1), SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2), @@ -3640,7 +3640,7 @@ static const struct hda_model_fixup stac922x_models[] = { {} }; -static const struct snd_pci_quirk stac922x_fixup_tbl[] = { +static const struct hda_quirk stac922x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D945_REF), @@ -3968,7 +3968,7 @@ static const struct hda_model_fixup stac927x_models[] = { {} }; -static const struct snd_pci_quirk stac927x_fixup_tbl[] = { +static const struct hda_quirk stac927x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D965_REF), @@ -4178,7 +4178,7 @@ static const struct hda_model_fixup stac9205_models[] = { {} }; -static const struct snd_pci_quirk stac9205_fixup_tbl[] = { +static const struct hda_quirk stac9205_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), @@ -4255,7 +4255,7 @@ static const struct hda_fixup stac92hd95_fixups[] = { }, }; -static const struct snd_pci_quirk stac92hd95_fixup_tbl[] = { +static const struct hda_quirk stac92hd95_fixup_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1911, "HP Spectre 13", STAC_92HD95_HP_BASS), {} /* terminator */ }; @@ -5002,7 +5002,7 @@ static const struct hda_fixup stac9872_fixups[] = { }, }; -static const struct snd_pci_quirk stac9872_fixup_tbl[] = { +static const struct hda_quirk stac9872_fixup_tbl[] = { SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0, "Sony VAIO F/S", STAC_9872_VAIO), {} /* terminator */ diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index a8ef4bb70dd057..d0893059b1b9b7 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1035,7 +1035,7 @@ static const struct hda_fixup via_fixups[] = { }, }; -static const struct snd_pci_quirk vt2002p_fixups[] = { +static const struct hda_quirk vt2002p_fixups[] = { SND_PCI_QUIRK(0x1043, 0x13f7, "Asus B23E", VIA_FIXUP_POWER_SAVE), SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75), SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST), diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 370d847517f9ab..0af015806aba57 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -110,10 +111,20 @@ static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) return 1; } +static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false }; + +static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = { + { "speakerid-gpios", &speakerid_gpios, 1 }, + { } +}; + static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) { struct acpi_device *adev; + struct device *physdev; LIST_HEAD(resources); + const char *sub; + uint32_t subid; int ret; adev = acpi_dev_get_first_match_dev(hid, NULL, -1); @@ -123,18 +134,46 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) return -ENODEV; } + physdev = get_device(acpi_get_first_physical_node(adev)); ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); - if (ret < 0) + if (ret < 0) { + dev_err(p->dev, "Failed to get ACPI resource.\n"); + goto err; + } + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); + if (IS_ERR(sub)) { + dev_err(p->dev, "Failed to get SUBSYS ID.\n"); + ret = PTR_ERR(sub); goto err; + } + /* Speaker id was needed for ASUS projects. */ + ret = kstrtou32(sub, 16, &subid); + if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) { + ret = devm_acpi_dev_add_driver_gpios(p->dev, + tas2781_speaker_id_gpios); + if (ret < 0) + dev_err(p->dev, "Failed to add driver gpio %d.\n", + ret); + p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN); + if (IS_ERR(p->speaker_id)) { + dev_err(p->dev, "Failed to get Speaker id.\n"); + ret = PTR_ERR(p->speaker_id); + goto err; + } + } else { + p->speaker_id = NULL; + } acpi_dev_free_resource_list(&resources); strscpy(p->dev_name, hid, sizeof(p->dev_name)); + put_device(physdev); acpi_dev_put(adev); return 0; err: dev_err(p->dev, "read acpi error, ret: %d\n", ret); + put_device(physdev); acpi_dev_put(adev); return ret; @@ -615,7 +654,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) struct tasdevice_priv *tas_priv = context; struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); struct hda_codec *codec = tas_priv->codec; - int i, ret; + int i, ret, spk_id; pm_runtime_get_sync(tas_priv->dev); mutex_lock(&tas_priv->codec_lock); @@ -648,8 +687,25 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) tasdevice_dsp_remove(tas_priv); tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; - scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X.bin", - codec->core.subsystem_id & 0xffff); + if (tas_priv->speaker_id != NULL) { + // Speaker id need to be checked for ASUS only. + spk_id = gpiod_get_value(tas_priv->speaker_id); + if (spk_id < 0) { + // Speaker id is not valid, use default. + dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id); + spk_id = 0; + } + snprintf(tas_priv->coef_binaryname, + sizeof(tas_priv->coef_binaryname), + "TAS2XXX%04X%d.bin", + lower_16_bits(codec->core.subsystem_id), + spk_id); + } else { + snprintf(tas_priv->coef_binaryname, + sizeof(tas_priv->coef_binaryname), + "TAS2XXX%04X.bin", + lower_16_bits(codec->core.subsystem_id)); + } ret = tasdevice_dsp_parser(tas_priv); if (ret) { dev_err(tas_priv->dev, "dspfw load %s error\n", @@ -977,4 +1033,4 @@ module_i2c_driver(tas2781_hda_i2c_driver); MODULE_DESCRIPTION("TAS2781 HDA Driver"); MODULE_AUTHOR("Shenghao Ding, TI, "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_TAS2781_FMWLIB); +MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB"); diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 096ec76f530467..a12dafbf53ab24 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -170,14 +170,9 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el tmp = stac9460_get(ice, idx); ovol = 0x7f - (tmp & 0x7f); change = (ovol != nvol); - if (change) { - ovol = (0x7f - nvol) | (tmp & 0x80); - /* - dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n", - idx, ovol); - */ + if (change) stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); - } + return change; } diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index e62fb1ad6d77c5..49b71082c48597 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2108,7 +2108,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) for (i=0; ivolumePhase[i] = 0; - err = pcim_iomap_regions_request_all(pci, 1 << 0, "korg1212"); + err = pcim_request_all_regions(pci, "korg1212"); if (err < 0) return err; @@ -2130,7 +2130,9 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci) korg1212->iomem2, iomem2_size, stateName[korg1212->cardState]); - korg1212->iobase = pcim_iomap_table(pci)[0]; + korg1212->iobase = pcim_iomap(pci, 0, 0); + if (!korg1212->iobase) + return -ENOMEM; err = devm_request_irq(&pci->dev, pci->irq, snd_korg1212_interrupt, IRQF_SHARED, diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index 8e29c92830ad64..f1b0cf9ea55557 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c @@ -160,7 +160,7 @@ static SIMPLE_DEV_PM_OPS(snd_pmac_pm, snd_pmac_driver_suspend, snd_pmac_driver_r static struct platform_driver snd_pmac_driver = { .probe = snd_pmac_probe, - .remove_new = snd_pmac_remove, + .remove = snd_pmac_remove, .driver = { .name = SND_PMAC_DRIVER, .pm = SND_PMAC_PM_OPS, diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 936cd6e91529c8..39bf51ff43a1ca 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -315,8 +315,6 @@ static void aica_period_elapsed(struct timer_list *t) static void spu_begin_dma(struct snd_pcm_substream *substream) { struct snd_card_aica *dreamcastcard; - struct snd_pcm_runtime *runtime; - runtime = substream->runtime; dreamcastcard = substream->pcm->private_data; /*get the queue to do the work */ schedule_work(&(dreamcastcard->spu_dma_work)); @@ -601,7 +599,7 @@ static int snd_aica_probe(struct platform_device *devptr) static struct platform_driver snd_aica_driver = { .probe = snd_aica_probe, - .remove_new = snd_aica_remove, + .remove = snd_aica_remove, .driver = { .name = SND_AICA_DRIVER, }, diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c index e7b6ce7bd086bd..a4d07438ad64b3 100644 --- a/sound/sh/sh_dac_audio.c +++ b/sound/sh/sh_dac_audio.c @@ -163,7 +163,7 @@ static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, /* channel is not used (interleaved data) */ struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); - if (copy_from_iter_toio(chip->data_buffer + pos, src, count)) + if (copy_from_iter(chip->data_buffer + pos, src, count) != count) return -EFAULT; chip->buffer_end = chip->data_buffer + pos + count; @@ -182,7 +182,7 @@ static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream, /* channel is not used (interleaved data) */ struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); - memset_io(chip->data_buffer + pos, 0, count); + memset(chip->data_buffer + pos, 0, count); chip->buffer_end = chip->data_buffer + pos + count; if (chip->empty) { @@ -211,7 +211,6 @@ static const struct snd_pcm_ops snd_sh_dac_pcm_ops = { .pointer = snd_sh_dac_pcm_pointer, .copy = snd_sh_dac_pcm_copy, .fill_silence = snd_sh_dac_pcm_silence, - .mmap = snd_pcm_lib_mmap_iomem, }; static int snd_sh_dac_pcm(struct snd_sh_dac *chip, int device) @@ -383,7 +382,7 @@ static int snd_sh_dac_probe(struct platform_device *devptr) */ static struct platform_driver sh_dac_driver = { .probe = snd_sh_dac_probe, - .remove_new = snd_sh_dac_remove, + .remove = snd_sh_dac_remove, .driver = { .name = "dac_audio", }, diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index e87bd15a8b4393..5efba76abb31a2 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -106,9 +106,10 @@ source "sound/soc/meson/Kconfig" source "sound/soc/mxs/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/qcom/Kconfig" +source "sound/soc/renesas/Kconfig" source "sound/soc/rockchip/Kconfig" source "sound/soc/samsung/Kconfig" -source "sound/soc/sh/Kconfig" +source "sound/soc/sdca/Kconfig" source "sound/soc/sof/Kconfig" source "sound/soc/spear/Kconfig" source "sound/soc/sprd/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 775bb38c2ed447..08baaa11d8139f 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -59,9 +59,10 @@ obj-$(CONFIG_SND_SOC) += mxs/ obj-$(CONFIG_SND_SOC) += kirkwood/ obj-$(CONFIG_SND_SOC) += pxa/ obj-$(CONFIG_SND_SOC) += qcom/ +obj-$(CONFIG_SND_SOC) += renesas/ obj-$(CONFIG_SND_SOC) += rockchip/ obj-$(CONFIG_SND_SOC) += samsung/ -obj-$(CONFIG_SND_SOC) += sh/ +obj-$(CONFIG_SND_SOC) += sdca/ obj-$(CONFIG_SND_SOC) += sof/ obj-$(CONFIG_SND_SOC) += spear/ obj-$(CONFIG_SND_SOC) += sprd/ diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 6dec44f516c13f..c7590d4989bba5 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -163,6 +163,7 @@ config SND_SOC_AMD_SOUNDWIRE config SND_SOC_AMD_PS tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support" select SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE + select SND_SOC_ACPI_AMD_MATCH depends on X86 && PCI && ACPI help This option enables Audio Coprocessor i.e ACP v6.3 support on diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 77cf72082e73d7..02b04f355ca663 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -542,7 +542,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .init = cz_da7219_init, - .dpcm_playback = 1, + .playback_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_da7219_play_ops, SND_SOC_DAILINK_REG(designware1, dlgs, platform), @@ -552,7 +552,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .stream_name = "Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_da7219_cap_ops, SND_SOC_DAILINK_REG(designware2, dlgs, platform), @@ -562,7 +562,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_playback = 1, + .playback_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_max_play_ops, SND_SOC_DAILINK_REG(designware3, mx, platform), @@ -573,7 +573,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .stream_name = "DMIC0 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_dmic0_cap_ops, SND_SOC_DAILINK_REG(designware3, adau, platform), @@ -584,7 +584,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .stream_name = "DMIC1 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_dmic1_cap_ops, SND_SOC_DAILINK_REG(designware2, adau, platform), @@ -598,7 +598,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .init = cz_rt5682_init, - .dpcm_playback = 1, + .playback_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_play_ops, SND_SOC_DAILINK_REG(designware1, rt5682, platform), @@ -608,7 +608,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .stream_name = "Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_cap_ops, SND_SOC_DAILINK_REG(designware2, rt5682, platform), @@ -618,7 +618,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_playback = 1, + .playback_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_max_play_ops, SND_SOC_DAILINK_REG(designware3, mx, platform), @@ -629,7 +629,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .stream_name = "DMIC0 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_dmic0_cap_ops, SND_SOC_DAILINK_REG(designware3, adau, platform), @@ -640,7 +640,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .stream_name = "DMIC1 Capture", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_dmic1_cap_ops, SND_SOC_DAILINK_REG(designware2, adau, platform), diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c index 3756b8bef17bc6..0193b3eae7a660 100644 --- a/sound/soc/amd/acp-es8336.c +++ b/sound/soc/amd/acp-es8336.c @@ -150,8 +150,6 @@ static struct snd_soc_dai_link st_dai_es8336[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, - .dpcm_capture = 1, - .dpcm_playback = 1, .init = st_es8336_init, .ops = &st_es8336_ops, SND_SOC_DAILINK_REG(designware1, codec, platform), diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 88391e4c17e3c6..03f3fcbba5af15 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -119,10 +119,17 @@ config SND_SOC_AMD_SOF_MACH help This option enables SOF sound card support for ACP audio. +config SND_SOC_AMD_SDW_MACH_COMMON + tristate + help + This option enables common SoundWire Machine driver module for + AMD platforms. + config SND_SOC_AMD_SOF_SDW_MACH tristate "AMD SOF Soundwire Machine Driver Support" depends on X86 && PCI && ACPI depends on SOUNDWIRE + select SND_SOC_AMD_SDW_MACH_COMMON select SND_SOC_SDW_UTILS select SND_SOC_DMIC select SND_SOC_RT711_SDW @@ -137,6 +144,28 @@ config SND_SOC_AMD_SOF_SDW_MACH on AMD platform. If unsure select "N". +config SND_SOC_AMD_LEGACY_SDW_MACH + tristate "AMD Legacy(No DSP) Soundwire Machine Driver Support" + depends on X86 && PCI && ACPI + depends on SOUNDWIRE + select SND_SOC_AMD_SDW_MACH_COMMON + select SND_SOC_SDW_UTILS + select SND_SOC_DMIC + select SND_SOC_RT711_SDW + select SND_SOC_RT711_SDCA_SDW + select SND_SOC_RT712_SDCA_SDW + select SND_SOC_RT712_SDCA_DMIC_SDW + select SND_SOC_RT1316_SDW + select SND_SOC_RT715_SDW + select SND_SOC_RT715_SDCA_SDW + select SND_SOC_RT722_SDCA_SDW + help + This option enables Legacy(No DSP) sound card support for SoundWire + enabled AMD platforms along with ACP PDM controller. + Say Y if you want to enable SoundWire based machine driver support + on AMD platform. + If unsure select "N". + endif # SND_SOC_AMD_ACP_COMMON config SND_AMD_SOUNDWIRE_ACPI diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index 82cf5d180b3a14..bb2702036338b8 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -23,7 +23,9 @@ snd-acp-mach-y := acp-mach-common.o snd-acp-legacy-mach-y := acp-legacy-mach.o acp3x-es83xx/acp3x-es83xx.o snd-acp-sof-mach-y := acp-sof-mach.o snd-soc-acpi-amd-match-y := amd-acp63-acpi-match.o +snd-acp-sdw-mach-y := acp-sdw-mach-common.o snd-acp-sdw-sof-mach-y += acp-sdw-sof-mach.o +snd-acp-sdw-legacy-mach-y += acp-sdw-legacy-mach.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCM) += snd-acp-pcm.o obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o @@ -41,4 +43,6 @@ obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o obj-$(CONFIG_SND_SOC_AMD_SOF_MACH) += snd-acp-sof-mach.o obj-$(CONFIG_SND_SOC_ACPI_AMD_MATCH) += snd-soc-acpi-amd-match.o +obj-$(CONFIG_SND_SOC_AMD_SDW_MACH_COMMON) += snd-acp-sdw-mach.o obj-$(CONFIG_SND_SOC_AMD_SOF_SDW_MACH) += snd-acp-sdw-sof-mach.o +obj-$(CONFIG_SND_SOC_AMD_LEGACY_SDW_MACH) += snd-acp-sdw-legacy-mach.o diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 56ce9e4b6accc7..1f59ee248771cc 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -59,9 +59,9 @@ static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id) val |= BIT(1); switch (chip->acp_rev) { - case ACP63_DEV: - case ACP70_DEV: - case ACP71_DEV: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div); val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div); break; @@ -121,8 +121,8 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas } switch (chip->acp_rev) { - case ACP3X_DEV: - case ACP6X_DEV: + case ACP_RN_PCI_ID: + case ACP_RMB_PCI_ID: switch (slots) { case 1 ... 7: no_of_slots = slots; @@ -135,9 +135,9 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas return -EINVAL; } break; - case ACP63_DEV: - case ACP70_DEV: - case ACP71_DEV: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: switch (slots) { case 1 ... 31: no_of_slots = slots; @@ -160,8 +160,8 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas spin_lock_irq(&adata->acp_lock); list_for_each_entry(stream, &adata->stream_list, list) { switch (chip->acp_rev) { - case ACP3X_DEV: - case ACP6X_DEV: + case ACP_RN_PCI_ID: + case ACP_RMB_PCI_ID: if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) adata->tdm_tx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 15) | (slot_len << 18); @@ -169,9 +169,9 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas adata->tdm_rx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 15) | (slot_len << 18); break; - case ACP63_DEV: - case ACP70_DEV: - case ACP71_DEV: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) adata->tdm_tx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 13) | (slot_len << 18); @@ -534,7 +534,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata); reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START; else phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; @@ -546,7 +546,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata); reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START; else phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; @@ -561,7 +561,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata); reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START; else phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; @@ -573,7 +573,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata); reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START; else phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; @@ -588,7 +588,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_HS_TX_FIFOADDR; reg_fifo_size = ACP_HS_TX_FIFOSIZE; - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START; else phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; @@ -600,7 +600,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d reg_fifo_addr = ACP_HS_RX_FIFOADDR; reg_fifo_size = ACP_HS_RX_FIFOSIZE; - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START; else phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; @@ -694,7 +694,7 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { .set_fmt = acp_i2s_set_fmt, .set_tdm_slot = acp_i2s_set_tdm_slot, }; -EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON"); MODULE_DESCRIPTION("AMD ACP Audio I2S controller"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index be01b178172e86..7acc7ed2e8cc90 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -31,7 +31,7 @@ void acp_enable_interrupts(struct acp_dev_data *adata) ext_intr_ctrl |= ACP_ERROR_MASK; writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); } -EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, "SND_SOC_ACP_COMMON"); void acp_disable_interrupts(struct acp_dev_data *adata) { @@ -40,7 +40,7 @@ void acp_disable_interrupts(struct acp_dev_data *adata) writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); } -EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, "SND_SOC_ACP_COMMON"); static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -97,7 +97,7 @@ void restore_acp_pdm_params(struct snd_pcm_substream *substream, writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); set_acp_pdm_clk(substream, dai); } -EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, "SND_SOC_ACP_COMMON"); static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -248,7 +248,7 @@ int restore_acp_i2s_params(struct snd_pcm_substream *substream, } return set_acp_i2s_dma_fifo(substream, dai); } -EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(restore_acp_i2s_params, "SND_SOC_ACP_COMMON"); static int acp_power_on(struct acp_chip_info *chip) { @@ -257,20 +257,20 @@ static int acp_power_on(struct acp_chip_info *chip) base = chip->base; switch (chip->acp_rev) { - case ACP3X_DEV: + case ACP_RN_PCI_ID: acp_pgfsm_stat_reg = ACP_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP_PGFSM_CONTROL; break; - case ACP6X_DEV: + case ACP_RMB_PCI_ID: acp_pgfsm_stat_reg = ACP6X_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP6X_PGFSM_CONTROL; break; - case ACP63_DEV: + case ACP63_PCI_ID: acp_pgfsm_stat_reg = ACP63_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP63_PGFSM_CONTROL; break; - case ACP70_DEV: - case ACP71_DEV: + case ACP70_PCI_ID: + case ACP71_PCI_ID: acp_pgfsm_stat_reg = ACP70_PGFSM_STATUS; acp_pgfsm_ctrl_reg = ACP70_PGFSM_CONTROL; break; @@ -322,11 +322,11 @@ int acp_init(struct acp_chip_info *chip) pr_err("ACP reset failed\n"); return ret; } - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) writel(0, chip->base + ACP_ZSC_DSP_CTRL); return 0; } -EXPORT_SYMBOL_NS_GPL(acp_init, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(acp_init, "SND_SOC_ACP_COMMON"); int acp_deinit(struct acp_chip_info *chip) { @@ -337,13 +337,13 @@ int acp_deinit(struct acp_chip_info *chip) if (ret) return ret; - if (chip->acp_rev < ACP70_DEV) + if (chip->acp_rev < ACP70_PCI_ID) writel(0, chip->base + ACP_CONTROL); else writel(0x01, chip->base + ACP_ZSC_DSP_CTRL); return 0; } -EXPORT_SYMBOL_NS_GPL(acp_deinit, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(acp_deinit, "SND_SOC_ACP_COMMON"); int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) { @@ -351,7 +351,7 @@ int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) pci_write_config_dword(dev, 0x64, data); return 0; } -EXPORT_SYMBOL_NS_GPL(smn_write, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(smn_write, "SND_SOC_ACP_COMMON"); int smn_read(struct pci_dev *dev, u32 smn_addr) { @@ -361,7 +361,7 @@ int smn_read(struct pci_dev *dev, u32 smn_addr) pci_read_config_dword(dev, 0x64, &data); return data; } -EXPORT_SYMBOL_NS_GPL(smn_read, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(smn_read, "SND_SOC_ACP_COMMON"); static void check_acp3x_config(struct acp_chip_info *chip) { @@ -448,20 +448,20 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) u32 pdm_addr; switch (chip->acp_rev) { - case ACP3X_DEV: + case ACP_RN_PCI_ID: pdm_addr = ACP_RENOIR_PDM_ADDR; check_acp3x_config(chip); break; - case ACP6X_DEV: + case ACP_RMB_PCI_ID: pdm_addr = ACP_REMBRANDT_PDM_ADDR; check_acp6x_config(chip); break; - case ACP63_DEV: + case ACP63_PCI_ID: pdm_addr = ACP63_PDM_ADDR; check_acp6x_config(chip); break; - case ACP70_DEV: - case ACP71_DEV: + case ACP70_PCI_ID: + case ACP71_PCI_ID: pdm_addr = ACP70_PDM_ADDR; check_acp70_config(chip); break; @@ -479,7 +479,7 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) } } } -EXPORT_SYMBOL_NS_GPL(check_acp_config, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(check_acp_config, "SND_SOC_ACP_COMMON"); MODULE_DESCRIPTION("AMD ACP legacy common features"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-legacy-mach.c b/sound/soc/amd/acp/acp-legacy-mach.c index d104f7e8fdcd8f..a7a551366a4097 100644 --- a/sound/soc/amd/acp/acp-legacy-mach.c +++ b/sound/soc/amd/acp/acp-legacy-mach.c @@ -57,7 +57,6 @@ static struct acp_card_drvdata es83xx_rn_data = { .dmic_cpu_id = DMIC, .hs_codec_id = ES83XX, .dmic_codec_id = DMIC, - .platform = RENOIR, }; static struct acp_card_drvdata max_nau8825_data = { @@ -68,7 +67,6 @@ static struct acp_card_drvdata max_nau8825_data = { .amp_codec_id = MAX98360A, .dmic_codec_id = DMIC, .soc_mclk = true, - .platform = REMBRANDT, .tdm_mode = false, }; @@ -80,7 +78,6 @@ static struct acp_card_drvdata rt5682s_rt1019_rmb_data = { .amp_codec_id = RT1019, .dmic_codec_id = DMIC, .soc_mclk = true, - .platform = REMBRANDT, .tdm_mode = false, }; @@ -126,6 +123,7 @@ static int acp_asoc_probe(struct platform_device *pdev) { struct snd_soc_card *card = NULL; struct device *dev = &pdev->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); const struct dmi_system_id *dmi_id; struct acp_card_drvdata *acp_card_drvdata; int ret; @@ -171,7 +169,9 @@ static int acp_asoc_probe(struct platform_device *pdev) goto out; } if (!strcmp(pdev->name, "acp-pdm-mach")) - acp_card_drvdata->platform = *((int *)dev->platform_data); + acp_card_drvdata->acp_rev = *((int *)dev->platform_data); + else + acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; dmi_id = dmi_first_match(acp_quirk_table); if (dmi_id && dmi_id->driver_data) @@ -240,6 +240,6 @@ static struct platform_driver acp_asoc_audio = { module_platform_driver(acp_asoc_audio); -MODULE_IMPORT_NS(SND_SOC_AMD_MACH); +MODULE_IMPORT_NS("SND_SOC_AMD_MACH"); MODULE_DESCRIPTION("ACP chrome audio support"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index e9ff4815c12c8c..f7602c1769bf4f 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -1407,8 +1407,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_sp); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->hs_codec_id) { @@ -1444,8 +1442,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_hs); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->hs_codec_id) { @@ -1471,7 +1467,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) if (drv_data->amp_cpu_id == I2S_SP) { links[i].name = "acp-amp-codec"; links[i].id = AMP_BE_ID; - if (drv_data->platform == RENOIR) { + if (drv_data->acp_rev == ACP_RN_PCI_ID) { links[i].cpus = sof_sp; links[i].num_cpus = ARRAY_SIZE(sof_sp); } else { @@ -1480,7 +1476,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) } links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; + links[i].playback_only = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->amp_codec_id) { @@ -1512,7 +1508,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_hs_virtual); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; + links[i].playback_only = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->amp_codec_id) { @@ -1527,7 +1523,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].init = acp_card_maxim_init; } if (drv_data->amp_codec_id == MAX98388) { - links[i].dpcm_capture = 1; + links[i].playback_only = 0; links[i].codecs = max98388; links[i].num_codecs = ARRAY_SIZE(max98388); links[i].ops = &acp_max98388_ops; @@ -1553,8 +1549,6 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_bt); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; links[i].nonatomic = true; links[i].no_pcm = 1; if (!drv_data->bt_codec_id) { @@ -1574,7 +1568,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(sof_dmic); links[i].platforms = sof_component; links[i].num_platforms = ARRAY_SIZE(sof_component); - links[i].dpcm_capture = 1; + links[i].capture_only = 1; links[i].nonatomic = true; links[i].no_pcm = 1; } @@ -1585,7 +1579,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) return 0; } -EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, SND_SOC_AMD_MACH); +EXPORT_SYMBOL_NS_GPL(acp_sofdsp_dai_links_create, "SND_SOC_AMD_MACH"); int acp_legacy_dai_links_create(struct snd_soc_card *card) { @@ -1613,8 +1607,6 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(i2s_sp); links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; if (!drv_data->hs_codec_id) { /* Use dummy codec if codec id not specified */ links[i].codecs = &snd_soc_dummy_dlc; @@ -1647,18 +1639,21 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].id = HEADSET_BE_ID; links[i].cpus = i2s_hs; links[i].num_cpus = ARRAY_SIZE(i2s_hs); - if (drv_data->platform == REMBRANDT) { + switch (drv_data->acp_rev) { + case ACP_RMB_PCI_ID: links[i].platforms = platform_rmb_component; links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); - } else if (drv_data->platform == ACP63) { + break; + case ACP63_PCI_ID: links[i].platforms = platform_acp63_component; links[i].num_platforms = ARRAY_SIZE(platform_acp63_component); - } else { + break; + default: links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); + break; } - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; + if (!drv_data->hs_codec_id) { /* Use dummy codec if codec id not specified */ links[i].codecs = &snd_soc_dummy_dlc; @@ -1686,7 +1681,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].num_cpus = ARRAY_SIZE(i2s_sp); links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); - links[i].dpcm_playback = 1; + links[i].playback_only = 1; if (!drv_data->amp_codec_id) { /* Use dummy codec if codec id not specified */ links[i].codecs = &snd_soc_dummy_dlc; @@ -1714,17 +1709,22 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) links[i].id = AMP_BE_ID; links[i].cpus = i2s_hs; links[i].num_cpus = ARRAY_SIZE(i2s_hs); - if (drv_data->platform == REMBRANDT) { + switch (drv_data->acp_rev) { + case ACP_RMB_PCI_ID: links[i].platforms = platform_rmb_component; links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); - } else if (drv_data->platform == ACP63) { + break; + case ACP63_PCI_ID: links[i].platforms = platform_acp63_component; links[i].num_platforms = ARRAY_SIZE(platform_acp63_component); - } else { + break; + default: links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); + break; } - links[i].dpcm_playback = 1; + + links[i].playback_only = 1; if (!drv_data->amp_codec_id) { /* Use dummy codec if codec id not specified */ links[i].codecs = &snd_soc_dummy_dlc; @@ -1749,6 +1749,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) if (drv_data->dmic_cpu_id == DMIC) { links[i].name = "acp-dmic-codec"; + links[i].stream_name = "DMIC capture"; links[i].id = DMIC_BE_ID; if (drv_data->dmic_codec_id == DMIC) { links[i].codecs = dmic_codec; @@ -1760,21 +1761,27 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) } links[i].cpus = pdm_dmic; links[i].num_cpus = ARRAY_SIZE(pdm_dmic); - if (drv_data->platform == REMBRANDT) { + switch (drv_data->acp_rev) { + case ACP_RMB_PCI_ID: links[i].platforms = platform_rmb_component; links[i].num_platforms = ARRAY_SIZE(platform_rmb_component); - } else if (drv_data->platform == ACP63) { + break; + case ACP63_PCI_ID: links[i].platforms = platform_acp63_component; links[i].num_platforms = ARRAY_SIZE(platform_acp63_component); - } else if ((drv_data->platform == ACP70) || (drv_data->platform == ACP71)) { + break; + case ACP70_PCI_ID: + case ACP71_PCI_ID: links[i].platforms = platform_acp70_component; links[i].num_platforms = ARRAY_SIZE(platform_acp70_component); - } else { + break; + default: links[i].platforms = platform_component; links[i].num_platforms = ARRAY_SIZE(platform_component); + break; } links[i].ops = &acp_card_dmic_ops; - links[i].dpcm_capture = 1; + links[i].capture_only = 1; } card->dai_link = links; @@ -1783,7 +1790,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card) return 0; } -EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, SND_SOC_AMD_MACH); +EXPORT_SYMBOL_NS_GPL(acp_legacy_dai_links_create, "SND_SOC_AMD_MACH"); MODULE_DESCRIPTION("AMD ACP Common Machine driver"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp/acp-mach.h b/sound/soc/amd/acp/acp-mach.h index 93d9e3886b7ecd..f94c30c20f20b6 100644 --- a/sound/soc/amd/acp/acp-mach.h +++ b/sound/soc/amd/acp/acp-mach.h @@ -18,6 +18,8 @@ #include #include +#include "acp_common.h" + #define TDM_CHANNELS 8 #define ACP_OPS(priv, cb) ((priv)->ops.cb) @@ -51,14 +53,6 @@ enum codec_endpoints { ES83XX, }; -enum platform_end_point { - RENOIR = 0, - REMBRANDT, - ACP63, - ACP70, - ACP71, -}; - struct acp_mach_ops { int (*probe)(struct snd_soc_card *card); int (*configure_link)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); @@ -77,7 +71,7 @@ struct acp_card_drvdata { unsigned int bt_codec_id; unsigned int dmic_codec_id; unsigned int dai_fmt; - unsigned int platform; + unsigned int acp_rev; struct clk *wclk; struct clk *bclk; struct acp_mach_ops ops; diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index f7450a5bd103e0..e0fc42d939d3ed 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -77,27 +77,22 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id res_acp = acp_res; num_res = ARRAY_SIZE(acp_res); - + chip->acp_rev = pci->revision; switch (pci->revision) { case 0x01: chip->name = "acp_asoc_renoir"; - chip->acp_rev = ACP3X_DEV; break; case 0x6f: chip->name = "acp_asoc_rembrandt"; - chip->acp_rev = ACP6X_DEV; break; case 0x63: chip->name = "acp_asoc_acp63"; - chip->acp_rev = ACP63_DEV; break; case 0x70: chip->name = "acp_asoc_acp70"; - chip->acp_rev = ACP70_DEV; break; case 0x71: chip->name = "acp_asoc_acp70"; - chip->acp_rev = ACP71_DEV; break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); @@ -255,5 +250,5 @@ module_pci_driver(snd_amd_acp_pci_driver); MODULE_DESCRIPTION("AMD ACP common PCI support"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); +MODULE_IMPORT_NS("SND_SOC_ACP_COMMON"); MODULE_ALIAS(DRV_NAME); diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index 22dd8988d005d7..d4855da05b6ae4 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -47,7 +47,7 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream, size_dmic = frames_to_bytes(substream->runtime, substream->runtime->buffer_size); - if (chip->acp_rev >= ACP70_DEV) + if (chip->acp_rev >= ACP70_PCI_ID) physical_addr = ACP7x_DMIC_MEM_WINDOW_START; else physical_addr = stream->reg_offset + MEM_WINDOW_START; @@ -181,7 +181,7 @@ const struct snd_soc_dai_ops acp_dmic_dai_ops = { .startup = acp_dmic_dai_startup, .shutdown = acp_dmic_dai_shutdown, }; -EXPORT_SYMBOL_NS_GPL(acp_dmic_dai_ops, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(acp_dmic_dai_ops, "SND_SOC_ACP_COMMON"); MODULE_DESCRIPTION("AMD ACP Audio PDM controller"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index 3a7a467b706338..aa330aeeb3012c 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -114,7 +114,7 @@ int acp_machine_select(struct acp_dev_data *adata) int size, platform; if (adata->flag == FLAG_AMD_LEGACY_ONLY_DMIC) { - platform = adata->platform; + platform = adata->acp_rev; adata->mach_dev = platform_device_register_data(adata->dev, "acp-pdm-mach", PLATFORM_DEVID_NONE, &platform, sizeof(platform)); @@ -125,6 +125,7 @@ int acp_machine_select(struct acp_dev_data *adata) dev_err(adata->dev, "warning: No matching ASoC machine driver found\n"); return -EINVAL; } + mach->mach_params.subsystem_rev = adata->acp_rev; adata->mach_dev = platform_device_register_data(adata->dev, mach->drv_name, PLATFORM_DEVID_NONE, mach, size); } @@ -132,7 +133,7 @@ int acp_machine_select(struct acp_dev_data *adata) dev_warn(adata->dev, "Unable to register Machine device\n"); return 0; } -EXPORT_SYMBOL_NS_GPL(acp_machine_select, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(acp_machine_select, "SND_SOC_ACP_COMMON"); static irqreturn_t i2s_irq_handler(int irq, void *data) { @@ -142,9 +143,6 @@ static irqreturn_t i2s_irq_handler(int irq, void *data) u16 i2s_flag = 0; u32 ext_intr_stat, ext_intr_stat1; - if (!adata) - return IRQ_NONE; - if (adata->rsrc->no_of_ctrls == 2) ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); @@ -193,7 +191,7 @@ void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); } -EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, "SND_SOC_ACP_COMMON"); void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size) { @@ -204,9 +202,9 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s u32 low, high, val; u16 page_idx; - switch (adata->platform) { - case ACP70: - case ACP71: + switch (adata->acp_rev) { + case ACP70_PCI_ID: + case ACP71_PCI_ID: switch (stream->dai_id) { case I2S_SP_INSTANCE: if (stream->dir == SNDRV_PCM_STREAM_PLAYBACK) @@ -252,7 +250,7 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s addr += PAGE_SIZE; } } -EXPORT_SYMBOL_NS_GPL(config_acp_dma, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(config_acp_dma, "SND_SOC_ACP_COMMON"); static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -270,9 +268,9 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs stream->substream = substream; chip = dev_get_platdata(dev); switch (chip->acp_rev) { - case ACP63_DEV: - case ACP70_DEV: - case ACP71_DEV: + case ACP63_PCI_ID: + case ACP70_PCI_ID: + case ACP71_PCI_ID: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) runtime->hw = acp6x_pcm_hardware_playback; else @@ -416,7 +414,7 @@ int acp_platform_register(struct device *dev) return 0; } -EXPORT_SYMBOL_NS_GPL(acp_platform_register, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(acp_platform_register, "SND_SOC_ACP_COMMON"); int acp_platform_unregister(struct device *dev) { @@ -426,7 +424,7 @@ int acp_platform_unregister(struct device *dev) platform_device_unregister(adata->mach_dev); return 0; } -EXPORT_SYMBOL_NS_GPL(acp_platform_unregister, SND_SOC_ACP_COMMON); +EXPORT_SYMBOL_NS_GPL(acp_platform_unregister, "SND_SOC_ACP_COMMON"); MODULE_DESCRIPTION("AMD ACP PCM Driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 396434a45eea9f..2648256fa129ce 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -197,7 +197,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev) return -ENODEV; } - if (chip->acp_rev != ACP6X_DEV) { + if (chip->acp_rev != ACP_RMB_PCI_ID) { dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); return -ENODEV; } @@ -227,7 +227,7 @@ static int rembrandt_audio_probe(struct platform_device *pdev) adata->dai_driver = acp_rmb_dai; adata->num_dai = ARRAY_SIZE(acp_rmb_dai); adata->rsrc = &rsrc; - adata->platform = REMBRANDT; + adata->acp_rev = chip->acp_rev; adata->flag = chip->flag; adata->is_i2s_config = chip->is_i2s_config; adata->machines = snd_soc_acpi_amd_rmb_acp_machines; @@ -305,6 +305,6 @@ static struct platform_driver rembrandt_driver = { module_platform_driver(rembrandt_driver); MODULE_DESCRIPTION("AMD ACP Rembrandt Driver"); -MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); +MODULE_IMPORT_NS("SND_SOC_ACP_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index 5e3f730aa6bfb1..ca2b74283d8fbc 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -157,7 +157,7 @@ static int renoir_audio_probe(struct platform_device *pdev) return -ENODEV; } - if (chip->acp_rev != ACP3X_DEV) { + if (chip->acp_rev != ACP_RN_PCI_ID) { dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); return -ENODEV; } @@ -185,7 +185,7 @@ static int renoir_audio_probe(struct platform_device *pdev) adata->dai_driver = acp_renoir_dai; adata->num_dai = ARRAY_SIZE(acp_renoir_dai); adata->rsrc = &rsrc; - adata->platform = RENOIR; + adata->acp_rev = chip->acp_rev; adata->flag = chip->flag; adata->machines = snd_soc_acpi_amd_acp_machines; @@ -254,6 +254,6 @@ static struct platform_driver renoir_driver = { module_platform_driver(renoir_driver); MODULE_DESCRIPTION("AMD ACP Renoir Driver"); -MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); +MODULE_IMPORT_NS("SND_SOC_ACP_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c new file mode 100644 index 00000000000000..9280cd30d19cf2 --- /dev/null +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2024 Advanced Micro Devices, Inc. + +/* + * acp-sdw-legacy-mach - ASoC legacy Machine driver for AMD SoundWire platforms + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "soc_amd_sdw_common.h" +#include "../../codecs/rt711.h" + +static unsigned long soc_sdw_quirk = RT711_JD1; +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +static void log_quirks(struct device *dev) +{ + if (SOC_JACK_JDSRC(soc_sdw_quirk)) + dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", + SOC_JACK_JDSRC(soc_sdw_quirk)); + if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) + dev_dbg(dev, "quirk SOC_SDW_ACP_DMIC enabled\n"); +} + +static int soc_sdw_quirk_cb(const struct dmi_system_id *id) +{ + soc_sdw_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id soc_sdw_quirk_table[] = { + { + .callback = soc_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AMD"), + DMI_MATCH(DMI_PRODUCT_NAME, "Birman-PHX"), + }, + .driver_data = (void *)RT711_JD2, + }, + {} +}; + +static const struct snd_soc_ops sdw_ops = { + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_hw_free, + .shutdown = asoc_sdw_shutdown, +}; + +static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; + +static int create_sdw_dailink(struct snd_soc_card *card, + struct asoc_sdw_dailink *soc_dai, + struct snd_soc_dai_link **dai_links, + int *be_id, struct snd_soc_codec_conf **codec_conf, + struct snd_soc_dai_link_component *sdw_platform_component) +{ + struct device *dev = card->dev; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private; + struct asoc_sdw_endpoint *soc_end; + int cpu_pin_id; + int stream; + int ret; + + list_for_each_entry(soc_end, &soc_dai->endpoints, list) { + if (soc_end->name_prefix) { + (*codec_conf)->dlc.name = soc_end->codec_name; + (*codec_conf)->name_prefix = soc_end->name_prefix; + (*codec_conf)++; + } + + if (soc_end->include_sidecar) { + ret = soc_end->codec_info->add_sidecar(card, dai_links, codec_conf); + if (ret) + return ret; + } + } + + for_each_pcm_streams(stream) { + static const char * const sdw_stream_name[] = { + "SDW%d-PIN%d-PLAYBACK", + "SDW%d-PIN%d-CAPTURE", + "SDW%d-PIN%d-PLAYBACK-%s", + "SDW%d-PIN%d-CAPTURE-%s", + }; + struct snd_soc_dai_link_ch_map *codec_maps; + struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *cpus; + int num_cpus = hweight32(soc_dai->link_mask[stream]); + int num_codecs = soc_dai->num_devs[stream]; + int playback, capture; + int j = 0; + char *name; + + if (!soc_dai->num_devs[stream]) + continue; + + soc_end = list_first_entry(&soc_dai->endpoints, + struct asoc_sdw_endpoint, list); + + *be_id = soc_end->dai_info->dailink[stream]; + if (*be_id < 0) { + dev_err(dev, "Invalid dailink id %d\n", *be_id); + return -EINVAL; + } + + switch (amd_ctx->acp_rev) { + case ACP63_PCI_REV: + ret = get_acp63_cpu_pin_id(ffs(soc_end->link_mask - 1), + *be_id, &cpu_pin_id, dev); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + /* create stream name according to first link id */ + if (ctx->append_dai_type) { + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream + 2], + ffs(soc_end->link_mask) - 1, + cpu_pin_id, + type_strings[soc_end->dai_info->dai_type]); + } else { + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream], + ffs(soc_end->link_mask) - 1, + cpu_pin_id); + } + if (!name) + return -ENOMEM; + + cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); + if (!codecs) + return -ENOMEM; + + codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); + if (!codec_maps) + return -ENOMEM; + + list_for_each_entry(soc_end, &soc_dai->endpoints, list) { + if (!soc_end->dai_info->direction[stream]) + continue; + + int link_num = ffs(soc_end->link_mask) - 1; + + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", + link_num, cpu_pin_id); + dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name); + if (!cpus->dai_name) + return -ENOMEM; + + codec_maps[j].cpu = 0; + codec_maps[j].codec = j; + + codecs[j].name = soc_end->codec_name; + codecs[j].dai_name = soc_end->dai_info->dai_name; + j++; + } + + WARN_ON(j != num_codecs); + + playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); + capture = (stream == SNDRV_PCM_STREAM_CAPTURE); + + asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, + cpus, num_cpus, sdw_platform_component, + 1, codecs, num_codecs, + 0, asoc_sdw_rtd_init, &sdw_ops); + /* + * SoundWire DAILINKs use 'stream' functions and Bank Switch operations + * based on wait_for_completion(), tag them as 'nonatomic'. + */ + (*dai_links)->nonatomic = true; + (*dai_links)->ch_maps = codec_maps; + + list_for_each_entry(soc_end, &soc_dai->endpoints, list) { + if (soc_end->dai_info->init) + soc_end->dai_info->init(card, *dai_links, + soc_end->codec_info, + playback); + } + + (*dai_links)++; + } + + return 0; +} + +static int create_sdw_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct asoc_sdw_dailink *soc_dais, + struct snd_soc_codec_conf **codec_conf) +{ + struct device *dev = card->dev; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private; + struct snd_soc_dai_link_component *sdw_platform_component; + int ret; + + sdw_platform_component = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!sdw_platform_component) + return -ENOMEM; + + switch (amd_ctx->acp_rev) { + case ACP63_PCI_REV: + sdw_platform_component->name = "amd_ps_sdw_dma.0"; + break; + default: + return -EINVAL; + } + + /* generate DAI links by each sdw link */ + while (soc_dais->initialised) { + int current_be_id; + + ret = create_sdw_dailink(card, soc_dais, dai_links, + ¤t_be_id, codec_conf, sdw_platform_component); + if (ret) + return ret; + + /* Update the be_id to match the highest ID used for SDW link */ + if (*be_id < current_be_id) + *be_id = current_be_id; + + soc_dais++; + } + + return 0; +} + +static int create_dmic_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, int no_pcm) +{ + struct device *dev = card->dev; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct amd_mc_ctx *amd_ctx = (struct amd_mc_ctx *)ctx->private; + struct snd_soc_dai_link_component *pdm_cpu; + struct snd_soc_dai_link_component *pdm_platform; + int ret; + + pdm_cpu = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); + if (!pdm_cpu) + return -ENOMEM; + + pdm_platform = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); + if (!pdm_platform) + return -ENOMEM; + + switch (amd_ctx->acp_rev) { + case ACP63_PCI_REV: + pdm_cpu->name = "acp_ps_pdm_dma.0"; + pdm_platform->name = "acp_ps_pdm_dma.0"; + break; + default: + return -EINVAL; + } + + *be_id = ACP_DMIC_BE_ID; + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "acp-dmic-codec", + 0, 1, // DMIC only supports capture + pdm_cpu->name, pdm_platform->name, 1, + "dmic-codec.0", "dmic-hifi", no_pcm, + asoc_sdw_dmic_init, NULL); + if (ret) + return ret; + + (*dai_links)++; + + return 0; +} + +static int soc_card_dai_links_create(struct snd_soc_card *card) +{ + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); + int sdw_be_num = 0, dmic_num = 0; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + struct asoc_sdw_endpoint *soc_ends __free(kfree) = NULL; + struct asoc_sdw_dailink *soc_dais __free(kfree) = NULL; + struct snd_soc_codec_conf *codec_conf; + struct snd_soc_dai_link *dai_links; + int num_devs = 0; + int num_ends = 0; + int num_links; + int be_id = 0; + int ret; + + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + if (ret < 0) { + dev_err(dev, "failed to count devices/endpoints: %d\n", ret); + return ret; + } + + /* One per DAI link, worst case is a DAI link for every endpoint */ + soc_dais = kcalloc(num_ends, sizeof(*soc_dais), GFP_KERNEL); + if (!soc_dais) + return -ENOMEM; + + /* One per endpoint, ie. each DAI on each codec/amp */ + soc_ends = kcalloc(num_ends, sizeof(*soc_ends), GFP_KERNEL); + if (!soc_ends) + return -ENOMEM; + + ret = asoc_sdw_parse_sdw_endpoints(card, soc_dais, soc_ends, &num_devs); + if (ret < 0) + return ret; + + sdw_be_num = ret; + + /* enable dmic */ + if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC || mach_params->dmic_num) + dmic_num = 1; + + dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num); + + codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + if (!codec_conf) + return -ENOMEM; + + /* allocate BE dailinks */ + num_links = sdw_be_num + dmic_num; + dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); + if (!dai_links) + return -ENOMEM; + + card->codec_conf = codec_conf; + card->num_configs = num_devs; + card->dai_link = dai_links; + card->num_links = num_links; + + /* SDW */ + if (sdw_be_num) { + ret = create_sdw_dailinks(card, &dai_links, &be_id, + soc_dais, &codec_conf); + if (ret) + return ret; + } + + /* dmic */ + if (dmic_num > 0) { + if (ctx->ignore_internal_dmic) { + dev_warn(dev, "Ignoring ACP DMIC\n"); + } else { + ret = create_dmic_dailinks(card, &dai_links, &be_id, 0); + if (ret) + return ret; + } + } + + WARN_ON(codec_conf != card->codec_conf + card->num_configs); + WARN_ON(dai_links != card->dai_link + card->num_links); + + return ret; +} + +static int mc_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); + struct snd_soc_card *card; + struct amd_mc_ctx *amd_ctx; + struct asoc_sdw_mc_private *ctx; + int amp_num = 0, i; + int ret; + + amd_ctx = devm_kzalloc(&pdev->dev, sizeof(*amd_ctx), GFP_KERNEL); + if (!amd_ctx) + return -ENOMEM; + + amd_ctx->acp_rev = mach->mach_params.subsystem_rev; + amd_ctx->max_sdw_links = ACP63_SDW_MAX_LINKS; + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); + ctx->private = amd_ctx; + card = &ctx->card; + card->dev = &pdev->dev; + card->name = "amd-soundwire"; + card->owner = THIS_MODULE; + card->late_probe = asoc_sdw_card_late_probe; + + snd_soc_card_set_drvdata(card, ctx); + + dmi_check_system(soc_sdw_quirk_table); + + if (quirk_override != -1) { + dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n", + soc_sdw_quirk, quirk_override); + soc_sdw_quirk = quirk_override; + } + + log_quirks(card->dev); + + ctx->mc_quirk = soc_sdw_quirk; + dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk); + /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ + for (i = 0; i < ctx->codec_info_list_count; i++) + codec_info_list[i].amp_num = 0; + + ret = soc_card_dai_links_create(card); + if (ret < 0) + return ret; + + /* + * the default amp_num is zero for each codec and + * amp_num will only be increased for active amp + * codecs on used platform + */ + for (i = 0; i < ctx->codec_info_list_count; i++) + amp_num += codec_info_list[i].amp_num; + + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + " cfg-amp:%d", amp_num); + if (!card->components) + return -ENOMEM; + if (mach->mach_params.dmic_num) { + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:dmic cfg-mics:%d", + card->components, + mach->mach_params.dmic_num); + if (!card->components) + return -ENOMEM; + } + + /* Register the card */ + ret = devm_snd_soc_register_card(card->dev, card); + if (ret) { + dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); + asoc_sdw_mc_dailink_exit_loop(card); + return ret; + } + + platform_set_drvdata(pdev, card); + + return ret; +} + +static void mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + asoc_sdw_mc_dailink_exit_loop(card); +} + +static const struct platform_device_id mc_id_table[] = { + { "amd_sdw", }, + {} +}; +MODULE_DEVICE_TABLE(platform, mc_id_table); + +static struct platform_driver soc_sdw_driver = { + .driver = { + .name = "amd_sdw", + .pm = &snd_soc_pm_ops, + }, + .probe = mc_probe, + .remove = mc_remove, + .id_table = mc_id_table, +}; + +module_platform_driver(soc_sdw_driver); + +MODULE_DESCRIPTION("ASoC AMD SoundWire Legacy Generic Machine driver"); +MODULE_AUTHOR("Vijendar Mukunda "); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); +MODULE_IMPORT_NS("SND_SOC_AMD_SDW_MACH"); diff --git a/sound/soc/amd/acp/acp-sdw-mach-common.c b/sound/soc/amd/acp/acp-sdw-mach-common.c new file mode 100644 index 00000000000000..6f5c39ed1a18d4 --- /dev/null +++ b/sound/soc/amd/acp/acp-sdw-mach-common.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright(c) 2024 Advanced Micro Devices, Inc. + +/* + * acp-sdw-mach-common - Common machine driver helper functions for + * legacy(No DSP) stack and SOF stack. + */ + +#include +#include +#include "soc_amd_sdw_common.h" + +int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev) +{ + switch (sdw_link_id) { + case AMD_SDW0: + switch (be_id) { + case SOC_SDW_JACK_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO0_TX; + break; + case SOC_SDW_JACK_IN_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO0_RX; + break; + case SOC_SDW_AMP_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO1_TX; + break; + case SOC_SDW_AMP_IN_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO1_RX; + break; + case SOC_SDW_DMIC_DAI_ID: + *cpu_pin_id = ACP63_SW0_AUDIO2_RX; + break; + default: + dev_err(dev, "Invalid be id:%d\n", be_id); + return -EINVAL; + } + break; + case AMD_SDW1: + switch (be_id) { + case SOC_SDW_JACK_OUT_DAI_ID: + case SOC_SDW_AMP_OUT_DAI_ID: + *cpu_pin_id = ACP63_SW1_AUDIO0_TX; + break; + case SOC_SDW_JACK_IN_DAI_ID: + case SOC_SDW_AMP_IN_DAI_ID: + case SOC_SDW_DMIC_DAI_ID: + *cpu_pin_id = ACP63_SW1_AUDIO0_RX; + break; + default: + dev_err(dev, "invalid be_id:%d\n", be_id); + return -EINVAL; + } + break; + default: + dev_err(dev, "Invalid link id:%d\n", sdw_link_id); + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL_NS_GPL(get_acp63_cpu_pin_id, "SND_SOC_AMD_SDW_MACH"); + +MODULE_DESCRIPTION("AMD SoundWire Common Machine driver"); +MODULE_AUTHOR("Vijendar Mukunda "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index 306854fb08e3d7..c09b1f118a6cc1 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -64,54 +64,6 @@ static const struct snd_soc_ops sdw_ops = { .shutdown = asoc_sdw_shutdown, }; -static int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev) -{ - switch (sdw_link_id) { - case AMD_SDW0: - switch (be_id) { - case SOC_SDW_JACK_OUT_DAI_ID: - *cpu_pin_id = ACP63_SW0_AUDIO0_TX; - break; - case SOC_SDW_JACK_IN_DAI_ID: - *cpu_pin_id = ACP63_SW0_AUDIO0_RX; - break; - case SOC_SDW_AMP_OUT_DAI_ID: - *cpu_pin_id = ACP63_SW0_AUDIO1_TX; - break; - case SOC_SDW_AMP_IN_DAI_ID: - *cpu_pin_id = ACP63_SW0_AUDIO1_RX; - break; - case SOC_SDW_DMIC_DAI_ID: - *cpu_pin_id = ACP63_SW0_AUDIO2_RX; - break; - default: - dev_err(dev, "Invalid be id:%d\n", be_id); - return -EINVAL; - } - break; - case AMD_SDW1: - switch (be_id) { - case SOC_SDW_JACK_OUT_DAI_ID: - case SOC_SDW_AMP_OUT_DAI_ID: - *cpu_pin_id = ACP63_SW1_AUDIO0_TX; - break; - case SOC_SDW_JACK_IN_DAI_ID: - case SOC_SDW_AMP_IN_DAI_ID: - case SOC_SDW_DMIC_DAI_ID: - *cpu_pin_id = ACP63_SW1_AUDIO0_RX; - break; - default: - dev_err(dev, "invalid be_id:%d\n", be_id); - return -EINVAL; - } - break; - default: - dev_err(dev, "Invalid link id:%d\n", sdw_link_id); - return -EINVAL; - } - return 0; -} - static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; static int create_sdw_dailink(struct snd_soc_card *card, @@ -154,7 +106,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, int num_cpus = hweight32(sof_dai->link_mask[stream]); int num_codecs = sof_dai->num_devs[stream]; int playback, capture; - int i = 0, j = 0; + int j = 0; char *name; if (!sof_dai->num_devs[stream]) @@ -213,14 +165,14 @@ static int create_sdw_dailink(struct snd_soc_card *card, int link_num = ffs(sof_end->link_mask) - 1; - cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SDW%d Pin%d", - link_num, cpu_pin_id); - dev_dbg(dev, "cpu[%d].dai_name:%s\n", i, cpus[i].dai_name); - if (!cpus[i].dai_name) + cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", + link_num, cpu_pin_id); + dev_dbg(dev, "cpu->dai_name:%s\n", cpus->dai_name); + if (!cpus->dai_name) return -ENOMEM; - codec_maps[j].cpu = i; + codec_maps[j].cpu = 0; codec_maps[j].codec = j; codecs[j].name = sof_end->codec_name; @@ -236,7 +188,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, cpus, num_cpus, platform_component, ARRAY_SIZE(platform_component), codecs, num_codecs, - asoc_sdw_rtd_init, &sdw_ops); + 1, asoc_sdw_rtd_init, &sdw_ops); /* * SoundWire DAILINKs use 'stream' functions and Bank Switch operations @@ -285,7 +237,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card, } static int create_dmic_dailinks(struct snd_soc_card *card, - struct snd_soc_dai_link **dai_links, int *be_id) + struct snd_soc_dai_link **dai_links, int *be_id, int no_pcm) { struct device *dev = card->dev; int ret; @@ -294,7 +246,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card, 0, 1, // DMIC only supports capture "acp-sof-dmic", platform_component->name, ARRAY_SIZE(platform_component), - "dmic-codec", "dmic-hifi", + "dmic-codec", "dmic-hifi", no_pcm, asoc_sdw_dmic_init, NULL); if (ret) return ret; @@ -311,9 +263,9 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int sdw_be_num = 0, dmic_num = 0; struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + struct asoc_sdw_endpoint *sof_ends __free(kfree) = NULL; + struct asoc_sdw_dailink *sof_dais __free(kfree) = NULL; struct snd_soc_codec_conf *codec_conf; - struct asoc_sdw_endpoint *sof_ends; - struct asoc_sdw_dailink *sof_dais; struct snd_soc_dai_link *dai_links; int num_devs = 0; int num_ends = 0; @@ -334,14 +286,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) /* One per endpoint, ie. each DAI on each codec/amp */ sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL); - if (!sof_ends) { - ret = -ENOMEM; - goto err_dai; - } + if (!sof_ends) + return -ENOMEM; ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); if (ret < 0) - goto err_end; + return ret; sdw_be_num = ret; @@ -352,18 +302,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num); codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); - if (!codec_conf) { - ret = -ENOMEM; - goto err_end; - } + if (!codec_conf) + return -ENOMEM; /* allocate BE dailinks */ num_links = sdw_be_num + dmic_num; dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); - if (!dai_links) { - ret = -ENOMEM; - goto err_end; - } + if (!dai_links) + return -ENOMEM; card->codec_conf = codec_conf; card->num_configs = num_devs; @@ -375,7 +321,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) ret = create_sdw_dailinks(card, &dai_links, &be_id, sof_dais, &codec_conf); if (ret) - goto err_end; + return ret; } /* dmic */ @@ -383,20 +329,15 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (ctx->ignore_internal_dmic) { dev_warn(dev, "Ignoring ACP DMIC\n"); } else { - ret = create_dmic_dailinks(card, &dai_links, &be_id); + ret = create_dmic_dailinks(card, &dai_links, &be_id, 1); if (ret) - goto err_end; + return ret; } } WARN_ON(codec_conf != card->codec_conf + card->num_configs); WARN_ON(dai_links != card->dai_link + card->num_links); -err_end: - kfree(sof_ends); -err_dai: - kfree(sof_dais); - return ret; } @@ -501,4 +442,5 @@ module_platform_driver(sof_sdw_driver); MODULE_DESCRIPTION("ASoC AMD SoundWire Generic Machine driver"); MODULE_AUTHOR("Vijendar Mukunda dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); const struct dmi_system_id *dmi_id; struct acp_card_drvdata *acp_card_drvdata; int ret; @@ -116,6 +113,7 @@ static int acp_sof_probe(struct platform_device *pdev) if (dmi_id && dmi_id->driver_data) acp_card_drvdata->tdm_mode = dmi_id->driver_data; + acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev; ret = acp_sofdsp_dai_links_create(card); if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to create DAI links\n"); @@ -171,6 +169,6 @@ static struct platform_driver acp_asoc_audio = { module_platform_driver(acp_asoc_audio); -MODULE_IMPORT_NS(SND_SOC_AMD_MACH); +MODULE_IMPORT_NS("SND_SOC_AMD_MACH"); MODULE_DESCRIPTION("ACP SOF Machine Driver"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c index f325c374f22852..81496e713440b4 100644 --- a/sound/soc/amd/acp/acp63.c +++ b/sound/soc/amd/acp/acp63.c @@ -207,7 +207,7 @@ static int acp63_audio_probe(struct platform_device *pdev) return -ENODEV; } - if (chip->acp_rev != ACP63_DEV) { + if (chip->acp_rev != ACP63_PCI_ID) { dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); return -ENODEV; } @@ -237,7 +237,7 @@ static int acp63_audio_probe(struct platform_device *pdev) adata->dai_driver = acp63_dai; adata->num_dai = ARRAY_SIZE(acp63_dai); adata->rsrc = &rsrc; - adata->platform = ACP63; + adata->acp_rev = chip->acp_rev; adata->flag = chip->flag; adata->is_i2s_config = chip->is_i2s_config; adata->machines = snd_soc_acpi_amd_acp63_acp_machines; @@ -314,6 +314,6 @@ static struct platform_driver acp63_driver = { module_platform_driver(acp63_driver); MODULE_DESCRIPTION("AMD ACP acp63 Driver"); -MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); +MODULE_IMPORT_NS("SND_SOC_ACP_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index 68d2590e1a4efb..9e23729fd1a71d 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -142,9 +142,9 @@ static int acp70_i2s_master_clock_generate(struct acp_dev_data *adata) struct pci_dev *smn_dev; u32 device_id; - if (adata->platform == ACP70) + if (adata->acp_rev == ACP70_PCI_ID) device_id = 0x1507; - else if (adata->platform == ACP71) + else if (adata->acp_rev == ACP71_PCI_ID) device_id = 0x1122; else return -ENODEV; @@ -175,8 +175,8 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) } switch (chip->acp_rev) { - case ACP70_DEV: - case ACP71_DEV: + case ACP70_PCI_ID: + case ACP71_PCI_ID: break; default: dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev); @@ -209,11 +209,7 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) adata->num_dai = ARRAY_SIZE(acp70_dai); adata->rsrc = &rsrc; adata->machines = snd_soc_acpi_amd_acp70_acp_machines; - if (chip->acp_rev == ACP70_DEV) - adata->platform = ACP70; - else - adata->platform = ACP71; - + adata->acp_rev = chip->acp_rev; adata->flag = chip->flag; acp_machine_select(adata); @@ -288,6 +284,6 @@ static struct platform_driver acp70_driver = { module_platform_driver(acp70_driver); MODULE_DESCRIPTION("AMD ACP ACP70 Driver"); -MODULE_IMPORT_NS(SND_SOC_ACP_COMMON); +MODULE_IMPORT_NS("SND_SOC_ACP_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/acp/acp_common.h b/sound/soc/amd/acp/acp_common.h new file mode 100644 index 00000000000000..f1ae88013f629b --- /dev/null +++ b/sound/soc/amd/acp/acp_common.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved + */ + +/* + * acp_common.h - acp common header file + */ + +#ifndef __ACP_COMMON_H +#define __ACP_COMMON_H + +#define ACP_RN_PCI_ID 0x01 +#define ACP_VANGOGH_PCI_ID 0x50 +#define ACP_RMB_PCI_ID 0x6F +#define ACP63_PCI_ID 0x63 +#define ACP70_PCI_ID 0x70 +#define ACP71_PCI_ID 0x71 + +#endif diff --git a/sound/soc/amd/acp/amd-acp63-acpi-match.c b/sound/soc/amd/acp/amd-acp63-acpi-match.c index be936791307353..9b6a49c051cda9 100644 --- a/sound/soc/amd/acp/amd-acp63-acpi-match.c +++ b/sound/soc/amd/acp/amd-acp63-acpi-match.c @@ -73,6 +73,45 @@ static const struct snd_soc_acpi_link_adr acp63_4_in_1_sdca[] = { {} }; +static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { + { + .adr = 0x000030025d072201ull, + .num_endpoints = ARRAY_SIZE(rt722_endpoints), + .endpoints = rt722_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_link_adr acp63_rt722_only[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[] = { { .link_mask = BIT(0) | BIT(1), @@ -85,6 +124,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[] = { }; EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sof_sdw_machines); +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sdw_machines[] = { + { + .link_mask = BIT(0), + .links = acp63_rt722_only, + .drv_name = "amd_sdw", + }, + { + .link_mask = BIT(0) | BIT(1), + .links = acp63_4_in_1_sdca, + .drv_name = "amd_sdw", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sdw_machines); + MODULE_DESCRIPTION("AMD ACP6.3 tables and support for ACPI enumeration"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); diff --git a/sound/soc/amd/acp/amd-sdw-acpi.c b/sound/soc/amd/acp/amd-sdw-acpi.c index babd841d32962a..238b584887eead 100644 --- a/sound/soc/amd/acp/amd-sdw-acpi.c +++ b/sound/soc/amd/acp/amd-sdw-acpi.c @@ -56,7 +56,7 @@ int amd_sdw_scan_controller(struct sdw_amd_acpi_info *info) info->link_mask = sdw_bitmap; return 0; } -EXPORT_SYMBOL_NS(amd_sdw_scan_controller, SND_AMD_SOUNDWIRE_ACPI); +EXPORT_SYMBOL_NS(amd_sdw_scan_controller, "SND_AMD_SOUNDWIRE_ACPI"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("AMD SoundWire ACPI helpers"); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index 854269fea875f1..ee69dfb10cb86d 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -16,14 +16,9 @@ #include #include +#include "acp_common.h" #include "chip_offset_byte.h" -#define ACP3X_DEV 3 -#define ACP6X_DEV 6 -#define ACP63_DEV 0x63 -#define ACP70_DEV 0x70 -#define ACP71_DEV 0x71 - #define DMIC_INSTANCE 0x00 #define I2S_SP_INSTANCE 0x01 #define I2S_BT_INSTANCE 0x02 @@ -182,6 +177,7 @@ struct acp_dev_data { struct device *dev; void __iomem *acp_base; unsigned int i2s_irq; + unsigned int acp_rev; /* ACP Revision id */ bool tdm_mode; bool is_i2s_config; @@ -205,7 +201,6 @@ struct acp_dev_data { u32 xfer_tx_resolution[3]; u32 xfer_rx_resolution[3]; unsigned int flag; - unsigned int platform; }; enum acp_config { diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h index f1bd5a7afc8eab..b7bae107c13e4f 100644 --- a/sound/soc/amd/acp/soc_amd_sdw_common.h +++ b/sound/soc/amd/acp/soc_amd_sdw_common.h @@ -36,9 +36,13 @@ #define ACP63_SW1_AUDIO0_TX 0 #define ACP63_SW1_AUDIO0_RX 1 +#define ACP_DMIC_BE_ID 4 + struct amd_mc_ctx { unsigned int acp_rev; unsigned int max_sdw_links; }; +int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev); + #endif diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index 357dfd016bafd6..4ca1978020a962 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -317,8 +317,6 @@ static struct snd_soc_dai_link acp3x_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .init = acp3x_5682_init, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &acp3x_5682_ops, SND_SOC_DAILINK_REG(acp3x_i2s, rt5682, platform), }, @@ -327,7 +325,7 @@ static struct snd_soc_dai_link acp3x_dai[] = { .stream_name = "HiFi Playback", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, + .playback_only = 1, .ops = &acp3x_max_play_ops, .cpus = acp3x_bt, .num_cpus = ARRAY_SIZE(acp3x_bt), @@ -339,7 +337,7 @@ static struct snd_soc_dai_link acp3x_dai[] = { .stream_name = "Capture DMIC0", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_capture = 1, + .capture_only = 1, .ops = &acp3x_ec_cap0_ops, SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform), }, diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index 1a967da35a0fdd..a86c76f781f9eb 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -23,6 +23,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_vangogh_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[]; diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h index 39208305dd6c3c..e54eabaa4d3e16 100644 --- a/sound/soc/amd/ps/acp63.h +++ b/sound/soc/amd/ps/acp63.h @@ -231,6 +231,7 @@ struct sdw_dma_ring_buf_reg { * @sdw_en_stat: flag set to true when any one of the SoundWire manager instance is enabled * @addr: pci ioremap address * @reg_range: ACP reigister range + * @acp_rev: ACP PCI revision id * @sdw0-dma_intr_stat: DMA interrupt status array for SoundWire manager-SW0 instance * @sdw_dma_intr_stat: DMA interrupt status array for SoundWire manager-SW1 instance */ @@ -254,6 +255,7 @@ struct acp63_dev_data { bool sdw_en_stat; u32 addr; u32 reg_range; + u32 acp_rev; u16 sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS]; u16 sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS]; }; diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index c72d666d51bdf4..823a69bf778b9c 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -267,6 +267,7 @@ static int amd_sdw_probe(struct device *dev) sdw_res.acp_lock = &acp_data->acp_lock; sdw_res.count = acp_data->info.count; sdw_res.mmio_base = acp_data->acp63_base; + sdw_res.acp_rev = acp_data->acp_rev; sdw_res.link_mask = acp_data->info.link_mask; ret = sdw_amd_probe(&sdw_res, &acp_data->sdw); if (ret) @@ -302,8 +303,7 @@ static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev) link = mach->links; for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) { if (!snd_soc_acpi_sdw_link_slaves_found(dev, link, - acp_data->sdw->ids, - acp_data->sdw->num_slaves)) + acp_data->sdw->peripherals)) break; } if (i == acp_data->info.count || !link->num_adr) @@ -576,6 +576,7 @@ static int snd_acp63_probe(struct pci_dev *pci, } adata->addr = addr; adata->reg_range = ACP63_REG_END - ACP63_REG_START; + adata->acp_rev = pci->revision; pci_set_master(pci); pci_set_drvdata(pci, adata); mutex_init(&adata->acp_lock); @@ -599,6 +600,7 @@ static int snd_acp63_probe(struct pci_dev *pci, dev_err(&pci->dev, "ACP platform devices creation failed\n"); goto de_init; } + adata->machines = snd_soc_acpi_amd_acp63_sdw_machines; ret = acp63_machine_register(&pci->dev); if (ret) { dev_err(&pci->dev, "ACP machine register failed\n"); @@ -751,6 +753,6 @@ module_pci_driver(ps_acp63_driver); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); MODULE_AUTHOR("Syed.SabaKareem@amd.com"); MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver"); -MODULE_IMPORT_NS(SOUNDWIRE_AMD_INIT); -MODULE_IMPORT_NS(SND_AMD_SOUNDWIRE_ACPI); +MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); +MODULE_IMPORT_NS("SND_AMD_SOUNDWIRE_ACPI"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c index 3b4b9c6b3171ed..b602cca92b8bbb 100644 --- a/sound/soc/amd/ps/ps-sdw-dma.c +++ b/sound/soc/amd/ps/ps-sdw-dma.c @@ -445,6 +445,8 @@ static const struct snd_soc_component_driver acp63_sdw_component = { .trigger = acp63_sdw_dma_trigger, .pointer = acp63_sdw_dma_pointer, .pcm_construct = acp63_sdw_dma_new, + .use_dai_pcm_id = true, + }; static int acp63_sdw_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/amd/vangogh/acp5x-mach.c b/sound/soc/amd/vangogh/acp5x-mach.c index 7878e061ecb984..2ca904db82abe1 100644 --- a/sound/soc/amd/vangogh/acp5x-mach.c +++ b/sound/soc/amd/vangogh/acp5x-mach.c @@ -276,8 +276,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &acp5x_8821_ops, .init = acp5x_8821_init, SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform), @@ -288,7 +286,6 @@ static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, .playback_only = 1, .ops = &acp5x_cs35l41_play_ops, SND_SOC_DAILINK_REG(acp5x_bt, cs35l41, platform), @@ -375,8 +372,6 @@ static struct snd_soc_dai_link acp5x_8821_98388_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &acp5x_8821_ops, .init = acp5x_8821_init, SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform), @@ -387,7 +382,6 @@ static struct snd_soc_dai_link acp5x_8821_98388_dai[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, .playback_only = 1, .ops = &acp5x_max98388_play_ops, SND_SOC_DAILINK_REG(acp5x_bt, max98388, platform), diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index 2436e8deb2be48..ecf57a6cb7c37d 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -220,6 +220,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "21J6"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21M1"), + } + }, { .driver_data = &acp6x_card, .matches = { @@ -241,6 +248,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "21M5"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21ME"), + } + }, { .driver_data = &acp6x_card, .matches = { @@ -409,6 +423,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Xiaomi Book Pro 14 2022"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "TIMI"), + DMI_MATCH(DMI_PRODUCT_NAME, "Redmi G 2022"), + } + }, { .driver_data = &acp6x_card, .matches = { @@ -537,8 +558,14 @@ static int acp6x_probe(struct platform_device *pdev) struct acp6x_pdm *machine = NULL; struct snd_soc_card *card; struct acpi_device *adev; + acpi_handle handle; + acpi_integer dmic_status; int ret; + bool is_dmic_enable, wov_en; + /* IF WOV entry not found, enable dmic based on AcpDmicConnected entry*/ + is_dmic_enable = false; + wov_en = true; /* check the parent device's firmware node has _DSD or not */ adev = ACPI_COMPANION(pdev->dev.parent); if (adev) { @@ -546,9 +573,24 @@ static int acp6x_probe(struct platform_device *pdev) if (!acpi_dev_get_property(adev, "AcpDmicConnected", ACPI_TYPE_INTEGER, &obj) && obj->integer.value == 1) - platform_set_drvdata(pdev, &acp6x_card); + is_dmic_enable = true; } + handle = ACPI_HANDLE(pdev->dev.parent); + ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status); + if (!ACPI_FAILURE(ret)) { + wov_en = dmic_status; + if (!wov_en) + return -ENODEV; + } else { + /* Incase of ACPI method read failure then jump to check_dmi_entry */ + goto check_dmi_entry; + } + + if (is_dmic_enable) + platform_set_drvdata(pdev, &acp6x_card); + +check_dmi_entry: /* check for any DMI overrides */ dmi_id = dmi_first_match(yc_acp_quirk_table); if (dmi_id) diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c index c9e7d40c47cc1c..b4f4696809dd23 100644 --- a/sound/soc/apple/mca.c +++ b/sound/soc/apple/mca.c @@ -616,7 +616,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream, tdm_slot_width = 32; if (tdm_slot_width < params_width(params)) { - dev_err(dev, "TDM slots too narrow (tdm=%d params=%d)\n", + dev_err(dev, "TDM slots too narrow (tdm=%u params=%d)\n", tdm_slot_width, params_width(params)); return -EINVAL; } diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 3763454436c157..89098f41679c0a 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -821,8 +821,9 @@ static int atmel_ssc_resume(struct snd_soc_component *component) return 0; } +/* S24_LE is not supported if more than 2 channels (of TDM slots) are used. */ #define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { .startup = atmel_ssc_startup, @@ -836,6 +837,7 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = { static struct snd_soc_dai_driver atmel_ssc_dai = { .playback = { + .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_CONTINUOUS, @@ -843,6 +845,7 @@ static struct snd_soc_dai_driver atmel_ssc_dai = { .rate_max = 384000, .formats = ATMEL_SSC_FORMATS,}, .capture = { + .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_CONTINUOUS, diff --git a/sound/soc/atmel/mchp-spdifrx.c b/sound/soc/atmel/mchp-spdifrx.c index b2507a1491b714..fb820609c043d0 100644 --- a/sound/soc/atmel/mchp-spdifrx.c +++ b/sound/soc/atmel/mchp-spdifrx.c @@ -1014,7 +1014,7 @@ static const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { static struct snd_soc_dai_driver mchp_spdifrx_dai = { .name = "mchp-spdifrx", .capture = { - .stream_name = "S/PDIF Capture", + .stream_name = "Capture", .channels_min = SPDIFRX_CHANNELS, .channels_max = SPDIFRX_CHANNELS, .rates = MCHP_SPDIF_RATES, diff --git a/sound/soc/atmel/mchp-spdiftx.c b/sound/soc/atmel/mchp-spdiftx.c index 4c60ea6528967d..245c0352c1417c 100644 --- a/sound/soc/atmel/mchp-spdiftx.c +++ b/sound/soc/atmel/mchp-spdiftx.c @@ -707,7 +707,7 @@ static const struct snd_soc_dai_ops mchp_spdiftx_dai_ops = { static struct snd_soc_dai_driver mchp_spdiftx_dai = { .name = "mchp-spdiftx", .playback = { - .stream_name = "S/PDIF Playback", + .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = MCHP_SPDIFTX_RATES, diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index ea01d6490cec0b..3392693faeb932 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -311,7 +311,7 @@ static int au1xpsc_pcm_new(struct snd_soc_component *component, } /* au1xpsc audio platform */ -static struct snd_soc_component_driver au1xpsc_soc_component = { +static const struct snd_soc_component_driver au1xpsc_soc_component = { .name = DRV_NAME, .open = au1xpsc_pcm_open, .close = au1xpsc_pcm_close, diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index d2fdebd8881bbc..c9c2b1e71d55c0 100644 --- a/sound/soc/au1x/dma.c +++ b/sound/soc/au1x/dma.c @@ -289,7 +289,7 @@ static int alchemy_pcm_new(struct snd_soc_component *component, return 0; } -static struct snd_soc_component_driver alchemy_pcm_soc_component = { +static const struct snd_soc_component_driver alchemy_pcm_soc_component = { .name = DRV_NAME, .open = alchemy_pcm_open, .close = alchemy_pcm_close, diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 9bda6499e66e1c..87d2f06c2f53aa 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -817,7 +817,7 @@ static const struct regmap_config bcm2835_regmap_config = { .max_register = BCM2835_I2S_GRAY_REG, .precious_reg = bcm2835_i2s_precious_reg, .volatile_reg = bcm2835_i2s_volatile_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct snd_soc_component_driver bcm2835_i2s_component = { diff --git a/sound/soc/bcm/bcm63xx-pcm-whistler.c b/sound/soc/bcm/bcm63xx-pcm-whistler.c index 018f2372e892c2..e3a4fcc63a56dc 100644 --- a/sound/soc/bcm/bcm63xx-pcm-whistler.c +++ b/sound/soc/bcm/bcm63xx-pcm-whistler.c @@ -256,12 +256,16 @@ static irqreturn_t i2s_dma_isr(int irq, void *bcm_i2s_priv) offlevel = (int_status & I2S_RX_DESC_OFF_LEVEL_MASK) >> I2S_RX_DESC_OFF_LEVEL_SHIFT; + bool val_read = false; while (offlevel) { regmap_read(regmap_i2s, I2S_RX_DESC_OFF_ADDR, &val_1); regmap_read(regmap_i2s, I2S_RX_DESC_OFF_LEN, &val_2); + val_read = true; offlevel--; } - prtd->dma_addr_next = val_1 + val_2; + if (val_read) + prtd->dma_addr_next = val_1 + val_2; + ifflevel = (int_status & I2S_RX_DESC_IFF_LEVEL_MASK) >> I2S_RX_DESC_IFF_LEVEL_SHIFT; diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c index 2d1e241d836736..4cb2fe10bcdc10 100644 --- a/sound/soc/bcm/cygnus-pcm.c +++ b/sound/soc/bcm/cygnus-pcm.c @@ -707,7 +707,7 @@ static int cygnus_dma_new(struct snd_soc_component *component, return 0; } -static struct snd_soc_component_driver cygnus_soc_platform = { +static const struct snd_soc_component_driver cygnus_soc_platform = { .open = cygnus_pcm_open, .close = cygnus_pcm_close, .prepare = cygnus_pcm_prepare, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7092842480ef17..0f2df7c91e186a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -57,6 +57,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AW8738 imply SND_SOC_AW87390 imply SND_SOC_AW88395 + imply SND_SOC_AW88081 imply SND_SOC_AW88261 imply SND_SOC_AW88399 imply SND_SOC_BT_SCO @@ -85,6 +86,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_CS42L52 imply SND_SOC_CS42L56 imply SND_SOC_CS42L73 + imply SND_SOC_CS42L84 imply SND_SOC_CS4234 imply SND_SOC_CS4265 imply SND_SOC_CS4270 @@ -112,6 +114,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_DA9055 imply SND_SOC_DMIC imply SND_SOC_ES8316 + imply SND_SOC_ES8323 imply SND_SOC_ES8326 imply SND_SOC_ES8328_SPI imply SND_SOC_ES8328_I2C @@ -222,6 +225,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT712_SDCA_DMIC_SDW imply SND_SOC_RT715_SDW imply SND_SOC_RT715_SDCA_SDW + imply SND_SOC_RT721_SDCA_SDW imply SND_SOC_RT722_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW @@ -236,6 +240,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_SIMPLE_AMPLIFIER imply SND_SOC_SIMPLE_MUX imply SND_SOC_SMA1303 + imply SND_SOC_SMA1307 imply SND_SOC_SPDIF imply SND_SOC_SRC4XXX_I2C imply SND_SOC_SSM2305 @@ -281,6 +286,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TWL4030 imply SND_SOC_TWL6040 imply SND_SOC_UDA1334 + imply SND_SOC_UDA1342 imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X @@ -461,7 +467,7 @@ config SND_SOC_ADAU1372_SPI select REGMAP_SPI config SND_SOC_ADAU1373 - tristate + tristate "Analog Devices ADAU1373 CODEC" depends on I2C select SND_SOC_ADAU_UTILS @@ -685,6 +691,17 @@ config SND_SOC_AW88261 boost converter can be adjusted smartly according to the input amplitude. +config SND_SOC_AW88081 + tristate "Soc Audio for awinic aw88081" + depends on I2C + select REGMAP_I2C + select SND_SOC_AW88395_LIB + help + This option enables support for aw88081 Smart PA. + The awinic AW88081 is an I2S/TDM input, high efficiency + digital Smart K audio amplifier. Due to its 9uV noise + floor and ultra-low distortion, clean listening is guaranteed. + config SND_SOC_AW87390 tristate "Soc Audio for awinic aw87390" depends on I2C @@ -926,6 +943,12 @@ config SND_SOC_CS42L83 select REGMAP_I2C select SND_SOC_CS42L42_CORE +config SND_SOC_CS42L84 + tristate "Cirrus Logic CS42L84 CODEC" + depends on I2C + select REGMAP + select REGMAP_I2C + config SND_SOC_CS4234 tristate "Cirrus Logic CS4234 CODEC" depends on I2C @@ -1143,6 +1166,10 @@ config SND_SOC_ES8316 tristate "Everest Semi ES8316 CODEC" depends on I2C +config SND_SOC_ES8323 + tristate "Everest Semi ES8323 CODEC" + depends on I2C + config SND_SOC_ES8326 tristate "Everest Semi ES8326 CODEC" depends on I2C @@ -1545,6 +1572,11 @@ config SND_SOC_RL6231 default m if SND_SOC_RT1305=m default m if SND_SOC_RT1308=m +config SND_SOC_RT_SDW_COMMON + tristate + default y if SND_SOC_RT721_SDCA_SDW=y + default m if SND_SOC_RT721_SDCA_SDW=m + config SND_SOC_RL6347A tristate default y if SND_SOC_RT274=y @@ -1743,6 +1775,12 @@ config SND_SOC_RT712_SDCA_DMIC_SDW select REGMAP_SOUNDWIRE select REGMAP_SOUNDWIRE_MBQ +config SND_SOC_RT721_SDCA_SDW + tristate "Realtek RT721 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + select REGMAP_SOUNDWIRE_MBQ + config SND_SOC_RT722_SDCA_SDW tristate "Realtek RT722 SDCA Codec - SDW" depends on SOUNDWIRE @@ -1836,6 +1874,15 @@ config SND_SOC_SMA1303 help Enable support for Iron Device SMA1303 Boosted Class-D amplifier +config SND_SOC_SMA1307 + tristate "Iron Device SMA1307 Audio Amplifier" + depends on I2C + help + Enable support for Iron Device SMA1307 boosted digital speaker + amplifier with feedback-loop. + If you are using a system with an SMA1307 amplifier connected + via I2C, enable this option. + config SND_SOC_SPDIF tristate "S/PDIF CODEC" @@ -2114,6 +2161,13 @@ config SND_SOC_UDA1334 and has basic features such as de-emphasis (at 44.1 kHz sampling rate) and mute. +config SND_SOC_UDA1342 + tristate "NXP UDA1342 CODEC" + depends on I2C + help + The UDA1342 is an NXP audio codec, support 2x Stereo audio ADC (4x PGA + mic inputs), stereo audio DAC, with basic audio processing. + config SND_SOC_UDA1380 tristate depends on I2C @@ -2565,6 +2619,19 @@ config SND_SOC_NAU8825 tristate depends on I2C +config SND_SOC_NTPFW + tristate + +config SND_SOC_NTP8918 + select SND_SOC_NTPFW + tristate "NeoFidelity NTP8918 amplifier" + depends on I2C + +config SND_SOC_NTP8835 + select SND_SOC_NTPFW + tristate "NeoFidelity NTP8835 and NTP8835C amplifiers" + depends on I2C + config SND_SOC_TPA6130A2 tristate "Texas Instruments TPA6130A2 headphone amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 54cbc3feae3277..f37e82ddb7a104 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -49,6 +49,7 @@ snd-soc-arizona-y := arizona.o arizona-jack.o snd-soc-audio-iio-aux-y := audio-iio-aux.o snd-soc-aw8738-y := aw8738.o snd-soc-aw87390-y := aw87390.o +snd-soc-aw88081-y := aw88081.o snd-soc-aw88395-lib-y := aw88395/aw88395_lib.o snd-soc-aw88395-y := aw88395/aw88395.o \ aw88395/aw88395_device.o @@ -91,6 +92,7 @@ snd-soc-cs42l52-y := cs42l52.o snd-soc-cs42l56-y := cs42l56.o snd-soc-cs42l73-y := cs42l73.o snd-soc-cs42l83-i2c-y := cs42l83-i2c.o +snd-soc-cs42l84-objs := cs42l84.o snd-soc-cs4234-y := cs4234.o snd-soc-cs4265-y := cs4265.o snd-soc-cs4270-y := cs4270.o @@ -125,6 +127,7 @@ snd-soc-es7241-y := es7241.o snd-soc-es83xx-dsm-common-y := es83xx-dsm-common.o snd-soc-es8311-y := es8311.o snd-soc-es8316-y := es8316.o +snd-soc-es8323-y := es8323.o snd-soc-es8326-y := es8326.o snd-soc-es8328-y := es8328.o snd-soc-es8328-i2c-y := es8328-i2c.o @@ -189,6 +192,9 @@ snd-soc-nau8821-y := nau8821.o snd-soc-nau8822-y := nau8822.o snd-soc-nau8824-y := nau8824.o snd-soc-nau8825-y := nau8825.o +snd-soc-ntp8835-y := ntp8835.o +snd-soc-ntp8918-y := ntp8918.o +snd-soc-ntpfw-y := ntpfw.o snd-soc-hdmi-codec-y := hdmi-codec.o snd-soc-pcm1681-y := pcm1681.o snd-soc-pcm1789-codec-y := pcm1789.o @@ -216,6 +222,7 @@ snd-soc-rk3308-y := rk3308_codec.o snd-soc-rk3328-y := rk3328_codec.o snd-soc-rk817-y := rk817_codec.o snd-soc-rl6231-y := rl6231.o +snd-soc-rt-sdw-common-y := rt-sdw-common.o snd-soc-rl6347a-y := rl6347a.o snd-soc-rt1011-y := rt1011.o snd-soc-rt1015-y := rt1015.o @@ -259,6 +266,7 @@ snd-soc-rt712-sdca-y := rt712-sdca.o rt712-sdca-sdw.o snd-soc-rt712-sdca-dmic-y := rt712-sdca-dmic.o snd-soc-rt715-y := rt715.o rt715-sdw.o snd-soc-rt715-sdca-y := rt715-sdca.o rt715-sdca-sdw.o +snd-soc-rt721-sdca-y := rt721-sdca.o rt721-sdca-sdw.o snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o snd-soc-rt9120-y := rt9120.o snd-soc-rtq9128-y := rtq9128.o @@ -271,6 +279,7 @@ snd-soc-sigmadsp-i2c-y := sigmadsp-i2c.o snd-soc-sigmadsp-regmap-y := sigmadsp-regmap.o snd-soc-si476x-y := si476x.o snd-soc-sma1303-y := sma1303.o +snd-soc-sma1307-y := sma1307.o snd-soc-spdif-tx-y := spdif_transmitter.o snd-soc-spdif-rx-y := spdif_receiver.o snd-soc-src4xxx-y := src4xxx.o @@ -319,6 +328,7 @@ snd-soc-ts3a227e-y := ts3a227e.o snd-soc-twl4030-y := twl4030.o snd-soc-twl6040-y := twl6040.o snd-soc-uda1334-y := uda1334.o +snd-soc-uda1342-y := uda1342.o snd-soc-uda1380-y := uda1380.o snd-soc-wcd-classh-y := wcd-clsh-v2.o snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o @@ -457,6 +467,7 @@ obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o obj-$(CONFIG_SND_SOC_AUDIO_IIO_AUX) += snd-soc-audio-iio-aux.o obj-$(CONFIG_SND_SOC_AW8738) += snd-soc-aw8738.o obj-$(CONFIG_SND_SOC_AW87390) += snd-soc-aw87390.o +obj-$(CONFIG_SND_SOC_AW88081) += snd-soc-aw88081.o obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o @@ -498,6 +509,7 @@ obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o obj-$(CONFIG_SND_SOC_CS42L83) += snd-soc-cs42l83-i2c.o +obj-$(CONFIG_SND_SOC_CS42L84) += snd-soc-cs42l84.o obj-$(CONFIG_SND_SOC_CS4234) += snd-soc-cs4234.o obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o @@ -532,6 +544,7 @@ obj-$(CONFIG_SND_SOC_ES7241) += snd-soc-es7241.o obj-$(CONFIG_SND_SOC_ES83XX_DSM_COMMON) += snd-soc-es83xx-dsm-common.o obj-$(CONFIG_SND_SOC_ES8311) += snd-soc-es8311.o obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o +obj-$(CONFIG_SND_SOC_ES8323) += snd-soc-es8323.o obj-$(CONFIG_SND_SOC_ES8326) += snd-soc-es8326.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o @@ -591,6 +604,9 @@ obj-$(CONFIG_SND_SOC_NAU8821) += snd-soc-nau8821.o obj-$(CONFIG_SND_SOC_NAU8822) += snd-soc-nau8822.o obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o +obj-$(CONFIG_SND_SOC_NTP8835) += snd-soc-ntp8835.o +obj-$(CONFIG_SND_SOC_NTP8918) += snd-soc-ntp8918.o +obj-$(CONFIG_SND_SOC_NTPFW) += snd-soc-ntpfw.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o @@ -618,6 +634,7 @@ obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o +obj-$(CONFIG_SND_SOC_RT_SDW_COMMON) += snd-soc-rt-sdw-common.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o @@ -662,6 +679,7 @@ obj-$(CONFIG_SND_SOC_RT712_SDCA_SDW) += snd-soc-rt712-sdca.o obj-$(CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW) += snd-soc-rt712-sdca-dmic.o obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o +obj-$(CONFIG_SND_SOC_RT721_SDCA_SDW) += snd-soc-rt721-sdca.o obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o obj-$(CONFIG_SND_SOC_RTQ9128) += snd-soc-rtq9128.o @@ -672,6 +690,7 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SMA1303) += snd-soc-sma1303.o +obj-$(CONFIG_SND_SOC_SMA1307) += snd-soc-sma1307.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o @@ -723,6 +742,7 @@ obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o +obj-$(CONFIG_SND_SOC_UDA1342) += snd-soc-uda1342.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD_CLASSH) += snd-soc-wcd-classh.o obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c index 2869325f9acede..73f83be38f7490 100644 --- a/sound/soc/codecs/adau1372-i2c.c +++ b/sound/soc/codecs/adau1372-i2c.c @@ -29,6 +29,7 @@ MODULE_DEVICE_TABLE(i2c, adau1372_i2c_ids); static struct i2c_driver adau1372_i2c_driver = { .driver = { .name = "adau1372", + .of_match_table = adau1372_of_match, }, .probe = adau1372_i2c_probe, .id_table = adau1372_i2c_ids, diff --git a/sound/soc/codecs/adau1372-spi.c b/sound/soc/codecs/adau1372-spi.c index 51298e00fbd69c..656bd1fabeb3a1 100644 --- a/sound/soc/codecs/adau1372-spi.c +++ b/sound/soc/codecs/adau1372-spi.c @@ -47,6 +47,7 @@ MODULE_DEVICE_TABLE(spi, adau1372_spi_id); static struct spi_driver adau1372_spi_driver = { .driver = { .name = "adau1372", + .of_match_table = adau1372_of_match, }, .probe = adau1372_spi_probe, .id_table = adau1372_spi_id, diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index 98380a7ce64d80..fdee689cae5383 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -1060,6 +1061,13 @@ const struct regmap_config adau1372_regmap_config = { }; EXPORT_SYMBOL_GPL(adau1372_regmap_config); +const struct of_device_id adau1372_of_match[] = { + { .compatible = "adi,adau1372" }, + { } +}; +EXPORT_SYMBOL_GPL(adau1372_of_match); +MODULE_DEVICE_TABLE(of, adau1372_of_match); + MODULE_DESCRIPTION("ASoC ADAU1372 CODEC driver"); MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/adau1372.h b/sound/soc/codecs/adau1372.h index a9d2c59b73a93c..c55b1c24fe397a 100644 --- a/sound/soc/codecs/adau1372.h +++ b/sound/soc/codecs/adau1372.h @@ -13,6 +13,7 @@ struct device; +extern const struct of_device_id adau1372_of_match[]; int adau1372_probe(struct device *dev, struct regmap *regmap, void (*switch_mode)(struct device *dev)); diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index a910e252aa1265..16b9b265834179 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -8,8 +8,10 @@ #include #include +#include #include #include +#include #include #include @@ -18,7 +20,6 @@ #include #include #include -#include #include "adau1373.h" #include "adau-utils.h" @@ -30,9 +31,28 @@ struct adau1373_dai { bool clock_provider; }; +enum adau1373_micbias_voltage { + ADAU1373_MICBIAS_2_9V, + ADAU1373_MICBIAS_2_2V, + ADAU1373_MICBIAS_2_6V, + ADAU1373_MICBIAS_1_8V, +}; + +#define ADAU1373_DRC_SIZE 13 + struct adau1373 { struct regmap *regmap; struct adau1373_dai dais[3]; + + bool input_differential[4]; + bool lineout_differential; + bool lineout_ground_sense; + + unsigned int num_drc; + u8 drc_setting[3][ADAU1373_DRC_SIZE]; + + enum adau1373_micbias_voltage micbias1; + enum adau1373_micbias_voltage micbias2; }; #define ADAU1373_INPUT_MODE 0x00 @@ -1332,66 +1352,61 @@ static void adau1373_load_drc_settings(struct adau1373 *adau1373, regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]); } -static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias) +static int adau1373_get_micbias(unsigned int val, + enum adau1373_micbias_voltage *micbias) { - switch (micbias) { - case ADAU1373_MICBIAS_2_9V: - case ADAU1373_MICBIAS_2_2V: - case ADAU1373_MICBIAS_2_6V: - case ADAU1373_MICBIAS_1_8V: - return true; + switch (val) { + case 2900000: + *micbias = ADAU1373_MICBIAS_2_9V; + return 0; + case 2200000: + *micbias = ADAU1373_MICBIAS_2_2V; + return 0; + case 2600000: + *micbias = ADAU1373_MICBIAS_2_6V; + return 0; + case 1800000: + *micbias = ADAU1373_MICBIAS_1_8V; + return 0; default: - break; + return -EINVAL; } - return false; } static int adau1373_probe(struct snd_soc_component *component) { struct adau1373 *adau1373 = snd_soc_component_get_drvdata(component); - struct adau1373_platform_data *pdata = component->dev->platform_data; - bool lineout_differential = false; unsigned int val; int i; - if (pdata) { - if (pdata->num_drc > ARRAY_SIZE(pdata->drc_setting)) - return -EINVAL; - - if (!adau1373_valid_micbias(pdata->micbias1) || - !adau1373_valid_micbias(pdata->micbias2)) - return -EINVAL; - - for (i = 0; i < pdata->num_drc; ++i) { - adau1373_load_drc_settings(adau1373, i, - pdata->drc_setting[i]); - } + for (i = 0; i < adau1373->num_drc; ++i) { + adau1373_load_drc_settings(adau1373, i, + adau1373->drc_setting[i]); + } - snd_soc_add_component_controls(component, adau1373_drc_controls, - pdata->num_drc); + snd_soc_add_component_controls(component, adau1373_drc_controls, + adau1373->num_drc); - val = 0; - for (i = 0; i < 4; ++i) { - if (pdata->input_differential[i]) - val |= BIT(i); - } - regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val); + val = 0; + for (i = 0; i < ARRAY_SIZE(adau1373->input_differential); ++i) { + if (adau1373->input_differential[i]) + val |= BIT(i); + } + regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val); - val = 0; - if (pdata->lineout_differential) - val |= ADAU1373_OUTPUT_CTRL_LDIFF; - if (pdata->lineout_ground_sense) - val |= ADAU1373_OUTPUT_CTRL_LNFBEN; - regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val); + val = 0; + if (adau1373->lineout_differential) + val |= ADAU1373_OUTPUT_CTRL_LDIFF; + if (adau1373->lineout_ground_sense) + val |= ADAU1373_OUTPUT_CTRL_LNFBEN; - lineout_differential = pdata->lineout_differential; + regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val); - regmap_write(adau1373->regmap, ADAU1373_EP_CTRL, - (pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) | - (pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET)); - } + regmap_write(adau1373->regmap, ADAU1373_EP_CTRL, + (adau1373->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) | + (adau1373->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET)); - if (!lineout_differential) { + if (!adau1373->lineout_differential) { snd_soc_add_component_controls(component, adau1373_lineout2_controls, ARRAY_SIZE(adau1373_lineout2_controls)); } @@ -1471,9 +1486,74 @@ static const struct snd_soc_component_driver adau1373_component_driver = { .endianness = 1, }; +static void adau1373_reset(void *reset_gpio) +{ + gpiod_set_value_cansleep(reset_gpio, 1); +} + +static int adau1373_parse_fw(struct device *dev, struct adau1373 *adau1373) +{ + int ret, drc_count; + unsigned int val; + + if (device_property_present(dev, "adi,input1-differential")) + adau1373->input_differential[0] = true; + if (device_property_present(dev, "adi,input2-differential")) + adau1373->input_differential[1] = true; + if (device_property_present(dev, "adi,input3-differential")) + adau1373->input_differential[2] = true; + if (device_property_present(dev, "adi,input4-differential")) + adau1373->input_differential[3] = true; + + if (device_property_present(dev, "adi,lineout-differential")) + adau1373->lineout_differential = true; + if (device_property_present(dev, "adi,lineout-gnd-sense")) + adau1373->lineout_ground_sense = true; + + ret = device_property_read_u32(dev, "adi,micbias1-microvolt", &val); + if (!ret) { + ret = adau1373_get_micbias(val, &adau1373->micbias1); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get micbias1(%u)\n", val); + } + + ret = device_property_read_u32(dev, "adi,micbias2-microvolt", &val); + if (!ret) { + ret = adau1373_get_micbias(val, &adau1373->micbias2); + if (ret) + return dev_err_probe(dev, ret, + "Failed to get micbias2(%u)\n", val); + } + + drc_count = device_property_count_u8(dev, "adi,drc-settings"); + if (drc_count < 0) + return 0; + if (drc_count % ADAU1373_DRC_SIZE != 0) + return dev_err_probe(dev, -EINVAL, + "DRC count(%u) not multiple of %u\n", + drc_count, ADAU1373_DRC_SIZE); + + adau1373->num_drc = drc_count / ADAU1373_DRC_SIZE; + if (adau1373->num_drc > ARRAY_SIZE(adau1373->drc_setting)) + return dev_err_probe(dev, -EINVAL, + "Too many DRC settings(%u)\n", + adau1373->num_drc); + + ret = device_property_read_u8_array(dev, "adi,drc-settings", + (u8 *)&adau1373->drc_setting[0], + drc_count); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read DRC settings\n"); + + return 0; +} + static int adau1373_i2c_probe(struct i2c_client *client) { struct adau1373 *adau1373; + struct gpio_desc *gpiod; int ret; adau1373 = devm_kzalloc(&client->dev, sizeof(*adau1373), GFP_KERNEL); @@ -1485,10 +1565,33 @@ static int adau1373_i2c_probe(struct i2c_client *client) if (IS_ERR(adau1373->regmap)) return PTR_ERR(adau1373->regmap); - regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00); + /* + * If the powerdown GPIO is specified, we use it for reset. Otherwise + * a software reset is done. + */ + gpiod = devm_gpiod_get_optional(&client->dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + if (gpiod) { + gpiod_set_value_cansleep(gpiod, 0); + fsleep(10); + + ret = devm_add_action_or_reset(&client->dev, adau1373_reset, + gpiod); + if (ret) + return ret; + } else { + regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00); + } dev_set_drvdata(&client->dev, adau1373); + ret = adau1373_parse_fw(&client->dev, adau1373); + if (ret) + return ret; + ret = devm_snd_soc_register_component(&client->dev, &adau1373_component_driver, adau1373_dai_driver, ARRAY_SIZE(adau1373_dai_driver)); @@ -1501,9 +1604,16 @@ static const struct i2c_device_id adau1373_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id); +static const struct of_device_id adau1373_of_match[] = { + { .compatible = "adi,adau1373", }, + { } +}; +MODULE_DEVICE_TABLE(of, adau1373_of_match); + static struct i2c_driver adau1373_i2c_driver = { .driver = { .name = "adau1373", + .of_match_table = adau1373_of_match, }, .probe = adau1373_i2c_probe, .id_table = adau1373_i2c_id, diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c new file mode 100644 index 00000000000000..58b8e002d76f08 --- /dev/null +++ b/sound/soc/codecs/aw88081.c @@ -0,0 +1,1087 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88081.c -- AW88081 ALSA SoC Audio driver +// +// Copyright (c) 2024 awinic Technology CO., LTD +// +// Author: Weidong Wang +// + +#include +#include +#include +#include +#include "aw88081.h" +#include "aw88395/aw88395_device.h" + +struct aw88081 { + struct aw_device *aw_pa; + struct mutex lock; + struct delayed_work start_work; + struct regmap *regmap; + struct aw_container *aw_cfg; + + bool phase_sync; +}; + +static const struct regmap_config aw88081_regmap_config = { + .val_bits = 16, + .reg_bits = 8, + .max_register = AW88081_REG_MAX, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static int aw88081_dev_get_iis_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88081_SYSST_REG, ®_val); + if (ret) + return ret; + if ((reg_val & AW88081_BIT_PLL_CHECK) != AW88081_BIT_PLL_CHECK) { + dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val); + return -EINVAL; + } + + return 0; +} + +static int aw88081_dev_check_mode1_pll(struct aw_device *aw_dev) +{ + int ret, i; + + for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88081_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode1 iis signal check error"); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static int aw88081_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88081_PLLCTRL1_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88081_CCO_MUX_MASK); + if (reg_val == AW88081_CCO_MUX_DIVIDED_VALUE) { + dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); + return -EPERM; + } + + /* change mode2 */ + ret = regmap_update_bits(aw_dev->regmap, AW88081_PLLCTRL1_REG, + ~AW88081_CCO_MUX_MASK, AW88081_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88081_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis check error"); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + ret = regmap_update_bits(aw_dev->regmap, AW88081_PLLCTRL1_REG, + ~AW88081_CCO_MUX_MASK, AW88081_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88081_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis check error"); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +static int aw88081_dev_check_syspll(struct aw_device *aw_dev) +{ + int ret; + + ret = aw88081_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw88081_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } + + return 0; +} + +static int aw88081_dev_check_sysst(struct aw_device *aw_dev) +{ + unsigned int check_val; + unsigned int reg_val; + unsigned int value; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88081_PWMCTRL4_REG, ®_val); + if (ret) + return ret; + + if (reg_val & (~AW88081_NOISE_GATE_EN_MASK)) + check_val = AW88081_NO_SWS_SYSST_CHECK; + else + check_val = AW88081_SWS_SYSST_CHECK; + + for (i = 0; i < AW88081_DEV_SYSST_CHECK_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88081_SYSST_REG, ®_val); + if (ret) + return ret; + + value = reg_val & (~AW88081_BIT_SYSST_CHECK_MASK) & check_val; + if (value != check_val) { + dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", + reg_val, check_val); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static void aw88081_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) +{ + if (flag) + regmap_update_bits(aw_dev->regmap, AW88081_I2SCTRL3_REG, + ~AW88081_I2STXEN_MASK, AW88081_I2STXEN_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88081_I2SCTRL3_REG, + ~AW88081_I2STXEN_MASK, AW88081_I2STXEN_DISABLE_VALUE); +} + +static void aw88081_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + if (pwd) + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_PWDN_MASK, AW88081_PWDN_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_PWDN_MASK, AW88081_PWDN_WORKING_VALUE); +} + +static void aw88081_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + if (amppd) + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_EN_PA_MASK, AW88081_EN_PA_POWER_DOWN_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_EN_PA_MASK, AW88081_EN_PA_WORKING_VALUE); +} + +static void aw88081_dev_clear_int_status(struct aw_device *aw_dev) +{ + unsigned int int_status; + + /* read int status and clear */ + regmap_read(aw_dev->regmap, AW88081_SYSINT_REG, &int_status); + /* make sure int status is clear */ + regmap_read(aw_dev->regmap, AW88081_SYSINT_REG, &int_status); + + dev_dbg(aw_dev->dev, "read interrupt reg = 0x%04x", int_status); +} + +static void aw88081_dev_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int volume; + + volume = min((value + vol_desc->init_volume), (unsigned int)AW88081_MUTE_VOL); + + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL2_REG, ~AW88081_VOL_MASK, volume); +} + +static void aw88081_dev_fade_in(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_in_vol = desc->ctl_volume; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_in_time == 0) { + aw88081_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88081_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw88081_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw88081_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw88081_dev_fade_out(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_out_time == 0) { + aw88081_dev_set_volume(aw_dev, AW88081_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88081_MUTE_VOL; i += fade_step) { + aw88081_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88081_MUTE_VOL) + aw88081_dev_set_volume(aw_dev, AW88081_MUTE_VOL); +} + +static void aw88081_dev_mute(struct aw_device *aw_dev, bool is_mute) +{ + if (is_mute) { + aw88081_dev_fade_out(aw_dev); + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_HMUTE_MASK, AW88081_HMUTE_ENABLE_VALUE); + } else { + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_HMUTE_MASK, AW88081_HMUTE_DISABLE_VALUE); + aw88081_dev_fade_in(aw_dev); + } +} + +static void aw88081_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute) +{ + if (uls_hmute) + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_ULS_HMUTE_MASK, + AW88081_ULS_HMUTE_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG, + ~AW88081_ULS_HMUTE_MASK, + AW88081_ULS_HMUTE_DISABLE_VALUE); +} + +static int aw88081_dev_reg_update(struct aw88081 *aw88081, + unsigned char *data, unsigned int len) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int read_vol; + int data_len, i, ret; + int16_t *reg_data; + u16 reg_val; + u8 reg_addr; + + if (!len || !data) { + dev_err(aw_dev->dev, "reg data is null or len is 0"); + return -EINVAL; + } + + reg_data = (int16_t *)data; + data_len = len >> 1; + + if (data_len & 0x1) { + dev_err(aw_dev->dev, "data len:%d unsupported", data_len); + return -EINVAL; + } + + for (i = 0; i < data_len; i += 2) { + reg_addr = reg_data[i]; + reg_val = reg_data[i + 1]; + + if (reg_addr == AW88081_SYSCTRL_REG) { + reg_val &= ~(~AW88081_EN_PA_MASK | + ~AW88081_PWDN_MASK | + ~AW88081_HMUTE_MASK | + ~AW88081_ULS_HMUTE_MASK); + + reg_val |= AW88081_EN_PA_POWER_DOWN_VALUE | + AW88081_PWDN_POWER_DOWN_VALUE | + AW88081_HMUTE_ENABLE_VALUE | + AW88081_ULS_HMUTE_ENABLE_VALUE; + } + + if (reg_addr == AW88081_SYSCTRL2_REG) { + read_vol = (reg_val & (~AW88081_VOL_MASK)) >> + AW88081_VOL_START_BIT; + aw_dev->volume_desc.init_volume = read_vol; + } + + /* i2stxen */ + if (reg_addr == AW88081_I2SCTRL3_REG) { + /* close tx */ + reg_val &= AW88081_I2STXEN_MASK; + reg_val |= AW88081_I2STXEN_DISABLE_VALUE; + } + + ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); + if (ret) + return ret; + } + + if (aw_dev->prof_cur != aw_dev->prof_index) + vol_desc->ctl_volume = 0; + + /* keep min volume */ + aw88081_dev_set_volume(aw_dev, vol_desc->mute_volume); + + return 0; +} + +static int aw88081_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc; + + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "index[%d] overflow count[%d]", + index, aw_dev->prof_info.count); + return -EINVAL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + *prof_name = prof_info->prof_name_list[prof_desc->id]; + + return 0; +} + +static int aw88081_dev_get_prof_data(struct aw_device *aw_dev, int index, + struct aw_prof_desc **prof_desc) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", + __func__, index, aw_dev->prof_info.count); + return -EINVAL; + } + + *prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return 0; +} + +static int aw88081_dev_fw_update(struct aw88081 *aw88081) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + ret = aw88081_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); + if (ret) { + dev_err(aw_dev->dev, "get prof name failed"); + return -EINVAL; + } + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw88081_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); + if (ret) + return ret; + + /* update reg */ + sec_desc = prof_index_desc->sec_desc; + ret = aw88081_dev_reg_update(aw88081, sec_desc[AW88395_DATA_TYPE_REG].data, + sec_desc[AW88395_DATA_TYPE_REG].len); + if (ret) { + dev_err(aw_dev->dev, "update reg failed"); + return ret; + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return 0; +} + +static int aw88081_dev_start(struct aw88081 *aw88081) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + int ret; + + if (aw_dev->status == AW88081_DEV_PW_ON) { + dev_dbg(aw_dev->dev, "already power on"); + return 0; + } + + /* power on */ + aw88081_dev_pwd(aw_dev, false); + usleep_range(AW88081_2000_US, AW88081_2000_US + 10); + + ret = aw88081_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start"); + goto pll_check_fail; + } + + /* amppd on */ + aw88081_dev_amppd(aw_dev, false); + usleep_range(AW88081_1000_US, AW88081_1000_US + 50); + + /* check i2s status */ + ret = aw88081_dev_check_sysst(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "sysst check failed"); + goto sysst_check_fail; + } + + /* enable tx feedback */ + aw88081_dev_i2s_tx_enable(aw_dev, true); + + /* close uls mute */ + aw88081_dev_uls_hmute(aw_dev, false); + + /* close mute */ + aw88081_dev_mute(aw_dev, false); + + /* clear inturrupt */ + aw88081_dev_clear_int_status(aw_dev); + aw_dev->status = AW88081_DEV_PW_ON; + + return 0; + +sysst_check_fail: + aw88081_dev_i2s_tx_enable(aw_dev, false); + aw88081_dev_clear_int_status(aw_dev); + aw88081_dev_amppd(aw_dev, true); +pll_check_fail: + aw88081_dev_pwd(aw_dev, true); + aw_dev->status = AW88081_DEV_PW_OFF; + + return ret; +} + +static int aw88081_dev_stop(struct aw_device *aw_dev) +{ + if (aw_dev->status == AW88081_DEV_PW_OFF) { + dev_dbg(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW88081_DEV_PW_OFF; + + /* clear inturrupt */ + aw88081_dev_clear_int_status(aw_dev); + + aw88081_dev_uls_hmute(aw_dev, true); + /* set mute */ + aw88081_dev_mute(aw_dev, true); + + /* close tx feedback */ + aw88081_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88081_1000_US, AW88081_1000_US + 100); + + /* enable amppd */ + aw88081_dev_amppd(aw_dev, true); + + /* set power down */ + aw88081_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88081_reg_update(struct aw88081 *aw88081, bool force) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + int ret; + + if (force) { + ret = regmap_write(aw_dev->regmap, + AW88081_ID_REG, AW88081_SOFT_RESET_VALUE); + if (ret) + return ret; + + ret = aw88081_dev_fw_update(aw88081); + if (ret) + return ret; + } else { + if (aw_dev->prof_cur != aw_dev->prof_index) { + ret = aw88081_dev_fw_update(aw88081); + if (ret) + return ret; + } + } + + aw_dev->prof_cur = aw_dev->prof_index; + + return 0; +} + +static void aw88081_start_pa(struct aw88081 *aw88081) +{ + int ret, i; + + for (i = 0; i < AW88081_START_RETRIES; i++) { + ret = aw88081_reg_update(aw88081, aw88081->phase_sync); + if (ret) { + dev_err(aw88081->aw_pa->dev, "fw update failed, cnt:%d\n", i); + continue; + } + ret = aw88081_dev_start(aw88081); + if (ret) { + dev_err(aw88081->aw_pa->dev, "aw88081 device start failed. retry = %d", i); + continue; + } else { + dev_dbg(aw88081->aw_pa->dev, "start success\n"); + break; + } + } +} + +static void aw88081_startup_work(struct work_struct *work) +{ + struct aw88081 *aw88081 = + container_of(work, struct aw88081, start_work.work); + + mutex_lock(&aw88081->lock); + aw88081_start_pa(aw88081); + mutex_unlock(&aw88081->lock); +} + +static void aw88081_start(struct aw88081 *aw88081, bool sync_start) +{ + if (aw88081->aw_pa->fw_status != AW88081_DEV_FW_OK) + return; + + if (aw88081->aw_pa->status == AW88081_DEV_PW_ON) + return; + + if (sync_start == AW88081_SYNC_START) + aw88081_start_pa(aw88081); + else + queue_delayed_work(system_wq, + &aw88081->start_work, + AW88081_START_WORK_DELAY_MS); +} + +static struct snd_soc_dai_driver aw88081_dai[] = { + { + .name = "aw88081-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW88081_RATES, + .formats = AW88081_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW88081_RATES, + .formats = AW88081_FORMATS, + }, + }, +}; + +static int aw88081_get_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88081->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_in_time; + + return 0; +} + +static int aw88081_set_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88081->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_in_time) { + aw_dev->fade_in_time = time; + return 1; + } + + return 0; +} + +static int aw88081_get_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88081->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_out_time; + + return 0; +} + +static int aw88081_set_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88081->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_out_time) { + aw_dev->fade_out_time = time; + return 1; + } + + return 0; +} + +static int aw88081_dev_set_profile_index(struct aw_device *aw_dev, int index) +{ + /* check the index whether is valid */ + if ((index >= aw_dev->prof_info.count) || (index < 0)) + return -EINVAL; + /* check the index whether change */ + if (aw_dev->prof_index == index) + return -EPERM; + + aw_dev->prof_index = index; + + return 0; +} + +static int aw88081_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + char *prof_name; + int count, ret; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw88081->aw_pa->prof_info.count; + if (count <= 0) { + uinfo->value.enumerated.items = 0; + return 0; + } + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + count = uinfo->value.enumerated.item; + + ret = aw88081_dev_get_prof_name(aw88081->aw_pa, count, &prof_name); + if (ret) { + strscpy(uinfo->value.enumerated.name, "null", + sizeof(uinfo->value.enumerated.name)); + return 0; + } + + strscpy(uinfo->value.enumerated.name, prof_name, sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int aw88081_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88081->aw_pa->prof_index; + + return 0; +} + +static int aw88081_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + int ret; + + /* pa stop or stopping just set profile */ + mutex_lock(&aw88081->lock); + ret = aw88081_dev_set_profile_index(aw88081->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + dev_dbg(codec->dev, "profile index does not change"); + mutex_unlock(&aw88081->lock); + return 0; + } + + if (aw88081->aw_pa->status) { + aw88081_dev_stop(aw88081->aw_pa); + aw88081_start(aw88081, AW88081_SYNC_START); + } + + mutex_unlock(&aw88081->lock); + + return 1; +} + +static int aw88081_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88081->aw_pa->volume_desc; + + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; + + return 0; +} + +static int aw88081_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88081->aw_pa->volume_desc; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (vol_desc->ctl_volume != value) { + vol_desc->ctl_volume = value; + aw88081_dev_set_volume(aw88081->aw_pa, vol_desc->ctl_volume); + return 1; + } + + return 0; +} + +static int aw88081_get_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88081->aw_pa->fade_step; + + return 0; +} + +static int aw88081_set_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (aw88081->aw_pa->fade_step != value) { + aw88081->aw_pa->fade_step = value; + return 1; + } + + return 0; +} + +static const struct snd_kcontrol_new aw88081_controls[] = { + SOC_SINGLE_EXT("PCM Playback Volume", AW88081_SYSCTRL2_REG, + 0, AW88081_MUTE_VOL, 0, aw88081_volume_get, + aw88081_volume_set), + SOC_SINGLE_EXT("Fade Step", 0, 0, AW88081_MUTE_VOL, 0, + aw88081_get_fade_step, aw88081_set_fade_step), + SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, 0, + aw88081_get_fade_in_time, aw88081_set_fade_in_time), + SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, 0, + aw88081_get_fade_out_time, aw88081_set_fade_out_time), + AW88081_PROFILE_EXT("Profile Set", aw88081_profile_info, + aw88081_profile_get, aw88081_profile_set), +}; + +static void aw88081_parse_channel_dt(struct aw88081 *aw88081) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value = AW88081_DEV_DEFAULT_CH; + + of_property_read_u32(np, "awinic,audio-channel", &channel_value); + aw88081->phase_sync = of_property_read_bool(np, "awinic,sync-flag"); + + aw_dev->channel = channel_value; +} + +static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct regmap *regmap) +{ + struct aw_device *aw_dev; + unsigned int chip_id; + int ret; + + /* read chip id */ + ret = regmap_read(regmap, AW88081_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret); + return ret; + } + if (chip_id != AW88081_CHIP_ID) { + dev_err(&i2c->dev, "unsupported device"); + return -ENXIO; + } + + dev_dbg(&i2c->dev, "chip id = %x\n", chip_id); + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + + aw88081->aw_pa = aw_dev; + aw_dev->i2c = i2c; + aw_dev->regmap = regmap; + aw_dev->dev = &i2c->dev; + aw_dev->chip_id = AW88081_CHIP_ID; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->fade_step = AW88081_VOLUME_STEP_DB; + aw_dev->volume_desc.mute_volume = AW88081_MUTE_VOL; + aw88081_parse_channel_dt(aw88081); + + return 0; +} + +static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg) +{ + struct aw_device *aw_dev = aw88081->aw_pa; + int ret; + + ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); + if (ret) { + dev_err(aw_dev->dev, "aw_dev acf parse failed"); + return -EINVAL; + } + + ret = regmap_write(aw_dev->regmap, AW88081_ID_REG, AW88081_SOFT_RESET_VALUE); + if (ret) + return ret; + + aw_dev->fade_in_time = AW88081_500_US; + aw_dev->fade_out_time = AW88081_500_US; + aw_dev->prof_cur = AW88081_INIT_PROFILE; + aw_dev->prof_index = AW88081_INIT_PROFILE; + + ret = aw88081_dev_fw_update(aw88081); + if (ret) { + dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); + return ret; + } + + aw88081_dev_clear_int_status(aw_dev); + + aw88081_dev_uls_hmute(aw_dev, true); + + aw88081_dev_mute(aw_dev, true); + + usleep_range(AW88081_5000_US, AW88081_5000_US + 10); + + aw88081_dev_i2s_tx_enable(aw_dev, false); + + usleep_range(AW88081_1000_US, AW88081_1000_US + 100); + + aw88081_dev_amppd(aw_dev, true); + + aw88081_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88081_request_firmware_file(struct aw88081 *aw88081) +{ + const struct firmware *cont = NULL; + int ret; + + aw88081->aw_pa->fw_status = AW88081_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW88081_ACF_FILE, aw88081->aw_pa->dev); + if (ret) + return ret; + + dev_dbg(aw88081->aw_pa->dev, "loaded %s - size: %zu\n", + AW88081_ACF_FILE, cont ? cont->size : 0); + + aw88081->aw_cfg = devm_kzalloc(aw88081->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL); + if (!aw88081->aw_cfg) { + release_firmware(cont); + return -ENOMEM; + } + aw88081->aw_cfg->len = (int)cont->size; + memcpy(aw88081->aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw88395_dev_load_acf_check(aw88081->aw_pa, aw88081->aw_cfg); + if (ret) + return ret; + + mutex_lock(&aw88081->lock); + ret = aw88081_dev_init(aw88081, aw88081->aw_cfg); + mutex_unlock(&aw88081->lock); + + return ret; +} + +static int aw88081_playback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + + mutex_lock(&aw88081->lock); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aw88081_start(aw88081, AW88081_ASYNC_START); + break; + case SND_SOC_DAPM_POST_PMD: + aw88081_dev_stop(aw88081->aw_pa); + break; + default: + break; + } + mutex_unlock(&aw88081->lock); + + return 0; +} + +static const struct snd_soc_dapm_widget aw88081_dapm_widgets[] = { + /* playback */ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0, + aw88081_playback_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("DAC Output"), + + /* capture */ + SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("ADC Input"), +}; + +static const struct snd_soc_dapm_route aw88081_audio_map[] = { + {"DAC Output", NULL, "AIF_RX"}, + {"AIF_TX", NULL, "ADC Input"}, +}; + +static int aw88081_codec_probe(struct snd_soc_component *component) +{ + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component); + int ret; + + INIT_DELAYED_WORK(&aw88081->start_work, aw88081_startup_work); + + ret = aw88081_request_firmware_file(aw88081); + if (ret) + dev_err(aw88081->aw_pa->dev, "%s: request firmware failed\n", __func__); + + return ret; +} + +static void aw88081_codec_remove(struct snd_soc_component *aw_codec) +{ + struct aw88081 *aw88081 = snd_soc_component_get_drvdata(aw_codec); + + cancel_delayed_work_sync(&aw88081->start_work); +} + +static const struct snd_soc_component_driver soc_codec_dev_aw88081 = { + .probe = aw88081_codec_probe, + .remove = aw88081_codec_remove, + .dapm_widgets = aw88081_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aw88081_dapm_widgets), + .dapm_routes = aw88081_audio_map, + .num_dapm_routes = ARRAY_SIZE(aw88081_audio_map), + .controls = aw88081_controls, + .num_controls = ARRAY_SIZE(aw88081_controls), +}; + +static int aw88081_i2c_probe(struct i2c_client *i2c) +{ + struct aw88081 *aw88081; + int ret; + + ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C); + if (!ret) + return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed"); + + aw88081 = devm_kzalloc(&i2c->dev, sizeof(*aw88081), GFP_KERNEL); + if (!aw88081) + return -ENOMEM; + + mutex_init(&aw88081->lock); + + i2c_set_clientdata(i2c, aw88081); + + aw88081->regmap = devm_regmap_init_i2c(i2c, &aw88081_regmap_config); + if (IS_ERR(aw88081->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(aw88081->regmap), + "failed to init regmap\n"); + + /* aw pa init */ + ret = aw88081_init(aw88081, i2c, aw88081->regmap); + if (ret) + return ret; + + return devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_aw88081, + aw88081_dai, ARRAY_SIZE(aw88081_dai)); +} + +static const struct i2c_device_id aw88081_i2c_id[] = { + { AW88081_I2C_NAME }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw88081_i2c_id); + +static struct i2c_driver aw88081_i2c_driver = { + .driver = { + .name = AW88081_I2C_NAME, + }, + .probe = aw88081_i2c_probe, + .id_table = aw88081_i2c_id, +}; +module_i2c_driver(aw88081_i2c_driver); + +MODULE_DESCRIPTION("ASoC AW88081 Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw88081.h b/sound/soc/codecs/aw88081.h new file mode 100644 index 00000000000000..b4bf7288021abc --- /dev/null +++ b/sound/soc/codecs/aw88081.h @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88081.h -- AW88081 ALSA SoC Audio driver +// +// Copyright (c) 2024 awinic Technology CO., LTD +// +// Author: Weidong Wang +// + +#ifndef __AW88081_H__ +#define __AW88081_H__ + +#define AW88081_ID_REG (0x00) +#define AW88081_SYSST_REG (0x01) +#define AW88081_SYSINT_REG (0x02) +#define AW88081_SYSINTM_REG (0x03) +#define AW88081_SYSCTRL_REG (0x04) +#define AW88081_SYSCTRL2_REG (0x05) +#define AW88081_I2SCTRL1_REG (0x06) +#define AW88081_I2SCTRL2_REG (0x07) +#define AW88081_I2SCTRL3_REG (0x08) +#define AW88081_DACCFG1_REG (0x09) +#define AW88081_DACCFG2_REG (0x0A) +#define AW88081_DACCFG3_REG (0x0B) +#define AW88081_DACCFG4_REG (0x0C) +#define AW88081_DACCFG5_REG (0x0D) +#define AW88081_DACCFG6_REG (0x0E) +#define AW88081_DACCFG7_REG (0x11) +#define AW88081_PWMCTRL1_REG (0x13) +#define AW88081_PWMCTRL2_REG (0x14) +#define AW88081_PWMCTRL3_REG (0x15) +#define AW88081_PWMCTRL4_REG (0x16) +#define AW88081_I2SCFG1_REG (0x17) +#define AW88081_DBGCTRL_REG (0x18) +#define AW88081_PDMCTRL_REG (0x19) +#define AW88081_DACST_REG (0x20) +#define AW88081_PATTERNST_REG (0x21) +#define AW88081_I2SINT_REG (0x26) +#define AW88081_I2SCAPCNT_REG (0x27) +#define AW88081_ANASTA1_REG (0x28) +#define AW88081_ANASTA2_REG (0x29) +#define AW88081_ANASTA3_REG (0x2A) +#define AW88081_VBAT_REG (0x21) +#define AW88081_TEMP_REG (0x22) +#define AW88081_PVDD_REG (0x23) +#define AW88081_ISNDAT_REG (0x24) +#define AW88081_VSNDAT_REG (0x25) +#define AW88081_DSMCFG1_REG (0x30) +#define AW88081_DSMCFG2_REG (0x31) +#define AW88081_DSMCFG3_REG (0x32) +#define AW88081_DSMCFG4_REG (0x33) +#define AW88081_DSMCFG5_REG (0x34) +#define AW88081_DSMCFG6_REG (0x35) +#define AW88081_DSMCFG7_REG (0x36) +#define AW88081_DSMCFG8_REG (0x37) +#define AW88081_TESTIN_REG (0x38) +#define AW88081_TESTOUT_REG (0x39) +#define AW88081_BOPCTRL1_REG (0x40) +#define AW88081_BOPCTRL2_REG (0x41) +#define AW88081_BOPCTRL3_REG (0x42) +#define AW88081_BOPSTA_REG (0x43) +#define AW88081_PLLCTRL1_REG (0x54) +#define AW88081_PLLCTRL2_REG (0x55) +#define AW88081_PLLCTRL3_REG (0x56) +#define AW88081_CDACTRL1_REG (0x57) +#define AW88081_CDACTRL2_REG (0x58) +#define AW88081_CDACTRL3_REG (0x59) +#define AW88081_DITHERCFG1_REG (0x5A) +#define AW88081_DITHERCFG2_REG (0x5B) +#define AW88081_DITHERCFG3_REG (0x5C) +#define AW88081_TM_REG (0x6E) +#define AW88081_TM2_REG (0x6F) +#define AW88081_TESTCTRL1_REG (0x70) +#define AW88081_TESTCTRL2_REG (0x71) + +#define AW88081_REG_MAX (0x72) + +#define AW88081_UVLS_START_BIT (14) +#define AW88081_UVLS_UVLO (1) +#define AW88081_UVLS_UVLO_VALUE \ + (AW88081_UVLS_UVLO << AW88081_UVLS_START_BIT) + +#define AW88081_SWS_START_BIT (8) +#define AW88081_SWS_SWITCHING (1) +#define AW88081_SWS_SWITCHING_VALUE \ + (AW88081_SWS_SWITCHING << AW88081_SWS_START_BIT) + +#define AW88081_NOCLKS_START_BIT (5) +#define AW88081_NOCLKS_NO_CLOCK (1) +#define AW88081_NOCLKS_NO_CLOCK_VALUE \ + (AW88081_NOCLKS_NO_CLOCK << AW88081_NOCLKS_START_BIT) + +#define AW88081_CLKS_START_BIT (4) +#define AW88081_CLKS_STABLE (1) +#define AW88081_CLKS_STABLE_VALUE \ + (AW88081_CLKS_STABLE << AW88081_CLKS_START_BIT) + +#define AW88081_OCDS_START_BIT (3) +#define AW88081_OCDS_OC (1) +#define AW88081_OCDS_OC_VALUE \ + (AW88081_OCDS_OC << AW88081_OCDS_START_BIT) + +#define AW88081_OTHS_START_BIT (1) +#define AW88081_OTHS_OT (1) +#define AW88081_OTHS_OT_VALUE \ + (AW88081_OTHS_OT << AW88081_OTHS_START_BIT) + +#define AW88081_PLLS_START_BIT (0) +#define AW88081_PLLS_LOCKED (1) +#define AW88081_PLLS_LOCKED_VALUE \ + (AW88081_PLLS_LOCKED << AW88081_PLLS_START_BIT) + +#define AW88081_BIT_PLL_CHECK \ + (AW88081_CLKS_STABLE_VALUE | \ + AW88081_PLLS_LOCKED_VALUE) + +#define AW88081_BIT_SYSST_CHECK_MASK \ + (~(AW88081_UVLS_UVLO_VALUE | \ + AW88081_SWS_SWITCHING_VALUE | \ + AW88081_NOCLKS_NO_CLOCK_VALUE | \ + AW88081_CLKS_STABLE_VALUE | \ + AW88081_OCDS_OC_VALUE | \ + AW88081_OTHS_OT_VALUE | \ + AW88081_PLLS_LOCKED_VALUE)) + +#define AW88081_NO_SWS_SYSST_CHECK \ + (AW88081_CLKS_STABLE_VALUE | \ + AW88081_PLLS_LOCKED_VALUE) + +#define AW88081_SWS_SYSST_CHECK \ + (AW88081_SWS_SWITCHING_VALUE | \ + AW88081_CLKS_STABLE_VALUE | \ + AW88081_PLLS_LOCKED_VALUE) + +#define AW88081_ULS_HMUTE_START_BIT (14) +#define AW88081_ULS_HMUTE_BITS_LEN (1) +#define AW88081_ULS_HMUTE_MASK \ + (~(((1<dev, "unsupport vsense status"); + dev_err(aw_dev->dev, "unsupported vsense status"); return -EINVAL; } diff --git a/sound/soc/codecs/aw88395/aw88395_lib.c b/sound/soc/codecs/aw88395/aw88395_lib.c index 769ca32a5c8efa..ceb7fc43d01800 100644 --- a/sound/soc/codecs/aw88395/aw88395_lib.c +++ b/sound/soc/codecs/aw88395/aw88395_lib.c @@ -688,7 +688,7 @@ static int aw_dev_load_cfg_by_hdr(struct aw_device *aw_dev, ret = aw_dev_cfg_get_reg_valid_prof(aw_dev, all_prof_info); break; default: - dev_err(aw_dev->dev, "unsupport data type\n"); + dev_err(aw_dev->dev, "unsupported data type\n"); ret = -EINVAL; break; } diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c index bba59885242d0c..ee3cc2a95f85e7 100644 --- a/sound/soc/codecs/aw88399.c +++ b/sound/soc/codecs/aw88399.c @@ -462,7 +462,7 @@ static int aw_dev_set_vcalb(struct aw88399 *aw88399) vcal_k * aw88399->vcalb_init_val; break; default: - dev_err(aw_dev->dev, "%s: unsupport vsense\n", __func__); + dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__); ret = -EINVAL; break; } diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c index 4f9dabd9d78a67..04304a7ad9153d 100644 --- a/sound/soc/codecs/cpcap.c +++ b/sound/soc/codecs/cpcap.c @@ -1649,7 +1649,7 @@ static int cpcap_soc_probe(struct snd_soc_component *component) return cpcap_audio_reset(component, false); } -static struct snd_soc_component_driver soc_codec_dev_cpcap = { +static const struct snd_soc_component_driver soc_codec_dev_cpcap = { .probe = cpcap_soc_probe, .controls = cpcap_snd_controls, .num_controls = ARRAY_SIZE(cpcap_snd_controls), diff --git a/sound/soc/codecs/cs-amp-lib-test.c b/sound/soc/codecs/cs-amp-lib-test.c index a6e8348a1bd537..45626f99a4175e 100644 --- a/sound/soc/codecs/cs-amp-lib-test.c +++ b/sound/soc/codecs/cs-amp-lib-test.c @@ -756,7 +756,7 @@ static struct kunit_suite cs_amp_lib_test_suite = { kunit_test_suite(cs_amp_lib_test_suite); -MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB); +MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); MODULE_DESCRIPTION("KUnit test for Cirrus Logic amplifier library"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c index 51b128c8067188..c677868c5d5f7b 100644 --- a/sound/soc/codecs/cs-amp-lib.c +++ b/sound/soc/codecs/cs-amp-lib.c @@ -97,7 +97,7 @@ int cs_amp_write_cal_coeffs(struct cs_dsp *dsp, else return -ENODEV; } -EXPORT_SYMBOL_NS_GPL(cs_amp_write_cal_coeffs, SND_SOC_CS_AMP_LIB); +EXPORT_SYMBOL_NS_GPL(cs_amp_write_cal_coeffs, "SND_SOC_CS_AMP_LIB"); static efi_status_t cs_amp_get_efi_variable(efi_char16_t *name, efi_guid_t *guid, @@ -270,7 +270,7 @@ int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_ else return -ENOENT; } -EXPORT_SYMBOL_NS_GPL(cs_amp_get_efi_calibration_data, SND_SOC_CS_AMP_LIB); +EXPORT_SYMBOL_NS_GPL(cs_amp_get_efi_calibration_data, "SND_SOC_CS_AMP_LIB"); static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = { .get_efi_variable = cs_amp_get_efi_variable, @@ -279,9 +279,9 @@ static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = { const struct cs_amp_test_hooks * const cs_amp_test_hooks = PTR_IF(IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST), &cs_amp_test_hook_ptrs); -EXPORT_SYMBOL_NS_GPL(cs_amp_test_hooks, SND_SOC_CS_AMP_LIB); +EXPORT_SYMBOL_NS_GPL(cs_amp_test_hooks, "SND_SOC_CS_AMP_LIB"); MODULE_DESCRIPTION("Cirrus Logic amplifier library"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(FW_CS_DSP); +MODULE_IMPORT_NS("FW_CS_DSP"); diff --git a/sound/soc/codecs/cs35l45-i2c.c b/sound/soc/codecs/cs35l45-i2c.c index f5fc42dcc8c70c..a09aa3b92ae157 100644 --- a/sound/soc/codecs/cs35l45-i2c.c +++ b/sound/soc/codecs/cs35l45-i2c.c @@ -73,4 +73,4 @@ module_i2c_driver(cs35l45_i2c_driver); MODULE_DESCRIPTION("I2C CS35L45 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_CS35L45); +MODULE_IMPORT_NS("SND_SOC_CS35L45"); diff --git a/sound/soc/codecs/cs35l45-spi.c b/sound/soc/codecs/cs35l45-spi.c index 39e203a5f060c6..5f91472c3fd291 100644 --- a/sound/soc/codecs/cs35l45-spi.c +++ b/sound/soc/codecs/cs35l45-spi.c @@ -75,4 +75,4 @@ module_spi_driver(cs35l45_spi_driver); MODULE_DESCRIPTION("SPI CS35L45 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_CS35L45); +MODULE_IMPORT_NS("SND_SOC_CS35L45"); diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c index 405dab137b3b09..d2ecc7b3f61938 100644 --- a/sound/soc/codecs/cs35l45-tables.c +++ b/sound/soc/codecs/cs35l45-tables.c @@ -38,7 +38,7 @@ int cs35l45_apply_patch(struct cs35l45_private *cs35l45) return regmap_register_patch(cs35l45->regmap, cs35l45_patch, ARRAY_SIZE(cs35l45_patch)); } -EXPORT_SYMBOL_NS_GPL(cs35l45_apply_patch, SND_SOC_CS35L45); +EXPORT_SYMBOL_NS_GPL(cs35l45_apply_patch, "SND_SOC_CS35L45"); static const struct reg_default cs35l45_defaults[] = { { CS35L45_BLOCK_ENABLES, 0x00003323 }, @@ -260,7 +260,7 @@ const struct regmap_config cs35l45_i2c_regmap = { .readable_reg = cs35l45_readable_reg, .cache_type = REGCACHE_MAPLE, }; -EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, SND_SOC_CS35L45); +EXPORT_SYMBOL_NS_GPL(cs35l45_i2c_regmap, "SND_SOC_CS35L45"); const struct regmap_config cs35l45_spi_regmap = { .reg_bits = 32, @@ -276,7 +276,7 @@ const struct regmap_config cs35l45_spi_regmap = { .readable_reg = cs35l45_readable_reg, .cache_type = REGCACHE_MAPLE, }; -EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, SND_SOC_CS35L45); +EXPORT_SYMBOL_NS_GPL(cs35l45_spi_regmap, "SND_SOC_CS35L45"); static const struct { u8 cfg_id; @@ -329,4 +329,4 @@ int cs35l45_get_clk_freq_id(unsigned int freq) return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(cs35l45_get_clk_freq_id, SND_SOC_CS35L45); +EXPORT_SYMBOL_NS_GPL(cs35l45_get_clk_freq_id, "SND_SOC_CS35L45"); diff --git a/sound/soc/codecs/cs35l45.c b/sound/soc/codecs/cs35l45.c index fa1d9d9151f96e..432a19f4de2b4b 100644 --- a/sound/soc/codecs/cs35l45.c +++ b/sound/soc/codecs/cs35l45.c @@ -1486,7 +1486,7 @@ int cs35l45_probe(struct cs35l45_private *cs35l45) return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l45_probe, SND_SOC_CS35L45); +EXPORT_SYMBOL_NS_GPL(cs35l45_probe, "SND_SOC_CS35L45"); void cs35l45_remove(struct cs35l45_private *cs35l45) { @@ -1501,7 +1501,7 @@ void cs35l45_remove(struct cs35l45_private *cs35l45) /* VDD_BATT must be the last to power-off */ regulator_disable(cs35l45->vdd_batt); } -EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45); +EXPORT_SYMBOL_NS_GPL(cs35l45_remove, "SND_SOC_CS35L45"); EXPORT_GPL_DEV_PM_OPS(cs35l45_pm_ops) = { RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL) diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c index 2bd2ff75cd5047..8a518df1e16e83 100644 --- a/sound/soc/codecs/cs35l56-i2c.c +++ b/sound/soc/codecs/cs35l56-i2c.c @@ -84,8 +84,8 @@ static struct i2c_driver cs35l56_i2c_driver = { module_i2c_driver(cs35l56_i2c_driver); MODULE_DESCRIPTION("ASoC CS35L56 I2C driver"); -MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index 7c9a17fe2195cc..3f91cb3f9ae70f 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -582,8 +582,8 @@ static struct sdw_driver cs35l56_sdw_driver = { module_sdw_driver(cs35l56_sdw_driver); MODULE_DESCRIPTION("ASoC CS35L56 SoundWire driver"); -MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index e45e9ae01bc668..e0ed4fc11155a5 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -49,7 +49,7 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base) return regmap_register_patch(cs35l56_base->regmap, cs35l56_patch, ARRAY_SIZE(cs35l56_patch)); } -EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_set_patch, "SND_SOC_CS35L56_SHARED"); static const struct reg_default cs35l56_reg_defaults[] = { /* no defaults for OTP_MEM - first read populates cache */ @@ -241,7 +241,7 @@ int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command) return 0; } -EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_mbox_send, "SND_SOC_CS35L56_SHARED"); int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base) { @@ -261,7 +261,7 @@ int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base) val, ret); return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_firmware_shutdown, "SND_SOC_CS35L56_SHARED"); int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) { @@ -287,21 +287,21 @@ int cs35l56_wait_for_firmware_boot(struct cs35l56_base *cs35l56_base) return 0; } -EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_for_firmware_boot, "SND_SOC_CS35L56_SHARED"); void cs35l56_wait_control_port_ready(void) { /* Wait for control port to be ready (datasheet tIRS). */ usleep_range(CS35L56_CONTROL_PORT_READY_US, 2 * CS35L56_CONTROL_PORT_READY_US); } -EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_control_port_ready, "SND_SOC_CS35L56_SHARED"); void cs35l56_wait_min_reset_pulse(void) { /* Satisfy minimum reset pulse width spec */ usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US); } -EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, "SND_SOC_CS35L56_SHARED"); static const struct reg_sequence cs35l56_system_reset_seq[] = { REG_SEQ0(CS35L56_DSP1_HALO_STATE, 0), @@ -327,7 +327,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire) /* Leave in cache-only. This will be revoked when the chip has rebooted. */ } -EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, "SND_SOC_CS35L56_SHARED"); int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) { @@ -346,7 +346,7 @@ int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq) return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED"); irqreturn_t cs35l56_irq(int irq, void *data) { @@ -413,7 +413,7 @@ irqreturn_t cs35l56_irq(int irq, void *data) return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED"); int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) { @@ -444,7 +444,7 @@ int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base) return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_is_fw_reload_needed, "SND_SOC_CS35L56_SHARED"); static const struct reg_sequence cs35l56_hibernate_seq[] = { /* This must be the last register access */ @@ -513,7 +513,7 @@ int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base) return 0; } -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend_common, "SND_SOC_CS35L56_SHARED"); int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire) { @@ -565,7 +565,7 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, "SND_SOC_CS35L56_SHARED"); static const struct cs_dsp_region cs35l56_dsp1_regions[] = { { .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 }, @@ -588,7 +588,7 @@ void cs35l56_init_cs_dsp(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_ds cs_dsp->num_mems = ARRAY_SIZE(cs35l56_dsp1_regions); cs_dsp->no_core_startstop = true; } -EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_init_cs_dsp, "SND_SOC_CS35L56_SHARED"); struct cs35l56_pte { u8 x; @@ -634,7 +634,7 @@ const struct cirrus_amp_cal_controls cs35l56_calibration_controls = { .status = "CAL_STATUS", .checksum = "CAL_CHECKSUM", }; -EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_calibration_controls, "SND_SOC_CS35L56_SHARED"); int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base) { @@ -664,7 +664,7 @@ int cs35l56_get_calibration(struct cs35l56_base *cs35l56_base) return 0; } -EXPORT_SYMBOL_NS_GPL(cs35l56_get_calibration, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_get_calibration, "SND_SOC_CS35L56_SHARED"); int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base, bool *fw_missing, unsigned int *fw_version) @@ -688,7 +688,7 @@ int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base, return 0; } -EXPORT_SYMBOL_NS_GPL(cs35l56_read_prot_status, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_read_prot_status, "SND_SOC_CS35L56_SHARED"); int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) { @@ -774,7 +774,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) return 0; } -EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_hw_init, "SND_SOC_CS35L56_SHARED"); int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base) { @@ -816,7 +816,7 @@ int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base) return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, "SND_SOC_CS35L56_SHARED"); static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = { [0x0C] = 128000, @@ -865,7 +865,7 @@ int cs35l56_get_bclk_freq_id(unsigned int freq) return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(cs35l56_get_bclk_freq_id, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_get_bclk_freq_id, "SND_SOC_CS35L56_SHARED"); static const char * const cs35l56_supplies[/* auto-sized */] = { "VDD_P", @@ -881,7 +881,7 @@ void cs35l56_fill_supply_names(struct regulator_bulk_data *data) for (i = 0; i < ARRAY_SIZE(cs35l56_supplies); i++) data[i].supply = cs35l56_supplies[i]; } -EXPORT_SYMBOL_NS_GPL(cs35l56_fill_supply_names, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_fill_supply_names, "SND_SOC_CS35L56_SHARED"); const char * const cs35l56_tx_input_texts[] = { "None", "ASP1RX1", "ASP1RX2", "VMON", "IMON", "ERRVOL", "CLASSH", @@ -889,7 +889,7 @@ const char * const cs35l56_tx_input_texts[] = { "DSP1TX5", "DSP1TX6", "DSP1TX7", "DSP1TX8", "TEMPMON", "INTERPOLATOR", "SDW1RX1", "SDW1RX2", }; -EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_texts, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_texts, "SND_SOC_CS35L56_SHARED"); const unsigned int cs35l56_tx_input_values[] = { CS35L56_INPUT_SRC_NONE, @@ -914,7 +914,7 @@ const unsigned int cs35l56_tx_input_values[] = { CS35L56_INPUT_SRC_SWIRE_DP1_CHANNEL1, CS35L56_INPUT_SRC_SWIRE_DP1_CHANNEL2, }; -EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, "SND_SOC_CS35L56_SHARED"); const struct regmap_config cs35l56_regmap_i2c = { .reg_bits = 32, @@ -930,7 +930,7 @@ const struct regmap_config cs35l56_regmap_i2c = { .precious_reg = cs35l56_precious_reg, .cache_type = REGCACHE_MAPLE, }; -EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, "SND_SOC_CS35L56_SHARED"); const struct regmap_config cs35l56_regmap_spi = { .reg_bits = 32, @@ -947,7 +947,7 @@ const struct regmap_config cs35l56_regmap_spi = { .precious_reg = cs35l56_precious_reg, .cache_type = REGCACHE_MAPLE, }; -EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, "SND_SOC_CS35L56_SHARED"); const struct regmap_config cs35l56_regmap_sdw = { .reg_bits = 32, @@ -963,10 +963,10 @@ const struct regmap_config cs35l56_regmap_sdw = { .precious_reg = cs35l56_precious_reg, .cache_type = REGCACHE_MAPLE, }; -EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, SND_SOC_CS35L56_SHARED); +EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, "SND_SOC_CS35L56_SHARED"); MODULE_DESCRIPTION("ASoC CS35L56 Shared"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB); +MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c index b07b798b0b45d6..c101134e85328e 100644 --- a/sound/soc/codecs/cs35l56-spi.c +++ b/sound/soc/codecs/cs35l56-spi.c @@ -82,8 +82,8 @@ static struct spi_driver cs35l56_spi_driver = { module_spi_driver(cs35l56_spi_driver); MODULE_DESCRIPTION("ASoC CS35L56 SPI driver"); -MODULE_IMPORT_NS(SND_SOC_CS35L56_CORE); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); +MODULE_IMPORT_NS("SND_SOC_CS35L56_CORE"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 757ade6373ede3..ae045c88c48d27 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1341,7 +1341,7 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56) return ret; } -EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, SND_SOC_CS35L56_CORE); +EXPORT_SYMBOL_NS_GPL(cs35l56_common_probe, "SND_SOC_CS35L56_CORE"); int cs35l56_init(struct cs35l56_private *cs35l56) { @@ -1422,7 +1422,7 @@ int cs35l56_init(struct cs35l56_private *cs35l56) return 0; } -EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_SOC_CS35L56_CORE); +EXPORT_SYMBOL_NS_GPL(cs35l56_init, "SND_SOC_CS35L56_CORE"); void cs35l56_remove(struct cs35l56_private *cs35l56) { @@ -1447,7 +1447,7 @@ void cs35l56_remove(struct cs35l56_private *cs35l56) gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies); } -EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE); +EXPORT_SYMBOL_NS_GPL(cs35l56_remove, "SND_SOC_CS35L56_CORE"); #if IS_ENABLED(CONFIG_SND_SOC_CS35L56_I2C) || IS_ENABLED(CONFIG_SND_SOC_CS35L56_SPI) EXPORT_NS_GPL_DEV_PM_OPS(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE) = { @@ -1459,8 +1459,8 @@ EXPORT_NS_GPL_DEV_PM_OPS(cs35l56_pm_ops_i2c_spi, SND_SOC_CS35L56_CORE) = { #endif MODULE_DESCRIPTION("ASoC CS35L56 driver"); -MODULE_IMPORT_NS(SND_SOC_CS35L56_SHARED); -MODULE_IMPORT_NS(SND_SOC_CS_AMP_LIB); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); +MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c index 8d10f9328e02d0..8a1d5c7a61d7fe 100644 --- a/sound/soc/codecs/cs42l42-i2c.c +++ b/sound/soc/codecs/cs42l42-i2c.c @@ -101,4 +101,4 @@ module_i2c_driver(cs42l42_i2c_driver); MODULE_DESCRIPTION("ASoC CS42L42 I2C driver"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE); +MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE"); diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c index 29891c1f6bece5..ae1401b250a307 100644 --- a/sound/soc/codecs/cs42l42-sdw.c +++ b/sound/soc/codecs/cs42l42-sdw.c @@ -622,4 +622,4 @@ module_sdw_driver(cs42l42_sdw_driver); MODULE_DESCRIPTION("ASoC CS42L42 SoundWire driver"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE); +MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE"); diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 6400ac875e6f6c..501c951cc327c5 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -329,7 +329,7 @@ bool cs42l42_readable_register(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_readable_register, "SND_SOC_CS42L42_CORE"); bool cs42l42_volatile_register(struct device *dev, unsigned int reg) { @@ -363,7 +363,7 @@ bool cs42l42_volatile_register(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_volatile_register, "SND_SOC_CS42L42_CORE"); const struct regmap_range_cfg cs42l42_page_range = { .name = "Pages", @@ -375,7 +375,7 @@ const struct regmap_range_cfg cs42l42_page_range = { .window_start = 0, .window_len = 256, }; -EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_page_range, "SND_SOC_CS42L42_CORE"); const struct regmap_config cs42l42_regmap = { .reg_bits = 8, @@ -395,7 +395,7 @@ const struct regmap_config cs42l42_regmap = { .use_single_read = true, .use_single_write = true, }; -EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_regmap, "SND_SOC_CS42L42_CORE"); static DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 100, true); static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true); @@ -596,7 +596,7 @@ const struct snd_soc_component_driver cs42l42_soc_component = { .num_controls = ARRAY_SIZE(cs42l42_snd_controls), .endianness = 1, }; -EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_soc_component, "SND_SOC_CS42L42_CORE"); /* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */ static const struct reg_sequence cs42l42_to_sclk_seq[] = { @@ -748,7 +748,7 @@ int cs42l42_pll_config(struct snd_soc_component *component, unsigned int clk, return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(cs42l42_pll_config, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_pll_config, "SND_SOC_CS42L42_CORE"); void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample_rate) { @@ -782,7 +782,7 @@ void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample CS42L42_CLK_OASRC_SEL_MASK, fs << CS42L42_CLK_OASRC_SEL_SHIFT); } -EXPORT_SYMBOL_NS_GPL(cs42l42_src_config, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_src_config, "SND_SOC_CS42L42_CORE"); static int cs42l42_asp_config(struct snd_soc_component *component, unsigned int sclk, unsigned int sample_rate) @@ -1116,7 +1116,7 @@ int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) return 0; } -EXPORT_SYMBOL_NS_GPL(cs42l42_mute_stream, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_mute_stream, "SND_SOC_CS42L42_CORE"); #define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S24_LE |\ @@ -1151,7 +1151,7 @@ struct snd_soc_dai_driver cs42l42_dai = { .symmetric_sample_bits = 1, .ops = &cs42l42_ops, }; -EXPORT_SYMBOL_NS_GPL(cs42l42_dai, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_dai, "SND_SOC_CS42L42_CORE"); static void cs42l42_manual_hs_type_detect(struct cs42l42_private *cs42l42) { @@ -1780,7 +1780,7 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE"); static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42) { @@ -2211,7 +2211,7 @@ int cs42l42_suspend(struct device *dev) return 0; } -EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_suspend, "SND_SOC_CS42L42_CORE"); int cs42l42_resume(struct device *dev) { @@ -2242,7 +2242,7 @@ int cs42l42_resume(struct device *dev) return 0; } -EXPORT_SYMBOL_NS_GPL(cs42l42_resume, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_resume, "SND_SOC_CS42L42_CORE"); void cs42l42_resume_restore(struct device *dev) { @@ -2261,7 +2261,7 @@ void cs42l42_resume_restore(struct device *dev) dev_dbg(dev, "System resumed\n"); } -EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_resume_restore, "SND_SOC_CS42L42_CORE"); static int __maybe_unused cs42l42_i2c_resume(struct device *dev) { @@ -2370,7 +2370,7 @@ int cs42l42_common_probe(struct cs42l42_private *cs42l42, return ret; } -EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_common_probe, "SND_SOC_CS42L42_CORE"); int cs42l42_init(struct cs42l42_private *cs42l42) { @@ -2464,7 +2464,7 @@ int cs42l42_init(struct cs42l42_private *cs42l42) cs42l42->supplies); return ret; } -EXPORT_SYMBOL_NS_GPL(cs42l42_init, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_init, "SND_SOC_CS42L42_CORE"); void cs42l42_common_remove(struct cs42l42_private *cs42l42) { @@ -2484,7 +2484,7 @@ void cs42l42_common_remove(struct cs42l42_private *cs42l42) gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies); } -EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, SND_SOC_CS42L42_CORE); +EXPORT_SYMBOL_NS_GPL(cs42l42_common_remove, "SND_SOC_CS42L42_CORE"); MODULE_DESCRIPTION("ASoC CS42L42 driver"); MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, "); diff --git a/sound/soc/codecs/cs42l43-sdw.c b/sound/soc/codecs/cs42l43-sdw.c index 60c00c05da055c..336e88a7a987ce 100644 --- a/sound/soc/codecs/cs42l43-sdw.c +++ b/sound/soc/codecs/cs42l43-sdw.c @@ -42,7 +42,7 @@ int cs42l43_sdw_add_peripheral(struct snd_pcm_substream *substream, return 0; } -EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_add_peripheral, SND_SOC_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_add_peripheral, "SND_SOC_CS42L43"); int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) @@ -56,7 +56,7 @@ int cs42l43_sdw_remove_peripheral(struct snd_pcm_substream *substream, return sdw_stream_remove_slave(sdw, sdw_stream); } -EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_remove_peripheral, SND_SOC_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_remove_peripheral, "SND_SOC_CS42L43"); int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction) { @@ -64,7 +64,7 @@ int cs42l43_sdw_set_stream(struct snd_soc_dai *dai, void *sdw_stream, int direct return 0; } -EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_set_stream, SND_SOC_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_sdw_set_stream, "SND_SOC_CS42L43"); MODULE_DESCRIPTION("CS42L43 CODEC SoundWire Driver"); MODULE_AUTHOR("Charles Keepax "); diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index d0098b4558b529..4236f78beec069 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -2402,49 +2402,7 @@ static int cs42l43_codec_runtime_resume(struct device *dev) return 0; } -static int cs42l43_codec_suspend(struct device *dev) -{ - struct cs42l43_codec *priv = dev_get_drvdata(dev); - struct cs42l43 *cs42l43 = priv->core; - - disable_irq(cs42l43->irq); - - return 0; -} - -static int cs42l43_codec_suspend_noirq(struct device *dev) -{ - struct cs42l43_codec *priv = dev_get_drvdata(dev); - struct cs42l43 *cs42l43 = priv->core; - - enable_irq(cs42l43->irq); - - return 0; -} - -static int cs42l43_codec_resume(struct device *dev) -{ - struct cs42l43_codec *priv = dev_get_drvdata(dev); - struct cs42l43 *cs42l43 = priv->core; - - enable_irq(cs42l43->irq); - - return 0; -} - -static int cs42l43_codec_resume_noirq(struct device *dev) -{ - struct cs42l43_codec *priv = dev_get_drvdata(dev); - struct cs42l43 *cs42l43 = priv->core; - - disable_irq(cs42l43->irq); - - return 0; -} - static const struct dev_pm_ops cs42l43_codec_pm_ops = { - SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend, cs42l43_codec_resume) - NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_codec_suspend_noirq, cs42l43_codec_resume_noirq) RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL) }; @@ -2466,7 +2424,7 @@ static struct platform_driver cs42l43_codec_driver = { }; module_platform_driver(cs42l43_codec_driver); -MODULE_IMPORT_NS(SND_SOC_CS42L43); +MODULE_IMPORT_NS("SND_SOC_CS42L43"); MODULE_DESCRIPTION("CS42L43 CODEC Driver"); MODULE_AUTHOR("Charles Keepax "); diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c index f482b6a4f5c3a3..42c3e1efdc0867 100644 --- a/sound/soc/codecs/cs42l83-i2c.c +++ b/sound/soc/codecs/cs42l83-i2c.c @@ -237,4 +237,4 @@ module_i2c_driver(cs42l83_i2c_driver); MODULE_DESCRIPTION("ASoC CS42L83 I2C driver"); MODULE_AUTHOR("Martin Povišer "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_CS42L42_CORE); +MODULE_IMPORT_NS("SND_SOC_CS42L42_CORE"); diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c new file mode 100644 index 00000000000000..17d5c96e334d0b --- /dev/null +++ b/sound/soc/codecs/cs42l84.c @@ -0,0 +1,1111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * cs42l84.c -- CS42L84 ALSA SoC audio driver + * + * Copyright (C) The Asahi Linux Contributors + * + * Based on sound/soc/codecs/cs42l42{.c,.h} + * Copyright 2016 Cirrus Logic, 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 +#include + +#include "cs42l84.h" +#include "cirrus_legacy.h" + +struct cs42l84_private { + struct regmap *regmap; + struct device *dev; + struct gpio_desc *reset_gpio; + struct snd_soc_jack *jack; + struct mutex irq_lock; + u8 tip_state; + u8 ring_state; + int pll_config; + int bclk; + u8 pll_mclk_f; + u32 srate; + u8 stream_use; + int hs_type; +}; + +static bool cs42l84_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L84_DEVID ... CS42L84_DEVID+5: + case CS42L84_TSRS_PLUG_INT_STATUS: + case CS42L84_PLL_LOCK_STATUS: + case CS42L84_TSRS_PLUG_STATUS: + case CS42L84_HS_DET_STATUS2: + return true; + default: + return false; + } +} + +static const struct regmap_config cs42l84_regmap = { + .reg_bits = 16, + .val_bits = 8, + + .volatile_reg = cs42l84_volatile_register, + + .max_register = 0x73fe, + + .cache_type = REGCACHE_MAPLE, + + .use_single_read = true, + .use_single_write = true, +}; + +static int cs42l84_put_dac_vol(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *val) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kctl); + struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value; + int vola, volb; + int ret, ret2, updated = 0; + + vola = val->value.integer.value[0] + mc->min; + volb = val->value.integer.value[1] + mc->min; + + if (vola < mc->min || vola > mc->max || volb < mc->min || volb > mc->max) + return -EINVAL; + + ret = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL, + CS42L84_FRZ_CTL_ENGAGE, + CS42L84_FRZ_CTL_ENGAGE); + if (ret < 0) + goto bail; + updated |= ret; + + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_LSB, + 0xff, vola & 0xff); + if (ret < 0) + goto bail; + updated |= ret; + + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHA_VOL_MSB, + 0xff, (vola >> 8) & 0x01); + if (ret < 0) + goto bail; + updated |= ret; + + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_LSB, + 0xff, volb & 0xff); + if (ret < 0) + goto bail; + updated |= ret; + + ret = snd_soc_component_update_bits(component, CS42L84_DAC_CHB_VOL_MSB, + 0xff, (volb >> 8) & 0x01); + if (ret < 0) + goto bail; + ret |= updated; + +bail: + ret2 = snd_soc_component_update_bits(component, CS42L84_FRZ_CTL, + CS42L84_FRZ_CTL_ENGAGE, 0); + if (ret2 < 0 && ret >= 0) + ret = ret2; + + return ret; +} + +static int cs42l84_get_dac_vol(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *val) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kctl); + struct soc_mixer_control *mc = (struct soc_mixer_control *) kctl->private_value; + int vola, volb; + int ret; + + ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_LSB); + if (ret < 0) + return ret; + vola = ret; + + ret = snd_soc_component_read(component, CS42L84_DAC_CHA_VOL_MSB); + if (ret < 0) + return ret; + vola |= (ret & 1) << 8; + + ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_LSB); + if (ret < 0) + return ret; + volb = ret; + + ret = snd_soc_component_read(component, CS42L84_DAC_CHB_VOL_MSB); + if (ret < 0) + return ret; + volb |= (ret & 1) << 8; + + if (vola & BIT(8)) + vola |= ~((int)(BIT(8) - 1)); + if (volb & BIT(8)) + volb |= ~((int)(BIT(8) - 1)); + + val->value.integer.value[0] = vola - mc->min; + val->value.integer.value[1] = volb - mc->min; + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(cs42l84_dac_tlv, -12800, 50, true); +static const DECLARE_TLV_DB_SCALE(cs42l84_adc_tlv, -1200, 50, false); +static const DECLARE_TLV_DB_SCALE(cs42l84_pre_tlv, 0, 1000, false); + +static const struct snd_kcontrol_new cs42l84_snd_controls[] = { + SOC_DOUBLE_R_S_EXT_TLV("DAC Playback Volume", CS42L84_DAC_CHA_VOL_LSB, + CS42L84_DAC_CHB_VOL_LSB, 0, -256, 24, 8, 0, + cs42l84_get_dac_vol, cs42l84_put_dac_vol, cs42l84_dac_tlv), + SOC_SINGLE_TLV("ADC Preamp Capture Volume", CS42L84_ADC_CTL1, + CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT, 2, 0, cs42l84_pre_tlv), + SOC_SINGLE_TLV("ADC PGA Capture Volume", CS42L84_ADC_CTL1, + CS42L84_ADC_CTL1_PGA_GAIN_SHIFT, 24, 0, cs42l84_adc_tlv), + SOC_SINGLE("ADC WNF Switch", CS42L84_ADC_CTL4, + CS42L84_ADC_CTL4_WNF_EN_SHIFT, 1, 0), + SOC_SINGLE("WNF Corner Frequency", CS42L84_ADC_CTL4, + CS42L84_ADC_CTL4_WNF_CF_SHIFT, 3, 0), + SOC_SINGLE("ADC HPF Switch", CS42L84_ADC_CTL4, + CS42L84_ADC_CTL4_HPF_EN_SHIFT, 1, 0), + SOC_SINGLE("HPF Corner Frequency", CS42L84_ADC_CTL4, + CS42L84_ADC_CTL4_HPF_CF_SHIFT, 3, 0), +}; + +static const char * const cs42l84_mux_text[] = { + "Blank", "ADC", "ASP RX CH1", "ASP RX CH2", +}; + +static const unsigned int cs42l84_mux_values[] = { + 0b0000, 0b0111, 0b1101, 0b1110, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_daca_mux_enum, + CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACA_SHIFT, + 0b1111, cs42l84_mux_text, cs42l84_mux_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_dacb_mux_enum, + CS42L84_BUS_DAC_SRC, CS42L84_BUS_DAC_SRC_DACB_SHIFT, + 0b1111, cs42l84_mux_text, cs42l84_mux_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs42l84_sdout1_mux_enum, + CS42L84_BUS_ASP_TX_SRC, CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT, + 0b1111, cs42l84_mux_text, cs42l84_mux_values); + +static const struct snd_kcontrol_new cs42l84_daca_mux_ctrl = + SOC_DAPM_ENUM("DACA Select", cs42l84_daca_mux_enum); + +static const struct snd_kcontrol_new cs42l84_dacb_mux_ctrl = + SOC_DAPM_ENUM("DACB Select", cs42l84_dacb_mux_enum); + +static const struct snd_kcontrol_new cs42l84_sdout1_mux_ctrl = + SOC_DAPM_ENUM("SDOUT1 Select", cs42l84_sdout1_mux_enum); + +static const struct snd_soc_dapm_widget cs42l84_dapm_widgets[] = { + /* Playback Path */ + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_DAC("DAC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_DAC_SHIFT, 0), + SND_SOC_DAPM_MUX("DACA Select", SND_SOC_NOPM, 0, 0, &cs42l84_daca_mux_ctrl), + SND_SOC_DAPM_MUX("DACB Select", SND_SOC_NOPM, 0, 0, &cs42l84_dacb_mux_ctrl), + SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH1_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L84_ASP_RX_EN, CS42L84_ASP_RX_EN_CH2_SHIFT, 0), + + /* Capture Path */ + SND_SOC_DAPM_INPUT("HS"), + SND_SOC_DAPM_ADC("ADC", NULL, CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ADC_SHIFT, 0), + SND_SOC_DAPM_MUX("SDOUT1 Select", SND_SOC_NOPM, 0, 0, &cs42l84_sdout1_mux_ctrl), + SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L84_ASP_TX_EN, CS42L84_ASP_TX_EN_CH1_SHIFT, 0), + + /* Playback/Capture Requirements */ + SND_SOC_DAPM_SUPPLY("BUS", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_BUS_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASP", CS42L84_MSM_BLOCK_EN2, CS42L84_MSM_BLOCK_EN2_ASP_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BCLK", CS42L84_ASP_CTL, CS42L84_ASP_CTL_BCLK_EN_SHIFT, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route cs42l84_audio_map[] = { + /* Playback Path */ + {"HP", NULL, "DAC"}, + {"DAC", NULL, "DACA Select"}, + {"DAC", NULL, "DACB Select"}, + {"DACA Select", "ASP RX CH1", "SDIN1"}, + {"DACA Select", "ASP RX CH2", "SDIN2"}, + {"DACB Select", "ASP RX CH1", "SDIN1"}, + {"DACB Select", "ASP RX CH2", "SDIN2"}, + {"SDIN1", NULL, "Playback"}, + {"SDIN2", NULL, "Playback"}, + + {"ADC", NULL, "HS"}, + {"SDOUT1 Select", "ADC", "ADC"}, + {"SDOUT1", NULL, "SDOUT1 Select"}, + {"Capture", NULL, "SDOUT1"}, + + /* Playback Requirements */ + {"DAC", NULL, "BUS"}, + {"SDIN1", NULL, "ASP"}, + {"SDIN2", NULL, "ASP"}, + {"SDIN1", NULL, "BCLK"}, + {"SDIN2", NULL, "BCLK"}, + + /* Capture Requirements */ + {"SDOUT1", NULL, "BUS"}, + {"SDOUT1", NULL, "ASP"}, + {"SDOUT1", NULL, "BCLK"}, +}; + +static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jk, void *d) +{ + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + + /* Prevent race with interrupt handler */ + mutex_lock(&cs42l84->irq_lock); + cs42l84->jack = jk; + snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET); + mutex_unlock(&cs42l84->irq_lock); + + return 0; +} + +static int cs42l84_component_probe(struct snd_soc_component *component) +{ + snd_soc_component_update_bits(component, CS42L84_ASP_CTL, + CS42L84_ASP_CTL_TDM_MODE, 0); + snd_soc_component_update_bits(component, CS42L84_HP_VOL_CTL, + CS42L84_HP_VOL_CTL_SOFT | CS42L84_HP_VOL_CTL_ZERO_CROSS, + CS42L84_HP_VOL_CTL_ZERO_CROSS); + + /* TDM settings */ + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL1, + CS42L84_ASP_RX_CHx_CTL1_EDGE | + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH1_CTL2, + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL1, + CS42L84_ASP_RX_CHx_CTL1_EDGE | + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, + CS42L84_ASP_RX_CHx_CTL1_EDGE); + snd_soc_component_update_bits(component, CS42L84_ASP_RX_CH2_CTL2, + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL1, + CS42L84_ASP_RX_CHx_CTL1_EDGE | \ + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH1_CTL2, + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL1, + CS42L84_ASP_RX_CHx_CTL1_EDGE | \ + CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB, + CS42L84_ASP_RX_CHx_CTL1_EDGE); + snd_soc_component_update_bits(component, CS42L84_ASP_TX_CH2_CTL2, + CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB, 0); + /* Routing defaults */ + snd_soc_component_write(component, CS42L84_BUS_DAC_SRC, + 0b1101 << CS42L84_BUS_DAC_SRC_DACA_SHIFT | + 0b1110 << CS42L84_BUS_DAC_SRC_DACB_SHIFT); + snd_soc_component_write(component, CS42L84_BUS_ASP_TX_SRC, + 0b0111 << CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_cs42l84 = { + .set_jack = cs42l84_set_jack, + .probe = cs42l84_component_probe, + .controls = cs42l84_snd_controls, + .num_controls = ARRAY_SIZE(cs42l84_snd_controls), + .dapm_widgets = cs42l84_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l84_dapm_widgets), + .dapm_routes = cs42l84_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs42l84_audio_map), + .endianness = 1, +}; + +struct cs42l84_pll_params { + u32 bclk; + u8 mclk_src_sel; + u8 bclk_prediv; + u8 pll_div_int; + u32 pll_div_frac; + u8 pll_mode; + u8 pll_divout; + u32 mclk_int; +}; + +/* + * Common PLL Settings for given BCLK + */ +static const struct cs42l84_pll_params pll_ratio_table[] = { + { 3072000, 1, 0, 0x40, 0x000000, 0x03, 0x10, 12288000}, + { 6144000, 1, 1, 0x40, 0x000000, 0x03, 0x10, 12288000}, + { 12288000, 0, 0, 0, 0, 0, 0, 12288000}, + { 24576000, 1, 3, 0x40, 0x000000, 0x03, 0x10, 12288000}, +}; + +static int cs42l84_pll_config(struct snd_soc_component *component) +{ + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + int i; + u32 clk; + u32 fsync; + + clk = cs42l84->bclk; + + /* Don't reconfigure if there is an audio stream running */ + if (cs42l84->stream_use) { + if (pll_ratio_table[cs42l84->pll_config].bclk == clk) + return 0; + else + return -EBUSY; + } + + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { + if (pll_ratio_table[i].bclk == clk) { + cs42l84->pll_config = i; + break; + } + } + + if (i == ARRAY_SIZE(pll_ratio_table)) + return -EINVAL; + + /* Set up the LRCLK */ + fsync = clk / cs42l84->srate; + if (((fsync * cs42l84->srate) != clk) + || ((fsync % 2) != 0)) { + dev_err(component->dev, + "Unsupported bclk %d/sample rate %d\n", + clk, cs42l84->srate); + return -EINVAL; + } + + /* Set the LRCLK period */ + snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL2, + CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO, + FIELD_PREP(CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO, fsync & 0x7f)); + snd_soc_component_update_bits(component, CS42L84_ASP_FSYNC_CTL3, + CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, + FIELD_PREP(CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI, fsync >> 7)); + + /* Save what the MCLK will be */ + switch (pll_ratio_table[i].mclk_int) { + case 12000000: + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12MHZ; + break; + case 12288000: + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_12_288KHZ; + break; + case 24000000: + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24MHZ; + break; + case 24576000: + cs42l84->pll_mclk_f = CS42L84_CCM_CTL1_MCLK_F_24_576KHZ; + break; + } + + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_EN, 0); + + if (pll_ratio_table[i].mclk_src_sel) { + /* Configure PLL */ + snd_soc_component_update_bits(component, + CS42L84_CCM_CTL3, CS42L84_CCM_CTL3_REFCLK_DIV, + FIELD_PREP(CS42L84_CCM_CTL3_REFCLK_DIV, pll_ratio_table[i].bclk_prediv)); + snd_soc_component_write(component, + CS42L84_PLL_DIV_INT, + pll_ratio_table[i].pll_div_int); + snd_soc_component_write(component, + CS42L84_PLL_DIV_FRAC0, + pll_ratio_table[i].pll_div_frac); + snd_soc_component_write(component, + CS42L84_PLL_DIV_FRAC1, + pll_ratio_table[i].pll_div_frac >> 8); + snd_soc_component_write(component, + CS42L84_PLL_DIV_FRAC2, + pll_ratio_table[i].pll_div_frac >> 16); + snd_soc_component_update_bits(component, + CS42L84_PLL_CTL1, CS42L84_PLL_CTL1_MODE, + FIELD_PREP(CS42L84_PLL_CTL1_MODE, pll_ratio_table[i].pll_mode)); + snd_soc_component_write(component, + CS42L84_PLL_DIVOUT, + pll_ratio_table[i].pll_divout); + } + + return 0; +} + +static int cs42l84_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + default: + return -EINVAL; + } + + /* Bitclock/frame inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs42l84_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + int ret; + u32 ccm_samp_rate; + + cs42l84->srate = params_rate(params); + + ret = cs42l84_pll_config(component); + if (ret) + return ret; + + switch (params_rate(params)) { + case 44100: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_44K1HZ; + break; + case 48000: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_48KHZ; + break; + case 88200: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_88K2HZ; + break; + case 96000: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_96KHZ; + break; + case 176400: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_176K4HZ; + break; + case 192000: + ccm_samp_rate = CS42L84_CCM_SAMP_RATE_RATE_192KHZ; + break; + default: + return -EINVAL; + } + + snd_soc_component_write(component, CS42L84_CCM_SAMP_RATE, ccm_samp_rate); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + snd_soc_component_write(component, CS42L84_ASP_RX_CH1_WIDTH, + params_width(params) - 1); + snd_soc_component_write(component, CS42L84_ASP_RX_CH2_WIDTH, + params_width(params) - 1); + break; + + case SNDRV_PCM_STREAM_CAPTURE: + snd_soc_component_write(component, CS42L84_ASP_TX_CH1_WIDTH, + params_width(params) - 1); + snd_soc_component_write(component, CS42L84_ASP_TX_CH2_WIDTH, + params_width(params) - 1); + break; + } + + return 0; +} + +static int cs42l84_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + int i; + + if (freq == 0) { + cs42l84->bclk = 0; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { + if (pll_ratio_table[i].bclk == freq) { + cs42l84->bclk = freq; + return 0; + } + } + + dev_err(component->dev, "BCLK %u not supported\n", freq); + + return -EINVAL; +} + +static int cs42l84_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component); + unsigned int regval; + int ret; + + if (mute) { + /* Mute the headphone */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_component_update_bits(component, CS42L84_DAC_CTL1, + CS42L84_DAC_CTL1_UNMUTE, 0); + cs42l84->stream_use &= ~(1 << stream); + if (!cs42l84->stream_use) { + /* Must disconnect PLL before stopping it */ + snd_soc_component_write(component, CS42L84_CCM_CTL1, + CS42L84_CCM_CTL1_RCO); + + usleep_range(150, 300); + + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, + CS42L84_PLL_CTL1_EN, 0); + + snd_soc_component_update_bits(component, CS42L84_CCM_CTL4, + CS42L84_CCM_CTL4_REFCLK_EN, 0); + } + } else { + if (!cs42l84->stream_use) { + /* SCLK must be running before codec unmute. + * + * Note carried over from CS42L42: + * + * PLL must not be started with ADC and HP both off + * otherwise the FILT+ supply will not charge properly. + * DAPM widgets power-up before stream unmute so at least + * one of the "DAC" or "ADC" widgets will already have + * powered-up. + */ + + snd_soc_component_update_bits(component, CS42L84_CCM_CTL4, + CS42L84_CCM_CTL4_REFCLK_EN, + CS42L84_CCM_CTL4_REFCLK_EN); + + if (pll_ratio_table[cs42l84->pll_config].mclk_src_sel) { + snd_soc_component_update_bits(component, CS42L84_PLL_CTL1, + CS42L84_PLL_CTL1_EN, + CS42L84_PLL_CTL1_EN); + /* TODO: should we be doing something with divout here? */ + + ret = regmap_read_poll_timeout(cs42l84->regmap, + CS42L84_PLL_LOCK_STATUS, + regval, + (regval & CS42L84_PLL_LOCK_STATUS_LOCKED), + CS42L84_PLL_LOCK_POLL_US, + CS42L84_PLL_LOCK_TIMEOUT_US); + if (ret < 0) + dev_warn(component->dev, "PLL failed to lock: %d\n", ret); + + if (regval & CS42L84_PLL_LOCK_STATUS_ERROR) + dev_warn(component->dev, "PLL lock error\n"); + + /* PLL must be running to drive glitchless switch logic */ + snd_soc_component_update_bits(component, + CS42L84_CCM_CTL1, + CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ, + FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_PLL) + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f)); + usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2); + } else { + snd_soc_component_update_bits(component, + CS42L84_CCM_CTL1, + CS42L84_CCM_CTL1_MCLK_SRC | CS42L84_CCM_CTL1_MCLK_FREQ, + FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_BCLK) + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, cs42l84->pll_mclk_f)); + usleep_range(CS42L84_CLOCK_SWITCH_DELAY_US, CS42L84_CLOCK_SWITCH_DELAY_US*2); + } + } + cs42l84->stream_use |= 1 << stream; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + /* Un-mute the headphone */ + snd_soc_component_update_bits(component, CS42L84_DAC_CTL1, + CS42L84_DAC_CTL1_UNMUTE, + CS42L84_DAC_CTL1_UNMUTE); + } + + return 0; +} + +static const struct snd_soc_dai_ops cs42l84_ops = { + .hw_params = cs42l84_pcm_hw_params, + .set_fmt = cs42l84_set_dai_fmt, + .set_sysclk = cs42l84_set_sysclk, + .mute_stream = cs42l84_mute_stream, +}; + +#define CS42L84_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver cs42l84_dai = { + .name = "cs42l84", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, + .formats = CS42L84_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, + .formats = CS42L84_FORMATS, + }, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, + .ops = &cs42l84_ops, +}; + +struct cs42l84_irq_params { + u16 status_addr; + u16 mask_addr; + u8 mask; +}; + +static const struct cs42l84_irq_params irq_params_table[] = { + {CS42L84_TSRS_PLUG_INT_STATUS, CS42L84_TSRS_PLUG_INT_MASK, + CS42L84_TSRS_PLUG_VAL_MASK} +}; + +static void cs42l84_detect_hs(struct cs42l84_private *cs42l84) +{ + unsigned int reg; + + /* Power up HSBIAS */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE, + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 3) | /* 2.7 V */ + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0)); + + /* Power up level detection circuitry */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET, 0); + + /* TODO: Optimize */ + msleep(50); + + /* Connect HSBIAS in CTIA wiring */ + /* TODO: Should likely be subject of detection */ + regmap_write(cs42l84->regmap, + CS42L84_HS_SWITCH_CTL, + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ + CS42L84_HS_SWITCH_CTL_HSB_HS4); + regmap_update_bits(cs42l84->regmap, + CS42L84_HS_DET_CTL2, + CS42L84_HS_DET_CTL2_SET, + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 0)); + + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_DETECT_MODE, + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 3)); + + /* TODO: Optimize */ + msleep(50); + + regmap_read(cs42l84->regmap, CS42L84_HS_DET_STATUS2, ®); + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET, + CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET); + + switch (reg & 0b11) { + case 0b11: /* shorted */ + case 0b00: /* open */ + /* Power down HSBIAS */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_HSBIAS_CTL, + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1)); /* 0.0 V */ + break; + } + + switch (reg & 0b11) { + case 0b10: /* load */ + dev_dbg(cs42l84->dev, "Detected mic\n"); + cs42l84->hs_type = SND_JACK_HEADSET; + snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADSET, + SND_JACK_HEADSET); + break; + + case 0b00: /* open */ + dev_dbg(cs42l84->dev, "Detected open circuit on HS4\n"); + fallthrough; + case 0b11: /* shorted */ + default: + snd_soc_jack_report(cs42l84->jack, SND_JACK_HEADPHONE, + SND_JACK_HEADSET); + cs42l84->hs_type = SND_JACK_HEADPHONE; + dev_dbg(cs42l84->dev, "Detected bare headphone (no mic)\n"); + break; + } +} + +static void cs42l84_revert_hs(struct cs42l84_private *cs42l84) +{ + /* Power down HSBIAS */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MISC_DET_CTL, + CS42L84_MISC_DET_CTL_HSBIAS_CTL | CS42L84_MISC_DET_CTL_DETECT_MODE, + FIELD_PREP(CS42L84_MISC_DET_CTL_HSBIAS_CTL, 1) | /* 0.0 V */ + FIELD_PREP(CS42L84_MISC_DET_CTL_DETECT_MODE, 0)); + + /* Disconnect HSBIAS */ + regmap_write(cs42l84->regmap, + CS42L84_HS_SWITCH_CTL, + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ + CS42L84_HS_SWITCH_CTL_REF_HS4 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS4); + regmap_update_bits(cs42l84->regmap, + CS42L84_HS_DET_CTL2, + CS42L84_HS_DET_CTL2_SET, + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2)); +} + +static void cs42l84_set_interrupt_masks(struct cs42l84_private *cs42l84, + unsigned int val) +{ + regmap_update_bits(cs42l84->regmap, CS42L84_TSRS_PLUG_INT_MASK, + CS42L84_RS_PLUG | CS42L84_RS_UNPLUG | + CS42L84_TS_PLUG | CS42L84_TS_UNPLUG, + val); +} + +static irqreturn_t cs42l84_irq_thread(int irq, void *data) +{ + struct cs42l84_private *cs42l84 = (struct cs42l84_private *)data; + unsigned int stickies[1]; + unsigned int masks[1]; + unsigned int reg; + u8 current_tip_state; + u8 current_ring_state; + int i; + + mutex_lock(&cs42l84->irq_lock); + /* Read sticky registers to clear interrupt */ + for (i = 0; i < ARRAY_SIZE(stickies); i++) { + regmap_read(cs42l84->regmap, irq_params_table[i].status_addr, + &(stickies[i])); + regmap_read(cs42l84->regmap, irq_params_table[i].mask_addr, + &(masks[i])); + stickies[i] = stickies[i] & (~masks[i]) & + irq_params_table[i].mask; + } + + /* When handling plug sene IRQs, we only care about EITHER tip OR ring. + * Ring is useless on remove, and is only useful on insert for + * detecting if the plug state has changed AFTER we have handled the + * tip sense IRQ, e.g. if the plug was not fully seated within the tip + * sense debounce time. + */ + + if ((~masks[0]) & irq_params_table[0].mask) { + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®); + + current_tip_state = (((char) reg) & + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> + CS42L84_TS_PLUG_SHIFT; + + if (current_tip_state != cs42l84->tip_state) { + cs42l84->tip_state = current_tip_state; + switch (current_tip_state) { + case CS42L84_PLUG: + dev_dbg(cs42l84->dev, "Plug event\n"); + + cs42l84_detect_hs(cs42l84); + + /* + * Check the tip sense status again, and possibly invalidate + * the detection result + * + * Thanks to debounce, this should reliably indicate if the tip + * was disconnected at any point during the detection procedure. + */ + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®); + current_tip_state = (((char) reg) & + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> + CS42L84_TS_PLUG_SHIFT; + if (current_tip_state != CS42L84_PLUG) { + dev_dbg(cs42l84->dev, "Wobbly connection, detection invalidated\n"); + cs42l84->tip_state = CS42L84_UNPLUG; + cs42l84_revert_hs(cs42l84); + } + + /* Unmask ring sense interrupts */ + cs42l84_set_interrupt_masks(cs42l84, 0); + break; + case CS42L84_UNPLUG: + cs42l84->ring_state = CS42L84_UNPLUG; + dev_dbg(cs42l84->dev, "Unplug event\n"); + + cs42l84_revert_hs(cs42l84); + cs42l84->hs_type = 0; + snd_soc_jack_report(cs42l84->jack, 0, + SND_JACK_HEADSET); + + /* Mask ring sense interrupts */ + cs42l84_set_interrupt_masks(cs42l84, + CS42L84_RS_PLUG | CS42L84_RS_UNPLUG); + break; + default: + cs42l84->ring_state = CS42L84_TRANS; + break; + } + + mutex_unlock(&cs42l84->irq_lock); + + return IRQ_HANDLED; + } + + /* Tip state didn't change, we must've got a ring sense IRQ */ + current_ring_state = (((char) reg) & + (CS42L84_RS_PLUG | CS42L84_RS_UNPLUG)) >> + CS42L84_RS_PLUG_SHIFT; + + if (current_ring_state != cs42l84->ring_state) { + cs42l84->ring_state = current_ring_state; + if (current_ring_state == CS42L84_PLUG) + cs42l84_detect_hs(cs42l84); + } + } + + mutex_unlock(&cs42l84->irq_lock); + + return IRQ_HANDLED; +} + +static void cs42l84_setup_plug_detect(struct cs42l84_private *cs42l84) +{ + unsigned int reg; + + /* Set up plug detection */ + regmap_update_bits(cs42l84->regmap, CS42L84_MIC_DET_CTL4, + CS42L84_MIC_DET_CTL4_LATCH_TO_VP, + CS42L84_MIC_DET_CTL4_LATCH_TO_VP); + regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL2, + CS42L84_TIP_SENSE_CTL2_MODE, + FIELD_PREP(CS42L84_TIP_SENSE_CTL2_MODE, CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET)); + regmap_update_bits(cs42l84->regmap, CS42L84_RING_SENSE_CTL, + CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 | + CS42L84_RING_SENSE_CTL_RISETIME | CS42L84_RING_SENSE_CTL_FALLTIME, + CS42L84_RING_SENSE_CTL_INV | CS42L84_RING_SENSE_CTL_UNK1 | + FIELD_PREP(CS42L84_RING_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_125MS) | + FIELD_PREP(CS42L84_RING_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS)); + regmap_update_bits(cs42l84->regmap, CS42L84_TIP_SENSE_CTL, + CS42L84_TIP_SENSE_CTL_INV | + CS42L84_TIP_SENSE_CTL_RISETIME | CS42L84_TIP_SENSE_CTL_FALLTIME, + CS42L84_TIP_SENSE_CTL_INV | + FIELD_PREP(CS42L84_TIP_SENSE_CTL_RISETIME, CS42L84_DEBOUNCE_TIME_500MS) | + FIELD_PREP(CS42L84_TIP_SENSE_CTL_FALLTIME, CS42L84_DEBOUNCE_TIME_125MS)); + regmap_update_bits(cs42l84->regmap, CS42L84_MSM_BLOCK_EN3, + CS42L84_MSM_BLOCK_EN3_TR_SENSE, + CS42L84_MSM_BLOCK_EN3_TR_SENSE); + + /* Save the initial status of the tip sense */ + regmap_read(cs42l84->regmap, CS42L84_TSRS_PLUG_STATUS, ®); + cs42l84->tip_state = (((char) reg) & + (CS42L84_TS_PLUG | CS42L84_TS_UNPLUG)) >> + CS42L84_TS_PLUG_SHIFT; + + /* Set mic-detection threshold */ + regmap_update_bits(cs42l84->regmap, + CS42L84_MIC_DET_CTL1, CS42L84_MIC_DET_CTL1_HS_DET_LEVEL, + FIELD_PREP(CS42L84_MIC_DET_CTL1_HS_DET_LEVEL, 0x2c)); /* ~1.9 V */ + + /* Disconnect HSBIAS (initially) */ + regmap_write(cs42l84->regmap, + CS42L84_HS_SWITCH_CTL, + CS42L84_HS_SWITCH_CTL_REF_HS3 | \ + CS42L84_HS_SWITCH_CTL_REF_HS4 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 | \ + CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS3 | \ + CS42L84_HS_SWITCH_CTL_GNDHS_HS4); + regmap_update_bits(cs42l84->regmap, + CS42L84_HS_DET_CTL2, + CS42L84_HS_DET_CTL2_SET | CS42L84_HS_DET_CTL2_CTL, + FIELD_PREP(CS42L84_HS_DET_CTL2_SET, 2) | + FIELD_PREP(CS42L84_HS_DET_CTL2_CTL, 0)); + regmap_update_bits(cs42l84->regmap, + CS42L84_HS_CLAMP_DISABLE, 1, 1); + +} + +static int cs42l84_i2c_probe(struct i2c_client *i2c_client) +{ + struct cs42l84_private *cs42l84; + int ret, devid; + unsigned int reg; + + cs42l84 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l84_private), + GFP_KERNEL); + if (!cs42l84) + return -ENOMEM; + + cs42l84->dev = &i2c_client->dev; + i2c_set_clientdata(i2c_client, cs42l84); + mutex_init(&cs42l84->irq_lock); + + cs42l84->regmap = devm_regmap_init_i2c(i2c_client, &cs42l84_regmap); + if (IS_ERR(cs42l84->regmap)) { + ret = PTR_ERR(cs42l84->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + /* Reset the Device */ + cs42l84->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs42l84->reset_gpio)) { + ret = PTR_ERR(cs42l84->reset_gpio); + goto err_disable_noreset; + } + + if (cs42l84->reset_gpio) { + dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); + gpiod_set_value_cansleep(cs42l84->reset_gpio, 1); + } + usleep_range(CS42L84_BOOT_TIME_US, CS42L84_BOOT_TIME_US * 2); + + /* Request IRQ if one was specified */ + if (i2c_client->irq) { + ret = request_threaded_irq(i2c_client->irq, + NULL, cs42l84_irq_thread, + IRQF_ONESHOT, + "cs42l84", cs42l84); + if (ret == -EPROBE_DEFER) { + goto err_disable_noirq; + } else if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request IRQ: %d\n", ret); + goto err_disable_noirq; + } + } + + /* initialize codec */ + devid = cirrus_read_device_id(cs42l84->regmap, CS42L84_DEVID); + if (devid < 0) { + ret = devid; + dev_err(&i2c_client->dev, "Failed to read device ID: %d\n", ret); + goto err_disable; + } + + if (devid != CS42L84_CHIP_ID) { + dev_err(&i2c_client->dev, + "CS42L84 Device ID (%X). Expected %X\n", + devid, CS42L84_CHIP_ID); + ret = -EINVAL; + goto err_disable; + } + + ret = regmap_read(cs42l84->regmap, CS42L84_REVID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + goto err_shutdown; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS42L84, Revision: %02X\n", reg & 0xFF); + + /* Setup plug detection */ + cs42l84_setup_plug_detect(cs42l84); + + /* Mask ring sense interrupts */ + cs42l84_set_interrupt_masks(cs42l84, CS42L84_RS_PLUG | CS42L84_RS_UNPLUG); + + /* Register codec for machine driver */ + ret = devm_snd_soc_register_component(&i2c_client->dev, + &soc_component_dev_cs42l84, &cs42l84_dai, 1); + if (ret < 0) + goto err_shutdown; + + return 0; + +err_shutdown: + /* Nothing to do */ + +err_disable: + if (i2c_client->irq) + free_irq(i2c_client->irq, cs42l84); + +err_disable_noirq: + gpiod_set_value_cansleep(cs42l84->reset_gpio, 0); +err_disable_noreset: + return ret; +} + +static void cs42l84_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l84_private *cs42l84 = i2c_get_clientdata(i2c_client); + + if (i2c_client->irq) + free_irq(i2c_client->irq, cs42l84); + + gpiod_set_value_cansleep(cs42l84->reset_gpio, 0); +} + +static const struct of_device_id cs42l84_of_match[] = { + { .compatible = "cirrus,cs42l84", }, + {} +}; +MODULE_DEVICE_TABLE(of, cs42l84_of_match); + +static const struct i2c_device_id cs42l84_id[] = { + {"cs42l84", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs42l84_id); + +static struct i2c_driver cs42l84_i2c_driver = { + .driver = { + .name = "cs42l84", + .of_match_table = cs42l84_of_match, + }, + .id_table = cs42l84_id, + .probe = cs42l84_i2c_probe, + .remove = cs42l84_i2c_remove, +}; + +module_i2c_driver(cs42l84_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L84 driver"); +MODULE_AUTHOR("Martin Povišer "); +MODULE_AUTHOR("Hector Martin "); +MODULE_AUTHOR("James Calligeros "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l84.h b/sound/soc/codecs/cs42l84.h new file mode 100644 index 00000000000000..dbf778a902b9cc --- /dev/null +++ b/sound/soc/codecs/cs42l84.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) The Asahi Linux Contributors + * + * Based on sound/soc/codecs/cs42l42.h + * + * Copyright 2016 Cirrus Logic, Inc. + */ + + +#ifndef __CS42L84_H__ +#define __CS42L84_H__ + +#include + +#define CS42L84_CHIP_ID 0x42a84 + +#define CS42L84_DEVID 0x0000 +#define CS42L84_REVID 0x73fe +#define CS42L84_FRZ_CTL 0x0006 +#define CS42L84_FRZ_CTL_ENGAGE BIT(0) + +#define CS42L84_TSRS_PLUG_INT_STATUS 0x0400 +#define CS42L84_TSRS_PLUG_INT_MASK 0x0418 +#define CS42L84_RS_PLUG_SHIFT 0 +#define CS42L84_RS_PLUG BIT(0) +#define CS42L84_RS_UNPLUG BIT(1) +#define CS42L84_TS_PLUG_SHIFT 2 +#define CS42L84_TS_PLUG BIT(2) +#define CS42L84_TS_UNPLUG BIT(3) +#define CS42L84_TSRS_PLUG_VAL_MASK GENMASK(3, 0) +#define CS42L84_PLL_LOCK_STATUS 0x040e // probably bit 0x10 +#define CS42L84_PLL_LOCK_STATUS_LOCKED BIT(4) +#define CS42L84_PLL_LOCK_STATUS_ERROR BIT(5) + +#define CS42L84_PLUG 3 +#define CS42L84_UNPLUG 0 +#define CS42L84_TRANS 1 + +#define CS42L84_CCM_CTL1 0x0600 +#define CS42L84_CCM_CTL1_MCLK_SRC GENMASK(1, 0) +#define CS42L84_CCM_CTL1_MCLK_SRC_RCO 0 +#define CS42L84_CCM_CTL1_MCLK_SRC_MCLK 1 +#define CS42L84_CCM_CTL1_MCLK_SRC_BCLK 2 +#define CS42L84_CCM_CTL1_MCLK_SRC_PLL 3 +#define CS42L84_CCM_CTL1_MCLK_FREQ GENMASK(3, 2) +#define CS42L84_CCM_CTL1_MCLK_F_12MHZ 0b00 +#define CS42L84_CCM_CTL1_MCLK_F_24MHZ 0b01 +#define CS42L84_CCM_CTL1_MCLK_F_12_288KHZ 0b10 +#define CS42L84_CCM_CTL1_MCLK_F_24_576KHZ 0b11 +#define CS42L84_CCM_CTL1_RCO \ + (FIELD_PREP(CS42L84_CCM_CTL1_MCLK_SRC, CS42L84_CCM_CTL1_MCLK_SRC_RCO) \ + | FIELD_PREP(CS42L84_CCM_CTL1_MCLK_FREQ, CS42L84_CCM_CTL1_MCLK_F_12MHZ)) + +#define CS42L84_CCM_SAMP_RATE 0x0601 +#define CS42L84_CCM_SAMP_RATE_RATE_48KHZ 4 +#define CS42L84_CCM_SAMP_RATE_RATE_96KHZ 5 +#define CS42L84_CCM_SAMP_RATE_RATE_192KHZ 6 +#define CS42L84_CCM_SAMP_RATE_RATE_44K1HZ 12 +#define CS42L84_CCM_SAMP_RATE_RATE_88K2HZ 13 +#define CS42L84_CCM_SAMP_RATE_RATE_176K4HZ 14 +#define CS42L84_CCM_CTL3 0x0602 +#define CS42L84_CCM_CTL3_REFCLK_DIV GENMASK(2, 1) +#define CS42L84_CCM_CTL4 0x0603 +#define CS42L84_CCM_CTL4_REFCLK_EN BIT(0) + +#define CS42L84_CCM_ASP_CLK_CTRL 0x0608 + +#define CS42L84_PLL_CTL1 0x0800 +#define CS42L84_PLL_CTL1_EN BIT(0) +#define CS42L84_PLL_CTL1_MODE GENMASK(2, 1) +#define CS42L84_PLL_DIV_FRAC0 0x0804 +#define CS42L84_PLL_DIV_FRAC1 0x0805 +#define CS42L84_PLL_DIV_FRAC2 0x0806 +#define CS42L84_PLL_DIV_INT 0x0807 +#define CS42L84_PLL_DIVOUT 0x0808 + +#define CS42L84_RING_SENSE_CTL 0x1282 +#define CS42L84_RING_SENSE_CTL_INV BIT(7) +#define CS42L84_RING_SENSE_CTL_UNK1 BIT(6) +#define CS42L84_RING_SENSE_CTL_FALLTIME GENMASK(5, 3) +#define CS42L84_RING_SENSE_CTL_RISETIME GENMASK(2, 0) +#define CS42L84_TIP_SENSE_CTL 0x1283 +#define CS42L84_TIP_SENSE_CTL_INV BIT(7) +#define CS42L84_TIP_SENSE_CTL_FALLTIME GENMASK(5, 3) +#define CS42L84_TIP_SENSE_CTL_RISETIME GENMASK(2, 0) + +#define CS42L84_TSRS_PLUG_STATUS 0x1288 + +#define CS42L84_TIP_SENSE_CTL2 0x1473 +#define CS42L84_TIP_SENSE_CTL2_MODE GENMASK(7, 6) +#define CS42L84_TIP_SENSE_CTL2_MODE_DISABLED 0b00 +#define CS42L84_TIP_SENSE_CTL2_MODE_DIG_INPUT 0b01 +#define CS42L84_TIP_SENSE_CTL2_MODE_SHORT_DET 0b11 +#define CS42L84_TIP_SENSE_CTL2_INV BIT(5) + +#define CS42L84_MISC_DET_CTL 0x1474 +#define CS42L84_MISC_DET_CTL_DETECT_MODE GENMASK(4, 3) +#define CS42L84_MISC_DET_CTL_HSBIAS_CTL GENMASK(2, 1) +#define CS42L84_MISC_DET_CTL_PDN_MIC_LVL_DET BIT(0) + +#define CS42L84_MIC_DET_CTL1 0x1475 +#define CS42L84_MIC_DET_CTL1_HS_DET_LEVEL GENMASK(5, 0) + +#define CS42L84_MIC_DET_CTL4 0x1477 +#define CS42L84_MIC_DET_CTL4_LATCH_TO_VP BIT(1) + +#define CS42L84_HS_DET_STATUS2 0x147d + +#define CS42L84_MSM_BLOCK_EN1 0x1800 +#define CS42L84_MSM_BLOCK_EN2 0x1801 +#define CS42L84_MSM_BLOCK_EN2_ASP_SHIFT 6 +#define CS42L84_MSM_BLOCK_EN2_BUS_SHIFT 5 +#define CS42L84_MSM_BLOCK_EN2_DAC_SHIFT 4 +#define CS42L84_MSM_BLOCK_EN2_ADC_SHIFT 3 +#define CS42L84_MSM_BLOCK_EN3 0x1802 +#define CS42L84_MSM_BLOCK_EN3_TR_SENSE BIT(3) + +#define CS42L84_HS_DET_CTL2 0x1811 +#define CS42L84_HS_DET_CTL2_CTL GENMASK(7, 6) +#define CS42L84_HS_DET_CTL2_SET GENMASK(5, 4) +#define CS42L84_HS_DET_CTL2_REF BIT(3) +#define CS42L84_HS_DET_CTL2_AUTO_TIME GENMASK(1, 0) + +#define CS42L84_HS_SWITCH_CTL 0x1812 +#define CS42L84_HS_SWITCH_CTL_REF_HS3 BIT(7) +#define CS42L84_HS_SWITCH_CTL_REF_HS4 BIT(6) +#define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS3 BIT(5) +#define CS42L84_HS_SWITCH_CTL_HSB_FILT_HS4 BIT(4) +#define CS42L84_HS_SWITCH_CTL_HSB_HS3 BIT(3) +#define CS42L84_HS_SWITCH_CTL_HSB_HS4 BIT(2) +#define CS42L84_HS_SWITCH_CTL_GNDHS_HS3 BIT(1) +#define CS42L84_HS_SWITCH_CTL_GNDHS_HS4 BIT(0) + +#define CS42L84_HS_CLAMP_DISABLE 0x1813 + +#define CS42L84_ADC_CTL1 0x2000 +#define CS42L84_ADC_CTL1_PREAMP_GAIN_SHIFT 6 +#define CS42L84_ADC_CTL1_PGA_GAIN_SHIFT 0 +#define CS42L84_ADC_CTL4 0x2003 +#define CS42L84_ADC_CTL4_WNF_CF_SHIFT 4 +#define CS42L84_ADC_CTL4_WNF_EN_SHIFT 3 +#define CS42L84_ADC_CTL4_HPF_CF_SHIFT 1 +#define CS42L84_ADC_CTL4_HPF_EN_SHIFT 0 + +#define CS42L84_DAC_CTL1 0x3000 +#define CS42L84_DAC_CTL1_UNMUTE BIT(0) +//#define CS42L84_DAC_CTL1_DACB_INV_SHIFT 1 +//#define CS42L84_DAC_CTL1_DACA_INV_SHIFT 0 +#define CS42L84_DAC_CTL2 0x3001 + +#define CS42L84_DAC_CHA_VOL_LSB 0x3004 +#define CS42L84_DAC_CHA_VOL_MSB 0x3005 +#define CS42L84_DAC_CHB_VOL_LSB 0x3006 +#define CS42L84_DAC_CHB_VOL_MSB 0x3007 +#define CS42L84_HP_VOL_CTL 0x3020 +#define CS42L84_HP_VOL_CTL_ZERO_CROSS BIT(1) +#define CS42L84_HP_VOL_CTL_SOFT BIT(0) + +#define CS42L84_SRC_ASP_RX_CH1 0b1101 +#define CS42L84_SRC_ASP_RX_CH2 0b1110 + +#define CS42L84_BUS_ASP_TX_SRC 0x4000 +#define CS42L84_BUS_ASP_TX_SRC_CH1_SHIFT 0 +#define CS42L84_BUS_DAC_SRC 0x4001 +#define CS42L84_BUS_DAC_SRC_DACA_SHIFT 0 +#define CS42L84_BUS_DAC_SRC_DACB_SHIFT 4 + +#define CS42L84_ASP_CTL 0x5000 +#define CS42L84_ASP_CTL_BCLK_EN_SHIFT 1 +#define CS42L84_ASP_CTL_TDM_MODE BIT(2) +#define CS42L84_ASP_FSYNC_CTL2 0x5010 +#define CS42L84_ASP_FSYNC_CTL2_BCLK_PERIOD_LO GENMASK(7, 1) +#define CS42L84_ASP_FSYNC_CTL3 0x5011 +#define CS42L84_ASP_FSYNC_CTL3_BCLK_PERIOD_HI GENMASK(4, 0) +#define CS42L84_ASP_DATA_CTL 0x5018 + +#define CS42L84_ASP_RX_EN 0x5020 +#define CS42L84_ASP_RX_EN_CH1_SHIFT 0 +#define CS42L84_ASP_RX_EN_CH2_SHIFT 1 +#define CS42L84_ASP_TX_EN 0x5024 +#define CS42L84_ASP_TX_EN_CH1_SHIFT 0 + +#define CS42L84_ASP_RX_CH1_CTL1 0x5028 +#define CS42L84_ASP_RX_CH1_CTL2 0x5029 +#define CS42L84_ASP_RX_CH1_WIDTH 0x502a +#define CS42L84_ASP_RX_CH2_CTL1 0x502c +#define CS42L84_ASP_RX_CH2_CTL2 0x502d +#define CS42L84_ASP_RX_CH2_WIDTH 0x502e + +#define CS42L84_ASP_RX_CHx_CTL1_EDGE BIT(0) +#define CS42L84_ASP_RX_CHx_CTL1_SLOT_START_LSB GENMASK(7, 1) +#define CS42L84_ASP_RX_CHx_CTL2_SLOT_START_MSB GENMASK(2, 0) + +#define CS42L84_ASP_TX_CH1_CTL1 0x5068 +#define CS42L84_ASP_TX_CH1_CTL2 0x5069 +#define CS42L84_ASP_TX_CH1_WIDTH 0x506a +#define CS42L84_ASP_TX_CH2_CTL1 0x506c +#define CS42L84_ASP_TX_CH2_CTL2 0x506d +#define CS42L84_ASP_TX_CH2_WIDTH 0x506e + +#define CS42L84_DEBOUNCE_TIME_125MS 0b001 +#define CS42L84_DEBOUNCE_TIME_500MS 0b011 + +#define CS42L84_BOOT_TIME_US 3000 +#define CS42L84_CLOCK_SWITCH_DELAY_US 150 +#define CS42L84_PLL_LOCK_POLL_US 250 +#define CS42L84_PLL_LOCK_TIMEOUT_US 1250 + +#endif /* __CS42L84_H__ */ diff --git a/sound/soc/codecs/cs530x-i2c.c b/sound/soc/codecs/cs530x-i2c.c index 56659bf735db7c..22b1a4d6b61cfb 100644 --- a/sound/soc/codecs/cs530x-i2c.c +++ b/sound/soc/codecs/cs530x-i2c.c @@ -67,6 +67,6 @@ static struct i2c_driver cs530x_i2c_driver = { module_i2c_driver(cs530x_i2c_driver); MODULE_DESCRIPTION("I2C CS530X driver"); -MODULE_IMPORT_NS(SND_SOC_CS530X); +MODULE_IMPORT_NS("SND_SOC_CS530X"); MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index da52afe56c3c62..252e66c8449ecd 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -821,7 +821,7 @@ const struct regmap_config cs530x_regmap = { .reg_defaults = cs530x_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults), }; -EXPORT_SYMBOL_NS_GPL(cs530x_regmap, SND_SOC_CS530X); +EXPORT_SYMBOL_NS_GPL(cs530x_regmap, "SND_SOC_CS530X"); static int cs530x_check_device_id(struct cs530x_priv *cs530x) { @@ -964,7 +964,7 @@ int cs530x_probe(struct cs530x_priv *cs530x) return ret; } -EXPORT_SYMBOL_NS_GPL(cs530x_probe, SND_SOC_CS530X); +EXPORT_SYMBOL_NS_GPL(cs530x_probe, "SND_SOC_CS530X"); MODULE_DESCRIPTION("CS530X CODEC Driver"); MODULE_AUTHOR("Paul Handrigan "); diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index f3ef6fb5530471..ca4cc954efa8e6 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1555,7 +1556,11 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component, if ((da7213->clk_src == clk_id) && (da7213->mclk_rate == freq)) return 0; - if (((freq < 5000000) && (freq != 32768)) || (freq > 54000000)) { + /* Maybe audio stream is closing. */ + if (freq == 0) + return 0; + + if (((freq < da7213->fin_min_rate) && (freq != 32768)) || (freq > 54000000)) { dev_err(component->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; @@ -1854,11 +1859,14 @@ static int da7213_set_bias_level(struct snd_soc_component *component, return 0; } +#define DA7213_FIN_MIN_RATE (5 * MEGA) +#define DA7212_FIN_MIN_RATE (2 * MEGA) + #if defined(CONFIG_OF) /* DT */ static const struct of_device_id da7213_of_match[] = { - { .compatible = "dlg,da7212", }, - { .compatible = "dlg,da7213", }, + { .compatible = "dlg,da7212", .data = (void *)DA7212_FIN_MIN_RATE }, + { .compatible = "dlg,da7213", .data = (void *)DA7213_FIN_MIN_RATE }, { } }; MODULE_DEVICE_TABLE(of, da7213_of_match); @@ -1866,8 +1874,8 @@ MODULE_DEVICE_TABLE(of, da7213_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id da7213_acpi_match[] = { - { "DLGS7212", 0}, - { "DLGS7213", 0}, + { "DLGS7212", DA7212_FIN_MIN_RATE }, + { "DLGS7213", DA7213_FIN_MIN_RATE }, { }, }; MODULE_DEVICE_TABLE(acpi, da7213_acpi_match); @@ -2136,6 +2144,7 @@ static const struct regmap_config da7213_regmap_config = { .reg_bits = 8, .val_bits = 8, + .max_register = DA7213_TONE_GEN_OFF_PER, .reg_defaults = da7213_reg_defaults, .num_reg_defaults = ARRAY_SIZE(da7213_reg_defaults), .volatile_reg = da7213_volatile_register, @@ -2162,6 +2171,10 @@ static int da7213_i2c_probe(struct i2c_client *i2c) if (!da7213) return -ENOMEM; + da7213->fin_min_rate = (uintptr_t)i2c_get_match_data(i2c); + if (!da7213->fin_min_rate) + return -EINVAL; + i2c_set_clientdata(i2c, da7213); /* Get required supplies */ @@ -2229,12 +2242,12 @@ static int __maybe_unused da7213_runtime_resume(struct device *dev) if (ret < 0) return ret; regcache_cache_only(da7213->regmap, false); - regcache_sync(da7213->regmap); - return 0; + return regcache_sync(da7213->regmap); } static const struct dev_pm_ops da7213_pm = { SET_RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct i2c_device_id da7213_i2c_id[] = { diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 505b731c0adb93..b9ab791d6b883b 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -600,6 +600,7 @@ struct da7213_priv { struct clk *mclk; unsigned int mclk_rate; unsigned int out_rate; + unsigned int fin_min_rate; int clk_src; bool master; bool alc_calib_auto; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 311ea7918b3124..e2da3e317b5a3e 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1167,17 +1167,20 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); int ret = 0; - if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) + mutex_lock(&da7219->pll_lock); + + if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) { + mutex_unlock(&da7219->pll_lock); return 0; + } if ((freq < 2000000) || (freq > 54000000)) { + mutex_unlock(&da7219->pll_lock); dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; } - mutex_lock(&da7219->pll_lock); - switch (clk_id) { case DA7219_CLKSRC_MCLK_SQR: snd_soc_component_update_bits(component, DA7219_PLL_CTRL, diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c new file mode 100644 index 00000000000000..6f4fa36ea34d67 --- /dev/null +++ b/sound/soc/codecs/es8323.c @@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// es8323.c -- es8323 ALSA SoC audio driver +// +// Copyright 2024 Rockchip Electronics Co. Ltd. +// Copyright 2024 Everest Semiconductor Co.,Ltd. +// Copyright 2024 Loongson Technology Co.,Ltd. +// +// Author: Mark Brown +// Jianqun Xu +// Nickey Yang +// Further cleanup and restructuring by: +// Binbin Zhou + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "es8323.h" + +struct es8323_priv { + unsigned int sysclk; + struct clk *mclk; + struct regmap *regmap; + struct snd_pcm_hw_constraint_list *sysclk_constraints; + struct snd_soc_component *component; +}; + +/* es8323 register cache */ +static const struct reg_default es8323_reg_defaults[] = { + { ES8323_CONTROL1, 0x06 }, + { ES8323_CONTROL2, 0x1c }, + { ES8323_CHIPPOWER, 0xc3 }, + { ES8323_ADCPOWER, 0xfc }, + { ES8323_DACPOWER, 0xc0 }, + { ES8323_CHIPLOPOW1, 0x00 }, + { ES8323_CHIPLOPOW2, 0x00 }, + { ES8323_ANAVOLMANAG, 0x7c }, + { ES8323_MASTERMODE, 0x80 }, + { ES8323_ADCCONTROL1, 0x00 }, + { ES8323_ADCCONTROL2, 0x00 }, + { ES8323_ADCCONTROL3, 0x06 }, + { ES8323_ADCCONTROL4, 0x00 }, + { ES8323_ADCCONTROL5, 0x06 }, + { ES8323_ADCCONTROL6, 0x30 }, + { ES8323_ADC_MUTE, 0x30 }, + { ES8323_LADC_VOL, 0xc0 }, + { ES8323_RADC_VOL, 0xc0 }, + { ES8323_ADCCONTROL10, 0x38 }, + { ES8323_ADCCONTROL11, 0xb0 }, + { ES8323_ADCCONTROL12, 0x32 }, + { ES8323_ADCCONTROL13, 0x06 }, + { ES8323_ADCCONTROL14, 0x00 }, + { ES8323_DACCONTROL1, 0x00 }, + { ES8323_DACCONTROL2, 0x06 }, + { ES8323_DAC_MUTE, 0x30 }, + { ES8323_LDAC_VOL, 0xc0 }, + { ES8323_RDAC_VOL, 0xc0 }, + { ES8323_DACCONTROL6, 0x08 }, + { ES8323_DACCONTROL7, 0x06 }, + { ES8323_DACCONTROL8, 0x1f }, + { ES8323_DACCONTROL9, 0xf7 }, + { ES8323_DACCONTROL10, 0xfd }, + { ES8323_DACCONTROL11, 0xff }, + { ES8323_DACCONTROL12, 0x1f }, + { ES8323_DACCONTROL13, 0xf7 }, + { ES8323_DACCONTROL14, 0xfd }, + { ES8323_DACCONTROL15, 0xff }, + { ES8323_DACCONTROL16, 0x00 }, + { ES8323_DACCONTROL17, 0x38 }, + { ES8323_DACCONTROL18, 0x38 }, + { ES8323_DACCONTROL19, 0x38 }, + { ES8323_DACCONTROL20, 0x38 }, + { ES8323_DACCONTROL21, 0x38 }, + { ES8323_DACCONTROL22, 0x38 }, + { ES8323_DACCONTROL23, 0x00 }, + { ES8323_LOUT1_VOL, 0x00 }, + { ES8323_ROUT1_VOL, 0x00 }, +}; + +static const char *const es8323_stereo_3d_texts[] = { "No 3D ", "Level 1", "Level 2", "Level 3", + "Level 4", "Level 5", "Level 6", "Level 7" }; +static SOC_ENUM_SINGLE_DECL(es8323_stereo_3d_enum, ES8323_DACCONTROL7, 2, es8323_stereo_3d_texts); + +static const char *const es8323_alc_func_texts[] = { "Off", "Right", "Left", "Stereo" }; +static SOC_ENUM_SINGLE_DECL(es8323_alc_function_enum, + ES8323_ADCCONTROL10, 6, es8323_alc_func_texts); + +static const char *const es8323_ng_type_texts[] = { "Constant PGA Gain", "Mute ADC Output" }; +static SOC_ENUM_SINGLE_DECL(es8323_alc_ng_type_enum, ES8323_ADCCONTROL14, 1, es8323_ng_type_texts); + +static const char *const es8323_deemph_texts[] = { "None", "32Khz", "44.1Khz", "48Khz" }; +static SOC_ENUM_SINGLE_DECL(es8323_playback_deemphasis_enum, + ES8323_DACCONTROL6, 6, es8323_deemph_texts); + +static const char *const es8323_adcpol_texts[] = { "Normal", "L Invert", + "R Invert", "L + R Invert" }; +static SOC_ENUM_SINGLE_DECL(es8323_capture_polarity_enum, + ES8323_ADCCONTROL6, 6, es8323_adcpol_texts); + +static const DECLARE_TLV_DB_SCALE(es8323_adc_tlv, -9600, 50, 1); +static const DECLARE_TLV_DB_SCALE(es8323_dac_tlv, -9600, 50, 1); +static const DECLARE_TLV_DB_SCALE(es8323_out_tlv, -4500, 150, 0); +static const DECLARE_TLV_DB_SCALE(es8323_bypass_tlv, 0, 300, 0); +static const DECLARE_TLV_DB_SCALE(es8323_bypass_tlv2, -15, 300, 0); + +static const struct snd_kcontrol_new es8323_snd_controls[] = { + SOC_ENUM("3D Mode", es8323_stereo_3d_enum), + SOC_ENUM("ALC Capture Function", es8323_alc_function_enum), + SOC_ENUM("ALC Capture NG Type", es8323_alc_ng_type_enum), + SOC_ENUM("Playback De-emphasis", es8323_playback_deemphasis_enum), + SOC_ENUM("Capture Polarity", es8323_capture_polarity_enum), + SOC_SINGLE("ALC Capture ZC Switch", ES8323_ADCCONTROL13, 6, 1, 0), + SOC_SINGLE("ALC Capture Decay Time", ES8323_ADCCONTROL12, 4, 15, 0), + SOC_SINGLE("ALC Capture Attack Time", ES8323_ADCCONTROL12, 0, 15, 0), + SOC_SINGLE("ALC Capture NG Threshold", ES8323_ADCCONTROL14, 3, 31, 0), + SOC_SINGLE("ALC Capture NG Switch", ES8323_ADCCONTROL14, 0, 1, 0), + SOC_SINGLE("ZC Timeout Switch", ES8323_ADCCONTROL13, 6, 1, 0), + SOC_SINGLE("Capture Mute Switch", ES8323_ADC_MUTE, 2, 1, 0), + SOC_SINGLE_TLV("Left Channel Capture Volume", ES8323_ADCCONTROL1, 4, 8, + 0, es8323_bypass_tlv), + SOC_SINGLE_TLV("Right Channel Capture Volume", ES8323_ADCCONTROL1, 0, + 8, 0, es8323_bypass_tlv), + SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", ES8323_DACCONTROL17, 3, + 7, 1, es8323_bypass_tlv2), + SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", ES8323_DACCONTROL20, + 3, 7, 1, es8323_bypass_tlv2), + SOC_DOUBLE_R_TLV("PCM Volume", ES8323_LDAC_VOL, ES8323_RDAC_VOL, + 0, 192, 1, es8323_dac_tlv), + SOC_DOUBLE_R_TLV("Capture Digital Volume", ES8323_LADC_VOL, + ES8323_RADC_VOL, 0, 192, 1, es8323_adc_tlv), + SOC_DOUBLE_R_TLV("Output 1 Playback Volume", ES8323_LOUT1_VOL, + ES8323_ROUT1_VOL, 0, 33, 0, es8323_out_tlv), + SOC_DOUBLE_R_TLV("Output 2 Playback Volume", ES8323_LOUT2_VOL, + ES8323_ROUT2_VOL, 0, 33, 0, es8323_out_tlv), +}; + +/* Left DAC Route */ +static const char *const es8323_pga_sell[] = { "Line 1L", "Line 2L", "NC", "DifferentialL" }; +static SOC_ENUM_SINGLE_DECL(es8323_left_dac_enum, ES8323_ADCCONTROL2, 6, es8323_pga_sell); +static const struct snd_kcontrol_new es8323_left_dac_mux_controls = + SOC_DAPM_ENUM("Left DAC Route", es8323_left_dac_enum); + +/* Right DAC Route */ +static const char *const es8323_pga_selr[] = { "Line 1R", "Line 2R", "NC", "DifferentialR" }; +static SOC_ENUM_SINGLE_DECL(es8323_right_dac_enum, ES8323_ADCCONTROL2, 4, es8323_pga_selr); +static const struct snd_kcontrol_new es8323_right_dac_mux_controls = + SOC_DAPM_ENUM("Right DAC Route", es8323_right_dac_enum); + +/* Left Line Mux */ +static const char *const es8323_lin_sell[] = { "Line 1L", "Line 2L", "NC", "MicL" }; +static SOC_ENUM_SINGLE_DECL(es8323_llin_enum, ES8323_DACCONTROL16, 3, es8323_lin_sell); +static const struct snd_kcontrol_new es8323_left_line_controls = + SOC_DAPM_ENUM("LLIN Mux", es8323_llin_enum); + +/* Right Line Mux */ +static const char *const es8323_lin_selr[] = { "Line 1R", "Line 2R", "NC", "MicR" }; +static SOC_ENUM_SINGLE_DECL(es8323_rlin_enum, ES8323_DACCONTROL16, 0, es8323_lin_selr); +static const struct snd_kcontrol_new es8323_right_line_controls = + SOC_DAPM_ENUM("RLIN Mux", es8323_rlin_enum); + +/* Differential Mux */ +static const char *const es8323_diffmux_sel[] = { "Line 1", "Line 2" }; +static SOC_ENUM_SINGLE_DECL(es8323_diffmux_enum, ES8323_ADCCONTROL3, 7, es8323_diffmux_sel); +static const struct snd_kcontrol_new es8323_diffmux_controls = + SOC_DAPM_ENUM("Route2", es8323_diffmux_enum); + +/* Mono ADC Mux */ +static const char *const es8323_mono_adc_mux[] = { "Stereo", "Mono (Left)", "Mono (Right)" }; +static SOC_ENUM_SINGLE_DECL(es8323_mono_adc_mux_enum, ES8323_ADCCONTROL3, 3, es8323_mono_adc_mux); +static const struct snd_kcontrol_new es8323_mono_adc_mux_controls = + SOC_DAPM_ENUM("Mono Mux", es8323_mono_adc_mux_enum); + +/* Left Mixer */ +static const struct snd_kcontrol_new es8323_left_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", SND_SOC_NOPM, 7, 1, 1), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8323_DACCONTROL17, 6, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new es8323_right_mixer_controls[] = { + SOC_DAPM_SINGLE("Right Playback Switch", SND_SOC_NOPM, 6, 1, 1), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8323_DACCONTROL20, 6, 1, 0), +}; + +static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), + + SND_SOC_DAPM_MICBIAS("Mic Bias", SND_SOC_NOPM, 3, 1), + + /* Muxes */ + SND_SOC_DAPM_MUX("Left PGA Mux", SND_SOC_NOPM, 0, 0, &es8323_left_dac_mux_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", SND_SOC_NOPM, 0, 0, &es8323_right_dac_mux_controls), + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, &es8323_diffmux_controls), + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, &es8323_mono_adc_mux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, &es8323_mono_adc_mux_controls), + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, &es8323_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, &es8323_right_line_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", SND_SOC_NOPM, 4, 1), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", SND_SOC_NOPM, 5, 1), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", SND_SOC_NOPM, 6, 1), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", SND_SOC_NOPM, 7, 1), + + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &es8323_left_mixer_controls[0], + ARRAY_SIZE(es8323_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &es8323_right_mixer_controls[0], + ARRAY_SIZE(es8323_right_mixer_controls)), + + SND_SOC_DAPM_PGA("Right ADC Power", SND_SOC_NOPM, 6, 1, NULL, 0), + SND_SOC_DAPM_PGA("Left ADC Power", SND_SOC_NOPM, 7, 1, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 2", SND_SOC_NOPM, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", SND_SOC_NOPM, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", SND_SOC_NOPM, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", SND_SOC_NOPM, 5, 0, NULL, 0), + SND_SOC_DAPM_PGA("LAMP", ES8323_ADCCONTROL1, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("RAMP", ES8323_ADCCONTROL1, 0, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + SND_SOC_DAPM_OUTPUT("VREF"), +}; + +static const struct snd_soc_dapm_route es8323_dapm_routes[] = { + /*12.22*/ + {"Left PGA Mux", "Line 1L", "LINPUT1"}, + {"Left PGA Mux", "Line 2L", "LINPUT2"}, + {"Left PGA Mux", "DifferentialL", "Differential Mux"}, + + {"Right PGA Mux", "Line 1R", "RINPUT1"}, + {"Right PGA Mux", "Line 2R", "RINPUT2"}, + {"Right PGA Mux", "DifferentialR", "Differential Mux"}, + + {"Differential Mux", "Line 1", "LINPUT1"}, + {"Differential Mux", "Line 1", "RINPUT1"}, + {"Differential Mux", "Line 2", "LINPUT2"}, + {"Differential Mux", "Line 2", "RINPUT2"}, + + {"Left ADC Mux", "Stereo", "Right PGA Mux"}, + {"Left ADC Mux", "Stereo", "Left PGA Mux"}, + {"Left ADC Mux", "Mono (Left)", "Left PGA Mux"}, + + {"Right ADC Mux", "Stereo", "Left PGA Mux"}, + {"Right ADC Mux", "Stereo", "Right PGA Mux"}, + {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, + + {"Left ADC Power", NULL, "Left ADC Mux"}, + {"Right ADC Power", NULL, "Right ADC Mux"}, + {"Left ADC", NULL, "Left ADC Power"}, + {"Right ADC", NULL, "Right ADC Power"}, + + {"Left Line Mux", "Line 1L", "LINPUT1"}, + {"Left Line Mux", "Line 2L", "LINPUT2"}, + {"Left Line Mux", "MicL", "Left PGA Mux"}, + + {"Right Line Mux", "Line 1R", "RINPUT1"}, + {"Right Line Mux", "Line 2R", "RINPUT2"}, + {"Right Line Mux", "MicR", "Right PGA Mux"}, + + {"Left Mixer", "Left Playback Switch", "Left DAC"}, + {"Left Mixer", "Left Bypass Switch", "Left Line Mux"}, + + {"Right Mixer", "Right Playback Switch", "Right DAC"}, + {"Right Mixer", "Right Bypass Switch", "Right Line Mux"}, + + {"Left Out 1", NULL, "Left Mixer"}, + {"LOUT1", NULL, "Left Out 1"}, + {"Right Out 1", NULL, "Right Mixer"}, + {"ROUT1", NULL, "Right Out 1"}, + + {"Left Out 2", NULL, "Left Mixer"}, + {"LOUT2", NULL, "Left Out 2"}, + {"Right Out 2", NULL, "Right Mixer"}, + {"ROUT2", NULL, "Right Out 2"}, +}; + +struct coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:4; + u8 usb:1; +}; + +/* codec hifi mclk clock divider coefficients */ +static const struct coeff_div es8323_coeff_div[] = { + /* 8k */ + {12288000, 8000, 1536, 0xa, 0x0}, + {11289600, 8000, 1408, 0x9, 0x0}, + {18432000, 8000, 2304, 0xc, 0x0}, + {16934400, 8000, 2112, 0xb, 0x0}, + {12000000, 8000, 1500, 0xb, 0x1}, + + /* 11.025k */ + {11289600, 11025, 1024, 0x7, 0x0}, + {16934400, 11025, 1536, 0xa, 0x0}, + {12000000, 11025, 1088, 0x9, 0x1}, + + /* 16k */ + {12288000, 16000, 768, 0x6, 0x0}, + {18432000, 16000, 1152, 0x8, 0x0}, + {12000000, 16000, 750, 0x7, 0x1}, + + /* 22.05k */ + {11289600, 22050, 512, 0x4, 0x0}, + {16934400, 22050, 768, 0x6, 0x0}, + {12000000, 22050, 544, 0x6, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0x3, 0x0}, + {18432000, 32000, 576, 0x5, 0x0}, + {12000000, 32000, 375, 0x4, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x2, 0x0}, + {16934400, 44100, 384, 0x3, 0x0}, + {12000000, 44100, 272, 0x3, 0x1}, + + /* 48k */ + {12288000, 48000, 256, 0x2, 0x0}, + {18432000, 48000, 384, 0x3, 0x0}, + {12000000, 48000, 250, 0x2, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0x0, 0x0}, + {16934400, 88200, 192, 0x1, 0x0}, + {12000000, 88200, 136, 0x1, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0x0, 0x0}, + {18432000, 96000, 192, 0x1, 0x0}, + {12000000, 96000, 125, 0x0, 0x1}, +}; + +static unsigned int rates_12288[] = { + 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12288 = { + .count = ARRAY_SIZE(rates_12288), + .list = rates_12288, +}; + +static unsigned int rates_112896[] = { + 8000, 11025, 22050, 44100, +}; + +static struct snd_pcm_hw_constraint_list constraints_112896 = { + .count = ARRAY_SIZE(rates_112896), + .list = rates_112896, +}; + +static unsigned int rates_12[] = { + 8000, 11025, 12000, 16000, 22050, 24000, + 32000, 44100, 48000, 48000, 88235, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12 = { + .count = ARRAY_SIZE(rates_12), + .list = rates_12, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(es8323_coeff_div); i++) { + if (es8323_coeff_div[i].rate == rate && + es8323_coeff_div[i].mclk == mclk) + return i; + } + + return -EINVAL; +} + +static int es8323_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + switch (freq) { + case 11289600: + case 18432000: + case 22579200: + case 36864000: + es8323->sysclk_constraints = &constraints_112896; + break; + case 12288000: + case 16934400: + case 24576000: + case 33868800: + es8323->sysclk_constraints = &constraints_12288; + break; + case 12000000: + case 24000000: + es8323->sysclk_constraints = &constraints_12; + break; + default: + return -EINVAL; + } + + es8323->sysclk = freq; + return 0; +} + +static int es8323_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + u8 iface = snd_soc_component_read(component, ES8323_MASTERMODE); + u8 adciface = snd_soc_component_read(component, ES8323_ADC_IFACE); + u8 daciface = snd_soc_component_read(component, ES8323_DAC_IFACE); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_BC_FP: + iface |= 0x80; + break; + case SND_SOC_DAIFMT_BC_FC: + iface &= 0x7f; + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + adciface &= 0xfc; + daciface &= 0xf8; + break; + case SND_SOC_DAIFMT_LEFT_J: + adciface &= 0xfd; + daciface &= 0xf9; + break; + case SND_SOC_DAIFMT_RIGHT_J: + adciface &= 0xfe; + daciface &= 0xfa; + break; + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + adciface &= 0xff; + daciface &= 0xfb; + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + iface &= 0xdf; + adciface &= 0xdf; + daciface &= 0xbf; + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x20; + adciface |= 0x20; + daciface |= 0x40; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x20; + adciface &= 0xdf; + daciface &= 0xbf; + break; + case SND_SOC_DAIFMT_NB_IF: + iface &= 0xdf; + adciface |= 0x20; + daciface |= 0x40; + break; + default: + return -EINVAL; + } + + snd_soc_component_write(component, ES8323_MASTERMODE, iface); + snd_soc_component_write(component, ES8323_ADC_IFACE, adciface); + snd_soc_component_write(component, ES8323_DAC_IFACE, daciface); + + return 0; +} + +static int es8323_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + if (es8323->sysclk) { + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + es8323->sysclk_constraints); + } + + return 0; +} + +static int es8323_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + u16 srate = snd_soc_component_read(component, ES8323_MASTERMODE) & 0x80; + u16 adciface = snd_soc_component_read(component, ES8323_ADC_IFACE) & 0xe3; + u16 daciface = snd_soc_component_read(component, ES8323_DAC_IFACE) & 0xc7; + int coeff; + + coeff = get_coeff(es8323->sysclk, params_rate(params)); + if (coeff < 0) { + coeff = get_coeff(es8323->sysclk / 2, params_rate(params)); + srate |= 0x40; + } + + if (coeff < 0) { + dev_err(component->dev, + "Unable to configure sample rate %dHz with %dHz MCLK\n", + params_rate(params), es8323->sysclk); + return coeff; + } + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + adciface |= 0xc; + daciface |= 0x18; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + adciface |= 0x4; + daciface |= 0x8; + break; + case SNDRV_PCM_FORMAT_S24_LE: + break; + case SNDRV_PCM_FORMAT_S32_LE: + adciface |= 0x10; + daciface |= 0x20; + break; + } + + snd_soc_component_write(component, ES8323_DAC_IFACE, daciface); + snd_soc_component_write(component, ES8323_ADC_IFACE, adciface); + + snd_soc_component_write(component, ES8323_MASTERMODE, srate); + snd_soc_component_write(component, ES8323_ADCCONTROL5, + es8323_coeff_div[coeff].sr | + (es8323_coeff_div[coeff].usb) << 4); + snd_soc_component_write(component, ES8323_DACCONTROL2, + es8323_coeff_div[coeff].sr | + (es8323_coeff_div[coeff].usb) << 4); + + snd_soc_component_write(component, ES8323_DACPOWER, 0x3c); + + return 0; +} + +static int es8323_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + u32 val = mute ? 0x6 : 0x2; + + snd_soc_component_write(component, ES8323_DAC_MUTE, val); + + return 0; +} + +static const struct snd_soc_dai_ops es8323_ops = { + .startup = es8323_pcm_startup, + .hw_params = es8323_pcm_hw_params, + .set_fmt = es8323_set_dai_fmt, + .set_sysclk = es8323_set_dai_sysclk, + .mute_stream = es8323_mute_stream, +}; + +#define ES8323_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver es8323_dai = { + .name = "ES8323 HiFi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = ES8323_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = ES8323_FORMATS, + }, + .ops = &es8323_ops, + .symmetric_rate = 1, +}; + +static int es8323_probe(struct snd_soc_component *component) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + int ret; + + es8323->component = component; + + es8323->mclk = devm_clk_get_optional(component->dev, "mclk"); + if (IS_ERR(es8323->mclk)) { + dev_err(component->dev, "unable to get mclk\n"); + return PTR_ERR(es8323->mclk); + } + + if (!es8323->mclk) + dev_warn(component->dev, "assuming static mclk\n"); + + ret = clk_prepare_enable(es8323->mclk); + if (ret) { + dev_err(component->dev, "unable to enable mclk\n"); + return ret; + } + + snd_soc_component_write(component, ES8323_CONTROL2, 0x60); + snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00); + snd_soc_component_write(component, ES8323_DACCONTROL17, 0xB8); + + return 0; +} + +static int es8323_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + ret = clk_prepare_enable(es8323->mclk); + if (ret) + return ret; + + snd_soc_component_write(component, ES8323_CHIPPOWER, 0xf0); + usleep_range(18000, 20000); + snd_soc_component_write(component, ES8323_DACPOWER, 0x3c); + snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7c); + snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0x00); + snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0x00); + snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00); + snd_soc_component_write(component, ES8323_ADCPOWER, 0x09); + snd_soc_component_write(component, ES8323_ADCCONTROL14, 0x00); + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7c); + snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0x00); + snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0x00); + snd_soc_component_write(component, ES8323_CHIPPOWER, 0x00); + snd_soc_component_write(component, ES8323_ADCPOWER, 0x59); + break; + case SND_SOC_BIAS_OFF: + clk_disable_unprepare(es8323->mclk); + snd_soc_component_write(component, ES8323_ADCPOWER, 0xff); + snd_soc_component_write(component, ES8323_DACPOWER, 0xC0); + snd_soc_component_write(component, ES8323_CHIPLOPOW1, 0xff); + snd_soc_component_write(component, ES8323_CHIPLOPOW2, 0xff); + snd_soc_component_write(component, ES8323_CHIPPOWER, 0xff); + snd_soc_component_write(component, ES8323_ANAVOLMANAG, 0x7b); + break; + } + + return 0; +} + +static void es8323_remove(struct snd_soc_component *component) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + clk_disable_unprepare(es8323->mclk); + es8323_set_bias_level(component, SND_SOC_BIAS_OFF); +} + +static int es8323_suspend(struct snd_soc_component *component) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(es8323->regmap, true); + regcache_mark_dirty(es8323->regmap); + + return 0; +} + +static int es8323_resume(struct snd_soc_component *component) +{ + struct es8323_priv *es8323 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(es8323->regmap, false); + regcache_sync(es8323->regmap); + + return 0; +} + +static const struct snd_soc_component_driver soc_component_dev_es8323 = { + .probe = es8323_probe, + .remove = es8323_remove, + .suspend = es8323_suspend, + .resume = es8323_resume, + .set_bias_level = es8323_set_bias_level, + .controls = es8323_snd_controls, + .num_controls = ARRAY_SIZE(es8323_snd_controls), + .dapm_widgets = es8323_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8323_dapm_widgets), + .dapm_routes = es8323_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(es8323_dapm_routes), + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct regmap_config es8323_regmap = { + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, + .max_register = 0x53, + .reg_defaults = es8323_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(es8323_reg_defaults), + .cache_type = REGCACHE_MAPLE, +}; + +static int es8323_i2c_probe(struct i2c_client *i2c_client) +{ + struct es8323_priv *es8323; + struct device *dev = &i2c_client->dev; + + es8323 = devm_kzalloc(dev, sizeof(*es8323), GFP_KERNEL); + if (!es8323) + return -ENOMEM; + + i2c_set_clientdata(i2c_client, es8323); + + es8323->regmap = devm_regmap_init_i2c(i2c_client, &es8323_regmap); + if (IS_ERR(es8323->regmap)) + return PTR_ERR(es8323->regmap); + + return devm_snd_soc_register_component(dev, + &soc_component_dev_es8323, + &es8323_dai, 1); +} + +static const struct i2c_device_id es8323_i2c_id[] = { + { "es8323", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, es8323_i2c_id); + +static const struct acpi_device_id es8323_acpi_match[] = { + { "ESSX8323", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, es8323_acpi_match); + +static const struct of_device_id es8323_of_match[] = { + { .compatible = "everest,es8323" }, + { } +}; +MODULE_DEVICE_TABLE(of, es8323_of_match); + +static struct i2c_driver es8323_i2c_driver = { + .driver = { + .name = "ES8323", + .acpi_match_table = es8323_acpi_match, + .of_match_table = es8323_of_match, + }, + .probe = es8323_i2c_probe, + .id_table = es8323_i2c_id, +}; +module_i2c_driver(es8323_i2c_driver); + +MODULE_DESCRIPTION("Everest Semi ES8323 ALSA SoC Codec Driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_AUTHOR("Binbin Zhou "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/es8323.h b/sound/soc/codecs/es8323.h new file mode 100644 index 00000000000000..f986c9301dc624 --- /dev/null +++ b/sound/soc/codecs/es8323.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright Openedhand Ltd. + * + * Author: Richard Purdie + * Binbin Zhou + * + */ + +#ifndef _ES8323_H +#define _ES8323_H + +/* ES8323 register space */ + +/* Chip Control and Power Management */ +#define ES8323_CONTROL1 0x00 +#define ES8323_CONTROL2 0x01 +#define ES8323_CHIPPOWER 0x02 +#define ES8323_ADCPOWER 0x03 +#define ES8323_DACPOWER 0x04 +#define ES8323_CHIPLOPOW1 0x05 +#define ES8323_CHIPLOPOW2 0x06 +#define ES8323_ANAVOLMANAG 0x07 +#define ES8323_MASTERMODE 0x08 + +/* ADC Control */ +#define ES8323_ADCCONTROL1 0x09 +#define ES8323_ADCCONTROL2 0x0a +#define ES8323_ADCCONTROL3 0x0b +#define ES8323_ADCCONTROL4 0x0c +#define ES8323_ADCCONTROL5 0x0d +#define ES8323_ADCCONTROL6 0x0e +#define ES8323_ADC_MUTE 0x0f +#define ES8323_LADC_VOL 0x10 +#define ES8323_RADC_VOL 0x11 +#define ES8323_ADCCONTROL10 0x12 +#define ES8323_ADCCONTROL11 0x13 +#define ES8323_ADCCONTROL12 0x14 +#define ES8323_ADCCONTROL13 0x15 +#define ES8323_ADCCONTROL14 0x16 + +/* DAC Control */ +#define ES8323_DACCONTROL1 0x17 +#define ES8323_DACCONTROL2 0x18 +#define ES8323_DAC_MUTE 0x19 +#define ES8323_LDAC_VOL 0x1a +#define ES8323_RDAC_VOL 0x1b +#define ES8323_DACCONTROL6 0x1c +#define ES8323_DACCONTROL7 0x1d +#define ES8323_DACCONTROL8 0x1e +#define ES8323_DACCONTROL9 0x1f +#define ES8323_DACCONTROL10 0x20 +#define ES8323_DACCONTROL11 0x21 +#define ES8323_DACCONTROL12 0x22 +#define ES8323_DACCONTROL13 0x23 +#define ES8323_DACCONTROL14 0x24 +#define ES8323_DACCONTROL15 0x25 +#define ES8323_DACCONTROL16 0x26 +#define ES8323_DACCONTROL17 0x27 +#define ES8323_DACCONTROL18 0x28 +#define ES8323_DACCONTROL19 0x29 +#define ES8323_DACCONTROL20 0x2a +#define ES8323_DACCONTROL21 0x2b +#define ES8323_DACCONTROL22 0x2c +#define ES8323_DACCONTROL23 0x2d +#define ES8323_LOUT1_VOL 0x2e +#define ES8323_ROUT1_VOL 0x2f +#define ES8323_LOUT2_VOL 0x30 +#define ES8323_ROUT2_VOL 0x31 +#define ES8323_DACCONTROL28 0x32 +#define ES8323_DACCONTROL29 0x33 +#define ES8323_DACCONTROL30 0x34 + +#define ES8323_ADC_IFACE ES8323_ADCCONTROL4 +#define ES8323_ADC_SRATE ES8323_ADCCONTROL5 +#define ES8323_DAC_IFACE ES8323_DACCONTROL1 +#define ES8323_DAC_SRATE ES8323_DACCONTROL2 +#endif diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c index d5362b3be48444..a5603b6176889a 100644 --- a/sound/soc/codecs/es8326.c +++ b/sound/soc/codecs/es8326.c @@ -614,6 +614,10 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) } else { regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE, 0x0F, 0x0F); + if (es8326->version > ES8326_VERSION_B) { + regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40); + regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x10); + } } } else { if (!es8326->calibrated) { @@ -640,6 +644,10 @@ static int es8326_mute(struct snd_soc_dai *dai, int mute, int direction) ES8326_MUTE_MASK, ~(ES8326_MUTE)); } else { msleep(300); + if (es8326->version > ES8326_VERSION_B) { + regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x70, 0x50); + regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x00); + } regmap_update_bits(es8326->regmap, ES8326_ADC_MUTE, 0x0F, 0x00); } @@ -821,7 +829,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) iface = snd_soc_component_read(comp, ES8326_HPDET_STA); dev_dbg(comp->dev, "gpio flag %#04x", iface); - if ((es8326->jack_remove_retry == 1) && (es8326->version != ES8326_VERSION_B)) { + if ((es8326->jack_remove_retry == 1) && (es8326->version < ES8326_VERSION_B)) { if (iface & ES8326_HPINSERT_FLAG) es8326->jack_remove_retry = 2; else @@ -859,7 +867,7 @@ static void es8326_jack_detect_handler(struct work_struct *work) /* * Inverted HPJACK_POL bit to trigger one IRQ to double check HP Removal event */ - if ((es8326->jack_remove_retry == 0) && (es8326->version != ES8326_VERSION_B)) { + if ((es8326->jack_remove_retry == 0) && (es8326->version < ES8326_VERSION_B)) { es8326->jack_remove_retry = 1; dev_dbg(comp->dev, "remove event check, invert HPJACK_POL, cnt = %d\n", es8326->jack_remove_retry); @@ -954,7 +962,7 @@ static int es8326_calibrate(struct snd_soc_component *component) regmap_read(es8326->regmap, ES8326_CHIP_VERSION, ®); es8326->version = reg; - if ((es8326->version == ES8326_VERSION_B) && (es8326->calibrated == false)) { + if ((es8326->version >= ES8326_VERSION_B) && (es8326->calibrated == false)) { dev_dbg(component->dev, "ES8326_VERSION_B, calibrating\n"); regmap_write(es8326->regmap, ES8326_CLK_INV, 0xc0); regmap_write(es8326->regmap, ES8326_CLK_DIV1, 0x03); @@ -1047,7 +1055,7 @@ static void es8326_init(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_DAC_VPPSCALE, 0x15); regmap_write(es8326->regmap, ES8326_HPDET_TYPE, 0x80 | - ((es8326->version == ES8326_VERSION_B) ? + ((es8326->version >= ES8326_VERSION_B) ? (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol) : (ES8326_HP_DET_SRC_PIN9 | es8326->jack_pol | 0x04))); usleep_range(5000, 10000); @@ -1073,6 +1081,10 @@ static void es8326_init(struct snd_soc_component *component) regmap_write(es8326->regmap, ES8326_ADC1_SRC, 0x44); regmap_write(es8326->regmap, ES8326_ADC2_SRC, 0x66); es8326_disable_micbias(es8326->component); + if (es8326->version > ES8326_VERSION_B) { + regmap_update_bits(es8326->regmap, ES8326_ANA_MICBIAS, 0x73, 0x13); + regmap_update_bits(es8326->regmap, ES8326_VMIDSEL, 0x40, 0x40); + } msleep(200); regmap_write(es8326->regmap, ES8326_INT_SOURCE, ES8326_INT_SRC_PIN9); diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 74caae52e1273f..d9df29a26f4f21 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -185,84 +185,97 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { /* * hdmi_codec_channel_alloc: speaker configuration available for CEA * - * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct + * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps * The preceding ones have better chances to be selected by * hdmi_codec_get_ch_alloc_table_idx(). */ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { { .ca_id = 0x00, .n_ch = 2, - .mask = FL | FR}, - /* 2.1 */ - { .ca_id = 0x01, .n_ch = 4, - .mask = FL | FR | LFE}, - /* Dolby Surround */ + .mask = FL | FR }, + { .ca_id = 0x03, .n_ch = 4, + .mask = FL | FR | LFE | FC }, { .ca_id = 0x02, .n_ch = 4, .mask = FL | FR | FC }, - /* surround51 */ + { .ca_id = 0x01, .n_ch = 4, + .mask = FL | FR | LFE }, { .ca_id = 0x0b, .n_ch = 6, - .mask = FL | FR | LFE | FC | RL | RR}, - /* surround40 */ - { .ca_id = 0x08, .n_ch = 6, - .mask = FL | FR | RL | RR }, - /* surround41 */ - { .ca_id = 0x09, .n_ch = 6, - .mask = FL | FR | LFE | RL | RR }, - /* surround50 */ + .mask = FL | FR | LFE | FC | RL | RR }, { .ca_id = 0x0a, .n_ch = 6, .mask = FL | FR | FC | RL | RR }, - /* 6.1 */ - { .ca_id = 0x0f, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | RC }, - /* surround71 */ + { .ca_id = 0x09, .n_ch = 6, + .mask = FL | FR | LFE | RL | RR }, + { .ca_id = 0x08, .n_ch = 6, + .mask = FL | FR | RL | RR }, + { .ca_id = 0x07, .n_ch = 6, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x06, .n_ch = 6, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x05, .n_ch = 6, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x04, .n_ch = 6, + .mask = FL | FR | RC }, { .ca_id = 0x13, .n_ch = 8, .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, - /* others */ - { .ca_id = 0x03, .n_ch = 8, - .mask = FL | FR | LFE | FC }, - { .ca_id = 0x04, .n_ch = 8, - .mask = FL | FR | RC}, - { .ca_id = 0x05, .n_ch = 8, - .mask = FL | FR | LFE | RC }, - { .ca_id = 0x06, .n_ch = 8, - .mask = FL | FR | FC | RC }, - { .ca_id = 0x07, .n_ch = 8, - .mask = FL | FR | LFE | FC | RC }, - { .ca_id = 0x0c, .n_ch = 8, - .mask = FL | FR | RC | RL | RR }, - { .ca_id = 0x0d, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | RC }, - { .ca_id = 0x0e, .n_ch = 8, - .mask = FL | FR | FC | RL | RR | RC }, - { .ca_id = 0x10, .n_ch = 8, - .mask = FL | FR | RL | RR | RLC | RRC }, - { .ca_id = 0x11, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x1f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, { .ca_id = 0x12, .n_ch = 8, .mask = FL | FR | FC | RL | RR | RLC | RRC }, - { .ca_id = 0x14, .n_ch = 8, - .mask = FL | FR | FLC | FRC }, - { .ca_id = 0x15, .n_ch = 8, - .mask = FL | FR | LFE | FLC | FRC }, - { .ca_id = 0x16, .n_ch = 8, - .mask = FL | FR | FC | FLC | FRC }, - { .ca_id = 0x17, .n_ch = 8, - .mask = FL | FR | LFE | FC | FLC | FRC }, - { .ca_id = 0x18, .n_ch = 8, - .mask = FL | FR | RC | FLC | FRC }, - { .ca_id = 0x19, .n_ch = 8, - .mask = FL | FR | LFE | RC | FLC | FRC }, - { .ca_id = 0x1a, .n_ch = 8, - .mask = FL | FR | RC | FC | FLC | FRC }, - { .ca_id = 0x1b, .n_ch = 8, - .mask = FL | FR | LFE | RC | FC | FLC | FRC }, - { .ca_id = 0x1c, .n_ch = 8, - .mask = FL | FR | RL | RR | FLC | FRC }, - { .ca_id = 0x1d, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | FLC | FRC }, { .ca_id = 0x1e, .n_ch = 8, .mask = FL | FR | FC | RL | RR | FLC | FRC }, - { .ca_id = 0x1f, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, + { .ca_id = 0x11, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x1d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | FLC | FRC }, + { .ca_id = 0x10, .n_ch = 8, + .mask = FL | FR | RL | RR | RLC | RRC }, + { .ca_id = 0x1c, .n_ch = 8, + .mask = FL | FR | RL | RR | FLC | FRC }, + { .ca_id = 0x0f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RC }, + { .ca_id = 0x1b, .n_ch = 8, + .mask = FL | FR | LFE | RC | FC | FLC | FRC }, + { .ca_id = 0x0e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RC }, + { .ca_id = 0x1a, .n_ch = 8, + .mask = FL | FR | RC | FC | FLC | FRC }, + { .ca_id = 0x0d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RC }, + { .ca_id = 0x19, .n_ch = 8, + .mask = FL | FR | LFE | RC | FLC | FRC }, + { .ca_id = 0x0c, .n_ch = 8, + .mask = FL | FR | RC | RL | RR }, + { .ca_id = 0x18, .n_ch = 8, + .mask = FL | FR | RC | FLC | FRC }, + { .ca_id = 0x17, .n_ch = 8, + .mask = FL | FR | LFE | FC | FLC | FRC }, + { .ca_id = 0x16, .n_ch = 8, + .mask = FL | FR | FC | FLC | FRC }, + { .ca_id = 0x15, .n_ch = 8, + .mask = FL | FR | LFE | FLC | FRC }, + { .ca_id = 0x14, .n_ch = 8, + .mask = FL | FR | FLC | FRC }, + { .ca_id = 0x0b, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR }, + { .ca_id = 0x0a, .n_ch = 8, + .mask = FL | FR | FC | RL | RR }, + { .ca_id = 0x09, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR }, + { .ca_id = 0x08, .n_ch = 8, + .mask = FL | FR | RL | RR }, + { .ca_id = 0x07, .n_ch = 8, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x06, .n_ch = 8, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x05, .n_ch = 8, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x04, .n_ch = 8, + .mask = FL | FR | RC }, + { .ca_id = 0x03, .n_ch = 8, + .mask = FL | FR | LFE | FC }, + { .ca_id = 0x02, .n_ch = 8, + .mask = FL | FR | FC }, + { .ca_id = 0x01, .n_ch = 8, + .mask = FL | FR | LFE }, }; struct hdmi_codec_priv { @@ -371,7 +384,8 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hdmi_codec_priv *hcp = info->private_data; - map = info->chmap[hcp->chmap_idx].map; + if (hcp->chmap_idx != HDMI_CODEC_CHMAP_IDX_UNKNOWN) + map = info->chmap[hcp->chmap_idx].map; for (i = 0; i < info->max_channels; i++) { if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 8b0645c6346207..8915f525069533 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -480,12 +480,18 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = { SOC_SINGLE("INA Volume", M98088_REG_37_LVL_INA, 0, 7, 1), SOC_SINGLE("INB Volume", M98088_REG_38_LVL_INB, 0, 7, 1), + SOC_SINGLE("DACL Volume", M98088_REG_2F_LVL_DAI1_PLAY, 0, 15, 1), + SOC_SINGLE("DACR Volume", M98088_REG_31_LVL_DAI2_PLAY, 0, 15, 1), + SOC_SINGLE("ADCL Volume", M98088_REG_33_LVL_ADC_L, 0, 15, 0), SOC_SINGLE("ADCR Volume", M98088_REG_34_LVL_ADC_R, 0, 15, 0), SOC_SINGLE("ADCL Boost Volume", M98088_REG_33_LVL_ADC_L, 4, 3, 0), SOC_SINGLE("ADCR Boost Volume", M98088_REG_34_LVL_ADC_R, 4, 3, 0), + SOC_SINGLE("Left HP Output Mixer Switch", M98088_REG_27_MIX_HP_CNTL, 4, 1, 0), + SOC_SINGLE("Right HP Output Mixer Switch", M98088_REG_27_MIX_HP_CNTL, 5, 1, 0), + SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0), SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0), @@ -515,10 +521,8 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = { /* Left speaker mixer switch */ static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0), @@ -529,10 +533,8 @@ static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = { /* Right speaker mixer switch */ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_2C_MIX_SPK_RIGHT, 7, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_2C_MIX_SPK_RIGHT, 0, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2C_MIX_SPK_RIGHT, 1, 1, 0), @@ -543,10 +545,8 @@ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = { /* Left headphone mixer switch */ static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0), @@ -557,10 +557,8 @@ static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = { /* Right headphone mixer switch */ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_26_MIX_HP_RIGHT, 7, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_26_MIX_HP_RIGHT, 0, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_26_MIX_HP_RIGHT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_26_MIX_HP_RIGHT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_26_MIX_HP_RIGHT, 1, 1, 0), @@ -571,10 +569,8 @@ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = { /* Left earpiece/receiver mixer switch */ static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0), @@ -585,10 +581,8 @@ static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = { /* Right earpiece/receiver mixer switch */ static const struct snd_kcontrol_new max98088_right_rec_mixer_controls[] = { - SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0), - SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0), - SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0), + SOC_DAPM_SINGLE("Left DAC Switch", M98088_REG_29_MIX_REC_RIGHT, 7, 1, 0), + SOC_DAPM_SINGLE("Right DAC Switch", M98088_REG_29_MIX_REC_RIGHT, 0, 1, 0), SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_29_MIX_REC_RIGHT, 5, 1, 0), SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_29_MIX_REC_RIGHT, 6, 1, 0), SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_29_MIX_REC_RIGHT, 1, 1, 0), @@ -717,13 +711,9 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 1, 0), SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98088_REG_4C_PWR_EN_IN, 0, 0), - SND_SOC_DAPM_DAC("DACL1", "HiFi Playback", - M98088_REG_4D_PWR_EN_OUT, 1, 0), - SND_SOC_DAPM_DAC("DACR1", "HiFi Playback", - M98088_REG_4D_PWR_EN_OUT, 0, 0), - SND_SOC_DAPM_DAC("DACL2", "Aux Playback", + SND_SOC_DAPM_DAC("DACL", "HiFi Playback", M98088_REG_4D_PWR_EN_OUT, 1, 0), - SND_SOC_DAPM_DAC("DACR2", "Aux Playback", + SND_SOC_DAPM_DAC("DACR", "HiFi Playback", M98088_REG_4D_PWR_EN_OUT, 0, 0), SND_SOC_DAPM_PGA("HP Left Out", M98088_REG_4D_PWR_EN_OUT, @@ -819,10 +809,8 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = { static const struct snd_soc_dapm_route max98088_audio_map[] = { /* Left headphone output mixer */ - {"Left HP Mixer", "Left DAC1 Switch", "DACL1"}, - {"Left HP Mixer", "Left DAC2 Switch", "DACL2"}, - {"Left HP Mixer", "Right DAC1 Switch", "DACR1"}, - {"Left HP Mixer", "Right DAC2 Switch", "DACR2"}, + {"Left HP Mixer", "Left DAC Switch", "DACL"}, + {"Left HP Mixer", "Right DAC Switch", "DACR"}, {"Left HP Mixer", "MIC1 Switch", "MIC1 Input"}, {"Left HP Mixer", "MIC2 Switch", "MIC2 Input"}, {"Left HP Mixer", "INA1 Switch", "INA1 Input"}, @@ -831,10 +819,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Left HP Mixer", "INB2 Switch", "INB2 Input"}, /* Right headphone output mixer */ - {"Right HP Mixer", "Left DAC1 Switch", "DACL1"}, - {"Right HP Mixer", "Left DAC2 Switch", "DACL2" }, - {"Right HP Mixer", "Right DAC1 Switch", "DACR1"}, - {"Right HP Mixer", "Right DAC2 Switch", "DACR2"}, + {"Right HP Mixer", "Left DAC Switch", "DACL"}, + {"Right HP Mixer", "Right DAC Switch", "DACR"}, {"Right HP Mixer", "MIC1 Switch", "MIC1 Input"}, {"Right HP Mixer", "MIC2 Switch", "MIC2 Input"}, {"Right HP Mixer", "INA1 Switch", "INA1 Input"}, @@ -843,10 +829,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Right HP Mixer", "INB2 Switch", "INB2 Input"}, /* Left speaker output mixer */ - {"Left SPK Mixer", "Left DAC1 Switch", "DACL1"}, - {"Left SPK Mixer", "Left DAC2 Switch", "DACL2"}, - {"Left SPK Mixer", "Right DAC1 Switch", "DACR1"}, - {"Left SPK Mixer", "Right DAC2 Switch", "DACR2"}, + {"Left SPK Mixer", "Left DAC Switch", "DACL"}, + {"Left SPK Mixer", "Right DAC Switch", "DACR"}, {"Left SPK Mixer", "MIC1 Switch", "MIC1 Input"}, {"Left SPK Mixer", "MIC2 Switch", "MIC2 Input"}, {"Left SPK Mixer", "INA1 Switch", "INA1 Input"}, @@ -855,10 +839,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Left SPK Mixer", "INB2 Switch", "INB2 Input"}, /* Right speaker output mixer */ - {"Right SPK Mixer", "Left DAC1 Switch", "DACL1"}, - {"Right SPK Mixer", "Left DAC2 Switch", "DACL2"}, - {"Right SPK Mixer", "Right DAC1 Switch", "DACR1"}, - {"Right SPK Mixer", "Right DAC2 Switch", "DACR2"}, + {"Right SPK Mixer", "Left DAC Switch", "DACL"}, + {"Right SPK Mixer", "Right DAC Switch", "DACR"}, {"Right SPK Mixer", "MIC1 Switch", "MIC1 Input"}, {"Right SPK Mixer", "MIC2 Switch", "MIC2 Input"}, {"Right SPK Mixer", "INA1 Switch", "INA1 Input"}, @@ -867,10 +849,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Right SPK Mixer", "INB2 Switch", "INB2 Input"}, /* Earpiece/Receiver output mixer */ - {"Left REC Mixer", "Left DAC1 Switch", "DACL1"}, - {"Left REC Mixer", "Left DAC2 Switch", "DACL2"}, - {"Left REC Mixer", "Right DAC1 Switch", "DACR1"}, - {"Left REC Mixer", "Right DAC2 Switch", "DACR2"}, + {"Left REC Mixer", "Left DAC Switch", "DACL"}, + {"Left REC Mixer", "Right DAC Switch", "DACR"}, {"Left REC Mixer", "MIC1 Switch", "MIC1 Input"}, {"Left REC Mixer", "MIC2 Switch", "MIC2 Input"}, {"Left REC Mixer", "INA1 Switch", "INA1 Input"}, @@ -879,10 +859,8 @@ static const struct snd_soc_dapm_route max98088_audio_map[] = { {"Left REC Mixer", "INB2 Switch", "INB2 Input"}, /* Earpiece/Receiver output mixer */ - {"Right REC Mixer", "Left DAC1 Switch", "DACL1"}, - {"Right REC Mixer", "Left DAC2 Switch", "DACL2"}, - {"Right REC Mixer", "Right DAC1 Switch", "DACR1"}, - {"Right REC Mixer", "Right DAC2 Switch", "DACR2"}, + {"Right REC Mixer", "Left DAC Switch", "DACL"}, + {"Right REC Mixer", "Right DAC Switch", "DACR"}, {"Right REC Mixer", "MIC1 Switch", "MIC1 Input"}, {"Right REC Mixer", "MIC2 Switch", "MIC2 Input"}, {"Right REC Mixer", "INA1 Switch", "INA1 Input"}, diff --git a/sound/soc/codecs/nau8821.c b/sound/soc/codecs/nau8821.c index de5c4db05c8f8b..edb95f869a4a6b 100644 --- a/sound/soc/codecs/nau8821.c +++ b/sound/soc/codecs/nau8821.c @@ -287,10 +287,8 @@ static int nau8821_biq_coeff_get(struct snd_kcontrol *kcontrol, if (!component->regmap) return -EINVAL; - regmap_raw_read(component->regmap, NAU8821_R21_BIQ0_COF1, + return regmap_raw_read(component->regmap, NAU8821_R21_BIQ0_COF1, ucontrol->value.bytes.data, params->max); - - return 0; } static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol, @@ -299,6 +297,7 @@ static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_bytes_ext *params = (void *)kcontrol->private_value; void *data; + int ret; if (!component->regmap) return -EINVAL; @@ -308,12 +307,12 @@ static int nau8821_biq_coeff_put(struct snd_kcontrol *kcontrol, if (!data) return -ENOMEM; - regmap_raw_write(component->regmap, NAU8821_R21_BIQ0_COF1, + ret = regmap_raw_write(component->regmap, NAU8821_R21_BIQ0_COF1, data, params->max); kfree(data); - return 0; + return ret; } static const char * const nau8821_adc_decimation[] = { diff --git a/sound/soc/codecs/ntp8835.c b/sound/soc/codecs/ntp8835.c new file mode 100644 index 00000000000000..796e1410496f43 --- /dev/null +++ b/sound/soc/codecs/ntp8835.c @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the NTP8835/NTP8835C Audio Amplifiers + * + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + * + * Author: Igor Prusov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ntpfw.h" + +#define NTP8835_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define NTP8835_INPUT_FMT 0x0 +#define NTP8835_INPUT_FMT_MASTER_MODE BIT(0) +#define NTP8835_INPUT_FMT_GSA_MODE BIT(1) +#define NTP8835_GSA_FMT 0x1 +#define NTP8835_GSA_BS_MASK GENMASK(3, 2) +#define NTP8835_GSA_BS(x) ((x) << 2) +#define NTP8835_GSA_RIGHT_J BIT(0) +#define NTP8835_GSA_LSB BIT(1) +#define NTP8835_MCLK_FREQ_CTRL 0x2 +#define NTP8835_MCLK_FREQ_MCF GENMASK(1, 0) +#define NTP8835_SOFT_MUTE 0x26 +#define NTP8835_SOFT_MUTE_SM1 BIT(0) +#define NTP8835_SOFT_MUTE_SM2 BIT(1) +#define NTP8835_SOFT_MUTE_SM3 BIT(2) +#define NTP8835_PWM_SWITCH 0x27 +#define NTP8835_PWM_SWITCH_POF1 BIT(0) +#define NTP8835_PWM_SWITCH_POF2 BIT(1) +#define NTP8835_PWM_SWITCH_POF3 BIT(2) +#define NTP8835_PWM_MASK_CTRL0 0x28 +#define NTP8835_PWM_MASK_CTRL0_OUT_LOW BIT(1) +#define NTP8835_PWM_MASK_CTRL0_FPMLD BIT(2) +#define NTP8835_MASTER_VOL 0x2e +#define NTP8835_CHNL_A_VOL 0x2f +#define NTP8835_CHNL_B_VOL 0x30 +#define NTP8835_CHNL_C_VOL 0x31 +#define REG_MAX NTP8835_CHNL_C_VOL + +#define NTP8835_FW_NAME "eq_8835.bin" +#define NTP8835_FW_MAGIC 0x38383335 /* "8835" */ + +struct ntp8835_priv { + struct i2c_client *i2c; + struct reset_control *reset; + unsigned int format; + struct clk *mclk; + unsigned int mclk_rate; +}; + +static const DECLARE_TLV_DB_RANGE(ntp8835_vol_scale, + 0, 1, TLV_DB_SCALE_ITEM(-15000, 0, 0), + 2, 6, TLV_DB_SCALE_ITEM(-15000, 1000, 0), + 7, 0xff, TLV_DB_SCALE_ITEM(-10000, 50, 0), +); + +static int ntp8835_mute_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->access = + (SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE); + uinfo->count = 1; + + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + uinfo->value.integer.step = 1; + + return 0; +} + +static int ntp8835_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int val; + + val = snd_soc_component_read(component, NTP8835_SOFT_MUTE); + + ucontrol->value.integer.value[0] = val ? 0 : 1; + return 0; +} + +static int ntp8835_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int val; + + val = ucontrol->value.integer.value[0] ? 0 : 7; + + snd_soc_component_write(component, NTP8835_SOFT_MUTE, val); + + return 0; +} + +static const struct snd_kcontrol_new ntp8835_vol_control[] = { + SOC_SINGLE_TLV("Playback Volume", NTP8835_MASTER_VOL, 0, + 0xff, 0, ntp8835_vol_scale), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Playback Switch", + .info = ntp8835_mute_info, + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, + .get = ntp8835_mute_get, + .put = ntp8835_mute_put, + }, +}; + +static void ntp8835_reset_gpio(struct ntp8835_priv *ntp8835) +{ + /* + * Proper initialization sequence for NTP835 amplifier requires driving + * /RESET signal low during power up for at least 0.1us. The sequence is, + * according to NTP8835 datasheet, 6.2 Timing Sequence (recommended): + * Deassert for T2 >= 1ms... + */ + reset_control_deassert(ntp8835->reset); + fsleep(1000); + + /* ...Assert for T3 >= 0.1us... */ + reset_control_assert(ntp8835->reset); + fsleep(1); + + /* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */ + reset_control_deassert(ntp8835->reset); + fsleep(500); +} + +static const struct reg_sequence ntp8835_sound_on[] = { + { NTP8835_PWM_MASK_CTRL0, NTP8835_PWM_MASK_CTRL0_FPMLD }, + { NTP8835_PWM_SWITCH, 0x00 }, + { NTP8835_SOFT_MUTE, 0x00 }, +}; + +static const struct reg_sequence ntp8835_sound_off[] = { + { NTP8835_SOFT_MUTE, NTP8835_SOFT_MUTE_SM1 | + NTP8835_SOFT_MUTE_SM2 | + NTP8835_SOFT_MUTE_SM3 }, + + { NTP8835_PWM_SWITCH, NTP8835_PWM_SWITCH_POF1 | + NTP8835_PWM_SWITCH_POF2 | + NTP8835_PWM_SWITCH_POF3 }, + + { NTP8835_PWM_MASK_CTRL0, NTP8835_PWM_MASK_CTRL0_OUT_LOW | + NTP8835_PWM_MASK_CTRL0_FPMLD }, +}; + +static int ntp8835_load_firmware(struct ntp8835_priv *ntp8835) +{ + int ret; + + ret = ntpfw_load(ntp8835->i2c, NTP8835_FW_NAME, NTP8835_FW_MAGIC); + if (ret == -ENOENT) { + dev_warn_once(&ntp8835->i2c->dev, + "Could not find firmware %s\n", NTP8835_FW_NAME); + return 0; + } + + return ret; +} + +static int ntp8835_snd_suspend(struct snd_soc_component *component) +{ + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(component->regmap, true); + + regmap_multi_reg_write_bypassed(component->regmap, + ntp8835_sound_off, + ARRAY_SIZE(ntp8835_sound_off)); + + /* + * According to NTP8835 datasheet, 6.2 Timing Sequence (recommended): + * wait after sound off for T6 >= 0.5ms + */ + fsleep(500); + reset_control_assert(ntp8835->reset); + + regcache_mark_dirty(component->regmap); + clk_disable_unprepare(ntp8835->mclk); + + return 0; +} + +static int ntp8835_snd_resume(struct snd_soc_component *component) +{ + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + int ret; + + ntp8835_reset_gpio(ntp8835); + ret = clk_prepare_enable(ntp8835->mclk); + if (ret) + return ret; + + regmap_multi_reg_write_bypassed(component->regmap, + ntp8835_sound_on, + ARRAY_SIZE(ntp8835_sound_on)); + + ret = ntp8835_load_firmware(ntp8835); + if (ret) { + dev_err(&ntp8835->i2c->dev, "Failed to load firmware\n"); + return ret; + } + + regcache_cache_only(component->regmap, false); + snd_soc_component_cache_sync(component); + + return 0; +} + +static int ntp8835_probe(struct snd_soc_component *component) +{ + int ret; + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + struct device *dev = component->dev; + + ret = snd_soc_add_component_controls(component, ntp8835_vol_control, + ARRAY_SIZE(ntp8835_vol_control)); + if (ret) + return dev_err_probe(dev, ret, "Failed to add controls\n"); + + ret = ntp8835_load_firmware(ntp8835); + if (ret) + return dev_err_probe(dev, ret, "Failed to load firmware\n"); + + return 0; +} + +static const struct snd_soc_dapm_widget ntp8835_dapm_widgets[] = { + SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OUT1"), + SND_SOC_DAPM_OUTPUT("OUT2"), + SND_SOC_DAPM_OUTPUT("OUT3"), +}; + +static const struct snd_soc_dapm_route ntp8835_dapm_routes[] = { + { "OUT1", NULL, "AIFIN" }, + { "OUT2", NULL, "AIFIN" }, + { "OUT3", NULL, "AIFIN" }, +}; + +static int ntp8835_set_component_sysclk(struct snd_soc_component *component, + int clk_id, int source, + unsigned int freq, int dir) +{ + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + + switch (freq) { + case 12288000: + case 24576000: + case 18432000: + ntp8835->mclk_rate = freq; + break; + default: + ntp8835->mclk_rate = 0; + dev_err(component->dev, "Unsupported MCLK value: %u", freq); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_component_driver soc_component_ntp8835 = { + .probe = ntp8835_probe, + .suspend = ntp8835_snd_suspend, + .resume = ntp8835_snd_resume, + .dapm_widgets = ntp8835_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ntp8835_dapm_widgets), + .dapm_routes = ntp8835_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ntp8835_dapm_routes), + .set_sysclk = ntp8835_set_component_sysclk, +}; + +static int ntp8835_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + unsigned int input_fmt = 0; + unsigned int gsa_fmt = 0; + unsigned int gsa_fmt_mask; + unsigned int mcf; + int ret; + + switch (ntp8835->mclk_rate) { + case 12288000: + mcf = 0; + break; + case 24576000: + mcf = 1; + break; + case 18432000: + mcf = 2; + break; + default: + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, NTP8835_MCLK_FREQ_CTRL, + NTP8835_MCLK_FREQ_MCF, mcf); + if (ret) + return ret; + + switch (ntp8835->format) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + input_fmt |= NTP8835_INPUT_FMT_GSA_MODE; + gsa_fmt |= NTP8835_GSA_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + input_fmt |= NTP8835_INPUT_FMT_GSA_MODE; + break; + } + + ret = snd_soc_component_update_bits(component, NTP8835_INPUT_FMT, + NTP8835_INPUT_FMT_MASTER_MODE | + NTP8835_INPUT_FMT_GSA_MODE, + input_fmt); + + if (!(input_fmt & NTP8835_INPUT_FMT_GSA_MODE) || ret < 0) + return ret; + + switch (params_width(params)) { + case 24: + gsa_fmt |= NTP8835_GSA_BS(0); + break; + case 20: + gsa_fmt |= NTP8835_GSA_BS(1); + break; + case 18: + gsa_fmt |= NTP8835_GSA_BS(2); + break; + case 16: + gsa_fmt |= NTP8835_GSA_BS(3); + break; + default: + return -EINVAL; + } + + gsa_fmt_mask = NTP8835_GSA_BS_MASK | + NTP8835_GSA_RIGHT_J | + NTP8835_GSA_LSB; + return snd_soc_component_update_bits(component, NTP8835_GSA_FMT, + gsa_fmt_mask, gsa_fmt); +} + +static int ntp8835_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + ntp8835->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + return 0; +}; + +static const struct snd_soc_dai_ops ntp8835_dai_ops = { + .hw_params = ntp8835_hw_params, + .set_fmt = ntp8835_set_fmt, +}; + +static struct snd_soc_dai_driver ntp8835_dai = { + .name = "ntp8835-amplifier", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 3, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = NTP8835_FORMATS, + }, + .ops = &ntp8835_dai_ops, +}; + +static const struct regmap_config ntp8835_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, + .cache_type = REGCACHE_MAPLE, +}; + +static int ntp8835_i2c_probe(struct i2c_client *i2c) +{ + struct ntp8835_priv *ntp8835; + struct regmap *regmap; + int ret; + + ntp8835 = devm_kzalloc(&i2c->dev, sizeof(*ntp8835), GFP_KERNEL); + if (!ntp8835) + return -ENOMEM; + + ntp8835->i2c = i2c; + + ntp8835->reset = devm_reset_control_get_shared(&i2c->dev, NULL); + if (IS_ERR(ntp8835->reset)) + return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->reset), + "Failed to get reset\n"); + + ret = reset_control_deassert(ntp8835->reset); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to deassert reset\n"); + + dev_set_drvdata(&i2c->dev, ntp8835); + + ntp8835_reset_gpio(ntp8835); + + regmap = devm_regmap_init_i2c(i2c, &ntp8835_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(regmap), + "Failed to allocate regmap\n"); + + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8835, + &ntp8835_dai, 1); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to register component\n"); + + ntp8835->mclk = devm_clk_get_enabled(&i2c->dev, "mclk"); + if (IS_ERR(ntp8835->mclk)) + return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->mclk), "failed to get mclk\n"); + + return 0; +} + +static const struct i2c_device_id ntp8835_i2c_id[] = { + { "ntp8835", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ntp8835_i2c_id); + +static const struct of_device_id ntp8835_of_match[] = { + {.compatible = "neofidelity,ntp8835",}, + {} +}; +MODULE_DEVICE_TABLE(of, ntp8835_of_match); + +static struct i2c_driver ntp8835_i2c_driver = { + .probe = ntp8835_i2c_probe, + .id_table = ntp8835_i2c_id, + .driver = { + .name = "ntp8835", + .of_match_table = ntp8835_of_match, + }, +}; +module_i2c_driver(ntp8835_i2c_driver); + +MODULE_AUTHOR("Igor Prusov "); +MODULE_DESCRIPTION("NTP8835 Audio Amplifier Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ntp8918.c b/sound/soc/codecs/ntp8918.c new file mode 100644 index 00000000000000..0493ab6acbe4ec --- /dev/null +++ b/sound/soc/codecs/ntp8918.c @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for the NTP8918 Audio Amplifier + * + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + * + * Author: Igor Prusov + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ntpfw.h" + +#define NTP8918_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) + +#define NTP8918_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define NTP8918_INPUT_FMT 0x0 +#define NTP8918_INPUT_FMT_MASTER_MODE BIT(0) +#define NTP8918_INPUT_FMT_GSA_MODE BIT(1) +#define NTP8918_GSA_FMT 0x1 +#define NTP8918_GSA_BS_MASK GENMASK(3, 2) +#define NTP8918_GSA_BS(x) ((x) << 2) +#define NTP8918_GSA_RIGHT_J BIT(0) +#define NTP8918_GSA_LSB BIT(1) +#define NTP8918_MCLK_FREQ_CTRL 0x2 +#define NTP8918_MCLK_FREQ_MCF GENMASK(1, 0) +#define NTP8918_MASTER_VOL 0x0C +#define NTP8918_CHNL_A_VOL 0x17 +#define NTP8918_CHNL_B_VOL 0x18 +#define NTP8918_SOFT_MUTE 0x33 +#define NTP8918_SOFT_MUTE_SM1 BIT(0) +#define NTP8918_SOFT_MUTE_SM2 BIT(1) +#define NTP8918_PWM_SWITCH 0x34 +#define NTP8918_PWM_MASK_CTRL0 0x35 +#define REG_MAX NTP8918_PWM_MASK_CTRL0 + +#define NTP8918_FW_NAME "eq_8918.bin" +#define NTP8918_FW_MAGIC 0x38393138 /* "8918" */ + +struct ntp8918_priv { + struct i2c_client *i2c; + struct clk *bck; + struct reset_control *reset; + unsigned int format; +}; + +static const DECLARE_TLV_DB_SCALE(ntp8918_master_vol_scale, -12550, 50, 0); + +static const struct snd_kcontrol_new ntp8918_vol_control[] = { + SOC_SINGLE_RANGE_TLV("Playback Volume", NTP8918_MASTER_VOL, 0, + 0x04, 0xff, 0, ntp8918_master_vol_scale), + SOC_SINGLE("Playback Switch", NTP8918_PWM_MASK_CTRL0, 1, 1, 1), +}; + +static void ntp8918_reset_gpio(struct ntp8918_priv *ntp8918) +{ + /* + * Proper initialization sequence for NTP8918 amplifier requires driving + * /RESET signal low during power up for at least 0.1us. The sequence is, + * according to NTP8918 datasheet, 6.2 Timing Sequence 1: + * Deassert for T2 >= 1ms... + */ + reset_control_deassert(ntp8918->reset); + fsleep(1000); + + /* ...Assert for T3 >= 0.1us... */ + reset_control_assert(ntp8918->reset); + fsleep(1); + + /* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */ + reset_control_deassert(ntp8918->reset); + fsleep(500); +} + +static const struct reg_sequence ntp8918_sound_off[] = { + { NTP8918_MASTER_VOL, 0 }, +}; + +static const struct reg_sequence ntp8918_sound_on[] = { + { NTP8918_MASTER_VOL, 0b11 }, +}; + +static int ntp8918_load_firmware(struct ntp8918_priv *ntp8918) +{ + int ret; + + ret = ntpfw_load(ntp8918->i2c, NTP8918_FW_NAME, NTP8918_FW_MAGIC); + if (ret == -ENOENT) { + dev_warn_once(&ntp8918->i2c->dev, "Could not find firmware %s\n", + NTP8918_FW_NAME); + return 0; + } + + return ret; +} + +static int ntp8918_snd_suspend(struct snd_soc_component *component) +{ + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(component->regmap, true); + + regmap_multi_reg_write_bypassed(component->regmap, + ntp8918_sound_off, + ARRAY_SIZE(ntp8918_sound_off)); + + /* + * According to NTP8918 datasheet, 6.2 Timing Sequence 1: + * wait after sound off for T6 >= 0.5ms + */ + fsleep(500); + reset_control_assert(ntp8918->reset); + + regcache_mark_dirty(component->regmap); + clk_disable_unprepare(ntp8918->bck); + + return 0; +} + +static int ntp8918_snd_resume(struct snd_soc_component *component) +{ + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + int ret; + + ret = clk_prepare_enable(ntp8918->bck); + if (ret) + return ret; + + ntp8918_reset_gpio(ntp8918); + + regmap_multi_reg_write_bypassed(component->regmap, + ntp8918_sound_on, + ARRAY_SIZE(ntp8918_sound_on)); + + ret = ntp8918_load_firmware(ntp8918); + if (ret) { + dev_err(&ntp8918->i2c->dev, "Failed to load firmware\n"); + return ret; + } + + regcache_cache_only(component->regmap, false); + snd_soc_component_cache_sync(component); + + return 0; +} + +static int ntp8918_probe(struct snd_soc_component *component) +{ + int ret; + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + struct device *dev = component->dev; + + ret = snd_soc_add_component_controls(component, ntp8918_vol_control, + ARRAY_SIZE(ntp8918_vol_control)); + if (ret) + return dev_err_probe(dev, ret, "Failed to add controls\n"); + + ret = ntp8918_load_firmware(ntp8918); + if (ret) + return dev_err_probe(dev, ret, "Failed to load firmware\n"); + + return 0; +} + +static const struct snd_soc_dapm_widget ntp8918_dapm_widgets[] = { + SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OUT1"), + SND_SOC_DAPM_OUTPUT("OUT2"), +}; + +static const struct snd_soc_dapm_route ntp8918_dapm_routes[] = { + { "OUT1", NULL, "AIFIN" }, + { "OUT2", NULL, "AIFIN" }, +}; + +static const struct snd_soc_component_driver soc_component_ntp8918 = { + .probe = ntp8918_probe, + .suspend = ntp8918_snd_suspend, + .resume = ntp8918_snd_resume, + .dapm_widgets = ntp8918_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ntp8918_dapm_widgets), + .dapm_routes = ntp8918_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(ntp8918_dapm_routes), +}; + +static int ntp8918_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + unsigned int input_fmt = 0; + unsigned int gsa_fmt = 0; + unsigned int gsa_fmt_mask; + unsigned int mcf; + int bclk; + int ret; + + bclk = snd_soc_params_to_bclk(params); + switch (bclk) { + case 3072000: + case 2822400: + mcf = 0; + break; + case 6144000: + mcf = 1; + break; + case 2048000: + mcf = 2; + break; + default: + return -EINVAL; + } + + ret = snd_soc_component_update_bits(component, NTP8918_MCLK_FREQ_CTRL, + NTP8918_MCLK_FREQ_MCF, mcf); + if (ret) + return ret; + + switch (ntp8918->format) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + input_fmt |= NTP8918_INPUT_FMT_GSA_MODE; + gsa_fmt |= NTP8918_GSA_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + input_fmt |= NTP8918_INPUT_FMT_GSA_MODE; + break; + } + + ret = snd_soc_component_update_bits(component, NTP8918_INPUT_FMT, + NTP8918_INPUT_FMT_MASTER_MODE | + NTP8918_INPUT_FMT_GSA_MODE, + input_fmt); + + if (!(input_fmt & NTP8918_INPUT_FMT_GSA_MODE) || ret < 0) + return ret; + + switch (params_width(params)) { + case 24: + gsa_fmt |= NTP8918_GSA_BS(0); + break; + case 20: + gsa_fmt |= NTP8918_GSA_BS(1); + break; + case 18: + gsa_fmt |= NTP8918_GSA_BS(2); + break; + case 16: + gsa_fmt |= NTP8918_GSA_BS(3); + break; + default: + return -EINVAL; + } + + gsa_fmt_mask = NTP8918_GSA_BS_MASK | + NTP8918_GSA_RIGHT_J | + NTP8918_GSA_LSB; + return snd_soc_component_update_bits(component, NTP8918_GSA_FMT, + gsa_fmt_mask, gsa_fmt); +} + +static int ntp8918_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct ntp8918_priv *ntp8918 = snd_soc_component_get_drvdata(component); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + ntp8918->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + return 0; +} + +static int ntp8918_digital_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + unsigned int mute_mask = NTP8918_SOFT_MUTE_SM1 | + NTP8918_SOFT_MUTE_SM2; + + return snd_soc_component_update_bits(dai->component, NTP8918_SOFT_MUTE, + mute_mask, mute ? mute_mask : 0); +} + +static const struct snd_soc_dai_ops ntp8918_dai_ops = { + .hw_params = ntp8918_hw_params, + .set_fmt = ntp8918_set_fmt, + .mute_stream = ntp8918_digital_mute, +}; + +static struct snd_soc_dai_driver ntp8918_dai = { + .name = "ntp8918-amplifier", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = NTP8918_RATES, + .formats = NTP8918_FORMATS, + }, + .ops = &ntp8918_dai_ops, +}; + +static const struct regmap_config ntp8918_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, + .cache_type = REGCACHE_MAPLE, +}; + +static int ntp8918_i2c_probe(struct i2c_client *i2c) +{ + struct ntp8918_priv *ntp8918; + int ret; + struct regmap *regmap; + + ntp8918 = devm_kzalloc(&i2c->dev, sizeof(*ntp8918), GFP_KERNEL); + if (!ntp8918) + return -ENOMEM; + + ntp8918->i2c = i2c; + + ntp8918->reset = devm_reset_control_get_shared(&i2c->dev, NULL); + if (IS_ERR(ntp8918->reset)) + return dev_err_probe(&i2c->dev, PTR_ERR(ntp8918->reset), "Failed to get reset\n"); + + dev_set_drvdata(&i2c->dev, ntp8918); + + ntp8918_reset_gpio(ntp8918); + + regmap = devm_regmap_init_i2c(i2c, &ntp8918_regmap); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(regmap), + "Failed to allocate regmap\n"); + + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8918, + &ntp8918_dai, 1); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to register component\n"); + + ntp8918->bck = devm_clk_get_enabled(&i2c->dev, "bck"); + if (IS_ERR(ntp8918->bck)) + return dev_err_probe(&i2c->dev, PTR_ERR(ntp8918->bck), "failed to get bck clock\n"); + + return 0; +} + +static const struct i2c_device_id ntp8918_i2c_id[] = { + { "ntp8918", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ntp8918_i2c_id); + +static const struct of_device_id ntp8918_of_match[] = { + {.compatible = "neofidelity,ntp8918"}, + {} +}; +MODULE_DEVICE_TABLE(of, ntp8918_of_match); + +static struct i2c_driver ntp8918_i2c_driver = { + .probe = ntp8918_i2c_probe, + .id_table = ntp8918_i2c_id, + .driver = { + .name = "ntp8918", + .of_match_table = ntp8918_of_match, + }, +}; +module_i2c_driver(ntp8918_i2c_driver); + +MODULE_AUTHOR("Igor Prusov "); +MODULE_DESCRIPTION("NTP8918 Audio Amplifier Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ntpfw.c b/sound/soc/codecs/ntpfw.c new file mode 100644 index 00000000000000..5ced2e966ab7d2 --- /dev/null +++ b/sound/soc/codecs/ntpfw.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntpfw.c - Firmware helper functions for Neofidelity codecs + * + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + */ + +#include +#include +#include + +#include "ntpfw.h" + +struct ntpfw_chunk { + __be16 length; + u8 step; + u8 data[]; +} __packed; + +struct ntpfw_header { + __be32 magic; +} __packed; + +static bool ntpfw_verify(struct device *dev, const u8 *buf, size_t buf_size, u32 magic) +{ + const struct ntpfw_header *header = (struct ntpfw_header *)buf; + u32 buf_magic; + + if (buf_size <= sizeof(*header)) { + dev_err(dev, "Failed to load firmware: image too small\n"); + return false; + } + + buf_magic = be32_to_cpu(header->magic); + if (buf_magic != magic) { + dev_err(dev, "Failed to load firmware: invalid magic 0x%x:\n", buf_magic); + return false; + } + + return true; +} + +static bool ntpfw_verify_chunk(struct device *dev, const struct ntpfw_chunk *chunk, size_t buf_size) +{ + size_t chunk_size; + + if (buf_size <= sizeof(*chunk)) { + dev_err(dev, "Failed to load firmware: chunk size too big\n"); + return false; + } + + if (chunk->step != 2 && chunk->step != 5) { + dev_err(dev, "Failed to load firmware: invalid chunk step: %d\n", chunk->step); + return false; + } + + chunk_size = be16_to_cpu(chunk->length); + if (chunk_size > buf_size) { + dev_err(dev, "Failed to load firmware: invalid chunk length\n"); + return false; + } + + if (chunk_size % chunk->step) { + dev_err(dev, "Failed to load firmware: chunk length and step mismatch\n"); + return false; + } + + return true; +} + +static int ntpfw_send_chunk(struct i2c_client *i2c, const struct ntpfw_chunk *chunk) +{ + int ret; + size_t i; + size_t length = be16_to_cpu(chunk->length); + + for (i = 0; i < length; i += chunk->step) { + ret = i2c_master_send(i2c, &chunk->data[i], chunk->step); + if (ret != chunk->step) { + dev_err(&i2c->dev, "I2C send failed: %d\n", ret); + return ret < 0 ? ret : -EIO; + } + } + + return 0; +} + +int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic) +{ + struct device *dev = &i2c->dev; + const struct ntpfw_chunk *chunk; + const struct firmware *fw; + const u8 *data; + size_t leftover; + int ret; + + ret = request_firmware(&fw, name, dev); + if (ret) { + dev_warn(dev, "request_firmware '%s' failed with %d\n", + name, ret); + return ret; + } + + if (!ntpfw_verify(dev, fw->data, fw->size, magic)) { + ret = -EINVAL; + goto done; + } + + data = fw->data + sizeof(struct ntpfw_header); + leftover = fw->size - sizeof(struct ntpfw_header); + + while (leftover) { + chunk = (struct ntpfw_chunk *)data; + + if (!ntpfw_verify_chunk(dev, chunk, leftover)) { + ret = -EINVAL; + goto done; + } + + ret = ntpfw_send_chunk(i2c, chunk); + if (ret) + goto done; + + data += be16_to_cpu(chunk->length) + sizeof(*chunk); + leftover -= be16_to_cpu(chunk->length) + sizeof(*chunk); + } + +done: + release_firmware(fw); + + return ret; +} +EXPORT_SYMBOL_GPL(ntpfw_load); + +MODULE_AUTHOR("Igor Prusov "); +MODULE_DESCRIPTION("Helper for loading Neofidelity amplifiers firmware"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ntpfw.h b/sound/soc/codecs/ntpfw.h new file mode 100644 index 00000000000000..1cf10d5480ee7f --- /dev/null +++ b/sound/soc/codecs/ntpfw.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/** + * ntpfw.h - Firmware helper functions for Neofidelity codecs + * + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + */ + +#ifndef __NTPFW_H__ +#define __NTPFW_H__ +#include +#include + +/** + * ntpfw_load - load firmware to amplifier over i2c interface. + * + * @i2c Pointer to amplifier's I2C client. + * @name Firmware file name. + * @magic Magic number to validate firmware. + * @return 0 or error code upon error. + */ +int ntpfw_load(struct i2c_client *i2c, const char *name, const u32 magic); + +#endif /* __NTPFW_H__ */ diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c index 451a8fd8fac506..13443f569ddb4d 100644 --- a/sound/soc/codecs/pcm186x.c +++ b/sound/soc/codecs/pcm186x.c @@ -566,7 +566,7 @@ static int pcm186x_set_bias_level(struct snd_soc_component *component, return 0; } -static struct snd_soc_component_driver soc_codec_dev_pcm1863 = { +static const struct snd_soc_component_driver soc_codec_dev_pcm1863 = { .set_bias_level = pcm186x_set_bias_level, .controls = pcm1863_snd_controls, .num_controls = ARRAY_SIZE(pcm1863_snd_controls), @@ -579,7 +579,7 @@ static struct snd_soc_component_driver soc_codec_dev_pcm1863 = { .endianness = 1, }; -static struct snd_soc_component_driver soc_codec_dev_pcm1865 = { +static const struct snd_soc_component_driver soc_codec_dev_pcm1865 = { .set_bias_level = pcm186x_set_bias_level, .controls = pcm1865_snd_controls, .num_controls = ARRAY_SIZE(pcm1865_snd_controls), diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c index 3401a25341e616..9bca53de2475f0 100644 --- a/sound/soc/codecs/pcm5102a.c +++ b/sound/soc/codecs/pcm5102a.c @@ -24,7 +24,7 @@ static struct snd_soc_dai_driver pcm5102a_dai = { }, }; -static struct snd_soc_component_driver soc_component_dev_pcm5102a = { +static const struct snd_soc_component_driver soc_component_dev_pcm5102a = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, diff --git a/sound/soc/codecs/rt-sdw-common.c b/sound/soc/codecs/rt-sdw-common.c new file mode 100644 index 00000000000000..ad61943ce75ffc --- /dev/null +++ b/sound/soc/codecs/rt-sdw-common.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt-sdw-common.c +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// + +/* + * This file defines common functions used with Realtek soundwire codecs. + */ + +#include +#include +#include +#include +#include + +#include "rt-sdw-common.h" + +/** + * rt_sdca_index_write - Write a value to Realtek defined register. + * + * @map: map for setting. + * @nid: Realtek-defined ID. + * @reg: register. + * @value: value. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int rt_sdca_index_write(struct regmap *map, unsigned int nid, + unsigned int reg, unsigned int value) +{ + unsigned int addr = (nid << 20) | reg; + int ret; + + ret = regmap_write(map, addr, value); + if (ret < 0) + pr_err("Failed to set value: %06x <= %04x ret=%d\n", + addr, value, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(rt_sdca_index_write); + +/** + * rt_sdca_index_read - Read value from Realtek defined register. + * + * @map: map for setting. + * @nid: Realtek-defined ID. + * @reg: register. + * @value: value. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +int rt_sdca_index_read(struct regmap *map, unsigned int nid, + unsigned int reg, unsigned int *value) +{ + unsigned int addr = (nid << 20) | reg; + int ret; + + ret = regmap_read(map, addr, value); + if (ret < 0) + pr_err("Failed to get value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(rt_sdca_index_read); + +/** + * rt_sdca_index_update_bits - Update value on Realtek defined register. + * + * @map: map for setting. + * @nid: Realtek-defined ID. + * @reg: register. + * @mask: Bitmask to change + * @val: New value for bitmask + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ + +int rt_sdca_index_update_bits(struct regmap *map, + unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp; + int ret; + + ret = rt_sdca_index_read(map, nid, reg, &tmp); + if (ret < 0) + return ret; + + set_mask_bits(&tmp, mask, val); + return rt_sdca_index_write(map, nid, reg, tmp); +} +EXPORT_SYMBOL_GPL(rt_sdca_index_update_bits); + +/** + * rt_sdca_btn_type - Decision of button type. + * + * @buffer: UMP message buffer. + * + * A button type will be returned regarding to buffer, + * it returns zero if buffer cannot be recognized. + */ +int rt_sdca_btn_type(unsigned char *buffer) +{ + u8 btn_type = 0; + int ret = 0; + + btn_type |= buffer[0] & 0xf; + btn_type |= (buffer[0] >> 4) & 0xf; + btn_type |= buffer[1] & 0xf; + btn_type |= (buffer[1] >> 4) & 0xf; + + if (btn_type & BIT(0)) + ret |= SND_JACK_BTN_2; + if (btn_type & BIT(1)) + ret |= SND_JACK_BTN_3; + if (btn_type & BIT(2)) + ret |= SND_JACK_BTN_0; + if (btn_type & BIT(3)) + ret |= SND_JACK_BTN_1; + + return ret; +} +EXPORT_SYMBOL_GPL(rt_sdca_btn_type); + +/** + * rt_sdca_headset_detect - Headset jack type detection. + * + * @map: map for setting. + * @entity_id: SDCA entity ID. + * + * A headset jack type will be returned, a negative errno will + * be returned in error cases. + */ +int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id) +{ + unsigned int det_mode, jack_type; + int ret; + + /* get detected_mode */ + ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id, + RT_SDCA_CTL_DETECTED_MODE, 0), &det_mode); + + if (ret < 0) + goto io_error; + + switch (det_mode) { + case 0x03: + jack_type = SND_JACK_HEADPHONE; + break; + case 0x05: + jack_type = SND_JACK_HEADSET; + break; + default: + jack_type = 0; + break; + } + + /* write selected_mode */ + if (det_mode) { + ret = regmap_write(map, SDW_SDCA_CTL(SDCA_NUM_JACK_CODEC, entity_id, + RT_SDCA_CTL_SELECTED_MODE, 0), det_mode); + if (ret < 0) + goto io_error; + } + + return jack_type; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL_GPL(rt_sdca_headset_detect); + +/** + * rt_sdca_button_detect - Read UMP message and decide button type. + * + * @map: map for setting. + * @entity_id: SDCA entity ID. + * @hid_buf_addr: HID buffer address. + * @hid_id: Report ID for HID. + * + * A button type will be returned regarding to buffer, + * it returns zero if buffer cannot be recognized. + */ +int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id, + unsigned int hid_buf_addr, unsigned int hid_id) +{ + unsigned int btn_type = 0, offset, idx, val, owner; + unsigned char buf[3]; + int ret; + + /* get current UMP message owner */ + ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, + RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner); + if (ret < 0) + return 0; + + /* if owner is device then there is no button event from device */ + if (owner == 1) + return 0; + + /* read UMP message offset */ + ret = regmap_read(map, SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, + RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset); + if (ret < 0) + goto _end_btn_det_; + + for (idx = 0; idx < sizeof(buf); idx++) { + ret = regmap_read(map, hid_buf_addr + offset + idx, &val); + if (ret < 0) + goto _end_btn_det_; + buf[idx] = val & 0xff; + } + /* Report ID for HID */ + if (buf[0] == hid_id) + btn_type = rt_sdca_btn_type(&buf[1]); + +_end_btn_det_: + /* Host is owner, so set back to device */ + if (owner == 0) + /* set owner to device */ + regmap_write(map, + SDW_SDCA_CTL(SDCA_NUM_HID, entity_id, + RT_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01); + + return btn_type; +} +EXPORT_SYMBOL_GPL(rt_sdca_button_detect); + +MODULE_DESCRIPTION("Realtek soundwire common functions"); +MODULE_AUTHOR("jack yu "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt-sdw-common.h b/sound/soc/codecs/rt-sdw-common.h new file mode 100644 index 00000000000000..4759516feb3888 --- /dev/null +++ b/sound/soc/codecs/rt-sdw-common.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +// +// rt-sdw-common.h +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// + +/* + * This file defines common functions used with Realtek soundwire codecs. + */ + +#ifndef __RT_SDW_COMMON_H__ +#define __RT_SDW_COMMON_H__ + +#define SDCA_NUM_JACK_CODEC 0x01 +#define SDCA_NUM_MIC_ARRAY 0x02 +#define SDCA_NUM_HID 0x03 +#define SDCA_NUM_AMP 0x04 +#define RT_SDCA_CTL_SELECTED_MODE 0x01 +#define RT_SDCA_CTL_DETECTED_MODE 0x02 +#define RT_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10 +#define RT_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12 + +struct rt_sdca_dmic_kctrl_priv { + unsigned int reg_base; + unsigned int count; + unsigned int max; + unsigned int invert; +}; + +#define RT_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \ + ((unsigned long)&(struct rt_sdca_dmic_kctrl_priv) \ + {.reg_base = xreg_base, .count = xcount, .max = xmax, \ + .invert = xinvert}) + +#define RT_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount, \ + xinfo, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = xinfo, \ + .get = xget, \ + .put = xput, \ + .private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)} + +#define RT_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\ + xhandler_put, xcount, xmax, tlv_array, xinfo) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = xinfo, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = RT_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) } + + +int rt_sdca_index_write(struct regmap *map, unsigned int nid, + unsigned int reg, unsigned int value); +int rt_sdca_index_read(struct regmap *map, unsigned int nid, + unsigned int reg, unsigned int *value); +int rt_sdca_index_update_bits(struct regmap *map, + unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val); +int rt_sdca_btn_type(unsigned char *buffer); +int rt_sdca_headset_detect(struct regmap *map, unsigned int entity_id); +int rt_sdca_button_detect(struct regmap *map, unsigned int entity_id, + unsigned int hid_buf_addr, unsigned int hid_id); + +#endif /* __RT_SDW_COMMON_H__ */ diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index f4e1ea29c26513..3510c3819074b4 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -21,6 +21,7 @@ #include #include #include "rt1320-sdw.h" +#include "rt-sdw-common.h" /* * The 'blind writes' is an SDCA term to deal with platform-specific initialization. @@ -89,6 +90,25 @@ static const struct reg_sequence rt1320_blind_write[] = { { 0xc019, 0x10 }, { 0xd487, 0x3f }, { 0xd486, 0xc3 }, + { 0x3fc2bfc7, 0x00 }, + { 0x3fc2bfc6, 0x00 }, + { 0x3fc2bfc5, 0x00 }, + { 0x3fc2bfc4, 0x01 }, + { 0x0000d486, 0x43 }, + { 0x1000db00, 0x02 }, + { 0x1000db01, 0x00 }, + { 0x1000db02, 0x11 }, + { 0x1000db03, 0x00 }, + { 0x1000db04, 0x00 }, + { 0x1000db05, 0x82 }, + { 0x1000db06, 0x04 }, + { 0x1000db07, 0xf1 }, + { 0x1000db08, 0x00 }, + { 0x1000db09, 0x00 }, + { 0x1000db0a, 0x40 }, + { 0x0000d540, 0x01 }, + { 0xd172, 0x2a }, + { 0xc5d6, 0x01 }, }; static const struct reg_sequence rt1320_vc_blind_write[] = { @@ -148,6 +168,12 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0xd487, 0x3b }, { 0xd486, 0xc3 }, { 0xc598, 0x04 }, + { 0xdb03, 0xf0 }, + { 0xdb09, 0x00 }, + { 0xdb08, 0x7a }, + { 0xdb19, 0x02 }, + { 0xdb07, 0x5a }, + { 0xdb05, 0x45 }, { 0xd500, 0x00 }, { 0xd500, 0x17 }, { 0xd600, 0x01 }, @@ -164,1913 +190,6 @@ static const struct reg_sequence rt1320_vc_blind_write[] = { { 0xd610, 0x01 }, { 0xd608, 0x03 }, { 0xd609, 0x00 }, -}; - -static const struct reg_sequence rt1320_vc_patch_code_write[] = { - { 0x10007000, 0x37 }, - { 0x10007001, 0x77 }, - { 0x10007002, 0x00 }, - { 0x10007003, 0x10 }, - { 0x10007004, 0xb7 }, - { 0x10007005, 0xe7 }, - { 0x10007006, 0x00 }, - { 0x10007007, 0x10 }, - { 0x10007008, 0x13 }, - { 0x10007009, 0x07 }, - { 0x1000700a, 0x87 }, - { 0x1000700b, 0x48 }, - { 0x1000700c, 0x23 }, - { 0x1000700d, 0xa6 }, - { 0x1000700e, 0xe7 }, - { 0x1000700f, 0xee }, - { 0x10007010, 0x37 }, - { 0x10007011, 0x77 }, - { 0x10007012, 0x00 }, - { 0x10007013, 0x10 }, - { 0x10007014, 0x13 }, - { 0x10007015, 0x07 }, - { 0x10007016, 0x87 }, - { 0x10007017, 0x56 }, - { 0x10007018, 0x23 }, - { 0x10007019, 0xac }, - { 0x1000701a, 0xe7 }, - { 0x1000701b, 0xde }, - { 0x1000701c, 0x37 }, - { 0x1000701d, 0x77 }, - { 0x1000701e, 0x00 }, - { 0x1000701f, 0x10 }, - { 0x10007020, 0x13 }, - { 0x10007021, 0x07 }, - { 0x10007022, 0xc7 }, - { 0x10007023, 0x5f }, - { 0x10007024, 0x23 }, - { 0x10007025, 0xae }, - { 0x10007026, 0xe7 }, - { 0x10007027, 0xdc }, - { 0x10007028, 0x37 }, - { 0x10007029, 0x87 }, - { 0x1000702a, 0x00 }, - { 0x1000702b, 0x10 }, - { 0x1000702c, 0x13 }, - { 0x1000702d, 0x07 }, - { 0x1000702e, 0xc7 }, - { 0x1000702f, 0x86 }, - { 0x10007030, 0x23 }, - { 0x10007031, 0xae }, - { 0x10007032, 0xe7 }, - { 0x10007033, 0xe6 }, - { 0x10007034, 0x37 }, - { 0x10007035, 0x77 }, - { 0x10007036, 0x00 }, - { 0x10007037, 0x10 }, - { 0x10007038, 0x13 }, - { 0x10007039, 0x07 }, - { 0x1000703a, 0x07 }, - { 0x1000703b, 0x40 }, - { 0x1000703c, 0x23 }, - { 0x1000703d, 0xa6 }, - { 0x1000703e, 0xe7 }, - { 0x1000703f, 0xe8 }, - { 0x10007040, 0x37 }, - { 0x10007041, 0x77 }, - { 0x10007042, 0x00 }, - { 0x10007043, 0x10 }, - { 0x10007044, 0x13 }, - { 0x10007045, 0x07 }, - { 0x10007046, 0xc7 }, - { 0x10007047, 0x63 }, - { 0x10007048, 0x23 }, - { 0x10007049, 0xa2 }, - { 0x1000704a, 0xe7 }, - { 0x1000704b, 0xec }, - { 0x1000704c, 0x37 }, - { 0x1000704d, 0x77 }, - { 0x1000704e, 0x00 }, - { 0x1000704f, 0x10 }, - { 0x10007050, 0x13 }, - { 0x10007051, 0x07 }, - { 0x10007052, 0x47 }, - { 0x10007053, 0x6f }, - { 0x10007054, 0x23 }, - { 0x10007055, 0xa6 }, - { 0x10007056, 0xe7 }, - { 0x10007057, 0xec }, - { 0x10007058, 0x37 }, - { 0x10007059, 0x77 }, - { 0x1000705a, 0x00 }, - { 0x1000705b, 0x10 }, - { 0x1000705c, 0x13 }, - { 0x1000705d, 0x07 }, - { 0x1000705e, 0x07 }, - { 0x1000705f, 0x44 }, - { 0x10007060, 0x23 }, - { 0x10007061, 0xa8 }, - { 0x10007062, 0xe7 }, - { 0x10007063, 0xec }, - { 0x10007064, 0x37 }, - { 0x10007065, 0x87 }, - { 0x10007066, 0x00 }, - { 0x10007067, 0x10 }, - { 0x10007068, 0x13 }, - { 0x10007069, 0x07 }, - { 0x1000706a, 0x87 }, - { 0x1000706b, 0x84 }, - { 0x1000706c, 0x23 }, - { 0x1000706d, 0xa8 }, - { 0x1000706e, 0xe7 }, - { 0x1000706f, 0xee }, - { 0x10007070, 0x37 }, - { 0x10007071, 0x87 }, - { 0x10007072, 0x00 }, - { 0x10007073, 0x10 }, - { 0x10007074, 0x13 }, - { 0x10007075, 0x07 }, - { 0x10007076, 0x47 }, - { 0x10007077, 0x97 }, - { 0x10007078, 0x23 }, - { 0x10007079, 0xaa }, - { 0x1000707a, 0xe7 }, - { 0x1000707b, 0xee }, - { 0x1000707c, 0x67 }, - { 0x1000707d, 0x80 }, - { 0x1000707e, 0x00 }, - { 0x1000707f, 0x00 }, - { 0x10007400, 0xb7 }, - { 0x10007401, 0xd6 }, - { 0x10007402, 0x00 }, - { 0x10007403, 0x00 }, - { 0x10007404, 0x83 }, - { 0x10007405, 0xc7 }, - { 0x10007406, 0x06 }, - { 0x10007407, 0x47 }, - { 0x10007408, 0x93 }, - { 0x10007409, 0xf7 }, - { 0x1000740a, 0x87 }, - { 0x1000740b, 0x00 }, - { 0x1000740c, 0x63 }, - { 0x1000740d, 0x88 }, - { 0x1000740e, 0x07 }, - { 0x1000740f, 0x02 }, - { 0x10007410, 0x03 }, - { 0x10007411, 0xc7 }, - { 0x10007412, 0x31 }, - { 0x10007413, 0x43 }, - { 0x10007414, 0x63 }, - { 0x10007415, 0x14 }, - { 0x10007416, 0x07 }, - { 0x10007417, 0x02 }, - { 0x10007418, 0x13 }, - { 0x10007419, 0x07 }, - { 0x1000741a, 0x10 }, - { 0x1000741b, 0x00 }, - { 0x1000741c, 0xa3 }, - { 0x1000741d, 0x89 }, - { 0x1000741e, 0xe1 }, - { 0x1000741f, 0x42 }, - { 0x10007420, 0x37 }, - { 0x10007421, 0xc7 }, - { 0x10007422, 0x00 }, - { 0x10007423, 0x00 }, - { 0x10007424, 0x03 }, - { 0x10007425, 0x46 }, - { 0x10007426, 0x07 }, - { 0x10007427, 0x06 }, - { 0x10007428, 0x23 }, - { 0x10007429, 0x8a }, - { 0x1000742a, 0xc1 }, - { 0x1000742b, 0x42 }, - { 0x1000742c, 0x83 }, - { 0x1000742d, 0xc7 }, - { 0x1000742e, 0x46 }, - { 0x1000742f, 0x47 }, - { 0x10007430, 0x93 }, - { 0x10007431, 0xf7 }, - { 0x10007432, 0xf7 }, - { 0x10007433, 0x0f }, - { 0x10007434, 0x23 }, - { 0x10007435, 0x00 }, - { 0x10007436, 0xf7 }, - { 0x10007437, 0x06 }, - { 0x10007438, 0x23 }, - { 0x10007439, 0x89 }, - { 0x1000743a, 0x01 }, - { 0x1000743b, 0x42 }, - { 0x1000743c, 0x67 }, - { 0x1000743d, 0x80 }, - { 0x1000743e, 0x00 }, - { 0x1000743f, 0x00 }, - { 0x10007440, 0x37 }, - { 0x10007441, 0xc7 }, - { 0x10007442, 0x00 }, - { 0x10007443, 0x00 }, - { 0x10007444, 0x83 }, - { 0x10007445, 0x27 }, - { 0x10007446, 0xc7 }, - { 0x10007447, 0x5f }, - { 0x10007448, 0x13 }, - { 0x10007449, 0x05 }, - { 0x1000744a, 0x00 }, - { 0x1000744b, 0x00 }, - { 0x1000744c, 0x23 }, - { 0x1000744d, 0xa2 }, - { 0x1000744e, 0xf1 }, - { 0x1000744f, 0x42 }, - { 0x10007450, 0xb7 }, - { 0x10007451, 0x06 }, - { 0x10007452, 0x00 }, - { 0x10007453, 0x10 }, - { 0x10007454, 0xb3 }, - { 0x10007455, 0xf7 }, - { 0x10007456, 0xd7 }, - { 0x10007457, 0x00 }, - { 0x10007458, 0x63 }, - { 0x10007459, 0x86 }, - { 0x1000745a, 0x07 }, - { 0x1000745b, 0x02 }, - { 0x1000745c, 0x83 }, - { 0x1000745d, 0x47 }, - { 0x1000745e, 0x07 }, - { 0x1000745f, 0x56 }, - { 0x10007460, 0x93 }, - { 0x10007461, 0xf7 }, - { 0x10007462, 0x87 }, - { 0x10007463, 0x01 }, - { 0x10007464, 0x63 }, - { 0x10007465, 0x80 }, - { 0x10007466, 0x07 }, - { 0x10007467, 0x02 }, - { 0x10007468, 0x83 }, - { 0x10007469, 0x47 }, - { 0x1000746a, 0x17 }, - { 0x1000746b, 0x08 }, - { 0x1000746c, 0x93 }, - { 0x1000746d, 0xf7 }, - { 0x1000746e, 0x47 }, - { 0x1000746f, 0x00 }, - { 0x10007470, 0x63 }, - { 0x10007471, 0x8a }, - { 0x10007472, 0x07 }, - { 0x10007473, 0x00 }, - { 0x10007474, 0xb7 }, - { 0x10007475, 0xc7 }, - { 0x10007476, 0xc2 }, - { 0x10007477, 0x3f }, - { 0x10007478, 0x03 }, - { 0x10007479, 0xa5 }, - { 0x1000747a, 0x47 }, - { 0x1000747b, 0xfc }, - { 0x1000747c, 0x13 }, - { 0x1000747d, 0x55 }, - { 0x1000747e, 0x25 }, - { 0x1000747f, 0x00 }, - { 0x10007480, 0x13 }, - { 0x10007481, 0x75 }, - { 0x10007482, 0x15 }, - { 0x10007483, 0x00 }, - { 0x10007484, 0x67 }, - { 0x10007485, 0x80 }, - { 0x10007486, 0x00 }, - { 0x10007487, 0x00 }, - { 0x10007488, 0x03 }, - { 0x10007489, 0xa7 }, - { 0x1000748a, 0x81 }, - { 0x1000748b, 0x57 }, - { 0x1000748c, 0x13 }, - { 0x1000748d, 0x01 }, - { 0x1000748e, 0x01 }, - { 0x1000748f, 0xff }, - { 0x10007490, 0x23 }, - { 0x10007491, 0x26 }, - { 0x10007492, 0x11 }, - { 0x10007493, 0x00 }, - { 0x10007494, 0x23 }, - { 0x10007495, 0x24 }, - { 0x10007496, 0x81 }, - { 0x10007497, 0x00 }, - { 0x10007498, 0x23 }, - { 0x10007499, 0x22 }, - { 0x1000749a, 0x91 }, - { 0x1000749b, 0x00 }, - { 0x1000749c, 0x93 }, - { 0x1000749d, 0x07 }, - { 0x1000749e, 0xa0 }, - { 0x1000749f, 0x05 }, - { 0x100074a0, 0x63 }, - { 0x100074a1, 0x14 }, - { 0x100074a2, 0xf7 }, - { 0x100074a3, 0x04 }, - { 0x100074a4, 0x37 }, - { 0x100074a5, 0x07 }, - { 0x100074a6, 0x00 }, - { 0x100074a7, 0x11 }, - { 0x100074a8, 0x83 }, - { 0x100074a9, 0x47 }, - { 0x100074aa, 0x07 }, - { 0x100074ab, 0x01 }, - { 0x100074ac, 0x13 }, - { 0x100074ad, 0x06 }, - { 0x100074ae, 0x30 }, - { 0x100074af, 0x00 }, - { 0x100074b0, 0x93 }, - { 0x100074b1, 0xf7 }, - { 0x100074b2, 0xf7 }, - { 0x100074b3, 0x0f }, - { 0x100074b4, 0x63 }, - { 0x100074b5, 0x9a }, - { 0x100074b6, 0xc7 }, - { 0x100074b7, 0x02 }, - { 0x100074b8, 0x03 }, - { 0x100074b9, 0x47 }, - { 0x100074ba, 0x87 }, - { 0x100074bb, 0x01 }, - { 0x100074bc, 0x13 }, - { 0x100074bd, 0x77 }, - { 0x100074be, 0xf7 }, - { 0x100074bf, 0x0f }, - { 0x100074c0, 0x63 }, - { 0x100074c1, 0x14 }, - { 0x100074c2, 0xf7 }, - { 0x100074c3, 0x02 }, - { 0x100074c4, 0x37 }, - { 0x100074c5, 0xd7 }, - { 0x100074c6, 0x00 }, - { 0x100074c7, 0x00 }, - { 0x100074c8, 0x83 }, - { 0x100074c9, 0x47 }, - { 0x100074ca, 0x37 }, - { 0x100074cb, 0x54 }, - { 0x100074cc, 0x93 }, - { 0x100074cd, 0xf7 }, - { 0x100074ce, 0xf7 }, - { 0x100074cf, 0x0f }, - { 0x100074d0, 0x93 }, - { 0x100074d1, 0xe7 }, - { 0x100074d2, 0x07 }, - { 0x100074d3, 0x02 }, - { 0x100074d4, 0xa3 }, - { 0x100074d5, 0x01 }, - { 0x100074d6, 0xf7 }, - { 0x100074d7, 0x54 }, - { 0x100074d8, 0x83 }, - { 0x100074d9, 0x47 }, - { 0x100074da, 0x37 }, - { 0x100074db, 0x54 }, - { 0x100074dc, 0x93 }, - { 0x100074dd, 0xf7 }, - { 0x100074de, 0xf7 }, - { 0x100074df, 0x0d }, - { 0x100074e0, 0xa3 }, - { 0x100074e1, 0x01 }, - { 0x100074e2, 0xf7 }, - { 0x100074e3, 0x54 }, - { 0x100074e4, 0x23 }, - { 0x100074e5, 0xac }, - { 0x100074e6, 0x01 }, - { 0x100074e7, 0x56 }, - { 0x100074e8, 0x37 }, - { 0x100074e9, 0xd4 }, - { 0x100074ea, 0x00 }, - { 0x100074eb, 0x00 }, - { 0x100074ec, 0x83 }, - { 0x100074ed, 0x47 }, - { 0x100074ee, 0xd4 }, - { 0x100074ef, 0x47 }, - { 0x100074f0, 0x93 }, - { 0x100074f1, 0xf7 }, - { 0x100074f2, 0x17 }, - { 0x100074f3, 0x00 }, - { 0x100074f4, 0x63 }, - { 0x100074f5, 0x80 }, - { 0x100074f6, 0x07 }, - { 0x100074f7, 0x06 }, - { 0x100074f8, 0x37 }, - { 0x100074f9, 0xd7 }, - { 0x100074fa, 0x00 }, - { 0x100074fb, 0x10 }, - { 0x100074fc, 0x83 }, - { 0x100074fd, 0x47 }, - { 0x100074fe, 0x77 }, - { 0x100074ff, 0xd9 }, - { 0x10007500, 0x93 }, - { 0x10007501, 0x87 }, - { 0x10007502, 0x17 }, - { 0x10007503, 0x00 }, - { 0x10007504, 0x93 }, - { 0x10007505, 0xf7 }, - { 0x10007506, 0xf7 }, - { 0x10007507, 0x0f }, - { 0x10007508, 0xa3 }, - { 0x10007509, 0x0b }, - { 0x1000750a, 0xf7 }, - { 0x1000750b, 0xd8 }, - { 0x1000750c, 0x03 }, - { 0x1000750d, 0x47 }, - { 0x1000750e, 0x77 }, - { 0x1000750f, 0xd9 }, - { 0x10007510, 0x83 }, - { 0x10007511, 0x47 }, - { 0x10007512, 0xc4 }, - { 0x10007513, 0x47 }, - { 0x10007514, 0x13 }, - { 0x10007515, 0x77 }, - { 0x10007516, 0xf7 }, - { 0x10007517, 0x0f }, - { 0x10007518, 0x93 }, - { 0x10007519, 0xf7 }, - { 0x1000751a, 0xf7 }, - { 0x1000751b, 0x0f }, - { 0x1000751c, 0x63 }, - { 0x1000751d, 0x6c }, - { 0x1000751e, 0xf7 }, - { 0x1000751f, 0x02 }, - { 0x10007520, 0xb7 }, - { 0x10007521, 0xf4 }, - { 0x10007522, 0x00 }, - { 0x10007523, 0x00 }, - { 0x10007524, 0x93 }, - { 0x10007525, 0x05 }, - { 0x10007526, 0x00 }, - { 0x10007527, 0x01 }, - { 0x10007528, 0x13 }, - { 0x10007529, 0x85 }, - { 0x1000752a, 0x34 }, - { 0x1000752b, 0x52 }, - { 0x1000752c, 0xef }, - { 0x1000752d, 0xa0 }, - { 0x1000752e, 0x8f }, - { 0x1000752f, 0xc6 }, - { 0x10007530, 0x93 }, - { 0x10007531, 0x05 }, - { 0x10007532, 0x00 }, - { 0x10007533, 0x00 }, - { 0x10007534, 0x13 }, - { 0x10007535, 0x85 }, - { 0x10007536, 0x54 }, - { 0x10007537, 0x10 }, - { 0x10007538, 0xef }, - { 0x10007539, 0xa0 }, - { 0x1000753a, 0xcf }, - { 0x1000753b, 0xc5 }, - { 0x1000753c, 0x93 }, - { 0x1000753d, 0x05 }, - { 0x1000753e, 0x00 }, - { 0x1000753f, 0x00 }, - { 0x10007540, 0x13 }, - { 0x10007541, 0x85 }, - { 0x10007542, 0x74 }, - { 0x10007543, 0x10 }, - { 0x10007544, 0xef }, - { 0x10007545, 0xa0 }, - { 0x10007546, 0x0f }, - { 0x10007547, 0xc5 }, - { 0x10007548, 0x83 }, - { 0x10007549, 0x47 }, - { 0x1000754a, 0xd4 }, - { 0x1000754b, 0x47 }, - { 0x1000754c, 0x93 }, - { 0x1000754d, 0xf7 }, - { 0x1000754e, 0xe7 }, - { 0x1000754f, 0x0f }, - { 0x10007550, 0xa3 }, - { 0x10007551, 0x0e }, - { 0x10007552, 0xf4 }, - { 0x10007553, 0x46 }, - { 0x10007554, 0x83 }, - { 0x10007555, 0x20 }, - { 0x10007556, 0xc1 }, - { 0x10007557, 0x00 }, - { 0x10007558, 0x03 }, - { 0x10007559, 0x24 }, - { 0x1000755a, 0x81 }, - { 0x1000755b, 0x00 }, - { 0x1000755c, 0x83 }, - { 0x1000755d, 0x24 }, - { 0x1000755e, 0x41 }, - { 0x1000755f, 0x00 }, - { 0x10007560, 0x13 }, - { 0x10007561, 0x01 }, - { 0x10007562, 0x01 }, - { 0x10007563, 0x01 }, - { 0x10007564, 0x67 }, - { 0x10007565, 0x80 }, - { 0x10007566, 0x00 }, - { 0x10007567, 0x00 }, - { 0x10007568, 0x13 }, - { 0x10007569, 0x01 }, - { 0x1000756a, 0x01 }, - { 0x1000756b, 0xff }, - { 0x1000756c, 0x23 }, - { 0x1000756d, 0x24 }, - { 0x1000756e, 0x81 }, - { 0x1000756f, 0x00 }, - { 0x10007570, 0x23 }, - { 0x10007571, 0x26 }, - { 0x10007572, 0x11 }, - { 0x10007573, 0x00 }, - { 0x10007574, 0x23 }, - { 0x10007575, 0x22 }, - { 0x10007576, 0x91 }, - { 0x10007577, 0x00 }, - { 0x10007578, 0x37 }, - { 0x10007579, 0xd4 }, - { 0x1000757a, 0x00 }, - { 0x1000757b, 0x00 }, - { 0x1000757c, 0x83 }, - { 0x1000757d, 0x47 }, - { 0x1000757e, 0x04 }, - { 0x1000757f, 0x54 }, - { 0x10007580, 0x93 }, - { 0x10007581, 0x97 }, - { 0x10007582, 0x87 }, - { 0x10007583, 0x01 }, - { 0x10007584, 0x93 }, - { 0x10007585, 0xd7 }, - { 0x10007586, 0x87 }, - { 0x10007587, 0x41 }, - { 0x10007588, 0x63 }, - { 0x10007589, 0xd0 }, - { 0x1000758a, 0x07 }, - { 0x1000758b, 0x06 }, - { 0x1000758c, 0xb7 }, - { 0x1000758d, 0xf4 }, - { 0x1000758e, 0x00 }, - { 0x1000758f, 0x00 }, - { 0x10007590, 0x93 }, - { 0x10007591, 0x05 }, - { 0x10007592, 0x60 }, - { 0x10007593, 0x01 }, - { 0x10007594, 0x13 }, - { 0x10007595, 0x85 }, - { 0x10007596, 0x34 }, - { 0x10007597, 0x52 }, - { 0x10007598, 0xef }, - { 0x10007599, 0xa0 }, - { 0x1000759a, 0xcf }, - { 0x1000759b, 0xbf }, - { 0x1000759c, 0x93 }, - { 0x1000759d, 0x05 }, - { 0x1000759e, 0x00 }, - { 0x1000759f, 0x04 }, - { 0x100075a0, 0x13 }, - { 0x100075a1, 0x85 }, - { 0x100075a2, 0x54 }, - { 0x100075a3, 0x10 }, - { 0x100075a4, 0xef }, - { 0x100075a5, 0xa0 }, - { 0x100075a6, 0x0f }, - { 0x100075a7, 0xbf }, - { 0x100075a8, 0x93 }, - { 0x100075a9, 0x05 }, - { 0x100075aa, 0x00 }, - { 0x100075ab, 0x04 }, - { 0x100075ac, 0x13 }, - { 0x100075ad, 0x85 }, - { 0x100075ae, 0x74 }, - { 0x100075af, 0x10 }, - { 0x100075b0, 0xef }, - { 0x100075b1, 0xa0 }, - { 0x100075b2, 0x4f }, - { 0x100075b3, 0xbe }, - { 0x100075b4, 0x83 }, - { 0x100075b5, 0x47 }, - { 0x100075b6, 0xd4 }, - { 0x100075b7, 0x47 }, - { 0x100075b8, 0x37 }, - { 0x100075b9, 0xd7 }, - { 0x100075ba, 0x00 }, - { 0x100075bb, 0x10 }, - { 0x100075bc, 0x93 }, - { 0x100075bd, 0xf7 }, - { 0x100075be, 0xf7 }, - { 0x100075bf, 0x0f }, - { 0x100075c0, 0x93 }, - { 0x100075c1, 0xe7 }, - { 0x100075c2, 0x17 }, - { 0x100075c3, 0x00 }, - { 0x100075c4, 0xa3 }, - { 0x100075c5, 0x0e }, - { 0x100075c6, 0xf4 }, - { 0x100075c7, 0x46 }, - { 0x100075c8, 0xa3 }, - { 0x100075c9, 0x0b }, - { 0x100075ca, 0x07 }, - { 0x100075cb, 0xd8 }, - { 0x100075cc, 0x83 }, - { 0x100075cd, 0x47 }, - { 0x100075ce, 0x87 }, - { 0x100075cf, 0xd9 }, - { 0x100075d0, 0x93 }, - { 0x100075d1, 0x87 }, - { 0x100075d2, 0x17 }, - { 0x100075d3, 0x00 }, - { 0x100075d4, 0x93 }, - { 0x100075d5, 0xf7 }, - { 0x100075d6, 0xf7 }, - { 0x100075d7, 0x0f }, - { 0x100075d8, 0x23 }, - { 0x100075d9, 0x0c }, - { 0x100075da, 0xf7 }, - { 0x100075db, 0xd8 }, - { 0x100075dc, 0x83 }, - { 0x100075dd, 0x47 }, - { 0x100075de, 0x04 }, - { 0x100075df, 0x54 }, - { 0x100075e0, 0x93 }, - { 0x100075e1, 0xf7 }, - { 0x100075e2, 0xf7 }, - { 0x100075e3, 0x07 }, - { 0x100075e4, 0x23 }, - { 0x100075e5, 0x00 }, - { 0x100075e6, 0xf4 }, - { 0x100075e7, 0x54 }, - { 0x100075e8, 0x83 }, - { 0x100075e9, 0x20 }, - { 0x100075ea, 0xc1 }, - { 0x100075eb, 0x00 }, - { 0x100075ec, 0x03 }, - { 0x100075ed, 0x24 }, - { 0x100075ee, 0x81 }, - { 0x100075ef, 0x00 }, - { 0x100075f0, 0x83 }, - { 0x100075f1, 0x24 }, - { 0x100075f2, 0x41 }, - { 0x100075f3, 0x00 }, - { 0x100075f4, 0x13 }, - { 0x100075f5, 0x01 }, - { 0x100075f6, 0x01 }, - { 0x100075f7, 0x01 }, - { 0x100075f8, 0x67 }, - { 0x100075f9, 0x80 }, - { 0x100075fa, 0x00 }, - { 0x100075fb, 0x00 }, - { 0x100075fc, 0x13 }, - { 0x100075fd, 0x01 }, - { 0x100075fe, 0x01 }, - { 0x100075ff, 0xff }, - { 0x10007600, 0x23 }, - { 0x10007601, 0x24 }, - { 0x10007602, 0x81 }, - { 0x10007603, 0x00 }, - { 0x10007604, 0x37 }, - { 0x10007605, 0xd4 }, - { 0x10007606, 0x00 }, - { 0x10007607, 0x00 }, - { 0x10007608, 0x83 }, - { 0x10007609, 0x27 }, - { 0x1000760a, 0x04 }, - { 0x1000760b, 0x53 }, - { 0x1000760c, 0x23 }, - { 0x1000760d, 0x22 }, - { 0x1000760e, 0x91 }, - { 0x1000760f, 0x00 }, - { 0x10007610, 0xb7 }, - { 0x10007611, 0x04 }, - { 0x10007612, 0x00 }, - { 0x10007613, 0x40 }, - { 0x10007614, 0x23 }, - { 0x10007615, 0x26 }, - { 0x10007616, 0x11 }, - { 0x10007617, 0x00 }, - { 0x10007618, 0xb3 }, - { 0x10007619, 0xf7 }, - { 0x1000761a, 0x97 }, - { 0x1000761b, 0x00 }, - { 0x1000761c, 0x63 }, - { 0x1000761d, 0x86 }, - { 0x1000761e, 0x07 }, - { 0x1000761f, 0x00 }, - { 0x10007620, 0xef }, - { 0x10007621, 0xd0 }, - { 0x10007622, 0x5f }, - { 0x10007623, 0xc2 }, - { 0x10007624, 0x23 }, - { 0x10007625, 0x28 }, - { 0x10007626, 0x94 }, - { 0x10007627, 0x52 }, - { 0x10007628, 0x83 }, - { 0x10007629, 0x20 }, - { 0x1000762a, 0xc1 }, - { 0x1000762b, 0x00 }, - { 0x1000762c, 0x03 }, - { 0x1000762d, 0x24 }, - { 0x1000762e, 0x81 }, - { 0x1000762f, 0x00 }, - { 0x10007630, 0x83 }, - { 0x10007631, 0x24 }, - { 0x10007632, 0x41 }, - { 0x10007633, 0x00 }, - { 0x10007634, 0x13 }, - { 0x10007635, 0x01 }, - { 0x10007636, 0x01 }, - { 0x10007637, 0x01 }, - { 0x10007638, 0x67 }, - { 0x10007639, 0x80 }, - { 0x1000763a, 0x00 }, - { 0x1000763b, 0x00 }, - { 0x1000763c, 0x37 }, - { 0x1000763d, 0xc7 }, - { 0x1000763e, 0x00 }, - { 0x1000763f, 0x00 }, - { 0x10007640, 0x83 }, - { 0x10007641, 0x27 }, - { 0x10007642, 0xc7 }, - { 0x10007643, 0x5f }, - { 0x10007644, 0x23 }, - { 0x10007645, 0xa2 }, - { 0x10007646, 0xf1 }, - { 0x10007647, 0x42 }, - { 0x10007648, 0xb7 }, - { 0x10007649, 0x06 }, - { 0x1000764a, 0x00 }, - { 0x1000764b, 0x10 }, - { 0x1000764c, 0xb3 }, - { 0x1000764d, 0xf7 }, - { 0x1000764e, 0xd7 }, - { 0x1000764f, 0x00 }, - { 0x10007650, 0x63 }, - { 0x10007651, 0x80 }, - { 0x10007652, 0x07 }, - { 0x10007653, 0x0a }, - { 0x10007654, 0x83 }, - { 0x10007655, 0x47 }, - { 0x10007656, 0x07 }, - { 0x10007657, 0x56 }, - { 0x10007658, 0x93 }, - { 0x10007659, 0xf7 }, - { 0x1000765a, 0x87 }, - { 0x1000765b, 0x01 }, - { 0x1000765c, 0x63 }, - { 0x1000765d, 0x8a }, - { 0x1000765e, 0x07 }, - { 0x1000765f, 0x08 }, - { 0x10007660, 0x83 }, - { 0x10007661, 0x47 }, - { 0x10007662, 0x17 }, - { 0x10007663, 0x08 }, - { 0x10007664, 0x93 }, - { 0x10007665, 0xf7 }, - { 0x10007666, 0x47 }, - { 0x10007667, 0x00 }, - { 0x10007668, 0x63 }, - { 0x10007669, 0x84 }, - { 0x1000766a, 0x07 }, - { 0x1000766b, 0x08 }, - { 0x1000766c, 0x13 }, - { 0x1000766d, 0x01 }, - { 0x1000766e, 0x01 }, - { 0x1000766f, 0xff }, - { 0x10007670, 0x23 }, - { 0x10007671, 0x26 }, - { 0x10007672, 0x11 }, - { 0x10007673, 0x00 }, - { 0x10007674, 0xb7 }, - { 0x10007675, 0xc7 }, - { 0x10007676, 0xc2 }, - { 0x10007677, 0x3f }, - { 0x10007678, 0x03 }, - { 0x10007679, 0xa7 }, - { 0x1000767a, 0x07 }, - { 0x1000767b, 0xfc }, - { 0x1000767c, 0x63 }, - { 0x1000767d, 0x10 }, - { 0x1000767e, 0x05 }, - { 0x1000767f, 0x06 }, - { 0x10007680, 0x13 }, - { 0x10007681, 0x67 }, - { 0x10007682, 0x07 }, - { 0x10007683, 0x20 }, - { 0x10007684, 0x23 }, - { 0x10007685, 0xa0 }, - { 0x10007686, 0xe7 }, - { 0x10007687, 0xfc }, - { 0x10007688, 0x03 }, - { 0x10007689, 0xa7 }, - { 0x1000768a, 0x07 }, - { 0x1000768b, 0xfc }, - { 0x1000768c, 0x13 }, - { 0x1000768d, 0x67 }, - { 0x1000768e, 0x07 }, - { 0x1000768f, 0x40 }, - { 0x10007690, 0x23 }, - { 0x10007691, 0xa0 }, - { 0x10007692, 0xe7 }, - { 0x10007693, 0xfc }, - { 0x10007694, 0x37 }, - { 0x10007695, 0xc7 }, - { 0x10007696, 0xc2 }, - { 0x10007697, 0x3f }, - { 0x10007698, 0x83 }, - { 0x10007699, 0x27 }, - { 0x1000769a, 0x07 }, - { 0x1000769b, 0xfc }, - { 0x1000769c, 0x13 }, - { 0x1000769d, 0x75 }, - { 0x1000769e, 0x15 }, - { 0x1000769f, 0x00 }, - { 0x100076a0, 0x13 }, - { 0x100076a1, 0x15 }, - { 0x100076a2, 0x85 }, - { 0x100076a3, 0x00 }, - { 0x100076a4, 0x93 }, - { 0x100076a5, 0xf7 }, - { 0x100076a6, 0xf7 }, - { 0x100076a7, 0xef }, - { 0x100076a8, 0x33 }, - { 0x100076a9, 0xe5 }, - { 0x100076aa, 0xa7 }, - { 0x100076ab, 0x00 }, - { 0x100076ac, 0x23 }, - { 0x100076ad, 0x20 }, - { 0x100076ae, 0xa7 }, - { 0x100076af, 0xfc }, - { 0x100076b0, 0x93 }, - { 0x100076b1, 0x05 }, - { 0x100076b2, 0x00 }, - { 0x100076b3, 0x00 }, - { 0x100076b4, 0x13 }, - { 0x100076b5, 0x05 }, - { 0x100076b6, 0xa0 }, - { 0x100076b7, 0x00 }, - { 0x100076b8, 0xef }, - { 0x100076b9, 0xe0 }, - { 0x100076ba, 0xcf }, - { 0x100076bb, 0xb6 }, - { 0x100076bc, 0x37 }, - { 0x100076bd, 0xf7 }, - { 0x100076be, 0x00 }, - { 0x100076bf, 0x00 }, - { 0x100076c0, 0x83 }, - { 0x100076c1, 0x47 }, - { 0x100076c2, 0x57 }, - { 0x100076c3, 0x01 }, - { 0x100076c4, 0x93 }, - { 0x100076c5, 0xf7 }, - { 0x100076c6, 0xf7 }, - { 0x100076c7, 0x0f }, - { 0x100076c8, 0x93 }, - { 0x100076c9, 0xe7 }, - { 0x100076ca, 0x47 }, - { 0x100076cb, 0x00 }, - { 0x100076cc, 0xa3 }, - { 0x100076cd, 0x0a }, - { 0x100076ce, 0xf7 }, - { 0x100076cf, 0x00 }, - { 0x100076d0, 0x83 }, - { 0x100076d1, 0x20 }, - { 0x100076d2, 0xc1 }, - { 0x100076d3, 0x00 }, - { 0x100076d4, 0x13 }, - { 0x100076d5, 0x01 }, - { 0x100076d6, 0x01 }, - { 0x100076d7, 0x01 }, - { 0x100076d8, 0x67 }, - { 0x100076d9, 0x80 }, - { 0x100076da, 0x00 }, - { 0x100076db, 0x00 }, - { 0x100076dc, 0x13 }, - { 0x100076dd, 0x77 }, - { 0x100076de, 0xf7 }, - { 0x100076df, 0xdf }, - { 0x100076e0, 0x23 }, - { 0x100076e1, 0xa0 }, - { 0x100076e2, 0xe7 }, - { 0x100076e3, 0xfc }, - { 0x100076e4, 0x03 }, - { 0x100076e5, 0xa7 }, - { 0x100076e6, 0x07 }, - { 0x100076e7, 0xfc }, - { 0x100076e8, 0x13 }, - { 0x100076e9, 0x77 }, - { 0x100076ea, 0xf7 }, - { 0x100076eb, 0xbf }, - { 0x100076ec, 0x6f }, - { 0x100076ed, 0xf0 }, - { 0x100076ee, 0x5f }, - { 0x100076ef, 0xfa }, - { 0x100076f0, 0x67 }, - { 0x100076f1, 0x80 }, - { 0x100076f2, 0x00 }, - { 0x100076f3, 0x00 }, - { 0x100076f4, 0xb7 }, - { 0x100076f5, 0xc7 }, - { 0x100076f6, 0x00 }, - { 0x100076f7, 0x00 }, - { 0x100076f8, 0x03 }, - { 0x100076f9, 0xc7 }, - { 0x100076fa, 0x87 }, - { 0x100076fb, 0x59 }, - { 0x100076fc, 0x13 }, - { 0x100076fd, 0x77 }, - { 0x100076fe, 0xf7 }, - { 0x100076ff, 0x0f }, - { 0x10007700, 0x13 }, - { 0x10007701, 0x67 }, - { 0x10007702, 0x17 }, - { 0x10007703, 0x00 }, - { 0x10007704, 0x23 }, - { 0x10007705, 0x8c }, - { 0x10007706, 0xe7 }, - { 0x10007707, 0x58 }, - { 0x10007708, 0x03 }, - { 0x10007709, 0xc7 }, - { 0x1000770a, 0x77 }, - { 0x1000770b, 0x04 }, - { 0x1000770c, 0x13 }, - { 0x1000770d, 0x17 }, - { 0x1000770e, 0x87 }, - { 0x1000770f, 0x01 }, - { 0x10007710, 0x13 }, - { 0x10007711, 0x57 }, - { 0x10007712, 0x87 }, - { 0x10007713, 0x41 }, - { 0x10007714, 0x63 }, - { 0x10007715, 0x58 }, - { 0x10007716, 0x07 }, - { 0x10007717, 0x12 }, - { 0x10007718, 0x37 }, - { 0x10007719, 0xd7 }, - { 0x1000771a, 0x00 }, - { 0x1000771b, 0x00 }, - { 0x1000771c, 0x83 }, - { 0x1000771d, 0x26 }, - { 0x1000771e, 0x87 }, - { 0x1000771f, 0x53 }, - { 0x10007720, 0x37 }, - { 0x10007721, 0x06 }, - { 0x10007722, 0x00 }, - { 0x10007723, 0x40 }, - { 0x10007724, 0x93 }, - { 0x10007725, 0x05 }, - { 0x10007726, 0x80 }, - { 0x10007727, 0x01 }, - { 0x10007728, 0xb3 }, - { 0x10007729, 0xe6 }, - { 0x1000772a, 0xc6 }, - { 0x1000772b, 0x00 }, - { 0x1000772c, 0x23 }, - { 0x1000772d, 0x2c }, - { 0x1000772e, 0xd7 }, - { 0x1000772f, 0x52 }, - { 0x10007730, 0x83 }, - { 0x10007731, 0xc6 }, - { 0x10007732, 0x07 }, - { 0x10007733, 0x56 }, - { 0x10007734, 0x93 }, - { 0x10007735, 0xf6 }, - { 0x10007736, 0xf6 }, - { 0x10007737, 0x0f }, - { 0x10007738, 0x63 }, - { 0x10007739, 0x9c }, - { 0x1000773a, 0xb6 }, - { 0x1000773b, 0x0e }, - { 0x1000773c, 0x83 }, - { 0x1000773d, 0x27 }, - { 0x1000773e, 0x87 }, - { 0x1000773f, 0x53 }, - { 0x10007740, 0xb3 }, - { 0x10007741, 0xf7 }, - { 0x10007742, 0xc7 }, - { 0x10007743, 0x00 }, - { 0x10007744, 0x63 }, - { 0x10007745, 0x80 }, - { 0x10007746, 0x07 }, - { 0x10007747, 0x10 }, - { 0x10007748, 0x13 }, - { 0x10007749, 0x01 }, - { 0x1000774a, 0x01 }, - { 0x1000774b, 0xff }, - { 0x1000774c, 0x23 }, - { 0x1000774d, 0x24 }, - { 0x1000774e, 0x81 }, - { 0x1000774f, 0x00 }, - { 0x10007750, 0x83 }, - { 0x10007751, 0xa7 }, - { 0x10007752, 0x41 }, - { 0x10007753, 0x58 }, - { 0x10007754, 0x23 }, - { 0x10007755, 0x26 }, - { 0x10007756, 0x11 }, - { 0x10007757, 0x00 }, - { 0x10007758, 0x63 }, - { 0x10007759, 0x94 }, - { 0x1000775a, 0x07 }, - { 0x1000775b, 0x0c }, - { 0x1000775c, 0x83 }, - { 0x1000775d, 0x27 }, - { 0x1000775e, 0x07 }, - { 0x1000775f, 0x53 }, - { 0x10007760, 0x03 }, - { 0x10007761, 0xc6 }, - { 0x10007762, 0xb1 }, - { 0x10007763, 0x42 }, - { 0x10007764, 0x93 }, - { 0x10007765, 0xd7 }, - { 0x10007766, 0xe7 }, - { 0x10007767, 0x01 }, - { 0x10007768, 0x93 }, - { 0x10007769, 0xf7 }, - { 0x1000776a, 0x17 }, - { 0x1000776b, 0x00 }, - { 0x1000776c, 0x93 }, - { 0x1000776d, 0x06 }, - { 0x1000776e, 0x10 }, - { 0x1000776f, 0x00 }, - { 0x10007770, 0x63 }, - { 0x10007771, 0x14 }, - { 0x10007772, 0x06 }, - { 0x10007773, 0x00 }, - { 0x10007774, 0xb3 }, - { 0x10007775, 0x86 }, - { 0x10007776, 0xf6 }, - { 0x10007777, 0x40 }, - { 0x10007778, 0xa3 }, - { 0x10007779, 0x85 }, - { 0x1000777a, 0xd1 }, - { 0x1000777b, 0x42 }, - { 0x1000777c, 0x03 }, - { 0x1000777d, 0xc6 }, - { 0x1000777e, 0xa1 }, - { 0x1000777f, 0x42 }, - { 0x10007780, 0x93 }, - { 0x10007781, 0x06 }, - { 0x10007782, 0x10 }, - { 0x10007783, 0x00 }, - { 0x10007784, 0x63 }, - { 0x10007785, 0x14 }, - { 0x10007786, 0x06 }, - { 0x10007787, 0x00 }, - { 0x10007788, 0xb3 }, - { 0x10007789, 0x86 }, - { 0x1000778a, 0xf6 }, - { 0x1000778b, 0x40 }, - { 0x1000778c, 0x23 }, - { 0x1000778d, 0x85 }, - { 0x1000778e, 0xd1 }, - { 0x1000778f, 0x42 }, - { 0x10007790, 0x03 }, - { 0x10007791, 0xc6 }, - { 0x10007792, 0x91 }, - { 0x10007793, 0x42 }, - { 0x10007794, 0x93 }, - { 0x10007795, 0x06 }, - { 0x10007796, 0x10 }, - { 0x10007797, 0x00 }, - { 0x10007798, 0x63 }, - { 0x10007799, 0x14 }, - { 0x1000779a, 0x06 }, - { 0x1000779b, 0x00 }, - { 0x1000779c, 0xb3 }, - { 0x1000779d, 0x86 }, - { 0x1000779e, 0xf6 }, - { 0x1000779f, 0x40 }, - { 0x100077a0, 0xa3 }, - { 0x100077a1, 0x84 }, - { 0x100077a2, 0xd1 }, - { 0x100077a3, 0x42 }, - { 0x100077a4, 0x03 }, - { 0x100077a5, 0xc6 }, - { 0x100077a6, 0x81 }, - { 0x100077a7, 0x42 }, - { 0x100077a8, 0x93 }, - { 0x100077a9, 0x06 }, - { 0x100077aa, 0x10 }, - { 0x100077ab, 0x00 }, - { 0x100077ac, 0x63 }, - { 0x100077ad, 0x14 }, - { 0x100077ae, 0x06 }, - { 0x100077af, 0x00 }, - { 0x100077b0, 0xb3 }, - { 0x100077b1, 0x86 }, - { 0x100077b2, 0xf6 }, - { 0x100077b3, 0x40 }, - { 0x100077b4, 0x23 }, - { 0x100077b5, 0x84 }, - { 0x100077b6, 0xd1 }, - { 0x100077b7, 0x42 }, - { 0x100077b8, 0xb7 }, - { 0x100077b9, 0xd7 }, - { 0x100077ba, 0x00 }, - { 0x100077bb, 0x00 }, - { 0x100077bc, 0x83 }, - { 0x100077bd, 0xa7 }, - { 0x100077be, 0x07 }, - { 0x100077bf, 0x53 }, - { 0x100077c0, 0x37 }, - { 0x100077c1, 0x07 }, - { 0x100077c2, 0x00 }, - { 0x100077c3, 0x40 }, - { 0x100077c4, 0xb3 }, - { 0x100077c5, 0xf7 }, - { 0x100077c6, 0xe7 }, - { 0x100077c7, 0x00 }, - { 0x100077c8, 0x63 }, - { 0x100077c9, 0x8c }, - { 0x100077ca, 0x07 }, - { 0x100077cb, 0x04 }, - { 0x100077cc, 0xb7 }, - { 0x100077cd, 0x47 }, - { 0x100077ce, 0x0f }, - { 0x100077cf, 0x00 }, - { 0x100077d0, 0x93 }, - { 0x100077d1, 0x87 }, - { 0x100077d2, 0x17 }, - { 0x100077d3, 0x24 }, - { 0x100077d4, 0xb7 }, - { 0x100077d5, 0xf6 }, - { 0x100077d6, 0x00 }, - { 0x100077d7, 0x00 }, - { 0x100077d8, 0x03 }, - { 0x100077d9, 0xc7 }, - { 0x100077da, 0xf6 }, - { 0x100077db, 0x83 }, - { 0x100077dc, 0x13 }, - { 0x100077dd, 0x77 }, - { 0x100077de, 0x07 }, - { 0x100077df, 0x04 }, - { 0x100077e0, 0x63 }, - { 0x100077e1, 0x16 }, - { 0x100077e2, 0x07 }, - { 0x100077e3, 0x00 }, - { 0x100077e4, 0x93 }, - { 0x100077e5, 0x87 }, - { 0x100077e6, 0xf7 }, - { 0x100077e7, 0xff }, - { 0x100077e8, 0xe3 }, - { 0x100077e9, 0x98 }, - { 0x100077ea, 0x07 }, - { 0x100077eb, 0xfe }, - { 0x100077ec, 0x13 }, - { 0x100077ed, 0x05 }, - { 0x100077ee, 0x80 }, - { 0x100077ef, 0x3e }, - { 0x100077f0, 0x93 }, - { 0x100077f1, 0x05 }, - { 0x100077f2, 0x00 }, - { 0x100077f3, 0x00 }, - { 0x100077f4, 0xef }, - { 0x100077f5, 0xe0 }, - { 0x100077f6, 0x0f }, - { 0x100077f7, 0xa3 }, - { 0x100077f8, 0x37 }, - { 0x100077f9, 0xf7 }, - { 0x100077fa, 0x00 }, - { 0x100077fb, 0x00 }, - { 0x100077fc, 0x83 }, - { 0x100077fd, 0x47 }, - { 0x100077fe, 0xb7 }, - { 0x100077ff, 0x80 }, - { 0x10007800, 0x93 }, - { 0x10007801, 0xe7 }, - { 0x10007802, 0x07 }, - { 0x10007803, 0xf8 }, - { 0x10007804, 0x93 }, - { 0x10007805, 0xf7 }, - { 0x10007806, 0xf7 }, - { 0x10007807, 0x0f }, - { 0x10007808, 0xa3 }, - { 0x10007809, 0x05 }, - { 0x1000780a, 0xf7 }, - { 0x1000780b, 0x80 }, - { 0x1000780c, 0xb7 }, - { 0x1000780d, 0xd7 }, - { 0x1000780e, 0x00 }, - { 0x1000780f, 0x00 }, - { 0x10007810, 0x37 }, - { 0x10007811, 0x07 }, - { 0x10007812, 0x00 }, - { 0x10007813, 0x40 }, - { 0x10007814, 0x23 }, - { 0x10007815, 0xa8 }, - { 0x10007816, 0xe7 }, - { 0x10007817, 0x52 }, - { 0x10007818, 0x93 }, - { 0x10007819, 0x07 }, - { 0x1000781a, 0x10 }, - { 0x1000781b, 0x00 }, - { 0x1000781c, 0x23 }, - { 0x1000781d, 0xa2 }, - { 0x1000781e, 0xf1 }, - { 0x1000781f, 0x58 }, - { 0x10007820, 0x83 }, - { 0x10007821, 0x20 }, - { 0x10007822, 0xc1 }, - { 0x10007823, 0x00 }, - { 0x10007824, 0x03 }, - { 0x10007825, 0x24 }, - { 0x10007826, 0x81 }, - { 0x10007827, 0x00 }, - { 0x10007828, 0x13 }, - { 0x10007829, 0x01 }, - { 0x1000782a, 0x01 }, - { 0x1000782b, 0x01 }, - { 0x1000782c, 0x67 }, - { 0x1000782d, 0x80 }, - { 0x1000782e, 0x00 }, - { 0x1000782f, 0x00 }, - { 0x10007830, 0x83 }, - { 0x10007831, 0xc7 }, - { 0x10007832, 0x07 }, - { 0x10007833, 0x56 }, - { 0x10007834, 0x93 }, - { 0x10007835, 0xf7 }, - { 0x10007836, 0xf7 }, - { 0x10007837, 0x0f }, - { 0x10007838, 0x63 }, - { 0x10007839, 0x96 }, - { 0x1000783a, 0x07 }, - { 0x1000783b, 0x00 }, - { 0x1000783c, 0x23 }, - { 0x1000783d, 0xa2 }, - { 0x1000783e, 0x01 }, - { 0x1000783f, 0x58 }, - { 0x10007840, 0x67 }, - { 0x10007841, 0x80 }, - { 0x10007842, 0x00 }, - { 0x10007843, 0x00 }, - { 0x10007844, 0x67 }, - { 0x10007845, 0x80 }, - { 0x10007846, 0x00 }, - { 0x10007847, 0x00 }, - { 0x10007848, 0xb7 }, - { 0x10007849, 0xc7 }, - { 0x1000784a, 0x00 }, - { 0x1000784b, 0x00 }, - { 0x1000784c, 0x83 }, - { 0x1000784d, 0xc7 }, - { 0x1000784e, 0x07 }, - { 0x1000784f, 0x56 }, - { 0x10007850, 0x13 }, - { 0x10007851, 0x07 }, - { 0x10007852, 0x80 }, - { 0x10007853, 0x01 }, - { 0x10007854, 0x93 }, - { 0x10007855, 0xf7 }, - { 0x10007856, 0xf7 }, - { 0x10007857, 0x0f }, - { 0x10007858, 0x63 }, - { 0x10007859, 0x98 }, - { 0x1000785a, 0xe7 }, - { 0x1000785b, 0x00 }, - { 0x1000785c, 0x13 }, - { 0x1000785d, 0x05 }, - { 0x1000785e, 0x00 }, - { 0x1000785f, 0x7d }, - { 0x10007860, 0x93 }, - { 0x10007861, 0x05 }, - { 0x10007862, 0x00 }, - { 0x10007863, 0x00 }, - { 0x10007864, 0x6f }, - { 0x10007865, 0xe0 }, - { 0x10007866, 0x0f }, - { 0x10007867, 0x9c }, - { 0x10007868, 0x67 }, - { 0x10007869, 0x80 }, - { 0x1000786a, 0x00 }, - { 0x1000786b, 0x00 }, - { 0x1000786c, 0x13 }, - { 0x1000786d, 0x01 }, - { 0x1000786e, 0x01 }, - { 0x1000786f, 0xff }, - { 0x10007870, 0x23 }, - { 0x10007871, 0x26 }, - { 0x10007872, 0x11 }, - { 0x10007873, 0x00 }, - { 0x10007874, 0x23 }, - { 0x10007875, 0x24 }, - { 0x10007876, 0x81 }, - { 0x10007877, 0x00 }, - { 0x10007878, 0xef }, - { 0x10007879, 0xd0 }, - { 0x1000787a, 0x4f }, - { 0x1000787b, 0x91 }, - { 0x1000787c, 0x83 }, - { 0x1000787d, 0xc7 }, - { 0x1000787e, 0x81 }, - { 0x1000787f, 0x41 }, - { 0x10007880, 0x63 }, - { 0x10007881, 0x84 }, - { 0x10007882, 0x07 }, - { 0x10007883, 0x08 }, - { 0x10007884, 0xb7 }, - { 0x10007885, 0xd7 }, - { 0x10007886, 0x00 }, - { 0x10007887, 0x00 }, - { 0x10007888, 0x83 }, - { 0x10007889, 0xc7 }, - { 0x1000788a, 0x07 }, - { 0x1000788b, 0x47 }, - { 0x1000788c, 0x93 }, - { 0x1000788d, 0xf7 }, - { 0x1000788e, 0x07 }, - { 0x1000788f, 0x02 }, - { 0x10007890, 0x63 }, - { 0x10007891, 0x8a }, - { 0x10007892, 0x07 }, - { 0x10007893, 0x04 }, - { 0x10007894, 0x83 }, - { 0x10007895, 0xc7 }, - { 0x10007896, 0x11 }, - { 0x10007897, 0x44 }, - { 0x10007898, 0x93 }, - { 0x10007899, 0xf7 }, - { 0x1000789a, 0xd7 }, - { 0x1000789b, 0x0f }, - { 0x1000789c, 0x63 }, - { 0x1000789d, 0x90 }, - { 0x1000789e, 0x07 }, - { 0x1000789f, 0x02 }, - { 0x100078a0, 0x03 }, - { 0x100078a1, 0xc7 }, - { 0x100078a2, 0xd1 }, - { 0x100078a3, 0x58 }, - { 0x100078a4, 0xb7 }, - { 0x100078a5, 0x07 }, - { 0x100078a6, 0x00 }, - { 0x100078a7, 0x11 }, - { 0x100078a8, 0x23 }, - { 0x100078a9, 0x88 }, - { 0x100078aa, 0xe7 }, - { 0x100078ab, 0x00 }, - { 0x100078ac, 0x23 }, - { 0x100078ad, 0x88 }, - { 0x100078ae, 0xe7 }, - { 0x100078af, 0x20 }, - { 0x100078b0, 0x03 }, - { 0x100078b1, 0xc7 }, - { 0x100078b2, 0xc1 }, - { 0x100078b3, 0x58 }, - { 0x100078b4, 0x23 }, - { 0x100078b5, 0x8c }, - { 0x100078b6, 0xe7 }, - { 0x100078b7, 0x00 }, - { 0x100078b8, 0x6f }, - { 0x100078b9, 0x00 }, - { 0x100078ba, 0x80 }, - { 0x100078bb, 0x04 }, - { 0x100078bc, 0xb7 }, - { 0x100078bd, 0x07 }, - { 0x100078be, 0x00 }, - { 0x100078bf, 0x11 }, - { 0x100078c0, 0x23 }, - { 0x100078c1, 0x88 }, - { 0x100078c2, 0x07 }, - { 0x100078c3, 0x00 }, - { 0x100078c4, 0x23 }, - { 0x100078c5, 0x88 }, - { 0x100078c6, 0x07 }, - { 0x100078c7, 0x20 }, - { 0x100078c8, 0x23 }, - { 0x100078c9, 0x8c }, - { 0x100078ca, 0x07 }, - { 0x100078cb, 0x00 }, - { 0x100078cc, 0x23 }, - { 0x100078cd, 0x8c }, - { 0x100078ce, 0x07 }, - { 0x100078cf, 0x20 }, - { 0x100078d0, 0xef }, - { 0x100078d1, 0xb0 }, - { 0x100078d2, 0xcf }, - { 0x100078d3, 0xc4 }, - { 0x100078d4, 0x03 }, - { 0x100078d5, 0x24 }, - { 0x100078d6, 0x81 }, - { 0x100078d7, 0x00 }, - { 0x100078d8, 0x83 }, - { 0x100078d9, 0x20 }, - { 0x100078da, 0xc1 }, - { 0x100078db, 0x00 }, - { 0x100078dc, 0x13 }, - { 0x100078dd, 0x01 }, - { 0x100078de, 0x01 }, - { 0x100078df, 0x01 }, - { 0x100078e0, 0x6f }, - { 0x100078e1, 0xb0 }, - { 0x100078e2, 0xcf }, - { 0x100078e3, 0xcd }, - { 0x100078e4, 0x03 }, - { 0x100078e5, 0xc7 }, - { 0x100078e6, 0xd1 }, - { 0x100078e7, 0x58 }, - { 0x100078e8, 0xb7 }, - { 0x100078e9, 0x07 }, - { 0x100078ea, 0x00 }, - { 0x100078eb, 0x11 }, - { 0x100078ec, 0x23 }, - { 0x100078ed, 0x88 }, - { 0x100078ee, 0xe7 }, - { 0x100078ef, 0x00 }, - { 0x100078f0, 0x83 }, - { 0x100078f1, 0xc6 }, - { 0x100078f2, 0xc1 }, - { 0x100078f3, 0x58 }, - { 0x100078f4, 0x23 }, - { 0x100078f5, 0x88 }, - { 0x100078f6, 0xd7 }, - { 0x100078f7, 0x20 }, - { 0x100078f8, 0x23 }, - { 0x100078f9, 0x8c }, - { 0x100078fa, 0xd7 }, - { 0x100078fb, 0x00 }, - { 0x100078fc, 0x03 }, - { 0x100078fd, 0xc7 }, - { 0x100078fe, 0xc1 }, - { 0x100078ff, 0x58 }, - { 0x10007900, 0x23 }, - { 0x10007901, 0x8c }, - { 0x10007902, 0xe7 }, - { 0x10007903, 0x20 }, - { 0x10007904, 0x6f }, - { 0x10007905, 0xf0 }, - { 0x10007906, 0xdf }, - { 0x10007907, 0xfc }, - { 0x10007908, 0xb7 }, - { 0x10007909, 0x06 }, - { 0x1000790a, 0x00 }, - { 0x1000790b, 0x11 }, - { 0x1000790c, 0x03 }, - { 0x1000790d, 0xc7 }, - { 0x1000790e, 0x06 }, - { 0x1000790f, 0x21 }, - { 0x10007910, 0x03 }, - { 0x10007911, 0xc6 }, - { 0x10007912, 0xd1 }, - { 0x10007913, 0x58 }, - { 0x10007914, 0x13 }, - { 0x10007915, 0x84 }, - { 0x10007916, 0x07 }, - { 0x10007917, 0x00 }, - { 0x10007918, 0x13 }, - { 0x10007919, 0x77 }, - { 0x1000791a, 0xf7 }, - { 0x1000791b, 0x0f }, - { 0x1000791c, 0x63 }, - { 0x1000791d, 0x1a }, - { 0x1000791e, 0xe6 }, - { 0x1000791f, 0x00 }, - { 0x10007920, 0x83 }, - { 0x10007921, 0xc7 }, - { 0x10007922, 0x86 }, - { 0x10007923, 0x21 }, - { 0x10007924, 0x03 }, - { 0x10007925, 0xc7 }, - { 0x10007926, 0xc1 }, - { 0x10007927, 0x58 }, - { 0x10007928, 0x93 }, - { 0x10007929, 0xf7 }, - { 0x1000792a, 0xf7 }, - { 0x1000792b, 0x0f }, - { 0x1000792c, 0xe3 }, - { 0x1000792d, 0x02 }, - { 0x1000792e, 0xf7 }, - { 0x1000792f, 0xfa }, - { 0x10007930, 0xb7 }, - { 0x10007931, 0xc7 }, - { 0x10007932, 0x00 }, - { 0x10007933, 0x00 }, - { 0x10007934, 0x83 }, - { 0x10007935, 0xc7 }, - { 0x10007936, 0x07 }, - { 0x10007937, 0x56 }, - { 0x10007938, 0x13 }, - { 0x10007939, 0x07 }, - { 0x1000793a, 0xf0 }, - { 0x1000793b, 0x00 }, - { 0x1000793c, 0x93 }, - { 0x1000793d, 0xf7 }, - { 0x1000793e, 0xf7 }, - { 0x1000793f, 0x0f }, - { 0x10007940, 0xe3 }, - { 0x10007941, 0x78 }, - { 0x10007942, 0xf7 }, - { 0x10007943, 0xf8 }, - { 0x10007944, 0xb7 }, - { 0x10007945, 0xd7 }, - { 0x10007946, 0x00 }, - { 0x10007947, 0x00 }, - { 0x10007948, 0x83 }, - { 0x10007949, 0xc5 }, - { 0x1000794a, 0xa7 }, - { 0x1000794b, 0x47 }, - { 0x1000794c, 0x93 }, - { 0x1000794d, 0xf7 }, - { 0x1000794e, 0xf5 }, - { 0x1000794f, 0x0f }, - { 0x10007950, 0x93 }, - { 0x10007951, 0x95 }, - { 0x10007952, 0x57 }, - { 0x10007953, 0x00 }, - { 0x10007954, 0xb3 }, - { 0x10007955, 0x85 }, - { 0x10007956, 0xf5 }, - { 0x10007957, 0x40 }, - { 0x10007958, 0x93 }, - { 0x10007959, 0x95 }, - { 0x1000795a, 0x25 }, - { 0x1000795b, 0x00 }, - { 0x1000795c, 0xb3 }, - { 0x1000795d, 0x85 }, - { 0x1000795e, 0xf5 }, - { 0x1000795f, 0x00 }, - { 0x10007960, 0x13 }, - { 0x10007961, 0x95 }, - { 0x10007962, 0x35 }, - { 0x10007963, 0x00 }, - { 0x10007964, 0x93 }, - { 0x10007965, 0xd5 }, - { 0x10007966, 0xf5 }, - { 0x10007967, 0x41 }, - { 0x10007968, 0xef }, - { 0x10007969, 0xe0 }, - { 0x1000796a, 0xcf }, - { 0x1000796b, 0x8b }, - { 0x1000796c, 0x03 }, - { 0x1000796d, 0xc7 }, - { 0x1000796e, 0xd1 }, - { 0x1000796f, 0x58 }, - { 0x10007970, 0x6f }, - { 0x10007971, 0xf0 }, - { 0x10007972, 0x5f }, - { 0x10007973, 0xf3 }, - { 0x10007974, 0x13 }, - { 0x10007975, 0x01 }, - { 0x10007976, 0x01 }, - { 0x10007977, 0xfe }, - { 0x10007978, 0x23 }, - { 0x10007979, 0x2c }, - { 0x1000797a, 0x81 }, - { 0x1000797b, 0x00 }, - { 0x1000797c, 0x83 }, - { 0x1000797d, 0xc7 }, - { 0x1000797e, 0x21 }, - { 0x1000797f, 0x41 }, - { 0x10007980, 0x23 }, - { 0x10007981, 0x2e }, - { 0x10007982, 0x11 }, - { 0x10007983, 0x00 }, - { 0x10007984, 0x23 }, - { 0x10007985, 0x2a }, - { 0x10007986, 0x91 }, - { 0x10007987, 0x00 }, - { 0x10007988, 0x23 }, - { 0x10007989, 0x28 }, - { 0x1000798a, 0x21 }, - { 0x1000798b, 0x01 }, - { 0x1000798c, 0x23 }, - { 0x1000798d, 0x26 }, - { 0x1000798e, 0x31 }, - { 0x1000798f, 0x01 }, - { 0x10007990, 0x13 }, - { 0x10007991, 0x07 }, - { 0x10007992, 0x10 }, - { 0x10007993, 0x00 }, - { 0x10007994, 0x63 }, - { 0x10007995, 0x92 }, - { 0x10007996, 0xe7 }, - { 0x10007997, 0x02 }, - { 0x10007998, 0xa3 }, - { 0x10007999, 0x81 }, - { 0x1000799a, 0xf1 }, - { 0x1000799b, 0x40 }, - { 0x1000799c, 0x83 }, - { 0x1000799d, 0x20 }, - { 0x1000799e, 0xc1 }, - { 0x1000799f, 0x01 }, - { 0x100079a0, 0x03 }, - { 0x100079a1, 0x24 }, - { 0x100079a2, 0x81 }, - { 0x100079a3, 0x01 }, - { 0x100079a4, 0x83 }, - { 0x100079a5, 0x24 }, - { 0x100079a6, 0x41 }, - { 0x100079a7, 0x01 }, - { 0x100079a8, 0x03 }, - { 0x100079a9, 0x29 }, - { 0x100079aa, 0x01 }, - { 0x100079ab, 0x01 }, - { 0x100079ac, 0x83 }, - { 0x100079ad, 0x29 }, - { 0x100079ae, 0xc1 }, - { 0x100079af, 0x00 }, - { 0x100079b0, 0x13 }, - { 0x100079b1, 0x01 }, - { 0x100079b2, 0x01 }, - { 0x100079b3, 0x02 }, - { 0x100079b4, 0x67 }, - { 0x100079b5, 0x80 }, - { 0x100079b6, 0x00 }, - { 0x100079b7, 0x00 }, - { 0x100079b8, 0xe3 }, - { 0x100079b9, 0x92 }, - { 0x100079ba, 0x07 }, - { 0x100079bb, 0xfe }, - { 0x100079bc, 0x37 }, - { 0x100079bd, 0xc9 }, - { 0x100079be, 0x00 }, - { 0x100079bf, 0x00 }, - { 0x100079c0, 0x83 }, - { 0x100079c1, 0x47 }, - { 0x100079c2, 0x09 }, - { 0x100079c3, 0x56 }, - { 0x100079c4, 0x13 }, - { 0x100079c5, 0x07 }, - { 0x100079c6, 0x80 }, - { 0x100079c7, 0x01 }, - { 0x100079c8, 0x93 }, - { 0x100079c9, 0xf7 }, - { 0x100079ca, 0xf7 }, - { 0x100079cb, 0x0f }, - { 0x100079cc, 0xe3 }, - { 0x100079cd, 0x78 }, - { 0x100079ce, 0xf7 }, - { 0x100079cf, 0xfc }, - { 0x100079d0, 0x83 }, - { 0x100079d1, 0xc7 }, - { 0x100079d2, 0x31 }, - { 0x100079d3, 0x40 }, - { 0x100079d4, 0xe3 }, - { 0x100079d5, 0x84 }, - { 0x100079d6, 0x07 }, - { 0x100079d7, 0xfc }, - { 0x100079d8, 0xb7 }, - { 0x100079d9, 0xd4 }, - { 0x100079da, 0x00 }, - { 0x100079db, 0x00 }, - { 0x100079dc, 0x03 }, - { 0x100079dd, 0xc5 }, - { 0x100079de, 0x94 }, - { 0x100079df, 0x47 }, - { 0x100079e0, 0xb7 }, - { 0x100079e1, 0x15 }, - { 0x100079e2, 0x00 }, - { 0x100079e3, 0x00 }, - { 0x100079e4, 0x93 }, - { 0x100079e5, 0x85 }, - { 0x100079e6, 0x85 }, - { 0x100079e7, 0x38 }, - { 0x100079e8, 0x13 }, - { 0x100079e9, 0x75 }, - { 0x100079ea, 0xf5 }, - { 0x100079eb, 0x0f }, - { 0x100079ec, 0xef }, - { 0x100079ed, 0xe0 }, - { 0x100079ee, 0x5f }, - { 0x100079ef, 0xe0 }, - { 0x100079f0, 0x93 }, - { 0x100079f1, 0x55 }, - { 0x100079f2, 0xf5 }, - { 0x100079f3, 0x41 }, - { 0x100079f4, 0xef }, - { 0x100079f5, 0xe0 }, - { 0x100079f6, 0x0f }, - { 0x100079f7, 0x83 }, - { 0x100079f8, 0xa3 }, - { 0x100079f9, 0x81 }, - { 0x100079fa, 0x01 }, - { 0x100079fb, 0x40 }, - { 0x100079fc, 0x83 }, - { 0x100079fd, 0x27 }, - { 0x100079fe, 0xc9 }, - { 0x100079ff, 0x5f }, - { 0x10007a00, 0x37 }, - { 0x10007a01, 0x07 }, - { 0x10007a02, 0x00 }, - { 0x10007a03, 0x02 }, - { 0x10007a04, 0xb3 }, - { 0x10007a05, 0xf7 }, - { 0x10007a06, 0xe7 }, - { 0x10007a07, 0x00 }, - { 0x10007a08, 0xe3 }, - { 0x10007a09, 0x8a }, - { 0x10007a0a, 0x07 }, - { 0x10007a0b, 0xf8 }, - { 0x10007a0c, 0x03 }, - { 0x10007a0d, 0xc7 }, - { 0x10007a0e, 0x04 }, - { 0x10007a0f, 0x90 }, - { 0x10007a10, 0x93 }, - { 0x10007a11, 0x07 }, - { 0x10007a12, 0x10 }, - { 0x10007a13, 0x00 }, - { 0x10007a14, 0x13 }, - { 0x10007a15, 0x77 }, - { 0x10007a16, 0x17 }, - { 0x10007a17, 0x00 }, - { 0x10007a18, 0x63 }, - { 0x10007a19, 0x1c }, - { 0x10007a1a, 0x07 }, - { 0x10007a1b, 0x00 }, - { 0x10007a1c, 0x83 }, - { 0x10007a1d, 0xc7 }, - { 0x10007a1e, 0x34 }, - { 0x10007a1f, 0x54 }, - { 0x10007a20, 0x93 }, - { 0x10007a21, 0xf7 }, - { 0x10007a22, 0xf7 }, - { 0x10007a23, 0x0f }, - { 0x10007a24, 0x93 }, - { 0x10007a25, 0xd7 }, - { 0x10007a26, 0x17 }, - { 0x10007a27, 0x00 }, - { 0x10007a28, 0x93 }, - { 0x10007a29, 0xc7 }, - { 0x10007a2a, 0x17 }, - { 0x10007a2b, 0x00 }, - { 0x10007a2c, 0x93 }, - { 0x10007a2d, 0xf7 }, - { 0x10007a2e, 0x17 }, - { 0x10007a2f, 0x00 }, - { 0x10007a30, 0xa3 }, - { 0x10007a31, 0x85 }, - { 0x10007a32, 0xf1 }, - { 0x10007a33, 0x42 }, - { 0x10007a34, 0x37 }, - { 0x10007a35, 0xd6 }, - { 0x10007a36, 0x00 }, - { 0x10007a37, 0x00 }, - { 0x10007a38, 0x03 }, - { 0x10007a39, 0x47 }, - { 0x10007a3a, 0x06 }, - { 0x10007a3b, 0x90 }, - { 0x10007a3c, 0x93 }, - { 0x10007a3d, 0x06 }, - { 0x10007a3e, 0x10 }, - { 0x10007a3f, 0x00 }, - { 0x10007a40, 0x13 }, - { 0x10007a41, 0x77 }, - { 0x10007a42, 0x27 }, - { 0x10007a43, 0x00 }, - { 0x10007a44, 0x63 }, - { 0x10007a45, 0x18 }, - { 0x10007a46, 0x07 }, - { 0x10007a47, 0x00 }, - { 0x10007a48, 0x03 }, - { 0x10007a49, 0x47 }, - { 0x10007a4a, 0x36 }, - { 0x10007a4b, 0x54 }, - { 0x10007a4c, 0x13 }, - { 0x10007a4d, 0x77 }, - { 0x10007a4e, 0x17 }, - { 0x10007a4f, 0x00 }, - { 0x10007a50, 0xb3 }, - { 0x10007a51, 0x86 }, - { 0x10007a52, 0xe6 }, - { 0x10007a53, 0x40 }, - { 0x10007a54, 0x23 }, - { 0x10007a55, 0x85 }, - { 0x10007a56, 0xd1 }, - { 0x10007a57, 0x42 }, - { 0x10007a58, 0xb7 }, - { 0x10007a59, 0xd5 }, - { 0x10007a5a, 0x00 }, - { 0x10007a5b, 0x00 }, - { 0x10007a5c, 0x03 }, - { 0x10007a5d, 0xc6 }, - { 0x10007a5e, 0x05 }, - { 0x10007a5f, 0x92 }, - { 0x10007a60, 0x13 }, - { 0x10007a61, 0x07 }, - { 0x10007a62, 0x10 }, - { 0x10007a63, 0x00 }, - { 0x10007a64, 0x13 }, - { 0x10007a65, 0x76 }, - { 0x10007a66, 0x16 }, - { 0x10007a67, 0x00 }, - { 0x10007a68, 0x63 }, - { 0x10007a69, 0x1c }, - { 0x10007a6a, 0x06 }, - { 0x10007a6b, 0x00 }, - { 0x10007a6c, 0x03 }, - { 0x10007a6d, 0xc7 }, - { 0x10007a6e, 0x35 }, - { 0x10007a6f, 0x54 }, - { 0x10007a70, 0x13 }, - { 0x10007a71, 0x77 }, - { 0x10007a72, 0xf7 }, - { 0x10007a73, 0x0f }, - { 0x10007a74, 0x13 }, - { 0x10007a75, 0x57 }, - { 0x10007a76, 0x37 }, - { 0x10007a77, 0x00 }, - { 0x10007a78, 0x13 }, - { 0x10007a79, 0x47 }, - { 0x10007a7a, 0x17 }, - { 0x10007a7b, 0x00 }, - { 0x10007a7c, 0x13 }, - { 0x10007a7d, 0x77 }, - { 0x10007a7e, 0x17 }, - { 0x10007a7f, 0x00 }, - { 0x10007a80, 0xa3 }, - { 0x10007a81, 0x84 }, - { 0x10007a82, 0xe1 }, - { 0x10007a83, 0x42 }, - { 0x10007a84, 0xb7 }, - { 0x10007a85, 0xd5 }, - { 0x10007a86, 0x00 }, - { 0x10007a87, 0x00 }, - { 0x10007a88, 0x03 }, - { 0x10007a89, 0xc6 }, - { 0x10007a8a, 0x05 }, - { 0x10007a8b, 0x92 }, - { 0x10007a8c, 0x13 }, - { 0x10007a8d, 0x07 }, - { 0x10007a8e, 0x10 }, - { 0x10007a8f, 0x00 }, - { 0x10007a90, 0x13 }, - { 0x10007a91, 0x76 }, - { 0x10007a92, 0x26 }, - { 0x10007a93, 0x00 }, - { 0x10007a94, 0x63 }, - { 0x10007a95, 0x1c }, - { 0x10007a96, 0x06 }, - { 0x10007a97, 0x00 }, - { 0x10007a98, 0x03 }, - { 0x10007a99, 0xc7 }, - { 0x10007a9a, 0x35 }, - { 0x10007a9b, 0x54 }, - { 0x10007a9c, 0x13 }, - { 0x10007a9d, 0x77 }, - { 0x10007a9e, 0xf7 }, - { 0x10007a9f, 0x0f }, - { 0x10007aa0, 0x13 }, - { 0x10007aa1, 0x57 }, - { 0x10007aa2, 0x27 }, - { 0x10007aa3, 0x00 }, - { 0x10007aa4, 0x13 }, - { 0x10007aa5, 0x47 }, - { 0x10007aa6, 0x17 }, - { 0x10007aa7, 0x00 }, - { 0x10007aa8, 0x13 }, - { 0x10007aa9, 0x77 }, - { 0x10007aaa, 0x17 }, - { 0x10007aab, 0x00 }, - { 0x10007aac, 0x23 }, - { 0x10007aad, 0x84 }, - { 0x10007aae, 0xe1 }, - { 0x10007aaf, 0x42 }, - { 0x10007ab0, 0x63 }, - { 0x10007ab1, 0x84 }, - { 0x10007ab2, 0x07 }, - { 0x10007ab3, 0x00 }, - { 0x10007ab4, 0xe3 }, - { 0x10007ab5, 0x94 }, - { 0x10007ab6, 0x06 }, - { 0x10007ab7, 0xee }, - { 0x10007ab8, 0xef }, - { 0x10007ab9, 0x90 }, - { 0x10007aba, 0x0f }, - { 0x10007abb, 0x86 }, - { 0x10007abc, 0xef }, - { 0x10007abd, 0xd0 }, - { 0x10007abe, 0x0f }, - { 0x10007abf, 0x97 }, - { 0x10007ac0, 0x37 }, - { 0x10007ac1, 0x15 }, - { 0x10007ac2, 0x00 }, - { 0x10007ac3, 0x00 }, - { 0x10007ac4, 0x13 }, - { 0x10007ac5, 0x05 }, - { 0x10007ac6, 0x85 }, - { 0x10007ac7, 0xbb }, - { 0x10007ac8, 0x93 }, - { 0x10007ac9, 0x05 }, - { 0x10007aca, 0x00 }, - { 0x10007acb, 0x00 }, - { 0x10007acc, 0xef }, - { 0x10007acd, 0xd0 }, - { 0x10007ace, 0x9f }, - { 0x10007acf, 0xf5 }, - { 0x10007ad0, 0xb7 }, - { 0x10007ad1, 0xd7 }, - { 0x10007ad2, 0x00 }, - { 0x10007ad3, 0x00 }, - { 0x10007ad4, 0x83 }, - { 0x10007ad5, 0xc7 }, - { 0x10007ad6, 0x07 }, - { 0x10007ad7, 0x47 }, - { 0x10007ad8, 0x93 }, - { 0x10007ad9, 0xf7 }, - { 0x10007ada, 0x47 }, - { 0x10007adb, 0x00 }, - { 0x10007adc, 0xe3 }, - { 0x10007add, 0x80 }, - { 0x10007ade, 0x07 }, - { 0x10007adf, 0xec }, - { 0x10007ae0, 0xef }, - { 0x10007ae1, 0x80 }, - { 0x10007ae2, 0xdf }, - { 0x10007ae3, 0xf4 }, - { 0x10007ae4, 0x23 }, - { 0x10007ae5, 0x89 }, - { 0x10007ae6, 0xa1 }, - { 0x10007ae7, 0x40 }, - { 0x10007ae8, 0x6f }, - { 0x10007ae9, 0xf0 }, - { 0x10007aea, 0x5f }, - { 0x10007aeb, 0xeb }, - { 0x10007aec, 0x00 }, - { 0x10007aed, 0x00 }, - { 0x10007aee, 0x00 }, - { 0x10007aef, 0x00 }, { 0x3fc2bf83, 0x00 }, { 0x3fc2bf82, 0x00 }, { 0x3fc2bf81, 0x00 }, @@ -2109,1346 +228,41 @@ static const struct reg_sequence rt1320_vc_patch_code_write[] = { { 0x0000d540, 0x01 }, { 0x0000c081, 0xfc }, { 0x0000f01e, 0x80 }, + { 0xc01b, 0xfc }, + { 0xc5d1, 0x89 }, + { 0xc5d8, 0x0a }, + { 0xc5f7, 0x22 }, + { 0xc5f6, 0x22 }, + { 0xc065, 0xa5 }, + { 0xc06b, 0x0a }, + { 0xd172, 0x2a }, + { 0xc5d6, 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, }; -/* - * The 'patch code' is written to the patch code area. - * The patch code area is used for SDCA register expansion flexibility. - */ -static const struct reg_sequence rt1320_patch_code_write[] = { - { 0x10007000, 0x37 }, - { 0x10007001, 0x77 }, - { 0x10007002, 0x00 }, - { 0x10007003, 0x10 }, - { 0x10007004, 0xb7 }, - { 0x10007005, 0xe7 }, - { 0x10007006, 0x00 }, - { 0x10007007, 0x10 }, - { 0x10007008, 0x13 }, - { 0x10007009, 0x07 }, - { 0x1000700a, 0x07 }, - { 0x1000700b, 0x40 }, - { 0x1000700c, 0x23 }, - { 0x1000700d, 0xae }, - { 0x1000700e, 0xe7 }, - { 0x1000700f, 0xda }, - { 0x10007010, 0x37 }, - { 0x10007011, 0x77 }, - { 0x10007012, 0x00 }, - { 0x10007013, 0x10 }, - { 0x10007014, 0x13 }, - { 0x10007015, 0x07 }, - { 0x10007016, 0x47 }, - { 0x10007017, 0x61 }, - { 0x10007018, 0x23 }, - { 0x10007019, 0xa4 }, - { 0x1000701a, 0xe7 }, - { 0x1000701b, 0xde }, - { 0x1000701c, 0x37 }, - { 0x1000701d, 0x77 }, - { 0x1000701e, 0x00 }, - { 0x1000701f, 0x10 }, - { 0x10007020, 0x13 }, - { 0x10007021, 0x07 }, - { 0x10007022, 0x07 }, - { 0x10007023, 0x52 }, - { 0x10007024, 0x23 }, - { 0x10007025, 0xae }, - { 0x10007026, 0xe7 }, - { 0x10007027, 0xde }, - { 0x10007028, 0x37 }, - { 0x10007029, 0x77 }, - { 0x1000702a, 0x00 }, - { 0x1000702b, 0x10 }, - { 0x1000702c, 0x13 }, - { 0x1000702d, 0x07 }, - { 0x1000702e, 0x47 }, - { 0x1000702f, 0x54 }, - { 0x10007030, 0x23 }, - { 0x10007031, 0xaa }, - { 0x10007032, 0xe7 }, - { 0x10007033, 0xe4 }, - { 0x10007034, 0x37 }, - { 0x10007035, 0x87 }, - { 0x10007036, 0x00 }, - { 0x10007037, 0x10 }, - { 0x10007038, 0x13 }, - { 0x10007039, 0x07 }, - { 0x1000703a, 0x47 }, - { 0x1000703b, 0x81 }, - { 0x1000703c, 0x23 }, - { 0x1000703d, 0xa2 }, - { 0x1000703e, 0xe7 }, - { 0x1000703f, 0xe8 }, - { 0x10007040, 0x23 }, - { 0x10007041, 0xa4 }, - { 0x10007042, 0xe7 }, - { 0x10007043, 0xe8 }, - { 0x10007044, 0x37 }, - { 0x10007045, 0x77 }, - { 0x10007046, 0x00 }, - { 0x10007047, 0x10 }, - { 0x10007048, 0x13 }, - { 0x10007049, 0x07 }, - { 0x1000704a, 0x07 }, - { 0x1000704b, 0x59 }, - { 0x1000704c, 0x23 }, - { 0x1000704d, 0xa8 }, - { 0x1000704e, 0xe7 }, - { 0x1000704f, 0xea }, - { 0x10007050, 0x37 }, - { 0x10007051, 0x77 }, - { 0x10007052, 0x00 }, - { 0x10007053, 0x10 }, - { 0x10007054, 0x13 }, - { 0x10007055, 0x07 }, - { 0x10007056, 0x07 }, - { 0x10007057, 0x78 }, - { 0x10007058, 0x23 }, - { 0x10007059, 0xa6 }, - { 0x1000705a, 0xe7 }, - { 0x1000705b, 0xec }, - { 0x1000705c, 0x67 }, - { 0x1000705d, 0x80 }, - { 0x1000705e, 0x00 }, - { 0x1000705f, 0x00 }, - { 0x10007400, 0x37 }, - { 0x10007401, 0xd7 }, - { 0x10007402, 0x00 }, - { 0x10007403, 0x00 }, - { 0x10007404, 0x83 }, - { 0x10007405, 0x27 }, - { 0x10007406, 0x47 }, - { 0x10007407, 0x56 }, - { 0x10007408, 0xb7 }, - { 0x10007409, 0x06 }, - { 0x1000740a, 0x00 }, - { 0x1000740b, 0x02 }, - { 0x1000740c, 0xb3 }, - { 0x1000740d, 0xf7 }, - { 0x1000740e, 0xd7 }, - { 0x1000740f, 0x00 }, - { 0x10007410, 0x63 }, - { 0x10007411, 0x8a }, - { 0x10007412, 0x07 }, - { 0x10007413, 0x00 }, - { 0x10007414, 0x93 }, - { 0x10007415, 0x06 }, - { 0x10007416, 0x10 }, - { 0x10007417, 0x00 }, - { 0x10007418, 0x23 }, - { 0x10007419, 0x83 }, - { 0x1000741a, 0xd1 }, - { 0x1000741b, 0x44 }, - { 0x1000741c, 0x93 }, - { 0x1000741d, 0x07 }, - { 0x1000741e, 0xf0 }, - { 0x1000741f, 0xff }, - { 0x10007420, 0x23 }, - { 0x10007421, 0x22 }, - { 0x10007422, 0xf7 }, - { 0x10007423, 0x56 }, - { 0x10007424, 0x37 }, - { 0x10007425, 0xd7 }, - { 0x10007426, 0x00 }, - { 0x10007427, 0x00 }, - { 0x10007428, 0x83 }, - { 0x10007429, 0x27 }, - { 0x1000742a, 0x47 }, - { 0x1000742b, 0x58 }, - { 0x1000742c, 0x93 }, - { 0x1000742d, 0xf7 }, - { 0x1000742e, 0x17 }, - { 0x1000742f, 0x00 }, - { 0x10007430, 0x63 }, - { 0x10007431, 0x86 }, - { 0x10007432, 0x07 }, - { 0x10007433, 0x00 }, - { 0x10007434, 0x93 }, - { 0x10007435, 0x07 }, - { 0x10007436, 0x10 }, - { 0x10007437, 0x00 }, - { 0x10007438, 0x23 }, - { 0x10007439, 0x22 }, - { 0x1000743a, 0xf7 }, - { 0x1000743b, 0x58 }, - { 0x1000743c, 0xb7 }, - { 0x1000743d, 0xd7 }, - { 0x1000743e, 0x00 }, - { 0x1000743f, 0x00 }, - { 0x10007440, 0x03 }, - { 0x10007441, 0xa7 }, - { 0x10007442, 0x47 }, - { 0x10007443, 0x58 }, - { 0x10007444, 0xb7 }, - { 0x10007445, 0x07 }, - { 0x10007446, 0x00 }, - { 0x10007447, 0x04 }, - { 0x10007448, 0x33 }, - { 0x10007449, 0x77 }, - { 0x1000744a, 0xf7 }, - { 0x1000744b, 0x00 }, - { 0x1000744c, 0x93 }, - { 0x1000744d, 0x07 }, - { 0x1000744e, 0x00 }, - { 0x1000744f, 0x00 }, - { 0x10007450, 0x63 }, - { 0x10007451, 0x0e }, - { 0x10007452, 0x07 }, - { 0x10007453, 0x04 }, - { 0x10007454, 0x37 }, - { 0x10007455, 0x07 }, - { 0x10007456, 0x00 }, - { 0x10007457, 0x11 }, - { 0x10007458, 0x03 }, - { 0x10007459, 0x47 }, - { 0x1000745a, 0x87 }, - { 0x1000745b, 0x0e }, - { 0x1000745c, 0x93 }, - { 0x1000745d, 0x06 }, - { 0x1000745e, 0x40 }, - { 0x1000745f, 0x00 }, - { 0x10007460, 0x13 }, - { 0x10007461, 0x77 }, - { 0x10007462, 0xf7 }, - { 0x10007463, 0x0f }, - { 0x10007464, 0x63 }, - { 0x10007465, 0x02 }, - { 0x10007466, 0xd7 }, - { 0x10007467, 0x0a }, - { 0x10007468, 0x93 }, - { 0x10007469, 0x06 }, - { 0x1000746a, 0x70 }, - { 0x1000746b, 0x00 }, - { 0x1000746c, 0x63 }, - { 0x1000746d, 0x10 }, - { 0x1000746e, 0xd7 }, - { 0x1000746f, 0x04 }, - { 0x10007470, 0x93 }, - { 0x10007471, 0x07 }, - { 0x10007472, 0x60 }, - { 0x10007473, 0x06 }, - { 0x10007474, 0x37 }, - { 0x10007475, 0xd7 }, - { 0x10007476, 0x00 }, - { 0x10007477, 0x00 }, - { 0x10007478, 0x83 }, - { 0x10007479, 0x46 }, - { 0x1000747a, 0x77 }, - { 0x1000747b, 0xa6 }, - { 0x1000747c, 0x93 }, - { 0x1000747d, 0xe6 }, - { 0x1000747e, 0x06 }, - { 0x1000747f, 0xf8 }, - { 0x10007480, 0x93 }, - { 0x10007481, 0xf6 }, - { 0x10007482, 0xf6 }, - { 0x10007483, 0x0f }, - { 0x10007484, 0xa3 }, - { 0x10007485, 0x03 }, - { 0x10007486, 0xd7 }, - { 0x10007487, 0xa6 }, - { 0x10007488, 0x83 }, - { 0x10007489, 0x46 }, - { 0x1000748a, 0x77 }, - { 0x1000748b, 0xa8 }, - { 0x1000748c, 0x93 }, - { 0x1000748d, 0xe6 }, - { 0x1000748e, 0x06 }, - { 0x1000748f, 0xf8 }, - { 0x10007490, 0x93 }, - { 0x10007491, 0xf6 }, - { 0x10007492, 0xf6 }, - { 0x10007493, 0x0f }, - { 0x10007494, 0xa3 }, - { 0x10007495, 0x03 }, - { 0x10007496, 0xd7 }, - { 0x10007497, 0xa8 }, - { 0x10007498, 0xb7 }, - { 0x10007499, 0xc6 }, - { 0x1000749a, 0x00 }, - { 0x1000749b, 0x00 }, - { 0x1000749c, 0x23 }, - { 0x1000749d, 0x84 }, - { 0x1000749e, 0xf6 }, - { 0x1000749f, 0x06 }, - { 0x100074a0, 0xa3 }, - { 0x100074a1, 0x84 }, - { 0x100074a2, 0xf6 }, - { 0x100074a3, 0x06 }, - { 0x100074a4, 0xb7 }, - { 0x100074a5, 0x06 }, - { 0x100074a6, 0x00 }, - { 0x100074a7, 0x04 }, - { 0x100074a8, 0x23 }, - { 0x100074a9, 0x22 }, - { 0x100074aa, 0xd7 }, - { 0x100074ab, 0x58 }, - { 0x100074ac, 0x37 }, - { 0x100074ad, 0xd7 }, - { 0x100074ae, 0x00 }, - { 0x100074af, 0x00 }, - { 0x100074b0, 0x03 }, - { 0x100074b1, 0x27 }, - { 0x100074b2, 0x47 }, - { 0x100074b3, 0x58 }, - { 0x100074b4, 0xb7 }, - { 0x100074b5, 0x06 }, - { 0x100074b6, 0x00 }, - { 0x100074b7, 0x08 }, - { 0x100074b8, 0x33 }, - { 0x100074b9, 0x77 }, - { 0x100074ba, 0xd7 }, - { 0x100074bb, 0x00 }, - { 0x100074bc, 0x63 }, - { 0x100074bd, 0x04 }, - { 0x100074be, 0x07 }, - { 0x100074bf, 0x04 }, - { 0x100074c0, 0x37 }, - { 0x100074c1, 0x07 }, - { 0x100074c2, 0x00 }, - { 0x100074c3, 0x11 }, - { 0x100074c4, 0x03 }, - { 0x100074c5, 0x47 }, - { 0x100074c6, 0xc7 }, - { 0x100074c7, 0x0e }, - { 0x100074c8, 0x93 }, - { 0x100074c9, 0x06 }, - { 0x100074ca, 0x40 }, - { 0x100074cb, 0x00 }, - { 0x100074cc, 0x13 }, - { 0x100074cd, 0x77 }, - { 0x100074ce, 0xf7 }, - { 0x100074cf, 0x0f }, - { 0x100074d0, 0x63 }, - { 0x100074d1, 0x00 }, - { 0x100074d2, 0xd7 }, - { 0x100074d3, 0x04 }, - { 0x100074d4, 0x93 }, - { 0x100074d5, 0x06 }, - { 0x100074d6, 0x70 }, - { 0x100074d7, 0x00 }, - { 0x100074d8, 0x63 }, - { 0x100074d9, 0x00 }, - { 0x100074da, 0xd7 }, - { 0x100074db, 0x04 }, - { 0x100074dc, 0x63 }, - { 0x100074dd, 0x84 }, - { 0x100074de, 0x07 }, - { 0x100074df, 0x02 }, - { 0x100074e0, 0xb7 }, - { 0x100074e1, 0xd6 }, - { 0x100074e2, 0x00 }, - { 0x100074e3, 0x00 }, - { 0x100074e4, 0x03 }, - { 0x100074e5, 0xc7 }, - { 0x100074e6, 0x56 }, - { 0x100074e7, 0xa4 }, - { 0x100074e8, 0x13 }, - { 0x100074e9, 0x67 }, - { 0x100074ea, 0x07 }, - { 0x100074eb, 0xf8 }, - { 0x100074ec, 0x13 }, - { 0x100074ed, 0x77 }, - { 0x100074ee, 0xf7 }, - { 0x100074ef, 0x0f }, - { 0x100074f0, 0xa3 }, - { 0x100074f1, 0x82 }, - { 0x100074f2, 0xe6 }, - { 0x100074f3, 0xa4 }, - { 0x100074f4, 0x37 }, - { 0x100074f5, 0xc7 }, - { 0x100074f6, 0x00 }, - { 0x100074f7, 0x00 }, - { 0x100074f8, 0x23 }, - { 0x100074f9, 0x02 }, - { 0x100074fa, 0xf7 }, - { 0x100074fb, 0x06 }, - { 0x100074fc, 0xb7 }, - { 0x100074fd, 0x07 }, - { 0x100074fe, 0x00 }, - { 0x100074ff, 0x08 }, - { 0x10007500, 0x23 }, - { 0x10007501, 0xa2 }, - { 0x10007502, 0xf6 }, - { 0x10007503, 0x58 }, - { 0x10007504, 0x67 }, - { 0x10007505, 0x80 }, - { 0x10007506, 0x00 }, - { 0x10007507, 0x00 }, - { 0x10007508, 0x93 }, - { 0x10007509, 0x07 }, - { 0x1000750a, 0x80 }, - { 0x1000750b, 0x08 }, - { 0x1000750c, 0x6f }, - { 0x1000750d, 0xf0 }, - { 0x1000750e, 0x9f }, - { 0x1000750f, 0xf6 }, - { 0x10007510, 0x93 }, - { 0x10007511, 0x07 }, - { 0x10007512, 0x80 }, - { 0x10007513, 0x08 }, - { 0x10007514, 0x6f }, - { 0x10007515, 0xf0 }, - { 0x10007516, 0xdf }, - { 0x10007517, 0xfc }, - { 0x10007518, 0x93 }, - { 0x10007519, 0x07 }, - { 0x1000751a, 0x60 }, - { 0x1000751b, 0x06 }, - { 0x1000751c, 0x6f }, - { 0x1000751d, 0xf0 }, - { 0x1000751e, 0x5f }, - { 0x1000751f, 0xfc }, - { 0x10007520, 0x37 }, - { 0x10007521, 0xd7 }, - { 0x10007522, 0x00 }, - { 0x10007523, 0x00 }, - { 0x10007524, 0x83 }, - { 0x10007525, 0x27 }, - { 0x10007526, 0x07 }, - { 0x10007527, 0x53 }, - { 0x10007528, 0xb7 }, - { 0x10007529, 0x06 }, - { 0x1000752a, 0x02 }, - { 0x1000752b, 0x00 }, - { 0x1000752c, 0xb3 }, - { 0x1000752d, 0xf7 }, - { 0x1000752e, 0xd7 }, - { 0x1000752f, 0x00 }, - { 0x10007530, 0x63 }, - { 0x10007531, 0x88 }, - { 0x10007532, 0x07 }, - { 0x10007533, 0x00 }, - { 0x10007534, 0x13 }, - { 0x10007535, 0x06 }, - { 0x10007536, 0xa0 }, - { 0x10007537, 0x05 }, - { 0x10007538, 0x23 }, - { 0x10007539, 0xa8 }, - { 0x1000753a, 0xc1 }, - { 0x1000753b, 0x56 }, - { 0x1000753c, 0x23 }, - { 0x1000753d, 0x28 }, - { 0x1000753e, 0xd7 }, - { 0x1000753f, 0x52 }, - { 0x10007540, 0x67 }, - { 0x10007541, 0x80 }, - { 0x10007542, 0x00 }, - { 0x10007543, 0x00 }, - { 0x10007544, 0x37 }, - { 0x10007545, 0xd7 }, - { 0x10007546, 0x00 }, - { 0x10007547, 0x10 }, - { 0x10007548, 0x83 }, - { 0x10007549, 0x47 }, - { 0x1000754a, 0x07 }, - { 0x1000754b, 0xd9 }, - { 0x1000754c, 0x93 }, - { 0x1000754d, 0x06 }, - { 0x1000754e, 0x20 }, - { 0x1000754f, 0x00 }, - { 0x10007550, 0x93 }, - { 0x10007551, 0xf7 }, - { 0x10007552, 0xf7 }, - { 0x10007553, 0x0f }, - { 0x10007554, 0x63 }, - { 0x10007555, 0x9c }, - { 0x10007556, 0xd7 }, - { 0x10007557, 0x02 }, - { 0x10007558, 0xb7 }, - { 0x10007559, 0xc6 }, - { 0x1000755a, 0x00 }, - { 0x1000755b, 0x00 }, - { 0x1000755c, 0x83 }, - { 0x1000755d, 0xc7 }, - { 0x1000755e, 0x26 }, - { 0x1000755f, 0x04 }, - { 0x10007560, 0x93 }, - { 0x10007561, 0xf7 }, - { 0x10007562, 0xf7 }, - { 0x10007563, 0x07 }, - { 0x10007564, 0x23 }, - { 0x10007565, 0x81 }, - { 0x10007566, 0xf6 }, - { 0x10007567, 0x04 }, - { 0x10007568, 0xb7 }, - { 0x10007569, 0xd6 }, - { 0x1000756a, 0x00 }, - { 0x1000756b, 0x00 }, - { 0x1000756c, 0x83 }, - { 0x1000756d, 0xc7 }, - { 0x1000756e, 0xa6 }, - { 0x1000756f, 0xe1 }, - { 0x10007570, 0x93 }, - { 0x10007571, 0xf7 }, - { 0x10007572, 0xf7 }, - { 0x10007573, 0x07 }, - { 0x10007574, 0x23 }, - { 0x10007575, 0x8d }, - { 0x10007576, 0xf6 }, - { 0x10007577, 0xe0 }, - { 0x10007578, 0x23 }, - { 0x10007579, 0x08 }, - { 0x1000757a, 0x07 }, - { 0x1000757b, 0xd8 }, - { 0x1000757c, 0x83 }, - { 0x1000757d, 0x47 }, - { 0x1000757e, 0x47 }, - { 0x1000757f, 0xd9 }, - { 0x10007580, 0x93 }, - { 0x10007581, 0x87 }, - { 0x10007582, 0x17 }, - { 0x10007583, 0x00 }, - { 0x10007584, 0x93 }, - { 0x10007585, 0xf7 }, - { 0x10007586, 0xf7 }, - { 0x10007587, 0x0f }, - { 0x10007588, 0x23 }, - { 0x10007589, 0x0a }, - { 0x1000758a, 0xf7 }, - { 0x1000758b, 0xd8 }, - { 0x1000758c, 0x67 }, - { 0x1000758d, 0x80 }, - { 0x1000758e, 0x00 }, - { 0x1000758f, 0x00 }, - { 0x10007590, 0xb7 }, - { 0x10007591, 0xd7 }, - { 0x10007592, 0x00 }, - { 0x10007593, 0x00 }, - { 0x10007594, 0x83 }, - { 0x10007595, 0xc7 }, - { 0x10007596, 0x07 }, - { 0x10007597, 0x47 }, - { 0x10007598, 0x93 }, - { 0x10007599, 0xf7 }, - { 0x1000759a, 0x07 }, - { 0x1000759b, 0x01 }, - { 0x1000759c, 0x63 }, - { 0x1000759d, 0x8a }, - { 0x1000759e, 0x07 }, - { 0x1000759f, 0x06 }, - { 0x100075a0, 0x63 }, - { 0x100075a1, 0x02 }, - { 0x100075a2, 0x05 }, - { 0x100075a3, 0x06 }, - { 0x100075a4, 0x37 }, - { 0x100075a5, 0xc7 }, - { 0x100075a6, 0x00 }, - { 0x100075a7, 0x00 }, - { 0x100075a8, 0x83 }, - { 0x100075a9, 0x27 }, - { 0x100075aa, 0xc7 }, - { 0x100075ab, 0x5f }, - { 0x100075ac, 0x23 }, - { 0x100075ad, 0xae }, - { 0x100075ae, 0xf1 }, - { 0x100075af, 0x40 }, - { 0x100075b0, 0xb7 }, - { 0x100075b1, 0x06 }, - { 0x100075b2, 0x00 }, - { 0x100075b3, 0x10 }, - { 0x100075b4, 0xb3 }, - { 0x100075b5, 0xf7 }, - { 0x100075b6, 0xd7 }, - { 0x100075b7, 0x00 }, - { 0x100075b8, 0x63 }, - { 0x100075b9, 0x8c }, - { 0x100075ba, 0x07 }, - { 0x100075bb, 0x04 }, - { 0x100075bc, 0x83 }, - { 0x100075bd, 0x47 }, - { 0x100075be, 0x07 }, - { 0x100075bf, 0x56 }, - { 0x100075c0, 0x93 }, - { 0x100075c1, 0xf7 }, - { 0x100075c2, 0x87 }, - { 0x100075c3, 0x01 }, - { 0x100075c4, 0x63 }, - { 0x100075c5, 0x86 }, - { 0x100075c6, 0x07 }, - { 0x100075c7, 0x04 }, - { 0x100075c8, 0x83 }, - { 0x100075c9, 0x47 }, - { 0x100075ca, 0x17 }, - { 0x100075cb, 0x08 }, - { 0x100075cc, 0x93 }, - { 0x100075cd, 0xf7 }, - { 0x100075ce, 0x47 }, - { 0x100075cf, 0x00 }, - { 0x100075d0, 0x63 }, - { 0x100075d1, 0x80 }, - { 0x100075d2, 0x07 }, - { 0x100075d3, 0x04 }, - { 0x100075d4, 0xb7 }, - { 0x100075d5, 0xc7 }, - { 0x100075d6, 0xc2 }, - { 0x100075d7, 0x3f }, - { 0x100075d8, 0x93 }, - { 0x100075d9, 0x87 }, - { 0x100075da, 0x07 }, - { 0x100075db, 0xfc }, - { 0x100075dc, 0x83 }, - { 0x100075dd, 0xa7 }, - { 0x100075de, 0x47 }, - { 0x100075df, 0x00 }, - { 0x100075e0, 0x93 }, - { 0x100075e1, 0xd7 }, - { 0x100075e2, 0x17 }, - { 0x100075e3, 0x00 }, - { 0x100075e4, 0x93 }, - { 0x100075e5, 0xf7 }, - { 0x100075e6, 0x17 }, - { 0x100075e7, 0x00 }, - { 0x100075e8, 0x63 }, - { 0x100075e9, 0x84 }, - { 0x100075ea, 0x07 }, - { 0x100075eb, 0x02 }, - { 0x100075ec, 0x23 }, - { 0x100075ed, 0x8a }, - { 0x100075ee, 0xf1 }, - { 0x100075ef, 0x40 }, - { 0x100075f0, 0xb7 }, - { 0x100075f1, 0x07 }, - { 0x100075f2, 0x00 }, - { 0x100075f3, 0xc0 }, - { 0x100075f4, 0x37 }, - { 0x100075f5, 0xf7 }, - { 0x100075f6, 0x00 }, - { 0x100075f7, 0x00 }, - { 0x100075f8, 0x93 }, - { 0x100075f9, 0x87 }, - { 0x100075fa, 0xf7 }, - { 0x100075fb, 0xff }, - { 0x100075fc, 0x23 }, - { 0x100075fd, 0x2c }, - { 0x100075fe, 0xf7 }, - { 0x100075ff, 0x06 }, - { 0x10007600, 0x67 }, - { 0x10007601, 0x80 }, - { 0x10007602, 0x00 }, - { 0x10007603, 0x00 }, - { 0x10007604, 0x23 }, - { 0x10007605, 0x8a }, - { 0x10007606, 0x01 }, - { 0x10007607, 0x40 }, - { 0x10007608, 0xb7 }, - { 0x10007609, 0xf7 }, - { 0x1000760a, 0x00 }, - { 0x1000760b, 0x00 }, - { 0x1000760c, 0x23 }, - { 0x1000760d, 0xac }, - { 0x1000760e, 0x07 }, - { 0x1000760f, 0x06 }, - { 0x10007610, 0x67 }, - { 0x10007611, 0x80 }, - { 0x10007612, 0x00 }, - { 0x10007613, 0x00 }, - { 0x10007614, 0x13 }, - { 0x10007615, 0x01 }, - { 0x10007616, 0x01 }, - { 0x10007617, 0xff }, - { 0x10007618, 0x23 }, - { 0x10007619, 0x26 }, - { 0x1000761a, 0x11 }, - { 0x1000761b, 0x00 }, - { 0x1000761c, 0x23 }, - { 0x1000761d, 0x24 }, - { 0x1000761e, 0x81 }, - { 0x1000761f, 0x00 }, - { 0x10007620, 0x37 }, - { 0x10007621, 0xc7 }, - { 0x10007622, 0x00 }, - { 0x10007623, 0x00 }, - { 0x10007624, 0x83 }, - { 0x10007625, 0x47 }, - { 0x10007626, 0x07 }, - { 0x10007627, 0x56 }, - { 0x10007628, 0x93 }, - { 0x10007629, 0xf7 }, - { 0x1000762a, 0x17 }, - { 0x1000762b, 0x00 }, - { 0x1000762c, 0x63 }, - { 0x1000762d, 0x98 }, - { 0x1000762e, 0x07 }, - { 0x1000762f, 0x00 }, - { 0x10007630, 0x83 }, - { 0x10007631, 0x47 }, - { 0x10007632, 0x07 }, - { 0x10007633, 0x56 }, - { 0x10007634, 0x93 }, - { 0x10007635, 0xf7 }, - { 0x10007636, 0x27 }, - { 0x10007637, 0x00 }, - { 0x10007638, 0x63 }, - { 0x10007639, 0x82 }, - { 0x1000763a, 0x07 }, - { 0x1000763b, 0x08 }, - { 0x1000763c, 0x37 }, - { 0x1000763d, 0xd4 }, - { 0x1000763e, 0x00 }, - { 0x1000763f, 0x00 }, - { 0x10007640, 0x83 }, - { 0x10007641, 0x47 }, - { 0x10007642, 0x14 }, - { 0x10007643, 0x47 }, - { 0x10007644, 0x93 }, - { 0x10007645, 0xf7 }, - { 0x10007646, 0x27 }, - { 0x10007647, 0x00 }, - { 0x10007648, 0x63 }, - { 0x10007649, 0x8a }, - { 0x1000764a, 0x07 }, - { 0x1000764b, 0x06 }, - { 0x1000764c, 0x93 }, - { 0x1000764d, 0x05 }, - { 0x1000764e, 0x10 }, - { 0x1000764f, 0x00 }, - { 0x10007650, 0x13 }, - { 0x10007651, 0x05 }, - { 0x10007652, 0x20 }, - { 0x10007653, 0x10 }, - { 0x10007654, 0xef }, - { 0x10007655, 0xa0 }, - { 0x10007656, 0x8f }, - { 0x10007657, 0x9a }, - { 0x10007658, 0x37 }, - { 0x10007659, 0x05 }, - { 0x1000765a, 0x01 }, - { 0x1000765b, 0x00 }, - { 0x1000765c, 0x93 }, - { 0x1000765d, 0x05 }, - { 0x1000765e, 0x00 }, - { 0x1000765f, 0x01 }, - { 0x10007660, 0x13 }, - { 0x10007661, 0x05 }, - { 0x10007662, 0xb5 }, - { 0x10007663, 0xa0 }, - { 0x10007664, 0xef }, - { 0x10007665, 0xa0 }, - { 0x10007666, 0x8f }, - { 0x10007667, 0x99 }, - { 0x10007668, 0x83 }, - { 0x10007669, 0x47 }, - { 0x1000766a, 0x24 }, - { 0x1000766b, 0xe0 }, - { 0x1000766c, 0x13 }, - { 0x1000766d, 0x05 }, - { 0x1000766e, 0x80 }, - { 0x1000766f, 0x3e }, - { 0x10007670, 0x93 }, - { 0x10007671, 0x05 }, - { 0x10007672, 0x00 }, - { 0x10007673, 0x00 }, - { 0x10007674, 0x93 }, - { 0x10007675, 0xe7 }, - { 0x10007676, 0x07 }, - { 0x10007677, 0xf8 }, - { 0x10007678, 0x93 }, - { 0x10007679, 0xf7 }, - { 0x1000767a, 0xf7 }, - { 0x1000767b, 0x0f }, - { 0x1000767c, 0x23 }, - { 0x1000767d, 0x01 }, - { 0x1000767e, 0xf4 }, - { 0x1000767f, 0xe0 }, - { 0x10007680, 0x83 }, - { 0x10007681, 0x47 }, - { 0x10007682, 0x24 }, - { 0x10007683, 0xe0 }, - { 0x10007684, 0x93 }, - { 0x10007685, 0xf7 }, - { 0x10007686, 0xf7 }, - { 0x10007687, 0x0f }, - { 0x10007688, 0x93 }, - { 0x10007689, 0xe7 }, - { 0x1000768a, 0x07 }, - { 0x1000768b, 0x04 }, - { 0x1000768c, 0x23 }, - { 0x1000768d, 0x01 }, - { 0x1000768e, 0xf4 }, - { 0x1000768f, 0xe0 }, - { 0x10007690, 0xef }, - { 0x10007691, 0xe0 }, - { 0x10007692, 0x8f }, - { 0x10007693, 0xb9 }, - { 0x10007694, 0x83 }, - { 0x10007695, 0x47 }, - { 0x10007696, 0x34 }, - { 0x10007697, 0xe0 }, - { 0x10007698, 0x93 }, - { 0x10007699, 0xf7 }, - { 0x1000769a, 0x07 }, - { 0x1000769b, 0x02 }, - { 0x1000769c, 0xe3 }, - { 0x1000769d, 0x9c }, - { 0x1000769e, 0x07 }, - { 0x1000769f, 0xfe }, - { 0x100076a0, 0x37 }, - { 0x100076a1, 0x05 }, - { 0x100076a2, 0x01 }, - { 0x100076a3, 0x00 }, - { 0x100076a4, 0x93 }, - { 0x100076a5, 0x05 }, - { 0x100076a6, 0x00 }, - { 0x100076a7, 0x00 }, - { 0x100076a8, 0x13 }, - { 0x100076a9, 0x05 }, - { 0x100076aa, 0xb5 }, - { 0x100076ab, 0xa0 }, - { 0x100076ac, 0xef }, - { 0x100076ad, 0xa0 }, - { 0x100076ae, 0x0f }, - { 0x100076af, 0x95 }, - { 0x100076b0, 0x83 }, - { 0x100076b1, 0x47 }, - { 0x100076b2, 0x14 }, - { 0x100076b3, 0x47 }, - { 0x100076b4, 0x93 }, - { 0x100076b5, 0xf7 }, - { 0x100076b6, 0xd7 }, - { 0x100076b7, 0x0f }, - { 0x100076b8, 0xa3 }, - { 0x100076b9, 0x08 }, - { 0x100076ba, 0xf4 }, - { 0x100076bb, 0x46 }, - { 0x100076bc, 0x03 }, - { 0x100076bd, 0xa7 }, - { 0x100076be, 0x01 }, - { 0x100076bf, 0x57 }, - { 0x100076c0, 0x93 }, - { 0x100076c1, 0x07 }, - { 0x100076c2, 0xa0 }, - { 0x100076c3, 0x05 }, - { 0x100076c4, 0x63 }, - { 0x100076c5, 0x14 }, - { 0x100076c6, 0xf7 }, - { 0x100076c7, 0x04 }, - { 0x100076c8, 0x37 }, - { 0x100076c9, 0x07 }, - { 0x100076ca, 0x00 }, - { 0x100076cb, 0x11 }, - { 0x100076cc, 0x83 }, - { 0x100076cd, 0x47 }, - { 0x100076ce, 0x07 }, - { 0x100076cf, 0x01 }, - { 0x100076d0, 0x13 }, - { 0x100076d1, 0x06 }, - { 0x100076d2, 0x30 }, - { 0x100076d3, 0x00 }, - { 0x100076d4, 0x93 }, - { 0x100076d5, 0xf7 }, - { 0x100076d6, 0xf7 }, - { 0x100076d7, 0x0f }, - { 0x100076d8, 0x63 }, - { 0x100076d9, 0x9a }, - { 0x100076da, 0xc7 }, - { 0x100076db, 0x02 }, - { 0x100076dc, 0x03 }, - { 0x100076dd, 0x47 }, - { 0x100076de, 0x87 }, - { 0x100076df, 0x01 }, - { 0x100076e0, 0x13 }, - { 0x100076e1, 0x77 }, - { 0x100076e2, 0xf7 }, - { 0x100076e3, 0x0f }, - { 0x100076e4, 0x63 }, - { 0x100076e5, 0x14 }, - { 0x100076e6, 0xf7 }, - { 0x100076e7, 0x02 }, - { 0x100076e8, 0x37 }, - { 0x100076e9, 0xd7 }, - { 0x100076ea, 0x00 }, - { 0x100076eb, 0x00 }, - { 0x100076ec, 0x83 }, - { 0x100076ed, 0x47 }, - { 0x100076ee, 0x37 }, - { 0x100076ef, 0x54 }, - { 0x100076f0, 0x93 }, - { 0x100076f1, 0xf7 }, - { 0x100076f2, 0xf7 }, - { 0x100076f3, 0x0f }, - { 0x100076f4, 0x93 }, - { 0x100076f5, 0xe7 }, - { 0x100076f6, 0x07 }, - { 0x100076f7, 0x02 }, - { 0x100076f8, 0xa3 }, - { 0x100076f9, 0x01 }, - { 0x100076fa, 0xf7 }, - { 0x100076fb, 0x54 }, - { 0x100076fc, 0x83 }, - { 0x100076fd, 0x47 }, - { 0x100076fe, 0x37 }, - { 0x100076ff, 0x54 }, - { 0x10007700, 0x93 }, - { 0x10007701, 0xf7 }, - { 0x10007702, 0xf7 }, - { 0x10007703, 0x0d }, - { 0x10007704, 0xa3 }, - { 0x10007705, 0x01 }, - { 0x10007706, 0xf7 }, - { 0x10007707, 0x54 }, - { 0x10007708, 0x23 }, - { 0x10007709, 0xa8 }, - { 0x1000770a, 0x01 }, - { 0x1000770b, 0x56 }, - { 0x1000770c, 0xb7 }, - { 0x1000770d, 0xd7 }, - { 0x1000770e, 0x00 }, - { 0x1000770f, 0x10 }, - { 0x10007710, 0x03 }, - { 0x10007711, 0xc7 }, - { 0x10007712, 0x07 }, - { 0x10007713, 0xd9 }, - { 0x10007714, 0x93 }, - { 0x10007715, 0x06 }, - { 0x10007716, 0x10 }, - { 0x10007717, 0x00 }, - { 0x10007718, 0x13 }, - { 0x10007719, 0x77 }, - { 0x1000771a, 0xf7 }, - { 0x1000771b, 0x0f }, - { 0x1000771c, 0x63 }, - { 0x1000771d, 0x1a }, - { 0x1000771e, 0xd7 }, - { 0x1000771f, 0x04 }, - { 0x10007720, 0x03 }, - { 0x10007721, 0xc7 }, - { 0x10007722, 0x27 }, - { 0x10007723, 0xd9 }, - { 0x10007724, 0x13 }, - { 0x10007725, 0x07 }, - { 0x10007726, 0x17 }, - { 0x10007727, 0x00 }, - { 0x10007728, 0x13 }, - { 0x10007729, 0x77 }, - { 0x1000772a, 0xf7 }, - { 0x1000772b, 0x0f }, - { 0x1000772c, 0x23 }, - { 0x1000772d, 0x89 }, - { 0x1000772e, 0xe7 }, - { 0x1000772f, 0xd8 }, - { 0x10007730, 0x83 }, - { 0x10007731, 0xc6 }, - { 0x10007732, 0x27 }, - { 0x10007733, 0xd9 }, - { 0x10007734, 0x03 }, - { 0x10007735, 0xc7 }, - { 0x10007736, 0x17 }, - { 0x10007737, 0xd9 }, - { 0x10007738, 0x93 }, - { 0x10007739, 0xf6 }, - { 0x1000773a, 0xf6 }, - { 0x1000773b, 0x0f }, - { 0x1000773c, 0x13 }, - { 0x1000773d, 0x77 }, - { 0x1000773e, 0xf7 }, - { 0x1000773f, 0x0f }, - { 0x10007740, 0x63 }, - { 0x10007741, 0xe8 }, - { 0x10007742, 0xe6 }, - { 0x10007743, 0x02 }, - { 0x10007744, 0xb7 }, - { 0x10007745, 0xd6 }, - { 0x10007746, 0x00 }, - { 0x10007747, 0x00 }, - { 0x10007748, 0x03 }, - { 0x10007749, 0xc7 }, - { 0x1000774a, 0xa6 }, - { 0x1000774b, 0xe1 }, - { 0x1000774c, 0x13 }, - { 0x1000774d, 0x67 }, - { 0x1000774e, 0x07 }, - { 0x1000774f, 0xf8 }, - { 0x10007750, 0x13 }, - { 0x10007751, 0x77 }, - { 0x10007752, 0xf7 }, - { 0x10007753, 0x0f }, - { 0x10007754, 0x23 }, - { 0x10007755, 0x8d }, - { 0x10007756, 0xe6 }, - { 0x10007757, 0xe0 }, - { 0x10007758, 0x03 }, - { 0x10007759, 0xc7 }, - { 0x1000775a, 0x37 }, - { 0x1000775b, 0xd9 }, - { 0x1000775c, 0x13 }, - { 0x1000775d, 0x07 }, - { 0x1000775e, 0x17 }, - { 0x1000775f, 0x00 }, - { 0x10007760, 0x13 }, - { 0x10007761, 0x77 }, - { 0x10007762, 0xf7 }, - { 0x10007763, 0x0f }, - { 0x10007764, 0xa3 }, - { 0x10007765, 0x89 }, - { 0x10007766, 0xe7 }, - { 0x10007767, 0xd8 }, - { 0x10007768, 0x13 }, - { 0x10007769, 0x07 }, - { 0x1000776a, 0x20 }, - { 0x1000776b, 0x00 }, - { 0x1000776c, 0x23 }, - { 0x1000776d, 0x88 }, - { 0x1000776e, 0xe7 }, - { 0x1000776f, 0xd8 }, - { 0x10007770, 0x83 }, - { 0x10007771, 0x20 }, - { 0x10007772, 0xc1 }, - { 0x10007773, 0x00 }, - { 0x10007774, 0x03 }, - { 0x10007775, 0x24 }, - { 0x10007776, 0x81 }, - { 0x10007777, 0x00 }, - { 0x10007778, 0x13 }, - { 0x10007779, 0x01 }, - { 0x1000777a, 0x01 }, - { 0x1000777b, 0x01 }, - { 0x1000777c, 0x67 }, - { 0x1000777d, 0x80 }, - { 0x1000777e, 0x00 }, - { 0x1000777f, 0x00 }, - { 0x10007780, 0x03 }, - { 0x10007781, 0xc7 }, - { 0x10007782, 0xa1 }, - { 0x10007783, 0x40 }, - { 0x10007784, 0x93 }, - { 0x10007785, 0x06 }, - { 0x10007786, 0x10 }, - { 0x10007787, 0x00 }, - { 0x10007788, 0x63 }, - { 0x10007789, 0x16 }, - { 0x1000778a, 0xd7 }, - { 0x1000778b, 0x00 }, - { 0x1000778c, 0xb7 }, - { 0x1000778d, 0xd6 }, - { 0x1000778e, 0x00 }, - { 0x1000778f, 0x10 }, - { 0x10007790, 0xa3 }, - { 0x10007791, 0x8a }, - { 0x10007792, 0xe6 }, - { 0x10007793, 0xd8 }, - { 0x10007794, 0x83 }, - { 0x10007795, 0xc7 }, - { 0x10007796, 0xa1 }, - { 0x10007797, 0x40 }, - { 0x10007798, 0x63 }, - { 0x10007799, 0x9c }, - { 0x1000779a, 0x07 }, - { 0x1000779b, 0x06 }, - { 0x1000779c, 0x13 }, - { 0x1000779d, 0x01 }, - { 0x1000779e, 0x01 }, - { 0x1000779f, 0xff }, - { 0x100077a0, 0x23 }, - { 0x100077a1, 0x22 }, - { 0x100077a2, 0x91 }, - { 0x100077a3, 0x00 }, - { 0x100077a4, 0x23 }, - { 0x100077a5, 0x26 }, - { 0x100077a6, 0x11 }, - { 0x100077a7, 0x00 }, - { 0x100077a8, 0x23 }, - { 0x100077a9, 0x24 }, - { 0x100077aa, 0x81 }, - { 0x100077ab, 0x00 }, - { 0x100077ac, 0xb7 }, - { 0x100077ad, 0xc4 }, - { 0x100077ae, 0x00 }, - { 0x100077af, 0x00 }, - { 0x100077b0, 0x83 }, - { 0x100077b1, 0xc7 }, - { 0x100077b2, 0x04 }, - { 0x100077b3, 0x56 }, - { 0x100077b4, 0x13 }, - { 0x100077b5, 0x07 }, - { 0x100077b6, 0x80 }, - { 0x100077b7, 0x01 }, - { 0x100077b8, 0x93 }, - { 0x100077b9, 0xf7 }, - { 0x100077ba, 0xf7 }, - { 0x100077bb, 0x0f }, - { 0x100077bc, 0x63 }, - { 0x100077bd, 0x70 }, - { 0x100077be, 0xf7 }, - { 0x100077bf, 0x04 }, - { 0x100077c0, 0x37 }, - { 0x100077c1, 0xd4 }, - { 0x100077c2, 0x00 }, - { 0x100077c3, 0x10 }, - { 0x100077c4, 0x83 }, - { 0x100077c5, 0x47 }, - { 0x100077c6, 0x54 }, - { 0x100077c7, 0xd9 }, - { 0x100077c8, 0x93 }, - { 0x100077c9, 0xf7 }, - { 0x100077ca, 0xf7 }, - { 0x100077cb, 0x0f }, - { 0x100077cc, 0x63 }, - { 0x100077cd, 0x88 }, - { 0x100077ce, 0x07 }, - { 0x100077cf, 0x02 }, - { 0x100077d0, 0x93 }, - { 0x100077d1, 0x07 }, - { 0x100077d2, 0x10 }, - { 0x100077d3, 0x00 }, - { 0x100077d4, 0x23 }, - { 0x100077d5, 0x82 }, - { 0x100077d6, 0xf4 }, - { 0x100077d7, 0x58 }, - { 0x100077d8, 0x03 }, - { 0x100077d9, 0x45 }, - { 0x100077da, 0x64 }, - { 0x100077db, 0xd9 }, - { 0x100077dc, 0xb7 }, - { 0x100077dd, 0x15 }, - { 0x100077de, 0x00 }, - { 0x100077df, 0x00 }, - { 0x100077e0, 0x93 }, - { 0x100077e1, 0x85 }, - { 0x100077e2, 0x85 }, - { 0x100077e3, 0x38 }, - { 0x100077e4, 0x13 }, - { 0x100077e5, 0x75 }, - { 0x100077e6, 0xf5 }, - { 0x100077e7, 0x0f }, - { 0x100077e8, 0xef }, - { 0x100077e9, 0xe0 }, - { 0x100077ea, 0x9f }, - { 0x100077eb, 0xd0 }, - { 0x100077ec, 0x93 }, - { 0x100077ed, 0x55 }, - { 0x100077ee, 0xf5 }, - { 0x100077ef, 0x41 }, - { 0x100077f0, 0xef }, - { 0x100077f1, 0xe0 }, - { 0x100077f2, 0x8f }, - { 0x100077f3, 0xa3 }, - { 0x100077f4, 0x23 }, - { 0x100077f5, 0x82 }, - { 0x100077f6, 0x04 }, - { 0x100077f7, 0x58 }, - { 0x100077f8, 0xa3 }, - { 0x100077f9, 0x0a }, - { 0x100077fa, 0x04 }, - { 0x100077fb, 0xd8 }, - { 0x100077fc, 0x83 }, - { 0x100077fd, 0x20 }, - { 0x100077fe, 0xc1 }, - { 0x100077ff, 0x00 }, - { 0x10007800, 0x03 }, - { 0x10007801, 0x24 }, - { 0x10007802, 0x81 }, - { 0x10007803, 0x00 }, - { 0x10007804, 0x83 }, - { 0x10007805, 0x24 }, - { 0x10007806, 0x41 }, - { 0x10007807, 0x00 }, - { 0x10007808, 0x13 }, - { 0x10007809, 0x01 }, - { 0x1000780a, 0x01 }, - { 0x1000780b, 0x01 }, - { 0x1000780c, 0x67 }, - { 0x1000780d, 0x80 }, - { 0x1000780e, 0x00 }, - { 0x1000780f, 0x00 }, - { 0x10007810, 0x67 }, - { 0x10007811, 0x80 }, - { 0x10007812, 0x00 }, - { 0x10007813, 0x00 }, - { 0x10007814, 0x13 }, - { 0x10007815, 0x01 }, - { 0x10007816, 0x01 }, - { 0x10007817, 0xff }, - { 0x10007818, 0x23 }, - { 0x10007819, 0x26 }, - { 0x1000781a, 0x11 }, - { 0x1000781b, 0x00 }, - { 0x1000781c, 0xef }, - { 0x1000781d, 0xd0 }, - { 0x1000781e, 0x8f }, - { 0x1000781f, 0x86 }, - { 0x10007820, 0x83 }, - { 0x10007821, 0xc7 }, - { 0x10007822, 0x11 }, - { 0x10007823, 0x42 }, - { 0x10007824, 0x63 }, - { 0x10007825, 0x86 }, - { 0x10007826, 0x07 }, - { 0x10007827, 0x00 }, - { 0x10007828, 0x03 }, - { 0x10007829, 0xc7 }, - { 0x1000782a, 0x01 }, - { 0x1000782b, 0x42 }, - { 0x1000782c, 0x63 }, - { 0x1000782d, 0x10 }, - { 0x1000782e, 0x07 }, - { 0x1000782f, 0x02 }, - { 0x10007830, 0x83 }, - { 0x10007831, 0xc6 }, - { 0x10007832, 0x21 }, - { 0x10007833, 0x41 }, - { 0x10007834, 0x13 }, - { 0x10007835, 0x07 }, - { 0x10007836, 0xf0 }, - { 0x10007837, 0x01 }, - { 0x10007838, 0x13 }, - { 0x10007839, 0x05 }, - { 0x1000783a, 0xf0 }, - { 0x1000783b, 0x01 }, - { 0x1000783c, 0x63 }, - { 0x1000783d, 0x98 }, - { 0x1000783e, 0xe6 }, - { 0x1000783f, 0x02 }, - { 0x10007840, 0x63 }, - { 0x10007841, 0x8a }, - { 0x10007842, 0x07 }, - { 0x10007843, 0x02 }, - { 0x10007844, 0x83 }, - { 0x10007845, 0xc7 }, - { 0x10007846, 0x01 }, - { 0x10007847, 0x42 }, - { 0x10007848, 0x63 }, - { 0x10007849, 0x86 }, - { 0x1000784a, 0x07 }, - { 0x1000784b, 0x02 }, - { 0x1000784c, 0x83 }, - { 0x1000784d, 0xc7 }, - { 0x1000784e, 0x31 }, - { 0x1000784f, 0x42 }, - { 0x10007850, 0x63 }, - { 0x10007851, 0x86 }, - { 0x10007852, 0x07 }, - { 0x10007853, 0x00 }, - { 0x10007854, 0x83 }, - { 0x10007855, 0xc7 }, - { 0x10007856, 0x21 }, - { 0x10007857, 0x42 }, - { 0x10007858, 0x63 }, - { 0x10007859, 0x9e }, - { 0x1000785a, 0x07 }, - { 0x1000785b, 0x00 }, - { 0x1000785c, 0x03 }, - { 0x1000785d, 0xc7 }, - { 0x1000785e, 0x21 }, - { 0x1000785f, 0x41 }, - { 0x10007860, 0x93 }, - { 0x10007861, 0x07 }, - { 0x10007862, 0xb0 }, - { 0x10007863, 0x01 }, - { 0x10007864, 0x63 }, - { 0x10007865, 0x08 }, - { 0x10007866, 0xf7 }, - { 0x10007867, 0x00 }, - { 0x10007868, 0x13 }, - { 0x10007869, 0x05 }, - { 0x1000786a, 0xb0 }, - { 0x1000786b, 0x01 }, - { 0x1000786c, 0xef }, - { 0x1000786d, 0xd0 }, - { 0x1000786e, 0x0f }, - { 0x1000786f, 0xcf }, - { 0x10007870, 0xef }, - { 0x10007871, 0xd0 }, - { 0x10007872, 0x8f }, - { 0x10007873, 0xa4 }, - { 0x10007874, 0x93 }, - { 0x10007875, 0x06 }, - { 0x10007876, 0x10 }, - { 0x10007877, 0x00 }, - { 0x10007878, 0xa3 }, - { 0x10007879, 0x89 }, - { 0x1000787a, 0xd1 }, - { 0x1000787b, 0x40 }, - { 0x1000787c, 0x37 }, - { 0x1000787d, 0xd7 }, - { 0x1000787e, 0x00 }, - { 0x1000787f, 0x10 }, - { 0x10007880, 0x83 }, - { 0x10007881, 0x47 }, - { 0x10007882, 0x07 }, - { 0x10007883, 0xd9 }, - { 0x10007884, 0x93 }, - { 0x10007885, 0xf7 }, - { 0x10007886, 0xf7 }, - { 0x10007887, 0x0f }, - { 0x10007888, 0x63 }, - { 0x10007889, 0x90 }, - { 0x1000788a, 0x07 }, - { 0x1000788b, 0x02 }, - { 0x1000788c, 0x37 }, - { 0x1000788d, 0xc6 }, - { 0x1000788e, 0x00 }, - { 0x1000788f, 0x00 }, - { 0x10007890, 0x83 }, - { 0x10007891, 0x47 }, - { 0x10007892, 0x26 }, - { 0x10007893, 0x04 }, - { 0x10007894, 0x93 }, - { 0x10007895, 0xe7 }, - { 0x10007896, 0x07 }, - { 0x10007897, 0xf8 }, - { 0x10007898, 0x93 }, - { 0x10007899, 0xf7 }, - { 0x1000789a, 0xf7 }, - { 0x1000789b, 0x0f }, - { 0x1000789c, 0x23 }, - { 0x1000789d, 0x01 }, - { 0x1000789e, 0xf6 }, - { 0x1000789f, 0x04 }, - { 0x100078a0, 0x23 }, - { 0x100078a1, 0x08 }, - { 0x100078a2, 0xd7 }, - { 0x100078a3, 0xd8 }, - { 0x100078a4, 0x23 }, - { 0x100078a5, 0x09 }, - { 0x100078a6, 0x07 }, - { 0x100078a7, 0xd8 }, - { 0x100078a8, 0x83 }, - { 0x100078a9, 0x20 }, - { 0x100078aa, 0xc1 }, - { 0x100078ab, 0x00 }, - { 0x100078ac, 0x13 }, - { 0x100078ad, 0x01 }, - { 0x100078ae, 0x01 }, - { 0x100078af, 0x01 }, - { 0x100078b0, 0x67 }, - { 0x100078b1, 0x80 }, - { 0x100078b2, 0x00 }, - { 0x100078b3, 0x00 }, - { 0x3fc2bfc7, 0x00 }, - { 0x3fc2bfc6, 0x00 }, - { 0x3fc2bfc5, 0x00 }, - { 0x3fc2bfc4, 0x01 }, - { 0x0000d486, 0x43 }, - { 0x1000db00, 0x02 }, - { 0x1000db01, 0x00 }, - { 0x1000db02, 0x11 }, - { 0x1000db03, 0x00 }, - { 0x1000db04, 0x00 }, - { 0x1000db05, 0x82 }, - { 0x1000db06, 0x04 }, - { 0x1000db07, 0xf1 }, - { 0x1000db08, 0x00 }, - { 0x1000db09, 0x00 }, - { 0x1000db0a, 0x40 }, - { 0x0000d540, 0x01 }, -}; - static const struct reg_default rt1320_reg_defaults[] = { + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0x00 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 }, }; static const struct reg_default rt1320_mbq_defaults[] = { + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, }; @@ -3514,6 +328,17 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg) case 0x1000f021: case 0x3fe2e000 ... 0x3fe2e003: case 0x3fc2ab80 ... 0x3fc2abd4: + /* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */ + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02): + /* 0x40880900/0x40880980 */ + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + /* 0x40881500 */ + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): /* 0x41000189/0x4100018a */ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02): @@ -3596,6 +421,7 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) case 0x3fc2bf80 ... 0x3fc2bf83: case 0x3fc2bfc0 ... 0x3fc2bfc7: case 0x3fe2e000 ... 0x3fe2e003: + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0): @@ -3609,6 +435,10 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg) static bool rt1320_mbq_readable_register(struct device *dev, unsigned int reg) { switch (reg) { + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01): case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02): return true; @@ -3664,7 +494,7 @@ static int rt1320_read_prop(struct sdw_slave *slave) prop->lane_control_support = true; /* first we need to allocate memory for set bits in port lists */ - prop->source_ports = BIT(4); + prop->source_ports = BIT(4) | BIT(8) | BIT(10); prop->sink_ports = BIT(1); nval = hweight32(prop->source_ports); @@ -3708,7 +538,8 @@ static int rt1320_read_prop(struct sdw_slave *slave) return 0; } -static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char ps) +static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char func, + unsigned char entity, unsigned char ps) { unsigned int delay = 1000, val; @@ -3717,8 +548,7 @@ static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned /* waiting for Actual PDE becomes to PS0/PS3 */ while (delay) { regmap_read(rt1320->regmap, - SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, - RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val); + SDW_SDCA_CTL(func, entity, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val); if (val == ps) break; @@ -3733,17 +563,88 @@ static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned return 0; } +/* + * The 'patch code' is written to the patch code area. + * The patch code area is used for SDCA register expansion flexibility. + */ +static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320) +{ + struct sdw_slave *slave = rt1320->sdw_slave; + const struct firmware *patch; + const char *filename; + unsigned int addr, val; + const unsigned char *ptr; + int ret, i; + + if (rt1320->version_id <= RT1320_VB) + filename = RT1320_VAB_MCU_PATCH; + else + filename = RT1320_VC_MCU_PATCH; + + /* load the patch code here */ + ret = request_firmware(&patch, filename, &slave->dev); + if (ret) { + dev_err(&slave->dev, "%s: Failed to load %s firmware", __func__, filename); + regmap_write(rt1320->regmap, 0xc598, 0x00); + regmap_write(rt1320->regmap, 0x10007000, 0x67); + regmap_write(rt1320->regmap, 0x10007001, 0x80); + regmap_write(rt1320->regmap, 0x10007002, 0x00); + regmap_write(rt1320->regmap, 0x10007003, 0x00); + } else { + ptr = (const unsigned char *)patch->data; + if ((patch->size % 8) == 0) { + for (i = 0; i < patch->size; i += 8) { + addr = (ptr[i] & 0xff) | (ptr[i + 1] & 0xff) << 8 | + (ptr[i + 2] & 0xff) << 16 | (ptr[i + 3] & 0xff) << 24; + val = (ptr[i + 4] & 0xff) | (ptr[i + 5] & 0xff) << 8 | + (ptr[i + 6] & 0xff) << 16 | (ptr[i + 7] & 0xff) << 24; + + if (addr > 0x10007fff || addr < 0x10007000) { + dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr); + goto _exit_; + } + if (val > 0xff) { + dev_err(&slave->dev, "%s: the value 0x%x is wrong", __func__, val); + goto _exit_; + } + regmap_write(rt1320->regmap, addr, val); + } + } +_exit_: + release_firmware(patch); + } +} + +static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320) +{ + unsigned int i, reg, val, delay; + + for (i = 0; i < ARRAY_SIZE(rt1320_blind_write); i++) { + reg = rt1320_blind_write[i].reg; + val = rt1320_blind_write[i].def; + delay = rt1320_blind_write[i].delay_us; + + if (reg == 0x3fc2bfc7) + rt1320_load_mcu_patch(rt1320); + + regmap_write(rt1320->regmap, reg, val); + if (delay) + usleep_range(delay, delay + 1000); + } +} + static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) { struct sdw_slave *slave = rt1320->sdw_slave; unsigned int i, reg, val, delay, retry, tmp; - regmap_multi_reg_write(rt1320->regmap, rt1320_vc_blind_write, ARRAY_SIZE(rt1320_vc_blind_write)); + for (i = 0; i < ARRAY_SIZE(rt1320_vc_blind_write); i++) { + reg = rt1320_vc_blind_write[i].reg; + val = rt1320_vc_blind_write[i].def; + delay = rt1320_vc_blind_write[i].delay_us; - for (i = 0; i < ARRAY_SIZE(rt1320_vc_patch_code_write); i++) { - reg = rt1320_vc_patch_code_write[i].reg; - val = rt1320_vc_patch_code_write[i].def; - delay = rt1320_vc_patch_code_write[i].delay_us; + if (reg == 0x3fc2bf83) + rt1320_load_mcu_patch(rt1320); if ((reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0)) && (val == 0x00)) { @@ -3762,6 +663,9 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320) regmap_write(rt1320->regmap, reg, val); if (delay) usleep_range(delay, delay + 1000); + + if (reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0)) + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, val); } } @@ -3799,13 +703,10 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave) /* initialization write */ if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION)) { - if (rt1320->version_id < RT1320_VC) { - regmap_multi_reg_write(rt1320->regmap, rt1320_blind_write, ARRAY_SIZE(rt1320_blind_write)); - regmap_multi_reg_write(rt1320->regmap, rt1320_patch_code_write, - ARRAY_SIZE(rt1320_patch_code_write)); - } else if (rt1320->version_id == RT1320_VC) { + if (rt1320->version_id < RT1320_VC) + rt1320_vab_preset(rt1320); + else rt1320_vc_preset(rt1320); - } regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0), @@ -3870,6 +771,34 @@ static int rt1320_update_status(struct sdw_slave *slave, return rt1320_io_init(&slave->dev, slave); } +static int rt1320_pde11_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, + RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps3); + break; + default: + break; + } + + return 0; +} + static int rt1320_pde23_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -3883,13 +812,13 @@ static int rt1320_pde23_event(struct snd_soc_dapm_widget *w, regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0); - rt1320_pde_transition_delay(rt1320, ps0); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps0); break; case SND_SOC_DAPM_PRE_PMD: regmap_write(rt1320->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3); - rt1320_pde_transition_delay(rt1320, ps3); + rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps3); break; default: break; @@ -3908,6 +837,13 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, unsigned int gain_l_val, gain_r_val; unsigned int lvalue, rvalue; const unsigned int interval_offset = 0xc0; + unsigned int changed = 0, reg_base; + struct rt_sdca_dmic_kctrl_priv *p; + unsigned int regvalue[4], gain_val[4], i; + int err; + + if (strstr(ucontrol->id.name, "FU Capture Volume")) + goto _dmic_vol_; regmap_read(rt1320->mbq_regmap, mc->reg, &lvalue); regmap_read(rt1320->mbq_regmap, mc->rreg, &rvalue); @@ -3933,7 +869,48 @@ static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol, regmap_write(rt1320->mbq_regmap, mc->reg, gain_l_val); /* Rch */ regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val); + goto _done_; + +_dmic_vol_: + p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i, ®value[i]); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i - 2, ®value[i]); + } + + gain_val[i] = ucontrol->value.integer.value[i]; + if (gain_val[i] > p->max) + gain_val[i] = p->max; + + gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset); + gain_val[i] &= 0xffff; + if (regvalue[i] != gain_val[i]) + changed = 1; + } + + if (!changed) + return 0; + for (i = 0; i < p->count; i++) { + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + err = regmap_write(rt1320->mbq_regmap, reg_base + i, gain_val[i]); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + err = regmap_write(rt1320->mbq_regmap, reg_base + i - 2, gain_val[i]); + } + + if (err < 0) + dev_err(&rt1320->sdw_slave->dev, "0x%08x can't be set\n", reg_base + i); + } + +_done_: return 1; } @@ -3946,6 +923,11 @@ static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0; const unsigned int interval_offset = 0xc0; + unsigned int reg_base, regvalue, ctl, i; + struct rt_sdca_dmic_kctrl_priv *p; + + if (strstr(ucontrol->id.name, "FU Capture Volume")) + goto _dmic_vol_; regmap_read(rt1320->mbq_regmap, mc->reg, &read_l); regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r); @@ -3959,6 +941,121 @@ static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = ctl_l; ucontrol->value.integer.value[1] = ctl_r; + goto _done_; + +_dmic_vol_: + p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + if (i < 2) { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i, ®value); + } else { + reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01); + regmap_read(rt1320->mbq_regmap, reg_base + i - 2, ®value); + } + + ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset); + ucontrol->value.integer.value[i] = ctl; + } +_done_: + return 0; +} + +static int rt1320_set_fu_capture_ctl(struct rt1320_sdw_priv *rt1320) +{ + int err, i; + unsigned int ch_mute; + + for (i = 0; i < ARRAY_SIZE(rt1320->fu_mixer_mute); i++) { + ch_mute = (rt1320->fu_dapm_mute || rt1320->fu_mixer_mute[i]) ? 0x01 : 0x00; + + if (i < 2) + err = regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, + RT1320_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); + else + err = regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, + RT1320_SDCA_CTL_FU_MUTE, CH_01) + i - 2, ch_mute); + if (err < 0) + return err; + } + + return 0; +} + +static int rt1320_dmic_fu_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int i; + + for (i = 0; i < p->count; i++) + ucontrol->value.integer.value[i] = !rt1320->fu_mixer_mute[i]; + + return 0; +} + +static int rt1320_dmic_fu_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + int err, changed = 0, i; + + for (i = 0; i < p->count; i++) { + if (rt1320->fu_mixer_mute[i] != !ucontrol->value.integer.value[i]) + changed = 1; + rt1320->fu_mixer_mute[i] = !ucontrol->value.integer.value[i]; + } + + err = rt1320_set_fu_capture_ctl(rt1320); + if (err < 0) + return err; + + return changed; +} + +static int rt1320_dmic_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt_sdca_dmic_kctrl_priv *p = + (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +static int rt1320_dmic_fu_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt1320->fu_dapm_mute = false; + rt1320_set_fu_capture_ctl(rt1320); + break; + case SND_SOC_DAPM_PRE_PMD: + rt1320->fu_dapm_mute = true; + rt1320_set_fu_capture_ctl(rt1320); + break; + } return 0; } @@ -3979,6 +1076,7 @@ static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum, rt1320_rx_data_ch_select); static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static const struct snd_kcontrol_new rt1320_snd_controls[] = { SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume", @@ -3986,6 +1084,13 @@ static const struct snd_kcontrol_new rt1320_snd_controls[] = { SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0, 0x57, 0, rt1320_set_gain_get, rt1320_set_gain_put, out_vol_tlv), SOC_ENUM("RX Channel Select", rt1320_rx_data_ch_enum), + + RT_SDCA_FU_CTRL("FU Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), + 1, 1, 4, rt1320_dmic_fu_info, rt1320_dmic_fu_capture_get, rt1320_dmic_fu_capture_put), + RT_SDCA_EXT_TLV("FU Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01), + rt1320_set_gain_get, rt1320_set_gain_put, 4, 0x3f, in_vol_tlv, rt1320_dmic_fu_info), }; static const struct snd_kcontrol_new rt1320_spk_l_dac = @@ -4001,12 +1106,19 @@ static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = { /* Audio Interface */ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP8-10TX", "DP8-10 Capture", 0, SND_SOC_NOPM, 0, 0), /* Digital Interface */ SND_SOC_DAPM_PGA("FU21", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0, rt1320_pde23_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, + rt1320_pde11_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC("FU 113", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("FU 14", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA_E("FU", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1320_dmic_fu_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), /* Output */ SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt1320_spk_l_dac), @@ -4017,6 +1129,8 @@ static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = { /* Input */ SND_SOC_DAPM_PGA("AEC Data", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SIGGEN("AEC Gen"), + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), }; static const struct snd_soc_dapm_route rt1320_dapm_routes[] = { @@ -4029,6 +1143,13 @@ static const struct snd_soc_dapm_route rt1320_dapm_routes[] = { { "AEC Data", NULL, "AEC Gen" }, { "DP4TX", NULL, "AEC Data" }, + + {"DP8-10TX", NULL, "FU"}, + {"FU", NULL, "PDE 11"}, + {"FU", NULL, "FU 113"}, + {"FU", NULL, "FU 14"}, + {"FU 113", NULL, "DMIC1"}, + {"FU 14", NULL, "DMIC2"}, }; static int rt1320_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, @@ -4052,6 +1173,7 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, snd_soc_component_get_drvdata(component); struct sdw_stream_config stream_config; struct sdw_port_config port_config; + struct sdw_port_config dmic_port_config[2]; struct sdw_stream_runtime *sdw_stream; int retval; unsigned int sampling_rate; @@ -4076,12 +1198,23 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, } else { if (dai->id == RT1320_AIF1) port_config.num = 4; - else + else if (dai->id == RT1320_AIF2) { + dmic_port_config[0].ch_mask = BIT(0) | BIT(1); + dmic_port_config[0].num = 8; + dmic_port_config[1].ch_mask = BIT(0) | BIT(1); + dmic_port_config[1].num = 10; + } else return -EINVAL; } - retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, + if (dai->id == RT1320_AIF1) + retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, &port_config, 1, sdw_stream); + else if (dai->id == RT1320_AIF2) + retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config, + dmic_port_config, 2, sdw_stream); + else + return -EINVAL; if (retval) { dev_err(dai->dev, "%s: Unable to configure port\n", __func__); return retval; @@ -4114,9 +1247,18 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream, } /* set sampling frequency */ - regmap_write(rt1320->regmap, - SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), - sampling_rate); + if (dai->id == RT1320_AIF1) + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + else { + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + regmap_write(rt1320->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + } return 0; } @@ -4207,6 +1349,19 @@ static struct snd_soc_dai_driver rt1320_sdw_dai[] = { }, .ops = &rt1320_aif_dai_ops, }, + /* DMIC: DP8 2ch + DP10 2ch */ + { + .name = "rt1320-aif2", + .id = RT1320_AIF2, + .capture = { + .stream_name = "DP8-10 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = RT1320_STEREO_RATES, + .formats = RT1320_FORMATS, + }, + .ops = &rt1320_aif_dai_ops, + }, }; static int rt1320_sdw_init(struct device *dev, struct regmap *regmap, @@ -4234,6 +1389,9 @@ static int rt1320_sdw_init(struct device *dev, struct regmap *regmap, rt1320->hw_init = false; rt1320->first_hw_init = false; rt1320->version_id = -1; + rt1320->fu_dapm_mute = true; + rt1320->fu_mixer_mute[0] = rt1320->fu_mixer_mute[1] = + rt1320->fu_mixer_mute[2] = rt1320->fu_mixer_mute[3] = true; ret = devm_snd_soc_register_component(dev, &soc_component_sdw_rt1320, diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h index 1fbc1fcd71cfd8..23b321aee6a912 100644 --- a/sound/soc/codecs/rt1320-sdw.h +++ b/sound/soc/codecs/rt1320-sdw.h @@ -26,6 +26,7 @@ /* RT1320 SDCA Control - function number */ #define FUNC_NUM_AMP 0x04 +#define FUNC_NUM_MIC 0x02 /* RT1320 SDCA entity */ #define RT1320_SDCA_ENT0 0x00 @@ -69,6 +70,7 @@ enum { RT1320_AIF1, + RT1320_AIF2, }; /* @@ -82,6 +84,8 @@ enum rt1320_version_id { }; #define RT1320_VER_B_ID 0x07392238 +#define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin" +#define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin" struct rt1320_sdw_priv { struct snd_soc_component *component; @@ -92,6 +96,8 @@ struct rt1320_sdw_priv { bool hw_init; bool first_hw_init; int version_id; + bool fu_dapm_mute; + bool fu_mixer_mute[4]; }; #endif /* __RT1320_SDW_H__ */ diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 90d5aaddbd5b94..b584a3f854b853 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -507,3 +507,4 @@ module_sdw_driver(rt712_sdca_sdw_driver); MODULE_DESCRIPTION("ASoC RT712 SDCA SDW driver"); MODULE_AUTHOR("Shuming Fan "); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_SDCA"); diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index e210c574bb74a1..78dbf9eed494bb 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1652,6 +1653,17 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, if (ret < 0) return ret; + /* only add the dmic component if a SMART_MIC function is exposed in ACPI */ + if (sdca_device_quirk_match(slave, SDCA_QUIRKS_RT712_VB)) { + ret = devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt712_dmic, + rt712_sdca_dmic_dai, + ARRAY_SIZE(rt712_sdca_dmic_dai)); + if (ret < 0) + return ret; + rt712->dmic_function_found = true; + } + /* set autosuspend parameters */ pm_runtime_set_autosuspend_delay(dev, 3000); pm_runtime_use_autosuspend(dev); @@ -1799,7 +1811,6 @@ static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712) int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) { struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); - int ret = 0; unsigned int val; struct sdw_slave_prop *prop = &slave->prop; @@ -1829,15 +1840,22 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) rt712->version_id = (val & 0x0f00) >> 8; dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id); - if (rt712->version_id == RT712_VA) + if (rt712->version_id == RT712_VA) { + if (rt712->dmic_function_found) { + dev_err(&slave->dev, "%s RT712 VA detected but SMART_MIC function exposed in ACPI\n", + __func__); + goto suspend; + } + rt712_sdca_va_io_init(rt712); - else { - /* multilanes and DMIC are supported by rt712vb */ - ret = devm_snd_soc_register_component(dev, - &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai)); - if (ret < 0) - return ret; + } else { + if (!rt712->dmic_function_found) { + dev_err(&slave->dev, "%s RT712 VB detected but no SMART_MIC function exposed in ACPI\n", + __func__); + goto suspend; + } + /* multilanes and DMIC are supported by rt712vb */ prop->lane_control_support = true; rt712_sdca_vb_io_init(rt712); } @@ -1862,10 +1880,12 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) /* Mark Slave initialization complete */ rt712->hw_init = true; + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + +suspend: pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); - dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); return 0; } diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h index 2169f2f726b9fb..a08491496d9013 100644 --- a/sound/soc/codecs/rt712-sdca.h +++ b/sound/soc/codecs/rt712-sdca.h @@ -36,6 +36,7 @@ struct rt712_sdca_priv { unsigned int scp_sdca_stat2; unsigned int hw_id; unsigned int version_id; + bool dmic_function_found; bool fu0f_dapm_mute; bool fu0f_mixer_l_mute; bool fu0f_mixer_r_mute; diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c new file mode 100644 index 00000000000000..c71453da088a01 --- /dev/null +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -0,0 +1,546 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt721-sdca-sdw.c -- rt721 SDCA ALSA SoC audio driver +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include + +#include "rt721-sdca.h" +#include "rt721-sdca-sdw.h" +#include "rt-sdw-common.h" + +static bool rt721_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f01 ... 0x2f0a: + case 0x2f35: + case 0x2f50: + case 0x2f51: + case 0x2f58 ... 0x2f5d: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV, + RT721_SDCA_CTL_XUV, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49, + RT721_SDCA_CTL_SELECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49, + RT721_SDCA_CTL_DETECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01, + RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, + RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt721_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f01: + case 0x2f51: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49, + RT721_SDCA_CTL_DETECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XUV, + RT721_SDCA_CTL_XUV, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01, + RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, + RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x0900007: + case 0x0a00005: + case 0x0c00005: + case 0x0d00014: + case 0x0310100: + case 0x2000001: + case 0x2000002: + case 0x2000003: + case 0x2000013: + case 0x200003c: + case 0x2000046: + case 0x5810000: + case 0x5810036: + case 0x5810037: + case 0x5810038: + case 0x5810039: + case 0x5b10018: + case 0x5b10019: + case 0x5f00045: + case 0x5f00048: + case 0x6100000: + case 0x6100005: + case 0x6100006: + case 0x610000d: + case 0x6100010: + case 0x6100011: + case 0x6100013: + case 0x6100015: + case 0x6100017: + case 0x6100025: + case 0x6100029: + case 0x610002c ... 0x610002f: + case 0x6100053 ... 0x6100055: + case 0x6100057: + case 0x610005a: + case 0x610005b: + case 0x610006a: + case 0x610006d: + case 0x6100092: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME, + CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME, + CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME, + CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME, + CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, + RT721_SDCA_CTL_FU_CH_GAIN, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, + RT721_SDCA_CTL_FU_CH_GAIN, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_03): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_04): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_R): + return true; + default: + return false; + } +} + +static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x0310100: + case 0x0a00005: + case 0x0c00005: + case 0x0d00014: + case 0x2000000: + case 0x200000d: + case 0x2000019: + case 0x2000020: + case 0x2000030: + case 0x2000046: + case 0x2000067: + case 0x2000084: + case 0x2000086: + case 0x5810000: + case 0x5810036: + case 0x5810037: + case 0x5810038: + case 0x5810039: + case 0x5b10018: + case 0x5b10019: + return true; + default: + return false; + } +} + +static const struct regmap_config rt721_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt721_sdca_readable_register, + .volatile_reg = rt721_sdca_volatile_register, + .max_register = 0x44ffffff, + .reg_defaults = rt721_sdca_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt721_sdca_reg_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct regmap_config rt721_sdca_mbq_regmap = { + .name = "sdw-mbq", + .reg_bits = 32, + .val_bits = 16, + .readable_reg = rt721_sdca_mbq_readable_register, + .volatile_reg = rt721_sdca_mbq_volatile_register, + .max_register = 0x41000312, + .reg_defaults = rt721_sdca_mbq_defaults, + .num_reg_defaults = ARRAY_SIZE(rt721_sdca_mbq_defaults), + .cache_type = REGCACHE_MAPLE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt721_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev); + + if (status == SDW_SLAVE_UNATTACHED) + rt721->hw_init = false; + + if (status == SDW_SLAVE_ATTACHED) { + if (rt721->hs_jack) { + /* + * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then + * if the device attached again, we will need to set the setting back. + * It could avoid losing the jack detection interrupt. + * This also could sync with the cache value as the rt721_sdca_jack_init set. + */ + sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + } + } + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt721->hw_init || status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt721_sdca_io_init(&slave->dev, slave); +} + +static int rt721_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + sdw_slave_read_prop(slave); + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + + prop->paging_support = true; + + /* + * port = 1 for headphone playback + * port = 2 for headset-mic capture + * port = 3 for speaker playback + * port = 6 for digital-mic capture + */ + prop->source_ports = BIT(6) | BIT(2); /* BITMAP: 01000100 */ + prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 1380; + + /* wake-up event */ + prop->wake_capable = 1; + + /* Three data lanes are supported by rt721-sdca codec */ + prop->lane_control_support = true; + + return 0; +} + +static int rt721_sdca_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev); + int ret, stat; + int count = 0, retry = 3; + unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0; + + if (cancel_delayed_work_sync(&rt721->jack_detect_work)) { + dev_warn(&slave->dev, "%s the pending delayed_work was cancelled", __func__); + /* avoid the HID owner doesn't change to device */ + if (rt721->scp_sdca_stat2) + scp_sdca_stat2 = rt721->scp_sdca_stat2; + } + + /* + * The critical section below intentionally protects a rather large piece of code. + * We don't want to allow the system suspend to disable an interrupt while we are + * processing it, which could be problematic given the quirky SoundWire interrupt + * scheme. We do want however to prevent new workqueues from being scheduled if + * the disable_irq flag was set during system suspend. + */ + mutex_lock(&rt721->disable_irq_lock); + + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + + rt721->scp_sdca_stat1 = ret; + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + + rt721->scp_sdca_stat2 = ret; + if (scp_sdca_stat2) + rt721->scp_sdca_stat2 |= scp_sdca_stat2; + do { + /* clear flag */ + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) { + ret = sdw_update_no_pm(rt721->slave, SDW_SCP_SDCA_INT1, + SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0); + if (ret < 0) + goto io_error; + } + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) { + ret = sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INT2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + if (ret < 0) + goto io_error; + } + + /* check if flag clear or not */ + ret = sdw_read_no_pm(rt721->slave, SDW_DP0_INT); + if (ret < 0) + goto io_error; + sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; + + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0; + + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8; + + stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade; + + count++; + } while (stat != 0 && count < retry); + + if (stat) + dev_warn(&slave->dev, + "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, + rt721->scp_sdca_stat1, rt721->scp_sdca_stat2); + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT1); + ret = sdw_read_no_pm(rt721->slave, SDW_SCP_SDCA_INT2); + + if (status->sdca_cascade && !rt721->disable_irq) + mod_delayed_work(system_power_efficient_wq, + &rt721->jack_detect_work, msecs_to_jiffies(280)); + + mutex_unlock(&rt721->disable_irq_lock); + + return 0; + +io_error: + mutex_unlock(&rt721->disable_irq_lock); + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static const struct sdw_slave_ops rt721_sdca_slave_ops = { + .read_prop = rt721_sdca_read_prop, + .interrupt_callback = rt721_sdca_interrupt_callback, + .update_status = rt721_sdca_update_status, +}; + +static int rt721_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap, *mbq_regmap; + + /* Regmap Initialization */ + mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt721_sdca_mbq_regmap); + if (IS_ERR(mbq_regmap)) + return PTR_ERR(mbq_regmap); + + regmap = devm_regmap_init_sdw(slave, &rt721_sdca_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt721_sdca_init(&slave->dev, regmap, mbq_regmap, slave); +} + +static int rt721_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(&slave->dev); + + if (rt721->hw_init) { + cancel_delayed_work_sync(&rt721->jack_detect_work); + cancel_delayed_work_sync(&rt721->jack_btn_check_work); + } + + if (rt721->first_hw_init) + pm_runtime_disable(&slave->dev); + + mutex_destroy(&rt721->calibrate_mutex); + mutex_destroy(&rt721->disable_irq_lock); + + return 0; +} + +static const struct sdw_device_id rt721_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x721, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt721_sdca_id); + +static int __maybe_unused rt721_sdca_dev_suspend(struct device *dev) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); + + if (!rt721->hw_init) + return 0; + + cancel_delayed_work_sync(&rt721->jack_detect_work); + cancel_delayed_work_sync(&rt721->jack_btn_check_work); + + regcache_cache_only(rt721->regmap, true); + regcache_cache_only(rt721->mbq_regmap, true); + + return 0; +} + +static int __maybe_unused rt721_sdca_dev_system_suspend(struct device *dev) +{ + struct rt721_sdca_priv *rt721_sdca = dev_get_drvdata(dev); + struct sdw_slave *slave = dev_to_sdw_dev(dev); + int ret1, ret2; + + if (!rt721_sdca->hw_init) + return 0; + + /* + * prevent new interrupts from being handled after the + * deferred work completes and before the parent disables + * interrupts on the link + */ + mutex_lock(&rt721_sdca->disable_irq_lock); + rt721_sdca->disable_irq = true; + ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); + ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8, 0); + mutex_unlock(&rt721_sdca->disable_irq_lock); + + if (ret1 < 0 || ret2 < 0) { + /* log but don't prevent suspend from happening */ + dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__); + } + + return rt721_sdca_dev_suspend(dev); +} + +#define RT721_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt721_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt721->first_hw_init) + return 0; + + if (!slave->unattach_request) { + mutex_lock(&rt721->disable_irq_lock); + if (rt721->disable_irq == true) { + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); + rt721->disable_irq = false; + } + mutex_unlock(&rt721->disable_irq_lock); + goto regmap_sync; + } + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT721_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + sdw_show_ping_status(slave->bus, true); + + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt721->regmap, false); + regcache_sync(rt721->regmap); + regcache_cache_only(rt721->mbq_regmap, false); + regcache_sync(rt721->mbq_regmap); + return 0; +} + +static const struct dev_pm_ops rt721_sdca_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt721_sdca_dev_system_suspend, rt721_sdca_dev_resume) + SET_RUNTIME_PM_OPS(rt721_sdca_dev_suspend, rt721_sdca_dev_resume, NULL) +}; + +static struct sdw_driver rt721_sdca_sdw_driver = { + .driver = { + .name = "rt721-sdca", + .owner = THIS_MODULE, + .pm = &rt721_sdca_pm, + }, + .probe = rt721_sdca_sdw_probe, + .remove = rt721_sdca_sdw_remove, + .ops = &rt721_sdca_slave_ops, + .id_table = rt721_sdca_id, +}; +module_sdw_driver(rt721_sdca_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT721 SDCA SDW driver"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt721-sdca-sdw.h b/sound/soc/codecs/rt721-sdca-sdw.h new file mode 100644 index 00000000000000..214b31b825833e --- /dev/null +++ b/sound/soc/codecs/rt721-sdca-sdw.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt721-sdca-sdw.h -- RT721 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2024 Realtek Semiconductor Corp. + */ + +#ifndef __RT721_SDW_H__ +#define __RT721_SDW_H__ + +#include +#include + +static const struct reg_default rt721_sdca_reg_defaults[] = { + { 0x202d, 0x00 }, + { 0x2f01, 0x00 }, + { 0x2f02, 0x09 }, + { 0x2f03, 0x08 }, + { 0x2f04, 0x00 }, + { 0x2f05, 0x0e }, + { 0x2f06, 0x01 }, + { 0x2f09, 0x00 }, + { 0x2f0a, 0x00 }, + { 0x2f35, 0x00 }, + { 0x2f50, 0xf0 }, + { 0x2f58, 0x07 }, + { 0x2f59, 0x07 }, + { 0x2f5a, 0x00 }, + { 0x2f5b, 0x07 }, + { 0x2f5c, 0x27 }, + { 0x2f5d, 0x07 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_03), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, +}; + +static const struct reg_default rt721_sdca_mbq_defaults[] = { + { 0x0900007, 0xc004 }, + { 0x2000001, 0x0000 }, + { 0x2000002, 0x0000 }, + { 0x2000003, 0x0000 }, + { 0x2000013, 0x8001 }, + { 0x200003c, 0x0000 }, + { 0x2000046, 0x3400 }, + { 0x5f00044, 0x6040 }, + { 0x5f00045, 0x3333 }, + { 0x5f00048, 0x0000 }, + { 0x6100005, 0x0005 }, + { 0x6100006, 0x0000 }, + { 0x610000d, 0x0051 }, + { 0x6100010, 0x0180 }, + { 0x6100011, 0x0000 }, + { 0x6100013, 0x0000 }, + { 0x6100015, 0x0000 }, + { 0x6100017, 0x8049 }, + { 0x6100025, 0x1000 }, + { 0x6100029, 0x0809 }, + { 0x610002c, 0x2828 }, + { 0x610002d, 0x2929 }, + { 0x610002e, 0x3529 }, + { 0x610002f, 0x2901 }, + { 0x6100053, 0x2630 }, + { 0x6100054, 0x2a2a }, + { 0x6100055, 0x152f }, + { 0x6100057, 0x2200 }, + { 0x610005a, 0x2a4b }, + { 0x610005b, 0x2a00 }, + { 0x610006a, 0x0102 }, + { 0x610006d, 0x0102 }, + { 0x6100092, 0x4f61 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME, + CH_L), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, RT721_SDCA_CTL_FU_VOLUME, + CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME, + CH_L), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, RT721_SDCA_CTL_FU_VOLUME, + CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, RT721_SDCA_CTL_FU_CH_GAIN, + CH_L), 0xfe00 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, RT721_SDCA_CTL_FU_CH_GAIN, + CH_R), 0xfe00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_01), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_02), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_03), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, RT721_SDCA_CTL_FU_CH_GAIN, CH_04), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_03), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, RT721_SDCA_CTL_FU_VOLUME, + CH_04), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_L), + 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, RT721_SDCA_CTL_FU_VOLUME, CH_R), + 0x0000 }, +}; + +#endif /* __RT721_SDW_H__ */ diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c new file mode 100644 index 00000000000000..1c9f32e405cf95 --- /dev/null +++ b/sound/soc/codecs/rt721-sdca.c @@ -0,0 +1,1545 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt721-sdca.c -- rt721 SDCA ALSA SoC audio driver +// +// Copyright(c) 2024 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt721-sdca.h" +#include "rt-sdw-common.h" + +static void rt721_sdca_jack_detect_handler(struct work_struct *work) +{ + struct rt721_sdca_priv *rt721 = + container_of(work, struct rt721_sdca_priv, jack_detect_work.work); + int btn_type = 0; + + if (!rt721->hs_jack) + return; + + if (!rt721->component->card || !rt721->component->card->instantiated) + return; + + /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */ + if (rt721->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) { + rt721->jack_type = rt_sdca_headset_detect(rt721->regmap, + RT721_SDCA_ENT_GE49); + if (rt721->jack_type < 0) + return; + } + + /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */ + if (rt721->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8) + btn_type = rt_sdca_button_detect(rt721->regmap, + RT721_SDCA_ENT_HID01, RT721_BUF_ADDR_HID1, + RT721_SDCA_HID_ID); + + if (rt721->jack_type == 0) + btn_type = 0; + + dev_dbg(&rt721->slave->dev, + "in %s, jack_type=%d\n", __func__, rt721->jack_type); + dev_dbg(&rt721->slave->dev, + "in %s, btn_type=0x%x\n", __func__, btn_type); + dev_dbg(&rt721->slave->dev, + "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, + rt721->scp_sdca_stat1, rt721->scp_sdca_stat2); + + snd_soc_jack_report(rt721->hs_jack, rt721->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt721->hs_jack, rt721->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt721->jack_btn_check_work, msecs_to_jiffies(200)); + } +} + +static void rt721_sdca_btn_check_handler(struct work_struct *work) +{ + struct rt721_sdca_priv *rt721 = + container_of(work, struct rt721_sdca_priv, jack_btn_check_work.work); + int btn_type = 0, ret, idx; + unsigned int det_mode, offset, val; + unsigned char buf[3]; + + ret = regmap_read(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_GE49, + RT721_SDCA_CTL_DETECTED_MODE, 0), &det_mode); + if (ret < 0) + goto io_error; + + /* pin attached */ + if (det_mode) { + /* read UMP message offset */ + ret = regmap_read(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT721_SDCA_ENT_HID01, + RT721_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset); + if (ret < 0) + goto io_error; + + for (idx = 0; idx < sizeof(buf); idx++) { + ret = regmap_read(rt721->regmap, + RT721_BUF_ADDR_HID1 + offset + idx, &val); + if (ret < 0) + goto io_error; + buf[idx] = val & 0xff; + } + /* Report ID for HID1 */ + if (buf[0] == 0x11) + btn_type = rt_sdca_btn_type(&buf[1]); + } else + rt721->jack_type = 0; + + dev_dbg(&rt721->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type); + snd_soc_jack_report(rt721->hs_jack, rt721->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt721->hs_jack, rt721->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt721->jack_btn_check_work, msecs_to_jiffies(200)); + } + + return; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); +} + +static void rt721_sdca_dmic_preset(struct rt721_sdca_priv *rt721) +{ + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_VREF1_HV_CTRL1, 0xe000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8007); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL9, 0x2a2a); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL10, 0x2a00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL6, 0x2a2a); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL5, 0x2626); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL8, 0x1e00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL7, 0x1515); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_CH_FLOAT_CTL3, 0x0304); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_CH_FLOAT_CTL4, 0x0304); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_CTL1, 0x0000); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x01); + regmap_write(rt721->mbq_regmap, 0x5910009, 0x2e01); + rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL, + RT721_RC_CALIB_CTRL0, 0x0b00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL, + RT721_RC_CALIB_CTRL0, 0x0b40); + regmap_write(rt721->regmap, 0x2f5c, 0x25); +} + +static void rt721_sdca_amp_preset(struct rt721_sdca_priv *rt721) +{ + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_VREF1_HV_CTRL1, 0xe000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8007); + regmap_write(rt721->mbq_regmap, 0x5810000, 0x6420); + regmap_write(rt721->mbq_regmap, 0x5810000, 0x6421); + regmap_write(rt721->mbq_regmap, 0x5810000, 0xe421); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_CH_FLOAT_CTL6, 0x5561); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_REG, + RT721_GPIO_PAD_CTRL5, 0x8003); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23, + RT721_SDCA_CTL_VENDOR_DEF, 0), 0x04); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, + RT721_SDCA_CTL_FU_MUTE, CH_01), 0x00); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55, + RT721_SDCA_CTL_FU_MUTE, CH_02), 0x00); +} + +static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721) +{ + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_VREF1_HV_CTRL1, 0xe000); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_MISC_POWER_CTL31, 0x8007); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_GE_REL_CTRL1, 0x8011); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_UMP_HID_CTRL3, 0xcf00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_UMP_HID_CTRL4, 0x000f); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_UMP_HID_CTRL1, 0x1100); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_UMP_HID_CTRL5, 0x0c12); + rt_sdca_index_write(rt721->mbq_regmap, RT721_JD_CTRL, + RT721_JD_1PIN_GAT_CTRL2, 0xc002); + rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL, + RT721_RC_CALIB_CTRL0, 0x0b00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_RC_CALIB_CTRL, + RT721_RC_CALIB_CTRL0, 0x0b40); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON14, 0x3333); + regmap_write(rt721->mbq_regmap, 0x5810035, 0x0036); + regmap_write(rt721->mbq_regmap, 0x5810030, 0xee00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL, + RT721_HP_AMP_2CH_CAL1, 0x0140); + regmap_write(rt721->mbq_regmap, 0x5810000, 0x0021); + regmap_write(rt721->mbq_regmap, 0x5810000, 0x8021); + rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL, + RT721_HP_AMP_2CH_CAL18, 0x5522); + regmap_write(rt721->mbq_regmap, 0x5b10007, 0x2000); + regmap_write(rt721->mbq_regmap, 0x5B10017, 0x1b0f); + rt_sdca_index_write(rt721->mbq_regmap, RT721_CBJ_CTRL, + RT721_CBJ_A0_GAT_CTRL1, 0x2a02); + rt_sdca_index_write(rt721->mbq_regmap, RT721_CAP_PORT_CTRL, + RT721_HP_AMP_2CH_CAL4, 0xa105); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON14, 0x3b33); + regmap_write(rt721->mbq_regmap, 0x310400, 0x3023); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON14, 0x3f33); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON13, 0x6048); + regmap_write(rt721->mbq_regmap, 0x310401, 0x3000); + regmap_write(rt721->mbq_regmap, 0x310402, 0x1b00); + regmap_write(rt721->mbq_regmap, 0x310300, 0x000f); + regmap_write(rt721->mbq_regmap, 0x310301, 0x3000); + regmap_write(rt721->mbq_regmap, 0x310302, 0x1b00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_VENDOR_ANA_CTL, + RT721_UAJ_TOP_TCON17, 0x0008); + rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL, + RT721_DAC_2CH_CTRL3, 0x55ff); + rt_sdca_index_write(rt721->mbq_regmap, RT721_DAC_CTRL, + RT721_DAC_2CH_CTRL4, 0xcc00); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_MBIAS_LV_CTRL2, 0x6677); + rt_sdca_index_write(rt721->mbq_regmap, RT721_ANA_POW_PART, + RT721_VREF2_LV_CTRL1, 0x7600); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL2, 0x1234); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL3, 0x3512); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL1, 0x4040); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_ENT_FLOAT_CTL4, 0x1201); + regmap_write(rt721->regmap, 0x2f58, 0x07); +} + +static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721) +{ + mutex_lock(&rt721->calibrate_mutex); + if (rt721->hs_jack) { + sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + dev_dbg(&rt721->slave->dev, "in %s enable\n", __func__); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_UAJ_CTL, 0x036E); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XU03, + RT721_SDCA_CTL_SELECTED_MODE, 0), 0); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_XU0D, + RT721_SDCA_CTL_SELECTED_MODE, 0), 0); + rt_sdca_index_write(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_XU_REL_CTRL, 0x0000); + rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_GE_REL_CTRL1, 0x4000, 0x4000); + } + mutex_unlock(&rt721->calibrate_mutex); +} + +static int rt721_sdca_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + int ret; + + rt721->hs_jack = hs_jack; + + ret = pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret != -EACCES) { + dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); + return ret; + } + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); + return 0; + } + + rt721_sdca_jack_init(rt721); + + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + + return 0; +} + +/* For SDCA control DAC/ADC Gain */ +static int rt721_sdca_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned int read_l, read_r, gain_l_val, gain_r_val; + unsigned int adc_vol_flag = 0, changed = 0; + unsigned int lvalue, rvalue; + const unsigned int interval_offset = 0xc0; + const unsigned int tendA = 0x200; + const unsigned int tendB = 0xa00; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume") || + strstr(ucontrol->id.name, "FU0F Capture Volume")) + adc_vol_flag = 1; + + regmap_read(rt721->mbq_regmap, mc->reg, &lvalue); + regmap_read(rt721->mbq_regmap, mc->rreg, &rvalue); + + /* L Channel */ + gain_l_val = ucontrol->value.integer.value[0]; + if (gain_l_val > mc->max) + gain_l_val = mc->max; + + if (mc->shift == 8) { + /* boost gain */ + gain_l_val = gain_l_val * tendB; + } else if (mc->shift == 1) { + /* FU33 boost gain */ + if (gain_l_val == 0) + gain_l_val = 0x8000; + else + gain_l_val = (gain_l_val - 1) * tendA; + } else { + /* ADC/DAC gain */ + if (adc_vol_flag) + gain_l_val = 0x1e00 - ((mc->max - gain_l_val) * interval_offset); + else + gain_l_val = 0 - ((mc->max - gain_l_val) * interval_offset); + gain_l_val &= 0xffff; + } + + /* R Channel */ + gain_r_val = ucontrol->value.integer.value[1]; + if (gain_r_val > mc->max) + gain_r_val = mc->max; + + if (mc->shift == 8) { + /* boost gain */ + gain_r_val = gain_r_val * tendB; + } else if (mc->shift == 1) { + /* FU33 boost gain */ + if (gain_r_val == 0) + gain_r_val = 0x8000; + else + gain_r_val = (gain_r_val - 1) * tendA; + } else { + /* ADC/DAC gain */ + if (adc_vol_flag) + gain_r_val = 0x1e00 - ((mc->max - gain_r_val) * interval_offset); + else + gain_r_val = 0 - ((mc->max - gain_r_val) * interval_offset); + gain_r_val &= 0xffff; + } + + if (lvalue != gain_l_val || rvalue != gain_r_val) + changed = 1; + else + return 0; + + /* Lch*/ + regmap_write(rt721->mbq_regmap, mc->reg, gain_l_val); + + /* Rch */ + regmap_write(rt721->mbq_regmap, mc->rreg, gain_r_val); + + regmap_read(rt721->mbq_regmap, mc->reg, &read_l); + regmap_read(rt721->mbq_regmap, mc->rreg, &read_r); + if (read_r == gain_r_val && read_l == gain_l_val) + return changed; + + return -EIO; +} + +static int rt721_sdca_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0; + unsigned int adc_vol_flag = 0; + const unsigned int interval_offset = 0xc0; + const unsigned int tendB = 0xa00; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume") || + strstr(ucontrol->id.name, "FU0F Capture Volume")) + adc_vol_flag = 1; + + regmap_read(rt721->mbq_regmap, mc->reg, &read_l); + regmap_read(rt721->mbq_regmap, mc->rreg, &read_r); + + if (mc->shift == 8) /* boost gain */ + ctl_l = read_l / tendB; + else { + if (adc_vol_flag) + ctl_l = mc->max - (((0x1e00 - read_l) & 0xffff) / interval_offset); + else + ctl_l = mc->max - (((0 - read_l) & 0xffff) / interval_offset); + } + + if (read_l != read_r) { + if (mc->shift == 8) /* boost gain */ + ctl_r = read_r / tendB; + else { /* ADC/DAC gain */ + if (adc_vol_flag) + ctl_r = mc->max - (((0x1e00 - read_r) & 0xffff) / interval_offset); + else + ctl_r = mc->max - (((0 - read_r) & 0xffff) / interval_offset); + } + } else { + ctl_r = ctl_l; + } + + ucontrol->value.integer.value[0] = ctl_l; + ucontrol->value.integer.value[1] = ctl_r; + + return 0; +} + +static int rt721_sdca_set_fu1e_capture_ctl(struct rt721_sdca_priv *rt721) +{ + int err, i; + unsigned int ch_mute; + + for (i = 0; i < ARRAY_SIZE(rt721->fu1e_mixer_mute); i++) { + ch_mute = rt721->fu1e_dapm_mute || rt721->fu1e_mixer_mute[i]; + err = regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); + if (err < 0) + return err; + } + + return 0; +} + +static int rt721_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int i; + + for (i = 0; i < p->count; i++) + ucontrol->value.integer.value[i] = !rt721->fu1e_mixer_mute[i]; + + return 0; +} + +static int rt721_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + int err, changed = 0, i; + + for (i = 0; i < p->count; i++) { + if (rt721->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i]) + changed = 1; + rt721->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i]; + } + + err = rt721_sdca_set_fu1e_capture_ctl(rt721); + if (err < 0) + return err; + + return changed; +} + +static int rt721_sdca_set_fu0f_capture_ctl(struct rt721_sdca_priv *rt721) +{ + int err; + unsigned int ch_l, ch_r; + + ch_l = (rt721->fu0f_dapm_mute || rt721->fu0f_mixer_l_mute) ? 0x01 : 0x00; + ch_r = (rt721->fu0f_dapm_mute || rt721->fu0f_mixer_r_mute) ? 0x01 : 0x00; + + err = regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_MUTE, CH_L), ch_l); + if (err < 0) + return err; + + err = regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_MUTE, CH_R), ch_r); + if (err < 0) + return err; + + return 0; +} + +static int rt721_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt721->fu0f_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt721->fu0f_mixer_r_mute; + return 0; +} + +static int rt721_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + int err, changed = 0; + + if (rt721->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] || + rt721->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1]) + changed = 1; + + rt721->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt721->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1]; + err = rt721_sdca_set_fu0f_capture_ctl(rt721); + if (err < 0) + return err; + + return changed; +} + +static int rt721_sdca_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +static int rt721_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int boost_step = 0x0a00; + unsigned int vol_max = 0x1e00; + unsigned int regvalue, ctl, i; + unsigned int adc_vol_flag = 0; + const unsigned int interval_offset = 0xc0; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt721->mbq_regmap, p->reg_base + i, ®value); + + if (!adc_vol_flag) /* boost gain */ + ctl = regvalue / boost_step; + else /* ADC gain */ + ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset); + + ucontrol->value.integer.value[i] = ctl; + } + + return 0; +} + +static int rt721_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt721_sdca_dmic_kctrl_priv *p = + (struct rt721_sdca_dmic_kctrl_priv *)kcontrol->private_value; + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned int boost_step = 0x0a00; + unsigned int vol_max = 0x1e00; + unsigned int gain_val[4]; + unsigned int i, adc_vol_flag = 0, changed = 0; + unsigned int regvalue[4]; + const unsigned int interval_offset = 0xc0; + int err; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt721->mbq_regmap, p->reg_base + i, ®value[i]); + + gain_val[i] = ucontrol->value.integer.value[i]; + if (gain_val[i] > p->max) + gain_val[i] = p->max; + + if (!adc_vol_flag) /* boost gain */ + gain_val[i] = gain_val[i] * boost_step; + else { /* ADC gain */ + gain_val[i] = vol_max - ((p->max - gain_val[i]) * interval_offset); + gain_val[i] &= 0xffff; + } + + if (regvalue[i] != gain_val[i]) + changed = 1; + } + + if (!changed) + return 0; + + for (i = 0; i < p->count; i++) { + err = regmap_write(rt721->mbq_regmap, p->reg_base + i, gain_val[i]); + if (err < 0) + dev_err(&rt721->slave->dev, "%#08x can't be set\n", p->reg_base + i); + } + + return changed; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0); +static const DECLARE_TLV_DB_SCALE(mic2_boost_vol_tlv, -200, 200, 0); + +static const struct snd_kcontrol_new rt721_sdca_controls[] = { + /* Headphone playback settings */ + SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0, + rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, out_vol_tlv), + /* Headset mic capture settings */ + SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt721_sdca_fu0f_capture_get, rt721_sdca_fu0f_capture_put), + SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F, + RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x3f, 0, + rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU33 Boost Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, + RT721_SDCA_CTL_FU_CH_GAIN, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PLATFORM_FU44, + RT721_SDCA_CTL_FU_CH_GAIN, CH_R), 1, 0x15, 0, + rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, mic2_boost_vol_tlv), + /* AMP playback settings */ + SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume", + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_VOLUME, CH_R), 0, 0x57, 0, + rt721_sdca_set_gain_get, rt721_sdca_set_gain_put, out_vol_tlv), + /* DMIC capture settings */ + RT_SDCA_FU_CTRL("FU1E Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_MUTE, CH_01), 1, 1, 4, rt721_sdca_fu_info, + rt721_sdca_fu1e_capture_get, rt721_sdca_fu1e_capture_put), + RT_SDCA_EXT_TLV("FU1E Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E, + RT721_SDCA_CTL_FU_VOLUME, CH_01), + rt721_sdca_dmic_set_gain_get, rt721_sdca_dmic_set_gain_put, + 4, 0x3f, mic_vol_tlv, rt721_sdca_fu_info), + RT_SDCA_EXT_TLV("FU15 Boost Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_FU15, + RT721_SDCA_CTL_FU_CH_GAIN, CH_01), + rt721_sdca_dmic_set_gain_get, rt721_sdca_dmic_set_gain_put, + 4, 3, boost_vol_tlv, rt721_sdca_fu_info), +}; + +static int rt721_sdca_adc_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned int val = 0, mask_sft, mask; + + if (strstr(ucontrol->id.name, "ADC 09 Mux")) { + mask_sft = 12; + mask = 0x7; + } else if (strstr(ucontrol->id.name, "ADC 08 R Mux")) { + mask_sft = 10; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 08 L Mux")) { + mask_sft = 8; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 10 R Mux")) { + mask_sft = 6; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 10 L Mux")) { + mask_sft = 4; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 07 R Mux")) { + mask_sft = 2; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 07 L Mux")) { + mask_sft = 0; + mask = 0x3; + } else + return -EINVAL; + + rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_MUX_CTL0, &val); + + ucontrol->value.enumerated.item[0] = (val >> mask_sft) & mask; + + return 0; +} + +static int rt721_sdca_adc_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, mask_sft, mask; + unsigned int check; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 09 Mux")) { + mask_sft = 12; + mask = 0x7; + } else if (strstr(ucontrol->id.name, "ADC 08 R Mux")) { + mask_sft = 10; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 08 L Mux")) { + mask_sft = 8; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 10 R Mux")) { + mask_sft = 6; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 10 L Mux")) { + mask_sft = 4; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 07 R Mux")) { + mask_sft = 2; + mask = 0x3; + } else if (strstr(ucontrol->id.name, "ADC 07 L Mux")) { + mask_sft = 0; + mask = 0x3; + } else + return -EINVAL; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_MUX_CTL0, &val2); + + if (strstr(ucontrol->id.name, "ADC 09 Mux")) + val2 = (val2 >> mask_sft) & 0x7; + else + val2 = (val2 >> mask_sft) & 0x3; + + if (val == val2) + change = 0; + else + change = 1; + + if (change) { + rt_sdca_index_read(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_MUX_CTL0, &check); + rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT, + RT721_HDA_LEGACY_MUX_CTL0, mask << mask_sft, + val << mask_sft); + } + + snd_soc_dapm_mux_update_power(dapm, kcontrol, + item[0], e, NULL); + + return change; +} + +static const char * const adc09_mux_text[] = { + "MIC2", + "LINE1", + "LINE2", +}; +static const char * const adc07_10_mux_text[] = { + "DMIC1 RE", + "DMIC1 FE", + "DMIC2 RE", + "DMIC2 FE", +}; + +static SOC_ENUM_SINGLE_DECL( + rt721_adc09_enum, SND_SOC_NOPM, 0, adc09_mux_text); +static SOC_ENUM_SINGLE_DECL( + rt721_dmic_enum, SND_SOC_NOPM, 0, adc07_10_mux_text); + +static const struct snd_kcontrol_new rt721_sdca_adc09_mux = + SOC_DAPM_ENUM_EXT("ADC 09 Mux", rt721_adc09_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc08_r_mux = + SOC_DAPM_ENUM_EXT("ADC 08 R Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc08_l_mux = + SOC_DAPM_ENUM_EXT("ADC 08 L Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc10_r_mux = + SOC_DAPM_ENUM_EXT("ADC 10 R Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc10_l_mux = + SOC_DAPM_ENUM_EXT("ADC 10 L Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc07_r_mux = + SOC_DAPM_ENUM_EXT("ADC 07 R Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); +static const struct snd_kcontrol_new rt721_sdca_adc07_l_mux = + SOC_DAPM_ENUM_EXT("ADC 07 L Mux", rt721_dmic_enum, + rt721_sdca_adc_mux_get, rt721_sdca_adc_mux_put); + + +static int rt721_sdca_fu42_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msleep(100); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_L), unmute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_R), unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_L), mute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05, + RT721_SDCA_CTL_FU_MUTE, CH_R), mute); + break; + } + return 0; +} + +static int rt721_sdca_fu21_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_L), unmute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_R), unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_L), mute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06, + RT721_SDCA_CTL_FU_MUTE, CH_R), mute); + break; + } + return 0; +} + +static int rt721_sdca_fu23_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_L), unmute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_R), unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_L), mute); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23, + RT721_SDCA_CTL_FU_MUTE, CH_R), mute); + break; + } + return 0; +} + +static int rt721_sdca_fu113_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt721->fu1e_dapm_mute = false; + rt721_sdca_set_fu1e_capture_ctl(rt721); + break; + case SND_SOC_DAPM_PRE_PMD: + rt721->fu1e_dapm_mute = true; + rt721_sdca_set_fu1e_capture_ctl(rt721); + break; + } + return 0; +} + +static int rt721_sdca_fu36_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt721->fu0f_dapm_mute = false; + rt721_sdca_set_fu0f_capture_ctl(rt721); + break; + case SND_SOC_DAPM_PRE_PMD: + rt721->fu0f_dapm_mute = true; + rt721_sdca_set_fu0f_capture_ctl(rt721); + break; + } + return 0; +} + +static int rt721_sdca_pde47_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt721_sdca_pde41_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt721_sdca_pde11_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static int rt721_sdca_pde34_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12, + RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps3); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt721_sdca_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + SND_SOC_DAPM_INPUT("DMIC1_2"), + SND_SOC_DAPM_INPUT("DMIC3_4"), + + SND_SOC_DAPM_SUPPLY("PDE 41", SND_SOC_NOPM, 0, 0, + rt721_sdca_pde41_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0, + rt721_sdca_pde47_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, + rt721_sdca_pde11_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 34", SND_SOC_NOPM, 0, 0, + rt721_sdca_pde34_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu21_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("FU 23", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu23_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("FU 42", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu42_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu36_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0, + rt721_sdca_fu113_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("ADC 09 Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc09_mux), + SND_SOC_DAPM_MUX("ADC 08 R Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc08_r_mux), + SND_SOC_DAPM_MUX("ADC 08 L Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc08_l_mux), + SND_SOC_DAPM_MUX("ADC 10 R Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc10_r_mux), + SND_SOC_DAPM_MUX("ADC 10 L Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc10_l_mux), + SND_SOC_DAPM_MUX("ADC 07 R Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc07_r_mux), + SND_SOC_DAPM_MUX("ADC 07 L Mux", SND_SOC_NOPM, 0, 0, + &rt721_sdca_adc07_l_mux), + + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Headphone Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Headset Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Speaker Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 DMic Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt721_sdca_audio_map[] = { + {"FU 42", NULL, "DP1RX"}, + {"FU 21", NULL, "DP3RX"}, + {"FU 23", NULL, "DP3RX"}, + + {"ADC 09 Mux", "MIC2", "MIC2"}, + {"ADC 09 Mux", "LINE1", "LINE1"}, + {"ADC 09 Mux", "LINE2", "LINE2"}, + {"ADC 07 R Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 07 R Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 07 R Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 07 R Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 07 L Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 07 L Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 07 L Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 07 L Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 08 R Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 08 R Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 08 R Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 08 R Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 08 L Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 08 L Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 08 L Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 08 L Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 10 R Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 10 R Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 10 R Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 10 R Mux", "DMIC2 FE", "DMIC3_4"}, + {"ADC 10 L Mux", "DMIC1 RE", "DMIC1_2"}, + {"ADC 10 L Mux", "DMIC1 FE", "DMIC1_2"}, + {"ADC 10 L Mux", "DMIC2 RE", "DMIC3_4"}, + {"ADC 10 L Mux", "DMIC2 FE", "DMIC3_4"}, + {"FU 36", NULL, "PDE 34"}, + {"FU 36", NULL, "ADC 09 Mux"}, + {"FU 113", NULL, "PDE 11"}, + {"FU 113", NULL, "ADC 07 R Mux"}, + {"FU 113", NULL, "ADC 07 L Mux"}, + {"FU 113", NULL, "ADC 10 R Mux"}, + {"FU 113", NULL, "ADC 10 L Mux"}, + {"DP2TX", NULL, "FU 36"}, + {"DP6TX", NULL, "FU 113"}, + + {"HP", NULL, "PDE 47"}, + {"HP", NULL, "FU 42"}, + {"SPK", NULL, "PDE 41"}, + {"SPK", NULL, "FU 21"}, + {"SPK", NULL, "FU 23"}, +}; + +static int rt721_sdca_parse_dt(struct rt721_sdca_priv *rt721, struct device *dev) +{ + device_property_read_u32(dev, "realtek,jd-src", &rt721->jd_src); + + return 0; +} + +static int rt721_sdca_probe(struct snd_soc_component *component) +{ + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + int ret; + + rt721_sdca_parse_dt(rt721, &rt721->slave->dev); + rt721->component = component; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + +static const struct snd_soc_component_driver soc_sdca_dev_rt721 = { + .probe = rt721_sdca_probe, + .controls = rt721_sdca_controls, + .num_controls = ARRAY_SIZE(rt721_sdca_controls), + .dapm_widgets = rt721_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt721_sdca_dapm_widgets), + .dapm_routes = rt721_sdca_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt721_sdca_audio_map), + .set_jack = rt721_sdca_set_jack_detect, + .endianness = 1, +}; + +static int rt721_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} + +static void rt721_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int rt721_sdca_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_runtime *sdw_stream; + int retval, port, num_channels; + unsigned int sampling_rate; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + sdw_stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!sdw_stream) + return -EINVAL; + + if (!rt721->slave) + return -EINVAL; + + /* + * RT721_AIF1 with port = 1 for headphone playback + * RT721_AIF1 with port = 2 for headset-mic capture + * RT721_AIF2 with port = 3 for speaker playback + * RT721_AIF3 with port = 6 for digital-mic capture + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + if (dai->id == RT721_AIF1) + port = 1; + else if (dai->id == RT721_AIF2) + port = 3; + else + return -EINVAL; + } else { + direction = SDW_DATA_DIR_TX; + if (dai->id == RT721_AIF1) + port = 2; + else if (dai->id == RT721_AIF3) + port = 6; + else + return -EINVAL; + } + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = GENMASK(num_channels - 1, 0); + port_config.num = port; + + retval = sdw_stream_add_slave(rt721->slave, &stream_config, + &port_config, 1, sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + if (params_channels(params) > 16) { + dev_err(component->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 8000: + sampling_rate = RT721_SDCA_RATE_8000HZ; + break; + case 16000: + sampling_rate = RT721_SDCA_RATE_16000HZ; + break; + case 24000: + sampling_rate = RT721_SDCA_RATE_24000HZ; + break; + case 32000: + sampling_rate = RT721_SDCA_RATE_32000HZ; + break; + case 44100: + sampling_rate = RT721_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT721_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT721_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT721_SDCA_RATE_192000HZ; + break; + case 384000: + sampling_rate = RT721_SDCA_RATE_384000HZ; + break; + case 768000: + sampling_rate = RT721_SDCA_RATE_768000HZ; + break; + default: + dev_err(component->dev, "Rate %d is not supported\n", + params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + if (dai->id == RT721_AIF1) { + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + } + + if (dai->id == RT721_AIF2) + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + + if (dai->id == RT721_AIF3) + regmap_write(rt721->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F, + RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); + + return 0; +} + +static int rt721_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt721_sdca_priv *rt721 = snd_soc_component_get_drvdata(component); + struct sdw_stream_runtime *sdw_stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt721->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt721->slave, sdw_stream); + return 0; +} + +#define RT721_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +#define RT721_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static const struct snd_soc_dai_ops rt721_sdca_ops = { + .hw_params = rt721_sdca_pcm_hw_params, + .hw_free = rt721_sdca_pcm_hw_free, + .set_stream = rt721_sdca_set_sdw_stream, + .shutdown = rt721_sdca_shutdown, +}; + +static struct snd_soc_dai_driver rt721_sdca_dai[] = { + { + .name = "rt721-sdca-aif1", + .id = RT721_AIF1, + .playback = { + .stream_name = "DP1 Headphone Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT721_STEREO_RATES, + .formats = RT721_FORMATS, + }, + .capture = { + .stream_name = "DP2 Headset Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT721_STEREO_RATES, + .formats = RT721_FORMATS, + }, + .ops = &rt721_sdca_ops, + }, + { + .name = "rt721-sdca-aif2", + .id = RT721_AIF2, + .playback = { + .stream_name = "DP3 Speaker Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT721_STEREO_RATES, + .formats = RT721_FORMATS, + }, + .ops = &rt721_sdca_ops, + }, + { + .name = "rt721-sdca-aif3", + .id = RT721_AIF3, + .capture = { + .stream_name = "DP6 DMic Capture", + .channels_min = 1, + .channels_max = 4, + .rates = RT721_STEREO_RATES, + .formats = RT721_FORMATS, + }, + .ops = &rt721_sdca_ops, + } +}; + +int rt721_sdca_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave) +{ + struct rt721_sdca_priv *rt721; + + rt721 = devm_kzalloc(dev, sizeof(*rt721), GFP_KERNEL); + if (!rt721) + return -ENOMEM; + + dev_set_drvdata(dev, rt721); + rt721->slave = slave; + rt721->regmap = regmap; + rt721->mbq_regmap = mbq_regmap; + + regcache_cache_only(rt721->regmap, true); + regcache_cache_only(rt721->mbq_regmap, true); + + mutex_init(&rt721->calibrate_mutex); + mutex_init(&rt721->disable_irq_lock); + + INIT_DELAYED_WORK(&rt721->jack_detect_work, rt721_sdca_jack_detect_handler); + INIT_DELAYED_WORK(&rt721->jack_btn_check_work, rt721_sdca_btn_check_handler); + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt721->hw_init = false; + rt721->first_hw_init = false; + rt721->fu1e_dapm_mute = true; + rt721->fu0f_dapm_mute = true; + rt721->fu0f_mixer_l_mute = rt721->fu0f_mixer_r_mute = true; + rt721->fu1e_mixer_mute[0] = rt721->fu1e_mixer_mute[1] = + rt721->fu1e_mixer_mute[2] = rt721->fu1e_mixer_mute[3] = true; + + return devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt721, rt721_sdca_dai, ARRAY_SIZE(rt721_sdca_dai)); +} + +int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); + + rt721->disable_irq = false; + + if (rt721->hw_init) + return 0; + + regcache_cache_only(rt721->regmap, false); + regcache_cache_only(rt721->mbq_regmap, false); + if (rt721->first_hw_init) { + regcache_cache_bypass(rt721->regmap, true); + regcache_cache_bypass(rt721->mbq_regmap, true); + } else { + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + rt721_sdca_dmic_preset(rt721); + rt721_sdca_amp_preset(rt721); + rt721_sdca_jack_preset(rt721); + if (rt721->first_hw_init) { + regcache_cache_bypass(rt721->regmap, false); + regcache_mark_dirty(rt721->regmap); + regcache_cache_bypass(rt721->mbq_regmap, false); + regcache_mark_dirty(rt721->mbq_regmap); + } else + rt721->first_hw_init = true; + + /* Mark Slave initialization complete */ + rt721->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + return 0; +} + +MODULE_DESCRIPTION("ASoC RT721 SDCA SDW driver"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt721-sdca.h b/sound/soc/codecs/rt721-sdca.h new file mode 100644 index 00000000000000..0a82c107b19a20 --- /dev/null +++ b/sound/soc/codecs/rt721-sdca.h @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt721-sdca.h -- RT721 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2024 Realtek Semiconductor Corp. + */ + +#ifndef __RT721_H__ +#define __RT721_H__ + +#include +#include +#include +#include +#include +#include + +struct rt721_sdca_priv { + struct regmap *regmap; + struct regmap *mbq_regmap; + struct snd_soc_component *component; + struct sdw_slave *slave; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; + struct mutex calibrate_mutex; + struct mutex disable_irq_lock; + bool disable_irq; + /* For Headset jack & Headphone */ + unsigned int scp_sdca_stat1; + unsigned int scp_sdca_stat2; + struct snd_soc_jack *hs_jack; + struct delayed_work jack_detect_work; + struct delayed_work jack_btn_check_work; + int jack_type; + int jd_src; + bool fu0f_dapm_mute; + bool fu0f_mixer_l_mute; + bool fu0f_mixer_r_mute; + /* For DMIC */ + bool fu1e_dapm_mute; + bool fu1e_mixer_mute[4]; +}; + +struct rt721_sdca_dmic_kctrl_priv { + unsigned int reg_base; + unsigned int count; + unsigned int max; + unsigned int invert; +}; + +/* NID */ +#define RT721_ANA_POW_PART 0x01 +#define RT721_DAC_CTRL 0x04 +#define RT721_JD_CTRL 0x09 +#define RT721_CBJ_CTRL 0x0a +#define RT721_CAP_PORT_CTRL 0x0c +#define RT721_CLASD_AMP_CTRL 0x0d +#define RT721_VENDOR_REG 0x20 +#define RT721_RC_CALIB_CTRL 0x40 +#define RT721_VENDOR_EQ_L 0x53 +#define RT721_VENDOR_EQ_R 0x54 +#define RT721_VENDOR_HP_CALI 0x56 +#define RT721_VENDOR_CHARGE_PUMP 0x57 +#define RT721_VENDOR_CLASD_CALI 0x58 +#define RT721_VENDOR_IMS_DRE 0x5b +#define RT721_VENDOR_SPK_EFUSE 0x5c +#define RT721_VENDOR_LEVEL_CTRL 0x5d +#define RT721_VENDOR_ANA_CTL 0x5f +#define RT721_HDA_SDCA_FLOAT 0x61 + +/* Index (NID:01h) */ +#define RT721_MBIAS_LV_CTRL2 0x07 +#define RT721_VREF1_HV_CTRL1 0x0a +#define RT721_VREF2_LV_CTRL1 0x0b + +/* Index (NID:04h) */ +#define RT721_DAC_2CH_CTRL3 0x02 +#define RT721_DAC_2CH_CTRL4 0x03 + +/* Index (NID:09h) */ +#define RT721_JD_1PIN_GAT_CTRL2 0x07 + +/* Index (NID:0ah) */ +#define RT721_CBJ_A0_GAT_CTRL1 0x04 +#define RT721_CBJ_A0_GAT_CTRL2 0x05 + +/* Index (NID:0Ch) */ +#define RT721_HP_AMP_2CH_CAL1 0x05 +#define RT721_HP_AMP_2CH_CAL4 0x08 +#define RT721_HP_AMP_2CH_CAL18 0x1b + +/* Index (NID:0dh) */ +#define RT721_CLASD_AMP_2CH_CAL 0x14 + +/* Index (NID:20h) */ +#define RT721_JD_PRODUCT_NUM 0x00 +#define RT721_ANALOG_BIAS_CTL3 0x04 +#define RT721_JD_CTRL1 0x09 +#define RT721_LDO2_3_CTL1 0x0e +#define RT721_GPIO_PAD_CTRL5 0x13 +#define RT721_LDO1_CTL 0x1a +#define RT721_HP_JD_CTRL 0x24 +#define RT721_VD_HIDDEN_CTRL 0x26 +#define RT721_CLSD_CTRL6 0x3c +#define RT721_COMBO_JACK_AUTO_CTL1 0x45 +#define RT721_COMBO_JACK_AUTO_CTL2 0x46 +#define RT721_COMBO_JACK_AUTO_CTL3 0x47 +#define RT721_DIGITAL_MISC_CTRL4 0x4a +#define RT721_VREFO_GAT 0x63 +#define RT721_FSM_CTL 0x67 +#define RT721_SDCA_INTR_REC 0x82 +#define RT721_SW_CONFIG1 0x8a +#define RT721_SW_CONFIG2 0x8b + +/* Index (NID:40h) */ +#define RT721_RC_CALIB_CTRL0 0x00 + +/* Index (NID:58h) */ +#define RT721_DAC_DC_CALI_CTL1 0x01 +#define RT721_DAC_DC_CALI_CTL2 0x02 +#define RT721_DAC_DC_CALI_CTL3 0x03 + +/* Index (NID:5fh) */ +#define RT721_MISC_POWER_CTL0 0x00 +#define RT721_MISC_POWER_CTL31 0x31 +#define RT721_UAJ_TOP_TCON13 0x44 +#define RT721_UAJ_TOP_TCON14 0x45 +#define RT721_UAJ_TOP_TCON17 0x48 + +/* Index (NID:61h) */ +#define RT721_HDA_LEGACY_MUX_CTL0 0x00 +#define RT721_HDA_LEGACY_UAJ_CTL 0x02 +#define RT721_HDA_LEGACY_CTL1 0x05 +#define RT721_HDA_LEGACY_RESET_CTL 0x06 +#define RT721_XU_REL_CTRL 0x0c +#define RT721_GE_REL_CTRL1 0x0d +#define RT721_HDA_LEGACY_GPIO_WAKE_EN_CTL 0x0e +#define RT721_GE_SDCA_RST_CTRL 0x10 +#define RT721_INT_RST_EN_CTRL 0x11 +#define RT721_XU_EVENT_EN 0x13 +#define RT721_INLINE_CTL2 0x17 +#define RT721_UMP_HID_CTRL1 0x18 +#define RT721_UMP_HID_CTRL2 0x19 +#define RT721_UMP_HID_CTRL3 0x1a +#define RT721_UMP_HID_CTRL4 0x1b +#define RT721_UMP_HID_CTRL5 0x1c +#define RT721_FUNC_FLOAT_CTL0 0x22 +#define RT721_FUNC_FLOAT_CTL1 0x23 +#define RT721_FUNC_FLOAT_CTL2 0x24 +#define RT721_FUNC_FLOAT_CTL3 0x25 +#define RT721_ENT_FLOAT_CTL0 0x29 +#define RT721_ENT_FLOAT_CTL1 0x2c +#define RT721_ENT_FLOAT_CTL2 0x2d +#define RT721_ENT_FLOAT_CTL3 0x2e +#define RT721_ENT_FLOAT_CTL4 0x2f +#define RT721_CH_FLOAT_CTL1 0x45 +#define RT721_CH_FLOAT_CTL2 0x46 +#define RT721_ENT_FLOAT_CTL5 0x53 +#define RT721_ENT_FLOAT_CTL6 0x54 +#define RT721_ENT_FLOAT_CTL7 0x55 +#define RT721_ENT_FLOAT_CTL8 0x57 +#define RT721_ENT_FLOAT_CTL9 0x5a +#define RT721_ENT_FLOAT_CTL10 0x5b +#define RT721_CH_FLOAT_CTL3 0x6a +#define RT721_CH_FLOAT_CTL4 0x6d +#define RT721_CH_FLOAT_CTL5 0x70 +#define RT721_CH_FLOAT_CTL6 0x92 + +/* Parameter & Verb control 01 (0x26)(NID:20h) */ +#define RT721_HIDDEN_REG_SW_RESET (0x1 << 14) + +/* Buffer address for HID */ +#define RT721_BUF_ADDR_HID1 0x44030000 +#define RT721_BUF_ADDR_HID2 0x44030020 + +/* RT721 SDCA Control - function number */ +#define FUNC_NUM_JACK_CODEC 0x01 +#define FUNC_NUM_MIC_ARRAY 0x02 +#define FUNC_NUM_HID 0x03 +#define FUNC_NUM_AMP 0x04 + +/* RT721 SDCA entity */ +#define RT721_SDCA_ENT_HID01 0x01 +#define RT721_SDCA_ENT_XUV 0x03 +#define RT721_SDCA_ENT_GE49 0x49 +#define RT721_SDCA_ENT_USER_FU05 0x05 +#define RT721_SDCA_ENT_USER_FU06 0x06 +#define RT721_SDCA_ENT_USER_FU0F 0x0f +#define RT721_SDCA_ENT_USER_FU10 0x19 +#define RT721_SDCA_ENT_USER_FU1E 0x1e +#define RT721_SDCA_ENT_FU15 0x15 +#define RT721_SDCA_ENT_PDE23 0x23 +#define RT721_SDCA_ENT_PDE40 0x40 +#define RT721_SDCA_ENT_PDE41 0x41 +#define RT721_SDCA_ENT_PDE11 0x11 +#define RT721_SDCA_ENT_PDE12 0x12 +#define RT721_SDCA_ENT_PDE2A 0x2a +#define RT721_SDCA_ENT_CS01 0x01 +#define RT721_SDCA_ENT_CS11 0x11 +#define RT721_SDCA_ENT_CS1F 0x1f +#define RT721_SDCA_ENT_CS1C 0x1c +#define RT721_SDCA_ENT_CS31 0x31 +#define RT721_SDCA_ENT_OT23 0x42 +#define RT721_SDCA_ENT_IT26 0x26 +#define RT721_SDCA_ENT_IT09 0x09 +#define RT721_SDCA_ENT_PLATFORM_FU15 0x15 +#define RT721_SDCA_ENT_PLATFORM_FU44 0x44 +#define RT721_SDCA_ENT_XU03 0x03 +#define RT721_SDCA_ENT_XU0D 0x0d +#define RT721_SDCA_ENT_FU55 0x55 + +/* RT721 SDCA control */ +#define RT721_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10 +#define RT721_SDCA_CTL_FU_MUTE 0x01 +#define RT721_SDCA_CTL_FU_VOLUME 0x02 +#define RT721_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10 +#define RT721_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11 +#define RT721_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12 +#define RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13 +#define RT721_SDCA_CTL_SELECTED_MODE 0x01 +#define RT721_SDCA_CTL_DETECTED_MODE 0x02 +#define RT721_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT721_SDCA_CTL_VENDOR_DEF 0x30 +#define RT721_SDCA_CTL_XUV 0x34 +#define RT721_SDCA_CTL_FU_CH_GAIN 0x0b + +/* RT721 SDCA channel */ +#define CH_L 0x01 +#define CH_R 0x02 +#define CH_01 0x01 +#define CH_02 0x02 +#define CH_03 0x03 +#define CH_04 0x04 +#define CH_08 0x08 +#define CH_09 0x09 +#define CH_0A 0x0a + +/* sample frequency index */ +#define RT721_SDCA_RATE_8000HZ 0x01 +#define RT721_SDCA_RATE_11025HZ 0x02 +#define RT721_SDCA_RATE_12000HZ 0x03 +#define RT721_SDCA_RATE_16000HZ 0x04 +#define RT721_SDCA_RATE_22050HZ 0x05 +#define RT721_SDCA_RATE_24000HZ 0x06 +#define RT721_SDCA_RATE_32000HZ 0x07 +#define RT721_SDCA_RATE_44100HZ 0x08 +#define RT721_SDCA_RATE_48000HZ 0x09 +#define RT721_SDCA_RATE_88200HZ 0x0a +#define RT721_SDCA_RATE_96000HZ 0x0b +#define RT721_SDCA_RATE_176400HZ 0x0c +#define RT721_SDCA_RATE_192000HZ 0x0d +#define RT721_SDCA_RATE_384000HZ 0x0e +#define RT721_SDCA_RATE_768000HZ 0x0f + +/* RT721 HID ID */ +#define RT721_SDCA_HID_ID 0x11 + +enum { + RT721_AIF1, /* For headset mic and headphone */ + RT721_AIF2, /* For speaker */ + RT721_AIF3, /* For dmic */ + RT721_AIFS, +}; + +int rt721_sdca_io_init(struct device *dev, struct sdw_slave *slave); +int rt721_sdca_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave); +#endif /* __RT721_H__ */ diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index d5c985ff5ac553..25fc13687bc83c 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -177,7 +177,7 @@ static int rt722_sdca_update_status(struct sdw_slave *slave, * This also could sync with the cache value as the rt722_sdca_jack_init set. */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_6); + SDW_SCP_SDCA_INTMASK_SDCA_0); sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); } @@ -308,12 +308,8 @@ static int rt722_sdca_interrupt_callback(struct sdw_slave *slave, SDW_SCP_SDCA_INT_SDCA_0, SDW_SCP_SDCA_INT_SDCA_0); if (ret < 0) goto io_error; - } else if (ret & SDW_SCP_SDCA_INTMASK_SDCA_6) { - ret = sdw_update_no_pm(rt722->slave, SDW_SCP_SDCA_INT1, - SDW_SCP_SDCA_INT_SDCA_6, SDW_SCP_SDCA_INT_SDCA_6); - if (ret < 0) - goto io_error; } + ret = sdw_read_no_pm(rt722->slave, SDW_SCP_SDCA_INT2); if (ret < 0) goto io_error; @@ -444,7 +440,7 @@ static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev) mutex_lock(&rt722_sdca->disable_irq_lock); rt722_sdca->disable_irq = true; ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6, 0); + SDW_SCP_SDCA_INTMASK_SDCA_0, 0); ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8, 0); mutex_unlock(&rt722_sdca->disable_irq_lock); @@ -471,7 +467,7 @@ static int __maybe_unused rt722_sdca_dev_resume(struct device *dev) if (!slave->unattach_request) { mutex_lock(&rt722->disable_irq_lock); if (rt722->disable_irq == true) { - sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_6); + sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); rt722->disable_irq = false; } diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index e5bd9ef812de13..908846e994df34 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -190,8 +190,8 @@ static void rt722_sdca_jack_detect_handler(struct work_struct *work) if (!rt722->component->card || !rt722->component->card->instantiated) return; - /* SDW_SCP_SDCA_INT_SDCA_6 is used for jack detection */ - if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_6) { + /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */ + if (rt722->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) { ret = rt722_sdca_headset_detect(rt722); if (ret < 0) return; @@ -294,7 +294,7 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) if (rt722->hs_jack) { /* set SCP_SDCA_IntMask1[0]=1 */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1, - SDW_SCP_SDCA_INTMASK_SDCA_0 | SDW_SCP_SDCA_INTMASK_SDCA_6); + SDW_SCP_SDCA_INTMASK_SDCA_0); /* set SCP_SDCA_IntMask2[0]=1 */ sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); @@ -308,6 +308,7 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722) regmap_write(rt722->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D, RT722_SDCA_CTL_SELECTED_MODE, 0), 0); + rt722_sdca_index_write(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL1, 0x0000); /* trigger GE interrupt */ rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL, RT722_GE_RELATED_CTL2, 0x4000, 0x4000); @@ -607,12 +608,8 @@ static int rt722_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, if (!adc_vol_flag) /* boost gain */ ctl = regvalue / boost_step; - else { /* ADC gain */ - if (adc_vol_flag) - ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset); - else - ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset); - } + else /* ADC gain */ + ctl = p->max - (((vol_max - regvalue) & 0xffff) / interval_offset); ucontrol->value.integer.value[i] = ctl; } diff --git a/sound/soc/codecs/simple-mux.c b/sound/soc/codecs/simple-mux.c index 240af0563283e5..3906964401557d 100644 --- a/sound/soc/codecs/simple-mux.c +++ b/sound/soc/codecs/simple-mux.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -16,6 +17,7 @@ struct simple_mux { struct gpio_desc *gpiod_mux; unsigned int mux; const char *mux_texts[MUX_TEXT_SIZE]; + unsigned int idle_state; struct soc_enum mux_enum; struct snd_kcontrol_new mux_mux; struct snd_soc_dapm_widget mux_widgets[MUX_WIDGET_SIZE]; @@ -57,6 +59,9 @@ static int simple_mux_control_put(struct snd_kcontrol *kcontrol, priv->mux = ucontrol->value.enumerated.item[0]; + if (priv->idle_state != MUX_IDLE_AS_IS && dapm->bias_level < SND_SOC_BIAS_PREPARE) + return 0; + gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux); return snd_soc_dapm_mux_update_power(dapm, kcontrol, @@ -75,10 +80,33 @@ static unsigned int simple_mux_read(struct snd_soc_component *component, static const struct snd_kcontrol_new simple_mux_mux = SOC_DAPM_ENUM_EXT("Muxer", simple_mux_enum, simple_mux_control_get, simple_mux_control_put); +static int simple_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); + struct simple_mux *priv = snd_soc_component_get_drvdata(c); + + if (priv->idle_state != MUX_IDLE_AS_IS) { + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + gpiod_set_value_cansleep(priv->gpiod_mux, priv->mux); + break; + case SND_SOC_DAPM_POST_PMD: + gpiod_set_value_cansleep(priv->gpiod_mux, priv->idle_state); + break; + default: + break; + } + } + + return 0; +} + static const struct snd_soc_dapm_widget simple_mux_dapm_widgets[MUX_WIDGET_SIZE] = { SND_SOC_DAPM_INPUT("IN1"), SND_SOC_DAPM_INPUT("IN2"), - SND_SOC_DAPM_MUX("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux), // see simple_mux_probe() + SND_SOC_DAPM_MUX_E("MUX", SND_SOC_NOPM, 0, 0, &simple_mux_mux, // see simple_mux_probe() + simple_mux_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUTPUT("OUT"), }; @@ -93,6 +121,7 @@ static int simple_mux_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct simple_mux *priv; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -121,6 +150,14 @@ static int simple_mux_probe(struct platform_device *pdev) /* Overwrite text ("Input 1", "Input 2") if property exists */ of_property_read_string_array(np, "state-labels", priv->mux_texts, MUX_TEXT_SIZE); + ret = of_property_read_u32(np, "idle-state", &priv->idle_state); + if (ret < 0) { + priv->idle_state = MUX_IDLE_AS_IS; + } else if (priv->idle_state != MUX_IDLE_AS_IS && priv->idle_state >= 2) { + dev_err(dev, "invalid idle-state %u\n", priv->idle_state); + return -EINVAL; + } + /* switch to use priv data instead of default */ priv->mux_enum.texts = priv->mux_texts; priv->mux_mux.private_value = (unsigned long)&priv->mux_enum; diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c new file mode 100644 index 00000000000000..f2cea6186d9894 --- /dev/null +++ b/sound/soc/codecs/sma1307.c @@ -0,0 +1,2049 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// sma1307.c -- sma1307 ALSA SoC Audio driver +// +// Copyright 2024 Iron Device Corporation +// +// Auther: Gyuhwa Park +// Auther: Kiseok Jo + +#include +#include +#include +#include +#include +#include +#include "sma1307.h" + +#define CHECK_PERIOD_TIME 1 /* sec per HZ */ +#define PLL_MATCH(_input_clk_name, _output_clk_name, _input_clk,\ + _post_n, _n, _vco, _p_cp)\ +{\ + .input_clk_name = _input_clk_name,\ + .output_clk_name = _output_clk_name,\ + .input_clk = _input_clk,\ + .post_n = _post_n,\ + .n = _n,\ + .vco = _vco,\ + .p_cp = _p_cp,\ +} + +static const char *setting_file = "sma1307_setting.bin"; +#define SMA1307_SETTING_CHECKSUM 0x100000 + +/* PLL clock setting Table */ +struct sma1307_pll_match { + char *input_clk_name; + char *output_clk_name; + unsigned int input_clk; + unsigned int post_n; + unsigned int n; + unsigned int vco; + unsigned int p_cp; +}; + +struct sma1307_data { + char *name; + void (*init)(struct regmap *regmap); +}; + +struct sma1307_priv { + bool check_fault_status; + bool force_mute_status; + bool sw_ot1_prot; + char *name; + enum sma1307_mode amp_mode; + int binary_mode; + int dapm_aif_in; + int dapm_aif_out0; + int dapm_aif_out1; + int dapm_sdo_en; + int dapm_sdo_setting; + int num_of_pll_matches; + int check_fault_period; + struct delayed_work check_fault_work; + struct device *dev; + struct kobject *kobj; + struct mutex default_lock; + struct regmap *regmap; + struct sma1307_setting_file set; + const struct sma1307_pll_match *pll_matches; + const struct sma1307_data *data; + unsigned int cur_vol; + unsigned int format; + unsigned int frame_size; + unsigned int init_vol; + unsigned int last_bclk; + unsigned int otp_trm2; + unsigned int otp_trm3; + unsigned int rev_num; + unsigned int sys_clk_id; + unsigned int tdm_slot0_rx; + unsigned int tdm_slot1_rx; + unsigned int tdm_slot0_tx; + unsigned int tdm_slot1_tx; + unsigned int tsdw_cnt; +}; + +static const struct sma1307_pll_match sma1307_pll_matches[] = { + /* in_clk_name, out_clk_name, input_clk post_n, n, vco, p_cp */ + PLL_MATCH("1.411MHz", "24.554MHz", + 1411200, 0x06, 0xD1, 0x88, 0x00), + PLL_MATCH("1.536MHz", "24.576MHz", + 1536000, 0x06, 0xC0, 0x88, 0x00), + PLL_MATCH("2.822MHz", "24.554MHz", + 2822400, 0x06, 0xD1, 0x88, 0x04), + PLL_MATCH("3.072MHz", "24.576MHz", + 3072000, 0x06, 0x60, 0x88, 0x00), + PLL_MATCH("6.144MHz", "24.576MHz", + 6144000, 0x06, 0x60, 0x88, 0x04), + PLL_MATCH("12.288MHz", "24.576MHz", + 12288000, 0x06, 0x60, 0x88, 0x08), + PLL_MATCH("19.2MHz", "24.48MHz", + 19200000, 0x06, 0x7B, 0x88, 0x0C), + PLL_MATCH("24.576MHz", "24.576MHz", + 24576000, 0x06, 0x60, 0x88, 0x0C), +}; + +static struct snd_soc_component *sma1307_amp_component; + +static void sma1307_startup(struct snd_soc_component *); +static void sma1307_shutdown(struct snd_soc_component *); +static void sma1307_reset(struct snd_soc_component *); +static void sma1307_set_binary(struct snd_soc_component *); +static void sma1307_set_default(struct snd_soc_component *); + +/* Initial register value - 6.0W SPK (8ohm load) */ +static const struct reg_default sma1307_reg_def[] = { + { 0x00, 0x80 }, + { 0x01, 0x00 }, + { 0x02, 0x52 }, + { 0x03, 0x4C }, + { 0x04, 0x47 }, + { 0x05, 0x42 }, + { 0x06, 0x40 }, + { 0x07, 0x40 }, + { 0x08, 0x3C }, + { 0x09, 0x2F }, + { 0x0A, 0x32 }, + { 0x0B, 0x50 }, + { 0x0C, 0x8C }, + { 0x0D, 0x00 }, + { 0x0E, 0x3F }, + { 0x0F, 0x00 }, + { 0x10, 0x00 }, + { 0x11, 0x00 }, + { 0x12, 0x00 }, + { 0x13, 0x09 }, + { 0x14, 0x12 }, + { 0x1C, 0x00 }, + { 0x1D, 0x85 }, + { 0x1E, 0xA1 }, + { 0x1F, 0x67 }, + { 0x22, 0x00 }, + { 0x23, 0x1F }, + { 0x24, 0x7A }, + { 0x25, 0x00 }, + { 0x26, 0xFF }, + { 0x27, 0x39 }, + { 0x28, 0x54 }, + { 0x29, 0x92 }, + { 0x2A, 0xB0 }, + { 0x2B, 0xED }, + { 0x2C, 0xED }, + { 0x2D, 0xFF }, + { 0x2E, 0xFF }, + { 0x2F, 0xFF }, + { 0x30, 0xFF }, + { 0x31, 0xFF }, + { 0x32, 0xFF }, + { 0x34, 0x01 }, + { 0x35, 0x17 }, + { 0x36, 0x92 }, + { 0x37, 0x00 }, + { 0x38, 0x01 }, + { 0x39, 0x10 }, + { 0x3E, 0x01 }, + { 0x3F, 0x08 }, + { 0x8B, 0x05 }, + { 0x8C, 0x50 }, + { 0x8D, 0x80 }, + { 0x8E, 0x10 }, + { 0x8F, 0x02 }, + { 0x90, 0x02 }, + { 0x91, 0x83 }, + { 0x92, 0xC0 }, + { 0x93, 0x00 }, + { 0x94, 0xA4 }, + { 0x95, 0x74 }, + { 0x96, 0x57 }, + { 0xA2, 0xCC }, + { 0xA3, 0x28 }, + { 0xA4, 0x40 }, + { 0xA5, 0x01 }, + { 0xA6, 0x41 }, + { 0xA7, 0x08 }, + { 0xA8, 0x04 }, + { 0xA9, 0x27 }, + { 0xAA, 0x10 }, + { 0xAB, 0x10 }, + { 0xAC, 0x10 }, + { 0xAD, 0x0F }, + { 0xAE, 0xCD }, + { 0xAF, 0x70 }, + { 0xB0, 0x03 }, + { 0xB1, 0xEF }, + { 0xB2, 0x03 }, + { 0xB3, 0xEF }, + { 0xB4, 0xF3 }, + { 0xB5, 0x3D }, +}; + +static bool sma1307_readable_register(struct device *dev, unsigned int reg) +{ + if (reg > SMA1307_FF_DEVICE_INDEX) + return false; + + switch (reg) { + case SMA1307_00_SYSTEM_CTRL ... SMA1307_1F_TONE_FINE_VOLUME: + case SMA1307_22_COMP_HYS_SEL ... SMA1307_32_BROWN_OUT_PROT19: + case SMA1307_34_OCP_SPK ... SMA1307_39_PMT_NZ_VAL: + case SMA1307_3B_TEST1 ... SMA1307_3F_ATEST2: + case SMA1307_8B_PLL_POST_N ... SMA1307_9A_OTP_TRM3: + case SMA1307_A0_PAD_CTRL0 ... SMA1307_BE_MCBS_CTRL2: + case SMA1307_F5_READY_FOR_V_SAR: + case SMA1307_F7_READY_FOR_T_SAR ... SMA1307_FF_DEVICE_INDEX: + break; + default: + return false; + } + return true; +} + +static bool sma1307_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg > SMA1307_FF_DEVICE_INDEX) + return false; + + switch (reg) { + case SMA1307_00_SYSTEM_CTRL ... SMA1307_1F_TONE_FINE_VOLUME: + case SMA1307_22_COMP_HYS_SEL ... SMA1307_32_BROWN_OUT_PROT19: + case SMA1307_34_OCP_SPK ... SMA1307_39_PMT_NZ_VAL: + case SMA1307_3B_TEST1 ... SMA1307_3F_ATEST2: + case SMA1307_8B_PLL_POST_N ... SMA1307_9A_OTP_TRM3: + case SMA1307_A0_PAD_CTRL0 ... SMA1307_BE_MCBS_CTRL2: + break; + default: + return false; + } + return true; +} + +static bool sma1307_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg > SMA1307_FF_DEVICE_INDEX) + return false; + + switch (reg) { + case SMA1307_F8_STATUS_T1 ... SMA1307_FF_DEVICE_INDEX: + break; + default: + return false; + } + return true; +} + +/* DB scale conversion of speaker volume */ +static const DECLARE_TLV_DB_SCALE(sma1307_spk_tlv, -6000, 50, 0); + +static const char *const sma1307_aif_in_source_text[] = { + "Mono", "Left", "Right" +}; + +static const char *const sma1307_sdo_setting_text[] = { + "Data_One_48k", "Data_Two_48k", "Data_Two_24k", + "Clk_PLL", "Clk_OSC" +}; + +static const char *const sma1307_aif_out_source_text[] = { + "Disable", "After_FmtC", "After_Mixer", "After_DSP", + "Vrms2_Avg", "Battery", "Temperature", "After_Delay" +}; + +static const char *const sma1307_tdm_slot_text[] = { + "Slot0", "Slot1", "Slot2", "Slot3", + "Slot4", "Slot5", "Slot6", "Slot7" +}; + +static const char *const sma1307_binary_mode_text[] = { + "Mode0", "Mode1", "Mode2", "Mode3", "Mode4" +}; + +static const char *const sma1307_reset_text[] = { + "Reset" +}; + +static const struct soc_enum sma1307_aif_in_source_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_aif_in_source_text), + sma1307_aif_in_source_text); +static const struct soc_enum sma1307_sdo_setting_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_sdo_setting_text), + sma1307_sdo_setting_text); +static const struct soc_enum sma1307_aif_out_source_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_aif_out_source_text), + sma1307_aif_out_source_text); +static const struct soc_enum sma1307_tdm_slot_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_tdm_slot_text), + sma1307_tdm_slot_text); +static const struct soc_enum sma1307_binary_mode_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_binary_mode_text), + sma1307_binary_mode_text); +static const struct soc_enum sma1307_reset_enum = +SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(sma1307_reset_text), + sma1307_reset_text); + +static int sma1307_force_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (int)sma1307->force_mute_status; + + return 0; +} + +static int sma1307_force_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + bool change = false, val = (bool)ucontrol->value.integer.value[0]; + + if (sma1307->force_mute_status == val) { + change = false; + } else { + change = true; + sma1307->force_mute_status = val; + } + + return change; +} + +static int sma1307_tdm_slot_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + int val1, val2; + + regmap_read(sma1307->regmap, SMA1307_A5_TDM1, &val1); + regmap_read(sma1307->regmap, SMA1307_A6_TDM2, &val2); + + if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX0_POS_NAME)) { + ucontrol->value.integer.value[0] + = (val1 & SMA1307_TDM_SLOT0_RX_POS_MASK) >> 3; + sma1307->tdm_slot0_rx = ucontrol->value.integer.value[0]; + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX1_POS_NAME)) { + ucontrol->value.integer.value[0] + = val1 & SMA1307_TDM_SLOT1_RX_POS_MASK; + sma1307->tdm_slot1_rx = ucontrol->value.integer.value[0]; + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX0_POS_NAME)) { + ucontrol->value.integer.value[0] + = (val2 & SMA1307_TDM_SLOT0_TX_POS_MASK) >> 3; + sma1307->tdm_slot0_tx = ucontrol->value.integer.value[0]; + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX1_POS_NAME)) { + ucontrol->value.integer.value[0] + = val2 & SMA1307_TDM_SLOT1_TX_POS_MASK; + sma1307->tdm_slot1_tx = ucontrol->value.integer.value[0]; + } else { + return -EINVAL; + } + + return 0; +} + +static int sma1307_tdm_slot_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + int val = (int)ucontrol->value.integer.value[0]; + bool change; + + if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX0_POS_NAME)) { + if (sma1307->tdm_slot0_rx == val) + change = false; + else { + change = true; + sma1307->tdm_slot0_rx = val; + regmap_update_bits(sma1307->regmap, SMA1307_A5_TDM1, + SMA1307_TDM_SLOT0_RX_POS_MASK, val << 3); + } + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_RX1_POS_NAME)) { + if (sma1307->tdm_slot1_rx == val) + change = false; + else { + change = true; + sma1307->tdm_slot1_rx = val; + regmap_update_bits(sma1307->regmap, SMA1307_A5_TDM1, + SMA1307_TDM_SLOT1_RX_POS_MASK, val); + } + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX0_POS_NAME)) { + if (sma1307->tdm_slot0_tx == val) + change = false; + else { + change = true; + sma1307->tdm_slot0_tx = val; + regmap_update_bits(sma1307->regmap, SMA1307_A6_TDM2, + SMA1307_TDM_SLOT0_TX_POS_MASK, val << 3); + } + } else if (!strcmp(kcontrol->id.name, SMA1307_TDM_TX1_POS_NAME)) { + if (sma1307->tdm_slot1_tx == val) + change = false; + else { + change = true; + sma1307->tdm_slot1_tx = val; + regmap_update_bits(sma1307->regmap, SMA1307_A6_TDM2, + SMA1307_TDM_SLOT1_TX_POS_MASK, val); + } + } else { + dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + + return change; +} + +static int sma1307_sw_ot1_prot_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (int)sma1307->sw_ot1_prot; + + return 0; +} + +static int sma1307_sw_ot1_prot_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + bool change = false, val = (bool)ucontrol->value.integer.value[0]; + + if (sma1307->sw_ot1_prot == val) + change = false; + else { + change = true; + sma1307->sw_ot1_prot = val; + } + + return change; +} + +static int sma1307_check_fault_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = (int)sma1307->check_fault_status; + + return 0; +} + +static int sma1307_check_fault_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + bool change = false, val = (bool)ucontrol->value.integer.value[0]; + + if (sma1307->check_fault_status == val) { + change = false; + } else { + change = true; + sma1307->check_fault_status = val; + } + + return change; +} + +static int sma1307_check_fault_period_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = sma1307->check_fault_period; + + return 0; +} + +static int sma1307_check_fault_period_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + bool change = false; + int val = ucontrol->value.integer.value[0]; + + if (val < mc->min || val > mc->max) + return -EINVAL; + if (sma1307->check_fault_period == val) { + change = false; + } else { + change = true; + sma1307->check_fault_period = val; + } + + return change; +} + +static int sma1307_reset_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL, + SMA1307_RESET_MASK, SMA1307_RESET_ON); + sma1307_reset(component); + + snd_ctl_notify(component->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, + &kcontrol->id); + + return true; +} + +static int sma1307_binary_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct sma1307_priv *sma1307 = snd_kcontrol_chip(kcontrol); + + sma1307->binary_mode = (int)ucontrol->value.enumerated.item[0]; + if (sma1307->set.status) + sma1307_set_binary(component); + + return snd_soc_put_enum_double(kcontrol, ucontrol); +} + +static void sma1307_startup(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + regmap_update_bits(sma1307->regmap, SMA1307_A2_TOP_MAN1, + SMA1307_PLL_MASK, SMA1307_PLL_ON); + regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL, + SMA1307_POWER_MASK, SMA1307_POWER_ON); + + if (sma1307->amp_mode == SMA1307_MONO_MODE) { + regmap_update_bits(sma1307->regmap, + SMA1307_10_SYSTEM_CTRL1, + SMA1307_SPK_MODE_MASK, + SMA1307_SPK_MONO); + } else { + regmap_update_bits(sma1307->regmap, + SMA1307_10_SYSTEM_CTRL1, + SMA1307_SPK_MODE_MASK, + SMA1307_SPK_STEREO); + } + + if (sma1307->check_fault_status) { + if (sma1307->check_fault_period > 0) + queue_delayed_work(system_freezable_wq, + &sma1307->check_fault_work, + sma1307->check_fault_period * HZ); + else + queue_delayed_work(system_freezable_wq, + &sma1307->check_fault_work, + CHECK_PERIOD_TIME * HZ); + } +} + +static void sma1307_shutdown(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + /* for SMA1307A */ + cancel_delayed_work_sync(&sma1307->check_fault_work); + + regmap_update_bits(sma1307->regmap, SMA1307_0E_MUTE_VOL_CTRL, + SMA1307_SPK_MUTE_MASK, SMA1307_SPK_MUTE); + /* Need to wait time for mute slope */ + msleep(55); + + regmap_update_bits(sma1307->regmap, SMA1307_10_SYSTEM_CTRL1, + SMA1307_SPK_MODE_MASK, SMA1307_SPK_OFF); + regmap_update_bits(sma1307->regmap, SMA1307_A2_TOP_MAN1, + SMA1307_PLL_MASK, SMA1307_PLL_OFF); + regmap_update_bits(sma1307->regmap, SMA1307_00_SYSTEM_CTRL, + SMA1307_POWER_MASK, SMA1307_POWER_OFF); +} + +static int sma1307_aif_in_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int mux = sma1307->dapm_aif_in; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (mux) { + case SMA1307_MONO_MODE: + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_MONOMIX_MASK, + SMA1307_MONOMIX_ON); + break; + case SMA1307_LEFT_MODE: + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_MONOMIX_MASK, + SMA1307_MONOMIX_OFF); + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_LR_DATA_SW_MASK, + SMA1307_LR_DATA_SW_NORMAL); + break; + case SMA1307_RIGHT_MODE: + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_MONOMIX_MASK, + SMA1307_MONOMIX_OFF); + regmap_update_bits(sma1307->regmap, + SMA1307_11_SYSTEM_CTRL2, + SMA1307_LR_DATA_SW_MASK, + SMA1307_LR_DATA_SW_SWAP); + break; + default: + + dev_err(sma1307->dev, "%s: Invalid value (%d)\n", + __func__, mux); + return -EINVAL; + } + sma1307->amp_mode = mux; + break; + } + return 0; +} + +static int sma1307_sdo_setting_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int mux = sma1307->dapm_sdo_setting; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (mux) { + case SMA1307_OUT_DATA_ONE_48K: + regmap_update_bits(sma1307->regmap, + SMA1307_A2_TOP_MAN1, + SMA1307_SDO_OUTPUT2_MASK, + SMA1307_ONE_SDO_PER_CH); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT3_MASK + | + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_SDO_OUTPUT3_DIS + | SMA1307_SDO_DATA); + break; + case SMA1307_OUT_DATA_TWO_48K: + regmap_update_bits(sma1307->regmap, + SMA1307_A2_TOP_MAN1, + SMA1307_SDO_OUTPUT2_MASK, + SMA1307_TWO_SDO_PER_CH); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT3_MASK + | + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_SDO_OUTPUT3_DIS + | SMA1307_SDO_DATA); + break; + case SMA1307_OUT_DATA_TWO_24K: + regmap_update_bits(sma1307->regmap, + SMA1307_A2_TOP_MAN1, + SMA1307_SDO_OUTPUT2_MASK, + SMA1307_TWO_SDO_PER_CH); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT3_MASK + | + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_TWO_SDO_PER_CH_24K + | SMA1307_SDO_DATA); + break; + case SMA1307_OUT_CLK_PLL: + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_SDO_CLK_PLL); + + break; + case SMA1307_OUT_CLK_OSC: + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_DATA_CLK_SEL_MASK, + SMA1307_SDO_CLK_OSC); + + break; + default: + dev_err(sma1307->dev, "%s: Invalid value (%d)\n", + __func__, mux); + return -EINVAL; + } + break; + } + return 0; +} + +static int sma1307_aif_out_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int mux = 0, val = 0, mask = 0; + + if (!strcmp(w->name, SMA1307_AIF_OUT0_NAME)) { + mux = sma1307->dapm_aif_out0; + val = mux; + mask = SMA1307_SDO_OUT0_SEL_MASK; + } else if (!strcmp(w->name, SMA1307_AIF_OUT1_NAME)) { + mux = sma1307->dapm_aif_out1; + val = mux << 3; + mask = SMA1307_SDO_OUT1_SEL_MASK; + } else { + dev_err(sma1307->dev, "%s: Invalid widget - %s\n", + __func__, w->name); + return -EINVAL; + } + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(sma1307->regmap, SMA1307_09_OUTPUT_CTRL, + mask, val); + break; + } + return 0; +} + +static int sma1307_sdo_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + regmap_update_bits(sma1307->regmap, + SMA1307_09_OUTPUT_CTRL, + SMA1307_PORT_CONFIG_MASK, + SMA1307_OUTPUT_PORT_ENABLE); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT_MASK, + SMA1307_LOGIC_OUTPUT); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(sma1307->regmap, + SMA1307_09_OUTPUT_CTRL, + SMA1307_PORT_CONFIG_MASK, + SMA1307_INPUT_PORT_ONLY); + regmap_update_bits(sma1307->regmap, + SMA1307_A3_TOP_MAN2, + SMA1307_SDO_OUTPUT_MASK, + SMA1307_HIGH_Z_OUTPUT); + break; + } + return 0; +} + +static int sma1307_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + sma1307_startup(component); + break; + case SND_SOC_DAPM_PRE_PMD: + sma1307_shutdown(component); + break; + } + return 0; +} + +static int sma1307_dapm_aif_in_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + + ucontrol->value.enumerated.item[0] = (unsigned int)sma1307->dapm_aif_in; + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return 0; +} + +static int sma1307_dapm_aif_in_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + int val = (int)ucontrol->value.enumerated.item[0]; + bool change; + + if ((val < 0) || (val >= ARRAY_SIZE(sma1307_aif_in_source_text))) { + dev_err(sma1307->dev, "%s: Out of range\n", __func__); + return -EINVAL; + } + + if (sma1307->dapm_aif_in != val) { + change = true; + sma1307->dapm_aif_in = val; + } else + change = false; + + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return change; +} + +static int sma1307_dapm_sdo_setting_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + + ucontrol->value.enumerated.item[0] = + (unsigned int)sma1307->dapm_sdo_setting; + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return 0; +} + +static int sma1307_dapm_sdo_setting_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + int val = (int)ucontrol->value.enumerated.item[0]; + bool change; + + if ((val < 0) || (val >= ARRAY_SIZE(sma1307_sdo_setting_text))) { + dev_err(sma1307->dev, "%s: Out of range\n", __func__); + return -EINVAL; + } + + if (sma1307->dapm_sdo_setting != val) { + change = true; + sma1307->dapm_sdo_setting = val; + } else + change = false; + + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return change; +} + +static int sma1307_dapm_aif_out_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + unsigned int val = 0; + + if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT0_NAME)) { + val = (unsigned int)sma1307->dapm_aif_out0; + } else if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT1_NAME)) { + val = (unsigned int)sma1307->dapm_aif_out1; + } else { + dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + ucontrol->value.enumerated.item[0] = val; + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return 0; +} + +static int sma1307_dapm_aif_out_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + int val = (int)ucontrol->value.enumerated.item[0]; + bool change; + + if ((val < 0) || (val >= ARRAY_SIZE(sma1307_aif_out_source_text))) { + dev_err(sma1307->dev, "%s: Out of range\n", __func__); + return -EINVAL; + } + + if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT0_NAME)) { + if (sma1307->dapm_aif_out0 != val) { + change = true; + sma1307->dapm_aif_out0 = val; + } else + change = false; + } else if (!strcmp(kcontrol->id.name, SMA1307_AIF_OUT1_NAME)) { + if (sma1307->dapm_aif_out1 != val) { + change = true; + sma1307->dapm_aif_out1 = val; + } else + change = false; + } else { + dev_err(sma1307->dev, "%s: Invalid Control ID - %s\n", + __func__, kcontrol->id.name); + return -EINVAL; + } + + snd_soc_dapm_put_enum_double(kcontrol, ucontrol); + + return change; +} + +static int sma1307_dapm_sdo_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + + ucontrol->value.integer.value[0] = (long)sma1307->dapm_sdo_en; + snd_soc_dapm_put_volsw(kcontrol, ucontrol); + + return 0; +} + +static int sma1307_dapm_sdo_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct sma1307_priv *sma1307 = + snd_soc_component_get_drvdata(dapm->component); + int val = (int)ucontrol->value.integer.value[0]; + bool change; + + if ((val < 0) || (val > 1)) { + dev_err(sma1307->dev, "%s: Out of range\n", __func__); + return -EINVAL; + } + + if (sma1307->dapm_sdo_en != val) { + change = true; + sma1307->dapm_sdo_en = val; + } else + change = false; + + snd_soc_dapm_put_volsw(kcontrol, ucontrol); + + return change; +} + +static const struct snd_kcontrol_new sma1307_aif_in_source_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SMA1307_AIF_IN_NAME, + .info = snd_soc_info_enum_double, + .get = sma1307_dapm_aif_in_get, + .put = sma1307_dapm_aif_in_put, + .private_value = (unsigned long)&sma1307_aif_in_source_enum +}; + +static const struct snd_kcontrol_new sma1307_sdo_setting_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SDO Setting", + .info = snd_soc_info_enum_double, + .get = sma1307_dapm_sdo_setting_get, + .put = sma1307_dapm_sdo_setting_put, + .private_value = (unsigned long)&sma1307_sdo_setting_enum +}; + +static const struct snd_kcontrol_new sma1307_aif_out0_source_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SMA1307_AIF_OUT0_NAME, + .info = snd_soc_info_enum_double, + .get = sma1307_dapm_aif_out_get, + .put = sma1307_dapm_aif_out_put, + .private_value = (unsigned long)&sma1307_aif_out_source_enum +}; + +static const struct snd_kcontrol_new sma1307_aif_out1_source_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SMA1307_AIF_OUT1_NAME, + .info = snd_soc_info_enum_double, + .get = sma1307_dapm_aif_out_get, + .put = sma1307_dapm_aif_out_put, + .private_value = (unsigned long)&sma1307_aif_out_source_enum +}; + +static const struct snd_kcontrol_new sma1307_sdo_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Switch", + .info = snd_soc_info_volsw, + .get = sma1307_dapm_sdo_enable_get, + .put = sma1307_dapm_sdo_enable_put, + .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, 0, 1, 0, 0) +}; + +static const struct snd_kcontrol_new sma1307_enable_control = + SOC_DAPM_SINGLE("Switch", SMA1307_00_SYSTEM_CTRL, 0, 1, 0); + +static const struct snd_kcontrol_new sma1307_binary_mode_control[] = { + SOC_ENUM_EXT("Binary Mode", sma1307_binary_mode_enum, + snd_soc_get_enum_double, sma1307_binary_mode_put), +}; + +static const struct snd_kcontrol_new sma1307_snd_controls[] = { + SOC_SINGLE_TLV(SMA1307_VOL_CTRL_NAME, SMA1307_0A_SPK_VOL, + 0, 167, 1, sma1307_spk_tlv), + SOC_ENUM_EXT(SMA1307_TDM_RX0_POS_NAME, sma1307_tdm_slot_enum, + sma1307_tdm_slot_get, sma1307_tdm_slot_put), + SOC_ENUM_EXT(SMA1307_TDM_RX1_POS_NAME, sma1307_tdm_slot_enum, + sma1307_tdm_slot_get, sma1307_tdm_slot_put), + SOC_ENUM_EXT(SMA1307_TDM_TX0_POS_NAME, sma1307_tdm_slot_enum, + sma1307_tdm_slot_get, sma1307_tdm_slot_put), + SOC_ENUM_EXT(SMA1307_TDM_TX1_POS_NAME, sma1307_tdm_slot_enum, + sma1307_tdm_slot_get, sma1307_tdm_slot_put), + SOC_ENUM_EXT(SMA1307_RESET_CTRL_NAME, sma1307_reset_enum, + snd_soc_get_enum_double, sma1307_reset_put), + SOC_SINGLE_BOOL_EXT(SMA1307_FORCE_MUTE_CTRL_NAME, 0, + sma1307_force_mute_get, sma1307_force_mute_put), + SOC_SINGLE_BOOL_EXT(SMA1307_OT1_SW_PROT_CTRL_NAME, 0, + sma1307_sw_ot1_prot_get, sma1307_sw_ot1_prot_put), + SOC_SINGLE_BOOL_EXT(SMA1307_CHECK_FAULT_STATUS_NAME, 0, + sma1307_check_fault_status_get, + sma1307_check_fault_status_put), + SOC_SINGLE_EXT(SMA1307_CHECK_FAULT_PERIOD_NAME, SND_SOC_NOPM, 0, 600, 0, + sma1307_check_fault_period_get, + sma1307_check_fault_period_put), +}; + +static const struct snd_soc_dapm_widget sma1307_dapm_widgets[] = { + /* platform domain */ + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_INPUT("SDO"), + + /* path domain */ + SND_SOC_DAPM_MUX_E(SMA1307_AIF_IN_NAME, SND_SOC_NOPM, 0, 0, + &sma1307_aif_in_source_control, + sma1307_aif_in_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("SDO Setting", SND_SOC_NOPM, 0, 0, + &sma1307_sdo_setting_control, + sma1307_sdo_setting_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MUX_E(SMA1307_AIF_OUT0_NAME, SND_SOC_NOPM, 0, 0, + &sma1307_aif_out0_source_control, + sma1307_aif_out_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_MUX_E(SMA1307_AIF_OUT1_NAME, SND_SOC_NOPM, 0, 0, + &sma1307_aif_out1_source_control, + sma1307_aif_out_event, + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SWITCH_E("SDO Enable", SND_SOC_NOPM, 0, 0, + &sma1307_sdo_control, + sma1307_sdo_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("Entry", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV_E("AMP Power", SND_SOC_NOPM, 0, 0, NULL, 0, + sma1307_power_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("AMP Enable", SND_SOC_NOPM, 0, 0, + &sma1307_enable_control), + + /* stream domain */ + SND_SOC_DAPM_AIF_IN("AIF IN", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF OUT", "Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route sma1307_audio_map[] = { + /* Playback */ + { "AIF IN Source", "Mono", "AIF IN" }, + { "AIF IN Source", "Left", "AIF IN" }, + { "AIF IN Source", "Right", "AIF IN" }, + + { "SDO Enable", "Switch", "AIF IN" }, + + { "SDO Setting", "Data_One_48k", "SDO Enable" }, + { "SDO Setting", "Data_Two_48k", "SDO Enable" }, + { "SDO Setting", "Data_Two_24k", "SDO Enable" }, + { "SDO Setting", "Clk_PLL", "SDO Enable" }, + { "SDO Setting", "Clk_OSC", "SDO Enable" }, + + { "AIF OUT0 Source", "Disable", "SDO Setting" }, + { "AIF OUT0 Source", "After_FmtC", "SDO Setting" }, + { "AIF OUT0 Source", "After_Mixer", "SDO Setting" }, + { "AIF OUT0 Source", "After_DSP", "SDO Setting" }, + { "AIF OUT0 Source", "Vrms2_Avg", "SDO Setting" }, + { "AIF OUT0 Source", "Battery", "SDO Setting" }, + { "AIF OUT0 Source", "Temperature", "SDO Setting" }, + { "AIF OUT0 Source", "After_Delay", "SDO Setting" }, + + { "AIF OUT1 Source", "Disable", "SDO Setting" }, + { "AIF OUT1 Source", "After_FmtC", "SDO Setting" }, + { "AIF OUT1 Source", "After_Mixer", "SDO Setting" }, + { "AIF OUT1 Source", "After_DSP", "SDO Setting" }, + { "AIF OUT1 Source", "Vrms2_Avg", "SDO Setting" }, + { "AIF OUT1 Source", "Battery", "SDO Setting" }, + { "AIF OUT1 Source", "Temperature", "SDO Setting" }, + { "AIF OUT1 Source", "After_Delay", "SDO Setting" }, + + { "Entry", NULL, "AIF OUT0 Source" }, + { "Entry", NULL, "AIF OUT1 Source" }, + { "Entry", NULL, "AIF IN Source" }, + + { "AMP Power", NULL, "Entry" }, + + { "AMP Enable", "Switch", "AMP Power" }, + { "SPK", NULL, "AMP Enable" }, + + /* Capture */ + { "AIF OUT", NULL, "AMP Enable" }, +}; + +static void sma1307_setup_pll(struct snd_soc_component *component, + unsigned int bclk) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + int i = 0; + + dev_dbg(component->dev, "%s: BCLK = %dHz\n", __func__, bclk); + + if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_MCLK) { + dev_warn(component->dev, "%s: MCLK is not supported\n", + __func__); + } else if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_BCLK) { + for (i = 0; i < sma1307->num_of_pll_matches; i++) { + if (sma1307->pll_matches[i].input_clk == bclk) + break; + } + if (i == sma1307->num_of_pll_matches) { + dev_warn(component->dev, + "%s: No matching value between pll table and SCK\n", + __func__); + return; + } + + regmap_update_bits(sma1307->regmap, + SMA1307_A2_TOP_MAN1, + SMA1307_PLL_MASK, SMA1307_PLL_ON); + } + + regmap_write(sma1307->regmap, SMA1307_8B_PLL_POST_N, + sma1307->pll_matches[i].post_n); + regmap_write(sma1307->regmap, SMA1307_8C_PLL_N, + sma1307->pll_matches[i].n); + regmap_write(sma1307->regmap, SMA1307_8D_PLL_A_SETTING, + sma1307->pll_matches[i].vco); + regmap_write(sma1307->regmap, SMA1307_8E_PLL_P_CP, + sma1307->pll_matches[i].p_cp); +} + +static int sma1307_dai_hw_params_amp(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int bclk = 0; + + if (sma1307->format == SND_SOC_DAIFMT_DSP_A) + bclk = params_rate(params) * sma1307->frame_size; + else + bclk = params_rate(params) * params_physical_width(params) + * params_channels(params); + + dev_dbg(component->dev, + "%s: rate = %d : bit size = %d : channel = %d\n", + __func__, params_rate(params), params_width(params), + params_channels(params)); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (sma1307->sys_clk_id == SMA1307_PLL_CLKIN_BCLK) { + if (sma1307->last_bclk != bclk) { + sma1307_setup_pll(component, bclk); + sma1307->last_bclk = bclk; + } + } + + switch (params_rate(params)) { + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 44100: + case 48000: + break; + + case 96000: + dev_warn(component->dev, + "%s: %d rate not support SDO\n", __func__, + params_rate(params)); + break; + + default: + dev_err(component->dev, "%s: not support rate : %d\n", + __func__, params_rate(params)); + + return -EINVAL; + } + + /* substream->stream is SNDRV_PCM_STREAM_CAPTURE */ + } else { + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_SCK_RATE_MASK + | + SMA1307_DATA_WIDTH_MASK, + SMA1307_SCK_32FS | + SMA1307_DATA_16BIT); + break; + + case SNDRV_PCM_FORMAT_S24_LE: + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_SCK_RATE_MASK + | + SMA1307_DATA_WIDTH_MASK, + SMA1307_SCK_64FS | + SMA1307_DATA_24BIT); + break; + + case SNDRV_PCM_FORMAT_S32_LE: + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_SCK_RATE_MASK + | + SMA1307_DATA_WIDTH_MASK, + SMA1307_SCK_64FS | + SMA1307_DATA_24BIT); + break; + default: + dev_err(component->dev, + "%s: not support data bit : %d\n", __func__, + params_format(params)); + return -EINVAL; + } + } + + switch (sma1307->format) { + case SND_SOC_DAIFMT_I2S: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, + SMA1307_STANDARD_I2S); + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_INTERFACE_MASK, + SMA1307_I2S_FORMAT); + break; + case SND_SOC_DAIFMT_LEFT_J: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, SMA1307_LJ); + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_INTERFACE_MASK, + SMA1307_LJ_FORMAT); + break; + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_width(params)) { + case 16: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, + SMA1307_RJ_16BIT); + break; + case 24: + case 32: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, + SMA1307_RJ_24BIT); + break; + } + break; + case SND_SOC_DAIFMT_DSP_A: + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_I2S_MODE_MASK, + SMA1307_STANDARD_I2S); + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_INTERFACE_MASK, + SMA1307_TDM_FORMAT); + break; + } + + switch (params_width(params)) { + case 16: + case 24: + case 32: + break; + default: + dev_err(component->dev, + "%s: not support data bit : %d\n", __func__, + params_format(params)); + return -EINVAL; + } + + return 0; +} + +static int sma1307_dai_set_sysclk_amp(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + switch (clk_id) { + case SMA1307_EXTERNAL_CLOCK_19_2: + case SMA1307_EXTERNAL_CLOCK_24_576: + case SMA1307_PLL_CLKIN_MCLK: + case SMA1307_PLL_CLKIN_BCLK: + break; + default: + dev_err(component->dev, "%s: Invalid clk id: %d\n", + __func__, clk_id); + return -EINVAL; + } + sma1307->sys_clk_id = clk_id; + + return 0; +} + +static int sma1307_dai_set_fmt_amp(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + + case SND_SOC_DAIFMT_CBC_CFC: + dev_dbg(component->dev, + "%s: %s\n", __func__, "I2S/TDM Device mode"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_CONTROLLER_DEVICE_MASK, + SMA1307_DEVICE_MODE); + break; + + case SND_SOC_DAIFMT_CBP_CFP: + dev_dbg(component->dev, + "%s: %s\n", __func__, "I2S/TDM Controller mode"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_CONTROLLER_DEVICE_MASK, + SMA1307_CONTROLLER_MODE); + break; + + default: + dev_err(component->dev, + "%s: Unsupported Controller/Device : 0x%x\n", + __func__, fmt); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + sma1307->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + dev_err(component->dev, + "%s: Unsupported Audio Interface Format : 0x%x\n", + __func__, fmt); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + + case SND_SOC_DAIFMT_IB_NF: + dev_dbg(component->dev, "%s: %s\n", + __func__, "Invert BCLK + Normal Frame"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_SCK_RISING_MASK, + SMA1307_SCK_RISING_EDGE); + break; + case SND_SOC_DAIFMT_IB_IF: + dev_dbg(component->dev, "%s: %s\n", + __func__, "Invert BCLK + Invert Frame"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_LEFTPOL_MASK + | SMA1307_SCK_RISING_MASK, + SMA1307_HIGH_FIRST_CH + | SMA1307_SCK_RISING_EDGE); + break; + case SND_SOC_DAIFMT_NB_IF: + dev_dbg(component->dev, "%s: %s\n", + __func__, "Normal BCLK + Invert Frame"); + regmap_update_bits(sma1307->regmap, + SMA1307_01_INPUT_CTRL1, + SMA1307_LEFTPOL_MASK, + SMA1307_HIGH_FIRST_CH); + break; + case SND_SOC_DAIFMT_NB_NF: + dev_dbg(component->dev, "%s: %s\n", + __func__, "Normal BCLK + Normal Frame"); + break; + default: + dev_err(component->dev, + "%s: Unsupported Bit & Frameclock : 0x%x\n", + __func__, fmt); + return -EINVAL; + } + + return 0; +} + +static int sma1307_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + dev_dbg(component->dev, "%s: slots = %d, slot_width - %d\n", + __func__, slots, slot_width); + + sma1307->frame_size = slot_width * slots; + + regmap_update_bits(sma1307->regmap, + SMA1307_A4_TOP_MAN3, + SMA1307_INTERFACE_MASK, SMA1307_TDM_FORMAT); + + regmap_update_bits(sma1307->regmap, + SMA1307_A5_TDM1, + SMA1307_TDM_TX_MODE_MASK, + SMA1307_TDM_TX_MONO); + + switch (slot_width) { + case 16: + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_DL_MASK, + SMA1307_TDM_DL_16); + break; + case 32: + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_DL_MASK, + SMA1307_TDM_DL_32); + break; + default: + dev_err(component->dev, "%s: not support TDM %d slot_width\n", + __func__, slot_width); + return -EINVAL; + } + + switch (slots) { + case 4: + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_N_SLOT_MASK, + SMA1307_TDM_N_SLOT_4); + break; + case 8: + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_N_SLOT_MASK, + SMA1307_TDM_N_SLOT_8); + break; + default: + dev_err(component->dev, "%s: not support TDM %d slots\n", + __func__, slots); + return -EINVAL; + } + + if (sma1307->tdm_slot0_rx < slots) + regmap_update_bits(sma1307->regmap, + SMA1307_A5_TDM1, + SMA1307_TDM_SLOT0_RX_POS_MASK, + sma1307->tdm_slot0_rx << 3); + else + dev_err(component->dev, "%s: Incorrect tdm-slot0-rx %d set\n", + __func__, sma1307->tdm_slot0_rx); + + if (sma1307->tdm_slot1_rx < slots) + regmap_update_bits(sma1307->regmap, + SMA1307_A5_TDM1, + SMA1307_TDM_SLOT1_RX_POS_MASK, + sma1307->tdm_slot1_rx); + else + dev_err(component->dev, "%s: Incorrect tdm-slot1-rx %d set\n", + __func__, sma1307->tdm_slot1_rx); + + if (sma1307->tdm_slot0_tx < slots) + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_SLOT0_TX_POS_MASK, + sma1307->tdm_slot0_tx << 3); + else + dev_err(component->dev, "%s: Incorrect tdm-slot0-tx %d set\n", + __func__, sma1307->tdm_slot0_tx); + + if (sma1307->tdm_slot1_tx < slots) + regmap_update_bits(sma1307->regmap, + SMA1307_A6_TDM2, + SMA1307_TDM_SLOT1_TX_POS_MASK, + sma1307->tdm_slot1_tx); + else + dev_err(component->dev, "%s: Incorrect tdm-slot1-tx %d set\n", + __func__, sma1307->tdm_slot1_tx); + + return 0; +} + +static int sma1307_dai_mute_stream(struct snd_soc_dai *dai, int mute, + int stream) +{ + struct snd_soc_component *component = dai->component; + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + + if (stream == SNDRV_PCM_STREAM_CAPTURE) + return 0; + if (mute) { + dev_dbg(component->dev, "%s: %s\n", __func__, "MUTE"); + regmap_update_bits(sma1307->regmap, + SMA1307_0E_MUTE_VOL_CTRL, + SMA1307_SPK_MUTE_MASK, + SMA1307_SPK_MUTE); + } else { + if (!sma1307->force_mute_status) { + dev_dbg(component->dev, "%s: %s\n", __func__, + "UNMUTE"); + regmap_update_bits(sma1307->regmap, + SMA1307_0E_MUTE_VOL_CTRL, + SMA1307_SPK_MUTE_MASK, + SMA1307_SPK_UNMUTE); + } else { + dev_dbg(sma1307->dev, "%s: FORCE MUTE!!!\n", __func__); + } + } + + return 0; +} + +static const struct snd_soc_dai_ops sma1307_dai_ops_amp = { + .hw_params = sma1307_dai_hw_params_amp, + .set_fmt = sma1307_dai_set_fmt_amp, + .set_sysclk = sma1307_dai_set_sysclk_amp, + .set_tdm_slot = sma1307_dai_set_tdm_slot, + .mute_stream = sma1307_dai_mute_stream, +}; + +#define SMA1307_RATES_PLAYBACK SNDRV_PCM_RATE_8000_96000 +#define SMA1307_RATES_CAPTURE SNDRV_PCM_RATE_8000_48000 +#define SMA1307_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver sma1307_dai[] = { + { + .name = "sma1307-amplifier", + .id = 0, + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SMA1307_RATES_PLAYBACK, + .formats = SMA1307_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SMA1307_RATES_CAPTURE, + .formats = SMA1307_FORMATS, + }, + .ops = &sma1307_dai_ops_amp, + }, +}; + +static void sma1307_check_fault_worker(struct work_struct *work) +{ + struct sma1307_priv *sma1307 = + container_of(work, struct sma1307_priv, check_fault_work.work); + unsigned int status1_val, status2_val; + char *envp[3] = { NULL, NULL, NULL }; + + if (sma1307->tsdw_cnt) + regmap_read(sma1307->regmap, + SMA1307_0A_SPK_VOL, &sma1307->cur_vol); + else + regmap_read(sma1307->regmap, + SMA1307_0A_SPK_VOL, &sma1307->init_vol); + + regmap_read(sma1307->regmap, SMA1307_FA_STATUS1, &status1_val); + regmap_read(sma1307->regmap, SMA1307_FB_STATUS2, &status2_val); + + if (~status1_val & SMA1307_OT1_OK_STATUS) { + dev_crit(sma1307->dev, + "%s: OT1(Over Temperature Level 1)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT1"); + if (sma1307->sw_ot1_prot) { + /* Volume control (Current Volume -3dB) */ + if ((sma1307->cur_vol + 6) <= 0xFA) { + sma1307->cur_vol += 6; + regmap_write(sma1307->regmap, + SMA1307_0A_SPK_VOL, + sma1307->cur_vol); + envp[1] = kasprintf(GFP_KERNEL, + "VOLUME=0x%02X", sma1307->cur_vol); + } + } + sma1307->tsdw_cnt++; + } else if (sma1307->tsdw_cnt) { + regmap_write(sma1307->regmap, + SMA1307_0A_SPK_VOL, sma1307->init_vol); + sma1307->tsdw_cnt = 0; + sma1307->cur_vol = sma1307->init_vol; + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT1_CLEAR"); + envp[1] = kasprintf(GFP_KERNEL, + "VOLUME=0x%02X", sma1307->cur_vol); + } + + if (~status1_val & SMA1307_OT2_OK_STATUS) { + dev_crit(sma1307->dev, + "%s: OT2(Over Temperature Level 2)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OT2"); + } + if (status1_val & SMA1307_UVLO_STATUS) { + dev_crit(sma1307->dev, + "%s: UVLO(Under Voltage Lock Out)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=UVLO"); + } + if (status1_val & SMA1307_OVP_BST_STATUS) { + dev_crit(sma1307->dev, + "%s: OVP_BST(Over Voltage Protection)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OVP_BST"); + } + if (status2_val & SMA1307_OCP_SPK_STATUS) { + dev_crit(sma1307->dev, + "%s: OCP_SPK(Over Current Protect SPK)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OCP_SPK"); + } + if (status2_val & SMA1307_OCP_BST_STATUS) { + dev_crit(sma1307->dev, + "%s: OCP_BST(Over Current Protect Boost)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=OCP_BST"); + } + if (status2_val & SMA1307_CLK_MON_STATUS) { + dev_crit(sma1307->dev, + "%s: CLK_FAULT(No clock input)\n", __func__); + envp[0] = kasprintf(GFP_KERNEL, "STATUS=CLK_FAULT"); + } + + if (envp[0] != NULL) { + if (kobject_uevent_env(sma1307->kobj, KOBJ_CHANGE, envp)) + dev_err(sma1307->dev, + "%s: Error sending uevent\n", __func__); + kfree(envp[0]); + kfree(envp[1]); + } + + if (sma1307->check_fault_status) { + if (sma1307->check_fault_period > 0) + queue_delayed_work(system_freezable_wq, + &sma1307->check_fault_work, + sma1307->check_fault_period * HZ); + else + queue_delayed_work(system_freezable_wq, + &sma1307->check_fault_work, + CHECK_PERIOD_TIME * HZ); + } +} + +static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file) +{ + const struct firmware *fw; + int *data, size, offset, num_mode; + int ret; + + ret = request_firmware(&fw, file, sma1307->dev); + + if (ret) { + dev_err(sma1307->dev, "%s: failed to read \"%s\": %pe\n", + __func__, setting_file, ERR_PTR(ret)); + sma1307->set.status = false; + return; + } else if ((fw->size) < SMA1307_SETTING_HEADER_SIZE) { + dev_err(sma1307->dev, "%s: Invalid file\n", __func__); + release_firmware(fw); + sma1307->set.status = false; + return; + } + + data = kzalloc(fw->size, GFP_KERNEL); + size = fw->size >> 2; + memcpy(data, fw->data, fw->size); + + release_firmware(fw); + + /* HEADER */ + sma1307->set.header_size = SMA1307_SETTING_HEADER_SIZE; + sma1307->set.checksum = data[sma1307->set.header_size - 2]; + sma1307->set.num_mode = data[sma1307->set.header_size - 1]; + num_mode = sma1307->set.num_mode; + sma1307->set.header = devm_kzalloc(sma1307->dev, + sma1307->set.header_size, + GFP_KERNEL); + memcpy(sma1307->set.header, data, + sma1307->set.header_size * sizeof(int)); + + if ((sma1307->set.checksum >> 8) != SMA1307_SETTING_CHECKSUM) { + dev_err(sma1307->dev, "%s: failed by dismatch \"%s\"\n", + __func__, setting_file); + sma1307->set.status = false; + return; + } + + /* DEFAULT */ + sma1307->set.def_size = SMA1307_SETTING_DEFAULT_SIZE; + sma1307->set.def + = devm_kzalloc(sma1307->dev, + sma1307->set.def_size * sizeof(int), GFP_KERNEL); + memcpy(sma1307->set.def, + &data[sma1307->set.header_size], + sma1307->set.def_size * sizeof(int)); + + /* MODE */ + offset = sma1307->set.header_size + sma1307->set.def_size; + sma1307->set.mode_size = DIV_ROUND_CLOSEST(size - offset, num_mode + 1); + for (int i = 0; i < num_mode; i++) { + sma1307->set.mode_set[i] + = devm_kzalloc(sma1307->dev, + sma1307->set.mode_size * 2 * sizeof(int), + GFP_KERNEL); + for (int j = 0; j < sma1307->set.mode_size; j++) { + sma1307->set.mode_set[i][2 * j] + = data[offset + ((num_mode + 1) * j)]; + sma1307->set.mode_set[i][2 * j + 1] + = data[offset + ((num_mode + 1) * j + i + 1)]; + } + } + + kfree(data); + sma1307->set.status = true; + +} + +static void sma1307_reset(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + unsigned int status = 0; + + regmap_read(sma1307->regmap, SMA1307_FF_DEVICE_INDEX, &status); + + sma1307->rev_num = status & SMA1307_REV_NUM_STATUS; + dev_dbg(component->dev, "%s: SMA1307 Revision %d\n", + __func__, sma1307->rev_num); + regmap_read(sma1307->regmap, SMA1307_99_OTP_TRM2, &sma1307->otp_trm2); + regmap_read(sma1307->regmap, SMA1307_9A_OTP_TRM3, &sma1307->otp_trm3); + + if ((sma1307->otp_trm2 & SMA1307_OTP_STAT_MASK) != SMA1307_OTP_STAT_1) + dev_warn(component->dev, "%s: SMA1307 OTP Status Fail\n", + __func__); + + /* Register Initial Value Setting */ + sma1307_setting_loaded(sma1307, setting_file); + if (sma1307->set.status) + sma1307_set_binary(component); + else + sma1307_set_default(component); + + regmap_update_bits(sma1307->regmap, + SMA1307_93_INT_CTRL, + SMA1307_DIS_INT_MASK, SMA1307_HIGH_Z_INT); + regmap_write(sma1307->regmap, SMA1307_0A_SPK_VOL, sma1307->init_vol); +} + +static void sma1307_set_binary(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + int i = 0, mode = 0; + + for (i = 0; i < (sma1307->set.def_size); i++) { + if (sma1307_writeable_register(sma1307->dev, i) + && ((i < SMA1307_97_OTP_TRM0) + || (i > SMA1307_9A_OTP_TRM3))) { + regmap_write(sma1307->regmap, i, sma1307->set.def[i]); + + } + } + for (i = 0; i < (sma1307->set.mode_size); i++) { + if (sma1307_writeable_register(sma1307->dev, i) + && ((i < SMA1307_97_OTP_TRM0) + || (i > SMA1307_9A_OTP_TRM3))) { + mode = sma1307->binary_mode; + regmap_write(sma1307->regmap, + sma1307->set.mode_set[mode][2 * i], + sma1307->set.mode_set[mode][2 * i + + 1]); + } + } +} + +static void sma1307_set_default(struct snd_soc_component *component) +{ + struct sma1307_priv *sma1307 = snd_soc_component_get_drvdata(component); + int i = 0; + + for (i = 0; i < (unsigned int)ARRAY_SIZE(sma1307_reg_def); i++) + regmap_write(sma1307->regmap, + sma1307_reg_def[i].reg, + sma1307_reg_def[i].def); + + if (!strcmp(sma1307->name, DEVICE_NAME_SMA1307AQ)) + sma1307->data->init(sma1307->regmap); +} + +static int sma1307_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + + snd_soc_dapm_sync(dapm); + + sma1307_amp_component = component; + + snd_soc_add_component_controls(component, sma1307_binary_mode_control, + ARRAY_SIZE(sma1307_binary_mode_control)); + sma1307_reset(component); + + return 0; +} + +static const struct snd_soc_component_driver sma1307_component = { + .probe = sma1307_probe, + .controls = sma1307_snd_controls, + .num_controls = ARRAY_SIZE(sma1307_snd_controls), + .dapm_widgets = sma1307_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sma1307_dapm_widgets), + .dapm_routes = sma1307_audio_map, + .num_dapm_routes = ARRAY_SIZE(sma1307_audio_map), +}; + +static const struct regmap_config sma_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = SMA1307_FF_DEVICE_INDEX, + .readable_reg = sma1307_readable_register, + .writeable_reg = sma1307_writeable_register, + .volatile_reg = sma1307_volatile_register, + + .reg_defaults = sma1307_reg_def, + .num_reg_defaults = ARRAY_SIZE(sma1307_reg_def), +}; + +static void sma1307aq_init(struct regmap *regmap) +{ + /* Guidelines for driving 4ohm load */ + /* Brown Out Protection */ + regmap_write(regmap, SMA1307_02_BROWN_OUT_PROT1, 0x62); + regmap_write(regmap, SMA1307_03_BROWN_OUT_PROT2, 0x5D); + regmap_write(regmap, SMA1307_04_BROWN_OUT_PROT3, 0x57); + regmap_write(regmap, SMA1307_05_BROWN_OUT_PROT8, 0x54); + regmap_write(regmap, SMA1307_06_BROWN_OUT_PROT9, 0x51); + regmap_write(regmap, + SMA1307_07_BROWN_OUT_PROT10, 0x4D); + regmap_write(regmap, + SMA1307_08_BROWN_OUT_PROT11, 0x4B); + regmap_write(regmap, SMA1307_27_BROWN_OUT_PROT4, 0x3C); + regmap_write(regmap, SMA1307_28_BROWN_OUT_PROT5, 0x5B); + regmap_write(regmap, + SMA1307_29_BROWN_OUT_PROT12, 0x78); + regmap_write(regmap, + SMA1307_2A_BROWN_OUT_PROT13, 0x96); + regmap_write(regmap, + SMA1307_2B_BROWN_OUT_PROT14, 0xB4); + regmap_write(regmap, + SMA1307_2C_BROWN_OUT_PROT15, 0xD3); + /* FDPEC Gain */ + regmap_write(regmap, SMA1307_35_FDPEC_CTRL0, 0x16); + /* FLT Vdd */ + regmap_write(regmap, SMA1307_92_FDPEC_CTRL1, 0xA0); + /* Boost Max */ + regmap_write(regmap, SMA1307_AB_BOOST_CTRL4, 0x0F); +} + +static const struct sma1307_data sma1307aq_data = { + .name = DEVICE_NAME_SMA1307AQ, + .init = sma1307aq_init, +}; + +static int sma1307_i2c_probe(struct i2c_client *client) +{ + struct sma1307_priv *sma1307; + const struct sma1307_data *data; + int ret = 0; + unsigned int device_info; + + sma1307 = devm_kzalloc(&client->dev, + sizeof(*sma1307), GFP_KERNEL); + if (!sma1307) + return -ENOMEM; + + sma1307->regmap = devm_regmap_init_i2c(client, &sma_i2c_regmap); + if (IS_ERR(sma1307->regmap)) { + return dev_err_probe(&client->dev, PTR_ERR(sma1307->regmap), + "%s: failed to allocate register map\n", __func__); + } + + data = device_get_match_data(&client->dev); + if (!data) + return -ENODEV; + + sma1307->data = data; + + /* set initial value as normal AMP IC status */ + sma1307->name = client->name; + sma1307->format = SND_SOC_DAIFMT_I2S; + sma1307->sys_clk_id = SMA1307_PLL_CLKIN_BCLK; + sma1307->num_of_pll_matches = ARRAY_SIZE(sma1307_pll_matches); + + sma1307->check_fault_period = CHECK_PERIOD_TIME; + sma1307->check_fault_status = true; + sma1307->init_vol = 0x32; + sma1307->cur_vol = sma1307->init_vol; + sma1307->sw_ot1_prot = true; + + mutex_init(&sma1307->default_lock); + + INIT_DELAYED_WORK(&sma1307->check_fault_work, + sma1307_check_fault_worker); + + sma1307->dev = &client->dev; + sma1307->kobj = &client->dev.kobj; + + i2c_set_clientdata(client, sma1307); + + sma1307->pll_matches = sma1307_pll_matches; + + regmap_read(sma1307->regmap, + SMA1307_FF_DEVICE_INDEX, &device_info); + + if ((device_info & 0xF8) != SMA1307_DEVICE_ID) { + dev_err(&client->dev, + "%s: device initialization error (0x%02X)", + __func__, device_info); + return -ENODEV; + } + dev_dbg(&client->dev, "%s: chip version 0x%02X\n", + __func__, device_info); + + i2c_set_clientdata(client, sma1307); + + ret = devm_snd_soc_register_component(&client->dev, + &sma1307_component, sma1307_dai, + 1); + + if (ret) { + dev_err(&client->dev, "%s: failed to register component\n", + __func__); + + return ret; + } + + return ret; +} + +static void sma1307_i2c_remove(struct i2c_client *client) +{ + struct sma1307_priv *sma1307 = + (struct sma1307_priv *)i2c_get_clientdata(client); + + cancel_delayed_work_sync(&sma1307->check_fault_work); +} + +static const struct i2c_device_id sma1307_i2c_id[] = { + { "sma1307a", 0 }, + { "sma1307aq", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, sma1307_i2c_id); + +static const struct of_device_id sma1307_of_match[] = { + { + .compatible = "irondevice,sma1307a", + }, + { + .compatible = "irondevice,sma1307aq", + .data = &sma1307aq_data //AEC-Q100 Qualificated + }, + { } +}; + +MODULE_DEVICE_TABLE(of, sma1307_of_match); + +static struct i2c_driver sma1307_i2c_driver = { + .driver = { + .name = "sma1307", + .of_match_table = sma1307_of_match, + }, + .probe = sma1307_i2c_probe, + .remove = sma1307_i2c_remove, + .id_table = sma1307_i2c_id, +}; + +module_i2c_driver(sma1307_i2c_driver); + +MODULE_DESCRIPTION("ALSA SoC SMA1307 driver"); +MODULE_AUTHOR("Gyuhwa Park, "); +MODULE_AUTHOR("KS Jo, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/sma1307.h b/sound/soc/codecs/sma1307.h new file mode 100644 index 00000000000000..44aab52a32f9b1 --- /dev/null +++ b/sound/soc/codecs/sma1307.h @@ -0,0 +1,444 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * sma1307.h -- sma1307 ALSA SoC Audio driver + * + * Copyright 2024 Iron Device Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _SMA1307_H +#define _SMA1307_H + +#include + +enum sma1307_fault { + SMA1307_FAULT_OT1, + SMA1307_FAULT_OT2, + SMA1307_FAULT_UVLO, + SMA1307_FAULT_OVP_BST, + SMA1307_FAULT_OCP_SPK, + SMA1307_FAULT_OCP_BST, + SMA1307_FAULT_CLK +}; + +enum sma1307_mode { + SMA1307_MONO_MODE, + SMA1307_LEFT_MODE, + SMA1307_RIGHT_MODE, +}; + +enum sma1307_sdo_mode { + SMA1307_OUT_DATA_ONE_48K, + SMA1307_OUT_DATA_TWO_48K, + SMA1307_OUT_DATA_TWO_24K, + SMA1307_OUT_CLK_PLL, + SMA1307_OUT_CLK_OSC +}; + +enum sma1307_sdo_source { + SMA1307_OUT_DISABLE, + SMA1307_OUT_FORMAT_C, + SMA1307_OUT_MIXER_OUT, + SMA1307_OUT_AFTER_DSP, + SMA1307_OUT_VRMS2_AVG, + SMA1307_OUT_BATTERY, + SMA1307_OUT_TEMP, + SMA1307_OUT_AFTER_DELAY +}; + +struct sma1307_setting_file { + bool status; + char *header; + int *def; + int *mode_set[5]; + int checksum; + int num_mode; + size_t header_size; + size_t def_size; + size_t mode_size; +}; + +#define SMA1307_I2C_ADDR_00 0x1e +#define SMA1307_I2C_ADDR_01 0x3e +#define SMA1307_I2C_ADDR_10 0x5e +#define SMA1307_I2C_ADDR_11 0x7e + +#define DEVICE_NAME_SMA1307A "sma1307a" +#define DEVICE_NAME_SMA1307AQ "sma1307aq" + +#define SMA1307_EXTERNAL_CLOCK_19_2 0x00 +#define SMA1307_EXTERNAL_CLOCK_24_576 0x01 +#define SMA1307_PLL_CLKIN_MCLK 0x02 +#define SMA1307_PLL_CLKIN_BCLK 0x03 + +#define SMA1307_OFFSET_DEFAULT_MODE 0x00 +#define SMA1307_OFFSET_BURNING_MODE 0x01 + +#define SMA1307_SETTING_HEADER_SIZE 0x08 +#define SMA1307_SETTING_DEFAULT_SIZE 0xC0 + +#define SMA1307_DEFAULT_SET 0x00 +#define SMA1307_BINARY_FILE_SET 0x01 + +/* Controls Name */ +#define SMA1307_REG_CTRL_NAME "Register Byte Control" +#define SMA1307_VOL_CTRL_NAME "Speaker Volume" +#define SMA1307_FORCE_MUTE_CTRL_NAME "Force Mute Switch" +#define SMA1307_TDM_RX0_POS_NAME "TDM RX Slot0 Position" +#define SMA1307_TDM_RX1_POS_NAME "TDM RX Slot1 Position" +#define SMA1307_TDM_TX0_POS_NAME "TDM TX Slot0 Position" +#define SMA1307_TDM_TX1_POS_NAME "TDM TX Slot1 Position" +#define SMA1307_OT1_SW_PROT_CTRL_NAME "OT1 SW Protection Switch" +#define SMA1307_RESET_CTRL_NAME "Reset Switch" +#define SMA1307_CHECK_FAULT_STATUS_NAME "Check Fault Status" +#define SMA1307_CHECK_FAULT_PERIOD_NAME "Check Fault Period" + +/* DAPM Name */ +#define SMA1307_AIF_IN_NAME "AIF IN Source" +#define SMA1307_AIF_OUT0_NAME "AIF OUT0 Source" +#define SMA1307_AIF_OUT1_NAME "AIF OUT1 Source" + +/* + * SMA1307 Register Definition + */ + +/* SMA1307 Register Addresses */ +#define SMA1307_00_SYSTEM_CTRL 0x00 +#define SMA1307_01_INPUT_CTRL1 0x01 +#define SMA1307_02_BROWN_OUT_PROT1 0x02 +#define SMA1307_03_BROWN_OUT_PROT2 0x03 +#define SMA1307_04_BROWN_OUT_PROT3 0x04 +#define SMA1307_05_BROWN_OUT_PROT8 0x05 +#define SMA1307_06_BROWN_OUT_PROT9 0x06 +#define SMA1307_07_BROWN_OUT_PROT10 0x07 +#define SMA1307_08_BROWN_OUT_PROT11 0x08 +#define SMA1307_09_OUTPUT_CTRL 0x09 +#define SMA1307_0A_SPK_VOL 0x0A +#define SMA1307_0B_BST_TEST 0x0B +#define SMA1307_0C_BOOST_CTRL8 0x0C +#define SMA1307_0D_SPK_TEST 0x0D +#define SMA1307_0E_MUTE_VOL_CTRL 0x0E +#define SMA1307_0F_VBAT_TEMP_SENSING 0x0F + +#define SMA1307_10_SYSTEM_CTRL1 0x10 +#define SMA1307_11_SYSTEM_CTRL2 0x11 +#define SMA1307_12_SYSTEM_CTRL3 0x12 +#define SMA1307_13_DELAY 0x13 +#define SMA1307_14_MODULATOR 0x14 +#define SMA1307_15_BASS_SPK1 0x15 +#define SMA1307_16_BASS_SPK2 0x16 +#define SMA1307_17_BASS_SPK3 0x17 +#define SMA1307_18_BASS_SPK4 0x18 +#define SMA1307_19_BASS_SPK5 0x19 +#define SMA1307_1A_BASS_SPK6 0x1A +#define SMA1307_1B_BASS_SPK7 0x1B +#define SMA1307_1C_BROWN_OUT_PROT20 0x1C +#define SMA1307_1D_BROWN_OUT_PROT0 0x1D +#define SMA1307_1E_TONE_GENERATOR 0x1E +#define SMA1307_1F_TONE_FINE_VOLUME 0x1F + +#define SMA1307_22_COMP_HYS_SEL 0x22 +#define SMA1307_23_COMPLIM1 0x23 +#define SMA1307_24_COMPLIM2 0x24 +#define SMA1307_25_COMPLIM3 0x25 +#define SMA1307_26_COMPLIM4 0x26 +#define SMA1307_27_BROWN_OUT_PROT4 0x27 +#define SMA1307_28_BROWN_OUT_PROT5 0x28 +#define SMA1307_29_BROWN_OUT_PROT12 0x29 +#define SMA1307_2A_BROWN_OUT_PROT13 0x2A +#define SMA1307_2B_BROWN_OUT_PROT14 0x2B +#define SMA1307_2C_BROWN_OUT_PROT15 0x2C +#define SMA1307_2D_BROWN_OUT_PROT6 0x2D +#define SMA1307_2E_BROWN_OUT_PROT7 0x2E +#define SMA1307_2F_BROWN_OUT_PROT16 0x2F + +#define SMA1307_30_BROWN_OUT_PROT17 0x30 +#define SMA1307_31_BROWN_OUT_PROT18 0x31 +#define SMA1307_32_BROWN_OUT_PROT19 0x32 +#define SMA1307_34_OCP_SPK 0x34 +#define SMA1307_35_FDPEC_CTRL0 0x35 +#define SMA1307_36_PROTECTION 0x36 +#define SMA1307_37_SLOPECTRL 0x37 +#define SMA1307_38_POWER_METER 0x38 +#define SMA1307_39_PMT_NZ_VAL 0x39 +#define SMA1307_3B_TEST1 0x3B +#define SMA1307_3C_TEST2 0x3C +#define SMA1307_3D_TEST3 0x3D +#define SMA1307_3E_IDLE_MODE_CTRL 0x3E +#define SMA1307_3F_ATEST2 0x3F +#define SMA1307_8B_PLL_POST_N 0x8B +#define SMA1307_8C_PLL_N 0x8C +#define SMA1307_8D_PLL_A_SETTING 0x8D +#define SMA1307_8E_PLL_P_CP 0x8E +#define SMA1307_8F_ANALOG_TEST 0x8F + +#define SMA1307_90_CRESTLIM1 0x90 +#define SMA1307_91_CRESTLIM2 0x91 +#define SMA1307_92_FDPEC_CTRL1 0x92 +#define SMA1307_93_INT_CTRL 0x93 +#define SMA1307_94_BOOST_CTRL9 0x94 +#define SMA1307_95_BOOST_CTRL10 0x95 +#define SMA1307_96_BOOST_CTRL11 0x96 +#define SMA1307_97_OTP_TRM0 0x97 +#define SMA1307_98_OTP_TRM1 0x98 +#define SMA1307_99_OTP_TRM2 0x99 +#define SMA1307_9A_OTP_TRM3 0x9A + +#define SMA1307_A0_PAD_CTRL0 0xA0 +#define SMA1307_A1_PAD_CTRL1 0xA1 +#define SMA1307_A2_TOP_MAN1 0xA2 +#define SMA1307_A3_TOP_MAN2 0xA3 +#define SMA1307_A4_TOP_MAN3 0xA4 +#define SMA1307_A5_TDM1 0xA5 +#define SMA1307_A6_TDM2 0xA6 +#define SMA1307_A7_CLK_MON 0xA7 +#define SMA1307_A8_BOOST_CTRL1 0xA8 +#define SMA1307_A9_BOOST_CTRL2 0xA9 +#define SMA1307_AA_BOOST_CTRL3 0xAA +#define SMA1307_AB_BOOST_CTRL4 0xAB +#define SMA1307_AC_BOOST_CTRL5 0xAC +#define SMA1307_AD_BOOST_CTRL6 0xAD +#define SMA1307_AE_BOOST_CTRL7 0xAE +#define SMA1307_AF_LPF 0xAF + +#define SMA1307_B0_RMS_TC1 0xB0 +#define SMA1307_B1_RMS_TC2 0xB1 +#define SMA1307_B2_AVG_TC1 0xB2 +#define SMA1307_B3_AVG_TC2 0xB3 +#define SMA1307_B4_PRVALUE1 0xB4 +#define SMA1307_B5_PRVALUE2 0xB5 +#define SMA1307_B8_SPK_NG_CTRL1 0xB8 +#define SMA1307_B9_SPK_NG_CTRL2 0xB9 +#define SMA1307_BA_DGC1 0xBA +#define SMA1307_BB_DGC2 0xBB +#define SMA1307_BC_DGC3 0xBC +#define SMA1307_BD_MCBS_CTRL1 0xBD +#define SMA1307_BE_MCBS_CTRL2 0xBE + +/* Status Register Read Only */ +#define SMA1307_F5_READY_FOR_V_SAR 0xF5 +#define SMA1307_F7_READY_FOR_T_SAR 0xF7 +#define SMA1307_F8_STATUS_T1 0xF8 +#define SMA1307_F9_STATUS_T2 0xF9 +#define SMA1307_FA_STATUS1 0xFA +#define SMA1307_FB_STATUS2 0xFB +#define SMA1307_FC_STATUS3 0xFC +#define SMA1307_FD_STATUS4 0xFD +#define SMA1307_FE_STATUS5 0xFE +#define SMA1307_FF_DEVICE_INDEX 0xFF + +/* SMA1307 Registers Bit Fields */ +/* Power On/Off */ +#define SMA1307_POWER_MASK BIT(0) +#define SMA1307_POWER_OFF 0 +#define SMA1307_POWER_ON BIT(0) + +/* Reset */ +#define SMA1307_RESET_MASK BIT(1) +#define SMA1307_RESET_ON BIT(1) + +/* Left Polarity */ +#define SMA1307_LEFTPOL_MASK BIT(3) +#define SMA1307_LOW_FIRST_CH 0 +#define SMA1307_HIGH_FIRST_CH BIT(3) + +/* SCK Falling/Rising */ +#define SMA1307_SCK_RISING_MASK BIT(2) +#define SMA1307_SCK_FALLING_EDGE 0 +#define SMA1307_SCK_RISING_EDGE BIT(2) + +/* SPK Mute */ +#define SMA1307_SPK_MUTE_MASK BIT(0) +#define SMA1307_SPK_UNMUTE 0 +#define SMA1307_SPK_MUTE BIT(0) + +/* SPK Mode */ +#define SMA1307_SPK_MODE_MASK (BIT(2)|BIT(3)|BIT(4)) +#define SMA1307_SPK_OFF 0 +#define SMA1307_SPK_MONO BIT(2) +#define SMA1307_SPK_STEREO BIT(4) + +/* Mono Mix */ +#define SMA1307_MONOMIX_MASK BIT(0) +#define SMA1307_MONOMIX_OFF 0 +#define SMA1307_MONOMIX_ON BIT(0) + +/* LR Data Swap */ +#define SMA1307_LR_DATA_SW_MASK BIT(4) +#define SMA1307_LR_DATA_SW_NORMAL 0 +#define SMA1307_LR_DATA_SW_SWAP BIT(4) + +/* PLL On/Off */ +#define SMA1307_PLL_MASK BIT(6) +#define SMA1307_PLL_ON 0 +#define SMA1307_PLL_OFF BIT(6) + +/* Input Format */ +#define SMA1307_I2S_MODE_MASK (BIT(4)|BIT(5)|BIT(6)) +#define SMA1307_STANDARD_I2S 0 +#define SMA1307_LJ BIT(4) +#define SMA1307_RJ_16BIT BIT(6) +#define SMA1307_RJ_18BIT (BIT(4)|BIT(6)) +#define SMA1307_RJ_20BIT (BIT(5)|BIT(6)) +#define SMA1307_RJ_24BIT (BIT(4)|BIT(5)|BIT(6)) + +/* Controller / Device Setting */ +#define SMA1307_CONTROLLER_DEVICE_MASK BIT(7) +#define SMA1307_DEVICE_MODE 0 +#define SMA1307_CONTROLLER_MODE BIT(7) + +/* Port Config */ +#define SMA1307_PORT_CONFIG_MASK (BIT(6)|BIT(7)) +#define SMA1307_INPUT_PORT_ONLY 0 +#define SMA1307_OUTPUT_PORT_ENABLE BIT(7) + +/* SDO Output */ +#define SMA1307_SDO_OUTPUT_MASK BIT(3) +#define SMA1307_LOGIC_OUTPUT 0 +#define SMA1307_HIGH_Z_OUTPUT BIT(3) + +#define SMA1307_DATA_CLK_SEL_MASK (BIT(6)|BIT(7)) +#define SMA1307_SDO_DATA 0 +#define SMA1307_SDO_CLK_PLL BIT(6) +#define SMA1307_SDO_CLK_OSC (BIT(6)|BIT(7)) + +/* SDO Output2 */ +#define SMA1307_SDO_OUTPUT2_MASK BIT(0) +#define SMA1307_ONE_SDO_PER_CH 0 +#define SMA1307_TWO_SDO_PER_CH BIT(0) + +/* SDO Output3 */ +#define SMA1307_SDO_OUTPUT3_MASK BIT(2) +#define SMA1307_SDO_OUTPUT3_DIS 0 +#define SMA1307_TWO_SDO_PER_CH_24K BIT(2) + +/* SDO OUT1 Select*/ +#define SMA1307_SDO_OUT1_SEL_MASK (BIT(3)|BIT(4)|BIT(5)) +#define SMA1307_SDO1_DISABLE 0 +#define SMA1307_SDO1_FORMAT_C BIT(3) +#define SMA1307_SDO1_MONO_MIX BIT(4) +#define SMA1307_SDO1_AFTER_DSP (BIT(3)|BIT(4)) +#define SMA1307_SDO1_VRMS2_AVG BIT(5) +#define SMA1307_SDO1_VBAT_MON (BIT(3)|BIT(5)) +#define SMA1307_SDO1_TEMP_MON (BIT(4)|BIT(5)) +#define SMA1307_SDO1_AFTER_DELAY (BIT(3)|BIT(4)|BIT(5)) + +/* SDO OUT0 Select*/ +#define SMA1307_SDO_OUT0_SEL_MASK (BIT(0)|BIT(1)|BIT(2)) +#define SMA1307_SDO0_DISABLE 0 +#define SMA1307_SDO0_FORMAT_C BIT(0) +#define SMA1307_SDO0_MONO_MIX BIT(1) +#define SMA1307_SDO0_AFTER_DSP (BIT(0)|BIT(1)) +#define SMA1307_SDO0_VRMS2_AVG BIT(2) +#define SMA1307_SDO0_VBAT_MON (BIT(0)|BIT(2)) +#define SMA1307_SDO0_TEMP_MON (BIT(1)|BIT(2)) +#define SMA1307_SDO0_AFTER_DELAY (BIT(0)|BIT(1)|BIT(2)) + +/* INTERRUPT Operation */ +#define SMA1307_SEL_INT_MASK BIT(2) +#define SMA1307_INT_CLEAR_AUTO 0 +#define SMA1307_INT_CLEAR_MANUAL BIT(2) + +/* INTERRUPT CLEAR */ +#define SMA1307_CLR_INT_MASK BIT(1) +#define SMA1307_INT_READY 0 +#define SMA1307_INT_CLEAR BIT(1) + +/* INTERRUPT Disable */ +#define SMA1307_DIS_INT_MASK BIT(0) +#define SMA1307_NORMAL_INT 0 +#define SMA1307_HIGH_Z_INT BIT(0) + +/* Interface Control */ +#define SMA1307_INTERFACE_MASK (BIT(5)|BIT(6)|BIT(7)) +#define SMA1307_LJ_FORMAT BIT(5) +#define SMA1307_I2S_FORMAT (BIT(5)|BIT(6)) +#define SMA1307_TDM_FORMAT BIT(7) + +#define SMA1307_SCK_RATE_MASK (BIT(3)|BIT(4)) +#define SMA1307_SCK_64FS 0 +#define SMA1307_SCK_32FS BIT(4) + +#define SMA1307_DATA_WIDTH_MASK (BIT(1)|BIT(2)) +#define SMA1307_DATA_24BIT 0 +#define SMA1307_DATA_16BIT (BIT(1)|BIT(2)) + +#define SMA1307_TDM_TX_MODE_MASK BIT(6) +#define SMA1307_TDM_TX_MONO 0 +#define SMA1307_TDM_TX_STEREO BIT(6) + +#define SMA1307_TDM_SLOT0_RX_POS_MASK (BIT(3)|BIT(4)|BIT(5)) +#define SMA1307_TDM_SLOT0_RX_POS_0 0 +#define SMA1307_TDM_SLOT0_RX_POS_1 BIT(3) +#define SMA1307_TDM_SLOT0_RX_POS_2 BIT(4) +#define SMA1307_TDM_SLOT0_RX_POS_3 (BIT(3)|BIT(4)) +#define SMA1307_TDM_SLOT0_RX_POS_4 BIT(5) +#define SMA1307_TDM_SLOT0_RX_POS_5 (BIT(3)|BIT(5)) +#define SMA1307_TDM_SLOT0_RX_POS_6 (BIT(4)|BIT(5)) +#define SMA1307_TDM_SLOT0_RX_POS_7 (BIT(3)|BIT(4)|BIT(5)) + +#define SMA1307_TDM_SLOT1_RX_POS_MASK (BIT(0)|BIT(1)|BIT(2)) +#define SMA1307_TDM_SLOT1_RX_POS_0 0 +#define SMA1307_TDM_SLOT1_RX_POS_1 BIT(0) +#define SMA1307_TDM_SLOT1_RX_POS_2 BIT(1) +#define SMA1307_TDM_SLOT1_RX_POS_3 (BIT(0)|BIT(1)) +#define SMA1307_TDM_SLOT1_RX_POS_4 BIT(2) +#define SMA1307_TDM_SLOT1_RX_POS_5 (BIT(0)|BIT(2)) +#define SMA1307_TDM_SLOT1_RX_POS_6 (BIT(1)|BIT(2)) +#define SMA1307_TDM_SLOT1_RX_POS_7 (BIT(0)|BIT(1)|BIT(2)) + +/* TDM2 FORMAT : 0xA6 */ +#define SMA1307_TDM_DL_MASK BIT(7) +#define SMA1307_TDM_DL_16 0 +#define SMA1307_TDM_DL_32 BIT(7) + +#define SMA1307_TDM_N_SLOT_MASK BIT(6) +#define SMA1307_TDM_N_SLOT_4 0 +#define SMA1307_TDM_N_SLOT_8 BIT(6) + +#define SMA1307_TDM_SLOT0_TX_POS_MASK (BIT(3)|BIT(4)|BIT(5)) +#define SMA1307_TDM_SLOT0_TX_POS_0 0 +#define SMA1307_TDM_SLOT0_TX_POS_1 BIT(3) +#define SMA1307_TDM_SLOT0_TX_POS_2 BIT(4) +#define SMA1307_TDM_SLOT0_TX_POS_3 (BIT(3)|BIT(4)) +#define SMA1307_TDM_SLOT0_TX_POS_4 BIT(5) +#define SMA1307_TDM_SLOT0_TX_POS_5 (BIT(3)|BIT(5)) +#define SMA1307_TDM_SLOT0_TX_POS_6 (BIT(4)|BIT(5)) +#define SMA1307_TDM_SLOT0_TX_POS_7 (BIT(3)|BIT(4)|BIT(5)) + +#define SMA1307_TDM_SLOT1_TX_POS_MASK (BIT(0)|BIT(1)|BIT(2)) +#define SMA1307_TDM_SLOT1_TX_POS_0 0 +#define SMA1307_TDM_SLOT1_TX_POS_1 BIT(0) +#define SMA1307_TDM_SLOT1_TX_POS_2 BIT(1) +#define SMA1307_TDM_SLOT1_TX_POS_3 (BIT(0)|BIT(1)) +#define SMA1307_TDM_SLOT1_TX_POS_4 BIT(2) +#define SMA1307_TDM_SLOT1_TX_POS_5 (BIT(0)|BIT(2)) +#define SMA1307_TDM_SLOT1_TX_POS_6 (BIT(1)|BIT(2)) +#define SMA1307_TDM_SLOT1_TX_POS_7 (BIT(0)|BIT(1)|BIT(2)) + +/* OTP STATUS */ +#define SMA1307_OTP_STAT_MASK BIT(6) +#define SMA1307_OTP_STAT_0 0 +#define SMA1307_OTP_STAT_1 BIT(6) + +/* STATUS */ +#define SMA1307_OT1_OK_STATUS BIT(7) +#define SMA1307_OT2_OK_STATUS BIT(6) +#define SMA1307_UVLO_STATUS BIT(5) +#define SMA1307_OVP_BST_STATUS BIT(4) +#define SMA1307_POWER_FLAG BIT(3) + +#define SMA1307_SCAN_CHK BIT(7) +#define SMA1307_OCP_SPK_STATUS BIT(5) +#define SMA1307_OCP_BST_STATUS BIT(4) +#define SMA1307_BOP_STATE (BIT(1)|BIT(2)|BIT(3)) +#define SMA1307_CLK_MON_STATUS BIT(0) + +#define SMA1307_DEVICE_ID (BIT(3)|BIT(4)) +#define SMA1307_REV_NUM_STATUS (BIT(0)|BIT(1)) +#define SMA1307_REV_NUM_REV0 0 +#define SMA1307_REV_NUM_REV1 BIT(0) + +#endif diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c index 310123d2bb5fb9..c9766979b1d7e2 100644 --- a/sound/soc/codecs/spdif_receiver.c +++ b/sound/soc/codecs/spdif_receiver.c @@ -36,7 +36,7 @@ static const struct snd_soc_dapm_route dir_routes[] = { SNDRV_PCM_FMTBIT_S32_LE | \ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) -static struct snd_soc_component_driver soc_codec_spdif_dir = { +static const struct snd_soc_component_driver soc_codec_spdif_dir = { .dapm_widgets = dir_widgets, .num_dapm_widgets = ARRAY_SIZE(dir_widgets), .dapm_routes = dir_routes, diff --git a/sound/soc/codecs/spdif_transmitter.c b/sound/soc/codecs/spdif_transmitter.c index db51a46e689dff..2409fd834f8427 100644 --- a/sound/soc/codecs/spdif_transmitter.c +++ b/sound/soc/codecs/spdif_transmitter.c @@ -36,7 +36,7 @@ static const struct snd_soc_dapm_route dit_routes[] = { { "spdif-out", NULL, "Playback" }, }; -static struct snd_soc_component_driver soc_codec_spdif_dit = { +static const struct snd_soc_component_driver soc_codec_spdif_dit = { .dapm_widgets = dit_widgets, .num_dapm_widgets = ARRAY_SIZE(dit_widgets), .dapm_routes = dit_routes, diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 0aeb88abbf52f1..61d9c220b6a4c0 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -374,7 +374,7 @@ int tasdevice_rca_parser(void *context, const struct firmware *fmw) out: return ret; } -EXPORT_SYMBOL_NS_GPL(tasdevice_rca_parser, SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tasdevice_rca_parser, "SND_SOC_TAS2781_FMWLIB"); /* fixed m68k compiling issue: mapping table can save code field */ static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw, @@ -862,7 +862,7 @@ void tasdevice_select_cfg_blk(void *pContext, int conf_no, __func__, length, blk_data[j]->block_size); } } -EXPORT_SYMBOL_NS_GPL(tasdevice_select_cfg_blk, SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tasdevice_select_cfg_blk, "SND_SOC_TAS2781_FMWLIB"); static int tasdevice_load_block_kernel( struct tasdevice_priv *tasdevice, struct tasdev_blk *block) @@ -1943,7 +1943,7 @@ int tas2781_load_calibration(void *context, char *file_name, return ret; } -EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, "SND_SOC_TAS2781_FMWLIB"); static int tasdevice_dspfw_ready(const struct firmware *fmw, void *context) @@ -2051,7 +2051,7 @@ int tasdevice_dsp_parser(void *context) out: return ret; } -EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, "SND_SOC_TAS2781_FMWLIB"); static void tas2781_clear_calfirmware(struct tasdevice_fw *tas_fmw) { @@ -2104,7 +2104,7 @@ void tasdevice_calbin_remove(void *context) tasdev->cali_data_fmw = NULL; } } -EXPORT_SYMBOL_NS_GPL(tasdevice_calbin_remove, SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tasdevice_calbin_remove, "SND_SOC_TAS2781_FMWLIB"); void tasdevice_config_info_remove(void *context) { @@ -2131,7 +2131,7 @@ void tasdevice_config_info_remove(void *context) } kfree(ci); } -EXPORT_SYMBOL_NS_GPL(tasdevice_config_info_remove, SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tasdevice_config_info_remove, "SND_SOC_TAS2781_FMWLIB"); static int tasdevice_load_data(struct tasdevice_priv *tas_priv, struct tasdevice_data *dev_data) @@ -2311,8 +2311,7 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no, out: return prog_status; } -EXPORT_SYMBOL_NS_GPL(tasdevice_select_tuningprm_cfg, - SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tasdevice_select_tuningprm_cfg, "SND_SOC_TAS2781_FMWLIB"); int tasdevice_prmg_load(void *context, int prm_no) { @@ -2357,7 +2356,7 @@ int tasdevice_prmg_load(void *context, int prm_no) out: return prog_status; } -EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, "SND_SOC_TAS2781_FMWLIB"); void tasdevice_tuning_switch(void *context, int state) { @@ -2393,8 +2392,7 @@ void tasdevice_tuning_switch(void *context, int state) TASDEVICE_BIN_BLK_PRE_SHUTDOWN); } } -EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch, - SND_SOC_TAS2781_FMWLIB); +EXPORT_SYMBOL_NS_GPL(tasdevice_tuning_switch, "SND_SOC_TAS2781_FMWLIB"); MODULE_DESCRIPTION("Texas Firmware Support"); MODULE_AUTHOR("Shenghao Ding, TI, "); diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 12d093437ba9b6..fb8cd2284fe85c 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -370,7 +370,7 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i, tasdevice_dev_read(tas_priv, i, p[j].reg, (int *)&p[j].val[0]); } else { - switch (p[j].reg) { + switch (tas2781_cali_start_reg[j].reg) { case 0: { if (!reg[0]) continue; @@ -650,7 +650,6 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; unsigned int reg; - int rc = -1; if (tas_priv->chip_id == TAS2781) reg = TAS2781_RUNTIME_RE_REG_TF; @@ -659,9 +658,7 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol, guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; - rc = calib_data_get(tas_priv, reg, &dst[1]); - - return rc; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_re_data_get(struct snd_kcontrol *kcontrol, @@ -673,7 +670,6 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; unsigned int reg; - int rc = -1; if (tas_priv->chip_id == TAS2781) reg = TAS2781_RUNTIME_RE_REG; @@ -681,9 +677,7 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol, reg = TAS2563_RUNTIME_RE_REG; guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; - rc = calib_data_get(tas_priv, reg, &dst[1]); - - return rc; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol, @@ -696,7 +690,6 @@ static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; unsigned int reg; - int rc = -1; guard(mutex)(&tas_priv->codec_lock); @@ -707,9 +700,7 @@ static int tasdev_r0_data_get(struct snd_kcontrol *kcontrol, else return -1; dst[0] = bytes_ext->max; - rc = calib_data_get(tas_priv, reg, &dst[1]); - - return rc; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol, @@ -721,13 +712,10 @@ static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; unsigned int reg = TASDEVICE_XM_A1_REG; - int rc = -1; guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; - rc = calib_data_get(tas_priv, reg, &dst[1]); - - return rc; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol, @@ -739,13 +727,10 @@ static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol, (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; unsigned int reg = TASDEVICE_XM_A2_REG; - int rc = -1; guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; - rc = calib_data_get(tas_priv, reg, &dst[1]); - - return rc; + return calib_data_get(tas_priv, reg, &dst[1]); } static int tasdev_nop_get( @@ -1115,14 +1100,12 @@ static int tasdevice_active_num_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec); int dev_id = ucontrol->value.integer.value[0]; - int max = tas_priv->ndev - 1, rc; + int max = tas_priv->ndev - 1; dev_id = clamp(dev_id, 0, max); guard(mutex)(&tas_priv->codec_lock); - rc = tasdev_chn_switch(tas_priv, dev_id); - - return rc; + return tasdev_chn_switch(tas_priv, dev_id); } static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv) @@ -1339,10 +1322,8 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) i++; } - rc = snd_soc_add_component_controls(priv->codec, cali_ctrls, + return snd_soc_add_component_controls(priv->codec, cali_ctrls, nctrls < i ? nctrls : i); - - return rc; } static void tasdevice_fw_ready(const struct firmware *fmw, @@ -1765,4 +1746,4 @@ MODULE_AUTHOR("Shenghao Ding "); MODULE_AUTHOR("Kevin Lu "); MODULE_DESCRIPTION("ASoC TAS2781 Driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_TAS2781_FMWLIB); +MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB"); diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c index 3b53eba38a0b1d..4c32500eef3ec2 100644 --- a/sound/soc/codecs/tas5805m.c +++ b/sound/soc/codecs/tas5805m.c @@ -474,7 +474,7 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c) return ret; } - tas5805m = devm_kzalloc(dev, sizeof(struct tas5805m_priv), GFP_KERNEL); + tas5805m = devm_kzalloc(dev, sizeof(*tas5805m), GFP_KERNEL); if (!tas5805m) return -ENOMEM; diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index bb0500e9d3eacf..9be054837f68eb 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -364,7 +364,7 @@ static int tas6424_set_bias_level(struct snd_soc_component *component, return 0; } -static struct snd_soc_component_driver soc_codec_dev_tas6424 = { +static const struct snd_soc_component_driver soc_codec_dev_tas6424 = { .set_bias_level = tas6424_set_bias_level, .controls = tas6424_snd_controls, .num_controls = ARRAY_SIZE(tas6424_snd_controls), diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index 7073b9d1cda845..868e8a91e05b38 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -961,7 +961,7 @@ static int adc3xxx_gpio_request(struct gpio_chip *chip, unsigned int offset) if (offset >= ADC3XXX_GPIOS_MAX) return -EINVAL; - if (offset >= 0 && offset < ADC3XXX_GPIO_PINS) { + if (offset < ADC3XXX_GPIO_PINS) { /* GPIO1 is offset 0, GPIO2 is offset 1 */ /* We check here that the GPIO pins are either not configured * in the DT, or that they purposely are set as outputs. diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 9c50ac356c8955..e3782762139f6a 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -555,7 +555,7 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control = * On unmute: restore the register content from the reg_cache * Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R */ -#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \ +#define TWL4030_OUTPUT_PGA(pin_name, reg) \ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ struct snd_kcontrol *kcontrol, int event) \ { \ @@ -575,11 +575,11 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ return 0; \ } -TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL, TWL4030_EAR_GAIN); -TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL, TWL4030_PREDL_GAIN); -TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN); -TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN); -TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN); +TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL); +TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL); +TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL); +TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL); +TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL); static void handsfree_ramp(struct snd_soc_component *component, int reg, int ramp) { diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c new file mode 100644 index 00000000000000..3d49a786994851 --- /dev/null +++ b/sound/soc/codecs/uda1342.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// uda1342.c -- UDA1342 ALSA SoC Codec driver +// Based on the WM87xx drivers by Liam Girdwood and Richard Purdie +// +// Copyright 2007 Dension Audio Systems Ltd. +// Copyright 2024 Loongson Technology Co.,Ltd. +// +// Modifications by Christian Pellegrin +// Further cleanup and restructuring by: +// Binbin Zhou + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uda1342.h" + +#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) + +struct uda1342_priv { + int sysclk; + int dai_fmt; + + struct snd_pcm_substream *provider_substream; + struct snd_pcm_substream *consumer_substream; + + struct regmap *regmap; + struct i2c_client *i2c; +}; + +static const struct reg_default uda1342_reg_defaults[] = { + { 0x00, 0x1042 }, + { 0x01, 0x0000 }, + { 0x10, 0x0088 }, + { 0x11, 0x0000 }, + { 0x12, 0x0000 }, + { 0x20, 0x0080 }, + { 0x21, 0x0080 }, +}; + +static int uda1342_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + struct snd_soc_component *component = dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + unsigned int mask; + unsigned int val = 0; + + /* Master mute */ + mask = BIT(5); + if (mute) + val = mask; + + return regmap_update_bits(uda1342->regmap, 0x10, mask, val); +} + +static int uda1342_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + struct snd_pcm_runtime *provider_runtime; + + if (uda1342->provider_substream) { + provider_runtime = uda1342->provider_substream->runtime; + + snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, provider_runtime->rate); + snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + provider_runtime->sample_bits); + + uda1342->consumer_substream = substream; + } else { + uda1342->provider_substream = substream; + } + + return 0; +} + +static void uda1342_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + + if (uda1342->provider_substream == substream) + uda1342->provider_substream = uda1342->consumer_substream; + + uda1342->consumer_substream = NULL; +} + +static int uda1342_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + struct device *dev = &uda1342->i2c->dev; + unsigned int hw_params = 0; + + if (substream == uda1342->consumer_substream) + return 0; + + /* set SYSCLK / fs ratio */ + switch (uda1342->sysclk / params_rate(params)) { + case 512: + break; + case 384: + hw_params |= BIT(4); + break; + case 256: + hw_params |= BIT(5); + break; + default: + dev_err(dev, "unsupported frequency\n"); + return -EINVAL; + } + + /* set DAI format and word length */ + switch (uda1342->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_width(params)) { + case 16: + hw_params |= BIT(1); + break; + case 18: + hw_params |= BIT(2); + break; + case 20: + hw_params |= BIT(2) | BIT(1); + break; + default: + dev_err(dev, "unsupported format (right)\n"); + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_LEFT_J: + hw_params |= BIT(3); + break; + default: + dev_err(dev, "unsupported format\n"); + return -EINVAL; + } + + return regmap_update_bits(uda1342->regmap, 0x0, + STATUS0_DAIFMT_MASK | STATUS0_SYSCLK_MASK, hw_params); +} + +static int uda1342_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = codec_dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + struct device *dev = &uda1342->i2c->dev; + + /* + * Anything between 256fs*8Khz and 512fs*48Khz should be acceptable + * because the codec is slave. Of course limitations of the clock + * master (the IIS controller) apply. + * We'll error out on set_hw_params if it's not OK + */ + if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { + uda1342->sysclk = freq; + return 0; + } + + dev_err(dev, "unsupported sysclk\n"); + + return -EINVAL; +} + +static int uda1342_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_component *component = codec_dai->component; + struct uda1342_priv *uda1342 = snd_soc_component_get_drvdata(component); + + /* codec supports only full consumer mode */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_BC_FC) { + dev_err(&uda1342->i2c->dev, "unsupported consumer mode.\n"); + return -EINVAL; + } + + /* We can't setup DAI format here as it depends on the word bit num */ + /* so let's just store the value for later */ + uda1342->dai_fmt = fmt; + + return 0; +} + +static const struct snd_kcontrol_new uda1342_snd_controls[] = { + SOC_SINGLE("Master Playback Volume", 0x11, 0, 0x3F, 1), + SOC_SINGLE("Analog1 Volume", 0x12, 0, 0x1F, 1), +}; + +/* Common DAPM widgets */ +static const struct snd_soc_dapm_widget uda1342_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("VINL1"), + SND_SOC_DAPM_INPUT("VINR1"), + SND_SOC_DAPM_INPUT("VINL2"), + SND_SOC_DAPM_INPUT("VINR2"), + + SND_SOC_DAPM_DAC("DAC", "Playback", 0, 1, 0), + SND_SOC_DAPM_ADC("ADC", "Capture", 0, 9, 0), + + SND_SOC_DAPM_OUTPUT("VOUTL"), + SND_SOC_DAPM_OUTPUT("VOUTR"), +}; + +static const struct snd_soc_dapm_route uda1342_dapm_routes[] = { + { "ADC", NULL, "VINL1" }, + { "ADC", NULL, "VINR1" }, + { "ADC", NULL, "VINL2" }, + { "ADC", NULL, "VINR2" }, + { "VOUTL", NULL, "DAC" }, + { "VOUTR", NULL, "DAC" }, +}; + +static const struct snd_soc_dai_ops uda1342_dai_ops = { + .startup = uda1342_startup, + .shutdown = uda1342_shutdown, + .hw_params = uda1342_hw_params, + .mute_stream = uda1342_mute, + .set_sysclk = uda1342_set_dai_sysclk, + .set_fmt = uda1342_set_dai_fmt, +}; + +static struct snd_soc_dai_driver uda1342_dai = { + .name = "uda1342-hifi", + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = UDA134X_FORMATS, + }, + /* capture capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = UDA134X_FORMATS, + }, + /* pcm operations */ + .ops = &uda1342_dai_ops, +}; + +static const struct snd_soc_component_driver soc_component_dev_uda1342 = { + .controls = uda1342_snd_controls, + .num_controls = ARRAY_SIZE(uda1342_snd_controls), + .dapm_widgets = uda1342_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(uda1342_dapm_widgets), + .dapm_routes = uda1342_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(uda1342_dapm_routes), + .suspend_bias_off = 1, + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct regmap_config uda1342_regmap = { + .reg_bits = 8, + .val_bits = 16, + .max_register = 0x21, + .reg_defaults = uda1342_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(uda1342_reg_defaults), + .cache_type = REGCACHE_MAPLE, +}; + +static int uda1342_i2c_probe(struct i2c_client *i2c) +{ + struct uda1342_priv *uda1342; + + uda1342 = devm_kzalloc(&i2c->dev, sizeof(*uda1342), GFP_KERNEL); + if (!uda1342) + return -ENOMEM; + + uda1342->regmap = devm_regmap_init_i2c(i2c, &uda1342_regmap); + if (IS_ERR(uda1342->regmap)) + return PTR_ERR(uda1342->regmap); + + i2c_set_clientdata(i2c, uda1342); + uda1342->i2c = i2c; + + return devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_uda1342, + &uda1342_dai, 1); +} + +static int uda1342_suspend(struct device *dev) +{ + struct uda1342_priv *uda1342 = dev_get_drvdata(dev); + + regcache_cache_only(uda1342->regmap, true); + + return 0; +} + +static int uda1342_resume(struct device *dev) +{ + struct uda1342_priv *uda1342 = dev_get_drvdata(dev); + + regcache_mark_dirty(uda1342->regmap); + regcache_sync(uda1342->regmap); + + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(uda1342_pm_ops, + uda1342_suspend, uda1342_resume, NULL); + +static const struct i2c_device_id uda1342_i2c_id[] = { + { "uda1342", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, uda1342_i2c_id); + +static const struct of_device_id uda1342_of_match[] = { + { .compatible = "nxp,uda1342" }, + { } +}; +MODULE_DEVICE_TABLE(of, uda1342_of_match); + +static struct i2c_driver uda1342_i2c_driver = { + .driver = { + .name = "uda1342", + .of_match_table = uda1342_of_match, + .pm = pm_sleep_ptr(&uda1342_pm_ops), + }, + .probe = uda1342_i2c_probe, + .id_table = uda1342_i2c_id, +}; +module_i2c_driver(uda1342_i2c_driver); + +MODULE_DESCRIPTION("UDA1342 ALSA soc codec driver"); +MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); +MODULE_AUTHOR("Binbin Zhou "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda1342.h b/sound/soc/codecs/uda1342.h new file mode 100644 index 00000000000000..ff6aea0a8b016e --- /dev/null +++ b/sound/soc/codecs/uda1342.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Audio support for NXP UDA1342 + * + * Copyright (c) 2005 Giorgio Padrin + * Copyright (c) 2024 Binbin Zhou + */ + +#ifndef _UDA1342_H +#define _UDA1342_H + +#define UDA1342_CLK 0x00 +#define UDA1342_IFACE 0x01 +#define UDA1342_PM 0x02 +#define UDA1342_AMIX 0x03 +#define UDA1342_HP 0x04 +#define UDA1342_MVOL 0x11 +#define UDA1342_MIXVOL 0x12 +#define UDA1342_MODE 0x12 +#define UDA1342_DEEMP 0x13 +#define UDA1342_MIXER 0x14 +#define UDA1342_INTSTAT 0x18 +#define UDA1342_DEC 0x20 +#define UDA1342_PGA 0x21 +#define UDA1342_ADC 0x22 +#define UDA1342_AGC 0x23 +#define UDA1342_DECSTAT 0x28 +#define UDA1342_RESET 0x7f + +/* Register flags */ +#define R00_EN_ADC 0x0800 +#define R00_EN_DEC 0x0400 +#define R00_EN_DAC 0x0200 +#define R00_EN_INT 0x0100 +#define R00_DAC_CLK 0x0010 +#define R01_SFORI_I2S 0x0000 +#define R01_SFORI_LSB16 0x0100 +#define R01_SFORI_LSB18 0x0200 +#define R01_SFORI_LSB20 0x0300 +#define R01_SFORI_MSB 0x0500 +#define R01_SFORI_MASK 0x0700 +#define R01_SFORO_I2S 0x0000 +#define R01_SFORO_LSB16 0x0001 +#define R01_SFORO_LSB18 0x0002 +#define R01_SFORO_LSB20 0x0003 +#define R01_SFORO_LSB24 0x0004 +#define R01_SFORO_MSB 0x0005 +#define R01_SFORO_MASK 0x0007 +#define R01_SEL_SOURCE 0x0040 +#define R01_SIM 0x0010 +#define R02_PON_PLL 0x8000 +#define R02_PON_HP 0x2000 +#define R02_PON_DAC 0x0400 +#define R02_PON_BIAS 0x0100 +#define R02_EN_AVC 0x0080 +#define R02_PON_AVC 0x0040 +#define R02_PON_LNA 0x0010 +#define R02_PON_PGAL 0x0008 +#define R02_PON_ADCL 0x0004 +#define R02_PON_PGAR 0x0002 +#define R02_PON_ADCR 0x0001 +#define R13_MTM 0x4000 +#define R14_SILENCE 0x0080 +#define R14_SDET_ON 0x0040 +#define R21_MT_ADC 0x8000 +#define R22_SEL_LNA 0x0008 +#define R22_SEL_MIC 0x0004 +#define R22_SKIP_DCFIL 0x0002 +#define R23_AGC_EN 0x0001 + +#define UDA1342_DAI_DUPLEX 0 /* playback and capture on single DAI */ +#define UDA1342_DAI_PLAYBACK 1 /* playback DAI */ +#define UDA1342_DAI_CAPTURE 2 /* capture DAI */ + +#define STATUS0_DAIFMT_MASK (~(7 << 1)) +#define STATUS0_SYSCLK_MASK (~(3 << 4)) + +#endif /* _UDA1342_H */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 373a31ddccb2d6..a2521e16c099b0 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5177,4 +5177,3 @@ static struct slim_driver wcd9335_slim_driver = { module_slim_driver(wcd9335_slim_driver); MODULE_DESCRIPTION("WCD9335 slim driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("slim:217:1a0:*"); diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index 08fb13a334a4cc..c9d5e67bf66e4e 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index e69283195f362f..91c8697c29c321 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2098,4 +2098,4 @@ static const struct cs_dsp_client_ops wm_adsp2_client_ops = { MODULE_DESCRIPTION("Cirrus Logic ASoC DSP Support"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(FW_CS_DSP); +MODULE_IMPORT_NS("FW_CS_DSP"); diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index e283751abfefe8..678540b7828059 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -29,6 +29,7 @@ config SND_SOC_FSL_SAI config SND_SOC_FSL_MQS tristate "Medium Quality Sound (MQS) module support" depends on SND_SOC_FSL_SAI + depends on IMX_SCMI_MISC_DRV || !IMX_SCMI_MISC_DRV select REGMAP_MMIO help Say Y if you want to add Medium Quality Sound (MQS) diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index f6c3aeff0d8eaf..02e1594e8223c9 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -317,8 +317,6 @@ static const struct snd_soc_dai_link fsl_asoc_card_dai[] = { { .name = "HiFi-ASRC-FE", .stream_name = "HiFi-ASRC-FE", - .dpcm_playback = 1, - .dpcm_capture = 1, .dynamic = 1, }, { @@ -326,8 +324,6 @@ static const struct snd_soc_dai_link fsl_asoc_card_dai[] = { .stream_name = "HiFi-ASRC-BE", .be_hw_params_fixup = be_hw_params_fixup, .ops = &fsl_asoc_card_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .no_pcm = 1, }, }; @@ -504,13 +500,13 @@ static int fsl_asoc_card_spdif_init(struct device_node *codec_np[], } if (priv->dai_link[0].playback_only) { - priv->dai_link[1].dpcm_capture = false; - priv->dai_link[2].dpcm_capture = false; + priv->dai_link[1].playback_only = true; + priv->dai_link[2].playback_only = true; priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (priv->dai_link[0].capture_only) { - priv->dai_link[1].dpcm_playback = false; - priv->dai_link[2].dpcm_playback = false; + priv->dai_link[1].capture_only = true; + priv->dai_link[2].capture_only = true; priv->card.dapm_routes = audio_map_rx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); } @@ -764,8 +760,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) { codec_dai_name[0] = "tlv320dac31xx-hifi"; priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; - priv->dai_link[1].dpcm_capture = 0; - priv->dai_link[2].dpcm_capture = 0; + priv->dai_link[1].playback_only = 1; + priv->dai_link[2].playback_only = 1; priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; priv->card.dapm_routes = audio_map_tx; @@ -791,15 +787,15 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_NB_NF; - priv->dai_link[1].dpcm_capture = 0; - priv->dai_link[2].dpcm_capture = 0; + priv->dai_link[1].playback_only = 1; + priv->dai_link[2].playback_only = 1; priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) { codec_dai_name[0] = "wm8524-hifi"; priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; - priv->dai_link[1].dpcm_capture = 0; - priv->dai_link[2].dpcm_capture = 0; + priv->dai_link[1].playback_only = 1; + priv->dai_link[2].playback_only = 1; priv->cpu_priv.slot_width = 32; priv->card.dapm_routes = audio_map_tx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx); @@ -1033,14 +1029,15 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } /* - * Properties "hp-det-gpio" and "mic-det-gpio" are optional, and + * Properties "hp-det-gpios" and "mic-det-gpios" are optional, and * simple_util_init_jack() uses these properties for creating * Headphone Jack and Microphone Jack. * * The notifier is initialized in snd_soc_card_jack_new(), then * snd_soc_jack_notifier_register can be called. */ - if (of_property_read_bool(np, "hp-det-gpio")) { + if (of_property_read_bool(np, "hp-det-gpios") || + of_property_read_bool(np, "hp-det-gpio") /* deprecated */) { ret = simple_util_init_jack(&priv->card, &priv->hp_jack, 1, NULL, "Headphone Jack"); if (ret) @@ -1049,7 +1046,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb); } - if (of_property_read_bool(np, "mic-det-gpio")) { + if (of_property_read_bool(np, "mic-det-gpios") || + of_property_read_bool(np, "mic-det-gpio") /* deprecated */) { ret = simple_util_init_jack(&priv->card, &priv->mic_jack, 0, NULL, "Mic Jack"); if (ret) diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 021d73e409aa2f..bde6423188356d 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -169,7 +169,7 @@ static const struct regmap_config fsl_aud2htx_regmap_config = { .readable_reg = fsl_aud2htx_readable_reg, .volatile_reg = fsl_aud2htx_volatile_reg, .writeable_reg = fsl_aud2htx_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct of_device_id fsl_aud2htx_dt_ids[] = { diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 82359edd6a8b49..d22f0621c465f5 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1748,7 +1748,7 @@ static const struct regmap_config fsl_easrc_regmap_config = { .rd_table = &fsl_easrc_readable_table, .wr_table = &fsl_easrc_writeable_table, .volatile_table = &fsl_easrc_volatileable_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #ifdef DEBUG diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 0c71a73476dfa6..8c15389c9a04bc 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -68,6 +68,7 @@ struct fsl_micfil { int vad_detected; struct fsl_micfil_verid verid; struct fsl_micfil_param param; + bool mclk_flag; /* mclk enable flag */ }; struct fsl_micfil_soc_data { @@ -708,7 +709,7 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, /* Enable the module */ ret = regmap_set_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN); + MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN); if (ret) return ret; @@ -724,7 +725,7 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, /* Disable the module */ ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, - MICFIL_CTRL1_PDMIEN); + MICFIL_CTRL1_PDMIEN | MICFIL_CTRL1_ERREN); if (ret) return ret; @@ -751,7 +752,6 @@ static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int s clk = micfil->mclk; /* Disable clock first, for it was enabled by pm_runtime */ - clk_disable_unprepare(clk); fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk, micfil->pll11k_clk, ratio); ret = clk_prepare_enable(clk); @@ -788,6 +788,8 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; + micfil->mclk_flag = true; + ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8); if (ret) return ret; @@ -822,6 +824,17 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, return 0; } +static int fsl_micfil_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); + + clk_disable_unprepare(micfil->mclk); + micfil->mclk_flag = false; + + return 0; +} + static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); @@ -878,6 +891,7 @@ static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { .startup = fsl_micfil_startup, .trigger = fsl_micfil_trigger, .hw_params = fsl_micfil_hw_params, + .hw_free = fsl_micfil_hw_free, }; static struct snd_soc_dai_driver fsl_micfil_dai = { @@ -999,6 +1013,7 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case REG_MICFIL_STAT: + case REG_MICFIL_FIFO_STAT: case REG_MICFIL_DATACH0: case REG_MICFIL_DATACH1: case REG_MICFIL_DATACH2: @@ -1007,6 +1022,7 @@ static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg) case REG_MICFIL_DATACH5: case REG_MICFIL_DATACH6: case REG_MICFIL_DATACH7: + case REG_MICFIL_OUT_STAT: case REG_MICFIL_VERID: case REG_MICFIL_PARAM: case REG_MICFIL_VAD0_STAT: @@ -1028,7 +1044,7 @@ static const struct regmap_config fsl_micfil_regmap_config = { .readable_reg = fsl_micfil_readable_reg, .volatile_reg = fsl_micfil_volatile_reg, .writeable_reg = fsl_micfil_writeable_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* END OF REGMAP */ @@ -1061,7 +1077,7 @@ static irqreturn_t micfil_isr(int irq, void *devid) regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, MICFIL_STAT_CHXF(i), - 1); + MICFIL_STAT_CHXF(i)); } for (i = 0; i < MICFIL_FIFO_NUM; i++) { @@ -1083,6 +1099,8 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) { struct fsl_micfil *micfil = (struct fsl_micfil *)devid; struct platform_device *pdev = micfil->pdev; + u32 fifo_stat_reg; + u32 out_stat_reg; u32 stat_reg; regmap_read(micfil->regmap, REG_MICFIL_STAT, &stat_reg); @@ -1096,9 +1114,17 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) if (stat_reg & MICFIL_STAT_LOWFREQF) { dev_dbg(&pdev->dev, "isr: ipg_clk_app is too low\n"); regmap_write_bits(micfil->regmap, REG_MICFIL_STAT, - MICFIL_STAT_LOWFREQF, 1); + MICFIL_STAT_LOWFREQF, MICFIL_STAT_LOWFREQF); } + regmap_read(micfil->regmap, REG_MICFIL_FIFO_STAT, &fifo_stat_reg); + regmap_write_bits(micfil->regmap, REG_MICFIL_FIFO_STAT, + fifo_stat_reg, fifo_stat_reg); + + regmap_read(micfil->regmap, REG_MICFIL_OUT_STAT, &out_stat_reg); + regmap_write_bits(micfil->regmap, REG_MICFIL_OUT_STAT, + out_stat_reg, out_stat_reg); + return IRQ_HANDLED; } @@ -1358,7 +1384,8 @@ static int fsl_micfil_runtime_suspend(struct device *dev) regcache_cache_only(micfil->regmap, true); - clk_disable_unprepare(micfil->mclk); + if (micfil->mclk_flag) + clk_disable_unprepare(micfil->mclk); clk_disable_unprepare(micfil->busclk); return 0; @@ -1373,10 +1400,12 @@ static int fsl_micfil_runtime_resume(struct device *dev) if (ret < 0) return ret; - ret = clk_prepare_enable(micfil->mclk); - if (ret < 0) { - clk_disable_unprepare(micfil->busclk); - return ret; + if (micfil->mclk_flag) { + ret = clk_prepare_enable(micfil->mclk); + if (ret < 0) { + clk_disable_unprepare(micfil->busclk); + return ret; + } } regcache_cache_only(micfil->regmap, false); diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index 145f9ca15e43cb..0513e9e8402e82 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -6,6 +6,7 @@ // Copyright 2019 NXP #include +#include #include #include #include @@ -74,6 +75,29 @@ struct fsl_mqs { #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) #define FSL_MQS_FORMATS SNDRV_PCM_FMTBIT_S16_LE +static int fsl_mqs_sm_read(void *context, unsigned int reg, unsigned int *val) +{ + struct fsl_mqs *mqs_priv = context; + int num = 1; + + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && + mqs_priv->soc->ctrl_off == reg) + return scmi_imx_misc_ctrl_get(SCMI_IMX_CTRL_MQS1_SETTINGS, &num, val); + + return -EINVAL; +}; + +static int fsl_mqs_sm_write(void *context, unsigned int reg, unsigned int val) +{ + struct fsl_mqs *mqs_priv = context; + + if (IS_ENABLED(CONFIG_IMX_SCMI_MISC_DRV) && + mqs_priv->soc->ctrl_off == reg) + return scmi_imx_misc_ctrl_set(SCMI_IMX_CTRL_MQS1_SETTINGS, val); + + return -EINVAL; +}; + static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -188,6 +212,13 @@ static const struct regmap_config fsl_mqs_regmap_config = { .cache_type = REGCACHE_NONE, }; +static const struct regmap_config fsl_mqs_sm_regmap = { + .reg_bits = 32, + .val_bits = 32, + .reg_read = fsl_mqs_sm_read, + .reg_write = fsl_mqs_sm_write, +}; + static int fsl_mqs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -219,6 +250,16 @@ static int fsl_mqs_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get gpr regmap\n"); return PTR_ERR(mqs_priv->regmap); } + } else if (mqs_priv->soc->type == TYPE_REG_SM) { + mqs_priv->regmap = devm_regmap_init(&pdev->dev, + NULL, + mqs_priv, + &fsl_mqs_sm_regmap); + if (IS_ERR(mqs_priv->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(mqs_priv->regmap)); + return PTR_ERR(mqs_priv->regmap); + } } else { regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index 8668abd3520800..e257b8adafe095 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -838,8 +838,6 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * qmc_dai->id, i, ret); return ret; } - dev_info(qmc_audio->dev, "dai %d QMC channel %d mode %d, nb_tx_ts %u, nb_rx_ts %u\n", - qmc_dai->id, i, info.mode, info.nb_tx_ts, info.nb_rx_ts); if (info.mode != QMC_TRANSPARENT) { dev_err(qmc_audio->dev, "dai %d QMC chan %d mode %d is not QMC_TRANSPARENT\n", diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index b6ff04f7138a2c..ee946e0d3f4969 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1204,7 +1204,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { }, /* DPLL lock info get controller */ { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = RX_SAMPLE_RATE_KCONTROL, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index beede7344efd63..9c184ab7346884 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -53,6 +53,8 @@ struct fsl_xcvr { struct snd_aes_iec958 rx_iec958; struct snd_aes_iec958 tx_iec958; u8 cap_ds[FSL_XCVR_CAPDS_SIZE]; + struct work_struct work_rst; + spinlock_t lock; /* Protect hw_reset and trigger */ }; static const struct fsl_xcvr_pll_conf { @@ -169,7 +171,7 @@ static int fsl_xcvr_capds_put(struct snd_kcontrol *kcontrol, } static struct snd_kcontrol_new fsl_xcvr_earc_capds_kctl = { - .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capabilities Data Structure", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .info = fsl_xcvr_type_capds_bytes_info, @@ -663,7 +665,10 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, { struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - int ret; + unsigned long lock_flags; + int ret = 0; + + spin_lock_irqsave(&xcvr->lock, lock_flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -675,7 +680,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); if (ret < 0) { dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret); - return ret; + goto release_lock; } if (tx) { @@ -687,7 +692,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) { dev_err(dai->dev, "err updating isr %d\n", ret); - return ret; + goto release_lock; } fallthrough; case FSL_XCVR_MODE_SPDIF: @@ -696,7 +701,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret); - return ret; + goto release_lock; } break; } @@ -707,14 +712,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0); if (ret < 0) { dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); - return ret; + goto release_lock; } ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); if (ret < 0) { dev_err(dai->dev, "Error while setting IER0: %d\n", ret); - return ret; + goto release_lock; } /* clear DPATH RESET */ @@ -723,7 +728,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, 0); if (ret < 0) { dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret); - return ret; + goto release_lock; } break; @@ -736,14 +741,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_EXT_CTRL_DMA_DIS(tx)); if (ret < 0) { dev_err(dai->dev, "Failed to disable DMA: %d\n", ret); - return ret; + goto release_lock; } ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0, FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) { dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); - return ret; + goto release_lock; } if (tx) { @@ -754,7 +759,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) { dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret); - return ret; + goto release_lock; } if (xcvr->soc_data->spdif_only) break; @@ -768,17 +773,20 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, if (ret < 0) { dev_err(dai->dev, "Err updating ISR %d\n", ret); - return ret; + goto release_lock; } break; } } break; default: - return -EINVAL; + ret = -EINVAL; + break; } - return 0; +release_lock: + spin_unlock_irqrestore(&xcvr->lock, lock_flags); + return ret; } static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr) @@ -1198,6 +1206,34 @@ static const struct regmap_config fsl_xcvr_regmap_cfg = { .cache_type = REGCACHE_FLAT, }; +static void reset_rx_work(struct work_struct *work) +{ + struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst); + struct device *dev = &xcvr->pdev->dev; + unsigned long lock_flags; + u32 ext_ctrl; + + dev_dbg(dev, "reset rx path\n"); + spin_lock_irqsave(&xcvr->lock, lock_flags); + regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl); + + if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) { + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_DMA_RD_DIS, + FSL_XCVR_EXT_CTRL_DMA_RD_DIS); + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_RX_DPTH_RESET, + FSL_XCVR_EXT_CTRL_RX_DPTH_RESET); + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_DMA_RD_DIS, + 0); + regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, + FSL_XCVR_EXT_CTRL_RX_DPTH_RESET, + 0); + } + spin_unlock_irqrestore(&xcvr->lock, lock_flags); +} + static irqreturn_t irq0_isr(int irq, void *devid) { struct fsl_xcvr *xcvr = (struct fsl_xcvr *)devid; @@ -1265,6 +1301,33 @@ static irqreturn_t irq0_isr(int irq, void *devid) dev_dbg(dev, "DMA write request\n"); isr_clr |= FSL_XCVR_IRQ_DMA_WR_REQ; } + if (isr & FSL_XCVR_IRQ_CMDC_STATUS_UPD) { + dev_dbg(dev, "CMDC status update\n"); + isr_clr |= FSL_XCVR_IRQ_CMDC_STATUS_UPD; + } + if (isr & FSL_XCVR_IRQ_PREAMBLE_MISMATCH) { + dev_dbg(dev, "Preamble mismatch\n"); + isr_clr |= FSL_XCVR_IRQ_PREAMBLE_MISMATCH; + } + if (isr & FSL_XCVR_IRQ_UNEXP_PRE_REC) { + dev_dbg(dev, "Unexpected preamble received\n"); + isr_clr |= FSL_XCVR_IRQ_UNEXP_PRE_REC; + } + if (isr & FSL_XCVR_IRQ_M_W_PRE_MISMATCH) { + dev_dbg(dev, "M/W preamble mismatch\n"); + isr_clr |= FSL_XCVR_IRQ_M_W_PRE_MISMATCH; + } + if (isr & FSL_XCVR_IRQ_B_PRE_MISMATCH) { + dev_dbg(dev, "B preamble mismatch\n"); + isr_clr |= FSL_XCVR_IRQ_B_PRE_MISMATCH; + } + + if (isr & (FSL_XCVR_IRQ_PREAMBLE_MISMATCH | + FSL_XCVR_IRQ_UNEXP_PRE_REC | + FSL_XCVR_IRQ_M_W_PRE_MISMATCH | + FSL_XCVR_IRQ_B_PRE_MISMATCH)) { + schedule_work(&xcvr->work_rst); + } if (isr_clr) { regmap_write(regmap, FSL_XCVR_EXT_ISR_CLR, isr_clr); @@ -1411,11 +1474,16 @@ static int fsl_xcvr_probe(struct platform_device *pdev) fsl_xcvr_comp.name); } + INIT_WORK(&xcvr->work_rst, reset_rx_work); + spin_lock_init(&xcvr->lock); return ret; } static void fsl_xcvr_remove(struct platform_device *pdev) { + struct fsl_xcvr *xcvr = dev_get_drvdata(&pdev->dev); + + cancel_work_sync(&xcvr->work_rst); pm_runtime_disable(&pdev->dev); } diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h index 882428592e1ad6..c72cb05184df80 100644 --- a/sound/soc/fsl/fsl_xcvr.h +++ b/sound/soc/fsl/fsl_xcvr.h @@ -165,6 +165,11 @@ FSL_XCVR_IRQ_MUTE | \ FSL_XCVR_IRQ_FIFO_UOFL_ERR | \ FSL_XCVR_IRQ_HOST_WAKEUP | \ + FSL_XCVR_IRQ_CMDC_STATUS_UPD |\ + FSL_XCVR_IRQ_B_PRE_MISMATCH |\ + FSL_XCVR_IRQ_M_W_PRE_MISMATCH |\ + FSL_XCVR_IRQ_PREAMBLE_MISMATCH |\ + FSL_XCVR_IRQ_UNEXP_PRE_REC |\ FSL_XCVR_IRQ_ARC_MODE) #define FSL_XCVR_ISR_CMDC_TX_EN BIT(3) diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 6fbcf33fd0dea6..231400661c9060 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -264,17 +264,19 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->dai[i].cpus->dai_name = name[1][i]; priv->dai[i].dynamic = 1; - priv->dai[i].dpcm_playback = 1; - if (i == num_dai - 1) { - priv->dai[i].dpcm_capture = 1; - priv->dai[i].dpcm_playback = 0; - } + if (i == num_dai - 1) + priv->dai[i].capture_only = 1; + else + priv->dai[i].playback_only = 1; priv->dai[i].ignore_pmdown_time = 1; priv->dai[i].ops = &imx_audmix_fe_ops; /* Add AUDMIX Backend */ be_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "audmix-%d", i); + if (!be_name) + return -ENOMEM; + priv->dai[num_dai + i].cpus = &dlc[1]; priv->dai[num_dai + i].codecs = &snd_soc_dummy_dlc; @@ -285,11 +287,10 @@ static int imx_audmix_probe(struct platform_device *pdev) priv->dai[num_dai + i].cpus->of_node = audmix_np; priv->dai[num_dai + i].cpus->dai_name = be_name; priv->dai[num_dai + i].no_pcm = 1; - priv->dai[num_dai + i].dpcm_playback = 1; - if (i == num_dai - 1) { - priv->dai[num_dai + i].dpcm_capture = 1; - priv->dai[num_dai + i].dpcm_playback = 0; - } + if (i == num_dai - 1) + priv->dai[num_dai + i].capture_only = 1; + else + priv->dai[num_dai + i].playback_only = 1; priv->dai[num_dai + i].ignore_pmdown_time = 1; priv->dai[num_dai + i].ops = &imx_audmix_be_ops; diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index a7215bad648457..95a57fda025039 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -25,6 +25,7 @@ enum codec_type { CODEC_AK4458, CODEC_AK4497, CODEC_AK5552, + CODEC_CS42888, }; /* @@ -185,6 +186,16 @@ static struct imx_akcodec_tdm_fs_mul ak5558_tdm_fs_mul[] = { { .min = 512, .max = 512, .mul = 1024 }, }; +static struct imx_akcodec_fs_mul cs42888_fs_mul[] = { + { .rmin = 8000, .rmax = 48000, .wmin = 256, .wmax = 1024, }, + { .rmin = 64000, .rmax = 96000, .wmin = 128, .wmax = 512, }, + { .rmin = 176400, .rmax = 192000, .wmin = 64, .wmax = 256, }, +}; + +static struct imx_akcodec_tdm_fs_mul cs42888_tdm_fs_mul[] = { + { .min = 256, .max = 256, .mul = 256 }, +}; + static const u32 akcodec_rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000, @@ -210,6 +221,14 @@ static const u32 ak5558_tdm_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8, }; +static const u32 cs42888_channels[] = { + 1, 2, 4, 6, 8, +}; + +static const u32 cs42888_tdm_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, +}; + static bool format_is_dsd(struct snd_pcm_hw_params *params) { snd_pcm_format_t format = params_format(params); @@ -241,6 +260,7 @@ static bool codec_is_akcodec(unsigned int type) case CODEC_AK4497: case CODEC_AK5558: case CODEC_AK5552: + case CODEC_CS42888: return true; default: break; @@ -255,7 +275,7 @@ static unsigned long akcodec_get_mclk_rate(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct imx_card_data *data = snd_soc_card_get_drvdata(rtd->card); const struct imx_card_plat_data *plat_data = data->plat_data; - struct dai_link_data *link_data = &data->link_data[rtd->num]; + struct dai_link_data *link_data = &data->link_data[rtd->id]; unsigned int width = slots * slot_width; unsigned int rate = params_rate(params); int i; @@ -293,7 +313,7 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_card *card = rtd->card; struct imx_card_data *data = snd_soc_card_get_drvdata(card); - struct dai_link_data *link_data = &data->link_data[rtd->num]; + struct dai_link_data *link_data = &data->link_data[rtd->id]; struct imx_card_plat_data *plat_data = data->plat_data; struct device *dev = card->dev; struct snd_soc_dai *codec_dai; @@ -340,13 +360,15 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = snd_soc_dai_set_tdm_slot(codec_dai, - BIT(slots) - 1, - BIT(slots) - 1, - slots, slot_width); - if (ret && ret != -ENOTSUPP) { - dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); - return ret; + if (format_is_tdm(link_data)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + BIT(slots) - 1, + BIT(slots) - 1, + slots, slot_width); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n", i, ret); + return ret; + } } } @@ -370,6 +392,11 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n", mclk_freq, ret); return ret; } + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_freq, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) { + dev_err(dev, "failed to set codec dai mclk rate (%lu): %d\n", mclk_freq, ret); + return ret; + } return 0; } @@ -408,7 +435,7 @@ static int imx_aif_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_card *card = rtd->card; struct imx_card_data *data = snd_soc_card_get_drvdata(card); - struct dai_link_data *link_data = &data->link_data[rtd->num]; + struct dai_link_data *link_data = &data->link_data[rtd->id]; static struct snd_pcm_hw_constraint_list constraint_rates; static struct snd_pcm_hw_constraint_list constraint_channels; int ret = 0; @@ -604,6 +631,8 @@ static int imx_card_parse_of(struct imx_card_data *data) plat_data->type = CODEC_AK5558; else if (!strcmp(link->codecs->dai_name, "ak5552-aif")) plat_data->type = CODEC_AK5552; + else if (!strcmp(link->codecs->dai_name, "cs42888")) + plat_data->type = CODEC_CS42888; } else { link->codecs = &snd_soc_dummy_dlc; @@ -761,6 +790,12 @@ static int imx_card_probe(struct platform_device *pdev) data->dapm_routes[i].sink = "ASRC-Capture"; data->dapm_routes[i].source = "CPU-Capture"; break; + case CODEC_CS42888: + data->dapm_routes[0].sink = "Playback"; + data->dapm_routes[0].source = "CPU-Playback"; + data->dapm_routes[1].sink = "CPU-Capture"; + data->dapm_routes[1].source = "Capture"; + break; default: break; } @@ -800,6 +835,16 @@ static int imx_card_probe(struct platform_device *pdev) plat_data->support_tdm_channels = ak5558_tdm_channels; plat_data->num_tdm_channels = ARRAY_SIZE(ak5558_tdm_channels); break; + case CODEC_CS42888: + plat_data->fs_mul = cs42888_fs_mul; + plat_data->num_fs_mul = ARRAY_SIZE(cs42888_fs_mul); + plat_data->tdm_fs_mul = cs42888_tdm_fs_mul; + plat_data->num_tdm_fs_mul = ARRAY_SIZE(cs42888_tdm_fs_mul); + plat_data->support_channels = cs42888_channels; + plat_data->num_channels = ARRAY_SIZE(cs42888_channels); + plat_data->support_tdm_channels = cs42888_tdm_channels; + plat_data->num_tdm_channels = ARRAY_SIZE(cs42888_tdm_channels); + break; default: break; } @@ -815,8 +860,8 @@ static int imx_card_probe(struct platform_device *pdev) } for_each_card_prelinks(&data->card, i, link) { if (link->dynamic == 1 && link_be) { - link->dpcm_playback = link_be->dpcm_playback; - link->dpcm_capture = link_be->dpcm_capture; + link->playback_only = link_be->playback_only; + link->capture_only = link_be->capture_only; } } } diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 4b384475b9726a..7655425a3deb10 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -372,7 +372,7 @@ static int __graph_for_each_link(struct simple_util_priv *priv, cpu_port = it.node; /* loop for all CPU endpoint */ - for_each_child_of_node_scoped(cpu_port, cpu_ep) { + for_each_of_graph_port_endpoint(cpu_port, cpu_ep) { /* get codec */ codec_ep = of_graph_get_remote_endpoint(cpu_ep); codec_port = ep_to_port(codec_ep); diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index 93eee40cec760c..1f5c4e8ff1b900 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -50,7 +50,7 @@ snd_soc_runtime_get_dai_fmt() sample driver - linux/sound/soc/sh/rcar/core.c + linux/sound/soc/renesas/rcar/core.c linux/sound/soc/codecs/ak4613.c linux/sound/soc/codecs/pcm3168a.c linux/sound/soc/soc-utils.c @@ -234,8 +234,6 @@ enum graph_type { #define GRAPH_NODENAME_DPCM "dpcm" #define GRAPH_NODENAME_C2C "codec2codec" -#define port_to_endpoint(port) of_get_child_by_name(port, "endpoint") - #define ep_to_port(ep) of_get_parent(ep) static struct device_node *port_to_ports(struct device_node *port) { @@ -354,14 +352,9 @@ static struct device_node *graph_get_next_multi_ep(struct device_node **port) * port@1 { rep1 }; * }; */ - do { - *port = of_get_next_child(ports, *port); - if (!*port) - break; - } while (!of_node_name_eq(*port, "port")); - + *port = of_graph_get_next_port(ports, *port); if (*port) { - ep = port_to_endpoint(*port); + ep = of_graph_get_next_port_endpoint(*port, NULL); rep = of_graph_get_remote_endpoint(ep); } @@ -533,67 +526,66 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, * }; * }; */ - struct device_node *mcpu_ep = port_to_endpoint(mcpu_port); - struct device_node *mcpu_ep_n = mcpu_ep; - struct device_node *mcpu_port_top = of_get_next_child(port_to_ports(mcpu_port), NULL); - struct device_node *mcpu_ep_top = port_to_endpoint(mcpu_port_top); + struct device_node *mcpu_ep = of_graph_get_next_port_endpoint(mcpu_port, NULL); + struct device_node *mcpu_ports = port_to_ports(mcpu_port); + struct device_node *mcpu_port_top = of_graph_get_next_port(mcpu_ports, NULL); + struct device_node *mcpu_ep_top = of_graph_get_next_port_endpoint(mcpu_port_top, NULL); struct device_node *mcodec_ep_top = of_graph_get_remote_endpoint(mcpu_ep_top); struct device_node *mcodec_port_top = ep_to_port(mcodec_ep_top); struct device_node *mcodec_ports = port_to_ports(mcodec_port_top); int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); - int ret = -EINVAL; + int ret = 0; - if (cpu_idx > dai_link->num_cpus) + if (cpu_idx > dai_link->num_cpus) { + ret = -EINVAL; goto mcpu_err; + } - while (1) { + for_each_of_graph_port_endpoint(mcpu_port, mcpu_ep_n) { struct device_node *mcodec_ep_n; - struct device_node *mcodec_port_i; struct device_node *mcodec_port; int codec_idx; - if (*nm_idx > nm_max) - break; + /* ignore 1st ep which is for element */ + if (mcpu_ep_n == mcpu_ep) + continue; - mcpu_ep_n = of_get_next_child(mcpu_port, mcpu_ep_n); - if (!mcpu_ep_n) { - ret = 0; + if (*nm_idx > nm_max) break; - } mcodec_ep_n = of_graph_get_remote_endpoint(mcpu_ep_n); mcodec_port = ep_to_port(mcodec_ep_n); - if (mcodec_ports != port_to_ports(mcodec_port)) + if (mcodec_ports != port_to_ports(mcodec_port)) { + ret = -EINVAL; goto mcpu_err; + } codec_idx = 0; - mcodec_port_i = of_get_next_child(mcodec_ports, NULL); - while (1) { - if (codec_idx > dai_link->num_codecs) - goto mcodec_err; - - mcodec_port_i = of_get_next_child(mcodec_ports, mcodec_port_i); + ret = -EINVAL; + for_each_of_graph_port(mcodec_ports, mcodec_port_i) { - if (!mcodec_port_i) - goto mcodec_err; + /* ignore 1st port which is for pair connection */ + if (mcodec_port_top == mcodec_port_i) + continue; - if (mcodec_port_i == mcodec_port) + if (codec_idx > dai_link->num_codecs) break; + if (mcodec_port_i == mcodec_port) { + dai_link->ch_maps[*nm_idx].cpu = cpu_idx; + dai_link->ch_maps[*nm_idx].codec = codec_idx; + + (*nm_idx)++; + ret = 0; + break; + } codec_idx++; } - - dai_link->ch_maps[*nm_idx].cpu = cpu_idx; - dai_link->ch_maps[*nm_idx].codec = codec_idx; - - (*nm_idx)++; - - of_node_put(mcodec_port_i); -mcodec_err: of_node_put(mcodec_port); - of_node_put(mcpu_ep_n); of_node_put(mcodec_ep_n); + if (ret < 0) + break; } mcpu_err: of_node_put(mcpu_ep); @@ -677,7 +669,7 @@ static int graph_parse_node_single(struct simple_util_priv *priv, struct device_node *port, struct link_info *li, int is_cpu) { - struct device_node *ep = port_to_endpoint(port); + struct device_node *ep = of_graph_get_next_port_endpoint(port, NULL); int ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); of_node_put(ep); @@ -772,17 +764,17 @@ static void graph_link_init(struct simple_util_priv *priv, of_node_put(port_cpu); port_cpu = ep_to_port(ep_cpu); } else { - ep_cpu = port_to_endpoint(port_cpu); + ep_cpu = of_graph_get_next_port_endpoint(port_cpu, NULL); } ports_cpu = port_to_ports(port_cpu); of_node_get(port_codec); if (graph_lnk_is_multi(port_codec)) { ep_codec = graph_get_next_multi_ep(&port_codec); - of_node_put(port_cpu); + of_node_put(port_codec); port_codec = ep_to_port(ep_codec); } else { - ep_codec = port_to_endpoint(port_codec); + ep_codec = of_graph_get_next_port_endpoint(port_codec, NULL); } ports_codec = port_to_ports(port_codec); @@ -853,7 +845,7 @@ int audio_graph2_link_normal(struct simple_util_priv *priv, struct link_info *li) { struct device_node *cpu_port = lnk; - struct device_node *cpu_ep = port_to_endpoint(cpu_port); + struct device_node *cpu_ep = of_graph_get_next_port_endpoint(cpu_port, NULL); struct device_node *codec_port = of_graph_get_remote_port(cpu_ep); int ret; @@ -886,7 +878,7 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv, struct device_node *lnk, struct link_info *li) { - struct device_node *ep = port_to_endpoint(lnk); + struct device_node *ep = of_graph_get_next_port_endpoint(lnk, NULL); struct device_node *rep = of_graph_get_remote_endpoint(ep); struct device_node *cpu_port = NULL; struct device_node *codec_port = NULL; @@ -1010,7 +1002,7 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv, of_node_get(lnk); port0 = lnk; ports = port_to_ports(port0); - port1 = of_get_next_child(ports, lnk); + port1 = of_graph_get_next_port(ports, port0); /* * Card2 can use original Codec2Codec settings if DT has. @@ -1040,8 +1032,8 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv, dai_link->num_c2c_params = 1; } - ep0 = port_to_endpoint(port0); - ep1 = port_to_endpoint(port1); + ep0 = of_graph_get_next_port_endpoint(port0, NULL); + ep1 = of_graph_get_next_port_endpoint(port1, NULL); codec0_port = of_graph_get_remote_port(ep0); codec1_port = of_graph_get_remote_port(ep1); @@ -1147,7 +1139,7 @@ static int graph_counter(struct device_node *lnk) * CPU/Codec = N:M case has many endpoints. * We can't use of_graph_get_endpoint_count() here */ - return of_get_child_count(ports) - 1; + return of_graph_get_port_count(ports) - 1; } /* * Single CPU / Codec @@ -1161,7 +1153,7 @@ static int graph_count_normal(struct simple_util_priv *priv, struct link_info *li) { struct device_node *cpu_port = lnk; - struct device_node *cpu_ep = port_to_endpoint(cpu_port); + struct device_node *cpu_ep = of_graph_get_next_port_endpoint(cpu_port, NULL); struct device_node *codec_port = of_graph_get_remote_port(cpu_ep); /* @@ -1189,7 +1181,7 @@ static int graph_count_dpcm(struct simple_util_priv *priv, struct device_node *lnk, struct link_info *li) { - struct device_node *ep = port_to_endpoint(lnk); + struct device_node *ep = of_graph_get_next_port_endpoint(lnk, NULL); struct device_node *rport = of_graph_get_remote_port(ep); /* @@ -1231,9 +1223,9 @@ static int graph_count_c2c(struct simple_util_priv *priv, { struct device_node *ports = port_to_ports(lnk); struct device_node *port0 = lnk; - struct device_node *port1 = of_get_next_child(ports, of_node_get(lnk)); - struct device_node *ep0 = port_to_endpoint(port0); - struct device_node *ep1 = port_to_endpoint(port1); + struct device_node *port1 = of_graph_get_next_port(ports, of_node_get(port0)); + struct device_node *ep0 = of_graph_get_next_port_endpoint(port0, NULL); + struct device_node *ep1 = of_graph_get_next_port_endpoint(port1, NULL); struct device_node *codec0 = of_graph_get_remote_port(ep0); struct device_node *codec1 = of_graph_get_remote_port(ep1); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index fedae7f6f70cc5..24b371f3206632 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -296,7 +296,7 @@ int simple_util_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id); struct simple_util_dai *dai; unsigned int fixed_sysclk = 0; int i1, i2, i; @@ -357,7 +357,7 @@ void simple_util_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id); struct simple_util_dai *dai; int i; @@ -448,7 +448,7 @@ int simple_util_hw_params(struct snd_pcm_substream *substream, struct simple_util_dai *pdai; struct snd_soc_dai *sdai; struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id); unsigned int mclk, mclk_fs = 0; int i, ret; @@ -517,7 +517,7 @@ int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->id); struct simple_util_data *data = &dai_props->adata; struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); @@ -628,7 +628,7 @@ static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd) { struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id); struct simple_util_dai *dai; int i, ret; @@ -858,6 +858,10 @@ int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix) } EXPORT_SYMBOL_GPL(simple_util_init_aux_jacks); +static struct simple_util_dai dummy_util_dais = { + .name = "dummy_util_dais", +}; + int simple_util_init_priv(struct simple_util_priv *priv, struct link_info *li) { @@ -929,6 +933,7 @@ int simple_util_init_priv(struct simple_util_priv *priv, dai_link[i].cpus = &snd_soc_dummy_dlc; dai_props[i].num.cpus = dai_link[i].num_cpus = 1; + dai_props[i].cpu_dai = &dummy_util_dais; } if (li->num[i].codecs) { @@ -951,6 +956,7 @@ int simple_util_init_priv(struct simple_util_priv *priv, dai_link[i].codecs = &snd_soc_dummy_dlc; dai_props[i].num.codecs = dai_link[i].num_codecs = 1; + dai_props[i].codec_dai = &dummy_util_dais; } if (li->num[i].platforms) { diff --git a/sound/soc/generic/test-component.c b/sound/soc/generic/test-component.c index 407288055741a4..5430d25deaef18 100644 --- a/sound/soc/generic/test-component.c +++ b/sound/soc/generic/test-component.c @@ -224,7 +224,7 @@ static const struct snd_soc_dai_ops test_verbose_ops = { .num_auto_selectable_formats = 1, }; -#define STUB_RATES SNDRV_PCM_RATE_8000_384000 +#define STUB_RATES SNDRV_PCM_RATE_CONTINUOUS #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_U8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ @@ -521,7 +521,6 @@ static int test_driver_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - struct device_node *ep; const struct test_adata *adata = of_device_get_match_data(&pdev->dev); struct snd_soc_component_driver *cdriv; struct snd_soc_dai_driver *ddriv; @@ -591,7 +590,7 @@ static int test_driver_probe(struct platform_device *pdev) } i = 0; - for_each_endpoint_of_node(node, ep) { + for_each_of_graph_port(node, port) { snprintf(dname[i].name, TEST_NAME_LEN, "%s.%d", node->name, i); ddriv[i].name = dname[i].name; diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a32fb0a8d7d7cc..2db494b0e3cff0 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -15,9 +15,6 @@ config SND_SOC_INTEL_SST_TOPLEVEL if SND_SOC_INTEL_SST_TOPLEVEL -config SND_SOC_INTEL_SST - tristate - config SND_SOC_INTEL_CATPT tristate "Haswell and Broadwell" depends on ACPI || COMPILE_TEST @@ -74,9 +71,14 @@ if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_ACPI_INTEL_MATCH tristate select SND_SOC_ACPI if ACPI + select SND_SOC_ACPI_INTEL_SDCA_QUIRKS # this option controls the compilation of ACPI matching tables and # helpers and is not meant to be selected by the user. +config SND_SOC_ACPI_INTEL_SDCA_QUIRKS + tristate + select SND_SOC_SDCA if ACPI + endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_INTEL_KEEMBAY diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 80c0a1a956542d..76078a7005b07d 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -203,29 +203,12 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->exit = avs_da7219_codec_exit; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; return 0; } -static int avs_card_suspend_pre(struct snd_soc_card *card) -{ - struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME); - - return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); -} - -static int avs_card_resume_post(struct snd_soc_card *card) -{ - struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME); - struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); - - return snd_soc_component_set_jack(codec_dai->component, jack, NULL); -} - static int avs_da7219_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; @@ -257,8 +240,6 @@ static int avs_da7219_probe(struct platform_device *pdev) card->name = "avs_da7219"; card->dev = dev; card->owner = THIS_MODULE; - card->suspend_pre = avs_card_suspend_pre; - card->resume_post = avs_card_resume_post; card->dai_link = dai_link; card->num_links = 1; card->controls = card_controls; diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index a31aa471a1c219..4dd9591ee98b75 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -22,7 +22,7 @@ static struct snd_soc_dai_link card_dai_links[] = { { .name = "DMIC", .id = 0, - .dpcm_capture = 1, + .capture_only = 1, .nonatomic = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), @@ -30,7 +30,7 @@ static struct snd_soc_dai_link card_dai_links[] = { { .name = "DMIC WoV", .id = 1, - .dpcm_capture = 1, + .capture_only = 1, .nonatomic = 1, .no_pcm = 1, .ignore_suspend = 1, diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index c8522e2430f8af..426ce37105aebd 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -233,8 +233,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_es8336_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index 430c070a1a0ee5..cb6d54db718921 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -39,8 +39,6 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int dl[i].id = i; dl[i].nonatomic = 1; dl[i].no_pcm = 1; - dl[i].dpcm_playback = 1; - dl[i].dpcm_capture = 1; dl[i].platforms = platform; dl[i].num_platforms = 1; dl[i].ignore_pmdown_time = 1; @@ -160,8 +158,6 @@ static const struct snd_soc_dai_link probing_link = { .id = -1, .nonatomic = 1, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .cpus = &snd_soc_dummy_dlc, .num_cpus = 1, .init = avs_probing_link_init, diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 7e6c8d9c900bd0..4556f105c793eb 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -46,8 +46,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->id = 0; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index 8d550e82b46a82..6570209c1a63ef 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -82,7 +82,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_max98357a_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_playback = 1; + dl->playback_only = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index fdef5a008daffe..6f25e66344b7a4 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -134,8 +134,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_max98373_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; dl->ops = &avs_max98373_ops; diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index 082f311d8b840d..ad18c4e9a67041 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -131,8 +131,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_max98927_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; dl->ops = &avs_max98927_ops; diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index 6ea9058fdb2a77..bf902540744c5e 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -210,8 +210,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_nau8825_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index 9fcce86c6eb487..4b6c02a4020478 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -184,8 +184,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_rt274_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index f157f2d19efb4f..e40563ca99fd50 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -153,8 +153,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_rt286_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index 1e85242c8dd2b6..94fce07c83f9e9 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -173,8 +173,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_rt298_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index cfa146b6cf0879..30588d9e9ba3bc 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -121,7 +121,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_rt5514_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; + dl->capture_only = 1; dl->ops = &avs_rt5514_ops; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index 44f857e9096917..b456b9d1466549 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -171,8 +171,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_rt5663_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ops = &avs_rt5663_ops; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 0dcc6392a0cc8d..335960cfd7ba13 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -242,8 +242,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_rt5682_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index 63bbfc30f35e9c..cfef00462f6612 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -121,8 +121,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_ssm4567_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; *dai_link = dl; diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 4af81158035681..945f9c0a6a5455 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -509,7 +509,7 @@ static int avs_pcm_hw_constraints_init(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS, SNDRV_PCM_HW_PARAM_RATE, -1); - return ret; + return 0; } static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cc10ae58b0c7ed..9b80b19bb8d06c 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -519,6 +519,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT712_SDCA_DMIC_SDW select SND_SOC_RT715_SDW select SND_SOC_RT715_SDCA_SDW + select SND_SOC_RT721_SDCA_SDW select SND_SOC_RT722_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index 3c7cee03a02e64..d25a7188f603f1 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -239,8 +239,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(fe, dummy, platform), }, @@ -256,8 +254,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5650_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = bdw_rt5650_init, SND_SOC_DAILINK_REG(ssp0_port, be, platform), }, diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 304af3d06d0170..9484f341078769 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -329,8 +329,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, - .dpcm_capture = 1, - .dpcm_playback = 1, .ops = &bdw_rt5677_fe_ops, SND_SOC_DAILINK_REG(fe, dummy, platform), }, @@ -356,8 +354,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5677_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = bdw_rt5677_init, .exit = bdw_rt5677_exit, SND_SOC_DAILINK_REG(ssp0_port, be, platform), diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c index 58db09d9b6e16f..523ade9f31ab7f 100644 --- a/sound/soc/intel/boards/bdw_rt286.c +++ b/sound/soc/intel/boards/bdw_rt286.c @@ -133,8 +133,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(system, dummy, platform), }, { @@ -143,7 +141,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload0, dummy, platform), }, { @@ -152,7 +150,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload1, dummy, platform), }, { @@ -161,7 +159,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(loopback, dummy, platform), }, /* Back End DAI links */ @@ -177,8 +175,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = codec_link_hw_params_fixup, .ops = &codec_link_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp0_port, codec, platform), }, }; diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index 8c2b4ab764bbaf..68a3d345dc25df 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -175,8 +175,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_cht_cx2072x_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -185,7 +183,7 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_cht_cx2072x_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -198,8 +196,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = byt_cht_cx2072x_init, .be_hw_params_fixup = byt_cht_cx2072x_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2, cx2072x, platform), }, }; diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 9178bbe8d99506..31141d4b6b2569 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -174,8 +174,6 @@ static struct snd_soc_dai_link dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -184,7 +182,7 @@ static struct snd_soc_dai_link dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -197,8 +195,6 @@ static struct snd_soc_dai_link dailink[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index d3327bc237b5f4..62594e7966ab0f 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -315,8 +315,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_cht_es8316_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -326,7 +324,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_cht_es8316_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -339,8 +337,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_cht_es8316_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_cht_es8316_init, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 4a957d1cece356..fec23bda9e6431 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -119,8 +119,6 @@ static struct snd_soc_dai_link dais[] = { .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -130,7 +128,7 @@ static struct snd_soc_dai_link dais[] = { .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -144,8 +142,6 @@ static struct snd_soc_dai_link dais[] = { | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, .ignore_suspend = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2_port, dummy, platform), }, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 54f77f57ec8e25..9caa4407c1ca3d 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1564,8 +1564,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .stream_name = "Baytrail Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_rt5640_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -1574,7 +1572,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_rt5640_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -1586,8 +1584,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5640_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_rt5640_init, .exit = byt_rt5640_exit, .ops = &byt_rt5640_be_ssp2_ops, diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 8e4b821efe9277..67c62844ca2a91 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -770,8 +770,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_rt5651_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -780,7 +778,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_rt5651_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -793,8 +791,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5651_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_rt5651_init, .ops = &byt_rt5651_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index 0b10d89cb18920..a6dfbcfdf74e31 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -462,8 +462,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .stream_name = "Baytrail Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_wm5102_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), @@ -473,7 +471,7 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_wm5102_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -490,8 +488,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_wm5102_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_wm5102_init, SND_SOC_DAILINK_REG(ssp0_port, ssp0_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index d7c11485883314..36984de8a0679e 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -351,8 +351,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -361,7 +359,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -374,8 +372,6 @@ static struct snd_soc_dai_link cht_dailink[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 7651b83632fa4b..4afb292d4f13a7 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -193,8 +193,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -203,7 +201,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -217,8 +215,6 @@ static struct snd_soc_dai_link cht_dailink[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index ac23a8b7cafca2..b977a2db73a3a7 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -448,8 +448,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -458,7 +456,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -470,8 +468,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index c6c469d51243ef..aaef212cf44ec7 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -358,8 +358,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -368,7 +366,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -381,8 +379,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index 90d93e667bd9e1..5c7b218f22b72f 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -178,8 +178,6 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "SSP0-Codec", .id = 0, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &rt5660_ops, SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform), }, @@ -187,7 +185,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "dmic48k", .id = 1, .ignore_suspend = 1, - .dpcm_capture = 1, + .capture_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), }, @@ -195,7 +193,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "dmic16k", .id = 2, .ignore_suspend = 1, - .dpcm_capture = 1, + .capture_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), }, @@ -203,7 +201,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp1", .id = 5, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), }, @@ -211,7 +209,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp2", .id = 6, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), }, @@ -219,7 +217,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp3", .id = 7, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), }, @@ -227,7 +225,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp4", .id = 8, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), }, @@ -315,4 +313,4 @@ module_platform_driver(snd_ehl_rt5660_driver); MODULE_DESCRIPTION("ASoC Intel(R) Elkhartlake + rt5660 Machine driver"); MODULE_AUTHOR("libin.yang@intel.com"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index fda5a92b000636..86e541a2c204d4 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -83,7 +83,7 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, return err; } -EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, SND_SOC_INTEL_HDA_DSP_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, "SND_SOC_INTEL_HDA_DSP_COMMON"); #endif diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c index 1826a4dfd0f351..9bb2822ba63e34 100644 --- a/sound/soc/intel/boards/hsw_rt5640.c +++ b/sound/soc/intel/boards/hsw_rt5640.c @@ -85,8 +85,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(system, dummy, platform), }, { @@ -95,7 +93,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload0, dummy, platform), }, { @@ -104,7 +102,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload1, dummy, platform), }, { @@ -113,7 +111,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(loopback, dummy, platform), }, /* Back End DAI links */ @@ -127,8 +125,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = codec_link_hw_params_fixup, .ops = &codec_link_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp0_port, codec, platform), }, }; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 9edd6d985cf1ef..22668bac74a1fc 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -164,4 +164,4 @@ MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); MODULE_AUTHOR("Rakesh Ughreja "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:skl_hda_dsp_generic"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 24f716e42d6a38..2ea1dda446ec2c 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -35,7 +35,7 @@ int sof_intel_board_card_late_probe(struct snd_soc_card *card) return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); } -EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); /* * DMIC DAI Link @@ -217,8 +217,6 @@ static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link, link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; - link->dpcm_playback = 1; return 0; } @@ -268,7 +266,7 @@ static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, link->init = dmic_init; link->ignore_suspend = 1; link->no_pcm = 1; - link->dpcm_capture = 1; + link->capture_only = 1; return 0; } @@ -326,7 +324,7 @@ static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link link->id = be_id; link->init = (hdmi_id == 1) ? hdmi_init : NULL; link->no_pcm = 1; - link->dpcm_playback = 1; + link->playback_only = 1; return 0; } @@ -361,13 +359,12 @@ static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link, /* codecs - caller to handle */ /* platforms */ + /* feedback stream or firmware-generated echo reference */ link->platforms = platform_component; link->num_platforms = ARRAY_SIZE(platform_component); link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; /* feedback stream or firmware-generated echo reference */ - link->dpcm_playback = 1; return 0; } @@ -407,8 +404,6 @@ static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; - link->dpcm_playback = 1; return 0; } @@ -448,7 +443,7 @@ static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link, link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; + link->capture_only = 1; return 0; } @@ -496,8 +491,6 @@ static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link, if (be_type == SOF_HDA_ANALOG) link->init = hda_init; link->no_pcm = 1; - link->dpcm_capture = 1; - link->dpcm_playback = 1; return 0; } @@ -738,7 +731,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); struct sof_card_private * sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk) @@ -781,10 +774,10 @@ sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk) return ctx; } -EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); -MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_MATCH); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); +MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH"); diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c index e71e09124b34e3..8db7695b974764 100644 --- a/sound/soc/intel/boards/sof_cirrus_common.c +++ b/sound/soc/intel/boards/sof_cirrus_common.c @@ -193,14 +193,14 @@ void cs35l41_set_dai_link(struct snd_soc_dai_link *link) link->init = cs35l41_init; link->ops = &cs35l41_ops; } -EXPORT_SYMBOL_NS(cs35l41_set_dai_link, SND_SOC_INTEL_SOF_CIRRUS_COMMON); +EXPORT_SYMBOL_NS(cs35l41_set_dai_link, "SND_SOC_INTEL_SOF_CIRRUS_COMMON"); void cs35l41_set_codec_conf(struct snd_soc_card *card) { card->codec_conf = cs35l41_codec_conf; card->num_configs = ARRAY_SIZE(cs35l41_codec_conf); } -EXPORT_SYMBOL_NS(cs35l41_set_codec_conf, SND_SOC_INTEL_SOF_CIRRUS_COMMON); +EXPORT_SYMBOL_NS(cs35l41_set_codec_conf, "SND_SOC_INTEL_SOF_CIRRUS_COMMON"); MODULE_DESCRIPTION("ASoC Intel SOF Cirrus Logic helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index f4fee2ee0d63b3..455c5bc8c63423 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -303,5 +303,5 @@ module_platform_driver(sof_audio) MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42"); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c index fa1f7d2d82787e..9b7082b239c16d 100644 --- a/sound/soc/intel/boards/sof_da7219.c +++ b/sound/soc/intel/boards/sof_da7219.c @@ -487,5 +487,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec"); MODULE_AUTHOR("Yong Zhi "); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index fc998fe4b19605..a0b3679b17b423 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -455,8 +455,6 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].exit = sof_es8316_exit; links[id].ops = &sof_es8336_ops; links[id].nonatomic = true; - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; links[id].no_pcm = 1; links[id].cpus = &cpus[id]; links[id].num_cpus = 1; @@ -496,7 +494,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].ignore_suspend = 1; - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; id++; @@ -539,7 +537,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_hdmi_init; - links[id].dpcm_playback = 1; + links[id].playback_only = 1; links[id].no_pcm = 1; id++; @@ -569,7 +567,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; links[id].num_cpus = 1; id++; @@ -845,4 +843,4 @@ module_platform_driver(sof_es8336_driver); MODULE_DESCRIPTION("ASoC Intel(R) SOF + ES8336 Machine driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index fcc3b95e57a4f3..c98a67ae5e6626 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -283,14 +283,14 @@ void max_98373_dai_link(struct device *dev, struct snd_soc_dai_link *link) link->init = max_98373_spk_codec_init; link->ops = &max_98373_ops; } -EXPORT_SYMBOL_NS(max_98373_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98373_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); void max_98373_set_codec_conf(struct snd_soc_card *card) { card->codec_conf = max_98373_codec_conf; card->num_configs = ARRAY_SIZE(max_98373_codec_conf); } -EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98373_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); /* * Maxim MAX98390 @@ -506,7 +506,7 @@ void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link) link->init = max_98390_init; link->ops = &max_98390_ops; } -EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98390_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) { @@ -529,7 +529,7 @@ void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) break; } } -EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98390_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); /* * Maxim MAX98357A/MAX98360A @@ -596,7 +596,7 @@ void max_98357a_dai_link(struct snd_soc_dai_link *link) link->num_codecs = ARRAY_SIZE(max_98357a_components); link->init = max_98357a_init; } -EXPORT_SYMBOL_NS(max_98357a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98357a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); void max_98360a_dai_link(struct snd_soc_dai_link *link) { @@ -604,7 +604,7 @@ void max_98360a_dai_link(struct snd_soc_dai_link *link) link->num_codecs = ARRAY_SIZE(max_98360a_components); link->init = max_98357a_init; } -EXPORT_SYMBOL_NS(max_98360a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98360a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index bfe17acbc161f7..72ce32e2cd57d9 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -339,7 +339,7 @@ MODULE_AUTHOR("David Lin "); MODULE_AUTHOR("Mac Chiang "); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_NUVOTON_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_NUVOTON_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); diff --git a/sound/soc/intel/boards/sof_nuvoton_common.c b/sound/soc/intel/boards/sof_nuvoton_common.c index 549a412f5d531a..ed41cb6f7fa594 100644 --- a/sound/soc/intel/boards/sof_nuvoton_common.c +++ b/sound/soc/intel/boards/sof_nuvoton_common.c @@ -67,7 +67,7 @@ void nau8318_set_dai_link(struct snd_soc_dai_link *link) link->num_codecs = ARRAY_SIZE(nau8318_components); link->init = nau8318_init; } -EXPORT_SYMBOL_NS(nau8318_set_dai_link, SND_SOC_INTEL_SOF_NUVOTON_COMMON); +EXPORT_SYMBOL_NS(nau8318_set_dai_link, "SND_SOC_INTEL_SOF_NUVOTON_COMMON"); MODULE_DESCRIPTION("ASoC Intel SOF Nuvoton helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index 8d237f67bd0678..2f43710c1baeda 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -246,12 +246,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_pcm512x_codec_init; links[id].ops = &sof_pcm512x_ops; - links[id].dpcm_playback = 1; /* * capture only supported with specific versions of the Hifiberry DAC+ */ - if (sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE) - links[id].dpcm_capture = 1; + if (!(sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE)) + links[id].playback_only = 1; links[id].no_pcm = 1; links[id].cpus = &cpus[id]; links[id].num_cpus = 1; @@ -294,7 +293,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].ignore_suspend = 1; - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; id++; } @@ -341,7 +340,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_hdmi_init; - links[id].dpcm_playback = 1; + links[id].playback_only = 1; links[id].no_pcm = 1; id++; } @@ -441,4 +440,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF + PCM512x Machine driver"); MODULE_AUTHOR("Pierre-Louis Bossart"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sof_pcm512x"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index f52e2508390588..600707d403b9d5 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -276,7 +276,7 @@ void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link) link->init = rt1011_init; link->ops = &rt1011_ops; } -EXPORT_SYMBOL_NS(sof_rt1011_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1011_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card) { @@ -306,7 +306,7 @@ void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card) } } -EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); /* * rt1015: i2c mode driver for ALC1015 and ALC1015Q @@ -374,12 +374,12 @@ void sof_rt1015p_dai_link(struct snd_soc_dai_link *link) link->init = rt1015p_init; link->ops = &rt1015p_ops; } -EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); void sof_rt1015p_codec_conf(struct snd_soc_card *card) { } -EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); /* * RT1015 audio amplifier @@ -523,7 +523,7 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card) card->codec_conf = rt1015_amp_conf; card->num_configs = ARRAY_SIZE(rt1015_amp_conf); } -EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); void sof_rt1015_dai_link(struct snd_soc_dai_link *link) { @@ -532,7 +532,7 @@ void sof_rt1015_dai_link(struct snd_soc_dai_link *link) link->init = speaker_codec_init_lr; link->ops = &rt1015_ops; } -EXPORT_SYMBOL_NS(sof_rt1015_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1015_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); /* * RT1308 audio amplifier @@ -628,7 +628,7 @@ void sof_rt1308_dai_link(struct snd_soc_dai_link *link) link->init = rt1308_init; link->ops = &rt1308_ops; } -EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1308_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); /* * 2-amp Configuration for RT1019 @@ -681,7 +681,7 @@ void sof_rt1019p_dai_link(struct snd_soc_dai_link *link) link->num_codecs = ARRAY_SIZE(rt1019p_components); link->init = rt1019p_init; } -EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index bc581fea0e3a16..f5925bd0a3fc67 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -870,6 +870,13 @@ static const struct platform_device_id board_ids[] = { SOF_SSP_PORT_BT_OFFLOAD(2) | SOF_BT_OFFLOAD_PRESENT), }, + { + .name = "mtl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), + }, { .name = "arl_rt5682_c1_h02", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | @@ -877,6 +884,14 @@ static const struct platform_device_id board_ids[] = { /* SSP 0 and SSP 2 are used for HDMI IN */ SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, + { + .name = "ptl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); @@ -898,6 +913,6 @@ MODULE_AUTHOR("Sathya Prakash M R "); MODULE_AUTHOR("Brent Lu "); MODULE_AUTHOR("Mac Chiang "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 4a0ab50d1e50dc..f3369e569abc47 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -480,6 +480,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .driver_data = (void *)(SOF_SDW_TGL_HDMI | RT711_JD2), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, { .callback = sof_sdw_quirk_cb, .matches = { @@ -488,6 +496,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, /* MeteorLake devices */ { .callback = sof_sdw_quirk_cb, @@ -572,6 +588,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, { .callback = sof_sdw_quirk_cb, .matches = { @@ -580,6 +604,47 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "3838") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "3832") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "380E") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "233C") + }, + /* Note this quirk excludes the CODEC mic */ + .driver_data = (void *)(SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "233B") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, /* ArrowLake devices */ { @@ -606,6 +671,46 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + /* Pantherlake devices*/ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC), + }, {} }; @@ -741,7 +846,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, cpus, num_cpus, platform_component, ARRAY_SIZE(platform_component), codecs, num_codecs, - asoc_sdw_rtd_init, &sdw_ops); + 1, asoc_sdw_rtd_init, &sdw_ops); /* * SoundWire DAILINKs use 'stream' functions and Bank Switch operations @@ -818,7 +923,7 @@ static int create_ssp_dailinks(struct snd_soc_card *card, playback, capture, cpu_dai_name, platform_component->name, ARRAY_SIZE(platform_component), codec_name, - ssp_info->dais[0].dai_name, NULL, + ssp_info->dais[0].dai_name, 1, NULL, ssp_info->ops); if (ret) return ret; @@ -843,7 +948,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card, 0, 1, // DMIC only supports capture "DMIC01 Pin", platform_component->name, ARRAY_SIZE(platform_component), - "dmic-codec", "dmic-hifi", + "dmic-codec", "dmic-hifi", 1, asoc_sdw_dmic_init, NULL); if (ret) return ret; @@ -854,7 +959,7 @@ static int create_dmic_dailinks(struct snd_soc_card *card, 0, 1, // DMIC only supports capture "DMIC16k Pin", platform_component->name, ARRAY_SIZE(platform_component), - "dmic-codec", "dmic-hifi", + "dmic-codec", "dmic-hifi", 1, /* don't call asoc_sdw_dmic_init() twice */ NULL, NULL); if (ret) @@ -898,7 +1003,7 @@ static int create_hdmi_dailinks(struct snd_soc_card *card, 1, 0, // HDMI only supports playback cpu_dai_name, platform_component->name, ARRAY_SIZE(platform_component), - codec_name, codec_dai_name, + codec_name, codec_dai_name, 1, i == 0 ? sof_sdw_hdmi_init : NULL, NULL); if (ret) return ret; @@ -926,7 +1031,7 @@ static int create_bt_dailinks(struct snd_soc_card *card, 1, 1, cpu_dai_name, platform_component->name, ARRAY_SIZE(platform_component), snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, - NULL, NULL); + 1, NULL, NULL); if (ret) return ret; @@ -962,8 +1067,12 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) return ret; } - /* One per DAI link, worst case is a DAI link for every endpoint */ - sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL); + /* + * One per DAI link, worst case is a DAI link for every endpoint, also + * add one additional to act as a terminator such that code can iterate + * until it hits an uninitialised DAI. + */ + sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL); if (!sof_dais) return -ENOMEM; @@ -1220,5 +1329,5 @@ MODULE_AUTHOR("Bard Liao "); MODULE_AUTHOR("Rander Wang "); MODULE_AUTHOR("Pierre-Louis Bossart "); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); -MODULE_IMPORT_NS(SND_SOC_SDW_UTILS); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index 6ff8895a294a93..48ee5353bdf1c4 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -234,6 +234,6 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver"); MODULE_AUTHOR("Balamurugan C "); MODULE_AUTHOR("Brent Lu "); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_CIRRUS_COMMON"); diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index facc6c32cbfed8..51922347409f0d 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -167,8 +167,6 @@ static struct snd_soc_dai_link dailink[] = { .name = "SSP5-Codec", .id = 0, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &sof_wm8804_ops, SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), }, diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 91e146e2487da2..0afd114be9e5e6 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sst-dsp-y := sst-dsp.o -snd-soc-sst-ipc-y := sst-ipc.o snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \ soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ @@ -18,5 +16,7 @@ snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-matc snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o -obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o +snd-soc-acpi-intel-sdca-quirks-y += soc-acpi-intel-sdca-quirks.o + obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o +obj-$(CONFIG_SND_SOC_ACPI_INTEL_SDCA_QUIRKS) += snd-soc-acpi-intel-sdca-quirks.o diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c index 072b8486d0727c..24d850df77ca8e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -44,6 +44,31 @@ static const struct snd_soc_acpi_endpoint spk_3_endpoint = { .group_id = 1, }; +/* + * RT722 is a multi-function codec, three endpoints are created for + * its headset, amp and dmic functions. + */ +static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + static const struct snd_soc_acpi_adr_device cs35l56_2_lr_adr[] = { { .adr = 0x00023001FA355601ull, @@ -185,6 +210,24 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { + { + .adr = 0x000030025D072201ull, + .num_endpoints = ARRAY_SIZE(rt722_endpoints), + .endpoints = rt722_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_2_single_adr[] = { + { + .adr = 0x000230025D132001ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1320-1" + } +}; + static const struct snd_soc_acpi_link_adr arl_cs42l43_l0[] = { { .mask = BIT(0), @@ -287,6 +330,20 @@ static const struct snd_soc_acpi_link_adr arl_sdca_rvp[] = { {} }; +static const struct snd_soc_acpi_link_adr arl_rt722_l0_rt1320_l2[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_single_adr), + .adr_d = rt1320_2_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_codecs arl_essx_83x6 = { .num_codecs = 3, .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, @@ -385,6 +442,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-rt711-l0.tplg", }, + { + .link_mask = BIT(0) | BIT(2), + .links = arl_rt722_l0_rt1320_l2, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c index 094ed4b27cb068..98a9c36d7a4cd0 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -8,6 +8,7 @@ #include #include +#include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[] = { @@ -90,6 +91,30 @@ static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { }, }; +static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints_endpoints[] = { + /* Jack Endpoint */ + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + /* Amp Endpoint, work as spk_l_endpoint */ + { + .num = 1, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, + /* DMIC Endpoint */ + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { { /* Jack Playback Endpoint */ .num = 0, @@ -198,6 +223,15 @@ static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = { + { + .adr = 0x000230025D071201ull, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints_endpoints, + .name_prefix = "rt712" + } +}; + static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { { .adr = 0x000030025d072201ull, @@ -252,6 +286,15 @@ static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = { + { + .adr = 0x000130025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + static const struct snd_soc_acpi_adr_device rt713_0_adr[] = { { .adr = 0x000031025D071301ull, @@ -410,6 +453,21 @@ static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_l0_rt1318_l1[] = { {} }; +static const struct snd_soc_acpi_link_adr lnl_sdw_rt712_vb_l2_rt1320_l1[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt712_vb_2_group1_adr), + .adr_d = rt712_vb_2_group1_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group1_adr), + .adr_d = rt1320_1_group1_adr, + }, + {} +}; + +/* this table is used when there is no I2S codec present */ /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { /* mockup tests need to be first */ @@ -485,6 +543,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg" }, + { + .link_mask = BIT(1) | BIT(2), + .links = lnl_sdw_rt712_vb_l2_rt1320_l1, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-lnl-rt712-l2-rt1320-l1.tplg" + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index d4435a34a3a3f4..03fc5a1870123f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -6,9 +6,12 @@ * */ +#include +#include #include #include #include +#include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = { @@ -42,6 +45,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + { + .comp_ids = &mtl_rt5682_rt5682s_hp, + .drv_name = "mtl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &mtl_lt6911_hdmi, + .sof_tplg_filename = "sof-mtl-rt5682-ssp1-hdmi-ssp02.tplg", + }, /* place boards for each headphone codec: sof driver will complete the * tplg name and machine driver will detect the amp type */ @@ -126,6 +136,27 @@ static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { }, }; +static const struct snd_soc_acpi_endpoint rt712_vb_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + /* * RT722 is a multi-function codec, three endpoints are created for * its headset, amp and dmic functions. @@ -183,6 +214,15 @@ static const struct snd_soc_acpi_adr_device rt712_0_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt712_vb_0_single_adr[] = { + { + .adr = 0x000030025D071201ull, + .num_endpoints = ARRAY_SIZE(rt712_vb_endpoints), + .endpoints = rt712_vb_endpoints, + .name_prefix = "rt712" + } +}; + static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = { { .adr = 0x000330025D171201ull, @@ -356,6 +396,15 @@ static const struct snd_soc_acpi_link_adr mtl_712_l0[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_712_vb_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt712_vb_0_single_adr), + .adr_d = rt712_vb_0_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { { /* Jack Playback Endpoint */ .num = 0, @@ -767,6 +816,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg", }, + { + .link_mask = BIT(0), + .links = mtl_712_vb_l0, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-mtl-rt712-vb-l0.tplg", + }, { .link_mask = BIT(0), .links = mtl_712_l0, @@ -836,3 +892,5 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines); + +MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index 90f97a44b60707..f1c0d7a02cda38 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -9,8 +9,21 @@ #include #include #include "soc-acpi-intel-sdw-mockup-match.h" +#include + +static const struct snd_soc_acpi_codecs ptl_rt5682_rt5682s_hp = { + .num_codecs = 2, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, +}; struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { + { + .comp_ids = &ptl_rt5682_rt5682s_hp, + .drv_name = "ptl_rt5682_def", + .sof_tplg_filename = "sof-ptl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_machines); @@ -23,10 +36,10 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { }; /* - * RT722 is a multi-function codec, three endpoints are created for - * its headset, amp and dmic functions. + * Multi-function codecs with three endpoints created for + * headset, amp and dmic functions. */ -static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { +static const struct snd_soc_acpi_endpoint rt_mf_endpoints[] = { { .num = 0, .aggregated = 0, @@ -56,11 +69,38 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt721_3_single_adr[] = { + { + .adr = 0x000330025d072101ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt721" + } +}; + +static const struct snd_soc_acpi_link_adr ptl_rt721_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt721_3_single_adr), + .adr_d = rt721_3_single_adr, + }, + {}, +}; + static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { { .adr = 0x000030025d072201ull, - .num_endpoints = ARRAY_SIZE(rt722_endpoints), - .endpoints = rt722_endpoints, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt722_1_single_adr[] = { + { + .adr = 0x000130025d072201ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, .name_prefix = "rt722" } }; @@ -68,8 +108,8 @@ static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { static const struct snd_soc_acpi_adr_device rt722_3_single_adr[] = { { .adr = 0x000330025d072201ull, - .num_endpoints = ARRAY_SIZE(rt722_endpoints), - .endpoints = rt722_endpoints, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, .name_prefix = "rt722" } }; @@ -83,6 +123,15 @@ static const struct snd_soc_acpi_link_adr ptl_rt722_only[] = { {} }; +static const struct snd_soc_acpi_link_adr ptl_rt722_l1[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt722_1_single_adr), + .adr_d = rt722_1_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr ptl_rt722_l3[] = { { .mask = BIT(3), @@ -128,12 +177,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-rt711.tplg", }, + { + .link_mask = BIT(3), + .links = ptl_rt721_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt721.tplg", + }, { .link_mask = BIT(0), .links = ptl_rt722_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-rt722.tplg", }, + { + .link_mask = BIT(1), + .links = ptl_rt722_l1, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", + }, { .link_mask = BIT(3), .links = ptl_rt722_l3, diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c new file mode 100644 index 00000000000000..3eaa058f846085 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-sdca-quirks.c - tables and support for SDCA quirks + * + * Copyright (c) 2024, Intel Corporation. + * + */ + +#include +#include +#include +#include "soc-acpi-intel-sdca-quirks.h" + +/* + * Pretend machine quirk. The argument type is not the traditional + * 'struct snd_soc_acpi_mach' pointer but instead the sdw_intel_ctx + * which contains the peripheral information required for the + * SoundWire/SDCA filter on the SMART_MIC setup and interface + * revision. When the return value is false, the entry in the + * 'snd_soc_acpi_mach' table needs to be skipped. + */ +bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg) +{ + struct sdw_intel_ctx *ctx = arg; + int i; + + if (!ctx) + return false; + + for (i = 0; i < ctx->peripherals->num_peripherals; i++) { + if (sdca_device_quirk_match(ctx->peripherals->array[i], + SDCA_QUIRKS_RT712_VB)) + return true; + } + + return false; +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_sdca_is_device_rt712_vb, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); + +MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_SDCA"); diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h new file mode 100644 index 00000000000000..bead5ec6243f9b --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * soc-acpi-intel-sdca-quirks.h - tables and support for SDCA quirks + * + * Copyright (c) 2024, Intel Corporation. + * + */ + +#ifndef _SND_SOC_ACPI_INTEL_SDCA_QUIRKS +#define _SND_SOC_ACPI_INTEL_SDCA_QUIRKS + +bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg); + +#endif diff --git a/sound/soc/intel/common/soc-acpi-intel-ssp-common.c b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c index de7a3f7f47f104..f56f4bfa518718 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ssp-common.c +++ b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c @@ -90,7 +90,7 @@ snd_soc_acpi_intel_detect_codec_type(struct device *dev) return CODEC_NONE; } -EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_codec_type, SND_SOC_ACPI_INTEL_MATCH); +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_codec_type, "SND_SOC_ACPI_INTEL_MATCH"); enum snd_soc_acpi_intel_codec snd_soc_acpi_intel_detect_amp_type(struct device *dev) @@ -107,7 +107,7 @@ snd_soc_acpi_intel_detect_amp_type(struct device *dev) return CODEC_NONE; } -EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_amp_type, SND_SOC_ACPI_INTEL_MATCH); +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_amp_type, "SND_SOC_ACPI_INTEL_MATCH"); const char * snd_soc_acpi_intel_get_codec_name(enum snd_soc_acpi_intel_codec codec_type) @@ -129,7 +129,7 @@ snd_soc_acpi_intel_get_codec_name(enum snd_soc_acpi_intel_codec codec_type) return NULL; } -EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_name, SND_SOC_ACPI_INTEL_MATCH); +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_name, "SND_SOC_ACPI_INTEL_MATCH"); const char * snd_soc_acpi_intel_get_codec_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type) @@ -145,7 +145,7 @@ snd_soc_acpi_intel_get_codec_tplg_suffix(enum snd_soc_acpi_intel_codec codec_typ return NULL; } -EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_tplg_suffix, SND_SOC_ACPI_INTEL_MATCH); +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_tplg_suffix, "SND_SOC_ACPI_INTEL_MATCH"); const char * snd_soc_acpi_intel_get_amp_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type) @@ -161,7 +161,7 @@ snd_soc_acpi_intel_get_amp_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type) return NULL; } -EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_amp_tplg_suffix, SND_SOC_ACPI_INTEL_MATCH); +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_amp_tplg_suffix, "SND_SOC_ACPI_INTEL_MATCH"); MODULE_DESCRIPTION("ASoC Intel SOF Common Machine Driver Helpers"); MODULE_AUTHOR("Brent Lu "); diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h deleted file mode 100644 index de32bb9afccbdd..00000000000000 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Smart Sound Technology - * - * Copyright (C) 2013, Intel Corporation - */ - -#ifndef __SOUND_SOC_SST_DSP_PRIV_H -#define __SOUND_SOC_SST_DSP_PRIV_H - -#include -#include -#include -#include - -#include "../skylake/skl-sst-dsp.h" - -/* - * DSP Operations exported by platform Audio DSP driver. - */ -struct sst_ops { - /* Shim IO */ - void (*write)(void __iomem *addr, u32 offset, u32 value); - u32 (*read)(void __iomem *addr, u32 offset); - - /* IRQ handlers */ - irqreturn_t (*irq_handler)(int irq, void *context); - - /* SST init and free */ - int (*init)(struct sst_dsp *sst); - void (*free)(struct sst_dsp *sst); -}; - -/* - * Audio DSP memory offsets and addresses. - */ -struct sst_addr { - u32 sram0_base; - u32 sram1_base; - u32 w0_stat_sz; - u32 w0_up_sz; - void __iomem *lpe; - void __iomem *shim; -}; - -/* - * Audio DSP Mailbox configuration. - */ -struct sst_mailbox { - void __iomem *in_base; - void __iomem *out_base; - size_t in_size; - size_t out_size; -}; - -/* - * Generic SST Shim Interface. - */ -struct sst_dsp { - - /* Shared for all platforms */ - - /* runtime */ - struct sst_dsp_device *sst_dev; - spinlock_t spinlock; /* IPC locking */ - struct mutex mutex; /* DSP FW lock */ - struct device *dev; - void *thread_context; - int irq; - u32 id; - - /* operations */ - struct sst_ops *ops; - - /* debug FS */ - struct dentry *debugfs_root; - - /* base addresses */ - struct sst_addr addr; - - /* mailbox */ - struct sst_mailbox mailbox; - - /* SST FW files loaded and their modules */ - struct list_head module_list; - - /* SKL data */ - - const char *fw_name; - - /* To allocate CL dma buffers */ - struct skl_dsp_loader_ops dsp_ops; - struct skl_dsp_fw_ops fw_ops; - int sst_state; - struct skl_cl_dev cl_dev; - u32 intr_status; - const struct firmware *fw; - struct snd_dma_buffer dmab; -}; - -#endif diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c deleted file mode 100644 index cdd2f7cf50ae51..00000000000000 --- a/sound/soc/intel/common/sst-dsp.c +++ /dev/null @@ -1,250 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Smart Sound Technology (SST) DSP Core Driver - * - * Copyright (C) 2013, Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "sst-dsp.h" -#include "sst-dsp-priv.h" - -#define CREATE_TRACE_POINTS -#include - -/* Internal generic low-level SST IO functions - can be overidden */ -void sst_shim32_write(void __iomem *addr, u32 offset, u32 value) -{ - writel(value, addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_write); - -u32 sst_shim32_read(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_read); - -void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value) -{ - writeq(value, addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_write64); - -u64 sst_shim32_read64(void __iomem *addr, u32 offset) -{ - return readq(addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_read64); - -/* Public API */ -void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value) -{ - unsigned long flags; - - spin_lock_irqsave(&sst->spinlock, flags); - sst->ops->write(sst->addr.shim, offset, value); - spin_unlock_irqrestore(&sst->spinlock, flags); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_write); - -u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset) -{ - unsigned long flags; - u32 val; - - spin_lock_irqsave(&sst->spinlock, flags); - val = sst->ops->read(sst->addr.shim, offset); - spin_unlock_irqrestore(&sst->spinlock, flags); - - return val; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_read); - -void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value) -{ - sst->ops->write(sst->addr.shim, offset, value); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked); - -u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset) -{ - return sst->ops->read(sst->addr.shim, offset); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked); - -int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - bool change; - unsigned int old, new; - u32 ret; - - ret = sst_dsp_shim_read_unlocked(sst, offset); - - old = ret; - new = (old & (~mask)) | (value & mask); - - change = (old != new); - if (change) - sst_dsp_shim_write_unlocked(sst, offset, new); - - return change; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked); - -/* This is for registers bits with attribute RWC */ -void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned int old, new; - u32 ret; - - ret = sst_dsp_shim_read_unlocked(sst, offset); - - old = ret; - new = (old & (~mask)) | (value & mask); - - sst_dsp_shim_write_unlocked(sst, offset, new); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked); - -int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned long flags; - bool change; - - spin_lock_irqsave(&sst->spinlock, flags); - change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value); - spin_unlock_irqrestore(&sst->spinlock, flags); - return change; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits); - -/* This is for registers bits with attribute RWC */ -void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned long flags; - - spin_lock_irqsave(&sst->spinlock, flags); - sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value); - spin_unlock_irqrestore(&sst->spinlock, flags); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced); - -int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, - u32 target, u32 time, char *operation) -{ - u32 reg; - unsigned long timeout; - int k = 0, s = 500; - - /* - * split the loop into sleeps of varying resolution. more accurately, - * the range of wakeups are: - * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. - * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms - * (usleep_range (500, 1000) and usleep_range(5000, 10000) are - * both possible in this phase depending on whether k > 10 or not). - * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms. - */ - - timeout = jiffies + msecs_to_jiffies(time); - while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target) - && time_before(jiffies, timeout)) { - k++; - if (k > 10) - s = 5000; - - usleep_range(s, 2*s); - } - - if ((reg & mask) == target) { - dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n", - reg, operation); - - return 0; - } - - dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n", - reg, operation); - return -ETIME; -} -EXPORT_SYMBOL_GPL(sst_dsp_register_poll); - -int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size, - u32 outbox_offset, size_t outbox_size) -{ - sst->mailbox.in_base = sst->addr.lpe + inbox_offset; - sst->mailbox.out_base = sst->addr.lpe + outbox_offset; - sst->mailbox.in_size = inbox_size; - sst->mailbox.out_size = outbox_size; - return 0; -} -EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init); - -void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_outbox_write(bytes); - - memcpy_toio(sst->mailbox.out_base, message, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_outbox_write); - -void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_outbox_read(bytes); - - memcpy_fromio(message, sst->mailbox.out_base, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_outbox_read); - -void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_inbox_write(bytes); - - memcpy_toio(sst->mailbox.in_base, message, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_inbox_write); - -void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_inbox_read(bytes); - - memcpy_fromio(message, sst->mailbox.in_base, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); - -/* Module information */ -MODULE_AUTHOR("Liam Girdwood"); -MODULE_DESCRIPTION("Intel SST Core"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h deleted file mode 100644 index 998b1a05228167..00000000000000 --- a/sound/soc/intel/common/sst-dsp.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Smart Sound Technology (SST) Core - * - * Copyright (C) 2013, Intel Corporation - */ - -#ifndef __SOUND_SOC_SST_DSP_H -#define __SOUND_SOC_SST_DSP_H - -#include -#include -#include - -struct sst_dsp; - -/* - * SST Device. - * - * This structure is populated by the SST core driver. - */ -struct sst_dsp_device { - /* Mandatory fields */ - struct sst_ops *ops; - irqreturn_t (*thread)(int irq, void *context); - void *thread_context; -}; - -/* SHIM Read / Write */ -void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value); -u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset); -int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); -void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); - -/* SHIM Read / Write Unlocked for callers already holding sst lock */ -void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value); -u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset); -int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); -void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); - -/* Internal generic low-level SST IO functions - can be overidden */ -void sst_shim32_write(void __iomem *addr, u32 offset, u32 value); -u32 sst_shim32_read(void __iomem *addr, u32 offset); -void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value); -u64 sst_shim32_read64(void __iomem *addr, u32 offset); - -/* Mailbox management */ -int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, - size_t inbox_size, u32 outbox_offset, size_t outbox_size); -void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes); -int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, - u32 target, u32 time, char *operation); - -#endif diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c deleted file mode 100644 index 6b2c83f9f01079..00000000000000 --- a/sound/soc/intel/common/sst-ipc.c +++ /dev/null @@ -1,294 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel SST generic IPC Support - * - * Copyright (C) 2015, Intel Corporation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sst-dsp.h" -#include "sst-dsp-priv.h" -#include "sst-ipc.h" - -/* IPC message timeout (msecs) */ -#define IPC_TIMEOUT_MSECS 300 - -#define IPC_EMPTY_LIST_SIZE 8 - -/* locks held by caller */ -static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc) -{ - struct ipc_message *msg = NULL; - - if (!list_empty(&ipc->empty_list)) { - msg = list_first_entry(&ipc->empty_list, struct ipc_message, - list); - list_del(&msg->list); - } - - return msg; -} - -static int tx_wait_done(struct sst_generic_ipc *ipc, - struct ipc_message *msg, struct sst_ipc_message *reply) -{ - unsigned long flags; - int ret; - - /* wait for DSP completion (in all cases atm inc pending) */ - ret = wait_event_timeout(msg->waitq, msg->complete, - msecs_to_jiffies(IPC_TIMEOUT_MSECS)); - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - if (ret == 0) { - if (ipc->ops.shim_dbg != NULL) - ipc->ops.shim_dbg(ipc, "message timeout"); - - list_del(&msg->list); - ret = -ETIMEDOUT; - } else { - - /* copy the data returned from DSP */ - if (reply) { - reply->header = msg->rx.header; - if (reply->data) - memcpy(reply->data, msg->rx.data, msg->rx.size); - } - ret = msg->errno; - } - - list_add_tail(&msg->list, &ipc->empty_list); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return ret; -} - -static int ipc_tx_message(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, - struct sst_ipc_message *reply, int wait) -{ - struct ipc_message *msg; - unsigned long flags; - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - - msg = msg_get_empty(ipc); - if (msg == NULL) { - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return -EBUSY; - } - - msg->tx.header = request.header; - msg->tx.size = request.size; - msg->rx.header = 0; - msg->rx.size = reply ? reply->size : 0; - msg->wait = wait; - msg->errno = 0; - msg->pending = false; - msg->complete = false; - - if ((request.size) && (ipc->ops.tx_data_copy != NULL)) - ipc->ops.tx_data_copy(msg, request.data, request.size); - - list_add_tail(&msg->list, &ipc->tx_list); - schedule_work(&ipc->kwork); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - - if (wait) - return tx_wait_done(ipc, msg, reply); - else - return 0; -} - -static int msg_empty_list_init(struct sst_generic_ipc *ipc) -{ - int i; - - ipc->msg = kcalloc(IPC_EMPTY_LIST_SIZE, sizeof(struct ipc_message), - GFP_KERNEL); - if (ipc->msg == NULL) - return -ENOMEM; - - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - ipc->msg[i].tx.data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].tx.data == NULL) - goto free_mem; - - ipc->msg[i].rx.data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].rx.data == NULL) { - kfree(ipc->msg[i].tx.data); - goto free_mem; - } - - init_waitqueue_head(&ipc->msg[i].waitq); - list_add(&ipc->msg[i].list, &ipc->empty_list); - } - - return 0; - -free_mem: - while (i > 0) { - kfree(ipc->msg[i-1].tx.data); - kfree(ipc->msg[i-1].rx.data); - --i; - } - kfree(ipc->msg); - - return -ENOMEM; -} - -static void ipc_tx_msgs(struct work_struct *work) -{ - struct sst_generic_ipc *ipc = - container_of(work, struct sst_generic_ipc, kwork); - struct ipc_message *msg; - - spin_lock_irq(&ipc->dsp->spinlock); - - while (!list_empty(&ipc->tx_list) && !ipc->pending) { - /* if the DSP is busy, we will TX messages after IRQ. - * also postpone if we are in the middle of processing - * completion irq - */ - if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { - dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); - break; - } - - msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); - list_move(&msg->list, &ipc->rx_list); - - if (ipc->ops.tx_msg != NULL) - ipc->ops.tx_msg(ipc, msg); - } - - spin_unlock_irq(&ipc->dsp->spinlock); -} - -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply) -{ - int ret; - - /* - * DSP maybe in lower power active state, so - * check if the DSP supports DSP lp On method - * if so invoke that before sending IPC - */ - if (ipc->ops.check_dsp_lp_on) - if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) - return -EIO; - - ret = ipc_tx_message(ipc, request, reply, 1); - - if (ipc->ops.check_dsp_lp_on) - if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) - return -EIO; - - return ret; -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); - -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request) -{ - return ipc_tx_message(ipc, request, NULL, 0); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); - -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply) -{ - return ipc_tx_message(ipc, request, reply, 1); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); - -struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, - u64 header) -{ - struct ipc_message *msg; - u64 mask; - - if (ipc->ops.reply_msg_match != NULL) - header = ipc->ops.reply_msg_match(header, &mask); - else - mask = (u64)-1; - - if (list_empty(&ipc->rx_list)) { - dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n", - header); - return NULL; - } - - list_for_each_entry(msg, &ipc->rx_list, list) { - if ((msg->tx.header & mask) == header) - return msg; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(sst_ipc_reply_find_msg); - -/* locks held by caller */ -void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, - struct ipc_message *msg) -{ - msg->complete = true; - - if (!msg->wait) - list_add_tail(&msg->list, &ipc->empty_list); - else - wake_up(&msg->waitq); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_msg_reply_complete); - -int sst_ipc_init(struct sst_generic_ipc *ipc) -{ - int ret; - - INIT_LIST_HEAD(&ipc->tx_list); - INIT_LIST_HEAD(&ipc->rx_list); - INIT_LIST_HEAD(&ipc->empty_list); - init_waitqueue_head(&ipc->wait_txq); - - ret = msg_empty_list_init(ipc); - if (ret < 0) - return -ENOMEM; - - INIT_WORK(&ipc->kwork, ipc_tx_msgs); - return 0; -} -EXPORT_SYMBOL_GPL(sst_ipc_init); - -void sst_ipc_fini(struct sst_generic_ipc *ipc) -{ - int i; - - cancel_work_sync(&ipc->kwork); - - if (ipc->msg) { - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - kfree(ipc->msg[i].tx.data); - kfree(ipc->msg[i].rx.data); - } - kfree(ipc->msg); - } -} -EXPORT_SYMBOL_GPL(sst_ipc_fini); - -/* Module information */ -MODULE_AUTHOR("Jin Yao"); -MODULE_DESCRIPTION("Intel SST IPC generic"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h deleted file mode 100644 index 86d44ceadc9263..00000000000000 --- a/sound/soc/intel/common/sst-ipc.h +++ /dev/null @@ -1,86 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel SST generic IPC Support - * - * Copyright (C) 2015, Intel Corporation - */ - -#ifndef __SST_GENERIC_IPC_H -#define __SST_GENERIC_IPC_H - -#include -#include -#include -#include -#include -#include - -struct sst_ipc_message { - u64 header; - void *data; - size_t size; -}; - -struct ipc_message { - struct list_head list; - struct sst_ipc_message tx; - struct sst_ipc_message rx; - - wait_queue_head_t waitq; - bool pending; - bool complete; - bool wait; - int errno; -}; - -struct sst_generic_ipc; -struct sst_dsp; - -struct sst_plat_ipc_ops { - void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *); - void (*shim_dbg)(struct sst_generic_ipc *, const char *); - void (*tx_data_copy)(struct ipc_message *, char *, size_t); - u64 (*reply_msg_match)(u64 header, u64 *mask); - bool (*is_dsp_busy)(struct sst_dsp *dsp); - int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state); -}; - -/* SST generic IPC data */ -struct sst_generic_ipc { - struct device *dev; - struct sst_dsp *dsp; - - /* IPC messaging */ - struct list_head tx_list; - struct list_head rx_list; - struct list_head empty_list; - wait_queue_head_t wait_txq; - struct task_struct *tx_thread; - struct work_struct kwork; - bool pending; - struct ipc_message *msg; - int tx_data_max_size; - int rx_data_max_size; - - struct sst_plat_ipc_ops ops; -}; - -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply); - -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request); - -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply); - -struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, - u64 header); - -void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, - struct ipc_message *msg); - -int sst_ipc_init(struct sst_generic_ipc *ipc); -void sst_ipc_fini(struct sst_generic_ipc *ipc); - -#endif diff --git a/sound/soc/loongson/Kconfig b/sound/soc/loongson/Kconfig index b8d7e2bade246f..2d8291c1443ccd 100644 --- a/sound/soc/loongson/Kconfig +++ b/sound/soc/loongson/Kconfig @@ -1,11 +1,23 @@ # SPDX-License-Identifier: GPL-2.0 menu "SoC Audio for Loongson CPUs" + +config SND_SOC_LOONGSON_CARD + tristate "Loongson Sound Card Driver" depends on LOONGARCH || COMPILE_TEST + select SND_SOC_LOONGSON_I2S_PCI if PCI + select SND_SOC_LOONGSON_I2S_PLATFORM if OF + help + Say Y or M if you want to add support for SoC audio using + loongson I2S controller. + + The driver add support for ALSA SoC Audio support using + loongson I2S controller. config SND_SOC_LOONGSON_I2S_PCI tristate "Loongson I2S-PCI Device Driver" - select REGMAP_MMIO + depends on LOONGARCH || COMPILE_TEST depends on PCI + select REGMAP_MMIO help Say Y or M if you want to add support for I2S driver for Loongson I2S controller. @@ -13,15 +25,15 @@ config SND_SOC_LOONGSON_I2S_PCI The controller is found in loongson bridge chips or SoCs, and work as a PCI device. -config SND_SOC_LOONGSON_CARD - tristate "Loongson Sound Card Driver" - select SND_SOC_LOONGSON_I2S_PCI - depends on PCI +config SND_SOC_LOONGSON_I2S_PLATFORM + tristate "Loongson I2S-PLAT Device Driver" + depends on LOONGARCH || COMPILE_TEST + select REGMAP_MMIO + select SND_SOC_GENERIC_DMAENGINE_PCM help - Say Y or M if you want to add support for SoC audio using - loongson I2S controller. - - The driver add support for ALSA SoC Audio support using - loongson I2S controller. + Say Y or M if you want to add support for I2S driver for + Loongson I2S controller. + The controller work as a platform device, we can found it in + Loongson-2K1000 SoCs. endmenu diff --git a/sound/soc/loongson/Makefile b/sound/soc/loongson/Makefile index 578030ad6563cf..c0cb1acb36e347 100644 --- a/sound/soc/loongson/Makefile +++ b/sound/soc/loongson/Makefile @@ -1,7 +1,12 @@ # SPDX-License-Identifier: GPL-2.0 #Platform Support -snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_i2s.o loongson_dma.o -obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o +snd-soc-loongson-i2s-pci-y := loongson_i2s_pci.o loongson_dma.o +obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PCI) += snd-soc-loongson-i2s-pci.o snd-soc-loongson-i2s.o + +snd-soc-loongson-i2s-plat-y := loongson_i2s_plat.o +obj-$(CONFIG_SND_SOC_LOONGSON_I2S_PLATFORM) += snd-soc-loongson-i2s-plat.o snd-soc-loongson-i2s.o + +snd-soc-loongson-i2s-y := loongson_i2s.o #Machine Support snd-soc-loongson-card-y := loongson_card.o diff --git a/sound/soc/loongson/loongson_i2s.c b/sound/soc/loongson/loongson_i2s.c index 40bbf320539186..e8852a30f213f0 100644 --- a/sound/soc/loongson/loongson_i2s.c +++ b/sound/soc/loongson/loongson_i2s.c @@ -246,6 +246,7 @@ struct snd_soc_dai_driver loongson_i2s_dai = { .ops = &loongson_i2s_dai_ops, .symmetric_rate = 1, }; +EXPORT_SYMBOL_GPL(loongson_i2s_dai); static int i2s_suspend(struct device *dev) { @@ -268,3 +269,7 @@ static int i2s_resume(struct device *dev) const struct dev_pm_ops loongson_i2s_pm = { SYSTEM_SLEEP_PM_OPS(i2s_suspend, i2s_resume) }; +EXPORT_SYMBOL_GPL(loongson_i2s_pm); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Common functions for loongson I2S controller driver"); diff --git a/sound/soc/loongson/loongson_i2s_plat.c b/sound/soc/loongson/loongson_i2s_plat.c new file mode 100644 index 00000000000000..fa2e450ff618d4 --- /dev/null +++ b/sound/soc/loongson/loongson_i2s_plat.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Loongson I2S controller master mode dirver(platform device) +// +// Copyright (C) 2023-2024 Loongson Technology Corporation Limited +// +// Author: Yingkun Meng +// Binbin Zhou + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "loongson_i2s.h" + +#define LOONGSON_I2S_RX_DMA_OFFSET 21 +#define LOONGSON_I2S_TX_DMA_OFFSET 18 + +#define LOONGSON_DMA0_CONF 0x0 +#define LOONGSON_DMA1_CONF 0x1 +#define LOONGSON_DMA2_CONF 0x2 +#define LOONGSON_DMA3_CONF 0x3 +#define LOONGSON_DMA4_CONF 0x4 + +/* periods_max = PAGE_SIZE / sizeof(struct ls_dma_chan_reg) */ +static const struct snd_pcm_hardware loongson_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE, + .period_bytes_min = 128, + .period_bytes_max = 128 * 1024, + .periods_min = 1, + .periods_max = 64, + .buffer_bytes_max = 1024 * 1024, +}; + +static const struct snd_dmaengine_pcm_config loongson_dmaengine_pcm_config = { + .pcm_hardware = &loongson_pcm_hardware, + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .prealloc_buffer_size = 128 * 1024, +}; + +static int loongson_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + if (substream->pcm->device & 1) { + runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; + runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; + } + + if (substream->pcm->device & 2) + runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID); + /* + * For mysterious reasons (and despite what the manual says) + * playback samples are lost if the DMA count is not a multiple + * of the DMA burst size. Let's add a rule to enforce that. + */ + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128); + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + return 0; +} + +static const struct snd_soc_component_driver loongson_i2s_component_driver = { + .name = LS_I2S_DRVNAME, + .open = loongson_pcm_open, +}; + +static const struct regmap_config loongson_i2s_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x14, + .cache_type = REGCACHE_FLAT, +}; + +static int loongson_i2s_apbdma_config(struct platform_device *pdev) +{ + int val; + void __iomem *regs; + + regs = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + val = readl(regs); + val |= LOONGSON_DMA2_CONF << LOONGSON_I2S_TX_DMA_OFFSET; + val |= LOONGSON_DMA3_CONF << LOONGSON_I2S_RX_DMA_OFFSET; + writel(val, regs); + + return 0; +} + +static int loongson_i2s_plat_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct loongson_i2s *i2s; + struct resource *res; + struct clk *i2s_clk; + int ret; + + i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + ret = loongson_i2s_apbdma_config(pdev); + if (ret) + return ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2s->reg_base)) + return dev_err_probe(dev, PTR_ERR(i2s->reg_base), + "devm_ioremap_resource failed\n"); + + i2s->regmap = devm_regmap_init_mmio(dev, i2s->reg_base, + &loongson_i2s_regmap_config); + if (IS_ERR(i2s->regmap)) + return dev_err_probe(dev, PTR_ERR(i2s->regmap), + "devm_regmap_init_mmio failed\n"); + + i2s->playback_dma_data.addr = res->start + LS_I2S_TX_DATA; + i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + i2s->playback_dma_data.maxburst = 4; + + i2s->capture_dma_data.addr = res->start + LS_I2S_RX_DATA; + i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + i2s->capture_dma_data.maxburst = 4; + + i2s_clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(i2s_clk)) + return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n"); + i2s->clk_rate = clk_get_rate(i2s_clk); + + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + dev_set_name(dev, LS_I2S_DRVNAME); + dev_set_drvdata(dev, i2s); + + ret = devm_snd_soc_register_component(dev, &loongson_i2s_component_driver, + &loongson_i2s_dai, 1); + if (ret) + return dev_err_probe(dev, ret, "failed to register DAI\n"); + + return devm_snd_dmaengine_pcm_register(dev, &loongson_dmaengine_pcm_config, + SND_DMAENGINE_PCM_FLAG_COMPAT); +} + +static const struct of_device_id loongson_i2s_ids[] = { + { .compatible = "loongson,ls2k1000-i2s" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, loongson_i2s_ids); + +static struct platform_driver loongson_i2s_driver = { + .probe = loongson_i2s_plat_probe, + .driver = { + .name = "loongson-i2s-plat", + .pm = pm_sleep_ptr(&loongson_i2s_pm), + .of_match_table = loongson_i2s_ids, + }, +}; +module_platform_driver(loongson_i2s_driver); + +MODULE_DESCRIPTION("Loongson I2S Master Mode ASoC Driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 4974b0536b7bb6..00a79867235d24 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -221,7 +221,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST}, .ops = &mt2701_cs42448_48k_fe_ops, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(fe_multi_ch_out), }, [DAI_LINK_FE_PCM0_IN] = { @@ -231,7 +231,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST}, .ops = &mt2701_cs42448_48k_fe_ops, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(fe_pcm0_in), }, [DAI_LINK_FE_PCM1_IN] = { @@ -241,7 +241,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST}, .ops = &mt2701_cs42448_48k_fe_ops, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(fe_pcm1_in), }, [DAI_LINK_FE_BT_OUT] = { @@ -250,7 +250,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(fe_bt_out), }, [DAI_LINK_FE_BT_IN] = { @@ -259,7 +259,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(fe_bt_in), }, /* BE */ @@ -269,8 +269,6 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_i2s0), }, [DAI_LINK_BE_I2S1] = { @@ -279,8 +277,6 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_i2s1), }, [DAI_LINK_BE_I2S2] = { @@ -289,8 +285,6 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_i2s2), }, [DAI_LINK_BE_I2S3] = { @@ -299,15 +293,11 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_i2s3), }, [DAI_LINK_BE_MRG_BT] = { .name = "mt2701-cs42448-MRG-BT", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(be_mrg_bt), }, }; diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index 8a6643bfe830e3..2814f0570928f2 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -67,7 +67,7 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, { @@ -76,7 +76,7 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, /* BE */ @@ -86,8 +86,6 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, .ops = &mt2701_wm8960_be_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, }; diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index 784c201b8fd4b8..daad9544a8d413 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -78,7 +78,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_1), }, { @@ -87,7 +87,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_2), }, { @@ -96,7 +96,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_3), }, { @@ -105,7 +105,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_1), }, { @@ -114,7 +114,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_2), }, { @@ -123,7 +123,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_3), }, { @@ -132,7 +132,7 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono_1), }, { @@ -141,8 +141,6 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_lpbk), }, @@ -152,8 +150,6 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_speech), }, @@ -161,24 +157,18 @@ static struct snd_soc_dai_link mt6797_mt6351_dai_links[] = { { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(primary_codec), }, { .name = "PCM 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "PCM 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm2), }, diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c index 6982e833421d63..c3d1e2eeb0e571 100644 --- a/sound/soc/mediatek/mt7986/mt7986-wm8960.c +++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c @@ -45,7 +45,7 @@ static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, { @@ -54,7 +54,7 @@ static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, /* BE */ @@ -65,8 +65,6 @@ static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_GATED, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 0557a287c641a3..0724564cee6a6a 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -104,7 +104,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = { .stream_name = "MAX98090 Playback", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, { @@ -112,7 +112,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = { .stream_name = "MAX98090 Capture", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, /* Back End DAI links */ @@ -123,8 +123,6 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = { .ops = &mt8173_max98090_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(hifi), }, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 4ed06c26906524..d8e4e70d834cec 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -139,7 +139,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { .stream_name = "rt5650_rt5514 Playback", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, [DAI_LINK_CAPTURE] = { @@ -147,7 +147,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { .stream_name = "rt5650_rt5514 Capture", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, /* Back End DAI links */ @@ -159,8 +159,6 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { SND_SOC_DAIFMT_CBS_CFS, .ops = &mt8173_rt5650_rt5514_ops, .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 763067c211539c..488f2314dbf78e 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -171,7 +171,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .stream_name = "rt5650_rt5676 Playback", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, [DAI_LINK_CAPTURE] = { @@ -179,7 +179,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .stream_name = "rt5650_rt5676 Capture", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, [DAI_LINK_HDMI] = { @@ -187,7 +187,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .stream_name = "HDMI PCM", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(hdmi_pcm), }, @@ -200,14 +200,12 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { SND_SOC_DAIFMT_CBS_CFS, .ops = &mt8173_rt5650_rt5676_ops, .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, [DAI_LINK_HDMI_I2S] = { .name = "HDMI BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(hdmi_be), }, /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 466f176f8e9480..59c19fdd867581 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -210,7 +210,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { .stream_name = "rt5650 Playback", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback), }, [DAI_LINK_CAPTURE] = { @@ -218,7 +218,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { .stream_name = "rt5650 Capture", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture), }, [DAI_LINK_HDMI] = { @@ -226,7 +226,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { .stream_name = "HDMI PCM", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(hdmi_pcm), }, /* Back End DAI links */ @@ -238,14 +238,12 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { SND_SOC_DAIFMT_CBS_CFS, .ops = &mt8173_rt5650_ops, .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(codec), }, [DAI_LINK_HDMI_I2S] = { .name = "HDMI BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .init = mt8173_rt5650_hdmi_init, SND_SOC_DAILINK_REG(hdmi_be), }, diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index f848e14b091a15..1d8881e0a361ac 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -425,7 +425,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8183_da7219_max98357_ops, SND_SOC_DAILINK_REG(playback1), }, @@ -435,7 +435,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8183_da7219_max98357_bt_sco_ops, SND_SOC_DAILINK_REG(playback2), }, @@ -445,7 +445,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback3), }, { @@ -454,7 +454,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8183_da7219_max98357_bt_sco_ops, SND_SOC_DAILINK_REG(capture1), }, @@ -464,7 +464,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture2), }, { @@ -473,7 +473,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8183_da7219_max98357_ops, SND_SOC_DAILINK_REG(capture3), }, @@ -483,7 +483,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono), }, { @@ -492,38 +492,32 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_hdmi), }, /* BE */ { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(primary_codec), }, { .name = "PCM 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "PCM 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm2), }, { .name = "I2S0", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -532,7 +526,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { { .name = "I2S1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -541,7 +535,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { { .name = "I2S2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_da7219_i2s_ops, @@ -551,13 +545,13 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { { .name = "I2S3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, }, { .name = "I2S5", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -570,7 +564,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ignore = 1, diff --git a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c index 65e46ebe7be6c6..5cf5592336d33f 100644 --- a/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c +++ b/sound/soc/mediatek/mt8183/mt8183-dai-i2s.c @@ -1036,7 +1036,6 @@ static int mt8183_dai_i2s_set_priv(struct mtk_base_afe *afe) int mt8183_dai_i2s_register(struct mtk_base_afe *afe) { struct mtk_base_afe_dai *dai; - int ret; dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); if (!dai) @@ -1055,9 +1054,5 @@ int mt8183_dai_i2s_register(struct mtk_base_afe *afe) dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_i2s_routes); /* set all dai i2s private data */ - ret = mt8183_dai_i2s_set_priv(afe); - if (ret) - return ret; - - return 0; + return mt8183_dai_i2s_set_priv(afe); } diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index bb6df056a8789b..6267c8554c1522 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -430,7 +430,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8183_mt6358_ops, SND_SOC_DAILINK_REG(playback1), }, @@ -440,7 +440,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops, SND_SOC_DAILINK_REG(playback2), }, @@ -450,7 +450,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback3), }, { @@ -459,7 +459,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8183_mt6358_ts3a227_max98357_bt_sco_ops, SND_SOC_DAILINK_REG(capture1), }, @@ -469,7 +469,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture2), }, { @@ -478,7 +478,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8183_mt6358_ops, SND_SOC_DAILINK_REG(capture3), }, @@ -488,7 +488,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono), }, { @@ -497,7 +497,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_hdmi), }, { @@ -513,31 +513,25 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(primary_codec), }, { .name = "PCM 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "PCM 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm2), }, { .name = "I2S0", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .ops = &mt8183_mt6358_i2s_ops, SND_SOC_DAILINK_REG(i2s0), @@ -545,7 +539,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { { .name = "I2S1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -554,7 +548,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { { .name = "I2S2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_i2s_ops, @@ -564,13 +558,13 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { { .name = "I2S3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, }, { .name = "I2S5", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .ops = &mt8183_mt6358_i2s_ops, .init = &mt8183_bt_init, @@ -582,7 +576,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, .ops = &mt8183_mt6358_tdm_ops, diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c index 771d53611c2a41..a5ef913743d4e6 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c @@ -647,7 +647,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -660,7 +660,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback12), }, { @@ -669,7 +669,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -681,7 +681,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -694,7 +694,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback4), }, { @@ -703,7 +703,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback5), }, { @@ -712,7 +712,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback6), }, { @@ -721,7 +721,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback7), }, { @@ -730,7 +730,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback8), }, { @@ -739,7 +739,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture1), }, { @@ -748,7 +748,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -761,7 +761,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture3), }, { @@ -770,7 +770,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -783,7 +783,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture5), }, { @@ -792,7 +792,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_format = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, @@ -804,7 +804,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture7), }, { @@ -813,8 +813,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_lpbk), }, @@ -824,8 +822,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_fm), }, @@ -835,8 +831,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_src1), }, @@ -846,8 +840,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_src_bargein), }, @@ -857,7 +849,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_hw_gain_aaudio), }, @@ -867,8 +859,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_src_aaudio), }, @@ -876,8 +866,6 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, .init = primary_codec_init, SND_SOC_DAILINK_REG(adda), @@ -888,7 +876,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .init = mt8186_mt6366_rt1019_rt5682s_hdmi_init, SND_SOC_DAILINK_REG(i2s3), @@ -896,7 +884,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "I2S0", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .ops = &mt8186_rt5682s_i2s_ops, SND_SOC_DAILINK_REG(i2s0), @@ -904,7 +892,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "I2S1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .init = mt8186_headset_codec_init, SND_SOC_DAILINK_REG(i2s1), @@ -912,46 +900,38 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "I2S2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(i2s2), }, { .name = "HW Gain 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hw_gain1), }, { .name = "HW Gain 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hw_gain2), }, { .name = "HW_SRC_1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hw_src1), }, { .name = "HW_SRC_2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hw_src2), }, { .name = "CONNSYS_I2S", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(connsys_i2s), }, @@ -960,15 +940,13 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "TDM IN", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(tdm_in), }, @@ -976,35 +954,35 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "Hostless_UL1", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul1), }, { .name = "Hostless_UL2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul2), }, { .name = "Hostless_UL3", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul3), }, { .name = "Hostless_UL5", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul5), }, { .name = "Hostless_UL6", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(hostless_ul6), }, @@ -1012,25 +990,25 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { { .name = "AFE_SOF_DL1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(AFE_SOF_DL1), }, { .name = "AFE_SOF_DL2", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(AFE_SOF_DL2), }, { .name = "AFE_SOF_UL1", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(AFE_SOF_UL1), }, { .name = "AFE_SOF_UL2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(AFE_SOF_UL2), }, }; diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c index 8a17d1935c48f1..43670316611e9a 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-adda.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-adda.c @@ -63,7 +63,6 @@ static int mt8188_adda_mtkaif_init(struct mtk_base_afe *afe) param->mtkaif_phase_cycle[MT8188_MTKAIF_MISO_0]; } - val = 0; mask = (MTKAIF_RXIF_DELAY_DATA | MTKAIF_RXIF_DELAY_CYCLE_MASK); val |= FIELD_PREP(MTKAIF_RXIF_DELAY_CYCLE_MASK, delay_cycle); val |= FIELD_PREP(MTKAIF_RXIF_DELAY_DATA, delay_data); diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c index 2a48f5fd6826c6..69a091dad88dd5 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-etdm.c @@ -2422,7 +2422,6 @@ static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream, unsigned int channels = params_channels(params); snd_pcm_format_t format = params_format(params); int width = snd_pcm_format_physical_width(format); - int ret; if (!is_valid_etdm_dai(dai->id)) return -EINVAL; @@ -2450,9 +2449,7 @@ static int mtk_dai_hdmitx_dptx_hw_params(struct snd_pcm_substream *substream, etdm_data->data_mode = MTK_DAI_ETDM_DATA_MULTI_PIN; } - ret = mtk_dai_etdm_configure(afe, rate, channels, width, dai->id); - - return ret; + return mtk_dai_etdm_configure(afe, rate, channels, width, dai->id); } static int mtk_dai_hdmitx_dptx_set_sysclk(struct snd_soc_dai *dai, diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c index 5bc854a8f3df34..8ca7cc75e21dc8 100644 --- a/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c +++ b/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c @@ -128,7 +128,7 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, unsigned int lrck_inv; unsigned int bck_inv; unsigned int fmt; - unsigned int bit_width = dai->sample_bits; + unsigned int bit_width = dai->symmetric_sample_bits; unsigned int val = 0; unsigned int mask = 0; int fs = 0; diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index 08ae962afeb929..2d0d04e0232da0 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -188,9 +188,7 @@ SND_SOC_DAILINK_DEFS(pcm1, SND_SOC_DAILINK_DEFS(ul_src, DAILINK_COMP_ARRAY(COMP_CPU("UL_SRC")), DAILINK_COMP_ARRAY(COMP_CODEC("mt6359-sound", - "mt6359-snd-codec-aif1"), - COMP_CODEC("dmic-codec", - "dmic-hifi")), + "mt6359-snd-codec-aif1")), DAILINK_COMP_ARRAY(COMP_EMPTY())); SND_SOC_DAILINK_DEFS(AFE_SOF_DL2, @@ -932,7 +930,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -946,7 +944,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -960,7 +958,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -974,7 +972,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback7), }, [DAI_LINK_DL8_FE] = { @@ -985,7 +983,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback8), }, [DAI_LINK_DL10_FE] = { @@ -996,7 +994,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback10), }, [DAI_LINK_DL11_FE] = { @@ -1007,7 +1005,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback11), }, [DAI_LINK_UL1_FE] = { @@ -1018,7 +1016,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture1), }, [DAI_LINK_UL2_FE] = { @@ -1029,7 +1027,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture2), }, [DAI_LINK_UL3_FE] = { @@ -1040,7 +1038,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture3), }, [DAI_LINK_UL4_FE] = { @@ -1051,7 +1049,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -1065,7 +1063,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_chan = 1, .dpcm_merged_rate = 1, .dpcm_merged_format = 1, @@ -1079,7 +1077,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture6), }, [DAI_LINK_UL8_FE] = { @@ -1090,7 +1088,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture8), }, [DAI_LINK_UL9_FE] = { @@ -1101,7 +1099,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture9), }, [DAI_LINK_UL10_FE] = { @@ -1112,14 +1110,14 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture10), }, /* BE */ [DAI_LINK_DL_SRC_BE] = { .name = "DL_SRC_BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(dl_src), }, [DAI_LINK_DPTX_BE] = { @@ -1127,7 +1125,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .ops = &mt8188_dptx_ops, .be_hw_params_fixup = mt8188_dptx_hw_params_fixup, .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(dptx), }, [DAI_LINK_ETDM1_IN_BE] = { @@ -1136,7 +1134,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(etdm1_in), }, @@ -1146,7 +1144,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(etdm2_in), }, [DAI_LINK_ETDM1_OUT_BE] = { @@ -1155,7 +1153,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(etdm1_out), }, [DAI_LINK_ETDM2_OUT_BE] = { @@ -1164,7 +1162,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(etdm2_out), }, [DAI_LINK_ETDM3_OUT_BE] = { @@ -1173,7 +1171,7 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(etdm3_out), }, [DAI_LINK_PCM1_BE] = { @@ -1182,14 +1180,12 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(pcm1), }, [DAI_LINK_UL_SRC_BE] = { .name = "UL_SRC_BE", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(ul_src), }, @@ -1197,28 +1193,28 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { [DAI_LINK_SOF_DL2_BE] = { .name = "AFE_SOF_DL2", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8188_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_DL2), }, [DAI_LINK_SOF_DL3_BE] = { .name = "AFE_SOF_DL3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8188_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_DL3), }, [DAI_LINK_SOF_UL4_BE] = { .name = "AFE_SOF_UL4", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8188_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_UL4), }, [DAI_LINK_SOF_UL5_BE] = { .name = "AFE_SOF_UL5", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8188_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_UL5), }, @@ -1279,10 +1275,12 @@ static int mt8188_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, for_each_card_prelinks(card, i, dai_link) { if (strcmp(dai_link->name, "DPTX_BE") == 0) { - if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + if (dai_link->num_codecs && + strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) dai_link->init = mt8188_dptx_codec_init; } else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { - if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + if (dai_link->num_codecs && + strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) dai_link->init = mt8188_hdmi_codec_init; } else if (strcmp(dai_link->name, "DL_SRC_BE") == 0 || strcmp(dai_link->name, "UL_SRC_BE") == 0) { @@ -1294,6 +1292,9 @@ static int mt8188_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, strcmp(dai_link->name, "ETDM2_OUT_BE") == 0 || strcmp(dai_link->name, "ETDM1_IN_BE") == 0 || strcmp(dai_link->name, "ETDM2_IN_BE") == 0) { + if (!dai_link->num_codecs) + continue; + if (!strcmp(dai_link->codecs->dai_name, MAX98390_CODEC_DAI)) { /* * The TDM protocol settings with fixed 4 slots are defined in diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index db00704e206d6d..b1598cc5587e30 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -598,7 +598,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback1), }, { @@ -607,7 +607,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback12), }, { @@ -616,7 +616,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback2), }, { @@ -625,7 +625,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(playback3), }, @@ -635,7 +635,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback4), }, { @@ -644,7 +644,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback5), }, { @@ -653,7 +653,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback6), }, { @@ -662,7 +662,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback7), }, { @@ -671,7 +671,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback8), }, { @@ -680,7 +680,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback9), }, { @@ -689,7 +689,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(capture1), }, @@ -699,7 +699,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(capture2), }, @@ -709,7 +709,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture3), }, { @@ -718,7 +718,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture4), }, { @@ -727,7 +727,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture5), }, { @@ -736,7 +736,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture6), }, { @@ -745,7 +745,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture7), }, { @@ -754,7 +754,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture8), }, { @@ -763,7 +763,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono1), }, { @@ -772,7 +772,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono2), }, { @@ -781,7 +781,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(capture_mono3), }, { @@ -790,15 +790,13 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .trigger = {SND_SOC_DPCM_TRIGGER_PRE, SND_SOC_DPCM_TRIGGER_PRE}, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(playback_hdmi), }, /* Back End DAI links */ { .name = "Primary Codec", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, .init = mt8192_mt6359_init, SND_SOC_DAILINK_REG(primary_codec), @@ -806,29 +804,27 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "Primary Codec CH34", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(primary_codec_ch34), }, { .name = "AP_DMIC", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(ap_dmic), }, { .name = "AP_DMIC_CH34", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(ap_dmic_ch34), }, { .name = "I2S0", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s0), @@ -836,7 +832,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S1", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s1), @@ -844,7 +840,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S2", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s2), @@ -852,7 +848,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s3), @@ -860,7 +856,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S5", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s5), @@ -868,7 +864,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S6", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s6), @@ -876,7 +872,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S7", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s7), @@ -884,7 +880,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S8", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, .init = mt8192_rt5682_init, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, @@ -894,7 +890,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "I2S9", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, SND_SOC_DAILINK_REG(i2s9), @@ -903,23 +899,19 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { { .name = "CONNSYS_I2S", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(connsys_i2s), }, { .name = "PCM 1", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm1), }, { .name = "PCM 2", .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ignore_suspend = 1, SND_SOC_DAILINK_REG(pcm2), }, @@ -929,7 +921,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM, - .dpcm_playback = 1, + .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, .ignore = 1, @@ -1099,7 +1091,7 @@ static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data) dai_link->ignore = 0; } - if (dai_link->num_codecs && dai_link->codecs[0].dai_name && + if (dai_link->num_codecs && strcmp(dai_link->codecs[0].dai_name, RT1015_CODEC_DAI) == 0) dai_link->ops = &mt8192_rt1015_i2s_ops; } @@ -1127,7 +1119,7 @@ static int mt8192_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, int i; for_each_card_prelinks(card, i, dai_link) - if (dai_link->num_codecs && dai_link->codecs[0].dai_name && + if (dai_link->num_codecs && strcmp(dai_link->codecs[0].dai_name, RT1015_CODEC_DAI) == 0) dai_link->ops = &mt8192_rt1015_i2s_ops; } diff --git a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c index 6d6d79300d5121..cdc16057d50e2f 100644 --- a/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-dai-pcm.c @@ -127,7 +127,7 @@ static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream, unsigned int lrck_inv; unsigned int bck_inv; unsigned int fmt; - unsigned int bit_width = dai->sample_bits; + unsigned int bit_width = dai->symmetric_sample_bits; unsigned int val = 0; unsigned int mask = 0; int fs = 0; diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 2832ef78eaed72..2b9cb3248795b8 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -913,7 +913,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL2_FE), }, @@ -925,7 +925,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL3_FE), }, @@ -937,7 +937,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL6_FE), }, @@ -949,7 +949,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(DL7_FE), }, [DAI_LINK_DL8_FE] = { @@ -960,7 +960,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL8_FE), }, @@ -972,7 +972,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8195_hdmitx_dptx_playback_ops, SND_SOC_DAILINK_REG(DL10_FE), }, @@ -984,7 +984,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mtk_soundcard_common_playback_ops, SND_SOC_DAILINK_REG(DL11_FE), }, @@ -996,7 +996,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(UL1_FE), }, [DAI_LINK_UL2_FE] = { @@ -1007,7 +1007,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL2_FE), }, @@ -1019,7 +1019,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL3_FE), }, @@ -1031,7 +1031,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL4_FE), }, @@ -1043,7 +1043,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL5_FE), }, @@ -1055,7 +1055,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_PRE, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(UL6_FE), }, [DAI_LINK_UL8_FE] = { @@ -1066,7 +1066,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL8_FE), }, @@ -1078,7 +1078,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL9_FE), }, @@ -1090,7 +1090,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { SND_SOC_DPCM_TRIGGER_POST, }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mtk_soundcard_common_capture_ops, SND_SOC_DAILINK_REG(UL10_FE), }, @@ -1098,13 +1098,13 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { [DAI_LINK_DL_SRC_BE] = { .name = "DL_SRC_BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(DL_SRC_BE), }, [DAI_LINK_DPTX_BE] = { .name = "DPTX_BE", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8195_dptx_ops, .be_hw_params_fixup = mt8195_dptx_hw_params_fixup, SND_SOC_DAILINK_REG(DPTX_BE), @@ -1115,7 +1115,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(ETDM1_IN_BE), }, [DAI_LINK_ETDM2_IN_BE] = { @@ -1124,7 +1124,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_capture = 1, + .capture_only = 1, .be_hw_params_fixup = mt8195_etdm_hw_params_fixup, SND_SOC_DAILINK_REG(ETDM2_IN_BE), }, @@ -1134,7 +1134,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, + .playback_only = 1, .be_hw_params_fixup = mt8195_etdm_hw_params_fixup, SND_SOC_DAILINK_REG(ETDM1_OUT_BE), }, @@ -1144,7 +1144,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(ETDM2_OUT_BE), }, [DAI_LINK_ETDM3_OUT_BE] = { @@ -1153,7 +1153,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(ETDM3_OUT_BE), }, [DAI_LINK_PCM1_BE] = { @@ -1162,48 +1162,46 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(PCM1_BE), }, [DAI_LINK_UL_SRC1_BE] = { .name = "UL_SRC1_BE", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(UL_SRC1_BE), }, [DAI_LINK_UL_SRC2_BE] = { .name = "UL_SRC2_BE", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(UL_SRC2_BE), }, /* SOF BE */ [DAI_LINK_SOF_DL2_BE] = { .name = "AFE_SOF_DL2", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8195_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_DL2), }, [DAI_LINK_SOF_DL3_BE] = { .name = "AFE_SOF_DL3", .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &mt8195_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_DL3), }, [DAI_LINK_SOF_UL4_BE] = { .name = "AFE_SOF_UL4", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8195_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_UL4), }, [DAI_LINK_SOF_UL5_BE] = { .name = "AFE_SOF_UL5", .no_pcm = 1, - .dpcm_capture = 1, + .capture_only = 1, .ops = &mt8195_sof_be_ops, SND_SOC_DAILINK_REG(AFE_SOF_UL5), }, @@ -1380,10 +1378,12 @@ static int mt8195_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, for_each_card_prelinks(card, i, dai_link) { if (strcmp(dai_link->name, "DPTX_BE") == 0) { - if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + if (dai_link->num_codecs && + strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) dai_link->init = mt8195_dptx_codec_init; } else if (strcmp(dai_link->name, "ETDM3_OUT_BE") == 0) { - if (strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) + if (dai_link->num_codecs && + strcmp(dai_link->codecs->dai_name, "snd-soc-dummy-dai")) dai_link->init = mt8195_hdmi_codec_init; } else if (strcmp(dai_link->name, "DL_SRC_BE") == 0 || strcmp(dai_link->name, "UL_SRC1_BE") == 0 || @@ -1396,6 +1396,9 @@ static int mt8195_mt6359_soc_card_probe(struct mtk_soc_card_data *soc_card_data, strcmp(dai_link->name, "ETDM2_OUT_BE") == 0 || strcmp(dai_link->name, "ETDM1_IN_BE") == 0 || strcmp(dai_link->name, "ETDM2_IN_BE") == 0) { + if (!dai_link->num_codecs) + continue; + if (!strcmp(dai_link->codecs->dai_name, MAX98390_CODEC_DAI)) { if (!(codec_init & MAX98390_CODEC_INIT)) { dai_link->init = mt8195_max98390_init; diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c index f9945c2a2cd13c..0bac143b48bfb3 100644 --- a/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c +++ b/sound/soc/mediatek/mt8365/mt8365-dai-dmic.c @@ -118,13 +118,13 @@ static int mt8365_dai_configure_dmic(struct mtk_base_afe *afe, unsigned int clk_phase_sel_ch1 = dmic_data->clk_phase_sel_ch1; unsigned int clk_phase_sel_ch2 = dmic_data->clk_phase_sel_ch2; unsigned int val = 0; - unsigned int rate = dai->rate; - int reg = get_chan_reg(dai->channels); + unsigned int rate = dai->symmetric_rate; + int reg = get_chan_reg(dai->symmetric_channels); if (reg < 0) return -EINVAL; - dmic_data->dmic_channel = dai->channels; + dmic_data->dmic_channel = dai->symmetric_channels; val |= DMIC_TOP_CON_SDM3_LEVEL_MODE; diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c index f85ec07249c3b7..3373b88da28eaa 100644 --- a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c +++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c @@ -44,7 +44,7 @@ static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream, bool lrck_inv = pcm_priv->lrck_inv; bool bck_inv = pcm_priv->bck_inv; unsigned int fmt = pcm_priv->format; - unsigned int bit_width = dai->sample_bits; + unsigned int bit_width = dai->symmetric_sample_bits; unsigned int val = 0; if (!slave_mode) { diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c index 42cbdfdfadb558..d398e83ea05281 100644 --- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c +++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c @@ -168,7 +168,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_rate = 1, SND_SOC_DAILINK_REG(playback1), }, @@ -181,7 +181,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .dpcm_merged_rate = 1, SND_SOC_DAILINK_REG(playback2), }, @@ -194,7 +194,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_rate = 1, SND_SOC_DAILINK_REG(awb_capture), }, @@ -207,7 +207,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dynamic = 1, - .dpcm_capture = 1, + .capture_only = 1, .dpcm_merged_rate = 1, SND_SOC_DAILINK_REG(vul), }, @@ -219,23 +219,19 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(i2s3), }, [DAI_LINK_DMIC] = { .name = "DMIC_BE", .no_pcm = 1, .id = DAI_LINK_DMIC, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(dmic), }, [DAI_LINK_INT_ADDA] = { .name = "MTK_Codec", .no_pcm = 1, .id = DAI_LINK_INT_ADDA, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &mt8365_mt6357_int_adda_ops, SND_SOC_DAILINK_REG(primary_codec), }, diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 5ebf287fe7004e..a2dfccb7990f3a 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -43,7 +43,7 @@ static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs); } @@ -56,7 +56,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd) { struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; struct snd_soc_dai *codec_dai; int ret, i; @@ -86,7 +86,7 @@ static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd) { struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct axg_dai_link_tdm_data *be = - (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num]; + (struct axg_dai_link_tdm_data *)priv->link_data[rtd->id]; int ret; /* The loopback rx_mask is the pad tx_mask */ diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 62057c71f742e6..09103eef2a9797 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -442,14 +442,18 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { .stream_name = "Playback", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .id = TDM_IFACE_PAD, @@ -461,7 +465,9 @@ static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = { .stream_name = "Loopback", .channels_min = 1, .channels_max = AXG_TDM_CHANNEL_MAX, - .rates = AXG_TDM_RATES, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 768000, .formats = AXG_TDM_FORMATS, }, .id = TDM_IFACE_LOOPBACK, diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h index 1a17f546ce6e80..acfcd48f8a0028 100644 --- a/sound/soc/meson/axg-tdm.h +++ b/sound/soc/meson/axg-tdm.h @@ -15,8 +15,6 @@ #define AXG_TDM_NUM_LANES 4 #define AXG_TDM_CHANNEL_MAX 128 -#define AXG_TDM_RATES (SNDRV_PCM_RATE_5512 | \ - SNDRV_PCM_RATE_8000_768000) #define AXG_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S20_LE | \ diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c index 455f6bfc9f8fa5..b408cc2bbc9193 100644 --- a/sound/soc/meson/gx-card.c +++ b/sound/soc/meson/gx-card.c @@ -32,7 +32,7 @@ static int gx_card_i2s_be_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct meson_card *priv = snd_soc_card_get_drvdata(rtd->card); struct gx_dai_link_i2s_data *be = - (struct gx_dai_link_i2s_data *)priv->link_data[rtd->num]; + (struct gx_dai_link_i2s_data *)priv->link_data[rtd->id]; return meson_card_i2s_set_sysclk(substream, params, be->mclk_fs); } diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 922ecada1cd8d9..3113773171761a 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -190,6 +190,7 @@ static const struct of_device_id snd_sc8280xp_dt_match[] = { {.compatible = "qcom,sm8450-sndcard", "sm8450"}, {.compatible = "qcom,sm8550-sndcard", "sm8550"}, {.compatible = "qcom,sm8650-sndcard", "sm8650"}, + {.compatible = "qcom,sm8750-sndcard", "sm8750"}, {} }; diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 19adadedc88a2a..45e0c33fc3f376 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -63,6 +63,14 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_fmt(cpu_dai, fmt); snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; + case SECONDARY_MI2S_RX: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, fmt); + snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + break; case TERTIARY_MI2S_RX: codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; snd_soc_dai_set_sysclk(cpu_dai, @@ -78,7 +86,7 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) return qcom_snd_sdw_startup(substream); } -static void sm2450_snd_shutdown(struct snd_pcm_substream *substream) +static void sm8250_snd_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); @@ -123,7 +131,7 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) static const struct snd_soc_ops sm8250_be_ops = { .startup = sm8250_snd_startup, - .shutdown = sm2450_snd_shutdown, + .shutdown = sm8250_snd_shutdown, .hw_params = sm8250_snd_hw_params, .hw_free = sm8250_snd_hw_free, .prepare = sm8250_snd_prepare, diff --git a/sound/soc/qcom/x1e80100.c b/sound/soc/qcom/x1e80100.c index 898b5c26bf1ee6..8eb57fc12f0dab 100644 --- a/sound/soc/qcom/x1e80100.c +++ b/sound/soc/qcom/x1e80100.c @@ -95,23 +95,53 @@ static int x1e80100_snd_hw_params(struct snd_pcm_substream *substream, return qcom_snd_sdw_hw_params(substream, params, &data->sruntime[cpu_dai->id]); } +static int x1e80100_snd_hw_map_channels(unsigned int *ch_map, int num) +{ + switch (num) { + case 1: + ch_map[0] = PCM_CHANNEL_FC; + break; + case 2: + ch_map[0] = PCM_CHANNEL_FL; + ch_map[1] = PCM_CHANNEL_FR; + break; + case 3: + ch_map[0] = PCM_CHANNEL_FL; + ch_map[1] = PCM_CHANNEL_FR; + ch_map[2] = PCM_CHANNEL_FC; + break; + case 4: + ch_map[0] = PCM_CHANNEL_FL; + ch_map[1] = PCM_CHANNEL_LB; + ch_map[2] = PCM_CHANNEL_FR; + ch_map[3] = PCM_CHANNEL_RB; + break; + default: + return -EINVAL; + } + + return 0; +} + static int x1e80100_snd_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card); struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; - const unsigned int rx_slot[4] = { PCM_CHANNEL_FL, - PCM_CHANNEL_LB, - PCM_CHANNEL_FR, - PCM_CHANNEL_RB }; + unsigned int channels = substream->runtime->channels; + unsigned int rx_slot[4]; int ret; switch (cpu_dai->id) { case WSA_CODEC_DMA_RX_0: case WSA_CODEC_DMA_RX_1: + ret = x1e80100_snd_hw_map_channels(rx_slot, channels); + if (ret) + return ret; + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, - ARRAY_SIZE(rx_slot), rx_slot); + channels, rx_slot); if (ret) return ret; break; diff --git a/sound/soc/renesas/Kconfig b/sound/soc/renesas/Kconfig new file mode 100644 index 00000000000000..426632996a0a31 --- /dev/null +++ b/sound/soc/renesas/Kconfig @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0 +menu "SoC Audio support for Renesas SoCs" + depends on SUPERH || ARCH_RENESAS || COMPILE_TEST + +config SND_SOC_PCM_SH7760 + tristate "SoC Audio support for Renesas SH7760" + depends on CPU_SUBTYPE_SH7760 && SH_DMABRG + help + Enable this option for SH7760 AC97/I2S audio support. + + +## +## Audio unit modules +## + +config SND_SOC_SH4_HAC + tristate + select AC97_BUS + select SND_SOC_AC97_BUS + +config SND_SOC_SH4_SSI + tristate + +config SND_SOC_SH4_FSI + tristate "SH4 FSI support" + depends on SUPERH || COMMON_CLK + select SND_SIMPLE_CARD + help + This option enables FSI sound support + +config SND_SOC_SH4_SIU + tristate + depends on ARCH_SHMOBILE && HAVE_CLK + depends on DMADEVICES + select DMA_ENGINE + select SH_DMAE + select FW_LOADER + +config SND_SOC_RCAR + tristate "R-Car series SRU/SCU/SSIU/SSI support" + depends on COMMON_CLK + depends on OF + select SND_SIMPLE_CARD_UTILS + select SND_DMAENGINE_PCM + select REGMAP_MMIO + help + This option enables R-Car SRU/SCU/SSIU/SSI sound support + +config SND_SOC_RZ + tristate "RZ/G2L series SSIF-2 support" + depends on ARCH_RZG2L || COMPILE_TEST + help + This option enables RZ/G2L SSIF-2 sound support. + +## +## Boards +## + +config SND_SH7760_AC97 + tristate "SH7760 AC97 sound support" + depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760 + select SND_SOC_SH4_HAC + select SND_SOC_AC97_CODEC + help + This option enables generic sound support for the first + AC97 unit of the SH7760. + +config SND_SIU_MIGOR + tristate "SIU sound support on Migo-R" + depends on SH_MIGOR && I2C + select SND_SOC_SH4_SIU + select SND_SOC_WM8978 + help + This option enables sound support for the SH7722 Migo-R board + +endmenu diff --git a/sound/soc/renesas/Makefile b/sound/soc/renesas/Makefile new file mode 100644 index 00000000000000..f0e19cbd1581b8 --- /dev/null +++ b/sound/soc/renesas/Makefile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 +## DMA engines +snd-soc-dma-sh7760-y := dma-sh7760.o +obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o + +## audio units found on some SH-4 +snd-soc-hac-y := hac.o +snd-soc-ssi-y := ssi.o +snd-soc-fsi-y := fsi.o +snd-soc-siu-y := siu_pcm.o siu_dai.o +obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o +obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o +obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o +obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o + +## audio units for R-Car +obj-$(CONFIG_SND_SOC_RCAR) += rcar/ + +## boards +snd-soc-sh7760-ac97-y := sh7760-ac97.o +snd-soc-migor-y := migor.o + +obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o +obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o + +# RZ/G2L +snd-soc-rz-ssi-y := rz-ssi.o +obj-$(CONFIG_SND_SOC_RZ) += snd-soc-rz-ssi.o diff --git a/sound/soc/renesas/dma-sh7760.c b/sound/soc/renesas/dma-sh7760.c new file mode 100644 index 00000000000000..c53539482c208b --- /dev/null +++ b/sound/soc/renesas/dma-sh7760.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// SH7760 ("camelot") DMABRG audio DMA unit support +// +// Copyright (C) 2007 Manuel Lauss +// +// The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which +// trigger an interrupt when one half of the programmed transfer size +// has been xmitted. +// +// FIXME: little-endian only for now + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* registers and bits */ +#define BRGATXSAR 0x00 +#define BRGARXDAR 0x04 +#define BRGATXTCR 0x08 +#define BRGARXTCR 0x0C +#define BRGACR 0x10 +#define BRGATXTCNT 0x14 +#define BRGARXTCNT 0x18 + +#define ACR_RAR (1 << 18) +#define ACR_RDS (1 << 17) +#define ACR_RDE (1 << 16) +#define ACR_TAR (1 << 2) +#define ACR_TDS (1 << 1) +#define ACR_TDE (1 << 0) + +/* receiver/transmitter data alignment */ +#define ACR_RAM_NONE (0 << 24) +#define ACR_RAM_4BYTE (1 << 24) +#define ACR_RAM_2WORD (2 << 24) +#define ACR_TAM_NONE (0 << 8) +#define ACR_TAM_4BYTE (1 << 8) +#define ACR_TAM_2WORD (2 << 8) + + +struct camelot_pcm { + unsigned long mmio; /* DMABRG audio channel control reg MMIO */ + unsigned int txid; /* ID of first DMABRG IRQ for this unit */ + + struct snd_pcm_substream *tx_ss; + unsigned long tx_period_size; + unsigned int tx_period; + + struct snd_pcm_substream *rx_ss; + unsigned long rx_period_size; + unsigned int rx_period; + +} cam_pcm_data[2] = { + { + .mmio = 0xFE3C0040, + .txid = DMABRGIRQ_A0TXF, + }, + { + .mmio = 0xFE3C0060, + .txid = DMABRGIRQ_A1TXF, + }, +}; + +#define BRGREG(x) (*(unsigned long *)(cam->mmio + (x))) + +/* + * set a minimum of 16kb per period, to avoid interrupt-"storm" and + * resulting skipping. In general, the bigger the minimum size, the + * better for overall system performance. (The SH7760 is a puny CPU + * with a slow SDRAM interface and poor internal bus bandwidth, + * *especially* when the LCDC is active). The minimum for the DMAC + * is 8 bytes; 16kbytes are enough to get skip-free playback of a + * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain + * reasonable responsiveness in MPlayer. + */ +#define DMABRG_PERIOD_MIN 16 * 1024 +#define DMABRG_PERIOD_MAX 0x03fffffc +#define DMABRG_PREALLOC_BUFFER 32 * 1024 +#define DMABRG_PREALLOC_BUFFER_MAX 32 * 1024 + +static const struct snd_pcm_hardware camelot_pcm_hardware = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH), + .buffer_bytes_max = DMABRG_PERIOD_MAX, + .period_bytes_min = DMABRG_PERIOD_MIN, + .period_bytes_max = DMABRG_PERIOD_MAX / 2, + .periods_min = 2, + .periods_max = 2, + .fifo_size = 128, +}; + +static void camelot_txdma(void *data) +{ + struct camelot_pcm *cam = data; + cam->tx_period ^= 1; + snd_pcm_period_elapsed(cam->tx_ss); +} + +static void camelot_rxdma(void *data) +{ + struct camelot_pcm *cam = data; + cam->rx_period ^= 1; + snd_pcm_period_elapsed(cam->rx_ss); +} + +static int camelot_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; + int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; + int ret, dmairq; + + snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware); + + /* DMABRG buffer half/full events */ + dmairq = (recv) ? cam->txid + 2 : cam->txid; + if (recv) { + cam->rx_ss = substream; + ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam); + if (unlikely(ret)) { + pr_debug("audio unit %d irqs already taken!\n", + snd_soc_rtd_to_cpu(rtd, 0)->id); + return -EBUSY; + } + (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam); + } else { + cam->tx_ss = substream; + ret = dmabrg_request_irq(dmairq, camelot_txdma, cam); + if (unlikely(ret)) { + pr_debug("audio unit %d irqs already taken!\n", + snd_soc_rtd_to_cpu(rtd, 0)->id); + return -EBUSY; + } + (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam); + } + return 0; +} + +static int camelot_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; + int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; + int dmairq; + + dmairq = (recv) ? cam->txid + 2 : cam->txid; + + if (recv) + cam->rx_ss = NULL; + else + cam->tx_ss = NULL; + + dmabrg_free_irq(dmairq + 1); + dmabrg_free_irq(dmairq); + + return 0; +} + +static int camelot_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; + int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; + + if (recv) { + cam->rx_period_size = params_period_bytes(hw_params); + cam->rx_period = 0; + } else { + cam->tx_period_size = params_period_bytes(hw_params); + cam->tx_period = 0; + } + return 0; +} + +static int camelot_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; + + pr_debug("PCM data: addr %pad len %zu\n", &runtime->dma_addr, + runtime->dma_bytes); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area; + BRGREG(BRGATXTCR) = runtime->dma_bytes; + } else { + BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area; + BRGREG(BRGARXTCR) = runtime->dma_bytes; + } + + return 0; +} + +static inline void dmabrg_play_dma_start(struct camelot_pcm *cam) +{ + unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS); + /* start DMABRG engine: XFER start, auto-addr-reload */ + BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD; +} + +static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam) +{ + unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS); + /* forcibly terminate data transmission */ + BRGREG(BRGACR) = acr | ACR_TDS; +} + +static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam) +{ + unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS); + /* start DMABRG engine: recv start, auto-reload */ + BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD; +} + +static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam) +{ + unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS); + /* forcibly terminate data receiver */ + BRGREG(BRGACR) = acr | ACR_RDS; +} + +static int camelot_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; + int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (recv) + dmabrg_rec_dma_start(cam); + else + dmabrg_play_dma_start(cam); + break; + case SNDRV_PCM_TRIGGER_STOP: + if (recv) + dmabrg_rec_dma_stop(cam); + else + dmabrg_play_dma_stop(cam); + break; + default: + return -EINVAL; + } + + return 0; +} + +static snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; + int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; + unsigned long pos; + + /* cannot use the DMABRG pointer register: under load, by the + * time ALSA comes around to read the register, it is already + * far ahead (or worse, already done with the fragment) of the + * position at the time the IRQ was triggered, which results in + * fast-playback sound in my test application (ScummVM) + */ + if (recv) + pos = cam->rx_period ? cam->rx_period_size : 0; + else + pos = cam->tx_period ? cam->tx_period_size : 0; + + return bytes_to_frames(runtime, pos); +} + +static int camelot_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_pcm *pcm = rtd->pcm; + + /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel + * in MMAP mode (i.e. aplay -M) + */ + snd_pcm_set_managed_buffer_all(pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + NULL, + DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX); + + return 0; +} + +static const struct snd_soc_component_driver sh7760_soc_component = { + .open = camelot_pcm_open, + .close = camelot_pcm_close, + .hw_params = camelot_hw_params, + .prepare = camelot_prepare, + .trigger = camelot_trigger, + .pointer = camelot_pos, + .pcm_construct = camelot_pcm_new, +}; + +static int sh7760_soc_platform_probe(struct platform_device *pdev) +{ + return devm_snd_soc_register_component(&pdev->dev, &sh7760_soc_component, + NULL, 0); +} + +static struct platform_driver sh7760_pcm_driver = { + .driver = { + .name = "sh7760-pcm-audio", + }, + + .probe = sh7760_soc_platform_probe, +}; + +module_platform_driver(sh7760_pcm_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver"); +MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c new file mode 100644 index 00000000000000..221ce91f195005 --- /dev/null +++ b/sound/soc/renesas/fsi.c @@ -0,0 +1,2119 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Fifo-attached Serial Interface (FSI) support for SH7724 +// +// Copyright (C) 2009 Renesas Solutions Corp. +// Kuninori Morimoto +// +// Based on ssi.c +// Copyright (c) 2007 Manuel Lauss + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PortA/PortB register */ +#define REG_DO_FMT 0x0000 +#define REG_DOFF_CTL 0x0004 +#define REG_DOFF_ST 0x0008 +#define REG_DI_FMT 0x000C +#define REG_DIFF_CTL 0x0010 +#define REG_DIFF_ST 0x0014 +#define REG_CKG1 0x0018 +#define REG_CKG2 0x001C +#define REG_DIDT 0x0020 +#define REG_DODT 0x0024 +#define REG_MUTE_ST 0x0028 +#define REG_OUT_DMAC 0x002C +#define REG_OUT_SEL 0x0030 +#define REG_IN_DMAC 0x0038 + +/* master register */ +#define MST_CLK_RST 0x0210 +#define MST_SOFT_RST 0x0214 +#define MST_FIFO_SZ 0x0218 + +/* core register (depend on FSI version) */ +#define A_MST_CTLR 0x0180 +#define B_MST_CTLR 0x01A0 +#define CPU_INT_ST 0x01F4 +#define CPU_IEMSK 0x01F8 +#define CPU_IMSK 0x01FC +#define INT_ST 0x0200 +#define IEMSK 0x0204 +#define IMSK 0x0208 + +/* DO_FMT */ +/* DI_FMT */ +#define CR_BWS_MASK (0x3 << 20) /* FSI2 */ +#define CR_BWS_24 (0x0 << 20) /* FSI2 */ +#define CR_BWS_16 (0x1 << 20) /* FSI2 */ +#define CR_BWS_20 (0x2 << 20) /* FSI2 */ + +#define CR_DTMD_PCM (0x0 << 8) /* FSI2 */ +#define CR_DTMD_SPDIF_PCM (0x1 << 8) /* FSI2 */ +#define CR_DTMD_SPDIF_STREAM (0x2 << 8) /* FSI2 */ + +#define CR_MONO (0x0 << 4) +#define CR_MONO_D (0x1 << 4) +#define CR_PCM (0x2 << 4) +#define CR_I2S (0x3 << 4) +#define CR_TDM (0x4 << 4) +#define CR_TDM_D (0x5 << 4) + +/* OUT_DMAC */ +/* IN_DMAC */ +#define VDMD_MASK (0x3 << 4) +#define VDMD_FRONT (0x0 << 4) /* Package in front */ +#define VDMD_BACK (0x1 << 4) /* Package in back */ +#define VDMD_STREAM (0x2 << 4) /* Stream mode(16bit * 2) */ + +#define DMA_ON (0x1 << 0) + +/* DOFF_CTL */ +/* DIFF_CTL */ +#define IRQ_HALF 0x00100000 +#define FIFO_CLR 0x00000001 + +/* DOFF_ST */ +#define ERR_OVER 0x00000010 +#define ERR_UNDER 0x00000001 +#define ST_ERR (ERR_OVER | ERR_UNDER) + +/* CKG1 */ +#define ACKMD_MASK 0x00007000 +#define BPFMD_MASK 0x00000700 +#define DIMD (1 << 4) +#define DOMD (1 << 0) + +/* A/B MST_CTLR */ +#define BP (1 << 4) /* Fix the signal of Biphase output */ +#define SE (1 << 0) /* Fix the master clock */ + +/* CLK_RST */ +#define CRB (1 << 4) +#define CRA (1 << 0) + +/* IO SHIFT / MACRO */ +#define BI_SHIFT 12 +#define BO_SHIFT 8 +#define AI_SHIFT 4 +#define AO_SHIFT 0 +#define AB_IO(param, shift) (param << shift) + +/* SOFT_RST */ +#define PBSR (1 << 12) /* Port B Software Reset */ +#define PASR (1 << 8) /* Port A Software Reset */ +#define IR (1 << 4) /* Interrupt Reset */ +#define FSISR (1 << 0) /* Software Reset */ + +/* OUT_SEL (FSI2) */ +#define DMMD (1 << 4) /* SPDIF output timing 0: Biphase only */ + /* 1: Biphase and serial */ + +/* FIFO_SZ */ +#define FIFO_SZ_MASK 0x7 + +#define FSI_RATES SNDRV_PCM_RATE_8000_96000 + +#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) + +/* + * bus options + * + * 0x000000BA + * + * A : sample widtht 16bit setting + * B : sample widtht 24bit setting + */ + +#define SHIFT_16DATA 0 +#define SHIFT_24DATA 4 + +#define PACKAGE_24BITBUS_BACK 0 +#define PACKAGE_24BITBUS_FRONT 1 +#define PACKAGE_16BITBUS_STREAM 2 + +#define BUSOP_SET(s, a) ((a) << SHIFT_ ## s ## DATA) +#define BUSOP_GET(s, a) (((a) >> SHIFT_ ## s ## DATA) & 0xF) + +/* + * FSI driver use below type name for variable + * + * xxx_num : number of data + * xxx_pos : position of data + * xxx_capa : capacity of data + */ + +/* + * period/frame/sample image + * + * ex) PCM (2ch) + * + * period pos period pos + * [n] [n + 1] + * |<-------------------- period--------------------->| + * ==|============================================ ... =|== + * | | + * ||<----- frame ----->|<------ frame ----->| ... | + * |+--------------------+--------------------+- ... | + * ||[ sample ][ sample ]|[ sample ][ sample ]| ... | + * |+--------------------+--------------------+- ... | + * ==|============================================ ... =|== + */ + +/* + * FSI FIFO image + * + * | | + * | | + * | [ sample ] | + * | [ sample ] | + * | [ sample ] | + * | [ sample ] | + * --> go to codecs + */ + +/* + * FSI clock + * + * FSIxCLK [CPG] (ick) -------> | + * |-> FSI_DIV (div)-> FSI2 + * FSIxCK [external] (xck) ---> | + */ + +/* + * struct + */ + +struct fsi_stream_handler; +struct fsi_stream { + + /* + * these are initialized by fsi_stream_init() + */ + struct snd_pcm_substream *substream; + int fifo_sample_capa; /* sample capacity of FSI FIFO */ + int buff_sample_capa; /* sample capacity of ALSA buffer */ + int buff_sample_pos; /* sample position of ALSA buffer */ + int period_samples; /* sample number / 1 period */ + int period_pos; /* current period position */ + int sample_width; /* sample width */ + int uerr_num; + int oerr_num; + + /* + * bus options + */ + u32 bus_option; + + /* + * these are initialized by fsi_handler_init() + */ + struct fsi_stream_handler *handler; + struct fsi_priv *priv; + + /* + * these are for DMAEngine + */ + struct dma_chan *chan; + int dma_id; +}; + +struct fsi_clk { + /* see [FSI clock] */ + struct clk *own; + struct clk *xck; + struct clk *ick; + struct clk *div; + int (*set_rate)(struct device *dev, + struct fsi_priv *fsi); + + unsigned long rate; + unsigned int count; +}; + +struct fsi_priv { + void __iomem *base; + phys_addr_t phys; + struct fsi_master *master; + + struct fsi_stream playback; + struct fsi_stream capture; + + struct fsi_clk clock; + + u32 fmt; + + int chan_num:16; + unsigned int clk_master:1; + unsigned int clk_cpg:1; + unsigned int spdif:1; + unsigned int enable_stream:1; + unsigned int bit_clk_inv:1; + unsigned int lr_clk_inv:1; +}; + +struct fsi_stream_handler { + int (*init)(struct fsi_priv *fsi, struct fsi_stream *io); + int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io); + int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev); + int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); + int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); + int (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io, + int enable); +}; +#define fsi_stream_handler_call(io, func, args...) \ + (!(io) ? -ENODEV : \ + !((io)->handler->func) ? 0 : \ + (io)->handler->func(args)) + +struct fsi_core { + int ver; + + u32 int_st; + u32 iemsk; + u32 imsk; + u32 a_mclk; + u32 b_mclk; +}; + +struct fsi_master { + void __iomem *base; + struct fsi_priv fsia; + struct fsi_priv fsib; + const struct fsi_core *core; + spinlock_t lock; +}; + +static inline int fsi_stream_is_play(struct fsi_priv *fsi, + struct fsi_stream *io) +{ + return &fsi->playback == io; +} + + +/* + * basic read write function + */ + +static void __fsi_reg_write(u32 __iomem *reg, u32 data) +{ + /* valid data area is 24bit */ + data &= 0x00ffffff; + + __raw_writel(data, reg); +} + +static u32 __fsi_reg_read(u32 __iomem *reg) +{ + return __raw_readl(reg); +} + +static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data) +{ + u32 val = __fsi_reg_read(reg); + + val &= ~mask; + val |= data & mask; + + __fsi_reg_write(reg, val); +} + +#define fsi_reg_write(p, r, d)\ + __fsi_reg_write((p->base + REG_##r), d) + +#define fsi_reg_read(p, r)\ + __fsi_reg_read((p->base + REG_##r)) + +#define fsi_reg_mask_set(p, r, m, d)\ + __fsi_reg_mask_set((p->base + REG_##r), m, d) + +#define fsi_master_read(p, r) _fsi_master_read(p, MST_##r) +#define fsi_core_read(p, r) _fsi_master_read(p, p->core->r) +static u32 _fsi_master_read(struct fsi_master *master, u32 reg) +{ + u32 ret; + unsigned long flags; + + spin_lock_irqsave(&master->lock, flags); + ret = __fsi_reg_read(master->base + reg); + spin_unlock_irqrestore(&master->lock, flags); + + return ret; +} + +#define fsi_master_mask_set(p, r, m, d) _fsi_master_mask_set(p, MST_##r, m, d) +#define fsi_core_mask_set(p, r, m, d) _fsi_master_mask_set(p, p->core->r, m, d) +static void _fsi_master_mask_set(struct fsi_master *master, + u32 reg, u32 mask, u32 data) +{ + unsigned long flags; + + spin_lock_irqsave(&master->lock, flags); + __fsi_reg_mask_set(master->base + reg, mask, data); + spin_unlock_irqrestore(&master->lock, flags); +} + +/* + * basic function + */ +static int fsi_version(struct fsi_master *master) +{ + return master->core->ver; +} + +static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) +{ + return fsi->master; +} + +static int fsi_is_clk_master(struct fsi_priv *fsi) +{ + return fsi->clk_master; +} + +static int fsi_is_port_a(struct fsi_priv *fsi) +{ + return fsi->master->base == fsi->base; +} + +static int fsi_is_spdif(struct fsi_priv *fsi) +{ + return fsi->spdif; +} + +static int fsi_is_enable_stream(struct fsi_priv *fsi) +{ + return fsi->enable_stream; +} + +static int fsi_is_play(struct snd_pcm_substream *substream) +{ + return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; +} + +static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + + return snd_soc_rtd_to_cpu(rtd, 0); +} + +static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai) +{ + struct fsi_master *master = snd_soc_dai_get_drvdata(dai); + + if (dai->id == 0) + return &master->fsia; + else + return &master->fsib; +} + +static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) +{ + return fsi_get_priv_frm_dai(fsi_get_dai(substream)); +} + +static u32 fsi_get_port_shift(struct fsi_priv *fsi, struct fsi_stream *io) +{ + int is_play = fsi_stream_is_play(fsi, io); + int is_porta = fsi_is_port_a(fsi); + u32 shift; + + if (is_porta) + shift = is_play ? AO_SHIFT : AI_SHIFT; + else + shift = is_play ? BO_SHIFT : BI_SHIFT; + + return shift; +} + +static int fsi_frame2sample(struct fsi_priv *fsi, int frames) +{ + return frames * fsi->chan_num; +} + +static int fsi_sample2frame(struct fsi_priv *fsi, int samples) +{ + return samples / fsi->chan_num; +} + +static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, + struct fsi_stream *io) +{ + int is_play = fsi_stream_is_play(fsi, io); + u32 status; + int frames; + + status = is_play ? + fsi_reg_read(fsi, DOFF_ST) : + fsi_reg_read(fsi, DIFF_ST); + + frames = 0x1ff & (status >> 8); + + return fsi_frame2sample(fsi, frames); +} + +static void fsi_count_fifo_err(struct fsi_priv *fsi) +{ + u32 ostatus = fsi_reg_read(fsi, DOFF_ST); + u32 istatus = fsi_reg_read(fsi, DIFF_ST); + + if (ostatus & ERR_OVER) + fsi->playback.oerr_num++; + + if (ostatus & ERR_UNDER) + fsi->playback.uerr_num++; + + if (istatus & ERR_OVER) + fsi->capture.oerr_num++; + + if (istatus & ERR_UNDER) + fsi->capture.uerr_num++; + + fsi_reg_write(fsi, DOFF_ST, 0); + fsi_reg_write(fsi, DIFF_ST, 0); +} + +/* + * fsi_stream_xx() function + */ +static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi, + struct snd_pcm_substream *substream) +{ + return fsi_is_play(substream) ? &fsi->playback : &fsi->capture; +} + +static int fsi_stream_is_working(struct fsi_priv *fsi, + struct fsi_stream *io) +{ + struct fsi_master *master = fsi_get_master(fsi); + unsigned long flags; + int ret; + + spin_lock_irqsave(&master->lock, flags); + ret = !!(io->substream && io->substream->runtime); + spin_unlock_irqrestore(&master->lock, flags); + + return ret; +} + +static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io) +{ + return io->priv; +} + +static void fsi_stream_init(struct fsi_priv *fsi, + struct fsi_stream *io, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct fsi_master *master = fsi_get_master(fsi); + unsigned long flags; + + spin_lock_irqsave(&master->lock, flags); + io->substream = substream; + io->buff_sample_capa = fsi_frame2sample(fsi, runtime->buffer_size); + io->buff_sample_pos = 0; + io->period_samples = fsi_frame2sample(fsi, runtime->period_size); + io->period_pos = 0; + io->sample_width = samples_to_bytes(runtime, 1); + io->bus_option = 0; + io->oerr_num = -1; /* ignore 1st err */ + io->uerr_num = -1; /* ignore 1st err */ + fsi_stream_handler_call(io, init, fsi, io); + spin_unlock_irqrestore(&master->lock, flags); +} + +static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io) +{ + struct snd_soc_dai *dai = fsi_get_dai(io->substream); + struct fsi_master *master = fsi_get_master(fsi); + unsigned long flags; + + spin_lock_irqsave(&master->lock, flags); + + if (io->oerr_num > 0) + dev_err(dai->dev, "over_run = %d\n", io->oerr_num); + + if (io->uerr_num > 0) + dev_err(dai->dev, "under_run = %d\n", io->uerr_num); + + fsi_stream_handler_call(io, quit, fsi, io); + io->substream = NULL; + io->buff_sample_capa = 0; + io->buff_sample_pos = 0; + io->period_samples = 0; + io->period_pos = 0; + io->sample_width = 0; + io->bus_option = 0; + io->oerr_num = 0; + io->uerr_num = 0; + spin_unlock_irqrestore(&master->lock, flags); +} + +static int fsi_stream_transfer(struct fsi_stream *io) +{ + struct fsi_priv *fsi = fsi_stream_to_priv(io); + if (!fsi) + return -EIO; + + return fsi_stream_handler_call(io, transfer, fsi, io); +} + +#define fsi_stream_start(fsi, io)\ + fsi_stream_handler_call(io, start_stop, fsi, io, 1) + +#define fsi_stream_stop(fsi, io)\ + fsi_stream_handler_call(io, start_stop, fsi, io, 0) + +static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev) +{ + struct fsi_stream *io; + int ret1, ret2; + + io = &fsi->playback; + ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev); + + io = &fsi->capture; + ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev); + + if (ret1 < 0) + return ret1; + if (ret2 < 0) + return ret2; + + return 0; +} + +static int fsi_stream_remove(struct fsi_priv *fsi) +{ + struct fsi_stream *io; + int ret1, ret2; + + io = &fsi->playback; + ret1 = fsi_stream_handler_call(io, remove, fsi, io); + + io = &fsi->capture; + ret2 = fsi_stream_handler_call(io, remove, fsi, io); + + if (ret1 < 0) + return ret1; + if (ret2 < 0) + return ret2; + + return 0; +} + +/* + * format/bus/dma setting + */ +static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io, + u32 bus, struct device *dev) +{ + struct fsi_master *master = fsi_get_master(fsi); + int is_play = fsi_stream_is_play(fsi, io); + u32 fmt = fsi->fmt; + + if (fsi_version(master) >= 2) { + u32 dma = 0; + + /* + * FSI2 needs DMA/Bus setting + */ + switch (bus) { + case PACKAGE_24BITBUS_FRONT: + fmt |= CR_BWS_24; + dma |= VDMD_FRONT; + dev_dbg(dev, "24bit bus / package in front\n"); + break; + case PACKAGE_16BITBUS_STREAM: + fmt |= CR_BWS_16; + dma |= VDMD_STREAM; + dev_dbg(dev, "16bit bus / stream mode\n"); + break; + case PACKAGE_24BITBUS_BACK: + default: + fmt |= CR_BWS_24; + dma |= VDMD_BACK; + dev_dbg(dev, "24bit bus / package in back\n"); + break; + } + + if (is_play) + fsi_reg_write(fsi, OUT_DMAC, dma); + else + fsi_reg_write(fsi, IN_DMAC, dma); + } + + if (is_play) + fsi_reg_write(fsi, DO_FMT, fmt); + else + fsi_reg_write(fsi, DI_FMT, fmt); +} + +/* + * irq function + */ + +static void fsi_irq_enable(struct fsi_priv *fsi, struct fsi_stream *io) +{ + u32 data = AB_IO(1, fsi_get_port_shift(fsi, io)); + struct fsi_master *master = fsi_get_master(fsi); + + fsi_core_mask_set(master, imsk, data, data); + fsi_core_mask_set(master, iemsk, data, data); +} + +static void fsi_irq_disable(struct fsi_priv *fsi, struct fsi_stream *io) +{ + u32 data = AB_IO(1, fsi_get_port_shift(fsi, io)); + struct fsi_master *master = fsi_get_master(fsi); + + fsi_core_mask_set(master, imsk, data, 0); + fsi_core_mask_set(master, iemsk, data, 0); +} + +static u32 fsi_irq_get_status(struct fsi_master *master) +{ + return fsi_core_read(master, int_st); +} + +static void fsi_irq_clear_status(struct fsi_priv *fsi) +{ + u32 data = 0; + struct fsi_master *master = fsi_get_master(fsi); + + data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->playback)); + data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->capture)); + + /* clear interrupt factor */ + fsi_core_mask_set(master, int_st, data, 0); +} + +/* + * SPDIF master clock function + * + * These functions are used later FSI2 + */ +static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) +{ + struct fsi_master *master = fsi_get_master(fsi); + u32 mask, val; + + mask = BP | SE; + val = enable ? mask : 0; + + fsi_is_port_a(fsi) ? + fsi_core_mask_set(master, a_mclk, mask, val) : + fsi_core_mask_set(master, b_mclk, mask, val); +} + +/* + * clock function + */ +static int fsi_clk_init(struct device *dev, + struct fsi_priv *fsi, + int xck, + int ick, + int div, + int (*set_rate)(struct device *dev, + struct fsi_priv *fsi)) +{ + struct fsi_clk *clock = &fsi->clock; + int is_porta = fsi_is_port_a(fsi); + + clock->xck = NULL; + clock->ick = NULL; + clock->div = NULL; + clock->rate = 0; + clock->count = 0; + clock->set_rate = set_rate; + + clock->own = devm_clk_get(dev, NULL); + if (IS_ERR(clock->own)) + return -EINVAL; + + /* external clock */ + if (xck) { + clock->xck = devm_clk_get(dev, is_porta ? "xcka" : "xckb"); + if (IS_ERR(clock->xck)) { + dev_err(dev, "can't get xck clock\n"); + return -EINVAL; + } + if (clock->xck == clock->own) { + dev_err(dev, "cpu doesn't support xck clock\n"); + return -EINVAL; + } + } + + /* FSIACLK/FSIBCLK */ + if (ick) { + clock->ick = devm_clk_get(dev, is_porta ? "icka" : "ickb"); + if (IS_ERR(clock->ick)) { + dev_err(dev, "can't get ick clock\n"); + return -EINVAL; + } + if (clock->ick == clock->own) { + dev_err(dev, "cpu doesn't support ick clock\n"); + return -EINVAL; + } + } + + /* FSI-DIV */ + if (div) { + clock->div = devm_clk_get(dev, is_porta ? "diva" : "divb"); + if (IS_ERR(clock->div)) { + dev_err(dev, "can't get div clock\n"); + return -EINVAL; + } + if (clock->div == clock->own) { + dev_err(dev, "cpu doesn't support div clock\n"); + return -EINVAL; + } + } + + return 0; +} + +#define fsi_clk_invalid(fsi) fsi_clk_valid(fsi, 0) +static void fsi_clk_valid(struct fsi_priv *fsi, unsigned long rate) +{ + fsi->clock.rate = rate; +} + +static int fsi_clk_is_valid(struct fsi_priv *fsi) +{ + return fsi->clock.set_rate && + fsi->clock.rate; +} + +static int fsi_clk_enable(struct device *dev, + struct fsi_priv *fsi) +{ + struct fsi_clk *clock = &fsi->clock; + int ret = -EINVAL; + + if (!fsi_clk_is_valid(fsi)) + return ret; + + if (0 == clock->count) { + ret = clock->set_rate(dev, fsi); + if (ret < 0) { + fsi_clk_invalid(fsi); + return ret; + } + + ret = clk_enable(clock->xck); + if (ret) + goto err; + ret = clk_enable(clock->ick); + if (ret) + goto disable_xck; + ret = clk_enable(clock->div); + if (ret) + goto disable_ick; + + clock->count++; + } + + return ret; + +disable_ick: + clk_disable(clock->ick); +disable_xck: + clk_disable(clock->xck); +err: + return ret; +} + +static int fsi_clk_disable(struct device *dev, + struct fsi_priv *fsi) +{ + struct fsi_clk *clock = &fsi->clock; + + if (!fsi_clk_is_valid(fsi)) + return -EINVAL; + + if (1 == clock->count--) { + clk_disable(clock->xck); + clk_disable(clock->ick); + clk_disable(clock->div); + } + + return 0; +} + +static int fsi_clk_set_ackbpf(struct device *dev, + struct fsi_priv *fsi, + int ackmd, int bpfmd) +{ + u32 data = 0; + + /* check ackmd/bpfmd relationship */ + if (bpfmd > ackmd) { + dev_err(dev, "unsupported rate (%d/%d)\n", ackmd, bpfmd); + return -EINVAL; + } + + /* ACKMD */ + switch (ackmd) { + case 512: + data |= (0x0 << 12); + break; + case 256: + data |= (0x1 << 12); + break; + case 128: + data |= (0x2 << 12); + break; + case 64: + data |= (0x3 << 12); + break; + case 32: + data |= (0x4 << 12); + break; + default: + dev_err(dev, "unsupported ackmd (%d)\n", ackmd); + return -EINVAL; + } + + /* BPFMD */ + switch (bpfmd) { + case 32: + data |= (0x0 << 8); + break; + case 64: + data |= (0x1 << 8); + break; + case 128: + data |= (0x2 << 8); + break; + case 256: + data |= (0x3 << 8); + break; + case 512: + data |= (0x4 << 8); + break; + case 16: + data |= (0x7 << 8); + break; + default: + dev_err(dev, "unsupported bpfmd (%d)\n", bpfmd); + return -EINVAL; + } + + dev_dbg(dev, "ACKMD/BPFMD = %d/%d\n", ackmd, bpfmd); + + fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); + udelay(10); + + return 0; +} + +static int fsi_clk_set_rate_external(struct device *dev, + struct fsi_priv *fsi) +{ + struct clk *xck = fsi->clock.xck; + struct clk *ick = fsi->clock.ick; + unsigned long rate = fsi->clock.rate; + unsigned long xrate; + int ackmd, bpfmd; + int ret = 0; + + /* check clock rate */ + xrate = clk_get_rate(xck); + if (xrate % rate) { + dev_err(dev, "unsupported clock rate\n"); + return -EINVAL; + } + + clk_set_parent(ick, xck); + clk_set_rate(ick, xrate); + + bpfmd = fsi->chan_num * 32; + ackmd = xrate / rate; + + dev_dbg(dev, "external/rate = %ld/%ld\n", xrate, rate); + + ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); + if (ret < 0) + dev_err(dev, "%s failed", __func__); + + return ret; +} + +static int fsi_clk_set_rate_cpg(struct device *dev, + struct fsi_priv *fsi) +{ + struct clk *ick = fsi->clock.ick; + struct clk *div = fsi->clock.div; + unsigned long rate = fsi->clock.rate; + unsigned long target = 0; /* 12288000 or 11289600 */ + unsigned long actual, cout; + unsigned long diff, min; + unsigned long best_cout, best_act; + int adj; + int ackmd, bpfmd; + int ret = -EINVAL; + + if (!(12288000 % rate)) + target = 12288000; + if (!(11289600 % rate)) + target = 11289600; + if (!target) { + dev_err(dev, "unsupported rate\n"); + return ret; + } + + bpfmd = fsi->chan_num * 32; + ackmd = target / rate; + ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); + if (ret < 0) { + dev_err(dev, "%s failed", __func__); + return ret; + } + + /* + * The clock flow is + * + * [CPG] = cout => [FSI_DIV] = audio => [FSI] => [codec] + * + * But, it needs to find best match of CPG and FSI_DIV + * combination, since it is difficult to generate correct + * frequency of audio clock from ick clock only. + * Because ick is created from its parent clock. + * + * target = rate x [512/256/128/64]fs + * cout = round(target x adjustment) + * actual = cout / adjustment (by FSI-DIV) ~= target + * audio = actual + */ + min = ~0; + best_cout = 0; + best_act = 0; + for (adj = 1; adj < 0xffff; adj++) { + + cout = target * adj; + if (cout > 100000000) /* max clock = 100MHz */ + break; + + /* cout/actual audio clock */ + cout = clk_round_rate(ick, cout); + actual = cout / adj; + + /* find best frequency */ + diff = abs(actual - target); + if (diff < min) { + min = diff; + best_cout = cout; + best_act = actual; + } + } + + ret = clk_set_rate(ick, best_cout); + if (ret < 0) { + dev_err(dev, "ick clock failed\n"); + return -EIO; + } + + ret = clk_set_rate(div, clk_round_rate(div, best_act)); + if (ret < 0) { + dev_err(dev, "div clock failed\n"); + return -EIO; + } + + dev_dbg(dev, "ick/div = %ld/%ld\n", + clk_get_rate(ick), clk_get_rate(div)); + + return ret; +} + +static void fsi_pointer_update(struct fsi_stream *io, int size) +{ + io->buff_sample_pos += size; + + if (io->buff_sample_pos >= + io->period_samples * (io->period_pos + 1)) { + struct snd_pcm_substream *substream = io->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + io->period_pos++; + + if (io->period_pos >= runtime->periods) { + io->buff_sample_pos = 0; + io->period_pos = 0; + } + + snd_pcm_period_elapsed(substream); + } +} + +/* + * pio data transfer handler + */ +static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) +{ + int i; + + if (fsi_is_enable_stream(fsi)) { + /* + * stream mode + * see + * fsi_pio_push_init() + */ + u32 *buf = (u32 *)_buf; + + for (i = 0; i < samples / 2; i++) + fsi_reg_write(fsi, DODT, buf[i]); + } else { + /* normal mode */ + u16 *buf = (u16 *)_buf; + + for (i = 0; i < samples; i++) + fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); + } +} + +static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples) +{ + u16 *buf = (u16 *)_buf; + int i; + + for (i = 0; i < samples; i++) + *(buf + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8); +} + +static void fsi_pio_push32(struct fsi_priv *fsi, u8 *_buf, int samples) +{ + u32 *buf = (u32 *)_buf; + int i; + + for (i = 0; i < samples; i++) + fsi_reg_write(fsi, DODT, *(buf + i)); +} + +static void fsi_pio_pop32(struct fsi_priv *fsi, u8 *_buf, int samples) +{ + u32 *buf = (u32 *)_buf; + int i; + + for (i = 0; i < samples; i++) + *(buf + i) = fsi_reg_read(fsi, DIDT); +} + +static u8 *fsi_pio_get_area(struct fsi_priv *fsi, struct fsi_stream *io) +{ + struct snd_pcm_runtime *runtime = io->substream->runtime; + + return runtime->dma_area + + samples_to_bytes(runtime, io->buff_sample_pos); +} + +static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, + void (*run16)(struct fsi_priv *fsi, u8 *buf, int samples), + void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples), + int samples) +{ + u8 *buf; + + if (!fsi_stream_is_working(fsi, io)) + return -EINVAL; + + buf = fsi_pio_get_area(fsi, io); + + switch (io->sample_width) { + case 2: + run16(fsi, buf, samples); + break; + case 4: + run32(fsi, buf, samples); + break; + default: + return -EINVAL; + } + + fsi_pointer_update(io, samples); + + return 0; +} + +static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io) +{ + int sample_residues; /* samples in FSI fifo */ + int sample_space; /* ALSA free samples space */ + int samples; + + sample_residues = fsi_get_current_fifo_samples(fsi, io); + sample_space = io->buff_sample_capa - io->buff_sample_pos; + + samples = min(sample_residues, sample_space); + + return fsi_pio_transfer(fsi, io, + fsi_pio_pop16, + fsi_pio_pop32, + samples); +} + +static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io) +{ + int sample_residues; /* ALSA residue samples */ + int sample_space; /* FSI fifo free samples space */ + int samples; + + sample_residues = io->buff_sample_capa - io->buff_sample_pos; + sample_space = io->fifo_sample_capa - + fsi_get_current_fifo_samples(fsi, io); + + samples = min(sample_residues, sample_space); + + return fsi_pio_transfer(fsi, io, + fsi_pio_push16, + fsi_pio_push32, + samples); +} + +static int fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, + int enable) +{ + struct fsi_master *master = fsi_get_master(fsi); + u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; + + if (enable) + fsi_irq_enable(fsi, io); + else + fsi_irq_disable(fsi, io); + + if (fsi_is_clk_master(fsi)) + fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); + + return 0; +} + +static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io) +{ + /* + * we can use 16bit stream mode + * when "playback" and "16bit data" + * and platform allows "stream mode" + * see + * fsi_pio_push16() + */ + if (fsi_is_enable_stream(fsi)) + io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | + BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); + else + io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | + BUSOP_SET(16, PACKAGE_24BITBUS_BACK); + return 0; +} + +static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io) +{ + /* + * always 24bit bus, package back when "capture" + */ + io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | + BUSOP_SET(16, PACKAGE_24BITBUS_BACK); + return 0; +} + +static struct fsi_stream_handler fsi_pio_push_handler = { + .init = fsi_pio_push_init, + .transfer = fsi_pio_push, + .start_stop = fsi_pio_start_stop, +}; + +static struct fsi_stream_handler fsi_pio_pop_handler = { + .init = fsi_pio_pop_init, + .transfer = fsi_pio_pop, + .start_stop = fsi_pio_start_stop, +}; + +static irqreturn_t fsi_interrupt(int irq, void *data) +{ + struct fsi_master *master = data; + u32 int_st = fsi_irq_get_status(master); + + /* clear irq status */ + fsi_master_mask_set(master, SOFT_RST, IR, 0); + fsi_master_mask_set(master, SOFT_RST, IR, IR); + + if (int_st & AB_IO(1, AO_SHIFT)) + fsi_stream_transfer(&master->fsia.playback); + if (int_st & AB_IO(1, BO_SHIFT)) + fsi_stream_transfer(&master->fsib.playback); + if (int_st & AB_IO(1, AI_SHIFT)) + fsi_stream_transfer(&master->fsia.capture); + if (int_st & AB_IO(1, BI_SHIFT)) + fsi_stream_transfer(&master->fsib.capture); + + fsi_count_fifo_err(&master->fsia); + fsi_count_fifo_err(&master->fsib); + + fsi_irq_clear_status(&master->fsia); + fsi_irq_clear_status(&master->fsib); + + return IRQ_HANDLED; +} + +/* + * dma data transfer handler + */ +static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) +{ + /* + * 24bit data : 24bit bus / package in back + * 16bit data : 16bit bus / stream mode + */ + io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | + BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); + + return 0; +} + +static void fsi_dma_complete(void *data) +{ + struct fsi_stream *io = (struct fsi_stream *)data; + struct fsi_priv *fsi = fsi_stream_to_priv(io); + + fsi_pointer_update(io, io->period_samples); + + fsi_count_fifo_err(fsi); +} + +static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) +{ + struct snd_soc_dai *dai = fsi_get_dai(io->substream); + struct snd_pcm_substream *substream = io->substream; + struct dma_async_tx_descriptor *desc; + int is_play = fsi_stream_is_play(fsi, io); + enum dma_transfer_direction dir; + int ret = -EIO; + + if (is_play) + dir = DMA_MEM_TO_DEV; + else + dir = DMA_DEV_TO_MEM; + + desc = dmaengine_prep_dma_cyclic(io->chan, + substream->runtime->dma_addr, + snd_pcm_lib_buffer_bytes(substream), + snd_pcm_lib_period_bytes(substream), + dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n"); + goto fsi_dma_transfer_err; + } + + desc->callback = fsi_dma_complete; + desc->callback_param = io; + + if (dmaengine_submit(desc) < 0) { + dev_err(dai->dev, "tx_submit() fail\n"); + goto fsi_dma_transfer_err; + } + + dma_async_issue_pending(io->chan); + + /* + * FIXME + * + * In DMAEngine case, codec and FSI cannot be started simultaneously + * since FSI is using the scheduler work queue. + * Therefore, in capture case, probably FSI FIFO will have got + * overflow error in this point. + * in that case, DMA cannot start transfer until error was cleared. + */ + if (!is_play) { + if (ERR_OVER & fsi_reg_read(fsi, DIFF_ST)) { + fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); + fsi_reg_write(fsi, DIFF_ST, 0); + } + } + + ret = 0; + +fsi_dma_transfer_err: + return ret; +} + +static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, + int start) +{ + struct fsi_master *master = fsi_get_master(fsi); + u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; + u32 enable = start ? DMA_ON : 0; + + fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable); + + dmaengine_terminate_all(io->chan); + + if (fsi_is_clk_master(fsi)) + fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); + + return 0; +} + +static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) +{ + int is_play = fsi_stream_is_play(fsi, io); + +#ifdef CONFIG_SUPERH + dma_cap_mask_t mask; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + io->chan = dma_request_channel(mask, shdma_chan_filter, + (void *)io->dma_id); +#else + io->chan = dma_request_chan(dev, is_play ? "tx" : "rx"); + if (IS_ERR(io->chan)) + io->chan = NULL; +#endif + if (io->chan) { + struct dma_slave_config cfg = {}; + int ret; + + if (is_play) { + cfg.dst_addr = fsi->phys + REG_DODT; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.direction = DMA_MEM_TO_DEV; + } else { + cfg.src_addr = fsi->phys + REG_DIDT; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.direction = DMA_DEV_TO_MEM; + } + + ret = dmaengine_slave_config(io->chan, &cfg); + if (ret < 0) { + dma_release_channel(io->chan); + io->chan = NULL; + } + } + + if (!io->chan) { + + /* switch to PIO handler */ + if (is_play) + fsi->playback.handler = &fsi_pio_push_handler; + else + fsi->capture.handler = &fsi_pio_pop_handler; + + dev_info(dev, "switch handler (dma => pio)\n"); + + /* probe again */ + return fsi_stream_probe(fsi, dev); + } + + return 0; +} + +static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) +{ + fsi_stream_stop(fsi, io); + + if (io->chan) + dma_release_channel(io->chan); + + io->chan = NULL; + return 0; +} + +static struct fsi_stream_handler fsi_dma_push_handler = { + .init = fsi_dma_init, + .probe = fsi_dma_probe, + .transfer = fsi_dma_transfer, + .remove = fsi_dma_remove, + .start_stop = fsi_dma_push_start_stop, +}; + +/* + * dai ops + */ +static void fsi_fifo_init(struct fsi_priv *fsi, + struct fsi_stream *io, + struct device *dev) +{ + struct fsi_master *master = fsi_get_master(fsi); + int is_play = fsi_stream_is_play(fsi, io); + u32 shift, i; + int frame_capa; + + /* get on-chip RAM capacity */ + shift = fsi_master_read(master, FIFO_SZ); + shift >>= fsi_get_port_shift(fsi, io); + shift &= FIFO_SZ_MASK; + frame_capa = 256 << shift; + dev_dbg(dev, "fifo = %d words\n", frame_capa); + + /* + * The maximum number of sample data varies depending + * on the number of channels selected for the format. + * + * FIFOs are used in 4-channel units in 3-channel mode + * and in 8-channel units in 5- to 7-channel mode + * meaning that more FIFOs than the required size of DPRAM + * are used. + * + * ex) if 256 words of DP-RAM is connected + * 1 channel: 256 (256 x 1 = 256) + * 2 channels: 128 (128 x 2 = 256) + * 3 channels: 64 ( 64 x 3 = 192) + * 4 channels: 64 ( 64 x 4 = 256) + * 5 channels: 32 ( 32 x 5 = 160) + * 6 channels: 32 ( 32 x 6 = 192) + * 7 channels: 32 ( 32 x 7 = 224) + * 8 channels: 32 ( 32 x 8 = 256) + */ + for (i = 1; i < fsi->chan_num; i <<= 1) + frame_capa >>= 1; + dev_dbg(dev, "%d channel %d store\n", + fsi->chan_num, frame_capa); + + io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); + + /* + * set interrupt generation factor + * clear FIFO + */ + if (is_play) { + fsi_reg_write(fsi, DOFF_CTL, IRQ_HALF); + fsi_reg_mask_set(fsi, DOFF_CTL, FIFO_CLR, FIFO_CLR); + } else { + fsi_reg_write(fsi, DIFF_CTL, IRQ_HALF); + fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); + } +} + +static int fsi_hw_startup(struct fsi_priv *fsi, + struct fsi_stream *io, + struct device *dev) +{ + u32 data = 0; + + /* clock setting */ + if (fsi_is_clk_master(fsi)) + data = DIMD | DOMD; + + fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); + + /* clock inversion (CKG2) */ + data = 0; + if (fsi->bit_clk_inv) + data |= (1 << 0); + if (fsi->lr_clk_inv) + data |= (1 << 4); + if (fsi_is_clk_master(fsi)) + data <<= 8; + fsi_reg_write(fsi, CKG2, data); + + /* spdif ? */ + if (fsi_is_spdif(fsi)) { + fsi_spdif_clk_ctrl(fsi, 1); + fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); + } + + /* + * get bus settings + */ + data = 0; + switch (io->sample_width) { + case 2: + data = BUSOP_GET(16, io->bus_option); + break; + case 4: + data = BUSOP_GET(24, io->bus_option); + break; + } + fsi_format_bus_setup(fsi, io, data, dev); + + /* irq clear */ + fsi_irq_disable(fsi, io); + fsi_irq_clear_status(fsi); + + /* fifo init */ + fsi_fifo_init(fsi, io, dev); + + /* start master clock */ + if (fsi_is_clk_master(fsi)) + return fsi_clk_enable(dev, fsi); + + return 0; +} + +static int fsi_hw_shutdown(struct fsi_priv *fsi, + struct device *dev) +{ + /* stop master clock */ + if (fsi_is_clk_master(fsi)) + return fsi_clk_disable(dev, fsi); + + return 0; +} + +static int fsi_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get_priv(substream); + + fsi_clk_invalid(fsi); + + return 0; +} + +static void fsi_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get_priv(substream); + + fsi_clk_invalid(fsi); +} + +static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get_priv(substream); + struct fsi_stream *io = fsi_stream_get(fsi, substream); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + fsi_stream_init(fsi, io, substream); + if (!ret) + ret = fsi_hw_startup(fsi, io, dai->dev); + if (!ret) + ret = fsi_stream_start(fsi, io); + if (!ret) + ret = fsi_stream_transfer(io); + break; + case SNDRV_PCM_TRIGGER_STOP: + if (!ret) + ret = fsi_hw_shutdown(fsi, dai->dev); + fsi_stream_stop(fsi, io); + fsi_stream_quit(fsi, io); + break; + } + + return ret; +} + +static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) +{ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + fsi->fmt = CR_I2S; + fsi->chan_num = 2; + break; + case SND_SOC_DAIFMT_LEFT_J: + fsi->fmt = CR_PCM; + fsi->chan_num = 2; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int fsi_set_fmt_spdif(struct fsi_priv *fsi) +{ + struct fsi_master *master = fsi_get_master(fsi); + + if (fsi_version(master) < 2) + return -EINVAL; + + fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM; + fsi->chan_num = 2; + + return 0; +} + +static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); + int ret; + + /* set clock master audio interface */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + break; + case SND_SOC_DAIFMT_BP_FP: + fsi->clk_master = 1; /* cpu is master */ + break; + default: + return -EINVAL; + } + + /* set clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + fsi->bit_clk_inv = 0; + fsi->lr_clk_inv = 1; + break; + case SND_SOC_DAIFMT_IB_NF: + fsi->bit_clk_inv = 1; + fsi->lr_clk_inv = 0; + break; + case SND_SOC_DAIFMT_IB_IF: + fsi->bit_clk_inv = 1; + fsi->lr_clk_inv = 1; + break; + case SND_SOC_DAIFMT_NB_NF: + default: + fsi->bit_clk_inv = 0; + fsi->lr_clk_inv = 0; + break; + } + + if (fsi_is_clk_master(fsi)) { + if (fsi->clk_cpg) + fsi_clk_init(dai->dev, fsi, 0, 1, 1, + fsi_clk_set_rate_cpg); + else + fsi_clk_init(dai->dev, fsi, 1, 1, 0, + fsi_clk_set_rate_external); + } + + /* set format */ + if (fsi_is_spdif(fsi)) + ret = fsi_set_fmt_spdif(fsi); + else + ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK); + + return ret; +} + +static int fsi_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get_priv(substream); + + if (fsi_is_clk_master(fsi)) + fsi_clk_valid(fsi, params_rate(params)); + + return 0; +} + +/* + * Select below from Sound Card, not auto + * SND_SOC_DAIFMT_CBC_CFC + * SND_SOC_DAIFMT_CBP_CFP + */ +static const u64 fsi_dai_formats = + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF; + +static const struct snd_soc_dai_ops fsi_dai_ops = { + .startup = fsi_dai_startup, + .shutdown = fsi_dai_shutdown, + .trigger = fsi_dai_trigger, + .set_fmt = fsi_dai_set_fmt, + .hw_params = fsi_dai_hw_params, + .auto_selectable_formats = &fsi_dai_formats, + .num_auto_selectable_formats = 1, +}; + +/* + * pcm ops + */ + +static const struct snd_pcm_hardware fsi_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .buffer_bytes_max = 64 * 1024, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 32, + .fifo_size = 256, +}; + +static int fsi_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int ret = 0; + + snd_soc_set_runtime_hwparams(substream, &fsi_pcm_hardware); + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + return ret; +} + +static snd_pcm_uframes_t fsi_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct fsi_priv *fsi = fsi_get_priv(substream); + struct fsi_stream *io = fsi_stream_get(fsi, substream); + + return fsi_sample2frame(fsi, io->buff_sample_pos); +} + +/* + * snd_soc_component + */ + +#define PREALLOC_BUFFER (32 * 1024) +#define PREALLOC_BUFFER_MAX (32 * 1024) + +static int fsi_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + snd_pcm_set_managed_buffer_all( + rtd->pcm, + SNDRV_DMA_TYPE_DEV, + rtd->card->snd_card->dev, + PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); + return 0; +} + +/* + * alsa struct + */ + +static struct snd_soc_dai_driver fsi_soc_dai[] = { + { + .name = "fsia-dai", + .playback = { + .rates = FSI_RATES, + .formats = FSI_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .rates = FSI_RATES, + .formats = FSI_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .ops = &fsi_dai_ops, + }, + { + .name = "fsib-dai", + .playback = { + .rates = FSI_RATES, + .formats = FSI_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .rates = FSI_RATES, + .formats = FSI_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .ops = &fsi_dai_ops, + }, +}; + +static const struct snd_soc_component_driver fsi_soc_component = { + .name = "fsi", + .open = fsi_pcm_open, + .pointer = fsi_pointer, + .pcm_construct = fsi_pcm_new, +}; + +/* + * platform function + */ +static void fsi_of_parse(char *name, + struct device_node *np, + struct sh_fsi_port_info *info, + struct device *dev) +{ + int i; + char prop[128]; + unsigned long flags = 0; + struct { + char *name; + unsigned int val; + } of_parse_property[] = { + { "spdif-connection", SH_FSI_FMT_SPDIF }, + { "stream-mode-support", SH_FSI_ENABLE_STREAM_MODE }, + { "use-internal-clock", SH_FSI_CLK_CPG }, + }; + + for (i = 0; i < ARRAY_SIZE(of_parse_property); i++) { + sprintf(prop, "%s,%s", name, of_parse_property[i].name); + if (of_property_present(np, prop)) + flags |= of_parse_property[i].val; + } + info->flags = flags; + + dev_dbg(dev, "%s flags : %lx\n", name, info->flags); +} + +static void fsi_port_info_init(struct fsi_priv *fsi, + struct sh_fsi_port_info *info) +{ + if (info->flags & SH_FSI_FMT_SPDIF) + fsi->spdif = 1; + + if (info->flags & SH_FSI_CLK_CPG) + fsi->clk_cpg = 1; + + if (info->flags & SH_FSI_ENABLE_STREAM_MODE) + fsi->enable_stream = 1; +} + +static void fsi_handler_init(struct fsi_priv *fsi, + struct sh_fsi_port_info *info) +{ + fsi->playback.handler = &fsi_pio_push_handler; /* default PIO */ + fsi->playback.priv = fsi; + fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ + fsi->capture.priv = fsi; + + if (info->tx_id) { + fsi->playback.dma_id = info->tx_id; + fsi->playback.handler = &fsi_dma_push_handler; + } +} + +static const struct fsi_core fsi1_core = { + .ver = 1, + + /* Interrupt */ + .int_st = INT_ST, + .iemsk = IEMSK, + .imsk = IMSK, +}; + +static const struct fsi_core fsi2_core = { + .ver = 2, + + /* Interrupt */ + .int_st = CPU_INT_ST, + .iemsk = CPU_IEMSK, + .imsk = CPU_IMSK, + .a_mclk = A_MST_CTLR, + .b_mclk = B_MST_CTLR, +}; + +static const struct of_device_id fsi_of_match[] = { + { .compatible = "renesas,sh_fsi", .data = &fsi1_core}, + { .compatible = "renesas,sh_fsi2", .data = &fsi2_core}, + {}, +}; +MODULE_DEVICE_TABLE(of, fsi_of_match); + +static const struct platform_device_id fsi_id_table[] = { + { "sh_fsi", (kernel_ulong_t)&fsi1_core }, + {}, +}; +MODULE_DEVICE_TABLE(platform, fsi_id_table); + +static int fsi_probe(struct platform_device *pdev) +{ + struct fsi_master *master; + struct device_node *np = pdev->dev.of_node; + struct sh_fsi_platform_info info; + const struct fsi_core *core; + struct fsi_priv *fsi; + struct resource *res; + unsigned int irq; + int ret; + + memset(&info, 0, sizeof(info)); + + core = NULL; + if (np) { + core = of_device_get_match_data(&pdev->dev); + fsi_of_parse("fsia", np, &info.port_a, &pdev->dev); + fsi_of_parse("fsib", np, &info.port_b, &pdev->dev); + } else { + const struct platform_device_id *id_entry = pdev->id_entry; + if (id_entry) + core = (struct fsi_core *)id_entry->driver_data; + + if (pdev->dev.platform_data) + memcpy(&info, pdev->dev.platform_data, sizeof(info)); + } + + if (!core) { + dev_err(&pdev->dev, "unknown fsi device\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!res || (int)irq <= 0) { + dev_err(&pdev->dev, "Not enough FSI platform resources.\n"); + return -ENODEV; + } + + master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); + if (!master) + return -ENOMEM; + + master->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!master->base) { + dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n"); + return -ENXIO; + } + + /* master setting */ + master->core = core; + spin_lock_init(&master->lock); + + /* FSI A setting */ + fsi = &master->fsia; + fsi->base = master->base; + fsi->phys = res->start; + fsi->master = master; + fsi_port_info_init(fsi, &info.port_a); + fsi_handler_init(fsi, &info.port_a); + ret = fsi_stream_probe(fsi, &pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "FSIA stream probe failed\n"); + return ret; + } + + /* FSI B setting */ + fsi = &master->fsib; + fsi->base = master->base + 0x40; + fsi->phys = res->start + 0x40; + fsi->master = master; + fsi_port_info_init(fsi, &info.port_b); + fsi_handler_init(fsi, &info.port_b); + ret = fsi_stream_probe(fsi, &pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "FSIB stream probe failed\n"); + goto exit_fsia; + } + + pm_runtime_enable(&pdev->dev); + dev_set_drvdata(&pdev->dev, master); + + ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0, + dev_name(&pdev->dev), master); + if (ret) { + dev_err(&pdev->dev, "irq request err\n"); + goto exit_fsib; + } + + ret = devm_snd_soc_register_component(&pdev->dev, &fsi_soc_component, + fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "cannot snd component register\n"); + goto exit_fsib; + } + + return ret; + +exit_fsib: + pm_runtime_disable(&pdev->dev); + fsi_stream_remove(&master->fsib); +exit_fsia: + fsi_stream_remove(&master->fsia); + + return ret; +} + +static void fsi_remove(struct platform_device *pdev) +{ + struct fsi_master *master; + + master = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + + fsi_stream_remove(&master->fsia); + fsi_stream_remove(&master->fsib); +} + +static void __fsi_suspend(struct fsi_priv *fsi, + struct fsi_stream *io, + struct device *dev) +{ + if (!fsi_stream_is_working(fsi, io)) + return; + + fsi_stream_stop(fsi, io); + fsi_hw_shutdown(fsi, dev); +} + +static void __fsi_resume(struct fsi_priv *fsi, + struct fsi_stream *io, + struct device *dev) +{ + if (!fsi_stream_is_working(fsi, io)) + return; + + fsi_hw_startup(fsi, io, dev); + fsi_stream_start(fsi, io); +} + +static int fsi_suspend(struct device *dev) +{ + struct fsi_master *master = dev_get_drvdata(dev); + struct fsi_priv *fsia = &master->fsia; + struct fsi_priv *fsib = &master->fsib; + + __fsi_suspend(fsia, &fsia->playback, dev); + __fsi_suspend(fsia, &fsia->capture, dev); + + __fsi_suspend(fsib, &fsib->playback, dev); + __fsi_suspend(fsib, &fsib->capture, dev); + + return 0; +} + +static int fsi_resume(struct device *dev) +{ + struct fsi_master *master = dev_get_drvdata(dev); + struct fsi_priv *fsia = &master->fsia; + struct fsi_priv *fsib = &master->fsib; + + __fsi_resume(fsia, &fsia->playback, dev); + __fsi_resume(fsia, &fsia->capture, dev); + + __fsi_resume(fsib, &fsib->playback, dev); + __fsi_resume(fsib, &fsib->capture, dev); + + return 0; +} + +static const struct dev_pm_ops fsi_pm_ops = { + .suspend = fsi_suspend, + .resume = fsi_resume, +}; + +static struct platform_driver fsi_driver = { + .driver = { + .name = "fsi-pcm-audio", + .pm = &fsi_pm_ops, + .of_match_table = fsi_of_match, + }, + .probe = fsi_probe, + .remove = fsi_remove, + .id_table = fsi_id_table, +}; + +module_platform_driver(fsi_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SuperH onchip FSI audio driver"); +MODULE_AUTHOR("Kuninori Morimoto "); +MODULE_ALIAS("platform:fsi-pcm-audio"); diff --git a/sound/soc/renesas/hac.c b/sound/soc/renesas/hac.c new file mode 100644 index 00000000000000..db618c09d1e040 --- /dev/null +++ b/sound/soc/renesas/hac.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Hitachi Audio Controller (AC97) support for SH7760/SH7780 +// +// Copyright (c) 2007 Manuel Lauss +// +// dont forget to set IPSEL/OMSEL register bits (in your board code) to +// enable HAC output pins! + +/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only + * the FIRST can be used since ASoC does not pass any information to the + * ac97_read/write() functions regarding WHICH unit to use. You'll have + * to edit the code a bit to use the other AC97 unit. --mlau + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* regs and bits */ +#define HACCR 0x08 +#define HACCSAR 0x20 +#define HACCSDR 0x24 +#define HACPCML 0x28 +#define HACPCMR 0x2C +#define HACTIER 0x50 +#define HACTSR 0x54 +#define HACRIER 0x58 +#define HACRSR 0x5C +#define HACACR 0x60 + +#define CR_CR (1 << 15) /* "codec-ready" indicator */ +#define CR_CDRT (1 << 11) /* cold reset */ +#define CR_WMRT (1 << 10) /* warm reset */ +#define CR_B9 (1 << 9) /* the mysterious "bit 9" */ +#define CR_ST (1 << 5) /* AC97 link start bit */ + +#define CSAR_RD (1 << 19) /* AC97 data read bit */ +#define CSAR_WR (0) + +#define TSR_CMDAMT (1 << 31) +#define TSR_CMDDMT (1 << 30) + +#define RSR_STARY (1 << 22) +#define RSR_STDRY (1 << 21) + +#define ACR_DMARX16 (1 << 30) +#define ACR_DMATX16 (1 << 29) +#define ACR_TX12ATOM (1 << 26) +#define ACR_DMARX20 ((1 << 24) | (1 << 22)) +#define ACR_DMATX20 ((1 << 23) | (1 << 21)) + +#define CSDR_SHIFT 4 +#define CSDR_MASK (0xffff << CSDR_SHIFT) +#define CSAR_SHIFT 12 +#define CSAR_MASK (0x7f << CSAR_SHIFT) + +#define AC97_WRITE_RETRY 1 +#define AC97_READ_RETRY 5 + +/* manual-suggested AC97 codec access timeouts (us) */ +#define TMO_E1 500 /* 21 < E1 < 1000 */ +#define TMO_E2 13 /* 13 < E2 */ +#define TMO_E3 21 /* 21 < E3 */ +#define TMO_E4 500 /* 21 < E4 < 1000 */ + +struct hac_priv { + unsigned long mmio; /* HAC base address */ +} hac_cpu_data[] = { +#if defined(CONFIG_CPU_SUBTYPE_SH7760) + { + .mmio = 0xFE240000, + }, + { + .mmio = 0xFE250000, + }, +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) + { + .mmio = 0xFFE40000, + }, +#else +#error "Unsupported SuperH SoC" +#endif +}; + +#define HACREG(reg) (*(unsigned long *)(hac->mmio + (reg))) + +/* + * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906) + */ +static int hac_get_codec_data(struct hac_priv *hac, unsigned short r, + unsigned short *v) +{ + unsigned int to1, to2, i; + unsigned short adr; + + for (i = AC97_READ_RETRY; i; i--) { + *v = 0; + /* wait for HAC to receive something from the codec */ + for (to1 = TMO_E4; + to1 && !(HACREG(HACRSR) & RSR_STARY); + --to1) + udelay(1); + for (to2 = TMO_E4; + to2 && !(HACREG(HACRSR) & RSR_STDRY); + --to2) + udelay(1); + + if (!to1 && !to2) + return 0; /* codec comm is down */ + + adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT); + *v = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT); + + HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY); + + if (r == adr) + break; + + /* manual says: wait at least 21 usec before retrying */ + udelay(21); + } + HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY); + return i; +} + +static unsigned short hac_read_codec_aux(struct hac_priv *hac, + unsigned short reg) +{ + unsigned short val; + unsigned int i, to; + + for (i = AC97_READ_RETRY; i; i--) { + /* send_read_request */ + local_irq_disable(); + HACREG(HACTSR) &= ~(TSR_CMDAMT); + HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD; + local_irq_enable(); + + for (to = TMO_E3; + to && !(HACREG(HACTSR) & TSR_CMDAMT); + --to) + udelay(1); + + HACREG(HACTSR) &= ~TSR_CMDAMT; + val = 0; + if (hac_get_codec_data(hac, reg, &val) != 0) + break; + } + + return i ? val : ~0; +} + +static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) +{ + int unit_id = 0 /* ac97->private_data */; + struct hac_priv *hac = &hac_cpu_data[unit_id]; + unsigned int i, to; + /* write_codec_aux */ + for (i = AC97_WRITE_RETRY; i; i--) { + /* send_write_request */ + local_irq_disable(); + HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT); + HACREG(HACCSDR) = (val << CSDR_SHIFT); + HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD); + local_irq_enable(); + + /* poll-wait for CMDAMT and CMDDMT */ + for (to = TMO_E1; + to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT)); + --to) + udelay(1); + + HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT); + if (to) + break; + /* timeout, try again */ + } +} + +static unsigned short hac_ac97_read(struct snd_ac97 *ac97, + unsigned short reg) +{ + int unit_id = 0 /* ac97->private_data */; + struct hac_priv *hac = &hac_cpu_data[unit_id]; + return hac_read_codec_aux(hac, reg); +} + +static void hac_ac97_warmrst(struct snd_ac97 *ac97) +{ + int unit_id = 0 /* ac97->private_data */; + struct hac_priv *hac = &hac_cpu_data[unit_id]; + unsigned int tmo; + + HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9; + msleep(10); + HACREG(HACCR) = CR_ST | CR_B9; + for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--) + udelay(1); + + if (!tmo) + printk(KERN_INFO "hac: reset: AC97 link down!\n"); + /* settings this bit lets us have a conversation with codec */ + HACREG(HACACR) |= ACR_TX12ATOM; +} + +static void hac_ac97_coldrst(struct snd_ac97 *ac97) +{ + int unit_id = 0 /* ac97->private_data */; + struct hac_priv *hac; + hac = &hac_cpu_data[unit_id]; + + HACREG(HACCR) = 0; + HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9; + msleep(10); + hac_ac97_warmrst(ac97); +} + +static struct snd_ac97_bus_ops hac_ac97_ops = { + .read = hac_ac97_read, + .write = hac_ac97_write, + .reset = hac_ac97_coldrst, + .warm_reset = hac_ac97_warmrst, +}; + +static int hac_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hac_priv *hac = &hac_cpu_data[dai->id]; + int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; + + switch (params->msbits) { + case 16: + HACREG(HACACR) |= d ? ACR_DMARX16 : ACR_DMATX16; + HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20; + break; + case 20: + HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16; + HACREG(HACACR) |= d ? ACR_DMARX20 : ACR_DMATX20; + break; + default: + pr_debug("hac: invalid depth %d bit\n", params->msbits); + return -EINVAL; + break; + } + + return 0; +} + +#define AC97_RATES \ + SNDRV_PCM_RATE_8000_192000 + +#define AC97_FMTS \ + SNDRV_PCM_FMTBIT_S16_LE + +static const struct snd_soc_dai_ops hac_dai_ops = { + .hw_params = hac_hw_params, +}; + +static struct snd_soc_dai_driver sh4_hac_dai[] = { +{ + .name = "hac-dai.0", + .playback = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .ops = &hac_dai_ops, +}, +#ifdef CONFIG_CPU_SUBTYPE_SH7760 +{ + .name = "hac-dai.1", + .id = 1, + .playback = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .ops = &hac_dai_ops, + +}, +#endif +}; + +static const struct snd_soc_component_driver sh4_hac_component = { + .name = "sh4-hac", + .legacy_dai_naming = 1, +}; + +static int hac_soc_platform_probe(struct platform_device *pdev) +{ + int ret; + + ret = snd_soc_set_ac97_ops(&hac_ac97_ops); + if (ret != 0) + return ret; + + return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component, + sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); +} + +static void hac_soc_platform_remove(struct platform_device *pdev) +{ + snd_soc_set_ac97_ops(NULL); +} + +static struct platform_driver hac_pcm_driver = { + .driver = { + .name = "hac-pcm-audio", + }, + + .probe = hac_soc_platform_probe, + .remove = hac_soc_platform_remove, +}; + +module_platform_driver(hac_pcm_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver"); +MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/renesas/migor.c b/sound/soc/renesas/migor.c new file mode 100644 index 00000000000000..5a0bc6edac0a07 --- /dev/null +++ b/sound/soc/renesas/migor.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// ALSA SoC driver for Migo-R +// +// Copyright (C) 2009-2010 Guennadi Liakhovetski + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include "../codecs/wm8978.h" +#include "siu.h" + +/* Default 8000Hz sampling frequency */ +static unsigned long codec_freq = 8000 * 512; + +static unsigned int use_count; + +/* External clock, sourced from the codec at the SIUMCKB pin */ +static unsigned long siumckb_recalc(struct clk *clk) +{ + return codec_freq; +} + +static struct sh_clk_ops siumckb_clk_ops = { + .recalc = siumckb_recalc, +}; + +static struct clk siumckb_clk = { + .ops = &siumckb_clk_ops, + .rate = 0, /* initialised at run-time */ +}; + +static struct clk_lookup *siumckb_lookup; + +static int migor_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret; + unsigned int rate = params_rate(params); + + ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512); + if (ret < 0) + return ret; + + codec_freq = rate * 512; + /* + * This propagates the parent frequency change to children and + * recalculates the frequency table + */ + clk_set_rate(&siumckb_clk, codec_freq); + dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq); + + ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), SIU_CLKB_EXT, + codec_freq / 2, SND_SOC_CLOCK_IN); + + if (!ret) + use_count++; + + return ret; +} + +static int migor_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + + if (use_count) { + use_count--; + + if (!use_count) + snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0, + SND_SOC_CLOCK_IN); + } else { + dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n"); + } + + return 0; +} + +static const struct snd_soc_ops migor_dai_ops = { + .hw_params = migor_hw_params, + .hw_free = migor_hw_free, +}; + +static const struct snd_soc_dapm_widget migor_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Onboard Microphone", NULL), + SND_SOC_DAPM_MIC("External Microphone", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */ + { "Headphone", NULL, "OUT4 VMID" }, + { "OUT4 VMID", NULL, "LHP" }, + { "OUT4 VMID", NULL, "RHP" }, + + /* On-board microphone */ + { "RMICN", NULL, "Mic Bias" }, + { "RMICP", NULL, "Mic Bias" }, + { "Mic Bias", NULL, "Onboard Microphone" }, + + /* External microphone */ + { "LMICN", NULL, "Mic Bias" }, + { "LMICP", NULL, "Mic Bias" }, + { "Mic Bias", NULL, "External Microphone" }, +}; + +/* migor digital audio interface glue - connects codec <--> CPU */ +SND_SOC_DAILINK_DEFS(wm8978, + DAILINK_COMP_ARRAY(COMP_CPU("siu-pcm-audio")), + DAILINK_COMP_ARRAY(COMP_CODEC("wm8978.0-001a", "wm8978-hifi")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("siu-pcm-audio"))); + +static struct snd_soc_dai_link migor_dai = { + .name = "wm8978", + .stream_name = "WM8978", + .dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_CBS_CFS, + .ops = &migor_dai_ops, + SND_SOC_DAILINK_REG(wm8978), +}; + +/* migor audio machine driver */ +static struct snd_soc_card snd_soc_migor = { + .name = "Migo-R", + .owner = THIS_MODULE, + .dai_link = &migor_dai, + .num_links = 1, + + .dapm_widgets = migor_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(migor_dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), +}; + +static struct platform_device *migor_snd_device; + +static int __init migor_init(void) +{ + int ret; + + ret = clk_register(&siumckb_clk); + if (ret < 0) + return ret; + + siumckb_lookup = clkdev_create(&siumckb_clk, "siumckb_clk", NULL); + if (!siumckb_lookup) { + ret = -ENOMEM; + goto eclkdevalloc; + } + + /* Port number used on this machine: port B */ + migor_snd_device = platform_device_alloc("soc-audio", 1); + if (!migor_snd_device) { + ret = -ENOMEM; + goto epdevalloc; + } + + platform_set_drvdata(migor_snd_device, &snd_soc_migor); + + ret = platform_device_add(migor_snd_device); + if (ret) + goto epdevadd; + + return 0; + +epdevadd: + platform_device_put(migor_snd_device); +epdevalloc: + clkdev_drop(siumckb_lookup); +eclkdevalloc: + clk_unregister(&siumckb_clk); + return ret; +} + +static void __exit migor_exit(void) +{ + clkdev_drop(siumckb_lookup); + clk_unregister(&siumckb_clk); + platform_device_unregister(migor_snd_device); +} + +module_init(migor_init); +module_exit(migor_exit); + +MODULE_AUTHOR("Guennadi Liakhovetski "); +MODULE_DESCRIPTION("ALSA SoC Migor"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/renesas/rcar/Makefile b/sound/soc/renesas/rcar/Makefile new file mode 100644 index 00000000000000..45eb875a912a66 --- /dev/null +++ b/sound/soc/renesas/rcar/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +snd-soc-rcar-y := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o +obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o diff --git a/sound/soc/renesas/rcar/adg.c b/sound/soc/renesas/rcar/adg.c new file mode 100644 index 00000000000000..0f190abf00e756 --- /dev/null +++ b/sound/soc/renesas/rcar/adg.c @@ -0,0 +1,775 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Helper routines for R-Car sound ADG. +// +// Copyright (C) 2013 Kuninori Morimoto +#include +#include +#include "rsnd.h" + +#define CLKA 0 +#define CLKB 1 +#define CLKC 2 +#define CLKI 3 +#define CLKINMAX 4 + +#define CLKOUT 0 +#define CLKOUT1 1 +#define CLKOUT2 2 +#define CLKOUT3 3 +#define CLKOUTMAX 4 + +#define BRRx_MASK(x) (0x3FF & x) + +static struct rsnd_mod_ops adg_ops = { + .name = "adg", +}; + +#define ADG_HZ_441 0 +#define ADG_HZ_48 1 +#define ADG_HZ_SIZE 2 + +struct rsnd_adg { + struct clk *clkin[CLKINMAX]; + struct clk *clkout[CLKOUTMAX]; + struct clk *null_clk; + struct clk_onecell_data onecell; + struct rsnd_mod mod; + int clkin_rate[CLKINMAX]; + int clkin_size; + int clkout_size; + u32 ckr; + u32 brga; + u32 brgb; + + int brg_rate[ADG_HZ_SIZE]; /* BRGA / BRGB */ +}; + +#define for_each_rsnd_clkin(pos, adg, i) \ + for (i = 0; \ + (i < adg->clkin_size) && \ + ((pos) = adg->clkin[i]); \ + i++) +#define for_each_rsnd_clkout(pos, adg, i) \ + for (i = 0; \ + (i < adg->clkout_size) && \ + ((pos) = adg->clkout[i]); \ + i++) +#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) + +static const char * const clkin_name_gen4[] = { + [CLKA] = "clkin", +}; + +static const char * const clkin_name_gen2[] = { + [CLKA] = "clk_a", + [CLKB] = "clk_b", + [CLKC] = "clk_c", + [CLKI] = "clk_i", +}; + +static const char * const clkout_name_gen2[] = { + [CLKOUT] = "audio_clkout", + [CLKOUT1] = "audio_clkout1", + [CLKOUT2] = "audio_clkout2", + [CLKOUT3] = "audio_clkout3", +}; + +static u32 rsnd_adg_calculate_brgx(unsigned long div) +{ + int i; + + if (!div) + return 0; + + for (i = 3; i >= 0; i--) { + int ratio = 2 << (i * 2); + if (0 == (div % ratio)) + return (u32)((i << 8) | ((div / ratio) - 1)); + } + + return ~0; +} + +static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) +{ + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + int id = rsnd_mod_id(ssi_mod); + int ws = id; + + if (rsnd_ssi_is_pin_sharing(io)) { + switch (id) { + case 1: + case 2: + case 9: + ws = 0; + break; + case 4: + ws = 3; + break; + case 8: + ws = 7; + break; + } + } else { + /* + * SSI8 is not connected to ADG. + * Thus SSI9 is using ws = 8 + */ + if (id == 9) + ws = 8; + } + + return (0x6 + ws) << 8; +} + +static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + unsigned int target_rate, + unsigned int *target_val, + unsigned int *target_en) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + int sel; + unsigned int val, en; + unsigned int min, diff; + unsigned int sel_rate[] = { + adg->clkin_rate[CLKA], /* 0000: CLKA */ + adg->clkin_rate[CLKB], /* 0001: CLKB */ + adg->clkin_rate[CLKC], /* 0010: CLKC */ + adg->brg_rate[ADG_HZ_441], /* 0011: BRGA */ + adg->brg_rate[ADG_HZ_48], /* 0100: BRGB */ + }; + + min = ~0; + val = 0; + en = 0; + for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { + int idx = 0; + int step = 2; + int div; + + if (!sel_rate[sel]) + continue; + + for (div = 2; div <= 98304; div += step) { + diff = abs(target_rate - sel_rate[sel] / div); + if (min > diff) { + val = (sel << 8) | idx; + min = diff; + en = 1 << (sel + 1); /* fixme */ + } + + /* + * step of 0_0000 / 0_0001 / 0_1101 + * are out of order + */ + if ((idx > 2) && (idx % 2)) + step *= 2; + if (idx == 0x1c) { + div += step; + step *= 2; + } + idx++; + } + } + + if (min == ~0) { + dev_err(dev, "no Input clock\n"); + return; + } + + *target_val = val; + if (target_en) + *target_en = en; +} + +static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + unsigned int in_rate, + unsigned int out_rate, + u32 *in, u32 *out, u32 *en) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + unsigned int target_rate; + u32 *target_val; + u32 _in; + u32 _out; + u32 _en; + + /* default = SSI WS */ + _in = + _out = rsnd_adg_ssi_ws_timing_gen2(io); + + target_rate = 0; + target_val = NULL; + _en = 0; + if (runtime->rate != in_rate) { + target_rate = out_rate; + target_val = &_out; + } else if (runtime->rate != out_rate) { + target_rate = in_rate; + target_val = &_in; + } + + if (target_rate) + __rsnd_adg_get_timesel_ratio(priv, io, + target_rate, + target_val, &_en); + + if (in) + *in = _in; + if (out) + *out = _out; + if (en) + *en = _en; +} + +int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod); + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); + int id = rsnd_mod_id(cmd_mod); + int shift = (id % 2) ? 16 : 0; + u32 mask, val; + + rsnd_adg_get_timesel_ratio(priv, io, + rsnd_src_get_in_rate(priv, io), + rsnd_src_get_out_rate(priv, io), + NULL, &val, NULL); + + val = val << shift; + mask = 0x0f1f << shift; + + rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val); + + return 0; +} + +int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, + struct rsnd_dai_stream *io, + unsigned int in_rate, + unsigned int out_rate) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod); + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); + u32 in, out; + u32 mask, en; + int id = rsnd_mod_id(src_mod); + int shift = (id % 2) ? 16 : 0; + + rsnd_mod_make_sure(src_mod, RSND_MOD_SRC); + + rsnd_adg_get_timesel_ratio(priv, io, + in_rate, out_rate, + &in, &out, &en); + + in = in << shift; + out = out << shift; + mask = 0x0f1f << shift; + + rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2), mask, in); + rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out); + + if (en) + rsnd_mod_bset(adg_mod, DIV_EN, en, en); + + return 0; +} + +static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); + struct device *dev = rsnd_priv_to_dev(priv); + int id = rsnd_mod_id(ssi_mod); + int shift = (id % 4) * 8; + u32 mask = 0xFF << shift; + + rsnd_mod_make_sure(ssi_mod, RSND_MOD_SSI); + + val = val << shift; + + /* + * SSI 8 is not connected to ADG. + * it works with SSI 7 + */ + if (id == 8) + return; + + rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val); + + dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val); +} + +int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct clk *clk; + int i; + int sel_table[] = { + [CLKA] = 0x1, + [CLKB] = 0x2, + [CLKC] = 0x3, + [CLKI] = 0x0, + }; + + /* + * find suitable clock from + * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. + */ + for_each_rsnd_clkin(clk, adg, i) + if (rate == adg->clkin_rate[i]) + return sel_table[i]; + + /* + * find divided clock from BRGA/BRGB + */ + if (rate == adg->brg_rate[ADG_HZ_441]) + return 0x10; + + if (rate == adg->brg_rate[ADG_HZ_48]) + return 0x20; + + return -EIO; +} + +int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) +{ + rsnd_adg_set_ssi_clk(ssi_mod, 0); + + return 0; +} + +int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); + int data; + u32 ckr = 0; + + data = rsnd_adg_clk_query(priv, rate); + if (data < 0) + return data; + + rsnd_adg_set_ssi_clk(ssi_mod, data); + + if (0 == (rate % 8000)) + ckr = 0x80000000; /* BRGB output = 48kHz */ + + rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr); + + dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n", + (ckr) ? 'B' : 'A', + (ckr) ? adg->brg_rate[ADG_HZ_48] : + adg->brg_rate[ADG_HZ_441]); + + return 0; +} + +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); + struct clk *clk; + int i; + + if (enable) { + rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr); + rsnd_mod_write(adg_mod, BRRA, adg->brga); + rsnd_mod_write(adg_mod, BRRB, adg->brgb); + } + + for_each_rsnd_clkin(clk, adg, i) { + if (enable) { + clk_prepare_enable(clk); + + /* + * We shouldn't use clk_get_rate() under + * atomic context. Let's keep it when + * rsnd_adg_clk_enable() was called + */ + adg->clkin_rate[i] = clk_get_rate(clk); + } else { + clk_disable_unprepare(clk); + } + } +} + +static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv, + const char * const name, + const char *parent) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct clk *clk; + + clk = clk_register_fixed_rate(dev, name, parent, 0, 0); + if (IS_ERR_OR_NULL(clk)) { + dev_err(dev, "create null clk error\n"); + return ERR_CAST(clk); + } + + return clk; +} + +static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = priv->adg; + + if (!adg->null_clk) { + static const char * const name = "rsnd_adg_null"; + + adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL); + } + + return adg->null_clk; +} + +static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = priv->adg; + + if (adg->null_clk) + clk_unregister_fixed_rate(adg->null_clk); +} + +static int rsnd_adg_get_clkin(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = priv->adg; + struct device *dev = rsnd_priv_to_dev(priv); + struct clk *clk; + const char * const *clkin_name; + int clkin_size; + int i; + + clkin_name = clkin_name_gen2; + clkin_size = ARRAY_SIZE(clkin_name_gen2); + if (rsnd_is_gen4(priv)) { + clkin_name = clkin_name_gen4; + clkin_size = ARRAY_SIZE(clkin_name_gen4); + } + + for (i = 0; i < clkin_size; i++) { + clk = devm_clk_get(dev, clkin_name[i]); + + if (IS_ERR_OR_NULL(clk)) + clk = rsnd_adg_null_clk_get(priv); + if (IS_ERR_OR_NULL(clk)) + goto err; + + adg->clkin[i] = clk; + } + + adg->clkin_size = clkin_size; + + return 0; + +err: + dev_err(dev, "adg clock IN get failed\n"); + + rsnd_adg_null_clk_clean(priv); + + return -EIO; +} + +static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = priv->adg; + struct clk *clk; + int i; + + for_each_rsnd_clkout(clk, adg, i) + clk_unregister_fixed_rate(clk); +} + +static int rsnd_adg_get_clkout(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = priv->adg; + struct clk *clk; + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; + struct property *prop; + u32 ckr, brgx, brga, brgb; + u32 req_rate[ADG_HZ_SIZE] = {}; + uint32_t count = 0; + unsigned long req_Hz[ADG_HZ_SIZE]; + int clkout_size; + int i, req_size; + int approximate = 0; + const char *parent_clk_name = NULL; + const char * const *clkout_name; + int brg_table[] = { + [CLKA] = 0x0, + [CLKB] = 0x1, + [CLKC] = 0x4, + [CLKI] = 0x2, + }; + + ckr = 0; + brga = 0xff; /* default */ + brgb = 0xff; /* default */ + + /* + * ADG supports BRRA/BRRB output only + * this means all clkout0/1/2/3 will be same rate + */ + prop = of_find_property(np, "clock-frequency", NULL); + if (!prop) + goto rsnd_adg_get_clkout_end; + + req_size = prop->length / sizeof(u32); + if (req_size > ADG_HZ_SIZE) { + dev_err(dev, "too many clock-frequency\n"); + return -EINVAL; + } + + of_property_read_u32_array(np, "clock-frequency", req_rate, req_size); + req_Hz[ADG_HZ_48] = 0; + req_Hz[ADG_HZ_441] = 0; + for (i = 0; i < req_size; i++) { + if (0 == (req_rate[i] % 44100)) + req_Hz[ADG_HZ_441] = req_rate[i]; + if (0 == (req_rate[i] % 48000)) + req_Hz[ADG_HZ_48] = req_rate[i]; + } + + /* + * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC + * have 44.1kHz or 48kHz base clocks for now. + * + * SSI itself can divide parent clock by 1/1 - 1/16 + * see + * rsnd_adg_ssi_clk_try_start() + * rsnd_ssi_master_clk_start() + */ + + /* + * [APPROXIMATE] + * + * clk_i (internal clock) can't create accurate rate, it will be approximate rate. + * + * + * + * clk_i needs x2 of required maximum rate. + * see + * - Minimum division of BRRA/BRRB + * - rsnd_ssi_clk_query() + * + * Sample Settings for TDM 8ch, 32bit width + * + * 8(ch) x 32(bit) x 44100(Hz) x 2 = 22579200 + * 8(ch) x 32(bit) x 48000(Hz) x 2 = 24576000 + * + * clock-frequency = <22579200 24576000>; + */ + for_each_rsnd_clkin(clk, adg, i) { + u32 rate, div; + + rate = clk_get_rate(clk); + + if (0 == rate) /* not used */ + continue; + + /* BRGA */ + + if (i == CLKI) + /* see [APPROXIMATE] */ + rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441]; + if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) { + div = rate / req_Hz[ADG_HZ_441]; + brgx = rsnd_adg_calculate_brgx(div); + if (BRRx_MASK(brgx) == brgx) { + brga = brgx; + adg->brg_rate[ADG_HZ_441] = rate / div; + ckr |= brg_table[i] << 20; + if (req_Hz[ADG_HZ_441]) + parent_clk_name = __clk_get_name(clk); + if (i == CLKI) + approximate = 1; + } + } + + /* BRGB */ + + if (i == CLKI) + /* see [APPROXIMATE] */ + rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48]; + if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) { + div = rate / req_Hz[ADG_HZ_48]; + brgx = rsnd_adg_calculate_brgx(div); + if (BRRx_MASK(brgx) == brgx) { + brgb = brgx; + adg->brg_rate[ADG_HZ_48] = rate / div; + ckr |= brg_table[i] << 16; + if (req_Hz[ADG_HZ_48]) + parent_clk_name = __clk_get_name(clk); + if (i == CLKI) + approximate = 1; + } + } + } + + if (!(adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48]) && + !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441])) + goto rsnd_adg_get_clkout_end; + + if (approximate) + dev_info(dev, "It uses CLK_I as approximate rate"); + + clkout_name = clkout_name_gen2; + clkout_size = ARRAY_SIZE(clkout_name_gen2); + if (rsnd_is_gen4(priv)) + clkout_size = 1; /* reuse clkout_name_gen2[] */ + + /* + * ADG supports BRRA/BRRB output only. + * this means all clkout0/1/2/3 will be * same rate + */ + + of_property_read_u32(np, "#clock-cells", &count); + /* + * for clkout + */ + if (!count) { + clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], + parent_clk_name, 0, req_rate[0]); + if (IS_ERR_OR_NULL(clk)) + goto err; + + adg->clkout[CLKOUT] = clk; + adg->clkout_size = 1; + of_clk_add_provider(np, of_clk_src_simple_get, clk); + } + /* + * for clkout0/1/2/3 + */ + else { + for (i = 0; i < clkout_size; i++) { + clk = clk_register_fixed_rate(dev, clkout_name[i], + parent_clk_name, 0, + req_rate[0]); + if (IS_ERR_OR_NULL(clk)) + goto err; + + adg->clkout[i] = clk; + } + adg->onecell.clks = adg->clkout; + adg->onecell.clk_num = clkout_size; + adg->clkout_size = clkout_size; + of_clk_add_provider(np, of_clk_src_onecell_get, + &adg->onecell); + } + +rsnd_adg_get_clkout_end: + adg->ckr = ckr; + adg->brga = brga; + adg->brgb = brgb; + + return 0; + +err: + dev_err(dev, "adg clock OUT get failed\n"); + + rsnd_adg_unregister_clkout(priv); + + return -EIO; +} + +#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) +__printf(3, 4) +static void dbg_msg(struct device *dev, struct seq_file *m, + const char *fmt, ...) +{ + char msg[128]; + va_list args; + + va_start(args, fmt); + vsnprintf(msg, sizeof(msg), fmt, args); + va_end(args); + + if (m) + seq_puts(m, msg); + else + dev_dbg(dev, "%s", msg); +} + +void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct clk *clk; + int i; + + for_each_rsnd_clkin(clk, adg, i) + dbg_msg(dev, m, "%-18s : %pa : %ld\n", + __clk_get_name(clk), clk, clk_get_rate(clk)); + + dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", + adg->ckr, adg->brga, adg->brgb); + dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->brg_rate[ADG_HZ_441]); + dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->brg_rate[ADG_HZ_48]); + + /* + * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start() + * by BRGCKR::BRGCKR_31 + */ + for_each_rsnd_clkout(clk, adg, i) + dbg_msg(dev, m, "%-18s : %pa : %ld\n", + __clk_get_name(clk), clk, clk_get_rate(clk)); +} +#else +#define rsnd_adg_clk_dbg_info(priv, m) +#endif + +int rsnd_adg_probe(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg; + struct device *dev = rsnd_priv_to_dev(priv); + int ret; + + adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); + if (!adg) + return -ENOMEM; + + ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, + NULL, 0, 0); + if (ret) + return ret; + + priv->adg = adg; + + ret = rsnd_adg_get_clkin(priv); + if (ret) + return ret; + + ret = rsnd_adg_get_clkout(priv); + if (ret) + return ret; + + rsnd_adg_clk_enable(priv); + rsnd_adg_clk_dbg_info(priv, NULL); + + return 0; +} + +void rsnd_adg_remove(struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; + + rsnd_adg_unregister_clkout(priv); + + of_clk_del_provider(np); + + rsnd_adg_clk_disable(priv); + + /* It should be called after rsnd_adg_clk_disable() */ + rsnd_adg_null_clk_clean(priv); +} diff --git a/sound/soc/renesas/rcar/cmd.c b/sound/soc/renesas/rcar/cmd.c new file mode 100644 index 00000000000000..8d9a1e345a22c3 --- /dev/null +++ b/sound/soc/renesas/rcar/cmd.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car CMD support +// +// Copyright (C) 2015 Renesas Solutions Corp. +// Kuninori Morimoto + +#include "rsnd.h" + +struct rsnd_cmd { + struct rsnd_mod mod; +}; + +#define CMD_NAME "cmd" + +#define rsnd_cmd_nr(priv) ((priv)->cmd_nr) +#define for_each_rsnd_cmd(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_cmd_nr(priv)) && \ + ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \ + i++) + +static int rsnd_cmd_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); + struct device *dev = rsnd_priv_to_dev(priv); + u32 data; + static const u32 path[] = { + [1] = 1 << 0, + [5] = 1 << 8, + [6] = 1 << 12, + [9] = 1 << 15, + }; + + if (!mix && !dvc) + return 0; + + if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1) + return -ENXIO; + + if (mix) { + struct rsnd_dai *rdai; + int i; + + /* + * it is assuming that integrater is well understanding about + * data path. Here doesn't check impossible connection, + * like src2 + src5 + */ + data = 0; + for_each_rsnd_dai(rdai, priv, i) { + struct rsnd_dai_stream *tio = &rdai->playback; + struct rsnd_mod *src = rsnd_io_to_mod_src(tio); + + if (mix == rsnd_io_to_mod_mix(tio)) + data |= path[rsnd_mod_id(src)]; + + tio = &rdai->capture; + src = rsnd_io_to_mod_src(tio); + if (mix == rsnd_io_to_mod_mix(tio)) + data |= path[rsnd_mod_id(src)]; + } + + } else { + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + + static const u8 cmd_case[] = { + [0] = 0x3, + [1] = 0x3, + [2] = 0x4, + [3] = 0x1, + [4] = 0x2, + [5] = 0x4, + [6] = 0x1, + [9] = 0x2, + }; + + if (unlikely(!src)) + return -EIO; + + data = path[rsnd_mod_id(src)] | + cmd_case[rsnd_mod_id(src)] << 16; + } + + dev_dbg(dev, "ctu/mix path = 0x%08x\n", data); + + rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); + rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1); + rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); + + rsnd_adg_set_cmd_timsel_gen2(mod, io); + + return 0; +} + +static int rsnd_cmd_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_write(mod, CMD_CTRL, 0x10); + + return 0; +} + +static int rsnd_cmd_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_write(mod, CMD_CTRL, 0); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_cmd_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, + 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30); +} +#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info +#else +#define DEBUG_INFO +#endif + +static struct rsnd_mod_ops rsnd_cmd_ops = { + .name = CMD_NAME, + .init = rsnd_cmd_init, + .start = rsnd_cmd_start, + .stop = rsnd_cmd_stop, + .get_status = rsnd_mod_get_status, + DEBUG_INFO +}; + +static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv))) + id = 0; + + return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); +} +int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id); + + return rsnd_dai_connect(mod, io, mod->type); +} + +int rsnd_cmd_probe(struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_cmd *cmd; + int i, nr; + + /* same number as DVC */ + nr = priv->dvc_nr; + if (!nr) + return 0; + + cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + priv->cmd_nr = nr; + priv->cmd = cmd; + + for_each_rsnd_cmd(cmd, priv, i) { + int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), + &rsnd_cmd_ops, NULL, + RSND_MOD_CMD, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_cmd_remove(struct rsnd_priv *priv) +{ + struct rsnd_cmd *cmd; + int i; + + for_each_rsnd_cmd(cmd, priv, i) { + rsnd_mod_quit(rsnd_mod_get(cmd)); + } +} diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c new file mode 100644 index 00000000000000..e2234928c9e881 --- /dev/null +++ b/sound/soc/renesas/rcar/core.c @@ -0,0 +1,2112 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car SRU/SCU/SSIU/SSI support +// +// Copyright (C) 2013 Renesas Solutions Corp. +// Kuninori Morimoto +// +// Based on fsi.c +// Kuninori Morimoto + +/* + * Renesas R-Car sound device structure + * + * Gen1 + * + * SRU : Sound Routing Unit + * - SRC : Sampling Rate Converter + * - CMD + * - CTU : Channel Count Conversion Unit + * - MIX : Mixer + * - DVC : Digital Volume and Mute Function + * - SSI : Serial Sound Interface + * + * Gen2 + * + * SCU : Sampling Rate Converter Unit + * - SRC : Sampling Rate Converter + * - CMD + * - CTU : Channel Count Conversion Unit + * - MIX : Mixer + * - DVC : Digital Volume and Mute Function + * SSIU : Serial Sound Interface Unit + * - SSI : Serial Sound Interface + */ + +/* + * driver data Image + * + * rsnd_priv + * | + * | ** this depends on Gen1/Gen2 + * | + * +- gen + * | + * | ** these depend on data path + * | ** gen and platform data control it + * | + * +- rdai[0] + * | | sru ssiu ssi + * | +- playback -> [mod] -> [mod] -> [mod] -> ... + * | | + * | | sru ssiu ssi + * | +- capture -> [mod] -> [mod] -> [mod] -> ... + * | + * +- rdai[1] + * | | sru ssiu ssi + * | +- playback -> [mod] -> [mod] -> [mod] -> ... + * | | + * | | sru ssiu ssi + * | +- capture -> [mod] -> [mod] -> [mod] -> ... + * ... + * | + * | ** these control ssi + * | + * +- ssi + * | | + * | +- ssi[0] + * | +- ssi[1] + * | +- ssi[2] + * | ... + * | + * | ** these control src + * | + * +- src + * | + * +- src[0] + * +- src[1] + * +- src[2] + * ... + * + * + * for_each_rsnd_dai(xx, priv, xx) + * rdai[0] => rdai[1] => rdai[2] => ... + * + * for_each_rsnd_mod(xx, rdai, xx) + * [mod] => [mod] => [mod] => ... + * + * rsnd_dai_call(xxx, fn ) + * [mod]->fn() -> [mod]->fn() -> [mod]->fn()... + * + */ + +#include +#include +#include "rsnd.h" + +#define RSND_RATES SNDRV_PCM_RATE_8000_192000 +#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\ + SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static const struct of_device_id rsnd_of_match[] = { + { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, + { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, + { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 }, + { .compatible = "renesas,rcar_sound-gen4", .data = (void *)RSND_GEN4 }, + /* Special Handling */ + { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) }, + {}, +}; +MODULE_DEVICE_TABLE(of, rsnd_of_match); + +/* + * rsnd_mod functions + */ +void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) +{ + if (mod->type != type) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_warn(dev, "%s is not your expected module\n", + rsnd_mod_name(mod)); + } +} + +struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + if (!mod || !mod->ops || !mod->ops->dma_req) + return NULL; + + return mod->ops->dma_req(io, mod); +} + +#define MOD_NAME_NUM 5 +#define MOD_NAME_SIZE 16 +char *rsnd_mod_name(struct rsnd_mod *mod) +{ + static char names[MOD_NAME_NUM][MOD_NAME_SIZE]; + static int num; + char *name = names[num]; + + num++; + if (num >= MOD_NAME_NUM) + num = 0; + + /* + * Let's use same char to avoid pointlessness memory + * Thus, rsnd_mod_name() should be used immediately + * Don't keep pointer + */ + if ((mod)->ops->id_sub) { + snprintf(name, MOD_NAME_SIZE, "%s[%d%d]", + mod->ops->name, + rsnd_mod_id(mod), + rsnd_mod_id_sub(mod)); + } else { + snprintf(name, MOD_NAME_SIZE, "%s[%d]", + mod->ops->name, + rsnd_mod_id(mod)); + } + + return name; +} + +u32 *rsnd_mod_get_status(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) +{ + return &mod->status; +} + +int rsnd_mod_id_raw(struct rsnd_mod *mod) +{ + return mod->id; +} + +int rsnd_mod_id(struct rsnd_mod *mod) +{ + if ((mod)->ops->id) + return (mod)->ops->id(mod); + + return rsnd_mod_id_raw(mod); +} + +int rsnd_mod_id_sub(struct rsnd_mod *mod) +{ + if ((mod)->ops->id_sub) + return (mod)->ops->id_sub(mod); + + return 0; +} + +int rsnd_mod_init(struct rsnd_priv *priv, + struct rsnd_mod *mod, + struct rsnd_mod_ops *ops, + struct clk *clk, + enum rsnd_mod_type type, + int id) +{ + int ret = clk_prepare(clk); + + if (ret) + return ret; + + mod->id = id; + mod->ops = ops; + mod->type = type; + mod->clk = clk; + mod->priv = priv; + + return 0; +} + +void rsnd_mod_quit(struct rsnd_mod *mod) +{ + clk_unprepare(mod->clk); + mod->clk = NULL; +} + +void rsnd_mod_interrupt(struct rsnd_mod *mod, + void (*callback)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io)) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dai *rdai; + int i; + + for_each_rsnd_dai(rdai, priv, i) { + struct rsnd_dai_stream *io = &rdai->playback; + + if (mod == io->mod[mod->type]) + callback(mod, io); + + io = &rdai->capture; + if (mod == io->mod[mod->type]) + callback(mod, io); + } +} + +int rsnd_io_is_working(struct rsnd_dai_stream *io) +{ + /* see rsnd_dai_stream_init/quit() */ + if (io->substream) + return snd_pcm_running(io->substream); + + return 0; +} + +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + + /* + * params will be added when refine + * see + * __rsnd_soc_hw_rule_rate() + * __rsnd_soc_hw_rule_channels() + */ + if (params) + return params_channels(params); + else if (runtime) + return runtime->channels; + return 0; +} + +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) +{ + int chan = rsnd_runtime_channel_original_with_params(io, params); + struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); + + if (ctu_mod) { + u32 converted_chan = rsnd_io_converted_chan(io); + + /* + * !! Note !! + * + * converted_chan will be used for CTU, + * or TDM Split mode. + * User shouldn't use CTU with TDM Split mode. + */ + if (rsnd_runtime_is_tdm_split(io)) { + struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); + + dev_err(dev, "CTU and TDM Split should be used\n"); + } + + if (converted_chan) + return converted_chan; + } + + return chan; +} + +int rsnd_channel_normalization(int chan) +{ + if (WARN_ON((chan > 8) || (chan < 0))) + return 0; + + /* TDM Extend Mode needs 8ch */ + if (chan == 6) + chan = 8; + + return chan; +} + +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + int chan = rsnd_io_is_play(io) ? + rsnd_runtime_channel_after_ctu_with_params(io, params) : + rsnd_runtime_channel_original_with_params(io, params); + + /* Use Multi SSI */ + if (rsnd_runtime_is_multi_ssi(io)) + chan /= rsnd_rdai_ssi_lane_get(rdai); + + return rsnd_channel_normalization(chan); +} + +int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + int lane = rsnd_rdai_ssi_lane_get(rdai); + int chan = rsnd_io_is_play(io) ? + rsnd_runtime_channel_after_ctu(io) : + rsnd_runtime_channel_original(io); + + return (chan > 2) && (lane > 1); +} + +int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io) +{ + return rsnd_runtime_channel_for_ssi(io) >= 6; +} + +int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io) +{ + return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT); +} + +/* + * ADINR function + */ +u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct device *dev = rsnd_priv_to_dev(priv); + + switch (snd_pcm_format_width(runtime->format)) { + case 8: + return 16 << 16; + case 16: + return 8 << 16; + case 24: + return 0 << 16; + } + + dev_warn(dev, "not supported sample bits\n"); + + return 0; +} + +/* + * DALIGN function + */ +u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) +{ + static const u32 dalign_values[8] = { + 0x76543210, 0x00000032, 0x00007654, 0x00000076, + 0xfedcba98, 0x000000ba, 0x0000fedc, 0x000000fe, + }; + int id = 0; + struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); + struct rsnd_mod *target; + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + u32 dalign; + + /* + * *Hardware* L/R and *Software* L/R are inverted for 16bit data. + * 31..16 15...0 + * HW: [L ch] [R ch] + * SW: [R ch] [L ch] + * We need to care about inversion timing to control + * Playback/Capture correctly. + * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R + * + * sL/R : software L/R + * hL/R : hardware L/R + * (*) : conversion timing + * + * Playback + * sL/R (*) hL/R hL/R hL/R hL/R hL/R + * [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec + * + * Capture + * hL/R hL/R hL/R hL/R hL/R (*) sL/R + * codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM] + */ + if (rsnd_io_is_play(io)) { + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + + target = src ? src : ssiu; + } else { + struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); + + target = cmd ? cmd : ssiu; + } + + if (mod == ssiu) + id = rsnd_mod_id_sub(mod); + + dalign = dalign_values[id]; + + if (mod == target && snd_pcm_format_width(runtime->format) == 16) { + /* Target mod needs inverted DALIGN when 16bit */ + dalign = (dalign & 0xf0f0f0f0) >> 4 | + (dalign & 0x0f0f0f0f) << 4; + } + + return dalign; +} + +u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) +{ + static const enum rsnd_mod_type playback_mods[] = { + RSND_MOD_SRC, + RSND_MOD_CMD, + RSND_MOD_SSIU, + }; + static const enum rsnd_mod_type capture_mods[] = { + RSND_MOD_CMD, + RSND_MOD_SRC, + RSND_MOD_SSIU, + }; + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_mod *tmod = NULL; + const enum rsnd_mod_type *mods = + rsnd_io_is_play(io) ? + playback_mods : capture_mods; + int i; + + /* + * This is needed for 24bit data + * We need to shift 8bit + * + * Linux 24bit data is located as 0x00****** + * HW 24bit data is located as 0x******00 + * + */ + if (snd_pcm_format_width(runtime->format) != 24) + return 0; + + for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { + tmod = rsnd_io_to_mod(io, mods[i]); + if (tmod) + break; + } + + if (tmod != mod) + return 0; + + if (rsnd_io_is_play(io)) + return (0 << 20) | /* shift to Left */ + (8 << 16); /* 8bit */ + else + return (1 << 20) | /* shift to Right */ + (8 << 16); /* 8bit */ +} + +/* + * rsnd_dai functions + */ +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size) +{ + int max = array ? array_size : RSND_MOD_MAX; + + for (; *iterator < max; (*iterator)++) { + enum rsnd_mod_type type = (array) ? array[*iterator] : *iterator; + struct rsnd_mod *mod = rsnd_io_to_mod(io, type); + + if (mod) + return mod; + } + + return NULL; +} + +static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { + { + /* CAPTURE */ + RSND_MOD_AUDMAPP, + RSND_MOD_AUDMA, + RSND_MOD_DVC, + RSND_MOD_MIX, + RSND_MOD_CTU, + RSND_MOD_CMD, + RSND_MOD_SRC, + RSND_MOD_SSIU, + RSND_MOD_SSIM3, + RSND_MOD_SSIM2, + RSND_MOD_SSIM1, + RSND_MOD_SSIP, + RSND_MOD_SSI, + }, { + /* PLAYBACK */ + RSND_MOD_AUDMAPP, + RSND_MOD_AUDMA, + RSND_MOD_SSIM3, + RSND_MOD_SSIM2, + RSND_MOD_SSIM1, + RSND_MOD_SSIP, + RSND_MOD_SSI, + RSND_MOD_SSIU, + RSND_MOD_DVC, + RSND_MOD_MIX, + RSND_MOD_CTU, + RSND_MOD_CMD, + RSND_MOD_SRC, + }, +}; + +static int rsnd_status_update(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, enum rsnd_mod_type type, + int shift, int add, int timing) +{ + u32 *status = mod->ops->get_status(mod, io, type); + u32 mask = 0xF << shift; + u8 val = (*status >> shift) & 0xF; + u8 next_val = (val + add) & 0xF; + int func_call = (val == timing); + + /* no status update */ + if (add == 0 || shift == 28) + return 1; + + if (next_val == 0xF) /* underflow case */ + func_call = -1; + else + *status = (*status & ~mask) + (next_val << shift); + + return func_call; +} + +#define rsnd_dai_call(fn, io, param...) \ +({ \ + struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); \ + struct rsnd_mod *mod; \ + int is_play = rsnd_io_is_play(io); \ + int ret = 0, i; \ + enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ + for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ + int tmp = 0; \ + int func_call = rsnd_status_update(io, mod, types[i], \ + __rsnd_mod_shift_##fn, \ + __rsnd_mod_add_##fn, \ + __rsnd_mod_call_##fn); \ + if (func_call > 0 && (mod)->ops->fn) \ + tmp = (mod)->ops->fn(mod, io, param); \ + if (unlikely(func_call < 0) || \ + unlikely(tmp && (tmp != -EPROBE_DEFER))) \ + dev_err(dev, "%s : %s error (%d, %d)\n", \ + rsnd_mod_name(mod), #fn, tmp, func_call);\ + ret |= tmp; \ + } \ + ret; \ +}) + +int rsnd_dai_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) +{ + struct rsnd_priv *priv; + struct device *dev; + + if (!mod) + return -EIO; + + if (io->mod[type] == mod) + return 0; + + if (io->mod[type]) + return -EINVAL; + + priv = rsnd_mod_to_priv(mod); + dev = rsnd_priv_to_dev(priv); + + io->mod[type] = mod; + + dev_dbg(dev, "%s is connected to io (%s)\n", + rsnd_mod_name(mod), + rsnd_io_is_play(io) ? "Playback" : "Capture"); + + return 0; +} + +static void rsnd_dai_disconnect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) +{ + io->mod[type] = NULL; +} + +int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, + int max_channels) +{ + if (max_channels > 0) + rdai->max_channels = max_channels; + + return rdai->max_channels; +} + +int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, + int ssi_lane) +{ + if (ssi_lane > 0) + rdai->ssi_lane = ssi_lane; + + return rdai->ssi_lane; +} + +int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width) +{ + if (width > 0) + rdai->chan_width = width; + + return rdai->chan_width; +} + +struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) +{ + if ((id < 0) || (id >= rsnd_rdai_nr(priv))) + return NULL; + + return priv->rdai + id; +} + +static struct snd_soc_dai_driver +*rsnd_daidrv_get(struct rsnd_priv *priv, int id) +{ + if ((id < 0) || (id >= rsnd_rdai_nr(priv))) + return NULL; + + return priv->daidrv + id; +} + +#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai) +static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) +{ + struct rsnd_priv *priv = rsnd_dai_to_priv(dai); + + return rsnd_rdai_get(priv, dai->id); +} + +static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, + struct snd_pcm_substream *substream) +{ + io->substream = substream; +} + +static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) +{ + io->substream = NULL; +} + +static +struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + + return snd_soc_rtd_to_cpu(rtd, 0); +} + +static +struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai, + struct snd_pcm_substream *substream) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return &rdai->playback; + else + return &rdai->capture; +} + +static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct rsnd_priv *priv = rsnd_dai_to_priv(dai); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + int ret; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + ret = rsnd_dai_call(init, io, priv); + if (ret < 0) + goto dai_trigger_end; + + ret = rsnd_dai_call(start, io, priv); + if (ret < 0) + goto dai_trigger_end; + + ret = rsnd_dai_call(irq, io, priv, 1); + if (ret < 0) + goto dai_trigger_end; + + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + ret = rsnd_dai_call(irq, io, priv, 0); + + ret |= rsnd_dai_call(stop, io, priv); + + ret |= rsnd_dai_call(quit, io, priv); + + break; + default: + ret = -EINVAL; + } + +dai_trigger_end: + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + +static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + + /* set clock master for audio interface */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + rdai->clk_master = 0; + break; + case SND_SOC_DAIFMT_BP_FP: + rdai->clk_master = 1; /* cpu is master */ + break; + default: + return -EINVAL; + } + + /* set format */ + rdai->bit_clk_inv = 0; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + rdai->sys_delay = 0; + rdai->data_alignment = 0; + rdai->frm_clk_inv = 0; + break; + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_DSP_B: + rdai->sys_delay = 1; + rdai->data_alignment = 0; + rdai->frm_clk_inv = 1; + break; + case SND_SOC_DAIFMT_RIGHT_J: + rdai->sys_delay = 1; + rdai->data_alignment = 1; + rdai->frm_clk_inv = 1; + break; + case SND_SOC_DAIFMT_DSP_A: + rdai->sys_delay = 0; + rdai->data_alignment = 0; + rdai->frm_clk_inv = 1; + break; + } + + /* set clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + rdai->frm_clk_inv = !rdai->frm_clk_inv; + break; + case SND_SOC_DAIFMT_IB_NF: + rdai->bit_clk_inv = !rdai->bit_clk_inv; + break; + case SND_SOC_DAIFMT_IB_IF: + rdai->bit_clk_inv = !rdai->bit_clk_inv; + rdai->frm_clk_inv = !rdai->frm_clk_inv; + break; + case SND_SOC_DAIFMT_NB_NF: + default: + break; + } + + return 0; +} + +static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, + u32 tx_mask, u32 rx_mask, + int slots, int slot_width) +{ + struct rsnd_priv *priv = rsnd_dai_to_priv(dai); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct device *dev = rsnd_priv_to_dev(priv); + + switch (slot_width) { + case 16: + case 24: + case 32: + break; + default: + /* use default */ + /* + * Indicate warning if DT has "dai-tdm-slot-width" + * but the value was not expected. + */ + if (slot_width) + dev_warn(dev, "unsupported TDM slot width (%d), force to use default 32\n", + slot_width); + slot_width = 32; + } + + switch (slots) { + case 2: + /* TDM Split Mode */ + case 6: + case 8: + /* TDM Extend Mode */ + rsnd_rdai_channels_set(rdai, slots); + rsnd_rdai_ssi_lane_set(rdai, 1); + rsnd_rdai_width_set(rdai, slot_width); + break; + default: + dev_err(dev, "unsupported TDM slots (%d)\n", slots); + return -EINVAL; + } + + return 0; +} + +static unsigned int rsnd_soc_hw_channels_list[] = { + 2, 6, 8, +}; + +static unsigned int rsnd_soc_hw_rate_list[] = { + 8000, + 11025, + 16000, + 22050, + 32000, + 44100, + 48000, + 64000, + 88200, + 96000, + 176400, + 192000, +}; + +static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, + unsigned int *list, int list_num, + struct snd_interval *baseline, struct snd_interval *iv, + struct rsnd_dai_stream *io, char *unit) +{ + struct snd_interval p; + unsigned int rate; + int i; + + snd_interval_any(&p); + p.min = UINT_MAX; + p.max = 0; + + for (i = 0; i < list_num; i++) { + + if (!snd_interval_test(iv, list[i])) + continue; + + rate = rsnd_ssi_clk_query(rdai, + baseline->min, list[i], NULL); + if (rate > 0) { + p.min = min(p.min, list[i]); + p.max = max(p.max, list[i]); + } + + rate = rsnd_ssi_clk_query(rdai, + baseline->max, list[i], NULL); + if (rate > 0) { + p.min = min(p.min, list[i]); + p.max = max(p.max, list[i]); + } + } + + /* Indicate error once if it can't handle */ + if (!rsnd_flags_has(io, RSND_HW_RULE_ERR) && (p.min > p.max)) { + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_warn(dev, "It can't handle %d %s <-> %d %s\n", + baseline->min, unit, baseline->max, unit); + rsnd_flags_set(io, RSND_HW_RULE_ERR); + } + + return snd_interval_refine(iv, &p); +} + +static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval ic; + struct rsnd_dai_stream *io = rule->private; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + + /* + * possible sampling rate limitation is same as + * 2ch if it supports multi ssi + * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) + */ + ic = *ic_; + ic.min = + ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); + + return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list, + ARRAY_SIZE(rsnd_soc_hw_rate_list), + &ic, ir, io, "ch"); +} + +static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval ic; + struct rsnd_dai_stream *io = rule->private; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + + /* + * possible sampling rate limitation is same as + * 2ch if it supports multi ssi + * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) + */ + ic = *ic_; + ic.min = + ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); + + return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list, + ARRAY_SIZE(rsnd_soc_hw_channels_list), + ir, &ic, io, "Hz"); +} + +static const struct snd_pcm_hardware rsnd_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .buffer_bytes_max = 64 * 1024, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 32, + .fifo_size = 256, +}; + +static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int max_channels = rsnd_rdai_channels_get(rdai); + int i; + + rsnd_flags_del(io, RSND_HW_RULE_ERR); + + rsnd_dai_stream_init(io, substream); + + /* + * Channel Limitation + * It depends on Platform design + */ + constraint->list = rsnd_soc_hw_channels_list; + constraint->count = 0; + constraint->mask = 0; + + for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) { + if (rsnd_soc_hw_channels_list[i] > max_channels) + break; + constraint->count = i + 1; + } + + snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, constraint); + + snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + /* + * Sampling Rate / Channel Limitation + * It depends on Clock Master Mode + */ + if (rsnd_rdai_is_clk_master(rdai)) { + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + rsnd_soc_hw_rule_rate, + is_play ? &rdai->playback : &rdai->capture, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + rsnd_soc_hw_rule_channels, + is_play ? &rdai->playback : &rdai->capture, + SNDRV_PCM_HW_PARAM_RATE, -1); + } + + return 0; +} + +static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + rsnd_dai_call(cleanup, io, priv); + + rsnd_dai_stream_quit(io); +} + +static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_priv *priv = rsnd_dai_to_priv(dai); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + return rsnd_dai_call(prepare, io, priv); +} + +static const u64 rsnd_soc_dai_formats[] = { + /* + * 1st Priority + * + * Well tested formats. + * Select below from Sound Card, not auto + * SND_SOC_DAIFMT_CBC_CFC + * SND_SOC_DAIFMT_CBP_CFP + */ + SND_SOC_POSSIBLE_DAIFMT_I2S | + SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | + SND_SOC_POSSIBLE_DAIFMT_LEFT_J | + SND_SOC_POSSIBLE_DAIFMT_NB_NF | + SND_SOC_POSSIBLE_DAIFMT_NB_IF | + SND_SOC_POSSIBLE_DAIFMT_IB_NF | + SND_SOC_POSSIBLE_DAIFMT_IB_IF, + /* + * 2nd Priority + * + * Supported, but not well tested + */ + SND_SOC_POSSIBLE_DAIFMT_DSP_A | + SND_SOC_POSSIBLE_DAIFMT_DSP_B, +}; + +static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + struct device_node *dai_np) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); + struct device_node *np; + int is_play = rsnd_io_is_play(io); + int i; + + if (!ssiu_np) + return; + + /* + * This driver assumes that it is TDM Split mode + * if it includes ssiu node + */ + for (i = 0;; i++) { + struct device_node *node = is_play ? + of_parse_phandle(dai_np, "playback", i) : + of_parse_phandle(dai_np, "capture", i); + + if (!node) + break; + + for_each_child_of_node(ssiu_np, np) { + if (np == node) { + rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); + dev_dbg(dev, "%s is part of TDM Split\n", io->name); + } + } + + of_node_put(node); + } + + of_node_put(ssiu_np); +} + +static void rsnd_parse_connect_simple(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + struct device_node *dai_np) +{ + if (!rsnd_io_to_mod_ssi(io)) + return; + + rsnd_parse_tdm_split_mode(priv, io, dai_np); +} + +static void rsnd_parse_connect_graph(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + struct device_node *endpoint) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *remote_node; + + if (!rsnd_io_to_mod_ssi(io)) + return; + + remote_node = of_graph_get_remote_port_parent(endpoint); + + /* HDMI0 */ + if (strstr(remote_node->full_name, "hdmi@fead0000")) { + rsnd_flags_set(io, RSND_STREAM_HDMI0); + dev_dbg(dev, "%s connected to HDMI0\n", io->name); + } + + /* HDMI1 */ + if (strstr(remote_node->full_name, "hdmi@feae0000")) { + rsnd_flags_set(io, RSND_STREAM_HDMI1); + dev_dbg(dev, "%s connected to HDMI1\n", io->name); + } + + rsnd_parse_tdm_split_mode(priv, io, endpoint); + + of_node_put(remote_node); +} + +void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, + struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), + struct device_node *node, + struct device_node *playback, + struct device_node *capture) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np; + int i; + + if (!node) + return; + + i = 0; + for_each_child_of_node(node, np) { + struct rsnd_mod *mod; + + i = rsnd_node_fixed_index(dev, np, name, i); + if (i < 0) { + of_node_put(np); + break; + } + + mod = mod_get(priv, i); + + if (np == playback) + rsnd_dai_connect(mod, &rdai->playback, mod->type); + if (np == capture) + rsnd_dai_connect(mod, &rdai->capture, mod->type); + i++; + } + + of_node_put(node); +} + +int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx) +{ + char node_name[16]; + + /* + * rsnd is assuming each device nodes are sequential numbering, + * but some of them are not. + * This function adjusts index for it. + * + * ex) + * Normal case, special case + * ssi-0 + * ssi-1 + * ssi-2 + * ssi-3 ssi-3 + * ssi-4 ssi-4 + * ... + * + * assume Max 64 node + */ + for (; idx < 64; idx++) { + snprintf(node_name, sizeof(node_name), "%s-%d", name, idx); + + if (strncmp(node_name, of_node_full_name(node), sizeof(node_name)) == 0) + return idx; + } + + dev_err(dev, "strange node numbering (%s)", + of_node_full_name(node)); + return -EINVAL; +} + +int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np; + int i; + + i = 0; + for_each_child_of_node(node, np) { + i = rsnd_node_fixed_index(dev, np, name, i); + if (i < 0) { + of_node_put(np); + return 0; + } + i++; + } + + return i; +} + +static struct device_node* + rsnd_pick_endpoint_node_for_ports(struct device_node *e_ports, + struct device_node *e_port) +{ + if (of_node_name_eq(e_ports, "ports")) + return e_ports; + + if (of_node_name_eq(e_ports, "port")) + return e_port; + + return NULL; +} + +static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; + struct device_node *ports, *node; + int nr = 0; + int i = 0; + + *is_graph = 0; + + /* + * parse both previous dai (= rcar_sound,dai), and + * graph dai (= ports/port) + */ + + /* + * Simple-Card + */ + node = of_get_child_by_name(np, RSND_NODE_DAI); + if (!node) + goto audio_graph; + + of_node_put(node); + + for_each_child_of_node(np, node) { + if (!of_node_name_eq(node, RSND_NODE_DAI)) + continue; + + priv->component_dais[i] = of_get_child_count(node); + nr += priv->component_dais[i]; + i++; + if (i >= RSND_MAX_COMPONENT) { + dev_info(dev, "reach to max component\n"); + of_node_put(node); + break; + } + } + + return nr; + +audio_graph: + /* + * Audio-Graph-Card + */ + for_each_child_of_node(np, ports) { + node = rsnd_pick_endpoint_node_for_ports(ports, np); + if (!node) + continue; + priv->component_dais[i] = of_graph_get_endpoint_count(node); + nr += priv->component_dais[i]; + i++; + if (i >= RSND_MAX_COMPONENT) { + dev_info(dev, "reach to max component\n"); + of_node_put(ports); + break; + } + } + + *is_graph = 1; + + return nr; +} + + +#define PREALLOC_BUFFER (32 * 1024) +#define PREALLOC_BUFFER_MAX (32 * 1024) + +static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, + struct rsnd_dai_stream *io, + int stream) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + struct snd_pcm_substream *substream; + + /* + * use Audio-DMAC dev if we can use IPMMU + * see + * rsnd_dmaen_attach() + */ + if (io->dmac_dev) + dev = io->dmac_dev; + + for (substream = rtd->pcm->streams[stream].substream; + substream; + substream = substream->next) { + snd_pcm_set_managed_buffer(substream, + SNDRV_DMA_TYPE_DEV, + dev, + PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); + } + + return 0; +} + +static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + int ret; + + ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd); + if (ret) + return ret; + + ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd); + if (ret) + return ret; + + ret = rsnd_preallocate_pages(rtd, &rdai->playback, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + return ret; + + ret = rsnd_preallocate_pages(rtd, &rdai->capture, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + return ret; + + return 0; +} + +static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .pcm_new = rsnd_soc_dai_pcm_new, + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, + .trigger = rsnd_soc_dai_trigger, + .set_fmt = rsnd_soc_dai_set_fmt, + .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, + .prepare = rsnd_soc_dai_prepare, + .auto_selectable_formats = rsnd_soc_dai_formats, + .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), +}; + +static void __rsnd_dai_probe(struct rsnd_priv *priv, + struct device_node *dai_np, + struct device_node *node_np, + uint32_t node_arg, + int dai_i) +{ + struct rsnd_dai_stream *io_playback; + struct rsnd_dai_stream *io_capture; + struct snd_soc_dai_driver *drv; + struct rsnd_dai *rdai; + struct device *dev = rsnd_priv_to_dev(priv); + int playback_exist = 0, capture_exist = 0; + int io_i; + + rdai = rsnd_rdai_get(priv, dai_i); + drv = rsnd_daidrv_get(priv, dai_i); + io_playback = &rdai->playback; + io_capture = &rdai->capture; + + snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); + + /* for multi Component */ + rdai->dai_args.np = node_np; + rdai->dai_args.args_count = 1; + rdai->dai_args.args[0] = node_arg; + + rdai->priv = priv; + drv->name = rdai->name; + drv->ops = &rsnd_soc_dai_ops; + drv->id = dai_i; + drv->dai_args = &rdai->dai_args; + + io_playback->rdai = rdai; + io_capture->rdai = rdai; + rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ + rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ + rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ + + for (io_i = 0;; io_i++) { + struct device_node *playback = of_parse_phandle(dai_np, "playback", io_i); + struct device_node *capture = of_parse_phandle(dai_np, "capture", io_i); + + if (!playback && !capture) + break; + + if (io_i == 0) { + /* check whether playback/capture property exists */ + if (playback) + playback_exist = 1; + if (capture) + capture_exist = 1; + } + + rsnd_parse_connect_ssi(rdai, playback, capture); + rsnd_parse_connect_ssiu(rdai, playback, capture); + rsnd_parse_connect_src(rdai, playback, capture); + rsnd_parse_connect_ctu(rdai, playback, capture); + rsnd_parse_connect_mix(rdai, playback, capture); + rsnd_parse_connect_dvc(rdai, playback, capture); + + of_node_put(playback); + of_node_put(capture); + } + + if (playback_exist) { + snprintf(io_playback->name, RSND_DAI_NAME_SIZE, "DAI%d Playback", dai_i); + drv->playback.rates = RSND_RATES; + drv->playback.formats = RSND_FMTS; + drv->playback.channels_min = 2; + drv->playback.channels_max = 8; + drv->playback.stream_name = io_playback->name; + } + if (capture_exist) { + snprintf(io_capture->name, RSND_DAI_NAME_SIZE, "DAI%d Capture", dai_i); + drv->capture.rates = RSND_RATES; + drv->capture.formats = RSND_FMTS; + drv->capture.channels_min = 2; + drv->capture.channels_max = 8; + drv->capture.stream_name = io_capture->name; + } + + if (rsnd_ssi_is_pin_sharing(io_capture) || + rsnd_ssi_is_pin_sharing(io_playback)) { + /* should have symmetric_rate if pin sharing */ + drv->symmetric_rate = 1; + } + + dev_dbg(dev, "%s (%s/%s)\n", rdai->name, + rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", + rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); +} + +static int rsnd_dai_probe(struct rsnd_priv *priv) +{ + struct snd_soc_dai_driver *rdrv; + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *np = dev->of_node; + struct rsnd_dai *rdai; + int nr = 0; + int is_graph; + int dai_i; + + nr = rsnd_dai_of_node(priv, &is_graph); + if (!nr) + return -EINVAL; + + rdrv = devm_kcalloc(dev, nr, sizeof(*rdrv), GFP_KERNEL); + rdai = devm_kcalloc(dev, nr, sizeof(*rdai), GFP_KERNEL); + if (!rdrv || !rdai) + return -ENOMEM; + + priv->rdai_nr = nr; + priv->daidrv = rdrv; + priv->rdai = rdai; + + /* + * parse all dai + */ + dai_i = 0; + if (is_graph) { + struct device_node *dai_np_port; + struct device_node *ports; + struct device_node *dai_np; + + for_each_child_of_node(np, ports) { + dai_np_port = rsnd_pick_endpoint_node_for_ports(ports, np); + if (!dai_np_port) + continue; + + for_each_endpoint_of_node(dai_np_port, dai_np) { + __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); + if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) { + rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); + rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); + } + dai_i++; + } + } + } else { + struct device_node *node; + struct device_node *dai_np; + + for_each_child_of_node(np, node) { + if (!of_node_name_eq(node, RSND_NODE_DAI)) + continue; + + for_each_child_of_node(node, dai_np) { + __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); + if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) { + rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); + rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); + } + dai_i++; + } + } + } + + return 0; +} + +/* + * pcm ops + */ +static int rsnd_hw_update(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->lock, flags); + if (hw_params) + ret = rsnd_dai_call(hw_params, io, substream, hw_params); + else + ret = rsnd_dai_call(hw_free, io, substream); + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + +static int rsnd_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); + + /* + * rsnd assumes that it might be used under DPCM if user want to use + * channel / rate convert. Then, rsnd should be FE. + * And then, this function will be called *after* BE settings. + * this means, each BE already has fixuped hw_params. + * see + * dpcm_fe_dai_hw_params() + * dpcm_be_dai_hw_params() + */ + io->converted_rate = 0; + io->converted_chan = 0; + if (fe->dai_link->dynamic) { + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + struct snd_soc_dpcm *dpcm; + int stream = substream->stream; + + for_each_dpcm_be(fe, stream, dpcm) { + struct snd_soc_pcm_runtime *be = dpcm->be; + struct snd_pcm_hw_params *be_params = &be->dpcm[stream].hw_params; + + if (params_channels(hw_params) != params_channels(be_params)) + io->converted_chan = params_channels(be_params); + if (params_rate(hw_params) != params_rate(be_params)) + io->converted_rate = params_rate(be_params); + } + if (io->converted_chan) + dev_dbg(dev, "convert channels = %d\n", io->converted_chan); + if (io->converted_rate) { + /* + * SRC supports convert rates from params_rate(hw_params)/k_down + * to params_rate(hw_params)*k_up, where k_up is always 6, and + * k_down depends on number of channels and SRC unit. + * So all SRC units can upsample audio up to 6 times regardless + * its number of channels. And all SRC units can downsample + * 2 channel audio up to 6 times too. + */ + int k_up = 6; + int k_down = 6; + int channel; + struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); + + dev_dbg(dev, "convert rate = %d\n", io->converted_rate); + + channel = io->converted_chan ? io->converted_chan : + params_channels(hw_params); + + switch (rsnd_mod_id(src_mod)) { + /* + * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times. + * SRC1, SRC3 and SRC4 can downsample 4 channel audio + * up to 4 times. + * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio + * no more than twice. + */ + case 1: + case 3: + case 4: + if (channel > 4) { + k_down = 2; + break; + } + fallthrough; + case 0: + if (channel > 2) + k_down = 4; + break; + + /* Other SRC units do not support more than 2 channels */ + default: + if (channel > 2) + return -EINVAL; + } + + if (params_rate(hw_params) > io->converted_rate * k_down) { + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = + io->converted_rate * k_down; + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = + io->converted_rate * k_down; + hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; + } else if (params_rate(hw_params) * k_up < io->converted_rate) { + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = + DIV_ROUND_UP(io->converted_rate, k_up); + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = + DIV_ROUND_UP(io->converted_rate, k_up); + hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; + } + + /* + * TBD: Max SRC input and output rates also depend on number + * of channels and SRC unit: + * SRC1, SRC3 and SRC4 do not support more than 128kHz + * for 6 channel and 96kHz for 8 channel audio. + * Perhaps this function should return EINVAL if the input or + * the output rate exceeds the limitation. + */ + } + } + + return rsnd_hw_update(substream, hw_params); +} + +static int rsnd_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + return rsnd_hw_update(substream, NULL); +} + +static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + snd_pcm_uframes_t pointer = 0; + + rsnd_dai_call(pointer, io, &pointer); + + return pointer; +} + +/* + * snd_kcontrol + */ +static int rsnd_kctrl_info(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_info *uinfo) +{ + struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); + + if (cfg->texts) { + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = cfg->size; + uinfo->value.enumerated.items = cfg->max; + if (uinfo->value.enumerated.item >= cfg->max) + uinfo->value.enumerated.item = cfg->max - 1; + strscpy(uinfo->value.enumerated.name, + cfg->texts[uinfo->value.enumerated.item], + sizeof(uinfo->value.enumerated.name)); + } else { + uinfo->count = cfg->size; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = cfg->max; + uinfo->type = (cfg->max == 1) ? + SNDRV_CTL_ELEM_TYPE_BOOLEAN : + SNDRV_CTL_ELEM_TYPE_INTEGER; + } + + return 0; +} + +static int rsnd_kctrl_get(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *uc) +{ + struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); + int i; + + for (i = 0; i < cfg->size; i++) + if (cfg->texts) + uc->value.enumerated.item[i] = cfg->val[i]; + else + uc->value.integer.value[i] = cfg->val[i]; + + return 0; +} + +static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *uc) +{ + struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); + int i, change = 0; + + if (!cfg->accept(cfg->io)) + return 0; + + for (i = 0; i < cfg->size; i++) { + if (cfg->texts) { + change |= (uc->value.enumerated.item[i] != cfg->val[i]); + cfg->val[i] = uc->value.enumerated.item[i]; + } else { + change |= (uc->value.integer.value[i] != cfg->val[i]); + cfg->val[i] = uc->value.integer.value[i]; + } + } + + if (change && cfg->update) + cfg->update(cfg->io, cfg->mod); + + return change; +} + +int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) +{ + return 1; +} + +int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + + if (!runtime) { + dev_warn(dev, "Can't update kctrl when idle\n"); + return 0; + } + + return 1; +} + +struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) +{ + cfg->cfg.val = cfg->val; + + return &cfg->cfg; +} + +struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg) +{ + cfg->cfg.val = &cfg->val; + + return &cfg->cfg; +} + +const char * const volume_ramp_rate[] = { + "128 dB/1 step", /* 00000 */ + "64 dB/1 step", /* 00001 */ + "32 dB/1 step", /* 00010 */ + "16 dB/1 step", /* 00011 */ + "8 dB/1 step", /* 00100 */ + "4 dB/1 step", /* 00101 */ + "2 dB/1 step", /* 00110 */ + "1 dB/1 step", /* 00111 */ + "0.5 dB/1 step", /* 01000 */ + "0.25 dB/1 step", /* 01001 */ + "0.125 dB/1 step", /* 01010 = VOLUME_RAMP_MAX_MIX */ + "0.125 dB/2 steps", /* 01011 */ + "0.125 dB/4 steps", /* 01100 */ + "0.125 dB/8 steps", /* 01101 */ + "0.125 dB/16 steps", /* 01110 */ + "0.125 dB/32 steps", /* 01111 */ + "0.125 dB/64 steps", /* 10000 */ + "0.125 dB/128 steps", /* 10001 */ + "0.125 dB/256 steps", /* 10010 */ + "0.125 dB/512 steps", /* 10011 */ + "0.125 dB/1024 steps", /* 10100 */ + "0.125 dB/2048 steps", /* 10101 */ + "0.125 dB/4096 steps", /* 10110 */ + "0.125 dB/8192 steps", /* 10111 = VOLUME_RAMP_MAX_DVC */ +}; + +int rsnd_kctrl_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd, + const unsigned char *name, + int (*accept)(struct rsnd_dai_stream *io), + void (*update)(struct rsnd_dai_stream *io, + struct rsnd_mod *mod), + struct rsnd_kctrl_cfg *cfg, + const char * const *texts, + int size, + u32 max) +{ + struct snd_card *card = rtd->card->snd_card; + struct snd_kcontrol *kctrl; + struct snd_kcontrol_new knew = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = name, + .info = rsnd_kctrl_info, + .index = rtd->id, + .get = rsnd_kctrl_get, + .put = rsnd_kctrl_put, + }; + int ret; + + /* + * 1) Avoid duplicate register for DVC with MIX case + * 2) Allow duplicate register for MIX + * 3) re-register if card was rebinded + */ + list_for_each_entry(kctrl, &card->controls, list) { + struct rsnd_kctrl_cfg *c = kctrl->private_data; + + if (c == cfg) + return 0; + } + + if (size > RSND_MAX_CHANNELS) + return -EINVAL; + + kctrl = snd_ctl_new1(&knew, cfg); + if (!kctrl) + return -ENOMEM; + + ret = snd_ctl_add(card, kctrl); + if (ret < 0) + return ret; + + cfg->texts = texts; + cfg->max = max; + cfg->size = size; + cfg->accept = accept; + cfg->update = update; + cfg->card = card; + cfg->kctrl = kctrl; + cfg->io = io; + cfg->mod = mod; + + return 0; +} + +/* + * snd_soc_component + */ +static const struct snd_soc_component_driver rsnd_soc_component = { + .name = "rsnd", + .probe = rsnd_debugfs_probe, + .hw_params = rsnd_hw_params, + .hw_free = rsnd_hw_free, + .pointer = rsnd_pointer, + .legacy_dai_naming = 1, +}; + +static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, + struct rsnd_dai_stream *io) +{ + int ret; + + ret = rsnd_dai_call(probe, io, priv); + if (ret == -EAGAIN) { + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *mod; + int i; + + /* + * Fallback to PIO mode + */ + + /* + * call "remove" for SSI/SRC/DVC + * SSI will be switch to PIO mode if it was DMA mode + * see + * rsnd_dma_init() + * rsnd_ssi_fallback() + */ + rsnd_dai_call(remove, io, priv); + + /* + * remove all mod from io + * and, re connect ssi + */ + for_each_rsnd_mod(i, mod, io) + rsnd_dai_disconnect(mod, io, i); + rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); + + /* + * fallback + */ + rsnd_dai_call(fallback, io, priv); + + /* + * retry to "probe". + * DAI has SSI which is PIO mode only now. + */ + ret = rsnd_dai_call(probe, io, priv); + } + + return ret; +} + +/* + * rsnd probe + */ +static int rsnd_probe(struct platform_device *pdev) +{ + struct rsnd_priv *priv; + struct device *dev = &pdev->dev; + struct rsnd_dai *rdai; + int (*probe_func[])(struct rsnd_priv *priv) = { + rsnd_gen_probe, + rsnd_dma_probe, + rsnd_ssi_probe, + rsnd_ssiu_probe, + rsnd_src_probe, + rsnd_ctu_probe, + rsnd_mix_probe, + rsnd_dvc_probe, + rsnd_cmd_probe, + rsnd_adg_probe, + rsnd_dai_probe, + }; + int ret, i; + int ci; + + /* + * init priv data + */ + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENODEV; + + priv->pdev = pdev; + priv->flags = (unsigned long)of_device_get_match_data(dev); + spin_lock_init(&priv->lock); + + /* + * init each module + */ + for (i = 0; i < ARRAY_SIZE(probe_func); i++) { + ret = probe_func[i](priv); + if (ret) + return ret; + } + + for_each_rsnd_dai(rdai, priv, i) { + ret = rsnd_rdai_continuance_probe(priv, &rdai->playback); + if (ret) + goto exit_snd_probe; + + ret = rsnd_rdai_continuance_probe(priv, &rdai->capture); + if (ret) + goto exit_snd_probe; + } + + dev_set_drvdata(dev, priv); + + /* + * asoc register + */ + ci = 0; + for (i = 0; priv->component_dais[i] > 0; i++) { + int nr = priv->component_dais[i]; + + ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, + priv->daidrv + ci, nr); + if (ret < 0) { + dev_err(dev, "cannot snd component register\n"); + goto exit_snd_probe; + } + + ci += nr; + } + + pm_runtime_enable(dev); + + dev_info(dev, "probed\n"); + return ret; + +exit_snd_probe: + for_each_rsnd_dai(rdai, priv, i) { + rsnd_dai_call(remove, &rdai->playback, priv); + rsnd_dai_call(remove, &rdai->capture, priv); + } + + /* + * adg is very special mod which can't use rsnd_dai_call(remove), + * and it registers ADG clock on probe. + * It should be unregister if probe failed. + * Mainly it is assuming -EPROBE_DEFER case + */ + rsnd_adg_remove(priv); + + return ret; +} + +static void rsnd_remove(struct platform_device *pdev) +{ + struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); + struct rsnd_dai *rdai; + void (*remove_func[])(struct rsnd_priv *priv) = { + rsnd_ssi_remove, + rsnd_ssiu_remove, + rsnd_src_remove, + rsnd_ctu_remove, + rsnd_mix_remove, + rsnd_dvc_remove, + rsnd_cmd_remove, + rsnd_adg_remove, + }; + int i; + + pm_runtime_disable(&pdev->dev); + + for_each_rsnd_dai(rdai, priv, i) { + int ret; + + ret = rsnd_dai_call(remove, &rdai->playback, priv); + if (ret) + dev_warn(&pdev->dev, "Failed to remove playback dai #%d\n", i); + + ret = rsnd_dai_call(remove, &rdai->capture, priv); + if (ret) + dev_warn(&pdev->dev, "Failed to remove capture dai #%d\n", i); + } + + for (i = 0; i < ARRAY_SIZE(remove_func); i++) + remove_func[i](priv); +} + +static int __maybe_unused rsnd_suspend(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_disable(priv); + + return 0; +} + +static int __maybe_unused rsnd_resume(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_enable(priv); + + return 0; +} + +static const struct dev_pm_ops rsnd_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume) +}; + +static struct platform_driver rsnd_driver = { + .driver = { + .name = "rcar_sound", + .pm = &rsnd_pm_ops, + .of_match_table = rsnd_of_match, + }, + .probe = rsnd_probe, + .remove = rsnd_remove, +}; +module_platform_driver(rsnd_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Renesas R-Car audio driver"); +MODULE_AUTHOR("Kuninori Morimoto "); +MODULE_ALIAS("platform:rcar-pcm-audio"); diff --git a/sound/soc/renesas/rcar/ctu.c b/sound/soc/renesas/rcar/ctu.c new file mode 100644 index 00000000000000..a26ec7b780cd64 --- /dev/null +++ b/sound/soc/renesas/rcar/ctu.c @@ -0,0 +1,389 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// ctu.c +// +// Copyright (c) 2015 Kuninori Morimoto + +#include "rsnd.h" + +#define CTU_NAME_SIZE 16 +#define CTU_NAME "ctu" + +/* + * User needs to setup CTU by amixer, and its settings are + * based on below registers + * + * CTUn_CPMDR : amixser set "CTU Pass" + * CTUn_SV0xR : amixser set "CTU SV0" + * CTUn_SV1xR : amixser set "CTU SV1" + * CTUn_SV2xR : amixser set "CTU SV2" + * CTUn_SV3xR : amixser set "CTU SV3" + * + * [CTU Pass] + * 0000: default + * 0001: Connect input data of channel 0 + * 0010: Connect input data of channel 1 + * 0011: Connect input data of channel 2 + * 0100: Connect input data of channel 3 + * 0101: Connect input data of channel 4 + * 0110: Connect input data of channel 5 + * 0111: Connect input data of channel 6 + * 1000: Connect input data of channel 7 + * 1001: Connect calculated data by scale values of matrix row 0 + * 1010: Connect calculated data by scale values of matrix row 1 + * 1011: Connect calculated data by scale values of matrix row 2 + * 1100: Connect calculated data by scale values of matrix row 3 + * + * [CTU SVx] + * [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07] + * [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17] + * [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27] + * [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37] + * [Output4] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] + * [Output5] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] + * [Output6] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] + * [Output7] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] + * + * [SVxx] + * Plus Minus + * value time dB value time dB + * ----------------------------------------------------------------------- + * H'7F_FFFF 2 6 H'80_0000 2 6 + * ... + * H'40_0000 1 0 H'C0_0000 1 0 + * ... + * H'00_0001 2.38 x 10^-7 -132 + * H'00_0000 0 Mute H'FF_FFFF 2.38 x 10^-7 -132 + * + * + * Ex) Input ch -> Output ch + * 1ch -> 0ch + * 0ch -> 1ch + * + * amixer set "CTU Reset" on + * amixer set "CTU Pass" 9,10 + * amixer set "CTU SV0" 0,4194304 + * amixer set "CTU SV1" 4194304,0 + * or + * amixer set "CTU Reset" on + * amixer set "CTU Pass" 2,1 + */ + +struct rsnd_ctu { + struct rsnd_mod mod; + struct rsnd_kctrl_cfg_m pass; + struct rsnd_kctrl_cfg_m sv[4]; + struct rsnd_kctrl_cfg_s reset; + int channels; + u32 flags; +}; + +#define KCTRL_INITIALIZED (1 << 0) + +#define rsnd_ctu_nr(priv) ((priv)->ctu_nr) +#define for_each_rsnd_ctu(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_ctu_nr(priv)) && \ + ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ + i++) + +#define rsnd_mod_to_ctu(_mod) \ + container_of((_mod), struct rsnd_ctu, mod) + +#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) + +static void rsnd_ctu_activation(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, CTU_SWRSR, 0); + rsnd_mod_write(mod, CTU_SWRSR, 1); +} + +static void rsnd_ctu_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, CTU_CTUIR, 1); + rsnd_mod_write(mod, CTU_SWRSR, 0); +} + +static int rsnd_ctu_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod)); +} + +static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); + u32 cpmdr = 0; + u32 scmdr = 0; + int i, j; + + for (i = 0; i < RSND_MAX_CHANNELS; i++) { + u32 val = rsnd_kctrl_valm(ctu->pass, i); + + cpmdr |= val << (28 - (i * 4)); + + if ((val > 0x8) && (scmdr < (val - 0x8))) + scmdr = val - 0x8; + } + + rsnd_mod_write(mod, CTU_CTUIR, 1); + + rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io)); + + rsnd_mod_write(mod, CTU_CPMDR, cpmdr); + + rsnd_mod_write(mod, CTU_SCMDR, scmdr); + + for (i = 0; i < 4; i++) { + + if (i >= scmdr) + break; + + for (j = 0; j < RSND_MAX_CHANNELS; j++) + rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j)); + } + + rsnd_mod_write(mod, CTU_CTUIR, 0); +} + +static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); + int i; + + if (!rsnd_kctrl_vals(ctu->reset)) + return; + + for (i = 0; i < RSND_MAX_CHANNELS; i++) { + rsnd_kctrl_valm(ctu->pass, i) = 0; + rsnd_kctrl_valm(ctu->sv[0], i) = 0; + rsnd_kctrl_valm(ctu->sv[1], i) = 0; + rsnd_kctrl_valm(ctu->sv[2], i) = 0; + rsnd_kctrl_valm(ctu->sv[3], i) = 0; + } + rsnd_kctrl_vals(ctu->reset) = 0; +} + +static int rsnd_ctu_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + int ret; + + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; + + rsnd_ctu_activation(mod); + + rsnd_ctu_value_init(io, mod); + + return 0; +} + +static int rsnd_ctu_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_ctu_halt(mod); + + rsnd_mod_power_off(mod); + + return 0; +} + +static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd) +{ + struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); + int ret; + + if (rsnd_flags_has(ctu, KCTRL_INITIALIZED)) + return 0; + + /* CTU Pass */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", + rsnd_kctrl_accept_anytime, + NULL, + &ctu->pass, RSND_MAX_CHANNELS, + 0xC); + if (ret < 0) + return ret; + + /* ROW0 */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", + rsnd_kctrl_accept_anytime, + NULL, + &ctu->sv[0], RSND_MAX_CHANNELS, + 0x00FFFFFF); + if (ret < 0) + return ret; + + /* ROW1 */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", + rsnd_kctrl_accept_anytime, + NULL, + &ctu->sv[1], RSND_MAX_CHANNELS, + 0x00FFFFFF); + if (ret < 0) + return ret; + + /* ROW2 */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", + rsnd_kctrl_accept_anytime, + NULL, + &ctu->sv[2], RSND_MAX_CHANNELS, + 0x00FFFFFF); + if (ret < 0) + return ret; + + /* ROW3 */ + ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", + rsnd_kctrl_accept_anytime, + NULL, + &ctu->sv[3], RSND_MAX_CHANNELS, + 0x00FFFFFF); + if (ret < 0) + return ret; + + /* Reset */ + ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset", + rsnd_kctrl_accept_anytime, + rsnd_ctu_value_reset, + &ctu->reset, 1); + + rsnd_flags_set(ctu, KCTRL_INITIALIZED); + + return ret; +} + +static int rsnd_ctu_id(struct rsnd_mod *mod) +{ + /* + * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0 + * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1 + */ + return mod->id / 4; +} + +static int rsnd_ctu_id_sub(struct rsnd_mod *mod) +{ + /* + * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3 + * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3 + */ + return mod->id % 4; +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_ctu_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, + 0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100); +} +#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info +#else +#define DEBUG_INFO +#endif + +static struct rsnd_mod_ops rsnd_ctu_ops = { + .name = CTU_NAME, + .probe = rsnd_ctu_probe_, + .init = rsnd_ctu_init, + .quit = rsnd_ctu_quit, + .pcm_new = rsnd_ctu_pcm_new, + .get_status = rsnd_mod_get_status, + .id = rsnd_ctu_id, + .id_sub = rsnd_ctu_id_sub, + .id_cmd = rsnd_mod_id_raw, + DEBUG_INFO +}; + +struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) + id = 0; + + return rsnd_mod_get(rsnd_ctu_get(priv, id)); +} + +int rsnd_ctu_probe(struct rsnd_priv *priv) +{ + struct device_node *node; + struct device_node *np; + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_ctu *ctu; + struct clk *clk; + char name[CTU_NAME_SIZE]; + int i, nr, ret; + + node = rsnd_ctu_of_node(priv); + if (!node) + return 0; /* not used is not error */ + + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_ctu_probe_done; + } + + ctu = devm_kcalloc(dev, nr, sizeof(*ctu), GFP_KERNEL); + if (!ctu) { + ret = -ENOMEM; + goto rsnd_ctu_probe_done; + } + + priv->ctu_nr = nr; + priv->ctu = ctu; + + i = 0; + ret = 0; + for_each_child_of_node(node, np) { + ctu = rsnd_ctu_get(priv, i); + + /* + * CTU00, CTU01, CTU02, CTU03 => CTU0 + * CTU10, CTU11, CTU12, CTU13 => CTU1 + */ + snprintf(name, CTU_NAME_SIZE, "%s.%d", + CTU_NAME, i / 4); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + of_node_put(np); + goto rsnd_ctu_probe_done; + } + + ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, + clk, RSND_MOD_CTU, i); + if (ret) { + of_node_put(np); + goto rsnd_ctu_probe_done; + } + + i++; + } + + +rsnd_ctu_probe_done: + of_node_put(node); + + return ret; +} + +void rsnd_ctu_remove(struct rsnd_priv *priv) +{ + struct rsnd_ctu *ctu; + int i; + + for_each_rsnd_ctu(ctu, priv, i) { + rsnd_mod_quit(rsnd_mod_get(ctu)); + } +} diff --git a/sound/soc/renesas/rcar/debugfs.c b/sound/soc/renesas/rcar/debugfs.c new file mode 100644 index 00000000000000..26d3b310b9db7d --- /dev/null +++ b/sound/soc/renesas/rcar/debugfs.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// // Renesas R-Car debugfs support +// +// Copyright (c) 2021 Kuninori Morimoto +// +// > mount -t debugfs none /sys/kernel/debug +// > cd /sys/kernel/debug/asoc/rcar-sound/ec500000.sound/rdai{N}/ +// > cat playback/xxx +// > cat capture/xxx +// +#ifdef CONFIG_DEBUG_FS + +#include +#include "rsnd.h" + +static int rsnd_debugfs_show(struct seq_file *m, void *v) +{ + struct rsnd_dai_stream *io = m->private; + struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + int i; + + /* adg is out of mods */ + rsnd_adg_clk_dbg_info(priv, m); + + for_each_rsnd_mod(i, mod, io) { + u32 *status = mod->ops->get_status(mod, io, mod->type); + + seq_printf(m, "name: %s\n", rsnd_mod_name(mod)); + seq_printf(m, "status: %08x\n", *status); + + if (mod->ops->debug_info) + mod->ops->debug_info(m, io, mod); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rsnd_debugfs); + +void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr, + void __iomem *base, int offset, int size) +{ + int i, j; + + for (i = 0; i < size; i += 0x10) { + phys_addr_t addr = _addr + offset + i; + + seq_printf(m, "%pa:", &addr); + for (j = 0; j < 0x10; j += 0x4) + seq_printf(m, " %08x", __raw_readl(base + offset + i + j)); + seq_puts(m, "\n"); + } +} + +void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod, + int reg_id, int offset, int size) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + + rsnd_debugfs_reg_show(m, + rsnd_gen_get_phy_addr(priv, reg_id), + rsnd_gen_get_base_addr(priv, reg_id), + offset, size); +} + +int rsnd_debugfs_probe(struct snd_soc_component *component) +{ + struct rsnd_priv *priv = dev_get_drvdata(component->dev); + struct rsnd_dai *rdai; + struct dentry *dir; + char name[64]; + int i; + + /* Gen1 is not supported */ + if (rsnd_is_gen1(priv)) + return 0; + + for_each_rsnd_dai(rdai, priv, i) { + /* + * created debugfs will be automatically + * removed, nothing to do for _remove. + * see + * soc_cleanup_component_debugfs() + */ + snprintf(name, sizeof(name), "rdai%d", i); + dir = debugfs_create_dir(name, component->debugfs_root); + + debugfs_create_file("playback", 0444, dir, &rdai->playback, &rsnd_debugfs_fops); + debugfs_create_file("capture", 0444, dir, &rdai->capture, &rsnd_debugfs_fops); + } + + return 0; +} + +#endif /* CONFIG_DEBUG_FS */ diff --git a/sound/soc/renesas/rcar/dma.c b/sound/soc/renesas/rcar/dma.c new file mode 100644 index 00000000000000..2342bbb6fe92e8 --- /dev/null +++ b/sound/soc/renesas/rcar/dma.c @@ -0,0 +1,885 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car Audio DMAC support +// +// Copyright (C) 2015 Renesas Electronics Corp. +// Copyright (c) 2015 Kuninori Morimoto + +#include +#include +#include +#include "rsnd.h" + +/* + * Audio DMAC peri peri register + */ +#define PDMASAR 0x00 +#define PDMADAR 0x04 +#define PDMACHCR 0x0c + +/* PDMACHCR */ +#define PDMACHCR_DE (1 << 0) + + +struct rsnd_dmaen { + struct dma_chan *chan; +}; + +struct rsnd_dmapp { + int dmapp_id; + u32 chcr; +}; + +struct rsnd_dma { + struct rsnd_mod mod; + struct rsnd_mod *mod_from; + struct rsnd_mod *mod_to; + dma_addr_t src_addr; + dma_addr_t dst_addr; + union { + struct rsnd_dmaen en; + struct rsnd_dmapp pp; + } dma; +}; + +struct rsnd_dma_ctrl { + void __iomem *ppbase; + phys_addr_t ppres; + int dmaen_num; + int dmapp_num; +}; + +#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) +#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod) +#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) +#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) + +/* for DEBUG */ +static struct rsnd_mod_ops mem_ops = { + .name = "mem", +}; + +static struct rsnd_mod mem = { +}; + +/* + * Audio DMAC + */ +static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, + struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to) +{ + if ((!mod_from && !mod_to) || + (mod_from && mod_to)) + return NULL; + + if (mod_from) + return rsnd_mod_dma_req(io, mod_from); + else + return rsnd_mod_dma_req(io, mod_to); +} + +static int rsnd_dmaen_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP); +} + +static int rsnd_dmaen_cleanup(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + + /* + * DMAEngine release uses mutex lock. + * Thus, it shouldn't be called under spinlock. + * Let's call it under prepare + */ + if (dmaen->chan) + snd_dmaengine_pcm_close_release_chan(io->substream); + + dmaen->chan = NULL; + + return 0; +} + +static int rsnd_dmaen_prepare(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + struct device *dev = rsnd_priv_to_dev(priv); + + /* maybe suspended */ + if (dmaen->chan) + return 0; + + /* + * DMAEngine request uses mutex lock. + * Thus, it shouldn't be called under spinlock. + * Let's call it under prepare + */ + dmaen->chan = rsnd_dmaen_request_channel(io, + dma->mod_from, + dma->mod_to); + if (IS_ERR_OR_NULL(dmaen->chan)) { + dmaen->chan = NULL; + dev_err(dev, "can't get dma channel\n"); + return -EIO; + } + + return snd_dmaengine_pcm_open(io->substream, dmaen->chan); +} + +static int rsnd_dmaen_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + struct device *dev = rsnd_priv_to_dev(priv); + struct dma_slave_config cfg = {}; + enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + int ret; + + /* + * in case of monaural data writing or reading through Audio-DMAC + * data is always in Left Justified format, so both src and dst + * DMA Bus width need to be set equal to physical data width. + */ + if (rsnd_runtime_channel_original(io) == 1) { + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int bits = snd_pcm_format_physical_width(runtime->format); + + switch (bits) { + case 8: + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; + break; + case 16: + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + break; + case 32: + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + break; + default: + dev_err(dev, "invalid format width %d\n", bits); + return -EINVAL; + } + } + + cfg.direction = snd_pcm_substream_to_dma_direction(io->substream); + cfg.src_addr = dma->src_addr; + cfg.dst_addr = dma->dst_addr; + cfg.src_addr_width = buswidth; + cfg.dst_addr_width = buswidth; + + dev_dbg(dev, "%s %pad -> %pad\n", + rsnd_mod_name(mod), + &cfg.src_addr, &cfg.dst_addr); + + ret = dmaengine_slave_config(dmaen->chan, &cfg); + if (ret < 0) + return ret; + + return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START); +} + +struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, + struct rsnd_mod *mod, char *x) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct dma_chan *chan = NULL; + struct device_node *np; + int i = 0; + + for_each_child_of_node(of_node, np) { + i = rsnd_node_fixed_index(dev, np, name, i); + if (i < 0) { + chan = NULL; + of_node_put(np); + break; + } + + if (i == rsnd_mod_id_raw(mod) && (!chan)) + chan = of_dma_request_slave_channel(np, x); + i++; + } + + /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ + of_node_put(of_node); + + return chan; +} + +static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, + struct rsnd_dma *dma, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct dma_chan *chan; + + /* try to get DMAEngine channel */ + chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); + if (IS_ERR_OR_NULL(chan)) { + /* Let's follow when -EPROBE_DEFER case */ + if (PTR_ERR(chan) == -EPROBE_DEFER) + return PTR_ERR(chan); + + /* + * DMA failed. try to PIO mode + * see + * rsnd_ssi_fallback() + * rsnd_rdai_continuance_probe() + */ + return -EAGAIN; + } + + /* + * use it for IPMMU if needed + * see + * rsnd_preallocate_pages() + */ + io->dmac_dev = chan->device->dev; + + dma_release_channel(chan); + + dmac->dmaen_num++; + + return 0; +} + +static int rsnd_dmaen_pointer(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + snd_pcm_uframes_t *pointer) +{ + *pointer = snd_dmaengine_pcm_pointer(io->substream); + + return 0; +} + +static struct rsnd_mod_ops rsnd_dmaen_ops = { + .name = "audmac", + .prepare = rsnd_dmaen_prepare, + .cleanup = rsnd_dmaen_cleanup, + .start = rsnd_dmaen_start, + .stop = rsnd_dmaen_stop, + .pointer = rsnd_dmaen_pointer, + .get_status = rsnd_mod_get_status, +}; + +/* + * Audio DMAC peri peri + */ +static const u8 gen2_id_table_ssiu[] = { + /* SSI00 ~ SSI07 */ + 0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c, + /* SSI10 ~ SSI17 */ + 0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40, + /* SSI20 ~ SSI27 */ + 0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44, + /* SSI30 ~ SSI37 */ + 0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + /* SSI40 ~ SSI47 */ + 0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, + /* SSI5 */ + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI6 */ + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI7 */ + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI8 */ + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* SSI90 ~ SSI97 */ + 0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56, +}; +static const u8 gen2_id_table_scu[] = { + 0x2d, /* SCU_SRCI0 */ + 0x2e, /* SCU_SRCI1 */ + 0x2f, /* SCU_SRCI2 */ + 0x30, /* SCU_SRCI3 */ + 0x31, /* SCU_SRCI4 */ + 0x32, /* SCU_SRCI5 */ + 0x33, /* SCU_SRCI6 */ + 0x34, /* SCU_SRCI7 */ + 0x35, /* SCU_SRCI8 */ + 0x36, /* SCU_SRCI9 */ +}; +static const u8 gen2_id_table_cmd[] = { + 0x37, /* SCU_CMD0 */ + 0x38, /* SCU_CMD1 */ +}; + +static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + const u8 *entry = NULL; + int id = 255; + int size = 0; + + if ((mod == ssi) || + (mod == ssiu)) { + int busif = rsnd_mod_id_sub(ssiu); + + entry = gen2_id_table_ssiu; + size = ARRAY_SIZE(gen2_id_table_ssiu); + id = (rsnd_mod_id(mod) * 8) + busif; + } else if (mod == src) { + entry = gen2_id_table_scu; + size = ARRAY_SIZE(gen2_id_table_scu); + id = rsnd_mod_id(mod); + } else if (mod == dvc) { + entry = gen2_id_table_cmd; + size = ARRAY_SIZE(gen2_id_table_cmd); + id = rsnd_mod_id(mod); + } + + if ((!entry) || (size <= id)) { + struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); + + dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod)); + + /* use non-prohibited SRS number as error */ + return 0x00; /* SSI00 */ + } + + return entry[id]; +} + +static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, + struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to) +{ + return (rsnd_dmapp_get_id(io, mod_from) << 24) + + (rsnd_dmapp_get_id(io, mod_to) << 16); +} + +#define rsnd_dmapp_addr(dmac, dma, reg) \ + (dmac->ppbase + 0x20 + reg + \ + (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) +static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) +{ + struct rsnd_mod *mod = rsnd_mod_get(dma); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); + + iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); +} + +static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) +{ + struct rsnd_mod *mod = rsnd_mod_get(dma); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + + return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); +} + +static void rsnd_dmapp_bset(struct rsnd_dma *dma, u32 data, u32 mask, u32 reg) +{ + struct rsnd_mod *mod = rsnd_mod_get(dma); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + void __iomem *addr = rsnd_dmapp_addr(dmac, dma, reg); + u32 val = ioread32(addr); + + val &= ~mask; + val |= (data & mask); + + iowrite32(val, addr); +} + +static int rsnd_dmapp_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + int i; + + rsnd_dmapp_bset(dma, 0, PDMACHCR_DE, PDMACHCR); + + for (i = 0; i < 1024; i++) { + if (0 == (rsnd_dmapp_read(dma, PDMACHCR) & PDMACHCR_DE)) + return 0; + udelay(1); + } + + return -EIO; +} + +static int rsnd_dmapp_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); + + rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); + rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); + rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); + + return 0; +} + +static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, + struct rsnd_dma *dma, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) +{ + struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct device *dev = rsnd_priv_to_dev(priv); + + dmapp->dmapp_id = dmac->dmapp_num; + dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE; + + dmac->dmapp_num++; + + dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", + dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_dmapp_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); + + rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase, + 0x20 + 0x10 * dmapp->dmapp_id, 0x10); +} +#define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info +#else +#define DEBUG_INFO +#endif + +static struct rsnd_mod_ops rsnd_dmapp_ops = { + .name = "audmac-pp", + .start = rsnd_dmapp_start, + .stop = rsnd_dmapp_stop, + .quit = rsnd_dmapp_stop, + .get_status = rsnd_mod_get_status, + DEBUG_INFO +}; + +/* + * Common DMAC Interface + */ + +/* + * DMA read/write register offset + * + * RSND_xxx_I_N for Audio DMAC input + * RSND_xxx_O_N for Audio DMAC output + * RSND_xxx_I_P for Audio DMAC peri peri input + * RSND_xxx_O_P for Audio DMAC peri peri output + * + * ex) R-Car H2 case + * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out + * SSI : 0xec541000 / 0xec241008 / 0xec24100c + * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 + * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 + * CMD : 0xec500000 / / 0xec008000 0xec308000 + */ +#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) +#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) + +#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4))) +#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j) + +#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4))) +#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j) + +#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) +#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) + +#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) +#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) + +#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) +#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) + +static dma_addr_t +rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + int is_play, int is_from) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI); + phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU); + int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) || + !!(rsnd_io_to_mod_ssiu(io) == mod); + int use_src = !!rsnd_io_to_mod_src(io); + int use_cmd = !!rsnd_io_to_mod_dvc(io) || + !!rsnd_io_to_mod_mix(io) || + !!rsnd_io_to_mod_ctu(io); + int id = rsnd_mod_id(mod); + int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io)); + struct dma_addr { + dma_addr_t out_addr; + dma_addr_t in_addr; + } dma_addrs[3][2][3] = { + /* SRC */ + /* Capture */ + {{{ 0, 0 }, + { RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) }, + { RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } }, + /* Playback */ + {{ 0, 0, }, + { RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) }, + { RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } } + }, + /* SSI */ + /* Capture */ + {{{ RDMA_SSI_O_N(ssi, id), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, + /* Playback */ + {{ 0, RDMA_SSI_I_N(ssi, id) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) } } + }, + /* SSIU */ + /* Capture */ + {{{ RDMA_SSIU_O_N(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 }, + { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, + /* Playback */ + {{ 0, RDMA_SSIU_I_N(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) }, + { 0, RDMA_SSIU_I_P(ssi, id, busif) } } }, + }; + + /* + * FIXME + * + * We can't support SSI9-4/5/6/7, because its address is + * out of calculation rule + */ + if ((id == 9) && (busif >= 4)) + dev_err(dev, "This driver doesn't support SSI%d-%d, so far", + id, busif); + + /* it shouldn't happen */ + if (use_cmd && !use_src) + dev_err(dev, "DVC is selected without SRC\n"); + + /* use SSIU or SSI ? */ + if (is_ssi && rsnd_ssi_use_busif(io)) + is_ssi++; + + return (is_from) ? + dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr : + dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr; +} + +/* + * Gen4 DMA read/write register offset + * + * ex) R-Car V4H case + * mod / SYS-DMAC in / SYS-DMAC out + * SSI_SDMC: 0xec400000 / 0xec400000 / 0xec400000 + */ +#define RDMA_SSI_SDMC(addr, i) (addr + (0x8000 * i)) +static dma_addr_t +rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod, + int is_play, int is_from) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_BASE_SDMC); + int id = rsnd_mod_id(mod); + int busif = rsnd_mod_id_sub(mod); + + /* + * SSI0 only is supported + */ + if (id != 0) { + struct device *dev = rsnd_priv_to_dev(priv); + + dev_err(dev, "This driver doesn't support non SSI0"); + return -EINVAL; + } + + return RDMA_SSI_SDMC(addr, busif); +} + +static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, + int is_play, int is_from) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + + if (!mod) + return 0; + + /* + * gen1 uses default DMA addr + */ + if (rsnd_is_gen1(priv)) + return 0; + else if (rsnd_is_gen4(priv)) + return rsnd_gen4_dma_addr(io, mod, is_play, is_from); + else + return rsnd_gen2_dma_addr(io, mod, is_play, is_from); +} + +#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ +static void rsnd_dma_of_path(struct rsnd_mod *this, + struct rsnd_dai_stream *io, + int is_play, + struct rsnd_mod **mod_from, + struct rsnd_mod **mod_to) +{ + struct rsnd_mod *ssi; + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); + struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + struct rsnd_mod *mod[MOD_MAX]; + struct rsnd_mod *mod_start, *mod_end; + struct rsnd_priv *priv = rsnd_mod_to_priv(this); + struct device *dev = rsnd_priv_to_dev(priv); + int nr, i, idx; + + /* + * It should use "rcar_sound,ssiu" on DT. + * But, we need to keep compatibility for old version. + * + * If it has "rcar_sound.ssiu", it will be used. + * If not, "rcar_sound.ssi" will be used. + * see + * rsnd_ssiu_dma_req() + * rsnd_ssi_dma_req() + */ + if (rsnd_ssiu_of_node(priv)) { + struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); + + /* use SSIU */ + ssi = ssiu; + if (this == rsnd_io_to_mod_ssi(io)) + this = ssiu; + } else { + /* keep compatible, use SSI */ + ssi = rsnd_io_to_mod_ssi(io); + } + + if (!ssi) + return; + + nr = 0; + for (i = 0; i < MOD_MAX; i++) { + mod[i] = NULL; + nr += !!rsnd_io_to_mod(io, i); + } + + /* + * [S] -*-> [E] + * [S] -*-> SRC -o-> [E] + * [S] -*-> SRC -> DVC -o-> [E] + * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E] + * + * playback [S] = mem + * [E] = SSI + * + * capture [S] = SSI + * [E] = mem + * + * -*-> Audio DMAC + * -o-> Audio DMAC peri peri + */ + mod_start = (is_play) ? NULL : ssi; + mod_end = (is_play) ? ssi : NULL; + + idx = 0; + mod[idx++] = mod_start; + for (i = 1; i < nr; i++) { + if (src) { + mod[idx++] = src; + src = NULL; + } else if (ctu) { + mod[idx++] = ctu; + ctu = NULL; + } else if (mix) { + mod[idx++] = mix; + mix = NULL; + } else if (dvc) { + mod[idx++] = dvc; + dvc = NULL; + } + } + mod[idx] = mod_end; + + /* + * | SSI | SRC | + * -------------+-----+-----+ + * is_play | o | * | + * !is_play | * | o | + */ + if ((this == ssi) == (is_play)) { + *mod_from = mod[idx - 1]; + *mod_to = mod[idx]; + } else { + *mod_from = mod[0]; + *mod_to = mod[1]; + } + + dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this)); + for (i = 0; i <= idx; i++) { + dev_dbg(dev, " %s%s\n", + rsnd_mod_name(mod[i] ? mod[i] : &mem), + (mod[i] == *mod_from) ? " from" : + (mod[i] == *mod_to) ? " to" : ""); + } +} + +static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod, + struct rsnd_mod **dma_mod) +{ + struct rsnd_mod *mod_from = NULL; + struct rsnd_mod *mod_to = NULL; + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dma *dma; + struct rsnd_mod_ops *ops; + enum rsnd_mod_type type; + int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); + int is_play = rsnd_io_is_play(io); + int ret, dma_id; + + /* + * DMA failed. try to PIO mode + * see + * rsnd_ssi_fallback() + * rsnd_rdai_continuance_probe() + */ + if (!dmac) + return -EAGAIN; + + rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); + + /* for Gen2 or later */ + if (mod_from && mod_to) { + ops = &rsnd_dmapp_ops; + attach = rsnd_dmapp_attach; + dma_id = dmac->dmapp_num; + type = RSND_MOD_AUDMAPP; + } else { + ops = &rsnd_dmaen_ops; + attach = rsnd_dmaen_attach; + dma_id = dmac->dmaen_num; + type = RSND_MOD_AUDMA; + } + + /* for Gen1, overwrite */ + if (rsnd_is_gen1(priv)) { + ops = &rsnd_dmaen_ops; + attach = rsnd_dmaen_attach; + dma_id = dmac->dmaen_num; + type = RSND_MOD_AUDMA; + } + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + + *dma_mod = rsnd_mod_get(dma); + + ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, + type, dma_id); + if (ret < 0) + return ret; + + dev_dbg(dev, "%s %s -> %s\n", + rsnd_mod_name(*dma_mod), + rsnd_mod_name(mod_from ? mod_from : &mem), + rsnd_mod_name(mod_to ? mod_to : &mem)); + + ret = attach(io, dma, mod_from, mod_to); + if (ret < 0) + return ret; + + dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); + dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); + dma->mod_from = mod_from; + dma->mod_to = mod_to; + + return 0; +} + +int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, + struct rsnd_mod **dma_mod) +{ + if (!(*dma_mod)) { + int ret = rsnd_dma_alloc(io, mod, dma_mod); + + if (ret < 0) + return ret; + } + + return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type); +} + +int rsnd_dma_probe(struct rsnd_priv *priv) +{ + struct platform_device *pdev = rsnd_priv_to_pdev(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dma_ctrl *dmac; + struct resource *res; + + /* + * for Gen1 + */ + if (rsnd_is_gen1(priv)) + return 0; + + /* + * for Gen2 or later + */ + dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL); + if (!dmac) { + dev_err(dev, "dma allocate failed\n"); + return 0; /* it will be PIO mode */ + } + + /* for Gen4 doesn't have DMA-pp */ + if (rsnd_is_gen4(priv)) + goto audmapp_end; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp"); + if (!res) { + dev_err(dev, "lack of audmapp in DT\n"); + return 0; /* it will be PIO mode */ + } + + dmac->dmapp_num = 0; + dmac->ppres = res->start; + dmac->ppbase = devm_ioremap_resource(dev, res); + if (IS_ERR(dmac->ppbase)) + return PTR_ERR(dmac->ppbase); +audmapp_end: + priv->dma = dmac; + + /* dummy mem mod for debug */ + return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0); +} diff --git a/sound/soc/renesas/rcar/dvc.c b/sound/soc/renesas/rcar/dvc.c new file mode 100644 index 00000000000000..da91dd301aabeb --- /dev/null +++ b/sound/soc/renesas/rcar/dvc.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car DVC support +// +// Copyright (C) 2014 Renesas Solutions Corp. +// Kuninori Morimoto + +/* + * Playback Volume + * amixer set "DVC Out" 100% + * + * Capture Volume + * amixer set "DVC In" 100% + * + * Playback Mute + * amixer set "DVC Out Mute" on + * + * Capture Mute + * amixer set "DVC In Mute" on + * + * Volume Ramp + * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" + * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" + * amixer set "DVC Out Ramp" on + * aplay xxx.wav & + * amixer set "DVC Out" 80% // Volume Down + * amixer set "DVC Out" 100% // Volume Up + */ + +#include "rsnd.h" + +#define RSND_DVC_NAME_SIZE 16 + +#define DVC_NAME "dvc" + +struct rsnd_dvc { + struct rsnd_mod mod; + struct rsnd_kctrl_cfg_m volume; + struct rsnd_kctrl_cfg_m mute; + struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ + struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ + struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ +}; + +#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) +#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) + +#define rsnd_mod_to_dvc(_mod) \ + container_of((_mod), struct rsnd_dvc, mod) + +#define for_each_rsnd_dvc(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_dvc_nr(priv)) && \ + ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ + i++) + +static void rsnd_dvc_activation(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, DVC_SWRSR, 0); + rsnd_mod_write(mod, DVC_SWRSR, 1); +} + +static void rsnd_dvc_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, DVC_DVUIR, 1); + rsnd_mod_write(mod, DVC_SWRSR, 0); +} + +#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \ + rsnd_kctrl_vals(dvc->rdown)) +#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13)) + +static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 val[RSND_MAX_CHANNELS]; + int i; + + /* Enable Ramp */ + if (rsnd_kctrl_vals(dvc->ren)) + for (i = 0; i < RSND_MAX_CHANNELS; i++) + val[i] = rsnd_kctrl_max(dvc->volume); + else + for (i = 0; i < RSND_MAX_CHANNELS; i++) + val[i] = rsnd_kctrl_valm(dvc->volume, i); + + /* Enable Digital Volume */ + for (i = 0; i < RSND_MAX_CHANNELS; i++) + rsnd_mod_write(mod, DVC_VOLxR(i), val[i]); +} + +static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 adinr = 0; + u32 dvucr = 0; + u32 vrctr = 0; + u32 vrpdr = 0; + u32 vrdbr = 0; + + adinr = rsnd_get_adinr_bit(mod, io) | + rsnd_runtime_channel_after_ctu(io); + + /* Enable Digital Volume, Zero Cross Mute Mode */ + dvucr |= 0x101; + + /* Enable Ramp */ + if (rsnd_kctrl_vals(dvc->ren)) { + dvucr |= 0x10; + + /* + * FIXME !! + * use scale-downed Digital Volume + * as Volume Ramp + * 7F FFFF -> 3FF + */ + vrctr = 0xff; + vrpdr = rsnd_dvc_get_vrpdr(dvc); + vrdbr = rsnd_dvc_get_vrdbr(dvc); + } + + /* Initialize operation */ + rsnd_mod_write(mod, DVC_DVUIR, 1); + + /* General Information */ + rsnd_mod_write(mod, DVC_ADINR, adinr); + rsnd_mod_write(mod, DVC_DVUCR, dvucr); + + /* Volume Ramp Parameter */ + rsnd_mod_write(mod, DVC_VRCTR, vrctr); + rsnd_mod_write(mod, DVC_VRPDR, vrpdr); + rsnd_mod_write(mod, DVC_VRDBR, vrdbr); + + /* Digital Volume Function Parameter */ + rsnd_dvc_volume_parameter(io, mod); + + /* cancel operation */ + rsnd_mod_write(mod, DVC_DVUIR, 0); +} + +static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 zcmcr = 0; + u32 vrpdr = 0; + u32 vrdbr = 0; + int i; + + for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++) + zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i; + + if (rsnd_kctrl_vals(dvc->ren)) { + vrpdr = rsnd_dvc_get_vrpdr(dvc); + vrdbr = rsnd_dvc_get_vrdbr(dvc); + } + + /* Disable DVC Register access */ + rsnd_mod_write(mod, DVC_DVUER, 0); + + /* Zero Cross Mute Function */ + rsnd_mod_write(mod, DVC_ZCMCR, zcmcr); + + /* Volume Ramp Function */ + rsnd_mod_write(mod, DVC_VRPDR, vrpdr); + rsnd_mod_write(mod, DVC_VRDBR, vrdbr); + /* add DVC_VRWTR here */ + + /* Digital Volume Function Parameter */ + rsnd_dvc_volume_parameter(io, mod); + + /* Enable DVC Register access */ + rsnd_mod_write(mod, DVC_DVUER, 1); +} + +static int rsnd_dvc_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod)); +} + +static int rsnd_dvc_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + int ret; + + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; + + rsnd_dvc_activation(mod); + + rsnd_dvc_volume_init(io, mod); + + rsnd_dvc_volume_update(io, mod); + + return 0; +} + +static int rsnd_dvc_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_dvc_halt(mod); + + rsnd_mod_power_off(mod); + + return 0; +} + +static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + int is_play = rsnd_io_is_play(io); + int channels = rsnd_rdai_channels_get(rdai); + int ret; + + /* Volume */ + ret = rsnd_kctrl_new_m(mod, io, rtd, + is_play ? + "DVC Out Playback Volume" : "DVC In Capture Volume", + rsnd_kctrl_accept_anytime, + rsnd_dvc_volume_update, + &dvc->volume, channels, + 0x00800000 - 1); + if (ret < 0) + return ret; + + /* Mute */ + ret = rsnd_kctrl_new_m(mod, io, rtd, + is_play ? + "DVC Out Mute Switch" : "DVC In Mute Switch", + rsnd_kctrl_accept_anytime, + rsnd_dvc_volume_update, + &dvc->mute, channels, + 1); + if (ret < 0) + return ret; + + /* Ramp */ + ret = rsnd_kctrl_new_s(mod, io, rtd, + is_play ? + "DVC Out Ramp Switch" : "DVC In Ramp Switch", + rsnd_kctrl_accept_anytime, + rsnd_dvc_volume_update, + &dvc->ren, 1); + if (ret < 0) + return ret; + + ret = rsnd_kctrl_new_e(mod, io, rtd, + is_play ? + "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", + rsnd_kctrl_accept_anytime, + rsnd_dvc_volume_update, + &dvc->rup, + volume_ramp_rate, + VOLUME_RAMP_MAX_DVC); + if (ret < 0) + return ret; + + ret = rsnd_kctrl_new_e(mod, io, rtd, + is_play ? + "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", + rsnd_kctrl_accept_anytime, + rsnd_dvc_volume_update, + &dvc->rdown, + volume_ramp_rate, + VOLUME_RAMP_MAX_DVC); + + if (ret < 0) + return ret; + + return 0; +} + +static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + + return rsnd_dma_request_channel(rsnd_dvc_of_node(priv), + DVC_NAME, mod, "tx"); +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_dvc_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, + 0xe00 + rsnd_mod_id(mod) * 0x100, 0x60); +} +#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info +#else +#define DEBUG_INFO +#endif + +static struct rsnd_mod_ops rsnd_dvc_ops = { + .name = DVC_NAME, + .dma_req = rsnd_dvc_dma_req, + .probe = rsnd_dvc_probe_, + .init = rsnd_dvc_init, + .quit = rsnd_dvc_quit, + .pcm_new = rsnd_dvc_pcm_new, + .get_status = rsnd_mod_get_status, + DEBUG_INFO +}; + +struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) + id = 0; + + return rsnd_mod_get(rsnd_dvc_get(priv, id)); +} + +int rsnd_dvc_probe(struct rsnd_priv *priv) +{ + struct device_node *node; + struct device_node *np; + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dvc *dvc; + struct clk *clk; + char name[RSND_DVC_NAME_SIZE]; + int i, nr, ret; + + node = rsnd_dvc_of_node(priv); + if (!node) + return 0; /* not used is not error */ + + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_dvc_probe_done; + } + + dvc = devm_kcalloc(dev, nr, sizeof(*dvc), GFP_KERNEL); + if (!dvc) { + ret = -ENOMEM; + goto rsnd_dvc_probe_done; + } + + priv->dvc_nr = nr; + priv->dvc = dvc; + + i = 0; + ret = 0; + for_each_child_of_node(node, np) { + dvc = rsnd_dvc_get(priv, i); + + snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", + DVC_NAME, i); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + of_node_put(np); + goto rsnd_dvc_probe_done; + } + + ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, + clk, RSND_MOD_DVC, i); + if (ret) { + of_node_put(np); + goto rsnd_dvc_probe_done; + } + + i++; + } + +rsnd_dvc_probe_done: + of_node_put(node); + + return ret; +} + +void rsnd_dvc_remove(struct rsnd_priv *priv) +{ + struct rsnd_dvc *dvc; + int i; + + for_each_rsnd_dvc(dvc, priv, i) { + rsnd_mod_quit(rsnd_mod_get(dvc)); + } +} diff --git a/sound/soc/renesas/rcar/gen.c b/sound/soc/renesas/rcar/gen.c new file mode 100644 index 00000000000000..d1f20cde66be1f --- /dev/null +++ b/sound/soc/renesas/rcar/gen.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car Gen1 SRU/SSI support +// +// Copyright (C) 2013 Renesas Solutions Corp. +// Kuninori Morimoto + +/* + * #define DEBUG + * + * you can also add below in + * ${LINUX}/drivers/base/regmap/regmap.c + * for regmap debug + * + * #define LOG_DEVICE "xxxx.rcar_sound" + */ + +#include "rsnd.h" + +struct rsnd_gen { + struct rsnd_gen_ops *ops; + + /* RSND_BASE_MAX base */ + void __iomem *base[RSND_BASE_MAX]; + phys_addr_t res[RSND_BASE_MAX]; + struct regmap *regmap[RSND_BASE_MAX]; + + /* RSND_REG_MAX base */ + struct regmap_field *regs[REG_MAX]; + const char *reg_name[REG_MAX]; +}; + +#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) +#define rsnd_reg_name(gen, id) ((gen)->reg_name[id]) + +struct rsnd_regmap_field_conf { + int idx; + unsigned int reg_offset; + unsigned int id_offset; + const char *reg_name; +}; + +#define RSND_REG_SET(id, offset, _id_offset, n) \ +{ \ + .idx = id, \ + .reg_offset = offset, \ + .id_offset = _id_offset, \ + .reg_name = n, \ +} +/* single address mapping */ +#define RSND_GEN_S_REG(id, offset) \ + RSND_REG_SET(id, offset, 0, #id) + +/* multi address mapping */ +#define RSND_GEN_M_REG(id, offset, _id_offset) \ + RSND_REG_SET(id, offset, _id_offset, #id) + +/* + * basic function + */ +static int rsnd_is_accessible_reg(struct rsnd_priv *priv, + struct rsnd_gen *gen, enum rsnd_reg reg) +{ + if (!gen->regs[reg]) { + struct device *dev = rsnd_priv_to_dev(priv); + + dev_err(dev, "unsupported register access %x\n", reg); + return 0; + } + + return 1; +} + +static int rsnd_mod_id_cmd(struct rsnd_mod *mod) +{ + if (mod->ops->id_cmd) + return mod->ops->id_cmd(mod); + + return rsnd_mod_id(mod); +} + +u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + u32 val; + + if (!rsnd_is_accessible_reg(priv, gen, reg)) + return 0; + + regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val); + + dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), + rsnd_reg_name(gen, reg), reg, val); + + return val; +} + +void rsnd_mod_write(struct rsnd_mod *mod, + enum rsnd_reg reg, u32 data) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + if (!rsnd_is_accessible_reg(priv, gen, reg)) + return; + + regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data); + + dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), + rsnd_reg_name(gen, reg), reg, data); +} + +void rsnd_mod_bset(struct rsnd_mod *mod, + enum rsnd_reg reg, u32 mask, u32 data) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + if (!rsnd_is_accessible_reg(priv, gen, reg)) + return; + + regmap_fields_force_update_bits(gen->regs[reg], + rsnd_mod_id_cmd(mod), mask, data); + + dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n", + rsnd_mod_name(mod), + rsnd_reg_name(gen, reg), reg, data, mask); + +} + +phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) +{ + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + return gen->res[reg_id]; +} + +#ifdef CONFIG_DEBUG_FS +void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id) +{ + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + return gen->base[reg_id]; +} +#endif + +#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \ + _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf)) +static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, + int id_size, + int reg_id, + const char *name, + const struct rsnd_regmap_field_conf *conf, + int conf_size) +{ + struct platform_device *pdev = rsnd_priv_to_pdev(priv); + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct resource *res; + struct regmap_config regc; + struct regmap_field *regs; + struct regmap *regmap; + struct reg_field regf; + void __iomem *base; + int i; + + memset(®c, 0, sizeof(regc)); + regc.reg_bits = 32; + regc.val_bits = 32; + regc.reg_stride = 4; + regc.name = name; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + if (!res) + return -ENODEV; + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(dev, base, ®c); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* RSND_BASE_MAX base */ + gen->base[reg_id] = base; + gen->regmap[reg_id] = regmap; + gen->res[reg_id] = res->start; + + for (i = 0; i < conf_size; i++) { + + regf.reg = conf[i].reg_offset; + regf.id_offset = conf[i].id_offset; + regf.lsb = 0; + regf.msb = 31; + regf.id_size = id_size; + + regs = devm_regmap_field_alloc(dev, regmap, regf); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + /* RSND_REG_MAX base */ + gen->regs[conf[i].idx] = regs; + gen->reg_name[conf[i].idx] = conf[i].reg_name; + } + + return 0; +} + +/* + * (A) : Gen4 is 0xa0c, but it is not used. + * see + * rsnd_ssiu_init() + */ +static const struct rsnd_regmap_field_conf conf_common_ssiu[] = { + RSND_GEN_S_REG(SSI_MODE0, 0x800), + RSND_GEN_S_REG(SSI_MODE1, 0x804), + RSND_GEN_S_REG(SSI_MODE2, 0x808), // (A) + RSND_GEN_S_REG(SSI_CONTROL, 0x810), + RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840), + RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844), + RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848), + RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c), + RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880), + RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884), + RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), + RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c), + RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850), + RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854), + RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858), + RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c), + RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890), + RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894), + RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898), + RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c), + RSND_GEN_S_REG(HDMI0_SEL, 0x9e0), + RSND_GEN_S_REG(HDMI1_SEL, 0x9e4), + RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80), + RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80), + RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), + RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), + RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), + RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), + RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), + RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), + RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), + RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), + RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), + RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), + RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), + RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x48c), + RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484), + RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488), + RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0), + RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4), + RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8), + RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0), + RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4), + RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8), + RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0), + RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4), + RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8), + RSND_GEN_S_REG(SSI9_BUSIF4_MODE, 0xd80), + RSND_GEN_S_REG(SSI9_BUSIF4_ADINR, 0xd84), + RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN, 0xd88), + RSND_GEN_S_REG(SSI9_BUSIF5_MODE, 0xda0), + RSND_GEN_S_REG(SSI9_BUSIF5_ADINR, 0xda4), + RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN, 0xda8), + RSND_GEN_S_REG(SSI9_BUSIF6_MODE, 0xdc0), + RSND_GEN_S_REG(SSI9_BUSIF6_ADINR, 0xdc4), + RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN, 0xdc8), + RSND_GEN_S_REG(SSI9_BUSIF7_MODE, 0xde0), + RSND_GEN_S_REG(SSI9_BUSIF7_ADINR, 0xde4), + RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN, 0xde8), +}; + +static const struct rsnd_regmap_field_conf conf_common_scu[] = { + RSND_GEN_M_REG(SRC_I_BUSIF_MODE, 0x0, 0x20), + RSND_GEN_M_REG(SRC_O_BUSIF_MODE, 0x4, 0x20), + RSND_GEN_M_REG(SRC_BUSIF_DALIGN, 0x8, 0x20), + RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), + RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), + RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), + RSND_GEN_M_REG(CMD_BUSIF_MODE, 0x184, 0x20), + RSND_GEN_M_REG(CMD_BUSIF_DALIGN, 0x188, 0x20), + RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), + RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), + RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), + RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc), + RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0), + RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4), + RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), + RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), + RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), + RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40), + RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), + RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), + RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40), + RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), + RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100), + RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), + RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), + RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100), + RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100), + RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100), + RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100), + RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100), + RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100), + RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100), + RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100), + RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100), + RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100), + RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100), + RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100), + RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100), + RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100), + RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100), + RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100), + RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100), + RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100), + RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100), + RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100), + RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100), + RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100), + RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100), + RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100), + RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100), + RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100), + RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100), + RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100), + RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100), + RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100), + RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100), + RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100), + RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100), + RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100), + RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40), + RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40), + RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40), + RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40), + RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40), + RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40), + RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40), + RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40), + RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40), + RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40), + RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100), + RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100), + RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), + RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), + RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), + RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100), + RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100), + RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), + RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), + RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), + RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100), + RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100), + RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100), + RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100), + RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100), + RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100), + RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), +}; + +static const struct rsnd_regmap_field_conf conf_common_adg[] = { + RSND_GEN_S_REG(BRRA, 0x00), + RSND_GEN_S_REG(BRRB, 0x04), + RSND_GEN_S_REG(BRGCKR, 0x08), + RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), + RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), + RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14), + RSND_GEN_S_REG(DIV_EN, 0x30), + RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34), + RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38), + RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c), + RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40), + RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44), + RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48), + RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c), + RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50), + RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54), + RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), + RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), +}; + +static const struct rsnd_regmap_field_conf conf_common_ssi[] = { + RSND_GEN_M_REG(SSICR, 0x00, 0x40), + RSND_GEN_M_REG(SSISR, 0x04, 0x40), + RSND_GEN_M_REG(SSITDR, 0x08, 0x40), + RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), + RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), +}; + +/* + * Gen4 + */ +static int rsnd_gen4_probe(struct rsnd_priv *priv) +{ + struct rsnd_regmap_field_conf conf_null[] = { }; + + /* + * ssiu: SSIU0 + * ssi : SSI0 + */ + int ret_ssiu = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSIU, "ssiu", conf_common_ssiu); + int ret_ssi = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSI, "ssi", conf_common_ssi); + int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg); + int ret_sdmc = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SDMC, "sdmc", conf_null); + + return ret_adg | ret_ssiu | ret_ssi | ret_sdmc; +} + +/* + * Gen2 + */ +static int rsnd_gen2_probe(struct rsnd_priv *priv) +{ + /* + * ssi : SSI0 - SSI9 + * ssiu: SSIU0 - SSIU9 + * scu : SRC0 - SRC9 etc + */ + int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSI, "ssi", conf_common_ssi); + int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSIU, "ssiu", conf_common_ssiu); + int ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SCU, "scu", conf_common_scu); + int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg); + + return ret_ssi | ret_ssiu | ret_scu | ret_adg; +} + +/* + * Gen1 + */ + +static int rsnd_gen1_probe(struct rsnd_priv *priv) +{ + /* + * ssi : SSI0 - SSI8 + */ + int ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_BASE_SSI, "ssi", conf_common_ssi); + int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg); + + return ret_adg | ret_ssi; +} + +/* + * Gen + */ +int rsnd_gen_probe(struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_gen *gen; + int ret; + + gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); + if (!gen) + return -ENOMEM; + + priv->gen = gen; + + ret = -ENODEV; + if (rsnd_is_gen1(priv)) + ret = rsnd_gen1_probe(priv); + else if (rsnd_is_gen2(priv) || + rsnd_is_gen3(priv)) + ret = rsnd_gen2_probe(priv); + else if (rsnd_is_gen4(priv)) + ret = rsnd_gen4_probe(priv); + + if (ret < 0) + dev_err(dev, "unknown generation R-Car sound device\n"); + + return ret; +} diff --git a/sound/soc/renesas/rcar/mix.c b/sound/soc/renesas/rcar/mix.c new file mode 100644 index 00000000000000..024d91cc874840 --- /dev/null +++ b/sound/soc/renesas/rcar/mix.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mix.c +// +// Copyright (c) 2015 Kuninori Morimoto + +/* + * CTUn MIXn + * +------+ +------+ + * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| -> + * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| -> + * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| -> + * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| -> + * +------+ +------+ + * + * ex) + * DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>; + * DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; + * + * MIX Volume + * amixer set "MIX",0 100% // DAI0 Volume + * amixer set "MIX",1 100% // DAI1 Volume + * + * Volume Ramp + * amixer set "MIX Ramp Up Rate" "0.125 dB/1 step" + * amixer set "MIX Ramp Down Rate" "4 dB/1 step" + * amixer set "MIX Ramp" on + * aplay xxx.wav & + * amixer set "MIX",0 80% // DAI0 Volume Down + * amixer set "MIX",1 100% // DAI1 Volume Up + */ + +#include "rsnd.h" + +#define MIX_NAME_SIZE 16 +#define MIX_NAME "mix" + +struct rsnd_mix { + struct rsnd_mod mod; + struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */ + struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */ + struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */ + struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */ + struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ + struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ + struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */ + u32 flags; +}; + +#define ONCE_KCTRL_INITIALIZED (1 << 0) +#define HAS_VOLA (1 << 1) +#define HAS_VOLB (1 << 2) +#define HAS_VOLC (1 << 3) +#define HAS_VOLD (1 << 4) + +#define VOL_MAX 0x3ff + +#define rsnd_mod_to_mix(_mod) \ + container_of((_mod), struct rsnd_mix, mod) + +#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) +#define rsnd_mix_nr(priv) ((priv)->mix_nr) +#define for_each_rsnd_mix(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_mix_nr(priv)) && \ + ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ + i++) + +static void rsnd_mix_activation(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, MIX_SWRSR, 0); + rsnd_mod_write(mod, MIX_SWRSR, 1); +} + +static void rsnd_mix_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, MIX_MIXIR, 1); + rsnd_mod_write(mod, MIX_SWRSR, 0); +} + +#define rsnd_mix_get_vol(mix, X) \ + rsnd_flags_has(mix, HAS_VOL##X) ? \ + (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0 +static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mix *mix = rsnd_mod_to_mix(mod); + u32 volA = rsnd_mix_get_vol(mix, A); + u32 volB = rsnd_mix_get_vol(mix, B); + u32 volC = rsnd_mix_get_vol(mix, C); + u32 volD = rsnd_mix_get_vol(mix, D); + + dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n", + volA, volB, volC, volD); + + rsnd_mod_write(mod, MIX_MDBAR, volA); + rsnd_mod_write(mod, MIX_MDBBR, volB); + rsnd_mod_write(mod, MIX_MDBCR, volC); + rsnd_mod_write(mod, MIX_MDBDR, volD); +} + +static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_mix *mix = rsnd_mod_to_mix(mod); + + rsnd_mod_write(mod, MIX_MIXIR, 1); + + /* General Information */ + rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io)); + + /* volume step */ + rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren)); + rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 | + rsnd_kctrl_vals(mix->rdw)); + + /* common volume parameter */ + rsnd_mix_volume_parameter(io, mod); + + rsnd_mod_write(mod, MIX_MIXIR, 0); +} + +static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + /* Disable MIX dB setting */ + rsnd_mod_write(mod, MIX_MDBER, 0); + + /* common volume parameter */ + rsnd_mix_volume_parameter(io, mod); + + /* Enable MIX dB setting */ + rsnd_mod_write(mod, MIX_MDBER, 1); +} + +static int rsnd_mix_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod)); +} + +static int rsnd_mix_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + int ret; + + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; + + rsnd_mix_activation(mod); + + rsnd_mix_volume_init(io, mod); + + rsnd_mix_volume_update(io, mod); + + return 0; +} + +static int rsnd_mix_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mix_halt(mod); + + rsnd_mod_power_off(mod); + + return 0; +} + +static int rsnd_mix_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mix *mix = rsnd_mod_to_mix(mod); + struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); + struct rsnd_kctrl_cfg_s *volume; + int ret; + + switch (rsnd_mod_id(src_mod)) { + case 3: + case 6: /* MDBAR */ + volume = &mix->volumeA; + rsnd_flags_set(mix, HAS_VOLA); + break; + case 4: + case 9: /* MDBBR */ + volume = &mix->volumeB; + rsnd_flags_set(mix, HAS_VOLB); + break; + case 0: + case 1: /* MDBCR */ + volume = &mix->volumeC; + rsnd_flags_set(mix, HAS_VOLC); + break; + case 2: + case 5: /* MDBDR */ + volume = &mix->volumeD; + rsnd_flags_set(mix, HAS_VOLD); + break; + default: + dev_err(dev, "unknown SRC is connected\n"); + return -EINVAL; + } + + /* Volume */ + ret = rsnd_kctrl_new_s(mod, io, rtd, + "MIX Playback Volume", + rsnd_kctrl_accept_anytime, + rsnd_mix_volume_update, + volume, VOL_MAX); + if (ret < 0) + return ret; + rsnd_kctrl_vals(*volume) = VOL_MAX; + + if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED)) + return ret; + + /* Ramp */ + ret = rsnd_kctrl_new_s(mod, io, rtd, + "MIX Ramp Switch", + rsnd_kctrl_accept_anytime, + rsnd_mix_volume_update, + &mix->ren, 1); + if (ret < 0) + return ret; + + ret = rsnd_kctrl_new_e(mod, io, rtd, + "MIX Ramp Up Rate", + rsnd_kctrl_accept_anytime, + rsnd_mix_volume_update, + &mix->rup, + volume_ramp_rate, + VOLUME_RAMP_MAX_MIX); + if (ret < 0) + return ret; + + ret = rsnd_kctrl_new_e(mod, io, rtd, + "MIX Ramp Down Rate", + rsnd_kctrl_accept_anytime, + rsnd_mix_volume_update, + &mix->rdw, + volume_ramp_rate, + VOLUME_RAMP_MAX_MIX); + + rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED); + + return ret; +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_mix_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, + 0xd00 + rsnd_mod_id(mod) * 0x40, 0x30); +} +#define DEBUG_INFO .debug_info = rsnd_mix_debug_info +#else +#define DEBUG_INFO +#endif + +static struct rsnd_mod_ops rsnd_mix_ops = { + .name = MIX_NAME, + .probe = rsnd_mix_probe_, + .init = rsnd_mix_init, + .quit = rsnd_mix_quit, + .pcm_new = rsnd_mix_pcm_new, + .get_status = rsnd_mod_get_status, + DEBUG_INFO +}; + +struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) + id = 0; + + return rsnd_mod_get(rsnd_mix_get(priv, id)); +} + +int rsnd_mix_probe(struct rsnd_priv *priv) +{ + struct device_node *node; + struct device_node *np; + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mix *mix; + struct clk *clk; + char name[MIX_NAME_SIZE]; + int i, nr, ret; + + node = rsnd_mix_of_node(priv); + if (!node) + return 0; /* not used is not error */ + + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_mix_probe_done; + } + + mix = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL); + if (!mix) { + ret = -ENOMEM; + goto rsnd_mix_probe_done; + } + + priv->mix_nr = nr; + priv->mix = mix; + + i = 0; + ret = 0; + for_each_child_of_node(node, np) { + mix = rsnd_mix_get(priv, i); + + snprintf(name, MIX_NAME_SIZE, "%s.%d", + MIX_NAME, i); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + of_node_put(np); + goto rsnd_mix_probe_done; + } + + ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, + clk, RSND_MOD_MIX, i); + if (ret) { + of_node_put(np); + goto rsnd_mix_probe_done; + } + + i++; + } + +rsnd_mix_probe_done: + of_node_put(node); + + return ret; +} + +void rsnd_mix_remove(struct rsnd_priv *priv) +{ + struct rsnd_mix *mix; + int i; + + for_each_rsnd_mix(mix, priv, i) { + rsnd_mod_quit(rsnd_mod_get(mix)); + } +} diff --git a/sound/soc/renesas/rcar/rsnd.h b/sound/soc/renesas/rcar/rsnd.h new file mode 100644 index 00000000000000..3c164d8e3b16bf --- /dev/null +++ b/sound/soc/renesas/rcar/rsnd.h @@ -0,0 +1,896 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car +// +// Copyright (C) 2013 Renesas Solutions Corp. +// Kuninori Morimoto + +#ifndef RSND_H +#define RSND_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RSND_BASE_ADG 0 +#define RSND_BASE_SSI 1 +#define RSND_BASE_SSIU 2 +#define RSND_BASE_SCU 3 // for Gen2/Gen3 +#define RSND_BASE_SDMC 3 // for Gen4 reuse +#define RSND_BASE_MAX 4 + +/* + * pseudo register + * + * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different. + * This driver uses pseudo register in order to hide it. + * see gen1/gen2 for detail + */ +enum rsnd_reg { + /* SCU (MIX/CTU/DVC) */ + SRC_I_BUSIF_MODE, + SRC_O_BUSIF_MODE, + SRC_ROUTE_MODE0, + SRC_SWRSR, + SRC_SRCIR, + SRC_ADINR, + SRC_IFSCR, + SRC_IFSVR, + SRC_SRCCR, + SRC_CTRL, + SRC_BSDSR, + SRC_BSISR, + SRC_INT_ENABLE0, + SRC_BUSIF_DALIGN, + SRCIN_TIMSEL0, + SRCIN_TIMSEL1, + SRCIN_TIMSEL2, + SRCIN_TIMSEL3, + SRCIN_TIMSEL4, + SRCOUT_TIMSEL0, + SRCOUT_TIMSEL1, + SRCOUT_TIMSEL2, + SRCOUT_TIMSEL3, + SRCOUT_TIMSEL4, + SCU_SYS_STATUS0, + SCU_SYS_STATUS1, + SCU_SYS_INT_EN0, + SCU_SYS_INT_EN1, + CMD_CTRL, + CMD_BUSIF_MODE, + CMD_BUSIF_DALIGN, + CMD_ROUTE_SLCT, + CMDOUT_TIMSEL, + CTU_SWRSR, + CTU_CTUIR, + CTU_ADINR, + CTU_CPMDR, + CTU_SCMDR, + CTU_SV00R, + CTU_SV01R, + CTU_SV02R, + CTU_SV03R, + CTU_SV04R, + CTU_SV05R, + CTU_SV06R, + CTU_SV07R, + CTU_SV10R, + CTU_SV11R, + CTU_SV12R, + CTU_SV13R, + CTU_SV14R, + CTU_SV15R, + CTU_SV16R, + CTU_SV17R, + CTU_SV20R, + CTU_SV21R, + CTU_SV22R, + CTU_SV23R, + CTU_SV24R, + CTU_SV25R, + CTU_SV26R, + CTU_SV27R, + CTU_SV30R, + CTU_SV31R, + CTU_SV32R, + CTU_SV33R, + CTU_SV34R, + CTU_SV35R, + CTU_SV36R, + CTU_SV37R, + MIX_SWRSR, + MIX_MIXIR, + MIX_ADINR, + MIX_MIXMR, + MIX_MVPDR, + MIX_MDBAR, + MIX_MDBBR, + MIX_MDBCR, + MIX_MDBDR, + MIX_MDBER, + DVC_SWRSR, + DVC_DVUIR, + DVC_ADINR, + DVC_DVUCR, + DVC_ZCMCR, + DVC_VOL0R, + DVC_VOL1R, + DVC_VOL2R, + DVC_VOL3R, + DVC_VOL4R, + DVC_VOL5R, + DVC_VOL6R, + DVC_VOL7R, + DVC_DVUER, + DVC_VRCTR, + DVC_VRPDR, + DVC_VRDBR, + + /* ADG */ + BRRA, + BRRB, + BRGCKR, + DIV_EN, + AUDIO_CLK_SEL0, + AUDIO_CLK_SEL1, + AUDIO_CLK_SEL2, + + /* SSIU */ + SSI_MODE, + SSI_MODE0, + SSI_MODE1, + SSI_MODE2, + SSI_CONTROL, + SSI_CTRL, + SSI_BUSIF0_MODE, + SSI_BUSIF1_MODE, + SSI_BUSIF2_MODE, + SSI_BUSIF3_MODE, + SSI_BUSIF4_MODE, + SSI_BUSIF5_MODE, + SSI_BUSIF6_MODE, + SSI_BUSIF7_MODE, + SSI_BUSIF0_ADINR, + SSI_BUSIF1_ADINR, + SSI_BUSIF2_ADINR, + SSI_BUSIF3_ADINR, + SSI_BUSIF4_ADINR, + SSI_BUSIF5_ADINR, + SSI_BUSIF6_ADINR, + SSI_BUSIF7_ADINR, + SSI_BUSIF0_DALIGN, + SSI_BUSIF1_DALIGN, + SSI_BUSIF2_DALIGN, + SSI_BUSIF3_DALIGN, + SSI_BUSIF4_DALIGN, + SSI_BUSIF5_DALIGN, + SSI_BUSIF6_DALIGN, + SSI_BUSIF7_DALIGN, + SSI_INT_ENABLE, + SSI_SYS_STATUS0, + SSI_SYS_STATUS1, + SSI_SYS_STATUS2, + SSI_SYS_STATUS3, + SSI_SYS_STATUS4, + SSI_SYS_STATUS5, + SSI_SYS_STATUS6, + SSI_SYS_STATUS7, + SSI_SYS_INT_ENABLE0, + SSI_SYS_INT_ENABLE1, + SSI_SYS_INT_ENABLE2, + SSI_SYS_INT_ENABLE3, + SSI_SYS_INT_ENABLE4, + SSI_SYS_INT_ENABLE5, + SSI_SYS_INT_ENABLE6, + SSI_SYS_INT_ENABLE7, + HDMI0_SEL, + HDMI1_SEL, + SSI9_BUSIF0_MODE, + SSI9_BUSIF1_MODE, + SSI9_BUSIF2_MODE, + SSI9_BUSIF3_MODE, + SSI9_BUSIF4_MODE, + SSI9_BUSIF5_MODE, + SSI9_BUSIF6_MODE, + SSI9_BUSIF7_MODE, + SSI9_BUSIF0_ADINR, + SSI9_BUSIF1_ADINR, + SSI9_BUSIF2_ADINR, + SSI9_BUSIF3_ADINR, + SSI9_BUSIF4_ADINR, + SSI9_BUSIF5_ADINR, + SSI9_BUSIF6_ADINR, + SSI9_BUSIF7_ADINR, + SSI9_BUSIF0_DALIGN, + SSI9_BUSIF1_DALIGN, + SSI9_BUSIF2_DALIGN, + SSI9_BUSIF3_DALIGN, + SSI9_BUSIF4_DALIGN, + SSI9_BUSIF5_DALIGN, + SSI9_BUSIF6_DALIGN, + SSI9_BUSIF7_DALIGN, + + /* SSI */ + SSICR, + SSISR, + SSITDR, + SSIRDR, + SSIWSR, + + REG_MAX, +}; +#define SRCIN_TIMSEL(i) (SRCIN_TIMSEL0 + (i)) +#define SRCOUT_TIMSEL(i) (SRCOUT_TIMSEL0 + (i)) +#define CTU_SVxxR(i, j) (CTU_SV00R + (i * 8) + (j)) +#define DVC_VOLxR(i) (DVC_VOL0R + (i)) +#define AUDIO_CLK_SEL(i) (AUDIO_CLK_SEL0 + (i)) +#define SSI_BUSIF_MODE(i) (SSI_BUSIF0_MODE + (i)) +#define SSI_BUSIF_ADINR(i) (SSI_BUSIF0_ADINR + (i)) +#define SSI_BUSIF_DALIGN(i) (SSI_BUSIF0_DALIGN + (i)) +#define SSI9_BUSIF_MODE(i) (SSI9_BUSIF0_MODE + (i)) +#define SSI9_BUSIF_ADINR(i) (SSI9_BUSIF0_ADINR + (i)) +#define SSI9_BUSIF_DALIGN(i) (SSI9_BUSIF0_DALIGN + (i)) +#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i)) +#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i)) + + +struct rsnd_priv; +struct rsnd_mod; +struct rsnd_dai; +struct rsnd_dai_stream; + +/* + * R-Car basic functions + */ +u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg); +void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); +void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); +u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod); + +/* + * R-Car DMA + */ +int rsnd_dma_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, struct rsnd_mod **dma_mod); +int rsnd_dma_probe(struct rsnd_priv *priv); +struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, + struct rsnd_mod *mod, char *x); + +/* + * R-Car sound mod + */ +enum rsnd_mod_type { + RSND_MOD_AUDMAPP, + RSND_MOD_AUDMA, + RSND_MOD_DVC, + RSND_MOD_MIX, + RSND_MOD_CTU, + RSND_MOD_CMD, + RSND_MOD_SRC, + RSND_MOD_SSIM3, /* SSI multi 3 */ + RSND_MOD_SSIM2, /* SSI multi 2 */ + RSND_MOD_SSIM1, /* SSI multi 1 */ + RSND_MOD_SSIP, /* SSI parent */ + RSND_MOD_SSI, + RSND_MOD_SSIU, + RSND_MOD_MAX, +}; + +struct rsnd_mod_ops { + char *name; + struct dma_chan* (*dma_req)(struct rsnd_dai_stream *io, + struct rsnd_mod *mod); + int (*probe)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*remove)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*init)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*quit)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*start)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*stop)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*irq)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv, int enable); + int (*pcm_new)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd); + int (*hw_params)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params); + int (*pointer)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + snd_pcm_uframes_t *pointer); + int (*fallback)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*prepare)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*cleanup)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*hw_free)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_pcm_substream *substream); + u32 *(*get_status)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type); + int (*id)(struct rsnd_mod *mod); + int (*id_sub)(struct rsnd_mod *mod); + int (*id_cmd)(struct rsnd_mod *mod); + +#ifdef CONFIG_DEBUG_FS + void (*debug_info)(struct seq_file *m, + struct rsnd_dai_stream *io, struct rsnd_mod *mod); +#endif +}; + +struct rsnd_dai_stream; +struct rsnd_mod { + int id; + enum rsnd_mod_type type; + struct rsnd_mod_ops *ops; + struct rsnd_priv *priv; + struct clk *clk; + u32 status; +}; +/* + * status + * + * 0xH000DCB0 + * + * B 0: init 1: quit + * C 0: start 1: stop + * D 0: hw_params 1: hw_free + * + * H is always called (see __rsnd_mod_call) + */ +#define __rsnd_mod_shift_init 4 +#define __rsnd_mod_shift_quit 4 +#define __rsnd_mod_shift_start 8 +#define __rsnd_mod_shift_stop 8 +#define __rsnd_mod_shift_hw_params 12 +#define __rsnd_mod_shift_hw_free 12 +#define __rsnd_mod_shift_probe 28 /* always called */ +#define __rsnd_mod_shift_remove 28 /* always called */ +#define __rsnd_mod_shift_irq 28 /* always called */ +#define __rsnd_mod_shift_pcm_new 28 /* always called */ +#define __rsnd_mod_shift_fallback 28 /* always called */ +#define __rsnd_mod_shift_pointer 28 /* always called */ +#define __rsnd_mod_shift_prepare 28 /* always called */ +#define __rsnd_mod_shift_cleanup 28 /* always called */ + +#define __rsnd_mod_add_probe 0 +#define __rsnd_mod_add_remove 0 +#define __rsnd_mod_add_prepare 0 +#define __rsnd_mod_add_cleanup 0 +#define __rsnd_mod_add_init 1 /* needs protect */ +#define __rsnd_mod_add_quit -1 /* needs protect */ +#define __rsnd_mod_add_start 1 /* needs protect */ +#define __rsnd_mod_add_stop -1 /* needs protect */ +#define __rsnd_mod_add_hw_params 1 /* needs protect */ +#define __rsnd_mod_add_hw_free -1 /* needs protect */ +#define __rsnd_mod_add_irq 0 +#define __rsnd_mod_add_pcm_new 0 +#define __rsnd_mod_add_fallback 0 +#define __rsnd_mod_add_pointer 0 + +#define __rsnd_mod_call_probe 0 +#define __rsnd_mod_call_remove 0 +#define __rsnd_mod_call_prepare 0 +#define __rsnd_mod_call_cleanup 0 +#define __rsnd_mod_call_init 0 /* needs protect */ +#define __rsnd_mod_call_quit 1 /* needs protect */ +#define __rsnd_mod_call_start 0 /* needs protect */ +#define __rsnd_mod_call_stop 1 /* needs protect */ +#define __rsnd_mod_call_hw_params 0 /* needs protect */ +#define __rsnd_mod_call_hw_free 1 /* needs protect */ +#define __rsnd_mod_call_irq 0 +#define __rsnd_mod_call_pcm_new 0 +#define __rsnd_mod_call_fallback 0 +#define __rsnd_mod_call_pointer 0 + +#define rsnd_mod_to_priv(mod) ((mod)->priv) +#define rsnd_mod_power_on(mod) clk_enable((mod)->clk) +#define rsnd_mod_power_off(mod) clk_disable((mod)->clk) +#define rsnd_mod_get(ip) (&(ip)->mod) + +int rsnd_mod_init(struct rsnd_priv *priv, + struct rsnd_mod *mod, + struct rsnd_mod_ops *ops, + struct clk *clk, + enum rsnd_mod_type type, + int id); +void rsnd_mod_quit(struct rsnd_mod *mod); +struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, + struct rsnd_mod *mod); +void rsnd_mod_interrupt(struct rsnd_mod *mod, + void (*callback)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io)); +u32 *rsnd_mod_get_status(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type); +int rsnd_mod_id(struct rsnd_mod *mod); +int rsnd_mod_id_raw(struct rsnd_mod *mod); +int rsnd_mod_id_sub(struct rsnd_mod *mod); +char *rsnd_mod_name(struct rsnd_mod *mod); +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size); +#define for_each_rsnd_mod(iterator, pos, io) \ + for (iterator = 0; \ + (pos = rsnd_mod_next(&iterator, io, NULL, 0)); iterator++) +#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size) \ + for (iterator = 0; \ + (pos = rsnd_mod_next(&iterator, io, array, size)); iterator++) +#define for_each_rsnd_mod_array(iterator, pos, io, array) \ + for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array)) + +void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, + struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), + struct device_node *node, + struct device_node *playback, + struct device_node *capture); +int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name); +int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx); + +int rsnd_channel_normalization(int chan); +#define rsnd_runtime_channel_original(io) \ + rsnd_runtime_channel_original_with_params(io, NULL) +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); +#define rsnd_runtime_channel_after_ctu(io) \ + rsnd_runtime_channel_after_ctu_with_params(io, NULL) +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); +#define rsnd_runtime_channel_for_ssi(io) \ + rsnd_runtime_channel_for_ssi_with_params(io, NULL) +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); +int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io); +int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io); +int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io); + +/* + * DT + */ +#define rsnd_parse_of_node(priv, node) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) +#define RSND_NODE_DAI "rcar_sound,dai" +#define RSND_NODE_SSI "rcar_sound,ssi" +#define RSND_NODE_SSIU "rcar_sound,ssiu" +#define RSND_NODE_SRC "rcar_sound,src" +#define RSND_NODE_CTU "rcar_sound,ctu" +#define RSND_NODE_MIX "rcar_sound,mix" +#define RSND_NODE_DVC "rcar_sound,dvc" + +/* + * R-Car sound DAI + */ +#define RSND_DAI_NAME_SIZE 16 +struct rsnd_dai_stream { + char name[RSND_DAI_NAME_SIZE]; + struct snd_pcm_substream *substream; + struct rsnd_mod *mod[RSND_MOD_MAX]; + struct rsnd_mod *dma; + struct rsnd_dai *rdai; + struct device *dmac_dev; /* for IPMMU */ + u32 converted_rate; /* converted sampling rate */ + int converted_chan; /* converted channels */ + u32 parent_ssi_status; + u32 flags; +}; + +/* flags */ +#define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */ +#define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */ +#define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */ +#define RSND_HW_RULE_ERR (1 << 3) /* hw_rule error */ + +#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) +#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU) +#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) +#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) +#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) +#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) +#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) +#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD) +#define rsnd_io_to_rdai(io) ((io)->rdai) +#define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) +#define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) +#define rsnd_io_to_runtime(io) ((io)->substream ? \ + (io)->substream->runtime : NULL) +#define rsnd_io_converted_rate(io) ((io)->converted_rate) +#define rsnd_io_converted_chan(io) ((io)->converted_chan) +int rsnd_io_is_working(struct rsnd_dai_stream *io); + +struct rsnd_dai { + char name[RSND_DAI_NAME_SIZE]; + struct rsnd_dai_stream playback; + struct rsnd_dai_stream capture; + struct rsnd_priv *priv; + struct snd_pcm_hw_constraint_list constraint; + struct of_phandle_args dai_args; + + int max_channels; /* 2ch - 16ch */ + int ssi_lane; /* 1lane - 4lane */ + int chan_width; /* 16/24/32 bit width */ + + unsigned int clk_master:1; + unsigned int bit_clk_inv:1; + unsigned int frm_clk_inv:1; + unsigned int sys_delay:1; + unsigned int data_alignment:1; +}; + +#define rsnd_rdai_nr(priv) ((priv)->rdai_nr) +#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) +#define rsnd_rdai_to_priv(rdai) ((rdai)->priv) +#define for_each_rsnd_dai(rdai, priv, i) \ + for (i = 0; \ + (i < rsnd_rdai_nr(priv)) && \ + ((rdai) = rsnd_rdai_get(priv, i)); \ + i++) + +struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); + +#define rsnd_rdai_channels_set(rdai, max_channels) \ + rsnd_rdai_channels_ctrl(rdai, max_channels) +#define rsnd_rdai_channels_get(rdai) \ + rsnd_rdai_channels_ctrl(rdai, 0) +int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, + int max_channels); + +#define rsnd_rdai_ssi_lane_set(rdai, ssi_lane) \ + rsnd_rdai_ssi_lane_ctrl(rdai, ssi_lane) +#define rsnd_rdai_ssi_lane_get(rdai) \ + rsnd_rdai_ssi_lane_ctrl(rdai, 0) +int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, + int ssi_lane); + +#define rsnd_rdai_width_set(rdai, width) \ + rsnd_rdai_width_ctrl(rdai, width) +#define rsnd_rdai_width_get(rdai) \ + rsnd_rdai_width_ctrl(rdai, 0) +int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width); +int rsnd_dai_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type); + +/* + * R-Car Gen1/Gen2 + */ +int rsnd_gen_probe(struct rsnd_priv *priv); +void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, + struct rsnd_mod *mod, + enum rsnd_reg reg); +phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); +#ifdef CONFIG_DEBUG_FS +void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id); +#endif + +/* + * R-Car ADG + */ +int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate); +int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod); +int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate); +int rsnd_adg_probe(struct rsnd_priv *priv); +void rsnd_adg_remove(struct rsnd_priv *priv); +int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, + struct rsnd_dai_stream *io, + unsigned int in_rate, + unsigned int out_rate); +int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, + struct rsnd_dai_stream *io); +#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) +#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable); +void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m); + +/* + * R-Car sound priv + */ +struct rsnd_priv { + + struct platform_device *pdev; + spinlock_t lock; + unsigned long flags; +#define RSND_GEN_MASK (0xF << 0) +#define RSND_GEN1 (1 << 0) +#define RSND_GEN2 (2 << 0) +#define RSND_GEN3 (3 << 0) +#define RSND_GEN4 (4 << 0) +#define RSND_SOC_MASK (0xFF << 4) +#define RSND_SOC_E (1 << 4) /* E1/E2/E3 */ + + /* + * below value will be filled on rsnd_gen_probe() + */ + void *gen; + + /* + * below value will be filled on rsnd_adg_probe() + */ + void *adg; + + /* + * below value will be filled on rsnd_dma_probe() + */ + void *dma; + + /* + * below value will be filled on rsnd_ssi_probe() + */ + void *ssi; + int ssi_nr; + + /* + * below value will be filled on rsnd_ssiu_probe() + */ + void *ssiu; + int ssiu_nr; + + /* + * below value will be filled on rsnd_src_probe() + */ + void *src; + int src_nr; + + /* + * below value will be filled on rsnd_ctu_probe() + */ + void *ctu; + int ctu_nr; + + /* + * below value will be filled on rsnd_mix_probe() + */ + void *mix; + int mix_nr; + + /* + * below value will be filled on rsnd_dvc_probe() + */ + void *dvc; + int dvc_nr; + + /* + * below value will be filled on rsnd_cmd_probe() + */ + void *cmd; + int cmd_nr; + + /* + * below value will be filled on rsnd_dai_probe() + */ + struct snd_soc_dai_driver *daidrv; + struct rsnd_dai *rdai; + int rdai_nr; + +#define RSND_MAX_COMPONENT 3 + int component_dais[RSND_MAX_COMPONENT]; +}; + +#define rsnd_priv_to_pdev(priv) ((priv)->pdev) +#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) + +#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) +#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) +#define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3) +#define rsnd_is_gen4(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4) +#define rsnd_is_gen3_e3(priv) (((priv)->flags & \ + (RSND_GEN_MASK | RSND_SOC_MASK)) == \ + (RSND_GEN3 | RSND_SOC_E)) + +#define rsnd_flags_has(p, f) ((p)->flags & (f)) +#define rsnd_flags_set(p, f) ((p)->flags |= (f)) +#define rsnd_flags_del(p, f) ((p)->flags &= ~(f)) + +/* + * rsnd_kctrl + */ +struct rsnd_kctrl_cfg { + unsigned int max; + unsigned int size; + u32 *val; + const char * const *texts; + int (*accept)(struct rsnd_dai_stream *io); + void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod); + struct rsnd_dai_stream *io; + struct snd_card *card; + struct snd_kcontrol *kctrl; + struct rsnd_mod *mod; +}; + +#define RSND_MAX_CHANNELS 8 +struct rsnd_kctrl_cfg_m { + struct rsnd_kctrl_cfg cfg; + u32 val[RSND_MAX_CHANNELS]; +}; + +struct rsnd_kctrl_cfg_s { + struct rsnd_kctrl_cfg cfg; + u32 val; +}; +#define rsnd_kctrl_size(x) ((x).cfg.size) +#define rsnd_kctrl_max(x) ((x).cfg.max) +#define rsnd_kctrl_valm(x, i) ((x).val[i]) /* = (x).cfg.val[i] */ +#define rsnd_kctrl_vals(x) ((x).val) /* = (x).cfg.val[0] */ + +int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io); +int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io); +struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg); +struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg); +int rsnd_kctrl_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd, + const unsigned char *name, + int (*accept)(struct rsnd_dai_stream *io), + void (*update)(struct rsnd_dai_stream *io, + struct rsnd_mod *mod), + struct rsnd_kctrl_cfg *cfg, + const char * const *texts, + int size, + u32 max); + +#define rsnd_kctrl_new_m(mod, io, rtd, name, accept, update, cfg, size, max) \ + rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_m(cfg), \ + NULL, size, max) + +#define rsnd_kctrl_new_s(mod, io, rtd, name, accept, update, cfg, max) \ + rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ + NULL, 1, max) + +#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts, size) \ + rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ + texts, 1, size) + +extern const char * const volume_ramp_rate[]; +#define VOLUME_RAMP_MAX_DVC (0x17 + 1) +#define VOLUME_RAMP_MAX_MIX (0x0a + 1) + +/* + * R-Car SSI + */ +int rsnd_ssi_probe(struct rsnd_priv *priv); +void rsnd_ssi_remove(struct rsnd_priv *priv); +struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); +int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); +u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io); +int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); + +#define rsnd_ssi_is_pin_sharing(io) \ + __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) +int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); + +#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI) +void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture); +unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, + int param1, int param2, int *idx); + +/* + * R-Car SSIU + */ +int rsnd_ssiu_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *mod); +int rsnd_ssiu_probe(struct rsnd_priv *priv); +void rsnd_ssiu_remove(struct rsnd_priv *priv); +void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture); +#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU) +bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod); + +/* + * R-Car SRC + */ +int rsnd_src_probe(struct rsnd_priv *priv); +void rsnd_src_remove(struct rsnd_priv *priv); +struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); + +#define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1) +#define rsnd_src_get_out_rate(priv, io) rsnd_src_get_rate(priv, io, 0) +unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + int is_in); + +#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC) +#define rsnd_parse_connect_src(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, "src", rsnd_src_mod_get, \ + rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) + +/* + * R-Car CTU + */ +int rsnd_ctu_probe(struct rsnd_priv *priv); +void rsnd_ctu_remove(struct rsnd_priv *priv); +struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) +#define rsnd_parse_connect_ctu(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, "ctu", rsnd_ctu_mod_get, \ + rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) + +/* + * R-Car MIX + */ +int rsnd_mix_probe(struct rsnd_priv *priv); +void rsnd_mix_remove(struct rsnd_priv *priv); +struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX) +#define rsnd_parse_connect_mix(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, "mix", rsnd_mix_mod_get, \ + rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) + +/* + * R-Car DVC + */ +int rsnd_dvc_probe(struct rsnd_priv *priv); +void rsnd_dvc_remove(struct rsnd_priv *priv); +struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC) +#define rsnd_parse_connect_dvc(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, "dvc", rsnd_dvc_mod_get, \ + rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) + +/* + * R-Car CMD + */ +int rsnd_cmd_probe(struct rsnd_priv *priv); +void rsnd_cmd_remove(struct rsnd_priv *priv); +int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id); + +void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); + +/* + * If you don't need interrupt status debug message, + * define RSND_DEBUG_NO_IRQ_STATUS as 1 on top of src.c/ssi.c + * + * #define RSND_DEBUG_NO_IRQ_STATUS 1 + */ +#define rsnd_print_irq_status(dev, param...) do { \ + if (!IS_BUILTIN(RSND_DEBUG_NO_IRQ_STATUS)) \ + dev_info(dev, param); \ +} while (0) + +#ifdef CONFIG_DEBUG_FS +int rsnd_debugfs_probe(struct snd_soc_component *component); +void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr, + void __iomem *base, int offset, int size); +void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod, + int reg_id, int offset, int size); + +#else +#define rsnd_debugfs_probe NULL +#endif + +#endif /* RSND_H */ diff --git a/sound/soc/renesas/rcar/src.c b/sound/soc/renesas/rcar/src.c new file mode 100644 index 00000000000000..e7f86db0d94c3c --- /dev/null +++ b/sound/soc/renesas/rcar/src.c @@ -0,0 +1,732 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car SRC support +// +// Copyright (C) 2013 Renesas Solutions Corp. +// Kuninori Morimoto + +/* + * You can use Synchronous Sampling Rate Convert (if no DVC) + * + * amixer set "SRC Out Rate" on + * aplay xxx.wav & + * amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz + * amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz + */ + +/* + * you can enable below define if you don't need + * SSI interrupt status debug message when debugging + * see rsnd_print_irq_status() + * + * #define RSND_DEBUG_NO_IRQ_STATUS 1 + */ + +#include +#include "rsnd.h" + +#define SRC_NAME "src" + +/* SCU_SYSTEM_STATUS0/1 */ +#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) + +struct rsnd_src { + struct rsnd_mod mod; + struct rsnd_mod *dma; + struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ + struct rsnd_kctrl_cfg_s sync; /* sync convert */ + int irq; +}; + +#define RSND_SRC_NAME_SIZE 16 + +#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) +#define rsnd_src_nr(priv) ((priv)->src_nr) +#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val) + +#define rsnd_mod_to_src(_mod) \ + container_of((_mod), struct rsnd_src, mod) + +#define for_each_rsnd_src(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_src_nr(priv)) && \ + ((pos) = (struct rsnd_src *)(priv)->src + i); \ + i++) + + +/* + * image of SRC (Sampling Rate Converter) + * + * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ + * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | + * 44.1kHz <-> +-----+ +-----+ +-------+ + * ... + * + */ + +static void rsnd_src_activation(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SRC_SWRSR, 0); + rsnd_mod_write(mod, SRC_SWRSR, 1); +} + +static void rsnd_src_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SRC_SRCIR, 1); + rsnd_mod_write(mod, SRC_SWRSR, 0); +} + +static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + int is_play = rsnd_io_is_play(io); + + return rsnd_dma_request_channel(rsnd_src_of_node(priv), + SRC_NAME, mod, + is_play ? "rx" : "tx"); +} + +static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 convert_rate; + + if (!runtime) + return 0; + + if (!rsnd_src_sync_is_enabled(mod)) + return rsnd_io_converted_rate(io); + + convert_rate = src->sync.val; + + if (!convert_rate) + convert_rate = rsnd_io_converted_rate(io); + + if (!convert_rate) + convert_rate = runtime->rate; + + return convert_rate; +} + +unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + int is_in) +{ + struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + unsigned int rate = 0; + int is_play = rsnd_io_is_play(io); + + /* + * Playback + * runtime_rate -> [SRC] -> convert_rate + * + * Capture + * convert_rate -> [SRC] -> runtime_rate + */ + + if (is_play == is_in) + return runtime->rate; + + /* + * return convert rate if SRC is used, + * otherwise, return runtime->rate as usual + */ + if (src_mod) + rate = rsnd_src_convert_rate(io, src_mod); + + if (!rate) + rate = runtime->rate; + + return rate; +} + +static const u32 bsdsr_table_pattern1[] = { + 0x01800000, /* 6 - 1/6 */ + 0x01000000, /* 6 - 1/4 */ + 0x00c00000, /* 6 - 1/3 */ + 0x00800000, /* 6 - 1/2 */ + 0x00600000, /* 6 - 2/3 */ + 0x00400000, /* 6 - 1 */ +}; + +static const u32 bsdsr_table_pattern2[] = { + 0x02400000, /* 6 - 1/6 */ + 0x01800000, /* 6 - 1/4 */ + 0x01200000, /* 6 - 1/3 */ + 0x00c00000, /* 6 - 1/2 */ + 0x00900000, /* 6 - 2/3 */ + 0x00600000, /* 6 - 1 */ +}; + +static const u32 bsisr_table[] = { + 0x00100060, /* 6 - 1/6 */ + 0x00100040, /* 6 - 1/4 */ + 0x00100030, /* 6 - 1/3 */ + 0x00100020, /* 6 - 1/2 */ + 0x00100020, /* 6 - 2/3 */ + 0x00100020, /* 6 - 1 */ +}; + +static const u32 chan288888[] = { + 0x00000006, /* 1 to 2 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ +}; + +static const u32 chan244888[] = { + 0x00000006, /* 1 to 2 */ + 0x0000001e, /* 1 to 4 */ + 0x0000001e, /* 1 to 4 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ +}; + +static const u32 chan222222[] = { + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ +}; + +static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int is_play = rsnd_io_is_play(io); + int use_src = 0; + u32 fin, fout; + u32 ifscr, fsrate, adinr; + u32 cr, route; + u32 i_busif, o_busif, tmp; + const u32 *bsdsr_table; + const u32 *chptn; + uint ratio; + int chan; + int idx; + + if (!runtime) + return; + + fin = rsnd_src_get_in_rate(priv, io); + fout = rsnd_src_get_out_rate(priv, io); + + chan = rsnd_runtime_channel_original(io); + + /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ + if (fin == fout) + ratio = 0; + else if (fin > fout) + ratio = 100 * fin / fout; + else + ratio = 100 * fout / fin; + + if (ratio > 600) { + dev_err(dev, "FSO/FSI ratio error\n"); + return; + } + + use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod); + + /* + * SRC_ADINR + */ + adinr = rsnd_get_adinr_bit(mod, io) | chan; + + /* + * SRC_IFSCR / SRC_IFSVR + */ + ifscr = 0; + fsrate = 0; + if (use_src) { + u64 n; + + ifscr = 1; + n = (u64)0x0400000 * fin; + do_div(n, fout); + fsrate = n; + } + + /* + * SRC_SRCCR / SRC_ROUTE_MODE0 + */ + cr = 0x00011110; + route = 0x0; + if (use_src) { + route = 0x1; + + if (rsnd_src_sync_is_enabled(mod)) { + cr |= 0x1; + route |= rsnd_io_is_play(io) ? + (0x1 << 24) : (0x1 << 25); + } + } + + /* + * SRC_BSDSR / SRC_BSISR + * + * see + * Combination of Register Setting Related to + * FSO/FSI Ratio and Channel, Latency + */ + switch (rsnd_mod_id(mod)) { + case 0: + chptn = chan288888; + bsdsr_table = bsdsr_table_pattern1; + break; + case 1: + case 3: + case 4: + chptn = chan244888; + bsdsr_table = bsdsr_table_pattern1; + break; + case 2: + case 9: + chptn = chan222222; + bsdsr_table = bsdsr_table_pattern1; + break; + case 5: + case 6: + case 7: + case 8: + chptn = chan222222; + bsdsr_table = bsdsr_table_pattern2; + break; + default: + goto convert_rate_err; + } + + /* + * E3 need to overwrite + */ + if (rsnd_is_gen3_e3(priv)) + switch (rsnd_mod_id(mod)) { + case 0: + case 4: + chptn = chan222222; + } + + for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++) + if (chptn[idx] & (1 << chan)) + break; + + if (chan > 8 || + idx >= ARRAY_SIZE(chan222222)) + goto convert_rate_err; + + /* BUSIF_MODE */ + tmp = rsnd_get_busif_shift(io, mod); + i_busif = ( is_play ? tmp : 0) | 1; + o_busif = (!is_play ? tmp : 0) | 1; + + rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); + + rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ + rsnd_mod_write(mod, SRC_ADINR, adinr); + rsnd_mod_write(mod, SRC_IFSCR, ifscr); + rsnd_mod_write(mod, SRC_IFSVR, fsrate); + rsnd_mod_write(mod, SRC_SRCCR, cr); + rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]); + rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]); + rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ + + rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif); + rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif); + + rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); + + rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); + + return; + +convert_rate_err: + dev_err(dev, "unknown BSDSR/BSDIR settings\n"); +} + +static int rsnd_src_irq(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv, + int enable) +{ + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 sys_int_val, int_val, sys_int_mask; + int irq = src->irq; + int id = rsnd_mod_id(mod); + + sys_int_val = + sys_int_mask = OUF_SRC(id); + int_val = 0x3300; + + /* + * IRQ is not supported on non-DT + * see + * rsnd_src_probe_() + */ + if ((irq <= 0) || !enable) { + sys_int_val = 0; + int_val = 0; + } + + /* + * WORKAROUND + * + * ignore over flow error when rsnd_src_sync_is_enabled() + */ + if (rsnd_src_sync_is_enabled(mod)) + sys_int_val = sys_int_val & 0xffff; + + rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); + rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); + rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); + + return 0; +} + +static void rsnd_src_status_clear(struct rsnd_mod *mod) +{ + u32 val = OUF_SRC(rsnd_mod_id(mod)); + + rsnd_mod_write(mod, SCU_SYS_STATUS0, val); + rsnd_mod_write(mod, SCU_SYS_STATUS1, val); +} + +static bool rsnd_src_error_occurred(struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + u32 val0, val1; + u32 status0, status1; + bool ret = false; + + val0 = val1 = OUF_SRC(rsnd_mod_id(mod)); + + /* + * WORKAROUND + * + * ignore over flow error when rsnd_src_sync_is_enabled() + */ + if (rsnd_src_sync_is_enabled(mod)) + val0 = val0 & 0xffff; + + status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); + status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); + if ((status0 & val0) || (status1 & val1)) { + rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", + rsnd_mod_name(mod), status0, status1); + + ret = true; + } + + return ret; +} + +static int rsnd_src_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + u32 val; + + /* + * WORKAROUND + * + * Enable SRC output if you want to use sync convert together with DVC + */ + val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ? + 0x01 : 0x11; + + rsnd_mod_write(mod, SRC_CTRL, val); + + return 0; +} + +static int rsnd_src_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_write(mod, SRC_CTRL, 0); + + return 0; +} + +static int rsnd_src_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_src *src = rsnd_mod_to_src(mod); + int ret; + + /* reset sync convert_rate */ + src->sync.val = 0; + + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; + + rsnd_src_activation(mod); + + rsnd_src_set_convert_rate(io, mod); + + rsnd_src_status_clear(mod); + + return 0; +} + +static int rsnd_src_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_src *src = rsnd_mod_to_src(mod); + + rsnd_src_halt(mod); + + rsnd_mod_power_off(mod); + + /* reset sync convert_rate */ + src->sync.val = 0; + + return 0; +} + +static void __rsnd_src_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + bool stop = false; + + spin_lock(&priv->lock); + + /* ignore all cases if not working */ + if (!rsnd_io_is_working(io)) + goto rsnd_src_interrupt_out; + + if (rsnd_src_error_occurred(mod)) + stop = true; + + rsnd_src_status_clear(mod); +rsnd_src_interrupt_out: + + spin_unlock(&priv->lock); + + if (stop) + snd_pcm_stop_xrun(io->substream); +} + +static irqreturn_t rsnd_src_interrupt(int irq, void *data) +{ + struct rsnd_mod *mod = data; + + rsnd_mod_interrupt(mod, __rsnd_src_interrupt); + + return IRQ_HANDLED; +} + +static int rsnd_src_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_src *src = rsnd_mod_to_src(mod); + struct device *dev = rsnd_priv_to_dev(priv); + int irq = src->irq; + int ret; + + if (irq > 0) { + /* + * IRQ is not supported on non-DT + * see + * rsnd_src_irq() + */ + ret = devm_request_irq(dev, irq, + rsnd_src_interrupt, + IRQF_SHARED, + dev_name(dev), mod); + if (ret) + return ret; + } + + ret = rsnd_dma_attach(io, mod, &src->dma); + + return ret; +} + +static int rsnd_src_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd) +{ + struct rsnd_src *src = rsnd_mod_to_src(mod); + int ret; + + /* + * enable SRC sync convert if possible + */ + + /* + * It can't use SRC Synchronous convert + * when Capture if it uses CMD + */ + if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io)) + return 0; + + /* + * enable sync convert + */ + ret = rsnd_kctrl_new_s(mod, io, rtd, + rsnd_io_is_play(io) ? + "SRC Out Rate Switch" : + "SRC In Rate Switch", + rsnd_kctrl_accept_anytime, + rsnd_src_set_convert_rate, + &src->sen, 1); + if (ret < 0) + return ret; + + ret = rsnd_kctrl_new_s(mod, io, rtd, + rsnd_io_is_play(io) ? + "SRC Out Rate" : + "SRC In Rate", + rsnd_kctrl_accept_runtime, + rsnd_src_set_convert_rate, + &src->sync, 192000); + + return ret; +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_src_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, + rsnd_mod_id(mod) * 0x20, 0x20); + seq_puts(m, "\n"); + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, + 0x1c0, 0x20); + seq_puts(m, "\n"); + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, + 0x200 + rsnd_mod_id(mod) * 0x40, 0x40); +} +#define DEBUG_INFO .debug_info = rsnd_src_debug_info +#else +#define DEBUG_INFO +#endif + +static struct rsnd_mod_ops rsnd_src_ops = { + .name = SRC_NAME, + .dma_req = rsnd_src_dma_req, + .probe = rsnd_src_probe_, + .init = rsnd_src_init, + .quit = rsnd_src_quit, + .start = rsnd_src_start, + .stop = rsnd_src_stop, + .irq = rsnd_src_irq, + .pcm_new = rsnd_src_pcm_new, + .get_status = rsnd_mod_get_status, + DEBUG_INFO +}; + +struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) + id = 0; + + return rsnd_mod_get(rsnd_src_get(priv, id)); +} + +int rsnd_src_probe(struct rsnd_priv *priv) +{ + struct device_node *node; + struct device_node *np; + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_src *src; + struct clk *clk; + char name[RSND_SRC_NAME_SIZE]; + int i, nr, ret; + + node = rsnd_src_of_node(priv); + if (!node) + return 0; /* not used is not error */ + + nr = rsnd_node_count(priv, node, SRC_NAME); + if (!nr) { + ret = -EINVAL; + goto rsnd_src_probe_done; + } + + src = devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL); + if (!src) { + ret = -ENOMEM; + goto rsnd_src_probe_done; + } + + priv->src_nr = nr; + priv->src = src; + + i = 0; + for_each_child_of_node(node, np) { + if (!of_device_is_available(np)) + goto skip; + + i = rsnd_node_fixed_index(dev, np, SRC_NAME, i); + if (i < 0) { + ret = -EINVAL; + of_node_put(np); + goto rsnd_src_probe_done; + } + + src = rsnd_src_get(priv, i); + + snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", + SRC_NAME, i); + + src->irq = irq_of_parse_and_map(np, 0); + if (!src->irq) { + ret = -EINVAL; + of_node_put(np); + goto rsnd_src_probe_done; + } + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + of_node_put(np); + goto rsnd_src_probe_done; + } + + ret = rsnd_mod_init(priv, rsnd_mod_get(src), + &rsnd_src_ops, clk, RSND_MOD_SRC, i); + if (ret) { + of_node_put(np); + goto rsnd_src_probe_done; + } + +skip: + i++; + } + + ret = 0; + +rsnd_src_probe_done: + of_node_put(node); + + return ret; +} + +void rsnd_src_remove(struct rsnd_priv *priv) +{ + struct rsnd_src *src; + int i; + + for_each_rsnd_src(src, priv, i) { + rsnd_mod_quit(rsnd_mod_get(src)); + } +} diff --git a/sound/soc/renesas/rcar/ssi.c b/sound/soc/renesas/rcar/ssi.c new file mode 100644 index 00000000000000..b3d4e8ae07eff8 --- /dev/null +++ b/sound/soc/renesas/rcar/ssi.c @@ -0,0 +1,1260 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car SSIU/SSI support +// +// Copyright (C) 2013 Renesas Solutions Corp. +// Kuninori Morimoto +// +// Based on fsi.c +// Kuninori Morimoto + +/* + * you can enable below define if you don't need + * SSI interrupt status debug message when debugging + * see rsnd_print_irq_status() + * + * #define RSND_DEBUG_NO_IRQ_STATUS 1 + */ + +#include +#include +#include +#include +#include "rsnd.h" +#define RSND_SSI_NAME_SIZE 16 + +/* + * SSICR + */ +#define FORCE (1u << 31) /* Fixed */ +#define DMEN (1u << 28) /* DMA Enable */ +#define UIEN (1u << 27) /* Underflow Interrupt Enable */ +#define OIEN (1u << 26) /* Overflow Interrupt Enable */ +#define IIEN (1u << 25) /* Idle Mode Interrupt Enable */ +#define DIEN (1u << 24) /* Data Interrupt Enable */ +#define CHNL_4 (1u << 22) /* Channels */ +#define CHNL_6 (2u << 22) /* Channels */ +#define CHNL_8 (3u << 22) /* Channels */ +#define DWL_MASK (7u << 19) /* Data Word Length mask */ +#define DWL_8 (0u << 19) /* Data Word Length */ +#define DWL_16 (1u << 19) /* Data Word Length */ +#define DWL_18 (2u << 19) /* Data Word Length */ +#define DWL_20 (3u << 19) /* Data Word Length */ +#define DWL_22 (4u << 19) /* Data Word Length */ +#define DWL_24 (5u << 19) /* Data Word Length */ +#define DWL_32 (6u << 19) /* Data Word Length */ + +/* + * System word length + */ +#define SWL_16 (1 << 16) /* R/W System Word Length */ +#define SWL_24 (2 << 16) /* R/W System Word Length */ +#define SWL_32 (3 << 16) /* R/W System Word Length */ + +#define SCKD (1 << 15) /* Serial Bit Clock Direction */ +#define SWSD (1 << 14) /* Serial WS Direction */ +#define SCKP (1 << 13) /* Serial Bit Clock Polarity */ +#define SWSP (1 << 12) /* Serial WS Polarity */ +#define SDTA (1 << 10) /* Serial Data Alignment */ +#define PDTA (1 << 9) /* Parallel Data Alignment */ +#define DEL (1 << 8) /* Serial Data Delay */ +#define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ +#define TRMD (1 << 1) /* Transmit/Receive Mode Select */ +#define EN (1 << 0) /* SSI Module Enable */ + +/* + * SSISR + */ +#define UIRQ (1 << 27) /* Underflow Error Interrupt Status */ +#define OIRQ (1 << 26) /* Overflow Error Interrupt Status */ +#define IIRQ (1 << 25) /* Idle Mode Interrupt Status */ +#define DIRQ (1 << 24) /* Data Interrupt Status Flag */ + +/* + * SSIWSR + */ +#define CONT (1 << 8) /* WS Continue Function */ +#define WS_MODE (1 << 0) /* WS Mode */ + +#define SSI_NAME "ssi" + +struct rsnd_ssi { + struct rsnd_mod mod; + + u32 flags; + u32 cr_own; + u32 cr_clk; + u32 cr_mode; + u32 cr_en; + u32 wsr; + int chan; + int rate; + int irq; + unsigned int usrcnt; + + /* for PIO */ + int byte_pos; + int byte_per_period; + int next_period_byte; +}; + +/* flags */ +#define RSND_SSI_CLK_PIN_SHARE (1 << 0) +#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ +#define RSND_SSI_PROBED (1 << 2) + +#define for_each_rsnd_ssi(pos, priv, i) \ + for (i = 0; \ + (i < rsnd_ssi_nr(priv)) && \ + ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ + i++) + +#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id) +#define rsnd_ssi_nr(priv) ((priv)->ssi_nr) +#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) +#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) +#define rsnd_ssi_is_multi_secondary(mod, io) \ + (rsnd_ssi_multi_secondaries(io) & (1 << rsnd_mod_id(mod))) +#define rsnd_ssi_is_run_mods(mod, io) \ + (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) +#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod)) + +int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) +{ + struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + int use_busif = 0; + + if (!rsnd_ssi_is_dma_mode(mod)) + return 0; + + if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF))) + use_busif = 1; + if (rsnd_io_to_mod_src(io)) + use_busif = 1; + + return use_busif; +} + +static void rsnd_ssi_status_clear(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SSISR, 0); +} + +static u32 rsnd_ssi_status_get(struct rsnd_mod *mod) +{ + return rsnd_mod_read(mod, SSISR); +} + +static void rsnd_ssi_status_check(struct rsnd_mod *mod, + u32 bit) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + u32 status; + int i; + + for (i = 0; i < 1024; i++) { + status = rsnd_ssi_status_get(mod); + if (status & bit) + return; + + udelay(5); + } + + dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod)); +} + +static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io) +{ + static const enum rsnd_mod_type types[] = { + RSND_MOD_SSIM1, + RSND_MOD_SSIM2, + RSND_MOD_SSIM3, + }; + int i, mask; + + mask = 0; + for (i = 0; i < ARRAY_SIZE(types); i++) { + struct rsnd_mod *mod = rsnd_io_to_mod(io, types[i]); + + if (!mod) + continue; + + mask |= 1 << rsnd_mod_id(mod); + } + + return mask; +} + +static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) +{ + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + u32 mods; + + mods = rsnd_ssi_multi_secondaries_runtime(io) | + 1 << rsnd_mod_id(ssi_mod); + + if (ssi_parent_mod) + mods |= 1 << rsnd_mod_id(ssi_parent_mod); + + return mods; +} + +u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io) +{ + if (rsnd_runtime_is_multi_ssi(io)) + return rsnd_ssi_multi_secondaries(io); + + return 0; +} + +static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); + int width = rsnd_rdai_width_get(rdai); + + switch (width) { + case 32: return SWL_32; + case 24: return SWL_24; + case 16: return SWL_16; + } + + dev_err(dev, "unsupported slot width value: %d\n", width); + return 0; +} + +unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, + int param1, int param2, int *idx) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + static const int ssi_clk_mul_table[] = { + 1, 2, 4, 8, 16, 6, 12, + }; + int j, ret; + unsigned int main_rate; + int width = rsnd_rdai_width_get(rdai); + + for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { + + /* + * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 + * with it is not allowed. (SSIWSR.WS_MODE with + * SSICR.CKDV = 000 is not allowed either). + * Skip it. See SSICR.CKDV + */ + if (j == 0) + continue; + + main_rate = width * param1 * param2 * ssi_clk_mul_table[j]; + + ret = rsnd_adg_clk_query(priv, main_rate); + if (ret < 0) + continue; + + if (idx) + *idx = j; + + return main_rate; + } + + return 0; +} + +static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + int chan = rsnd_runtime_channel_for_ssi(io); + int idx, ret; + unsigned int main_rate; + unsigned int rate = rsnd_io_is_play(io) ? + rsnd_src_get_out_rate(priv, io) : + rsnd_src_get_in_rate(priv, io); + + if (!rsnd_rdai_is_clk_master(rdai)) + return 0; + + if (!rsnd_ssi_can_output_clk(mod)) + return 0; + + if (rsnd_ssi_is_multi_secondary(mod, io)) + return 0; + + if (rsnd_runtime_is_tdm_split(io)) + chan = rsnd_io_converted_chan(io); + + chan = rsnd_channel_normalization(chan); + + if (ssi->usrcnt > 0) { + if (ssi->rate != rate) { + dev_err(dev, "SSI parent/child should use same rate\n"); + return -EINVAL; + } + + if (ssi->chan != chan) { + dev_err(dev, "SSI parent/child should use same chan\n"); + return -EINVAL; + } + + return 0; + } + + ret = -EIO; + main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); + if (!main_rate) + goto rate_err; + + ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); + if (ret < 0) + goto rate_err; + + /* + * SSI clock will be output contiguously + * by below settings. + * This means, rsnd_ssi_master_clk_start() + * and rsnd_ssi_register_setup() are necessary + * for SSI parent + * + * SSICR : FORCE, SCKD, SWSD + * SSIWSR : CONT + */ + ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) | + SCKD | SWSD | CKDV(idx); + ssi->wsr = CONT; + ssi->rate = rate; + ssi->chan = chan; + + dev_dbg(dev, "%s outputs %d chan %u Hz\n", + rsnd_mod_name(mod), chan, rate); + + return 0; + +rate_err: + dev_err(dev, "unsupported clock rate\n"); + return ret; +} + +static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + if (!rsnd_rdai_is_clk_master(rdai)) + return; + + if (!rsnd_ssi_can_output_clk(mod)) + return; + + if (ssi->usrcnt > 1) + return; + + ssi->cr_clk = 0; + ssi->rate = 0; + ssi->chan = 0; + + rsnd_adg_ssi_clk_stop(mod); +} + +static void rsnd_ssi_config_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr_own = ssi->cr_own; + u32 cr_mode = ssi->cr_mode; + u32 wsr = ssi->wsr; + int width; + int is_tdm, is_tdm_split; + + is_tdm = rsnd_runtime_is_tdm(io); + is_tdm_split = rsnd_runtime_is_tdm_split(io); + + if (is_tdm) + dev_dbg(dev, "TDM mode\n"); + if (is_tdm_split) + dev_dbg(dev, "TDM Split mode\n"); + + cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); + + if (rdai->bit_clk_inv) + cr_own |= SCKP; + if (rdai->frm_clk_inv && !is_tdm) + cr_own |= SWSP; + if (rdai->data_alignment) + cr_own |= SDTA; + if (rdai->sys_delay) + cr_own |= DEL; + + /* + * TDM Mode + * see + * rsnd_ssiu_init_gen2() + */ + if (is_tdm || is_tdm_split) { + wsr |= WS_MODE; + cr_own |= CHNL_8; + } + + /* + * We shouldn't exchange SWSP after running. + * This means, parent needs to care it. + */ + if (rsnd_ssi_is_parent(mod, io)) + goto init_end; + + if (rsnd_io_is_play(io)) + cr_own |= TRMD; + + cr_own &= ~DWL_MASK; + width = snd_pcm_format_width(runtime->format); + if (is_tdm_split) { + /* + * The SWL and DWL bits in SSICR should be fixed at 32-bit + * setting when TDM split mode. + * see datasheet + * Operation :: TDM Format Split Function (TDM Split Mode) + */ + width = 32; + } + + switch (width) { + case 8: + cr_own |= DWL_8; + break; + case 16: + cr_own |= DWL_16; + break; + case 24: + cr_own |= DWL_24; + break; + case 32: + cr_own |= DWL_32; + break; + } + + if (rsnd_ssi_is_dma_mode(mod)) { + cr_mode = UIEN | OIEN | /* over/under run */ + DMEN; /* DMA : enable DMA */ + } else { + cr_mode = DIEN; /* PIO : enable Data interrupt */ + } + +init_end: + ssi->cr_own = cr_own; + ssi->cr_mode = cr_mode; + ssi->wsr = wsr; +} + +static void rsnd_ssi_register_setup(struct rsnd_mod *mod) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + rsnd_mod_write(mod, SSIWSR, ssi->wsr); + rsnd_mod_write(mod, SSICR, ssi->cr_own | + ssi->cr_clk | + ssi->cr_mode | + ssi->cr_en); +} + +/* + * SSI mod common functions + */ +static int rsnd_ssi_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + int ret; + + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + + ret = rsnd_ssi_master_clk_start(mod, io); + if (ret < 0) + return ret; + + ssi->usrcnt++; + + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; + + rsnd_ssi_config_init(mod, io); + + rsnd_ssi_register_setup(mod); + + /* clear error status */ + rsnd_ssi_status_clear(mod); + + return 0; +} + +static int rsnd_ssi_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + + if (!ssi->usrcnt) { + dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod)); + return -EIO; + } + + rsnd_ssi_master_clk_stop(mod, io); + + rsnd_mod_power_off(mod); + + ssi->usrcnt--; + + if (!ssi->usrcnt) { + ssi->cr_own = 0; + ssi->cr_mode = 0; + ssi->wsr = 0; + } + + return 0; +} + +static int rsnd_ssi_hw_params(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + unsigned int fmt_width = snd_pcm_format_width(params_format(params)); + + if (fmt_width > rdai->chan_width) { + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + + dev_err(dev, "invalid combination of slot-width and format-data-width\n"); + return -EINVAL; + } + + return 0; +} + +static int rsnd_ssi_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + + /* + * EN will be set via SSIU :: SSI_CONTROL + * if Multi channel mode + */ + if (rsnd_ssi_multi_secondaries_runtime(io)) + return 0; + + /* + * EN is for data output. + * SSI parent EN is not needed. + */ + if (rsnd_ssi_is_parent(mod, io)) + return 0; + + ssi->cr_en = EN; + + rsnd_mod_write(mod, SSICR, ssi->cr_own | + ssi->cr_clk | + ssi->cr_mode | + ssi->cr_en); + + return 0; +} + +static int rsnd_ssi_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr; + + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + + if (rsnd_ssi_is_parent(mod, io)) + return 0; + + cr = ssi->cr_own | + ssi->cr_clk; + + /* + * disable all IRQ, + * Playback: Wait all data was sent + * Capture: It might not receave data. Do nothing + */ + if (rsnd_io_is_play(io)) { + rsnd_mod_write(mod, SSICR, cr | ssi->cr_en); + rsnd_ssi_status_check(mod, DIRQ); + } + + /* In multi-SSI mode, stop is performed by setting ssi0129 in + * SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here. + */ + if (rsnd_ssi_multi_secondaries_runtime(io)) + return 0; + + /* + * disable SSI, + * and, wait idle state + */ + rsnd_mod_write(mod, SSICR, cr); /* disabled all */ + rsnd_ssi_status_check(mod, IIRQ); + + ssi->cr_en = 0; + + return 0; +} + +static int rsnd_ssi_irq(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv, + int enable) +{ + u32 val = 0; + int is_tdm, is_tdm_split; + int id = rsnd_mod_id(mod); + + is_tdm = rsnd_runtime_is_tdm(io); + is_tdm_split = rsnd_runtime_is_tdm_split(io); + + if (rsnd_is_gen1(priv)) + return 0; + + if (rsnd_ssi_is_parent(mod, io)) + return 0; + + if (!rsnd_ssi_is_run_mods(mod, io)) + return 0; + + if (enable) + val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000; + + if (is_tdm || is_tdm_split) { + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 9: + val |= 0x0000ff00; + break; + } + } + + rsnd_mod_write(mod, SSI_INT_ENABLE, val); + + return 0; +} + +static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io); +static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + int is_dma = rsnd_ssi_is_dma_mode(mod); + u32 status; + bool elapsed = false; + bool stop = false; + + spin_lock(&priv->lock); + + /* ignore all cases if not working */ + if (!rsnd_io_is_working(io)) + goto rsnd_ssi_interrupt_out; + + status = rsnd_ssi_status_get(mod); + + /* PIO only */ + if (!is_dma && (status & DIRQ)) + elapsed = rsnd_ssi_pio_interrupt(mod, io); + + /* DMA only */ + if (is_dma && (status & (UIRQ | OIRQ))) { + rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); + + stop = true; + } + + stop |= rsnd_ssiu_busif_err_status_clear(mod); + + rsnd_ssi_status_clear(mod); +rsnd_ssi_interrupt_out: + spin_unlock(&priv->lock); + + if (elapsed) + snd_pcm_period_elapsed(io->substream); + + if (stop) + snd_pcm_stop_xrun(io->substream); + +} + +static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) +{ + struct rsnd_mod *mod = data; + + rsnd_mod_interrupt(mod, __rsnd_ssi_interrupt); + + return IRQ_HANDLED; +} + +static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) +{ + /* + * SSIP (= SSI parent) needs to be special, otherwise, + * 2nd SSI might doesn't start. see also rsnd_mod_call() + * + * We can't include parent SSI status on SSI, because we don't know + * how many SSI requests parent SSI. Thus, it is localed on "io" now. + * ex) trouble case + * Playback: SSI0 + * Capture : SSI1 (needs SSI0) + * + * 1) start Capture -> SSI0/SSI1 are started. + * 2) start Playback -> SSI0 doesn't work, because it is already + * marked as "started" on 1) + * + * OTOH, using each mod's status is good for MUX case. + * It doesn't need to start in 2nd start + * ex) + * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 + * | + * IO-1: SRC1 -> CTU2 -+ + * + * 1) start IO-0 -> start SSI0 + * 2) start IO-1 -> SSI0 doesn't need to start, because it is + * already started on 1) + */ + if (type == RSND_MOD_SSIP) + return &io->parent_ssi_status; + + return rsnd_mod_get_status(mod, io, type); +} + +/* + * SSI PIO + */ +static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + + if (!__rsnd_ssi_is_pin_sharing(mod)) + return; + + if (!rsnd_rdai_is_clk_master(rdai)) + return; + + if (rsnd_ssi_is_multi_secondary(mod, io)) + return; + + switch (rsnd_mod_id(mod)) { + case 1: + case 2: + case 9: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP); + break; + case 4: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP); + break; + case 8: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP); + break; + } +} + +static int rsnd_ssi_pcm_new(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct snd_soc_pcm_runtime *rtd) +{ + /* + * rsnd_rdai_is_clk_master() will be enabled after set_fmt, + * and, pcm_new will be called after it. + * This function reuse pcm_new at this point. + */ + rsnd_ssi_parent_attach(mod, io); + + return 0; +} + +static int rsnd_ssi_common_probe(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + int ret = 0; + + /* + * SSIP/SSIU/IRQ are not needed on + * SSI Multi secondaries + */ + if (rsnd_ssi_is_multi_secondary(mod, io)) + return 0; + + /* + * It can't judge ssi parent at this point + * see rsnd_ssi_pcm_new() + */ + + /* + * SSI might be called again as PIO fallback + * It is easy to manual handling for IRQ request/free + * + * OTOH, this function might be called many times if platform is + * using MIX. It needs xxx_attach() many times on xxx_probe(). + * Because of it, we can't control .probe/.remove calling count by + * mod->status. + * But it don't need to call request_irq() many times. + * Let's control it by RSND_SSI_PROBED flag. + */ + if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) { + ret = request_irq(ssi->irq, + rsnd_ssi_interrupt, + IRQF_SHARED, + dev_name(dev), mod); + + rsnd_flags_set(ssi, RSND_SSI_PROBED); + } + + return ret; +} + +static int rsnd_ssi_common_remove(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io); + + /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ + if (pure_ssi_mod != mod) + return 0; + + /* PIO will request IRQ again */ + if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) { + free_irq(ssi->irq, mod); + + rsnd_flags_del(ssi, RSND_SSI_PROBED); + } + + return 0; +} + +/* + * SSI PIO functions + */ +static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos); + int shift = 0; + int byte_pos; + bool elapsed = false; + + if (snd_pcm_format_width(runtime->format) == 24) + shift = 8; + + /* + * 8/16/32 data can be assesse to TDR/RDR register + * directly as 32bit data + * see rsnd_ssi_init() + */ + if (rsnd_io_is_play(io)) + rsnd_mod_write(mod, SSITDR, (*buf) << shift); + else + *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); + + byte_pos = ssi->byte_pos + sizeof(*buf); + + if (byte_pos >= ssi->next_period_byte) { + int period_pos = byte_pos / ssi->byte_per_period; + + if (period_pos >= runtime->periods) { + byte_pos = 0; + period_pos = 0; + } + + ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; + + elapsed = true; + } + + WRITE_ONCE(ssi->byte_pos, byte_pos); + + return elapsed; +} + +static int rsnd_ssi_pio_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + if (!rsnd_ssi_is_parent(mod, io)) { + ssi->byte_pos = 0; + ssi->byte_per_period = runtime->period_size * + runtime->channels * + samples_to_bytes(runtime, 1); + ssi->next_period_byte = ssi->byte_per_period; + } + + return rsnd_ssi_init(mod, io, priv); +} + +static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + snd_pcm_uframes_t *pointer) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + + *pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos)); + + return 0; +} + +static struct rsnd_mod_ops rsnd_ssi_pio_ops = { + .name = SSI_NAME, + .probe = rsnd_ssi_common_probe, + .remove = rsnd_ssi_common_remove, + .init = rsnd_ssi_pio_init, + .quit = rsnd_ssi_quit, + .start = rsnd_ssi_start, + .stop = rsnd_ssi_stop, + .irq = rsnd_ssi_irq, + .pointer = rsnd_ssi_pio_pointer, + .pcm_new = rsnd_ssi_pcm_new, + .hw_params = rsnd_ssi_hw_params, + .get_status = rsnd_ssi_get_status, +}; + +static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + int ret; + + /* + * SSIP/SSIU/IRQ/DMA are not needed on + * SSI Multi secondaries + */ + if (rsnd_ssi_is_multi_secondary(mod, io)) + return 0; + + ret = rsnd_ssi_common_probe(mod, io, priv); + if (ret) + return ret; + + /* SSI probe might be called many times in MUX multi path */ + ret = rsnd_dma_attach(io, mod, &io->dma); + + return ret; +} + +static int rsnd_ssi_fallback(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + + /* + * fallback to PIO + * + * SSI .probe might be called again. + * see + * rsnd_rdai_continuance_probe() + */ + mod->ops = &rsnd_ssi_pio_ops; + + dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod)); + + return 0; +} + +static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + int is_play = rsnd_io_is_play(io); + char *name; + + /* + * It should use "rcar_sound,ssiu" on DT. + * But, we need to keep compatibility for old version. + * + * If it has "rcar_sound.ssiu", it will be used. + * If not, "rcar_sound.ssi" will be used. + * see + * rsnd_ssiu_dma_req() + * rsnd_dma_of_path() + */ + + if (rsnd_ssi_use_busif(io)) + name = is_play ? "rxu" : "txu"; + else + name = is_play ? "rx" : "tx"; + + return rsnd_dma_request_channel(rsnd_ssi_of_node(priv), + SSI_NAME, mod, name); +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_ssi_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + seq_printf(m, "clock: %s\n", rsnd_rdai_is_clk_master(rdai) ? + "provider" : "consumer"); + seq_printf(m, "bit_clk_inv: %d\n", rdai->bit_clk_inv); + seq_printf(m, "frm_clk_inv: %d\n", rdai->frm_clk_inv); + seq_printf(m, "pin share: %d\n", __rsnd_ssi_is_pin_sharing(mod)); + seq_printf(m, "can out clk: %d\n", rsnd_ssi_can_output_clk(mod)); + seq_printf(m, "multi secondary: %d\n", rsnd_ssi_is_multi_secondary(mod, io)); + seq_printf(m, "tdm: %d, %d\n", rsnd_runtime_is_tdm(io), + rsnd_runtime_is_tdm_split(io)); + seq_printf(m, "chan: %d\n", ssi->chan); + seq_printf(m, "user: %d\n", ssi->usrcnt); + + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSI, + rsnd_mod_id(mod) * 0x40, 0x40); +} +#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info +#else +#define DEBUG_INFO +#endif + +static struct rsnd_mod_ops rsnd_ssi_dma_ops = { + .name = SSI_NAME, + .dma_req = rsnd_ssi_dma_req, + .probe = rsnd_ssi_dma_probe, + .remove = rsnd_ssi_common_remove, + .init = rsnd_ssi_init, + .quit = rsnd_ssi_quit, + .start = rsnd_ssi_start, + .stop = rsnd_ssi_stop, + .irq = rsnd_ssi_irq, + .pcm_new = rsnd_ssi_pcm_new, + .fallback = rsnd_ssi_fallback, + .hw_params = rsnd_ssi_hw_params, + .get_status = rsnd_ssi_get_status, + DEBUG_INFO +}; + +int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) +{ + return mod->ops == &rsnd_ssi_dma_ops; +} + +/* + * ssi mod function + */ +static void rsnd_ssi_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + static const enum rsnd_mod_type types[] = { + RSND_MOD_SSI, + RSND_MOD_SSIM1, + RSND_MOD_SSIM2, + RSND_MOD_SSIM3, + }; + enum rsnd_mod_type type; + int i; + + /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */ + for (i = 0; i < ARRAY_SIZE(types); i++) { + type = types[i]; + if (!rsnd_io_to_mod(io, type)) { + rsnd_dai_connect(mod, io, type); + rsnd_rdai_channels_set(rdai, (i + 1) * 2); + rsnd_rdai_ssi_lane_set(rdai, (i + 1)); + return; + } + } +} + +void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *node; + struct device_node *np; + int i; + + node = rsnd_ssi_of_node(priv); + if (!node) + return; + + i = 0; + for_each_child_of_node(node, np) { + struct rsnd_mod *mod; + + i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); + if (i < 0) { + of_node_put(np); + break; + } + + mod = rsnd_ssi_mod_get(priv, i); + + if (np == playback) + rsnd_ssi_connect(mod, &rdai->playback); + if (np == capture) + rsnd_ssi_connect(mod, &rdai->capture); + i++; + } + + of_node_put(node); +} + +struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) + id = 0; + + return rsnd_mod_get(rsnd_ssi_get(priv, id)); +} + +int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) +{ + if (!mod) + return 0; + + return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE)); +} + +int rsnd_ssi_probe(struct rsnd_priv *priv) +{ + struct device_node *node; + struct device_node *np; + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod_ops *ops; + struct clk *clk; + struct rsnd_ssi *ssi; + char name[RSND_SSI_NAME_SIZE]; + int i, nr, ret; + + node = rsnd_ssi_of_node(priv); + if (!node) + return -EINVAL; + + nr = rsnd_node_count(priv, node, SSI_NAME); + if (!nr) { + ret = -EINVAL; + goto rsnd_ssi_probe_done; + } + + ssi = devm_kcalloc(dev, nr, sizeof(*ssi), GFP_KERNEL); + if (!ssi) { + ret = -ENOMEM; + goto rsnd_ssi_probe_done; + } + + priv->ssi = ssi; + priv->ssi_nr = nr; + + i = 0; + for_each_child_of_node(node, np) { + if (!of_device_is_available(np)) + goto skip; + + i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); + if (i < 0) { + ret = -EINVAL; + of_node_put(np); + goto rsnd_ssi_probe_done; + } + + ssi = rsnd_ssi_get(priv, i); + + snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", + SSI_NAME, i); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + of_node_put(np); + goto rsnd_ssi_probe_done; + } + + if (of_property_read_bool(np, "shared-pin")) + rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE); + + if (of_property_read_bool(np, "no-busif")) + rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF); + + ssi->irq = irq_of_parse_and_map(np, 0); + if (!ssi->irq) { + ret = -EINVAL; + of_node_put(np); + goto rsnd_ssi_probe_done; + } + + if (of_property_read_bool(np, "pio-transfer")) + ops = &rsnd_ssi_pio_ops; + else + ops = &rsnd_ssi_dma_ops; + + ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, + RSND_MOD_SSI, i); + if (ret) { + of_node_put(np); + goto rsnd_ssi_probe_done; + } +skip: + i++; + } + + ret = 0; + +rsnd_ssi_probe_done: + of_node_put(node); + + return ret; +} + +void rsnd_ssi_remove(struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi; + int i; + + for_each_rsnd_ssi(ssi, priv, i) { + rsnd_mod_quit(rsnd_mod_get(ssi)); + } +} diff --git a/sound/soc/renesas/rcar/ssiu.c b/sound/soc/renesas/rcar/ssiu.c new file mode 100644 index 00000000000000..665e8b2db579e3 --- /dev/null +++ b/sound/soc/renesas/rcar/ssiu.c @@ -0,0 +1,609 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas R-Car SSIU support +// +// Copyright (c) 2015 Kuninori Morimoto + +#include "rsnd.h" + +#define SSIU_NAME "ssiu" + +struct rsnd_ssiu { + struct rsnd_mod mod; + u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ + unsigned int usrcnt; + int id; + int id_sub; +}; + +/* SSI_MODE */ +#define TDM_EXT (1 << 0) +#define TDM_SPLIT (1 << 8) + +#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) +#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) +#define for_each_rsnd_ssiu(pos, priv, i) \ + for (i = 0; \ + (i < rsnd_ssiu_nr(priv)) && \ + ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ + i++) + +/* + * SSI Gen2 Gen3 Gen4 + * 0 BUSIF0-3 BUSIF0-7 BUSIF0-7 + * 1 BUSIF0-3 BUSIF0-7 + * 2 BUSIF0-3 BUSIF0-7 + * 3 BUSIF0 BUSIF0-7 + * 4 BUSIF0 BUSIF0-7 + * 5 BUSIF0 BUSIF0 + * 6 BUSIF0 BUSIF0 + * 7 BUSIF0 BUSIF0 + * 8 BUSIF0 BUSIF0 + * 9 BUSIF0-3 BUSIF0-7 + * total 22 52 8 + */ +static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; +static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; +static const int gen4_id[] = { 0 }; + +/* enable busif buffer over/under run interrupt. */ +#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1) +#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0) +static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable) +{ + int id = rsnd_mod_id(mod); + int shift, offset; + int i; + + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + shift = id; + offset = 0; + break; + case 9: + shift = 1; + offset = 1; + break; + default: + return; + } + + for (i = 0; i < 4; i++) { + enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset); + u32 val = 0xf << (shift * 4); + u32 sys_int_enable = rsnd_mod_read(mod, reg); + + if (enable) + sys_int_enable |= val; + else + sys_int_enable &= ~val; + rsnd_mod_write(mod, reg, sys_int_enable); + } +} + +bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod) +{ + bool error = false; + int id = rsnd_mod_id(mod); + int shift, offset; + int i; + + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + shift = id; + offset = 0; + break; + case 9: + shift = 1; + offset = 1; + break; + default: + goto out; + } + + for (i = 0; i < 4; i++) { + u32 reg = SSI_SYS_STATUS(i * 2) + offset; + u32 status = rsnd_mod_read(mod, reg); + u32 val = 0xf << (shift * 4); + + status &= val; + if (status) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); + error = true; + } + rsnd_mod_write(mod, reg, val); + } +out: + return error; +} + +static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + int busif = rsnd_mod_id_sub(mod); + + return &ssiu->busif_status[busif]; +} + +static int rsnd_ssiu_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + u32 ssis = rsnd_ssi_multi_secondaries_runtime(io); + int use_busif = rsnd_ssi_use_busif(io); + int id = rsnd_mod_id(mod); + int is_clk_master = rsnd_rdai_is_clk_master(rdai); + u32 val1, val2; + + /* clear status */ + rsnd_ssiu_busif_err_status_clear(mod); + + /* Gen4 doesn't have SSI_MODE */ + if (rsnd_is_gen4(priv)) + goto ssi_mode_setting_end; + + /* + * SSI_MODE0 + */ + rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id); + + /* + * SSI_MODE1 / SSI_MODE2 + * + * FIXME + * sharing/multi with SSI0 are mainly supported + */ + val1 = rsnd_mod_read(mod, SSI_MODE1); + val2 = rsnd_mod_read(mod, SSI_MODE2); + if (rsnd_ssi_is_pin_sharing(io)) { + + ssis |= (1 << id); + + } else if (ssis) { + /* + * Multi SSI + * + * set synchronized bit here + */ + + /* SSI4 is synchronized with SSI3 */ + if (ssis & (1 << 4)) + val1 |= (1 << 20); + /* SSI012 are synchronized */ + if (ssis == 0x0006) + val1 |= (1 << 4); + /* SSI0129 are synchronized */ + if (ssis == 0x0206) + val2 |= (1 << 4); + } + + /* SSI1 is sharing pin with SSI0 */ + if (ssis & (1 << 1)) + val1 |= is_clk_master ? 0x2 : 0x1; + + /* SSI2 is sharing pin with SSI0 */ + if (ssis & (1 << 2)) + val1 |= is_clk_master ? 0x2 << 2 : + 0x1 << 2; + /* SSI4 is sharing pin with SSI3 */ + if (ssis & (1 << 4)) + val1 |= is_clk_master ? 0x2 << 16 : + 0x1 << 16; + /* SSI9 is sharing pin with SSI0 */ + if (ssis & (1 << 9)) + val2 |= is_clk_master ? 0x2 : 0x1; + + rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1); + rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2); + +ssi_mode_setting_end: + /* + * Enable busif buffer over/under run interrupt. + * It will be handled from ssi.c + * see + * __rsnd_ssi_interrupt() + */ + rsnd_ssiu_busif_err_irq_enable(mod); + + return 0; +} + +static int rsnd_ssiu_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + /* disable busif buffer over/under run interrupt. */ + rsnd_ssiu_busif_err_irq_disable(mod); + + return 0; +} + +static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { + .name = SSIU_NAME, + .init = rsnd_ssiu_init, + .quit = rsnd_ssiu_quit, + .get_status = rsnd_ssiu_get_status, +}; + +static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0); + u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1); + int ret; + u32 mode = 0; + + ret = rsnd_ssiu_init(mod, io, priv); + if (ret < 0) + return ret; + + ssiu->usrcnt++; + + /* + * TDM Extend/Split Mode + * see + * rsnd_ssi_config_init() + */ + if (rsnd_runtime_is_tdm(io)) + mode = TDM_EXT; + else if (rsnd_runtime_is_tdm_split(io)) + mode = TDM_SPLIT; + + rsnd_mod_write(mod, SSI_MODE, mode); + + if (rsnd_ssi_use_busif(io)) { + int id = rsnd_mod_id(mod); + int busif = rsnd_mod_id_sub(mod); + enum rsnd_reg adinr_reg, mode_reg, dalign_reg; + + if ((id == 9) && (busif >= 4)) { + adinr_reg = SSI9_BUSIF_ADINR(busif); + mode_reg = SSI9_BUSIF_MODE(busif); + dalign_reg = SSI9_BUSIF_DALIGN(busif); + } else { + adinr_reg = SSI_BUSIF_ADINR(busif); + mode_reg = SSI_BUSIF_MODE(busif); + dalign_reg = SSI_BUSIF_DALIGN(busif); + } + + rsnd_mod_write(mod, adinr_reg, + rsnd_get_adinr_bit(mod, io) | + (rsnd_io_is_play(io) ? + rsnd_runtime_channel_after_ctu(io) : + rsnd_runtime_channel_original(io))); + rsnd_mod_write(mod, mode_reg, + rsnd_get_busif_shift(io, mod) | 1); + rsnd_mod_write(mod, dalign_reg, + rsnd_get_dalign(mod, io)); + } + + if (has_hdmi0 || has_hdmi1) { + enum rsnd_mod_type rsnd_ssi_array[] = { + RSND_MOD_SSIM1, + RSND_MOD_SSIM2, + RSND_MOD_SSIM3, + }; + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *pos; + u32 val; + int i; + + i = rsnd_mod_id(ssi_mod); + + /* output all same SSI as default */ + val = i << 16 | + i << 20 | + i << 24 | + i << 28 | + i; + + for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) { + int shift = (i * 4) + 20; + + val = (val & ~(0xF << shift)) | + rsnd_mod_id(pos) << shift; + } + + if (has_hdmi0) + rsnd_mod_write(mod, HDMI0_SEL, val); + if (has_hdmi1) + rsnd_mod_write(mod, HDMI1_SEL, val); + } + + return 0; +} + +static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + int busif = rsnd_mod_id_sub(mod); + + if (!rsnd_ssi_use_busif(io)) + return 0; + + rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4)); + + if (rsnd_ssi_multi_secondaries_runtime(io)) + rsnd_mod_write(mod, SSI_CONTROL, 0x1); + + return 0; +} + +static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + int busif = rsnd_mod_id_sub(mod); + + if (!rsnd_ssi_use_busif(io)) + return 0; + + rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); + + if (--ssiu->usrcnt) + return 0; + + if (rsnd_ssi_multi_secondaries_runtime(io)) + rsnd_mod_write(mod, SSI_CONTROL, 0); + + return 0; +} + +static int rsnd_ssiu_id(struct rsnd_mod *mod) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + + /* see rsnd_ssiu_probe() */ + return ssiu->id; +} + +static int rsnd_ssiu_id_sub(struct rsnd_mod *mod) +{ + struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); + + /* see rsnd_ssiu_probe() */ + return ssiu->id_sub; +} + +static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + int is_play = rsnd_io_is_play(io); + char *name; + + /* + * It should use "rcar_sound,ssiu" on DT. + * But, we need to keep compatibility for old version. + * + * If it has "rcar_sound.ssiu", it will be used. + * If not, "rcar_sound.ssi" will be used. + * see + * rsnd_ssi_dma_req() + * rsnd_dma_of_path() + */ + + name = is_play ? "rx" : "tx"; + + return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv), + SSIU_NAME, mod, name); +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_ssiu_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSIU, + rsnd_mod_id(mod) * 0x80, 0x80); +} +#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info +#else +#define DEBUG_INFO +#endif + +static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { + .name = SSIU_NAME, + .dma_req = rsnd_ssiu_dma_req, + .init = rsnd_ssiu_init_gen2, + .quit = rsnd_ssiu_quit, + .start = rsnd_ssiu_start_gen2, + .stop = rsnd_ssiu_stop_gen2, + .get_status = rsnd_ssiu_get_status, + DEBUG_INFO +}; + +static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv))) + id = 0; + + return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); +} + +static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, + struct rsnd_dai_stream *io) +{ + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_ssiu *ssiu; + int is_dma_mode; + int i; + + if (!ssi_mod) + return; + + is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod); + + /* select BUSIF0 */ + for_each_rsnd_ssiu(ssiu, priv, i) { + struct rsnd_mod *mod = rsnd_mod_get(ssiu); + + if (is_dma_mode && + (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && + (rsnd_mod_id_sub(mod) == 0)) { + rsnd_dai_connect(mod, io, mod->type); + return; + } + } +} + +void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *node = rsnd_ssiu_of_node(priv); + struct rsnd_dai_stream *io_p = &rdai->playback; + struct rsnd_dai_stream *io_c = &rdai->capture; + + /* use rcar_sound,ssiu if exist */ + if (node) { + struct device_node *np; + int i = 0; + + for_each_child_of_node(node, np) { + struct rsnd_mod *mod; + + i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i); + if (i < 0) { + of_node_put(np); + break; + } + + mod = rsnd_ssiu_mod_get(priv, i); + + if (np == playback) + rsnd_dai_connect(mod, io_p, mod->type); + if (np == capture) + rsnd_dai_connect(mod, io_c, mod->type); + i++; + } + + of_node_put(node); + } + + /* Keep DT compatibility */ + if (!rsnd_io_to_mod_ssiu(io_p)) + rsnd_parse_connect_ssiu_compatible(priv, io_p); + if (!rsnd_io_to_mod_ssiu(io_c)) + rsnd_parse_connect_ssiu_compatible(priv, io_c); +} + +int rsnd_ssiu_probe(struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct device_node *node; + struct rsnd_ssiu *ssiu; + struct rsnd_mod_ops *ops; + const int *list = NULL; + int i, nr; + + /* + * Keep DT compatibility. + * if it has "rcar_sound,ssiu", use it. + * if not, use "rcar_sound,ssi" + * see + * rsnd_ssiu_bufsif_to_id() + */ + node = rsnd_ssiu_of_node(priv); + if (node) + nr = rsnd_node_count(priv, node, SSIU_NAME); + else + nr = priv->ssi_nr; + + if (!nr) + return -EINVAL; + + ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); + if (!ssiu) + return -ENOMEM; + + priv->ssiu = ssiu; + priv->ssiu_nr = nr; + + if (rsnd_is_gen1(priv)) + ops = &rsnd_ssiu_ops_gen1; + else + ops = &rsnd_ssiu_ops_gen2; + + /* Keep compatibility */ + nr = 0; + if ((node) && + (ops == &rsnd_ssiu_ops_gen2)) { + ops->id = rsnd_ssiu_id; + ops->id_sub = rsnd_ssiu_id_sub; + + if (rsnd_is_gen2(priv)) { + list = gen2_id; + nr = ARRAY_SIZE(gen2_id); + } else if (rsnd_is_gen3(priv)) { + list = gen3_id; + nr = ARRAY_SIZE(gen3_id); + } else if (rsnd_is_gen4(priv)) { + list = gen4_id; + nr = ARRAY_SIZE(gen4_id); + } else { + dev_err(dev, "unknown SSIU\n"); + return -ENODEV; + } + } + + for_each_rsnd_ssiu(ssiu, priv, i) { + int ret; + + if (node) { + int j; + + /* + * see + * rsnd_ssiu_get_id() + * rsnd_ssiu_get_id_sub() + */ + for (j = 0; j < nr; j++) { + if (list[j] > i) + break; + ssiu->id = j; + ssiu->id_sub = i - list[ssiu->id]; + } + } else { + ssiu->id = i; + } + + ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), + ops, NULL, RSND_MOD_SSIU, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_ssiu_remove(struct rsnd_priv *priv) +{ + struct rsnd_ssiu *ssiu; + int i; + + for_each_rsnd_ssiu(ssiu, priv, i) { + rsnd_mod_quit(rsnd_mod_get(ssiu)); + } +} diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c new file mode 100644 index 00000000000000..6efd017aaa7fce --- /dev/null +++ b/sound/soc/renesas/rz-ssi.c @@ -0,0 +1,1212 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Renesas RZ/G2L ASoC Serial Sound Interface (SSIF-2) Driver +// +// Copyright (C) 2021 Renesas Electronics Corp. +// Copyright (C) 2019 Chris Brandt. +// + +#include +#include +#include +#include +#include +#include +#include + +/* REGISTER OFFSET */ +#define SSICR 0x000 +#define SSISR 0x004 +#define SSIFCR 0x010 +#define SSIFSR 0x014 +#define SSIFTDR 0x018 +#define SSIFRDR 0x01c +#define SSIOFR 0x020 +#define SSISCR 0x024 + +/* SSI REGISTER BITS */ +#define SSICR_DWL(x) (((x) & 0x7) << 19) +#define SSICR_SWL(x) (((x) & 0x7) << 16) + +#define SSICR_CKS BIT(30) +#define SSICR_TUIEN BIT(29) +#define SSICR_TOIEN BIT(28) +#define SSICR_RUIEN BIT(27) +#define SSICR_ROIEN BIT(26) +#define SSICR_MST BIT(14) +#define SSICR_BCKP BIT(13) +#define SSICR_LRCKP BIT(12) +#define SSICR_CKDV(x) (((x) & 0xf) << 4) +#define SSICR_TEN BIT(1) +#define SSICR_REN BIT(0) + +#define SSISR_TUIRQ BIT(29) +#define SSISR_TOIRQ BIT(28) +#define SSISR_RUIRQ BIT(27) +#define SSISR_ROIRQ BIT(26) +#define SSISR_IIRQ BIT(25) + +#define SSIFCR_AUCKE BIT(31) +#define SSIFCR_SSIRST BIT(16) +#define SSIFCR_TIE BIT(3) +#define SSIFCR_RIE BIT(2) +#define SSIFCR_TFRST BIT(1) +#define SSIFCR_RFRST BIT(0) +#define SSIFCR_FIFO_RST (SSIFCR_TFRST | SSIFCR_RFRST) + +#define SSIFSR_TDC_MASK 0x3f +#define SSIFSR_TDC_SHIFT 24 +#define SSIFSR_RDC_MASK 0x3f +#define SSIFSR_RDC_SHIFT 8 + +#define SSIFSR_TDE BIT(16) +#define SSIFSR_RDF BIT(0) + +#define SSIOFR_LRCONT BIT(8) + +#define SSISCR_TDES(x) (((x) & 0x1f) << 8) +#define SSISCR_RDFS(x) (((x) & 0x1f) << 0) + +/* Pre allocated buffers sizes */ +#define PREALLOC_BUFFER (SZ_32K) +#define PREALLOC_BUFFER_MAX (SZ_32K) + +#define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-44.1kHz */ +#define SSI_FMTS SNDRV_PCM_FMTBIT_S16_LE +#define SSI_CHAN_MIN 2 +#define SSI_CHAN_MAX 2 +#define SSI_FIFO_DEPTH 32 + +struct rz_ssi_priv; + +struct rz_ssi_stream { + struct rz_ssi_priv *priv; + struct snd_pcm_substream *substream; + int fifo_sample_size; /* sample capacity of SSI FIFO */ + int dma_buffer_pos; /* The address for the next DMA descriptor */ + int period_counter; /* for keeping track of periods transferred */ + int sample_width; + int buffer_pos; /* current frame position in the buffer */ + int running; /* 0=stopped, 1=running */ + + int uerr_num; + int oerr_num; + + struct dma_chan *dma_ch; + + int (*transfer)(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm); +}; + +struct rz_ssi_priv { + void __iomem *base; + struct platform_device *pdev; + struct reset_control *rstc; + struct device *dev; + struct clk *sfr_clk; + struct clk *clk; + + phys_addr_t phys; + int irq_int; + int irq_tx; + int irq_rx; + int irq_rt; + + spinlock_t lock; + + /* + * The SSI supports full-duplex transmission and reception. + * However, if an error occurs, channel reset (both transmission + * and reception reset) is required. + * So it is better to use as half-duplex (playing and recording + * should be done on separate channels). + */ + struct rz_ssi_stream playback; + struct rz_ssi_stream capture; + + /* clock */ + unsigned long audio_mck; + unsigned long audio_clk_1; + unsigned long audio_clk_2; + + bool lrckp_fsync_fall; /* LR clock polarity (SSICR.LRCKP) */ + bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */ + bool dma_rt; + + /* Full duplex communication support */ + struct { + unsigned int rate; + unsigned int channels; + unsigned int sample_width; + unsigned int sample_bits; + } hw_params_cache; +}; + +static void rz_ssi_dma_complete(void *data); + +static void rz_ssi_reg_writel(struct rz_ssi_priv *priv, uint reg, u32 data) +{ + writel(data, (priv->base + reg)); +} + +static u32 rz_ssi_reg_readl(struct rz_ssi_priv *priv, uint reg) +{ + return readl(priv->base + reg); +} + +static void rz_ssi_reg_mask_setl(struct rz_ssi_priv *priv, uint reg, + u32 bclr, u32 bset) +{ + u32 val; + + val = readl(priv->base + reg); + val = (val & ~bclr) | bset; + writel(val, (priv->base + reg)); +} + +static inline struct snd_soc_dai * +rz_ssi_get_dai(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + + return snd_soc_rtd_to_cpu(rtd, 0); +} + +static inline bool rz_ssi_stream_is_play(struct rz_ssi_priv *ssi, + struct snd_pcm_substream *substream) +{ + return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; +} + +static inline struct rz_ssi_stream * +rz_ssi_stream_get(struct rz_ssi_priv *ssi, struct snd_pcm_substream *substream) +{ + struct rz_ssi_stream *stream = &ssi->playback; + + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + stream = &ssi->capture; + + return stream; +} + +static inline bool rz_ssi_is_dma_enabled(struct rz_ssi_priv *ssi) +{ + return (ssi->playback.dma_ch && (ssi->dma_rt || ssi->capture.dma_ch)); +} + +static void rz_ssi_set_substream(struct rz_ssi_stream *strm, + struct snd_pcm_substream *substream) +{ + struct rz_ssi_priv *ssi = strm->priv; + unsigned long flags; + + spin_lock_irqsave(&ssi->lock, flags); + strm->substream = substream; + spin_unlock_irqrestore(&ssi->lock, flags); +} + +static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi, + struct rz_ssi_stream *strm) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&ssi->lock, flags); + ret = strm->substream && strm->substream->runtime; + spin_unlock_irqrestore(&ssi->lock, flags); + + return ret; +} + +static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm) +{ + return strm->substream && strm->running; +} + +static void rz_ssi_stream_init(struct rz_ssi_stream *strm, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + rz_ssi_set_substream(strm, substream); + strm->sample_width = samples_to_bytes(runtime, 1); + strm->dma_buffer_pos = 0; + strm->period_counter = 0; + strm->buffer_pos = 0; + + strm->oerr_num = 0; + strm->uerr_num = 0; + strm->running = 0; + + /* fifo init */ + strm->fifo_sample_size = SSI_FIFO_DEPTH; +} + +static void rz_ssi_stream_quit(struct rz_ssi_priv *ssi, + struct rz_ssi_stream *strm) +{ + struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream); + + rz_ssi_set_substream(strm, NULL); + + if (strm->oerr_num > 0) + dev_info(dai->dev, "overrun = %d\n", strm->oerr_num); + + if (strm->uerr_num > 0) + dev_info(dai->dev, "underrun = %d\n", strm->uerr_num); +} + +static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, + unsigned int channels) +{ + static s8 ckdv[16] = { 1, 2, 4, 8, 16, 32, 64, 128, + 6, 12, 24, 48, 96, -1, -1, -1 }; + unsigned int channel_bits = 32; /* System Word Length */ + unsigned long bclk_rate = rate * channels * channel_bits; + unsigned int div; + unsigned int i; + u32 ssicr = 0; + u32 clk_ckdv; + + /* Clear AUCKE so we can set MST */ + rz_ssi_reg_writel(ssi, SSIFCR, 0); + + /* Continue to output LRCK pin even when idle */ + rz_ssi_reg_writel(ssi, SSIOFR, SSIOFR_LRCONT); + if (ssi->audio_clk_1 && ssi->audio_clk_2) { + if (ssi->audio_clk_1 % bclk_rate) + ssi->audio_mck = ssi->audio_clk_2; + else + ssi->audio_mck = ssi->audio_clk_1; + } + + /* Clock setting */ + ssicr |= SSICR_MST; + if (ssi->audio_mck == ssi->audio_clk_1) + ssicr |= SSICR_CKS; + if (ssi->bckp_rise) + ssicr |= SSICR_BCKP; + if (ssi->lrckp_fsync_fall) + ssicr |= SSICR_LRCKP; + + /* Determine the clock divider */ + clk_ckdv = 0; + div = ssi->audio_mck / bclk_rate; + /* try to find an match */ + for (i = 0; i < ARRAY_SIZE(ckdv); i++) { + if (ckdv[i] == div) { + clk_ckdv = i; + break; + } + } + + if (i == ARRAY_SIZE(ckdv)) { + dev_err(ssi->dev, "Rate not divisible by audio clock source\n"); + return -EINVAL; + } + + /* + * DWL: Data Word Length = 16 bits + * SWL: System Word Length = 32 bits + */ + ssicr |= SSICR_CKDV(clk_ckdv); + ssicr |= SSICR_DWL(1) | SSICR_SWL(3); + rz_ssi_reg_writel(ssi, SSICR, ssicr); + rz_ssi_reg_writel(ssi, SSIFCR, SSIFCR_AUCKE | SSIFCR_FIFO_RST); + + return 0; +} + +static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) +{ + int timeout; + + /* Disable irqs */ + rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN | + SSICR_RUIEN | SSICR_ROIEN, 0); + rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0); + + /* Clear all error flags */ + rz_ssi_reg_mask_setl(ssi, SSISR, + (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | + SSISR_RUIRQ), 0); + + /* Wait for idle */ + timeout = 100; + while (--timeout) { + if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ) + break; + udelay(1); + } + + if (!timeout) + dev_info(ssi->dev, "timeout waiting for SSI idle\n"); + + /* Hold FIFOs in reset */ + rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_FIFO_RST); +} + +static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) +{ + bool is_play = rz_ssi_stream_is_play(ssi, strm->substream); + bool is_full_duplex; + u32 ssicr, ssifcr; + + is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture); + ssicr = rz_ssi_reg_readl(ssi, SSICR); + ssifcr = rz_ssi_reg_readl(ssi, SSIFCR); + if (!is_full_duplex) { + ssifcr &= ~0xF; + } else { + rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); + rz_ssi_set_idle(ssi); + ssifcr &= ~SSIFCR_FIFO_RST; + } + + /* FIFO interrupt thresholds */ + if (rz_ssi_is_dma_enabled(ssi)) + rz_ssi_reg_writel(ssi, SSISCR, 0); + else + rz_ssi_reg_writel(ssi, SSISCR, + SSISCR_TDES(strm->fifo_sample_size / 2 - 1) | + SSISCR_RDFS(0)); + + /* enable IRQ */ + if (is_play) { + ssicr |= SSICR_TUIEN | SSICR_TOIEN; + ssifcr |= SSIFCR_TIE; + if (!is_full_duplex) + ssifcr |= SSIFCR_RFRST; + } else { + ssicr |= SSICR_RUIEN | SSICR_ROIEN; + ssifcr |= SSIFCR_RIE; + if (!is_full_duplex) + ssifcr |= SSIFCR_TFRST; + } + + rz_ssi_reg_writel(ssi, SSICR, ssicr); + rz_ssi_reg_writel(ssi, SSIFCR, ssifcr); + + /* Clear all error flags */ + rz_ssi_reg_mask_setl(ssi, SSISR, + (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | + SSISR_RUIRQ), 0); + + strm->running = 1; + if (is_full_duplex) + ssicr |= SSICR_TEN | SSICR_REN; + else + ssicr |= is_play ? SSICR_TEN : SSICR_REN; + + rz_ssi_reg_writel(ssi, SSICR, ssicr); + + return 0; +} + +static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) +{ + strm->running = 0; + + if (rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture)) + return 0; + + /* Disable TX/RX */ + rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); + + /* Cancel all remaining DMA transactions */ + if (rz_ssi_is_dma_enabled(ssi)) + dmaengine_terminate_async(strm->dma_ch); + + rz_ssi_set_idle(ssi); + + return 0; +} + +static void rz_ssi_pointer_update(struct rz_ssi_stream *strm, int frames) +{ + struct snd_pcm_substream *substream = strm->substream; + struct snd_pcm_runtime *runtime; + int current_period; + + if (!strm->running || !substream || !substream->runtime) + return; + + runtime = substream->runtime; + strm->buffer_pos += frames; + WARN_ON(strm->buffer_pos > runtime->buffer_size); + + /* ring buffer */ + if (strm->buffer_pos == runtime->buffer_size) + strm->buffer_pos = 0; + + current_period = strm->buffer_pos / runtime->period_size; + if (strm->period_counter != current_period) { + snd_pcm_period_elapsed(strm->substream); + strm->period_counter = current_period; + } +} + +static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) +{ + struct snd_pcm_substream *substream = strm->substream; + struct snd_pcm_runtime *runtime; + u16 *buf; + int fifo_samples; + int frames_left; + int samples; + int i; + + if (!rz_ssi_stream_is_valid(ssi, strm)) + return -EINVAL; + + runtime = substream->runtime; + + do { + /* frames left in this period */ + frames_left = runtime->period_size - + (strm->buffer_pos % runtime->period_size); + if (!frames_left) + frames_left = runtime->period_size; + + /* Samples in RX FIFO */ + fifo_samples = (rz_ssi_reg_readl(ssi, SSIFSR) >> + SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK; + + /* Only read full frames at a time */ + samples = 0; + while (frames_left && (fifo_samples >= runtime->channels)) { + samples += runtime->channels; + fifo_samples -= runtime->channels; + frames_left--; + } + + /* not enough samples yet */ + if (!samples) + break; + + /* calculate new buffer index */ + buf = (u16 *)runtime->dma_area; + buf += strm->buffer_pos * runtime->channels; + + /* Note, only supports 16-bit samples */ + for (i = 0; i < samples; i++) + *buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16); + + rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); + rz_ssi_pointer_update(strm, samples / runtime->channels); + } while (!frames_left && fifo_samples >= runtime->channels); + + return 0; +} + +static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) +{ + struct snd_pcm_substream *substream = strm->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + int sample_space; + int samples = 0; + int frames_left; + int i; + u32 ssifsr; + u16 *buf; + + if (!rz_ssi_stream_is_valid(ssi, strm)) + return -EINVAL; + + /* frames left in this period */ + frames_left = runtime->period_size - (strm->buffer_pos % + runtime->period_size); + if (frames_left == 0) + frames_left = runtime->period_size; + + sample_space = strm->fifo_sample_size; + ssifsr = rz_ssi_reg_readl(ssi, SSIFSR); + sample_space -= (ssifsr >> SSIFSR_TDC_SHIFT) & SSIFSR_TDC_MASK; + + /* Only add full frames at a time */ + while (frames_left && (sample_space >= runtime->channels)) { + samples += runtime->channels; + sample_space -= runtime->channels; + frames_left--; + } + + /* no space to send anything right now */ + if (samples == 0) + return 0; + + /* calculate new buffer index */ + buf = (u16 *)(runtime->dma_area); + buf += strm->buffer_pos * runtime->channels; + + /* Note, only supports 16-bit samples */ + for (i = 0; i < samples; i++) + rz_ssi_reg_writel(ssi, SSIFTDR, ((u32)(*buf++) << 16)); + + rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_TDE, 0); + rz_ssi_pointer_update(strm, samples / runtime->channels); + + return 0; +} + +static irqreturn_t rz_ssi_interrupt(int irq, void *data) +{ + struct rz_ssi_stream *strm_playback = NULL; + struct rz_ssi_stream *strm_capture = NULL; + struct rz_ssi_priv *ssi = data; + u32 ssisr = rz_ssi_reg_readl(ssi, SSISR); + + if (ssi->playback.substream) + strm_playback = &ssi->playback; + if (ssi->capture.substream) + strm_capture = &ssi->capture; + + if (!strm_playback && !strm_capture) + return IRQ_HANDLED; /* Left over TX/RX interrupt */ + + if (irq == ssi->irq_int) { /* error or idle */ + bool is_stopped = false; + int i, count; + + if (rz_ssi_is_dma_enabled(ssi)) + count = 4; + else + count = 1; + + if (ssisr & (SSISR_RUIRQ | SSISR_ROIRQ | SSISR_TUIRQ | SSISR_TOIRQ)) + is_stopped = true; + + if (ssi->capture.substream && is_stopped) { + if (ssisr & SSISR_RUIRQ) + strm_capture->uerr_num++; + if (ssisr & SSISR_ROIRQ) + strm_capture->oerr_num++; + + rz_ssi_stop(ssi, strm_capture); + } + + if (ssi->playback.substream && is_stopped) { + if (ssisr & SSISR_TUIRQ) + strm_playback->uerr_num++; + if (ssisr & SSISR_TOIRQ) + strm_playback->oerr_num++; + + rz_ssi_stop(ssi, strm_playback); + } + + /* Clear all flags */ + rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | SSISR_TUIRQ | + SSISR_ROIRQ | SSISR_RUIRQ, 0); + + /* Add/remove more data */ + if (ssi->capture.substream && is_stopped) { + for (i = 0; i < count; i++) + strm_capture->transfer(ssi, strm_capture); + } + + if (ssi->playback.substream && is_stopped) { + for (i = 0; i < count; i++) + strm_playback->transfer(ssi, strm_playback); + } + + /* Resume */ + if (ssi->playback.substream && is_stopped) + rz_ssi_start(ssi, &ssi->playback); + if (ssi->capture.substream && is_stopped) + rz_ssi_start(ssi, &ssi->capture); + } + + if (!rz_ssi_is_stream_running(&ssi->playback) && + !rz_ssi_is_stream_running(&ssi->capture)) + return IRQ_HANDLED; + + /* tx data empty */ + if (irq == ssi->irq_tx && rz_ssi_is_stream_running(&ssi->playback)) + strm_playback->transfer(ssi, &ssi->playback); + + /* rx data full */ + if (irq == ssi->irq_rx && rz_ssi_is_stream_running(&ssi->capture)) { + strm_capture->transfer(ssi, &ssi->capture); + rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); + } + + if (irq == ssi->irq_rt) { + if (ssi->playback.substream) { + strm_playback->transfer(ssi, &ssi->playback); + } else { + strm_capture->transfer(ssi, &ssi->capture); + rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); + } + } + + return IRQ_HANDLED; +} + +static int rz_ssi_dma_slave_config(struct rz_ssi_priv *ssi, + struct dma_chan *dma_ch, bool is_play) +{ + struct dma_slave_config cfg; + + memset(&cfg, 0, sizeof(cfg)); + + cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + cfg.dst_addr = ssi->phys + SSIFTDR; + cfg.src_addr = ssi->phys + SSIFRDR; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + + return dmaengine_slave_config(dma_ch, &cfg); +} + +static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi, + struct rz_ssi_stream *strm) +{ + struct snd_pcm_substream *substream = strm->substream; + struct dma_async_tx_descriptor *desc; + struct snd_pcm_runtime *runtime; + enum dma_transfer_direction dir; + u32 dma_paddr, dma_size; + int amount; + + if (!rz_ssi_stream_is_valid(ssi, strm)) + return -EINVAL; + + runtime = substream->runtime; + if (runtime->state == SNDRV_PCM_STATE_DRAINING) + /* + * Stream is ending, so do not queue up any more DMA + * transfers otherwise we play partial sound clips + * because we can't shut off the DMA quick enough. + */ + return 0; + + dir = rz_ssi_stream_is_play(ssi, substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + + /* Always transfer 1 period */ + amount = runtime->period_size; + + /* DMA physical address and size */ + dma_paddr = runtime->dma_addr + frames_to_bytes(runtime, + strm->dma_buffer_pos); + dma_size = frames_to_bytes(runtime, amount); + desc = dmaengine_prep_slave_single(strm->dma_ch, dma_paddr, dma_size, + dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(ssi->dev, "dmaengine_prep_slave_single() fail\n"); + return -ENOMEM; + } + + desc->callback = rz_ssi_dma_complete; + desc->callback_param = strm; + + if (dmaengine_submit(desc) < 0) { + dev_err(ssi->dev, "dmaengine_submit() fail\n"); + return -EIO; + } + + /* Update DMA pointer */ + strm->dma_buffer_pos += amount; + if (strm->dma_buffer_pos >= runtime->buffer_size) + strm->dma_buffer_pos = 0; + + /* Start DMA */ + dma_async_issue_pending(strm->dma_ch); + + return 0; +} + +static void rz_ssi_dma_complete(void *data) +{ + struct rz_ssi_stream *strm = (struct rz_ssi_stream *)data; + + if (!strm->running || !strm->substream || !strm->substream->runtime) + return; + + /* Note that next DMA transaction has probably already started */ + rz_ssi_pointer_update(strm, strm->substream->runtime->period_size); + + /* Queue up another DMA transaction */ + rz_ssi_dma_transfer(strm->priv, strm); +} + +static void rz_ssi_release_dma_channels(struct rz_ssi_priv *ssi) +{ + if (ssi->playback.dma_ch) { + dma_release_channel(ssi->playback.dma_ch); + ssi->playback.dma_ch = NULL; + if (ssi->dma_rt) + ssi->dma_rt = false; + } + + if (ssi->capture.dma_ch) { + dma_release_channel(ssi->capture.dma_ch); + ssi->capture.dma_ch = NULL; + } +} + +static int rz_ssi_dma_request(struct rz_ssi_priv *ssi, struct device *dev) +{ + ssi->playback.dma_ch = dma_request_chan(dev, "tx"); + if (IS_ERR(ssi->playback.dma_ch)) + ssi->playback.dma_ch = NULL; + + ssi->capture.dma_ch = dma_request_chan(dev, "rx"); + if (IS_ERR(ssi->capture.dma_ch)) + ssi->capture.dma_ch = NULL; + + if (!ssi->playback.dma_ch && !ssi->capture.dma_ch) { + ssi->playback.dma_ch = dma_request_chan(dev, "rt"); + if (IS_ERR(ssi->playback.dma_ch)) { + ssi->playback.dma_ch = NULL; + goto no_dma; + } + + ssi->dma_rt = true; + } + + if (!rz_ssi_is_dma_enabled(ssi)) + goto no_dma; + + if (ssi->playback.dma_ch && + (rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, true) < 0)) + goto no_dma; + + if (ssi->capture.dma_ch && + (rz_ssi_dma_slave_config(ssi, ssi->capture.dma_ch, false) < 0)) + goto no_dma; + + return 0; + +no_dma: + rz_ssi_release_dma_channels(ssi); + + return -ENODEV; +} + +static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); + struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); + int ret = 0, i, num_transfer = 1; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* Soft Reset */ + if (!rz_ssi_is_stream_running(&ssi->playback) && + !rz_ssi_is_stream_running(&ssi->capture)) { + rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); + rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); + udelay(5); + } + + rz_ssi_stream_init(strm, substream); + + if (ssi->dma_rt) { + bool is_playback; + + is_playback = rz_ssi_stream_is_play(ssi, substream); + ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, + is_playback); + /* Fallback to pio */ + if (ret < 0) { + ssi->playback.transfer = rz_ssi_pio_send; + ssi->capture.transfer = rz_ssi_pio_recv; + rz_ssi_release_dma_channels(ssi); + } + } + + /* For DMA, queue up multiple DMA descriptors */ + if (rz_ssi_is_dma_enabled(ssi)) + num_transfer = 4; + + for (i = 0; i < num_transfer; i++) { + ret = strm->transfer(ssi, strm); + if (ret) + goto done; + } + + ret = rz_ssi_start(ssi, strm); + break; + case SNDRV_PCM_TRIGGER_STOP: + rz_ssi_stop(ssi, strm); + rz_ssi_stream_quit(ssi, strm); + break; + } + +done: + return ret; +} + +static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BP_FP: + break; + default: + dev_err(ssi->dev, "Codec should be clk and frame consumer\n"); + return -EINVAL; + } + + /* + * set clock polarity + * + * "normal" BCLK = Signal is available at rising edge of BCLK + * "normal" FSYNC = (I2S) Left ch starts with falling FSYNC edge + */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + ssi->bckp_rise = false; + ssi->lrckp_fsync_fall = false; + break; + case SND_SOC_DAIFMT_NB_IF: + ssi->bckp_rise = false; + ssi->lrckp_fsync_fall = true; + break; + case SND_SOC_DAIFMT_IB_NF: + ssi->bckp_rise = true; + ssi->lrckp_fsync_fall = false; + break; + case SND_SOC_DAIFMT_IB_IF: + ssi->bckp_rise = true; + ssi->lrckp_fsync_fall = true; + break; + default: + return -EINVAL; + } + + /* only i2s support */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + default: + dev_err(ssi->dev, "Only I2S mode is supported.\n"); + return -EINVAL; + } + + return 0; +} + +static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, + unsigned int channels, + unsigned int sample_width, + unsigned int sample_bits) +{ + if (ssi->hw_params_cache.rate != rate || + ssi->hw_params_cache.channels != channels || + ssi->hw_params_cache.sample_width != sample_width || + ssi->hw_params_cache.sample_bits != sample_bits) + return false; + + return true; +} + +static void rz_ssi_cache_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, + unsigned int channels, + unsigned int sample_width, + unsigned int sample_bits) +{ + ssi->hw_params_cache.rate = rate; + ssi->hw_params_cache.channels = channels; + ssi->hw_params_cache.sample_width = sample_width; + ssi->hw_params_cache.sample_bits = sample_bits; +} + +static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); + struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); + unsigned int sample_bits = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; + unsigned int channels = params_channels(params); + unsigned int rate = params_rate(params); + + if (sample_bits != 16) { + dev_err(ssi->dev, "Unsupported sample width: %d\n", + sample_bits); + return -EINVAL; + } + + if (channels != 2) { + dev_err(ssi->dev, "Number of channels not matched: %d\n", + channels); + return -EINVAL; + } + + if (rz_ssi_is_stream_running(&ssi->playback) || + rz_ssi_is_stream_running(&ssi->capture)) { + if (rz_ssi_is_valid_hw_params(ssi, rate, channels, + strm->sample_width, sample_bits)) + return 0; + + dev_err(ssi->dev, "Full duplex needs same HW params\n"); + return -EINVAL; + } + + rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width, + sample_bits); + + return rz_ssi_clk_setup(ssi, rate, channels); +} + +static const struct snd_soc_dai_ops rz_ssi_dai_ops = { + .trigger = rz_ssi_dai_trigger, + .set_fmt = rz_ssi_dai_set_fmt, + .hw_params = rz_ssi_dai_hw_params, +}; + +static const struct snd_pcm_hardware rz_ssi_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .buffer_bytes_max = PREALLOC_BUFFER, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .channels_min = SSI_CHAN_MIN, + .channels_max = SSI_CHAN_MAX, + .periods_min = 1, + .periods_max = 32, + .fifo_size = 32 * 2, +}; + +static int rz_ssi_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + snd_soc_set_runtime_hwparams(substream, &rz_ssi_pcm_hardware); + + return snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); +} + +static snd_pcm_uframes_t rz_ssi_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_dai *dai = rz_ssi_get_dai(substream); + struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); + struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); + + return strm->buffer_pos; +} + +static int rz_ssi_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, + rtd->card->snd_card->dev, + PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); + return 0; +} + +static struct snd_soc_dai_driver rz_ssi_soc_dai[] = { + { + .name = "rz-ssi-dai", + .playback = { + .rates = SSI_RATES, + .formats = SSI_FMTS, + .channels_min = SSI_CHAN_MIN, + .channels_max = SSI_CHAN_MAX, + }, + .capture = { + .rates = SSI_RATES, + .formats = SSI_FMTS, + .channels_min = SSI_CHAN_MIN, + .channels_max = SSI_CHAN_MAX, + }, + .ops = &rz_ssi_dai_ops, + }, +}; + +static const struct snd_soc_component_driver rz_ssi_soc_component = { + .name = "rz-ssi", + .open = rz_ssi_pcm_open, + .pointer = rz_ssi_pcm_pointer, + .pcm_construct = rz_ssi_pcm_new, + .legacy_dai_naming = 1, +}; + +static int rz_ssi_probe(struct platform_device *pdev) +{ + struct rz_ssi_priv *ssi; + struct clk *audio_clk; + struct resource *res; + int ret; + + ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); + if (!ssi) + return -ENOMEM; + + ssi->pdev = pdev; + ssi->dev = &pdev->dev; + ssi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(ssi->base)) + return PTR_ERR(ssi->base); + + ssi->phys = res->start; + ssi->clk = devm_clk_get(&pdev->dev, "ssi"); + if (IS_ERR(ssi->clk)) + return PTR_ERR(ssi->clk); + + ssi->sfr_clk = devm_clk_get(&pdev->dev, "ssi_sfr"); + if (IS_ERR(ssi->sfr_clk)) + return PTR_ERR(ssi->sfr_clk); + + audio_clk = devm_clk_get(&pdev->dev, "audio_clk1"); + if (IS_ERR(audio_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), + "no audio clk1"); + + ssi->audio_clk_1 = clk_get_rate(audio_clk); + audio_clk = devm_clk_get(&pdev->dev, "audio_clk2"); + if (IS_ERR(audio_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), + "no audio clk2"); + + ssi->audio_clk_2 = clk_get_rate(audio_clk); + if (!(ssi->audio_clk_1 || ssi->audio_clk_2)) + return dev_err_probe(&pdev->dev, -EINVAL, + "no audio clk1 or audio clk2"); + + ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2; + + /* Detect DMA support */ + ret = rz_ssi_dma_request(ssi, &pdev->dev); + if (ret < 0) { + dev_warn(&pdev->dev, "DMA not available, using PIO\n"); + ssi->playback.transfer = rz_ssi_pio_send; + ssi->capture.transfer = rz_ssi_pio_recv; + } else { + dev_info(&pdev->dev, "DMA enabled"); + ssi->playback.transfer = rz_ssi_dma_transfer; + ssi->capture.transfer = rz_ssi_dma_transfer; + } + + ssi->playback.priv = ssi; + ssi->capture.priv = ssi; + + spin_lock_init(&ssi->lock); + dev_set_drvdata(&pdev->dev, ssi); + + /* Error Interrupt */ + ssi->irq_int = platform_get_irq_byname(pdev, "int_req"); + if (ssi->irq_int < 0) { + rz_ssi_release_dma_channels(ssi); + return ssi->irq_int; + } + + ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt, + 0, dev_name(&pdev->dev), ssi); + if (ret < 0) { + rz_ssi_release_dma_channels(ssi); + return dev_err_probe(&pdev->dev, ret, + "irq request error (int_req)\n"); + } + + if (!rz_ssi_is_dma_enabled(ssi)) { + /* Tx and Rx interrupts (pio only) */ + ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx"); + ssi->irq_rx = platform_get_irq_byname(pdev, "dma_rx"); + if (ssi->irq_tx == -ENXIO && ssi->irq_rx == -ENXIO) { + ssi->irq_rt = platform_get_irq_byname(pdev, "dma_rt"); + if (ssi->irq_rt < 0) + return ssi->irq_rt; + + ret = devm_request_irq(&pdev->dev, ssi->irq_rt, + &rz_ssi_interrupt, 0, + dev_name(&pdev->dev), ssi); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "irq request error (dma_rt)\n"); + } else { + if (ssi->irq_tx < 0) + return ssi->irq_tx; + + if (ssi->irq_rx < 0) + return ssi->irq_rx; + + ret = devm_request_irq(&pdev->dev, ssi->irq_tx, + &rz_ssi_interrupt, 0, + dev_name(&pdev->dev), ssi); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "irq request error (dma_tx)\n"); + + ret = devm_request_irq(&pdev->dev, ssi->irq_rx, + &rz_ssi_interrupt, 0, + dev_name(&pdev->dev), ssi); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "irq request error (dma_rx)\n"); + } + } + + ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(ssi->rstc)) { + ret = PTR_ERR(ssi->rstc); + goto err_reset; + } + + reset_control_deassert(ssi->rstc); + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n"); + goto err_pm; + } + + ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component, + rz_ssi_soc_dai, + ARRAY_SIZE(rz_ssi_soc_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register snd component\n"); + goto err_snd_soc; + } + + return 0; + +err_snd_soc: + pm_runtime_put(ssi->dev); +err_pm: + pm_runtime_disable(ssi->dev); + reset_control_assert(ssi->rstc); +err_reset: + rz_ssi_release_dma_channels(ssi); + + return ret; +} + +static void rz_ssi_remove(struct platform_device *pdev) +{ + struct rz_ssi_priv *ssi = dev_get_drvdata(&pdev->dev); + + rz_ssi_release_dma_channels(ssi); + + pm_runtime_put(ssi->dev); + pm_runtime_disable(ssi->dev); + reset_control_assert(ssi->rstc); +} + +static const struct of_device_id rz_ssi_of_match[] = { + { .compatible = "renesas,rz-ssi", }, + {/* Sentinel */}, +}; +MODULE_DEVICE_TABLE(of, rz_ssi_of_match); + +static struct platform_driver rz_ssi_driver = { + .driver = { + .name = "rz-ssi-pcm-audio", + .of_match_table = rz_ssi_of_match, + }, + .probe = rz_ssi_probe, + .remove = rz_ssi_remove, +}; + +module_platform_driver(rz_ssi_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Renesas RZ/G2L ASoC Serial Sound Interface Driver"); +MODULE_AUTHOR("Biju Das "); diff --git a/sound/soc/renesas/sh7760-ac97.c b/sound/soc/renesas/sh7760-ac97.c new file mode 100644 index 00000000000000..d267243a159ba6 --- /dev/null +++ b/sound/soc/renesas/sh7760-ac97.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Generic AC97 sound support for SH7760 +// +// (c) 2007 Manuel Lauss + +#include +#include +#include +#include +#include +#include +#include + +#define IPSEL 0xFE400034 + +SND_SOC_DAILINK_DEFS(ac97, + DAILINK_COMP_ARRAY(COMP_CPU("hac-dai.0")), /* HAC0 */ + DAILINK_COMP_ARRAY(COMP_CODEC("ac97-codec", "ac97-hifi")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("sh7760-pcm-audio"))); + +static struct snd_soc_dai_link sh7760_ac97_dai = { + .name = "AC97", + .stream_name = "AC97 HiFi", + SND_SOC_DAILINK_REG(ac97), +}; + +static struct snd_soc_card sh7760_ac97_soc_machine = { + .name = "SH7760 AC97", + .owner = THIS_MODULE, + .dai_link = &sh7760_ac97_dai, + .num_links = 1, +}; + +static struct platform_device *sh7760_ac97_snd_device; + +static int __init sh7760_ac97_init(void) +{ + int ret; + unsigned short ipsel; + + /* enable both AC97 controllers in pinmux reg */ + ipsel = __raw_readw(IPSEL); + __raw_writew(ipsel | (3 << 10), IPSEL); + + ret = -ENOMEM; + sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1); + if (!sh7760_ac97_snd_device) + goto out; + + platform_set_drvdata(sh7760_ac97_snd_device, + &sh7760_ac97_soc_machine); + ret = platform_device_add(sh7760_ac97_snd_device); + + if (ret) + platform_device_put(sh7760_ac97_snd_device); + +out: + return ret; +} + +static void __exit sh7760_ac97_exit(void) +{ + platform_device_unregister(sh7760_ac97_snd_device); +} + +module_init(sh7760_ac97_init); +module_exit(sh7760_ac97_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine"); +MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/renesas/siu.h b/sound/soc/renesas/siu.h new file mode 100644 index 00000000000000..a675c36fc9d956 --- /dev/null +++ b/sound/soc/renesas/siu.h @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral. +// +// Copyright (C) 2009-2010 Guennadi Liakhovetski +// Copyright (C) 2006 Carlos Munoz + +#ifndef SIU_H +#define SIU_H + +/* Common kernel and user-space firmware-building defines and types */ + +#define YRAM0_SIZE (0x0040 / 4) /* 16 */ +#define YRAM1_SIZE (0x0080 / 4) /* 32 */ +#define YRAM2_SIZE (0x0040 / 4) /* 16 */ +#define YRAM3_SIZE (0x0080 / 4) /* 32 */ +#define YRAM4_SIZE (0x0080 / 4) /* 32 */ +#define YRAM_DEF_SIZE (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \ + YRAM3_SIZE + YRAM4_SIZE) +#define YRAM_FIR_SIZE (0x0400 / 4) /* 256 */ +#define YRAM_IIR_SIZE (0x0200 / 4) /* 128 */ + +#define XRAM0_SIZE (0x0400 / 4) /* 256 */ +#define XRAM1_SIZE (0x0200 / 4) /* 128 */ +#define XRAM2_SIZE (0x0200 / 4) /* 128 */ + +/* PRAM program array size */ +#define PRAM0_SIZE (0x0100 / 4) /* 64 */ +#define PRAM1_SIZE ((0x2000 - 0x0100) / 4) /* 1984 */ + +#include + +struct siu_spb_param { + __u32 ab1a; /* input FIFO address */ + __u32 ab0a; /* output FIFO address */ + __u32 dir; /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */ + __u32 event; /* SPB program starting conditions */ + __u32 stfifo; /* STFIFO register setting value */ + __u32 trdat; /* TRDAT register setting value */ +}; + +struct siu_firmware { + __u32 yram_fir_coeff[YRAM_FIR_SIZE]; + __u32 pram0[PRAM0_SIZE]; + __u32 pram1[PRAM1_SIZE]; + __u32 yram0[YRAM0_SIZE]; + __u32 yram1[YRAM1_SIZE]; + __u32 yram2[YRAM2_SIZE]; + __u32 yram3[YRAM3_SIZE]; + __u32 yram4[YRAM4_SIZE]; + __u32 spbpar_num; + struct siu_spb_param spbpar[32]; +}; + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +#include +#include +#include + +#define SIU_PERIOD_BYTES_MAX 8192 /* DMA transfer/period size */ +#define SIU_PERIOD_BYTES_MIN 256 /* DMA transfer/period size */ +#define SIU_PERIODS_MAX 64 /* Max periods in buffer */ +#define SIU_PERIODS_MIN 4 /* Min periods in buffer */ +#define SIU_BUFFER_BYTES_MAX (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX) + +/* SIU ports: only one can be used at a time */ +enum { + SIU_PORT_A, + SIU_PORT_B, + SIU_PORT_NUM, +}; + +/* SIU clock configuration */ +enum { + SIU_CLKA_PLL, + SIU_CLKA_EXT, + SIU_CLKB_PLL, + SIU_CLKB_EXT +}; + +struct device; +struct siu_info { + struct device *dev; + int port_id; + u32 __iomem *pram; + u32 __iomem *xram; + u32 __iomem *yram; + u32 __iomem *reg; + struct siu_firmware fw; +}; + +struct siu_stream { + struct work_struct work; + struct snd_pcm_substream *substream; + snd_pcm_format_t format; + size_t buf_bytes; + size_t period_bytes; + int cur_period; /* Period currently in dma */ + u32 volume; + snd_pcm_sframes_t xfer_cnt; /* Number of frames */ + u8 rw_flg; /* transfer status */ + /* DMA status */ + struct dma_chan *chan; /* DMA channel */ + struct dma_async_tx_descriptor *tx_desc; + dma_cookie_t cookie; + struct sh_dmae_slave param; +}; + +struct siu_port { + unsigned long play_cap; /* Used to track full duplex */ + struct snd_pcm *pcm; + struct siu_stream playback; + struct siu_stream capture; + u32 stfifo; /* STFIFO value from firmware */ + u32 trdat; /* TRDAT value from firmware */ +}; + +extern struct siu_port *siu_ports[SIU_PORT_NUM]; + +static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream) +{ + struct platform_device *pdev = + to_platform_device(substream->pcm->card->dev); + return siu_ports[pdev->id]; +} + +/* Register access */ +static inline void siu_write32(u32 __iomem *addr, u32 val) +{ + __raw_writel(val, addr); +} + +static inline u32 siu_read32(u32 __iomem *addr) +{ + return __raw_readl(addr); +} + +/* SIU registers */ +#define SIU_IFCTL (0x000 / sizeof(u32)) +#define SIU_SRCTL (0x004 / sizeof(u32)) +#define SIU_SFORM (0x008 / sizeof(u32)) +#define SIU_CKCTL (0x00c / sizeof(u32)) +#define SIU_TRDAT (0x010 / sizeof(u32)) +#define SIU_STFIFO (0x014 / sizeof(u32)) +#define SIU_DPAK (0x01c / sizeof(u32)) +#define SIU_CKREV (0x020 / sizeof(u32)) +#define SIU_EVNTC (0x028 / sizeof(u32)) +#define SIU_SBCTL (0x040 / sizeof(u32)) +#define SIU_SBPSET (0x044 / sizeof(u32)) +#define SIU_SBFSTS (0x068 / sizeof(u32)) +#define SIU_SBDVCA (0x06c / sizeof(u32)) +#define SIU_SBDVCB (0x070 / sizeof(u32)) +#define SIU_SBACTIV (0x074 / sizeof(u32)) +#define SIU_DMAIA (0x090 / sizeof(u32)) +#define SIU_DMAIB (0x094 / sizeof(u32)) +#define SIU_DMAOA (0x098 / sizeof(u32)) +#define SIU_DMAOB (0x09c / sizeof(u32)) +#define SIU_DMAML (0x0a0 / sizeof(u32)) +#define SIU_SPSTS (0x0cc / sizeof(u32)) +#define SIU_SPCTL (0x0d0 / sizeof(u32)) +#define SIU_BRGASEL (0x100 / sizeof(u32)) +#define SIU_BRRA (0x104 / sizeof(u32)) +#define SIU_BRGBSEL (0x108 / sizeof(u32)) +#define SIU_BRRB (0x10c / sizeof(u32)) + +extern const struct snd_soc_component_driver siu_component; +extern struct siu_info *siu_i2s_data; + +int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card); +void siu_free_port(struct siu_port *port_info); + +#endif + +#endif /* SIU_H */ diff --git a/sound/soc/renesas/siu_dai.c b/sound/soc/renesas/siu_dai.c new file mode 100644 index 00000000000000..7e771a164a80e4 --- /dev/null +++ b/sound/soc/renesas/siu_dai.c @@ -0,0 +1,800 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral. +// +// Copyright (C) 2009-2010 Guennadi Liakhovetski +// Copyright (C) 2006 Carlos Munoz + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "siu.h" + +/* Board specifics */ +#if defined(CONFIG_CPU_SUBTYPE_SH7722) +# define SIU_MAX_VOLUME 0x1000 +#else +# define SIU_MAX_VOLUME 0x7fff +#endif + +#define PRAM_SIZE 0x2000 +#define XRAM_SIZE 0x800 +#define YRAM_SIZE 0x800 + +#define XRAM_OFFSET 0x4000 +#define YRAM_OFFSET 0x6000 +#define REG_OFFSET 0xc000 + +#define PLAYBACK_ENABLED 1 +#define CAPTURE_ENABLED 2 + +#define VOLUME_CAPTURE 0 +#define VOLUME_PLAYBACK 1 +#define DFLT_VOLUME_LEVEL 0x08000800 + +/* + * SPDIF is only available on port A and on some SIU implementations it is only + * available for input. Due to the lack of hardware to test it, SPDIF is left + * disabled in this driver version + */ +struct format_flag { + u32 i2s; + u32 pcm; + u32 spdif; + u32 mask; +}; + +struct port_flag { + struct format_flag playback; + struct format_flag capture; +}; + +struct siu_info *siu_i2s_data; + +static struct port_flag siu_flags[SIU_PORT_NUM] = { + [SIU_PORT_A] = { + .playback = { + .i2s = 0x50000000, + .pcm = 0x40000000, + .spdif = 0x80000000, /* not on all SIU versions */ + .mask = 0xd0000000, + }, + .capture = { + .i2s = 0x05000000, + .pcm = 0x04000000, + .spdif = 0x08000000, + .mask = 0x0d000000, + }, + }, + [SIU_PORT_B] = { + .playback = { + .i2s = 0x00500000, + .pcm = 0x00400000, + .spdif = 0, /* impossible - turn off */ + .mask = 0x00500000, + }, + .capture = { + .i2s = 0x00050000, + .pcm = 0x00040000, + .spdif = 0, /* impossible - turn off */ + .mask = 0x00050000, + }, + }, +}; + +static void siu_dai_start(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + + dev_dbg(port_info->pcm->card->dev, "%s\n", __func__); + + /* Issue software reset to siu */ + siu_write32(base + SIU_SRCTL, 0); + + /* Wait for the reset to take effect */ + udelay(1); + + port_info->stfifo = 0; + port_info->trdat = 0; + + /* portA, portB, SIU operate */ + siu_write32(base + SIU_SRCTL, 0x301); + + /* portA=256fs, portB=256fs */ + siu_write32(base + SIU_CKCTL, 0x40400000); + + /* portA's BRG does not divide SIUCKA */ + siu_write32(base + SIU_BRGASEL, 0); + siu_write32(base + SIU_BRRA, 0); + + /* portB's BRG divides SIUCKB by half */ + siu_write32(base + SIU_BRGBSEL, 1); + siu_write32(base + SIU_BRRB, 0); + + siu_write32(base + SIU_IFCTL, 0x44440000); + + /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */ + siu_write32(base + SIU_SFORM, 0x0c0c0000); + + /* + * Volume levels: looks like the DSP firmware implements volume controls + * differently from what's described in the datasheet + */ + siu_write32(base + SIU_SBDVCA, port_info->playback.volume); + siu_write32(base + SIU_SBDVCB, port_info->capture.volume); +} + +static void siu_dai_stop(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + + /* SIU software reset */ + siu_write32(base + SIU_SRCTL, 0); +} + +static void siu_dai_spbAselect(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_data; + struct siu_firmware *fw = &info->fw; + u32 *ydef = fw->yram0; + u32 idx; + + /* path A use */ + if (!info->port_id) + idx = 1; /* portA */ + else + idx = 2; /* portB */ + + ydef[0] = (fw->spbpar[idx].ab1a << 16) | + (fw->spbpar[idx].ab0a << 8) | + (fw->spbpar[idx].dir << 7) | 3; + ydef[1] = fw->yram0[1]; /* 0x03000300 */ + ydef[2] = (16 / 2) << 24; + ydef[3] = fw->yram0[3]; /* 0 */ + ydef[4] = fw->yram0[4]; /* 0 */ + ydef[7] = fw->spbpar[idx].event; + port_info->stfifo |= fw->spbpar[idx].stfifo; + port_info->trdat |= fw->spbpar[idx].trdat; +} + +static void siu_dai_spbBselect(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_data; + struct siu_firmware *fw = &info->fw; + u32 *ydef = fw->yram0; + u32 idx; + + /* path B use */ + if (!info->port_id) + idx = 7; /* portA */ + else + idx = 8; /* portB */ + + ydef[5] = (fw->spbpar[idx].ab1a << 16) | + (fw->spbpar[idx].ab0a << 8) | 1; + ydef[6] = fw->spbpar[idx].event; + port_info->stfifo |= fw->spbpar[idx].stfifo; + port_info->trdat |= fw->spbpar[idx].trdat; +} + +static void siu_dai_open(struct siu_stream *siu_stream) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + u32 srctl, ifctl; + + srctl = siu_read32(base + SIU_SRCTL); + ifctl = siu_read32(base + SIU_IFCTL); + + switch (info->port_id) { + case SIU_PORT_A: + /* portA operates */ + srctl |= 0x200; + ifctl &= ~0xc2; + break; + case SIU_PORT_B: + /* portB operates */ + srctl |= 0x100; + ifctl &= ~0x31; + break; + } + + siu_write32(base + SIU_SRCTL, srctl); + /* Unmute and configure portA */ + siu_write32(base + SIU_IFCTL, ifctl); +} + +/* + * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower + * packing is supported + */ +static void siu_dai_pcmdatapack(struct siu_stream *siu_stream) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + u32 dpak; + + dpak = siu_read32(base + SIU_DPAK); + + switch (info->port_id) { + case SIU_PORT_A: + dpak &= ~0xc0000000; + break; + case SIU_PORT_B: + dpak &= ~0x00c00000; + break; + } + + siu_write32(base + SIU_DPAK, dpak); +} + +static int siu_dai_spbstart(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + struct siu_firmware *fw = &info->fw; + u32 *ydef = fw->yram0; + int cnt; + u32 __iomem *add; + u32 *ptr; + + /* Load SPB Program in PRAM */ + ptr = fw->pram0; + add = info->pram; + for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++) + siu_write32(add, *ptr); + + ptr = fw->pram1; + add = info->pram + (0x0100 / sizeof(u32)); + for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++) + siu_write32(add, *ptr); + + /* XRAM initialization */ + add = info->xram; + for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++) + siu_write32(add, 0); + + /* YRAM variable area initialization */ + add = info->yram; + for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++) + siu_write32(add, ydef[cnt]); + + /* YRAM FIR coefficient area initialization */ + add = info->yram + (0x0200 / sizeof(u32)); + for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++) + siu_write32(add, fw->yram_fir_coeff[cnt]); + + /* YRAM IIR coefficient area initialization */ + add = info->yram + (0x0600 / sizeof(u32)); + for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++) + siu_write32(add, 0); + + siu_write32(base + SIU_TRDAT, port_info->trdat); + port_info->trdat = 0x0; + + + /* SPB start condition: software */ + siu_write32(base + SIU_SBACTIV, 0); + /* Start SPB */ + siu_write32(base + SIU_SBCTL, 0xc0000000); + /* Wait for program to halt */ + cnt = 0x10000; + while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000) + cpu_relax(); + + if (!cnt) + return -EBUSY; + + /* SPB program start address setting */ + siu_write32(base + SIU_SBPSET, 0x00400000); + /* SPB hardware start(FIFOCTL source) */ + siu_write32(base + SIU_SBACTIV, 0xc0000000); + + return 0; +} + +static void siu_dai_spbstop(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + + siu_write32(base + SIU_SBACTIV, 0); + /* SPB stop */ + siu_write32(base + SIU_SBCTL, 0); + + port_info->stfifo = 0; +} + +/* API functions */ + +/* Playback and capture hardware properties are identical */ +static const struct snd_pcm_hardware siu_dai_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = SIU_BUFFER_BYTES_MAX, + .period_bytes_min = SIU_PERIOD_BYTES_MIN, + .period_bytes_max = SIU_PERIOD_BYTES_MAX, + .periods_min = SIU_PERIODS_MIN, + .periods_max = SIU_PERIODS_MAX, +}; + +static int siu_dai_info_volume(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_info *uinfo) +{ + struct siu_port *port_info = snd_kcontrol_chip(kctrl); + + dev_dbg(port_info->pcm->card->dev, "%s\n", __func__); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SIU_MAX_VOLUME; + + return 0; +} + +static int siu_dai_get_volume(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct siu_port *port_info = snd_kcontrol_chip(kctrl); + struct device *dev = port_info->pcm->card->dev; + u32 vol; + + dev_dbg(dev, "%s\n", __func__); + + switch (kctrl->private_value) { + case VOLUME_PLAYBACK: + /* Playback is always on port 0 */ + vol = port_info->playback.volume; + ucontrol->value.integer.value[0] = vol & 0xffff; + ucontrol->value.integer.value[1] = vol >> 16 & 0xffff; + break; + case VOLUME_CAPTURE: + /* Capture is always on port 1 */ + vol = port_info->capture.volume; + ucontrol->value.integer.value[0] = vol & 0xffff; + ucontrol->value.integer.value[1] = vol >> 16 & 0xffff; + break; + default: + dev_err(dev, "%s() invalid private_value=%ld\n", + __func__, kctrl->private_value); + return -EINVAL; + } + + return 0; +} + +static int siu_dai_put_volume(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct siu_port *port_info = snd_kcontrol_chip(kctrl); + struct device *dev = port_info->pcm->card->dev; + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + u32 new_vol; + u32 cur_vol; + + dev_dbg(dev, "%s\n", __func__); + + if (ucontrol->value.integer.value[0] < 0 || + ucontrol->value.integer.value[0] > SIU_MAX_VOLUME || + ucontrol->value.integer.value[1] < 0 || + ucontrol->value.integer.value[1] > SIU_MAX_VOLUME) + return -EINVAL; + + new_vol = ucontrol->value.integer.value[0] | + ucontrol->value.integer.value[1] << 16; + + /* See comment above - DSP firmware implementation */ + switch (kctrl->private_value) { + case VOLUME_PLAYBACK: + /* Playback is always on port 0 */ + cur_vol = port_info->playback.volume; + siu_write32(base + SIU_SBDVCA, new_vol); + port_info->playback.volume = new_vol; + break; + case VOLUME_CAPTURE: + /* Capture is always on port 1 */ + cur_vol = port_info->capture.volume; + siu_write32(base + SIU_SBDVCB, new_vol); + port_info->capture.volume = new_vol; + break; + default: + dev_err(dev, "%s() invalid private_value=%ld\n", + __func__, kctrl->private_value); + return -EINVAL; + } + + if (cur_vol != new_vol) + return 1; + + return 0; +} + +static const struct snd_kcontrol_new playback_controls = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Volume", + .index = 0, + .info = siu_dai_info_volume, + .get = siu_dai_get_volume, + .put = siu_dai_put_volume, + .private_value = VOLUME_PLAYBACK, +}; + +static const struct snd_kcontrol_new capture_controls = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Capture Volume", + .index = 0, + .info = siu_dai_info_volume, + .get = siu_dai_get_volume, + .put = siu_dai_put_volume, + .private_value = VOLUME_CAPTURE, +}; + +int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card) +{ + struct device *dev = card->dev; + struct snd_kcontrol *kctrl; + int ret; + + *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL); + if (!*port_info) + return -ENOMEM; + + dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info); + + (*port_info)->playback.volume = DFLT_VOLUME_LEVEL; + (*port_info)->capture.volume = DFLT_VOLUME_LEVEL; + + /* + * Add mixer support. The SPB is used to change the volume. Both + * ports use the same SPB. Therefore, we only register one + * control instance since it will be used by both channels. + * In error case we continue without controls. + */ + kctrl = snd_ctl_new1(&playback_controls, *port_info); + ret = snd_ctl_add(card, kctrl); + if (ret < 0) + dev_err(dev, + "failed to add playback controls %p port=%d err=%d\n", + kctrl, port, ret); + + kctrl = snd_ctl_new1(&capture_controls, *port_info); + ret = snd_ctl_add(card, kctrl); + if (ret < 0) + dev_err(dev, + "failed to add capture controls %p port=%d err=%d\n", + kctrl, port, ret); + + return 0; +} + +void siu_free_port(struct siu_port *port_info) +{ + kfree(port_info); +} + +static int siu_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct siu_info *info = snd_soc_dai_get_drvdata(dai); + struct snd_pcm_runtime *rt = substream->runtime; + struct siu_port *port_info = siu_port_info(substream); + int ret; + + dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__, + info->port_id, port_info); + + snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw); + + ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); + if (unlikely(ret < 0)) + return ret; + + siu_dai_start(port_info); + + return 0; +} + +static void siu_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct siu_info *info = snd_soc_dai_get_drvdata(dai); + struct siu_port *port_info = siu_port_info(substream); + + dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__, + info->port_id, port_info); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + port_info->play_cap &= ~PLAYBACK_ENABLED; + else + port_info->play_cap &= ~CAPTURE_ENABLED; + + /* Stop the siu if the other stream is not using it */ + if (!port_info->play_cap) { + /* during stmread or stmwrite ? */ + if (WARN_ON(port_info->playback.rw_flg || port_info->capture.rw_flg)) + return; + siu_dai_spbstop(port_info); + siu_dai_stop(port_info); + } +} + +/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */ +static int siu_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct siu_info *info = snd_soc_dai_get_drvdata(dai); + struct snd_pcm_runtime *rt = substream->runtime; + struct siu_port *port_info = siu_port_info(substream); + struct siu_stream *siu_stream; + int self, ret; + + dev_dbg(substream->pcm->card->dev, + "%s: port %d, active streams %lx, %d channels\n", + __func__, info->port_id, port_info->play_cap, rt->channels); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + self = PLAYBACK_ENABLED; + siu_stream = &port_info->playback; + } else { + self = CAPTURE_ENABLED; + siu_stream = &port_info->capture; + } + + /* Set up the siu if not already done */ + if (!port_info->play_cap) { + siu_stream->rw_flg = 0; /* stream-data transfer flag */ + + siu_dai_spbAselect(port_info); + siu_dai_spbBselect(port_info); + + siu_dai_open(siu_stream); + + siu_dai_pcmdatapack(siu_stream); + + ret = siu_dai_spbstart(port_info); + if (ret < 0) + goto fail; + } else { + ret = 0; + } + + port_info->play_cap |= self; + +fail: + return ret; +} + +/* + * SIU can set bus format to I2S / PCM / SPDIF independently for playback and + * capture, however, the current API sets the bus format globally for a DAI. + */ +static int siu_dai_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct siu_info *info = snd_soc_dai_get_drvdata(dai); + u32 __iomem *base = info->reg; + u32 ifctl; + + dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n", + __func__, fmt, info->port_id); + + if (info->port_id < 0) + return -ENODEV; + + /* Here select between I2S / PCM / SPDIF */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ifctl = siu_flags[info->port_id].playback.i2s | + siu_flags[info->port_id].capture.i2s; + break; + case SND_SOC_DAIFMT_LEFT_J: + ifctl = siu_flags[info->port_id].playback.pcm | + siu_flags[info->port_id].capture.pcm; + break; + /* SPDIF disabled - see comment at the top */ + default: + return -EINVAL; + } + + ifctl |= ~(siu_flags[info->port_id].playback.mask | + siu_flags[info->port_id].capture.mask) & + siu_read32(base + SIU_IFCTL); + siu_write32(base + SIU_IFCTL, ifctl); + + return 0; +} + +static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct clk *siu_clk, *parent_clk; + char *siu_name, *parent_name; + int ret; + + if (dir != SND_SOC_CLOCK_IN) + return -EINVAL; + + dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id); + + switch (clk_id) { + case SIU_CLKA_PLL: + siu_name = "siua_clk"; + parent_name = "pll_clk"; + break; + case SIU_CLKA_EXT: + siu_name = "siua_clk"; + parent_name = "siumcka_clk"; + break; + case SIU_CLKB_PLL: + siu_name = "siub_clk"; + parent_name = "pll_clk"; + break; + case SIU_CLKB_EXT: + siu_name = "siub_clk"; + parent_name = "siumckb_clk"; + break; + default: + return -EINVAL; + } + + siu_clk = clk_get(dai->dev, siu_name); + if (IS_ERR(siu_clk)) { + dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__, + PTR_ERR(siu_clk)); + return PTR_ERR(siu_clk); + } + + parent_clk = clk_get(dai->dev, parent_name); + if (IS_ERR(parent_clk)) { + ret = PTR_ERR(parent_clk); + dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret); + goto epclkget; + } + + ret = clk_set_parent(siu_clk, parent_clk); + if (ret < 0) { + dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret); + goto eclksetp; + } + + ret = clk_set_rate(siu_clk, freq); + if (ret < 0) + dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret); + + /* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */ +eclksetp: + clk_put(parent_clk); +epclkget: + clk_put(siu_clk); + + return ret; +} + +static const struct snd_soc_dai_ops siu_dai_ops = { + .startup = siu_dai_startup, + .shutdown = siu_dai_shutdown, + .prepare = siu_dai_prepare, + .set_sysclk = siu_dai_set_sysclk, + .set_fmt = siu_dai_set_fmt, +}; + +static struct snd_soc_dai_driver siu_i2s_dai = { + .name = "siu-i2s-dai", + .playback = { + .channels_min = 2, + .channels_max = 2, + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_8000_48000, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .formats = SNDRV_PCM_FMTBIT_S16, + .rates = SNDRV_PCM_RATE_8000_48000, + }, + .ops = &siu_dai_ops, +}; + +static int siu_probe(struct platform_device *pdev) +{ + const struct firmware *fw_entry; + struct resource *res, *region; + struct siu_info *info; + int ret; + + info = devm_kmalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + siu_i2s_data = info; + info->dev = &pdev->dev; + + ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev); + if (ret) + return ret; + + /* + * Loaded firmware is "const" - read only, but we have to modify it in + * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect() + */ + memcpy(&info->fw, fw_entry->data, fw_entry->size); + + release_firmware(fw_entry); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + region = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name); + if (!region) { + dev_err(&pdev->dev, "SIU region already claimed\n"); + return -EBUSY; + } + + info->pram = devm_ioremap(&pdev->dev, res->start, PRAM_SIZE); + if (!info->pram) + return -ENOMEM; + info->xram = devm_ioremap(&pdev->dev, res->start + XRAM_OFFSET, + XRAM_SIZE); + if (!info->xram) + return -ENOMEM; + info->yram = devm_ioremap(&pdev->dev, res->start + YRAM_OFFSET, + YRAM_SIZE); + if (!info->yram) + return -ENOMEM; + info->reg = devm_ioremap(&pdev->dev, res->start + REG_OFFSET, + resource_size(res) - REG_OFFSET); + if (!info->reg) + return -ENOMEM; + + dev_set_drvdata(&pdev->dev, info); + + /* register using ARRAY version so we can keep dai name */ + ret = devm_snd_soc_register_component(&pdev->dev, &siu_component, + &siu_i2s_dai, 1); + if (ret < 0) + return ret; + + pm_runtime_enable(&pdev->dev); + + return 0; +} + +static void siu_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); +} + +static struct platform_driver siu_driver = { + .driver = { + .name = "siu-pcm-audio", + }, + .probe = siu_probe, + .remove = siu_remove, +}; + +module_platform_driver(siu_driver); + +MODULE_AUTHOR("Carlos Munoz "); +MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver"); +MODULE_LICENSE("GPL"); + +MODULE_FIRMWARE("siu_spb.bin"); diff --git a/sound/soc/renesas/siu_pcm.c b/sound/soc/renesas/siu_pcm.c new file mode 100644 index 00000000000000..f15ff36e793455 --- /dev/null +++ b/sound/soc/renesas/siu_pcm.c @@ -0,0 +1,553 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral. +// +// Copyright (C) 2009-2010 Guennadi Liakhovetski +// Copyright (C) 2006 Carlos Munoz + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "siu.h" + +#define DRV_NAME "siu-i2s" +#define GET_MAX_PERIODS(buf_bytes, period_bytes) \ + ((buf_bytes) / (period_bytes)) +#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \ + ((buf_addr) + ((period_num) * (period_bytes))) + +#define RWF_STM_RD 0x01 /* Read in progress */ +#define RWF_STM_WT 0x02 /* Write in progress */ + +struct siu_port *siu_ports[SIU_PORT_NUM]; + +/* transfersize is number of u32 dma transfers per period */ +static int siu_pcm_stmwrite_stop(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + struct siu_stream *siu_stream = &port_info->playback; + u32 stfifo; + + if (!siu_stream->rw_flg) + return -EPERM; + + /* output FIFO disable */ + stfifo = siu_read32(base + SIU_STFIFO); + siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18); + pr_debug("%s: STFIFO %x -> %x\n", __func__, + stfifo, stfifo & ~0x0c180c18); + + /* during stmwrite clear */ + siu_stream->rw_flg = 0; + + return 0; +} + +static int siu_pcm_stmwrite_start(struct siu_port *port_info) +{ + struct siu_stream *siu_stream = &port_info->playback; + + if (siu_stream->rw_flg) + return -EPERM; + + /* Current period in buffer */ + port_info->playback.cur_period = 0; + + /* during stmwrite flag set */ + siu_stream->rw_flg = RWF_STM_WT; + + /* DMA transfer start */ + queue_work(system_highpri_wq, &siu_stream->work); + + return 0; +} + +static void siu_dma_tx_complete(void *arg) +{ + struct siu_stream *siu_stream = arg; + + if (!siu_stream->rw_flg) + return; + + /* Update completed period count */ + if (++siu_stream->cur_period >= + GET_MAX_PERIODS(siu_stream->buf_bytes, + siu_stream->period_bytes)) + siu_stream->cur_period = 0; + + pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n", + __func__, siu_stream->cur_period, + siu_stream->cur_period * siu_stream->period_bytes, + siu_stream->buf_bytes, siu_stream->cookie); + + queue_work(system_highpri_wq, &siu_stream->work); + + /* Notify alsa: a period is done */ + snd_pcm_period_elapsed(siu_stream->substream); +} + +static int siu_pcm_wr_set(struct siu_port *port_info, + dma_addr_t buff, u32 size) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + struct siu_stream *siu_stream = &port_info->playback; + struct snd_pcm_substream *substream = siu_stream->substream; + struct device *dev = substream->pcm->card->dev; + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + struct scatterlist sg; + u32 stfifo; + + sg_init_table(&sg, 1); + sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)), + size, offset_in_page(buff)); + sg_dma_len(&sg) = size; + sg_dma_address(&sg) = buff; + + desc = dmaengine_prep_slave_sg(siu_stream->chan, + &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(dev, "Failed to allocate a dma descriptor\n"); + return -ENOMEM; + } + + desc->callback = siu_dma_tx_complete; + desc->callback_param = siu_stream; + cookie = dmaengine_submit(desc); + if (cookie < 0) { + dev_err(dev, "Failed to submit a dma transfer\n"); + return cookie; + } + + siu_stream->tx_desc = desc; + siu_stream->cookie = cookie; + + dma_async_issue_pending(siu_stream->chan); + + /* only output FIFO enable */ + stfifo = siu_read32(base + SIU_STFIFO); + siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18)); + dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, + stfifo, stfifo | (port_info->stfifo & 0x0c180c18)); + + return 0; +} + +static int siu_pcm_rd_set(struct siu_port *port_info, + dma_addr_t buff, size_t size) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + struct siu_stream *siu_stream = &port_info->capture; + struct snd_pcm_substream *substream = siu_stream->substream; + struct device *dev = substream->pcm->card->dev; + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + struct scatterlist sg; + u32 stfifo; + + dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff); + + sg_init_table(&sg, 1); + sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)), + size, offset_in_page(buff)); + sg_dma_len(&sg) = size; + sg_dma_address(&sg) = buff; + + desc = dmaengine_prep_slave_sg(siu_stream->chan, + &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(dev, "Failed to allocate dma descriptor\n"); + return -ENOMEM; + } + + desc->callback = siu_dma_tx_complete; + desc->callback_param = siu_stream; + cookie = dmaengine_submit(desc); + if (cookie < 0) { + dev_err(dev, "Failed to submit dma descriptor\n"); + return cookie; + } + + siu_stream->tx_desc = desc; + siu_stream->cookie = cookie; + + dma_async_issue_pending(siu_stream->chan); + + /* only input FIFO enable */ + stfifo = siu_read32(base + SIU_STFIFO); + siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) | + (port_info->stfifo & 0x13071307)); + dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, + stfifo, stfifo | (port_info->stfifo & 0x13071307)); + + return 0; +} + +static void siu_io_work(struct work_struct *work) +{ + struct siu_stream *siu_stream = container_of(work, struct siu_stream, + work); + struct snd_pcm_substream *substream = siu_stream->substream; + struct device *dev = substream->pcm->card->dev; + struct snd_pcm_runtime *rt = substream->runtime; + struct siu_port *port_info = siu_port_info(substream); + + dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg); + + if (!siu_stream->rw_flg) { + dev_dbg(dev, "%s: stream inactive\n", __func__); + return; + } + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + dma_addr_t buff; + size_t count; + + buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, + siu_stream->cur_period, + siu_stream->period_bytes); + count = siu_stream->period_bytes; + + /* DMA transfer start */ + siu_pcm_rd_set(port_info, buff, count); + } else { + siu_pcm_wr_set(port_info, + (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, + siu_stream->cur_period, + siu_stream->period_bytes), + siu_stream->period_bytes); + } +} + +/* Capture */ +static int siu_pcm_stmread_start(struct siu_port *port_info) +{ + struct siu_stream *siu_stream = &port_info->capture; + + if (siu_stream->xfer_cnt > 0x1000000) + return -EINVAL; + if (siu_stream->rw_flg) + return -EPERM; + + /* Current period in buffer */ + siu_stream->cur_period = 0; + + /* during stmread flag set */ + siu_stream->rw_flg = RWF_STM_RD; + + queue_work(system_highpri_wq, &siu_stream->work); + + return 0; +} + +static int siu_pcm_stmread_stop(struct siu_port *port_info) +{ + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + struct siu_stream *siu_stream = &port_info->capture; + struct device *dev = siu_stream->substream->pcm->card->dev; + u32 stfifo; + + if (!siu_stream->rw_flg) + return -EPERM; + + /* input FIFO disable */ + stfifo = siu_read32(base + SIU_STFIFO); + siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307); + dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, + stfifo, stfifo & ~0x13071307); + + /* during stmread flag clear */ + siu_stream->rw_flg = 0; + + return 0; +} + +static bool filter(struct dma_chan *chan, void *secondary) +{ + struct sh_dmae_slave *param = secondary; + + pr_debug("%s: secondary ID %d\n", __func__, param->shdma_slave.slave_id); + + chan->private = ¶m->shdma_slave; + return true; +} + +static int siu_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *ss) +{ + /* Playback / Capture */ + struct siu_platform *pdata = component->dev->platform_data; + struct siu_info *info = siu_i2s_data; + struct siu_port *port_info = siu_port_info(ss); + struct siu_stream *siu_stream; + u32 port = info->port_id; + struct device *dev = ss->pcm->card->dev; + dma_cap_mask_t mask; + struct sh_dmae_slave *param; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info); + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) { + siu_stream = &port_info->playback; + param = &siu_stream->param; + param->shdma_slave.slave_id = port ? pdata->dma_slave_tx_b : + pdata->dma_slave_tx_a; + } else { + siu_stream = &port_info->capture; + param = &siu_stream->param; + param->shdma_slave.slave_id = port ? pdata->dma_slave_rx_b : + pdata->dma_slave_rx_a; + } + + /* Get DMA channel */ + siu_stream->chan = dma_request_channel(mask, filter, param); + if (!siu_stream->chan) { + dev_err(dev, "DMA channel allocation failed!\n"); + return -EBUSY; + } + + siu_stream->substream = ss; + + return 0; +} + +static int siu_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *ss) +{ + struct siu_info *info = siu_i2s_data; + struct device *dev = ss->pcm->card->dev; + struct siu_port *port_info = siu_port_info(ss); + struct siu_stream *siu_stream; + + dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id); + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_stream = &port_info->playback; + else + siu_stream = &port_info->capture; + + dma_release_channel(siu_stream->chan); + siu_stream->chan = NULL; + + siu_stream->substream = NULL; + + return 0; +} + +static int siu_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *ss) +{ + struct siu_info *info = siu_i2s_data; + struct siu_port *port_info = siu_port_info(ss); + struct device *dev = ss->pcm->card->dev; + struct snd_pcm_runtime *rt; + struct siu_stream *siu_stream; + snd_pcm_sframes_t xfer_cnt; + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_stream = &port_info->playback; + else + siu_stream = &port_info->capture; + + rt = siu_stream->substream->runtime; + + siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss); + siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss); + + dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__, + info->port_id, rt->channels, siu_stream->period_bytes); + + /* We only support buffers that are multiples of the period */ + if (siu_stream->buf_bytes % siu_stream->period_bytes) { + dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n", + __func__, siu_stream->buf_bytes, + siu_stream->period_bytes); + return -EINVAL; + } + + xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes); + if (!xfer_cnt || xfer_cnt > 0x1000000) + return -EINVAL; + + siu_stream->format = rt->format; + siu_stream->xfer_cnt = xfer_cnt; + + dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d " + "format=%d channels=%d xfer_cnt=%d\n", info->port_id, + (unsigned long)rt->dma_addr, siu_stream->buf_bytes, + siu_stream->period_bytes, + siu_stream->format, rt->channels, (int)xfer_cnt); + + return 0; +} + +static int siu_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *ss, int cmd) +{ + struct siu_info *info = siu_i2s_data; + struct device *dev = ss->pcm->card->dev; + struct siu_port *port_info = siu_port_info(ss); + int ret; + + dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__, + info->port_id, port_info, cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = siu_pcm_stmwrite_start(port_info); + else + ret = siu_pcm_stmread_start(port_info); + + if (ret < 0) + dev_warn(dev, "%s: start failed on port=%d\n", + __func__, info->port_id); + + break; + case SNDRV_PCM_TRIGGER_STOP: + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_pcm_stmwrite_stop(port_info); + else + siu_pcm_stmread_stop(port_info); + ret = 0; + + break; + default: + dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd); + ret = -EINVAL; + } + + return ret; +} + +/* + * So far only resolution of one period is supported, subject to extending the + * dmangine API + */ +static snd_pcm_uframes_t +siu_pcm_pointer_dma(struct snd_soc_component *component, + struct snd_pcm_substream *ss) +{ + struct device *dev = ss->pcm->card->dev; + struct siu_info *info = siu_i2s_data; + u32 __iomem *base = info->reg; + struct siu_port *port_info = siu_port_info(ss); + struct snd_pcm_runtime *rt = ss->runtime; + size_t ptr; + struct siu_stream *siu_stream; + + if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) + siu_stream = &port_info->playback; + else + siu_stream = &port_info->capture; + + /* + * ptr is the offset into the buffer where the dma is currently at. We + * check if the dma buffer has just wrapped. + */ + ptr = PERIOD_OFFSET(rt->dma_addr, + siu_stream->cur_period, + siu_stream->period_bytes) - rt->dma_addr; + + dev_dbg(dev, + "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n", + __func__, info->port_id, siu_read32(base + SIU_EVNTC), + siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes, + siu_stream->cookie); + + if (ptr >= siu_stream->buf_bytes) + ptr = 0; + + return bytes_to_frames(ss->runtime, ptr); +} + +static int siu_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + /* card->dev == socdev->dev, see snd_soc_new_pcms() */ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + struct siu_info *info = siu_i2s_data; + struct platform_device *pdev = to_platform_device(card->dev); + int ret; + int i; + + /* pdev->id selects between SIUA and SIUB */ + if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM) + return -EINVAL; + + info->port_id = pdev->id; + + /* + * While the siu has 2 ports, only one port can be on at a time (only 1 + * SPB). So far all the boards using the siu had only one of the ports + * wired to a codec. To simplify things, we only register one port with + * alsa. In case both ports are needed, it should be changed here + */ + for (i = pdev->id; i < pdev->id + 1; i++) { + struct siu_port **port_info = &siu_ports[i]; + + ret = siu_init_port(i, port_info, card); + if (ret < 0) + return ret; + + snd_pcm_set_managed_buffer_all(pcm, + SNDRV_DMA_TYPE_DEV, card->dev, + SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX); + + (*port_info)->pcm = pcm; + + /* IO works */ + INIT_WORK(&(*port_info)->playback.work, siu_io_work); + INIT_WORK(&(*port_info)->capture.work, siu_io_work); + } + + dev_info(card->dev, "SuperH SIU driver initialized.\n"); + return 0; +} + +static void siu_pcm_free(struct snd_soc_component *component, + struct snd_pcm *pcm) +{ + struct platform_device *pdev = to_platform_device(pcm->card->dev); + struct siu_port *port_info = siu_ports[pdev->id]; + + cancel_work_sync(&port_info->capture.work); + cancel_work_sync(&port_info->playback.work); + + siu_free_port(port_info); + + dev_dbg(pcm->card->dev, "%s\n", __func__); +} + +const struct snd_soc_component_driver siu_component = { + .name = DRV_NAME, + .open = siu_pcm_open, + .close = siu_pcm_close, + .prepare = siu_pcm_prepare, + .trigger = siu_pcm_trigger, + .pointer = siu_pcm_pointer_dma, + .pcm_construct = siu_pcm_new, + .pcm_destruct = siu_pcm_free, + .legacy_dai_naming = 1, +}; +EXPORT_SYMBOL_GPL(siu_component); diff --git a/sound/soc/renesas/ssi.c b/sound/soc/renesas/ssi.c new file mode 100644 index 00000000000000..96cf523c227343 --- /dev/null +++ b/sound/soc/renesas/ssi.c @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Serial Sound Interface (I2S) support for SH7760/SH7780 +// +// Copyright (c) 2007 Manuel Lauss +// +// dont forget to set IPSEL/OMSEL register bits (in your board code) to +// enable SSI output pins! + +/* + * LIMITATIONS: + * The SSI unit has only one physical data line, so full duplex is + * impossible. This can be remedied on the SH7760 by using the + * other SSI unit for recording; however the SH7780 has only 1 SSI + * unit, and its pins are shared with the AC97 unit, among others. + * + * FEATURES: + * The SSI features "compressed mode": in this mode it continuously + * streams PCM data over the I2S lines and uses LRCK as a handshake + * signal. Can be used to send compressed data (AC3/DTS) to a DSP. + * The number of bits sent over the wire in a frame can be adjusted + * and can be independent from the actual sample bit depth. This is + * useful to support TDM mode codecs like the AD1939 which have a + * fixed TDM slot size, regardless of sample resolution. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SSICR 0x00 +#define SSISR 0x04 + +#define CR_DMAEN (1 << 28) +#define CR_CHNL_SHIFT 22 +#define CR_CHNL_MASK (3 << CR_CHNL_SHIFT) +#define CR_DWL_SHIFT 19 +#define CR_DWL_MASK (7 << CR_DWL_SHIFT) +#define CR_SWL_SHIFT 16 +#define CR_SWL_MASK (7 << CR_SWL_SHIFT) +#define CR_SCK_MASTER (1 << 15) /* bitclock master bit */ +#define CR_SWS_MASTER (1 << 14) /* wordselect master bit */ +#define CR_SCKP (1 << 13) /* I2Sclock polarity */ +#define CR_SWSP (1 << 12) /* LRCK polarity */ +#define CR_SPDP (1 << 11) +#define CR_SDTA (1 << 10) /* i2s alignment (msb/lsb) */ +#define CR_PDTA (1 << 9) /* fifo data alignment */ +#define CR_DEL (1 << 8) /* delay data by 1 i2sclk */ +#define CR_BREN (1 << 7) /* clock gating in burst mode */ +#define CR_CKDIV_SHIFT 4 +#define CR_CKDIV_MASK (7 << CR_CKDIV_SHIFT) /* bitclock divider */ +#define CR_MUTE (1 << 3) /* SSI mute */ +#define CR_CPEN (1 << 2) /* compressed mode */ +#define CR_TRMD (1 << 1) /* transmit/receive select */ +#define CR_EN (1 << 0) /* enable SSI */ + +#define SSIREG(reg) (*(unsigned long *)(ssi->mmio + (reg))) + +struct ssi_priv { + unsigned long mmio; + unsigned long sysclk; + int inuse; +} ssi_cpu_data[] = { +#if defined(CONFIG_CPU_SUBTYPE_SH7760) + { + .mmio = 0xFE680000, + }, + { + .mmio = 0xFE690000, + }, +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) + { + .mmio = 0xFFE70000, + }, +#else +#error "Unsupported SuperH SoC" +#endif +}; + +/* + * track usage of the SSI; it is simplex-only so prevent attempts of + * concurrent playback + capture. FIXME: any locking required? + */ +static int ssi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; + if (ssi->inuse) { + pr_debug("ssi: already in use!\n"); + return -EBUSY; + } else + ssi->inuse = 1; + return 0; +} + +static void ssi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; + + ssi->inuse = 0; +} + +static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + SSIREG(SSICR) |= CR_DMAEN | CR_EN; + break; + case SNDRV_PCM_TRIGGER_STOP: + SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ssi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; + unsigned long ssicr = SSIREG(SSICR); + unsigned int bits, channels, swl, recv, i; + + channels = params_channels(params); + bits = params->msbits; + recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1; + + pr_debug("ssi_hw_params() enter\nssicr was %08lx\n", ssicr); + pr_debug("bits: %u channels: %u\n", bits, channels); + + ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA | + CR_SWL_MASK); + + /* direction (send/receive) */ + if (!recv) + ssicr |= CR_TRMD; /* transmit */ + + /* channels */ + if ((channels < 2) || (channels > 8) || (channels & 1)) { + pr_debug("ssi: invalid number of channels\n"); + return -EINVAL; + } + ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT; + + /* DATA WORD LENGTH (DWL): databits in audio sample */ + i = 0; + switch (bits) { + case 32: ++i; + case 24: ++i; + case 22: ++i; + case 20: ++i; + case 18: ++i; + case 16: ++i; + ssicr |= i << CR_DWL_SHIFT; + case 8: break; + default: + pr_debug("ssi: invalid sample width\n"); + return -EINVAL; + } + + /* + * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S + * wires. This is usually bits_per_sample x channels/2; i.e. in + * Stereo mode the SWL equals DWL. SWL can be bigger than the + * product of (channels_per_slot x samplebits), e.g. for codecs + * like the AD1939 which only accept 32bit wide TDM slots. For + * "standard" I2S operation we set SWL = chans / 2 * DWL here. + * Waiting for ASoC to get TDM support ;-) + */ + if ((bits > 16) && (bits <= 24)) { + bits = 24; /* these are padded by the SSI */ + /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */ + } + i = 0; + swl = (bits * channels) / 2; + switch (swl) { + case 256: ++i; + case 128: ++i; + case 64: ++i; + case 48: ++i; + case 32: ++i; + case 16: ++i; + ssicr |= i << CR_SWL_SHIFT; + case 8: break; + default: + pr_debug("ssi: invalid system word length computed\n"); + return -EINVAL; + } + + SSIREG(SSICR) = ssicr; + + pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr); + return 0; +} + +static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, + unsigned int freq, int dir) +{ + struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id]; + + ssi->sysclk = freq; + + return 0; +} + +/* + * This divider is used to generate the SSI_SCK (I2S bitclock) from the + * clock at the HAC_BIT_CLK ("oversampling clock") pin. + */ +static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div) +{ + struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; + unsigned long ssicr; + int i; + + i = 0; + ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK; + switch (div) { + case 16: ++i; + case 8: ++i; + case 4: ++i; + case 2: ++i; + SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT); + case 1: break; + default: + pr_debug("ssi: invalid sck divider %d\n", div); + return -EINVAL; + } + + return 0; +} + +static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; + unsigned long ssicr = SSIREG(SSICR); + + pr_debug("ssi_set_fmt()\nssicr was 0x%08lx\n", ssicr); + + ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP | + CR_SWS_MASTER | CR_SCK_MASTER); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + ssicr |= CR_DEL | CR_PDTA; + break; + case SND_SOC_DAIFMT_LEFT_J: + ssicr |= CR_DEL; + break; + default: + pr_debug("ssi: unsupported format\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { + case SND_SOC_DAIFMT_CONT: + break; + case SND_SOC_DAIFMT_GATED: + ssicr |= CR_BREN; + break; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + ssicr |= CR_SCKP; /* sample data at low clkedge */ + break; + case SND_SOC_DAIFMT_NB_IF: + ssicr |= CR_SCKP | CR_SWSP; + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + ssicr |= CR_SWSP; /* word select starts low */ + break; + default: + pr_debug("ssi: invalid inversion\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + break; + case SND_SOC_DAIFMT_BP_FC: + ssicr |= CR_SCK_MASTER; + break; + case SND_SOC_DAIFMT_BC_FP: + ssicr |= CR_SWS_MASTER; + break; + case SND_SOC_DAIFMT_BP_FP: + ssicr |= CR_SWS_MASTER | CR_SCK_MASTER; + break; + default: + pr_debug("ssi: invalid master/secondary configuration\n"); + return -EINVAL; + } + + SSIREG(SSICR) = ssicr; + pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr); + + return 0; +} + +/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in + * Master mode, so really this is board specific; the SSI can do any + * rate with the right bitclk and divider settings. + */ +#define SSI_RATES \ + SNDRV_PCM_RATE_8000_192000 + +/* the SSI can do 8-32 bit samples, with 8 possible channels */ +#define SSI_FMTS \ + (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) + +static const struct snd_soc_dai_ops ssi_dai_ops = { + .startup = ssi_startup, + .shutdown = ssi_shutdown, + .trigger = ssi_trigger, + .hw_params = ssi_hw_params, + .set_sysclk = ssi_set_sysclk, + .set_clkdiv = ssi_set_clkdiv, + .set_fmt = ssi_set_fmt, +}; + +static struct snd_soc_dai_driver sh4_ssi_dai[] = { +{ + .name = "ssi-dai.0", + .playback = { + .rates = SSI_RATES, + .formats = SSI_FMTS, + .channels_min = 2, + .channels_max = 8, + }, + .capture = { + .rates = SSI_RATES, + .formats = SSI_FMTS, + .channels_min = 2, + .channels_max = 8, + }, + .ops = &ssi_dai_ops, +}, +#ifdef CONFIG_CPU_SUBTYPE_SH7760 +{ + .name = "ssi-dai.1", + .playback = { + .rates = SSI_RATES, + .formats = SSI_FMTS, + .channels_min = 2, + .channels_max = 8, + }, + .capture = { + .rates = SSI_RATES, + .formats = SSI_FMTS, + .channels_min = 2, + .channels_max = 8, + }, + .ops = &ssi_dai_ops, +}, +#endif +}; + +static const struct snd_soc_component_driver sh4_ssi_component = { + .name = "sh4-ssi", + .legacy_dai_naming = 1, +}; + +static int sh4_soc_dai_probe(struct platform_device *pdev) +{ + return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component, + sh4_ssi_dai, + ARRAY_SIZE(sh4_ssi_dai)); +} + +static struct platform_driver sh4_ssi_driver = { + .driver = { + .name = "sh4-ssi-dai", + }, + + .probe = sh4_soc_dai_probe, +}; + +module_platform_driver(sh4_ssi_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver"); +MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index ed865cc07e2ef1..40ac12c0714553 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -171,25 +171,24 @@ static struct snd_soc_dai_link odroid_card_dais[] = { .name = "Primary", .stream_name = "Primary", .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(primary), }, { /* BE <-> CODECs link */ .name = "I2S Mixer", .ops = &odroid_card_be_ops, .no_pcm = 1, - .dpcm_playback = 1, + .playback_only = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, SND_SOC_DAILINK_REG(mixer), }, { /* Secondary FE <-> BE link */ - .playback_only = 1, .ops = &odroid_card_fe_ops, .name = "Secondary", .stream_name = "Secondary", .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(secondary), } }; @@ -278,8 +277,8 @@ static int odroid_audio_probe(struct platform_device *pdev) /* Set capture capability only for boards with the MAX98090 CODEC */ if (codec_link->num_codecs > 1) { - card->dai_link[0].dpcm_capture = 1; - card->dai_link[1].dpcm_capture = 1; + card->dai_link[0].playback_only = 0; + card->dai_link[1].playback_only = 0; } priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1"); diff --git a/sound/soc/sdca/Kconfig b/sound/soc/sdca/Kconfig new file mode 100644 index 00000000000000..ee20b9914aa1fa --- /dev/null +++ b/sound/soc/sdca/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config SND_SOC_SDCA + tristate + depends on ACPI + help + This option enables support for the MIPI SoundWire Device + Class for Audio (SDCA). + +config SND_SOC_SDCA_OPTIONAL + def_tristate SND_SOC_SDCA || !SND_SOC_SDCA diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile new file mode 100644 index 00000000000000..c296bd5a0a7cfa --- /dev/null +++ b/sound/soc/sdca/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +snd-soc-sdca-objs := sdca_functions.o sdca_device.o + +obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c new file mode 100644 index 00000000000000..80d663777eb53a --- /dev/null +++ b/sound/soc/sdca/sdca_device.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2024 Intel Corporation + +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + */ + +#include +#include +#include +#include + +void sdca_lookup_interface_revision(struct sdw_slave *slave) +{ + struct fwnode_handle *fwnode = slave->dev.fwnode; + + /* + * if this property is not present, then the sdca_interface_revision will + * remain zero, which will be considered as 'not defined' or 'invalid'. + */ + fwnode_property_read_u32(fwnode, "mipi-sdw-sdca-interface-revision", + &slave->sdca_data.interface_revision); +} +EXPORT_SYMBOL_NS(sdca_lookup_interface_revision, "SND_SOC_SDCA"); + +static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave) +{ + struct sdw_slave_id *id = &slave->id; + int i; + + /* + * The RT712_VA relies on the v06r04 draft, and the + * RT712_VB on a more recent v08r01 draft. + */ + if (slave->sdca_data.interface_revision < 0x0801) + return false; + + if (id->mfg_id != 0x025d) + return false; + + if (id->part_id != 0x712 && + id->part_id != 0x713 && + id->part_id != 0x716 && + id->part_id != 0x717) + return false; + + for (i = 0; i < slave->sdca_data.num_functions; i++) { + if (slave->sdca_data.sdca_func[i].type == + SDCA_FUNCTION_TYPE_SMART_MIC) + return true; + } + + return false; +} + +bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk) +{ + switch (quirk) { + case SDCA_QUIRKS_RT712_VB: + return sdca_device_quirk_rt712_vb(slave); + default: + break; + } + return false; +} +EXPORT_SYMBOL_NS(sdca_device_quirk_match, "SND_SOC_SDCA"); diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c new file mode 100644 index 00000000000000..65286532996868 --- /dev/null +++ b/sound/soc/sdca/sdca_functions.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2024 Intel Corporation + +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + */ + +#include +#include +#include +#include + +static int patch_sdca_function_type(struct device *dev, + u32 interface_revision, + u32 *function_type, + const char **function_name) +{ + unsigned long function_type_patch = 0; + + /* + * Unfortunately early SDCA specifications used different indices for Functions, + * for backwards compatibility we have to reorder the values found + */ + if (interface_revision >= 0x0801) + goto skip_early_draft_order; + + switch (*function_type) { + case 1: + function_type_patch = SDCA_FUNCTION_TYPE_SMART_AMP; + break; + case 2: + function_type_patch = SDCA_FUNCTION_TYPE_SMART_MIC; + break; + case 3: + function_type_patch = SDCA_FUNCTION_TYPE_SPEAKER_MIC; + break; + case 4: + function_type_patch = SDCA_FUNCTION_TYPE_UAJ; + break; + case 5: + function_type_patch = SDCA_FUNCTION_TYPE_RJ; + break; + case 6: + function_type_patch = SDCA_FUNCTION_TYPE_HID; + break; + default: + dev_warn(dev, "%s: SDCA version %#x unsupported function type %d, skipped\n", + __func__, interface_revision, *function_type); + return -EINVAL; + } + +skip_early_draft_order: + if (function_type_patch) + *function_type = function_type_patch; + + /* now double-check the values */ + switch (*function_type) { + case SDCA_FUNCTION_TYPE_SMART_AMP: + *function_name = SDCA_FUNCTION_TYPE_SMART_AMP_NAME; + break; + case SDCA_FUNCTION_TYPE_SMART_MIC: + *function_name = SDCA_FUNCTION_TYPE_SMART_MIC_NAME; + break; + case SDCA_FUNCTION_TYPE_UAJ: + *function_name = SDCA_FUNCTION_TYPE_UAJ_NAME; + break; + case SDCA_FUNCTION_TYPE_HID: + *function_name = SDCA_FUNCTION_TYPE_HID_NAME; + break; + case SDCA_FUNCTION_TYPE_SIMPLE_AMP: + case SDCA_FUNCTION_TYPE_SIMPLE_MIC: + case SDCA_FUNCTION_TYPE_SPEAKER_MIC: + case SDCA_FUNCTION_TYPE_RJ: + case SDCA_FUNCTION_TYPE_IMP_DEF: + dev_warn(dev, "%s: found unsupported SDCA function type %d, skipped\n", + __func__, *function_type); + return -EINVAL; + default: + dev_err(dev, "%s: found invalid SDCA function type %d, skipped\n", + __func__, *function_type); + return -EINVAL; + } + + dev_info(dev, "%s: found SDCA function %s (type %d)\n", + __func__, *function_name, *function_type); + + return 0; +} + +static int find_sdca_function(struct acpi_device *adev, void *data) +{ + struct fwnode_handle *function_node = acpi_fwnode_handle(adev); + struct sdca_device_data *sdca_data = data; + struct device *dev = &adev->dev; + struct fwnode_handle *control5; /* used to identify function type */ + const char *function_name; + u32 function_type; + int func_index; + u64 addr; + int ret; + + if (sdca_data->num_functions >= SDCA_MAX_FUNCTION_COUNT) { + dev_err(dev, "%s: maximum number of functions exceeded\n", __func__); + return -EINVAL; + } + + /* + * The number of functions cannot exceed 8, we could use + * acpi_get_local_address() but the value is stored as u64 so + * we might as well avoid casts and intermediate levels + */ + ret = acpi_get_local_u64_address(adev->handle, &addr); + if (ret < 0) + return ret; + + if (!addr) { + dev_err(dev, "%s: no addr\n", __func__); + return -ENODEV; + } + + /* + * Extracting the topology type for an SDCA function is a + * convoluted process. + * The Function type is only visible as a result of a read + * from a control. In theory this would mean reading from the hardware, + * but the SDCA/DisCo specs defined the notion of "DC value" - a constant + * represented with a DSD subproperty. + * Drivers have to query the properties for the control + * SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY (0x05) + */ + control5 = fwnode_get_named_child_node(function_node, + "mipi-sdca-control-0x5-subproperties"); + if (!control5) + return -ENODEV; + + ret = fwnode_property_read_u32(control5, "mipi-sdca-control-dc-value", + &function_type); + + fwnode_handle_put(control5); + + if (ret < 0) { + dev_err(dev, "%s: the function type can only be determined from ACPI information\n", + __func__); + return ret; + } + + ret = patch_sdca_function_type(dev, sdca_data->interface_revision, + &function_type, &function_name); + if (ret < 0) + return ret; + + /* store results */ + func_index = sdca_data->num_functions; + sdca_data->sdca_func[func_index].adr = addr; + sdca_data->sdca_func[func_index].type = function_type; + sdca_data->sdca_func[func_index].name = function_name; + sdca_data->num_functions++; + + return 0; +} + +void sdca_lookup_functions(struct sdw_slave *slave) +{ + struct device *dev = &slave->dev; + struct acpi_device *adev = to_acpi_device_node(dev->fwnode); + + if (!adev) { + dev_info(dev, "No matching ACPI device found, ignoring peripheral\n"); + return; + } + acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data); +} +EXPORT_SYMBOL_NS(sdca_lookup_functions, "SND_SOC_SDCA"); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("SDCA library"); diff --git a/sound/soc/sdw_utils/Makefile b/sound/soc/sdw_utils/Makefile index 28229ed96ffb5e..daf01911355371 100644 --- a/sound/soc/sdw_utils/Makefile +++ b/sound/soc/sdw_utils/Makefile @@ -1,9 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only snd-soc-sdw-utils-y := soc_sdw_utils.o soc_sdw_dmic.o soc_sdw_rt_dmic.o \ soc_sdw_rt700.o soc_sdw_rt711.o \ - soc_sdw_rt712_sdca.o soc_sdw_rt722_sdca.o \ soc_sdw_rt5682.o soc_sdw_rt_sdca_jack_common.o \ - soc_sdw_rt_amp.o \ + soc_sdw_rt_amp.o soc_sdw_rt_mf_sdca.o \ soc_sdw_bridge_cs35l56.o \ soc_sdw_cs42l42.o soc_sdw_cs42l43.o \ soc_sdw_cs_amp.o \ diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c index fcc3ef685af7d3..246e5c2e0af55f 100644 --- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c +++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c @@ -112,7 +112,7 @@ int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_count_sidecar, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_count_sidecar, "SND_SOC_SDW_UTILS"); int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, @@ -134,7 +134,7 @@ int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_add_sidecar, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_add_sidecar, "SND_SOC_SDW_UTILS"); int asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card, struct snd_soc_dai_link *dai_links, @@ -148,4 +148,4 @@ int asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_spk_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_bridge_cs35l56_spk_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l42.c b/sound/soc/sdw_utils/soc_sdw_cs42l42.c index 78a6cb059ac06b..f37c1793991a4c 100644 --- a/sound/soc/sdw_utils/soc_sdw_cs42l42.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l42.c @@ -88,4 +88,4 @@ int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_da return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_cs42l42_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_cs42l42_rtd_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c index adb1c008e871d5..668c9d28a1c12d 100644 --- a/sound/soc/sdw_utils/soc_sdw_cs42l43.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c @@ -100,7 +100,7 @@ int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_hs_rtd_init, "SND_SOC_SDW_UTILS"); int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { @@ -124,7 +124,7 @@ int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_so return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_rtd_init, "SND_SOC_SDW_UTILS"); int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card, struct snd_soc_dai_link *dai_links, @@ -139,7 +139,7 @@ int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card, return asoc_sdw_bridge_cs35l56_spk_init(card, dai_links, info, playback); } -EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_spk_init, "SND_SOC_SDW_UTILS"); int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) { @@ -158,4 +158,4 @@ int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_s return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_dmic_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_cs42l43_dmic_rtd_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_cs_amp.c b/sound/soc/sdw_utils/soc_sdw_cs_amp.c index 58b059b68016b8..a0bb626c5cb8c4 100644 --- a/sound/soc/sdw_utils/soc_sdw_cs_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_cs_amp.c @@ -46,7 +46,7 @@ int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, "SND_SOC_SDW_UTILS"); int asoc_sdw_cs_amp_init(struct snd_soc_card *card, struct snd_soc_dai_link *dai_links, @@ -61,4 +61,4 @@ int asoc_sdw_cs_amp_init(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_cs_amp_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_cs_amp_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_dmic.c b/sound/soc/sdw_utils/soc_sdw_dmic.c index fc2aae985084b6..0d8fce7234a737 100644 --- a/sound/soc/sdw_utils/soc_sdw_dmic.c +++ b/sound/soc/sdw_utils/soc_sdw_dmic.c @@ -42,4 +42,4 @@ int asoc_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_dmic_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_dmic_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_maxim.c b/sound/soc/sdw_utils/soc_sdw_maxim.c index cdcd8df37e1d3c..5df8d9cae60c3e 100644 --- a/sound/soc/sdw_utils/soc_sdw_maxim.c +++ b/sound/soc/sdw_utils/soc_sdw_maxim.c @@ -43,7 +43,7 @@ int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_ return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_maxim_spk_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_maxim_spk_rtd_init, "SND_SOC_SDW_UTILS"); static int asoc_sdw_mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable) { @@ -145,4 +145,4 @@ int asoc_sdw_maxim_init(struct snd_soc_card *card, } return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_maxim_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_maxim_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_rt5682.c b/sound/soc/sdw_utils/soc_sdw_rt5682.c index 80b4caa926670f..8c86254cbaf640 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt5682.c +++ b/sound/soc/sdw_utils/soc_sdw_rt5682.c @@ -88,4 +88,4 @@ int asoc_sdw_rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_rt5682_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt5682_rtd_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_rt700.c b/sound/soc/sdw_utils/soc_sdw_rt700.c index 4dbeeeca343441..e6468e4ac6e726 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt700.c +++ b/sound/soc/sdw_utils/soc_sdw_rt700.c @@ -85,4 +85,4 @@ int asoc_sdw_rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_rt700_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt700_rtd_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_rt711.c b/sound/soc/sdw_utils/soc_sdw_rt711.c index 38b4126dd45f16..4aa93fdefef63a 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt711.c +++ b/sound/soc/sdw_utils/soc_sdw_rt711.c @@ -112,7 +112,7 @@ int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_rt711_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt711_rtd_init, "SND_SOC_SDW_UTILS"); int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -126,7 +126,7 @@ int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_ return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_rt711_exit, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt711_exit, "SND_SOC_SDW_UTILS"); int asoc_sdw_rt711_init(struct snd_soc_card *card, struct snd_soc_dai_link *dai_links, @@ -157,4 +157,4 @@ int asoc_sdw_rt711_init(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_rt711_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt711_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c deleted file mode 100644 index 5127210b9a03c1..00000000000000 --- a/sound/soc/sdw_utils/soc_sdw_rt712_sdca.c +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// This file incorporates work covered by the following copyright notice: -// Copyright (c) 2023 Intel Corporation -// Copyright (c) 2024 Advanced Micro Devices, Inc. - -/* - * soc_sdw_rt712_sdca - Helpers to handle RT712-SDCA from generic machine driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * dapm routes for rt712 spk will be registered dynamically according - * to the number of rt712 spk used. The first two entries will be registered - * for one codec case, and the last two entries are also registered - * if two rt712s are used. - */ -static const struct snd_soc_dapm_route rt712_spk_map[] = { - { "Speaker", NULL, "rt712 SPOL" }, - { "Speaker", NULL, "rt712 SPOR" }, -}; - -int asoc_sdw_rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:rt712", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_dapm_add_routes(&card->dapm, rt712_spk_map, ARRAY_SIZE(rt712_spk_map)); - if (ret) - dev_err(rtd->dev, "failed to add SPK map: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS(asoc_sdw_rt712_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c deleted file mode 100644 index 6a402172289fa2..00000000000000 --- a/sound/soc/sdw_utils/soc_sdw_rt722_sdca.c +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// This file incorporates work covered by the following copyright notice: -// Copyright (c) 2023 Intel Corporation -// Copyright (c) 2024 Advanced Micro Devices, Inc. - -/* - * soc_sdw_rt722_sdca - Helpers to handle RT722-SDCA from generic machine driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const struct snd_soc_dapm_route rt722_spk_map[] = { - { "Speaker", NULL, "rt722 SPK" }, -}; - -int asoc_sdw_rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:rt722", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_dapm_add_routes(&card->dapm, rt722_spk_map, ARRAY_SIZE(rt722_spk_map)); - if (ret) - dev_err(rtd->dev, "failed to add rt722 spk map: %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_NS(asoc_sdw_rt722_spk_rtd_init, SND_SOC_SDW_UTILS); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_amp.c b/sound/soc/sdw_utils/soc_sdw_rt_amp.c index 6951dfb5652632..0538c252ba69b1 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_amp.c @@ -210,7 +210,7 @@ int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_spk_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_spk_rtd_init, "SND_SOC_SDW_UTILS"); static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -248,7 +248,7 @@ static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, const struct snd_soc_ops soc_sdw_rt1308_i2s_ops = { .hw_params = rt1308_i2s_hw_params, }; -EXPORT_SYMBOL_NS(soc_sdw_rt1308_i2s_ops, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(soc_sdw_rt1308_i2s_ops, "SND_SOC_SDW_UTILS"); int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -266,7 +266,7 @@ int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_exit, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_exit, "SND_SOC_SDW_UTILS"); int asoc_sdw_rt_amp_init(struct snd_soc_card *card, struct snd_soc_dai_link *dai_links, @@ -309,4 +309,4 @@ int asoc_sdw_rt_amp_init(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_amp_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c index 7f24806d809d9d..46d917a99c51da 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt_dmic.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_dmic.c @@ -40,4 +40,4 @@ int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_da return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_rt_dmic_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_dmic_rtd_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c b/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c new file mode 100644 index 00000000000000..0161b14297d5a1 --- /dev/null +++ b/sound/soc/sdw_utils/soc_sdw_rt_mf_sdca.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only +// This file incorporates work covered by the following copyright notice: +// Copyright (c) 2024 Intel Corporation. + +/* + * soc_sdw_rt_mf_sdca + * - Helpers to handle RT Multifunction Codec from generic machine driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CODEC_NAME_SIZE 6 + +/* dapm routes for RT-SPK will be registered dynamically */ +static const struct snd_soc_dapm_route rt712_spk_map[] = { + { "Speaker", NULL, "rt712 SPOL" }, + { "Speaker", NULL, "rt712 SPOR" }, +}; + +static const struct snd_soc_dapm_route rt721_spk_map[] = { + { "Speaker", NULL, "rt721 SPK" }, +}; + +static const struct snd_soc_dapm_route rt722_spk_map[] = { + { "Speaker", NULL, "rt722 SPK" }, +}; + +/* Structure to map codec names to respective route arrays and sizes */ +struct codec_route_map { + const char *codec_name; + const struct snd_soc_dapm_route *route_map; + size_t route_size; +}; + +/* Codec route maps array */ +static const struct codec_route_map codec_routes[] = { + { "rt712", rt712_spk_map, ARRAY_SIZE(rt712_spk_map) }, + { "rt721", rt721_spk_map, ARRAY_SIZE(rt721_spk_map) }, + { "rt722", rt722_spk_map, ARRAY_SIZE(rt722_spk_map) }, +}; + +static const struct codec_route_map *get_codec_route_map(const char *codec_name) +{ + for (size_t i = 0; i < ARRAY_SIZE(codec_routes); i++) { + if (strcmp(codec_routes[i].codec_name, codec_name) == 0) + return &codec_routes[i]; + } + return NULL; +} + +int asoc_sdw_rt_mf_sdca_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) +{ + struct snd_soc_card *card = rtd->card; + char codec_name[CODEC_NAME_SIZE]; + int ret; + + /* acquire codec name */ + snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai->name); + + /* acquire corresponding route map and size */ + const struct codec_route_map *route_map = get_codec_route_map(codec_name); + + if (!route_map) { + dev_err(rtd->dev, "failed to get codec name and route map\n"); + return -EINVAL; + } + + /* Update card components */ + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "%s spk:%s", + card->components, codec_name); + if (!card->components) + return -ENOMEM; + + /* Add routes */ + ret = snd_soc_dapm_add_routes(&card->dapm, route_map->route_map, route_map->route_size); + if (ret) + dev_err(rtd->dev, "failed to add rt sdca spk map: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_NS(asoc_sdw_rt_mf_sdca_spk_rtd_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c index 3e6211dc1599a8..6279faf6edd488 100644 --- a/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c +++ b/sound/soc/sdw_utils/soc_sdw_rt_sdca_jack_common.c @@ -60,6 +60,11 @@ static const struct snd_soc_dapm_route rt713_sdca_map[] = { { "rt713 MIC2", NULL, "Headset Mic" }, }; +static const struct snd_soc_dapm_route rt721_sdca_map[] = { + { "Headphone", NULL, "rt721 HP" }, + { "rt721 MIC2", NULL, "Headset Mic" }, +}; + static const struct snd_soc_dapm_route rt722_sdca_map[] = { { "Headphone", NULL, "rt722 HP" }, { "rt722 MIC2", NULL, "Headset Mic" }, @@ -121,6 +126,9 @@ int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_s } else if (strstr(component->name_prefix, "rt713")) { ret = snd_soc_dapm_add_routes(&card->dapm, rt713_sdca_map, ARRAY_SIZE(rt713_sdca_map)); + } else if (strstr(component->name_prefix, "rt721")) { + ret = snd_soc_dapm_add_routes(&card->dapm, rt721_sdca_map, + ARRAY_SIZE(rt721_sdca_map)); } else if (strstr(component->name_prefix, "rt722")) { ret = snd_soc_dapm_add_routes(&card->dapm, rt722_sdca_map, ARRAY_SIZE(rt722_sdca_map)); @@ -162,7 +170,7 @@ int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_s return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_rtd_init, "SND_SOC_SDW_UTILS"); int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -180,7 +188,7 @@ int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_lin return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_exit, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_exit, "SND_SOC_SDW_UTILS"); int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card, struct snd_soc_dai_link *dai_links, @@ -211,4 +219,4 @@ int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index a6070f822eb9e4..937fa3ce59dfd6 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -138,14 +138,21 @@ struct asoc_sdw_codec_info codec_info_list[] = { .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_rt_amp_init, .exit = asoc_sdw_rt_amp_exit, - .rtd_init = asoc_sdw_rt712_spk_rtd_init, + .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, .controls = generic_spk_controls, .num_controls = ARRAY_SIZE(generic_spk_controls), .widgets = generic_spk_widgets, .num_widgets = ARRAY_SIZE(generic_spk_widgets), }, + { + .direction = {false, true}, + .dai_name = "rt712-sdca-aif3", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, }, - .dai_num = 2, + .dai_num = 3, }, { .part_id = 0x1712, @@ -178,8 +185,15 @@ struct asoc_sdw_codec_info codec_info_list[] = { .widgets = generic_jack_widgets, .num_widgets = ARRAY_SIZE(generic_jack_widgets), }, + { + .direction = {false, true}, + .dai_name = "rt712-sdca-aif3", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, }, - .dai_num = 1, + .dai_num = 2, }, { .part_id = 0x1713, @@ -333,6 +347,47 @@ struct asoc_sdw_codec_info codec_info_list[] = { }, .dai_num = 1, }, + { + .part_id = 0x721, + .version_id = 3, + .dais = { + { + .direction = {true, true}, + .dai_name = "rt721-sdca-aif1", + .dai_type = SOC_SDW_DAI_TYPE_JACK, + .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .init = asoc_sdw_rt_sdca_jack_init, + .exit = asoc_sdw_rt_sdca_jack_exit, + .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init, + .controls = generic_jack_controls, + .num_controls = ARRAY_SIZE(generic_jack_controls), + .widgets = generic_jack_widgets, + .num_widgets = ARRAY_SIZE(generic_jack_widgets), + }, + { + .direction = {true, false}, + .dai_name = "rt721-sdca-aif2", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + /* No feedback capability is provided by rt721-sdca codec driver*/ + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init = asoc_sdw_rt_amp_init, + .exit = asoc_sdw_rt_amp_exit, + .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, + .controls = generic_spk_controls, + .num_controls = ARRAY_SIZE(generic_spk_controls), + .widgets = generic_spk_widgets, + .num_widgets = ARRAY_SIZE(generic_spk_widgets), + }, + { + .direction = {false, true}, + .dai_name = "rt721-sdca-aif3", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init = asoc_sdw_rt_dmic_rtd_init, + }, + }, + .dai_num = 3, + }, { .part_id = 0x722, .version_id = 3, @@ -358,11 +413,13 @@ struct asoc_sdw_codec_info codec_info_list[] = { .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, .init = asoc_sdw_rt_amp_init, .exit = asoc_sdw_rt_amp_exit, - .rtd_init = asoc_sdw_rt722_spk_rtd_init, + .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init, .controls = generic_spk_controls, .num_controls = ARRAY_SIZE(generic_spk_controls), .widgets = generic_spk_widgets, .num_widgets = ARRAY_SIZE(generic_spk_widgets), + .quirk = SOC_SDW_CODEC_SPKR, + .quirk_exclude = true, }, { .direction = {false, true}, @@ -487,6 +544,8 @@ struct asoc_sdw_codec_info codec_info_list[] = { .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init, .widgets = generic_dmic_widgets, .num_widgets = ARRAY_SIZE(generic_dmic_widgets), + .quirk = SOC_SDW_CODEC_MIC, + .quirk_exclude = true, }, { .direction = {false, true}, @@ -563,13 +622,13 @@ struct asoc_sdw_codec_info codec_info_list[] = { .dai_num = 1, }, }; -EXPORT_SYMBOL_NS(codec_info_list, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS"); int asoc_sdw_get_codec_info_list_count(void) { return ARRAY_SIZE(codec_info_list); }; -EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS"); struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr) { @@ -590,7 +649,7 @@ struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr) return NULL; } -EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS"); struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id) { @@ -605,7 +664,7 @@ struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id) return NULL; } -EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, "SND_SOC_SDW_UTILS"); struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index) { @@ -622,7 +681,7 @@ struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, i return NULL; } -EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS"); int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) { @@ -686,14 +745,14 @@ int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, "SND_SOC_SDW_UTILS"); /* these wrappers are only needed to avoid typecast compilation errors */ int asoc_sdw_startup(struct snd_pcm_substream *substream) { return sdw_startup_stream(substream); } -EXPORT_SYMBOL_NS(asoc_sdw_startup, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_startup, "SND_SOC_SDW_UTILS"); int asoc_sdw_prepare(struct snd_pcm_substream *substream) { @@ -712,7 +771,7 @@ int asoc_sdw_prepare(struct snd_pcm_substream *substream) return sdw_prepare_stream(sdw_stream); } -EXPORT_SYMBOL_NS(asoc_sdw_prepare, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS"); int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd) { @@ -752,7 +811,7 @@ int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_trigger, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_trigger, "SND_SOC_SDW_UTILS"); int asoc_sdw_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -795,7 +854,7 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_hw_params, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_hw_params, "SND_SOC_SDW_UTILS"); int asoc_sdw_hw_free(struct snd_pcm_substream *substream) { @@ -814,13 +873,13 @@ int asoc_sdw_hw_free(struct snd_pcm_substream *substream) return sdw_deprepare_stream(sdw_stream); } -EXPORT_SYMBOL_NS(asoc_sdw_hw_free, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS"); void asoc_sdw_shutdown(struct snd_pcm_substream *substream) { sdw_shutdown_stream(substream); } -EXPORT_SYMBOL_NS(asoc_sdw_shutdown, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_shutdown, "SND_SOC_SDW_UTILS"); static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, unsigned int sdw_version, @@ -881,7 +940,7 @@ const char *asoc_sdw_get_codec_name(struct device *dev, return NULL; } -EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS"); /* helper to get the link that the codec DAI is used */ struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card, @@ -900,7 +959,7 @@ struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *ca } return NULL; } -EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, "SND_SOC_SDW_UTILS"); void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card) { @@ -933,7 +992,7 @@ void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card) } } } -EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, "SND_SOC_SDW_UTILS"); int asoc_sdw_card_late_probe(struct snd_soc_card *card) { @@ -949,22 +1008,24 @@ int asoc_sdw_card_late_probe(struct snd_soc_card *card) } return ret; } -EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, "SND_SOC_SDW_UTILS"); void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, int *be_id, char *name, int playback, int capture, struct snd_soc_dai_link_component *cpus, int cpus_num, struct snd_soc_dai_link_component *platform_component, int num_platforms, struct snd_soc_dai_link_component *codecs, - int codecs_num, int (*init)(struct snd_soc_pcm_runtime *rtd), + int codecs_num, int no_pcm, + int (*init)(struct snd_soc_pcm_runtime *rtd), const struct snd_soc_ops *ops) { dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); dai_links->id = (*be_id)++; dai_links->name = name; + dai_links->stream_name = name; dai_links->platforms = platform_component; dai_links->num_platforms = num_platforms; - dai_links->no_pcm = 1; + dai_links->no_pcm = no_pcm; dai_links->cpus = cpus; dai_links->num_cpus = cpus_num; dai_links->codecs = codecs; @@ -974,13 +1035,13 @@ void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_lin dai_links->init = init; dai_links->ops = ops; } -EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, "SND_SOC_SDW_UTILS"); int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, int *be_id, char *name, int playback, int capture, const char *cpu_dai_name, const char *platform_comp_name, int num_platforms, const char *codec_name, - const char *codec_dai_name, + const char *codec_dai_name, int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd), const struct snd_soc_ops *ops) { @@ -999,11 +1060,11 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture, &dlc[0], 1, &dlc[1], num_platforms, - &dlc[2], 1, init, ops); + &dlc[2], 1, no_pcm, init, ops); return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS"); int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) { @@ -1024,7 +1085,7 @@ int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int * return 0; } -EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, "SND_SOC_SDW_UTILS"); struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, const struct snd_soc_acpi_endpoint *new) @@ -1042,7 +1103,7 @@ struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks return dailinks; } -EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS"); int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, struct asoc_sdw_dailink *soc_dais, @@ -1112,7 +1173,8 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, dai_info = &codec_info->dais[adr_end->num]; soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); - if (dai_info->quirk && !(dai_info->quirk & ctx->mc_quirk)) + if (dai_info->quirk && + !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) continue; dev_dbg(dev, @@ -1164,7 +1226,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, return num_dais; } -EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, SND_SOC_SDW_UTILS); +EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, "SND_SOC_SDW_UTILS"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SoundWire ASoC helpers"); diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig deleted file mode 100644 index 426632996a0a31..00000000000000 --- a/sound/soc/sh/Kconfig +++ /dev/null @@ -1,76 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -menu "SoC Audio support for Renesas SoCs" - depends on SUPERH || ARCH_RENESAS || COMPILE_TEST - -config SND_SOC_PCM_SH7760 - tristate "SoC Audio support for Renesas SH7760" - depends on CPU_SUBTYPE_SH7760 && SH_DMABRG - help - Enable this option for SH7760 AC97/I2S audio support. - - -## -## Audio unit modules -## - -config SND_SOC_SH4_HAC - tristate - select AC97_BUS - select SND_SOC_AC97_BUS - -config SND_SOC_SH4_SSI - tristate - -config SND_SOC_SH4_FSI - tristate "SH4 FSI support" - depends on SUPERH || COMMON_CLK - select SND_SIMPLE_CARD - help - This option enables FSI sound support - -config SND_SOC_SH4_SIU - tristate - depends on ARCH_SHMOBILE && HAVE_CLK - depends on DMADEVICES - select DMA_ENGINE - select SH_DMAE - select FW_LOADER - -config SND_SOC_RCAR - tristate "R-Car series SRU/SCU/SSIU/SSI support" - depends on COMMON_CLK - depends on OF - select SND_SIMPLE_CARD_UTILS - select SND_DMAENGINE_PCM - select REGMAP_MMIO - help - This option enables R-Car SRU/SCU/SSIU/SSI sound support - -config SND_SOC_RZ - tristate "RZ/G2L series SSIF-2 support" - depends on ARCH_RZG2L || COMPILE_TEST - help - This option enables RZ/G2L SSIF-2 sound support. - -## -## Boards -## - -config SND_SH7760_AC97 - tristate "SH7760 AC97 sound support" - depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760 - select SND_SOC_SH4_HAC - select SND_SOC_AC97_CODEC - help - This option enables generic sound support for the first - AC97 unit of the SH7760. - -config SND_SIU_MIGOR - tristate "SIU sound support on Migo-R" - depends on SH_MIGOR && I2C - select SND_SOC_SH4_SIU - select SND_SOC_WM8978 - help - This option enables sound support for the SH7722 Migo-R board - -endmenu diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile deleted file mode 100644 index f0e19cbd1581b8..00000000000000 --- a/sound/soc/sh/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -## DMA engines -snd-soc-dma-sh7760-y := dma-sh7760.o -obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o - -## audio units found on some SH-4 -snd-soc-hac-y := hac.o -snd-soc-ssi-y := ssi.o -snd-soc-fsi-y := fsi.o -snd-soc-siu-y := siu_pcm.o siu_dai.o -obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o -obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o -obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o -obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o - -## audio units for R-Car -obj-$(CONFIG_SND_SOC_RCAR) += rcar/ - -## boards -snd-soc-sh7760-ac97-y := sh7760-ac97.o -snd-soc-migor-y := migor.o - -obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o -obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o - -# RZ/G2L -snd-soc-rz-ssi-y := rz-ssi.o -obj-$(CONFIG_SND_SOC_RZ) += snd-soc-rz-ssi.o diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c deleted file mode 100644 index c53539482c208b..00000000000000 --- a/sound/soc/sh/dma-sh7760.c +++ /dev/null @@ -1,334 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// SH7760 ("camelot") DMABRG audio DMA unit support -// -// Copyright (C) 2007 Manuel Lauss -// -// The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which -// trigger an interrupt when one half of the programmed transfer size -// has been xmitted. -// -// FIXME: little-endian only for now - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* registers and bits */ -#define BRGATXSAR 0x00 -#define BRGARXDAR 0x04 -#define BRGATXTCR 0x08 -#define BRGARXTCR 0x0C -#define BRGACR 0x10 -#define BRGATXTCNT 0x14 -#define BRGARXTCNT 0x18 - -#define ACR_RAR (1 << 18) -#define ACR_RDS (1 << 17) -#define ACR_RDE (1 << 16) -#define ACR_TAR (1 << 2) -#define ACR_TDS (1 << 1) -#define ACR_TDE (1 << 0) - -/* receiver/transmitter data alignment */ -#define ACR_RAM_NONE (0 << 24) -#define ACR_RAM_4BYTE (1 << 24) -#define ACR_RAM_2WORD (2 << 24) -#define ACR_TAM_NONE (0 << 8) -#define ACR_TAM_4BYTE (1 << 8) -#define ACR_TAM_2WORD (2 << 8) - - -struct camelot_pcm { - unsigned long mmio; /* DMABRG audio channel control reg MMIO */ - unsigned int txid; /* ID of first DMABRG IRQ for this unit */ - - struct snd_pcm_substream *tx_ss; - unsigned long tx_period_size; - unsigned int tx_period; - - struct snd_pcm_substream *rx_ss; - unsigned long rx_period_size; - unsigned int rx_period; - -} cam_pcm_data[2] = { - { - .mmio = 0xFE3C0040, - .txid = DMABRGIRQ_A0TXF, - }, - { - .mmio = 0xFE3C0060, - .txid = DMABRGIRQ_A1TXF, - }, -}; - -#define BRGREG(x) (*(unsigned long *)(cam->mmio + (x))) - -/* - * set a minimum of 16kb per period, to avoid interrupt-"storm" and - * resulting skipping. In general, the bigger the minimum size, the - * better for overall system performance. (The SH7760 is a puny CPU - * with a slow SDRAM interface and poor internal bus bandwidth, - * *especially* when the LCDC is active). The minimum for the DMAC - * is 8 bytes; 16kbytes are enough to get skip-free playback of a - * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain - * reasonable responsiveness in MPlayer. - */ -#define DMABRG_PERIOD_MIN 16 * 1024 -#define DMABRG_PERIOD_MAX 0x03fffffc -#define DMABRG_PREALLOC_BUFFER 32 * 1024 -#define DMABRG_PREALLOC_BUFFER_MAX 32 * 1024 - -static const struct snd_pcm_hardware camelot_pcm_hardware = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH), - .buffer_bytes_max = DMABRG_PERIOD_MAX, - .period_bytes_min = DMABRG_PERIOD_MIN, - .period_bytes_max = DMABRG_PERIOD_MAX / 2, - .periods_min = 2, - .periods_max = 2, - .fifo_size = 128, -}; - -static void camelot_txdma(void *data) -{ - struct camelot_pcm *cam = data; - cam->tx_period ^= 1; - snd_pcm_period_elapsed(cam->tx_ss); -} - -static void camelot_rxdma(void *data) -{ - struct camelot_pcm *cam = data; - cam->rx_period ^= 1; - snd_pcm_period_elapsed(cam->rx_ss); -} - -static int camelot_pcm_open(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; - int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; - int ret, dmairq; - - snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware); - - /* DMABRG buffer half/full events */ - dmairq = (recv) ? cam->txid + 2 : cam->txid; - if (recv) { - cam->rx_ss = substream; - ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam); - if (unlikely(ret)) { - pr_debug("audio unit %d irqs already taken!\n", - snd_soc_rtd_to_cpu(rtd, 0)->id); - return -EBUSY; - } - (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam); - } else { - cam->tx_ss = substream; - ret = dmabrg_request_irq(dmairq, camelot_txdma, cam); - if (unlikely(ret)) { - pr_debug("audio unit %d irqs already taken!\n", - snd_soc_rtd_to_cpu(rtd, 0)->id); - return -EBUSY; - } - (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam); - } - return 0; -} - -static int camelot_pcm_close(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; - int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; - int dmairq; - - dmairq = (recv) ? cam->txid + 2 : cam->txid; - - if (recv) - cam->rx_ss = NULL; - else - cam->tx_ss = NULL; - - dmabrg_free_irq(dmairq + 1); - dmabrg_free_irq(dmairq); - - return 0; -} - -static int camelot_hw_params(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; - int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; - - if (recv) { - cam->rx_period_size = params_period_bytes(hw_params); - cam->rx_period = 0; - } else { - cam->tx_period_size = params_period_bytes(hw_params); - cam->tx_period = 0; - } - return 0; -} - -static int camelot_prepare(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; - - pr_debug("PCM data: addr %pad len %zu\n", &runtime->dma_addr, - runtime->dma_bytes); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area; - BRGREG(BRGATXTCR) = runtime->dma_bytes; - } else { - BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area; - BRGREG(BRGARXTCR) = runtime->dma_bytes; - } - - return 0; -} - -static inline void dmabrg_play_dma_start(struct camelot_pcm *cam) -{ - unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS); - /* start DMABRG engine: XFER start, auto-addr-reload */ - BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD; -} - -static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam) -{ - unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS); - /* forcibly terminate data transmission */ - BRGREG(BRGACR) = acr | ACR_TDS; -} - -static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam) -{ - unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS); - /* start DMABRG engine: recv start, auto-reload */ - BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD; -} - -static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam) -{ - unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS); - /* forcibly terminate data receiver */ - BRGREG(BRGACR) = acr | ACR_RDS; -} - -static int camelot_trigger(struct snd_soc_component *component, - struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; - int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - if (recv) - dmabrg_rec_dma_start(cam); - else - dmabrg_play_dma_start(cam); - break; - case SNDRV_PCM_TRIGGER_STOP: - if (recv) - dmabrg_rec_dma_stop(cam); - else - dmabrg_play_dma_stop(cam); - break; - default: - return -EINVAL; - } - - return 0; -} - -static snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct camelot_pcm *cam = &cam_pcm_data[snd_soc_rtd_to_cpu(rtd, 0)->id]; - int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; - unsigned long pos; - - /* cannot use the DMABRG pointer register: under load, by the - * time ALSA comes around to read the register, it is already - * far ahead (or worse, already done with the fragment) of the - * position at the time the IRQ was triggered, which results in - * fast-playback sound in my test application (ScummVM) - */ - if (recv) - pos = cam->rx_period ? cam->rx_period_size : 0; - else - pos = cam->tx_period ? cam->tx_period_size : 0; - - return bytes_to_frames(runtime, pos); -} - -static int camelot_pcm_new(struct snd_soc_component *component, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_pcm *pcm = rtd->pcm; - - /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel - * in MMAP mode (i.e. aplay -M) - */ - snd_pcm_set_managed_buffer_all(pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - NULL, - DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX); - - return 0; -} - -static const struct snd_soc_component_driver sh7760_soc_component = { - .open = camelot_pcm_open, - .close = camelot_pcm_close, - .hw_params = camelot_hw_params, - .prepare = camelot_prepare, - .trigger = camelot_trigger, - .pointer = camelot_pos, - .pcm_construct = camelot_pcm_new, -}; - -static int sh7760_soc_platform_probe(struct platform_device *pdev) -{ - return devm_snd_soc_register_component(&pdev->dev, &sh7760_soc_component, - NULL, 0); -} - -static struct platform_driver sh7760_pcm_driver = { - .driver = { - .name = "sh7760-pcm-audio", - }, - - .probe = sh7760_soc_platform_probe, -}; - -module_platform_driver(sh7760_pcm_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver"); -MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c deleted file mode 100644 index 221ce91f195005..00000000000000 --- a/sound/soc/sh/fsi.c +++ /dev/null @@ -1,2119 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Fifo-attached Serial Interface (FSI) support for SH7724 -// -// Copyright (C) 2009 Renesas Solutions Corp. -// Kuninori Morimoto -// -// Based on ssi.c -// Copyright (c) 2007 Manuel Lauss - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* PortA/PortB register */ -#define REG_DO_FMT 0x0000 -#define REG_DOFF_CTL 0x0004 -#define REG_DOFF_ST 0x0008 -#define REG_DI_FMT 0x000C -#define REG_DIFF_CTL 0x0010 -#define REG_DIFF_ST 0x0014 -#define REG_CKG1 0x0018 -#define REG_CKG2 0x001C -#define REG_DIDT 0x0020 -#define REG_DODT 0x0024 -#define REG_MUTE_ST 0x0028 -#define REG_OUT_DMAC 0x002C -#define REG_OUT_SEL 0x0030 -#define REG_IN_DMAC 0x0038 - -/* master register */ -#define MST_CLK_RST 0x0210 -#define MST_SOFT_RST 0x0214 -#define MST_FIFO_SZ 0x0218 - -/* core register (depend on FSI version) */ -#define A_MST_CTLR 0x0180 -#define B_MST_CTLR 0x01A0 -#define CPU_INT_ST 0x01F4 -#define CPU_IEMSK 0x01F8 -#define CPU_IMSK 0x01FC -#define INT_ST 0x0200 -#define IEMSK 0x0204 -#define IMSK 0x0208 - -/* DO_FMT */ -/* DI_FMT */ -#define CR_BWS_MASK (0x3 << 20) /* FSI2 */ -#define CR_BWS_24 (0x0 << 20) /* FSI2 */ -#define CR_BWS_16 (0x1 << 20) /* FSI2 */ -#define CR_BWS_20 (0x2 << 20) /* FSI2 */ - -#define CR_DTMD_PCM (0x0 << 8) /* FSI2 */ -#define CR_DTMD_SPDIF_PCM (0x1 << 8) /* FSI2 */ -#define CR_DTMD_SPDIF_STREAM (0x2 << 8) /* FSI2 */ - -#define CR_MONO (0x0 << 4) -#define CR_MONO_D (0x1 << 4) -#define CR_PCM (0x2 << 4) -#define CR_I2S (0x3 << 4) -#define CR_TDM (0x4 << 4) -#define CR_TDM_D (0x5 << 4) - -/* OUT_DMAC */ -/* IN_DMAC */ -#define VDMD_MASK (0x3 << 4) -#define VDMD_FRONT (0x0 << 4) /* Package in front */ -#define VDMD_BACK (0x1 << 4) /* Package in back */ -#define VDMD_STREAM (0x2 << 4) /* Stream mode(16bit * 2) */ - -#define DMA_ON (0x1 << 0) - -/* DOFF_CTL */ -/* DIFF_CTL */ -#define IRQ_HALF 0x00100000 -#define FIFO_CLR 0x00000001 - -/* DOFF_ST */ -#define ERR_OVER 0x00000010 -#define ERR_UNDER 0x00000001 -#define ST_ERR (ERR_OVER | ERR_UNDER) - -/* CKG1 */ -#define ACKMD_MASK 0x00007000 -#define BPFMD_MASK 0x00000700 -#define DIMD (1 << 4) -#define DOMD (1 << 0) - -/* A/B MST_CTLR */ -#define BP (1 << 4) /* Fix the signal of Biphase output */ -#define SE (1 << 0) /* Fix the master clock */ - -/* CLK_RST */ -#define CRB (1 << 4) -#define CRA (1 << 0) - -/* IO SHIFT / MACRO */ -#define BI_SHIFT 12 -#define BO_SHIFT 8 -#define AI_SHIFT 4 -#define AO_SHIFT 0 -#define AB_IO(param, shift) (param << shift) - -/* SOFT_RST */ -#define PBSR (1 << 12) /* Port B Software Reset */ -#define PASR (1 << 8) /* Port A Software Reset */ -#define IR (1 << 4) /* Interrupt Reset */ -#define FSISR (1 << 0) /* Software Reset */ - -/* OUT_SEL (FSI2) */ -#define DMMD (1 << 4) /* SPDIF output timing 0: Biphase only */ - /* 1: Biphase and serial */ - -/* FIFO_SZ */ -#define FIFO_SZ_MASK 0x7 - -#define FSI_RATES SNDRV_PCM_RATE_8000_96000 - -#define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) - -/* - * bus options - * - * 0x000000BA - * - * A : sample widtht 16bit setting - * B : sample widtht 24bit setting - */ - -#define SHIFT_16DATA 0 -#define SHIFT_24DATA 4 - -#define PACKAGE_24BITBUS_BACK 0 -#define PACKAGE_24BITBUS_FRONT 1 -#define PACKAGE_16BITBUS_STREAM 2 - -#define BUSOP_SET(s, a) ((a) << SHIFT_ ## s ## DATA) -#define BUSOP_GET(s, a) (((a) >> SHIFT_ ## s ## DATA) & 0xF) - -/* - * FSI driver use below type name for variable - * - * xxx_num : number of data - * xxx_pos : position of data - * xxx_capa : capacity of data - */ - -/* - * period/frame/sample image - * - * ex) PCM (2ch) - * - * period pos period pos - * [n] [n + 1] - * |<-------------------- period--------------------->| - * ==|============================================ ... =|== - * | | - * ||<----- frame ----->|<------ frame ----->| ... | - * |+--------------------+--------------------+- ... | - * ||[ sample ][ sample ]|[ sample ][ sample ]| ... | - * |+--------------------+--------------------+- ... | - * ==|============================================ ... =|== - */ - -/* - * FSI FIFO image - * - * | | - * | | - * | [ sample ] | - * | [ sample ] | - * | [ sample ] | - * | [ sample ] | - * --> go to codecs - */ - -/* - * FSI clock - * - * FSIxCLK [CPG] (ick) -------> | - * |-> FSI_DIV (div)-> FSI2 - * FSIxCK [external] (xck) ---> | - */ - -/* - * struct - */ - -struct fsi_stream_handler; -struct fsi_stream { - - /* - * these are initialized by fsi_stream_init() - */ - struct snd_pcm_substream *substream; - int fifo_sample_capa; /* sample capacity of FSI FIFO */ - int buff_sample_capa; /* sample capacity of ALSA buffer */ - int buff_sample_pos; /* sample position of ALSA buffer */ - int period_samples; /* sample number / 1 period */ - int period_pos; /* current period position */ - int sample_width; /* sample width */ - int uerr_num; - int oerr_num; - - /* - * bus options - */ - u32 bus_option; - - /* - * these are initialized by fsi_handler_init() - */ - struct fsi_stream_handler *handler; - struct fsi_priv *priv; - - /* - * these are for DMAEngine - */ - struct dma_chan *chan; - int dma_id; -}; - -struct fsi_clk { - /* see [FSI clock] */ - struct clk *own; - struct clk *xck; - struct clk *ick; - struct clk *div; - int (*set_rate)(struct device *dev, - struct fsi_priv *fsi); - - unsigned long rate; - unsigned int count; -}; - -struct fsi_priv { - void __iomem *base; - phys_addr_t phys; - struct fsi_master *master; - - struct fsi_stream playback; - struct fsi_stream capture; - - struct fsi_clk clock; - - u32 fmt; - - int chan_num:16; - unsigned int clk_master:1; - unsigned int clk_cpg:1; - unsigned int spdif:1; - unsigned int enable_stream:1; - unsigned int bit_clk_inv:1; - unsigned int lr_clk_inv:1; -}; - -struct fsi_stream_handler { - int (*init)(struct fsi_priv *fsi, struct fsi_stream *io); - int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io); - int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev); - int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); - int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); - int (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io, - int enable); -}; -#define fsi_stream_handler_call(io, func, args...) \ - (!(io) ? -ENODEV : \ - !((io)->handler->func) ? 0 : \ - (io)->handler->func(args)) - -struct fsi_core { - int ver; - - u32 int_st; - u32 iemsk; - u32 imsk; - u32 a_mclk; - u32 b_mclk; -}; - -struct fsi_master { - void __iomem *base; - struct fsi_priv fsia; - struct fsi_priv fsib; - const struct fsi_core *core; - spinlock_t lock; -}; - -static inline int fsi_stream_is_play(struct fsi_priv *fsi, - struct fsi_stream *io) -{ - return &fsi->playback == io; -} - - -/* - * basic read write function - */ - -static void __fsi_reg_write(u32 __iomem *reg, u32 data) -{ - /* valid data area is 24bit */ - data &= 0x00ffffff; - - __raw_writel(data, reg); -} - -static u32 __fsi_reg_read(u32 __iomem *reg) -{ - return __raw_readl(reg); -} - -static void __fsi_reg_mask_set(u32 __iomem *reg, u32 mask, u32 data) -{ - u32 val = __fsi_reg_read(reg); - - val &= ~mask; - val |= data & mask; - - __fsi_reg_write(reg, val); -} - -#define fsi_reg_write(p, r, d)\ - __fsi_reg_write((p->base + REG_##r), d) - -#define fsi_reg_read(p, r)\ - __fsi_reg_read((p->base + REG_##r)) - -#define fsi_reg_mask_set(p, r, m, d)\ - __fsi_reg_mask_set((p->base + REG_##r), m, d) - -#define fsi_master_read(p, r) _fsi_master_read(p, MST_##r) -#define fsi_core_read(p, r) _fsi_master_read(p, p->core->r) -static u32 _fsi_master_read(struct fsi_master *master, u32 reg) -{ - u32 ret; - unsigned long flags; - - spin_lock_irqsave(&master->lock, flags); - ret = __fsi_reg_read(master->base + reg); - spin_unlock_irqrestore(&master->lock, flags); - - return ret; -} - -#define fsi_master_mask_set(p, r, m, d) _fsi_master_mask_set(p, MST_##r, m, d) -#define fsi_core_mask_set(p, r, m, d) _fsi_master_mask_set(p, p->core->r, m, d) -static void _fsi_master_mask_set(struct fsi_master *master, - u32 reg, u32 mask, u32 data) -{ - unsigned long flags; - - spin_lock_irqsave(&master->lock, flags); - __fsi_reg_mask_set(master->base + reg, mask, data); - spin_unlock_irqrestore(&master->lock, flags); -} - -/* - * basic function - */ -static int fsi_version(struct fsi_master *master) -{ - return master->core->ver; -} - -static struct fsi_master *fsi_get_master(struct fsi_priv *fsi) -{ - return fsi->master; -} - -static int fsi_is_clk_master(struct fsi_priv *fsi) -{ - return fsi->clk_master; -} - -static int fsi_is_port_a(struct fsi_priv *fsi) -{ - return fsi->master->base == fsi->base; -} - -static int fsi_is_spdif(struct fsi_priv *fsi) -{ - return fsi->spdif; -} - -static int fsi_is_enable_stream(struct fsi_priv *fsi) -{ - return fsi->enable_stream; -} - -static int fsi_is_play(struct snd_pcm_substream *substream) -{ - return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; -} - -static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - - return snd_soc_rtd_to_cpu(rtd, 0); -} - -static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai) -{ - struct fsi_master *master = snd_soc_dai_get_drvdata(dai); - - if (dai->id == 0) - return &master->fsia; - else - return &master->fsib; -} - -static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) -{ - return fsi_get_priv_frm_dai(fsi_get_dai(substream)); -} - -static u32 fsi_get_port_shift(struct fsi_priv *fsi, struct fsi_stream *io) -{ - int is_play = fsi_stream_is_play(fsi, io); - int is_porta = fsi_is_port_a(fsi); - u32 shift; - - if (is_porta) - shift = is_play ? AO_SHIFT : AI_SHIFT; - else - shift = is_play ? BO_SHIFT : BI_SHIFT; - - return shift; -} - -static int fsi_frame2sample(struct fsi_priv *fsi, int frames) -{ - return frames * fsi->chan_num; -} - -static int fsi_sample2frame(struct fsi_priv *fsi, int samples) -{ - return samples / fsi->chan_num; -} - -static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, - struct fsi_stream *io) -{ - int is_play = fsi_stream_is_play(fsi, io); - u32 status; - int frames; - - status = is_play ? - fsi_reg_read(fsi, DOFF_ST) : - fsi_reg_read(fsi, DIFF_ST); - - frames = 0x1ff & (status >> 8); - - return fsi_frame2sample(fsi, frames); -} - -static void fsi_count_fifo_err(struct fsi_priv *fsi) -{ - u32 ostatus = fsi_reg_read(fsi, DOFF_ST); - u32 istatus = fsi_reg_read(fsi, DIFF_ST); - - if (ostatus & ERR_OVER) - fsi->playback.oerr_num++; - - if (ostatus & ERR_UNDER) - fsi->playback.uerr_num++; - - if (istatus & ERR_OVER) - fsi->capture.oerr_num++; - - if (istatus & ERR_UNDER) - fsi->capture.uerr_num++; - - fsi_reg_write(fsi, DOFF_ST, 0); - fsi_reg_write(fsi, DIFF_ST, 0); -} - -/* - * fsi_stream_xx() function - */ -static inline struct fsi_stream *fsi_stream_get(struct fsi_priv *fsi, - struct snd_pcm_substream *substream) -{ - return fsi_is_play(substream) ? &fsi->playback : &fsi->capture; -} - -static int fsi_stream_is_working(struct fsi_priv *fsi, - struct fsi_stream *io) -{ - struct fsi_master *master = fsi_get_master(fsi); - unsigned long flags; - int ret; - - spin_lock_irqsave(&master->lock, flags); - ret = !!(io->substream && io->substream->runtime); - spin_unlock_irqrestore(&master->lock, flags); - - return ret; -} - -static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io) -{ - return io->priv; -} - -static void fsi_stream_init(struct fsi_priv *fsi, - struct fsi_stream *io, - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct fsi_master *master = fsi_get_master(fsi); - unsigned long flags; - - spin_lock_irqsave(&master->lock, flags); - io->substream = substream; - io->buff_sample_capa = fsi_frame2sample(fsi, runtime->buffer_size); - io->buff_sample_pos = 0; - io->period_samples = fsi_frame2sample(fsi, runtime->period_size); - io->period_pos = 0; - io->sample_width = samples_to_bytes(runtime, 1); - io->bus_option = 0; - io->oerr_num = -1; /* ignore 1st err */ - io->uerr_num = -1; /* ignore 1st err */ - fsi_stream_handler_call(io, init, fsi, io); - spin_unlock_irqrestore(&master->lock, flags); -} - -static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io) -{ - struct snd_soc_dai *dai = fsi_get_dai(io->substream); - struct fsi_master *master = fsi_get_master(fsi); - unsigned long flags; - - spin_lock_irqsave(&master->lock, flags); - - if (io->oerr_num > 0) - dev_err(dai->dev, "over_run = %d\n", io->oerr_num); - - if (io->uerr_num > 0) - dev_err(dai->dev, "under_run = %d\n", io->uerr_num); - - fsi_stream_handler_call(io, quit, fsi, io); - io->substream = NULL; - io->buff_sample_capa = 0; - io->buff_sample_pos = 0; - io->period_samples = 0; - io->period_pos = 0; - io->sample_width = 0; - io->bus_option = 0; - io->oerr_num = 0; - io->uerr_num = 0; - spin_unlock_irqrestore(&master->lock, flags); -} - -static int fsi_stream_transfer(struct fsi_stream *io) -{ - struct fsi_priv *fsi = fsi_stream_to_priv(io); - if (!fsi) - return -EIO; - - return fsi_stream_handler_call(io, transfer, fsi, io); -} - -#define fsi_stream_start(fsi, io)\ - fsi_stream_handler_call(io, start_stop, fsi, io, 1) - -#define fsi_stream_stop(fsi, io)\ - fsi_stream_handler_call(io, start_stop, fsi, io, 0) - -static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev) -{ - struct fsi_stream *io; - int ret1, ret2; - - io = &fsi->playback; - ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev); - - io = &fsi->capture; - ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev); - - if (ret1 < 0) - return ret1; - if (ret2 < 0) - return ret2; - - return 0; -} - -static int fsi_stream_remove(struct fsi_priv *fsi) -{ - struct fsi_stream *io; - int ret1, ret2; - - io = &fsi->playback; - ret1 = fsi_stream_handler_call(io, remove, fsi, io); - - io = &fsi->capture; - ret2 = fsi_stream_handler_call(io, remove, fsi, io); - - if (ret1 < 0) - return ret1; - if (ret2 < 0) - return ret2; - - return 0; -} - -/* - * format/bus/dma setting - */ -static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io, - u32 bus, struct device *dev) -{ - struct fsi_master *master = fsi_get_master(fsi); - int is_play = fsi_stream_is_play(fsi, io); - u32 fmt = fsi->fmt; - - if (fsi_version(master) >= 2) { - u32 dma = 0; - - /* - * FSI2 needs DMA/Bus setting - */ - switch (bus) { - case PACKAGE_24BITBUS_FRONT: - fmt |= CR_BWS_24; - dma |= VDMD_FRONT; - dev_dbg(dev, "24bit bus / package in front\n"); - break; - case PACKAGE_16BITBUS_STREAM: - fmt |= CR_BWS_16; - dma |= VDMD_STREAM; - dev_dbg(dev, "16bit bus / stream mode\n"); - break; - case PACKAGE_24BITBUS_BACK: - default: - fmt |= CR_BWS_24; - dma |= VDMD_BACK; - dev_dbg(dev, "24bit bus / package in back\n"); - break; - } - - if (is_play) - fsi_reg_write(fsi, OUT_DMAC, dma); - else - fsi_reg_write(fsi, IN_DMAC, dma); - } - - if (is_play) - fsi_reg_write(fsi, DO_FMT, fmt); - else - fsi_reg_write(fsi, DI_FMT, fmt); -} - -/* - * irq function - */ - -static void fsi_irq_enable(struct fsi_priv *fsi, struct fsi_stream *io) -{ - u32 data = AB_IO(1, fsi_get_port_shift(fsi, io)); - struct fsi_master *master = fsi_get_master(fsi); - - fsi_core_mask_set(master, imsk, data, data); - fsi_core_mask_set(master, iemsk, data, data); -} - -static void fsi_irq_disable(struct fsi_priv *fsi, struct fsi_stream *io) -{ - u32 data = AB_IO(1, fsi_get_port_shift(fsi, io)); - struct fsi_master *master = fsi_get_master(fsi); - - fsi_core_mask_set(master, imsk, data, 0); - fsi_core_mask_set(master, iemsk, data, 0); -} - -static u32 fsi_irq_get_status(struct fsi_master *master) -{ - return fsi_core_read(master, int_st); -} - -static void fsi_irq_clear_status(struct fsi_priv *fsi) -{ - u32 data = 0; - struct fsi_master *master = fsi_get_master(fsi); - - data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->playback)); - data |= AB_IO(1, fsi_get_port_shift(fsi, &fsi->capture)); - - /* clear interrupt factor */ - fsi_core_mask_set(master, int_st, data, 0); -} - -/* - * SPDIF master clock function - * - * These functions are used later FSI2 - */ -static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) -{ - struct fsi_master *master = fsi_get_master(fsi); - u32 mask, val; - - mask = BP | SE; - val = enable ? mask : 0; - - fsi_is_port_a(fsi) ? - fsi_core_mask_set(master, a_mclk, mask, val) : - fsi_core_mask_set(master, b_mclk, mask, val); -} - -/* - * clock function - */ -static int fsi_clk_init(struct device *dev, - struct fsi_priv *fsi, - int xck, - int ick, - int div, - int (*set_rate)(struct device *dev, - struct fsi_priv *fsi)) -{ - struct fsi_clk *clock = &fsi->clock; - int is_porta = fsi_is_port_a(fsi); - - clock->xck = NULL; - clock->ick = NULL; - clock->div = NULL; - clock->rate = 0; - clock->count = 0; - clock->set_rate = set_rate; - - clock->own = devm_clk_get(dev, NULL); - if (IS_ERR(clock->own)) - return -EINVAL; - - /* external clock */ - if (xck) { - clock->xck = devm_clk_get(dev, is_porta ? "xcka" : "xckb"); - if (IS_ERR(clock->xck)) { - dev_err(dev, "can't get xck clock\n"); - return -EINVAL; - } - if (clock->xck == clock->own) { - dev_err(dev, "cpu doesn't support xck clock\n"); - return -EINVAL; - } - } - - /* FSIACLK/FSIBCLK */ - if (ick) { - clock->ick = devm_clk_get(dev, is_porta ? "icka" : "ickb"); - if (IS_ERR(clock->ick)) { - dev_err(dev, "can't get ick clock\n"); - return -EINVAL; - } - if (clock->ick == clock->own) { - dev_err(dev, "cpu doesn't support ick clock\n"); - return -EINVAL; - } - } - - /* FSI-DIV */ - if (div) { - clock->div = devm_clk_get(dev, is_porta ? "diva" : "divb"); - if (IS_ERR(clock->div)) { - dev_err(dev, "can't get div clock\n"); - return -EINVAL; - } - if (clock->div == clock->own) { - dev_err(dev, "cpu doesn't support div clock\n"); - return -EINVAL; - } - } - - return 0; -} - -#define fsi_clk_invalid(fsi) fsi_clk_valid(fsi, 0) -static void fsi_clk_valid(struct fsi_priv *fsi, unsigned long rate) -{ - fsi->clock.rate = rate; -} - -static int fsi_clk_is_valid(struct fsi_priv *fsi) -{ - return fsi->clock.set_rate && - fsi->clock.rate; -} - -static int fsi_clk_enable(struct device *dev, - struct fsi_priv *fsi) -{ - struct fsi_clk *clock = &fsi->clock; - int ret = -EINVAL; - - if (!fsi_clk_is_valid(fsi)) - return ret; - - if (0 == clock->count) { - ret = clock->set_rate(dev, fsi); - if (ret < 0) { - fsi_clk_invalid(fsi); - return ret; - } - - ret = clk_enable(clock->xck); - if (ret) - goto err; - ret = clk_enable(clock->ick); - if (ret) - goto disable_xck; - ret = clk_enable(clock->div); - if (ret) - goto disable_ick; - - clock->count++; - } - - return ret; - -disable_ick: - clk_disable(clock->ick); -disable_xck: - clk_disable(clock->xck); -err: - return ret; -} - -static int fsi_clk_disable(struct device *dev, - struct fsi_priv *fsi) -{ - struct fsi_clk *clock = &fsi->clock; - - if (!fsi_clk_is_valid(fsi)) - return -EINVAL; - - if (1 == clock->count--) { - clk_disable(clock->xck); - clk_disable(clock->ick); - clk_disable(clock->div); - } - - return 0; -} - -static int fsi_clk_set_ackbpf(struct device *dev, - struct fsi_priv *fsi, - int ackmd, int bpfmd) -{ - u32 data = 0; - - /* check ackmd/bpfmd relationship */ - if (bpfmd > ackmd) { - dev_err(dev, "unsupported rate (%d/%d)\n", ackmd, bpfmd); - return -EINVAL; - } - - /* ACKMD */ - switch (ackmd) { - case 512: - data |= (0x0 << 12); - break; - case 256: - data |= (0x1 << 12); - break; - case 128: - data |= (0x2 << 12); - break; - case 64: - data |= (0x3 << 12); - break; - case 32: - data |= (0x4 << 12); - break; - default: - dev_err(dev, "unsupported ackmd (%d)\n", ackmd); - return -EINVAL; - } - - /* BPFMD */ - switch (bpfmd) { - case 32: - data |= (0x0 << 8); - break; - case 64: - data |= (0x1 << 8); - break; - case 128: - data |= (0x2 << 8); - break; - case 256: - data |= (0x3 << 8); - break; - case 512: - data |= (0x4 << 8); - break; - case 16: - data |= (0x7 << 8); - break; - default: - dev_err(dev, "unsupported bpfmd (%d)\n", bpfmd); - return -EINVAL; - } - - dev_dbg(dev, "ACKMD/BPFMD = %d/%d\n", ackmd, bpfmd); - - fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); - udelay(10); - - return 0; -} - -static int fsi_clk_set_rate_external(struct device *dev, - struct fsi_priv *fsi) -{ - struct clk *xck = fsi->clock.xck; - struct clk *ick = fsi->clock.ick; - unsigned long rate = fsi->clock.rate; - unsigned long xrate; - int ackmd, bpfmd; - int ret = 0; - - /* check clock rate */ - xrate = clk_get_rate(xck); - if (xrate % rate) { - dev_err(dev, "unsupported clock rate\n"); - return -EINVAL; - } - - clk_set_parent(ick, xck); - clk_set_rate(ick, xrate); - - bpfmd = fsi->chan_num * 32; - ackmd = xrate / rate; - - dev_dbg(dev, "external/rate = %ld/%ld\n", xrate, rate); - - ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); - if (ret < 0) - dev_err(dev, "%s failed", __func__); - - return ret; -} - -static int fsi_clk_set_rate_cpg(struct device *dev, - struct fsi_priv *fsi) -{ - struct clk *ick = fsi->clock.ick; - struct clk *div = fsi->clock.div; - unsigned long rate = fsi->clock.rate; - unsigned long target = 0; /* 12288000 or 11289600 */ - unsigned long actual, cout; - unsigned long diff, min; - unsigned long best_cout, best_act; - int adj; - int ackmd, bpfmd; - int ret = -EINVAL; - - if (!(12288000 % rate)) - target = 12288000; - if (!(11289600 % rate)) - target = 11289600; - if (!target) { - dev_err(dev, "unsupported rate\n"); - return ret; - } - - bpfmd = fsi->chan_num * 32; - ackmd = target / rate; - ret = fsi_clk_set_ackbpf(dev, fsi, ackmd, bpfmd); - if (ret < 0) { - dev_err(dev, "%s failed", __func__); - return ret; - } - - /* - * The clock flow is - * - * [CPG] = cout => [FSI_DIV] = audio => [FSI] => [codec] - * - * But, it needs to find best match of CPG and FSI_DIV - * combination, since it is difficult to generate correct - * frequency of audio clock from ick clock only. - * Because ick is created from its parent clock. - * - * target = rate x [512/256/128/64]fs - * cout = round(target x adjustment) - * actual = cout / adjustment (by FSI-DIV) ~= target - * audio = actual - */ - min = ~0; - best_cout = 0; - best_act = 0; - for (adj = 1; adj < 0xffff; adj++) { - - cout = target * adj; - if (cout > 100000000) /* max clock = 100MHz */ - break; - - /* cout/actual audio clock */ - cout = clk_round_rate(ick, cout); - actual = cout / adj; - - /* find best frequency */ - diff = abs(actual - target); - if (diff < min) { - min = diff; - best_cout = cout; - best_act = actual; - } - } - - ret = clk_set_rate(ick, best_cout); - if (ret < 0) { - dev_err(dev, "ick clock failed\n"); - return -EIO; - } - - ret = clk_set_rate(div, clk_round_rate(div, best_act)); - if (ret < 0) { - dev_err(dev, "div clock failed\n"); - return -EIO; - } - - dev_dbg(dev, "ick/div = %ld/%ld\n", - clk_get_rate(ick), clk_get_rate(div)); - - return ret; -} - -static void fsi_pointer_update(struct fsi_stream *io, int size) -{ - io->buff_sample_pos += size; - - if (io->buff_sample_pos >= - io->period_samples * (io->period_pos + 1)) { - struct snd_pcm_substream *substream = io->substream; - struct snd_pcm_runtime *runtime = substream->runtime; - - io->period_pos++; - - if (io->period_pos >= runtime->periods) { - io->buff_sample_pos = 0; - io->period_pos = 0; - } - - snd_pcm_period_elapsed(substream); - } -} - -/* - * pio data transfer handler - */ -static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples) -{ - int i; - - if (fsi_is_enable_stream(fsi)) { - /* - * stream mode - * see - * fsi_pio_push_init() - */ - u32 *buf = (u32 *)_buf; - - for (i = 0; i < samples / 2; i++) - fsi_reg_write(fsi, DODT, buf[i]); - } else { - /* normal mode */ - u16 *buf = (u16 *)_buf; - - for (i = 0; i < samples; i++) - fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8)); - } -} - -static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples) -{ - u16 *buf = (u16 *)_buf; - int i; - - for (i = 0; i < samples; i++) - *(buf + i) = (u16)(fsi_reg_read(fsi, DIDT) >> 8); -} - -static void fsi_pio_push32(struct fsi_priv *fsi, u8 *_buf, int samples) -{ - u32 *buf = (u32 *)_buf; - int i; - - for (i = 0; i < samples; i++) - fsi_reg_write(fsi, DODT, *(buf + i)); -} - -static void fsi_pio_pop32(struct fsi_priv *fsi, u8 *_buf, int samples) -{ - u32 *buf = (u32 *)_buf; - int i; - - for (i = 0; i < samples; i++) - *(buf + i) = fsi_reg_read(fsi, DIDT); -} - -static u8 *fsi_pio_get_area(struct fsi_priv *fsi, struct fsi_stream *io) -{ - struct snd_pcm_runtime *runtime = io->substream->runtime; - - return runtime->dma_area + - samples_to_bytes(runtime, io->buff_sample_pos); -} - -static int fsi_pio_transfer(struct fsi_priv *fsi, struct fsi_stream *io, - void (*run16)(struct fsi_priv *fsi, u8 *buf, int samples), - void (*run32)(struct fsi_priv *fsi, u8 *buf, int samples), - int samples) -{ - u8 *buf; - - if (!fsi_stream_is_working(fsi, io)) - return -EINVAL; - - buf = fsi_pio_get_area(fsi, io); - - switch (io->sample_width) { - case 2: - run16(fsi, buf, samples); - break; - case 4: - run32(fsi, buf, samples); - break; - default: - return -EINVAL; - } - - fsi_pointer_update(io, samples); - - return 0; -} - -static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io) -{ - int sample_residues; /* samples in FSI fifo */ - int sample_space; /* ALSA free samples space */ - int samples; - - sample_residues = fsi_get_current_fifo_samples(fsi, io); - sample_space = io->buff_sample_capa - io->buff_sample_pos; - - samples = min(sample_residues, sample_space); - - return fsi_pio_transfer(fsi, io, - fsi_pio_pop16, - fsi_pio_pop32, - samples); -} - -static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io) -{ - int sample_residues; /* ALSA residue samples */ - int sample_space; /* FSI fifo free samples space */ - int samples; - - sample_residues = io->buff_sample_capa - io->buff_sample_pos; - sample_space = io->fifo_sample_capa - - fsi_get_current_fifo_samples(fsi, io); - - samples = min(sample_residues, sample_space); - - return fsi_pio_transfer(fsi, io, - fsi_pio_push16, - fsi_pio_push32, - samples); -} - -static int fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, - int enable) -{ - struct fsi_master *master = fsi_get_master(fsi); - u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; - - if (enable) - fsi_irq_enable(fsi, io); - else - fsi_irq_disable(fsi, io); - - if (fsi_is_clk_master(fsi)) - fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); - - return 0; -} - -static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io) -{ - /* - * we can use 16bit stream mode - * when "playback" and "16bit data" - * and platform allows "stream mode" - * see - * fsi_pio_push16() - */ - if (fsi_is_enable_stream(fsi)) - io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | - BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); - else - io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | - BUSOP_SET(16, PACKAGE_24BITBUS_BACK); - return 0; -} - -static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io) -{ - /* - * always 24bit bus, package back when "capture" - */ - io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | - BUSOP_SET(16, PACKAGE_24BITBUS_BACK); - return 0; -} - -static struct fsi_stream_handler fsi_pio_push_handler = { - .init = fsi_pio_push_init, - .transfer = fsi_pio_push, - .start_stop = fsi_pio_start_stop, -}; - -static struct fsi_stream_handler fsi_pio_pop_handler = { - .init = fsi_pio_pop_init, - .transfer = fsi_pio_pop, - .start_stop = fsi_pio_start_stop, -}; - -static irqreturn_t fsi_interrupt(int irq, void *data) -{ - struct fsi_master *master = data; - u32 int_st = fsi_irq_get_status(master); - - /* clear irq status */ - fsi_master_mask_set(master, SOFT_RST, IR, 0); - fsi_master_mask_set(master, SOFT_RST, IR, IR); - - if (int_st & AB_IO(1, AO_SHIFT)) - fsi_stream_transfer(&master->fsia.playback); - if (int_st & AB_IO(1, BO_SHIFT)) - fsi_stream_transfer(&master->fsib.playback); - if (int_st & AB_IO(1, AI_SHIFT)) - fsi_stream_transfer(&master->fsia.capture); - if (int_st & AB_IO(1, BI_SHIFT)) - fsi_stream_transfer(&master->fsib.capture); - - fsi_count_fifo_err(&master->fsia); - fsi_count_fifo_err(&master->fsib); - - fsi_irq_clear_status(&master->fsia); - fsi_irq_clear_status(&master->fsib); - - return IRQ_HANDLED; -} - -/* - * dma data transfer handler - */ -static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) -{ - /* - * 24bit data : 24bit bus / package in back - * 16bit data : 16bit bus / stream mode - */ - io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | - BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); - - return 0; -} - -static void fsi_dma_complete(void *data) -{ - struct fsi_stream *io = (struct fsi_stream *)data; - struct fsi_priv *fsi = fsi_stream_to_priv(io); - - fsi_pointer_update(io, io->period_samples); - - fsi_count_fifo_err(fsi); -} - -static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) -{ - struct snd_soc_dai *dai = fsi_get_dai(io->substream); - struct snd_pcm_substream *substream = io->substream; - struct dma_async_tx_descriptor *desc; - int is_play = fsi_stream_is_play(fsi, io); - enum dma_transfer_direction dir; - int ret = -EIO; - - if (is_play) - dir = DMA_MEM_TO_DEV; - else - dir = DMA_DEV_TO_MEM; - - desc = dmaengine_prep_dma_cyclic(io->chan, - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), - dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_err(dai->dev, "dmaengine_prep_dma_cyclic() fail\n"); - goto fsi_dma_transfer_err; - } - - desc->callback = fsi_dma_complete; - desc->callback_param = io; - - if (dmaengine_submit(desc) < 0) { - dev_err(dai->dev, "tx_submit() fail\n"); - goto fsi_dma_transfer_err; - } - - dma_async_issue_pending(io->chan); - - /* - * FIXME - * - * In DMAEngine case, codec and FSI cannot be started simultaneously - * since FSI is using the scheduler work queue. - * Therefore, in capture case, probably FSI FIFO will have got - * overflow error in this point. - * in that case, DMA cannot start transfer until error was cleared. - */ - if (!is_play) { - if (ERR_OVER & fsi_reg_read(fsi, DIFF_ST)) { - fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); - fsi_reg_write(fsi, DIFF_ST, 0); - } - } - - ret = 0; - -fsi_dma_transfer_err: - return ret; -} - -static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, - int start) -{ - struct fsi_master *master = fsi_get_master(fsi); - u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; - u32 enable = start ? DMA_ON : 0; - - fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable); - - dmaengine_terminate_all(io->chan); - - if (fsi_is_clk_master(fsi)) - fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); - - return 0; -} - -static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) -{ - int is_play = fsi_stream_is_play(fsi, io); - -#ifdef CONFIG_SUPERH - dma_cap_mask_t mask; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - io->chan = dma_request_channel(mask, shdma_chan_filter, - (void *)io->dma_id); -#else - io->chan = dma_request_chan(dev, is_play ? "tx" : "rx"); - if (IS_ERR(io->chan)) - io->chan = NULL; -#endif - if (io->chan) { - struct dma_slave_config cfg = {}; - int ret; - - if (is_play) { - cfg.dst_addr = fsi->phys + REG_DODT; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.direction = DMA_MEM_TO_DEV; - } else { - cfg.src_addr = fsi->phys + REG_DIDT; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.direction = DMA_DEV_TO_MEM; - } - - ret = dmaengine_slave_config(io->chan, &cfg); - if (ret < 0) { - dma_release_channel(io->chan); - io->chan = NULL; - } - } - - if (!io->chan) { - - /* switch to PIO handler */ - if (is_play) - fsi->playback.handler = &fsi_pio_push_handler; - else - fsi->capture.handler = &fsi_pio_pop_handler; - - dev_info(dev, "switch handler (dma => pio)\n"); - - /* probe again */ - return fsi_stream_probe(fsi, dev); - } - - return 0; -} - -static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io) -{ - fsi_stream_stop(fsi, io); - - if (io->chan) - dma_release_channel(io->chan); - - io->chan = NULL; - return 0; -} - -static struct fsi_stream_handler fsi_dma_push_handler = { - .init = fsi_dma_init, - .probe = fsi_dma_probe, - .transfer = fsi_dma_transfer, - .remove = fsi_dma_remove, - .start_stop = fsi_dma_push_start_stop, -}; - -/* - * dai ops - */ -static void fsi_fifo_init(struct fsi_priv *fsi, - struct fsi_stream *io, - struct device *dev) -{ - struct fsi_master *master = fsi_get_master(fsi); - int is_play = fsi_stream_is_play(fsi, io); - u32 shift, i; - int frame_capa; - - /* get on-chip RAM capacity */ - shift = fsi_master_read(master, FIFO_SZ); - shift >>= fsi_get_port_shift(fsi, io); - shift &= FIFO_SZ_MASK; - frame_capa = 256 << shift; - dev_dbg(dev, "fifo = %d words\n", frame_capa); - - /* - * The maximum number of sample data varies depending - * on the number of channels selected for the format. - * - * FIFOs are used in 4-channel units in 3-channel mode - * and in 8-channel units in 5- to 7-channel mode - * meaning that more FIFOs than the required size of DPRAM - * are used. - * - * ex) if 256 words of DP-RAM is connected - * 1 channel: 256 (256 x 1 = 256) - * 2 channels: 128 (128 x 2 = 256) - * 3 channels: 64 ( 64 x 3 = 192) - * 4 channels: 64 ( 64 x 4 = 256) - * 5 channels: 32 ( 32 x 5 = 160) - * 6 channels: 32 ( 32 x 6 = 192) - * 7 channels: 32 ( 32 x 7 = 224) - * 8 channels: 32 ( 32 x 8 = 256) - */ - for (i = 1; i < fsi->chan_num; i <<= 1) - frame_capa >>= 1; - dev_dbg(dev, "%d channel %d store\n", - fsi->chan_num, frame_capa); - - io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); - - /* - * set interrupt generation factor - * clear FIFO - */ - if (is_play) { - fsi_reg_write(fsi, DOFF_CTL, IRQ_HALF); - fsi_reg_mask_set(fsi, DOFF_CTL, FIFO_CLR, FIFO_CLR); - } else { - fsi_reg_write(fsi, DIFF_CTL, IRQ_HALF); - fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR); - } -} - -static int fsi_hw_startup(struct fsi_priv *fsi, - struct fsi_stream *io, - struct device *dev) -{ - u32 data = 0; - - /* clock setting */ - if (fsi_is_clk_master(fsi)) - data = DIMD | DOMD; - - fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); - - /* clock inversion (CKG2) */ - data = 0; - if (fsi->bit_clk_inv) - data |= (1 << 0); - if (fsi->lr_clk_inv) - data |= (1 << 4); - if (fsi_is_clk_master(fsi)) - data <<= 8; - fsi_reg_write(fsi, CKG2, data); - - /* spdif ? */ - if (fsi_is_spdif(fsi)) { - fsi_spdif_clk_ctrl(fsi, 1); - fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); - } - - /* - * get bus settings - */ - data = 0; - switch (io->sample_width) { - case 2: - data = BUSOP_GET(16, io->bus_option); - break; - case 4: - data = BUSOP_GET(24, io->bus_option); - break; - } - fsi_format_bus_setup(fsi, io, data, dev); - - /* irq clear */ - fsi_irq_disable(fsi, io); - fsi_irq_clear_status(fsi); - - /* fifo init */ - fsi_fifo_init(fsi, io, dev); - - /* start master clock */ - if (fsi_is_clk_master(fsi)) - return fsi_clk_enable(dev, fsi); - - return 0; -} - -static int fsi_hw_shutdown(struct fsi_priv *fsi, - struct device *dev) -{ - /* stop master clock */ - if (fsi_is_clk_master(fsi)) - return fsi_clk_disable(dev, fsi); - - return 0; -} - -static int fsi_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct fsi_priv *fsi = fsi_get_priv(substream); - - fsi_clk_invalid(fsi); - - return 0; -} - -static void fsi_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct fsi_priv *fsi = fsi_get_priv(substream); - - fsi_clk_invalid(fsi); -} - -static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct fsi_priv *fsi = fsi_get_priv(substream); - struct fsi_stream *io = fsi_stream_get(fsi, substream); - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - fsi_stream_init(fsi, io, substream); - if (!ret) - ret = fsi_hw_startup(fsi, io, dai->dev); - if (!ret) - ret = fsi_stream_start(fsi, io); - if (!ret) - ret = fsi_stream_transfer(io); - break; - case SNDRV_PCM_TRIGGER_STOP: - if (!ret) - ret = fsi_hw_shutdown(fsi, dai->dev); - fsi_stream_stop(fsi, io); - fsi_stream_quit(fsi, io); - break; - } - - return ret; -} - -static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) -{ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - fsi->fmt = CR_I2S; - fsi->chan_num = 2; - break; - case SND_SOC_DAIFMT_LEFT_J: - fsi->fmt = CR_PCM; - fsi->chan_num = 2; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int fsi_set_fmt_spdif(struct fsi_priv *fsi) -{ - struct fsi_master *master = fsi_get_master(fsi); - - if (fsi_version(master) < 2) - return -EINVAL; - - fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM; - fsi->chan_num = 2; - - return 0; -} - -static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); - int ret; - - /* set clock master audio interface */ - switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_BC_FC: - break; - case SND_SOC_DAIFMT_BP_FP: - fsi->clk_master = 1; /* cpu is master */ - break; - default: - return -EINVAL; - } - - /* set clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_IF: - fsi->bit_clk_inv = 0; - fsi->lr_clk_inv = 1; - break; - case SND_SOC_DAIFMT_IB_NF: - fsi->bit_clk_inv = 1; - fsi->lr_clk_inv = 0; - break; - case SND_SOC_DAIFMT_IB_IF: - fsi->bit_clk_inv = 1; - fsi->lr_clk_inv = 1; - break; - case SND_SOC_DAIFMT_NB_NF: - default: - fsi->bit_clk_inv = 0; - fsi->lr_clk_inv = 0; - break; - } - - if (fsi_is_clk_master(fsi)) { - if (fsi->clk_cpg) - fsi_clk_init(dai->dev, fsi, 0, 1, 1, - fsi_clk_set_rate_cpg); - else - fsi_clk_init(dai->dev, fsi, 1, 1, 0, - fsi_clk_set_rate_external); - } - - /* set format */ - if (fsi_is_spdif(fsi)) - ret = fsi_set_fmt_spdif(fsi); - else - ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK); - - return ret; -} - -static int fsi_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct fsi_priv *fsi = fsi_get_priv(substream); - - if (fsi_is_clk_master(fsi)) - fsi_clk_valid(fsi, params_rate(params)); - - return 0; -} - -/* - * Select below from Sound Card, not auto - * SND_SOC_DAIFMT_CBC_CFC - * SND_SOC_DAIFMT_CBP_CFP - */ -static const u64 fsi_dai_formats = - SND_SOC_POSSIBLE_DAIFMT_I2S | - SND_SOC_POSSIBLE_DAIFMT_LEFT_J | - SND_SOC_POSSIBLE_DAIFMT_NB_NF | - SND_SOC_POSSIBLE_DAIFMT_NB_IF | - SND_SOC_POSSIBLE_DAIFMT_IB_NF | - SND_SOC_POSSIBLE_DAIFMT_IB_IF; - -static const struct snd_soc_dai_ops fsi_dai_ops = { - .startup = fsi_dai_startup, - .shutdown = fsi_dai_shutdown, - .trigger = fsi_dai_trigger, - .set_fmt = fsi_dai_set_fmt, - .hw_params = fsi_dai_hw_params, - .auto_selectable_formats = &fsi_dai_formats, - .num_auto_selectable_formats = 1, -}; - -/* - * pcm ops - */ - -static const struct snd_pcm_hardware fsi_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID, - .buffer_bytes_max = 64 * 1024, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 32, - .fifo_size = 256, -}; - -static int fsi_pcm_open(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &fsi_pcm_hardware); - - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - - return ret; -} - -static snd_pcm_uframes_t fsi_pointer(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct fsi_priv *fsi = fsi_get_priv(substream); - struct fsi_stream *io = fsi_stream_get(fsi, substream); - - return fsi_sample2frame(fsi, io->buff_sample_pos); -} - -/* - * snd_soc_component - */ - -#define PREALLOC_BUFFER (32 * 1024) -#define PREALLOC_BUFFER_MAX (32 * 1024) - -static int fsi_pcm_new(struct snd_soc_component *component, - struct snd_soc_pcm_runtime *rtd) -{ - snd_pcm_set_managed_buffer_all( - rtd->pcm, - SNDRV_DMA_TYPE_DEV, - rtd->card->snd_card->dev, - PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); - return 0; -} - -/* - * alsa struct - */ - -static struct snd_soc_dai_driver fsi_soc_dai[] = { - { - .name = "fsia-dai", - .playback = { - .rates = FSI_RATES, - .formats = FSI_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .capture = { - .rates = FSI_RATES, - .formats = FSI_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .ops = &fsi_dai_ops, - }, - { - .name = "fsib-dai", - .playback = { - .rates = FSI_RATES, - .formats = FSI_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .capture = { - .rates = FSI_RATES, - .formats = FSI_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .ops = &fsi_dai_ops, - }, -}; - -static const struct snd_soc_component_driver fsi_soc_component = { - .name = "fsi", - .open = fsi_pcm_open, - .pointer = fsi_pointer, - .pcm_construct = fsi_pcm_new, -}; - -/* - * platform function - */ -static void fsi_of_parse(char *name, - struct device_node *np, - struct sh_fsi_port_info *info, - struct device *dev) -{ - int i; - char prop[128]; - unsigned long flags = 0; - struct { - char *name; - unsigned int val; - } of_parse_property[] = { - { "spdif-connection", SH_FSI_FMT_SPDIF }, - { "stream-mode-support", SH_FSI_ENABLE_STREAM_MODE }, - { "use-internal-clock", SH_FSI_CLK_CPG }, - }; - - for (i = 0; i < ARRAY_SIZE(of_parse_property); i++) { - sprintf(prop, "%s,%s", name, of_parse_property[i].name); - if (of_property_present(np, prop)) - flags |= of_parse_property[i].val; - } - info->flags = flags; - - dev_dbg(dev, "%s flags : %lx\n", name, info->flags); -} - -static void fsi_port_info_init(struct fsi_priv *fsi, - struct sh_fsi_port_info *info) -{ - if (info->flags & SH_FSI_FMT_SPDIF) - fsi->spdif = 1; - - if (info->flags & SH_FSI_CLK_CPG) - fsi->clk_cpg = 1; - - if (info->flags & SH_FSI_ENABLE_STREAM_MODE) - fsi->enable_stream = 1; -} - -static void fsi_handler_init(struct fsi_priv *fsi, - struct sh_fsi_port_info *info) -{ - fsi->playback.handler = &fsi_pio_push_handler; /* default PIO */ - fsi->playback.priv = fsi; - fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ - fsi->capture.priv = fsi; - - if (info->tx_id) { - fsi->playback.dma_id = info->tx_id; - fsi->playback.handler = &fsi_dma_push_handler; - } -} - -static const struct fsi_core fsi1_core = { - .ver = 1, - - /* Interrupt */ - .int_st = INT_ST, - .iemsk = IEMSK, - .imsk = IMSK, -}; - -static const struct fsi_core fsi2_core = { - .ver = 2, - - /* Interrupt */ - .int_st = CPU_INT_ST, - .iemsk = CPU_IEMSK, - .imsk = CPU_IMSK, - .a_mclk = A_MST_CTLR, - .b_mclk = B_MST_CTLR, -}; - -static const struct of_device_id fsi_of_match[] = { - { .compatible = "renesas,sh_fsi", .data = &fsi1_core}, - { .compatible = "renesas,sh_fsi2", .data = &fsi2_core}, - {}, -}; -MODULE_DEVICE_TABLE(of, fsi_of_match); - -static const struct platform_device_id fsi_id_table[] = { - { "sh_fsi", (kernel_ulong_t)&fsi1_core }, - {}, -}; -MODULE_DEVICE_TABLE(platform, fsi_id_table); - -static int fsi_probe(struct platform_device *pdev) -{ - struct fsi_master *master; - struct device_node *np = pdev->dev.of_node; - struct sh_fsi_platform_info info; - const struct fsi_core *core; - struct fsi_priv *fsi; - struct resource *res; - unsigned int irq; - int ret; - - memset(&info, 0, sizeof(info)); - - core = NULL; - if (np) { - core = of_device_get_match_data(&pdev->dev); - fsi_of_parse("fsia", np, &info.port_a, &pdev->dev); - fsi_of_parse("fsib", np, &info.port_b, &pdev->dev); - } else { - const struct platform_device_id *id_entry = pdev->id_entry; - if (id_entry) - core = (struct fsi_core *)id_entry->driver_data; - - if (pdev->dev.platform_data) - memcpy(&info, pdev->dev.platform_data, sizeof(info)); - } - - if (!core) { - dev_err(&pdev->dev, "unknown fsi device\n"); - return -ENODEV; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || (int)irq <= 0) { - dev_err(&pdev->dev, "Not enough FSI platform resources.\n"); - return -ENODEV; - } - - master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL); - if (!master) - return -ENOMEM; - - master->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!master->base) { - dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n"); - return -ENXIO; - } - - /* master setting */ - master->core = core; - spin_lock_init(&master->lock); - - /* FSI A setting */ - fsi = &master->fsia; - fsi->base = master->base; - fsi->phys = res->start; - fsi->master = master; - fsi_port_info_init(fsi, &info.port_a); - fsi_handler_init(fsi, &info.port_a); - ret = fsi_stream_probe(fsi, &pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, "FSIA stream probe failed\n"); - return ret; - } - - /* FSI B setting */ - fsi = &master->fsib; - fsi->base = master->base + 0x40; - fsi->phys = res->start + 0x40; - fsi->master = master; - fsi_port_info_init(fsi, &info.port_b); - fsi_handler_init(fsi, &info.port_b); - ret = fsi_stream_probe(fsi, &pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, "FSIB stream probe failed\n"); - goto exit_fsia; - } - - pm_runtime_enable(&pdev->dev); - dev_set_drvdata(&pdev->dev, master); - - ret = devm_request_irq(&pdev->dev, irq, &fsi_interrupt, 0, - dev_name(&pdev->dev), master); - if (ret) { - dev_err(&pdev->dev, "irq request err\n"); - goto exit_fsib; - } - - ret = devm_snd_soc_register_component(&pdev->dev, &fsi_soc_component, - fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); - if (ret < 0) { - dev_err(&pdev->dev, "cannot snd component register\n"); - goto exit_fsib; - } - - return ret; - -exit_fsib: - pm_runtime_disable(&pdev->dev); - fsi_stream_remove(&master->fsib); -exit_fsia: - fsi_stream_remove(&master->fsia); - - return ret; -} - -static void fsi_remove(struct platform_device *pdev) -{ - struct fsi_master *master; - - master = dev_get_drvdata(&pdev->dev); - - pm_runtime_disable(&pdev->dev); - - fsi_stream_remove(&master->fsia); - fsi_stream_remove(&master->fsib); -} - -static void __fsi_suspend(struct fsi_priv *fsi, - struct fsi_stream *io, - struct device *dev) -{ - if (!fsi_stream_is_working(fsi, io)) - return; - - fsi_stream_stop(fsi, io); - fsi_hw_shutdown(fsi, dev); -} - -static void __fsi_resume(struct fsi_priv *fsi, - struct fsi_stream *io, - struct device *dev) -{ - if (!fsi_stream_is_working(fsi, io)) - return; - - fsi_hw_startup(fsi, io, dev); - fsi_stream_start(fsi, io); -} - -static int fsi_suspend(struct device *dev) -{ - struct fsi_master *master = dev_get_drvdata(dev); - struct fsi_priv *fsia = &master->fsia; - struct fsi_priv *fsib = &master->fsib; - - __fsi_suspend(fsia, &fsia->playback, dev); - __fsi_suspend(fsia, &fsia->capture, dev); - - __fsi_suspend(fsib, &fsib->playback, dev); - __fsi_suspend(fsib, &fsib->capture, dev); - - return 0; -} - -static int fsi_resume(struct device *dev) -{ - struct fsi_master *master = dev_get_drvdata(dev); - struct fsi_priv *fsia = &master->fsia; - struct fsi_priv *fsib = &master->fsib; - - __fsi_resume(fsia, &fsia->playback, dev); - __fsi_resume(fsia, &fsia->capture, dev); - - __fsi_resume(fsib, &fsib->playback, dev); - __fsi_resume(fsib, &fsib->capture, dev); - - return 0; -} - -static const struct dev_pm_ops fsi_pm_ops = { - .suspend = fsi_suspend, - .resume = fsi_resume, -}; - -static struct platform_driver fsi_driver = { - .driver = { - .name = "fsi-pcm-audio", - .pm = &fsi_pm_ops, - .of_match_table = fsi_of_match, - }, - .probe = fsi_probe, - .remove = fsi_remove, - .id_table = fsi_id_table, -}; - -module_platform_driver(fsi_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("SuperH onchip FSI audio driver"); -MODULE_AUTHOR("Kuninori Morimoto "); -MODULE_ALIAS("platform:fsi-pcm-audio"); diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c deleted file mode 100644 index db618c09d1e040..00000000000000 --- a/sound/soc/sh/hac.c +++ /dev/null @@ -1,344 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Hitachi Audio Controller (AC97) support for SH7760/SH7780 -// -// Copyright (c) 2007 Manuel Lauss -// -// dont forget to set IPSEL/OMSEL register bits (in your board code) to -// enable HAC output pins! - -/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only - * the FIRST can be used since ASoC does not pass any information to the - * ac97_read/write() functions regarding WHICH unit to use. You'll have - * to edit the code a bit to use the other AC97 unit. --mlau - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* regs and bits */ -#define HACCR 0x08 -#define HACCSAR 0x20 -#define HACCSDR 0x24 -#define HACPCML 0x28 -#define HACPCMR 0x2C -#define HACTIER 0x50 -#define HACTSR 0x54 -#define HACRIER 0x58 -#define HACRSR 0x5C -#define HACACR 0x60 - -#define CR_CR (1 << 15) /* "codec-ready" indicator */ -#define CR_CDRT (1 << 11) /* cold reset */ -#define CR_WMRT (1 << 10) /* warm reset */ -#define CR_B9 (1 << 9) /* the mysterious "bit 9" */ -#define CR_ST (1 << 5) /* AC97 link start bit */ - -#define CSAR_RD (1 << 19) /* AC97 data read bit */ -#define CSAR_WR (0) - -#define TSR_CMDAMT (1 << 31) -#define TSR_CMDDMT (1 << 30) - -#define RSR_STARY (1 << 22) -#define RSR_STDRY (1 << 21) - -#define ACR_DMARX16 (1 << 30) -#define ACR_DMATX16 (1 << 29) -#define ACR_TX12ATOM (1 << 26) -#define ACR_DMARX20 ((1 << 24) | (1 << 22)) -#define ACR_DMATX20 ((1 << 23) | (1 << 21)) - -#define CSDR_SHIFT 4 -#define CSDR_MASK (0xffff << CSDR_SHIFT) -#define CSAR_SHIFT 12 -#define CSAR_MASK (0x7f << CSAR_SHIFT) - -#define AC97_WRITE_RETRY 1 -#define AC97_READ_RETRY 5 - -/* manual-suggested AC97 codec access timeouts (us) */ -#define TMO_E1 500 /* 21 < E1 < 1000 */ -#define TMO_E2 13 /* 13 < E2 */ -#define TMO_E3 21 /* 21 < E3 */ -#define TMO_E4 500 /* 21 < E4 < 1000 */ - -struct hac_priv { - unsigned long mmio; /* HAC base address */ -} hac_cpu_data[] = { -#if defined(CONFIG_CPU_SUBTYPE_SH7760) - { - .mmio = 0xFE240000, - }, - { - .mmio = 0xFE250000, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) - { - .mmio = 0xFFE40000, - }, -#else -#error "Unsupported SuperH SoC" -#endif -}; - -#define HACREG(reg) (*(unsigned long *)(hac->mmio + (reg))) - -/* - * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906) - */ -static int hac_get_codec_data(struct hac_priv *hac, unsigned short r, - unsigned short *v) -{ - unsigned int to1, to2, i; - unsigned short adr; - - for (i = AC97_READ_RETRY; i; i--) { - *v = 0; - /* wait for HAC to receive something from the codec */ - for (to1 = TMO_E4; - to1 && !(HACREG(HACRSR) & RSR_STARY); - --to1) - udelay(1); - for (to2 = TMO_E4; - to2 && !(HACREG(HACRSR) & RSR_STDRY); - --to2) - udelay(1); - - if (!to1 && !to2) - return 0; /* codec comm is down */ - - adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT); - *v = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT); - - HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY); - - if (r == adr) - break; - - /* manual says: wait at least 21 usec before retrying */ - udelay(21); - } - HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY); - return i; -} - -static unsigned short hac_read_codec_aux(struct hac_priv *hac, - unsigned short reg) -{ - unsigned short val; - unsigned int i, to; - - for (i = AC97_READ_RETRY; i; i--) { - /* send_read_request */ - local_irq_disable(); - HACREG(HACTSR) &= ~(TSR_CMDAMT); - HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD; - local_irq_enable(); - - for (to = TMO_E3; - to && !(HACREG(HACTSR) & TSR_CMDAMT); - --to) - udelay(1); - - HACREG(HACTSR) &= ~TSR_CMDAMT; - val = 0; - if (hac_get_codec_data(hac, reg, &val) != 0) - break; - } - - return i ? val : ~0; -} - -static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - int unit_id = 0 /* ac97->private_data */; - struct hac_priv *hac = &hac_cpu_data[unit_id]; - unsigned int i, to; - /* write_codec_aux */ - for (i = AC97_WRITE_RETRY; i; i--) { - /* send_write_request */ - local_irq_disable(); - HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT); - HACREG(HACCSDR) = (val << CSDR_SHIFT); - HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD); - local_irq_enable(); - - /* poll-wait for CMDAMT and CMDDMT */ - for (to = TMO_E1; - to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT)); - --to) - udelay(1); - - HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT); - if (to) - break; - /* timeout, try again */ - } -} - -static unsigned short hac_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - int unit_id = 0 /* ac97->private_data */; - struct hac_priv *hac = &hac_cpu_data[unit_id]; - return hac_read_codec_aux(hac, reg); -} - -static void hac_ac97_warmrst(struct snd_ac97 *ac97) -{ - int unit_id = 0 /* ac97->private_data */; - struct hac_priv *hac = &hac_cpu_data[unit_id]; - unsigned int tmo; - - HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9; - msleep(10); - HACREG(HACCR) = CR_ST | CR_B9; - for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--) - udelay(1); - - if (!tmo) - printk(KERN_INFO "hac: reset: AC97 link down!\n"); - /* settings this bit lets us have a conversation with codec */ - HACREG(HACACR) |= ACR_TX12ATOM; -} - -static void hac_ac97_coldrst(struct snd_ac97 *ac97) -{ - int unit_id = 0 /* ac97->private_data */; - struct hac_priv *hac; - hac = &hac_cpu_data[unit_id]; - - HACREG(HACCR) = 0; - HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9; - msleep(10); - hac_ac97_warmrst(ac97); -} - -static struct snd_ac97_bus_ops hac_ac97_ops = { - .read = hac_ac97_read, - .write = hac_ac97_write, - .reset = hac_ac97_coldrst, - .warm_reset = hac_ac97_warmrst, -}; - -static int hac_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct hac_priv *hac = &hac_cpu_data[dai->id]; - int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - - switch (params->msbits) { - case 16: - HACREG(HACACR) |= d ? ACR_DMARX16 : ACR_DMATX16; - HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20; - break; - case 20: - HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16; - HACREG(HACACR) |= d ? ACR_DMARX20 : ACR_DMATX20; - break; - default: - pr_debug("hac: invalid depth %d bit\n", params->msbits); - return -EINVAL; - break; - } - - return 0; -} - -#define AC97_RATES \ - SNDRV_PCM_RATE_8000_192000 - -#define AC97_FMTS \ - SNDRV_PCM_FMTBIT_S16_LE - -static const struct snd_soc_dai_ops hac_dai_ops = { - .hw_params = hac_hw_params, -}; - -static struct snd_soc_dai_driver sh4_hac_dai[] = { -{ - .name = "hac-dai.0", - .playback = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .capture = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .ops = &hac_dai_ops, -}, -#ifdef CONFIG_CPU_SUBTYPE_SH7760 -{ - .name = "hac-dai.1", - .id = 1, - .playback = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .capture = { - .rates = AC97_RATES, - .formats = AC97_FMTS, - .channels_min = 2, - .channels_max = 2, - }, - .ops = &hac_dai_ops, - -}, -#endif -}; - -static const struct snd_soc_component_driver sh4_hac_component = { - .name = "sh4-hac", - .legacy_dai_naming = 1, -}; - -static int hac_soc_platform_probe(struct platform_device *pdev) -{ - int ret; - - ret = snd_soc_set_ac97_ops(&hac_ac97_ops); - if (ret != 0) - return ret; - - return devm_snd_soc_register_component(&pdev->dev, &sh4_hac_component, - sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); -} - -static void hac_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_set_ac97_ops(NULL); -} - -static struct platform_driver hac_pcm_driver = { - .driver = { - .name = "hac-pcm-audio", - }, - - .probe = hac_soc_platform_probe, - .remove = hac_soc_platform_remove, -}; - -module_platform_driver(hac_pcm_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver"); -MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c deleted file mode 100644 index 5a0bc6edac0a07..00000000000000 --- a/sound/soc/sh/migor.c +++ /dev/null @@ -1,205 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ALSA SoC driver for Migo-R -// -// Copyright (C) 2009-2010 Guennadi Liakhovetski - -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#include "../codecs/wm8978.h" -#include "siu.h" - -/* Default 8000Hz sampling frequency */ -static unsigned long codec_freq = 8000 * 512; - -static unsigned int use_count; - -/* External clock, sourced from the codec at the SIUMCKB pin */ -static unsigned long siumckb_recalc(struct clk *clk) -{ - return codec_freq; -} - -static struct sh_clk_ops siumckb_clk_ops = { - .recalc = siumckb_recalc, -}; - -static struct clk siumckb_clk = { - .ops = &siumckb_clk_ops, - .rate = 0, /* initialised at run-time */ -}; - -static struct clk_lookup *siumckb_lookup; - -static int migor_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - unsigned int rate = params_rate(params); - - ret = snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 13000000, - SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8978_OPCLKRATE, rate * 512); - if (ret < 0) - return ret; - - codec_freq = rate * 512; - /* - * This propagates the parent frequency change to children and - * recalculates the frequency table - */ - clk_set_rate(&siumckb_clk, codec_freq); - dev_dbg(codec_dai->dev, "%s: configure %luHz\n", __func__, codec_freq); - - ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), SIU_CLKB_EXT, - codec_freq / 2, SND_SOC_CLOCK_IN); - - if (!ret) - use_count++; - - return ret; -} - -static int migor_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - - if (use_count) { - use_count--; - - if (!use_count) - snd_soc_dai_set_sysclk(codec_dai, WM8978_PLL, 0, - SND_SOC_CLOCK_IN); - } else { - dev_dbg(codec_dai->dev, "Unbalanced hw_free!\n"); - } - - return 0; -} - -static const struct snd_soc_ops migor_dai_ops = { - .hw_params = migor_hw_params, - .hw_free = migor_hw_free, -}; - -static const struct snd_soc_dapm_widget migor_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Onboard Microphone", NULL), - SND_SOC_DAPM_MIC("External Microphone", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* Headphone output connected to LHP/RHP, enable OUT4 for VMID */ - { "Headphone", NULL, "OUT4 VMID" }, - { "OUT4 VMID", NULL, "LHP" }, - { "OUT4 VMID", NULL, "RHP" }, - - /* On-board microphone */ - { "RMICN", NULL, "Mic Bias" }, - { "RMICP", NULL, "Mic Bias" }, - { "Mic Bias", NULL, "Onboard Microphone" }, - - /* External microphone */ - { "LMICN", NULL, "Mic Bias" }, - { "LMICP", NULL, "Mic Bias" }, - { "Mic Bias", NULL, "External Microphone" }, -}; - -/* migor digital audio interface glue - connects codec <--> CPU */ -SND_SOC_DAILINK_DEFS(wm8978, - DAILINK_COMP_ARRAY(COMP_CPU("siu-pcm-audio")), - DAILINK_COMP_ARRAY(COMP_CODEC("wm8978.0-001a", "wm8978-hifi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("siu-pcm-audio"))); - -static struct snd_soc_dai_link migor_dai = { - .name = "wm8978", - .stream_name = "WM8978", - .dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBS_CFS, - .ops = &migor_dai_ops, - SND_SOC_DAILINK_REG(wm8978), -}; - -/* migor audio machine driver */ -static struct snd_soc_card snd_soc_migor = { - .name = "Migo-R", - .owner = THIS_MODULE, - .dai_link = &migor_dai, - .num_links = 1, - - .dapm_widgets = migor_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(migor_dapm_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), -}; - -static struct platform_device *migor_snd_device; - -static int __init migor_init(void) -{ - int ret; - - ret = clk_register(&siumckb_clk); - if (ret < 0) - return ret; - - siumckb_lookup = clkdev_create(&siumckb_clk, "siumckb_clk", NULL); - if (!siumckb_lookup) { - ret = -ENOMEM; - goto eclkdevalloc; - } - - /* Port number used on this machine: port B */ - migor_snd_device = platform_device_alloc("soc-audio", 1); - if (!migor_snd_device) { - ret = -ENOMEM; - goto epdevalloc; - } - - platform_set_drvdata(migor_snd_device, &snd_soc_migor); - - ret = platform_device_add(migor_snd_device); - if (ret) - goto epdevadd; - - return 0; - -epdevadd: - platform_device_put(migor_snd_device); -epdevalloc: - clkdev_drop(siumckb_lookup); -eclkdevalloc: - clk_unregister(&siumckb_clk); - return ret; -} - -static void __exit migor_exit(void) -{ - clkdev_drop(siumckb_lookup); - clk_unregister(&siumckb_clk); - platform_device_unregister(migor_snd_device); -} - -module_init(migor_init); -module_exit(migor_exit); - -MODULE_AUTHOR("Guennadi Liakhovetski "); -MODULE_DESCRIPTION("ALSA SoC Migor"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile deleted file mode 100644 index 45eb875a912a66..00000000000000 --- a/sound/soc/sh/rcar/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -snd-soc-rcar-y := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o debugfs.o -obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c deleted file mode 100644 index 0f190abf00e756..00000000000000 --- a/sound/soc/sh/rcar/adg.c +++ /dev/null @@ -1,775 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Helper routines for R-Car sound ADG. -// -// Copyright (C) 2013 Kuninori Morimoto -#include -#include -#include "rsnd.h" - -#define CLKA 0 -#define CLKB 1 -#define CLKC 2 -#define CLKI 3 -#define CLKINMAX 4 - -#define CLKOUT 0 -#define CLKOUT1 1 -#define CLKOUT2 2 -#define CLKOUT3 3 -#define CLKOUTMAX 4 - -#define BRRx_MASK(x) (0x3FF & x) - -static struct rsnd_mod_ops adg_ops = { - .name = "adg", -}; - -#define ADG_HZ_441 0 -#define ADG_HZ_48 1 -#define ADG_HZ_SIZE 2 - -struct rsnd_adg { - struct clk *clkin[CLKINMAX]; - struct clk *clkout[CLKOUTMAX]; - struct clk *null_clk; - struct clk_onecell_data onecell; - struct rsnd_mod mod; - int clkin_rate[CLKINMAX]; - int clkin_size; - int clkout_size; - u32 ckr; - u32 brga; - u32 brgb; - - int brg_rate[ADG_HZ_SIZE]; /* BRGA / BRGB */ -}; - -#define for_each_rsnd_clkin(pos, adg, i) \ - for (i = 0; \ - (i < adg->clkin_size) && \ - ((pos) = adg->clkin[i]); \ - i++) -#define for_each_rsnd_clkout(pos, adg, i) \ - for (i = 0; \ - (i < adg->clkout_size) && \ - ((pos) = adg->clkout[i]); \ - i++) -#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) - -static const char * const clkin_name_gen4[] = { - [CLKA] = "clkin", -}; - -static const char * const clkin_name_gen2[] = { - [CLKA] = "clk_a", - [CLKB] = "clk_b", - [CLKC] = "clk_c", - [CLKI] = "clk_i", -}; - -static const char * const clkout_name_gen2[] = { - [CLKOUT] = "audio_clkout", - [CLKOUT1] = "audio_clkout1", - [CLKOUT2] = "audio_clkout2", - [CLKOUT3] = "audio_clkout3", -}; - -static u32 rsnd_adg_calculate_brgx(unsigned long div) -{ - int i; - - if (!div) - return 0; - - for (i = 3; i >= 0; i--) { - int ratio = 2 << (i * 2); - if (0 == (div % ratio)) - return (u32)((i << 8) | ((div / ratio) - 1)); - } - - return ~0; -} - -static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) -{ - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - int id = rsnd_mod_id(ssi_mod); - int ws = id; - - if (rsnd_ssi_is_pin_sharing(io)) { - switch (id) { - case 1: - case 2: - case 9: - ws = 0; - break; - case 4: - ws = 3; - break; - case 8: - ws = 7; - break; - } - } else { - /* - * SSI8 is not connected to ADG. - * Thus SSI9 is using ws = 8 - */ - if (id == 9) - ws = 8; - } - - return (0x6 + ws) << 8; -} - -static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - unsigned int target_rate, - unsigned int *target_val, - unsigned int *target_en) -{ - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct device *dev = rsnd_priv_to_dev(priv); - int sel; - unsigned int val, en; - unsigned int min, diff; - unsigned int sel_rate[] = { - adg->clkin_rate[CLKA], /* 0000: CLKA */ - adg->clkin_rate[CLKB], /* 0001: CLKB */ - adg->clkin_rate[CLKC], /* 0010: CLKC */ - adg->brg_rate[ADG_HZ_441], /* 0011: BRGA */ - adg->brg_rate[ADG_HZ_48], /* 0100: BRGB */ - }; - - min = ~0; - val = 0; - en = 0; - for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { - int idx = 0; - int step = 2; - int div; - - if (!sel_rate[sel]) - continue; - - for (div = 2; div <= 98304; div += step) { - diff = abs(target_rate - sel_rate[sel] / div); - if (min > diff) { - val = (sel << 8) | idx; - min = diff; - en = 1 << (sel + 1); /* fixme */ - } - - /* - * step of 0_0000 / 0_0001 / 0_1101 - * are out of order - */ - if ((idx > 2) && (idx % 2)) - step *= 2; - if (idx == 0x1c) { - div += step; - step *= 2; - } - idx++; - } - } - - if (min == ~0) { - dev_err(dev, "no Input clock\n"); - return; - } - - *target_val = val; - if (target_en) - *target_en = en; -} - -static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - unsigned int in_rate, - unsigned int out_rate, - u32 *in, u32 *out, u32 *en) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - unsigned int target_rate; - u32 *target_val; - u32 _in; - u32 _out; - u32 _en; - - /* default = SSI WS */ - _in = - _out = rsnd_adg_ssi_ws_timing_gen2(io); - - target_rate = 0; - target_val = NULL; - _en = 0; - if (runtime->rate != in_rate) { - target_rate = out_rate; - target_val = &_out; - } else if (runtime->rate != out_rate) { - target_rate = in_rate; - target_val = &_in; - } - - if (target_rate) - __rsnd_adg_get_timesel_ratio(priv, io, - target_rate, - target_val, &_en); - - if (in) - *in = _in; - if (out) - *out = _out; - if (en) - *en = _en; -} - -int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - int id = rsnd_mod_id(cmd_mod); - int shift = (id % 2) ? 16 : 0; - u32 mask, val; - - rsnd_adg_get_timesel_ratio(priv, io, - rsnd_src_get_in_rate(priv, io), - rsnd_src_get_out_rate(priv, io), - NULL, &val, NULL); - - val = val << shift; - mask = 0x0f1f << shift; - - rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val); - - return 0; -} - -int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, - struct rsnd_dai_stream *io, - unsigned int in_rate, - unsigned int out_rate) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - u32 in, out; - u32 mask, en; - int id = rsnd_mod_id(src_mod); - int shift = (id % 2) ? 16 : 0; - - rsnd_mod_make_sure(src_mod, RSND_MOD_SRC); - - rsnd_adg_get_timesel_ratio(priv, io, - in_rate, out_rate, - &in, &out, &en); - - in = in << shift; - out = out << shift; - mask = 0x0f1f << shift; - - rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2), mask, in); - rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out); - - if (en) - rsnd_mod_bset(adg_mod, DIV_EN, en, en); - - return 0; -} - -static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - struct device *dev = rsnd_priv_to_dev(priv); - int id = rsnd_mod_id(ssi_mod); - int shift = (id % 4) * 8; - u32 mask = 0xFF << shift; - - rsnd_mod_make_sure(ssi_mod, RSND_MOD_SSI); - - val = val << shift; - - /* - * SSI 8 is not connected to ADG. - * it works with SSI 7 - */ - if (id == 8) - return; - - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val); - - dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val); -} - -int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate) -{ - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct clk *clk; - int i; - int sel_table[] = { - [CLKA] = 0x1, - [CLKB] = 0x2, - [CLKC] = 0x3, - [CLKI] = 0x0, - }; - - /* - * find suitable clock from - * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI. - */ - for_each_rsnd_clkin(clk, adg, i) - if (rate == adg->clkin_rate[i]) - return sel_table[i]; - - /* - * find divided clock from BRGA/BRGB - */ - if (rate == adg->brg_rate[ADG_HZ_441]) - return 0x10; - - if (rate == adg->brg_rate[ADG_HZ_48]) - return 0x20; - - return -EIO; -} - -int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) -{ - rsnd_adg_set_ssi_clk(ssi_mod, 0); - - return 0; -} - -int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - int data; - u32 ckr = 0; - - data = rsnd_adg_clk_query(priv, rate); - if (data < 0) - return data; - - rsnd_adg_set_ssi_clk(ssi_mod, data); - - if (0 == (rate % 8000)) - ckr = 0x80000000; /* BRGB output = 48kHz */ - - rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr); - - dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n", - (ckr) ? 'B' : 'A', - (ckr) ? adg->brg_rate[ADG_HZ_48] : - adg->brg_rate[ADG_HZ_441]); - - return 0; -} - -void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) -{ - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - struct clk *clk; - int i; - - if (enable) { - rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr); - rsnd_mod_write(adg_mod, BRRA, adg->brga); - rsnd_mod_write(adg_mod, BRRB, adg->brgb); - } - - for_each_rsnd_clkin(clk, adg, i) { - if (enable) { - clk_prepare_enable(clk); - - /* - * We shouldn't use clk_get_rate() under - * atomic context. Let's keep it when - * rsnd_adg_clk_enable() was called - */ - adg->clkin_rate[i] = clk_get_rate(clk); - } else { - clk_disable_unprepare(clk); - } - } -} - -static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv, - const char * const name, - const char *parent) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct clk *clk; - - clk = clk_register_fixed_rate(dev, name, parent, 0, 0); - if (IS_ERR_OR_NULL(clk)) { - dev_err(dev, "create null clk error\n"); - return ERR_CAST(clk); - } - - return clk; -} - -static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - - if (!adg->null_clk) { - static const char * const name = "rsnd_adg_null"; - - adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL); - } - - return adg->null_clk; -} - -static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - - if (adg->null_clk) - clk_unregister_fixed_rate(adg->null_clk); -} - -static int rsnd_adg_get_clkin(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - struct device *dev = rsnd_priv_to_dev(priv); - struct clk *clk; - const char * const *clkin_name; - int clkin_size; - int i; - - clkin_name = clkin_name_gen2; - clkin_size = ARRAY_SIZE(clkin_name_gen2); - if (rsnd_is_gen4(priv)) { - clkin_name = clkin_name_gen4; - clkin_size = ARRAY_SIZE(clkin_name_gen4); - } - - for (i = 0; i < clkin_size; i++) { - clk = devm_clk_get(dev, clkin_name[i]); - - if (IS_ERR_OR_NULL(clk)) - clk = rsnd_adg_null_clk_get(priv); - if (IS_ERR_OR_NULL(clk)) - goto err; - - adg->clkin[i] = clk; - } - - adg->clkin_size = clkin_size; - - return 0; - -err: - dev_err(dev, "adg clock IN get failed\n"); - - rsnd_adg_null_clk_clean(priv); - - return -EIO; -} - -static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - struct clk *clk; - int i; - - for_each_rsnd_clkout(clk, adg, i) - clk_unregister_fixed_rate(clk); -} - -static int rsnd_adg_get_clkout(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg = priv->adg; - struct clk *clk; - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; - struct property *prop; - u32 ckr, brgx, brga, brgb; - u32 req_rate[ADG_HZ_SIZE] = {}; - uint32_t count = 0; - unsigned long req_Hz[ADG_HZ_SIZE]; - int clkout_size; - int i, req_size; - int approximate = 0; - const char *parent_clk_name = NULL; - const char * const *clkout_name; - int brg_table[] = { - [CLKA] = 0x0, - [CLKB] = 0x1, - [CLKC] = 0x4, - [CLKI] = 0x2, - }; - - ckr = 0; - brga = 0xff; /* default */ - brgb = 0xff; /* default */ - - /* - * ADG supports BRRA/BRRB output only - * this means all clkout0/1/2/3 will be same rate - */ - prop = of_find_property(np, "clock-frequency", NULL); - if (!prop) - goto rsnd_adg_get_clkout_end; - - req_size = prop->length / sizeof(u32); - if (req_size > ADG_HZ_SIZE) { - dev_err(dev, "too many clock-frequency\n"); - return -EINVAL; - } - - of_property_read_u32_array(np, "clock-frequency", req_rate, req_size); - req_Hz[ADG_HZ_48] = 0; - req_Hz[ADG_HZ_441] = 0; - for (i = 0; i < req_size; i++) { - if (0 == (req_rate[i] % 44100)) - req_Hz[ADG_HZ_441] = req_rate[i]; - if (0 == (req_rate[i] % 48000)) - req_Hz[ADG_HZ_48] = req_rate[i]; - } - - /* - * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC - * have 44.1kHz or 48kHz base clocks for now. - * - * SSI itself can divide parent clock by 1/1 - 1/16 - * see - * rsnd_adg_ssi_clk_try_start() - * rsnd_ssi_master_clk_start() - */ - - /* - * [APPROXIMATE] - * - * clk_i (internal clock) can't create accurate rate, it will be approximate rate. - * - * - * - * clk_i needs x2 of required maximum rate. - * see - * - Minimum division of BRRA/BRRB - * - rsnd_ssi_clk_query() - * - * Sample Settings for TDM 8ch, 32bit width - * - * 8(ch) x 32(bit) x 44100(Hz) x 2 = 22579200 - * 8(ch) x 32(bit) x 48000(Hz) x 2 = 24576000 - * - * clock-frequency = <22579200 24576000>; - */ - for_each_rsnd_clkin(clk, adg, i) { - u32 rate, div; - - rate = clk_get_rate(clk); - - if (0 == rate) /* not used */ - continue; - - /* BRGA */ - - if (i == CLKI) - /* see [APPROXIMATE] */ - rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441]; - if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) { - div = rate / req_Hz[ADG_HZ_441]; - brgx = rsnd_adg_calculate_brgx(div); - if (BRRx_MASK(brgx) == brgx) { - brga = brgx; - adg->brg_rate[ADG_HZ_441] = rate / div; - ckr |= brg_table[i] << 20; - if (req_Hz[ADG_HZ_441]) - parent_clk_name = __clk_get_name(clk); - if (i == CLKI) - approximate = 1; - } - } - - /* BRGB */ - - if (i == CLKI) - /* see [APPROXIMATE] */ - rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48]; - if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) { - div = rate / req_Hz[ADG_HZ_48]; - brgx = rsnd_adg_calculate_brgx(div); - if (BRRx_MASK(brgx) == brgx) { - brgb = brgx; - adg->brg_rate[ADG_HZ_48] = rate / div; - ckr |= brg_table[i] << 16; - if (req_Hz[ADG_HZ_48]) - parent_clk_name = __clk_get_name(clk); - if (i == CLKI) - approximate = 1; - } - } - } - - if (!(adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48]) && - !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441])) - goto rsnd_adg_get_clkout_end; - - if (approximate) - dev_info(dev, "It uses CLK_I as approximate rate"); - - clkout_name = clkout_name_gen2; - clkout_size = ARRAY_SIZE(clkout_name_gen2); - if (rsnd_is_gen4(priv)) - clkout_size = 1; /* reuse clkout_name_gen2[] */ - - /* - * ADG supports BRRA/BRRB output only. - * this means all clkout0/1/2/3 will be * same rate - */ - - of_property_read_u32(np, "#clock-cells", &count); - /* - * for clkout - */ - if (!count) { - clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], - parent_clk_name, 0, req_rate[0]); - if (IS_ERR_OR_NULL(clk)) - goto err; - - adg->clkout[CLKOUT] = clk; - adg->clkout_size = 1; - of_clk_add_provider(np, of_clk_src_simple_get, clk); - } - /* - * for clkout0/1/2/3 - */ - else { - for (i = 0; i < clkout_size; i++) { - clk = clk_register_fixed_rate(dev, clkout_name[i], - parent_clk_name, 0, - req_rate[0]); - if (IS_ERR_OR_NULL(clk)) - goto err; - - adg->clkout[i] = clk; - } - adg->onecell.clks = adg->clkout; - adg->onecell.clk_num = clkout_size; - adg->clkout_size = clkout_size; - of_clk_add_provider(np, of_clk_src_onecell_get, - &adg->onecell); - } - -rsnd_adg_get_clkout_end: - adg->ckr = ckr; - adg->brga = brga; - adg->brgb = brgb; - - return 0; - -err: - dev_err(dev, "adg clock OUT get failed\n"); - - rsnd_adg_unregister_clkout(priv); - - return -EIO; -} - -#if defined(DEBUG) || defined(CONFIG_DEBUG_FS) -__printf(3, 4) -static void dbg_msg(struct device *dev, struct seq_file *m, - const char *fmt, ...) -{ - char msg[128]; - va_list args; - - va_start(args, fmt); - vsnprintf(msg, sizeof(msg), fmt, args); - va_end(args); - - if (m) - seq_puts(m, msg); - else - dev_dbg(dev, "%s", msg); -} - -void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m) -{ - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct clk *clk; - int i; - - for_each_rsnd_clkin(clk, adg, i) - dbg_msg(dev, m, "%-18s : %pa : %ld\n", - __clk_get_name(clk), clk, clk_get_rate(clk)); - - dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", - adg->ckr, adg->brga, adg->brgb); - dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->brg_rate[ADG_HZ_441]); - dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->brg_rate[ADG_HZ_48]); - - /* - * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start() - * by BRGCKR::BRGCKR_31 - */ - for_each_rsnd_clkout(clk, adg, i) - dbg_msg(dev, m, "%-18s : %pa : %ld\n", - __clk_get_name(clk), clk, clk_get_rate(clk)); -} -#else -#define rsnd_adg_clk_dbg_info(priv, m) -#endif - -int rsnd_adg_probe(struct rsnd_priv *priv) -{ - struct rsnd_adg *adg; - struct device *dev = rsnd_priv_to_dev(priv); - int ret; - - adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); - if (!adg) - return -ENOMEM; - - ret = rsnd_mod_init(priv, &adg->mod, &adg_ops, - NULL, 0, 0); - if (ret) - return ret; - - priv->adg = adg; - - ret = rsnd_adg_get_clkin(priv); - if (ret) - return ret; - - ret = rsnd_adg_get_clkout(priv); - if (ret) - return ret; - - rsnd_adg_clk_enable(priv); - rsnd_adg_clk_dbg_info(priv, NULL); - - return 0; -} - -void rsnd_adg_remove(struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; - - rsnd_adg_unregister_clkout(priv); - - of_clk_del_provider(np); - - rsnd_adg_clk_disable(priv); - - /* It should be called after rsnd_adg_clk_disable() */ - rsnd_adg_null_clk_clean(priv); -} diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c deleted file mode 100644 index 8d9a1e345a22c3..00000000000000 --- a/sound/soc/sh/rcar/cmd.c +++ /dev/null @@ -1,191 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car CMD support -// -// Copyright (C) 2015 Renesas Solutions Corp. -// Kuninori Morimoto - -#include "rsnd.h" - -struct rsnd_cmd { - struct rsnd_mod mod; -}; - -#define CMD_NAME "cmd" - -#define rsnd_cmd_nr(priv) ((priv)->cmd_nr) -#define for_each_rsnd_cmd(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_cmd_nr(priv)) && \ - ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \ - i++) - -static int rsnd_cmd_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); - struct device *dev = rsnd_priv_to_dev(priv); - u32 data; - static const u32 path[] = { - [1] = 1 << 0, - [5] = 1 << 8, - [6] = 1 << 12, - [9] = 1 << 15, - }; - - if (!mix && !dvc) - return 0; - - if (ARRAY_SIZE(path) < rsnd_mod_id(mod) + 1) - return -ENXIO; - - if (mix) { - struct rsnd_dai *rdai; - int i; - - /* - * it is assuming that integrater is well understanding about - * data path. Here doesn't check impossible connection, - * like src2 + src5 - */ - data = 0; - for_each_rsnd_dai(rdai, priv, i) { - struct rsnd_dai_stream *tio = &rdai->playback; - struct rsnd_mod *src = rsnd_io_to_mod_src(tio); - - if (mix == rsnd_io_to_mod_mix(tio)) - data |= path[rsnd_mod_id(src)]; - - tio = &rdai->capture; - src = rsnd_io_to_mod_src(tio); - if (mix == rsnd_io_to_mod_mix(tio)) - data |= path[rsnd_mod_id(src)]; - } - - } else { - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - - static const u8 cmd_case[] = { - [0] = 0x3, - [1] = 0x3, - [2] = 0x4, - [3] = 0x1, - [4] = 0x2, - [5] = 0x4, - [6] = 0x1, - [9] = 0x2, - }; - - if (unlikely(!src)) - return -EIO; - - data = path[rsnd_mod_id(src)] | - cmd_case[rsnd_mod_id(src)] << 16; - } - - dev_dbg(dev, "ctu/mix path = 0x%08x\n", data); - - rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); - rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1); - rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); - - rsnd_adg_set_cmd_timsel_gen2(mod, io); - - return 0; -} - -static int rsnd_cmd_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mod_write(mod, CMD_CTRL, 0x10); - - return 0; -} - -static int rsnd_cmd_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mod_write(mod, CMD_CTRL, 0); - - return 0; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_cmd_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, - 0x180 + rsnd_mod_id_raw(mod) * 0x20, 0x30); -} -#define DEBUG_INFO .debug_info = rsnd_cmd_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_cmd_ops = { - .name = CMD_NAME, - .init = rsnd_cmd_init, - .start = rsnd_cmd_start, - .stop = rsnd_cmd_stop, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -static struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv))) - id = 0; - - return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); -} -int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id); - - return rsnd_dai_connect(mod, io, mod->type); -} - -int rsnd_cmd_probe(struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_cmd *cmd; - int i, nr; - - /* same number as DVC */ - nr = priv->dvc_nr; - if (!nr) - return 0; - - cmd = devm_kcalloc(dev, nr, sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - priv->cmd_nr = nr; - priv->cmd = cmd; - - for_each_rsnd_cmd(cmd, priv, i) { - int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), - &rsnd_cmd_ops, NULL, - RSND_MOD_CMD, i); - if (ret) - return ret; - } - - return 0; -} - -void rsnd_cmd_remove(struct rsnd_priv *priv) -{ - struct rsnd_cmd *cmd; - int i; - - for_each_rsnd_cmd(cmd, priv, i) { - rsnd_mod_quit(rsnd_mod_get(cmd)); - } -} diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c deleted file mode 100644 index eca5ce096e5457..00000000000000 --- a/sound/soc/sh/rcar/core.c +++ /dev/null @@ -1,2100 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car SRU/SCU/SSIU/SSI support -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto -// -// Based on fsi.c -// Kuninori Morimoto - -/* - * Renesas R-Car sound device structure - * - * Gen1 - * - * SRU : Sound Routing Unit - * - SRC : Sampling Rate Converter - * - CMD - * - CTU : Channel Count Conversion Unit - * - MIX : Mixer - * - DVC : Digital Volume and Mute Function - * - SSI : Serial Sound Interface - * - * Gen2 - * - * SCU : Sampling Rate Converter Unit - * - SRC : Sampling Rate Converter - * - CMD - * - CTU : Channel Count Conversion Unit - * - MIX : Mixer - * - DVC : Digital Volume and Mute Function - * SSIU : Serial Sound Interface Unit - * - SSI : Serial Sound Interface - */ - -/* - * driver data Image - * - * rsnd_priv - * | - * | ** this depends on Gen1/Gen2 - * | - * +- gen - * | - * | ** these depend on data path - * | ** gen and platform data control it - * | - * +- rdai[0] - * | | sru ssiu ssi - * | +- playback -> [mod] -> [mod] -> [mod] -> ... - * | | - * | | sru ssiu ssi - * | +- capture -> [mod] -> [mod] -> [mod] -> ... - * | - * +- rdai[1] - * | | sru ssiu ssi - * | +- playback -> [mod] -> [mod] -> [mod] -> ... - * | | - * | | sru ssiu ssi - * | +- capture -> [mod] -> [mod] -> [mod] -> ... - * ... - * | - * | ** these control ssi - * | - * +- ssi - * | | - * | +- ssi[0] - * | +- ssi[1] - * | +- ssi[2] - * | ... - * | - * | ** these control src - * | - * +- src - * | - * +- src[0] - * +- src[1] - * +- src[2] - * ... - * - * - * for_each_rsnd_dai(xx, priv, xx) - * rdai[0] => rdai[1] => rdai[2] => ... - * - * for_each_rsnd_mod(xx, rdai, xx) - * [mod] => [mod] => [mod] => ... - * - * rsnd_dai_call(xxx, fn ) - * [mod]->fn() -> [mod]->fn() -> [mod]->fn()... - * - */ - -#include -#include -#include "rsnd.h" - -#define RSND_RATES SNDRV_PCM_RATE_8000_192000 -#define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\ - SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE) - -static const struct of_device_id rsnd_of_match[] = { - { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, - { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, - { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 }, - { .compatible = "renesas,rcar_sound-gen4", .data = (void *)RSND_GEN4 }, - /* Special Handling */ - { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) }, - {}, -}; -MODULE_DEVICE_TABLE(of, rsnd_of_match); - -/* - * rsnd_mod functions - */ -void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) -{ - if (mod->type != type) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_warn(dev, "%s is not your expected module\n", - rsnd_mod_name(mod)); - } -} - -struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - if (!mod || !mod->ops || !mod->ops->dma_req) - return NULL; - - return mod->ops->dma_req(io, mod); -} - -#define MOD_NAME_NUM 5 -#define MOD_NAME_SIZE 16 -char *rsnd_mod_name(struct rsnd_mod *mod) -{ - static char names[MOD_NAME_NUM][MOD_NAME_SIZE]; - static int num; - char *name = names[num]; - - num++; - if (num >= MOD_NAME_NUM) - num = 0; - - /* - * Let's use same char to avoid pointlessness memory - * Thus, rsnd_mod_name() should be used immediately - * Don't keep pointer - */ - if ((mod)->ops->id_sub) { - snprintf(name, MOD_NAME_SIZE, "%s[%d%d]", - mod->ops->name, - rsnd_mod_id(mod), - rsnd_mod_id_sub(mod)); - } else { - snprintf(name, MOD_NAME_SIZE, "%s[%d]", - mod->ops->name, - rsnd_mod_id(mod)); - } - - return name; -} - -u32 *rsnd_mod_get_status(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - return &mod->status; -} - -int rsnd_mod_id_raw(struct rsnd_mod *mod) -{ - return mod->id; -} - -int rsnd_mod_id(struct rsnd_mod *mod) -{ - if ((mod)->ops->id) - return (mod)->ops->id(mod); - - return rsnd_mod_id_raw(mod); -} - -int rsnd_mod_id_sub(struct rsnd_mod *mod) -{ - if ((mod)->ops->id_sub) - return (mod)->ops->id_sub(mod); - - return 0; -} - -int rsnd_mod_init(struct rsnd_priv *priv, - struct rsnd_mod *mod, - struct rsnd_mod_ops *ops, - struct clk *clk, - enum rsnd_mod_type type, - int id) -{ - int ret = clk_prepare(clk); - - if (ret) - return ret; - - mod->id = id; - mod->ops = ops; - mod->type = type; - mod->clk = clk; - mod->priv = priv; - - return 0; -} - -void rsnd_mod_quit(struct rsnd_mod *mod) -{ - clk_unprepare(mod->clk); - mod->clk = NULL; -} - -void rsnd_mod_interrupt(struct rsnd_mod *mod, - void (*callback)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io)) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dai *rdai; - int i; - - for_each_rsnd_dai(rdai, priv, i) { - struct rsnd_dai_stream *io = &rdai->playback; - - if (mod == io->mod[mod->type]) - callback(mod, io); - - io = &rdai->capture; - if (mod == io->mod[mod->type]) - callback(mod, io); - } -} - -int rsnd_io_is_working(struct rsnd_dai_stream *io) -{ - /* see rsnd_dai_stream_init/quit() */ - if (io->substream) - return snd_pcm_running(io->substream); - - return 0; -} - -int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - - /* - * params will be added when refine - * see - * __rsnd_soc_hw_rule_rate() - * __rsnd_soc_hw_rule_channels() - */ - if (params) - return params_channels(params); - else if (runtime) - return runtime->channels; - return 0; -} - -int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params) -{ - int chan = rsnd_runtime_channel_original_with_params(io, params); - struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); - - if (ctu_mod) { - u32 converted_chan = rsnd_io_converted_chan(io); - - /* - * !! Note !! - * - * converted_chan will be used for CTU, - * or TDM Split mode. - * User shouldn't use CTU with TDM Split mode. - */ - if (rsnd_runtime_is_tdm_split(io)) { - struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); - - dev_err(dev, "CTU and TDM Split should be used\n"); - } - - if (converted_chan) - return converted_chan; - } - - return chan; -} - -int rsnd_channel_normalization(int chan) -{ - if (WARN_ON((chan > 8) || (chan < 0))) - return 0; - - /* TDM Extend Mode needs 8ch */ - if (chan == 6) - chan = 8; - - return chan; -} - -int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int chan = rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu_with_params(io, params) : - rsnd_runtime_channel_original_with_params(io, params); - - /* Use Multi SSI */ - if (rsnd_runtime_is_multi_ssi(io)) - chan /= rsnd_rdai_ssi_lane_get(rdai); - - return rsnd_channel_normalization(chan); -} - -int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int lane = rsnd_rdai_ssi_lane_get(rdai); - int chan = rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu(io) : - rsnd_runtime_channel_original(io); - - return (chan > 2) && (lane > 1); -} - -int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io) -{ - return rsnd_runtime_channel_for_ssi(io) >= 6; -} - -int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io) -{ - return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT); -} - -/* - * ADINR function - */ -u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct device *dev = rsnd_priv_to_dev(priv); - - switch (snd_pcm_format_width(runtime->format)) { - case 8: - return 16 << 16; - case 16: - return 8 << 16; - case 24: - return 0 << 16; - } - - dev_warn(dev, "not supported sample bits\n"); - - return 0; -} - -/* - * DALIGN function - */ -u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) -{ - static const u32 dalign_values[8] = { - 0x76543210, 0x00000032, 0x00007654, 0x00000076, - 0xfedcba98, 0x000000ba, 0x0000fedc, 0x000000fe, - }; - int id = 0; - struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); - struct rsnd_mod *target; - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 dalign; - - /* - * *Hardware* L/R and *Software* L/R are inverted for 16bit data. - * 31..16 15...0 - * HW: [L ch] [R ch] - * SW: [R ch] [L ch] - * We need to care about inversion timing to control - * Playback/Capture correctly. - * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R - * - * sL/R : software L/R - * hL/R : hardware L/R - * (*) : conversion timing - * - * Playback - * sL/R (*) hL/R hL/R hL/R hL/R hL/R - * [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec - * - * Capture - * hL/R hL/R hL/R hL/R hL/R (*) sL/R - * codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM] - */ - if (rsnd_io_is_play(io)) { - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - - target = src ? src : ssiu; - } else { - struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); - - target = cmd ? cmd : ssiu; - } - - if (mod == ssiu) - id = rsnd_mod_id_sub(mod); - - dalign = dalign_values[id]; - - if (mod == target && snd_pcm_format_width(runtime->format) == 16) { - /* Target mod needs inverted DALIGN when 16bit */ - dalign = (dalign & 0xf0f0f0f0) >> 4 | - (dalign & 0x0f0f0f0f) << 4; - } - - return dalign; -} - -u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) -{ - static const enum rsnd_mod_type playback_mods[] = { - RSND_MOD_SRC, - RSND_MOD_CMD, - RSND_MOD_SSIU, - }; - static const enum rsnd_mod_type capture_mods[] = { - RSND_MOD_CMD, - RSND_MOD_SRC, - RSND_MOD_SSIU, - }; - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_mod *tmod = NULL; - const enum rsnd_mod_type *mods = - rsnd_io_is_play(io) ? - playback_mods : capture_mods; - int i; - - /* - * This is needed for 24bit data - * We need to shift 8bit - * - * Linux 24bit data is located as 0x00****** - * HW 24bit data is located as 0x******00 - * - */ - if (snd_pcm_format_width(runtime->format) != 24) - return 0; - - for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { - tmod = rsnd_io_to_mod(io, mods[i]); - if (tmod) - break; - } - - if (tmod != mod) - return 0; - - if (rsnd_io_is_play(io)) - return (0 << 20) | /* shift to Left */ - (8 << 16); /* 8bit */ - else - return (1 << 20) | /* shift to Right */ - (8 << 16); /* 8bit */ -} - -/* - * rsnd_dai functions - */ -struct rsnd_mod *rsnd_mod_next(int *iterator, - struct rsnd_dai_stream *io, - enum rsnd_mod_type *array, - int array_size) -{ - int max = array ? array_size : RSND_MOD_MAX; - - for (; *iterator < max; (*iterator)++) { - enum rsnd_mod_type type = (array) ? array[*iterator] : *iterator; - struct rsnd_mod *mod = rsnd_io_to_mod(io, type); - - if (mod) - return mod; - } - - return NULL; -} - -static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { - { - /* CAPTURE */ - RSND_MOD_AUDMAPP, - RSND_MOD_AUDMA, - RSND_MOD_DVC, - RSND_MOD_MIX, - RSND_MOD_CTU, - RSND_MOD_CMD, - RSND_MOD_SRC, - RSND_MOD_SSIU, - RSND_MOD_SSIM3, - RSND_MOD_SSIM2, - RSND_MOD_SSIM1, - RSND_MOD_SSIP, - RSND_MOD_SSI, - }, { - /* PLAYBACK */ - RSND_MOD_AUDMAPP, - RSND_MOD_AUDMA, - RSND_MOD_SSIM3, - RSND_MOD_SSIM2, - RSND_MOD_SSIM1, - RSND_MOD_SSIP, - RSND_MOD_SSI, - RSND_MOD_SSIU, - RSND_MOD_DVC, - RSND_MOD_MIX, - RSND_MOD_CTU, - RSND_MOD_CMD, - RSND_MOD_SRC, - }, -}; - -static int rsnd_status_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, enum rsnd_mod_type type, - int shift, int add, int timing) -{ - u32 *status = mod->ops->get_status(mod, io, type); - u32 mask = 0xF << shift; - u8 val = (*status >> shift) & 0xF; - u8 next_val = (val + add) & 0xF; - int func_call = (val == timing); - - /* no status update */ - if (add == 0 || shift == 28) - return 1; - - if (next_val == 0xF) /* underflow case */ - func_call = -1; - else - *status = (*status & ~mask) + (next_val << shift); - - return func_call; -} - -#define rsnd_dai_call(fn, io, param...) \ -({ \ - struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); \ - struct rsnd_mod *mod; \ - int is_play = rsnd_io_is_play(io); \ - int ret = 0, i; \ - enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ - for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ - int tmp = 0; \ - int func_call = rsnd_status_update(io, mod, types[i], \ - __rsnd_mod_shift_##fn, \ - __rsnd_mod_add_##fn, \ - __rsnd_mod_call_##fn); \ - if (func_call > 0 && (mod)->ops->fn) \ - tmp = (mod)->ops->fn(mod, io, param); \ - if (unlikely(func_call < 0) || \ - unlikely(tmp && (tmp != -EPROBE_DEFER))) \ - dev_err(dev, "%s : %s error (%d, %d)\n", \ - rsnd_mod_name(mod), #fn, tmp, func_call);\ - ret |= tmp; \ - } \ - ret; \ -}) - -int rsnd_dai_connect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - struct rsnd_priv *priv; - struct device *dev; - - if (!mod) - return -EIO; - - if (io->mod[type] == mod) - return 0; - - if (io->mod[type]) - return -EINVAL; - - priv = rsnd_mod_to_priv(mod); - dev = rsnd_priv_to_dev(priv); - - io->mod[type] = mod; - - dev_dbg(dev, "%s is connected to io (%s)\n", - rsnd_mod_name(mod), - rsnd_io_is_play(io) ? "Playback" : "Capture"); - - return 0; -} - -static void rsnd_dai_disconnect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - io->mod[type] = NULL; -} - -int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, - int max_channels) -{ - if (max_channels > 0) - rdai->max_channels = max_channels; - - return rdai->max_channels; -} - -int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, - int ssi_lane) -{ - if (ssi_lane > 0) - rdai->ssi_lane = ssi_lane; - - return rdai->ssi_lane; -} - -int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width) -{ - if (width > 0) - rdai->chan_width = width; - - return rdai->chan_width; -} - -struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) -{ - if ((id < 0) || (id >= rsnd_rdai_nr(priv))) - return NULL; - - return priv->rdai + id; -} - -static struct snd_soc_dai_driver -*rsnd_daidrv_get(struct rsnd_priv *priv, int id) -{ - if ((id < 0) || (id >= rsnd_rdai_nr(priv))) - return NULL; - - return priv->daidrv + id; -} - -#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai) -static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) -{ - struct rsnd_priv *priv = rsnd_dai_to_priv(dai); - - return rsnd_rdai_get(priv, dai->id); -} - -static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream) -{ - io->substream = substream; -} - -static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) -{ - io->substream = NULL; -} - -static -struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - - return snd_soc_rtd_to_cpu(rtd, 0); -} - -static -struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai, - struct snd_pcm_substream *substream) -{ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - return &rdai->playback; - else - return &rdai->capture; -} - -static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct rsnd_priv *priv = rsnd_dai_to_priv(dai); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - int ret; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - ret = rsnd_dai_call(init, io, priv); - if (ret < 0) - goto dai_trigger_end; - - ret = rsnd_dai_call(start, io, priv); - if (ret < 0) - goto dai_trigger_end; - - ret = rsnd_dai_call(irq, io, priv, 1); - if (ret < 0) - goto dai_trigger_end; - - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - ret = rsnd_dai_call(irq, io, priv, 0); - - ret |= rsnd_dai_call(stop, io, priv); - - ret |= rsnd_dai_call(quit, io, priv); - - break; - default: - ret = -EINVAL; - } - -dai_trigger_end: - spin_unlock_irqrestore(&priv->lock, flags); - - return ret; -} - -static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - - /* set clock master for audio interface */ - switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_BC_FC: - rdai->clk_master = 0; - break; - case SND_SOC_DAIFMT_BP_FP: - rdai->clk_master = 1; /* cpu is master */ - break; - default: - return -EINVAL; - } - - /* set format */ - rdai->bit_clk_inv = 0; - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - rdai->sys_delay = 0; - rdai->data_alignment = 0; - rdai->frm_clk_inv = 0; - break; - case SND_SOC_DAIFMT_LEFT_J: - case SND_SOC_DAIFMT_DSP_B: - rdai->sys_delay = 1; - rdai->data_alignment = 0; - rdai->frm_clk_inv = 1; - break; - case SND_SOC_DAIFMT_RIGHT_J: - rdai->sys_delay = 1; - rdai->data_alignment = 1; - rdai->frm_clk_inv = 1; - break; - case SND_SOC_DAIFMT_DSP_A: - rdai->sys_delay = 0; - rdai->data_alignment = 0; - rdai->frm_clk_inv = 1; - break; - } - - /* set clock inversion */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_IF: - rdai->frm_clk_inv = !rdai->frm_clk_inv; - break; - case SND_SOC_DAIFMT_IB_NF: - rdai->bit_clk_inv = !rdai->bit_clk_inv; - break; - case SND_SOC_DAIFMT_IB_IF: - rdai->bit_clk_inv = !rdai->bit_clk_inv; - rdai->frm_clk_inv = !rdai->frm_clk_inv; - break; - case SND_SOC_DAIFMT_NB_NF: - default: - break; - } - - return 0; -} - -static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, - u32 tx_mask, u32 rx_mask, - int slots, int slot_width) -{ - struct rsnd_priv *priv = rsnd_dai_to_priv(dai); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct device *dev = rsnd_priv_to_dev(priv); - - switch (slot_width) { - case 16: - case 24: - case 32: - break; - default: - /* use default */ - /* - * Indicate warning if DT has "dai-tdm-slot-width" - * but the value was not expected. - */ - if (slot_width) - dev_warn(dev, "unsupported TDM slot width (%d), force to use default 32\n", - slot_width); - slot_width = 32; - } - - switch (slots) { - case 2: - /* TDM Split Mode */ - case 6: - case 8: - /* TDM Extend Mode */ - rsnd_rdai_channels_set(rdai, slots); - rsnd_rdai_ssi_lane_set(rdai, 1); - rsnd_rdai_width_set(rdai, slot_width); - break; - default: - dev_err(dev, "unsupported TDM slots (%d)\n", slots); - return -EINVAL; - } - - return 0; -} - -static unsigned int rsnd_soc_hw_channels_list[] = { - 2, 6, 8, -}; - -static unsigned int rsnd_soc_hw_rate_list[] = { - 8000, - 11025, - 16000, - 22050, - 32000, - 44100, - 48000, - 64000, - 88200, - 96000, - 176400, - 192000, -}; - -static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, - unsigned int *list, int list_num, - struct snd_interval *baseline, struct snd_interval *iv, - struct rsnd_dai_stream *io, char *unit) -{ - struct snd_interval p; - unsigned int rate; - int i; - - snd_interval_any(&p); - p.min = UINT_MAX; - p.max = 0; - - for (i = 0; i < list_num; i++) { - - if (!snd_interval_test(iv, list[i])) - continue; - - rate = rsnd_ssi_clk_query(rdai, - baseline->min, list[i], NULL); - if (rate > 0) { - p.min = min(p.min, list[i]); - p.max = max(p.max, list[i]); - } - - rate = rsnd_ssi_clk_query(rdai, - baseline->max, list[i], NULL); - if (rate > 0) { - p.min = min(p.min, list[i]); - p.max = max(p.max, list[i]); - } - } - - /* Indicate error once if it can't handle */ - if (!rsnd_flags_has(io, RSND_HW_RULE_ERR) && (p.min > p.max)) { - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_warn(dev, "It can't handle %d %s <-> %d %s\n", - baseline->min, unit, baseline->max, unit); - rsnd_flags_set(io, RSND_HW_RULE_ERR); - } - - return snd_interval_refine(iv, &p); -} - -static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval ic; - struct rsnd_dai_stream *io = rule->private; - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - - /* - * possible sampling rate limitation is same as - * 2ch if it supports multi ssi - * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) - */ - ic = *ic_; - ic.min = - ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - - return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list, - ARRAY_SIZE(rsnd_soc_hw_rate_list), - &ic, ir, io, "ch"); -} - -static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval ic; - struct rsnd_dai_stream *io = rule->private; - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - - /* - * possible sampling rate limitation is same as - * 2ch if it supports multi ssi - * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) - */ - ic = *ic_; - ic.min = - ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); - - return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list, - ARRAY_SIZE(rsnd_soc_hw_channels_list), - ir, &ic, io, "Hz"); -} - -static const struct snd_pcm_hardware rsnd_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID, - .buffer_bytes_max = 64 * 1024, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .periods_min = 1, - .periods_max = 32, - .fifo_size = 256, -}; - -static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int max_channels = rsnd_rdai_channels_get(rdai); - int i; - - rsnd_flags_del(io, RSND_HW_RULE_ERR); - - rsnd_dai_stream_init(io, substream); - - /* - * Channel Limitation - * It depends on Platform design - */ - constraint->list = rsnd_soc_hw_channels_list; - constraint->count = 0; - constraint->mask = 0; - - for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) { - if (rsnd_soc_hw_channels_list[i] > max_channels) - break; - constraint->count = i + 1; - } - - snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, constraint); - - snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - - /* - * Sampling Rate / Channel Limitation - * It depends on Clock Master Mode - */ - if (rsnd_rdai_is_clk_master(rdai)) { - int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - rsnd_soc_hw_rule_rate, - is_play ? &rdai->playback : &rdai->capture, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - rsnd_soc_hw_rule_channels, - is_play ? &rdai->playback : &rdai->capture, - SNDRV_PCM_HW_PARAM_RATE, -1); - } - - return 0; -} - -static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - - /* - * call rsnd_dai_call without spinlock - */ - rsnd_dai_call(cleanup, io, priv); - - rsnd_dai_stream_quit(io); -} - -static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct rsnd_priv *priv = rsnd_dai_to_priv(dai); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - - return rsnd_dai_call(prepare, io, priv); -} - -static const u64 rsnd_soc_dai_formats[] = { - /* - * 1st Priority - * - * Well tested formats. - * Select below from Sound Card, not auto - * SND_SOC_DAIFMT_CBC_CFC - * SND_SOC_DAIFMT_CBP_CFP - */ - SND_SOC_POSSIBLE_DAIFMT_I2S | - SND_SOC_POSSIBLE_DAIFMT_RIGHT_J | - SND_SOC_POSSIBLE_DAIFMT_LEFT_J | - SND_SOC_POSSIBLE_DAIFMT_NB_NF | - SND_SOC_POSSIBLE_DAIFMT_NB_IF | - SND_SOC_POSSIBLE_DAIFMT_IB_NF | - SND_SOC_POSSIBLE_DAIFMT_IB_IF, - /* - * 2nd Priority - * - * Supported, but not well tested - */ - SND_SOC_POSSIBLE_DAIFMT_DSP_A | - SND_SOC_POSSIBLE_DAIFMT_DSP_B, -}; - -static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct device_node *dai_np) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); - struct device_node *np; - int is_play = rsnd_io_is_play(io); - int i; - - if (!ssiu_np) - return; - - /* - * This driver assumes that it is TDM Split mode - * if it includes ssiu node - */ - for (i = 0;; i++) { - struct device_node *node = is_play ? - of_parse_phandle(dai_np, "playback", i) : - of_parse_phandle(dai_np, "capture", i); - - if (!node) - break; - - for_each_child_of_node(ssiu_np, np) { - if (np == node) { - rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); - dev_dbg(dev, "%s is part of TDM Split\n", io->name); - } - } - - of_node_put(node); - } - - of_node_put(ssiu_np); -} - -static void rsnd_parse_connect_simple(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct device_node *dai_np) -{ - if (!rsnd_io_to_mod_ssi(io)) - return; - - rsnd_parse_tdm_split_mode(priv, io, dai_np); -} - -static void rsnd_parse_connect_graph(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - struct device_node *endpoint) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *remote_node; - - if (!rsnd_io_to_mod_ssi(io)) - return; - - remote_node = of_graph_get_remote_port_parent(endpoint); - - /* HDMI0 */ - if (strstr(remote_node->full_name, "hdmi@fead0000")) { - rsnd_flags_set(io, RSND_STREAM_HDMI0); - dev_dbg(dev, "%s connected to HDMI0\n", io->name); - } - - /* HDMI1 */ - if (strstr(remote_node->full_name, "hdmi@feae0000")) { - rsnd_flags_set(io, RSND_STREAM_HDMI1); - dev_dbg(dev, "%s connected to HDMI1\n", io->name); - } - - rsnd_parse_tdm_split_mode(priv, io, endpoint); - - of_node_put(remote_node); -} - -void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, - struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), - struct device_node *node, - struct device_node *playback, - struct device_node *capture) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np; - int i; - - if (!node) - return; - - i = 0; - for_each_child_of_node(node, np) { - struct rsnd_mod *mod; - - i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - of_node_put(np); - break; - } - - mod = mod_get(priv, i); - - if (np == playback) - rsnd_dai_connect(mod, &rdai->playback, mod->type); - if (np == capture) - rsnd_dai_connect(mod, &rdai->capture, mod->type); - i++; - } - - of_node_put(node); -} - -int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx) -{ - char node_name[16]; - - /* - * rsnd is assuming each device nodes are sequential numbering, - * but some of them are not. - * This function adjusts index for it. - * - * ex) - * Normal case, special case - * ssi-0 - * ssi-1 - * ssi-2 - * ssi-3 ssi-3 - * ssi-4 ssi-4 - * ... - * - * assume Max 64 node - */ - for (; idx < 64; idx++) { - snprintf(node_name, sizeof(node_name), "%s-%d", name, idx); - - if (strncmp(node_name, of_node_full_name(node), sizeof(node_name)) == 0) - return idx; - } - - dev_err(dev, "strange node numbering (%s)", - of_node_full_name(node)); - return -EINVAL; -} - -int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np; - int i; - - i = 0; - for_each_child_of_node(node, np) { - i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - of_node_put(np); - return 0; - } - i++; - } - - return i; -} - -static int rsnd_dai_of_node(struct rsnd_priv *priv, int *is_graph) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; - struct device_node *ports, *node; - int nr = 0; - int i = 0; - - *is_graph = 0; - - /* - * parse both previous dai (= rcar_sound,dai), and - * graph dai (= ports/port) - */ - - /* - * Simple-Card - */ - node = of_get_child_by_name(np, RSND_NODE_DAI); - if (!node) - goto audio_graph; - - of_node_put(node); - - for_each_child_of_node(np, node) { - if (!of_node_name_eq(node, RSND_NODE_DAI)) - continue; - - priv->component_dais[i] = of_get_child_count(node); - nr += priv->component_dais[i]; - i++; - if (i >= RSND_MAX_COMPONENT) { - dev_info(dev, "reach to max component\n"); - of_node_put(node); - break; - } - } - - return nr; - -audio_graph: - /* - * Audio-Graph-Card - */ - for_each_child_of_node(np, ports) { - if (!of_node_name_eq(ports, "ports") && - !of_node_name_eq(ports, "port")) - continue; - priv->component_dais[i] = - of_graph_get_endpoint_count(of_node_name_eq(ports, "ports") ? - ports : np); - nr += priv->component_dais[i]; - i++; - if (i >= RSND_MAX_COMPONENT) { - dev_info(dev, "reach to max component\n"); - of_node_put(ports); - break; - } - } - - *is_graph = 1; - - return nr; -} - - -#define PREALLOC_BUFFER (32 * 1024) -#define PREALLOC_BUFFER_MAX (32 * 1024) - -static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, - struct rsnd_dai_stream *io, - int stream) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_pcm_substream *substream; - - /* - * use Audio-DMAC dev if we can use IPMMU - * see - * rsnd_dmaen_attach() - */ - if (io->dmac_dev) - dev = io->dmac_dev; - - for (substream = rtd->pcm->streams[stream].substream; - substream; - substream = substream->next) { - snd_pcm_set_managed_buffer(substream, - SNDRV_DMA_TYPE_DEV, - dev, - PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); - } - - return 0; -} - -static int rsnd_soc_dai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) -{ - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - int ret; - - ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd); - if (ret) - return ret; - - ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd); - if (ret) - return ret; - - ret = rsnd_preallocate_pages(rtd, &rdai->playback, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - return ret; - - ret = rsnd_preallocate_pages(rtd, &rdai->capture, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - return ret; - - return 0; -} - -static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { - .pcm_new = rsnd_soc_dai_pcm_new, - .startup = rsnd_soc_dai_startup, - .shutdown = rsnd_soc_dai_shutdown, - .trigger = rsnd_soc_dai_trigger, - .set_fmt = rsnd_soc_dai_set_fmt, - .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, - .prepare = rsnd_soc_dai_prepare, - .auto_selectable_formats = rsnd_soc_dai_formats, - .num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats), -}; - -static void __rsnd_dai_probe(struct rsnd_priv *priv, - struct device_node *dai_np, - struct device_node *node_np, - uint32_t node_arg, - int dai_i) -{ - struct rsnd_dai_stream *io_playback; - struct rsnd_dai_stream *io_capture; - struct snd_soc_dai_driver *drv; - struct rsnd_dai *rdai; - struct device *dev = rsnd_priv_to_dev(priv); - int playback_exist = 0, capture_exist = 0; - int io_i; - - rdai = rsnd_rdai_get(priv, dai_i); - drv = rsnd_daidrv_get(priv, dai_i); - io_playback = &rdai->playback; - io_capture = &rdai->capture; - - snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); - - /* for multi Component */ - rdai->dai_args.np = node_np; - rdai->dai_args.args_count = 1; - rdai->dai_args.args[0] = node_arg; - - rdai->priv = priv; - drv->name = rdai->name; - drv->ops = &rsnd_soc_dai_ops; - drv->id = dai_i; - drv->dai_args = &rdai->dai_args; - - io_playback->rdai = rdai; - io_capture->rdai = rdai; - rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ - rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ - rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ - - for (io_i = 0;; io_i++) { - struct device_node *playback = of_parse_phandle(dai_np, "playback", io_i); - struct device_node *capture = of_parse_phandle(dai_np, "capture", io_i); - - if (!playback && !capture) - break; - - if (io_i == 0) { - /* check whether playback/capture property exists */ - if (playback) - playback_exist = 1; - if (capture) - capture_exist = 1; - } - - rsnd_parse_connect_ssi(rdai, playback, capture); - rsnd_parse_connect_ssiu(rdai, playback, capture); - rsnd_parse_connect_src(rdai, playback, capture); - rsnd_parse_connect_ctu(rdai, playback, capture); - rsnd_parse_connect_mix(rdai, playback, capture); - rsnd_parse_connect_dvc(rdai, playback, capture); - - of_node_put(playback); - of_node_put(capture); - } - - if (playback_exist) { - snprintf(io_playback->name, RSND_DAI_NAME_SIZE, "DAI%d Playback", dai_i); - drv->playback.rates = RSND_RATES; - drv->playback.formats = RSND_FMTS; - drv->playback.channels_min = 2; - drv->playback.channels_max = 8; - drv->playback.stream_name = io_playback->name; - } - if (capture_exist) { - snprintf(io_capture->name, RSND_DAI_NAME_SIZE, "DAI%d Capture", dai_i); - drv->capture.rates = RSND_RATES; - drv->capture.formats = RSND_FMTS; - drv->capture.channels_min = 2; - drv->capture.channels_max = 8; - drv->capture.stream_name = io_capture->name; - } - - if (rsnd_ssi_is_pin_sharing(io_capture) || - rsnd_ssi_is_pin_sharing(io_playback)) { - /* should have symmetric_rate if pin sharing */ - drv->symmetric_rate = 1; - } - - dev_dbg(dev, "%s (%s/%s)\n", rdai->name, - rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", - rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); -} - -static int rsnd_dai_probe(struct rsnd_priv *priv) -{ - struct snd_soc_dai_driver *rdrv; - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *np = dev->of_node; - struct rsnd_dai *rdai; - int nr = 0; - int is_graph; - int dai_i; - - nr = rsnd_dai_of_node(priv, &is_graph); - if (!nr) - return -EINVAL; - - rdrv = devm_kcalloc(dev, nr, sizeof(*rdrv), GFP_KERNEL); - rdai = devm_kcalloc(dev, nr, sizeof(*rdai), GFP_KERNEL); - if (!rdrv || !rdai) - return -ENOMEM; - - priv->rdai_nr = nr; - priv->daidrv = rdrv; - priv->rdai = rdai; - - /* - * parse all dai - */ - dai_i = 0; - if (is_graph) { - struct device_node *ports; - struct device_node *dai_np; - - for_each_child_of_node(np, ports) { - if (!of_node_name_eq(ports, "ports") && - !of_node_name_eq(ports, "port")) - continue; - for_each_endpoint_of_node(of_node_name_eq(ports, "ports") ? - ports : np, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_np, 0, dai_i); - if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); - - rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); - rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); - } - dai_i++; - } - } - } else { - struct device_node *node; - struct device_node *dai_np; - - for_each_child_of_node(np, node) { - if (!of_node_name_eq(node, RSND_NODE_DAI)) - continue; - - for_each_child_of_node(node, dai_np) { - __rsnd_dai_probe(priv, dai_np, np, dai_i, dai_i); - if (!rsnd_is_gen1(priv) && !rsnd_is_gen2(priv)) { - rdai = rsnd_rdai_get(priv, dai_i); - - rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); - rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); - } - dai_i++; - } - } - } - - return 0; -} - -/* - * pcm ops - */ -static int rsnd_hw_update(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - struct rsnd_priv *priv = rsnd_io_to_priv(io); - unsigned long flags; - int ret; - - spin_lock_irqsave(&priv->lock, flags); - if (hw_params) - ret = rsnd_dai_call(hw_params, io, substream, hw_params); - else - ret = rsnd_dai_call(hw_free, io, substream); - spin_unlock_irqrestore(&priv->lock, flags); - - return ret; -} - -static int rsnd_hw_params(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); - - /* - * rsnd assumes that it might be used under DPCM if user want to use - * channel / rate convert. Then, rsnd should be FE. - * And then, this function will be called *after* BE settings. - * this means, each BE already has fixuped hw_params. - * see - * dpcm_fe_dai_hw_params() - * dpcm_be_dai_hw_params() - */ - io->converted_rate = 0; - io->converted_chan = 0; - if (fe->dai_link->dynamic) { - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_soc_dpcm *dpcm; - int stream = substream->stream; - - for_each_dpcm_be(fe, stream, dpcm) { - struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_pcm_hw_params *be_params = &be->dpcm[stream].hw_params; - - if (params_channels(hw_params) != params_channels(be_params)) - io->converted_chan = params_channels(be_params); - if (params_rate(hw_params) != params_rate(be_params)) - io->converted_rate = params_rate(be_params); - } - if (io->converted_chan) - dev_dbg(dev, "convert channels = %d\n", io->converted_chan); - if (io->converted_rate) { - /* - * SRC supports convert rates from params_rate(hw_params)/k_down - * to params_rate(hw_params)*k_up, where k_up is always 6, and - * k_down depends on number of channels and SRC unit. - * So all SRC units can upsample audio up to 6 times regardless - * its number of channels. And all SRC units can downsample - * 2 channel audio up to 6 times too. - */ - int k_up = 6; - int k_down = 6; - int channel; - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - - dev_dbg(dev, "convert rate = %d\n", io->converted_rate); - - channel = io->converted_chan ? io->converted_chan : - params_channels(hw_params); - - switch (rsnd_mod_id(src_mod)) { - /* - * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times. - * SRC1, SRC3 and SRC4 can downsample 4 channel audio - * up to 4 times. - * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio - * no more than twice. - */ - case 1: - case 3: - case 4: - if (channel > 4) { - k_down = 2; - break; - } - fallthrough; - case 0: - if (channel > 2) - k_down = 4; - break; - - /* Other SRC units do not support more than 2 channels */ - default: - if (channel > 2) - return -EINVAL; - } - - if (params_rate(hw_params) > io->converted_rate * k_down) { - hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = - io->converted_rate * k_down; - hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = - io->converted_rate * k_down; - hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; - } else if (params_rate(hw_params) * k_up < io->converted_rate) { - hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = - DIV_ROUND_UP(io->converted_rate, k_up); - hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = - DIV_ROUND_UP(io->converted_rate, k_up); - hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; - } - - /* - * TBD: Max SRC input and output rates also depend on number - * of channels and SRC unit: - * SRC1, SRC3 and SRC4 do not support more than 128kHz - * for 6 channel and 96kHz for 8 channel audio. - * Perhaps this function should return EINVAL if the input or - * the output rate exceeds the limitation. - */ - } - } - - return rsnd_hw_update(substream, hw_params); -} - -static int rsnd_hw_free(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - return rsnd_hw_update(substream, NULL); -} - -static snd_pcm_uframes_t rsnd_pointer(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); - struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); - struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - snd_pcm_uframes_t pointer = 0; - - rsnd_dai_call(pointer, io, &pointer); - - return pointer; -} - -/* - * snd_kcontrol - */ -static int rsnd_kctrl_info(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_info *uinfo) -{ - struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); - - if (cfg->texts) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = cfg->size; - uinfo->value.enumerated.items = cfg->max; - if (uinfo->value.enumerated.item >= cfg->max) - uinfo->value.enumerated.item = cfg->max - 1; - strscpy(uinfo->value.enumerated.name, - cfg->texts[uinfo->value.enumerated.item], - sizeof(uinfo->value.enumerated.name)); - } else { - uinfo->count = cfg->size; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = cfg->max; - uinfo->type = (cfg->max == 1) ? - SNDRV_CTL_ELEM_TYPE_BOOLEAN : - SNDRV_CTL_ELEM_TYPE_INTEGER; - } - - return 0; -} - -static int rsnd_kctrl_get(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_value *uc) -{ - struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); - int i; - - for (i = 0; i < cfg->size; i++) - if (cfg->texts) - uc->value.enumerated.item[i] = cfg->val[i]; - else - uc->value.integer.value[i] = cfg->val[i]; - - return 0; -} - -static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_value *uc) -{ - struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); - int i, change = 0; - - if (!cfg->accept(cfg->io)) - return 0; - - for (i = 0; i < cfg->size; i++) { - if (cfg->texts) { - change |= (uc->value.enumerated.item[i] != cfg->val[i]); - cfg->val[i] = uc->value.enumerated.item[i]; - } else { - change |= (uc->value.integer.value[i] != cfg->val[i]); - cfg->val[i] = uc->value.integer.value[i]; - } - } - - if (change && cfg->update) - cfg->update(cfg->io, cfg->mod); - - return change; -} - -int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) -{ - return 1; -} - -int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - - if (!runtime) { - dev_warn(dev, "Can't update kctrl when idle\n"); - return 0; - } - - return 1; -} - -struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) -{ - cfg->cfg.val = cfg->val; - - return &cfg->cfg; -} - -struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg) -{ - cfg->cfg.val = &cfg->val; - - return &cfg->cfg; -} - -const char * const volume_ramp_rate[] = { - "128 dB/1 step", /* 00000 */ - "64 dB/1 step", /* 00001 */ - "32 dB/1 step", /* 00010 */ - "16 dB/1 step", /* 00011 */ - "8 dB/1 step", /* 00100 */ - "4 dB/1 step", /* 00101 */ - "2 dB/1 step", /* 00110 */ - "1 dB/1 step", /* 00111 */ - "0.5 dB/1 step", /* 01000 */ - "0.25 dB/1 step", /* 01001 */ - "0.125 dB/1 step", /* 01010 = VOLUME_RAMP_MAX_MIX */ - "0.125 dB/2 steps", /* 01011 */ - "0.125 dB/4 steps", /* 01100 */ - "0.125 dB/8 steps", /* 01101 */ - "0.125 dB/16 steps", /* 01110 */ - "0.125 dB/32 steps", /* 01111 */ - "0.125 dB/64 steps", /* 10000 */ - "0.125 dB/128 steps", /* 10001 */ - "0.125 dB/256 steps", /* 10010 */ - "0.125 dB/512 steps", /* 10011 */ - "0.125 dB/1024 steps", /* 10100 */ - "0.125 dB/2048 steps", /* 10101 */ - "0.125 dB/4096 steps", /* 10110 */ - "0.125 dB/8192 steps", /* 10111 = VOLUME_RAMP_MAX_DVC */ -}; - -int rsnd_kctrl_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - int (*accept)(struct rsnd_dai_stream *io), - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - struct rsnd_kctrl_cfg *cfg, - const char * const *texts, - int size, - u32 max) -{ - struct snd_card *card = rtd->card->snd_card; - struct snd_kcontrol *kctrl; - struct snd_kcontrol_new knew = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = name, - .info = rsnd_kctrl_info, - .index = rtd->num, - .get = rsnd_kctrl_get, - .put = rsnd_kctrl_put, - }; - int ret; - - /* - * 1) Avoid duplicate register for DVC with MIX case - * 2) Allow duplicate register for MIX - * 3) re-register if card was rebinded - */ - list_for_each_entry(kctrl, &card->controls, list) { - struct rsnd_kctrl_cfg *c = kctrl->private_data; - - if (c == cfg) - return 0; - } - - if (size > RSND_MAX_CHANNELS) - return -EINVAL; - - kctrl = snd_ctl_new1(&knew, cfg); - if (!kctrl) - return -ENOMEM; - - ret = snd_ctl_add(card, kctrl); - if (ret < 0) - return ret; - - cfg->texts = texts; - cfg->max = max; - cfg->size = size; - cfg->accept = accept; - cfg->update = update; - cfg->card = card; - cfg->kctrl = kctrl; - cfg->io = io; - cfg->mod = mod; - - return 0; -} - -/* - * snd_soc_component - */ -static const struct snd_soc_component_driver rsnd_soc_component = { - .name = "rsnd", - .probe = rsnd_debugfs_probe, - .hw_params = rsnd_hw_params, - .hw_free = rsnd_hw_free, - .pointer = rsnd_pointer, - .legacy_dai_naming = 1, -}; - -static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, - struct rsnd_dai_stream *io) -{ - int ret; - - ret = rsnd_dai_call(probe, io, priv); - if (ret == -EAGAIN) { - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *mod; - int i; - - /* - * Fallback to PIO mode - */ - - /* - * call "remove" for SSI/SRC/DVC - * SSI will be switch to PIO mode if it was DMA mode - * see - * rsnd_dma_init() - * rsnd_ssi_fallback() - */ - rsnd_dai_call(remove, io, priv); - - /* - * remove all mod from io - * and, re connect ssi - */ - for_each_rsnd_mod(i, mod, io) - rsnd_dai_disconnect(mod, io, i); - rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); - - /* - * fallback - */ - rsnd_dai_call(fallback, io, priv); - - /* - * retry to "probe". - * DAI has SSI which is PIO mode only now. - */ - ret = rsnd_dai_call(probe, io, priv); - } - - return ret; -} - -/* - * rsnd probe - */ -static int rsnd_probe(struct platform_device *pdev) -{ - struct rsnd_priv *priv; - struct device *dev = &pdev->dev; - struct rsnd_dai *rdai; - int (*probe_func[])(struct rsnd_priv *priv) = { - rsnd_gen_probe, - rsnd_dma_probe, - rsnd_ssi_probe, - rsnd_ssiu_probe, - rsnd_src_probe, - rsnd_ctu_probe, - rsnd_mix_probe, - rsnd_dvc_probe, - rsnd_cmd_probe, - rsnd_adg_probe, - rsnd_dai_probe, - }; - int ret, i; - int ci; - - /* - * init priv data - */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENODEV; - - priv->pdev = pdev; - priv->flags = (unsigned long)of_device_get_match_data(dev); - spin_lock_init(&priv->lock); - - /* - * init each module - */ - for (i = 0; i < ARRAY_SIZE(probe_func); i++) { - ret = probe_func[i](priv); - if (ret) - return ret; - } - - for_each_rsnd_dai(rdai, priv, i) { - ret = rsnd_rdai_continuance_probe(priv, &rdai->playback); - if (ret) - goto exit_snd_probe; - - ret = rsnd_rdai_continuance_probe(priv, &rdai->capture); - if (ret) - goto exit_snd_probe; - } - - dev_set_drvdata(dev, priv); - - /* - * asoc register - */ - ci = 0; - for (i = 0; priv->component_dais[i] > 0; i++) { - int nr = priv->component_dais[i]; - - ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, - priv->daidrv + ci, nr); - if (ret < 0) { - dev_err(dev, "cannot snd component register\n"); - goto exit_snd_probe; - } - - ci += nr; - } - - pm_runtime_enable(dev); - - dev_info(dev, "probed\n"); - return ret; - -exit_snd_probe: - for_each_rsnd_dai(rdai, priv, i) { - rsnd_dai_call(remove, &rdai->playback, priv); - rsnd_dai_call(remove, &rdai->capture, priv); - } - - /* - * adg is very special mod which can't use rsnd_dai_call(remove), - * and it registers ADG clock on probe. - * It should be unregister if probe failed. - * Mainly it is assuming -EPROBE_DEFER case - */ - rsnd_adg_remove(priv); - - return ret; -} - -static void rsnd_remove(struct platform_device *pdev) -{ - struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); - struct rsnd_dai *rdai; - void (*remove_func[])(struct rsnd_priv *priv) = { - rsnd_ssi_remove, - rsnd_ssiu_remove, - rsnd_src_remove, - rsnd_ctu_remove, - rsnd_mix_remove, - rsnd_dvc_remove, - rsnd_cmd_remove, - rsnd_adg_remove, - }; - int i; - - pm_runtime_disable(&pdev->dev); - - for_each_rsnd_dai(rdai, priv, i) { - int ret; - - ret = rsnd_dai_call(remove, &rdai->playback, priv); - if (ret) - dev_warn(&pdev->dev, "Failed to remove playback dai #%d\n", i); - - ret = rsnd_dai_call(remove, &rdai->capture, priv); - if (ret) - dev_warn(&pdev->dev, "Failed to remove capture dai #%d\n", i); - } - - for (i = 0; i < ARRAY_SIZE(remove_func); i++) - remove_func[i](priv); -} - -static int __maybe_unused rsnd_suspend(struct device *dev) -{ - struct rsnd_priv *priv = dev_get_drvdata(dev); - - rsnd_adg_clk_disable(priv); - - return 0; -} - -static int __maybe_unused rsnd_resume(struct device *dev) -{ - struct rsnd_priv *priv = dev_get_drvdata(dev); - - rsnd_adg_clk_enable(priv); - - return 0; -} - -static const struct dev_pm_ops rsnd_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume) -}; - -static struct platform_driver rsnd_driver = { - .driver = { - .name = "rcar_sound", - .pm = &rsnd_pm_ops, - .of_match_table = rsnd_of_match, - }, - .probe = rsnd_probe, - .remove = rsnd_remove, -}; -module_platform_driver(rsnd_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Renesas R-Car audio driver"); -MODULE_AUTHOR("Kuninori Morimoto "); -MODULE_ALIAS("platform:rcar-pcm-audio"); diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c deleted file mode 100644 index a26ec7b780cd64..00000000000000 --- a/sound/soc/sh/rcar/ctu.c +++ /dev/null @@ -1,389 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ctu.c -// -// Copyright (c) 2015 Kuninori Morimoto - -#include "rsnd.h" - -#define CTU_NAME_SIZE 16 -#define CTU_NAME "ctu" - -/* - * User needs to setup CTU by amixer, and its settings are - * based on below registers - * - * CTUn_CPMDR : amixser set "CTU Pass" - * CTUn_SV0xR : amixser set "CTU SV0" - * CTUn_SV1xR : amixser set "CTU SV1" - * CTUn_SV2xR : amixser set "CTU SV2" - * CTUn_SV3xR : amixser set "CTU SV3" - * - * [CTU Pass] - * 0000: default - * 0001: Connect input data of channel 0 - * 0010: Connect input data of channel 1 - * 0011: Connect input data of channel 2 - * 0100: Connect input data of channel 3 - * 0101: Connect input data of channel 4 - * 0110: Connect input data of channel 5 - * 0111: Connect input data of channel 6 - * 1000: Connect input data of channel 7 - * 1001: Connect calculated data by scale values of matrix row 0 - * 1010: Connect calculated data by scale values of matrix row 1 - * 1011: Connect calculated data by scale values of matrix row 2 - * 1100: Connect calculated data by scale values of matrix row 3 - * - * [CTU SVx] - * [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07] - * [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17] - * [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27] - * [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37] - * [Output4] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] - * [Output5] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] - * [Output6] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] - * [Output7] = [ 0, 0, 0, 0, 0, 0, 0, 0 ] - * - * [SVxx] - * Plus Minus - * value time dB value time dB - * ----------------------------------------------------------------------- - * H'7F_FFFF 2 6 H'80_0000 2 6 - * ... - * H'40_0000 1 0 H'C0_0000 1 0 - * ... - * H'00_0001 2.38 x 10^-7 -132 - * H'00_0000 0 Mute H'FF_FFFF 2.38 x 10^-7 -132 - * - * - * Ex) Input ch -> Output ch - * 1ch -> 0ch - * 0ch -> 1ch - * - * amixer set "CTU Reset" on - * amixer set "CTU Pass" 9,10 - * amixer set "CTU SV0" 0,4194304 - * amixer set "CTU SV1" 4194304,0 - * or - * amixer set "CTU Reset" on - * amixer set "CTU Pass" 2,1 - */ - -struct rsnd_ctu { - struct rsnd_mod mod; - struct rsnd_kctrl_cfg_m pass; - struct rsnd_kctrl_cfg_m sv[4]; - struct rsnd_kctrl_cfg_s reset; - int channels; - u32 flags; -}; - -#define KCTRL_INITIALIZED (1 << 0) - -#define rsnd_ctu_nr(priv) ((priv)->ctu_nr) -#define for_each_rsnd_ctu(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_ctu_nr(priv)) && \ - ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ - i++) - -#define rsnd_mod_to_ctu(_mod) \ - container_of((_mod), struct rsnd_ctu, mod) - -#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) - -static void rsnd_ctu_activation(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, CTU_SWRSR, 0); - rsnd_mod_write(mod, CTU_SWRSR, 1); -} - -static void rsnd_ctu_halt(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, CTU_CTUIR, 1); - rsnd_mod_write(mod, CTU_SWRSR, 0); -} - -static int rsnd_ctu_probe_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return rsnd_cmd_attach(io, rsnd_mod_id(mod)); -} - -static void rsnd_ctu_value_init(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); - u32 cpmdr = 0; - u32 scmdr = 0; - int i, j; - - for (i = 0; i < RSND_MAX_CHANNELS; i++) { - u32 val = rsnd_kctrl_valm(ctu->pass, i); - - cpmdr |= val << (28 - (i * 4)); - - if ((val > 0x8) && (scmdr < (val - 0x8))) - scmdr = val - 0x8; - } - - rsnd_mod_write(mod, CTU_CTUIR, 1); - - rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io)); - - rsnd_mod_write(mod, CTU_CPMDR, cpmdr); - - rsnd_mod_write(mod, CTU_SCMDR, scmdr); - - for (i = 0; i < 4; i++) { - - if (i >= scmdr) - break; - - for (j = 0; j < RSND_MAX_CHANNELS; j++) - rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j)); - } - - rsnd_mod_write(mod, CTU_CTUIR, 0); -} - -static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); - int i; - - if (!rsnd_kctrl_vals(ctu->reset)) - return; - - for (i = 0; i < RSND_MAX_CHANNELS; i++) { - rsnd_kctrl_valm(ctu->pass, i) = 0; - rsnd_kctrl_valm(ctu->sv[0], i) = 0; - rsnd_kctrl_valm(ctu->sv[1], i) = 0; - rsnd_kctrl_valm(ctu->sv[2], i) = 0; - rsnd_kctrl_valm(ctu->sv[3], i) = 0; - } - rsnd_kctrl_vals(ctu->reset) = 0; -} - -static int rsnd_ctu_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_ctu_activation(mod); - - rsnd_ctu_value_init(io, mod); - - return 0; -} - -static int rsnd_ctu_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_ctu_halt(mod); - - rsnd_mod_power_off(mod); - - return 0; -} - -static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod); - int ret; - - if (rsnd_flags_has(ctu, KCTRL_INITIALIZED)) - return 0; - - /* CTU Pass */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->pass, RSND_MAX_CHANNELS, - 0xC); - if (ret < 0) - return ret; - - /* ROW0 */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->sv[0], RSND_MAX_CHANNELS, - 0x00FFFFFF); - if (ret < 0) - return ret; - - /* ROW1 */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->sv[1], RSND_MAX_CHANNELS, - 0x00FFFFFF); - if (ret < 0) - return ret; - - /* ROW2 */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->sv[2], RSND_MAX_CHANNELS, - 0x00FFFFFF); - if (ret < 0) - return ret; - - /* ROW3 */ - ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3", - rsnd_kctrl_accept_anytime, - NULL, - &ctu->sv[3], RSND_MAX_CHANNELS, - 0x00FFFFFF); - if (ret < 0) - return ret; - - /* Reset */ - ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset", - rsnd_kctrl_accept_anytime, - rsnd_ctu_value_reset, - &ctu->reset, 1); - - rsnd_flags_set(ctu, KCTRL_INITIALIZED); - - return ret; -} - -static int rsnd_ctu_id(struct rsnd_mod *mod) -{ - /* - * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0 - * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1 - */ - return mod->id / 4; -} - -static int rsnd_ctu_id_sub(struct rsnd_mod *mod) -{ - /* - * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3 - * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3 - */ - return mod->id % 4; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_ctu_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, - 0x500 + rsnd_mod_id_raw(mod) * 0x100, 0x100); -} -#define DEBUG_INFO .debug_info = rsnd_ctu_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_ctu_ops = { - .name = CTU_NAME, - .probe = rsnd_ctu_probe_, - .init = rsnd_ctu_init, - .quit = rsnd_ctu_quit, - .pcm_new = rsnd_ctu_pcm_new, - .get_status = rsnd_mod_get_status, - .id = rsnd_ctu_id, - .id_sub = rsnd_ctu_id_sub, - .id_cmd = rsnd_mod_id_raw, - DEBUG_INFO -}; - -struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_ctu_get(priv, id)); -} - -int rsnd_ctu_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_ctu *ctu; - struct clk *clk; - char name[CTU_NAME_SIZE]; - int i, nr, ret; - - node = rsnd_ctu_of_node(priv); - if (!node) - return 0; /* not used is not error */ - - nr = of_get_child_count(node); - if (!nr) { - ret = -EINVAL; - goto rsnd_ctu_probe_done; - } - - ctu = devm_kcalloc(dev, nr, sizeof(*ctu), GFP_KERNEL); - if (!ctu) { - ret = -ENOMEM; - goto rsnd_ctu_probe_done; - } - - priv->ctu_nr = nr; - priv->ctu = ctu; - - i = 0; - ret = 0; - for_each_child_of_node(node, np) { - ctu = rsnd_ctu_get(priv, i); - - /* - * CTU00, CTU01, CTU02, CTU03 => CTU0 - * CTU10, CTU11, CTU12, CTU13 => CTU1 - */ - snprintf(name, CTU_NAME_SIZE, "%s.%d", - CTU_NAME, i / 4); - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_ctu_probe_done; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, - clk, RSND_MOD_CTU, i); - if (ret) { - of_node_put(np); - goto rsnd_ctu_probe_done; - } - - i++; - } - - -rsnd_ctu_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_ctu_remove(struct rsnd_priv *priv) -{ - struct rsnd_ctu *ctu; - int i; - - for_each_rsnd_ctu(ctu, priv, i) { - rsnd_mod_quit(rsnd_mod_get(ctu)); - } -} diff --git a/sound/soc/sh/rcar/debugfs.c b/sound/soc/sh/rcar/debugfs.c deleted file mode 100644 index 26d3b310b9db7d..00000000000000 --- a/sound/soc/sh/rcar/debugfs.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// // Renesas R-Car debugfs support -// -// Copyright (c) 2021 Kuninori Morimoto -// -// > mount -t debugfs none /sys/kernel/debug -// > cd /sys/kernel/debug/asoc/rcar-sound/ec500000.sound/rdai{N}/ -// > cat playback/xxx -// > cat capture/xxx -// -#ifdef CONFIG_DEBUG_FS - -#include -#include "rsnd.h" - -static int rsnd_debugfs_show(struct seq_file *m, void *v) -{ - struct rsnd_dai_stream *io = m->private; - struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - int i; - - /* adg is out of mods */ - rsnd_adg_clk_dbg_info(priv, m); - - for_each_rsnd_mod(i, mod, io) { - u32 *status = mod->ops->get_status(mod, io, mod->type); - - seq_printf(m, "name: %s\n", rsnd_mod_name(mod)); - seq_printf(m, "status: %08x\n", *status); - - if (mod->ops->debug_info) - mod->ops->debug_info(m, io, mod); - } - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(rsnd_debugfs); - -void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr, - void __iomem *base, int offset, int size) -{ - int i, j; - - for (i = 0; i < size; i += 0x10) { - phys_addr_t addr = _addr + offset + i; - - seq_printf(m, "%pa:", &addr); - for (j = 0; j < 0x10; j += 0x4) - seq_printf(m, " %08x", __raw_readl(base + offset + i + j)); - seq_puts(m, "\n"); - } -} - -void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod, - int reg_id, int offset, int size) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - - rsnd_debugfs_reg_show(m, - rsnd_gen_get_phy_addr(priv, reg_id), - rsnd_gen_get_base_addr(priv, reg_id), - offset, size); -} - -int rsnd_debugfs_probe(struct snd_soc_component *component) -{ - struct rsnd_priv *priv = dev_get_drvdata(component->dev); - struct rsnd_dai *rdai; - struct dentry *dir; - char name[64]; - int i; - - /* Gen1 is not supported */ - if (rsnd_is_gen1(priv)) - return 0; - - for_each_rsnd_dai(rdai, priv, i) { - /* - * created debugfs will be automatically - * removed, nothing to do for _remove. - * see - * soc_cleanup_component_debugfs() - */ - snprintf(name, sizeof(name), "rdai%d", i); - dir = debugfs_create_dir(name, component->debugfs_root); - - debugfs_create_file("playback", 0444, dir, &rdai->playback, &rsnd_debugfs_fops); - debugfs_create_file("capture", 0444, dir, &rdai->capture, &rsnd_debugfs_fops); - } - - return 0; -} - -#endif /* CONFIG_DEBUG_FS */ diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c deleted file mode 100644 index 2342bbb6fe92e8..00000000000000 --- a/sound/soc/sh/rcar/dma.c +++ /dev/null @@ -1,885 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car Audio DMAC support -// -// Copyright (C) 2015 Renesas Electronics Corp. -// Copyright (c) 2015 Kuninori Morimoto - -#include -#include -#include -#include "rsnd.h" - -/* - * Audio DMAC peri peri register - */ -#define PDMASAR 0x00 -#define PDMADAR 0x04 -#define PDMACHCR 0x0c - -/* PDMACHCR */ -#define PDMACHCR_DE (1 << 0) - - -struct rsnd_dmaen { - struct dma_chan *chan; -}; - -struct rsnd_dmapp { - int dmapp_id; - u32 chcr; -}; - -struct rsnd_dma { - struct rsnd_mod mod; - struct rsnd_mod *mod_from; - struct rsnd_mod *mod_to; - dma_addr_t src_addr; - dma_addr_t dst_addr; - union { - struct rsnd_dmaen en; - struct rsnd_dmapp pp; - } dma; -}; - -struct rsnd_dma_ctrl { - void __iomem *ppbase; - phys_addr_t ppres; - int dmaen_num; - int dmapp_num; -}; - -#define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) -#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod) -#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) -#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) - -/* for DEBUG */ -static struct rsnd_mod_ops mem_ops = { - .name = "mem", -}; - -static struct rsnd_mod mem = { -}; - -/* - * Audio DMAC - */ -static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, - struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to) -{ - if ((!mod_from && !mod_to) || - (mod_from && mod_to)) - return NULL; - - if (mod_from) - return rsnd_mod_dma_req(io, mod_from); - else - return rsnd_mod_dma_req(io, mod_to); -} - -static int rsnd_dmaen_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP); -} - -static int rsnd_dmaen_cleanup(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - /* - * DMAEngine release uses mutex lock. - * Thus, it shouldn't be called under spinlock. - * Let's call it under prepare - */ - if (dmaen->chan) - snd_dmaengine_pcm_close_release_chan(io->substream); - - dmaen->chan = NULL; - - return 0; -} - -static int rsnd_dmaen_prepare(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct device *dev = rsnd_priv_to_dev(priv); - - /* maybe suspended */ - if (dmaen->chan) - return 0; - - /* - * DMAEngine request uses mutex lock. - * Thus, it shouldn't be called under spinlock. - * Let's call it under prepare - */ - dmaen->chan = rsnd_dmaen_request_channel(io, - dma->mod_from, - dma->mod_to); - if (IS_ERR_OR_NULL(dmaen->chan)) { - dmaen->chan = NULL; - dev_err(dev, "can't get dma channel\n"); - return -EIO; - } - - return snd_dmaengine_pcm_open(io->substream, dmaen->chan); -} - -static int rsnd_dmaen_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_slave_config cfg = {}; - enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; - int ret; - - /* - * in case of monaural data writing or reading through Audio-DMAC - * data is always in Left Justified format, so both src and dst - * DMA Bus width need to be set equal to physical data width. - */ - if (rsnd_runtime_channel_original(io) == 1) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int bits = snd_pcm_format_physical_width(runtime->format); - - switch (bits) { - case 8: - buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; - break; - case 16: - buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; - break; - case 32: - buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; - break; - default: - dev_err(dev, "invalid format width %d\n", bits); - return -EINVAL; - } - } - - cfg.direction = snd_pcm_substream_to_dma_direction(io->substream); - cfg.src_addr = dma->src_addr; - cfg.dst_addr = dma->dst_addr; - cfg.src_addr_width = buswidth; - cfg.dst_addr_width = buswidth; - - dev_dbg(dev, "%s %pad -> %pad\n", - rsnd_mod_name(mod), - &cfg.src_addr, &cfg.dst_addr); - - ret = dmaengine_slave_config(dmaen->chan, &cfg); - if (ret < 0) - return ret; - - return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START); -} - -struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, - struct rsnd_mod *mod, char *x) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_chan *chan = NULL; - struct device_node *np; - int i = 0; - - for_each_child_of_node(of_node, np) { - i = rsnd_node_fixed_index(dev, np, name, i); - if (i < 0) { - chan = NULL; - of_node_put(np); - break; - } - - if (i == rsnd_mod_id_raw(mod) && (!chan)) - chan = of_dma_request_slave_channel(np, x); - i++; - } - - /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ - of_node_put(of_node); - - return chan; -} - -static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct dma_chan *chan; - - /* try to get DMAEngine channel */ - chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - if (IS_ERR_OR_NULL(chan)) { - /* Let's follow when -EPROBE_DEFER case */ - if (PTR_ERR(chan) == -EPROBE_DEFER) - return PTR_ERR(chan); - - /* - * DMA failed. try to PIO mode - * see - * rsnd_ssi_fallback() - * rsnd_rdai_continuance_probe() - */ - return -EAGAIN; - } - - /* - * use it for IPMMU if needed - * see - * rsnd_preallocate_pages() - */ - io->dmac_dev = chan->device->dev; - - dma_release_channel(chan); - - dmac->dmaen_num++; - - return 0; -} - -static int rsnd_dmaen_pointer(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - snd_pcm_uframes_t *pointer) -{ - *pointer = snd_dmaengine_pcm_pointer(io->substream); - - return 0; -} - -static struct rsnd_mod_ops rsnd_dmaen_ops = { - .name = "audmac", - .prepare = rsnd_dmaen_prepare, - .cleanup = rsnd_dmaen_cleanup, - .start = rsnd_dmaen_start, - .stop = rsnd_dmaen_stop, - .pointer = rsnd_dmaen_pointer, - .get_status = rsnd_mod_get_status, -}; - -/* - * Audio DMAC peri peri - */ -static const u8 gen2_id_table_ssiu[] = { - /* SSI00 ~ SSI07 */ - 0x00, 0x01, 0x02, 0x03, 0x39, 0x3a, 0x3b, 0x3c, - /* SSI10 ~ SSI17 */ - 0x04, 0x05, 0x06, 0x07, 0x3d, 0x3e, 0x3f, 0x40, - /* SSI20 ~ SSI27 */ - 0x08, 0x09, 0x0a, 0x0b, 0x41, 0x42, 0x43, 0x44, - /* SSI30 ~ SSI37 */ - 0x0c, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, - /* SSI40 ~ SSI47 */ - 0x0d, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, - /* SSI5 */ - 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* SSI6 */ - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* SSI7 */ - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* SSI8 */ - 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* SSI90 ~ SSI97 */ - 0x12, 0x13, 0x14, 0x15, 0x53, 0x54, 0x55, 0x56, -}; -static const u8 gen2_id_table_scu[] = { - 0x2d, /* SCU_SRCI0 */ - 0x2e, /* SCU_SRCI1 */ - 0x2f, /* SCU_SRCI2 */ - 0x30, /* SCU_SRCI3 */ - 0x31, /* SCU_SRCI4 */ - 0x32, /* SCU_SRCI5 */ - 0x33, /* SCU_SRCI6 */ - 0x34, /* SCU_SRCI7 */ - 0x35, /* SCU_SRCI8 */ - 0x36, /* SCU_SRCI9 */ -}; -static const u8 gen2_id_table_cmd[] = { - 0x37, /* SCU_CMD0 */ - 0x38, /* SCU_CMD1 */ -}; - -static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - const u8 *entry = NULL; - int id = 255; - int size = 0; - - if ((mod == ssi) || - (mod == ssiu)) { - int busif = rsnd_mod_id_sub(ssiu); - - entry = gen2_id_table_ssiu; - size = ARRAY_SIZE(gen2_id_table_ssiu); - id = (rsnd_mod_id(mod) * 8) + busif; - } else if (mod == src) { - entry = gen2_id_table_scu; - size = ARRAY_SIZE(gen2_id_table_scu); - id = rsnd_mod_id(mod); - } else if (mod == dvc) { - entry = gen2_id_table_cmd; - size = ARRAY_SIZE(gen2_id_table_cmd); - id = rsnd_mod_id(mod); - } - - if ((!entry) || (size <= id)) { - struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); - - dev_err(dev, "unknown connection (%s)\n", rsnd_mod_name(mod)); - - /* use non-prohibited SRS number as error */ - return 0x00; /* SSI00 */ - } - - return entry[id]; -} - -static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, - struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to) -{ - return (rsnd_dmapp_get_id(io, mod_from) << 24) + - (rsnd_dmapp_get_id(io, mod_to) << 16); -} - -#define rsnd_dmapp_addr(dmac, dma, reg) \ - (dmac->ppbase + 0x20 + reg + \ - (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) -static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) -{ - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_dbg(dev, "w 0x%px : %08x\n", rsnd_dmapp_addr(dmac, dma, reg), data); - - iowrite32(data, rsnd_dmapp_addr(dmac, dma, reg)); -} - -static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) -{ - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - - return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); -} - -static void rsnd_dmapp_bset(struct rsnd_dma *dma, u32 data, u32 mask, u32 reg) -{ - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - void __iomem *addr = rsnd_dmapp_addr(dmac, dma, reg); - u32 val = ioread32(addr); - - val &= ~mask; - val |= (data & mask); - - iowrite32(val, addr); -} - -static int rsnd_dmapp_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - int i; - - rsnd_dmapp_bset(dma, 0, PDMACHCR_DE, PDMACHCR); - - for (i = 0; i < 1024; i++) { - if (0 == (rsnd_dmapp_read(dma, PDMACHCR) & PDMACHCR_DE)) - return 0; - udelay(1); - } - - return -EIO; -} - -static int rsnd_dmapp_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); - - rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); - rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); - rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); - - return 0; -} - -static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) -{ - struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - - dmapp->dmapp_id = dmac->dmapp_num; - dmapp->chcr = rsnd_dmapp_get_chcr(io, mod_from, mod_to) | PDMACHCR_DE; - - dmac->dmapp_num++; - - dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", - dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); - - return 0; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_dmapp_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); - - rsnd_debugfs_reg_show(m, dmac->ppres, dmac->ppbase, - 0x20 + 0x10 * dmapp->dmapp_id, 0x10); -} -#define DEBUG_INFO .debug_info = rsnd_dmapp_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_dmapp_ops = { - .name = "audmac-pp", - .start = rsnd_dmapp_start, - .stop = rsnd_dmapp_stop, - .quit = rsnd_dmapp_stop, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -/* - * Common DMAC Interface - */ - -/* - * DMA read/write register offset - * - * RSND_xxx_I_N for Audio DMAC input - * RSND_xxx_O_N for Audio DMAC output - * RSND_xxx_I_P for Audio DMAC peri peri input - * RSND_xxx_O_P for Audio DMAC peri peri output - * - * ex) R-Car H2 case - * mod / DMAC in / DMAC out / DMAC PP in / DMAC pp out - * SSI : 0xec541000 / 0xec241008 / 0xec24100c - * SSIU: 0xec541000 / 0xec100000 / 0xec100000 / 0xec400000 / 0xec400000 - * SCU : 0xec500000 / 0xec000000 / 0xec004000 / 0xec300000 / 0xec304000 - * CMD : 0xec500000 / / 0xec008000 0xec308000 - */ -#define RDMA_SSI_I_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0x8) -#define RDMA_SSI_O_N(addr, i) (addr ##_reg - 0x00300000 + (0x40 * i) + 0xc) - -#define RDMA_SSIU_I_N(addr, i, j) (addr ##_reg - 0x00441000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4))) -#define RDMA_SSIU_O_N(addr, i, j) RDMA_SSIU_I_N(addr, i, j) - -#define RDMA_SSIU_I_P(addr, i, j) (addr ##_reg - 0x00141000 + (0x1000 * (i)) + (((j) / 4) * 0xA000) + (((j) % 4) * 0x400) - (0x4000 * ((i) / 9) * ((j) / 4))) -#define RDMA_SSIU_O_P(addr, i, j) RDMA_SSIU_I_P(addr, i, j) - -#define RDMA_SRC_I_N(addr, i) (addr ##_reg - 0x00500000 + (0x400 * i)) -#define RDMA_SRC_O_N(addr, i) (addr ##_reg - 0x004fc000 + (0x400 * i)) - -#define RDMA_SRC_I_P(addr, i) (addr ##_reg - 0x00200000 + (0x400 * i)) -#define RDMA_SRC_O_P(addr, i) (addr ##_reg - 0x001fc000 + (0x400 * i)) - -#define RDMA_CMD_O_N(addr, i) (addr ##_reg - 0x004f8000 + (0x400 * i)) -#define RDMA_CMD_O_P(addr, i) (addr ##_reg - 0x001f8000 + (0x400 * i)) - -static dma_addr_t -rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - int is_play, int is_from) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - phys_addr_t ssi_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SSI); - phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_BASE_SCU); - int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod) || - !!(rsnd_io_to_mod_ssiu(io) == mod); - int use_src = !!rsnd_io_to_mod_src(io); - int use_cmd = !!rsnd_io_to_mod_dvc(io) || - !!rsnd_io_to_mod_mix(io) || - !!rsnd_io_to_mod_ctu(io); - int id = rsnd_mod_id(mod); - int busif = rsnd_mod_id_sub(rsnd_io_to_mod_ssiu(io)); - struct dma_addr { - dma_addr_t out_addr; - dma_addr_t in_addr; - } dma_addrs[3][2][3] = { - /* SRC */ - /* Capture */ - {{{ 0, 0 }, - { RDMA_SRC_O_N(src, id), RDMA_SRC_I_P(src, id) }, - { RDMA_CMD_O_N(src, id), RDMA_SRC_I_P(src, id) } }, - /* Playback */ - {{ 0, 0, }, - { RDMA_SRC_O_P(src, id), RDMA_SRC_I_N(src, id) }, - { RDMA_CMD_O_P(src, id), RDMA_SRC_I_N(src, id) } } - }, - /* SSI */ - /* Capture */ - {{{ RDMA_SSI_O_N(ssi, id), 0 }, - { RDMA_SSIU_O_P(ssi, id, busif), 0 }, - { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, - /* Playback */ - {{ 0, RDMA_SSI_I_N(ssi, id) }, - { 0, RDMA_SSIU_I_P(ssi, id, busif) }, - { 0, RDMA_SSIU_I_P(ssi, id, busif) } } - }, - /* SSIU */ - /* Capture */ - {{{ RDMA_SSIU_O_N(ssi, id, busif), 0 }, - { RDMA_SSIU_O_P(ssi, id, busif), 0 }, - { RDMA_SSIU_O_P(ssi, id, busif), 0 } }, - /* Playback */ - {{ 0, RDMA_SSIU_I_N(ssi, id, busif) }, - { 0, RDMA_SSIU_I_P(ssi, id, busif) }, - { 0, RDMA_SSIU_I_P(ssi, id, busif) } } }, - }; - - /* - * FIXME - * - * We can't support SSI9-4/5/6/7, because its address is - * out of calculation rule - */ - if ((id == 9) && (busif >= 4)) - dev_err(dev, "This driver doesn't support SSI%d-%d, so far", - id, busif); - - /* it shouldn't happen */ - if (use_cmd && !use_src) - dev_err(dev, "DVC is selected without SRC\n"); - - /* use SSIU or SSI ? */ - if (is_ssi && rsnd_ssi_use_busif(io)) - is_ssi++; - - return (is_from) ? - dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr : - dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr; -} - -/* - * Gen4 DMA read/write register offset - * - * ex) R-Car V4H case - * mod / SYS-DMAC in / SYS-DMAC out - * SSI_SDMC: 0xec400000 / 0xec400000 / 0xec400000 - */ -#define RDMA_SSI_SDMC(addr, i) (addr + (0x8000 * i)) -static dma_addr_t -rsnd_gen4_dma_addr(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - int is_play, int is_from) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - phys_addr_t addr = rsnd_gen_get_phy_addr(priv, RSND_BASE_SDMC); - int id = rsnd_mod_id(mod); - int busif = rsnd_mod_id_sub(mod); - - /* - * SSI0 only is supported - */ - if (id != 0) { - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "This driver doesn't support non SSI0"); - return -EINVAL; - } - - return RDMA_SSI_SDMC(addr, busif); -} - -static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, - int is_play, int is_from) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - - if (!mod) - return 0; - - /* - * gen1 uses default DMA addr - */ - if (rsnd_is_gen1(priv)) - return 0; - else if (rsnd_is_gen4(priv)) - return rsnd_gen4_dma_addr(io, mod, is_play, is_from); - else - return rsnd_gen2_dma_addr(io, mod, is_play, is_from); -} - -#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ -static void rsnd_dma_of_path(struct rsnd_mod *this, - struct rsnd_dai_stream *io, - int is_play, - struct rsnd_mod **mod_from, - struct rsnd_mod **mod_to) -{ - struct rsnd_mod *ssi; - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); - struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - struct rsnd_mod *mod[MOD_MAX]; - struct rsnd_mod *mod_start, *mod_end; - struct rsnd_priv *priv = rsnd_mod_to_priv(this); - struct device *dev = rsnd_priv_to_dev(priv); - int nr, i, idx; - - /* - * It should use "rcar_sound,ssiu" on DT. - * But, we need to keep compatibility for old version. - * - * If it has "rcar_sound.ssiu", it will be used. - * If not, "rcar_sound.ssi" will be used. - * see - * rsnd_ssiu_dma_req() - * rsnd_ssi_dma_req() - */ - if (rsnd_ssiu_of_node(priv)) { - struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); - - /* use SSIU */ - ssi = ssiu; - if (this == rsnd_io_to_mod_ssi(io)) - this = ssiu; - } else { - /* keep compatible, use SSI */ - ssi = rsnd_io_to_mod_ssi(io); - } - - if (!ssi) - return; - - nr = 0; - for (i = 0; i < MOD_MAX; i++) { - mod[i] = NULL; - nr += !!rsnd_io_to_mod(io, i); - } - - /* - * [S] -*-> [E] - * [S] -*-> SRC -o-> [E] - * [S] -*-> SRC -> DVC -o-> [E] - * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E] - * - * playback [S] = mem - * [E] = SSI - * - * capture [S] = SSI - * [E] = mem - * - * -*-> Audio DMAC - * -o-> Audio DMAC peri peri - */ - mod_start = (is_play) ? NULL : ssi; - mod_end = (is_play) ? ssi : NULL; - - idx = 0; - mod[idx++] = mod_start; - for (i = 1; i < nr; i++) { - if (src) { - mod[idx++] = src; - src = NULL; - } else if (ctu) { - mod[idx++] = ctu; - ctu = NULL; - } else if (mix) { - mod[idx++] = mix; - mix = NULL; - } else if (dvc) { - mod[idx++] = dvc; - dvc = NULL; - } - } - mod[idx] = mod_end; - - /* - * | SSI | SRC | - * -------------+-----+-----+ - * is_play | o | * | - * !is_play | * | o | - */ - if ((this == ssi) == (is_play)) { - *mod_from = mod[idx - 1]; - *mod_to = mod[idx]; - } else { - *mod_from = mod[0]; - *mod_to = mod[1]; - } - - dev_dbg(dev, "module connection (this is %s)\n", rsnd_mod_name(this)); - for (i = 0; i <= idx; i++) { - dev_dbg(dev, " %s%s\n", - rsnd_mod_name(mod[i] ? mod[i] : &mem), - (mod[i] == *mod_from) ? " from" : - (mod[i] == *mod_to) ? " to" : ""); - } -} - -static int rsnd_dma_alloc(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod) -{ - struct rsnd_mod *mod_from = NULL; - struct rsnd_mod *mod_to = NULL; - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dma *dma; - struct rsnd_mod_ops *ops; - enum rsnd_mod_type type; - int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); - int is_play = rsnd_io_is_play(io); - int ret, dma_id; - - /* - * DMA failed. try to PIO mode - * see - * rsnd_ssi_fallback() - * rsnd_rdai_continuance_probe() - */ - if (!dmac) - return -EAGAIN; - - rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); - - /* for Gen2 or later */ - if (mod_from && mod_to) { - ops = &rsnd_dmapp_ops; - attach = rsnd_dmapp_attach; - dma_id = dmac->dmapp_num; - type = RSND_MOD_AUDMAPP; - } else { - ops = &rsnd_dmaen_ops; - attach = rsnd_dmaen_attach; - dma_id = dmac->dmaen_num; - type = RSND_MOD_AUDMA; - } - - /* for Gen1, overwrite */ - if (rsnd_is_gen1(priv)) { - ops = &rsnd_dmaen_ops; - attach = rsnd_dmaen_attach; - dma_id = dmac->dmaen_num; - type = RSND_MOD_AUDMA; - } - - dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); - if (!dma) - return -ENOMEM; - - *dma_mod = rsnd_mod_get(dma); - - ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, - type, dma_id); - if (ret < 0) - return ret; - - dev_dbg(dev, "%s %s -> %s\n", - rsnd_mod_name(*dma_mod), - rsnd_mod_name(mod_from ? mod_from : &mem), - rsnd_mod_name(mod_to ? mod_to : &mem)); - - ret = attach(io, dma, mod_from, mod_to); - if (ret < 0) - return ret; - - dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); - dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); - dma->mod_from = mod_from; - dma->mod_to = mod_to; - - return 0; -} - -int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod) -{ - if (!(*dma_mod)) { - int ret = rsnd_dma_alloc(io, mod, dma_mod); - - if (ret < 0) - return ret; - } - - return rsnd_dai_connect(*dma_mod, io, (*dma_mod)->type); -} - -int rsnd_dma_probe(struct rsnd_priv *priv) -{ - struct platform_device *pdev = rsnd_priv_to_pdev(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dma_ctrl *dmac; - struct resource *res; - - /* - * for Gen1 - */ - if (rsnd_is_gen1(priv)) - return 0; - - /* - * for Gen2 or later - */ - dmac = devm_kzalloc(dev, sizeof(*dmac), GFP_KERNEL); - if (!dmac) { - dev_err(dev, "dma allocate failed\n"); - return 0; /* it will be PIO mode */ - } - - /* for Gen4 doesn't have DMA-pp */ - if (rsnd_is_gen4(priv)) - goto audmapp_end; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audmapp"); - if (!res) { - dev_err(dev, "lack of audmapp in DT\n"); - return 0; /* it will be PIO mode */ - } - - dmac->dmapp_num = 0; - dmac->ppres = res->start; - dmac->ppbase = devm_ioremap_resource(dev, res); - if (IS_ERR(dmac->ppbase)) - return PTR_ERR(dmac->ppbase); -audmapp_end: - priv->dma = dmac; - - /* dummy mem mod for debug */ - return rsnd_mod_init(NULL, &mem, &mem_ops, NULL, 0, 0); -} diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c deleted file mode 100644 index da91dd301aabeb..00000000000000 --- a/sound/soc/sh/rcar/dvc.c +++ /dev/null @@ -1,392 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car DVC support -// -// Copyright (C) 2014 Renesas Solutions Corp. -// Kuninori Morimoto - -/* - * Playback Volume - * amixer set "DVC Out" 100% - * - * Capture Volume - * amixer set "DVC In" 100% - * - * Playback Mute - * amixer set "DVC Out Mute" on - * - * Capture Mute - * amixer set "DVC In Mute" on - * - * Volume Ramp - * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" - * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" - * amixer set "DVC Out Ramp" on - * aplay xxx.wav & - * amixer set "DVC Out" 80% // Volume Down - * amixer set "DVC Out" 100% // Volume Up - */ - -#include "rsnd.h" - -#define RSND_DVC_NAME_SIZE 16 - -#define DVC_NAME "dvc" - -struct rsnd_dvc { - struct rsnd_mod mod; - struct rsnd_kctrl_cfg_m volume; - struct rsnd_kctrl_cfg_m mute; - struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ - struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ - struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ -}; - -#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) -#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) - -#define rsnd_mod_to_dvc(_mod) \ - container_of((_mod), struct rsnd_dvc, mod) - -#define for_each_rsnd_dvc(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_dvc_nr(priv)) && \ - ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ - i++) - -static void rsnd_dvc_activation(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, DVC_SWRSR, 0); - rsnd_mod_write(mod, DVC_SWRSR, 1); -} - -static void rsnd_dvc_halt(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, DVC_DVUIR, 1); - rsnd_mod_write(mod, DVC_SWRSR, 0); -} - -#define rsnd_dvc_get_vrpdr(dvc) (rsnd_kctrl_vals(dvc->rup) << 8 | \ - rsnd_kctrl_vals(dvc->rdown)) -#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (rsnd_kctrl_valm(dvc->volume, 0) >> 13)) - -static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u32 val[RSND_MAX_CHANNELS]; - int i; - - /* Enable Ramp */ - if (rsnd_kctrl_vals(dvc->ren)) - for (i = 0; i < RSND_MAX_CHANNELS; i++) - val[i] = rsnd_kctrl_max(dvc->volume); - else - for (i = 0; i < RSND_MAX_CHANNELS; i++) - val[i] = rsnd_kctrl_valm(dvc->volume, i); - - /* Enable Digital Volume */ - for (i = 0; i < RSND_MAX_CHANNELS; i++) - rsnd_mod_write(mod, DVC_VOLxR(i), val[i]); -} - -static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u32 adinr = 0; - u32 dvucr = 0; - u32 vrctr = 0; - u32 vrpdr = 0; - u32 vrdbr = 0; - - adinr = rsnd_get_adinr_bit(mod, io) | - rsnd_runtime_channel_after_ctu(io); - - /* Enable Digital Volume, Zero Cross Mute Mode */ - dvucr |= 0x101; - - /* Enable Ramp */ - if (rsnd_kctrl_vals(dvc->ren)) { - dvucr |= 0x10; - - /* - * FIXME !! - * use scale-downed Digital Volume - * as Volume Ramp - * 7F FFFF -> 3FF - */ - vrctr = 0xff; - vrpdr = rsnd_dvc_get_vrpdr(dvc); - vrdbr = rsnd_dvc_get_vrdbr(dvc); - } - - /* Initialize operation */ - rsnd_mod_write(mod, DVC_DVUIR, 1); - - /* General Information */ - rsnd_mod_write(mod, DVC_ADINR, adinr); - rsnd_mod_write(mod, DVC_DVUCR, dvucr); - - /* Volume Ramp Parameter */ - rsnd_mod_write(mod, DVC_VRCTR, vrctr); - rsnd_mod_write(mod, DVC_VRPDR, vrpdr); - rsnd_mod_write(mod, DVC_VRDBR, vrdbr); - - /* Digital Volume Function Parameter */ - rsnd_dvc_volume_parameter(io, mod); - - /* cancel operation */ - rsnd_mod_write(mod, DVC_DVUIR, 0); -} - -static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - u32 zcmcr = 0; - u32 vrpdr = 0; - u32 vrdbr = 0; - int i; - - for (i = 0; i < rsnd_kctrl_size(dvc->mute); i++) - zcmcr |= (!!rsnd_kctrl_valm(dvc->mute, i)) << i; - - if (rsnd_kctrl_vals(dvc->ren)) { - vrpdr = rsnd_dvc_get_vrpdr(dvc); - vrdbr = rsnd_dvc_get_vrdbr(dvc); - } - - /* Disable DVC Register access */ - rsnd_mod_write(mod, DVC_DVUER, 0); - - /* Zero Cross Mute Function */ - rsnd_mod_write(mod, DVC_ZCMCR, zcmcr); - - /* Volume Ramp Function */ - rsnd_mod_write(mod, DVC_VRPDR, vrpdr); - rsnd_mod_write(mod, DVC_VRDBR, vrdbr); - /* add DVC_VRWTR here */ - - /* Digital Volume Function Parameter */ - rsnd_dvc_volume_parameter(io, mod); - - /* Enable DVC Register access */ - rsnd_mod_write(mod, DVC_DVUER, 1); -} - -static int rsnd_dvc_probe_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return rsnd_cmd_attach(io, rsnd_mod_id(mod)); -} - -static int rsnd_dvc_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_dvc_activation(mod); - - rsnd_dvc_volume_init(io, mod); - - rsnd_dvc_volume_update(io, mod); - - return 0; -} - -static int rsnd_dvc_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_dvc_halt(mod); - - rsnd_mod_power_off(mod); - - return 0; -} - -static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int is_play = rsnd_io_is_play(io); - int channels = rsnd_rdai_channels_get(rdai); - int ret; - - /* Volume */ - ret = rsnd_kctrl_new_m(mod, io, rtd, - is_play ? - "DVC Out Playback Volume" : "DVC In Capture Volume", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->volume, channels, - 0x00800000 - 1); - if (ret < 0) - return ret; - - /* Mute */ - ret = rsnd_kctrl_new_m(mod, io, rtd, - is_play ? - "DVC Out Mute Switch" : "DVC In Mute Switch", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->mute, channels, - 1); - if (ret < 0) - return ret; - - /* Ramp */ - ret = rsnd_kctrl_new_s(mod, io, rtd, - is_play ? - "DVC Out Ramp Switch" : "DVC In Ramp Switch", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->ren, 1); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_e(mod, io, rtd, - is_play ? - "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->rup, - volume_ramp_rate, - VOLUME_RAMP_MAX_DVC); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_e(mod, io, rtd, - is_play ? - "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", - rsnd_kctrl_accept_anytime, - rsnd_dvc_volume_update, - &dvc->rdown, - volume_ramp_rate, - VOLUME_RAMP_MAX_DVC); - - if (ret < 0) - return ret; - - return 0; -} - -static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - - return rsnd_dma_request_channel(rsnd_dvc_of_node(priv), - DVC_NAME, mod, "tx"); -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_dvc_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, - 0xe00 + rsnd_mod_id(mod) * 0x100, 0x60); -} -#define DEBUG_INFO .debug_info = rsnd_dvc_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_dvc_ops = { - .name = DVC_NAME, - .dma_req = rsnd_dvc_dma_req, - .probe = rsnd_dvc_probe_, - .init = rsnd_dvc_init, - .quit = rsnd_dvc_quit, - .pcm_new = rsnd_dvc_pcm_new, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_dvc_get(priv, id)); -} - -int rsnd_dvc_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dvc *dvc; - struct clk *clk; - char name[RSND_DVC_NAME_SIZE]; - int i, nr, ret; - - node = rsnd_dvc_of_node(priv); - if (!node) - return 0; /* not used is not error */ - - nr = of_get_child_count(node); - if (!nr) { - ret = -EINVAL; - goto rsnd_dvc_probe_done; - } - - dvc = devm_kcalloc(dev, nr, sizeof(*dvc), GFP_KERNEL); - if (!dvc) { - ret = -ENOMEM; - goto rsnd_dvc_probe_done; - } - - priv->dvc_nr = nr; - priv->dvc = dvc; - - i = 0; - ret = 0; - for_each_child_of_node(node, np) { - dvc = rsnd_dvc_get(priv, i); - - snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", - DVC_NAME, i); - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_dvc_probe_done; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, - clk, RSND_MOD_DVC, i); - if (ret) { - of_node_put(np); - goto rsnd_dvc_probe_done; - } - - i++; - } - -rsnd_dvc_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_dvc_remove(struct rsnd_priv *priv) -{ - struct rsnd_dvc *dvc; - int i; - - for_each_rsnd_dvc(dvc, priv, i) { - rsnd_mod_quit(rsnd_mod_get(dvc)); - } -} diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c deleted file mode 100644 index d1f20cde66be1f..00000000000000 --- a/sound/soc/sh/rcar/gen.c +++ /dev/null @@ -1,495 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car Gen1 SRU/SSI support -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto - -/* - * #define DEBUG - * - * you can also add below in - * ${LINUX}/drivers/base/regmap/regmap.c - * for regmap debug - * - * #define LOG_DEVICE "xxxx.rcar_sound" - */ - -#include "rsnd.h" - -struct rsnd_gen { - struct rsnd_gen_ops *ops; - - /* RSND_BASE_MAX base */ - void __iomem *base[RSND_BASE_MAX]; - phys_addr_t res[RSND_BASE_MAX]; - struct regmap *regmap[RSND_BASE_MAX]; - - /* RSND_REG_MAX base */ - struct regmap_field *regs[REG_MAX]; - const char *reg_name[REG_MAX]; -}; - -#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) -#define rsnd_reg_name(gen, id) ((gen)->reg_name[id]) - -struct rsnd_regmap_field_conf { - int idx; - unsigned int reg_offset; - unsigned int id_offset; - const char *reg_name; -}; - -#define RSND_REG_SET(id, offset, _id_offset, n) \ -{ \ - .idx = id, \ - .reg_offset = offset, \ - .id_offset = _id_offset, \ - .reg_name = n, \ -} -/* single address mapping */ -#define RSND_GEN_S_REG(id, offset) \ - RSND_REG_SET(id, offset, 0, #id) - -/* multi address mapping */ -#define RSND_GEN_M_REG(id, offset, _id_offset) \ - RSND_REG_SET(id, offset, _id_offset, #id) - -/* - * basic function - */ -static int rsnd_is_accessible_reg(struct rsnd_priv *priv, - struct rsnd_gen *gen, enum rsnd_reg reg) -{ - if (!gen->regs[reg]) { - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "unsupported register access %x\n", reg); - return 0; - } - - return 1; -} - -static int rsnd_mod_id_cmd(struct rsnd_mod *mod) -{ - if (mod->ops->id_cmd) - return mod->ops->id_cmd(mod); - - return rsnd_mod_id(mod); -} - -u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - u32 val; - - if (!rsnd_is_accessible_reg(priv, gen, reg)) - return 0; - - regmap_fields_read(gen->regs[reg], rsnd_mod_id_cmd(mod), &val); - - dev_dbg(dev, "r %s - %-18s (%4d) : %08x\n", - rsnd_mod_name(mod), - rsnd_reg_name(gen, reg), reg, val); - - return val; -} - -void rsnd_mod_write(struct rsnd_mod *mod, - enum rsnd_reg reg, u32 data) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - if (!rsnd_is_accessible_reg(priv, gen, reg)) - return; - - regmap_fields_force_write(gen->regs[reg], rsnd_mod_id_cmd(mod), data); - - dev_dbg(dev, "w %s - %-18s (%4d) : %08x\n", - rsnd_mod_name(mod), - rsnd_reg_name(gen, reg), reg, data); -} - -void rsnd_mod_bset(struct rsnd_mod *mod, - enum rsnd_reg reg, u32 mask, u32 data) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - if (!rsnd_is_accessible_reg(priv, gen, reg)) - return; - - regmap_fields_force_update_bits(gen->regs[reg], - rsnd_mod_id_cmd(mod), mask, data); - - dev_dbg(dev, "b %s - %-18s (%4d) : %08x/%08x\n", - rsnd_mod_name(mod), - rsnd_reg_name(gen, reg), reg, data, mask); - -} - -phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) -{ - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - return gen->res[reg_id]; -} - -#ifdef CONFIG_DEBUG_FS -void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id) -{ - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - - return gen->base[reg_id]; -} -#endif - -#define rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf) \ - _rsnd_gen_regmap_init(priv, id_size, reg_id, name, conf, ARRAY_SIZE(conf)) -static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, - int id_size, - int reg_id, - const char *name, - const struct rsnd_regmap_field_conf *conf, - int conf_size) -{ - struct platform_device *pdev = rsnd_priv_to_pdev(priv); - struct rsnd_gen *gen = rsnd_priv_to_gen(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct resource *res; - struct regmap_config regc; - struct regmap_field *regs; - struct regmap *regmap; - struct reg_field regf; - void __iomem *base; - int i; - - memset(®c, 0, sizeof(regc)); - regc.reg_bits = 32; - regc.val_bits = 32; - regc.reg_stride = 4; - regc.name = name; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); - if (!res) - return -ENODEV; - - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, ®c); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - /* RSND_BASE_MAX base */ - gen->base[reg_id] = base; - gen->regmap[reg_id] = regmap; - gen->res[reg_id] = res->start; - - for (i = 0; i < conf_size; i++) { - - regf.reg = conf[i].reg_offset; - regf.id_offset = conf[i].id_offset; - regf.lsb = 0; - regf.msb = 31; - regf.id_size = id_size; - - regs = devm_regmap_field_alloc(dev, regmap, regf); - if (IS_ERR(regs)) - return PTR_ERR(regs); - - /* RSND_REG_MAX base */ - gen->regs[conf[i].idx] = regs; - gen->reg_name[conf[i].idx] = conf[i].reg_name; - } - - return 0; -} - -/* - * (A) : Gen4 is 0xa0c, but it is not used. - * see - * rsnd_ssiu_init() - */ -static const struct rsnd_regmap_field_conf conf_common_ssiu[] = { - RSND_GEN_S_REG(SSI_MODE0, 0x800), - RSND_GEN_S_REG(SSI_MODE1, 0x804), - RSND_GEN_S_REG(SSI_MODE2, 0x808), // (A) - RSND_GEN_S_REG(SSI_CONTROL, 0x810), - RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840), - RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844), - RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848), - RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c), - RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880), - RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884), - RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), - RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE0, 0x850), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE1, 0x854), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE2, 0x858), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE3, 0x85c), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE4, 0x890), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE5, 0x894), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE6, 0x898), - RSND_GEN_S_REG(SSI_SYS_INT_ENABLE7, 0x89c), - RSND_GEN_S_REG(HDMI0_SEL, 0x9e0), - RSND_GEN_S_REG(HDMI1_SEL, 0x9e4), - RSND_GEN_M_REG(SSI_BUSIF0_MODE, 0x0, 0x80), - RSND_GEN_M_REG(SSI_BUSIF0_ADINR, 0x4, 0x80), - RSND_GEN_M_REG(SSI_BUSIF0_DALIGN, 0x8, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_MODE, 0x20, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_ADINR, 0x24, 0x80), - RSND_GEN_M_REG(SSI_BUSIF1_DALIGN, 0x28, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_MODE, 0x40, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_ADINR, 0x44, 0x80), - RSND_GEN_M_REG(SSI_BUSIF2_DALIGN, 0x48, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_MODE, 0x60, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_ADINR, 0x64, 0x80), - RSND_GEN_M_REG(SSI_BUSIF3_DALIGN, 0x68, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_MODE, 0x500, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_ADINR, 0x504, 0x80), - RSND_GEN_M_REG(SSI_BUSIF4_DALIGN, 0x508, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_MODE, 0x520, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_ADINR, 0x524, 0x80), - RSND_GEN_M_REG(SSI_BUSIF5_DALIGN, 0x528, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_MODE, 0x540, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_ADINR, 0x544, 0x80), - RSND_GEN_M_REG(SSI_BUSIF6_DALIGN, 0x548, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_MODE, 0x560, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_ADINR, 0x564, 0x80), - RSND_GEN_M_REG(SSI_BUSIF7_DALIGN, 0x568, 0x80), - RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), - RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), - RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), - RSND_GEN_S_REG(SSI9_BUSIF0_MODE, 0x48c), - RSND_GEN_S_REG(SSI9_BUSIF0_ADINR, 0x484), - RSND_GEN_S_REG(SSI9_BUSIF0_DALIGN, 0x488), - RSND_GEN_S_REG(SSI9_BUSIF1_MODE, 0x4a0), - RSND_GEN_S_REG(SSI9_BUSIF1_ADINR, 0x4a4), - RSND_GEN_S_REG(SSI9_BUSIF1_DALIGN, 0x4a8), - RSND_GEN_S_REG(SSI9_BUSIF2_MODE, 0x4c0), - RSND_GEN_S_REG(SSI9_BUSIF2_ADINR, 0x4c4), - RSND_GEN_S_REG(SSI9_BUSIF2_DALIGN, 0x4c8), - RSND_GEN_S_REG(SSI9_BUSIF3_MODE, 0x4e0), - RSND_GEN_S_REG(SSI9_BUSIF3_ADINR, 0x4e4), - RSND_GEN_S_REG(SSI9_BUSIF3_DALIGN, 0x4e8), - RSND_GEN_S_REG(SSI9_BUSIF4_MODE, 0xd80), - RSND_GEN_S_REG(SSI9_BUSIF4_ADINR, 0xd84), - RSND_GEN_S_REG(SSI9_BUSIF4_DALIGN, 0xd88), - RSND_GEN_S_REG(SSI9_BUSIF5_MODE, 0xda0), - RSND_GEN_S_REG(SSI9_BUSIF5_ADINR, 0xda4), - RSND_GEN_S_REG(SSI9_BUSIF5_DALIGN, 0xda8), - RSND_GEN_S_REG(SSI9_BUSIF6_MODE, 0xdc0), - RSND_GEN_S_REG(SSI9_BUSIF6_ADINR, 0xdc4), - RSND_GEN_S_REG(SSI9_BUSIF6_DALIGN, 0xdc8), - RSND_GEN_S_REG(SSI9_BUSIF7_MODE, 0xde0), - RSND_GEN_S_REG(SSI9_BUSIF7_ADINR, 0xde4), - RSND_GEN_S_REG(SSI9_BUSIF7_DALIGN, 0xde8), -}; - -static const struct rsnd_regmap_field_conf conf_common_scu[] = { - RSND_GEN_M_REG(SRC_I_BUSIF_MODE, 0x0, 0x20), - RSND_GEN_M_REG(SRC_O_BUSIF_MODE, 0x4, 0x20), - RSND_GEN_M_REG(SRC_BUSIF_DALIGN, 0x8, 0x20), - RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), - RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), - RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), - RSND_GEN_M_REG(CMD_BUSIF_MODE, 0x184, 0x20), - RSND_GEN_M_REG(CMD_BUSIF_DALIGN, 0x188, 0x20), - RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), - RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), - RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), - RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc), - RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0), - RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4), - RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), - RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), - RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), - RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40), - RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), - RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), - RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40), - RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), - RSND_GEN_M_REG(CTU_SWRSR, 0x500, 0x100), - RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), - RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), - RSND_GEN_M_REG(CTU_CPMDR, 0x510, 0x100), - RSND_GEN_M_REG(CTU_SCMDR, 0x514, 0x100), - RSND_GEN_M_REG(CTU_SV00R, 0x518, 0x100), - RSND_GEN_M_REG(CTU_SV01R, 0x51c, 0x100), - RSND_GEN_M_REG(CTU_SV02R, 0x520, 0x100), - RSND_GEN_M_REG(CTU_SV03R, 0x524, 0x100), - RSND_GEN_M_REG(CTU_SV04R, 0x528, 0x100), - RSND_GEN_M_REG(CTU_SV05R, 0x52c, 0x100), - RSND_GEN_M_REG(CTU_SV06R, 0x530, 0x100), - RSND_GEN_M_REG(CTU_SV07R, 0x534, 0x100), - RSND_GEN_M_REG(CTU_SV10R, 0x538, 0x100), - RSND_GEN_M_REG(CTU_SV11R, 0x53c, 0x100), - RSND_GEN_M_REG(CTU_SV12R, 0x540, 0x100), - RSND_GEN_M_REG(CTU_SV13R, 0x544, 0x100), - RSND_GEN_M_REG(CTU_SV14R, 0x548, 0x100), - RSND_GEN_M_REG(CTU_SV15R, 0x54c, 0x100), - RSND_GEN_M_REG(CTU_SV16R, 0x550, 0x100), - RSND_GEN_M_REG(CTU_SV17R, 0x554, 0x100), - RSND_GEN_M_REG(CTU_SV20R, 0x558, 0x100), - RSND_GEN_M_REG(CTU_SV21R, 0x55c, 0x100), - RSND_GEN_M_REG(CTU_SV22R, 0x560, 0x100), - RSND_GEN_M_REG(CTU_SV23R, 0x564, 0x100), - RSND_GEN_M_REG(CTU_SV24R, 0x568, 0x100), - RSND_GEN_M_REG(CTU_SV25R, 0x56c, 0x100), - RSND_GEN_M_REG(CTU_SV26R, 0x570, 0x100), - RSND_GEN_M_REG(CTU_SV27R, 0x574, 0x100), - RSND_GEN_M_REG(CTU_SV30R, 0x578, 0x100), - RSND_GEN_M_REG(CTU_SV31R, 0x57c, 0x100), - RSND_GEN_M_REG(CTU_SV32R, 0x580, 0x100), - RSND_GEN_M_REG(CTU_SV33R, 0x584, 0x100), - RSND_GEN_M_REG(CTU_SV34R, 0x588, 0x100), - RSND_GEN_M_REG(CTU_SV35R, 0x58c, 0x100), - RSND_GEN_M_REG(CTU_SV36R, 0x590, 0x100), - RSND_GEN_M_REG(CTU_SV37R, 0x594, 0x100), - RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40), - RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40), - RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40), - RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40), - RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40), - RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40), - RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40), - RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40), - RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40), - RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40), - RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100), - RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100), - RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), - RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), - RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), - RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100), - RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100), - RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), - RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), - RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), - RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100), - RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100), - RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100), - RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100), - RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100), - RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100), - RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), -}; - -static const struct rsnd_regmap_field_conf conf_common_adg[] = { - RSND_GEN_S_REG(BRRA, 0x00), - RSND_GEN_S_REG(BRRB, 0x04), - RSND_GEN_S_REG(BRGCKR, 0x08), - RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), - RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), - RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14), - RSND_GEN_S_REG(DIV_EN, 0x30), - RSND_GEN_S_REG(SRCIN_TIMSEL0, 0x34), - RSND_GEN_S_REG(SRCIN_TIMSEL1, 0x38), - RSND_GEN_S_REG(SRCIN_TIMSEL2, 0x3c), - RSND_GEN_S_REG(SRCIN_TIMSEL3, 0x40), - RSND_GEN_S_REG(SRCIN_TIMSEL4, 0x44), - RSND_GEN_S_REG(SRCOUT_TIMSEL0, 0x48), - RSND_GEN_S_REG(SRCOUT_TIMSEL1, 0x4c), - RSND_GEN_S_REG(SRCOUT_TIMSEL2, 0x50), - RSND_GEN_S_REG(SRCOUT_TIMSEL3, 0x54), - RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), - RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), -}; - -static const struct rsnd_regmap_field_conf conf_common_ssi[] = { - RSND_GEN_M_REG(SSICR, 0x00, 0x40), - RSND_GEN_M_REG(SSISR, 0x04, 0x40), - RSND_GEN_M_REG(SSITDR, 0x08, 0x40), - RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), - RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), -}; - -/* - * Gen4 - */ -static int rsnd_gen4_probe(struct rsnd_priv *priv) -{ - struct rsnd_regmap_field_conf conf_null[] = { }; - - /* - * ssiu: SSIU0 - * ssi : SSI0 - */ - int ret_ssiu = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSIU, "ssiu", conf_common_ssiu); - int ret_ssi = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SSI, "ssi", conf_common_ssi); - int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg); - int ret_sdmc = rsnd_gen_regmap_init(priv, 1, RSND_BASE_SDMC, "sdmc", conf_null); - - return ret_adg | ret_ssiu | ret_ssi | ret_sdmc; -} - -/* - * Gen2 - */ -static int rsnd_gen2_probe(struct rsnd_priv *priv) -{ - /* - * ssi : SSI0 - SSI9 - * ssiu: SSIU0 - SSIU9 - * scu : SRC0 - SRC9 etc - */ - int ret_ssi = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSI, "ssi", conf_common_ssi); - int ret_ssiu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SSIU, "ssiu", conf_common_ssiu); - int ret_scu = rsnd_gen_regmap_init(priv, 10, RSND_BASE_SCU, "scu", conf_common_scu); - int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg); - - return ret_ssi | ret_ssiu | ret_scu | ret_adg; -} - -/* - * Gen1 - */ - -static int rsnd_gen1_probe(struct rsnd_priv *priv) -{ - /* - * ssi : SSI0 - SSI8 - */ - int ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_BASE_SSI, "ssi", conf_common_ssi); - int ret_adg = rsnd_gen_regmap_init(priv, 1, RSND_BASE_ADG, "adg", conf_common_adg); - - return ret_adg | ret_ssi; -} - -/* - * Gen - */ -int rsnd_gen_probe(struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_gen *gen; - int ret; - - gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); - if (!gen) - return -ENOMEM; - - priv->gen = gen; - - ret = -ENODEV; - if (rsnd_is_gen1(priv)) - ret = rsnd_gen1_probe(priv); - else if (rsnd_is_gen2(priv) || - rsnd_is_gen3(priv)) - ret = rsnd_gen2_probe(priv); - else if (rsnd_is_gen4(priv)) - ret = rsnd_gen4_probe(priv); - - if (ret < 0) - dev_err(dev, "unknown generation R-Car sound device\n"); - - return ret; -} diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c deleted file mode 100644 index 024d91cc874840..00000000000000 --- a/sound/soc/sh/rcar/mix.c +++ /dev/null @@ -1,356 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// mix.c -// -// Copyright (c) 2015 Kuninori Morimoto - -/* - * CTUn MIXn - * +------+ +------+ - * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| -> - * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| -> - * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| -> - * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| -> - * +------+ +------+ - * - * ex) - * DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>; - * DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; - * - * MIX Volume - * amixer set "MIX",0 100% // DAI0 Volume - * amixer set "MIX",1 100% // DAI1 Volume - * - * Volume Ramp - * amixer set "MIX Ramp Up Rate" "0.125 dB/1 step" - * amixer set "MIX Ramp Down Rate" "4 dB/1 step" - * amixer set "MIX Ramp" on - * aplay xxx.wav & - * amixer set "MIX",0 80% // DAI0 Volume Down - * amixer set "MIX",1 100% // DAI1 Volume Up - */ - -#include "rsnd.h" - -#define MIX_NAME_SIZE 16 -#define MIX_NAME "mix" - -struct rsnd_mix { - struct rsnd_mod mod; - struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */ - struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */ - struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */ - struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */ - struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ - struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ - struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */ - u32 flags; -}; - -#define ONCE_KCTRL_INITIALIZED (1 << 0) -#define HAS_VOLA (1 << 1) -#define HAS_VOLB (1 << 2) -#define HAS_VOLC (1 << 3) -#define HAS_VOLD (1 << 4) - -#define VOL_MAX 0x3ff - -#define rsnd_mod_to_mix(_mod) \ - container_of((_mod), struct rsnd_mix, mod) - -#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) -#define rsnd_mix_nr(priv) ((priv)->mix_nr) -#define for_each_rsnd_mix(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_mix_nr(priv)) && \ - ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ - i++) - -static void rsnd_mix_activation(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, MIX_SWRSR, 0); - rsnd_mod_write(mod, MIX_SWRSR, 1); -} - -static void rsnd_mix_halt(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, MIX_MIXIR, 1); - rsnd_mod_write(mod, MIX_SWRSR, 0); -} - -#define rsnd_mix_get_vol(mix, X) \ - rsnd_flags_has(mix, HAS_VOL##X) ? \ - (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0 -static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mix *mix = rsnd_mod_to_mix(mod); - u32 volA = rsnd_mix_get_vol(mix, A); - u32 volB = rsnd_mix_get_vol(mix, B); - u32 volC = rsnd_mix_get_vol(mix, C); - u32 volD = rsnd_mix_get_vol(mix, D); - - dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n", - volA, volB, volC, volD); - - rsnd_mod_write(mod, MIX_MDBAR, volA); - rsnd_mod_write(mod, MIX_MDBBR, volB); - rsnd_mod_write(mod, MIX_MDBCR, volC); - rsnd_mod_write(mod, MIX_MDBDR, volD); -} - -static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_mix *mix = rsnd_mod_to_mix(mod); - - rsnd_mod_write(mod, MIX_MIXIR, 1); - - /* General Information */ - rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io)); - - /* volume step */ - rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren)); - rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 | - rsnd_kctrl_vals(mix->rdw)); - - /* common volume parameter */ - rsnd_mix_volume_parameter(io, mod); - - rsnd_mod_write(mod, MIX_MIXIR, 0); -} - -static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - /* Disable MIX dB setting */ - rsnd_mod_write(mod, MIX_MDBER, 0); - - /* common volume parameter */ - rsnd_mix_volume_parameter(io, mod); - - /* Enable MIX dB setting */ - rsnd_mod_write(mod, MIX_MDBER, 1); -} - -static int rsnd_mix_probe_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return rsnd_cmd_attach(io, rsnd_mod_id(mod)); -} - -static int rsnd_mix_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_mix_activation(mod); - - rsnd_mix_volume_init(io, mod); - - rsnd_mix_volume_update(io, mod); - - return 0; -} - -static int rsnd_mix_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mix_halt(mod); - - rsnd_mod_power_off(mod); - - return 0; -} - -static int rsnd_mix_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mix *mix = rsnd_mod_to_mix(mod); - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - struct rsnd_kctrl_cfg_s *volume; - int ret; - - switch (rsnd_mod_id(src_mod)) { - case 3: - case 6: /* MDBAR */ - volume = &mix->volumeA; - rsnd_flags_set(mix, HAS_VOLA); - break; - case 4: - case 9: /* MDBBR */ - volume = &mix->volumeB; - rsnd_flags_set(mix, HAS_VOLB); - break; - case 0: - case 1: /* MDBCR */ - volume = &mix->volumeC; - rsnd_flags_set(mix, HAS_VOLC); - break; - case 2: - case 5: /* MDBDR */ - volume = &mix->volumeD; - rsnd_flags_set(mix, HAS_VOLD); - break; - default: - dev_err(dev, "unknown SRC is connected\n"); - return -EINVAL; - } - - /* Volume */ - ret = rsnd_kctrl_new_s(mod, io, rtd, - "MIX Playback Volume", - rsnd_kctrl_accept_anytime, - rsnd_mix_volume_update, - volume, VOL_MAX); - if (ret < 0) - return ret; - rsnd_kctrl_vals(*volume) = VOL_MAX; - - if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED)) - return ret; - - /* Ramp */ - ret = rsnd_kctrl_new_s(mod, io, rtd, - "MIX Ramp Switch", - rsnd_kctrl_accept_anytime, - rsnd_mix_volume_update, - &mix->ren, 1); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_e(mod, io, rtd, - "MIX Ramp Up Rate", - rsnd_kctrl_accept_anytime, - rsnd_mix_volume_update, - &mix->rup, - volume_ramp_rate, - VOLUME_RAMP_MAX_MIX); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_e(mod, io, rtd, - "MIX Ramp Down Rate", - rsnd_kctrl_accept_anytime, - rsnd_mix_volume_update, - &mix->rdw, - volume_ramp_rate, - VOLUME_RAMP_MAX_MIX); - - rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED); - - return ret; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_mix_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, - 0xd00 + rsnd_mod_id(mod) * 0x40, 0x30); -} -#define DEBUG_INFO .debug_info = rsnd_mix_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_mix_ops = { - .name = MIX_NAME, - .probe = rsnd_mix_probe_, - .init = rsnd_mix_init, - .quit = rsnd_mix_quit, - .pcm_new = rsnd_mix_pcm_new, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_mix_get(priv, id)); -} - -int rsnd_mix_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mix *mix; - struct clk *clk; - char name[MIX_NAME_SIZE]; - int i, nr, ret; - - node = rsnd_mix_of_node(priv); - if (!node) - return 0; /* not used is not error */ - - nr = of_get_child_count(node); - if (!nr) { - ret = -EINVAL; - goto rsnd_mix_probe_done; - } - - mix = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL); - if (!mix) { - ret = -ENOMEM; - goto rsnd_mix_probe_done; - } - - priv->mix_nr = nr; - priv->mix = mix; - - i = 0; - ret = 0; - for_each_child_of_node(node, np) { - mix = rsnd_mix_get(priv, i); - - snprintf(name, MIX_NAME_SIZE, "%s.%d", - MIX_NAME, i); - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_mix_probe_done; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, - clk, RSND_MOD_MIX, i); - if (ret) { - of_node_put(np); - goto rsnd_mix_probe_done; - } - - i++; - } - -rsnd_mix_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_mix_remove(struct rsnd_priv *priv) -{ - struct rsnd_mix *mix; - int i; - - for_each_rsnd_mix(mix, priv, i) { - rsnd_mod_quit(rsnd_mod_get(mix)); - } -} diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h deleted file mode 100644 index 3c164d8e3b16bf..00000000000000 --- a/sound/soc/sh/rcar/rsnd.h +++ /dev/null @@ -1,896 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto - -#ifndef RSND_H -#define RSND_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RSND_BASE_ADG 0 -#define RSND_BASE_SSI 1 -#define RSND_BASE_SSIU 2 -#define RSND_BASE_SCU 3 // for Gen2/Gen3 -#define RSND_BASE_SDMC 3 // for Gen4 reuse -#define RSND_BASE_MAX 4 - -/* - * pseudo register - * - * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different. - * This driver uses pseudo register in order to hide it. - * see gen1/gen2 for detail - */ -enum rsnd_reg { - /* SCU (MIX/CTU/DVC) */ - SRC_I_BUSIF_MODE, - SRC_O_BUSIF_MODE, - SRC_ROUTE_MODE0, - SRC_SWRSR, - SRC_SRCIR, - SRC_ADINR, - SRC_IFSCR, - SRC_IFSVR, - SRC_SRCCR, - SRC_CTRL, - SRC_BSDSR, - SRC_BSISR, - SRC_INT_ENABLE0, - SRC_BUSIF_DALIGN, - SRCIN_TIMSEL0, - SRCIN_TIMSEL1, - SRCIN_TIMSEL2, - SRCIN_TIMSEL3, - SRCIN_TIMSEL4, - SRCOUT_TIMSEL0, - SRCOUT_TIMSEL1, - SRCOUT_TIMSEL2, - SRCOUT_TIMSEL3, - SRCOUT_TIMSEL4, - SCU_SYS_STATUS0, - SCU_SYS_STATUS1, - SCU_SYS_INT_EN0, - SCU_SYS_INT_EN1, - CMD_CTRL, - CMD_BUSIF_MODE, - CMD_BUSIF_DALIGN, - CMD_ROUTE_SLCT, - CMDOUT_TIMSEL, - CTU_SWRSR, - CTU_CTUIR, - CTU_ADINR, - CTU_CPMDR, - CTU_SCMDR, - CTU_SV00R, - CTU_SV01R, - CTU_SV02R, - CTU_SV03R, - CTU_SV04R, - CTU_SV05R, - CTU_SV06R, - CTU_SV07R, - CTU_SV10R, - CTU_SV11R, - CTU_SV12R, - CTU_SV13R, - CTU_SV14R, - CTU_SV15R, - CTU_SV16R, - CTU_SV17R, - CTU_SV20R, - CTU_SV21R, - CTU_SV22R, - CTU_SV23R, - CTU_SV24R, - CTU_SV25R, - CTU_SV26R, - CTU_SV27R, - CTU_SV30R, - CTU_SV31R, - CTU_SV32R, - CTU_SV33R, - CTU_SV34R, - CTU_SV35R, - CTU_SV36R, - CTU_SV37R, - MIX_SWRSR, - MIX_MIXIR, - MIX_ADINR, - MIX_MIXMR, - MIX_MVPDR, - MIX_MDBAR, - MIX_MDBBR, - MIX_MDBCR, - MIX_MDBDR, - MIX_MDBER, - DVC_SWRSR, - DVC_DVUIR, - DVC_ADINR, - DVC_DVUCR, - DVC_ZCMCR, - DVC_VOL0R, - DVC_VOL1R, - DVC_VOL2R, - DVC_VOL3R, - DVC_VOL4R, - DVC_VOL5R, - DVC_VOL6R, - DVC_VOL7R, - DVC_DVUER, - DVC_VRCTR, - DVC_VRPDR, - DVC_VRDBR, - - /* ADG */ - BRRA, - BRRB, - BRGCKR, - DIV_EN, - AUDIO_CLK_SEL0, - AUDIO_CLK_SEL1, - AUDIO_CLK_SEL2, - - /* SSIU */ - SSI_MODE, - SSI_MODE0, - SSI_MODE1, - SSI_MODE2, - SSI_CONTROL, - SSI_CTRL, - SSI_BUSIF0_MODE, - SSI_BUSIF1_MODE, - SSI_BUSIF2_MODE, - SSI_BUSIF3_MODE, - SSI_BUSIF4_MODE, - SSI_BUSIF5_MODE, - SSI_BUSIF6_MODE, - SSI_BUSIF7_MODE, - SSI_BUSIF0_ADINR, - SSI_BUSIF1_ADINR, - SSI_BUSIF2_ADINR, - SSI_BUSIF3_ADINR, - SSI_BUSIF4_ADINR, - SSI_BUSIF5_ADINR, - SSI_BUSIF6_ADINR, - SSI_BUSIF7_ADINR, - SSI_BUSIF0_DALIGN, - SSI_BUSIF1_DALIGN, - SSI_BUSIF2_DALIGN, - SSI_BUSIF3_DALIGN, - SSI_BUSIF4_DALIGN, - SSI_BUSIF5_DALIGN, - SSI_BUSIF6_DALIGN, - SSI_BUSIF7_DALIGN, - SSI_INT_ENABLE, - SSI_SYS_STATUS0, - SSI_SYS_STATUS1, - SSI_SYS_STATUS2, - SSI_SYS_STATUS3, - SSI_SYS_STATUS4, - SSI_SYS_STATUS5, - SSI_SYS_STATUS6, - SSI_SYS_STATUS7, - SSI_SYS_INT_ENABLE0, - SSI_SYS_INT_ENABLE1, - SSI_SYS_INT_ENABLE2, - SSI_SYS_INT_ENABLE3, - SSI_SYS_INT_ENABLE4, - SSI_SYS_INT_ENABLE5, - SSI_SYS_INT_ENABLE6, - SSI_SYS_INT_ENABLE7, - HDMI0_SEL, - HDMI1_SEL, - SSI9_BUSIF0_MODE, - SSI9_BUSIF1_MODE, - SSI9_BUSIF2_MODE, - SSI9_BUSIF3_MODE, - SSI9_BUSIF4_MODE, - SSI9_BUSIF5_MODE, - SSI9_BUSIF6_MODE, - SSI9_BUSIF7_MODE, - SSI9_BUSIF0_ADINR, - SSI9_BUSIF1_ADINR, - SSI9_BUSIF2_ADINR, - SSI9_BUSIF3_ADINR, - SSI9_BUSIF4_ADINR, - SSI9_BUSIF5_ADINR, - SSI9_BUSIF6_ADINR, - SSI9_BUSIF7_ADINR, - SSI9_BUSIF0_DALIGN, - SSI9_BUSIF1_DALIGN, - SSI9_BUSIF2_DALIGN, - SSI9_BUSIF3_DALIGN, - SSI9_BUSIF4_DALIGN, - SSI9_BUSIF5_DALIGN, - SSI9_BUSIF6_DALIGN, - SSI9_BUSIF7_DALIGN, - - /* SSI */ - SSICR, - SSISR, - SSITDR, - SSIRDR, - SSIWSR, - - REG_MAX, -}; -#define SRCIN_TIMSEL(i) (SRCIN_TIMSEL0 + (i)) -#define SRCOUT_TIMSEL(i) (SRCOUT_TIMSEL0 + (i)) -#define CTU_SVxxR(i, j) (CTU_SV00R + (i * 8) + (j)) -#define DVC_VOLxR(i) (DVC_VOL0R + (i)) -#define AUDIO_CLK_SEL(i) (AUDIO_CLK_SEL0 + (i)) -#define SSI_BUSIF_MODE(i) (SSI_BUSIF0_MODE + (i)) -#define SSI_BUSIF_ADINR(i) (SSI_BUSIF0_ADINR + (i)) -#define SSI_BUSIF_DALIGN(i) (SSI_BUSIF0_DALIGN + (i)) -#define SSI9_BUSIF_MODE(i) (SSI9_BUSIF0_MODE + (i)) -#define SSI9_BUSIF_ADINR(i) (SSI9_BUSIF0_ADINR + (i)) -#define SSI9_BUSIF_DALIGN(i) (SSI9_BUSIF0_DALIGN + (i)) -#define SSI_SYS_STATUS(i) (SSI_SYS_STATUS0 + (i)) -#define SSI_SYS_INT_ENABLE(i) (SSI_SYS_INT_ENABLE0 + (i)) - - -struct rsnd_priv; -struct rsnd_mod; -struct rsnd_dai; -struct rsnd_dai_stream; - -/* - * R-Car basic functions - */ -u32 rsnd_mod_read(struct rsnd_mod *mod, enum rsnd_reg reg); -void rsnd_mod_write(struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); -void rsnd_mod_bset(struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); -u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod); - -/* - * R-Car DMA - */ -int rsnd_dma_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, struct rsnd_mod **dma_mod); -int rsnd_dma_probe(struct rsnd_priv *priv); -struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name, - struct rsnd_mod *mod, char *x); - -/* - * R-Car sound mod - */ -enum rsnd_mod_type { - RSND_MOD_AUDMAPP, - RSND_MOD_AUDMA, - RSND_MOD_DVC, - RSND_MOD_MIX, - RSND_MOD_CTU, - RSND_MOD_CMD, - RSND_MOD_SRC, - RSND_MOD_SSIM3, /* SSI multi 3 */ - RSND_MOD_SSIM2, /* SSI multi 2 */ - RSND_MOD_SSIM1, /* SSI multi 1 */ - RSND_MOD_SSIP, /* SSI parent */ - RSND_MOD_SSI, - RSND_MOD_SSIU, - RSND_MOD_MAX, -}; - -struct rsnd_mod_ops { - char *name; - struct dma_chan* (*dma_req)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod); - int (*probe)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*remove)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*init)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*quit)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*start)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*stop)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*irq)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv, int enable); - int (*pcm_new)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd); - int (*hw_params)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params); - int (*pointer)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - snd_pcm_uframes_t *pointer); - int (*fallback)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*prepare)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*cleanup)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv); - int (*hw_free)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream); - u32 *(*get_status)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type); - int (*id)(struct rsnd_mod *mod); - int (*id_sub)(struct rsnd_mod *mod); - int (*id_cmd)(struct rsnd_mod *mod); - -#ifdef CONFIG_DEBUG_FS - void (*debug_info)(struct seq_file *m, - struct rsnd_dai_stream *io, struct rsnd_mod *mod); -#endif -}; - -struct rsnd_dai_stream; -struct rsnd_mod { - int id; - enum rsnd_mod_type type; - struct rsnd_mod_ops *ops; - struct rsnd_priv *priv; - struct clk *clk; - u32 status; -}; -/* - * status - * - * 0xH000DCB0 - * - * B 0: init 1: quit - * C 0: start 1: stop - * D 0: hw_params 1: hw_free - * - * H is always called (see __rsnd_mod_call) - */ -#define __rsnd_mod_shift_init 4 -#define __rsnd_mod_shift_quit 4 -#define __rsnd_mod_shift_start 8 -#define __rsnd_mod_shift_stop 8 -#define __rsnd_mod_shift_hw_params 12 -#define __rsnd_mod_shift_hw_free 12 -#define __rsnd_mod_shift_probe 28 /* always called */ -#define __rsnd_mod_shift_remove 28 /* always called */ -#define __rsnd_mod_shift_irq 28 /* always called */ -#define __rsnd_mod_shift_pcm_new 28 /* always called */ -#define __rsnd_mod_shift_fallback 28 /* always called */ -#define __rsnd_mod_shift_pointer 28 /* always called */ -#define __rsnd_mod_shift_prepare 28 /* always called */ -#define __rsnd_mod_shift_cleanup 28 /* always called */ - -#define __rsnd_mod_add_probe 0 -#define __rsnd_mod_add_remove 0 -#define __rsnd_mod_add_prepare 0 -#define __rsnd_mod_add_cleanup 0 -#define __rsnd_mod_add_init 1 /* needs protect */ -#define __rsnd_mod_add_quit -1 /* needs protect */ -#define __rsnd_mod_add_start 1 /* needs protect */ -#define __rsnd_mod_add_stop -1 /* needs protect */ -#define __rsnd_mod_add_hw_params 1 /* needs protect */ -#define __rsnd_mod_add_hw_free -1 /* needs protect */ -#define __rsnd_mod_add_irq 0 -#define __rsnd_mod_add_pcm_new 0 -#define __rsnd_mod_add_fallback 0 -#define __rsnd_mod_add_pointer 0 - -#define __rsnd_mod_call_probe 0 -#define __rsnd_mod_call_remove 0 -#define __rsnd_mod_call_prepare 0 -#define __rsnd_mod_call_cleanup 0 -#define __rsnd_mod_call_init 0 /* needs protect */ -#define __rsnd_mod_call_quit 1 /* needs protect */ -#define __rsnd_mod_call_start 0 /* needs protect */ -#define __rsnd_mod_call_stop 1 /* needs protect */ -#define __rsnd_mod_call_hw_params 0 /* needs protect */ -#define __rsnd_mod_call_hw_free 1 /* needs protect */ -#define __rsnd_mod_call_irq 0 -#define __rsnd_mod_call_pcm_new 0 -#define __rsnd_mod_call_fallback 0 -#define __rsnd_mod_call_pointer 0 - -#define rsnd_mod_to_priv(mod) ((mod)->priv) -#define rsnd_mod_power_on(mod) clk_enable((mod)->clk) -#define rsnd_mod_power_off(mod) clk_disable((mod)->clk) -#define rsnd_mod_get(ip) (&(ip)->mod) - -int rsnd_mod_init(struct rsnd_priv *priv, - struct rsnd_mod *mod, - struct rsnd_mod_ops *ops, - struct clk *clk, - enum rsnd_mod_type type, - int id); -void rsnd_mod_quit(struct rsnd_mod *mod); -struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod); -void rsnd_mod_interrupt(struct rsnd_mod *mod, - void (*callback)(struct rsnd_mod *mod, - struct rsnd_dai_stream *io)); -u32 *rsnd_mod_get_status(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type); -int rsnd_mod_id(struct rsnd_mod *mod); -int rsnd_mod_id_raw(struct rsnd_mod *mod); -int rsnd_mod_id_sub(struct rsnd_mod *mod); -char *rsnd_mod_name(struct rsnd_mod *mod); -struct rsnd_mod *rsnd_mod_next(int *iterator, - struct rsnd_dai_stream *io, - enum rsnd_mod_type *array, - int array_size); -#define for_each_rsnd_mod(iterator, pos, io) \ - for (iterator = 0; \ - (pos = rsnd_mod_next(&iterator, io, NULL, 0)); iterator++) -#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size) \ - for (iterator = 0; \ - (pos = rsnd_mod_next(&iterator, io, array, size)); iterator++) -#define for_each_rsnd_mod_array(iterator, pos, io, array) \ - for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array)) - -void rsnd_parse_connect_common(struct rsnd_dai *rdai, char *name, - struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), - struct device_node *node, - struct device_node *playback, - struct device_node *capture); -int rsnd_node_count(struct rsnd_priv *priv, struct device_node *node, char *name); -int rsnd_node_fixed_index(struct device *dev, struct device_node *node, char *name, int idx); - -int rsnd_channel_normalization(int chan); -#define rsnd_runtime_channel_original(io) \ - rsnd_runtime_channel_original_with_params(io, NULL) -int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params); -#define rsnd_runtime_channel_after_ctu(io) \ - rsnd_runtime_channel_after_ctu_with_params(io, NULL) -int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params); -#define rsnd_runtime_channel_for_ssi(io) \ - rsnd_runtime_channel_for_ssi_with_params(io, NULL) -int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, - struct snd_pcm_hw_params *params); -int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io); -int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io); -int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io); - -/* - * DT - */ -#define rsnd_parse_of_node(priv, node) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) -#define RSND_NODE_DAI "rcar_sound,dai" -#define RSND_NODE_SSI "rcar_sound,ssi" -#define RSND_NODE_SSIU "rcar_sound,ssiu" -#define RSND_NODE_SRC "rcar_sound,src" -#define RSND_NODE_CTU "rcar_sound,ctu" -#define RSND_NODE_MIX "rcar_sound,mix" -#define RSND_NODE_DVC "rcar_sound,dvc" - -/* - * R-Car sound DAI - */ -#define RSND_DAI_NAME_SIZE 16 -struct rsnd_dai_stream { - char name[RSND_DAI_NAME_SIZE]; - struct snd_pcm_substream *substream; - struct rsnd_mod *mod[RSND_MOD_MAX]; - struct rsnd_mod *dma; - struct rsnd_dai *rdai; - struct device *dmac_dev; /* for IPMMU */ - u32 converted_rate; /* converted sampling rate */ - int converted_chan; /* converted channels */ - u32 parent_ssi_status; - u32 flags; -}; - -/* flags */ -#define RSND_STREAM_HDMI0 (1 << 0) /* for HDMI0 */ -#define RSND_STREAM_HDMI1 (1 << 1) /* for HDMI1 */ -#define RSND_STREAM_TDM_SPLIT (1 << 2) /* for TDM split mode */ -#define RSND_HW_RULE_ERR (1 << 3) /* hw_rule error */ - -#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) -#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) -#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU) -#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) -#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) -#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) -#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) -#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) -#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD) -#define rsnd_io_to_rdai(io) ((io)->rdai) -#define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) -#define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) -#define rsnd_io_to_runtime(io) ((io)->substream ? \ - (io)->substream->runtime : NULL) -#define rsnd_io_converted_rate(io) ((io)->converted_rate) -#define rsnd_io_converted_chan(io) ((io)->converted_chan) -int rsnd_io_is_working(struct rsnd_dai_stream *io); - -struct rsnd_dai { - char name[RSND_DAI_NAME_SIZE]; - struct rsnd_dai_stream playback; - struct rsnd_dai_stream capture; - struct rsnd_priv *priv; - struct snd_pcm_hw_constraint_list constraint; - struct of_phandle_args dai_args; - - int max_channels; /* 2ch - 16ch */ - int ssi_lane; /* 1lane - 4lane */ - int chan_width; /* 16/24/32 bit width */ - - unsigned int clk_master:1; - unsigned int bit_clk_inv:1; - unsigned int frm_clk_inv:1; - unsigned int sys_delay:1; - unsigned int data_alignment:1; -}; - -#define rsnd_rdai_nr(priv) ((priv)->rdai_nr) -#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) -#define rsnd_rdai_to_priv(rdai) ((rdai)->priv) -#define for_each_rsnd_dai(rdai, priv, i) \ - for (i = 0; \ - (i < rsnd_rdai_nr(priv)) && \ - ((rdai) = rsnd_rdai_get(priv, i)); \ - i++) - -struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); - -#define rsnd_rdai_channels_set(rdai, max_channels) \ - rsnd_rdai_channels_ctrl(rdai, max_channels) -#define rsnd_rdai_channels_get(rdai) \ - rsnd_rdai_channels_ctrl(rdai, 0) -int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, - int max_channels); - -#define rsnd_rdai_ssi_lane_set(rdai, ssi_lane) \ - rsnd_rdai_ssi_lane_ctrl(rdai, ssi_lane) -#define rsnd_rdai_ssi_lane_get(rdai) \ - rsnd_rdai_ssi_lane_ctrl(rdai, 0) -int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, - int ssi_lane); - -#define rsnd_rdai_width_set(rdai, width) \ - rsnd_rdai_width_ctrl(rdai, width) -#define rsnd_rdai_width_get(rdai) \ - rsnd_rdai_width_ctrl(rdai, 0) -int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width); -int rsnd_dai_connect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type); - -/* - * R-Car Gen1/Gen2 - */ -int rsnd_gen_probe(struct rsnd_priv *priv); -void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, - struct rsnd_mod *mod, - enum rsnd_reg reg); -phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); -#ifdef CONFIG_DEBUG_FS -void __iomem *rsnd_gen_get_base_addr(struct rsnd_priv *priv, int reg_id); -#endif - -/* - * R-Car ADG - */ -int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate); -int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod); -int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate); -int rsnd_adg_probe(struct rsnd_priv *priv); -void rsnd_adg_remove(struct rsnd_priv *priv); -int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, - struct rsnd_dai_stream *io, - unsigned int in_rate, - unsigned int out_rate); -int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, - struct rsnd_dai_stream *io); -#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) -#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) -void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable); -void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m); - -/* - * R-Car sound priv - */ -struct rsnd_priv { - - struct platform_device *pdev; - spinlock_t lock; - unsigned long flags; -#define RSND_GEN_MASK (0xF << 0) -#define RSND_GEN1 (1 << 0) -#define RSND_GEN2 (2 << 0) -#define RSND_GEN3 (3 << 0) -#define RSND_GEN4 (4 << 0) -#define RSND_SOC_MASK (0xFF << 4) -#define RSND_SOC_E (1 << 4) /* E1/E2/E3 */ - - /* - * below value will be filled on rsnd_gen_probe() - */ - void *gen; - - /* - * below value will be filled on rsnd_adg_probe() - */ - void *adg; - - /* - * below value will be filled on rsnd_dma_probe() - */ - void *dma; - - /* - * below value will be filled on rsnd_ssi_probe() - */ - void *ssi; - int ssi_nr; - - /* - * below value will be filled on rsnd_ssiu_probe() - */ - void *ssiu; - int ssiu_nr; - - /* - * below value will be filled on rsnd_src_probe() - */ - void *src; - int src_nr; - - /* - * below value will be filled on rsnd_ctu_probe() - */ - void *ctu; - int ctu_nr; - - /* - * below value will be filled on rsnd_mix_probe() - */ - void *mix; - int mix_nr; - - /* - * below value will be filled on rsnd_dvc_probe() - */ - void *dvc; - int dvc_nr; - - /* - * below value will be filled on rsnd_cmd_probe() - */ - void *cmd; - int cmd_nr; - - /* - * below value will be filled on rsnd_dai_probe() - */ - struct snd_soc_dai_driver *daidrv; - struct rsnd_dai *rdai; - int rdai_nr; - -#define RSND_MAX_COMPONENT 3 - int component_dais[RSND_MAX_COMPONENT]; -}; - -#define rsnd_priv_to_pdev(priv) ((priv)->pdev) -#define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) - -#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) -#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) -#define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3) -#define rsnd_is_gen4(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN4) -#define rsnd_is_gen3_e3(priv) (((priv)->flags & \ - (RSND_GEN_MASK | RSND_SOC_MASK)) == \ - (RSND_GEN3 | RSND_SOC_E)) - -#define rsnd_flags_has(p, f) ((p)->flags & (f)) -#define rsnd_flags_set(p, f) ((p)->flags |= (f)) -#define rsnd_flags_del(p, f) ((p)->flags &= ~(f)) - -/* - * rsnd_kctrl - */ -struct rsnd_kctrl_cfg { - unsigned int max; - unsigned int size; - u32 *val; - const char * const *texts; - int (*accept)(struct rsnd_dai_stream *io); - void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod); - struct rsnd_dai_stream *io; - struct snd_card *card; - struct snd_kcontrol *kctrl; - struct rsnd_mod *mod; -}; - -#define RSND_MAX_CHANNELS 8 -struct rsnd_kctrl_cfg_m { - struct rsnd_kctrl_cfg cfg; - u32 val[RSND_MAX_CHANNELS]; -}; - -struct rsnd_kctrl_cfg_s { - struct rsnd_kctrl_cfg cfg; - u32 val; -}; -#define rsnd_kctrl_size(x) ((x).cfg.size) -#define rsnd_kctrl_max(x) ((x).cfg.max) -#define rsnd_kctrl_valm(x, i) ((x).val[i]) /* = (x).cfg.val[i] */ -#define rsnd_kctrl_vals(x) ((x).val) /* = (x).cfg.val[0] */ - -int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io); -int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io); -struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg); -struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg); -int rsnd_kctrl_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd, - const unsigned char *name, - int (*accept)(struct rsnd_dai_stream *io), - void (*update)(struct rsnd_dai_stream *io, - struct rsnd_mod *mod), - struct rsnd_kctrl_cfg *cfg, - const char * const *texts, - int size, - u32 max); - -#define rsnd_kctrl_new_m(mod, io, rtd, name, accept, update, cfg, size, max) \ - rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_m(cfg), \ - NULL, size, max) - -#define rsnd_kctrl_new_s(mod, io, rtd, name, accept, update, cfg, max) \ - rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ - NULL, 1, max) - -#define rsnd_kctrl_new_e(mod, io, rtd, name, accept, update, cfg, texts, size) \ - rsnd_kctrl_new(mod, io, rtd, name, accept, update, rsnd_kctrl_init_s(cfg), \ - texts, 1, size) - -extern const char * const volume_ramp_rate[]; -#define VOLUME_RAMP_MAX_DVC (0x17 + 1) -#define VOLUME_RAMP_MAX_MIX (0x0a + 1) - -/* - * R-Car SSI - */ -int rsnd_ssi_probe(struct rsnd_priv *priv); -void rsnd_ssi_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); -int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); -u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io); -int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); - -#define rsnd_ssi_is_pin_sharing(io) \ - __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) -int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); - -#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI) -void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, - struct device_node *playback, - struct device_node *capture); -unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, - int param1, int param2, int *idx); - -/* - * R-Car SSIU - */ -int rsnd_ssiu_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod); -int rsnd_ssiu_probe(struct rsnd_priv *priv); -void rsnd_ssiu_remove(struct rsnd_priv *priv); -void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, - struct device_node *playback, - struct device_node *capture); -#define rsnd_ssiu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSIU) -bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod); - -/* - * R-Car SRC - */ -int rsnd_src_probe(struct rsnd_priv *priv); -void rsnd_src_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); - -#define rsnd_src_get_in_rate(priv, io) rsnd_src_get_rate(priv, io, 1) -#define rsnd_src_get_out_rate(priv, io) rsnd_src_get_rate(priv, io, 0) -unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - int is_in); - -#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC) -#define rsnd_parse_connect_src(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, "src", rsnd_src_mod_get, \ - rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) - -/* - * R-Car CTU - */ -int rsnd_ctu_probe(struct rsnd_priv *priv); -void rsnd_ctu_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) -#define rsnd_parse_connect_ctu(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, "ctu", rsnd_ctu_mod_get, \ - rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) - -/* - * R-Car MIX - */ -int rsnd_mix_probe(struct rsnd_priv *priv); -void rsnd_mix_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX) -#define rsnd_parse_connect_mix(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, "mix", rsnd_mix_mod_get, \ - rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) - -/* - * R-Car DVC - */ -int rsnd_dvc_probe(struct rsnd_priv *priv); -void rsnd_dvc_remove(struct rsnd_priv *priv); -struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC) -#define rsnd_parse_connect_dvc(rdai, playback, capture) \ - rsnd_parse_connect_common(rdai, "dvc", rsnd_dvc_mod_get, \ - rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ - playback, capture) - -/* - * R-Car CMD - */ -int rsnd_cmd_probe(struct rsnd_priv *priv); -void rsnd_cmd_remove(struct rsnd_priv *priv); -int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id); - -void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); - -/* - * If you don't need interrupt status debug message, - * define RSND_DEBUG_NO_IRQ_STATUS as 1 on top of src.c/ssi.c - * - * #define RSND_DEBUG_NO_IRQ_STATUS 1 - */ -#define rsnd_print_irq_status(dev, param...) do { \ - if (!IS_BUILTIN(RSND_DEBUG_NO_IRQ_STATUS)) \ - dev_info(dev, param); \ -} while (0) - -#ifdef CONFIG_DEBUG_FS -int rsnd_debugfs_probe(struct snd_soc_component *component); -void rsnd_debugfs_reg_show(struct seq_file *m, phys_addr_t _addr, - void __iomem *base, int offset, int size); -void rsnd_debugfs_mod_reg_show(struct seq_file *m, struct rsnd_mod *mod, - int reg_id, int offset, int size); - -#else -#define rsnd_debugfs_probe NULL -#endif - -#endif /* RSND_H */ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c deleted file mode 100644 index e7f86db0d94c3c..00000000000000 --- a/sound/soc/sh/rcar/src.c +++ /dev/null @@ -1,732 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car SRC support -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto - -/* - * You can use Synchronous Sampling Rate Convert (if no DVC) - * - * amixer set "SRC Out Rate" on - * aplay xxx.wav & - * amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz - * amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz - */ - -/* - * you can enable below define if you don't need - * SSI interrupt status debug message when debugging - * see rsnd_print_irq_status() - * - * #define RSND_DEBUG_NO_IRQ_STATUS 1 - */ - -#include -#include "rsnd.h" - -#define SRC_NAME "src" - -/* SCU_SYSTEM_STATUS0/1 */ -#define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) - -struct rsnd_src { - struct rsnd_mod mod; - struct rsnd_mod *dma; - struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ - struct rsnd_kctrl_cfg_s sync; /* sync convert */ - int irq; -}; - -#define RSND_SRC_NAME_SIZE 16 - -#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) -#define rsnd_src_nr(priv) ((priv)->src_nr) -#define rsnd_src_sync_is_enabled(mod) (rsnd_mod_to_src(mod)->sen.val) - -#define rsnd_mod_to_src(_mod) \ - container_of((_mod), struct rsnd_src, mod) - -#define for_each_rsnd_src(pos, priv, i) \ - for ((i) = 0; \ - ((i) < rsnd_src_nr(priv)) && \ - ((pos) = (struct rsnd_src *)(priv)->src + i); \ - i++) - - -/* - * image of SRC (Sampling Rate Converter) - * - * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ - * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | - * 44.1kHz <-> +-----+ +-----+ +-------+ - * ... - * - */ - -static void rsnd_src_activation(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, SRC_SWRSR, 0); - rsnd_mod_write(mod, SRC_SWRSR, 1); -} - -static void rsnd_src_halt(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, SRC_SRCIR, 1); - rsnd_mod_write(mod, SRC_SWRSR, 0); -} - -static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - int is_play = rsnd_io_is_play(io); - - return rsnd_dma_request_channel(rsnd_src_of_node(priv), - SRC_NAME, mod, - is_play ? "rx" : "tx"); -} - -static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate; - - if (!runtime) - return 0; - - if (!rsnd_src_sync_is_enabled(mod)) - return rsnd_io_converted_rate(io); - - convert_rate = src->sync.val; - - if (!convert_rate) - convert_rate = rsnd_io_converted_rate(io); - - if (!convert_rate) - convert_rate = runtime->rate; - - return convert_rate; -} - -unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, - struct rsnd_dai_stream *io, - int is_in) -{ - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - unsigned int rate = 0; - int is_play = rsnd_io_is_play(io); - - /* - * Playback - * runtime_rate -> [SRC] -> convert_rate - * - * Capture - * convert_rate -> [SRC] -> runtime_rate - */ - - if (is_play == is_in) - return runtime->rate; - - /* - * return convert rate if SRC is used, - * otherwise, return runtime->rate as usual - */ - if (src_mod) - rate = rsnd_src_convert_rate(io, src_mod); - - if (!rate) - rate = runtime->rate; - - return rate; -} - -static const u32 bsdsr_table_pattern1[] = { - 0x01800000, /* 6 - 1/6 */ - 0x01000000, /* 6 - 1/4 */ - 0x00c00000, /* 6 - 1/3 */ - 0x00800000, /* 6 - 1/2 */ - 0x00600000, /* 6 - 2/3 */ - 0x00400000, /* 6 - 1 */ -}; - -static const u32 bsdsr_table_pattern2[] = { - 0x02400000, /* 6 - 1/6 */ - 0x01800000, /* 6 - 1/4 */ - 0x01200000, /* 6 - 1/3 */ - 0x00c00000, /* 6 - 1/2 */ - 0x00900000, /* 6 - 2/3 */ - 0x00600000, /* 6 - 1 */ -}; - -static const u32 bsisr_table[] = { - 0x00100060, /* 6 - 1/6 */ - 0x00100040, /* 6 - 1/4 */ - 0x00100030, /* 6 - 1/3 */ - 0x00100020, /* 6 - 1/2 */ - 0x00100020, /* 6 - 2/3 */ - 0x00100020, /* 6 - 1 */ -}; - -static const u32 chan288888[] = { - 0x00000006, /* 1 to 2 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ -}; - -static const u32 chan244888[] = { - 0x00000006, /* 1 to 2 */ - 0x0000001e, /* 1 to 4 */ - 0x0000001e, /* 1 to 4 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ - 0x000001fe, /* 1 to 8 */ -}; - -static const u32 chan222222[] = { - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ - 0x00000006, /* 1 to 2 */ -}; - -static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int is_play = rsnd_io_is_play(io); - int use_src = 0; - u32 fin, fout; - u32 ifscr, fsrate, adinr; - u32 cr, route; - u32 i_busif, o_busif, tmp; - const u32 *bsdsr_table; - const u32 *chptn; - uint ratio; - int chan; - int idx; - - if (!runtime) - return; - - fin = rsnd_src_get_in_rate(priv, io); - fout = rsnd_src_get_out_rate(priv, io); - - chan = rsnd_runtime_channel_original(io); - - /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ - if (fin == fout) - ratio = 0; - else if (fin > fout) - ratio = 100 * fin / fout; - else - ratio = 100 * fout / fin; - - if (ratio > 600) { - dev_err(dev, "FSO/FSI ratio error\n"); - return; - } - - use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod); - - /* - * SRC_ADINR - */ - adinr = rsnd_get_adinr_bit(mod, io) | chan; - - /* - * SRC_IFSCR / SRC_IFSVR - */ - ifscr = 0; - fsrate = 0; - if (use_src) { - u64 n; - - ifscr = 1; - n = (u64)0x0400000 * fin; - do_div(n, fout); - fsrate = n; - } - - /* - * SRC_SRCCR / SRC_ROUTE_MODE0 - */ - cr = 0x00011110; - route = 0x0; - if (use_src) { - route = 0x1; - - if (rsnd_src_sync_is_enabled(mod)) { - cr |= 0x1; - route |= rsnd_io_is_play(io) ? - (0x1 << 24) : (0x1 << 25); - } - } - - /* - * SRC_BSDSR / SRC_BSISR - * - * see - * Combination of Register Setting Related to - * FSO/FSI Ratio and Channel, Latency - */ - switch (rsnd_mod_id(mod)) { - case 0: - chptn = chan288888; - bsdsr_table = bsdsr_table_pattern1; - break; - case 1: - case 3: - case 4: - chptn = chan244888; - bsdsr_table = bsdsr_table_pattern1; - break; - case 2: - case 9: - chptn = chan222222; - bsdsr_table = bsdsr_table_pattern1; - break; - case 5: - case 6: - case 7: - case 8: - chptn = chan222222; - bsdsr_table = bsdsr_table_pattern2; - break; - default: - goto convert_rate_err; - } - - /* - * E3 need to overwrite - */ - if (rsnd_is_gen3_e3(priv)) - switch (rsnd_mod_id(mod)) { - case 0: - case 4: - chptn = chan222222; - } - - for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++) - if (chptn[idx] & (1 << chan)) - break; - - if (chan > 8 || - idx >= ARRAY_SIZE(chan222222)) - goto convert_rate_err; - - /* BUSIF_MODE */ - tmp = rsnd_get_busif_shift(io, mod); - i_busif = ( is_play ? tmp : 0) | 1; - o_busif = (!is_play ? tmp : 0) | 1; - - rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); - - rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ - rsnd_mod_write(mod, SRC_ADINR, adinr); - rsnd_mod_write(mod, SRC_IFSCR, ifscr); - rsnd_mod_write(mod, SRC_IFSVR, fsrate); - rsnd_mod_write(mod, SRC_SRCCR, cr); - rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]); - rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]); - rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ - - rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif); - rsnd_mod_write(mod, SRC_O_BUSIF_MODE, o_busif); - - rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); - - rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); - - return; - -convert_rate_err: - dev_err(dev, "unknown BSDSR/BSDIR settings\n"); -} - -static int rsnd_src_irq(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv, - int enable) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 sys_int_val, int_val, sys_int_mask; - int irq = src->irq; - int id = rsnd_mod_id(mod); - - sys_int_val = - sys_int_mask = OUF_SRC(id); - int_val = 0x3300; - - /* - * IRQ is not supported on non-DT - * see - * rsnd_src_probe_() - */ - if ((irq <= 0) || !enable) { - sys_int_val = 0; - int_val = 0; - } - - /* - * WORKAROUND - * - * ignore over flow error when rsnd_src_sync_is_enabled() - */ - if (rsnd_src_sync_is_enabled(mod)) - sys_int_val = sys_int_val & 0xffff; - - rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); - rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); - rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); - - return 0; -} - -static void rsnd_src_status_clear(struct rsnd_mod *mod) -{ - u32 val = OUF_SRC(rsnd_mod_id(mod)); - - rsnd_mod_write(mod, SCU_SYS_STATUS0, val); - rsnd_mod_write(mod, SCU_SYS_STATUS1, val); -} - -static bool rsnd_src_error_occurred(struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - u32 val0, val1; - u32 status0, status1; - bool ret = false; - - val0 = val1 = OUF_SRC(rsnd_mod_id(mod)); - - /* - * WORKAROUND - * - * ignore over flow error when rsnd_src_sync_is_enabled() - */ - if (rsnd_src_sync_is_enabled(mod)) - val0 = val0 & 0xffff; - - status0 = rsnd_mod_read(mod, SCU_SYS_STATUS0); - status1 = rsnd_mod_read(mod, SCU_SYS_STATUS1); - if ((status0 & val0) || (status1 & val1)) { - rsnd_print_irq_status(dev, "%s err status : 0x%08x, 0x%08x\n", - rsnd_mod_name(mod), status0, status1); - - ret = true; - } - - return ret; -} - -static int rsnd_src_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - u32 val; - - /* - * WORKAROUND - * - * Enable SRC output if you want to use sync convert together with DVC - */ - val = (rsnd_io_to_mod_dvc(io) && !rsnd_src_sync_is_enabled(mod)) ? - 0x01 : 0x11; - - rsnd_mod_write(mod, SRC_CTRL, val); - - return 0; -} - -static int rsnd_src_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mod_write(mod, SRC_CTRL, 0); - - return 0; -} - -static int rsnd_src_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - int ret; - - /* reset sync convert_rate */ - src->sync.val = 0; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_src_activation(mod); - - rsnd_src_set_convert_rate(io, mod); - - rsnd_src_status_clear(mod); - - return 0; -} - -static int rsnd_src_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - - rsnd_src_halt(mod); - - rsnd_mod_power_off(mod); - - /* reset sync convert_rate */ - src->sync.val = 0; - - return 0; -} - -static void __rsnd_src_interrupt(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - bool stop = false; - - spin_lock(&priv->lock); - - /* ignore all cases if not working */ - if (!rsnd_io_is_working(io)) - goto rsnd_src_interrupt_out; - - if (rsnd_src_error_occurred(mod)) - stop = true; - - rsnd_src_status_clear(mod); -rsnd_src_interrupt_out: - - spin_unlock(&priv->lock); - - if (stop) - snd_pcm_stop_xrun(io->substream); -} - -static irqreturn_t rsnd_src_interrupt(int irq, void *data) -{ - struct rsnd_mod *mod = data; - - rsnd_mod_interrupt(mod, __rsnd_src_interrupt); - - return IRQ_HANDLED; -} - -static int rsnd_src_probe_(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int irq = src->irq; - int ret; - - if (irq > 0) { - /* - * IRQ is not supported on non-DT - * see - * rsnd_src_irq() - */ - ret = devm_request_irq(dev, irq, - rsnd_src_interrupt, - IRQF_SHARED, - dev_name(dev), mod); - if (ret) - return ret; - } - - ret = rsnd_dma_attach(io, mod, &src->dma); - - return ret; -} - -static int rsnd_src_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - int ret; - - /* - * enable SRC sync convert if possible - */ - - /* - * It can't use SRC Synchronous convert - * when Capture if it uses CMD - */ - if (rsnd_io_to_mod_cmd(io) && !rsnd_io_is_play(io)) - return 0; - - /* - * enable sync convert - */ - ret = rsnd_kctrl_new_s(mod, io, rtd, - rsnd_io_is_play(io) ? - "SRC Out Rate Switch" : - "SRC In Rate Switch", - rsnd_kctrl_accept_anytime, - rsnd_src_set_convert_rate, - &src->sen, 1); - if (ret < 0) - return ret; - - ret = rsnd_kctrl_new_s(mod, io, rtd, - rsnd_io_is_play(io) ? - "SRC Out Rate" : - "SRC In Rate", - rsnd_kctrl_accept_runtime, - rsnd_src_set_convert_rate, - &src->sync, 192000); - - return ret; -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_src_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, - rsnd_mod_id(mod) * 0x20, 0x20); - seq_puts(m, "\n"); - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, - 0x1c0, 0x20); - seq_puts(m, "\n"); - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SCU, - 0x200 + rsnd_mod_id(mod) * 0x40, 0x40); -} -#define DEBUG_INFO .debug_info = rsnd_src_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_src_ops = { - .name = SRC_NAME, - .dma_req = rsnd_src_dma_req, - .probe = rsnd_src_probe_, - .init = rsnd_src_init, - .quit = rsnd_src_quit, - .start = rsnd_src_start, - .stop = rsnd_src_stop, - .irq = rsnd_src_irq, - .pcm_new = rsnd_src_pcm_new, - .get_status = rsnd_mod_get_status, - DEBUG_INFO -}; - -struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_src_get(priv, id)); -} - -int rsnd_src_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_src *src; - struct clk *clk; - char name[RSND_SRC_NAME_SIZE]; - int i, nr, ret; - - node = rsnd_src_of_node(priv); - if (!node) - return 0; /* not used is not error */ - - nr = rsnd_node_count(priv, node, SRC_NAME); - if (!nr) { - ret = -EINVAL; - goto rsnd_src_probe_done; - } - - src = devm_kcalloc(dev, nr, sizeof(*src), GFP_KERNEL); - if (!src) { - ret = -ENOMEM; - goto rsnd_src_probe_done; - } - - priv->src_nr = nr; - priv->src = src; - - i = 0; - for_each_child_of_node(node, np) { - if (!of_device_is_available(np)) - goto skip; - - i = rsnd_node_fixed_index(dev, np, SRC_NAME, i); - if (i < 0) { - ret = -EINVAL; - of_node_put(np); - goto rsnd_src_probe_done; - } - - src = rsnd_src_get(priv, i); - - snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", - SRC_NAME, i); - - src->irq = irq_of_parse_and_map(np, 0); - if (!src->irq) { - ret = -EINVAL; - of_node_put(np); - goto rsnd_src_probe_done; - } - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_src_probe_done; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(src), - &rsnd_src_ops, clk, RSND_MOD_SRC, i); - if (ret) { - of_node_put(np); - goto rsnd_src_probe_done; - } - -skip: - i++; - } - - ret = 0; - -rsnd_src_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_src_remove(struct rsnd_priv *priv) -{ - struct rsnd_src *src; - int i; - - for_each_rsnd_src(src, priv, i) { - rsnd_mod_quit(rsnd_mod_get(src)); - } -} diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c deleted file mode 100644 index b3d4e8ae07eff8..00000000000000 --- a/sound/soc/sh/rcar/ssi.c +++ /dev/null @@ -1,1260 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car SSIU/SSI support -// -// Copyright (C) 2013 Renesas Solutions Corp. -// Kuninori Morimoto -// -// Based on fsi.c -// Kuninori Morimoto - -/* - * you can enable below define if you don't need - * SSI interrupt status debug message when debugging - * see rsnd_print_irq_status() - * - * #define RSND_DEBUG_NO_IRQ_STATUS 1 - */ - -#include -#include -#include -#include -#include "rsnd.h" -#define RSND_SSI_NAME_SIZE 16 - -/* - * SSICR - */ -#define FORCE (1u << 31) /* Fixed */ -#define DMEN (1u << 28) /* DMA Enable */ -#define UIEN (1u << 27) /* Underflow Interrupt Enable */ -#define OIEN (1u << 26) /* Overflow Interrupt Enable */ -#define IIEN (1u << 25) /* Idle Mode Interrupt Enable */ -#define DIEN (1u << 24) /* Data Interrupt Enable */ -#define CHNL_4 (1u << 22) /* Channels */ -#define CHNL_6 (2u << 22) /* Channels */ -#define CHNL_8 (3u << 22) /* Channels */ -#define DWL_MASK (7u << 19) /* Data Word Length mask */ -#define DWL_8 (0u << 19) /* Data Word Length */ -#define DWL_16 (1u << 19) /* Data Word Length */ -#define DWL_18 (2u << 19) /* Data Word Length */ -#define DWL_20 (3u << 19) /* Data Word Length */ -#define DWL_22 (4u << 19) /* Data Word Length */ -#define DWL_24 (5u << 19) /* Data Word Length */ -#define DWL_32 (6u << 19) /* Data Word Length */ - -/* - * System word length - */ -#define SWL_16 (1 << 16) /* R/W System Word Length */ -#define SWL_24 (2 << 16) /* R/W System Word Length */ -#define SWL_32 (3 << 16) /* R/W System Word Length */ - -#define SCKD (1 << 15) /* Serial Bit Clock Direction */ -#define SWSD (1 << 14) /* Serial WS Direction */ -#define SCKP (1 << 13) /* Serial Bit Clock Polarity */ -#define SWSP (1 << 12) /* Serial WS Polarity */ -#define SDTA (1 << 10) /* Serial Data Alignment */ -#define PDTA (1 << 9) /* Parallel Data Alignment */ -#define DEL (1 << 8) /* Serial Data Delay */ -#define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ -#define TRMD (1 << 1) /* Transmit/Receive Mode Select */ -#define EN (1 << 0) /* SSI Module Enable */ - -/* - * SSISR - */ -#define UIRQ (1 << 27) /* Underflow Error Interrupt Status */ -#define OIRQ (1 << 26) /* Overflow Error Interrupt Status */ -#define IIRQ (1 << 25) /* Idle Mode Interrupt Status */ -#define DIRQ (1 << 24) /* Data Interrupt Status Flag */ - -/* - * SSIWSR - */ -#define CONT (1 << 8) /* WS Continue Function */ -#define WS_MODE (1 << 0) /* WS Mode */ - -#define SSI_NAME "ssi" - -struct rsnd_ssi { - struct rsnd_mod mod; - - u32 flags; - u32 cr_own; - u32 cr_clk; - u32 cr_mode; - u32 cr_en; - u32 wsr; - int chan; - int rate; - int irq; - unsigned int usrcnt; - - /* for PIO */ - int byte_pos; - int byte_per_period; - int next_period_byte; -}; - -/* flags */ -#define RSND_SSI_CLK_PIN_SHARE (1 << 0) -#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ -#define RSND_SSI_PROBED (1 << 2) - -#define for_each_rsnd_ssi(pos, priv, i) \ - for (i = 0; \ - (i < rsnd_ssi_nr(priv)) && \ - ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ - i++) - -#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id) -#define rsnd_ssi_nr(priv) ((priv)->ssi_nr) -#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) -#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) -#define rsnd_ssi_is_multi_secondary(mod, io) \ - (rsnd_ssi_multi_secondaries(io) & (1 << rsnd_mod_id(mod))) -#define rsnd_ssi_is_run_mods(mod, io) \ - (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) -#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod)) - -int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) -{ - struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int use_busif = 0; - - if (!rsnd_ssi_is_dma_mode(mod)) - return 0; - - if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF))) - use_busif = 1; - if (rsnd_io_to_mod_src(io)) - use_busif = 1; - - return use_busif; -} - -static void rsnd_ssi_status_clear(struct rsnd_mod *mod) -{ - rsnd_mod_write(mod, SSISR, 0); -} - -static u32 rsnd_ssi_status_get(struct rsnd_mod *mod) -{ - return rsnd_mod_read(mod, SSISR); -} - -static void rsnd_ssi_status_check(struct rsnd_mod *mod, - u32 bit) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - u32 status; - int i; - - for (i = 0; i < 1024; i++) { - status = rsnd_ssi_status_get(mod); - if (status & bit) - return; - - udelay(5); - } - - dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod)); -} - -static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io) -{ - static const enum rsnd_mod_type types[] = { - RSND_MOD_SSIM1, - RSND_MOD_SSIM2, - RSND_MOD_SSIM3, - }; - int i, mask; - - mask = 0; - for (i = 0; i < ARRAY_SIZE(types); i++) { - struct rsnd_mod *mod = rsnd_io_to_mod(io, types[i]); - - if (!mod) - continue; - - mask |= 1 << rsnd_mod_id(mod); - } - - return mask; -} - -static u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io) -{ - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); - u32 mods; - - mods = rsnd_ssi_multi_secondaries_runtime(io) | - 1 << rsnd_mod_id(ssi_mod); - - if (ssi_parent_mod) - mods |= 1 << rsnd_mod_id(ssi_parent_mod); - - return mods; -} - -u32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io) -{ - if (rsnd_runtime_is_multi_ssi(io)) - return rsnd_ssi_multi_secondaries(io); - - return 0; -} - -static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - int width = rsnd_rdai_width_get(rdai); - - switch (width) { - case 32: return SWL_32; - case 24: return SWL_24; - case 16: return SWL_16; - } - - dev_err(dev, "unsupported slot width value: %d\n", width); - return 0; -} - -unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, - int param1, int param2, int *idx) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - static const int ssi_clk_mul_table[] = { - 1, 2, 4, 8, 16, 6, 12, - }; - int j, ret; - unsigned int main_rate; - int width = rsnd_rdai_width_get(rdai); - - for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { - - /* - * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 - * with it is not allowed. (SSIWSR.WS_MODE with - * SSICR.CKDV = 000 is not allowed either). - * Skip it. See SSICR.CKDV - */ - if (j == 0) - continue; - - main_rate = width * param1 * param2 * ssi_clk_mul_table[j]; - - ret = rsnd_adg_clk_query(priv, main_rate); - if (ret < 0) - continue; - - if (idx) - *idx = j; - - return main_rate; - } - - return 0; -} - -static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int chan = rsnd_runtime_channel_for_ssi(io); - int idx, ret; - unsigned int main_rate; - unsigned int rate = rsnd_io_is_play(io) ? - rsnd_src_get_out_rate(priv, io) : - rsnd_src_get_in_rate(priv, io); - - if (!rsnd_rdai_is_clk_master(rdai)) - return 0; - - if (!rsnd_ssi_can_output_clk(mod)) - return 0; - - if (rsnd_ssi_is_multi_secondary(mod, io)) - return 0; - - if (rsnd_runtime_is_tdm_split(io)) - chan = rsnd_io_converted_chan(io); - - chan = rsnd_channel_normalization(chan); - - if (ssi->usrcnt > 0) { - if (ssi->rate != rate) { - dev_err(dev, "SSI parent/child should use same rate\n"); - return -EINVAL; - } - - if (ssi->chan != chan) { - dev_err(dev, "SSI parent/child should use same chan\n"); - return -EINVAL; - } - - return 0; - } - - ret = -EIO; - main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); - if (!main_rate) - goto rate_err; - - ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); - if (ret < 0) - goto rate_err; - - /* - * SSI clock will be output contiguously - * by below settings. - * This means, rsnd_ssi_master_clk_start() - * and rsnd_ssi_register_setup() are necessary - * for SSI parent - * - * SSICR : FORCE, SCKD, SWSD - * SSIWSR : CONT - */ - ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) | - SCKD | SWSD | CKDV(idx); - ssi->wsr = CONT; - ssi->rate = rate; - ssi->chan = chan; - - dev_dbg(dev, "%s outputs %d chan %u Hz\n", - rsnd_mod_name(mod), chan, rate); - - return 0; - -rate_err: - dev_err(dev, "unsupported clock rate\n"); - return ret; -} - -static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - if (!rsnd_rdai_is_clk_master(rdai)) - return; - - if (!rsnd_ssi_can_output_clk(mod)) - return; - - if (ssi->usrcnt > 1) - return; - - ssi->cr_clk = 0; - ssi->rate = 0; - ssi->chan = 0; - - rsnd_adg_ssi_clk_stop(mod); -} - -static void rsnd_ssi_config_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - u32 cr_own = ssi->cr_own; - u32 cr_mode = ssi->cr_mode; - u32 wsr = ssi->wsr; - int width; - int is_tdm, is_tdm_split; - - is_tdm = rsnd_runtime_is_tdm(io); - is_tdm_split = rsnd_runtime_is_tdm_split(io); - - if (is_tdm) - dev_dbg(dev, "TDM mode\n"); - if (is_tdm_split) - dev_dbg(dev, "TDM Split mode\n"); - - cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); - - if (rdai->bit_clk_inv) - cr_own |= SCKP; - if (rdai->frm_clk_inv && !is_tdm) - cr_own |= SWSP; - if (rdai->data_alignment) - cr_own |= SDTA; - if (rdai->sys_delay) - cr_own |= DEL; - - /* - * TDM Mode - * see - * rsnd_ssiu_init_gen2() - */ - if (is_tdm || is_tdm_split) { - wsr |= WS_MODE; - cr_own |= CHNL_8; - } - - /* - * We shouldn't exchange SWSP after running. - * This means, parent needs to care it. - */ - if (rsnd_ssi_is_parent(mod, io)) - goto init_end; - - if (rsnd_io_is_play(io)) - cr_own |= TRMD; - - cr_own &= ~DWL_MASK; - width = snd_pcm_format_width(runtime->format); - if (is_tdm_split) { - /* - * The SWL and DWL bits in SSICR should be fixed at 32-bit - * setting when TDM split mode. - * see datasheet - * Operation :: TDM Format Split Function (TDM Split Mode) - */ - width = 32; - } - - switch (width) { - case 8: - cr_own |= DWL_8; - break; - case 16: - cr_own |= DWL_16; - break; - case 24: - cr_own |= DWL_24; - break; - case 32: - cr_own |= DWL_32; - break; - } - - if (rsnd_ssi_is_dma_mode(mod)) { - cr_mode = UIEN | OIEN | /* over/under run */ - DMEN; /* DMA : enable DMA */ - } else { - cr_mode = DIEN; /* PIO : enable Data interrupt */ - } - -init_end: - ssi->cr_own = cr_own; - ssi->cr_mode = cr_mode; - ssi->wsr = wsr; -} - -static void rsnd_ssi_register_setup(struct rsnd_mod *mod) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - rsnd_mod_write(mod, SSIWSR, ssi->wsr); - rsnd_mod_write(mod, SSICR, ssi->cr_own | - ssi->cr_clk | - ssi->cr_mode | - ssi->cr_en); -} - -/* - * SSI mod common functions - */ -static int rsnd_ssi_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int ret; - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - ret = rsnd_ssi_master_clk_start(mod, io); - if (ret < 0) - return ret; - - ssi->usrcnt++; - - ret = rsnd_mod_power_on(mod); - if (ret < 0) - return ret; - - rsnd_ssi_config_init(mod, io); - - rsnd_ssi_register_setup(mod); - - /* clear error status */ - rsnd_ssi_status_clear(mod); - - return 0; -} - -static int rsnd_ssi_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - if (!ssi->usrcnt) { - dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod)); - return -EIO; - } - - rsnd_ssi_master_clk_stop(mod, io); - - rsnd_mod_power_off(mod); - - ssi->usrcnt--; - - if (!ssi->usrcnt) { - ssi->cr_own = 0; - ssi->cr_mode = 0; - ssi->wsr = 0; - } - - return 0; -} - -static int rsnd_ssi_hw_params(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - unsigned int fmt_width = snd_pcm_format_width(params_format(params)); - - if (fmt_width > rdai->chan_width) { - struct rsnd_priv *priv = rsnd_io_to_priv(io); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "invalid combination of slot-width and format-data-width\n"); - return -EINVAL; - } - - return 0; -} - -static int rsnd_ssi_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - /* - * EN will be set via SSIU :: SSI_CONTROL - * if Multi channel mode - */ - if (rsnd_ssi_multi_secondaries_runtime(io)) - return 0; - - /* - * EN is for data output. - * SSI parent EN is not needed. - */ - if (rsnd_ssi_is_parent(mod, io)) - return 0; - - ssi->cr_en = EN; - - rsnd_mod_write(mod, SSICR, ssi->cr_own | - ssi->cr_clk | - ssi->cr_mode | - ssi->cr_en); - - return 0; -} - -static int rsnd_ssi_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - u32 cr; - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - if (rsnd_ssi_is_parent(mod, io)) - return 0; - - cr = ssi->cr_own | - ssi->cr_clk; - - /* - * disable all IRQ, - * Playback: Wait all data was sent - * Capture: It might not receave data. Do nothing - */ - if (rsnd_io_is_play(io)) { - rsnd_mod_write(mod, SSICR, cr | ssi->cr_en); - rsnd_ssi_status_check(mod, DIRQ); - } - - /* In multi-SSI mode, stop is performed by setting ssi0129 in - * SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here. - */ - if (rsnd_ssi_multi_secondaries_runtime(io)) - return 0; - - /* - * disable SSI, - * and, wait idle state - */ - rsnd_mod_write(mod, SSICR, cr); /* disabled all */ - rsnd_ssi_status_check(mod, IIRQ); - - ssi->cr_en = 0; - - return 0; -} - -static int rsnd_ssi_irq(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv, - int enable) -{ - u32 val = 0; - int is_tdm, is_tdm_split; - int id = rsnd_mod_id(mod); - - is_tdm = rsnd_runtime_is_tdm(io); - is_tdm_split = rsnd_runtime_is_tdm_split(io); - - if (rsnd_is_gen1(priv)) - return 0; - - if (rsnd_ssi_is_parent(mod, io)) - return 0; - - if (!rsnd_ssi_is_run_mods(mod, io)) - return 0; - - if (enable) - val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000; - - if (is_tdm || is_tdm_split) { - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 9: - val |= 0x0000ff00; - break; - } - } - - rsnd_mod_write(mod, SSI_INT_ENABLE, val); - - return 0; -} - -static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, - struct rsnd_dai_stream *io); -static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int is_dma = rsnd_ssi_is_dma_mode(mod); - u32 status; - bool elapsed = false; - bool stop = false; - - spin_lock(&priv->lock); - - /* ignore all cases if not working */ - if (!rsnd_io_is_working(io)) - goto rsnd_ssi_interrupt_out; - - status = rsnd_ssi_status_get(mod); - - /* PIO only */ - if (!is_dma && (status & DIRQ)) - elapsed = rsnd_ssi_pio_interrupt(mod, io); - - /* DMA only */ - if (is_dma && (status & (UIRQ | OIRQ))) { - rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - - stop = true; - } - - stop |= rsnd_ssiu_busif_err_status_clear(mod); - - rsnd_ssi_status_clear(mod); -rsnd_ssi_interrupt_out: - spin_unlock(&priv->lock); - - if (elapsed) - snd_pcm_period_elapsed(io->substream); - - if (stop) - snd_pcm_stop_xrun(io->substream); - -} - -static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) -{ - struct rsnd_mod *mod = data; - - rsnd_mod_interrupt(mod, __rsnd_ssi_interrupt); - - return IRQ_HANDLED; -} - -static u32 *rsnd_ssi_get_status(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - /* - * SSIP (= SSI parent) needs to be special, otherwise, - * 2nd SSI might doesn't start. see also rsnd_mod_call() - * - * We can't include parent SSI status on SSI, because we don't know - * how many SSI requests parent SSI. Thus, it is localed on "io" now. - * ex) trouble case - * Playback: SSI0 - * Capture : SSI1 (needs SSI0) - * - * 1) start Capture -> SSI0/SSI1 are started. - * 2) start Playback -> SSI0 doesn't work, because it is already - * marked as "started" on 1) - * - * OTOH, using each mod's status is good for MUX case. - * It doesn't need to start in 2nd start - * ex) - * IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0 - * | - * IO-1: SRC1 -> CTU2 -+ - * - * 1) start IO-0 -> start SSI0 - * 2) start IO-1 -> SSI0 doesn't need to start, because it is - * already started on 1) - */ - if (type == RSND_MOD_SSIP) - return &io->parent_ssi_status; - - return rsnd_mod_get_status(mod, io, type); -} - -/* - * SSI PIO - */ -static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - - if (!__rsnd_ssi_is_pin_sharing(mod)) - return; - - if (!rsnd_rdai_is_clk_master(rdai)) - return; - - if (rsnd_ssi_is_multi_secondary(mod, io)) - return; - - switch (rsnd_mod_id(mod)) { - case 1: - case 2: - case 9: - rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP); - break; - case 4: - rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP); - break; - case 8: - rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP); - break; - } -} - -static int rsnd_ssi_pcm_new(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct snd_soc_pcm_runtime *rtd) -{ - /* - * rsnd_rdai_is_clk_master() will be enabled after set_fmt, - * and, pcm_new will be called after it. - * This function reuse pcm_new at this point. - */ - rsnd_ssi_parent_attach(mod, io); - - return 0; -} - -static int rsnd_ssi_common_probe(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int ret = 0; - - /* - * SSIP/SSIU/IRQ are not needed on - * SSI Multi secondaries - */ - if (rsnd_ssi_is_multi_secondary(mod, io)) - return 0; - - /* - * It can't judge ssi parent at this point - * see rsnd_ssi_pcm_new() - */ - - /* - * SSI might be called again as PIO fallback - * It is easy to manual handling for IRQ request/free - * - * OTOH, this function might be called many times if platform is - * using MIX. It needs xxx_attach() many times on xxx_probe(). - * Because of it, we can't control .probe/.remove calling count by - * mod->status. - * But it don't need to call request_irq() many times. - * Let's control it by RSND_SSI_PROBED flag. - */ - if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) { - ret = request_irq(ssi->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); - - rsnd_flags_set(ssi, RSND_SSI_PROBED); - } - - return ret; -} - -static int rsnd_ssi_common_remove(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io); - - /* Do nothing if non SSI (= SSI parent, multi SSI) mod */ - if (pure_ssi_mod != mod) - return 0; - - /* PIO will request IRQ again */ - if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) { - free_irq(ssi->irq, mod); - - rsnd_flags_del(ssi, RSND_SSI_PROBED); - } - - return 0; -} - -/* - * SSI PIO functions - */ -static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos); - int shift = 0; - int byte_pos; - bool elapsed = false; - - if (snd_pcm_format_width(runtime->format) == 24) - shift = 8; - - /* - * 8/16/32 data can be assesse to TDR/RDR register - * directly as 32bit data - * see rsnd_ssi_init() - */ - if (rsnd_io_is_play(io)) - rsnd_mod_write(mod, SSITDR, (*buf) << shift); - else - *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); - - byte_pos = ssi->byte_pos + sizeof(*buf); - - if (byte_pos >= ssi->next_period_byte) { - int period_pos = byte_pos / ssi->byte_per_period; - - if (period_pos >= runtime->periods) { - byte_pos = 0; - period_pos = 0; - } - - ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; - - elapsed = true; - } - - WRITE_ONCE(ssi->byte_pos, byte_pos); - - return elapsed; -} - -static int rsnd_ssi_pio_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - if (!rsnd_ssi_is_parent(mod, io)) { - ssi->byte_pos = 0; - ssi->byte_per_period = runtime->period_size * - runtime->channels * - samples_to_bytes(runtime, 1); - ssi->next_period_byte = ssi->byte_per_period; - } - - return rsnd_ssi_init(mod, io, priv); -} - -static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - snd_pcm_uframes_t *pointer) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - - *pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos)); - - return 0; -} - -static struct rsnd_mod_ops rsnd_ssi_pio_ops = { - .name = SSI_NAME, - .probe = rsnd_ssi_common_probe, - .remove = rsnd_ssi_common_remove, - .init = rsnd_ssi_pio_init, - .quit = rsnd_ssi_quit, - .start = rsnd_ssi_start, - .stop = rsnd_ssi_stop, - .irq = rsnd_ssi_irq, - .pointer = rsnd_ssi_pio_pointer, - .pcm_new = rsnd_ssi_pcm_new, - .hw_params = rsnd_ssi_hw_params, - .get_status = rsnd_ssi_get_status, -}; - -static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - /* - * SSIP/SSIU/IRQ/DMA are not needed on - * SSI Multi secondaries - */ - if (rsnd_ssi_is_multi_secondary(mod, io)) - return 0; - - ret = rsnd_ssi_common_probe(mod, io, priv); - if (ret) - return ret; - - /* SSI probe might be called many times in MUX multi path */ - ret = rsnd_dma_attach(io, mod, &io->dma); - - return ret; -} - -static int rsnd_ssi_fallback(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - - /* - * fallback to PIO - * - * SSI .probe might be called again. - * see - * rsnd_rdai_continuance_probe() - */ - mod->ops = &rsnd_ssi_pio_ops; - - dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod)); - - return 0; -} - -static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - int is_play = rsnd_io_is_play(io); - char *name; - - /* - * It should use "rcar_sound,ssiu" on DT. - * But, we need to keep compatibility for old version. - * - * If it has "rcar_sound.ssiu", it will be used. - * If not, "rcar_sound.ssi" will be used. - * see - * rsnd_ssiu_dma_req() - * rsnd_dma_of_path() - */ - - if (rsnd_ssi_use_busif(io)) - name = is_play ? "rxu" : "txu"; - else - name = is_play ? "rx" : "tx"; - - return rsnd_dma_request_channel(rsnd_ssi_of_node(priv), - SSI_NAME, mod, name); -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_ssi_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - seq_printf(m, "clock: %s\n", rsnd_rdai_is_clk_master(rdai) ? - "provider" : "consumer"); - seq_printf(m, "bit_clk_inv: %d\n", rdai->bit_clk_inv); - seq_printf(m, "frm_clk_inv: %d\n", rdai->frm_clk_inv); - seq_printf(m, "pin share: %d\n", __rsnd_ssi_is_pin_sharing(mod)); - seq_printf(m, "can out clk: %d\n", rsnd_ssi_can_output_clk(mod)); - seq_printf(m, "multi secondary: %d\n", rsnd_ssi_is_multi_secondary(mod, io)); - seq_printf(m, "tdm: %d, %d\n", rsnd_runtime_is_tdm(io), - rsnd_runtime_is_tdm_split(io)); - seq_printf(m, "chan: %d\n", ssi->chan); - seq_printf(m, "user: %d\n", ssi->usrcnt); - - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSI, - rsnd_mod_id(mod) * 0x40, 0x40); -} -#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_ssi_dma_ops = { - .name = SSI_NAME, - .dma_req = rsnd_ssi_dma_req, - .probe = rsnd_ssi_dma_probe, - .remove = rsnd_ssi_common_remove, - .init = rsnd_ssi_init, - .quit = rsnd_ssi_quit, - .start = rsnd_ssi_start, - .stop = rsnd_ssi_stop, - .irq = rsnd_ssi_irq, - .pcm_new = rsnd_ssi_pcm_new, - .fallback = rsnd_ssi_fallback, - .hw_params = rsnd_ssi_hw_params, - .get_status = rsnd_ssi_get_status, - DEBUG_INFO -}; - -int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) -{ - return mod->ops == &rsnd_ssi_dma_ops; -} - -/* - * ssi mod function - */ -static void rsnd_ssi_connect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - static const enum rsnd_mod_type types[] = { - RSND_MOD_SSI, - RSND_MOD_SSIM1, - RSND_MOD_SSIM2, - RSND_MOD_SSIM3, - }; - enum rsnd_mod_type type; - int i; - - /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */ - for (i = 0; i < ARRAY_SIZE(types); i++) { - type = types[i]; - if (!rsnd_io_to_mod(io, type)) { - rsnd_dai_connect(mod, io, type); - rsnd_rdai_channels_set(rdai, (i + 1) * 2); - rsnd_rdai_ssi_lane_set(rdai, (i + 1)); - return; - } - } -} - -void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, - struct device_node *playback, - struct device_node *capture) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *node; - struct device_node *np; - int i; - - node = rsnd_ssi_of_node(priv); - if (!node) - return; - - i = 0; - for_each_child_of_node(node, np) { - struct rsnd_mod *mod; - - i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); - if (i < 0) { - of_node_put(np); - break; - } - - mod = rsnd_ssi_mod_get(priv, i); - - if (np == playback) - rsnd_ssi_connect(mod, &rdai->playback); - if (np == capture) - rsnd_ssi_connect(mod, &rdai->capture); - i++; - } - - of_node_put(node); -} - -struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) - id = 0; - - return rsnd_mod_get(rsnd_ssi_get(priv, id)); -} - -int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) -{ - if (!mod) - return 0; - - return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE)); -} - -int rsnd_ssi_probe(struct rsnd_priv *priv) -{ - struct device_node *node; - struct device_node *np; - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mod_ops *ops; - struct clk *clk; - struct rsnd_ssi *ssi; - char name[RSND_SSI_NAME_SIZE]; - int i, nr, ret; - - node = rsnd_ssi_of_node(priv); - if (!node) - return -EINVAL; - - nr = rsnd_node_count(priv, node, SSI_NAME); - if (!nr) { - ret = -EINVAL; - goto rsnd_ssi_probe_done; - } - - ssi = devm_kcalloc(dev, nr, sizeof(*ssi), GFP_KERNEL); - if (!ssi) { - ret = -ENOMEM; - goto rsnd_ssi_probe_done; - } - - priv->ssi = ssi; - priv->ssi_nr = nr; - - i = 0; - for_each_child_of_node(node, np) { - if (!of_device_is_available(np)) - goto skip; - - i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); - if (i < 0) { - ret = -EINVAL; - of_node_put(np); - goto rsnd_ssi_probe_done; - } - - ssi = rsnd_ssi_get(priv, i); - - snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", - SSI_NAME, i); - - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - of_node_put(np); - goto rsnd_ssi_probe_done; - } - - if (of_property_read_bool(np, "shared-pin")) - rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE); - - if (of_property_read_bool(np, "no-busif")) - rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF); - - ssi->irq = irq_of_parse_and_map(np, 0); - if (!ssi->irq) { - ret = -EINVAL; - of_node_put(np); - goto rsnd_ssi_probe_done; - } - - if (of_property_read_bool(np, "pio-transfer")) - ops = &rsnd_ssi_pio_ops; - else - ops = &rsnd_ssi_dma_ops; - - ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, - RSND_MOD_SSI, i); - if (ret) { - of_node_put(np); - goto rsnd_ssi_probe_done; - } -skip: - i++; - } - - ret = 0; - -rsnd_ssi_probe_done: - of_node_put(node); - - return ret; -} - -void rsnd_ssi_remove(struct rsnd_priv *priv) -{ - struct rsnd_ssi *ssi; - int i; - - for_each_rsnd_ssi(ssi, priv, i) { - rsnd_mod_quit(rsnd_mod_get(ssi)); - } -} diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c deleted file mode 100644 index 665e8b2db579e3..00000000000000 --- a/sound/soc/sh/rcar/ssiu.c +++ /dev/null @@ -1,609 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas R-Car SSIU support -// -// Copyright (c) 2015 Kuninori Morimoto - -#include "rsnd.h" - -#define SSIU_NAME "ssiu" - -struct rsnd_ssiu { - struct rsnd_mod mod; - u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */ - unsigned int usrcnt; - int id; - int id_sub; -}; - -/* SSI_MODE */ -#define TDM_EXT (1 << 0) -#define TDM_SPLIT (1 << 8) - -#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) -#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod) -#define for_each_rsnd_ssiu(pos, priv, i) \ - for (i = 0; \ - (i < rsnd_ssiu_nr(priv)) && \ - ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ - i++) - -/* - * SSI Gen2 Gen3 Gen4 - * 0 BUSIF0-3 BUSIF0-7 BUSIF0-7 - * 1 BUSIF0-3 BUSIF0-7 - * 2 BUSIF0-3 BUSIF0-7 - * 3 BUSIF0 BUSIF0-7 - * 4 BUSIF0 BUSIF0-7 - * 5 BUSIF0 BUSIF0 - * 6 BUSIF0 BUSIF0 - * 7 BUSIF0 BUSIF0 - * 8 BUSIF0 BUSIF0 - * 9 BUSIF0-3 BUSIF0-7 - * total 22 52 8 - */ -static const int gen2_id[] = { 0, 4, 8, 12, 13, 14, 15, 16, 17, 18 }; -static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 }; -static const int gen4_id[] = { 0 }; - -/* enable busif buffer over/under run interrupt. */ -#define rsnd_ssiu_busif_err_irq_enable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 1) -#define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0) -static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable) -{ - int id = rsnd_mod_id(mod); - int shift, offset; - int i; - - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - shift = id; - offset = 0; - break; - case 9: - shift = 1; - offset = 1; - break; - default: - return; - } - - for (i = 0; i < 4; i++) { - enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset); - u32 val = 0xf << (shift * 4); - u32 sys_int_enable = rsnd_mod_read(mod, reg); - - if (enable) - sys_int_enable |= val; - else - sys_int_enable &= ~val; - rsnd_mod_write(mod, reg, sys_int_enable); - } -} - -bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod) -{ - bool error = false; - int id = rsnd_mod_id(mod); - int shift, offset; - int i; - - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - shift = id; - offset = 0; - break; - case 9: - shift = 1; - offset = 1; - break; - default: - goto out; - } - - for (i = 0; i < 4; i++) { - u32 reg = SSI_SYS_STATUS(i * 2) + offset; - u32 status = rsnd_mod_read(mod, reg); - u32 val = 0xf << (shift * 4); - - status &= val; - if (status) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - error = true; - } - rsnd_mod_write(mod, reg, val); - } -out: - return error; -} - -static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - enum rsnd_mod_type type) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - int busif = rsnd_mod_id_sub(mod); - - return &ssiu->busif_status[busif]; -} - -static int rsnd_ssiu_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - u32 ssis = rsnd_ssi_multi_secondaries_runtime(io); - int use_busif = rsnd_ssi_use_busif(io); - int id = rsnd_mod_id(mod); - int is_clk_master = rsnd_rdai_is_clk_master(rdai); - u32 val1, val2; - - /* clear status */ - rsnd_ssiu_busif_err_status_clear(mod); - - /* Gen4 doesn't have SSI_MODE */ - if (rsnd_is_gen4(priv)) - goto ssi_mode_setting_end; - - /* - * SSI_MODE0 - */ - rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id); - - /* - * SSI_MODE1 / SSI_MODE2 - * - * FIXME - * sharing/multi with SSI0 are mainly supported - */ - val1 = rsnd_mod_read(mod, SSI_MODE1); - val2 = rsnd_mod_read(mod, SSI_MODE2); - if (rsnd_ssi_is_pin_sharing(io)) { - - ssis |= (1 << id); - - } else if (ssis) { - /* - * Multi SSI - * - * set synchronized bit here - */ - - /* SSI4 is synchronized with SSI3 */ - if (ssis & (1 << 4)) - val1 |= (1 << 20); - /* SSI012 are synchronized */ - if (ssis == 0x0006) - val1 |= (1 << 4); - /* SSI0129 are synchronized */ - if (ssis == 0x0206) - val2 |= (1 << 4); - } - - /* SSI1 is sharing pin with SSI0 */ - if (ssis & (1 << 1)) - val1 |= is_clk_master ? 0x2 : 0x1; - - /* SSI2 is sharing pin with SSI0 */ - if (ssis & (1 << 2)) - val1 |= is_clk_master ? 0x2 << 2 : - 0x1 << 2; - /* SSI4 is sharing pin with SSI3 */ - if (ssis & (1 << 4)) - val1 |= is_clk_master ? 0x2 << 16 : - 0x1 << 16; - /* SSI9 is sharing pin with SSI0 */ - if (ssis & (1 << 9)) - val2 |= is_clk_master ? 0x2 : 0x1; - - rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1); - rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2); - -ssi_mode_setting_end: - /* - * Enable busif buffer over/under run interrupt. - * It will be handled from ssi.c - * see - * __rsnd_ssi_interrupt() - */ - rsnd_ssiu_busif_err_irq_enable(mod); - - return 0; -} - -static int rsnd_ssiu_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - /* disable busif buffer over/under run interrupt. */ - rsnd_ssiu_busif_err_irq_disable(mod); - - return 0; -} - -static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { - .name = SSIU_NAME, - .init = rsnd_ssiu_init, - .quit = rsnd_ssiu_quit, - .get_status = rsnd_ssiu_get_status, -}; - -static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0); - u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1); - int ret; - u32 mode = 0; - - ret = rsnd_ssiu_init(mod, io, priv); - if (ret < 0) - return ret; - - ssiu->usrcnt++; - - /* - * TDM Extend/Split Mode - * see - * rsnd_ssi_config_init() - */ - if (rsnd_runtime_is_tdm(io)) - mode = TDM_EXT; - else if (rsnd_runtime_is_tdm_split(io)) - mode = TDM_SPLIT; - - rsnd_mod_write(mod, SSI_MODE, mode); - - if (rsnd_ssi_use_busif(io)) { - int id = rsnd_mod_id(mod); - int busif = rsnd_mod_id_sub(mod); - enum rsnd_reg adinr_reg, mode_reg, dalign_reg; - - if ((id == 9) && (busif >= 4)) { - adinr_reg = SSI9_BUSIF_ADINR(busif); - mode_reg = SSI9_BUSIF_MODE(busif); - dalign_reg = SSI9_BUSIF_DALIGN(busif); - } else { - adinr_reg = SSI_BUSIF_ADINR(busif); - mode_reg = SSI_BUSIF_MODE(busif); - dalign_reg = SSI_BUSIF_DALIGN(busif); - } - - rsnd_mod_write(mod, adinr_reg, - rsnd_get_adinr_bit(mod, io) | - (rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu(io) : - rsnd_runtime_channel_original(io))); - rsnd_mod_write(mod, mode_reg, - rsnd_get_busif_shift(io, mod) | 1); - rsnd_mod_write(mod, dalign_reg, - rsnd_get_dalign(mod, io)); - } - - if (has_hdmi0 || has_hdmi1) { - enum rsnd_mod_type rsnd_ssi_array[] = { - RSND_MOD_SSIM1, - RSND_MOD_SSIM2, - RSND_MOD_SSIM3, - }; - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *pos; - u32 val; - int i; - - i = rsnd_mod_id(ssi_mod); - - /* output all same SSI as default */ - val = i << 16 | - i << 20 | - i << 24 | - i << 28 | - i; - - for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) { - int shift = (i * 4) + 20; - - val = (val & ~(0xF << shift)) | - rsnd_mod_id(pos) << shift; - } - - if (has_hdmi0) - rsnd_mod_write(mod, HDMI0_SEL, val); - if (has_hdmi1) - rsnd_mod_write(mod, HDMI1_SEL, val); - } - - return 0; -} - -static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int busif = rsnd_mod_id_sub(mod); - - if (!rsnd_ssi_use_busif(io)) - return 0; - - rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4)); - - if (rsnd_ssi_multi_secondaries_runtime(io)) - rsnd_mod_write(mod, SSI_CONTROL, 0x1); - - return 0; -} - -static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - int busif = rsnd_mod_id_sub(mod); - - if (!rsnd_ssi_use_busif(io)) - return 0; - - rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0); - - if (--ssiu->usrcnt) - return 0; - - if (rsnd_ssi_multi_secondaries_runtime(io)) - rsnd_mod_write(mod, SSI_CONTROL, 0); - - return 0; -} - -static int rsnd_ssiu_id(struct rsnd_mod *mod) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - - /* see rsnd_ssiu_probe() */ - return ssiu->id; -} - -static int rsnd_ssiu_id_sub(struct rsnd_mod *mod) -{ - struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod); - - /* see rsnd_ssiu_probe() */ - return ssiu->id_sub; -} - -static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - int is_play = rsnd_io_is_play(io); - char *name; - - /* - * It should use "rcar_sound,ssiu" on DT. - * But, we need to keep compatibility for old version. - * - * If it has "rcar_sound.ssiu", it will be used. - * If not, "rcar_sound.ssi" will be used. - * see - * rsnd_ssi_dma_req() - * rsnd_dma_of_path() - */ - - name = is_play ? "rx" : "tx"; - - return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv), - SSIU_NAME, mod, name); -} - -#ifdef CONFIG_DEBUG_FS -static void rsnd_ssiu_debug_info(struct seq_file *m, - struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSIU, - rsnd_mod_id(mod) * 0x80, 0x80); -} -#define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info -#else -#define DEBUG_INFO -#endif - -static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { - .name = SSIU_NAME, - .dma_req = rsnd_ssiu_dma_req, - .init = rsnd_ssiu_init_gen2, - .quit = rsnd_ssiu_quit, - .start = rsnd_ssiu_start_gen2, - .stop = rsnd_ssiu_stop_gen2, - .get_status = rsnd_ssiu_get_status, - DEBUG_INFO -}; - -static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) -{ - if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv))) - id = 0; - - return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); -} - -static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, - struct rsnd_dai_stream *io) -{ - struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_ssiu *ssiu; - int is_dma_mode; - int i; - - if (!ssi_mod) - return; - - is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod); - - /* select BUSIF0 */ - for_each_rsnd_ssiu(ssiu, priv, i) { - struct rsnd_mod *mod = rsnd_mod_get(ssiu); - - if (is_dma_mode && - (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && - (rsnd_mod_id_sub(mod) == 0)) { - rsnd_dai_connect(mod, io, mod->type); - return; - } - } -} - -void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, - struct device_node *playback, - struct device_node *capture) -{ - struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *node = rsnd_ssiu_of_node(priv); - struct rsnd_dai_stream *io_p = &rdai->playback; - struct rsnd_dai_stream *io_c = &rdai->capture; - - /* use rcar_sound,ssiu if exist */ - if (node) { - struct device_node *np; - int i = 0; - - for_each_child_of_node(node, np) { - struct rsnd_mod *mod; - - i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i); - if (i < 0) { - of_node_put(np); - break; - } - - mod = rsnd_ssiu_mod_get(priv, i); - - if (np == playback) - rsnd_dai_connect(mod, io_p, mod->type); - if (np == capture) - rsnd_dai_connect(mod, io_c, mod->type); - i++; - } - - of_node_put(node); - } - - /* Keep DT compatibility */ - if (!rsnd_io_to_mod_ssiu(io_p)) - rsnd_parse_connect_ssiu_compatible(priv, io_p); - if (!rsnd_io_to_mod_ssiu(io_c)) - rsnd_parse_connect_ssiu_compatible(priv, io_c); -} - -int rsnd_ssiu_probe(struct rsnd_priv *priv) -{ - struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *node; - struct rsnd_ssiu *ssiu; - struct rsnd_mod_ops *ops; - const int *list = NULL; - int i, nr; - - /* - * Keep DT compatibility. - * if it has "rcar_sound,ssiu", use it. - * if not, use "rcar_sound,ssi" - * see - * rsnd_ssiu_bufsif_to_id() - */ - node = rsnd_ssiu_of_node(priv); - if (node) - nr = rsnd_node_count(priv, node, SSIU_NAME); - else - nr = priv->ssi_nr; - - if (!nr) - return -EINVAL; - - ssiu = devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL); - if (!ssiu) - return -ENOMEM; - - priv->ssiu = ssiu; - priv->ssiu_nr = nr; - - if (rsnd_is_gen1(priv)) - ops = &rsnd_ssiu_ops_gen1; - else - ops = &rsnd_ssiu_ops_gen2; - - /* Keep compatibility */ - nr = 0; - if ((node) && - (ops == &rsnd_ssiu_ops_gen2)) { - ops->id = rsnd_ssiu_id; - ops->id_sub = rsnd_ssiu_id_sub; - - if (rsnd_is_gen2(priv)) { - list = gen2_id; - nr = ARRAY_SIZE(gen2_id); - } else if (rsnd_is_gen3(priv)) { - list = gen3_id; - nr = ARRAY_SIZE(gen3_id); - } else if (rsnd_is_gen4(priv)) { - list = gen4_id; - nr = ARRAY_SIZE(gen4_id); - } else { - dev_err(dev, "unknown SSIU\n"); - return -ENODEV; - } - } - - for_each_rsnd_ssiu(ssiu, priv, i) { - int ret; - - if (node) { - int j; - - /* - * see - * rsnd_ssiu_get_id() - * rsnd_ssiu_get_id_sub() - */ - for (j = 0; j < nr; j++) { - if (list[j] > i) - break; - ssiu->id = j; - ssiu->id_sub = i - list[ssiu->id]; - } - } else { - ssiu->id = i; - } - - ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), - ops, NULL, RSND_MOD_SSIU, i); - if (ret) - return ret; - } - - return 0; -} - -void rsnd_ssiu_remove(struct rsnd_priv *priv) -{ - struct rsnd_ssiu *ssiu; - int i; - - for_each_rsnd_ssiu(ssiu, priv, i) { - rsnd_mod_quit(rsnd_mod_get(ssiu)); - } -} diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c deleted file mode 100644 index 040ce0431fd2c5..00000000000000 --- a/sound/soc/sh/rz-ssi.c +++ /dev/null @@ -1,1214 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Renesas RZ/G2L ASoC Serial Sound Interface (SSIF-2) Driver -// -// Copyright (C) 2021 Renesas Electronics Corp. -// Copyright (C) 2019 Chris Brandt. -// - -#include -#include -#include -#include -#include -#include -#include - -/* REGISTER OFFSET */ -#define SSICR 0x000 -#define SSISR 0x004 -#define SSIFCR 0x010 -#define SSIFSR 0x014 -#define SSIFTDR 0x018 -#define SSIFRDR 0x01c -#define SSIOFR 0x020 -#define SSISCR 0x024 - -/* SSI REGISTER BITS */ -#define SSICR_DWL(x) (((x) & 0x7) << 19) -#define SSICR_SWL(x) (((x) & 0x7) << 16) - -#define SSICR_CKS BIT(30) -#define SSICR_TUIEN BIT(29) -#define SSICR_TOIEN BIT(28) -#define SSICR_RUIEN BIT(27) -#define SSICR_ROIEN BIT(26) -#define SSICR_MST BIT(14) -#define SSICR_BCKP BIT(13) -#define SSICR_LRCKP BIT(12) -#define SSICR_CKDV(x) (((x) & 0xf) << 4) -#define SSICR_TEN BIT(1) -#define SSICR_REN BIT(0) - -#define SSISR_TUIRQ BIT(29) -#define SSISR_TOIRQ BIT(28) -#define SSISR_RUIRQ BIT(27) -#define SSISR_ROIRQ BIT(26) -#define SSISR_IIRQ BIT(25) - -#define SSIFCR_AUCKE BIT(31) -#define SSIFCR_SSIRST BIT(16) -#define SSIFCR_TIE BIT(3) -#define SSIFCR_RIE BIT(2) -#define SSIFCR_TFRST BIT(1) -#define SSIFCR_RFRST BIT(0) -#define SSIFCR_FIFO_RST (SSIFCR_TFRST | SSIFCR_RFRST) - -#define SSIFSR_TDC_MASK 0x3f -#define SSIFSR_TDC_SHIFT 24 -#define SSIFSR_RDC_MASK 0x3f -#define SSIFSR_RDC_SHIFT 8 - -#define SSIFSR_TDE BIT(16) -#define SSIFSR_RDF BIT(0) - -#define SSIOFR_LRCONT BIT(8) - -#define SSISCR_TDES(x) (((x) & 0x1f) << 8) -#define SSISCR_RDFS(x) (((x) & 0x1f) << 0) - -/* Pre allocated buffers sizes */ -#define PREALLOC_BUFFER (SZ_32K) -#define PREALLOC_BUFFER_MAX (SZ_32K) - -#define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-44.1kHz */ -#define SSI_FMTS SNDRV_PCM_FMTBIT_S16_LE -#define SSI_CHAN_MIN 2 -#define SSI_CHAN_MAX 2 -#define SSI_FIFO_DEPTH 32 - -struct rz_ssi_priv; - -struct rz_ssi_stream { - struct rz_ssi_priv *priv; - struct snd_pcm_substream *substream; - int fifo_sample_size; /* sample capacity of SSI FIFO */ - int dma_buffer_pos; /* The address for the next DMA descriptor */ - int period_counter; /* for keeping track of periods transferred */ - int sample_width; - int buffer_pos; /* current frame position in the buffer */ - int running; /* 0=stopped, 1=running */ - - int uerr_num; - int oerr_num; - - struct dma_chan *dma_ch; - - int (*transfer)(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm); -}; - -struct rz_ssi_priv { - void __iomem *base; - struct platform_device *pdev; - struct reset_control *rstc; - struct device *dev; - struct clk *sfr_clk; - struct clk *clk; - - phys_addr_t phys; - int irq_int; - int irq_tx; - int irq_rx; - int irq_rt; - - spinlock_t lock; - - /* - * The SSI supports full-duplex transmission and reception. - * However, if an error occurs, channel reset (both transmission - * and reception reset) is required. - * So it is better to use as half-duplex (playing and recording - * should be done on separate channels). - */ - struct rz_ssi_stream playback; - struct rz_ssi_stream capture; - - /* clock */ - unsigned long audio_mck; - unsigned long audio_clk_1; - unsigned long audio_clk_2; - - bool lrckp_fsync_fall; /* LR clock polarity (SSICR.LRCKP) */ - bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */ - bool dma_rt; - - /* Full duplex communication support */ - struct { - unsigned int rate; - unsigned int channels; - unsigned int sample_width; - unsigned int sample_bits; - } hw_params_cache; -}; - -static void rz_ssi_dma_complete(void *data); - -static void rz_ssi_reg_writel(struct rz_ssi_priv *priv, uint reg, u32 data) -{ - writel(data, (priv->base + reg)); -} - -static u32 rz_ssi_reg_readl(struct rz_ssi_priv *priv, uint reg) -{ - return readl(priv->base + reg); -} - -static void rz_ssi_reg_mask_setl(struct rz_ssi_priv *priv, uint reg, - u32 bclr, u32 bset) -{ - u32 val; - - val = readl(priv->base + reg); - val = (val & ~bclr) | bset; - writel(val, (priv->base + reg)); -} - -static inline struct snd_soc_dai * -rz_ssi_get_dai(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - - return snd_soc_rtd_to_cpu(rtd, 0); -} - -static inline bool rz_ssi_stream_is_play(struct rz_ssi_priv *ssi, - struct snd_pcm_substream *substream) -{ - return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; -} - -static inline struct rz_ssi_stream * -rz_ssi_stream_get(struct rz_ssi_priv *ssi, struct snd_pcm_substream *substream) -{ - struct rz_ssi_stream *stream = &ssi->playback; - - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - stream = &ssi->capture; - - return stream; -} - -static inline bool rz_ssi_is_dma_enabled(struct rz_ssi_priv *ssi) -{ - return (ssi->playback.dma_ch && (ssi->dma_rt || ssi->capture.dma_ch)); -} - -static void rz_ssi_set_substream(struct rz_ssi_stream *strm, - struct snd_pcm_substream *substream) -{ - struct rz_ssi_priv *ssi = strm->priv; - unsigned long flags; - - spin_lock_irqsave(&ssi->lock, flags); - strm->substream = substream; - spin_unlock_irqrestore(&ssi->lock, flags); -} - -static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi, - struct rz_ssi_stream *strm) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&ssi->lock, flags); - ret = strm->substream && strm->substream->runtime; - spin_unlock_irqrestore(&ssi->lock, flags); - - return ret; -} - -static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm) -{ - return strm->substream && strm->running; -} - -static void rz_ssi_stream_init(struct rz_ssi_stream *strm, - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - rz_ssi_set_substream(strm, substream); - strm->sample_width = samples_to_bytes(runtime, 1); - strm->dma_buffer_pos = 0; - strm->period_counter = 0; - strm->buffer_pos = 0; - - strm->oerr_num = 0; - strm->uerr_num = 0; - strm->running = 0; - - /* fifo init */ - strm->fifo_sample_size = SSI_FIFO_DEPTH; -} - -static void rz_ssi_stream_quit(struct rz_ssi_priv *ssi, - struct rz_ssi_stream *strm) -{ - struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream); - - rz_ssi_set_substream(strm, NULL); - - if (strm->oerr_num > 0) - dev_info(dai->dev, "overrun = %d\n", strm->oerr_num); - - if (strm->uerr_num > 0) - dev_info(dai->dev, "underrun = %d\n", strm->uerr_num); -} - -static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, - unsigned int channels) -{ - static s8 ckdv[16] = { 1, 2, 4, 8, 16, 32, 64, 128, - 6, 12, 24, 48, 96, -1, -1, -1 }; - unsigned int channel_bits = 32; /* System Word Length */ - unsigned long bclk_rate = rate * channels * channel_bits; - unsigned int div; - unsigned int i; - u32 ssicr = 0; - u32 clk_ckdv; - - /* Clear AUCKE so we can set MST */ - rz_ssi_reg_writel(ssi, SSIFCR, 0); - - /* Continue to output LRCK pin even when idle */ - rz_ssi_reg_writel(ssi, SSIOFR, SSIOFR_LRCONT); - if (ssi->audio_clk_1 && ssi->audio_clk_2) { - if (ssi->audio_clk_1 % bclk_rate) - ssi->audio_mck = ssi->audio_clk_2; - else - ssi->audio_mck = ssi->audio_clk_1; - } - - /* Clock setting */ - ssicr |= SSICR_MST; - if (ssi->audio_mck == ssi->audio_clk_1) - ssicr |= SSICR_CKS; - if (ssi->bckp_rise) - ssicr |= SSICR_BCKP; - if (ssi->lrckp_fsync_fall) - ssicr |= SSICR_LRCKP; - - /* Determine the clock divider */ - clk_ckdv = 0; - div = ssi->audio_mck / bclk_rate; - /* try to find an match */ - for (i = 0; i < ARRAY_SIZE(ckdv); i++) { - if (ckdv[i] == div) { - clk_ckdv = i; - break; - } - } - - if (i == ARRAY_SIZE(ckdv)) { - dev_err(ssi->dev, "Rate not divisible by audio clock source\n"); - return -EINVAL; - } - - /* - * DWL: Data Word Length = 16 bits - * SWL: System Word Length = 32 bits - */ - ssicr |= SSICR_CKDV(clk_ckdv); - ssicr |= SSICR_DWL(1) | SSICR_SWL(3); - rz_ssi_reg_writel(ssi, SSICR, ssicr); - rz_ssi_reg_writel(ssi, SSIFCR, - (SSIFCR_AUCKE | SSIFCR_TFRST | SSIFCR_RFRST)); - - return 0; -} - -static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) -{ - int timeout; - - /* Disable irqs */ - rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN | - SSICR_RUIEN | SSICR_ROIEN, 0); - rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0); - - /* Clear all error flags */ - rz_ssi_reg_mask_setl(ssi, SSISR, - (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | - SSISR_RUIRQ), 0); - - /* Wait for idle */ - timeout = 100; - while (--timeout) { - if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ) - break; - udelay(1); - } - - if (!timeout) - dev_info(ssi->dev, "timeout waiting for SSI idle\n"); - - /* Hold FIFOs in reset */ - rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, - SSIFCR_TFRST | SSIFCR_RFRST); -} - -static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) -{ - bool is_play = rz_ssi_stream_is_play(ssi, strm->substream); - bool is_full_duplex; - u32 ssicr, ssifcr; - - is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) || - rz_ssi_is_stream_running(&ssi->capture); - ssicr = rz_ssi_reg_readl(ssi, SSICR); - ssifcr = rz_ssi_reg_readl(ssi, SSIFCR); - if (!is_full_duplex) { - ssifcr &= ~0xF; - } else { - rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); - rz_ssi_set_idle(ssi); - ssifcr &= ~SSIFCR_FIFO_RST; - } - - /* FIFO interrupt thresholds */ - if (rz_ssi_is_dma_enabled(ssi)) - rz_ssi_reg_writel(ssi, SSISCR, 0); - else - rz_ssi_reg_writel(ssi, SSISCR, - SSISCR_TDES(strm->fifo_sample_size / 2 - 1) | - SSISCR_RDFS(0)); - - /* enable IRQ */ - if (is_play) { - ssicr |= SSICR_TUIEN | SSICR_TOIEN; - ssifcr |= SSIFCR_TIE; - if (!is_full_duplex) - ssifcr |= SSIFCR_RFRST; - } else { - ssicr |= SSICR_RUIEN | SSICR_ROIEN; - ssifcr |= SSIFCR_RIE; - if (!is_full_duplex) - ssifcr |= SSIFCR_TFRST; - } - - rz_ssi_reg_writel(ssi, SSICR, ssicr); - rz_ssi_reg_writel(ssi, SSIFCR, ssifcr); - - /* Clear all error flags */ - rz_ssi_reg_mask_setl(ssi, SSISR, - (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | - SSISR_RUIRQ), 0); - - strm->running = 1; - if (is_full_duplex) - ssicr |= SSICR_TEN | SSICR_REN; - else - ssicr |= is_play ? SSICR_TEN : SSICR_REN; - - rz_ssi_reg_writel(ssi, SSICR, ssicr); - - return 0; -} - -static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) -{ - strm->running = 0; - - if (rz_ssi_is_stream_running(&ssi->playback) || - rz_ssi_is_stream_running(&ssi->capture)) - return 0; - - /* Disable TX/RX */ - rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); - - /* Cancel all remaining DMA transactions */ - if (rz_ssi_is_dma_enabled(ssi)) - dmaengine_terminate_async(strm->dma_ch); - - rz_ssi_set_idle(ssi); - - return 0; -} - -static void rz_ssi_pointer_update(struct rz_ssi_stream *strm, int frames) -{ - struct snd_pcm_substream *substream = strm->substream; - struct snd_pcm_runtime *runtime; - int current_period; - - if (!strm->running || !substream || !substream->runtime) - return; - - runtime = substream->runtime; - strm->buffer_pos += frames; - WARN_ON(strm->buffer_pos > runtime->buffer_size); - - /* ring buffer */ - if (strm->buffer_pos == runtime->buffer_size) - strm->buffer_pos = 0; - - current_period = strm->buffer_pos / runtime->period_size; - if (strm->period_counter != current_period) { - snd_pcm_period_elapsed(strm->substream); - strm->period_counter = current_period; - } -} - -static int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) -{ - struct snd_pcm_substream *substream = strm->substream; - struct snd_pcm_runtime *runtime; - u16 *buf; - int fifo_samples; - int frames_left; - int samples; - int i; - - if (!rz_ssi_stream_is_valid(ssi, strm)) - return -EINVAL; - - runtime = substream->runtime; - - do { - /* frames left in this period */ - frames_left = runtime->period_size - - (strm->buffer_pos % runtime->period_size); - if (!frames_left) - frames_left = runtime->period_size; - - /* Samples in RX FIFO */ - fifo_samples = (rz_ssi_reg_readl(ssi, SSIFSR) >> - SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK; - - /* Only read full frames at a time */ - samples = 0; - while (frames_left && (fifo_samples >= runtime->channels)) { - samples += runtime->channels; - fifo_samples -= runtime->channels; - frames_left--; - } - - /* not enough samples yet */ - if (!samples) - break; - - /* calculate new buffer index */ - buf = (u16 *)runtime->dma_area; - buf += strm->buffer_pos * runtime->channels; - - /* Note, only supports 16-bit samples */ - for (i = 0; i < samples; i++) - *buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16); - - rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); - rz_ssi_pointer_update(strm, samples / runtime->channels); - } while (!frames_left && fifo_samples >= runtime->channels); - - return 0; -} - -static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) -{ - struct snd_pcm_substream *substream = strm->substream; - struct snd_pcm_runtime *runtime = substream->runtime; - int sample_space; - int samples = 0; - int frames_left; - int i; - u32 ssifsr; - u16 *buf; - - if (!rz_ssi_stream_is_valid(ssi, strm)) - return -EINVAL; - - /* frames left in this period */ - frames_left = runtime->period_size - (strm->buffer_pos % - runtime->period_size); - if (frames_left == 0) - frames_left = runtime->period_size; - - sample_space = strm->fifo_sample_size; - ssifsr = rz_ssi_reg_readl(ssi, SSIFSR); - sample_space -= (ssifsr >> SSIFSR_TDC_SHIFT) & SSIFSR_TDC_MASK; - - /* Only add full frames at a time */ - while (frames_left && (sample_space >= runtime->channels)) { - samples += runtime->channels; - sample_space -= runtime->channels; - frames_left--; - } - - /* no space to send anything right now */ - if (samples == 0) - return 0; - - /* calculate new buffer index */ - buf = (u16 *)(runtime->dma_area); - buf += strm->buffer_pos * runtime->channels; - - /* Note, only supports 16-bit samples */ - for (i = 0; i < samples; i++) - rz_ssi_reg_writel(ssi, SSIFTDR, ((u32)(*buf++) << 16)); - - rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_TDE, 0); - rz_ssi_pointer_update(strm, samples / runtime->channels); - - return 0; -} - -static irqreturn_t rz_ssi_interrupt(int irq, void *data) -{ - struct rz_ssi_stream *strm_playback = NULL; - struct rz_ssi_stream *strm_capture = NULL; - struct rz_ssi_priv *ssi = data; - u32 ssisr = rz_ssi_reg_readl(ssi, SSISR); - - if (ssi->playback.substream) - strm_playback = &ssi->playback; - if (ssi->capture.substream) - strm_capture = &ssi->capture; - - if (!strm_playback && !strm_capture) - return IRQ_HANDLED; /* Left over TX/RX interrupt */ - - if (irq == ssi->irq_int) { /* error or idle */ - bool is_stopped = false; - int i, count; - - if (rz_ssi_is_dma_enabled(ssi)) - count = 4; - else - count = 1; - - if (ssisr & (SSISR_RUIRQ | SSISR_ROIRQ | SSISR_TUIRQ | SSISR_TOIRQ)) - is_stopped = true; - - if (ssi->capture.substream && is_stopped) { - if (ssisr & SSISR_RUIRQ) - strm_capture->uerr_num++; - if (ssisr & SSISR_ROIRQ) - strm_capture->oerr_num++; - - rz_ssi_stop(ssi, strm_capture); - } - - if (ssi->playback.substream && is_stopped) { - if (ssisr & SSISR_TUIRQ) - strm_playback->uerr_num++; - if (ssisr & SSISR_TOIRQ) - strm_playback->oerr_num++; - - rz_ssi_stop(ssi, strm_playback); - } - - /* Clear all flags */ - rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | SSISR_TUIRQ | - SSISR_ROIRQ | SSISR_RUIRQ, 0); - - /* Add/remove more data */ - if (ssi->capture.substream && is_stopped) { - for (i = 0; i < count; i++) - strm_capture->transfer(ssi, strm_capture); - } - - if (ssi->playback.substream && is_stopped) { - for (i = 0; i < count; i++) - strm_playback->transfer(ssi, strm_playback); - } - - /* Resume */ - if (ssi->playback.substream && is_stopped) - rz_ssi_start(ssi, &ssi->playback); - if (ssi->capture.substream && is_stopped) - rz_ssi_start(ssi, &ssi->capture); - } - - if (!rz_ssi_is_stream_running(&ssi->playback) && - !rz_ssi_is_stream_running(&ssi->capture)) - return IRQ_HANDLED; - - /* tx data empty */ - if (irq == ssi->irq_tx && rz_ssi_is_stream_running(&ssi->playback)) - strm_playback->transfer(ssi, &ssi->playback); - - /* rx data full */ - if (irq == ssi->irq_rx && rz_ssi_is_stream_running(&ssi->capture)) { - strm_capture->transfer(ssi, &ssi->capture); - rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); - } - - if (irq == ssi->irq_rt) { - if (ssi->playback.substream) { - strm_playback->transfer(ssi, &ssi->playback); - } else { - strm_capture->transfer(ssi, &ssi->capture); - rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); - } - } - - return IRQ_HANDLED; -} - -static int rz_ssi_dma_slave_config(struct rz_ssi_priv *ssi, - struct dma_chan *dma_ch, bool is_play) -{ - struct dma_slave_config cfg; - - memset(&cfg, 0, sizeof(cfg)); - - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - cfg.dst_addr = ssi->phys + SSIFTDR; - cfg.src_addr = ssi->phys + SSIFRDR; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - - return dmaengine_slave_config(dma_ch, &cfg); -} - -static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi, - struct rz_ssi_stream *strm) -{ - struct snd_pcm_substream *substream = strm->substream; - struct dma_async_tx_descriptor *desc; - struct snd_pcm_runtime *runtime; - enum dma_transfer_direction dir; - u32 dma_paddr, dma_size; - int amount; - - if (!rz_ssi_stream_is_valid(ssi, strm)) - return -EINVAL; - - runtime = substream->runtime; - if (runtime->state == SNDRV_PCM_STATE_DRAINING) - /* - * Stream is ending, so do not queue up any more DMA - * transfers otherwise we play partial sound clips - * because we can't shut off the DMA quick enough. - */ - return 0; - - dir = rz_ssi_stream_is_play(ssi, substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - - /* Always transfer 1 period */ - amount = runtime->period_size; - - /* DMA physical address and size */ - dma_paddr = runtime->dma_addr + frames_to_bytes(runtime, - strm->dma_buffer_pos); - dma_size = frames_to_bytes(runtime, amount); - desc = dmaengine_prep_slave_single(strm->dma_ch, dma_paddr, dma_size, - dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_err(ssi->dev, "dmaengine_prep_slave_single() fail\n"); - return -ENOMEM; - } - - desc->callback = rz_ssi_dma_complete; - desc->callback_param = strm; - - if (dmaengine_submit(desc) < 0) { - dev_err(ssi->dev, "dmaengine_submit() fail\n"); - return -EIO; - } - - /* Update DMA pointer */ - strm->dma_buffer_pos += amount; - if (strm->dma_buffer_pos >= runtime->buffer_size) - strm->dma_buffer_pos = 0; - - /* Start DMA */ - dma_async_issue_pending(strm->dma_ch); - - return 0; -} - -static void rz_ssi_dma_complete(void *data) -{ - struct rz_ssi_stream *strm = (struct rz_ssi_stream *)data; - - if (!strm->running || !strm->substream || !strm->substream->runtime) - return; - - /* Note that next DMA transaction has probably already started */ - rz_ssi_pointer_update(strm, strm->substream->runtime->period_size); - - /* Queue up another DMA transaction */ - rz_ssi_dma_transfer(strm->priv, strm); -} - -static void rz_ssi_release_dma_channels(struct rz_ssi_priv *ssi) -{ - if (ssi->playback.dma_ch) { - dma_release_channel(ssi->playback.dma_ch); - ssi->playback.dma_ch = NULL; - if (ssi->dma_rt) - ssi->dma_rt = false; - } - - if (ssi->capture.dma_ch) { - dma_release_channel(ssi->capture.dma_ch); - ssi->capture.dma_ch = NULL; - } -} - -static int rz_ssi_dma_request(struct rz_ssi_priv *ssi, struct device *dev) -{ - ssi->playback.dma_ch = dma_request_chan(dev, "tx"); - if (IS_ERR(ssi->playback.dma_ch)) - ssi->playback.dma_ch = NULL; - - ssi->capture.dma_ch = dma_request_chan(dev, "rx"); - if (IS_ERR(ssi->capture.dma_ch)) - ssi->capture.dma_ch = NULL; - - if (!ssi->playback.dma_ch && !ssi->capture.dma_ch) { - ssi->playback.dma_ch = dma_request_chan(dev, "rt"); - if (IS_ERR(ssi->playback.dma_ch)) { - ssi->playback.dma_ch = NULL; - goto no_dma; - } - - ssi->dma_rt = true; - } - - if (!rz_ssi_is_dma_enabled(ssi)) - goto no_dma; - - if (ssi->playback.dma_ch && - (rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, true) < 0)) - goto no_dma; - - if (ssi->capture.dma_ch && - (rz_ssi_dma_slave_config(ssi, ssi->capture.dma_ch, false) < 0)) - goto no_dma; - - return 0; - -no_dma: - rz_ssi_release_dma_channels(ssi); - - return -ENODEV; -} - -static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); - struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); - int ret = 0, i, num_transfer = 1; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - /* Soft Reset */ - if (!rz_ssi_is_stream_running(&ssi->playback) && - !rz_ssi_is_stream_running(&ssi->capture)) { - rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); - rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); - udelay(5); - } - - rz_ssi_stream_init(strm, substream); - - if (ssi->dma_rt) { - bool is_playback; - - is_playback = rz_ssi_stream_is_play(ssi, substream); - ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, - is_playback); - /* Fallback to pio */ - if (ret < 0) { - ssi->playback.transfer = rz_ssi_pio_send; - ssi->capture.transfer = rz_ssi_pio_recv; - rz_ssi_release_dma_channels(ssi); - } - } - - /* For DMA, queue up multiple DMA descriptors */ - if (rz_ssi_is_dma_enabled(ssi)) - num_transfer = 4; - - for (i = 0; i < num_transfer; i++) { - ret = strm->transfer(ssi, strm); - if (ret) - goto done; - } - - ret = rz_ssi_start(ssi, strm); - break; - case SNDRV_PCM_TRIGGER_STOP: - rz_ssi_stop(ssi, strm); - rz_ssi_stream_quit(ssi, strm); - break; - } - -done: - return ret; -} - -static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); - - switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_BP_FP: - break; - default: - dev_err(ssi->dev, "Codec should be clk and frame consumer\n"); - return -EINVAL; - } - - /* - * set clock polarity - * - * "normal" BCLK = Signal is available at rising edge of BCLK - * "normal" FSYNC = (I2S) Left ch starts with falling FSYNC edge - */ - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - ssi->bckp_rise = false; - ssi->lrckp_fsync_fall = false; - break; - case SND_SOC_DAIFMT_NB_IF: - ssi->bckp_rise = false; - ssi->lrckp_fsync_fall = true; - break; - case SND_SOC_DAIFMT_IB_NF: - ssi->bckp_rise = true; - ssi->lrckp_fsync_fall = false; - break; - case SND_SOC_DAIFMT_IB_IF: - ssi->bckp_rise = true; - ssi->lrckp_fsync_fall = true; - break; - default: - return -EINVAL; - } - - /* only i2s support */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - break; - default: - dev_err(ssi->dev, "Only I2S mode is supported.\n"); - return -EINVAL; - } - - return 0; -} - -static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, - unsigned int channels, - unsigned int sample_width, - unsigned int sample_bits) -{ - if (ssi->hw_params_cache.rate != rate || - ssi->hw_params_cache.channels != channels || - ssi->hw_params_cache.sample_width != sample_width || - ssi->hw_params_cache.sample_bits != sample_bits) - return false; - - return true; -} - -static void rz_ssi_cache_hw_params(struct rz_ssi_priv *ssi, unsigned int rate, - unsigned int channels, - unsigned int sample_width, - unsigned int sample_bits) -{ - ssi->hw_params_cache.rate = rate; - ssi->hw_params_cache.channels = channels; - ssi->hw_params_cache.sample_width = sample_width; - ssi->hw_params_cache.sample_bits = sample_bits; -} - -static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); - struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); - unsigned int sample_bits = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; - unsigned int channels = params_channels(params); - unsigned int rate = params_rate(params); - - if (sample_bits != 16) { - dev_err(ssi->dev, "Unsupported sample width: %d\n", - sample_bits); - return -EINVAL; - } - - if (channels != 2) { - dev_err(ssi->dev, "Number of channels not matched: %d\n", - channels); - return -EINVAL; - } - - if (rz_ssi_is_stream_running(&ssi->playback) || - rz_ssi_is_stream_running(&ssi->capture)) { - if (rz_ssi_is_valid_hw_params(ssi, rate, channels, - strm->sample_width, sample_bits)) - return 0; - - dev_err(ssi->dev, "Full duplex needs same HW params\n"); - return -EINVAL; - } - - rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width, - sample_bits); - - return rz_ssi_clk_setup(ssi, rate, channels); -} - -static const struct snd_soc_dai_ops rz_ssi_dai_ops = { - .trigger = rz_ssi_dai_trigger, - .set_fmt = rz_ssi_dai_set_fmt, - .hw_params = rz_ssi_dai_hw_params, -}; - -static const struct snd_pcm_hardware rz_ssi_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID, - .buffer_bytes_max = PREALLOC_BUFFER, - .period_bytes_min = 32, - .period_bytes_max = 8192, - .channels_min = SSI_CHAN_MIN, - .channels_max = SSI_CHAN_MAX, - .periods_min = 1, - .periods_max = 32, - .fifo_size = 32 * 2, -}; - -static int rz_ssi_pcm_open(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - snd_soc_set_runtime_hwparams(substream, &rz_ssi_pcm_hardware); - - return snd_pcm_hw_constraint_integer(substream->runtime, - SNDRV_PCM_HW_PARAM_PERIODS); -} - -static snd_pcm_uframes_t rz_ssi_pcm_pointer(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_soc_dai *dai = rz_ssi_get_dai(substream); - struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); - struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); - - return strm->buffer_pos; -} - -static int rz_ssi_pcm_new(struct snd_soc_component *component, - struct snd_soc_pcm_runtime *rtd) -{ - snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, - rtd->card->snd_card->dev, - PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); - return 0; -} - -static struct snd_soc_dai_driver rz_ssi_soc_dai[] = { - { - .name = "rz-ssi-dai", - .playback = { - .rates = SSI_RATES, - .formats = SSI_FMTS, - .channels_min = SSI_CHAN_MIN, - .channels_max = SSI_CHAN_MAX, - }, - .capture = { - .rates = SSI_RATES, - .formats = SSI_FMTS, - .channels_min = SSI_CHAN_MIN, - .channels_max = SSI_CHAN_MAX, - }, - .ops = &rz_ssi_dai_ops, - }, -}; - -static const struct snd_soc_component_driver rz_ssi_soc_component = { - .name = "rz-ssi", - .open = rz_ssi_pcm_open, - .pointer = rz_ssi_pcm_pointer, - .pcm_construct = rz_ssi_pcm_new, - .legacy_dai_naming = 1, -}; - -static int rz_ssi_probe(struct platform_device *pdev) -{ - struct rz_ssi_priv *ssi; - struct clk *audio_clk; - struct resource *res; - int ret; - - ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); - if (!ssi) - return -ENOMEM; - - ssi->pdev = pdev; - ssi->dev = &pdev->dev; - ssi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(ssi->base)) - return PTR_ERR(ssi->base); - - ssi->phys = res->start; - ssi->clk = devm_clk_get(&pdev->dev, "ssi"); - if (IS_ERR(ssi->clk)) - return PTR_ERR(ssi->clk); - - ssi->sfr_clk = devm_clk_get(&pdev->dev, "ssi_sfr"); - if (IS_ERR(ssi->sfr_clk)) - return PTR_ERR(ssi->sfr_clk); - - audio_clk = devm_clk_get(&pdev->dev, "audio_clk1"); - if (IS_ERR(audio_clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), - "no audio clk1"); - - ssi->audio_clk_1 = clk_get_rate(audio_clk); - audio_clk = devm_clk_get(&pdev->dev, "audio_clk2"); - if (IS_ERR(audio_clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), - "no audio clk2"); - - ssi->audio_clk_2 = clk_get_rate(audio_clk); - if (!(ssi->audio_clk_1 || ssi->audio_clk_2)) - return dev_err_probe(&pdev->dev, -EINVAL, - "no audio clk1 or audio clk2"); - - ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2; - - /* Detect DMA support */ - ret = rz_ssi_dma_request(ssi, &pdev->dev); - if (ret < 0) { - dev_warn(&pdev->dev, "DMA not available, using PIO\n"); - ssi->playback.transfer = rz_ssi_pio_send; - ssi->capture.transfer = rz_ssi_pio_recv; - } else { - dev_info(&pdev->dev, "DMA enabled"); - ssi->playback.transfer = rz_ssi_dma_transfer; - ssi->capture.transfer = rz_ssi_dma_transfer; - } - - ssi->playback.priv = ssi; - ssi->capture.priv = ssi; - - spin_lock_init(&ssi->lock); - dev_set_drvdata(&pdev->dev, ssi); - - /* Error Interrupt */ - ssi->irq_int = platform_get_irq_byname(pdev, "int_req"); - if (ssi->irq_int < 0) { - rz_ssi_release_dma_channels(ssi); - return ssi->irq_int; - } - - ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt, - 0, dev_name(&pdev->dev), ssi); - if (ret < 0) { - rz_ssi_release_dma_channels(ssi); - return dev_err_probe(&pdev->dev, ret, - "irq request error (int_req)\n"); - } - - if (!rz_ssi_is_dma_enabled(ssi)) { - /* Tx and Rx interrupts (pio only) */ - ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx"); - ssi->irq_rx = platform_get_irq_byname(pdev, "dma_rx"); - if (ssi->irq_tx == -ENXIO && ssi->irq_rx == -ENXIO) { - ssi->irq_rt = platform_get_irq_byname(pdev, "dma_rt"); - if (ssi->irq_rt < 0) - return ssi->irq_rt; - - ret = devm_request_irq(&pdev->dev, ssi->irq_rt, - &rz_ssi_interrupt, 0, - dev_name(&pdev->dev), ssi); - if (ret < 0) - return dev_err_probe(&pdev->dev, ret, - "irq request error (dma_rt)\n"); - } else { - if (ssi->irq_tx < 0) - return ssi->irq_tx; - - if (ssi->irq_rx < 0) - return ssi->irq_rx; - - ret = devm_request_irq(&pdev->dev, ssi->irq_tx, - &rz_ssi_interrupt, 0, - dev_name(&pdev->dev), ssi); - if (ret < 0) - return dev_err_probe(&pdev->dev, ret, - "irq request error (dma_tx)\n"); - - ret = devm_request_irq(&pdev->dev, ssi->irq_rx, - &rz_ssi_interrupt, 0, - dev_name(&pdev->dev), ssi); - if (ret < 0) - return dev_err_probe(&pdev->dev, ret, - "irq request error (dma_rx)\n"); - } - } - - ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(ssi->rstc)) { - ret = PTR_ERR(ssi->rstc); - goto err_reset; - } - - reset_control_deassert(ssi->rstc); - pm_runtime_enable(&pdev->dev); - ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n"); - goto err_pm; - } - - ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component, - rz_ssi_soc_dai, - ARRAY_SIZE(rz_ssi_soc_dai)); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register snd component\n"); - goto err_snd_soc; - } - - return 0; - -err_snd_soc: - pm_runtime_put(ssi->dev); -err_pm: - pm_runtime_disable(ssi->dev); - reset_control_assert(ssi->rstc); -err_reset: - rz_ssi_release_dma_channels(ssi); - - return ret; -} - -static void rz_ssi_remove(struct platform_device *pdev) -{ - struct rz_ssi_priv *ssi = dev_get_drvdata(&pdev->dev); - - rz_ssi_release_dma_channels(ssi); - - pm_runtime_put(ssi->dev); - pm_runtime_disable(ssi->dev); - reset_control_assert(ssi->rstc); -} - -static const struct of_device_id rz_ssi_of_match[] = { - { .compatible = "renesas,rz-ssi", }, - {/* Sentinel */}, -}; -MODULE_DEVICE_TABLE(of, rz_ssi_of_match); - -static struct platform_driver rz_ssi_driver = { - .driver = { - .name = "rz-ssi-pcm-audio", - .of_match_table = rz_ssi_of_match, - }, - .probe = rz_ssi_probe, - .remove = rz_ssi_remove, -}; - -module_platform_driver(rz_ssi_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Renesas RZ/G2L ASoC Serial Sound Interface Driver"); -MODULE_AUTHOR("Biju Das "); diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c deleted file mode 100644 index d267243a159ba6..00000000000000 --- a/sound/soc/sh/sh7760-ac97.c +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Generic AC97 sound support for SH7760 -// -// (c) 2007 Manuel Lauss - -#include -#include -#include -#include -#include -#include -#include - -#define IPSEL 0xFE400034 - -SND_SOC_DAILINK_DEFS(ac97, - DAILINK_COMP_ARRAY(COMP_CPU("hac-dai.0")), /* HAC0 */ - DAILINK_COMP_ARRAY(COMP_CODEC("ac97-codec", "ac97-hifi")), - DAILINK_COMP_ARRAY(COMP_PLATFORM("sh7760-pcm-audio"))); - -static struct snd_soc_dai_link sh7760_ac97_dai = { - .name = "AC97", - .stream_name = "AC97 HiFi", - SND_SOC_DAILINK_REG(ac97), -}; - -static struct snd_soc_card sh7760_ac97_soc_machine = { - .name = "SH7760 AC97", - .owner = THIS_MODULE, - .dai_link = &sh7760_ac97_dai, - .num_links = 1, -}; - -static struct platform_device *sh7760_ac97_snd_device; - -static int __init sh7760_ac97_init(void) -{ - int ret; - unsigned short ipsel; - - /* enable both AC97 controllers in pinmux reg */ - ipsel = __raw_readw(IPSEL); - __raw_writew(ipsel | (3 << 10), IPSEL); - - ret = -ENOMEM; - sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1); - if (!sh7760_ac97_snd_device) - goto out; - - platform_set_drvdata(sh7760_ac97_snd_device, - &sh7760_ac97_soc_machine); - ret = platform_device_add(sh7760_ac97_snd_device); - - if (ret) - platform_device_put(sh7760_ac97_snd_device); - -out: - return ret; -} - -static void __exit sh7760_ac97_exit(void) -{ - platform_device_unregister(sh7760_ac97_snd_device); -} - -module_init(sh7760_ac97_init); -module_exit(sh7760_ac97_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine"); -MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h deleted file mode 100644 index a675c36fc9d956..00000000000000 --- a/sound/soc/sh/siu.h +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral. -// -// Copyright (C) 2009-2010 Guennadi Liakhovetski -// Copyright (C) 2006 Carlos Munoz - -#ifndef SIU_H -#define SIU_H - -/* Common kernel and user-space firmware-building defines and types */ - -#define YRAM0_SIZE (0x0040 / 4) /* 16 */ -#define YRAM1_SIZE (0x0080 / 4) /* 32 */ -#define YRAM2_SIZE (0x0040 / 4) /* 16 */ -#define YRAM3_SIZE (0x0080 / 4) /* 32 */ -#define YRAM4_SIZE (0x0080 / 4) /* 32 */ -#define YRAM_DEF_SIZE (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \ - YRAM3_SIZE + YRAM4_SIZE) -#define YRAM_FIR_SIZE (0x0400 / 4) /* 256 */ -#define YRAM_IIR_SIZE (0x0200 / 4) /* 128 */ - -#define XRAM0_SIZE (0x0400 / 4) /* 256 */ -#define XRAM1_SIZE (0x0200 / 4) /* 128 */ -#define XRAM2_SIZE (0x0200 / 4) /* 128 */ - -/* PRAM program array size */ -#define PRAM0_SIZE (0x0100 / 4) /* 64 */ -#define PRAM1_SIZE ((0x2000 - 0x0100) / 4) /* 1984 */ - -#include - -struct siu_spb_param { - __u32 ab1a; /* input FIFO address */ - __u32 ab0a; /* output FIFO address */ - __u32 dir; /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */ - __u32 event; /* SPB program starting conditions */ - __u32 stfifo; /* STFIFO register setting value */ - __u32 trdat; /* TRDAT register setting value */ -}; - -struct siu_firmware { - __u32 yram_fir_coeff[YRAM_FIR_SIZE]; - __u32 pram0[PRAM0_SIZE]; - __u32 pram1[PRAM1_SIZE]; - __u32 yram0[YRAM0_SIZE]; - __u32 yram1[YRAM1_SIZE]; - __u32 yram2[YRAM2_SIZE]; - __u32 yram3[YRAM3_SIZE]; - __u32 yram4[YRAM4_SIZE]; - __u32 spbpar_num; - struct siu_spb_param spbpar[32]; -}; - -#ifdef __KERNEL__ - -#include -#include -#include -#include - -#include -#include -#include - -#define SIU_PERIOD_BYTES_MAX 8192 /* DMA transfer/period size */ -#define SIU_PERIOD_BYTES_MIN 256 /* DMA transfer/period size */ -#define SIU_PERIODS_MAX 64 /* Max periods in buffer */ -#define SIU_PERIODS_MIN 4 /* Min periods in buffer */ -#define SIU_BUFFER_BYTES_MAX (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX) - -/* SIU ports: only one can be used at a time */ -enum { - SIU_PORT_A, - SIU_PORT_B, - SIU_PORT_NUM, -}; - -/* SIU clock configuration */ -enum { - SIU_CLKA_PLL, - SIU_CLKA_EXT, - SIU_CLKB_PLL, - SIU_CLKB_EXT -}; - -struct device; -struct siu_info { - struct device *dev; - int port_id; - u32 __iomem *pram; - u32 __iomem *xram; - u32 __iomem *yram; - u32 __iomem *reg; - struct siu_firmware fw; -}; - -struct siu_stream { - struct work_struct work; - struct snd_pcm_substream *substream; - snd_pcm_format_t format; - size_t buf_bytes; - size_t period_bytes; - int cur_period; /* Period currently in dma */ - u32 volume; - snd_pcm_sframes_t xfer_cnt; /* Number of frames */ - u8 rw_flg; /* transfer status */ - /* DMA status */ - struct dma_chan *chan; /* DMA channel */ - struct dma_async_tx_descriptor *tx_desc; - dma_cookie_t cookie; - struct sh_dmae_slave param; -}; - -struct siu_port { - unsigned long play_cap; /* Used to track full duplex */ - struct snd_pcm *pcm; - struct siu_stream playback; - struct siu_stream capture; - u32 stfifo; /* STFIFO value from firmware */ - u32 trdat; /* TRDAT value from firmware */ -}; - -extern struct siu_port *siu_ports[SIU_PORT_NUM]; - -static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream) -{ - struct platform_device *pdev = - to_platform_device(substream->pcm->card->dev); - return siu_ports[pdev->id]; -} - -/* Register access */ -static inline void siu_write32(u32 __iomem *addr, u32 val) -{ - __raw_writel(val, addr); -} - -static inline u32 siu_read32(u32 __iomem *addr) -{ - return __raw_readl(addr); -} - -/* SIU registers */ -#define SIU_IFCTL (0x000 / sizeof(u32)) -#define SIU_SRCTL (0x004 / sizeof(u32)) -#define SIU_SFORM (0x008 / sizeof(u32)) -#define SIU_CKCTL (0x00c / sizeof(u32)) -#define SIU_TRDAT (0x010 / sizeof(u32)) -#define SIU_STFIFO (0x014 / sizeof(u32)) -#define SIU_DPAK (0x01c / sizeof(u32)) -#define SIU_CKREV (0x020 / sizeof(u32)) -#define SIU_EVNTC (0x028 / sizeof(u32)) -#define SIU_SBCTL (0x040 / sizeof(u32)) -#define SIU_SBPSET (0x044 / sizeof(u32)) -#define SIU_SBFSTS (0x068 / sizeof(u32)) -#define SIU_SBDVCA (0x06c / sizeof(u32)) -#define SIU_SBDVCB (0x070 / sizeof(u32)) -#define SIU_SBACTIV (0x074 / sizeof(u32)) -#define SIU_DMAIA (0x090 / sizeof(u32)) -#define SIU_DMAIB (0x094 / sizeof(u32)) -#define SIU_DMAOA (0x098 / sizeof(u32)) -#define SIU_DMAOB (0x09c / sizeof(u32)) -#define SIU_DMAML (0x0a0 / sizeof(u32)) -#define SIU_SPSTS (0x0cc / sizeof(u32)) -#define SIU_SPCTL (0x0d0 / sizeof(u32)) -#define SIU_BRGASEL (0x100 / sizeof(u32)) -#define SIU_BRRA (0x104 / sizeof(u32)) -#define SIU_BRGBSEL (0x108 / sizeof(u32)) -#define SIU_BRRB (0x10c / sizeof(u32)) - -extern const struct snd_soc_component_driver siu_component; -extern struct siu_info *siu_i2s_data; - -int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card); -void siu_free_port(struct siu_port *port_info); - -#endif - -#endif /* SIU_H */ diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c deleted file mode 100644 index 7e771a164a80e4..00000000000000 --- a/sound/soc/sh/siu_dai.c +++ /dev/null @@ -1,800 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral. -// -// Copyright (C) 2009-2010 Guennadi Liakhovetski -// Copyright (C) 2006 Carlos Munoz - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "siu.h" - -/* Board specifics */ -#if defined(CONFIG_CPU_SUBTYPE_SH7722) -# define SIU_MAX_VOLUME 0x1000 -#else -# define SIU_MAX_VOLUME 0x7fff -#endif - -#define PRAM_SIZE 0x2000 -#define XRAM_SIZE 0x800 -#define YRAM_SIZE 0x800 - -#define XRAM_OFFSET 0x4000 -#define YRAM_OFFSET 0x6000 -#define REG_OFFSET 0xc000 - -#define PLAYBACK_ENABLED 1 -#define CAPTURE_ENABLED 2 - -#define VOLUME_CAPTURE 0 -#define VOLUME_PLAYBACK 1 -#define DFLT_VOLUME_LEVEL 0x08000800 - -/* - * SPDIF is only available on port A and on some SIU implementations it is only - * available for input. Due to the lack of hardware to test it, SPDIF is left - * disabled in this driver version - */ -struct format_flag { - u32 i2s; - u32 pcm; - u32 spdif; - u32 mask; -}; - -struct port_flag { - struct format_flag playback; - struct format_flag capture; -}; - -struct siu_info *siu_i2s_data; - -static struct port_flag siu_flags[SIU_PORT_NUM] = { - [SIU_PORT_A] = { - .playback = { - .i2s = 0x50000000, - .pcm = 0x40000000, - .spdif = 0x80000000, /* not on all SIU versions */ - .mask = 0xd0000000, - }, - .capture = { - .i2s = 0x05000000, - .pcm = 0x04000000, - .spdif = 0x08000000, - .mask = 0x0d000000, - }, - }, - [SIU_PORT_B] = { - .playback = { - .i2s = 0x00500000, - .pcm = 0x00400000, - .spdif = 0, /* impossible - turn off */ - .mask = 0x00500000, - }, - .capture = { - .i2s = 0x00050000, - .pcm = 0x00040000, - .spdif = 0, /* impossible - turn off */ - .mask = 0x00050000, - }, - }, -}; - -static void siu_dai_start(struct siu_port *port_info) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - - dev_dbg(port_info->pcm->card->dev, "%s\n", __func__); - - /* Issue software reset to siu */ - siu_write32(base + SIU_SRCTL, 0); - - /* Wait for the reset to take effect */ - udelay(1); - - port_info->stfifo = 0; - port_info->trdat = 0; - - /* portA, portB, SIU operate */ - siu_write32(base + SIU_SRCTL, 0x301); - - /* portA=256fs, portB=256fs */ - siu_write32(base + SIU_CKCTL, 0x40400000); - - /* portA's BRG does not divide SIUCKA */ - siu_write32(base + SIU_BRGASEL, 0); - siu_write32(base + SIU_BRRA, 0); - - /* portB's BRG divides SIUCKB by half */ - siu_write32(base + SIU_BRGBSEL, 1); - siu_write32(base + SIU_BRRB, 0); - - siu_write32(base + SIU_IFCTL, 0x44440000); - - /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */ - siu_write32(base + SIU_SFORM, 0x0c0c0000); - - /* - * Volume levels: looks like the DSP firmware implements volume controls - * differently from what's described in the datasheet - */ - siu_write32(base + SIU_SBDVCA, port_info->playback.volume); - siu_write32(base + SIU_SBDVCB, port_info->capture.volume); -} - -static void siu_dai_stop(struct siu_port *port_info) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - - /* SIU software reset */ - siu_write32(base + SIU_SRCTL, 0); -} - -static void siu_dai_spbAselect(struct siu_port *port_info) -{ - struct siu_info *info = siu_i2s_data; - struct siu_firmware *fw = &info->fw; - u32 *ydef = fw->yram0; - u32 idx; - - /* path A use */ - if (!info->port_id) - idx = 1; /* portA */ - else - idx = 2; /* portB */ - - ydef[0] = (fw->spbpar[idx].ab1a << 16) | - (fw->spbpar[idx].ab0a << 8) | - (fw->spbpar[idx].dir << 7) | 3; - ydef[1] = fw->yram0[1]; /* 0x03000300 */ - ydef[2] = (16 / 2) << 24; - ydef[3] = fw->yram0[3]; /* 0 */ - ydef[4] = fw->yram0[4]; /* 0 */ - ydef[7] = fw->spbpar[idx].event; - port_info->stfifo |= fw->spbpar[idx].stfifo; - port_info->trdat |= fw->spbpar[idx].trdat; -} - -static void siu_dai_spbBselect(struct siu_port *port_info) -{ - struct siu_info *info = siu_i2s_data; - struct siu_firmware *fw = &info->fw; - u32 *ydef = fw->yram0; - u32 idx; - - /* path B use */ - if (!info->port_id) - idx = 7; /* portA */ - else - idx = 8; /* portB */ - - ydef[5] = (fw->spbpar[idx].ab1a << 16) | - (fw->spbpar[idx].ab0a << 8) | 1; - ydef[6] = fw->spbpar[idx].event; - port_info->stfifo |= fw->spbpar[idx].stfifo; - port_info->trdat |= fw->spbpar[idx].trdat; -} - -static void siu_dai_open(struct siu_stream *siu_stream) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - u32 srctl, ifctl; - - srctl = siu_read32(base + SIU_SRCTL); - ifctl = siu_read32(base + SIU_IFCTL); - - switch (info->port_id) { - case SIU_PORT_A: - /* portA operates */ - srctl |= 0x200; - ifctl &= ~0xc2; - break; - case SIU_PORT_B: - /* portB operates */ - srctl |= 0x100; - ifctl &= ~0x31; - break; - } - - siu_write32(base + SIU_SRCTL, srctl); - /* Unmute and configure portA */ - siu_write32(base + SIU_IFCTL, ifctl); -} - -/* - * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower - * packing is supported - */ -static void siu_dai_pcmdatapack(struct siu_stream *siu_stream) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - u32 dpak; - - dpak = siu_read32(base + SIU_DPAK); - - switch (info->port_id) { - case SIU_PORT_A: - dpak &= ~0xc0000000; - break; - case SIU_PORT_B: - dpak &= ~0x00c00000; - break; - } - - siu_write32(base + SIU_DPAK, dpak); -} - -static int siu_dai_spbstart(struct siu_port *port_info) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - struct siu_firmware *fw = &info->fw; - u32 *ydef = fw->yram0; - int cnt; - u32 __iomem *add; - u32 *ptr; - - /* Load SPB Program in PRAM */ - ptr = fw->pram0; - add = info->pram; - for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++) - siu_write32(add, *ptr); - - ptr = fw->pram1; - add = info->pram + (0x0100 / sizeof(u32)); - for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++) - siu_write32(add, *ptr); - - /* XRAM initialization */ - add = info->xram; - for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++) - siu_write32(add, 0); - - /* YRAM variable area initialization */ - add = info->yram; - for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++) - siu_write32(add, ydef[cnt]); - - /* YRAM FIR coefficient area initialization */ - add = info->yram + (0x0200 / sizeof(u32)); - for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++) - siu_write32(add, fw->yram_fir_coeff[cnt]); - - /* YRAM IIR coefficient area initialization */ - add = info->yram + (0x0600 / sizeof(u32)); - for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++) - siu_write32(add, 0); - - siu_write32(base + SIU_TRDAT, port_info->trdat); - port_info->trdat = 0x0; - - - /* SPB start condition: software */ - siu_write32(base + SIU_SBACTIV, 0); - /* Start SPB */ - siu_write32(base + SIU_SBCTL, 0xc0000000); - /* Wait for program to halt */ - cnt = 0x10000; - while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000) - cpu_relax(); - - if (!cnt) - return -EBUSY; - - /* SPB program start address setting */ - siu_write32(base + SIU_SBPSET, 0x00400000); - /* SPB hardware start(FIFOCTL source) */ - siu_write32(base + SIU_SBACTIV, 0xc0000000); - - return 0; -} - -static void siu_dai_spbstop(struct siu_port *port_info) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - - siu_write32(base + SIU_SBACTIV, 0); - /* SPB stop */ - siu_write32(base + SIU_SBCTL, 0); - - port_info->stfifo = 0; -} - -/* API functions */ - -/* Playback and capture hardware properties are identical */ -static const struct snd_pcm_hardware siu_dai_pcm_hw = { - .info = SNDRV_PCM_INFO_INTERLEAVED, - .formats = SNDRV_PCM_FMTBIT_S16, - .rates = SNDRV_PCM_RATE_8000_48000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = SIU_BUFFER_BYTES_MAX, - .period_bytes_min = SIU_PERIOD_BYTES_MIN, - .period_bytes_max = SIU_PERIOD_BYTES_MAX, - .periods_min = SIU_PERIODS_MIN, - .periods_max = SIU_PERIODS_MAX, -}; - -static int siu_dai_info_volume(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_info *uinfo) -{ - struct siu_port *port_info = snd_kcontrol_chip(kctrl); - - dev_dbg(port_info->pcm->card->dev, "%s\n", __func__); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = SIU_MAX_VOLUME; - - return 0; -} - -static int siu_dai_get_volume(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_value *ucontrol) -{ - struct siu_port *port_info = snd_kcontrol_chip(kctrl); - struct device *dev = port_info->pcm->card->dev; - u32 vol; - - dev_dbg(dev, "%s\n", __func__); - - switch (kctrl->private_value) { - case VOLUME_PLAYBACK: - /* Playback is always on port 0 */ - vol = port_info->playback.volume; - ucontrol->value.integer.value[0] = vol & 0xffff; - ucontrol->value.integer.value[1] = vol >> 16 & 0xffff; - break; - case VOLUME_CAPTURE: - /* Capture is always on port 1 */ - vol = port_info->capture.volume; - ucontrol->value.integer.value[0] = vol & 0xffff; - ucontrol->value.integer.value[1] = vol >> 16 & 0xffff; - break; - default: - dev_err(dev, "%s() invalid private_value=%ld\n", - __func__, kctrl->private_value); - return -EINVAL; - } - - return 0; -} - -static int siu_dai_put_volume(struct snd_kcontrol *kctrl, - struct snd_ctl_elem_value *ucontrol) -{ - struct siu_port *port_info = snd_kcontrol_chip(kctrl); - struct device *dev = port_info->pcm->card->dev; - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - u32 new_vol; - u32 cur_vol; - - dev_dbg(dev, "%s\n", __func__); - - if (ucontrol->value.integer.value[0] < 0 || - ucontrol->value.integer.value[0] > SIU_MAX_VOLUME || - ucontrol->value.integer.value[1] < 0 || - ucontrol->value.integer.value[1] > SIU_MAX_VOLUME) - return -EINVAL; - - new_vol = ucontrol->value.integer.value[0] | - ucontrol->value.integer.value[1] << 16; - - /* See comment above - DSP firmware implementation */ - switch (kctrl->private_value) { - case VOLUME_PLAYBACK: - /* Playback is always on port 0 */ - cur_vol = port_info->playback.volume; - siu_write32(base + SIU_SBDVCA, new_vol); - port_info->playback.volume = new_vol; - break; - case VOLUME_CAPTURE: - /* Capture is always on port 1 */ - cur_vol = port_info->capture.volume; - siu_write32(base + SIU_SBDVCB, new_vol); - port_info->capture.volume = new_vol; - break; - default: - dev_err(dev, "%s() invalid private_value=%ld\n", - __func__, kctrl->private_value); - return -EINVAL; - } - - if (cur_vol != new_vol) - return 1; - - return 0; -} - -static const struct snd_kcontrol_new playback_controls = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .index = 0, - .info = siu_dai_info_volume, - .get = siu_dai_get_volume, - .put = siu_dai_put_volume, - .private_value = VOLUME_PLAYBACK, -}; - -static const struct snd_kcontrol_new capture_controls = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Capture Volume", - .index = 0, - .info = siu_dai_info_volume, - .get = siu_dai_get_volume, - .put = siu_dai_put_volume, - .private_value = VOLUME_CAPTURE, -}; - -int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card) -{ - struct device *dev = card->dev; - struct snd_kcontrol *kctrl; - int ret; - - *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL); - if (!*port_info) - return -ENOMEM; - - dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info); - - (*port_info)->playback.volume = DFLT_VOLUME_LEVEL; - (*port_info)->capture.volume = DFLT_VOLUME_LEVEL; - - /* - * Add mixer support. The SPB is used to change the volume. Both - * ports use the same SPB. Therefore, we only register one - * control instance since it will be used by both channels. - * In error case we continue without controls. - */ - kctrl = snd_ctl_new1(&playback_controls, *port_info); - ret = snd_ctl_add(card, kctrl); - if (ret < 0) - dev_err(dev, - "failed to add playback controls %p port=%d err=%d\n", - kctrl, port, ret); - - kctrl = snd_ctl_new1(&capture_controls, *port_info); - ret = snd_ctl_add(card, kctrl); - if (ret < 0) - dev_err(dev, - "failed to add capture controls %p port=%d err=%d\n", - kctrl, port, ret); - - return 0; -} - -void siu_free_port(struct siu_port *port_info) -{ - kfree(port_info); -} - -static int siu_dai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct siu_info *info = snd_soc_dai_get_drvdata(dai); - struct snd_pcm_runtime *rt = substream->runtime; - struct siu_port *port_info = siu_port_info(substream); - int ret; - - dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__, - info->port_id, port_info); - - snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw); - - ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS); - if (unlikely(ret < 0)) - return ret; - - siu_dai_start(port_info); - - return 0; -} - -static void siu_dai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct siu_info *info = snd_soc_dai_get_drvdata(dai); - struct siu_port *port_info = siu_port_info(substream); - - dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__, - info->port_id, port_info); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - port_info->play_cap &= ~PLAYBACK_ENABLED; - else - port_info->play_cap &= ~CAPTURE_ENABLED; - - /* Stop the siu if the other stream is not using it */ - if (!port_info->play_cap) { - /* during stmread or stmwrite ? */ - if (WARN_ON(port_info->playback.rw_flg || port_info->capture.rw_flg)) - return; - siu_dai_spbstop(port_info); - siu_dai_stop(port_info); - } -} - -/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */ -static int siu_dai_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct siu_info *info = snd_soc_dai_get_drvdata(dai); - struct snd_pcm_runtime *rt = substream->runtime; - struct siu_port *port_info = siu_port_info(substream); - struct siu_stream *siu_stream; - int self, ret; - - dev_dbg(substream->pcm->card->dev, - "%s: port %d, active streams %lx, %d channels\n", - __func__, info->port_id, port_info->play_cap, rt->channels); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - self = PLAYBACK_ENABLED; - siu_stream = &port_info->playback; - } else { - self = CAPTURE_ENABLED; - siu_stream = &port_info->capture; - } - - /* Set up the siu if not already done */ - if (!port_info->play_cap) { - siu_stream->rw_flg = 0; /* stream-data transfer flag */ - - siu_dai_spbAselect(port_info); - siu_dai_spbBselect(port_info); - - siu_dai_open(siu_stream); - - siu_dai_pcmdatapack(siu_stream); - - ret = siu_dai_spbstart(port_info); - if (ret < 0) - goto fail; - } else { - ret = 0; - } - - port_info->play_cap |= self; - -fail: - return ret; -} - -/* - * SIU can set bus format to I2S / PCM / SPDIF independently for playback and - * capture, however, the current API sets the bus format globally for a DAI. - */ -static int siu_dai_set_fmt(struct snd_soc_dai *dai, - unsigned int fmt) -{ - struct siu_info *info = snd_soc_dai_get_drvdata(dai); - u32 __iomem *base = info->reg; - u32 ifctl; - - dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n", - __func__, fmt, info->port_id); - - if (info->port_id < 0) - return -ENODEV; - - /* Here select between I2S / PCM / SPDIF */ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - ifctl = siu_flags[info->port_id].playback.i2s | - siu_flags[info->port_id].capture.i2s; - break; - case SND_SOC_DAIFMT_LEFT_J: - ifctl = siu_flags[info->port_id].playback.pcm | - siu_flags[info->port_id].capture.pcm; - break; - /* SPDIF disabled - see comment at the top */ - default: - return -EINVAL; - } - - ifctl |= ~(siu_flags[info->port_id].playback.mask | - siu_flags[info->port_id].capture.mask) & - siu_read32(base + SIU_IFCTL); - siu_write32(base + SIU_IFCTL, ifctl); - - return 0; -} - -static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir) -{ - struct clk *siu_clk, *parent_clk; - char *siu_name, *parent_name; - int ret; - - if (dir != SND_SOC_CLOCK_IN) - return -EINVAL; - - dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id); - - switch (clk_id) { - case SIU_CLKA_PLL: - siu_name = "siua_clk"; - parent_name = "pll_clk"; - break; - case SIU_CLKA_EXT: - siu_name = "siua_clk"; - parent_name = "siumcka_clk"; - break; - case SIU_CLKB_PLL: - siu_name = "siub_clk"; - parent_name = "pll_clk"; - break; - case SIU_CLKB_EXT: - siu_name = "siub_clk"; - parent_name = "siumckb_clk"; - break; - default: - return -EINVAL; - } - - siu_clk = clk_get(dai->dev, siu_name); - if (IS_ERR(siu_clk)) { - dev_err(dai->dev, "%s: cannot get a SIU clock: %ld\n", __func__, - PTR_ERR(siu_clk)); - return PTR_ERR(siu_clk); - } - - parent_clk = clk_get(dai->dev, parent_name); - if (IS_ERR(parent_clk)) { - ret = PTR_ERR(parent_clk); - dev_err(dai->dev, "cannot get a SIU clock parent: %d\n", ret); - goto epclkget; - } - - ret = clk_set_parent(siu_clk, parent_clk); - if (ret < 0) { - dev_err(dai->dev, "cannot reparent the SIU clock: %d\n", ret); - goto eclksetp; - } - - ret = clk_set_rate(siu_clk, freq); - if (ret < 0) - dev_err(dai->dev, "cannot set SIU clock rate: %d\n", ret); - - /* TODO: when clkdev gets reference counting we'll move these to siu_dai_shutdown() */ -eclksetp: - clk_put(parent_clk); -epclkget: - clk_put(siu_clk); - - return ret; -} - -static const struct snd_soc_dai_ops siu_dai_ops = { - .startup = siu_dai_startup, - .shutdown = siu_dai_shutdown, - .prepare = siu_dai_prepare, - .set_sysclk = siu_dai_set_sysclk, - .set_fmt = siu_dai_set_fmt, -}; - -static struct snd_soc_dai_driver siu_i2s_dai = { - .name = "siu-i2s-dai", - .playback = { - .channels_min = 2, - .channels_max = 2, - .formats = SNDRV_PCM_FMTBIT_S16, - .rates = SNDRV_PCM_RATE_8000_48000, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .formats = SNDRV_PCM_FMTBIT_S16, - .rates = SNDRV_PCM_RATE_8000_48000, - }, - .ops = &siu_dai_ops, -}; - -static int siu_probe(struct platform_device *pdev) -{ - const struct firmware *fw_entry; - struct resource *res, *region; - struct siu_info *info; - int ret; - - info = devm_kmalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - siu_i2s_data = info; - info->dev = &pdev->dev; - - ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev); - if (ret) - return ret; - - /* - * Loaded firmware is "const" - read only, but we have to modify it in - * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect() - */ - memcpy(&info->fw, fw_entry->data, fw_entry->size); - - release_firmware(fw_entry); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - region = devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name); - if (!region) { - dev_err(&pdev->dev, "SIU region already claimed\n"); - return -EBUSY; - } - - info->pram = devm_ioremap(&pdev->dev, res->start, PRAM_SIZE); - if (!info->pram) - return -ENOMEM; - info->xram = devm_ioremap(&pdev->dev, res->start + XRAM_OFFSET, - XRAM_SIZE); - if (!info->xram) - return -ENOMEM; - info->yram = devm_ioremap(&pdev->dev, res->start + YRAM_OFFSET, - YRAM_SIZE); - if (!info->yram) - return -ENOMEM; - info->reg = devm_ioremap(&pdev->dev, res->start + REG_OFFSET, - resource_size(res) - REG_OFFSET); - if (!info->reg) - return -ENOMEM; - - dev_set_drvdata(&pdev->dev, info); - - /* register using ARRAY version so we can keep dai name */ - ret = devm_snd_soc_register_component(&pdev->dev, &siu_component, - &siu_i2s_dai, 1); - if (ret < 0) - return ret; - - pm_runtime_enable(&pdev->dev); - - return 0; -} - -static void siu_remove(struct platform_device *pdev) -{ - pm_runtime_disable(&pdev->dev); -} - -static struct platform_driver siu_driver = { - .driver = { - .name = "siu-pcm-audio", - }, - .probe = siu_probe, - .remove = siu_remove, -}; - -module_platform_driver(siu_driver); - -MODULE_AUTHOR("Carlos Munoz "); -MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver"); -MODULE_LICENSE("GPL"); - -MODULE_FIRMWARE("siu_spb.bin"); diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c deleted file mode 100644 index f15ff36e793455..00000000000000 --- a/sound/soc/sh/siu_pcm.c +++ /dev/null @@ -1,553 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral. -// -// Copyright (C) 2009-2010 Guennadi Liakhovetski -// Copyright (C) 2006 Carlos Munoz - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "siu.h" - -#define DRV_NAME "siu-i2s" -#define GET_MAX_PERIODS(buf_bytes, period_bytes) \ - ((buf_bytes) / (period_bytes)) -#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \ - ((buf_addr) + ((period_num) * (period_bytes))) - -#define RWF_STM_RD 0x01 /* Read in progress */ -#define RWF_STM_WT 0x02 /* Write in progress */ - -struct siu_port *siu_ports[SIU_PORT_NUM]; - -/* transfersize is number of u32 dma transfers per period */ -static int siu_pcm_stmwrite_stop(struct siu_port *port_info) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - struct siu_stream *siu_stream = &port_info->playback; - u32 stfifo; - - if (!siu_stream->rw_flg) - return -EPERM; - - /* output FIFO disable */ - stfifo = siu_read32(base + SIU_STFIFO); - siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18); - pr_debug("%s: STFIFO %x -> %x\n", __func__, - stfifo, stfifo & ~0x0c180c18); - - /* during stmwrite clear */ - siu_stream->rw_flg = 0; - - return 0; -} - -static int siu_pcm_stmwrite_start(struct siu_port *port_info) -{ - struct siu_stream *siu_stream = &port_info->playback; - - if (siu_stream->rw_flg) - return -EPERM; - - /* Current period in buffer */ - port_info->playback.cur_period = 0; - - /* during stmwrite flag set */ - siu_stream->rw_flg = RWF_STM_WT; - - /* DMA transfer start */ - queue_work(system_highpri_wq, &siu_stream->work); - - return 0; -} - -static void siu_dma_tx_complete(void *arg) -{ - struct siu_stream *siu_stream = arg; - - if (!siu_stream->rw_flg) - return; - - /* Update completed period count */ - if (++siu_stream->cur_period >= - GET_MAX_PERIODS(siu_stream->buf_bytes, - siu_stream->period_bytes)) - siu_stream->cur_period = 0; - - pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n", - __func__, siu_stream->cur_period, - siu_stream->cur_period * siu_stream->period_bytes, - siu_stream->buf_bytes, siu_stream->cookie); - - queue_work(system_highpri_wq, &siu_stream->work); - - /* Notify alsa: a period is done */ - snd_pcm_period_elapsed(siu_stream->substream); -} - -static int siu_pcm_wr_set(struct siu_port *port_info, - dma_addr_t buff, u32 size) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - struct siu_stream *siu_stream = &port_info->playback; - struct snd_pcm_substream *substream = siu_stream->substream; - struct device *dev = substream->pcm->card->dev; - struct dma_async_tx_descriptor *desc; - dma_cookie_t cookie; - struct scatterlist sg; - u32 stfifo; - - sg_init_table(&sg, 1); - sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)), - size, offset_in_page(buff)); - sg_dma_len(&sg) = size; - sg_dma_address(&sg) = buff; - - desc = dmaengine_prep_slave_sg(siu_stream->chan, - &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_err(dev, "Failed to allocate a dma descriptor\n"); - return -ENOMEM; - } - - desc->callback = siu_dma_tx_complete; - desc->callback_param = siu_stream; - cookie = dmaengine_submit(desc); - if (cookie < 0) { - dev_err(dev, "Failed to submit a dma transfer\n"); - return cookie; - } - - siu_stream->tx_desc = desc; - siu_stream->cookie = cookie; - - dma_async_issue_pending(siu_stream->chan); - - /* only output FIFO enable */ - stfifo = siu_read32(base + SIU_STFIFO); - siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18)); - dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, - stfifo, stfifo | (port_info->stfifo & 0x0c180c18)); - - return 0; -} - -static int siu_pcm_rd_set(struct siu_port *port_info, - dma_addr_t buff, size_t size) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - struct siu_stream *siu_stream = &port_info->capture; - struct snd_pcm_substream *substream = siu_stream->substream; - struct device *dev = substream->pcm->card->dev; - struct dma_async_tx_descriptor *desc; - dma_cookie_t cookie; - struct scatterlist sg; - u32 stfifo; - - dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff); - - sg_init_table(&sg, 1); - sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)), - size, offset_in_page(buff)); - sg_dma_len(&sg) = size; - sg_dma_address(&sg) = buff; - - desc = dmaengine_prep_slave_sg(siu_stream->chan, - &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - dev_err(dev, "Failed to allocate dma descriptor\n"); - return -ENOMEM; - } - - desc->callback = siu_dma_tx_complete; - desc->callback_param = siu_stream; - cookie = dmaengine_submit(desc); - if (cookie < 0) { - dev_err(dev, "Failed to submit dma descriptor\n"); - return cookie; - } - - siu_stream->tx_desc = desc; - siu_stream->cookie = cookie; - - dma_async_issue_pending(siu_stream->chan); - - /* only input FIFO enable */ - stfifo = siu_read32(base + SIU_STFIFO); - siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) | - (port_info->stfifo & 0x13071307)); - dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, - stfifo, stfifo | (port_info->stfifo & 0x13071307)); - - return 0; -} - -static void siu_io_work(struct work_struct *work) -{ - struct siu_stream *siu_stream = container_of(work, struct siu_stream, - work); - struct snd_pcm_substream *substream = siu_stream->substream; - struct device *dev = substream->pcm->card->dev; - struct snd_pcm_runtime *rt = substream->runtime; - struct siu_port *port_info = siu_port_info(substream); - - dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg); - - if (!siu_stream->rw_flg) { - dev_dbg(dev, "%s: stream inactive\n", __func__); - return; - } - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - dma_addr_t buff; - size_t count; - - buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, - siu_stream->cur_period, - siu_stream->period_bytes); - count = siu_stream->period_bytes; - - /* DMA transfer start */ - siu_pcm_rd_set(port_info, buff, count); - } else { - siu_pcm_wr_set(port_info, - (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, - siu_stream->cur_period, - siu_stream->period_bytes), - siu_stream->period_bytes); - } -} - -/* Capture */ -static int siu_pcm_stmread_start(struct siu_port *port_info) -{ - struct siu_stream *siu_stream = &port_info->capture; - - if (siu_stream->xfer_cnt > 0x1000000) - return -EINVAL; - if (siu_stream->rw_flg) - return -EPERM; - - /* Current period in buffer */ - siu_stream->cur_period = 0; - - /* during stmread flag set */ - siu_stream->rw_flg = RWF_STM_RD; - - queue_work(system_highpri_wq, &siu_stream->work); - - return 0; -} - -static int siu_pcm_stmread_stop(struct siu_port *port_info) -{ - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - struct siu_stream *siu_stream = &port_info->capture; - struct device *dev = siu_stream->substream->pcm->card->dev; - u32 stfifo; - - if (!siu_stream->rw_flg) - return -EPERM; - - /* input FIFO disable */ - stfifo = siu_read32(base + SIU_STFIFO); - siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307); - dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__, - stfifo, stfifo & ~0x13071307); - - /* during stmread flag clear */ - siu_stream->rw_flg = 0; - - return 0; -} - -static bool filter(struct dma_chan *chan, void *secondary) -{ - struct sh_dmae_slave *param = secondary; - - pr_debug("%s: secondary ID %d\n", __func__, param->shdma_slave.slave_id); - - chan->private = ¶m->shdma_slave; - return true; -} - -static int siu_pcm_open(struct snd_soc_component *component, - struct snd_pcm_substream *ss) -{ - /* Playback / Capture */ - struct siu_platform *pdata = component->dev->platform_data; - struct siu_info *info = siu_i2s_data; - struct siu_port *port_info = siu_port_info(ss); - struct siu_stream *siu_stream; - u32 port = info->port_id; - struct device *dev = ss->pcm->card->dev; - dma_cap_mask_t mask; - struct sh_dmae_slave *param; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info); - - if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) { - siu_stream = &port_info->playback; - param = &siu_stream->param; - param->shdma_slave.slave_id = port ? pdata->dma_slave_tx_b : - pdata->dma_slave_tx_a; - } else { - siu_stream = &port_info->capture; - param = &siu_stream->param; - param->shdma_slave.slave_id = port ? pdata->dma_slave_rx_b : - pdata->dma_slave_rx_a; - } - - /* Get DMA channel */ - siu_stream->chan = dma_request_channel(mask, filter, param); - if (!siu_stream->chan) { - dev_err(dev, "DMA channel allocation failed!\n"); - return -EBUSY; - } - - siu_stream->substream = ss; - - return 0; -} - -static int siu_pcm_close(struct snd_soc_component *component, - struct snd_pcm_substream *ss) -{ - struct siu_info *info = siu_i2s_data; - struct device *dev = ss->pcm->card->dev; - struct siu_port *port_info = siu_port_info(ss); - struct siu_stream *siu_stream; - - dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id); - - if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) - siu_stream = &port_info->playback; - else - siu_stream = &port_info->capture; - - dma_release_channel(siu_stream->chan); - siu_stream->chan = NULL; - - siu_stream->substream = NULL; - - return 0; -} - -static int siu_pcm_prepare(struct snd_soc_component *component, - struct snd_pcm_substream *ss) -{ - struct siu_info *info = siu_i2s_data; - struct siu_port *port_info = siu_port_info(ss); - struct device *dev = ss->pcm->card->dev; - struct snd_pcm_runtime *rt; - struct siu_stream *siu_stream; - snd_pcm_sframes_t xfer_cnt; - - if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) - siu_stream = &port_info->playback; - else - siu_stream = &port_info->capture; - - rt = siu_stream->substream->runtime; - - siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss); - siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss); - - dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__, - info->port_id, rt->channels, siu_stream->period_bytes); - - /* We only support buffers that are multiples of the period */ - if (siu_stream->buf_bytes % siu_stream->period_bytes) { - dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n", - __func__, siu_stream->buf_bytes, - siu_stream->period_bytes); - return -EINVAL; - } - - xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes); - if (!xfer_cnt || xfer_cnt > 0x1000000) - return -EINVAL; - - siu_stream->format = rt->format; - siu_stream->xfer_cnt = xfer_cnt; - - dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d " - "format=%d channels=%d xfer_cnt=%d\n", info->port_id, - (unsigned long)rt->dma_addr, siu_stream->buf_bytes, - siu_stream->period_bytes, - siu_stream->format, rt->channels, (int)xfer_cnt); - - return 0; -} - -static int siu_pcm_trigger(struct snd_soc_component *component, - struct snd_pcm_substream *ss, int cmd) -{ - struct siu_info *info = siu_i2s_data; - struct device *dev = ss->pcm->card->dev; - struct siu_port *port_info = siu_port_info(ss); - int ret; - - dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__, - info->port_id, port_info, cmd); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = siu_pcm_stmwrite_start(port_info); - else - ret = siu_pcm_stmread_start(port_info); - - if (ret < 0) - dev_warn(dev, "%s: start failed on port=%d\n", - __func__, info->port_id); - - break; - case SNDRV_PCM_TRIGGER_STOP: - if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) - siu_pcm_stmwrite_stop(port_info); - else - siu_pcm_stmread_stop(port_info); - ret = 0; - - break; - default: - dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd); - ret = -EINVAL; - } - - return ret; -} - -/* - * So far only resolution of one period is supported, subject to extending the - * dmangine API - */ -static snd_pcm_uframes_t -siu_pcm_pointer_dma(struct snd_soc_component *component, - struct snd_pcm_substream *ss) -{ - struct device *dev = ss->pcm->card->dev; - struct siu_info *info = siu_i2s_data; - u32 __iomem *base = info->reg; - struct siu_port *port_info = siu_port_info(ss); - struct snd_pcm_runtime *rt = ss->runtime; - size_t ptr; - struct siu_stream *siu_stream; - - if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) - siu_stream = &port_info->playback; - else - siu_stream = &port_info->capture; - - /* - * ptr is the offset into the buffer where the dma is currently at. We - * check if the dma buffer has just wrapped. - */ - ptr = PERIOD_OFFSET(rt->dma_addr, - siu_stream->cur_period, - siu_stream->period_bytes) - rt->dma_addr; - - dev_dbg(dev, - "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n", - __func__, info->port_id, siu_read32(base + SIU_EVNTC), - siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes, - siu_stream->cookie); - - if (ptr >= siu_stream->buf_bytes) - ptr = 0; - - return bytes_to_frames(ss->runtime, ptr); -} - -static int siu_pcm_new(struct snd_soc_component *component, - struct snd_soc_pcm_runtime *rtd) -{ - /* card->dev == socdev->dev, see snd_soc_new_pcms() */ - struct snd_card *card = rtd->card->snd_card; - struct snd_pcm *pcm = rtd->pcm; - struct siu_info *info = siu_i2s_data; - struct platform_device *pdev = to_platform_device(card->dev); - int ret; - int i; - - /* pdev->id selects between SIUA and SIUB */ - if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM) - return -EINVAL; - - info->port_id = pdev->id; - - /* - * While the siu has 2 ports, only one port can be on at a time (only 1 - * SPB). So far all the boards using the siu had only one of the ports - * wired to a codec. To simplify things, we only register one port with - * alsa. In case both ports are needed, it should be changed here - */ - for (i = pdev->id; i < pdev->id + 1; i++) { - struct siu_port **port_info = &siu_ports[i]; - - ret = siu_init_port(i, port_info, card); - if (ret < 0) - return ret; - - snd_pcm_set_managed_buffer_all(pcm, - SNDRV_DMA_TYPE_DEV, card->dev, - SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX); - - (*port_info)->pcm = pcm; - - /* IO works */ - INIT_WORK(&(*port_info)->playback.work, siu_io_work); - INIT_WORK(&(*port_info)->capture.work, siu_io_work); - } - - dev_info(card->dev, "SuperH SIU driver initialized.\n"); - return 0; -} - -static void siu_pcm_free(struct snd_soc_component *component, - struct snd_pcm *pcm) -{ - struct platform_device *pdev = to_platform_device(pcm->card->dev); - struct siu_port *port_info = siu_ports[pdev->id]; - - cancel_work_sync(&port_info->capture.work); - cancel_work_sync(&port_info->playback.work); - - siu_free_port(port_info); - - dev_dbg(pcm->card->dev, "%s\n", __func__); -} - -const struct snd_soc_component_driver siu_component = { - .name = DRV_NAME, - .open = siu_pcm_open, - .close = siu_pcm_close, - .prepare = siu_pcm_prepare, - .trigger = siu_pcm_trigger, - .pointer = siu_pcm_pointer_dma, - .pcm_construct = siu_pcm_new, - .pcm_destruct = siu_pcm_free, - .legacy_dai_naming = 1, -}; -EXPORT_SYMBOL_GPL(siu_component); diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c deleted file mode 100644 index 96cf523c227343..00000000000000 --- a/sound/soc/sh/ssi.c +++ /dev/null @@ -1,403 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// Serial Sound Interface (I2S) support for SH7760/SH7780 -// -// Copyright (c) 2007 Manuel Lauss -// -// dont forget to set IPSEL/OMSEL register bits (in your board code) to -// enable SSI output pins! - -/* - * LIMITATIONS: - * The SSI unit has only one physical data line, so full duplex is - * impossible. This can be remedied on the SH7760 by using the - * other SSI unit for recording; however the SH7780 has only 1 SSI - * unit, and its pins are shared with the AC97 unit, among others. - * - * FEATURES: - * The SSI features "compressed mode": in this mode it continuously - * streams PCM data over the I2S lines and uses LRCK as a handshake - * signal. Can be used to send compressed data (AC3/DTS) to a DSP. - * The number of bits sent over the wire in a frame can be adjusted - * and can be independent from the actual sample bit depth. This is - * useful to support TDM mode codecs like the AD1939 which have a - * fixed TDM slot size, regardless of sample resolution. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define SSICR 0x00 -#define SSISR 0x04 - -#define CR_DMAEN (1 << 28) -#define CR_CHNL_SHIFT 22 -#define CR_CHNL_MASK (3 << CR_CHNL_SHIFT) -#define CR_DWL_SHIFT 19 -#define CR_DWL_MASK (7 << CR_DWL_SHIFT) -#define CR_SWL_SHIFT 16 -#define CR_SWL_MASK (7 << CR_SWL_SHIFT) -#define CR_SCK_MASTER (1 << 15) /* bitclock master bit */ -#define CR_SWS_MASTER (1 << 14) /* wordselect master bit */ -#define CR_SCKP (1 << 13) /* I2Sclock polarity */ -#define CR_SWSP (1 << 12) /* LRCK polarity */ -#define CR_SPDP (1 << 11) -#define CR_SDTA (1 << 10) /* i2s alignment (msb/lsb) */ -#define CR_PDTA (1 << 9) /* fifo data alignment */ -#define CR_DEL (1 << 8) /* delay data by 1 i2sclk */ -#define CR_BREN (1 << 7) /* clock gating in burst mode */ -#define CR_CKDIV_SHIFT 4 -#define CR_CKDIV_MASK (7 << CR_CKDIV_SHIFT) /* bitclock divider */ -#define CR_MUTE (1 << 3) /* SSI mute */ -#define CR_CPEN (1 << 2) /* compressed mode */ -#define CR_TRMD (1 << 1) /* transmit/receive select */ -#define CR_EN (1 << 0) /* enable SSI */ - -#define SSIREG(reg) (*(unsigned long *)(ssi->mmio + (reg))) - -struct ssi_priv { - unsigned long mmio; - unsigned long sysclk; - int inuse; -} ssi_cpu_data[] = { -#if defined(CONFIG_CPU_SUBTYPE_SH7760) - { - .mmio = 0xFE680000, - }, - { - .mmio = 0xFE690000, - }, -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) - { - .mmio = 0xFFE70000, - }, -#else -#error "Unsupported SuperH SoC" -#endif -}; - -/* - * track usage of the SSI; it is simplex-only so prevent attempts of - * concurrent playback + capture. FIXME: any locking required? - */ -static int ssi_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; - if (ssi->inuse) { - pr_debug("ssi: already in use!\n"); - return -EBUSY; - } else - ssi->inuse = 1; - return 0; -} - -static void ssi_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; - - ssi->inuse = 0; -} - -static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - SSIREG(SSICR) |= CR_DMAEN | CR_EN; - break; - case SNDRV_PCM_TRIGGER_STOP: - SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int ssi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; - unsigned long ssicr = SSIREG(SSICR); - unsigned int bits, channels, swl, recv, i; - - channels = params_channels(params); - bits = params->msbits; - recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1; - - pr_debug("ssi_hw_params() enter\nssicr was %08lx\n", ssicr); - pr_debug("bits: %u channels: %u\n", bits, channels); - - ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA | - CR_SWL_MASK); - - /* direction (send/receive) */ - if (!recv) - ssicr |= CR_TRMD; /* transmit */ - - /* channels */ - if ((channels < 2) || (channels > 8) || (channels & 1)) { - pr_debug("ssi: invalid number of channels\n"); - return -EINVAL; - } - ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT; - - /* DATA WORD LENGTH (DWL): databits in audio sample */ - i = 0; - switch (bits) { - case 32: ++i; - case 24: ++i; - case 22: ++i; - case 20: ++i; - case 18: ++i; - case 16: ++i; - ssicr |= i << CR_DWL_SHIFT; - case 8: break; - default: - pr_debug("ssi: invalid sample width\n"); - return -EINVAL; - } - - /* - * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S - * wires. This is usually bits_per_sample x channels/2; i.e. in - * Stereo mode the SWL equals DWL. SWL can be bigger than the - * product of (channels_per_slot x samplebits), e.g. for codecs - * like the AD1939 which only accept 32bit wide TDM slots. For - * "standard" I2S operation we set SWL = chans / 2 * DWL here. - * Waiting for ASoC to get TDM support ;-) - */ - if ((bits > 16) && (bits <= 24)) { - bits = 24; /* these are padded by the SSI */ - /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */ - } - i = 0; - swl = (bits * channels) / 2; - switch (swl) { - case 256: ++i; - case 128: ++i; - case 64: ++i; - case 48: ++i; - case 32: ++i; - case 16: ++i; - ssicr |= i << CR_SWL_SHIFT; - case 8: break; - default: - pr_debug("ssi: invalid system word length computed\n"); - return -EINVAL; - } - - SSIREG(SSICR) = ssicr; - - pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr); - return 0; -} - -static int ssi_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, - unsigned int freq, int dir) -{ - struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id]; - - ssi->sysclk = freq; - - return 0; -} - -/* - * This divider is used to generate the SSI_SCK (I2S bitclock) from the - * clock at the HAC_BIT_CLK ("oversampling clock") pin. - */ -static int ssi_set_clkdiv(struct snd_soc_dai *dai, int did, int div) -{ - struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; - unsigned long ssicr; - int i; - - i = 0; - ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK; - switch (div) { - case 16: ++i; - case 8: ++i; - case 4: ++i; - case 2: ++i; - SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT); - case 1: break; - default: - pr_debug("ssi: invalid sck divider %d\n", div); - return -EINVAL; - } - - return 0; -} - -static int ssi_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct ssi_priv *ssi = &ssi_cpu_data[dai->id]; - unsigned long ssicr = SSIREG(SSICR); - - pr_debug("ssi_set_fmt()\nssicr was 0x%08lx\n", ssicr); - - ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP | - CR_SWS_MASTER | CR_SCK_MASTER); - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - break; - case SND_SOC_DAIFMT_RIGHT_J: - ssicr |= CR_DEL | CR_PDTA; - break; - case SND_SOC_DAIFMT_LEFT_J: - ssicr |= CR_DEL; - break; - default: - pr_debug("ssi: unsupported format\n"); - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { - case SND_SOC_DAIFMT_CONT: - break; - case SND_SOC_DAIFMT_GATED: - ssicr |= CR_BREN; - break; - } - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - ssicr |= CR_SCKP; /* sample data at low clkedge */ - break; - case SND_SOC_DAIFMT_NB_IF: - ssicr |= CR_SCKP | CR_SWSP; - break; - case SND_SOC_DAIFMT_IB_NF: - break; - case SND_SOC_DAIFMT_IB_IF: - ssicr |= CR_SWSP; /* word select starts low */ - break; - default: - pr_debug("ssi: invalid inversion\n"); - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_BC_FC: - break; - case SND_SOC_DAIFMT_BP_FC: - ssicr |= CR_SCK_MASTER; - break; - case SND_SOC_DAIFMT_BC_FP: - ssicr |= CR_SWS_MASTER; - break; - case SND_SOC_DAIFMT_BP_FP: - ssicr |= CR_SWS_MASTER | CR_SCK_MASTER; - break; - default: - pr_debug("ssi: invalid master/secondary configuration\n"); - return -EINVAL; - } - - SSIREG(SSICR) = ssicr; - pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr); - - return 0; -} - -/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in - * Master mode, so really this is board specific; the SSI can do any - * rate with the right bitclk and divider settings. - */ -#define SSI_RATES \ - SNDRV_PCM_RATE_8000_192000 - -/* the SSI can do 8-32 bit samples, with 8 possible channels */ -#define SSI_FMTS \ - (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE) - -static const struct snd_soc_dai_ops ssi_dai_ops = { - .startup = ssi_startup, - .shutdown = ssi_shutdown, - .trigger = ssi_trigger, - .hw_params = ssi_hw_params, - .set_sysclk = ssi_set_sysclk, - .set_clkdiv = ssi_set_clkdiv, - .set_fmt = ssi_set_fmt, -}; - -static struct snd_soc_dai_driver sh4_ssi_dai[] = { -{ - .name = "ssi-dai.0", - .playback = { - .rates = SSI_RATES, - .formats = SSI_FMTS, - .channels_min = 2, - .channels_max = 8, - }, - .capture = { - .rates = SSI_RATES, - .formats = SSI_FMTS, - .channels_min = 2, - .channels_max = 8, - }, - .ops = &ssi_dai_ops, -}, -#ifdef CONFIG_CPU_SUBTYPE_SH7760 -{ - .name = "ssi-dai.1", - .playback = { - .rates = SSI_RATES, - .formats = SSI_FMTS, - .channels_min = 2, - .channels_max = 8, - }, - .capture = { - .rates = SSI_RATES, - .formats = SSI_FMTS, - .channels_min = 2, - .channels_max = 8, - }, - .ops = &ssi_dai_ops, -}, -#endif -}; - -static const struct snd_soc_component_driver sh4_ssi_component = { - .name = "sh4-ssi", - .legacy_dai_naming = 1, -}; - -static int sh4_soc_dai_probe(struct platform_device *pdev) -{ - return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component, - sh4_ssi_dai, - ARRAY_SIZE(sh4_ssi_dai)); -} - -static struct platform_driver sh4_ssi_driver = { - .driver = { - .name = "sh4-ssi-dai", - }, - - .probe = sh4_soc_dai_probe, -}; - -module_platform_driver(sh4_ssi_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver"); -MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 6d693b2ad5a35b..270f9777942f02 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -131,8 +131,7 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); /* Check if all Slaves defined on the link can be found */ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, const struct snd_soc_acpi_link_adr *link, - struct sdw_extended_slave_id *ids, - int num_slaves) + struct sdw_peripherals *peripherals) { unsigned int part_id, link_id, unique_id, mfg_id, version; int i, j, k; @@ -146,22 +145,25 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, link_id = SDW_DISCO_LINK_ID(adr); version = SDW_VERSION(adr); - for (j = 0; j < num_slaves; j++) { + for (j = 0; j < peripherals->num_peripherals; j++) { + struct sdw_slave *peripheral = peripherals->array[j]; + /* find out how many identical parts were reported on that link */ - if (ids[j].link_id == link_id && - ids[j].id.part_id == part_id && - ids[j].id.mfg_id == mfg_id && - ids[j].id.sdw_version == version) + if (peripheral->bus->link_id == link_id && + peripheral->id.part_id == part_id && + peripheral->id.mfg_id == mfg_id && + peripheral->id.sdw_version == version) reported_part_count++; } - for (j = 0; j < num_slaves; j++) { + for (j = 0; j < peripherals->num_peripherals; j++) { + struct sdw_slave *peripheral = peripherals->array[j]; int expected_part_count = 0; - if (ids[j].link_id != link_id || - ids[j].id.part_id != part_id || - ids[j].id.mfg_id != mfg_id || - ids[j].id.sdw_version != version) + if (peripheral->bus->link_id != link_id || + peripheral->id.part_id != part_id || + peripheral->id.mfg_id != mfg_id || + peripheral->id.sdw_version != version) continue; /* find out how many identical parts are expected */ @@ -180,7 +182,7 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, */ unique_id = SDW_UNIQUE_ID(adr); if (reported_part_count == 1 || - ids[j].id.unique_id == unique_id) { + peripheral->id.unique_id == unique_id) { dev_dbg(dev, "found part_id %#x at link %d\n", part_id, link_id); break; } @@ -189,7 +191,7 @@ bool snd_soc_acpi_sdw_link_slaves_found(struct device *dev, part_id, reported_part_count, expected_part_count, link_id); } } - if (j == num_slaves) { + if (j == peripherals->num_peripherals) { dev_dbg(dev, "Slave part_id %#x not found\n", part_id); return false; } diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index b3d7bb91e29497..b67ef78f405c3b 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -58,7 +58,7 @@ static inline int soc_component_field_shift(struct snd_soc_component *component, * In such case, we can update these macros. */ #define soc_component_mark_push(component, substream, tgt) ((component)->mark_##tgt = substream) -#define soc_component_mark_pop(component, substream, tgt) ((component)->mark_##tgt = NULL) +#define soc_component_mark_pop(component, tgt) ((component)->mark_##tgt = NULL) #define soc_component_mark_match(component, substream, tgt) ((component)->mark_##tgt == substream) void snd_soc_component_set_aux(struct snd_soc_component *component, @@ -339,7 +339,7 @@ void snd_soc_component_module_put(struct snd_soc_component *component, module_put(component->dev->driver->owner); /* remove the mark from module */ - soc_component_mark_pop(component, mark, module); + soc_component_mark_pop(component, module); } int snd_soc_component_open(struct snd_soc_component *component, @@ -370,7 +370,7 @@ int snd_soc_component_close(struct snd_soc_component *component, ret = component->driver->close(component, substream); /* remove marked substream */ - soc_component_mark_pop(component, substream, open); + soc_component_mark_pop(component, open); return soc_component_ret(component, ret); } @@ -515,7 +515,7 @@ void snd_soc_component_compr_free(struct snd_soc_component *component, component->driver->compress_ops->free(component, cstream); /* remove marked substream */ - soc_component_mark_pop(component, cstream, compr_open); + soc_component_mark_pop(component, compr_open); } EXPORT_SYMBOL_GPL(snd_soc_component_compr_free); @@ -1210,7 +1210,7 @@ void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream, } /* remove marked substream */ - soc_component_mark_pop(component, substream, hw_params); + soc_component_mark_pop(component, hw_params); } } @@ -1254,7 +1254,7 @@ int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream, r = soc_component_trigger(component, substream, cmd); if (r < 0) ret = r; /* use last ret */ - soc_component_mark_pop(component, substream, trigger); + soc_component_mark_pop(component, trigger); } } @@ -1294,7 +1294,7 @@ void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd, pm_runtime_put_autosuspend(component->dev); /* remove marked stream */ - soc_component_mark_pop(component, stream, pm); + soc_component_mark_pop(component, pm); } } diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index e692aa3b8b22f8..563dc0767c177a 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -69,10 +69,10 @@ static int soc_compr_clean(struct snd_compr_stream *cstream, int rollback) snd_soc_dai_digital_mute(codec_dai, 1, stream); if (!snd_soc_dai_active(cpu_dai)) - cpu_dai->rate = 0; + cpu_dai->symmetric_rate = 0; if (!snd_soc_dai_active(codec_dai)) - codec_dai->rate = 0; + codec_dai->symmetric_rate = 0; snd_soc_link_compr_shutdown(cstream, rollback); @@ -537,11 +537,10 @@ static struct snd_compr_ops soc_compr_dyn_ops = { * snd_soc_new_compress - create a new compress. * * @rtd: The runtime for which we will create compress - * @num: the device index number (zero based - shared with normal PCMs) * * Return: 0 for success, else error. */ -int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) +int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component; struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); @@ -606,12 +605,19 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) return -ENOMEM; if (rtd->dai_link->dynamic) { + int playback = 1; + int capture = 1; + + if (rtd->dai_link->capture_only) + playback = 0; + if (rtd->dai_link->playback_only) + capture = 0; + snprintf(new_name, sizeof(new_name), "(%s)", rtd->dai_link->stream_name); - ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, - rtd->dai_link->dpcm_playback, - rtd->dai_link->dpcm_capture, &be_pcm); + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id, + playback, capture, &be_pcm); if (ret < 0) { dev_err(rtd->card->dev, "Compress ASoC: can't create compressed for %s: %d\n", @@ -624,14 +630,14 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) rtd->pcm = be_pcm; rtd->fe_compr = 1; - if (rtd->dai_link->dpcm_playback) + if (playback) be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd; - if (rtd->dai_link->dpcm_capture) + if (capture) be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd; memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops)); } else { snprintf(new_name, sizeof(new_name), "%s %s-%d", - rtd->dai_link->stream_name, codec_dai->name, num); + rtd->dai_link->stream_name, codec_dai->name, rtd->id); memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops)); } @@ -645,7 +651,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) break; } - ret = snd_compress_new(rtd->card->snd_card, num, direction, + ret = snd_compress_new(rtd->card->snd_card, rtd->id, direction, new_name, compr); if (ret < 0) { component = snd_soc_rtd_to_codec(rtd, 0)->component; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 20248a29d1674a..a1dace4bb61664 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -558,7 +558,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( */ rtd->card = card; rtd->dai_link = dai_link; - rtd->num = card->num_rtd++; + rtd->id = card->num_rtd++; rtd->pmdown_time = pmdown_time; /* default power off timeout */ /* see for_each_card_rtds */ @@ -1166,7 +1166,7 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codec, *platform, *cpu; struct snd_soc_component *component; - int i, ret; + int i, id, ret; lockdep_assert_held(&client_mutex); @@ -1225,6 +1225,28 @@ static int snd_soc_add_pcm_runtime(struct snd_soc_card *card, } } + /* + * Most drivers will register their PCMs using DAI link ordering but + * topology based drivers can use the DAI link id field to set PCM + * device number and then use rtd + a base offset of the BEs. + * + * FIXME + * + * This should be implemented by using "dai_link" feature instead of + * "component" feature. + */ + id = rtd->id; + for_each_rtd_components(rtd, i, component) { + if (!component->driver->use_dai_pcm_id) + continue; + + if (rtd->dai_link->no_pcm) + id += component->driver->be_pcm_base; + else + id = rtd->dai_link->id; + } + rtd->id = id; + return 0; _err_defer: @@ -1457,8 +1479,7 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card, { struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - struct snd_soc_component *component; - int ret, num, i; + int ret; /* do machine specific initialization */ ret = snd_soc_link_init(rtd); @@ -1473,30 +1494,13 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card, /* add DPCM sysfs entries */ soc_dpcm_debugfs_add(rtd); - num = rtd->num; - - /* - * most drivers will register their PCMs using DAI link ordering but - * topology based drivers can use the DAI link id field to set PCM - * device number and then use rtd + a base offset of the BEs. - */ - for_each_rtd_components(rtd, i, component) { - if (!component->driver->use_dai_pcm_id) - continue; - - if (rtd->dai_link->no_pcm) - num += component->driver->be_pcm_base; - else - num = rtd->dai_link->id; - } - /* create compress_device if possible */ - ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); + ret = snd_soc_dai_compress_new(cpu_dai, rtd); if (ret != -ENOTSUPP) goto err; /* create the pcm */ - ret = soc_new_pcm(rtd, num); + ret = soc_new_pcm(rtd); if (ret < 0) { dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", dai_link->stream_name, ret); @@ -1999,25 +2003,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) dai_link->platforms->name = component->name; /* convert non BE into BE */ - if (!dai_link->no_pcm) { - dai_link->no_pcm = 1; - - if (dai_link->dpcm_playback) - dev_warn(card->dev, - "invalid configuration, dailink %s has flags no_pcm=0 and dpcm_playback=1\n", - dai_link->name); - if (dai_link->dpcm_capture) - dev_warn(card->dev, - "invalid configuration, dailink %s has flags no_pcm=0 and dpcm_capture=1\n", - dai_link->name); - - /* convert normal link into DPCM one */ - if (!(dai_link->dpcm_playback || - dai_link->dpcm_capture)) { - dai_link->dpcm_playback = !dai_link->capture_only; - dai_link->dpcm_capture = !dai_link->playback_only; - } - } + dai_link->no_pcm = 1; /* * override any BE fixups diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index 4e08892d24c62d..34ba1a93a4c95a 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -37,7 +37,7 @@ static inline int _soc_dai_ret(const struct snd_soc_dai *dai, * In such case, we can update these macros. */ #define soc_dai_mark_push(dai, substream, tgt) ((dai)->mark_##tgt = substream) -#define soc_dai_mark_pop(dai, substream, tgt) ((dai)->mark_##tgt = NULL) +#define soc_dai_mark_pop(dai, tgt) ((dai)->mark_##tgt = NULL) #define soc_dai_mark_match(dai, substream, tgt) ((dai)->mark_##tgt == substream) /** @@ -416,7 +416,7 @@ void snd_soc_dai_hw_free(struct snd_soc_dai *dai, dai->driver->ops->hw_free(substream, dai); /* remove marked substream */ - soc_dai_mark_pop(dai, substream, hw_params); + soc_dai_mark_pop(dai, hw_params); } int snd_soc_dai_startup(struct snd_soc_dai *dai, @@ -453,16 +453,16 @@ void snd_soc_dai_shutdown(struct snd_soc_dai *dai, dai->driver->ops->shutdown(substream, dai); /* remove marked substream */ - soc_dai_mark_pop(dai, substream, startup); + soc_dai_mark_pop(dai, startup); } int snd_soc_dai_compress_new(struct snd_soc_dai *dai, - struct snd_soc_pcm_runtime *rtd, int num) + struct snd_soc_pcm_runtime *rtd) { int ret = -ENOTSUPP; if (dai->driver->ops && dai->driver->ops->compress_new) - ret = dai->driver->ops->compress_new(rtd, num); + ret = dai->driver->ops->compress_new(rtd); return soc_dai_ret(dai, ret); } @@ -640,7 +640,7 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, r = soc_dai_trigger(dai, substream, cmd); if (r < 0) ret = r; /* use last ret */ - soc_dai_mark_pop(dai, substream, trigger); + soc_dai_mark_pop(dai, trigger); } } @@ -704,7 +704,7 @@ void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai, dai->driver->cops->shutdown(cstream, dai); /* remove marked cstream */ - soc_dai_mark_pop(dai, cstream, compr_startup); + soc_dai_mark_pop(dai, compr_startup); } EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index 4534a1c03e8e5e..c6364caabc0ec5 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -9,43 +9,6 @@ #include #include -static void devm_dai_release(struct device *dev, void *res) -{ - snd_soc_unregister_dai(*(struct snd_soc_dai **)res); -} - -/** - * devm_snd_soc_register_dai - resource-managed dai registration - * @dev: Device used to manage component - * @component: The component the DAIs are registered for - * @dai_drv: DAI driver to use for the DAI - * @legacy_dai_naming: if %true, use legacy single-name format; - * if %false, use multiple-name format; - */ -struct snd_soc_dai *devm_snd_soc_register_dai(struct device *dev, - struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, - bool legacy_dai_naming) -{ - struct snd_soc_dai **ptr; - struct snd_soc_dai *dai; - - ptr = devres_alloc(devm_dai_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - dai = snd_soc_register_dai(component, dai_drv, legacy_dai_naming); - if (dai) { - *ptr = dai; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return dai; -} -EXPORT_SYMBOL_GPL(devm_snd_soc_register_dai); - static void devm_component_release(struct device *dev, void *res) { const struct snd_soc_component_driver **cmpnt_drv = res; diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index fee4022708bc7c..7f1f1bc717e2ce 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -35,7 +35,7 @@ static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd, * In such case, we can update these macros. */ #define soc_link_mark_push(rtd, substream, tgt) ((rtd)->mark_##tgt = substream) -#define soc_link_mark_pop(rtd, substream, tgt) ((rtd)->mark_##tgt = NULL) +#define soc_link_mark_pop(rtd, tgt) ((rtd)->mark_##tgt = NULL) #define soc_link_mark_match(rtd, substream, tgt) ((rtd)->mark_##tgt == substream) int snd_soc_link_init(struct snd_soc_pcm_runtime *rtd) @@ -94,7 +94,7 @@ void snd_soc_link_shutdown(struct snd_pcm_substream *substream, rtd->dai_link->ops->shutdown(substream); /* remove marked substream */ - soc_link_mark_pop(rtd, substream, startup); + soc_link_mark_pop(rtd, startup); } int snd_soc_link_prepare(struct snd_pcm_substream *substream) @@ -138,7 +138,7 @@ void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback) rtd->dai_link->ops->hw_free(substream); /* remove marked substream */ - soc_link_mark_pop(rtd, substream, hw_params); + soc_link_mark_pop(rtd, hw_params); } static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd) @@ -175,7 +175,7 @@ int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd, break; ret = soc_link_trigger(substream, cmd); - soc_link_mark_pop(rtd, substream, startup); + soc_link_mark_pop(rtd, startup); } return ret; @@ -209,7 +209,7 @@ void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream, rtd->dai_link->compr_ops->shutdown) rtd->dai_link->compr_ops->shutdown(cstream); - soc_link_mark_pop(rtd, cstream, compr_startup); + soc_link_mark_pop(rtd, compr_startup); } EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7a59121fc323c3..1150455619aa49 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -416,22 +416,6 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) return true; } -/** - * snd_soc_set_runtime_hwparams - set the runtime hardware parameters - * @substream: the pcm substream - * @hw: the hardware parameters - * - * Sets the substream runtime hardware parameters. - */ -int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, - const struct snd_pcm_hardware *hw) -{ - substream->runtime->hw = *hw; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); - /* DPCM stream event, send event to FE and all active BEs. */ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event) @@ -463,13 +447,13 @@ static void soc_pcm_set_dai_params(struct snd_soc_dai *dai, struct snd_pcm_hw_params *params) { if (params) { - dai->rate = params_rate(params); - dai->channels = params_channels(params); - dai->sample_bits = snd_pcm_format_physical_width(params_format(params)); + dai->symmetric_rate = params_rate(params); + dai->symmetric_channels = params_channels(params); + dai->symmetric_sample_bits = snd_pcm_format_physical_width(params_format(params)); } else { - dai->rate = 0; - dai->channels = 0; - dai->sample_bits = 0; + dai->symmetric_rate = 0; + dai->symmetric_channels = 0; + dai->symmetric_sample_bits = 0; } } @@ -483,14 +467,14 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, return 0; #define __soc_pcm_apply_symmetry(name, NAME) \ - if (soc_dai->name && (soc_dai->driver->symmetric_##name || \ - rtd->dai_link->symmetric_##name)) { \ + if (soc_dai->symmetric_##name && \ + (soc_dai->driver->symmetric_##name || rtd->dai_link->symmetric_##name)) { \ dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %s to %d\n",\ - #name, soc_dai->name); \ + #name, soc_dai->symmetric_##name); \ \ ret = snd_pcm_hw_constraint_single(substream->runtime, \ SNDRV_PCM_HW_PARAM_##NAME,\ - soc_dai->name); \ + soc_dai->symmetric_##name); \ if (ret < 0) { \ dev_err(soc_dai->dev, \ "ASoC: Unable to apply %s constraint: %d\n",\ @@ -526,9 +510,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, if (symmetry) \ for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ if (!snd_soc_dai_is_dummy(cpu_dai) && \ - cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ + cpu_dai->symmetric_##xxx && \ + cpu_dai->symmetric_##xxx != d.symmetric_##xxx) { \ dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \ - #xxx, cpu_dai->name, cpu_dai->xxx, d.name, d.xxx); \ + #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \ + d.name, d.symmetric_##xxx); \ return -EINVAL; \ } @@ -799,8 +785,7 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd, /* Make sure DAI parameters cleared if the DAI becomes inactive */ for_each_rtd_dais(rtd, i, dai) { - if (snd_soc_dai_active(dai) == 0 && - (dai->rate || dai->channels || dai->sample_bits)) + if (snd_soc_dai_active(dai) == 0) soc_pcm_set_dai_params(dai, NULL); } } @@ -2838,7 +2823,11 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai; + struct snd_soc_dai *codec_dai; struct snd_soc_dai_link_ch_map *ch_maps; + struct snd_soc_dai *dummy_dai = snd_soc_find_dai(&snd_soc_dummy_dlc); + int cpu_capture; + int cpu_playback; int has_playback = 0; int has_capture = 0; int i; @@ -2848,73 +2837,38 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, return -EINVAL; } - if (dai_link->dynamic || dai_link->no_pcm) { - - for_each_rtd_ch_maps(rtd, i, ch_maps) { - cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); + /* Adapt stream for codec2codec links */ + cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE); + cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK); - if (snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_PLAYBACK)) - has_playback = 1; - - if (snd_soc_dai_stream_valid(cpu_dai, SNDRV_PCM_STREAM_CAPTURE)) - has_capture = 1; - } + /* + * see + * soc.h :: [dai_link->ch_maps Image sample] + */ + for_each_rtd_ch_maps(rtd, i, ch_maps) { + cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); + codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec); /* - * REMOVE ME + * FIXME + * + * DPCM Codec has been no checked before. + * It should be checked, but it breaks compatibility. * - * dpcm_xxx flag will be removed soon, Indicates warning if dpcm_xxx flag was used - * as availability limitation + * For example there is a case that CPU have loopback capabilities which is used + * for tests on boards where the Codec has no capture capabilities. In this case, + * Codec capture validation check will be fail, but system should allow capture + * capabilities. We have no solution for it today. */ - if (has_playback && has_capture) { - if ( dai_link->dpcm_playback && - !dai_link->dpcm_capture && - !dai_link->playback_only) { - dev_warn(rtd->card->dev, - "both playback/capture are available," - " but not using playback_only flag (%s)\n", - dai_link->stream_name); - dev_warn(rtd->card->dev, - "dpcm_playback/capture are no longer needed," - " please use playback/capture_only instead\n"); - has_capture = 0; - } - - if (!dai_link->dpcm_playback && - dai_link->dpcm_capture && - !dai_link->capture_only) { - dev_warn(rtd->card->dev, - "both playback/capture are available," - " but not using capture_only flag (%s)\n", - dai_link->stream_name); - dev_warn(rtd->card->dev, - "dpcm_playback/capture are no longer needed," - " please use playback/capture_only instead\n"); - has_playback = 0; - } - } - } else { - struct snd_soc_dai *codec_dai; + if (dai_link->dynamic || dai_link->no_pcm) + codec_dai = dummy_dai; - /* Adapt stream for codec2codec links */ - int cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE); - int cpu_playback = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_PLAYBACK); - - /* - * see - * soc.h :: [dai_link->ch_maps Image sample] - */ - for_each_rtd_ch_maps(rtd, i, ch_maps) { - cpu_dai = snd_soc_rtd_to_cpu(rtd, ch_maps->cpu); - codec_dai = snd_soc_rtd_to_codec(rtd, ch_maps->codec); - - if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && - snd_soc_dai_stream_valid(cpu_dai, cpu_playback)) - has_playback = 1; - if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && - snd_soc_dai_stream_valid(cpu_dai, cpu_capture)) - has_capture = 1; - } + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) && + snd_soc_dai_stream_valid(cpu_dai, cpu_playback)) + has_playback = 1; + if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) && + snd_soc_dai_stream_valid(cpu_dai, cpu_capture)) + has_capture = 1; } if (dai_link->playback_only) @@ -2938,7 +2892,7 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, static int soc_create_pcm(struct snd_pcm **pcm, struct snd_soc_pcm_runtime *rtd, - int playback, int capture, int num) + int playback, int capture) { char new_name[64]; int ret; @@ -2948,13 +2902,13 @@ static int soc_create_pcm(struct snd_pcm **pcm, snprintf(new_name, sizeof(new_name), "codec2codec(%s)", rtd->dai_link->stream_name); - ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id, playback, capture, pcm); } else if (rtd->dai_link->no_pcm) { snprintf(new_name, sizeof(new_name), "(%s)", rtd->dai_link->stream_name); - ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num, + ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, rtd->id, playback, capture, pcm); } else { if (rtd->dai_link->dynamic) @@ -2963,9 +2917,9 @@ static int soc_create_pcm(struct snd_pcm **pcm, else snprintf(new_name, sizeof(new_name), "%s %s-%d", rtd->dai_link->stream_name, - soc_codec_dai_name(rtd), num); + soc_codec_dai_name(rtd), rtd->id); - ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, + ret = snd_pcm_new(rtd->card->snd_card, new_name, rtd->id, playback, capture, pcm); } if (ret < 0) { @@ -2973,13 +2927,13 @@ static int soc_create_pcm(struct snd_pcm **pcm, new_name, rtd->dai_link->name, ret); return ret; } - dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n",num, new_name); + dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n", rtd->id, new_name); return 0; } /* create a new pcm */ -int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) +int soc_new_pcm(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component; struct snd_pcm *pcm; @@ -2990,7 +2944,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (ret < 0) return ret; - ret = soc_create_pcm(&pcm, rtd, playback, capture, num); + ret = soc_create_pcm(&pcm, rtd, playback, capture); if (ret < 0) return ret; diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c index a2b08568f4e898..c8f2ec29e97030 100644 --- a/sound/soc/soc-topology-test.c +++ b/sound/soc/soc-topology-test.c @@ -88,8 +88,6 @@ static struct snd_soc_dai_link kunit_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(dummy, dummy, platform), }, }; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 97517423d1f0bb..43003d2d366673 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1544,8 +1544,8 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, /* enable DPCM */ link->dynamic = 1; link->ignore_pmdown_time = 1; - link->dpcm_playback = le32_to_cpu(pcm->playback); - link->dpcm_capture = le32_to_cpu(pcm->capture); + link->playback_only = le32_to_cpu(pcm->playback) && !le32_to_cpu(pcm->capture); + link->capture_only = !le32_to_cpu(pcm->playback) && le32_to_cpu(pcm->capture); if (pcm->flag_mask) set_link_flags(link, le32_to_cpu(pcm->flag_mask), diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 303823dc45d7ac..aa93e77ac937b0 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -103,8 +103,8 @@ static const struct snd_pcm_hardware dummy_dma_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER, .buffer_bytes_max = 128*1024, - .period_bytes_min = PAGE_SIZE, - .period_bytes_max = PAGE_SIZE*2, + .period_bytes_min = 4096, + .period_bytes_max = 4096*2, .periods_min = 2, .periods_max = 128, }; diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c index dbcaac84cb73af..0c3a92f5f942d0 100644 --- a/sound/soc/sof/amd/acp-common.c +++ b/sound/soc/sof/amd/acp-common.c @@ -145,8 +145,7 @@ static struct snd_soc_acpi_mach *amd_sof_sdw_machine_select(struct snd_sof_dev * link = mach->links; for (i = 0; i < acp_data->info.count && link->num_adr; link++, i++) { if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, - acp_data->sdw->ids, - acp_data->sdw->num_slaves)) + acp_data->sdw->peripherals)) break; } if (i == acp_data->info.count || !link->num_adr) @@ -259,10 +258,10 @@ const struct snd_sof_dsp_ops sof_acp_common_ops = { .register_ipc_clients = acp_probes_register, .unregister_ipc_clients = acp_probes_unregister, }; -EXPORT_SYMBOL_NS(sof_acp_common_ops, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(sof_acp_common_ops, "SND_SOC_SOF_AMD_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("ACP SOF COMMON Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); -MODULE_IMPORT_NS(SOUNDWIRE_AMD_INIT); +MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); +MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c index b44b1b1adb6ed9..5f371d9263f3ba 100644 --- a/sound/soc/sof/amd/acp-ipc.c +++ b/sound/soc/sof/amd/acp-ipc.c @@ -19,13 +19,13 @@ void acp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size { memcpy_to_scratch(sdev, offset, message, bytes); } -EXPORT_SYMBOL_NS(acp_mailbox_write, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_mailbox_write, "SND_SOC_SOF_AMD_COMMON"); void acp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) { memcpy_from_scratch(sdev, offset, message, bytes); } -EXPORT_SYMBOL_NS(acp_mailbox_read, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_mailbox_read, "SND_SOC_SOF_AMD_COMMON"); static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata) { @@ -91,7 +91,7 @@ int acp_sof_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -EXPORT_SYMBOL_NS(acp_sof_ipc_send_msg, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_ipc_send_msg, "SND_SOC_SOF_AMD_COMMON"); static void acp_dsp_ipc_get_reply(struct snd_sof_dev *sdev) { @@ -235,7 +235,7 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(acp_sof_ipc_irq_thread, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_ipc_irq_thread, "SND_SOC_SOF_AMD_COMMON"); int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, void *p, size_t sz) @@ -261,7 +261,7 @@ int acp_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sp return 0; } -EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_ipc_msg_data, "SND_SOC_SOF_AMD_COMMON"); int acp_set_stream_data_offset(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, @@ -282,7 +282,7 @@ int acp_set_stream_data_offset(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_NS(acp_set_stream_data_offset, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_set_stream_data_offset, "SND_SOC_SOF_AMD_COMMON"); int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { @@ -290,12 +290,12 @@ int acp_sof_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) return desc->sram_pte_offset; } -EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_ipc_get_mailbox_offset, "SND_SOC_SOF_AMD_COMMON"); int acp_sof_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return 0; } -EXPORT_SYMBOL_NS(acp_sof_ipc_get_window_offset, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_ipc_get_window_offset, "SND_SOC_SOF_AMD_COMMON"); MODULE_DESCRIPTION("AMD ACP sof-ipc driver"); diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c index 077af9e2af8d09..ea105227227dc4 100644 --- a/sound/soc/sof/amd/acp-loader.c +++ b/sound/soc/sof/amd/acp-loader.c @@ -44,7 +44,7 @@ int acp_dsp_block_read(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_ty return 0; } -EXPORT_SYMBOL_NS(acp_dsp_block_read, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_dsp_block_read, "SND_SOC_SOF_AMD_COMMON"); int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_type, u32 offset, void *src, size_t size) @@ -106,13 +106,13 @@ int acp_dsp_block_write(struct snd_sof_dev *sdev, enum snd_sof_fw_blk_type blk_t memcpy(dest, src, size); return 0; } -EXPORT_SYMBOL_NS(acp_dsp_block_write, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_dsp_block_write, "SND_SOC_SOF_AMD_COMMON"); int acp_get_bar_index(struct snd_sof_dev *sdev, u32 type) { return type; } -EXPORT_SYMBOL_NS(acp_get_bar_index, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_get_bar_index, "SND_SOC_SOF_AMD_COMMON"); static void configure_pte_for_fw_loading(int type, int num_pages, struct acp_dev_data *adata) { @@ -244,7 +244,7 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev) } return ret; } -EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_dsp_pre_fw_run, "SND_SOC_SOF_AMD_COMMON"); int acp_sof_dsp_run(struct snd_sof_dev *sdev) { @@ -264,7 +264,7 @@ int acp_sof_dsp_run(struct snd_sof_dev *sdev) } return 0; } -EXPORT_SYMBOL_NS(acp_sof_dsp_run, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_dsp_run, "SND_SOC_SOF_AMD_COMMON"); int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) { @@ -317,4 +317,4 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) adata->fw_dbin->size); return ret; } -EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, "SND_SOC_SOF_AMD_COMMON"); diff --git a/sound/soc/sof/amd/acp-pcm.c b/sound/soc/sof/amd/acp-pcm.c index cee0b115487428..2802684f26de17 100644 --- a/sound/soc/sof/amd/acp-pcm.c +++ b/sound/soc/sof/amd/acp-pcm.c @@ -52,7 +52,7 @@ int acp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substr return 0; } -EXPORT_SYMBOL_NS(acp_pcm_hw_params, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_pcm_hw_params, "SND_SOC_SOF_AMD_COMMON"); int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -67,7 +67,7 @@ int acp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) return 0; } -EXPORT_SYMBOL_NS(acp_pcm_open, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_pcm_open, "SND_SOC_SOF_AMD_COMMON"); int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { @@ -84,7 +84,7 @@ int acp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) return acp_dsp_stream_put(sdev, stream); } -EXPORT_SYMBOL_NS(acp_pcm_close, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_pcm_close, "SND_SOC_SOF_AMD_COMMON"); snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) @@ -117,4 +117,4 @@ snd_pcm_uframes_t acp_pcm_pointer(struct snd_sof_dev *sdev, return pos; } -EXPORT_SYMBOL_NS(acp_pcm_pointer, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_pcm_pointer, "SND_SOC_SOF_AMD_COMMON"); diff --git a/sound/soc/sof/amd/acp-probes.c b/sound/soc/sof/amd/acp-probes.c index 778cf1a8b61052..0d0f8ec4aed838 100644 --- a/sound/soc/sof/amd/acp-probes.c +++ b/sound/soc/sof/amd/acp-probes.c @@ -135,13 +135,13 @@ int acp_probes_register(struct snd_sof_dev *sdev) return sof_client_dev_register(sdev, "acp-probes", 0, &acp_probes_ops, sizeof(acp_probes_ops)); } -EXPORT_SYMBOL_NS(acp_probes_register, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_probes_register, "SND_SOC_SOF_AMD_COMMON"); void acp_probes_unregister(struct snd_sof_dev *sdev) { sof_client_dev_unregister(sdev, "acp-probes", 0); } -EXPORT_SYMBOL_NS(acp_probes_unregister, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_probes_unregister, "SND_SOC_SOF_AMD_COMMON"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/amd/acp-stream.c b/sound/soc/sof/amd/acp-stream.c index 6f40ef7ba85ec2..9212a3137cfd2b 100644 --- a/sound/soc/sof/amd/acp-stream.c +++ b/sound/soc/sof/amd/acp-stream.c @@ -150,7 +150,7 @@ struct acp_dsp_stream *acp_dsp_stream_get(struct snd_sof_dev *sdev, int tag) dev_err(sdev->dev, "stream %d active or no inactive stream\n", tag); return NULL; } -EXPORT_SYMBOL_NS(acp_dsp_stream_get, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_dsp_stream_get, "SND_SOC_SOF_AMD_COMMON"); int acp_dsp_stream_put(struct snd_sof_dev *sdev, struct acp_dsp_stream *acp_stream) @@ -170,7 +170,7 @@ int acp_dsp_stream_put(struct snd_sof_dev *sdev, dev_err(sdev->dev, "Cannot find active stream tag %d\n", acp_stream->stream_tag); return -EINVAL; } -EXPORT_SYMBOL_NS(acp_dsp_stream_put, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_dsp_stream_put, "SND_SOC_SOF_AMD_COMMON"); int acp_dsp_stream_init(struct snd_sof_dev *sdev) { @@ -184,4 +184,4 @@ int acp_dsp_stream_init(struct snd_sof_dev *sdev) } return 0; } -EXPORT_SYMBOL_NS(acp_dsp_stream_init, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_dsp_stream_init, "SND_SOC_SOF_AMD_COMMON"); diff --git a/sound/soc/sof/amd/acp-trace.c b/sound/soc/sof/amd/acp-trace.c index c9482b27cbe393..0bd1f5990e8cd7 100644 --- a/sound/soc/sof/amd/acp-trace.c +++ b/sound/soc/sof/amd/acp-trace.c @@ -32,7 +32,7 @@ int acp_sof_trace_release(struct snd_sof_dev *sdev) adata->dtrace_stream = NULL; return 0; } -EXPORT_SYMBOL_NS(acp_sof_trace_release, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_trace_release, "SND_SOC_SOF_AMD_COMMON"); int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct sof_ipc_dma_trace_params_ext *dtrace_params) @@ -61,4 +61,4 @@ int acp_sof_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, return 0; } -EXPORT_SYMBOL_NS(acp_sof_trace_init, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(acp_sof_trace_init, "SND_SOC_SOF_AMD_COMMON"); diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 95d4762c9d9390..33648ff8b83365 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -633,7 +633,7 @@ int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state) return 0; } -EXPORT_SYMBOL_NS(amd_sof_acp_suspend, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(amd_sof_acp_suspend, "SND_SOC_SOF_AMD_COMMON"); int amd_sof_acp_resume(struct snd_sof_dev *sdev) { @@ -652,7 +652,7 @@ int amd_sof_acp_resume(struct snd_sof_dev *sdev) return acp_dsp_reset(sdev); } } -EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(amd_sof_acp_resume, "SND_SOC_SOF_AMD_COMMON"); #if IS_ENABLED(CONFIG_SND_SOC_SOF_AMD_SOUNDWIRE) static int acp_sof_scan_sdw_devices(struct snd_sof_dev *sdev, u64 addr) @@ -693,6 +693,7 @@ static int amd_sof_sdw_probe(struct snd_sof_dev *sdev) sdw_res.count = acp_data->info.count; sdw_res.link_mask = acp_data->info.link_mask; sdw_res.mmio_base = sdev->bar[ACP_DSP_BAR]; + sdw_res.acp_rev = acp_data->pci_rev; ret = sdw_amd_probe(&sdw_res, &acp_data->sdw); if (ret) @@ -851,7 +852,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) platform_device_unregister(adata->dmic_dev); return ret; } -EXPORT_SYMBOL_NS(amd_sof_acp_probe, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(amd_sof_acp_probe, "SND_SOC_SOF_AMD_COMMON"); void amd_sof_acp_remove(struct snd_sof_dev *sdev) { @@ -871,9 +872,9 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev) acp_reset(sdev); } -EXPORT_SYMBOL_NS(amd_sof_acp_remove, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(amd_sof_acp_remove, "SND_SOC_SOF_AMD_COMMON"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("AMD ACP sof driver"); -MODULE_IMPORT_NS(SOUNDWIRE_AMD_INIT); -MODULE_IMPORT_NS(SND_AMD_SOUNDWIRE_ACPI); +MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); +MODULE_IMPORT_NS("SND_AMD_SOUNDWIRE_ACPI"); diff --git a/sound/soc/sof/amd/acp63.c b/sound/soc/sof/amd/acp63.c index 9e6eb4bfc805b2..a686620b13588b 100644 --- a/sound/soc/sof/amd/acp63.c +++ b/sound/soc/sof/amd/acp63.c @@ -128,7 +128,7 @@ static struct snd_soc_dai_driver acp63_sof_dai[] = { /* Phoenix ops */ struct snd_sof_dsp_ops sof_acp63_ops; -EXPORT_SYMBOL_NS(sof_acp63_ops, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(sof_acp63_ops, "SND_SOC_SOF_AMD_COMMON"); int sof_acp63_ops_init(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/amd/acp70.c b/sound/soc/sof/amd/acp70.c index 7d1842f42c90c0..8314ac4008dae1 100644 --- a/sound/soc/sof/amd/acp70.c +++ b/sound/soc/sof/amd/acp70.c @@ -128,7 +128,7 @@ static struct snd_soc_dai_driver acp70_sof_dai[] = { /* Phoenix ops */ struct snd_sof_dsp_ops sof_acp70_ops; -EXPORT_SYMBOL_NS(sof_acp70_ops, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(sof_acp70_ops, "SND_SOC_SOF_AMD_COMMON"); int sof_acp70_ops_init(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/amd/pci-acp63.c b/sound/soc/sof/amd/pci-acp63.c index b54ed61b79edd2..ffe7c755d655e6 100644 --- a/sound/soc/sof/amd/pci-acp63.c +++ b/sound/soc/sof/amd/pci-acp63.c @@ -112,5 +112,5 @@ module_pci_driver(snd_sof_pci_amd_acp63_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("ACP63 SOF Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c index a5d8b6a95a2226..3647ec992e95f6 100644 --- a/sound/soc/sof/amd/pci-acp70.c +++ b/sound/soc/sof/amd/pci-acp70.c @@ -108,5 +108,5 @@ module_pci_driver(snd_sof_pci_amd_acp70_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("ACP70 SOF Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c index c45256bf4fda62..cbb4d528266442 100644 --- a/sound/soc/sof/amd/pci-rmb.c +++ b/sound/soc/sof/amd/pci-rmb.c @@ -101,5 +101,5 @@ module_pci_driver(snd_sof_pci_amd_rmb_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("REMBRANDT SOF Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index 386a0f1e7ee014..b7d558cb1fd7a7 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -105,5 +105,5 @@ module_pci_driver(snd_sof_pci_amd_rn_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("RENOIR SOF Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c index cb845f81795e55..53f64d6bc91bae 100644 --- a/sound/soc/sof/amd/pci-vangogh.c +++ b/sound/soc/sof/amd/pci-vangogh.c @@ -100,5 +100,5 @@ module_pci_driver(snd_sof_pci_amd_vgh_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("VANGOGH SOF Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_AMD_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/amd/rembrandt.c b/sound/soc/sof/amd/rembrandt.c index 076f2f05a95c20..86ef59743fc875 100644 --- a/sound/soc/sof/amd/rembrandt.c +++ b/sound/soc/sof/amd/rembrandt.c @@ -128,7 +128,7 @@ static struct snd_soc_dai_driver rembrandt_sof_dai[] = { /* Rembrandt ops */ struct snd_sof_dsp_ops sof_rembrandt_ops; -EXPORT_SYMBOL_NS(sof_rembrandt_ops, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(sof_rembrandt_ops, "SND_SOC_SOF_AMD_COMMON"); int sof_rembrandt_ops_init(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/amd/renoir.c b/sound/soc/sof/amd/renoir.c index aa2d24dac6f5d5..b3b4639abf5065 100644 --- a/sound/soc/sof/amd/renoir.c +++ b/sound/soc/sof/amd/renoir.c @@ -103,7 +103,7 @@ static struct snd_soc_dai_driver renoir_sof_dai[] = { /* Renoir ops */ struct snd_sof_dsp_ops sof_renoir_ops; -EXPORT_SYMBOL_NS(sof_renoir_ops, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(sof_renoir_ops, "SND_SOC_SOF_AMD_COMMON"); int sof_renoir_ops_init(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c index 61372958c09dc8..8e2672106ac60a 100644 --- a/sound/soc/sof/amd/vangogh.c +++ b/sound/soc/sof/amd/vangogh.c @@ -138,7 +138,7 @@ static struct snd_soc_dai_driver vangogh_sof_dai[] = { /* Vangogh ops */ struct snd_sof_dsp_ops sof_vangogh_ops; -EXPORT_SYMBOL_NS(sof_vangogh_ops, SND_SOC_SOF_AMD_COMMON); +EXPORT_SYMBOL_NS(sof_vangogh_ops, "SND_SOC_SOF_AMD_COMMON"); int sof_vangogh_ops_init(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 83fe0401baf867..aed834d03e1086 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -19,11 +19,47 @@ #define CREATE_TRACE_POINTS #include +/* Module parameters for firmware, topology and IPC type override */ +static char *override_fw_path; +module_param_named(fw_path, override_fw_path, charp, 0444); +MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); + +static char *override_fw_filename; +module_param_named(fw_filename, override_fw_filename, charp, 0444); +MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware."); + +static char *override_lib_path; +module_param_named(lib_path, override_lib_path, charp, 0444); +MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries."); + +static char *override_tplg_path; +module_param_named(tplg_path, override_tplg_path, charp, 0444); +MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); + +static char *override_tplg_filename; +module_param_named(tplg_filename, override_tplg_filename, charp, 0444); +MODULE_PARM_DESC(tplg_filename, "alternate filename for SOF topology."); + +static int override_ipc_type = -1; +module_param_named(ipc_type, override_ipc_type, int, 0444); +MODULE_PARM_DESC(ipc_type, "Force SOF IPC type. 0 - IPC3, 1 - IPC4"); + /* see SOF_DBG_ flags */ static int sof_core_debug = IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE); module_param_named(sof_debug, sof_core_debug, int, 0444); MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) +static unsigned int sof_ipc_timeout_ms; +static unsigned int sof_boot_timeout_ms; +module_param_named(ipc_timeout, sof_ipc_timeout_ms, uint, 0444); +MODULE_PARM_DESC(ipc_timeout, + "Set the IPC timeout value in ms (0 to use the platform default)"); +module_param_named(boot_timeout, sof_boot_timeout_ms, uint, 0444); +MODULE_PARM_DESC(boot_timeout, + "Set the DSP boot timeout value in ms (0 to use the platform default)"); +#endif + /* SOF defaults if not provided by the platform in ms */ #define TIMEOUT_DEFAULT_IPC_MS 500 #define TIMEOUT_DEFAULT_BOOT_MS 2000 @@ -570,6 +606,23 @@ static void sof_probe_work(struct work_struct *work) } } +static void +sof_apply_profile_override(struct sof_loadable_file_profile *path_override) +{ + if (override_ipc_type >= 0 && override_ipc_type < SOF_IPC_TYPE_COUNT) + path_override->ipc_type = override_ipc_type; + if (override_fw_path) + path_override->fw_path = override_fw_path; + if (override_fw_filename) + path_override->fw_name = override_fw_filename; + if (override_lib_path) + path_override->fw_lib_path = override_lib_path; + if (override_tplg_path) + path_override->tplg_path = override_tplg_path; + if (override_tplg_filename) + path_override->tplg_name = override_tplg_filename; +} + int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) { struct snd_sof_dev *sdev; @@ -601,6 +654,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) } } + sof_apply_profile_override(&plat_data->ipc_file_profile_base); + /* Initialize sof_ops based on the initial selected IPC version */ ret = sof_init_sof_ops(sdev); if (ret) @@ -632,6 +687,15 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) else sdev->boot_timeout = plat_data->desc->boot_timeout; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) + /* Override the timeout values with module parameter, if set */ + if (sof_ipc_timeout_ms) + sdev->ipc_timeout = sof_ipc_timeout_ms; + + if (sof_boot_timeout_ms) + sdev->boot_timeout = sof_boot_timeout_ms; +#endif + sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED); /* @@ -772,4 +836,4 @@ MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core"); MODULE_ALIAS("platform:sof-audio"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index f09ee0dea2ccd5..0b85b29d1067f6 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -669,4 +669,4 @@ module_platform_driver(snd_sof_of_imx8_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for IMX8 platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index 01d3ad3314f3f2..ff42743efa7913 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -516,4 +516,4 @@ module_platform_driver(snd_sof_of_imx8m_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for IMX8M platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c index e5eee1c9f6da46..6965791ab6ef64 100644 --- a/sound/soc/sof/imx/imx8ulp.c +++ b/sound/soc/sof/imx/imx8ulp.c @@ -518,4 +518,4 @@ module_platform_driver(snd_sof_of_imx8ulp_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for IMX8ULP platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c index 3505ac3a1b143f..30e981c558c649 100644 --- a/sound/soc/sof/intel/atom.c +++ b/sound/soc/sof/intel/atom.c @@ -94,7 +94,7 @@ void atom_dump(struct snd_sof_dev *sdev, u32 flags) (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd); } -EXPORT_SYMBOL_NS(atom_dump, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_dump, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); /* * IPC Doorbell IRQ handler and thread. @@ -131,7 +131,7 @@ irqreturn_t atom_irq_handler(int irq, void *context) return ret; } -EXPORT_SYMBOL_NS(atom_irq_handler, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_irq_handler, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); irqreturn_t atom_irq_thread(int irq, void *context) { @@ -176,7 +176,7 @@ irqreturn_t atom_irq_thread(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(atom_irq_thread, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_irq_thread, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { @@ -191,19 +191,19 @@ int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -EXPORT_SYMBOL_NS(atom_send_msg, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_send_msg, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); int atom_get_mailbox_offset(struct snd_sof_dev *sdev) { return MBOX_OFFSET; } -EXPORT_SYMBOL_NS(atom_get_mailbox_offset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_get_mailbox_offset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); int atom_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return MBOX_OFFSET; } -EXPORT_SYMBOL_NS(atom_get_window_offset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_get_window_offset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); static void atom_host_done(struct snd_sof_dev *sdev) { @@ -248,7 +248,7 @@ int atom_run(struct snd_sof_dev *sdev) /* return init core mask */ return 1; } -EXPORT_SYMBOL_NS(atom_run, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_run, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); int atom_reset(struct snd_sof_dev *sdev) { @@ -267,7 +267,7 @@ int atom_reset(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(atom_reset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_reset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); static const char *fixup_tplg_name(struct snd_sof_dev *sdev, const char *sof_tplg_filename, @@ -330,7 +330,7 @@ struct snd_soc_acpi_mach *atom_machine_select(struct snd_sof_dev *sdev) return mach; } -EXPORT_SYMBOL_NS(atom_machine_select, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_machine_select, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); /* Atom DAIs */ struct snd_soc_dai_driver atom_dai[] = { @@ -401,7 +401,7 @@ struct snd_soc_dai_driver atom_dai[] = { }, }, }; -EXPORT_SYMBOL_NS(atom_dai, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_dai, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); void atom_set_mach_params(struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev) @@ -415,7 +415,7 @@ void atom_set_mach_params(struct snd_soc_acpi_mach *mach, mach_params->num_dai_drivers = desc->ops->num_drv; mach_params->dai_drivers = desc->ops->drv; } -EXPORT_SYMBOL_NS(atom_set_mach_params, SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +EXPORT_SYMBOL_NS(atom_set_mach_params, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Atom platforms"); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 322ff118f0f68b..c4d92f3508b6c5 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -695,6 +695,6 @@ module_platform_driver(snd_sof_acpi_intel_bdw_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Broadwell platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); -MODULE_IMPORT_NS(SND_SOC_SOF_ACPI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC"); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); +MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV"); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index f531710cf94ec2..536d4c89d2f02c 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -476,7 +476,7 @@ module_platform_driver(snd_sof_acpi_intel_byt_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Baytrail/Cherrytrail"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); -MODULE_IMPORT_NS(SND_SOC_SOF_ACPI_DEV); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC"); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); +MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 6a8c7a108ef05d..385e5339f0a4b7 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -110,7 +110,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(cnl_ipc4_irq_thread, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(cnl_ipc4_irq_thread, "SND_SOC_SOF_INTEL_CNL"); irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { @@ -203,7 +203,7 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(cnl_ipc_irq_thread, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(cnl_ipc_irq_thread, "SND_SOC_SOF_INTEL_CNL"); static void cnl_ipc_host_done(struct snd_sof_dev *sdev) { @@ -286,7 +286,7 @@ int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -EXPORT_SYMBOL_NS(cnl_ipc4_send_msg, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(cnl_ipc4_send_msg, "SND_SOC_SOF_INTEL_CNL"); int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { @@ -334,7 +334,7 @@ int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -EXPORT_SYMBOL_NS(cnl_ipc_send_msg, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(cnl_ipc_send_msg, "SND_SOC_SOF_INTEL_CNL"); void cnl_ipc_dump(struct snd_sof_dev *sdev) { @@ -355,7 +355,7 @@ void cnl_ipc_dump(struct snd_sof_dev *sdev) "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", hipcida, hipctdr, hipcctl); } -EXPORT_SYMBOL_NS(cnl_ipc_dump, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(cnl_ipc_dump, "SND_SOC_SOF_INTEL_CNL"); void cnl_ipc4_dump(struct snd_sof_dev *sdev) { @@ -377,11 +377,11 @@ void cnl_ipc4_dump(struct snd_sof_dev *sdev) "Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n", hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl); } -EXPORT_SYMBOL_NS(cnl_ipc4_dump, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(cnl_ipc4_dump, "SND_SOC_SOF_INTEL_CNL"); /* cannonlake ops */ struct snd_sof_dsp_ops sof_cnl_ops; -EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(sof_cnl_ops, "SND_SOC_SOF_INTEL_CNL"); int sof_cnl_ops_init(struct snd_sof_dev *sdev) { @@ -450,7 +450,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev) return 0; }; -EXPORT_SYMBOL_NS(sof_cnl_ops_init, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(sof_cnl_ops_init, "SND_SOC_SOF_INTEL_CNL"); const struct sof_intel_dsp_desc cnl_chip_info = { /* Cannonlake */ @@ -516,4 +516,4 @@ const struct sof_intel_dsp_desc jsl_chip_info = { .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_2_0, }; -EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(jsl_chip_info, "SND_SOC_SOF_INTEL_CNL"); diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 1989147aa6a463..b1be03011d7e15 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -99,7 +99,7 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev) spin_lock_init(&bus->reg_lock); #endif /* CONFIG_SND_SOC_SOF_HDA_LINK */ } -EXPORT_SYMBOL_NS(sof_hda_bus_init, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sof_hda_bus_init, "SND_SOC_SOF_INTEL_HDA_COMMON"); void sof_hda_bus_exit(struct snd_sof_dev *sdev) { @@ -109,4 +109,4 @@ void sof_hda_bus_exit(struct snd_sof_dev *sdev) snd_hdac_ext_bus_exit(bus); #endif } -EXPORT_SYMBOL_NS(sof_hda_bus_exit, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sof_hda_bus_exit, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index dc46888faa0dc9..568f3dfe822f57 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -101,7 +101,7 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable) snd_hdac_chip_updatew(bus, WAKEEN, mask & STATESTS_INT_MASK, val); } -EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, "SND_SOC_SOF_HDA_AUDIO_CODEC"); /* check jack status after resuming from suspend mode */ void hda_codec_jack_check(struct snd_sof_dev *sdev) @@ -121,7 +121,7 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev) if (codec->jacktbl.used) pm_request_resume(&codec->core.dev); } -EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, "SND_SOC_SOF_HDA_AUDIO_CODEC"); #if IS_ENABLED(CONFIG_SND_HDA_GENERIC) #define is_generic_config(bus) \ @@ -237,7 +237,7 @@ void hda_codec_probe_bus(struct snd_sof_dev *sdev) } } } -EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_check_for_state_change(struct snd_sof_dev *sdev) { @@ -250,7 +250,7 @@ void hda_codec_check_for_state_change(struct snd_sof_dev *sdev) snd_hdac_chip_writew(bus, STATESTS, codec_mask); } } -EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_detect_mask(struct snd_sof_dev *sdev) { @@ -275,7 +275,7 @@ void hda_codec_detect_mask(struct snd_sof_dev *sdev) bus->codec_mask); } } -EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_init_cmd_io(struct snd_sof_dev *sdev) { @@ -288,7 +288,7 @@ void hda_codec_init_cmd_io(struct snd_sof_dev *sdev) /* initialize the codec command I/O */ snd_hdac_bus_init_cmd_io(bus); } -EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev) { @@ -302,7 +302,7 @@ void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev) if (bus->cmd_dma_state) snd_hdac_bus_init_cmd_io(bus); } -EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev) { @@ -315,7 +315,7 @@ void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev) /* initialize the codec command I/O */ snd_hdac_bus_stop_cmd_io(bus); } -EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev) { @@ -330,7 +330,7 @@ void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev) snd_hdac_bus_stop_cmd_io(bus); } -EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev) { @@ -343,7 +343,7 @@ void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev) /* clear rirb status */ snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); } -EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status) { @@ -354,7 +354,7 @@ void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status) snd_hdac_set_codec_wakeup(bus, status); } -EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, "SND_SOC_SOF_HDA_AUDIO_CODEC"); bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev) { @@ -381,7 +381,7 @@ bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev) } return active; } -EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, "SND_SOC_SOF_HDA_AUDIO_CODEC"); void hda_codec_device_remove(struct snd_sof_dev *sdev) { @@ -394,7 +394,7 @@ void hda_codec_device_remove(struct snd_sof_dev *sdev) /* codec removal, invoke bus_device_remove */ snd_hdac_ext_bus_device_remove(bus); } -EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, SND_SOC_SOF_HDA_AUDIO_CODEC); +EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, "SND_SOC_SOF_HDA_AUDIO_CODEC"); #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ @@ -413,7 +413,7 @@ void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable) snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable); } } -EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); +EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915"); int hda_codec_i915_init(struct snd_sof_dev *sdev) { @@ -434,7 +434,7 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); +EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915"); int hda_codec_i915_exit(struct snd_sof_dev *sdev) { @@ -452,7 +452,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev) return snd_hdac_i915_exit(bus); } -EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915); +EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915"); #endif diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c index 5fc28039a8e825..746b426b1329b0 100644 --- a/sound/soc/sof/intel/hda-common-ops.c +++ b/sound/soc/sof/intel/hda-common-ops.c @@ -105,4 +105,4 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = { .dsp_arch_ops = &sof_xtensa_arch_ops, }; -EXPORT_SYMBOL_NS(sof_hda_common_ops, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(sof_hda_common_ops, "SND_SOC_SOF_INTEL_HDA_GENERIC"); diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index b9a02750ce6131..4f34fd919a00aa 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -128,7 +128,7 @@ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(hda_dsp_ctrl_get_caps, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ctrl_get_caps, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable) { @@ -137,7 +137,7 @@ void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable) snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, SOF_HDA_PPCTL_GPROCEN, val); } -EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_enable, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_enable, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable) { @@ -146,7 +146,7 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable) snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, SOF_HDA_PPCTL_PIE, val); } -EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_int_enable, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) { @@ -181,7 +181,7 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) return 0; } -EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) { @@ -266,7 +266,7 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_ctrl_init_chip, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ctrl_init_chip, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) { @@ -329,6 +329,6 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF helpers for HDaudio platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC_I915"); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index ac505c7ad34295..c13f89b7065ec6 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -54,7 +54,7 @@ int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags, return 0; } -EXPORT_SYMBOL_NS(hda_dai_config, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dai_config, "SND_SOC_SOF_INTEL_HDA_COMMON"); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK) @@ -574,7 +574,7 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream, } return 0; } -EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON"); int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai, @@ -603,14 +603,14 @@ int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream, return 0; } -EXPORT_SYMBOL_NS(sdw_hda_dai_hw_free, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sdw_hda_dai_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai) { return hda_dai_trigger(substream, cmd, cpu_dai); } -EXPORT_SYMBOL_NS(sdw_hda_dai_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sdw_hda_dai_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); static int hda_dai_suspend(struct hdac_bus *bus) { @@ -646,6 +646,10 @@ static int hda_dai_suspend(struct hdac_bus *bus) sdai = swidget->private; ops = sdai->platform_private; + if (rtd->dpcm[hext_stream->link_substream->stream].state != + SND_SOC_DPCM_STATE_PAUSED) + continue; + /* for consistency with TRIGGER_SUSPEND */ if (ops->post_trigger) { ret = ops->post_trigger(sdev, cpu_dai, @@ -725,7 +729,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops) ipc4_data->nhlt = intel_nhlt_init(sdev->dev); } } -EXPORT_SYMBOL_NS(hda_set_dai_drv_ops, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_set_dai_drv_ops, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_ops_free(struct snd_sof_dev *sdev) { @@ -739,7 +743,7 @@ void hda_ops_free(struct snd_sof_dev *sdev) sdev->private = NULL; } } -EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_ops_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* * common dai driver for skl+ platforms. @@ -891,7 +895,7 @@ struct snd_soc_dai_driver skl_dai[] = { }, #endif }; -EXPORT_SYMBOL_NS(skl_dai, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(skl_dai, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_dais_suspend(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 4c88522d404847..ccf8eefdca707c 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -90,7 +90,7 @@ u32 hda_get_interface_mask(struct snd_sof_dev *sdev) return interface_mask[sdev->dspless_mode_selected]; } -EXPORT_SYMBOL_NS(hda_get_interface_mask, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_get_interface_mask, "SND_SOC_SOF_INTEL_HDA_COMMON"); bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type) { @@ -120,7 +120,7 @@ bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type) return false; } } -EXPORT_SYMBOL_NS(hda_is_chain_dma_supported, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_is_chain_dma_supported, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* * DSP Core control. @@ -216,7 +216,7 @@ int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) /* set reset state */ return hda_dsp_core_reset_enter(sdev, core_mask); } -EXPORT_SYMBOL_NS(hda_dsp_core_stall_reset, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_core_stall_reset, "SND_SOC_SOF_INTEL_HDA_COMMON"); bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask) { @@ -242,7 +242,7 @@ bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask) return is_enable; } -EXPORT_SYMBOL_NS(hda_dsp_core_is_enabled, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_core_is_enabled, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) { @@ -270,7 +270,7 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_core_run, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_core_run, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* * Power Management. @@ -322,7 +322,7 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_core_power_up, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_core_power_up, "SND_SOC_SOF_INTEL_HDA_COMMON"); static int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) { @@ -370,7 +370,7 @@ int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask) return hda_dsp_core_run(sdev, core_mask); } -EXPORT_SYMBOL_NS(hda_dsp_enable_core, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_enable_core, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) @@ -411,7 +411,7 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, return ret; } -EXPORT_SYMBOL_NS(hda_dsp_core_reset_power_down, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_core_reset_power_down, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) { @@ -430,7 +430,7 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); } -EXPORT_SYMBOL_NS(hda_dsp_ipc_int_enable, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) { @@ -448,7 +448,7 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } -EXPORT_SYMBOL_NS(hda_dsp_ipc_int_disable, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc_int_disable, "SND_SOC_SOF_INTEL_HDA_COMMON"); static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev) { @@ -732,7 +732,7 @@ int hda_dsp_set_power_state_ipc3(struct snd_sof_dev *sdev, return hda_dsp_set_power_state(sdev, target_state); } -EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc3, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc3, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_set_power_state_ipc4(struct snd_sof_dev *sdev, const struct sof_dsp_power_state *target_state) @@ -744,7 +744,7 @@ int hda_dsp_set_power_state_ipc4(struct snd_sof_dev *sdev, return hda_dsp_set_power_state(sdev, target_state); } -EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc4, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc4, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* * Audio DSP states may transform as below:- @@ -858,7 +858,6 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) { - const struct sof_intel_dsp_desc *chip; int ret; /* display codec must be powered before link reset */ @@ -891,10 +890,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) hda_dsp_ctrl_ppcap_int_enable(sdev, true); } - chip = get_chip_info(sdev->pdata); - if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0) - hda_sdw_int_enable(sdev, true); - cleanup: /* display codec can powered off after controller init */ hda_codec_i915_display_power(sdev, false); @@ -953,7 +948,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev) return snd_sof_dsp_set_power_state(sdev, &target_state); } -EXPORT_SYMBOL_NS(hda_dsp_resume, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_resume, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) { @@ -969,7 +964,7 @@ int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) return snd_sof_dsp_set_power_state(sdev, &target_state); } -EXPORT_SYMBOL_NS(hda_dsp_runtime_resume, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_runtime_resume, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_runtime_idle(struct snd_sof_dev *sdev) { @@ -983,7 +978,7 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(hda_dsp_runtime_idle, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_runtime_idle, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) { @@ -1005,7 +1000,7 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) return snd_sof_dsp_set_power_state(sdev, &target_state); } -EXPORT_SYMBOL_NS(hda_dsp_runtime_suspend, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_runtime_suspend, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) { @@ -1066,7 +1061,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); } -EXPORT_SYMBOL_NS(hda_dsp_suspend, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_suspend, "SND_SOC_SOF_INTEL_HDA_COMMON"); static unsigned int hda_dsp_check_for_dma_streams(struct snd_sof_dev *sdev) { @@ -1139,14 +1134,14 @@ int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_shutdown_dma_flush, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_shutdown_dma_flush, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_shutdown(struct snd_sof_dev *sdev) { sdev->system_suspend_target = SOF_SUSPEND_S3; return snd_sof_suspend(sdev->dev); } -EXPORT_SYMBOL_NS(hda_dsp_shutdown, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_shutdown, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { @@ -1159,7 +1154,7 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_set_hw_params_upon_resume, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_set_hw_params_upon_resume, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_d0i3_work(struct work_struct *work) { @@ -1186,7 +1181,7 @@ void hda_dsp_d0i3_work(struct work_struct *work) "error: failed to set DSP state %d substate %d\n", target_state.state, target_state.substate); } -EXPORT_SYMBOL_NS(hda_dsp_d0i3_work, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_d0i3_work, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_core_get(struct snd_sof_dev *sdev, int core) { @@ -1227,7 +1222,7 @@ int hda_dsp_core_get(struct snd_sof_dev *sdev, int core) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_core_get, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_core_get, "SND_SOC_SOF_INTEL_HDA_COMMON"); #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) @@ -1243,7 +1238,7 @@ void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) HDA_DSP_REG_ADSPIC2_SNDW, enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0); } -EXPORT_SYMBOL_NS(hda_common_enable_sdw_irq, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_common_enable_sdw_irq, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { @@ -1257,7 +1252,7 @@ void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) if (chip && chip->enable_sdw_irq) chip->enable_sdw_irq(sdev, enable); } -EXPORT_SYMBOL_NS(hda_sdw_int_enable, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_sdw_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev) { @@ -1281,7 +1276,7 @@ int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(hda_sdw_check_lcount_common, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_sdw_check_lcount_common, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev) { @@ -1307,7 +1302,7 @@ int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(hda_sdw_check_lcount_ext, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_sdw_check_lcount_ext, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_sdw_check_lcount(struct snd_sof_dev *sdev) { @@ -1319,7 +1314,7 @@ int hda_sdw_check_lcount(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(hda_sdw_check_lcount, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_sdw_check_lcount, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { @@ -1333,7 +1328,7 @@ void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) if (chip && chip->sdw_process_wakeen) chip->sdw_process_wakeen(sdev); } -EXPORT_SYMBOL_NS(hda_sdw_process_wakeen, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_sdw_process_wakeen, "SND_SOC_SOF_INTEL_HDA_COMMON"); #endif @@ -1344,7 +1339,7 @@ int hda_dsp_disable_interrupts(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(hda_dsp_disable_interrupts, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_disable_interrupts, "SND_SOC_SOF_INTEL_HDA_COMMON"); static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = { {HDA_DSP_ROM_CSE_ERROR, "error: cse error"}, @@ -1555,7 +1550,7 @@ void hda_dsp_get_state(struct snd_sof_dev *sdev, const char *level) dev_printk(level, sdev->dev, "error code: %#x (%s)\n", error_code, error_text); } -EXPORT_SYMBOL_NS(hda_dsp_get_state, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_get_state, "SND_SOC_SOF_INTEL_HDA_COMMON"); static void hda_dsp_get_registers(struct snd_sof_dev *sdev, struct sof_ipc_dsp_oops_xtensa *xoops, @@ -1628,4 +1623,4 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) hda_dsp_dump_ext_rom_status(sdev, level, flags); } } -EXPORT_SYMBOL_NS(hda_dsp_dump, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_dump, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 9feaaa2d166acc..f3fbf43a70c2bb 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -72,7 +72,7 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -EXPORT_SYMBOL_NS(hda_dsp_ipc_send_msg, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc_send_msg, "SND_SOC_SOF_INTEL_HDA_COMMON"); static inline bool hda_dsp_ipc4_pm_msg(u32 primary) { @@ -99,7 +99,7 @@ void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev, mod_delayed_work(system_wq, &hdev->d0i3_work, msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS)); } -EXPORT_SYMBOL_NS(hda_dsp_ipc4_schedule_d0i3_work, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc4_schedule_d0i3_work, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { @@ -126,7 +126,7 @@ int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -EXPORT_SYMBOL_NS(hda_dsp_ipc4_send_msg, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc4_send_msg, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) { @@ -162,7 +162,7 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) snd_sof_ipc_get_reply(sdev); } } -EXPORT_SYMBOL_NS(hda_dsp_ipc_get_reply, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc_get_reply, "SND_SOC_SOF_INTEL_HDA_COMMON"); irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) { @@ -245,7 +245,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(hda_dsp_ipc4_irq_thread, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc4_irq_thread, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* IPC handler thread */ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) @@ -358,7 +358,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(hda_dsp_ipc_irq_thread, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc_irq_thread, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* Check if an IPC IRQ occurred */ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) @@ -392,19 +392,19 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) out: return ret; } -EXPORT_SYMBOL_NS(hda_dsp_check_ipc_irq, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_check_ipc_irq, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { return HDA_DSP_MBOX_UPLINK_OFFSET; } -EXPORT_SYMBOL_NS(hda_dsp_ipc_get_mailbox_offset, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc_get_mailbox_offset, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return SRAM_WINDOW_OFFSET(id); } -EXPORT_SYMBOL_NS(hda_dsp_ipc_get_window_offset, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc_get_window_offset, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, @@ -430,7 +430,7 @@ int hda_ipc_msg_data(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_NS(hda_ipc_msg_data, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_ipc_msg_data, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_set_stream_data_offset(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *sps, @@ -455,7 +455,7 @@ int hda_set_stream_data_offset(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_NS(hda_set_stream_data_offset, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_set_stream_data_offset, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_ipc4_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { @@ -469,7 +469,7 @@ void hda_ipc4_dsp_dump(struct snd_sof_dev *sdev, u32 flags) else hda_dsp_dump_ext_rom_status(sdev, level, flags); } -EXPORT_SYMBOL_NS(hda_ipc4_dsp_dump, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_ipc4_dsp_dump, "SND_SOC_SOF_INTEL_HDA_COMMON"); bool hda_check_ipc_irq(struct snd_sof_dev *sdev) { @@ -481,7 +481,7 @@ bool hda_check_ipc_irq(struct snd_sof_dev *sdev) return false; } -EXPORT_SYMBOL_NS(hda_check_ipc_irq, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_check_ipc_irq, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_ipc_irq_dump(struct snd_sof_dev *sdev) { @@ -502,7 +502,7 @@ void hda_ipc_irq_dump(struct snd_sof_dev *sdev) intsts, intctl, rirbsts); dev_err(sdev->dev, "dsp irq ppsts 0x%8.8x adspis 0x%8.8x\n", ppsts, adspis); } -EXPORT_SYMBOL_NS(hda_ipc_irq_dump, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_ipc_irq_dump, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_ipc_dump(struct snd_sof_dev *sdev) { @@ -522,7 +522,7 @@ void hda_ipc_dump(struct snd_sof_dev *sdev) dev_err(sdev->dev, "host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", hipcie, hipct, hipcctl); } -EXPORT_SYMBOL_NS(hda_ipc_dump, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_ipc_dump, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_ipc4_dump(struct snd_sof_dev *sdev) { @@ -541,7 +541,7 @@ void hda_ipc4_dump(struct snd_sof_dev *sdev) dev_err(sdev->dev, "Host IPC initiator: %#x|%#x, target: %#x|%#x, ctl: %#x\n", hipci, hipcie, hipct, hipcte, hipcctl); } -EXPORT_SYMBOL_NS(hda_ipc4_dump, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_ipc4_dump, "SND_SOC_SOF_INTEL_HDA_COMMON"); bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev) { @@ -553,4 +553,4 @@ bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev) return !!(val & chip->ipc_req_mask); } -EXPORT_SYMBOL_NS(hda_ipc4_tx_is_busy, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_ipc4_tx_is_busy, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 9d8ebb7c6a1060..49085ca7b46bf0 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -26,6 +26,11 @@ #include "../sof-priv.h" #include "hda.h" +static bool persistent_cl_buffer = true; +module_param(persistent_cl_buffer, bool, 0444); +MODULE_PARM_DESC(persistent_cl_buffer, "Persistent Code Loader DMA buffer " + "(default = Y, use N to force buffer re-allocation)"); + static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; @@ -43,9 +48,10 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev) } } -struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, - unsigned int size, struct snd_dma_buffer *dmab, - int direction, bool is_iccmax) +struct hdac_ext_stream* +hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size, + struct snd_dma_buffer *dmab, bool persistent_buffer, int direction, + bool is_iccmax) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct hdac_ext_stream *hext_stream; @@ -61,11 +67,19 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, hstream = &hext_stream->hstream; hstream->substream = NULL; - /* allocate DMA buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab); - if (ret < 0) { - dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret); - goto out_put; + /* + * Allocate DMA buffer if it is temporary or if the buffer is intended + * to be persistent but not yet allocated. + * We cannot rely solely on !dmab->area as caller might use a struct on + * stack (when it is temporary) without clearing it to 0. + */ + if (!persistent_buffer || !dmab->area) { + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab); + if (ret < 0) { + dev_err(sdev->dev, "%s: memory alloc failed: %d\n", + __func__, ret); + goto out_put; + } } hstream->period_bytes = 0;/* initialize period_bytes */ @@ -91,11 +105,15 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, out_free: snd_dma_free_pages(dmab); + dmab->area = NULL; + dmab->bytes = 0; + hstream->bufsize = 0; + hstream->format_val = 0; out_put: hda_dsp_stream_put(sdev, direction, hstream->stream_tag); return ERR_PTR(ret); } -EXPORT_SYMBOL_NS(hda_cl_prepare, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_cl_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* * first boot sequence has some extra steps. @@ -219,7 +237,7 @@ int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) kfree(dump_msg); return ret; } -EXPORT_SYMBOL_NS(cl_dsp_init, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(cl_dsp_init, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd) { @@ -252,10 +270,10 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int return hda_dsp_stream_trigger(sdev, hext_stream, cmd); } } -EXPORT_SYMBOL_NS(hda_cl_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, - struct hdac_ext_stream *hext_stream) + bool persistent_buffer, struct hdac_ext_stream *hext_stream) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct hdac_stream *hstream = &hext_stream->hstream; @@ -279,14 +297,18 @@ int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0); snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); - snd_dma_free_pages(dmab); - dmab->area = NULL; - hstream->bufsize = 0; - hstream->format_val = 0; + + if (!persistent_buffer) { + snd_dma_free_pages(dmab); + dmab->area = NULL; + dmab->bytes = 0; + hstream->bufsize = 0; + hstream->format_val = 0; + } return ret; } -EXPORT_SYMBOL_NS(hda_cl_cleanup, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON"); #define HDA_CL_DMA_IOC_TIMEOUT_MS 500 @@ -340,8 +362,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_ext_stream *iccmax_stream; - struct snd_dma_buffer dmab_bdl; int ret, ret1; u8 original_gb; @@ -354,7 +376,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) * the data, so use a buffer of PAGE_SIZE for receiving. */ iccmax_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, PAGE_SIZE, - &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE, true); + &hda->iccmax_dmab, persistent_cl_buffer, + SNDRV_PCM_STREAM_CAPTURE, true); if (IS_ERR(iccmax_stream)) { dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n"); return PTR_ERR(iccmax_stream); @@ -366,7 +389,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) * Perform iccmax stream cleanup. This should be done even if firmware loading fails. * If the cleanup also fails, we return the initial error */ - ret1 = hda_cl_cleanup(sdev->dev, &dmab_bdl, iccmax_stream); + ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab, + persistent_cl_buffer, iccmax_stream); if (ret1 < 0) { dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); @@ -381,7 +405,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware_iccmax, SND_SOC_SOF_INTEL_CNL); +EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware_iccmax, "SND_SOC_SOF_INTEL_CNL"); static int hda_dsp_boot_imr(struct snd_sof_dev *sdev) { @@ -408,7 +432,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) const struct sof_intel_dsp_desc *chip_info; struct hdac_ext_stream *hext_stream; struct firmware stripped_firmware; - struct snd_dma_buffer dmab; int ret, ret1, i; if (hda->imrboot_supported && !sdev->first_boot && !hda->skip_imr_boot) { @@ -432,23 +455,31 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) return -EINVAL; } - stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset; - stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset; - /* init for booting wait */ init_waitqueue_head(&sdev->boot_wait); /* prepare DMA for code loader stream */ + stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset; hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, - &dmab, SNDRV_PCM_STREAM_PLAYBACK, false); + &hda->cl_dmab, persistent_cl_buffer, + SNDRV_PCM_STREAM_PLAYBACK, false); if (IS_ERR(hext_stream)) { dev_err(sdev->dev, "error: dma prepare for fw loading failed\n"); return PTR_ERR(hext_stream); } - memcpy(dmab.area, stripped_firmware.data, - stripped_firmware.size); + /* + * Copy the payload to the DMA buffer if it is temporary or if the + * buffer is persistent but it does not have the basefw payload either + * because this is the first boot and the buffer needs to be initialized, + * or a library got loaded and it replaced the basefw. + */ + if (!persistent_cl_buffer || !hda->cl_dmab_contains_basefw) { + stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset; + memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size); + hda->cl_dmab_contains_basefw = true; + } /* try ROM init a few times before giving up */ for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { @@ -514,7 +545,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) * This should be done even if firmware loading fails. * If the cleanup also fails, we return the initial error */ - ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream); + ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, + persistent_cl_buffer, hext_stream); if (ret1 < 0) { dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); @@ -535,7 +567,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, struct sof_ipc4_fw_library *fw_lib, bool reload) @@ -545,7 +577,6 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream; struct firmware stripped_firmware; struct sof_ipc4_msg msg = {}; - struct snd_dma_buffer dmab; int ret, ret1; /* if IMR booting is enabled and fw context is saved for D3 state, skip the loading */ @@ -556,16 +587,28 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset; stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset; + /* + * force re-allocation of the cl_dmab if the preserved DMA buffer is + * smaller than what is needed for the library + */ + if (persistent_cl_buffer && stripped_firmware.size > hda->cl_dmab.bytes) { + snd_dma_free_pages(&hda->cl_dmab); + hda->cl_dmab.area = NULL; + hda->cl_dmab.bytes = 0; + } + /* prepare DMA for code loader stream */ hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, - &dmab, SNDRV_PCM_STREAM_PLAYBACK, false); + &hda->cl_dmab, persistent_cl_buffer, + SNDRV_PCM_STREAM_PLAYBACK, false); if (IS_ERR(hext_stream)) { dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__); return PTR_ERR(hext_stream); } - memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size); + memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size); + hda->cl_dmab_contains_basefw = false; /* * 1st stage: SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE @@ -628,7 +671,8 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, cleanup: /* clean up even in case of error and return the first error */ - ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream); + ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer, + hext_stream); if (ret1 < 0) { dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__); @@ -639,7 +683,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, return ret; } -EXPORT_SYMBOL_NS(hda_dsp_ipc4_load_library, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ipc4_load_library, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, const struct sof_ext_man_elem_header *hdr) @@ -678,4 +722,4 @@ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_NS(hda_dsp_ext_man_get_cavs_config_data, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_ext_man_get_cavs_config_data, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index 9a3559c78b6279..fe627bcb0531a0 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -434,7 +434,7 @@ int hda_bus_ml_init(struct hdac_bus *bus) } return 0; } -EXPORT_SYMBOL_NS(hda_bus_ml_init, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hda_bus_ml_init, "SND_SOC_SOF_HDA_MLINK"); void hda_bus_ml_free(struct hdac_bus *bus) { @@ -452,7 +452,7 @@ void hda_bus_ml_free(struct hdac_bus *bus) kfree(h2link); } } -EXPORT_SYMBOL_NS(hda_bus_ml_free, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hda_bus_ml_free, "SND_SOC_SOF_HDA_MLINK"); static struct hdac_ext2_link * find_ext2_link(struct hdac_bus *bus, bool alt, int elid) @@ -479,7 +479,25 @@ int hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid) return h2link->slcount; } -EXPORT_SYMBOL_NS(hdac_bus_eml_get_count, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_get_count, "SND_SOC_SOF_HDA_MLINK"); + +void hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int elid, bool enable) +{ + struct hdac_ext2_link *h2link; + struct hdac_ext_link *hlink; + + h2link = find_ext2_link(bus, alt, elid); + if (!h2link) + return; + + if (!h2link->intc) + return; + + hlink = &h2link->hext_link; + + hdaml_link_enable_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL, enable); +} +EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt_unlocked, "SND_SOC_SOF_HDA_MLINK"); void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable) { @@ -501,7 +519,7 @@ void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, boo mutex_unlock(&h2link->eml_lock); } -EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt, "SND_SOC_SOF_HDA_MLINK"); bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid) { @@ -519,7 +537,7 @@ bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid) return hdaml_link_check_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL); } -EXPORT_SYMBOL_NS(hdac_bus_eml_check_interrupt, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_check_interrupt, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_set_syncprd_unlocked(struct hdac_bus *bus, bool alt, int elid, u32 syncprd) { @@ -539,13 +557,13 @@ int hdac_bus_eml_set_syncprd_unlocked(struct hdac_bus *bus, bool alt, int elid, return 0; } -EXPORT_SYMBOL_NS(hdac_bus_eml_set_syncprd_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_set_syncprd_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_sdw_set_syncprd_unlocked(struct hdac_bus *bus, u32 syncprd) { return hdac_bus_eml_set_syncprd_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, syncprd); } -EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_syncprd_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_syncprd_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_wait_syncpu_unlocked(struct hdac_bus *bus, bool alt, int elid) { @@ -563,13 +581,13 @@ int hdac_bus_eml_wait_syncpu_unlocked(struct hdac_bus *bus, bool alt, int elid) return hdaml_link_wait_syncpu(hlink->ml_addr + AZX_REG_ML_LSYNC); } -EXPORT_SYMBOL_NS(hdac_bus_eml_wait_syncpu_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_wait_syncpu_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_sdw_wait_syncpu_unlocked(struct hdac_bus *bus) { return hdac_bus_eml_wait_syncpu_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW); } -EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_wait_syncpu_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_wait_syncpu_unlocked, "SND_SOC_SOF_HDA_MLINK"); void hdac_bus_eml_sync_arm_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink) { @@ -587,13 +605,13 @@ void hdac_bus_eml_sync_arm_unlocked(struct hdac_bus *bus, bool alt, int elid, in hdaml_link_sync_arm(hlink->ml_addr + AZX_REG_ML_LSYNC, sublink); } -EXPORT_SYMBOL_NS(hdac_bus_eml_sync_arm_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sync_arm_unlocked, "SND_SOC_SOF_HDA_MLINK"); void hdac_bus_eml_sdw_sync_arm_unlocked(struct hdac_bus *bus, int sublink) { hdac_bus_eml_sync_arm_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink); } -EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_arm_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_arm_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_sync_go_unlocked(struct hdac_bus *bus, bool alt, int elid) { @@ -613,13 +631,13 @@ int hdac_bus_eml_sync_go_unlocked(struct hdac_bus *bus, bool alt, int elid) return 0; } -EXPORT_SYMBOL_NS(hdac_bus_eml_sync_go_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sync_go_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_sdw_sync_go_unlocked(struct hdac_bus *bus) { return hdac_bus_eml_sync_go_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW); } -EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_go_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_go_unlocked, "SND_SOC_SOF_HDA_MLINK"); bool hdac_bus_eml_check_cmdsync_unlocked(struct hdac_bus *bus, bool alt, int elid) { @@ -642,13 +660,13 @@ bool hdac_bus_eml_check_cmdsync_unlocked(struct hdac_bus *bus, bool alt, int eli return hdaml_link_check_cmdsync(hlink->ml_addr + AZX_REG_ML_LSYNC, cmdsync_mask); } -EXPORT_SYMBOL_NS(hdac_bus_eml_check_cmdsync_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_check_cmdsync_unlocked, "SND_SOC_SOF_HDA_MLINK"); bool hdac_bus_eml_sdw_check_cmdsync_unlocked(struct hdac_bus *bus) { return hdac_bus_eml_check_cmdsync_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW); } -EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_check_cmdsync_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_check_cmdsync_unlocked, "SND_SOC_SOF_HDA_MLINK"); static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid, int sublink, bool eml_lock) @@ -690,13 +708,13 @@ int hdac_bus_eml_power_up(struct hdac_bus *bus, bool alt, int elid, int sublink) { return hdac_bus_eml_power_up_base(bus, alt, elid, sublink, true); } -EXPORT_SYMBOL_NS(hdac_bus_eml_power_up, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_power_up, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_power_up_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink) { return hdac_bus_eml_power_up_base(bus, alt, elid, sublink, false); } -EXPORT_SYMBOL_NS(hdac_bus_eml_power_up_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_power_up_unlocked, "SND_SOC_SOF_HDA_MLINK"); static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid, int sublink, bool eml_lock) @@ -737,25 +755,25 @@ int hdac_bus_eml_power_down(struct hdac_bus *bus, bool alt, int elid, int sublin { return hdac_bus_eml_power_down_base(bus, alt, elid, sublink, true); } -EXPORT_SYMBOL_NS(hdac_bus_eml_power_down, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_power_down, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_power_down_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink) { return hdac_bus_eml_power_down_base(bus, alt, elid, sublink, false); } -EXPORT_SYMBOL_NS(hdac_bus_eml_power_down_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_power_down_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink) { return hdac_bus_eml_power_up_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink); } -EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_up_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_up_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink) { return hdac_bus_eml_power_down_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink); } -EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid) { @@ -771,7 +789,7 @@ int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink)); return 0; -} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK); +} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) { @@ -791,7 +809,7 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num) mutex_unlock(&h2link->eml_lock); return 0; -} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_lsdiid, SND_SOC_SOF_HDA_MLINK); +} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_lsdiid, "SND_SOC_SOF_HDA_MLINK"); /* * the 'y' parameter comes from the PCMSyCM hardware register naming. 'y' refers to the @@ -835,7 +853,7 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y, sublink, channel_mask, stream_id, dir, val); return 0; -} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK); +} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, "SND_SOC_SOF_HDA_MLINK"); void hda_bus_ml_put_all(struct hdac_bus *bus) { @@ -848,7 +866,7 @@ void hda_bus_ml_put_all(struct hdac_bus *bus) snd_hdac_ext_bus_link_put(bus, hlink); } } -EXPORT_SYMBOL_NS(hda_bus_ml_put_all, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK"); void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { @@ -858,7 +876,7 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus) list_for_each_entry(hlink, &bus->hlink_list, list) writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); } -EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK"); int hda_bus_ml_resume(struct hdac_bus *bus) { @@ -877,7 +895,7 @@ int hda_bus_ml_resume(struct hdac_bus *bus) } return 0; } -EXPORT_SYMBOL_NS(hda_bus_ml_resume, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hda_bus_ml_resume, "SND_SOC_SOF_HDA_MLINK"); int hda_bus_ml_suspend(struct hdac_bus *bus) { @@ -895,7 +913,7 @@ int hda_bus_ml_suspend(struct hdac_bus *bus) } return 0; } -EXPORT_SYMBOL_NS(hda_bus_ml_suspend, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hda_bus_ml_suspend, "SND_SOC_SOF_HDA_MLINK"); struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid) { @@ -907,7 +925,7 @@ struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid) return &h2link->eml_lock; } -EXPORT_SYMBOL_NS(hdac_bus_eml_get_mutex, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_get_mutex, "SND_SOC_SOF_HDA_MLINK"); struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus) { @@ -919,7 +937,7 @@ struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus) return &h2link->hext_link; } -EXPORT_SYMBOL_NS(hdac_bus_eml_ssp_get_hlink, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_ssp_get_hlink, "SND_SOC_SOF_HDA_MLINK"); struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus) { @@ -931,7 +949,7 @@ struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus) return &h2link->hext_link; } -EXPORT_SYMBOL_NS(hdac_bus_eml_dmic_get_hlink, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_dmic_get_hlink, "SND_SOC_SOF_HDA_MLINK"); struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus) { @@ -943,7 +961,7 @@ struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus) return &h2link->hext_link; } -EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_hlink, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_hlink, "SND_SOC_SOF_HDA_MLINK"); int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable) { @@ -967,7 +985,7 @@ int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool e return 0; } -EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, SND_SOC_SOF_HDA_MLINK); +EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, "SND_SOC_SOF_HDA_MLINK"); #endif diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index f6e24edd7adbe9..5b5e484f9acf1a 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -142,7 +142,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_NS(hda_dsp_pcm_hw_params, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_pcm_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON"); /* update SPIB register with appl position */ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) @@ -165,7 +165,7 @@ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substrea return 0; } -EXPORT_SYMBOL_NS(hda_dsp_pcm_ack, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_pcm_ack, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd) @@ -175,7 +175,7 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, return hda_dsp_stream_trigger(sdev, hext_stream, cmd); } -EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) @@ -207,7 +207,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, trace_sof_intel_hda_dsp_pcm(sdev, hstream, substream, pos); return pos; } -EXPORT_SYMBOL_NS(hda_dsp_pcm_pointer, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_pcm_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) @@ -302,7 +302,7 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_NS(hda_dsp_pcm_open, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_pcm_open, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) @@ -322,4 +322,4 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev, substream->runtime->private_data = NULL; return 0; } -EXPORT_SYMBOL_NS(hda_dsp_pcm_close, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_pcm_close, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda-probes.c b/sound/soc/sof/intel/hda-probes.c index 3e33101f052102..c645346c2c847c 100644 --- a/sound/soc/sof/intel/hda-probes.c +++ b/sound/soc/sof/intel/hda-probes.c @@ -139,12 +139,12 @@ int hda_probes_register(struct snd_sof_dev *sdev) return sof_client_dev_register(sdev, "hda-probes", 0, &hda_probes_ops, sizeof(hda_probes_ops)); } -EXPORT_SYMBOL_NS(hda_probes_register, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_probes_register, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_probes_unregister(struct snd_sof_dev *sdev) { sof_client_dev_unregister(sdev, "hda-probes", 0); } -EXPORT_SYMBOL_NS(hda_probes_unregister, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_probes_unregister, "SND_SOC_SOF_INTEL_HDA_COMMON"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 3ac63ce67ab1ce..aa6b0247d5c99e 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -27,7 +27,7 @@ int sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS; module_param_named(position_quirk, sof_hda_position_quirk, int, 0444); MODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk"); -EXPORT_SYMBOL_NS(sof_hda_position_quirk, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sof_hda_position_quirk, "SND_SOC_SOF_INTEL_HDA_COMMON"); #define HDA_LTRP_GB_VALUE_US 95 @@ -119,13 +119,39 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, int remain, ioc; period_bytes = hstream->period_bytes; - dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes); - if (!period_bytes) + dev_dbg(sdev->dev, "period_bytes: %#x, bufsize: %#x\n", period_bytes, + hstream->bufsize); + + if (!period_bytes) { + unsigned int chunk_size; + + chunk_size = snd_sgbuf_get_chunk_size(dmab, 0, hstream->bufsize); + period_bytes = hstream->bufsize; + /* + * HDA spec demands that the LVI value must be at least one + * before the DMA operation can begin. This means that there + * must be at least two BDLE present for the transfer. + * + * If the buffer is not a single continuous area then the + * hda_setup_bdle() will create multiple BDLEs for each segment. + * If the memory is a single continuous area, force it to be + * split into two 'periods', otherwise the transfer will be + * split to multiple BDLE for each chunk in hda_setup_bdle() + * + * Note: period_bytes == 0 can only happen for firmware or + * library loading. The data size is 4K aligned, which ensures + * that the second chunk's start address will be 128-byte + * aligned. + */ + if (chunk_size == hstream->bufsize) + period_bytes /= 2; + } + periods = hstream->bufsize / period_bytes; - dev_dbg(sdev->dev, "periods:%d\n", periods); + dev_dbg(sdev->dev, "periods: %d\n", periods); remain = hstream->bufsize % period_bytes; if (remain) @@ -712,7 +738,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) { @@ -735,7 +761,7 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_check_stream_irq, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_check_stream_irq, "SND_SOC_SOF_INTEL_HDA_COMMON"); static void hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction) @@ -832,7 +858,7 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(hda_dsp_stream_threaded_handler, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_stream_threaded_handler, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_stream_init(struct snd_sof_dev *sdev) { @@ -970,7 +996,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS(hda_dsp_stream_init, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_stream_init, "SND_SOC_SOF_INTEL_HDA_COMMON"); void hda_dsp_stream_free(struct snd_sof_dev *sdev) { @@ -1000,7 +1026,7 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev) devm_kfree(sdev->dev, hda_stream); } } -EXPORT_SYMBOL_NS(hda_dsp_stream_free, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_stream_free, "SND_SOC_SOF_INTEL_HDA_COMMON"); snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream, int direction, bool can_sleep) @@ -1087,7 +1113,7 @@ snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream, return pos; } -EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, "SND_SOC_SOF_INTEL_HDA_COMMON"); #define merge_u64(u32_u, u32_l) (((u64)(u32_u) << 32) | (u32_l)) @@ -1127,7 +1153,7 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev, return merge_u64(llp_u, llp_l); } -EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, "SND_SOC_SOF_INTEL_HDA_COMMON"); /** * hda_dsp_get_stream_ldp - Retrieve the LDP (Linear DMA Position) of the stream @@ -1159,4 +1185,4 @@ u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev, return ((u64)ldp_u << 32) | ldp_l; } -EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 351eb2eb184bc1..5da8188ffcfe1f 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -68,7 +68,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, return ret; } -EXPORT_SYMBOL_NS(hda_dsp_trace_init, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_trace_init, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_trace_release(struct snd_sof_dev *sdev) { @@ -87,7 +87,7 @@ int hda_dsp_trace_release(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "DMA trace stream is not opened!\n"); return -ENODEV; } -EXPORT_SYMBOL_NS(hda_dsp_trace_release, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_trace_release, "SND_SOC_SOF_INTEL_HDA_COMMON"); int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd) { @@ -95,4 +95,4 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd) return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd); } -EXPORT_SYMBOL_NS(hda_dsp_trace_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_trace_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 70fc08c8fc99e2..f991785f727e9e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -238,7 +238,7 @@ int hda_sdw_startup(struct snd_sof_dev *sdev) return sdw_intel_startup(hdev->sdw); } -EXPORT_SYMBOL_NS(hda_sdw_startup, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_sdw_startup, "SND_SOC_SOF_INTEL_HDA_GENERIC"); static int hda_sdw_exit(struct snd_sof_dev *sdev) { @@ -280,7 +280,7 @@ bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev) out: return ret; } -EXPORT_SYMBOL_NS(hda_common_check_sdw_irq, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_common_check_sdw_irq, "SND_SOC_SOF_INTEL_HDA_GENERIC"); static bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev) { @@ -314,7 +314,7 @@ bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev) return false; } -EXPORT_SYMBOL_NS(hda_sdw_check_wakeen_irq_common, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_sdw_check_wakeen_irq_common, "SND_SOC_SOF_INTEL_HDA_GENERIC"); static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) { @@ -345,7 +345,7 @@ void hda_sdw_process_wakeen_common(struct snd_sof_dev *sdev) sdw_intel_process_wakeen_event(hdev->sdw); } -EXPORT_SYMBOL_NS(hda_sdw_process_wakeen_common, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_sdw_process_wakeen_common, "SND_SOC_SOF_INTEL_HDA_GENERIC"); #else /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */ static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) @@ -418,7 +418,7 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) /* re-enable clock gating and power gating */ return hda_dsp_ctrl_clock_power_gating(sdev, true); } -EXPORT_SYMBOL_NS(hda_dsp_post_fw_run, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_dsp_post_fw_run, "SND_SOC_SOF_INTEL_HDA_GENERIC"); /* * Debug @@ -739,7 +739,7 @@ int hda_dsp_probe_early(struct snd_sof_dev *sdev) err: return ret; } -EXPORT_SYMBOL_NS(hda_dsp_probe_early, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_dsp_probe_early, "SND_SOC_SOF_INTEL_HDA_GENERIC"); int hda_dsp_probe(struct snd_sof_dev *sdev) { @@ -866,8 +866,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) dev_err(sdev->dev, "could not startup SoundWire links\n"); goto disable_pp_cap; } - - hda_sdw_int_enable(sdev, true); } init_waitqueue_head(&hdev->waitq); @@ -896,7 +894,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(hda_dsp_probe, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_dsp_probe, "SND_SOC_SOF_INTEL_HDA_GENERIC"); void hda_dsp_remove(struct snd_sof_dev *sdev) { @@ -938,6 +936,12 @@ void hda_dsp_remove(struct snd_sof_dev *sdev) /* disable DSP */ hda_dsp_ctrl_ppcap_enable(sdev, false); + /* Free the persistent DMA buffers used for base firmware download */ + if (hda->cl_dmab.area) + snd_dma_free_pages(&hda->cl_dmab); + if (hda->iccmax_dmab.area) + snd_dma_free_pages(&hda->iccmax_dmab); + skip_disable_dsp: free_irq(sdev->ipc_irq, sdev); if (sdev->msi_enabled) @@ -950,7 +954,7 @@ void hda_dsp_remove(struct snd_sof_dev *sdev) if (!sdev->dspless_mode_selected) iounmap(sdev->bar[HDA_DSP_BAR]); } -EXPORT_SYMBOL_NS(hda_dsp_remove, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_dsp_remove, "SND_SOC_SOF_INTEL_HDA_GENERIC"); void hda_dsp_remove_late(struct snd_sof_dev *sdev) { @@ -966,7 +970,7 @@ int hda_power_down_dsp(struct snd_sof_dev *sdev) return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask); } -EXPORT_SYMBOL_NS(hda_power_down_dsp, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_power_down_dsp, "SND_SOC_SOF_INTEL_HDA_GENERIC"); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) static void hda_generic_machine_select(struct snd_sof_dev *sdev, @@ -1066,7 +1070,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev { struct snd_sof_pdata *pdata = sdev->pdata; const struct snd_soc_acpi_link_adr *link; - struct sdw_extended_slave_id *ids; + struct sdw_peripherals *peripherals; struct snd_soc_acpi_mach *mach; struct sof_intel_hda_dev *hdev; u32 link_mask; @@ -1085,7 +1089,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev return NULL; } - if (!hdev->sdw->num_slaves) { + if (!hdev->sdw->peripherals || !hdev->sdw->peripherals->num_peripherals) { dev_warn(sdev->dev, "No SoundWire peripheral detected in ACPI tables\n"); return NULL; } @@ -1121,13 +1125,13 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev * are not found on this link. */ if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link, - hdev->sdw->ids, - hdev->sdw->num_slaves)) + hdev->sdw->peripherals)) break; } /* Found if all Slaves are checked */ if (i == hdev->info.count || !link->num_adr) - break; + if (!mach->machine_check || mach->machine_check(hdev->sdw)) + break; } if (mach && mach->link_mask) { mach->mach_params.links = mach->links; @@ -1138,10 +1142,13 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev } dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n"); - ids = hdev->sdw->ids; - for (i = 0; i < hdev->sdw->num_slaves; i++) + peripherals = hdev->sdw->peripherals; + for (i = 0; i < peripherals->num_peripherals; i++) dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n", - ids[i].link_id, ids[i].id.mfg_id, ids[i].id.part_id, ids[i].id.sdw_version); + peripherals->array[i]->bus->link_id, + peripherals->array[i]->id.mfg_id, + peripherals->array[i]->id.part_id, + peripherals->array[i]->id.sdw_version); return NULL; } @@ -1464,7 +1471,7 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return sof_pci_probe(pci, pci_id); } -EXPORT_SYMBOL_NS(hda_pci_intel_probe, SND_SOC_SOF_INTEL_HDA_GENERIC); +EXPORT_SYMBOL_NS(hda_pci_intel_probe, "SND_SOC_SOF_INTEL_HDA_GENERIC"); int hda_register_clients(struct snd_sof_dev *sdev) { @@ -1478,13 +1485,13 @@ void hda_unregister_clients(struct snd_sof_dev *sdev) MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for HDaudio platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); -MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); -MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); -MODULE_IMPORT_NS(SOUNDWIRE_INTEL); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_MATCH); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC_I915"); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); +MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI"); +MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT"); +MODULE_IMPORT_NS("SOUNDWIRE_INTEL"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH"); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index b74a472435b5d2..22bd9c3c8216c5 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -495,6 +495,15 @@ struct sof_intel_hda_dev { int boot_iteration; + /* + * DMA buffers for base firmware download. By default the buffers are + * allocated once and kept through the lifetime of the driver. + * See module parameter: persistent_cl_buffer + */ + struct snd_dma_buffer cl_dmab; + bool cl_dmab_contains_basefw; + struct snd_dma_buffer iccmax_dmab; + struct hda_bus hbus; /* hw config */ @@ -714,11 +723,12 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size, struct snd_dma_buffer *dmab, - int direction, bool is_iccmax); + bool persistent_buffer, int direction, + bool is_iccmax); int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd); int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, - struct hdac_ext_stream *hext_stream); + bool persistent_buffer, struct hdac_ext_stream *hext_stream); int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); #define HDA_CL_STREAM_FORMAT 0x40 diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 3d5a1f8b17e5ca..793d8539821d46 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -22,7 +22,7 @@ /* LunarLake ops */ struct snd_sof_dsp_ops sof_lnl_ops; -EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_LNL); +EXPORT_SYMBOL_NS(sof_lnl_ops, "SND_SOC_SOF_INTEL_LNL"); static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, @@ -182,7 +182,7 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev) return 0; }; -EXPORT_SYMBOL_NS(sof_lnl_ops_init, SND_SOC_SOF_INTEL_LNL); +EXPORT_SYMBOL_NS(sof_lnl_ops_init, "SND_SOC_SOF_INTEL_LNL"); /* Check if an SDW IRQ occurred */ static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) @@ -192,16 +192,8 @@ static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW); } -static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) -{ - struct hdac_bus *bus = sof_to_bus(sdev); - - hdac_bus_eml_enable_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW, enable); -} - static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) { - lnl_enable_sdw_irq(sdev, false); mtl_disable_ipc_interrupts(sdev); return mtl_enable_interrupts(sdev, false); } @@ -237,7 +229,6 @@ const struct sof_intel_dsp_desc lnl_chip_info = { .ssp_count = MTL_SSP_COUNT, .d0i3_offset = MTL_HDA_VS_D0I3C, .read_sdw_lcount = hda_sdw_check_lcount_ext, - .enable_sdw_irq = lnl_enable_sdw_irq, .check_sdw_irq = lnl_dsp_check_sdw_irq, .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq, .sdw_process_wakeen = hda_sdw_process_wakeen_common, @@ -262,7 +253,6 @@ const struct sof_intel_dsp_desc ptl_chip_info = { .ssp_count = MTL_SSP_COUNT, .d0i3_offset = MTL_HDA_VS_D0I3C, .read_sdw_lcount = hda_sdw_check_lcount_ext, - .enable_sdw_irq = lnl_enable_sdw_irq, .check_sdw_irq = lnl_dsp_check_sdw_irq, .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq, .check_ipc_irq = mtl_dsp_check_ipc_irq, @@ -271,4 +261,4 @@ const struct sof_intel_dsp_desc ptl_chip_info = { .disable_interrupts = lnl_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_ACE_3_0, }; -EXPORT_SYMBOL_NS(ptl_chip_info, SND_SOC_SOF_INTEL_LNL); +EXPORT_SYMBOL_NS(ptl_chip_info, "SND_SOC_SOF_INTEL_LNL"); diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index 2b9d22ccf345b8..d07c68f431baf3 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -77,7 +77,7 @@ bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev) return false; } -EXPORT_SYMBOL_NS(mtl_dsp_check_ipc_irq, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_check_ipc_irq, "SND_SOC_SOF_INTEL_MTL"); /* Check if an SDW IRQ occurred */ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) @@ -121,7 +121,7 @@ int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -EXPORT_SYMBOL_NS(mtl_ipc_send_msg, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_ipc_send_msg, "SND_SOC_SOF_INTEL_MTL"); void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev) { @@ -149,7 +149,7 @@ void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0); } -EXPORT_SYMBOL_NS(mtl_disable_ipc_interrupts, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_disable_ipc_interrupts, "SND_SOC_SOF_INTEL_MTL"); static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) { @@ -234,7 +234,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) return ret; } -EXPORT_SYMBOL_NS(mtl_enable_interrupts, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL"); /* pre fw run operations */ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) @@ -297,7 +297,7 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(mtl_dsp_pre_fw_run, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_pre_fw_run, "SND_SOC_SOF_INTEL_MTL"); int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) { @@ -324,7 +324,7 @@ int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) hda_sdw_int_enable(sdev, true); return 0; } -EXPORT_SYMBOL_NS(mtl_dsp_post_fw_run, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_post_fw_run, "SND_SOC_SOF_INTEL_MTL"); void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { @@ -342,7 +342,7 @@ void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) sof_ipc4_intel_dump_telemetry_state(sdev, flags); } -EXPORT_SYMBOL_NS(mtl_dsp_dump, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_dump, "SND_SOC_SOF_INTEL_MTL"); static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev) { @@ -453,7 +453,7 @@ int mtl_power_down_dsp(struct snd_sof_dev *sdev) (dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); } -EXPORT_SYMBOL_NS(mtl_power_down_dsp, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_power_down_dsp, "SND_SOC_SOF_INTEL_MTL"); int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) { @@ -556,7 +556,7 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot) kfree(dump_msg); return ret; } -EXPORT_SYMBOL_NS(mtl_dsp_cl_init, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_cl_init, "SND_SOC_SOF_INTEL_MTL"); irqreturn_t mtl_ipc_irq_thread(int irq, void *context) { @@ -640,19 +640,19 @@ irqreturn_t mtl_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(mtl_ipc_irq_thread, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_ipc_irq_thread, "SND_SOC_SOF_INTEL_MTL"); int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { return MTL_DSP_MBOX_UPLINK_OFFSET; } -EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_mailbox_offset, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_mailbox_offset, "SND_SOC_SOF_INTEL_MTL"); int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return MTL_SRAM_WINDOW_OFFSET(id); } -EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_window_offset, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_window_offset, "SND_SOC_SOF_INTEL_MTL"); void mtl_ipc_dump(struct snd_sof_dev *sdev) { @@ -670,7 +670,7 @@ void mtl_ipc_dump(struct snd_sof_dev *sdev) "Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n", hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl); } -EXPORT_SYMBOL_NS(mtl_ipc_dump, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_ipc_dump, "SND_SOC_SOF_INTEL_MTL"); static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) { @@ -691,7 +691,7 @@ int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) return 0; } -EXPORT_SYMBOL_NS(mtl_dsp_core_get, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_core_get, "SND_SOC_SOF_INTEL_MTL"); int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) { @@ -709,7 +709,7 @@ int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) return 0; } -EXPORT_SYMBOL_NS(mtl_dsp_core_put, SND_SOC_SOF_INTEL_MTL); +EXPORT_SYMBOL_NS(mtl_dsp_core_put, "SND_SOC_SOF_INTEL_MTL"); /* Meteorlake ops */ struct snd_sof_dsp_ops sof_mtl_ops; diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index f006dcf5458aee..94ab3c61e3f7fe 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -106,6 +106,6 @@ module_pci_driver(snd_sof_pci_intel_apl_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for ApolloLake platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index a8406342f08bdd..739c352c3860fe 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -144,6 +144,6 @@ module_pci_driver(snd_sof_pci_intel_cnl_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for CannonLake platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index 25effca50d9fed..8545ab95eac8b1 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -109,7 +109,7 @@ module_pci_driver(snd_sof_pci_intel_icl_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for IceLake platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_CNL); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_CNL"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c index 602c574064eb5c..8d4d74ac4398b9 100644 --- a/sound/soc/sof/intel/pci-lnl.c +++ b/sound/soc/sof/intel/pci-lnl.c @@ -71,8 +71,8 @@ module_pci_driver(snd_sof_pci_intel_lnl_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for LunarLake platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_MTL); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index 8cb0333c033ef1..71f711cf85990e 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -134,6 +134,6 @@ module_pci_driver(snd_sof_pci_intel_mtl_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for MeteorLake platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c index 69195b5e7b1a92..0aacdfac9fb431 100644 --- a/sound/soc/sof/intel/pci-ptl.c +++ b/sound/soc/sof/intel/pci-ptl.c @@ -69,9 +69,9 @@ module_pci_driver(snd_sof_pci_intel_ptl_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for PantherLake platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_LNL); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_MTL); -MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c index 8ca0231d7e4f6e..bd9daae51e4cc3 100644 --- a/sound/soc/sof/intel/pci-skl.c +++ b/sound/soc/sof/intel/pci-skl.c @@ -90,6 +90,6 @@ module_pci_driver(snd_sof_pci_intel_skl_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for SkyLake platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 01db2e720b44ed..f76a7197f6caa4 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -318,7 +318,7 @@ module_pci_driver(snd_sof_pci_intel_tgl_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for TigerLake platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_CNL); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_CNL"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index 1375c393827e11..b585ac4a85c2c7 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -245,7 +245,7 @@ module_pci_driver(snd_sof_pci_intel_tng_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Tangier platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); -MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_ATOM_HIFI_EP); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC"); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); +MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 9a002811e9ffde..0696bce65e33ef 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -50,7 +50,7 @@ static int skl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) /* skylake ops */ struct snd_sof_dsp_ops sof_skl_ops; -EXPORT_SYMBOL_NS(sof_skl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sof_skl_ops, "SND_SOC_SOF_INTEL_HDA_COMMON"); int sof_skl_ops_init(struct snd_sof_dev *sdev) { @@ -96,7 +96,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev) return 0; }; -EXPORT_SYMBOL_NS(sof_skl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sof_skl_ops_init, "SND_SOC_SOF_INTEL_HDA_COMMON"); const struct sof_intel_dsp_desc skl_chip_info = { .cores_num = 2, @@ -114,4 +114,4 @@ const struct sof_intel_dsp_desc skl_chip_info = { .disable_interrupts = hda_dsp_disable_interrupts, .hw_ip_version = SOF_INTEL_CAVS_1_5, }; -EXPORT_SYMBOL_NS(skl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(skl_chip_info, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/intel/telemetry.c b/sound/soc/sof/intel/telemetry.c index 2d2f96548310a7..dcaaf03599db22 100644 --- a/sound/soc/sof/intel/telemetry.c +++ b/sound/soc/sof/intel/telemetry.c @@ -93,4 +93,4 @@ void sof_ipc4_intel_dump_telemetry_state(struct snd_sof_dev *sdev, u32 flags) free_telemetry_data: kfree(telemetry_data); } -EXPORT_SYMBOL_NS(sof_ipc4_intel_dump_telemetry_state, SND_SOC_SOF_INTEL_HDA_COMMON); +EXPORT_SYMBOL_NS(sof_ipc4_intel_dump_telemetry_state, "SND_SOC_SOF_INTEL_HDA_COMMON"); diff --git a/sound/soc/sof/ipc3-loader.c b/sound/soc/sof/ipc3-loader.c index 35b89c2b9d4c02..7e9c76d5b2c91c 100644 --- a/sound/soc/sof/ipc3-loader.c +++ b/sound/soc/sof/ipc3-loader.c @@ -193,6 +193,9 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev) case SOF_EXT_MAN_ELEM_CC_VERSION: ret = ipc3_fw_ext_man_get_cc_info(sdev, elem_hdr); break; + case SOF_EXT_MAN_ELEM_PROBE_INFO: + dev_dbg(sdev->dev, "Probe info (not parsed)\n"); + break; case SOF_EXT_MAN_ELEM_DBG_ABI: ret = ipc3_fw_ext_man_get_dbg_abi_info(sdev, elem_hdr); break; diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index be61e377e59e03..e98b53b67d12b9 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -20,6 +20,9 @@ /* size of tplg ABI in bytes */ #define SOF_IPC3_TPLG_ABI_SIZE 3 +/* Base of SOF_DAI_INTEL_ALH, this should be aligned with SOC_SDW_INTEL_BIDIR_PDI_BASE */ +#define INTEL_ALH_DAI_INDEX_BASE 2 + struct sof_widget_data { int ctrl_type; int ipc_cmd; @@ -1585,14 +1588,26 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget) ret = sof_update_ipc_object(scomp, comp_dai, SOF_DAI_TOKENS, swidget->tuples, swidget->num_tuples, sizeof(*comp_dai), 1); if (ret < 0) - goto free; + goto free_comp; /* update comp_tokens */ ret = sof_update_ipc_object(scomp, &comp_dai->config, SOF_COMP_TOKENS, swidget->tuples, swidget->num_tuples, sizeof(comp_dai->config), 1); if (ret < 0) - goto free; + goto free_comp; + + /* Subtract the base to match the FW dai index. */ + if (comp_dai->type == SOF_DAI_INTEL_ALH) { + if (comp_dai->dai_index < INTEL_ALH_DAI_INDEX_BASE) { + dev_err(sdev->dev, + "Invalid ALH dai index %d, only Pin numbers >= %d can be used\n", + comp_dai->dai_index, INTEL_ALH_DAI_INDEX_BASE); + ret = -EINVAL; + goto free_comp; + } + comp_dai->dai_index -= INTEL_ALH_DAI_INDEX_BASE; + } dev_dbg(scomp->dev, "dai %s: type %d index %d\n", swidget->widget->name, comp_dai->type, comp_dai->dai_index); @@ -2167,8 +2182,16 @@ static int sof_ipc3_dai_config(struct snd_sof_dev *sdev, struct snd_sof_widget * case SOF_DAI_INTEL_ALH: if (data) { /* save the dai_index during hw_params and reuse it for hw_free */ - if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) - config->dai_index = data->dai_index; + if (flags & SOF_DAI_CONFIG_FLAGS_HW_PARAMS) { + /* Subtract the base to match the FW dai index. */ + if (data->dai_index < INTEL_ALH_DAI_INDEX_BASE) { + dev_err(sdev->dev, + "Invalid ALH dai index %d, only Pin numbers >= %d can be used\n", + config->dai_index, INTEL_ALH_DAI_INDEX_BASE); + return -EINVAL; + } + config->dai_index = data->dai_index - INTEL_ALH_DAI_INDEX_BASE; + } config->alh.stream_id = data->dai_data; } break; diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 83c22d4a48304f..7de5e3d285e73d 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -226,7 +226,7 @@ static inline void ipc3_log_header(struct device *dev, u8 *text, u32 cmd) static void sof_ipc3_dump_payload(struct snd_sof_dev *sdev, void *ipc_data, size_t size) { - printk(KERN_DEBUG "Size of payload following the header: %zu\n", size); + dev_dbg(sdev->dev, "Size of payload following the header: %zu\n", size); print_hex_dump_debug("Message payload: ", DUMP_PREFIX_OFFSET, 16, 4, ipc_data, size, false); } diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 4df2be3d39eba0..18fff2df76f97e 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -603,6 +603,9 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev, unsigned int be_rate; int i; + if (WARN_ON_ONCE(!num_input_formats)) + return -EINVAL; + /* * Copier does not change sampling rate, so we * need to only consider the input pin information. diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 240fee2166d125..b55eb977e443d4 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -195,7 +195,7 @@ static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_fo for (i = 0; i < num_formats; i++) { struct sof_ipc4_audio_format *fmt = &pin_fmt[i].audio_fmt; dev_dbg(dev, - "Pin index #%d: %uHz, %ubit, %luch (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n", + "Pin #%d: %uHz, %ubit, %luch (ch_map %#x ch_cfg %u interleaving_style %u fmt_cfg %#x) buffer size %d\n", pin_fmt[i].pin_index, fmt->sampling_frequency, fmt->bit_depth, SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg), fmt->ch_map, fmt->ch_cfg, fmt->interleaving_style, fmt->fmt_cfg, @@ -203,6 +203,101 @@ static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_fo } } +static void +sof_ipc4_dbg_module_audio_format(struct device *dev, + struct snd_sof_widget *swidget, + struct sof_ipc4_available_audio_format *available_fmt, + int in_fmt_index, int out_fmt_index) +{ + struct sof_ipc4_audio_format *in_fmt, *out_fmt; + u32 out_rate, out_channels, out_valid_bits; + u32 in_rate, in_channels, in_valid_bits; + struct sof_ipc4_pin_format *pin_fmt; + + if (!available_fmt->num_input_formats && + !available_fmt->num_output_formats) + return; + + /* Only input or output is supported by the module */ + if (!available_fmt->num_input_formats) { + if (available_fmt->num_output_formats == 1) + dev_dbg(dev, "Output audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, + "Output audio format (format index: %d) for %s:\n", + out_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); + + return; + } else if (!available_fmt->num_output_formats) { + if (available_fmt->num_input_formats == 1) + dev_dbg(dev, "Input audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, + "Input audio format (format index: %d) for %s:\n", + out_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); + + return; + } + + in_fmt = &available_fmt->input_pin_fmts[in_fmt_index].audio_fmt; + out_fmt = &available_fmt->output_pin_fmts[out_fmt_index].audio_fmt; + + in_rate = in_fmt->sampling_frequency; + in_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + in_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + out_rate = out_fmt->sampling_frequency; + out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg); + out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + + if (!(in_valid_bits != out_valid_bits || in_rate != out_rate || + in_channels != out_channels)) { + /* There is no change in format */ + if (available_fmt->num_input_formats == 1 && + available_fmt->num_output_formats == 1) + dev_dbg(dev, "Audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, + "Audio format (in/out format index: %d/%d) for %s:\n", + in_fmt_index, out_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); + + return; + } + + /* The format is changed by the module */ + if (available_fmt->num_input_formats == 1) + dev_dbg(dev, "Input audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, "Input audio format (format index: %d) for %s:\n", + in_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->input_pin_fmts[in_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); + + if (available_fmt->num_output_formats == 1) + dev_dbg(dev, "Output audio format for %s:\n", + swidget->widget->name); + else + dev_dbg(dev, "Output audio format (format index: %d) for %s:\n", + out_fmt_index, swidget->widget->name); + + pin_fmt = &available_fmt->output_pin_fmts[out_fmt_index]; + sof_ipc4_dbg_audio_format(dev, pin_fmt, 1); +} + static const struct sof_ipc4_audio_format * sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index) { @@ -660,7 +755,6 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget) * It is fine to call kfree(ipc4_copier->copier_config) since * ipc4_copier->copier_config is null. */ - ret = 0; break; } @@ -1205,47 +1299,56 @@ static bool sof_ipc4_is_single_format(struct snd_sof_dev *sdev, } static int sof_ipc4_init_output_audio_fmt(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, struct sof_ipc4_base_module_cfg *base_config, struct sof_ipc4_available_audio_format *available_fmt, u32 out_ref_rate, u32 out_ref_channels, u32 out_ref_valid_bits) { - struct sof_ipc4_audio_format *out_fmt; + struct sof_ipc4_pin_format *pin_fmts = available_fmt->output_pin_fmts; + u32 pin_fmts_size = available_fmt->num_output_formats; bool single_format; - int i; + int i = 0; - if (!available_fmt->num_output_formats) + if (!pin_fmts_size) { + dev_err(sdev->dev, "no output formats for %s\n", + swidget->widget->name); return -EINVAL; + } - single_format = sof_ipc4_is_single_format(sdev, available_fmt->output_pin_fmts, - available_fmt->num_output_formats); + single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size); /* pick the first format if there's only one available or if all formats are the same */ - if (single_format) { - base_config->obs = available_fmt->output_pin_fmts[0].buffer_size; - return 0; - } + if (single_format) + goto out_fmt; /* * if there are multiple output formats, then choose the output format that matches * the reference params */ - for (i = 0; i < available_fmt->num_output_formats; i++) { + for (i = 0; i < pin_fmts_size; i++) { + struct sof_ipc4_audio_format *fmt = &pin_fmts[i].audio_fmt; + u32 _out_rate, _out_channels, _out_valid_bits; - out_fmt = &available_fmt->output_pin_fmts[i].audio_fmt; - _out_rate = out_fmt->sampling_frequency; - _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(out_fmt->fmt_cfg); - _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); + _out_rate = fmt->sampling_frequency; + _out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); + _out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); if (_out_rate == out_ref_rate && _out_channels == out_ref_channels && - _out_valid_bits == out_ref_valid_bits) { - base_config->obs = available_fmt->output_pin_fmts[i].buffer_size; - return i; - } + _out_valid_bits == out_ref_valid_bits) + goto out_fmt; } + dev_err(sdev->dev, "%s: Unsupported audio format: %uHz, %ubit, %u channels\n", + __func__, out_ref_rate, out_ref_valid_bits, out_ref_channels); + return -EINVAL; + +out_fmt: + base_config->obs = pin_fmts[i].buffer_size; + + return i; } static int sof_ipc4_get_valid_bits(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params) @@ -1278,13 +1381,12 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, int sample_valid_bits; int i = 0; - if (!available_fmt->num_input_formats) { + if (!pin_fmts_size) { dev_err(sdev->dev, "no input formats for %s\n", swidget->widget->name); return -EINVAL; } - single_format = sof_ipc4_is_single_format(sdev, available_fmt->input_pin_fmts, - available_fmt->num_input_formats); + single_format = sof_ipc4_is_single_format(sdev, pin_fmts, pin_fmts_size); if (single_format) goto in_fmt; @@ -1306,11 +1408,8 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); if (params_rate(params) == rate && params_channels(params) == channels && - sample_valid_bits == valid_bits) { - dev_dbg(sdev->dev, "matched audio format index for %uHz, %ubit, %u channels: %d\n", - rate, valid_bits, channels, i); + sample_valid_bits == valid_bits) break; - } } if (i == pin_fmts_size) { @@ -1321,16 +1420,11 @@ static int sof_ipc4_init_input_audio_fmt(struct snd_sof_dev *sdev, in_fmt: /* copy input format */ - if (available_fmt->num_input_formats && i < available_fmt->num_input_formats) { - memcpy(&base_config->audio_fmt, &available_fmt->input_pin_fmts[i].audio_fmt, - sizeof(struct sof_ipc4_audio_format)); + memcpy(&base_config->audio_fmt, &pin_fmts[i].audio_fmt, + sizeof(struct sof_ipc4_audio_format)); - /* set base_cfg ibs/obs */ - base_config->ibs = available_fmt->input_pin_fmts[i].buffer_size; - - dev_dbg(sdev->dev, "Init input audio formats for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->input_pin_fmts[i], 1); - } + /* set base_cfg ibs/obs */ + base_config->ibs = pin_fmts[i].buffer_size; return i; } @@ -1706,6 +1800,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_soc_component *scomp = swidget->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_copier_data *copier_data; + int input_fmt_index, output_fmt_index; struct snd_pcm_hw_params ref_params; struct sof_ipc4_copier *ipc4_copier; struct snd_sof_dai *dai; @@ -1717,7 +1812,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, int ipc_size, ret, out_ref_valid_bits; u32 out_ref_rate, out_ref_channels; u32 deep_buffer_dma_ms = 0; - int output_fmt_index; bool single_output_bitdepth; int i; @@ -1849,10 +1943,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* set input and output audio formats */ - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, - &ref_params, available_fmt); - if (ret < 0) - return ret; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &copier_data->base_config, + &ref_params, available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; /* set the reference params for output format selection */ single_output_bitdepth = sof_ipc4_copier_is_single_bitdepth(sdev, @@ -1865,7 +1960,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, { struct sof_ipc4_audio_format *in_fmt; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); @@ -1904,17 +1999,12 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(out_fmt->fmt_cfg); } - dev_dbg(sdev->dev, "copier %s: reference output rate %d, channels %d valid_bits %d\n", - swidget->widget->name, out_ref_rate, out_ref_channels, out_ref_valid_bits); - - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &copier_data->base_config, + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &copier_data->base_config, available_fmt, out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (output_fmt_index < 0) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); + if (output_fmt_index < 0) return output_fmt_index; - } /* * Set the output format. Current topology defines pin 0 input and output formats in pairs. @@ -1926,8 +2016,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, memcpy(&copier_data->out_format, &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt, sizeof(struct sof_ipc4_audio_format)); - dev_dbg(sdev->dev, "Output audio format for %s\n", swidget->widget->name); - sof_ipc4_dbg_audio_format(sdev->dev, &available_fmt->output_pin_fmts[output_fmt_index], 1); switch (swidget->id) { case snd_soc_dapm_dai_in: @@ -2104,6 +2192,9 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, *ipc_config_size = ipc_size; + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); + /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config); @@ -2139,25 +2230,31 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, struct sof_ipc4_available_audio_format *available_fmt = &gain->available_fmt; struct sof_ipc4_audio_format *in_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int ret; + int input_fmt_index, output_fmt_index; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->data.base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &gain->data.base_config, + pipeline_params, + available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); - ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->data.base_config, available_fmt, - out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (ret < 0) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); - return ret; - } + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &gain->data.base_config, + available_fmt, + out_ref_rate, + out_ref_channels, + out_ref_valid_bits); + if (output_fmt_index < 0) + return output_fmt_index; + + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &gain->data.base_config); @@ -2176,25 +2273,31 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, struct sof_ipc4_available_audio_format *available_fmt = &mixer->available_fmt; struct sof_ipc4_audio_format *in_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int ret; + int input_fmt_index, output_fmt_index; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &mixer->base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &mixer->base_config, + pipeline_params, + available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; + in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_rate = in_fmt->sampling_frequency; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); - ret = sof_ipc4_init_output_audio_fmt(sdev, &mixer->base_config, available_fmt, - out_ref_rate, out_ref_channels, out_ref_valid_bits); - if (ret < 0) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); - return ret; - } + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &mixer->base_config, + available_fmt, + out_ref_rate, + out_ref_channels, + out_ref_valid_bits); + if (output_fmt_index < 0) + return output_fmt_index; + + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config); @@ -2214,12 +2317,14 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, struct sof_ipc4_audio_format *out_audio_fmt; struct sof_ipc4_audio_format *in_audio_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; - int output_format_index, input_format_index; + int output_fmt_index, input_fmt_index; - input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->data.base_config, - pipeline_params, available_fmt); - if (input_format_index < 0) - return input_format_index; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &src->data.base_config, + pipeline_params, + available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; /* * For playback, the SRC sink rate will be configured based on the requested output @@ -2235,7 +2340,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, * SRC does not perform format conversion, so the output channels and valid bit depth must * be the same as that of the input. */ - in_audio_fmt = &available_fmt->input_pin_fmts[input_format_index].audio_fmt; + in_audio_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_audio_fmt->fmt_cfg); out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg); @@ -2246,19 +2351,22 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, */ out_ref_rate = params_rate(fe_params); - output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->data.base_config, - available_fmt, out_ref_rate, - out_ref_channels, out_ref_valid_bits); - if (output_format_index < 0) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); - return output_format_index; - } + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &src->data.base_config, + available_fmt, + out_ref_rate, + out_ref_channels, + out_ref_valid_bits); + if (output_fmt_index < 0) + return output_fmt_index; + + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config); - out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt; + out_audio_fmt = &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt; src->data.sink_rate = out_audio_fmt->sampling_frequency; /* update pipeline_params for sink widgets */ @@ -2355,49 +2463,61 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_process *process = swidget->private; struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; - struct sof_ipc4_audio_format *in_fmt; - u32 out_ref_rate, out_ref_channels, out_ref_valid_bits; void *cfg = process->ipc_config_data; - int output_fmt_index; + int output_fmt_index = 0; + int input_fmt_index = 0; int ret; - ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &process->base_config, - pipeline_params, available_fmt); - if (ret < 0) - return ret; + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, + &process->base_config, + pipeline_params, + available_fmt); + if (input_fmt_index < 0) + return input_fmt_index; - in_fmt = &available_fmt->input_pin_fmts[ret].audio_fmt; - out_ref_rate = in_fmt->sampling_frequency; - out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); - out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + /* Configure output audio format only if the module supports output */ + if (available_fmt->num_output_formats) { + struct sof_ipc4_audio_format *in_fmt; + struct sof_ipc4_pin_format *pin_fmt; + u32 out_ref_rate, out_ref_channels; + int out_ref_valid_bits; - output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, &process->base_config, - available_fmt, out_ref_rate, - out_ref_channels, out_ref_valid_bits); - if (output_fmt_index < 0 && available_fmt->num_output_formats) { - dev_err(sdev->dev, "Failed to initialize output format for %s", - swidget->widget->name); - return output_fmt_index; - } + in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt; - /* copy Pin 0 output format */ - if (available_fmt->num_output_formats && - output_fmt_index < available_fmt->num_output_formats && - !available_fmt->output_pin_fmts[output_fmt_index].pin_index) { - memcpy(&process->output_format, - &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt, - sizeof(struct sof_ipc4_audio_format)); - - /* modify the pipeline params with the pin 0 output format */ - ret = sof_ipc4_update_hw_params(sdev, pipeline_params, - &process->output_format, - BIT(SNDRV_PCM_HW_PARAM_FORMAT) | - BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | - BIT(SNDRV_PCM_HW_PARAM_RATE)); - if (ret) - return ret; + out_ref_rate = in_fmt->sampling_frequency; + out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg); + out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg); + + output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, + &process->base_config, + available_fmt, + out_ref_rate, + out_ref_channels, + out_ref_valid_bits); + if (output_fmt_index < 0) + return output_fmt_index; + + pin_fmt = &available_fmt->output_pin_fmts[output_fmt_index]; + + /* copy Pin output format for Pin 0 only */ + if (pin_fmt->pin_index == 0) { + memcpy(&process->output_format, &pin_fmt->audio_fmt, + sizeof(struct sof_ipc4_audio_format)); + + /* modify the pipeline params with the output format */ + ret = sof_ipc4_update_hw_params(sdev, pipeline_params, + &process->output_format, + BIT(SNDRV_PCM_HW_PARAM_FORMAT) | + BIT(SNDRV_PCM_HW_PARAM_CHANNELS) | + BIT(SNDRV_PCM_HW_PARAM_RATE)); + if (ret) + return ret; + } } + sof_ipc4_dbg_module_audio_format(sdev->dev, swidget, available_fmt, + input_fmt_index, output_fmt_index); + /* update pipeline memory usage */ sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config); diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 9466f7d2e53503..9955dfa520ae2f 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -668,5 +668,5 @@ module_platform_driver(snd_sof_of_mt8186_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for MT8186/MT8188 platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); -MODULE_IMPORT_NS(SND_SOC_SOF_MTK_COMMON); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); +MODULE_IMPORT_NS("SND_SOC_SOF_MTK_COMMON"); diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 5b4423ed8023bd..6032b566c67958 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -624,5 +624,5 @@ module_platform_driver(snd_sof_of_mt8195_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for MTL 8195 platforms"); -MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); -MODULE_IMPORT_NS(SND_SOC_SOF_MTK_COMMON); +MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); +MODULE_IMPORT_NS("SND_SOC_SOF_MTK_COMMON"); diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index b12b3d865ae30c..c0c906a78ebae4 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -55,10 +55,9 @@ static int sof_nocodec_bes_setup(struct device *dev, links[i].no_pcm = 1; links[i].cpus->dai_name = drv[i].name; links[i].platforms->name = dev_name(dev->parent); - if (drv[i].playback.channels_min) - links[i].dpcm_playback = 1; - if (drv[i].capture.channels_min) - links[i].dpcm_capture = 1; + + links[i].playback_only = drv[i].playback.channels_min && !drv[i].capture.channels_min; + links[i].capture_only = !drv[i].playback.channels_min && drv[i].capture.channels_min; links[i].be_hw_params_fixup = sof_pcm_dai_link_fixup; } diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 2584621c3b2d48..d73644e85b6e5d 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -597,12 +597,12 @@ snd_sof_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type) * @addr: Address to poll * @val: Variable to read the value into * @cond: Break condition (usually involving @val) - * @sleep_us: Maximum time to sleep between reads in us (0 - * tight-loops). Should be less than ~20ms since usleep_range - * is used (see Documentation/timers/timers-howto.rst). + * @sleep_us: Maximum time to sleep between reads in us (0 tight-loops). Please + * read usleep_range() function description for details and + * limitations. * @timeout_us: Timeout in us, 0 means never timeout * - * Returns 0 on success and -ETIMEDOUT upon a timeout. In either + * Returns: 0 on success and -ETIMEDOUT upon a timeout. In either * case, the last read value at @addr is stored in @val. Must not * be called from atomic context if sleep_us or timeout_us are used. * diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index b196b2b74c2647..58fd5f7c790540 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -24,11 +24,11 @@ static char *fw_path; module_param(fw_path, charp, 0444); -MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); +MODULE_PARM_DESC(fw_path, "deprecated - moved to snd-sof module."); static char *tplg_path; module_param(tplg_path, charp, 0444); -MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +MODULE_PARM_DESC(tplg_path, "deprecated - moved to snd-sof module."); static int sof_acpi_debug; module_param_named(sof_acpi_debug, sof_acpi_debug, int, 0444); @@ -41,7 +41,7 @@ const struct dev_pm_ops sof_acpi_pm = { SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, snd_sof_runtime_idle) }; -EXPORT_SYMBOL_NS(sof_acpi_pm, SND_SOC_SOF_ACPI_DEV); +EXPORT_SYMBOL_NS(sof_acpi_pm, "SND_SOC_SOF_ACPI_DEV"); static void sof_acpi_probe_complete(struct device *dev) { @@ -85,7 +85,7 @@ int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc /* call sof helper for DSP hardware probe */ return snd_sof_device_probe(dev, sof_pdata); } -EXPORT_SYMBOL_NS(sof_acpi_probe, SND_SOC_SOF_ACPI_DEV); +EXPORT_SYMBOL_NS(sof_acpi_probe, "SND_SOC_SOF_ACPI_DEV"); void sof_acpi_remove(struct platform_device *pdev) { @@ -97,7 +97,7 @@ void sof_acpi_remove(struct platform_device *pdev) /* call sof helper for DSP hardware remove */ snd_sof_device_remove(dev); } -EXPORT_SYMBOL_NS(sof_acpi_remove, SND_SOC_SOF_ACPI_DEV); +EXPORT_SYMBOL_NS(sof_acpi_remove, "SND_SOC_SOF_ACPI_DEV"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for ACPI platforms"); diff --git a/sound/soc/sof/sof-client-ipc-flood-test.c b/sound/soc/sof/sof-client-ipc-flood-test.c index e7d2001140e81a..b35c9889696814 100644 --- a/sound/soc/sof/sof-client-ipc-flood-test.c +++ b/sound/soc/sof/sof-client-ipc-flood-test.c @@ -396,4 +396,4 @@ module_auxiliary_driver(sof_ipc_flood_client_drv); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SOF IPC Flood Test Client Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client-ipc-kernel-injector.c b/sound/soc/sof/sof-client-ipc-kernel-injector.c index d3f541069b24b8..8b28c3dc920cb0 100644 --- a/sound/soc/sof/sof-client-ipc-kernel-injector.c +++ b/sound/soc/sof/sof-client-ipc-kernel-injector.c @@ -159,4 +159,4 @@ module_auxiliary_driver(sof_msg_inject_client_drv); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SOF IPC Kernel Injector Client Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client-ipc-msg-injector.c b/sound/soc/sof/sof-client-ipc-msg-injector.c index d0f8beb9d0008d..ba7ca1c5027ff0 100644 --- a/sound/soc/sof/sof-client-ipc-msg-injector.c +++ b/sound/soc/sof/sof-client-ipc-msg-injector.c @@ -337,4 +337,4 @@ module_auxiliary_driver(sof_msg_inject_client_drv); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SOF IPC Message Injector Client Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c index ccc7d38ddc3834..aff9ce98042954 100644 --- a/sound/soc/sof/sof-client-probes.c +++ b/sound/soc/sof/sof-client-probes.c @@ -542,4 +542,4 @@ module_auxiliary_driver(sof_probes_client_drv); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("SOF Probes Client Driver"); -MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); +MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-client.c b/sound/soc/sof/sof-client.c index 5d6005a88e798f..4c7951338c66f6 100644 --- a/sound/soc/sof/sof-client.c +++ b/sound/soc/sof/sof-client.c @@ -259,7 +259,7 @@ int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id, return ret; } -EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, "SND_SOC_SOF_CLIENT"); void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id) { @@ -282,7 +282,7 @@ void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 i mutex_unlock(&sdev->ipc_client_mutex); } -EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, void *reply_data, size_t reply_bytes) @@ -301,7 +301,7 @@ int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg, return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_rx_message(struct sof_client_dev *cdev, void *ipc_msg, void *msg_buf) { @@ -320,7 +320,7 @@ int sof_client_ipc_rx_message(struct sof_client_dev *cdev, void *ipc_msg, void * return -EOPNOTSUPP; } -EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message, "SND_SOC_SOF_CLIENT"); int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg, bool set) @@ -339,7 +339,7 @@ int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg, return -EINVAL; } -EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, "SND_SOC_SOF_CLIENT"); #ifdef CONFIG_SND_SOC_SOF_IPC4 struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *uuid) @@ -352,7 +352,7 @@ struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, return NULL; } -EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, "SND_SOC_SOF_CLIENT"); #endif int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) @@ -376,7 +376,7 @@ int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state) return 0; } -EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, "SND_SOC_SOF_CLIENT"); int sof_resume_clients(struct snd_sof_dev *sdev) { @@ -399,20 +399,20 @@ int sof_resume_clients(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL_NS_GPL(sof_resume_clients, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_resume_clients, "SND_SOC_SOF_CLIENT"); struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev) { return cdev->sdev->debugfs_root; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, "SND_SOC_SOF_CLIENT"); /* DMA buffer allocation in client drivers must use the core SOF device */ struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev) { return cdev->sdev->dev; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, "SND_SOC_SOF_CLIENT"); const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev) { @@ -420,7 +420,7 @@ const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev return &sdev->fw_ready.version; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, "SND_SOC_SOF_CLIENT"); size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev) { @@ -428,7 +428,7 @@ size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev) return sdev->ipc->max_payload_size; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, "SND_SOC_SOF_CLIENT"); enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev) { @@ -436,7 +436,7 @@ enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev) return sdev->pdata->ipc_type; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, "SND_SOC_SOF_CLIENT"); /* module refcount management of SOF core */ int sof_client_core_module_get(struct sof_client_dev *cdev) @@ -448,7 +448,7 @@ int sof_client_core_module_get(struct sof_client_dev *cdev) return 0; } -EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, "SND_SOC_SOF_CLIENT"); void sof_client_core_module_put(struct sof_client_dev *cdev) { @@ -456,7 +456,7 @@ void sof_client_core_module_put(struct sof_client_dev *cdev) module_put(sdev->dev->driver->owner); } -EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, "SND_SOC_SOF_CLIENT"); /* IPC event handling */ void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf) @@ -525,7 +525,7 @@ int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev, return 0; } -EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, "SND_SOC_SOF_CLIENT"); void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, u32 ipc_msg_type) @@ -545,7 +545,7 @@ void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev, mutex_unlock(&sdev->client_event_handler_mutex); } -EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, "SND_SOC_SOF_CLIENT"); /*DSP state notification and query */ void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev) @@ -583,7 +583,7 @@ int sof_client_register_fw_state_handler(struct sof_client_dev *cdev, return 0; } -EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, "SND_SOC_SOF_CLIENT"); void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) { @@ -602,7 +602,7 @@ void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev) mutex_unlock(&sdev->client_event_handler_mutex); } -EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, "SND_SOC_SOF_CLIENT"); enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) { @@ -610,4 +610,4 @@ enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev) return sdev->fw_state; } -EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, SND_SOC_SOF_CLIENT); +EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, "SND_SOC_SOF_CLIENT"); diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 71f7153cf79c69..fb8c8a14d885a7 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -16,11 +16,19 @@ static char *fw_path; module_param(fw_path, charp, 0444); -MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); +MODULE_PARM_DESC(fw_path, "deprecated - moved to snd-sof module."); + +static char *fw_filename; +module_param(fw_filename, charp, 0444); +MODULE_PARM_DESC(fw_filename, "deprecated - moved to snd-sof module."); static char *tplg_path; module_param(tplg_path, charp, 0444); -MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +MODULE_PARM_DESC(tplg_path, "deprecated - moved to snd-sof module."); + +static char *tplg_filename; +module_param(tplg_filename, charp, 0444); +MODULE_PARM_DESC(tplg_filename, "deprecated - moved to snd-sof module."); const struct dev_pm_ops sof_of_pm = { .prepare = snd_sof_prepare, @@ -68,6 +76,8 @@ int sof_of_probe(struct platform_device *pdev) sof_pdata->ipc_file_profile_base.ipc_type = desc->ipc_default; sof_pdata->ipc_file_profile_base.fw_path = fw_path; sof_pdata->ipc_file_profile_base.tplg_path = tplg_path; + sof_pdata->ipc_file_profile_base.fw_name = fw_filename; + sof_pdata->ipc_file_profile_base.tplg_name = tplg_filename; /* set callback to be called on successful device probe to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_of_probe_complete; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 38f2187da5de18..103377e2caaf82 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -22,23 +22,23 @@ static char *fw_path; module_param(fw_path, charp, 0444); -MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); +MODULE_PARM_DESC(fw_path, "deprecated - moved to snd-sof module."); static char *fw_filename; module_param(fw_filename, charp, 0444); -MODULE_PARM_DESC(fw_filename, "alternate filename for SOF firmware."); +MODULE_PARM_DESC(fw_filename, "deprecated - moved to snd-sof module."); static char *lib_path; module_param(lib_path, charp, 0444); -MODULE_PARM_DESC(lib_path, "alternate path for SOF firmware libraries."); +MODULE_PARM_DESC(lib_path, "deprecated - moved to snd-sof module."); static char *tplg_path; module_param(tplg_path, charp, 0444); -MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +MODULE_PARM_DESC(tplg_path, "deprecated - moved to snd-sof module."); static char *tplg_filename; module_param(tplg_filename, charp, 0444); -MODULE_PARM_DESC(tplg_filename, "alternate filename for SOF topology."); +MODULE_PARM_DESC(tplg_filename, "deprecated - moved to snd-sof module."); static int sof_pci_debug; module_param_named(sof_pci_debug, sof_pci_debug, int, 0444); @@ -46,7 +46,7 @@ MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)"); static int sof_pci_ipc_type = -1; module_param_named(ipc_type, sof_pci_ipc_type, int, 0444); -MODULE_PARM_DESC(ipc_type, "Force SOF IPC type. 0 - IPC3, 1 - IPC4"); +MODULE_PARM_DESC(ipc_type, "deprecated - moved to snd-sof module."); static const char *sof_dmi_override_tplg_name; static bool sof_dmi_use_community_key; @@ -162,7 +162,7 @@ const struct dev_pm_ops sof_pci_pm = { SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, snd_sof_runtime_idle) }; -EXPORT_SYMBOL_NS(sof_pci_pm, SND_SOC_SOF_PCI_DEV); +EXPORT_SYMBOL_NS(sof_pci_pm, "SND_SOC_SOF_PCI_DEV"); static void sof_pci_probe_complete(struct device *dev) { @@ -280,7 +280,7 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return ret; } -EXPORT_SYMBOL_NS(sof_pci_probe, SND_SOC_SOF_PCI_DEV); +EXPORT_SYMBOL_NS(sof_pci_probe, "SND_SOC_SOF_PCI_DEV"); void sof_pci_remove(struct pci_dev *pci) { @@ -295,13 +295,13 @@ void sof_pci_remove(struct pci_dev *pci) /* release pci regions and disable device */ pci_release_regions(pci); } -EXPORT_SYMBOL_NS(sof_pci_remove, SND_SOC_SOF_PCI_DEV); +EXPORT_SYMBOL_NS(sof_pci_remove, "SND_SOC_SOF_PCI_DEV"); void sof_pci_shutdown(struct pci_dev *pci) { snd_sof_device_shutdown(&pci->dev); } -EXPORT_SYMBOL_NS(sof_pci_shutdown, SND_SOC_SOF_PCI_DEV); +EXPORT_SYMBOL_NS(sof_pci_shutdown, "SND_SOC_SOF_PCI_DEV"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for PCI platforms"); diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index 3cf8c84beff957..50623e65fe1a51 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -149,7 +149,7 @@ const struct dsp_arch_ops sof_xtensa_arch_ops = { .dsp_oops = xtensa_dsp_oops, .dsp_stack = xtensa_stack, }; -EXPORT_SYMBOL_NS(sof_xtensa_arch_ops, SND_SOC_SOF_XTENSA); +EXPORT_SYMBOL_NS(sof_xtensa_arch_ops, "SND_SOC_SOF_XTENSA"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF Xtensa DSP support"); diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 9351727dce1acd..c914d1c4685019 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -142,7 +142,7 @@ static const struct snd_soc_dai_driver stm32_adfsdm_dai = { SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .ops = &stm32_adfsdm_dai_ops, }; @@ -309,7 +309,7 @@ static void stm32_adfsdm_cleanup(void *data) iio_channel_release_all_cb(data); } -static struct snd_soc_component_driver stm32_adfsdm_soc_platform = { +static const struct snd_soc_component_driver stm32_adfsdm_soc_platform = { .open = stm32_adfsdm_pcm_open, .close = stm32_adfsdm_pcm_close, .hw_params = stm32_adfsdm_pcm_hw_params, diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index faa00103ee7f17..19dc61008a75f3 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -200,10 +200,13 @@ enum i2s_datlen { #define STM32_I2S_NAME_LEN 32 #define STM32_I2S_RATE_11K 11025 +#define STM32_I2S_MAX_SAMPLE_RATE_8K 192000 +#define STM32_I2S_MAX_SAMPLE_RATE_11K 176400 +#define STM32_I2S_CLK_RATE_TOLERANCE 1000 /* ppm */ /** * struct stm32_i2s_data - private data of I2S - * @regmap_conf: I2S register map configuration pointer + * @conf: I2S configuration pointer * @regmap: I2S register map pointer * @pdev: device data pointer * @dai_drv: DAI driver pointer @@ -224,11 +227,14 @@ enum i2s_datlen { * @divider: prescaler division ratio * @div: prescaler div field * @odd: prescaler odd field + * @i2s_clk_flg: flag set while exclusivity on I2S kernel clock is active * @refcount: keep count of opened streams on I2S * @ms_flg: master mode flag. + * @set_i2s_clk_rate: set I2S kernel clock rate + * @put_i2s_clk_rate: put I2S kernel clock rate */ struct stm32_i2s_data { - const struct regmap_config *regmap_conf; + const struct stm32_i2s_conf *conf; struct regmap *regmap; struct platform_device *pdev; struct snd_soc_dai_driver *dai_drv; @@ -249,8 +255,21 @@ struct stm32_i2s_data { unsigned int divider; unsigned int div; bool odd; + bool i2s_clk_flg; int refcount; int ms_flg; + int (*set_i2s_clk_rate)(struct stm32_i2s_data *i2s, unsigned int rate); + void (*put_i2s_clk_rate)(struct stm32_i2s_data *i2s); +}; + +/** + * struct stm32_i2s_conf - I2S configuration + * @regmap_conf: regmap configuration pointer + * @get_i2s_clk_parent: get parent clock of I2S kernel clock + */ +struct stm32_i2s_conf { + const struct regmap_config *regmap_conf; + int (*get_i2s_clk_parent)(struct stm32_i2s_data *i2s); }; struct stm32_i2smclk_data { @@ -261,6 +280,8 @@ struct stm32_i2smclk_data { #define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw) +static int stm32_i2s_get_parent_clk(struct stm32_i2s_data *i2s); + static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s, unsigned long input_rate, unsigned long output_rate) @@ -312,6 +333,33 @@ static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s) cgfr_mask, cgfr); } +static bool stm32_i2s_rate_accurate(struct stm32_i2s_data *i2s, + unsigned int max_rate, unsigned int rate) +{ + struct platform_device *pdev = i2s->pdev; + u64 delta, dividend; + int ratio; + + if (!rate) { + dev_err(&pdev->dev, "Unexpected null rate\n"); + return false; + } + + ratio = DIV_ROUND_CLOSEST(max_rate, rate); + if (!ratio) + return false; + + dividend = mul_u32_u32(1000000, abs(max_rate - (ratio * rate))); + delta = div_u64(dividend, max_rate); + + if (delta <= STM32_I2S_CLK_RATE_TOLERANCE) + return true; + + dev_dbg(&pdev->dev, "Rate [%u] not accurate\n", rate); + + return false; +} + static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s, unsigned int rate) { @@ -332,6 +380,87 @@ static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s, return ret; } +static void stm32_i2s_put_parent_rate(struct stm32_i2s_data *i2s) +{ + if (i2s->i2s_clk_flg) { + i2s->i2s_clk_flg = false; + clk_rate_exclusive_put(i2s->i2sclk); + } +} + +static int stm32_i2s_set_parent_rate(struct stm32_i2s_data *i2s, + unsigned int rate) +{ + struct platform_device *pdev = i2s->pdev; + unsigned int i2s_clk_rate, i2s_clk_max_rate, i2s_curr_rate, i2s_new_rate; + int ret, div; + + /* + * Set maximum expected kernel clock frequency + * - mclk on: + * f_i2s_ck = MCKDIV * mclk-fs * fs + * Here typical 256 ratio is assumed for mclk-fs + * - mclk off: + * f_i2s_ck = MCKDIV * FRL * fs + * Where FRL=[16,32], MCKDIV=[1..256] + * f_i2s_ck = i2s_clk_max_rate * 32 / 256 + */ + if (!(rate % STM32_I2S_RATE_11K)) + i2s_clk_max_rate = STM32_I2S_MAX_SAMPLE_RATE_11K * 256; + else + i2s_clk_max_rate = STM32_I2S_MAX_SAMPLE_RATE_8K * 256; + + if (!i2s->i2smclk) + i2s_clk_max_rate /= 8; + + /* Request exclusivity, as the clock may be shared by I2S instances */ + clk_rate_exclusive_get(i2s->i2sclk); + i2s->i2s_clk_flg = true; + + /* + * Check current kernel clock rate. If it gives the expected accuracy + * return immediately. + */ + i2s_curr_rate = clk_get_rate(i2s->i2sclk); + if (stm32_i2s_rate_accurate(i2s, i2s_clk_max_rate, i2s_curr_rate)) + return 0; + + /* + * Otherwise try to set the maximum rate and check the new actual rate. + * If the new rate does not give the expected accuracy, try to set + * lower rates for the kernel clock. + */ + i2s_clk_rate = i2s_clk_max_rate; + div = 1; + do { + /* Check new rate accuracy. Return if ok */ + i2s_new_rate = clk_round_rate(i2s->i2sclk, i2s_clk_rate); + if (stm32_i2s_rate_accurate(i2s, i2s_clk_rate, i2s_new_rate)) { + ret = clk_set_rate(i2s->i2sclk, i2s_clk_rate); + if (ret) { + dev_err(&pdev->dev, "Error %d setting i2s_clk_rate rate. %s", + ret, ret == -EBUSY ? + "Active stream rates may be in conflict\n" : "\n"); + goto err; + } + + return 0; + } + + /* Try a lower frequency */ + div++; + i2s_clk_rate = i2s_clk_max_rate / div; + } while (i2s_clk_rate > rate); + + /* no accurate rate found */ + dev_err(&pdev->dev, "Failed to find an accurate rate"); + +err: + stm32_i2s_put_parent_rate(i2s); + + return -EINVAL; +} + static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { @@ -635,12 +764,16 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, clk_rate_exclusive_put(i2s->i2smclk); i2s->mclk_rate = 0; } + + if (i2s->put_i2s_clk_rate) + i2s->put_i2s_clk_rate(i2s); + return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, 0); } /* If master clock is used, set parent clock now */ - ret = stm32_i2s_set_parent_clock(i2s, freq); + ret = i2s->set_i2s_clk_rate(i2s, freq); if (ret) return ret; ret = clk_set_rate_exclusive(i2s->i2smclk, freq); @@ -667,10 +800,11 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, u32 cgfr; int ret; - if (!(rate % 11025)) - clk_set_parent(i2s->i2sclk, i2s->x11kclk); - else - clk_set_parent(i2s->i2sclk, i2s->x8kclk); + if (!i2s->mclk_rate) { + ret = i2s->set_i2s_clk_rate(i2s, rate); + if (ret) + return ret; + } i2s_clock_rate = clk_get_rate(i2s->i2sclk); /* @@ -915,6 +1049,14 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(i2s->i2sclk); + /* + * Release kernel clock if following conditions are fulfilled + * - Master clock is not used. Kernel clock won't be released trough sysclk + * - Put handler is defined. Involve that clock is managed exclusively + */ + if (!i2s->i2smclk && i2s->put_i2s_clk_rate) + i2s->put_i2s_clk_rate(i2s); + spin_lock_irqsave(&i2s->irq_lock, flags); i2s->substream = NULL; spin_unlock_irqrestore(&i2s->irq_lock, flags); @@ -1012,14 +1154,36 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, return 0; } +static const struct stm32_i2s_conf stm32_i2s_conf_h7 = { + .regmap_conf = &stm32_h7_i2s_regmap_conf, + .get_i2s_clk_parent = stm32_i2s_get_parent_clk, +}; + +static const struct stm32_i2s_conf stm32_i2s_conf_mp25 = { + .regmap_conf = &stm32_h7_i2s_regmap_conf +}; + static const struct of_device_id stm32_i2s_ids[] = { - { - .compatible = "st,stm32h7-i2s", - .data = &stm32_h7_i2s_regmap_conf - }, + { .compatible = "st,stm32h7-i2s", .data = &stm32_i2s_conf_h7 }, + { .compatible = "st,stm32mp25-i2s", .data = &stm32_i2s_conf_mp25 }, {}, }; +static int stm32_i2s_get_parent_clk(struct stm32_i2s_data *i2s) +{ + struct device *dev = &i2s->pdev->dev; + + i2s->x8kclk = devm_clk_get(dev, "x8k"); + if (IS_ERR(i2s->x8kclk)) + return dev_err_probe(dev, PTR_ERR(i2s->x8kclk), "Cannot get x8k parent clock\n"); + + i2s->x11kclk = devm_clk_get(dev, "x11k"); + if (IS_ERR(i2s->x11kclk)) + return dev_err_probe(dev, PTR_ERR(i2s->x11kclk), "Cannot get x11k parent clock\n"); + + return 0; +} + static int stm32_i2s_parse_dt(struct platform_device *pdev, struct stm32_i2s_data *i2s) { @@ -1031,8 +1195,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, if (!np) return -ENODEV; - i2s->regmap_conf = device_get_match_data(&pdev->dev); - if (!i2s->regmap_conf) + i2s->conf = device_get_match_data(&pdev->dev); + if (!i2s->conf) return -EINVAL; i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); @@ -1052,15 +1216,18 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, return dev_err_probe(&pdev->dev, PTR_ERR(i2s->i2sclk), "Could not get i2sclk\n"); - i2s->x8kclk = devm_clk_get(&pdev->dev, "x8k"); - if (IS_ERR(i2s->x8kclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x8kclk), - "Could not get x8k parent clock\n"); + if (i2s->conf->get_i2s_clk_parent) { + i2s->set_i2s_clk_rate = stm32_i2s_set_parent_clock; + } else { + i2s->set_i2s_clk_rate = stm32_i2s_set_parent_rate; + i2s->put_i2s_clk_rate = stm32_i2s_put_parent_rate; + } - i2s->x11kclk = devm_clk_get(&pdev->dev, "x11k"); - if (IS_ERR(i2s->x11kclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(i2s->x11kclk), - "Could not get x11k parent clock\n"); + if (i2s->conf->get_i2s_clk_parent) { + ret = i2s->conf->get_i2s_clk_parent(i2s); + if (ret) + return ret; + } /* Register mclk provider if requested */ if (of_property_present(np, "#clock-cells")) { @@ -1126,7 +1293,7 @@ static int stm32_i2s_probe(struct platform_device *pdev) return ret; i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk", - i2s->base, i2s->regmap_conf); + i2s->base, i2s->conf->regmap_conf); if (IS_ERR(i2s->regmap)) return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), "Regmap init error\n"); diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index b45ee7e24f224d..bc8180fc8462db 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -19,26 +19,42 @@ #include "stm32_sai.h" +static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai); + static const struct stm32_sai_conf stm32_sai_conf_f4 = { .version = STM_SAI_STM32F4, .fifo_size = 8, .has_spdif_pdm = false, + .get_sai_ck_parent = stm32_sai_get_parent_clk, }; /* - * Default settings for stm32 H7 socs and next. + * Default settings for STM32H7x socs and STM32MP1x. * These default settings will be overridden if the soc provides * support of hardware configuration registers. + * - STM32H7: rely on default settings + * - STM32MP1: retrieve settings from registers */ static const struct stm32_sai_conf stm32_sai_conf_h7 = { .version = STM_SAI_STM32H7, .fifo_size = 8, .has_spdif_pdm = true, + .get_sai_ck_parent = stm32_sai_get_parent_clk, +}; + +/* + * STM32MP2x: + * - do not use SAI parent clock source selection + * - do not use DMA burst mode + */ +static const struct stm32_sai_conf stm32_sai_conf_mp25 = { + .no_dma_burst = true, }; static const struct of_device_id stm32_sai_ids[] = { { .compatible = "st,stm32f4-sai", .data = (void *)&stm32_sai_conf_f4 }, { .compatible = "st,stm32h7-sai", .data = (void *)&stm32_sai_conf_h7 }, + { .compatible = "st,stm32mp25-sai", .data = (void *)&stm32_sai_conf_mp25 }, {} }; @@ -148,6 +164,29 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, return ret; } +static int stm32_sai_get_parent_clk(struct stm32_sai_data *sai) +{ + struct device *dev = &sai->pdev->dev; + + sai->clk_x8k = devm_clk_get(dev, "x8k"); + if (IS_ERR(sai->clk_x8k)) { + if (PTR_ERR(sai->clk_x8k) != -EPROBE_DEFER) + dev_err(dev, "missing x8k parent clock: %ld\n", + PTR_ERR(sai->clk_x8k)); + return PTR_ERR(sai->clk_x8k); + } + + sai->clk_x11k = devm_clk_get(dev, "x11k"); + if (IS_ERR(sai->clk_x11k)) { + if (PTR_ERR(sai->clk_x11k) != -EPROBE_DEFER) + dev_err(dev, "missing x11k parent clock: %ld\n", + PTR_ERR(sai->clk_x11k)); + return PTR_ERR(sai->clk_x11k); + } + + return 0; +} + static int stm32_sai_probe(struct platform_device *pdev) { struct stm32_sai_data *sai; @@ -160,6 +199,8 @@ static int stm32_sai_probe(struct platform_device *pdev) if (!sai) return -ENOMEM; + sai->pdev = pdev; + sai->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sai->base)) return PTR_ERR(sai->base); @@ -178,15 +219,11 @@ static int stm32_sai_probe(struct platform_device *pdev) "missing bus clock pclk\n"); } - sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k"); - if (IS_ERR(sai->clk_x8k)) - return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x8k), - "missing x8k parent clock\n"); - - sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k"); - if (IS_ERR(sai->clk_x11k)) - return dev_err_probe(&pdev->dev, PTR_ERR(sai->clk_x11k), - "missing x11k parent clock\n"); + if (sai->conf.get_sai_ck_parent) { + ret = sai->conf.get_sai_ck_parent(sai); + if (ret) + return ret; + } /* init irqs */ sai->irq = platform_get_irq(pdev, 0); @@ -227,7 +264,6 @@ static int stm32_sai_probe(struct platform_device *pdev) } clk_disable_unprepare(sai->pclk); - sai->pdev = pdev; sai->set_sync = &stm32_sai_set_sync; platform_set_drvdata(pdev, sai); diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h index 33e4bff8c2f575..07b71133db2a64 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -264,16 +264,22 @@ enum stm32_sai_syncout { STM_SAI_SYNC_OUT_B, }; +struct stm32_sai_data; + /** * struct stm32_sai_conf - SAI configuration + * @get_sai_ck_parent: get parent clock of SAI kernel clock * @version: SAI version * @fifo_size: SAI fifo size as words number * @has_spdif_pdm: SAI S/PDIF and PDM features support flag + * @no_dma_burst: Support only DMA single transfers if set */ struct stm32_sai_conf { + int (*get_sai_ck_parent)(struct stm32_sai_data *sai); u32 version; u32 fifo_size; bool has_spdif_pdm; + bool no_dma_burst; }; /** diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 5828f9dd866e4d..3efbf4aaf96549 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -53,13 +53,16 @@ #define STM_SAI_PROTOCOL_IS_SPDIF(ip) ((ip)->spdif) #define STM_SAI_HAS_SPDIF(x) ((x)->pdata->conf.has_spdif_pdm) #define STM_SAI_HAS_PDM(x) ((x)->pdata->conf.has_spdif_pdm) -#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata)) +#define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4((x)->pdata)) #define SAI_IEC60958_BLOCK_FRAMES 192 #define SAI_IEC60958_STATUS_BYTES 24 #define SAI_MCLK_NAME_LEN 32 #define SAI_RATE_11K 11025 +#define SAI_MAX_SAMPLE_RATE_8K 192000 +#define SAI_MAX_SAMPLE_RATE_11K 176400 +#define SAI_CK_RATE_TOLERANCE 1000 /* ppm */ /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) @@ -80,6 +83,7 @@ * @dir: SAI block direction (playback or capture). set at init * @master: SAI block mode flag. (true=master, false=slave) set at init * @spdif: SAI S/PDIF iec60958 mode flag. set at init + * @sai_ck_used: flag set while exclusivity on SAI kernel clock is active * @fmt: SAI block format. relevant only for custom protocols. set at init * @sync: SAI block synchronization mode. (none, internal or external) * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B) @@ -93,6 +97,8 @@ * @iec958: iec958 data * @ctrl_lock: control lock * @irq_lock: prevent race condition with IRQ + * @set_sai_ck_rate: set SAI kernel clock rate + * @put_sai_ck_rate: put SAI kernel clock rate */ struct stm32_sai_sub_data { struct platform_device *pdev; @@ -112,6 +118,7 @@ struct stm32_sai_sub_data { int dir; bool master; bool spdif; + bool sai_ck_used; int fmt; int sync; int synco; @@ -125,6 +132,8 @@ struct stm32_sai_sub_data { struct snd_aes_iec958 iec958; struct mutex ctrl_lock; /* protect resources accessed by controls */ spinlock_t irq_lock; /* used to prevent race condition with IRQ */ + int (*set_sai_ck_rate)(struct stm32_sai_sub_data *sai, unsigned int rate); + void (*put_sai_ck_rate)(struct stm32_sai_sub_data *sai); }; enum stm32_sai_fifo_th { @@ -351,8 +360,26 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai, return ret; } -static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai, - unsigned int rate) +static bool stm32_sai_rate_accurate(unsigned int max_rate, unsigned int rate) +{ + u64 delta, dividend; + int ratio; + + ratio = DIV_ROUND_CLOSEST(max_rate, rate); + if (!ratio) + return false; + + dividend = mul_u32_u32(1000000, abs(max_rate - (ratio * rate))); + delta = div_u64(dividend, max_rate); + + if (delta <= SAI_CK_RATE_TOLERANCE) + return true; + + return false; +} + +static int stm32_sai_set_parent_clk(struct stm32_sai_sub_data *sai, + unsigned int rate) { struct platform_device *pdev = sai->pdev; struct clk *parent_clk = sai->pdata->clk_x8k; @@ -370,6 +397,92 @@ static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai, return ret; } +static void stm32_sai_put_parent_rate(struct stm32_sai_sub_data *sai) +{ + if (sai->sai_ck_used) { + sai->sai_ck_used = false; + clk_rate_exclusive_put(sai->sai_ck); + } +} + +static int stm32_sai_set_parent_rate(struct stm32_sai_sub_data *sai, + unsigned int rate) +{ + struct platform_device *pdev = sai->pdev; + unsigned int sai_ck_rate, sai_ck_max_rate, sai_curr_rate, sai_new_rate; + int div, ret; + + /* + * Set maximum expected kernel clock frequency + * - mclk on or spdif: + * f_sai_ck = MCKDIV * mclk-fs * fs + * Here typical 256 ratio is assumed for mclk-fs + * - mclk off: + * f_sai_ck = MCKDIV * FRL * fs + * Where FRL=[8..256], MCKDIV=[1..n] (n depends on SAI version) + * Set constraint MCKDIV * FRL <= 256, to ensure MCKDIV is in available range + * f_sai_ck = sai_ck_max_rate * pow_of_two(FRL) / 256 + */ + if (!(rate % SAI_RATE_11K)) + sai_ck_max_rate = SAI_MAX_SAMPLE_RATE_11K * 256; + else + sai_ck_max_rate = SAI_MAX_SAMPLE_RATE_8K * 256; + + if (!sai->sai_mclk && !STM_SAI_PROTOCOL_IS_SPDIF(sai)) + sai_ck_max_rate /= DIV_ROUND_CLOSEST(256, roundup_pow_of_two(sai->fs_length)); + + /* + * Request exclusivity, as the clock is shared by SAI sub-blocks and by + * some SAI instances. This allows to ensure that the rate cannot be + * changed while one or more SAIs are using the clock. + */ + clk_rate_exclusive_get(sai->sai_ck); + sai->sai_ck_used = true; + + /* + * Check current kernel clock rate. If it gives the expected accuracy + * return immediately. + */ + sai_curr_rate = clk_get_rate(sai->sai_ck); + if (stm32_sai_rate_accurate(sai_ck_max_rate, sai_curr_rate)) + return 0; + + /* + * Otherwise try to set the maximum rate and check the new actual rate. + * If the new rate does not give the expected accuracy, try to set + * lower rates for the kernel clock. + */ + sai_ck_rate = sai_ck_max_rate; + div = 1; + do { + /* Check new rate accuracy. Return if ok */ + sai_new_rate = clk_round_rate(sai->sai_ck, sai_ck_rate); + if (stm32_sai_rate_accurate(sai_ck_rate, sai_new_rate)) { + ret = clk_set_rate(sai->sai_ck, sai_ck_rate); + if (ret) { + dev_err(&pdev->dev, "Error %d setting sai_ck rate. %s", + ret, ret == -EBUSY ? + "Active stream rates may be in conflict\n" : "\n"); + goto err; + } + + return 0; + } + + /* Try a lower frequency */ + div++; + sai_ck_rate = sai_ck_max_rate / div; + } while (sai_ck_rate > rate); + + /* No accurate rate found */ + dev_err(&pdev->dev, "Failed to find an accurate rate"); + +err: + stm32_sai_put_parent_rate(sai); + + return -EINVAL; +} + static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { @@ -565,11 +678,15 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, clk_rate_exclusive_put(sai->sai_mclk); sai->mclk_rate = 0; } + + if (sai->put_sai_ck_rate) + sai->put_sai_ck_rate(sai); + return 0; } - /* If master clock is used, set parent clock now */ - ret = stm32_sai_set_parent_clock(sai, freq); + /* If master clock is used, configure SAI kernel clock now */ + ret = sai->set_sai_ck_rate(sai, freq); if (ret) return ret; @@ -993,7 +1110,7 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, int ret; if (!sai->sai_mclk) { - ret = stm32_sai_set_parent_clock(sai, rate); + ret = sai->set_sai_ck_rate(sai, rate); if (ret) return ret; } @@ -1154,6 +1271,14 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(sai->sai_ck); + /* + * Release kernel clock if following conditions are fulfilled + * - Master clock is not used. Kernel clock won't be released trough sysclk + * - Put handler is defined. Involve that clock is managed exclusively + */ + if (!sai->sai_mclk && sai->put_sai_ck_rate) + sai->put_sai_ck_rate(sai); + spin_lock_irqsave(&sai->irq_lock, flags); sai->substream = NULL; spin_unlock_irqrestore(&sai->irq_lock, flags); @@ -1188,7 +1313,7 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) * constraints). */ sai->dma_params.maxburst = 4; - if (sai->pdata->conf.fifo_size < 8) + if (sai->pdata->conf.fifo_size < 8 || sai->pdata->conf.no_dma_burst) sai->dma_params.maxburst = 1; /* Buswidth will be set by framework at runtime */ sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; @@ -1526,6 +1651,13 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) return -EINVAL; } + if (sai->pdata->conf.get_sai_ck_parent) { + sai->set_sai_ck_rate = stm32_sai_set_parent_clk; + } else { + sai->set_sai_ck_rate = stm32_sai_set_parent_rate; + sai->put_sai_ck_rate = stm32_sai_put_parent_rate; + } + ret = stm32_sai_sub_parse_of(pdev, sai); if (ret) return ret; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 330bc0c09f56bf..933a0913237c8e 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -226,6 +226,43 @@ #define SUN8I_H3_CODEC_DAC_DBG (0x48) #define SUN8I_H3_CODEC_ADC_DBG (0x4c) +/* H616 specific registers */ +#define SUN50I_H616_CODEC_DAC_FIFOC (0x10) + +#define SUN50I_DAC_FIFO_STA (0x14) +#define SUN50I_DAC_TXE_INT (3) +#define SUN50I_DAC_TXU_INT (2) +#define SUN50I_DAC_TXO_INT (1) + +#define SUN50I_DAC_CNT (0x24) +#define SUN50I_DAC_DG_REG (0x28) +#define SUN50I_DAC_DAP_CTL (0xf0) + +#define SUN50I_H616_DAC_AC_DAC_REG (0x310) +#define SUN50I_H616_DAC_LEN (15) +#define SUN50I_H616_DAC_REN (14) +#define SUN50I_H616_LINEOUTL_EN (13) +#define SUN50I_H616_LMUTE (12) +#define SUN50I_H616_LINEOUTR_EN (11) +#define SUN50I_H616_RMUTE (10) +#define SUN50I_H616_RSWITCH (9) +#define SUN50I_H616_RAMPEN (8) +#define SUN50I_H616_LINEOUTL_SEL (6) +#define SUN50I_H616_LINEOUTR_SEL (5) +#define SUN50I_H616_LINEOUT_VOL (0) + +#define SUN50I_H616_DAC_AC_MIXER_REG (0x314) +#define SUN50I_H616_LMIX_LDAC (21) +#define SUN50I_H616_LMIX_RDAC (20) +#define SUN50I_H616_RMIX_RDAC (17) +#define SUN50I_H616_RMIX_LDAC (16) +#define SUN50I_H616_LMIXEN (11) +#define SUN50I_H616_RMIXEN (10) + +#define SUN50I_H616_DAC_AC_RAMP_REG (0x31c) +#define SUN50I_H616_RAMP_STEP (4) +#define SUN50I_H616_RDEN (0) + /* TODO H3 DAP (Digital Audio Processing) bits */ struct sun4i_codec { @@ -238,6 +275,8 @@ struct sun4i_codec { /* ADC_FIFOC register is at different offset on different SoCs */ struct regmap_field *reg_adc_fifoc; + /* DAC_FIFOC register is at different offset on different SoCs */ + struct regmap_field *reg_dac_fifoc; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; @@ -246,19 +285,19 @@ struct sun4i_codec { static void sun4i_codec_start_playback(struct sun4i_codec *scodec) { /* Flush TX FIFO */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); /* Enable DAC DRQ */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); } static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) { /* Disable DAC DRQ */ - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); + regmap_field_clear_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN)); } static void sun4i_codec_start_capture(struct sun4i_codec *scodec) @@ -356,13 +395,13 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, u32 val; /* Flush the TX FIFO */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH)); /* Set TX FIFO Empty Trigger Level */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, - 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); + regmap_field_update_bits(scodec->reg_dac_fifoc, + 0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL, + 0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL); if (substream->runtime->rate > 32000) /* Use 64 bits FIR filter */ @@ -371,13 +410,13 @@ static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, /* Use 32 bits FIR filter */ val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION); - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), - val); + regmap_field_update_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION), + val); /* Send zeros when we have an underrun */ - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); + regmap_field_clear_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT)); return 0; }; @@ -510,9 +549,9 @@ static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, u32 val; /* Set DAC sample rate */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, - hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); + regmap_field_update_bits(scodec->reg_dac_fifoc, + 7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS, + hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS); /* Set the number of channels we want to use */ if (params_channels(params) == 1) @@ -520,27 +559,27 @@ static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, else val = 0; - regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), - val); + regmap_field_update_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN), + val); /* Set the number of sample bits to either 16 or 24 bits */ if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) { - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); /* Set TX FIFO mode to padding the LSBs with 0 */ - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); + regmap_field_clear_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; } else { - regmap_clear_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); + regmap_field_clear_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS)); /* Set TX FIFO mode to repeat the MSB */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); + regmap_field_set_bits(scodec->reg_dac_fifoc, + BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE)); scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; } @@ -587,8 +626,8 @@ static int sun4i_codec_startup(struct snd_pcm_substream *substream, * Stop issuing DRQ when we have room for less than 16 samples * in our TX FIFO */ - regmap_set_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, - 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); + regmap_field_set_bits(scodec->reg_dac_fifoc, + 3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT); return clk_prepare_enable(scodec->clk_module); } @@ -1518,6 +1557,150 @@ static struct snd_soc_card *sun8i_v3s_codec_create_card(struct device *dev) return card; }; +static const struct snd_kcontrol_new sun50i_h616_codec_codec_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, + sun6i_codec_dvol_scale), + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_LINEOUT_VOL, 0x1f, 0, + sun6i_codec_lineout_vol_scale), + SOC_DOUBLE("Line Out Playback Switch", + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_LINEOUTL_EN, + SUN50I_H616_LINEOUTR_EN, 1, 0), +}; + +static const struct snd_kcontrol_new sun50i_h616_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE("DAC Playback Switch", + SUN50I_H616_DAC_AC_MIXER_REG, + SUN50I_H616_LMIX_LDAC, + SUN50I_H616_RMIX_RDAC, 1, 0), + SOC_DAPM_DOUBLE("DAC Reversed Playback Switch", + SUN50I_H616_DAC_AC_MIXER_REG, + SUN50I_H616_LMIX_RDAC, + SUN50I_H616_RMIX_LDAC, 1, 0), +}; + +static SOC_ENUM_DOUBLE_DECL(sun50i_h616_codec_lineout_src_enum, + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_LINEOUTL_SEL, + SUN50I_H616_LINEOUTR_SEL, + sun6i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun50i_h616_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun50i_h616_codec_lineout_src_enum), +}; + +static const struct snd_soc_dapm_widget sun50i_h616_codec_codec_widgets[] = { + /* Digital parts of the DACs */ + SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_EN_DA, 0, + NULL, 0), + + /* Analog parts of the DACs */ + SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_DAC_LEN, 0), + SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", + SUN50I_H616_DAC_AC_DAC_REG, + SUN50I_H616_DAC_REN, 0), + + /* Mixers */ + SOC_MIXER_ARRAY("Left Mixer", SUN50I_H616_DAC_AC_MIXER_REG, + SUN50I_H616_LMIXEN, 0, + sun50i_h616_codec_mixer_controls), + SOC_MIXER_ARRAY("Right Mixer", SUN50I_H616_DAC_AC_MIXER_REG, + SUN50I_H616_RMIXEN, 0, + sun50i_h616_codec_mixer_controls), + + /* Line Out path */ + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun50i_h616_codec_lineout_src), + SND_SOC_DAPM_OUT_DRV("Line Out Ramp Controller", + SUN50I_H616_DAC_AC_RAMP_REG, + SUN50I_H616_RDEN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + +static const struct snd_soc_component_driver sun50i_h616_codec_codec = { + .controls = sun50i_h616_codec_codec_controls, + .num_controls = ARRAY_SIZE(sun50i_h616_codec_codec_controls), + .dapm_widgets = sun50i_h616_codec_codec_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_codec_widgets), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, +}; + +static const struct snd_kcontrol_new sun50i_h616_card_controls[] = { + SOC_DAPM_PIN_SWITCH("LINEOUT"), +}; + +static const struct snd_soc_dapm_widget sun50i_h616_codec_card_dapm_widgets[] = { + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), +}; + +/* Connect digital side enables to analog side widgets */ +static const struct snd_soc_dapm_route sun50i_h616_codec_card_routes[] = { + /* DAC Routes */ + { "Left DAC", NULL, "DAC Enable" }, + { "Right DAC", NULL, "DAC Enable" }, + + /* Left Mixer Routes */ + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + + /* Right Mixer Routes */ + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + + /* Line Out Routes */ + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" }, + { "Line Out Ramp Controller", NULL, "Line Out Source Playback Route" }, + { "LINEOUT", NULL, "Line Out Ramp Controller" }, +}; + +static struct snd_soc_card *sun50i_h616_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dai_link->playback_only = true; + card->dai_link->capture_only = false; + + card->dev = dev; + card->owner = THIS_MODULE; + card->name = "H616 Audio Codec"; + card->driver_name = "sun4i-codec"; + card->controls = sun50i_h616_card_controls; + card->num_controls = ARRAY_SIZE(sun50i_h616_card_controls); + card->dapm_widgets = sun50i_h616_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun50i_h616_codec_card_dapm_widgets); + card->dapm_routes = sun50i_h616_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun50i_h616_codec_card_routes); + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1560,14 +1743,24 @@ static const struct regmap_config sun8i_v3s_codec_regmap_config = { .max_register = SUN8I_H3_CODEC_ADC_DBG, }; +static const struct regmap_config sun50i_h616_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN50I_H616_DAC_AC_RAMP_REG, + .cache_type = REGCACHE_NONE, +}; + struct sun4i_codec_quirks { const struct regmap_config *regmap_config; const struct snd_soc_component_driver *codec; struct snd_soc_card * (*create_card)(struct device *dev); struct reg_field reg_adc_fifoc; /* used for regmap_field */ + struct reg_field reg_dac_fifoc; /* used for regmap_field */ unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ bool has_reset; + bool playback_only; }; static const struct sun4i_codec_quirks sun4i_codec_quirks = { @@ -1575,6 +1768,7 @@ static const struct sun4i_codec_quirks sun4i_codec_quirks = { .codec = &sun4i_codec_codec, .create_card = sun4i_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, }; @@ -1584,6 +1778,7 @@ static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { .codec = &sun6i_codec_codec, .create_card = sun6i_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, .has_reset = true, @@ -1594,6 +1789,7 @@ static const struct sun4i_codec_quirks sun7i_codec_quirks = { .codec = &sun7i_codec_codec, .create_card = sun4i_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, }; @@ -1603,6 +1799,7 @@ static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { .codec = &sun8i_a23_codec_codec, .create_card = sun8i_a23_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, .has_reset = true, @@ -1618,6 +1815,7 @@ static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { .codec = &sun8i_a23_codec_codec, .create_card = sun8i_h3_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, .has_reset = true, @@ -1632,11 +1830,21 @@ static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = { .codec = &sun8i_a23_codec_codec, .create_card = sun8i_v3s_codec_create_card, .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31), .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, .has_reset = true, }; +static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = { + .regmap_config = &sun50i_h616_codec_regmap_config, + .codec = &sun50i_h616_codec_codec, + .create_card = sun50i_h616_codec_create_card, + .reg_dac_fifoc = REG_FIELD(SUN50I_H616_CODEC_DAC_FIFOC, 0, 31), + .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, + .has_reset = true, +}; + static const struct of_device_id sun4i_codec_of_match[] = { { .compatible = "allwinner,sun4i-a10-codec", @@ -1662,6 +1870,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { .compatible = "allwinner,sun8i-v3s-codec", .data = &sun8i_v3s_codec_quirks, }, + { + .compatible = "allwinner,sun50i-h616-codec", + .data = &sun50i_h616_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); @@ -1739,6 +1951,16 @@ static int sun4i_codec_probe(struct platform_device *pdev) return ret; } + scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev, + scodec->regmap, + quirks->reg_dac_fifoc); + if (IS_ERR(scodec->reg_dac_fifoc)) { + ret = PTR_ERR(scodec->reg_dac_fifoc); + dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", + ret); + return ret; + } + /* Enable the bus clock */ if (clk_prepare_enable(scodec->clk_apb)) { dev_err(&pdev->dev, "Failed to enable the APB clock\n"); @@ -1760,10 +1982,13 @@ static int sun4i_codec_probe(struct platform_device *pdev) scodec->playback_dma_data.maxburst = 8; scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - /* DMA configuration for RX FIFO */ - scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata; - scodec->capture_dma_data.maxburst = 8; - scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + if (!quirks->playback_only) { + /* DMA configuration for RX FIFO */ + scodec->capture_dma_data.addr = res->start + + quirks->reg_adc_rxdata; + scodec->capture_dma_data.maxburst = 8; + scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + } ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec, &sun4i_codec_dai, 1); @@ -1837,4 +2062,5 @@ MODULE_AUTHOR("Emilio López "); MODULE_AUTHOR("Jon Smirl "); MODULE_AUTHOR("Maxime Ripard "); MODULE_AUTHOR("Chen-Yu Tsai "); +MODULE_AUTHOR("Ryan Walklin #include @@ -285,6 +285,11 @@ static int tegra_admaif_hw_params(struct snd_pcm_substream *substream, cif_conf.client_bits = TEGRA_ACIF_BITS_16; valid_bit = DATA_16BIT; break; + case SNDRV_PCM_FORMAT_S24_LE: + cif_conf.audio_bits = TEGRA_ACIF_BITS_32; + cif_conf.client_bits = TEGRA_ACIF_BITS_24; + valid_bit = DATA_32BIT; + break; case SNDRV_PCM_FORMAT_S32_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_32; cif_conf.client_bits = TEGRA_ACIF_BITS_32; @@ -561,6 +566,7 @@ static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -570,6 +576,7 @@ static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra_admaif_dai_ops, \ diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index 109f763fe211eb..3e6e8f51f380ba 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_adx.c - Tegra210 ADX driver -// -// Copyright (c) 2021-2023 NVIDIA CORPORATION. All rights reserved. #include #include @@ -127,6 +127,7 @@ static int tegra210_adx_set_audio_cif(struct snd_soc_dai *dai, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -237,6 +238,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -246,6 +248,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_adx_in_dai_ops, \ @@ -260,6 +263,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { .channels_max = 16, \ .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ @@ -269,6 +273,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = { .channels_max = 16, \ .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c index 38a2d6ec033b40..a9ef22c19e814e 100644 --- a/sound/soc/tegra/tegra210_amx.c +++ b/sound/soc/tegra/tegra210_amx.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_amx.c - Tegra210 AMX driver -// -// Copyright (c) 2021-2023 NVIDIA CORPORATION. All rights reserved. #include #include @@ -144,6 +144,7 @@ static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -266,6 +267,7 @@ static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -275,6 +277,7 @@ static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_amx_in_dai_ops, \ @@ -290,6 +293,7 @@ static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -299,6 +303,7 @@ static const struct snd_soc_dai_ops tegra210_amx_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_amx_out_dai_ops, \ diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index d9b577f146dc5a..7986be71f43d6d 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_dmic.c - Tegra210 DMIC driver -// -// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. #include #include @@ -139,6 +139,7 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_32; break; @@ -325,6 +326,7 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -336,6 +338,7 @@ static struct snd_soc_dai_driver tegra210_dmic_dais[] = { .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_dmic_dai_ops, diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index a3908b15dfdc0a..07ce2dbe6c00a8 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_i2s.c - Tegra210 I2S driver -// -// Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. #include #include @@ -629,6 +629,7 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: cif_conf.audio_bits = TEGRA_ACIF_BITS_32; break; @@ -656,6 +657,11 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, sample_size = 16; cif_conf.client_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: + val = I2S_BITS_24; + sample_size = 32; + cif_conf.client_bits = TEGRA_ACIF_BITS_24; + break; case SNDRV_PCM_FORMAT_S32_LE: val = I2S_BITS_32; sample_size = 32; @@ -720,6 +726,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -729,6 +736,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -741,6 +749,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -750,6 +759,7 @@ static struct snd_soc_dai_driver tegra210_i2s_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_i2s_dai_ops, diff --git a/sound/soc/tegra/tegra210_i2s.h b/sound/soc/tegra/tegra210_i2s.h index fe478f3d843529..543332de740547 100644 --- a/sound/soc/tegra/tegra210_i2s.h +++ b/sound/soc/tegra/tegra210_i2s.h @@ -1,8 +1,8 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * tegra210_i2s.h - Definitions for Tegra210 I2S driver +/* SPDX-License-Identifier: GPL-2.0-only + * SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. * - * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. + * tegra210_i2s.h - Definitions for Tegra210 I2S driver * */ @@ -87,6 +87,7 @@ #define I2S_BITS_8 1 #define I2S_BITS_16 3 +#define I2S_BITS_24 5 #define I2S_BITS_32 7 #define I2S_CTRL_BIT_SIZE_MASK 0x7 diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c index e07e2f1d2f7075..410259d98dfb30 100644 --- a/sound/soc/tegra/tegra210_mixer.c +++ b/sound/soc/tegra/tegra210_mixer.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_mixer.c - Tegra210 MIXER driver -// -// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. #include #include @@ -248,6 +248,7 @@ static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -312,6 +313,7 @@ static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -321,6 +323,7 @@ static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_mixer_in_dai_ops, \ @@ -336,6 +339,7 @@ static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .capture = { \ @@ -345,6 +349,7 @@ static const struct snd_soc_dai_ops tegra210_mixer_in_dai_ops = { .rates = SNDRV_PCM_RATE_8000_192000, \ .formats = SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE, \ }, \ .ops = &tegra210_mixer_out_dai_ops, \ diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c index 4ead52564ab6ec..119f1750147864 100644 --- a/sound/soc/tegra/tegra210_mvc.c +++ b/sound/soc/tegra/tegra210_mvc.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_mvc.c - Tegra210 MVC driver -// -// Copyright (c) 2021 NVIDIA CORPORATION. All rights reserved. #include #include @@ -441,6 +441,7 @@ static int tegra210_mvc_set_audio_cif(struct tegra210_mvc *mvc, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -569,6 +570,7 @@ static struct snd_soc_dai_driver tegra210_mvc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -578,6 +580,7 @@ static struct snd_soc_dai_driver tegra210_mvc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -592,6 +595,7 @@ static struct snd_soc_dai_driver tegra210_mvc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -601,6 +605,7 @@ static struct snd_soc_dai_driver tegra210_mvc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_mvc_dai_ops, diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c index e2bc604e8b797b..c595cec9baaba8 100644 --- a/sound/soc/tegra/tegra210_ope.c +++ b/sound/soc/tegra/tegra210_ope.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_ope.c - Tegra210 OPE driver -// -// Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. #include #include @@ -47,6 +47,7 @@ static int tegra210_ope_set_audio_cif(struct tegra210_ope *ope, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -129,6 +130,7 @@ static struct snd_soc_dai_driver tegra210_ope_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -138,6 +140,7 @@ static struct snd_soc_dai_driver tegra210_ope_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, }, @@ -150,6 +153,7 @@ static struct snd_soc_dai_driver tegra210_ope_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -159,6 +163,7 @@ static struct snd_soc_dai_driver tegra210_ope_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_ope_dai_ops, diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c index e16bbb44cc77c7..df88708c733cef 100644 --- a/sound/soc/tegra/tegra210_sfc.c +++ b/sound/soc/tegra/tegra210_sfc.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. // // tegra210_sfc.c - Tegra210 SFC driver -// -// Copyright (c) 2021-2023 NVIDIA CORPORATION. All rights reserved. #include #include @@ -3133,6 +3133,7 @@ static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc, case SNDRV_PCM_FORMAT_S16_LE: audio_bits = TEGRA_ACIF_BITS_16; break; + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: audio_bits = TEGRA_ACIF_BITS_32; break; @@ -3395,6 +3396,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -3404,6 +3406,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_sfc_in_dai_ops, @@ -3417,6 +3420,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { @@ -3426,6 +3430,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, }, .ops = &tegra210_sfc_out_dai_ops, diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c index 77296237575a1d..d9900c69e536f2 100644 --- a/sound/soc/ti/rx51.c +++ b/sound/soc/ti/rx51.c @@ -371,7 +371,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0); if (!dai_node) { - dev_err(&pdev->dev, "McBSP node is not provided\n"); + dev_err(card->dev, "McBSP node is not provided\n"); return -EINVAL; } rx51_dai[0].cpus->dai_name = NULL; @@ -381,7 +381,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,audio-codec", 0); if (!dai_node) { - dev_err(&pdev->dev, "Codec node is not provided\n"); + dev_err(card->dev, "Codec node is not provided\n"); return -EINVAL; } rx51_dai[0].codecs->name = NULL; @@ -389,7 +389,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,audio-codec", 1); if (!dai_node) { - dev_err(&pdev->dev, "Auxiliary Codec node is not provided\n"); + dev_err(card->dev, "Auxiliary Codec node is not provided\n"); return -EINVAL; } rx51_aux_dev[0].dlc.name = NULL; @@ -399,7 +399,7 @@ static int rx51_soc_probe(struct platform_device *pdev) dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0); if (!dai_node) { - dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); + dev_err(card->dev, "Headphone amplifier node is not provided\n"); return -EINVAL; } rx51_aux_dev[1].dlc.name = NULL; @@ -408,7 +408,7 @@ static int rx51_soc_probe(struct platform_device *pdev) rx51_codec_conf[1].dlc.of_node = dai_node; } - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata = devm_kzalloc(card->dev, sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) return -ENOMEM; @@ -439,7 +439,7 @@ static int rx51_soc_probe(struct platform_device *pdev) err = devm_snd_soc_register_card(card->dev, card); if (err) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", err); + dev_err(card->dev, "snd_soc_register_card failed (%d)\n", err); return err; } diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c index 0eba607581341e..d63def8615eb72 100644 --- a/sound/soc/uniphier/aio-core.c +++ b/sound/soc/uniphier/aio-core.c @@ -838,6 +838,7 @@ int aio_oport_set_stream_type(struct uniphier_aio_sub *sub, { struct regmap *r = sub->aio->chip->regmap; u32 repet = 0, pause = OPORTMXPAUDAT_PAUSEPC_CMN; + int ret; switch (pc) { case IEC61937_PC_AC3: @@ -880,8 +881,13 @@ int aio_oport_set_stream_type(struct uniphier_aio_sub *sub, break; } - regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet); - regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause); + ret = regmap_write(r, OPORTMXREPET(sub->swm->oport.map), repet); + if (ret) + return ret; + + ret = regmap_write(r, OPORTMXPAUDAT(sub->swm->oport.map), pause); + if (ret) + return ret; return 0; } @@ -921,16 +927,19 @@ int aio_src_set_param(struct uniphier_aio_sub *sub, { struct regmap *r = sub->aio->chip->regmap; u32 v; + int ret; if (sub->swm->dir != PORT_DIR_OUTPUT) return 0; - regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map), + ret = regmap_write(r, OPORTMXSRC1CTR(sub->swm->oport.map), OPORTMXSRC1CTR_THMODE_SRC | OPORTMXSRC1CTR_SRCPATH_CALC | OPORTMXSRC1CTR_SYNC_ASYNC | OPORTMXSRC1CTR_FSIIPSEL_INNER | OPORTMXSRC1CTR_FSISEL_ACLK); + if (ret) + return ret; switch (params_rate(params)) { default: @@ -951,12 +960,18 @@ int aio_src_set_param(struct uniphier_aio_sub *sub, break; } - regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map), + + ret = regmap_write(r, OPORTMXRATE_I(sub->swm->oport.map), v | OPORTMXRATE_I_ACLKSRC_APLL | OPORTMXRATE_I_LRCKSTP_STOP); - regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map), + if (ret) + return ret; + + ret = regmap_update_bits(r, OPORTMXRATE_I(sub->swm->oport.map), OPORTMXRATE_I_LRCKSTP_MASK, OPORTMXRATE_I_LRCKSTP_START); + if (ret) + return ret; return 0; } diff --git a/sound/soc/uniphier/evea.c b/sound/soc/uniphier/evea.c index 662e45882c90d6..f6c6eb95262a42 100644 --- a/sound/soc/uniphier/evea.c +++ b/sound/soc/uniphier/evea.c @@ -384,7 +384,7 @@ static int evea_codec_resume(struct snd_soc_component *component) return ret; } -static struct snd_soc_component_driver soc_codec_evea = { +static const struct snd_soc_component_driver soc_codec_evea = { .probe = evea_codec_probe, .suspend = evea_codec_suspend, .resume = evea_codec_resume, diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index a2dd739fdf2df3..7798957c6504d5 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -733,7 +733,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape"); if (IS_ERR(drvdata->reg_vape)) { - ret = (int)PTR_ERR(drvdata->reg_vape); + ret = PTR_ERR(drvdata->reg_vape); dev_err(&pdev->dev, "%s: ERROR: Failed to get Vape supply (%d)!\n", __func__, ret); @@ -743,7 +743,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(drvdata->pclk)) { - ret = (int)PTR_ERR(drvdata->pclk); + ret = PTR_ERR(drvdata->pclk); dev_err(&pdev->dev, "%s: ERROR: devm_clk_get of pclk failed (%d)!\n", __func__, ret); @@ -752,7 +752,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) drvdata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(drvdata->clk)) { - ret = (int)PTR_ERR(drvdata->clk); + ret = PTR_ERR(drvdata->clk); dev_err(&pdev->dev, "%s: ERROR: devm_clk_get failed (%d)!\n", __func__, ret); diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index a1339f9ef12a6a..1b44119edfbc4a 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -2107,7 +2107,7 @@ static struct platform_driver cs4231_driver = { .of_match_table = cs4231_match, }, .probe = cs4231_probe, - .remove_new = cs4231_remove, + .remove = cs4231_remove, }; module_platform_driver(cs4231_driver); diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 050e98f32d3621..69f1c9e37f4b97 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -2616,7 +2616,7 @@ static int dbri_probe(struct platform_device *op) strcpy(card->driver, "DBRI"); strcpy(card->shortname, "Sun DBRI"); rp = &op->resource[0]; - sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d", + sprintf(card->longname, "%s at 0x%02lx:0x%016llx, irq %d", card->shortname, rp->flags & 0xffL, (unsigned long long)rp->start, irq); @@ -2682,7 +2682,7 @@ static struct platform_driver dbri_sbus_driver = { .of_match_table = dbri_match, }, .probe = dbri_probe, - .remove_new = dbri_remove, + .remove = dbri_remove, }; module_platform_driver(dbri_sbus_driver); diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index 33e962178c9363..d562a30b087f01 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -61,8 +61,10 @@ static void usb6fire_chip_abort(struct sfire_chip *chip) } } -static void usb6fire_chip_destroy(struct sfire_chip *chip) +static void usb6fire_card_free(struct snd_card *card) { + struct sfire_chip *chip = card->private_data; + if (chip) { if (chip->pcm) usb6fire_pcm_destroy(chip); @@ -72,8 +74,6 @@ static void usb6fire_chip_destroy(struct sfire_chip *chip) usb6fire_comm_destroy(chip); if (chip->control) usb6fire_control_destroy(chip); - if (chip->card) - snd_card_free(chip->card); } } @@ -136,6 +136,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf, chip->regidx = regidx; chip->intf_count = 1; chip->card = card; + card->private_free = usb6fire_card_free; ret = usb6fire_comm_init(chip); if (ret < 0) @@ -162,7 +163,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf, return 0; destroy_chip: - usb6fire_chip_destroy(chip); + snd_card_free(card); return ret; } @@ -181,7 +182,6 @@ static void usb6fire_chip_disconnect(struct usb_interface *intf) chip->shutdown = true; usb6fire_chip_abort(chip); - usb6fire_chip_destroy(chip); } } } diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c index 772c0ecb707738..05f964347ed6c2 100644 --- a/sound/usb/caiaq/audio.c +++ b/sound/usb/caiaq/audio.c @@ -858,14 +858,20 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev) return 0; } -void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev) +void snd_usb_caiaq_audio_disconnect(struct snd_usb_caiaqdev *cdev) { struct device *dev = caiaqdev_to_dev(cdev); dev_dbg(dev, "%s(%p)\n", __func__, cdev); stream_stop(cdev); +} + +void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev) +{ + struct device *dev = caiaqdev_to_dev(cdev); + + dev_dbg(dev, "%s(%p)\n", __func__, cdev); free_urbs(cdev->data_urbs_in); free_urbs(cdev->data_urbs_out); kfree(cdev->data_cb_info); } - diff --git a/sound/usb/caiaq/audio.h b/sound/usb/caiaq/audio.h index 869bf6264d6a09..07f5d064456cf7 100644 --- a/sound/usb/caiaq/audio.h +++ b/sound/usb/caiaq/audio.h @@ -3,6 +3,7 @@ #define CAIAQ_AUDIO_H int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_audio_disconnect(struct snd_usb_caiaqdev *cdev); void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev); #endif /* CAIAQ_AUDIO_H */ diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index b5cbf1f195c48c..dfd820483849eb 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -376,6 +376,17 @@ static void setup_card(struct snd_usb_caiaqdev *cdev) dev_err(dev, "Unable to set up control system (ret=%d)\n", ret); } +static void card_free(struct snd_card *card) +{ + struct snd_usb_caiaqdev *cdev = caiaqdev(card); + +#ifdef CONFIG_SND_USB_CAIAQ_INPUT + snd_usb_caiaq_input_free(cdev); +#endif + snd_usb_caiaq_audio_free(cdev); + usb_reset_device(cdev->chip.dev); +} + static int create_card(struct usb_device *usb_dev, struct usb_interface *intf, struct snd_card **cardp) @@ -489,6 +500,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev) cdev->vendor_name, cdev->product_name, usbpath); setup_card(cdev); + card->private_free = card_free; return 0; err_kill_urb: @@ -534,15 +546,14 @@ static void snd_disconnect(struct usb_interface *intf) snd_card_disconnect(card); #ifdef CONFIG_SND_USB_CAIAQ_INPUT - snd_usb_caiaq_input_free(cdev); + snd_usb_caiaq_input_disconnect(cdev); #endif - snd_usb_caiaq_audio_free(cdev); + snd_usb_caiaq_audio_disconnect(cdev); usb_kill_urb(&cdev->ep1_in_urb); usb_kill_urb(&cdev->midi_out_urb); - snd_card_free(card); - usb_reset_device(interface_to_usbdev(intf)); + snd_card_free_when_closed(card); } diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index 84f26dce7f5d03..a9130891bb696d 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c @@ -829,15 +829,21 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev) return ret; } -void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev) +void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev) { if (!cdev || !cdev->input_dev) return; usb_kill_urb(cdev->ep4_in_urb); + input_unregister_device(cdev->input_dev); +} + +void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev) +{ + if (!cdev || !cdev->input_dev) + return; + usb_free_urb(cdev->ep4_in_urb); cdev->ep4_in_urb = NULL; - - input_unregister_device(cdev->input_dev); cdev->input_dev = NULL; } diff --git a/sound/usb/caiaq/input.h b/sound/usb/caiaq/input.h index c42891e7be884d..fbe267f85d025f 100644 --- a/sound/usb/caiaq/input.h +++ b/sound/usb/caiaq/input.h @@ -4,6 +4,7 @@ void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *cdev, char *buf, unsigned int len); int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *cdev); +void snd_usb_caiaq_input_disconnect(struct snd_usb_caiaqdev *cdev); void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *cdev); #endif diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 8f85200292f3ff..842ba5b801eae8 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -36,6 +36,12 @@ union uac23_clock_multiplier_desc { struct uac_clock_multiplier_descriptor v3; }; +/* check whether the descriptor bLength has the minimal length */ +#define DESC_LENGTH_CHECK(p, proto) \ + ((proto) == UAC_VERSION_3 ? \ + ((p)->v3.bLength >= sizeof((p)->v3)) : \ + ((p)->v2.bLength >= sizeof((p)->v2))) + #define GET_VAL(p, proto, field) \ ((proto) == UAC_VERSION_3 ? (p)->v3.field : (p)->v2.field) @@ -58,6 +64,8 @@ static bool validate_clock_source(void *p, int id, int proto) { union uac23_clock_source_desc *cs = p; + if (!DESC_LENGTH_CHECK(cs, proto)) + return false; return GET_VAL(cs, proto, bClockID) == id; } @@ -65,13 +73,27 @@ static bool validate_clock_selector(void *p, int id, int proto) { union uac23_clock_selector_desc *cs = p; - return GET_VAL(cs, proto, bClockID) == id; + if (!DESC_LENGTH_CHECK(cs, proto)) + return false; + if (GET_VAL(cs, proto, bClockID) != id) + return false; + /* additional length check for baCSourceID array (in bNrInPins size) + * and two more fields (which sizes depend on the protocol) + */ + if (proto == UAC_VERSION_3) + return cs->v3.bLength >= sizeof(cs->v3) + cs->v3.bNrInPins + + 4 /* bmControls */ + 2 /* wCSelectorDescrStr */; + else + return cs->v2.bLength >= sizeof(cs->v2) + cs->v2.bNrInPins + + 1 /* bmControls */ + 1 /* iClockSelector */; } static bool validate_clock_multiplier(void *p, int id, int proto) { union uac23_clock_multiplier_desc *cs = p; + if (!DESC_LENGTH_CHECK(cs, proto)) + return false; return GET_VAL(cs, proto, bClockID) == id; } diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 568099467dbbcc..a29f28eb7d0c64 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -403,10 +403,15 @@ static int prepare_inbound_urb(struct snd_usb_endpoint *ep, static void notify_xrun(struct snd_usb_endpoint *ep) { struct snd_usb_substream *data_subs; + struct snd_pcm_substream *psubs; data_subs = READ_ONCE(ep->data_subs); - if (data_subs && data_subs->pcm_substream) - snd_pcm_stop_xrun(data_subs->pcm_substream); + if (!data_subs) + return; + psubs = data_subs->pcm_substream; + if (psubs && psubs->runtime && + psubs->runtime->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_stop_xrun(psubs); } static struct snd_usb_packet_info * @@ -562,7 +567,10 @@ static void snd_complete_urb(struct urb *urb) push_back_to_ready_list(ep, ctx); clear_bit(ctx->index, &ep->active_mask); snd_usb_queue_pending_output_urbs(ep, false); - atomic_dec(&ep->submitted_urbs); /* decrement at last */ + /* decrement at last, and check xrun */ + if (atomic_dec_and_test(&ep->submitted_urbs) && + !snd_usb_endpoint_implicit_feedback_sink(ep)) + notify_xrun(ep); return; } diff --git a/sound/usb/format.c b/sound/usb/format.c index 0cbf1d4fbe6edd..6049d957694ca6 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -60,6 +60,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL; /* flag potentially raw DSD capable altsettings */ fp->dsd_raw = true; + /* clear special format bit to avoid "unsupported format" msg below */ + format &= ~UAC2_FORMAT_TYPE_I_RAW_DATA; } format <<= 1; @@ -71,8 +73,11 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, sample_width = as->bBitResolution; sample_bytes = as->bSubslotSize; - if (format & UAC3_FORMAT_TYPE_I_RAW_DATA) + if (format & UAC3_FORMAT_TYPE_I_RAW_DATA) { pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL; + /* clear special format bit to avoid "unsupported format" msg below */ + format &= ~UAC3_FORMAT_TYPE_I_RAW_DATA; + } format <<= 1; break; diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index bd67027c767751..66976be06bc088 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1084,6 +1084,21 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, struct snd_kcontrol *kctl) { struct snd_usb_audio *chip = cval->head.mixer->chip; + + if (chip->quirk_flags & QUIRK_FLAG_MIC_RES_384) { + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + usb_audio_info(chip, + "set resolution quirk: cval->res = 384\n"); + cval->res = 384; + } + } else if (chip->quirk_flags & QUIRK_FLAG_MIC_RES_16) { + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + usb_audio_info(chip, + "set resolution quirk: cval->res = 16\n"); + cval->res = 16; + } + } + switch (chip->usb_id) { case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ @@ -1168,27 +1183,6 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, } break; - case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */ - case USB_ID(0x046d, 0x0808): - case USB_ID(0x046d, 0x0809): - case USB_ID(0x046d, 0x0819): /* Logitech Webcam C210 */ - case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */ - case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */ - case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */ - case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */ - case USB_ID(0x046d, 0x08ca): /* Logitech Quickcam Fusion */ - case USB_ID(0x046d, 0x0991): - case USB_ID(0x046d, 0x09a2): /* QuickCam Communicate Deluxe/S7500 */ - /* Most audio usb devices lie about volume resolution. - * Most Logitech webcams have res = 384. - * Probably there is some logitech magic behind this number --fishor - */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - usb_audio_info(chip, - "set resolution quirk: cval->res = 384\n"); - cval->res = 384; - } - break; case USB_ID(0x0495, 0x3042): /* ESS Technology Asus USB DAC */ if ((strstr(kctl->id.name, "Playback Volume") != NULL) || strstr(kctl->id.name, "Capture Volume") != NULL) { @@ -1197,28 +1191,6 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, cval->res = 1; } break; - case USB_ID(0x1224, 0x2a25): /* Jieli Technology USB PHY 2.0 */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - usb_audio_info(chip, - "set resolution quirk: cval->res = 16\n"); - cval->res = 16; - } - break; - case USB_ID(0x1bcf, 0x2283): /* NexiGo N930AF FHD Webcam */ - case USB_ID(0x03f0, 0x654a): /* HP 320 FHD Webcam */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - usb_audio_info(chip, - "set resolution quirk: cval->res = 16\n"); - cval->res = 16; - } - break; - case USB_ID(0x1bcf, 0x2281): /* HD Webcam */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - usb_audio_info(chip, - "set resolution quirk: cval->res = 16\n"); - cval->res = 16; - } - break; } } @@ -2225,7 +2197,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state, len = get_term_name(state->chip, iterm, kctl->id.name, sizeof(kctl->id.name), 0); if (!len) - len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1); + snprintf(kctl->id.name, sizeof(kctl->id.name), "Mixer Source %d", in_ch + 1); + append_ctl_name(kctl, " Volume"); usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n", diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 23260aa1919d32..0e9b5431a47f20 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -621,6 +621,16 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x1b1c, 0x0a42), .map = corsair_virtuoso_map, }, + { + /* Corsair HS80 RGB Wireless (wired mode) */ + .id = USB_ID(0x1b1c, 0x0a6a), + .map = corsair_virtuoso_map, + }, + { + /* Corsair HS80 RGB Wireless (wireless mode) */ + .id = USB_ID(0x1b1c, 0x0a6b), + .map = corsair_virtuoso_map, + }, { /* Gigabyte TRX40 Aorus Master (rear panel + front mic) */ .id = USB_ID(0x0414, 0xa001), .map = aorus_master_alc1220vb_map, diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 6456e87e2f3974..23fcd680167d02 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3498,7 +3498,7 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) } /* - * Pioneer DJ DJM Mixers + * Pioneer DJ / AlphaTheta DJM Mixers * * These devices generally have options for soft-switching the playback and * capture sources in addition to the recording level. Although different @@ -3515,17 +3515,23 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_CAP_CDLINE 0x01 #define SND_DJM_CAP_DIGITAL 0x02 #define SND_DJM_CAP_PHONO 0x03 +#define SND_DJM_CAP_PREFADER 0x05 #define SND_DJM_CAP_PFADER 0x06 #define SND_DJM_CAP_XFADERA 0x07 #define SND_DJM_CAP_XFADERB 0x08 #define SND_DJM_CAP_MIC 0x09 #define SND_DJM_CAP_AUX 0x0d #define SND_DJM_CAP_RECOUT 0x0a +#define SND_DJM_CAP_RECOUT_NOMIC 0x0e #define SND_DJM_CAP_NONE 0x0f #define SND_DJM_CAP_CH1PFADER 0x11 #define SND_DJM_CAP_CH2PFADER 0x12 #define SND_DJM_CAP_CH3PFADER 0x13 #define SND_DJM_CAP_CH4PFADER 0x14 +#define SND_DJM_CAP_CH1PREFADER 0x31 +#define SND_DJM_CAP_CH2PREFADER 0x32 +#define SND_DJM_CAP_CH3PREFADER 0x33 +#define SND_DJM_CAP_CH4PREFADER 0x34 // Playback types #define SND_DJM_PB_CH1 0x00 @@ -3551,6 +3557,7 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_900NXS2_IDX 0x3 #define SND_DJM_750MK2_IDX 0x4 #define SND_DJM_450_IDX 0x5 +#define SND_DJM_A9_IDX 0x6 #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ @@ -3579,7 +3586,7 @@ struct snd_djm_ctl { u16 wIndex; }; -static const char *snd_djm_get_label_caplevel(u16 wvalue) +static const char *snd_djm_get_label_caplevel_common(u16 wvalue) { switch (wvalue) { case 0x0000: return "-19dB"; @@ -3590,6 +3597,20 @@ static const char *snd_djm_get_label_caplevel(u16 wvalue) } }; +// The DJM-A9 has different capture levels than other, older models +static const char *snd_djm_get_label_caplevel_a9(u16 wvalue) +{ + switch (wvalue) { + case 0x0000: return "+15dB"; + case 0x0100: return "+12dB"; + case 0x0200: return "+9dB"; + case 0x0300: return "+6dB"; + case 0x0400: return "+3dB"; + case 0x0500: return "0dB"; + default: return NULL; + } +}; + static const char *snd_djm_get_label_cap_common(u16 wvalue) { switch (wvalue & 0x00ff) { @@ -3602,8 +3623,13 @@ static const char *snd_djm_get_label_cap_common(u16 wvalue) case SND_DJM_CAP_XFADERB: return "Cross Fader B"; case SND_DJM_CAP_MIC: return "Mic"; case SND_DJM_CAP_RECOUT: return "Rec Out"; + case SND_DJM_CAP_RECOUT_NOMIC: return "Rec Out without Mic"; case SND_DJM_CAP_AUX: return "Aux"; case SND_DJM_CAP_NONE: return "None"; + case SND_DJM_CAP_CH1PREFADER: return "Pre Fader Ch1"; + case SND_DJM_CAP_CH2PREFADER: return "Pre Fader Ch2"; + case SND_DJM_CAP_CH3PREFADER: return "Pre Fader Ch3"; + case SND_DJM_CAP_CH4PREFADER: return "Pre Fader Ch4"; case SND_DJM_CAP_CH1PFADER: return "Post Fader Ch1"; case SND_DJM_CAP_CH2PFADER: return "Post Fader Ch2"; case SND_DJM_CAP_CH3PFADER: return "Post Fader Ch3"; @@ -3623,6 +3649,14 @@ static const char *snd_djm_get_label_cap_850(u16 wvalue) } }; +static const char *snd_djm_get_label_caplevel(u8 device_idx, u16 wvalue) +{ + switch (device_idx) { + case SND_DJM_A9_IDX: return snd_djm_get_label_caplevel_a9(wvalue); + default: return snd_djm_get_label_caplevel_common(wvalue); + } +}; + static const char *snd_djm_get_label_cap(u8 device_idx, u16 wvalue) { switch (device_idx) { @@ -3644,7 +3678,7 @@ static const char *snd_djm_get_label_pb(u16 wvalue) static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) { switch (windex) { - case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(wvalue); + case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(device_idx, wvalue); case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(device_idx, wvalue); case SND_DJM_WINDEX_PB: return snd_djm_get_label_pb(wvalue); default: return NULL; @@ -3653,7 +3687,7 @@ static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) // common DJM capture level option values static const u16 snd_djm_opts_cap_level[] = { - 0x0000, 0x0100, 0x0200, 0x0300 }; + 0x0000, 0x0100, 0x0200, 0x0300, 0x400, 0x500 }; // DJM-250MK2 @@ -3795,6 +3829,28 @@ static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = { }; +// DJM-A9 +static const u16 snd_djm_opts_a9_cap1[] = { + 0x0107, 0x0108, 0x0109, 0x010a, 0x010e, + 0x111, 0x112, 0x113, 0x114, 0x0131, 0x132, 0x133, 0x134 }; +static const u16 snd_djm_opts_a9_cap2[] = { + 0x0201, 0x0202, 0x0203, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020e }; +static const u16 snd_djm_opts_a9_cap3[] = { + 0x0301, 0x0302, 0x0303, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030e }; +static const u16 snd_djm_opts_a9_cap4[] = { + 0x0401, 0x0402, 0x0403, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040e }; +static const u16 snd_djm_opts_a9_cap5[] = { + 0x0501, 0x0502, 0x0503, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050a, 0x050e }; + +static const struct snd_djm_ctl snd_djm_ctls_a9[] = { + SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Master Input", a9_cap1, 3, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch1 Input", a9_cap2, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch2 Input", a9_cap3, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch3 Input", a9_cap4, 2, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch4 Input", a9_cap5, 2, SND_DJM_WINDEX_CAP) +}; + static const struct snd_djm_device snd_djm_devices[] = { [SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2), [SND_DJM_750_IDX] = SND_DJM_DEVICE(750), @@ -3802,6 +3858,7 @@ static const struct snd_djm_device snd_djm_devices[] = { [SND_DJM_900NXS2_IDX] = SND_DJM_DEVICE(900nxs2), [SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2), [SND_DJM_450_IDX] = SND_DJM_DEVICE(450), + [SND_DJM_A9_IDX] = SND_DJM_DEVICE(a9), }; @@ -4059,6 +4116,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) err = snd_bbfpro_controls_create(mixer); break; case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */ + case USB_ID(0x2a39, 0x3fa0): /* RME Digiface USB (alternate) */ err = snd_rme_digiface_controls_create(mixer); break; case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ @@ -4079,6 +4137,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX); break; + case USB_ID(0x2b73, 0x003c): /* Pioneer DJ / AlphaTheta DJM-A9 */ + err = snd_djm_controls_create(mixer, SND_DJM_A9_IDX); + break; } return err; diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c index 4cddf84db631c6..7f595c1752a5a1 100644 --- a/sound/usb/mixer_scarlett2.c +++ b/sound/usb/mixer_scarlett2.c @@ -11,7 +11,7 @@ * - Clarett 2Pre/4Pre/8Pre USB * - Clarett+ 2Pre/4Pre/8Pre * - * Copyright (c) 2018-2023 by Geoffrey D. Bennett + * Copyright (c) 2018-2024 by Geoffrey D. Bennett * Copyright (c) 2020-2021 by Vladimir Sadovnikov * Copyright (c) 2022 by Christian Colglazier * @@ -1079,6 +1079,9 @@ struct scarlett2_device_info { /* minimum firmware version required */ u16 min_firmware_version; + /* has a downloadable device map */ + u8 has_devmap; + /* support for main/alt speaker switching */ u8 has_speaker_switching; @@ -1253,7 +1256,7 @@ struct scarlett2_data { u8 phantom_switch[SCARLETT2_PHANTOM_SWITCH_MAX]; u8 phantom_persistence; u8 input_select_switch; - u8 input_link_switch[SCARLETT2_INPUT_GAIN_MAX / 2]; + u8 input_link_switch[SCARLETT2_INPUT_GAIN_MAX]; u8 gain[SCARLETT2_INPUT_GAIN_MAX]; u8 autogain_switch[SCARLETT2_INPUT_GAIN_MAX]; u8 autogain_status[SCARLETT2_INPUT_GAIN_MAX]; @@ -1284,7 +1287,7 @@ struct scarlett2_data { struct snd_kcontrol *input_mute_ctls[SCARLETT2_INPUT_MUTE_SWITCH_MAX]; struct snd_kcontrol *phantom_ctls[SCARLETT2_PHANTOM_SWITCH_MAX]; struct snd_kcontrol *input_select_ctl; - struct snd_kcontrol *input_link_ctls[SCARLETT2_INPUT_GAIN_MAX / 2]; + struct snd_kcontrol *input_link_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *input_gain_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *autogain_ctls[SCARLETT2_INPUT_GAIN_MAX]; struct snd_kcontrol *autogain_status_ctls[SCARLETT2_INPUT_GAIN_MAX]; @@ -1773,6 +1776,7 @@ static const struct scarlett2_device_info s18i20_gen3_info = { static const struct scarlett2_device_info vocaster_one_info = { .config_set = &scarlett2_config_set_vocaster, .min_firmware_version = 1769, + .has_devmap = 1, .phantom_count = 1, .inputs_per_phantom = 1, @@ -1815,6 +1819,7 @@ static const struct scarlett2_device_info vocaster_one_info = { static const struct scarlett2_device_info vocaster_two_info = { .config_set = &scarlett2_config_set_vocaster, .min_firmware_version = 1769, + .has_devmap = 1, .phantom_count = 2, .inputs_per_phantom = 1, @@ -1858,6 +1863,7 @@ static const struct scarlett2_device_info vocaster_two_info = { static const struct scarlett2_device_info solo_gen4_info = { .config_set = &scarlett2_config_set_gen4_solo, .min_firmware_version = 2115, + .has_devmap = 1, .level_input_count = 1, .air_input_count = 1, @@ -1912,6 +1918,7 @@ static const struct scarlett2_device_info solo_gen4_info = { static const struct scarlett2_device_info s2i2_gen4_info = { .config_set = &scarlett2_config_set_gen4_2i2, .min_firmware_version = 2115, + .has_devmap = 1, .level_input_count = 2, .air_input_count = 2, @@ -1966,6 +1973,7 @@ static const struct scarlett2_device_info s2i2_gen4_info = { static const struct scarlett2_device_info s4i4_gen4_info = { .config_set = &scarlett2_config_set_gen4_4i4, .min_firmware_version = 2089, + .has_devmap = 1, .level_input_count = 2, .air_input_count = 2, @@ -2264,6 +2272,8 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_USB_GET_DATA 0x00800000 #define SCARLETT2_USB_SET_DATA 0x00800001 #define SCARLETT2_USB_DATA_CMD 0x00800002 +#define SCARLETT2_USB_INFO_DEVMAP 0x0080000c +#define SCARLETT2_USB_GET_DEVMAP 0x0080000d #define SCARLETT2_USB_CONFIG_SAVE 6 @@ -2277,6 +2287,14 @@ static int scarlett2_get_port_start_num( #define SCARLETT2_SEGMENT_SETTINGS_NAME "App_Settings" #define SCARLETT2_SEGMENT_FIRMWARE_NAME "App_Upgrade" +/* Gen 4 device firmware provides access to a base64-encoded + * zlib-compressed JSON description of the device's capabilities and + * configuration. This device map is made available in + * /proc/asound/cardX/device-map.json.zz.b64 + */ +#define SCARLETT2_DEVMAP_BLOCK_SIZE 1024 +#define SCARLETT2_DEVMAP_FILENAME "device-map.json.zz.b64" + /* proprietary request/response format */ struct scarlett2_usb_packet { __le32 cmd; @@ -3409,7 +3427,7 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) private->num_autogain_status_texts - 1; - for (int i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) if (scarlett2_has_config_item(private, scarlett2_ag_target_configs[i])) { err = scarlett2_usb_get_config( @@ -3420,7 +3438,7 @@ static int scarlett2_update_autogain(struct usb_mixer_interface *mixer) } /* convert from negative dBFS as used by the device */ - for (int i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) + for (i = 0; i < SCARLETT2_AG_TARGET_COUNT; i++) private->ag_targets[i] = -ag_target_values[i]; return 0; @@ -3439,7 +3457,7 @@ static void scarlett2_autogain_update_access(struct usb_mixer_interface *mixer) scarlett2_set_ctl_access(private->input_select_ctl, val); if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) - for (i = 0; i < info->gain_input_count / 2; i++) + for (i = 0; i < info->gain_input_count; i++) scarlett2_set_ctl_access(private->input_link_ctls[i], val); for (i = 0; i < info->gain_input_count; i++) @@ -3480,7 +3498,7 @@ static void scarlett2_autogain_notify_access(struct usb_mixer_interface *mixer) &private->input_select_ctl->id); if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) - for (i = 0; i < info->gain_input_count / 2; i++) + for (i = 0; i < info->gain_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &private->input_link_ctls[i]->id); for (i = 0; i < info->gain_input_count; i++) @@ -3825,7 +3843,7 @@ static int scarlett2_update_input_select(struct usb_mixer_interface *mixer) { struct scarlett2_data *private = mixer->private_data; const struct scarlett2_device_info *info = private->info; - int link_count = info->gain_input_count / 2; + int link_count = info->gain_input_count; int err; private->input_select_updated = 0; @@ -3847,10 +3865,6 @@ static int scarlett2_update_input_select(struct usb_mixer_interface *mixer) if (err < 0) return err; - /* simplified because no model yet has link_count > 1 */ - if (private->input_link_switch[0]) - private->input_select_switch = 0; - return 0; } @@ -3887,9 +3901,9 @@ static int scarlett2_input_select_ctl_put( struct usb_mixer_elem_info *elem = kctl->private_data; struct usb_mixer_interface *mixer = elem->head.mixer; struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; int oval, val, err; - int max_val = private->input_link_switch[0] ? 0 : 1; mutex_lock(&private->data_mutex); @@ -3907,19 +3921,18 @@ static int scarlett2_input_select_ctl_put( if (val < 0) val = 0; - else if (val > max_val) - val = max_val; + else if (val >= info->gain_input_count) + val = info->gain_input_count - 1; if (oval == val) goto unlock; private->input_select_switch = val; - /* Send switch change to the device if inputs not linked */ - if (!private->input_link_switch[0]) - err = scarlett2_usb_set_config( - mixer, SCARLETT2_CONFIG_INPUT_SELECT_SWITCH, - 1, val); + /* Send new value to the device */ + err = scarlett2_usb_set_config( + mixer, SCARLETT2_CONFIG_INPUT_SELECT_SWITCH, + 0, val); if (err == 0) err = 1; @@ -3936,8 +3949,7 @@ static int scarlett2_input_select_ctl_info( struct scarlett2_data *private = mixer->private_data; int inputs = private->info->gain_input_count; - int i, j; - int err; + int i, err; char **values = kcalloc(inputs, sizeof(char *), GFP_KERNEL); if (!values) @@ -3954,21 +3966,11 @@ static int scarlett2_input_select_ctl_info( if (err < 0) goto unlock; - /* Loop through each input - * Linked inputs have one value for the pair - */ - for (i = 0, j = 0; i < inputs; i++) { - if (private->input_link_switch[i / 2]) { - values[j++] = kasprintf( - GFP_KERNEL, "Input %d-%d", i + 1, i + 2); - i++; - } else { - values[j++] = kasprintf( - GFP_KERNEL, "Input %d", i + 1); - } - } + /* Loop through each input */ + for (i = 0; i < inputs; i++) + values[i] = kasprintf(GFP_KERNEL, "Input %d", i + 1); - err = snd_ctl_enum_info(uinfo, 1, j, + err = snd_ctl_enum_info(uinfo, 1, i, (const char * const *)values); unlock: @@ -4077,18 +4079,8 @@ static int scarlett2_input_link_ctl_put( private->input_link_switch[index] = val; - /* Notify of change in input select options available */ - snd_ctl_notify(mixer->chip->card, - SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, - &private->input_select_ctl->id); - private->input_select_updated = 1; - - /* Send switch change to the device - * Link for channels 1-2 is at index 1 - * No device yet has more than 2 channels linked - */ err = scarlett2_usb_set_config( - mixer, SCARLETT2_CONFIG_INPUT_LINK_SWITCH, index + 1, val); + mixer, SCARLETT2_CONFIG_INPUT_LINK_SWITCH, index, val); if (err == 0) err = 1; @@ -5385,6 +5377,8 @@ static int scarlett2_compressor_ctl_put( int index = elem->control; int channel = index / SCARLETT2_COMPRESSOR_PARAM_COUNT; int param_index = index % SCARLETT2_COMPRESSOR_PARAM_COUNT; + const struct compressor_param *param = &compressor_params[param_index]; + int oval, val, err; s32 scaled_val; @@ -5406,8 +5400,6 @@ static int scarlett2_compressor_ctl_put( private->compressor_values[index] = val; - const struct compressor_param *param = &compressor_params[param_index]; - scaled_val = val << param->scale_bits; /* Send change to the device */ @@ -6916,10 +6908,9 @@ static int scarlett2_add_line_in_ctls(struct usb_mixer_interface *mixer) if (scarlett2_has_config_item(private, SCARLETT2_CONFIG_INPUT_LINK_SWITCH)) { - for (i = 0; i < info->gain_input_count / 2; i++) { + for (i = 0; i < info->gain_input_count; i++) { scnprintf(s, sizeof(s), - "Line In %d-%d Link Capture Switch", - (i * 2) + 1, (i * 2) + 2); + "Line In %d Link Capture Switch", i + 1); err = scarlett2_add_new_ctl( mixer, &scarlett2_input_link_ctl, i, 1, s, &private->input_link_ctls[i]); @@ -8246,7 +8237,7 @@ static void scarlett2_notify_input_select(struct usb_mixer_interface *mixer) SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &private->input_select_ctl->id); - for (i = 0; i < info->gain_input_count / 2; i++) + for (i = 0; i < info->gain_input_count; i++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &private->input_link_ctls[i]->id); } @@ -9518,7 +9509,7 @@ static long scarlett2_hwdep_write(struct snd_hwdep *hw, SCARLETT2_FLASH_BLOCK_SIZE; if (count < 0 || *offset < 0 || *offset + count >= flash_size) - return -EINVAL; + return -ENOSPC; if (!count) return 0; @@ -9591,6 +9582,116 @@ static int scarlett2_hwdep_init(struct usb_mixer_interface *mixer) return 0; } +/*** device-map file ***/ + +static ssize_t scarlett2_devmap_read( + struct snd_info_entry *entry, + void *file_private_data, + struct file *file, + char __user *buf, + size_t count, + loff_t pos) +{ + struct usb_mixer_interface *mixer = entry->private_data; + u8 *resp_buf; + const size_t block_size = SCARLETT2_DEVMAP_BLOCK_SIZE; + size_t copied = 0; + + if (pos >= entry->size) + return 0; + + if (pos + count > entry->size) + count = entry->size - pos; + + resp_buf = kmalloc(block_size, GFP_KERNEL); + if (!resp_buf) + return -ENOMEM; + + while (count > 0) { + /* SCARLETT2_USB_GET_DEVMAP reads only on block boundaries, + * so we need to read a whole block and copy the requested + * chunk to userspace. + */ + + __le32 req; + int err; + + /* offset within the block that we're reading */ + size_t offset = pos % block_size; + + /* read_size is block_size except for the last block */ + size_t block_start = pos - offset; + size_t read_size = min_t(size_t, + block_size, + entry->size - block_start); + + /* size of the chunk to copy to userspace */ + size_t copy_size = min_t(size_t, count, read_size - offset); + + /* request the block */ + req = cpu_to_le32(pos / block_size); + err = scarlett2_usb(mixer, SCARLETT2_USB_GET_DEVMAP, + &req, sizeof(req), resp_buf, read_size); + if (err < 0) { + kfree(resp_buf); + return copied ? copied : err; + } + + if (copy_to_user(buf, resp_buf + offset, copy_size)) { + kfree(resp_buf); + return -EFAULT; + } + + buf += copy_size; + pos += copy_size; + copied += copy_size; + count -= copy_size; + } + + kfree(resp_buf); + return copied; +} + +static const struct snd_info_entry_ops scarlett2_devmap_ops = { + .read = scarlett2_devmap_read, +}; + +static int scarlett2_devmap_init(struct usb_mixer_interface *mixer) +{ + struct snd_card *card = mixer->chip->card; + struct scarlett2_data *private = mixer->private_data; + const struct scarlett2_device_info *info = private->info; + __le16 config_len_buf[2]; + int config_len; + struct snd_info_entry *entry; + int err; + + /* If the device doesn't support the DEVMAP commands, don't + * create the /proc/asound/cardX/scarlett.json.zlib entry + */ + if (!info->has_devmap) + return 0; + + err = scarlett2_usb(mixer, SCARLETT2_USB_INFO_DEVMAP, + NULL, 0, &config_len_buf, sizeof(config_len_buf)); + if (err < 0) + return err; + + config_len = le16_to_cpu(config_len_buf[1]); + + err = snd_card_proc_new(card, SCARLETT2_DEVMAP_FILENAME, &entry); + if (err < 0) + return err; + + entry->content = SNDRV_INFO_CONTENT_DATA; + entry->private_data = mixer; + entry->c.ops = &scarlett2_devmap_ops; + entry->size = config_len; + entry->mode = S_IFREG | 0444; + + return 0; +} + int snd_scarlett2_init(struct usb_mixer_interface *mixer) { struct snd_usb_audio *chip = mixer->chip; @@ -9641,11 +9742,20 @@ int snd_scarlett2_init(struct usb_mixer_interface *mixer) } err = scarlett2_hwdep_init(mixer); - if (err < 0) + if (err < 0) { usb_audio_err(mixer->chip, "Error creating %s hwdep device: %d", entry->series_name, err); + return err; + } + + err = scarlett2_devmap_init(mixer); + if (err < 0) + usb_audio_err(mixer->chip, + "Error creating %s devmap entry: %d", + entry->series_name, + err); return err; } diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 199d0603cf8e59..8954be23325c50 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3131,6 +3131,63 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + /* + * Pioneer DJ / AlphaTheta DJM-A9 + * 10 channels playback & 12 channels capture @ 44.1/48/96kHz S24LE + */ + USB_DEVICE_VENDOR_SPEC(0x2b73, 0x003c), + QUIRK_DRIVER_INFO { + QUIRK_DATA_COMPOSITE { + { + QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 10, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x01, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { + 44100, 48000, 96000 + } + } + }, + { + QUIRK_DATA_AUDIOFORMAT(0) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 12, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x82, + .ep_idx = 1, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_IMPLICIT_FB, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { + 44100, 48000, 96000 + } + } + }, + QUIRK_COMPOSITE_END + } + } +}, + /* * MacroSilicon MS2100/MS2106 based AV capture cards * @@ -3616,176 +3673,181 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, -{ - /* Only claim interface 0 */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR | - USB_DEVICE_ID_MATCH_PRODUCT | - USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_NUMBER, - .idVendor = 0x2a39, - .idProduct = 0x3f8c, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceNumber = 0, - QUIRK_DRIVER_INFO { - QUIRK_DATA_COMPOSITE { +#define QUIRK_RME_DIGIFACE(pid) \ +{ \ + /* Only claim interface 0 */ \ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | \ + USB_DEVICE_ID_MATCH_PRODUCT | \ + USB_DEVICE_ID_MATCH_INT_CLASS | \ + USB_DEVICE_ID_MATCH_INT_NUMBER, \ + .idVendor = 0x2a39, \ + .idProduct = pid, \ + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \ + .bInterfaceNumber = 0, \ + QUIRK_DRIVER_INFO { \ + QUIRK_DATA_COMPOSITE { \ /* * Three modes depending on sample rate band, * with different channel counts for in/out - */ - { QUIRK_DATA_STANDARD_MIXER(0) }, - { - QUIRK_DATA_AUDIOFORMAT(0) { - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .channels = 34, // outputs - .fmt_bits = 24, - .iface = 0, - .altsetting = 1, - .altset_idx = 1, - .endpoint = 0x02, - .ep_idx = 1, - .ep_attr = USB_ENDPOINT_XFER_ISOC | - USB_ENDPOINT_SYNC_ASYNC, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000, - .rate_min = 32000, - .rate_max = 48000, - .nr_rates = 3, - .rate_table = (unsigned int[]) { - 32000, 44100, 48000, - }, - .sync_ep = 0x81, - .sync_iface = 0, - .sync_altsetting = 1, - .sync_ep_idx = 0, - .implicit_fb = 1, - }, - }, - { - QUIRK_DATA_AUDIOFORMAT(0) { - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .channels = 18, // outputs - .fmt_bits = 24, - .iface = 0, - .altsetting = 1, - .altset_idx = 1, - .endpoint = 0x02, - .ep_idx = 1, - .ep_attr = USB_ENDPOINT_XFER_ISOC | - USB_ENDPOINT_SYNC_ASYNC, - .rates = SNDRV_PCM_RATE_64000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000, - .rate_min = 64000, - .rate_max = 96000, - .nr_rates = 3, - .rate_table = (unsigned int[]) { - 64000, 88200, 96000, - }, - .sync_ep = 0x81, - .sync_iface = 0, - .sync_altsetting = 1, - .sync_ep_idx = 0, - .implicit_fb = 1, - }, - }, - { - QUIRK_DATA_AUDIOFORMAT(0) { - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .channels = 10, // outputs - .fmt_bits = 24, - .iface = 0, - .altsetting = 1, - .altset_idx = 1, - .endpoint = 0x02, - .ep_idx = 1, - .ep_attr = USB_ENDPOINT_XFER_ISOC | - USB_ENDPOINT_SYNC_ASYNC, - .rates = SNDRV_PCM_RATE_KNOT | - SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .rate_min = 128000, - .rate_max = 192000, - .nr_rates = 3, - .rate_table = (unsigned int[]) { - 128000, 176400, 192000, - }, - .sync_ep = 0x81, - .sync_iface = 0, - .sync_altsetting = 1, - .sync_ep_idx = 0, - .implicit_fb = 1, - }, - }, - { - QUIRK_DATA_AUDIOFORMAT(0) { - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .channels = 32, // inputs - .fmt_bits = 24, - .iface = 0, - .altsetting = 1, - .altset_idx = 1, - .endpoint = 0x81, - .ep_attr = USB_ENDPOINT_XFER_ISOC | - USB_ENDPOINT_SYNC_ASYNC, - .rates = SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000, - .rate_min = 32000, - .rate_max = 48000, - .nr_rates = 3, - .rate_table = (unsigned int[]) { - 32000, 44100, 48000, - } - } - }, - { - QUIRK_DATA_AUDIOFORMAT(0) { - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .channels = 16, // inputs - .fmt_bits = 24, - .iface = 0, - .altsetting = 1, - .altset_idx = 1, - .endpoint = 0x81, - .ep_attr = USB_ENDPOINT_XFER_ISOC | - USB_ENDPOINT_SYNC_ASYNC, - .rates = SNDRV_PCM_RATE_64000 | - SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000, - .rate_min = 64000, - .rate_max = 96000, - .nr_rates = 3, - .rate_table = (unsigned int[]) { - 64000, 88200, 96000, - } - } - }, - { - QUIRK_DATA_AUDIOFORMAT(0) { - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .channels = 8, // inputs - .fmt_bits = 24, - .iface = 0, - .altsetting = 1, - .altset_idx = 1, - .endpoint = 0x81, - .ep_attr = USB_ENDPOINT_XFER_ISOC | - USB_ENDPOINT_SYNC_ASYNC, - .rates = SNDRV_PCM_RATE_KNOT | - SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .rate_min = 128000, - .rate_max = 192000, - .nr_rates = 3, - .rate_table = (unsigned int[]) { - 128000, 176400, 192000, - } - } - }, - QUIRK_COMPOSITE_END - } - } -}, + */ \ + { QUIRK_DATA_STANDARD_MIXER(0) }, \ + { \ + QUIRK_DATA_AUDIOFORMAT(0) { \ + .formats = SNDRV_PCM_FMTBIT_S32_LE, \ + .channels = 34, /* outputs */ \ + .fmt_bits = 24, \ + .iface = 0, \ + .altsetting = 1, \ + .altset_idx = 1, \ + .endpoint = 0x02, \ + .ep_idx = 1, \ + .ep_attr = USB_ENDPOINT_XFER_ISOC | \ + USB_ENDPOINT_SYNC_ASYNC, \ + .rates = SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000, \ + .rate_min = 32000, \ + .rate_max = 48000, \ + .nr_rates = 3, \ + .rate_table = (unsigned int[]) { \ + 32000, 44100, 48000, \ + }, \ + .sync_ep = 0x81, \ + .sync_iface = 0, \ + .sync_altsetting = 1, \ + .sync_ep_idx = 0, \ + .implicit_fb = 1, \ + }, \ + }, \ + { \ + QUIRK_DATA_AUDIOFORMAT(0) { \ + .formats = SNDRV_PCM_FMTBIT_S32_LE, \ + .channels = 18, /* outputs */ \ + .fmt_bits = 24, \ + .iface = 0, \ + .altsetting = 1, \ + .altset_idx = 1, \ + .endpoint = 0x02, \ + .ep_idx = 1, \ + .ep_attr = USB_ENDPOINT_XFER_ISOC | \ + USB_ENDPOINT_SYNC_ASYNC, \ + .rates = SNDRV_PCM_RATE_64000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000, \ + .rate_min = 64000, \ + .rate_max = 96000, \ + .nr_rates = 3, \ + .rate_table = (unsigned int[]) { \ + 64000, 88200, 96000, \ + }, \ + .sync_ep = 0x81, \ + .sync_iface = 0, \ + .sync_altsetting = 1, \ + .sync_ep_idx = 0, \ + .implicit_fb = 1, \ + }, \ + }, \ + { \ + QUIRK_DATA_AUDIOFORMAT(0) { \ + .formats = SNDRV_PCM_FMTBIT_S32_LE, \ + .channels = 10, /* outputs */ \ + .fmt_bits = 24, \ + .iface = 0, \ + .altsetting = 1, \ + .altset_idx = 1, \ + .endpoint = 0x02, \ + .ep_idx = 1, \ + .ep_attr = USB_ENDPOINT_XFER_ISOC | \ + USB_ENDPOINT_SYNC_ASYNC, \ + .rates = SNDRV_PCM_RATE_KNOT | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000, \ + .rate_min = 128000, \ + .rate_max = 192000, \ + .nr_rates = 3, \ + .rate_table = (unsigned int[]) { \ + 128000, 176400, 192000, \ + }, \ + .sync_ep = 0x81, \ + .sync_iface = 0, \ + .sync_altsetting = 1, \ + .sync_ep_idx = 0, \ + .implicit_fb = 1, \ + }, \ + }, \ + { \ + QUIRK_DATA_AUDIOFORMAT(0) { \ + .formats = SNDRV_PCM_FMTBIT_S32_LE, \ + .channels = 32, /* inputs */ \ + .fmt_bits = 24, \ + .iface = 0, \ + .altsetting = 1, \ + .altset_idx = 1, \ + .endpoint = 0x81, \ + .ep_attr = USB_ENDPOINT_XFER_ISOC | \ + USB_ENDPOINT_SYNC_ASYNC, \ + .rates = SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000, \ + .rate_min = 32000, \ + .rate_max = 48000, \ + .nr_rates = 3, \ + .rate_table = (unsigned int[]) { \ + 32000, 44100, 48000, \ + } \ + } \ + }, \ + { \ + QUIRK_DATA_AUDIOFORMAT(0) { \ + .formats = SNDRV_PCM_FMTBIT_S32_LE, \ + .channels = 16, /* inputs */ \ + .fmt_bits = 24, \ + .iface = 0, \ + .altsetting = 1, \ + .altset_idx = 1, \ + .endpoint = 0x81, \ + .ep_attr = USB_ENDPOINT_XFER_ISOC | \ + USB_ENDPOINT_SYNC_ASYNC, \ + .rates = SNDRV_PCM_RATE_64000 | \ + SNDRV_PCM_RATE_88200 | \ + SNDRV_PCM_RATE_96000, \ + .rate_min = 64000, \ + .rate_max = 96000, \ + .nr_rates = 3, \ + .rate_table = (unsigned int[]) { \ + 64000, 88200, 96000, \ + } \ + } \ + }, \ + { \ + QUIRK_DATA_AUDIOFORMAT(0) { \ + .formats = SNDRV_PCM_FMTBIT_S32_LE, \ + .channels = 8, /* inputs */ \ + .fmt_bits = 24, \ + .iface = 0, \ + .altsetting = 1, \ + .altset_idx = 1, \ + .endpoint = 0x81, \ + .ep_attr = USB_ENDPOINT_XFER_ISOC | \ + USB_ENDPOINT_SYNC_ASYNC, \ + .rates = SNDRV_PCM_RATE_KNOT | \ + SNDRV_PCM_RATE_176400 | \ + SNDRV_PCM_RATE_192000, \ + .rate_min = 128000, \ + .rate_max = 192000, \ + .nr_rates = 3, \ + .rate_table = (unsigned int[]) { \ + 128000, 176400, 192000, \ + } \ + } \ + }, \ + QUIRK_COMPOSITE_END \ + } \ + } \ +} + +QUIRK_RME_DIGIFACE(0x3f8c), +QUIRK_RME_DIGIFACE(0x3fa0), + #undef USB_DEVICE_VENDOR_SPEC #undef USB_AUDIO_DEVICE diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index c5fd180357d1e8..8ba0aff8be2ec2 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -555,6 +555,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf) { struct usb_host_config *config = dev->actconfig; + struct usb_device_descriptor *new_device_descriptor __free(kfree) = NULL; int err; if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD || @@ -565,11 +566,19 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac 0x10, 0x43, 0x0001, 0x000a, NULL, 0); if (err < 0) dev_dbg(&dev->dev, "error sending boot message: %d\n", err); + + new_device_descriptor = kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); + if (!new_device_descriptor) + return -ENOMEM; err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, - &dev->descriptor, sizeof(dev->descriptor)); - config = dev->actconfig; + new_device_descriptor, sizeof(*new_device_descriptor)); if (err < 0) dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err); + if (new_device_descriptor->bNumConfigurations > dev->descriptor.bNumConfigurations) + dev_dbg(&dev->dev, "error too large bNumConfigurations: %d\n", + new_device_descriptor->bNumConfigurations); + else + memcpy(&dev->descriptor, new_device_descriptor, sizeof(dev->descriptor)); err = usb_reset_configuration(dev); if (err < 0) dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err); @@ -901,6 +910,7 @@ static void mbox2_setup_48_24_magic(struct usb_device *dev) static int snd_usb_mbox2_boot_quirk(struct usb_device *dev) { struct usb_host_config *config = dev->actconfig; + struct usb_device_descriptor *new_device_descriptor __free(kfree) = NULL; int err; u8 bootresponse[0x12]; int fwsize; @@ -935,11 +945,19 @@ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev) dev_dbg(&dev->dev, "device initialised!\n"); + new_device_descriptor = kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); + if (!new_device_descriptor) + return -ENOMEM; + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, - &dev->descriptor, sizeof(dev->descriptor)); - config = dev->actconfig; + new_device_descriptor, sizeof(*new_device_descriptor)); if (err < 0) dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err); + if (new_device_descriptor->bNumConfigurations > dev->descriptor.bNumConfigurations) + dev_dbg(&dev->dev, "error too large bNumConfigurations: %d\n", + new_device_descriptor->bNumConfigurations); + else + memcpy(&dev->descriptor, new_device_descriptor, sizeof(dev->descriptor)); err = usb_reset_configuration(dev); if (err < 0) @@ -1249,6 +1267,7 @@ static void mbox3_setup_defaults(struct usb_device *dev) static int snd_usb_mbox3_boot_quirk(struct usb_device *dev) { struct usb_host_config *config = dev->actconfig; + struct usb_device_descriptor *new_device_descriptor __free(kfree) = NULL; int err; int descriptor_size; @@ -1261,11 +1280,19 @@ static int snd_usb_mbox3_boot_quirk(struct usb_device *dev) dev_dbg(&dev->dev, "MBOX3: device initialised!\n"); + new_device_descriptor = kmalloc(sizeof(*new_device_descriptor), GFP_KERNEL); + if (!new_device_descriptor) + return -ENOMEM; + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, - &dev->descriptor, sizeof(dev->descriptor)); - config = dev->actconfig; + new_device_descriptor, sizeof(*new_device_descriptor)); if (err < 0) dev_dbg(&dev->dev, "MBOX3: error usb_get_descriptor: %d\n", err); + if (new_device_descriptor->bNumConfigurations > dev->descriptor.bNumConfigurations) + dev_dbg(&dev->dev, "MBOX3: error too large bNumConfigurations: %d\n", + new_device_descriptor->bNumConfigurations); + else + memcpy(&dev->descriptor, new_device_descriptor, sizeof(dev->descriptor)); err = usb_reset_configuration(dev); if (err < 0) @@ -1638,6 +1665,7 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, return snd_usb_motu_microbookii_boot_quirk(dev); break; case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */ + case USB_ID(0x2a39, 0x3fa0): /* RME Digiface USB (alternate) */ return snd_usb_rme_digiface_boot_quirk(dev); } @@ -1851,6 +1879,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, mbox3_set_format_quirk(subs, fmt); /* Digidesign Mbox 3 */ break; case USB_ID(0x2a39, 0x3f8c): /* RME Digiface USB */ + case USB_ID(0x2a39, 0x3fa0): /* RME Digiface USB (alternate) */ rme_digiface_set_format_quirk(subs); break; } @@ -2115,7 +2144,7 @@ struct usb_audio_quirk_flags_table { static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { /* Device matches */ DEVICE_FLG(0x03f0, 0x654a, /* HP 320 FHD Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE), + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x041e, 0x3000, /* Creative SB Extigy */ QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x041e, 0x4080, /* Creative Live Cam VF0610 */ @@ -2123,12 +2152,35 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x045e, 0x083c, /* MS USB Link headset */ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY | QUIRK_FLAG_DISABLE_AUTOSUSPEND), + DEVICE_FLG(0x046d, 0x0807, /* Logitech Webcam C500 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0808, /* Logitech Webcam C600 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0809, + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0819, /* Logitech Webcam C210 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x081b, /* HD Webcam c310 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x081d, /* HD Webcam c510 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0825, /* HD Webcam c270 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x0826, /* HD Webcam c525 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), DEVICE_FLG(0x046d, 0x084c, /* Logitech ConferenceCam Connect */ QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_CTL_MSG_DELAY_1M), + DEVICE_FLG(0x046d, 0x08ca, /* Logitech Quickcam Fusion */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), DEVICE_FLG(0x046d, 0x0991, /* Logitech QuickCam Pro */ - QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR), + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR | + QUIRK_FLAG_MIC_RES_384), + DEVICE_FLG(0x046d, 0x09a2, /* QuickCam Communicate Deluxe/S7500 */ + QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIC_RES_384), DEVICE_FLG(0x046d, 0x09a4, /* Logitech QuickCam E 3500 */ QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_IGNORE_CTL_ERROR), + DEVICE_FLG(0x0499, 0x1506, /* Yamaha THR5 */ + QUIRK_FLAG_GENERIC_IMPLICIT_FB), DEVICE_FLG(0x0499, 0x1509, /* Steinberg UR22 */ QUIRK_FLAG_GENERIC_IMPLICIT_FB), DEVICE_FLG(0x0499, 0x3108, /* Yamaha YIT-W12TX */ @@ -2194,7 +2246,7 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x0fd9, 0x0008, /* Hauppauge HVR-950Q */ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */ - QUIRK_FLAG_GET_SAMPLE_RATE), + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1397, 0x0507, /* Behringer UMC202HD */ @@ -2232,9 +2284,9 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { DEVICE_FLG(0x19f7, 0x0035, /* RODE NT-USB+ */ QUIRK_FLAG_GET_SAMPLE_RATE), DEVICE_FLG(0x1bcf, 0x2281, /* HD Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE), + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */ - QUIRK_FLAG_GET_SAMPLE_RATE), + QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16), DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */ QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER), DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */ @@ -2273,6 +2325,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_DSD_RAW), DEVICE_FLG(0x2522, 0x0007, /* LH Labs Geek Out HD Audio 1V5 */ QUIRK_FLAG_SET_IFACE_FIRST), + DEVICE_FLG(0x262a, 0x9302, /* ddHiFi TC44C */ + QUIRK_FLAG_DSD_RAW), DEVICE_FLG(0x2708, 0x0002, /* Audient iD14 */ QUIRK_FLAG_IGNORE_CTL_ERROR), DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b0f042c996087e..158ec053dc44dd 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -194,6 +194,8 @@ extern bool snd_usb_skip_validation; * QUIRK_FLAG_FIXED_RATE * Do not set PCM rate (frequency) when only one rate is available * for the given endpoint. + * QUIRK_FLAG_MIC_RES_16 and QUIRK_FLAG_MIC_RES_384 + * Set the fixed resolution for Mic Capture Volume (mostly for webcams) */ #define QUIRK_FLAG_GET_SAMPLE_RATE (1U << 0) @@ -218,5 +220,7 @@ extern bool snd_usb_skip_validation; #define QUIRK_FLAG_IFACE_SKIP_CLOSE (1U << 19) #define QUIRK_FLAG_FORCE_IFACE_RESET (1U << 20) #define QUIRK_FLAG_FIXED_RATE (1U << 21) +#define QUIRK_FLAG_MIC_RES_16 (1U << 22) +#define QUIRK_FLAG_MIC_RES_384 (1U << 23) #endif /* __USBAUDIO_H */ diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 1be0e980feb958..6bcf8b859ebb20 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -89,13 +89,6 @@ static void pt_info_set(struct usb_device *dev, u8 v) v, 0, NULL, 0, 1000, GFP_NOIO); } -static void usb_stream_hwdep_vm_open(struct vm_area_struct *area) -{ - struct us122l *us122l = area->vm_private_data; - - atomic_inc(&us122l->mmap_count); -} - static vm_fault_t usb_stream_hwdep_vm_fault(struct vm_fault *vmf) { unsigned long offset; @@ -132,17 +125,9 @@ static vm_fault_t usb_stream_hwdep_vm_fault(struct vm_fault *vmf) return VM_FAULT_SIGBUS; } -static void usb_stream_hwdep_vm_close(struct vm_area_struct *area) -{ - struct us122l *us122l = area->vm_private_data; - - atomic_dec(&us122l->mmap_count); -} static const struct vm_operations_struct usb_stream_hwdep_vm_ops = { - .open = usb_stream_hwdep_vm_open, .fault = usb_stream_hwdep_vm_fault, - .close = usb_stream_hwdep_vm_close, }; static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) @@ -218,7 +203,6 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw, if (!read) vm_flags_set(area, VM_DONTEXPAND); area->vm_private_data = us122l; - atomic_inc(&us122l->mmap_count); out: mutex_unlock(&us122l->mutex); return err; @@ -606,10 +590,7 @@ static void snd_us122l_disconnect(struct usb_interface *intf) usb_put_intf(usb_ifnum_to_if(us122l->dev, 1)); usb_put_dev(us122l->dev); - while (atomic_read(&us122l->mmap_count)) - msleep(500); - - snd_card_free(card); + snd_card_free_when_closed(card); } static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message) diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index c32ae5e981e909..8e59b78d35142d 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -16,8 +16,6 @@ struct us122l { struct file *slave; struct list_head midi_list; - atomic_t mmap_count; - bool is_us144; }; diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 2f9cede242b3a9..5f81c68fd42b68 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -422,7 +422,7 @@ static void snd_usx2y_disconnect(struct usb_interface *intf) } if (usx2y->us428ctls_sharedmem) wake_up(&usx2y->us428ctls_wait_queue_head); - snd_card_free(card); + snd_card_free_when_closed(card); } static int snd_usx2y_probe(struct usb_interface *intf, diff --git a/tools/arch/arm64/include/asm/brk-imm.h b/tools/arch/arm64/include/asm/brk-imm.h new file mode 100644 index 00000000000000..beb42c62b6acc5 --- /dev/null +++ b/tools/arch/arm64/include/asm/brk-imm.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2012 ARM Ltd. + */ + +#ifndef __ASM_BRK_IMM_H +#define __ASM_BRK_IMM_H + +/* + * #imm16 values used for BRK instruction generation + * 0x004: for installing kprobes + * 0x005: for installing uprobes + * 0x006: for kprobe software single-step + * 0x007: for kretprobe return + * Allowed values for kgdb are 0x400 - 0x7ff + * 0x100: for triggering a fault on purpose (reserved) + * 0x400: for dynamic BRK instruction + * 0x401: for compile time BRK instruction + * 0x800: kernel-mode BUG() and WARN() traps + * 0x9xx: tag-based KASAN trap (allowed values 0x900 - 0x9ff) + * 0x55xx: Undefined Behavior Sanitizer traps ('U' << 8) + * 0x8xxx: Control-Flow Integrity traps + */ +#define KPROBES_BRK_IMM 0x004 +#define UPROBES_BRK_IMM 0x005 +#define KPROBES_BRK_SS_IMM 0x006 +#define KRETPROBES_BRK_IMM 0x007 +#define FAULT_BRK_IMM 0x100 +#define KGDB_DYN_DBG_BRK_IMM 0x400 +#define KGDB_COMPILED_DBG_BRK_IMM 0x401 +#define BUG_BRK_IMM 0x800 +#define KASAN_BRK_IMM 0x900 +#define KASAN_BRK_MASK 0x0ff +#define UBSAN_BRK_IMM 0x5500 +#define UBSAN_BRK_MASK 0x00ff + +#define CFI_BRK_IMM_TARGET GENMASK(4, 0) +#define CFI_BRK_IMM_TYPE GENMASK(9, 5) +#define CFI_BRK_IMM_BASE 0x8000 +#define CFI_BRK_IMM_MASK (CFI_BRK_IMM_TARGET | CFI_BRK_IMM_TYPE) + +#endif diff --git a/tools/arch/arm64/include/asm/esr.h b/tools/arch/arm64/include/asm/esr.h new file mode 100644 index 00000000000000..bd592ca815711c --- /dev/null +++ b/tools/arch/arm64/include/asm/esr.h @@ -0,0 +1,455 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2013 - ARM Ltd + * Author: Marc Zyngier + */ + +#ifndef __ASM_ESR_H +#define __ASM_ESR_H + +#include + +#define ESR_ELx_EC_UNKNOWN UL(0x00) +#define ESR_ELx_EC_WFx UL(0x01) +/* Unallocated EC: 0x02 */ +#define ESR_ELx_EC_CP15_32 UL(0x03) +#define ESR_ELx_EC_CP15_64 UL(0x04) +#define ESR_ELx_EC_CP14_MR UL(0x05) +#define ESR_ELx_EC_CP14_LS UL(0x06) +#define ESR_ELx_EC_FP_ASIMD UL(0x07) +#define ESR_ELx_EC_CP10_ID UL(0x08) /* EL2 only */ +#define ESR_ELx_EC_PAC UL(0x09) /* EL2 and above */ +/* Unallocated EC: 0x0A - 0x0B */ +#define ESR_ELx_EC_CP14_64 UL(0x0C) +#define ESR_ELx_EC_BTI UL(0x0D) +#define ESR_ELx_EC_ILL UL(0x0E) +/* Unallocated EC: 0x0F - 0x10 */ +#define ESR_ELx_EC_SVC32 UL(0x11) +#define ESR_ELx_EC_HVC32 UL(0x12) /* EL2 only */ +#define ESR_ELx_EC_SMC32 UL(0x13) /* EL2 and above */ +/* Unallocated EC: 0x14 */ +#define ESR_ELx_EC_SVC64 UL(0x15) +#define ESR_ELx_EC_HVC64 UL(0x16) /* EL2 and above */ +#define ESR_ELx_EC_SMC64 UL(0x17) /* EL2 and above */ +#define ESR_ELx_EC_SYS64 UL(0x18) +#define ESR_ELx_EC_SVE UL(0x19) +#define ESR_ELx_EC_ERET UL(0x1a) /* EL2 only */ +/* Unallocated EC: 0x1B */ +#define ESR_ELx_EC_FPAC UL(0x1C) /* EL1 and above */ +#define ESR_ELx_EC_SME UL(0x1D) +/* Unallocated EC: 0x1E */ +#define ESR_ELx_EC_IMP_DEF UL(0x1f) /* EL3 only */ +#define ESR_ELx_EC_IABT_LOW UL(0x20) +#define ESR_ELx_EC_IABT_CUR UL(0x21) +#define ESR_ELx_EC_PC_ALIGN UL(0x22) +/* Unallocated EC: 0x23 */ +#define ESR_ELx_EC_DABT_LOW UL(0x24) +#define ESR_ELx_EC_DABT_CUR UL(0x25) +#define ESR_ELx_EC_SP_ALIGN UL(0x26) +#define ESR_ELx_EC_MOPS UL(0x27) +#define ESR_ELx_EC_FP_EXC32 UL(0x28) +/* Unallocated EC: 0x29 - 0x2B */ +#define ESR_ELx_EC_FP_EXC64 UL(0x2C) +/* Unallocated EC: 0x2D - 0x2E */ +#define ESR_ELx_EC_SERROR UL(0x2F) +#define ESR_ELx_EC_BREAKPT_LOW UL(0x30) +#define ESR_ELx_EC_BREAKPT_CUR UL(0x31) +#define ESR_ELx_EC_SOFTSTP_LOW UL(0x32) +#define ESR_ELx_EC_SOFTSTP_CUR UL(0x33) +#define ESR_ELx_EC_WATCHPT_LOW UL(0x34) +#define ESR_ELx_EC_WATCHPT_CUR UL(0x35) +/* Unallocated EC: 0x36 - 0x37 */ +#define ESR_ELx_EC_BKPT32 UL(0x38) +/* Unallocated EC: 0x39 */ +#define ESR_ELx_EC_VECTOR32 UL(0x3A) /* EL2 only */ +/* Unallocated EC: 0x3B */ +#define ESR_ELx_EC_BRK64 UL(0x3C) +/* Unallocated EC: 0x3D - 0x3F */ +#define ESR_ELx_EC_MAX UL(0x3F) + +#define ESR_ELx_EC_SHIFT (26) +#define ESR_ELx_EC_WIDTH (6) +#define ESR_ELx_EC_MASK (UL(0x3F) << ESR_ELx_EC_SHIFT) +#define ESR_ELx_EC(esr) (((esr) & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT) + +#define ESR_ELx_IL_SHIFT (25) +#define ESR_ELx_IL (UL(1) << ESR_ELx_IL_SHIFT) +#define ESR_ELx_ISS_MASK (GENMASK(24, 0)) +#define ESR_ELx_ISS(esr) ((esr) & ESR_ELx_ISS_MASK) +#define ESR_ELx_ISS2_SHIFT (32) +#define ESR_ELx_ISS2_MASK (GENMASK_ULL(55, 32)) +#define ESR_ELx_ISS2(esr) (((esr) & ESR_ELx_ISS2_MASK) >> ESR_ELx_ISS2_SHIFT) + +/* ISS field definitions shared by different classes */ +#define ESR_ELx_WNR_SHIFT (6) +#define ESR_ELx_WNR (UL(1) << ESR_ELx_WNR_SHIFT) + +/* Asynchronous Error Type */ +#define ESR_ELx_IDS_SHIFT (24) +#define ESR_ELx_IDS (UL(1) << ESR_ELx_IDS_SHIFT) +#define ESR_ELx_AET_SHIFT (10) +#define ESR_ELx_AET (UL(0x7) << ESR_ELx_AET_SHIFT) + +#define ESR_ELx_AET_UC (UL(0) << ESR_ELx_AET_SHIFT) +#define ESR_ELx_AET_UEU (UL(1) << ESR_ELx_AET_SHIFT) +#define ESR_ELx_AET_UEO (UL(2) << ESR_ELx_AET_SHIFT) +#define ESR_ELx_AET_UER (UL(3) << ESR_ELx_AET_SHIFT) +#define ESR_ELx_AET_CE (UL(6) << ESR_ELx_AET_SHIFT) + +/* Shared ISS field definitions for Data/Instruction aborts */ +#define ESR_ELx_SET_SHIFT (11) +#define ESR_ELx_SET_MASK (UL(3) << ESR_ELx_SET_SHIFT) +#define ESR_ELx_FnV_SHIFT (10) +#define ESR_ELx_FnV (UL(1) << ESR_ELx_FnV_SHIFT) +#define ESR_ELx_EA_SHIFT (9) +#define ESR_ELx_EA (UL(1) << ESR_ELx_EA_SHIFT) +#define ESR_ELx_S1PTW_SHIFT (7) +#define ESR_ELx_S1PTW (UL(1) << ESR_ELx_S1PTW_SHIFT) + +/* Shared ISS fault status code(IFSC/DFSC) for Data/Instruction aborts */ +#define ESR_ELx_FSC (0x3F) +#define ESR_ELx_FSC_TYPE (0x3C) +#define ESR_ELx_FSC_LEVEL (0x03) +#define ESR_ELx_FSC_EXTABT (0x10) +#define ESR_ELx_FSC_MTE (0x11) +#define ESR_ELx_FSC_SERROR (0x11) +#define ESR_ELx_FSC_ACCESS (0x08) +#define ESR_ELx_FSC_FAULT (0x04) +#define ESR_ELx_FSC_PERM (0x0C) +#define ESR_ELx_FSC_SEA_TTW(n) (0x14 + (n)) +#define ESR_ELx_FSC_SECC (0x18) +#define ESR_ELx_FSC_SECC_TTW(n) (0x1c + (n)) + +/* Status codes for individual page table levels */ +#define ESR_ELx_FSC_ACCESS_L(n) (ESR_ELx_FSC_ACCESS + (n)) +#define ESR_ELx_FSC_PERM_L(n) (ESR_ELx_FSC_PERM + (n)) + +#define ESR_ELx_FSC_FAULT_nL (0x2C) +#define ESR_ELx_FSC_FAULT_L(n) (((n) < 0 ? ESR_ELx_FSC_FAULT_nL : \ + ESR_ELx_FSC_FAULT) + (n)) + +/* ISS field definitions for Data Aborts */ +#define ESR_ELx_ISV_SHIFT (24) +#define ESR_ELx_ISV (UL(1) << ESR_ELx_ISV_SHIFT) +#define ESR_ELx_SAS_SHIFT (22) +#define ESR_ELx_SAS (UL(3) << ESR_ELx_SAS_SHIFT) +#define ESR_ELx_SSE_SHIFT (21) +#define ESR_ELx_SSE (UL(1) << ESR_ELx_SSE_SHIFT) +#define ESR_ELx_SRT_SHIFT (16) +#define ESR_ELx_SRT_MASK (UL(0x1F) << ESR_ELx_SRT_SHIFT) +#define ESR_ELx_SF_SHIFT (15) +#define ESR_ELx_SF (UL(1) << ESR_ELx_SF_SHIFT) +#define ESR_ELx_AR_SHIFT (14) +#define ESR_ELx_AR (UL(1) << ESR_ELx_AR_SHIFT) +#define ESR_ELx_CM_SHIFT (8) +#define ESR_ELx_CM (UL(1) << ESR_ELx_CM_SHIFT) + +/* ISS2 field definitions for Data Aborts */ +#define ESR_ELx_TnD_SHIFT (10) +#define ESR_ELx_TnD (UL(1) << ESR_ELx_TnD_SHIFT) +#define ESR_ELx_TagAccess_SHIFT (9) +#define ESR_ELx_TagAccess (UL(1) << ESR_ELx_TagAccess_SHIFT) +#define ESR_ELx_GCS_SHIFT (8) +#define ESR_ELx_GCS (UL(1) << ESR_ELx_GCS_SHIFT) +#define ESR_ELx_Overlay_SHIFT (6) +#define ESR_ELx_Overlay (UL(1) << ESR_ELx_Overlay_SHIFT) +#define ESR_ELx_DirtyBit_SHIFT (5) +#define ESR_ELx_DirtyBit (UL(1) << ESR_ELx_DirtyBit_SHIFT) +#define ESR_ELx_Xs_SHIFT (0) +#define ESR_ELx_Xs_MASK (GENMASK_ULL(4, 0)) + +/* ISS field definitions for exceptions taken in to Hyp */ +#define ESR_ELx_FSC_ADDRSZ (0x00) +#define ESR_ELx_FSC_ADDRSZ_L(n) (ESR_ELx_FSC_ADDRSZ + (n)) +#define ESR_ELx_CV (UL(1) << 24) +#define ESR_ELx_COND_SHIFT (20) +#define ESR_ELx_COND_MASK (UL(0xF) << ESR_ELx_COND_SHIFT) +#define ESR_ELx_WFx_ISS_RN (UL(0x1F) << 5) +#define ESR_ELx_WFx_ISS_RV (UL(1) << 2) +#define ESR_ELx_WFx_ISS_TI (UL(3) << 0) +#define ESR_ELx_WFx_ISS_WFxT (UL(2) << 0) +#define ESR_ELx_WFx_ISS_WFI (UL(0) << 0) +#define ESR_ELx_WFx_ISS_WFE (UL(1) << 0) +#define ESR_ELx_xVC_IMM_MASK ((UL(1) << 16) - 1) + +#define DISR_EL1_IDS (UL(1) << 24) +/* + * DISR_EL1 and ESR_ELx share the bottom 13 bits, but the RES0 bits may mean + * different things in the future... + */ +#define DISR_EL1_ESR_MASK (ESR_ELx_AET | ESR_ELx_EA | ESR_ELx_FSC) + +/* ESR value templates for specific events */ +#define ESR_ELx_WFx_MASK (ESR_ELx_EC_MASK | \ + (ESR_ELx_WFx_ISS_TI & ~ESR_ELx_WFx_ISS_WFxT)) +#define ESR_ELx_WFx_WFI_VAL ((ESR_ELx_EC_WFx << ESR_ELx_EC_SHIFT) | \ + ESR_ELx_WFx_ISS_WFI) + +/* BRK instruction trap from AArch64 state */ +#define ESR_ELx_BRK64_ISS_COMMENT_MASK 0xffff + +/* ISS field definitions for System instruction traps */ +#define ESR_ELx_SYS64_ISS_RES0_SHIFT 22 +#define ESR_ELx_SYS64_ISS_RES0_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_RES0_SHIFT) +#define ESR_ELx_SYS64_ISS_DIR_MASK 0x1 +#define ESR_ELx_SYS64_ISS_DIR_READ 0x1 +#define ESR_ELx_SYS64_ISS_DIR_WRITE 0x0 + +#define ESR_ELx_SYS64_ISS_RT_SHIFT 5 +#define ESR_ELx_SYS64_ISS_RT_MASK (UL(0x1f) << ESR_ELx_SYS64_ISS_RT_SHIFT) +#define ESR_ELx_SYS64_ISS_CRM_SHIFT 1 +#define ESR_ELx_SYS64_ISS_CRM_MASK (UL(0xf) << ESR_ELx_SYS64_ISS_CRM_SHIFT) +#define ESR_ELx_SYS64_ISS_CRN_SHIFT 10 +#define ESR_ELx_SYS64_ISS_CRN_MASK (UL(0xf) << ESR_ELx_SYS64_ISS_CRN_SHIFT) +#define ESR_ELx_SYS64_ISS_OP1_SHIFT 14 +#define ESR_ELx_SYS64_ISS_OP1_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_OP1_SHIFT) +#define ESR_ELx_SYS64_ISS_OP2_SHIFT 17 +#define ESR_ELx_SYS64_ISS_OP2_MASK (UL(0x7) << ESR_ELx_SYS64_ISS_OP2_SHIFT) +#define ESR_ELx_SYS64_ISS_OP0_SHIFT 20 +#define ESR_ELx_SYS64_ISS_OP0_MASK (UL(0x3) << ESR_ELx_SYS64_ISS_OP0_SHIFT) +#define ESR_ELx_SYS64_ISS_SYS_MASK (ESR_ELx_SYS64_ISS_OP0_MASK | \ + ESR_ELx_SYS64_ISS_OP1_MASK | \ + ESR_ELx_SYS64_ISS_OP2_MASK | \ + ESR_ELx_SYS64_ISS_CRN_MASK | \ + ESR_ELx_SYS64_ISS_CRM_MASK) +#define ESR_ELx_SYS64_ISS_SYS_VAL(op0, op1, op2, crn, crm) \ + (((op0) << ESR_ELx_SYS64_ISS_OP0_SHIFT) | \ + ((op1) << ESR_ELx_SYS64_ISS_OP1_SHIFT) | \ + ((op2) << ESR_ELx_SYS64_ISS_OP2_SHIFT) | \ + ((crn) << ESR_ELx_SYS64_ISS_CRN_SHIFT) | \ + ((crm) << ESR_ELx_SYS64_ISS_CRM_SHIFT)) + +#define ESR_ELx_SYS64_ISS_SYS_OP_MASK (ESR_ELx_SYS64_ISS_SYS_MASK | \ + ESR_ELx_SYS64_ISS_DIR_MASK) +#define ESR_ELx_SYS64_ISS_RT(esr) \ + (((esr) & ESR_ELx_SYS64_ISS_RT_MASK) >> ESR_ELx_SYS64_ISS_RT_SHIFT) +/* + * User space cache operations have the following sysreg encoding + * in System instructions. + * op0=1, op1=3, op2=1, crn=7, crm={ 5, 10, 11, 12, 13, 14 }, WRITE (L=0) + */ +#define ESR_ELx_SYS64_ISS_CRM_DC_CIVAC 14 +#define ESR_ELx_SYS64_ISS_CRM_DC_CVADP 13 +#define ESR_ELx_SYS64_ISS_CRM_DC_CVAP 12 +#define ESR_ELx_SYS64_ISS_CRM_DC_CVAU 11 +#define ESR_ELx_SYS64_ISS_CRM_DC_CVAC 10 +#define ESR_ELx_SYS64_ISS_CRM_IC_IVAU 5 + +#define ESR_ELx_SYS64_ISS_EL0_CACHE_OP_MASK (ESR_ELx_SYS64_ISS_OP0_MASK | \ + ESR_ELx_SYS64_ISS_OP1_MASK | \ + ESR_ELx_SYS64_ISS_OP2_MASK | \ + ESR_ELx_SYS64_ISS_CRN_MASK | \ + ESR_ELx_SYS64_ISS_DIR_MASK) +#define ESR_ELx_SYS64_ISS_EL0_CACHE_OP_VAL \ + (ESR_ELx_SYS64_ISS_SYS_VAL(1, 3, 1, 7, 0) | \ + ESR_ELx_SYS64_ISS_DIR_WRITE) +/* + * User space MRS operations which are supported for emulation + * have the following sysreg encoding in System instructions. + * op0 = 3, op1= 0, crn = 0, {crm = 0, 4-7}, READ (L = 1) + */ +#define ESR_ELx_SYS64_ISS_SYS_MRS_OP_MASK (ESR_ELx_SYS64_ISS_OP0_MASK | \ + ESR_ELx_SYS64_ISS_OP1_MASK | \ + ESR_ELx_SYS64_ISS_CRN_MASK | \ + ESR_ELx_SYS64_ISS_DIR_MASK) +#define ESR_ELx_SYS64_ISS_SYS_MRS_OP_VAL \ + (ESR_ELx_SYS64_ISS_SYS_VAL(3, 0, 0, 0, 0) | \ + ESR_ELx_SYS64_ISS_DIR_READ) + +#define ESR_ELx_SYS64_ISS_SYS_CTR ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 1, 0, 0) +#define ESR_ELx_SYS64_ISS_SYS_CTR_READ (ESR_ELx_SYS64_ISS_SYS_CTR | \ + ESR_ELx_SYS64_ISS_DIR_READ) + +#define ESR_ELx_SYS64_ISS_SYS_CNTVCT (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 2, 14, 0) | \ + ESR_ELx_SYS64_ISS_DIR_READ) + +#define ESR_ELx_SYS64_ISS_SYS_CNTVCTSS (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 6, 14, 0) | \ + ESR_ELx_SYS64_ISS_DIR_READ) + +#define ESR_ELx_SYS64_ISS_SYS_CNTFRQ (ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \ + ESR_ELx_SYS64_ISS_DIR_READ) + +#define esr_sys64_to_sysreg(e) \ + sys_reg((((e) & ESR_ELx_SYS64_ISS_OP0_MASK) >> \ + ESR_ELx_SYS64_ISS_OP0_SHIFT), \ + (((e) & ESR_ELx_SYS64_ISS_OP1_MASK) >> \ + ESR_ELx_SYS64_ISS_OP1_SHIFT), \ + (((e) & ESR_ELx_SYS64_ISS_CRN_MASK) >> \ + ESR_ELx_SYS64_ISS_CRN_SHIFT), \ + (((e) & ESR_ELx_SYS64_ISS_CRM_MASK) >> \ + ESR_ELx_SYS64_ISS_CRM_SHIFT), \ + (((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >> \ + ESR_ELx_SYS64_ISS_OP2_SHIFT)) + +#define esr_cp15_to_sysreg(e) \ + sys_reg(3, \ + (((e) & ESR_ELx_SYS64_ISS_OP1_MASK) >> \ + ESR_ELx_SYS64_ISS_OP1_SHIFT), \ + (((e) & ESR_ELx_SYS64_ISS_CRN_MASK) >> \ + ESR_ELx_SYS64_ISS_CRN_SHIFT), \ + (((e) & ESR_ELx_SYS64_ISS_CRM_MASK) >> \ + ESR_ELx_SYS64_ISS_CRM_SHIFT), \ + (((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >> \ + ESR_ELx_SYS64_ISS_OP2_SHIFT)) + +/* ISS field definitions for ERET/ERETAA/ERETAB trapping */ +#define ESR_ELx_ERET_ISS_ERET 0x2 +#define ESR_ELx_ERET_ISS_ERETA 0x1 + +/* + * ISS field definitions for floating-point exception traps + * (FP_EXC_32/FP_EXC_64). + * + * (The FPEXC_* constants are used instead for common bits.) + */ + +#define ESR_ELx_FP_EXC_TFV (UL(1) << 23) + +/* + * ISS field definitions for CP15 accesses + */ +#define ESR_ELx_CP15_32_ISS_DIR_MASK 0x1 +#define ESR_ELx_CP15_32_ISS_DIR_READ 0x1 +#define ESR_ELx_CP15_32_ISS_DIR_WRITE 0x0 + +#define ESR_ELx_CP15_32_ISS_RT_SHIFT 5 +#define ESR_ELx_CP15_32_ISS_RT_MASK (UL(0x1f) << ESR_ELx_CP15_32_ISS_RT_SHIFT) +#define ESR_ELx_CP15_32_ISS_CRM_SHIFT 1 +#define ESR_ELx_CP15_32_ISS_CRM_MASK (UL(0xf) << ESR_ELx_CP15_32_ISS_CRM_SHIFT) +#define ESR_ELx_CP15_32_ISS_CRN_SHIFT 10 +#define ESR_ELx_CP15_32_ISS_CRN_MASK (UL(0xf) << ESR_ELx_CP15_32_ISS_CRN_SHIFT) +#define ESR_ELx_CP15_32_ISS_OP1_SHIFT 14 +#define ESR_ELx_CP15_32_ISS_OP1_MASK (UL(0x7) << ESR_ELx_CP15_32_ISS_OP1_SHIFT) +#define ESR_ELx_CP15_32_ISS_OP2_SHIFT 17 +#define ESR_ELx_CP15_32_ISS_OP2_MASK (UL(0x7) << ESR_ELx_CP15_32_ISS_OP2_SHIFT) + +#define ESR_ELx_CP15_32_ISS_SYS_MASK (ESR_ELx_CP15_32_ISS_OP1_MASK | \ + ESR_ELx_CP15_32_ISS_OP2_MASK | \ + ESR_ELx_CP15_32_ISS_CRN_MASK | \ + ESR_ELx_CP15_32_ISS_CRM_MASK | \ + ESR_ELx_CP15_32_ISS_DIR_MASK) +#define ESR_ELx_CP15_32_ISS_SYS_VAL(op1, op2, crn, crm) \ + (((op1) << ESR_ELx_CP15_32_ISS_OP1_SHIFT) | \ + ((op2) << ESR_ELx_CP15_32_ISS_OP2_SHIFT) | \ + ((crn) << ESR_ELx_CP15_32_ISS_CRN_SHIFT) | \ + ((crm) << ESR_ELx_CP15_32_ISS_CRM_SHIFT)) + +#define ESR_ELx_CP15_64_ISS_DIR_MASK 0x1 +#define ESR_ELx_CP15_64_ISS_DIR_READ 0x1 +#define ESR_ELx_CP15_64_ISS_DIR_WRITE 0x0 + +#define ESR_ELx_CP15_64_ISS_RT_SHIFT 5 +#define ESR_ELx_CP15_64_ISS_RT_MASK (UL(0x1f) << ESR_ELx_CP15_64_ISS_RT_SHIFT) + +#define ESR_ELx_CP15_64_ISS_RT2_SHIFT 10 +#define ESR_ELx_CP15_64_ISS_RT2_MASK (UL(0x1f) << ESR_ELx_CP15_64_ISS_RT2_SHIFT) + +#define ESR_ELx_CP15_64_ISS_OP1_SHIFT 16 +#define ESR_ELx_CP15_64_ISS_OP1_MASK (UL(0xf) << ESR_ELx_CP15_64_ISS_OP1_SHIFT) +#define ESR_ELx_CP15_64_ISS_CRM_SHIFT 1 +#define ESR_ELx_CP15_64_ISS_CRM_MASK (UL(0xf) << ESR_ELx_CP15_64_ISS_CRM_SHIFT) + +#define ESR_ELx_CP15_64_ISS_SYS_VAL(op1, crm) \ + (((op1) << ESR_ELx_CP15_64_ISS_OP1_SHIFT) | \ + ((crm) << ESR_ELx_CP15_64_ISS_CRM_SHIFT)) + +#define ESR_ELx_CP15_64_ISS_SYS_MASK (ESR_ELx_CP15_64_ISS_OP1_MASK | \ + ESR_ELx_CP15_64_ISS_CRM_MASK | \ + ESR_ELx_CP15_64_ISS_DIR_MASK) + +#define ESR_ELx_CP15_64_ISS_SYS_CNTVCT (ESR_ELx_CP15_64_ISS_SYS_VAL(1, 14) | \ + ESR_ELx_CP15_64_ISS_DIR_READ) + +#define ESR_ELx_CP15_64_ISS_SYS_CNTVCTSS (ESR_ELx_CP15_64_ISS_SYS_VAL(9, 14) | \ + ESR_ELx_CP15_64_ISS_DIR_READ) + +#define ESR_ELx_CP15_32_ISS_SYS_CNTFRQ (ESR_ELx_CP15_32_ISS_SYS_VAL(0, 0, 14, 0) |\ + ESR_ELx_CP15_32_ISS_DIR_READ) + +/* + * ISS values for SME traps + */ + +#define ESR_ELx_SME_ISS_SME_DISABLED 0 +#define ESR_ELx_SME_ISS_ILL 1 +#define ESR_ELx_SME_ISS_SM_DISABLED 2 +#define ESR_ELx_SME_ISS_ZA_DISABLED 3 +#define ESR_ELx_SME_ISS_ZT_DISABLED 4 + +/* ISS field definitions for MOPS exceptions */ +#define ESR_ELx_MOPS_ISS_MEM_INST (UL(1) << 24) +#define ESR_ELx_MOPS_ISS_FROM_EPILOGUE (UL(1) << 18) +#define ESR_ELx_MOPS_ISS_WRONG_OPTION (UL(1) << 17) +#define ESR_ELx_MOPS_ISS_OPTION_A (UL(1) << 16) +#define ESR_ELx_MOPS_ISS_DESTREG(esr) (((esr) & (UL(0x1f) << 10)) >> 10) +#define ESR_ELx_MOPS_ISS_SRCREG(esr) (((esr) & (UL(0x1f) << 5)) >> 5) +#define ESR_ELx_MOPS_ISS_SIZEREG(esr) (((esr) & (UL(0x1f) << 0)) >> 0) + +#ifndef __ASSEMBLY__ +#include + +static inline unsigned long esr_brk_comment(unsigned long esr) +{ + return esr & ESR_ELx_BRK64_ISS_COMMENT_MASK; +} + +static inline bool esr_is_data_abort(unsigned long esr) +{ + const unsigned long ec = ESR_ELx_EC(esr); + + return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR; +} + +static inline bool esr_is_cfi_brk(unsigned long esr) +{ + return ESR_ELx_EC(esr) == ESR_ELx_EC_BRK64 && + (esr_brk_comment(esr) & ~CFI_BRK_IMM_MASK) == CFI_BRK_IMM_BASE; +} + +static inline bool esr_fsc_is_translation_fault(unsigned long esr) +{ + esr = esr & ESR_ELx_FSC; + + return (esr == ESR_ELx_FSC_FAULT_L(3)) || + (esr == ESR_ELx_FSC_FAULT_L(2)) || + (esr == ESR_ELx_FSC_FAULT_L(1)) || + (esr == ESR_ELx_FSC_FAULT_L(0)) || + (esr == ESR_ELx_FSC_FAULT_L(-1)); +} + +static inline bool esr_fsc_is_permission_fault(unsigned long esr) +{ + esr = esr & ESR_ELx_FSC; + + return (esr == ESR_ELx_FSC_PERM_L(3)) || + (esr == ESR_ELx_FSC_PERM_L(2)) || + (esr == ESR_ELx_FSC_PERM_L(1)) || + (esr == ESR_ELx_FSC_PERM_L(0)); +} + +static inline bool esr_fsc_is_access_flag_fault(unsigned long esr) +{ + esr = esr & ESR_ELx_FSC; + + return (esr == ESR_ELx_FSC_ACCESS_L(3)) || + (esr == ESR_ELx_FSC_ACCESS_L(2)) || + (esr == ESR_ELx_FSC_ACCESS_L(1)) || + (esr == ESR_ELx_FSC_ACCESS_L(0)); +} + +/* Indicate whether ESR.EC==0x1A is for an ERETAx instruction */ +static inline bool esr_iss_is_eretax(unsigned long esr) +{ + return esr & ESR_ELx_ERET_ISS_ERET; +} + +/* Indicate which key is used for ERETAx (false: A-Key, true: B-Key) */ +static inline bool esr_iss_is_eretab(unsigned long esr) +{ + return esr & ESR_ELx_ERET_ISS_ERETA; +} + +const char *esr_get_class_string(unsigned long esr); +#endif /* __ASSEMBLY */ + +#endif /* __ASM_ESR_H */ diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h index 964df31da9751c..66736ff04011e0 100644 --- a/tools/arch/arm64/include/uapi/asm/kvm.h +++ b/tools/arch/arm64/include/uapi/asm/kvm.h @@ -484,6 +484,12 @@ enum { */ #define KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2 (1ULL << 0) +/* + * Shutdown caused by a PSCI v1.3 SYSTEM_OFF2 call. + * Valid only when the system event has a type of KVM_SYSTEM_EVENT_SHUTDOWN. + */ +#define KVM_SYSTEM_EVENT_SHUTDOWN_FLAG_PSCI_OFF2 (1ULL << 0) + /* run->fail_entry.hardware_entry_failure_reason codes. */ #define KVM_EXIT_FAIL_ENTRY_CPU_UNSUPPORTED (1ULL << 0) diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h index 05eaf6db3ad4cb..60345dd2cba2d6 100644 --- a/tools/arch/s390/include/uapi/asm/kvm.h +++ b/tools/arch/s390/include/uapi/asm/kvm.h @@ -469,7 +469,8 @@ struct kvm_s390_vm_cpu_subfunc { __u8 kdsa[16]; /* with MSA9 */ __u8 sortl[32]; /* with STFLE.150 */ __u8 dfltcc[32]; /* with STFLE.151 */ - __u8 reserved[1728]; + __u8 pfcr[16]; /* with STFLE.201 */ + __u8 reserved[1712]; }; #define KVM_S390_VM_CPU_PROCESSOR_UV_FEAT_GUEST 6 diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index dd4682857c1208..17b6590748c00c 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -215,7 +215,7 @@ #define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* Disable Speculative Store Bypass. */ #define X86_FEATURE_LS_CFG_SSBD ( 7*32+24) /* AMD SSBD implementation via LS_CFG MSR */ #define X86_FEATURE_IBRS ( 7*32+25) /* "ibrs" Indirect Branch Restricted Speculation */ -#define X86_FEATURE_IBPB ( 7*32+26) /* "ibpb" Indirect Branch Prediction Barrier */ +#define X86_FEATURE_IBPB ( 7*32+26) /* "ibpb" Indirect Branch Prediction Barrier without a guaranteed RSB flush */ #define X86_FEATURE_STIBP ( 7*32+27) /* "stibp" Single Thread Indirect Branch Predictors */ #define X86_FEATURE_ZEN ( 7*32+28) /* Generic flag for all Zen and newer */ #define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* L1TF workaround PTE inversion */ @@ -317,6 +317,9 @@ #define X86_FEATURE_ZEN1 (11*32+31) /* CPU based on Zen1 microarchitecture */ /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ +#define X86_FEATURE_SHA512 (12*32+ 0) /* SHA512 instructions */ +#define X86_FEATURE_SM3 (12*32+ 1) /* SM3 instructions */ +#define X86_FEATURE_SM4 (12*32+ 2) /* SM4 instructions */ #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* "avx_vnni" AVX VNNI instructions */ #define X86_FEATURE_AVX512_BF16 (12*32+ 5) /* "avx512_bf16" AVX512 BFLOAT16 instructions */ #define X86_FEATURE_CMPCCXADD (12*32+ 7) /* CMPccXADD instructions */ @@ -348,6 +351,7 @@ #define X86_FEATURE_CPPC (13*32+27) /* "cppc" 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_AMD_IBPB_RET (13*32+30) /* IBPB clears return address predictor */ #define X86_FEATURE_BRS (13*32+31) /* "brs" Branch Sampling available */ /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */ @@ -472,7 +476,9 @@ #define X86_FEATURE_BHI_CTRL (21*32+ 2) /* BHI_DIS_S HW control available */ #define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* BHI_DIS_S HW control enabled */ #define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* Clear branch history at vmexit using SW loop */ -#define X86_FEATURE_FAST_CPPC (21*32 + 5) /* AMD Fast CPPC */ +#define X86_FEATURE_AMD_FAST_CPPC (21*32 + 5) /* Fast CPPC */ +#define X86_FEATURE_AMD_HETEROGENEOUS_CORES (21*32 + 6) /* Heterogeneous Core Topology */ +#define X86_FEATURE_AMD_WORKLOAD_CLASS (21*32 + 7) /* Workload Classification */ /* * BUG word(s) @@ -523,4 +529,5 @@ #define X86_BUG_DIV0 X86_BUG(1*32 + 1) /* "div0" AMD DIV0 speculation bug */ #define X86_BUG_RFDS X86_BUG(1*32 + 2) /* "rfds" CPU is vulnerable to Register File Data Sampling */ #define X86_BUG_BHI X86_BUG(1*32 + 3) /* "bhi" CPU is affected by Branch History Injection */ +#define X86_BUG_IBPB_NO_RET X86_BUG(1*32 + 4) /* "ibpb_no_ret" IBPB omits return target predictions */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/tools/arch/x86/include/uapi/asm/kvm.h b/tools/arch/x86/include/uapi/asm/kvm.h index a8debbf2f70280..88585c1de416fa 100644 --- a/tools/arch/x86/include/uapi/asm/kvm.h +++ b/tools/arch/x86/include/uapi/asm/kvm.h @@ -440,6 +440,7 @@ struct kvm_sync_regs { #define KVM_X86_QUIRK_FIX_HYPERCALL_INSN (1 << 5) #define KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS (1 << 6) #define KVM_X86_QUIRK_SLOT_ZAP_ALL (1 << 7) +#define KVM_X86_QUIRK_STUFF_FEATURE_MSRS (1 << 8) #define KVM_STATE_NESTED_FORMAT_VMX 0 #define KVM_STATE_NESTED_FORMAT_SVM 1 diff --git a/tools/bpf/bpf_jit_disasm.c b/tools/bpf/bpf_jit_disasm.c index a90a5d110f9255..1baee9e2aba981 100644 --- a/tools/bpf/bpf_jit_disasm.c +++ b/tools/bpf/bpf_jit_disasm.c @@ -210,7 +210,7 @@ static uint8_t *get_last_jit_image(char *haystack, size_t hlen, return NULL; } if (proglen > 1000000) { - printf("proglen of %d too big, stopping\n", proglen); + printf("proglen of %u too big, stopping\n", proglen); return NULL; } diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index ba927379eb2017..a4263dfb5e03a6 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -147,7 +147,11 @@ ifeq ($(feature-llvm),1) # If LLVM is available, use it for JIT disassembly CFLAGS += -DHAVE_LLVM_SUPPORT LLVM_CONFIG_LIB_COMPONENTS := mcdisassembler all-targets - CFLAGS += $(shell $(LLVM_CONFIG) --cflags) + # llvm-config always adds -D_GNU_SOURCE, however, it may already be in CFLAGS + # (e.g. when bpftool build is called from selftests build as selftests + # Makefile includes lib.mk which sets -D_GNU_SOURCE) which would cause + # compilation error due to redefinition. Let's filter it out here. + CFLAGS += $(filter-out -D_GNU_SOURCE,$(shell $(LLVM_CONFIG) --cflags)) LIBS += $(shell $(LLVM_CONFIG) --libs $(LLVM_CONFIG_LIB_COMPONENTS)) ifeq ($(shell $(LLVM_CONFIG) --shared-mode),static) LIBS += $(shell $(LLVM_CONFIG) --system-libs $(LLVM_CONFIG_LIB_COMPONENTS)) diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c index 7d2af1ff3c8d84..d005e4fd6128a2 100644 --- a/tools/bpf/bpftool/btf.c +++ b/tools/bpf/bpftool/btf.c @@ -1,11 +1,15 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* Copyright (C) 2019 Facebook */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif #include #include #include #include #include +#include #include #include #include @@ -21,6 +25,7 @@ #include "main.h" #define KFUNC_DECL_TAG "bpf_kfunc" +#define FASTCALL_DECL_TAG "bpf_fastcall" static const char * const btf_kind_str[NR_BTF_KINDS] = { [BTF_KIND_UNKN] = "UNKNOWN", @@ -284,7 +289,7 @@ static int dump_btf_type(const struct btf *btf, __u32 id, } else { if (btf_kflag(t)) printf("\n\t'%s' val=%lldLL", name, - (unsigned long long)val); + (long long)val); else printf("\n\t'%s' val=%lluULL", name, (unsigned long long)val); @@ -464,19 +469,59 @@ static int dump_btf_raw(const struct btf *btf, return 0; } +struct ptr_array { + __u32 cnt; + __u32 cap; + const void **elems; +}; + +static int ptr_array_push(const void *ptr, struct ptr_array *arr) +{ + __u32 new_cap; + void *tmp; + + if (arr->cnt == arr->cap) { + new_cap = (arr->cap ?: 16) * 2; + tmp = realloc(arr->elems, sizeof(*arr->elems) * new_cap); + if (!tmp) + return -ENOMEM; + arr->elems = tmp; + arr->cap = new_cap; + } + arr->elems[arr->cnt++] = ptr; + return 0; +} + +static void ptr_array_free(struct ptr_array *arr) +{ + free(arr->elems); +} + +static int cmp_kfuncs(const void *pa, const void *pb, void *ctx) +{ + struct btf *btf = ctx; + const struct btf_type *a = *(void **)pa; + const struct btf_type *b = *(void **)pb; + + return strcmp(btf__str_by_offset(btf, a->name_off), + btf__str_by_offset(btf, b->name_off)); +} + static int dump_btf_kfuncs(struct btf_dump *d, const struct btf *btf) { LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts); - int cnt = btf__type_cnt(btf); - int i; + __u32 cnt = btf__type_cnt(btf), i, j; + struct ptr_array fastcalls = {}; + struct ptr_array kfuncs = {}; + int err = 0; printf("\n/* BPF kfuncs */\n"); printf("#ifndef BPF_NO_KFUNC_PROTOTYPES\n"); for (i = 1; i < cnt; i++) { const struct btf_type *t = btf__type_by_id(btf, i); + const struct btf_type *ft; const char *name; - int err; if (!btf_is_decl_tag(t)) continue; @@ -484,27 +529,53 @@ static int dump_btf_kfuncs(struct btf_dump *d, const struct btf *btf) if (btf_decl_tag(t)->component_idx != -1) continue; - name = btf__name_by_offset(btf, t->name_off); - if (strncmp(name, KFUNC_DECL_TAG, sizeof(KFUNC_DECL_TAG))) + ft = btf__type_by_id(btf, t->type); + if (!btf_is_func(ft)) continue; - t = btf__type_by_id(btf, t->type); - if (!btf_is_func(t)) - continue; + name = btf__name_by_offset(btf, t->name_off); + if (strncmp(name, KFUNC_DECL_TAG, sizeof(KFUNC_DECL_TAG)) == 0) { + err = ptr_array_push(ft, &kfuncs); + if (err) + goto out; + } + + if (strncmp(name, FASTCALL_DECL_TAG, sizeof(FASTCALL_DECL_TAG)) == 0) { + err = ptr_array_push(ft, &fastcalls); + if (err) + goto out; + } + } + + /* Sort kfuncs by name for improved vmlinux.h stability */ + qsort_r(kfuncs.elems, kfuncs.cnt, sizeof(*kfuncs.elems), cmp_kfuncs, (void *)btf); + for (i = 0; i < kfuncs.cnt; i++) { + const struct btf_type *t = kfuncs.elems[i]; printf("extern "); + /* Assume small amount of fastcall kfuncs */ + for (j = 0; j < fastcalls.cnt; j++) { + if (fastcalls.elems[j] == t) { + printf("__bpf_fastcall "); + break; + } + } + opts.field_name = btf__name_by_offset(btf, t->name_off); err = btf_dump__emit_type_decl(d, t->type, &opts); if (err) - return err; + goto out; printf(" __weak __ksym;\n"); } printf("#endif\n\n"); - return 0; +out: + ptr_array_free(&fastcalls); + ptr_array_free(&kfuncs); + return err; } static void __printf(2, 0) btf_dump_printf(void *ctx, @@ -718,6 +789,13 @@ static int dump_btf_c(const struct btf *btf, printf("#ifndef __weak\n"); printf("#define __weak __attribute__((weak))\n"); printf("#endif\n\n"); + printf("#ifndef __bpf_fastcall\n"); + printf("#if __has_attribute(bpf_fastcall)\n"); + printf("#define __bpf_fastcall __attribute__((bpf_fastcall))\n"); + printf("#else\n"); + printf("#define __bpf_fastcall\n"); + printf("#endif\n"); + printf("#endif\n\n"); if (root_type_cnt) { for (i = 0; i < root_type_cnt; i++) { diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c index 7b8d9ec89ebd35..c032d2c6ab6d55 100644 --- a/tools/bpf/bpftool/jit_disasm.c +++ b/tools/bpf/bpftool/jit_disasm.c @@ -80,7 +80,8 @@ symbol_lookup_callback(__maybe_unused void *disasm_info, static int init_context(disasm_ctx_t *ctx, const char *arch, __maybe_unused const char *disassembler_options, - __maybe_unused unsigned char *image, __maybe_unused ssize_t len) + __maybe_unused unsigned char *image, __maybe_unused ssize_t len, + __maybe_unused __u64 func_ksym) { char *triple; @@ -109,12 +110,13 @@ static void destroy_context(disasm_ctx_t *ctx) } static int -disassemble_insn(disasm_ctx_t *ctx, unsigned char *image, ssize_t len, int pc) +disassemble_insn(disasm_ctx_t *ctx, unsigned char *image, ssize_t len, int pc, + __u64 func_ksym) { char buf[256]; int count; - count = LLVMDisasmInstruction(*ctx, image + pc, len - pc, pc, + count = LLVMDisasmInstruction(*ctx, image + pc, len - pc, func_ksym + pc, buf, sizeof(buf)); if (json_output) printf_json(buf); @@ -136,8 +138,21 @@ int disasm_init(void) #ifdef HAVE_LIBBFD_SUPPORT #define DISASM_SPACER "\t" +struct disasm_info { + struct disassemble_info info; + __u64 func_ksym; +}; + +static void disasm_print_addr(bfd_vma addr, struct disassemble_info *info) +{ + struct disasm_info *dinfo = container_of(info, struct disasm_info, info); + + addr += dinfo->func_ksym; + generic_print_address(addr, info); +} + typedef struct { - struct disassemble_info *info; + struct disasm_info *info; disassembler_ftype disassemble; bfd *bfdf; } disasm_ctx_t; @@ -215,7 +230,7 @@ static int fprintf_json_styled(void *out, static int init_context(disasm_ctx_t *ctx, const char *arch, const char *disassembler_options, - unsigned char *image, ssize_t len) + unsigned char *image, ssize_t len, __u64 func_ksym) { struct disassemble_info *info; char tpath[PATH_MAX]; @@ -238,12 +253,13 @@ static int init_context(disasm_ctx_t *ctx, const char *arch, } bfdf = ctx->bfdf; - ctx->info = malloc(sizeof(struct disassemble_info)); + ctx->info = malloc(sizeof(struct disasm_info)); if (!ctx->info) { p_err("mem alloc failed"); goto err_close; } - info = ctx->info; + ctx->info->func_ksym = func_ksym; + info = &ctx->info->info; if (json_output) init_disassemble_info_compat(info, stdout, @@ -272,6 +288,7 @@ static int init_context(disasm_ctx_t *ctx, const char *arch, info->disassembler_options = disassembler_options; info->buffer = image; info->buffer_length = len; + info->print_address_func = disasm_print_addr; disassemble_init_for_target(info); @@ -304,9 +321,10 @@ static void destroy_context(disasm_ctx_t *ctx) static int disassemble_insn(disasm_ctx_t *ctx, __maybe_unused unsigned char *image, - __maybe_unused ssize_t len, int pc) + __maybe_unused ssize_t len, int pc, + __maybe_unused __u64 func_ksym) { - return ctx->disassemble(pc, ctx->info); + return ctx->disassemble(pc, &ctx->info->info); } int disasm_init(void) @@ -331,7 +349,7 @@ int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, if (!len) return -1; - if (init_context(&ctx, arch, disassembler_options, image, len)) + if (init_context(&ctx, arch, disassembler_options, image, len, func_ksym)) return -1; if (json_output) @@ -360,7 +378,7 @@ int disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, printf("%4x:" DISASM_SPACER, pc); } - count = disassemble_insn(&ctx, image, len, pc); + count = disassemble_insn(&ctx, image, len, pc, func_ksym); if (json_output) { /* Operand array, was started in fprintf_json. Before diff --git a/tools/bpf/bpftool/pids.c b/tools/bpf/bpftool/pids.c index 9b898571b49e9e..23f488cf17403c 100644 --- a/tools/bpf/bpftool/pids.c +++ b/tools/bpf/bpftool/pids.c @@ -54,6 +54,7 @@ static void add_ref(struct hashmap *map, struct pid_iter_entry *e) ref = &refs->refs[refs->ref_cnt]; ref->pid = e->pid; memcpy(ref->comm, e->comm, sizeof(ref->comm)); + ref->comm[sizeof(ref->comm) - 1] = '\0'; refs->ref_cnt++; return; @@ -77,6 +78,7 @@ static void add_ref(struct hashmap *map, struct pid_iter_entry *e) ref = &refs->refs[0]; ref->pid = e->pid; memcpy(ref->comm, e->comm, sizeof(ref->comm)); + ref->comm[sizeof(ref->comm) - 1] = '\0'; refs->ref_cnt = 1; refs->has_bpf_cookie = e->has_bpf_cookie; refs->bpf_cookie = e->bpf_cookie; diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 2ff949ea82fa66..e71be67f1d8658 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -822,11 +822,18 @@ prog_dump(struct bpf_prog_info *info, enum dump_mode mode, printf("%s:\n", sym_name); } - if (disasm_print_insn(img, lens[i], opcodes, - name, disasm_opt, btf, - prog_linfo, ksyms[i], i, - linum)) - goto exit_free; + if (ksyms) { + if (disasm_print_insn(img, lens[i], opcodes, + name, disasm_opt, btf, + prog_linfo, ksyms[i], i, + linum)) + goto exit_free; + } else { + if (disasm_print_insn(img, lens[i], opcodes, + name, disasm_opt, btf, + NULL, 0, 0, false)) + goto exit_free; + } img += lens[i]; diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c index d54aaa0619df95..bd9f960bce3d5b 100644 --- a/tools/bpf/resolve_btfids/main.c +++ b/tools/bpf/resolve_btfids/main.c @@ -679,8 +679,8 @@ static int sets_patch(struct object *obj) next = rb_first(&obj->sets); while (next) { - struct btf_id_set8 *set8; - struct btf_id_set *set; + struct btf_id_set8 *set8 = NULL; + struct btf_id_set *set = NULL; unsigned long addr, off; struct btf_id *id; diff --git a/tools/bpf/runqslower/runqslower.bpf.c b/tools/bpf/runqslower/runqslower.bpf.c index 9a5c1f008fe603..fced54a3adf642 100644 --- a/tools/bpf/runqslower/runqslower.bpf.c +++ b/tools/bpf/runqslower/runqslower.bpf.c @@ -70,7 +70,6 @@ int handle__sched_switch(u64 *ctx) struct task_struct *next = (struct task_struct *)ctx[2]; struct runq_event event = {}; u64 *tsp, delta_us; - long state; u32 pid; /* ivcsw: treat like an enqueue event and store timestamp */ diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index ffd117135094cc..bca47d136f058f 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -30,9 +30,7 @@ endef # FEATURE_TESTS_BASIC := \ backtrace \ - dwarf \ - dwarf_getlocations \ - dwarf_getcfi \ + libdw \ eventfd \ fortify-source \ get_current_dir_name \ @@ -53,6 +51,7 @@ FEATURE_TESTS_BASIC := \ libslang-include-subdir \ libtraceevent \ libtracefs \ + libcpupower \ libcrypto \ libunwind \ pthread-attr-setaffinity-np \ @@ -60,7 +59,6 @@ FEATURE_TESTS_BASIC := \ reallocarray \ stackprotector-all \ timerfd \ - libdw-dwarf-unwind \ zlib \ lzma \ get_cpuid \ @@ -120,8 +118,7 @@ ifeq ($(FEATURE_TESTS),all) endif FEATURE_DISPLAY ?= \ - dwarf \ - dwarf_getlocations \ + libdw \ glibc \ libbfd \ libbfd-buildid \ @@ -133,7 +130,6 @@ FEATURE_DISPLAY ?= \ libpython \ libcrypto \ libunwind \ - libdw-dwarf-unwind \ libcapstone \ llvm-perf \ zlib \ @@ -233,7 +229,7 @@ endef # # generates feature value assignment for name, like: -# $(call feature_assign,dwarf) == feature-dwarf=1 +# $(call feature_assign,libdw) == feature-libdw=1 # feature_assign = feature-$(1)=$(feature-$(1)) diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 1658596188bf85..043dfd00fce72d 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -5,9 +5,7 @@ FILES= \ test-all.bin \ test-backtrace.bin \ test-bionic.bin \ - test-dwarf.bin \ - test-dwarf_getlocations.bin \ - test-dwarf_getcfi.bin \ + test-libdw.bin \ test-eventfd.bin \ test-fortify-source.bin \ test-get_current_dir_name.bin \ @@ -38,6 +36,7 @@ FILES= \ test-libslang.bin \ test-libslang-include-subdir.bin \ test-libtraceevent.bin \ + test-libcpupower.bin \ test-libtracefs.bin \ test-libcrypto.bin \ test-libunwind.bin \ @@ -52,7 +51,6 @@ FILES= \ test-pthread-barrier.bin \ test-stackprotector-all.bin \ test-timerfd.bin \ - test-libdw-dwarf-unwind.bin \ test-libbabeltrace.bin \ test-libcapstone.bin \ test-compile-32.bin \ @@ -168,9 +166,9 @@ $(OUTPUT)test-libopencsd.bin: $(BUILD) # -lopencsd_c_api -lopencsd provided by # $(FEATURE_CHECK_LDFLAGS-libopencsd) -DWARFLIBS := -ldw +DWLIBS := -ldw ifeq ($(findstring -static,${LDFLAGS}),-static) - DWARFLIBS += -lelf -lz -llzma -lbz2 -lzstd + DWLIBS += -lelf -lz -llzma -lbz2 -lzstd LIBDW_VERSION := $(shell $(PKG_CONFIG) --modversion libdw).0.0 LIBDW_VERSION_1 := $(word 1, $(subst ., ,$(LIBDW_VERSION))) @@ -179,21 +177,15 @@ ifeq ($(findstring -static,${LDFLAGS}),-static) # Elfutils merged libebl.a into libdw.a starting from version 0.177, # Link libebl.a only if libdw is older than this version. ifeq ($(shell test $(LIBDW_VERSION_2) -lt 177; echo $$?),0) - DWARFLIBS += -lebl + DWLIBS += -lebl endif # Must put -ldl after -lebl for dependency DWARFLIBS += -ldl endif -$(OUTPUT)test-dwarf.bin: - $(BUILD) $(DWARFLIBS) - -$(OUTPUT)test-dwarf_getlocations.bin: - $(BUILD) $(DWARFLIBS) - -$(OUTPUT)test-dwarf_getcfi.bin: - $(BUILD) $(DWARFLIBS) +$(OUTPUT)test-libdw.bin: + $(BUILD) $(DWLIBS) $(OUTPUT)test-libelf-getphdrnum.bin: $(BUILD) -lelf @@ -248,6 +240,9 @@ $(OUTPUT)test-libslang-include-subdir.bin: $(OUTPUT)test-libtraceevent.bin: $(BUILD) -ltraceevent +$(OUTPUT)test-libcpupower.bin: + $(BUILD) -lcpupower + $(OUTPUT)test-libtracefs.bin: $(BUILD) $(shell $(PKG_CONFIG) --cflags libtracefs 2>/dev/null) -ltracefs @@ -317,9 +312,6 @@ $(OUTPUT)test-backtrace.bin: $(OUTPUT)test-timerfd.bin: $(BUILD) -$(OUTPUT)test-libdw-dwarf-unwind.bin: - $(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind) - $(OUTPUT)test-libbabeltrace.bin: $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace) diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c index 6f4bf386a3b5c4..59ef3d7fe6a4e7 100644 --- a/tools/build/feature/test-all.c +++ b/tools/build/feature/test-all.c @@ -38,12 +38,8 @@ # include "test-glibc.c" #undef main -#define main main_test_dwarf -# include "test-dwarf.c" -#undef main - -#define main main_test_dwarf_getlocations -# include "test-dwarf_getlocations.c" +#define main main_test_libdw +# include "test-libdw.c" #undef main #define main main_test_eventfd @@ -98,10 +94,6 @@ # include "test-stackprotector-all.c" #undef main -#define main main_test_libdw_dwarf_unwind -# include "test-libdw-dwarf-unwind.c" -#undef main - #define main main_test_zlib # include "test-zlib.c" #undef main @@ -187,8 +179,7 @@ int main(int argc, char *argv[]) main_test_get_current_dir_name(); main_test_gettid(); main_test_glibc(); - main_test_dwarf(); - main_test_dwarf_getlocations(); + main_test_libdw(); main_test_eventfd(); main_test_libelf_getphdrnum(); main_test_libelf_gelf_getnote(); @@ -202,7 +193,6 @@ int main(int argc, char *argv[]) main_test_numa_num_possible_cpus(); main_test_timerfd(); main_test_stackprotector_all(); - main_test_libdw_dwarf_unwind(); main_test_zlib(); main_test_pthread_attr_setaffinity_np(); main_test_pthread_barrier(); diff --git a/tools/build/feature/test-dwarf.c b/tools/build/feature/test-dwarf.c deleted file mode 100644 index 8d474bd7371b21..00000000000000 --- a/tools/build/feature/test-dwarf.c +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - -int main(void) -{ - Dwarf *dbg = dwarf_begin(0, DWARF_C_READ); - - return (long)dbg; -} diff --git a/tools/build/feature/test-dwarf_getcfi.c b/tools/build/feature/test-dwarf_getcfi.c deleted file mode 100644 index 50e7d7cb7bdf94..00000000000000 --- a/tools/build/feature/test-dwarf_getcfi.c +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -int main(void) -{ - Dwarf *dwarf = NULL; - return dwarf_getcfi(dwarf) == NULL; -} diff --git a/tools/build/feature/test-dwarf_getlocations.c b/tools/build/feature/test-dwarf_getlocations.c deleted file mode 100644 index 78fb4a1fa68c3f..00000000000000 --- a/tools/build/feature/test-dwarf_getlocations.c +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -int main(void) -{ - Dwarf_Addr base, start, end; - Dwarf_Attribute attr; - Dwarf_Op *op; - size_t nops; - ptrdiff_t offset = 0; - return (int)dwarf_getlocations(&attr, offset, &base, &start, &end, &op, &nops); -} diff --git a/tools/build/feature/test-libcpupower.c b/tools/build/feature/test-libcpupower.c new file mode 100644 index 00000000000000..a346aa332a71d9 --- /dev/null +++ b/tools/build/feature/test-libcpupower.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +int main(void) +{ + int rv = cpuidle_state_count(0); + return rv; +} diff --git a/tools/build/feature/test-libdw-dwarf-unwind.c b/tools/build/feature/test-libdw-dwarf-unwind.c deleted file mode 100644 index ed03d95056090c..00000000000000 --- a/tools/build/feature/test-libdw-dwarf-unwind.c +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include - -int main(void) -{ - /* - * This function is guarded via: __nonnull_attribute__ (1, 2). - * Passing '1' as arguments value. This code is never executed, - * only compiled. - */ - dwfl_thread_getframes((void *) 1, (void *) 1, NULL); - return 0; -} diff --git a/tools/build/feature/test-libdw.c b/tools/build/feature/test-libdw.c new file mode 100644 index 00000000000000..2fb59479ab7716 --- /dev/null +++ b/tools/build/feature/test-libdw.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include + +int test_libdw(void) +{ + Dwarf *dbg = dwarf_begin(0, DWARF_C_READ); + + return (long)dbg; +} + +int test_libdw_unwind(void) +{ + /* + * This function is guarded via: __nonnull_attribute__ (1, 2). + * Passing '1' as arguments value. This code is never executed, + * only compiled. + */ + dwfl_thread_getframes((void *) 1, (void *) 1, NULL); + return 0; +} + +int test_libdw_getlocations(void) +{ + Dwarf_Addr base, start, end; + Dwarf_Attribute attr; + Dwarf_Op *op; + size_t nops; + ptrdiff_t offset = 0; + + return (int)dwarf_getlocations(&attr, offset, &base, &start, &end, &op, &nops); +} + +int test_libdw_getcfi(void) +{ + Dwarf *dwarf = NULL; + + return dwarf_getcfi(dwarf) == NULL; +} + +int test_elfutils(void) +{ + Dwarf_CFI *cfi = NULL; + + dwarf_cfi_end(cfi); + return 0; +} + +int main(void) +{ + return test_libdw() + test_libdw_unwind() + test_libdw_getlocations() + + test_libdw_getcfi() + test_elfutils(); +} diff --git a/tools/build/feature/test-libtraceevent.c b/tools/build/feature/test-libtraceevent.c index 416b11ffd4b4fc..804ad80dbbd937 100644 --- a/tools/build/feature/test-libtraceevent.c +++ b/tools/build/feature/test-libtraceevent.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -#include +#include int main(void) { diff --git a/tools/firewire/decode-fcp.c b/tools/firewire/decode-fcp.c index b67ebc88434d91..f115a3be8d1ef9 100644 --- a/tools/firewire/decode-fcp.c +++ b/tools/firewire/decode-fcp.c @@ -160,7 +160,7 @@ decode_avc(struct link_transaction *t) name = info->name; } - printf("av/c %s, subunit_type=%s, subunit_id=%d, opcode=%s", + printf("av/c %s, subunit_type=%s, subunit_id=%u, opcode=%s", ctype_names[frame->ctype], subunit_type_names[frame->subunit_type], frame->subunit_id, name); diff --git a/tools/firewire/nosy-dump.c b/tools/firewire/nosy-dump.c index 156e0356e81476..9a906de3a9efa5 100644 --- a/tools/firewire/nosy-dump.c +++ b/tools/firewire/nosy-dump.c @@ -771,7 +771,7 @@ print_packet(uint32_t *data, size_t length) if (pp->phy_config.set_root) printf(" set_root_id=%02x", pp->phy_config.root_id); if (pp->phy_config.set_gap_count) - printf(" set_gap_count=%d", pp->phy_config.gap_count); + printf(" set_gap_count=%u", pp->phy_config.gap_count); } break; @@ -781,13 +781,13 @@ print_packet(uint32_t *data, size_t length) case PHY_PACKET_SELF_ID: if (pp->self_id.extended) { - printf("extended self id: phy_id=%02x, seq=%d", + printf("extended self id: phy_id=%02x, seq=%u", pp->ext_self_id.phy_id, pp->ext_self_id.sequence); } else { static const char * const speed_names[] = { "S100", "S200", "S400", "BETA" }; - printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s", + printf("self id: phy_id=%02x, link %s, gap_count=%u speed=%s%s%s", pp->self_id.phy_id, (pp->self_id.link_active ? "active" : "not active"), pp->self_id.gap_count, diff --git a/tools/gpio/gpio-event-mon.c b/tools/gpio/gpio-event-mon.c index 5dee2b98ab6043..b70813b0bf8efa 100644 --- a/tools/gpio/gpio-event-mon.c +++ b/tools/gpio/gpio-event-mon.c @@ -69,14 +69,14 @@ int monitor_device(const char *device_name, } if (num_lines == 1) { - fprintf(stdout, "Monitoring line %d on %s\n", lines[0], device_name); + fprintf(stdout, "Monitoring line %u on %s\n", lines[0], device_name); fprintf(stdout, "Initial line value: %d\n", gpiotools_test_bit(values.bits, 0)); } else { - fprintf(stdout, "Monitoring lines %d", lines[0]); + fprintf(stdout, "Monitoring lines %u", lines[0]); for (i = 1; i < num_lines - 1; i++) - fprintf(stdout, ", %d", lines[i]); - fprintf(stdout, " and %d on %s\n", lines[i], device_name); + fprintf(stdout, ", %u", lines[i]); + fprintf(stdout, " and %u on %s\n", lines[i], device_name); fprintf(stdout, "Initial line values: %d", gpiotools_test_bit(values.bits, 0)); for (i = 1; i < num_lines - 1; i++) diff --git a/tools/gpio/gpio-sloppy-logic-analyzer.sh b/tools/gpio/gpio-sloppy-logic-analyzer.sh index ed21a110df5e5d..3ef2278e49f916 100755 --- a/tools/gpio/gpio-sloppy-logic-analyzer.sh +++ b/tools/gpio/gpio-sloppy-logic-analyzer.sh @@ -113,7 +113,7 @@ init_cpu() taskset -p "$newmask" "$p" || continue done 2>/dev/null >/dev/null - # Big hammer! Working with 'rcu_momentary_dyntick_idle()' for a more fine-grained solution + # Big hammer! Working with 'rcu_momentary_eqs()' for a more fine-grained solution # still printed warnings. Same for re-enabling the stall detector after sampling. echo 1 > /sys/module/rcupdate/parameters/rcu_cpu_stall_suppress diff --git a/tools/hv/.gitignore b/tools/hv/.gitignore new file mode 100644 index 00000000000000..0c5bc15d602f06 --- /dev/null +++ b/tools/hv/.gitignore @@ -0,0 +1,3 @@ +hv_fcopy_uio_daemon +hv_kvp_daemon +hv_vss_daemon diff --git a/tools/hv/hv_fcopy_uio_daemon.c b/tools/hv/hv_fcopy_uio_daemon.c index 7a00f3066a9807..0198321d14a291 100644 --- a/tools/hv/hv_fcopy_uio_daemon.c +++ b/tools/hv/hv_fcopy_uio_daemon.c @@ -35,8 +35,6 @@ #define WIN8_SRV_MINOR 1 #define WIN8_SRV_VERSION (WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR) -#define MAX_FOLDER_NAME 15 -#define MAX_PATH_LEN 15 #define FCOPY_UIO "/sys/bus/vmbus/devices/eb765408-105f-49b6-b4aa-c123b64d17d4/uio" #define FCOPY_VER_COUNT 1 @@ -51,7 +49,7 @@ static const int fw_versions[] = { #define HV_RING_SIZE 0x4000 /* 16KB ring buffer size */ -unsigned char desc[HV_RING_SIZE]; +static unsigned char desc[HV_RING_SIZE]; static int target_fd; static char target_fname[PATH_MAX]; @@ -409,8 +407,8 @@ int main(int argc, char *argv[]) struct vmbus_br txbr, rxbr; void *ring; uint32_t len = HV_RING_SIZE; - char uio_name[MAX_FOLDER_NAME] = {0}; - char uio_dev_path[MAX_PATH_LEN] = {0}; + char uio_name[NAME_MAX] = {0}; + char uio_dev_path[PATH_MAX] = {0}; static struct option long_options[] = { {"help", no_argument, 0, 'h' }, @@ -468,8 +466,10 @@ int main(int argc, char *argv[]) */ ret = pread(fcopy_fd, &tmp, sizeof(int), 0); if (ret < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; syslog(LOG_ERR, "pread failed: %s", strerror(errno)); - continue; + goto close; } len = HV_RING_SIZE; diff --git a/tools/hv/hv_get_dns_info.sh b/tools/hv/hv_get_dns_info.sh index 058c17b46ffcdd..268521234d4b06 100755 --- a/tools/hv/hv_get_dns_info.sh +++ b/tools/hv/hv_get_dns_info.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # This example script parses /etc/resolv.conf to retrive DNS information. # In the interest of keeping the KVP daemon code free of distro specific @@ -10,4 +10,4 @@ # this script can be based on the Network Manager APIs for retrieving DNS # entries. -cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }' +exec awk '/^nameserver/ { print $2 }' /etc/resolv.conf 2>/dev/null diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index ae57bf69ad4af3..04ba035d67e9de 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -725,7 +725,7 @@ static void kvp_get_ipconfig_info(char *if_name, * . */ - sprintf(cmd, KVP_SCRIPTS_PATH "%s", "hv_get_dns_info"); + sprintf(cmd, "exec %s %s", KVP_SCRIPTS_PATH "hv_get_dns_info", if_name); /* * Execute the command to gather DNS info. @@ -742,7 +742,7 @@ static void kvp_get_ipconfig_info(char *if_name, * Enabled: DHCP enabled. */ - sprintf(cmd, KVP_SCRIPTS_PATH "%s %s", "hv_get_dhcp_info", if_name); + sprintf(cmd, "exec %s %s", KVP_SCRIPTS_PATH "hv_get_dhcp_info", if_name); file = popen(cmd, "r"); if (file == NULL) @@ -1606,8 +1606,9 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) * invoke the external script to do its magic. */ - str_len = snprintf(cmd, sizeof(cmd), KVP_SCRIPTS_PATH "%s %s %s", - "hv_set_ifconfig", if_filename, nm_filename); + str_len = snprintf(cmd, sizeof(cmd), "exec %s %s %s", + KVP_SCRIPTS_PATH "hv_set_ifconfig", + if_filename, nm_filename); /* * This is a little overcautious, but it's necessary to suppress some * false warnings from gcc 8.0.1. diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh index 440a91b35823bf..2f8baed2b8f796 100755 --- a/tools/hv/hv_set_ifconfig.sh +++ b/tools/hv/hv_set_ifconfig.sh @@ -81,7 +81,7 @@ echo "ONBOOT=yes" >> $1 cp $1 /etc/sysconfig/network-scripts/ -chmod 600 $2 +umask 0177 interface=$(echo $2 | awk -F - '{ print $2 }') filename="${2##*/}" diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c index 8073c9e4fe46a0..cccf62ea2b8f9b 100644 --- a/tools/iio/iio_event_monitor.c +++ b/tools/iio/iio_event_monitor.c @@ -63,6 +63,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_DELTA_VELOCITY] = "deltavelocity", [IIO_COLORTEMP] = "colortemp", [IIO_CHROMATICITY] = "chromaticity", + [IIO_ATTENTION] = "attention", }; static const char * const iio_ev_type_text[] = { @@ -183,6 +184,7 @@ static bool event_is_known(struct iio_event_data *event) case IIO_DELTA_VELOCITY: case IIO_COLORTEMP: case IIO_CHROMATICITY: + case IIO_ATTENTION: break; default: return false; @@ -449,6 +451,7 @@ int main(int argc, char **argv) enable_events(dev_dir_name, 0); free(chrdev_name); + free(dev_dir_name); return ret; } diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index 62e7c901ac28c5..e20f98e14e8146 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _TOOLS_LINUX_COMPILER_H_ -#error "Please don't include directly, include instead." +#error "Please do not include directly, include instead." #endif /* diff --git a/tools/include/nolibc/arch-s390.h b/tools/include/nolibc/arch-s390.h index 2ec13d8b9a2db8..f9ab83a219b8a2 100644 --- a/tools/include/nolibc/arch-s390.h +++ b/tools/include/nolibc/arch-s390.h @@ -10,6 +10,7 @@ #include "compiler.h" #include "crt.h" +#include "std.h" /* Syscalls for s390: * - registers are 64-bit diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h index 9bc6a706a33237..fa1f547e7f13d1 100644 --- a/tools/include/nolibc/compiler.h +++ b/tools/include/nolibc/compiler.h @@ -32,4 +32,10 @@ # define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector"))) #endif /* __nolibc_has_attribute(no_stack_protector) */ +#if __nolibc_has_attribute(fallthrough) +# define __nolibc_fallthrough do { } while (0); __attribute__((fallthrough)) +#else +# define __nolibc_fallthrough do { } while (0) +#endif /* __nolibc_has_attribute(fallthrough) */ + #endif /* _NOLIBC_COMPILER_H */ diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index c968dbbc4ef813..3892034198dd56 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -15,6 +15,7 @@ #include "stdarg.h" #include "stdlib.h" #include "string.h" +#include "compiler.h" #ifndef EOF #define EOF (-1) @@ -264,7 +265,7 @@ int vfprintf(FILE *stream, const char *fmt, va_list args) case 'p': *(out++) = '0'; *(out++) = 'x'; - /* fall through */ + __nolibc_fallthrough; default: /* 'x' and 'p' above */ u64toh_r(v, out); break; diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h index 6ce1f1ceb432c6..1ea2c4c33b86a2 100644 --- a/tools/include/uapi/asm-generic/mman-common.h +++ b/tools/include/uapi/asm-generic/mman-common.h @@ -79,6 +79,9 @@ #define MADV_COLLAPSE 25 /* Synchronous hugepage collapse */ +#define MADV_GUARD_INSTALL 102 /* fatal signal on access to range */ +#define MADV_GUARD_REMOVE 103 /* unguard range */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/tools/include/uapi/asm-generic/mman.h b/tools/include/uapi/asm-generic/mman.h index 406f7718f9ad07..51d2556af54ac7 100644 --- a/tools/include/uapi/asm-generic/mman.h +++ b/tools/include/uapi/asm-generic/mman.h @@ -19,4 +19,8 @@ #define MCL_FUTURE 2 /* lock all future mappings */ #define MCL_ONFAULT 4 /* lock all pages that are faulted in */ +#define SHADOW_STACK_SET_TOKEN (1ULL << 0) /* Set up a restore token in the shadow stack */ +#define SHADOW_STACK_SET_MARKER (1ULL << 1) /* Set up a top of stack marker in the shadow stack */ + + #endif /* __ASM_GENERIC_MMAN_H */ diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h index 54d9c8bf7c55f0..281df9139d2b90 100644 --- a/tools/include/uapi/asm-generic/socket.h +++ b/tools/include/uapi/asm-generic/socket.h @@ -124,6 +124,8 @@ #define SO_PASSPIDFD 76 #define SO_PEERPIDFD 77 +#define SCM_TS_OPT_ID 78 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h index 5bf6148cac2b93..88dc393c2bca38 100644 --- a/tools/include/uapi/asm-generic/unistd.h +++ b/tools/include/uapi/asm-generic/unistd.h @@ -841,8 +841,17 @@ __SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules) #define __NR_mseal 462 __SYSCALL(__NR_mseal, sys_mseal) +#define __NR_setxattrat 463 +__SYSCALL(__NR_setxattrat, sys_setxattrat) +#define __NR_getxattrat 464 +__SYSCALL(__NR_getxattrat, sys_getxattrat) +#define __NR_listxattrat 465 +__SYSCALL(__NR_listxattrat, sys_listxattrat) +#define __NR_removexattrat 466 +__SYSCALL(__NR_removexattrat, sys_removexattrat) + #undef __NR_syscalls -#define __NR_syscalls 463 +#define __NR_syscalls 467 /* * 32 bit systems traditionally used different diff --git a/tools/include/uapi/drm/drm.h b/tools/include/uapi/drm/drm.h index 16122819edfeff..7fba37b94401a6 100644 --- a/tools/include/uapi/drm/drm.h +++ b/tools/include/uapi/drm/drm.h @@ -1024,6 +1024,13 @@ struct drm_crtc_queue_sequence { __u64 user_data; /* user data passed to event */ }; +#define DRM_CLIENT_NAME_MAX_LEN 64 +struct drm_set_client_name { + __u64 name_len; + __u64 name; +}; + + #if defined(__cplusplus) } #endif @@ -1288,6 +1295,16 @@ extern "C" { */ #define DRM_IOCTL_MODE_CLOSEFB DRM_IOWR(0xD0, struct drm_mode_closefb) +/** + * DRM_IOCTL_SET_CLIENT_NAME - Attach a name to a drm_file + * + * Having a name allows for easier tracking and debugging. + * The length of the name (without null ending char) must be + * <= DRM_CLIENT_NAME_MAX_LEN. + * The call will fail if the name contains whitespaces or non-printable chars. + */ +#define DRM_IOCTL_SET_CLIENT_NAME DRM_IOWR(0xD1, struct drm_set_client_name) + /* * Device specific ioctls should only be in their respective headers * The device specific ioctl range is from 0x40 to 0x9f. diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 4a939c90dc2e4b..4162afc6b5d0d6 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1116,6 +1116,7 @@ enum bpf_attach_type { BPF_NETKIT_PRIMARY, BPF_NETKIT_PEER, BPF_TRACE_KPROBE_SESSION, + BPF_TRACE_UPROBE_SESSION, __MAX_BPF_ATTACH_TYPE }; @@ -1973,6 +1974,8 @@ union bpf_attr { * program. * Return * The SMP id of the processor running the program. + * Attributes + * __bpf_fastcall * * long bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len, u64 flags) * Description @@ -3104,10 +3107,6 @@ union bpf_attr { * with the **CONFIG_BPF_KPROBE_OVERRIDE** configuration * option, and in this case it only works on functions tagged with * **ALLOW_ERROR_INJECTION** in the kernel code. - * - * Also, the helper is only available for the architectures having - * the CONFIG_FUNCTION_ERROR_INJECTION option. As of this writing, - * x86 architecture is the only one to support this feature. * Return * 0 * @@ -5372,7 +5371,7 @@ union bpf_attr { * Currently, the **flags** must be 0. Currently, nr_loops is * limited to 1 << 23 (~8 million) loops. * - * long (\*callback_fn)(u32 index, void \*ctx); + * long (\*callback_fn)(u64 index, void \*ctx); * * where **index** is the current index in the loop. The index * is zero-indexed. diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index f0d71b2a3f1e1a..8516c1ccd57a7c 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -377,6 +377,7 @@ enum { IFLA_GSO_IPV4_MAX_SIZE, IFLA_GRO_IPV4_MAX_SIZE, IFLA_DPLL_PIN, + IFLA_MAX_PACING_OFFLOAD_HORIZON, __IFLA_MAX }; @@ -461,6 +462,286 @@ enum in6_addr_gen_mode { /* Bridge section */ +/** + * DOC: Bridge enum definition + * + * Please *note* that the timer values in the following section are expected + * in clock_t format, which is seconds multiplied by USER_HZ (generally + * defined as 100). + * + * @IFLA_BR_FORWARD_DELAY + * The bridge forwarding delay is the time spent in LISTENING state + * (before moving to LEARNING) and in LEARNING state (before moving + * to FORWARDING). Only relevant if STP is enabled. + * + * The valid values are between (2 * USER_HZ) and (30 * USER_HZ). + * The default value is (15 * USER_HZ). + * + * @IFLA_BR_HELLO_TIME + * The time between hello packets sent by the bridge, when it is a root + * bridge or a designated bridge. Only relevant if STP is enabled. + * + * The valid values are between (1 * USER_HZ) and (10 * USER_HZ). + * The default value is (2 * USER_HZ). + * + * @IFLA_BR_MAX_AGE + * The hello packet timeout is the time until another bridge in the + * spanning tree is assumed to be dead, after reception of its last hello + * message. Only relevant if STP is enabled. + * + * The valid values are between (6 * USER_HZ) and (40 * USER_HZ). + * The default value is (20 * USER_HZ). + * + * @IFLA_BR_AGEING_TIME + * Configure the bridge's FDB entries aging time. It is the time a MAC + * address will be kept in the FDB after a packet has been received from + * that address. After this time has passed, entries are cleaned up. + * Allow values outside the 802.1 standard specification for special cases: + * + * * 0 - entry never ages (all permanent) + * * 1 - entry disappears (no persistence) + * + * The default value is (300 * USER_HZ). + * + * @IFLA_BR_STP_STATE + * Turn spanning tree protocol on (*IFLA_BR_STP_STATE* > 0) or off + * (*IFLA_BR_STP_STATE* == 0) for this bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_PRIORITY + * Set this bridge's spanning tree priority, used during STP root bridge + * election. + * + * The valid values are between 0 and 65535. + * + * @IFLA_BR_VLAN_FILTERING + * Turn VLAN filtering on (*IFLA_BR_VLAN_FILTERING* > 0) or off + * (*IFLA_BR_VLAN_FILTERING* == 0). When disabled, the bridge will not + * consider the VLAN tag when handling packets. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_VLAN_PROTOCOL + * Set the protocol used for VLAN filtering. + * + * The valid values are 0x8100(802.1Q) or 0x88A8(802.1AD). The default value + * is 0x8100(802.1Q). + * + * @IFLA_BR_GROUP_FWD_MASK + * The group forwarding mask. This is the bitmask that is applied to + * decide whether to forward incoming frames destined to link-local + * addresses (of the form 01:80:C2:00:00:0X). + * + * The default value is 0, which means the bridge does not forward any + * link-local frames coming on this port. + * + * @IFLA_BR_ROOT_ID + * The bridge root id, read only. + * + * @IFLA_BR_BRIDGE_ID + * The bridge id, read only. + * + * @IFLA_BR_ROOT_PORT + * The bridge root port, read only. + * + * @IFLA_BR_ROOT_PATH_COST + * The bridge root path cost, read only. + * + * @IFLA_BR_TOPOLOGY_CHANGE + * The bridge topology change, read only. + * + * @IFLA_BR_TOPOLOGY_CHANGE_DETECTED + * The bridge topology change detected, read only. + * + * @IFLA_BR_HELLO_TIMER + * The bridge hello timer, read only. + * + * @IFLA_BR_TCN_TIMER + * The bridge tcn timer, read only. + * + * @IFLA_BR_TOPOLOGY_CHANGE_TIMER + * The bridge topology change timer, read only. + * + * @IFLA_BR_GC_TIMER + * The bridge gc timer, read only. + * + * @IFLA_BR_GROUP_ADDR + * Set the MAC address of the multicast group this bridge uses for STP. + * The address must be a link-local address in standard Ethernet MAC address + * format. It is an address of the form 01:80:C2:00:00:0X, with X in [0, 4..f]. + * + * The default value is 0. + * + * @IFLA_BR_FDB_FLUSH + * Flush bridge's fdb dynamic entries. + * + * @IFLA_BR_MCAST_ROUTER + * Set bridge's multicast router if IGMP snooping is enabled. + * The valid values are: + * + * * 0 - disabled. + * * 1 - automatic (queried). + * * 2 - permanently enabled. + * + * The default value is 1. + * + * @IFLA_BR_MCAST_SNOOPING + * Turn multicast snooping on (*IFLA_BR_MCAST_SNOOPING* > 0) or off + * (*IFLA_BR_MCAST_SNOOPING* == 0). + * + * The default value is 1. + * + * @IFLA_BR_MCAST_QUERY_USE_IFADDR + * If enabled use the bridge's own IP address as source address for IGMP + * queries (*IFLA_BR_MCAST_QUERY_USE_IFADDR* > 0) or the default of 0.0.0.0 + * (*IFLA_BR_MCAST_QUERY_USE_IFADDR* == 0). + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MCAST_QUERIER + * Enable (*IFLA_BR_MULTICAST_QUERIER* > 0) or disable + * (*IFLA_BR_MULTICAST_QUERIER* == 0) IGMP querier, ie sending of multicast + * queries by the bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MCAST_HASH_ELASTICITY + * Set multicast database hash elasticity, It is the maximum chain length in + * the multicast hash table. This attribute is *deprecated* and the value + * is always 16. + * + * @IFLA_BR_MCAST_HASH_MAX + * Set maximum size of the multicast hash table + * + * The default value is 4096, the value must be a power of 2. + * + * @IFLA_BR_MCAST_LAST_MEMBER_CNT + * The Last Member Query Count is the number of Group-Specific Queries + * sent before the router assumes there are no local members. The Last + * Member Query Count is also the number of Group-and-Source-Specific + * Queries sent before the router assumes there are no listeners for a + * particular source. + * + * The default value is 2. + * + * @IFLA_BR_MCAST_STARTUP_QUERY_CNT + * The Startup Query Count is the number of Queries sent out on startup, + * separated by the Startup Query Interval. + * + * The default value is 2. + * + * @IFLA_BR_MCAST_LAST_MEMBER_INTVL + * The Last Member Query Interval is the Max Response Time inserted into + * Group-Specific Queries sent in response to Leave Group messages, and + * is also the amount of time between Group-Specific Query messages. + * + * The default value is (1 * USER_HZ). + * + * @IFLA_BR_MCAST_MEMBERSHIP_INTVL + * The interval after which the bridge will leave a group, if no membership + * reports for this group are received. + * + * The default value is (260 * USER_HZ). + * + * @IFLA_BR_MCAST_QUERIER_INTVL + * The interval between queries sent by other routers. if no queries are + * seen after this delay has passed, the bridge will start to send its own + * queries (as if *IFLA_BR_MCAST_QUERIER_INTVL* was enabled). + * + * The default value is (255 * USER_HZ). + * + * @IFLA_BR_MCAST_QUERY_INTVL + * The Query Interval is the interval between General Queries sent by + * the Querier. + * + * The default value is (125 * USER_HZ). The minimum value is (1 * USER_HZ). + * + * @IFLA_BR_MCAST_QUERY_RESPONSE_INTVL + * The Max Response Time used to calculate the Max Resp Code inserted + * into the periodic General Queries. + * + * The default value is (10 * USER_HZ). + * + * @IFLA_BR_MCAST_STARTUP_QUERY_INTVL + * The interval between queries in the startup phase. + * + * The default value is (125 * USER_HZ) / 4. The minimum value is (1 * USER_HZ). + * + * @IFLA_BR_NF_CALL_IPTABLES + * Enable (*NF_CALL_IPTABLES* > 0) or disable (*NF_CALL_IPTABLES* == 0) + * iptables hooks on the bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_NF_CALL_IP6TABLES + * Enable (*NF_CALL_IP6TABLES* > 0) or disable (*NF_CALL_IP6TABLES* == 0) + * ip6tables hooks on the bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_NF_CALL_ARPTABLES + * Enable (*NF_CALL_ARPTABLES* > 0) or disable (*NF_CALL_ARPTABLES* == 0) + * arptables hooks on the bridge. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_VLAN_DEFAULT_PVID + * VLAN ID applied to untagged and priority-tagged incoming packets. + * + * The default value is 1. Setting to the special value 0 makes all ports of + * this bridge not have a PVID by default, which means that they will + * not accept VLAN-untagged traffic. + * + * @IFLA_BR_PAD + * Bridge attribute padding type for netlink message. + * + * @IFLA_BR_VLAN_STATS_ENABLED + * Enable (*IFLA_BR_VLAN_STATS_ENABLED* == 1) or disable + * (*IFLA_BR_VLAN_STATS_ENABLED* == 0) per-VLAN stats accounting. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MCAST_STATS_ENABLED + * Enable (*IFLA_BR_MCAST_STATS_ENABLED* > 0) or disable + * (*IFLA_BR_MCAST_STATS_ENABLED* == 0) multicast (IGMP/MLD) stats + * accounting. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MCAST_IGMP_VERSION + * Set the IGMP version. + * + * The valid values are 2 and 3. The default value is 2. + * + * @IFLA_BR_MCAST_MLD_VERSION + * Set the MLD version. + * + * The valid values are 1 and 2. The default value is 1. + * + * @IFLA_BR_VLAN_STATS_PER_PORT + * Enable (*IFLA_BR_VLAN_STATS_PER_PORT* == 1) or disable + * (*IFLA_BR_VLAN_STATS_PER_PORT* == 0) per-VLAN per-port stats accounting. + * Can be changed only when there are no port VLANs configured. + * + * The default value is 0 (disabled). + * + * @IFLA_BR_MULTI_BOOLOPT + * The multi_boolopt is used to control new boolean options to avoid adding + * new netlink attributes. You can look at ``enum br_boolopt_id`` for those + * options. + * + * @IFLA_BR_MCAST_QUERIER_STATE + * Bridge mcast querier states, read only. + * + * @IFLA_BR_FDB_N_LEARNED + * The number of dynamically learned FDB entries for the current bridge, + * read only. + * + * @IFLA_BR_FDB_MAX_LEARNED + * Set the number of max dynamically learned FDB entries for the current + * bridge. + */ enum { IFLA_BR_UNSPEC, IFLA_BR_FORWARD_DELAY, @@ -510,6 +791,8 @@ enum { IFLA_BR_VLAN_STATS_PER_PORT, IFLA_BR_MULTI_BOOLOPT, IFLA_BR_MCAST_QUERIER_STATE, + IFLA_BR_FDB_N_LEARNED, + IFLA_BR_FDB_MAX_LEARNED, __IFLA_BR_MAX, }; @@ -520,11 +803,252 @@ struct ifla_bridge_id { __u8 addr[6]; /* ETH_ALEN */ }; +/** + * DOC: Bridge mode enum definition + * + * @BRIDGE_MODE_HAIRPIN + * Controls whether traffic may be sent back out of the port on which it + * was received. This option is also called reflective relay mode, and is + * used to support basic VEPA (Virtual Ethernet Port Aggregator) + * capabilities. By default, this flag is turned off and the bridge will + * not forward traffic back out of the receiving port. + */ enum { BRIDGE_MODE_UNSPEC, BRIDGE_MODE_HAIRPIN, }; +/** + * DOC: Bridge port enum definition + * + * @IFLA_BRPORT_STATE + * The operation state of the port. Here are the valid values. + * + * * 0 - port is in STP *DISABLED* state. Make this port completely + * inactive for STP. This is also called BPDU filter and could be used + * to disable STP on an untrusted port, like a leaf virtual device. + * The traffic forwarding is also stopped on this port. + * * 1 - port is in STP *LISTENING* state. Only valid if STP is enabled + * on the bridge. In this state the port listens for STP BPDUs and + * drops all other traffic frames. + * * 2 - port is in STP *LEARNING* state. Only valid if STP is enabled on + * the bridge. In this state the port will accept traffic only for the + * purpose of updating MAC address tables. + * * 3 - port is in STP *FORWARDING* state. Port is fully active. + * * 4 - port is in STP *BLOCKING* state. Only valid if STP is enabled on + * the bridge. This state is used during the STP election process. + * In this state, port will only process STP BPDUs. + * + * @IFLA_BRPORT_PRIORITY + * The STP port priority. The valid values are between 0 and 255. + * + * @IFLA_BRPORT_COST + * The STP path cost of the port. The valid values are between 1 and 65535. + * + * @IFLA_BRPORT_MODE + * Set the bridge port mode. See *BRIDGE_MODE_HAIRPIN* for more details. + * + * @IFLA_BRPORT_GUARD + * Controls whether STP BPDUs will be processed by the bridge port. By + * default, the flag is turned off to allow BPDU processing. Turning this + * flag on will disable the bridge port if a STP BPDU packet is received. + * + * If the bridge has Spanning Tree enabled, hostile devices on the network + * may send BPDU on a port and cause network failure. Setting *guard on* + * will detect and stop this by disabling the port. The port will be + * restarted if the link is brought down, or removed and reattached. + * + * @IFLA_BRPORT_PROTECT + * Controls whether a given port is allowed to become a root port or not. + * Only used when STP is enabled on the bridge. By default the flag is off. + * + * This feature is also called root port guard. If BPDU is received from a + * leaf (edge) port, it should not be elected as root port. This could + * be used if using STP on a bridge and the downstream bridges are not fully + * trusted; this prevents a hostile guest from rerouting traffic. + * + * @IFLA_BRPORT_FAST_LEAVE + * This flag allows the bridge to immediately stop multicast traffic + * forwarding on a port that receives an IGMP Leave message. It is only used + * when IGMP snooping is enabled on the bridge. By default the flag is off. + * + * @IFLA_BRPORT_LEARNING + * Controls whether a given port will learn *source* MAC addresses from + * received traffic or not. Also controls whether dynamic FDB entries + * (which can also be added by software) will be refreshed by incoming + * traffic. By default this flag is on. + * + * @IFLA_BRPORT_UNICAST_FLOOD + * Controls whether unicast traffic for which there is no FDB entry will + * be flooded towards this port. By default this flag is on. + * + * @IFLA_BRPORT_PROXYARP + * Enable proxy ARP on this port. + * + * @IFLA_BRPORT_LEARNING_SYNC + * Controls whether a given port will sync MAC addresses learned on device + * port to bridge FDB. + * + * @IFLA_BRPORT_PROXYARP_WIFI + * Enable proxy ARP on this port which meets extended requirements by + * IEEE 802.11 and Hotspot 2.0 specifications. + * + * @IFLA_BRPORT_ROOT_ID + * + * @IFLA_BRPORT_BRIDGE_ID + * + * @IFLA_BRPORT_DESIGNATED_PORT + * + * @IFLA_BRPORT_DESIGNATED_COST + * + * @IFLA_BRPORT_ID + * + * @IFLA_BRPORT_NO + * + * @IFLA_BRPORT_TOPOLOGY_CHANGE_ACK + * + * @IFLA_BRPORT_CONFIG_PENDING + * + * @IFLA_BRPORT_MESSAGE_AGE_TIMER + * + * @IFLA_BRPORT_FORWARD_DELAY_TIMER + * + * @IFLA_BRPORT_HOLD_TIMER + * + * @IFLA_BRPORT_FLUSH + * Flush bridge ports' fdb dynamic entries. + * + * @IFLA_BRPORT_MULTICAST_ROUTER + * Configure the port's multicast router presence. A port with + * a multicast router will receive all multicast traffic. + * The valid values are: + * + * * 0 disable multicast routers on this port + * * 1 let the system detect the presence of routers (default) + * * 2 permanently enable multicast traffic forwarding on this port + * * 3 enable multicast routers temporarily on this port, not depending + * on incoming queries. + * + * @IFLA_BRPORT_PAD + * + * @IFLA_BRPORT_MCAST_FLOOD + * Controls whether a given port will flood multicast traffic for which + * there is no MDB entry. By default this flag is on. + * + * @IFLA_BRPORT_MCAST_TO_UCAST + * Controls whether a given port will replicate packets using unicast + * instead of multicast. By default this flag is off. + * + * This is done by copying the packet per host and changing the multicast + * destination MAC to a unicast one accordingly. + * + * *mcast_to_unicast* works on top of the multicast snooping feature of the + * bridge. Which means unicast copies are only delivered to hosts which + * are interested in unicast and signaled this via IGMP/MLD reports previously. + * + * This feature is intended for interface types which have a more reliable + * and/or efficient way to deliver unicast packets than broadcast ones + * (e.g. WiFi). + * + * However, it should only be enabled on interfaces where no IGMPv2/MLDv1 + * report suppression takes place. IGMP/MLD report suppression issue is + * usually overcome by the network daemon (supplicant) enabling AP isolation + * and by that separating all STAs. + * + * Delivery of STA-to-STA IP multicast is made possible again by enabling + * and utilizing the bridge hairpin mode, which considers the incoming port + * as a potential outgoing port, too (see *BRIDGE_MODE_HAIRPIN* option). + * Hairpin mode is performed after multicast snooping, therefore leading + * to only deliver reports to STAs running a multicast router. + * + * @IFLA_BRPORT_VLAN_TUNNEL + * Controls whether vlan to tunnel mapping is enabled on the port. + * By default this flag is off. + * + * @IFLA_BRPORT_BCAST_FLOOD + * Controls flooding of broadcast traffic on the given port. By default + * this flag is on. + * + * @IFLA_BRPORT_GROUP_FWD_MASK + * Set the group forward mask. This is a bitmask that is applied to + * decide whether to forward incoming frames destined to link-local + * addresses. The addresses of the form are 01:80:C2:00:00:0X (defaults + * to 0, which means the bridge does not forward any link-local frames + * coming on this port). + * + * @IFLA_BRPORT_NEIGH_SUPPRESS + * Controls whether neighbor discovery (arp and nd) proxy and suppression + * is enabled on the port. By default this flag is off. + * + * @IFLA_BRPORT_ISOLATED + * Controls whether a given port will be isolated, which means it will be + * able to communicate with non-isolated ports only. By default this + * flag is off. + * + * @IFLA_BRPORT_BACKUP_PORT + * Set a backup port. If the port loses carrier all traffic will be + * redirected to the configured backup port. Set the value to 0 to disable + * it. + * + * @IFLA_BRPORT_MRP_RING_OPEN + * + * @IFLA_BRPORT_MRP_IN_OPEN + * + * @IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT + * The number of per-port EHT hosts limit. The default value is 512. + * Setting to 0 is not allowed. + * + * @IFLA_BRPORT_MCAST_EHT_HOSTS_CNT + * The current number of tracked hosts, read only. + * + * @IFLA_BRPORT_LOCKED + * Controls whether a port will be locked, meaning that hosts behind the + * port will not be able to communicate through the port unless an FDB + * entry with the unit's MAC address is in the FDB. The common use case is + * that hosts are allowed access through authentication with the IEEE 802.1X + * protocol or based on whitelists. By default this flag is off. + * + * Please note that secure 802.1X deployments should always use the + * *BR_BOOLOPT_NO_LL_LEARN* flag, to not permit the bridge to populate its + * FDB based on link-local (EAPOL) traffic received on the port. + * + * @IFLA_BRPORT_MAB + * Controls whether a port will use MAC Authentication Bypass (MAB), a + * technique through which select MAC addresses may be allowed on a locked + * port, without using 802.1X authentication. Packets with an unknown source + * MAC address generates a "locked" FDB entry on the incoming bridge port. + * The common use case is for user space to react to these bridge FDB + * notifications and optionally replace the locked FDB entry with a normal + * one, allowing traffic to pass for whitelisted MAC addresses. + * + * Setting this flag also requires *IFLA_BRPORT_LOCKED* and + * *IFLA_BRPORT_LEARNING*. *IFLA_BRPORT_LOCKED* ensures that unauthorized + * data packets are dropped, and *IFLA_BRPORT_LEARNING* allows the dynamic + * FDB entries installed by user space (as replacements for the locked FDB + * entries) to be refreshed and/or aged out. + * + * @IFLA_BRPORT_MCAST_N_GROUPS + * + * @IFLA_BRPORT_MCAST_MAX_GROUPS + * Sets the maximum number of MDB entries that can be registered for a + * given port. Attempts to register more MDB entries at the port than this + * limit allows will be rejected, whether they are done through netlink + * (e.g. the bridge tool), or IGMP or MLD membership reports. Setting a + * limit of 0 disables the limit. The default value is 0. + * + * @IFLA_BRPORT_NEIGH_VLAN_SUPPRESS + * Controls whether neighbor discovery (arp and nd) proxy and suppression is + * enabled for a given port. By default this flag is off. + * + * Note that this option only takes effect when *IFLA_BRPORT_NEIGH_SUPPRESS* + * is enabled for a given port. + * + * @IFLA_BRPORT_BACKUP_NHID + * The FDB nexthop object ID to attach to packets being redirected to a + * backup port that has VLAN tunnel mapping enabled (via the + * *IFLA_BRPORT_VLAN_TUNNEL* option). Setting a value of 0 (default) has + * the effect of not attaching any ID. + */ enum { IFLA_BRPORT_UNSPEC, IFLA_BRPORT_STATE, /* Spanning tree state */ @@ -769,6 +1293,19 @@ enum netkit_mode { NETKIT_L3, }; +/* NETKIT_SCRUB_NONE leaves clearing skb->{mark,priority} up to + * the BPF program if attached. This also means the latter can + * consume the two fields if they were populated earlier. + * + * NETKIT_SCRUB_DEFAULT zeroes skb->{mark,priority} fields before + * invoking the attached BPF program when the peer device resides + * in a different network namespace. This is the default behavior. + */ +enum netkit_scrub { + NETKIT_SCRUB_NONE, + NETKIT_SCRUB_DEFAULT, +}; + enum { IFLA_NETKIT_UNSPEC, IFLA_NETKIT_PEER_INFO, @@ -776,6 +1313,8 @@ enum { IFLA_NETKIT_POLICY, IFLA_NETKIT_PEER_POLICY, IFLA_NETKIT_MODE, + IFLA_NETKIT_SCRUB, + IFLA_NETKIT_PEER_SCRUB, __IFLA_NETKIT_MAX, }; #define IFLA_NETKIT_MAX (__IFLA_NETKIT_MAX - 1) @@ -854,6 +1393,7 @@ enum { IFLA_VXLAN_DF, IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */ IFLA_VXLAN_LOCALBYPASS, + IFLA_VXLAN_LABEL_POLICY, /* IPv6 flow label policy; ifla_vxlan_label_policy */ __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) @@ -871,6 +1411,13 @@ enum ifla_vxlan_df { VXLAN_DF_MAX = __VXLAN_DF_END - 1, }; +enum ifla_vxlan_label_policy { + VXLAN_LABEL_FIXED = 0, + VXLAN_LABEL_INHERIT = 1, + __VXLAN_LABEL_END, + VXLAN_LABEL_MAX = __VXLAN_LABEL_END - 1, +}; + /* GENEVE section */ enum { IFLA_GENEVE_UNSPEC, @@ -935,6 +1482,8 @@ enum { IFLA_GTP_ROLE, IFLA_GTP_CREATE_SOCKETS, IFLA_GTP_RESTART_COUNT, + IFLA_GTP_LOCAL, + IFLA_GTP_LOCAL6, __IFLA_GTP_MAX, }; #define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1) @@ -1240,6 +1789,7 @@ enum { IFLA_HSR_PROTOCOL, /* Indicate different protocol than * HSR. For example PRP. */ + IFLA_HSR_INTERLINK, /* HSR interlink network device */ __IFLA_HSR_MAX, }; @@ -1417,7 +1967,9 @@ enum { enum { IFLA_DSA_UNSPEC, - IFLA_DSA_MASTER, + IFLA_DSA_CONDUIT, + /* Deprecated, use IFLA_DSA_CONDUIT instead */ + IFLA_DSA_MASTER = IFLA_DSA_CONDUIT, __IFLA_DSA_MAX, }; diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 637efc05514534..502ea63b5d2e73 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -1158,7 +1158,15 @@ enum kvm_device_type { #define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_RISCV_AIA, #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA + KVM_DEV_TYPE_LOONGARCH_IPI, +#define KVM_DEV_TYPE_LOONGARCH_IPI KVM_DEV_TYPE_LOONGARCH_IPI + KVM_DEV_TYPE_LOONGARCH_EIOINTC, +#define KVM_DEV_TYPE_LOONGARCH_EIOINTC KVM_DEV_TYPE_LOONGARCH_EIOINTC + KVM_DEV_TYPE_LOONGARCH_PCHPIC, +#define KVM_DEV_TYPE_LOONGARCH_PCHPIC KVM_DEV_TYPE_LOONGARCH_PCHPIC + KVM_DEV_TYPE_MAX, + }; struct kvm_vfio_spapr_tce { diff --git a/tools/include/uapi/linux/netdev.h b/tools/include/uapi/linux/netdev.h index 7c308f04e7a063..e4be227d3ad648 100644 --- a/tools/include/uapi/linux/netdev.h +++ b/tools/include/uapi/linux/netdev.h @@ -122,6 +122,9 @@ enum { NETDEV_A_NAPI_ID, NETDEV_A_NAPI_IRQ, NETDEV_A_NAPI_PID, + NETDEV_A_NAPI_DEFER_HARD_IRQS, + NETDEV_A_NAPI_GRO_FLUSH_TIMEOUT, + NETDEV_A_NAPI_IRQ_SUSPEND_TIMEOUT, __NETDEV_A_NAPI_MAX, NETDEV_A_NAPI_MAX = (__NETDEV_A_NAPI_MAX - 1) @@ -199,6 +202,7 @@ enum { NETDEV_CMD_NAPI_GET, NETDEV_CMD_QSTATS_GET, NETDEV_CMD_BIND_RX, + NETDEV_CMD_NAPI_SET, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h index 4842c36fdf8019..0524d541d4e3d5 100644 --- a/tools/include/uapi/linux/perf_event.h +++ b/tools/include/uapi/linux/perf_event.h @@ -511,7 +511,16 @@ struct perf_event_attr { __u16 sample_max_stack; __u16 __reserved_2; __u32 aux_sample_size; - __u32 __reserved_3; + + union { + __u32 aux_action; + struct { + __u32 aux_start_paused : 1, /* start AUX area tracing paused */ + aux_pause : 1, /* on overflow, pause AUX area tracing */ + aux_resume : 1, /* on overflow, resume AUX area tracing */ + __reserved_3 : 29; + }; + }; /* * User provided data if sigtrap=1, passed back to user via diff --git a/tools/lib/api/io.h b/tools/lib/api/io.h index d3eb04d1bc8970..1731996b2c32ae 100644 --- a/tools/lib/api/io.h +++ b/tools/lib/api/io.h @@ -189,6 +189,7 @@ static inline ssize_t io__getdelim(struct io *io, char **line_out, size_t *line_ err_out: free(line); *line_out = NULL; + *line_len_out = 0; return -ENOMEM; } diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 1b22f0f372880e..857a5f7b413d6d 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -61,7 +61,8 @@ ifndef VERBOSE endif INCLUDES = -I$(or $(OUTPUT),.) \ - -I$(srctree)/tools/include -I$(srctree)/tools/include/uapi + -I$(srctree)/tools/include -I$(srctree)/tools/include/uapi \ + -I$(srctree)/tools/arch/$(SRCARCH)/include export prefix libdir src obj diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 2a4c71501a17db..becdfa701c7580 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -776,6 +776,7 @@ int bpf_link_create(int prog_fd, int target_fd, return libbpf_err(-EINVAL); break; case BPF_TRACE_UPROBE_MULTI: + case BPF_TRACE_UPROBE_SESSION: attr.link_create.uprobe_multi.flags = OPTS_GET(opts, uprobe_multi.flags, 0); attr.link_create.uprobe_multi.cnt = OPTS_GET(opts, uprobe_multi.cnt, 0); attr.link_create.uprobe_multi.path = ptr_to_u64(OPTS_GET(opts, uprobe_multi.path, 0)); diff --git a/tools/lib/bpf/bpf_gen_internal.h b/tools/lib/bpf/bpf_gen_internal.h index fdf44403ff3699..6ff963a491d972 100644 --- a/tools/lib/bpf/bpf_gen_internal.h +++ b/tools/lib/bpf/bpf_gen_internal.h @@ -34,6 +34,7 @@ struct bpf_gen { void *data_cur; void *insn_start; void *insn_cur; + bool swapped_endian; ssize_t cleanup_label; __u32 nr_progs; __u32 nr_maps; diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index 80bc0242e8dca9..686824b8b413bf 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -185,6 +185,7 @@ enum libbpf_tristate { #define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted"))) #define __kptr __attribute__((btf_type_tag("kptr"))) #define __percpu_kptr __attribute__((btf_type_tag("percpu_kptr"))) +#define __uptr __attribute__((btf_type_tag("uptr"))) #if defined (__clang__) #define bpf_ksym_exists(sym) ({ \ diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 3c131039c52326..12468ae0d573d7 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -22,6 +22,7 @@ #include "libbpf_internal.h" #include "hashmap.h" #include "strset.h" +#include "str_error.h" #define BTF_MAX_NR_TYPES 0x7fffffffU #define BTF_MAX_STR_OFFSET 0x7fffffffU @@ -1179,7 +1180,7 @@ static struct btf *btf_parse_elf(const char *path, struct btf *base_btf, fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { err = -errno; - pr_warn("failed to open %s: %s\n", path, strerror(errno)); + pr_warn("failed to open %s: %s\n", path, errstr(err)); return ERR_PTR(err); } @@ -1445,7 +1446,7 @@ int btf_load_into_kernel(struct btf *btf, goto retry_load; err = -errno; - pr_warn("BTF loading error: %d\n", err); + pr_warn("BTF loading error: %s\n", errstr(err)); /* don't print out contents of custom log_buf */ if (!log_buf && buf[0]) pr_warn("-- BEGIN BTF LOAD LOG ---\n%s\n-- END BTF LOAD LOG --\n", buf); @@ -2885,7 +2886,7 @@ int btf__add_decl_tag(struct btf *btf, const char *value, int ref_type_id, return btf_commit_type(btf, sz); } -struct btf_ext_sec_setup_param { +struct btf_ext_sec_info_param { __u32 off; __u32 len; __u32 min_rec_size; @@ -2893,14 +2894,20 @@ struct btf_ext_sec_setup_param { const char *desc; }; -static int btf_ext_setup_info(struct btf_ext *btf_ext, - struct btf_ext_sec_setup_param *ext_sec) +/* + * Parse a single info subsection of the BTF.ext info data: + * - validate subsection structure and elements + * - save info subsection start and sizing details in struct btf_ext + * - endian-independent operation, for calling before byte-swapping + */ +static int btf_ext_parse_sec_info(struct btf_ext *btf_ext, + struct btf_ext_sec_info_param *ext_sec, + bool is_native) { const struct btf_ext_info_sec *sinfo; struct btf_ext_info *ext_info; __u32 info_left, record_size; size_t sec_cnt = 0; - /* The start of the info sec (including the __u32 record_size). */ void *info; if (ext_sec->len == 0) @@ -2912,6 +2919,7 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext, return -EINVAL; } + /* The start of the info sec (including the __u32 record_size). */ info = btf_ext->data + btf_ext->hdr->hdr_len + ext_sec->off; info_left = ext_sec->len; @@ -2927,9 +2935,13 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext, return -EINVAL; } - /* The record size needs to meet the minimum standard */ - record_size = *(__u32 *)info; + /* The record size needs to meet either the minimum standard or, when + * handling non-native endianness data, the exact standard so as + * to allow safe byte-swapping. + */ + record_size = is_native ? *(__u32 *)info : bswap_32(*(__u32 *)info); if (record_size < ext_sec->min_rec_size || + (!is_native && record_size != ext_sec->min_rec_size) || record_size & 0x03) { pr_debug("%s section in .BTF.ext has invalid record size %u\n", ext_sec->desc, record_size); @@ -2941,7 +2953,7 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext, /* If no records, return failure now so .BTF.ext won't be used. */ if (!info_left) { - pr_debug("%s section in .BTF.ext has no records", ext_sec->desc); + pr_debug("%s section in .BTF.ext has no records\n", ext_sec->desc); return -EINVAL; } @@ -2956,7 +2968,7 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext, return -EINVAL; } - num_records = sinfo->num_info; + num_records = is_native ? sinfo->num_info : bswap_32(sinfo->num_info); if (num_records == 0) { pr_debug("%s section has incorrect num_records in .BTF.ext\n", ext_sec->desc); @@ -2984,64 +2996,157 @@ static int btf_ext_setup_info(struct btf_ext *btf_ext, return 0; } -static int btf_ext_setup_func_info(struct btf_ext *btf_ext) +/* Parse all info secs in the BTF.ext info data */ +static int btf_ext_parse_info(struct btf_ext *btf_ext, bool is_native) { - struct btf_ext_sec_setup_param param = { + struct btf_ext_sec_info_param func_info = { .off = btf_ext->hdr->func_info_off, .len = btf_ext->hdr->func_info_len, .min_rec_size = sizeof(struct bpf_func_info_min), .ext_info = &btf_ext->func_info, .desc = "func_info" }; - - return btf_ext_setup_info(btf_ext, ¶m); -} - -static int btf_ext_setup_line_info(struct btf_ext *btf_ext) -{ - struct btf_ext_sec_setup_param param = { + struct btf_ext_sec_info_param line_info = { .off = btf_ext->hdr->line_info_off, .len = btf_ext->hdr->line_info_len, .min_rec_size = sizeof(struct bpf_line_info_min), .ext_info = &btf_ext->line_info, .desc = "line_info", }; - - return btf_ext_setup_info(btf_ext, ¶m); -} - -static int btf_ext_setup_core_relos(struct btf_ext *btf_ext) -{ - struct btf_ext_sec_setup_param param = { + struct btf_ext_sec_info_param core_relo = { .off = btf_ext->hdr->core_relo_off, .len = btf_ext->hdr->core_relo_len, .min_rec_size = sizeof(struct bpf_core_relo), .ext_info = &btf_ext->core_relo_info, .desc = "core_relo", }; + int err; + + err = btf_ext_parse_sec_info(btf_ext, &func_info, is_native); + if (err) + return err; + + err = btf_ext_parse_sec_info(btf_ext, &line_info, is_native); + if (err) + return err; + + if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, core_relo_len)) + return 0; /* skip core relos parsing */ + + err = btf_ext_parse_sec_info(btf_ext, &core_relo, is_native); + if (err) + return err; + + return 0; +} + +/* Swap byte-order of BTF.ext header with any endianness */ +static void btf_ext_bswap_hdr(struct btf_ext_header *h) +{ + bool is_native = h->magic == BTF_MAGIC; + __u32 hdr_len; + + hdr_len = is_native ? h->hdr_len : bswap_32(h->hdr_len); + + h->magic = bswap_16(h->magic); + h->hdr_len = bswap_32(h->hdr_len); + h->func_info_off = bswap_32(h->func_info_off); + h->func_info_len = bswap_32(h->func_info_len); + h->line_info_off = bswap_32(h->line_info_off); + h->line_info_len = bswap_32(h->line_info_len); + + if (hdr_len < offsetofend(struct btf_ext_header, core_relo_len)) + return; + + h->core_relo_off = bswap_32(h->core_relo_off); + h->core_relo_len = bswap_32(h->core_relo_len); +} + +/* Swap byte-order of generic info subsection */ +static void btf_ext_bswap_info_sec(void *info, __u32 len, bool is_native, + info_rec_bswap_fn bswap_fn) +{ + struct btf_ext_info_sec *sec; + __u32 info_left, rec_size, *rs; + + if (len == 0) + return; + + rs = info; /* info record size */ + rec_size = is_native ? *rs : bswap_32(*rs); + *rs = bswap_32(*rs); + + sec = info + sizeof(__u32); /* info sec #1 */ + info_left = len - sizeof(__u32); + while (info_left) { + unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec); + __u32 i, num_recs; + void *p; + + num_recs = is_native ? sec->num_info : bswap_32(sec->num_info); + sec->sec_name_off = bswap_32(sec->sec_name_off); + sec->num_info = bswap_32(sec->num_info); + p = sec->data; /* info rec #1 */ + for (i = 0; i < num_recs; i++, p += rec_size) + bswap_fn(p); + sec = p; + info_left -= sec_hdrlen + (__u64)rec_size * num_recs; + } +} + +/* + * Swap byte-order of all info data in a BTF.ext section + * - requires BTF.ext hdr in native endianness + */ +static void btf_ext_bswap_info(struct btf_ext *btf_ext, void *data) +{ + const bool is_native = btf_ext->swapped_endian; + const struct btf_ext_header *h = data; + void *info; + + /* Swap func_info subsection byte-order */ + info = data + h->hdr_len + h->func_info_off; + btf_ext_bswap_info_sec(info, h->func_info_len, is_native, + (info_rec_bswap_fn)bpf_func_info_bswap); + + /* Swap line_info subsection byte-order */ + info = data + h->hdr_len + h->line_info_off; + btf_ext_bswap_info_sec(info, h->line_info_len, is_native, + (info_rec_bswap_fn)bpf_line_info_bswap); + + /* Swap core_relo subsection byte-order (if present) */ + if (h->hdr_len < offsetofend(struct btf_ext_header, core_relo_len)) + return; - return btf_ext_setup_info(btf_ext, ¶m); + info = data + h->hdr_len + h->core_relo_off; + btf_ext_bswap_info_sec(info, h->core_relo_len, is_native, + (info_rec_bswap_fn)bpf_core_relo_bswap); } -static int btf_ext_parse_hdr(__u8 *data, __u32 data_size) +/* Parse hdr data and info sections: check and convert to native endianness */ +static int btf_ext_parse(struct btf_ext *btf_ext) { - const struct btf_ext_header *hdr = (struct btf_ext_header *)data; + __u32 hdr_len, data_size = btf_ext->data_size; + struct btf_ext_header *hdr = btf_ext->hdr; + bool swapped_endian = false; + int err; - if (data_size < offsetofend(struct btf_ext_header, hdr_len) || - data_size < hdr->hdr_len) { - pr_debug("BTF.ext header not found"); + if (data_size < offsetofend(struct btf_ext_header, hdr_len)) { + pr_debug("BTF.ext header too short\n"); return -EINVAL; } + hdr_len = hdr->hdr_len; if (hdr->magic == bswap_16(BTF_MAGIC)) { - pr_warn("BTF.ext in non-native endianness is not supported\n"); - return -ENOTSUP; + swapped_endian = true; + hdr_len = bswap_32(hdr_len); } else if (hdr->magic != BTF_MAGIC) { pr_debug("Invalid BTF.ext magic:%x\n", hdr->magic); return -EINVAL; } - if (hdr->version != BTF_VERSION) { + /* Ensure known version of structs, current BTF_VERSION == 1 */ + if (hdr->version != 1) { pr_debug("Unsupported BTF.ext version:%u\n", hdr->version); return -ENOTSUP; } @@ -3051,11 +3156,39 @@ static int btf_ext_parse_hdr(__u8 *data, __u32 data_size) return -ENOTSUP; } - if (data_size == hdr->hdr_len) { + if (data_size < hdr_len) { + pr_debug("BTF.ext header not found\n"); + return -EINVAL; + } else if (data_size == hdr_len) { pr_debug("BTF.ext has no data\n"); return -EINVAL; } + /* Verify mandatory hdr info details present */ + if (hdr_len < offsetofend(struct btf_ext_header, line_info_len)) { + pr_warn("BTF.ext header missing func_info, line_info\n"); + return -EINVAL; + } + + /* Keep hdr native byte-order in memory for introspection */ + if (swapped_endian) + btf_ext_bswap_hdr(btf_ext->hdr); + + /* Validate info subsections and cache key metadata */ + err = btf_ext_parse_info(btf_ext, !swapped_endian); + if (err) + return err; + + /* Keep infos native byte-order in memory for introspection */ + if (swapped_endian) + btf_ext_bswap_info(btf_ext, btf_ext->data); + + /* + * Set btf_ext->swapped_endian only after all header and info data has + * been swapped, helping bswap functions determine if their data are + * in native byte-order when called. + */ + btf_ext->swapped_endian = swapped_endian; return 0; } @@ -3067,6 +3200,7 @@ void btf_ext__free(struct btf_ext *btf_ext) free(btf_ext->line_info.sec_idxs); free(btf_ext->core_relo_info.sec_idxs); free(btf_ext->data); + free(btf_ext->data_swapped); free(btf_ext); } @@ -3087,29 +3221,7 @@ struct btf_ext *btf_ext__new(const __u8 *data, __u32 size) } memcpy(btf_ext->data, data, size); - err = btf_ext_parse_hdr(btf_ext->data, size); - if (err) - goto done; - - if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, line_info_len)) { - err = -EINVAL; - goto done; - } - - err = btf_ext_setup_func_info(btf_ext); - if (err) - goto done; - - err = btf_ext_setup_line_info(btf_ext); - if (err) - goto done; - - if (btf_ext->hdr->hdr_len < offsetofend(struct btf_ext_header, core_relo_len)) - goto done; /* skip core relos parsing */ - - err = btf_ext_setup_core_relos(btf_ext); - if (err) - goto done; + err = btf_ext_parse(btf_ext); done: if (err) { @@ -3120,15 +3232,66 @@ struct btf_ext *btf_ext__new(const __u8 *data, __u32 size) return btf_ext; } +static void *btf_ext_raw_data(const struct btf_ext *btf_ext_ro, bool swap_endian) +{ + struct btf_ext *btf_ext = (struct btf_ext *)btf_ext_ro; + const __u32 data_sz = btf_ext->data_size; + void *data; + + /* Return native data (always present) or swapped data if present */ + if (!swap_endian) + return btf_ext->data; + else if (btf_ext->data_swapped) + return btf_ext->data_swapped; + + /* Recreate missing swapped data, then cache and return */ + data = calloc(1, data_sz); + if (!data) + return NULL; + memcpy(data, btf_ext->data, data_sz); + + btf_ext_bswap_info(btf_ext, data); + btf_ext_bswap_hdr(data); + btf_ext->data_swapped = data; + return data; +} + const void *btf_ext__raw_data(const struct btf_ext *btf_ext, __u32 *size) { + void *data; + + data = btf_ext_raw_data(btf_ext, btf_ext->swapped_endian); + if (!data) + return errno = ENOMEM, NULL; + *size = btf_ext->data_size; - return btf_ext->data; + return data; } __attribute__((alias("btf_ext__raw_data"))) const void *btf_ext__get_raw_data(const struct btf_ext *btf_ext, __u32 *size); +enum btf_endianness btf_ext__endianness(const struct btf_ext *btf_ext) +{ + if (is_host_big_endian()) + return btf_ext->swapped_endian ? BTF_LITTLE_ENDIAN : BTF_BIG_ENDIAN; + else + return btf_ext->swapped_endian ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN; +} + +int btf_ext__set_endianness(struct btf_ext *btf_ext, enum btf_endianness endian) +{ + if (endian != BTF_LITTLE_ENDIAN && endian != BTF_BIG_ENDIAN) + return libbpf_err(-EINVAL); + + btf_ext->swapped_endian = is_host_big_endian() != (endian == BTF_BIG_ENDIAN); + + if (!btf_ext->swapped_endian) { + free(btf_ext->data_swapped); + btf_ext->data_swapped = NULL; + } + return 0; +} struct btf_dedup; @@ -3291,7 +3454,7 @@ int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts) d = btf_dedup_new(btf, opts); if (IS_ERR(d)) { - pr_debug("btf_dedup_new failed: %ld", PTR_ERR(d)); + pr_debug("btf_dedup_new failed: %ld\n", PTR_ERR(d)); return libbpf_err(-EINVAL); } @@ -3302,42 +3465,42 @@ int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts) err = btf_dedup_prep(d); if (err) { - pr_debug("btf_dedup_prep failed:%d\n", err); + pr_debug("btf_dedup_prep failed: %s\n", errstr(err)); goto done; } err = btf_dedup_strings(d); if (err < 0) { - pr_debug("btf_dedup_strings failed:%d\n", err); + pr_debug("btf_dedup_strings failed: %s\n", errstr(err)); goto done; } err = btf_dedup_prim_types(d); if (err < 0) { - pr_debug("btf_dedup_prim_types failed:%d\n", err); + pr_debug("btf_dedup_prim_types failed: %s\n", errstr(err)); goto done; } err = btf_dedup_struct_types(d); if (err < 0) { - pr_debug("btf_dedup_struct_types failed:%d\n", err); + pr_debug("btf_dedup_struct_types failed: %s\n", errstr(err)); goto done; } err = btf_dedup_resolve_fwds(d); if (err < 0) { - pr_debug("btf_dedup_resolve_fwds failed:%d\n", err); + pr_debug("btf_dedup_resolve_fwds failed: %s\n", errstr(err)); goto done; } err = btf_dedup_ref_types(d); if (err < 0) { - pr_debug("btf_dedup_ref_types failed:%d\n", err); + pr_debug("btf_dedup_ref_types failed: %s\n", errstr(err)); goto done; } err = btf_dedup_compact_types(d); if (err < 0) { - pr_debug("btf_dedup_compact_types failed:%d\n", err); + pr_debug("btf_dedup_compact_types failed: %s\n", errstr(err)); goto done; } err = btf_dedup_remap_types(d); if (err < 0) { - pr_debug("btf_dedup_remap_types failed:%d\n", err); + pr_debug("btf_dedup_remap_types failed: %s\n", errstr(err)); goto done; } @@ -3385,7 +3548,7 @@ struct btf_dedup { struct strset *strs_set; }; -static long hash_combine(long h, long value) +static unsigned long hash_combine(unsigned long h, unsigned long value) { return h * 31 + value; } @@ -5056,7 +5219,8 @@ struct btf *btf__load_vmlinux_btf(void) btf = btf__parse(sysfs_btf_path, NULL); if (!btf) { err = -errno; - pr_warn("failed to read kernel BTF from '%s': %d\n", sysfs_btf_path, err); + pr_warn("failed to read kernel BTF from '%s': %s\n", + sysfs_btf_path, errstr(err)); return libbpf_err_ptr(err); } pr_debug("loaded kernel BTF from '%s'\n", sysfs_btf_path); @@ -5073,7 +5237,7 @@ struct btf *btf__load_vmlinux_btf(void) btf = btf__parse(path, NULL); err = libbpf_get_error(btf); - pr_debug("loading kernel BTF '%s': %d\n", path, err); + pr_debug("loading kernel BTF '%s': %s\n", path, errstr(err)); if (err) continue; diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 4e349ad79ee699..47ee8f6ac48961 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -167,6 +167,9 @@ LIBBPF_API const char *btf__str_by_offset(const struct btf *btf, __u32 offset); LIBBPF_API struct btf_ext *btf_ext__new(const __u8 *data, __u32 size); LIBBPF_API void btf_ext__free(struct btf_ext *btf_ext); LIBBPF_API const void *btf_ext__raw_data(const struct btf_ext *btf_ext, __u32 *size); +LIBBPF_API enum btf_endianness btf_ext__endianness(const struct btf_ext *btf_ext); +LIBBPF_API int btf_ext__set_endianness(struct btf_ext *btf_ext, + enum btf_endianness endian); LIBBPF_API int btf__find_str(struct btf *btf, const char *s); LIBBPF_API int btf__add_str(struct btf *btf, const char *s); diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index 0a7327541c17f1..a3fc6908f6c936 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -21,6 +21,7 @@ #include "hashmap.h" #include "libbpf.h" #include "libbpf_internal.h" +#include "str_error.h" static const char PREFIXES[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t"; static const size_t PREFIX_CNT = sizeof(PREFIXES) - 1; @@ -867,8 +868,8 @@ static void btf_dump_emit_bit_padding(const struct btf_dump *d, } pads[] = { {"long", d->ptr_sz * 8}, {"int", 32}, {"short", 16}, {"char", 8} }; - int new_off, pad_bits, bits, i; - const char *pad_type; + int new_off = 0, pad_bits = 0, bits, i; + const char *pad_type = NULL; if (cur_off >= next_off) return; /* no gap */ @@ -1304,7 +1305,7 @@ static void btf_dump_emit_type_decl(struct btf_dump *d, __u32 id, * chain, restore stack, emit warning, and try to * proceed nevertheless */ - pr_warn("not enough memory for decl stack:%d", err); + pr_warn("not enough memory for decl stack: %s\n", errstr(err)); d->decl_stack_cnt = stack_start; return; } diff --git a/tools/lib/bpf/btf_relocate.c b/tools/lib/bpf/btf_relocate.c index 4f7399d85eab3d..b72f83e15156a6 100644 --- a/tools/lib/bpf/btf_relocate.c +++ b/tools/lib/bpf/btf_relocate.c @@ -428,7 +428,7 @@ static int btf_relocate_rewrite_strs(struct btf_relocate *r, __u32 i) } else { off = r->str_map[*str_off]; if (!off) { - pr_warn("string '%s' [offset %u] is not mapped to base BTF", + pr_warn("string '%s' [offset %u] is not mapped to base BTF\n", btf__str_by_offset(r->btf, off), *str_off); return -ENOENT; } diff --git a/tools/lib/bpf/elf.c b/tools/lib/bpf/elf.c index b5ab1cb13e5ea0..823f83ad819c8e 100644 --- a/tools/lib/bpf/elf.c +++ b/tools/lib/bpf/elf.c @@ -24,7 +24,6 @@ int elf_open(const char *binary_path, struct elf_fd *elf_fd) { - char errmsg[STRERR_BUFSIZE]; int fd, ret; Elf *elf; @@ -38,8 +37,7 @@ int elf_open(const char *binary_path, struct elf_fd *elf_fd) fd = open(binary_path, O_RDONLY | O_CLOEXEC); if (fd < 0) { ret = -errno; - pr_warn("elf: failed to open %s: %s\n", binary_path, - libbpf_strerror_r(ret, errmsg, sizeof(errmsg))); + pr_warn("elf: failed to open %s: %s\n", binary_path, errstr(ret)); return ret; } elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); diff --git a/tools/lib/bpf/features.c b/tools/lib/bpf/features.c index 50befe125ddc55..760657f5224c2a 100644 --- a/tools/lib/bpf/features.c +++ b/tools/lib/bpf/features.c @@ -47,7 +47,6 @@ static int probe_kern_prog_name(int token_fd) static int probe_kern_global_data(int token_fd) { - char *cp, errmsg[STRERR_BUFSIZE]; struct bpf_insn insns[] = { BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16), BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42), @@ -67,9 +66,8 @@ static int probe_kern_global_data(int token_fd) map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, &map_opts); if (map < 0) { ret = -errno; - cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); - pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", - __func__, cp, -ret); + pr_warn("Error in %s(): %s. Couldn't create simple array map.\n", + __func__, errstr(ret)); return ret; } @@ -267,7 +265,6 @@ static int probe_kern_probe_read_kernel(int token_fd) static int probe_prog_bind_map(int token_fd) { - char *cp, errmsg[STRERR_BUFSIZE]; struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), @@ -285,9 +282,8 @@ static int probe_prog_bind_map(int token_fd) map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, &map_opts); if (map < 0) { ret = -errno; - cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); - pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", - __func__, cp, -ret); + pr_warn("Error in %s(): %s. Couldn't create simple array map.\n", + __func__, errstr(ret)); return ret; } @@ -604,7 +600,8 @@ bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_ } else if (ret == 0) { WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); } else { - pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret); + pr_warn("Detection of kernel %s support failed: %s\n", + feat->desc, errstr(ret)); WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); } } diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c index cf3323fd47b886..113ae4abd345f2 100644 --- a/tools/lib/bpf/gen_loader.c +++ b/tools/lib/bpf/gen_loader.c @@ -14,6 +14,7 @@ #include "bpf_gen_internal.h" #include "skel_internal.h" #include +#include "str_error.h" #define MAX_USED_MAPS 64 #define MAX_USED_PROGS 32 @@ -393,7 +394,7 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps) blob_fd_array_off(gen, i)); emit(gen, BPF_MOV64_IMM(BPF_REG_0, 0)); emit(gen, BPF_EXIT_INSN()); - pr_debug("gen: finish %d\n", gen->error); + pr_debug("gen: finish %s\n", errstr(gen->error)); if (!gen->error) { struct gen_loader_opts *opts = gen->opts; @@ -401,6 +402,15 @@ int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps) opts->insns_sz = gen->insn_cur - gen->insn_start; opts->data = gen->data_start; opts->data_sz = gen->data_cur - gen->data_start; + + /* use target endianness for embedded loader */ + if (gen->swapped_endian) { + struct bpf_insn *insn = (struct bpf_insn *)opts->insns; + int insn_cnt = opts->insns_sz / sizeof(struct bpf_insn); + + for (i = 0; i < insn_cnt; i++) + bpf_insn_bswap(insn++); + } } return gen->error; } @@ -414,6 +424,28 @@ void bpf_gen__free(struct bpf_gen *gen) free(gen); } +/* + * Fields of bpf_attr are set to values in native byte-order before being + * written to the target-bound data blob, and may need endian conversion. + * This macro allows providing the correct value in situ more simply than + * writing a separate converter for *all fields* of *all records* included + * in union bpf_attr. Note that sizeof(rval) should match the assignment + * target to avoid runtime problems. + */ +#define tgt_endian(rval) ({ \ + typeof(rval) _val = (rval); \ + if (gen->swapped_endian) { \ + switch (sizeof(_val)) { \ + case 1: break; \ + case 2: _val = bswap_16(_val); break; \ + case 4: _val = bswap_32(_val); break; \ + case 8: _val = bswap_64(_val); break; \ + default: pr_warn("unsupported bswap size!\n"); \ + } \ + } \ + _val; \ +}) + void bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data, __u32 btf_raw_size) { @@ -422,11 +454,12 @@ void bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data, union bpf_attr attr; memset(&attr, 0, attr_size); - pr_debug("gen: load_btf: size %d\n", btf_raw_size); btf_data = add_data(gen, btf_raw_data, btf_raw_size); - attr.btf_size = btf_raw_size; + attr.btf_size = tgt_endian(btf_raw_size); btf_load_attr = add_data(gen, &attr, attr_size); + pr_debug("gen: load_btf: off %d size %d, attr: off %d size %d\n", + btf_data, btf_raw_size, btf_load_attr, attr_size); /* populate union bpf_attr with user provided log details */ move_ctx2blob(gen, attr_field(btf_load_attr, btf_log_level), 4, @@ -457,28 +490,29 @@ void bpf_gen__map_create(struct bpf_gen *gen, union bpf_attr attr; memset(&attr, 0, attr_size); - attr.map_type = map_type; - attr.key_size = key_size; - attr.value_size = value_size; - attr.map_flags = map_attr->map_flags; - attr.map_extra = map_attr->map_extra; + attr.map_type = tgt_endian(map_type); + attr.key_size = tgt_endian(key_size); + attr.value_size = tgt_endian(value_size); + attr.map_flags = tgt_endian(map_attr->map_flags); + attr.map_extra = tgt_endian(map_attr->map_extra); if (map_name) libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name)); - attr.numa_node = map_attr->numa_node; - attr.map_ifindex = map_attr->map_ifindex; - attr.max_entries = max_entries; - attr.btf_key_type_id = map_attr->btf_key_type_id; - attr.btf_value_type_id = map_attr->btf_value_type_id; - - pr_debug("gen: map_create: %s idx %d type %d value_type_id %d\n", - attr.map_name, map_idx, map_type, attr.btf_value_type_id); + attr.numa_node = tgt_endian(map_attr->numa_node); + attr.map_ifindex = tgt_endian(map_attr->map_ifindex); + attr.max_entries = tgt_endian(max_entries); + attr.btf_key_type_id = tgt_endian(map_attr->btf_key_type_id); + attr.btf_value_type_id = tgt_endian(map_attr->btf_value_type_id); map_create_attr = add_data(gen, &attr, attr_size); - if (attr.btf_value_type_id) + pr_debug("gen: map_create: %s idx %d type %d value_type_id %d, attr: off %d size %d\n", + map_name, map_idx, map_type, map_attr->btf_value_type_id, + map_create_attr, attr_size); + + if (map_attr->btf_value_type_id) /* populate union bpf_attr with btf_fd saved in the stack earlier */ move_stack2blob(gen, attr_field(map_create_attr, btf_fd), 4, stack_off(btf_fd)); - switch (attr.map_type) { + switch (map_type) { case BPF_MAP_TYPE_ARRAY_OF_MAPS: case BPF_MAP_TYPE_HASH_OF_MAPS: move_stack2blob(gen, attr_field(map_create_attr, inner_map_fd), 4, @@ -498,8 +532,8 @@ void bpf_gen__map_create(struct bpf_gen *gen, /* emit MAP_CREATE command */ emit_sys_bpf(gen, BPF_MAP_CREATE, map_create_attr, attr_size); debug_ret(gen, "map_create %s idx %d type %d value_size %d value_btf_id %d", - attr.map_name, map_idx, map_type, value_size, - attr.btf_value_type_id); + map_name, map_idx, map_type, value_size, + map_attr->btf_value_type_id); emit_check_err(gen); /* remember map_fd in the stack, if successful */ if (map_idx < 0) { @@ -784,12 +818,12 @@ static void emit_relo_ksym_typeless(struct bpf_gen *gen, emit_ksym_relo_log(gen, relo, kdesc->ref); } -static __u32 src_reg_mask(void) +static __u32 src_reg_mask(struct bpf_gen *gen) { -#if defined(__LITTLE_ENDIAN_BITFIELD) - return 0x0f; /* src_reg,dst_reg,... */ -#elif defined(__BIG_ENDIAN_BITFIELD) - return 0xf0; /* dst_reg,src_reg,... */ +#if defined(__LITTLE_ENDIAN_BITFIELD) /* src_reg,dst_reg,... */ + return gen->swapped_endian ? 0xf0 : 0x0f; +#elif defined(__BIG_ENDIAN_BITFIELD) /* dst_reg,src_reg,... */ + return gen->swapped_endian ? 0x0f : 0xf0; #else #error "Unsupported bit endianness, cannot proceed" #endif @@ -840,7 +874,7 @@ static void emit_relo_ksym_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo, emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 3)); clear_src_reg: /* clear bpf_object__relocate_data's src_reg assignment, otherwise we get a verifier failure */ - reg_mask = src_reg_mask(); + reg_mask = src_reg_mask(gen); emit(gen, BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_8, offsetofend(struct bpf_insn, code))); emit(gen, BPF_ALU32_IMM(BPF_AND, BPF_REG_9, reg_mask)); emit(gen, BPF_STX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, offsetofend(struct bpf_insn, code))); @@ -931,48 +965,94 @@ static void cleanup_relos(struct bpf_gen *gen, int insns) cleanup_core_relo(gen); } +/* Convert func, line, and core relo info blobs to target endianness */ +static void info_blob_bswap(struct bpf_gen *gen, int func_info, int line_info, + int core_relos, struct bpf_prog_load_opts *load_attr) +{ + struct bpf_func_info *fi = gen->data_start + func_info; + struct bpf_line_info *li = gen->data_start + line_info; + struct bpf_core_relo *cr = gen->data_start + core_relos; + int i; + + for (i = 0; i < load_attr->func_info_cnt; i++) + bpf_func_info_bswap(fi++); + + for (i = 0; i < load_attr->line_info_cnt; i++) + bpf_line_info_bswap(li++); + + for (i = 0; i < gen->core_relo_cnt; i++) + bpf_core_relo_bswap(cr++); +} + void bpf_gen__prog_load(struct bpf_gen *gen, enum bpf_prog_type prog_type, const char *prog_name, const char *license, struct bpf_insn *insns, size_t insn_cnt, struct bpf_prog_load_opts *load_attr, int prog_idx) { + int func_info_tot_sz = load_attr->func_info_cnt * + load_attr->func_info_rec_size; + int line_info_tot_sz = load_attr->line_info_cnt * + load_attr->line_info_rec_size; + int core_relo_tot_sz = gen->core_relo_cnt * + sizeof(struct bpf_core_relo); int prog_load_attr, license_off, insns_off, func_info, line_info, core_relos; int attr_size = offsetofend(union bpf_attr, core_relo_rec_size); union bpf_attr attr; memset(&attr, 0, attr_size); - pr_debug("gen: prog_load: type %d insns_cnt %zd progi_idx %d\n", - prog_type, insn_cnt, prog_idx); /* add license string to blob of bytes */ license_off = add_data(gen, license, strlen(license) + 1); /* add insns to blob of bytes */ insns_off = add_data(gen, insns, insn_cnt * sizeof(struct bpf_insn)); + pr_debug("gen: prog_load: prog_idx %d type %d insn off %d insns_cnt %zd license off %d\n", + prog_idx, prog_type, insns_off, insn_cnt, license_off); - attr.prog_type = prog_type; - attr.expected_attach_type = load_attr->expected_attach_type; - attr.attach_btf_id = load_attr->attach_btf_id; - attr.prog_ifindex = load_attr->prog_ifindex; - attr.kern_version = 0; - attr.insn_cnt = (__u32)insn_cnt; - attr.prog_flags = load_attr->prog_flags; - - attr.func_info_rec_size = load_attr->func_info_rec_size; - attr.func_info_cnt = load_attr->func_info_cnt; - func_info = add_data(gen, load_attr->func_info, - attr.func_info_cnt * attr.func_info_rec_size); + /* convert blob insns to target endianness */ + if (gen->swapped_endian) { + struct bpf_insn *insn = gen->data_start + insns_off; + int i; - attr.line_info_rec_size = load_attr->line_info_rec_size; - attr.line_info_cnt = load_attr->line_info_cnt; - line_info = add_data(gen, load_attr->line_info, - attr.line_info_cnt * attr.line_info_rec_size); + for (i = 0; i < insn_cnt; i++, insn++) + bpf_insn_bswap(insn); + } - attr.core_relo_rec_size = sizeof(struct bpf_core_relo); - attr.core_relo_cnt = gen->core_relo_cnt; - core_relos = add_data(gen, gen->core_relos, - attr.core_relo_cnt * attr.core_relo_rec_size); + attr.prog_type = tgt_endian(prog_type); + attr.expected_attach_type = tgt_endian(load_attr->expected_attach_type); + attr.attach_btf_id = tgt_endian(load_attr->attach_btf_id); + attr.prog_ifindex = tgt_endian(load_attr->prog_ifindex); + attr.kern_version = 0; + attr.insn_cnt = tgt_endian((__u32)insn_cnt); + attr.prog_flags = tgt_endian(load_attr->prog_flags); + + attr.func_info_rec_size = tgt_endian(load_attr->func_info_rec_size); + attr.func_info_cnt = tgt_endian(load_attr->func_info_cnt); + func_info = add_data(gen, load_attr->func_info, func_info_tot_sz); + pr_debug("gen: prog_load: func_info: off %d cnt %d rec size %d\n", + func_info, load_attr->func_info_cnt, + load_attr->func_info_rec_size); + + attr.line_info_rec_size = tgt_endian(load_attr->line_info_rec_size); + attr.line_info_cnt = tgt_endian(load_attr->line_info_cnt); + line_info = add_data(gen, load_attr->line_info, line_info_tot_sz); + pr_debug("gen: prog_load: line_info: off %d cnt %d rec size %d\n", + line_info, load_attr->line_info_cnt, + load_attr->line_info_rec_size); + + attr.core_relo_rec_size = tgt_endian((__u32)sizeof(struct bpf_core_relo)); + attr.core_relo_cnt = tgt_endian(gen->core_relo_cnt); + core_relos = add_data(gen, gen->core_relos, core_relo_tot_sz); + pr_debug("gen: prog_load: core_relos: off %d cnt %d rec size %zd\n", + core_relos, gen->core_relo_cnt, + sizeof(struct bpf_core_relo)); + + /* convert all info blobs to target endianness */ + if (gen->swapped_endian) + info_blob_bswap(gen, func_info, line_info, core_relos, load_attr); libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name)); prog_load_attr = add_data(gen, &attr, attr_size); + pr_debug("gen: prog_load: attr: off %d size %d\n", + prog_load_attr, attr_size); /* populate union bpf_attr with a pointer to license */ emit_rel_store(gen, attr_field(prog_load_attr, license), license_off); @@ -1040,7 +1120,6 @@ void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *pvalue, int zero = 0; memset(&attr, 0, attr_size); - pr_debug("gen: map_update_elem: idx %d\n", map_idx); value = add_data(gen, pvalue, value_size); key = add_data(gen, &zero, sizeof(zero)); @@ -1068,6 +1147,8 @@ void bpf_gen__map_update_elem(struct bpf_gen *gen, int map_idx, void *pvalue, emit(gen, BPF_EMIT_CALL(BPF_FUNC_probe_read_kernel)); map_update_attr = add_data(gen, &attr, attr_size); + pr_debug("gen: map_update_elem: idx %d, value: off %d size %d, attr: off %d size %d\n", + map_idx, value, value_size, map_update_attr, attr_size); move_blob2blob(gen, attr_field(map_update_attr, map_fd), 4, blob_fd_array_off(gen, map_idx)); emit_rel_store(gen, attr_field(map_update_attr, key), key); @@ -1084,14 +1165,16 @@ void bpf_gen__populate_outer_map(struct bpf_gen *gen, int outer_map_idx, int slo int attr_size = offsetofend(union bpf_attr, flags); int map_update_attr, key; union bpf_attr attr; + int tgt_slot; memset(&attr, 0, attr_size); - pr_debug("gen: populate_outer_map: outer %d key %d inner %d\n", - outer_map_idx, slot, inner_map_idx); - key = add_data(gen, &slot, sizeof(slot)); + tgt_slot = tgt_endian(slot); + key = add_data(gen, &tgt_slot, sizeof(tgt_slot)); map_update_attr = add_data(gen, &attr, attr_size); + pr_debug("gen: populate_outer_map: outer %d key %d inner %d, attr: off %d size %d\n", + outer_map_idx, slot, inner_map_idx, map_update_attr, attr_size); move_blob2blob(gen, attr_field(map_update_attr, map_fd), 4, blob_fd_array_off(gen, outer_map_idx)); emit_rel_store(gen, attr_field(map_update_attr, key), key); @@ -1112,8 +1195,9 @@ void bpf_gen__map_freeze(struct bpf_gen *gen, int map_idx) union bpf_attr attr; memset(&attr, 0, attr_size); - pr_debug("gen: map_freeze: idx %d\n", map_idx); map_freeze_attr = add_data(gen, &attr, attr_size); + pr_debug("gen: map_freeze: idx %d, attr: off %d size %d\n", + map_idx, map_freeze_attr, attr_size); move_blob2blob(gen, attr_field(map_freeze_attr, map_fd), 4, blob_fd_array_off(gen, map_idx)); /* emit MAP_FREEZE command */ diff --git a/tools/lib/bpf/hashmap.h b/tools/lib/bpf/hashmap.h index c12f8320e6682d..0c4f155e8eb745 100644 --- a/tools/lib/bpf/hashmap.h +++ b/tools/lib/bpf/hashmap.h @@ -166,8 +166,8 @@ bool hashmap_find(const struct hashmap *map, long key, long *value); * @bkt: integer used as a bucket loop cursor */ #define hashmap__for_each_entry(map, cur, bkt) \ - for (bkt = 0; bkt < map->cap; bkt++) \ - for (cur = map->buckets[bkt]; cur; cur = cur->next) + for (bkt = 0; bkt < (map)->cap; bkt++) \ + for (cur = (map)->buckets[bkt]; cur; cur = cur->next) /* * hashmap__for_each_entry_safe - iterate over all entries in hashmap, safe @@ -178,8 +178,8 @@ bool hashmap_find(const struct hashmap *map, long key, long *value); * @bkt: integer used as a bucket loop cursor */ #define hashmap__for_each_entry_safe(map, cur, tmp, bkt) \ - for (bkt = 0; bkt < map->cap; bkt++) \ - for (cur = map->buckets[bkt]; \ + for (bkt = 0; bkt < (map)->cap; bkt++) \ + for (cur = (map)->buckets[bkt]; \ cur && ({tmp = cur->next; true; }); \ cur = tmp) @@ -190,19 +190,19 @@ bool hashmap_find(const struct hashmap *map, long key, long *value); * @key: key to iterate entries for */ #define hashmap__for_each_key_entry(map, cur, _key) \ - for (cur = map->buckets \ - ? map->buckets[hash_bits(map->hash_fn((_key), map->ctx), map->cap_bits)] \ + for (cur = (map)->buckets \ + ? (map)->buckets[hash_bits((map)->hash_fn((_key), (map)->ctx), (map)->cap_bits)] \ : NULL; \ cur; \ cur = cur->next) \ - if (map->equal_fn(cur->key, (_key), map->ctx)) + if ((map)->equal_fn(cur->key, (_key), (map)->ctx)) #define hashmap__for_each_key_entry_safe(map, cur, tmp, _key) \ - for (cur = map->buckets \ - ? map->buckets[hash_bits(map->hash_fn((_key), map->ctx), map->cap_bits)] \ + for (cur = (map)->buckets \ + ? (map)->buckets[hash_bits((map)->hash_fn((_key), (map)->ctx), (map)->cap_bits)] \ : NULL; \ cur && ({ tmp = cur->next; true; }); \ cur = tmp) \ - if (map->equal_fn(cur->key, (_key), map->ctx)) + if ((map)->equal_fn(cur->key, (_key), (map)->ctx)) #endif /* __LIBBPF_HASHMAP_H */ diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 219facd0e66e8b..66173ddb5a2df3 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -133,6 +133,7 @@ static const char * const attach_type_name[] = { [BPF_NETKIT_PRIMARY] = "netkit_primary", [BPF_NETKIT_PEER] = "netkit_peer", [BPF_TRACE_KPROBE_SESSION] = "trace_kprobe_session", + [BPF_TRACE_UPROBE_SESSION] = "trace_uprobe_session", }; static const char * const link_type_name[] = { @@ -694,6 +695,8 @@ struct bpf_object { /* Information when doing ELF related work. Only valid if efile.elf is not NULL */ struct elf_state efile; + unsigned char byteorder; + struct btf *btf; struct btf_ext *btf_ext; @@ -940,6 +943,20 @@ bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data, return 0; } +static void bpf_object_bswap_progs(struct bpf_object *obj) +{ + struct bpf_program *prog = obj->programs; + struct bpf_insn *insn; + int p, i; + + for (p = 0; p < obj->nr_programs; p++, prog++) { + insn = prog->insns; + for (i = 0; i < prog->insns_cnt; i++, insn++) + bpf_insn_bswap(insn); + } + pr_debug("converted %zu BPF programs to native byte order\n", obj->nr_programs); +} + static const struct btf_member * find_member_by_offset(const struct btf_type *t, __u32 bit_offset) { @@ -1506,6 +1523,7 @@ static void bpf_object__elf_finish(struct bpf_object *obj) elf_end(obj->efile.elf); obj->efile.elf = NULL; + obj->efile.ehdr = NULL; obj->efile.symbols = NULL; obj->efile.arena_data = NULL; @@ -1533,11 +1551,8 @@ static int bpf_object__elf_init(struct bpf_object *obj) } else { obj->efile.fd = open(obj->path, O_RDONLY | O_CLOEXEC); if (obj->efile.fd < 0) { - char errmsg[STRERR_BUFSIZE], *cp; - err = -errno; - cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); - pr_warn("elf: failed to open %s: %s\n", obj->path, cp); + pr_warn("elf: failed to open %s: %s\n", obj->path, errstr(err)); return err; } @@ -1571,6 +1586,16 @@ static int bpf_object__elf_init(struct bpf_object *obj) goto errout; } + /* Validate ELF object endianness... */ + if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB && + ehdr->e_ident[EI_DATA] != ELFDATA2MSB) { + err = -LIBBPF_ERRNO__ENDIAN; + pr_warn("elf: '%s' has unknown byte order\n", obj->path); + goto errout; + } + /* and save after bpf_object_open() frees ELF data */ + obj->byteorder = ehdr->e_ident[EI_DATA]; + if (elf_getshdrstrndx(elf, &obj->efile.shstrndx)) { pr_warn("elf: failed to get section names section index for %s: %s\n", obj->path, elf_errmsg(-1)); @@ -1599,19 +1624,15 @@ static int bpf_object__elf_init(struct bpf_object *obj) return err; } -static int bpf_object__check_endianness(struct bpf_object *obj) +static bool is_native_endianness(struct bpf_object *obj) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - if (obj->efile.ehdr->e_ident[EI_DATA] == ELFDATA2LSB) - return 0; + return obj->byteorder == ELFDATA2LSB; #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - if (obj->efile.ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - return 0; + return obj->byteorder == ELFDATA2MSB; #else # error "Unrecognized __BYTE_ORDER__" #endif - pr_warn("elf: endianness mismatch in %s.\n", obj->path); - return -LIBBPF_ERRNO__ENDIAN; } static int @@ -1937,8 +1958,7 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, if (map->mmaped == MAP_FAILED) { err = -errno; map->mmaped = NULL; - pr_warn("failed to alloc map '%s' content buffer: %d\n", - map->name, err); + pr_warn("failed to alloc map '%s' content buffer: %s\n", map->name, errstr(err)); zfree(&map->real_name); zfree(&map->name); return err; @@ -2102,7 +2122,7 @@ static int parse_u64(const char *value, __u64 *res) *res = strtoull(value, &value_end, 0); if (errno) { err = -errno; - pr_warn("failed to parse '%s' as integer: %d\n", value, err); + pr_warn("failed to parse '%s': %s\n", value, errstr(err)); return err; } if (*value_end) { @@ -2268,8 +2288,8 @@ static int bpf_object__read_kconfig_file(struct bpf_object *obj, void *data) while (gzgets(file, buf, sizeof(buf))) { err = bpf_object__process_kconfig_line(obj, buf, data); if (err) { - pr_warn("error parsing system Kconfig line '%s': %d\n", - buf, err); + pr_warn("error parsing system Kconfig line '%s': %s\n", + buf, errstr(err)); goto out; } } @@ -2289,15 +2309,15 @@ static int bpf_object__read_kconfig_mem(struct bpf_object *obj, file = fmemopen((void *)config, strlen(config), "r"); if (!file) { err = -errno; - pr_warn("failed to open in-memory Kconfig: %d\n", err); + pr_warn("failed to open in-memory Kconfig: %s\n", errstr(err)); return err; } while (fgets(buf, sizeof(buf), file)) { err = bpf_object__process_kconfig_line(obj, buf, data); if (err) { - pr_warn("error parsing in-memory Kconfig line '%s': %d\n", - buf, err); + pr_warn("error parsing in-memory Kconfig line '%s': %s\n", + buf, errstr(err)); break; } } @@ -3212,7 +3232,7 @@ static int bpf_object__init_btf(struct bpf_object *obj, err = libbpf_get_error(obj->btf); if (err) { obj->btf = NULL; - pr_warn("Error loading ELF section %s: %d.\n", BTF_ELF_SEC, err); + pr_warn("Error loading ELF section %s: %s.\n", BTF_ELF_SEC, errstr(err)); goto out; } /* enforce 8-byte pointers for BPF-targeted BTFs */ @@ -3230,8 +3250,8 @@ static int bpf_object__init_btf(struct bpf_object *obj, obj->btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size); err = libbpf_get_error(obj->btf_ext); if (err) { - pr_warn("Error loading ELF section %s: %d. Ignored and continue.\n", - BTF_EXT_ELF_SEC, err); + pr_warn("Error loading ELF section %s: %s. Ignored and continue.\n", + BTF_EXT_ELF_SEC, errstr(err)); obj->btf_ext = NULL; goto out; } @@ -3323,8 +3343,8 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf, if (t->size == 0) { err = find_elf_sec_sz(obj, sec_name, &size); if (err || !size) { - pr_debug("sec '%s': failed to determine size from ELF: size %u, err %d\n", - sec_name, size, err); + pr_debug("sec '%s': failed to determine size from ELF: size %u, err %s\n", + sec_name, size, errstr(err)); return -ENOENT; } @@ -3478,7 +3498,7 @@ static int bpf_object__load_vmlinux_btf(struct bpf_object *obj, bool force) obj->btf_vmlinux = btf__load_vmlinux_btf(); err = libbpf_get_error(obj->btf_vmlinux); if (err) { - pr_warn("Error loading vmlinux BTF: %d\n", err); + pr_warn("Error loading vmlinux BTF: %s\n", errstr(err)); obj->btf_vmlinux = NULL; return err; } @@ -3581,11 +3601,14 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj) report: if (err) { btf_mandatory = kernel_needs_btf(obj); - pr_warn("Error loading .BTF into kernel: %d. %s\n", err, - btf_mandatory ? "BTF is mandatory, can't proceed." - : "BTF is optional, ignoring."); - if (!btf_mandatory) + if (btf_mandatory) { + pr_warn("Error loading .BTF into kernel: %s. BTF is mandatory, can't proceed.\n", + errstr(err)); + } else { + pr_info("Error loading .BTF into kernel: %s. BTF is optional, ignoring.\n", + errstr(err)); err = 0; + } } return err; } @@ -3953,6 +3976,10 @@ static int bpf_object__elf_collect(struct bpf_object *obj) return -LIBBPF_ERRNO__FORMAT; } + /* change BPF program insns to native endianness for introspection */ + if (!is_native_endianness(obj)) + bpf_object_bswap_progs(obj); + /* sort BPF programs by section name and in-section instruction offset * for faster search */ @@ -3985,7 +4012,7 @@ static bool sym_is_subprog(const Elf64_Sym *sym, int text_shndx) return true; /* global function */ - return bind == STB_GLOBAL && type == STT_FUNC; + return (bind == STB_GLOBAL || bind == STB_WEAK) && type == STT_FUNC; } static int find_extern_btf_id(const struct btf *btf, const char *ext_name) @@ -4389,7 +4416,7 @@ static int bpf_object__collect_externs(struct bpf_object *obj) static bool prog_is_subprog(const struct bpf_object *obj, const struct bpf_program *prog) { - return prog->sec_idx == obj->efile.text_shndx && obj->nr_programs > 1; + return prog->sec_idx == obj->efile.text_shndx; } struct bpf_program * @@ -4783,8 +4810,8 @@ static int bpf_get_map_info_from_fdinfo(int fd, struct bpf_map_info *info) fp = fopen(file, "re"); if (!fp) { err = -errno; - pr_warn("failed to open %s: %d. No procfs support?\n", file, - err); + pr_warn("failed to open %s: %s. No procfs support?\n", file, + errstr(err)); return err; } @@ -4939,8 +4966,8 @@ static int bpf_object_prepare_token(struct bpf_object *obj) bpffs_fd = open(bpffs_path, O_DIRECTORY, O_RDWR); if (bpffs_fd < 0) { err = -errno; - __pr(level, "object '%s': failed (%d) to open BPF FS mount at '%s'%s\n", - obj->name, err, bpffs_path, + __pr(level, "object '%s': failed (%s) to open BPF FS mount at '%s'%s\n", + obj->name, errstr(err), bpffs_path, mandatory ? "" : ", skipping optional step..."); return mandatory ? err : 0; } @@ -4974,7 +5001,6 @@ static int bpf_object_prepare_token(struct bpf_object *obj) static int bpf_object__probe_loading(struct bpf_object *obj) { - char *cp, errmsg[STRERR_BUFSIZE]; struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN(), @@ -4990,7 +5016,8 @@ bpf_object__probe_loading(struct bpf_object *obj) ret = bump_rlimit_memlock(); if (ret) - pr_warn("Failed to bump RLIMIT_MEMLOCK (err = %d), you might need to do it explicitly!\n", ret); + pr_warn("Failed to bump RLIMIT_MEMLOCK (err = %s), you might need to do it explicitly!\n", + errstr(ret)); /* make sure basic loading works */ ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &opts); @@ -4998,11 +5025,8 @@ bpf_object__probe_loading(struct bpf_object *obj) ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); if (ret < 0) { ret = errno; - cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); - pr_warn("Error in %s():%s(%d). Couldn't load trivial BPF " - "program. Make sure your kernel supports BPF " - "(CONFIG_BPF_SYSCALL=y) and/or that RLIMIT_MEMLOCK is " - "set to big enough value.\n", __func__, cp, ret); + pr_warn("Error in %s(): %s. Couldn't load trivial BPF program. Make sure your kernel supports BPF (CONFIG_BPF_SYSCALL=y) and/or that RLIMIT_MEMLOCK is set to big enough value.\n", + __func__, errstr(ret)); return -ret; } close(ret); @@ -5027,7 +5051,6 @@ bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) { struct bpf_map_info map_info; - char msg[STRERR_BUFSIZE]; __u32 map_info_len = sizeof(map_info); int err; @@ -5037,7 +5060,7 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) err = bpf_get_map_info_from_fdinfo(map_fd, &map_info); if (err) { pr_warn("failed to get map info for map FD %d: %s\n", map_fd, - libbpf_strerror_r(errno, msg, sizeof(msg))); + errstr(err)); return false; } @@ -5052,7 +5075,6 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) static int bpf_object__reuse_map(struct bpf_map *map) { - char *cp, errmsg[STRERR_BUFSIZE]; int err, pin_fd; pin_fd = bpf_obj_get(map->pin_path); @@ -5064,9 +5086,8 @@ bpf_object__reuse_map(struct bpf_map *map) return 0; } - cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg)); pr_warn("couldn't retrieve pinned map '%s': %s\n", - map->pin_path, cp); + map->pin_path, errstr(err)); return err; } @@ -5092,8 +5113,8 @@ static int bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) { enum libbpf_map_type map_type = map->libbpf_type; - char *cp, errmsg[STRERR_BUFSIZE]; int err, zero = 0; + size_t mmap_sz; if (obj->gen_loader) { bpf_gen__map_update_elem(obj->gen_loader, map - obj->maps, @@ -5106,9 +5127,8 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) err = bpf_map_update_elem(map->fd, &zero, map->mmaped, 0); if (err) { err = -errno; - cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); - pr_warn("Error setting initial map(%s) contents: %s\n", - map->name, cp); + pr_warn("map '%s': failed to set initial contents: %s\n", + bpf_map__name(map), errstr(err)); return err; } @@ -5117,12 +5137,43 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map) err = bpf_map_freeze(map->fd); if (err) { err = -errno; - cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); - pr_warn("Error freezing map(%s) as read-only: %s\n", - map->name, cp); + pr_warn("map '%s': failed to freeze as read-only: %s\n", + bpf_map__name(map), errstr(err)); return err; } } + + /* Remap anonymous mmap()-ed "map initialization image" as + * a BPF map-backed mmap()-ed memory, but preserving the same + * memory address. This will cause kernel to change process' + * page table to point to a different piece of kernel memory, + * but from userspace point of view memory address (and its + * contents, being identical at this point) will stay the + * same. This mapping will be released by bpf_object__close() + * as per normal clean up procedure. + */ + mmap_sz = bpf_map_mmap_sz(map); + if (map->def.map_flags & BPF_F_MMAPABLE) { + void *mmaped; + int prot; + + if (map->def.map_flags & BPF_F_RDONLY_PROG) + prot = PROT_READ; + else + prot = PROT_READ | PROT_WRITE; + mmaped = mmap(map->mmaped, mmap_sz, prot, MAP_SHARED | MAP_FIXED, map->fd, 0); + if (mmaped == MAP_FAILED) { + err = -errno; + pr_warn("map '%s': failed to re-mmap() contents: %s\n", + bpf_map__name(map), errstr(err)); + return err; + } + map->mmaped = mmaped; + } else if (map->mmaped) { + munmap(map->mmaped, mmap_sz); + map->mmaped = NULL; + } + return 0; } @@ -5171,8 +5222,8 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b return err; err = bpf_object__create_map(obj, map->inner_map, true); if (err) { - pr_warn("map '%s': failed to create inner map: %d\n", - map->name, err); + pr_warn("map '%s': failed to create inner map: %s\n", + map->name, errstr(err)); return err; } map->inner_map_fd = map->inner_map->fd; @@ -5226,12 +5277,9 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b def->max_entries, &create_attr); } if (map_fd < 0 && (create_attr.btf_key_type_id || create_attr.btf_value_type_id)) { - char *cp, errmsg[STRERR_BUFSIZE]; - err = -errno; - cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); - pr_warn("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", - map->name, cp, err); + pr_warn("Error in bpf_create_map_xattr(%s): %s. Retrying without BTF.\n", + map->name, errstr(err)); create_attr.btf_fd = 0; create_attr.btf_key_type_id = 0; create_attr.btf_value_type_id = 0; @@ -5286,8 +5334,8 @@ static int init_map_in_map_slots(struct bpf_object *obj, struct bpf_map *map) } if (err) { err = -errno; - pr_warn("map '%s': failed to initialize slot [%d] to map '%s' fd=%d: %d\n", - map->name, i, targ_map->name, fd, err); + pr_warn("map '%s': failed to initialize slot [%d] to map '%s' fd=%d: %s\n", + map->name, i, targ_map->name, fd, errstr(err)); return err; } pr_debug("map '%s': slot [%d] set to map '%s' fd=%d\n", @@ -5319,8 +5367,8 @@ static int init_prog_array_slots(struct bpf_object *obj, struct bpf_map *map) err = bpf_map_update_elem(map->fd, &i, &fd, 0); if (err) { err = -errno; - pr_warn("map '%s': failed to initialize slot [%d] to prog '%s' fd=%d: %d\n", - map->name, i, targ_prog->name, fd, err); + pr_warn("map '%s': failed to initialize slot [%d] to prog '%s' fd=%d: %s\n", + map->name, i, targ_prog->name, fd, errstr(err)); return err; } pr_debug("map '%s': slot [%d] set to prog '%s' fd=%d\n", @@ -5373,7 +5421,6 @@ static int bpf_object__create_maps(struct bpf_object *obj) { struct bpf_map *map; - char *cp, errmsg[STRERR_BUFSIZE]; unsigned int i, j; int err; bool retried; @@ -5439,8 +5486,7 @@ bpf_object__create_maps(struct bpf_object *obj) err = bpf_object__populate_internal_map(obj, map); if (err < 0) goto err_out; - } - if (map->def.type == BPF_MAP_TYPE_ARENA) { + } else if (map->def.type == BPF_MAP_TYPE_ARENA) { map->mmaped = mmap((void *)(long)map->map_extra, bpf_map_mmap_sz(map), PROT_READ | PROT_WRITE, map->map_extra ? MAP_SHARED | MAP_FIXED : MAP_SHARED, @@ -5448,8 +5494,8 @@ bpf_object__create_maps(struct bpf_object *obj) if (map->mmaped == MAP_FAILED) { err = -errno; map->mmaped = NULL; - pr_warn("map '%s': failed to mmap arena: %d\n", - map->name, err); + pr_warn("map '%s': failed to mmap arena: %s\n", + map->name, errstr(err)); return err; } if (obj->arena_data) { @@ -5471,8 +5517,8 @@ bpf_object__create_maps(struct bpf_object *obj) retried = true; goto retry; } - pr_warn("map '%s': failed to auto-pin at '%s': %d\n", - map->name, map->pin_path, err); + pr_warn("map '%s': failed to auto-pin at '%s': %s\n", + map->name, map->pin_path, errstr(err)); goto err_out; } } @@ -5481,8 +5527,7 @@ bpf_object__create_maps(struct bpf_object *obj) return 0; err_out: - cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); - pr_warn("map '%s': failed to create: %s(%d)\n", map->name, cp, err); + pr_warn("map '%s': failed to create: %s\n", map->name, errstr(err)); pr_perm_msg(err); for (j = 0; j < i; j++) zclose(obj->maps[j].fd); @@ -5606,7 +5651,7 @@ static int load_module_btfs(struct bpf_object *obj) } if (err) { err = -errno; - pr_warn("failed to iterate BTF objects: %d\n", err); + pr_warn("failed to iterate BTF objects: %s\n", errstr(err)); return err; } @@ -5615,7 +5660,7 @@ static int load_module_btfs(struct bpf_object *obj) if (errno == ENOENT) continue; /* expected race: BTF was unloaded */ err = -errno; - pr_warn("failed to get BTF object #%d FD: %d\n", id, err); + pr_warn("failed to get BTF object #%d FD: %s\n", id, errstr(err)); return err; } @@ -5627,7 +5672,7 @@ static int load_module_btfs(struct bpf_object *obj) err = bpf_btf_get_info_by_fd(fd, &info, &len); if (err) { err = -errno; - pr_warn("failed to get BTF object #%d info: %d\n", id, err); + pr_warn("failed to get BTF object #%d info: %s\n", id, errstr(err)); goto err_out; } @@ -5640,8 +5685,8 @@ static int load_module_btfs(struct bpf_object *obj) btf = btf_get_from_fd(fd, obj->btf_vmlinux); err = libbpf_get_error(btf); if (err) { - pr_warn("failed to load module [%s]'s BTF object #%d: %d\n", - name, id, err); + pr_warn("failed to load module [%s]'s BTF object #%d: %s\n", + name, id, errstr(err)); goto err_out; } @@ -5870,7 +5915,7 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path) obj->btf_vmlinux_override = btf__parse(targ_btf_path, NULL); err = libbpf_get_error(obj->btf_vmlinux_override); if (err) { - pr_warn("failed to parse target BTF: %d\n", err); + pr_warn("failed to parse target BTF: %s\n", errstr(err)); return err; } } @@ -5930,8 +5975,8 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path) err = record_relo_core(prog, rec, insn_idx); if (err) { - pr_warn("prog '%s': relo #%d: failed to record relocation: %d\n", - prog->name, i, err); + pr_warn("prog '%s': relo #%d: failed to record relocation: %s\n", + prog->name, i, errstr(err)); goto out; } @@ -5940,15 +5985,15 @@ bpf_object__relocate_core(struct bpf_object *obj, const char *targ_btf_path) err = bpf_core_resolve_relo(prog, rec, i, obj->btf, cand_cache, &targ_res); if (err) { - pr_warn("prog '%s': relo #%d: failed to relocate: %d\n", - prog->name, i, err); + pr_warn("prog '%s': relo #%d: failed to relocate: %s\n", + prog->name, i, errstr(err)); goto out; } err = bpf_core_patch_insn(prog->name, insn, insn_idx, rec, i, &targ_res); if (err) { - pr_warn("prog '%s': relo #%d: failed to patch insn #%u: %d\n", - prog->name, i, insn_idx, err); + pr_warn("prog '%s': relo #%d: failed to patch insn #%u: %s\n", + prog->name, i, insn_idx, errstr(err)); goto out; } } @@ -6216,8 +6261,8 @@ reloc_prog_func_and_line_info(const struct bpf_object *obj, &main_prog->func_info_rec_size); if (err) { if (err != -ENOENT) { - pr_warn("prog '%s': error relocating .BTF.ext function info: %d\n", - prog->name, err); + pr_warn("prog '%s': error relocating .BTF.ext function info: %s\n", + prog->name, errstr(err)); return err; } if (main_prog->func_info) { @@ -6244,8 +6289,8 @@ reloc_prog_func_and_line_info(const struct bpf_object *obj, &main_prog->line_info_rec_size); if (err) { if (err != -ENOENT) { - pr_warn("prog '%s': error relocating .BTF.ext line info: %d\n", - prog->name, err); + pr_warn("prog '%s': error relocating .BTF.ext line info: %s\n", + prog->name, errstr(err)); return err; } if (main_prog->line_info) { @@ -7009,8 +7054,8 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat if (obj->btf_ext) { err = bpf_object__relocate_core(obj, targ_btf_path); if (err) { - pr_warn("failed to perform CO-RE relocations: %d\n", - err); + pr_warn("failed to perform CO-RE relocations: %s\n", + errstr(err)); return err; } bpf_object__sort_relos(obj); @@ -7054,8 +7099,8 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat err = bpf_object__relocate_calls(obj, prog); if (err) { - pr_warn("prog '%s': failed to relocate calls: %d\n", - prog->name, err); + pr_warn("prog '%s': failed to relocate calls: %s\n", + prog->name, errstr(err)); return err; } @@ -7091,16 +7136,16 @@ static int bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_pat /* Process data relos for main programs */ err = bpf_object__relocate_data(obj, prog); if (err) { - pr_warn("prog '%s': failed to relocate data references: %d\n", - prog->name, err); + pr_warn("prog '%s': failed to relocate data references: %s\n", + prog->name, errstr(err)); return err; } /* Fix up .BTF.ext information, if necessary */ err = bpf_program_fixup_func_info(obj, prog); if (err) { - pr_warn("prog '%s': failed to perform .BTF.ext fix ups: %d\n", - prog->name, err); + pr_warn("prog '%s': failed to perform .BTF.ext fix ups: %s\n", + prog->name, errstr(err)); return err; } } @@ -7352,8 +7397,14 @@ static int libbpf_prepare_prog_load(struct bpf_program *prog, opts->prog_flags |= BPF_F_XDP_HAS_FRAGS; /* special check for usdt to use uprobe_multi link */ - if ((def & SEC_USDT) && kernel_supports(prog->obj, FEAT_UPROBE_MULTI_LINK)) + if ((def & SEC_USDT) && kernel_supports(prog->obj, FEAT_UPROBE_MULTI_LINK)) { + /* for BPF_TRACE_UPROBE_MULTI, user might want to query expected_attach_type + * in prog, and expected_attach_type we set in kernel is from opts, so we + * update both. + */ prog->expected_attach_type = BPF_TRACE_UPROBE_MULTI; + opts->expected_attach_type = BPF_TRACE_UPROBE_MULTI; + } if ((def & SEC_ATTACH_BTF) && !prog->attach_btf_id) { int btf_obj_fd = 0, btf_type_id = 0, err; @@ -7403,7 +7454,6 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog { LIBBPF_OPTS(bpf_prog_load_opts, load_attr); const char *prog_name = NULL; - char *cp, errmsg[STRERR_BUFSIZE]; size_t log_buf_size = 0; char *log_buf = NULL, *tmp; bool own_log_buf = true; @@ -7443,6 +7493,7 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog load_attr.attach_btf_id = prog->attach_btf_id; load_attr.kern_version = kern_version; load_attr.prog_ifindex = prog->prog_ifindex; + load_attr.expected_attach_type = prog->expected_attach_type; /* specify func_info/line_info only if kernel supports them */ if (obj->btf && btf__fd(obj->btf) >= 0 && kernel_supports(obj, FEAT_BTF_FUNC)) { @@ -7466,17 +7517,14 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog if (prog->sec_def && prog->sec_def->prog_prepare_load_fn) { err = prog->sec_def->prog_prepare_load_fn(prog, &load_attr, prog->sec_def->cookie); if (err < 0) { - pr_warn("prog '%s': failed to prepare load attributes: %d\n", - prog->name, err); + pr_warn("prog '%s': failed to prepare load attributes: %s\n", + prog->name, errstr(err)); return err; } insns = prog->insns; insns_cnt = prog->insns_cnt; } - /* allow prog_prepare_load_fn to change expected_attach_type */ - load_attr.expected_attach_type = prog->expected_attach_type; - if (obj->gen_loader) { bpf_gen__prog_load(obj->gen_loader, prog->type, prog->name, license, insns, insns_cnt, &load_attr, @@ -7534,9 +7582,8 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog continue; if (bpf_prog_bind_map(ret, map->fd, NULL)) { - cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); pr_warn("prog '%s': failed to bind map '%s': %s\n", - prog->name, map->real_name, cp); + prog->name, map->real_name, errstr(errno)); /* Don't fail hard if can't bind rodata. */ } } @@ -7566,8 +7613,7 @@ static int bpf_object_load_prog(struct bpf_object *obj, struct bpf_program *prog /* post-process verifier log to improve error descriptions */ fixup_verifier_log(prog, log_buf, log_buf_size); - cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); - pr_warn("prog '%s': BPF program load failed: %s\n", prog->name, cp); + pr_warn("prog '%s': BPF program load failed: %s\n", prog->name, errstr(errno)); pr_perm_msg(ret); if (own_log_buf && log_buf && log_buf[0] != '\0') { @@ -7860,7 +7906,7 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level) err = bpf_object_load_prog(obj, prog, prog->insns, prog->insns_cnt, obj->license, obj->kern_version, &prog->fd); if (err) { - pr_warn("prog '%s': failed to load: %d\n", prog->name, err); + pr_warn("prog '%s': failed to load: %s\n", prog->name, errstr(err)); return err; } } @@ -7894,8 +7940,8 @@ static int bpf_object_init_progs(struct bpf_object *obj, const struct bpf_object if (prog->sec_def->prog_setup_fn) { err = prog->sec_def->prog_setup_fn(prog, prog->sec_def->cookie); if (err < 0) { - pr_warn("prog '%s': failed to initialize: %d\n", - prog->name, err); + pr_warn("prog '%s': failed to initialize: %s\n", + prog->name, errstr(err)); return err; } } @@ -7992,7 +8038,6 @@ static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, } err = bpf_object__elf_init(obj); - err = err ? : bpf_object__check_endianness(obj); err = err ? : bpf_object__elf_collect(obj); err = err ? : bpf_object__collect_externs(obj); err = err ? : bpf_object_fixup_btf(obj); @@ -8085,7 +8130,7 @@ static int libbpf_kallsyms_parse(kallsyms_cb_t cb, void *ctx) f = fopen("/proc/kallsyms", "re"); if (!f) { err = -errno; - pr_warn("failed to open /proc/kallsyms: %d\n", err); + pr_warn("failed to open /proc/kallsyms: %s\n", errstr(err)); return err; } @@ -8498,8 +8543,15 @@ static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const ch return libbpf_err(-EINVAL); } - if (obj->gen_loader) + /* Disallow kernel loading programs of non-native endianness but + * permit cross-endian creation of "light skeleton". + */ + if (obj->gen_loader) { bpf_gen__init(obj->gen_loader, extra_log_level, obj->nr_programs, obj->nr_maps); + } else if (!is_native_endianness(obj)) { + pr_warn("object '%s': loading non-native endianness is unsupported\n", obj->name); + return libbpf_err(-LIBBPF_ERRNO__ENDIAN); + } err = bpf_object_prepare_token(obj); err = err ? : bpf_object__probe_loading(obj); @@ -8562,7 +8614,6 @@ int bpf_object__load(struct bpf_object *obj) static int make_parent_dir(const char *path) { - char *cp, errmsg[STRERR_BUFSIZE]; char *dname, *dir; int err = 0; @@ -8576,15 +8627,13 @@ static int make_parent_dir(const char *path) free(dname); if (err) { - cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg)); - pr_warn("failed to mkdir %s: %s\n", path, cp); + pr_warn("failed to mkdir %s: %s\n", path, errstr(err)); } return err; } static int check_path(const char *path) { - char *cp, errmsg[STRERR_BUFSIZE]; struct statfs st_fs; char *dname, *dir; int err = 0; @@ -8598,8 +8647,7 @@ static int check_path(const char *path) dir = dirname(dname); if (statfs(dir, &st_fs)) { - cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); - pr_warn("failed to statfs %s: %s\n", dir, cp); + pr_warn("failed to statfs %s: %s\n", dir, errstr(errno)); err = -errno; } free(dname); @@ -8614,7 +8662,6 @@ static int check_path(const char *path) int bpf_program__pin(struct bpf_program *prog, const char *path) { - char *cp, errmsg[STRERR_BUFSIZE]; int err; if (prog->fd < 0) { @@ -8632,8 +8679,7 @@ int bpf_program__pin(struct bpf_program *prog, const char *path) if (bpf_obj_pin(prog->fd, path)) { err = -errno; - cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); - pr_warn("prog '%s': failed to pin at '%s': %s\n", prog->name, path, cp); + pr_warn("prog '%s': failed to pin at '%s': %s\n", prog->name, path, errstr(err)); return libbpf_err(err); } @@ -8664,7 +8710,6 @@ int bpf_program__unpin(struct bpf_program *prog, const char *path) int bpf_map__pin(struct bpf_map *map, const char *path) { - char *cp, errmsg[STRERR_BUFSIZE]; int err; if (map == NULL) { @@ -8723,8 +8768,7 @@ int bpf_map__pin(struct bpf_map *map, const char *path) return 0; out_err: - cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg)); - pr_warn("failed to pin map: %s\n", cp); + pr_warn("failed to pin map: %s\n", errstr(err)); return libbpf_err(err); } @@ -9096,6 +9140,7 @@ int bpf_object__gen_loader(struct bpf_object *obj, struct gen_loader_opts *opts) if (!gen) return -ENOMEM; gen->opts = opts; + gen->swapped_endian = !is_native_endianness(obj); obj->gen_loader = gen; return 0; } @@ -9370,8 +9415,10 @@ static const struct bpf_sec_def section_defs[] = { SEC_DEF("kprobe.session+", KPROBE, BPF_TRACE_KPROBE_SESSION, SEC_NONE, attach_kprobe_session), SEC_DEF("uprobe.multi+", KPROBE, BPF_TRACE_UPROBE_MULTI, SEC_NONE, attach_uprobe_multi), SEC_DEF("uretprobe.multi+", KPROBE, BPF_TRACE_UPROBE_MULTI, SEC_NONE, attach_uprobe_multi), + SEC_DEF("uprobe.session+", KPROBE, BPF_TRACE_UPROBE_SESSION, SEC_NONE, attach_uprobe_multi), SEC_DEF("uprobe.multi.s+", KPROBE, BPF_TRACE_UPROBE_MULTI, SEC_SLEEPABLE, attach_uprobe_multi), SEC_DEF("uretprobe.multi.s+", KPROBE, BPF_TRACE_UPROBE_MULTI, SEC_SLEEPABLE, attach_uprobe_multi), + SEC_DEF("uprobe.session.s+", KPROBE, BPF_TRACE_UPROBE_SESSION, SEC_SLEEPABLE, attach_uprobe_multi), SEC_DEF("ksyscall+", KPROBE, 0, SEC_NONE, attach_ksyscall), SEC_DEF("kretsyscall+", KPROBE, 0, SEC_NONE, attach_ksyscall), SEC_DEF("usdt+", KPROBE, 0, SEC_USDT, attach_usdt), @@ -9910,8 +9957,8 @@ static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd) memset(&info, 0, info_len); err = bpf_prog_get_info_by_fd(attach_prog_fd, &info, &info_len); if (err) { - pr_warn("failed bpf_prog_get_info_by_fd for FD %d: %d\n", - attach_prog_fd, err); + pr_warn("failed bpf_prog_get_info_by_fd for FD %d: %s\n", + attach_prog_fd, errstr(err)); return err; } @@ -9923,7 +9970,7 @@ static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd) btf = btf__load_from_kernel_by_id(info.btf_id); err = libbpf_get_error(btf); if (err) { - pr_warn("Failed to get BTF %d of the program: %d\n", info.btf_id, err); + pr_warn("Failed to get BTF %d of the program: %s\n", info.btf_id, errstr(err)); goto out; } err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC); @@ -10005,8 +10052,8 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attac } err = libbpf_find_prog_btf_id(attach_name, attach_prog_fd); if (err < 0) { - pr_warn("prog '%s': failed to find BPF program (FD %d) BTF ID for '%s': %d\n", - prog->name, attach_prog_fd, attach_name, err); + pr_warn("prog '%s': failed to find BPF program (FD %d) BTF ID for '%s': %s\n", + prog->name, attach_prog_fd, attach_name, errstr(err)); return err; } *btf_obj_fd = 0; @@ -10025,8 +10072,8 @@ static int libbpf_find_attach_btf_id(struct bpf_program *prog, const char *attac btf_type_id); } if (err) { - pr_warn("prog '%s': failed to find kernel BTF type ID of '%s': %d\n", - prog->name, attach_name, err); + pr_warn("prog '%s': failed to find kernel BTF type ID of '%s': %s\n", + prog->name, attach_name, errstr(err)); return err; } return 0; @@ -10254,14 +10301,14 @@ int bpf_map__set_value_size(struct bpf_map *map, __u32 size) mmap_new_sz = array_map_mmap_sz(size, map->def.max_entries); err = bpf_map_mmap_resize(map, mmap_old_sz, mmap_new_sz); if (err) { - pr_warn("map '%s': failed to resize memory-mapped region: %d\n", - bpf_map__name(map), err); + pr_warn("map '%s': failed to resize memory-mapped region: %s\n", + bpf_map__name(map), errstr(err)); return err; } err = map_btf_datasec_resize(map, size); if (err && err != -ENOENT) { - pr_warn("map '%s': failed to adjust resized BTF, clearing BTF key/value info: %d\n", - bpf_map__name(map), err); + pr_warn("map '%s': failed to adjust resized BTF, clearing BTF key/value info: %s\n", + bpf_map__name(map), errstr(err)); map->btf_value_type_id = 0; map->btf_key_type_id = 0; } @@ -10752,7 +10799,6 @@ static void bpf_link_perf_dealloc(struct bpf_link *link) struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *prog, int pfd, const struct bpf_perf_event_opts *opts) { - char errmsg[STRERR_BUFSIZE]; struct bpf_link_perf *link; int prog_fd, link_fd = -1, err; bool force_ioctl_attach; @@ -10787,9 +10833,8 @@ struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *p link_fd = bpf_link_create(prog_fd, pfd, BPF_PERF_EVENT, &link_opts); if (link_fd < 0) { err = -errno; - pr_warn("prog '%s': failed to create BPF link for perf_event FD %d: %d (%s)\n", - prog->name, pfd, - err, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + pr_warn("prog '%s': failed to create BPF link for perf_event FD %d: %s\n", + prog->name, pfd, errstr(err)); goto err_out; } link->link.fd = link_fd; @@ -10803,7 +10848,7 @@ struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *p if (ioctl(pfd, PERF_EVENT_IOC_SET_BPF, prog_fd) < 0) { err = -errno; pr_warn("prog '%s': failed to attach to perf_event FD %d: %s\n", - prog->name, pfd, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + prog->name, pfd, errstr(err)); if (err == -EPROTO) pr_warn("prog '%s': try add PERF_SAMPLE_CALLCHAIN to or remove exclude_callchain_[kernel|user] from pfd %d\n", prog->name, pfd); @@ -10814,7 +10859,7 @@ struct bpf_link *bpf_program__attach_perf_event_opts(const struct bpf_program *p if (ioctl(pfd, PERF_EVENT_IOC_ENABLE, 0) < 0) { err = -errno; pr_warn("prog '%s': failed to enable perf_event FD %d: %s\n", - prog->name, pfd, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + prog->name, pfd, errstr(err)); goto err_out; } @@ -10838,22 +10883,19 @@ struct bpf_link *bpf_program__attach_perf_event(const struct bpf_program *prog, */ static int parse_uint_from_file(const char *file, const char *fmt) { - char buf[STRERR_BUFSIZE]; int err, ret; FILE *f; f = fopen(file, "re"); if (!f) { err = -errno; - pr_debug("failed to open '%s': %s\n", file, - libbpf_strerror_r(err, buf, sizeof(buf))); + pr_debug("failed to open '%s': %s\n", file, errstr(err)); return err; } err = fscanf(f, fmt, &ret); if (err != 1) { err = err == EOF ? -EIO : -errno; - pr_debug("failed to parse '%s': %s\n", file, - libbpf_strerror_r(err, buf, sizeof(buf))); + pr_debug("failed to parse '%s': %s\n", file, errstr(err)); fclose(f); return err; } @@ -10897,7 +10939,6 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, { const size_t attr_sz = sizeof(struct perf_event_attr); struct perf_event_attr attr; - char errmsg[STRERR_BUFSIZE]; int type, pfd; if ((__u64)ref_ctr_off >= (1ULL << PERF_UPROBE_REF_CTR_OFFSET_BITS)) @@ -10910,7 +10951,7 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, if (type < 0) { pr_warn("failed to determine %s perf type: %s\n", uprobe ? "uprobe" : "kprobe", - libbpf_strerror_r(type, errmsg, sizeof(errmsg))); + errstr(type)); return type; } if (retprobe) { @@ -10920,7 +10961,7 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name, if (bit < 0) { pr_warn("failed to determine %s retprobe bit: %s\n", uprobe ? "uprobe" : "kprobe", - libbpf_strerror_r(bit, errmsg, sizeof(errmsg))); + errstr(bit)); return bit; } attr.config |= 1 << bit; @@ -11049,14 +11090,13 @@ static int perf_event_kprobe_open_legacy(const char *probe_name, bool retprobe, { const size_t attr_sz = sizeof(struct perf_event_attr); struct perf_event_attr attr; - char errmsg[STRERR_BUFSIZE]; int type, pfd, err; err = add_kprobe_event_legacy(probe_name, retprobe, kfunc_name, offset); if (err < 0) { pr_warn("failed to add legacy kprobe event for '%s+0x%zx': %s\n", kfunc_name, offset, - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); return err; } type = determine_kprobe_perf_type_legacy(probe_name, retprobe); @@ -11064,7 +11104,7 @@ static int perf_event_kprobe_open_legacy(const char *probe_name, bool retprobe, err = type; pr_warn("failed to determine legacy kprobe event id for '%s+0x%zx': %s\n", kfunc_name, offset, - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); goto err_clean_legacy; } @@ -11080,7 +11120,7 @@ static int perf_event_kprobe_open_legacy(const char *probe_name, bool retprobe, if (pfd < 0) { err = -errno; pr_warn("legacy kprobe perf_event_open() failed: %s\n", - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); goto err_clean_legacy; } return pfd; @@ -11156,7 +11196,6 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog, { DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts); enum probe_attach_mode attach_mode; - char errmsg[STRERR_BUFSIZE]; char *legacy_probe = NULL; struct bpf_link *link; size_t offset; @@ -11214,7 +11253,7 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog, pr_warn("prog '%s': failed to create %s '%s+0x%zx' perf event: %s\n", prog->name, retprobe ? "kretprobe" : "kprobe", func_name, offset, - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); goto err_out; } link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts); @@ -11224,7 +11263,7 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog, pr_warn("prog '%s': failed to attach to %s '%s+0x%zx': %s\n", prog->name, retprobe ? "kretprobe" : "kprobe", func_name, offset, - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); goto err_clean_legacy; } if (legacy) { @@ -11360,7 +11399,7 @@ static int libbpf_available_kallsyms_parse(struct kprobe_multi_resolve *res) f = fopen(available_functions_file, "re"); if (!f) { err = -errno; - pr_warn("failed to open %s: %d\n", available_functions_file, err); + pr_warn("failed to open %s: %s\n", available_functions_file, errstr(err)); return err; } @@ -11435,7 +11474,7 @@ static int libbpf_available_kprobes_parse(struct kprobe_multi_resolve *res) f = fopen(available_path, "re"); if (!f) { err = -errno; - pr_warn("failed to open %s: %d\n", available_path, err); + pr_warn("failed to open %s: %s\n", available_path, errstr(err)); return err; } @@ -11481,7 +11520,6 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog, }; enum bpf_attach_type attach_type; struct bpf_link *link = NULL; - char errmsg[STRERR_BUFSIZE]; const unsigned long *addrs; int err, link_fd, prog_fd; bool retprobe, session; @@ -11549,7 +11587,7 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog, if (link_fd < 0) { err = -errno; pr_warn("prog '%s': failed to attach: %s\n", - prog->name, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + prog->name, errstr(err)); goto error; } link->fd = link_fd; @@ -11693,7 +11731,9 @@ static int attach_uprobe_multi(const struct bpf_program *prog, long cookie, stru ret = 0; break; case 3: + opts.session = str_has_pfx(probe_type, "uprobe.session"); opts.retprobe = str_has_pfx(probe_type, "uretprobe.multi"); + *link = bpf_program__attach_uprobe_multi(prog, -1, binary_path, func_name, &opts); ret = libbpf_get_error(*link); break; @@ -11756,15 +11796,15 @@ static int perf_event_uprobe_open_legacy(const char *probe_name, bool retprobe, err = add_uprobe_event_legacy(probe_name, retprobe, binary_path, offset); if (err < 0) { - pr_warn("failed to add legacy uprobe event for %s:0x%zx: %d\n", - binary_path, (size_t)offset, err); + pr_warn("failed to add legacy uprobe event for %s:0x%zx: %s\n", + binary_path, (size_t)offset, errstr(err)); return err; } type = determine_uprobe_perf_type_legacy(probe_name, retprobe); if (type < 0) { err = type; - pr_warn("failed to determine legacy uprobe event id for %s:0x%zx: %d\n", - binary_path, offset, err); + pr_warn("failed to determine legacy uprobe event id for %s:0x%zx: %s\n", + binary_path, offset, errstr(err)); goto err_clean_legacy; } @@ -11779,7 +11819,7 @@ static int perf_event_uprobe_open_legacy(const char *probe_name, bool retprobe, -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC); if (pfd < 0) { err = -errno; - pr_warn("legacy uprobe perf_event_open() failed: %d\n", err); + pr_warn("legacy uprobe perf_event_open() failed: %s\n", errstr(err)); goto err_clean_legacy; } return pfd; @@ -11942,10 +11982,11 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, const unsigned long *ref_ctr_offsets = NULL, *offsets = NULL; LIBBPF_OPTS(bpf_link_create_opts, lopts); unsigned long *resolved_offsets = NULL; + enum bpf_attach_type attach_type; int err = 0, link_fd, prog_fd; struct bpf_link *link = NULL; - char errmsg[STRERR_BUFSIZE]; char full_path[PATH_MAX]; + bool retprobe, session; const __u64 *cookies; const char **syms; size_t cnt; @@ -11965,6 +12006,8 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, ref_ctr_offsets = OPTS_GET(opts, ref_ctr_offsets, NULL); cookies = OPTS_GET(opts, cookies, NULL); cnt = OPTS_GET(opts, cnt, 0); + retprobe = OPTS_GET(opts, retprobe, false); + session = OPTS_GET(opts, session, false); /* * User can specify 2 mutually exclusive set of inputs: @@ -11993,12 +12036,15 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, return libbpf_err_ptr(-EINVAL); } + if (retprobe && session) + return libbpf_err_ptr(-EINVAL); + if (func_pattern) { if (!strchr(path, '/')) { err = resolve_full_path(path, full_path, sizeof(full_path)); if (err) { - pr_warn("prog '%s': failed to resolve full path for '%s': %d\n", - prog->name, path, err); + pr_warn("prog '%s': failed to resolve full path for '%s': %s\n", + prog->name, path, errstr(err)); return libbpf_err_ptr(err); } path = full_path; @@ -12016,12 +12062,14 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, offsets = resolved_offsets; } + attach_type = session ? BPF_TRACE_UPROBE_SESSION : BPF_TRACE_UPROBE_MULTI; + lopts.uprobe_multi.path = path; lopts.uprobe_multi.offsets = offsets; lopts.uprobe_multi.ref_ctr_offsets = ref_ctr_offsets; lopts.uprobe_multi.cookies = cookies; lopts.uprobe_multi.cnt = cnt; - lopts.uprobe_multi.flags = OPTS_GET(opts, retprobe, false) ? BPF_F_UPROBE_MULTI_RETURN : 0; + lopts.uprobe_multi.flags = retprobe ? BPF_F_UPROBE_MULTI_RETURN : 0; if (pid == 0) pid = getpid(); @@ -12035,11 +12083,11 @@ bpf_program__attach_uprobe_multi(const struct bpf_program *prog, } link->detach = &bpf_link__detach_fd; - link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &lopts); + link_fd = bpf_link_create(prog_fd, 0, attach_type, &lopts); if (link_fd < 0) { err = -errno; pr_warn("prog '%s': failed to attach multi-uprobe: %s\n", - prog->name, libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + prog->name, errstr(err)); goto error; } link->fd = link_fd; @@ -12058,7 +12106,7 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid, const struct bpf_uprobe_opts *opts) { const char *archive_path = NULL, *archive_sep = NULL; - char errmsg[STRERR_BUFSIZE], *legacy_probe = NULL; + char *legacy_probe = NULL; DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts); enum probe_attach_mode attach_mode; char full_path[PATH_MAX]; @@ -12090,8 +12138,8 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid, } else if (!strchr(binary_path, '/')) { err = resolve_full_path(binary_path, full_path, sizeof(full_path)); if (err) { - pr_warn("prog '%s': failed to resolve full path for '%s': %d\n", - prog->name, binary_path, err); + pr_warn("prog '%s': failed to resolve full path for '%s': %s\n", + prog->name, binary_path, errstr(err)); return libbpf_err_ptr(err); } binary_path = full_path; @@ -12157,7 +12205,7 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid, pr_warn("prog '%s': failed to create %s '%s:0x%zx' perf event: %s\n", prog->name, retprobe ? "uretprobe" : "uprobe", binary_path, func_offset, - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); goto err_out; } @@ -12168,7 +12216,7 @@ bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid, pr_warn("prog '%s': failed to attach to %s '%s:0x%zx': %s\n", prog->name, retprobe ? "uretprobe" : "uprobe", binary_path, func_offset, - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); goto err_clean_legacy; } if (legacy) { @@ -12289,8 +12337,8 @@ struct bpf_link *bpf_program__attach_usdt(const struct bpf_program *prog, if (!strchr(binary_path, '/')) { err = resolve_full_path(binary_path, resolved_path, sizeof(resolved_path)); if (err) { - pr_warn("prog '%s': failed to resolve full path for '%s': %d\n", - prog->name, binary_path, err); + pr_warn("prog '%s': failed to resolve full path for '%s': %s\n", + prog->name, binary_path, errstr(err)); return libbpf_err_ptr(err); } binary_path = resolved_path; @@ -12368,14 +12416,13 @@ static int perf_event_open_tracepoint(const char *tp_category, { const size_t attr_sz = sizeof(struct perf_event_attr); struct perf_event_attr attr; - char errmsg[STRERR_BUFSIZE]; int tp_id, pfd, err; tp_id = determine_tracepoint_id(tp_category, tp_name); if (tp_id < 0) { pr_warn("failed to determine tracepoint '%s/%s' perf event ID: %s\n", tp_category, tp_name, - libbpf_strerror_r(tp_id, errmsg, sizeof(errmsg))); + errstr(tp_id)); return tp_id; } @@ -12390,7 +12437,7 @@ static int perf_event_open_tracepoint(const char *tp_category, err = -errno; pr_warn("tracepoint '%s/%s' perf_event_open() failed: %s\n", tp_category, tp_name, - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); return err; } return pfd; @@ -12402,7 +12449,6 @@ struct bpf_link *bpf_program__attach_tracepoint_opts(const struct bpf_program *p const struct bpf_tracepoint_opts *opts) { DECLARE_LIBBPF_OPTS(bpf_perf_event_opts, pe_opts); - char errmsg[STRERR_BUFSIZE]; struct bpf_link *link; int pfd, err; @@ -12415,7 +12461,7 @@ struct bpf_link *bpf_program__attach_tracepoint_opts(const struct bpf_program *p if (pfd < 0) { pr_warn("prog '%s': failed to create tracepoint '%s/%s' perf event: %s\n", prog->name, tp_category, tp_name, - libbpf_strerror_r(pfd, errmsg, sizeof(errmsg))); + errstr(pfd)); return libbpf_err_ptr(pfd); } link = bpf_program__attach_perf_event_opts(prog, pfd, &pe_opts); @@ -12424,7 +12470,7 @@ struct bpf_link *bpf_program__attach_tracepoint_opts(const struct bpf_program *p close(pfd); pr_warn("prog '%s': failed to attach to tracepoint '%s/%s': %s\n", prog->name, tp_category, tp_name, - libbpf_strerror_r(err, errmsg, sizeof(errmsg))); + errstr(err)); return libbpf_err_ptr(err); } return link; @@ -12475,7 +12521,6 @@ bpf_program__attach_raw_tracepoint_opts(const struct bpf_program *prog, struct bpf_raw_tracepoint_opts *opts) { LIBBPF_OPTS(bpf_raw_tp_opts, raw_opts); - char errmsg[STRERR_BUFSIZE]; struct bpf_link *link; int prog_fd, pfd; @@ -12500,7 +12545,7 @@ bpf_program__attach_raw_tracepoint_opts(const struct bpf_program *prog, pfd = -errno; free(link); pr_warn("prog '%s': failed to attach to raw tracepoint '%s': %s\n", - prog->name, tp_name, libbpf_strerror_r(pfd, errmsg, sizeof(errmsg))); + prog->name, tp_name, errstr(pfd)); return libbpf_err_ptr(pfd); } link->fd = pfd; @@ -12559,7 +12604,6 @@ static struct bpf_link *bpf_program__attach_btf_id(const struct bpf_program *pro const struct bpf_trace_opts *opts) { LIBBPF_OPTS(bpf_link_create_opts, link_opts); - char errmsg[STRERR_BUFSIZE]; struct bpf_link *link; int prog_fd, pfd; @@ -12584,7 +12628,7 @@ static struct bpf_link *bpf_program__attach_btf_id(const struct bpf_program *pro pfd = -errno; free(link); pr_warn("prog '%s': failed to attach: %s\n", - prog->name, libbpf_strerror_r(pfd, errmsg, sizeof(errmsg))); + prog->name, errstr(pfd)); return libbpf_err_ptr(pfd); } link->fd = pfd; @@ -12625,7 +12669,6 @@ bpf_program_attach_fd(const struct bpf_program *prog, const struct bpf_link_create_opts *opts) { enum bpf_attach_type attach_type; - char errmsg[STRERR_BUFSIZE]; struct bpf_link *link; int prog_fd, link_fd; @@ -12647,7 +12690,7 @@ bpf_program_attach_fd(const struct bpf_program *prog, free(link); pr_warn("prog '%s': failed to attach to %s: %s\n", prog->name, target_name, - libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg))); + errstr(link_fd)); return libbpf_err_ptr(link_fd); } link->fd = link_fd; @@ -12760,7 +12803,7 @@ struct bpf_link *bpf_program__attach_freplace(const struct bpf_program *prog, } if (prog->type != BPF_PROG_TYPE_EXT) { - pr_warn("prog '%s': only BPF_PROG_TYPE_EXT can attach as freplace", + pr_warn("prog '%s': only BPF_PROG_TYPE_EXT can attach as freplace\n", prog->name); return libbpf_err_ptr(-EINVAL); } @@ -12789,7 +12832,6 @@ bpf_program__attach_iter(const struct bpf_program *prog, const struct bpf_iter_attach_opts *opts) { DECLARE_LIBBPF_OPTS(bpf_link_create_opts, link_create_opts); - char errmsg[STRERR_BUFSIZE]; struct bpf_link *link; int prog_fd, link_fd; __u32 target_fd = 0; @@ -12817,7 +12859,7 @@ bpf_program__attach_iter(const struct bpf_program *prog, link_fd = -errno; free(link); pr_warn("prog '%s': failed to attach to iterator: %s\n", - prog->name, libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg))); + prog->name, errstr(link_fd)); return libbpf_err_ptr(link_fd); } link->fd = link_fd; @@ -12859,12 +12901,10 @@ struct bpf_link *bpf_program__attach_netfilter(const struct bpf_program *prog, link_fd = bpf_link_create(prog_fd, 0, BPF_NETFILTER, &lopts); if (link_fd < 0) { - char errmsg[STRERR_BUFSIZE]; - link_fd = -errno; free(link); pr_warn("prog '%s': failed to attach to netfilter: %s\n", - prog->name, libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg))); + prog->name, errstr(link_fd)); return libbpf_err_ptr(link_fd); } link->fd = link_fd; @@ -13149,7 +13189,6 @@ perf_buffer__open_cpu_buf(struct perf_buffer *pb, struct perf_event_attr *attr, int cpu, int map_key) { struct perf_cpu_buf *cpu_buf; - char msg[STRERR_BUFSIZE]; int err; cpu_buf = calloc(1, sizeof(*cpu_buf)); @@ -13165,7 +13204,7 @@ perf_buffer__open_cpu_buf(struct perf_buffer *pb, struct perf_event_attr *attr, if (cpu_buf->fd < 0) { err = -errno; pr_warn("failed to open perf buffer event on cpu #%d: %s\n", - cpu, libbpf_strerror_r(err, msg, sizeof(msg))); + cpu, errstr(err)); goto error; } @@ -13176,14 +13215,14 @@ perf_buffer__open_cpu_buf(struct perf_buffer *pb, struct perf_event_attr *attr, cpu_buf->base = NULL; err = -errno; pr_warn("failed to mmap perf buffer on cpu #%d: %s\n", - cpu, libbpf_strerror_r(err, msg, sizeof(msg))); + cpu, errstr(err)); goto error; } if (ioctl(cpu_buf->fd, PERF_EVENT_IOC_ENABLE, 0) < 0) { err = -errno; pr_warn("failed to enable perf buffer event on cpu #%d: %s\n", - cpu, libbpf_strerror_r(err, msg, sizeof(msg))); + cpu, errstr(err)); goto error; } @@ -13259,7 +13298,6 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, { const char *online_cpus_file = "/sys/devices/system/cpu/online"; struct bpf_map_info map; - char msg[STRERR_BUFSIZE]; struct perf_buffer *pb; bool *online = NULL; __u32 map_info_len; @@ -13282,7 +13320,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, */ if (err != -EINVAL) { pr_warn("failed to get map info for map FD %d: %s\n", - map_fd, libbpf_strerror_r(err, msg, sizeof(msg))); + map_fd, errstr(err)); return ERR_PTR(err); } pr_debug("failed to get map info for FD %d; API not supported? Ignoring...\n", @@ -13312,7 +13350,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, if (pb->epoll_fd < 0) { err = -errno; pr_warn("failed to create epoll instance: %s\n", - libbpf_strerror_r(err, msg, sizeof(msg))); + errstr(err)); goto error; } @@ -13343,7 +13381,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, err = parse_cpu_mask_file(online_cpus_file, &online, &n); if (err) { - pr_warn("failed to get online CPU mask: %d\n", err); + pr_warn("failed to get online CPU mask: %s\n", errstr(err)); goto error; } @@ -13374,7 +13412,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, err = -errno; pr_warn("failed to set cpu #%d, key %d -> perf FD %d: %s\n", cpu, map_key, cpu_buf->fd, - libbpf_strerror_r(err, msg, sizeof(msg))); + errstr(err)); goto error; } @@ -13385,7 +13423,7 @@ static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt, err = -errno; pr_warn("failed to epoll_ctl cpu #%d perf FD %d: %s\n", cpu, cpu_buf->fd, - libbpf_strerror_r(err, msg, sizeof(msg))); + errstr(err)); goto error; } j++; @@ -13480,7 +13518,7 @@ int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms) err = perf_buffer__process_records(pb, cpu_buf); if (err) { - pr_warn("error while processing records: %d\n", err); + pr_warn("error while processing records: %s\n", errstr(err)); return libbpf_err(err); } } @@ -13564,7 +13602,8 @@ int perf_buffer__consume(struct perf_buffer *pb) err = perf_buffer__process_records(pb, cpu_buf); if (err) { - pr_warn("perf_buffer: failed to process records in buffer #%d: %d\n", i, err); + pr_warn("perf_buffer: failed to process records in buffer #%d: %s\n", + i, errstr(err)); return libbpf_err(err); } } @@ -13675,14 +13714,14 @@ int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz) fd = open(fcpu, O_RDONLY | O_CLOEXEC); if (fd < 0) { err = -errno; - pr_warn("Failed to open cpu mask file %s: %d\n", fcpu, err); + pr_warn("Failed to open cpu mask file %s: %s\n", fcpu, errstr(err)); return err; } len = read(fd, buf, sizeof(buf)); close(fd); if (len <= 0) { err = len ? -errno : -EINVAL; - pr_warn("Failed to read cpu mask from %s: %d\n", fcpu, err); + pr_warn("Failed to read cpu mask from %s: %s\n", fcpu, errstr(err)); return err; } if (len >= sizeof(buf)) { @@ -13774,20 +13813,21 @@ int bpf_object__open_skeleton(struct bpf_object_skeleton *s, obj = bpf_object_open(NULL, s->data, s->data_sz, s->name, opts); if (IS_ERR(obj)) { err = PTR_ERR(obj); - pr_warn("failed to initialize skeleton BPF object '%s': %d\n", s->name, err); + pr_warn("failed to initialize skeleton BPF object '%s': %s\n", + s->name, errstr(err)); return libbpf_err(err); } *s->obj = obj; err = populate_skeleton_maps(obj, s->maps, s->map_cnt, s->map_skel_sz); if (err) { - pr_warn("failed to populate skeleton maps for '%s': %d\n", s->name, err); + pr_warn("failed to populate skeleton maps for '%s': %s\n", s->name, errstr(err)); return libbpf_err(err); } err = populate_skeleton_progs(obj, s->progs, s->prog_cnt, s->prog_skel_sz); if (err) { - pr_warn("failed to populate skeleton progs for '%s': %d\n", s->name, err); + pr_warn("failed to populate skeleton progs for '%s': %s\n", s->name, errstr(err)); return libbpf_err(err); } @@ -13817,13 +13857,13 @@ int bpf_object__open_subskeleton(struct bpf_object_subskeleton *s) err = populate_skeleton_maps(s->obj, s->maps, s->map_cnt, s->map_skel_sz); if (err) { - pr_warn("failed to populate subskeleton maps: %d\n", err); + pr_warn("failed to populate subskeleton maps: %s\n", errstr(err)); return libbpf_err(err); } err = populate_skeleton_progs(s->obj, s->progs, s->prog_cnt, s->prog_skel_sz); if (err) { - pr_warn("failed to populate subskeleton maps: %d\n", err); + pr_warn("failed to populate subskeleton maps: %s\n", errstr(err)); return libbpf_err(err); } @@ -13834,7 +13874,7 @@ int bpf_object__open_subskeleton(struct bpf_object_subskeleton *s) map_type = btf__type_by_id(btf, map_type_id); if (!btf_is_datasec(map_type)) { - pr_warn("type for map '%1$s' is not a datasec: %2$s", + pr_warn("type for map '%1$s' is not a datasec: %2$s\n", bpf_map__name(map), __btf_kind_str(btf_kind(map_type))); return libbpf_err(-EINVAL); @@ -13870,53 +13910,18 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s) err = bpf_object__load(*s->obj); if (err) { - pr_warn("failed to load BPF skeleton '%s': %d\n", s->name, err); + pr_warn("failed to load BPF skeleton '%s': %s\n", s->name, errstr(err)); return libbpf_err(err); } for (i = 0; i < s->map_cnt; i++) { struct bpf_map_skeleton *map_skel = (void *)s->maps + i * s->map_skel_sz; struct bpf_map *map = *map_skel->map; - size_t mmap_sz = bpf_map_mmap_sz(map); - int prot, map_fd = map->fd; - void **mmaped = map_skel->mmaped; - if (!mmaped) + if (!map_skel->mmaped) continue; - if (!(map->def.map_flags & BPF_F_MMAPABLE)) { - *mmaped = NULL; - continue; - } - - if (map->def.type == BPF_MAP_TYPE_ARENA) { - *mmaped = map->mmaped; - continue; - } - - if (map->def.map_flags & BPF_F_RDONLY_PROG) - prot = PROT_READ; - else - prot = PROT_READ | PROT_WRITE; - - /* Remap anonymous mmap()-ed "map initialization image" as - * a BPF map-backed mmap()-ed memory, but preserving the same - * memory address. This will cause kernel to change process' - * page table to point to a different piece of kernel memory, - * but from userspace point of view memory address (and its - * contents, being identical at this point) will stay the - * same. This mapping will be released by bpf_object__close() - * as per normal clean up procedure, so we don't need to worry - * about it from skeleton's clean up perspective. - */ - *mmaped = mmap(map->mmaped, mmap_sz, prot, MAP_SHARED | MAP_FIXED, map_fd, 0); - if (*mmaped == MAP_FAILED) { - err = -errno; - *mmaped = NULL; - pr_warn("failed to re-mmap() map '%s': %d\n", - bpf_map__name(map), err); - return libbpf_err(err); - } + *map_skel->mmaped = map->mmaped; } return 0; @@ -13944,8 +13949,8 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s) err = prog->sec_def->prog_attach_fn(prog, prog->sec_def->cookie, link); if (err) { - pr_warn("prog '%s': failed to auto-attach: %d\n", - bpf_program__name(prog), err); + pr_warn("prog '%s': failed to auto-attach: %s\n", + bpf_program__name(prog), errstr(err)); return libbpf_err(err); } @@ -13988,7 +13993,8 @@ int bpf_object__attach_skeleton(struct bpf_object_skeleton *s) *link = bpf_map__attach_struct_ops(map); if (!*link) { err = -errno; - pr_warn("map '%s': failed to auto-attach: %d\n", bpf_map__name(map), err); + pr_warn("map '%s': failed to auto-attach: %s\n", + bpf_map__name(map), errstr(err)); return libbpf_err(err); } } diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 91484303849c80..b2ce3a72b11d6a 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -577,10 +577,12 @@ struct bpf_uprobe_multi_opts { size_t cnt; /* create return uprobes */ bool retprobe; + /* create session kprobes */ + bool session; size_t :0; }; -#define bpf_uprobe_multi_opts__last_field retprobe +#define bpf_uprobe_multi_opts__last_field session /** * @brief **bpf_program__attach_uprobe_multi()** attaches a BPF program diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 0096e483f7eb9e..54b6f312cfa809 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -421,6 +421,8 @@ LIBBPF_1.5.0 { global: btf__distill_base; btf__relocate; + btf_ext__endianness; + btf_ext__set_endianness; bpf_map__autoattach; bpf_map__set_autoattach; bpf_object__token_fd; @@ -428,3 +430,6 @@ LIBBPF_1.5.0 { ring__consume_n; ring_buffer__consume_n; } LIBBPF_1.4.0; + +LIBBPF_1.6.0 { +} LIBBPF_1.5.0; diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 408df59e07719f..de498e2dd6b0bb 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -10,6 +10,7 @@ #define __LIBBPF_LIBBPF_INTERNAL_H #include +#include #include #include #include @@ -448,11 +449,11 @@ struct btf_ext_info { * * The func_info subsection layout: * record size for struct bpf_func_info in the func_info subsection - * struct btf_sec_func_info for section #1 + * struct btf_ext_info_sec for section #1 * a list of bpf_func_info records for section #1 * where struct bpf_func_info mimics one in include/uapi/linux/bpf.h * but may not be identical - * struct btf_sec_func_info for section #2 + * struct btf_ext_info_sec for section #2 * a list of bpf_func_info records for section #2 * ...... * @@ -484,6 +485,8 @@ struct btf_ext { struct btf_ext_header *hdr; void *data; }; + void *data_swapped; + bool swapped_endian; struct btf_ext_info func_info; struct btf_ext_info line_info; struct btf_ext_info core_relo_info; @@ -511,6 +514,32 @@ struct bpf_line_info_min { __u32 line_col; }; +/* Functions to byte-swap info records */ + +typedef void (*info_rec_bswap_fn)(void *); + +static inline void bpf_func_info_bswap(struct bpf_func_info *i) +{ + i->insn_off = bswap_32(i->insn_off); + i->type_id = bswap_32(i->type_id); +} + +static inline void bpf_line_info_bswap(struct bpf_line_info *i) +{ + i->insn_off = bswap_32(i->insn_off); + i->file_name_off = bswap_32(i->file_name_off); + i->line_off = bswap_32(i->line_off); + i->line_col = bswap_32(i->line_col); +} + +static inline void bpf_core_relo_bswap(struct bpf_core_relo *i) +{ + i->insn_off = bswap_32(i->insn_off); + i->type_id = bswap_32(i->type_id); + i->access_str_off = bswap_32(i->access_str_off); + i->kind = bswap_32(i->kind); +} + enum btf_field_iter_kind { BTF_FIELD_ITER_IDS, BTF_FIELD_ITER_STRS, @@ -588,6 +617,16 @@ static inline bool is_ldimm64_insn(struct bpf_insn *insn) return insn->code == (BPF_LD | BPF_IMM | BPF_DW); } +static inline void bpf_insn_bswap(struct bpf_insn *insn) +{ + __u8 tmp_reg = insn->dst_reg; + + insn->dst_reg = insn->src_reg; + insn->src_reg = tmp_reg; + insn->off = bswap_16(insn->off); + insn->imm = bswap_32(insn->imm); +} + /* Unconditionally dup FD, ensuring it doesn't use [0, 2] range. * Original FD is not closed or altered in any other way. * Preserves original FD value, if it's invalid (negative). diff --git a/tools/lib/bpf/libbpf_version.h b/tools/lib/bpf/libbpf_version.h index d6e5eff967cb3f..28c58fb17250e5 100644 --- a/tools/lib/bpf/libbpf_version.h +++ b/tools/lib/bpf/libbpf_version.h @@ -4,6 +4,6 @@ #define __LIBBPF_VERSION_H #define LIBBPF_MAJOR_VERSION 1 -#define LIBBPF_MINOR_VERSION 5 +#define LIBBPF_MINOR_VERSION 6 #endif /* __LIBBPF_VERSION_H */ diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c index e0005c6ade88a2..cf71d149fe26a2 100644 --- a/tools/lib/bpf/linker.c +++ b/tools/lib/bpf/linker.c @@ -20,6 +20,7 @@ #include "btf.h" #include "libbpf_internal.h" #include "strset.h" +#include "str_error.h" #define BTF_EXTERN_SEC ".extern" @@ -135,6 +136,7 @@ struct bpf_linker { int fd; Elf *elf; Elf64_Ehdr *elf_hdr; + bool swapped_endian; /* Output sections metadata */ struct dst_sec *secs; @@ -305,7 +307,7 @@ static int init_output_elf(struct bpf_linker *linker, const char *file) linker->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); if (linker->fd < 0) { err = -errno; - pr_warn("failed to create '%s': %d\n", file, err); + pr_warn("failed to create '%s': %s\n", file, errstr(err)); return err; } @@ -324,13 +326,8 @@ static int init_output_elf(struct bpf_linker *linker, const char *file) linker->elf_hdr->e_machine = EM_BPF; linker->elf_hdr->e_type = ET_REL; -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - linker->elf_hdr->e_ident[EI_DATA] = ELFDATA2LSB; -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - linker->elf_hdr->e_ident[EI_DATA] = ELFDATA2MSB; -#else -#error "Unknown __BYTE_ORDER__" -#endif + /* Set unknown ELF endianness, assign later from input files */ + linker->elf_hdr->e_ident[EI_DATA] = ELFDATANONE; /* STRTAB */ /* initialize strset with an empty string to conform to ELF */ @@ -396,6 +393,8 @@ static int init_output_elf(struct bpf_linker *linker, const char *file) pr_warn_elf("failed to create SYMTAB data"); return -EINVAL; } + /* Ensure libelf translates byte-order of symbol records */ + sec->data->d_type = ELF_T_SYM; str_off = strset__add_str(linker->strtab_strs, sec->sec_name); if (str_off < 0) @@ -539,19 +538,21 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, const struct bpf_linker_file_opts *opts, struct src_obj *obj) { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - const int host_endianness = ELFDATA2LSB; -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - const int host_endianness = ELFDATA2MSB; -#else -#error "Unknown __BYTE_ORDER__" -#endif int err = 0; Elf_Scn *scn; Elf_Data *data; Elf64_Ehdr *ehdr; Elf64_Shdr *shdr; struct src_sec *sec; + unsigned char obj_byteorder; + unsigned char link_byteorder = linker->elf_hdr->e_ident[EI_DATA]; +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + const unsigned char host_byteorder = ELFDATA2LSB; +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + const unsigned char host_byteorder = ELFDATA2MSB; +#else +#error "Unknown __BYTE_ORDER__" +#endif pr_debug("linker: adding object file '%s'...\n", filename); @@ -560,7 +561,7 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, obj->fd = open(filename, O_RDONLY | O_CLOEXEC); if (obj->fd < 0) { err = -errno; - pr_warn("failed to open file '%s': %d\n", filename, err); + pr_warn("failed to open file '%s': %s\n", filename, errstr(err)); return err; } obj->elf = elf_begin(obj->fd, ELF_C_READ_MMAP, NULL); @@ -577,11 +578,25 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, pr_warn_elf("failed to get ELF header for %s", filename); return err; } - if (ehdr->e_ident[EI_DATA] != host_endianness) { + + /* Linker output endianness set by first input object */ + obj_byteorder = ehdr->e_ident[EI_DATA]; + if (obj_byteorder != ELFDATA2LSB && obj_byteorder != ELFDATA2MSB) { err = -EOPNOTSUPP; - pr_warn_elf("unsupported byte order of ELF file %s", filename); + pr_warn("unknown byte order of ELF file %s\n", filename); return err; } + if (link_byteorder == ELFDATANONE) { + linker->elf_hdr->e_ident[EI_DATA] = obj_byteorder; + linker->swapped_endian = obj_byteorder != host_byteorder; + pr_debug("linker: set %s-endian output byte order\n", + obj_byteorder == ELFDATA2MSB ? "big" : "little"); + } else if (link_byteorder != obj_byteorder) { + err = -EOPNOTSUPP; + pr_warn("byte order mismatch with ELF file %s\n", filename); + return err; + } + if (ehdr->e_type != ET_REL || ehdr->e_machine != EM_BPF || ehdr->e_ident[EI_CLASS] != ELFCLASS64) { @@ -656,7 +671,8 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, obj->btf = btf__new(data->d_buf, shdr->sh_size); err = libbpf_get_error(obj->btf); if (err) { - pr_warn("failed to parse .BTF from %s: %d\n", filename, err); + pr_warn("failed to parse .BTF from %s: %s\n", + filename, errstr(err)); return err; } sec->skipped = true; @@ -666,7 +682,8 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, obj->btf_ext = btf_ext__new(data->d_buf, shdr->sh_size); err = libbpf_get_error(obj->btf_ext); if (err) { - pr_warn("failed to parse .BTF.ext from '%s': %d\n", filename, err); + pr_warn("failed to parse .BTF.ext from '%s': %s\n", + filename, errstr(err)); return err; } sec->skipped = true; @@ -1109,6 +1126,24 @@ static bool sec_content_is_same(struct dst_sec *dst_sec, struct src_sec *src_sec return true; } +static bool is_exec_sec(struct dst_sec *sec) +{ + if (!sec || sec->ephemeral) + return false; + return (sec->shdr->sh_type == SHT_PROGBITS) && + (sec->shdr->sh_flags & SHF_EXECINSTR); +} + +static void exec_sec_bswap(void *raw_data, int size) +{ + const int insn_cnt = size / sizeof(struct bpf_insn); + struct bpf_insn *insn = raw_data; + int i; + + for (i = 0; i < insn_cnt; i++, insn++) + bpf_insn_bswap(insn); +} + static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src_sec *src) { void *tmp; @@ -1168,6 +1203,10 @@ static int extend_sec(struct bpf_linker *linker, struct dst_sec *dst, struct src memset(dst->raw_data + dst->sec_sz, 0, dst_align_sz - dst->sec_sz); /* now copy src data at a properly aligned offset */ memcpy(dst->raw_data + dst_align_sz, src->data->d_buf, src->shdr->sh_size); + + /* convert added bpf insns to native byte-order */ + if (linker->swapped_endian && is_exec_sec(dst)) + exec_sec_bswap(dst->raw_data + dst_align_sz, src->shdr->sh_size); } dst->sec_sz = dst_final_sz; @@ -2415,6 +2454,10 @@ static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj) if (glob_sym && glob_sym->var_idx >= 0) { __s64 sz; + /* FUNCs don't have size, nothing to update */ + if (btf_is_func(t)) + continue; + dst_var = &dst_sec->sec_vars[glob_sym->var_idx]; /* Because underlying BTF type might have * changed, so might its size have changed, so @@ -2628,6 +2671,10 @@ int bpf_linker__finalize(struct bpf_linker *linker) if (!sec->scn) continue; + /* restore sections with bpf insns to target byte-order */ + if (linker->swapped_endian && is_exec_sec(sec)) + exec_sec_bswap(sec->raw_data, sec->sec_sz); + sec->data->d_buf = sec->raw_data; } @@ -2696,6 +2743,7 @@ static int emit_elf_data_sec(struct bpf_linker *linker, const char *sec_name, static int finalize_btf(struct bpf_linker *linker) { + enum btf_endianness link_endianness; LIBBPF_OPTS(btf_dedup_opts, opts); struct btf *btf = linker->btf; const void *raw_data; @@ -2729,17 +2777,24 @@ static int finalize_btf(struct bpf_linker *linker) err = finalize_btf_ext(linker); if (err) { - pr_warn(".BTF.ext generation failed: %d\n", err); + pr_warn(".BTF.ext generation failed: %s\n", errstr(err)); return err; } opts.btf_ext = linker->btf_ext; err = btf__dedup(linker->btf, &opts); if (err) { - pr_warn("BTF dedup failed: %d\n", err); + pr_warn("BTF dedup failed: %s\n", errstr(err)); return err; } + /* Set .BTF and .BTF.ext output byte order */ + link_endianness = linker->elf_hdr->e_ident[EI_DATA] == ELFDATA2MSB ? + BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN; + btf__set_endianness(linker->btf, link_endianness); + if (linker->btf_ext) + btf_ext__set_endianness(linker->btf_ext, link_endianness); + /* Emit .BTF section */ raw_data = btf__raw_data(linker->btf, &raw_sz); if (!raw_data) @@ -2747,7 +2802,7 @@ static int finalize_btf(struct bpf_linker *linker) err = emit_elf_data_sec(linker, BTF_ELF_SEC, 8, raw_data, raw_sz); if (err) { - pr_warn("failed to write out .BTF ELF section: %d\n", err); + pr_warn("failed to write out .BTF ELF section: %s\n", errstr(err)); return err; } @@ -2759,7 +2814,7 @@ static int finalize_btf(struct bpf_linker *linker) err = emit_elf_data_sec(linker, BTF_EXT_ELF_SEC, 8, raw_data, raw_sz); if (err) { - pr_warn("failed to write out .BTF.ext ELF section: %d\n", err); + pr_warn("failed to write out .BTF.ext ELF section: %s\n", errstr(err)); return err; } } @@ -2935,7 +2990,7 @@ static int finalize_btf_ext(struct bpf_linker *linker) err = libbpf_get_error(linker->btf_ext); if (err) { linker->btf_ext = NULL; - pr_warn("failed to parse final .BTF.ext data: %d\n", err); + pr_warn("failed to parse final .BTF.ext data: %s\n", errstr(err)); goto out; } diff --git a/tools/lib/bpf/relo_core.c b/tools/lib/bpf/relo_core.c index 63a4d5ad12d1a3..7632e9d4182717 100644 --- a/tools/lib/bpf/relo_core.c +++ b/tools/lib/bpf/relo_core.c @@ -1339,7 +1339,7 @@ int bpf_core_calc_relo_insn(const char *prog_name, cands->cands[i].id, cand_spec); if (err < 0) { bpf_core_format_spec(spec_buf, sizeof(spec_buf), cand_spec); - pr_warn("prog '%s': relo #%d: error matching candidate #%d %s: %d\n ", + pr_warn("prog '%s': relo #%d: error matching candidate #%d %s: %d\n", prog_name, relo_idx, i, spec_buf, err); return err; } diff --git a/tools/lib/bpf/ringbuf.c b/tools/lib/bpf/ringbuf.c index bfd8dac4c0cc0c..9702b70da444c5 100644 --- a/tools/lib/bpf/ringbuf.c +++ b/tools/lib/bpf/ringbuf.c @@ -21,6 +21,7 @@ #include "libbpf.h" #include "libbpf_internal.h" #include "bpf.h" +#include "str_error.h" struct ring { ring_buffer_sample_fn sample_cb; @@ -88,8 +89,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd, err = bpf_map_get_info_by_fd(map_fd, &info, &len); if (err) { err = -errno; - pr_warn("ringbuf: failed to get map info for fd=%d: %d\n", - map_fd, err); + pr_warn("ringbuf: failed to get map info for fd=%d: %s\n", + map_fd, errstr(err)); return libbpf_err(err); } @@ -123,8 +124,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd, tmp = mmap(NULL, rb->page_size, PROT_READ | PROT_WRITE, MAP_SHARED, map_fd, 0); if (tmp == MAP_FAILED) { err = -errno; - pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %d\n", - map_fd, err); + pr_warn("ringbuf: failed to mmap consumer page for map fd=%d: %s\n", + map_fd, errstr(err)); goto err_out; } r->consumer_pos = tmp; @@ -142,8 +143,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd, tmp = mmap(NULL, (size_t)mmap_sz, PROT_READ, MAP_SHARED, map_fd, rb->page_size); if (tmp == MAP_FAILED) { err = -errno; - pr_warn("ringbuf: failed to mmap data pages for map fd=%d: %d\n", - map_fd, err); + pr_warn("ringbuf: failed to mmap data pages for map fd=%d: %s\n", + map_fd, errstr(err)); goto err_out; } r->producer_pos = tmp; @@ -156,8 +157,8 @@ int ring_buffer__add(struct ring_buffer *rb, int map_fd, e->data.fd = rb->ring_cnt; if (epoll_ctl(rb->epoll_fd, EPOLL_CTL_ADD, map_fd, e) < 0) { err = -errno; - pr_warn("ringbuf: failed to epoll add map fd=%d: %d\n", - map_fd, err); + pr_warn("ringbuf: failed to epoll add map fd=%d: %s\n", + map_fd, errstr(err)); goto err_out; } @@ -205,7 +206,7 @@ ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void *ctx, rb->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (rb->epoll_fd < 0) { err = -errno; - pr_warn("ringbuf: failed to create epoll instance: %d\n", err); + pr_warn("ringbuf: failed to create epoll instance: %s\n", errstr(err)); goto err_out; } @@ -458,7 +459,8 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd) err = bpf_map_get_info_by_fd(map_fd, &info, &len); if (err) { err = -errno; - pr_warn("user ringbuf: failed to get map info for fd=%d: %d\n", map_fd, err); + pr_warn("user ringbuf: failed to get map info for fd=%d: %s\n", + map_fd, errstr(err)); return err; } @@ -474,8 +476,8 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd) tmp = mmap(NULL, rb->page_size, PROT_READ, MAP_SHARED, map_fd, 0); if (tmp == MAP_FAILED) { err = -errno; - pr_warn("user ringbuf: failed to mmap consumer page for map fd=%d: %d\n", - map_fd, err); + pr_warn("user ringbuf: failed to mmap consumer page for map fd=%d: %s\n", + map_fd, errstr(err)); return err; } rb->consumer_pos = tmp; @@ -494,8 +496,8 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd) map_fd, rb->page_size); if (tmp == MAP_FAILED) { err = -errno; - pr_warn("user ringbuf: failed to mmap data pages for map fd=%d: %d\n", - map_fd, err); + pr_warn("user ringbuf: failed to mmap data pages for map fd=%d: %s\n", + map_fd, errstr(err)); return err; } @@ -506,7 +508,7 @@ static int user_ringbuf_map(struct user_ring_buffer *rb, int map_fd) rb_epoll->events = EPOLLOUT; if (epoll_ctl(rb->epoll_fd, EPOLL_CTL_ADD, map_fd, rb_epoll) < 0) { err = -errno; - pr_warn("user ringbuf: failed to epoll add map fd=%d: %d\n", map_fd, err); + pr_warn("user ringbuf: failed to epoll add map fd=%d: %s\n", map_fd, errstr(err)); return err; } @@ -531,7 +533,7 @@ user_ring_buffer__new(int map_fd, const struct user_ring_buffer_opts *opts) rb->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (rb->epoll_fd < 0) { err = -errno; - pr_warn("user ringbuf: failed to create epoll instance: %d\n", err); + pr_warn("user ringbuf: failed to create epoll instance: %s\n", errstr(err)); goto err_out; } diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h index 0875452521e96a..4d5fa079b5d626 100644 --- a/tools/lib/bpf/skel_internal.h +++ b/tools/lib/bpf/skel_internal.h @@ -351,10 +351,11 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts) attr.test.ctx_size_in = opts->ctx->sz; err = skel_sys_bpf(BPF_PROG_RUN, &attr, test_run_attr_sz); if (err < 0 || (int)attr.test.retval < 0) { - opts->errstr = "failed to execute loader prog"; if (err < 0) { + opts->errstr = "failed to execute loader prog"; set_err; } else { + opts->errstr = "error returned by loader prog"; err = (int)attr.test.retval; #ifndef __KERNEL__ errno = -err; diff --git a/tools/lib/bpf/str_error.c b/tools/lib/bpf/str_error.c index 5e6a1e27ddf90b..8743049e32b7d4 100644 --- a/tools/lib/bpf/str_error.c +++ b/tools/lib/bpf/str_error.c @@ -5,6 +5,10 @@ #include #include "str_error.h" +#ifndef ENOTSUPP +#define ENOTSUPP 524 +#endif + /* make sure libbpf doesn't use kernel-only integer typedefs */ #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64 @@ -31,3 +35,70 @@ char *libbpf_strerror_r(int err, char *dst, int len) } return dst; } + +const char *errstr(int err) +{ + static __thread char buf[12]; + + if (err > 0) + err = -err; + + switch (err) { + case -E2BIG: return "-E2BIG"; + case -EACCES: return "-EACCES"; + case -EADDRINUSE: return "-EADDRINUSE"; + case -EADDRNOTAVAIL: return "-EADDRNOTAVAIL"; + case -EAGAIN: return "-EAGAIN"; + case -EALREADY: return "-EALREADY"; + case -EBADF: return "-EBADF"; + case -EBADFD: return "-EBADFD"; + case -EBUSY: return "-EBUSY"; + case -ECANCELED: return "-ECANCELED"; + case -ECHILD: return "-ECHILD"; + case -EDEADLK: return "-EDEADLK"; + case -EDOM: return "-EDOM"; + case -EEXIST: return "-EEXIST"; + case -EFAULT: return "-EFAULT"; + case -EFBIG: return "-EFBIG"; + case -EILSEQ: return "-EILSEQ"; + case -EINPROGRESS: return "-EINPROGRESS"; + case -EINTR: return "-EINTR"; + case -EINVAL: return "-EINVAL"; + case -EIO: return "-EIO"; + case -EISDIR: return "-EISDIR"; + case -ELOOP: return "-ELOOP"; + case -EMFILE: return "-EMFILE"; + case -EMLINK: return "-EMLINK"; + case -EMSGSIZE: return "-EMSGSIZE"; + case -ENAMETOOLONG: return "-ENAMETOOLONG"; + case -ENFILE: return "-ENFILE"; + case -ENODATA: return "-ENODATA"; + case -ENODEV: return "-ENODEV"; + case -ENOENT: return "-ENOENT"; + case -ENOEXEC: return "-ENOEXEC"; + case -ENOLINK: return "-ENOLINK"; + case -ENOMEM: return "-ENOMEM"; + case -ENOSPC: return "-ENOSPC"; + case -ENOTBLK: return "-ENOTBLK"; + case -ENOTDIR: return "-ENOTDIR"; + case -ENOTSUPP: return "-ENOTSUPP"; + case -ENOTTY: return "-ENOTTY"; + case -ENXIO: return "-ENXIO"; + case -EOPNOTSUPP: return "-EOPNOTSUPP"; + case -EOVERFLOW: return "-EOVERFLOW"; + case -EPERM: return "-EPERM"; + case -EPIPE: return "-EPIPE"; + case -EPROTO: return "-EPROTO"; + case -EPROTONOSUPPORT: return "-EPROTONOSUPPORT"; + case -ERANGE: return "-ERANGE"; + case -EROFS: return "-EROFS"; + case -ESPIPE: return "-ESPIPE"; + case -ESRCH: return "-ESRCH"; + case -ETXTBSY: return "-ETXTBSY"; + case -EUCLEAN: return "-EUCLEAN"; + case -EXDEV: return "-EXDEV"; + default: + snprintf(buf, sizeof(buf), "%d", err); + return buf; + } +} diff --git a/tools/lib/bpf/str_error.h b/tools/lib/bpf/str_error.h index 626d7ffb03d60d..66ffebde0684aa 100644 --- a/tools/lib/bpf/str_error.h +++ b/tools/lib/bpf/str_error.h @@ -6,4 +6,11 @@ char *libbpf_strerror_r(int err, char *dst, int len); +/** + * @brief **errstr()** returns string corresponding to numeric errno + * @param err negative numeric errno + * @return pointer to string representation of the errno, that is invalidated + * upon the next call. + */ +const char *errstr(int err); #endif /* __LIBBPF_STR_ERROR_H */ diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c index 93794f01bb67cb..5f085736c6c45d 100644 --- a/tools/lib/bpf/usdt.c +++ b/tools/lib/bpf/usdt.c @@ -20,6 +20,7 @@ #include "libbpf_common.h" #include "libbpf_internal.h" #include "hashmap.h" +#include "str_error.h" /* libbpf's USDT support consists of BPF-side state/code and user-space * state/code working together in concert. BPF-side parts are defined in @@ -465,8 +466,8 @@ static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs, goto proceed; if (!realpath(lib_path, path)) { - pr_warn("usdt: failed to get absolute path of '%s' (err %d), using path as is...\n", - lib_path, -errno); + pr_warn("usdt: failed to get absolute path of '%s' (err %s), using path as is...\n", + lib_path, errstr(-errno)); libbpf_strlcpy(path, lib_path, sizeof(path)); } @@ -475,8 +476,8 @@ static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs, f = fopen(line, "re"); if (!f) { err = -errno; - pr_warn("usdt: failed to open '%s' to get base addr of '%s': %d\n", - line, lib_path, err); + pr_warn("usdt: failed to open '%s' to get base addr of '%s': %s\n", + line, lib_path, errstr(err)); return err; } @@ -606,7 +607,8 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char * err = parse_elf_segs(elf, path, &segs, &seg_cnt); if (err) { - pr_warn("usdt: failed to process ELF program segments for '%s': %d\n", path, err); + pr_warn("usdt: failed to process ELF program segments for '%s': %s\n", + path, errstr(err)); goto err_out; } @@ -708,8 +710,8 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char * if (vma_seg_cnt == 0) { err = parse_vma_segs(pid, path, &vma_segs, &vma_seg_cnt); if (err) { - pr_warn("usdt: failed to get memory segments in PID %d for shared library '%s': %d\n", - pid, path, err); + pr_warn("usdt: failed to get memory segments in PID %d for shared library '%s': %s\n", + pid, path, errstr(err)); goto err_out; } } @@ -1047,8 +1049,8 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct if (is_new && bpf_map_update_elem(spec_map_fd, &spec_id, &target->spec, BPF_ANY)) { err = -errno; - pr_warn("usdt: failed to set USDT spec #%d for '%s:%s' in '%s': %d\n", - spec_id, usdt_provider, usdt_name, path, err); + pr_warn("usdt: failed to set USDT spec #%d for '%s:%s' in '%s': %s\n", + spec_id, usdt_provider, usdt_name, path, errstr(err)); goto err_out; } if (!man->has_bpf_cookie && @@ -1058,9 +1060,9 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct pr_warn("usdt: IP collision detected for spec #%d for '%s:%s' in '%s'\n", spec_id, usdt_provider, usdt_name, path); } else { - pr_warn("usdt: failed to map IP 0x%lx to spec #%d for '%s:%s' in '%s': %d\n", + pr_warn("usdt: failed to map IP 0x%lx to spec #%d for '%s:%s' in '%s': %s\n", target->abs_ip, spec_id, usdt_provider, usdt_name, - path, err); + path, errstr(err)); } goto err_out; } @@ -1076,8 +1078,8 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct target->rel_ip, &opts); err = libbpf_get_error(uprobe_link); if (err) { - pr_warn("usdt: failed to attach uprobe #%d for '%s:%s' in '%s': %d\n", - i, usdt_provider, usdt_name, path, err); + pr_warn("usdt: failed to attach uprobe #%d for '%s:%s' in '%s': %s\n", + i, usdt_provider, usdt_name, path, errstr(err)); goto err_out; } @@ -1099,8 +1101,8 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct NULL, &opts_multi); if (!link->multi_link) { err = -errno; - pr_warn("usdt: failed to attach uprobe multi for '%s:%s' in '%s': %d\n", - usdt_provider, usdt_name, path, err); + pr_warn("usdt: failed to attach uprobe multi for '%s:%s' in '%s': %s\n", + usdt_provider, usdt_name, path, errstr(err)); goto err_out; } diff --git a/tools/lib/bpf/zip.c b/tools/lib/bpf/zip.c index 3f26d629b2b498..88c376a8348d1f 100644 --- a/tools/lib/bpf/zip.c +++ b/tools/lib/bpf/zip.c @@ -223,7 +223,7 @@ struct zip_archive *zip_archive_open(const char *path) if (!archive) { munmap(data, size); return ERR_PTR(-ENOMEM); - }; + } archive->data = data; archive->size = size; diff --git a/tools/lib/list_sort.c b/tools/lib/list_sort.c index 69affa251fa78d..bb99e493dcd101 100644 --- a/tools/lib/list_sort.c +++ b/tools/lib/list_sort.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include #include -#include #include #include diff --git a/tools/lib/perf/Documentation/Makefile b/tools/lib/perf/Documentation/Makefile index 972754082a8547..573ca5b2755677 100644 --- a/tools/lib/perf/Documentation/Makefile +++ b/tools/lib/perf/Documentation/Makefile @@ -121,7 +121,7 @@ install-man: all $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir); \ $(INSTALL) -m 644 $(MAN_7) $(DESTDIR)$(man7dir); -install-html: +install-html: $(MAN_HTML) $(call QUIET_INSTALL, html) \ $(INSTALL) -d -m 755 $(DESTDIR)$(htmldir); \ $(INSTALL) -m 644 $(MAN_HTML) $(DESTDIR)$(htmldir); \ diff --git a/tools/lib/perf/evlist.c b/tools/lib/perf/evlist.c index c6d67fc9e57ef0..83c43dc13313cc 100644 --- a/tools/lib/perf/evlist.c +++ b/tools/lib/perf/evlist.c @@ -47,6 +47,20 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, */ perf_cpu_map__put(evsel->cpus); evsel->cpus = perf_cpu_map__intersect(evlist->user_requested_cpus, evsel->own_cpus); + + /* + * Empty cpu lists would eventually get opened as "any" so remove + * genuinely empty ones before they're opened in the wrong place. + */ + if (perf_cpu_map__is_empty(evsel->cpus)) { + struct perf_evsel *next = perf_evlist__next(evlist, evsel); + + perf_evlist__remove(evlist, evsel); + /* Keep idx contiguous */ + if (next) + list_for_each_entry_from(next, &evlist->entries, node) + next->idx--; + } } else if (!evsel->own_cpus || evlist->has_user_cpus || (!evsel->requires_cpu && perf_cpu_map__has_any_cpu(evlist->user_requested_cpus))) { /* @@ -80,11 +94,11 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, static void perf_evlist__propagate_maps(struct perf_evlist *evlist) { - struct perf_evsel *evsel; + struct perf_evsel *evsel, *n; evlist->needs_map_propagation = true; - perf_evlist__for_each_evsel(evlist, evsel) + list_for_each_entry_safe(evsel, n, &evlist->entries, node) __perf_evlist__propagate_maps(evlist, evsel); } diff --git a/tools/lib/perf/evsel.c b/tools/lib/perf/evsel.c index c07160953224ad..c475319e2e410d 100644 --- a/tools/lib/perf/evsel.c +++ b/tools/lib/perf/evsel.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr, int idx) { INIT_LIST_HEAD(&evsel->node); + INIT_LIST_HEAD(&evsel->per_stream_periods); evsel->attr = *attr; evsel->idx = idx; evsel->leader = evsel; @@ -531,10 +533,56 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) void perf_evsel__free_id(struct perf_evsel *evsel) { + struct perf_sample_id_period *pos, *n; + xyarray__delete(evsel->sample_id); evsel->sample_id = NULL; zfree(&evsel->id); evsel->ids = 0; + + perf_evsel_for_each_per_thread_period_safe(evsel, n, pos) { + list_del_init(&pos->node); + free(pos); + } +} + +bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel *evsel) +{ + return (evsel->attr.sample_type & PERF_SAMPLE_READ) && + (evsel->attr.sample_type & PERF_SAMPLE_TID) && + evsel->attr.inherit; +} + +u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, bool per_thread) +{ + struct hlist_head *head; + struct perf_sample_id_period *res; + int hash; + + if (!per_thread) + return &sid->period; + + hash = hash_32(tid, PERF_SAMPLE_ID__HLIST_BITS); + head = &sid->periods[hash]; + + hlist_for_each_entry(res, head, hnode) + if (res->tid == tid) + return &res->period; + + if (sid->evsel == NULL) + return NULL; + + res = zalloc(sizeof(struct perf_sample_id_period)); + if (res == NULL) + return NULL; + + INIT_LIST_HEAD(&res->node); + res->tid = tid; + + list_add_tail(&res->node, &sid->evsel->per_stream_periods); + hlist_add_head(&res->hnode, &sid->periods[hash]); + + return &res->period; } void perf_counts_values__scale(struct perf_counts_values *count, diff --git a/tools/lib/perf/include/internal/evsel.h b/tools/lib/perf/include/internal/evsel.h index 5cd220a61962e1..ea78defa77d0be 100644 --- a/tools/lib/perf/include/internal/evsel.h +++ b/tools/lib/perf/include/internal/evsel.h @@ -11,6 +11,32 @@ struct perf_thread_map; struct xyarray; +/** + * The per-thread accumulated period storage node. + */ +struct perf_sample_id_period { + struct list_head node; + struct hlist_node hnode; + /* Holds total ID period value for PERF_SAMPLE_READ processing. */ + u64 period; + /* The TID that the values belongs to */ + u32 tid; +}; + +/** + * perf_evsel_for_each_per_thread_period_safe - safely iterate thru all the + * per_stream_periods + * @evlist:perf_evsel instance to iterate + * @item: struct perf_sample_id_period iterator + * @tmp: struct perf_sample_id_period temp iterator + */ +#define perf_evsel_for_each_per_thread_period_safe(evsel, tmp, item) \ + list_for_each_entry_safe(item, tmp, &(evsel)->per_stream_periods, node) + + +#define PERF_SAMPLE_ID__HLIST_BITS 4 +#define PERF_SAMPLE_ID__HLIST_SIZE (1 << PERF_SAMPLE_ID__HLIST_BITS) + /* * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are * more than one entry in the evlist. @@ -34,8 +60,32 @@ struct perf_sample_id { pid_t machine_pid; struct perf_cpu vcpu; - /* Holds total ID period value for PERF_SAMPLE_READ processing. */ - u64 period; + /* + * Per-thread, and global event counts are mutually exclusive: + * Whilst it is possible to combine events into a group with differing + * values of PERF_SAMPLE_READ, it is not valid to have inconsistent + * values for `inherit`. Therefore it is not possible to have a + * situation where a per-thread event is sampled as a global event; + * all !inherit groups are global, and all groups where the sampling + * event is inherit + PERF_SAMPLE_READ will be per-thread. Any event + * that is part of such a group that is inherit but not PERF_SAMPLE_READ + * will be read as per-thread. If such an event can also trigger a + * sample (such as with sample_period > 0) then it will not cause + * `read_format` to be included in its PERF_RECORD_SAMPLE, and + * therefore will not expose the per-thread group members as global. + */ + union { + /* + * Holds total ID period value for PERF_SAMPLE_READ processing + * (when period is not per-thread). + */ + u64 period; + /* + * Holds total ID period value for PERF_SAMPLE_READ processing + * (when period is per-thread). + */ + struct hlist_head periods[PERF_SAMPLE_ID__HLIST_SIZE]; + }; }; struct perf_evsel { @@ -58,6 +108,10 @@ struct perf_evsel { u32 ids; struct perf_evsel *leader; + /* For events where the read_format value is per-thread rather than + * global, stores the per-thread cumulative period */ + struct list_head per_stream_periods; + /* parse modifier helper */ int nr_members; /* @@ -88,4 +142,9 @@ int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter); int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); void perf_evsel__free_id(struct perf_evsel *evsel); +bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel *evsel); + +u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, + bool per_thread); + #endif /* __LIBPERF_INTERNAL_EVSEL_H */ diff --git a/tools/lib/subcmd/parse-options.c b/tools/lib/subcmd/parse-options.c index eb896d30545b63..555d617c1f502a 100644 --- a/tools/lib/subcmd/parse-options.c +++ b/tools/lib/subcmd/parse-options.c @@ -807,7 +807,7 @@ static int option__cmp(const void *va, const void *vb) static struct option *options__order(const struct option *opts) { int nr_opts = 0, nr_group = 0, nr_parent = 0, len; - const struct option *o, *p = opts; + const struct option *o = NULL, *p = opts; struct option *opt, *ordered = NULL, *group; /* flatten the options that have parents */ diff --git a/tools/lib/subcmd/run-command.c b/tools/lib/subcmd/run-command.c index 4e3a557a2f3741..0a764c25c384f0 100644 --- a/tools/lib/subcmd/run-command.c +++ b/tools/lib/subcmd/run-command.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -217,8 +218,40 @@ static int wait_or_whine(struct child_process *cmd, bool block) int check_if_command_finished(struct child_process *cmd) { +#ifdef __linux__ + char filename[FILENAME_MAX + 12]; + char status_line[256]; + FILE *status_file; + + /* + * Check by reading /proc//status as calling waitpid causes + * stdout/stderr to be closed and data lost. + */ + sprintf(filename, "/proc/%d/status", cmd->pid); + status_file = fopen(filename, "r"); + if (status_file == NULL) { + /* Open failed assume finish_command was called. */ + return true; + } + while (fgets(status_line, sizeof(status_line), status_file) != NULL) { + char *p; + + if (strncmp(status_line, "State:", 6)) + continue; + + fclose(status_file); + p = status_line + 6; + while (isspace(*p)) + p++; + return *p == 'Z' ? 1 : 0; + } + /* Read failed assume finish_command was called. */ + fclose(status_file); + return 1; +#else wait_or_whine(cmd, /*block=*/false); return cmd->finished; +#endif } int finish_command(struct child_process *cmd) diff --git a/tools/lib/subcmd/subcmd-util.h b/tools/lib/subcmd/subcmd-util.h index dfac76e35ac73d..c742b08815dcbf 100644 --- a/tools/lib/subcmd/subcmd-util.h +++ b/tools/lib/subcmd/subcmd-util.h @@ -20,8 +20,8 @@ static __noreturn inline void die(const char *err, ...) va_start(params, err); report(" Fatal: ", err, params); - exit(128); va_end(params); + exit(128); } #define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) diff --git a/tools/lib/thermal/commands.c b/tools/lib/thermal/commands.c index 73d4d4e8d6ec0b..4998cec793ed86 100644 --- a/tools/lib/thermal/commands.c +++ b/tools/lib/thermal/commands.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "thermal_nl.h" @@ -33,6 +34,11 @@ static struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = { [THERMAL_GENL_ATTR_CDEV_CUR_STATE] = { .type = NLA_U32 }, [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 }, [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING }, + + /* Thresholds */ + [THERMAL_GENL_ATTR_THRESHOLD] = { .type = NLA_NESTED }, + [THERMAL_GENL_ATTR_THRESHOLD_TEMP] = { .type = NLA_U32 }, + [THERMAL_GENL_ATTR_THRESHOLD_DIRECTION] = { .type = NLA_U32 }, }; static int parse_tz_get(struct genl_info *info, struct thermal_zone **tz) @@ -182,6 +188,48 @@ static int parse_tz_get_gov(struct genl_info *info, struct thermal_zone *tz) return THERMAL_SUCCESS; } +static int parse_threshold_get(struct genl_info *info, struct thermal_zone *tz) +{ + struct nlattr *attr; + struct thermal_threshold *__tt = NULL; + size_t size = 0; + int rem; + + /* + * The size contains the size of the array and we want to + * access the last element, size - 1. + * + * The variable size is initialized to zero but it will be + * then incremented by the first if() statement. The message + * attributes are ordered, so the first if() statement will be + * always called before the second one. If it happens that is + * not the case, then it is a kernel bug. + */ + nla_for_each_nested(attr, info->attrs[THERMAL_GENL_ATTR_THRESHOLD], rem) { + + if (nla_type(attr) == THERMAL_GENL_ATTR_THRESHOLD_TEMP) { + + size++; + + __tt = realloc(__tt, sizeof(*__tt) * (size + 2)); + if (!__tt) + return THERMAL_ERROR; + + __tt[size - 1].temperature = nla_get_u32(attr); + } + + if (nla_type(attr) == THERMAL_GENL_ATTR_THRESHOLD_DIRECTION) + __tt[size - 1].direction = nla_get_u32(attr); + } + + if (__tt) + __tt[size].temperature = INT_MAX; + + tz->thresholds = __tt; + + return THERMAL_SUCCESS; +} + static int handle_netlink(struct nl_cache_ops *unused, struct genl_cmd *cmd, struct genl_info *info, void *arg) @@ -210,6 +258,10 @@ static int handle_netlink(struct nl_cache_ops *unused, ret = parse_tz_get_gov(info, arg); break; + case THERMAL_GENL_CMD_THRESHOLD_GET: + ret = parse_threshold_get(info, arg); + break; + default: return THERMAL_ERROR; } @@ -253,6 +305,34 @@ static struct genl_cmd thermal_cmds[] = { .c_maxattr = THERMAL_GENL_ATTR_MAX, .c_attr_policy = thermal_genl_policy, }, + { + .c_id = THERMAL_GENL_CMD_THRESHOLD_GET, + .c_name = (char *)"Get thresholds list", + .c_msg_parser = handle_netlink, + .c_maxattr = THERMAL_GENL_ATTR_MAX, + .c_attr_policy = thermal_genl_policy, + }, + { + .c_id = THERMAL_GENL_CMD_THRESHOLD_ADD, + .c_name = (char *)"Add a threshold", + .c_msg_parser = handle_netlink, + .c_maxattr = THERMAL_GENL_ATTR_MAX, + .c_attr_policy = thermal_genl_policy, + }, + { + .c_id = THERMAL_GENL_CMD_THRESHOLD_DELETE, + .c_name = (char *)"Delete a threshold", + .c_msg_parser = handle_netlink, + .c_maxattr = THERMAL_GENL_ATTR_MAX, + .c_attr_policy = thermal_genl_policy, + }, + { + .c_id = THERMAL_GENL_CMD_THRESHOLD_FLUSH, + .c_name = (char *)"Flush the thresholds", + .c_msg_parser = handle_netlink, + .c_maxattr = THERMAL_GENL_ATTR_MAX, + .c_attr_policy = thermal_genl_policy, + }, }; static struct genl_ops thermal_cmd_ops = { @@ -261,9 +341,41 @@ static struct genl_ops thermal_cmd_ops = { .o_ncmds = ARRAY_SIZE(thermal_cmds), }; -static thermal_error_t thermal_genl_auto(struct thermal_handler *th, int id, int cmd, - int flags, void *arg) +struct cmd_param { + int tz_id; + int temp; + int direction; +}; + +typedef int (*cmd_cb_t)(struct nl_msg *, struct cmd_param *); + +static int thermal_genl_tz_id_encode(struct nl_msg *msg, struct cmd_param *p) { + if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id)) + return -1; + + return 0; +} + +static int thermal_genl_threshold_encode(struct nl_msg *msg, struct cmd_param *p) +{ + if (thermal_genl_tz_id_encode(msg, p)) + return -1; + + if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_TEMP, p->temp)) + return -1; + + if (nla_put_u32(msg, THERMAL_GENL_ATTR_THRESHOLD_DIRECTION, p->direction)) + return -1; + + return 0; +} + +static thermal_error_t thermal_genl_auto(struct thermal_handler *th, cmd_cb_t cmd_cb, + struct cmd_param *param, + int cmd, int flags, void *arg) +{ + thermal_error_t ret = THERMAL_ERROR; struct nl_msg *msg; void *hdr; @@ -274,45 +386,95 @@ static thermal_error_t thermal_genl_auto(struct thermal_handler *th, int id, int hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, thermal_cmd_ops.o_id, 0, flags, cmd, THERMAL_GENL_VERSION); if (!hdr) - return THERMAL_ERROR; + goto out; - if (id >= 0 && nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_ID, id)) - return THERMAL_ERROR; + if (cmd_cb && cmd_cb(msg, param)) + goto out; if (nl_send_msg(th->sk_cmd, th->cb_cmd, msg, genl_handle_msg, arg)) - return THERMAL_ERROR; + goto out; + ret = THERMAL_SUCCESS; +out: nlmsg_free(msg); - return THERMAL_SUCCESS; + return ret; } thermal_error_t thermal_cmd_get_tz(struct thermal_handler *th, struct thermal_zone **tz) { - return thermal_genl_auto(th, -1, THERMAL_GENL_CMD_TZ_GET_ID, + return thermal_genl_auto(th, NULL, NULL, THERMAL_GENL_CMD_TZ_GET_ID, NLM_F_DUMP | NLM_F_ACK, tz); } thermal_error_t thermal_cmd_get_cdev(struct thermal_handler *th, struct thermal_cdev **tc) { - return thermal_genl_auto(th, -1, THERMAL_GENL_CMD_CDEV_GET, + return thermal_genl_auto(th, NULL, NULL, THERMAL_GENL_CMD_CDEV_GET, NLM_F_DUMP | NLM_F_ACK, tc); } thermal_error_t thermal_cmd_get_trip(struct thermal_handler *th, struct thermal_zone *tz) { - return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_TRIP, - 0, tz); + struct cmd_param p = { .tz_id = tz->id }; + + return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p, + THERMAL_GENL_CMD_TZ_GET_TRIP, 0, tz); } thermal_error_t thermal_cmd_get_governor(struct thermal_handler *th, struct thermal_zone *tz) { - return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_GOV, 0, tz); + struct cmd_param p = { .tz_id = tz->id }; + + return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p, + THERMAL_GENL_CMD_TZ_GET_GOV, 0, tz); } thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th, struct thermal_zone *tz) { - return thermal_genl_auto(th, tz->id, THERMAL_GENL_CMD_TZ_GET_TEMP, 0, tz); + struct cmd_param p = { .tz_id = tz->id }; + + return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p, + THERMAL_GENL_CMD_TZ_GET_TEMP, 0, tz); +} + +thermal_error_t thermal_cmd_threshold_get(struct thermal_handler *th, + struct thermal_zone *tz) +{ + struct cmd_param p = { .tz_id = tz->id }; + + return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p, + THERMAL_GENL_CMD_THRESHOLD_GET, 0, tz); +} + +thermal_error_t thermal_cmd_threshold_add(struct thermal_handler *th, + struct thermal_zone *tz, + int temperature, + int direction) +{ + struct cmd_param p = { .tz_id = tz->id, .temp = temperature, .direction = direction }; + + return thermal_genl_auto(th, thermal_genl_threshold_encode, &p, + THERMAL_GENL_CMD_THRESHOLD_ADD, 0, tz); +} + +thermal_error_t thermal_cmd_threshold_delete(struct thermal_handler *th, + struct thermal_zone *tz, + int temperature, + int direction) +{ + struct cmd_param p = { .tz_id = tz->id, .temp = temperature, .direction = direction }; + + return thermal_genl_auto(th, thermal_genl_threshold_encode, &p, + THERMAL_GENL_CMD_THRESHOLD_DELETE, 0, tz); +} + +thermal_error_t thermal_cmd_threshold_flush(struct thermal_handler *th, + struct thermal_zone *tz) +{ + struct cmd_param p = { .tz_id = tz->id }; + + return thermal_genl_auto(th, thermal_genl_tz_id_encode, &p, + THERMAL_GENL_CMD_THRESHOLD_FLUSH, 0, tz); } thermal_error_t thermal_cmd_exit(struct thermal_handler *th) diff --git a/tools/lib/thermal/events.c b/tools/lib/thermal/events.c index a7a55d1a0c4c32..bd851c8690294e 100644 --- a/tools/lib/thermal/events.c +++ b/tools/lib/thermal/events.c @@ -94,6 +94,30 @@ static int handle_thermal_event(struct nl_msg *n, void *arg) case THERMAL_GENL_EVENT_TZ_GOV_CHANGE: return ops->gov_change(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), nla_get_string(attrs[THERMAL_GENL_ATTR_GOV_NAME]), arg); + + case THERMAL_GENL_EVENT_THRESHOLD_ADD: + return ops->threshold_add(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), + nla_get_u32(attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]), + nla_get_u32(attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]), arg); + + case THERMAL_GENL_EVENT_THRESHOLD_DELETE: + return ops->threshold_delete(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), + nla_get_u32(attrs[THERMAL_GENL_ATTR_THRESHOLD_TEMP]), + nla_get_u32(attrs[THERMAL_GENL_ATTR_THRESHOLD_DIRECTION]), arg); + + case THERMAL_GENL_EVENT_THRESHOLD_FLUSH: + return ops->threshold_flush(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), arg); + + case THERMAL_GENL_EVENT_THRESHOLD_UP: + return ops->threshold_up(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), + nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]), + nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_PREV_TEMP]), arg); + + case THERMAL_GENL_EVENT_THRESHOLD_DOWN: + return ops->threshold_down(nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]), + nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]), + nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_PREV_TEMP]), arg); + default: return -1; } @@ -101,19 +125,24 @@ static int handle_thermal_event(struct nl_msg *n, void *arg) static void thermal_events_ops_init(struct thermal_events_ops *ops) { - enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create; - enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete; - enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable; - enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable; - enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high; - enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low; - enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change; - enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add; - enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete; - enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add; - enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete; - enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update; - enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = !!ops->gov_change; + enabled_ops[THERMAL_GENL_EVENT_TZ_CREATE] = !!ops->tz_create; + enabled_ops[THERMAL_GENL_EVENT_TZ_DELETE] = !!ops->tz_delete; + enabled_ops[THERMAL_GENL_EVENT_TZ_DISABLE] = !!ops->tz_disable; + enabled_ops[THERMAL_GENL_EVENT_TZ_ENABLE] = !!ops->tz_enable; + enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_UP] = !!ops->trip_high; + enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = !!ops->trip_low; + enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = !!ops->trip_change; + enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_ADD] = !!ops->trip_add; + enabled_ops[THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = !!ops->trip_delete; + enabled_ops[THERMAL_GENL_EVENT_CDEV_ADD] = !!ops->cdev_add; + enabled_ops[THERMAL_GENL_EVENT_CDEV_DELETE] = !!ops->cdev_delete; + enabled_ops[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = !!ops->cdev_update; + enabled_ops[THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = !!ops->gov_change; + enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_ADD] = !!ops->threshold_add; + enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_DELETE] = !!ops->threshold_delete; + enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_FLUSH] = !!ops->threshold_flush; + enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_UP] = !!ops->threshold_up; + enabled_ops[THERMAL_GENL_EVENT_THRESHOLD_DOWN] = !!ops->threshold_down; } thermal_error_t thermal_events_handle(struct thermal_handler *th, void *arg) diff --git a/tools/lib/thermal/include/thermal.h b/tools/lib/thermal/include/thermal.h index 1abc560602cfb9..818ecdfb46e509 100644 --- a/tools/lib/thermal/include/thermal.h +++ b/tools/lib/thermal/include/thermal.h @@ -4,11 +4,20 @@ #define __LIBTHERMAL_H #include +#include #ifndef LIBTHERMAL_API #define LIBTHERMAL_API __attribute__((visibility("default"))) #endif +#ifndef THERMAL_THRESHOLD_WAY_UP +#define THERMAL_THRESHOLD_WAY_UP 0x1 +#endif + +#ifndef THERMAL_THRESHOLD_WAY_DOWN +#define THERMAL_THRESHOLD_WAY_DOWN 0x2 +#endif + #ifdef __cplusplus extern "C" { #endif @@ -31,6 +40,11 @@ struct thermal_events_ops { int (*cdev_delete)(int cdev_id, void *arg); int (*cdev_update)(int cdev_id, int cur_state, void *arg); int (*gov_change)(int tz_id, const char *gov_name, void *arg); + int (*threshold_add)(int tz_id, int temperature, int direction, void *arg); + int (*threshold_delete)(int tz_id, int temperature, int direction, void *arg); + int (*threshold_flush)(int tz_id, void *arg); + int (*threshold_up)(int tz_id, int temp, int prev_temp, void *arg); + int (*threshold_down)(int tz_id, int temp, int prev_temp, void *arg); }; struct thermal_ops { @@ -45,12 +59,18 @@ struct thermal_trip { int hyst; }; +struct thermal_threshold { + int temperature; + int direction; +}; + struct thermal_zone { int id; int temp; char name[THERMAL_NAME_LENGTH]; char governor[THERMAL_NAME_LENGTH]; struct thermal_trip *trip; + struct thermal_threshold *thresholds; }; struct thermal_cdev { @@ -74,12 +94,16 @@ typedef int (*cb_tt_t)(struct thermal_trip *, void *); typedef int (*cb_tc_t)(struct thermal_cdev *, void *); +typedef int (*cb_th_t)(struct thermal_threshold *, void *); + LIBTHERMAL_API int for_each_thermal_zone(struct thermal_zone *tz, cb_tz_t cb, void *arg); LIBTHERMAL_API int for_each_thermal_trip(struct thermal_trip *tt, cb_tt_t cb, void *arg); LIBTHERMAL_API int for_each_thermal_cdev(struct thermal_cdev *cdev, cb_tc_t cb, void *arg); +LIBTHERMAL_API int for_each_thermal_threshold(struct thermal_threshold *th, cb_th_t cb, void *arg); + LIBTHERMAL_API struct thermal_zone *thermal_zone_find_by_name(struct thermal_zone *tz, const char *name); @@ -124,6 +148,22 @@ LIBTHERMAL_API thermal_error_t thermal_cmd_get_governor(struct thermal_handler * LIBTHERMAL_API thermal_error_t thermal_cmd_get_temp(struct thermal_handler *th, struct thermal_zone *tz); +LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_get(struct thermal_handler *th, + struct thermal_zone *tz); + +LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_add(struct thermal_handler *th, + struct thermal_zone *tz, + int temperature, + int direction); + +LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_delete(struct thermal_handler *th, + struct thermal_zone *tz, + int temperature, + int direction); + +LIBTHERMAL_API thermal_error_t thermal_cmd_threshold_flush(struct thermal_handler *th, + struct thermal_zone *tz); + /* * Netlink thermal samples */ diff --git a/tools/lib/thermal/libthermal.map b/tools/lib/thermal/libthermal.map index d5e77738c7a41c..d657176aa47fb5 100644 --- a/tools/lib/thermal/libthermal.map +++ b/tools/lib/thermal/libthermal.map @@ -4,6 +4,7 @@ LIBTHERMAL_0.0.1 { for_each_thermal_zone; for_each_thermal_trip; for_each_thermal_cdev; + for_each_thermal_threshold; thermal_zone_find_by_name; thermal_zone_find_by_id; thermal_zone_discover; @@ -17,6 +18,10 @@ LIBTHERMAL_0.0.1 { thermal_cmd_get_trip; thermal_cmd_get_governor; thermal_cmd_get_temp; + thermal_cmd_threshold_get; + thermal_cmd_threshold_add; + thermal_cmd_threshold_delete; + thermal_cmd_threshold_flush; thermal_sampling_init; thermal_sampling_handle; thermal_sampling_fd; diff --git a/tools/lib/thermal/thermal.c b/tools/lib/thermal/thermal.c index 72a76dc205bceb..6f02e35391594b 100644 --- a/tools/lib/thermal/thermal.c +++ b/tools/lib/thermal/thermal.c @@ -1,10 +1,24 @@ // SPDX-License-Identifier: LGPL-2.1+ // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano #include +#include #include #include "thermal_nl.h" +int for_each_thermal_threshold(struct thermal_threshold *th, cb_th_t cb, void *arg) +{ + int i, ret = 0; + + if (!th) + return 0; + + for (i = 0; th[i].temperature != INT_MAX; i++) + ret |= cb(&th[i], arg); + + return ret; +} + int for_each_thermal_cdev(struct thermal_cdev *cdev, cb_tc_t cb, void *arg) { int i, ret = 0; @@ -80,6 +94,9 @@ static int __thermal_zone_discover(struct thermal_zone *tz, void *th) if (thermal_cmd_get_trip(th, tz) < 0) return -1; + if (thermal_cmd_threshold_get(th, tz)) + return -1; + if (thermal_cmd_get_governor(th, tz)) return -1; diff --git a/tools/mm/page_owner_sort.c b/tools/mm/page_owner_sort.c index e1f26444434297..880e36df0c1189 100644 --- a/tools/mm/page_owner_sort.c +++ b/tools/mm/page_owner_sort.c @@ -377,6 +377,7 @@ static char *get_comm(char *buf) if (errno != 0) { if (debug_on) fprintf(stderr, "wrong comm in follow buf:\n%s\n", buf); + free(comm_str); return NULL; } diff --git a/tools/mm/slabinfo.c b/tools/mm/slabinfo.c index 04e9e6ba86ead5..1433eff99feb05 100644 --- a/tools/mm/slabinfo.c +++ b/tools/mm/slabinfo.c @@ -21,7 +21,7 @@ #include #include -#define MAX_SLABS 500 +#define MAX_SLABS 2000 #define MAX_ALIASES 500 #define MAX_NODES 1024 @@ -1228,6 +1228,8 @@ static void read_slab_dir(void) continue; switch (de->d_type) { case DT_LNK: + if (alias - aliasinfo == MAX_ALIASES) + fatal("Too many aliases\n"); alias->name = strdup(de->d_name); count = readlink(de->d_name, buffer, sizeof(buffer)-1); @@ -1242,6 +1244,8 @@ static void read_slab_dir(void) alias++; break; case DT_DIR: + if (slab - slabinfo == MAX_SLABS) + fatal("Too many slabs\n"); if (chdir(de->d_name)) fatal("Unable to access slab %s\n", slab->name); slab->name = strdup(de->d_name); @@ -1312,10 +1316,6 @@ static void read_slab_dir(void) slabs = slab - slabinfo; actual_slabs = slabs; aliases = alias - aliasinfo; - if (slabs > MAX_SLABS) - fatal("Too many slabs\n"); - if (aliases > MAX_ALIASES) - fatal("Too many aliases\n"); } static void output_slabs(void) diff --git a/tools/net/sunrpc/extract.sh b/tools/net/sunrpc/extract.sh new file mode 100755 index 00000000000000..f944066f25bcc8 --- /dev/null +++ b/tools/net/sunrpc/extract.sh @@ -0,0 +1,11 @@ +#! /bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Extract an RPC protocol specification from an RFC document. +# The version of this script comes from RFC 8166. +# +# Usage: +# $ extract.sh < rfcNNNN.txt > protocol.x +# + +grep '^ *///' | sed 's?^ */// ??' | sed 's?^ *///$??' diff --git a/tools/net/sunrpc/xdrgen/README b/tools/net/sunrpc/xdrgen/README index 92f7738ad50c31..27218a78ab402c 100644 --- a/tools/net/sunrpc/xdrgen/README +++ b/tools/net/sunrpc/xdrgen/README @@ -150,6 +150,23 @@ Pragma directives specify exceptions to the normal generation of encoding and decoding functions. Currently one directive is implemented: "public". +Pragma big_endian +------ ---------- + + pragma big_endian ; + +For variables that might contain only a small number values, it +is more efficient to avoid the byte-swap when encoding or decoding +on little-endian machines. Such is often the case with error status +codes. For example: + + pragma big_endian nfsstat3; + +In this case, when generating an XDR struct or union containing a +field of type "nfsstat3", xdrgen will make the type of that field +"__be32" instead of "enum nfsstat3". XDR unions then switch on the +non-byte-swapped value of that field. + Pragma exclude ------ ------- diff --git a/tools/net/sunrpc/xdrgen/generators/__init__.py b/tools/net/sunrpc/xdrgen/generators/__init__.py index fd245746127424..b98574a36a4ac3 100644 --- a/tools/net/sunrpc/xdrgen/generators/__init__.py +++ b/tools/net/sunrpc/xdrgen/generators/__init__.py @@ -111,3 +111,7 @@ class SourceGenerator: def emit_encoder(self, node: _XdrAst) -> None: """Emit one encoder function for this XDR type""" raise NotImplementedError("Encoder generation not supported") + + def emit_maxsize(self, node: _XdrAst) -> None: + """Emit one maxsize macro for this XDR type""" + raise NotImplementedError("Maxsize macro generation not supported") diff --git a/tools/net/sunrpc/xdrgen/generators/enum.py b/tools/net/sunrpc/xdrgen/generators/enum.py index 855e43f4ae38ea..e62f715d3996f3 100644 --- a/tools/net/sunrpc/xdrgen/generators/enum.py +++ b/tools/net/sunrpc/xdrgen/generators/enum.py @@ -4,7 +4,7 @@ """Generate code to handle XDR enum types""" from generators import SourceGenerator, create_jinja2_environment -from xdr_ast import _XdrEnum, public_apis +from xdr_ast import _XdrEnum, public_apis, big_endian, get_header_name class XdrEnumGenerator(SourceGenerator): @@ -18,7 +18,7 @@ class XdrEnumGenerator(SourceGenerator): def emit_declaration(self, node: _XdrEnum) -> None: """Emit one declaration pair for an XDR enum type""" if node.name in public_apis: - template = self.environment.get_template("declaration/close.j2") + template = self.environment.get_template("declaration/enum.j2") print(template.render(name=node.name)) def emit_definition(self, node: _XdrEnum) -> None: @@ -30,15 +30,35 @@ class XdrEnumGenerator(SourceGenerator): for enumerator in node.enumerators: print(template.render(name=enumerator.name, value=enumerator.value)) - template = self.environment.get_template("definition/close.j2") + if node.name in big_endian: + template = self.environment.get_template("definition/close_be.j2") + else: + template = self.environment.get_template("definition/close.j2") print(template.render(name=node.name)) def emit_decoder(self, node: _XdrEnum) -> None: """Emit one decoder function for an XDR enum type""" - template = self.environment.get_template("decoder/enum.j2") + if node.name in big_endian: + template = self.environment.get_template("decoder/enum_be.j2") + else: + template = self.environment.get_template("decoder/enum.j2") print(template.render(name=node.name)) def emit_encoder(self, node: _XdrEnum) -> None: """Emit one encoder function for an XDR enum type""" - template = self.environment.get_template("encoder/enum.j2") + if node.name in big_endian: + template = self.environment.get_template("encoder/enum_be.j2") + else: + template = self.environment.get_template("encoder/enum.j2") print(template.render(name=node.name)) + + def emit_maxsize(self, node: _XdrEnum) -> None: + """Emit one maxsize macro for an XDR enum type""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = self.environment.get_template("maxsize/enum.j2") + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) diff --git a/tools/net/sunrpc/xdrgen/generators/pointer.py b/tools/net/sunrpc/xdrgen/generators/pointer.py index b0b27f1819c8cb..6dbda60ad2db44 100644 --- a/tools/net/sunrpc/xdrgen/generators/pointer.py +++ b/tools/net/sunrpc/xdrgen/generators/pointer.py @@ -8,11 +8,11 @@ from jinja2 import Environment from generators import SourceGenerator, kernel_c_type from generators import create_jinja2_environment, get_jinja2_template -from xdr_ast import _XdrBasic, _XdrVariableLengthString +from xdr_ast import _XdrBasic, _XdrString from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray from xdr_ast import _XdrOptionalData, _XdrPointer, _XdrDeclaration -from xdr_ast import public_apis +from xdr_ast import public_apis, get_header_name def emit_pointer_declaration(environment: Environment, node: _XdrPointer) -> None: @@ -46,7 +46,7 @@ def emit_pointer_member_definition( elif isinstance(field, _XdrVariableLengthOpaque): template = get_jinja2_template(environment, "definition", field.template) print(template.render(name=field.name)) - elif isinstance(field, _XdrVariableLengthString): + elif isinstance(field, _XdrString): template = get_jinja2_template(environment, "definition", field.template) print(template.render(name=field.name)) elif isinstance(field, _XdrFixedLengthArray): @@ -119,7 +119,7 @@ def emit_pointer_member_decoder( maxsize=field.maxsize, ) ) - elif isinstance(field, _XdrVariableLengthString): + elif isinstance(field, _XdrString): template = get_jinja2_template(environment, "decoder", field.template) print( template.render( @@ -198,7 +198,7 @@ def emit_pointer_member_encoder( maxsize=field.maxsize, ) ) - elif isinstance(field, _XdrVariableLengthString): + elif isinstance(field, _XdrString): template = get_jinja2_template(environment, "encoder", field.template) print( template.render( @@ -247,6 +247,18 @@ def emit_pointer_encoder(environment: Environment, node: _XdrPointer) -> None: print(template.render()) +def emit_pointer_maxsize(environment: Environment, node: _XdrPointer) -> None: + """Emit one maxsize macro for an XDR pointer type""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = get_jinja2_template(environment, "maxsize", "pointer") + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) + + class XdrPointerGenerator(SourceGenerator): """Generate source code for XDR pointer""" @@ -270,3 +282,7 @@ class XdrPointerGenerator(SourceGenerator): def emit_encoder(self, node: _XdrPointer) -> None: """Emit one encoder function for an XDR pointer type""" emit_pointer_encoder(self.environment, node) + + def emit_maxsize(self, node: _XdrPointer) -> None: + """Emit one maxsize macro for an XDR pointer type""" + emit_pointer_maxsize(self.environment, node) diff --git a/tools/net/sunrpc/xdrgen/generators/struct.py b/tools/net/sunrpc/xdrgen/generators/struct.py index b694cd47082901..64911de46f6233 100644 --- a/tools/net/sunrpc/xdrgen/generators/struct.py +++ b/tools/net/sunrpc/xdrgen/generators/struct.py @@ -8,11 +8,11 @@ from jinja2 import Environment from generators import SourceGenerator, kernel_c_type from generators import create_jinja2_environment, get_jinja2_template -from xdr_ast import _XdrBasic, _XdrVariableLengthString +from xdr_ast import _XdrBasic, _XdrString from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray from xdr_ast import _XdrOptionalData, _XdrStruct, _XdrDeclaration -from xdr_ast import public_apis +from xdr_ast import public_apis, get_header_name def emit_struct_declaration(environment: Environment, node: _XdrStruct) -> None: @@ -46,7 +46,7 @@ def emit_struct_member_definition( elif isinstance(field, _XdrVariableLengthOpaque): template = get_jinja2_template(environment, "definition", field.template) print(template.render(name=field.name)) - elif isinstance(field, _XdrVariableLengthString): + elif isinstance(field, _XdrString): template = get_jinja2_template(environment, "definition", field.template) print(template.render(name=field.name)) elif isinstance(field, _XdrFixedLengthArray): @@ -119,7 +119,7 @@ def emit_struct_member_decoder( maxsize=field.maxsize, ) ) - elif isinstance(field, _XdrVariableLengthString): + elif isinstance(field, _XdrString): template = get_jinja2_template(environment, "decoder", field.template) print( template.render( @@ -198,7 +198,7 @@ def emit_struct_member_encoder( maxsize=field.maxsize, ) ) - elif isinstance(field, _XdrVariableLengthString): + elif isinstance(field, _XdrString): template = get_jinja2_template(environment, "encoder", field.template) print( template.render( @@ -247,6 +247,18 @@ def emit_struct_encoder(environment: Environment, node: _XdrStruct) -> None: print(template.render()) +def emit_struct_maxsize(environment: Environment, node: _XdrStruct) -> None: + """Emit one maxsize macro for an XDR struct type""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = get_jinja2_template(environment, "maxsize", "struct") + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) + + class XdrStructGenerator(SourceGenerator): """Generate source code for XDR structs""" @@ -270,3 +282,7 @@ class XdrStructGenerator(SourceGenerator): def emit_encoder(self, node: _XdrStruct) -> None: """Emit one encoder function for an XDR struct type""" emit_struct_encoder(self.environment, node) + + def emit_maxsize(self, node: _XdrStruct) -> None: + """Emit one maxsize macro for an XDR struct type""" + emit_struct_maxsize(self.environment, node) diff --git a/tools/net/sunrpc/xdrgen/generators/typedef.py b/tools/net/sunrpc/xdrgen/generators/typedef.py index 85a1b23033339a..fab72e9d691584 100644 --- a/tools/net/sunrpc/xdrgen/generators/typedef.py +++ b/tools/net/sunrpc/xdrgen/generators/typedef.py @@ -8,11 +8,11 @@ from jinja2 import Environment from generators import SourceGenerator, kernel_c_type from generators import create_jinja2_environment, get_jinja2_template -from xdr_ast import _XdrBasic, _XdrTypedef, _XdrVariableLengthString +from xdr_ast import _XdrBasic, _XdrTypedef, _XdrString from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray from xdr_ast import _XdrOptionalData, _XdrVoid, _XdrDeclaration -from xdr_ast import public_apis +from xdr_ast import public_apis, get_header_name def emit_typedef_declaration(environment: Environment, node: _XdrDeclaration) -> None: @@ -28,7 +28,7 @@ def emit_typedef_declaration(environment: Environment, node: _XdrDeclaration) -> classifier=node.spec.c_classifier, ) ) - elif isinstance(node, _XdrVariableLengthString): + elif isinstance(node, _XdrString): template = get_jinja2_template(environment, "declaration", node.template) print(template.render(name=node.name)) elif isinstance(node, _XdrFixedLengthOpaque): @@ -74,7 +74,7 @@ def emit_type_definition(environment: Environment, node: _XdrDeclaration) -> Non classifier=node.spec.c_classifier, ) ) - elif isinstance(node, _XdrVariableLengthString): + elif isinstance(node, _XdrString): template = get_jinja2_template(environment, "definition", node.template) print(template.render(name=node.name)) elif isinstance(node, _XdrFixedLengthOpaque): @@ -119,7 +119,7 @@ def emit_typedef_decoder(environment: Environment, node: _XdrDeclaration) -> Non type=node.spec.type_name, ) ) - elif isinstance(node, _XdrVariableLengthString): + elif isinstance(node, _XdrString): template = get_jinja2_template(environment, "decoder", node.template) print( template.render( @@ -180,7 +180,7 @@ def emit_typedef_encoder(environment: Environment, node: _XdrDeclaration) -> Non type=node.spec.type_name, ) ) - elif isinstance(node, _XdrVariableLengthString): + elif isinstance(node, _XdrString): template = get_jinja2_template(environment, "encoder", node.template) print( template.render( @@ -230,6 +230,18 @@ def emit_typedef_encoder(environment: Environment, node: _XdrDeclaration) -> Non raise NotImplementedError("typedef: type not recognized") +def emit_typedef_maxsize(environment: Environment, node: _XdrDeclaration) -> None: + """Emit a maxsize macro for an XDR typedef""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = get_jinja2_template(environment, "maxsize", node.template) + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) + + class XdrTypedefGenerator(SourceGenerator): """Generate source code for XDR typedefs""" @@ -253,3 +265,7 @@ class XdrTypedefGenerator(SourceGenerator): def emit_encoder(self, node: _XdrTypedef) -> None: """Emit one encoder function for an XDR typedef""" emit_typedef_encoder(self.environment, node.declaration) + + def emit_maxsize(self, node: _XdrTypedef) -> None: + """Emit one maxsize macro for an XDR typedef""" + emit_typedef_maxsize(self.environment, node.declaration) diff --git a/tools/net/sunrpc/xdrgen/generators/union.py b/tools/net/sunrpc/xdrgen/generators/union.py index 7974967bbb9fdf..2cca00e279cd9d 100644 --- a/tools/net/sunrpc/xdrgen/generators/union.py +++ b/tools/net/sunrpc/xdrgen/generators/union.py @@ -8,8 +8,8 @@ from jinja2 import Environment from generators import SourceGenerator from generators import create_jinja2_environment, get_jinja2_template -from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid -from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis +from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid, get_header_name +from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis, big_endian def emit_union_declaration(environment: Environment, node: _XdrUnion) -> None: @@ -77,13 +77,18 @@ def emit_union_switch_spec_decoder( print(template.render(name=node.name, type=node.spec.type_name)) -def emit_union_case_spec_decoder(environment: Environment, node: _XdrCaseSpec) -> None: +def emit_union_case_spec_decoder( + environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool +) -> None: """Emit decoder functions for an XDR union's case arm""" if isinstance(node.arm, _XdrVoid): return - template = get_jinja2_template(environment, "decoder", "case_spec") + if big_endian_discriminant: + template = get_jinja2_template(environment, "decoder", "case_spec_be") + else: + template = get_jinja2_template(environment, "decoder", "case_spec") for case in node.values: print(template.render(case=case)) @@ -136,7 +141,11 @@ def emit_union_decoder(environment: Environment, node: _XdrUnion) -> None: emit_union_switch_spec_decoder(environment, node.discriminant) for case in node.cases: - emit_union_case_spec_decoder(environment, case) + emit_union_case_spec_decoder( + environment, + case, + node.discriminant.spec.type_name in big_endian, + ) emit_union_default_spec_decoder(environment, node) @@ -153,17 +162,21 @@ def emit_union_switch_spec_encoder( print(template.render(name=node.name, type=node.spec.type_name)) -def emit_union_case_spec_encoder(environment: Environment, node: _XdrCaseSpec) -> None: +def emit_union_case_spec_encoder( + environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool +) -> None: """Emit encoder functions for an XDR union's case arm""" if isinstance(node.arm, _XdrVoid): return - template = get_jinja2_template(environment, "encoder", "case_spec") + if big_endian_discriminant: + template = get_jinja2_template(environment, "encoder", "case_spec_be") + else: + template = get_jinja2_template(environment, "encoder", "case_spec") for case in node.values: print(template.render(case=case)) - assert isinstance(node.arm, _XdrBasic) template = get_jinja2_template(environment, "encoder", node.arm.template) print( template.render( @@ -192,7 +205,6 @@ def emit_union_default_spec_encoder(environment: Environment, node: _XdrUnion) - print(template.render()) return - assert isinstance(default_case.arm, _XdrBasic) template = get_jinja2_template(environment, "encoder", default_case.arm.template) print( template.render( @@ -210,7 +222,11 @@ def emit_union_encoder(environment, node: _XdrUnion) -> None: emit_union_switch_spec_encoder(environment, node.discriminant) for case in node.cases: - emit_union_case_spec_encoder(environment, case) + emit_union_case_spec_encoder( + environment, + case, + node.discriminant.spec.type_name in big_endian, + ) emit_union_default_spec_encoder(environment, node) @@ -218,6 +234,18 @@ def emit_union_encoder(environment, node: _XdrUnion) -> None: print(template.render()) +def emit_union_maxsize(environment: Environment, node: _XdrUnion) -> None: + """Emit one maxsize macro for an XDR union type""" + macro_name = get_header_name().upper() + "_" + node.name + "_sz" + template = get_jinja2_template(environment, "maxsize", "union") + print( + template.render( + macro=macro_name, + width=" + ".join(node.symbolic_width()), + ) + ) + + class XdrUnionGenerator(SourceGenerator): """Generate source code for XDR unions""" @@ -241,3 +269,7 @@ class XdrUnionGenerator(SourceGenerator): def emit_encoder(self, node: _XdrUnion) -> None: """Emit one encoder function for an XDR union""" emit_union_encoder(self.environment, node) + + def emit_maxsize(self, node: _XdrUnion) -> None: + """Emit one maxsize macro for an XDR union""" + emit_union_maxsize(self.environment, node) diff --git a/tools/net/sunrpc/xdrgen/grammars/xdr.lark b/tools/net/sunrpc/xdrgen/grammars/xdr.lark index f3c4552e548d62..7c2c1b8c86d126 100644 --- a/tools/net/sunrpc/xdrgen/grammars/xdr.lark +++ b/tools/net/sunrpc/xdrgen/grammars/xdr.lark @@ -3,7 +3,7 @@ declaration : "opaque" identifier "[" value "]" -> fixed_length_opaque | "opaque" identifier "<" [ value ] ">" -> variable_length_opaque - | "string" identifier "<" [ value ] ">" -> variable_length_string + | "string" identifier "<" [ value ] ">" -> string | type_specifier identifier "[" value "]" -> fixed_length_array | type_specifier identifier "<" [ value ] ">" -> variable_length_array | type_specifier "*" identifier -> optional_data @@ -87,12 +87,14 @@ procedure_def : type_specifier identifier "(" type_specifier ")" "=" c pragma_def : "pragma" directive identifier [ identifier ] ";" -directive : exclude_directive +directive : big_endian_directive + | exclude_directive | header_directive | pages_directive | public_directive | skip_directive +big_endian_directive : "big_endian" exclude_directive : "exclude" header_directive : "header" pages_directive : "pages" diff --git a/tools/net/sunrpc/xdrgen/subcmds/definitions.py b/tools/net/sunrpc/xdrgen/subcmds/definitions.py index 5cd13d53221f65..c956e27f37c091 100644 --- a/tools/net/sunrpc/xdrgen/subcmds/definitions.py +++ b/tools/net/sunrpc/xdrgen/subcmds/definitions.py @@ -28,9 +28,7 @@ from xdr_parse import xdr_parser, set_xdr_annotate logger.setLevel(logging.INFO) -def emit_header_definitions( - root: Specification, language: str, peer: str -) -> None: +def emit_header_definitions(root: Specification, language: str, peer: str) -> None: """Emit header definitions""" for definition in root.definitions: if isinstance(definition.value, _XdrConstant): @@ -52,6 +50,25 @@ def emit_header_definitions( gen.emit_definition(definition.value) +def emit_header_maxsize(root: Specification, language: str, peer: str) -> None: + """Emit header maxsize macros""" + print("") + for definition in root.definitions: + if isinstance(definition.value, _XdrEnum): + gen = XdrEnumGenerator(language, peer) + elif isinstance(definition.value, _XdrPointer): + gen = XdrPointerGenerator(language, peer) + elif isinstance(definition.value, _XdrTypedef): + gen = XdrTypedefGenerator(language, peer) + elif isinstance(definition.value, _XdrStruct): + gen = XdrStructGenerator(language, peer) + elif isinstance(definition.value, _XdrUnion): + gen = XdrUnionGenerator(language, peer) + else: + continue + gen.emit_maxsize(definition.value) + + def handle_parse_error(e: UnexpectedInput) -> bool: """Simple parse error reporting, no recovery attempted""" print(e) @@ -71,6 +88,7 @@ def subcmd(args: Namespace) -> int: gen.emit_definition(args.filename, ast) emit_header_definitions(ast, args.language, args.peer) + emit_header_maxsize(ast, args.language, args.peer) gen = XdrHeaderBottomGenerator(args.language, args.peer) gen.emit_definition(args.filename, ast) diff --git a/tools/net/sunrpc/xdrgen/subcmds/source.py b/tools/net/sunrpc/xdrgen/subcmds/source.py index 00c04ad15b895d..2024954748f096 100644 --- a/tools/net/sunrpc/xdrgen/subcmds/source.py +++ b/tools/net/sunrpc/xdrgen/subcmds/source.py @@ -83,8 +83,7 @@ def generate_client_source(filename: str, root: Specification, language: str) -> gen = XdrSourceTopGenerator(language, "client") gen.emit_source(filename, root) - # cel: todo: client needs XDR size macros - + print("") for definition in root.definitions: emit_source_encoder(definition.value, language, "client") for definition in root.definitions: diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/close.j2 deleted file mode 100644 index ab1e576c953183..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/close.j2 +++ /dev/null @@ -1,4 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} - -bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} *ptr); -bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2 new file mode 100644 index 00000000000000..d1405c7c5354ae --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/declaration/enum.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 index 341d829afeda97..6482984f1cb715 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 @@ -8,7 +8,7 @@ bool {% else %} static bool __maybe_unused {% endif %} -xdrgen_decode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} *ptr) +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr) { u32 val; diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 new file mode 100644 index 00000000000000..44c391c10b42ed --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 @@ -0,0 +1,14 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* enum {{ name }} (big-endian) */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr) +{ + return xdr_stream_decode_be32(xdr, ptr) == 0; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 index 9e62344a976aa8..a07586cbee1797 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 @@ -1,2 +1,3 @@ {# SPDX-License-Identifier: GPL-2.0 #} }; +typedef enum {{ name }} {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 new file mode 100644 index 00000000000000..2c18948bddf753 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +}; +typedef __be32 {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 index bd0a770e50f24f..67245b9a914d2d 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 @@ -8,7 +8,7 @@ bool {% else %} static bool __maybe_unused {% endif %} -xdrgen_encode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} value) +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value) { return xdr_stream_encode_u32(xdr, value) == XDR_UNIT; } diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum_be.j2 new file mode 100644 index 00000000000000..fbbcc45948d6a7 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum_be.j2 @@ -0,0 +1,14 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* enum {{ name }} (big-endian) */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value) +{ + return xdr_stream_encode_be32(xdr, value) == XDR_UNIT; +} diff --git a/tools/net/sunrpc/xdrgen/templates/C/enum/maxsize/enum.j2 b/tools/net/sunrpc/xdrgen/templates/C/enum/maxsize/enum.j2 new file mode 100644 index 00000000000000..45c1d4c21b2205 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/enum/maxsize/enum.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/string.j2 new file mode 100644 index 00000000000000..12d20b143b4362 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (!xdrgen_decode_string(xdr, (string *)ptr, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_string.j2 deleted file mode 100644 index 12d20b143b4362..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/pointer/decoder/variable_length_string.j2 +++ /dev/null @@ -1,6 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} -{% if annotate %} - /* member {{ name }} (variable-length string) */ -{% endif %} - if (!xdrgen_decode_string(xdr, (string *)ptr, {{ maxsize }})) - return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/string.j2 new file mode 100644 index 00000000000000..2de2feec77db9f --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/string.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (variable-length string) */ +{% endif %} + string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_string.j2 deleted file mode 100644 index 2de2feec77db9f..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/pointer/definition/variable_length_string.j2 +++ /dev/null @@ -1,5 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} -{% if annotate %} - /* (variable-length string) */ -{% endif %} - string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 new file mode 100644 index 00000000000000..cf65b71eaef396 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/string.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (value->{{ name }}.len > {{ maxsize }}) + return false; + if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_string.j2 deleted file mode 100644 index cf65b71eaef396..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_string.j2 +++ /dev/null @@ -1,8 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} -{% if annotate %} - /* member {{ name }} (variable-length string) */ -{% endif %} - if (value->{{ name }}.len > {{ maxsize }}) - return false; - if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) - return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/pointer/maxsize/pointer.j2 b/tools/net/sunrpc/xdrgen/templates/C/pointer/maxsize/pointer.j2 new file mode 100644 index 00000000000000..9f3bfb47d2f47b --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/pointer/maxsize/pointer.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} \ + ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/result.j2 b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/result.j2 index d304eccb5c4025..aa9940e322db9b 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/program/decoder/result.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/program/decoder/result.j2 @@ -13,10 +13,6 @@ static int {{ program }}_xdr_dec_{{ result }}(struct rpc_rqst *req, if (!xdrgen_decode_{{ result }}(xdr, result)) return -EIO; - if (result->stat != nfs_ok) { - trace_nfs_xdr_status(xdr, (int)result->stat); - return {{ program }}_stat_to_errno(result->stat); - } {% endif %} return 0; } diff --git a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 index e3a802cbc4d752..c5518c519854a0 100644 --- a/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 +++ b/tools/net/sunrpc/xdrgen/templates/C/source_top/client.j2 @@ -3,6 +3,11 @@ // XDR specification file: {{ filename }} // XDR specification modification time: {{ mtime }} -#include +#include -#include "{{ program }}xdr_gen.h" +#include +#include +#include +#include + +#include diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/string.j2 new file mode 100644 index 00000000000000..12d20b143b4362 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (!xdrgen_decode_string(xdr, (string *)ptr, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_string.j2 deleted file mode 100644 index 12d20b143b4362..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/struct/decoder/variable_length_string.j2 +++ /dev/null @@ -1,6 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} -{% if annotate %} - /* member {{ name }} (variable-length string) */ -{% endif %} - if (!xdrgen_decode_string(xdr, (string *)ptr, {{ maxsize }})) - return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/string.j2 new file mode 100644 index 00000000000000..2de2feec77db9f --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/string.j2 @@ -0,0 +1,5 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* (variable-length string) */ +{% endif %} + string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_string.j2 deleted file mode 100644 index 2de2feec77db9f..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/struct/definition/variable_length_string.j2 +++ /dev/null @@ -1,5 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} -{% if annotate %} - /* (variable-length string) */ -{% endif %} - string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 new file mode 100644 index 00000000000000..cf65b71eaef396 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/string.j2 @@ -0,0 +1,8 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (value->{{ name }}.len > {{ maxsize }}) + return false; + if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_string.j2 deleted file mode 100644 index cf65b71eaef396..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_string.j2 +++ /dev/null @@ -1,8 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} -{% if annotate %} - /* member {{ name }} (variable-length string) */ -{% endif %} - if (value->{{ name }}.len > {{ maxsize }}) - return false; - if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) - return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/struct/maxsize/struct.j2 b/tools/net/sunrpc/xdrgen/templates/C/struct/maxsize/struct.j2 new file mode 100644 index 00000000000000..9f3bfb47d2f47b --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/struct/maxsize/struct.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} \ + ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/string.j2 new file mode 100644 index 00000000000000..3fe3ddd9f3596e --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/string.j2 @@ -0,0 +1,4 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_string.j2 deleted file mode 100644 index 3fe3ddd9f3596e..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/typedef/declaration/variable_length_string.j2 +++ /dev/null @@ -1,4 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} - -bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr); -bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value); diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/string.j2 new file mode 100644 index 00000000000000..56c5a17d6a70d5 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/string.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr) +{ +{% if annotate %} + /* (variable-length string) */ +{% endif %} + return xdrgen_decode_string(xdr, ptr, {{ maxsize }}); +}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_string.j2 deleted file mode 100644 index 56c5a17d6a70d5..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/typedef/decoder/variable_length_string.j2 +++ /dev/null @@ -1,17 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} - -{% if annotate %} -/* typedef {{ name }} */ -{% endif %} -{% if name in public_apis %} -bool -{% else %} -static bool __maybe_unused -{% endif %} -xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ classifier }}{{ name }} *ptr) -{ -{% if annotate %} - /* (variable-length string) */ -{% endif %} - return xdrgen_decode_string(xdr, ptr, {{ maxsize }}); -}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/string.j2 new file mode 100644 index 00000000000000..c03c2df8e625d7 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} (variable-length string) */ +{% endif %} +typedef string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_string.j2 deleted file mode 100644 index c03c2df8e625d7..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/typedef/definition/variable_length_string.j2 +++ /dev/null @@ -1,6 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} - -{% if annotate %} -/* typedef {{ name }} (variable-length string) */ -{% endif %} -typedef string {{ name }}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/string.j2 new file mode 100644 index 00000000000000..3d490ff180d038 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/string.j2 @@ -0,0 +1,17 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* typedef {{ name }} */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value) +{ +{% if annotate %} + /* (variable-length string) */ +{% endif %} + return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0; +}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_string.j2 deleted file mode 100644 index 3d490ff180d038..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/typedef/encoder/variable_length_string.j2 +++ /dev/null @@ -1,17 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} - -{% if annotate %} -/* typedef {{ name }} */ -{% endif %} -{% if name in public_apis %} -bool -{% else %} -static bool __maybe_unused -{% endif %} -xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const {{ classifier }}{{ name }} value) -{ -{% if annotate %} - /* (variable-length string) */ -{% endif %} - return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0; -}; diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/basic.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/basic.j2 new file mode 100644 index 00000000000000..9f3bfb47d2f47b --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/basic.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} \ + ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/fixed_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/fixed_length_opaque.j2 new file mode 100644 index 00000000000000..45c1d4c21b2205 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/fixed_length_opaque.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/string.j2 new file mode 100644 index 00000000000000..45c1d4c21b2205 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/string.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_array.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_array.j2 new file mode 100644 index 00000000000000..45c1d4c21b2205 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_array.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_opaque.j2 b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_opaque.j2 new file mode 100644 index 00000000000000..45c1d4c21b2205 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/typedef/maxsize/variable_length_opaque.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec_be.j2 new file mode 100644 index 00000000000000..917f3a1c458884 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec_be.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + case __constant_cpu_to_be32({{ case }}): diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/string.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/string.j2 new file mode 100644 index 00000000000000..83b6e5a14e7fb2 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/string.j2 @@ -0,0 +1,6 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +{% if annotate %} + /* member {{ name }} (variable-length string) */ +{% endif %} + if (!xdrgen_decode_string(xdr, (struct string *)ptr->u.{{ name }}, {{ maxsize }})) + return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_string.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_string.j2 deleted file mode 100644 index 83b6e5a14e7fb2..00000000000000 --- a/tools/net/sunrpc/xdrgen/templates/C/union/decoder/variable_length_string.j2 +++ /dev/null @@ -1,6 +0,0 @@ -{# SPDX-License-Identifier: GPL-2.0 #} -{% if annotate %} - /* member {{ name }} (variable-length string) */ -{% endif %} - if (!xdrgen_decode_string(xdr, (struct string *)ptr->u.{{ name }}, {{ maxsize }})) - return false; diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec_be.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec_be.j2 new file mode 100644 index 00000000000000..917f3a1c458884 --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec_be.j2 @@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + case __constant_cpu_to_be32({{ case }}): diff --git a/tools/net/sunrpc/xdrgen/templates/C/union/maxsize/union.j2 b/tools/net/sunrpc/xdrgen/templates/C/union/maxsize/union.j2 new file mode 100644 index 00000000000000..9f3bfb47d2f47b --- /dev/null +++ b/tools/net/sunrpc/xdrgen/templates/C/union/maxsize/union.j2 @@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +#define {{ '{:<31}'.format(macro) }} \ + ({{ width }}) diff --git a/tools/net/sunrpc/xdrgen/xdr_ast.py b/tools/net/sunrpc/xdrgen/xdr_ast.py index dbd3fcf9c95766..5233e73c7046a6 100644 --- a/tools/net/sunrpc/xdrgen/xdr_ast.py +++ b/tools/net/sunrpc/xdrgen/xdr_ast.py @@ -12,13 +12,50 @@ from lark.tree import Meta this_module = sys.modules[__name__] +big_endian = [] excluded_apis = [] header_name = "none" public_apis = [] -enums = set() structs = set() pass_by_reference = set() +constants = {} + + +def xdr_quadlen(val: str) -> int: + """Return integer XDR width of an XDR type""" + if val in constants: + octets = constants[val] + else: + octets = int(val) + return int((octets + 3) / 4) + + +symbolic_widths = { + "void": ["XDR_void"], + "bool": ["XDR_bool"], + "int": ["XDR_int"], + "unsigned_int": ["XDR_unsigned_int"], + "long": ["XDR_long"], + "unsigned_long": ["XDR_unsigned_long"], + "hyper": ["XDR_hyper"], + "unsigned_hyper": ["XDR_unsigned_hyper"], +} + +# Numeric XDR widths are tracked in a dictionary that is keyed +# by type_name because sometimes a caller has nothing more than +# the type_name to use to figure out the numeric width. +max_widths = { + "void": 0, + "bool": 1, + "int": 1, + "unsigned_int": 1, + "long": 1, + "unsigned_long": 1, + "hyper": 2, + "unsigned_hyper": 2, +} + @dataclass class _XdrAst(ast_utils.Ast): @@ -51,18 +88,31 @@ class _XdrTypeSpecifier(_XdrAst): """Corresponds to 'type_specifier' in the XDR language grammar""" type_name: str - c_classifier: str + c_classifier: str = "" @dataclass class _XdrDefinedType(_XdrTypeSpecifier): """Corresponds to a type defined by the input specification""" + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return [get_header_name().upper() + "_" + self.type_name + "_sz"] + + def __post_init__(self): + if self.type_name in structs: + self.c_classifier = "struct " + symbolic_widths[self.type_name] = self.symbolic_width() + @dataclass class _XdrBuiltInType(_XdrTypeSpecifier): """Corresponds to a built-in XDR type""" + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return symbolic_widths[self.type_name] + @dataclass class _XdrDeclaration(_XdrAst): @@ -77,6 +127,18 @@ class _XdrFixedLengthOpaque(_XdrDeclaration): size: str template: str = "fixed_length_opaque" + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return xdr_quadlen(self.size) + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return ["XDR_QUADLEN(" + self.size + ")"] + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _XdrVariableLengthOpaque(_XdrDeclaration): @@ -86,14 +148,44 @@ class _XdrVariableLengthOpaque(_XdrDeclaration): maxsize: str template: str = "variable_length_opaque" + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + xdr_quadlen(self.maxsize) + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = ["XDR_unsigned_int"] + if self.maxsize != "0": + widths.append("XDR_QUADLEN(" + self.maxsize + ")") + return widths + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass -class _XdrVariableLengthString(_XdrDeclaration): +class _XdrString(_XdrDeclaration): """A (NUL-terminated) variable-length string declaration""" name: str maxsize: str - template: str = "variable_length_string" + template: str = "string" + + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + xdr_quadlen(self.maxsize) + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = ["XDR_unsigned_int"] + if self.maxsize != "0": + widths.append("XDR_QUADLEN(" + self.maxsize + ")") + return widths + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() @dataclass @@ -105,6 +197,19 @@ class _XdrFixedLengthArray(_XdrDeclaration): size: str template: str = "fixed_length_array" + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return xdr_quadlen(self.size) * max_widths[self.spec.type_name] + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + item_width = " + ".join(symbolic_widths[self.spec.type_name]) + return ["(" + self.size + " * (" + item_width + "))"] + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _XdrVariableLengthArray(_XdrDeclaration): @@ -115,6 +220,22 @@ class _XdrVariableLengthArray(_XdrDeclaration): maxsize: str template: str = "variable_length_array" + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + (xdr_quadlen(self.maxsize) * max_widths[self.spec.type_name]) + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = ["XDR_unsigned_int"] + if self.maxsize != "0": + item_width = " + ".join(symbolic_widths[self.spec.type_name]) + widths.append("(" + self.maxsize + " * (" + item_width + "))") + return widths + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _XdrOptionalData(_XdrDeclaration): @@ -124,6 +245,20 @@ class _XdrOptionalData(_XdrDeclaration): spec: _XdrTypeSpecifier template: str = "optional_data" + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return ["XDR_bool"] + + def __post_init__(self): + structs.add(self.name) + pass_by_reference.add(self.name) + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _XdrBasic(_XdrDeclaration): @@ -133,13 +268,34 @@ class _XdrBasic(_XdrDeclaration): spec: _XdrTypeSpecifier template: str = "basic" + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return max_widths[self.spec.type_name] + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return symbolic_widths[self.spec.type_name] + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _XdrVoid(_XdrDeclaration): """A void declaration""" + name: str = "void" template: str = "void" + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 0 + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return [] + @dataclass class _XdrConstant(_XdrAst): @@ -148,6 +304,10 @@ class _XdrConstant(_XdrAst): name: str value: str + def __post_init__(self): + if self.value not in constants: + constants[self.name] = int(self.value, 0) + @dataclass class _XdrEnumerator(_XdrAst): @@ -156,6 +316,10 @@ class _XdrEnumerator(_XdrAst): name: str value: str + def __post_init__(self): + if self.value not in constants: + constants[self.name] = int(self.value, 0) + @dataclass class _XdrEnum(_XdrAst): @@ -166,6 +330,18 @@ class _XdrEnum(_XdrAst): maximum: int enumerators: List[_XdrEnumerator] + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return 1 + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return ["XDR_int"] + + def __post_init__(self): + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _XdrStruct(_XdrAst): @@ -174,6 +350,26 @@ class _XdrStruct(_XdrAst): name: str fields: List[_XdrDeclaration] + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + width = 0 + for field in self.fields: + width += field.max_width() + return width + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = [] + for field in self.fields: + widths += field.symbolic_width() + return widths + + def __post_init__(self): + structs.add(self.name) + pass_by_reference.add(self.name) + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _XdrPointer(_XdrAst): @@ -182,6 +378,27 @@ class _XdrPointer(_XdrAst): name: str fields: List[_XdrDeclaration] + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + width = 1 + for field in self.fields[0:-1]: + width += field.max_width() + return width + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + widths = [] + widths += ["XDR_bool"] + for field in self.fields[0:-1]: + widths += field.symbolic_width() + return widths + + def __post_init__(self): + structs.add(self.name) + pass_by_reference.add(self.name) + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _XdrTypedef(_XdrAst): @@ -189,6 +406,23 @@ class _XdrTypedef(_XdrAst): declaration: _XdrDeclaration + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + return self.declaration.max_width() + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + return self.declaration.symbolic_width() + + def __post_init__(self): + if isinstance(self.declaration, _XdrBasic): + new_type = self.declaration + if isinstance(new_type.spec, _XdrDefinedType): + if new_type.spec.type_name in pass_by_reference: + pass_by_reference.add(new_type.name) + max_widths[new_type.name] = self.max_width() + symbolic_widths[new_type.name] = self.symbolic_width() + @dataclass class _XdrCaseSpec(_XdrAst): @@ -216,6 +450,36 @@ class _XdrUnion(_XdrAst): cases: List[_XdrCaseSpec] default: _XdrDeclaration + def max_width(self) -> int: + """Return width of type in XDR_UNITS""" + max_width = 0 + for case in self.cases: + if case.arm.max_width() > max_width: + max_width = case.arm.max_width() + if self.default: + if self.default.arm.max_width() > max_width: + max_width = self.default.arm.max_width() + return 1 + max_width + + def symbolic_width(self) -> List: + """Return list containing XDR width of type's components""" + max_width = 0 + for case in self.cases: + if case.arm.max_width() > max_width: + max_width = case.arm.max_width() + width = case.arm.symbolic_width() + if self.default: + if self.default.arm.max_width() > max_width: + max_width = self.default.arm.max_width() + width = self.default.arm.symbolic_width() + return symbolic_widths[self.discriminant.name] + width + + def __post_init__(self): + structs.add(self.name) + pass_by_reference.add(self.name) + max_widths[self.name] = self.max_width() + symbolic_widths[self.name] = self.symbolic_width() + @dataclass class _RpcProcedure(_XdrAst): @@ -290,24 +554,13 @@ class ParseToAst(Transformer): return _XdrConstantValue(value) def type_specifier(self, children): - """Instantiate one type_specifier object""" - c_classifier = "" + """Instantiate one _XdrTypeSpecifier object""" if isinstance(children[0], _XdrIdentifier): name = children[0].symbol - if name in enums: - c_classifier = "enum " - if name in structs: - c_classifier = "struct " - return _XdrDefinedType( - type_name=name, - c_classifier=c_classifier, - ) - - token = children[0].data - return _XdrBuiltInType( - type_name=token.value, - c_classifier=c_classifier, - ) + return _XdrDefinedType(type_name=name) + + name = children[0].data.value + return _XdrBuiltInType(type_name=name) def constant_def(self, children): """Instantiate one _XdrConstant object""" @@ -320,7 +573,6 @@ class ParseToAst(Transformer): def enum(self, children): """Instantiate one _XdrEnum object""" enum_name = children[0].symbol - enums.add(enum_name) i = 0 enumerators = [] @@ -350,15 +602,15 @@ class ParseToAst(Transformer): return _XdrVariableLengthOpaque(name, maxsize) - def variable_length_string(self, children): - """Instantiate one _XdrVariableLengthString declaration object""" + def string(self, children): + """Instantiate one _XdrString declaration object""" name = children[0].symbol if children[1] is not None: maxsize = children[1].value else: maxsize = "0" - return _XdrVariableLengthString(name, maxsize) + return _XdrString(name, maxsize) def fixed_length_array(self, children): """Instantiate one _XdrFixedLengthArray declaration object""" @@ -383,8 +635,6 @@ class ParseToAst(Transformer): """Instantiate one _XdrOptionalData declaration object""" spec = children[0] name = children[1].symbol - structs.add(name) - pass_by_reference.add(name) return _XdrOptionalData(name, spec) @@ -403,8 +653,6 @@ class ParseToAst(Transformer): def struct(self, children): """Instantiate one _XdrStruct object""" name = children[0].symbol - structs.add(name) - pass_by_reference.add(name) fields = children[1].children last_field = fields[-1] @@ -419,11 +667,6 @@ class ParseToAst(Transformer): def typedef(self, children): """Instantiate one _XdrTypedef object""" new_type = children[0] - if isinstance(new_type, _XdrBasic) and isinstance( - new_type.spec, _XdrDefinedType - ): - if new_type.spec.type_name in pass_by_reference: - pass_by_reference.add(new_type.name) return _XdrTypedef(new_type) @@ -445,8 +688,6 @@ class ParseToAst(Transformer): def union(self, children): """Instantiate one _XdrUnion object""" name = children[0].symbol - structs.add(name) - pass_by_reference.add(name) body = children[1] discriminant = body.children[0].children[0] @@ -484,6 +725,8 @@ class ParseToAst(Transformer): """Instantiate one _Pragma object""" directive = children[0].children[0].data match directive: + case "big_endian_directive": + big_endian.append(children[1].symbol) case "exclude_directive": excluded_apis.append(children[1].symbol) case "header_directive": diff --git a/tools/net/sunrpc/xdrgen/xdrgen b/tools/net/sunrpc/xdrgen/xdrgen index 95f303b2861b1b..43762be39252d3 100755 --- a/tools/net/sunrpc/xdrgen/xdrgen +++ b/tools/net/sunrpc/xdrgen/xdrgen @@ -128,5 +128,7 @@ There is NO WARRANTY, to the extent permitted by law.""", try: if __name__ == "__main__": sys.exit(main()) -except (SystemExit, KeyboardInterrupt, BrokenPipeError): +except SystemExit: + sys.exit(0) +except (KeyboardInterrupt, BrokenPipeError): sys.exit(1) diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py index b8481f401376d8..41d9fa5c818d13 100755 --- a/tools/net/ynl/cli.py +++ b/tools/net/ynl/cli.py @@ -3,9 +3,11 @@ import argparse import json +import pathlib import pprint -import time +import sys +sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) from lib import YnlFamily, Netlink, NlError @@ -43,7 +45,10 @@ def main(): group.add_argument('--list-ops', action='store_true') group.add_argument('--list-msgs', action='store_true') - parser.add_argument('--sleep', dest='sleep', type=int) + parser.add_argument('--duration', dest='duration', type=int, + help='when subscribed, watch for DURATION seconds') + parser.add_argument('--sleep', dest='duration', type=int, + help='alias for duration') parser.add_argument('--subscribe', dest='ntf', type=str) parser.add_argument('--replace', dest='flags', action='append_const', const=Netlink.NLM_F_REPLACE) @@ -80,9 +85,6 @@ def main(): if args.ntf: ynl.ntf_subscribe(args.ntf) - if args.sleep: - time.sleep(args.sleep) - if args.list_ops: for op_name, op in ynl.ops.items(): print(op_name, " [", ", ".join(op.modes), "]") @@ -106,8 +108,11 @@ def main(): exit(1) if args.ntf: - ynl.check_ntf() - output(ynl.async_msg_queue) + try: + for msg in ynl.poll_ntf(duration=args.duration): + output(msg) + except KeyboardInterrupt: + pass if __name__ == "__main__": diff --git a/tools/net/ynl/ethtool.py b/tools/net/ynl/ethtool.py index 63c471f075abf8..ebb0a11f67bf60 100755 --- a/tools/net/ynl/ethtool.py +++ b/tools/net/ynl/ethtool.py @@ -3,11 +3,13 @@ import argparse import json +import pathlib import pprint import sys import re import os +sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) from lib import YnlFamily def args_to_req(ynl, op_name, args, req): diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 713f5fb9cc2d3e..7db5240de58a2d 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 CC=gcc -CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ +CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ -I../lib/ -idirafter $(UAPI_PATH) ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan diff --git a/tools/net/ynl/lib/Makefile b/tools/net/ynl/lib/Makefile index 2887cc5de530fc..94c49cca3dca57 100644 --- a/tools/net/ynl/lib/Makefile +++ b/tools/net/ynl/lib/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 CC=gcc -CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow +CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan endif diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index b6d6f8aef423cb..a745739655adde 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -131,6 +131,9 @@ class SpecEnumSet(SpecElement): def has_doc(self): if 'doc' in self.yaml: return True + return self.has_entry_doc() + + def has_entry_doc(self): for entry in self.entries.values(): if entry.has_doc(): return True diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index c22c22bf2cb7d1..eea29359a899a5 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -12,6 +12,9 @@ import sys import yaml import ipaddress import uuid +import queue +import selectors +import time from .nlspec import SpecFamily @@ -489,7 +492,7 @@ class YnlFamily(SpecFamily): self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_GET_STRICT_CHK, 1) self.async_msg_ids = set() - self.async_msg_queue = [] + self.async_msg_queue = queue.Queue() for msg in self.msgs.values(): if msg.is_async: @@ -553,10 +556,10 @@ class YnlFamily(SpecFamily): if attr["type"] == 'nest': nl_type |= Netlink.NLA_F_NESTED attr_payload = b'' - sub_attrs = SpaceAttrs(self.attr_sets[space], value, search_attrs) + sub_space = attr['nested-attributes'] + sub_attrs = SpaceAttrs(self.attr_sets[sub_space], value, search_attrs) for subname, subvalue in value.items(): - attr_payload += self._add_attr(attr['nested-attributes'], - subname, subvalue, sub_attrs) + attr_payload += self._add_attr(sub_space, subname, subvalue, sub_attrs) elif attr["type"] == 'flag': if not value: # If value is absent or false then skip attribute creation. @@ -903,7 +906,7 @@ class YnlFamily(SpecFamily): msg['name'] = op['name'] msg['msg'] = attrs - self.async_msg_queue.append(msg) + self.async_msg_queue.put(msg) def check_ntf(self): while True: @@ -925,11 +928,30 @@ class YnlFamily(SpecFamily): decoded = self.nlproto.decode(self, nl_msg, None) if decoded.cmd() not in self.async_msg_ids: - print("Unexpected msg id done while checking for ntf", decoded) + print("Unexpected msg id while checking for ntf", decoded) continue self.handle_ntf(decoded) + def poll_ntf(self, duration=None): + start_time = time.time() + selector = selectors.DefaultSelector() + selector.register(self.sock, selectors.EVENT_READ) + + while True: + try: + yield self.async_msg_queue.get_nowait() + except queue.Empty: + if duration is not None: + timeout = start_time + duration - time.time() + if timeout <= 0: + return + else: + timeout = None + events = selector.select(timeout) + if events: + self.check_ntf() + def operation_do_attributes(self, name): """ For a given operation name, find and return a supported diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index e194a756586161..c9494a564da492 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -3,7 +3,7 @@ include ../Makefile.deps CC=gcc -CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ +CFLAGS += -std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ -I../lib/ -I../generated/ -idirafter $(UAPI_PATH) ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan diff --git a/tools/net/ynl/samples/page-pool.c b/tools/net/ynl/samples/page-pool.c index 332f281ee5cb32..e5d521320fbf34 100644 --- a/tools/net/ynl/samples/page-pool.c +++ b/tools/net/ynl/samples/page-pool.c @@ -118,7 +118,7 @@ int main(int argc, char **argv) name = if_indextoname(s->ifc, ifname); if (name) printf("%8s", name); - printf("[%d]\t", s->ifc); + printf("[%u]\t", s->ifc); } printf("page pools: %u (zombies: %u)\n", diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 717530bc9c52e7..d8201c4b152099 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -4,12 +4,15 @@ import argparse import collections import filecmp +import pathlib import os import re import shutil +import sys import tempfile import yaml +sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry @@ -80,11 +83,21 @@ class Type(SpecAttr): value = self.checks.get(limit, default) if value is None: return value - elif value in self.family.consts: + if isinstance(value, int): + return value + if value in self.family.consts: + raise Exception("Resolving family constants not implemented, yet") + return limit_to_number(value) + + def get_limit_str(self, limit, default=None, suffix=''): + value = self.checks.get(limit, default) + if value is None: + return '' + if isinstance(value, int): + return str(value) + suffix + if value in self.family.consts: return c_upper(f"{self.family['name']}-{value}") - if not isinstance(value, int): - value = limit_to_number(value) - return value + return c_upper(value) def resolve(self): if 'name-prefix' in self.attr: @@ -157,7 +170,10 @@ class Type(SpecAttr): return '{ .type = ' + policy + ', }' def attr_policy(self, cw): - policy = c_upper('nla-' + self.attr['type']) + policy = f'NLA_{c_upper(self.type)}' + if self.attr.get('byte-order') == 'big-endian': + if self.type in {'u16', 'u32'}: + policy = f'NLA_BE{self.type[1:]}' spec = self._attr_policy(policy) cw.p(f"\t[{self.enum_name}] = {spec},") @@ -358,11 +374,11 @@ class TypeScalar(Type): elif 'full-range' in self.checks: return f"NLA_POLICY_FULL_RANGE({policy}, &{c_lower(self.enum_name)}_range)" elif 'range' in self.checks: - return f"NLA_POLICY_RANGE({policy}, {self.get_limit('min')}, {self.get_limit('max')})" + return f"NLA_POLICY_RANGE({policy}, {self.get_limit_str('min')}, {self.get_limit_str('max')})" elif 'min' in self.checks: - return f"NLA_POLICY_MIN({policy}, {self.get_limit('min')})" + return f"NLA_POLICY_MIN({policy}, {self.get_limit_str('min')})" elif 'max' in self.checks: - return f"NLA_POLICY_MAX({policy}, {self.get_limit('max')})" + return f"NLA_POLICY_MAX({policy}, {self.get_limit_str('max')})" return super()._attr_policy(policy) def _attr_typol(self): @@ -413,11 +429,11 @@ class TypeString(Type): def _attr_policy(self, policy): if 'exact-len' in self.checks: - mem = 'NLA_POLICY_EXACT_LEN(' + str(self.get_limit('exact-len')) + ')' + mem = 'NLA_POLICY_EXACT_LEN(' + self.get_limit_str('exact-len') + ')' else: mem = '{ .type = ' + policy if 'max-len' in self.checks: - mem += ', .len = ' + str(self.get_limit('max-len')) + mem += ', .len = ' + self.get_limit_str('max-len') mem += ', }' return mem @@ -464,17 +480,24 @@ class TypeBinary(Type): return f'.type = YNL_PT_BINARY,' def _attr_policy(self, policy): - if 'exact-len' in self.checks: - mem = 'NLA_POLICY_EXACT_LEN(' + str(self.get_limit('exact-len')) + ')' + if len(self.checks) == 0: + pass + elif len(self.checks) == 1: + check_name = list(self.checks)[0] + if check_name not in {'exact-len', 'min-len', 'max-len'}: + raise Exception('Unsupported check for binary type: ' + check_name) else: - mem = '{ ' - if len(self.checks) == 1 and 'min-len' in self.checks: - mem += '.len = ' + str(self.get_limit('min-len')) - elif len(self.checks) == 0: - mem += '.type = NLA_BINARY' - else: - raise Exception('One or more of binary type checks not implemented, yet') - mem += ', }' + raise Exception('More than one check for binary type not implemented, yet') + + if len(self.checks) == 0: + mem = '{ .type = NLA_BINARY, }' + elif 'exact-len' in self.checks: + mem = 'NLA_POLICY_EXACT_LEN(' + self.get_limit_str('exact-len') + ')' + elif 'min-len' in self.checks: + mem = '{ .len = ' + self.get_limit_str('min-len') + ', }' + elif 'max-len' in self.checks: + mem = 'NLA_POLICY_MAX_LEN(' + self.get_limit_str('max-len') + ')' + return mem def attr_put(self, ri, var): @@ -2161,9 +2184,9 @@ def print_kernel_policy_ranges(family, cw): cw.block_start(line=f'static const struct netlink_range_validation{sign} {c_lower(attr.enum_name)}_range =') members = [] if 'min' in attr.checks: - members.append(('min', str(attr.get_limit('min')) + suffix)) + members.append(('min', attr.get_limit_str('min', suffix=suffix))) if 'max' in attr.checks: - members.append(('max', str(attr.get_limit('max')) + suffix)) + members.append(('max', attr.get_limit_str('max', suffix=suffix))) cw.write_struct_init(members) cw.block_end(line=';') cw.nl() @@ -2396,6 +2419,7 @@ def uapi_enum_start(family, cw, obj, ckey='', enum_name='enum-name'): def render_uapi(family, cw): hdr_prot = f"_UAPI_LINUX_{c_upper(family.uapi_header_name)}_H" + hdr_prot = hdr_prot.replace('/', '_') cw.p('#ifndef ' + hdr_prot) cw.p('#define ' + hdr_prot) cw.nl() @@ -2417,11 +2441,15 @@ def render_uapi(family, cw): enum = family.consts[const['name']] if enum.has_doc(): - cw.p('/**') - doc = '' - if 'doc' in enum: - doc = ' - ' + enum['doc'] - cw.write_doc_line(enum.enum_name + doc) + if enum.has_entry_doc(): + cw.p('/**') + doc = '' + if 'doc' in enum: + doc = ' - ' + enum['doc'] + cw.write_doc_line(enum.enum_name + doc) + else: + cw.p('/*') + cw.write_doc_line(enum['doc'], indent=False) for entry in enum.entries.values(): if entry.has_doc(): doc = '@' + entry.c_name + ': ' + entry['doc'] diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index bf7f7f84ac6259..f56e2772753414 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -24,6 +24,7 @@ LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lel all: $(OBJTOOL) INCLUDES := -I$(srctree)/tools/include \ + -I$(srctree)/tools/include/uapi \ -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ -I$(srctree)/tools/arch/$(SRCARCH)/include \ -I$(srctree)/tools/objtool/include \ diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index ed6bff0e01dcd5..fe1362c345647e 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -456,10 +456,6 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec if (!rex_w) break; - /* skip RIP relative displacement */ - if (is_RIP()) - break; - /* skip nontrivial SIB */ if (have_SIB()) { modrm_rm = sib_base; @@ -467,6 +463,12 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec break; } + /* lea disp(%rip), %dst */ + if (is_RIP()) { + insn->type = INSN_LEA_RIP; + break; + } + /* lea disp(%src), %dst */ ADD_OP(op) { op->src.offset = ins.displacement.value; @@ -737,7 +739,10 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec break; } - insn->immediate = ins.immediate.nbytes ? ins.immediate.value : 0; + if (ins.immediate.nbytes) + insn->immediate = ins.immediate.value; + else if (ins.displacement.nbytes) + insn->immediate = ins.displacement.value; return 0; } diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 6604f5d038aadf..76060da755b5c5 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -3820,9 +3820,12 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, break; case INSN_CONTEXT_SWITCH: - if (func && (!next_insn || !next_insn->hint)) { - WARN_INSN(insn, "unsupported instruction in callable function"); - return 1; + if (func) { + if (!next_insn || !next_insn->hint) { + WARN_INSN(insn, "unsupported instruction in callable function"); + return 1; + } + break; } return 0; @@ -4392,6 +4395,51 @@ static bool noendbr_range(struct objtool_file *file, struct instruction *insn) return insn->offset == sym->offset + sym->len; } +static int __validate_ibt_insn(struct objtool_file *file, struct instruction *insn, + struct instruction *dest) +{ + if (dest->type == INSN_ENDBR) { + mark_endbr_used(dest); + return 0; + } + + if (insn_func(dest) && insn_func(insn) && + insn_func(dest)->pfunc == insn_func(insn)->pfunc) { + /* + * Anything from->to self is either _THIS_IP_ or + * IRET-to-self. + * + * There is no sane way to annotate _THIS_IP_ since the + * compiler treats the relocation as a constant and is + * happy to fold in offsets, skewing any annotation we + * do, leading to vast amounts of false-positives. + * + * There's also compiler generated _THIS_IP_ through + * KCOV and such which we have no hope of annotating. + * + * As such, blanket accept self-references without + * issue. + */ + return 0; + } + + /* + * Accept anything ANNOTATE_NOENDBR. + */ + if (dest->noendbr) + return 0; + + /* + * Accept if this is the instruction after a symbol + * that is (no)endbr -- typical code-range usage. + */ + if (noendbr_range(file, dest)) + return 0; + + WARN_INSN(insn, "relocation to !ENDBR: %s", offstr(dest->sec, dest->offset)); + return 1; +} + static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn) { struct instruction *dest; @@ -4404,6 +4452,7 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn * direct/indirect branches: */ switch (insn->type) { + case INSN_CALL: case INSN_CALL_DYNAMIC: case INSN_JUMP_CONDITIONAL: @@ -4413,6 +4462,23 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn case INSN_RETURN: case INSN_NOP: return 0; + + case INSN_LEA_RIP: + if (!insn_reloc(file, insn)) { + /* local function pointer reference without reloc */ + + off = arch_jump_destination(insn); + + dest = find_insn(file, insn->sec, off); + if (!dest) { + WARN_INSN(insn, "corrupt function pointer reference"); + return 1; + } + + return __validate_ibt_insn(file, insn, dest); + } + break; + default: break; } @@ -4423,13 +4489,6 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn reloc_offset(reloc) + 1, (insn->offset + insn->len) - (reloc_offset(reloc) + 1))) { - /* - * static_call_update() references the trampoline, which - * doesn't have (or need) ENDBR. Skip warning in that case. - */ - if (reloc->sym->static_call_tramp) - continue; - off = reloc->sym->offset; if (reloc_type(reloc) == R_X86_64_PC32 || reloc_type(reloc) == R_X86_64_PLT32) @@ -4441,47 +4500,7 @@ static int validate_ibt_insn(struct objtool_file *file, struct instruction *insn if (!dest) continue; - if (dest->type == INSN_ENDBR) { - mark_endbr_used(dest); - continue; - } - - if (insn_func(dest) && insn_func(insn) && - insn_func(dest)->pfunc == insn_func(insn)->pfunc) { - /* - * Anything from->to self is either _THIS_IP_ or - * IRET-to-self. - * - * There is no sane way to annotate _THIS_IP_ since the - * compiler treats the relocation as a constant and is - * happy to fold in offsets, skewing any annotation we - * do, leading to vast amounts of false-positives. - * - * There's also compiler generated _THIS_IP_ through - * KCOV and such which we have no hope of annotating. - * - * As such, blanket accept self-references without - * issue. - */ - continue; - } - - /* - * Accept anything ANNOTATE_NOENDBR. - */ - if (dest->noendbr) - continue; - - /* - * Accept if this is the instruction after a symbol - * that is (no)endbr -- typical code-range usage. - */ - if (noendbr_range(file, dest)) - continue; - - WARN_INSN(insn, "relocation to !ENDBR: %s", offstr(dest->sec, dest->offset)); - - warnings++; + warnings += __validate_ibt_insn(file, insn, dest); } return warnings; @@ -4557,6 +4576,9 @@ static int validate_ibt(struct objtool_file *file) !strcmp(sec->name, "__jump_table") || !strcmp(sec->name, "__mcount_loc") || !strcmp(sec->name, ".kcfi_traps") || + !strcmp(sec->name, ".llvm.call-graph-profile") || + !strcmp(sec->name, ".llvm_bb_addr_map") || + !strcmp(sec->name, "__tracepoints") || strstr(sec->name, "__patchable_function_entries")) continue; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 3d27983dc908d8..6f64d611faea96 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -224,12 +224,17 @@ int find_symbol_hole_containing(const struct section *sec, unsigned long offset) if (n) return 0; /* not a hole */ - /* didn't find a symbol for which @offset is after it */ - if (!hole.sym) - return 0; /* not a hole */ + /* + * @offset >= sym->offset + sym->len, find symbol after it. + * When hole.sym is empty, use the first node to compute the hole. + * If there is no symbol in the section, the first node will be NULL, + * in which case, -1 is returned to skip the whole section. + */ + if (hole.sym) + n = rb_next(&hole.sym->node); + else + n = rb_first_cached(&sec->symbol_tree); - /* @offset >= sym->offset + sym->len, find symbol after it */ - n = rb_next(&hole.sym->node); if (!n) return -1; /* until end of address space */ diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h index 0b303eba660e46..d63b46a19f3979 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -28,6 +28,7 @@ enum insn_type { INSN_CLD, INSN_TRAP, INSN_ENDBR, + INSN_LEA_RIP, INSN_OTHER, }; diff --git a/tools/objtool/noreturns.h b/tools/objtool/noreturns.h index e7da92489167e9..f37614cc2c1b2f 100644 --- a/tools/objtool/noreturns.h +++ b/tools/objtool/noreturns.h @@ -11,7 +11,6 @@ NORETURN(__ia32_sys_exit) NORETURN(__ia32_sys_exit_group) NORETURN(__kunit_abort) NORETURN(__module_put_and_kthread_exit) -NORETURN(__reiserfs_panic) NORETURN(__stack_chk_fail) NORETURN(__tdx_hypercall_failed) NORETURN(__ubsan_handle_builtin_unreachable) diff --git a/tools/pci/pcitest.c b/tools/pci/pcitest.c index 470258009ddc27..7b530d838d4082 100644 --- a/tools/pci/pcitest.c +++ b/tools/pci/pcitest.c @@ -95,7 +95,7 @@ static int run_test(struct pci_test *test) if (test->msinum > 0 && test->msinum <= 32) { ret = ioctl(fd, PCITEST_MSI, test->msinum); - fprintf(stdout, "MSI%d:\t\t", test->msinum); + fprintf(stdout, "MSI%u:\t\t", test->msinum); if (ret < 0) fprintf(stdout, "TEST FAILED\n"); else @@ -104,7 +104,7 @@ static int run_test(struct pci_test *test) if (test->msixnum > 0 && test->msixnum <= 2048) { ret = ioctl(fd, PCITEST_MSIX, test->msixnum); - fprintf(stdout, "MSI-X%d:\t\t", test->msixnum); + fprintf(stdout, "MSI-X%u:\t\t", test->msixnum); if (ret < 0) fprintf(stdout, "TEST FAILED\n"); else @@ -116,7 +116,7 @@ static int run_test(struct pci_test *test) if (test->use_dma) param.flags = PCITEST_FLAGS_USE_DMA; ret = ioctl(fd, PCITEST_WRITE, ¶m); - fprintf(stdout, "WRITE (%7ld bytes):\t\t", test->size); + fprintf(stdout, "WRITE (%7lu bytes):\t\t", test->size); if (ret < 0) fprintf(stdout, "TEST FAILED\n"); else @@ -128,7 +128,7 @@ static int run_test(struct pci_test *test) if (test->use_dma) param.flags = PCITEST_FLAGS_USE_DMA; ret = ioctl(fd, PCITEST_READ, ¶m); - fprintf(stdout, "READ (%7ld bytes):\t\t", test->size); + fprintf(stdout, "READ (%7lu bytes):\t\t", test->size); if (ret < 0) fprintf(stdout, "TEST FAILED\n"); else @@ -140,7 +140,7 @@ static int run_test(struct pci_test *test) if (test->use_dma) param.flags = PCITEST_FLAGS_USE_DMA; ret = ioctl(fd, PCITEST_COPY, ¶m); - fprintf(stdout, "COPY (%7ld bytes):\t\t", test->size); + fprintf(stdout, "COPY (%7lu bytes):\t\t", test->size); if (ret < 0) fprintf(stdout, "TEST FAILED\n"); else diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index f5b81d439387a1..5aaf73df6700dc 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -39,9 +39,9 @@ trace/beauty/generated/ pmu-events/pmu-events.c pmu-events/jevents pmu-events/metric_test.log -tests/shell/*.shellcheck_log -tests/shell/coresight/*.shellcheck_log -tests/shell/lib/*.shellcheck_log +pmu-events/empty-pmu-events.log +pmu-events/test-empty-pmu-events.c +*.shellcheck_log feature/ libapi/ libbpf/ diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index 19cc179be9a784..40476b227f8d61 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt @@ -1,6 +1,6 @@ i synthesize instructions events y synthesize cycles events - b synthesize branches events (branch misses for Arm SPE) + b synthesize branches events c synthesize branches events (calls only) r synthesize branches events (returns only) x synthesize transactions events diff --git a/tools/perf/Documentation/perf-arm-spe.txt b/tools/perf/Documentation/perf-arm-spe.txt index 0a3eda482307a3..de2b0b479249e7 100644 --- a/tools/perf/Documentation/perf-arm-spe.txt +++ b/tools/perf/Documentation/perf-arm-spe.txt @@ -187,7 +187,7 @@ groups: 7 llc-access 2 tlb-miss 1K tlb-access - 36 branch-miss + 36 branch 0 remote-access 900 memory diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt index 10f69fb6850bcc..31741499e7867c 100644 --- a/tools/perf/Documentation/perf-check.txt +++ b/tools/perf/Documentation/perf-check.txt @@ -47,15 +47,15 @@ feature:: bpf / HAVE_LIBBPF_SUPPORT bpf_skeletons / HAVE_BPF_SKEL debuginfod / HAVE_DEBUGINFOD_SUPPORT - dwarf / HAVE_DWARF_SUPPORT - dwarf_getlocations / HAVE_DWARF_GETLOCATIONS_SUPPORT + dwarf / HAVE_LIBDW_SUPPORT + dwarf_getlocations / HAVE_LIBDW_SUPPORT dwarf-unwind / HAVE_DWARF_UNWIND_SUPPORT auxtrace / HAVE_AUXTRACE_SUPPORT libaudit / HAVE_LIBAUDIT_SUPPORT libbfd / HAVE_LIBBFD_SUPPORT libcapstone / HAVE_LIBCAPSTONE_SUPPORT libcrypto / HAVE_LIBCRYPTO_SUPPORT - libdw-dwarf-unwind / HAVE_DWARF_SUPPORT + libdw-dwarf-unwind / HAVE_LIBDW_SUPPORT libelf / HAVE_LIBELF_SUPPORT libnuma / HAVE_LIBNUMA_SUPPORT libopencsd / HAVE_CSTRACE_SUPPORT diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 379f9d7a8ab11a..1f668d4724e374 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -247,6 +247,19 @@ annotate.*:: These are in control of addresses, jump function, source code in lines of assembly code from a specific program. + annotate.disassemblers:: + Choose the disassembler to use: "objdump", "llvm", "capstone", + if not specified it will first try, if available, the "llvm" one, + then, if it fails, "capstone", and finally the original "objdump" + based one. + + Choosing a different one is useful when handling some feature that + is known to be best support at some point by one of the options, + to compare the output when in doubt about some bug, etc. + + This can be a list, in order of preference, the first one that works + finishes the process. + annotate.addr2line:: addr2line binary to use for file names and line numbers. diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index dea005410ec02f..d0c65fad419a07 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -8,7 +8,7 @@ perf-list - List all symbolic event types SYNOPSIS -------- [verse] -'perf list' [--no-desc] [--long-desc] +'perf list' [] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob] DESCRIPTION @@ -243,6 +243,21 @@ For accessing trace point events perf needs to have read access to /sys/kernel/tracing, even when perf_event_paranoid is in a relaxed setting. +TOOL/HWMON EVENTS +----------------- + +Some events don't have an associated PMU instead reading values +available to software without perf_event_open. As these events don't +support sampling they can only really be read by tools like perf stat. + +Tool events provide times and certain system parameters. Examples +include duration_time, user_time, system_time and num_cpus_online. + +Hwmon events provide easy access to hwmon sysfs data typically in +/sys/class/hwmon. This information includes temperatures, fan speeds +and energy usage. + + TRACING ------- diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 7c66d81ab978c8..87f86451940623 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -391,6 +391,14 @@ OPTIONS This allows to examine the path the program took to each sample. The data collection must have used -b (or -j) and -g. + Also show with some branch flags that can be: + - Predicted: display the average percentage of predicated branches. + (predicated number / total number) + - Abort: display the number of tsx aborted branches. + - Cycles: cycles in basic block. + + - iterations: display the average number of iterations in callchain list. + --addr2line=:: Path to addr2line binary. diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt index 3db64954a267a3..6dbbddb6464d01 100644 --- a/tools/perf/Documentation/perf-sched.txt +++ b/tools/perf/Documentation/perf-sched.txt @@ -221,6 +221,14 @@ OPTIONS for 'perf sched timehist' priorities are specified with -: 120-129. A combination of both can also be provided: 0,120-129. +-P:: +--pre-migrations:: + Show pre-migration wait time. pre-migration wait time is the time spent + by a task waiting on a runqueue but not getting the chance to run there + and is migrated to a different runqueue where it is finally run. This + time between sched_wakeup and migrate_task is the pre-migration wait + time. + OPTIONS for 'perf sched replay' ------------------------------ diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt index 13e37e9385ee42..27a1cac6fe7638 100644 --- a/tools/perf/Documentation/perf-script-python.txt +++ b/tools/perf/Documentation/perf-script-python.txt @@ -624,7 +624,7 @@ as perf_trace_context.perf_script_context . perf_set_itrace_options(context, itrace_options) - set --itrace options if they have not been set already perf_sample_srcline(context) - returns source_file_name, line_number perf_sample_srccode(context) - returns source_file_name, line_number, source_line - + perf_config_get(config_name) - returns the value of the named config item, or None if unset Util.py Module ~~~~~~~~~~~~~~ diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt index 9acb8d1f658890..efcdec528a8f72 100644 --- a/tools/perf/Documentation/perf-test.txt +++ b/tools/perf/Documentation/perf-test.txt @@ -48,3 +48,20 @@ OPTIONS --dso:: Specify a DSO for the "Symbols" test. + +-w:: +--workload=:: + Run a built-in workload, to list them use '--list-workloads', current ones include: + noploop, thloop, leafloop, sqrtloop, brstack, datasym and landlock. + + Used with the shell script regression tests. + + Some accept an extra parameter: + + seconds: leafloop, noploop, sqrtloop, thloop + nrloops: brstack + + The datasym and landlock workloads don't accept any. + +--list-workloads:: + List the available workloads to use with -w/--workload. diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index d4332675babb74..2916d59c88cd08 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -31,7 +31,7 @@ $(call detected_var,SRCARCH) ifneq ($(NO_SYSCALL_TABLE),1) NO_SYSCALL_TABLE := 1 - ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 powerpc arm64 s390 mips loongarch)) + ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 powerpc arm64 s390 mips loongarch riscv)) NO_SYSCALL_TABLE := 0 endif @@ -83,6 +83,10 @@ ifeq ($(ARCH),mips) LIBUNWIND_LIBS = -lunwind -lunwind-mips endif +ifeq ($(ARCH),riscv) + CFLAGS += -I$(OUTPUT)arch/riscv/include/generated +endif + # So far there's only x86 and arm libdw unwind support merged in perf. # Disable it on all other architectures in case libdw unwind # support is detected in system. Add supported architectures @@ -91,6 +95,10 @@ ifneq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc s390 csky riscv loon NO_LIBDW_DWARF_UNWIND := 1 endif +ifneq ($(LIBUNWIND),1) + NO_LIBUNWIND := 1 +endif + ifeq ($(LIBUNWIND_LIBS),) NO_LIBUNWIND := 1 endif @@ -162,8 +170,8 @@ ifeq ($(findstring -static,${LDFLAGS}),-static) # Must put -ldl after -lebl for dependency DWARFLIBS += -ldl endif -FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS) -FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) $(DWARFLIBS) +FEATURE_CHECK_CFLAGS-libdw := $(LIBDW_CFLAGS) +FEATURE_CHECK_LDFLAGS-libdw := $(LIBDW_LDFLAGS) $(DWARFLIBS) # for linking with debug library, run like: # make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/ @@ -203,10 +211,6 @@ FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arc # include ARCH specific config -include $(src-perf)/arch/$(SRCARCH)/Makefile -ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET - CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET -endif - include $(srctree)/tools/scripts/utilities.mak ifeq ($(call get-executable,$(FLEX)),) @@ -426,7 +430,7 @@ ifeq ($(feature-file-handle), 1) endif ifdef NO_LIBELF - NO_DWARF := 1 + NO_LIBDW := 1 NO_LIBUNWIND := 1 NO_LIBDW_DWARF_UNWIND := 1 NO_LIBBPF := 1 @@ -461,28 +465,11 @@ else endif endif else - ifndef NO_LIBDW_DWARF_UNWIND - ifneq ($(feature-libdw-dwarf-unwind),1) - NO_LIBDW_DWARF_UNWIND := 1 - $(warning No libdw DWARF unwind found, Please install elfutils-devel/libdw-dev >= 0.158 and/or set LIBDW_DIR) + ifneq ($(feature-libdw), 1) + ifndef NO_LIBDW + $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.157, disables dwarf support. Please install new elfutils-devel/libdw-dev) + NO_LIBDW := 1 endif - endif - ifneq ($(feature-dwarf), 1) - ifndef NO_DWARF - $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev) - NO_DWARF := 1 - endif - else - ifneq ($(feature-dwarf_getlocations), 1) - $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157) - else - CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT - endif # dwarf_getlocations - ifneq ($(feature-dwarf_getcfi), 1) - $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.142) - else - CFLAGS += -DHAVE_DWARF_CFI_SUPPORT - endif # dwarf_getcfi endif # Dwarf support endif # libelf support endif # NO_LIBELF @@ -493,7 +480,7 @@ ifeq ($(feature-libaio), 1) endif endif -ifdef NO_DWARF +ifdef NO_LIBDW NO_LIBDW_DWARF_UNWIND := 1 endif @@ -571,17 +558,12 @@ ifndef NO_LIBELF endif endif - ifndef NO_DWARF - ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) - $(warning DWARF register mappings have not been defined for architecture $(SRCARCH), DWARF support disabled) - NO_DWARF := 1 - else - CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS) - LDFLAGS += $(LIBDW_LDFLAGS) - EXTLIBS += ${DWARFLIBS} - $(call detected,CONFIG_DWARF) - endif # PERF_HAVE_DWARF_REGS - endif # NO_DWARF + ifndef NO_LIBDW + CFLAGS += -DHAVE_LIBDW_SUPPORT $(LIBDW_CFLAGS) + LDFLAGS += $(LIBDW_LDFLAGS) + EXTLIBS += ${DWARFLIBS} + $(call detected,CONFIG_LIBDW) + endif # NO_LIBDW ifndef NO_LIBBPF ifeq ($(feature-bpf), 1) @@ -630,7 +612,7 @@ ifdef PERF_HAVE_JITDUMP endif ifeq ($(SRCARCH),powerpc) - ifndef NO_DWARF + ifndef NO_LIBDW CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX endif endif @@ -750,8 +732,6 @@ endif ifeq ($(dwarf-post-unwind),1) CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT $(call detected,CONFIG_DWARF_UNWIND) -else - NO_DWARF_UNWIND := 1 endif ifndef NO_LOCAL_LIBUNWIND @@ -1194,7 +1174,7 @@ endif ifneq ($(NO_LIBTRACEEVENT),1) $(call feature_check,libtraceevent) ifeq ($(feature-libtraceevent), 1) - CFLAGS += -DHAVE_LIBTRACEEVENT + CFLAGS += -DHAVE_LIBTRACEEVENT $(shell $(PKG_CONFIG) --cflags libtraceevent) LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L libtraceevent) EXTLIBS += $(shell $(PKG_CONFIG) --libs-only-l libtraceevent) LIBTRACEEVENT_VERSION := $(shell $(PKG_CONFIG) --modversion libtraceevent).0.0 diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 9dd2e8d3f3c9b7..d74241a151313b 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -40,7 +40,7 @@ include ../scripts/utilities.mak # # Define EXTRA_PERFLIBS to pass extra libraries to PERFLIBS. # -# Define NO_DWARF if you do not want debug-info analysis feature at all. +# Define NO_LIBDW if you do not want debug-info analysis feature at all. # # Define WERROR=0 to disable treating any warnings as errors. # @@ -52,7 +52,7 @@ include ../scripts/utilities.mak # # Define NO_LIBELF if you do not want libelf dependency (e.g. cross-builds) # -# Define NO_LIBUNWIND if you do not want libunwind dependency for dwarf +# Define LIBUNWIND if you do not want libunwind dependency for dwarf # backtrace post unwind. # # Define NO_BACKTRACE if you do not want stack backtrace debug feature @@ -1128,12 +1128,11 @@ endif install-tests: all install-gtk $(call QUIET_INSTALL, tests) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ - $(INSTALL) tests/attr.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ $(INSTALL) tests/pe-file.exe* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ - $(INSTALL) tests/attr/* -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \ $(INSTALL) tests/shell/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \ + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/attr'; \ + $(INSTALL) tests/shell/attr/* -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/attr'; \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \ $(INSTALL) tests/shell/lib/*.sh -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \ $(INSTALL) tests/shell/lib/*.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \ diff --git a/tools/perf/arch/arc/annotate/instructions.c b/tools/perf/arch/arc/annotate/instructions.c index 2f00e995c7e38d..e5619770a1af73 100644 --- a/tools/perf/arch/arc/annotate/instructions.c +++ b/tools/perf/arch/arc/annotate/instructions.c @@ -5,5 +5,7 @@ static int arc__annotate_init(struct arch *arch, char *cpuid __maybe_unused) { arch->initialized = true; arch->objdump.comment_char = ';'; + arch->e_machine = EM_ARC; + arch->e_flags = 0; return 0; } diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile index 1d88fdab13bf8f..8b59ce8efb8926 100644 --- a/tools/perf/arch/arm/Makefile +++ b/tools/perf/arch/arm/Makefile @@ -1,5 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif PERF_HAVE_JITDUMP := 1 diff --git a/tools/perf/arch/arm/annotate/instructions.c b/tools/perf/arch/arm/annotate/instructions.c index 2ff6cedeb9c537..cf91a43362b0e3 100644 --- a/tools/perf/arch/arm/annotate/instructions.c +++ b/tools/perf/arch/arm/annotate/instructions.c @@ -53,6 +53,8 @@ static int arm__annotate_init(struct arch *arch, char *cpuid __maybe_unused) arch->associate_instruction_ops = arm__associate_instruction_ops; arch->objdump.comment_char = ';'; arch->objdump.skip_functions_char = '+'; + arch->e_machine = EM_ARM; + arch->e_flags = 0; return 0; out_free_call: diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build index e6dd7cd79ebd06..f7a8b37d1c6883 100644 --- a/tools/perf/arch/arm/util/Build +++ b/tools/perf/arch/arm/util/Build @@ -1,7 +1,5 @@ perf-util-y += perf_regs.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o - perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c deleted file mode 100644 index fc5f71c918020d..00000000000000 --- a/tools/perf/arch/arm/util/dwarf-regs.c +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Mapping of DWARF debug register numbers into register names. - * - * Copyright (C) 2010 Will Deacon, ARM Ltd. - */ - -#include -#include -#include - -struct pt_regs_dwarfnum { - const char *name; - unsigned int dwarfnum; -}; - -#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} -#define GPR_DWARFNUM_NAME(num) \ - {.name = __stringify(%r##num), .dwarfnum = num} -#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} - -/* - * Reference: - * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf - */ -static const struct pt_regs_dwarfnum regdwarfnum_table[] = { - GPR_DWARFNUM_NAME(0), - GPR_DWARFNUM_NAME(1), - GPR_DWARFNUM_NAME(2), - GPR_DWARFNUM_NAME(3), - GPR_DWARFNUM_NAME(4), - GPR_DWARFNUM_NAME(5), - GPR_DWARFNUM_NAME(6), - GPR_DWARFNUM_NAME(7), - GPR_DWARFNUM_NAME(8), - GPR_DWARFNUM_NAME(9), - GPR_DWARFNUM_NAME(10), - REG_DWARFNUM_NAME("%fp", 11), - REG_DWARFNUM_NAME("%ip", 12), - REG_DWARFNUM_NAME("%sp", 13), - REG_DWARFNUM_NAME("%lr", 14), - REG_DWARFNUM_NAME("%pc", 15), - REG_DWARFNUM_END, -}; - -/** - * get_arch_regstr() - lookup register name from it's DWARF register number - * @n: the DWARF register number - * - * get_arch_regstr() returns the name of the register in struct - * regdwarfnum_table from it's DWARF register number. If the register is not - * found in the table, this returns NULL; - */ -const char *get_arch_regstr(unsigned int n) -{ - const struct pt_regs_dwarfnum *roff; - for (roff = regdwarfnum_table; roff->name != NULL; roff++) - if (roff->dwarfnum == n) - return roff->name; - return NULL; -} diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile index 5735ed4479bb9b..91570d5d428e40 100644 --- a/tools/perf/arch/arm64/Makefile +++ b/tools/perf/arch/arm64/Makefile @@ -1,9 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif PERF_HAVE_JITDUMP := 1 -PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 HAVE_KVM_STAT_SUPPORT := 1 # diff --git a/tools/perf/arch/arm64/annotate/instructions.c b/tools/perf/arch/arm64/annotate/instructions.c index f86d9f4798bd06..d465d093e7eb57 100644 --- a/tools/perf/arch/arm64/annotate/instructions.c +++ b/tools/perf/arch/arm64/annotate/instructions.c @@ -113,6 +113,8 @@ static int arm64__annotate_init(struct arch *arch, char *cpuid __maybe_unused) arch->associate_instruction_ops = arm64__associate_instruction_ops; arch->objdump.comment_char = '/'; arch->objdump.skip_functions_char = '+'; + arch->e_machine = EM_AARCH64; + arch->e_flags = 0; return 0; out_free_call: diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build index 343ef7589a77ab..a74521b79eaaa3 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -4,7 +4,6 @@ perf-util-y += perf_regs.o perf-util-y += tsc.o perf-util-y += pmu.o perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 2be99fdf997db1..22b19dcc6beb8e 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c @@ -23,9 +23,12 @@ #include "../../../util/debug.h" #include "../../../util/auxtrace.h" #include "../../../util/record.h" +#include "../../../util/header.h" #include "../../../util/arm-spe.h" #include // reallocarray +#define ARM_SPE_CPU_MAGIC 0x1010101010101010ULL + #define KiB(x) ((x) * 1024) #define MiB(x) ((x) * 1024 * 1024) @@ -37,11 +40,84 @@ struct arm_spe_recording { bool *wrapped; }; +/* + * arm_spe_find_cpus() returns a new cpu map, and the caller should invoke + * perf_cpu_map__put() to release the map after use. + */ +static struct perf_cpu_map *arm_spe_find_cpus(struct evlist *evlist) +{ + struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus; + struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus(); + struct perf_cpu_map *intersect_cpus; + + /* cpu map is not "any" CPU , we have specific CPUs to work with */ + if (!perf_cpu_map__has_any_cpu(event_cpus)) { + intersect_cpus = perf_cpu_map__intersect(event_cpus, online_cpus); + perf_cpu_map__put(online_cpus); + /* Event can be "any" CPU so count all CPUs. */ + } else { + intersect_cpus = online_cpus; + } + + return intersect_cpus; +} + static size_t arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused, - struct evlist *evlist __maybe_unused) + struct evlist *evlist) +{ + struct perf_cpu_map *cpu_map = arm_spe_find_cpus(evlist); + size_t size; + + if (!cpu_map) + return 0; + + size = ARM_SPE_AUXTRACE_PRIV_MAX + + ARM_SPE_CPU_PRIV_MAX * perf_cpu_map__nr(cpu_map); + size *= sizeof(u64); + + perf_cpu_map__put(cpu_map); + return size; +} + +static int arm_spe_save_cpu_header(struct auxtrace_record *itr, + struct perf_cpu cpu, __u64 data[]) { - return ARM_SPE_AUXTRACE_PRIV_SIZE; + struct arm_spe_recording *sper = + container_of(itr, struct arm_spe_recording, itr); + struct perf_pmu *pmu = NULL; + char *cpuid = NULL; + u64 val; + + /* Read CPU MIDR */ + cpuid = get_cpuid_allow_env_override(cpu); + if (!cpuid) + return -ENOMEM; + val = strtol(cpuid, NULL, 16); + + data[ARM_SPE_MAGIC] = ARM_SPE_CPU_MAGIC; + data[ARM_SPE_CPU] = cpu.cpu; + data[ARM_SPE_CPU_NR_PARAMS] = ARM_SPE_CPU_PRIV_MAX - ARM_SPE_CPU_MIDR; + data[ARM_SPE_CPU_MIDR] = val; + + /* Find the associate Arm SPE PMU for the CPU */ + if (perf_cpu_map__has(sper->arm_spe_pmu->cpus, cpu)) + pmu = sper->arm_spe_pmu; + + if (!pmu) { + /* No Arm SPE PMU is found */ + data[ARM_SPE_CPU_PMU_TYPE] = ULLONG_MAX; + data[ARM_SPE_CAP_MIN_IVAL] = 0; + } else { + data[ARM_SPE_CPU_PMU_TYPE] = pmu->type; + + if (perf_pmu__scan_file(pmu, "caps/min_interval", "%lu", &val) != 1) + val = 0; + data[ARM_SPE_CAP_MIN_IVAL] = val; + } + + free(cpuid); + return ARM_SPE_CPU_PRIV_MAX; } static int arm_spe_info_fill(struct auxtrace_record *itr, @@ -49,20 +125,46 @@ static int arm_spe_info_fill(struct auxtrace_record *itr, struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size) { + int i, ret; + size_t offset; struct arm_spe_recording *sper = container_of(itr, struct arm_spe_recording, itr); struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu; + struct perf_cpu_map *cpu_map; + struct perf_cpu cpu; + __u64 *data; - if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE) + if (priv_size != arm_spe_info_priv_size(itr, session->evlist)) return -EINVAL; if (!session->evlist->core.nr_mmaps) return -EINVAL; + cpu_map = arm_spe_find_cpus(session->evlist); + if (!cpu_map) + return -EINVAL; + auxtrace_info->type = PERF_AUXTRACE_ARM_SPE; - auxtrace_info->priv[ARM_SPE_PMU_TYPE] = arm_spe_pmu->type; + auxtrace_info->priv[ARM_SPE_HEADER_VERSION] = ARM_SPE_HEADER_CURRENT_VERSION; + auxtrace_info->priv[ARM_SPE_HEADER_SIZE] = + ARM_SPE_AUXTRACE_PRIV_MAX - ARM_SPE_HEADER_VERSION; + auxtrace_info->priv[ARM_SPE_PMU_TYPE_V2] = arm_spe_pmu->type; + auxtrace_info->priv[ARM_SPE_CPUS_NUM] = perf_cpu_map__nr(cpu_map); + + offset = ARM_SPE_AUXTRACE_PRIV_MAX; + perf_cpu_map__for_each_cpu(cpu, i, cpu_map) { + assert(offset < priv_size); + data = &auxtrace_info->priv[offset]; + ret = arm_spe_save_cpu_header(itr, cpu, data); + if (ret < 0) + goto out; + offset += ret; + } - return 0; + ret = 0; +out: + perf_cpu_map__put(cpu_map); + return ret; } static void @@ -188,9 +290,9 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, evlist__for_each_entry(evlist, evsel) { if (evsel__is_aux_event(evsel)) { - if (!strstarts(evsel->pmu_name, ARM_SPE_PMU_NAME)) { + if (!strstarts(evsel->pmu->name, ARM_SPE_PMU_NAME)) { pr_err("Found unexpected auxtrace event: %s\n", - evsel->pmu_name); + evsel->pmu->name); return -EINVAL; } opts->full_auxtrace = true; diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c deleted file mode 100644 index 917b97d7c5d365..00000000000000 --- a/tools/perf/arch/arm64/util/dwarf-regs.c +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Mapping of DWARF debug register numbers into register names. - * - * Copyright (C) 2010 Will Deacon, ARM Ltd. - */ - -#include -#include -#include -#include -#include /* for struct user_pt_regs */ -#include - -struct pt_regs_dwarfnum { - const char *name; - unsigned int dwarfnum; -}; - -#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} -#define GPR_DWARFNUM_NAME(num) \ - {.name = __stringify(%x##num), .dwarfnum = num} -#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} -#define DWARFNUM2OFFSET(index) \ - (index * sizeof((struct user_pt_regs *)0)->regs[0]) - -/* - * Reference: - * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf - */ -static const struct pt_regs_dwarfnum regdwarfnum_table[] = { - GPR_DWARFNUM_NAME(0), - GPR_DWARFNUM_NAME(1), - GPR_DWARFNUM_NAME(2), - GPR_DWARFNUM_NAME(3), - GPR_DWARFNUM_NAME(4), - GPR_DWARFNUM_NAME(5), - GPR_DWARFNUM_NAME(6), - GPR_DWARFNUM_NAME(7), - GPR_DWARFNUM_NAME(8), - GPR_DWARFNUM_NAME(9), - GPR_DWARFNUM_NAME(10), - GPR_DWARFNUM_NAME(11), - GPR_DWARFNUM_NAME(12), - GPR_DWARFNUM_NAME(13), - GPR_DWARFNUM_NAME(14), - GPR_DWARFNUM_NAME(15), - GPR_DWARFNUM_NAME(16), - GPR_DWARFNUM_NAME(17), - GPR_DWARFNUM_NAME(18), - GPR_DWARFNUM_NAME(19), - GPR_DWARFNUM_NAME(20), - GPR_DWARFNUM_NAME(21), - GPR_DWARFNUM_NAME(22), - GPR_DWARFNUM_NAME(23), - GPR_DWARFNUM_NAME(24), - GPR_DWARFNUM_NAME(25), - GPR_DWARFNUM_NAME(26), - GPR_DWARFNUM_NAME(27), - GPR_DWARFNUM_NAME(28), - GPR_DWARFNUM_NAME(29), - REG_DWARFNUM_NAME("%lr", 30), - REG_DWARFNUM_NAME("%sp", 31), - REG_DWARFNUM_END, -}; - -/** - * get_arch_regstr() - lookup register name from it's DWARF register number - * @n: the DWARF register number - * - * get_arch_regstr() returns the name of the register in struct - * regdwarfnum_table from it's DWARF register number. If the register is not - * found in the table, this returns NULL; - */ -const char *get_arch_regstr(unsigned int n) -{ - const struct pt_regs_dwarfnum *roff; - for (roff = regdwarfnum_table; roff->name != NULL; roff++) - if (roff->dwarfnum == n) - return roff->name; - return NULL; -} - -int regs_query_register_offset(const char *name) -{ - const struct pt_regs_dwarfnum *roff; - - for (roff = regdwarfnum_table; roff->name != NULL; roff++) - if (!strcmp(roff->name, name)) - return DWARFNUM2OFFSET(roff->dwarfnum); - return -EINVAL; -} diff --git a/tools/perf/arch/arm64/util/header.c b/tools/perf/arch/arm64/util/header.c index 741df3614a09ac..f445a2dd629344 100644 --- a/tools/perf/arch/arm64/util/header.c +++ b/tools/perf/arch/arm64/util/header.c @@ -14,73 +14,66 @@ #define MIDR_REVISION_MASK GENMASK(3, 0) #define MIDR_VARIANT_MASK GENMASK(23, 20) -static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus) +static int _get_cpuid(char *buf, size_t sz, struct perf_cpu cpu) { + char path[PATH_MAX]; + FILE *file; const char *sysfs = sysfs__mountpoint(); - struct perf_cpu cpu; - int idx, ret = EINVAL; + assert(cpu.cpu != -1); if (!sysfs || sz < MIDR_SIZE) return EINVAL; - perf_cpu_map__for_each_cpu(cpu, idx, cpus) { - char path[PATH_MAX]; - FILE *file; - - scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR, - sysfs, cpu.cpu); - - file = fopen(path, "r"); - if (!file) { - pr_debug("fopen failed for file %s\n", path); - continue; - } - - if (!fgets(buf, MIDR_SIZE, file)) { - fclose(file); - continue; - } - fclose(file); + scnprintf(path, PATH_MAX, "%s/devices/system/cpu/cpu%d" MIDR, sysfs, cpu.cpu); - /* got midr break loop */ - ret = 0; - break; + file = fopen(path, "r"); + if (!file) { + pr_debug("fopen failed for file %s\n", path); + return EINVAL; } - return ret; + if (!fgets(buf, MIDR_SIZE, file)) { + pr_debug("Failed to read file %s\n", path); + fclose(file); + return EINVAL; + } + fclose(file); + return 0; } -int get_cpuid(char *buf, size_t sz) +int get_cpuid(char *buf, size_t sz, struct perf_cpu cpu) { - struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus(); - int ret; + struct perf_cpu_map *cpus; + int idx; + if (cpu.cpu != -1) + return _get_cpuid(buf, sz, cpu); + + cpus = perf_cpu_map__new_online_cpus(); if (!cpus) return EINVAL; - ret = _get_cpuid(buf, sz, cpus); - - perf_cpu_map__put(cpus); + perf_cpu_map__for_each_cpu(cpu, idx, cpus) { + int ret = _get_cpuid(buf, sz, cpu); - return ret; + if (ret == 0) + return 0; + } + return EINVAL; } -char *get_cpuid_str(struct perf_pmu *pmu) +char *get_cpuid_str(struct perf_cpu cpu) { - char *buf = NULL; + char *buf = malloc(MIDR_SIZE); int res; - if (!pmu || !pmu->cpus) - return NULL; - - buf = malloc(MIDR_SIZE); if (!buf) return NULL; /* read midr from list of cpus mapped to this pmu */ - res = _get_cpuid(buf, MIDR_SIZE, pmu->cpus); + res = get_cpuid(buf, MIDR_SIZE, cpu); if (res) { - pr_err("failed to get cpuid string for PMU %s\n", pmu->name); + pr_err("failed to get cpuid string for CPU %d\n", cpu.cpu); free(buf); buf = NULL; } diff --git a/tools/perf/arch/arm64/util/pmu.c b/tools/perf/arch/arm64/util/pmu.c index 2a4eab2d160ee5..895fb0d0610cf1 100644 --- a/tools/perf/arch/arm64/util/pmu.c +++ b/tools/perf/arch/arm64/util/pmu.c @@ -1,30 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -#include -#include "../../../util/cpumap.h" -#include "../../../util/header.h" #include "../../../util/pmu.h" #include "../../../util/pmus.h" +#include "../../../util/tool_pmu.h" #include -#include -const struct pmu_metrics_table *pmu_metrics_table__find(void) -{ - struct perf_pmu *pmu; - - /* Metrics aren't currently supported on heterogeneous Arm systems */ - if (perf_pmus__num_core_pmus() > 1) - return NULL; - - /* Doesn't matter which one here because they'll all be the same */ - pmu = perf_pmus__find_core_pmu(); - if (pmu) - return perf_pmu__find_metrics_table(pmu); - - return NULL; -} - -double perf_pmu__cpu_slots_per_cycle(void) +u64 tool_pmu__cpu_slots_per_cycle(void) { char path[PATH_MAX]; unsigned long long slots = 0; @@ -41,5 +22,5 @@ double perf_pmu__cpu_slots_per_cycle(void) filename__read_ull(path, &slots); } - return slots ? (double)slots : NAN; + return slots; } diff --git a/tools/perf/arch/csky/Makefile b/tools/perf/arch/csky/Makefile deleted file mode 100644 index 88c08eed9c7be5..00000000000000 --- a/tools/perf/arch/csky/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif diff --git a/tools/perf/arch/csky/annotate/instructions.c b/tools/perf/arch/csky/annotate/instructions.c index 5337bfb7d5fcf6..14270311d215ef 100644 --- a/tools/perf/arch/csky/annotate/instructions.c +++ b/tools/perf/arch/csky/annotate/instructions.c @@ -43,6 +43,11 @@ static int csky__annotate_init(struct arch *arch, char *cpuid __maybe_unused) arch->initialized = true; arch->objdump.comment_char = '/'; arch->associate_instruction_ops = csky__associate_ins_ops; - + arch->e_machine = EM_CSKY; +#if defined(__CSKYABIV2__) + arch->e_flags = EF_CSKY_ABIV2; +#else + arch->e_flags = EF_CSKY_ABIV1; +#endif return 0; } diff --git a/tools/perf/arch/csky/util/Build b/tools/perf/arch/csky/util/Build index 99d83f41bf4335..5e6ea82c42021d 100644 --- a/tools/perf/arch/csky/util/Build +++ b/tools/perf/arch/csky/util/Build @@ -1,4 +1,3 @@ perf-util-y += perf_regs.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/csky/util/dwarf-regs.c b/tools/perf/arch/csky/util/dwarf-regs.c deleted file mode 100644 index ca86ecaeacbb52..00000000000000 --- a/tools/perf/arch/csky/util/dwarf-regs.c +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. -// Mapping of DWARF debug register numbers into register names. - -#include -#include - -#if defined(__CSKYABIV2__) -#define CSKY_MAX_REGS 73 -const char *csky_dwarf_regs_table[CSKY_MAX_REGS] = { - /* r0 ~ r8 */ - "%a0", "%a1", "%a2", "%a3", "%regs0", "%regs1", "%regs2", "%regs3", - /* r9 ~ r15 */ - "%regs4", "%regs5", "%regs6", "%regs7", "%regs8", "%regs9", "%sp", - "%lr", - /* r16 ~ r23 */ - "%exregs0", "%exregs1", "%exregs2", "%exregs3", "%exregs4", - "%exregs5", "%exregs6", "%exregs7", - /* r24 ~ r31 */ - "%exregs8", "%exregs9", "%exregs10", "%exregs11", "%exregs12", - "%exregs13", "%exregs14", "%tls", - "%pc", NULL, NULL, NULL, "%hi", "%lo", NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "%epc", -}; -#else -#define CSKY_MAX_REGS 57 -const char *csky_dwarf_regs_table[CSKY_MAX_REGS] = { - /* r0 ~ r8 */ - "%sp", "%regs9", "%a0", "%a1", "%a2", "%a3", "%regs0", "%regs1", - /* r9 ~ r15 */ - "%regs2", "%regs3", "%regs4", "%regs5", "%regs6", "%regs7", "%regs8", - "%lr", - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "%epc", -}; -#endif - -const char *get_arch_regstr(unsigned int n) -{ - return (n < CSKY_MAX_REGS) ? csky_dwarf_regs_table[n] : NULL; -} diff --git a/tools/perf/arch/loongarch/Makefile b/tools/perf/arch/loongarch/Makefile index c89d6bb6b184b1..52544d59245bab 100644 --- a/tools/perf/arch/loongarch/Makefile +++ b/tools/perf/arch/loongarch/Makefile @@ -1,8 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif -PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 PERF_HAVE_JITDUMP := 1 HAVE_KVM_STAT_SUPPORT := 1 diff --git a/tools/perf/arch/loongarch/annotate/instructions.c b/tools/perf/arch/loongarch/annotate/instructions.c index ab43b1ab51e3ba..70262d5f144424 100644 --- a/tools/perf/arch/loongarch/annotate/instructions.c +++ b/tools/perf/arch/loongarch/annotate/instructions.c @@ -131,6 +131,8 @@ int loongarch__annotate_init(struct arch *arch, char *cpuid __maybe_unused) arch->associate_instruction_ops = loongarch__associate_ins_ops; arch->initialized = true; arch->objdump.comment_char = '#'; + arch->e_machine = EM_LOONGARCH; + arch->e_flags = 0; } return 0; diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongarch/util/Build index b6b97de4823331..0aa31986ecb5b2 100644 --- a/tools/perf/arch/loongarch/util/Build +++ b/tools/perf/arch/loongarch/util/Build @@ -1,7 +1,6 @@ perf-util-y += header.o perf-util-y += perf_regs.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o diff --git a/tools/perf/arch/loongarch/util/dwarf-regs.c b/tools/perf/arch/loongarch/util/dwarf-regs.c deleted file mode 100644 index 0f6ebc38746311..00000000000000 --- a/tools/perf/arch/loongarch/util/dwarf-regs.c +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. - * - * Copyright (C) 2020-2023 Loongson Technology Corporation Limited - */ - -#include -#include /* for EINVAL */ -#include /* for strcmp */ -#include - -struct pt_regs_dwarfnum { - const char *name; - unsigned int dwarfnum; -}; - -static struct pt_regs_dwarfnum loongarch_gpr_table[] = { - {"%r0", 0}, {"%r1", 1}, {"%r2", 2}, {"%r3", 3}, - {"%r4", 4}, {"%r5", 5}, {"%r6", 6}, {"%r7", 7}, - {"%r8", 8}, {"%r9", 9}, {"%r10", 10}, {"%r11", 11}, - {"%r12", 12}, {"%r13", 13}, {"%r14", 14}, {"%r15", 15}, - {"%r16", 16}, {"%r17", 17}, {"%r18", 18}, {"%r19", 19}, - {"%r20", 20}, {"%r21", 21}, {"%r22", 22}, {"%r23", 23}, - {"%r24", 24}, {"%r25", 25}, {"%r26", 26}, {"%r27", 27}, - {"%r28", 28}, {"%r29", 29}, {"%r30", 30}, {"%r31", 31}, - {NULL, 0} -}; - -const char *get_arch_regstr(unsigned int n) -{ - n %= 32; - return loongarch_gpr_table[n].name; -} - -int regs_query_register_offset(const char *name) -{ - const struct pt_regs_dwarfnum *roff; - - for (roff = loongarch_gpr_table; roff->name != NULL; roff++) - if (!strcmp(roff->name, name)) - return roff->dwarfnum; - return -EINVAL; -} diff --git a/tools/perf/arch/loongarch/util/header.c b/tools/perf/arch/loongarch/util/header.c index d962dff55512b3..0c6d823334a21d 100644 --- a/tools/perf/arch/loongarch/util/header.c +++ b/tools/perf/arch/loongarch/util/header.c @@ -70,7 +70,7 @@ static char *_get_cpuid(void) return cpuid; } -int get_cpuid(char *buffer, size_t sz) +int get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused) { int ret = 0; char *cpuid = _get_cpuid(); @@ -90,7 +90,7 @@ int get_cpuid(char *buffer, size_t sz) return ret; } -char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused) +char *get_cpuid_str(struct perf_cpu cpu __maybe_unused) { return _get_cpuid(); } diff --git a/tools/perf/arch/mips/Makefile b/tools/perf/arch/mips/Makefile index cd0b011b3be5f5..827168f1077a67 100644 --- a/tools/perf/arch/mips/Makefile +++ b/tools/perf/arch/mips/Makefile @@ -1,8 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif - # Syscall table generation for perf out := $(OUTPUT)arch/mips/include/generated/asm header := $(out)/syscalls_n64.c diff --git a/tools/perf/arch/mips/annotate/instructions.c b/tools/perf/arch/mips/annotate/instructions.c index 340993f2a897a4..b50b46c613d660 100644 --- a/tools/perf/arch/mips/annotate/instructions.c +++ b/tools/perf/arch/mips/annotate/instructions.c @@ -40,6 +40,8 @@ int mips__annotate_init(struct arch *arch, char *cpuid __maybe_unused) arch->associate_instruction_ops = mips__associate_ins_ops; arch->initialized = true; arch->objdump.comment_char = '#'; + arch->e_machine = EM_MIPS; + arch->e_flags = 0; } return 0; diff --git a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl index 1464c6be6eb3c7..c844cd5cda620b 100644 --- a/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl +++ b/tools/perf/arch/mips/entry/syscalls/syscall_n64.tbl @@ -377,3 +377,7 @@ 460 n64 lsm_set_self_attr sys_lsm_set_self_attr 461 n64 lsm_list_modules sys_lsm_list_modules 462 n64 mseal sys_mseal +463 n64 setxattrat sys_setxattrat +464 n64 getxattrat sys_getxattrat +465 n64 listxattrat sys_listxattrat +466 n64 removexattrat sys_removexattrat diff --git a/tools/perf/arch/mips/util/Build b/tools/perf/arch/mips/util/Build index e4644f1e68a039..691fa2051958a0 100644 --- a/tools/perf/arch/mips/util/Build +++ b/tools/perf/arch/mips/util/Build @@ -1,3 +1,2 @@ perf-util-y += perf_regs.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o diff --git a/tools/perf/arch/mips/util/dwarf-regs.c b/tools/perf/arch/mips/util/dwarf-regs.c deleted file mode 100644 index 25c13a91c2a757..00000000000000 --- a/tools/perf/arch/mips/util/dwarf-regs.c +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. - * - * Copyright (C) 2013 Cavium, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include - -static const char *mips_gpr_names[32] = { - "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", - "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", - "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", - "$30", "$31" -}; - -const char *get_arch_regstr(unsigned int n) -{ - if (n < 32) - return mips_gpr_names[n]; - if (n == 64) - return "hi"; - if (n == 65) - return "lo"; - return NULL; -} diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile index bf6d323574f66d..dc8f4fb8e324ab 100644 --- a/tools/perf/arch/powerpc/Makefile +++ b/tools/perf/arch/powerpc/Makefile @@ -1,10 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif - HAVE_KVM_STAT_SUPPORT := 1 -PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 PERF_HAVE_JITDUMP := 1 # diff --git a/tools/perf/arch/powerpc/annotate/instructions.c b/tools/perf/arch/powerpc/annotate/instructions.c index ede9eeade0ab34..ca567cfdcbdb4d 100644 --- a/tools/perf/arch/powerpc/annotate/instructions.c +++ b/tools/perf/arch/powerpc/annotate/instructions.c @@ -255,7 +255,7 @@ static struct ins_ops *check_ppc_insn(struct disasm_line *dl) * is moved to r31. update_insn_state_powerpc tracks these state * changes */ -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT static void update_insn_state_powerpc(struct type_state *state, struct data_loc_info *dloc, Dwarf_Die * cu_die __maybe_unused, struct disasm_line *dl) @@ -300,7 +300,7 @@ static void update_insn_state_powerpc(struct type_state *state, insn_offset, src->reg1, dst->reg1); pr_debug_type_name(&tsr->type, tsr->kind); } -#endif /* HAVE_DWARF_SUPPORT */ +#endif /* HAVE_LIBDW_SUPPORT */ static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused) { @@ -309,6 +309,8 @@ static int powerpc__annotate_init(struct arch *arch, char *cpuid __maybe_unused) arch->associate_instruction_ops = powerpc__associate_instruction_ops; arch->objdump.comment_char = '#'; annotate_opts.show_asm_raw = true; + arch->e_machine = EM_PPC; + arch->e_flags = 0; } return 0; diff --git a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl index ebae8415dfbbab..d8b4ab78bef076 100644 --- a/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/powerpc/entry/syscalls/syscall.tbl @@ -553,3 +553,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build index 6c588ecdf3bd42..ed82715080f96a 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build @@ -7,8 +7,7 @@ perf-util-y += sym-handling.o perf-util-y += evsel.o perf-util-y += event.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o -perf-util-$(CONFIG_DWARF) += skip-callchain-idx.o +perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o perf-util-$(CONFIG_LIBUNWIND) += unwind-libunwind.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c deleted file mode 100644 index 104c7ae5c433df..00000000000000 --- a/tools/perf/arch/powerpc/util/dwarf-regs.c +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Mapping of DWARF debug register numbers into register names. - * - * Copyright (C) 2010 Ian Munsie, IBM Corporation. - */ - -#include -#include -#include -#include -#include -#include -#include - -struct pt_regs_dwarfnum { - const char *name; - unsigned int dwarfnum; - unsigned int ptregs_offset; -}; - -#define REG_DWARFNUM_NAME(r, num) \ - {.name = __stringify(%)__stringify(r), .dwarfnum = num, \ - .ptregs_offset = offsetof(struct pt_regs, r)} -#define GPR_DWARFNUM_NAME(num) \ - {.name = __stringify(%gpr##num), .dwarfnum = num, \ - .ptregs_offset = offsetof(struct pt_regs, gpr[num])} -#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0, .ptregs_offset = 0} - -/* - * Reference: - * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html - */ -static const struct pt_regs_dwarfnum regdwarfnum_table[] = { - GPR_DWARFNUM_NAME(0), - GPR_DWARFNUM_NAME(1), - GPR_DWARFNUM_NAME(2), - GPR_DWARFNUM_NAME(3), - GPR_DWARFNUM_NAME(4), - GPR_DWARFNUM_NAME(5), - GPR_DWARFNUM_NAME(6), - GPR_DWARFNUM_NAME(7), - GPR_DWARFNUM_NAME(8), - GPR_DWARFNUM_NAME(9), - GPR_DWARFNUM_NAME(10), - GPR_DWARFNUM_NAME(11), - GPR_DWARFNUM_NAME(12), - GPR_DWARFNUM_NAME(13), - GPR_DWARFNUM_NAME(14), - GPR_DWARFNUM_NAME(15), - GPR_DWARFNUM_NAME(16), - GPR_DWARFNUM_NAME(17), - GPR_DWARFNUM_NAME(18), - GPR_DWARFNUM_NAME(19), - GPR_DWARFNUM_NAME(20), - GPR_DWARFNUM_NAME(21), - GPR_DWARFNUM_NAME(22), - GPR_DWARFNUM_NAME(23), - GPR_DWARFNUM_NAME(24), - GPR_DWARFNUM_NAME(25), - GPR_DWARFNUM_NAME(26), - GPR_DWARFNUM_NAME(27), - GPR_DWARFNUM_NAME(28), - GPR_DWARFNUM_NAME(29), - GPR_DWARFNUM_NAME(30), - GPR_DWARFNUM_NAME(31), - REG_DWARFNUM_NAME(msr, 66), - REG_DWARFNUM_NAME(ctr, 109), - REG_DWARFNUM_NAME(link, 108), - REG_DWARFNUM_NAME(xer, 101), - REG_DWARFNUM_NAME(dar, 119), - REG_DWARFNUM_NAME(dsisr, 118), - REG_DWARFNUM_END, -}; - -/** - * get_arch_regstr() - lookup register name from it's DWARF register number - * @n: the DWARF register number - * - * get_arch_regstr() returns the name of the register in struct - * regdwarfnum_table from it's DWARF register number. If the register is not - * found in the table, this returns NULL; - */ -const char *get_arch_regstr(unsigned int n) -{ - const struct pt_regs_dwarfnum *roff; - for (roff = regdwarfnum_table; roff->name != NULL; roff++) - if (roff->dwarfnum == n) - return roff->name; - return NULL; -} - -int regs_query_register_offset(const char *name) -{ - const struct pt_regs_dwarfnum *roff; - for (roff = regdwarfnum_table; roff->name != NULL; roff++) - if (!strcmp(roff->name, name)) - return roff->ptregs_offset; - return -EINVAL; -} - -#define PPC_OP(op) (((op) >> 26) & 0x3F) -#define PPC_RA(a) (((a) >> 16) & 0x1f) -#define PPC_RT(t) (((t) >> 21) & 0x1f) -#define PPC_RB(b) (((b) >> 11) & 0x1f) -#define PPC_D(D) ((D) & 0xfffe) -#define PPC_DS(DS) ((DS) & 0xfffc) -#define OP_LD 58 -#define OP_STD 62 - -static int get_source_reg(u32 raw_insn) -{ - return PPC_RA(raw_insn); -} - -static int get_target_reg(u32 raw_insn) -{ - return PPC_RT(raw_insn); -} - -static int get_offset_opcode(u32 raw_insn) -{ - int opcode = PPC_OP(raw_insn); - - /* DS- form */ - if ((opcode == OP_LD) || (opcode == OP_STD)) - return PPC_DS(raw_insn); - else - return PPC_D(raw_insn); -} - -/* - * Fills the required fields for op_loc depending on if it - * is a source or target. - * D form: ins RT,D(RA) -> src_reg1 = RA, offset = D, dst_reg1 = RT - * DS form: ins RT,DS(RA) -> src_reg1 = RA, offset = DS, dst_reg1 = RT - * X form: ins RT,RA,RB -> src_reg1 = RA, src_reg2 = RB, dst_reg1 = RT - */ -void get_powerpc_regs(u32 raw_insn, int is_source, - struct annotated_op_loc *op_loc) -{ - if (is_source) - op_loc->reg1 = get_source_reg(raw_insn); - else - op_loc->reg1 = get_target_reg(raw_insn); - - if (op_loc->multi_regs) - op_loc->reg2 = PPC_RB(raw_insn); - - /* TODO: Implement offset handling for X Form */ - if ((op_loc->mem_ref) && (PPC_OP(raw_insn) != 31)) - op_loc->offset = get_offset_opcode(raw_insn); -} diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c index 6b00efd53638d5..c7df534dbf8f84 100644 --- a/tools/perf/arch/powerpc/util/header.c +++ b/tools/perf/arch/powerpc/util/header.c @@ -10,9 +10,21 @@ #include "utils_header.h" #include "metricgroup.h" #include +#include + +static bool is_compat_mode(void) +{ + u64 base_platform = getauxval(AT_BASE_PLATFORM); + u64 platform = getauxval(AT_PLATFORM); + + if (!strcmp((char *)platform, (char *)base_platform)) + return false; + + return true; +} int -get_cpuid(char *buffer, size_t sz) +get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused) { unsigned long pvr; int nb; @@ -30,11 +42,29 @@ get_cpuid(char *buffer, size_t sz) } char * -get_cpuid_str(struct perf_pmu *pmu __maybe_unused) +get_cpuid_str(struct perf_cpu cpu __maybe_unused) { char *bufp; + unsigned long pvr; + + /* + * IBM Power System supports compatible mode. That is + * Nth generation platform can support previous generation + * OS in a mode called compatibile mode. For ex. LPAR can be + * booted in a Power9 mode when the system is a Power10. + * + * In the compatible mode, care must be taken when generating + * PVR value. When read, PVR will be of the AT_BASE_PLATFORM + * To support generic events, return 0x00ffffff as pvr when + * booted in compat mode. Based on this pvr value, json will + * pick events from pmu-events/arch/powerpc/compat + */ + if (!is_compat_mode()) + pvr = mfspr(SPRN_PVR); + else + pvr = 0x00ffffff; - if (asprintf(&bufp, "0x%.8lx", mfspr(SPRN_PVR)) < 0) + if (asprintf(&bufp, "0x%.8lx", pvr) < 0) bufp = NULL; return bufp; diff --git a/tools/perf/arch/riscv/Makefile b/tools/perf/arch/riscv/Makefile index 90c3c476a242c0..18ad078000e2bb 100644 --- a/tools/perf/arch/riscv/Makefile +++ b/tools/perf/arch/riscv/Makefile @@ -1,6 +1,25 @@ -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif -PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 +# SPDX-License-Identifier: GPL-2.0 PERF_HAVE_JITDUMP := 1 HAVE_KVM_STAT_SUPPORT := 1 + +# +# Syscall table generation for perf +# + +out := $(OUTPUT)arch/riscv/include/generated/asm +header := $(out)/syscalls.c +incpath := $(srctree)/tools +sysdef := $(srctree)/tools/arch/riscv/include/uapi/asm/unistd.h +sysprf := $(srctree)/tools/perf/arch/riscv/entry/syscalls/ +systbl := $(sysprf)/mksyscalltbl + +# Create output directory if not already present +$(shell [ -d '$(out)' ] || mkdir -p '$(out)') + +$(header): $(sysdef) $(systbl) + $(Q)$(SHELL) '$(systbl)' '$(CC)' '$(HOSTCC)' $(incpath) $(sysdef) > $@ + +clean:: + $(call QUIET_CLEAN, riscv) $(RM) $(header) + +archheaders: $(header) diff --git a/tools/perf/arch/riscv/entry/syscalls/mksyscalltbl b/tools/perf/arch/riscv/entry/syscalls/mksyscalltbl new file mode 100755 index 00000000000000..c59f5e852b9771 --- /dev/null +++ b/tools/perf/arch/riscv/entry/syscalls/mksyscalltbl @@ -0,0 +1,47 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Generate system call table for perf. Derived from +# powerpc script. +# +# Copyright IBM Corp. 2017 +# Author(s): Hendrik Brueckner +# Changed by: Ravi Bangoria +# Changed by: Kim Phillips +# Changed by: Björn Töpel + +gcc=$1 +hostcc=$2 +incpath=$3 +input=$4 + +if ! test -r $input; then + echo "Could not read input file" >&2 + exit 1 +fi + +create_sc_table() +{ + local sc nr max_nr + + while read sc nr; do + printf "%s\n" " [$nr] = \"$sc\"," + max_nr=$nr + done + + echo "#define SYSCALLTBL_RISCV_MAX_ID $max_nr" +} + +create_table() +{ + echo "#include \"$input\"" + echo "static const char *const syscalltbl_riscv[] = {" + create_sc_table + echo "};" +} + +$gcc -E -dM -x c -I $incpath/include/uapi $input \ + |awk '$2 ~ "__NR" && $3 !~ "__NR3264_" { + sub("^#define __NR(3264)?_", ""); + print | "sort -k2 -n"}' \ + |create_table diff --git a/tools/perf/arch/riscv/include/dwarf-regs-table.h b/tools/perf/arch/riscv/include/dwarf-regs-table.h new file mode 100644 index 00000000000000..a45b63a6d5a8e3 --- /dev/null +++ b/tools/perf/arch/riscv/include/dwarf-regs-table.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifdef DEFINE_DWARF_REGSTR_TABLE +/* This is included in perf/util/dwarf-regs.c */ + +#define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg + +static const char * const riscv_regstr_tbl[] = { + REG_DWARFNUM_NAME("%zero", 0), + REG_DWARFNUM_NAME("%ra", 1), + REG_DWARFNUM_NAME("%sp", 2), + REG_DWARFNUM_NAME("%gp", 3), + REG_DWARFNUM_NAME("%tp", 4), + REG_DWARFNUM_NAME("%t0", 5), + REG_DWARFNUM_NAME("%t1", 6), + REG_DWARFNUM_NAME("%t2", 7), + REG_DWARFNUM_NAME("%s0", 8), + REG_DWARFNUM_NAME("%s1", 9), + REG_DWARFNUM_NAME("%a0", 10), + REG_DWARFNUM_NAME("%a1", 11), + REG_DWARFNUM_NAME("%a2", 12), + REG_DWARFNUM_NAME("%a3", 13), + REG_DWARFNUM_NAME("%a4", 14), + REG_DWARFNUM_NAME("%a5", 15), + REG_DWARFNUM_NAME("%a6", 16), + REG_DWARFNUM_NAME("%a7", 17), + REG_DWARFNUM_NAME("%s2", 18), + REG_DWARFNUM_NAME("%s3", 19), + REG_DWARFNUM_NAME("%s4", 20), + REG_DWARFNUM_NAME("%s5", 21), + REG_DWARFNUM_NAME("%s6", 22), + REG_DWARFNUM_NAME("%s7", 23), + REG_DWARFNUM_NAME("%s8", 24), + REG_DWARFNUM_NAME("%s9", 25), + REG_DWARFNUM_NAME("%s10", 26), + REG_DWARFNUM_NAME("%s11", 27), + REG_DWARFNUM_NAME("%t3", 28), + REG_DWARFNUM_NAME("%t4", 29), + REG_DWARFNUM_NAME("%t5", 30), + REG_DWARFNUM_NAME("%t6", 31), +}; + +#endif diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build index f865cb0489ec6f..58a672246024dd 100644 --- a/tools/perf/arch/riscv/util/Build +++ b/tools/perf/arch/riscv/util/Build @@ -2,5 +2,4 @@ perf-util-y += perf_regs.o perf-util-y += header.o perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/riscv/util/dwarf-regs.c b/tools/perf/arch/riscv/util/dwarf-regs.c deleted file mode 100644 index cd0504c02e2e02..00000000000000 --- a/tools/perf/arch/riscv/util/dwarf-regs.c +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. - * Mapping of DWARF debug register numbers into register names. - */ - -#include -#include /* for EINVAL */ -#include /* for strcmp */ -#include - -struct pt_regs_dwarfnum { - const char *name; - unsigned int dwarfnum; -}; - -#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} -#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} - -struct pt_regs_dwarfnum riscv_dwarf_regs_table[] = { - REG_DWARFNUM_NAME("%zero", 0), - REG_DWARFNUM_NAME("%ra", 1), - REG_DWARFNUM_NAME("%sp", 2), - REG_DWARFNUM_NAME("%gp", 3), - REG_DWARFNUM_NAME("%tp", 4), - REG_DWARFNUM_NAME("%t0", 5), - REG_DWARFNUM_NAME("%t1", 6), - REG_DWARFNUM_NAME("%t2", 7), - REG_DWARFNUM_NAME("%s0", 8), - REG_DWARFNUM_NAME("%s1", 9), - REG_DWARFNUM_NAME("%a0", 10), - REG_DWARFNUM_NAME("%a1", 11), - REG_DWARFNUM_NAME("%a2", 12), - REG_DWARFNUM_NAME("%a3", 13), - REG_DWARFNUM_NAME("%a4", 14), - REG_DWARFNUM_NAME("%a5", 15), - REG_DWARFNUM_NAME("%a6", 16), - REG_DWARFNUM_NAME("%a7", 17), - REG_DWARFNUM_NAME("%s2", 18), - REG_DWARFNUM_NAME("%s3", 19), - REG_DWARFNUM_NAME("%s4", 20), - REG_DWARFNUM_NAME("%s5", 21), - REG_DWARFNUM_NAME("%s6", 22), - REG_DWARFNUM_NAME("%s7", 23), - REG_DWARFNUM_NAME("%s8", 24), - REG_DWARFNUM_NAME("%s9", 25), - REG_DWARFNUM_NAME("%s10", 26), - REG_DWARFNUM_NAME("%s11", 27), - REG_DWARFNUM_NAME("%t3", 28), - REG_DWARFNUM_NAME("%t4", 29), - REG_DWARFNUM_NAME("%t5", 30), - REG_DWARFNUM_NAME("%t6", 31), - REG_DWARFNUM_END, -}; - -#define RISCV_MAX_REGS ((sizeof(riscv_dwarf_regs_table) / \ - sizeof(riscv_dwarf_regs_table[0])) - 1) - -const char *get_arch_regstr(unsigned int n) -{ - return (n < RISCV_MAX_REGS) ? riscv_dwarf_regs_table[n].name : NULL; -} - -int regs_query_register_offset(const char *name) -{ - const struct pt_regs_dwarfnum *roff; - - for (roff = riscv_dwarf_regs_table; roff->name; roff++) - if (!strcmp(roff->name, name)) - return roff->dwarfnum; - return -EINVAL; -} diff --git a/tools/perf/arch/riscv/util/header.c b/tools/perf/arch/riscv/util/header.c index 1b29030021eeba..4b839203d4a54d 100644 --- a/tools/perf/arch/riscv/util/header.c +++ b/tools/perf/arch/riscv/util/header.c @@ -81,7 +81,7 @@ static char *_get_cpuid(void) return cpuid; } -int get_cpuid(char *buffer, size_t sz) +int get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused) { char *cpuid = _get_cpuid(); int ret = 0; @@ -98,7 +98,7 @@ int get_cpuid(char *buffer, size_t sz) } char * -get_cpuid_str(struct perf_pmu *pmu __maybe_unused) +get_cpuid_str(struct perf_cpu cpu __maybe_unused) { return _get_cpuid(); } diff --git a/tools/perf/arch/riscv64/annotate/instructions.c b/tools/perf/arch/riscv64/annotate/instructions.c index 869a0eb2895319..55cf911633f8bd 100644 --- a/tools/perf/arch/riscv64/annotate/instructions.c +++ b/tools/perf/arch/riscv64/annotate/instructions.c @@ -28,6 +28,8 @@ int riscv64__annotate_init(struct arch *arch, char *cpuid __maybe_unused) arch->associate_instruction_ops = riscv64__associate_ins_ops; arch->initialized = true; arch->objdump.comment_char = '#'; + arch->e_machine = EM_RISCV; + arch->e_flags = 0; } return 0; diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile index 56994e63b43ae2..c431c21b11ef82 100644 --- a/tools/perf/arch/s390/Makefile +++ b/tools/perf/arch/s390/Makefile @@ -1,9 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif HAVE_KVM_STAT_SUPPORT := 1 -PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 PERF_HAVE_JITDUMP := 1 # diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c index eeac25cca699a0..c61193f1e09640 100644 --- a/tools/perf/arch/s390/annotate/instructions.c +++ b/tools/perf/arch/s390/annotate/instructions.c @@ -166,6 +166,8 @@ static int s390__annotate_init(struct arch *arch, char *cpuid __maybe_unused) if (s390__cpuid_parse(arch, cpuid)) err = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING; } + arch->e_machine = EM_S390; + arch->e_flags = 0; } return err; diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl index 01071182763e96..e9115b4d8b635b 100644 --- a/tools/perf/arch/s390/entry/syscalls/syscall.tbl +++ b/tools/perf/arch/s390/entry/syscalls/syscall.tbl @@ -465,3 +465,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal sys_mseal +463 common setxattrat sys_setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat sys_removexattrat diff --git a/tools/perf/arch/s390/util/Build b/tools/perf/arch/s390/util/Build index 1ac830030ff3f4..736c0ad0919437 100644 --- a/tools/perf/arch/s390/util/Build +++ b/tools/perf/arch/s390/util/Build @@ -2,7 +2,6 @@ perf-util-y += header.o perf-util-$(CONFIG_LIBTRACEEVENT) += kvm-stat.o perf-util-y += perf_regs.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o perf-util-y += machine.o diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c deleted file mode 100644 index dfddb3099bfa56..00000000000000 --- a/tools/perf/arch/s390/util/dwarf-regs.c +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Mapping of DWARF debug register numbers into register names. - * - * Copyright IBM Corp. 2010, 2017 - * Author(s): Hendrik Brueckner - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "dwarf-regs-table.h" - -const char *get_arch_regstr(unsigned int n) -{ - return (n >= ARRAY_SIZE(s390_dwarf_regs)) ? NULL : s390_dwarf_regs[n]; -} - -/* - * Convert the register name into an offset to struct pt_regs (kernel). - * This is required by the BPF prologue generator. The BPF - * program is called in the BPF overflow handler in the perf - * core. - */ -int regs_query_register_offset(const char *name) -{ - unsigned long gpr; - - if (!name || strncmp(name, "%r", 2)) - return -EINVAL; - - errno = 0; - gpr = strtoul(name + 2, NULL, 10); - if (errno || gpr >= 16) - return -EINVAL; - - return offsetof(user_pt_regs, gprs) + 8 * gpr; -} diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c index 7933f6871c8180..db54677a17d24a 100644 --- a/tools/perf/arch/s390/util/header.c +++ b/tools/perf/arch/s390/util/header.c @@ -27,7 +27,7 @@ #define SYSINFO "/proc/sysinfo" #define SRVLVL "/proc/service_levels" -int get_cpuid(char *buffer, size_t sz) +int get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused) { char *cp, *line = NULL, *line2; char type[8], model[33], version[8], manufacturer[32], authorization[8]; @@ -137,11 +137,11 @@ int get_cpuid(char *buffer, size_t sz) return (nbytes >= sz) ? ENOBUFS : 0; } -char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused) +char *get_cpuid_str(struct perf_cpu cpu) { char *buf = malloc(128); - if (buf && get_cpuid(buf, 128)) + if (buf && get_cpuid(buf, 128, cpu)) zfree(&buf); return buf; } diff --git a/tools/perf/arch/sh/Build b/tools/perf/arch/sh/Build deleted file mode 100644 index e63eabc2c8f416..00000000000000 --- a/tools/perf/arch/sh/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-y += util/ diff --git a/tools/perf/arch/sh/Makefile b/tools/perf/arch/sh/Makefile deleted file mode 100644 index 88c08eed9c7be5..00000000000000 --- a/tools/perf/arch/sh/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif diff --git a/tools/perf/arch/sh/util/Build b/tools/perf/arch/sh/util/Build deleted file mode 100644 index 32f44fc4ab9854..00000000000000 --- a/tools/perf/arch/sh/util/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-$(CONFIG_DWARF) += dwarf-regs.o diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c deleted file mode 100644 index 4b17fc86c73bd4..00000000000000 --- a/tools/perf/arch/sh/util/dwarf-regs.c +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Mapping of DWARF debug register numbers into register names. - * - * Copyright (C) 2010 Matt Fleming - */ - -#include -#include - -/* - * Generic dwarf analysis helpers - */ - -#define SH_MAX_REGS 18 -const char *sh_regs_table[SH_MAX_REGS] = { - "r0", - "r1", - "r2", - "r3", - "r4", - "r5", - "r6", - "r7", - "r8", - "r9", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", - "pc", - "pr", -}; - -/* Return architecture dependent register string (for kprobe-tracer) */ -const char *get_arch_regstr(unsigned int n) -{ - return (n < SH_MAX_REGS) ? sh_regs_table[n] : NULL; -} diff --git a/tools/perf/arch/sparc/Build b/tools/perf/arch/sparc/Build deleted file mode 100644 index e63eabc2c8f416..00000000000000 --- a/tools/perf/arch/sparc/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-y += util/ diff --git a/tools/perf/arch/sparc/Makefile b/tools/perf/arch/sparc/Makefile index 4031db72ba71a9..8b59ce8efb8926 100644 --- a/tools/perf/arch/sparc/Makefile +++ b/tools/perf/arch/sparc/Makefile @@ -1,6 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif - PERF_HAVE_JITDUMP := 1 diff --git a/tools/perf/arch/sparc/annotate/instructions.c b/tools/perf/arch/sparc/annotate/instructions.c index 2614c010c23522..68c31580ccfc44 100644 --- a/tools/perf/arch/sparc/annotate/instructions.c +++ b/tools/perf/arch/sparc/annotate/instructions.c @@ -163,6 +163,8 @@ static int sparc__annotate_init(struct arch *arch, char *cpuid __maybe_unused) arch->initialized = true; arch->associate_instruction_ops = sparc__associate_instruction_ops; arch->objdump.comment_char = '#'; + arch->e_machine = EM_SPARC; + arch->e_flags = 0; } return 0; diff --git a/tools/perf/arch/sparc/util/Build b/tools/perf/arch/sparc/util/Build deleted file mode 100644 index 32f44fc4ab9854..00000000000000 --- a/tools/perf/arch/sparc/util/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-$(CONFIG_DWARF) += dwarf-regs.o diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c deleted file mode 100644 index 1282cb2dc7bdc7..00000000000000 --- a/tools/perf/arch/sparc/util/dwarf-regs.c +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Mapping of DWARF debug register numbers into register names. - * - * Copyright (C) 2010 David S. Miller - */ - -#include -#include - -#define SPARC_MAX_REGS 96 - -const char *sparc_regs_table[SPARC_MAX_REGS] = { - "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", - "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", - "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", - "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", - "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", - "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", - "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", - "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", - "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39", - "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47", - "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55", - "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63", -}; - -/** - * get_arch_regstr() - lookup register name from it's DWARF register number - * @n: the DWARF register number - * - * get_arch_regstr() returns the name of the register in struct - * regdwarfnum_table from it's DWARF register number. If the register is not - * found in the table, this returns NULL; - */ -const char *get_arch_regstr(unsigned int n) -{ - return (n < SPARC_MAX_REGS) ? sparc_regs_table[n] : NULL; -} diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index 67b4969a673836..a6b6e0a9308a8e 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile @@ -1,9 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif HAVE_KVM_STAT_SUPPORT := 1 -PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 PERF_HAVE_JITDUMP := 1 ### diff --git a/tools/perf/arch/x86/annotate/instructions.c b/tools/perf/arch/x86/annotate/instructions.c index 5caf5a17f03d8f..ae94b1f0b9cce1 100644 --- a/tools/perf/arch/x86/annotate/instructions.c +++ b/tools/perf/arch/x86/annotate/instructions.c @@ -202,12 +202,13 @@ static int x86__annotate_init(struct arch *arch, char *cpuid) if (x86__cpuid_parse(arch, cpuid)) err = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING; } - + arch->e_machine = EM_X86_64; + arch->e_flags = 0; arch->initialized = true; return err; } -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT static void update_insn_state_x86(struct type_state *state, struct data_loc_info *dloc, Dwarf_Die *cu_die, struct disasm_line *dl) diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_32.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_32.tbl index 534c74b14fab51..4d0fb2fba7e208 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_32.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_32.tbl @@ -468,3 +468,7 @@ 460 i386 lsm_set_self_attr sys_lsm_set_self_attr 461 i386 lsm_list_modules sys_lsm_list_modules 462 i386 mseal sys_mseal +463 i386 setxattrat sys_setxattrat +464 i386 getxattrat sys_getxattrat +465 i386 listxattrat sys_listxattrat +466 i386 removexattrat sys_removexattrat diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index 7093ee21c0d1c0..5eb708bff1c791 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl @@ -386,6 +386,10 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common setxattrat sys_setxattrat +464 common getxattrat sys_getxattrat +465 common listxattrat sys_listxattrat +466 common removexattrat sys_removexattrat # # Due to a historical design error, certain syscalls are numbered differently diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c deleted file mode 100644 index 360a082fc9280f..00000000000000 --- a/tools/perf/arch/x86/tests/intel-cqm.c +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "tests/tests.h" -#include "cloexec.h" -#include "debug.h" -#include "evlist.h" -#include "evsel.h" -#include "arch-tests.h" -#include // page_size - -#include -#include -#include -#include -#include - -static pid_t spawn(void) -{ - pid_t pid; - - pid = fork(); - if (pid) - return pid; - - while(1) - sleep(5); - return 0; -} - -/* - * Create an event group that contains both a sampled hardware - * (cpu-cycles) and software (intel_cqm/llc_occupancy/) event. We then - * wait for the hardware perf counter to overflow and generate a PMI, - * which triggers an event read for both of the events in the group. - * - * Since reading Intel CQM event counters requires sending SMP IPIs, the - * CQM pmu needs to handle the above situation gracefully, and return - * the last read counter value to avoid triggering a WARN_ON_ONCE() in - * smp_call_function_many() caused by sending IPIs from NMI context. - */ -int test__intel_cqm_count_nmi_context(struct test_suite *test __maybe_unused, int subtest __maybe_unused) -{ - struct evlist *evlist = NULL; - struct evsel *evsel = NULL; - struct perf_event_attr pe; - int i, fd[2], flag, ret; - size_t mmap_len; - void *event; - pid_t pid; - int err = TEST_FAIL; - - flag = perf_event_open_cloexec_flag(); - - evlist = evlist__new(); - if (!evlist) { - pr_debug("evlist__new failed\n"); - return TEST_FAIL; - } - - ret = parse_event(evlist, "intel_cqm/llc_occupancy/"); - if (ret) { - pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n"); - err = TEST_SKIP; - goto out; - } - - evsel = evlist__first(evlist); - if (!evsel) { - pr_debug("evlist__first failed\n"); - goto out; - } - - memset(&pe, 0, sizeof(pe)); - pe.size = sizeof(pe); - - pe.type = PERF_TYPE_HARDWARE; - pe.config = PERF_COUNT_HW_CPU_CYCLES; - pe.read_format = PERF_FORMAT_GROUP; - - pe.sample_period = 128; - pe.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_READ; - - pid = spawn(); - - fd[0] = sys_perf_event_open(&pe, pid, -1, -1, flag); - if (fd[0] < 0) { - pr_debug("failed to open event\n"); - goto out; - } - - memset(&pe, 0, sizeof(pe)); - pe.size = sizeof(pe); - - pe.type = evsel->attr.type; - pe.config = evsel->attr.config; - - fd[1] = sys_perf_event_open(&pe, pid, -1, fd[0], flag); - if (fd[1] < 0) { - pr_debug("failed to open event\n"); - goto out; - } - - /* - * Pick a power-of-two number of pages + 1 for the meta-data - * page (struct perf_event_mmap_page). See tools/perf/design.txt. - */ - mmap_len = page_size * 65; - - event = mmap(NULL, mmap_len, PROT_READ, MAP_SHARED, fd[0], 0); - if (event == (void *)(-1)) { - pr_debug("failed to mmap %d\n", errno); - goto out; - } - - sleep(1); - - err = TEST_OK; - - munmap(event, mmap_len); - - for (i = 0; i < 2; i++) - close(fd[i]); - - kill(pid, SIGKILL); - wait(NULL); -out: - evlist__delete(evlist); - return err; -} diff --git a/tools/perf/arch/x86/tests/intel-pt-test.c b/tools/perf/arch/x86/tests/intel-pt-test.c index 09d61fa736e364..b217ed67cd4e52 100644 --- a/tools/perf/arch/x86/tests/intel-pt-test.c +++ b/tools/perf/arch/x86/tests/intel-pt-test.c @@ -375,7 +375,7 @@ static int get_pt_caps(int cpu, struct pt_caps *caps) return 0; } -static bool is_hydrid(void) +static bool is_hybrid(void) { unsigned int eax, ebx, ecx, edx = 0; bool result; @@ -441,7 +441,7 @@ int test__intel_pt_hybrid_compat(struct test_suite *test, int subtest) int ret = TEST_OK; int cpu; - if (!is_hydrid()) { + if (!is_hybrid()) { test->test_cases[subtest].skip_reason = "not hybrid"; return TEST_SKIP; } diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index 2607ed5c429665..848327378694d9 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -10,10 +10,6 @@ perf-util-y += evlist.o perf-util-y += mem-events.o perf-util-y += evsel.o perf-util-y += iostat.o -perf-util-y += env.o - -perf-util-$(CONFIG_DWARF) += dwarf-regs.o -perf-util-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/x86/util/auxtrace.c b/tools/perf/arch/x86/util/auxtrace.c index 354780ff1605db..ecbf61a7eb3a3e 100644 --- a/tools/perf/arch/x86/util/auxtrace.c +++ b/tools/perf/arch/x86/util/auxtrace.c @@ -55,11 +55,12 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist, int *err) { char buffer[64]; + struct perf_cpu cpu = perf_cpu_map__min(evlist->core.all_cpus); int ret; *err = 0; - ret = get_cpuid(buffer, sizeof(buffer)); + ret = get_cpuid(buffer, sizeof(buffer), cpu); if (ret) { *err = ret; return NULL; diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c deleted file mode 100644 index 399c4a0a29d8c1..00000000000000 --- a/tools/perf/arch/x86/util/dwarf-regs.c +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. - * Extracted from probe-finder.c - * - * Written by Masami Hiramatsu - */ - -#include -#include /* for EINVAL */ -#include /* for strcmp */ -#include /* for struct pt_regs */ -#include /* for offsetof */ -#include - -/* - * See arch/x86/kernel/ptrace.c. - * Different from it: - * - * - Since struct pt_regs is defined differently for user and kernel, - * but we want to use 'ax, bx' instead of 'rax, rbx' (which is struct - * field name of user's pt_regs), we make REG_OFFSET_NAME to accept - * both string name and reg field name. - * - * - Since accessing x86_32's pt_regs from x86_64 building is difficult - * and vise versa, we simply fill offset with -1, so - * get_arch_regstr() still works but regs_query_register_offset() - * returns error. - * The only inconvenience caused by it now is that we are not allowed - * to generate BPF prologue for a x86_64 kernel if perf is built for - * x86_32. This is really a rare usecase. - * - * - Order is different from kernel's ptrace.c for get_arch_regstr(). Use - * the order defined by dwarf. - */ - -struct pt_regs_offset { - const char *name; - int offset; -}; - -#define REG_OFFSET_END {.name = NULL, .offset = 0} - -#ifdef __x86_64__ -# define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} -# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = -1} -#else -# define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = -1} -# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} -#endif - -/* TODO: switching by dwarf address size */ -#ifndef __x86_64__ -static const struct pt_regs_offset x86_32_regoffset_table[] = { - REG_OFFSET_NAME_32("%ax", eax), - REG_OFFSET_NAME_32("%cx", ecx), - REG_OFFSET_NAME_32("%dx", edx), - REG_OFFSET_NAME_32("%bx", ebx), - REG_OFFSET_NAME_32("$stack", esp), /* Stack address instead of %sp */ - REG_OFFSET_NAME_32("%bp", ebp), - REG_OFFSET_NAME_32("%si", esi), - REG_OFFSET_NAME_32("%di", edi), - REG_OFFSET_END, -}; - -#define regoffset_table x86_32_regoffset_table -#else -static const struct pt_regs_offset x86_64_regoffset_table[] = { - REG_OFFSET_NAME_64("%ax", rax), - REG_OFFSET_NAME_64("%dx", rdx), - REG_OFFSET_NAME_64("%cx", rcx), - REG_OFFSET_NAME_64("%bx", rbx), - REG_OFFSET_NAME_64("%si", rsi), - REG_OFFSET_NAME_64("%di", rdi), - REG_OFFSET_NAME_64("%bp", rbp), - REG_OFFSET_NAME_64("%sp", rsp), - REG_OFFSET_NAME_64("%r8", r8), - REG_OFFSET_NAME_64("%r9", r9), - REG_OFFSET_NAME_64("%r10", r10), - REG_OFFSET_NAME_64("%r11", r11), - REG_OFFSET_NAME_64("%r12", r12), - REG_OFFSET_NAME_64("%r13", r13), - REG_OFFSET_NAME_64("%r14", r14), - REG_OFFSET_NAME_64("%r15", r15), - REG_OFFSET_END, -}; - -#define regoffset_table x86_64_regoffset_table -#endif - -/* Minus 1 for the ending REG_OFFSET_END */ -#define ARCH_MAX_REGS ((sizeof(regoffset_table) / sizeof(regoffset_table[0])) - 1) - -/* Return architecture dependent register string (for kprobe-tracer) */ -const char *get_arch_regstr(unsigned int n) -{ - return (n < ARCH_MAX_REGS) ? regoffset_table[n].name : NULL; -} - -/* Reuse code from arch/x86/kernel/ptrace.c */ -/** - * regs_query_register_offset() - query register offset from its name - * @name: the name of a register - * - * regs_query_register_offset() returns the offset of a register in struct - * pt_regs from its name. If the name is invalid, this returns -EINVAL; - */ -int regs_query_register_offset(const char *name) -{ - const struct pt_regs_offset *roff; - for (roff = regoffset_table; roff->name != NULL; roff++) - if (!strcmp(roff->name, name)) - return roff->offset; - return -EINVAL; -} - -struct dwarf_regs_idx { - const char *name; - int idx; -}; - -static const struct dwarf_regs_idx x86_regidx_table[] = { - { "rax", 0 }, { "eax", 0 }, { "ax", 0 }, { "al", 0 }, - { "rdx", 1 }, { "edx", 1 }, { "dx", 1 }, { "dl", 1 }, - { "rcx", 2 }, { "ecx", 2 }, { "cx", 2 }, { "cl", 2 }, - { "rbx", 3 }, { "edx", 3 }, { "bx", 3 }, { "bl", 3 }, - { "rsi", 4 }, { "esi", 4 }, { "si", 4 }, { "sil", 4 }, - { "rdi", 5 }, { "edi", 5 }, { "di", 5 }, { "dil", 5 }, - { "rbp", 6 }, { "ebp", 6 }, { "bp", 6 }, { "bpl", 6 }, - { "rsp", 7 }, { "esp", 7 }, { "sp", 7 }, { "spl", 7 }, - { "r8", 8 }, { "r8d", 8 }, { "r8w", 8 }, { "r8b", 8 }, - { "r9", 9 }, { "r9d", 9 }, { "r9w", 9 }, { "r9b", 9 }, - { "r10", 10 }, { "r10d", 10 }, { "r10w", 10 }, { "r10b", 10 }, - { "r11", 11 }, { "r11d", 11 }, { "r11w", 11 }, { "r11b", 11 }, - { "r12", 12 }, { "r12d", 12 }, { "r12w", 12 }, { "r12b", 12 }, - { "r13", 13 }, { "r13d", 13 }, { "r13w", 13 }, { "r13b", 13 }, - { "r14", 14 }, { "r14d", 14 }, { "r14w", 14 }, { "r14b", 14 }, - { "r15", 15 }, { "r15d", 15 }, { "r15w", 15 }, { "r15b", 15 }, - { "rip", DWARF_REG_PC }, -}; - -int get_arch_regnum(const char *name) -{ - unsigned int i; - - if (*name != '%') - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(x86_regidx_table); i++) - if (!strcmp(x86_regidx_table[i].name, name + 1)) - return x86_regidx_table[i].idx; - return -ENOENT; -} diff --git a/tools/perf/arch/x86/util/env.c b/tools/perf/arch/x86/util/env.c deleted file mode 100644 index 3e537ffb1353aa..00000000000000 --- a/tools/perf/arch/x86/util/env.c +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "linux/string.h" -#include "util/env.h" -#include "env.h" - -bool x86__is_amd_cpu(void) -{ - struct perf_env env = { .total_mem = 0, }; - static int is_amd; /* 0: Uninitialized, 1: Yes, -1: No */ - - if (is_amd) - goto ret; - - perf_env__cpuid(&env); - is_amd = env.cpuid && strstarts(env.cpuid, "AuthenticAMD") ? 1 : -1; - perf_env__exit(&env); -ret: - return is_amd >= 1 ? true : false; -} diff --git a/tools/perf/arch/x86/util/env.h b/tools/perf/arch/x86/util/env.h deleted file mode 100644 index d78f080b6b3f88..00000000000000 --- a/tools/perf/arch/x86/util/env.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _X86_ENV_H -#define _X86_ENV_H - -bool x86__is_amd_cpu(void); - -#endif /* _X86_ENV_H */ diff --git a/tools/perf/arch/x86/util/evlist.c b/tools/perf/arch/x86/util/evlist.c index cebdd483149e84..447a734e591c8f 100644 --- a/tools/perf/arch/x86/util/evlist.c +++ b/tools/perf/arch/x86/util/evlist.c @@ -1,91 +1,86 @@ // SPDX-License-Identifier: GPL-2.0 -#include -#include "util/pmu.h" -#include "util/pmus.h" -#include "util/evlist.h" -#include "util/parse-events.h" -#include "util/event.h" +#include +#include "../../../util/evlist.h" +#include "../../../util/evsel.h" #include "topdown.h" #include "evsel.h" -static int ___evlist__add_default_attrs(struct evlist *evlist, - struct perf_event_attr *attrs, - size_t nr_attrs) -{ - LIST_HEAD(head); - size_t i = 0; - - for (i = 0; i < nr_attrs; i++) - event_attr_init(attrs + i); - - if (perf_pmus__num_core_pmus() == 1) - return evlist__add_attrs(evlist, attrs, nr_attrs); - - for (i = 0; i < nr_attrs; i++) { - struct perf_pmu *pmu = NULL; - - if (attrs[i].type == PERF_TYPE_SOFTWARE) { - struct evsel *evsel = evsel__new(attrs + i); - - if (evsel == NULL) - goto out_delete_partial_list; - list_add_tail(&evsel->core.node, &head); - continue; - } - - while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { - struct perf_cpu_map *cpus; - struct evsel *evsel; - - evsel = evsel__new(attrs + i); - if (evsel == NULL) - goto out_delete_partial_list; - evsel->core.attr.config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT; - cpus = perf_cpu_map__get(pmu->cpus); - evsel->core.cpus = cpus; - evsel->core.own_cpus = perf_cpu_map__get(cpus); - evsel->pmu_name = strdup(pmu->name); - list_add_tail(&evsel->core.node, &head); - } - } - - evlist__splice_list_tail(evlist, &head); - - return 0; - -out_delete_partial_list: - { - struct evsel *evsel, *n; - - __evlist__for_each_entry_safe(&head, n, evsel) - evsel__delete(evsel); - } - return -1; -} - -int arch_evlist__add_default_attrs(struct evlist *evlist, - struct perf_event_attr *attrs, - size_t nr_attrs) -{ - if (!nr_attrs) - return 0; - - return ___evlist__add_default_attrs(evlist, attrs, nr_attrs); -} - int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs) { + /* + * Currently the following topdown events sequence are supported to + * move and regroup correctly. + * + * a. all events in a group + * perf stat -e "{instructions,topdown-retiring,slots}" -C0 sleep 1 + * WARNING: events were regrouped to match PMUs + * Performance counter stats for 'CPU(s) 0': + * 15,066,240 slots + * 1,899,760 instructions + * 2,126,998 topdown-retiring + * b. all events not in a group + * perf stat -e "instructions,topdown-retiring,slots" -C0 sleep 1 + * WARNING: events were regrouped to match PMUs + * Performance counter stats for 'CPU(s) 0': + * 2,045,561 instructions + * 17,108,370 slots + * 2,281,116 topdown-retiring + * c. slots event in a group but topdown metrics events outside the group + * perf stat -e "{instructions,slots},topdown-retiring" -C0 sleep 1 + * WARNING: events were regrouped to match PMUs + * Performance counter stats for 'CPU(s) 0': + * 20,323,878 slots + * 2,634,884 instructions + * 3,028,656 topdown-retiring + * d. slots event and topdown metrics events in two groups + * perf stat -e "{instructions,slots},{topdown-retiring}" -C0 sleep 1 + * WARNING: events were regrouped to match PMUs + * Performance counter stats for 'CPU(s) 0': + * 26,319,024 slots + * 2,427,791 instructions + * 2,683,508 topdown-retiring + * + * If slots event and topdown metrics events are not in same group, the + * topdown metrics events must be first event after the slots event group, + * otherwise topdown metrics events can't be regrouped correctly, e.g. + * + * a. perf stat -e "{instructions,slots},cycles,topdown-retiring" -C0 sleep 1 + * WARNING: events were regrouped to match PMUs + * Performance counter stats for 'CPU(s) 0': + * 17,923,134 slots + * 2,154,855 instructions + * 3,015,058 cycles + * topdown-retiring + * + * If slots event and topdown metrics events are in two groups, the group which + * has topdown metrics events must contain only the topdown metrics event, + * otherwise topdown metrics event can't be regrouped correctly as well, e.g. + * + * a. perf stat -e "{instructions,slots},{topdown-retiring,cycles}" -C0 sleep 1 + * WARNING: events were regrouped to match PMUs + * Error: + * The sys_perf_event_open() syscall returned with 22 (Invalid argument) for + * event (topdown-retiring) + */ if (topdown_sys_has_perf_metrics() && (arch_evsel__must_be_in_group(lhs) || arch_evsel__must_be_in_group(rhs))) { /* Ensure the topdown slots comes first. */ - if (strcasestr(lhs->name, "slots") && !strcasestr(lhs->name, "uops_retired.slots")) + if (arch_is_topdown_slots(lhs)) return -1; - if (strcasestr(rhs->name, "slots") && !strcasestr(rhs->name, "uops_retired.slots")) + if (arch_is_topdown_slots(rhs)) return 1; - /* Followed by topdown events. */ - if (strcasestr(lhs->name, "topdown") && !strcasestr(rhs->name, "topdown")) + + /* + * Move topdown metrics events forward only when topdown metrics + * events are not in same group with previous slots event. If + * topdown metrics events are already in same group with slots + * event, do nothing. + */ + if (arch_is_topdown_metrics(lhs) && !arch_is_topdown_metrics(rhs) && + lhs->core.leader != rhs->core.leader) return -1; - if (!strcasestr(lhs->name, "topdown") && strcasestr(rhs->name, "topdown")) + if (!arch_is_topdown_metrics(lhs) && arch_is_topdown_metrics(rhs) && + lhs->core.leader != rhs->core.leader) return 1; } diff --git a/tools/perf/arch/x86/util/evsel.c b/tools/perf/arch/x86/util/evsel.c index 090d0f371891f5..3dd29ba2c23b06 100644 --- a/tools/perf/arch/x86/util/evsel.c +++ b/tools/perf/arch/x86/util/evsel.c @@ -6,6 +6,7 @@ #include "util/pmu.h" #include "util/pmus.h" #include "linux/string.h" +#include "topdown.h" #include "evsel.h" #include "util/debug.h" #include "env.h" @@ -21,7 +22,8 @@ void arch_evsel__set_sample_weight(struct evsel *evsel) /* Check whether the evsel's PMU supports the perf metrics */ bool evsel__sys_has_perf_metrics(const struct evsel *evsel) { - const char *pmu_name = evsel->pmu_name ? evsel->pmu_name : "cpu"; + struct perf_pmu *pmu; + u32 type = evsel->core.attr.type; /* * The PERF_TYPE_RAW type is the core PMU type, e.g., "cpu" PMU @@ -31,11 +33,31 @@ bool evsel__sys_has_perf_metrics(const struct evsel *evsel) * Checking both the PERF_TYPE_RAW type and the slots event * should be good enough to detect the perf metrics feature. */ - if ((evsel->core.attr.type == PERF_TYPE_RAW) && - perf_pmus__have_event(pmu_name, "slots")) - return true; +again: + switch (type) { + case PERF_TYPE_HARDWARE: + case PERF_TYPE_HW_CACHE: + type = evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT; + if (type) + goto again; + break; + case PERF_TYPE_RAW: + break; + default: + return false; + } + + pmu = evsel->pmu; + if (pmu && perf_pmu__is_fake(pmu)) + pmu = NULL; - return false; + if (!pmu) { + while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { + if (pmu->type == PERF_TYPE_RAW) + break; + } + } + return pmu && perf_pmu__have_event(pmu, "slots"); } bool arch_evsel__must_be_in_group(const struct evsel *evsel) @@ -44,7 +66,7 @@ bool arch_evsel__must_be_in_group(const struct evsel *evsel) strcasestr(evsel->name, "uops_retired.slots")) return false; - return strcasestr(evsel->name, "topdown") || strcasestr(evsel->name, "slots"); + return arch_is_topdown_metrics(evsel) || arch_is_topdown_slots(evsel); } int arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size) @@ -63,7 +85,7 @@ int arch_evsel__hw_name(struct evsel *evsel, char *bf, size_t size) return scnprintf(bf, size, "%s", event_name); return scnprintf(bf, size, "%s/%s/", - evsel->pmu_name ? evsel->pmu_name : "cpu", + evsel->pmu ? evsel->pmu->name : "cpu", event_name); } @@ -108,7 +130,7 @@ int arch_evsel__open_strerror(struct evsel *evsel, char *msg, size_t size) return 0; if (!evsel->core.attr.precise_ip && - !(evsel->pmu_name && !strncmp(evsel->pmu_name, "ibs", 3))) + !(evsel->pmu && !strncmp(evsel->pmu->name, "ibs", 3))) return 0; /* More verbose IBS errors. */ diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c index a51444a77a5f2b..412977f8aa8374 100644 --- a/tools/perf/arch/x86/util/header.c +++ b/tools/perf/arch/x86/util/header.c @@ -58,13 +58,12 @@ __get_cpuid(char *buffer, size_t sz, const char *fmt) } int -get_cpuid(char *buffer, size_t sz) +get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu __maybe_unused) { return __get_cpuid(buffer, sz, "%s,%u,%u,%u$"); } -char * -get_cpuid_str(struct perf_pmu *pmu __maybe_unused) +char *get_cpuid_str(struct perf_cpu cpu __maybe_unused) { char *buf = malloc(128); diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index ea510a7486b14f..8f235d8b67b628 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -75,7 +75,8 @@ static int intel_pt_parse_terms_with_default(const struct perf_pmu *pmu, goto out_free; attr.config = *config; - err = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/true, /*err=*/NULL); + err = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/true, /*apply_hardcoded=*/false, + /*err=*/NULL); if (err) goto out_free; diff --git a/tools/perf/arch/x86/util/iostat.c b/tools/perf/arch/x86/util/iostat.c index df7b5dfcc26a51..366b44d0bb7e59 100644 --- a/tools/perf/arch/x86/util/iostat.c +++ b/tools/perf/arch/x86/util/iostat.c @@ -444,7 +444,7 @@ void iostat_print_metric(struct perf_stat_config *config, struct evsel *evsel, iostat_value = (count->val - prev_count_val) / ((double) count->run / count->ena); } - out->print_metric(config, out->ctx, NULL, "%8.0f", iostat_metric, + out->print_metric(config, out->ctx, METRIC_THRESHOLD_UNKNOWN, "%8.0f", iostat_metric, iostat_value / (256 * 1024)); } diff --git a/tools/perf/arch/x86/util/pmu.c b/tools/perf/arch/x86/util/pmu.c index c3d89d6ba1bf03..e0060dac2a9f92 100644 --- a/tools/perf/arch/x86/util/pmu.c +++ b/tools/perf/arch/x86/util/pmu.c @@ -16,7 +16,7 @@ #include "../../../util/fncache.h" #include "../../../util/pmus.h" #include "mem-events.h" -#include "env.h" +#include "util/env.h" void perf_pmu__arch_init(struct perf_pmu *pmu __maybe_unused) { diff --git a/tools/perf/arch/x86/util/topdown.c b/tools/perf/arch/x86/util/topdown.c index 3f9a267d4501b6..f63747d0abdf9e 100644 --- a/tools/perf/arch/x86/util/topdown.c +++ b/tools/perf/arch/x86/util/topdown.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "api/fs/fs.h" #include "util/evsel.h" +#include "util/evlist.h" #include "util/pmu.h" #include "util/pmus.h" #include "util/topdown.h" @@ -32,6 +33,31 @@ bool topdown_sys_has_perf_metrics(void) } #define TOPDOWN_SLOTS 0x0400 +bool arch_is_topdown_slots(const struct evsel *evsel) +{ + if (evsel->core.attr.config == TOPDOWN_SLOTS) + return true; + + return false; +} + +bool arch_is_topdown_metrics(const struct evsel *evsel) +{ + int config = evsel->core.attr.config; + const char *name_from_config; + struct perf_pmu *pmu; + + /* All topdown events have an event code of 0. */ + if ((config & 0xFF) != 0) + return false; + + pmu = evsel__find_pmu(evsel); + if (!pmu || !pmu->is_core) + return false; + + name_from_config = perf_pmu__name_from_config(pmu, config); + return name_from_config && strcasestr(name_from_config, "topdown"); +} /* * Check whether a topdown group supports sample-read. @@ -41,11 +67,24 @@ bool topdown_sys_has_perf_metrics(void) */ bool arch_topdown_sample_read(struct evsel *leader) { + struct evsel *evsel; + if (!evsel__sys_has_perf_metrics(leader)) return false; - if (leader->core.attr.config == TOPDOWN_SLOTS) - return true; + if (!arch_is_topdown_slots(leader)) + return false; + + /* + * If slots event as leader event but no topdown metric events + * in group, slots event should still sample as leader. + */ + evlist__for_each_entry(leader->evlist, evsel) { + if (evsel->core.leader != leader->core.leader) + return false; + if (evsel != leader && arch_is_topdown_metrics(evsel)) + return true; + } return false; } diff --git a/tools/perf/arch/x86/util/topdown.h b/tools/perf/arch/x86/util/topdown.h index 46bf9273e572fa..1bae9b1822d71b 100644 --- a/tools/perf/arch/x86/util/topdown.h +++ b/tools/perf/arch/x86/util/topdown.h @@ -3,5 +3,7 @@ #define _TOPDOWN_H 1 bool topdown_sys_has_perf_metrics(void); +bool arch_is_topdown_slots(const struct evsel *evsel); +bool arch_is_topdown_metrics(const struct evsel *evsel); #endif diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index e2d6cfe21057bd..3a439e4b12d28e 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c @@ -24,9 +24,9 @@ u64 rdtsc(void) * ... * will return 3000000000. */ -static double cpuinfo_tsc_freq(void) +static u64 cpuinfo_tsc_freq(void) { - double result = 0; + u64 result = 0; FILE *cpuinfo; char *line = NULL; size_t len = 0; @@ -34,20 +34,22 @@ static double cpuinfo_tsc_freq(void) cpuinfo = fopen("/proc/cpuinfo", "r"); if (!cpuinfo) { pr_err("Failed to read /proc/cpuinfo for TSC frequency\n"); - return NAN; + return 0; } while (getline(&line, &len, cpuinfo) > 0) { if (!strncmp(line, "model name", 10)) { char *pos = strstr(line + 11, " @ "); + double float_result; - if (pos && sscanf(pos, " @ %lfGHz", &result) == 1) { - result *= 1000000000; + if (pos && sscanf(pos, " @ %lfGHz", &float_result) == 1) { + float_result *= 1000000000; + result = (u64)float_result; goto out; } } } out: - if (fpclassify(result) == FP_ZERO) + if (result == 0) pr_err("Failed to find TSC frequency in /proc/cpuinfo\n"); free(line); @@ -55,7 +57,7 @@ static double cpuinfo_tsc_freq(void) return result; } -double arch_get_tsc_freq(void) +u64 arch_get_tsc_freq(void) { unsigned int a, b, c, d, lvl; static bool cached; @@ -86,6 +88,6 @@ double arch_get_tsc_freq(void) return tsc; } - tsc = (double)c * (double)b / (double)a; + tsc = (u64)c * (u64)b / (u64)a; return tsc; } diff --git a/tools/perf/arch/xtensa/Build b/tools/perf/arch/xtensa/Build deleted file mode 100644 index e63eabc2c8f416..00000000000000 --- a/tools/perf/arch/xtensa/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-y += util/ diff --git a/tools/perf/arch/xtensa/Makefile b/tools/perf/arch/xtensa/Makefile deleted file mode 100644 index 88c08eed9c7be5..00000000000000 --- a/tools/perf/arch/xtensa/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -ifndef NO_DWARF -PERF_HAVE_DWARF_REGS := 1 -endif diff --git a/tools/perf/arch/xtensa/util/Build b/tools/perf/arch/xtensa/util/Build deleted file mode 100644 index e813e618954b00..00000000000000 --- a/tools/perf/arch/xtensa/util/Build +++ /dev/null @@ -1 +0,0 @@ -perf-$(CONFIG_DWARF) += dwarf-regs.o diff --git a/tools/perf/arch/xtensa/util/dwarf-regs.c b/tools/perf/arch/xtensa/util/dwarf-regs.c deleted file mode 100644 index 12f5457300f5c3..00000000000000 --- a/tools/perf/arch/xtensa/util/dwarf-regs.c +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Mapping of DWARF debug register numbers into register names. - * - * Copyright (c) 2015 Cadence Design Systems Inc. - */ - -#include -#include - -#define XTENSA_MAX_REGS 16 - -const char *xtensa_regs_table[XTENSA_MAX_REGS] = { - "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", - "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15", -}; - -const char *get_arch_regstr(unsigned int n) -{ - return n < XTENSA_MAX_REGS ? xtensa_regs_table[n] : NULL; -} diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 1fbd7c947abc2b..19be2aaf4dc0c0 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include "../util/header.h" #include "../util/mutex.h" +#include #include #include @@ -533,6 +535,57 @@ static int parse_cpu_list(const char *arg) return 0; } +/* + * Check whether a CPU is online + * + * Returns: + * 1 -> if CPU is online + * 0 -> if CPU is offline + * -1 -> error case + */ +static int is_cpu_online(unsigned int cpu) +{ + char *str; + size_t strlen; + char buf[256]; + int status = -1; + struct stat statbuf; + + snprintf(buf, sizeof(buf), + "/sys/devices/system/cpu/cpu%d", cpu); + if (stat(buf, &statbuf) != 0) + return 0; + + /* + * Check if /sys/devices/system/cpu/cpux/online file + * exists. Some cases cpu0 won't have online file since + * it is not expected to be turned off generally. + * In kernels without CONFIG_HOTPLUG_CPU, this + * file won't exist + */ + snprintf(buf, sizeof(buf), + "/sys/devices/system/cpu/cpu%d/online", cpu); + if (stat(buf, &statbuf) != 0) + return 1; + + /* + * Read online file using sysfs__read_str. + * If read or open fails, return -1. + * If read succeeds, return value from file + * which gets stored in "str" + */ + snprintf(buf, sizeof(buf), + "devices/system/cpu/cpu%d/online", cpu); + + if (sysfs__read_str(buf, &str, &strlen) < 0) + return status; + + status = atoi(str); + + free(str); + return status; +} + static int parse_setup_cpu_list(void) { struct thread_data *td; diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c index 3af6d3c55aba19..e2562677df9640 100644 --- a/tools/perf/bench/sched-pipe.c +++ b/tools/perf/bench/sched-pipe.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,8 @@ struct thread_data { int nr; int pipe_read; int pipe_write; + struct epoll_event epoll_ev; + int epoll_fd; bool cgroup_failed; pthread_t pthread; }; @@ -44,6 +47,7 @@ static int loops = LOOPS_DEFAULT; /* Use processes by default: */ static bool threaded; +static bool nonblocking; static char *cgrp_names[2]; static struct cgroup *cgrps[2]; @@ -81,6 +85,7 @@ static int parse_two_cgroups(const struct option *opt __maybe_unused, } static const struct option options[] = { + OPT_BOOLEAN('n', "nonblocking", &nonblocking, "Use non-blocking operations"), OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"), OPT_CALLBACK('G', "cgroups", NULL, "SEND,RECV", @@ -165,11 +170,25 @@ static void exit_cgroup(int nr) free(cgrp_names[nr]); } +static inline int read_pipe(struct thread_data *td) +{ + int ret, m; +retry: + if (nonblocking) { + ret = epoll_wait(td->epoll_fd, &td->epoll_ev, 1, -1); + if (ret < 0) + return ret; + } + ret = read(td->pipe_read, &m, sizeof(int)); + if (nonblocking && ret < 0 && errno == EWOULDBLOCK) + goto retry; + return ret; +} + static void *worker_thread(void *__tdata) { struct thread_data *td = __tdata; - int m = 0, i; - int ret; + int i, ret, m = 0; ret = enter_cgroup(td->nr); if (ret < 0) { @@ -177,16 +196,23 @@ static void *worker_thread(void *__tdata) return NULL; } + if (nonblocking) { + td->epoll_ev.events = EPOLLIN; + td->epoll_fd = epoll_create(1); + BUG_ON(td->epoll_fd < 0); + BUG_ON(epoll_ctl(td->epoll_fd, EPOLL_CTL_ADD, td->pipe_read, &td->epoll_ev) < 0); + } + for (i = 0; i < loops; i++) { if (!td->nr) { - ret = read(td->pipe_read, &m, sizeof(int)); + ret = read_pipe(td); BUG_ON(ret != sizeof(int)); ret = write(td->pipe_write, &m, sizeof(int)); BUG_ON(ret != sizeof(int)); } else { ret = write(td->pipe_write, &m, sizeof(int)); BUG_ON(ret != sizeof(int)); - ret = read(td->pipe_read, &m, sizeof(int)); + ret = read_pipe(td); BUG_ON(ret != sizeof(int)); } } @@ -209,13 +235,16 @@ int bench_sched_pipe(int argc, const char **argv) * discarding returned value of read(), write() * causes error in building environment for perf */ - int __maybe_unused ret, wait_stat; + int __maybe_unused ret, wait_stat, flags = 0; pid_t pid, retpid __maybe_unused; argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0); - BUG_ON(pipe(pipe_1)); - BUG_ON(pipe(pipe_2)); + if (nonblocking) + flags |= O_NONBLOCK; + + BUG_ON(pipe2(pipe_1, flags)); + BUG_ON(pipe2(pipe_2, flags)); gettimeofday(&start, NULL); diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3dc6197ef3fa6d..bb87e6e7687dc1 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -840,7 +840,7 @@ int cmd_annotate(int argc, const char **argv) } #endif -#ifndef HAVE_DWARF_GETLOCATIONS_SUPPORT +#ifndef HAVE_LIBDW_SUPPORT if (annotate.data_type) { pr_err("Error: Data type profiling is disabled due to missing DWARF support\n"); return -ENOTSUP; diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c index 0b76b6e42b781b..2346536a5ee14f 100644 --- a/tools/perf/builtin-check.c +++ b/tools/perf/builtin-check.c @@ -27,15 +27,15 @@ struct feature_status supported_features[] = { FEATURE_STATUS("bpf", HAVE_LIBBPF_SUPPORT), FEATURE_STATUS("bpf_skeletons", HAVE_BPF_SKEL), FEATURE_STATUS("debuginfod", HAVE_DEBUGINFOD_SUPPORT), - FEATURE_STATUS("dwarf", HAVE_DWARF_SUPPORT), - FEATURE_STATUS("dwarf_getlocations", HAVE_DWARF_GETLOCATIONS_SUPPORT), + FEATURE_STATUS("dwarf", HAVE_LIBDW_SUPPORT), + FEATURE_STATUS("dwarf_getlocations", HAVE_LIBDW_SUPPORT), FEATURE_STATUS("dwarf-unwind", HAVE_DWARF_UNWIND_SUPPORT), FEATURE_STATUS("auxtrace", HAVE_AUXTRACE_SUPPORT), FEATURE_STATUS("libaudit", HAVE_LIBAUDIT_SUPPORT), FEATURE_STATUS("libbfd", HAVE_LIBBFD_SUPPORT), FEATURE_STATUS("libcapstone", HAVE_LIBCAPSTONE_SUPPORT), FEATURE_STATUS("libcrypto", HAVE_LIBCRYPTO_SUPPORT), - FEATURE_STATUS("libdw-dwarf-unwind", HAVE_DWARF_SUPPORT), + FEATURE_STATUS("libdw-dwarf-unwind", HAVE_LIBDW_SUPPORT), FEATURE_STATUS("libelf", HAVE_LIBELF_SUPPORT), FEATURE_STATUS("libnuma", HAVE_LIBNUMA_SUPPORT), FEATURE_STATUS("libopencsd", HAVE_CSTRACE_SUPPORT), diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 23326dd2033395..82fb7773e03e62 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -469,13 +469,13 @@ static int diff__process_sample_event(const struct perf_tool *tool, static struct perf_diff pdiff; -static struct evsel *evsel_match(struct evsel *evsel, - struct evlist *evlist) +static struct evsel *evsel_match(struct evsel *evsel, struct evlist *evlist) { struct evsel *e; evlist__for_each_entry(evlist, e) { - if (evsel__match2(evsel, e)) + if ((evsel->core.attr.type == e->core.attr.type) && + (evsel->core.attr.config == e->core.attr.config)) return e; } diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index abcdc49b7a987f..a56cf8b0a7d405 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -815,7 +815,7 @@ static void display_histogram(int buckets[], bool use_nsec) bar_len = buckets[0] * bar_total / total; printf(" %4d - %-4d %s | %10d | %.*s%*s |\n", - 0, 1, "us", buckets[0], bar_len, bar, bar_total - bar_len, ""); + 0, 1, use_nsec ? "ns" : "us", buckets[0], bar_len, bar, bar_total - bar_len, ""); for (i = 1; i < NUM_BUCKET - 1; i++) { int start = (1 << (i - 1)); @@ -1151,8 +1151,9 @@ static int cmp_profile_data(const void *a, const void *b) if (v1 > v2) return -1; - else + if (v1 < v2) return 1; + return 0; } static void print_profile_result(struct perf_ftrace *ftrace) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index a756147e2eec7a..4d8d94146f8dd7 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -36,7 +36,7 @@ #include #include -#include +#include static int kmem_slab; static int kmem_page; diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 55ea17c5ff02ac..274568d712d12f 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1226,7 +1226,9 @@ static int cpu_isa_config(struct perf_kvm_stat *kvm) int err; if (kvm->live) { - err = get_cpuid(buf, sizeof(buf)); + struct perf_cpu cpu = {-1}; + + err = get_cpuid(buf, sizeof(buf), cpu); if (err != 0) { pr_err("Failed to look up CPU type: %s\n", str_error_r(err, buf, sizeof(buf))); @@ -2147,6 +2149,7 @@ int cmd_kvm(int argc, const char **argv) "buildid-list", "stat", NULL }; const char *kvm_usage[] = { NULL, NULL }; + exclude_GH_default = true; perf_host = 0; perf_guest = 1; diff --git a/tools/perf/builtin-kwork.c b/tools/perf/builtin-kwork.c index c1daf82c9b923b..8234410cba4c88 100644 --- a/tools/perf/builtin-kwork.c +++ b/tools/perf/builtin-kwork.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 65b8cba324be4b..9e7fdfcdd7ffb7 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -19,6 +19,7 @@ #include "util/string2.h" #include "util/strlist.h" #include "util/strbuf.h" +#include "util/tool_pmu.h" #include #include #include @@ -112,7 +113,7 @@ static void wordwrap(FILE *fp, const char *s, int start, int max, int corr) } } -static void default_print_event(void *ps, const char *pmu_name, const char *topic, +static void default_print_event(void *ps, const char *topic, const char *pmu_name, const char *event_name, const char *event_alias, const char *scale_unit __maybe_unused, bool deprecated, const char *event_type_desc, @@ -353,7 +354,7 @@ static void fix_escape_fprintf(FILE *fp, struct strbuf *buf, const char *fmt, .. fputs(buf->buf, fp); } -static void json_print_event(void *ps, const char *pmu_name, const char *topic, +static void json_print_event(void *ps, const char *topic, const char *pmu_name, const char *event_name, const char *event_alias, const char *scale_unit, bool deprecated, const char *event_type_desc, @@ -614,9 +615,18 @@ int cmd_list(int argc, const char **argv) event_symbols_hw, PERF_COUNT_HW_MAX); else if (strcmp(argv[i], "sw") == 0 || strcmp(argv[i], "software") == 0) { + char *old_pmu_glob = default_ps.pmu_glob; + print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, event_symbols_sw, PERF_COUNT_SW_MAX); - print_tool_events(&print_cb, ps); + default_ps.pmu_glob = strdup("tool"); + if (!default_ps.pmu_glob) { + ret = -1; + goto out; + } + perf_pmus__print_pmu_events(&print_cb, ps); + zfree(&default_ps.pmu_glob); + default_ps.pmu_glob = old_pmu_glob; } else if (strcmp(argv[i], "cache") == 0 || strcmp(argv[i], "hwcache") == 0) print_hwcache_events(&print_cb, ps); @@ -664,7 +674,6 @@ int cmd_list(int argc, const char **argv) event_symbols_hw, PERF_COUNT_HW_MAX); print_symbol_events(&print_cb, ps, PERF_TYPE_SOFTWARE, event_symbols_sw, PERF_COUNT_SW_MAX); - print_tool_events(&print_cb, ps); print_hwcache_events(&print_cb, ps); perf_pmus__print_pmu_events(&print_cb, ps); print_tracepoint_events(&print_cb, ps); diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 003a3bcebfdfc2..69800e4d9530b6 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -229,7 +229,7 @@ static int opt_set_target_ns(const struct option *opt __maybe_unused, /* Command option callbacks */ -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT static int opt_show_lines(const struct option *opt, const char *str, int unset __maybe_unused) { @@ -505,7 +505,7 @@ static int perf_del_probe_events(struct strfilter *filter) return ret; } -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT #define PROBEDEF_STR \ "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]" #else @@ -521,7 +521,7 @@ __cmd_probe(int argc, const char **argv) "perf probe [] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", "perf probe [] --del '[GROUP:]EVENT' ...", "perf probe --list [GROUP:]EVENT ...", -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT "perf probe [] --line 'LINEDESC'", "perf probe [] --vars 'PROBEPOINT'", #endif @@ -545,7 +545,7 @@ __cmd_probe(int argc, const char **argv) "\t\tFUNC:\tFunction name\n" "\t\tOFF:\tOffset from function entry (in byte)\n" "\t\t%return:\tPut the probe at function return\n" -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT "\t\tSRC:\tSource code path\n" "\t\tRL:\tRelative line number from function entry.\n" "\t\tAL:\tAbsolute line number in file.\n" @@ -612,11 +612,11 @@ __cmd_probe(int argc, const char **argv) set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE); set_option_flag(options, 'D', "definition", PARSE_OPT_EXCLUSIVE); set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE); -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE); #else -# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c) +# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_LIBDW=1", c) set_nobuild('L', "line", false); set_nobuild('V', "vars", false); set_nobuild('\0', "externs", false); @@ -694,7 +694,7 @@ __cmd_probe(int argc, const char **argv) if (ret < 0) pr_err_with_code(" Error: Failed to show functions.", ret); return ret; -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT case 'L': ret = show_line_range(¶ms->line_range, params->target, params->nsi, params->uprobes); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index adbaf80b398c1f..f8325247292112 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -4157,9 +4157,7 @@ int cmd_record(int argc, const char **argv) record.opts.tail_synthesize = true; if (rec->evlist->core.nr_entries == 0) { - bool can_profile_kernel = perf_event_paranoid_check(1); - - err = parse_event(rec->evlist, can_profile_kernel ? "cycles:P" : "cycles:Pu"); + err = parse_event(rec->evlist, "cycles:P"); if (err) goto out; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5dc17ffee27a2d..048c91960ba91c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -70,7 +70,7 @@ #include #ifdef HAVE_LIBTRACEEVENT -#include +#include #endif struct report { @@ -455,7 +455,7 @@ static int report__setup_sample_type(struct report *rep) if (!(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_ANY)) rep->nonany_branch_mode = true; -#if !defined(HAVE_LIBUNWIND_SUPPORT) && !defined(HAVE_DWARF_SUPPORT) +#if !defined(HAVE_LIBUNWIND_SUPPORT) && !defined(HAVE_LIBDW_SUPPORT) if (dwarf_callchain_users) { ui__warning("Please install libunwind or libdw " "development packages during the perf build.\n"); @@ -1271,6 +1271,10 @@ static int process_attr(const struct perf_tool *tool __maybe_unused, return 0; } +#define CALLCHAIN_BRANCH_SORT_ORDER \ + "srcline,symbol,dso,callchain_branch_predicted," \ + "callchain_branch_abort,callchain_branch_cycles" + int cmd_report(int argc, const char **argv) { struct perf_session *session; @@ -1639,7 +1643,7 @@ int cmd_report(int argc, const char **argv) symbol_conf.use_callchain = true; callchain_register_param(&callchain_param); if (sort_order == NULL) - sort_order = "srcline,symbol,dso"; + sort_order = CALLCHAIN_BRANCH_SORT_ORDER; } if (report.mem_mode) { @@ -1701,7 +1705,7 @@ int cmd_report(int argc, const char **argv) report.data_type = true; annotate_opts.annotate_src = false; -#ifndef HAVE_DWARF_GETLOCATIONS_SUPPORT +#ifndef HAVE_LIBDW_SUPPORT pr_err("Error: Data type profiling is disabled due to missing DWARF support\n"); goto error; #endif diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 5981cc51abc88b..7049c60ebf77c6 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -68,7 +68,6 @@ struct task_desc { struct sched_atom **atoms; pthread_t thread; - sem_t sleep_sem; sem_t ready_for_work; sem_t work_done_sem; @@ -80,12 +79,10 @@ enum sched_event_type { SCHED_EVENT_RUN, SCHED_EVENT_SLEEP, SCHED_EVENT_WAKEUP, - SCHED_EVENT_MIGRATION, }; struct sched_atom { enum sched_event_type type; - int specific_wait; u64 timestamp; u64 duration; unsigned long nr; @@ -228,6 +225,7 @@ struct perf_sched { bool show_wakeups; bool show_next; bool show_migrations; + bool pre_migrations; bool show_state; bool show_prio; u64 skipped_samples; @@ -247,7 +245,9 @@ struct thread_runtime { u64 dt_iowait; /* time between CPU access by iowait (off cpu) */ u64 dt_preempt; /* time between CPU access by preempt (off cpu) */ u64 dt_delay; /* time between wakeup and sched-in */ + u64 dt_pre_mig; /* time between migration and wakeup */ u64 ready_to_run; /* time of wakeup */ + u64 migrated; /* time when a thread is migrated */ struct stats run_stats; u64 total_run_time; @@ -255,6 +255,7 @@ struct thread_runtime { u64 total_iowait_time; u64 total_preempt_time; u64 total_delay_time; + u64 total_pre_mig_time; char last_state; @@ -421,14 +422,13 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem)); sem_init(wakee_event->wait_sem, 0, 0); - wakee_event->specific_wait = 1; event->wait_sem = wakee_event->wait_sem; sched->nr_wakeup_events++; } static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *task, - u64 timestamp, const char task_state __maybe_unused) + u64 timestamp) { struct sched_atom *event = get_new_event(task, timestamp); @@ -468,7 +468,7 @@ static struct task_desc *register_pid(struct perf_sched *sched, * every task starts in sleeping state - this gets ignored * if there's no wakeup pointing to this sleep state: */ - add_sched_event_sleep(sched, task, 0, 0); + add_sched_event_sleep(sched, task, 0); sched->pid_to_task[pid] = task; sched->nr_tasks++; @@ -529,8 +529,6 @@ static void perf_sched__process_event(struct perf_sched *sched, ret = sem_post(atom->wait_sem); BUG_ON(ret); break; - case SCHED_EVENT_MIGRATION: - break; default: BUG_ON(1); } @@ -673,7 +671,6 @@ static void create_tasks(struct perf_sched *sched) parms->task = task = sched->tasks[i]; parms->sched = sched; parms->fd = self_open_counters(sched, i); - sem_init(&task->sleep_sem, 0, 0); sem_init(&task->ready_for_work, 0, 0); sem_init(&task->work_done_sem, 0, 0); task->curr_event = 0; @@ -697,7 +694,6 @@ static void destroy_tasks(struct perf_sched *sched) task = sched->tasks[i]; err = pthread_join(task->thread, NULL); BUG_ON(err); - sem_destroy(&task->sleep_sem); sem_destroy(&task->ready_for_work); sem_destroy(&task->work_done_sem); } @@ -751,7 +747,6 @@ static void wait_for_tasks(struct perf_sched *sched) for (i = 0; i < sched->nr_tasks; i++) { task = sched->tasks[i]; - sem_init(&task->sleep_sem, 0, 0); task->curr_event = 0; } } @@ -852,7 +847,6 @@ static int replay_switch_event(struct perf_sched *sched, *next_comm = evsel__strval(evsel, sample, "next_comm"); const u32 prev_pid = evsel__intval(evsel, sample, "prev_pid"), next_pid = evsel__intval(evsel, sample, "next_pid"); - const char prev_state = evsel__taskstate(evsel, sample, "prev_state"); struct task_desc *prev, __maybe_unused *next; u64 timestamp0, timestamp = sample->time; int cpu = sample->cpu; @@ -884,7 +878,7 @@ static int replay_switch_event(struct perf_sched *sched, sched->cpu_last_switched[cpu] = timestamp; add_sched_event_run(sched, prev, timestamp, delta); - add_sched_event_sleep(sched, prev, timestamp, prev_state); + add_sched_event_sleep(sched, prev, timestamp); return 0; } @@ -1749,7 +1743,7 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel, } if (sched->map.comp && new_cpu) - color_fprintf(stdout, color, " (CPU %d)", this_cpu); + color_fprintf(stdout, color, " (CPU %d)", this_cpu.cpu); if (proceed != 1) { color_fprintf(stdout, color, "\n"); @@ -2083,14 +2077,15 @@ static void timehist_header(struct perf_sched *sched) printf(" "); } - if (sched->show_prio) { - printf(" %-*s %-*s %9s %9s %9s", - comm_width, "task name", MAX_PRIO_STR_LEN, "prio", - "wait time", "sch delay", "run time"); - } else { - printf(" %-*s %9s %9s %9s", comm_width, - "task name", "wait time", "sch delay", "run time"); - } + printf(" %-*s", comm_width, "task name"); + + if (sched->show_prio) + printf(" %-*s", MAX_PRIO_STR_LEN, "prio"); + + printf(" %9s %9s %9s", "wait time", "sch delay", "run time"); + + if (sched->pre_migrations) + printf(" %9s", "pre-mig time"); if (sched->show_state) printf(" %s", "state"); @@ -2105,17 +2100,15 @@ static void timehist_header(struct perf_sched *sched) if (sched->show_cpu_visual) printf(" %*s ", ncpus, ""); - if (sched->show_prio) { - printf(" %-*s %-*s %9s %9s %9s", - comm_width, "[tid/pid]", MAX_PRIO_STR_LEN, "", - "(msec)", "(msec)", "(msec)"); - } else { - printf(" %-*s %9s %9s %9s", comm_width, - "[tid/pid]", "(msec)", "(msec)", "(msec)"); - } + printf(" %-*s", comm_width, "[tid/pid]"); - if (sched->show_state) - printf(" %5s", ""); + if (sched->show_prio) + printf(" %-*s", MAX_PRIO_STR_LEN, ""); + + printf(" %9s %9s %9s", "(msec)", "(msec)", "(msec)"); + + if (sched->pre_migrations) + printf(" %9s", "(msec)"); printf("\n"); @@ -2127,15 +2120,15 @@ static void timehist_header(struct perf_sched *sched) if (sched->show_cpu_visual) printf(" %.*s ", ncpus, graph_dotted_line); - if (sched->show_prio) { - printf(" %.*s %.*s %.9s %.9s %.9s", - comm_width, graph_dotted_line, MAX_PRIO_STR_LEN, graph_dotted_line, - graph_dotted_line, graph_dotted_line, graph_dotted_line); - } else { - printf(" %.*s %.9s %.9s %.9s", comm_width, - graph_dotted_line, graph_dotted_line, graph_dotted_line, - graph_dotted_line); - } + printf(" %.*s", comm_width, graph_dotted_line); + + if (sched->show_prio) + printf(" %.*s", MAX_PRIO_STR_LEN, graph_dotted_line); + + printf(" %.9s %.9s %.9s", graph_dotted_line, graph_dotted_line, graph_dotted_line); + + if (sched->pre_migrations) + printf(" %.9s", graph_dotted_line); if (sched->show_state) printf(" %.5s", graph_dotted_line); @@ -2190,6 +2183,8 @@ static void timehist_print_sample(struct perf_sched *sched, print_sched_time(tr->dt_delay, 6); print_sched_time(tr->dt_run, 6); + if (sched->pre_migrations) + print_sched_time(tr->dt_pre_mig, 6); if (sched->show_state) printf(" %5c ", thread__tid(thread) == 0 ? 'I' : state); @@ -2227,18 +2222,21 @@ static void timehist_print_sample(struct perf_sched *sched, * last_time = time of last sched change event for current task * (i.e, time process was last scheduled out) * ready_to_run = time of wakeup for current task + * migrated = time of task migration to another CPU * - * -----|------------|------------|------------|------ - * last ready tprev t + * -----|-------------|-------------|-------------|-------------|----- + * last ready migrated tprev t * time to run * - * |-------- dt_wait --------| - * |- dt_delay -|-- dt_run --| + * |---------------- dt_wait ----------------| + * |--------- dt_delay ---------|-- dt_run --| + * |- dt_pre_mig -| * - * dt_run = run time of current task - * dt_wait = time between last schedule out event for task and tprev - * represents time spent off the cpu - * dt_delay = time between wakeup and schedule-in of task + * dt_run = run time of current task + * dt_wait = time between last schedule out event for task and tprev + * represents time spent off the cpu + * dt_delay = time between wakeup and schedule-in of task + * dt_pre_mig = time between wakeup and migration to another CPU */ static void timehist_update_runtime_stats(struct thread_runtime *r, @@ -2249,6 +2247,7 @@ static void timehist_update_runtime_stats(struct thread_runtime *r, r->dt_iowait = 0; r->dt_preempt = 0; r->dt_run = 0; + r->dt_pre_mig = 0; if (tprev) { r->dt_run = t - tprev; @@ -2257,6 +2256,9 @@ static void timehist_update_runtime_stats(struct thread_runtime *r, pr_debug("time travel: wakeup time for task > previous sched_switch event\n"); else r->dt_delay = tprev - r->ready_to_run; + + if ((r->migrated > r->ready_to_run) && (r->migrated < tprev)) + r->dt_pre_mig = r->migrated - r->ready_to_run; } if (r->last_time > tprev) @@ -2280,6 +2282,7 @@ static void timehist_update_runtime_stats(struct thread_runtime *r, r->total_sleep_time += r->dt_sleep; r->total_iowait_time += r->dt_iowait; r->total_preempt_time += r->dt_preempt; + r->total_pre_mig_time += r->dt_pre_mig; } static bool is_idle_sample(struct perf_sample *sample, @@ -2693,9 +2696,13 @@ static int timehist_migrate_task_event(const struct perf_tool *tool, return -1; tr->migrations++; + tr->migrated = sample->time; /* show migrations if requested */ - timehist_print_migration_event(sched, evsel, sample, machine, thread); + if (sched->show_migrations) { + timehist_print_migration_event(sched, evsel, sample, + machine, thread); + } return 0; } @@ -2846,11 +2853,13 @@ static int timehist_sched_change_event(const struct perf_tool *tool, /* last state is used to determine where to account wait time */ tr->last_state = state; - /* sched out event for task so reset ready to run time */ + /* sched out event for task so reset ready to run time and migrated time */ if (state == 'R') tr->ready_to_run = t; else tr->ready_to_run = 0; + + tr->migrated = 0; } evsel__save_time(evsel, sample->time, sample->cpu); @@ -3290,8 +3299,8 @@ static int perf_sched__timehist(struct perf_sched *sched) goto out; } - if (sched->show_migrations && - perf_session__set_tracepoints_handlers(session, migrate_handlers)) + if ((sched->show_migrations || sched->pre_migrations) && + perf_session__set_tracepoints_handlers(session, migrate_handlers)) goto out; /* pre-allocate struct for per-CPU idle stats */ @@ -3833,6 +3842,7 @@ int cmd_sched(int argc, const char **argv) OPT_BOOLEAN(0, "show-prio", &sched.show_prio, "Show task priority"), OPT_STRING(0, "prio", &sched.prio_str, "prio", "analyze events only for given task priority(ies)"), + OPT_BOOLEAN('P', "pre-migrations", &sched.pre_migrations, "Show pre-migration wait time"), OPT_PARENT(sched_options) }; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index a644787fa9e1dc..9e47905f75a6b8 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -67,7 +67,7 @@ #include #ifdef HAVE_LIBTRACEEVENT -#include +#include #endif static char const *script_name; @@ -1728,6 +1728,7 @@ static struct { {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"}, {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vmentry"}, {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vmexit"}, + {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_BRANCH_MISS, "br miss"}, {0, NULL} }; @@ -2136,11 +2137,11 @@ struct metric_ctx { }; static void script_print_metric(struct perf_stat_config *config __maybe_unused, - void *ctx, const char *color, - const char *fmt, - const char *unit, double val) + void *ctx, enum metric_threshold_classify thresh, + const char *fmt, const char *unit, double val) { struct metric_ctx *mctx = ctx; + const char *color = metric_threshold_classify__color(thresh); if (!fmt) return; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 689a3d43c2584f..fdf5172646a598 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -46,6 +46,7 @@ #include "util/parse-events.h" #include "util/pmus.h" #include "util/pmu.h" +#include "util/tool_pmu.h" #include "util/event.h" #include "util/evlist.h" #include "util/evsel.h" @@ -294,14 +295,14 @@ static int read_single_counter(struct evsel *counter, int cpu_map_idx, int threa * terminates. Use the wait4 values in that case. */ if (err && cpu_map_idx == 0 && - (evsel__tool_event(counter) == PERF_TOOL_USER_TIME || - evsel__tool_event(counter) == PERF_TOOL_SYSTEM_TIME)) { + (evsel__tool_event(counter) == TOOL_PMU__EVENT_USER_TIME || + evsel__tool_event(counter) == TOOL_PMU__EVENT_SYSTEM_TIME)) { u64 val, *start_time; struct perf_counts_values *count = perf_counts(counter->counts, cpu_map_idx, thread); start_time = xyarray__entry(counter->start_times, cpu_map_idx, thread); - if (evsel__tool_event(counter) == PERF_TOOL_USER_TIME) + if (evsel__tool_event(counter) == TOOL_PMU__EVENT_USER_TIME) val = ru_stats.ru_utime_usec_stat.mean; else val = ru_stats.ru_stime_usec_stat.mean; @@ -639,8 +640,7 @@ static enum counter_recovery stat_handle_error(struct evsel *counter) * (behavior changed with commit b0a873e). */ if (errno == EINVAL || errno == ENOSYS || - errno == ENOENT || errno == EOPNOTSUPP || - errno == ENXIO) { + errno == ENOENT || errno == ENXIO) { if (verbose > 0) ui__warning("%s event is not supported by the kernel.\n", evsel__name(counter)); @@ -658,7 +658,7 @@ static enum counter_recovery stat_handle_error(struct evsel *counter) if (verbose > 0) ui__warning("%s\n", msg); return COUNTER_RETRY; - } else if (target__has_per_thread(&target) && + } else if (target__has_per_thread(&target) && errno != EOPNOTSUPP && evsel_list->core.threads && evsel_list->core.threads->err_thread != -1) { /* @@ -679,6 +679,19 @@ static enum counter_recovery stat_handle_error(struct evsel *counter) return COUNTER_SKIP; } + if (errno == EOPNOTSUPP) { + if (verbose > 0) { + ui__warning("%s event is not supported by the kernel.\n", + evsel__name(counter)); + } + counter->supported = false; + counter->errored = true; + + if ((evsel__leader(counter) != counter) || + !(counter->core.leader->nr_members > 1)) + return COUNTER_SKIP; + } + evsel__open_strerror(counter, &target, errno, msg, sizeof(msg)); ui__error("%s\n", msg); @@ -716,15 +729,19 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) } if (!cpu_map__is_dummy(evsel_list->core.user_requested_cpus)) { - if (affinity__setup(&saved_affinity) < 0) - return -1; + if (affinity__setup(&saved_affinity) < 0) { + err = -1; + goto err_out; + } affinity = &saved_affinity; } evlist__for_each_entry(evsel_list, counter) { counter->reset_group = false; - if (bpf_counter__load(counter, &target)) - return -1; + if (bpf_counter__load(counter, &target)) { + err = -1; + goto err_out; + } if (!(evsel__is_bperf(counter))) all_counters_use_bpf = false; } @@ -767,7 +784,8 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) switch (stat_handle_error(counter)) { case COUNTER_FATAL: - return -1; + err = -1; + goto err_out; case COUNTER_RETRY: goto try_again; case COUNTER_SKIP: @@ -808,7 +826,8 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) switch (stat_handle_error(counter)) { case COUNTER_FATAL: - return -1; + err = -1; + goto err_out; case COUNTER_RETRY: goto try_again_reset; case COUNTER_SKIP: @@ -821,6 +840,7 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) } } affinity__cleanup(affinity); + affinity = NULL; evlist__for_each_entry(evsel_list, counter) { if (!counter->supported) { @@ -833,8 +853,10 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) stat_config.unit_width = l; if (evsel__should_store_id(counter) && - evsel__store_ids(counter, evsel_list)) - return -1; + evsel__store_ids(counter, evsel_list)) { + err = -1; + goto err_out; + } } if (evlist__apply_filters(evsel_list, &counter, &target)) { @@ -855,20 +877,23 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) } if (err < 0) - return err; + goto err_out; err = perf_event__synthesize_stat_events(&stat_config, NULL, evsel_list, process_synthesized_event, is_pipe); if (err < 0) - return err; + goto err_out; + } if (target.initial_delay) { pr_info(EVLIST_DISABLED_MSG); } else { err = enable_counters(); - if (err) - return -1; + if (err) { + err = -1; + goto err_out; + } } /* Exec the command, if any */ @@ -878,8 +903,10 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) if (target.initial_delay > 0) { usleep(target.initial_delay * USEC_PER_MSEC); err = enable_counters(); - if (err) - return -1; + if (err) { + err = -1; + goto err_out; + } pr_info(EVLIST_ENABLED_MSG); } @@ -899,7 +926,8 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) if (workload_exec_errno) { const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); pr_err("Workload failed: %s\n", emsg); - return -1; + err = -1; + goto err_out; } if (WIFSIGNALED(status)) @@ -946,8 +974,23 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) evlist__close(evsel_list); return WEXITSTATUS(status); + +err_out: + if (forks) + evlist__cancel_workload(evsel_list); + + affinity__cleanup(affinity); + return err; } +/* + * Returns -1 for fatal errors which signifies to not continue + * when in repeat mode. + * + * Returns < -1 error codes when stat record is used. These + * result in the stat information being displayed, but writing + * to the file fails and is non fatal. + */ static int run_perf_stat(int argc, const char **argv, int run_idx) { int ret; @@ -1814,130 +1857,25 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st) } /* - * Add default attributes, if there were no attributes specified or + * Add default events, if there were no attributes specified or * if -d/--detailed, -d -d or -d -d -d is used: */ -static int add_default_attributes(void) +static int add_default_events(void) { - struct perf_event_attr default_attrs0[] = { - - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS }, - { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, - - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, -}; - struct perf_event_attr frontend_attrs[] = { - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, -}; - struct perf_event_attr backend_attrs[] = { - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, -}; - struct perf_event_attr default_attrs1[] = { - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, - { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, - -}; - -/* - * Detailed stats (-d), covering the L1 and last level data caches: - */ - struct perf_event_attr detailed_attrs[] = { - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1D << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1D << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_LL << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_LL << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, -}; - -/* - * Very detailed stats (-d -d), covering the instruction cache and the TLB caches: - */ - struct perf_event_attr very_detailed_attrs[] = { - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1I << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1I << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_DTLB << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_DTLB << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_ITLB << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_ITLB << 0 | - (PERF_COUNT_HW_CACHE_OP_READ << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, - -}; + const char *pmu = parse_events_option_args.pmu_filter ?: "all"; + struct parse_events_error err; + struct evlist *evlist = evlist__new(); + struct evsel *evsel; + int ret = 0; -/* - * Very, very detailed stats (-d -d -d), adding prefetch events: - */ - struct perf_event_attr very_very_detailed_attrs[] = { - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1D << 0 | - (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | - (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) }, - - { .type = PERF_TYPE_HW_CACHE, - .config = - PERF_COUNT_HW_CACHE_L1D << 0 | - (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | - (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, -}; + if (!evlist) + return -ENOMEM; - struct perf_event_attr default_null_attrs[] = {}; - const char *pmu = parse_events_option_args.pmu_filter ?: "all"; + parse_events_error__init(&err); /* Set attrs if no event is selected and !null_run: */ if (stat_config.null_run) - return 0; + goto out; if (transaction_run) { /* Handle -T as -M transaction. Once platform specific metrics @@ -1947,9 +1885,10 @@ static int add_default_attributes(void) */ if (!metricgroup__has_metric(pmu, "transaction")) { pr_err("Missing transaction metrics\n"); - return -1; + ret = -1; + goto out; } - return metricgroup__parse_groups(evsel_list, pmu, "transaction", + ret = metricgroup__parse_groups(evlist, pmu, "transaction", stat_config.metric_no_group, stat_config.metric_no_merge, stat_config.metric_no_threshold, @@ -1957,6 +1896,7 @@ static int add_default_attributes(void) stat_config.system_wide, stat_config.hardware_aware_grouping, &stat_config.metric_events); + goto out; } if (smi_cost) { @@ -1964,26 +1904,29 @@ static int add_default_attributes(void) if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) { pr_err("freeze_on_smi is not supported.\n"); - return -1; + ret = -1; + goto out; } if (!smi) { if (sysfs__write_int(FREEZE_ON_SMI_PATH, 1) < 0) { - fprintf(stderr, "Failed to set freeze_on_smi.\n"); - return -1; + pr_err("Failed to set freeze_on_smi.\n"); + ret = -1; + goto out; } smi_reset = true; } if (!metricgroup__has_metric(pmu, "smi")) { pr_err("Missing smi metrics\n"); - return -1; + ret = -1; + goto out; } if (!force_metric_only) stat_config.metric_only = true; - return metricgroup__parse_groups(evsel_list, pmu, "smi", + ret = metricgroup__parse_groups(evlist, pmu, "smi", stat_config.metric_no_group, stat_config.metric_no_merge, stat_config.metric_no_threshold, @@ -1991,6 +1934,7 @@ static int add_default_attributes(void) stat_config.system_wide, stat_config.hardware_aware_grouping, &stat_config.metric_events); + goto out; } if (topdown_run) { @@ -2003,21 +1947,23 @@ static int add_default_attributes(void) if (!max_level) { pr_err("Topdown requested but the topdown metric groups aren't present.\n" "(See perf list the metric groups have names like TopdownL1)\n"); - return -1; + ret = -1; + goto out; } if (stat_config.topdown_level > max_level) { pr_err("Invalid top-down metrics level. The max level is %u.\n", max_level); - return -1; - } else if (!stat_config.topdown_level) + ret = -1; + goto out; + } else if (!stat_config.topdown_level) { stat_config.topdown_level = 1; - + } if (!stat_config.interval && !stat_config.metric_only) { fprintf(stat_config.output, "Topdown accuracy may decrease when measuring long periods.\n" "Please print the result regularly, e.g. -I1000\n"); } str[8] = stat_config.topdown_level + '0'; - if (metricgroup__parse_groups(evsel_list, + if (metricgroup__parse_groups(evlist, pmu, str, /*metric_no_group=*/false, /*metric_no_merge=*/false, @@ -2025,41 +1971,49 @@ static int add_default_attributes(void) stat_config.user_requested_cpu_list, stat_config.system_wide, stat_config.hardware_aware_grouping, - &stat_config.metric_events) < 0) - return -1; + &stat_config.metric_events) < 0) { + ret = -1; + goto out; + } } if (!stat_config.topdown_level) stat_config.topdown_level = 1; - if (!evsel_list->core.nr_entries) { + if (!evlist->core.nr_entries && !evsel_list->core.nr_entries) { /* No events so add defaults. */ if (target__has_cpu(&target)) - default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK; + ret = parse_events(evlist, "cpu-clock", &err); + else + ret = parse_events(evlist, "task-clock", &err); + if (ret) + goto out; + + ret = parse_events(evlist, + "context-switches," + "cpu-migrations," + "page-faults," + "instructions," + "cycles," + "stalled-cycles-frontend," + "stalled-cycles-backend," + "branches," + "branch-misses", + &err); + if (ret) + goto out; - if (evlist__add_default_attrs(evsel_list, default_attrs0) < 0) - return -1; - if (perf_pmus__have_event("cpu", "stalled-cycles-frontend")) { - if (evlist__add_default_attrs(evsel_list, frontend_attrs) < 0) - return -1; - } - if (perf_pmus__have_event("cpu", "stalled-cycles-backend")) { - if (evlist__add_default_attrs(evsel_list, backend_attrs) < 0) - return -1; - } - if (evlist__add_default_attrs(evsel_list, default_attrs1) < 0) - return -1; /* * Add TopdownL1 metrics if they exist. To minimize * multiplexing, don't request threshold computation. */ if (metricgroup__has_metric(pmu, "Default")) { struct evlist *metric_evlist = evlist__new(); - struct evsel *metric_evsel; - - if (!metric_evlist) - return -1; + if (!metric_evlist) { + ret = -ENOMEM; + goto out; + } if (metricgroup__parse_groups(metric_evlist, pmu, "Default", /*metric_no_group=*/false, /*metric_no_merge=*/false, @@ -2067,43 +2021,71 @@ static int add_default_attributes(void) stat_config.user_requested_cpu_list, stat_config.system_wide, stat_config.hardware_aware_grouping, - &stat_config.metric_events) < 0) - return -1; - - evlist__for_each_entry(metric_evlist, metric_evsel) { - metric_evsel->skippable = true; - metric_evsel->default_metricgroup = true; + &stat_config.metric_events) < 0) { + ret = -1; + goto out; } - evlist__splice_list_tail(evsel_list, &metric_evlist->core.entries); + + evlist__for_each_entry(metric_evlist, evsel) + evsel->default_metricgroup = true; + + evlist__splice_list_tail(evlist, &metric_evlist->core.entries); evlist__delete(metric_evlist); } - - /* Platform specific attrs */ - if (evlist__add_default_attrs(evsel_list, default_null_attrs) < 0) - return -1; } /* Detailed events get appended to the event list: */ - if (detailed_run < 1) - return 0; - - /* Append detailed run extra attributes: */ - if (evlist__add_default_attrs(evsel_list, detailed_attrs) < 0) - return -1; - - if (detailed_run < 2) - return 0; - - /* Append very detailed run extra attributes: */ - if (evlist__add_default_attrs(evsel_list, very_detailed_attrs) < 0) - return -1; - - if (detailed_run < 3) - return 0; - - /* Append very, very detailed run extra attributes: */ - return evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); + if (!ret && detailed_run >= 1) { + /* + * Detailed stats (-d), covering the L1 and last level data + * caches: + */ + ret = parse_events(evlist, + "L1-dcache-loads," + "L1-dcache-load-misses," + "LLC-loads," + "LLC-load-misses", + &err); + } + if (!ret && detailed_run >= 2) { + /* + * Very detailed stats (-d -d), covering the instruction cache + * and the TLB caches: + */ + ret = parse_events(evlist, + "L1-icache-loads," + "L1-icache-load-misses," + "dTLB-loads," + "dTLB-load-misses," + "iTLB-loads," + "iTLB-load-misses", + &err); + } + if (!ret && detailed_run >= 3) { + /* + * Very, very detailed stats (-d -d -d), adding prefetch events: + */ + ret = parse_events(evlist, + "L1-dcache-prefetches," + "L1-dcache-prefetch-misses", + &err); + } +out: + if (!ret) { + evlist__for_each_entry(evlist, evsel) { + /* + * Make at least one event non-skippable so fatal errors are visible. + * 'cycles' always used to be default and non-skippable, so use that. + */ + if (strcmp("cycles", evsel__name(evsel))) + evsel->skippable = true; + } + } + parse_events_error__exit(&err); + evlist__splice_list_tail(evsel_list, &evlist->core.entries); + evlist__delete(evlist); + return ret; } static const char * const stat_record_usage[] = { @@ -2591,6 +2573,14 @@ int cmd_stat(int argc, const char **argv) goto out; } + if (stat_config.csv_output || (stat_config.metric_only && stat_config.json_output)) { + /* + * Current CSV and metric-only JSON output doesn't display the + * metric threshold so don't compute it. + */ + stat_config.metric_no_threshold = true; + } + if (stat_config.walltime_run_table && stat_config.run_count <= 1) { fprintf(stderr, "--table is only supported with -r\n"); parse_options_usage(stat_usage, stat_options, "r", 1); @@ -2651,6 +2641,7 @@ int cmd_stat(int argc, const char **argv) } else if (big_num_opt == 0) /* User passed --no-big-num */ stat_config.big_num = false; + target.inherit = !stat_config.no_inherit; err = target__validate(&target); if (err) { target__strerror(&target, err, errbuf, BUFSIZ); @@ -2760,7 +2751,7 @@ int cmd_stat(int argc, const char **argv) } } - if (add_default_attributes()) + if (add_default_events()) goto out; if (stat_config.cgroup_list) { @@ -2879,7 +2870,10 @@ int cmd_stat(int argc, const char **argv) evlist__reset_prev_raw_counts(evsel_list); status = run_perf_stat(argc, argv, run_idx); - if (forever && status != -1 && !interval) { + if (status == -1) + break; + + if (forever && !interval) { print_counters(NULL, argc, argv); perf_stat__reset_stats(); } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 218c8b44d7beac..068d297aaf44b2 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -38,7 +38,7 @@ #include "util/tracepoint.h" #include "util/util.h" #include -#include +#include #ifdef LACKS_OPEN_MEMSTREAM_PROTOTYPE FILE *open_memstream(char **ptr, size_t *sizeloc); @@ -1158,7 +1158,6 @@ static void draw_io_bars(struct timechart *tchart) } svg_box(Y, c->start_time, c->end_time, "process3"); - sample = c->io_samples; for (sample = c->io_samples; sample; sample = sample->next) { double h = (double)sample->bytes / c->max_bytes; diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d3f11b90d0255c..6a1a128fe64501 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -88,7 +88,7 @@ #include #ifdef HAVE_LIBTRACEEVENT -#include +#include #endif #ifndef O_CLOEXEC @@ -1873,7 +1873,7 @@ static int trace__process_event(struct trace *trace, struct machine *machine, switch (event->header.type) { case PERF_RECORD_LOST: color_fprintf(trace->output, PERF_COLOR_RED, - "LOST %" PRIu64 " events!\n", event->lost.lost); + "LOST %" PRIu64 " events!\n", (u64)event->lost.lost); ret = machine__process_lost_event(machine, event, sample); break; default: @@ -2702,6 +2702,7 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel, char msg[1024]; void *args, *augmented_args = NULL; int augmented_args_size; + size_t printed = 0; if (sc == NULL) return -1; @@ -2717,8 +2718,8 @@ static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel, args = perf_evsel__sc_tp_ptr(evsel, args, sample); augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size); - syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread); - fprintf(trace->output, "%s", msg); + printed += syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread); + fprintf(trace->output, "%.*s", (int)printed, msg); err = 0; out_put: thread__put(thread); @@ -3087,7 +3088,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel, printed += syscall_arg_fmt__scnprintf_val(arg, bf + printed, size - printed, &syscall_arg, val); } - return printed + fprintf(trace->output, "%s", bf); + return printed + fprintf(trace->output, "%.*s", (int)printed, bf); } static int trace__event_handler(struct trace *trace, struct evsel *evsel, @@ -3096,13 +3097,8 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel, { struct thread *thread; int callchain_ret = 0; - /* - * Check if we called perf_evsel__disable(evsel) due to, for instance, - * this event's max_events having been hit and this is an entry coming - * from the ring buffer that we should discard, since the max events - * have already been considered/printed. - */ - if (evsel->disabled) + + if (evsel->nr_events_printed >= evsel->max_events) return 0; thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); @@ -4326,6 +4322,9 @@ static int trace__run(struct trace *trace, int argc, const char **argv) sizeof(__u32), BPF_ANY); } } + + if (trace->skel) + trace->filter_pids.map = trace->skel->maps.pids_filtered; #endif err = trace__set_filter_pids(trace); if (err < 0) @@ -5449,6 +5448,10 @@ int cmd_trace(int argc, const char **argv) if (trace.summary_only) trace.summary = trace.summary_only; + /* Keep exited threads, otherwise information might be lost for summary */ + if (trace.summary) + symbol_conf.keep_exited_threads = true; + if (output_name != NULL) { err = trace__open_output(&trace, output_name); if (err < 0) { diff --git a/tools/perf/check-header_ignore_hunks/lib/list_sort.c b/tools/perf/check-header_ignore_hunks/lib/list_sort.c index 32d98cb34f80a9..b7316d29857d4f 100644 --- a/tools/perf/check-header_ignore_hunks/lib/list_sort.c +++ b/tools/perf/check-header_ignore_hunks/lib/list_sort.c @@ -1,11 +1,4 @@ -@@ -1,5 +1,6 @@ - // SPDX-License-Identifier: GPL-2.0 - #include -+#include - #include - #include - #include -@@ -52,6 +53,7 @@ +@@ -50,6 +50,7 @@ struct list_head *a, struct list_head *b) { struct list_head *tail = head; @@ -13,7 +6,7 @@ for (;;) { /* if equal, take 'a' -- important for sort stability */ -@@ -77,6 +79,15 @@ +@@ -75,6 +76,15 @@ /* Finish linking remainder of list b on to tail */ tail->next = b; do { diff --git a/tools/perf/dlfilters/dlfilter-test-api-v0.c b/tools/perf/dlfilters/dlfilter-test-api-v0.c index 4083b1abeaabe6..4ca2d7b2ea6c82 100644 --- a/tools/perf/dlfilters/dlfilter-test-api-v0.c +++ b/tools/perf/dlfilters/dlfilter-test-api-v0.c @@ -220,7 +220,7 @@ static int check_sample(struct filter_data *d, const struct perf_dlfilter_sample CHECK_SAMPLE(raw_callchain_nr); CHECK(!sample->raw_callchain); -#define EVENT_NAME "branches:" +#define EVENT_NAME "branches" CHECK(!strncmp(sample->event, EVENT_NAME, strlen(EVENT_NAME))); return 0; diff --git a/tools/perf/dlfilters/dlfilter-test-api-v2.c b/tools/perf/dlfilters/dlfilter-test-api-v2.c index 32ff619e881caa..00d73a16c4fdae 100644 --- a/tools/perf/dlfilters/dlfilter-test-api-v2.c +++ b/tools/perf/dlfilters/dlfilter-test-api-v2.c @@ -235,7 +235,7 @@ static int check_sample(struct filter_data *d, const struct perf_dlfilter_sample CHECK_SAMPLE(raw_callchain_nr); CHECK(!sample->raw_callchain); -#define EVENT_NAME "branches:" +#define EVENT_NAME "branches" CHECK(!strncmp(sample->event, EVENT_NAME, strlen(EVENT_NAME))); return 0; diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 4def800f4089d7..a2987f2cfe1a39 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -542,8 +542,6 @@ int main(int argc, const char **argv) } cmd = argv[0]; - test_attr__init(); - /* * We use PATH to find perf commands, but we prepend some higher * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH diff --git a/tools/perf/pmu-events/arch/arm64/freescale/imx91/sys/ddrc.json b/tools/perf/pmu-events/arch/arm64/freescale/imx91/sys/ddrc.json new file mode 100644 index 00000000000000..74ac12660a2948 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/freescale/imx91/sys/ddrc.json @@ -0,0 +1,9 @@ +[ + { + "BriefDescription": "ddr cycles event", + "EventCode": "0x00", + "EventName": "imx91_ddr.cycles", + "Unit": "imx9_ddr", + "Compat": "imx91" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/freescale/imx91/sys/metrics.json b/tools/perf/pmu-events/arch/arm64/freescale/imx91/sys/metrics.json new file mode 100644 index 00000000000000..f0c5911eb2d0cd --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/freescale/imx91/sys/metrics.json @@ -0,0 +1,26 @@ +[ + { + "BriefDescription": "bandwidth usage for lpddr4 evk board", + "MetricName": "imx91_bandwidth_usage.lpddr4", + "MetricExpr": "(((( imx9_ddr0@ddrc_pm_0@ ) * 2 * 8 ) + (( imx9_ddr0@ddrc_pm_3@ + imx9_ddr0@ddrc_pm_5@ + imx9_ddr0@ddrc_pm_7@ + imx9_ddr0@ddrc_pm_9@ - imx9_ddr0@ddrc_pm_2@ - imx9_ddr0@ddrc_pm_4@ - imx9_ddr0@ddrc_pm_6@ - imx9_ddr0@ddrc_pm_8@ ) * 32 )) / duration_time) / (2400 * 1000000 * 2)", + "ScaleUnit": "1e2%", + "Unit": "imx9_ddr", + "Compat": "imx91" + }, + { + "BriefDescription": "bytes all masters read from ddr", + "MetricName": "imx91_ddr_read.all", + "MetricExpr": "( imx9_ddr0@ddrc_pm_0@ ) * 2 * 8", + "ScaleUnit": "9.765625e-4KB", + "Unit": "imx9_ddr", + "Compat": "imx91" + }, + { + "BriefDescription": "bytes all masters write to ddr", + "MetricName": "imx91_ddr_write.all", + "MetricExpr": "( imx9_ddr0@ddrc_pm_3@ + imx9_ddr0@ddrc_pm_5@ + imx9_ddr0@ddrc_pm_7@ + imx9_ddr0@ddrc_pm_9@ - imx9_ddr0@ddrc_pm_2@ - imx9_ddr0@ddrc_pm_4@ - imx9_ddr0@ddrc_pm_6@ - imx9_ddr0@ddrc_pm_8@ ) * 32", + "ScaleUnit": "9.765625e-4KB", + "Unit": "imx9_ddr", + "Compat": "imx91" + } +] diff --git a/tools/perf/pmu-events/arch/arm64/freescale/imx95/sys/metrics.json b/tools/perf/pmu-events/arch/arm64/freescale/imx95/sys/metrics.json index 126ce980f6f251..45a0d51dfb6398 100644 --- a/tools/perf/pmu-events/arch/arm64/freescale/imx95/sys/metrics.json +++ b/tools/perf/pmu-events/arch/arm64/freescale/imx95/sys/metrics.json @@ -7,6 +7,14 @@ "Unit": "imx9_ddr", "Compat": "imx95" }, + { + "BriefDescription": "bandwidth usage for lpddr4x evk board", + "MetricName": "imx95_bandwidth_usage.lpddr4x", + "MetricExpr": "(( imx9_ddr0@eddrtq_pm_rd_beat_filt0\\,axi_mask\\=0x000\\,axi_id\\=0x000@ + imx9_ddr0@eddrtq_pm_wr_beat_filt\\,axi_mask\\=0x000\\,axi_id\\=0x000@ ) * 32 / duration_time) / (4000 * 1000000 * 4)", + "ScaleUnit": "1e2%", + "Unit": "imx9_ddr", + "Compat": "imx95" + }, { "BriefDescription": "bytes of all masters read from ddr", "MetricName": "imx95_ddr_read.all", diff --git a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/metrics.json b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/metrics.json index 6463531b99410f..b6a0d2de8534af 100644 --- a/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/metrics.json +++ b/tools/perf/pmu-events/arch/arm64/hisilicon/hip08/metrics.json @@ -3,235 +3,235 @@ "MetricExpr": "FETCH_BUBBLE / (4 * CPU_CYCLES)", "PublicDescription": "Frontend bound L1 topdown metric", "BriefDescription": "Frontend bound L1 topdown metric", - "DefaultMetricgroupName": "TopDownL1", - "MetricGroup": "Default;TopDownL1", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", "MetricName": "frontend_bound" }, { "MetricExpr": "(INST_SPEC - INST_RETIRED) / (4 * CPU_CYCLES)", "PublicDescription": "Bad Speculation L1 topdown metric", "BriefDescription": "Bad Speculation L1 topdown metric", - "DefaultMetricgroupName": "TopDownL1", - "MetricGroup": "Default;TopDownL1", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", "MetricName": "bad_speculation" }, { "MetricExpr": "INST_RETIRED / (CPU_CYCLES * 4)", "PublicDescription": "Retiring L1 topdown metric", "BriefDescription": "Retiring L1 topdown metric", - "DefaultMetricgroupName": "TopDownL1", - "MetricGroup": "Default;TopDownL1", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", "MetricName": "retiring" }, { "MetricExpr": "1 - (frontend_bound + bad_speculation + retiring)", "PublicDescription": "Backend Bound L1 topdown metric", "BriefDescription": "Backend Bound L1 topdown metric", - "DefaultMetricgroupName": "TopDownL1", - "MetricGroup": "Default;TopDownL1", + "DefaultMetricgroupName": "TopdownL1", + "MetricGroup": "Default;TopdownL1", "MetricName": "backend_bound" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x201d@ / CPU_CYCLES", "PublicDescription": "Fetch latency bound L2 topdown metric", "BriefDescription": "Fetch latency bound L2 topdown metric", - "MetricGroup": "TopDownL2", + "MetricGroup": "TopdownL2", "MetricName": "fetch_latency_bound" }, { "MetricExpr": "frontend_bound - fetch_latency_bound", "PublicDescription": "Fetch bandwidth bound L2 topdown metric", "BriefDescription": "Fetch bandwidth bound L2 topdown metric", - "MetricGroup": "TopDownL2", + "MetricGroup": "TopdownL2", "MetricName": "fetch_bandwidth_bound" }, { "MetricExpr": "(bad_speculation * BR_MIS_PRED) / (BR_MIS_PRED + armv8_pmuv3_0@event\\=0x2013@)", "PublicDescription": "Branch mispredicts L2 topdown metric", "BriefDescription": "Branch mispredicts L2 topdown metric", - "MetricGroup": "TopDownL2", + "MetricGroup": "TopdownL2", "MetricName": "branch_mispredicts" }, { "MetricExpr": "bad_speculation - branch_mispredicts", "PublicDescription": "Machine clears L2 topdown metric", "BriefDescription": "Machine clears L2 topdown metric", - "MetricGroup": "TopDownL2", + "MetricGroup": "TopdownL2", "MetricName": "machine_clears" }, { "MetricExpr": "(EXE_STALL_CYCLE - (MEM_STALL_ANYLOAD + armv8_pmuv3_0@event\\=0x7005@)) / CPU_CYCLES", "PublicDescription": "Core bound L2 topdown metric", "BriefDescription": "Core bound L2 topdown metric", - "MetricGroup": "TopDownL2", + "MetricGroup": "TopdownL2", "MetricName": "core_bound" }, { "MetricExpr": "(MEM_STALL_ANYLOAD + armv8_pmuv3_0@event\\=0x7005@) / CPU_CYCLES", "PublicDescription": "Memory bound L2 topdown metric", "BriefDescription": "Memory bound L2 topdown metric", - "MetricGroup": "TopDownL2", + "MetricGroup": "TopdownL2", "MetricName": "memory_bound" }, { "MetricExpr": "(((L2I_TLB - L2I_TLB_REFILL) * 15) + (L2I_TLB_REFILL * 100)) / CPU_CYCLES", "PublicDescription": "Idle by itlb miss L3 topdown metric", "BriefDescription": "Idle by itlb miss L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "idle_by_itlb_miss" }, { "MetricExpr": "(((L2I_CACHE - L2I_CACHE_REFILL) * 15) + (L2I_CACHE_REFILL * 100)) / CPU_CYCLES", "PublicDescription": "Idle by icache miss L3 topdown metric", "BriefDescription": "Idle by icache miss L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "idle_by_icache_miss" }, { "MetricExpr": "(BR_MIS_PRED * 5) / CPU_CYCLES", "PublicDescription": "BP misp flush L3 topdown metric", "BriefDescription": "BP misp flush L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "bp_misp_flush" }, { "MetricExpr": "(armv8_pmuv3_0@event\\=0x2013@ * 5) / CPU_CYCLES", "PublicDescription": "OOO flush L3 topdown metric", "BriefDescription": "OOO flush L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "ooo_flush" }, { "MetricExpr": "(armv8_pmuv3_0@event\\=0x1001@ * 5) / CPU_CYCLES", "PublicDescription": "Static predictor flush L3 topdown metric", "BriefDescription": "Static predictor flush L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "sp_flush" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x1010@ / BR_MIS_PRED", "PublicDescription": "Indirect branch L3 topdown metric", "BriefDescription": "Indirect branch L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "indirect_branch" }, { "MetricExpr": "(armv8_pmuv3_0@event\\=0x1013@ + armv8_pmuv3_0@event\\=0x1016@) / BR_MIS_PRED", "PublicDescription": "Push branch L3 topdown metric", "BriefDescription": "Push branch L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "push_branch" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x100d@ / BR_MIS_PRED", "PublicDescription": "Pop branch L3 topdown metric", "BriefDescription": "Pop branch L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "pop_branch" }, { "MetricExpr": "(BR_MIS_PRED - armv8_pmuv3_0@event\\=0x1010@ - armv8_pmuv3_0@event\\=0x1013@ - armv8_pmuv3_0@event\\=0x1016@ - armv8_pmuv3_0@event\\=0x100d@) / BR_MIS_PRED", "PublicDescription": "Other branch L3 topdown metric", "BriefDescription": "Other branch L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "other_branch" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x2012@ / armv8_pmuv3_0@event\\=0x2013@", "PublicDescription": "Nuke flush L3 topdown metric", "BriefDescription": "Nuke flush L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "nuke_flush" }, { "MetricExpr": "1 - nuke_flush", "PublicDescription": "Other flush L3 topdown metric", "BriefDescription": "Other flush L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "other_flush" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x2010@ / CPU_CYCLES", "PublicDescription": "Sync stall L3 topdown metric", "BriefDescription": "Sync stall L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "sync_stall" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x2004@ / CPU_CYCLES", "PublicDescription": "Rob stall L3 topdown metric", "BriefDescription": "Rob stall L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "rob_stall" }, { "MetricExpr": "(armv8_pmuv3_0@event\\=0x2006@ + armv8_pmuv3_0@event\\=0x2007@ + armv8_pmuv3_0@event\\=0x2008@) / CPU_CYCLES", "PublicDescription": "Ptag stall L3 topdown metric", "BriefDescription": "Ptag stall L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "ptag_stall" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x201e@ / CPU_CYCLES", "PublicDescription": "SaveOpQ stall L3 topdown metric", "BriefDescription": "SaveOpQ stall L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "saveopq_stall" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x2005@ / CPU_CYCLES", "PublicDescription": "PC buffer stall L3 topdown metric", "BriefDescription": "PC buffer stall L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "pc_buffer_stall" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x7002@ / CPU_CYCLES", "PublicDescription": "Divider L3 topdown metric", "BriefDescription": "Divider L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "divider" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x7003@ / CPU_CYCLES", "PublicDescription": "FSU stall L3 topdown metric", "BriefDescription": "FSU stall L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "fsu_stall" }, { "MetricExpr": "core_bound - divider - fsu_stall", "PublicDescription": "EXE ports util L3 topdown metric", "BriefDescription": "EXE ports util L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "exe_ports_util" }, { "MetricExpr": "(MEM_STALL_ANYLOAD - MEM_STALL_L1MISS) / CPU_CYCLES", "PublicDescription": "L1 bound L3 topdown metric", "BriefDescription": "L1 bound L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "l1_bound" }, { "MetricExpr": "(MEM_STALL_L1MISS - MEM_STALL_L2MISS) / CPU_CYCLES", "PublicDescription": "L2 bound L3 topdown metric", "BriefDescription": "L2 bound L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "l2_bound" }, { "MetricExpr": "MEM_STALL_L2MISS / CPU_CYCLES", "PublicDescription": "Mem bound L3 topdown metric", "BriefDescription": "Mem bound L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "mem_bound" }, { "MetricExpr": "armv8_pmuv3_0@event\\=0x7005@ / CPU_CYCLES", "PublicDescription": "Store bound L3 topdown metric", "BriefDescription": "Store bound L3 topdown metric", - "MetricGroup": "TopDownL3", + "MetricGroup": "TopdownL3", "MetricName": "store_bound" } ] diff --git a/tools/perf/pmu-events/arch/common/common/tool.json b/tools/perf/pmu-events/arch/common/common/tool.json new file mode 100644 index 00000000000000..12f2ef1813a63e --- /dev/null +++ b/tools/perf/pmu-events/arch/common/common/tool.json @@ -0,0 +1,74 @@ +[ + { + "Unit": "tool", + "EventName": "duration_time", + "BriefDescription": "Wall clock interval time in nanoseconds", + "ConfigCode": "1" + }, + { + "Unit": "tool", + "EventName": "user_time", + "BriefDescription": "User (non-kernel) time in nanoseconds", + "ConfigCode": "2" + }, + { + "Unit": "tool", + "EventName": "system_time", + "BriefDescription": "System/kernel time in nanoseconds", + "ConfigCode": "3" + }, + { + "Unit": "tool", + "EventName": "has_pmem", + "BriefDescription": "1 if persistent memory installed otherwise 0", + "ConfigCode": "4" + }, + { + "Unit": "tool", + "EventName": "num_cores", + "BriefDescription": "Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU", + "ConfigCode": "5" + }, + { + "Unit": "tool", + "EventName": "num_cpus", + "BriefDescription": "Number of logical Linux CPUs. There may be multiple such CPUs on a core", + "ConfigCode": "6" + }, + { + "Unit": "tool", + "EventName": "num_cpus_online", + "BriefDescription": "Number of online logical Linux CPUs. There may be multiple such CPUs on a core", + "ConfigCode": "7" + }, + { + "Unit": "tool", + "EventName": "num_dies", + "BriefDescription": "Number of dies. Each die has 1 or more cores", + "ConfigCode": "8" + }, + { + "Unit": "tool", + "EventName": "num_packages", + "BriefDescription": "Number of packages. Each package has 1 or more die", + "ConfigCode": "9" + }, + { + "Unit": "tool", + "EventName": "slots", + "BriefDescription": "Number of functional units that in parallel can execute parts of an instruction", + "ConfigCode": "10" + }, + { + "Unit": "tool", + "EventName": "smt_on", + "BriefDescription": "1 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0", + "ConfigCode": "11" + }, + { + "Unit": "tool", + "EventName": "system_tsc_freq", + "BriefDescription": "The amount a Time Stamp Counter (TSC) increases per second", + "ConfigCode": "12" + } +] diff --git a/tools/perf/pmu-events/arch/powerpc/compat/generic-events.json b/tools/perf/pmu-events/arch/powerpc/compat/generic-events.json new file mode 100644 index 00000000000000..6f5e8efcb098cf --- /dev/null +++ b/tools/perf/pmu-events/arch/powerpc/compat/generic-events.json @@ -0,0 +1,117 @@ +[ + { + "EventCode": "0x600F4", + "EventName": "PM_CYC", + "BriefDescription": "Processor cycles." + }, + { + "EventCode": "0x100F2", + "EventName": "PM_CYC_INST_CMPL", + "BriefDescription": "1 or more ppc insts finished" + }, + { + "EventCode": "0x100f4", + "EventName": "PM_FLOP_CMPL", + "BriefDescription": "Floating Point Operations Finished." + }, + { + "EventCode": "0x100F6", + "EventName": "PM_L1_ITLB_MISS", + "BriefDescription": "Number of I-ERAT reloads." + }, + { + "EventCode": "0x100F8", + "EventName": "PM_NO_INST_AVAIL", + "BriefDescription": "Number of cycles the ICT has no itags assigned to this thread." + }, + { + "EventCode": "0x100fc", + "EventName": "PM_LD_CMPL", + "BriefDescription": "Load instruction completed." + }, + { + "EventCode": "0x200F0", + "EventName": "PM_ST_CMPL", + "BriefDescription": "Stores completed from S2Q (2nd-level store queue)." + }, + { + "EventCode": "0x200F2", + "EventName": "PM_INST_DISP", + "BriefDescription": "PowerPC instruction dispatched." + }, + { + "EventCode": "0x200F4", + "EventName": "PM_RUN_CYC", + "BriefDescription": "Processor cycles gated by the run latch." + }, + { + "EventCode": "0x200F6", + "EventName": "PM_L1_DTLB_RELOAD", + "BriefDescription": "DERAT Reloaded due to a DERAT miss." + }, + { + "EventCode": "0x200FA", + "EventName": "PM_BR_TAKEN_CMPL", + "BriefDescription": "Branch Taken instruction completed." + }, + { + "EventCode": "0x200FC", + "EventName": "PM_L1_ICACHE_MISS", + "BriefDescription": "Demand instruction cache miss." + }, + { + "EventCode": "0x200FE", + "EventName": "PM_L1_RELOAD_FROM_MEM", + "BriefDescription": "L1 Dcache reload from memory" + }, + { + "EventCode": "0x300F0", + "EventName": "PM_ST_MISS_L1", + "BriefDescription": "Store Missed L1" + }, + { + "EventCode": "0x300FC", + "EventName": "PM_DTLB_MISS", + "BriefDescription": "Data PTEG reload" + }, + { + "EventCode": "0x300FE", + "EventName": "PM_DATA_FROM_L3MISS", + "BriefDescription": "Demand LD - L3 Miss (not L2 hit and not L3 hit)" + }, + { + "EventCode": "0x400F0", + "EventName": "PM_LD_MISS_L1", + "BriefDescription": "L1 Dcache load miss" + }, + { + "EventCode": "0x400F2", + "EventName": "PM_CYC_INST_DISP", + "BriefDescription": "Cycle when instruction(s) dispatched." + }, + { + "EventCode": "0x400F6", + "EventName": "PM_BR_MPRED_CMPL", + "BriefDescription": "A mispredicted branch completed. Includes direction and target." + }, + { + "EventCode": "0x400FA", + "EventName": "PM_RUN_INST_CMPL", + "BriefDescription": "PowerPC instruction completed while the run latch is set." + }, + { + "EventCode": "0x400FC", + "EventName": "PM_ITLB_MISS", + "BriefDescription": "Instruction TLB reload (after a miss), all page sizes. Includes only demand misses." + }, + { + "EventCode": "0x400fe", + "EventName": "PM_LD_NOT_CACHED", + "BriefDescription": "Load data not cached." + }, + { + "EventCode": "0x500fa", + "EventName": "PM_INST_CMPL", + "BriefDescription": "Instructions." + } +] diff --git a/tools/perf/pmu-events/arch/powerpc/mapfile.csv b/tools/perf/pmu-events/arch/powerpc/mapfile.csv index 4d5e9138d4cc27..cbd3cb443784fd 100644 --- a/tools/perf/pmu-events/arch/powerpc/mapfile.csv +++ b/tools/perf/pmu-events/arch/powerpc/mapfile.csv @@ -16,3 +16,4 @@ 0x004e[[:xdigit:]]{4},1,power9,core 0x0080[[:xdigit:]]{4},1,power10,core 0x0082[[:xdigit:]]{4},1,power10,core +0x00ffffff,1,compat,core diff --git a/tools/perf/pmu-events/arch/x86/amdzen5/data-fabric.json b/tools/perf/pmu-events/arch/x86/amdzen5/data-fabric.json new file mode 100644 index 00000000000000..fa06569d881d1f --- /dev/null +++ b/tools/perf/pmu-events/arch/x86/amdzen5/data-fabric.json @@ -0,0 +1,1634 @@ +[ + { + "EventName": "local_or_remote_socket_read_data_beats_dram_0", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 0.", + "EventCode": "0x1f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_1", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 1.", + "EventCode": "0x5f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_2", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 2.", + "EventCode": "0x9f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_3", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 3.", + "EventCode": "0xdf", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_4", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 4.", + "EventCode": "0x11f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_5", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 5.", + "EventCode": "0x15f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_6", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 6.", + "EventCode": "0x19f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_7", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 7.", + "EventCode": "0x1df", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_8", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 8.", + "EventCode": "0x21f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_9", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 9.", + "EventCode": "0x25f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_10", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 10.", + "EventCode": "0x29f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_read_data_beats_dram_11", + "PublicDescription": "Read data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 11.", + "EventCode": "0x2df", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_0", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 0.", + "EventCode": "0x1f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_1", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 1.", + "EventCode": "0x5f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_2", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 2.", + "EventCode": "0x9f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_3", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 3.", + "EventCode": "0xdf", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_4", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 4.", + "EventCode": "0x11f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_5", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 5.", + "EventCode": "0x15f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_6", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 6.", + "EventCode": "0x19f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_7", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 7.", + "EventCode": "0x1df", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_8", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 8.", + "EventCode": "0x21f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_9", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 9.", + "EventCode": "0x25f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_10", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 10.", + "EventCode": "0x29f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_write_data_beats_dram_11", + "PublicDescription": "Write data beats (64 bytes) for transactions between local socket and DRAM Channel 11.", + "EventCode": "0x2df", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_0", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 0.", + "EventCode": "0x1f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_1", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 1.", + "EventCode": "0x5f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_2", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 2.", + "EventCode": "0x9f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_3", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 3.", + "EventCode": "0xdf", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_4", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 4.", + "EventCode": "0x11f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_5", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 5.", + "EventCode": "0x15f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_6", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 6.", + "EventCode": "0x19f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_7", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 7.", + "EventCode": "0x1df", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_8", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 8.", + "EventCode": "0x21f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_9", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 9.", + "EventCode": "0x25f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_10", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 10.", + "EventCode": "0x29f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_write_data_beats_dram_11", + "PublicDescription": "Write data beats (64 bytes) for transactions between remote socket and DRAM Channel 11.", + "EventCode": "0x2df", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_0", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 0.", + "EventCode": "0x1f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_1", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 1.", + "EventCode": "0x5f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_2", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 2.", + "EventCode": "0x9f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_3", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 3.", + "EventCode": "0xdf", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_4", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 4.", + "EventCode": "0x11f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_5", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 5.", + "EventCode": "0x15f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_6", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 6.", + "EventCode": "0x19f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_7", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 7.", + "EventCode": "0x1df", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_8", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 8.", + "EventCode": "0x21f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_9", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 9.", + "EventCode": "0x25f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_10", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 10.", + "EventCode": "0x29f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_write_data_beats_dram_11", + "PublicDescription": "Write data beats (64 bytes) for transactions between local or remote socket and DRAM Channel 11.", + "EventCode": "0x2df", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_read_data_beats_io_0", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local socket and IO Root Complex 0.", + "EventCode": "0x81f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_read_data_beats_io_1", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local socket and IO Root Complex 1.", + "EventCode": "0x85f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_read_data_beats_io_2", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local socket and IO Root Complex 2.", + "EventCode": "0x89f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_read_data_beats_io_3", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local socket and IO Root Complex 3.", + "EventCode": "0x8df", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_read_data_beats_io_4", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local socket and IO Root Complex 4.", + "EventCode": "0x91f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_read_data_beats_io_5", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local socket and IO Root Complex 5.", + "EventCode": "0x95f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_read_data_beats_io_6", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local socket and IO Root Complex 6.", + "EventCode": "0x99f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_read_data_beats_io_7", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local socket and IO Root Complex 7.", + "EventCode": "0x9df", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_write_data_beats_io_0", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local socket and IO Root Complex 0.", + "EventCode": "0x81f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_write_data_beats_io_1", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local socket and IO Root Complex 1.", + "EventCode": "0x85f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_write_data_beats_io_2", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local socket and IO Root Complex 2.", + "EventCode": "0x89f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_write_data_beats_io_3", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local socket and IO Root Complex 3.", + "EventCode": "0x8df", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_write_data_beats_io_4", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local socket and IO Root Complex 4.", + "EventCode": "0x91f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_write_data_beats_io_5", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local socket and IO Root Complex 5.", + "EventCode": "0x95f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_write_data_beats_io_6", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local socket and IO Root Complex 6.", + "EventCode": "0x99f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_upstream_write_data_beats_io_7", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local socket and IO Root Complex 7.", + "EventCode": "0x9df", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_read_data_beats_io_0", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between remote socket and IO Root Complex 0.", + "EventCode": "0x81f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_read_data_beats_io_1", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between remote socket and IO Root Complex 1.", + "EventCode": "0x85f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_read_data_beats_io_2", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between remote socket and IO Root Complex 2.", + "EventCode": "0x89f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_read_data_beats_io_3", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between remote socket and IO Root Complex 3.", + "EventCode": "0x8df", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_read_data_beats_io_4", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between remote socket and IO Root Complex 4.", + "EventCode": "0x91f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_read_data_beats_io_5", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between remote socket and IO Root Complex 5.", + "EventCode": "0x95f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_read_data_beats_io_6", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between remote socket and IO Root Complex 6.", + "EventCode": "0x99f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_read_data_beats_io_7", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between remote socket and IO Root Complex 7.", + "EventCode": "0x9df", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_write_data_beats_io_0", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between remote socket and IO Root Complex 0.", + "EventCode": "0x81f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_write_data_beats_io_1", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between remote socket and IO Root Complex 1.", + "EventCode": "0x85f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_write_data_beats_io_2", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between remote socket and IO Root Complex 2.", + "EventCode": "0x89f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_write_data_beats_io_3", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between remote socket and IO Root Complex 3.", + "EventCode": "0x8df", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_write_data_beats_io_4", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between remote socket and IO Root Complex 4.", + "EventCode": "0x91f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_write_data_beats_io_5", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between remote socket and IO Root Complex 5.", + "EventCode": "0x95f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_write_data_beats_io_6", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between remote socket and IO Root Complex 6.", + "EventCode": "0x99f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_upstream_write_data_beats_io_7", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between remote socket and IO Root Complex 7.", + "EventCode": "0x9df", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_read_data_beats_io_0", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 0.", + "EventCode": "0x81f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_read_data_beats_io_1", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 1.", + "EventCode": "0x85f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_read_data_beats_io_2", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 2.", + "EventCode": "0x89f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_read_data_beats_io_3", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 3.", + "EventCode": "0x8df", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_read_data_beats_io_4", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 4.", + "EventCode": "0x91f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_read_data_beats_io_5", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 5.", + "EventCode": "0x95f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_read_data_beats_io_6", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 6.", + "EventCode": "0x99f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_read_data_beats_io_7", + "PublicDescription": "Upstream DMA read data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 7.", + "EventCode": "0x9df", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_write_data_beats_io_0", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 0.", + "EventCode": "0x81f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_write_data_beats_io_1", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 1.", + "EventCode": "0x85f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_write_data_beats_io_2", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 2.", + "EventCode": "0x89f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_write_data_beats_io_3", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 3.", + "EventCode": "0x8df", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_write_data_beats_io_4", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 4.", + "EventCode": "0x91f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_write_data_beats_io_5", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 5.", + "EventCode": "0x95f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_write_data_beats_io_6", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 6.", + "EventCode": "0x99f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_upstream_write_data_beats_io_7", + "PublicDescription": "Upstream DMA write data beats (64 bytes) for transactions between local or remote socket and IO Root Complex 7.", + "EventCode": "0x9df", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_0", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 0.", + "EventCode": "0x41e", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_1", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 1.", + "EventCode": "0x45e", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_2", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 2.", + "EventCode": "0x49e", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_3", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 3.", + "EventCode": "0x4de", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_4", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 4.", + "EventCode": "0x51e", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_5", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 5.", + "EventCode": "0x55e", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_6", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 6.", + "EventCode": "0x59e", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_7", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 7.", + "EventCode": "0x5de", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_8", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 8.", + "EventCode": "0x41f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_9", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 9.", + "EventCode": "0x45f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_10", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 10.", + "EventCode": "0x49f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_11", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 11.", + "EventCode": "0x4df", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_12", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 12.", + "EventCode": "0x51f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_13", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 13.", + "EventCode": "0x55f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_14", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 14.", + "EventCode": "0x59f", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_cfi_15", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local socket and Core-to-Fabric Interface 15.", + "EventCode": "0x5df", + "UMask": "0x7fe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_0", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 0.", + "EventCode": "0x41e", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_1", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 1.", + "EventCode": "0x45e", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_2", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 2.", + "EventCode": "0x49e", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_3", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 3.", + "EventCode": "0x4de", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_4", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 4.", + "EventCode": "0x51e", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_5", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 5.", + "EventCode": "0x55e", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_6", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 6.", + "EventCode": "0x59e", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_7", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 7.", + "EventCode": "0x5de", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_8", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 8.", + "EventCode": "0x41f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_9", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 9.", + "EventCode": "0x45f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_10", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 10.", + "EventCode": "0x49f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_11", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 11.", + "EventCode": "0x4df", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_12", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 12.", + "EventCode": "0x51f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_13", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 13.", + "EventCode": "0x55f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_14", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 14.", + "EventCode": "0x59f", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_cfi_15", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and Core-to-Fabric Interface 15.", + "EventCode": "0x5df", + "UMask": "0x7ff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_0", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 0.", + "EventCode": "0x41e", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_1", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 1.", + "EventCode": "0x45e", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_2", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 2.", + "EventCode": "0x49e", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_3", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 3.", + "EventCode": "0x4de", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_4", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 4.", + "EventCode": "0x51e", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_5", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 5.", + "EventCode": "0x55e", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_6", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 6.", + "EventCode": "0x59e", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_7", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 7.", + "EventCode": "0x5de", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_8", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 8.", + "EventCode": "0x41f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_9", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 9.", + "EventCode": "0x45f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_10", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 10.", + "EventCode": "0x49f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_11", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 11.", + "EventCode": "0x4df", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_12", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 12.", + "EventCode": "0x51f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_13", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 13.", + "EventCode": "0x55f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_14", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 14.", + "EventCode": "0x59f", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_inbound_data_beats_cfi_15", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between remote socket and Core-to-Fabric Interface 15.", + "EventCode": "0x5df", + "UMask": "0xbfe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_0", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 0.", + "EventCode": "0x41e", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_1", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 1.", + "EventCode": "0x45e", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_2", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 2.", + "EventCode": "0x49e", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_3", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 3.", + "EventCode": "0x4de", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_4", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 4.", + "EventCode": "0x51e", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_5", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 5.", + "EventCode": "0x55e", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_6", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 6.", + "EventCode": "0x59e", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_7", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 7.", + "EventCode": "0x5de", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_8", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 8.", + "EventCode": "0x41f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_9", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 9.", + "EventCode": "0x45f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_10", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 10.", + "EventCode": "0x49f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_11", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 11.", + "EventCode": "0x4df", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_12", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 12.", + "EventCode": "0x51f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_13", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 13.", + "EventCode": "0x55f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_14", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 14.", + "EventCode": "0x59f", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "remote_socket_outbound_data_beats_cfi_15", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between remote socket and Core-to-Fabric Interface 15.", + "EventCode": "0x5df", + "UMask": "0xbff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_0", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 0.", + "EventCode": "0x41e", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_1", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 1.", + "EventCode": "0x45e", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_2", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 2.", + "EventCode": "0x49e", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_3", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 3.", + "EventCode": "0x4de", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_4", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 4.", + "EventCode": "0x51e", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_5", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 5.", + "EventCode": "0x55e", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_6", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 6.", + "EventCode": "0x59e", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_7", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 7.", + "EventCode": "0x5de", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_8", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 8.", + "EventCode": "0x41f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_9", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 9.", + "EventCode": "0x45f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_10", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 10.", + "EventCode": "0x49f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_11", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 11.", + "EventCode": "0x4df", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_12", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 12.", + "EventCode": "0x51f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_13", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 13.", + "EventCode": "0x55f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_14", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 14.", + "EventCode": "0x59f", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_inbound_data_beats_cfi_15", + "PublicDescription": "Inbound data beats (32 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 15.", + "EventCode": "0x5df", + "UMask": "0xffe", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_0", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 0.", + "EventCode": "0x41e", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_1", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 1.", + "EventCode": "0x45e", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_2", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 2.", + "EventCode": "0x49e", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_3", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 3.", + "EventCode": "0x4de", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_4", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 4.", + "EventCode": "0x51e", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_5", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 5.", + "EventCode": "0x55e", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_6", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 6.", + "EventCode": "0x59e", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_7", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 7.", + "EventCode": "0x5de", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_8", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 8.", + "EventCode": "0x41f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_9", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 9.", + "EventCode": "0x45f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_10", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 10.", + "EventCode": "0x49f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_11", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 11.", + "EventCode": "0x4df", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_12", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 12.", + "EventCode": "0x51f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_13", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 13.", + "EventCode": "0x55f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_14", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 14.", + "EventCode": "0x59f", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_or_remote_socket_outbound_data_beats_cfi_15", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local or remote socket and Core-to-Fabric Interface 15.", + "EventCode": "0x5df", + "UMask": "0xfff", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_link_0", + "PublicDescription": "Inbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 0.", + "EventCode": "0xd5f", + "UMask": "0xf3f", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_link_1", + "PublicDescription": "Inbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 1.", + "EventCode": "0xd9f", + "UMask": "0xf3f", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_link_2", + "PublicDescription": "Inbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 2.", + "EventCode": "0xddf", + "UMask": "0xf3f", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_link_3", + "PublicDescription": "Inbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 3.", + "EventCode": "0xe1f", + "UMask": "0xf3f", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_link_4", + "PublicDescription": "Inbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 4.", + "EventCode": "0xe5f", + "UMask": "0xf3f", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_inbound_data_beats_link_5", + "PublicDescription": "Inbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 5.", + "EventCode": "0xe9f", + "UMask": "0xf3f", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_link_0", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 0.", + "EventCode": "0xd5f", + "UMask": "0xf3e", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_link_1", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 1.", + "EventCode": "0xd9f", + "UMask": "0xf3e", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_link_2", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 2.", + "EventCode": "0xddf", + "UMask": "0xf3e", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_link_3", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 3.", + "EventCode": "0xe1f", + "UMask": "0xf3e", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_link_4", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 4.", + "EventCode": "0xe5f", + "UMask": "0xf3e", + "PerPkg": "1", + "Unit": "DFPMC" + }, + { + "EventName": "local_socket_outbound_data_beats_link_5", + "PublicDescription": "Outbound data beats (64 bytes) for transactions between local socket and remote socket over Cross-socket Link 5.", + "EventCode": "0xe9f", + "UMask": "0xf3e", + "PerPkg": "1", + "Unit": "DFPMC" + } +] diff --git a/tools/perf/pmu-events/arch/x86/amdzen5/load-store.json b/tools/perf/pmu-events/arch/x86/amdzen5/load-store.json index af2fdf1f55d649..ff6627a7780579 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen5/load-store.json +++ b/tools/perf/pmu-events/arch/x86/amdzen5/load-store.json @@ -96,6 +96,12 @@ "BriefDescription": "Demand data cache fills from L3 cache or different L2 cache in the same CCX.", "UMask": "0x02" }, + { + "EventName": "ls_dmnd_fills_from_sys.local_all", + "EventCode": "0x43", + "BriefDescription": "Demand data cache fills from local L2 cache, L3 cache or different L2 cache in the same CCX.", + "UMask": "0x03" + }, { "EventName": "ls_dmnd_fills_from_sys.near_cache", "EventCode": "0x43", @@ -114,12 +120,30 @@ "BriefDescription": "Demand data cache fills from cache of another CCX when the address was in a different NUMA node.", "UMask": "0x10" }, + { + "EventName": "ls_dmnd_fills_from_sys.remote_cache", + "EventCode": "0x43", + "BriefDescription": "Demand data cache fills from cache of another CCX when the address was in the same or a different NUMA node.", + "UMask": "0x14" + }, { "EventName": "ls_dmnd_fills_from_sys.dram_io_far", "EventCode": "0x43", "BriefDescription": "Demand data cache fills from either DRAM or MMIO in a different NUMA node (same or different socket).", "UMask": "0x40" }, + { + "EventName": "ls_dmnd_fills_from_sys.dram_io_all", + "EventCode": "0x43", + "BriefDescription": "Demand data cache fills from either DRAM or MMIO in the same or a different NUMA node (same or different socket).", + "UMask": "0x48" + }, + { + "EventName": "ls_dmnd_fills_from_sys.far_all", + "EventCode": "0x43", + "BriefDescription": "Demand data cache fills from either cache of another CCX, DRAM or MMIO when the address was in a different NUMA node (same or different socket).", + "UMask": "0x50" + }, { "EventName": "ls_dmnd_fills_from_sys.alternate_memories", "EventCode": "0x43", @@ -192,12 +216,6 @@ "BriefDescription": "Any data cache fills from either cache of another CCX, DRAM or MMIO when the address was in a different NUMA node (same or different socket).", "UMask": "0x50" }, - { - "EventName": "ls_any_fills_from_sys.all_dram_io", - "EventCode": "0x44", - "BriefDescription": "Any data cache fills from either DRAM or MMIO in any NUMA node (same or different socket).", - "UMask": "0x48" - }, { "EventName": "ls_any_fills_from_sys.alternate_memories", "EventCode": "0x44", @@ -342,6 +360,12 @@ "BriefDescription": "Software prefetch data cache fills from L3 cache or different L2 cache in the same CCX.", "UMask": "0x02" }, + { + "EventName": "ls_sw_pf_dc_fills.local_all", + "EventCode": "0x59", + "BriefDescription": "Software prefetch data cache fills from local L2 cache, L3 cache or different L2 cache in the same CCX.", + "UMask": "0x03" + }, { "EventName": "ls_sw_pf_dc_fills.near_cache", "EventCode": "0x59", @@ -360,12 +384,30 @@ "BriefDescription": "Software prefetch data cache fills from cache of another CCX in a different NUMA node.", "UMask": "0x10" }, + { + "EventName": "ls_sw_pf_dc_fills.remote_cache", + "EventCode": "0x59", + "BriefDescription": "Software prefetch data cache fills from cache of another CCX when the address was in the same or a different NUMA node.", + "UMask": "0x14" + }, { "EventName": "ls_sw_pf_dc_fills.dram_io_far", "EventCode": "0x59", "BriefDescription": "Software prefetch data cache fills from either DRAM or MMIO in a different NUMA node (same or different socket).", "UMask": "0x40" }, + { + "EventName": "ls_sw_pf_dc_fills.dram_io_all", + "EventCode": "0x59", + "BriefDescription": "Software prefetch data cache fills from either DRAM or MMIO in the same or a different NUMA node (same or different socket).", + "UMask": "0x48" + }, + { + "EventName": "ls_sw_pf_dc_fills.far_all", + "EventCode": "0x59", + "BriefDescription": "Software prefetch data cache fills from either cache of another CCX, DRAM or MMIO when the address was in a different NUMA node (same or different socket).", + "UMask": "0x50" + }, { "EventName": "ls_sw_pf_dc_fills.alternate_memories", "EventCode": "0x59", @@ -390,6 +432,12 @@ "BriefDescription": "Hardware prefetch data cache fills from L3 cache or different L2 cache in the same CCX.", "UMask": "0x02" }, + { + "EventName": "ls_hw_pf_dc_fills.local_all", + "EventCode": "0x5a", + "BriefDescription": "Hardware prefetch data cache fills from local L2 cache, L3 cache or different L2 cache in the same CCX.", + "UMask": "0x03" + }, { "EventName": "ls_hw_pf_dc_fills.near_cache", "EventCode": "0x5a", @@ -408,12 +456,30 @@ "BriefDescription": "Hardware prefetch data cache fills from cache of another CCX when the address was in a different NUMA node.", "UMask": "0x10" }, + { + "EventName": "ls_hw_pf_dc_fills.remote_cache", + "EventCode": "0x5a", + "BriefDescription": "Hardware prefetch data cache fills from cache of another CCX when the address was in the same or a different NUMA node.", + "UMask": "0x14" + }, { "EventName": "ls_hw_pf_dc_fills.dram_io_far", "EventCode": "0x5a", "BriefDescription": "Hardware prefetch data cache fills from either DRAM or MMIO in a different NUMA node (same or different socket).", "UMask": "0x40" }, + { + "EventName": "ls_hw_pf_dc_fills.dram_io_all", + "EventCode": "0x5a", + "BriefDescription": "Hardware prefetch data cache fills from either DRAM or MMIO in the same or a different NUMA node (same or different socket).", + "UMask": "0x48" + }, + { + "EventName": "ls_hw_pf_dc_fills.far_all", + "EventCode": "0x5a", + "BriefDescription": "Hardware prefetch data cache fills from either cache of another CCX, DRAM or MMIO when the address was in a different NUMA node (same or different socket).", + "UMask": "0x50" + }, { "EventName": "ls_hw_pf_dc_fills.alternate_memories", "EventCode": "0x5a", diff --git a/tools/perf/pmu-events/arch/x86/amdzen5/recommended.json b/tools/perf/pmu-events/arch/x86/amdzen5/recommended.json index c97874039c1e79..635d57e3bc151b 100644 --- a/tools/perf/pmu-events/arch/x86/amdzen5/recommended.json +++ b/tools/perf/pmu-events/arch/x86/amdzen5/recommended.json @@ -341,5 +341,117 @@ "MetricGroup": "memory_controller", "PerPkg": "1", "ScaleUnit": "1per_memclk" + }, + { + "MetricName": "dram_read_bandwidth_for_local_or_remote_socket", + "BriefDescription": "DRAM read data bandwidth for accesses in local or remote socket.", + "MetricExpr": "(local_or_remote_socket_read_data_beats_dram_0 + local_or_remote_socket_read_data_beats_dram_1 + local_or_remote_socket_read_data_beats_dram_2 + local_or_remote_socket_read_data_beats_dram_3 + local_or_remote_socket_read_data_beats_dram_4 + local_or_remote_socket_read_data_beats_dram_5 + local_or_remote_socket_read_data_beats_dram_6 + local_or_remote_socket_read_data_beats_dram_7 + local_or_remote_socket_read_data_beats_dram_8 + local_or_remote_socket_read_data_beats_dram_9 + local_or_remote_socket_read_data_beats_dram_10 + local_or_remote_socket_read_data_beats_dram_11) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "dram_write_bandwidth_for_local_socket", + "BriefDescription": "DRAM write data bandwidth for accesses in local socket.", + "MetricExpr": "(local_socket_write_data_beats_dram_0 + local_socket_write_data_beats_dram_1 + local_socket_write_data_beats_dram_2 + local_socket_write_data_beats_dram_3 + local_socket_write_data_beats_dram_4 + local_socket_write_data_beats_dram_5 + local_socket_write_data_beats_dram_6 + local_socket_write_data_beats_dram_7 + local_socket_write_data_beats_dram_8 + local_socket_write_data_beats_dram_9 + local_socket_write_data_beats_dram_10 + local_socket_write_data_beats_dram_11) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "dram_write_bandwidth_for_remote_socket", + "BriefDescription": "DRAM write data bandwidth for accesses in remote socket.", + "MetricExpr": "(remote_socket_write_data_beats_dram_0 + remote_socket_write_data_beats_dram_1 + remote_socket_write_data_beats_dram_2 + remote_socket_write_data_beats_dram_3 + remote_socket_write_data_beats_dram_4 + remote_socket_write_data_beats_dram_5 + remote_socket_write_data_beats_dram_6 + remote_socket_write_data_beats_dram_7 + remote_socket_write_data_beats_dram_8 + remote_socket_write_data_beats_dram_9 + remote_socket_write_data_beats_dram_10 + remote_socket_write_data_beats_dram_11) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "dram_write_bandwidth_for_local_or_remote_socket", + "BriefDescription": "DRAM write data bandwidth for accesses in local or remote socket.", + "MetricExpr": "(local_or_remote_socket_write_data_beats_dram_0 + local_or_remote_socket_write_data_beats_dram_1 + local_or_remote_socket_write_data_beats_dram_2 + local_or_remote_socket_write_data_beats_dram_3 + local_or_remote_socket_write_data_beats_dram_4 + local_or_remote_socket_write_data_beats_dram_5 + local_or_remote_socket_write_data_beats_dram_6 + local_or_remote_socket_write_data_beats_dram_7 + local_or_remote_socket_write_data_beats_dram_8 + local_or_remote_socket_write_data_beats_dram_9 + local_or_remote_socket_write_data_beats_dram_10 + local_or_remote_socket_write_data_beats_dram_11) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "upstream_dma_read_bandwidth_for_local_socket", + "BriefDescription": "Upstream DMA read data bandwidth for accesses in local socket.", + "MetricExpr": "(local_socket_upstream_read_data_beats_io_0 + local_socket_upstream_read_data_beats_io_1 + local_socket_upstream_read_data_beats_io_2 + local_socket_upstream_read_data_beats_io_3 + local_socket_upstream_read_data_beats_io_4 + local_socket_upstream_read_data_beats_io_5 + local_socket_upstream_read_data_beats_io_6 + local_socket_upstream_read_data_beats_io_7) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "upstream_dma_write_bandwidth_for_local_socket", + "BriefDescription": "Upstream DMA write data bandwidth for accesses in local socket.", + "MetricExpr": "(local_socket_upstream_write_data_beats_io_0 + local_socket_upstream_write_data_beats_io_1 + local_socket_upstream_write_data_beats_io_2 + local_socket_upstream_write_data_beats_io_3 + local_socket_upstream_write_data_beats_io_4 + local_socket_upstream_write_data_beats_io_5 + local_socket_upstream_write_data_beats_io_6 + local_socket_upstream_write_data_beats_io_7) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "upstream_dma_read_bandwidth_for_remote_socket", + "BriefDescription": "Upstream DMA read data bandwidth for accesses in remote socket.", + "MetricExpr": "(remote_socket_upstream_read_data_beats_io_0 + remote_socket_upstream_read_data_beats_io_1 + remote_socket_upstream_read_data_beats_io_2 + remote_socket_upstream_read_data_beats_io_3 + remote_socket_upstream_read_data_beats_io_4 + remote_socket_upstream_read_data_beats_io_5 + remote_socket_upstream_read_data_beats_io_6 + remote_socket_upstream_read_data_beats_io_7) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "upstream_dma_write_bandwidth_for_remote_socket", + "BriefDescription": "Upstream DMA write data bandwidth for accesses in remote socket.", + "MetricExpr": "(remote_socket_upstream_write_data_beats_io_0 + remote_socket_upstream_write_data_beats_io_1 + remote_socket_upstream_write_data_beats_io_2 + remote_socket_upstream_write_data_beats_io_3 + remote_socket_upstream_write_data_beats_io_4 + remote_socket_upstream_write_data_beats_io_5 + remote_socket_upstream_write_data_beats_io_6 + remote_socket_upstream_write_data_beats_io_7) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "core_inbound_data_bandwidth_for_local_socket", + "BriefDescription": "Core inbound data bandwidth for accesses in local socket.", + "MetricExpr": "(local_socket_inbound_data_beats_cfi_0 + local_socket_inbound_data_beats_cfi_1 + local_socket_inbound_data_beats_cfi_2 + local_socket_inbound_data_beats_cfi_3 + local_socket_inbound_data_beats_cfi_4 + local_socket_inbound_data_beats_cfi_5 + local_socket_inbound_data_beats_cfi_6 + local_socket_inbound_data_beats_cfi_7 + local_socket_inbound_data_beats_cfi_8 + local_socket_inbound_data_beats_cfi_9 + local_socket_inbound_data_beats_cfi_10 + local_socket_inbound_data_beats_cfi_11 + local_socket_inbound_data_beats_cfi_12 + local_socket_inbound_data_beats_cfi_13 + local_socket_inbound_data_beats_cfi_14 + local_socket_inbound_data_beats_cfi_15) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "3.2e-5MB/s" + }, + { + "MetricName": "core_outbound_data_bandwidth_for_local_socket", + "BriefDescription": "Core outbound data bandwidth for accesses in local socket.", + "MetricExpr": "(local_socket_outbound_data_beats_cfi_0 + local_socket_outbound_data_beats_cfi_1 + local_socket_outbound_data_beats_cfi_2 + local_socket_outbound_data_beats_cfi_3 + local_socket_outbound_data_beats_cfi_4 + local_socket_outbound_data_beats_cfi_5 + local_socket_outbound_data_beats_cfi_6 + local_socket_outbound_data_beats_cfi_7 + local_socket_outbound_data_beats_cfi_8 + local_socket_outbound_data_beats_cfi_9 + local_socket_outbound_data_beats_cfi_10 + local_socket_outbound_data_beats_cfi_11 + local_socket_outbound_data_beats_cfi_12 + local_socket_outbound_data_beats_cfi_13 + local_socket_outbound_data_beats_cfi_14 + local_socket_outbound_data_beats_cfi_15) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "core_inbound_data_bandwidth_for_remote_socket", + "BriefDescription": "Core inbound data bandwidth for accesses in remote socket.", + "MetricExpr": "(remote_socket_inbound_data_beats_cfi_0 + remote_socket_inbound_data_beats_cfi_1 + remote_socket_inbound_data_beats_cfi_2 + remote_socket_inbound_data_beats_cfi_3 + remote_socket_inbound_data_beats_cfi_4 + remote_socket_inbound_data_beats_cfi_5 + remote_socket_inbound_data_beats_cfi_6 + remote_socket_inbound_data_beats_cfi_7 + remote_socket_inbound_data_beats_cfi_8 + remote_socket_inbound_data_beats_cfi_9 + remote_socket_inbound_data_beats_cfi_10 + remote_socket_inbound_data_beats_cfi_11 + remote_socket_inbound_data_beats_cfi_12 + remote_socket_inbound_data_beats_cfi_13 + remote_socket_inbound_data_beats_cfi_14 + remote_socket_inbound_data_beats_cfi_15) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "3.2e-5MB/s" + }, + { + "MetricName": "core_outbound_data_bandwidth_for_remote_socket", + "BriefDescription": "Core outbound data bandwidth for accesses in remote socket.", + "MetricExpr": "(remote_socket_outbound_data_beats_cfi_0 + remote_socket_outbound_data_beats_cfi_1 + remote_socket_outbound_data_beats_cfi_2 + remote_socket_outbound_data_beats_cfi_3 + remote_socket_outbound_data_beats_cfi_4 + remote_socket_outbound_data_beats_cfi_5 + remote_socket_outbound_data_beats_cfi_6 + remote_socket_outbound_data_beats_cfi_7 + remote_socket_outbound_data_beats_cfi_8 + remote_socket_outbound_data_beats_cfi_9 + remote_socket_outbound_data_beats_cfi_10 + remote_socket_outbound_data_beats_cfi_11 + remote_socket_outbound_data_beats_cfi_12 + remote_socket_outbound_data_beats_cfi_13 + remote_socket_outbound_data_beats_cfi_14 + remote_socket_outbound_data_beats_cfi_15) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "cross_socket_inbound_data_bandwidth_for_local_socket", + "BriefDescription": "Inbound data bandwidth for accesses between local socket and remote socket.", + "MetricExpr": "(local_socket_inbound_data_beats_link_0 + local_socket_inbound_data_beats_link_1 + local_socket_inbound_data_beats_link_2 + local_socket_inbound_data_beats_link_3 + local_socket_inbound_data_beats_link_4 + local_socket_inbound_data_beats_link_5) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" + }, + { + "MetricName": "cross_socket_outbound_data_bandwidth_for_local_socket", + "BriefDescription": "Outbound data bandwidth for accesses between local socket and remote socket.", + "MetricExpr": "(local_socket_outbound_data_beats_link_0 + local_socket_outbound_data_beats_link_1 + local_socket_outbound_data_beats_link_2 + local_socket_outbound_data_beats_link_3 + local_socket_outbound_data_beats_link_4 + local_socket_outbound_data_beats_link_5) / duration_time", + "MetricGroup": "data_fabric", + "PerPkg": "1", + "ScaleUnit": "6.4e-5MB/s" } ] diff --git a/tools/perf/pmu-events/empty-pmu-events.c b/tools/perf/pmu-events/empty-pmu-events.c index c592079982fbd8..1c7a2cfa321fcd 100644 --- a/tools/perf/pmu-events/empty-pmu-events.c +++ b/tools/perf/pmu-events/empty-pmu-events.c @@ -19,72 +19,109 @@ struct pmu_table_entry { }; static const char *const big_c_string = -/* offset=0 */ "default_core\000" -/* offset=13 */ "bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000" -/* offset=72 */ "bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000" -/* offset=131 */ "l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000Attributable Level 3 cache access, read\000" -/* offset=226 */ "segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000" -/* offset=325 */ "dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000" -/* offset=455 */ "eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000" -/* offset=570 */ "hisi_sccl,ddrc\000" -/* offset=585 */ "uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000DDRC write commands\000" -/* offset=671 */ "uncore_cbox\000" -/* offset=683 */ "unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000" -/* offset=914 */ "event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000UNC_CBO_HYPHEN\000" -/* offset=979 */ "event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000UNC_CBO_TWO_HYPH\000" -/* offset=1050 */ "hisi_sccl,l3c\000" -/* offset=1064 */ "uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000Total read hits\000" -/* offset=1144 */ "uncore_imc_free_running\000" -/* offset=1168 */ "uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000Total cache misses\000" -/* offset=1263 */ "uncore_imc\000" -/* offset=1274 */ "uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000Total cache hits\000" -/* offset=1352 */ "uncore_sys_ddr_pmu\000" -/* offset=1371 */ "sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000" -/* offset=1444 */ "uncore_sys_ccn_pmu\000" -/* offset=1463 */ "sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000" -/* offset=1537 */ "uncore_sys_cmn_pmu\000" -/* offset=1556 */ "sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000" -/* offset=1696 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000" -/* offset=1718 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000" -/* offset=1781 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000" -/* offset=1947 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000" -/* offset=2011 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000" -/* offset=2078 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000" -/* offset=2149 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000" -/* offset=2243 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000" -/* offset=2377 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000" -/* offset=2441 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000" -/* offset=2509 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000" -/* offset=2579 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\00000" -/* offset=2601 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\00000" -/* offset=2623 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\00000" -/* offset=2643 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000" +/* offset=0 */ "tool\000" +/* offset=5 */ "duration_time\000tool\000Wall clock interval time in nanoseconds\000config=1\000\00000\000\000" +/* offset=78 */ "user_time\000tool\000User (non-kernel) time in nanoseconds\000config=2\000\00000\000\000" +/* offset=145 */ "system_time\000tool\000System/kernel time in nanoseconds\000config=3\000\00000\000\000" +/* offset=210 */ "has_pmem\000tool\0001 if persistent memory installed otherwise 0\000config=4\000\00000\000\000" +/* offset=283 */ "num_cores\000tool\000Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU\000config=5\000\00000\000\000" +/* offset=425 */ "num_cpus\000tool\000Number of logical Linux CPUs. There may be multiple such CPUs on a core\000config=6\000\00000\000\000" +/* offset=525 */ "num_cpus_online\000tool\000Number of online logical Linux CPUs. There may be multiple such CPUs on a core\000config=7\000\00000\000\000" +/* offset=639 */ "num_dies\000tool\000Number of dies. Each die has 1 or more cores\000config=8\000\00000\000\000" +/* offset=712 */ "num_packages\000tool\000Number of packages. Each package has 1 or more die\000config=9\000\00000\000\000" +/* offset=795 */ "slots\000tool\000Number of functional units that in parallel can execute parts of an instruction\000config=0xa\000\00000\000\000" +/* offset=902 */ "smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0\000config=0xb\000\00000\000\000" +/* offset=1006 */ "system_tsc_freq\000tool\000The amount a Time Stamp Counter (TSC) increases per second\000config=0xc\000\00000\000\000" +/* offset=1102 */ "default_core\000" +/* offset=1115 */ "bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000" +/* offset=1174 */ "bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000" +/* offset=1233 */ "l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000Attributable Level 3 cache access, read\000" +/* offset=1328 */ "segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000" +/* offset=1427 */ "dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000" +/* offset=1557 */ "eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000" +/* offset=1672 */ "hisi_sccl,ddrc\000" +/* offset=1687 */ "uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000DDRC write commands\000" +/* offset=1773 */ "uncore_cbox\000" +/* offset=1785 */ "unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000" +/* offset=2016 */ "event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000UNC_CBO_HYPHEN\000" +/* offset=2081 */ "event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000UNC_CBO_TWO_HYPH\000" +/* offset=2152 */ "hisi_sccl,l3c\000" +/* offset=2166 */ "uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000Total read hits\000" +/* offset=2246 */ "uncore_imc_free_running\000" +/* offset=2270 */ "uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000Total cache misses\000" +/* offset=2365 */ "uncore_imc\000" +/* offset=2376 */ "uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000Total cache hits\000" +/* offset=2454 */ "uncore_sys_ddr_pmu\000" +/* offset=2473 */ "sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000" +/* offset=2546 */ "uncore_sys_ccn_pmu\000" +/* offset=2565 */ "sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000" +/* offset=2639 */ "uncore_sys_cmn_pmu\000" +/* offset=2658 */ "sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000" +/* offset=2798 */ "CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000" +/* offset=2820 */ "IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000" +/* offset=2883 */ "Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000" +/* offset=3049 */ "dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000" +/* offset=3113 */ "icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000" +/* offset=3180 */ "cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000" +/* offset=3251 */ "DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000" +/* offset=3345 */ "DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000" +/* offset=3479 */ "DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000" +/* offset=3543 */ "DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000" +/* offset=3611 */ "DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000" +/* offset=3681 */ "M1\000\000ipc + M2\000\000\000\000\000\000\000\00000" +/* offset=3703 */ "M2\000\000ipc + M1\000\000\000\000\000\000\000\00000" +/* offset=3725 */ "M3\000\0001 / M3\000\000\000\000\000\000\000\00000" +/* offset=3745 */ "L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000" ; +static const struct compact_pmu_event pmu_events__common_tool[] = { +{ 5 }, /* duration_time\000tool\000Wall clock interval time in nanoseconds\000config=1\000\00000\000\000 */ +{ 210 }, /* has_pmem\000tool\0001 if persistent memory installed otherwise 0\000config=4\000\00000\000\000 */ +{ 283 }, /* num_cores\000tool\000Number of cores. A core consists of 1 or more thread, with each thread being associated with a logical Linux CPU\000config=5\000\00000\000\000 */ +{ 425 }, /* num_cpus\000tool\000Number of logical Linux CPUs. There may be multiple such CPUs on a core\000config=6\000\00000\000\000 */ +{ 525 }, /* num_cpus_online\000tool\000Number of online logical Linux CPUs. There may be multiple such CPUs on a core\000config=7\000\00000\000\000 */ +{ 639 }, /* num_dies\000tool\000Number of dies. Each die has 1 or more cores\000config=8\000\00000\000\000 */ +{ 712 }, /* num_packages\000tool\000Number of packages. Each package has 1 or more die\000config=9\000\00000\000\000 */ +{ 795 }, /* slots\000tool\000Number of functional units that in parallel can execute parts of an instruction\000config=0xa\000\00000\000\000 */ +{ 902 }, /* smt_on\000tool\0001 if simultaneous multithreading (aka hyperthreading) is enable otherwise 0\000config=0xb\000\00000\000\000 */ +{ 145 }, /* system_time\000tool\000System/kernel time in nanoseconds\000config=3\000\00000\000\000 */ +{ 1006 }, /* system_tsc_freq\000tool\000The amount a Time Stamp Counter (TSC) increases per second\000config=0xc\000\00000\000\000 */ +{ 78 }, /* user_time\000tool\000User (non-kernel) time in nanoseconds\000config=2\000\00000\000\000 */ + +}; + +const struct pmu_table_entry pmu_events__common[] = { +{ + .entries = pmu_events__common_tool, + .num_entries = ARRAY_SIZE(pmu_events__common_tool), + .pmu_name = { 0 /* tool\000 */ }, +}, +}; + static const struct compact_pmu_event pmu_events__test_soc_cpu_default_core[] = { -{ 13 }, /* bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000 */ -{ 72 }, /* bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000 */ -{ 325 }, /* dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000 */ -{ 455 }, /* eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000 */ -{ 131 }, /* l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000Attributable Level 3 cache access, read\000 */ -{ 226 }, /* segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000 */ +{ 1115 }, /* bp_l1_btb_correct\000branch\000L1 BTB Correction\000event=0x8a\000\00000\000\000 */ +{ 1174 }, /* bp_l2_btb_correct\000branch\000L2 BTB Correction\000event=0x8b\000\00000\000\000 */ +{ 1427 }, /* dispatch_blocked.any\000other\000Memory cluster signals to block micro-op dispatch for any reason\000event=9,period=200000,umask=0x20\000\00000\000\000 */ +{ 1557 }, /* eist_trans\000other\000Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions\000event=0x3a,period=200000\000\00000\000\000 */ +{ 1233 }, /* l3_cache_rd\000cache\000L3 cache access, read\000event=0x40\000\00000\000Attributable Level 3 cache access, read\000 */ +{ 1328 }, /* segment_reg_loads.any\000other\000Number of segment register loads\000event=6,period=200000,umask=0x80\000\00000\000\000 */ }; static const struct compact_pmu_event pmu_events__test_soc_cpu_hisi_sccl_ddrc[] = { -{ 585 }, /* uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000DDRC write commands\000 */ +{ 1687 }, /* uncore_hisi_ddrc.flux_wcmd\000uncore\000DDRC write commands\000event=2\000\00000\000DDRC write commands\000 */ }; static const struct compact_pmu_event pmu_events__test_soc_cpu_hisi_sccl_l3c[] = { -{ 1064 }, /* uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000Total read hits\000 */ +{ 2166 }, /* uncore_hisi_l3c.rd_hit_cpipe\000uncore\000Total read hits\000event=7\000\00000\000Total read hits\000 */ }; static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_cbox[] = { -{ 914 }, /* event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000UNC_CBO_HYPHEN\000 */ -{ 979 }, /* event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000UNC_CBO_TWO_HYPH\000 */ -{ 683 }, /* unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000 */ +{ 2016 }, /* event-hyphen\000uncore\000UNC_CBO_HYPHEN\000event=0xe0\000\00000\000UNC_CBO_HYPHEN\000 */ +{ 2081 }, /* event-two-hyph\000uncore\000UNC_CBO_TWO_HYPH\000event=0xc0\000\00000\000UNC_CBO_TWO_HYPH\000 */ +{ 1785 }, /* unc_cbo_xsnp_response.miss_eviction\000uncore\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000event=0x22,umask=0x81\000\00000\000A cross-core snoop resulted from L3 Eviction which misses in some processor core\000 */ }; static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_imc[] = { -{ 1274 }, /* uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000Total cache hits\000 */ +{ 2376 }, /* uncore_imc.cache_hits\000uncore\000Total cache hits\000event=0x34\000\00000\000Total cache hits\000 */ }; static const struct compact_pmu_event pmu_events__test_soc_cpu_uncore_imc_free_running[] = { -{ 1168 }, /* uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000Total cache misses\000 */ +{ 2270 }, /* uncore_imc_free_running.cache_miss\000uncore\000Total cache misses\000event=0x12\000\00000\000Total cache misses\000 */ }; @@ -92,51 +129,51 @@ const struct pmu_table_entry pmu_events__test_soc_cpu[] = { { .entries = pmu_events__test_soc_cpu_default_core, .num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_default_core), - .pmu_name = { 0 /* default_core\000 */ }, + .pmu_name = { 1102 /* default_core\000 */ }, }, { .entries = pmu_events__test_soc_cpu_hisi_sccl_ddrc, .num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_hisi_sccl_ddrc), - .pmu_name = { 570 /* hisi_sccl,ddrc\000 */ }, + .pmu_name = { 1672 /* hisi_sccl,ddrc\000 */ }, }, { .entries = pmu_events__test_soc_cpu_hisi_sccl_l3c, .num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_hisi_sccl_l3c), - .pmu_name = { 1050 /* hisi_sccl,l3c\000 */ }, + .pmu_name = { 2152 /* hisi_sccl,l3c\000 */ }, }, { .entries = pmu_events__test_soc_cpu_uncore_cbox, .num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_cbox), - .pmu_name = { 671 /* uncore_cbox\000 */ }, + .pmu_name = { 1773 /* uncore_cbox\000 */ }, }, { .entries = pmu_events__test_soc_cpu_uncore_imc, .num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_imc), - .pmu_name = { 1263 /* uncore_imc\000 */ }, + .pmu_name = { 2365 /* uncore_imc\000 */ }, }, { .entries = pmu_events__test_soc_cpu_uncore_imc_free_running, .num_entries = ARRAY_SIZE(pmu_events__test_soc_cpu_uncore_imc_free_running), - .pmu_name = { 1144 /* uncore_imc_free_running\000 */ }, + .pmu_name = { 2246 /* uncore_imc_free_running\000 */ }, }, }; static const struct compact_pmu_event pmu_metrics__test_soc_cpu_default_core[] = { -{ 1696 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000 */ -{ 2377 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000 */ -{ 2149 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000 */ -{ 2243 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000 */ -{ 2441 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000 */ -{ 2509 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000 */ -{ 1781 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000 */ -{ 1718 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000 */ -{ 2643 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000 */ -{ 2579 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\00000 */ -{ 2601 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\00000 */ -{ 2623 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\00000 */ -{ 2078 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000 */ -{ 1947 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */ -{ 2011 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */ +{ 2798 }, /* CPI\000\0001 / IPC\000\000\000\000\000\000\000\00000 */ +{ 3479 }, /* DCache_L2_All\000\000DCache_L2_All_Hits + DCache_L2_All_Miss\000\000\000\000\000\000\000\00000 */ +{ 3251 }, /* DCache_L2_All_Hits\000\000l2_rqsts.demand_data_rd_hit + l2_rqsts.pf_hit + l2_rqsts.rfo_hit\000\000\000\000\000\000\000\00000 */ +{ 3345 }, /* DCache_L2_All_Miss\000\000max(l2_rqsts.all_demand_data_rd - l2_rqsts.demand_data_rd_hit, 0) + l2_rqsts.pf_miss + l2_rqsts.rfo_miss\000\000\000\000\000\000\000\00000 */ +{ 3543 }, /* DCache_L2_Hits\000\000d_ratio(DCache_L2_All_Hits, DCache_L2_All)\000\000\000\000\000\000\000\00000 */ +{ 3611 }, /* DCache_L2_Misses\000\000d_ratio(DCache_L2_All_Miss, DCache_L2_All)\000\000\000\000\000\000\000\00000 */ +{ 2883 }, /* Frontend_Bound_SMT\000\000idq_uops_not_delivered.core / (4 * (cpu_clk_unhalted.thread / 2 * (1 + cpu_clk_unhalted.one_thread_active / cpu_clk_unhalted.ref_xclk)))\000\000\000\000\000\000\000\00000 */ +{ 2820 }, /* IPC\000group1\000inst_retired.any / cpu_clk_unhalted.thread\000\000\000\000\000\000\000\00000 */ +{ 3745 }, /* L1D_Cache_Fill_BW\000\00064 * l1d.replacement / 1e9 / duration_time\000\000\000\000\000\000\000\00000 */ +{ 3681 }, /* M1\000\000ipc + M2\000\000\000\000\000\000\000\00000 */ +{ 3703 }, /* M2\000\000ipc + M1\000\000\000\000\000\000\000\00000 */ +{ 3725 }, /* M3\000\0001 / M3\000\000\000\000\000\000\000\00000 */ +{ 3180 }, /* cache_miss_cycles\000group1\000dcache_miss_cpi + icache_miss_cycles\000\000\000\000\000\000\000\00000 */ +{ 3049 }, /* dcache_miss_cpi\000\000l1d\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */ +{ 3113 }, /* icache_miss_cycles\000\000l1i\\-loads\\-misses / inst_retired.any\000\000\000\000\000\000\000\00000 */ }; @@ -144,18 +181,18 @@ const struct pmu_table_entry pmu_metrics__test_soc_cpu[] = { { .entries = pmu_metrics__test_soc_cpu_default_core, .num_entries = ARRAY_SIZE(pmu_metrics__test_soc_cpu_default_core), - .pmu_name = { 0 /* default_core\000 */ }, + .pmu_name = { 1102 /* default_core\000 */ }, }, }; static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_ccn_pmu[] = { -{ 1463 }, /* sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000 */ +{ 2565 }, /* sys_ccn_pmu.read_cycles\000uncore\000ccn read-cycles event\000config=0x2c\0000x01\00000\000\000 */ }; static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_cmn_pmu[] = { -{ 1556 }, /* sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000 */ +{ 2658 }, /* sys_cmn_pmu.hnf_cache_miss\000uncore\000Counts total cache misses in first lookup result (high priority)\000eventid=1,type=5\000(434|436|43c|43a).*\00000\000\000 */ }; static const struct compact_pmu_event pmu_events__test_soc_sys_uncore_sys_ddr_pmu[] = { -{ 1371 }, /* sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000 */ +{ 2473 }, /* sys_ddr_pmu.write_cycles\000uncore\000ddr write-cycles event\000event=0x2b\000v8\00000\000\000 */ }; @@ -163,17 +200,17 @@ const struct pmu_table_entry pmu_events__test_soc_sys[] = { { .entries = pmu_events__test_soc_sys_uncore_sys_ccn_pmu, .num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_ccn_pmu), - .pmu_name = { 1444 /* uncore_sys_ccn_pmu\000 */ }, + .pmu_name = { 2546 /* uncore_sys_ccn_pmu\000 */ }, }, { .entries = pmu_events__test_soc_sys_uncore_sys_cmn_pmu, .num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_cmn_pmu), - .pmu_name = { 1537 /* uncore_sys_cmn_pmu\000 */ }, + .pmu_name = { 2639 /* uncore_sys_cmn_pmu\000 */ }, }, { .entries = pmu_events__test_soc_sys_uncore_sys_ddr_pmu, .num_entries = ARRAY_SIZE(pmu_events__test_soc_sys_uncore_sys_ddr_pmu), - .pmu_name = { 1352 /* uncore_sys_ddr_pmu\000 */ }, + .pmu_name = { 2454 /* uncore_sys_ddr_pmu\000 */ }, }, }; @@ -210,6 +247,15 @@ struct pmu_events_map { * table of PMU events. */ const struct pmu_events_map pmu_events_map[] = { +{ + .arch = "common", + .cpuid = "common", + .event_table = { + .pmus = pmu_events__common, + .num_pmus = ARRAY_SIZE(pmu_events__common), + }, + .metric_table = {}, +}, { .arch = "testarch", .cpuid = "testcpu", @@ -380,7 +426,7 @@ int pmu_events_table__for_each_event(const struct pmu_events_table *table, continue; ret = pmu_events_table__for_each_event_pmu(table, table_pmu, fn, data); - if (pmu || ret) + if (ret) return ret; } return 0; @@ -457,11 +503,11 @@ int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, return 0; } -static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu) +static const struct pmu_events_map *map_for_cpu(struct perf_cpu cpu) { static struct { const struct pmu_events_map *map; - struct perf_pmu *pmu; + struct perf_cpu cpu; } last_result; static struct { const struct pmu_events_map *map; @@ -472,10 +518,10 @@ static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu) char *cpuid = NULL; size_t i; - if (has_last_result && last_result.pmu == pmu) + if (has_last_result && last_result.cpu.cpu == cpu.cpu) return last_result.map; - cpuid = perf_pmu__getcpuid(pmu); + cpuid = get_cpuid_allow_env_override(cpu); /* * On some platforms which uses cpus map, cpuid can be NULL for @@ -506,12 +552,21 @@ static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu) has_last_map_search = true; } out_update_last_result: - last_result.pmu = pmu; + last_result.cpu = cpu; last_result.map = map; has_last_result = true; return map; } +static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu) +{ + struct perf_cpu cpu = {-1}; + + if (pmu) + cpu = perf_cpu_map__min(pmu->cpus); + return map_for_cpu(cpu); +} + const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu) { const struct pmu_events_map *map = map_for_pmu(pmu); @@ -532,24 +587,12 @@ const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu) return NULL; } -const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu) +const struct pmu_metrics_table *pmu_metrics_table__find(void) { - const struct pmu_events_map *map = map_for_pmu(pmu); - - if (!map) - return NULL; + struct perf_cpu cpu = {-1}; + const struct pmu_events_map *map = map_for_cpu(cpu); - if (!pmu) - return &map->metric_table; - - for (size_t i = 0; i < map->metric_table.num_pmus; i++) { - const struct pmu_table_entry *table_pmu = &map->metric_table.pmus[i]; - const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset]; - - if (pmu__name_match(pmu, pmu_name)) - return &map->metric_table; - } - return NULL; + return map ? &map->metric_table : NULL; } const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid) diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py index bb0a5d92df4a15..d781a377757a1b 100755 --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py @@ -292,6 +292,7 @@ class JsonEvent: 'cpu_atom': 'cpu_atom', 'ali_drw': 'ali_drw', 'arm_cmn': 'arm_cmn', + 'tool': 'tool', } return table[unit] if unit in table else f'uncore_{unit.lower()}' @@ -721,6 +722,17 @@ const struct pmu_events_map pmu_events_map[] = { \t\t.num_pmus = ARRAY_SIZE(pmu_metrics__test_soc_cpu), \t} }, +""") + elif arch == 'common': + _args.output_file.write("""{ +\t.arch = "common", +\t.cpuid = "common", +\t.event_table = { +\t\t.pmus = pmu_events__common, +\t\t.num_pmus = ARRAY_SIZE(pmu_events__common), +\t}, +\t.metric_table = {}, +}, """) else: with open(f'{_args.starting_dir}/{arch}/mapfile.csv') as csvfile: @@ -930,7 +942,7 @@ int pmu_events_table__for_each_event(const struct pmu_events_table *table, continue; ret = pmu_events_table__for_each_event_pmu(table, table_pmu, fn, data); - if (pmu || ret) + if (ret) return ret; } return 0; @@ -1007,11 +1019,11 @@ int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, return 0; } -static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu) +static const struct pmu_events_map *map_for_cpu(struct perf_cpu cpu) { static struct { const struct pmu_events_map *map; - struct perf_pmu *pmu; + struct perf_cpu cpu; } last_result; static struct { const struct pmu_events_map *map; @@ -1022,10 +1034,10 @@ static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu) char *cpuid = NULL; size_t i; - if (has_last_result && last_result.pmu == pmu) + if (has_last_result && last_result.cpu.cpu == cpu.cpu) return last_result.map; - cpuid = perf_pmu__getcpuid(pmu); + cpuid = get_cpuid_allow_env_override(cpu); /* * On some platforms which uses cpus map, cpuid can be NULL for @@ -1056,12 +1068,21 @@ static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu) has_last_map_search = true; } out_update_last_result: - last_result.pmu = pmu; + last_result.cpu = cpu; last_result.map = map; has_last_result = true; return map; } +static const struct pmu_events_map *map_for_pmu(struct perf_pmu *pmu) +{ + struct perf_cpu cpu = {-1}; + + if (pmu) + cpu = perf_cpu_map__min(pmu->cpus); + return map_for_cpu(cpu); +} + const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu) { const struct pmu_events_map *map = map_for_pmu(pmu); @@ -1082,24 +1103,12 @@ const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu) return NULL; } -const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu) +const struct pmu_metrics_table *pmu_metrics_table__find(void) { - const struct pmu_events_map *map = map_for_pmu(pmu); - - if (!map) - return NULL; - - if (!pmu) - return &map->metric_table; + struct perf_cpu cpu = {-1}; + const struct pmu_events_map *map = map_for_cpu(cpu); - for (size_t i = 0; i < map->metric_table.num_pmus; i++) { - const struct pmu_table_entry *table_pmu = &map->metric_table.pmus[i]; - const char *pmu_name = &big_c_string[table_pmu->pmu_name.offset]; - - if (pmu__name_match(pmu, pmu_name)) - return &map->metric_table; - } - return NULL; + return map ? &map->metric_table : NULL; } const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid) @@ -1241,7 +1250,7 @@ def main() -> None: if len(parents) == _args.model.split(',')[0].count('/'): # We're testing the correct directory. item_path = '/'.join(parents) + ('/' if len(parents) > 0 else '') + item.name - if 'test' not in item_path and item_path not in _args.model.split(','): + if 'test' not in item_path and 'common' not in item_path and item_path not in _args.model.split(','): continue action(parents, item) if item.is_dir(): @@ -1289,7 +1298,7 @@ struct pmu_table_entry { for item in os.scandir(_args.starting_dir): if not item.is_dir(): continue - if item.name == _args.arch or _args.arch == 'all' or item.name == 'test': + if item.name == _args.arch or _args.arch == 'all' or item.name == 'test' or item.name == 'common': archs.append(item.name) if len(archs) < 2 and _args.arch != 'none': diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h index 5435ad92180cf3..675562e6f7704e 100644 --- a/tools/perf/pmu-events/pmu-events.h +++ b/tools/perf/pmu-events/pmu-events.h @@ -103,7 +103,7 @@ int pmu_metrics_table__for_each_metric(const struct pmu_metrics_table *table, pm void *data); const struct pmu_events_table *perf_pmu__find_events_table(struct perf_pmu *pmu); -const struct pmu_metrics_table *perf_pmu__find_metrics_table(struct perf_pmu *pmu); +const struct pmu_metrics_table *pmu_metrics_table__find(void); const struct pmu_events_table *find_core_events_table(const char *arch, const char *cpuid); const struct pmu_metrics_table *find_core_metrics_table(const char *arch, const char *cpuid); int pmu_for_each_core_event(pmu_event_iter_fn fn, void *data); diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c index 3954bd1587ce95..01f54d6724a5f8 100644 --- a/tools/perf/scripts/python/Perf-Trace-Util/Context.c +++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c @@ -12,6 +12,7 @@ #define PY_SSIZE_T_CLEAN #include +#include "../../../util/config.h" #include "../../../util/trace-event.h" #include "../../../util/event.h" #include "../../../util/symbol.h" @@ -182,6 +183,15 @@ static PyObject *perf_sample_srccode(PyObject *obj, PyObject *args) return perf_sample_src(obj, args, true); } +static PyObject *__perf_config_get(PyObject *obj, PyObject *args) +{ + const char *config_name; + + if (!PyArg_ParseTuple(args, "s", &config_name)) + return NULL; + return Py_BuildValue("s", perf_config_get(config_name)); +} + static PyMethodDef ContextMethods[] = { #ifdef HAVE_LIBTRACEEVENT { "common_pc", perf_trace_context_common_pc, METH_VARARGS, @@ -199,6 +209,7 @@ static PyMethodDef ContextMethods[] = { METH_VARARGS, "Get source file name and line number."}, { "perf_sample_srccode", perf_sample_srccode, METH_VARARGS, "Get source file name, line number and line."}, + { "perf_config_get", __perf_config_get, METH_VARARGS, "Get perf config entry"}, { NULL, NULL, 0, NULL} }; diff --git a/tools/perf/scripts/python/arm-cs-trace-disasm.py b/tools/perf/scripts/python/arm-cs-trace-disasm.py index 7aff02d84ffb3b..ba208c90d63110 100755 --- a/tools/perf/scripts/python/arm-cs-trace-disasm.py +++ b/tools/perf/scripts/python/arm-cs-trace-disasm.py @@ -11,36 +11,74 @@ import os from os import path import re from subprocess import * -from optparse import OptionParser, make_option +import argparse +import platform -from perf_trace_context import perf_set_itrace_options, \ - perf_sample_insn, perf_sample_srccode +from perf_trace_context import perf_sample_srccode, perf_config_get # Below are some example commands for using this script. +# Note a --kcore recording is required for accurate decode +# due to the alternatives patching mechanism. However this +# script only supports reading vmlinux for disassembly dump, +# meaning that any patched instructions will appear +# as unpatched, but the instruction ranges themselves will +# be correct. In addition to this, source line info comes +# from Perf, and when using kcore there is no debug info. The +# following lists the supported features in each mode: +# +# +-----------+-----------------+------------------+------------------+ +# | Recording | Accurate decode | Source line dump | Disassembly dump | +# +-----------+-----------------+------------------+------------------+ +# | --kcore | yes | no | yes | +# | normal | no | yes | yes | +# +-----------+-----------------+------------------+------------------+ +# +# Output disassembly with objdump and auto detect vmlinux +# (when running on same machine.) +# perf script -s scripts/python/arm-cs-trace-disasm.py -d # -# Output disassembly with objdump: -# perf script -s scripts/python/arm-cs-trace-disasm.py \ -# -- -d objdump -k path/to/vmlinux # Output disassembly with llvm-objdump: # perf script -s scripts/python/arm-cs-trace-disasm.py \ # -- -d llvm-objdump-11 -k path/to/vmlinux +# # Output only source line and symbols: # perf script -s scripts/python/arm-cs-trace-disasm.py -# Command line parsing. -option_list = [ - # formatting options for the bottom entry of the stack - make_option("-k", "--vmlinux", dest="vmlinux_name", - help="Set path to vmlinux file"), - make_option("-d", "--objdump", dest="objdump_name", - help="Set path to objdump executable file"), - make_option("-v", "--verbose", dest="verbose", - action="store_true", default=False, - help="Enable debugging log") -] +def default_objdump(): + config = perf_config_get("annotate.objdump") + return config if config else "objdump" -parser = OptionParser(option_list=option_list) -(options, args) = parser.parse_args() +# Command line parsing. +def int_arg(v): + v = int(v) + if v < 0: + raise argparse.ArgumentTypeError("Argument must be a positive integer") + return v + +args = argparse.ArgumentParser() +args.add_argument("-k", "--vmlinux", + help="Set path to vmlinux file. Omit to autodetect if running on same machine") +args.add_argument("-d", "--objdump", nargs="?", const=default_objdump(), + help="Show disassembly. Can also be used to change the objdump path"), +args.add_argument("-v", "--verbose", action="store_true", help="Enable debugging log") +args.add_argument("--start-time", type=int_arg, help="Monotonic clock time of sample to start from. " + "See 'time' field on samples in -v mode.") +args.add_argument("--stop-time", type=int_arg, help="Monotonic clock time of sample to stop at. " + "See 'time' field on samples in -v mode.") +args.add_argument("--start-sample", type=int_arg, help="Index of sample to start from. " + "See 'index' field on samples in -v mode.") +args.add_argument("--stop-sample", type=int_arg, help="Index of sample to stop at. " + "See 'index' field on samples in -v mode.") + +options = args.parse_args() +if (options.start_time and options.stop_time and + options.start_time >= options.stop_time): + print("--start-time must less than --stop-time") + exit(2) +if (options.start_sample and options.stop_sample and + options.start_sample >= options.stop_sample): + print("--start-sample must less than --stop-sample") + exit(2) # Initialize global dicts and regular expression disasm_cache = dict() @@ -48,11 +86,23 @@ cpu_data = dict() disasm_re = re.compile(r"^\s*([0-9a-fA-F]+):") disasm_func_re = re.compile(r"^\s*([0-9a-fA-F]+)\s.*:") cache_size = 64*1024 +sample_idx = -1 glb_source_file_name = None glb_line_number = None glb_dso = None +kver = platform.release() +vmlinux_paths = [ + f"/usr/lib/debug/boot/vmlinux-{kver}.debug", + f"/usr/lib/debug/lib/modules/{kver}/vmlinux", + f"/lib/modules/{kver}/build/vmlinux", + f"/usr/lib/debug/boot/vmlinux-{kver}", + f"/boot/vmlinux-{kver}", + f"/boot/vmlinux", + f"vmlinux" +] + def get_optional(perf_dict, field): if field in perf_dict: return perf_dict[field] @@ -63,12 +113,25 @@ def get_offset(perf_dict, field): return "+%#x" % perf_dict[field] return "" +def find_vmlinux(): + if hasattr(find_vmlinux, "path"): + return find_vmlinux.path + + for v in vmlinux_paths: + if os.access(v, os.R_OK): + find_vmlinux.path = v + break + else: + find_vmlinux.path = None + + return find_vmlinux.path + def get_dso_file_path(dso_name, dso_build_id): if (dso_name == "[kernel.kallsyms]" or dso_name == "vmlinux"): - if (options.vmlinux_name): - return options.vmlinux_name; + if (options.vmlinux): + return options.vmlinux; else: - return dso_name + return find_vmlinux() if find_vmlinux() else dso_name if (dso_name == "[vdso]") : append = "/vdso" @@ -92,7 +155,7 @@ def read_disam(dso_fname, dso_start, start_addr, stop_addr): else: start_addr = start_addr - dso_start; stop_addr = stop_addr - dso_start; - disasm = [ options.objdump_name, "-d", "-z", + disasm = [ options.objdump, "-d", "-z", "--start-address="+format(start_addr,"#x"), "--stop-address="+format(stop_addr,"#x") ] disasm += [ dso_fname ] @@ -112,10 +175,10 @@ def print_disam(dso_fname, dso_start, start_addr, stop_addr): def print_sample(sample): print("Sample = { cpu: %04d addr: 0x%016x phys_addr: 0x%016x ip: 0x%016x " \ - "pid: %d tid: %d period: %d time: %d }" % \ + "pid: %d tid: %d period: %d time: %d index: %d}" % \ (sample['cpu'], sample['addr'], sample['phys_addr'], \ sample['ip'], sample['pid'], sample['tid'], \ - sample['period'], sample['time'])) + sample['period'], sample['time'], sample_idx)) def trace_begin(): print('ARM CoreSight Trace Data Assembler Dump') @@ -177,6 +240,7 @@ def print_srccode(comm, param_dict, sample, symbol, dso): def process_event(param_dict): global cache_size global options + global sample_idx sample = param_dict["sample"] comm = param_dict["comm"] @@ -187,11 +251,26 @@ def process_event(param_dict): dso_start = get_optional(param_dict, "dso_map_start") dso_end = get_optional(param_dict, "dso_map_end") symbol = get_optional(param_dict, "symbol") + map_pgoff = get_optional(param_dict, "map_pgoff") + # check for valid map offset + if (str(map_pgoff) == '[unknown]'): + map_pgoff = 0 cpu = sample["cpu"] ip = sample["ip"] addr = sample["addr"] + sample_idx += 1 + + if (options.start_time and sample["time"] < options.start_time): + return + if (options.stop_time and sample["time"] > options.stop_time): + exit(0) + if (options.start_sample and sample_idx < options.start_sample): + return + if (options.stop_sample and sample_idx > options.stop_sample): + exit(0) + if (options.verbose == True): print("Event type: %s" % name) print_sample(sample) @@ -243,9 +322,10 @@ def process_event(param_dict): # Record for previous sample packet cpu_data[str(cpu) + 'addr'] = addr - # Handle CS_ETM_TRACE_ON packet if start_addr=0 and stop_addr=4 - if (start_addr == 0 and stop_addr == 4): - print("CPU%d: CS_ETM_TRACE_ON packet is inserted" % cpu) + # Filter out zero start_address. Optionally identify CS_ETM_TRACE_ON packet + if (start_addr == 0): + if ((stop_addr == 4) and (options.verbose == True)): + print("CPU%d: CS_ETM_TRACE_ON packet is inserted" % cpu) return if (start_addr < int(dso_start) or start_addr > int(dso_end)): @@ -256,19 +336,20 @@ def process_event(param_dict): print("Stop address 0x%x is out of range [ 0x%x .. 0x%x ] for dso %s" % (stop_addr, int(dso_start), int(dso_end), dso)) return - if (options.objdump_name != None): + if (options.objdump != None): # It doesn't need to decrease virtual memory offset for disassembly # for kernel dso and executable file dso, so in this case we set # vm_start to zero. if (dso == "[kernel.kallsyms]" or dso_start == 0x400000): dso_vm_start = 0 + map_pgoff = 0 else: dso_vm_start = int(dso_start) dso_fname = get_dso_file_path(dso, dso_bid) if path.exists(dso_fname): - print_disam(dso_fname, dso_vm_start, start_addr, stop_addr) + print_disam(dso_fname, dso_vm_start, start_addr + map_pgoff, stop_addr + map_pgoff) else: - print("Failed to find dso %s for address range [ 0x%x .. 0x%x ]" % (dso, start_addr, stop_addr)) + print("Failed to find dso %s for address range [ 0x%x .. 0x%x ]" % (dso, start_addr + map_pgoff, stop_addr + map_pgoff)) print_srccode(comm, param_dict, sample, symbol, dso) diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 5671ee53001959..ec4e1f03474240 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -4,7 +4,6 @@ perf-test-y += builtin-test.o perf-test-y += tests-scripts.o perf-test-y += parse-events.o perf-test-y += dso-data.o -perf-test-y += attr.o perf-test-y += vmlinux-kallsyms.o perf-test-$(CONFIG_LIBTRACEEVENT) += openat-syscall.o perf-test-$(CONFIG_LIBTRACEEVENT) += openat-syscall-all-cpus.o @@ -67,12 +66,13 @@ perf-test-y += sigtrap.o perf-test-y += event_groups.o perf-test-y += symbols.o perf-test-y += util.o +perf-test-y += hwmon_pmu.o +perf-test-y += tool_pmu.o ifeq ($(SRCARCH),$(filter $(SRCARCH),x86 arm arm64 powerpc)) perf-test-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o endif -CFLAGS_attr.o += -DBINDIR="BUILD_STR($(bindir_SQ))" -DPYTHON="BUILD_STR($(PYTHON_WORD))" CFLAGS_python-use.o += -DPYTHONPATH="BUILD_STR($(OUTPUT)python)" -DPYTHON="BUILD_STR($(PYTHON_WORD))" CFLAGS_dwarf-unwind.o += -fno-optimize-sibling-calls diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c deleted file mode 100644 index 97e1bdd6ec0e9f..00000000000000 --- a/tools/perf/tests/attr.c +++ /dev/null @@ -1,218 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * The struct perf_event_attr test support. - * - * This test is embedded inside into perf directly and is governed - * by the PERF_TEST_ATTR environment variable and hook inside - * sys_perf_event_open function. - * - * The general idea is to store 'struct perf_event_attr' details for - * each event created within single perf command. Each event details - * are stored into separate text file. Once perf command is finished - * these files can be checked for values we expect for command. - * - * Besides 'struct perf_event_attr' values we also store 'fd' and - * 'group_fd' values to allow checking for groups created. - * - * This all is triggered by setting PERF_TEST_ATTR environment variable. - * It must contain name of existing directory with access and write - * permissions. All the event text files are stored there. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "event.h" -#include "util.h" -#include "tests.h" -#include "pmus.h" - -#define ENV "PERF_TEST_ATTR" - -static char *dir; -static bool ready; - -void test_attr__init(void) -{ - dir = getenv(ENV); - test_attr__enabled = (dir != NULL); -} - -#define BUFSIZE 1024 - -#define __WRITE_ASS(str, fmt, data) \ -do { \ - char buf[BUFSIZE]; \ - size_t size; \ - \ - size = snprintf(buf, BUFSIZE, #str "=%"fmt "\n", data); \ - if (1 != fwrite(buf, size, 1, file)) { \ - perror("test attr - failed to write event file"); \ - fclose(file); \ - return -1; \ - } \ - \ -} while (0) - -#define WRITE_ASS(field, fmt) __WRITE_ASS(field, fmt, attr->field) - -static int store_event(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu, - int fd, int group_fd, unsigned long flags) -{ - FILE *file; - char path[PATH_MAX]; - - if (!ready) - return 0; - - snprintf(path, PATH_MAX, "%s/event-%d-%llu-%d", dir, - attr->type, attr->config, fd); - - file = fopen(path, "w+"); - if (!file) { - perror("test attr - failed to open event file"); - return -1; - } - - if (fprintf(file, "[event-%d-%llu-%d]\n", - attr->type, attr->config, fd) < 0) { - perror("test attr - failed to write event file"); - fclose(file); - return -1; - } - - /* syscall arguments */ - __WRITE_ASS(fd, "d", fd); - __WRITE_ASS(group_fd, "d", group_fd); - __WRITE_ASS(cpu, "d", cpu.cpu); - __WRITE_ASS(pid, "d", pid); - __WRITE_ASS(flags, "lu", flags); - - /* struct perf_event_attr */ - WRITE_ASS(type, PRIu32); - WRITE_ASS(size, PRIu32); - WRITE_ASS(config, "llu"); - WRITE_ASS(sample_period, "llu"); - WRITE_ASS(sample_type, "llu"); - WRITE_ASS(read_format, "llu"); - WRITE_ASS(disabled, "d"); - WRITE_ASS(inherit, "d"); - WRITE_ASS(pinned, "d"); - WRITE_ASS(exclusive, "d"); - WRITE_ASS(exclude_user, "d"); - WRITE_ASS(exclude_kernel, "d"); - WRITE_ASS(exclude_hv, "d"); - WRITE_ASS(exclude_idle, "d"); - WRITE_ASS(mmap, "d"); - WRITE_ASS(comm, "d"); - WRITE_ASS(freq, "d"); - WRITE_ASS(inherit_stat, "d"); - WRITE_ASS(enable_on_exec, "d"); - WRITE_ASS(task, "d"); - WRITE_ASS(watermark, "d"); - WRITE_ASS(precise_ip, "d"); - WRITE_ASS(mmap_data, "d"); - WRITE_ASS(sample_id_all, "d"); - WRITE_ASS(exclude_host, "d"); - WRITE_ASS(exclude_guest, "d"); - WRITE_ASS(exclude_callchain_kernel, "d"); - WRITE_ASS(exclude_callchain_user, "d"); - WRITE_ASS(mmap2, "d"); - WRITE_ASS(comm_exec, "d"); - WRITE_ASS(context_switch, "d"); - WRITE_ASS(write_backward, "d"); - WRITE_ASS(namespaces, "d"); - WRITE_ASS(use_clockid, "d"); - WRITE_ASS(wakeup_events, PRIu32); - WRITE_ASS(bp_type, PRIu32); - WRITE_ASS(config1, "llu"); - WRITE_ASS(config2, "llu"); - WRITE_ASS(branch_sample_type, "llu"); - WRITE_ASS(sample_regs_user, "llu"); - WRITE_ASS(sample_stack_user, PRIu32); - - fclose(file); - return 0; -} - -void test_attr__open(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu, - int fd, int group_fd, unsigned long flags) -{ - int errno_saved = errno; - - if ((fd != -1) && store_event(attr, pid, cpu, fd, group_fd, flags)) { - pr_err("test attr FAILED"); - exit(128); - } - - errno = errno_saved; -} - -void test_attr__ready(void) -{ - if (unlikely(test_attr__enabled) && !ready) - ready = true; -} - -static int run_dir(const char *d, const char *perf) -{ - char v[] = "-vvvvv"; - int vcnt = min(verbose, (int) sizeof(v) - 1); - char cmd[3*PATH_MAX]; - - if (verbose > 0) - vcnt++; - - scnprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s", - d, d, perf, vcnt, v); - - return system(cmd) ? TEST_FAIL : TEST_OK; -} - -static int test__attr(struct test_suite *test __maybe_unused, int subtest __maybe_unused) -{ - struct stat st; - char path_perf[PATH_MAX]; - char path_dir[PATH_MAX]; - char *exec_path; - - if (perf_pmus__num_core_pmus() > 1) { - /* - * TODO: Attribute tests hard code the PMU type. If there are >1 - * core PMU then each PMU will have a different type which - * requires additional support. - */ - pr_debug("Skip test on hybrid systems"); - return TEST_SKIP; - } - - /* First try development tree tests. */ - if (!lstat("./tests", &st)) - return run_dir("./tests", "./perf"); - - exec_path = get_argv_exec_path(); - if (exec_path == NULL) - return -1; - - /* Then installed path. */ - snprintf(path_dir, PATH_MAX, "%s/tests", exec_path); - snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR); - free(exec_path); - - if (!lstat(path_dir, &st) && - !lstat(path_perf, &st)) - return run_dir(path_dir, path_perf); - - return TEST_SKIP; -} - -DEFINE_SUITE("Setup struct perf_event_attr", attr); diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py deleted file mode 100644 index e890c261ad2695..00000000000000 --- a/tools/perf/tests/attr.py +++ /dev/null @@ -1,458 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -from __future__ import print_function - -import os -import sys -import glob -import optparse -import platform -import tempfile -import logging -import re -import shutil -import subprocess - -try: - import configparser -except ImportError: - import ConfigParser as configparser - -def data_equal(a, b): - # Allow multiple values in assignment separated by '|' - a_list = a.split('|') - b_list = b.split('|') - - for a_item in a_list: - for b_item in b_list: - if (a_item == b_item): - return True - elif (a_item == '*') or (b_item == '*'): - return True - - return False - -class Fail(Exception): - def __init__(self, test, msg): - self.msg = msg - self.test = test - def getMsg(self): - return '\'%s\' - %s' % (self.test.path, self.msg) - -class Notest(Exception): - def __init__(self, test, arch): - self.arch = arch - self.test = test - def getMsg(self): - return '[%s] \'%s\'' % (self.arch, self.test.path) - -class Unsup(Exception): - def __init__(self, test): - self.test = test - def getMsg(self): - return '\'%s\'' % self.test.path - -class Event(dict): - terms = [ - 'cpu', - 'flags', - 'type', - 'size', - 'config', - 'sample_period', - 'sample_type', - 'read_format', - 'disabled', - 'inherit', - 'pinned', - 'exclusive', - 'exclude_user', - 'exclude_kernel', - 'exclude_hv', - 'exclude_idle', - 'mmap', - 'comm', - 'freq', - 'inherit_stat', - 'enable_on_exec', - 'task', - 'watermark', - 'precise_ip', - 'mmap_data', - 'sample_id_all', - 'exclude_host', - 'exclude_guest', - 'exclude_callchain_kernel', - 'exclude_callchain_user', - 'wakeup_events', - 'bp_type', - 'config1', - 'config2', - 'branch_sample_type', - 'sample_regs_user', - 'sample_stack_user', - ] - - def add(self, data): - for key, val in data: - log.debug(" %s = %s" % (key, val)) - self[key] = val - - def __init__(self, name, data, base): - log.debug(" Event %s" % name); - self.name = name; - self.group = '' - self.add(base) - self.add(data) - - def equal(self, other): - for t in Event.terms: - log.debug(" [%s] %s %s" % (t, self[t], other[t])); - if t not in self or t not in other: - return False - if not data_equal(self[t], other[t]): - return False - return True - - def optional(self): - if 'optional' in self and self['optional'] == '1': - return True - return False - - def diff(self, other): - for t in Event.terms: - if t not in self or t not in other: - continue - if not data_equal(self[t], other[t]): - log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) - -def parse_version(version): - if not version: - return None - return [int(v) for v in version.split(".")[0:2]] - -# Test file description needs to have following sections: -# [config] -# - just single instance in file -# - needs to specify: -# 'command' - perf command name -# 'args' - special command arguments -# 'ret' - Skip test if Perf doesn't exit with this value (0 by default) -# 'test_ret'- If set to 'true', fail test instead of skipping for 'ret' argument -# 'arch' - architecture specific test (optional) -# comma separated list, ! at the beginning -# negates it. -# 'auxv' - Truthy statement that is evaled in the scope of the auxv map. When false, -# the test is skipped. For example 'auxv["AT_HWCAP"] == 10'. (optional) -# 'kernel_since' - Inclusive kernel version from which the test will start running. Only the -# first two values are supported, for example "6.1" (optional) -# 'kernel_until' - Exclusive kernel version from which the test will stop running. (optional) -# [eventX:base] -# - one or multiple instances in file -# - expected values assignments -class Test(object): - def __init__(self, path, options): - parser = configparser.ConfigParser() - parser.read(path) - - log.warning("running '%s'" % path) - - self.path = path - self.test_dir = options.test_dir - self.perf = options.perf - self.command = parser.get('config', 'command') - self.args = parser.get('config', 'args') - - try: - self.ret = parser.get('config', 'ret') - except: - self.ret = 0 - - self.test_ret = parser.getboolean('config', 'test_ret', fallback=False) - - try: - self.arch = parser.get('config', 'arch') - log.warning("test limitation '%s'" % self.arch) - except: - self.arch = '' - - self.auxv = parser.get('config', 'auxv', fallback=None) - self.kernel_since = parse_version(parser.get('config', 'kernel_since', fallback=None)) - self.kernel_until = parse_version(parser.get('config', 'kernel_until', fallback=None)) - self.expect = {} - self.result = {} - log.debug(" loading expected events"); - self.load_events(path, self.expect) - - def is_event(self, name): - if name.find("event") == -1: - return False - else: - return True - - def skip_test_kernel_since(self): - if not self.kernel_since: - return False - return not self.kernel_since <= parse_version(platform.release()) - - def skip_test_kernel_until(self): - if not self.kernel_until: - return False - return not parse_version(platform.release()) < self.kernel_until - - def skip_test_auxv(self): - def new_auxv(a, pattern): - items = list(filter(None, pattern.split(a))) - # AT_HWCAP is hex but doesn't have a prefix, so special case it - if items[0] == "AT_HWCAP": - value = int(items[-1], 16) - else: - try: - value = int(items[-1], 0) - except: - value = items[-1] - return (items[0], value) - - if not self.auxv: - return False - auxv = subprocess.check_output("LD_SHOW_AUXV=1 sleep 0", shell=True) \ - .decode(sys.stdout.encoding) - pattern = re.compile(r"[: ]+") - auxv = dict([new_auxv(a, pattern) for a in auxv.splitlines()]) - return not eval(self.auxv) - - def skip_test_arch(self, myarch): - # If architecture not set always run test - if self.arch == '': - # log.warning("test for arch %s is ok" % myarch) - return False - - # Allow multiple values in assignment separated by ',' - arch_list = self.arch.split(',') - - # Handle negated list such as !s390x,ppc - if arch_list[0][0] == '!': - arch_list[0] = arch_list[0][1:] - log.warning("excluded architecture list %s" % arch_list) - for arch_item in arch_list: - # log.warning("test for %s arch is %s" % (arch_item, myarch)) - if arch_item == myarch: - return True - return False - - for arch_item in arch_list: - # log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch)) - if arch_item == myarch: - return False - return True - - def load_events(self, path, events): - parser_event = configparser.ConfigParser() - parser_event.read(path) - - # The event record section header contains 'event' word, - # optionaly followed by ':' allowing to load 'parent - # event' first as a base - for section in filter(self.is_event, parser_event.sections()): - - parser_items = parser_event.items(section); - base_items = {} - - # Read parent event if there's any - if (':' in section): - base = section[section.index(':') + 1:] - parser_base = configparser.ConfigParser() - parser_base.read(self.test_dir + '/' + base) - base_items = parser_base.items('event') - - e = Event(section, parser_items, base_items) - events[section] = e - - def run_cmd(self, tempdir): - junk1, junk2, junk3, junk4, myarch = (os.uname()) - - if self.skip_test_arch(myarch): - raise Notest(self, myarch) - - if self.skip_test_auxv(): - raise Notest(self, "auxv skip") - - if self.skip_test_kernel_since(): - raise Notest(self, "old kernel skip") - - if self.skip_test_kernel_until(): - raise Notest(self, "new kernel skip") - - cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, - self.perf, self.command, tempdir, self.args) - ret = os.WEXITSTATUS(os.system(cmd)) - - log.info(" '%s' ret '%s', expected '%s'" % (cmd, str(ret), str(self.ret))) - - if not data_equal(str(ret), str(self.ret)): - if self.test_ret: - raise Fail(self, "Perf exit code failure") - else: - raise Unsup(self) - - def compare(self, expect, result): - match = {} - - log.debug(" compare"); - - # For each expected event find all matching - # events in result. Fail if there's not any. - for exp_name, exp_event in expect.items(): - exp_list = [] - res_event = {} - log.debug(" matching [%s]" % exp_name) - for res_name, res_event in result.items(): - log.debug(" to [%s]" % res_name) - if (exp_event.equal(res_event)): - exp_list.append(res_name) - log.debug(" ->OK") - else: - log.debug(" ->FAIL"); - - log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list))) - - # we did not any matching event - fail - if not exp_list: - if exp_event.optional(): - log.debug(" %s does not match, but is optional" % exp_name) - else: - if not res_event: - log.debug(" res_event is empty"); - else: - exp_event.diff(res_event) - raise Fail(self, 'match failure'); - - match[exp_name] = exp_list - - # For each defined group in the expected events - # check we match the same group in the result. - for exp_name, exp_event in expect.items(): - group = exp_event.group - - if (group == ''): - continue - - for res_name in match[exp_name]: - res_group = result[res_name].group - if res_group not in match[group]: - raise Fail(self, 'group failure') - - log.debug(" group: [%s] matches group leader %s" % - (exp_name, str(match[group]))) - - log.debug(" matched") - - def resolve_groups(self, events): - for name, event in events.items(): - group_fd = event['group_fd']; - if group_fd == '-1': - continue; - - for iname, ievent in events.items(): - if (ievent['fd'] == group_fd): - event.group = iname - log.debug('[%s] has group leader [%s]' % (name, iname)) - break; - - def run(self): - tempdir = tempfile.mkdtemp(); - - try: - # run the test script - self.run_cmd(tempdir); - - # load events expectation for the test - log.debug(" loading result events"); - for f in glob.glob(tempdir + '/event*'): - self.load_events(f, self.result); - - # resolve group_fd to event names - self.resolve_groups(self.expect); - self.resolve_groups(self.result); - - # do the expectation - results matching - both ways - self.compare(self.expect, self.result) - self.compare(self.result, self.expect) - - finally: - # cleanup - shutil.rmtree(tempdir) - - -def run_tests(options): - for f in glob.glob(options.test_dir + '/' + options.test): - try: - Test(f, options).run() - except Unsup as obj: - log.warning("unsupp %s" % obj.getMsg()) - except Notest as obj: - log.warning("skipped %s" % obj.getMsg()) - -def setup_log(verbose): - global log - level = logging.CRITICAL - - if verbose == 1: - level = logging.WARNING - if verbose == 2: - level = logging.INFO - if verbose >= 3: - level = logging.DEBUG - - log = logging.getLogger('test') - log.setLevel(level) - ch = logging.StreamHandler() - ch.setLevel(level) - formatter = logging.Formatter('%(message)s') - ch.setFormatter(formatter) - log.addHandler(ch) - -USAGE = '''%s [OPTIONS] - -d dir # tests dir - -p path # perf binary - -t test # single test - -v # verbose level -''' % sys.argv[0] - -def main(): - parser = optparse.OptionParser(usage=USAGE) - - parser.add_option("-t", "--test", - action="store", type="string", dest="test") - parser.add_option("-d", "--test-dir", - action="store", type="string", dest="test_dir") - parser.add_option("-p", "--perf", - action="store", type="string", dest="perf") - parser.add_option("-v", "--verbose", - default=0, action="count", dest="verbose") - - options, args = parser.parse_args() - if args: - parser.error('FAILED wrong arguments %s' % ' '.join(args)) - return -1 - - setup_log(options.verbose) - - if not options.test_dir: - print('FAILED no -d option specified') - sys.exit(-1) - - if not options.test: - options.test = 'test*' - - try: - run_tests(options) - - except Fail as obj: - print("FAILED %s" % obj.getMsg()) - sys.exit(-1) - - sys.exit(0) - -if __name__ == '__main__': - main() diff --git a/tools/perf/tests/attr/README b/tools/perf/tests/attr/README deleted file mode 100644 index 4066fec7180a8e..00000000000000 --- a/tools/perf/tests/attr/README +++ /dev/null @@ -1,69 +0,0 @@ -The struct perf_event_attr test (attr tests) support -==================================================== -This testing support is embedded into perf directly and is governed -by the PERF_TEST_ATTR environment variable and hook inside the -sys_perf_event_open function. - -The general idea is to store 'struct perf_event_attr' details for -each event created within single perf command. Each event details -are stored into separate text file. Once perf command is finished -these files are checked for values we expect for command. - -The attr tests consist of following parts: - -tests/attr.c ------------- -This is the sys_perf_event_open hook implementation. The hook -is triggered when the PERF_TEST_ATTR environment variable is -defined. It must contain name of existing directory with access -and write permissions. - -For each sys_perf_event_open call event details are stored in -separate file. Besides 'struct perf_event_attr' values we also -store 'fd' and 'group_fd' values to allow checking for groups. - -tests/attr.py -------------- -This is the python script that does all the hard work. It reads -the test definition, executes it and checks results. - -tests/attr/ ------------ -Directory containing all attr test definitions. -Following tests are defined (with perf commands): - - perf record kill (test-record-basic) - perf record -b kill (test-record-branch-any) - perf record -j any kill (test-record-branch-filter-any) - perf record -j any_call kill (test-record-branch-filter-any_call) - perf record -j any_ret kill (test-record-branch-filter-any_ret) - perf record -j hv kill (test-record-branch-filter-hv) - perf record -j ind_call kill (test-record-branch-filter-ind_call) - perf record -j k kill (test-record-branch-filter-k) - perf record -j u kill (test-record-branch-filter-u) - perf record -c 123 kill (test-record-count) - perf record -d kill (test-record-data) - perf record -F 100 kill (test-record-freq) - perf record -g kill (test-record-graph-default) - perf record -g kill (test-record-graph-default-aarch64) - perf record --call-graph dwarf kill (test-record-graph-dwarf) - perf record --call-graph fp kill (test-record-graph-fp) - perf record --call-graph fp kill (test-record-graph-fp-aarch64) - perf record -e '{cycles,instructions}' kill (test-record-group1) - perf record -e '{cycles/period=1/,instructions/period=2/}:S' kill (test-record-group2) - perf record -D kill (test-record-no-delay) - perf record -i kill (test-record-no-inherit) - perf record -n kill (test-record-no-samples) - perf record -c 100 -P kill (test-record-period) - perf record -c 1 --pfm-events=cycles:period=2 (test-record-pfm-period) - perf record -R kill (test-record-raw) - perf record -c 2 -e arm_spe_0// -- kill (test-record-spe-period) - perf record -e arm_spe_0/period=3/ -- kill (test-record-spe-period-term) - perf record -e arm_spe_0/pa_enable=1/ -- kill (test-record-spe-physical-address) - perf stat -e cycles kill (test-stat-basic) - perf stat kill (test-stat-default) - perf stat -d kill (test-stat-detailed-1) - perf stat -dd kill (test-stat-detailed-2) - perf stat -ddd kill (test-stat-detailed-3) - perf stat -e '{cycles,instructions}' kill (test-stat-group1) - perf stat -i -e cycles kill (test-stat-no-inherit) diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record deleted file mode 100644 index b44e4e6e444386..00000000000000 --- a/tools/perf/tests/attr/base-record +++ /dev/null @@ -1,41 +0,0 @@ -[event] -fd=1 -group_fd=-1 -# 0 or PERF_FLAG_FD_CLOEXEC flag -flags=0|8 -cpu=* -type=0|1 -size=136 -config=0|1 -sample_period=* -sample_type=263 -read_format=0|4|20 -disabled=1 -inherit=1 -pinned=0 -exclusive=0 -exclude_user=0 -exclude_kernel=0|1 -exclude_hv=0|1 -exclude_idle=0 -mmap=1 -comm=1 -freq=1 -inherit_stat=0 -enable_on_exec=1 -task=1 -watermark=0 -precise_ip=0|1|2|3 -mmap_data=0 -sample_id_all=1 -exclude_host=0|1 -exclude_guest=0|1 -exclude_callchain_kernel=0 -exclude_callchain_user=0 -wakeup_events=0 -bp_type=0 -config1=0 -config2=0 -branch_sample_type=0 -sample_regs_user=0 -sample_stack_user=0 diff --git a/tools/perf/tests/attr/base-record-spe b/tools/perf/tests/attr/base-record-spe deleted file mode 100644 index 08fa96b5924057..00000000000000 --- a/tools/perf/tests/attr/base-record-spe +++ /dev/null @@ -1,40 +0,0 @@ -[event] -fd=* -group_fd=-1 -flags=* -cpu=* -type=* -size=* -config=* -sample_period=* -sample_type=* -read_format=* -disabled=* -inherit=* -pinned=* -exclusive=* -exclude_user=* -exclude_kernel=* -exclude_hv=* -exclude_idle=* -mmap=* -comm=* -freq=* -inherit_stat=* -enable_on_exec=* -task=* -watermark=* -precise_ip=* -mmap_data=* -sample_id_all=* -exclude_host=* -exclude_guest=* -exclude_callchain_kernel=* -exclude_callchain_user=* -wakeup_events=* -bp_type=* -config1=* -config2=* -branch_sample_type=* -sample_regs_user=* -sample_stack_user=* diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat deleted file mode 100644 index fccd8ec4d1b022..00000000000000 --- a/tools/perf/tests/attr/base-stat +++ /dev/null @@ -1,41 +0,0 @@ -[event] -fd=1 -group_fd=-1 -# 0 or PERF_FLAG_FD_CLOEXEC flag -flags=0|8 -cpu=* -type=0 -size=136 -config=0 -sample_period=0 -sample_type=65536 -read_format=3 -disabled=1 -inherit=1 -pinned=0 -exclusive=0 -exclude_user=0 -exclude_kernel=0|1 -exclude_hv=0|1 -exclude_idle=0 -mmap=0 -comm=0 -freq=0 -inherit_stat=0 -enable_on_exec=1 -task=0 -watermark=0 -precise_ip=0 -mmap_data=0 -sample_id_all=0 -exclude_host=0|1 -exclude_guest=0|1 -exclude_callchain_kernel=0 -exclude_callchain_user=0 -wakeup_events=0 -bp_type=0 -config1=0 -config2=0 -branch_sample_type=0 -sample_regs_user=0 -sample_stack_user=0 diff --git a/tools/perf/tests/attr/system-wide-dummy b/tools/perf/tests/attr/system-wide-dummy deleted file mode 100644 index a1e1d6a263bf14..00000000000000 --- a/tools/perf/tests/attr/system-wide-dummy +++ /dev/null @@ -1,52 +0,0 @@ -# Event added by system-wide or CPU perf-record to handle the race of -# processes starting while /proc is processed. -[event] -fd=1 -group_fd=-1 -cpu=* -pid=-1 -flags=8 -type=1 -size=136 -config=9 -sample_period=1 -# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | -# PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER -sample_type=65671 -read_format=4|20 -# Event will be enabled right away. -disabled=0 -inherit=1 -pinned=0 -exclusive=0 -exclude_user=0 -exclude_kernel=1 -exclude_hv=1 -exclude_idle=0 -mmap=1 -comm=1 -freq=0 -inherit_stat=0 -enable_on_exec=0 -task=1 -watermark=0 -precise_ip=0 -mmap_data=0 -sample_id_all=1 -exclude_host=0 -exclude_guest=1 -exclude_callchain_kernel=0 -exclude_callchain_user=0 -mmap2=1 -comm_exec=1 -context_switch=0 -write_backward=0 -namespaces=0 -use_clockid=0 -wakeup_events=0 -bp_type=0 -config1=0 -config2=0 -branch_sample_type=0 -sample_regs_user=0 -sample_stack_user=0 diff --git a/tools/perf/tests/attr/test-record-C0 b/tools/perf/tests/attr/test-record-C0 deleted file mode 100644 index 198e8429a1bf85..00000000000000 --- a/tools/perf/tests/attr/test-record-C0 +++ /dev/null @@ -1,22 +0,0 @@ -[config] -command = record -args = --no-bpf-event -C 0 kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -cpu=0 - -# no enable on exec for CPU attached -enable_on_exec=0 - -# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | -# PERF_SAMPLE_PERIOD | PERF_SAMPLE_IDENTIFIER -# + PERF_SAMPLE_CPU added by -C 0 -sample_type=65927 - -# Dummy event handles mmaps, comm and task. -mmap=0 -comm=0 -task=0 - -[event:system-wide-dummy] diff --git a/tools/perf/tests/attr/test-record-basic b/tools/perf/tests/attr/test-record-basic deleted file mode 100644 index b0ca42a5ecc9ce..00000000000000 --- a/tools/perf/tests/attr/test-record-basic +++ /dev/null @@ -1,6 +0,0 @@ -[config] -command = record -args = --no-bpf-event kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] diff --git a/tools/perf/tests/attr/test-record-branch-any b/tools/perf/tests/attr/test-record-branch-any deleted file mode 100644 index 1a99b3ce6b899c..00000000000000 --- a/tools/perf/tests/attr/test-record-branch-any +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -b kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=2311 -branch_sample_type=8 diff --git a/tools/perf/tests/attr/test-record-branch-filter-any b/tools/perf/tests/attr/test-record-branch-filter-any deleted file mode 100644 index 709768b508c624..00000000000000 --- a/tools/perf/tests/attr/test-record-branch-filter-any +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -j any kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=2311 -branch_sample_type=8 diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_call b/tools/perf/tests/attr/test-record-branch-filter-any_call deleted file mode 100644 index f943221f782543..00000000000000 --- a/tools/perf/tests/attr/test-record-branch-filter-any_call +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -j any_call kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=2311 -branch_sample_type=16 diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_ret b/tools/perf/tests/attr/test-record-branch-filter-any_ret deleted file mode 100644 index fd4f5b4154a9d3..00000000000000 --- a/tools/perf/tests/attr/test-record-branch-filter-any_ret +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -j any_ret kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=2311 -branch_sample_type=32 diff --git a/tools/perf/tests/attr/test-record-branch-filter-hv b/tools/perf/tests/attr/test-record-branch-filter-hv deleted file mode 100644 index 4e52d685ebe172..00000000000000 --- a/tools/perf/tests/attr/test-record-branch-filter-hv +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -j hv kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=2311 -branch_sample_type=8 diff --git a/tools/perf/tests/attr/test-record-branch-filter-ind_call b/tools/perf/tests/attr/test-record-branch-filter-ind_call deleted file mode 100644 index e08c6ab3796e01..00000000000000 --- a/tools/perf/tests/attr/test-record-branch-filter-ind_call +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -j ind_call kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=2311 -branch_sample_type=64 diff --git a/tools/perf/tests/attr/test-record-branch-filter-k b/tools/perf/tests/attr/test-record-branch-filter-k deleted file mode 100644 index b4b98f84fc2f75..00000000000000 --- a/tools/perf/tests/attr/test-record-branch-filter-k +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -j k kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=2311 -branch_sample_type=8 diff --git a/tools/perf/tests/attr/test-record-branch-filter-u b/tools/perf/tests/attr/test-record-branch-filter-u deleted file mode 100644 index fb9610edbb0d7e..00000000000000 --- a/tools/perf/tests/attr/test-record-branch-filter-u +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -j u kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=2311 -branch_sample_type=8 diff --git a/tools/perf/tests/attr/test-record-count b/tools/perf/tests/attr/test-record-count deleted file mode 100644 index 5e9b9019d7865c..00000000000000 --- a/tools/perf/tests/attr/test-record-count +++ /dev/null @@ -1,9 +0,0 @@ -[config] -command = record -args = --no-bpf-event -c 123 kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_period=123 -sample_type=7 -freq=0 diff --git a/tools/perf/tests/attr/test-record-data b/tools/perf/tests/attr/test-record-data deleted file mode 100644 index a99bb13149c20d..00000000000000 --- a/tools/perf/tests/attr/test-record-data +++ /dev/null @@ -1,10 +0,0 @@ -[config] -command = record -args = --no-bpf-event -d kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -# sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | -# PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC -sample_type=33039 -mmap_data=1 diff --git a/tools/perf/tests/attr/test-record-dummy-C0 b/tools/perf/tests/attr/test-record-dummy-C0 deleted file mode 100644 index 576ec48b3aafaa..00000000000000 --- a/tools/perf/tests/attr/test-record-dummy-C0 +++ /dev/null @@ -1,55 +0,0 @@ -[config] -command = record -args = --no-bpf-event -e dummy -C 0 kill >/dev/null 2>&1 -ret = 1 - -[event] -fd=1 -group_fd=-1 -cpu=0 -pid=-1 -flags=8 -type=1 -size=136 -config=9 -sample_period=4000 -# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | -# PERF_SAMPLE_PERIOD -# + PERF_SAMPLE_CPU added by -C 0 -sample_type=391 -read_format=4|20 -disabled=0 -inherit=1 -pinned=0 -exclusive=0 -exclude_user=0 -exclude_kernel=0 -exclude_hv=0 -exclude_idle=0 -mmap=1 -comm=1 -freq=1 -inherit_stat=0 -enable_on_exec=0 -task=1 -watermark=0 -precise_ip=0 -mmap_data=0 -sample_id_all=1 -exclude_host=0 -exclude_guest=1 -exclude_callchain_kernel=0 -exclude_callchain_user=0 -mmap2=1 -comm_exec=1 -context_switch=0 -write_backward=0 -namespaces=0 -use_clockid=0 -wakeup_events=0 -bp_type=0 -config1=0 -config2=0 -branch_sample_type=0 -sample_regs_user=0 -sample_stack_user=0 diff --git a/tools/perf/tests/attr/test-record-freq b/tools/perf/tests/attr/test-record-freq deleted file mode 100644 index 89e29f6b2ae0cf..00000000000000 --- a/tools/perf/tests/attr/test-record-freq +++ /dev/null @@ -1,7 +0,0 @@ -[config] -command = record -args = --no-bpf-event -F 100 kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_period=100 diff --git a/tools/perf/tests/attr/test-record-graph-default b/tools/perf/tests/attr/test-record-graph-default deleted file mode 100644 index f0a18b4ea4f562..00000000000000 --- a/tools/perf/tests/attr/test-record-graph-default +++ /dev/null @@ -1,9 +0,0 @@ -[config] -command = record -args = --no-bpf-event -g kill >/dev/null 2>&1 -ret = 1 -# arm64 enables registers in the default mode (fp) -arch = !aarch64 - -[event:base-record] -sample_type=295 diff --git a/tools/perf/tests/attr/test-record-graph-default-aarch64 b/tools/perf/tests/attr/test-record-graph-default-aarch64 deleted file mode 100644 index e98d62efb6f7ee..00000000000000 --- a/tools/perf/tests/attr/test-record-graph-default-aarch64 +++ /dev/null @@ -1,9 +0,0 @@ -[config] -command = record -args = --no-bpf-event -g kill >/dev/null 2>&1 -ret = 1 -arch = aarch64 - -[event:base-record] -sample_type=4391 -sample_regs_user=1073741824 diff --git a/tools/perf/tests/attr/test-record-graph-dwarf b/tools/perf/tests/attr/test-record-graph-dwarf deleted file mode 100644 index ae92061d611ded..00000000000000 --- a/tools/perf/tests/attr/test-record-graph-dwarf +++ /dev/null @@ -1,12 +0,0 @@ -[config] -command = record -args = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=45359 -exclude_callchain_user=1 -sample_stack_user=8192 -# TODO different for each arch, no support for that now -sample_regs_user=* -mmap_data=1 diff --git a/tools/perf/tests/attr/test-record-graph-fp b/tools/perf/tests/attr/test-record-graph-fp deleted file mode 100644 index a6e60e83920514..00000000000000 --- a/tools/perf/tests/attr/test-record-graph-fp +++ /dev/null @@ -1,9 +0,0 @@ -[config] -command = record -args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1 -ret = 1 -# arm64 enables registers in fp mode -arch = !aarch64 - -[event:base-record] -sample_type=295 diff --git a/tools/perf/tests/attr/test-record-graph-fp-aarch64 b/tools/perf/tests/attr/test-record-graph-fp-aarch64 deleted file mode 100644 index cbeea9971285b1..00000000000000 --- a/tools/perf/tests/attr/test-record-graph-fp-aarch64 +++ /dev/null @@ -1,9 +0,0 @@ -[config] -command = record -args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1 -ret = 1 -arch = aarch64 - -[event:base-record] -sample_type=4391 -sample_regs_user=1073741824 diff --git a/tools/perf/tests/attr/test-record-group-sampling b/tools/perf/tests/attr/test-record-group-sampling deleted file mode 100644 index 97e7e64a38f07f..00000000000000 --- a/tools/perf/tests/attr/test-record-group-sampling +++ /dev/null @@ -1,39 +0,0 @@ -[config] -command = record -args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 -ret = 1 - -[event-1:base-record] -fd=1 -group_fd=-1 -sample_type=343 -read_format=12|28 -inherit=0 - -[event-2:base-record] -fd=2 -group_fd=1 - -# cache-misses -type=0 -config=3 - -# default | PERF_SAMPLE_READ -sample_type=343 - -# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST -read_format=12|28 -task=0 -mmap=0 -comm=0 -enable_on_exec=0 -disabled=0 - -# inherit is disabled for group sampling -inherit=0 - -# sampling disabled -sample_freq=0 -sample_period=0 -freq=0 -write_backward=0 diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1 deleted file mode 100644 index eeb1db392bc9ce..00000000000000 --- a/tools/perf/tests/attr/test-record-group1 +++ /dev/null @@ -1,23 +0,0 @@ -[config] -command = record -args = --no-bpf-event -e '{cycles,instructions}' kill >/dev/null 2>&1 -ret = 1 - -[event-1:base-record] -fd=1 -group_fd=-1 -sample_type=327 -read_format=4|20 - -[event-2:base-record] -fd=2 -group_fd=1 -type=0 -config=1 -sample_type=327 -read_format=4|20 -mmap=0 -comm=0 -task=0 -enable_on_exec=0 -disabled=0 diff --git a/tools/perf/tests/attr/test-record-group2 b/tools/perf/tests/attr/test-record-group2 deleted file mode 100644 index cebdaa8e64e474..00000000000000 --- a/tools/perf/tests/attr/test-record-group2 +++ /dev/null @@ -1,29 +0,0 @@ -[config] -command = record -args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1 -ret = 1 - -[event-1:base-record] -fd=1 -group_fd=-1 -config=0|1 -sample_period=1234000 -sample_type=87 -read_format=12|28 -inherit=0 -freq=0 - -[event-2:base-record] -fd=2 -group_fd=1 -config=0|1 -sample_period=6789000 -sample_type=87 -read_format=12|28 -disabled=0 -inherit=0 -mmap=0 -comm=0 -freq=0 -enable_on_exec=0 -task=0 diff --git a/tools/perf/tests/attr/test-record-no-buffering b/tools/perf/tests/attr/test-record-no-buffering deleted file mode 100644 index 583dcbb078bad8..00000000000000 --- a/tools/perf/tests/attr/test-record-no-buffering +++ /dev/null @@ -1,9 +0,0 @@ -[config] -command = record -args = --no-bpf-event --no-buffering kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=263 -watermark=0 -wakeup_events=1 diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/attr/test-record-no-inherit deleted file mode 100644 index 15d1dc162e1c3e..00000000000000 --- a/tools/perf/tests/attr/test-record-no-inherit +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -i kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=263 -inherit=0 diff --git a/tools/perf/tests/attr/test-record-no-samples b/tools/perf/tests/attr/test-record-no-samples deleted file mode 100644 index 596fbd6d5a2ccd..00000000000000 --- a/tools/perf/tests/attr/test-record-no-samples +++ /dev/null @@ -1,7 +0,0 @@ -[config] -command = record -args = --no-bpf-event -n kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_period=0 diff --git a/tools/perf/tests/attr/test-record-period b/tools/perf/tests/attr/test-record-period deleted file mode 100644 index 119101154c5ee9..00000000000000 --- a/tools/perf/tests/attr/test-record-period +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = record -args = --no-bpf-event -c 100 -P kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_period=100 -freq=0 diff --git a/tools/perf/tests/attr/test-record-pfm-period b/tools/perf/tests/attr/test-record-pfm-period deleted file mode 100644 index 368f5b81409433..00000000000000 --- a/tools/perf/tests/attr/test-record-pfm-period +++ /dev/null @@ -1,9 +0,0 @@ -[config] -command = record -args = --no-bpf-event -c 10000 --pfm-events=cycles:period=77777 kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_period=77777 -sample_type=7 -freq=0 diff --git a/tools/perf/tests/attr/test-record-raw b/tools/perf/tests/attr/test-record-raw deleted file mode 100644 index 13a5f7860c786c..00000000000000 --- a/tools/perf/tests/attr/test-record-raw +++ /dev/null @@ -1,7 +0,0 @@ -[config] -command = record -args = --no-bpf-event -R kill >/dev/null 2>&1 -ret = 1 - -[event:base-record] -sample_type=1415 diff --git a/tools/perf/tests/attr/test-record-spe-period b/tools/perf/tests/attr/test-record-spe-period deleted file mode 100644 index 75f8c9cd8e3f74..00000000000000 --- a/tools/perf/tests/attr/test-record-spe-period +++ /dev/null @@ -1,12 +0,0 @@ -[config] -command = record -args = --no-bpf-event -c 2 -e arm_spe_0// -- kill >/dev/null 2>&1 -ret = 1 -arch = aarch64 - -[event-10:base-record-spe] -sample_period=2 -freq=0 - -# dummy event -[event-1:base-record-spe] diff --git a/tools/perf/tests/attr/test-record-spe-period-term b/tools/perf/tests/attr/test-record-spe-period-term deleted file mode 100644 index 8f60a4fec657ff..00000000000000 --- a/tools/perf/tests/attr/test-record-spe-period-term +++ /dev/null @@ -1,12 +0,0 @@ -[config] -command = record -args = --no-bpf-event -e arm_spe_0/period=3/ -- kill >/dev/null 2>&1 -ret = 1 -arch = aarch64 - -[event-10:base-record-spe] -sample_period=3 -freq=0 - -# dummy event -[event-1:base-record-spe] diff --git a/tools/perf/tests/attr/test-record-spe-physical-address b/tools/perf/tests/attr/test-record-spe-physical-address deleted file mode 100644 index 7ebcf5012ce354..00000000000000 --- a/tools/perf/tests/attr/test-record-spe-physical-address +++ /dev/null @@ -1,12 +0,0 @@ -[config] -command = record -args = --no-bpf-event -e arm_spe_0/pa_enable=1/ -- kill >/dev/null 2>&1 -ret = 1 -arch = aarch64 - -[event-10:base-record-spe] -# 622727 is the decimal of IP|TID|TIME|CPU|IDENTIFIER|DATA_SRC|PHYS_ADDR -sample_type=622727 - -# dummy event -[event-1:base-record-spe] \ No newline at end of file diff --git a/tools/perf/tests/attr/test-record-user-regs-no-sve-aarch64 b/tools/perf/tests/attr/test-record-user-regs-no-sve-aarch64 deleted file mode 100644 index bed765450ca976..00000000000000 --- a/tools/perf/tests/attr/test-record-user-regs-no-sve-aarch64 +++ /dev/null @@ -1,9 +0,0 @@ -# Test that asking for VG fails if the system doesn't support SVE. This -# applies both before and after the feature was added in 6.1 -[config] -command = record -args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1 -ret = 129 -test_ret = true -arch = aarch64 -auxv = auxv["AT_HWCAP"] & 0x400000 == 0 diff --git a/tools/perf/tests/attr/test-record-user-regs-old-sve-aarch64 b/tools/perf/tests/attr/test-record-user-regs-old-sve-aarch64 deleted file mode 100644 index 15ebfc3418e3f5..00000000000000 --- a/tools/perf/tests/attr/test-record-user-regs-old-sve-aarch64 +++ /dev/null @@ -1,10 +0,0 @@ -# Test that asking for VG always fails on old kernels because it was -# added in 6.1. This applies to systems that either support or don't -# support SVE. -[config] -command = record -args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1 -ret = 129 -test_ret = true -arch = aarch64 -kernel_until = 6.1 diff --git a/tools/perf/tests/attr/test-record-user-regs-sve-aarch64 b/tools/perf/tests/attr/test-record-user-regs-sve-aarch64 deleted file mode 100644 index a65113cd7311b4..00000000000000 --- a/tools/perf/tests/attr/test-record-user-regs-sve-aarch64 +++ /dev/null @@ -1,14 +0,0 @@ -# Test that asking for VG works if the system has SVE and after the -# feature was added in 6.1 -[config] -command = record -args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1 -ret = 1 -test_ret = true -arch = aarch64 -auxv = auxv["AT_HWCAP"] & 0x400000 == 0x400000 -kernel_since = 6.1 - -[event:base-record] -sample_type=4359 -sample_regs_user=70368744177664 diff --git a/tools/perf/tests/attr/test-stat-C0 b/tools/perf/tests/attr/test-stat-C0 deleted file mode 100644 index a2c76d10b2bb2a..00000000000000 --- a/tools/perf/tests/attr/test-stat-C0 +++ /dev/null @@ -1,10 +0,0 @@ -[config] -command = stat -args = -e cycles -C 0 kill >/dev/null 2>&1 -ret = 1 - -[event:base-stat] -# events are disabled by default when attached to cpu -disabled=1 -enable_on_exec=0 -optional=1 diff --git a/tools/perf/tests/attr/test-stat-basic b/tools/perf/tests/attr/test-stat-basic deleted file mode 100644 index 69867d049fda92..00000000000000 --- a/tools/perf/tests/attr/test-stat-basic +++ /dev/null @@ -1,7 +0,0 @@ -[config] -command = stat -args = -e cycles kill >/dev/null 2>&1 -ret = 1 - -[event:base-stat] -optional=1 diff --git a/tools/perf/tests/attr/test-stat-default b/tools/perf/tests/attr/test-stat-default deleted file mode 100644 index a1e2da0a9a6ddb..00000000000000 --- a/tools/perf/tests/attr/test-stat-default +++ /dev/null @@ -1,185 +0,0 @@ -[config] -command = stat -args = kill >/dev/null 2>&1 -ret = 1 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK -[event1:base-stat] -fd=1 -type=1 -config=1 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES -[event2:base-stat] -fd=2 -type=1 -config=3 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS -[event3:base-stat] -fd=3 -type=1 -config=4 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS -[event4:base-stat] -fd=4 -type=1 -config=2 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES -[event5:base-stat] -fd=5 -type=0 -config=0 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND -[event6:base-stat] -fd=6 -type=0 -config=7 -optional=1 -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND -[event7:base-stat] -fd=7 -type=0 -config=8 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS -[event8:base-stat] -fd=8 -type=0 -config=1 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS -[event9:base-stat] -fd=9 -type=0 -config=4 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES -[event10:base-stat] -fd=10 -type=0 -config=5 -optional=1 - -# PERF_TYPE_RAW / slots (0x400) -[event11:base-stat] -fd=11 -group_fd=-1 -type=4 -config=1024 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-retiring (0x8000) -[event12:base-stat] -fd=12 -group_fd=11 -type=4 -config=32768 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-fe-bound (0x8200) -[event13:base-stat] -fd=13 -group_fd=11 -type=4 -config=33280 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-be-bound (0x8300) -[event14:base-stat] -fd=14 -group_fd=11 -type=4 -config=33536 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-bad-spec (0x8100) -[event15:base-stat] -fd=15 -group_fd=11 -type=4 -config=33024 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING -[event16:base-stat] -fd=16 -type=4 -config=4109 -optional=1 - -# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ -[event17:base-stat] -fd=17 -type=4 -config=17039629 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD -[event18:base-stat] -fd=18 -type=4 -config=60 -optional=1 - -# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY -[event19:base-stat] -fd=19 -type=4 -config=2097421 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK -[event20:base-stat] -fd=20 -type=4 -config=316 -optional=1 - -# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE -[event21:base-stat] -fd=21 -type=4 -config=412 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE -[event22:base-stat] -fd=22 -type=4 -config=572 -optional=1 - -# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS -[event23:base-stat] -fd=23 -type=4 -config=706 -optional=1 - -# PERF_TYPE_RAW / UOPS_ISSUED.ANY -[event24:base-stat] -fd=24 -type=4 -config=270 -optional=1 diff --git a/tools/perf/tests/attr/test-stat-detailed-1 b/tools/perf/tests/attr/test-stat-detailed-1 deleted file mode 100644 index 1c52cb05c900d7..00000000000000 --- a/tools/perf/tests/attr/test-stat-detailed-1 +++ /dev/null @@ -1,227 +0,0 @@ -[config] -command = stat -args = -d kill >/dev/null 2>&1 -ret = 1 - - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK -[event1:base-stat] -fd=1 -type=1 -config=1 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES -[event2:base-stat] -fd=2 -type=1 -config=3 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS -[event3:base-stat] -fd=3 -type=1 -config=4 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS -[event4:base-stat] -fd=4 -type=1 -config=2 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES -[event5:base-stat] -fd=5 -type=0 -config=0 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND -[event6:base-stat] -fd=6 -type=0 -config=7 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND -[event7:base-stat] -fd=7 -type=0 -config=8 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS -[event8:base-stat] -fd=8 -type=0 -config=1 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS -[event9:base-stat] -fd=9 -type=0 -config=4 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES -[event10:base-stat] -fd=10 -type=0 -config=5 -optional=1 - -# PERF_TYPE_RAW / slots (0x400) -[event11:base-stat] -fd=11 -group_fd=-1 -type=4 -config=1024 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-retiring (0x8000) -[event12:base-stat] -fd=12 -group_fd=11 -type=4 -config=32768 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-fe-bound (0x8200) -[event13:base-stat] -fd=13 -group_fd=11 -type=4 -config=33280 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-be-bound (0x8300) -[event14:base-stat] -fd=14 -group_fd=11 -type=4 -config=33536 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-bad-spec (0x8100) -[event15:base-stat] -fd=15 -group_fd=11 -type=4 -config=33024 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING -[event16:base-stat] -fd=16 -type=4 -config=4109 -optional=1 - -# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ -[event17:base-stat] -fd=17 -type=4 -config=17039629 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD -[event18:base-stat] -fd=18 -type=4 -config=60 -optional=1 - -# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY -[event19:base-stat] -fd=19 -type=4 -config=2097421 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK -[event20:base-stat] -fd=20 -type=4 -config=316 -optional=1 - -# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE -[event21:base-stat] -fd=21 -type=4 -config=412 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE -[event22:base-stat] -fd=22 -type=4 -config=572 -optional=1 - -# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS -[event23:base-stat] -fd=23 -type=4 -config=706 -optional=1 - -# PERF_TYPE_RAW / UOPS_ISSUED.ANY -[event24:base-stat] -fd=24 -type=4 -config=270 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_L1D << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event25:base-stat] -fd=25 -type=3 -config=0 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_L1D << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event26:base-stat] -fd=26 -type=3 -config=65536 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_LL << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event27:base-stat] -fd=27 -type=3 -config=2 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_LL << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event28:base-stat] -fd=28 -type=3 -config=65538 -optional=1 diff --git a/tools/perf/tests/attr/test-stat-detailed-2 b/tools/perf/tests/attr/test-stat-detailed-2 deleted file mode 100644 index 7e961d24a885a7..00000000000000 --- a/tools/perf/tests/attr/test-stat-detailed-2 +++ /dev/null @@ -1,287 +0,0 @@ -[config] -command = stat -args = -dd kill >/dev/null 2>&1 -ret = 1 - - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK -[event1:base-stat] -fd=1 -type=1 -config=1 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES -[event2:base-stat] -fd=2 -type=1 -config=3 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS -[event3:base-stat] -fd=3 -type=1 -config=4 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS -[event4:base-stat] -fd=4 -type=1 -config=2 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES -[event5:base-stat] -fd=5 -type=0 -config=0 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND -[event6:base-stat] -fd=6 -type=0 -config=7 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND -[event7:base-stat] -fd=7 -type=0 -config=8 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS -[event8:base-stat] -fd=8 -type=0 -config=1 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS -[event9:base-stat] -fd=9 -type=0 -config=4 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES -[event10:base-stat] -fd=10 -type=0 -config=5 -optional=1 - -# PERF_TYPE_RAW / slots (0x400) -[event11:base-stat] -fd=11 -group_fd=-1 -type=4 -config=1024 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-retiring (0x8000) -[event12:base-stat] -fd=12 -group_fd=11 -type=4 -config=32768 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-fe-bound (0x8200) -[event13:base-stat] -fd=13 -group_fd=11 -type=4 -config=33280 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-be-bound (0x8300) -[event14:base-stat] -fd=14 -group_fd=11 -type=4 -config=33536 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-bad-spec (0x8100) -[event15:base-stat] -fd=15 -group_fd=11 -type=4 -config=33024 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING -[event16:base-stat] -fd=16 -type=4 -config=4109 -optional=1 - -# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ -[event17:base-stat] -fd=17 -type=4 -config=17039629 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD -[event18:base-stat] -fd=18 -type=4 -config=60 -optional=1 - -# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY -[event19:base-stat] -fd=19 -type=4 -config=2097421 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK -[event20:base-stat] -fd=20 -type=4 -config=316 -optional=1 - -# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE -[event21:base-stat] -fd=21 -type=4 -config=412 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE -[event22:base-stat] -fd=22 -type=4 -config=572 -optional=1 - -# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS -[event23:base-stat] -fd=23 -type=4 -config=706 -optional=1 - -# PERF_TYPE_RAW / UOPS_ISSUED.ANY -[event24:base-stat] -fd=24 -type=4 -config=270 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_L1D << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event25:base-stat] -fd=25 -type=3 -config=0 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_L1D << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event26:base-stat] -fd=26 -type=3 -config=65536 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_LL << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event27:base-stat] -fd=27 -type=3 -config=2 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_LL << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event28:base-stat] -fd=28 -type=3 -config=65538 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_L1I << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event29:base-stat] -fd=29 -type=3 -config=1 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_L1I << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event30:base-stat] -fd=30 -type=3 -config=65537 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_DTLB << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event31:base-stat] -fd=31 -type=3 -config=3 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_DTLB << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event32:base-stat] -fd=32 -type=3 -config=65539 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_ITLB << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event33:base-stat] -fd=33 -type=3 -config=4 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_ITLB << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event34:base-stat] -fd=34 -type=3 -config=65540 -optional=1 diff --git a/tools/perf/tests/attr/test-stat-detailed-3 b/tools/perf/tests/attr/test-stat-detailed-3 deleted file mode 100644 index e50535f45977c6..00000000000000 --- a/tools/perf/tests/attr/test-stat-detailed-3 +++ /dev/null @@ -1,307 +0,0 @@ -[config] -command = stat -args = -ddd kill >/dev/null 2>&1 -ret = 1 - - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK -[event1:base-stat] -fd=1 -type=1 -config=1 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES -[event2:base-stat] -fd=2 -type=1 -config=3 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS -[event3:base-stat] -fd=3 -type=1 -config=4 - -# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS -[event4:base-stat] -fd=4 -type=1 -config=2 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES -[event5:base-stat] -fd=5 -type=0 -config=0 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND -[event6:base-stat] -fd=6 -type=0 -config=7 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND -[event7:base-stat] -fd=7 -type=0 -config=8 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS -[event8:base-stat] -fd=8 -type=0 -config=1 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS -[event9:base-stat] -fd=9 -type=0 -config=4 -optional=1 - -# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES -[event10:base-stat] -fd=10 -type=0 -config=5 -optional=1 - -# PERF_TYPE_RAW / slots (0x400) -[event11:base-stat] -fd=11 -group_fd=-1 -type=4 -config=1024 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-retiring (0x8000) -[event12:base-stat] -fd=12 -group_fd=11 -type=4 -config=32768 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-fe-bound (0x8200) -[event13:base-stat] -fd=13 -group_fd=11 -type=4 -config=33280 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-be-bound (0x8300) -[event14:base-stat] -fd=14 -group_fd=11 -type=4 -config=33536 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / topdown-bad-spec (0x8100) -[event15:base-stat] -fd=15 -group_fd=11 -type=4 -config=33024 -disabled=0 -enable_on_exec=0 -read_format=15 -optional=1 - -# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING -[event16:base-stat] -fd=16 -type=4 -config=4109 -optional=1 - -# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ -[event17:base-stat] -fd=17 -type=4 -config=17039629 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD -[event18:base-stat] -fd=18 -type=4 -config=60 -optional=1 - -# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY -[event19:base-stat] -fd=19 -type=4 -config=2097421 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK -[event20:base-stat] -fd=20 -type=4 -config=316 -optional=1 - -# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE -[event21:base-stat] -fd=21 -type=4 -config=412 -optional=1 - -# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE -[event22:base-stat] -fd=22 -type=4 -config=572 -optional=1 - -# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS -[event23:base-stat] -fd=23 -type=4 -config=706 -optional=1 - -# PERF_TYPE_RAW / UOPS_ISSUED.ANY -[event24:base-stat] -fd=24 -type=4 -config=270 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_L1D << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event25:base-stat] -fd=25 -type=3 -config=0 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_L1D << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event26:base-stat] -fd=26 -type=3 -config=65536 -optional=1 - -# PERF_TYPE_HW_CACHE / -# PERF_COUNT_HW_CACHE_LL << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event27:base-stat] -fd=27 -type=3 -config=2 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_LL << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event28:base-stat] -fd=28 -type=3 -config=65538 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_L1I << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event29:base-stat] -fd=29 -type=3 -config=1 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_L1I << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event30:base-stat] -fd=30 -type=3 -config=65537 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_DTLB << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event31:base-stat] -fd=31 -type=3 -config=3 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_DTLB << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event32:base-stat] -fd=32 -type=3 -config=65539 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_ITLB << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event33:base-stat] -fd=33 -type=3 -config=4 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_ITLB << 0 | -# (PERF_COUNT_HW_CACHE_OP_READ << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event34:base-stat] -fd=34 -type=3 -config=65540 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_L1D << 0 | -# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) -[event35:base-stat] -fd=35 -type=3 -config=512 -optional=1 - -# PERF_TYPE_HW_CACHE, -# PERF_COUNT_HW_CACHE_L1D << 0 | -# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | -# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) -[event36:base-stat] -fd=36 -type=3 -config=66048 -optional=1 diff --git a/tools/perf/tests/attr/test-stat-group1 b/tools/perf/tests/attr/test-stat-group1 deleted file mode 100644 index 1746751123dcb2..00000000000000 --- a/tools/perf/tests/attr/test-stat-group1 +++ /dev/null @@ -1,17 +0,0 @@ -[config] -command = stat -args = -e '{cycles,instructions}' kill >/dev/null 2>&1 -ret = 1 - -[event-1:base-stat] -fd=1 -group_fd=-1 -read_format=3|15 - -[event-2:base-stat] -fd=2 -group_fd=1 -config=1 -disabled=0 -enable_on_exec=0 -read_format=3|15 diff --git a/tools/perf/tests/attr/test-stat-no-inherit b/tools/perf/tests/attr/test-stat-no-inherit deleted file mode 100644 index 924fbb9300d162..00000000000000 --- a/tools/perf/tests/attr/test-stat-no-inherit +++ /dev/null @@ -1,8 +0,0 @@ -[config] -command = stat -args = -i -e cycles kill >/dev/null 2>&1 -ret = 1 - -[event:base-stat] -inherit=0 -optional=1 diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 470a9709427dda..4751dd3c6f672e 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -39,11 +40,8 @@ * making them easier to debug. */ static bool dont_fork; -/* Don't fork the tests in parallel and wait for their completion. */ -static bool sequential = true; -/* Do it in parallel, lacks infrastructure to avoid running tests that clash for resources, - * So leave it as the developers choice to enable while working on the needed infra */ -static bool parallel; +/* Fork the tests in parallel and wait for their completion. */ +static bool sequential; const char *dso_to_test; const char *test_objdump_path = "objdump"; @@ -73,13 +71,14 @@ static struct test_suite *generic_tests[] = { &suite__PERF_RECORD, &suite__pmu, &suite__pmu_events, + &suite__hwmon_pmu, + &suite__tool_pmu, &suite__dso_data, &suite__perf_evsel__roundtrip_name_test, #ifdef HAVE_LIBTRACEEVENT &suite__perf_evsel__tp_sched_test, &suite__syscall_openat_tp_fields, #endif - &suite__attr, &suite__hists_link, &suite__python_use, &suite__bp_signal, @@ -139,12 +138,6 @@ static struct test_suite *generic_tests[] = { NULL, }; -static struct test_suite **tests[] = { - generic_tests, - arch_tests, - NULL, /* shell tests created at runtime. */ -}; - static struct test_workload *workloads[] = { &workload__noploop, &workload__thloop, @@ -155,6 +148,9 @@ static struct test_workload *workloads[] = { &workload__landlock, }; +#define workloads__for_each(workload) \ + for (unsigned i = 0; i < ARRAY_SIZE(workloads) && ({ workload = workloads[i]; 1; }); i++) + static int num_subtests(const struct test_suite *t) { int num; @@ -198,6 +194,14 @@ static test_fnptr test_function(const struct test_suite *t, int subtest) return t->test_cases[subtest].run_case; } +static bool test_exclusive(const struct test_suite *t, int subtest) +{ + if (subtest <= 0) + return t->test_cases[0].exclusive; + + return t->test_cases[subtest].exclusive; +} + static bool perf_test__matches(const char *desc, int curr, int argc, const char *argv[]) { int i; @@ -229,20 +233,47 @@ struct child_test { int subtest; }; +static jmp_buf run_test_jmp_buf; + +static void child_test_sig_handler(int sig) +{ + siglongjmp(run_test_jmp_buf, sig); +} + static int run_test_child(struct child_process *process) { + const int signals[] = { + SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGINT, SIGPIPE, SIGQUIT, SIGSEGV, SIGTERM, + }; struct child_test *child = container_of(process, struct child_test, process); int err; + err = sigsetjmp(run_test_jmp_buf, 1); + if (err) { + fprintf(stderr, "\n---- unexpected signal (%d) ----\n", err); + err = err > 0 ? -err : -1; + goto err_out; + } + + for (size_t i = 0; i < ARRAY_SIZE(signals); i++) + signal(signals[i], child_test_sig_handler); + pr_debug("--- start ---\n"); pr_debug("test child forked, pid %d\n", getpid()); err = test_function(child->test, child->subtest)(child->test, child->subtest); pr_debug("---- end(%d) ----\n", err); + +err_out: fflush(NULL); + for (size_t i = 0; i < ARRAY_SIZE(signals); i++) + signal(signals[i], SIG_DFL); return -err; } -static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width) +#define TEST_RUNNING -3 + +static int print_test_result(struct test_suite *t, int i, int subtest, int result, int width, + int running) { if (has_subtests(t)) { int subw = width > 2 ? width - 2 : width; @@ -252,6 +283,9 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul pr_info("%3d: %-*s:", i + 1, width, test_description(t, subtest)); switch (result) { + case TEST_RUNNING: + color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d active)\n", running); + break; case TEST_OK: pr_info(" Ok\n"); break; @@ -273,16 +307,25 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resul return 0; } -static int finish_test(struct child_test *child_test, int width) +static void finish_test(struct child_test **child_tests, int running_test, int child_test_num, + int width) { - struct test_suite *t = child_test->test; - int i = child_test->test_num; - int subi = child_test->subtest; - int err = child_test->process.err; - bool err_done = err <= 0; + struct child_test *child_test = child_tests[running_test]; + struct test_suite *t; + int i, subi, err; + bool err_done = false; struct strbuf err_output = STRBUF_INIT; + int last_running = -1; int ret; + if (child_test == NULL) { + /* Test wasn't started. */ + return; + } + t = child_test->test; + i = child_test->test_num; + subi = child_test->subtest; + err = child_test->process.err; /* * For test suites with subtests, display the suite name ahead of the * sub test names. @@ -294,7 +337,7 @@ static int finish_test(struct child_test *child_test, int width) * Busy loop reading from the child's stdout/stderr that are set to be * non-blocking until EOF. */ - if (!err_done) + if (err > 0) fcntl(err, F_SETFL, O_NONBLOCK); if (verbose > 1) { if (has_subtests(t)) @@ -308,57 +351,90 @@ static int finish_test(struct child_test *child_test, int width) .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, }, }; - char buf[512]; - ssize_t len; + if (perf_use_color_default) { + int running = 0; - /* Poll to avoid excessive spinning, timeout set for 100ms. */ - poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); - if (!err_done && pfds[0].revents) { - errno = 0; - len = read(err, buf, sizeof(buf) - 1); + for (int y = running_test; y < child_test_num; y++) { + if (child_tests[y] == NULL) + continue; + if (check_if_command_finished(&child_tests[y]->process) == 0) + running++; + } + if (running != last_running) { + if (last_running != -1) { + /* + * Erase "Running (.. active)" line + * printed before poll/sleep. + */ + fprintf(debug_file(), PERF_COLOR_DELETE_LINE); + } + print_test_result(t, i, subi, TEST_RUNNING, width, running); + last_running = running; + } + } - if (len <= 0) { - err_done = errno != EAGAIN; - } else { - buf[len] = '\0'; - if (verbose > 1) - fprintf(stdout, "%s", buf); - else + err_done = true; + if (err <= 0) { + /* No child stderr to poll, sleep for 10ms for child to complete. */ + usleep(10 * 1000); + } else { + /* Poll to avoid excessive spinning, timeout set for 100ms. */ + poll(pfds, ARRAY_SIZE(pfds), /*timeout=*/100); + if (pfds[0].revents) { + char buf[512]; + ssize_t len; + + len = read(err, buf, sizeof(buf) - 1); + + if (len > 0) { + err_done = false; + buf[len] = '\0'; strbuf_addstr(&err_output, buf); + } } } + if (err_done) + err_done = check_if_command_finished(&child_test->process); + } + if (perf_use_color_default && last_running != -1) { + /* Erase "Running (.. active)" line printed before poll/sleep. */ + fprintf(debug_file(), PERF_COLOR_DELETE_LINE); } /* Clean up child process. */ ret = finish_command(&child_test->process); - if (verbose == 1 && ret == TEST_FAIL) { - /* Add header for test that was skipped above. */ - if (has_subtests(t)) - pr_info("%3d.%1d: %s:\n", i + 1, subi + 1, test_description(t, subi)); - else - pr_info("%3d: %s:\n", i + 1, test_description(t, -1)); + if (verbose > 1 || (verbose == 1 && ret == TEST_FAIL)) fprintf(stderr, "%s", err_output.buf); - } + strbuf_release(&err_output); - print_test_result(t, i, subi, ret, width); + print_test_result(t, i, subi, ret, width, /*running=*/0); if (err > 0) close(err); - return 0; + zfree(&child_tests[running_test]); } static int start_test(struct test_suite *test, int i, int subi, struct child_test **child, - int width) + int width, int pass) { int err; *child = NULL; if (dont_fork) { - pr_debug("--- start ---\n"); - err = test_function(test, subi)(test, subi); - pr_debug("---- end ----\n"); - print_test_result(test, i, subi, err, width); + if (pass == 1) { + pr_debug("--- start ---\n"); + err = test_function(test, subi)(test, subi); + pr_debug("---- end ----\n"); + print_test_result(test, i, subi, err, width, /*running=*/0); + } + return 0; + } + if (pass == 1 && !sequential && test_exclusive(test, subi)) { + /* When parallel, skip exclusive tests on the first pass. */ + return 0; + } + if (pass != 1 && (sequential || !test_exclusive(test, subi))) { + /* Sequential and non-exclusive tests were run on the first pass. */ return 0; } - *child = zalloc(sizeof(**child)); if (!*child) return -ENOMEM; @@ -377,35 +453,42 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes (*child)->process.err = -1; } (*child)->process.no_exec_cmd = run_test_child; - err = start_command(&(*child)->process); - if (err || !sequential) - return err; - return finish_test(*child, width); + if (sequential || pass == 2) { + err = start_command(&(*child)->process); + if (err) + return err; + finish_test(child, /*running_test=*/0, /*child_test_num=*/1, width); + return 0; + } + return start_command(&(*child)->process); } -#define for_each_test(j, k, t) \ - for (j = 0, k = 0; j < ARRAY_SIZE(tests); j++, k = 0) \ - while ((t = tests[j][k++]) != NULL) +/* State outside of __cmd_test for the sake of the signal handler. */ + +static size_t num_tests; +static struct child_test **child_tests; +static jmp_buf cmd_test_jmp_buf; -static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) +static void cmd_test_sig_handler(int sig) { - struct test_suite *t; - unsigned int j, k; - int i = 0; - int width = 0; - size_t num_tests = 0; - struct child_test **child_tests; - int child_test_num = 0; + siglongjmp(cmd_test_jmp_buf, sig); +} + +static int __cmd_test(struct test_suite **suites, int argc, const char *argv[], + struct intlist *skiplist) +{ + static int width = 0; + int err = 0; - for_each_test(j, k, t) { - int len = strlen(test_description(t, -1)); + for (struct test_suite **t = suites; *t; t++) { + int len = strlen(test_description(*t, -1)); if (width < len) width = len; - if (has_subtests(t)) { - for (int subi = 0, subn = num_subtests(t); subi < subn; subi++) { - len = strlen(test_description(t, subi)); + if (has_subtests(*t)) { + for (int subi = 0, subn = num_subtests(*t); subi < subn; subi++) { + len = strlen(test_description(*t, subi)); if (width < len) width = len; num_tests++; @@ -418,97 +501,137 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) if (!child_tests) return -ENOMEM; - for_each_test(j, k, t) { - int curr = i++; - - if (!perf_test__matches(test_description(t, -1), curr, argc, argv)) { - bool skip = true; + err = sigsetjmp(cmd_test_jmp_buf, 1); + if (err) { + pr_err("\nSignal (%d) while running tests.\nTerminating tests with the same signal\n", + err); + for (size_t x = 0; x < num_tests; x++) { + struct child_test *child_test = child_tests[x]; - for (int subi = 0, subn = num_subtests(t); subi < subn; subi++) { - if (perf_test__matches(test_description(t, subi), - curr, argc, argv)) - skip = false; - } - - if (skip) + if (!child_test || child_test->process.pid <= 0) continue; - } - if (intlist__find(skiplist, i)) { - pr_info("%3d: %-*s:", curr + 1, width, test_description(t, -1)); - color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); - continue; + pr_debug3("Killing %d pid %d\n", + child_test->test_num + 1, + child_test->process.pid); + kill(child_test->process.pid, err); } + goto err_out; + } + signal(SIGINT, cmd_test_sig_handler); + signal(SIGTERM, cmd_test_sig_handler); - if (!has_subtests(t)) { - int err = start_test(t, curr, -1, &child_tests[child_test_num++], width); + /* + * In parallel mode pass 1 runs non-exclusive tests in parallel, pass 2 + * runs the exclusive tests sequentially. In other modes all tests are + * run in pass 1. + */ + for (int pass = 1; pass <= 2; pass++) { + int child_test_num = 0; + int i = 0; + + for (struct test_suite **t = suites; *t; t++) { + int curr = i++; + + if (!perf_test__matches(test_description(*t, -1), curr, argc, argv)) { + /* + * Test suite shouldn't be run based on + * description. See if subtest should. + */ + bool skip = true; + + for (int subi = 0, subn = num_subtests(*t); subi < subn; subi++) { + if (perf_test__matches(test_description(*t, subi), + curr, argc, argv)) + skip = false; + } + + if (skip) + continue; + } - if (err) { - /* TODO: if !sequential waitpid the already forked children. */ - free(child_tests); - return err; + if (intlist__find(skiplist, i)) { + pr_info("%3d: %-*s:", curr + 1, width, test_description(*t, -1)); + color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); + continue; } - } else { - for (int subi = 0, subn = num_subtests(t); subi < subn; subi++) { - int err; - if (!perf_test__matches(test_description(t, subi), + if (!has_subtests(*t)) { + err = start_test(*t, curr, -1, &child_tests[child_test_num++], + width, pass); + if (err) + goto err_out; + continue; + } + for (int subi = 0, subn = num_subtests(*t); subi < subn; subi++) { + if (!perf_test__matches(test_description(*t, subi), curr, argc, argv)) continue; - err = start_test(t, curr, subi, &child_tests[child_test_num++], - width); + err = start_test(*t, curr, subi, &child_tests[child_test_num++], + width, pass); if (err) - return err; + goto err_out; } } - } - for (i = 0; i < child_test_num; i++) { if (!sequential) { - int ret = finish_test(child_tests[i], width); - - if (ret) - return ret; + /* Parallel mode starts tests but doesn't finish them. Do that now. */ + for (size_t x = 0; x < num_tests; x++) + finish_test(child_tests, x, num_tests, width); } - free(child_tests[i]); + } +err_out: + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + if (err) { + pr_err("Internal test harness failure. Completing any started tests:\n:"); + for (size_t x = 0; x < num_tests; x++) + finish_test(child_tests, x, num_tests, width); } free(child_tests); - return 0; + return err; } -static int perf_test__list(int argc, const char **argv) +static int perf_test__list(struct test_suite **suites, int argc, const char **argv) { - unsigned int j, k; - struct test_suite *t; int i = 0; - for_each_test(j, k, t) { + for (struct test_suite **t = suites; *t; t++) { int curr = i++; - if (!perf_test__matches(test_description(t, -1), curr, argc, argv)) + if (!perf_test__matches(test_description(*t, -1), curr, argc, argv)) continue; - pr_info("%3d: %s\n", i, test_description(t, -1)); + pr_info("%3d: %s\n", i, test_description(*t, -1)); - if (has_subtests(t)) { - int subn = num_subtests(t); + if (has_subtests(*t)) { + int subn = num_subtests(*t); int subi; for (subi = 0; subi < subn; subi++) pr_info("%3d:%1d: %s\n", i, subi + 1, - test_description(t, subi)); + test_description(*t, subi)); } } return 0; } +static int workloads__fprintf_list(FILE *fp) +{ + struct test_workload *twl; + int printed = 0; + + workloads__for_each(twl) + printed += fprintf(fp, "%s\n", twl->name); + + return printed; +} + static int run_workload(const char *work, int argc, const char **argv) { - unsigned int i = 0; struct test_workload *twl; - for (i = 0; i < ARRAY_SIZE(workloads); i++) { - twl = workloads[i]; + workloads__for_each(twl) { if (!strcmp(twl->name, work)) return twl->func(argc, argv); } @@ -526,6 +649,55 @@ static int perf_test__config(const char *var, const char *value, return 0; } +static struct test_suite **build_suites(void) +{ + /* + * TODO: suites is static to avoid needing to clean up the scripts tests + * for leak sanitizer. + */ + static struct test_suite **suites[] = { + generic_tests, + arch_tests, + NULL, + }; + struct test_suite **result; + struct test_suite *t; + size_t n = 0, num_suites = 0; + + if (suites[2] == NULL) + suites[2] = create_script_test_suites(); + +#define for_each_test(t) \ + for (size_t i = 0, j = 0; i < ARRAY_SIZE(suites); i++, j = 0) \ + while ((t = suites[i][j++]) != NULL) + + for_each_test(t) + num_suites++; + + result = calloc(num_suites + 1, sizeof(struct test_suite *)); + + for (int pass = 1; pass <= 2; pass++) { + for_each_test(t) { + bool exclusive = false; + + if (!has_subtests(t)) { + exclusive = test_exclusive(t, -1); + } else { + for (int subi = 0, subn = num_subtests(t); subi < subn; subi++) { + if (test_exclusive(t, subi)) { + exclusive = true; + break; + } + } + } + if ((!exclusive && pass == 1) || (exclusive && pass == 2)) + result[n++] = t; + } + } + return result; +#undef for_each_test +} + int cmd_test(int argc, const char **argv) { const char *test_usage[] = { @@ -534,16 +706,17 @@ int cmd_test(int argc, const char **argv) }; const char *skip = NULL; const char *workload = NULL; + bool list_workloads = false; const struct option test_options[] = { OPT_STRING('s', "skip", &skip, "tests", "tests to skip"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('F', "dont-fork", &dont_fork, "Do not fork for testcase"), - OPT_BOOLEAN('p', "parallel", ¶llel, "Run the tests in parallel"), OPT_BOOLEAN('S', "sequential", &sequential, "Run the tests one after another rather than in parallel"), - OPT_STRING('w', "workload", &workload, "work", "workload to run for testing"), + OPT_STRING('w', "workload", &workload, "work", "workload to run for testing, use '--list-workloads' to list the available ones."), + OPT_BOOLEAN(0, "list-workloads", &list_workloads, "List the available builtin workloads to use with -w/--workload"), OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"), OPT_STRING(0, "objdump", &test_objdump_path, "path", "objdump binary to use for disassembly and annotations"), @@ -552,6 +725,7 @@ int cmd_test(int argc, const char **argv) const char * const test_subcommands[] = { "list", NULL }; struct intlist *skiplist = NULL; int ret = hists__init(); + struct test_suite **suites; if (ret < 0) return ret; @@ -561,22 +735,29 @@ int cmd_test(int argc, const char **argv) /* Unbuffered output */ setvbuf(stdout, NULL, _IONBF, 0); - tests[2] = create_script_test_suites(); argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0); - if (argc >= 1 && !strcmp(argv[0], "list")) - return perf_test__list(argc - 1, argv + 1); + if (argc >= 1 && !strcmp(argv[0], "list")) { + suites = build_suites(); + ret = perf_test__list(suites, argc - 1, argv + 1); + free(suites); + return ret; + } if (workload) return run_workload(workload, argc, argv); + if (list_workloads) { + workloads__fprintf_list(stdout); + return 0; + } + if (dont_fork) sequential = true; - else if (parallel) - sequential = false; symbol_conf.priv_size = sizeof(int); symbol_conf.try_vmlinux_path = true; + if (symbol__init(NULL) < 0) return -1; @@ -588,5 +769,8 @@ int cmd_test(int argc, const char **argv) */ rlimit__bump_memlock(); - return __cmd_test(argc, argv, skiplist); + suites = build_suites(); + ret = __cmd_test(suites, argc, argv, skiplist); + free(suites); + return ret; } diff --git a/tools/perf/tests/demangle-java-test.c b/tools/perf/tests/demangle-java-test.c index 44d1be303b67ae..93c94408bdc8f0 100644 --- a/tools/perf/tests/demangle-java-test.c +++ b/tools/perf/tests/demangle-java-test.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "tests.h" #include "session.h" #include "debug.h" @@ -28,7 +29,7 @@ static int test__demangle_java(struct test_suite *test __maybe_unused, int subte "void java.lang.Object()" }, }; - for (i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) { + for (i = 0; i < ARRAY_SIZE(test_cases); i++) { buf = java_demangle_sym(test_cases[i].mangled, 0); if (strcmp(buf, test_cases[i].demangled)) { pr_debug("FAILED: %s: %s != %s\n", test_cases[i].mangled, diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index e155f0e0e04d55..deefe5003bfc29 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -126,6 +126,7 @@ static int attach__cpu_disabled(struct evlist *evlist) evsel->core.attr.disabled = 1; err = evsel__open_per_cpu(evsel, cpus, -1); + perf_cpu_map__put(cpus); if (err) { if (err == -EACCES) return TEST_SKIP; @@ -134,7 +135,6 @@ static int attach__cpu_disabled(struct evlist *evlist) return err; } - perf_cpu_map__put(cpus); return evsel__enable(evsel); } @@ -153,10 +153,10 @@ static int attach__cpu_enabled(struct evlist *evlist) } err = evsel__open_per_cpu(evsel, cpus, -1); + perf_cpu_map__put(cpus); if (err == -EACCES) return TEST_SKIP; - perf_cpu_map__put(cpus); return err ? TEST_FAIL : TEST_OK; } @@ -188,6 +188,7 @@ static int test_times(int (attach)(struct evlist *), err = attach(evlist); if (err == TEST_SKIP) { pr_debug(" SKIP : not enough rights\n"); + evlist__delete(evlist); return err; } diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index cf4da3d748c29f..226196fb967795 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include -#include +#include #include "evsel.h" #include "tests.h" #include "debug.h" @@ -36,33 +36,33 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse int subtest __maybe_unused) { struct evsel *evsel = evsel__newtp("sched", "sched_switch"); - int ret = 0; + int ret = TEST_OK; if (IS_ERR(evsel)) { pr_debug("evsel__newtp failed with %ld\n", PTR_ERR(evsel)); - return -1; + return PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL; } if (evsel__test_field(evsel, "prev_comm", 16, false)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "prev_pid", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "prev_prio", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "prev_state", sizeof(long), true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "next_comm", 16, false)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "next_pid", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "next_prio", 4, true)) - ret = -1; + ret = TEST_FAIL; evsel__delete(evsel); @@ -70,23 +70,33 @@ static int test__perf_evsel__tp_sched_test(struct test_suite *test __maybe_unuse if (IS_ERR(evsel)) { pr_debug("evsel__newtp failed with %ld\n", PTR_ERR(evsel)); - return -1; + return TEST_FAIL; } if (evsel__test_field(evsel, "comm", 16, false)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "pid", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "prio", 4, true)) - ret = -1; + ret = TEST_FAIL; if (evsel__test_field(evsel, "target_cpu", 4, true)) - ret = -1; + ret = TEST_FAIL; evsel__delete(evsel); return ret; } -DEFINE_SUITE("Parse sched tracepoints fields", perf_evsel__tp_sched_test); +static struct test_case tests__perf_evsel__tp_sched_test[] = { + TEST_CASE_REASON("Parse sched tracepoints fields", + perf_evsel__tp_sched_test, + "permissions"), + { .name = NULL, } +}; + +struct test_suite suite__perf_evsel__tp_sched_test = { + .desc = "Parse sched tracepoints fields", + .test_cases = tests__perf_evsel__tp_sched_test, +}; diff --git a/tools/perf/tests/expr.c b/tools/perf/tests/expr.c index e3aa9d4fcf3a56..726cf8d4da28d8 100644 --- a/tools/perf/tests/expr.c +++ b/tools/perf/tests/expr.c @@ -6,6 +6,7 @@ #include "util/header.h" #include "util/smt.h" #include "tests.h" +#include #include #include #include @@ -74,14 +75,12 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u double val, num_cpus_online, num_cpus, num_cores, num_dies, num_packages; int ret; struct expr_parse_ctx *ctx; - bool is_intel = false; char strcmp_cpuid_buf[256]; - struct perf_pmu *pmu = perf_pmus__find_core_pmu(); - char *cpuid = perf_pmu__getcpuid(pmu); + struct perf_cpu cpu = {-1}; + char *cpuid = get_cpuid_allow_env_override(cpu); char *escaped_cpuid1, *escaped_cpuid2; TEST_ASSERT_VAL("get_cpuid", cpuid); - is_intel = strstr(cpuid, "Intel") != NULL; TEST_ASSERT_EQUAL("ids_union", test_ids_union(), 0); @@ -244,12 +243,19 @@ static int test__expr(struct test_suite *t __maybe_unused, int subtest __maybe_u if (num_dies) // Some platforms do not have CPU die support, for example s390 TEST_ASSERT_VAL("#num_dies >= #num_packages", num_dies >= num_packages); - TEST_ASSERT_VAL("#system_tsc_freq", expr__parse(&val, ctx, "#system_tsc_freq") == 0); - if (is_intel) - TEST_ASSERT_VAL("#system_tsc_freq > 0", val > 0); - else - TEST_ASSERT_VAL("#system_tsc_freq == 0", fpclassify(val) == FP_ZERO); + if (expr__parse(&val, ctx, "#system_tsc_freq") == 0) { + bool is_intel = strstr(cpuid, "Intel") != NULL; + + if (is_intel) + TEST_ASSERT_VAL("#system_tsc_freq > 0", val > 0); + else + TEST_ASSERT_VAL("#system_tsc_freq == 0", fpclassify(val) == FP_ZERO); + } else { +#if defined(__i386__) || defined(__x86_64__) + TEST_ASSERT_VAL("#system_tsc_freq unsupported", 0); +#endif + } /* * Source count returns the number of events aggregating in a leader * event including the leader. Check parsing yields an id. diff --git a/tools/perf/tests/hwmon_pmu.c b/tools/perf/tests/hwmon_pmu.c new file mode 100644 index 00000000000000..d2b066a2b557aa --- /dev/null +++ b/tools/perf/tests/hwmon_pmu.c @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +#include "debug.h" +#include "evlist.h" +#include "hwmon_pmu.h" +#include "parse-events.h" +#include "tests.h" +#include +#include +#include +#include +#include + +static const struct test_event { + const char *name; + const char *alias; + long config; +} test_events[] = { + { + "temp_test_hwmon_event1", + "temp1", + 0xA0001, + }, + { + "temp_test_hwmon_event2", + "temp2", + 0xA0002, + }, +}; + +/* Cleanup test PMU directory. */ +static int test_pmu_put(const char *dir, struct perf_pmu *hwm) +{ + char buf[PATH_MAX + 20]; + int ret; + + if (scnprintf(buf, sizeof(buf), "rm -fr %s", dir) < 0) { + pr_err("Failure to set up buffer for \"%s\"\n", dir); + return -EINVAL; + } + ret = system(buf); + if (ret) + pr_err("Failure to \"%s\"\n", buf); + + list_del(&hwm->list); + perf_pmu__delete(hwm); + return ret; +} + +/* + * Prepare test PMU directory data, normally exported by kernel at + * /sys/class/hwmon/hwmon/. Give as input a buffer to hold the file + * path, the result is PMU loaded using that directory. + */ +static struct perf_pmu *test_pmu_get(char *dir, size_t sz) +{ + const char *test_hwmon_name_nl = "A test hwmon PMU\n"; + const char *test_hwmon_name = "A test hwmon PMU"; + /* Simulated hwmon items. */ + const struct test_item { + const char *name; + const char *value; + } test_items[] = { + { "temp1_label", "test hwmon event1\n", }, + { "temp1_input", "40000\n", }, + { "temp2_label", "test hwmon event2\n", }, + { "temp2_input", "50000\n", }, + }; + int hwmon_dirfd = -1, test_dirfd = -1, file; + struct perf_pmu *hwm = NULL; + ssize_t len; + + /* Create equivalent of sysfs mount point. */ + scnprintf(dir, sz, "/tmp/perf-hwmon-pmu-test-XXXXXX"); + if (!mkdtemp(dir)) { + pr_err("mkdtemp failed\n"); + dir[0] = '\0'; + return NULL; + } + test_dirfd = open(dir, O_PATH|O_DIRECTORY); + if (test_dirfd < 0) { + pr_err("Failed to open test directory \"%s\"\n", dir); + goto err_out; + } + + /* Create the test hwmon directory and give it a name. */ + if (mkdirat(test_dirfd, "hwmon1234", 0755) < 0) { + pr_err("Failed to mkdir hwmon directory\n"); + goto err_out; + } + hwmon_dirfd = openat(test_dirfd, "hwmon1234", O_DIRECTORY); + if (hwmon_dirfd < 0) { + pr_err("Failed to open test hwmon directory \"%s/hwmon1234\"\n", dir); + goto err_out; + } + file = openat(hwmon_dirfd, "name", O_WRONLY | O_CREAT, 0600); + if (file < 0) { + pr_err("Failed to open for writing file \"name\"\n"); + goto err_out; + } + len = strlen(test_hwmon_name_nl); + if (write(file, test_hwmon_name_nl, len) < len) { + close(file); + pr_err("Failed to write to 'name' file\n"); + goto err_out; + } + close(file); + + /* Create test hwmon files. */ + for (size_t i = 0; i < ARRAY_SIZE(test_items); i++) { + const struct test_item *item = &test_items[i]; + + file = openat(hwmon_dirfd, item->name, O_WRONLY | O_CREAT, 0600); + if (file < 0) { + pr_err("Failed to open for writing file \"%s\"\n", item->name); + goto err_out; + } + + if (write(file, item->value, strlen(item->value)) < 0) { + pr_err("Failed to write to file \"%s\"\n", item->name); + close(file); + goto err_out; + } + close(file); + } + + /* Make the PMU reading the files created above. */ + hwm = perf_pmus__add_test_hwmon_pmu(hwmon_dirfd, "hwmon1234", test_hwmon_name); + if (!hwm) + pr_err("Test hwmon creation failed\n"); + +err_out: + if (!hwm) { + test_pmu_put(dir, hwm); + if (hwmon_dirfd >= 0) + close(hwmon_dirfd); + } + if (test_dirfd >= 0) + close(test_dirfd); + return hwm; +} + +static int do_test(size_t i, bool with_pmu, bool with_alias) +{ + const char *test_event = with_alias ? test_events[i].alias : test_events[i].name; + struct evlist *evlist = evlist__new(); + struct evsel *evsel; + struct parse_events_error err; + int ret; + char str[128]; + bool found = false; + + if (!evlist) { + pr_err("evlist allocation failed\n"); + return TEST_FAIL; + } + + if (with_pmu) + snprintf(str, sizeof(str), "hwmon_a_test_hwmon_pmu/%s/", test_event); + else + strlcpy(str, test_event, sizeof(str)); + + pr_debug("Testing '%s'\n", str); + parse_events_error__init(&err); + ret = parse_events(evlist, str, &err); + if (ret) { + pr_debug("FAILED %s:%d failed to parse event '%s', err %d\n", + __FILE__, __LINE__, str, ret); + parse_events_error__print(&err, str); + ret = TEST_FAIL; + goto out; + } + + ret = TEST_OK; + if (with_pmu ? (evlist->core.nr_entries != 1) : (evlist->core.nr_entries < 1)) { + pr_debug("FAILED %s:%d Unexpected number of events for '%s' of %d\n", + __FILE__, __LINE__, str, evlist->core.nr_entries); + ret = TEST_FAIL; + goto out; + } + + evlist__for_each_entry(evlist, evsel) { + if (!evsel->pmu || !evsel->pmu->name || + strcmp(evsel->pmu->name, "hwmon_a_test_hwmon_pmu")) + continue; + + if (evsel->core.attr.config != (u64)test_events[i].config) { + pr_debug("FAILED %s:%d Unexpected config for '%s', %lld != %ld\n", + __FILE__, __LINE__, str, + evsel->core.attr.config, + test_events[i].config); + ret = TEST_FAIL; + goto out; + } + found = true; + } + + if (!found) { + pr_debug("FAILED %s:%d Didn't find hwmon event '%s' in parsed evsels\n", + __FILE__, __LINE__, str); + ret = TEST_FAIL; + } + +out: + parse_events_error__exit(&err); + evlist__delete(evlist); + return ret; +} + +static int test__hwmon_pmu(bool with_pmu) +{ + char dir[PATH_MAX]; + struct perf_pmu *pmu = test_pmu_get(dir, sizeof(dir)); + int ret = TEST_OK; + + if (!pmu) + return TEST_FAIL; + + for (size_t i = 0; i < ARRAY_SIZE(test_events); i++) { + ret = do_test(i, with_pmu, /*with_alias=*/false); + + if (ret != TEST_OK) + break; + + ret = do_test(i, with_pmu, /*with_alias=*/true); + + if (ret != TEST_OK) + break; + } + test_pmu_put(dir, pmu); + return ret; +} + +static int test__hwmon_pmu_without_pmu(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + return test__hwmon_pmu(/*with_pmu=*/false); +} + +static int test__hwmon_pmu_with_pmu(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + return test__hwmon_pmu(/*with_pmu=*/true); +} + +static int test__parse_hwmon_filename(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + const struct hwmon_parse_test { + const char *filename; + enum hwmon_type type; + int number; + enum hwmon_item item; + bool alarm; + bool parse_ok; + } tests[] = { + { + .filename = "cpu0_accuracy", + .type = HWMON_TYPE_CPU, + .number = 0, + .item = HWMON_ITEM_ACCURACY, + .alarm = false, + .parse_ok = true, + }, + { + .filename = "temp1_input", + .type = HWMON_TYPE_TEMP, + .number = 1, + .item = HWMON_ITEM_INPUT, + .alarm = false, + .parse_ok = true, + }, + { + .filename = "fan2_vid", + .type = HWMON_TYPE_FAN, + .number = 2, + .item = HWMON_ITEM_VID, + .alarm = false, + .parse_ok = true, + }, + { + .filename = "power3_crit_alarm", + .type = HWMON_TYPE_POWER, + .number = 3, + .item = HWMON_ITEM_CRIT, + .alarm = true, + .parse_ok = true, + }, + { + .filename = "intrusion4_average_interval_min_alarm", + .type = HWMON_TYPE_INTRUSION, + .number = 4, + .item = HWMON_ITEM_AVERAGE_INTERVAL_MIN, + .alarm = true, + .parse_ok = true, + }, + { + .filename = "badtype5_baditem", + .type = HWMON_TYPE_NONE, + .number = 5, + .item = HWMON_ITEM_NONE, + .alarm = false, + .parse_ok = false, + }, + { + .filename = "humidity6_baditem", + .type = HWMON_TYPE_NONE, + .number = 6, + .item = HWMON_ITEM_NONE, + .alarm = false, + .parse_ok = false, + }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(tests); i++) { + enum hwmon_type type; + int number; + enum hwmon_item item; + bool alarm; + + TEST_ASSERT_EQUAL("parse_hwmon_filename", + parse_hwmon_filename( + tests[i].filename, + &type, + &number, + &item, + &alarm), + tests[i].parse_ok + ); + if (tests[i].parse_ok) { + TEST_ASSERT_EQUAL("parse_hwmon_filename type", type, tests[i].type); + TEST_ASSERT_EQUAL("parse_hwmon_filename number", number, tests[i].number); + TEST_ASSERT_EQUAL("parse_hwmon_filename item", item, tests[i].item); + TEST_ASSERT_EQUAL("parse_hwmon_filename alarm", alarm, tests[i].alarm); + } + } + return TEST_OK; +} + +static struct test_case tests__hwmon_pmu[] = { + TEST_CASE("Basic parsing test", parse_hwmon_filename), + TEST_CASE("Parsing without PMU name", hwmon_pmu_without_pmu), + TEST_CASE("Parsing with PMU name", hwmon_pmu_with_pmu), + { .name = NULL, } +}; + +struct test_suite suite__hwmon_pmu = { + .desc = "Hwmon PMU", + .test_cases = tests__hwmon_pmu, +}; diff --git a/tools/perf/tests/make b/tools/perf/tests/make index a5040772043f63..a7fcbd589752a9 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -81,7 +81,7 @@ make_no_gtk2 := NO_GTK2=1 make_no_ui := NO_SLANG=1 NO_GTK2=1 make_no_demangle := NO_DEMANGLE=1 make_no_libelf := NO_LIBELF=1 -make_no_libunwind := NO_LIBUNWIND=1 +make_libunwind := LIBUNWIND=1 make_no_libdw_dwarf_unwind := NO_LIBDW_DWARF_UNWIND=1 make_no_backtrace := NO_BACKTRACE=1 make_no_libcapstone := NO_CAPSTONE=1 @@ -121,7 +121,7 @@ make_static := LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX3 # all the NO_* variable combined make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_GTK2=1 -make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 +make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_BACKTRACE=1 make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1 NO_LIBZSTD=1 @@ -153,7 +153,7 @@ run += make_no_gtk2 run += make_no_ui run += make_no_demangle run += make_no_libelf -run += make_no_libunwind +run += make_libunwind run += make_no_libdw_dwarf_unwind run += make_no_backtrace run += make_no_libcapstone diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 888df8eca98121..3943da441979c0 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -40,7 +40,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused int flags = O_RDONLY | O_DIRECTORY; struct evlist *evlist = evlist__new(); struct evsel *evsel; - int err = -1, i, nr_events = 0, nr_polls = 0; + int ret = TEST_FAIL, err, i, nr_events = 0, nr_polls = 0; char sbuf[STRERR_BUFSIZE]; if (evlist == NULL) { @@ -51,6 +51,7 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused evsel = evsel__newtp("syscalls", "sys_enter_openat"); if (IS_ERR(evsel)) { pr_debug("%s: evsel__newtp\n", __func__); + ret = PTR_ERR(evsel) == -EACCES ? TEST_SKIP : TEST_FAIL; goto out_delete_evlist; } @@ -138,11 +139,21 @@ static int test__syscall_openat_tp_fields(struct test_suite *test __maybe_unused } } out_ok: - err = 0; + ret = TEST_OK; out_delete_evlist: evlist__delete(evlist); out: - return err; + return ret; } -DEFINE_SUITE("syscalls:sys_enter_openat event fields", syscall_openat_tp_fields); +static struct test_case tests__syscall_openat_tp_fields[] = { + TEST_CASE_REASON("syscalls:sys_enter_openat event fields", + syscall_openat_tp_fields, + "permissions"), + { .name = NULL, } +}; + +struct test_suite suite__syscall_openat_tp_fields = { + .desc = "syscalls:sys_enter_openat event fields", + .test_cases = tests__syscall_openat_tp_fields, +}; diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 9e3086d0215089..82a19674a38f77 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -730,7 +730,7 @@ static int test__checkevent_pmu_events(struct evlist *evlist) TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type || - strcmp(evsel->pmu_name, "cpu")); + strcmp(evsel->pmu->name, "cpu")); TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", @@ -898,8 +898,7 @@ static int test__group1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); @@ -932,7 +931,7 @@ static int test__group2(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); @@ -947,7 +946,7 @@ static int test__group2(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); if (evsel__has_leader(evsel, leader)) @@ -1016,9 +1015,8 @@ static int test__group3(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - /* use of precise requires exclude_guest */ TEST_ASSERT_VAL("wrong exclude guest", - evsel->core.attr.exclude_guest); + !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", @@ -1072,7 +1070,7 @@ static int test__group3(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); @@ -1103,8 +1101,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 1); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); @@ -1122,8 +1119,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - /* use of precise requires exclude_guest */ - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", evsel->core.attr.precise_ip == 2); TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); @@ -1222,7 +1218,7 @@ static int test__group5(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel__is_group_leader(evsel)); @@ -1437,7 +1433,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); @@ -1453,7 +1449,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); @@ -1468,7 +1464,7 @@ static int test__leader_sample1(struct evlist *evlist) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); @@ -1497,7 +1493,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); @@ -1513,7 +1509,7 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv); - TEST_ASSERT_VAL("wrong exclude guest", evsel->core.attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude guest", !evsel->core.attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude host", !evsel->core.attr.exclude_host); TEST_ASSERT_VAL("wrong precise_ip", !evsel->core.attr.precise_ip); TEST_ASSERT_VAL("wrong group name", !evsel->group_name); diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index be18506f6a2425..6a681e3fb552d6 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c @@ -176,7 +176,8 @@ static int test__pmu_format(struct test_suite *test __maybe_unused, int subtest } memset(&attr, 0, sizeof(attr)); - ret = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/false, /*err=*/NULL); + ret = perf_pmu__config_terms(pmu, &attr, &terms, /*zero=*/false, + /*apply_hardcoded=*/false, /*err=*/NULL); if (ret) { pr_err("perf_pmu__config_terms failed"); goto err_out; diff --git a/tools/perf/tests/shell/annotate.sh b/tools/perf/tests/shell/annotate.sh index 2ccf4f1d46b60d..1590a37363deb7 100755 --- a/tools/perf/tests/shell/annotate.sh +++ b/tools/perf/tests/shell/annotate.sh @@ -44,7 +44,7 @@ test_basic() { fi # Generate the annotated output file - perf annotate -i "${perfdata}" --stdio 2> /dev/null > "${perfout}" + perf annotate --no-demangle -i "${perfdata}" --stdio 2> /dev/null | head -250 > "${perfout}" # check if it has the target symbol if ! grep "${testsym}" "${perfout}" @@ -63,8 +63,8 @@ test_basic() { fi # check again with a target symbol name - if ! perf annotate -i "${perfdata}" "${testsym}" 2> /dev/null | \ - grep -m 3 "${disasm_regex}" + if ! perf annotate --no-demangle -i "${perfdata}" "${testsym}" 2> /dev/null | \ + head -250 | grep -m 3 "${disasm_regex}" then echo "Basic annotate [Failed: missing disasm output when specifying the target symbol]" err=1 @@ -72,8 +72,8 @@ test_basic() { fi # check one more with external objdump tool (forced by --objdump option) - if ! perf annotate -i "${perfdata}" --objdump=objdump 2> /dev/null | \ - grep -m 3 "${disasm_regex}" + if ! perf annotate --no-demangle -i "${perfdata}" --objdump=objdump 2> /dev/null | \ + head -250 | grep -m 3 "${disasm_regex}" then echo "Basic annotate [Failed: missing disasm output from non default disassembler (using --objdump)]" err=1 diff --git a/tools/perf/tests/shell/attr.sh b/tools/perf/tests/shell/attr.sh new file mode 100755 index 00000000000000..5a4e43b2471de8 --- /dev/null +++ b/tools/perf/tests/shell/attr.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Perf attribute expectations test +# SPDX-License-Identifier: GPL-2.0 + +err=0 + +cleanup() { + trap - EXIT TERM INT +} + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup + exit 1 +} +trap trap_cleanup EXIT TERM INT + +shelldir=$(dirname "$0") +perf_path=$(which perf) +python "${shelldir}"/lib/attr.py -d "${shelldir}"/attr -v -p "$perf_path" +cleanup +exit $err diff --git a/tools/perf/tests/shell/attr/README b/tools/perf/tests/shell/attr/README new file mode 100644 index 00000000000000..67c4ca76b85d56 --- /dev/null +++ b/tools/perf/tests/shell/attr/README @@ -0,0 +1,71 @@ +The struct perf_event_attr test (attr tests) support +==================================================== +This testing support is embedded into perf directly and is governed +by the PERF_TEST_ATTR environment variable and hook inside the +sys_perf_event_open function. + +The general idea is to store 'struct perf_event_attr' details for +each event created within single perf command. Each event details +are stored into separate text file. Once perf command is finished +these files are checked for values we expect for command. + +The attr tests consist of following parts: + +tests/attr.c +------------ +This is the sys_perf_event_open hook implementation. The hook +is triggered when the PERF_TEST_ATTR environment variable is +defined. It must contain name of existing directory with access +and write permissions. + +For each sys_perf_event_open call event details are stored in +separate file. Besides 'struct perf_event_attr' values we also +store 'fd' and 'group_fd' values to allow checking for groups. + +tests/attr.py +------------- +This is the python script that does all the hard work. It reads +the test definition, executes it and checks results. + +tests/attr/ +----------- +Directory containing all attr test definitions. +Following tests are defined (with perf commands): + + perf record kill (test-record-basic) + perf record -b kill (test-record-branch-any) + perf record -j any kill (test-record-branch-filter-any) + perf record -j any_call kill (test-record-branch-filter-any_call) + perf record -j any_ret kill (test-record-branch-filter-any_ret) + perf record -j hv kill (test-record-branch-filter-hv) + perf record -j ind_call kill (test-record-branch-filter-ind_call) + perf record -j k kill (test-record-branch-filter-k) + perf record -j u kill (test-record-branch-filter-u) + perf record -c 123 kill (test-record-count) + perf record -d kill (test-record-data) + perf record -F 100 kill (test-record-freq) + perf record -g kill (test-record-graph-default) + perf record -g kill (test-record-graph-default-aarch64) + perf record --call-graph dwarf kill (test-record-graph-dwarf) + perf record --call-graph fp kill (test-record-graph-fp) + perf record --call-graph fp kill (test-record-graph-fp-aarch64) + perf record -e '{cycles,instructions}' kill (test-record-group1) + perf record -e '{cycles/period=1/,instructions/period=2/}:S' kill (test-record-group2) + perf record -e '{cycles,cache-misses}:S' kill (test-record-group-sampling1) + perf record -c 10000 -e '{cycles,cache-misses}:S' kill (test-record-group-sampling2) + perf record -D kill (test-record-no-delay) + perf record -i kill (test-record-no-inherit) + perf record -n kill (test-record-no-samples) + perf record -c 100 -P kill (test-record-period) + perf record -c 1 --pfm-events=cycles:period=2 (test-record-pfm-period) + perf record -R kill (test-record-raw) + perf record -c 2 -e arm_spe_0// -- kill (test-record-spe-period) + perf record -e arm_spe_0/period=3/ -- kill (test-record-spe-period-term) + perf record -e arm_spe_0/pa_enable=1/ -- kill (test-record-spe-physical-address) + perf stat -e cycles kill (test-stat-basic) + perf stat kill (test-stat-default) + perf stat -d kill (test-stat-detailed-1) + perf stat -dd kill (test-stat-detailed-2) + perf stat -ddd kill (test-stat-detailed-3) + perf stat -e '{cycles,instructions}' kill (test-stat-group1) + perf stat -i -e cycles kill (test-stat-no-inherit) diff --git a/tools/perf/tests/shell/attr/base-record b/tools/perf/tests/shell/attr/base-record new file mode 100644 index 00000000000000..b44e4e6e444386 --- /dev/null +++ b/tools/perf/tests/shell/attr/base-record @@ -0,0 +1,41 @@ +[event] +fd=1 +group_fd=-1 +# 0 or PERF_FLAG_FD_CLOEXEC flag +flags=0|8 +cpu=* +type=0|1 +size=136 +config=0|1 +sample_period=* +sample_type=263 +read_format=0|4|20 +disabled=1 +inherit=1 +pinned=0 +exclusive=0 +exclude_user=0 +exclude_kernel=0|1 +exclude_hv=0|1 +exclude_idle=0 +mmap=1 +comm=1 +freq=1 +inherit_stat=0 +enable_on_exec=1 +task=1 +watermark=0 +precise_ip=0|1|2|3 +mmap_data=0 +sample_id_all=1 +exclude_host=0|1 +exclude_guest=0|1 +exclude_callchain_kernel=0 +exclude_callchain_user=0 +wakeup_events=0 +bp_type=0 +config1=0 +config2=0 +branch_sample_type=0 +sample_regs_user=0 +sample_stack_user=0 diff --git a/tools/perf/tests/shell/attr/base-record-spe b/tools/perf/tests/shell/attr/base-record-spe new file mode 100644 index 00000000000000..08fa96b5924057 --- /dev/null +++ b/tools/perf/tests/shell/attr/base-record-spe @@ -0,0 +1,40 @@ +[event] +fd=* +group_fd=-1 +flags=* +cpu=* +type=* +size=* +config=* +sample_period=* +sample_type=* +read_format=* +disabled=* +inherit=* +pinned=* +exclusive=* +exclude_user=* +exclude_kernel=* +exclude_hv=* +exclude_idle=* +mmap=* +comm=* +freq=* +inherit_stat=* +enable_on_exec=* +task=* +watermark=* +precise_ip=* +mmap_data=* +sample_id_all=* +exclude_host=* +exclude_guest=* +exclude_callchain_kernel=* +exclude_callchain_user=* +wakeup_events=* +bp_type=* +config1=* +config2=* +branch_sample_type=* +sample_regs_user=* +sample_stack_user=* diff --git a/tools/perf/tests/shell/attr/base-stat b/tools/perf/tests/shell/attr/base-stat new file mode 100644 index 00000000000000..fccd8ec4d1b022 --- /dev/null +++ b/tools/perf/tests/shell/attr/base-stat @@ -0,0 +1,41 @@ +[event] +fd=1 +group_fd=-1 +# 0 or PERF_FLAG_FD_CLOEXEC flag +flags=0|8 +cpu=* +type=0 +size=136 +config=0 +sample_period=0 +sample_type=65536 +read_format=3 +disabled=1 +inherit=1 +pinned=0 +exclusive=0 +exclude_user=0 +exclude_kernel=0|1 +exclude_hv=0|1 +exclude_idle=0 +mmap=0 +comm=0 +freq=0 +inherit_stat=0 +enable_on_exec=1 +task=0 +watermark=0 +precise_ip=0 +mmap_data=0 +sample_id_all=0 +exclude_host=0|1 +exclude_guest=0|1 +exclude_callchain_kernel=0 +exclude_callchain_user=0 +wakeup_events=0 +bp_type=0 +config1=0 +config2=0 +branch_sample_type=0 +sample_regs_user=0 +sample_stack_user=0 diff --git a/tools/perf/tests/shell/attr/system-wide-dummy b/tools/perf/tests/shell/attr/system-wide-dummy new file mode 100644 index 00000000000000..a1e1d6a263bf14 --- /dev/null +++ b/tools/perf/tests/shell/attr/system-wide-dummy @@ -0,0 +1,52 @@ +# Event added by system-wide or CPU perf-record to handle the race of +# processes starting while /proc is processed. +[event] +fd=1 +group_fd=-1 +cpu=* +pid=-1 +flags=8 +type=1 +size=136 +config=9 +sample_period=1 +# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | +# PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER +sample_type=65671 +read_format=4|20 +# Event will be enabled right away. +disabled=0 +inherit=1 +pinned=0 +exclusive=0 +exclude_user=0 +exclude_kernel=1 +exclude_hv=1 +exclude_idle=0 +mmap=1 +comm=1 +freq=0 +inherit_stat=0 +enable_on_exec=0 +task=1 +watermark=0 +precise_ip=0 +mmap_data=0 +sample_id_all=1 +exclude_host=0 +exclude_guest=1 +exclude_callchain_kernel=0 +exclude_callchain_user=0 +mmap2=1 +comm_exec=1 +context_switch=0 +write_backward=0 +namespaces=0 +use_clockid=0 +wakeup_events=0 +bp_type=0 +config1=0 +config2=0 +branch_sample_type=0 +sample_regs_user=0 +sample_stack_user=0 diff --git a/tools/perf/tests/shell/attr/test-record-C0 b/tools/perf/tests/shell/attr/test-record-C0 new file mode 100644 index 00000000000000..1049ac8b52f27f --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-C0 @@ -0,0 +1,24 @@ +[config] +command = record +args = --no-bpf-event -C 0 kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +cpu=0 + +# no enable on exec for CPU attached +enable_on_exec=0 + +# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | +# PERF_SAMPLE_PERIOD | PERF_SAMPLE_IDENTIFIER +# + PERF_SAMPLE_CPU added by -C 0 +sample_type=65927 + +# Dummy event handles mmaps, comm and task. +mmap=0 +comm=0 +task=0 +inherit=0 + +[event:system-wide-dummy] +inherit=0 diff --git a/tools/perf/tests/shell/attr/test-record-basic b/tools/perf/tests/shell/attr/test-record-basic new file mode 100644 index 00000000000000..b0ca42a5ecc9ce --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-basic @@ -0,0 +1,6 @@ +[config] +command = record +args = --no-bpf-event kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] diff --git a/tools/perf/tests/shell/attr/test-record-branch-any b/tools/perf/tests/shell/attr/test-record-branch-any new file mode 100644 index 00000000000000..1a99b3ce6b899c --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-branch-any @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -b kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=2311 +branch_sample_type=8 diff --git a/tools/perf/tests/shell/attr/test-record-branch-filter-any b/tools/perf/tests/shell/attr/test-record-branch-filter-any new file mode 100644 index 00000000000000..709768b508c624 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-any @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -j any kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=2311 +branch_sample_type=8 diff --git a/tools/perf/tests/shell/attr/test-record-branch-filter-any_call b/tools/perf/tests/shell/attr/test-record-branch-filter-any_call new file mode 100644 index 00000000000000..f943221f782543 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-any_call @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -j any_call kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=2311 +branch_sample_type=16 diff --git a/tools/perf/tests/shell/attr/test-record-branch-filter-any_ret b/tools/perf/tests/shell/attr/test-record-branch-filter-any_ret new file mode 100644 index 00000000000000..fd4f5b4154a9d3 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-any_ret @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -j any_ret kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=2311 +branch_sample_type=32 diff --git a/tools/perf/tests/shell/attr/test-record-branch-filter-hv b/tools/perf/tests/shell/attr/test-record-branch-filter-hv new file mode 100644 index 00000000000000..4e52d685ebe172 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-hv @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -j hv kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=2311 +branch_sample_type=8 diff --git a/tools/perf/tests/shell/attr/test-record-branch-filter-ind_call b/tools/perf/tests/shell/attr/test-record-branch-filter-ind_call new file mode 100644 index 00000000000000..e08c6ab3796e01 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-ind_call @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -j ind_call kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=2311 +branch_sample_type=64 diff --git a/tools/perf/tests/shell/attr/test-record-branch-filter-k b/tools/perf/tests/shell/attr/test-record-branch-filter-k new file mode 100644 index 00000000000000..b4b98f84fc2f75 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-k @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -j k kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=2311 +branch_sample_type=8 diff --git a/tools/perf/tests/shell/attr/test-record-branch-filter-u b/tools/perf/tests/shell/attr/test-record-branch-filter-u new file mode 100644 index 00000000000000..fb9610edbb0d7e --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-branch-filter-u @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -j u kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=2311 +branch_sample_type=8 diff --git a/tools/perf/tests/shell/attr/test-record-count b/tools/perf/tests/shell/attr/test-record-count new file mode 100644 index 00000000000000..5e9b9019d7865c --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-count @@ -0,0 +1,9 @@ +[config] +command = record +args = --no-bpf-event -c 123 kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_period=123 +sample_type=7 +freq=0 diff --git a/tools/perf/tests/shell/attr/test-record-data b/tools/perf/tests/shell/attr/test-record-data new file mode 100644 index 00000000000000..a99bb13149c20d --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-data @@ -0,0 +1,10 @@ +[config] +command = record +args = --no-bpf-event -d kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +# sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | +# PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC +sample_type=33039 +mmap_data=1 diff --git a/tools/perf/tests/shell/attr/test-record-dummy-C0 b/tools/perf/tests/shell/attr/test-record-dummy-C0 new file mode 100644 index 00000000000000..91499405fff4d3 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-dummy-C0 @@ -0,0 +1,55 @@ +[config] +command = record +args = --no-bpf-event -e dummy -C 0 kill >/dev/null 2>&1 +ret = 1 + +[event] +fd=1 +group_fd=-1 +cpu=0 +pid=-1 +flags=8 +type=1 +size=136 +config=9 +sample_period=4000 +# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | +# PERF_SAMPLE_PERIOD +# + PERF_SAMPLE_CPU added by -C 0 +sample_type=391 +read_format=4|20 +disabled=0 +inherit=0 +pinned=0 +exclusive=0 +exclude_user=0 +exclude_kernel=0 +exclude_hv=0 +exclude_idle=0 +mmap=1 +comm=1 +freq=1 +inherit_stat=0 +enable_on_exec=0 +task=1 +watermark=0 +precise_ip=0 +mmap_data=0 +sample_id_all=1 +exclude_host=0 +exclude_guest=0 +exclude_callchain_kernel=0 +exclude_callchain_user=0 +mmap2=1 +comm_exec=1 +context_switch=0 +write_backward=0 +namespaces=0 +use_clockid=0 +wakeup_events=0 +bp_type=0 +config1=0 +config2=0 +branch_sample_type=0 +sample_regs_user=0 +sample_stack_user=0 diff --git a/tools/perf/tests/shell/attr/test-record-freq b/tools/perf/tests/shell/attr/test-record-freq new file mode 100644 index 00000000000000..89e29f6b2ae0cf --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-freq @@ -0,0 +1,7 @@ +[config] +command = record +args = --no-bpf-event -F 100 kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_period=100 diff --git a/tools/perf/tests/shell/attr/test-record-graph-default b/tools/perf/tests/shell/attr/test-record-graph-default new file mode 100644 index 00000000000000..f0a18b4ea4f562 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-graph-default @@ -0,0 +1,9 @@ +[config] +command = record +args = --no-bpf-event -g kill >/dev/null 2>&1 +ret = 1 +# arm64 enables registers in the default mode (fp) +arch = !aarch64 + +[event:base-record] +sample_type=295 diff --git a/tools/perf/tests/shell/attr/test-record-graph-default-aarch64 b/tools/perf/tests/shell/attr/test-record-graph-default-aarch64 new file mode 100644 index 00000000000000..e98d62efb6f7ee --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-graph-default-aarch64 @@ -0,0 +1,9 @@ +[config] +command = record +args = --no-bpf-event -g kill >/dev/null 2>&1 +ret = 1 +arch = aarch64 + +[event:base-record] +sample_type=4391 +sample_regs_user=1073741824 diff --git a/tools/perf/tests/shell/attr/test-record-graph-dwarf b/tools/perf/tests/shell/attr/test-record-graph-dwarf new file mode 100644 index 00000000000000..ae92061d611ded --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-graph-dwarf @@ -0,0 +1,12 @@ +[config] +command = record +args = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=45359 +exclude_callchain_user=1 +sample_stack_user=8192 +# TODO different for each arch, no support for that now +sample_regs_user=* +mmap_data=1 diff --git a/tools/perf/tests/shell/attr/test-record-graph-fp b/tools/perf/tests/shell/attr/test-record-graph-fp new file mode 100644 index 00000000000000..a6e60e83920514 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-graph-fp @@ -0,0 +1,9 @@ +[config] +command = record +args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1 +ret = 1 +# arm64 enables registers in fp mode +arch = !aarch64 + +[event:base-record] +sample_type=295 diff --git a/tools/perf/tests/shell/attr/test-record-graph-fp-aarch64 b/tools/perf/tests/shell/attr/test-record-graph-fp-aarch64 new file mode 100644 index 00000000000000..cbeea9971285b1 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-graph-fp-aarch64 @@ -0,0 +1,9 @@ +[config] +command = record +args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1 +ret = 1 +arch = aarch64 + +[event:base-record] +sample_type=4391 +sample_regs_user=1073741824 diff --git a/tools/perf/tests/shell/attr/test-record-group-sampling b/tools/perf/tests/shell/attr/test-record-group-sampling new file mode 100644 index 00000000000000..86a940d7895d74 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group-sampling @@ -0,0 +1,40 @@ +[config] +command = record +args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 +ret = 1 +kernel_until = 6.12 + +[event-1:base-record] +fd=1 +group_fd=-1 +sample_type=343 +read_format=12|28 +inherit=0 + +[event-2:base-record] +fd=2 +group_fd=1 + +# cache-misses +type=0 +config=3 + +# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD +sample_type=343 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST +read_format=12|28 +task=0 +mmap=0 +comm=0 +enable_on_exec=0 +disabled=0 + +# inherit is disabled for group sampling +inherit=0 + +# sampling disabled +sample_freq=0 +sample_period=0 +freq=0 +write_backward=0 diff --git a/tools/perf/tests/shell/attr/test-record-group-sampling1 b/tools/perf/tests/shell/attr/test-record-group-sampling1 new file mode 100644 index 00000000000000..4748ab7bf68437 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group-sampling1 @@ -0,0 +1,50 @@ +[config] +command = record +args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 +ret = 1 +kernel_since = 6.12 + +[event-1:base-record] +fd=1 +group_fd=-1 + +# cycles +type=0 +config=0 + +# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD +sample_type=343 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING +read_format=28|31 +task=1 +mmap=1 +comm=1 +enable_on_exec=1 +disabled=1 + +# inherit is enabled for group sampling +inherit=1 + +[event-2:base-record] +fd=2 +group_fd=1 + +# cache-misses +type=0 +config=3 + +# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD +sample_type=343 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING +read_format=28|31 +task=0 +mmap=0 +comm=0 +enable_on_exec=0 +disabled=0 +freq=0 + +# inherit is enabled for group sampling +inherit=1 diff --git a/tools/perf/tests/shell/attr/test-record-group-sampling2 b/tools/perf/tests/shell/attr/test-record-group-sampling2 new file mode 100644 index 00000000000000..e0432244a0eb7f --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group-sampling2 @@ -0,0 +1,61 @@ +[config] +command = record +args = --no-bpf-event -c 10000 -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 +ret = 1 +kernel_since = 6.12 + +[event-1:base-record] +fd=1 +group_fd=-1 + +# cycles +type=0 +config=0 + +# default | PERF_SAMPLE_READ +sample_type=87 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING +read_format=28|31 +task=1 +mmap=1 +comm=1 +enable_on_exec=1 +disabled=1 + +# inherit is enabled for group sampling +inherit=1 + +# sampling disabled +sample_freq=0 +sample_period=10000 +freq=0 +write_backward=0 + +[event-2:base-record] +fd=2 +group_fd=1 + +# cache-misses +type=0 +config=3 + +# default | PERF_SAMPLE_READ +sample_type=87 + +# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING +read_format=28|31 +task=0 +mmap=0 +comm=0 +enable_on_exec=0 +disabled=0 + +# inherit is enabled for group sampling +inherit=1 + +# sampling disabled +sample_freq=0 +sample_period=0 +freq=0 +write_backward=0 diff --git a/tools/perf/tests/shell/attr/test-record-group1 b/tools/perf/tests/shell/attr/test-record-group1 new file mode 100644 index 00000000000000..eeb1db392bc9ce --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group1 @@ -0,0 +1,23 @@ +[config] +command = record +args = --no-bpf-event -e '{cycles,instructions}' kill >/dev/null 2>&1 +ret = 1 + +[event-1:base-record] +fd=1 +group_fd=-1 +sample_type=327 +read_format=4|20 + +[event-2:base-record] +fd=2 +group_fd=1 +type=0 +config=1 +sample_type=327 +read_format=4|20 +mmap=0 +comm=0 +task=0 +enable_on_exec=0 +disabled=0 diff --git a/tools/perf/tests/shell/attr/test-record-group2 b/tools/perf/tests/shell/attr/test-record-group2 new file mode 100644 index 00000000000000..891d41a7bddf78 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group2 @@ -0,0 +1,30 @@ +[config] +command = record +args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1 +ret = 1 +kernel_until = 6.12 + +[event-1:base-record] +fd=1 +group_fd=-1 +config=0|1 +sample_period=1234000 +sample_type=87 +read_format=12|28 +inherit=0 +freq=0 + +[event-2:base-record] +fd=2 +group_fd=1 +config=0|1 +sample_period=6789000 +sample_type=87 +read_format=12|28 +disabled=0 +inherit=0 +mmap=0 +comm=0 +freq=0 +enable_on_exec=0 +task=0 diff --git a/tools/perf/tests/shell/attr/test-record-group3 b/tools/perf/tests/shell/attr/test-record-group3 new file mode 100644 index 00000000000000..249be884959eaa --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-group3 @@ -0,0 +1,31 @@ +[config] +command = record +args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1 +ret = 1 +kernel_since = 6.12 + +[event-1:base-record] +fd=1 +group_fd=-1 +config=0|1 +sample_period=1234000 +sample_type=87 +read_format=28|31 +disabled=1 +inherit=1 +freq=0 + +[event-2:base-record] +fd=2 +group_fd=1 +config=0|1 +sample_period=6789000 +sample_type=87 +read_format=28|31 +disabled=0 +inherit=1 +mmap=0 +comm=0 +freq=0 +enable_on_exec=0 +task=0 diff --git a/tools/perf/tests/shell/attr/test-record-no-buffering b/tools/perf/tests/shell/attr/test-record-no-buffering new file mode 100644 index 00000000000000..583dcbb078bad8 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-no-buffering @@ -0,0 +1,9 @@ +[config] +command = record +args = --no-bpf-event --no-buffering kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=263 +watermark=0 +wakeup_events=1 diff --git a/tools/perf/tests/shell/attr/test-record-no-inherit b/tools/perf/tests/shell/attr/test-record-no-inherit new file mode 100644 index 00000000000000..15d1dc162e1c3e --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-no-inherit @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -i kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=263 +inherit=0 diff --git a/tools/perf/tests/shell/attr/test-record-no-samples b/tools/perf/tests/shell/attr/test-record-no-samples new file mode 100644 index 00000000000000..596fbd6d5a2ccd --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-no-samples @@ -0,0 +1,7 @@ +[config] +command = record +args = --no-bpf-event -n kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_period=0 diff --git a/tools/perf/tests/shell/attr/test-record-period b/tools/perf/tests/shell/attr/test-record-period new file mode 100644 index 00000000000000..119101154c5ee9 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-period @@ -0,0 +1,8 @@ +[config] +command = record +args = --no-bpf-event -c 100 -P kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_period=100 +freq=0 diff --git a/tools/perf/tests/shell/attr/test-record-pfm-period b/tools/perf/tests/shell/attr/test-record-pfm-period new file mode 100644 index 00000000000000..368f5b81409433 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-pfm-period @@ -0,0 +1,9 @@ +[config] +command = record +args = --no-bpf-event -c 10000 --pfm-events=cycles:period=77777 kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_period=77777 +sample_type=7 +freq=0 diff --git a/tools/perf/tests/shell/attr/test-record-raw b/tools/perf/tests/shell/attr/test-record-raw new file mode 100644 index 00000000000000..13a5f7860c786c --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-raw @@ -0,0 +1,7 @@ +[config] +command = record +args = --no-bpf-event -R kill >/dev/null 2>&1 +ret = 1 + +[event:base-record] +sample_type=1415 diff --git a/tools/perf/tests/shell/attr/test-record-spe-period b/tools/perf/tests/shell/attr/test-record-spe-period new file mode 100644 index 00000000000000..75f8c9cd8e3f74 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-spe-period @@ -0,0 +1,12 @@ +[config] +command = record +args = --no-bpf-event -c 2 -e arm_spe_0// -- kill >/dev/null 2>&1 +ret = 1 +arch = aarch64 + +[event-10:base-record-spe] +sample_period=2 +freq=0 + +# dummy event +[event-1:base-record-spe] diff --git a/tools/perf/tests/shell/attr/test-record-spe-period-term b/tools/perf/tests/shell/attr/test-record-spe-period-term new file mode 100644 index 00000000000000..8f60a4fec657ff --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-spe-period-term @@ -0,0 +1,12 @@ +[config] +command = record +args = --no-bpf-event -e arm_spe_0/period=3/ -- kill >/dev/null 2>&1 +ret = 1 +arch = aarch64 + +[event-10:base-record-spe] +sample_period=3 +freq=0 + +# dummy event +[event-1:base-record-spe] diff --git a/tools/perf/tests/shell/attr/test-record-spe-physical-address b/tools/perf/tests/shell/attr/test-record-spe-physical-address new file mode 100644 index 00000000000000..7ebcf5012ce354 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-spe-physical-address @@ -0,0 +1,12 @@ +[config] +command = record +args = --no-bpf-event -e arm_spe_0/pa_enable=1/ -- kill >/dev/null 2>&1 +ret = 1 +arch = aarch64 + +[event-10:base-record-spe] +# 622727 is the decimal of IP|TID|TIME|CPU|IDENTIFIER|DATA_SRC|PHYS_ADDR +sample_type=622727 + +# dummy event +[event-1:base-record-spe] \ No newline at end of file diff --git a/tools/perf/tests/shell/attr/test-record-user-regs-no-sve-aarch64 b/tools/perf/tests/shell/attr/test-record-user-regs-no-sve-aarch64 new file mode 100644 index 00000000000000..bed765450ca976 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-user-regs-no-sve-aarch64 @@ -0,0 +1,9 @@ +# Test that asking for VG fails if the system doesn't support SVE. This +# applies both before and after the feature was added in 6.1 +[config] +command = record +args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1 +ret = 129 +test_ret = true +arch = aarch64 +auxv = auxv["AT_HWCAP"] & 0x400000 == 0 diff --git a/tools/perf/tests/shell/attr/test-record-user-regs-old-sve-aarch64 b/tools/perf/tests/shell/attr/test-record-user-regs-old-sve-aarch64 new file mode 100644 index 00000000000000..15ebfc3418e3f5 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-user-regs-old-sve-aarch64 @@ -0,0 +1,10 @@ +# Test that asking for VG always fails on old kernels because it was +# added in 6.1. This applies to systems that either support or don't +# support SVE. +[config] +command = record +args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1 +ret = 129 +test_ret = true +arch = aarch64 +kernel_until = 6.1 diff --git a/tools/perf/tests/shell/attr/test-record-user-regs-sve-aarch64 b/tools/perf/tests/shell/attr/test-record-user-regs-sve-aarch64 new file mode 100644 index 00000000000000..a65113cd7311b4 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-record-user-regs-sve-aarch64 @@ -0,0 +1,14 @@ +# Test that asking for VG works if the system has SVE and after the +# feature was added in 6.1 +[config] +command = record +args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1 +ret = 1 +test_ret = true +arch = aarch64 +auxv = auxv["AT_HWCAP"] & 0x400000 == 0x400000 +kernel_since = 6.1 + +[event:base-record] +sample_type=4359 +sample_regs_user=70368744177664 diff --git a/tools/perf/tests/shell/attr/test-stat-C0 b/tools/perf/tests/shell/attr/test-stat-C0 new file mode 100644 index 00000000000000..a2c76d10b2bb2a --- /dev/null +++ b/tools/perf/tests/shell/attr/test-stat-C0 @@ -0,0 +1,10 @@ +[config] +command = stat +args = -e cycles -C 0 kill >/dev/null 2>&1 +ret = 1 + +[event:base-stat] +# events are disabled by default when attached to cpu +disabled=1 +enable_on_exec=0 +optional=1 diff --git a/tools/perf/tests/shell/attr/test-stat-basic b/tools/perf/tests/shell/attr/test-stat-basic new file mode 100644 index 00000000000000..69867d049fda92 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-stat-basic @@ -0,0 +1,7 @@ +[config] +command = stat +args = -e cycles kill >/dev/null 2>&1 +ret = 1 + +[event:base-stat] +optional=1 diff --git a/tools/perf/tests/shell/attr/test-stat-default b/tools/perf/tests/shell/attr/test-stat-default new file mode 100644 index 00000000000000..e47fb49446799b --- /dev/null +++ b/tools/perf/tests/shell/attr/test-stat-default @@ -0,0 +1,229 @@ +[config] +command = stat +args = kill >/dev/null 2>&1 +ret = 1 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK +[event1:base-stat] +fd=1 +type=1 +config=1 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES +[event2:base-stat] +fd=2 +type=1 +config=3 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS +[event3:base-stat] +fd=3 +type=1 +config=4 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS +[event4:base-stat] +fd=4 +type=1 +config=2 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES +[event5:base-stat] +fd=5 +type=0 +config=0 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND +[event6:base-stat] +fd=6 +type=0 +config=7 +optional=1 +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND +[event7:base-stat] +fd=7 +type=0 +config=8 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS +[event8:base-stat] +fd=8 +type=0 +config=1 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS +[event9:base-stat] +fd=9 +type=0 +config=4 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES +[event10:base-stat] +fd=10 +type=0 +config=5 +optional=1 + +# PERF_TYPE_RAW / slots (0x400) +[event11:base-stat] +fd=11 +group_fd=-1 +type=4 +config=1024 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-retiring (0x8000) +[event12:base-stat] +fd=12 +group_fd=11 +type=4 +config=32768 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-bad-spec (0x8100) +[event13:base-stat] +fd=13 +group_fd=11 +type=4 +config=33024 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-fe-bound (0x8200) +[event14:base-stat] +fd=14 +group_fd=11 +type=4 +config=33280 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-be-bound (0x8300) +[event15:base-stat] +fd=15 +group_fd=11 +type=4 +config=33536 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-heavy-ops (0x8400) +[event16:base-stat] +fd=16 +group_fd=11 +type=4 +config=33792 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-br-mispredict (0x8500) +[event17:base-stat] +fd=17 +group_fd=11 +type=4 +config=34048 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-fetch-lat (0x8600) +[event18:base-stat] +fd=18 +group_fd=11 +type=4 +config=34304 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-mem-bound (0x8700) +[event19:base-stat] +fd=19 +group_fd=11 +type=4 +config=34560 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event20:base-stat] +fd=20 +type=4 +config=4109 +optional=1 + +# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ +[event21:base-stat] +fd=21 +type=4 +config=17039629 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD +[event22:base-stat] +fd=22 +type=4 +config=60 +optional=1 + +# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY +[event23:base-stat] +fd=23 +type=4 +config=2097421 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK +[event24:base-stat] +fd=24 +type=4 +config=316 +optional=1 + +# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +[event25:base-stat] +fd=25 +type=4 +config=412 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +[event26:base-stat] +fd=26 +type=4 +config=572 +optional=1 + +# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +[event27:base-stat] +fd=27 +type=4 +config=706 +optional=1 + +# PERF_TYPE_RAW / UOPS_ISSUED.ANY +[event28:base-stat] +fd=28 +type=4 +config=270 +optional=1 diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-1 b/tools/perf/tests/shell/attr/test-stat-detailed-1 new file mode 100644 index 00000000000000..3d500d3e0c5c8a --- /dev/null +++ b/tools/perf/tests/shell/attr/test-stat-detailed-1 @@ -0,0 +1,271 @@ +[config] +command = stat +args = -d kill >/dev/null 2>&1 +ret = 1 + + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK +[event1:base-stat] +fd=1 +type=1 +config=1 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES +[event2:base-stat] +fd=2 +type=1 +config=3 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS +[event3:base-stat] +fd=3 +type=1 +config=4 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS +[event4:base-stat] +fd=4 +type=1 +config=2 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES +[event5:base-stat] +fd=5 +type=0 +config=0 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND +[event6:base-stat] +fd=6 +type=0 +config=7 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND +[event7:base-stat] +fd=7 +type=0 +config=8 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS +[event8:base-stat] +fd=8 +type=0 +config=1 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS +[event9:base-stat] +fd=9 +type=0 +config=4 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES +[event10:base-stat] +fd=10 +type=0 +config=5 +optional=1 + +# PERF_TYPE_RAW / slots (0x400) +[event11:base-stat] +fd=11 +group_fd=-1 +type=4 +config=1024 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-retiring (0x8000) +[event12:base-stat] +fd=12 +group_fd=11 +type=4 +config=32768 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-bad-spec (0x8100) +[event13:base-stat] +fd=13 +group_fd=11 +type=4 +config=33024 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-fe-bound (0x8200) +[event14:base-stat] +fd=14 +group_fd=11 +type=4 +config=33280 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-be-bound (0x8300) +[event15:base-stat] +fd=15 +group_fd=11 +type=4 +config=33536 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-heavy-ops (0x8400) +[event16:base-stat] +fd=16 +group_fd=11 +type=4 +config=33792 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-br-mispredict (0x8500) +[event17:base-stat] +fd=17 +group_fd=11 +type=4 +config=34048 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-fetch-lat (0x8600) +[event18:base-stat] +fd=18 +group_fd=11 +type=4 +config=34304 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-mem-bound (0x8700) +[event19:base-stat] +fd=19 +group_fd=11 +type=4 +config=34560 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event20:base-stat] +fd=20 +type=4 +config=4109 +optional=1 + +# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ +[event21:base-stat] +fd=21 +type=4 +config=17039629 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD +[event22:base-stat] +fd=22 +type=4 +config=60 +optional=1 + +# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY +[event23:base-stat] +fd=23 +type=4 +config=2097421 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK +[event24:base-stat] +fd=24 +type=4 +config=316 +optional=1 + +# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +[event25:base-stat] +fd=25 +type=4 +config=412 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +[event26:base-stat] +fd=26 +type=4 +config=572 +optional=1 + +# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +[event27:base-stat] +fd=27 +type=4 +config=706 +optional=1 + +# PERF_TYPE_RAW / UOPS_ISSUED.ANY +[event28:base-stat] +fd=28 +type=4 +config=270 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_L1D << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event29:base-stat] +fd=29 +type=3 +config=0 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_L1D << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event30:base-stat] +fd=30 +type=3 +config=65536 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_LL << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event31:base-stat] +fd=31 +type=3 +config=2 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_LL << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event32:base-stat] +fd=32 +type=3 +config=65538 +optional=1 diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-2 b/tools/perf/tests/shell/attr/test-stat-detailed-2 new file mode 100644 index 00000000000000..01777a63752fe6 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-stat-detailed-2 @@ -0,0 +1,331 @@ +[config] +command = stat +args = -dd kill >/dev/null 2>&1 +ret = 1 + + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK +[event1:base-stat] +fd=1 +type=1 +config=1 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES +[event2:base-stat] +fd=2 +type=1 +config=3 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS +[event3:base-stat] +fd=3 +type=1 +config=4 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS +[event4:base-stat] +fd=4 +type=1 +config=2 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES +[event5:base-stat] +fd=5 +type=0 +config=0 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND +[event6:base-stat] +fd=6 +type=0 +config=7 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND +[event7:base-stat] +fd=7 +type=0 +config=8 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS +[event8:base-stat] +fd=8 +type=0 +config=1 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS +[event9:base-stat] +fd=9 +type=0 +config=4 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES +[event10:base-stat] +fd=10 +type=0 +config=5 +optional=1 + +# PERF_TYPE_RAW / slots (0x400) +[event11:base-stat] +fd=11 +group_fd=-1 +type=4 +config=1024 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-retiring (0x8000) +[event12:base-stat] +fd=12 +group_fd=11 +type=4 +config=32768 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-bad-spec (0x8100) +[event13:base-stat] +fd=13 +group_fd=11 +type=4 +config=33024 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-fe-bound (0x8200) +[event14:base-stat] +fd=14 +group_fd=11 +type=4 +config=33280 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-be-bound (0x8300) +[event15:base-stat] +fd=15 +group_fd=11 +type=4 +config=33536 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-heavy-ops (0x8400) +[event16:base-stat] +fd=16 +group_fd=11 +type=4 +config=33792 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-br-mispredict (0x8500) +[event17:base-stat] +fd=17 +group_fd=11 +type=4 +config=34048 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-fetch-lat (0x8600) +[event18:base-stat] +fd=18 +group_fd=11 +type=4 +config=34304 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-mem-bound (0x8700) +[event19:base-stat] +fd=19 +group_fd=11 +type=4 +config=34560 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event20:base-stat] +fd=20 +type=4 +config=4109 +optional=1 + +# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ +[event21:base-stat] +fd=21 +type=4 +config=17039629 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD +[event22:base-stat] +fd=22 +type=4 +config=60 +optional=1 + +# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY +[event23:base-stat] +fd=23 +type=4 +config=2097421 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK +[event24:base-stat] +fd=24 +type=4 +config=316 +optional=1 + +# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +[event25:base-stat] +fd=25 +type=4 +config=412 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +[event26:base-stat] +fd=26 +type=4 +config=572 +optional=1 + +# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +[event27:base-stat] +fd=27 +type=4 +config=706 +optional=1 + +# PERF_TYPE_RAW / UOPS_ISSUED.ANY +[event28:base-stat] +fd=28 +type=4 +config=270 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_L1D << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event29:base-stat] +fd=29 +type=3 +config=0 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_L1D << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event30:base-stat] +fd=30 +type=3 +config=65536 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_LL << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event31:base-stat] +fd=31 +type=3 +config=2 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_LL << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event32:base-stat] +fd=32 +type=3 +config=65538 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_L1I << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event33:base-stat] +fd=33 +type=3 +config=1 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_L1I << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event34:base-stat] +fd=34 +type=3 +config=65537 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_DTLB << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event35:base-stat] +fd=35 +type=3 +config=3 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_DTLB << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event36:base-stat] +fd=36 +type=3 +config=65539 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_ITLB << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event37:base-stat] +fd=37 +type=3 +config=4 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_ITLB << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event38:base-stat] +fd=38 +type=3 +config=65540 +optional=1 diff --git a/tools/perf/tests/shell/attr/test-stat-detailed-3 b/tools/perf/tests/shell/attr/test-stat-detailed-3 new file mode 100644 index 00000000000000..8400abd7e1e488 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-stat-detailed-3 @@ -0,0 +1,351 @@ +[config] +command = stat +args = -ddd kill >/dev/null 2>&1 +ret = 1 + + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK +[event1:base-stat] +fd=1 +type=1 +config=1 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES +[event2:base-stat] +fd=2 +type=1 +config=3 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS +[event3:base-stat] +fd=3 +type=1 +config=4 + +# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS +[event4:base-stat] +fd=4 +type=1 +config=2 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES +[event5:base-stat] +fd=5 +type=0 +config=0 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND +[event6:base-stat] +fd=6 +type=0 +config=7 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND +[event7:base-stat] +fd=7 +type=0 +config=8 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS +[event8:base-stat] +fd=8 +type=0 +config=1 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS +[event9:base-stat] +fd=9 +type=0 +config=4 +optional=1 + +# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES +[event10:base-stat] +fd=10 +type=0 +config=5 +optional=1 + +# PERF_TYPE_RAW / slots (0x400) +[event11:base-stat] +fd=11 +group_fd=-1 +type=4 +config=1024 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-retiring (0x8000) +[event12:base-stat] +fd=12 +group_fd=11 +type=4 +config=32768 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-bad-spec (0x8100) +[event13:base-stat] +fd=13 +group_fd=11 +type=4 +config=33024 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-fe-bound (0x8200) +[event14:base-stat] +fd=14 +group_fd=11 +type=4 +config=33280 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-be-bound (0x8300) +[event15:base-stat] +fd=15 +group_fd=11 +type=4 +config=33536 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-heavy-ops (0x8400) +[event16:base-stat] +fd=16 +group_fd=11 +type=4 +config=33792 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-br-mispredict (0x8500) +[event17:base-stat] +fd=17 +group_fd=11 +type=4 +config=34048 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-fetch-lat (0x8600) +[event18:base-stat] +fd=18 +group_fd=11 +type=4 +config=34304 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / topdown-mem-bound (0x8700) +[event19:base-stat] +fd=19 +group_fd=11 +type=4 +config=34560 +disabled=0 +enable_on_exec=0 +read_format=15 +optional=1 + +# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING +[event20:base-stat] +fd=20 +type=4 +config=4109 +optional=1 + +# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/ +[event21:base-stat] +fd=21 +type=4 +config=17039629 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD +[event22:base-stat] +fd=22 +type=4 +config=60 +optional=1 + +# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY +[event23:base-stat] +fd=23 +type=4 +config=2097421 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK +[event24:base-stat] +fd=24 +type=4 +config=316 +optional=1 + +# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE +[event25:base-stat] +fd=25 +type=4 +config=412 +optional=1 + +# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE +[event26:base-stat] +fd=26 +type=4 +config=572 +optional=1 + +# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS +[event27:base-stat] +fd=27 +type=4 +config=706 +optional=1 + +# PERF_TYPE_RAW / UOPS_ISSUED.ANY +[event28:base-stat] +fd=28 +type=4 +config=270 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_L1D << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event29:base-stat] +fd=29 +type=3 +config=0 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_L1D << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event30:base-stat] +fd=30 +type=3 +config=65536 +optional=1 + +# PERF_TYPE_HW_CACHE / +# PERF_COUNT_HW_CACHE_LL << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event31:base-stat] +fd=31 +type=3 +config=2 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_LL << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event32:base-stat] +fd=32 +type=3 +config=65538 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_L1I << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event33:base-stat] +fd=33 +type=3 +config=1 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_L1I << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event34:base-stat] +fd=34 +type=3 +config=65537 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_DTLB << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event35:base-stat] +fd=35 +type=3 +config=3 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_DTLB << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event36:base-stat] +fd=36 +type=3 +config=65539 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_ITLB << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event37:base-stat] +fd=37 +type=3 +config=4 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_ITLB << 0 | +# (PERF_COUNT_HW_CACHE_OP_READ << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event38:base-stat] +fd=38 +type=3 +config=65540 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_L1D << 0 | +# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16) +[event39:base-stat] +fd=39 +type=3 +config=512 +optional=1 + +# PERF_TYPE_HW_CACHE, +# PERF_COUNT_HW_CACHE_L1D << 0 | +# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | +# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) +[event40:base-stat] +fd=40 +type=3 +config=66048 +optional=1 diff --git a/tools/perf/tests/shell/attr/test-stat-group1 b/tools/perf/tests/shell/attr/test-stat-group1 new file mode 100644 index 00000000000000..1746751123dcb2 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-stat-group1 @@ -0,0 +1,17 @@ +[config] +command = stat +args = -e '{cycles,instructions}' kill >/dev/null 2>&1 +ret = 1 + +[event-1:base-stat] +fd=1 +group_fd=-1 +read_format=3|15 + +[event-2:base-stat] +fd=2 +group_fd=1 +config=1 +disabled=0 +enable_on_exec=0 +read_format=3|15 diff --git a/tools/perf/tests/shell/attr/test-stat-no-inherit b/tools/perf/tests/shell/attr/test-stat-no-inherit new file mode 100644 index 00000000000000..924fbb9300d162 --- /dev/null +++ b/tools/perf/tests/shell/attr/test-stat-no-inherit @@ -0,0 +1,8 @@ +[config] +command = stat +args = -i -e cycles kill >/dev/null 2>&1 +ret = 1 + +[event:base-stat] +inherit=0 +optional=1 diff --git a/tools/perf/tests/shell/coresight/asm_pure_loop.sh b/tools/perf/tests/shell/coresight/asm_pure_loop.sh index 2d65defb7e0f15..c63bc8c73e262b 100755 --- a/tools/perf/tests/shell/coresight/asm_pure_loop.sh +++ b/tools/perf/tests/shell/coresight/asm_pure_loop.sh @@ -1,5 +1,5 @@ #!/bin/sh -e -# CoreSight / ASM Pure Loop +# CoreSight / ASM Pure Loop (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler , 2021 diff --git a/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh b/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh index ddcc9bb850f5fc..8e29630957c8d5 100755 --- a/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh +++ b/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh @@ -1,5 +1,5 @@ #!/bin/sh -e -# CoreSight / Memcpy 16k 10 Threads +# CoreSight / Memcpy 16k 10 Threads (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler , 2021 diff --git a/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh b/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh index 2ce5e139b2fdd7..0c4c82a1c8e15a 100755 --- a/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh +++ b/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh @@ -1,5 +1,5 @@ #!/bin/sh -e -# CoreSight / Thread Loop 10 Threads - Check TID +# CoreSight / Thread Loop 10 Threads - Check TID (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler , 2021 diff --git a/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh b/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh index 3ad9498753d7b7..d3aea9fc6ced9c 100755 --- a/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh +++ b/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh @@ -1,5 +1,5 @@ #!/bin/sh -e -# CoreSight / Thread Loop 2 Threads - Check TID +# CoreSight / Thread Loop 2 Threads - Check TID (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler , 2021 diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh b/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh index 4fbb4a29aad3fa..7429d3a2ae4368 100755 --- a/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh +++ b/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh @@ -1,5 +1,5 @@ #!/bin/sh -e -# CoreSight / Unroll Loop Thread 10 +# CoreSight / Unroll Loop Thread 10 (exclusive) # SPDX-License-Identifier: GPL-2.0 # Carsten Haitzler , 2021 diff --git a/tools/perf/tests/shell/ftrace.sh b/tools/perf/tests/shell/ftrace.sh index a6ee740f0d7eca..2df05052c324a2 100755 --- a/tools/perf/tests/shell/ftrace.sh +++ b/tools/perf/tests/shell/ftrace.sh @@ -67,12 +67,12 @@ test_ftrace_latency() { test_ftrace_profile() { echo "perf ftrace profile test" - perf ftrace profile sleep 0.1 > "${output}" + perf ftrace profile -m 16M sleep 0.1 > "${output}" grep ^# "${output}" grep sleep "${output}" grep schedule "${output}" grep execve "${output}" - time_re="[[:space:]]+10[[:digit:]]{4}\.[[:digit:]]{3}" + time_re="[[:space:]]+1[[:digit:]]{5}\.[[:digit:]]{3}" # 100283.000 100283.000 100283.000 1 __x64_sys_clock_nanosleep # Check for one *clock_nanosleep line with a Count of just 1 that takes a bit more than 0.1 seconds # Strip the _x64_sys part to work with other architectures diff --git a/tools/perf/tests/shell/lib/attr.py b/tools/perf/tests/shell/lib/attr.py new file mode 100644 index 00000000000000..3db9a7d78715f1 --- /dev/null +++ b/tools/perf/tests/shell/lib/attr.py @@ -0,0 +1,476 @@ +# SPDX-License-Identifier: GPL-2.0 + +from __future__ import print_function + +import os +import sys +import glob +import optparse +import platform +import tempfile +import logging +import re +import shutil +import subprocess + +try: + import configparser +except ImportError: + import ConfigParser as configparser + +def data_equal(a, b): + # Allow multiple values in assignment separated by '|' + a_list = a.split('|') + b_list = b.split('|') + + for a_item in a_list: + for b_item in b_list: + if (a_item == b_item): + return True + elif (a_item == '*') or (b_item == '*'): + return True + + return False + +class Fail(Exception): + def __init__(self, test, msg): + self.msg = msg + self.test = test + def getMsg(self): + return '\'%s\' - %s' % (self.test.path, self.msg) + +class Notest(Exception): + def __init__(self, test, arch): + self.arch = arch + self.test = test + def getMsg(self): + return '[%s] \'%s\'' % (self.arch, self.test.path) + +class Unsup(Exception): + def __init__(self, test): + self.test = test + def getMsg(self): + return '\'%s\'' % self.test.path + +class Event(dict): + terms = [ + 'cpu', + 'flags', + 'type', + 'size', + 'config', + 'sample_period', + 'sample_type', + 'read_format', + 'disabled', + 'inherit', + 'pinned', + 'exclusive', + 'exclude_user', + 'exclude_kernel', + 'exclude_hv', + 'exclude_idle', + 'mmap', + 'comm', + 'freq', + 'inherit_stat', + 'enable_on_exec', + 'task', + 'watermark', + 'precise_ip', + 'mmap_data', + 'sample_id_all', + 'exclude_host', + 'exclude_guest', + 'exclude_callchain_kernel', + 'exclude_callchain_user', + 'wakeup_events', + 'bp_type', + 'config1', + 'config2', + 'branch_sample_type', + 'sample_regs_user', + 'sample_stack_user', + ] + + def add(self, data): + for key, val in data: + log.debug(" %s = %s" % (key, val)) + self[key] = val + + def __init__(self, name, data, base): + log.debug(" Event %s" % name); + self.name = name; + self.group = '' + self.add(base) + self.add(data) + + def equal(self, other): + for t in Event.terms: + log.debug(" [%s] %s %s" % (t, self[t], other[t])); + if t not in self or t not in other: + return False + if not data_equal(self[t], other[t]): + return False + return True + + def optional(self): + if 'optional' in self and self['optional'] == '1': + return True + return False + + def diff(self, other): + for t in Event.terms: + if t not in self or t not in other: + continue + if not data_equal(self[t], other[t]): + log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) + +def parse_version(version): + if not version: + return None + return [int(v) for v in version.split(".")[0:2]] + +# Test file description needs to have following sections: +# [config] +# - just single instance in file +# - needs to specify: +# 'command' - perf command name +# 'args' - special command arguments +# 'ret' - Skip test if Perf doesn't exit with this value (0 by default) +# 'test_ret'- If set to 'true', fail test instead of skipping for 'ret' argument +# 'arch' - architecture specific test (optional) +# comma separated list, ! at the beginning +# negates it. +# 'auxv' - Truthy statement that is evaled in the scope of the auxv map. When false, +# the test is skipped. For example 'auxv["AT_HWCAP"] == 10'. (optional) +# 'kernel_since' - Inclusive kernel version from which the test will start running. Only the +# first two values are supported, for example "6.1" (optional) +# 'kernel_until' - Exclusive kernel version from which the test will stop running. (optional) +# [eventX:base] +# - one or multiple instances in file +# - expected values assignments +class Test(object): + def __init__(self, path, options): + parser = configparser.ConfigParser() + parser.read(path) + + log.warning("running '%s'" % path) + + self.path = path + self.test_dir = options.test_dir + self.perf = options.perf + self.command = parser.get('config', 'command') + self.args = parser.get('config', 'args') + + try: + self.ret = parser.get('config', 'ret') + except: + self.ret = 0 + + self.test_ret = parser.getboolean('config', 'test_ret', fallback=False) + + try: + self.arch = parser.get('config', 'arch') + log.warning("test limitation '%s'" % self.arch) + except: + self.arch = '' + + self.auxv = parser.get('config', 'auxv', fallback=None) + self.kernel_since = parse_version(parser.get('config', 'kernel_since', fallback=None)) + self.kernel_until = parse_version(parser.get('config', 'kernel_until', fallback=None)) + self.expect = {} + self.result = {} + log.debug(" loading expected events"); + self.load_events(path, self.expect) + + def is_event(self, name): + if name.find("event") == -1: + return False + else: + return True + + def skip_test_kernel_since(self): + if not self.kernel_since: + return False + return not self.kernel_since <= parse_version(platform.release()) + + def skip_test_kernel_until(self): + if not self.kernel_until: + return False + return not parse_version(platform.release()) < self.kernel_until + + def skip_test_auxv(self): + def new_auxv(a, pattern): + items = list(filter(None, pattern.split(a))) + # AT_HWCAP is hex but doesn't have a prefix, so special case it + if items[0] == "AT_HWCAP": + value = int(items[-1], 16) + else: + try: + value = int(items[-1], 0) + except: + value = items[-1] + return (items[0], value) + + if not self.auxv: + return False + auxv = subprocess.check_output("LD_SHOW_AUXV=1 sleep 0", shell=True) \ + .decode(sys.stdout.encoding) + pattern = re.compile(r"[: ]+") + auxv = dict([new_auxv(a, pattern) for a in auxv.splitlines()]) + return not eval(self.auxv) + + def skip_test_arch(self, myarch): + # If architecture not set always run test + if self.arch == '': + # log.warning("test for arch %s is ok" % myarch) + return False + + # Allow multiple values in assignment separated by ',' + arch_list = self.arch.split(',') + + # Handle negated list such as !s390x,ppc + if arch_list[0][0] == '!': + arch_list[0] = arch_list[0][1:] + log.warning("excluded architecture list %s" % arch_list) + for arch_item in arch_list: + # log.warning("test for %s arch is %s" % (arch_item, myarch)) + if arch_item == myarch: + return True + return False + + for arch_item in arch_list: + # log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch)) + if arch_item == myarch: + return False + return True + + def restore_sample_rate(self, value=10000): + try: + # Check value of sample_rate + with open("/proc/sys/kernel/perf_event_max_sample_rate", "r") as fIn: + curr_value = fIn.readline() + # If too low restore to reasonable value + if not curr_value or int(curr_value) < int(value): + with open("/proc/sys/kernel/perf_event_max_sample_rate", "w") as fOut: + fOut.write(str(value)) + + except IOError as e: + log.warning("couldn't restore sample_rate value: I/O error %s" % e) + except ValueError as e: + log.warning("couldn't restore sample_rate value: Value error %s" % e) + except TypeError as e: + log.warning("couldn't restore sample_rate value: Type error %s" % e) + + def load_events(self, path, events): + parser_event = configparser.ConfigParser() + parser_event.read(path) + + # The event record section header contains 'event' word, + # optionaly followed by ':' allowing to load 'parent + # event' first as a base + for section in filter(self.is_event, parser_event.sections()): + + parser_items = parser_event.items(section); + base_items = {} + + # Read parent event if there's any + if (':' in section): + base = section[section.index(':') + 1:] + parser_base = configparser.ConfigParser() + parser_base.read(self.test_dir + '/' + base) + base_items = parser_base.items('event') + + e = Event(section, parser_items, base_items) + events[section] = e + + def run_cmd(self, tempdir): + junk1, junk2, junk3, junk4, myarch = (os.uname()) + + if self.skip_test_arch(myarch): + raise Notest(self, myarch) + + if self.skip_test_auxv(): + raise Notest(self, "auxv skip") + + if self.skip_test_kernel_since(): + raise Notest(self, "old kernel skip") + + if self.skip_test_kernel_until(): + raise Notest(self, "new kernel skip") + + self.restore_sample_rate() + cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir, + self.perf, self.command, tempdir, self.args) + ret = os.WEXITSTATUS(os.system(cmd)) + + log.info(" '%s' ret '%s', expected '%s'" % (cmd, str(ret), str(self.ret))) + + if not data_equal(str(ret), str(self.ret)): + if self.test_ret: + raise Fail(self, "Perf exit code failure") + else: + raise Unsup(self) + + def compare(self, expect, result): + match = {} + + log.debug(" compare"); + + # For each expected event find all matching + # events in result. Fail if there's not any. + for exp_name, exp_event in expect.items(): + exp_list = [] + res_event = {} + log.debug(" matching [%s]" % exp_name) + for res_name, res_event in result.items(): + log.debug(" to [%s]" % res_name) + if (exp_event.equal(res_event)): + exp_list.append(res_name) + log.debug(" ->OK") + else: + log.debug(" ->FAIL"); + + log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list))) + + # we did not any matching event - fail + if not exp_list: + if exp_event.optional(): + log.debug(" %s does not match, but is optional" % exp_name) + else: + if not res_event: + log.debug(" res_event is empty"); + else: + exp_event.diff(res_event) + raise Fail(self, 'match failure'); + + match[exp_name] = exp_list + + # For each defined group in the expected events + # check we match the same group in the result. + for exp_name, exp_event in expect.items(): + group = exp_event.group + + if (group == ''): + continue + + for res_name in match[exp_name]: + res_group = result[res_name].group + if res_group not in match[group]: + raise Fail(self, 'group failure') + + log.debug(" group: [%s] matches group leader %s" % + (exp_name, str(match[group]))) + + log.debug(" matched") + + def resolve_groups(self, events): + for name, event in events.items(): + group_fd = event['group_fd']; + if group_fd == '-1': + continue; + + for iname, ievent in events.items(): + if (ievent['fd'] == group_fd): + event.group = iname + log.debug('[%s] has group leader [%s]' % (name, iname)) + break; + + def run(self): + tempdir = tempfile.mkdtemp(); + + try: + # run the test script + self.run_cmd(tempdir); + + # load events expectation for the test + log.debug(" loading result events"); + for f in glob.glob(tempdir + '/event*'): + self.load_events(f, self.result); + + # resolve group_fd to event names + self.resolve_groups(self.expect); + self.resolve_groups(self.result); + + # do the expectation - results matching - both ways + self.compare(self.expect, self.result) + self.compare(self.result, self.expect) + + finally: + # cleanup + shutil.rmtree(tempdir) + + +def run_tests(options): + for f in glob.glob(options.test_dir + '/' + options.test): + try: + Test(f, options).run() + except Unsup as obj: + log.warning("unsupp %s" % obj.getMsg()) + except Notest as obj: + log.warning("skipped %s" % obj.getMsg()) + +def setup_log(verbose): + global log + level = logging.CRITICAL + + if verbose == 1: + level = logging.WARNING + if verbose == 2: + level = logging.INFO + if verbose >= 3: + level = logging.DEBUG + + log = logging.getLogger('test') + log.setLevel(level) + ch = logging.StreamHandler() + ch.setLevel(level) + formatter = logging.Formatter('%(message)s') + ch.setFormatter(formatter) + log.addHandler(ch) + +USAGE = '''%s [OPTIONS] + -d dir # tests dir + -p path # perf binary + -t test # single test + -v # verbose level +''' % sys.argv[0] + +def main(): + parser = optparse.OptionParser(usage=USAGE) + + parser.add_option("-t", "--test", + action="store", type="string", dest="test") + parser.add_option("-d", "--test-dir", + action="store", type="string", dest="test_dir") + parser.add_option("-p", "--perf", + action="store", type="string", dest="perf") + parser.add_option("-v", "--verbose", + default=0, action="count", dest="verbose") + + options, args = parser.parse_args() + if args: + parser.error('FAILED wrong arguments %s' % ' '.join(args)) + return -1 + + setup_log(options.verbose) + + if not options.test_dir: + print('FAILED no -d option specified') + sys.exit(-1) + + if not options.test: + options.test = 'test*' + + try: + run_tests(options) + + except Fail as obj: + print("FAILED %s" % obj.getMsg()) + sys.exit(-1) + + sys.exit(0) + +if __name__ == '__main__': + main() diff --git a/tools/perf/tests/shell/lib/coresight.sh b/tools/perf/tests/shell/lib/coresight.sh index 11ed2c25ed9126..184d62e7e5bdf9 100644 --- a/tools/perf/tests/shell/lib/coresight.sh +++ b/tools/perf/tests/shell/lib/coresight.sh @@ -18,7 +18,7 @@ BIN="$DIR/$TEST" # If the test tool/binary does not exist and is executable then skip the test if ! test -x "$BIN"; then exit 2; fi # If CoreSight is not available, skip the test -perf list cs_etm | grep -q cs_etm || exit 2 +perf list pmu | grep -q cs_etm || exit 2 DATD="." # If the data dir env is set then make the data dir use that instead of ./ if test -n "$PERF_TEST_CORESIGHT_DATADIR"; then diff --git a/tools/perf/tests/shell/lib/perf_json_output_lint.py b/tools/perf/tests/shell/lib/perf_json_output_lint.py index abc1fd73778229..8ddb8558613195 100644 --- a/tools/perf/tests/shell/lib/perf_json_output_lint.py +++ b/tools/perf/tests/shell/lib/perf_json_output_lint.py @@ -57,6 +57,7 @@ def check_json_output(expected_items): 'interval': lambda x: isfloat(x), 'metric-unit': lambda x: True, 'metric-value': lambda x: isfloat(x), + 'metric-threshold': lambda x: x in ['unknown', 'good', 'less good', 'nearly bad', 'bad'], 'metricgroup': lambda x: True, 'node': lambda x: True, 'pcnt-running': lambda x: isfloat(x), @@ -68,13 +69,15 @@ def check_json_output(expected_items): for item in json.loads(input): if expected_items != -1: count = len(item) - if count != expected_items and count >= 1 and count <= 6 and 'metric-value' in item: + if count != expected_items and count >= 1 and count <= 7 and 'metric-value' in item: # Events that generate >1 metric may have isolated metric # values and possibly other prefixes like interval, core, # aggregate-number, or event-runtime/pcnt-running from multiplexing. pass elif count != expected_items and count >= 1 and count <= 5 and 'metricgroup' in item: pass + elif count == expected_items + 1 and 'metric-threshold' in item: + pass elif count != expected_items: raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}' f' in \'{item}\'') diff --git a/tools/perf/tests/shell/list.sh b/tools/perf/tests/shell/list.sh index 8a868ae64560e1..76a9846cff223b 100755 --- a/tools/perf/tests/shell/list.sh +++ b/tools/perf/tests/shell/list.sh @@ -24,8 +24,11 @@ trap trap_cleanup EXIT TERM INT test_list_json() { echo "Json output test" + # Generate perf list json output into list_output file. perf list -j -o "${list_output}" - $PYTHON -m json.tool "${list_output}" + # Validate the json using python, redirect the json copy to /dev/null as + # otherwise the test may block writing to stdout. + $PYTHON -m json.tool "${list_output}" /dev/null echo "Json output test [Success]" } diff --git a/tools/perf/tests/shell/lock_contention.sh b/tools/perf/tests/shell/lock_contention.sh index c1ec5762215ba4..30d195d4c62f74 100755 --- a/tools/perf/tests/shell/lock_contention.sh +++ b/tools/perf/tests/shell/lock_contention.sh @@ -27,7 +27,7 @@ check() { exit fi - if ! perf list | grep -q lock:contention_begin; then + if ! perf list tracepoint | grep -q lock:contention_begin; then echo "[Skip] No lock contention tracepoints" err=2 exit diff --git a/tools/perf/tests/shell/perftool-testsuite_report.sh b/tools/perf/tests/shell/perftool-testsuite_report.sh index 973012ce92a76f..a8cf75b4e77ec1 100755 --- a/tools/perf/tests/shell/perftool-testsuite_report.sh +++ b/tools/perf/tests/shell/perftool-testsuite_report.sh @@ -1,5 +1,5 @@ #!/bin/bash -# perftool-testsuite_report +# perftool-testsuite_report (exclusive) # SPDX-License-Identifier: GPL-2.0 test -d "$(dirname "$0")/base_report" || exit 2 diff --git a/tools/perf/tests/shell/pipe_test.sh b/tools/perf/tests/shell/pipe_test.sh index d4c8005ce9b96b..e459aa99a9515b 100755 --- a/tools/perf/tests/shell/pipe_test.sh +++ b/tools/perf/tests/shell/pipe_test.sh @@ -13,6 +13,7 @@ skip_test_missing_symbol ${sym} data=$(mktemp /tmp/perf.data.XXXXXX) data2=$(mktemp /tmp/perf.data2.XXXXXX) prog="perf test -w noploop" +[ "$(uname -m)" = "s390x" ] && prog="$prog 3" err=0 set -e diff --git a/tools/perf/tests/shell/probe_vfs_getname.sh b/tools/perf/tests/shell/probe_vfs_getname.sh index 554e12e83c55fd..0c5aacc446b3ef 100755 --- a/tools/perf/tests/shell/probe_vfs_getname.sh +++ b/tools/perf/tests/shell/probe_vfs_getname.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Add vfs_getname probe to get syscall args filenames +# Add vfs_getname probe to get syscall args filenames (exclusive) # SPDX-License-Identifier: GPL-2.0 # Arnaldo Carvalho de Melo , 2017 diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index f38c8ead0b03ee..47a26f25db9fe3 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -40,8 +40,8 @@ trace_libc_inet_pton_backtrace() { case "$(uname -m)" in s390x) eventattr='call-graph=dwarf,max-stack=4' - echo "(__GI_)?getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected - echo "main\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" >> $expected + echo "((__GI_)?getaddrinfo|text_to_binary_address)\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" >> $expected + echo "(gaih_inet|main)\+0x[[:xdigit:]]+[[:space:]]\(inlined|.*/bin/ping.*\)$" >> $expected ;; ppc64|ppc64le) eventattr='max-stack=4' diff --git a/tools/perf/tests/shell/record+script_probe_vfs_getname.sh b/tools/perf/tests/shell/record+script_probe_vfs_getname.sh index 9a61928e3c9aa0..5940fdc1df37c5 100755 --- a/tools/perf/tests/shell/record+script_probe_vfs_getname.sh +++ b/tools/perf/tests/shell/record+script_probe_vfs_getname.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Use vfs_getname probe to get syscall args filenames +# Use vfs_getname probe to get syscall args filenames (exclusive) # Uses the 'perf test shell' library to add probe:vfs_getname to the system # then use it with 'perf record' using 'touch' to write to a temp file, then diff --git a/tools/perf/tests/shell/record.sh b/tools/perf/tests/shell/record.sh index 048078ee2eca5d..0fc7a909ae9b54 100755 --- a/tools/perf/tests/shell/record.sh +++ b/tools/perf/tests/shell/record.sh @@ -1,5 +1,5 @@ #!/bin/bash -# perf record tests +# perf record tests (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e @@ -17,6 +17,7 @@ skip_test_missing_symbol ${testsym} err=0 perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) +script_output=$(mktemp /tmp/__perf_test.perf.data.XXXXX.script) testprog="perf test -w thloop" cpu_pmu_dir="/sys/bus/event_source/devices/cpu*" br_cntr_file="/caps/branch_counter_nr" @@ -93,7 +94,7 @@ test_per_thread() { test_register_capture() { echo "Register capture test" - if ! perf list | grep -q 'br_inst_retired.near_call' + if ! perf list pmu | grep -q 'br_inst_retired.near_call' then echo "Register capture test [Skipped missing event]" return @@ -228,6 +229,73 @@ test_cgroup() { echo "Cgroup sampling test [Success]" } +test_leader_sampling() { + echo "Basic leader sampling test" + if ! perf record -o "${perfdata}" -e "{instructions,instructions}:Su" -- \ + perf test -w brstack 2> /dev/null + then + echo "Leader sampling [Failed record]" + err=1 + return + fi + index=0 + perf script -i "${perfdata}" > $script_output + while IFS= read -r line + do + # Check if the two instruction counts are equal in each record + instructions=$(echo $line | awk '{for(i=1;i<=NF;i++) if($i=="instructions:") print $(i-1)}') + if [ $(($index%2)) -ne 0 ] && [ ${instructions}x != ${prev_instructions}x ] + then + echo "Leader sampling [Failed inconsistent instructions count]" + err=1 + return + fi + index=$(($index+1)) + prev_instructions=$instructions + done < $script_output + echo "Basic leader sampling test [Success]" +} + +test_topdown_leader_sampling() { + echo "Topdown leader sampling test" + if ! perf stat -e "{slots,topdown-retiring}" true 2> /dev/null + then + echo "Topdown leader sampling [Skipped event parsing failed]" + return + fi + if ! perf record -o "${perfdata}" -e "{instructions,slots,topdown-retiring}:S" true 2> /dev/null + then + echo "Topdown leader sampling [Failed topdown events not reordered correctly]" + err=1 + return + fi + echo "Topdown leader sampling test [Success]" +} + +test_precise_max() { + echo "precise_max attribute test" + if ! perf stat -e "cycles,instructions" true 2> /dev/null + then + echo "precise_max attribute [Skipped no hardware events]" + return + fi + # Just to make sure it doesn't fail + if ! perf record -o "${perfdata}" -e "cycles:P" true 2> /dev/null + then + echo "precise_max attribute [Failed cycles:P event]" + err=1 + return + fi + # On AMD, cycles and instructions events are treated differently + if ! perf record -o "${perfdata}" -e "instructions:P" true 2> /dev/null + then + echo "precise_max attribute [Failed instructions:P event]" + err=1 + return + fi + echo "precise_max attribute test [Success]" +} + # raise the limit of file descriptors to minimum if [[ $default_fd_limit -lt $min_fd_limit ]]; then ulimit -Sn $min_fd_limit @@ -239,6 +307,9 @@ test_system_wide test_workload test_branch_counter test_cgroup +test_leader_sampling +test_topdown_leader_sampling +test_precise_max # restore the default value ulimit -Sn $default_fd_limit diff --git a/tools/perf/tests/shell/record_lbr.sh b/tools/perf/tests/shell/record_lbr.sh index 32314641217e6d..8d750ee631f877 100755 --- a/tools/perf/tests/shell/record_lbr.sh +++ b/tools/perf/tests/shell/record_lbr.sh @@ -1,5 +1,5 @@ #!/bin/bash -# perf record LBR tests +# perf record LBR tests (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e diff --git a/tools/perf/tests/shell/record_offcpu.sh b/tools/perf/tests/shell/record_offcpu.sh index 67c925f3a15aa7..678947fe69eed2 100755 --- a/tools/perf/tests/shell/record_offcpu.sh +++ b/tools/perf/tests/shell/record_offcpu.sh @@ -1,5 +1,5 @@ #!/bin/sh -# perf record offcpu profiling tests +# perf record offcpu profiling tests (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e diff --git a/tools/perf/tests/shell/stat.sh b/tools/perf/tests/shell/stat.sh index 3f1e67795490a0..7a8adf81e4b393 100755 --- a/tools/perf/tests/shell/stat.sh +++ b/tools/perf/tests/shell/stat.sh @@ -73,9 +73,33 @@ test_topdown_groups() { err=1 return fi - if perf stat -e '{topdown-retiring,slots}' true 2>&1 | grep -E -q "" + if perf stat -e 'instructions,topdown-retiring,slots' true 2>&1 | grep -E -q "" then - echo "Topdown event group test [Failed slots not reordered first]" + echo "Topdown event group test [Failed slots not reordered first in no-group case]" + err=1 + return + fi + if perf stat -e '{instructions,topdown-retiring,slots}' true 2>&1 | grep -E -q "" + then + echo "Topdown event group test [Failed slots not reordered first in single group case]" + err=1 + return + fi + if perf stat -e '{instructions,slots},topdown-retiring' true 2>&1 | grep -E -q "" + then + echo "Topdown event group test [Failed topdown metrics event not move into slots group]" + err=1 + return + fi + if perf stat -e '{instructions,slots},{topdown-retiring}' true 2>&1 | grep -E -q "" + then + echo "Topdown event group test [Failed topdown metrics group not merge into slots group]" + err=1 + return + fi + if perf stat -e '{instructions,r400,r8000}' true 2>&1 | grep -E -q "" + then + echo "Topdown event group test [Failed raw format slots not reordered first]" err=1 return fi @@ -117,16 +141,18 @@ test_cputype() { # Find a known PMU for cputype. pmu="" - for i in cpu cpu_atom armv8_pmuv3_0 + devs="/sys/bus/event_source/devices" + for i in $devs/cpu $devs/cpu_atom $devs/armv8_pmuv3_0 $devs/armv8_cortex_* do - if test -d "/sys/devices/$i" + i_base=$(basename "$i") + if test -d "$i" then - pmu="$i" + pmu="$i_base" break fi - if perf stat -e "$i/instructions/" true > /dev/null 2>&1 + if perf stat -e "$i_base/instructions/" true > /dev/null 2>&1 then - pmu="$i" + pmu="$i_base" break fi done @@ -146,6 +172,30 @@ test_cputype() { echo "cputype test [Success]" } +test_hybrid() { + # Test the default stat command on hybrid devices opens one cycles event for + # each CPU type. + echo "hybrid test" + + # Count the number of core PMUs, assume minimum of 1 + pmus=$(ls /sys/bus/event_source/devices/*/cpus 2>/dev/null | wc -l) + if [ "$pmus" -lt 1 ] + then + pmus=1 + fi + + # Run default Perf stat + cycles_events=$(perf stat -- true 2>&1 | grep -E "/cycles/[uH]*| cycles[:uH]* " -c) + + if [ "$pmus" -ne "$cycles_events" ] + then + echo "hybrid test [Found $pmus PMUs but $cycles_events cycles events. Failed]" + err=1 + return + fi + echo "hybrid test [Success]" +} + test_default_stat test_stat_record_report test_stat_record_script @@ -153,4 +203,5 @@ test_stat_repeat_weak_groups test_topdown_groups test_topdown_weak_groups test_cputype +test_hybrid exit $err diff --git a/tools/perf/tests/shell/stat_all_metricgroups.sh b/tools/perf/tests/shell/stat_all_metricgroups.sh index 55ef9c9ded2d71..c6d61a4ac3e7d3 100755 --- a/tools/perf/tests/shell/stat_all_metricgroups.sh +++ b/tools/perf/tests/shell/stat_all_metricgroups.sh @@ -1,9 +1,7 @@ -#!/bin/sh +#!/bin/bash # perf all metricgroups test # SPDX-License-Identifier: GPL-2.0 -set -e - ParanoidAndNotRoot() { [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] @@ -14,11 +12,37 @@ if ParanoidAndNotRoot 0 then system_wide_flag="" fi - +err=0 for m in $(perf list --raw-dump metricgroups) do echo "Testing $m" - perf stat -M "$m" $system_wide_flag sleep 0.01 + result=$(perf stat -M "$m" $system_wide_flag sleep 0.01 2>&1) + result_err=$? + if [[ $result_err -gt 0 ]] + then + if [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] + then + echo "Permission failure" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + else + echo "Metric group $m failed" + echo $result + err=1 # Fail + fi + fi done -exit 0 +exit $err diff --git a/tools/perf/tests/shell/stat_all_metrics.sh b/tools/perf/tests/shell/stat_all_metrics.sh index 54774525e18a7b..73e9347e88a964 100755 --- a/tools/perf/tests/shell/stat_all_metrics.sh +++ b/tools/perf/tests/shell/stat_all_metrics.sh @@ -2,42 +2,87 @@ # perf all metrics test # SPDX-License-Identifier: GPL-2.0 +ParanoidAndNotRoot() +{ + [ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ] +} + +system_wide_flag="-a" +if ParanoidAndNotRoot 0 +then + system_wide_flag="" +fi + err=0 for m in $(perf list --raw-dump metrics); do echo "Testing $m" - result=$(perf stat -M "$m" true 2>&1) - if [[ "$result" =~ ${m:0:50} ]] || [[ "$result" =~ "" ]] + result=$(perf stat -M "$m" $system_wide_flag -- sleep 0.01 2>&1) + result_err=$? + if [[ $result_err -gt 0 ]] then - continue + if [[ "$result" =~ \ + "Access to performance monitoring and observability operations is limited" ]] + then + echo "Permission failure" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "in per-thread mode, enable system wide" ]] + then + echo "Permissions - need system wide mode" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "" ]] + then + echo "Not supported events" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] + then + echo "FP issues" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + elif [[ "$result" =~ "PMM" ]] + then + echo "Optane memory issues" + echo $result + if [[ $err -eq 0 ]] + then + err=2 # Skip + fi + continue + fi fi - # Failed so try system wide. - result=$(perf stat -M "$m" -a sleep 0.01 2>&1) + if [[ "$result" =~ ${m:0:50} ]] then continue fi - # Failed again, possibly the workload was too small so retry with something - # longer. - result=$(perf stat -M "$m" perf bench internals synthesize 2>&1) + + # Failed, possibly the workload was too small so retry with something longer. + result=$(perf stat -M "$m" $system_wide_flag -- perf bench internals synthesize 2>&1) if [[ "$result" =~ ${m:0:50} ]] then continue fi echo "Metric '$m' not printed in:" echo "$result" - if [[ "$err" != "1" ]] - then - err=2 - if [[ "$result" =~ "FP_ARITH" || "$result" =~ "AMX" ]] - then - echo "Skip, not fail, for FP issues" - elif [[ "$result" =~ "PMM" ]] - then - echo "Skip, not fail, for Optane memory issues" - else - err=1 - fi - fi + err=1 done exit "$err" diff --git a/tools/perf/tests/shell/stat_all_pmu.sh b/tools/perf/tests/shell/stat_all_pmu.sh index d2a3506e0d196c..8b148b300be113 100755 --- a/tools/perf/tests/shell/stat_all_pmu.sh +++ b/tools/perf/tests/shell/stat_all_pmu.sh @@ -1,23 +1,51 @@ -#!/bin/sh -# perf all PMU test +#!/bin/bash +# perf all PMU test (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e +err=0 +result="" + +trap_cleanup() { + echo "Unexpected signal in ${FUNCNAME[1]}" + echo "$result" + exit 1 +} +trap trap_cleanup EXIT TERM INT # Test all PMU events; however exclude parameterized ones (name contains '?') -for p in $(perf list --raw-dump pmu | sed 's/[[:graph:]]\+?[[:graph:]]\+[[:space:]]//g'); do +for p in $(perf list --raw-dump pmu | sed 's/[[:graph:]]\+?[[:graph:]]\+[[:space:]]//g') +do echo "Testing $p" result=$(perf stat -e "$p" true 2>&1) - if ! echo "$result" | grep -q "$p" && ! echo "$result" | grep -q "" ; then - # We failed to see the event and it is supported. Possibly the workload was - # too small so retry with something longer. - result=$(perf stat -e "$p" perf bench internals synthesize 2>&1) - if ! echo "$result" | grep -q "$p" ; then - echo "Event '$p' not printed in:" - echo "$result" - exit 1 - fi + if echo "$result" | grep -q "$p" + then + # Event seen in output. + continue + fi + if echo "$result" | grep -q "" + then + # Event not supported, so ignore. + continue + fi + if echo "$result" | grep -q "Access to performance monitoring and observability operations is limited." + then + # Access is limited, so ignore. + continue + fi + + # We failed to see the event and it is supported. Possibly the workload was + # too small so retry with something longer. + result=$(perf stat -e "$p" perf bench internals synthesize 2>&1) + if echo "$result" | grep -q "$p" + then + # Event seen in output. + continue fi + echo "Error: event '$p' not printed in:" + echo "$result" + err=1 done -exit 0 +trap - EXIT TERM INT +exit $err diff --git a/tools/perf/tests/shell/stat_bpf_counters.sh b/tools/perf/tests/shell/stat_bpf_counters.sh index f250b7d6f773fe..95d2ad5d17c67d 100755 --- a/tools/perf/tests/shell/stat_bpf_counters.sh +++ b/tools/perf/tests/shell/stat_bpf_counters.sh @@ -1,10 +1,10 @@ #!/bin/sh -# perf stat --bpf-counters test +# perf stat --bpf-counters test (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e -workload="perf test -w brstack" +workload="perf test -w sqrtloop" # check whether $2 is within +/- 20% of $1 compare_number() diff --git a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh index e75d0780dc788a..2ec69060c42ffd 100755 --- a/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh +++ b/tools/perf/tests/shell/stat_bpf_counters_cgrp.sh @@ -58,22 +58,9 @@ check_system_wide_counted() fi } -check_cpu_list_counted() -{ - check_cpu_list_counted_output=$(perf stat -C 0,1 --bpf-counters --for-each-cgroup ${test_cgroups} -e cpu-clock -x, taskset -c 1 sleep 1 2>&1) - if echo ${check_cpu_list_counted_output} | grep -q -F " /dev/null 2>&1 + perf script -i ${perfdata} -s python:${script_path} -- \ + -d --stop-sample=30 2> /dev/null > ${file} + grep -q -e ${branch_search} ${file} + echo "Found kernel branches" +else + # kcore is required for correct kernel decode due to runtime code patching + echo "No kcore, skipping kernel test" +fi + +## Test user ## +echo "Testing userspace disassembly" +perf record -o ${perfdata} -e cs_etm//u -- touch $file > /dev/null 2>&1 +perf script -i ${perfdata} -s python:${script_path} -- \ + -d --stop-sample=30 2> /dev/null > ${file} +grep -q -e ${branch_search} ${file} +echo "Found userspace branches" + +glb_err=0 diff --git a/tools/perf/tests/shell/test_arm_spe.sh b/tools/perf/tests/shell/test_arm_spe.sh index 03d5c7d12ee53d..3258368634f793 100755 --- a/tools/perf/tests/shell/test_arm_spe.sh +++ b/tools/perf/tests/shell/test_arm_spe.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Check Arm SPE trace data recording and synthesized samples +# Check Arm SPE trace data recording and synthesized samples (exclusive) # Uses the 'perf record' to record trace data of Arm SPE events; # then verify if any SPE event samples are generated by SPE with @@ -9,7 +9,7 @@ # German Gomez , 2021 skip_if_no_arm_spe_event() { - perf list | grep -E -q 'arm_spe_[0-9]+//' && return 0 + perf list pmu | grep -E -q 'arm_spe_[0-9]+//' && return 0 # arm_spe event doesn't exist return 2 diff --git a/tools/perf/tests/shell/test_arm_spe_fork.sh b/tools/perf/tests/shell/test_arm_spe_fork.sh index 1a7e6a82d0e341..8efeef9fb9564a 100755 --- a/tools/perf/tests/shell/test_arm_spe_fork.sh +++ b/tools/perf/tests/shell/test_arm_spe_fork.sh @@ -5,7 +5,7 @@ # German Gomez , 2022 skip_if_no_arm_spe_event() { - perf list | grep -E -q 'arm_spe_[0-9]+//' && return 0 + perf list pmu | grep -E -q 'arm_spe_[0-9]+//' && return 0 return 2 } diff --git a/tools/perf/tests/shell/test_data_symbol.sh b/tools/perf/tests/shell/test_data_symbol.sh index 3dfa91832aa87f..c86da02350596b 100755 --- a/tools/perf/tests/shell/test_data_symbol.sh +++ b/tools/perf/tests/shell/test_data_symbol.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Test data symbol +# Test data symbol (exclusive) # SPDX-License-Identifier: GPL-2.0 # Leo Yan , 2022 diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh index 723ec501f99abe..e6f0070975f664 100755 --- a/tools/perf/tests/shell/test_intel_pt.sh +++ b/tools/perf/tests/shell/test_intel_pt.sh @@ -1,11 +1,11 @@ #!/bin/sh -# Miscellaneous Intel PT testing +# Miscellaneous Intel PT testing (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e # Skip if no Intel PT -perf list | grep -q 'intel_pt//' || exit 2 +perf list pmu | grep -q 'intel_pt//' || exit 2 shelldir=$(dirname "$0") # shellcheck source=lib/waiting.sh diff --git a/tools/perf/tests/shell/test_stat_intel_tpebs.sh b/tools/perf/tests/shell/test_stat_intel_tpebs.sh index c60b29add98012..f95fc64bf0a7b2 100755 --- a/tools/perf/tests/shell/test_stat_intel_tpebs.sh +++ b/tools/perf/tests/shell/test_stat_intel_tpebs.sh @@ -1,5 +1,5 @@ #!/bin/bash -# test Intel TPEBS counting mode +# test Intel TPEBS counting mode (exclusive) # SPDX-License-Identifier: GPL-2.0 set -e @@ -8,12 +8,15 @@ grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; } # Use this event for testing because it should exist in all platforms event=cache-misses:R +# Hybrid platforms output like "cpu_atom/cache-misses/R", rather than as above +alt_name=/cache-misses/R + # Without this cmd option, default value or zero is returned -echo "Testing without --record-tpebs" -result=$(perf stat -e "$event" true 2>&1) -[[ "$result" =~ $event ]] || exit 1 +#echo "Testing without --record-tpebs" +#result=$(perf stat -e "$event" true 2>&1) +#[[ "$result" =~ $event || "$result" =~ $alt_name ]] || exit 1 # In platforms that do not support TPEBS, it should execute without error. echo "Testing with --record-tpebs" result=$(perf stat -e "$event" --record-tpebs -a sleep 0.01 2>&1) -[[ "$result" =~ "perf record" && "$result" =~ $event ]] || exit 1 +[[ "$result" =~ "perf record" && "$result" =~ $event || "$result" =~ $alt_name ]] || exit 1 diff --git a/tools/perf/tests/shell/trace+probe_vfs_getname.sh b/tools/perf/tests/shell/trace+probe_vfs_getname.sh index 3146a1eece0789..708a13f0063536 100755 --- a/tools/perf/tests/shell/trace+probe_vfs_getname.sh +++ b/tools/perf/tests/shell/trace+probe_vfs_getname.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Check open filename arg using perf trace + vfs_getname +# Check open filename arg using perf trace + vfs_getname (exclusive) # Uses the 'perf test shell' library to add probe:vfs_getname to the system # then use it with 'perf trace' using 'touch' to write to a temp file, then @@ -19,7 +19,7 @@ skip_if_no_perf_trace || exit 2 . "$(dirname $0)"/lib/probe_vfs_getname.sh trace_open_vfs_getname() { - evts="$(echo "$(perf list syscalls:sys_enter_open* 2>/dev/null | grep -E 'open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/')" | sed ':a;N;s:\n:,:g')" + evts="$(echo "$(perf list tracepoint 2>/dev/null | grep -E 'syscalls:sys_enter_open(at)? ' | sed -r 's/.*sys_enter_([a-z]+) +\[.*$/\1/')" | sed ':a;N;s:\n:,:g')" perf trace -e $evts touch $file 2>&1 | \ grep -E " +[0-9]+\.[0-9]+ +\( +[0-9]+\.[0-9]+ ms\): +touch/[0-9]+ open(at)?\((dfd: +CWD, +)?filename: +\"?${file}\"?, +flags: CREAT\|NOCTTY\|NONBLOCK\|WRONLY, +mode: +IRUGO\|IWUGO\) += +[0-9]+$" } diff --git a/tools/perf/tests/shell/trace_exit_race.sh b/tools/perf/tests/shell/trace_exit_race.sh new file mode 100755 index 00000000000000..fbb0adc33a8895 --- /dev/null +++ b/tools/perf/tests/shell/trace_exit_race.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# perf trace exit race +# SPDX-License-Identifier: GPL-2.0 + +# Check that the last events of a perf trace'd subprocess are not +# lost. Specifically, trace the exiting syscall of "true" 10 times and ensure +# the output contains 10 correct lines. + +# shellcheck source=lib/probe.sh +. "$(dirname $0)"/lib/probe.sh + +skip_if_no_perf_trace || exit 2 + +if [ "$1" = "-v" ]; then + verbose="1" +fi + +iter=10 +regexp=" +[0-9]+\.[0-9]+ [0-9]+ syscalls:sys_enter_exit_group\(\)$" + +trace_shutdown_race() { + for _ in $(seq $iter); do + perf trace --no-comm -e syscalls:sys_enter_exit_group true 2>>$file + done + result="$(grep -c -E "$regexp" $file)" + [ $result = $iter ] +} + + +file=$(mktemp /tmp/temporary_file.XXXXX) + +# Do not use whatever ~/.perfconfig file, it may change the output +# via trace.{show_timestamp,show_prefix,etc} +export PERF_CONFIG=/dev/null + +trace_shutdown_race +err=$? + +if [ $err != 0 ] && [ "${verbose}" = "1" ]; then + lines_not_matching=$(mktemp /tmp/temporary_file.XXXXX) + if grep -v -E "$regexp" $file > $lines_not_matching ; then + echo "Lines not matching the expected regexp: '$regexp':" + cat $lines_not_matching + else + echo "Missing output, expected $iter but only got $result" + fi + rm -f $lines_not_matching +fi + +rm -f ${file} +exit $err diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index d33d0952025cf5..8e328bbd509dc6 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -152,4 +152,11 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ return err; } -DEFINE_SUITE("Number of exit events of a simple workload", task_exit); +struct test_case tests__task_exit[] = { + TEST_CASE_EXCLUSIVE("Number of exit events of a simple workload", task_exit), + { .name = NULL, } +}; +struct test_suite suite__task_exit = { + .desc = "Number of exit events of a simple workload", + .test_cases = tests__task_exit, +}; diff --git a/tools/perf/tests/tests-scripts.c b/tools/perf/tests/tests-scripts.c index ed114b04429365..cf3ae0c1d87174 100644 --- a/tools/perf/tests/tests-scripts.c +++ b/tools/perf/tests/tests-scripts.c @@ -175,6 +175,7 @@ static void append_script(int dir_fd, const char *name, char *desc, struct test_suite *test_suite, **result_tmp; struct test_case *tests; size_t len; + char *exclusive; snprintf(link, sizeof(link), "/proc/%d/fd/%d", getpid(), dir_fd); len = readlink(link, filename, sizeof(filename)); @@ -191,9 +192,13 @@ static void append_script(int dir_fd, const char *name, char *desc, return; } tests[0].name = strdup_check(name); + exclusive = strstr(desc, " (exclusive)"); + if (exclusive != NULL) { + tests[0].exclusive = true; + exclusive[0] = '\0'; + } tests[0].desc = strdup_check(desc); tests[0].run_case = shell_test__run; - test_suite = zalloc(sizeof(*test_suite)); if (!test_suite) { pr_err("Out of memory while building script test suite list\n"); diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 6ea2be86b7bf8b..cb58b43aa063c9 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -36,6 +36,7 @@ struct test_case { const char *desc; const char *skip_reason; test_fnptr run_case; + bool exclusive; }; struct test_suite { @@ -62,6 +63,14 @@ struct test_suite { .skip_reason = _reason, \ } +#define TEST_CASE_EXCLUSIVE(description, _name) \ + { \ + .name = #_name, \ + .desc = description, \ + .run_case = test__##_name, \ + .exclusive = true, \ + } + #define DEFINE_SUITE(description, _name) \ struct test_case tests__##_name[] = { \ TEST_CASE(description, _name), \ @@ -83,6 +92,8 @@ DECLARE_SUITE(perf_evsel__tp_sched_test); DECLARE_SUITE(syscall_openat_tp_fields); DECLARE_SUITE(pmu); DECLARE_SUITE(pmu_events); +DECLARE_SUITE(hwmon_pmu); +DECLARE_SUITE(tool_pmu); DECLARE_SUITE(attr); DECLARE_SUITE(dso_data); DECLARE_SUITE(dso_data_cache); diff --git a/tools/perf/tests/tool_pmu.c b/tools/perf/tests/tool_pmu.c new file mode 100644 index 00000000000000..187942b749b7c9 --- /dev/null +++ b/tools/perf/tests/tool_pmu.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +#include "debug.h" +#include "evlist.h" +#include "parse-events.h" +#include "tests.h" +#include "tool_pmu.h" + +static int do_test(enum tool_pmu_event ev, bool with_pmu) +{ + struct evlist *evlist = evlist__new(); + struct evsel *evsel; + struct parse_events_error err; + int ret; + char str[128]; + bool found = false; + + if (!evlist) { + pr_err("evlist allocation failed\n"); + return TEST_FAIL; + } + + if (with_pmu) + snprintf(str, sizeof(str), "tool/%s/", tool_pmu__event_to_str(ev)); + else + snprintf(str, sizeof(str), "%s", tool_pmu__event_to_str(ev)); + + parse_events_error__init(&err); + ret = parse_events(evlist, str, &err); + if (ret) { + if (tool_pmu__skip_event(tool_pmu__event_to_str(ev))) { + ret = TEST_OK; + goto out; + } + + pr_debug("FAILED %s:%d failed to parse event '%s', err %d\n", + __FILE__, __LINE__, str, ret); + parse_events_error__print(&err, str); + ret = TEST_FAIL; + goto out; + } + + ret = TEST_OK; + if (with_pmu ? (evlist->core.nr_entries != 1) : (evlist->core.nr_entries < 1)) { + pr_debug("FAILED %s:%d Unexpected number of events for '%s' of %d\n", + __FILE__, __LINE__, str, evlist->core.nr_entries); + ret = TEST_FAIL; + goto out; + } + + evlist__for_each_entry(evlist, evsel) { + if (perf_pmu__is_tool(evsel->pmu)) { + if (evsel->core.attr.config != ev) { + pr_debug("FAILED %s:%d Unexpected config for '%s', %lld != %d\n", + __FILE__, __LINE__, str, evsel->core.attr.config, ev); + ret = TEST_FAIL; + goto out; + } + found = true; + } + } + + if (!found && !tool_pmu__skip_event(tool_pmu__event_to_str(ev))) { + pr_debug("FAILED %s:%d Didn't find tool event '%s' in parsed evsels\n", + __FILE__, __LINE__, str); + ret = TEST_FAIL; + } + +out: + parse_events_error__exit(&err); + evlist__delete(evlist); + return ret; +} + +static int test__tool_pmu_without_pmu(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + int i; + + tool_pmu__for_each_event(i) { + int ret = do_test(i, /*with_pmu=*/false); + + if (ret != TEST_OK) + return ret; + } + return TEST_OK; +} + +static int test__tool_pmu_with_pmu(struct test_suite *test __maybe_unused, + int subtest __maybe_unused) +{ + int i; + + tool_pmu__for_each_event(i) { + int ret = do_test(i, /*with_pmu=*/true); + + if (ret != TEST_OK) + return ret; + } + return TEST_OK; +} + +static struct test_case tests__tool_pmu[] = { + TEST_CASE("Parsing without PMU name", tool_pmu_without_pmu), + TEST_CASE("Parsing with PMU name", tool_pmu_with_pmu), + { .name = NULL, } +}; + +struct test_suite suite__tool_pmu = { + .desc = "Tool PMU", + .test_cases = tests__tool_pmu, +}; diff --git a/tools/perf/trace/beauty/fs_at_flags.sh b/tools/perf/trace/beauty/fs_at_flags.sh index e3f13f96a27c22..fac4d0c049fcc8 100755 --- a/tools/perf/trace/beauty/fs_at_flags.sh +++ b/tools/perf/trace/beauty/fs_at_flags.sh @@ -13,13 +13,14 @@ printf "static const char *fs_at_flags[] = {\n" regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+AT_([^_]+[[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' # AT_EACCESS is only meaningful to faccessat, so we will special case it there... # AT_STATX_SYNC_TYPE is not a bit, its a mask of AT_STATX_SYNC_AS_STAT, AT_STATX_FORCE_SYNC and AT_STATX_DONT_SYNC -# AT_HANDLE_FID and AT_HANDLE_MNT_ID_UNIQUE are reusing values and are valid only for name_to_handle_at() +# AT_HANDLE_FID, AT_HANDLE_MNT_ID_UNIQUE and AT_HANDLE_CONNECTABLE are reusing values and are valid only for name_to_handle_at() # AT_RENAME_NOREPLACE reuses 0x1 and is valid only for renameat2() grep -E $regex ${linux_fcntl} | \ grep -v AT_EACCESS | \ grep -v AT_STATX_SYNC_TYPE | \ grep -v AT_HANDLE_FID | \ grep -v AT_HANDLE_MNT_ID_UNIQUE | \ + grep -v AT_HANDLE_CONNECTABLE | \ grep -v AT_RENAME_NOREPLACE | \ sed -r "s/$regex/\2 \1/g" | \ xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n" diff --git a/tools/perf/trace/beauty/include/uapi/linux/fcntl.h b/tools/perf/trace/beauty/include/uapi/linux/fcntl.h index 87e2dec79fea4e..6e6907e63bfc2b 100644 --- a/tools/perf/trace/beauty/include/uapi/linux/fcntl.h +++ b/tools/perf/trace/beauty/include/uapi/linux/fcntl.h @@ -153,9 +153,6 @@ object identity and may not be usable with open_by_handle_at(2). */ #define AT_HANDLE_MNT_ID_UNIQUE 0x001 /* Return the u64 unique mount ID. */ - -#if defined(__KERNEL__) -#define AT_GETATTR_NOSEC 0x80000000 -#endif +#define AT_HANDLE_CONNECTABLE 0x002 /* Request a connectable file handle */ #endif /* _UAPI_LINUX_FCNTL_H */ diff --git a/tools/perf/trace/beauty/include/uapi/linux/mount.h b/tools/perf/trace/beauty/include/uapi/linux/mount.h index 225bc366ffcbf0..c07008816acae8 100644 --- a/tools/perf/trace/beauty/include/uapi/linux/mount.h +++ b/tools/perf/trace/beauty/include/uapi/linux/mount.h @@ -154,7 +154,7 @@ struct mount_attr { */ struct statmount { __u32 size; /* Total size, including strings */ - __u32 mnt_opts; /* [str] Mount options of the mount */ + __u32 mnt_opts; /* [str] Options (comma separated, escaped) */ __u64 mask; /* What results were written */ __u32 sb_dev_major; /* Device ID */ __u32 sb_dev_minor; @@ -173,7 +173,13 @@ struct statmount { __u32 mnt_root; /* [str] Root of mount relative to root of fs */ __u32 mnt_point; /* [str] Mountpoint relative to current root */ __u64 mnt_ns_id; /* ID of the mount namespace */ - __u64 __spare2[49]; + __u32 fs_subtype; /* [str] Subtype of fs_type (if any) */ + __u32 sb_source; /* [str] Source string of the mount */ + __u32 opt_num; /* Number of fs options */ + __u32 opt_array; /* [str] Array of nul terminated fs options */ + __u32 opt_sec_num; /* Number of security options */ + __u32 opt_sec_array; /* [str] Array of nul terminated security options */ + __u64 __spare2[46]; char str[]; /* Variable size part containing strings */ }; @@ -207,6 +213,10 @@ struct mnt_id_req { #define STATMOUNT_FS_TYPE 0x00000020U /* Want/got fs_type */ #define STATMOUNT_MNT_NS_ID 0x00000040U /* Want/got mnt_ns_id */ #define STATMOUNT_MNT_OPTS 0x00000080U /* Want/got mnt_opts */ +#define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */ +#define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */ +#define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */ +#define STATMOUNT_OPT_SEC_ARRAY 0x00000800U /* Want/got opt_sec... */ /* * Special @mnt_id values that can be passed to listmount diff --git a/tools/perf/trace/beauty/include/uapi/linux/prctl.h b/tools/perf/trace/beauty/include/uapi/linux/prctl.h index 35791791a879b2..5c6080680cb27b 100644 --- a/tools/perf/trace/beauty/include/uapi/linux/prctl.h +++ b/tools/perf/trace/beauty/include/uapi/linux/prctl.h @@ -230,7 +230,7 @@ struct prctl_mm_map { # define PR_PAC_APDBKEY (1UL << 3) # define PR_PAC_APGAKEY (1UL << 4) -/* Tagged user address controls for arm64 */ +/* Tagged user address controls for arm64 and RISC-V */ #define PR_SET_TAGGED_ADDR_CTRL 55 #define PR_GET_TAGGED_ADDR_CTRL 56 # define PR_TAGGED_ADDR_ENABLE (1UL << 0) @@ -244,6 +244,9 @@ struct prctl_mm_map { # define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) /* Unused; kept only for source compatibility */ # define PR_MTE_TCF_SHIFT 1 +/* RISC-V pointer masking tag length */ +# define PR_PMLEN_SHIFT 24 +# define PR_PMLEN_MASK (0x7fUL << PR_PMLEN_SHIFT) /* Control reclaim behavior when allocating memory */ #define PR_SET_IO_FLUSHER 57 @@ -328,4 +331,26 @@ struct prctl_mm_map { # define PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC 0x10 /* Clear the aspect on exec */ # define PR_PPC_DEXCR_CTRL_MASK 0x1f +/* + * Get the current shadow stack configuration for the current thread, + * this will be the value configured via PR_SET_SHADOW_STACK_STATUS. + */ +#define PR_GET_SHADOW_STACK_STATUS 74 + +/* + * Set the current shadow stack configuration. Enabling the shadow + * stack will cause a shadow stack to be allocated for the thread. + */ +#define PR_SET_SHADOW_STACK_STATUS 75 +# define PR_SHADOW_STACK_ENABLE (1UL << 0) +# define PR_SHADOW_STACK_WRITE (1UL << 1) +# define PR_SHADOW_STACK_PUSH (1UL << 2) + +/* + * Prevent further changes to the specified shadow stack + * configuration. All bits may be locked via this call, including + * undefined bits. + */ +#define PR_LOCK_SHADOW_STACK_STATUS 76 + #endif /* _LINUX_PRCTL_H */ diff --git a/tools/perf/util/Build b/tools/perf/util/Build index dc616292b2ddf2..c06d2ee9024c63 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -83,6 +83,8 @@ perf-util-y += pmu.o perf-util-y += pmus.o perf-util-y += pmu-flex.o perf-util-y += pmu-bison.o +perf-util-y += hwmon_pmu.o +perf-util-y += tool_pmu.o perf-util-y += svghelper.o perf-util-$(CONFIG_LIBTRACEEVENT) += trace-event-info.o perf-util-y += trace-event-scripting.o @@ -199,11 +201,14 @@ ifndef CONFIG_SETNS perf-util-y += setns.o endif -perf-util-$(CONFIG_DWARF) += probe-finder.o -perf-util-$(CONFIG_DWARF) += dwarf-aux.o -perf-util-$(CONFIG_DWARF) += dwarf-regs.o -perf-util-$(CONFIG_DWARF) += debuginfo.o -perf-util-$(CONFIG_DWARF) += annotate-data.o +perf-util-$(CONFIG_LIBDW) += probe-finder.o +perf-util-$(CONFIG_LIBDW) += dwarf-aux.o +perf-util-$(CONFIG_LIBDW) += dwarf-regs.o +perf-util-$(CONFIG_LIBDW) += dwarf-regs-csky.o +perf-util-$(CONFIG_LIBDW) += dwarf-regs-powerpc.o +perf-util-$(CONFIG_LIBDW) += dwarf-regs-x86.o +perf-util-$(CONFIG_LIBDW) += debuginfo.o +perf-util-$(CONFIG_LIBDW) += annotate-data.o perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o perf-util-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o @@ -234,7 +239,7 @@ perf-util-$(CONFIG_LIBLLVM) += llvm-c-helpers.o ifdef CONFIG_JITDUMP perf-util-$(CONFIG_LIBELF) += jitdump.o perf-util-$(CONFIG_LIBELF) += genelf.o -perf-util-$(CONFIG_DWARF) += genelf_debug.o +perf-util-$(CONFIG_LIBDW) += genelf_debug.o endif perf-util-y += perf-hooks.o diff --git a/tools/perf/util/annotate-data.h b/tools/perf/util/annotate-data.h index 8ac0fd94a0ba4e..98c80b2268dde8 100644 --- a/tools/perf/util/annotate-data.h +++ b/tools/perf/util/annotate-data.h @@ -9,7 +9,7 @@ #include "dwarf-regs.h" #include "annotate.h" -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT #include "debuginfo.h" #endif @@ -165,7 +165,7 @@ struct annotated_data_stat { }; extern struct annotated_data_stat ann_data_stat; -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT /* * Type information in a register, valid when @ok is true. * The @caller_saved registers are invalidated after a function call. @@ -244,7 +244,7 @@ bool get_global_var_info(struct data_loc_info *dloc, u64 addr, const char **var_name, int *var_offset); void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind); -#else /* HAVE_DWARF_SUPPORT */ +#else /* HAVE_LIBDW_SUPPORT */ static inline struct annotated_data_type * find_data_type(struct data_loc_info *dloc __maybe_unused) @@ -276,7 +276,7 @@ static inline int hist_entry__annotate_data_tty(struct hist_entry *he __maybe_un return -1; } -#endif /* HAVE_DWARF_SUPPORT */ +#endif /* HAVE_LIBDW_SUPPORT */ #ifdef HAVE_SLANG_SUPPORT int hist_entry__annotate_data_tui(struct hist_entry *he, struct evsel *evsel, diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 37ce43c4eb8f69..32e15c9f53f3c0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2116,6 +2116,12 @@ static int annotation__config(const char *var, const char *value, void *data) opt->offset_level = ANNOTATION__MAX_OFFSET_LEVEL; else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL) opt->offset_level = ANNOTATION__MIN_OFFSET_LEVEL; + } else if (!strcmp(var, "annotate.disassemblers")) { + opt->disassemblers_str = strdup(value); + if (!opt->disassemblers_str) { + pr_err("Not enough memory for annotate.disassemblers\n"); + return -1; + } } else if (!strcmp(var, "annotate.hide_src_code")) { opt->hide_src_code = perf_config_bool("hide_src_code", value); } else if (!strcmp(var, "annotate.jump_arrows")) { @@ -2292,7 +2298,7 @@ static int extract_reg_offset(struct arch *arch, const char *str, if (regname == NULL) return -1; - op_loc->reg1 = get_dwarf_regnum(regname, 0); + op_loc->reg1 = get_dwarf_regnum(regname, arch->e_machine, arch->e_flags); free(regname); /* Get the second register */ @@ -2305,7 +2311,7 @@ static int extract_reg_offset(struct arch *arch, const char *str, if (regname == NULL) return -1; - op_loc->reg2 = get_dwarf_regnum(regname, 0); + op_loc->reg2 = get_dwarf_regnum(regname, arch->e_machine, arch->e_flags); free(regname); } return 0; @@ -2405,7 +2411,7 @@ int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl, return -1; if (*s == arch->objdump.register_char) - op_loc->reg1 = get_dwarf_regnum(s, 0); + op_loc->reg1 = get_dwarf_regnum(s, arch->e_machine, arch->e_flags); else if (*s == arch->objdump.imm_char) { op_loc->offset = strtol(s + 1, &p, 0); if (p && p != s + 1) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8b9e05a1932f2f..194a05cbc506e4 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -34,6 +34,9 @@ struct annotated_data_type; #define ANNOTATION__BR_CNTR_WIDTH 30 #define ANNOTATION_DUMMY_LEN 256 +// llvm, capstone, objdump +#define MAX_DISASSEMBLERS 3 + struct annotation_options { bool hide_src_code, use_offset, @@ -49,11 +52,14 @@ struct annotation_options { annotate_src, full_addr; u8 offset_level; + u8 nr_disassemblers; int min_pcnt; int max_lines; int context; char *objdump_path; char *disassembler_style; + const char *disassemblers_str; + const char *disassemblers[MAX_DISASSEMBLERS]; const char *prefix; const char *prefix_strip; unsigned int percent_type; diff --git a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h index 1443c28545a946..358c611eeddbb3 100644 --- a/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h +++ b/tools/perf/util/arm-spe-decoder/arm-spe-decoder.h @@ -56,15 +56,15 @@ enum arm_spe_op_type { ARM_SPE_OP_BR_INDIRECT = 1 << 17, }; -enum arm_spe_neoverse_data_source { - ARM_SPE_NV_L1D = 0x0, - ARM_SPE_NV_L2 = 0x8, - ARM_SPE_NV_PEER_CORE = 0x9, - ARM_SPE_NV_LOCAL_CLUSTER = 0xa, - ARM_SPE_NV_SYS_CACHE = 0xb, - ARM_SPE_NV_PEER_CLUSTER = 0xc, - ARM_SPE_NV_REMOTE = 0xd, - ARM_SPE_NV_DRAM = 0xe, +enum arm_spe_common_data_source { + ARM_SPE_COMMON_DS_L1D = 0x0, + ARM_SPE_COMMON_DS_L2 = 0x8, + ARM_SPE_COMMON_DS_PEER_CORE = 0x9, + ARM_SPE_COMMON_DS_LOCAL_CLUSTER = 0xa, + ARM_SPE_COMMON_DS_SYS_CACHE = 0xb, + ARM_SPE_COMMON_DS_PEER_CLUSTER = 0xc, + ARM_SPE_COMMON_DS_REMOTE = 0xd, + ARM_SPE_COMMON_DS_DRAM = 0xe, }; struct arm_spe_record { diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index 138ffc71b32dd7..dbf13f47879c00 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -46,7 +46,6 @@ struct arm_spe { struct perf_session *session; struct machine *machine; u32 pmu_type; - u64 midr; struct perf_tsc_conversion tc; @@ -69,7 +68,7 @@ struct arm_spe { u64 llc_access_id; u64 tlb_miss_id; u64 tlb_access_id; - u64 branch_miss_id; + u64 branch_id; u64 remote_access_id; u64 memory_id; u64 instructions_id; @@ -78,6 +77,11 @@ struct arm_spe { unsigned long num_events; u8 use_ctx_pkt_for_pid; + + u64 **metadata; + u64 metadata_ver; + u64 metadata_nr_cpu; + bool is_homogeneous; }; struct arm_spe_queue { @@ -96,6 +100,7 @@ struct arm_spe_queue { u64 timestamp; struct thread *thread; u64 period_instructions; + u32 flags; }; static void arm_spe_dump(struct arm_spe *spe __maybe_unused, @@ -118,7 +123,7 @@ static void arm_spe_dump(struct arm_spe *spe __maybe_unused, else pkt_len = 1; printf("."); - color_fprintf(stdout, color, " %08x: ", pos); + color_fprintf(stdout, color, " %08zx: ", pos); for (i = 0; i < pkt_len; i++) color_fprintf(stdout, color, " %02x", buf[i]); for (; i < 16; i++) @@ -273,6 +278,20 @@ static int arm_spe_set_tid(struct arm_spe_queue *speq, pid_t tid) return 0; } +static u64 *arm_spe__get_metadata_by_cpu(struct arm_spe *spe, u64 cpu) +{ + u64 i; + + if (!spe->metadata) + return NULL; + + for (i = 0; i < spe->metadata_nr_cpu; i++) + if (spe->metadata[i][ARM_SPE_CPU] == cpu) + return spe->metadata[i]; + + return NULL; +} + static struct simd_flags arm_spe__synth_simd_flags(const struct arm_spe_record *record) { struct simd_flags simd_flags = {}; @@ -376,6 +395,7 @@ static int arm_spe__synth_branch_sample(struct arm_spe_queue *speq, sample.stream_id = spe_events_id; sample.addr = record->to_ip; sample.weight = record->latency; + sample.flags = speq->flags; return arm_spe_deliver_synth_event(spe, speq, event, &sample); } @@ -400,24 +420,44 @@ static int arm_spe__synth_instruction_sample(struct arm_spe_queue *speq, sample.id = spe_events_id; sample.stream_id = spe_events_id; - sample.addr = record->virt_addr; + sample.addr = record->to_ip; sample.phys_addr = record->phys_addr; sample.data_src = data_src; sample.period = spe->instructions_sample_period; sample.weight = record->latency; + sample.flags = speq->flags; return arm_spe_deliver_synth_event(spe, speq, event, &sample); } -static const struct midr_range neoverse_spe[] = { +static const struct midr_range common_ds_encoding_cpus[] = { + MIDR_ALL_VERSIONS(MIDR_CORTEX_A720), + MIDR_ALL_VERSIONS(MIDR_CORTEX_A725), + MIDR_ALL_VERSIONS(MIDR_CORTEX_X1C), + MIDR_ALL_VERSIONS(MIDR_CORTEX_X3), + MIDR_ALL_VERSIONS(MIDR_CORTEX_X925), MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1), MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2), MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1), + MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V2), {}, }; -static void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *record, - union perf_mem_data_src *data_src) +static void arm_spe__sample_flags(struct arm_spe_queue *speq) +{ + const struct arm_spe_record *record = &speq->decoder->record; + + speq->flags = 0; + if (record->op & ARM_SPE_OP_BRANCH_ERET) { + speq->flags = PERF_IP_FLAG_BRANCH; + + if (record->type & ARM_SPE_BRANCH_MISS) + speq->flags |= PERF_IP_FLAG_BRANCH_MISS; + } +} + +static void arm_spe__synth_data_source_common(const struct arm_spe_record *record, + union perf_mem_data_src *data_src) { /* * Even though four levels of cache hierarchy are possible, no known @@ -439,17 +479,17 @@ static void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *rec } switch (record->source) { - case ARM_SPE_NV_L1D: + case ARM_SPE_COMMON_DS_L1D: data_src->mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L1; data_src->mem_snoop = PERF_MEM_SNOOP_NONE; break; - case ARM_SPE_NV_L2: + case ARM_SPE_COMMON_DS_L2: data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2; data_src->mem_snoop = PERF_MEM_SNOOP_NONE; break; - case ARM_SPE_NV_PEER_CORE: + case ARM_SPE_COMMON_DS_PEER_CORE: data_src->mem_lvl = PERF_MEM_LVL_L2 | PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L2; data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER; @@ -458,8 +498,8 @@ static void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *rec * We don't know if this is L1, L2 but we do know it was a cache-2-cache * transfer, so set SNOOPX_PEER */ - case ARM_SPE_NV_LOCAL_CLUSTER: - case ARM_SPE_NV_PEER_CLUSTER: + case ARM_SPE_COMMON_DS_LOCAL_CLUSTER: + case ARM_SPE_COMMON_DS_PEER_CLUSTER: data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER; @@ -467,7 +507,7 @@ static void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *rec /* * System cache is assumed to be L3 */ - case ARM_SPE_NV_SYS_CACHE: + case ARM_SPE_COMMON_DS_SYS_CACHE: data_src->mem_lvl = PERF_MEM_LVL_L3 | PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_L3; data_src->mem_snoop = PERF_MEM_SNOOP_HIT; @@ -476,13 +516,13 @@ static void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *rec * We don't know what level it hit in, except it came from the other * socket */ - case ARM_SPE_NV_REMOTE: + case ARM_SPE_COMMON_DS_REMOTE: data_src->mem_lvl = PERF_MEM_LVL_REM_CCE1; data_src->mem_lvl_num = PERF_MEM_LVLNUM_ANY_CACHE; data_src->mem_remote = PERF_MEM_REMOTE_REMOTE; data_src->mem_snoopx = PERF_MEM_SNOOPX_PEER; break; - case ARM_SPE_NV_DRAM: + case ARM_SPE_COMMON_DS_DRAM: data_src->mem_lvl = PERF_MEM_LVL_LOC_RAM | PERF_MEM_LVL_HIT; data_src->mem_lvl_num = PERF_MEM_LVLNUM_RAM; data_src->mem_snoop = PERF_MEM_SNOOP_NONE; @@ -492,8 +532,8 @@ static void arm_spe__synth_data_source_neoverse(const struct arm_spe_record *rec } } -static void arm_spe__synth_data_source_generic(const struct arm_spe_record *record, - union perf_mem_data_src *data_src) +static void arm_spe__synth_memory_level(const struct arm_spe_record *record, + union perf_mem_data_src *data_src) { if (record->type & (ARM_SPE_LLC_ACCESS | ARM_SPE_LLC_MISS)) { data_src->mem_lvl = PERF_MEM_LVL_L3; @@ -515,10 +555,55 @@ static void arm_spe__synth_data_source_generic(const struct arm_spe_record *reco data_src->mem_lvl |= PERF_MEM_LVL_REM_CCE1; } -static u64 arm_spe__synth_data_source(const struct arm_spe_record *record, u64 midr) +static bool arm_spe__is_common_ds_encoding(struct arm_spe_queue *speq) +{ + struct arm_spe *spe = speq->spe; + bool is_in_cpu_list; + u64 *metadata = NULL; + u64 midr = 0; + + /* Metadata version 1 assumes all CPUs are the same (old behavior) */ + if (spe->metadata_ver == 1) { + const char *cpuid; + + pr_warning_once("Old SPE metadata, re-record to improve decode accuracy\n"); + cpuid = perf_env__cpuid(spe->session->evlist->env); + midr = strtol(cpuid, NULL, 16); + } else { + /* CPU ID is -1 for per-thread mode */ + if (speq->cpu < 0) { + /* + * On the heterogeneous system, due to CPU ID is -1, + * cannot confirm the data source packet is supported. + */ + if (!spe->is_homogeneous) + return false; + + /* In homogeneous system, simply use CPU0's metadata */ + if (spe->metadata) + metadata = spe->metadata[0]; + } else { + metadata = arm_spe__get_metadata_by_cpu(spe, speq->cpu); + } + + if (!metadata) + return false; + + midr = metadata[ARM_SPE_CPU_MIDR]; + } + + is_in_cpu_list = is_midr_in_range_list(midr, common_ds_encoding_cpus); + if (is_in_cpu_list) + return true; + else + return false; +} + +static u64 arm_spe__synth_data_source(struct arm_spe_queue *speq, + const struct arm_spe_record *record) { union perf_mem_data_src data_src = { .mem_op = PERF_MEM_OP_NA }; - bool is_neoverse = is_midr_in_range_list(midr, neoverse_spe); + bool is_common = arm_spe__is_common_ds_encoding(speq); if (record->op & ARM_SPE_OP_LD) data_src.mem_op = PERF_MEM_OP_LOAD; @@ -527,10 +612,10 @@ static u64 arm_spe__synth_data_source(const struct arm_spe_record *record, u64 m else return 0; - if (is_neoverse) - arm_spe__synth_data_source_neoverse(record, &data_src); + if (is_common) + arm_spe__synth_data_source_common(record, &data_src); else - arm_spe__synth_data_source_generic(record, &data_src); + arm_spe__synth_memory_level(record, &data_src); if (record->type & (ARM_SPE_TLB_ACCESS | ARM_SPE_TLB_MISS)) { data_src.mem_dtlb = PERF_MEM_TLB_WK; @@ -551,7 +636,8 @@ static int arm_spe_sample(struct arm_spe_queue *speq) u64 data_src; int err; - data_src = arm_spe__synth_data_source(record, spe->midr); + arm_spe__sample_flags(speq); + data_src = arm_spe__synth_data_source(speq, record); if (spe->sample_flc) { if (record->type & ARM_SPE_L1D_MISS) { @@ -601,8 +687,8 @@ static int arm_spe_sample(struct arm_spe_queue *speq) } } - if (spe->sample_branch && (record->type & ARM_SPE_BRANCH_MISS)) { - err = arm_spe__synth_branch_sample(speq, spe->branch_miss_id); + if (spe->sample_branch && (record->op & ARM_SPE_OP_BRANCH_ERET)) { + err = arm_spe__synth_branch_sample(speq, spe->branch_id); if (err) return err; } @@ -1016,6 +1102,73 @@ static int arm_spe_flush(struct perf_session *session __maybe_unused, return 0; } +static u64 *arm_spe__alloc_per_cpu_metadata(u64 *buf, int per_cpu_size) +{ + u64 *metadata; + + metadata = zalloc(per_cpu_size); + if (!metadata) + return NULL; + + memcpy(metadata, buf, per_cpu_size); + return metadata; +} + +static void arm_spe__free_metadata(u64 **metadata, int nr_cpu) +{ + int i; + + for (i = 0; i < nr_cpu; i++) + zfree(&metadata[i]); + free(metadata); +} + +static u64 **arm_spe__alloc_metadata(struct perf_record_auxtrace_info *info, + u64 *ver, int *nr_cpu) +{ + u64 *ptr = (u64 *)info->priv; + u64 metadata_size; + u64 **metadata = NULL; + int hdr_sz, per_cpu_sz, i; + + metadata_size = info->header.size - + sizeof(struct perf_record_auxtrace_info); + + /* Metadata version 1 */ + if (metadata_size == ARM_SPE_AUXTRACE_V1_PRIV_SIZE) { + *ver = 1; + *nr_cpu = 0; + /* No per CPU metadata */ + return NULL; + } + + *ver = ptr[ARM_SPE_HEADER_VERSION]; + hdr_sz = ptr[ARM_SPE_HEADER_SIZE]; + *nr_cpu = ptr[ARM_SPE_CPUS_NUM]; + + metadata = calloc(*nr_cpu, sizeof(*metadata)); + if (!metadata) + return NULL; + + /* Locate the start address of per CPU metadata */ + ptr += hdr_sz; + per_cpu_sz = (metadata_size - (hdr_sz * sizeof(u64))) / (*nr_cpu); + + for (i = 0; i < *nr_cpu; i++) { + metadata[i] = arm_spe__alloc_per_cpu_metadata(ptr, per_cpu_sz); + if (!metadata[i]) + goto err_per_cpu_metadata; + + ptr += per_cpu_sz / sizeof(u64); + } + + return metadata; + +err_per_cpu_metadata: + arm_spe__free_metadata(metadata, *nr_cpu); + return NULL; +} + static void arm_spe_free_queue(void *priv) { struct arm_spe_queue *speq = priv; @@ -1050,6 +1203,7 @@ static void arm_spe_free(struct perf_session *session) auxtrace_heap__free(&spe->heap); arm_spe_free_events(session); session->auxtrace = NULL; + arm_spe__free_metadata(spe->metadata, spe->metadata_nr_cpu); free(spe); } @@ -1061,16 +1215,60 @@ static bool arm_spe_evsel_is_auxtrace(struct perf_session *session, return evsel->core.attr.type == spe->pmu_type; } -static const char * const arm_spe_info_fmts[] = { - [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n", +static const char * const metadata_hdr_v1_fmts[] = { + [ARM_SPE_PMU_TYPE] = " PMU Type :%"PRId64"\n", + [ARM_SPE_PER_CPU_MMAPS] = " Per CPU mmaps :%"PRId64"\n", +}; + +static const char * const metadata_hdr_fmts[] = { + [ARM_SPE_HEADER_VERSION] = " Header version :%"PRId64"\n", + [ARM_SPE_HEADER_SIZE] = " Header size :%"PRId64"\n", + [ARM_SPE_PMU_TYPE_V2] = " PMU type v2 :%"PRId64"\n", + [ARM_SPE_CPUS_NUM] = " CPU number :%"PRId64"\n", +}; + +static const char * const metadata_per_cpu_fmts[] = { + [ARM_SPE_MAGIC] = " Magic :0x%"PRIx64"\n", + [ARM_SPE_CPU] = " CPU # :%"PRId64"\n", + [ARM_SPE_CPU_NR_PARAMS] = " Num of params :%"PRId64"\n", + [ARM_SPE_CPU_MIDR] = " MIDR :0x%"PRIx64"\n", + [ARM_SPE_CPU_PMU_TYPE] = " PMU Type :%"PRId64"\n", + [ARM_SPE_CAP_MIN_IVAL] = " Min Interval :%"PRId64"\n", }; -static void arm_spe_print_info(__u64 *arr) +static void arm_spe_print_info(struct arm_spe *spe, __u64 *arr) { + unsigned int i, cpu, hdr_size, cpu_num, cpu_size; + const char * const *hdr_fmts; + if (!dump_trace) return; - fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]); + if (spe->metadata_ver == 1) { + cpu_num = 0; + hdr_size = ARM_SPE_AUXTRACE_V1_PRIV_MAX; + hdr_fmts = metadata_hdr_v1_fmts; + } else { + cpu_num = arr[ARM_SPE_CPUS_NUM]; + hdr_size = arr[ARM_SPE_HEADER_SIZE]; + hdr_fmts = metadata_hdr_fmts; + } + + for (i = 0; i < hdr_size; i++) + fprintf(stdout, hdr_fmts[i], arr[i]); + + arr += hdr_size; + for (cpu = 0; cpu < cpu_num; cpu++) { + /* + * The parameters from ARM_SPE_MAGIC to ARM_SPE_CPU_NR_PARAMS + * are fixed. The sequential parameter size is decided by the + * field 'ARM_SPE_CPU_NR_PARAMS'. + */ + cpu_size = (ARM_SPE_CPU_NR_PARAMS + 1) + arr[ARM_SPE_CPU_NR_PARAMS]; + for (i = 0; i < cpu_size; i++) + fprintf(stdout, metadata_per_cpu_fmts[i], arr[i]); + arr += cpu_size; + } } static void arm_spe_set_event_name(struct evlist *evlist, u64 id, @@ -1202,12 +1400,12 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) if (spe->synth_opts.branches) { spe->sample_branch = true; - /* Branch miss */ + /* Branch */ err = perf_session__deliver_synth_attr_event(session, &attr, id); if (err) return err; - spe->branch_miss_id = id; - arm_spe_set_event_name(evlist, id, "branch-miss"); + spe->branch_id = id; + arm_spe_set_event_name(evlist, id, "branch"); id += 1; } @@ -1258,24 +1456,57 @@ arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session) return 0; } +static bool arm_spe__is_homogeneous(u64 **metadata, int nr_cpu) +{ + u64 midr; + int i; + + if (!nr_cpu) + return false; + + for (i = 0; i < nr_cpu; i++) { + if (!metadata[i]) + return false; + + if (i == 0) { + midr = metadata[i][ARM_SPE_CPU_MIDR]; + continue; + } + + if (midr != metadata[i][ARM_SPE_CPU_MIDR]) + return false; + } + + return true; +} + int arm_spe_process_auxtrace_info(union perf_event *event, struct perf_session *session) { struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; - size_t min_sz = sizeof(u64) * ARM_SPE_AUXTRACE_PRIV_MAX; + size_t min_sz = ARM_SPE_AUXTRACE_V1_PRIV_SIZE; struct perf_record_time_conv *tc = &session->time_conv; - const char *cpuid = perf_env__cpuid(session->evlist->env); - u64 midr = strtol(cpuid, NULL, 16); struct arm_spe *spe; - int err; + u64 **metadata = NULL; + u64 metadata_ver; + int nr_cpu, err; if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + min_sz) return -EINVAL; + metadata = arm_spe__alloc_metadata(auxtrace_info, &metadata_ver, + &nr_cpu); + if (!metadata && metadata_ver != 1) { + pr_err("Failed to parse Arm SPE metadata.\n"); + return -EINVAL; + } + spe = zalloc(sizeof(struct arm_spe)); - if (!spe) - return -ENOMEM; + if (!spe) { + err = -ENOMEM; + goto err_free_metadata; + } err = auxtrace_queues__init(&spe->queues); if (err) @@ -1284,8 +1515,14 @@ int arm_spe_process_auxtrace_info(union perf_event *event, spe->session = session; spe->machine = &session->machines.host; /* No kvm support */ spe->auxtrace_type = auxtrace_info->type; - spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE]; - spe->midr = midr; + if (metadata_ver == 1) + spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE]; + else + spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE_V2]; + spe->metadata = metadata; + spe->metadata_ver = metadata_ver; + spe->metadata_nr_cpu = nr_cpu; + spe->is_homogeneous = arm_spe__is_homogeneous(metadata, nr_cpu); spe->timeless_decoding = arm_spe__is_timeless_decoding(spe); @@ -1318,7 +1555,7 @@ int arm_spe_process_auxtrace_info(union perf_event *event, spe->auxtrace.evsel_is_auxtrace = arm_spe_evsel_is_auxtrace; session->auxtrace = &spe->auxtrace; - arm_spe_print_info(&auxtrace_info->priv[0]); + arm_spe_print_info(spe, &auxtrace_info->priv[0]); if (dump_trace) return 0; @@ -1346,5 +1583,7 @@ int arm_spe_process_auxtrace_info(union perf_event *event, session->auxtrace = NULL; err_free: free(spe); +err_free_metadata: + arm_spe__free_metadata(metadata, nr_cpu); return err; } diff --git a/tools/perf/util/arm-spe.h b/tools/perf/util/arm-spe.h index 4f4900c18f3e23..390679a4af2fb6 100644 --- a/tools/perf/util/arm-spe.h +++ b/tools/perf/util/arm-spe.h @@ -12,10 +12,46 @@ enum { ARM_SPE_PMU_TYPE, ARM_SPE_PER_CPU_MMAPS, + ARM_SPE_AUXTRACE_V1_PRIV_MAX, +}; + +#define ARM_SPE_AUXTRACE_V1_PRIV_SIZE \ + (ARM_SPE_AUXTRACE_V1_PRIV_MAX * sizeof(u64)) + +enum { + /* + * The old metadata format (defined above) does not include a + * field for version number. Version 1 is reserved and starts + * from version 2. + */ + ARM_SPE_HEADER_VERSION, + /* Number of sizeof(u64) */ + ARM_SPE_HEADER_SIZE, + /* PMU type shared by CPUs */ + ARM_SPE_PMU_TYPE_V2, + /* Number of CPUs */ + ARM_SPE_CPUS_NUM, ARM_SPE_AUXTRACE_PRIV_MAX, }; -#define ARM_SPE_AUXTRACE_PRIV_SIZE (ARM_SPE_AUXTRACE_PRIV_MAX * sizeof(u64)) +enum { + /* Magic number */ + ARM_SPE_MAGIC, + /* CPU logical number in system */ + ARM_SPE_CPU, + /* Number of parameters */ + ARM_SPE_CPU_NR_PARAMS, + /* CPU MIDR */ + ARM_SPE_CPU_MIDR, + /* Associated PMU type */ + ARM_SPE_CPU_PMU_TYPE, + /* Minimal interval */ + ARM_SPE_CAP_MIN_IVAL, + ARM_SPE_CPU_PRIV_MAX, +}; + +#define ARM_SPE_HEADER_CURRENT_VERSION 2 + union perf_event; struct perf_session; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index a1895a4f530be7..dddaf4f3ffeda6 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -75,7 +75,6 @@ enum itrace_period_type { * (not fully accurate, since CYC packets are only emitted * together with other events, such as branches) * @branches: whether to synthesize 'branches' events - * (branch misses only for Arm SPE) * @transactions: whether to synthesize events for transactions * @ptwrites: whether to synthesize events for ptwrites * @pwr_events: whether to synthesize power events @@ -650,7 +649,7 @@ bool auxtrace__evsel_is_auxtrace(struct perf_session *session, #define ITRACE_HELP \ " i[period]: synthesize instructions events\n" \ " y[period]: synthesize cycles events (same period as i)\n" \ -" b: synthesize branches events (branch misses for Arm SPE)\n" \ +" b: synthesize branches events\n" \ " c: synthesize branches events (calls only)\n" \ " r: synthesize branches events (returns only)\n" \ " x: synthesize transactions events\n" \ diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index e87b6789eb9ef3..a4fdf6911ec1c3 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -375,7 +375,7 @@ static int create_idx_hash(struct evsel *evsel, struct perf_bpf_filter_entry *en pfi = zalloc(sizeof(*pfi)); if (pfi == NULL) { pr_err("Cannot save pinned filter index\n"); - goto err; + return -ENOMEM; } pfi->evsel = evsel; diff --git a/tools/perf/util/bpf-prologue.h b/tools/perf/util/bpf-prologue.h deleted file mode 100644 index 66dcf751ef6540..00000000000000 --- a/tools/perf/util/bpf-prologue.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2015, He Kuang - * Copyright (C) 2015, Huawei Inc. - */ -#ifndef __BPF_PROLOGUE_H -#define __BPF_PROLOGUE_H - -struct probe_trace_arg; -struct bpf_insn; - -#define BPF_PROLOGUE_MAX_ARGS 3 -#define BPF_PROLOGUE_START_ARG_REG BPF_REG_3 -#define BPF_PROLOGUE_FETCH_RESULT_REG BPF_REG_2 - -#ifdef HAVE_BPF_PROLOGUE -int bpf__gen_prologue(struct probe_trace_arg *args, int nargs, - struct bpf_insn *new_prog, size_t *new_cnt, - size_t cnt_space); -#else -#include -#include - -static inline int -bpf__gen_prologue(struct probe_trace_arg *args __maybe_unused, - int nargs __maybe_unused, - struct bpf_insn *new_prog __maybe_unused, - size_t *new_cnt, - size_t cnt_space __maybe_unused) -{ - if (!new_cnt) - return -EINVAL; - *new_cnt = 0; - return -ENOTSUP; -} -#endif -#endif /* __BPF_PROLOGUE_H */ diff --git a/tools/perf/util/bpf_counter.c b/tools/perf/util/bpf_counter.c index 7a8af60e0f5158..73fcafbffc6a66 100644 --- a/tools/perf/util/bpf_counter.c +++ b/tools/perf/util/bpf_counter.c @@ -394,6 +394,7 @@ static int bperf_check_target(struct evsel *evsel, } static struct perf_cpu_map *all_cpu_map; +static __u32 filter_entry_cnt; static int bperf_reload_leader_program(struct evsel *evsel, int attr_map_fd, struct perf_event_attr_map_entry *entry) @@ -444,12 +445,32 @@ static int bperf_reload_leader_program(struct evsel *evsel, int attr_map_fd, return err; } +static int bperf_attach_follower_program(struct bperf_follower_bpf *skel, + enum bperf_filter_type filter_type, + bool inherit) +{ + struct bpf_link *link; + int err = 0; + + if ((filter_type == BPERF_FILTER_PID || + filter_type == BPERF_FILTER_TGID) && inherit) + /* attach all follower bpf progs to enable event inheritance */ + err = bperf_follower_bpf__attach(skel); + else { + link = bpf_program__attach(skel->progs.fexit_XXX); + if (IS_ERR(link)) + err = PTR_ERR(link); + } + + return err; +} + static int bperf__load(struct evsel *evsel, struct target *target) { struct perf_event_attr_map_entry entry = {0xffffffff, 0xffffffff}; int attr_map_fd, diff_map_fd = -1, err; enum bperf_filter_type filter_type; - __u32 filter_entry_cnt, i; + __u32 i; if (bperf_check_target(evsel, target, &filter_type, &filter_entry_cnt)) return -1; @@ -529,9 +550,6 @@ static int bperf__load(struct evsel *evsel, struct target *target) /* set up reading map */ bpf_map__set_max_entries(evsel->follower_skel->maps.accum_readings, filter_entry_cnt); - /* set up follower filter based on target */ - bpf_map__set_max_entries(evsel->follower_skel->maps.filter, - filter_entry_cnt); err = bperf_follower_bpf__load(evsel->follower_skel); if (err) { pr_err("Failed to load follower skeleton\n"); @@ -543,6 +561,7 @@ static int bperf__load(struct evsel *evsel, struct target *target) for (i = 0; i < filter_entry_cnt; i++) { int filter_map_fd; __u32 key; + struct bperf_filter_value fval = { i, 0 }; if (filter_type == BPERF_FILTER_PID || filter_type == BPERF_FILTER_TGID) @@ -553,12 +572,14 @@ static int bperf__load(struct evsel *evsel, struct target *target) break; filter_map_fd = bpf_map__fd(evsel->follower_skel->maps.filter); - bpf_map_update_elem(filter_map_fd, &key, &i, BPF_ANY); + bpf_map_update_elem(filter_map_fd, &key, &fval, BPF_ANY); } evsel->follower_skel->bss->type = filter_type; + evsel->follower_skel->bss->inherit = target->inherit; - err = bperf_follower_bpf__attach(evsel->follower_skel); + err = bperf_attach_follower_program(evsel->follower_skel, filter_type, + target->inherit); out: if (err && evsel->bperf_leader_link_fd >= 0) @@ -623,7 +644,7 @@ static int bperf__read(struct evsel *evsel) bperf_sync_counters(evsel); reading_map_fd = bpf_map__fd(skel->maps.accum_readings); - for (i = 0; i < bpf_map__max_entries(skel->maps.accum_readings); i++) { + for (i = 0; i < filter_entry_cnt; i++) { struct perf_cpu entry; __u32 cpu; diff --git a/tools/perf/util/bpf_skel/bperf_follower.bpf.c b/tools/perf/util/bpf_skel/bperf_follower.bpf.c index f193998530d431..0595063139a3d5 100644 --- a/tools/perf/util/bpf_skel/bperf_follower.bpf.c +++ b/tools/perf/util/bpf_skel/bperf_follower.bpf.c @@ -5,6 +5,8 @@ #include #include "bperf_u.h" +#define MAX_ENTRIES 102400 + struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(key_size, sizeof(__u32)); @@ -22,25 +24,29 @@ struct { struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(key_size, sizeof(__u32)); - __uint(value_size, sizeof(__u32)); + __uint(value_size, sizeof(struct bperf_filter_value)); + __uint(max_entries, MAX_ENTRIES); + __uint(map_flags, BPF_F_NO_PREALLOC); } filter SEC(".maps"); enum bperf_filter_type type = 0; int enabled = 0; +int inherit; SEC("fexit/XXX") int BPF_PROG(fexit_XXX) { struct bpf_perf_event_value *diff_val, *accum_val; __u32 filter_key, zero = 0; - __u32 *accum_key; + __u32 accum_key; + struct bperf_filter_value *fval; if (!enabled) return 0; switch (type) { case BPERF_FILTER_GLOBAL: - accum_key = &zero; + accum_key = zero; goto do_add; case BPERF_FILTER_CPU: filter_key = bpf_get_smp_processor_id(); @@ -49,22 +55,34 @@ int BPF_PROG(fexit_XXX) filter_key = bpf_get_current_pid_tgid() & 0xffffffff; break; case BPERF_FILTER_TGID: - filter_key = bpf_get_current_pid_tgid() >> 32; + /* Use pid as the filter_key to exclude new task counts + * when inherit is disabled. Don't worry about the existing + * children in TGID losing their counts, bpf_counter has + * already added them to the filter map via perf_thread_map + * before this bpf prog runs. + */ + filter_key = inherit ? + bpf_get_current_pid_tgid() >> 32 : + bpf_get_current_pid_tgid() & 0xffffffff; break; default: return 0; } - accum_key = bpf_map_lookup_elem(&filter, &filter_key); - if (!accum_key) + fval = bpf_map_lookup_elem(&filter, &filter_key); + if (!fval) return 0; + accum_key = fval->accum_key; + if (fval->exited) + bpf_map_delete_elem(&filter, &filter_key); + do_add: diff_val = bpf_map_lookup_elem(&diff_readings, &zero); if (!diff_val) return 0; - accum_val = bpf_map_lookup_elem(&accum_readings, accum_key); + accum_val = bpf_map_lookup_elem(&accum_readings, &accum_key); if (!accum_val) return 0; @@ -75,4 +93,70 @@ int BPF_PROG(fexit_XXX) return 0; } +/* The program is only used for PID or TGID filter types. */ +SEC("tp_btf/task_newtask") +int BPF_PROG(on_newtask, struct task_struct *task, __u64 clone_flags) +{ + __u32 parent_key, child_key; + struct bperf_filter_value *parent_fval; + struct bperf_filter_value child_fval = { 0 }; + + if (!enabled) + return 0; + + switch (type) { + case BPERF_FILTER_PID: + parent_key = bpf_get_current_pid_tgid() & 0xffffffff; + child_key = task->pid; + break; + case BPERF_FILTER_TGID: + parent_key = bpf_get_current_pid_tgid() >> 32; + child_key = task->tgid; + if (child_key == parent_key) + return 0; + break; + default: + return 0; + } + + /* Check if the current task is one of the target tasks to be counted */ + parent_fval = bpf_map_lookup_elem(&filter, &parent_key); + if (!parent_fval) + return 0; + + /* Start counting for the new task by adding it into filter map, + * inherit the accum key of its parent task so that they can be + * counted together. + */ + child_fval.accum_key = parent_fval->accum_key; + child_fval.exited = 0; + bpf_map_update_elem(&filter, &child_key, &child_fval, BPF_NOEXIST); + + return 0; +} + +/* The program is only used for PID or TGID filter types. */ +SEC("tp_btf/sched_process_exit") +int BPF_PROG(on_exittask, struct task_struct *task) +{ + __u32 pid; + struct bperf_filter_value *fval; + + if (!enabled) + return 0; + + /* Stop counting for this task by removing it from filter map. + * For TGID type, if the pid can be found in the map, it means that + * this pid belongs to the leader task. After the task exits, the + * tgid of its child tasks (if any) will be 1, so the pid can be + * safely removed. + */ + pid = task->pid; + fval = bpf_map_lookup_elem(&filter, &pid); + if (fval) + fval->exited = 1; + + return 0; +} + char LICENSE[] SEC("license") = "Dual BSD/GPL"; diff --git a/tools/perf/util/bpf_skel/bperf_u.h b/tools/perf/util/bpf_skel/bperf_u.h index 1ce0c2c905c112..4a4a753980bef8 100644 --- a/tools/perf/util/bpf_skel/bperf_u.h +++ b/tools/perf/util/bpf_skel/bperf_u.h @@ -11,4 +11,9 @@ enum bperf_filter_type { BPERF_FILTER_TGID, }; +struct bperf_filter_value { + __u32 accum_key; + __u8 exited; +}; + #endif /* __BPERF_STAT_U_H */ diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 8982f68e7230cd..e763e8d99a4367 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -277,7 +277,7 @@ static int write_buildid(const char *name, size_t name_len, struct build_id *bid struct perf_record_header_build_id b; size_t len; - len = sizeof(b) + name_len + 1; + len = name_len + 1; len = PERF_ALIGN(len, sizeof(u64)); memset(&b, 0, sizeof(b)); @@ -286,7 +286,7 @@ static int write_buildid(const char *name, size_t name_len, struct build_id *bid misc |= PERF_RECORD_MISC_BUILD_ID_SIZE; b.pid = pid; b.header.misc = misc; - b.header.size = len; + b.header.size = sizeof(b) + len; err = do_write(fd, &b, sizeof(b)); if (err < 0) diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index bffbdd216a6a57..e51f0a676a2280 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -93,34 +93,6 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) return r; } -/* - * This function splits the buffer by newlines and colors the lines individually. - * - * Returns 0 on success. - */ -int color_fwrite_lines(FILE *fp, const char *color, - size_t count, const char *buf) -{ - if (!*color) - return fwrite(buf, count, 1, fp) != 1; - - while (count) { - char *p = memchr(buf, '\n', count); - - if (p != buf && (fputs(color, fp) < 0 || - fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 || - fputs(PERF_COLOR_RESET, fp) < 0)) - return -1; - if (!p) - return 0; - if (fputc('\n', fp) < 0) - return -1; - count -= p + 1 - buf; - buf = p + 1; - } - return 0; -} - const char *get_percent_color(double percent) { const char *color = PERF_COLOR_NORMAL; diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index 01f7bed21c9b27..9a7248dbe2d74e 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h @@ -2,6 +2,7 @@ #ifndef __PERF_COLOR_H #define __PERF_COLOR_H +#include #include #include @@ -22,6 +23,7 @@ #define MIN_GREEN 0.5 #define MIN_RED 5.0 +#define PERF_COLOR_DELETE_LINE "\033[A\33[2K\r" /* * This variable stores the value of color.ui */ @@ -37,12 +39,11 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) int color_vsnprintf(char *bf, size_t size, const char *color, const char *fmt, va_list args); int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); -int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); -int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); -int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); +int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) __printf(3, 4); +int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...) __printf(4, 5); int value_color_snprintf(char *bf, size_t size, const char *fmt, double value); -int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); -int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...); +int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) __printf(3, 4); +int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...) __printf(3, 4); int percent_color_fprintf(FILE *fp, const char *fmt, double percent); const char *get_percent_color(double percent); diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 7a650de0db83f9..68f9407ca74b92 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -912,6 +912,7 @@ void set_buildid_dir(const char *dir) struct perf_config_scan_data { const char *name; const char *fmt; + const char *value; va_list args; int ret; }; @@ -939,3 +940,24 @@ int perf_config_scan(const char *name, const char *fmt, ...) return d.ret; } + +static int perf_config_get_cb(const char *var, const char *value, void *data) +{ + struct perf_config_scan_data *d = data; + + if (!strcmp(var, d->name)) + d->value = value; + + return 0; +} + +const char *perf_config_get(const char *name) +{ + struct perf_config_scan_data d = { + .name = name, + .value = NULL, + }; + + perf_config(perf_config_get_cb, &d); + return d.value; +} diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index 2e5e808928a55a..9971313d61c1e5 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h @@ -30,6 +30,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *); int perf_default_config(const char *, const char *, void *); int perf_config(config_fn_t fn, void *); int perf_config_scan(const char *name, const char *fmt, ...) __scanf(2, 3); +const char *perf_config_get(const char *name); int perf_config_set(struct perf_config_set *set, config_fn_t fn, void *data); int perf_config_int(int *dest, const char *, const char *); diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c index b78ef0262135ca..b85a8837bddcda 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -685,9 +685,14 @@ cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params, } if (d_params->operation == CS_ETM_OPERATION_DECODE) { + int decode_flags = OCSD_CREATE_FLG_FULL_DECODER; +#ifdef OCSD_OPFLG_N_UNCOND_DIR_BR_CHK + decode_flags |= OCSD_OPFLG_N_UNCOND_DIR_BR_CHK | OCSD_OPFLG_CHK_RANGE_CONTINUE | + ETM4_OPFLG_PKTDEC_AA64_OPCODE_CHK; +#endif if (ocsd_dt_create_decoder(decoder->dcd_tree, decoder->decoder_name, - OCSD_CREATE_FLG_FULL_DECODER, + decode_flags, trace_config, &csid)) return -1; diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 40f047baef8100..0bf9e5c27b599b 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -2490,12 +2490,6 @@ static void cs_etm__clear_all_traceid_queues(struct cs_etm_queue *etmq) /* Ignore return value */ cs_etm__process_traceid_queue(etmq, tidq); - - /* - * Generate an instruction sample with the remaining - * branchstack entries. - */ - cs_etm__flush(etmq, tidq); } } @@ -2638,7 +2632,7 @@ static int cs_etm__process_timestamped_queues(struct cs_etm_auxtrace *etm) while (1) { if (!etm->heap.heap_cnt) - goto out; + break; /* Take the entry at the top of the min heap */ cs_queue_nr = etm->heap.heap_array[0].queue_nr; @@ -2721,6 +2715,23 @@ static int cs_etm__process_timestamped_queues(struct cs_etm_auxtrace *etm) ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, cs_timestamp); } + for (i = 0; i < etm->queues.nr_queues; i++) { + struct int_node *inode; + + etmq = etm->queues.queue_array[i].priv; + if (!etmq) + continue; + + intlist__for_each_entry(inode, etmq->traceid_queues_list) { + int idx = (int)(intptr_t)inode->priv; + + /* Flush any remaining branch stack entries */ + tidq = etmq->traceid_queues[idx]; + ret = cs_etm__end_block(etmq, tidq); + if (ret) + return ret; + } + } out: return ret; } diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 021e9b1d5cc520..f0599c61fab47d 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -36,7 +36,7 @@ #include "util/sample.h" #ifdef HAVE_LIBTRACEEVENT -#include +#include #endif #define pr_N(n, fmt, ...) \ diff --git a/tools/perf/util/data-convert-json.c b/tools/perf/util/data-convert-json.c index 20bfb0884e9eaf..8304cd2d4a9ceb 100644 --- a/tools/perf/util/data-convert-json.c +++ b/tools/perf/util/data-convert-json.c @@ -28,7 +28,7 @@ #include "util/tool.h" #ifdef HAVE_LIBTRACEEVENT -#include +#include #endif struct convert_json { diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index d633d15329fa09..995f6bb05b5f88 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -27,7 +27,7 @@ #include #ifdef HAVE_LIBTRACEEVENT -#include +#include #else #define LIBTRACEEVENT_VERSION 0 #endif diff --git a/tools/perf/util/debuginfo.h b/tools/perf/util/debuginfo.h index ad6422c3f8ca3e..a52d69932815cd 100644 --- a/tools/perf/util/debuginfo.h +++ b/tools/perf/util/debuginfo.h @@ -5,7 +5,7 @@ #include #include -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT #include "dwarf-aux.h" @@ -25,7 +25,7 @@ void debuginfo__delete(struct debuginfo *dbg); int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, bool adjust_offset); -#else /* HAVE_DWARF_SUPPORT */ +#else /* HAVE_LIBDW_SUPPORT */ /* dummy debug information structure */ struct debuginfo { @@ -49,7 +49,7 @@ static inline int debuginfo__get_text_offset(struct debuginfo *dbg __maybe_unuse return -EINVAL; } -#endif /* HAVE_DWARF_SUPPORT */ +#endif /* HAVE_LIBDW_SUPPORT */ #ifdef HAVE_DEBUGINFOD_SUPPORT int get_source_from_debuginfod(const char *raw_path, const char *sbuild_id, diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index f05ba7739c1e91..41a2b08670dc5b 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -18,6 +18,7 @@ #include "disasm.h" #include "disasm_bpf.h" #include "dso.h" +#include "dwarf-regs.h" #include "env.h" #include "evsel.h" #include "map.h" @@ -151,14 +152,14 @@ static struct arch architectures[] = { .memory_ref_char = '(', .imm_char = '$', }, -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT .update_insn_state = update_insn_state_x86, #endif }, { .name = "powerpc", .init = powerpc__annotate_init, -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT .update_insn_state = update_insn_state_powerpc, #endif }, @@ -1423,6 +1424,15 @@ read_symbol(const char *filename, struct map *map, struct symbol *sym, } #endif +#if !defined(HAVE_LIBCAPSTONE_SUPPORT) || !defined(HAVE_LIBLLVM_SUPPORT) +static void symbol__disassembler_missing(const char *disassembler, const char *filename, + struct symbol *sym) +{ + pr_debug("The %s disassembler isn't linked in for %s in %s\n", + disassembler, sym->name, filename); +} +#endif + #ifdef HAVE_LIBCAPSTONE_SUPPORT static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, struct annotate_args *args, u64 addr) @@ -1573,7 +1583,7 @@ static int symbol__disassemble_capstone_powerpc(char *filename, struct symbol *s dl = disasm_line__new(args); if (dl == NULL) - goto err; + break; annotation_line__add(&dl->al, ¬es->src->source); @@ -1603,18 +1613,6 @@ static int symbol__disassemble_capstone_powerpc(char *filename, struct symbol *s err: if (fd >= 0) close(fd); - if (needs_cs_close) { - struct disasm_line *tmp; - - /* - * It probably failed in the middle of the above loop. - * Release any resources it might add. - */ - list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { - list_del(&dl->al.node); - free(dl); - } - } count = -1; goto out; } @@ -1627,12 +1625,12 @@ static int symbol__disassemble_capstone(char *filename, struct symbol *sym, u64 start = map__rip_2objdump(map, sym->start); u64 len; u64 offset; - int i, count; + int i, count, free_count; bool is_64bit = false; bool needs_cs_close = false; u8 *buf = NULL; csh handle; - cs_insn *insn; + cs_insn *insn = NULL; char disasm_buf[512]; struct disasm_line *dl; @@ -1664,7 +1662,7 @@ static int symbol__disassemble_capstone(char *filename, struct symbol *sym, needs_cs_close = true; - count = cs_disasm(handle, buf, len, start, len, &insn); + free_count = count = cs_disasm(handle, buf, len, start, len, &insn); for (i = 0, offset = 0; i < count; i++) { int printed; @@ -1702,8 +1700,11 @@ static int symbol__disassemble_capstone(char *filename, struct symbol *sym, } out: - if (needs_cs_close) + if (needs_cs_close) { cs_close(&handle); + if (free_count > 0) + cs_free(insn, free_count); + } free(buf); return count < 0 ? count : 0; @@ -1717,13 +1718,27 @@ static int symbol__disassemble_capstone(char *filename, struct symbol *sym, */ list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { list_del(&dl->al.node); - free(dl); + disasm_line__free(dl); } } count = -1; goto out; } -#endif +#else // HAVE_LIBCAPSTONE_SUPPORT +static int symbol__disassemble_capstone(char *filename, struct symbol *sym, + struct annotate_args *args __maybe_unused) +{ + symbol__disassembler_missing("capstone", filename, sym); + return -1; +} + +static int symbol__disassemble_capstone_powerpc(char *filename, struct symbol *sym, + struct annotate_args *args __maybe_unused) +{ + symbol__disassembler_missing("capstone powerpc", filename, sym); + return -1; +} +#endif // HAVE_LIBCAPSTONE_SUPPORT static int symbol__disassemble_raw(char *filename, struct symbol *sym, struct annotate_args *args) @@ -1782,7 +1797,7 @@ static int symbol__disassemble_raw(char *filename, struct symbol *sym, sprintf(args->line, "%x", line[i]); dl = disasm_line__new(args); if (dl == NULL) - goto err; + break; annotation_line__add(&dl->al, ¬es->src->source); offset += 4; @@ -1991,7 +2006,14 @@ static int symbol__disassemble_llvm(char *filename, struct symbol *sym, free(line_storage); return ret; } -#endif +#else // HAVE_LIBLLVM_SUPPORT +static int symbol__disassemble_llvm(char *filename, struct symbol *sym, + struct annotate_args *args __maybe_unused) +{ + symbol__disassembler_missing("LLVM", filename, sym); + return -1; +} +#endif // HAVE_LIBLLVM_SUPPORT /* * Possibly create a new version of line with tabs expanded. Returns the @@ -2053,17 +2075,14 @@ static char *expand_tabs(char *line, char **storage, size_t *storage_len) return new_line; } -int symbol__disassemble(struct symbol *sym, struct annotate_args *args) +static int symbol__disassemble_objdump(const char *filename, struct symbol *sym, + struct annotate_args *args) { struct annotation_options *opts = &annotate_opts; struct map *map = args->ms.map; struct dso *dso = map__dso(map); char *command; FILE *file; - char symfs_filename[PATH_MAX]; - struct kcore_extract kce; - bool delete_extract = false; - bool decomp = false; int lineno = 0; char *fileloc = NULL; int nline; @@ -2078,77 +2097,7 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) NULL, }; struct child_process objdump_process; - int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); - - if (err) - return err; - - pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, - symfs_filename, sym->name, map__unmap_ip(map, sym->start), - map__unmap_ip(map, sym->end)); - - pr_debug("annotating [%p] %30s : [%p] %30s\n", - dso, dso__long_name(dso), sym, sym->name); - - if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) { - return symbol__disassemble_bpf(sym, args); - } else if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE) { - return symbol__disassemble_bpf_image(sym, args); - } else if (dso__binary_type(dso) == DSO_BINARY_TYPE__NOT_FOUND) { - return -1; - } else if (dso__is_kcore(dso)) { - kce.kcore_filename = symfs_filename; - kce.addr = map__rip_2objdump(map, sym->start); - kce.offs = sym->start; - kce.len = sym->end - sym->start; - if (!kcore_extract__create(&kce)) { - delete_extract = true; - strlcpy(symfs_filename, kce.extract_filename, - sizeof(symfs_filename)); - } - } else if (dso__needs_decompress(dso)) { - char tmp[KMOD_DECOMP_LEN]; - - if (dso__decompress_kmodule_path(dso, symfs_filename, - tmp, sizeof(tmp)) < 0) - return -1; - - decomp = true; - strcpy(symfs_filename, tmp); - } - - /* - * For powerpc data type profiling, use the dso__data_read_offset - * to read raw instruction directly and interpret the binary code - * to understand instructions and register fields. For sort keys as - * type and typeoff, disassemble to mnemonic notation is - * not required in case of powerpc. - */ - if (arch__is(args->arch, "powerpc")) { - extern const char *sort_order; - - if (sort_order && !strstr(sort_order, "sym")) { - err = symbol__disassemble_raw(symfs_filename, sym, args); - if (err == 0) - goto out_remove_tmp; -#ifdef HAVE_LIBCAPSTONE_SUPPORT - err = symbol__disassemble_capstone_powerpc(symfs_filename, sym, args); - if (err == 0) - goto out_remove_tmp; -#endif - } - } - -#ifdef HAVE_LIBLLVM_SUPPORT - err = symbol__disassemble_llvm(symfs_filename, sym, args); - if (err == 0) - goto out_remove_tmp; -#endif -#ifdef HAVE_LIBCAPSTONE_SUPPORT - err = symbol__disassemble_capstone(symfs_filename, sym, args); - if (err == 0) - goto out_remove_tmp; -#endif + int err; err = asprintf(&command, "%s %s%s --start-address=0x%016" PRIx64 @@ -2171,13 +2120,13 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) if (err < 0) { pr_err("Failure allocating memory for the command to run\n"); - goto out_remove_tmp; + return err; } pr_debug("Executing: %s\n", command); objdump_argv[2] = command; - objdump_argv[4] = symfs_filename; + objdump_argv[4] = filename; /* Create a pipe to read from for stdout */ memset(&objdump_process, 0, sizeof(objdump_process)); @@ -2215,8 +2164,8 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) break; /* Skip lines containing "filename:" */ - match = strstr(line, symfs_filename); - if (match && match[strlen(symfs_filename)] == ':') + match = strstr(line, filename); + if (match && match[strlen(filename)] == ':') continue; expanded_line = strim(line); @@ -2261,7 +2210,150 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) out_free_command: free(command); + return err; +} + +static int annotation_options__init_disassemblers(struct annotation_options *options) +{ + char *disassembler; + + if (options->disassemblers_str == NULL) { + const char *default_disassemblers_str = +#ifdef HAVE_LIBLLVM_SUPPORT + "llvm," +#endif +#ifdef HAVE_LIBCAPSTONE_SUPPORT + "capstone," +#endif + "objdump"; + + options->disassemblers_str = strdup(default_disassemblers_str); + if (!options->disassemblers_str) + goto out_enomem; + } + + disassembler = strdup(options->disassemblers_str); + if (disassembler == NULL) + goto out_enomem; + + while (1) { + char *comma = strchr(disassembler, ','); + + if (comma != NULL) + *comma = '\0'; + + options->disassemblers[options->nr_disassemblers++] = strim(disassembler); + + if (comma == NULL) + break; + + disassembler = comma + 1; + + if (options->nr_disassemblers >= MAX_DISASSEMBLERS) { + pr_debug("annotate.disassemblers can have at most %d entries, ignoring \"%s\"\n", + MAX_DISASSEMBLERS, disassembler); + break; + } + } + + return 0; + +out_enomem: + pr_err("Not enough memory for annotate.disassemblers\n"); + return -1; +} + +int symbol__disassemble(struct symbol *sym, struct annotate_args *args) +{ + struct annotation_options *options = args->options; + struct map *map = args->ms.map; + struct dso *dso = map__dso(map); + char symfs_filename[PATH_MAX]; + bool delete_extract = false; + struct kcore_extract kce; + const char *disassembler; + bool decomp = false; + int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); + + if (err) + return err; + + pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, + symfs_filename, sym->name, map__unmap_ip(map, sym->start), + map__unmap_ip(map, sym->end)); + + pr_debug("annotating [%p] %30s : [%p] %30s\n", dso, dso__long_name(dso), sym, sym->name); + if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) { + return symbol__disassemble_bpf(sym, args); + } else if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE) { + return symbol__disassemble_bpf_image(sym, args); + } else if (dso__binary_type(dso) == DSO_BINARY_TYPE__NOT_FOUND) { + return -1; + } else if (dso__is_kcore(dso)) { + kce.addr = map__rip_2objdump(map, sym->start); + kce.kcore_filename = symfs_filename; + kce.len = sym->end - sym->start; + kce.offs = sym->start; + + if (!kcore_extract__create(&kce)) { + delete_extract = true; + strlcpy(symfs_filename, kce.extract_filename, sizeof(symfs_filename)); + } + } else if (dso__needs_decompress(dso)) { + char tmp[KMOD_DECOMP_LEN]; + + if (dso__decompress_kmodule_path(dso, symfs_filename, tmp, sizeof(tmp)) < 0) + return -1; + + decomp = true; + strcpy(symfs_filename, tmp); + } + + /* + * For powerpc data type profiling, use the dso__data_read_offset to + * read raw instruction directly and interpret the binary code to + * understand instructions and register fields. For sort keys as type + * and typeoff, disassemble to mnemonic notation is not required in + * case of powerpc. + */ + if (arch__is(args->arch, "powerpc")) { + extern const char *sort_order; + + if (sort_order && !strstr(sort_order, "sym")) { + err = symbol__disassemble_raw(symfs_filename, sym, args); + if (err == 0) + goto out_remove_tmp; + + err = symbol__disassemble_capstone_powerpc(symfs_filename, sym, args); + if (err == 0) + goto out_remove_tmp; + } + } + + err = annotation_options__init_disassemblers(options); + if (err) + goto out_remove_tmp; + + err = -1; + + for (int i = 0; i < options->nr_disassemblers && err != 0; ++i) { + disassembler = options->disassemblers[i]; + + if (!strcmp(disassembler, "llvm")) + err = symbol__disassemble_llvm(symfs_filename, sym, args); + else if (!strcmp(disassembler, "capstone")) + err = symbol__disassemble_capstone(symfs_filename, sym, args); + else if (!strcmp(disassembler, "objdump")) + err = symbol__disassemble_objdump(symfs_filename, sym, args); + else + pr_debug("Unknown disassembler %s, skipping...\n", disassembler); + } + + if (err == 0) { + pr_debug("Disassembled with %s\nannotate.disassemblers=%s\n", + disassembler, options->disassemblers_str); + } out_remove_tmp: if (decomp) unlink(symfs_filename); diff --git a/tools/perf/util/disasm.h b/tools/perf/util/disasm.h index f56beedeb9dadb..c135db2416b5cd 100644 --- a/tools/perf/util/disasm.h +++ b/tools/perf/util/disasm.h @@ -4,7 +4,7 @@ #include "map_symbol.h" -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT #include "dwarf-aux.h" #endif @@ -39,11 +39,15 @@ struct arch { char memory_ref_char; char imm_char; } objdump; -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT void (*update_insn_state)(struct type_state *state, struct data_loc_info *dloc, Dwarf_Die *cu_die, struct disasm_line *dl); #endif + /** @e_machine: ELF machine associated with arch. */ + unsigned int e_machine; + /** @e_flags: Optional ELF flags associated with arch. */ + unsigned int e_flags; }; struct ins { diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 92eb9c8dc3e520..559c953ca17271 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -1182,7 +1182,6 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); } -#if defined(HAVE_DWARF_GETLOCATIONS_SUPPORT) || defined(HAVE_DWARF_CFI_SUPPORT) static int reg_from_dwarf_op(Dwarf_Op *op) { switch (op->atom) { @@ -1245,9 +1244,7 @@ static bool check_allowed_ops(Dwarf_Op *ops, size_t nops) } return true; } -#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT || HAVE_DWARF_CFI_SUPPORT */ -#ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT /** * die_get_var_innermost_scope - Get innermost scope range of given variable DIE * @sp_die: a subprogram DIE @@ -1697,9 +1694,7 @@ void die_collect_global_vars(Dwarf_Die *cu_die, struct die_var_type **var_types) die_find_child(cu_die, __die_collect_global_vars_cb, (void *)var_types, &die_mem); } -#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ -#ifdef HAVE_DWARF_CFI_SUPPORT /** * die_get_cfa - Get frame base information * @dwarf: a Dwarf info @@ -1732,7 +1727,6 @@ int die_get_cfa(Dwarf *dwarf, u64 pc, int *preg, int *poffset) } return -1; } -#endif /* HAVE_DWARF_CFI_SUPPORT */ /* * die_has_loclist - Check if DW_AT_location of @vr_die is a location list diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index bd750581256934..892c8c5c23fc06 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -9,7 +9,6 @@ #include #include #include -#include struct strbuf; @@ -157,8 +156,6 @@ Dwarf_Die *die_get_member_type(Dwarf_Die *type_die, int offset, Dwarf_Die *die_m /* Return type info where the pointer and offset point to */ Dwarf_Die *die_deref_ptr_type(Dwarf_Die *ptr_die, int offset, Dwarf_Die *die_mem); -#ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT - /* Get byte offset range of given variable DIE */ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); @@ -177,58 +174,7 @@ void die_collect_vars(Dwarf_Die *sc_die, struct die_var_type **var_types); /* Save all global variables in this CU */ void die_collect_global_vars(Dwarf_Die *cu_die, struct die_var_type **var_types); -#else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ - -static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, - Dwarf_Die *vr_die __maybe_unused, - struct strbuf *buf __maybe_unused) -{ - return -ENOTSUP; -} - -static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unused, - Dwarf_Addr pc __maybe_unused, - int reg __maybe_unused, - int *poffset __maybe_unused, - bool is_fbreg __maybe_unused, - Dwarf_Die *die_mem __maybe_unused) -{ - return NULL; -} - -static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unused, - Dwarf_Addr addr __maybe_unused, - Dwarf_Die *die_mem __maybe_unused, - int *offset __maybe_unused) -{ - return NULL; -} - -static inline void die_collect_vars(Dwarf_Die *sc_die __maybe_unused, - struct die_var_type **var_types __maybe_unused) -{ -} - -static inline void die_collect_global_vars(Dwarf_Die *cu_die __maybe_unused, - struct die_var_type **var_types __maybe_unused) -{ -} - -#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ - -#ifdef HAVE_DWARF_CFI_SUPPORT - /* Get the frame base information from CFA */ int die_get_cfa(Dwarf *dwarf, u64 pc, int *preg, int *poffset); -#else /* HAVE_DWARF_CFI_SUPPORT */ - -static inline int die_get_cfa(Dwarf *dwarf __maybe_unused, u64 pc __maybe_unused, - int *preg __maybe_unused, int *poffset __maybe_unused) -{ - return -1; -} - -#endif /* HAVE_DWARF_CFI_SUPPORT */ - #endif /* _DWARF_AUX_H */ diff --git a/tools/perf/util/dwarf-regs-csky.c b/tools/perf/util/dwarf-regs-csky.c new file mode 100644 index 00000000000000..d38ef1f07f3e39 --- /dev/null +++ b/tools/perf/util/dwarf-regs-csky.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. +// Mapping of DWARF debug register numbers into register names. + +#include +#include + +#define CSKY_ABIV2_MAX_REGS 73 +const char *csky_dwarf_regs_table_abiv2[CSKY_ABIV2_MAX_REGS] = { + /* r0 ~ r8 */ + "%a0", "%a1", "%a2", "%a3", "%regs0", "%regs1", "%regs2", "%regs3", + /* r9 ~ r15 */ + "%regs4", "%regs5", "%regs6", "%regs7", "%regs8", "%regs9", "%sp", + "%lr", + /* r16 ~ r23 */ + "%exregs0", "%exregs1", "%exregs2", "%exregs3", "%exregs4", + "%exregs5", "%exregs6", "%exregs7", + /* r24 ~ r31 */ + "%exregs8", "%exregs9", "%exregs10", "%exregs11", "%exregs12", + "%exregs13", "%exregs14", "%tls", + "%pc", NULL, NULL, NULL, "%hi", "%lo", NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "%epc", +}; + +#define CSKY_ABIV1_MAX_REGS 57 +const char *csky_dwarf_regs_table_abiv1[CSKY_ABIV1_MAX_REGS] = { + /* r0 ~ r8 */ + "%sp", "%regs9", "%a0", "%a1", "%a2", "%a3", "%regs0", "%regs1", + /* r9 ~ r15 */ + "%regs2", "%regs3", "%regs4", "%regs5", "%regs6", "%regs7", "%regs8", + "%lr", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "%epc", +}; + +const char *get_csky_regstr(unsigned int n, unsigned int flags) +{ + if (flags & EF_CSKY_ABIV2) + return (n < CSKY_ABIV2_MAX_REGS) ? csky_dwarf_regs_table_abiv2[n] : NULL; + + return (n < CSKY_ABIV1_MAX_REGS) ? csky_dwarf_regs_table_abiv1[n] : NULL; +} diff --git a/tools/perf/util/dwarf-regs-powerpc.c b/tools/perf/util/dwarf-regs-powerpc.c new file mode 100644 index 00000000000000..caf77a234c785a --- /dev/null +++ b/tools/perf/util/dwarf-regs-powerpc.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Mapping of DWARF debug register numbers into register names. + * + * Copyright (C) 2010 Ian Munsie, IBM Corporation. + */ + +#include + +#define PPC_OP(op) (((op) >> 26) & 0x3F) +#define PPC_RA(a) (((a) >> 16) & 0x1f) +#define PPC_RT(t) (((t) >> 21) & 0x1f) +#define PPC_RB(b) (((b) >> 11) & 0x1f) +#define PPC_D(D) ((D) & 0xfffe) +#define PPC_DS(DS) ((DS) & 0xfffc) +#define OP_LD 58 +#define OP_STD 62 + +static int get_source_reg(u32 raw_insn) +{ + return PPC_RA(raw_insn); +} + +static int get_target_reg(u32 raw_insn) +{ + return PPC_RT(raw_insn); +} + +static int get_offset_opcode(u32 raw_insn) +{ + int opcode = PPC_OP(raw_insn); + + /* DS- form */ + if ((opcode == OP_LD) || (opcode == OP_STD)) + return PPC_DS(raw_insn); + else + return PPC_D(raw_insn); +} + +/* + * Fills the required fields for op_loc depending on if it + * is a source or target. + * D form: ins RT,D(RA) -> src_reg1 = RA, offset = D, dst_reg1 = RT + * DS form: ins RT,DS(RA) -> src_reg1 = RA, offset = DS, dst_reg1 = RT + * X form: ins RT,RA,RB -> src_reg1 = RA, src_reg2 = RB, dst_reg1 = RT + */ +void get_powerpc_regs(u32 raw_insn, int is_source, + struct annotated_op_loc *op_loc) +{ + if (is_source) + op_loc->reg1 = get_source_reg(raw_insn); + else + op_loc->reg1 = get_target_reg(raw_insn); + + if (op_loc->multi_regs) + op_loc->reg2 = PPC_RB(raw_insn); + + /* TODO: Implement offset handling for X Form */ + if ((op_loc->mem_ref) && (PPC_OP(raw_insn) != 31)) + op_loc->offset = get_offset_opcode(raw_insn); +} diff --git a/tools/perf/util/dwarf-regs-x86.c b/tools/perf/util/dwarf-regs-x86.c new file mode 100644 index 00000000000000..7a55c65e8da6eb --- /dev/null +++ b/tools/perf/util/dwarf-regs-x86.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * dwarf-regs.c : Mapping of DWARF debug register numbers into register names. + * Extracted from probe-finder.c + * + * Written by Masami Hiramatsu + */ + +#include /* for EINVAL */ +#include /* for strcmp */ +#include /* for ARRAY_SIZE */ +#include + +struct dwarf_regs_idx { + const char *name; + int idx; +}; + +static const struct dwarf_regs_idx x86_regidx_table[] = { + { "rax", 0 }, { "eax", 0 }, { "ax", 0 }, { "al", 0 }, + { "rdx", 1 }, { "edx", 1 }, { "dx", 1 }, { "dl", 1 }, + { "rcx", 2 }, { "ecx", 2 }, { "cx", 2 }, { "cl", 2 }, + { "rbx", 3 }, { "edx", 3 }, { "bx", 3 }, { "bl", 3 }, + { "rsi", 4 }, { "esi", 4 }, { "si", 4 }, { "sil", 4 }, + { "rdi", 5 }, { "edi", 5 }, { "di", 5 }, { "dil", 5 }, + { "rbp", 6 }, { "ebp", 6 }, { "bp", 6 }, { "bpl", 6 }, + { "rsp", 7 }, { "esp", 7 }, { "sp", 7 }, { "spl", 7 }, + { "r8", 8 }, { "r8d", 8 }, { "r8w", 8 }, { "r8b", 8 }, + { "r9", 9 }, { "r9d", 9 }, { "r9w", 9 }, { "r9b", 9 }, + { "r10", 10 }, { "r10d", 10 }, { "r10w", 10 }, { "r10b", 10 }, + { "r11", 11 }, { "r11d", 11 }, { "r11w", 11 }, { "r11b", 11 }, + { "r12", 12 }, { "r12d", 12 }, { "r12w", 12 }, { "r12b", 12 }, + { "r13", 13 }, { "r13d", 13 }, { "r13w", 13 }, { "r13b", 13 }, + { "r14", 14 }, { "r14d", 14 }, { "r14w", 14 }, { "r14b", 14 }, + { "r15", 15 }, { "r15d", 15 }, { "r15w", 15 }, { "r15b", 15 }, + { "rip", DWARF_REG_PC }, +}; + +int get_x86_regnum(const char *name) +{ + unsigned int i; + + if (*name != '%') + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(x86_regidx_table); i++) + if (!strcmp(x86_regidx_table[i].name, name + 1)) + return x86_regidx_table[i].idx; + return -ENOENT; +} diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c index 5b7f86c0063f2b..28a1cfdf26d400 100644 --- a/tools/perf/util/dwarf-regs.c +++ b/tools/perf/util/dwarf-regs.c @@ -13,14 +13,6 @@ #include #include -#ifndef EM_AARCH64 -#define EM_AARCH64 183 /* ARM 64 bit */ -#endif - -#ifndef EM_LOONGARCH -#define EM_LOONGARCH 258 /* LoongArch */ -#endif - /* Define const char * {arch}_register_tbl[] */ #define DEFINE_DWARF_REGSTR_TABLE #include "../arch/x86/include/dwarf-regs-table.h" @@ -28,6 +20,7 @@ #include "../arch/arm64/include/dwarf-regs-table.h" #include "../arch/sh/include/dwarf-regs-table.h" #include "../arch/powerpc/include/dwarf-regs-table.h" +#include "../arch/riscv/include/dwarf-regs-table.h" #include "../arch/s390/include/dwarf-regs-table.h" #include "../arch/sparc/include/dwarf-regs-table.h" #include "../arch/xtensa/include/dwarf-regs-table.h" @@ -37,11 +30,13 @@ #define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL) /* Return architecture dependent register string (for kprobe-tracer) */ -const char *get_dwarf_regstr(unsigned int n, unsigned int machine) +const char *get_dwarf_regstr(unsigned int n, unsigned int machine, unsigned int flags) { + if (machine == EM_NONE) { + /* Generic arch - use host arch */ + machine = EM_HOST; + } switch (machine) { - case EM_NONE: /* Generic arch - use host arch */ - return get_arch_regstr(n); case EM_386: return __get_dwarf_regstr(x86_32_regstr_tbl, n); case EM_X86_64: @@ -50,6 +45,8 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine) return __get_dwarf_regstr(arm_regstr_tbl, n); case EM_AARCH64: return __get_dwarf_regstr(aarch64_regstr_tbl, n); + case EM_CSKY: + return get_csky_regstr(n, flags); case EM_SH: return __get_dwarf_regstr(sh_regstr_tbl, n); case EM_S390: @@ -57,6 +54,8 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine) case EM_PPC: case EM_PPC64: return __get_dwarf_regstr(powerpc_regstr_tbl, n); + case EM_RISCV: + return __get_dwarf_regstr(riscv_regstr_tbl, n); case EM_SPARC: case EM_SPARCV9: return __get_dwarf_regstr(sparc_regstr_tbl, n); @@ -72,13 +71,15 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine) return NULL; } +#if EM_HOST != EM_X86_64 && EM_HOST != EM_386 __weak int get_arch_regnum(const char *name __maybe_unused) { return -ENOTSUP; } +#endif /* Return DWARF register number from architecture register name */ -int get_dwarf_regnum(const char *name, unsigned int machine) +int get_dwarf_regnum(const char *name, unsigned int machine, unsigned int flags __maybe_unused) { char *regname = strdup(name); int reg = -1; @@ -92,10 +93,21 @@ int get_dwarf_regnum(const char *name, unsigned int machine) if (p) *p = '\0'; + if (machine == EM_NONE) { + /* Generic arch - use host arch */ + machine = EM_HOST; + } switch (machine) { - case EM_NONE: /* Generic arch - use host arch */ +#if EM_HOST != EM_X86_64 && EM_HOST != EM_386 + case EM_HOST: reg = get_arch_regnum(regname); break; +#endif + case EM_X86_64: + fallthrough; + case EM_386: + reg = get_x86_regnum(regname); + break; default: pr_err("ELF MACHINE %x is not supported.\n", machine); } diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 1edbccfc3281d2..e2843ca2edd92e 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -5,12 +5,14 @@ #include "util/header.h" #include "linux/compiler.h" #include +#include #include #include "cgroup.h" #include #include #include #include +#include "pmu.h" #include "pmus.h" #include "strbuf.h" #include "trace/beauty/beauty.h" @@ -372,7 +374,8 @@ int perf_env__read_pmu_mappings(struct perf_env *env) int perf_env__read_cpuid(struct perf_env *env) { char cpuid[128]; - int err = get_cpuid(cpuid, sizeof(cpuid)); + struct perf_cpu cpu = {-1}; + int err = get_cpuid(cpuid, sizeof(cpuid), cpu); if (err) return err; @@ -639,3 +642,25 @@ void perf_env__find_br_cntr_info(struct perf_env *env, env->pmu_caps->br_cntr_width; } } + +bool perf_env__is_x86_amd_cpu(struct perf_env *env) +{ + static int is_amd; /* 0: Uninitialized, 1: Yes, -1: No */ + + if (is_amd == 0) + is_amd = env->cpuid && strstarts(env->cpuid, "AuthenticAMD") ? 1 : -1; + + return is_amd >= 1 ? true : false; +} + +bool x86__is_amd_cpu(void) +{ + struct perf_env env = { .total_mem = 0, }; + bool is_amd; + + perf_env__cpuid(&env); + is_amd = perf_env__is_x86_amd_cpu(&env); + perf_env__exit(&env); + + return is_amd; +} diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 51b36c36019be6..ae604c4edbb7eb 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -195,4 +195,8 @@ bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name); void perf_env__find_br_cntr_info(struct perf_env *env, unsigned int *nr, unsigned int *width); + +bool x86__is_amd_cpu(void); +bool perf_env__is_x86_amd_cpu(struct perf_env *env); + #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index f8742e6230a5ab..2744c54f404e7b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -66,6 +66,7 @@ enum { PERF_IP_FLAG_VMEXIT = 1ULL << 12, PERF_IP_FLAG_INTR_DISABLE = 1ULL << 13, PERF_IP_FLAG_INTR_TOGGLE = 1ULL << 14, + PERF_IP_FLAG_BRANCH_MISS = 1ULL << 15, }; #define PERF_IP_FLAG_CHARS "bcrosyiABExghDt" diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index f14b7e6ff1dcc2..f0dd174e2debdb 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -319,62 +320,6 @@ struct evsel *evlist__add_sched_switch(struct evlist *evlist, bool system_wide) } #endif -int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs) -{ - struct evsel *evsel, *n; - LIST_HEAD(head); - size_t i; - - for (i = 0; i < nr_attrs; i++) { - evsel = evsel__new_idx(attrs + i, evlist->core.nr_entries + i); - if (evsel == NULL) - goto out_delete_partial_list; - list_add_tail(&evsel->core.node, &head); - } - - evlist__splice_list_tail(evlist, &head); - - return 0; - -out_delete_partial_list: - __evlist__for_each_entry_safe(&head, n, evsel) - evsel__delete(evsel); - return -1; -} - -int __evlist__add_default_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs) -{ - size_t i; - - for (i = 0; i < nr_attrs; i++) - event_attr_init(attrs + i); - - return evlist__add_attrs(evlist, attrs, nr_attrs); -} - -__weak int arch_evlist__add_default_attrs(struct evlist *evlist, - struct perf_event_attr *attrs, - size_t nr_attrs) -{ - if (!nr_attrs) - return 0; - - return __evlist__add_default_attrs(evlist, attrs, nr_attrs); -} - -struct evsel *evlist__find_tracepoint_by_id(struct evlist *evlist, int id) -{ - struct evsel *evsel; - - evlist__for_each_entry(evlist, evsel) { - if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT && - (int)evsel->core.attr.config == id) - return evsel; - } - - return NULL; -} - struct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name) { struct evsel *evsel; @@ -1199,11 +1144,6 @@ int evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids) return ret; } -int evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid) -{ - return evlist__set_tp_filter_pids(evlist, 1, &pid); -} - int evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids) { char *filter = asprintf__tp_filter_pids(npids, pids); @@ -1484,6 +1424,8 @@ int evlist__prepare_workload(struct evlist *evlist, struct target *target, const int child_ready_pipe[2], go_pipe[2]; char bf; + evlist->workload.cork_fd = -1; + if (pipe(child_ready_pipe) < 0) { perror("failed to create 'ready' pipe"); return -1; @@ -1536,7 +1478,7 @@ int evlist__prepare_workload(struct evlist *evlist, struct target *target, const * For cancelling the workload without actually running it, * the parent will just close workload.cork_fd, without writing * anything, i.e. read will return zero and we just exit() - * here. + * here (See evlist__cancel_workload()). */ if (ret != 1) { if (ret == -1) @@ -1600,7 +1542,7 @@ int evlist__prepare_workload(struct evlist *evlist, struct target *target, const int evlist__start_workload(struct evlist *evlist) { - if (evlist->workload.cork_fd > 0) { + if (evlist->workload.cork_fd >= 0) { char bf = 0; int ret; /* @@ -1611,12 +1553,24 @@ int evlist__start_workload(struct evlist *evlist) perror("unable to write to pipe"); close(evlist->workload.cork_fd); + evlist->workload.cork_fd = -1; return ret; } return 0; } +void evlist__cancel_workload(struct evlist *evlist) +{ + int status; + + if (evlist->workload.cork_fd >= 0) { + close(evlist->workload.cork_fd); + evlist->workload.cork_fd = -1; + waitpid(evlist->workload.pid, &status, WNOHANG); + } +} + int evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) { struct evsel *evsel = evlist__event2evsel(evlist, event); @@ -2619,7 +2573,8 @@ void evlist__uniquify_name(struct evlist *evlist) else attributes = empty_attributes; - if (asprintf(&new_name, "%s/%s/%s", pos->pmu_name, pos->name, attributes + 1)) { + if (asprintf(&new_name, "%s/%s/%s", pos->pmu ? pos->pmu->name : "", + pos->name, attributes + 1)) { free(pos->name); pos->name = new_name; } else { diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index bcc1c6984bb58a..adddb1db1ad2b2 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -102,18 +102,6 @@ void evlist__delete(struct evlist *evlist); void evlist__add(struct evlist *evlist, struct evsel *entry); void evlist__remove(struct evlist *evlist, struct evsel *evsel); -int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs); - -int __evlist__add_default_attrs(struct evlist *evlist, - struct perf_event_attr *attrs, size_t nr_attrs); - -int arch_evlist__add_default_attrs(struct evlist *evlist, - struct perf_event_attr *attrs, - size_t nr_attrs); - -#define evlist__add_default_attrs(evlist, array) \ - arch_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) - int arch_evlist__cmp(const struct evsel *lhs, const struct evsel *rhs); int evlist__add_dummy(struct evlist *evlist); @@ -144,7 +132,6 @@ int __evlist__set_tracepoints_handlers(struct evlist *evlist, __evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) int evlist__set_tp_filter(struct evlist *evlist, const char *filter); -int evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid); int evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids); int evlist__append_tp_filter(struct evlist *evlist, const char *filter); @@ -152,7 +139,6 @@ int evlist__append_tp_filter(struct evlist *evlist, const char *filter); int evlist__append_tp_filter_pid(struct evlist *evlist, pid_t pid); int evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids); -struct evsel *evlist__find_tracepoint_by_id(struct evlist *evlist, int id); struct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name); int evlist__add_pollfd(struct evlist *evlist, int fd); @@ -186,6 +172,7 @@ int evlist__prepare_workload(struct evlist *evlist, struct target *target, const char *argv[], bool pipe_output, void (*exec_error)(int signo, siginfo_t *info, void *ucontext)); int evlist__start_workload(struct evlist *evlist); +void evlist__cancel_workload(struct evlist *evlist); struct option; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index dbf9c8cee3c565..d22c5df1701ecc 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -5,12 +5,16 @@ * Parts came from builtin-{top,stat,record}.c, see those files for further * copyright notes. */ +/* + * Powerpc needs __SANE_USERSPACE_TYPES__ before to select + * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu. + */ +#define __SANE_USERSPACE_TYPES__ #include #include #include #include -#include #include #include #include @@ -20,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +56,8 @@ #include "off_cpu.h" #include "pmu.h" #include "pmus.h" +#include "hwmon_pmu.h" +#include "tool_pmu.h" #include "rlimit.h" #include "../perf-sys.h" #include "util/parse-branch-options.h" @@ -64,46 +71,135 @@ #include #ifdef HAVE_LIBTRACEEVENT -#include +#include #endif struct perf_missing_features perf_missing_features; static clockid_t clockid; -static const char *const perf_tool_event__tool_names[PERF_TOOL_MAX] = { - NULL, - "duration_time", - "user_time", - "system_time", -}; - -const char *perf_tool_event__to_str(enum perf_tool_event ev) +static int evsel__no_extra_init(struct evsel *evsel __maybe_unused) { - if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX) - return perf_tool_event__tool_names[ev]; - - return NULL; + return 0; } -enum perf_tool_event perf_tool_event__from_str(const char *str) +static bool test_attr__enabled(void) { - int i; + static bool test_attr__enabled; + static bool test_attr__enabled_tested; + + if (!test_attr__enabled_tested) { + char *dir = getenv("PERF_TEST_ATTR"); - perf_tool_event__for_each_event(i) { - if (!strcmp(str, perf_tool_event__tool_names[i])) - return i; + test_attr__enabled = (dir != NULL); + test_attr__enabled_tested = true; } - return PERF_TOOL_NONE; + return test_attr__enabled; } +#define __WRITE_ASS(str, fmt, data) \ +do { \ + if (fprintf(file, #str "=%"fmt "\n", data) < 0) { \ + perror("test attr - failed to write event file"); \ + fclose(file); \ + return -1; \ + } \ +} while (0) -static int evsel__no_extra_init(struct evsel *evsel __maybe_unused) +#define WRITE_ASS(field, fmt) __WRITE_ASS(field, fmt, attr->field) + +static int store_event(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu, + int fd, int group_fd, unsigned long flags) { + FILE *file; + char path[PATH_MAX]; + char *dir = getenv("PERF_TEST_ATTR"); + + snprintf(path, PATH_MAX, "%s/event-%d-%llu-%d", dir, + attr->type, attr->config, fd); + + file = fopen(path, "w+"); + if (!file) { + perror("test attr - failed to open event file"); + return -1; + } + + if (fprintf(file, "[event-%d-%llu-%d]\n", + attr->type, attr->config, fd) < 0) { + perror("test attr - failed to write event file"); + fclose(file); + return -1; + } + + /* syscall arguments */ + __WRITE_ASS(fd, "d", fd); + __WRITE_ASS(group_fd, "d", group_fd); + __WRITE_ASS(cpu, "d", cpu.cpu); + __WRITE_ASS(pid, "d", pid); + __WRITE_ASS(flags, "lu", flags); + + /* struct perf_event_attr */ + WRITE_ASS(type, PRIu32); + WRITE_ASS(size, PRIu32); + WRITE_ASS(config, "llu"); + WRITE_ASS(sample_period, "llu"); + WRITE_ASS(sample_type, "llu"); + WRITE_ASS(read_format, "llu"); + WRITE_ASS(disabled, "d"); + WRITE_ASS(inherit, "d"); + WRITE_ASS(pinned, "d"); + WRITE_ASS(exclusive, "d"); + WRITE_ASS(exclude_user, "d"); + WRITE_ASS(exclude_kernel, "d"); + WRITE_ASS(exclude_hv, "d"); + WRITE_ASS(exclude_idle, "d"); + WRITE_ASS(mmap, "d"); + WRITE_ASS(comm, "d"); + WRITE_ASS(freq, "d"); + WRITE_ASS(inherit_stat, "d"); + WRITE_ASS(enable_on_exec, "d"); + WRITE_ASS(task, "d"); + WRITE_ASS(watermark, "d"); + WRITE_ASS(precise_ip, "d"); + WRITE_ASS(mmap_data, "d"); + WRITE_ASS(sample_id_all, "d"); + WRITE_ASS(exclude_host, "d"); + WRITE_ASS(exclude_guest, "d"); + WRITE_ASS(exclude_callchain_kernel, "d"); + WRITE_ASS(exclude_callchain_user, "d"); + WRITE_ASS(mmap2, "d"); + WRITE_ASS(comm_exec, "d"); + WRITE_ASS(context_switch, "d"); + WRITE_ASS(write_backward, "d"); + WRITE_ASS(namespaces, "d"); + WRITE_ASS(use_clockid, "d"); + WRITE_ASS(wakeup_events, PRIu32); + WRITE_ASS(bp_type, PRIu32); + WRITE_ASS(config1, "llu"); + WRITE_ASS(config2, "llu"); + WRITE_ASS(branch_sample_type, "llu"); + WRITE_ASS(sample_regs_user, "llu"); + WRITE_ASS(sample_stack_user, PRIu32); + + fclose(file); return 0; } -void __weak test_attr__ready(void) { } +#undef __WRITE_ASS +#undef WRITE_ASS + +static void test_attr__open(struct perf_event_attr *attr, pid_t pid, struct perf_cpu cpu, + int fd, int group_fd, unsigned long flags) +{ + int errno_saved = errno; + + if ((fd != -1) && store_event(attr, pid, cpu, fd, group_fd, flags)) { + pr_err("test attr FAILED"); + exit(128); + } + + errno = errno_saved; +} static void evsel__no_extra_fini(struct evsel *evsel __maybe_unused) { @@ -296,9 +392,9 @@ void evsel__init(struct evsel *evsel, evsel->metric_events = NULL; evsel->per_pkg_mask = NULL; evsel->collect_stat = false; - evsel->pmu_name = NULL; evsel->group_pmu_name = NULL; evsel->skippable = false; + evsel->alternate_hw_config = PERF_COUNT_HW_MAX; } struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx) @@ -393,11 +489,6 @@ struct evsel *evsel__clone(struct evsel *orig) if (evsel->group_name == NULL) goto out_err; } - if (orig->pmu_name) { - evsel->pmu_name = strdup(orig->pmu_name); - if (evsel->pmu_name == NULL) - goto out_err; - } if (orig->group_pmu_name) { evsel->group_pmu_name = strdup(orig->group_pmu_name); if (evsel->group_pmu_name == NULL) @@ -421,7 +512,6 @@ struct evsel *evsel__clone(struct evsel *orig) evsel->core.leader = orig->core.leader; evsel->max_events = orig->max_events; - evsel->tool_event = orig->tool_event; free((char *)evsel->unit); evsel->unit = strdup(orig->unit); if (evsel->unit == NULL) @@ -445,6 +535,8 @@ struct evsel *evsel__clone(struct evsel *orig) if (evsel__copy_config_terms(evsel, orig) < 0) goto out_err; + evsel->alternate_hw_config = orig->alternate_hw_config; + return evsel; out_err: @@ -548,7 +640,6 @@ static int evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size) { int colon = 0, r = 0; struct perf_event_attr *attr = &evsel->core.attr; - bool exclude_guest_default = false; #define MOD_PRINT(context, mod) do { \ if (!attr->exclude_##context) { \ @@ -560,17 +651,15 @@ static int evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size) MOD_PRINT(kernel, 'k'); MOD_PRINT(user, 'u'); MOD_PRINT(hv, 'h'); - exclude_guest_default = true; } if (attr->precise_ip) { if (!colon) colon = ++r; r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); - exclude_guest_default = true; } - if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) { + if (attr->exclude_host || attr->exclude_guest) { MOD_PRINT(host, 'H'); MOD_PRINT(guest, 'G'); } @@ -617,11 +706,6 @@ static int evsel__sw_name(struct evsel *evsel, char *bf, size_t size) return r + evsel__add_modifiers(evsel, bf + r, size - r); } -static int evsel__tool_name(enum perf_tool_event ev, char *bf, size_t size) -{ - return scnprintf(bf, size, "%s", perf_tool_event__to_str(ev)); -} - static int __evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) { int r; @@ -772,10 +856,7 @@ const char *evsel__name(struct evsel *evsel) break; case PERF_TYPE_SOFTWARE: - if (evsel__is_tool(evsel)) - evsel__tool_name(evsel__tool_event(evsel), bf, sizeof(bf)); - else - evsel__sw_name(evsel, bf, sizeof(bf)); + evsel__sw_name(evsel, bf, sizeof(bf)); break; case PERF_TYPE_TRACEPOINT: @@ -786,6 +867,10 @@ const char *evsel__name(struct evsel *evsel) evsel__bp_name(evsel, bf, sizeof(bf)); break; + case PERF_PMU_TYPE_TOOL: + scnprintf(bf, sizeof(bf), "%s", evsel__tool_pmu_event_name(evsel)); + break; + default: scnprintf(bf, sizeof(bf), "unknown attr type: %d", evsel->core.attr.type); @@ -811,7 +896,7 @@ const char *evsel__metric_id(const struct evsel *evsel) return evsel->metric_id; if (evsel__is_tool(evsel)) - return perf_tool_event__to_str(evsel__tool_event(evsel)); + return evsel__tool_pmu_event_name(evsel); return "unknown"; } @@ -862,7 +947,6 @@ static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *o { bool function = evsel__is_function_event(evsel); struct perf_event_attr *attr = &evsel->core.attr; - const char *arch = perf_env__arch(evsel__env(evsel)); evsel__set_sample_bit(evsel, CALLCHAIN); @@ -893,6 +977,8 @@ static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *o if (param->record_mode == CALLCHAIN_DWARF) { if (!function) { + const char *arch = perf_env__arch(evsel__env(evsel)); + evsel__set_sample_bit(evsel, REGS_USER); evsel__set_sample_bit(evsel, STACK_USER); if (opts->sample_user_regs && @@ -1150,7 +1236,7 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts, bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; - attr->inherit = !opts->no_inherit; + attr->inherit = target__has_cpu(&opts->target) ? 0 : !opts->no_inherit; attr->write_backward = opts->overwrite ? 1 : 0; attr->read_format = PERF_FORMAT_LOST; @@ -1172,7 +1258,15 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts, */ if (leader->core.nr_members > 1) { attr->read_format |= PERF_FORMAT_GROUP; - attr->inherit = 0; + } + + /* + * Inherit + SAMPLE_READ requires SAMPLE_TID in the read_format + */ + if (attr->inherit) { + evsel__set_sample_bit(evsel, TID); + evsel->core.attr.read_format |= + PERF_FORMAT_ID; } } @@ -1494,7 +1588,6 @@ void evsel__exit(struct evsel *evsel) zfree(&evsel->group_name); zfree(&evsel->name); zfree(&evsel->filter); - zfree(&evsel->pmu_name); zfree(&evsel->group_pmu_name); zfree(&evsel->unit); zfree(&evsel->metric_id); @@ -1503,8 +1596,8 @@ void evsel__exit(struct evsel *evsel) evsel->per_pkg_mask = NULL; zfree(&evsel->metric_events); perf_evsel__object.fini(evsel); - if (evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME || - evsel__tool_event(evsel) == PERF_TOOL_USER_TIME) + if (evsel__tool_event(evsel) == TOOL_PMU__EVENT_SYSTEM_TIME || + evsel__tool_event(evsel) == TOOL_PMU__EVENT_USER_TIME) xyarray__delete(evsel->start_times); } @@ -1684,171 +1777,31 @@ static int evsel__read_group(struct evsel *leader, int cpu_map_idx, int thread) return evsel__process_group_data(leader, cpu_map_idx, thread, data); } -static bool read_until_char(struct io *io, char e) -{ - int c; - - do { - c = io__get_char(io); - if (c == -1) - return false; - } while (c != e); - return true; -} - -static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val) -{ - char buf[256]; - struct io io; - int i; - - io__init(&io, fd, buf, sizeof(buf)); - - /* Skip lines to relevant CPU. */ - for (i = -1; i < cpu.cpu; i++) { - if (!read_until_char(&io, '\n')) - return -EINVAL; - } - /* Skip to "cpu". */ - if (io__get_char(&io) != 'c') return -EINVAL; - if (io__get_char(&io) != 'p') return -EINVAL; - if (io__get_char(&io) != 'u') return -EINVAL; - - /* Skip N of cpuN. */ - if (!read_until_char(&io, ' ')) - return -EINVAL; - - i = 1; - while (true) { - if (io__get_dec(&io, val) != ' ') - break; - if (field == i) - return 0; - i++; - } - return -EINVAL; -} - -static int read_pid_stat_field(int fd, int field, __u64 *val) +bool __evsel__match(const struct evsel *evsel, u32 type, u64 config) { - char buf[256]; - struct io io; - int c, i; - io__init(&io, fd, buf, sizeof(buf)); - if (io__get_dec(&io, val) != ' ') - return -EINVAL; - if (field == 1) - return 0; - - /* Skip comm. */ - if (io__get_char(&io) != '(' || !read_until_char(&io, ')')) - return -EINVAL; - if (field == 2) - return -EINVAL; /* String can't be returned. */ - - /* Skip state */ - if (io__get_char(&io) != ' ' || io__get_char(&io) == -1) - return -EINVAL; - if (field == 3) - return -EINVAL; /* String can't be returned. */ - - /* Loop over numeric fields*/ - if (io__get_char(&io) != ' ') - return -EINVAL; + u32 e_type = evsel->core.attr.type; + u64 e_config = evsel->core.attr.config; - i = 4; - while (true) { - c = io__get_dec(&io, val); - if (c == -1) - return -EINVAL; - if (c == -2) { - /* Assume a -ve was read */ - c = io__get_dec(&io, val); - *val *= -1; - } - if (c != ' ') - return -EINVAL; - if (field == i) - return 0; - i++; + if (e_type != type) { + return type == PERF_TYPE_HARDWARE && evsel->pmu && evsel->pmu->is_core && + evsel->alternate_hw_config == config; } - return -EINVAL; -} - -static int evsel__read_tool(struct evsel *evsel, int cpu_map_idx, int thread) -{ - __u64 *start_time, cur_time, delta_start; - int fd, err = 0; - struct perf_counts_values *count; - bool adjust = false; - count = perf_counts(evsel->counts, cpu_map_idx, thread); + if ((type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) && + perf_pmus__supports_extended_type()) + e_config &= PERF_HW_EVENT_MASK; - switch (evsel__tool_event(evsel)) { - case PERF_TOOL_DURATION_TIME: - /* - * Pretend duration_time is only on the first CPU and thread, or - * else aggregation will scale duration_time by the number of - * CPUs/threads. - */ - start_time = &evsel->start_time; - if (cpu_map_idx == 0 && thread == 0) - cur_time = rdclock(); - else - cur_time = *start_time; - break; - case PERF_TOOL_USER_TIME: - case PERF_TOOL_SYSTEM_TIME: { - bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME; - - start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread); - fd = FD(evsel, cpu_map_idx, thread); - lseek(fd, SEEK_SET, 0); - if (evsel->pid_stat) { - /* The event exists solely on 1 CPU. */ - if (cpu_map_idx == 0) - err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time); - else - cur_time = 0; - } else { - /* The event is for all threads. */ - if (thread == 0) { - struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus, - cpu_map_idx); - - err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time); - } else { - cur_time = 0; - } - } - adjust = true; - break; - } - case PERF_TOOL_NONE: - case PERF_TOOL_MAX: - default: - err = -EINVAL; - } - if (err) - return err; - - delta_start = cur_time - *start_time; - if (adjust) { - __u64 ticks_per_sec = sysconf(_SC_CLK_TCK); - - delta_start *= 1000000000 / ticks_per_sec; - } - count->val = delta_start; - count->ena = count->run = delta_start; - count->lost = 0; - return 0; + return e_config == config; } int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread) { if (evsel__is_tool(evsel)) - return evsel__read_tool(evsel, cpu_map_idx, thread); + return evsel__tool_pmu_read(evsel, cpu_map_idx, thread); + + if (evsel__is_hwmon(evsel)) + return evsel__hwmon_pmu_read(evsel, cpu_map_idx, thread); if (evsel__is_retire_lat(evsel)) return evsel__read_retire_lat(evsel, cpu_map_idx, thread); @@ -2042,6 +1995,7 @@ static struct perf_thread_map *empty_thread_map; static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, struct perf_thread_map *threads) { + int ret = 0; int nthreads = perf_thread_map__nr(threads); if ((perf_missing_features.write_backward && evsel->core.attr.write_backward) || @@ -2072,23 +2026,21 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, perf_evsel__alloc_fd(&evsel->core, perf_cpu_map__nr(cpus), nthreads) < 0) return -ENOMEM; - if ((evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME || - evsel__tool_event(evsel) == PERF_TOOL_USER_TIME) && - !evsel->start_times) { - evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus), nthreads, sizeof(__u64)); - if (!evsel->start_times) - return -ENOMEM; - } + if (evsel__is_tool(evsel)) + ret = evsel__tool_pmu_prepare_open(evsel, cpus, nthreads); evsel->open_flags = PERF_FLAG_FD_CLOEXEC; if (evsel->cgrp) evsel->open_flags |= PERF_FLAG_PID_CGROUP; - return 0; + return ret; } static void evsel__disable_missing_features(struct evsel *evsel) { + if (perf_missing_features.inherit_sample_read && evsel->core.attr.inherit && + (evsel->core.attr.sample_type & PERF_SAMPLE_READ)) + evsel->core.attr.inherit = 0; if (perf_missing_features.branch_counters) evsel->core.attr.branch_sample_type &= ~PERF_SAMPLE_BRANCH_COUNTERS; if (perf_missing_features.read_lost) @@ -2138,120 +2090,346 @@ int evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, return err; } -bool evsel__detect_missing_features(struct evsel *evsel) +static bool has_attr_feature(struct perf_event_attr *attr, unsigned long flags) +{ + int fd = syscall(SYS_perf_event_open, attr, /*pid=*/0, /*cpu=*/-1, + /*group_fd=*/-1, flags); + close(fd); + + if (fd < 0) { + attr->exclude_kernel = 1; + + fd = syscall(SYS_perf_event_open, attr, /*pid=*/0, /*cpu=*/-1, + /*group_fd=*/-1, flags); + close(fd); + } + + if (fd < 0) { + attr->exclude_hv = 1; + + fd = syscall(SYS_perf_event_open, attr, /*pid=*/0, /*cpu=*/-1, + /*group_fd=*/-1, flags); + close(fd); + } + + if (fd < 0) { + attr->exclude_guest = 1; + + fd = syscall(SYS_perf_event_open, attr, /*pid=*/0, /*cpu=*/-1, + /*group_fd=*/-1, flags); + close(fd); + } + + attr->exclude_kernel = 0; + attr->exclude_guest = 0; + attr->exclude_hv = 0; + + return fd >= 0; +} + +static void evsel__detect_missing_pmu_features(struct evsel *evsel) { + struct perf_event_attr attr = { + .type = evsel->core.attr.type, + .config = evsel->core.attr.config, + .disabled = 1, + }; + struct perf_pmu *pmu = evsel->pmu; + int old_errno; + + old_errno = errno; + + if (pmu == NULL) + pmu = evsel->pmu = evsel__find_pmu(evsel); + + if (pmu == NULL || pmu->missing_features.checked) + goto out; + /* * Must probe features in the order they were added to the - * perf_event_attr interface. + * perf_event_attr interface. These are kernel core limitation but + * specific to PMUs with branch stack. So we can detect with the given + * hardware event and stop on the first one succeeded. */ - if (!perf_missing_features.branch_counters && - (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS)) { - perf_missing_features.branch_counters = true; - pr_debug2("switching off branch counters support\n"); + + /* Please add new feature detection here. */ + + attr.exclude_guest = 1; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + pmu->missing_features.exclude_guest = true; + pr_debug2("switching off exclude_guest for PMU %s\n", pmu->name); + +found: + pmu->missing_features.checked = true; +out: + errno = old_errno; +} + +static void evsel__detect_missing_brstack_features(struct evsel *evsel) +{ + static bool detection_done = false; + struct perf_event_attr attr = { + .type = evsel->core.attr.type, + .config = evsel->core.attr.config, + .disabled = 1, + .sample_type = PERF_SAMPLE_BRANCH_STACK, + .sample_period = 1000, + }; + int old_errno; + + if (detection_done) + return; + + old_errno = errno; + + /* + * Must probe features in the order they were added to the + * perf_event_attr interface. These are PMU specific limitation + * so we can detect with the given hardware event and stop on the + * first one succeeded. + */ + + /* Please add new feature detection here. */ + + attr.branch_sample_type = PERF_SAMPLE_BRANCH_COUNTERS; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.branch_counters = true; + pr_debug2("switching off branch counters support\n"); + + attr.branch_sample_type = PERF_SAMPLE_BRANCH_HW_INDEX; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.branch_hw_idx = true; + pr_debug2("switching off branch HW index support\n"); + + attr.branch_sample_type = PERF_SAMPLE_BRANCH_NO_CYCLES | PERF_SAMPLE_BRANCH_NO_FLAGS; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.lbr_flags = true; + pr_debug2_peo("switching off branch sample type no (cycles/flags)\n"); + +found: + detection_done = true; + errno = old_errno; +} + +static bool evsel__detect_missing_features(struct evsel *evsel) +{ + static bool detection_done = false; + struct perf_event_attr attr = { + .type = PERF_TYPE_SOFTWARE, + .config = PERF_COUNT_SW_TASK_CLOCK, + .disabled = 1, + }; + int old_errno; + + evsel__detect_missing_pmu_features(evsel); + + if (evsel__has_br_stack(evsel)) + evsel__detect_missing_brstack_features(evsel); + + if (detection_done) + goto check; + + old_errno = errno; + + /* + * Must probe features in the order they were added to the + * perf_event_attr interface. These are kernel core limitation + * not PMU-specific so we can detect with a software event and + * stop on the first one succeeded. + */ + + /* Please add new feature detection here. */ + + attr.inherit = true; + attr.sample_type = PERF_SAMPLE_READ; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.inherit_sample_read = true; + pr_debug2("Using PERF_SAMPLE_READ / :S modifier is not compatible with inherit, falling back to no-inherit.\n"); + attr.inherit = false; + attr.sample_type = 0; + + attr.read_format = PERF_FORMAT_LOST; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.read_lost = true; + pr_debug2("switching off PERF_FORMAT_LOST support\n"); + attr.read_format = 0; + + attr.sample_type = PERF_SAMPLE_WEIGHT_STRUCT; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.weight_struct = true; + pr_debug2("switching off weight struct support\n"); + attr.sample_type = 0; + + attr.sample_type = PERF_SAMPLE_CODE_PAGE_SIZE; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.code_page_size = true; + pr_debug2_peo("Kernel has no PERF_SAMPLE_CODE_PAGE_SIZE support\n"); + attr.sample_type = 0; + + attr.sample_type = PERF_SAMPLE_DATA_PAGE_SIZE; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.data_page_size = true; + pr_debug2_peo("Kernel has no PERF_SAMPLE_DATA_PAGE_SIZE support\n"); + attr.sample_type = 0; + + attr.cgroup = 1; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.cgroup = true; + pr_debug2_peo("Kernel has no cgroup sampling support\n"); + attr.cgroup = 0; + + attr.aux_output = 1; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.aux_output = true; + pr_debug2_peo("Kernel has no attr.aux_output support\n"); + attr.aux_output = 0; + + attr.bpf_event = 1; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.bpf = true; + pr_debug2_peo("switching off bpf_event\n"); + attr.bpf_event = 0; + + attr.ksymbol = 1; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.ksymbol = true; + pr_debug2_peo("switching off ksymbol\n"); + attr.ksymbol = 0; + + attr.write_backward = 1; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.write_backward = true; + pr_debug2_peo("switching off write_backward\n"); + attr.write_backward = 0; + + attr.use_clockid = 1; + attr.clockid = CLOCK_MONOTONIC; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.clockid = true; + pr_debug2_peo("switching off clockid\n"); + attr.use_clockid = 0; + attr.clockid = 0; + + if (has_attr_feature(&attr, /*flags=*/PERF_FLAG_FD_CLOEXEC)) + goto found; + perf_missing_features.cloexec = true; + pr_debug2_peo("switching off cloexec flag\n"); + + attr.mmap2 = 1; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.mmap2 = true; + pr_debug2_peo("switching off mmap2\n"); + attr.mmap2 = 0; + + /* set this unconditionally? */ + perf_missing_features.sample_id_all = true; + pr_debug2_peo("switching off sample_id_all\n"); + + attr.inherit = 1; + attr.read_format = PERF_FORMAT_GROUP; + if (has_attr_feature(&attr, /*flags=*/0)) + goto found; + perf_missing_features.group_read = true; + pr_debug2_peo("switching off group read\n"); + attr.inherit = 0; + attr.read_format = 0; + +found: + detection_done = true; + errno = old_errno; + +check: + if (evsel->core.attr.inherit && + (evsel->core.attr.sample_type & PERF_SAMPLE_READ) && + perf_missing_features.inherit_sample_read) return true; - } else if (!perf_missing_features.read_lost && - (evsel->core.attr.read_format & PERF_FORMAT_LOST)) { - perf_missing_features.read_lost = true; - pr_debug2("switching off PERF_FORMAT_LOST support\n"); + + if ((evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS) && + perf_missing_features.branch_counters) return true; - } else if (!perf_missing_features.weight_struct && - (evsel->core.attr.sample_type & PERF_SAMPLE_WEIGHT_STRUCT)) { - perf_missing_features.weight_struct = true; - pr_debug2("switching off weight struct support\n"); + + if ((evsel->core.attr.read_format & PERF_FORMAT_LOST) && + perf_missing_features.read_lost) return true; - } else if (!perf_missing_features.code_page_size && - (evsel->core.attr.sample_type & PERF_SAMPLE_CODE_PAGE_SIZE)) { - perf_missing_features.code_page_size = true; - pr_debug2_peo("Kernel has no PERF_SAMPLE_CODE_PAGE_SIZE support, bailing out\n"); - return false; - } else if (!perf_missing_features.data_page_size && - (evsel->core.attr.sample_type & PERF_SAMPLE_DATA_PAGE_SIZE)) { - perf_missing_features.data_page_size = true; - pr_debug2_peo("Kernel has no PERF_SAMPLE_DATA_PAGE_SIZE support, bailing out\n"); - return false; - } else if (!perf_missing_features.cgroup && evsel->core.attr.cgroup) { - perf_missing_features.cgroup = true; - pr_debug2_peo("Kernel has no cgroup sampling support, bailing out\n"); - return false; - } else if (!perf_missing_features.branch_hw_idx && - (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX)) { - perf_missing_features.branch_hw_idx = true; - pr_debug2("switching off branch HW index support\n"); + + if ((evsel->core.attr.sample_type & PERF_SAMPLE_WEIGHT_STRUCT) && + perf_missing_features.weight_struct) return true; - } else if (!perf_missing_features.aux_output && evsel->core.attr.aux_output) { - perf_missing_features.aux_output = true; - pr_debug2_peo("Kernel has no attr.aux_output support, bailing out\n"); - return false; - } else if (!perf_missing_features.bpf && evsel->core.attr.bpf_event) { - perf_missing_features.bpf = true; - pr_debug2_peo("switching off bpf_event\n"); + + if (evsel->core.attr.use_clockid && evsel->core.attr.clockid != CLOCK_MONOTONIC && + !perf_missing_features.clockid) { + perf_missing_features.clockid_wrong = true; return true; - } else if (!perf_missing_features.ksymbol && evsel->core.attr.ksymbol) { - perf_missing_features.ksymbol = true; - pr_debug2_peo("switching off ksymbol\n"); + } + + if (evsel->core.attr.use_clockid && perf_missing_features.clockid) return true; - } else if (!perf_missing_features.write_backward && evsel->core.attr.write_backward) { - perf_missing_features.write_backward = true; - pr_debug2_peo("switching off write_backward\n"); - return false; - } else if (!perf_missing_features.clockid_wrong && evsel->core.attr.use_clockid) { - perf_missing_features.clockid_wrong = true; - pr_debug2_peo("switching off clockid\n"); + + if ((evsel->open_flags & PERF_FLAG_FD_CLOEXEC) && + perf_missing_features.cloexec) return true; - } else if (!perf_missing_features.clockid && evsel->core.attr.use_clockid) { - perf_missing_features.clockid = true; - pr_debug2_peo("switching off use_clockid\n"); + + if (evsel->core.attr.mmap2 && perf_missing_features.mmap2) return true; - } else if (!perf_missing_features.cloexec && (evsel->open_flags & PERF_FLAG_FD_CLOEXEC)) { - perf_missing_features.cloexec = true; - pr_debug2_peo("switching off cloexec flag\n"); + + if ((evsel->core.attr.branch_sample_type & (PERF_SAMPLE_BRANCH_NO_FLAGS | + PERF_SAMPLE_BRANCH_NO_CYCLES)) && + perf_missing_features.lbr_flags) return true; - } else if (!perf_missing_features.mmap2 && evsel->core.attr.mmap2) { - perf_missing_features.mmap2 = true; - pr_debug2_peo("switching off mmap2\n"); + + if (evsel->core.attr.inherit && (evsel->core.attr.read_format & PERF_FORMAT_GROUP) && + perf_missing_features.group_read) return true; - } else if (evsel->core.attr.exclude_guest || evsel->core.attr.exclude_host) { - if (evsel->pmu == NULL) - evsel->pmu = evsel__find_pmu(evsel); - - if (evsel->pmu) - evsel->pmu->missing_features.exclude_guest = true; - else { - /* we cannot find PMU, disable attrs now */ - evsel->core.attr.exclude_host = false; - evsel->core.attr.exclude_guest = false; - } - if (evsel->exclude_GH) { - pr_debug2_peo("PMU has no exclude_host/guest support, bailing out\n"); - return false; - } - if (!perf_missing_features.exclude_guest) { - perf_missing_features.exclude_guest = true; - pr_debug2_peo("switching off exclude_guest, exclude_host\n"); - } + if (evsel->core.attr.ksymbol && perf_missing_features.ksymbol) return true; - } else if (!perf_missing_features.sample_id_all) { - perf_missing_features.sample_id_all = true; - pr_debug2_peo("switching off sample_id_all\n"); + + if (evsel->core.attr.bpf_event && perf_missing_features.bpf) return true; - } else if (!perf_missing_features.lbr_flags && - (evsel->core.attr.branch_sample_type & - (PERF_SAMPLE_BRANCH_NO_CYCLES | - PERF_SAMPLE_BRANCH_NO_FLAGS))) { - perf_missing_features.lbr_flags = true; - pr_debug2_peo("switching off branch sample type no (cycles/flags)\n"); + + if ((evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX) && + perf_missing_features.branch_hw_idx) return true; - } else if (!perf_missing_features.group_read && - evsel->core.attr.inherit && - (evsel->core.attr.read_format & PERF_FORMAT_GROUP) && - evsel__is_group_leader(evsel)) { - perf_missing_features.group_read = true; - pr_debug2_peo("switching off group read\n"); + + if (evsel->core.attr.sample_id_all && perf_missing_features.sample_id_all) + return true; + + return false; +} + +static bool evsel__handle_error_quirks(struct evsel *evsel, int error) +{ + /* + * AMD core PMU tries to forward events with precise_ip to IBS PMU + * implicitly. But IBS PMU has more restrictions so it can fail with + * supported event attributes. Let's forward it back to the core PMU + * by clearing precise_ip only if it's from precise_max (:P). + */ + if ((error == -EINVAL || error == -ENOENT) && x86__is_amd_cpu() && + evsel->core.attr.precise_ip && evsel->precise_max) { + evsel->core.attr.precise_ip = 0; + pr_debug2_peo("removing precise_ip on AMD\n"); + display_attr(&evsel->core.attr); return true; - } else { - return false; } + + return false; } static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, @@ -2262,13 +2440,6 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, int pid = -1, err, old_errno; enum rlimit_action set_rlimit = NO_CHANGE; - if (evsel__tool_event(evsel) == PERF_TOOL_DURATION_TIME) { - if (evsel->core.attr.sample_period) /* no sampling */ - return -EINVAL; - evsel->start_time = rdclock(); - return 0; - } - if (evsel__is_retire_lat(evsel)) return tpebs_start(evsel->evlist); @@ -2293,6 +2464,17 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, pr_debug3("Opening: %s\n", evsel__name(evsel)); display_attr(&evsel->core.attr); + if (evsel__is_tool(evsel)) { + return evsel__tool_pmu_open(evsel, threads, + start_cpu_map_idx, + end_cpu_map_idx); + } + if (evsel__is_hwmon(evsel)) { + return evsel__hwmon_pmu_open(evsel, threads, + start_cpu_map_idx, + end_cpu_map_idx); + } + for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) { for (thread = 0; thread < nthreads; thread++) { @@ -2304,46 +2486,6 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, if (!evsel->cgrp && !evsel->core.system_wide) pid = perf_thread_map__pid(threads, thread); - if (evsel__tool_event(evsel) == PERF_TOOL_USER_TIME || - evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME) { - bool system = evsel__tool_event(evsel) == PERF_TOOL_SYSTEM_TIME; - __u64 *start_time = NULL; - - if (evsel->core.attr.sample_period) { - /* no sampling */ - err = -EINVAL; - goto out_close; - } - if (pid > -1) { - char buf[64]; - - snprintf(buf, sizeof(buf), "/proc/%d/stat", pid); - fd = open(buf, O_RDONLY); - evsel->pid_stat = true; - } else { - fd = open("/proc/stat", O_RDONLY); - } - FD(evsel, idx, thread) = fd; - if (fd < 0) { - err = -errno; - goto out_close; - } - start_time = xyarray__entry(evsel->start_times, idx, thread); - if (pid > -1) { - err = read_pid_stat_field(fd, system ? 15 : 14, - start_time); - } else { - struct perf_cpu cpu; - - cpu = perf_cpu_map__cpu(evsel->core.cpus, idx); - err = read_stat_field(fd, cpu, system ? 3 : 1, - start_time); - } - if (err) - goto out_close; - continue; - } - group_fd = get_group_fd(evsel, idx, thread); if (group_fd == -2) { @@ -2352,8 +2494,6 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, goto out_close; } - test_attr__ready(); - /* Debug message used by test scripts */ pr_debug2_peo("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", pid, perf_cpu_map__cpu(cpus, idx).cpu, group_fd, evsel->open_flags); @@ -2374,7 +2514,7 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, bpf_counter__install_pe(evsel, idx, fd); - if (unlikely(test_attr__enabled)) { + if (unlikely(test_attr__enabled())) { test_attr__open(&evsel->core.attr, pid, perf_cpu_map__cpu(cpus, idx), fd, group_fd, evsel->open_flags); @@ -2415,9 +2555,6 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, return 0; try_fallback: - if (evsel__precise_ip_fallback(evsel)) - goto retry_open; - if (evsel__ignore_missing_thread(evsel, perf_cpu_map__nr(cpus), idx, threads, thread, err)) { /* We just removed 1 thread, so lower the upper nthreads limit. */ @@ -2434,11 +2571,15 @@ static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, if (err == -EMFILE && rlimit__increase_nofile(&set_rlimit)) goto retry_open; - if (err != -EINVAL || idx > 0 || thread > 0) - goto out_close; - - if (evsel__detect_missing_features(evsel)) + if (err == -EINVAL && evsel__detect_missing_features(evsel)) goto fallback_missing_features; + + if (evsel__precise_ip_fallback(evsel)) + goto retry_open; + + if (evsel__handle_error_quirks(evsel, err)) + goto retry_open; + out_close: if (err) threads->err_thread = thread; @@ -3244,6 +3385,27 @@ bool evsel__fallback(struct evsel *evsel, struct target *target, int err, evsel->core.attr.exclude_kernel = 1; evsel->core.attr.exclude_hv = 1; + return true; + } else if (err == EOPNOTSUPP && !evsel->core.attr.exclude_guest && + !evsel->exclude_GH) { + const char *name = evsel__name(evsel); + char *new_name; + const char *sep = ":"; + + /* Is there already the separator in the name. */ + if (strchr(name, '/') || + (strchr(name, ':') && !evsel->is_libpfm_event)) + sep = ""; + + if (asprintf(&new_name, "%s%sH", name, sep) < 0) + return false; + + free(evsel->name); + evsel->name = new_name; + /* Apple M1 requires exclude_guest */ + scnprintf(msg, msgsize, "trying to fall back to excluding guest samples"); + evsel->core.attr.exclude_guest = 1; + return true; } @@ -3415,7 +3577,7 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target, return scnprintf(msg, size, "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" - "/bin/dmesg | grep -i perf may provide additional information.\n", + "\"dmesg | grep -i perf\" may provide additional information.\n", err, str_error_r(err, sbuf, sizeof(sbuf)), evsel__name(evsel)); } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 15e745a9a798fa..04934a7af17452 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -11,6 +11,7 @@ #include #include "symbol_conf.h" #include "pmus.h" +#include "pmu.h" struct bpf_object; struct cgroup; @@ -22,25 +23,9 @@ struct target; struct hashmap; struct bperf_leader_bpf; struct bperf_follower_bpf; -struct perf_pmu; typedef int (evsel__sb_cb_t)(union perf_event *event, void *data); -enum perf_tool_event { - PERF_TOOL_NONE = 0, - PERF_TOOL_DURATION_TIME = 1, - PERF_TOOL_USER_TIME = 2, - PERF_TOOL_SYSTEM_TIME = 3, - - PERF_TOOL_MAX, -}; - -const char *perf_tool_event__to_str(enum perf_tool_event ev); -enum perf_tool_event perf_tool_event__from_str(const char *str); - -#define perf_tool_event__for_each_event(ev) \ - for ((ev) = PERF_TOOL_DURATION_TIME; (ev) < PERF_TOOL_MAX; ev++) - /** struct evsel - event selector * * @evlist - evlist this evsel is in, if it is in one. @@ -72,7 +57,6 @@ struct evsel { struct { char *name; char *group_name; - const char *pmu_name; const char *group_pmu_name; #ifdef HAVE_LIBTRACEEVENT struct tep_event *tp_format; @@ -83,7 +67,6 @@ struct evsel { const char *unit; struct cgroup *cgrp; const char *metric_id; - enum perf_tool_event tool_event; /* parse modifier helper */ int exclude_GH; int sample_read; @@ -102,6 +85,7 @@ struct evsel { int bpf_fd; struct bpf_object *bpf_obj; struct list_head config_terms; + u64 alternate_hw_config; }; /* @@ -183,7 +167,7 @@ struct evsel { unsigned long open_flags; int precise_ip_original; - /* for missing_features */ + /* The PMU the event is from. Used for missing_features, PMU name, etc. */ struct perf_pmu *pmu; /* For tool events */ @@ -221,6 +205,7 @@ struct perf_missing_features { bool weight_struct; bool read_lost; bool branch_counters; + bool inherit_sample_read; }; extern struct perf_missing_features perf_missing_features; @@ -320,21 +305,11 @@ const char *evsel__name(struct evsel *evsel); bool evsel__name_is(struct evsel *evsel, const char *name); const char *evsel__metric_id(const struct evsel *evsel); -static inline bool evsel__is_tool(const struct evsel *evsel) -{ - return evsel->tool_event != PERF_TOOL_NONE; -} - static inline bool evsel__is_retire_lat(const struct evsel *evsel) { return evsel->retire_lat; } -static inline enum perf_tool_event evsel__tool_event(const struct evsel *evsel) -{ - return evsel->tool_event; -} - const char *evsel__group_name(struct evsel *evsel); int evsel__group_desc(struct evsel *evsel, char *buf, size_t size); @@ -368,7 +343,6 @@ int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus, void evsel__close(struct evsel *evsel); int evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, struct perf_thread_map *threads); -bool evsel__detect_missing_features(struct evsel *evsel); bool evsel__precise_ip_fallback(struct evsel *evsel); @@ -393,26 +367,10 @@ u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sam struct tep_format_field *evsel__field(struct evsel *evsel, const char *name); struct tep_format_field *evsel__common_field(struct evsel *evsel, const char *name); -static inline bool __evsel__match(const struct evsel *evsel, u32 type, u64 config) -{ - if (evsel->core.attr.type != type) - return false; - - if ((type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE) && - perf_pmus__supports_extended_type()) - return (evsel->core.attr.config & PERF_HW_EVENT_MASK) == config; - - return evsel->core.attr.config == config; -} +bool __evsel__match(const struct evsel *evsel, u32 type, u64 config); #define evsel__match(evsel, t, c) __evsel__match(evsel, PERF_TYPE_##t, PERF_COUNT_##c) -static inline bool evsel__match2(struct evsel *e1, struct evsel *e2) -{ - return (e1->core.attr.type == e2->core.attr.type) && - (e1->core.attr.config == e2->core.attr.config); -} - int evsel__read_counter(struct evsel *evsel, int cpu_map_idx, int thread); int __evsel__read_on_cpu(struct evsel *evsel, int cpu_map_idx, int thread, bool scale); diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index c2c0500d5da99d..86b7f46f9e2a9d 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -14,7 +14,7 @@ #include "dso.h" #ifdef HAVE_LIBTRACEEVENT -#include +#include #endif static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c index b2536a59c44e64..f289044a1f7c63 100644 --- a/tools/perf/util/expr.c +++ b/tools/perf/util/expr.c @@ -5,25 +5,22 @@ #include #include #include "metricgroup.h" -#include "cpumap.h" -#include "cputopo.h" #include "debug.h" #include "evlist.h" #include "expr.h" +#include "smt.h" +#include "tool_pmu.h" #include #include #include "util/hashmap.h" #include "util/header.h" #include "util/pmu.h" -#include "smt.h" -#include "tsc.h" -#include +#include #include #include #include #include #include -#include "pmu.h" struct expr_id_data { union { @@ -393,90 +390,26 @@ double expr_id_data__source_count(const struct expr_id_data *data) return data->val.source_count; } -#if !defined(__i386__) && !defined(__x86_64__) -double arch_get_tsc_freq(void) -{ - return 0.0; -} -#endif - -static double has_pmem(void) -{ - static bool has_pmem, cached; - const char *sysfs = sysfs__mountpoint(); - char path[PATH_MAX]; - - if (!cached) { - snprintf(path, sizeof(path), "%s/firmware/acpi/tables/NFIT", sysfs); - has_pmem = access(path, F_OK) == 0; - cached = true; - } - return has_pmem ? 1.0 : 0.0; -} - double expr__get_literal(const char *literal, const struct expr_scanner_ctx *ctx) { - const struct cpu_topology *topology; double result = NAN; + enum tool_pmu_event ev = tool_pmu__str_to_event(literal + 1); - if (!strcmp("#num_cpus", literal)) { - result = cpu__max_present_cpu().cpu; - goto out; - } - if (!strcmp("#num_cpus_online", literal)) { - struct perf_cpu_map *online = cpu_map__online(); - - if (online) - result = perf_cpu_map__nr(online); - goto out; - } + if (ev != TOOL_PMU__EVENT_NONE) { + u64 count; - if (!strcasecmp("#system_tsc_freq", literal)) { - result = arch_get_tsc_freq(); - goto out; - } + if (tool_pmu__read_event(ev, &count)) + result = count; + else + pr_err("Failure to read '%s'", literal); - /* - * Assume that topology strings are consistent, such as CPUs "0-1" - * wouldn't be listed as "0,1", and so after deduplication the number of - * these strings gives an indication of the number of packages, dies, - * etc. - */ - if (!strcasecmp("#smt_on", literal)) { - result = smt_on() ? 1.0 : 0.0; - goto out; - } - if (!strcmp("#core_wide", literal)) { + } else if (!strcmp("#core_wide", literal)) { result = core_wide(ctx->system_wide, ctx->user_requested_cpu_list) ? 1.0 : 0.0; - goto out; - } - if (!strcmp("#num_packages", literal)) { - topology = online_topology(); - result = topology->package_cpus_lists; - goto out; - } - if (!strcmp("#num_dies", literal)) { - topology = online_topology(); - result = topology->die_cpus_lists; - goto out; - } - if (!strcmp("#num_cores", literal)) { - topology = online_topology(); - result = topology->core_cpus_lists; - goto out; - } - if (!strcmp("#slots", literal)) { - result = perf_pmu__cpu_slots_per_cycle(); - goto out; - } - if (!strcmp("#has_pmem", literal)) { - result = has_pmem(); - goto out; + } else { + pr_err("Unrecognized literal '%s'", literal); } - pr_err("Unrecognized literal '%s'", literal); -out: pr_debug2("literal: %s = %f\n", literal, result); return result; } @@ -523,8 +456,8 @@ double expr__strcmp_cpuid_str(const struct expr_parse_ctx *ctx __maybe_unused, bool compute_ids __maybe_unused, const char *test_id) { double ret; - struct perf_pmu *pmu = perf_pmus__find_core_pmu(); - char *cpuid = perf_pmu__getcpuid(pmu); + struct perf_cpu cpu = {-1}; + char *cpuid = get_cpuid_allow_env_override(cpu); if (!cpuid) return NAN; diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c index c8f6bee1fa6190..cdce7f173d00a9 100644 --- a/tools/perf/util/genelf.c +++ b/tools/perf/util/genelf.c @@ -16,7 +16,7 @@ #include #include #include -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT #include #endif @@ -499,7 +499,7 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym, shdr->sh_size = sizeof(bnote); shdr->sh_entsize = 0; -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT if (debug && nr_debug_entries) { retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries); if (retval) diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h index 4e2e4f40e134fd..9f0b875d6548cf 100644 --- a/tools/perf/util/genelf.h +++ b/tools/perf/util/genelf.h @@ -8,7 +8,7 @@ int jit_write_elf(int fd, uint64_t code_addr, const char *sym, const void *code, int csize, void *debug, int nr_debug_entries, void *unwinding, uint64_t unwinding_header_size, uint64_t unwinding_size); -#ifdef HAVE_DWARF_SUPPORT +#ifdef HAVE_LIBDW_SUPPORT /* genelf_debug.c */ int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries); #endif diff --git a/tools/perf/util/hashmap.h b/tools/perf/util/hashmap.h index c12f8320e6682d..0c4f155e8eb745 100644 --- a/tools/perf/util/hashmap.h +++ b/tools/perf/util/hashmap.h @@ -166,8 +166,8 @@ bool hashmap_find(const struct hashmap *map, long key, long *value); * @bkt: integer used as a bucket loop cursor */ #define hashmap__for_each_entry(map, cur, bkt) \ - for (bkt = 0; bkt < map->cap; bkt++) \ - for (cur = map->buckets[bkt]; cur; cur = cur->next) + for (bkt = 0; bkt < (map)->cap; bkt++) \ + for (cur = (map)->buckets[bkt]; cur; cur = cur->next) /* * hashmap__for_each_entry_safe - iterate over all entries in hashmap, safe @@ -178,8 +178,8 @@ bool hashmap_find(const struct hashmap *map, long key, long *value); * @bkt: integer used as a bucket loop cursor */ #define hashmap__for_each_entry_safe(map, cur, tmp, bkt) \ - for (bkt = 0; bkt < map->cap; bkt++) \ - for (cur = map->buckets[bkt]; \ + for (bkt = 0; bkt < (map)->cap; bkt++) \ + for (cur = (map)->buckets[bkt]; \ cur && ({tmp = cur->next; true; }); \ cur = tmp) @@ -190,19 +190,19 @@ bool hashmap_find(const struct hashmap *map, long key, long *value); * @key: key to iterate entries for */ #define hashmap__for_each_key_entry(map, cur, _key) \ - for (cur = map->buckets \ - ? map->buckets[hash_bits(map->hash_fn((_key), map->ctx), map->cap_bits)] \ + for (cur = (map)->buckets \ + ? (map)->buckets[hash_bits((map)->hash_fn((_key), (map)->ctx), (map)->cap_bits)] \ : NULL; \ cur; \ cur = cur->next) \ - if (map->equal_fn(cur->key, (_key), map->ctx)) + if ((map)->equal_fn(cur->key, (_key), (map)->ctx)) #define hashmap__for_each_key_entry_safe(map, cur, tmp, _key) \ - for (cur = map->buckets \ - ? map->buckets[hash_bits(map->hash_fn((_key), map->ctx), map->cap_bits)] \ + for (cur = (map)->buckets \ + ? (map)->buckets[hash_bits((map)->hash_fn((_key), (map)->ctx), (map)->cap_bits)] \ : NULL; \ cur && ({ tmp = cur->next; true; }); \ cur = tmp) \ - if (map->equal_fn(cur->key, (_key), map->ctx)) + if ((map)->equal_fn(cur->key, (_key), (map)->ctx)) #endif /* __LIBBPF_HASHMAP_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a6386d12afd729..3451e542b69a8c 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -58,7 +58,7 @@ #include #ifdef HAVE_LIBTRACEEVENT -#include +#include #endif /* @@ -819,11 +819,31 @@ static int write_group_desc(struct feat_fd *ff, * Each architecture should provide a more precise id string that * can be use to match the architecture's "mapfile". */ -char * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused) +char * __weak get_cpuid_str(struct perf_cpu cpu __maybe_unused) { return NULL; } +char *get_cpuid_allow_env_override(struct perf_cpu cpu) +{ + char *cpuid; + static bool printed; + + cpuid = getenv("PERF_CPUID"); + if (cpuid) + cpuid = strdup(cpuid); + if (!cpuid) + cpuid = get_cpuid_str(cpu); + if (!cpuid) + return NULL; + + if (!printed) { + pr_debug("Using CPUID %s\n", cpuid); + printed = true; + } + return cpuid; +} + /* Return zero when the cpuid from the mapfile.csv matches the * cpuid string generated on this platform. * Otherwise return non-zero. @@ -856,18 +876,19 @@ int __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid) * default get_cpuid(): nothing gets recorded * actual implementation must be in arch/$(SRCARCH)/util/header.c */ -int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) +int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused, + struct perf_cpu cpu __maybe_unused) { return ENOSYS; /* Not implemented */ } -static int write_cpuid(struct feat_fd *ff, - struct evlist *evlist __maybe_unused) +static int write_cpuid(struct feat_fd *ff, struct evlist *evlist) { + struct perf_cpu cpu = perf_cpu_map__min(evlist->core.all_cpus); char buffer[64]; int ret; - ret = get_cpuid(buffer, sizeof(buffer)); + ret = get_cpuid(buffer, sizeof(buffer), cpu); if (ret) return -1; @@ -987,57 +1008,6 @@ static int write_dir_format(struct feat_fd *ff, return do_write(ff, &data->dir.version, sizeof(data->dir.version)); } -/* - * Check whether a CPU is online - * - * Returns: - * 1 -> if CPU is online - * 0 -> if CPU is offline - * -1 -> error case - */ -int is_cpu_online(unsigned int cpu) -{ - char *str; - size_t strlen; - char buf[256]; - int status = -1; - struct stat statbuf; - - snprintf(buf, sizeof(buf), - "/sys/devices/system/cpu/cpu%d", cpu); - if (stat(buf, &statbuf) != 0) - return 0; - - /* - * Check if /sys/devices/system/cpu/cpux/online file - * exists. Some cases cpu0 won't have online file since - * it is not expected to be turned off generally. - * In kernels without CONFIG_HOTPLUG_CPU, this - * file won't exist - */ - snprintf(buf, sizeof(buf), - "/sys/devices/system/cpu/cpu%d/online", cpu); - if (stat(buf, &statbuf) != 0) - return 1; - - /* - * Read online file using sysfs__read_str. - * If read or open fails, return -1. - * If read succeeds, return value from file - * which gets stored in "str" - */ - snprintf(buf, sizeof(buf), - "devices/system/cpu/cpu%d/online", cpu); - - if (sysfs__read_str(buf, &str, &strlen) < 0) - return status; - - status = atoi(str); - - free(str); - return status; -} - #ifdef HAVE_LIBBPF_SUPPORT static int write_bpf_prog_info(struct feat_fd *ff, struct evlist *evlist __maybe_unused) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index a63a361f20f492..5201af6305f4bf 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -10,7 +10,13 @@ #include #include #include "env.h" -#include "pmu.h" +#include + +struct evlist; +union perf_event; +struct perf_header; +struct perf_session; +struct perf_tool; enum { HEADER_RESERVED = 0, /* always cleared */ @@ -91,8 +97,6 @@ struct perf_pipe_file_header { u64 size; }; -struct perf_header; - int perf_file_header__read(struct perf_file_header *header, struct perf_header *ph, int fd); @@ -124,11 +128,6 @@ struct perf_header_feature_ops { bool synthesize; }; -struct evlist; -struct perf_session; -struct perf_tool; -union perf_event; - extern const char perf_version_string[]; int perf_session__read_header(struct perf_session *session); @@ -196,14 +195,16 @@ int write_padded(struct feat_fd *fd, const void *bf, #define MAX_CACHE_LVL 4 -int is_cpu_online(unsigned int cpu); int build_caches_for_cpu(u32 cpu, struct cpu_cache_level caches[], u32 *cntp); /* * arch specific callback */ -int get_cpuid(char *buffer, size_t sz); +int get_cpuid(char *buffer, size_t sz, struct perf_cpu cpu); + +char *get_cpuid_str(struct perf_cpu cpu); + +char *get_cpuid_allow_env_override(struct perf_cpu cpu); -char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused); int strcmp_cpuid_str(const char *s1, const char *s2); #endif /* __PERF_HEADER_H */ diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f387e85a008739..fff13456580166 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -218,6 +218,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_LOCAL_P_STAGE_CYC, 13); hists__new_col_len(hists, HISTC_GLOBAL_P_STAGE_CYC, 13); hists__new_col_len(hists, HISTC_ADDR, BITS_PER_LONG / 4 + 2); + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_PREDICTED, 9); + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_ABORT, 5); + hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_CYCLES, 6); if (symbol_conf.nanosecs) hists__new_col_len(hists, HISTC_TIME, 16); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 7d7ae94b4b31fa..1131056924d9c2 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -87,6 +87,9 @@ enum hist_column { HISTC_TYPE_OFFSET, HISTC_SYMBOL_OFFSET, HISTC_TYPE_CACHELINE, + HISTC_CALLCHAIN_BRANCH_PREDICTED, + HISTC_CALLCHAIN_BRANCH_ABORT, + HISTC_CALLCHAIN_BRANCH_CYCLES, HISTC_NR_COLS, /* Last entry */ }; diff --git a/tools/perf/util/hwmon_pmu.c b/tools/perf/util/hwmon_pmu.c new file mode 100644 index 00000000000000..4acb9bb19b8464 --- /dev/null +++ b/tools/perf/util/hwmon_pmu.c @@ -0,0 +1,839 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +#include "counts.h" +#include "debug.h" +#include "evsel.h" +#include "hashmap.h" +#include "hwmon_pmu.h" +#include "pmu.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** Strings that correspond to enum hwmon_type. */ +static const char * const hwmon_type_strs[HWMON_TYPE_MAX] = { + NULL, + "cpu", + "curr", + "energy", + "fan", + "humidity", + "in", + "intrusion", + "power", + "pwm", + "temp", +}; +#define LONGEST_HWMON_TYPE_STR "intrusion" + +/** Strings that correspond to enum hwmon_item. */ +static const char * const hwmon_item_strs[HWMON_ITEM__MAX] = { + NULL, + "accuracy", + "alarm", + "auto_channels_temp", + "average", + "average_highest", + "average_interval", + "average_interval_max", + "average_interval_min", + "average_lowest", + "average_max", + "average_min", + "beep", + "cap", + "cap_hyst", + "cap_max", + "cap_min", + "crit", + "crit_hyst", + "div", + "emergency", + "emergency_hist", + "enable", + "fault", + "freq", + "highest", + "input", + "label", + "lcrit", + "lcrit_hyst", + "lowest", + "max", + "max_hyst", + "min", + "min_hyst", + "mod", + "offset", + "pulses", + "rated_max", + "rated_min", + "reset_history", + "target", + "type", + "vid", +}; +#define LONGEST_HWMON_ITEM_STR "average_interval_max" + +static const char *const hwmon_units[HWMON_TYPE_MAX] = { + NULL, + "V", /* cpu */ + "A", /* curr */ + "J", /* energy */ + "rpm", /* fan */ + "%", /* humidity */ + "V", /* in */ + "", /* intrusion */ + "W", /* power */ + "Hz", /* pwm */ + "'C", /* temp */ +}; + +struct hwmon_pmu { + struct perf_pmu pmu; + struct hashmap events; + int hwmon_dir_fd; +}; + +/** + * union hwmon_pmu_event_key: Key for hwmon_pmu->events as such each key + * represents an event. + * + * Related hwmon files start that this key represents. + */ +union hwmon_pmu_event_key { + long type_and_num; + struct { + int num :16; + enum hwmon_type type :8; + }; +}; + +/** + * struct hwmon_pmu_event_value: Value in hwmon_pmu->events. + * + * Hwmon files are of the form _ and may have a suffix + * _alarm. + */ +struct hwmon_pmu_event_value { + /** @items: which item files are present. */ + DECLARE_BITMAP(items, HWMON_ITEM__MAX); + /** @alarm_items: which item files are present. */ + DECLARE_BITMAP(alarm_items, HWMON_ITEM__MAX); + /** @label: contents of _label if present. */ + char *label; + /** @name: name computed from label of the form _